From 373092553491bc163ec6e977ae60b0d3f9bd6dcf Mon Sep 17 00:00:00 2001 From: oyang Date: Fri, 15 Apr 2011 17:06:38 -0700 Subject: [PATCH] Release 6.2.0beta4 --- HandleAjaxCall.php | 56 + LICENSE.txt | 661 + ModuleInstall/ModuleInstaller.php | 2351 ++ ModuleInstall/ModuleScanner.php | 436 + .../PackageManager/ListViewPackages.php | 72 + .../PackageManager/PackageController.php | 356 + .../PackageManager/PackageManager.php | 878 + .../PackageManager/PackageManagerComm.php | 309 + .../PackageManager/PackageManagerDisplay.php | 606 + .../PackageManagerDownloader.php | 72 + .../PackageManager/metadata/listviewdefs.php | 64 + .../tpls/ModuleLoaderListView.tpl | 97 + .../PackageManager/tpls/PackageForm.tpl | 106 + .../tpls/PackageManagerLicense.tpl | 51 + .../tpls/PackageManagerScripts.tpl | 1085 + SugarSecurity.php | 167 + TreeData.php | 146 + WebToLeadCapture.php | 47 + XTemplate/LICENSE | 502 + XTemplate/xtpl.php | 567 + Zend/Crypt.php | 167 + Zend/Crypt/DiffieHellman.php | 380 + Zend/Crypt/DiffieHellman/Exception.php | 36 + Zend/Crypt/Exception.php | 35 + Zend/Crypt/Hmac.php | 181 + Zend/Crypt/Hmac/Exception.php | 36 + Zend/Crypt/Math.php | 102 + Zend/Crypt/Math/BigInteger.php | 117 + Zend/Crypt/Math/BigInteger/Bcmath.php | 203 + Zend/Crypt/Math/BigInteger/Exception.php | 36 + Zend/Crypt/Math/BigInteger/Gmp.php | 196 + Zend/Crypt/Math/BigInteger/Interface.php | 51 + Zend/Crypt/Math/Exception.php | 36 + Zend/Crypt/Rsa.php | 309 + Zend/Crypt/Rsa/Key.php | 95 + Zend/Crypt/Rsa/Key/Private.php | 75 + Zend/Crypt/Rsa/Key/Public.php | 74 + Zend/Exception.php | 95 + Zend/Gdata.php | 241 + Zend/Gdata/App.php | 1234 + Zend/Gdata/App/AuthException.php | 41 + Zend/Gdata/App/BadMethodCallException.php | 42 + Zend/Gdata/App/Base.php | 572 + Zend/Gdata/App/BaseMediaSource.php | 179 + Zend/Gdata/App/CaptchaRequiredException.php | 94 + Zend/Gdata/App/Entry.php | 389 + Zend/Gdata/App/Exception.php | 43 + Zend/Gdata/App/Extension.php | 40 + Zend/Gdata/App/Extension/Author.php | 43 + Zend/Gdata/App/Extension/Category.php | 140 + Zend/Gdata/App/Extension/Content.php | 88 + Zend/Gdata/App/Extension/Contributor.php | 43 + Zend/Gdata/App/Extension/Control.php | 98 + Zend/Gdata/App/Extension/Draft.php | 50 + Zend/Gdata/App/Extension/Edited.php | 49 + Zend/Gdata/App/Extension/Element.php | 58 + Zend/Gdata/App/Extension/Email.php | 49 + Zend/Gdata/App/Extension/Generator.php | 115 + Zend/Gdata/App/Extension/Icon.php | 49 + Zend/Gdata/App/Extension/Id.php | 49 + Zend/Gdata/App/Extension/Link.php | 219 + Zend/Gdata/App/Extension/Logo.php | 49 + Zend/Gdata/App/Extension/Name.php | 48 + Zend/Gdata/App/Extension/Person.php | 163 + Zend/Gdata/App/Extension/Published.php | 49 + Zend/Gdata/App/Extension/Rights.php | 49 + Zend/Gdata/App/Extension/Source.php | 46 + Zend/Gdata/App/Extension/Subtitle.php | 43 + Zend/Gdata/App/Extension/Summary.php | 43 + Zend/Gdata/App/Extension/Text.php | 90 + Zend/Gdata/App/Extension/Title.php | 43 + Zend/Gdata/App/Extension/Updated.php | 49 + Zend/Gdata/App/Extension/Uri.php | 49 + Zend/Gdata/App/Feed.php | 352 + Zend/Gdata/App/FeedEntryParent.php | 681 + Zend/Gdata/App/FeedSourceParent.php | 267 + Zend/Gdata/App/HttpException.php | 121 + Zend/Gdata/App/IOException.php | 43 + Zend/Gdata/App/InvalidArgumentException.php | 42 + .../App/LoggingHttpClientAdapterSocket.php | 119 + Zend/Gdata/App/MediaEntry.php | 119 + Zend/Gdata/App/MediaFileSource.php | 146 + Zend/Gdata/App/MediaSource.php | 73 + Zend/Gdata/App/Util.php | 112 + Zend/Gdata/App/VersionException.php | 42 + Zend/Gdata/AuthSub.php | 246 + Zend/Gdata/Books.php | 204 + Zend/Gdata/Books/CollectionEntry.php | 56 + Zend/Gdata/Books/CollectionFeed.php | 62 + Zend/Gdata/Books/Extension/AnnotationLink.php | 63 + Zend/Gdata/Books/Extension/BooksCategory.php | 59 + Zend/Gdata/Books/Extension/BooksLink.php | 61 + Zend/Gdata/Books/Extension/Embeddability.php | 122 + Zend/Gdata/Books/Extension/InfoLink.php | 59 + Zend/Gdata/Books/Extension/PreviewLink.php | 60 + Zend/Gdata/Books/Extension/Review.php | 152 + Zend/Gdata/Books/Extension/ThumbnailLink.php | 60 + Zend/Gdata/Books/Extension/Viewability.php | 123 + Zend/Gdata/Books/VolumeEntry.php | 687 + Zend/Gdata/Books/VolumeFeed.php | 62 + Zend/Gdata/Books/VolumeQuery.php | 112 + Zend/Gdata/Calendar.php | 169 + Zend/Gdata/Calendar/EventEntry.php | 164 + Zend/Gdata/Calendar/EventFeed.php | 106 + Zend/Gdata/Calendar/EventQuery.php | 491 + Zend/Gdata/Calendar/Extension/AccessLevel.php | 125 + Zend/Gdata/Calendar/Extension/Color.php | 125 + Zend/Gdata/Calendar/Extension/Hidden.php | 134 + Zend/Gdata/Calendar/Extension/Link.php | 125 + Zend/Gdata/Calendar/Extension/QuickAdd.php | 132 + Zend/Gdata/Calendar/Extension/Selected.php | 133 + .../Extension/SendEventNotifications.php | 132 + Zend/Gdata/Calendar/Extension/Timezone.php | 124 + Zend/Gdata/Calendar/Extension/WebContent.php | 177 + Zend/Gdata/Calendar/ListEntry.php | 246 + Zend/Gdata/Calendar/ListFeed.php | 106 + Zend/Gdata/ClientLogin.php | 182 + Zend/Gdata/Docs.php | 319 + Zend/Gdata/Docs/DocumentListEntry.php | 54 + Zend/Gdata/Docs/DocumentListFeed.php | 68 + Zend/Gdata/Docs/Query.php | 228 + Zend/Gdata/DublinCore.php | 65 + Zend/Gdata/DublinCore/Extension/Creator.php | 58 + Zend/Gdata/DublinCore/Extension/Date.php | 60 + .../DublinCore/Extension/Description.php | 58 + Zend/Gdata/DublinCore/Extension/Format.php | 58 + .../Gdata/DublinCore/Extension/Identifier.php | 58 + Zend/Gdata/DublinCore/Extension/Language.php | 58 + Zend/Gdata/DublinCore/Extension/Publisher.php | 58 + Zend/Gdata/DublinCore/Extension/Rights.php | 58 + Zend/Gdata/DublinCore/Extension/Subject.php | 58 + Zend/Gdata/DublinCore/Extension/Title.php | 58 + Zend/Gdata/Entry.php | 132 + Zend/Gdata/Exif.php | 65 + Zend/Gdata/Exif/Entry.php | 145 + Zend/Gdata/Exif/Extension/Distance.php | 61 + Zend/Gdata/Exif/Extension/Exposure.php | 61 + Zend/Gdata/Exif/Extension/FStop.php | 61 + Zend/Gdata/Exif/Extension/Flash.php | 61 + Zend/Gdata/Exif/Extension/FocalLength.php | 61 + Zend/Gdata/Exif/Extension/ImageUniqueId.php | 61 + Zend/Gdata/Exif/Extension/Iso.php | 61 + Zend/Gdata/Exif/Extension/Make.php | 61 + Zend/Gdata/Exif/Extension/Model.php | 61 + Zend/Gdata/Exif/Extension/Tags.php | 549 + Zend/Gdata/Exif/Extension/Time.php | 61 + Zend/Gdata/Exif/Feed.php | 70 + Zend/Gdata/Extension.php | 58 + Zend/Gdata/Extension/AttendeeStatus.php | 123 + Zend/Gdata/Extension/AttendeeType.php | 123 + Zend/Gdata/Extension/Comments.php | 117 + Zend/Gdata/Extension/EntryLink.php | 167 + Zend/Gdata/Extension/EventStatus.php | 101 + Zend/Gdata/Extension/ExtendedProperty.php | 106 + Zend/Gdata/Extension/FeedLink.php | 175 + .../Extension/OpenSearchItemsPerPage.php | 50 + Zend/Gdata/Extension/OpenSearchStartIndex.php | 50 + .../Extension/OpenSearchTotalResults.php | 50 + Zend/Gdata/Extension/OriginalEvent.php | 142 + Zend/Gdata/Extension/Rating.php | 240 + Zend/Gdata/Extension/Recurrence.php | 49 + Zend/Gdata/Extension/RecurrenceException.php | 215 + Zend/Gdata/Extension/Reminder.php | 171 + Zend/Gdata/Extension/Transparency.php | 123 + Zend/Gdata/Extension/Visibility.php | 123 + Zend/Gdata/Extension/When.php | 169 + Zend/Gdata/Extension/Where.php | 171 + Zend/Gdata/Extension/Who.php | 299 + Zend/Gdata/Feed.php | 251 + Zend/Gdata/Gapps.php | 1683 + Zend/Gdata/Gapps/EmailListEntry.php | 214 + Zend/Gdata/Gapps/EmailListFeed.php | 53 + Zend/Gdata/Gapps/EmailListQuery.php | 187 + Zend/Gdata/Gapps/EmailListRecipientEntry.php | 146 + Zend/Gdata/Gapps/EmailListRecipientFeed.php | 53 + Zend/Gdata/Gapps/EmailListRecipientQuery.php | 153 + Zend/Gdata/Gapps/Error.php | 233 + Zend/Gdata/Gapps/Extension/EmailList.php | 144 + Zend/Gdata/Gapps/Extension/Login.php | 485 + Zend/Gdata/Gapps/Extension/Name.php | 181 + Zend/Gdata/Gapps/Extension/Nickname.php | 142 + Zend/Gdata/Gapps/Extension/Property.php | 180 + Zend/Gdata/Gapps/Extension/Quota.php | 142 + Zend/Gdata/Gapps/GroupEntry.php | 158 + Zend/Gdata/Gapps/GroupFeed.php | 53 + Zend/Gdata/Gapps/GroupQuery.php | 226 + Zend/Gdata/Gapps/MemberEntry.php | 159 + Zend/Gdata/Gapps/MemberFeed.php | 53 + Zend/Gdata/Gapps/MemberQuery.php | 194 + Zend/Gdata/Gapps/NicknameEntry.php | 189 + Zend/Gdata/Gapps/NicknameFeed.php | 53 + Zend/Gdata/Gapps/NicknameQuery.php | 186 + Zend/Gdata/Gapps/OwnerEntry.php | 158 + Zend/Gdata/Gapps/OwnerFeed.php | 53 + Zend/Gdata/Gapps/OwnerQuery.php | 147 + Zend/Gdata/Gapps/Query.php | 123 + Zend/Gdata/Gapps/ServiceException.php | 208 + Zend/Gdata/Gapps/UserEntry.php | 295 + Zend/Gdata/Gapps/UserFeed.php | 53 + Zend/Gdata/Gapps/UserQuery.php | 147 + Zend/Gdata/Gbase.php | 209 + Zend/Gdata/Gbase/Entry.php | 151 + Zend/Gdata/Gbase/Extension/BaseAttribute.php | 115 + Zend/Gdata/Gbase/Feed.php | 60 + Zend/Gdata/Gbase/ItemEntry.php | 161 + Zend/Gdata/Gbase/ItemFeed.php | 48 + Zend/Gdata/Gbase/ItemQuery.php | 101 + Zend/Gdata/Gbase/Query.php | 268 + Zend/Gdata/Gbase/SnippetEntry.php | 48 + Zend/Gdata/Gbase/SnippetFeed.php | 48 + Zend/Gdata/Gbase/SnippetQuery.php | 74 + Zend/Gdata/Geo.php | 70 + Zend/Gdata/Geo/Entry.php | 97 + Zend/Gdata/Geo/Extension/GeoRssWhere.php | 135 + Zend/Gdata/Geo/Extension/GmlPoint.php | 136 + Zend/Gdata/Geo/Extension/GmlPos.php | 61 + Zend/Gdata/Geo/Feed.php | 64 + Zend/Gdata/Health.php | 274 + Zend/Gdata/Health/Extension/Ccr.php | 124 + Zend/Gdata/Health/ProfileEntry.php | 135 + Zend/Gdata/Health/ProfileFeed.php | 67 + Zend/Gdata/Health/ProfileListEntry.php | 100 + Zend/Gdata/Health/ProfileListFeed.php | 53 + Zend/Gdata/Health/Query.php | 285 + Zend/Gdata/HttpAdapterStreamingProxy.php | 127 + Zend/Gdata/HttpAdapterStreamingSocket.php | 111 + Zend/Gdata/HttpClient.php | 352 + Zend/Gdata/Kind/EventEntry.php | 428 + Zend/Gdata/Media.php | 65 + Zend/Gdata/Media/Entry.php | 134 + Zend/Gdata/Media/Extension/MediaCategory.php | 148 + Zend/Gdata/Media/Extension/MediaContent.php | 522 + Zend/Gdata/Media/Extension/MediaCopyright.php | 116 + Zend/Gdata/Media/Extension/MediaCredit.php | 149 + .../Media/Extension/MediaDescription.php | 116 + Zend/Gdata/Media/Extension/MediaGroup.php | 566 + Zend/Gdata/Media/Extension/MediaHash.php | 115 + Zend/Gdata/Media/Extension/MediaKeywords.php | 52 + Zend/Gdata/Media/Extension/MediaPlayer.php | 178 + Zend/Gdata/Media/Extension/MediaRating.php | 118 + .../Media/Extension/MediaRestriction.php | 149 + Zend/Gdata/Media/Extension/MediaText.php | 211 + Zend/Gdata/Media/Extension/MediaThumbnail.php | 210 + Zend/Gdata/Media/Extension/MediaTitle.php | 118 + Zend/Gdata/Media/Feed.php | 70 + Zend/Gdata/MediaMimeStream.php | 190 + Zend/Gdata/MimeBodyString.php | 92 + Zend/Gdata/MimeFile.php | 66 + Zend/Gdata/Photos.php | 576 + Zend/Gdata/Photos/AlbumEntry.php | 610 + Zend/Gdata/Photos/AlbumFeed.php | 509 + Zend/Gdata/Photos/AlbumQuery.php | 149 + Zend/Gdata/Photos/CommentEntry.php | 195 + Zend/Gdata/Photos/Extension/Access.php | 63 + Zend/Gdata/Photos/Extension/AlbumId.php | 63 + Zend/Gdata/Photos/Extension/BytesUsed.php | 62 + Zend/Gdata/Photos/Extension/Checksum.php | 63 + Zend/Gdata/Photos/Extension/Client.php | 63 + Zend/Gdata/Photos/Extension/CommentCount.php | 63 + .../Photos/Extension/CommentingEnabled.php | 64 + Zend/Gdata/Photos/Extension/Height.php | 62 + Zend/Gdata/Photos/Extension/Id.php | 62 + Zend/Gdata/Photos/Extension/Location.php | 62 + .../Photos/Extension/MaxPhotosPerAlbum.php | 63 + Zend/Gdata/Photos/Extension/Name.php | 62 + Zend/Gdata/Photos/Extension/Nickname.php | 62 + Zend/Gdata/Photos/Extension/NumPhotos.php | 62 + .../Photos/Extension/NumPhotosRemaining.php | 62 + Zend/Gdata/Photos/Extension/PhotoId.php | 61 + Zend/Gdata/Photos/Extension/Position.php | 62 + Zend/Gdata/Photos/Extension/QuotaCurrent.php | 62 + Zend/Gdata/Photos/Extension/QuotaLimit.php | 63 + Zend/Gdata/Photos/Extension/Rotation.php | 63 + Zend/Gdata/Photos/Extension/Size.php | 62 + Zend/Gdata/Photos/Extension/Thumbnail.php | 62 + Zend/Gdata/Photos/Extension/Timestamp.php | 63 + Zend/Gdata/Photos/Extension/User.php | 62 + Zend/Gdata/Photos/Extension/Version.php | 63 + Zend/Gdata/Photos/Extension/Weight.php | 63 + Zend/Gdata/Photos/Extension/Width.php | 62 + Zend/Gdata/Photos/PhotoEntry.php | 691 + Zend/Gdata/Photos/PhotoFeed.php | 559 + Zend/Gdata/Photos/PhotoQuery.php | 98 + Zend/Gdata/Photos/TagEntry.php | 140 + Zend/Gdata/Photos/UserEntry.php | 366 + Zend/Gdata/Photos/UserFeed.php | 247 + Zend/Gdata/Photos/UserQuery.php | 355 + Zend/Gdata/Query.php | 418 + Zend/Gdata/Spreadsheets.php | 445 + Zend/Gdata/Spreadsheets/CellEntry.php | 103 + Zend/Gdata/Spreadsheets/CellFeed.php | 158 + Zend/Gdata/Spreadsheets/CellQuery.php | 417 + Zend/Gdata/Spreadsheets/DocumentQuery.php | 288 + Zend/Gdata/Spreadsheets/Extension/Cell.php | 201 + .../Gdata/Spreadsheets/Extension/ColCount.php | 59 + Zend/Gdata/Spreadsheets/Extension/Custom.php | 100 + .../Gdata/Spreadsheets/Extension/RowCount.php | 60 + Zend/Gdata/Spreadsheets/ListEntry.php | 208 + Zend/Gdata/Spreadsheets/ListFeed.php | 64 + Zend/Gdata/Spreadsheets/ListQuery.php | 305 + Zend/Gdata/Spreadsheets/SpreadsheetEntry.php | 64 + Zend/Gdata/Spreadsheets/SpreadsheetFeed.php | 64 + Zend/Gdata/Spreadsheets/WorksheetEntry.php | 187 + Zend/Gdata/Spreadsheets/WorksheetFeed.php | 64 + Zend/Gdata/YouTube.php | 874 + Zend/Gdata/YouTube/ActivityEntry.php | 232 + Zend/Gdata/YouTube/ActivityFeed.php | 66 + Zend/Gdata/YouTube/CommentEntry.php | 59 + Zend/Gdata/YouTube/CommentFeed.php | 66 + Zend/Gdata/YouTube/ContactEntry.php | 136 + Zend/Gdata/YouTube/ContactFeed.php | 68 + Zend/Gdata/YouTube/Extension/AboutMe.php | 51 + Zend/Gdata/YouTube/Extension/Age.php | 51 + Zend/Gdata/YouTube/Extension/Books.php | 51 + Zend/Gdata/YouTube/Extension/Company.php | 51 + Zend/Gdata/YouTube/Extension/Control.php | 133 + Zend/Gdata/YouTube/Extension/CountHint.php | 51 + Zend/Gdata/YouTube/Extension/Description.php | 51 + Zend/Gdata/YouTube/Extension/Duration.php | 126 + Zend/Gdata/YouTube/Extension/FirstName.php | 51 + Zend/Gdata/YouTube/Extension/Gender.php | 51 + Zend/Gdata/YouTube/Extension/Hobbies.php | 51 + Zend/Gdata/YouTube/Extension/Hometown.php | 51 + Zend/Gdata/YouTube/Extension/LastName.php | 51 + Zend/Gdata/YouTube/Extension/Link.php | 133 + Zend/Gdata/YouTube/Extension/Location.php | 51 + Zend/Gdata/YouTube/Extension/MediaContent.php | 120 + Zend/Gdata/YouTube/Extension/MediaCredit.php | 189 + Zend/Gdata/YouTube/Extension/MediaGroup.php | 336 + Zend/Gdata/YouTube/Extension/MediaRating.php | 150 + Zend/Gdata/YouTube/Extension/Movies.php | 51 + Zend/Gdata/YouTube/Extension/Music.php | 51 + Zend/Gdata/YouTube/Extension/NoEmbed.php | 54 + Zend/Gdata/YouTube/Extension/Occupation.php | 51 + Zend/Gdata/YouTube/Extension/PlaylistId.php | 51 + .../Gdata/YouTube/Extension/PlaylistTitle.php | 51 + Zend/Gdata/YouTube/Extension/Position.php | 90 + Zend/Gdata/YouTube/Extension/Private.php | 81 + Zend/Gdata/YouTube/Extension/QueryString.php | 51 + Zend/Gdata/YouTube/Extension/Racy.php | 124 + Zend/Gdata/YouTube/Extension/Recorded.php | 51 + Zend/Gdata/YouTube/Extension/Relationship.php | 51 + Zend/Gdata/YouTube/Extension/ReleaseDate.php | 51 + Zend/Gdata/YouTube/Extension/School.php | 51 + Zend/Gdata/YouTube/Extension/State.php | 193 + Zend/Gdata/YouTube/Extension/Statistics.php | 309 + Zend/Gdata/YouTube/Extension/Status.php | 51 + Zend/Gdata/YouTube/Extension/Token.php | 70 + Zend/Gdata/YouTube/Extension/Uploaded.php | 51 + Zend/Gdata/YouTube/Extension/Username.php | 51 + Zend/Gdata/YouTube/Extension/VideoId.php | 51 + Zend/Gdata/YouTube/InboxEntry.php | 281 + Zend/Gdata/YouTube/InboxFeed.php | 68 + Zend/Gdata/YouTube/MediaEntry.php | 81 + Zend/Gdata/YouTube/PlaylistListEntry.php | 300 + Zend/Gdata/YouTube/PlaylistListFeed.php | 68 + Zend/Gdata/YouTube/PlaylistVideoEntry.php | 132 + Zend/Gdata/YouTube/PlaylistVideoFeed.php | 68 + Zend/Gdata/YouTube/SubscriptionEntry.php | 446 + Zend/Gdata/YouTube/SubscriptionFeed.php | 68 + Zend/Gdata/YouTube/UserProfileEntry.php | 1041 + Zend/Gdata/YouTube/VideoEntry.php | 1095 + Zend/Gdata/YouTube/VideoFeed.php | 65 + Zend/Gdata/YouTube/VideoQuery.php | 540 + Zend/Http/Client.php | 1453 + Zend/Http/Client/Adapter/Curl.php | 507 + Zend/Http/Client/Adapter/Exception.php | 38 + Zend/Http/Client/Adapter/Interface.php | 78 + Zend/Http/Client/Adapter/Proxy.php | 284 + Zend/Http/Client/Adapter/Socket.php | 544 + Zend/Http/Client/Adapter/Stream.php | 46 + Zend/Http/Client/Adapter/Test.php | 238 + Zend/Http/Client/Exception.php | 36 + Zend/Http/Exception.php | 36 + Zend/Http/Response.php | 667 + Zend/Http/Response/Stream.php | 235 + Zend/Loader.php | 329 + Zend/Oauth.php | 89 + Zend/Oauth/Client.php | 336 + Zend/Oauth/Config.php | 658 + Zend/Oauth/Config/ConfigInterface.php | 75 + Zend/Oauth/Consumer.php | 273 + Zend/Oauth/Exception.php | 33 + Zend/Oauth/Http.php | 266 + Zend/Oauth/Http/AccessToken.php | 189 + Zend/Oauth/Http/RequestToken.php | 162 + Zend/Oauth/Http/UserAuthorization.php | 78 + Zend/Oauth/Http/Utility.php | 217 + Zend/Oauth/Signature/Hmac.php | 54 + Zend/Oauth/Signature/Plaintext.php | 49 + Zend/Oauth/Signature/Rsa.php | 65 + Zend/Oauth/Signature/SignatureAbstract.php | 183 + Zend/Oauth/Token.php | 285 + Zend/Oauth/Token/Access.php | 99 + Zend/Oauth/Token/AuthorizedRequest.php | 102 + Zend/Oauth/Token/Request.php | 50 + Zend/Registry.php | 209 + Zend/Uri.php | 202 + Zend/Uri/Exception.php | 37 + Zend/Uri/Http.php | 769 + Zend/Validate/Abstract.php | 456 + Zend/Validate/Hostname.php | 740 + Zend/Validate/Hostname/Biz.php | 2917 ++ Zend/Validate/Hostname/Cn.php | 2199 ++ Zend/Validate/Hostname/Com.php | 198 + Zend/Validate/Hostname/Jp.php | 739 + Zend/Validate/Interface.php | 54 + Zend/Validate/Ip.php | 191 + Zend/Version.php | 53 + acceptDecline.php | 46 + cache/csv/index.html | 1 + cache/feeds/index.html | 1 + cache/images/index.html | 1 + cache/import/index.html | 1 + cache/index.html | 1 + cache/layout/index.html | 1 + cache/pdf/index.html | 1 + cache/upload/index.html | 1 + cache/xml/index.html | 1 + campaign_tracker.php | 83 + campaign_trackerv2.php | 46 + config.php | 0 cron.php | 112 + custom/index.html | 5 + data/Link.php | 1094 + data/SugarBean.php | 5467 +++ data/Tracker.php | 50 + data/upload/index.html | 1 + dictionary.php | 42 + download.php | 180 + emailmandelivery.php | 41 + examples/EXAMPLES_README.txt | 7 + examples/ExampleLeadCapture.php | 70 + examples/FormValidationTest.php | 61 + examples/ProgressBarTest.php | 48 + examples/SoapTest.php | 122 + examples/SoapTestPortal.php | 262 + examples/SoapTestPortal2.php | 105 + export.php | 78 + files.md5 | 5781 +++ image.php | 46 + include/Dashlets/Dashlet.php | 378 + include/Dashlets/DashletCacheBuilder.php | 88 + include/Dashlets/DashletGeneric.php | 506 + .../Dashlets/DashletGenericAutoRefresh.tpl | 58 + .../DashletGenericAutoRefreshDynamic.tpl | 64 + include/Dashlets/DashletGenericChart.php | 354 + .../Dashlets/DashletGenericChartConfigure.tpl | 95 + include/Dashlets/DashletGenericConfigure.tpl | 134 + include/Dashlets/DashletGenericDisplay.tpl | 191 + include/DetailView/DetailView.php | 451 + include/DetailView/DetailView.tpl | 175 + include/DetailView/DetailView2.php | 104 + include/DetailView/footer.tpl | 38 + include/DetailView/header.tpl | 119 + include/EditView/EditView.php | 96 + include/EditView/EditView.tpl | 215 + include/EditView/EditView2.php | 716 + include/EditView/PopupQuickCreate.php | 54 + include/EditView/QuickCreate.php | 77 + include/EditView/QuickCreate.tpl | 38 + include/EditView/SubpanelQuickCreate.php | 121 + include/EditView/SugarVCR.php | 187 + include/EditView/footer.tpl | 64 + include/EditView/header.tpl | 91 + include/GroupedTabs/GroupedTabStructure.php | 149 + include/HTTP_WebDAV_Server/README | 10 + include/HTTP_WebDAV_Server/Server.php | 1873 + .../Tools/_parse_lockinfo.php | 237 + .../Tools/_parse_propfind.php | 178 + .../Tools/_parse_proppatch.php | 214 + include/HTTP_WebDAV_Server/dav.txt | 229 + include/HTTP_WebDAV_Server/license.txt | 68 + include/JSON.js | 44 + include/JSON.php | 104 + include/ListView/ListView.php | 1757 + include/ListView/ListViewDCMenu.tpl | 189 + include/ListView/ListViewData.php | 577 + include/ListView/ListViewDisplay.php | 615 + include/ListView/ListViewFacade.php | 177 + include/ListView/ListViewGeneric.tpl | 168 + include/ListView/ListViewNoMassUpdate.tpl | 133 + include/ListView/ListViewPagination.tpl | 91 + include/ListView/ListViewSmarty.php | 231 + include/ListView/ListViewXTPL.php | 221 + include/Localization/Localization.php | 694 + include/MVC/Controller/ControllerFactory.php | 82 + include/MVC/Controller/SugarController.php | 833 + include/MVC/Controller/action_file_map.php | 50 + include/MVC/Controller/action_view_map.php | 65 + .../MVC/Controller/entry_point_registry.php | 74 + .../Controller/file_access_control_map.php | 71 + include/MVC/SugarApplication.php | 582 + include/MVC/SugarModule.php | 120 + include/MVC/View/SugarView.php | 1248 + include/MVC/View/ViewFactory.php | 248 + include/MVC/View/tpls/Importvcard.tpl | 69 + include/MVC/View/tpls/modulelistmenu.tpl | 42 + include/MVC/View/tpls/xsrf.tpl | 61 + include/MVC/View/views/view.ajax.php | 57 + .../MVC/View/views/view.classic.config.php | 68 + include/MVC/View/views/view.classic.php | 71 + include/MVC/View/views/view.config.php | 120 + include/MVC/View/views/view.detail.php | 71 + include/MVC/View/views/view.edit.php | 68 + include/MVC/View/views/view.html.php | 49 + include/MVC/View/views/view.importvcard.php | 79 + .../MVC/View/views/view.importvcardsave.php | 70 + include/MVC/View/views/view.json.php | 65 + include/MVC/View/views/view.list.php | 293 + .../MVC/View/views/view.modulelistmenu.php | 66 + include/MVC/View/views/view.multiedit.php | 85 + include/MVC/View/views/view.noaccess.php | 49 + include/MVC/View/views/view.popup.php | 173 + include/MVC/View/views/view.quick.php | 68 + include/MVC/View/views/view.quickcreate.php | 168 + include/MVC/View/views/view.serialized.php | 49 + .../MVC/View/views/view.sugarpdf.config.php | 56 + include/MVC/View/views/view.sugarpdf.php | 86 + include/MVC/View/views/view.vcard.php | 62 + include/MVC/View/views/view.xml.php | 47 + include/MassUpdate.php | 1277 + .../MySugar/DashletsDialog/DashletsDialog.php | 191 + include/MySugar/MySugar.php | 425 + include/MySugar/javascript/MySugar.js | 74 + include/MySugar/tpls/MySugar.tpl | 186 + include/MySugar/tpls/addDashletsDialog.tpl | 154 + .../tpls/chartDashletsSearchResults.tpl | 49 + .../MySugar/tpls/dashletsSearchResults.tpl | 55 + include/MySugar/tpls/retrievePage.tpl | 92 + include/MySugar/tpls/retrieveReportCharts.tpl | 44 + include/OutboundEmail/OutboundEmail.php | 615 + include/Pear/Crypt_Blowfish/Blowfish.php | 325 + .../Crypt_Blowfish/Blowfish/DefaultKey.php | 327 + include/Pear/Crypt_Blowfish/license.txt | 68 + include/Pear/HTML_Safe/Safe.php | 672 + include/Pear/HTML_Safe/license.txt | 27 + include/Pear/XML_HTMLSax3/HTMLSax3.php | 685 + .../Pear/XML_HTMLSax3/HTMLSax3/Decorators.php | 363 + include/Pear/XML_HTMLSax3/HTMLSax3/States.php | 287 + include/Pear/XML_HTMLSax3/LICENSE | 68 + include/Popups/PopupSmarty.php | 521 + include/Popups/Popup_picker.php | 344 + include/Popups/tpls/PopupGeneric.tpl | 265 + include/Popups/tpls/footer.tpl | 52 + include/Popups/tpls/header.tpl | 132 + include/QuickSearchDefaults.php | 200 + include/SearchForm/SearchForm.php | 715 + include/SearchForm/SearchForm2.php | 1083 + include/SearchForm/SugarSpot.php | 429 + include/SearchForm/tpls/SearchFormGeneric.tpl | 83 + .../tpls/SearchFormGenericAdvanced.tpl | 100 + include/SearchForm/tpls/footer.tpl | 58 + include/SearchForm/tpls/header.tpl | 54 + include/Smarty/COPYING.lib | 502 + include/Smarty/Config_File.class.php | 413 + include/Smarty/LICENSE | 502 + include/Smarty/README | 80 + include/Smarty/Smarty.class.php | 1940 + include/Smarty/Smarty_Compiler.class.php | 2318 ++ include/Smarty/debug.tpl | 87 + .../core.assemble_plugin_filepath.php | 92 + .../core.assign_smarty_interface.php | 68 + .../internals/core.create_dir_structure.php | 106 + .../internals/core.display_debug_console.php | 86 + .../internals/core.get_include_path.php | 69 + .../Smarty/internals/core.get_microtime.php | 48 + .../internals/core.get_php_resource.php | 105 + include/Smarty/internals/core.is_secure.php | 86 + include/Smarty/internals/core.is_trusted.php | 74 + .../Smarty/internals/core.load_plugins.php | 150 + .../internals/core.load_resource_plugin.php | 99 + .../internals/core.process_cached_inserts.php | 98 + .../core.process_compiled_include.php | 62 + .../Smarty/internals/core.read_cache_file.php | 126 + include/Smarty/internals/core.rm_auto.php | 96 + include/Smarty/internals/core.rmdir.php | 79 + .../internals/core.run_insert_handler.php | 96 + .../internals/core.smarty_include_php.php | 75 + .../internals/core.write_cache_file.php | 121 + .../internals/core.write_compiled_include.php | 91 + .../core.write_compiled_resource.php | 60 + include/Smarty/internals/core.write_file.php | 79 + include/Smarty/plugins/block.textformat.php | 130 + include/Smarty/plugins/compiler.assign.php | 67 + .../plugins/function.assign_debug_info.php | 67 + .../Smarty/plugins/function.config_load.php | 223 + include/Smarty/plugins/function.counter.php | 107 + include/Smarty/plugins/function.cycle.php | 127 + include/Smarty/plugins/function.debug.php | 60 + include/Smarty/plugins/function.eval.php | 76 + .../Smarty/plugins/function.ext_includes.php | 61 + include/Smarty/plugins/function.fetch.php | 253 + .../plugins/function.html_checkboxes.php | 168 + .../Smarty/plugins/function.html_image.php | 169 + .../Smarty/plugins/function.html_options.php | 162 + .../Smarty/plugins/function.html_radios.php | 187 + .../plugins/function.html_select_date.php | 350 + .../plugins/function.html_select_time.php | 221 + .../Smarty/plugins/function.html_table.php | 162 + include/Smarty/plugins/function.mailto.php | 188 + include/Smarty/plugins/function.math.php | 111 + .../plugins/function.multienum_to_array.php | 93 + .../plugins/function.overlib_includes.php | 58 + include/Smarty/plugins/function.popup.php | 146 + .../Smarty/plugins/function.popup_init.php | 69 + .../Smarty/plugins/function.sugar_button.php | 385 + .../plugins/function.sugar_button_slider.php | 70 + .../function.sugar_connector_display.php | 112 + .../function.sugar_currency_format.php | 90 + .../plugins/function.sugar_evalcolumn.php | 108 + .../plugins/function.sugar_evalcolumn_old.php | 94 + .../Smarty/plugins/function.sugar_fetch.php | 61 + .../Smarty/plugins/function.sugar_field.php | 92 + .../plugins/function.sugar_getimagepath.php | 62 + .../plugins/function.sugar_getjspath.php | 53 + .../plugins/function.sugar_getwebpath.php | 53 + .../Smarty/plugins/function.sugar_help.php | 94 + .../Smarty/plugins/function.sugar_image.php | 53 + .../Smarty/plugins/function.sugar_include.php | 89 + .../Smarty/plugins/function.sugar_link.php | 115 + .../plugins/function.sugar_number_format.php | 57 + .../Smarty/plugins/function.sugar_phone.php | 116 + .../plugins/function.sugar_replace_vars.php | 73 + .../plugins/function.sugar_run_helper.php | 72 + .../plugins/function.sugar_translate.php | 91 + .../function.sugar_variable_constructor.php | 68 + include/Smarty/plugins/function.sugarvar.php | 114 + .../plugins/function.sugarvar_connector.php | 84 + .../Smarty/plugins/modifier.capitalize.php | 70 + include/Smarty/plugins/modifier.cat.php | 58 + .../plugins/modifier.count_characters.php | 59 + .../plugins/modifier.count_paragraphs.php | 56 + .../plugins/modifier.count_sentences.php | 56 + .../Smarty/plugins/modifier.count_words.php | 60 + .../Smarty/plugins/modifier.date_format.php | 76 + .../plugins/modifier.debug_print_var.php | 84 + include/Smarty/plugins/modifier.default.php | 59 + .../plugins/modifier.default_date_value.php | 211 + include/Smarty/plugins/modifier.escape.php | 125 + include/Smarty/plugins/modifier.in_array.php | 54 + include/Smarty/plugins/modifier.indent.php | 55 + include/Smarty/plugins/modifier.lower.php | 53 + include/Smarty/plugins/modifier.nl2br.php | 60 + .../Smarty/plugins/modifier.regex_replace.php | 61 + include/Smarty/plugins/modifier.replace.php | 57 + include/Smarty/plugins/modifier.spacify.php | 57 + .../Smarty/plugins/modifier.string_format.php | 56 + include/Smarty/plugins/modifier.strip.php | 64 + .../plugins/modifier.strip_semicolon.php | 59 + .../Smarty/plugins/modifier.strip_tags.php | 59 + include/Smarty/plugins/modifier.to_url.php | 83 + include/Smarty/plugins/modifier.truncate.php | 77 + include/Smarty/plugins/modifier.upper.php | 53 + include/Smarty/plugins/modifier.wordwrap.php | 56 + .../plugins/outputfilter.trimwhitespace.php | 108 + .../plugins/shared.escape_special_chars.php | 58 + .../Smarty/plugins/shared.make_timestamp.php | 73 + include/SubPanel/SubPanel.php | 383 + include/SubPanel/SubPanelDefinitions.php | 787 + include/SubPanel/SubPanelDynamic.html | 66 + include/SubPanel/SubPanelTiles.js | 124 + include/SubPanel/SubPanelTiles.php | 443 + include/SubPanel/SubPanelTilesTabs.php | 267 + include/SubPanel/SubPanelViewer.php | 92 + include/SubPanel/SugarTab.php | 91 + include/SubPanel/registered_layout_defs.php | 53 + include/SubPanel/subpanels.txt | 471 + include/SubPanel/tpls/singletabmenu.tpl | 142 + include/SugarCache/SugarCache.php | 181 + include/SugarCache/SugarCacheAPC.php | 104 + include/SugarCache/SugarCacheAbstract.php | 315 + include/SugarCache/SugarCacheFile.php | 149 + include/SugarCache/SugarCacheMemcache.php | 143 + include/SugarCache/SugarCacheMemcached.php | 143 + include/SugarCache/SugarCacheMemory.php | 98 + include/SugarCache/SugarCacheRedis.php | 175 + include/SugarCache/SugarCacheWincache.php | 104 + include/SugarCache/SugarCacheZend.php | 103 + include/SugarCache/SugarCachesMash.php | 100 + .../SugarCharts/Jit/FlashCanvas/canvas2png.js | 9 + .../Jit/FlashCanvas/flashcanvas.js | 8 + .../Jit/FlashCanvas/flashcanvas.swf | Bin 0 -> 21235 bytes include/SugarCharts/Jit/FlashCanvas/proxy.php | 73 + include/SugarCharts/Jit/FlashCanvas/save.php | 49 + include/SugarCharts/Jit/Jit.php | 88 + include/SugarCharts/Jit/JitReports.php | 215 + include/SugarCharts/Jit/css/base.css | 110 + include/SugarCharts/Jit/js/Jit/jit.js | 496 + include/SugarCharts/Jit/js/mySugarCharts.js | 39 + include/SugarCharts/Jit/js/sugarCharts.js | 76 + .../Jit/tpls/DashletGenericChartScript.tpl | 51 + include/SugarCharts/Jit/tpls/chart.tpl | 76 + include/SugarCharts/JsChart.php | 675 + include/SugarCharts/SugarChart.php | 841 + include/SugarCharts/SugarChartFactory.php | 93 + include/SugarCharts/swf/barChart.swf | Bin 0 -> 11828 bytes include/SugarCharts/swf/chart.swf | Bin 0 -> 11243 bytes include/SugarCharts/swf/groupByChart.swf | Bin 0 -> 12327 bytes .../SugarCharts/swf/horizontalBarChart.swf | Bin 0 -> 11926 bytes .../swf/horizontalGroupByChart.swf | Bin 0 -> 12451 bytes include/SugarCharts/swf/lineChart.swf | Bin 0 -> 11780 bytes include/SugarCharts/swf/pieChart.swf | Bin 0 -> 12168 bytes .../SugarCharts/swf/stackedGroupByChart.swf | Bin 0 -> 12211 bytes include/SugarDateTime.php | 584 + .../SugarDependentDropdown.php | 334 + .../javascript/SugarDependentDropdown.js | 52 + .../metadata/dependentDropdown.php | 343 + .../SugarEmailAddress/SugarEmailAddress.js | 69 + .../SugarEmailAddress/SugarEmailAddress.php | 990 + .../templates/forDetailView.tpl | 73 + .../templates/forDuplicatesView.tpl | 63 + .../templates/forEditView.tpl | 123 + .../templates/forWideFormBodyView.tpl | 105 + .../SugarFields/Fields/Address/DetailView.tpl | 58 + .../SugarFields/Fields/Address/EditView.tpl | 138 + .../Fields/Address/SugarFieldAddress.js | 41 + .../Fields/Address/SugarFieldAddress.php | 105 + .../Fields/Address/en_us.DetailView.tpl | 63 + .../Fields/Address/en_us.EditView.tpl | 138 + .../Assigned_user_name/EditViewFunction.tpl | 38 + .../Fields/Assigned_user_name/SearchView.tpl | 40 + .../SugarFieldAssigned_user_name.php | 51 + .../SugarFields/Fields/Base/DetailView.tpl | 48 + .../Fields/Base/DetailViewFunction.tpl | 41 + include/SugarFields/Fields/Base/EditView.tpl | 46 + .../Fields/Base/EditViewFunction.tpl | 38 + .../Fields/Base/ImportViewFunction.tpl | 38 + .../SugarFields/Fields/Base/InlineEdit.tpl | 39 + .../Fields/Base/InlineEditView.tpl | 39 + include/SugarFields/Fields/Base/ListView.tpl | 39 + .../SugarFields/Fields/Base/SearchForm.tpl | 38 + .../Fields/Base/SugarFieldBase.php | 393 + .../SugarFields/Fields/Bool/DetailView.tpl | 46 + include/SugarFields/Fields/Bool/EditView.tpl | 46 + .../SugarFields/Fields/Bool/InlineEdit.tpl | 45 + .../Fields/Bool/InlineEditView.tpl | 44 + include/SugarFields/Fields/Bool/ListView.tpl | 44 + .../SugarFields/Fields/Bool/SearchView.tpl | 55 + .../Fields/Bool/SugarFieldBool.php | 113 + .../Collection/CollectionDetailView.tpl | 61 + .../Fields/Collection/CollectionEditView.tpl | 98 + .../Collection/CollectionEditViewRow.tpl | 81 + .../Fields/Collection/DetailView.tpl | 61 + .../Fields/Collection/EditView.tpl | 67 + .../Fields/Collection/SugarFieldCollection.js | 80 + .../Collection/SugarFieldCollection.php | 222 + .../Collection/ViewSugarFieldCollection.php | 543 + .../Collection/view.sugarfieldcollection.php | 43 + .../Fields/Currency/DetailView.tpl | 43 + .../SugarFields/Fields/Currency/EditView.tpl | 44 + .../SugarFields/Fields/Currency/ListView.tpl | 43 + .../Fields/Currency/SugarFieldCurrency.php | 76 + .../SugarFields/Fields/Datetime/EditView.tpl | 66 + .../Fields/Datetime/SugarFieldDatetime.php | 181 + .../Fields/Datetimecombo/Datetimecombo.js | 51 + .../Fields/Datetimecombo/EditView.tpl | 118 + .../Fields/Datetimecombo/RangeSearchForm.tpl | 167 + .../Fields/Datetimecombo/SearchView.tpl | 111 + .../Datetimecombo/SugarFieldDatetimecombo.php | 150 + .../Fields/Download/DetailView.tpl | 46 + .../Fields/Download/SugarFieldDownload.php | 48 + .../SugarFields/Fields/Enum/DetailView.tpl | 49 + .../Fields/Enum/DetailViewFunction.tpl | 41 + include/SugarFields/Fields/Enum/EditView.tpl | 49 + .../Fields/Enum/EditViewFunction.tpl | 42 + .../SugarFields/Fields/Enum/SearchView.tpl | 39 + .../Fields/Enum/SugarFieldEnum.php | 147 + .../SugarFields/Fields/File/DetailView.tpl | 51 + include/SugarFields/Fields/File/EditView.tpl | 221 + include/SugarFields/Fields/File/ListView.tpl | 45 + .../SugarFields/Fields/File/SearchView.tpl | 39 + .../SugarFields/Fields/File/SugarFieldFile.js | 45 + .../Fields/File/SugarFieldFile.php | 163 + .../SugarFields/Fields/Float/DetailView.tpl | 43 + include/SugarFields/Fields/Float/EditView.tpl | 49 + .../Fields/Float/SugarFieldFloat.php | 85 + .../Fields/Fullname/DetailView.tpl | 58 + .../Fields/Fullname/SugarFieldFullname.php | 76 + .../SugarFields/Fields/Html/DetailView.tpl | 41 + .../Fields/Html/SugarFieldHtml.php | 73 + .../SugarFields/Fields/Id/SugarFieldId.php | 58 + .../SugarFields/Fields/Iframe/DetailView.tpl | 49 + .../SugarFields/Fields/Iframe/EditView.tpl | 49 + include/SugarFields/Fields/Int/DetailView.tpl | 48 + include/SugarFields/Fields/Int/EditView.tpl | 44 + .../Fields/Int/RangeSearchForm.tpl | 107 + include/SugarFields/Fields/Int/SearchForm.tpl | 46 + .../SugarFields/Fields/Int/SugarFieldInt.php | 103 + .../SugarFields/Fields/Link/DetailView.tpl | 50 + include/SugarFields/Fields/Link/EditView.tpl | 47 + include/SugarFields/Fields/Link/ListView.tpl | 39 + .../Fields/Multienum/DetailView.tpl | 47 + .../SugarFields/Fields/Multienum/EditView.tpl | 45 + .../Fields/Multienum/EditViewFunction.tpl | 41 + .../SugarFields/Fields/Multienum/ListView.tpl | 45 + .../Fields/Multienum/SearchView.tpl | 38 + .../Fields/Multienum/SugarFieldMultienum.php | 117 + .../SugarFields/Fields/Parent/DetailView.tpl | 47 + .../SugarFields/Fields/Parent/EditView.tpl | 97 + .../SugarFields/Fields/Parent/SearchView.tpl | 76 + .../Fields/Parent/SugarFieldParent.php | 169 + .../SugarFields/Fields/Password/EditView.tpl | 40 + .../Fields/Password/SugarFieldPassword.php | 56 + include/SugarFields/Fields/Phone/EditView.tpl | 50 + .../Fields/Phone/SugarFieldPhone.php | 56 + .../Fields/Radioenum/DetailView.tpl | 45 + .../SugarFields/Fields/Radioenum/EditView.tpl | 52 + .../Fields/Readonly/SugarFieldReadonly.php | 45 + .../SugarFields/Fields/Relate/DetailView.tpl | 49 + .../SugarFields/Fields/Relate/EditView.tpl | 76 + .../SugarFields/Fields/Relate/SearchView.tpl | 50 + .../Fields/Relate/SugarFieldRelate.php | 368 + .../Fields/Text/ClassicEditView.tpl | 45 + .../SugarFields/Fields/Text/DetailView.tpl | 49 + include/SugarFields/Fields/Text/EditView.tpl | 57 + .../Fields/Text/SugarFieldText.php | 77 + include/SugarFields/Fields/URL/DetailView.tpl | 52 + include/SugarFields/Fields/URL/EditView.tpl | 56 + include/SugarFields/Fields/URL/ListView.tpl | 45 + .../Fields/Username/DetailView.tpl | 43 + .../Fields/Username/SugarFieldUsername.php | 46 + .../Parsers/DetailViewMetaParser.php | 192 + .../Parsers/EditViewMetaParser.php | 342 + include/SugarFields/Parsers/MetaParser.php | 808 + .../Parsers/QuickCreateMetaParser.php | 266 + .../Parsers/Rules/AccountsParseRule.php | 68 + .../Parsers/Rules/ActivitiesParseRule.php | 78 + .../SugarFields/Parsers/Rules/AddressRule.php | 154 + .../SugarFields/Parsers/Rules/BaseRule.php | 95 + .../Parsers/Rules/BugsParseRule.php | 63 + .../Parsers/Rules/CallsParseRule.php | 69 + .../Parsers/Rules/CampaignsParseRule.php | 75 + .../Parsers/Rules/ContactsParseRule.php | 82 + .../Parsers/Rules/ContractsParseRule.php | 63 + .../Parsers/Rules/DocumentsParseRule.php | 97 + .../Parsers/Rules/EmailAddressRule.php | 122 + .../Parsers/Rules/EmptyRowRule.php | 91 + .../Parsers/Rules/LeadsParseRule.php | 66 + .../Parsers/Rules/MeetingsParseRule.php | 65 + .../Parsers/Rules/NotesParseRule.php | 65 + .../Parsers/Rules/OpportunitiesParseRule.php | 63 + .../SugarFields/Parsers/Rules/ParseRules.php | 71 + .../Parsers/Rules/ProductsParseRule.php | 69 + .../Parsers/Rules/QuotesParseRule.php | 131 + .../Parsers/Rules/UndefinedVardefRule.php | 75 + .../Parsers/Rules/VariableCleanupRule.php | 106 + .../Rules/VariableSubstitutionRule.php | 137 + .../Parsers/SearchFormMetaParser.php | 270 + include/SugarFields/SugarFieldHandler.php | 151 + include/SugarFolders/SugarFolders.php | 985 + include/SugarLogger/LoggerManager.php | 208 + include/SugarLogger/LoggerTemplate.php | 59 + include/SugarLogger/SugarLogger.php | 231 + include/SugarOauth.php | 153 + include/SugarObjects/LanguageManager.php | 262 + include/SugarObjects/SugarConfig.php | 78 + include/SugarObjects/SugarRegistry.php | 77 + include/SugarObjects/SugarSession.php | 101 + include/SugarObjects/VardefManager.php | 284 + .../assignable/language/en_us.lang.php | 40 + .../implements/assignable/vardefs.php | 92 + .../team_security/language/en_us.lang.php | 40 + .../implements/team_security/vardefs.php | 75 + .../SugarObjects/templates/basic/Basic.php | 55 + .../Dashlets/Dashlet/m-n-Dashlet.meta.php | 52 + .../basic/Dashlets/Dashlet/m-n-Dashlet.php | 63 + .../templates/basic/icons/Createbasic.gif | Bin 0 -> 637 bytes .../templates/basic/icons/basic.gif | Bin 0 -> 654 bytes .../templates/basic/icons/basic_32.gif | Bin 0 -> 1107 bytes .../templates/basic/language/en_us.lang.php | 55 + .../templates/basic/metadata/SearchFields.php | 54 + .../basic/metadata/dashletviewdefs.php | 60 + .../basic/metadata/detailviewdefs.php | 73 + .../templates/basic/metadata/editviewdefs.php | 64 + .../templates/basic/metadata/listviewdefs.php | 56 + .../templates/basic/metadata/metafiles.php | 52 + .../templates/basic/metadata/popupdefs.php | 52 + .../basic/metadata/quickcreatedefs.php | 60 + .../templates/basic/metadata/searchdefs.php | 60 + .../basic/metadata/subpanels/default.php | 71 + .../SugarObjects/templates/basic/vardefs.php | 195 + .../templates/company/Company.php | 83 + .../SugarObjects/templates/company/config.php | 44 + .../templates/company/icons/Createcompany.gif | Bin 0 -> 624 bytes .../templates/company/icons/company.gif | Bin 0 -> 642 bytes .../templates/company/icons/company_32.gif | Bin 0 -> 1146 bytes .../language/application/en_us.lang.php | 62 + .../templates/company/language/en_us.lang.php | 136 + .../company/metadata/SearchFields.php | 84 + .../company/metadata/dashletviewdefs.php | 59 + .../company/metadata/detailviewdefs.php | 86 + .../company/metadata/editviewdefs.php | 98 + .../company/metadata/listviewdefs.php | 124 + .../templates/company/metadata/metafiles.php | 52 + .../templates/company/metadata/popupdefs.php | 65 + .../company/metadata/quickcreatedefs.php | 74 + .../templates/company/metadata/searchdefs.php | 78 + .../company/metadata/subpanels/default.php | 83 + .../templates/company/vardefs.php | 365 + include/SugarObjects/templates/file/File.php | 108 + .../templates/file/controller.php | 71 + .../templates/file/icons/Createfile.gif | Bin 0 -> 610 bytes .../templates/file/icons/file.gif | Bin 0 -> 616 bytes .../templates/file/icons/file_32.gif | Bin 0 -> 1012 bytes .../file/language/application/en_us.lang.php | 72 + .../templates/file/language/en_us.lang.php | 123 + .../templates/file/metadata/SearchFields.php | 66 + .../file/metadata/dashletviewdefs.php | 60 + .../file/metadata/detailviewdefs.php | 100 + .../templates/file/metadata/editviewdefs.php | 101 + .../templates/file/metadata/listviewdefs.php | 86 + .../templates/file/metadata/metafiles.php | 53 + .../file/metadata/quickcreatedefs.php | 100 + .../templates/file/metadata/searchdefs.php | 65 + .../file/metadata/subpanels/default.php | 91 + .../SugarObjects/templates/file/vardefs.php | 158 + .../templates/file/views/view.edit.php | 63 + .../SugarObjects/templates/issue/Issue.php | 45 + .../SugarObjects/templates/issue/config.php | 39 + .../templates/issue/icons/Createissue.gif | Bin 0 -> 560 bytes .../templates/issue/icons/issue.gif | Bin 0 -> 574 bytes .../templates/issue/icons/issue_32.gif | Bin 0 -> 932 bytes .../issue/language/application/en_us.lang.php | 77 + .../templates/issue/language/en_us.lang.php | 69 + .../templates/issue/metadata/SearchFields.php | 65 + .../issue/metadata/dashletviewdefs.php | 59 + .../issue/metadata/detailviewdefs.php | 94 + .../templates/issue/metadata/editviewdefs.php | 87 + .../templates/issue/metadata/listviewdefs.php | 74 + .../templates/issue/metadata/metafiles.php | 52 + .../templates/issue/metadata/popupdefs.php | 53 + .../issue/metadata/quickcreatedefs.php | 82 + .../templates/issue/metadata/searchdefs.php | 66 + .../issue/metadata/subpanels/default.php | 93 + .../SugarObjects/templates/issue/vardefs.php | 130 + .../SugarObjects/templates/person/Person.php | 147 + .../SugarObjects/templates/person/config.php | 39 + .../templates/person/icons/Createperson.gif | Bin 0 -> 595 bytes .../templates/person/icons/person.gif | Bin 0 -> 607 bytes .../templates/person/icons/person_32.gif | Bin 0 -> 989 bytes .../templates/person/language/en_us.lang.php | 83 + .../person/metadata/SearchFields.php | 71 + .../person/metadata/dashletviewdefs.php | 59 + .../person/metadata/detailviewdefs.php | 135 + .../person/metadata/editviewdefs.php | 114 + .../person/metadata/listviewdefs.php | 100 + .../templates/person/metadata/metafiles.php | 52 + .../templates/person/metadata/popupdefs.php | 51 + .../person/metadata/quickcreatedefs.php | 84 + .../templates/person/metadata/searchdefs.php | 62 + .../person/metadata/subpanels/default.php | 95 + .../SugarObjects/templates/person/vardefs.php | 420 + .../SugarObjects/templates/sale/Chance.php | 55 + include/SugarObjects/templates/sale/Sale.php | 104 + .../SugarObjects/templates/sale/config.php | 45 + .../templates/sale/icons/Createchance.gif | Bin 0 -> 599 bytes .../templates/sale/icons/Createsale.gif | Bin 0 -> 579 bytes .../templates/sale/icons/chance.gif | Bin 0 -> 617 bytes .../templates/sale/icons/chance_32.gif | Bin 0 -> 1180 bytes .../templates/sale/icons/sale.gif | Bin 0 -> 583 bytes .../templates/sale/icons/sale_32.gif | Bin 0 -> 834 bytes .../sale/language/application/en_us.lang.php | 56 + .../templates/sale/language/en_us.lang.php | 139 + .../templates/sale/metadata/SearchFields.php | 79 + .../sale/metadata/dashletviewdefs.php | 60 + .../sale/metadata/detailviewdefs.php | 68 + .../templates/sale/metadata/editviewdefs.php | 88 + .../templates/sale/metadata/listviewdefs.php | 98 + .../templates/sale/metadata/metafiles.php | 56 + .../templates/sale/metadata/popupdefs.php | 62 + .../sale/metadata/quickcreatedefs.php | 83 + .../templates/sale/metadata/searchdefs.php | 71 + .../sale/metadata/subpanels/default.php | 100 + .../SugarObjects/templates/sale/vardefs.php | 189 + include/SugarPHPMailer.php | 401 + include/SugarTheme/SugarTheme.php | 1157 + include/SugarTheme/cssmin.php | 208 + include/SugarTheme/getImage.php | 99 + include/SugarTinyMCE.php | 220 + include/Sugar_Smarty.php | 66 + include/Sugarpdf/FontManager.php | 430 + include/Sugarpdf/Sugarpdf.php | 658 + include/Sugarpdf/SugarpdfFactory.php | 146 + include/Sugarpdf/SugarpdfHelper.php | 193 + include/Sugarpdf/sugarpdf/sugarpdf.smarty.php | 108 + include/Sugarpdf/sugarpdf_config.php | 341 + include/Sugarpdf/sugarpdf_default.php | 110 + include/TemplateHandler/TemplateHandler.php | 462 + include/TimeDate.php | 1809 + include/VarDefHandler/VarDefHandler.php | 228 + include/VarDefHandler/listvardefoverride.php | 89 + include/VarDefHandler/vardef_meta_arrays.php | 317 + include/connectors/ConnectorFactory.php | 81 + include/connectors/component.php | 344 + include/connectors/filters/FilterFactory.php | 81 + include/connectors/filters/default/filter.php | 56 + .../formatters/FormatterFactory.php | 96 + .../formatters/default/company_detail.js | 42 + .../formatters/default/formatter.php | 149 + .../formatters/ext/rest/tpls/default.tpl | 37 + .../formatters/ext/soap/tpls/default.tpl | 84 + include/connectors/sources/SourceFactory.php | 74 + include/connectors/sources/default/source.php | 355 + include/connectors/sources/ext/rest/rest.php | 70 + include/connectors/sources/ext/soap/soap.php | 88 + include/connectors/sources/loc/xml.php | 55 + include/connectors/utils/ConnectorUtils.php | 957 + include/contextMenus/contextMenu.php | 107 + .../contextMenus/menuDefs/sugarAccount.php | 73 + include/contextMenus/menuDefs/sugarObject.php | 45 + include/contextMenus/menuDefs/sugarPerson.php | 61 + include/controller/Controller.php | 338 + include/database/DBHelper.php | 1358 + include/database/DBManager.php | 1923 + include/database/DBManagerFactory.php | 149 + include/database/FreeTDSHelper.php | 180 + include/database/FreeTDSManager.php | 169 + include/database/MssqlHelper.php | 777 + include/database/MssqlManager.php | 1309 + include/database/MysqlHelper.php | 522 + include/database/MysqlManager.php | 558 + include/database/MysqliHelper.php | 55 + include/database/MysqliManager.php | 316 + include/database/PearDatabase.php | 133 + include/database/SqlsrvHelper.php | 323 + include/database/SqlsrvManager.php | 459 + include/dir_inc.php | 248 + include/entryPoint.php | 226 + include/export_utils.php | 330 + include/externalAPI/Base/ExternalAPIBase.php | 233 + .../externalAPI/Base/ExternalAPIPlugin.php | 61 + .../Base/ExternalOAuthAPIPlugin.php | 59 + include/externalAPI/Base/OAuthPluginBase.php | 199 + include/externalAPI/Base/WebDocument.php | 44 + include/externalAPI/Base/WebFeed.php | 40 + include/externalAPI/Base/WebMeeting.php | 45 + include/externalAPI/ExternalAPIFactory.php | 291 + include/fonts/Courier-Bold.afm | 342 + include/fonts/Courier-BoldOblique.afm | 342 + include/fonts/Courier-Oblique.afm | 342 + include/fonts/Courier.afm | 342 + include/fonts/Helvetica-Bold.afm | 2827 ++ include/fonts/Helvetica-BoldOblique.afm | 2827 ++ include/fonts/Helvetica-Oblique.afm | 3051 ++ include/fonts/Helvetica.afm | 3051 ++ include/fonts/License.html | 1 + include/fonts/Times-Bold.afm | 2588 ++ include/fonts/Times-BoldItalic.afm | 2384 ++ include/fonts/Times-Italic.afm | 2667 ++ include/fonts/Times-Roman.afm | 2419 ++ include/formbase.php | 291 + include/generic/DeleteRelationship.php | 131 + include/generic/LayoutManager.php | 343 + include/generic/Save2.php | 284 + include/generic/SugarWidgets/SugarWidget.php | 92 + .../generic/SugarWidgets/SugarWidgetField.php | 235 + .../SugarWidgets/SugarWidgetFieldbool.php | 120 + .../SugarWidgets/SugarWidgetFieldchar.php | 45 + .../SugarWidgets/SugarWidgetFieldcurrency.php | 185 + .../SugarWidgets/SugarWidgetFielddate.php | 434 + .../SugarWidgetFielddatepicker.php | 65 + .../SugarWidgets/SugarWidgetFielddatetime.php | 818 + .../SugarWidgetFielddatetimecombo.php | 123 + .../SugarWidgets/SugarWidgetFielddecimal.php | 49 + .../SugarWidgets/SugarWidgetFielddouble.php | 47 + .../SugarWidgets/SugarWidgetFieldemail.php | 45 + .../SugarWidgets/SugarWidgetFieldenum.php | 224 + .../SugarWidgets/SugarWidgetFieldfile.php | 45 + .../SugarWidgets/SugarWidgetFieldfloat.php | 86 + .../SugarWidgets/SugarWidgetFieldfullname.php | 52 + .../SugarWidgets/SugarWidgetFieldid.php | 50 + .../SugarWidgets/SugarWidgetFieldimage.php | 47 + .../SugarWidgets/SugarWidgetFieldint.php | 86 + .../SugarWidgets/SugarWidgetFieldlongtext.php | 46 + .../SugarWidgetFieldmultienum.php | 92 + .../SugarWidgets/SugarWidgetFieldname.php | 310 + .../SugarWidgets/SugarWidgetFieldnum.php | 44 + .../SugarWidgetFieldparent_type.php | 60 + .../SugarWidgets/SugarWidgetFieldphone.php | 45 + .../SugarWidgetFieldradioenum.php | 44 + .../SugarWidgets/SugarWidgetFieldrelate.php | 78 + .../SugarWidgetFieldsingleenum.php | 71 + .../SugarWidgets/SugarWidgetFieldtext.php | 86 + .../SugarWidgets/SugarWidgetFieldtime.php | 71 + .../SugarWidgets/SugarWidgetFieldurl.php | 44 + .../SugarWidgetFielduser_name.php | 51 + .../SugarWidgets/SugarWidgetFieldvarchar.php | 90 + .../SugarWidgets/SugarWidgetReportField.php | 353 + ...garWidgetSubPanelActivitiesStatusField.php | 69 + .../SugarWidgetSubPanelCloseButton.php | 69 + .../SugarWidgetSubPanelConcat.php | 62 + .../SugarWidgetSubPanelDetailViewLink.php | 137 + .../SugarWidgetSubPanelEditButton.php | 69 + .../SugarWidgetSubPanelEditRoleButton.php | 73 + .../SugarWidgetSubPanelEmailLink.php | 135 + .../SugarWidgetSubPanelGetLatestButton.php | 83 + .../SugarWidgets/SugarWidgetSubPanelIcon.php | 163 + .../SugarWidgetSubPanelLoadSignedButton.php | 80 + .../SugarWidgetSubPanelRemoveButton.php | 121 + ...ugarWidgetSubPanelRemoveButtonMeetings.php | 121 + ...ugarWidgetSubPanelRemoveButtonProjects.php | 125 + ...garWidgetSubPanelTopArchiveEmailButton.php | 81 + .../SugarWidgetSubPanelTopButton.php | 351 + ...ugarWidgetSubPanelTopButtonQuickCreate.php | 192 + ...garWidgetSubPanelTopComposeEmailButton.php | 88 + ...dgetSubPanelTopCreateAccountNameButton.php | 82 + ...ubPanelTopCreateCampaignLogEntryButton.php | 152 + ...rWidgetSubPanelTopCreateLeadNameButton.php | 120 + ...SugarWidgetSubPanelTopCreateNoteButton.php | 161 + ...SugarWidgetSubPanelTopCreateTaskButton.php | 161 + ...garWidgetSubPanelTopScheduleCallButton.php | 160 + ...WidgetSubPanelTopScheduleMeetingButton.php | 165 + .../SugarWidgetSubPanelTopSelectButton.php | 165 + ...rWidgetSubPanelTopSelectContactsButton.php | 175 + ...ugarWidgetSubPanelTopSelectUsersButton.php | 180 + .../SugarWidgetSubPanelTopSummaryButton.php | 80 + include/globalControlLinks.php | 88 + include/images/1.gif | Bin 0 -> 2603 bytes include/images/SugarPlanet.swf | Bin 0 -> 444571 bytes include/images/blank.gif | Bin 0 -> 43 bytes include/images/cube_bg.gif | Bin 0 -> 4954 bytes include/images/default_user_feed_picture.png | Bin 0 -> 3821 bytes include/images/docs.png | Bin 0 -> 1956 bytes include/images/forums.png | Bin 0 -> 3689 bytes include/images/install_themes.jpg | Bin 0 -> 115308 bytes include/images/iphone-listArrow.png | Bin 0 -> 259 bytes include/images/iphone-toolbar.png | Bin 0 -> 171 bytes include/images/kb.png | Bin 0 -> 2880 bytes include/images/options.gif | Bin 0 -> 125 bytes include/images/options_up.gif | Bin 0 -> 125 bytes include/images/powered_by_sugarcrm.gif | Bin 0 -> 1242 bytes include/images/poweredby_sugarcrm.png | Bin 0 -> 4579 bytes include/images/rss_xml.gif | Bin 0 -> 121 bytes include/images/seed_chris_id.gif | Bin 0 -> 3037 bytes include/images/seed_jim_id.gif | Bin 0 -> 2885 bytes include/images/seed_max_id.gif | Bin 0 -> 3090 bytes include/images/seed_sally_id.gif | Bin 0 -> 3315 bytes include/images/seed_sarah_id.gif | Bin 0 -> 3015 bytes include/images/seed_will_id.gif | Bin 0 -> 3210 bytes include/images/spacer.png | Bin 0 -> 3596 bytes include/images/sugar_icon.ico | Bin 0 -> 894 bytes include/images/sugar_md_open.png | Bin 0 -> 2169 bytes include/images/sugar_wizard_welcome.jpg | Bin 0 -> 106330 bytes include/images/sugarcrm_about_logo.gif | Bin 0 -> 2000 bytes include/images/sugarcrm_copyright_logo.jpg | Bin 0 -> 4860 bytes include/images/sugarcrm_login.png | Bin 0 -> 1548 bytes include/images/sugarsales_myarea.png | Bin 0 -> 2846 bytes include/images/university.png | Bin 0 -> 3933 bytes include/images/wiki.png | Bin 0 -> 3698 bytes include/javascript/calendar.js | 58 + include/javascript/cookie.js | 56 + include/javascript/dashlets.js | 38 + include/javascript/getYUIComboFile.php | 97 + include/javascript/include.js | 18 + include/javascript/iscroll.js | 66 + include/javascript/javascript.php | 265 + include/javascript/jsAlerts.php | 218 + include/javascript/jsclass_async.js | 68 + include/javascript/jsclass_base.js | 149 + include/javascript/menu.js | 85 + include/javascript/overlibmws.js | 289 + include/javascript/overlibmws_iframe.js | 93 + include/javascript/popup_helper.js | 69 + include/javascript/popup_parent_helper.js | 84 + include/javascript/quickCompose.js | 22 + include/javascript/quicksearch.js | 57 + include/javascript/report_additionals.js | 402 + include/javascript/sugar_3.js | 611 + .../sugar_connection_event_listener.js | 37 + include/javascript/sugar_grp1.js | 849 + include/javascript/sugar_grp1_yui.js | 7714 ++++ include/javascript/sugar_grp_emails.js | 9985 +++++ include/javascript/sugar_grp_overlib.js | 384 + include/javascript/sugar_grp_quickcomp.js | 5458 +++ include/javascript/sugar_grp_yui2.js | 31 + include/javascript/sugar_grp_yui_widgets.css | 55 + include/javascript/sugar_grp_yui_widgets.js | 173 + .../javascript/sugarwidgets/SugarYUILoader.js | 36 + .../sugarwidgets/SugarYUIWidgets.js | 80 + include/javascript/swfobject.js | 45 + include/javascript/tiny_mce/langs/en.js | 154 + include/javascript/tiny_mce/license.txt | 504 + .../tiny_mce/plugins/advhr/css/advhr.css | 5 + .../tiny_mce/plugins/advhr/editor_plugin.js | 1 + .../plugins/advhr/editor_plugin_src.js | 54 + .../tiny_mce/plugins/advhr/js/rule.js | 43 + .../tiny_mce/plugins/advhr/langs/en_dlg.js | 5 + .../tiny_mce/plugins/advhr/rule.htm | 63 + .../plugins/advimage/css/advimage.css | 13 + .../plugins/advimage/editor_plugin.js | 1 + .../plugins/advimage/editor_plugin_src.js | 47 + .../tiny_mce/plugins/advimage/image.htm | 238 + .../tiny_mce/plugins/advimage/img/sample.gif | Bin 0 -> 1624 bytes .../tiny_mce/plugins/advimage/js/image.js | 441 + .../tiny_mce/plugins/advimage/langs/en_dlg.js | 43 + .../tiny_mce/plugins/advlink/css/advlink.css | 8 + .../tiny_mce/plugins/advlink/editor_plugin.js | 1 + .../plugins/advlink/editor_plugin_src.js | 58 + .../tiny_mce/plugins/advlink/js/advlink.js | 527 + .../tiny_mce/plugins/advlink/langs/en_dlg.js | 52 + .../tiny_mce/plugins/advlink/link.htm | 339 + .../plugins/autosave/editor_plugin.js | 1 + .../plugins/autosave/editor_plugin_src.js | 51 + .../tiny_mce/plugins/bbcode/editor_plugin.js | 1 + .../plugins/bbcode/editor_plugin_src.js | 117 + .../plugins/compat2x/editor_plugin.js | 1 + .../plugins/compat2x/editor_plugin_src.js | 616 + .../plugins/contextmenu/editor_plugin.js | 1 + .../plugins/contextmenu/editor_plugin_src.js | 95 + .../plugins/directionality/editor_plugin.js | 1 + .../directionality/editor_plugin_src.js | 79 + .../plugins/emotions/editor_plugin.js | 1 + .../plugins/emotions/editor_plugin_src.js | 40 + .../tiny_mce/plugins/emotions/emotions.htm | 41 + .../plugins/emotions/img/smiley-cool.gif | Bin 0 -> 354 bytes .../plugins/emotions/img/smiley-cry.gif | Bin 0 -> 329 bytes .../emotions/img/smiley-embarassed.gif | Bin 0 -> 331 bytes .../emotions/img/smiley-foot-in-mouth.gif | Bin 0 -> 344 bytes .../plugins/emotions/img/smiley-frown.gif | Bin 0 -> 340 bytes .../plugins/emotions/img/smiley-innocent.gif | Bin 0 -> 336 bytes .../plugins/emotions/img/smiley-kiss.gif | Bin 0 -> 338 bytes .../plugins/emotions/img/smiley-laughing.gif | Bin 0 -> 344 bytes .../emotions/img/smiley-money-mouth.gif | Bin 0 -> 321 bytes .../plugins/emotions/img/smiley-sealed.gif | Bin 0 -> 325 bytes .../plugins/emotions/img/smiley-smile.gif | Bin 0 -> 345 bytes .../plugins/emotions/img/smiley-surprised.gif | Bin 0 -> 342 bytes .../emotions/img/smiley-tongue-out.gif | Bin 0 -> 328 bytes .../plugins/emotions/img/smiley-undecided.gif | Bin 0 -> 337 bytes .../plugins/emotions/img/smiley-wink.gif | Bin 0 -> 351 bytes .../plugins/emotions/img/smiley-yell.gif | Bin 0 -> 336 bytes .../tiny_mce/plugins/emotions/js/emotions.js | 22 + .../tiny_mce/plugins/emotions/langs/en_dlg.js | 20 + .../tiny_mce/plugins/example/dialog.htm | 27 + .../tiny_mce/plugins/example/editor_plugin.js | 1 + .../plugins/example/editor_plugin_src.js | 81 + .../tiny_mce/plugins/example/img/example.gif | Bin 0 -> 87 bytes .../tiny_mce/plugins/example/js/dialog.js | 19 + .../tiny_mce/plugins/example/langs/en.js | 3 + .../tiny_mce/plugins/example/langs/en_dlg.js | 3 + .../plugins/fullpage/css/fullpage.css | 182 + .../plugins/fullpage/editor_plugin.js | 1 + .../plugins/fullpage/editor_plugin_src.js | 142 + .../tiny_mce/plugins/fullpage/fullpage.htm | 577 + .../tiny_mce/plugins/fullpage/js/fullpage.js | 461 + .../tiny_mce/plugins/fullpage/langs/en_dlg.js | 85 + .../plugins/fullscreen/editor_plugin.js | 1 + .../plugins/fullscreen/editor_plugin_src.js | 145 + .../plugins/fullscreen/fullscreen.htm | 111 + .../tiny_mce/plugins/iespell/editor_plugin.js | 1 + .../plugins/iespell/editor_plugin_src.js | 51 + .../plugins/inlinepopups/editor_plugin.js | 1 + .../plugins/inlinepopups/editor_plugin_src.js | 632 + .../skins/clearlooks2/img/alert.gif | Bin 0 -> 818 bytes .../skins/clearlooks2/img/button.gif | Bin 0 -> 280 bytes .../skins/clearlooks2/img/buttons.gif | Bin 0 -> 1195 bytes .../skins/clearlooks2/img/confirm.gif | Bin 0 -> 915 bytes .../skins/clearlooks2/img/corners.gif | Bin 0 -> 911 bytes .../skins/clearlooks2/img/horizontal.gif | Bin 0 -> 769 bytes .../skins/clearlooks2/img/vertical.gif | Bin 0 -> 92 bytes .../inlinepopups/skins/clearlooks2/window.css | 90 + .../plugins/inlinepopups/template.htm | 387 + .../plugins/insertdatetime/editor_plugin.js | 1 + .../insertdatetime/editor_plugin_src.js | 80 + .../tiny_mce/plugins/layer/editor_plugin.js | 1 + .../plugins/layer/editor_plugin_src.js | 209 + .../tiny_mce/plugins/media/css/content.css | 6 + .../tiny_mce/plugins/media/css/media.css | 16 + .../tiny_mce/plugins/media/editor_plugin.js | 1 + .../plugins/media/editor_plugin_src.js | 400 + .../tiny_mce/plugins/media/img/flash.gif | Bin 0 -> 241 bytes .../tiny_mce/plugins/media/img/flv_player.swf | Bin 0 -> 11668 bytes .../tiny_mce/plugins/media/img/quicktime.gif | Bin 0 -> 303 bytes .../tiny_mce/plugins/media/img/realmedia.gif | Bin 0 -> 439 bytes .../tiny_mce/plugins/media/img/shockwave.gif | Bin 0 -> 387 bytes .../tiny_mce/plugins/media/img/trans.gif | Bin 0 -> 43 bytes .../plugins/media/img/windowsmedia.gif | Bin 0 -> 415 bytes .../tiny_mce/plugins/media/js/embed.js | 73 + .../tiny_mce/plugins/media/js/media.js | 630 + .../tiny_mce/plugins/media/langs/en_dlg.js | 103 + .../tiny_mce/plugins/media/media.htm | 824 + .../plugins/nonbreaking/editor_plugin.js | 1 + .../plugins/nonbreaking/editor_plugin_src.js | 50 + .../plugins/noneditable/editor_plugin.js | 1 + .../plugins/noneditable/editor_plugin_src.js | 87 + .../plugins/pagebreak/css/content.css | 1 + .../plugins/pagebreak/editor_plugin.js | 1 + .../plugins/pagebreak/editor_plugin_src.js | 74 + .../plugins/pagebreak/img/pagebreak.gif | Bin 0 -> 325 bytes .../tiny_mce/plugins/pagebreak/img/trans.gif | Bin 0 -> 43 bytes .../tiny_mce/plugins/paste/blank.htm | 22 + .../tiny_mce/plugins/paste/css/blank.css | 14 + .../tiny_mce/plugins/paste/css/pasteword.css | 3 + .../tiny_mce/plugins/paste/editor_plugin.js | 1 + .../plugins/paste/editor_plugin_src.js | 394 + .../tiny_mce/plugins/paste/js/pastetext.js | 42 + .../tiny_mce/plugins/paste/js/pasteword.js | 56 + .../tiny_mce/plugins/paste/langs/en_dlg.js | 5 + .../tiny_mce/plugins/paste/pastetext.htm | 34 + .../tiny_mce/plugins/paste/pasteword.htm | 29 + .../tiny_mce/plugins/preview/editor_plugin.js | 1 + .../plugins/preview/editor_plugin_src.js | 50 + .../tiny_mce/plugins/preview/example.html | 28 + .../plugins/preview/jscripts/embed.js | 73 + .../tiny_mce/plugins/preview/preview.html | 19 + .../tiny_mce/plugins/print/editor_plugin.js | 1 + .../plugins/print/editor_plugin_src.js | 31 + .../tiny_mce/plugins/safari/blank.htm | 1 + .../tiny_mce/plugins/safari/editor_plugin.js | 1 + .../plugins/safari/editor_plugin_src.js | 514 + .../tiny_mce/plugins/save/editor_plugin.js | 1 + .../plugins/save/editor_plugin_src.js | 98 + .../searchreplace/css/searchreplace.css | 6 + .../plugins/searchreplace/editor_plugin.js | 1 + .../searchreplace/editor_plugin_src.js | 54 + .../plugins/searchreplace/js/searchreplace.js | 126 + .../plugins/searchreplace/langs/en_dlg.js | 16 + .../plugins/searchreplace/searchreplace.htm | 105 + .../plugins/spellchecker/css/content.css | 1 + .../plugins/spellchecker/editor_plugin.js | 1 + .../plugins/spellchecker/editor_plugin_src.js | 338 + .../plugins/spellchecker/img/wline.gif | Bin 0 -> 46 bytes .../tiny_mce/plugins/style/css/props.css | 13 + .../tiny_mce/plugins/style/editor_plugin.js | 1 + .../plugins/style/editor_plugin_src.js | 52 + .../tiny_mce/plugins/style/js/props.js | 641 + .../tiny_mce/plugins/style/langs/en_dlg.js | 63 + .../tiny_mce/plugins/style/props.htm | 731 + .../tiny_mce/plugins/table/cell.htm | 184 + .../tiny_mce/plugins/table/css/cell.css | 17 + .../tiny_mce/plugins/table/css/row.css | 25 + .../tiny_mce/plugins/table/css/table.css | 13 + .../tiny_mce/plugins/table/editor_plugin.js | 1 + .../plugins/table/editor_plugin_src.js | 1136 + .../tiny_mce/plugins/table/js/cell.js | 269 + .../tiny_mce/plugins/table/js/merge_cells.js | 29 + .../tiny_mce/plugins/table/js/row.js | 212 + .../tiny_mce/plugins/table/js/table.js | 413 + .../tiny_mce/plugins/table/langs/en_dlg.js | 74 + .../tiny_mce/plugins/table/merge_cells.htm | 38 + .../javascript/tiny_mce/plugins/table/row.htm | 161 + .../tiny_mce/plugins/table/table.htm | 193 + .../tiny_mce/plugins/template/blank.htm | 12 + .../plugins/template/css/template.css | 23 + .../plugins/template/editor_plugin.js | 1 + .../plugins/template/editor_plugin_src.js | 156 + .../tiny_mce/plugins/template/js/template.js | 106 + .../tiny_mce/plugins/template/langs/en_dlg.js | 15 + .../tiny_mce/plugins/template/template.htm | 39 + .../plugins/visualchars/editor_plugin.js | 1 + .../plugins/visualchars/editor_plugin_src.js | 73 + .../tiny_mce/plugins/xhtmlxtras/abbr.htm | 149 + .../tiny_mce/plugins/xhtmlxtras/acronym.htm | 149 + .../plugins/xhtmlxtras/attributes.htm | 154 + .../tiny_mce/plugins/xhtmlxtras/cite.htm | 149 + .../plugins/xhtmlxtras/css/attributes.css | 11 + .../tiny_mce/plugins/xhtmlxtras/css/popup.css | 9 + .../tiny_mce/plugins/xhtmlxtras/del.htm | 170 + .../plugins/xhtmlxtras/editor_plugin.js | 1 + .../plugins/xhtmlxtras/editor_plugin_src.js | 136 + .../tiny_mce/plugins/xhtmlxtras/ins.htm | 170 + .../tiny_mce/plugins/xhtmlxtras/js/abbr.js | 25 + .../tiny_mce/plugins/xhtmlxtras/js/acronym.js | 25 + .../plugins/xhtmlxtras/js/attributes.js | 123 + .../tiny_mce/plugins/xhtmlxtras/js/cite.js | 25 + .../tiny_mce/plugins/xhtmlxtras/js/del.js | 60 + .../plugins/xhtmlxtras/js/element_common.js | 231 + .../tiny_mce/plugins/xhtmlxtras/js/ins.js | 59 + .../plugins/xhtmlxtras/langs/en_dlg.js | 32 + .../tiny_mce/themes/advanced/about.htm | 56 + .../tiny_mce/themes/advanced/anchor.htm | 32 + .../tiny_mce/themes/advanced/charmap.htm | 54 + .../tiny_mce/themes/advanced/color_picker.htm | 76 + .../themes/advanced/editor_template.js | 1 + .../themes/advanced/editor_template_src.js | 1153 + .../tiny_mce/themes/advanced/image.htm | 86 + .../themes/advanced/img/colorpicker.jpg | Bin 0 -> 3189 bytes .../tiny_mce/themes/advanced/img/icons.gif | Bin 0 -> 11505 bytes .../tiny_mce/themes/advanced/js/about.js | 72 + .../tiny_mce/themes/advanced/js/anchor.js | 37 + .../tiny_mce/themes/advanced/js/charmap.js | 325 + .../themes/advanced/js/color_picker.js | 253 + .../tiny_mce/themes/advanced/js/image.js | 245 + .../tiny_mce/themes/advanced/js/link.js | 155 + .../themes/advanced/js/source_editor.js | 62 + .../tiny_mce/themes/advanced/langs/en.js | 62 + .../tiny_mce/themes/advanced/langs/en_dlg.js | 51 + .../tiny_mce/themes/advanced/link.htm | 64 + .../themes/advanced/skins/default/content.css | 32 + .../themes/advanced/skins/default/dialog.css | 114 + .../advanced/skins/default/img/buttons.png | Bin 0 -> 3274 bytes .../advanced/skins/default/img/items.gif | Bin 0 -> 70 bytes .../advanced/skins/default/img/menu_arrow.gif | Bin 0 -> 68 bytes .../advanced/skins/default/img/menu_check.gif | Bin 0 -> 70 bytes .../advanced/skins/default/img/progress.gif | Bin 0 -> 1787 bytes .../advanced/skins/default/img/tabs.gif | Bin 0 -> 1326 bytes .../themes/advanced/skins/default/ui.css | 214 + .../themes/advanced/skins/o2k7/content.css | 32 + .../themes/advanced/skins/o2k7/dialog.css | 113 + .../advanced/skins/o2k7/img/button_bg.png | Bin 0 -> 5859 bytes .../skins/o2k7/img/button_bg_black.png | Bin 0 -> 3736 bytes .../skins/o2k7/img/button_bg_silver.png | Bin 0 -> 5358 bytes .../themes/advanced/skins/o2k7/ui.css | 215 + .../themes/advanced/skins/o2k7/ui_black.css | 8 + .../themes/advanced/skins/o2k7/ui_silver.css | 5 + .../themes/advanced/source_editor.htm | 32 + .../tiny_mce/themes/simple/editor_template.js | 1 + .../themes/simple/editor_template_src.js | 85 + .../tiny_mce/themes/simple/img/icons.gif | Bin 0 -> 1440 bytes .../tiny_mce/themes/simple/langs/en.js | 11 + .../themes/simple/skins/default/content.css | 25 + .../themes/simple/skins/default/ui.css | 32 + .../themes/simple/skins/o2k7/content.css | 17 + .../simple/skins/o2k7/img/button_bg.png | Bin 0 -> 5102 bytes .../tiny_mce/themes/simple/skins/o2k7/ui.css | 35 + include/javascript/tiny_mce/tiny_mce.js | 1 + include/javascript/tiny_mce/tiny_mce_popup.js | 294 + include/javascript/tiny_mce/tiny_mce_src.js | 11101 ++++++ .../tiny_mce/utils/editable_selects.js | 69 + .../javascript/tiny_mce/utils/form_utils.js | 199 + include/javascript/tiny_mce/utils/mctabs.js | 76 + include/javascript/tiny_mce/utils/validate.js | 219 + include/javascript/yui/LICENSE.txt | 10 + include/javascript/yui/README | 338 + .../yui/build/animation/animation-min.js | 23 + .../yui/build/animation/animation.js | 1392 + .../build/assets/skins/sam/ajax-loader.gif | Bin 0 -> 3208 bytes .../yui/build/assets/skins/sam/asc.gif | Bin 0 -> 177 bytes .../build/assets/skins/sam/autocomplete.css | 7 + .../yui/build/assets/skins/sam/back-h.png | Bin 0 -> 334 bytes .../yui/build/assets/skins/sam/back-v.png | Bin 0 -> 338 bytes .../yui/build/assets/skins/sam/bar-h.png | Bin 0 -> 365 bytes .../yui/build/assets/skins/sam/bar-v.png | Bin 0 -> 387 bytes .../yui/build/assets/skins/sam/bg-h.gif | Bin 0 -> 212 bytes .../yui/build/assets/skins/sam/bg-v.gif | Bin 0 -> 481 bytes .../yui/build/assets/skins/sam/blankimage.png | Bin 0 -> 2314 bytes .../yui/build/assets/skins/sam/button.css | 7 + .../yui/build/assets/skins/sam/calendar.css | 8 + .../yui/build/assets/skins/sam/carousel.css | 7 + .../yui/build/assets/skins/sam/check0.gif | Bin 0 -> 608 bytes .../yui/build/assets/skins/sam/check1.gif | Bin 0 -> 622 bytes .../yui/build/assets/skins/sam/check2.gif | Bin 0 -> 609 bytes .../build/assets/skins/sam/colorpicker.css | 7 + .../yui/build/assets/skins/sam/container.css | 7 + .../yui/build/assets/skins/sam/datatable.css | 8 + .../yui/build/assets/skins/sam/desc.gif | Bin 0 -> 177 bytes .../build/assets/skins/sam/dt-arrow-dn.png | Bin 0 -> 116 bytes .../build/assets/skins/sam/dt-arrow-up.png | Bin 0 -> 116 bytes .../build/assets/skins/sam/editor-knob.gif | Bin 0 -> 138 bytes .../assets/skins/sam/editor-sprite-active.gif | Bin 0 -> 5614 bytes .../build/assets/skins/sam/editor-sprite.gif | Bin 0 -> 5690 bytes .../yui/build/assets/skins/sam/editor.css | 10 + .../assets/skins/sam/header_background.png | Bin 0 -> 158 bytes .../yui/build/assets/skins/sam/hue_bg.png | Bin 0 -> 1120 bytes .../build/assets/skins/sam/imagecropper.css | 7 + .../yui/build/assets/skins/sam/layout.css | 7 + .../build/assets/skins/sam/layout_sprite.png | Bin 0 -> 1409 bytes .../yui/build/assets/skins/sam/loading.gif | Bin 0 -> 2673 bytes .../yui/build/assets/skins/sam/logger.css | 7 + .../skins/sam/menu-button-arrow-disabled.png | Bin 0 -> 173 bytes .../assets/skins/sam/menu-button-arrow.png | Bin 0 -> 173 bytes .../yui/build/assets/skins/sam/menu.css | 7 + .../sam/menubaritem_submenuindicator.png | Bin 0 -> 3618 bytes .../menubaritem_submenuindicator_disabled.png | Bin 0 -> 3618 bytes .../assets/skins/sam/menuitem_checkbox.png | Bin 0 -> 3625 bytes .../skins/sam/menuitem_checkbox_disabled.png | Bin 0 -> 3625 bytes .../skins/sam/menuitem_submenuindicator.png | Bin 0 -> 3617 bytes .../menuitem_submenuindicator_disabled.png | Bin 0 -> 3617 bytes .../yui/build/assets/skins/sam/paginator.css | 7 + .../build/assets/skins/sam/picker_mask.png | Bin 0 -> 12174 bytes .../build/assets/skins/sam/profilerviewer.css | 7 + .../build/assets/skins/sam/progressbar.css | 7 + .../yui/build/assets/skins/sam/resize.css | 7 + .../build/assets/skins/sam/simpleeditor.css | 10 + .../yui/build/assets/skins/sam/skin.css | 36 + .../yui/build/assets/skins/sam/slider.css | 7 + .../skins/sam/split-button-arrow-active.png | Bin 0 -> 280 bytes .../skins/sam/split-button-arrow-disabled.png | Bin 0 -> 185 bytes .../skins/sam/split-button-arrow-focus.png | Bin 0 -> 185 bytes .../skins/sam/split-button-arrow-hover.png | Bin 0 -> 185 bytes .../assets/skins/sam/split-button-arrow.png | Bin 0 -> 185 bytes .../yui/build/assets/skins/sam/sprite.png | Bin 0 -> 3745 bytes .../yui/build/assets/skins/sam/sprite.psd | Bin 0 -> 118162 bytes .../yui/build/assets/skins/sam/tabview.css | 8 + .../assets/skins/sam/treeview-loading.gif | Bin 0 -> 2673 bytes .../assets/skins/sam/treeview-sprite.gif | Bin 0 -> 4326 bytes .../yui/build/assets/skins/sam/treeview.css | 7 + .../yui/build/assets/skins/sam/wait.gif | Bin 0 -> 1100 bytes .../yui/build/assets/skins/sam/yuitest.css | 7 + .../autocomplete/assets/autocomplete-core.css | 7 + .../assets/skins/sam/autocomplete-skin.css | 57 + .../assets/skins/sam/autocomplete.css | 7 + .../build/autocomplete/autocomplete-min.js | 12 + .../yui/build/autocomplete/autocomplete.js | 2966 ++ .../javascript/yui/build/base/base-min.css | 7 + include/javascript/yui/build/base/base.css | 131 + .../yui/build/button/assets/button-core.css | 44 + .../button/assets/skins/sam/button-skin.css | 219 + .../build/button/assets/skins/sam/button.css | 7 + .../skins/sam/menu-button-arrow-disabled.png | Bin 0 -> 173 bytes .../assets/skins/sam/menu-button-arrow.png | Bin 0 -> 173 bytes .../skins/sam/split-button-arrow-active.png | Bin 0 -> 280 bytes .../skins/sam/split-button-arrow-disabled.png | Bin 0 -> 185 bytes .../skins/sam/split-button-arrow-focus.png | Bin 0 -> 185 bytes .../skins/sam/split-button-arrow-hover.png | Bin 0 -> 185 bytes .../assets/skins/sam/split-button-arrow.png | Bin 0 -> 185 bytes .../javascript/yui/build/button/button-min.js | 11 + include/javascript/yui/build/button/button.js | 4633 +++ .../build/calendar/assets/calendar-core.css | 132 + .../yui/build/calendar/assets/calendar.css | 319 + .../yui/build/calendar/assets/calgrad.png | Bin 0 -> 497 bytes .../yui/build/calendar/assets/callt.gif | Bin 0 -> 93 bytes .../yui/build/calendar/assets/calrt.gif | Bin 0 -> 94 bytes .../yui/build/calendar/assets/calx.gif | Bin 0 -> 88 bytes .../assets/skins/sam/calendar-skin.css | 362 + .../calendar/assets/skins/sam/calendar.css | 8 + .../yui/build/calendar/calendar-min.js | 18 + .../javascript/yui/build/calendar/calendar.js | 7294 ++++ .../yui/build/carousel/assets/ajax-loader.gif | Bin 0 -> 3208 bytes .../build/carousel/assets/carousel-core.css | 88 + .../carousel/assets/skins/sam/ajax-loader.gif | Bin 0 -> 3208 bytes .../assets/skins/sam/carousel-skin.css | 142 + .../carousel/assets/skins/sam/carousel.css | 7 + .../yui/build/carousel/carousel-min.js | 12 + .../javascript/yui/build/carousel/carousel.js | 4349 +++ .../yui/build/charts/assets/charts.swf | Bin 0 -> 81768 bytes .../javascript/yui/build/charts/charts-min.js | 9 + include/javascript/yui/build/charts/charts.js | 2060 ++ .../colorpicker/assets/colorpicker-core.css | 6 + .../build/colorpicker/assets/hue_thumb.png | Bin 0 -> 195 bytes .../build/colorpicker/assets/picker_mask.png | Bin 0 -> 12174 bytes .../build/colorpicker/assets/picker_thumb.png | Bin 0 -> 192 bytes .../assets/skins/sam/colorpicker-skin.css | 105 + .../assets/skins/sam/colorpicker.css | 7 + .../colorpicker/assets/skins/sam/hue_bg.png | Bin 0 -> 1120 bytes .../assets/skins/sam/picker_mask.png | Bin 0 -> 12174 bytes .../yui/build/colorpicker/colorpicker-min.js | 9 + .../yui/build/colorpicker/colorpicker.js | 1763 + .../yui/build/connection/connection-min.js | 9 + .../yui/build/connection/connection.js | 1546 + .../yui/build/connection/connection.swf | Bin 0 -> 2423 bytes .../build/connection/connection_core-debug.js | 980 + .../build/connection/connection_core-min.js | 8 + .../yui/build/connection/connection_core.js | 957 + .../yui/build/container/assets/alrt16_1.gif | Bin 0 -> 971 bytes .../yui/build/container/assets/blck16_1.gif | Bin 0 -> 591 bytes .../yui/build/container/assets/close12_1.gif | Bin 0 -> 85 bytes .../build/container/assets/container-core.css | 176 + .../yui/build/container/assets/container.css | 324 + .../yui/build/container/assets/hlp16_1.gif | Bin 0 -> 928 bytes .../yui/build/container/assets/info16_1.gif | Bin 0 -> 601 bytes .../assets/skins/sam/container-skin.css | 242 + .../container/assets/skins/sam/container.css | 7 + .../yui/build/container/assets/tip16_1.gif | Bin 0 -> 552 bytes .../yui/build/container/assets/warn16_1.gif | Bin 0 -> 580 bytes .../yui/build/container/container-min.js | 19 + .../yui/build/container/container.js | 9052 +++++ .../yui/build/container/container_core-min.js | 14 + .../javascript/yui/build/cookie/cookie-min.js | 7 + include/javascript/yui/build/cookie/cookie.js | 482 + .../yui/build/datasource/datasource-min.js | 12 + .../yui/build/datasource/datasource.js | 2996 ++ .../build/datatable/assets/datatable-core.css | 93 + .../yui/build/datatable/assets/datatable.css | 49 + .../assets/skins/sam/datatable-skin.css | 240 + .../datatable/assets/skins/sam/datatable.css | 8 + .../assets/skins/sam/dt-arrow-dn.png | Bin 0 -> 116 bytes .../assets/skins/sam/dt-arrow-up.png | Bin 0 -> 116 bytes .../yui/build/datatable/datatable-min.js | 29 + .../yui/build/datatable/datatable.js | 17122 +++++++++ .../yui/build/datemath/datemath-debug.js | 408 + .../yui/build/datemath/datemath-min.js | 7 + .../javascript/yui/build/datemath/datemath.js | 408 + include/javascript/yui/build/dom/dom-min.js | 9 + include/javascript/yui/build/dom/dom.js | 1832 + .../yui/build/dragdrop/dragdrop-min.js | 10 + .../javascript/yui/build/dragdrop/dragdrop.js | 3601 ++ .../yui/build/editor/assets/editor-core.css | 602 + .../build/editor/assets/simpleeditor-core.css | 602 + .../editor/assets/skins/sam/blankimage.png | Bin 0 -> 2314 bytes .../editor/assets/skins/sam/editor-knob.gif | Bin 0 -> 138 bytes .../editor/assets/skins/sam/editor-skin.css | 711 + .../assets/skins/sam/editor-sprite-active.gif | Bin 0 -> 5614 bytes .../editor/assets/skins/sam/editor-sprite.gif | Bin 0 -> 5690 bytes .../build/editor/assets/skins/sam/editor.css | 10 + .../assets/skins/sam/simpleeditor-skin.css | 711 + .../editor/assets/skins/sam/simpleeditor.css | 10 + .../javascript/yui/build/editor/editor-min.js | 30 + include/javascript/yui/build/editor/editor.js | 9447 +++++ .../yui/build/editor/simpleeditor-min.js | 24 + .../yui/build/editor/simpleeditor.js | 7406 ++++ .../element-delegate-debug.js | 141 + .../element-delegate/element-delegate-min.js | 7 + .../element-delegate/element-delegate.js | 138 + .../yui/build/element/element-min.js | 8 + .../javascript/yui/build/element/element.js | 1090 + .../event-delegate/event-delegate-debug.js | 283 + .../event-delegate/event-delegate-min.js | 7 + .../build/event-delegate/event-delegate.js | 281 + .../event-mouseenter-debug.js | 219 + .../event-mouseenter/event-mouseenter-min.js | 7 + .../event-mouseenter/event-mouseenter.js | 219 + .../event-simulate/event-simulate-debug.js | 622 + .../event-simulate/event-simulate-min.js | 7 + .../build/event-simulate/event-simulate.js | 622 + .../javascript/yui/build/event/event-min.js | 11 + include/javascript/yui/build/event/event.js | 2500 ++ .../javascript/yui/build/fonts/fonts-min.css | 7 + include/javascript/yui/build/fonts/fonts.css | 56 + include/javascript/yui/build/get/get-min.js | 7 + include/javascript/yui/build/get/get.js | 755 + .../javascript/yui/build/grids/grids-min.css | 7 + include/javascript/yui/build/grids/grids.css | 467 + .../yui/build/history/assets/blank.html | 1 + .../yui/build/history/history-min.js | 7 + .../javascript/yui/build/history/history.js | 803 + .../imagecropper/assets/imagecropper-core.css | 33 + .../assets/skins/sam/imagecropper-skin.css | 16 + .../assets/skins/sam/imagecropper.css | 7 + .../build/imagecropper/imagecropper-min.js | 8 + .../yui/build/imagecropper/imagecropper.js | 889 + .../yui/build/imageloader/imageloader-min.js | 7 + .../yui/build/imageloader/imageloader.js | 481 + include/javascript/yui/build/json/json-min.js | 7 + include/javascript/yui/build/json/json.js | 538 + .../yui/build/layout/assets/layout-core.css | 158 + .../layout/assets/skins/sam/layout-skin.css | 207 + .../build/layout/assets/skins/sam/layout.css | 7 + .../layout/assets/skins/sam/layout_sprite.png | Bin 0 -> 1409 bytes .../javascript/yui/build/layout/layout-min.js | 11 + include/javascript/yui/build/layout/layout.js | 2290 ++ .../yui/build/logger/assets/logger-core.css | 7 + .../yui/build/logger/assets/logger.css | 57 + .../logger/assets/skins/sam/logger-skin.css | 55 + .../build/logger/assets/skins/sam/logger.css | 7 + .../javascript/yui/build/logger/logger-min.js | 9 + include/javascript/yui/build/logger/logger.js | 2104 ++ .../yui/build/menu/assets/menu-core.css | 242 + .../javascript/yui/build/menu/assets/menu.css | 503 + .../yui/build/menu/assets/menu_down_arrow.png | Bin 0 -> 3624 bytes .../menu/assets/menu_down_arrow_disabled.png | Bin 0 -> 3621 bytes .../yui/build/menu/assets/menu_up_arrow.png | Bin 0 -> 936 bytes .../menu/assets/menu_up_arrow_disabled.png | Bin 0 -> 936 bytes .../assets/menubaritem_submenuindicator.png | Bin 0 -> 3623 bytes .../menubaritem_submenuindicator_disabled.png | Bin 0 -> 3623 bytes .../menubaritem_submenuindicator_selected.png | Bin 0 -> 3623 bytes .../build/menu/assets/menuitem_checkbox.png | Bin 0 -> 956 bytes .../assets/menuitem_checkbox_disabled.png | Bin 0 -> 956 bytes .../assets/menuitem_checkbox_selected.png | Bin 0 -> 956 bytes .../menu/assets/menuitem_submenuindicator.png | Bin 0 -> 942 bytes .../menuitem_submenuindicator_disabled.png | Bin 0 -> 942 bytes .../menuitem_submenuindicator_selected.png | Bin 0 -> 942 bytes .../build/menu/assets/skins/sam/menu-skin.css | 339 + .../yui/build/menu/assets/skins/sam/menu.css | 7 + .../sam/menubaritem_submenuindicator.png | Bin 0 -> 3618 bytes .../menubaritem_submenuindicator_disabled.png | Bin 0 -> 3618 bytes .../assets/skins/sam/menuitem_checkbox.png | Bin 0 -> 3625 bytes .../skins/sam/menuitem_checkbox_disabled.png | Bin 0 -> 3625 bytes .../skins/sam/menuitem_submenuindicator.png | Bin 0 -> 3617 bytes .../menuitem_submenuindicator_disabled.png | Bin 0 -> 3617 bytes include/javascript/yui/build/menu/menu-min.js | 16 + include/javascript/yui/build/menu/menu.js | 9823 +++++ .../build/paginator/assets/paginator-core.css | 6 + .../assets/skins/sam/paginator-skin.css | 78 + .../paginator/assets/skins/sam/paginator.css | 7 + .../yui/build/paginator/paginator-min.js | 10 + .../yui/build/paginator/paginator.js | 2393 ++ .../yui/build/profiler/profiler-min.js | 7 + .../javascript/yui/build/profiler/profiler.js | 557 + .../assets/profilerviewer-core.css | 6 + .../profilerviewer/assets/skins/sam/asc.gif | Bin 0 -> 177 bytes .../profilerviewer/assets/skins/sam/desc.gif | Bin 0 -> 177 bytes .../assets/skins/sam/header_background.png | Bin 0 -> 158 bytes .../assets/skins/sam/profilerviewer-skin.css | 167 + .../assets/skins/sam/profilerviewer.css | 7 + .../profilerviewer/assets/skins/sam/wait.gif | Bin 0 -> 1100 bytes .../profilerviewer/profilerviewer-min.js | 9 + .../build/profilerviewer/profilerviewer.js | 1192 + .../progressbar/assets/progressbar-core.css | 85 + .../progressbar/assets/skins/sam/back-h.png | Bin 0 -> 334 bytes .../progressbar/assets/skins/sam/back-v.png | Bin 0 -> 338 bytes .../progressbar/assets/skins/sam/bar-h.png | Bin 0 -> 365 bytes .../progressbar/assets/skins/sam/bar-v.png | Bin 0 -> 387 bytes .../assets/skins/sam/progressbar-skin.css | 56 + .../assets/skins/sam/progressbar.css | 7 + .../build/progressbar/progressbar-debug.js | 691 + .../yui/build/progressbar/progressbar-min.js | 8 + .../yui/build/progressbar/progressbar.js | 677 + .../reset-fonts-grids/reset-fonts-grids.css | 7 + .../yui/build/reset-fonts/reset-fonts.css | 7 + .../javascript/yui/build/reset/reset-min.css | 7 + include/javascript/yui/build/reset/reset.css | 142 + .../yui/build/resize/assets/resize-core.css | 173 + .../resize/assets/skins/sam/layout_sprite.png | Bin 0 -> 1409 bytes .../resize/assets/skins/sam/resize-skin.css | 142 + .../build/resize/assets/skins/sam/resize.css | 7 + .../javascript/yui/build/resize/resize-min.js | 10 + include/javascript/yui/build/resize/resize.js | 1689 + .../yui/build/selector/selector-min.js | 8 + .../javascript/yui/build/selector/selector.js | 644 + .../yui/build/slider/assets/bg-fader.gif | Bin 0 -> 433 bytes .../yui/build/slider/assets/bg-h.gif | Bin 0 -> 212 bytes .../yui/build/slider/assets/bg-v-e.gif | Bin 0 -> 476 bytes .../yui/build/slider/assets/bg-v.gif | Bin 0 -> 481 bytes .../yui/build/slider/assets/left-thumb.png | Bin 0 -> 348 bytes .../yui/build/slider/assets/right-thumb.png | Bin 0 -> 356 bytes .../build/slider/assets/skins/sam/bg-h.gif | Bin 0 -> 212 bytes .../build/slider/assets/skins/sam/bg-v.gif | Bin 0 -> 481 bytes .../slider/assets/skins/sam/slider-skin.css | 24 + .../build/slider/assets/skins/sam/slider.css | 7 + .../yui/build/slider/assets/slider-core.css | 17 + .../yui/build/slider/assets/slider-skin.css | 20 + .../yui/build/slider/assets/thumb-bar.gif | Bin 0 -> 580 bytes .../yui/build/slider/assets/thumb-e.gif | Bin 0 -> 340 bytes .../yui/build/slider/assets/thumb-fader.gif | Bin 0 -> 645 bytes .../yui/build/slider/assets/thumb-n.gif | Bin 0 -> 612 bytes .../yui/build/slider/assets/thumb-s.gif | Bin 0 -> 615 bytes .../yui/build/slider/assets/thumb-w.gif | Bin 0 -> 340 bytes .../javascript/yui/build/slider/slider-min.js | 9 + include/javascript/yui/build/slider/slider.js | 2068 ++ .../yui/build/storage/storage-debug.js | 1185 + .../yui/build/storage/storage-min.js | 8 + .../javascript/yui/build/storage/storage.js | 1183 + .../yui/build/stylesheet/stylesheet-debug.js | 648 + .../yui/build/stylesheet/stylesheet-min.js | 7 + .../yui/build/stylesheet/stylesheet.js | 645 + include/javascript/yui/build/swf/swf-debug.js | 269 + include/javascript/yui/build/swf/swf-min.js | 7 + include/javascript/yui/build/swf/swf.js | 268 + .../yui/build/swfdetect/swfdetect-debug.js | 93 + .../yui/build/swfdetect/swfdetect-min.js | 7 + .../yui/build/swfdetect/swfdetect.js | 93 + include/javascript/yui/build/swfstore/swf.js | 238 + .../yui/build/swfstore/swfstore-debug.js | 470 + .../yui/build/swfstore/swfstore-min.js | 7 + .../javascript/yui/build/swfstore/swfstore.js | 453 + .../yui/build/swfstore/swfstore.swf | Bin 0 -> 4819 bytes .../yui/build/tabview/assets/border_tabs.css | 54 + .../yui/build/tabview/assets/loading.gif | Bin 0 -> 729 bytes .../yui/build/tabview/assets/skin-sam.css | 77 + .../tabview/assets/skins/sam/tabview-skin.css | 186 + .../tabview/assets/skins/sam/tabview.css | 8 + .../yui/build/tabview/assets/tabview-core.css | 133 + .../yui/build/tabview/assets/tabview.css | 77 + .../yui/build/tabview/tabview-min.js | 8 + .../javascript/yui/build/tabview/tabview.js | 987 + .../treeview/assets/skins/sam/check0.gif | Bin 0 -> 608 bytes .../treeview/assets/skins/sam/check1.gif | Bin 0 -> 622 bytes .../treeview/assets/skins/sam/check2.gif | Bin 0 -> 609 bytes .../treeview/assets/skins/sam/loading.gif | Bin 0 -> 2673 bytes .../assets/skins/sam/treeview-loading.gif | Bin 0 -> 2673 bytes .../assets/skins/sam/treeview-skin.css | 249 + .../assets/skins/sam/treeview-sprite.gif | Bin 0 -> 4326 bytes .../treeview/assets/skins/sam/treeview.css | 7 + .../build/treeview/assets/treeview-core.css | 6 + .../yui/build/treeview/treeview-min.js | 12 + .../javascript/yui/build/treeview/treeview.js | 3989 ++ .../yui/build/uploader/assets/uploader.swf | Bin 0 -> 7098 bytes .../yui/build/uploader/uploader-min.js | 15 + .../javascript/yui/build/uploader/uploader.js | 1069 + .../yui/build/utilities/utilities.js | 39 + .../build/yahoo-dom-event/yahoo-dom-event.js | 14 + .../javascript/yui/build/yahoo/yahoo-min.js | 7 + include/javascript/yui/build/yahoo/yahoo.js | 1075 + .../yuiloader-dom-event.js | 17 + .../yui/build/yuiloader/yuiloader-min.js | 10 + .../yui/build/yuiloader/yuiloader.js | 3879 ++ .../yuitest/assets/skins/sam/yuitest-skin.css | 7 + .../yuitest/assets/skins/sam/yuitest.css | 7 + .../yui/build/yuitest/assets/testlogger.css | 7 + .../yui/build/yuitest/assets/yuitest-core.css | 7 + .../yui/build/yuitest/yuitest-min.js | 10 + .../javascript/yui/build/yuitest/yuitest.js | 2741 ++ .../yui/build/yuitest/yuitest_core-min.js | 9 + .../yui/build/yuitest/yuitest_core.js | 1976 + include/javascript/yui/ext/yui-ext.js | 13509 +++++++ include/javascript/yui/index.html | 171 + include/javascript/yui/ygDDList.js | 154 + include/javascript/yui3/README | 50 + include/javascript/yui3/assets/bg_hd.gif | Bin 0 -> 96 bytes .../javascript/yui3/assets/bullet-box6x6.gif | Bin 0 -> 51 bytes include/javascript/yui3/assets/bullet4x4.png | Bin 0 -> 126 bytes .../yui3/assets/cheatsheet-shadow.jpg | Bin 0 -> 11796 bytes .../yui3/assets/cheatsheet-thumbnail.png | Bin 0 -> 36189 bytes .../javascript/yui3/assets/download-arrow.png | Bin 0 -> 327 bytes .../yui3/assets/dpSyntaxHighlighter.css | 190 + .../yui3/assets/dpSyntaxHighlighter.js | 166 + .../javascript/yui3/assets/example-hd-bg.gif | Bin 0 -> 1487 bytes .../yui3/assets/gradient-ex-box.png | Bin 0 -> 482 bytes .../javascript/yui3/assets/gradient-mod.png | Bin 0 -> 207 bytes .../javascript/yui3/assets/gradient-promo.png | Bin 0 -> 480 bytes include/javascript/yui3/assets/logo.gif | Bin 0 -> 5901 bytes include/javascript/yui3/assets/syntax.js | 3 + include/javascript/yui3/assets/title_h_bg.gif | Bin 0 -> 91 bytes include/javascript/yui3/assets/yui-candy.jpg | Bin 0 -> 11389 bytes include/javascript/yui3/assets/yui.css | 719 + include/javascript/yui3/assets/yui.gif | Bin 0 -> 2425 bytes .../yui3/assets/yuiDistribution.css | 0 .../yui3/build/anim/anim-base-min.js | 8 + .../javascript/yui3/build/anim/anim-base.js | 25 + .../yui3/build/anim/anim-color-min.js | 8 + .../javascript/yui3/build/anim/anim-color.js | 9 + .../yui3/build/anim/anim-curve-min.js | 8 + .../javascript/yui3/build/anim/anim-curve.js | 10 + .../yui3/build/anim/anim-easing-min.js | 8 + .../javascript/yui3/build/anim/anim-easing.js | 33 + .../javascript/yui3/build/anim/anim-min.js | 8 + .../yui3/build/anim/anim-node-plugin-min.js | 8 + .../yui3/build/anim/anim-node-plugin.js | 8 + .../yui3/build/anim/anim-scroll-min.js | 8 + .../javascript/yui3/build/anim/anim-scroll.js | 10 + .../javascript/yui3/build/anim/anim-xy-min.js | 8 + include/javascript/yui3/build/anim/anim-xy.js | 8 + include/javascript/yui3/build/anim/anim.js | 55 + .../yui3/build/assets/skins/sam/bg.png | Bin 0 -> 219 bytes .../assets/skins/sam/console-filters.css | 8 + .../yui3/build/assets/skins/sam/console.css | 8 + .../sam/horizontal-menu-submenu-indicator.png | Bin 0 -> 879 bytes .../sam/horizontal-menu-submenu-toggle.png | Bin 0 -> 206 bytes .../build/assets/skins/sam/node-menunav.css | 8 + .../yui3/build/assets/skins/sam/overlay.css | 9 + .../build/assets/skins/sam/rail-classic-x.png | Bin 0 -> 92 bytes .../build/assets/skins/sam/rail-classic-y.png | Bin 0 -> 90 bytes .../yui3/build/assets/skins/sam/skin.css | 14 + .../yui3/build/assets/skins/sam/slider.css | 8 + .../yui3/build/assets/skins/sam/sprite.png | Bin 0 -> 3123 bytes .../assets/skins/sam/thumb-classic-x.png | Bin 0 -> 374 bytes .../assets/skins/sam/thumb-classic-y.png | Bin 0 -> 341 bytes .../sam/vertical-menu-submenu-indicator.png | Bin 0 -> 880 bytes .../build/assets/skins/sam/warn_error.png | Bin 0 -> 703 bytes .../build/assets/skins/sam/widget-stack.css | 8 + .../yui3/build/assets/skins/sam/widget.css | 8 + .../yui3/build/async-queue/async-queue-min.js | 8 + .../yui3/build/async-queue/async-queue.js | 19 + .../build/attribute/attribute-base-min.js | 8 + .../yui3/build/attribute/attribute-base.js | 37 + .../build/attribute/attribute-complex-min.js | 8 + .../yui3/build/attribute/attribute-complex.js | 11 + .../yui3/build/attribute/attribute-min.js | 8 + .../yui3/build/attribute/attribute.js | 40 + .../yui3/build/base/base-base-min.js | 8 + .../javascript/yui3/build/base/base-base.js | 24 + .../yui3/build/base/base-build-min.js | 8 + .../javascript/yui3/build/base/base-build.js | 19 + .../javascript/yui3/build/base/base-min.js | 8 + .../yui3/build/base/base-pluginhost-min.js | 8 + .../yui3/build/base/base-pluginhost.js | 8 + include/javascript/yui3/build/base/base.js | 35 + .../javascript/yui3/build/cache/cache-min.js | 8 + include/javascript/yui3/build/cache/cache.js | 15 + .../classnamemanager/classnamemanager-min.js | 8 + .../classnamemanager/classnamemanager.js | 9 + .../yui3/build/collection/collection-min.js | 8 + .../yui3/build/collection/collection.js | 14 + .../yui3/build/compat/compat-min.js | 8 + .../javascript/yui3/build/compat/compat.js | 45 + .../build/console/assets/console-core.css | 7 + .../console/assets/console-filters-core.css | 7 + .../build/console/assets/skins/sam/bg.png | Bin 0 -> 219 bytes .../assets/skins/sam/console-filters-skin.css | 34 + .../assets/skins/sam/console-filters.css | 8 + .../console/assets/skins/sam/console-skin.css | 192 + .../console/assets/skins/sam/console.css | 8 + .../console/assets/skins/sam/warn_error.png | Bin 0 -> 703 bytes .../yui3/build/console/assets/warn_error.png | Bin 0 -> 703 bytes .../yui3/build/console/console-filters-min.js | 8 + .../yui3/build/console/console-filters.js | 19 + .../yui3/build/console/console-min.js | 8 + .../javascript/yui3/build/console/console.js | 28 + .../yui3/build/cookie/cookie-min.js | 8 + .../javascript/yui3/build/cookie/cookie.js | 28 + .../yui3/build/cssbase/base-context-min.css | 8 + .../yui3/build/cssbase/base-context.css | 80 + .../yui3/build/cssbase/base-min.css | 8 + .../javascript/yui3/build/cssbase/base.css | 80 + .../yui3/build/cssfonts/fonts-context-min.css | 8 + .../yui3/build/cssfonts/fonts-context.css | 47 + .../yui3/build/cssfonts/fonts-min.css | 8 + .../javascript/yui3/build/cssfonts/fonts.css | 47 + .../yui3/build/cssgrids/grids-context-min.css | 8 + .../yui3/build/cssgrids/grids-context.css | 491 + .../yui3/build/cssgrids/grids-min.css | 8 + .../javascript/yui3/build/cssgrids/grids.css | 481 + .../yui3/build/cssreset/reset-context-min.css | 8 + .../yui3/build/cssreset/reset-context.css | 126 + .../yui3/build/cssreset/reset-min.css | 8 + .../javascript/yui3/build/cssreset/reset.css | 126 + .../build/dataschema/dataschema-array-min.js | 8 + .../yui3/build/dataschema/dataschema-array.js | 15 + .../build/dataschema/dataschema-base-min.js | 8 + .../yui3/build/dataschema/dataschema-base.js | 10 + .../build/dataschema/dataschema-json-min.js | 8 + .../yui3/build/dataschema/dataschema-json.js | 30 + .../yui3/build/dataschema/dataschema-min.js | 8 + .../build/dataschema/dataschema-text-min.js | 8 + .../yui3/build/dataschema/dataschema-text.js | 14 + .../build/dataschema/dataschema-xml-min.js | 8 + .../yui3/build/dataschema/dataschema-xml.js | 18 + .../yui3/build/dataschema/dataschema.js | 55 + .../datasource/datasource-arrayschema-min.js | 8 + .../datasource/datasource-arrayschema.js | 9 + .../build/datasource/datasource-cache-min.js | 8 + .../yui3/build/datasource/datasource-cache.js | 8 + .../datasource/datasource-function-min.js | 8 + .../build/datasource/datasource-function.js | 11 + .../build/datasource/datasource-get-min.js | 8 + .../yui3/build/datasource/datasource-get.js | 10 + .../build/datasource/datasource-io-min.js | 8 + .../yui3/build/datasource/datasource-io.js | 10 + .../datasource/datasource-jsonschema-min.js | 8 + .../build/datasource/datasource-jsonschema.js | 9 + .../build/datasource/datasource-local-min.js | 8 + .../yui3/build/datasource/datasource-local.js | 10 + .../yui3/build/datasource/datasource-min.js | 8 + .../datasource/datasource-polling-min.js | 8 + .../build/datasource/datasource-polling.js | 8 + .../datasource/datasource-textschema-min.js | 8 + .../build/datasource/datasource-textschema.js | 9 + .../datasource/datasource-xmlschema-min.js | 8 + .../build/datasource/datasource-xmlschema.js | 9 + .../yui3/build/datasource/datasource.js | 21 + .../datatype/datatype-date-format-min.js | 8 + .../build/datatype/datatype-date-format.js | 22 + .../yui3/build/datatype/datatype-date-min.js | 8 + .../build/datatype/datatype-date-parse-min.js | 8 + .../build/datatype/datatype-date-parse.js | 11 + .../yui3/build/datatype/datatype-date.js | 25 + .../yui3/build/datatype/datatype-min.js | 8 + .../datatype/datatype-number-format-min.js | 8 + .../build/datatype/datatype-number-format.js | 14 + .../build/datatype/datatype-number-min.js | 8 + .../datatype/datatype-number-parse-min.js | 8 + .../build/datatype/datatype-number-parse.js | 9 + .../yui3/build/datatype/datatype-number.js | 15 + .../build/datatype/datatype-xml-format-min.js | 8 + .../build/datatype/datatype-xml-format.js | 10 + .../yui3/build/datatype/datatype-xml-min.js | 8 + .../build/datatype/datatype-xml-parse-min.js | 8 + .../yui3/build/datatype/datatype-xml-parse.js | 12 + .../yui3/build/datatype/datatype-xml.js | 14 + .../yui3/build/datatype/datatype.js | 38 + .../yui3/build/dd/dd-constrain-min.js | 8 + .../javascript/yui3/build/dd/dd-constrain.js | 29 + .../yui3/build/dd/dd-ddm-base-min.js | 8 + .../javascript/yui3/build/dd/dd-ddm-base.js | 15 + .../yui3/build/dd/dd-ddm-drop-min.js | 8 + .../javascript/yui3/build/dd/dd-ddm-drop.js | 13 + .../javascript/yui3/build/dd/dd-ddm-min.js | 8 + include/javascript/yui3/build/dd/dd-ddm.js | 11 + .../javascript/yui3/build/dd/dd-drag-min.js | 8 + include/javascript/yui3/build/dd/dd-drag.js | 35 + .../javascript/yui3/build/dd/dd-drop-min.js | 8 + .../yui3/build/dd/dd-drop-plugin-min.js | 8 + .../yui3/build/dd/dd-drop-plugin.js | 8 + include/javascript/yui3/build/dd/dd-drop.js | 24 + include/javascript/yui3/build/dd/dd-min.js | 8 + .../javascript/yui3/build/dd/dd-plugin-min.js | 8 + include/javascript/yui3/build/dd/dd-plugin.js | 8 + .../javascript/yui3/build/dd/dd-proxy-min.js | 8 + include/javascript/yui3/build/dd/dd-proxy.js | 16 + .../javascript/yui3/build/dd/dd-scroll-min.js | 8 + include/javascript/yui3/build/dd/dd-scroll.js | 20 + include/javascript/yui3/build/dd/dd.js | 107 + .../javascript/yui3/build/dom/dom-base-min.js | 8 + include/javascript/yui3/build/dom/dom-base.js | 40 + include/javascript/yui3/build/dom/dom-min.js | 8 + .../yui3/build/dom/dom-screen-min.js | 8 + .../javascript/yui3/build/dom/dom-screen.js | 30 + .../yui3/build/dom/dom-style-min.js | 8 + .../javascript/yui3/build/dom/dom-style.js | 36 + include/javascript/yui3/build/dom/dom.js | 130 + .../yui3/build/dom/selector-css2-min.js | 8 + .../yui3/build/dom/selector-css2.js | 34 + .../yui3/build/dom/selector-css3-min.js | 8 + .../yui3/build/dom/selector-css3.js | 12 + .../javascript/yui3/build/dom/selector-min.js | 8 + .../yui3/build/dom/selector-native-min.js | 8 + .../yui3/build/dom/selector-native.js | 22 + include/javascript/yui3/build/dom/selector.js | 48 + .../javascript/yui3/build/dump/dump-min.js | 8 + include/javascript/yui3/build/dump/dump.js | 16 + .../event-custom/event-custom-base-min.js | 8 + .../build/event-custom/event-custom-base.js | 54 + .../event-custom/event-custom-complex-min.js | 8 + .../event-custom/event-custom-complex.js | 22 + .../build/event-custom/event-custom-min.js | 8 + .../yui3/build/event-custom/event-custom.js | 68 + .../event-simulate/event-simulate-min.js | 8 + .../build/event-simulate/event-simulate.js | 42 + .../yui3/build/event/event-base-min.js | 8 + .../javascript/yui3/build/event/event-base.js | 54 + .../yui3/build/event/event-delegate-min.js | 8 + .../yui3/build/event/event-delegate.js | 21 + .../yui3/build/event/event-focus-min.js | 8 + .../yui3/build/event/event-focus.js | 8 + .../yui3/build/event/event-key-min.js | 8 + .../javascript/yui3/build/event/event-key.js | 11 + .../javascript/yui3/build/event/event-min.js | 8 + .../yui3/build/event/event-mouseenter-min.js | 8 + .../yui3/build/event/event-mouseenter.js | 10 + .../yui3/build/event/event-mousewheel-min.js | 8 + .../yui3/build/event/event-mousewheel.js | 10 + .../yui3/build/event/event-resize-min.js | 8 + .../yui3/build/event/event-resize.js | 10 + include/javascript/yui3/build/event/event.js | 76 + include/javascript/yui3/build/get/get-min.js | 8 + include/javascript/yui3/build/get/get.js | 33 + .../yui3/build/history/history-min.js | 8 + .../javascript/yui3/build/history/history.js | 39 + .../yui3/build/imageloader/imageloader-min.js | 8 + .../yui3/build/imageloader/imageloader.js | 33 + .../javascript/yui3/build/io/io-base-min.js | 8 + include/javascript/yui3/build/io/io-base.js | 56 + .../javascript/yui3/build/io/io-form-min.js | 8 + include/javascript/yui3/build/io/io-form.js | 13 + include/javascript/yui3/build/io/io-min.js | 8 + .../javascript/yui3/build/io/io-queue-min.js | 8 + include/javascript/yui3/build/io/io-queue.js | 15 + .../yui3/build/io/io-upload-iframe-min.js | 8 + .../yui3/build/io/io-upload-iframe.js | 26 + .../javascript/yui3/build/io/io-xdr-min.js | 8 + include/javascript/yui3/build/io/io-xdr.js | 20 + include/javascript/yui3/build/io/io.js | 98 + include/javascript/yui3/build/io/io.swf | Bin 0 -> 2829 bytes .../javascript/yui3/build/json/json-min.js | 8 + .../yui3/build/json/json-parse-min.js | 8 + .../javascript/yui3/build/json/json-parse.js | 10 + .../yui3/build/json/json-stringify-min.js | 8 + .../yui3/build/json/json-stringify.js | 31 + include/javascript/yui3/build/json/json.js | 33 + .../yui3/build/loader/loader-min.js | 8 + .../javascript/yui3/build/loader/loader.js | 72 + .../node-focusmanager-min.js | 8 + .../node-focusmanager/node-focusmanager.js | 47 + .../node-menunav/assets/node-menunav-core.css | 176 + .../sam/horizontal-menu-submenu-indicator.png | Bin 0 -> 879 bytes .../sam/horizontal-menu-submenu-toggle.png | Bin 0 -> 206 bytes .../assets/skins/sam/node-menunav-skin.css | 270 + .../assets/skins/sam/node-menunav.css | 8 + .../sam/vertical-menu-submenu-indicator.png | Bin 0 -> 880 bytes .../build/node-menunav/node-menunav-min.js | 8 + .../yui3/build/node-menunav/node-menunav.js | 74 + .../yui3/build/node/node-aria-min.js | 8 + .../javascript/yui3/build/node/node-aria.js | 9 + .../yui3/build/node/node-base-min.js | 8 + .../javascript/yui3/build/node/node-base.js | 54 + .../build/node/node-event-delegate-min.js | 8 + .../yui3/build/node/node-event-delegate.js | 8 + .../build/node/node-event-simulate-min.js | 8 + .../yui3/build/node/node-event-simulate.js | 8 + .../javascript/yui3/build/node/node-min.js | 8 + .../yui3/build/node/node-pluginhost-min.js | 8 + .../yui3/build/node/node-pluginhost.js | 8 + .../yui3/build/node/node-screen-min.js | 8 + .../javascript/yui3/build/node/node-screen.js | 11 + .../yui3/build/node/node-style-min.js | 8 + .../javascript/yui3/build/node/node-style.js | 8 + include/javascript/yui3/build/node/node.js | 57 + include/javascript/yui3/build/oop/oop-min.js | 8 + include/javascript/yui3/build/oop/oop.js | 20 + .../build/overlay/assets/overlay-core.css | 14 + .../overlay/assets/skins/sam/overlay-skin.css | 7 + .../overlay/assets/skins/sam/overlay.css | 9 + .../yui3/build/overlay/overlay-min.js | 8 + .../javascript/yui3/build/overlay/overlay.js | 8 + .../yui3/build/plugin/plugin-min.js | 8 + .../javascript/yui3/build/plugin/plugin.js | 11 + .../yui3/build/pluginhost/pluginhost-min.js | 8 + .../yui3/build/pluginhost/pluginhost.js | 19 + .../yui3/build/profiler/profiler-min.js | 8 + .../yui3/build/profiler/profiler.js | 18 + .../build/queue-promote/queue-promote-min.js | 8 + .../yui3/build/queue-promote/queue-promote.js | 8 + .../assets/skins/sam/rail-classic-x.png | Bin 0 -> 92 bytes .../assets/skins/sam/rail-classic-y.png | Bin 0 -> 90 bytes .../slider/assets/skins/sam/slider-skin.css | 18 + .../build/slider/assets/skins/sam/slider.css | 8 + .../assets/skins/sam/thumb-classic-x.png | Bin 0 -> 374 bytes .../assets/skins/sam/thumb-classic-y.png | Bin 0 -> 341 bytes .../yui3/build/slider/assets/slider-core.css | 42 + .../yui3/build/slider/slider-min.js | 8 + .../javascript/yui3/build/slider/slider.js | 23 + .../yui3/build/stylesheet/stylesheet-min.js | 8 + .../yui3/build/stylesheet/stylesheet.js | 36 + .../yui3/build/substitute/substitute-min.js | 8 + .../yui3/build/substitute/substitute.js | 16 + .../yui3/build/test/assets/test-console.css | 34 + .../javascript/yui3/build/test/test-min.js | 8 + include/javascript/yui3/build/test/test.js | 62 + .../widget/assets/skins/sam/widget-skin.css | 7 + .../assets/skins/sam/widget-stack-skin.css | 7 + .../widget/assets/skins/sam/widget-stack.css | 8 + .../build/widget/assets/skins/sam/widget.css | 8 + .../yui3/build/widget/assets/widget-core.css | 10 + .../build/widget/assets/widget-stack-core.css | 26 + .../yui3/build/widget/widget-min.js | 8 + .../build/widget/widget-position-ext-min.js | 8 + .../yui3/build/widget/widget-position-ext.js | 15 + .../yui3/build/widget/widget-position-min.js | 8 + .../yui3/build/widget/widget-position.js | 9 + .../yui3/build/widget/widget-stack-min.js | 8 + .../yui3/build/widget/widget-stack.js | 12 + .../yui3/build/widget/widget-stdmod-min.js | 8 + .../yui3/build/widget/widget-stdmod.js | 21 + .../javascript/yui3/build/widget/widget.js | 36 + .../yui3/build/yui-base/yui-base-min.js | 8 + .../yui3/build/yui-base/yui-base.js | 65 + include/javascript/yui3/build/yui/get-min.js | 8 + include/javascript/yui3/build/yui/get.js | 33 + .../javascript/yui3/build/yui/yui-base-min.js | 8 + include/javascript/yui3/build/yui/yui-base.js | 62 + .../yui3/build/yui/yui-later-min.js | 8 + .../javascript/yui3/build/yui/yui-later.js | 10 + .../javascript/yui3/build/yui/yui-log-min.js | 8 + include/javascript/yui3/build/yui/yui-log.js | 12 + include/javascript/yui3/build/yui/yui-min.js | 8 + include/javascript/yui3/build/yui/yui.js | 93 + include/javascript/yui3/index.html | 163 + include/jsolait/LICENSE | 504 + include/jsolait/copying.txt | 504 + include/jsolait/init.js | 101 + include/jsolait/lib/codecs.js | 38 + include/jsolait/lib/crypto.js | 37 + include/jsolait/lib/jsonrpc.js | 112 + include/jsolait/lib/jsonrpclite.js | 96 + include/jsolait/lib/lang.js | 75 + include/jsolait/lib/langlite.js | 49 + include/jsolait/lib/urllib.js | 45 + include/jsolait/lib/xml.js | 37 + include/jsolait/lib/xmlrpc.js | 98 + include/jsolait/missingmixin.js | 46 + include/json_config.php | 224 + include/language/en_us.lang.php | 2959 ++ include/language/en_us.notify_template.html | 352 + include/language/jsLanguage.php | 85 + include/modules.php | 293 + include/nusoap/changelog | 648 + include/nusoap/class.nusoap_base.php | 1046 + include/nusoap/class.soap_fault.php | 131 + include/nusoap/class.soap_parser.php | 693 + include/nusoap/class.soap_server.php | 1177 + include/nusoap/class.soap_transport_http.php | 1359 + include/nusoap/class.soap_val.php | 148 + include/nusoap/class.soapclient.php | 1146 + include/nusoap/class.wsdl.php | 1983 + include/nusoap/class.wsdlcache.php | 251 + include/nusoap/class.xmlschema.php | 1019 + include/nusoap/license.txt | 531 + include/nusoap/nusoap.php | 10058 +++++ include/nusoap/nusoapmime.php | 611 + include/pclzip/gnu-lgpl.txt | 504 + include/pclzip/pclzip.lib.php | 5447 +++ include/pclzip/readme.txt | 332 + include/phpmailer/README | 193 + include/phpmailer/class.phpmailer.php | 2010 + include/phpmailer/class.smtp.php | 1105 + .../phpmailer/language/phpmailer.lang-ar.php | 48 + .../phpmailer/language/phpmailer.lang-br.php | 56 + .../phpmailer/language/phpmailer.lang-ca.php | 55 + .../phpmailer/language/phpmailer.lang-cz.php | 59 + .../phpmailer/language/phpmailer.lang-de.php | 59 + .../phpmailer/language/phpmailer.lang-dk.php | 56 + .../phpmailer/language/phpmailer.lang-en.php | 58 + .../phpmailer/language/phpmailer.lang-es.php | 58 + .../phpmailer/language/phpmailer.lang-et.php | 51 + .../phpmailer/language/phpmailer.lang-fi.php | 56 + .../phpmailer/language/phpmailer.lang-fo.php | 58 + .../phpmailer/language/phpmailer.lang-fr.php | 58 + .../phpmailer/language/phpmailer.lang-hu.php | 56 + .../phpmailer/language/phpmailer.lang-it.php | 64 + .../phpmailer/language/phpmailer.lang-ja.php | Bin 0 -> 2670 bytes .../phpmailer/language/phpmailer.lang-nl.php | 58 + .../phpmailer/language/phpmailer.lang-no.php | 58 + .../phpmailer/language/phpmailer.lang-pl.php | 56 + .../phpmailer/language/phpmailer.lang-ro.php | 55 + .../phpmailer/language/phpmailer.lang-ru.php | 55 + .../phpmailer/language/phpmailer.lang-se.php | 58 + .../phpmailer/language/phpmailer.lang-tr.php | 61 + include/phpmailer/license.txt | 504 + include/reCaptcha/LICENSE | 22 + include/reCaptcha/README | 7 + include/reCaptcha/recaptchalib.php | 278 + .../resource/Observers/ResourceObserver.php | 66 + .../Observers/SoapResourceObserver.php | 81 + .../Observers/WebResourceObserver.php | 64 + include/resource/ResourceManager.php | 154 + include/tabConfig.php | 103 + include/tabs.php | 130 + include/tcpdf/2dbarcodes.php | 149 + include/tcpdf/CHANGELOG.TXT | 1010 + include/tcpdf/LICENSE.TXT | 504 + include/tcpdf/README.TXT | 86 + include/tcpdf/barcodes.php | 1999 + include/tcpdf/config/lang/eng.php | 73 + include/tcpdf/config/lang/ita.php | 73 + include/tcpdf/config/tcpdf_config.php | 264 + include/tcpdf/config/tcpdf_config_alt.php | 259 + include/tcpdf/fonts/uni2cid_ac15.php | 23636 ++++++++++++ include/tcpdf/fonts/uni2cid_ag15.php | 30245 ++++++++++++++++ include/tcpdf/fonts/uni2cid_aj16.php | 15728 ++++++++ include/tcpdf/fonts/uni2cid_ak12.php | 17553 +++++++++ include/tcpdf/fonts/utils/enc/cp1250.map | 251 + include/tcpdf/fonts/utils/enc/cp1251.map | 255 + include/tcpdf/fonts/utils/enc/cp1252.map | 251 + include/tcpdf/fonts/utils/enc/cp1253.map | 239 + include/tcpdf/fonts/utils/enc/cp1254.map | 249 + include/tcpdf/fonts/utils/enc/cp1255.map | 233 + include/tcpdf/fonts/utils/enc/cp1257.map | 244 + include/tcpdf/fonts/utils/enc/cp1258.map | 247 + include/tcpdf/fonts/utils/enc/cp874.map | 225 + include/tcpdf/fonts/utils/enc/iso-8859-1.map | 256 + include/tcpdf/fonts/utils/enc/iso-8859-11.map | 248 + include/tcpdf/fonts/utils/enc/iso-8859-15.map | 256 + include/tcpdf/fonts/utils/enc/iso-8859-16.map | 256 + include/tcpdf/fonts/utils/enc/iso-8859-2.map | 256 + include/tcpdf/fonts/utils/enc/iso-8859-4.map | 256 + include/tcpdf/fonts/utils/enc/iso-8859-5.map | 256 + include/tcpdf/fonts/utils/enc/iso-8859-7.map | 250 + include/tcpdf/fonts/utils/enc/iso-8859-9.map | 256 + include/tcpdf/fonts/utils/enc/koi8-r.map | 256 + include/tcpdf/fonts/utils/enc/koi8-u.map | 256 + include/tcpdf/fonts/utils/makefont.php | 730 + include/tcpdf/htmlcolors.php | 231 + include/tcpdf/tcpdf.php | 13979 +++++++ include/tcpdf/unicode_data.php | 18383 ++++++++++ include/templates/Template.php | 51 + include/templates/TemplateDragDropChooser.php | 282 + include/templates/TemplateGroupChooser.php | 175 + include/timezone/timezones.php | 2920 ++ include/upload_file.php | 359 + include/utils.php | 4192 +++ include/utils/LogicHook.php | 168 + include/utils/activity_utils.php | 86 + include/utils/array_utils.php | 293 + include/utils/autoloader.php | 97 + include/utils/db_utils.php | 202 + include/utils/encryption_utils.php | 104 + include/utils/external_cache.php | 40 + include/utils/file_utils.php | 451 + include/utils/layout_utils.php | 367 + include/utils/logic_utils.php | 123 + include/utils/mvc_utils.php | 51 + include/utils/php_zip_utils.php | 121 + include/utils/progress_bar_utils.php | 148 + include/utils/security_utils.php | 146 + include/utils/sugar_file_utils.php | 328 + include/utils/zip_utils.php | 130 + include/vCard.php | 385 + include/ytree/ExtNode.php | 114 + include/ytree/Node.php | 110 + include/ytree/Tree.php | 169 + include/ytree/TreeView/HTMLNode.js | 6 + include/ytree/TreeView/MenuNode.js | 3 + include/ytree/TreeView/Node.js | 21 + include/ytree/TreeView/RootNode.js | 2 + include/ytree/TreeView/TaskNode.js | 28 + include/ytree/TreeView/TextNode.js | 9 + include/ytree/TreeView/TreeView.js | 79 + include/ytree/TreeView/anim/TVAnim.js | 2 + include/ytree/TreeView/anim/TVFadeIn.js | 2 + include/ytree/TreeView/anim/TVFadeOut.js | 2 + include/ytree/TreeView/css/check/tree.css | 1 + include/ytree/TreeView/css/default/tree.css | 97 + include/ytree/TreeView/css/folders/tree.css | 55 + include/ytree/TreeView/css/forecasts/tree.css | 55 + include/ytree/TreeView/img/bullet.gif | Bin 0 -> 172 bytes include/ytree/TreeView/img/check/Thumbs.db | Bin 0 -> 18432 bytes include/ytree/TreeView/img/check/check0.gif | Bin 0 -> 608 bytes include/ytree/TreeView/img/check/check1.gif | Bin 0 -> 609 bytes include/ytree/TreeView/img/check/check2.gif | Bin 0 -> 622 bytes include/ytree/TreeView/img/check/lm.gif | Bin 0 -> 94 bytes include/ytree/TreeView/img/check/lmh.gif | Bin 0 -> 106 bytes include/ytree/TreeView/img/check/ln.gif | Bin 0 -> 142 bytes include/ytree/TreeView/img/check/loading.gif | Bin 0 -> 2673 bytes include/ytree/TreeView/img/check/lp.gif | Bin 0 -> 130 bytes include/ytree/TreeView/img/check/lph.gif | Bin 0 -> 111 bytes include/ytree/TreeView/img/check/tm.gif | Bin 0 -> 545 bytes include/ytree/TreeView/img/check/tmh.gif | Bin 0 -> 563 bytes include/ytree/TreeView/img/check/tn.gif | Bin 0 -> 504 bytes include/ytree/TreeView/img/check/tp.gif | Bin 0 -> 539 bytes include/ytree/TreeView/img/check/tph.gif | Bin 0 -> 568 bytes include/ytree/TreeView/img/check/vline.gif | Bin 0 -> 503 bytes include/ytree/TreeView/img/default/lm.gif | Bin 0 -> 94 bytes include/ytree/TreeView/img/default/lmh.gif | Bin 0 -> 106 bytes include/ytree/TreeView/img/default/ln.gif | Bin 0 -> 142 bytes .../ytree/TreeView/img/default/loading.gif | Bin 0 -> 2673 bytes include/ytree/TreeView/img/default/lp.gif | Bin 0 -> 130 bytes include/ytree/TreeView/img/default/lph.gif | Bin 0 -> 111 bytes include/ytree/TreeView/img/default/tm.gif | Bin 0 -> 545 bytes include/ytree/TreeView/img/default/tmh.gif | Bin 0 -> 563 bytes include/ytree/TreeView/img/default/tn.gif | Bin 0 -> 504 bytes include/ytree/TreeView/img/default/tp.gif | Bin 0 -> 539 bytes include/ytree/TreeView/img/default/tph.gif | Bin 0 -> 568 bytes include/ytree/TreeView/img/default/vline.gif | Bin 0 -> 503 bytes include/ytree/TreeView/img/folders/lm.gif | Bin 0 -> 666 bytes include/ytree/TreeView/img/folders/lmh.gif | Bin 0 -> 677 bytes include/ytree/TreeView/img/folders/ln.gif | Bin 0 -> 142 bytes .../ytree/TreeView/img/folders/loading.gif | Bin 0 -> 516 bytes include/ytree/TreeView/img/folders/lp.gif | Bin 0 -> 641 bytes include/ytree/TreeView/img/folders/lph.gif | Bin 0 -> 651 bytes include/ytree/TreeView/img/folders/minus.gif | Bin 0 -> 853 bytes include/ytree/TreeView/img/folders/plus.gif | Bin 0 -> 857 bytes include/ytree/TreeView/img/folders/tm.gif | Bin 0 -> 1281 bytes include/ytree/TreeView/img/folders/tmh.gif | Bin 0 -> 1295 bytes include/ytree/TreeView/img/folders/tn.gif | Bin 0 -> 504 bytes include/ytree/TreeView/img/folders/tp.gif | Bin 0 -> 1243 bytes include/ytree/TreeView/img/folders/tph.gif | Bin 0 -> 1263 bytes include/ytree/TreeView/img/folders/vline.gif | Bin 0 -> 503 bytes include/ytree/TreeView/img/greybg.png | Bin 0 -> 197 bytes include/ytree/TreeView/img/header.gif | Bin 0 -> 203 bytes include/ytree/TreeView/img/logo.gif | Bin 0 -> 705 bytes include/ytree/TreeView/img/navHover2.png | Bin 0 -> 875 bytes include/ytree/TreeView/img/qbottom.png | Bin 0 -> 1351 bytes include/ytree/TreeView/img/qmiddle.png | Bin 0 -> 385 bytes include/ytree/TreeView/img/qtop.png | Bin 0 -> 2030 bytes include/ytree/TreeView/license.txt | 35 + include/ytree/treeutil.js | 50 + index.php | 46 + install.php | 586 + install/TeamDemoData.php | 191 + install/UploadLangFileCheck.php | 87 + install/UserDemoData.php | 188 + install/checkDBSettings.php | 571 + install/confirmSettings.php | 591 + install/data/disc_client.php | 57 + install/dbConfig.js | 40 + install/dbConfig_a.php | 465 + install/demoData.en_us.php | 21721 +++++++++++ install/download_modules.php | 356 + install/download_patches.php | 316 + install/install.css | 367 + install/installCommon.js | 37 + install/installDisabled.php | 93 + install/installHelp.php | 373 + install/installSystemCheck.php | 421 + install/installType.php | 154 + install/install_defaults.php | 100 + install/install_utils.php | 2309 ++ install/language/en_us.lang.php | 564 + install/license.js | 39 + install/license.php | 237 + install/licensePrint.php | 90 + install/oc_convert.js | 35 + install/oc_install.js | 36 + install/performSetup.php | 565 + install/populateSeedData.php | 503 + install/processing.gif | Bin 0 -> 10847 bytes install/ready.php | 166 + install/register.js | 44 + install/register.php | 139 + .../seed_data/Advanced_Password_SeedData.php | 83 + install/seed_data/quotes_SeedData.php | 174 + install/siteConfig.js | 42 + install/siteConfig_a.php | 210 + install/siteConfig_b.php | 235 + install/systemOptions.php | 174 + install/welcome.php | 145 + json.php | 112 + json_server.php | 765 + jssource/JSGroupings.php | 156 + jssource/jsmin.php | 291 + jssource/minify.php | 154 + jssource/minify_utils.php | 466 + jssource/src_files/include/JSON.js | 217 + .../include/MySugar/javascript/MySugar.js | 610 + .../include/SubPanel/SubPanelTiles.js | 736 + .../SugarCharts/Jit/FlashCanvas/canvas2png.js | 42 + .../Jit/FlashCanvas/flashcanvas.js | 28 + .../include/SugarCharts/Jit/js/Jit/jit.js | 20674 +++++++++++ .../SugarCharts/Jit/js/mySugarCharts.js | 117 + .../include/SugarCharts/Jit/js/sugarCharts.js | 784 + .../javascript/SugarDependentDropdown.js | 305 + .../SugarEmailAddress/SugarEmailAddress.js | 490 + .../Fields/Address/SugarFieldAddress.js | 102 + .../Fields/Collection/SugarFieldCollection.js | 637 + .../Fields/Datetimecombo/Datetimecombo.js | 239 + .../SugarFields/Fields/File/SugarFieldFile.js | 212 + .../formatters/default/company_detail.js | 80 + .../src_files/include/javascript/calendar.js | 236 + .../src_files/include/javascript/cookie.js | 121 + .../src_files/include/javascript/dashlets.js | 93 + .../src_files/include/javascript/include.js | 301 + .../src_files/include/javascript/iscroll.js | 725 + .../include/javascript/jsclass_async.js | 224 + .../include/javascript/jsclass_base.js | 775 + jssource/src_files/include/javascript/menu.js | 537 + .../include/javascript/overlibmws.js | 782 + .../include/javascript/overlibmws_iframe.js | 169 + .../include/javascript/popup_helper.js | 238 + .../include/javascript/popup_parent_helper.js | 227 + .../include/javascript/quickCompose.js | 290 + .../include/javascript/quicksearch.js | 335 + .../include/javascript/report_additionals.js | 2858 ++ .../src_files/include/javascript/sugar_3.js | 4136 +++ .../sugar_connection_event_listener.js | 49 + .../javascript/sugarwidgets/SugarYUILoader.js | 51 + .../sugarwidgets/SugarYUIWidgets.js | 681 + .../src_files/include/javascript/swfobject.js | 265 + .../yui3/assets/dpSyntaxHighlighter.js | 805 + .../include/javascript/yui3/assets/syntax.js | 56 + .../yui3/build/anim/anim-base-min.js | 8 + .../javascript/yui3/build/anim/anim-base.js | 602 + .../yui3/build/anim/anim-color-min.js | 8 + .../javascript/yui3/build/anim/anim-color.js | 55 + .../yui3/build/anim/anim-curve-min.js | 8 + .../javascript/yui3/build/anim/anim-curve.js | 64 + .../yui3/build/anim/anim-easing-min.js | 8 + .../javascript/yui3/build/anim/anim-easing.js | 355 + .../javascript/yui3/build/anim/anim-min.js | 9 + .../yui3/build/anim/anim-node-plugin-min.js | 8 + .../yui3/build/anim/anim-node-plugin.js | 33 + .../yui3/build/anim/anim-scroll-min.js | 8 + .../javascript/yui3/build/anim/anim-scroll.js | 45 + .../javascript/yui3/build/anim/anim-xy-min.js | 8 + .../javascript/yui3/build/anim/anim-xy.js | 33 + .../javascript/yui3/build/anim/anim.js | 1149 + .../yui3/build/async-queue/async-queue-min.js | 8 + .../yui3/build/async-queue/async-queue.js | 536 + .../build/attribute/attribute-base-min.js | 8 + .../yui3/build/attribute/attribute-base.js | 1064 + .../build/attribute/attribute-complex-min.js | 8 + .../yui3/build/attribute/attribute-complex.js | 120 + .../yui3/build/attribute/attribute-min.js | 9 + .../yui3/build/attribute/attribute.js | 1181 + .../yui3/build/base/base-base-min.js | 8 + .../javascript/yui3/build/base/base-base.js | 531 + .../yui3/build/base/base-build-min.js | 8 + .../javascript/yui3/build/base/base-build.js | 201 + .../javascript/yui3/build/base/base-min.js | 8 + .../yui3/build/base/base-pluginhost-min.js | 8 + .../yui3/build/base/base-pluginhost.js | 43 + .../javascript/yui3/build/base/base.js | 765 + .../javascript/yui3/build/cache/cache-min.js | 8 + .../javascript/yui3/build/cache/cache.js | 357 + .../classnamemanager/classnamemanager-min.js | 8 + .../classnamemanager/classnamemanager.js | 87 + .../yui3/build/collection/collection-min.js | 8 + .../yui3/build/collection/collection.js | 294 + .../yui3/build/compat/compat-min.js | 9 + .../javascript/yui3/build/compat/compat.js | 896 + .../yui3/build/console/console-filters-min.js | 8 + .../yui3/build/console/console-filters.js | 710 + .../yui3/build/console/console-min.js | 9 + .../javascript/yui3/build/console/console.js | 1478 + .../yui3/build/cookie/cookie-min.js | 8 + .../javascript/yui3/build/cookie/cookie.js | 491 + .../build/dataschema/dataschema-array-min.js | 8 + .../yui3/build/dataschema/dataschema-array.js | 107 + .../build/dataschema/dataschema-base-min.js | 8 + .../yui3/build/dataschema/dataschema-base.js | 73 + .../build/dataschema/dataschema-json-min.js | 8 + .../yui3/build/dataschema/dataschema-json.js | 294 + .../yui3/build/dataschema/dataschema-min.js | 8 + .../build/dataschema/dataschema-text-min.js | 8 + .../yui3/build/dataschema/dataschema-text.js | 116 + .../build/dataschema/dataschema-xml-min.js | 8 + .../yui3/build/dataschema/dataschema-xml.js | 164 + .../yui3/build/dataschema/dataschema.js | 735 + .../datasource/datasource-arrayschema-min.js | 8 + .../datasource/datasource-arrayschema.js | 113 + .../build/datasource/datasource-cache-min.js | 8 + .../yui3/build/datasource/datasource-cache.js | 136 + .../datasource/datasource-function-min.js | 8 + .../build/datasource/datasource-function.js | 115 + .../build/datasource/datasource-get-min.js | 8 + .../yui3/build/datasource/datasource-get.js | 226 + .../build/datasource/datasource-io-min.js | 8 + .../yui3/build/datasource/datasource-io.js | 154 + .../datasource/datasource-jsonschema-min.js | 8 + .../build/datasource/datasource-jsonschema.js | 113 + .../build/datasource/datasource-local-min.js | 8 + .../yui3/build/datasource/datasource-local.js | 336 + .../yui3/build/datasource/datasource-min.js | 9 + .../datasource/datasource-polling-min.js | 8 + .../build/datasource/datasource-polling.js | 93 + .../datasource/datasource-textschema-min.js | 8 + .../build/datasource/datasource-textschema.js | 113 + .../datasource/datasource-xmlschema-min.js | 8 + .../build/datasource/datasource-xmlschema.js | 113 + .../yui3/build/datasource/datasource.js | 1463 + .../datatype/datatype-date-format-min.js | 8 + .../build/datatype/datatype-date-format.js | 443 + .../yui3/build/datatype/datatype-date-min.js | 8 + .../build/datatype/datatype-date-parse-min.js | 8 + .../build/datatype/datatype-date-parse.js | 53 + .../yui3/build/datatype/datatype-date.js | 495 + .../yui3/build/datatype/datatype-min.js | 9 + .../datatype/datatype-number-format-min.js | 8 + .../build/datatype/datatype-number-format.js | 112 + .../build/datatype/datatype-number-min.js | 8 + .../datatype/datatype-number-parse-min.js | 8 + .../build/datatype/datatype-number-parse.js | 45 + .../yui3/build/datatype/datatype-number.js | 156 + .../build/datatype/datatype-xml-format-min.js | 8 + .../build/datatype/datatype-xml-format.js | 60 + .../yui3/build/datatype/datatype-xml-min.js | 8 + .../build/datatype/datatype-xml-parse-min.js | 8 + .../yui3/build/datatype/datatype-xml-parse.js | 62 + .../yui3/build/datatype/datatype-xml.js | 121 + .../yui3/build/datatype/datatype.js | 765 + .../yui3/build/dd/dd-constrain-min.js | 8 + .../javascript/yui3/build/dd/dd-constrain.js | 425 + .../yui3/build/dd/dd-ddm-base-min.js | 8 + .../javascript/yui3/build/dd/dd-ddm-base.js | 289 + .../yui3/build/dd/dd-ddm-drop-min.js | 8 + .../javascript/yui3/build/dd/dd-ddm-drop.js | 411 + .../javascript/yui3/build/dd/dd-ddm-min.js | 8 + .../javascript/yui3/build/dd/dd-ddm.js | 135 + .../javascript/yui3/build/dd/dd-drag-min.js | 9 + .../javascript/yui3/build/dd/dd-drag.js | 1100 + .../javascript/yui3/build/dd/dd-drop-min.js | 8 + .../yui3/build/dd/dd-drop-plugin-min.js | 8 + .../yui3/build/dd/dd-drop-plugin.js | 52 + .../javascript/yui3/build/dd/dd-drop.js | 485 + .../javascript/yui3/build/dd/dd-min.js | 12 + .../javascript/yui3/build/dd/dd-plugin-min.js | 8 + .../javascript/yui3/build/dd/dd-plugin.js | 53 + .../javascript/yui3/build/dd/dd-proxy-min.js | 8 + .../javascript/yui3/build/dd/dd-proxy.js | 225 + .../javascript/yui3/build/dd/dd-scroll-min.js | 8 + .../javascript/yui3/build/dd/dd-scroll.js | 413 + .../include/javascript/yui3/build/dd/dd.js | 3529 ++ .../javascript/yui3/build/dom/dom-base-min.js | 9 + .../javascript/yui3/build/dom/dom-base.js | 737 + .../javascript/yui3/build/dom/dom-min.js | 11 + .../yui3/build/dom/dom-screen-min.js | 8 + .../javascript/yui3/build/dom/dom-screen.js | 567 + .../yui3/build/dom/dom-style-min.js | 8 + .../javascript/yui3/build/dom/dom-style.js | 506 + .../include/javascript/yui3/build/dom/dom.js | 2466 ++ .../yui3/build/dom/selector-css2-min.js | 8 + .../yui3/build/dom/selector-css2.js | 449 + .../yui3/build/dom/selector-css3-min.js | 8 + .../yui3/build/dom/selector-css3.js | 151 + .../javascript/yui3/build/dom/selector-min.js | 9 + .../yui3/build/dom/selector-native-min.js | 8 + .../yui3/build/dom/selector-native.js | 227 + .../javascript/yui3/build/dom/selector.js | 673 + .../javascript/yui3/build/dump/dump-min.js | 8 + .../javascript/yui3/build/dump/dump.js | 119 + .../event-custom/event-custom-base-min.js | 9 + .../build/event-custom/event-custom-base.js | 1722 + .../event-custom/event-custom-complex-min.js | 8 + .../event-custom/event-custom-complex.js | 363 + .../build/event-custom/event-custom-min.js | 10 + .../yui3/build/event-custom/event-custom.js | 2082 ++ .../event-simulate/event-simulate-min.js | 8 + .../build/event-simulate/event-simulate.js | 490 + .../yui3/build/event/event-base-min.js | 11 + .../javascript/yui3/build/event/event-base.js | 1378 + .../yui3/build/event/event-delegate-min.js | 8 + .../yui3/build/event/event-delegate.js | 365 + .../yui3/build/event/event-focus-min.js | 8 + .../yui3/build/event/event-focus.js | 90 + .../yui3/build/event/event-key-min.js | 8 + .../javascript/yui3/build/event/event-key.js | 106 + .../javascript/yui3/build/event/event-min.js | 12 + .../yui3/build/event/event-mouseenter-min.js | 8 + .../yui3/build/event/event-mouseenter.js | 191 + .../yui3/build/event/event-mousewheel-min.js | 8 + .../yui3/build/event/event-mousewheel.js | 57 + .../yui3/build/event/event-resize-min.js | 8 + .../yui3/build/event/event-resize.js | 71 + .../javascript/yui3/build/event/event.js | 2220 ++ .../javascript/yui3/build/get/get-min.js | 8 + .../include/javascript/yui3/build/get/get.js | 734 + .../yui3/build/history/history-min.js | 8 + .../javascript/yui3/build/history/history.js | 680 + .../yui3/build/imageloader/imageloader-min.js | 8 + .../yui3/build/imageloader/imageloader.js | 623 + .../javascript/yui3/build/io/io-base-min.js | 8 + .../javascript/yui3/build/io/io-base.js | 743 + .../javascript/yui3/build/io/io-form-min.js | 8 + .../javascript/yui3/build/io/io-form.js | 101 + .../javascript/yui3/build/io/io-min.js | 9 + .../javascript/yui3/build/io/io-queue-min.js | 8 + .../javascript/yui3/build/io/io-queue.js | 222 + .../yui3/build/io/io-upload-iframe-min.js | 8 + .../yui3/build/io/io-upload-iframe.js | 283 + .../javascript/yui3/build/io/io-xdr-min.js | 8 + .../javascript/yui3/build/io/io-xdr.js | 291 + .../include/javascript/yui3/build/io/io.js | 1621 + .../javascript/yui3/build/json/json-min.js | 8 + .../yui3/build/json/json-parse-min.js | 8 + .../javascript/yui3/build/json/json-parse.js | 214 + .../yui3/build/json/json-stringify-min.js | 8 + .../yui3/build/json/json-stringify.js | 285 + .../javascript/yui3/build/json/json.js | 496 + .../yui3/build/loader/loader-min.js | 10 + .../javascript/yui3/build/loader/loader.js | 2129 ++ .../node-focusmanager-min.js | 8 + .../node-focusmanager/node-focusmanager.js | 1060 + .../build/node-menunav/node-menunav-min.js | 10 + .../yui3/build/node-menunav/node-menunav.js | 2165 ++ .../yui3/build/node/node-aria-min.js | 8 + .../javascript/yui3/build/node/node-aria.js | 32 + .../yui3/build/node/node-base-min.js | 9 + .../javascript/yui3/build/node/node-base.js | 1560 + .../build/node/node-event-delegate-min.js | 8 + .../yui3/build/node/node-event-delegate.js | 35 + .../build/node/node-event-simulate-min.js | 8 + .../yui3/build/node/node-event-simulate.js | 31 + .../javascript/yui3/build/node/node-min.js | 10 + .../yui3/build/node/node-pluginhost-min.js | 8 + .../yui3/build/node/node-pluginhost.js | 61 + .../yui3/build/node/node-screen-min.js | 8 + .../javascript/yui3/build/node/node-screen.js | 227 + .../yui3/build/node/node-style-min.js | 8 + .../javascript/yui3/build/node/node-style.js | 90 + .../javascript/yui3/build/node/node.js | 1949 + .../javascript/yui3/build/oop/oop-min.js | 8 + .../include/javascript/yui3/build/oop/oop.js | 367 + .../yui3/build/overlay/overlay-min.js | 8 + .../javascript/yui3/build/overlay/overlay.js | 36 + .../yui3/build/plugin/plugin-min.js | 8 + .../javascript/yui3/build/plugin/plugin.js | 170 + .../yui3/build/pluginhost/pluginhost-min.js | 8 + .../yui3/build/pluginhost/pluginhost.js | 296 + .../yui3/build/profiler/profiler-min.js | 8 + .../yui3/build/profiler/profiler.js | 555 + .../build/queue-promote/queue-promote-min.js | 8 + .../yui3/build/queue-promote/queue-promote.js | 60 + .../yui3/build/slider/slider-min.js | 9 + .../javascript/yui3/build/slider/slider.js | 1472 + .../yui3/build/stylesheet/stylesheet-min.js | 8 + .../yui3/build/stylesheet/stylesheet.js | 633 + .../yui3/build/substitute/substitute-min.js | 8 + .../yui3/build/substitute/substitute.js | 139 + .../javascript/yui3/build/test/test-min.js | 12 + .../javascript/yui3/build/test/test.js | 2796 ++ .../yui3/build/widget/widget-min.js | 9 + .../build/widget/widget-position-ext-min.js | 8 + .../yui3/build/widget/widget-position-ext.js | 407 + .../yui3/build/widget/widget-position-min.js | 8 + .../yui3/build/widget/widget-position.js | 272 + .../yui3/build/widget/widget-stack-min.js | 8 + .../yui3/build/widget/widget-stack.js | 403 + .../yui3/build/widget/widget-stdmod-min.js | 8 + .../yui3/build/widget/widget-stdmod.js | 755 + .../javascript/yui3/build/widget/widget.js | 1329 + .../yui3/build/yui-base/yui-base-min.js | 9 + .../yui3/build/yui-base/yui-base.js | 2136 ++ .../javascript/yui3/build/yui/get-min.js | 8 + .../include/javascript/yui3/build/yui/get.js | 734 + .../javascript/yui3/build/yui/yui-base-min.js | 9 + .../javascript/yui3/build/yui/yui-base.js | 2149 ++ .../yui3/build/yui/yui-later-min.js | 8 + .../javascript/yui3/build/yui/yui-later.js | 76 + .../javascript/yui3/build/yui/yui-log-min.js | 8 + .../javascript/yui3/build/yui/yui-log.js | 114 + .../javascript/yui3/build/yui/yui-min.js | 10 + .../include/javascript/yui3/build/yui/yui.js | 3056 ++ jssource/src_files/include/jsolait/init.js | 755 + .../src_files/include/jsolait/lib/codecs.js | 191 + .../src_files/include/jsolait/lib/crypto.js | 172 + .../src_files/include/jsolait/lib/jsonrpc.js | 462 + .../include/jsolait/lib/jsonrpclite.js | 451 + .../src_files/include/jsolait/lib/lang.js | 508 + .../src_files/include/jsolait/lib/langlite.js | 167 + .../src_files/include/jsolait/lib/urllib.js | 335 + jssource/src_files/include/jsolait/lib/xml.js | 270 + .../src_files/include/jsolait/lib/xmlrpc.js | 854 + .../src_files/include/jsolait/missingmixin.js | 174 + .../include/ytree/TreeView/HTMLNode.js | 114 + .../include/ytree/TreeView/MenuNode.js | 24 + .../src_files/include/ytree/TreeView/Node.js | 659 + .../include/ytree/TreeView/RootNode.js | 30 + .../include/ytree/TreeView/TaskNode.js | 276 + .../include/ytree/TreeView/TextNode.js | 135 + .../include/ytree/TreeView/TreeView.js | 2195 ++ .../include/ytree/TreeView/anim/TVAnim.js | 49 + .../include/ytree/TreeView/anim/TVFadeIn.js | 62 + .../include/ytree/TreeView/anim/TVFadeOut.js | 59 + jssource/src_files/include/ytree/treeutil.js | 188 + jssource/src_files/install/dbConfig.js | 77 + jssource/src_files/install/installCommon.js | 48 + jssource/src_files/install/license.js | 62 + jssource/src_files/install/oc_convert.js | 41 + jssource/src_files/install/oc_install.js | 51 + jssource/src_files/install/register.js | 83 + jssource/src_files/install/siteConfig.js | 93 + .../src_files/modules/ACLRoles/ACLRoles.js | 92 + .../src_files/modules/Accounts/Account.js | 90 + .../javascript/Administration.js | 136 + .../Administration/javascript/Async.js | 119 + .../src_files/modules/Campaigns/DetailView.js | 63 + .../src_files/modules/Campaigns/WebToLead.js | 226 + .../src_files/modules/Campaigns/wizard.js | 291 + .../src_files/modules/Connectors/Connector.js | 122 + .../src_files/modules/Contacts/Contact.js | 192 + .../src_files/modules/Currencies/EditView.js | 55 + .../src_files/modules/Documents/documents.js | 127 + jssource/src_files/modules/EAPM/EAPMEdit.js | 110 + .../modules/EmailTemplates/EmailTemplate.js | 189 + jssource/src_files/modules/Home/about.js | 65 + .../modules/InboundEmail/InboundEmail.js | 349 + jssource/src_files/modules/Leads/Lead.js | 108 + .../modules/Meetings/jsclass_scheduler.js | 627 + .../src_files/modules/MergeRecords/Merge.js | 404 + jssource/src_files/modules/Project/Project.js | 97 + .../modules/ProjectTask/ProjectTask.js | 66 + .../src_files/modules/Studio/JSTransaction.js | 79 + jssource/src_files/modules/Studio/studio.js | 549 + jssource/src_files/modules/Studio/studiodd.js | 219 + .../modules/Studio/studiotabgroups.js | 142 + .../modules/Studio/ygDDListStudio.js | 240 + .../modules/UpgradeWizard/upgradeWizard.js | 137 + .../src_files/modules/Users/DetailView.js | 133 + .../modules/Users/PasswordRequirementBox.js | 188 + jssource/src_files/modules/Users/User.js | 216 + jssource/src_files/modules/Users/login.js | 96 + jssource/src_files/service/utils/SugarRest.js | 244 + jssource/src_files/themes/Sugar5/js/style.js | 218 + jssource/src_files/themes/default/js/style.js | 45 + leadCapture.php | 46 + log4php/LoggerManager.php | 7 + log_file_restricted.html | 42 + maintenance.php | 41 + metadata/accounts_bugsMetaData.php | 57 + metadata/accounts_casesMetaData.php | 51 + metadata/accounts_contactsMetaData.php | 59 + metadata/accounts_opportunitiesMetaData.php | 58 + metadata/acl_roles_actionsMetaData.php | 98 + metadata/acl_roles_usersMetaData.php | 92 + metadata/addressBookMetaData.php | 81 + metadata/audit_templateMetaData.php | 61 + metadata/calls_contactsMetaData.php | 61 + metadata/calls_leadsMetaData.php | 61 + metadata/calls_usersMetaData.php | 59 + metadata/cases_bugsMetaData.php | 58 + metadata/configMetaData.php | 39 + metadata/contacts_bugsMetaData.php | 60 + metadata/contacts_casesMetaData.php | 58 + metadata/contacts_usersMetaData.php | 57 + metadata/custom_fieldsMetaData.php | 57 + metadata/documents_accountsMetaData.php | 124 + metadata/documents_bugsMetaData.php | 124 + metadata/documents_casesMetaData.php | 124 + metadata/documents_contactsMetaData.php | 124 + metadata/documents_opportunitiesMetaData.php | 124 + metadata/email_addressesMetaData.php | 245 + metadata/email_cacheMetaData.php | 188 + ...email_marketing_prospect_listsMetaData.php | 99 + metadata/emails_beansMetaData.php | 383 + metadata/fields_meta_dataMetaData.php | 39 + metadata/foldersMetaData.php | 205 + metadata/import_mapsMetaData.php | 39 + metadata/inboundEmail_autoreplyMetaData.php | 105 + .../inboundEmail_cacheTimestampMetaData.php | 68 + .../kbdocuments_views_ratingsMetaData.php | 54 + metadata/linked_documentsMetaData.php | 73 + metadata/meetings_contactsMetaData.php | 106 + metadata/meetings_leadsMetaData.php | 61 + metadata/meetings_usersMetaData.php | 106 + metadata/opportunities_contactsMetaData.php | 65 + metadata/outboundEmailMetaData.php | 160 + metadata/project_bugsMetaData.php | 69 + metadata/project_casesMetaData.php | 69 + metadata/project_productsMetaData.php | 69 + metadata/project_relationMetaData.php | 119 + .../project_task_project_tasksMetaData.php | 94 + metadata/projects_accountsMetaData.php | 70 + metadata/projects_contactsMetaData.php | 70 + metadata/projects_opportunitiesMetaData.php | 70 + metadata/projects_quotesMetaData.php | 70 + metadata/prospect_list_campaignsMetaData.php | 99 + metadata/prospect_lists_prospectsMetaData.php | 169 + metadata/queues_beansMetaData.php | 132 + metadata/queues_queueMetaData.php | 141 + metadata/roles_modulesMetaData.php | 92 + metadata/roles_usersMetaData.php | 91 + metadata/schedulers_timesMetaData.php | 115 + metadata/user_feedsMetaData.php | 52 + metadata/usersMetaData.php | 39 + metadata/users_last_importMetaData.php | 51 + metadata/users_passwordLinkMetaData.php | 84 + metadata/users_signaturesMetaData.php | 108 + metagen.php | 39 + modules/ACL/ACLController.php | 231 + modules/ACL/ACLJSController.php | 178 + modules/ACL/Forms.php | 0 modules/ACL/List.php | 46 + modules/ACL/Menu.php | 44 + modules/ACL/Save.php | 40 + modules/ACL/install_actions.php | 76 + modules/ACL/language/en_us.lang.php | 53 + modules/ACL/metadata/subpaneldefs.php | 73 + modules/ACL/remove_actions.php | 58 + modules/ACL/vardefs.php | 41 + modules/ACLActions/ACLAction.php | 510 + modules/ACLActions/Forms.php | 0 modules/ACLActions/Menu.php | 44 + modules/ACLActions/actiondefs.php | 126 + modules/ACLActions/language/en_us.lang.php | 65 + modules/ACLActions/metadata/subpaneldefs.php | 73 + modules/ACLActions/vardefs.php | 154 + modules/ACLRoles/ACLRole.php | 274 + modules/ACLRoles/ACLRoles.js | 36 + modules/ACLRoles/Delete.php | 46 + modules/ACLRoles/DetailUserRole.php | 92 + modules/ACLRoles/DetailView.php | 98 + modules/ACLRoles/DetailView.tpl | 70 + modules/ACLRoles/DetailViewBody.tpl | 92 + modules/ACLRoles/DetailViewUser.tpl | 46 + modules/ACLRoles/EditAllBody.tpl | 127 + modules/ACLRoles/EditRole.php | 103 + modules/ACLRoles/EditRole.tpl | 96 + modules/ACLRoles/EditView.php | 108 + modules/ACLRoles/EditView.tpl | 85 + modules/ACLRoles/EditViewBody.tpl | 48 + modules/ACLRoles/Forms.php | 0 modules/ACLRoles/ListUsers.php | 71 + modules/ACLRoles/Menu.php | 45 + modules/ACLRoles/Popup_picker.html | 108 + modules/ACLRoles/Popup_picker.php | 147 + modules/ACLRoles/Save.php | 75 + modules/ACLRoles/language/en_us.lang.php | 57 + modules/ACLRoles/metadata/SearchFields.php | 42 + modules/ACLRoles/metadata/listviewdefs.php | 51 + modules/ACLRoles/metadata/popupdefs.php | 50 + modules/ACLRoles/metadata/searchdefs.php | 55 + modules/ACLRoles/metadata/subpaneldefs.php | 76 + modules/ACLRoles/metadata/subpanels/admin.php | 75 + .../ACLRoles/metadata/subpanels/default.php | 77 + modules/ACLRoles/popup.tpl | 77 + modules/ACLRoles/vardefs.php | 144 + modules/ACLRoles/views/view.list.php | 51 + modules/Accounts/Account.js | 50 + modules/Accounts/Account.php | 341 + modules/Accounts/AccountFormBase.php | 551 + modules/Accounts/AccountsQuickCreate.php | 70 + .../MyAccountsDashlet.data.php | 99 + .../MyAccountsDashlet.meta.php | 47 + .../MyAccountsDashlet/MyAccountsDashlet.php | 85 + modules/Accounts/Menu.php | 53 + modules/Accounts/Popup_picker.html | 140 + modules/Accounts/Save.php | 51 + modules/Accounts/ShowDuplicates.html | 73 + modules/Accounts/ShowDuplicates.php | 159 + modules/Accounts/field_arrays.php | 94 + modules/Accounts/language/en_us.lang.php | 183 + modules/Accounts/metadata/SearchFields.php | 76 + modules/Accounts/metadata/acldefs.php | 61 + .../Accounts/metadata/additionalDetails.php | 84 + modules/Accounts/metadata/detailviewdefs.php | 219 + modules/Accounts/metadata/editviewdefs.php | 170 + modules/Accounts/metadata/fieldGroups.php | 38 + modules/Accounts/metadata/listviewdefs.php | 224 + modules/Accounts/metadata/metafiles.php | 52 + modules/Accounts/metadata/popupdefs.php | 138 + modules/Accounts/metadata/quickcreatedefs.php | 126 + modules/Accounts/metadata/searchdefs.php | 171 + modules/Accounts/metadata/studio.php | 66 + modules/Accounts/metadata/subpaneldefs.php | 264 + .../Accounts/metadata/subpanels/ForEmails.php | 76 + .../metadata/subpanels/ForProspectLists.php | 81 + .../Accounts/metadata/subpanels/default.php | 91 + modules/Accounts/tpls/QuickCreate.tpl | 90 + modules/Accounts/vardefs.php | 461 + modules/Accounts/views/view.detail.php | 106 + modules/Accounts/views/view.list.php | 48 + modules/Activities/Forms.php | 37 + modules/Activities/Menu.php | 62 + modules/Activities/OpenListView.html | 117 + modules/Activities/OpenListView.php | 328 + modules/Activities/Popup_picker.html | 71 + modules/Activities/Popup_picker.php | 429 + modules/Activities/SetAcceptStatus.php | 59 + modules/Activities/SubPanelView.html | 94 + modules/Activities/SubPanelView.php | 456 + modules/Activities/SubPanelViewContacts.html | 101 + modules/Activities/config.php | 46 + modules/Activities/language/en_us.lang.php | 130 + modules/Activities/metadata/subpaneldefs.php | 252 + modules/Activities/views/view.list.php | 47 + .../Activities/views/view.modulelistmenu.php | 55 + modules/Administration/Administration.php | 171 + modules/Administration/Async.php | 153 + modules/Administration/Common.php | 707 + modules/Administration/CustomizeFields.php | 71 + modules/Administration/Development.php | 64 + modules/Administration/Diagnostic.php | 103 + modules/Administration/Diagnostic.tpl | 129 + modules/Administration/DiagnosticDelete.php | 82 + modules/Administration/DiagnosticDownload.php | 65 + modules/Administration/DiagnosticRun.php | 837 + modules/Administration/DisplayWarnings.php | 159 + modules/Administration/DstFix.php | 402 + .../ExportCustomFieldStructure.php | 58 + modules/Administration/Forms.php | 79 + .../ImportCustomFieldStructure.php | 86 + modules/Administration/Locale.php | 121 + modules/Administration/Locale.tpl | 217 + modules/Administration/Menu.php | 46 + modules/Administration/PasswordManager.php | 203 + modules/Administration/PasswordManager.tpl | 685 + .../Administration/QuickRepairAndRebuild.php | 470 + modules/Administration/RebuildAudit.php | 58 + modules/Administration/RebuildConfig.html | 58 + modules/Administration/RebuildConfig.php | 84 + modules/Administration/RebuildDashlets.php | 55 + .../RebuildExpressionPlugins.php | 41 + .../Administration/RebuildFulltextIndices.php | 83 + modules/Administration/RebuildJSLang.php | 61 + .../Administration/RebuildRelationship.php | 151 + modules/Administration/RebuildSchedulers.php | 77 + modules/Administration/RepairActivities.php | 68 + modules/Administration/RepairFieldCasing.php | 152 + modules/Administration/RepairIE.php | 72 + modules/Administration/RepairIndex.php | 253 + modules/Administration/RepairJSFile.php | 99 + modules/Administration/RepairSeedUsers.php | 87 + modules/Administration/RepairXSS.php | 89 + modules/Administration/Save.php | 81 + modules/Administration/SupportPortal.php | 270 + modules/Administration/SupportPortal.tpl | 62 + modules/Administration/Updater.html | 98 + modules/Administration/Updater.php | 126 + modules/Administration/Upgrade.php | 144 + modules/Administration/UpgradeAccess.php | 151 + modules/Administration/UpgradeFields.php | 154 + modules/Administration/UpgradeHistory.php | 288 + modules/Administration/UpgradeIISAccess.php | 43 + modules/Administration/UpgradeWizard.php | 367 + .../Administration/UpgradeWizardCommon.php | 264 + .../Administration/UpgradeWizard_commit.php | 555 + .../Administration/UpgradeWizard_prepare.php | 534 + modules/Administration/action_view_map.php | 46 + modules/Administration/callJSRepair.php | 85 + modules/Administration/clear_chart_cache.php | 77 + modules/Administration/controller.php | 166 + modules/Administration/expandDatabase.php | 170 + modules/Administration/index.html | 62 + modules/Administration/index.php | 156 + modules/Administration/index.tpl | 90 + .../javascript/Administration.js | 39 + modules/Administration/javascript/Async.js | 37 + .../Administration/language/en_us.lang.php | 1093 + .../Administration/metadata/SearchFields.php | 45 + .../metadata/adminpaneldefs.php | 200 + modules/Administration/ncc_config.php | 38 + modules/Administration/repairDatabase.php | 176 + modules/Administration/repairSelectModule.php | 97 + modules/Administration/repairUniSearch.php | 56 + .../templates/ConfigureTabs.tpl | 206 + .../templates/GlobalSearchSettings.tpl | 154 + .../Administration/templates/Languages.tpl | 152 + .../templates/QuickRepairAndRebuild.tpl | 49 + .../templates/RepairDatabase.tpl | 48 + .../Administration/templates/RepairXSS.tpl | 61 + .../Administration/templates/ShortcutBar.tpl | 170 + .../templates/themeSettings.tpl | 158 + modules/Administration/undoupdateclass.php | 54 + .../Administration/updateTimezonePrefs.php | 172 + modules/Administration/updateclass.php | 111 + modules/Administration/updater_utils.php | 423 + .../upgrade_custom_relationships.php | 122 + modules/Administration/vardefs.php | 149 + modules/Administration/views/view.backups.php | 189 + .../views/view.configuretabs.php | 137 + .../views/view.globalsearchsettings.php | 85 + .../Administration/views/view.languages.php | 109 + modules/Administration/views/view.repair.php | 61 + .../views/view.themesettings.php | 119 + modules/Audit/Audit.php | 219 + modules/Audit/Popup_picker.html | 65 + modules/Audit/Popup_picker.php | 201 + modules/Audit/field_assoc.php | 86 + modules/Audit/language/en_us.lang.php | 50 + modules/Audit/vardefs.php | 39 + modules/BeanDictionary.php | 40 + modules/Bugs/Bug.php | 397 + modules/Bugs/BugsQuickCreate.php | 74 + .../MyBugsDashlet/MyBugsDashlet.data.php | 85 + .../MyBugsDashlet/MyBugsDashlet.meta.php | 47 + .../Dashlets/MyBugsDashlet/MyBugsDashlet.php | 80 + modules/Bugs/Menu.php | 53 + modules/Bugs/field_arrays.php | 68 + modules/Bugs/language/en_us.lang.php | 115 + modules/Bugs/metadata/SearchFields.php | 66 + modules/Bugs/metadata/additionalDetails.php | 80 + modules/Bugs/metadata/detailviewdefs.php | 118 + modules/Bugs/metadata/editviewdefs.php | 115 + modules/Bugs/metadata/listviewdefs.php | 90 + modules/Bugs/metadata/metafiles.php | 52 + modules/Bugs/metadata/popupdefs.php | 89 + modules/Bugs/metadata/quickcreatedefs.php | 143 + modules/Bugs/metadata/searchdefs.php | 69 + modules/Bugs/metadata/studio.php | 66 + modules/Bugs/metadata/subpaneldefs.php | 186 + modules/Bugs/metadata/subpanels/ForEmails.php | 85 + modules/Bugs/metadata/subpanels/default.php | 95 + modules/Bugs/tpls/QuickCreate.tpl | 93 + modules/Bugs/vardefs.php | 318 + modules/Bugs/views/view.detail.php | 65 + modules/Bugs/views/view.edit.php | 65 + modules/Calendar/Calendar.php | 613 + modules/Calendar/DateTimeUtil.php | 637 + modules/Calendar/Forms.php | 45 + modules/Calendar/Menu.php | 57 + modules/Calendar/SubPanelSharedCalendar.php | 69 + modules/Calendar/TasksListView.html | 61 + modules/Calendar/TasksListView.php | 144 + modules/Calendar/index.php | 128 + modules/Calendar/language/en_us.lang.php | 142 + modules/Calendar/metadata/listviewdefs.php | 68 + modules/Calendar/small_month.php | 56 + .../templates/template_shared_calendar.php | 183 + .../Calendar/templates/templates_calendar.php | 868 + modules/Calendar/views/view.list.php | 52 + modules/Calls/Call.php | 687 + modules/Calls/CallFormBase.php | 614 + modules/Calls/CallHelper.php | 103 + modules/Calls/CallsQuickCreate.php | 144 + .../MyCallsDashlet/MyCallsDashlet.data.php | 95 + .../MyCallsDashlet/MyCallsDashlet.meta.php | 47 + .../MyCallsDashlet/MyCallsDashlet.php | 163 + modules/Calls/Menu.php | 51 + modules/Calls/Save.php | 49 + modules/Calls/SubPanelViewInvitees.html | 89 + modules/Calls/SubPanelViewInvitees.php | 149 + modules/Calls/field_arrays.php | 69 + modules/Calls/language/en_us.lang.php | 130 + modules/Calls/metadata/SearchFields.php | 71 + modules/Calls/metadata/additionalDetails.php | 80 + modules/Calls/metadata/detailviewdefs.php | 152 + modules/Calls/metadata/editviewdefs.php | 162 + modules/Calls/metadata/listviewdefs.php | 123 + modules/Calls/metadata/quickcreatedefs.php | 177 + modules/Calls/metadata/searchdefs.php | 126 + modules/Calls/metadata/studio.php | 66 + modules/Calls/metadata/subpaneldefs.php | 96 + .../metadata/subpanels/ForActivities.php | 120 + .../Calls/metadata/subpanels/ForHistory.php | 128 + modules/Calls/metadata/subpanels/default.php | 114 + modules/Calls/tpls/QuickCreate.tpl | 138 + modules/Calls/tpls/footer.tpl | 87 + modules/Calls/vardefs.php | 389 + modules/Calls/views/view.edit.php | 90 + modules/CampaignLog/CampaignLog.php | 204 + modules/CampaignLog/Menu.php | 49 + modules/CampaignLog/Popup_picker.html | 101 + modules/CampaignLog/Popup_picker.php | 178 + modules/CampaignLog/language/en_us.lang.php | 100 + .../metadata/subpanels/ForTargets.php | 87 + .../metadata/subpanels/default.php | 100 + modules/CampaignLog/vardefs.php | 289 + modules/CampaignTrackers/CampaignTracker.php | 161 + modules/CampaignTrackers/DetailView.html | 88 + modules/CampaignTrackers/DetailView.php | 118 + modules/CampaignTrackers/EditView.html | 91 + modules/CampaignTrackers/EditView.php | 132 + modules/CampaignTrackers/Forms.html | 70 + modules/CampaignTrackers/Forms.php | 137 + modules/CampaignTrackers/Menu.php | 49 + modules/CampaignTrackers/Save.php | 82 + .../CampaignTrackers/language/en_us.lang.php | 74 + .../metadata/subpanels/default.php | 76 + modules/CampaignTrackers/vardefs.php | 157 + modules/Campaigns/Campaign.php | 406 + modules/Campaigns/CampaignDiagnostic.html | 77 + modules/Campaigns/CampaignDiagnostic.php | 278 + modules/Campaigns/CaptchaValidate.php | 65 + modules/Campaigns/Charts.php | 316 + modules/Campaigns/Charts1.php | 106 + .../TopCampaignsDashlet.meta.php | 47 + .../TopCampaignsDashlet.php | 132 + .../TopCampaignsDashlet.tpl | 59 + .../TopCampaignsDashletConfigure.tpl | 74 + modules/Campaigns/Delete.php | 116 + modules/Campaigns/DetailView.js | 41 + modules/Campaigns/EmailQueue.php | 125 + modules/Campaigns/GenerateWebToLeadForm.php | 580 + modules/Campaigns/MailMerge.php | 42 + modules/Campaigns/Menu.php | 91 + modules/Campaigns/PopupCampaignRoi.html | 71 + modules/Campaigns/PopupCampaignRoi.php | 200 + modules/Campaigns/Popup_picker.html | 118 + modules/Campaigns/Popup_picker.php | 176 + modules/Campaigns/ProcessBouncedEmails.php | 214 + modules/Campaigns/QueueCampaign.php | 212 + modules/Campaigns/RemoveMe.php | 89 + modules/Campaigns/RoiDetailView.php | 210 + modules/Campaigns/RoiDetailView.tpl | 140 + modules/Campaigns/Save.php | 131 + modules/Campaigns/Schedule.html | 75 + modules/Campaigns/Schedule.php | 171 + modules/Campaigns/SearchForm_NewsLetter.html | 103 + modules/Campaigns/SubPanelViewer.php | 105 + modules/Campaigns/Subscriptions.html | 117 + modules/Campaigns/Subscriptions.php | 244 + modules/Campaigns/Subscriptions.tpl | 295 + modules/Campaigns/TrackDetailView.php | 269 + modules/Campaigns/TrackDetailView.tpl | 173 + modules/Campaigns/Tracker.php | 92 + modules/Campaigns/WebToLead.js | 63 + modules/Campaigns/WebToLeadCapture.php | 220 + modules/Campaigns/WebToLeadCreation.html | 204 + modules/Campaigns/WebToLeadCreation.php | 308 + modules/Campaigns/WebToLeadDownloadForm.html | 90 + modules/Campaigns/WebToLeadForm.html | 102 + modules/Campaigns/WebToLeadFormSave.php | 122 + modules/Campaigns/WizardEmailSetup.html | 326 + modules/Campaigns/WizardEmailSetup.php | 413 + modules/Campaigns/WizardEmailSetupSave.php | 124 + modules/Campaigns/WizardHome.html | 92 + modules/Campaigns/WizardHome.php | 490 + modules/Campaigns/WizardMarketing.html | 382 + modules/Campaigns/WizardMarketing.php | 318 + modules/Campaigns/WizardMarketingSave.php | 189 + modules/Campaigns/WizardNewsletter.html | 107 + modules/Campaigns/WizardNewsletter.php | 611 + modules/Campaigns/WizardNewsletterSave.php | 337 + modules/Campaigns/action_file_map.php | 45 + modules/Campaigns/chart.tpl | 63 + modules/Campaigns/controller.php | 45 + modules/Campaigns/field_arrays.php | 68 + modules/Campaigns/image.php | 48 + modules/Campaigns/language/en_us.lang.php | 430 + modules/Campaigns/metadata/SearchFields.php | 66 + .../Campaigns/metadata/additionalDetails.php | 74 + modules/Campaigns/metadata/detailviewdefs.php | 158 + modules/Campaigns/metadata/editviewdefs.php | 150 + modules/Campaigns/metadata/listviewdefs.php | 90 + modules/Campaigns/metadata/popupdefs.php | 78 + modules/Campaigns/metadata/searchdefs.php | 60 + modules/Campaigns/metadata/studio.php | 66 + modules/Campaigns/metadata/subpaneldefs.php | 205 + .../metadata/subpanels/ForEmailMarketing.php | 51 + .../Campaigns/metadata/subpanels/default.php | 75 + .../Campaigns/tpls/WizardCampaignBudget.tpl | 137 + .../Campaigns/tpls/WizardCampaignHeader.tpl | 156 + .../tpls/WizardCampaignTargetList.tpl | 183 + ...zardCampaignTargetListForNonNewsLetter.tpl | 308 + .../Campaigns/tpls/WizardCampaignTracker.tpl | 257 + modules/Campaigns/tpls/WizardHomeStart.tpl | 111 + modules/Campaigns/tpls/WizardNewsletter.tpl | 109 + modules/Campaigns/utils.php | 985 + modules/Campaigns/vardefs.php | 323 + modules/Campaigns/views/view.classic.php | 109 + modules/Campaigns/views/view.detail.php | 138 + .../Campaigns/views/view.modulelistmenu.php | 55 + .../Campaigns/views/view.newsletterlist.php | 75 + modules/Campaigns/wizard.js | 56 + modules/Cases/Case.php | 317 + modules/Cases/CasesQuickCreate.php | 89 + .../MyCasesDashlet/MyCasesDashlet.data.php | 84 + .../MyCasesDashlet/MyCasesDashlet.meta.php | 47 + .../MyCasesDashlet/MyCasesDashlet.php | 58 + modules/Cases/Menu.php | 54 + modules/Cases/SugarFeeds/CaseFeed.php | 59 + modules/Cases/field_arrays.php | 64 + modules/Cases/language/en_us.lang.php | 110 + modules/Cases/metadata/SearchFields.php | 55 + .../metadata/accountsquickcreatedefs.php | 77 + modules/Cases/metadata/additionalDetails.php | 69 + modules/Cases/metadata/detailviewdefs.php | 105 + modules/Cases/metadata/editviewdefs.php | 99 + modules/Cases/metadata/listviewdefs.php | 80 + modules/Cases/metadata/popupdefs.php | 92 + modules/Cases/metadata/quickcreatedefs.php | 75 + modules/Cases/metadata/searchdefs.php | 61 + modules/Cases/metadata/studio.php | 66 + modules/Cases/metadata/subpaneldefs.php | 195 + .../Cases/metadata/subpanels/ForAccounts.php | 95 + .../Cases/metadata/subpanels/ForEmails.php | 94 + modules/Cases/metadata/subpanels/default.php | 100 + modules/Cases/tpls/QuickCreate.tpl | 100 + modules/Cases/vardefs.php | 264 + .../CampaignROIChartConfigure.tpl | 71 + .../CampaignROIChartDashlet.data.php | 48 + .../CampaignROIChartDashlet.en_us.lang.php | 45 + .../CampaignROIChartDashlet.meta.php | 50 + .../CampaignROIChartDashlet.php | 87 + .../MyPipelineBySalesStageConfigure.tpl | 100 + .../MyPipelineBySalesStageDashlet.data.php | 59 + ...PipelineBySalesStageDashlet.en_us.lang.php | 45 + .../MyPipelineBySalesStageDashlet.meta.php | 48 + .../MyPipelineBySalesStageDashlet.php | 256 + .../OppByLeadOutcomeConfigure.tpl | 79 + .../OppByLeadOutcomeDashlet.data.php | 53 + .../OppByLeadOutcomeDashlet.en_us.lang.php | 45 + .../OppByLeadOutcomeDashlet.meta.php | 48 + .../OppByLeadOutcomeDashlet.php | 129 + .../OppByLeadSourceConfigure.tpl | 79 + .../OppByLeadSourceDashlet.data.php | 53 + .../OppByLeadSourceDashlet.en_us.lang.php | 45 + .../OppByLeadSourceDashlet.meta.php | 48 + .../OppByLeadSourceDashlet.php | 130 + .../OutcomeByMonthConfigure.tpl | 100 + .../OutcomeByMonthDashlet.data.php | 58 + .../OutcomeByMonthDashlet.en_us.lang.php | 45 + .../OutcomeByMonthDashlet.meta.php | 48 + .../OutcomeByMonthDashlet.php | 138 + .../PipelineBySalesStageConfigure.tpl | 100 + .../PipelineBySalesStageDashlet.data.php | 58 + ...PipelineBySalesStageDashlet.en_us.lang.php | 45 + .../PipelineBySalesStageDashlet.meta.php | 48 + .../PipelineBySalesStageDashlet.php | 217 + .../Dashlets/PredefinedChartDashletScript.tpl | 45 + modules/Charts/DynamicAction.php | 51 + modules/Charts/PredefinedChart.php | 525 + modules/Charts/chartdefs.php | 122 + .../code/Chart_lead_source_by_outcome.php | 449 + .../code/Chart_my_pipeline_by_sales_stage.php | 495 + .../Charts/code/Chart_outcome_by_month.php | 460 + .../code/Chart_pipeline_by_lead_source.php | 431 + .../code/Chart_pipeline_by_sales_stage.php | 617 + modules/Charts/code/predefined_charts.php | 49 + modules/Charts/language/en_us.lang.php | 104 + modules/Configurator/Configurator.php | 291 + modules/Configurator/Forms.php | 104 + modules/Configurator/LogView.php | 154 + modules/Configurator/Menu.php | 43 + modules/Configurator/UploadFileCheck.php | 109 + modules/Configurator/action_view_map.php | 39 + modules/Configurator/controller.php | 191 + modules/Configurator/language/en_us.lang.php | 419 + .../metadata/SugarpdfSettingsdefs.php | 279 + modules/Configurator/tpls/EditView.tpl | 428 + .../Configurator/tpls/SugarpdfSettings.tpl | 221 + .../tpls/SugarpdfSettingsFields.tpl | 96 + modules/Configurator/tpls/addFontResult.tpl | 59 + modules/Configurator/tpls/addFontView.tpl | 166 + modules/Configurator/tpls/adminwizard.tpl | 794 + modules/Configurator/tpls/fontmanager.tpl | 120 + .../Configurator/views/view.addfontresult.php | 108 + .../Configurator/views/view.addfontview.php | 86 + .../Configurator/views/view.adminwizard.php | 123 + modules/Configurator/views/view.edit.php | 138 + .../Configurator/views/view.fontmanager.php | 245 + .../views/view.sugarpdfsettings.php | 200 + modules/Connectors/Connector.js | 56 + modules/Connectors/ConnectorRecord.php | 51 + modules/Connectors/Forms.php | 38 + .../Connectors/InstallDefaultConnectors.php | 116 + modules/Connectors/Menu.php | 63 + modules/Connectors/action_view_map.php | 60 + .../formatters/ext/rest/linkedin/linkedin.php | 60 + .../ext/rest/linkedin/tpls/default.tpl | 80 + .../ext/rest/linkedin/tpls/linkedin.gif | Bin 0 -> 325 bytes .../ext/rest/twitter/tpls/twitter.gif | Bin 0 -> 115 bytes .../sources/ext/rest/linkedin/config.php | 47 + .../ext/rest/linkedin/language/en_us.lang.php | 56 + .../sources/ext/rest/linkedin/linkedin.php | 69 + .../sources/ext/rest/linkedin/mapping.php | 54 + .../sources/ext/rest/linkedin/vardefs.php | 59 + modules/Connectors/controller.php | 647 + modules/Connectors/language/en_us.lang.php | 119 + modules/Connectors/metadata/searchdefs.php | 43 + modules/Connectors/tpls/administration.tpl | 102 + .../Connectors/tpls/display_properties.tpl | 215 + modules/Connectors/tpls/listview.tpl | 82 + .../Connectors/tpls/mapping_properties.tpl | 85 + modules/Connectors/tpls/modify_display.tpl | 188 + modules/Connectors/tpls/modify_mapping.tpl | 183 + modules/Connectors/tpls/modify_properties.tpl | 155 + modules/Connectors/tpls/modify_search.tpl | 184 + modules/Connectors/tpls/search_form.tpl | 72 + modules/Connectors/tpls/search_properties.tpl | 221 + modules/Connectors/tpls/source_properties.tpl | 82 + modules/Connectors/tpls/tabs.css | 134 + .../views/view.connectorsettings.php | 77 + .../views/view.displayproperties.php | 115 + .../views/view.mappingproperties.php | 158 + .../Connectors/views/view.modifydisplay.php | 82 + .../Connectors/views/view.modifymapping.php | 90 + .../views/view.modifyproperties.php | 104 + .../Connectors/views/view.modifysearch.php | 90 + .../views/view.searchproperties.php | 126 + .../views/view.sourceproperties.php | 88 + modules/Contacts/AcceptDecline.php | 115 + modules/Contacts/Address_picker.html | 118 + modules/Contacts/BusinessCard.html | 164 + modules/Contacts/BusinessCard.php | 367 + modules/Contacts/Contact.js | 61 + modules/Contacts/Contact.php | 615 + modules/Contacts/ContactFormBase.php | 810 + .../ContactOpportunityRelationship.php | 124 + .../ContactOpportunityRelationshipEdit.html | 104 + .../ContactOpportunityRelationshipEdit.php | 115 + modules/Contacts/ContactsQuickCreate.php | 72 + .../MyContactsDashlet.data.php | 87 + .../MyContactsDashlet.meta.php | 47 + .../MyContactsDashlet/MyContactsDashlet.php | 61 + modules/Contacts/Email_picker.html | 178 + modules/Contacts/MailMergePicker.html | 185 + modules/Contacts/Menu.php | 53 + modules/Contacts/Popup_picker.php | 390 + modules/Contacts/Save.php | 50 + .../SaveContactOpportunityRelationship.php | 81 + modules/Contacts/ShowDuplicates.html | 68 + modules/Contacts/ShowDuplicates.php | 174 + modules/Contacts/SugarFeeds/ContactFeed.php | 57 + modules/Contacts/controller.php | 68 + modules/Contacts/field_arrays.php | 91 + modules/Contacts/language/en_us.lang.php | 224 + modules/Contacts/metadata/SearchFields.php | 74 + .../Contacts/metadata/additionalDetails.php | 79 + modules/Contacts/metadata/detailviewdefs.php | 215 + modules/Contacts/metadata/editviewdefs.php | 213 + modules/Contacts/metadata/listviewdefs.php | 179 + modules/Contacts/metadata/metafiles.php | 51 + modules/Contacts/metadata/popupdefs.php | 93 + modules/Contacts/metadata/popupdefsEmail.php | 59 + modules/Contacts/metadata/quickcreatedefs.php | 147 + modules/Contacts/metadata/searchdefs.php | 154 + modules/Contacts/metadata/studio.php | 66 + modules/Contacts/metadata/subpaneldefs.php | 257 + .../metadata/subpanels/ForAccounts.php | 106 + .../Contacts/metadata/subpanels/ForCalls.php | 121 + .../Contacts/metadata/subpanels/ForCases.php | 110 + .../metadata/subpanels/ForContacts.php | 109 + .../Contacts/metadata/subpanels/ForEmails.php | 104 + .../metadata/subpanels/ForMeetings.php | 121 + .../metadata/subpanels/ForOpportunities.php | 131 + .../metadata/subpanels/ForProject.php | 81 + .../Contacts/metadata/subpanels/default.php | 112 + modules/Contacts/tpls/QuickCreate.tpl | 92 + modules/Contacts/vardefs.php | 597 + .../views/view.closecontactaddresspopup.php | 51 + .../views/view.contactaddresspopup.php | 62 + modules/Contacts/views/view.detail.php | 59 + modules/Contacts/views/view.edit.php | 90 + modules/Contacts/views/view.list.php | 48 + .../Contacts/views/view.mailmergepopup.php | 62 + modules/Contacts/views/view.retrieveemail.php | 77 + .../views/view.validportalusername.php | 78 + modules/Currencies/Currency.php | 630 + modules/Currencies/EditCurrency.php | 54 + modules/Currencies/EditView.js | 38 + modules/Currencies/EditView.tpl | 81 + modules/Currencies/Forms.php | 66 + modules/Currencies/ListCurrency.php | 244 + modules/Currencies/ListView.html | 72 + modules/Currencies/Menu.php | 50 + modules/Currencies/field_arrays.php | 57 + modules/Currencies/index.php | 189 + modules/Currencies/iso4217.php | 1850 + modules/Currencies/language/en_us.lang.php | 83 + modules/Currencies/vardefs.php | 143 + .../DocumentRevisions/DocumentRevision.php | 303 + modules/DocumentRevisions/Forms.php | 195 + modules/DocumentRevisions/ListView.html | 106 + modules/DocumentRevisions/Menu.php | 61 + modules/DocumentRevisions/field_arrays.php | 72 + .../DocumentRevisions/language/en_us.lang.php | 92 + .../metadata/detailviewdefs.php | 76 + .../metadata/editviewdefs.php | 75 + .../metadata/subpanels/default.php | 80 + .../DocumentRevisions/subpanels/default.php | 93 + modules/DocumentRevisions/vardefs.php | 239 + .../MyDocumentsDashlet.data.php | 102 + .../MyDocumentsDashlet.meta.php | 45 + .../MyDocumentsDashlet/MyDocumentsDashlet.php | 71 + modules/Documents/Delete.php | 88 + modules/Documents/Document.php | 341 + .../Documents/DocumentExternalApiDropDown.php | 51 + modules/Documents/DocumentSoap.php | 92 + modules/Documents/GetLatestRevision.php | 53 + modules/Documents/Menu.php | 61 + modules/Documents/Popup.php | 47 + modules/Documents/Popup_picker.html | 184 + modules/Documents/Popup_picker.php | 220 + modules/Documents/TreeData.php | 140 + modules/Documents/action_view_map.php | 38 + modules/Documents/documents.js | 49 + modules/Documents/field_arrays.php | 84 + modules/Documents/language/en_us.lang.php | 190 + modules/Documents/metadata/SearchFields.php | 55 + modules/Documents/metadata/detailviewdefs.php | 120 + modules/Documents/metadata/editviewdefs.php | 128 + modules/Documents/metadata/listviewdefs.php | 122 + .../Documents/metadata/quickcreatedefs.php | 89 + modules/Documents/metadata/searchdefs.php | 74 + modules/Documents/metadata/studio.php | 66 + modules/Documents/metadata/subpaneldefs.php | 178 + .../metadata/subpanels/ForContractType.php | 91 + .../Documents/metadata/subpanels/default.php | 111 + modules/Documents/tpls/view.extdoc.tpl | 132 + modules/Documents/vardefs.php | 433 + modules/Documents/views/view.detail.php | 63 + modules/Documents/views/view.edit.php | 175 + modules/Documents/views/view.extdoc.php | 187 + modules/DynamicFields/DynamicField.php | 923 + modules/DynamicFields/FieldCases.php | 150 + modules/DynamicFields/FieldViewer.php | 120 + modules/DynamicFields/FieldsMetaData.php | 139 + modules/DynamicFields/Save.php | 73 + modules/DynamicFields/UpgradeFields.php | 134 + modules/DynamicFields/language/en_us.lang.php | 130 + .../templates/Fields/Forms/address.tpl | 86 + .../templates/Fields/Forms/bool.tpl | 46 + .../templates/Fields/Forms/coreBottom.tpl | 86 + .../templates/Fields/Forms/coreTop.tpl | 94 + .../templates/Fields/Forms/currency.tpl | 62 + .../templates/Fields/Forms/date.php | 47 + .../templates/Fields/Forms/date.tpl | 72 + .../templates/Fields/Forms/datetimecombo.php | 84 + .../templates/Fields/Forms/datetimecombo.tpl | 117 + .../templates/Fields/Forms/encrypt.php | 48 + .../templates/Fields/Forms/encrypt.tpl | 51 + .../templates/Fields/Forms/enum.tpl | 78 + .../templates/Fields/Forms/enum2.php | 115 + .../templates/Fields/Forms/float.tpl | 91 + .../templates/Fields/Forms/html.php | 55 + .../templates/Fields/Forms/html.tpl | 75 + .../templates/Fields/Forms/iframe.php | 48 + .../templates/Fields/Forms/iframe.tpl | 116 + .../templates/Fields/Forms/image.php | 63 + .../templates/Fields/Forms/image.tpl | 78 + .../templates/Fields/Forms/int.tpl | 133 + .../templates/Fields/Forms/multienum.php | 46 + .../templates/Fields/Forms/multienum.tpl | 89 + .../templates/Fields/Forms/parent.php | 48 + .../templates/Fields/Forms/parent.tpl | 88 + .../templates/Fields/Forms/phone.php | 45 + .../templates/Fields/Forms/phone.tpl | 87 + .../templates/Fields/Forms/radioenum.php | 45 + .../templates/Fields/Forms/relate.php | 75 + .../templates/Fields/Forms/relate.tpl | 54 + .../templates/Fields/Forms/text.tpl | 76 + .../templates/Fields/Forms/url.php | 61 + .../templates/Fields/Forms/url.tpl | 118 + .../templates/Fields/Forms/varchar.tpl | 84 + .../templates/Fields/TemplateAddress.php | 67 + .../Fields/TemplateAddressCountry.php | 53 + .../templates/Fields/TemplateBoolean.php | 135 + .../templates/Fields/TemplateCurrency.php | 105 + .../templates/Fields/TemplateCurrencyId.php | 63 + .../templates/Fields/TemplateDate.php | 109 + .../Fields/TemplateDatetimecombo.php | 193 + .../templates/Fields/TemplateDecimal.php | 87 + .../templates/Fields/TemplateEmail.php | 48 + .../templates/Fields/TemplateEncrypt.php | 61 + .../templates/Fields/TemplateEnum.php | 204 + .../templates/Fields/TemplateField.php | 478 + .../templates/Fields/TemplateFloat.php | 103 + .../templates/Fields/TemplateHTML.php | 119 + .../templates/Fields/TemplateIFrame.php | 64 + .../templates/Fields/TemplateId.php | 47 + .../templates/Fields/TemplateImage.php | 84 + .../templates/Fields/TemplateInt.php | 122 + .../templates/Fields/TemplateMultiEnum.php | 178 + .../templates/Fields/TemplateParent.php | 107 + .../templates/Fields/TemplateParentType.php | 53 + .../templates/Fields/TemplatePhone.php | 69 + .../templates/Fields/TemplateRadioEnum.php | 136 + .../templates/Fields/TemplateRange.php | 287 + .../Fields/TemplateRelatedTextField.php | 255 + .../templates/Fields/TemplateText.php | 80 + .../templates/Fields/TemplateTextArea.php | 109 + .../templates/Fields/TemplateURL.php | 78 + .../templates/Files/DetailView.php | 49 + .../templates/Files/EditView.php | 49 + modules/DynamicFields/vardefs.php | 69 + modules/EAPM/CheckLogins.php | 89 + modules/EAPM/EAPM.php | 230 + modules/EAPM/EAPMEdit.js | 41 + modules/EAPM/action_view_map.php | 38 + modules/EAPM/controller.php | 186 + modules/EAPM/language/en_us.lang.php | 106 + modules/EAPM/metadata/SearchFields.php | 57 + modules/EAPM/metadata/detailviewdefs.php | 85 + modules/EAPM/metadata/editviewdefs.php | 84 + modules/EAPM/metadata/listviewdefs.php | 69 + modules/EAPM/metadata/metafiles.php | 52 + modules/EAPM/metadata/popupdefs.php | 52 + modules/EAPM/metadata/quickcreatedefs.php | 64 + modules/EAPM/metadata/searchdefs.php | 62 + modules/EAPM/metadata/subpanels/default.php | 77 + modules/EAPM/tpls/DetailViewFooter.tpl | 44 + modules/EAPM/tpls/EditViewFooter.tpl | 50 + modules/EAPM/tpls/EditViewHeader.tpl | 76 + modules/EAPM/vardefs.php | 200 + modules/EAPM/views/view.detail.php | 111 + modules/EAPM/views/view.edit.php | 121 + modules/EmailAddresses/EmailAddress.php | 68 + .../EmailAddresses/language/en_us.lang.php | 55 + modules/EmailAddresses/vardefs.php | 59 + modules/EmailMan/EmailMan.php | 1013 + modules/EmailMan/EmailManDelivery.php | 266 + modules/EmailMan/Forms.php | 155 + modules/EmailMan/Menu.php | 47 + modules/EmailMan/Save.php | 120 + modules/EmailMan/action_view_map.php | 39 + modules/EmailMan/field_arrays.php | 92 + modules/EmailMan/language/en_us.lang.php | 159 + modules/EmailMan/metadata/SearchFields.php | 45 + modules/EmailMan/metadata/listviewdefs.php | 78 + modules/EmailMan/metadata/searchdefs.php | 61 + .../EmailMan/metadata/subpanels/default.php | 78 + modules/EmailMan/subpanels/default.php | 78 + modules/EmailMan/testOutboundEmail.php | 73 + modules/EmailMan/tpls/campaignconfig.tpl | 125 + modules/EmailMan/tpls/config.tpl | 700 + modules/EmailMan/vardefs.php | 176 + .../EmailMan/views/view.campaignconfig.php | 130 + modules/EmailMan/views/view.config.php | 183 + modules/EmailMan/views/view.list.php | 100 + modules/EmailMarketing/Delete.php | 69 + modules/EmailMarketing/DetailView.html | 95 + modules/EmailMarketing/DetailView.php | 178 + modules/EmailMarketing/EditView.html | 226 + modules/EmailMarketing/EditView.php | 224 + modules/EmailMarketing/EmailMarketing.php | 173 + modules/EmailMarketing/Forms.php | 83 + modules/EmailMarketing/Menu.php | 57 + modules/EmailMarketing/Save.php | 142 + modules/EmailMarketing/SubPanelView.html | 65 + modules/EmailMarketing/SubPanelView.php | 90 + modules/EmailMarketing/field_arrays.php | 58 + .../EmailMarketing/language/en_us.lang.php | 108 + .../EmailMarketing/metadata/subpaneldefs.php | 67 + .../metadata/subpanels/default.php | 89 + modules/EmailMarketing/subpanels/default.php | 88 + modules/EmailMarketing/vardefs.php | 226 + modules/EmailTemplates/AttachFiles.php | 74 + modules/EmailTemplates/CheckDeletable.php | 84 + modules/EmailTemplates/Delete.php | 62 + modules/EmailTemplates/DetailView.html | 128 + modules/EmailTemplates/DetailView.php | 183 + modules/EmailTemplates/EditView.html | 250 + modules/EmailTemplates/EditView.php | 349 + modules/EmailTemplates/EditViewMain.html | 257 + modules/EmailTemplates/EmailTemplate.js | 60 + modules/EmailTemplates/EmailTemplate.php | 592 + .../EmailTemplates/EmailTemplateFormBase.php | 370 + modules/EmailTemplates/Menu.php | 47 + .../PopupDocumentsCampaignTemplate.html | 110 + .../PopupDocumentsCampaignTemplate.php | 147 + modules/EmailTemplates/Save.php | 68 + modules/EmailTemplates/field_arrays.php | 61 + .../EmailTemplates/language/en_us.lang.php | 116 + .../EmailTemplates/metadata/SearchFields.php | 43 + .../EmailTemplates/metadata/listviewdefs.php | 67 + .../EmailTemplates/metadata/searchdefs.php | 67 + modules/EmailTemplates/vardefs.php | 204 + modules/Emails/Check.php | 111 + modules/Emails/Compose.php | 266 + .../MyEmailsDashlet/MyEmailsDashlet.data.php | 83 + .../MyEmailsDashlet/MyEmailsDashlet.meta.php | 47 + .../MyEmailsDashlet/MyEmailsDashlet.php | 124 + modules/Emails/Delete.php | 72 + modules/Emails/DetailView.html | 165 + modules/Emails/DetailView.php | 356 + modules/Emails/DetailViewSent.html | 182 + modules/Emails/EditView.html | 434 + modules/Emails/EditView.php | 780 + modules/Emails/EditViewArchive.html | 319 + modules/Emails/Email.php | 3125 ++ modules/Emails/EmailUI.css | 496 + modules/Emails/EmailUI.php | 2960 ++ modules/Emails/EmailUIAjax.php | 1622 + modules/Emails/GenerateQuickComposeFrame.php | 50 + modules/Emails/Grab.php | 73 + modules/Emails/ListViewDrafts.html | 72 + modules/Emails/ListViewGroup.php | 264 + modules/Emails/ListViewGroupInbox.html | 83 + modules/Emails/ListViewHome.html | 68 + modules/Emails/ListViewHome.php | 77 + modules/Emails/ListViewMyInbox.html | 81 + modules/Emails/ListViewSent.html | 70 + modules/Emails/MassDelete.php | 61 + modules/Emails/Menu.php | 60 + modules/Emails/PessimisticLock.php | 111 + modules/Emails/Popup.php | 54 + modules/Emails/PopupDocuments.html | 111 + modules/Emails/PopupDocuments.php | 154 + modules/Emails/Popup_picker.html | 129 + modules/Emails/Popup_picker.php | 151 + modules/Emails/Save.php | 291 + modules/Emails/SearchForm.html | 117 + modules/Emails/SearchFormGroupInbox.html | 73 + modules/Emails/SearchFormMyInbox.html | 71 + modules/Emails/SearchFormSent.html | 70 + modules/Emails/Status.html | 43 + modules/Emails/Status.php | 112 + modules/Emails/SubPanelViewRecipients.html | 94 + modules/Emails/SubPanelViewRecipients.php | 150 + modules/Emails/SugarRoutingAsync.php | 118 + modules/Emails/field_arrays.php | 82 + modules/Emails/images/autofit.gif | Bin 0 -> 63 bytes modules/Emails/images/colsView.gif | Bin 0 -> 56 bytes modules/Emails/images/email.gif | Bin 0 -> 888 bytes modules/Emails/images/emailGroup.gif | Bin 0 -> 192 bytes modules/Emails/images/fullscreen.gif | Bin 0 -> 78 bytes modules/Emails/images/leftarrow_inline.gif | Bin 0 -> 898 bytes modules/Emails/images/rightarrow_inline.gif | Bin 0 -> 900 bytes modules/Emails/images/rowsView.gif | Bin 0 -> 79 bytes modules/Emails/images/sugar.gif | Bin 0 -> 550 bytes modules/Emails/images/sugarDynamic.gif | Bin 0 -> 226 bytes modules/Emails/images/sugarGroup.gif | Bin 0 -> 228 bytes modules/Emails/index.php | 54 + modules/Emails/javascript/Email.js | 1001 + modules/Emails/javascript/EmailUI.js | 3542 ++ modules/Emails/javascript/EmailUICompose.js | 2436 ++ modules/Emails/javascript/EmailUIShared.js | 90 + modules/Emails/javascript/ajax.js | 1618 + modules/Emails/javascript/complexLayout.js | 273 + .../Emails/javascript/composeEmailTemplate.js | 246 + .../javascript/displayOneEmailTemplate.js | 89 + .../Emails/javascript/email_popup_helper.js | 154 + modules/Emails/javascript/grid.js | 650 + modules/Emails/javascript/init.js | 461 + modules/Emails/javascript/vars.js | 53 + modules/Emails/javascript/viewPrintable.js | 105 + modules/Emails/language/en_us.lang.php | 371 + modules/Emails/metadata/additionalDetails.php | 89 + modules/Emails/metadata/popupdefs.php | 54 + modules/Emails/metadata/qcmodulesdefs.php | 45 + modules/Emails/metadata/subpaneldefs.php | 175 + .../Emails/metadata/subpanels/ForContacts.php | 46 + .../Emails/metadata/subpanels/ForHistory.php | 126 + .../Emails/metadata/subpanels/ForQueues.php | 116 + .../subpanels/ForUnlinkedEmailHistory.php | 118 + .../Emails/metadata/subpanels/ForUsers.php | 46 + modules/Emails/subpanels/ForContacts.php | 46 + modules/Emails/subpanels/ForHistory.php | 107 + modules/Emails/subpanels/ForQueues.php | 116 + modules/Emails/subpanels/ForUsers.php | 46 + modules/Emails/templates/_baseConfigData.tpl | 45 + modules/Emails/templates/_baseEmail.tpl | 172 + modules/Emails/templates/_baseJsVars.tpl | 58 + modules/Emails/templates/_blank.html | 38 + .../Emails/templates/_createGroupFolder.tpl | 147 + modules/Emails/templates/addressBook.tpl | 47 + modules/Emails/templates/addressSearch.tpl | 86 + .../Emails/templates/addressSearchContent.tpl | 67 + modules/Emails/templates/advancedSearch.tpl | 119 + modules/Emails/templates/assignTo.tpl | 67 + .../Emails/templates/dceMenuQuickCreate.tpl | 68 + .../Emails/templates/editAccountDialogue.tpl | 245 + modules/Emails/templates/editContact.tpl | 90 + modules/Emails/templates/editMailingList.tpl | 81 + modules/Emails/templates/emailDetailView.tpl | 128 + modules/Emails/templates/emailSettings.tpl | 47 + .../templates/emailSettingsAccountDetails.tpl | 105 + .../templates/emailSettingsAccounts.tpl | 51 + .../Emails/templates/emailSettingsFolders.tpl | 67 + .../Emails/templates/emailSettingsGeneral.tpl | 116 + .../Emails/templates/emailSettingsRules.tpl | 48 + modules/Emails/templates/importRelate.tpl | 128 + modules/Emails/templates/outboundDialog.tpl | 139 + .../Emails/templates/outboundDialogTest.tpl | 59 + modules/Emails/templates/overlay.tpl | 59 + modules/Emails/templates/successMessage.tpl | 49 + modules/Emails/vardefs.php | 501 + modules/Emails/views/view.classic.config.php | 60 + modules/Emails/views/view.modulelistmenu.php | 55 + modules/Emails/views/view.quickcreate.php | 84 + modules/Employees/Employee.php | 230 + modules/Employees/Error.php | 52 + modules/Employees/Forms.php | 138 + modules/Employees/Menu.php | 61 + modules/Employees/Popup_picker.html | 113 + modules/Employees/Popup_picker.php | 163 + modules/Employees/Save.php | 98 + modules/Employees/WapAuthenticate.php | 137 + modules/Employees/WapMenu.php | 56 + modules/Employees/controller.php | 69 + modules/Employees/field_arrays.php | 50 + modules/Employees/language/en_us.lang.php | 136 + modules/Employees/metadata/SearchFields.php | 69 + modules/Employees/metadata/detailviewdefs.php | 167 + modules/Employees/metadata/editviewdefs.php | 122 + modules/Employees/metadata/listviewdefs.php | 87 + modules/Employees/metadata/searchdefs.php | 117 + modules/Employees/vardefs.php | 49 + modules/Employees/views/view.detail.php | 79 + modules/Employees/views/view.edit.php | 75 + modules/Employees/views/view.list.php | 72 + modules/Groups/Delete.php | 47 + modules/Groups/DetailView.html | 71 + modules/Groups/DetailView.php | 77 + modules/Groups/EditView.html | 92 + modules/Groups/EditView.php | 82 + modules/Groups/Forms.php | 40 + modules/Groups/Group.php | 76 + modules/Groups/ListView.html | 66 + modules/Groups/ListView.php | 54 + modules/Groups/Menu.php | 45 + modules/Groups/Save.php | 80 + modules/Groups/index.php | 40 + modules/Groups/language/en_us.lang.php | 51 + modules/Groups/vardefs.php | 40 + modules/Help/Menu.php | 59 + modules/Help/index.php | 48 + modules/Help/language/en_us.lang.php | 65 + modules/History/language/en_us.lang.php | 120 + modules/History/metadata/subpaneldefs.php | 341 + modules/Home/About.php | 200 + modules/Home/AddToFavorites.php | 53 + .../ChartsDashlet.en_us.lang.php | 45 + .../ChartsDashlet/ChartsDashlet.meta.php | 48 + .../Dashlets/ChartsDashlet/ChartsDashlet.php | 185 + .../ChartsDashlet/ChartsDashletScript.tpl | 45 + .../InvadersDashlet.en_us.lang.php | 50 + .../InvadersDashlet/InvadersDashlet.icon.jpg | Bin 0 -> 81 bytes .../InvadersDashlet/InvadersDashlet.meta.php | 48 + .../InvadersDashlet/InvadersDashlet.php | 160 + .../InvadersDashlet/InvadersDashlet.tpl | 97 + .../InvadersDashlet/InvadersDashletScript.tpl | 262 + .../InvadersDashlet/InvadersOptions.tpl | 71 + .../InvadersDashlet/sprites/alien.png | Bin 0 -> 1192 bytes .../Dashlets/InvadersDashlet/sprites/bg.png | Bin 0 -> 22435 bytes .../Dashlets/InvadersDashlet/sprites/cube.png | Bin 0 -> 844 bytes .../InvadersDashlet/sprites/player.png | Bin 0 -> 1355 bytes .../JotPadDashlet.en_us.lang.php | 51 + .../JotPadDashlet/JotPadDashlet.meta.php | 47 + .../Dashlets/JotPadDashlet/JotPadDashlet.php | 177 + .../Dashlets/JotPadDashlet/JotPadDashlet.tpl | 45 + .../JotPadDashlet/JotPadDashletOptions.tpl | 71 + .../JotPadDashlet/JotPadDashletScript.tpl | 89 + .../RSSDashlet/RSSDashlet.en_us.lang.php | 54 + .../Dashlets/RSSDashlet/RSSDashlet.icon.jpg | Bin 0 -> 81 bytes .../Dashlets/RSSDashlet/RSSDashlet.meta.php | 46 + .../Home/Dashlets/RSSDashlet/RSSDashlet.php | 185 + .../Home/Dashlets/RSSDashlet/RSSDashlet.tpl | 44 + .../Dashlets/RSSDashlet/RSSDashletOptions.tpl | 89 + .../SugarNewsDashlet.meta.php | 45 + .../SugarNewsDashlet/SugarNewsDashlet.php | 119 + .../Dashlets/SugarNewsDashlet/configure.tpl | 86 + .../Home/Dashlets/iFrameDashlet/configure.tpl | 86 + .../iFrameDashlet/iFrameDashlet.meta.php | 45 + .../Dashlets/iFrameDashlet/iFrameDashlet.php | 133 + modules/Home/DynamicAction.php | 53 + modules/Home/Home.html | 61 + modules/Home/Home.tpl | 220 + modules/Home/LastViewed.php | 72 + modules/Home/Menu.php | 46 + modules/Home/PopupSugar.php | 146 + modules/Home/SaveSubpanelLayout.php | 60 + modules/Home/SubpanelCreates.php | 74 + modules/Home/TrainingPortal.php | 65 + modules/Home/TrainingPortal.tpl | 44 + modules/Home/UnifiedSearch.php | 57 + modules/Home/UnifiedSearchAdvanced.php | 753 + modules/Home/UnifiedSearchAdvanced.tpl | 81 + modules/Home/UnifiedSearchAdvancedForm.tpl | 179 + modules/Home/UnifiedSearchAdvancedResults.tpl | 93 + modules/Home/about.js | 35 + modules/Home/action_view_map.php | 38 + modules/Home/dashlets.php | 56 + modules/Home/index.php | 307 + modules/Home/language/en_us.lang.php | 247 + modules/Home/quicksearchQuery.php | 342 + modules/Home/sitemap.php | 151 + modules/Home/sitemap.tpl | 80 + .../views/view.additionaldetailsretrieve.php | 98 + modules/Home/views/view.list.php | 52 + modules/Home/views/view.modulelistmenu.php | 55 + modules/Import/Forms.php | 190 + modules/Import/ImportCacheFiles.php | 125 + modules/Import/ImportDuplicateCheck.php | 179 + modules/Import/ImportFieldSanitize.php | 304 + modules/Import/ImportFile.php | 329 + modules/Import/ImportFileSplitter.php | 206 + modules/Import/ImportMap.php | 358 + modules/Import/ImportMapAct.php | 129 + modules/Import/ImportMapCsv.php | 62 + modules/Import/ImportMapOther.php | 157 + modules/Import/ImportMapOutlook.php | 96 + modules/Import/ImportMapSalesforce.php | 161 + modules/Import/ImportMapTab.php | 64 + modules/Import/Menu.php | 47 + modules/Import/UsersLastImport.php | 254 + modules/Import/controller.php | 126 + modules/Import/language/en_us.lang.php | 315 + modules/Import/tpls/error.tpl | 59 + modules/Import/tpls/last.tpl | 93 + modules/Import/tpls/step1.tpl | 195 + modules/Import/tpls/step2.tpl | 112 + modules/Import/tpls/step3.tpl | 369 + modules/Import/tpls/undo.tpl | 65 + modules/Import/vardefs.php | 237 + modules/Import/views/view.error.php | 102 + modules/Import/views/view.last.php | 303 + modules/Import/views/view.step1.php | 324 + modules/Import/views/view.step2.php | 252 + modules/Import/views/view.step3.php | 793 + modules/Import/views/view.step4.php | 686 + modules/Import/views/view.undo.php | 129 + modules/InboundEmail/Delete.php | 48 + modules/InboundEmail/DetailView.html | 248 + modules/InboundEmail/DetailView.php | 303 + modules/InboundEmail/EditGroupFolder.php | 123 + modules/InboundEmail/EditView.html | 574 + modules/InboundEmail/EditView.php | 366 + modules/InboundEmail/InboundEmail.js | 94 + modules/InboundEmail/InboundEmail.php | 6402 ++++ modules/InboundEmail/InboundEmailTest.php | 42 + modules/InboundEmail/ListView.html | 85 + modules/InboundEmail/ListView.php | 75 + modules/InboundEmail/Menu.php | 53 + modules/InboundEmail/Popup.php | 179 + modules/InboundEmail/Save.php | 274 + modules/InboundEmail/SaveGroupFolder.php | 66 + .../InboundEmail/ShowInboundFoldersList.php | 323 + modules/InboundEmail/View.html | 84 + modules/InboundEmail/field_arrays.php | 70 + modules/InboundEmail/index.php | 49 + modules/InboundEmail/language/en_us.lang.php | 198 + modules/InboundEmail/vardefs.php | 284 + modules/LabelEditor/EditView.html | 69 + modules/LabelEditor/EditView.php | 92 + modules/LabelEditor/Forms.php | 53 + modules/LabelEditor/LabelList.php | 96 + modules/LabelEditor/Menu.php | 43 + modules/LabelEditor/Save.php | 68 + modules/LabelEditor/language/en_us.lang.php | 44 + modules/Leads/Capture.php | 124 + .../MyLeadsDashlet/MyLeadsDashlet.data.php | 87 + .../MyLeadsDashlet/MyLeadsDashlet.meta.php | 45 + .../MyLeadsDashlet/MyLeadsDashlet.php | 60 + modules/Leads/Lead.js | 48 + modules/Leads/Lead.php | 585 + modules/Leads/LeadFormBase.php | 379 + modules/Leads/LeadsQuickCreate.php | 74 + modules/Leads/Menu.php | 51 + modules/Leads/MyLeads.html | 62 + modules/Leads/MyLeads.php | 60 + modules/Leads/Popup_picker.html | 116 + modules/Leads/Save.php | 49 + modules/Leads/SubPanelView.html | 62 + modules/Leads/SubPanelView.php | 77 + modules/Leads/SugarFeeds/LeadFeed.php | 66 + modules/Leads/action_view_map.php | 42 + modules/Leads/controller.php | 85 + modules/Leads/field_arrays.php | 100 + modules/Leads/language/en_us.lang.php | 254 + modules/Leads/metadata/SearchFields.php | 82 + modules/Leads/metadata/additionalDetails.php | 83 + modules/Leads/metadata/convertdefs.php | 351 + modules/Leads/metadata/detailviewdefs.php | 184 + modules/Leads/metadata/editviewdefs.php | 153 + modules/Leads/metadata/listviewdefs.php | 228 + modules/Leads/metadata/popupdefs.php | 148 + modules/Leads/metadata/quickcreatedefs.php | 174 + modules/Leads/metadata/searchdefs.php | 167 + modules/Leads/metadata/studio.php | 66 + modules/Leads/metadata/subpaneldefs.php | 167 + modules/Leads/metadata/subpanels/ForCalls.php | 121 + .../Leads/metadata/subpanels/ForEmails.php | 96 + .../Leads/metadata/subpanels/ForMeetings.php | 105 + modules/Leads/metadata/subpanels/default.php | 115 + modules/Leads/tpls/ConvertLead.tpl | 167 + modules/Leads/tpls/ConvertLeadFooter.tpl | 62 + modules/Leads/tpls/ConvertLeadHeader.tpl | 78 + modules/Leads/tpls/DetailViewHeader.tpl | 81 + modules/Leads/tpls/QuickCreate.tpl | 96 + modules/Leads/vardefs.php | 551 + modules/Leads/views/view.convertlead.php | 741 + modules/Leads/views/view.list.php | 48 + modules/MailMerge/DetailView.php | 40 + modules/MailMerge/EditView.php | 40 + modules/MailMerge/MailMerge.php | 153 + modules/MailMerge/Menu.php | 51 + modules/MailMerge/Merge.html | 63 + modules/MailMerge/Merge.php | 171 + modules/MailMerge/Save.php | 90 + modules/MailMerge/Step1.html | 157 + modules/MailMerge/Step1.php | 274 + modules/MailMerge/Step2.html | 383 + modules/MailMerge/Step2.php | 174 + modules/MailMerge/Step3.html | 98 + modules/MailMerge/Step3.php | 274 + modules/MailMerge/Step4.html | 111 + modules/MailMerge/Step4.php | 153 + modules/MailMerge/Step5.html | 79 + modules/MailMerge/Step5.php | 60 + modules/MailMerge/get_doc.php | 63 + modules/MailMerge/index.php | 59 + modules/MailMerge/language/en_us.lang.php | 79 + modules/MailMerge/modules_array.php | 44 + .../MyMeetingsDashlet.data.php | 91 + .../MyMeetingsDashlet.meta.php | 47 + .../MyMeetingsDashlet/MyMeetingsDashlet.php | 188 + modules/Meetings/JoinExternalMeeting.php | 83 + modules/Meetings/Meeting.php | 740 + modules/Meetings/MeetingFormBase.php | 457 + modules/Meetings/MeetingsQuickCreate.php | 165 + modules/Meetings/Menu.php | 54 + modules/Meetings/Save.php | 50 + modules/Meetings/SubPanelViewInvitees.html | 95 + modules/Meetings/SubPanelViewInvitees.php | 150 + modules/Meetings/action_view_map.php | 38 + modules/Meetings/field_arrays.php | 69 + modules/Meetings/jsclass_scheduler.js | 109 + modules/Meetings/language/en_us.lang.php | 143 + modules/Meetings/metadata/SearchFields.php | 69 + .../Meetings/metadata/additionalDetails.php | 85 + modules/Meetings/metadata/detailviewdefs.php | 143 + modules/Meetings/metadata/editviewdefs.php | 171 + modules/Meetings/metadata/listviewdefs.php | 123 + modules/Meetings/metadata/quickcreatedefs.php | 177 + modules/Meetings/metadata/searchdefs.php | 118 + modules/Meetings/metadata/studio.php | 66 + modules/Meetings/metadata/subpaneldefs.php | 98 + .../metadata/subpanels/ForActivities.php | 120 + .../metadata/subpanels/ForHistory.php | 132 + .../Meetings/metadata/subpanels/default.php | 78 + modules/Meetings/tpls/QuickCreate.tpl | 146 + modules/Meetings/tpls/extMeetingNoStart.tpl | 40 + .../Meetings/tpls/extMeetingNotInvited.tpl | 40 + modules/Meetings/tpls/footer.tpl | 89 + modules/Meetings/tpls/header.tpl | 42 + modules/Meetings/vardefs.php | 383 + modules/Meetings/views/view.edit.php | 91 + modules/Meetings/views/view.listbytype.php | 124 + modules/MergeRecords/Menu.php | 50 + modules/MergeRecords/Merge.js | 93 + modules/MergeRecords/MergeField.html | 125 + modules/MergeRecords/MergeRecord.php | 348 + modules/MergeRecords/SaveMerge.php | 219 + modules/MergeRecords/SearchForm.html | 103 + modules/MergeRecords/Step1.html | 130 + modules/MergeRecords/Step1.php | 189 + modules/MergeRecords/Step2.html | 42 + modules/MergeRecords/Step2.php | 214 + modules/MergeRecords/Step3.html | 239 + modules/MergeRecords/Step3.php | 545 + modules/MergeRecords/controller.php | 50 + modules/MergeRecords/index.php | 107 + modules/MergeRecords/language/en_us.lang.php | 84 + modules/MergeRecords/vardefs.php | 50 + modules/ModuleBuilder/Forms.php | 38 + modules/ModuleBuilder/MB/AjaxCompose.php | 103 + modules/ModuleBuilder/MB/MBField.php | 101 + modules/ModuleBuilder/MB/MBLanguage.php | 253 + modules/ModuleBuilder/MB/MBModule.php | 801 + modules/ModuleBuilder/MB/MBPackage.php | 787 + modules/ModuleBuilder/MB/MBPackageTree.php | 79 + modules/ModuleBuilder/MB/MBRelationship.php | 176 + modules/ModuleBuilder/MB/MBVardefs.php | 146 + modules/ModuleBuilder/MB/ModuleBuilder.php | 148 + modules/ModuleBuilder/MB/header.php | 36 + .../ModuleBuilder/Module/DropDownBrowser.php | 64 + modules/ModuleBuilder/Module/DropDownTree.php | 53 + modules/ModuleBuilder/Module/MainTree.php | 48 + .../ModuleBuilder/Module/StudioBrowser.php | 86 + modules/ModuleBuilder/Module/StudioModule.php | 430 + .../Module/StudioModuleFactory.php | 55 + modules/ModuleBuilder/Module/StudioTree.php | 52 + modules/ModuleBuilder/action_view_map.php | 75 + modules/ModuleBuilder/controller.php | 782 + .../ModuleBuilder/javascript/JSTransaction.js | 79 + .../ModuleBuilder/javascript/ModuleBuilder.js | 1060 + .../ModuleBuilder/javascript/SimpleList.js | 309 + modules/ModuleBuilder/javascript/studio2.js | 914 + .../javascript/studio2FieldDD.js | 315 + .../ModuleBuilder/javascript/studio2ListDD.js | 188 + .../javascript/studio2PanelDD.js | 198 + .../ModuleBuilder/javascript/studio2RowDD.js | 185 + .../javascript/studiotabgroups.js | 197 + .../javascript/wizardTemplate.js | 37 + modules/ModuleBuilder/language/en_us.lang.php | 707 + .../parsers/ModuleBuilderParser.php | 177 + .../ModuleBuilder/parsers/ParserFactory.php | 120 + .../ModuleBuilder/parsers/StandardField.php | 117 + modules/ModuleBuilder/parsers/constants.php | 69 + .../ModuleBuilder/parsers/parser.dropdown.php | 211 + .../ModuleBuilder/parsers/parser.label.php | 190 + .../parsers/parser.modifylayoutview.php | 521 + .../parsers/parser.modifylistview.php | 331 + .../parsers/parser.modifysubpanel.php | 257 + .../relationships/AbstractRelationship.php | 655 + .../relationships/AbstractRelationships.php | 557 + .../relationships/ActivitiesRelationship.php | 276 + .../relationships/DeployedRelationships.php | 387 + .../relationships/ManyToManyRelationship.php | 106 + .../relationships/ManyToOneRelationship.php | 150 + .../relationships/OneToManyRelationship.php | 154 + .../relationships/OneToOneRelationship.php | 132 + .../relationships/RelationshipFactory.php | 82 + .../relationships/RelationshipsInterface.php | 56 + .../relationships/UndeployedRelationships.php | 416 + .../views/AbstractMetaDataImplementation.php | 304 + .../parsers/views/AbstractMetaDataParser.php | 133 + .../parsers/views/DashletMetaDataParser.php | 176 + .../views/DeployedMetaDataImplementation.php | 376 + .../views/DeployedSubpanelImplementation.php | 169 + .../views/GridLayoutMetaDataParser.php | 807 + .../ModuleBuilder/parsers/views/History.php | 220 + .../parsers/views/HistoryInterface.php | 76 + .../views/ListLayoutMetaDataParser.php | 375 + .../views/MetaDataImplementationInterface.php | 46 + .../parsers/views/MetaDataParserInterface.php | 51 + .../parsers/views/PopupMetaDataParser.php | 234 + .../views/SearchViewMetaDataParser.php | 211 + .../parsers/views/SubpanelMetaDataParser.php | 162 + .../UndeployedMetaDataImplementation.php | 211 + .../UndeployedSubpanelImplementation.php | 114 + modules/ModuleBuilder/tpls/LayoutEditor.css | 91 + modules/ModuleBuilder/tpls/ListEditor.css | 78 + modules/ModuleBuilder/tpls/MB.css | 155 + modules/ModuleBuilder/tpls/MBModule/Class.tpl | 71 + .../tpls/MBModule/DeveloperClass.tpl | 48 + modules/ModuleBuilder/tpls/MBModule/Menu.tpl | 44 + .../ModuleBuilder/tpls/MBModule/Studio.tpl | 41 + .../ModuleBuilder/tpls/MBModule/dropdown.css | 84 + .../ModuleBuilder/tpls/MBModule/dropdown.tpl | 161 + .../ModuleBuilder/tpls/MBModule/dropdowns.tpl | 72 + modules/ModuleBuilder/tpls/MBModule/field.tpl | 123 + .../ModuleBuilder/tpls/MBModule/fields.tpl | 80 + modules/ModuleBuilder/tpls/MBModule/form.tpl | 0 .../ModuleBuilder/tpls/MBModule/language.tpl | 39 + modules/ModuleBuilder/tpls/MBModule/main.tpl | 0 .../ModuleBuilder/tpls/MBModule/module.tpl | 129 + .../ModuleBuilder/tpls/MBModule/vardef.tpl | 50 + .../tpls/MBPackage/appLanguage.tpl | 0 .../ModuleBuilder/tpls/MBPackage/deploy.tpl | 39 + .../ModuleBuilder/tpls/MBPackage/package.tpl | 170 + .../ModuleBuilder/tpls/Preview/layoutView.tpl | 127 + .../ModuleBuilder/tpls/Preview/listView.tpl | 96 + .../tpls/assistantJavascript.tpl | 55 + modules/ModuleBuilder/tpls/editProperty.tpl | 109 + .../tpls/exportcustomizations.tpl | 115 + modules/ModuleBuilder/tpls/history.tpl | 50 + modules/ModuleBuilder/tpls/includes.tpl | 67 + modules/ModuleBuilder/tpls/index.tpl | 95 + modules/ModuleBuilder/tpls/labels.tpl | 83 + modules/ModuleBuilder/tpls/layoutView.tpl | 282 + modules/ModuleBuilder/tpls/listView.tpl | 224 + modules/ModuleBuilder/tpls/main.tpl | 51 + modules/ModuleBuilder/tpls/resetModule.tpl | 55 + .../ModuleBuilder/tpls/studioRelationship.tpl | 232 + .../tpls/studioRelationships.tpl | 111 + modules/ModuleBuilder/tpls/tabBG.png | Bin 0 -> 1041 bytes modules/ModuleBuilder/tpls/wizard.tpl | 96 + modules/ModuleBuilder/views/view.dashlet.php | 224 + .../ModuleBuilder/views/view.deletemodule.php | 61 + .../views/view.deletepackage.php | 64 + .../views/view.displaydeploy.php | 66 + .../views/view.displaydeployresult.php | 69 + modules/ModuleBuilder/views/view.dropdown.php | 159 + .../ModuleBuilder/views/view.dropdowns.php | 83 + .../views/view.exportcustomizations.php | 76 + modules/ModuleBuilder/views/view.history.php | 183 + modules/ModuleBuilder/views/view.home.php | 87 + modules/ModuleBuilder/views/view.labels.php | 185 + .../ModuleBuilder/views/view.layoutview.php | 292 + modules/ModuleBuilder/views/view.listview.php | 342 + modules/ModuleBuilder/views/view.main.php | 120 + modules/ModuleBuilder/views/view.module.php | 102 + .../ModuleBuilder/views/view.modulefield.php | 318 + .../ModuleBuilder/views/view.modulefields.php | 211 + .../ModuleBuilder/views/view.modulelabels.php | 103 + modules/ModuleBuilder/views/view.package.php | 163 + .../ModuleBuilder/views/view.popupview.php | 226 + modules/ModuleBuilder/views/view.property.php | 132 + .../ModuleBuilder/views/view.relationship.php | 273 + .../views/view.relationships.php | 152 + .../ModuleBuilder/views/view.resetmodule.php | 249 + .../ModuleBuilder/views/view.searchview.php | 132 + modules/ModuleBuilder/views/view.tree.php | 81 + modules/ModuleBuilder/views/view.wizard.php | 340 + modules/MySettings/LoadTabSubpanels.php | 70 + modules/MySettings/StoreQuery.php | 270 + modules/MySettings/TabController.php | 337 + modules/MySettings/language/en_us.lang.php | 40 + .../MyNotesDashlet/MyNotesDashlet.data.php | 126 + .../MyNotesDashlet/MyNotesDashlet.meta.php | 45 + .../MyNotesDashlet/MyNotesDashlet.php | 57 + modules/Notes/Menu.php | 52 + modules/Notes/Note.php | 325 + modules/Notes/NoteSoap.php | 157 + modules/Notes/NotesQuickCreate.php | 70 + modules/Notes/SubPanelView.html | 66 + modules/Notes/SubPanelView.php | 105 + modules/Notes/controller.php | 104 + modules/Notes/field_arrays.php | 63 + modules/Notes/language/en_us.lang.php | 107 + modules/Notes/metadata/SearchFields.php | 53 + modules/Notes/metadata/additionalDetails.php | 64 + modules/Notes/metadata/detailviewdefs.php | 115 + modules/Notes/metadata/editviewdefs.php | 87 + modules/Notes/metadata/listviewdefs.php | 116 + modules/Notes/metadata/quickcreatedefs.php | 110 + modules/Notes/metadata/searchdefs.php | 104 + modules/Notes/metadata/studio.php | 66 + modules/Notes/metadata/subpanels/ForCalls.php | 127 + .../Notes/metadata/subpanels/ForHistory.php | 137 + .../Notes/metadata/subpanels/ForMeetings.php | 127 + modules/Notes/metadata/subpanels/default.php | 100 + modules/Notes/tpls/EditViewHeader.tpl | 80 + modules/Notes/tpls/QuickCreate.tpl | 103 + modules/Notes/vardefs.php | 461 + .../MyClosedOpportunitiesDashlet.meta.php | 47 + .../MyClosedOpportunitiesDashlet.php | 130 + .../MyClosedOpportunitiesDashlet.tpl | 52 + .../MyClosedOpportunitiesDashletConfigure.tpl | 74 + .../MyClosedOpportunitiesDashletOptions.tpl | 86 + .../MyOpportunitiesDashlet.data.php | 89 + .../MyOpportunitiesDashlet.meta.php | 47 + .../MyOpportunitiesDashlet.php | 72 + modules/Opportunities/ListViewTop.html | 64 + modules/Opportunities/ListViewTop.php | 65 + modules/Opportunities/Menu.php | 58 + .../OpportunitiesQuickCreate.php | 81 + modules/Opportunities/Opportunity.php | 462 + modules/Opportunities/OpportunityFormBase.php | 467 + modules/Opportunities/Save.php | 49 + modules/Opportunities/SaveOverload.php | 48 + modules/Opportunities/SubPanelView.html | 63 + modules/Opportunities/SubPanelView.php | 145 + .../Opportunities/SubPanelViewProjects.html | 68 + .../Opportunities/SubPanelViewProjects.php | 111 + modules/Opportunities/SugarFeeds/OppFeed.php | 63 + modules/Opportunities/field_arrays.php | 69 + modules/Opportunities/language/en_us.lang.php | 146 + .../Opportunities/metadata/SearchFields.php | 75 + modules/Opportunities/metadata/acldefs.php | 61 + .../metadata/additionalDetails.php | 63 + .../Opportunities/metadata/detailviewdefs.php | 102 + .../Opportunities/metadata/editviewdefs.php | 86 + .../Opportunities/metadata/listviewdefs.php | 113 + modules/Opportunities/metadata/metafiles.php | 52 + modules/Opportunities/metadata/popupdefs.php | 86 + .../metadata/quickcreatedefs.php | 117 + modules/Opportunities/metadata/searchdefs.php | 133 + modules/Opportunities/metadata/studio.php | 66 + .../Opportunities/metadata/subpaneldefs.php | 195 + .../metadata/subpanels/ForAccounts.php | 90 + .../metadata/subpanels/ForEmails.php | 85 + .../metadata/subpanels/default.php | 104 + modules/Opportunities/tpls/QuickCreate.tpl | 110 + modules/Opportunities/vardefs.php | 435 + modules/Opportunities/views/view.detail.php | 75 + modules/Opportunities/views/view.edit.php | 86 + modules/OptimisticLock/Forms.php | 39 + modules/OptimisticLock/LockResolve.php | 84 + modules/OptimisticLock/Menu.php | 43 + .../OptimisticLock/language/en_us.lang.php | 57 + modules/Project/Delete.php | 88 + modules/Project/Menu.php | 78 + modules/Project/Project.js | 48 + modules/Project/Project.php | 286 + modules/Project/ProjectQuickCreate.php | 88 + modules/Project/Save.php | 125 + modules/Project/SubPanelView.html | 67 + modules/Project/SubPanelView.php | 103 + modules/Project/action_view_map.php | 41 + modules/Project/field_arrays.php | 77 + modules/Project/language/en_us.lang.php | 143 + modules/Project/metadata/SearchFields.php | 59 + .../Project/metadata/additionalDetails.php | 63 + modules/Project/metadata/detailviewdefs.php | 133 + modules/Project/metadata/editviewdefs.php | 80 + modules/Project/metadata/listviewdefs.php | 90 + modules/Project/metadata/metafiles.php | 47 + modules/Project/metadata/popupdefs.php | 50 + modules/Project/metadata/quickcreatedefs.php | 72 + modules/Project/metadata/searchdefs.php | 59 + modules/Project/metadata/studio.php | 66 + modules/Project/metadata/subpaneldefs.php | 237 + .../Project/metadata/subpanels/ForEmails.php | 88 + .../Project/metadata/subpanels/default.php | 90 + modules/Project/tpls/QuickCreate.tpl | 96 + modules/Project/vardefs.php | 431 + modules/Project/views/view.detail.php | 76 + modules/Project/views/view.edit.php | 53 + modules/Project/views/view.list.php | 79 + .../Project/views/view.templatesdetail.php | 87 + modules/Project/views/view.templatesedit.php | 66 + .../MyProjectTaskDashlet.data.php | 89 + .../MyProjectTaskDashlet.meta.php | 47 + .../MyProjectTaskDashlet.php | 70 + modules/ProjectTask/Delete.php | 88 + modules/ProjectTask/Forms.html | 67 + modules/ProjectTask/Menu.php | 59 + modules/ProjectTask/MyProjectTasks.html | 66 + modules/ProjectTask/MyProjectTasks.php | 76 + modules/ProjectTask/Popup.html | 116 + modules/ProjectTask/Popup.php | 47 + modules/ProjectTask/Popup_picker.html | 103 + modules/ProjectTask/ProjectTask.js | 42 + modules/ProjectTask/ProjectTask.php | 371 + .../ProjectTask/ProjectTaskQuickCreate.php | 102 + modules/ProjectTask/Save.php | 100 + modules/ProjectTask/SubPanelView.html | 70 + modules/ProjectTask/SubPanelView.php | 105 + modules/ProjectTask/field_arrays.php | 86 + modules/ProjectTask/language/en_us.lang.php | 120 + modules/ProjectTask/metadata/SearchFields.php | 61 + modules/ProjectTask/metadata/acldefs.php | 68 + .../metadata/additionalDetails.php | 69 + .../ProjectTask/metadata/detailviewdefs.php | 129 + modules/ProjectTask/metadata/editviewdefs.php | 144 + modules/ProjectTask/metadata/listviewdefs.php | 86 + modules/ProjectTask/metadata/popupdefs.php | 50 + modules/ProjectTask/metadata/searchdefs.php | 57 + modules/ProjectTask/metadata/studio.php | 66 + modules/ProjectTask/metadata/subpaneldefs.php | 125 + .../metadata/subpanels/default.php | 65 + modules/ProjectTask/tpls/QuickCreate.tpl | 104 + modules/ProjectTask/vardefs.php | 471 + modules/ProjectTask/views/view.list.php | 269 + modules/ProspectLists/Delete.php | 62 + modules/ProspectLists/Duplicate.php | 75 + modules/ProspectLists/Forms.html | 57 + modules/ProspectLists/Forms.php | 91 + modules/ProspectLists/Menu.php | 48 + modules/ProspectLists/Popup_picker.html | 129 + modules/ProspectLists/ProspectList.php | 350 + .../ProspectLists/ProspectListFormBase.php | 165 + modules/ProspectLists/Save.php | 85 + modules/ProspectLists/SubPanelView.html | 62 + modules/ProspectLists/SubPanelView.php | 119 + modules/ProspectLists/TargetListUpdate.php | 95 + modules/ProspectLists/field_arrays.php | 57 + modules/ProspectLists/language/en_us.lang.php | 97 + .../ProspectLists/metadata/SearchFields.php | 44 + .../ProspectLists/metadata/detailviewdefs.php | 81 + .../ProspectLists/metadata/editviewdefs.php | 87 + .../ProspectLists/metadata/listviewdefs.php | 66 + modules/ProspectLists/metadata/popupdefs.php | 85 + modules/ProspectLists/metadata/searchdefs.php | 62 + .../ProspectLists/metadata/subpaneldefs.php | 111 + .../metadata/subpanels/default.php | 83 + modules/ProspectLists/vardefs.php | 223 + modules/Prospects/Delete.php | 63 + modules/Prospects/Import.php | 55 + modules/Prospects/Menu.php | 50 + modules/Prospects/Popup_picker.html | 108 + modules/Prospects/Prospect.php | 310 + modules/Prospects/ProspectFormBase.php | 511 + modules/Prospects/Save.php | 52 + modules/Prospects/field_arrays.php | 90 + modules/Prospects/language/en_us.lang.php | 187 + modules/Prospects/metadata/SearchFields.php | 70 + .../Prospects/metadata/additionalDetails.php | 94 + modules/Prospects/metadata/detailviewdefs.php | 137 + modules/Prospects/metadata/editviewdefs.php | 113 + modules/Prospects/metadata/listviewdefs.php | 72 + modules/Prospects/metadata/popupdefs.php | 64 + .../Prospects/metadata/quickcreatedefs.php | 163 + modules/Prospects/metadata/searchdefs.php | 64 + modules/Prospects/metadata/studio.php | 66 + modules/Prospects/metadata/subpaneldefs.php | 140 + .../Prospects/metadata/subpanels/default.php | 92 + modules/Prospects/tpls/DetailViewHeader.tpl | 58 + modules/Prospects/vardefs.php | 239 + modules/Prospects/views/view.detail.php | 67 + modules/Prospects/views/view.list.php | 48 + modules/Relationships/Relationship.php | 279 + modules/Relationships/RelationshipHandler.php | 409 + modules/Relationships/field_arrays.php | 81 + modules/Relationships/language/en_us.lang.php | 65 + modules/Relationships/vardefs.php | 173 + modules/Releases/DetailView.php | 44 + modules/Releases/EditView.html | 63 + modules/Releases/EditView.php | 45 + modules/Releases/ListView.html | 67 + modules/Releases/Menu.php | 48 + modules/Releases/Popup_picker.html | 100 + modules/Releases/Popup_picker.php | 157 + modules/Releases/Release.php | 157 + modules/Releases/Save.php | 91 + modules/Releases/field_arrays.php | 57 + modules/Releases/index.php | 155 + modules/Releases/language/en_us.lang.php | 72 + modules/Releases/vardefs.php | 128 + modules/Roles/Delete.php | 58 + modules/Roles/DeleteUserRelationship.php | 62 + modules/Roles/DetailView.html | 86 + modules/Roles/DetailView.php | 153 + modules/Roles/EditView.html | 107 + modules/Roles/EditView.php | 145 + modules/Roles/Forms.php | 113 + modules/Roles/Menu.php | 50 + modules/Roles/Role.php | 202 + modules/Roles/Save.php | 90 + modules/Roles/SaveUserRelationship.php | 69 + modules/Roles/SubPanelViewUsers.html | 63 + modules/Roles/SubPanelViewUsers.php | 99 + modules/Roles/field_arrays.php | 57 + modules/Roles/language/en_us.lang.php | 60 + modules/Roles/metadata/SearchFields.php | 42 + modules/Roles/metadata/listviewdefs.php | 51 + modules/Roles/metadata/searchdefs.php | 55 + modules/Roles/metadata/subpaneldefs.php | 59 + modules/Roles/metadata/subpanels/default.php | 61 + modules/Roles/vardefs.php | 130 + modules/Roles/views/view.list.php | 48 + modules/SavedSearch/ListView.php | 84 + modules/SavedSearch/Menu.php | 46 + modules/SavedSearch/SavedSearch.php | 405 + modules/SavedSearch/SavedSearchForm.tpl | 107 + modules/SavedSearch/SavedSearchSelects.tpl | 57 + modules/SavedSearch/SearchForm.html | 58 + modules/SavedSearch/UpgradeSavedSearch.php | 129 + modules/SavedSearch/field_arrays.php | 59 + modules/SavedSearch/index.php | 89 + modules/SavedSearch/language/en_us.lang.php | 70 + modules/SavedSearch/metadata/listviewdefs.php | 54 + modules/SavedSearch/vardefs.php | 147 + modules/Schedulers/Delete.php | 56 + modules/Schedulers/DeleteScheduled.php | 55 + modules/Schedulers/DetailView.html | 113 + modules/Schedulers/DetailView.php | 135 + modules/Schedulers/EditView.html | 386 + modules/Schedulers/EditView.php | 349 + modules/Schedulers/JobThread.php | 76 + modules/Schedulers/ListView.html | 81 + modules/Schedulers/ListView.php | 74 + modules/Schedulers/Menu.php | 52 + modules/Schedulers/Save.php | 172 + modules/Schedulers/Scheduled.html | 72 + modules/Schedulers/Scheduled.php | 71 + modules/Schedulers/Scheduler.php | 1009 + modules/Schedulers/SchedulerDaemon.php | 575 + modules/Schedulers/_AddJobsHere.php | 432 + modules/Schedulers/field_arrays.php | 90 + modules/Schedulers/index.php | 48 + modules/Schedulers/language/en_us.lang.php | 157 + modules/Schedulers/metadata/subpaneldefs.php | 57 + .../Schedulers/metadata/subpanels/default.php | 59 + modules/Schedulers/vardefs.php | 251 + modules/SchedulersJobs/SchedulersJob.php | 290 + modules/SchedulersJobs/field_arrays.php | 59 + .../SchedulersJobs/language/en_us.lang.php | 49 + .../metadata/subpanels/default.php | 65 + modules/SchedulersJobs/vardefs.php | 115 + modules/Studio/DropDowns/DropDownHelper.php | 172 + modules/Studio/DropDowns/EditView.php | 143 + modules/Studio/DropDowns/EditView.tpl | 378 + modules/Studio/Forms.php | 133 + modules/Studio/JSTransaction.js | 40 + modules/Studio/SaveTabs.php | 49 + modules/Studio/TabGroups.php | 41 + modules/Studio/TabGroups/EditViewTabs.php | 116 + modules/Studio/TabGroups/EditViewTabs.tpl | 330 + modules/Studio/TabGroups/TabGroupHelper.php | 131 + modules/Studio/config.php | 69 + modules/Studio/language/en_us.Portal.html | 75 + modules/Studio/language/en_us.lang.php | 189 + modules/Studio/parsers/StudioParser.php | 658 + modules/Studio/studio.js | 79 + modules/Studio/studiodd.js | 55 + modules/Studio/studiotabgroups.js | 46 + modules/Studio/wizard.php | 64 + modules/Studio/wizards/EditDropDownWizard.php | 86 + modules/Studio/wizards/StudioWizard.php | 136 + modules/Studio/ygDDListStudio.js | 55 + modules/SugarFeed/AdminSettings.php | 153 + .../Dashlets/SugarFeedDashlet/Options.tpl | 183 + .../SugarFeedDashlet.meta.php | 53 + .../SugarFeedDashlet/SugarFeedDashlet.php | 506 + .../SugarFeedDashlet/SugarFeedScript.tpl | 124 + .../SugarFeedDashlet/UserPostForm.tpl | 76 + modules/SugarFeed/Forms.php | 0 modules/SugarFeed/Menu.php | 47 + modules/SugarFeed/SugarFeed.php | 468 + modules/SugarFeed/SugarFeedFlush.php | 63 + modules/SugarFeed/action_view_map.php | 38 + modules/SugarFeed/feedLogicBase.php | 53 + modules/SugarFeed/language/en_us.lang.php | 117 + modules/SugarFeed/linkHandlers/Image.php | 76 + modules/SugarFeed/linkHandlers/Link.php | 59 + modules/SugarFeed/linkHandlers/YouTube.php | 54 + modules/SugarFeed/metadata/SearchFields.php | 45 + .../SugarFeed/metadata/dashletviewdefs.php | 53 + modules/SugarFeed/metadata/detailviewdefs.php | 73 + modules/SugarFeed/metadata/editviewdefs.php | 64 + modules/SugarFeed/metadata/listviewdefs.php | 61 + modules/SugarFeed/metadata/metafiles.php | 53 + modules/SugarFeed/metadata/popupdefs.php | 51 + modules/SugarFeed/metadata/searchdefs.php | 61 + .../SugarFeed/metadata/subpanels/default.php | 71 + modules/SugarFeed/tpls/AdminSettings.tpl | 124 + modules/SugarFeed/vardefs.php | 133 + .../SugarFeed/views/view.adminsettings.php | 179 + modules/TableDictionary.php | 100 + .../MyTasksDashlet/MyTasksDashlet.data.php | 115 + .../MyTasksDashlet/MyTasksDashlet.meta.php | 47 + .../MyTasksDashlet/MyTasksDashlet.php | 61 + modules/Tasks/Menu.php | 42 + modules/Tasks/MyTasks.html | 65 + modules/Tasks/MyTasks.php | 83 + modules/Tasks/Save.php | 143 + modules/Tasks/Task.php | 403 + modules/Tasks/TasksQuickCreate.php | 98 + modules/Tasks/field_arrays.php | 69 + modules/Tasks/language/en_us.lang.php | 111 + modules/Tasks/metadata/SearchFields.php | 69 + modules/Tasks/metadata/additionalDetails.php | 75 + modules/Tasks/metadata/detailviewdefs.php | 147 + modules/Tasks/metadata/editviewdefs.php | 164 + modules/Tasks/metadata/listviewdefs.php | 106 + modules/Tasks/metadata/quickcreatedefs.php | 166 + modules/Tasks/metadata/searchdefs.php | 126 + modules/Tasks/metadata/studio.php | 66 + .../metadata/subpanels/ForActivities.php | 109 + .../Tasks/metadata/subpanels/ForEmails.php | 108 + .../Tasks/metadata/subpanels/ForHistory.php | 120 + modules/Tasks/metadata/subpanels/default.php | 115 + modules/Tasks/tpls/QuickCreate.tpl | 205 + modules/Tasks/vardefs.php | 300 + modules/Tasks/views/view.edit.php | 76 + modules/Trackers/BreadCrumbStack.php | 254 + modules/Trackers/Metric.php | 60 + modules/Trackers/Trackable.php | 43 + modules/Trackers/Tracker.php | 145 + modules/Trackers/TrackerManager.php | 294 + modules/Trackers/config.php | 58 + modules/Trackers/language/en_us.lang.php | 92 + modules/Trackers/monitor/BlankMonitor.php | 115 + modules/Trackers/monitor/Monitor.php | 244 + modules/Trackers/monitor/tracker_monitor.php | 76 + modules/Trackers/populateSeedData.php | 121 + modules/Trackers/store/DatabaseStore.php | 83 + modules/Trackers/store/Store.php | 56 + modules/Trackers/store/SugarLogStore.php | 66 + .../store/TrackerQueriesDatabaseStore.php | 85 + .../store/TrackerSessionsDatabaseStore.php | 83 + modules/Trackers/vardefs.php | 203 + modules/UpgradeWizard/Menu.php | 52 + modules/UpgradeWizard/SILENTUPGRADE.txt | 93 + .../SugarMerge/DetailViewMerge.php | 97 + .../SugarMerge/EditViewMerge.php | 757 + .../SugarMerge/ListViewMerge.php | 255 + .../SugarMerge/QuickCreateMerge.php | 54 + .../UpgradeWizard/SugarMerge/SearchMerge.php | 199 + .../SugarMerge/SubpanelMerge.php | 91 + .../UpgradeWizard/SugarMerge/SugarMerge.php | 229 + modules/UpgradeWizard/UploadFileCheck.php | 84 + modules/UpgradeWizard/cancel.php | 91 + modules/UpgradeWizard/commit.php | 662 + modules/UpgradeWizard/commitJson.php | 82 + modules/UpgradeWizard/deleteCache.php | 96 + modules/UpgradeWizard/end.php | 329 + modules/UpgradeWizard/index.php | 569 + modules/UpgradeWizard/language/en_us.lang.php | 298 + modules/UpgradeWizard/layouts.php | 240 + modules/UpgradeWizard/populateColumns.php | 102 + modules/UpgradeWizard/preflight.php | 495 + modules/UpgradeWizard/preflightJson.php | 90 + modules/UpgradeWizard/processing.gif | Bin 0 -> 10847 bytes modules/UpgradeWizard/silentUpgrade.php | 97 + .../UpgradeWizard/silentUpgrade_dce_step1.php | 646 + .../UpgradeWizard/silentUpgrade_dce_step2.php | 866 + modules/UpgradeWizard/silentUpgrade_step1.php | 1244 + modules/UpgradeWizard/silentUpgrade_step2.php | 564 + modules/UpgradeWizard/start.php | 120 + modules/UpgradeWizard/systemCheck.php | 284 + modules/UpgradeWizard/systemCheckJson.php | 95 + modules/UpgradeWizard/tpls/layoutsMerge.tpl | 81 + modules/UpgradeWizard/upgradeMetaHelper.php | 394 + modules/UpgradeWizard/upgradeTimeCounter.php | 88 + modules/UpgradeWizard/upgradeWizard.js | 43 + modules/UpgradeWizard/upload.php | 399 + modules/UpgradeWizard/uw_ajax.php | 912 + modules/UpgradeWizard/uw_emptyFunctions.php | 47 + modules/UpgradeWizard/uw_files.php | 110 + modules/UpgradeWizard/uw_main.tpl | 437 + modules/UpgradeWizard/uw_utils.php | 5135 +++ modules/UserPreferences/UserPreference.php | 490 + modules/UserPreferences/controller.php | 58 + modules/UserPreferences/field_arrays.php | 57 + modules/UserPreferences/index.php | 48 + modules/UserPreferences/vardefs.php | 111 + modules/Users/Authenticate.php | 109 + modules/Users/ChangeGroupTab.php | 42 + modules/Users/ChangePassword.php | 104 + modules/Users/Changenewpassword.php | 271 + modules/Users/Changenewpassword.tpl | 168 + modules/Users/DetailView.js | 54 + modules/Users/DetailView.php | 529 + modules/Users/DetailView.tpl | 363 + modules/Users/EditView.php | 702 + modules/Users/EditView.tpl | 857 + modules/Users/Error.php | 56 + modules/Users/Forms.php | 223 + modules/Users/GeneratePassword.php | 279 + modules/Users/ListRoles.php | 40 + modules/Users/Login.php | 218 + modules/Users/Logout.php | 70 + modules/Users/Menu.php | 65 + modules/Users/PasswordRequirementBox.css | 55 + modules/Users/PasswordRequirementBox.js | 66 + modules/Users/PopupSignature.php | 98 + modules/Users/PopupUsers.php | 135 + modules/Users/Popup_Users_picker.html | 102 + modules/Users/Popup_picker.html | 119 + modules/Users/Save.php | 422 + modules/Users/SaveSignature.php | 73 + modules/Users/SaveTimezone.php | 55 + modules/Users/SetTimezone.php | 85 + modules/Users/SetTimezone.tpl | 104 + modules/Users/User.js | 51 + modules/Users/User.php | 1322 + modules/Users/UserSignature.php | 111 + modules/Users/UserSignatureEditView.html | 129 + .../AuthenticationController.php | 186 + .../EmailAuthenticate/EmailAuthenticate.php | 62 + .../EmailAuthenticateUser.php | 165 + .../LDAPAuthenticate/LDAPAuthenticate.php | 61 + .../LDAPAuthenticate/LDAPAuthenticateUser.php | 401 + .../LDAPAuthenticate/LDAPConfigs/default.php | 70 + .../SAMLAuthenticate/SAMLAuthenticate.php | 64 + .../SAMLAuthenticate/SAMLAuthenticateUser.php | 123 + .../authentication/SAMLAuthenticate/index.php | 35 + .../SAMLAuthenticate/lib/onelogin/saml.php | 32 + .../lib/onelogin/saml/authrequest.php | 67 + .../lib/onelogin/saml/response.php | 59 + .../lib/onelogin/saml/settings.php | 31 + .../lib/onelogin/saml/xmlsec.php | 69 + .../lib/xmlseclibs/CHANGELOG.txt | 66 + .../lib/xmlseclibs/xmlseclibs.php | 1512 + .../SAMLAuthenticate/settings.php | 50 + .../SugarAuthenticate/SugarAuthenticate.php | 351 + .../SugarAuthenticateUser.php | 143 + modules/Users/controller.php | 94 + modules/Users/field_arrays.php | 154 + modules/Users/language/en_us.lang.php | 521 + modules/Users/login.css | 79 + modules/Users/login.js | 46 + modules/Users/login.tpl | 162 + modules/Users/metadata/SearchFields.php | 70 + modules/Users/metadata/listviewdefs.php | 91 + modules/Users/metadata/popupdefs.php | 56 + .../Users/metadata/reassignScriptMetadata.php | 153 + modules/Users/metadata/searchdefs.php | 119 + modules/Users/metadata/subpaneldefs.php | 141 + modules/Users/metadata/subpanels/ForCalls.php | 98 + .../Users/metadata/subpanels/ForEmails.php | 85 + .../Users/metadata/subpanels/ForMeetings.php | 97 + .../Users/metadata/subpanels/ForProject.php | 71 + .../metadata/subpanels/ForProspectLists.php | 83 + modules/Users/metadata/subpanels/ForTeams.php | 92 + modules/Users/metadata/subpanels/default.php | 85 + modules/Users/password_utils.php | 133 + modules/Users/reassignUserRecords.php | 515 + modules/Users/tpls/wizard.tpl | 612 + modules/Users/vardefs.php | 560 + modules/Users/views/view.list.php | 54 + modules/Users/views/view.wizard.php | 256 + modules/Versions/CheckVersions.php | 56 + modules/Versions/DefaultVersions.php | 77 + modules/Versions/ExpectedVersions.php | 50 + modules/Versions/InstallDefaultVersions.php | 58 + modules/Versions/Version.php | 140 + modules/Versions/field_arrays.php | 56 + modules/Versions/index.html | 46 + modules/Versions/language/en_us.lang.php | 0 modules/Versions/vardefs.php | 126 + modules/vCals/HTTP_WebDAV_Server_vCal.php | 430 + modules/vCals/Server.php | 84 + modules/vCals/field_arrays.php | 55 + modules/vCals/vCal.php | 243 + modules/vCals/vardefs.php | 103 + pdf.php | 56 + removeme.php | 47 + robots.txt | 2 + service/core/NusoapSoap.php | 172 + service/core/PHP5Soap.php | 173 + service/core/REST/SugarRest.php | 114 + service/core/REST/SugarRestJSON.php | 104 + service/core/REST/SugarRestRSS.php | 161 + service/core/REST/SugarRestSerialize.php | 100 + service/core/SoapHelperWebService.php | 1118 + service/core/SugarRestService.php | 212 + service/core/SugarRestServiceImpl.php | 50 + service/core/SugarRestUtils.php | 40 + service/core/SugarSoapService.php | 156 + service/core/SugarWebService.php | 53 + service/core/SugarWebServiceImpl.php | 1142 + service/core/WSDL.tpl | 0 service/core/webservice.php | 63 + service/example/Rest_Proxy.php | 102 + service/example/example.html | 338 + service/example/test.html | 324 + service/utils/SugarRest.js | 58 + service/v2/SugarSoapService2.php | 60 + service/v2/registry.php | 653 + service/v2/rest.php | 49 + service/v2/soap.php | 54 + service/v2_1/SugarWebServiceImplv2_1.php | 83 + service/v2_1/registry.php | 133 + service/v2_1/rest.php | 50 + service/v2_1/soap.php | 50 + service/v3/SugarWebServiceImplv3.php | 640 + service/v3/SugarWebServiceUtilv3.php | 501 + service/v3/registry.php | 194 + service/v3/rest.php | 50 + service/v3/soap.php | 50 + service/v3_1/SugarWebServiceImplv3_1.php | 865 + service/v3_1/SugarWebServiceUtilv3_1.php | 565 + service/v3_1/registry.php | 289 + service/v3_1/rest.php | 50 + service/v3_1/soap.php | 50 + service/v4/SugarWebServiceImplv4.php | 585 + service/v4/SugarWebServiceUtilv4.php | 677 + service/v4/registry.php | 144 + service/v4/rest.php | 50 + service/v4/soap.php | 50 + soap.php | 100 + soap/SoapData.php | 325 + soap/SoapDeprecated.php | 963 + soap/SoapError.php | 83 + soap/SoapErrorDefinitions.php | 67 + soap/SoapHelperFunctions.php | 1056 + soap/SoapPortalHelper.php | 424 + soap/SoapPortalUsers.php | 779 + soap/SoapRelationshipHelper.php | 504 + soap/SoapStudio.php | 319 + soap/SoapSugarUsers.php | 2116 ++ soap/SoapTypes.php | 830 + sugar_version.php | 47 + themes/Sugar5/css/chart.css | 258 + themes/Sugar5/css/deprecated.css | 125 + themes/Sugar5/css/print.css | 41 + themes/Sugar5/css/style.css | 3589 ++ themes/Sugar5/css/wizard.css | 65 + themes/Sugar5/css/yui.css | 6223 ++++ themes/Sugar5/images/ACLRoles.gif | Bin 0 -> 563 bytes themes/Sugar5/images/AccountReports.gif | Bin 0 -> 231 bytes themes/Sugar5/images/Accounts.gif | Bin 0 -> 553 bytes themes/Sugar5/images/ActivitiesReports.gif | Bin 0 -> 174 bytes themes/Sugar5/images/Administration.gif | Bin 0 -> 325 bytes themes/Sugar5/images/AlertEmailTemplates.gif | Bin 0 -> 349 bytes themes/Sugar5/images/AllNews.gif | Bin 0 -> 333 bytes themes/Sugar5/images/AllRSS.gif | Bin 0 -> 333 bytes themes/Sugar5/images/ArrowButtons.png | Bin 0 -> 1499 bytes themes/Sugar5/images/Backup.gif | Bin 0 -> 340 bytes themes/Sugar5/images/Backups.gif | Bin 0 -> 576 bytes themes/Sugar5/images/BugReports.gif | Bin 0 -> 172 bytes themes/Sugar5/images/Bugs.gif | Bin 0 -> 214 bytes themes/Sugar5/images/Calendar.gif | Bin 0 -> 350 bytes themes/Sugar5/images/CallReports.gif | Bin 0 -> 229 bytes themes/Sugar5/images/Calls.gif | Bin 0 -> 547 bytes themes/Sugar5/images/Campaigns.gif | Bin 0 -> 559 bytes themes/Sugar5/images/CampaignsWizard.gif | Bin 0 -> 353 bytes themes/Sugar5/images/CaseReports.gif | Bin 0 -> 233 bytes themes/Sugar5/images/Cases.gif | Bin 0 -> 334 bytes themes/Sugar5/images/ConfigureSubPanels.gif | Bin 0 -> 343 bytes themes/Sugar5/images/ConfigureTabs.gif | Bin 0 -> 563 bytes themes/Sugar5/images/ContactReports.gif | Bin 0 -> 338 bytes themes/Sugar5/images/Contacts.gif | Bin 0 -> 219 bytes themes/Sugar5/images/ContractReports.gif | Bin 0 -> 233 bytes themes/Sugar5/images/Contracts.gif | Bin 0 -> 110 bytes themes/Sugar5/images/CreateAccounts.gif | Bin 0 -> 547 bytes themes/Sugar5/images/CreateBugs.gif | Bin 0 -> 218 bytes themes/Sugar5/images/CreateCalls.gif | Bin 0 -> 343 bytes themes/Sugar5/images/CreateCampaigns.gif | Bin 0 -> 562 bytes themes/Sugar5/images/CreateCases.gif | Bin 0 -> 336 bytes themes/Sugar5/images/CreateContacts.gif | Bin 0 -> 214 bytes themes/Sugar5/images/CreateContracts.gif | Bin 0 -> 123 bytes themes/Sugar5/images/CreateCustomQuery.gif | Bin 0 -> 234 bytes themes/Sugar5/images/CreateDCEClusters.gif | Bin 0 -> 573 bytes themes/Sugar5/images/CreateDCEDataBases.gif | Bin 0 -> 366 bytes themes/Sugar5/images/CreateDCEInstances.gif | Bin 0 -> 596 bytes themes/Sugar5/images/CreateDCETemplates.gif | Bin 0 -> 569 bytes themes/Sugar5/images/CreateDataSet.gif | Bin 0 -> 226 bytes themes/Sugar5/images/CreateDocuments.gif | Bin 0 -> 225 bytes themes/Sugar5/images/CreateDropdown.gif | Bin 0 -> 349 bytes themes/Sugar5/images/CreateEmails.gif | Bin 0 -> 334 bytes themes/Sugar5/images/CreateEmployees.gif | Bin 0 -> 371 bytes themes/Sugar5/images/CreateHolidays.gif | Bin 0 -> 375 bytes themes/Sugar5/images/CreateKBArticle.gif | Bin 0 -> 236 bytes themes/Sugar5/images/CreateLeads.gif | Bin 0 -> 225 bytes themes/Sugar5/images/CreateMailboxes.gif | Bin 0 -> 381 bytes themes/Sugar5/images/CreateMeetings.gif | Bin 0 -> 343 bytes themes/Sugar5/images/CreateNotes.gif | Bin 0 -> 346 bytes themes/Sugar5/images/CreateOpportunities.gif | Bin 0 -> 326 bytes themes/Sugar5/images/CreateProducts.gif | Bin 0 -> 577 bytes themes/Sugar5/images/CreateProject.gif | Bin 0 -> 228 bytes themes/Sugar5/images/CreateProjectTask.gif | Bin 0 -> 221 bytes .../Sugar5/images/CreateProjectTemplate.gif | Bin 0 -> 173 bytes themes/Sugar5/images/CreateProspectLists.gif | Bin 0 -> 237 bytes themes/Sugar5/images/CreateProspects.gif | Bin 0 -> 223 bytes themes/Sugar5/images/CreateQuery.gif | Bin 0 -> 223 bytes themes/Sugar5/images/CreateQuotes.gif | Bin 0 -> 230 bytes themes/Sugar5/images/CreateReport.gif | Bin 0 -> 168 bytes themes/Sugar5/images/CreateRoles.gif | Bin 0 -> 565 bytes themes/Sugar5/images/CreateScheduler.gif | Bin 0 -> 360 bytes themes/Sugar5/images/CreateTasks.gif | Bin 0 -> 346 bytes themes/Sugar5/images/CreateTeams.gif | Bin 0 -> 209 bytes themes/Sugar5/images/CreateTimePeriods.gif | Bin 0 -> 348 bytes themes/Sugar5/images/CreateUsers.gif | Bin 0 -> 346 bytes themes/Sugar5/images/CreateWebToLeadForm.gif | Bin 0 -> 240 bytes .../images/CreateWorkflowDefinition.gif | Bin 0 -> 220 bytes themes/Sugar5/images/CreateiFrames.gif | Bin 0 -> 363 bytes themes/Sugar5/images/Currencies.gif | Bin 0 -> 569 bytes themes/Sugar5/images/CustomQueries.gif | Bin 0 -> 226 bytes themes/Sugar5/images/DCEActions.gif | Bin 0 -> 623 bytes themes/Sugar5/images/DCEClusters.gif | Bin 0 -> 573 bytes themes/Sugar5/images/DCEDataBases.gif | Bin 0 -> 360 bytes themes/Sugar5/images/DCEInstances.gif | Bin 0 -> 606 bytes themes/Sugar5/images/DCELicensingReport.gif | Bin 0 -> 338 bytes themes/Sugar5/images/DCETemplates.gif | Bin 0 -> 571 bytes themes/Sugar5/images/Dashboard.gif | Bin 0 -> 159 bytes themes/Sugar5/images/DataSets.gif | Bin 0 -> 227 bytes themes/Sugar5/images/Diagnostic.gif | Bin 0 -> 154 bytes themes/Sugar5/images/DocumentRevisions.gif | Bin 0 -> 164 bytes themes/Sugar5/images/Documents.gif | Bin 0 -> 223 bytes themes/Sugar5/images/Dropdown.gif | Bin 0 -> 549 bytes themes/Sugar5/images/EditLayout.gif | Bin 0 -> 353 bytes themes/Sugar5/images/EmailDiagnostic.gif | Bin 0 -> 346 bytes themes/Sugar5/images/EmailFolder.gif | Bin 0 -> 568 bytes themes/Sugar5/images/EmailMan.gif | Bin 0 -> 582 bytes themes/Sugar5/images/EmailReports.gif | Bin 0 -> 346 bytes themes/Sugar5/images/EmailSetupWizard.gif | Bin 0 -> 360 bytes themes/Sugar5/images/EmailTemplates.gif | Bin 0 -> 341 bytes themes/Sugar5/images/Emails.gif | Bin 0 -> 341 bytes themes/Sugar5/images/Employees.gif | Bin 0 -> 375 bytes themes/Sugar5/images/ExportCustomFields.gif | Bin 0 -> 573 bytes themes/Sugar5/images/FavoriteReports.gif | Bin 0 -> 928 bytes themes/Sugar5/images/Feeds.gif | Bin 0 -> 235 bytes themes/Sugar5/images/FieldLabels.gif | Bin 0 -> 560 bytes themes/Sugar5/images/ForecastReports.gif | Bin 0 -> 174 bytes themes/Sugar5/images/ForecastWorksheet.gif | Bin 0 -> 340 bytes themes/Sugar5/images/Forecasts.gif | Bin 0 -> 225 bytes themes/Sugar5/images/Holidays.gif | Bin 0 -> 376 bytes themes/Sugar5/images/Import.gif | Bin 0 -> 577 bytes themes/Sugar5/images/ImportCustomFields.gif | Bin 0 -> 572 bytes themes/Sugar5/images/InboundEmail.gif | Bin 0 -> 377 bytes themes/Sugar5/images/KB.gif | Bin 0 -> 173 bytes themes/Sugar5/images/KBArticle.gif | Bin 0 -> 170 bytes themes/Sugar5/images/KBDocuments.gif | Bin 0 -> 170 bytes themes/Sugar5/images/LanguagePacks.gif | Bin 0 -> 170 bytes themes/Sugar5/images/Layout.gif | Bin 0 -> 567 bytes themes/Sugar5/images/LeadReports.gif | Bin 0 -> 172 bytes themes/Sugar5/images/Leads.gif | Bin 0 -> 226 bytes themes/Sugar5/images/License.gif | Bin 0 -> 327 bytes themes/Sugar5/images/MailboxesTestImport.gif | Bin 0 -> 371 bytes themes/Sugar5/images/Manufacturers.gif | Bin 0 -> 322 bytes themes/Sugar5/images/MatrixReport.gif | Bin 0 -> 3058 bytes themes/Sugar5/images/MatrixReportOver.gif | Bin 0 -> 3322 bytes themes/Sugar5/images/MeetingReports.gif | Bin 0 -> 229 bytes themes/Sugar5/images/Meetings.gif | Bin 0 -> 551 bytes themes/Sugar5/images/MigrateFields.gif | Bin 0 -> 576 bytes themes/Sugar5/images/ModuleBuilder.gif | Bin 0 -> 363 bytes themes/Sugar5/images/ModuleLoader.gif | Bin 0 -> 207 bytes themes/Sugar5/images/MoreDetail.png | Bin 0 -> 2844 bytes themes/Sugar5/images/MyProject.gif | Bin 0 -> 339 bytes themes/Sugar5/images/MyReports.gif | Bin 0 -> 230 bytes themes/Sugar5/images/Newsletters.gif | Bin 0 -> 338 bytes themes/Sugar5/images/Notes.gif | Bin 0 -> 560 bytes themes/Sugar5/images/OfflineClient.gif | Bin 0 -> 353 bytes themes/Sugar5/images/OnlineDocumentation.gif | Bin 0 -> 400 bytes themes/Sugar5/images/Opportunities.gif | Bin 0 -> 322 bytes themes/Sugar5/images/OpportunityReports.gif | Bin 0 -> 165 bytes themes/Sugar5/images/Password.gif | Bin 0 -> 188 bytes themes/Sugar5/images/PatchUpgrades.gif | Bin 0 -> 333 bytes themes/Sugar5/images/PriceList.gif | Bin 0 -> 565 bytes themes/Sugar5/images/Price_List.gif | Bin 0 -> 565 bytes themes/Sugar5/images/Print_Email.gif | Bin 0 -> 585 bytes themes/Sugar5/images/ProductCategories.gif | Bin 0 -> 587 bytes themes/Sugar5/images/ProductTemplates.gif | Bin 0 -> 587 bytes themes/Sugar5/images/ProductTypes.gif | Bin 0 -> 556 bytes themes/Sugar5/images/Product_Categories.gif | Bin 0 -> 587 bytes themes/Sugar5/images/Product_Types.gif | Bin 0 -> 556 bytes themes/Sugar5/images/Products.gif | Bin 0 -> 587 bytes themes/Sugar5/images/Project.gif | Bin 0 -> 218 bytes themes/Sugar5/images/Project2Weeks.gif | Bin 0 -> 152 bytes themes/Sugar5/images/ProjectCollapseAll.gif | Bin 0 -> 96 bytes themes/Sugar5/images/ProjectCopy.gif | Bin 0 -> 245 bytes themes/Sugar5/images/ProjectCut.gif | Bin 0 -> 87 bytes themes/Sugar5/images/ProjectDelete.gif | Bin 0 -> 351 bytes themes/Sugar5/images/ProjectExpandAll.gif | Bin 0 -> 101 bytes themes/Sugar5/images/ProjectIndent.gif | Bin 0 -> 104 bytes themes/Sugar5/images/ProjectInsertRows.gif | Bin 0 -> 83 bytes themes/Sugar5/images/ProjectMinus.gif | Bin 0 -> 861 bytes themes/Sugar5/images/ProjectMonth.gif | Bin 0 -> 115 bytes themes/Sugar5/images/ProjectOutdent.gif | Bin 0 -> 105 bytes themes/Sugar5/images/ProjectPaste.gif | Bin 0 -> 609 bytes themes/Sugar5/images/ProjectPlus.gif | Bin 0 -> 865 bytes themes/Sugar5/images/ProjectSave.gif | Bin 0 -> 343 bytes themes/Sugar5/images/ProjectTask.gif | Bin 0 -> 214 bytes themes/Sugar5/images/ProjectTemplate.gif | Bin 0 -> 164 bytes themes/Sugar5/images/ProjectWeek.gif | Bin 0 -> 154 bytes themes/Sugar5/images/ProspectLists.gif | Bin 0 -> 232 bytes themes/Sugar5/images/Prospects.gif | Bin 0 -> 216 bytes themes/Sugar5/images/QueryBuilder.gif | Bin 0 -> 228 bytes themes/Sugar5/images/QuoteReports.gif | Bin 0 -> 167 bytes themes/Sugar5/images/Quotes.gif | Bin 0 -> 334 bytes themes/Sugar5/images/RSS.gif | Bin 0 -> 235 bytes themes/Sugar5/images/ReassignRecords.gif | Bin 0 -> 349 bytes themes/Sugar5/images/Rebuild.gif | Bin 0 -> 579 bytes themes/Sugar5/images/Rebuild2.gif | Bin 0 -> 590 bytes themes/Sugar5/images/Releases.gif | Bin 0 -> 570 bytes themes/Sugar5/images/RenameTabs.gif | Bin 0 -> 364 bytes themes/Sugar5/images/Repair.gif | Bin 0 -> 144 bytes themes/Sugar5/images/ReportMaker.gif | Bin 0 -> 171 bytes themes/Sugar5/images/Reports.gif | Bin 0 -> 162 bytes themes/Sugar5/images/Roles.gif | Bin 0 -> 563 bytes themes/Sugar5/images/RowsAndColumns.gif | Bin 0 -> 2855 bytes themes/Sugar5/images/RowsAndColumnsOver.gif | Bin 0 -> 3046 bytes themes/Sugar5/images/SchedulerTest.gif | Bin 0 -> 379 bytes themes/Sugar5/images/Schedulers.gif | Bin 0 -> 364 bytes themes/Sugar5/images/Search.gif | Bin 0 -> 100 bytes themes/Sugar5/images/Shippers.gif | Bin 0 -> 326 bytes themes/Sugar5/images/StickyThread.gif | Bin 0 -> 882 bytes themes/Sugar5/images/Studio.gif | Bin 0 -> 617 bytes themes/Sugar5/images/SugarPortal.gif | Bin 0 -> 366 bytes themes/Sugar5/images/Summation.gif | Bin 0 -> 2685 bytes themes/Sugar5/images/SummationOver.gif | Bin 0 -> 3064 bytes themes/Sugar5/images/SummationWithDetails.gif | Bin 0 -> 2596 bytes .../images/SummationWithDetailsOver.gif | Bin 0 -> 3121 bytes themes/Sugar5/images/Support.gif | Bin 0 -> 385 bytes themes/Sugar5/images/TaskReports.gif | Bin 0 -> 229 bytes themes/Sugar5/images/Tasks.gif | Bin 0 -> 352 bytes themes/Sugar5/images/TaxRates.gif | Bin 0 -> 215 bytes themes/Sugar5/images/Teams.gif | Bin 0 -> 148 bytes themes/Sugar5/images/Themes.gif | Bin 0 -> 1016 bytes themes/Sugar5/images/TimePeriods.gif | Bin 0 -> 353 bytes themes/Sugar5/images/Trackers.gif | Bin 0 -> 609 bytes themes/Sugar5/images/Upgrade.gif | Bin 0 -> 203 bytes themes/Sugar5/images/UpgradeDCEInstances.gif | Bin 0 -> 203 bytes themes/Sugar5/images/Users.gif | Bin 0 -> 343 bytes themes/Sugar5/images/WorkFlow.gif | Bin 0 -> 215 bytes themes/Sugar5/images/WorkflowSequence.gif | Bin 0 -> 207 bytes themes/Sugar5/images/_blank.png | Bin 0 -> 137 bytes themes/Sugar5/images/accept_inline.gif | Bin 0 -> 101 bytes themes/Sugar5/images/advanced_search.gif | Bin 0 -> 62 bytes themes/Sugar5/images/arrow.gif | Bin 0 -> 64 bytes themes/Sugar5/images/arrow_down.gif | Bin 0 -> 81 bytes themes/Sugar5/images/arrow_up.gif | Bin 0 -> 79 bytes themes/Sugar5/images/attachment.gif | Bin 0 -> 94 bytes themes/Sugar5/images/bar_loader.gif | Bin 0 -> 10819 bytes themes/Sugar5/images/basic_search.gif | Bin 0 -> 62 bytes themes/Sugar5/images/bg.gif | Bin 0 -> 90 bytes themes/Sugar5/images/bgBlue.gif | Bin 0 -> 90 bytes themes/Sugar5/images/bgBtn.gif | Bin 0 -> 93 bytes themes/Sugar5/images/bgBtnBlue.gif | Bin 0 -> 93 bytes themes/Sugar5/images/bgBtnGray.gif | Bin 0 -> 68 bytes themes/Sugar5/images/bgBtnGreen.gif | Bin 0 -> 93 bytes themes/Sugar5/images/bgBtnOrange.gif | Bin 0 -> 92 bytes themes/Sugar5/images/bgBtnPurple.gif | Bin 0 -> 92 bytes themes/Sugar5/images/bgGray.gif | Bin 0 -> 57 bytes themes/Sugar5/images/bgGreen.gif | Bin 0 -> 808 bytes themes/Sugar5/images/bgOcher.gif | Bin 0 -> 90 bytes themes/Sugar5/images/bgPurple.gif | Bin 0 -> 90 bytes themes/Sugar5/images/bgRed.gif | Bin 0 -> 65 bytes themes/Sugar5/images/blank.gif | Bin 0 -> 43 bytes themes/Sugar5/images/calendarHeaderBg.gif | Bin 0 -> 155 bytes themes/Sugar5/images/calendar_next.gif | Bin 0 -> 67 bytes themes/Sugar5/images/calendar_previous.gif | Bin 0 -> 65 bytes themes/Sugar5/images/check_inline.gif | Bin 0 -> 102 bytes themes/Sugar5/images/clear.gif | Bin 0 -> 272 bytes themes/Sugar5/images/close.gif | Bin 0 -> 83 bytes themes/Sugar5/images/close_dashboard.gif | Bin 0 -> 68 bytes themes/Sugar5/images/close_inline.gif | Bin 0 -> 103 bytes themes/Sugar5/images/colors.blue.icon.gif | Bin 0 -> 89 bytes themes/Sugar5/images/colors.gray.icon.gif | Bin 0 -> 62 bytes themes/Sugar5/images/colors.green.icon.gif | Bin 0 -> 89 bytes themes/Sugar5/images/colors.orange.icon.gif | Bin 0 -> 89 bytes themes/Sugar5/images/colors.purple.icon.gif | Bin 0 -> 89 bytes themes/Sugar5/images/colors.red.icon.gif | Bin 0 -> 70 bytes themes/Sugar5/images/colors.sugar.icon.gif | Bin 0 -> 89 bytes themes/Sugar5/images/currentTab.gif | Bin 0 -> 1002 bytes themes/Sugar5/images/currentTabBlue.gif | Bin 0 -> 993 bytes themes/Sugar5/images/currentTabGray.gif | Bin 0 -> 993 bytes themes/Sugar5/images/currentTabGreen.gif | Bin 0 -> 993 bytes themes/Sugar5/images/currentTabLinkBg.gif | Bin 0 -> 108 bytes themes/Sugar5/images/currentTabOcher.gif | Bin 0 -> 993 bytes themes/Sugar5/images/currentTabOff.gif | Bin 0 -> 764 bytes themes/Sugar5/images/currentTabPurple.gif | Bin 0 -> 993 bytes themes/Sugar5/images/currentTabRed.gif | Bin 0 -> 1006 bytes themes/Sugar5/images/dce_Settings.gif | Bin 0 -> 338 bytes themes/Sugar5/images/decline_inline.gif | Bin 0 -> 102 bytes themes/Sugar5/images/def_image_inline.gif | Bin 0 -> 587 bytes themes/Sugar5/images/delete.gif | Bin 0 -> 66 bytes themes/Sugar5/images/delete_inline.gif | Bin 0 -> 106 bytes themes/Sugar5/images/detailViewBg.gif | Bin 0 -> 262 bytes themes/Sugar5/images/detailview.gif | Bin 0 -> 355 bytes themes/Sugar5/images/doc_image_inline.gif | Bin 0 -> 353 bytes themes/Sugar5/images/downarrow.gif | Bin 0 -> 66 bytes themes/Sugar5/images/downarrow_big.gif | Bin 0 -> 74 bytes themes/Sugar5/images/downarrow_inline.gif | Bin 0 -> 80 bytes themes/Sugar5/images/edit.gif | Bin 0 -> 69 bytes themes/Sugar5/images/edit_inline.gif | Bin 0 -> 83 bytes themes/Sugar5/images/edit_wizard.gif | Bin 0 -> 82 bytes themes/Sugar5/images/editfields.gif | Bin 0 -> 560 bytes themes/Sugar5/images/editlabels.gif | Bin 0 -> 353 bytes themes/Sugar5/images/editview.gif | Bin 0 -> 353 bytes themes/Sugar5/images/emptyTabSpace.gif | Bin 0 -> 430 bytes themes/Sugar5/images/end.gif | Bin 0 -> 95 bytes themes/Sugar5/images/end_off.gif | Bin 0 -> 75 bytes themes/Sugar5/images/export.gif | Bin 0 -> 78 bytes themes/Sugar5/images/fonts.larger.icon.gif | Bin 0 -> 135 bytes themes/Sugar5/images/fonts.largest.icon.gif | Bin 0 -> 144 bytes themes/Sugar5/images/fonts.normal.icon.gif | Bin 0 -> 127 bytes themes/Sugar5/images/formButtonBg.gif | Bin 0 -> 93 bytes themes/Sugar5/images/formButtonBgOn.gif | Bin 0 -> 67 bytes themes/Sugar5/images/getLatestDocument.gif | Bin 0 -> 81 bytes themes/Sugar5/images/green_camp.gif | Bin 0 -> 1829 bytes themes/Sugar5/images/h3Arrow.gif | Bin 0 -> 64 bytes themes/Sugar5/images/help.gif | Bin 0 -> 66 bytes themes/Sugar5/images/helpInline.gif | Bin 0 -> 153 bytes themes/Sugar5/images/hide.gif | Bin 0 -> 223 bytes .../Sugar5/images/hide_submenu_shortcuts.gif | Bin 0 -> 74 bytes themes/Sugar5/images/iFrames.gif | Bin 0 -> 338 bytes themes/Sugar5/images/icon_A1_newmod.gif | Bin 0 -> 2201 bytes themes/Sugar5/images/icon_Accounts.gif | Bin 0 -> 2053 bytes themes/Sugar5/images/icon_Accounts_32.gif | Bin 0 -> 955 bytes themes/Sugar5/images/icon_Activities.gif | Bin 0 -> 2304 bytes themes/Sugar5/images/icon_Address.gif | Bin 0 -> 160 bytes themes/Sugar5/images/icon_AdminMobile.gif | Bin 0 -> 333 bytes themes/Sugar5/images/icon_AdminPDF.gif | Bin 0 -> 248 bytes themes/Sugar5/images/icon_AdminThemes.gif | Bin 0 -> 340 bytes themes/Sugar5/images/icon_AdvancedSearch.gif | Bin 0 -> 2518 bytes themes/Sugar5/images/icon_Application.gif | Bin 0 -> 5631 bytes themes/Sugar5/images/icon_BasicSearch.gif | Bin 0 -> 2561 bytes themes/Sugar5/images/icon_Bugs.gif | Bin 0 -> 2052 bytes themes/Sugar5/images/icon_Bugs_32.gif | Bin 0 -> 995 bytes themes/Sugar5/images/icon_Calls.gif | Bin 0 -> 1905 bytes themes/Sugar5/images/icon_Calls_32.gif | Bin 0 -> 990 bytes themes/Sugar5/images/icon_CampaignLog_32.gif | Bin 0 -> 1120 bytes themes/Sugar5/images/icon_Campaigns.gif | Bin 0 -> 2342 bytes themes/Sugar5/images/icon_Campaigns_32.gif | Bin 0 -> 1120 bytes themes/Sugar5/images/icon_Cases.gif | Bin 0 -> 2060 bytes themes/Sugar5/images/icon_Cases_32.gif | Bin 0 -> 976 bytes themes/Sugar5/images/icon_Charts_Funnel.gif | Bin 0 -> 2031 bytes .../Sugar5/images/icon_Charts_Funnel_32.gif | Bin 0 -> 697 bytes themes/Sugar5/images/icon_Charts_Gauge.gif | Bin 0 -> 2117 bytes themes/Sugar5/images/icon_Charts_Gauge_32.gif | Bin 0 -> 738 bytes themes/Sugar5/images/icon_Charts_GroupBy.gif | Bin 0 -> 2150 bytes .../Sugar5/images/icon_Charts_GroupBy_32.gif | Bin 0 -> 764 bytes .../Sugar5/images/icon_Charts_Horizontal.gif | Bin 0 -> 2113 bytes .../images/icon_Charts_Horizontal_32.gif | Bin 0 -> 800 bytes themes/Sugar5/images/icon_Charts_Pie.gif | Bin 0 -> 2223 bytes themes/Sugar5/images/icon_Charts_Pie_32.gif | Bin 0 -> 794 bytes themes/Sugar5/images/icon_Charts_Vertical.gif | Bin 0 -> 2131 bytes .../Sugar5/images/icon_Charts_Vertical_32.gif | Bin 0 -> 799 bytes themes/Sugar5/images/icon_Column_1.gif | Bin 0 -> 1971 bytes themes/Sugar5/images/icon_Column_2.gif | Bin 0 -> 2082 bytes themes/Sugar5/images/icon_Column_3.gif | Bin 0 -> 2186 bytes themes/Sugar5/images/icon_ConnectorConfig.gif | Bin 0 -> 4560 bytes .../images/icon_ConnectorConfigOver.gif | Bin 0 -> 4743 bytes .../Sugar5/images/icon_ConnectorConfig_16.gif | Bin 0 -> 622 bytes themes/Sugar5/images/icon_ConnectorEnable.gif | Bin 0 -> 4476 bytes .../images/icon_ConnectorEnableOver.gif | Bin 0 -> 4593 bytes .../Sugar5/images/icon_ConnectorEnable_16.gif | Bin 0 -> 382 bytes themes/Sugar5/images/icon_ConnectorMap.gif | Bin 0 -> 4577 bytes .../Sugar5/images/icon_ConnectorMapOver.gif | Bin 0 -> 4797 bytes themes/Sugar5/images/icon_ConnectorMap_16.gif | Bin 0 -> 594 bytes .../images/icon_ConnectorSearchFields.gif | Bin 0 -> 4548 bytes .../images/icon_ConnectorSearchFieldsOver.gif | Bin 0 -> 4656 bytes .../images/icon_ConnectorSearchFields_16.gif | Bin 0 -> 618 bytes themes/Sugar5/images/icon_Connectors.gif | Bin 0 -> 600 bytes themes/Sugar5/images/icon_Contacts.gif | Bin 0 -> 1953 bytes themes/Sugar5/images/icon_Contacts_32.gif | Bin 0 -> 971 bytes themes/Sugar5/images/icon_Contracts.gif | Bin 0 -> 1417 bytes themes/Sugar5/images/icon_Contracts_32.gif | Bin 0 -> 762 bytes themes/Sugar5/images/icon_DCEActions_32.gif | Bin 0 -> 1075 bytes themes/Sugar5/images/icon_DCEClusters_32.gif | Bin 0 -> 1051 bytes themes/Sugar5/images/icon_DCEDataBases_32.gif | Bin 0 -> 1059 bytes themes/Sugar5/images/icon_DCEInstances_32.gif | Bin 0 -> 1055 bytes themes/Sugar5/images/icon_DCEReports_32.gif | Bin 0 -> 979 bytes themes/Sugar5/images/icon_DCETemplates_32.gif | Bin 0 -> 1084 bytes themes/Sugar5/images/icon_Dashlet.gif | Bin 0 -> 1435 bytes themes/Sugar5/images/icon_Delete.gif | Bin 0 -> 2263 bytes themes/Sugar5/images/icon_DeleteFull.gif | Bin 0 -> 2340 bytes themes/Sugar5/images/icon_DetailView.gif | Bin 0 -> 1837 bytes themes/Sugar5/images/icon_Documents.gif | Bin 0 -> 2054 bytes themes/Sugar5/images/icon_Documents_32.gif | Bin 0 -> 1009 bytes themes/Sugar5/images/icon_DropDownEditor.gif | Bin 0 -> 3202 bytes themes/Sugar5/images/icon_EditView.gif | Bin 0 -> 1903 bytes themes/Sugar5/images/icon_EmailAddress.gif | Bin 0 -> 327 bytes .../Sugar5/images/icon_EmailAddresses_32.gif | Bin 0 -> 853 bytes themes/Sugar5/images/icon_Emails.gif | Bin 0 -> 1873 bytes themes/Sugar5/images/icon_Emails_32.gif | Bin 0 -> 859 bytes themes/Sugar5/images/icon_FavoriteReports.gif | Bin 0 -> 2196 bytes .../Sugar5/images/icon_FavoriteReports_32.gif | Bin 0 -> 779 bytes themes/Sugar5/images/icon_Feeds_32.gif | Bin 0 -> 1240 bytes themes/Sugar5/images/icon_Fields.gif | Bin 0 -> 1966 bytes themes/Sugar5/images/icon_Forecasts.gif | Bin 0 -> 2161 bytes themes/Sugar5/images/icon_Forecasts_32.gif | Bin 0 -> 1031 bytes themes/Sugar5/images/icon_Invaders_32.gif | Bin 0 -> 1256 bytes themes/Sugar5/images/icon_JotPad.gif | Bin 0 -> 2304 bytes themes/Sugar5/images/icon_JotPad_32.gif | Bin 0 -> 845 bytes themes/Sugar5/images/icon_KBDocuments.gif | Bin 0 -> 2145 bytes themes/Sugar5/images/icon_KBDocuments_32.gif | Bin 0 -> 1044 bytes themes/Sugar5/images/icon_Labels.gif | Bin 0 -> 2009 bytes themes/Sugar5/images/icon_Layouts.gif | Bin 0 -> 2099 bytes themes/Sugar5/images/icon_Leads.gif | Bin 0 -> 2513 bytes themes/Sugar5/images/icon_Leads_32.gif | Bin 0 -> 1180 bytes themes/Sugar5/images/icon_ListView.gif | Bin 0 -> 2019 bytes themes/Sugar5/images/icon_Meetings.gif | Bin 0 -> 2484 bytes themes/Sugar5/images/icon_Meetings_32.gif | Bin 0 -> 1140 bytes themes/Sugar5/images/icon_MobileLayouts.gif | Bin 0 -> 2244 bytes themes/Sugar5/images/icon_ModuleBuilder.gif | Bin 0 -> 4427 bytes themes/Sugar5/images/icon_MyPortal_32.gif | Bin 0 -> 1042 bytes themes/Sugar5/images/icon_MyTasks_32.gif | Bin 0 -> 929 bytes themes/Sugar5/images/icon_NewModule.gif | Bin 0 -> 2241 bytes themes/Sugar5/images/icon_Notes.gif | Bin 0 -> 2178 bytes themes/Sugar5/images/icon_Notes_32.gif | Bin 0 -> 1067 bytes themes/Sugar5/images/icon_OpenTasks_32.gif | Bin 0 -> 939 bytes themes/Sugar5/images/icon_Opportunities.gif | Bin 0 -> 2081 bytes .../Sugar5/images/icon_Opportunities_32.gif | Bin 0 -> 1026 bytes themes/Sugar5/images/icon_Phone.gif | Bin 0 -> 344 bytes themes/Sugar5/images/icon_Portal.gif | Bin 0 -> 2099 bytes .../images/icon_ProductCategories_32.gif | Bin 0 -> 965 bytes .../Sugar5/images/icon_ProductTemplates.gif | Bin 0 -> 2328 bytes themes/Sugar5/images/icon_ProductTypes_32.gif | Bin 0 -> 1081 bytes .../Sugar5/images/icon_Product_Types_32.gif | Bin 0 -> 1081 bytes themes/Sugar5/images/icon_Products.gif | Bin 0 -> 2263 bytes themes/Sugar5/images/icon_Products_32.gif | Bin 0 -> 1055 bytes themes/Sugar5/images/icon_Project.gif | Bin 0 -> 1732 bytes themes/Sugar5/images/icon_ProjectTask.gif | Bin 0 -> 1758 bytes themes/Sugar5/images/icon_ProjectTask_32.gif | Bin 0 -> 876 bytes themes/Sugar5/images/icon_Project_32.gif | Bin 0 -> 850 bytes themes/Sugar5/images/icon_Projects_32.gif | Bin 0 -> 850 bytes themes/Sugar5/images/icon_Prospects.gif | Bin 0 -> 1795 bytes themes/Sugar5/images/icon_Prospects_32.gif | Bin 0 -> 881 bytes themes/Sugar5/images/icon_QuickCreate.gif | Bin 0 -> 1806 bytes themes/Sugar5/images/icon_Quotes.gif | Bin 0 -> 2349 bytes themes/Sugar5/images/icon_Quotes_32.gif | Bin 0 -> 1157 bytes themes/Sugar5/images/icon_Relationships.gif | Bin 0 -> 1416 bytes themes/Sugar5/images/icon_Releases_32.gif | Bin 0 -> 919 bytes themes/Sugar5/images/icon_Reports_32.gif | Bin 0 -> 1020 bytes themes/Sugar5/images/icon_Rss_32.gif | Bin 0 -> 1240 bytes themes/Sugar5/images/icon_SPSync.gif | Bin 0 -> 2170 bytes themes/Sugar5/images/icon_SPUploadCSS.gif | Bin 0 -> 2034 bytes themes/Sugar5/images/icon_SearchForm.gif | Bin 0 -> 1993 bytes themes/Sugar5/images/icon_Studio.gif | Bin 0 -> 4786 bytes themes/Sugar5/images/icon_Subpanels.gif | Bin 0 -> 1921 bytes themes/Sugar5/images/icon_SugarFeed.gif | Bin 0 -> 225 bytes themes/Sugar5/images/icon_SugarFeed_32.gif | Bin 0 -> 1337 bytes themes/Sugar5/images/icon_SugarNews_32.gif | Bin 0 -> 904 bytes themes/Sugar5/images/icon_SugarPortal.gif | Bin 0 -> 4229 bytes themes/Sugar5/images/icon_Targets_32.gif | Bin 0 -> 881 bytes themes/Sugar5/images/icon_Tasks.gif | Bin 0 -> 1884 bytes themes/Sugar5/images/icon_Tasks_32.gif | Bin 0 -> 860 bytes themes/Sugar5/images/icon_Teams_32.gif | Bin 0 -> 950 bytes themes/Sugar5/images/icon_TrackerPerfs_32.gif | Bin 0 -> 982 bytes .../Sugar5/images/icon_TrackerQueries_32.gif | Bin 0 -> 987 bytes .../Sugar5/images/icon_TrackerSessions_32.gif | Bin 0 -> 1009 bytes themes/Sugar5/images/icon_Trackers_32.gif | Bin 0 -> 984 bytes themes/Sugar5/images/icon_Users_32.gif | Bin 0 -> 1081 bytes themes/Sugar5/images/icon_assistant.gif | Bin 0 -> 582 bytes themes/Sugar5/images/icon_back.gif | Bin 0 -> 538 bytes themes/Sugar5/images/icon_basic.gif | Bin 0 -> 2201 bytes themes/Sugar5/images/icon_company.gif | Bin 0 -> 2315 bytes themes/Sugar5/images/icon_document.gif | Bin 0 -> 2364 bytes .../Sugar5/images/icon_email_addressbook.gif | Bin 0 -> 594 bytes themes/Sugar5/images/icon_email_archive.gif | Bin 0 -> 372 bytes themes/Sugar5/images/icon_email_assign.gif | Bin 0 -> 578 bytes themes/Sugar5/images/icon_email_attach.gif | Bin 0 -> 331 bytes themes/Sugar5/images/icon_email_check.gif | Bin 0 -> 580 bytes themes/Sugar5/images/icon_email_compose.gif | Bin 0 -> 364 bytes themes/Sugar5/images/icon_email_create.gif | Bin 0 -> 332 bytes themes/Sugar5/images/icon_email_delete.gif | Bin 0 -> 341 bytes themes/Sugar5/images/icon_email_folder.gif | Bin 0 -> 1928 bytes .../images/icon_email_folder_archives.gif | Bin 0 -> 353 bytes .../images/icon_email_folder_drafts.gif | Bin 0 -> 609 bytes .../Sugar5/images/icon_email_folder_exp.gif | Bin 0 -> 1928 bytes .../Sugar5/images/icon_email_folder_grp.gif | Bin 0 -> 1935 bytes .../Sugar5/images/icon_email_folder_sent.gif | Bin 0 -> 619 bytes themes/Sugar5/images/icon_email_forward.gif | Bin 0 -> 594 bytes .../Sugar5/images/icon_email_fullscreen.gif | Bin 0 -> 178 bytes themes/Sugar5/images/icon_email_mark.gif | Bin 0 -> 355 bytes themes/Sugar5/images/icon_email_options.gif | Bin 0 -> 111 bytes themes/Sugar5/images/icon_email_relate.gif | Bin 0 -> 354 bytes themes/Sugar5/images/icon_email_reply.gif | Bin 0 -> 579 bytes themes/Sugar5/images/icon_email_replyall.gif | Bin 0 -> 379 bytes themes/Sugar5/images/icon_email_save.gif | Bin 0 -> 361 bytes themes/Sugar5/images/icon_email_send.gif | Bin 0 -> 580 bytes themes/Sugar5/images/icon_email_settings.gif | Bin 0 -> 601 bytes themes/Sugar5/images/icon_email_sugfolder.gif | Bin 0 -> 1940 bytes .../images/icon_email_sugfolder_exp.gif | Bin 0 -> 1927 bytes themes/Sugar5/images/icon_email_view.gif | Bin 0 -> 213 bytes themes/Sugar5/images/icon_email_view1.gif | Bin 0 -> 122 bytes themes/Sugar5/images/icon_email_view2.gif | Bin 0 -> 118 bytes themes/Sugar5/images/icon_email_view3.gif | Bin 0 -> 340 bytes .../Sugar5/images/icon_expression_types.gif | Bin 0 -> 324 bytes themes/Sugar5/images/icon_file.gif | Bin 0 -> 1727 bytes themes/Sugar5/images/icon_home.gif | Bin 0 -> 353 bytes themes/Sugar5/images/icon_iFrames_32.gif | Bin 0 -> 1042 bytes themes/Sugar5/images/icon_issue.gif | Bin 0 -> 2325 bytes themes/Sugar5/images/icon_new_package.gif | Bin 0 -> 6599 bytes themes/Sugar5/images/icon_opportunity.gif | Bin 0 -> 2273 bytes themes/Sugar5/images/icon_package.gif | Bin 0 -> 5677 bytes themes/Sugar5/images/icon_package_create.gif | Bin 0 -> 6599 bytes themes/Sugar5/images/icon_person.gif | Bin 0 -> 2311 bytes themes/Sugar5/images/icon_sale.gif | Bin 0 -> 1682 bytes themes/Sugar5/images/icon_therevisions.gif | Bin 0 -> 2054 bytes themes/Sugar5/images/img_close_search.gif | Bin 0 -> 118 bytes themes/Sugar5/images/img_left_arrow.jpg | Bin 0 -> 849 bytes themes/Sugar5/images/img_loading.gif | Bin 0 -> 771 bytes themes/Sugar5/images/img_right_arrow.jpg | Bin 0 -> 835 bytes themes/Sugar5/images/info-add-page.png | Bin 0 -> 312 bytes themes/Sugar5/images/info-del.png | Bin 0 -> 190 bytes themes/Sugar5/images/info_inline.gif | Bin 0 -> 79 bytes themes/Sugar5/images/jscalendar.gif | Bin 0 -> 221 bytes themes/Sugar5/images/leftarrow.gif | Bin 0 -> 74 bytes themes/Sugar5/images/leftarrow_big.gif | Bin 0 -> 74 bytes themes/Sugar5/images/line.gif | Bin 0 -> 1839 bytes themes/Sugar5/images/list.gif | Bin 0 -> 352 bytes themes/Sugar5/images/listViewBg.gif | Bin 0 -> 147 bytes themes/Sugar5/images/listViewHR.gif | Bin 0 -> 43 bytes themes/Sugar5/images/loadSignedDocument.gif | Bin 0 -> 82 bytes themes/Sugar5/images/loading.gif | Bin 0 -> 1787 bytes themes/Sugar5/images/mass_update.gif | Bin 0 -> 91 bytes themes/Sugar5/images/menuarrow.gif | Bin 0 -> 60 bytes themes/Sugar5/images/minus.gif | Bin 0 -> 197 bytes themes/Sugar5/images/minus_inline.gif | Bin 0 -> 76 bytes themes/Sugar5/images/more.gif | Bin 0 -> 58 bytes themes/Sugar5/images/new_inline.gif | Bin 0 -> 1437 bytes themes/Sugar5/images/next.gif | Bin 0 -> 81 bytes themes/Sugar5/images/next_off.gif | Bin 0 -> 64 bytes themes/Sugar5/images/no.gif | Bin 0 -> 72 bytes themes/Sugar5/images/open_multiple.gif | Bin 0 -> 371 bytes themes/Sugar5/images/otherTab.gif | Bin 0 -> 841 bytes themes/Sugar5/images/otherTabBlue.gif | Bin 0 -> 841 bytes themes/Sugar5/images/otherTabGray.gif | Bin 0 -> 841 bytes themes/Sugar5/images/otherTabGreen.gif | Bin 0 -> 841 bytes themes/Sugar5/images/otherTabOcher.gif | Bin 0 -> 841 bytes themes/Sugar5/images/otherTabPurple.gif | Bin 0 -> 841 bytes themes/Sugar5/images/otherTabRed.gif | Bin 0 -> 841 bytes .../images/pdf_header_logo_SugarCRMheader.jpg | Bin 0 -> 42438 bytes .../images/pdf_header_logo_img_left_arrow.jpg | Bin 0 -> 849 bytes ...er_logo_pdf_header_logo_SugarCRMheader.jpg | Bin 0 -> 42438 bytes themes/Sugar5/images/pdf_image_inline.gif | Bin 0 -> 588 bytes themes/Sugar5/images/pdf_logo.jpg | Bin 0 -> 20267 bytes themes/Sugar5/images/pdf_logo_small.jpg | Bin 0 -> 9442 bytes themes/Sugar5/images/plus.gif | Bin 0 -> 313 bytes themes/Sugar5/images/plus_inline.gif | Bin 0 -> 79 bytes themes/Sugar5/images/ppt_image_inline.gif | Bin 0 -> 349 bytes themes/Sugar5/images/previous.gif | Bin 0 -> 79 bytes themes/Sugar5/images/previous_off.gif | Bin 0 -> 63 bytes themes/Sugar5/images/print.gif | Bin 0 -> 68 bytes themes/Sugar5/images/publish_inline.gif | Bin 0 -> 80 bytes themes/Sugar5/images/red_camp.gif | Bin 0 -> 1944 bytes themes/Sugar5/images/refresh.gif | Bin 0 -> 70 bytes themes/Sugar5/images/rightarrow.gif | Bin 0 -> 75 bytes themes/Sugar5/images/rightarrow_big.gif | Bin 0 -> 75 bytes themes/Sugar5/images/scheduled_inline.gif | Bin 0 -> 84 bytes themes/Sugar5/images/searchMore.gif | Bin 0 -> 105 bytes themes/Sugar5/images/select.gif | Bin 0 -> 399 bytes themes/Sugar5/images/show.gif | Bin 0 -> 158 bytes .../Sugar5/images/show_submenu_shortcuts.gif | Bin 0 -> 76 bytes themes/Sugar5/images/slot.gif | Bin 0 -> 202 bytes themes/Sugar5/images/spacer.gif | Bin 0 -> 49 bytes themes/Sugar5/images/sqsWait.gif | Bin 0 -> 849 bytes themes/Sugar5/images/start.gif | Bin 0 -> 94 bytes themes/Sugar5/images/start_off.gif | Bin 0 -> 74 bytes themes/Sugar5/images/studio_addField.gif | Bin 0 -> 331 bytes themes/Sugar5/images/studio_addRows.gif | Bin 0 -> 323 bytes themes/Sugar5/images/studio_blank.gif | Bin 0 -> 328 bytes themes/Sugar5/images/studio_history.gif | Bin 0 -> 328 bytes themes/Sugar5/images/studio_publish.gif | Bin 0 -> 335 bytes themes/Sugar5/images/studio_redo.gif | Bin 0 -> 304 bytes themes/Sugar5/images/studio_save.gif | Bin 0 -> 306 bytes themes/Sugar5/images/studio_undo.gif | Bin 0 -> 330 bytes .../Sugar5/images/sugar-yui-sprites-green.png | Bin 0 -> 2912 bytes .../Sugar5/images/sugar-yui-sprites-grey.png | Bin 0 -> 2833 bytes .../images/sugar-yui-sprites-purple.png | Bin 0 -> 2879 bytes .../Sugar5/images/sugar-yui-sprites-red.png | Bin 0 -> 2894 bytes themes/Sugar5/images/sugar-yui-sprites.png | Bin 0 -> 2896 bytes themes/Sugar5/images/sugarColors.xml | 143 + themes/Sugar5/images/sugar_document.png | Bin 0 -> 601 bytes themes/Sugar5/images/sugar_icon.ico | Bin 0 -> 894 bytes themes/Sugar5/images/sugar_icon.png | Bin 0 -> 2641 bytes themes/Sugar5/images/sugarupdate.gif | Bin 0 -> 200 bytes themes/Sugar5/images/tabRowBg.gif | Bin 0 -> 99 bytes themes/Sugar5/images/tabRowBlueBg.gif | Bin 0 -> 99 bytes themes/Sugar5/images/tabRowGrayBg.gif | Bin 0 -> 99 bytes themes/Sugar5/images/tabRowGreenBg.gif | Bin 0 -> 99 bytes themes/Sugar5/images/tabRowOcherBg.gif | Bin 0 -> 99 bytes themes/Sugar5/images/tabRowPurpleBg.gif | Bin 0 -> 99 bytes themes/Sugar5/images/tabRowRedBg.gif | Bin 0 -> 99 bytes themes/Sugar5/images/tentative_inline.gif | Bin 0 -> 97 bytes themes/Sugar5/images/themePreview.png | Bin 0 -> 9502 bytes themes/Sugar5/images/txt_image_inline.gif | Bin 0 -> 554 bytes themes/Sugar5/images/unpublish_inline.gif | Bin 0 -> 82 bytes themes/Sugar5/images/unscheduled_inline.gif | Bin 0 -> 84 bytes themes/Sugar5/images/uparrow.gif | Bin 0 -> 66 bytes themes/Sugar5/images/uparrow_big.gif | Bin 0 -> 66 bytes themes/Sugar5/images/uparrow_inline.gif | Bin 0 -> 79 bytes themes/Sugar5/images/view.gif | Bin 0 -> 82 bytes themes/Sugar5/images/view_inline.gif | Bin 0 -> 82 bytes themes/Sugar5/images/view_status.gif | Bin 0 -> 83 bytes themes/Sugar5/images/xls_image_inline.gif | Bin 0 -> 352 bytes themes/Sugar5/images/yellow_camp.gif | Bin 0 -> 1828 bytes themes/Sugar5/images/yes.gif | Bin 0 -> 845 bytes themes/Sugar5/js/style.js | 60 + themes/Sugar5/layout_utils.php | 39 + themes/Sugar5/themedef.php | 46 + themes/Sugar5/tpls/_companyLogo.tpl | 43 + themes/Sugar5/tpls/_globalLinks.tpl | 57 + themes/Sugar5/tpls/_head.tpl | 60 + themes/Sugar5/tpls/_headerLastViewed.tpl | 54 + themes/Sugar5/tpls/_headerModuleList.tpl | 117 + themes/Sugar5/tpls/_headerSearch.tpl | 58 + themes/Sugar5/tpls/_headerShortcuts.tpl | 49 + themes/Sugar5/tpls/_welcome.tpl | 42 + themes/Sugar5/tpls/footer.tpl | 56 + themes/Sugar5/tpls/header.tpl | 62 + themes/default/css/chart.css | 258 + themes/default/css/deprecated.css | 125 + themes/default/css/print.css | 45 + themes/default/css/style.css | 0 themes/default/css/wizard.css | 172 + themes/default/images/Accounts.gif | Bin 0 -> 553 bytes themes/default/images/ActivitiesReports.gif | Bin 0 -> 174 bytes themes/default/images/Administration.gif | Bin 0 -> 325 bytes themes/default/images/AlertEmailTemplates.gif | Bin 0 -> 349 bytes themes/default/images/AllNews.gif | Bin 0 -> 333 bytes themes/default/images/AllRSS.gif | Bin 0 -> 333 bytes themes/default/images/ArrowButtons.png | Bin 0 -> 1499 bytes themes/default/images/Backup.gif | Bin 0 -> 340 bytes themes/default/images/Backups.gif | Bin 0 -> 576 bytes themes/default/images/BugReports.gif | Bin 0 -> 172 bytes themes/default/images/Bugs.gif | Bin 0 -> 214 bytes themes/default/images/Calendar.gif | Bin 0 -> 350 bytes themes/default/images/Calls.gif | Bin 0 -> 547 bytes themes/default/images/Campaigns.gif | Bin 0 -> 559 bytes themes/default/images/CampaignsWizard.gif | Bin 0 -> 353 bytes themes/default/images/Cases.gif | Bin 0 -> 334 bytes themes/default/images/ConfigureSubPanels.gif | Bin 0 -> 343 bytes themes/default/images/ConfigureTabs.gif | Bin 0 -> 563 bytes themes/default/images/Contacts.gif | Bin 0 -> 219 bytes themes/default/images/CreateAccounts.gif | Bin 0 -> 547 bytes themes/default/images/CreateBugs.gif | Bin 0 -> 218 bytes themes/default/images/CreateCalls.gif | Bin 0 -> 343 bytes themes/default/images/CreateCampaigns.gif | Bin 0 -> 562 bytes themes/default/images/CreateCases.gif | Bin 0 -> 336 bytes themes/default/images/CreateContacts.gif | Bin 0 -> 214 bytes themes/default/images/CreateDCEClusters.gif | Bin 0 -> 573 bytes themes/default/images/CreateDCEDataBases.gif | Bin 0 -> 366 bytes themes/default/images/CreateDCEInstances.gif | Bin 0 -> 596 bytes themes/default/images/CreateDCETemplates.gif | Bin 0 -> 569 bytes themes/default/images/CreateDocuments.gif | Bin 0 -> 225 bytes themes/default/images/CreateDropdown.gif | Bin 0 -> 349 bytes themes/default/images/CreateEmails.gif | Bin 0 -> 334 bytes themes/default/images/CreateEmployees.gif | Bin 0 -> 371 bytes themes/default/images/CreateHolidays.gif | Bin 0 -> 375 bytes themes/default/images/CreateKBArticle.gif | Bin 0 -> 236 bytes themes/default/images/CreateLeads.gif | Bin 0 -> 225 bytes themes/default/images/CreateMailboxes.gif | Bin 0 -> 381 bytes themes/default/images/CreateMeetings.gif | Bin 0 -> 343 bytes themes/default/images/CreateNotes.gif | Bin 0 -> 346 bytes themes/default/images/CreateOpportunities.gif | Bin 0 -> 326 bytes themes/default/images/CreateProject.gif | Bin 0 -> 228 bytes themes/default/images/CreateProjectTask.gif | Bin 0 -> 221 bytes .../default/images/CreateProjectTemplate.gif | Bin 0 -> 173 bytes themes/default/images/CreateProspectLists.gif | Bin 0 -> 237 bytes themes/default/images/CreateProspects.gif | Bin 0 -> 223 bytes themes/default/images/CreateQuery.gif | Bin 0 -> 223 bytes themes/default/images/CreateQuotes.gif | Bin 0 -> 230 bytes themes/default/images/CreateRoles.gif | Bin 0 -> 565 bytes themes/default/images/CreateScheduler.gif | Bin 0 -> 360 bytes themes/default/images/CreateTasks.gif | Bin 0 -> 346 bytes themes/default/images/CreateTeams.gif | Bin 0 -> 209 bytes themes/default/images/CreateUsers.gif | Bin 0 -> 346 bytes themes/default/images/CreateWebToLeadForm.gif | Bin 0 -> 240 bytes themes/default/images/CreateiFrames.gif | Bin 0 -> 363 bytes themes/default/images/Currencies.gif | Bin 0 -> 569 bytes themes/default/images/CustomQueries.gif | Bin 0 -> 226 bytes themes/default/images/DCEActions.gif | Bin 0 -> 623 bytes themes/default/images/DCELicensingReport.gif | Bin 0 -> 338 bytes themes/default/images/Dashboard.gif | Bin 0 -> 159 bytes themes/default/images/DataSets.gif | Bin 0 -> 227 bytes themes/default/images/Diagnostic.gif | Bin 0 -> 154 bytes themes/default/images/DocumentRevisions.gif | Bin 0 -> 164 bytes themes/default/images/Documents.gif | Bin 0 -> 223 bytes themes/default/images/Dropdown.gif | Bin 0 -> 549 bytes themes/default/images/EditLayout.gif | Bin 0 -> 353 bytes themes/default/images/EmailDiagnostic.gif | Bin 0 -> 346 bytes themes/default/images/EmailFolder.gif | Bin 0 -> 568 bytes themes/default/images/EmailMan.gif | Bin 0 -> 582 bytes themes/default/images/EmailSetupWizard.gif | Bin 0 -> 360 bytes themes/default/images/EmailTemplates.gif | Bin 0 -> 341 bytes themes/default/images/Emails.gif | Bin 0 -> 341 bytes themes/default/images/Employees.gif | Bin 0 -> 375 bytes themes/default/images/ExportCustomFields.gif | Bin 0 -> 573 bytes themes/default/images/FavoriteReports.gif | Bin 0 -> 928 bytes themes/default/images/Feeds.gif | Bin 0 -> 235 bytes themes/default/images/FieldLabels.gif | Bin 0 -> 560 bytes themes/default/images/Holidays.gif | Bin 0 -> 376 bytes themes/default/images/Import.gif | Bin 0 -> 577 bytes themes/default/images/ImportCustomFields.gif | Bin 0 -> 572 bytes themes/default/images/InboundEmail.gif | Bin 0 -> 377 bytes themes/default/images/KB.gif | Bin 0 -> 173 bytes themes/default/images/KBArticle.gif | Bin 0 -> 170 bytes themes/default/images/KBDocuments.gif | Bin 0 -> 170 bytes themes/default/images/LanguagePacks.gif | Bin 0 -> 170 bytes themes/default/images/Layout.gif | Bin 0 -> 567 bytes themes/default/images/Leads.gif | Bin 0 -> 226 bytes themes/default/images/License.gif | Bin 0 -> 327 bytes themes/default/images/MailboxesTestImport.gif | Bin 0 -> 371 bytes themes/default/images/Manufacturers.gif | Bin 0 -> 322 bytes themes/default/images/MatrixReport.gif | Bin 0 -> 3058 bytes themes/default/images/MatrixReportOver.gif | Bin 0 -> 3322 bytes themes/default/images/Meetings.gif | Bin 0 -> 551 bytes themes/default/images/MigrateFields.gif | Bin 0 -> 576 bytes themes/default/images/ModuleBuilder.gif | Bin 0 -> 363 bytes themes/default/images/ModuleLoader.gif | Bin 0 -> 207 bytes themes/default/images/MoreDetail.png | Bin 0 -> 2844 bytes themes/default/images/MyProject.gif | Bin 0 -> 339 bytes themes/default/images/Newsletters.gif | Bin 0 -> 338 bytes themes/default/images/Notes.gif | Bin 0 -> 560 bytes themes/default/images/OnlineDocumentation.gif | Bin 0 -> 400 bytes themes/default/images/Opportunities.gif | Bin 0 -> 322 bytes themes/default/images/OpportunityReports.gif | Bin 0 -> 165 bytes themes/default/images/Password.gif | Bin 0 -> 188 bytes themes/default/images/PatchUpgrades.gif | Bin 0 -> 333 bytes themes/default/images/Print_Email.gif | Bin 0 -> 585 bytes themes/default/images/ProductTemplates.gif | Bin 0 -> 587 bytes themes/default/images/Product_Types.gif | Bin 0 -> 556 bytes themes/default/images/Project.gif | Bin 0 -> 218 bytes themes/default/images/Project2Weeks.gif | Bin 0 -> 152 bytes themes/default/images/ProjectCollapseAll.gif | Bin 0 -> 96 bytes themes/default/images/ProjectCopy.gif | Bin 0 -> 245 bytes themes/default/images/ProjectCut.gif | Bin 0 -> 87 bytes themes/default/images/ProjectDelete.gif | Bin 0 -> 351 bytes themes/default/images/ProjectExpandAll.gif | Bin 0 -> 101 bytes themes/default/images/ProjectIndent.gif | Bin 0 -> 104 bytes themes/default/images/ProjectInsertRows.gif | Bin 0 -> 83 bytes themes/default/images/ProjectMinus.gif | Bin 0 -> 861 bytes themes/default/images/ProjectMonth.gif | Bin 0 -> 115 bytes themes/default/images/ProjectOutdent.gif | Bin 0 -> 105 bytes themes/default/images/ProjectPaste.gif | Bin 0 -> 609 bytes themes/default/images/ProjectPlus.gif | Bin 0 -> 865 bytes themes/default/images/ProjectSave.gif | Bin 0 -> 343 bytes themes/default/images/ProjectTask.gif | Bin 0 -> 214 bytes themes/default/images/ProjectTemplate.gif | Bin 0 -> 164 bytes themes/default/images/ProjectWeek.gif | Bin 0 -> 154 bytes themes/default/images/ProspectLists.gif | Bin 0 -> 232 bytes themes/default/images/Prospects.gif | Bin 0 -> 216 bytes themes/default/images/QueryBuilder.gif | Bin 0 -> 228 bytes themes/default/images/RSS.gif | Bin 0 -> 235 bytes themes/default/images/ReassignRecords.gif | Bin 0 -> 349 bytes themes/default/images/Rebuild.gif | Bin 0 -> 579 bytes themes/default/images/Rebuild2.gif | Bin 0 -> 590 bytes themes/default/images/Releases.gif | Bin 0 -> 570 bytes themes/default/images/RenameTabs.gif | Bin 0 -> 364 bytes themes/default/images/Repair.gif | Bin 0 -> 144 bytes themes/default/images/Roles.gif | Bin 0 -> 563 bytes themes/default/images/RowsAndColumns.gif | Bin 0 -> 2855 bytes themes/default/images/RowsAndColumnsOver.gif | Bin 0 -> 3046 bytes themes/default/images/SchedulerTest.gif | Bin 0 -> 379 bytes themes/default/images/Schedulers.gif | Bin 0 -> 364 bytes themes/default/images/Search.gif | Bin 0 -> 100 bytes themes/default/images/Shippers.gif | Bin 0 -> 326 bytes themes/default/images/StickyThread.gif | Bin 0 -> 882 bytes themes/default/images/Studio.gif | Bin 0 -> 617 bytes .../images/SugarLogic/icon_bool_16.png | Bin 0 -> 1328 bytes .../images/SugarLogic/icon_date_16.png | Bin 0 -> 1257 bytes .../images/SugarLogic/icon_enum_16.png | Bin 0 -> 1179 bytes .../images/SugarLogic/icon_generic_16.png | Bin 0 -> 1212 bytes .../default/images/SugarLogic/icon_num_16.png | Bin 0 -> 1267 bytes .../images/SugarLogic/icon_string_16.png | Bin 0 -> 1229 bytes themes/default/images/SugarPortal.gif | Bin 0 -> 366 bytes themes/default/images/Summation.gif | Bin 0 -> 2685 bytes themes/default/images/SummationOver.gif | Bin 0 -> 3064 bytes .../default/images/SummationWithDetails.gif | Bin 0 -> 2596 bytes .../images/SummationWithDetailsOver.gif | Bin 0 -> 3121 bytes themes/default/images/Support.gif | Bin 0 -> 385 bytes themes/default/images/Tasks.gif | Bin 0 -> 352 bytes themes/default/images/Teams.gif | Bin 0 -> 148 bytes themes/default/images/Themes.gif | Bin 0 -> 1016 bytes themes/default/images/Trackers.gif | Bin 0 -> 609 bytes themes/default/images/Upgrade.gif | Bin 0 -> 203 bytes themes/default/images/UpgradeDCEInstances.gif | Bin 0 -> 203 bytes themes/default/images/Users.gif | Bin 0 -> 343 bytes themes/default/images/WorkFlow.gif | Bin 0 -> 215 bytes themes/default/images/_blank.png | Bin 0 -> 137 bytes themes/default/images/accept_inline.gif | Bin 0 -> 101 bytes themes/default/images/advanced_search.gif | Bin 0 -> 62 bytes themes/default/images/arrow.gif | Bin 0 -> 64 bytes themes/default/images/arrow_down.gif | Bin 0 -> 81 bytes themes/default/images/arrow_up.gif | Bin 0 -> 79 bytes themes/default/images/attachment.gif | Bin 0 -> 94 bytes themes/default/images/backtotop.gif | Bin 0 -> 124 bytes themes/default/images/bar_loader.gif | Bin 0 -> 10819 bytes themes/default/images/basic_search.gif | Bin 0 -> 62 bytes themes/default/images/bg.gif | Bin 0 -> 90 bytes themes/default/images/bgBlue.gif | Bin 0 -> 90 bytes themes/default/images/bgBtn.gif | Bin 0 -> 93 bytes themes/default/images/bgBtnBlue.gif | Bin 0 -> 93 bytes themes/default/images/bgBtnGray.gif | Bin 0 -> 68 bytes themes/default/images/bgBtnGreen.gif | Bin 0 -> 93 bytes themes/default/images/bgBtnOrange.gif | Bin 0 -> 92 bytes themes/default/images/bgBtnPurple.gif | Bin 0 -> 92 bytes themes/default/images/bgGray.gif | Bin 0 -> 57 bytes themes/default/images/bgGreen.gif | Bin 0 -> 808 bytes themes/default/images/bgOcher.gif | Bin 0 -> 90 bytes themes/default/images/bgPurple.gif | Bin 0 -> 90 bytes themes/default/images/bgRed.gif | Bin 0 -> 65 bytes themes/default/images/blank.gif | Bin 0 -> 43 bytes themes/default/images/calendarHeaderBg.gif | Bin 0 -> 155 bytes themes/default/images/calendar_next.gif | Bin 0 -> 67 bytes themes/default/images/calendar_previous.gif | Bin 0 -> 65 bytes themes/default/images/chartBg.png | Bin 0 -> 583 bytes themes/default/images/check_inline.gif | Bin 0 -> 102 bytes themes/default/images/close.gif | Bin 0 -> 83 bytes themes/default/images/close_button_24.png | Bin 0 -> 1224 bytes themes/default/images/close_inline.gif | Bin 0 -> 103 bytes themes/default/images/colors.blue.icon.gif | Bin 0 -> 89 bytes themes/default/images/colors.gray.icon.gif | Bin 0 -> 62 bytes themes/default/images/colors.green.icon.gif | Bin 0 -> 89 bytes themes/default/images/colors.orange.icon.gif | Bin 0 -> 89 bytes themes/default/images/colors.purple.icon.gif | Bin 0 -> 89 bytes themes/default/images/colors.red.icon.gif | Bin 0 -> 70 bytes themes/default/images/colors.sugar.icon.gif | Bin 0 -> 89 bytes themes/default/images/company_logo.png | Bin 0 -> 2068 bytes themes/default/images/create-record.gif | Bin 0 -> 1437 bytes themes/default/images/currentTab.gif | Bin 0 -> 1002 bytes themes/default/images/currentTab.png | Bin 0 -> 4661 bytes themes/default/images/currentTabBlue.gif | Bin 0 -> 993 bytes themes/default/images/currentTabGray.gif | Bin 0 -> 993 bytes themes/default/images/currentTabGreen.gif | Bin 0 -> 993 bytes themes/default/images/currentTabLinkBg.gif | Bin 0 -> 108 bytes themes/default/images/currentTabOcher.gif | Bin 0 -> 993 bytes themes/default/images/currentTabOff.gif | Bin 0 -> 764 bytes themes/default/images/currentTabPurple.gif | Bin 0 -> 993 bytes themes/default/images/currentTabRed.gif | Bin 0 -> 1006 bytes .../default/images/dashlet-header-close.gif | Bin 0 -> 68 bytes themes/default/images/dashlet-header-edit.gif | Bin 0 -> 69 bytes .../default/images/dashlet-header-refresh.gif | Bin 0 -> 70 bytes themes/default/images/dcMenuDivider.png | Bin 0 -> 215 bytes themes/default/images/dce_Settings.gif | Bin 0 -> 338 bytes themes/default/images/dcmenugrade.png | Bin 0 -> 194 bytes themes/default/images/decline_inline.gif | Bin 0 -> 102 bytes themes/default/images/def_image_inline.gif | Bin 0 -> 587 bytes themes/default/images/delete.gif | Bin 0 -> 69 bytes themes/default/images/delete_inline.gif | Bin 0 -> 66 bytes themes/default/images/detailViewBg.gif | Bin 0 -> 262 bytes themes/default/images/detailview.gif | Bin 0 -> 355 bytes themes/default/images/doc_image_inline.gif | Bin 0 -> 353 bytes themes/default/images/downarrow.gif | Bin 0 -> 66 bytes themes/default/images/downarrow_big.gif | Bin 0 -> 74 bytes themes/default/images/downarrow_inline.gif | Bin 0 -> 80 bytes themes/default/images/dp-bd-dc.png | Bin 0 -> 109 bytes themes/default/images/dp-bd-menu.png | Bin 0 -> 109 bytes themes/default/images/dp-bd-top-menu.png | Bin 0 -> 183 bytes themes/default/images/dp-bd.png | Bin 0 -> 109 bytes themes/default/images/dp-bl-dc.png | Bin 0 -> 430 bytes themes/default/images/dp-bl-menu.png | Bin 0 -> 429 bytes themes/default/images/dp-bl.png | Bin 0 -> 366 bytes themes/default/images/dp-br-dc.png | Bin 0 -> 498 bytes themes/default/images/dp-br-menu.png | Bin 0 -> 485 bytes themes/default/images/dp-br.png | Bin 0 -> 360 bytes themes/default/images/dp-ft-dc.png | Bin 0 -> 154 bytes themes/default/images/dp-ft-menu.png | Bin 0 -> 139 bytes themes/default/images/dp-ft.png | Bin 0 -> 159 bytes themes/default/images/dp-hd-dc.png | Bin 0 -> 201 bytes themes/default/images/dp-hd-menu.png | Bin 0 -> 120 bytes themes/default/images/dp-hd-plain.png | Bin 0 -> 182 bytes themes/default/images/dp-hd.png | Bin 0 -> 140 bytes themes/default/images/dp-ml-dc.png | Bin 0 -> 123 bytes themes/default/images/dp-ml-menu.png | Bin 0 -> 123 bytes themes/default/images/dp-ml.png | Bin 0 -> 125 bytes themes/default/images/dp-mr-dc.png | Bin 0 -> 137 bytes themes/default/images/dp-mr-menu.png | Bin 0 -> 134 bytes themes/default/images/dp-mr.png | Bin 0 -> 128 bytes themes/default/images/dp-tl-dc.png | Bin 0 -> 332 bytes themes/default/images/dp-tl-menu.png | Bin 0 -> 260 bytes themes/default/images/dp-tl-plain.png | Bin 0 -> 355 bytes themes/default/images/dp-tl.png | Bin 0 -> 417 bytes themes/default/images/dp-tr-dc.png | Bin 0 -> 414 bytes themes/default/images/dp-tr-menu.png | Bin 0 -> 436 bytes themes/default/images/dp-tr-plain.png | Bin 0 -> 395 bytes themes/default/images/dp-tr.png | Bin 0 -> 473 bytes themes/default/images/edit_inline.gif | Bin 0 -> 83 bytes themes/default/images/edit_wizard.gif | Bin 0 -> 82 bytes themes/default/images/editfields.gif | Bin 0 -> 560 bytes themes/default/images/editlabels.gif | Bin 0 -> 353 bytes themes/default/images/editview.gif | Bin 0 -> 353 bytes themes/default/images/emptyTabSpace.gif | Bin 0 -> 430 bytes themes/default/images/end.gif | Bin 0 -> 95 bytes themes/default/images/end_off.gif | Bin 0 -> 75 bytes themes/default/images/export.gif | Bin 0 -> 78 bytes themes/default/images/fonts.larger.icon.gif | Bin 0 -> 135 bytes themes/default/images/fonts.largest.icon.gif | Bin 0 -> 144 bytes themes/default/images/fonts.normal.icon.gif | Bin 0 -> 127 bytes themes/default/images/form-button-bg.png | Bin 0 -> 166 bytes themes/default/images/form-button-bg2.png | Bin 0 -> 3545 bytes .../default/images/form-button-primary-bg.png | Bin 0 -> 203 bytes themes/default/images/formButtonBg.gif | Bin 0 -> 93 bytes themes/default/images/formButtonBgOn.gif | Bin 0 -> 67 bytes themes/default/images/getLatestDocument.gif | Bin 0 -> 81 bytes themes/default/images/green_camp.gif | Bin 0 -> 1829 bytes themes/default/images/grouped-menu-arrow.png | Bin 0 -> 320 bytes themes/default/images/grouped-menu.png | Bin 0 -> 340 bytes themes/default/images/h3Arrow.gif | Bin 0 -> 64 bytes themes/default/images/help-dashlet.gif | Bin 0 -> 66 bytes themes/default/images/help.gif | Bin 0 -> 66 bytes themes/default/images/helpInline.gif | Bin 0 -> 153 bytes themes/default/images/hide.gif | Bin 0 -> 223 bytes .../default/images/hide_submenu_shortcuts.gif | Bin 0 -> 74 bytes themes/default/images/iFrames.gif | Bin 0 -> 338 bytes themes/default/images/icon_A1_newmod.gif | Bin 0 -> 2201 bytes themes/default/images/icon_Accounts.gif | Bin 0 -> 2053 bytes themes/default/images/icon_Accounts_32.gif | Bin 0 -> 955 bytes themes/default/images/icon_Activities.gif | Bin 0 -> 2304 bytes themes/default/images/icon_Address.gif | Bin 0 -> 160 bytes themes/default/images/icon_AdminMobile.gif | Bin 0 -> 333 bytes themes/default/images/icon_AdminPDF.gif | Bin 0 -> 248 bytes themes/default/images/icon_AdminThemes.gif | Bin 0 -> 340 bytes themes/default/images/icon_AdvancedSearch.gif | Bin 0 -> 2518 bytes themes/default/images/icon_Application.gif | Bin 0 -> 5631 bytes themes/default/images/icon_BasicSearch.gif | Bin 0 -> 2561 bytes themes/default/images/icon_Bugs.gif | Bin 0 -> 2052 bytes themes/default/images/icon_Bugs_32.gif | Bin 0 -> 995 bytes themes/default/images/icon_Calendar_32.gif | Bin 0 -> 1683 bytes themes/default/images/icon_Calls.gif | Bin 0 -> 1905 bytes themes/default/images/icon_Calls_32.gif | Bin 0 -> 990 bytes themes/default/images/icon_CampaignLog_32.gif | Bin 0 -> 1120 bytes themes/default/images/icon_Campaigns.gif | Bin 0 -> 2342 bytes themes/default/images/icon_Campaigns_32.gif | Bin 0 -> 1120 bytes themes/default/images/icon_Cases.gif | Bin 0 -> 2060 bytes themes/default/images/icon_Cases_32.gif | Bin 0 -> 976 bytes themes/default/images/icon_Charts_Funnel.gif | Bin 0 -> 2031 bytes .../default/images/icon_Charts_Funnel_32.gif | Bin 0 -> 697 bytes .../default/images/icon_Charts_Gauge_32.gif | Bin 0 -> 738 bytes themes/default/images/icon_Charts_GroupBy.gif | Bin 0 -> 2150 bytes .../default/images/icon_Charts_GroupBy_32.gif | Bin 0 -> 764 bytes .../default/images/icon_Charts_Horizontal.gif | Bin 0 -> 2113 bytes .../images/icon_Charts_Horizontal_32.gif | Bin 0 -> 800 bytes themes/default/images/icon_Charts_Pie.gif | Bin 0 -> 2223 bytes themes/default/images/icon_Charts_Pie_32.gif | Bin 0 -> 794 bytes .../default/images/icon_Charts_Vertical.gif | Bin 0 -> 2131 bytes .../images/icon_Charts_Vertical_32.gif | Bin 0 -> 799 bytes themes/default/images/icon_Column_1.gif | Bin 0 -> 1971 bytes themes/default/images/icon_Column_2.gif | Bin 0 -> 2082 bytes themes/default/images/icon_Column_3.gif | Bin 0 -> 2186 bytes .../default/images/icon_ConnectorConfig.gif | Bin 0 -> 4560 bytes .../images/icon_ConnectorConfigOver.gif | Bin 0 -> 4743 bytes .../images/icon_ConnectorConfig_16.gif | Bin 0 -> 622 bytes .../default/images/icon_ConnectorEnable.gif | Bin 0 -> 4476 bytes .../images/icon_ConnectorEnableOver.gif | Bin 0 -> 4593 bytes .../images/icon_ConnectorEnable_16.gif | Bin 0 -> 382 bytes themes/default/images/icon_ConnectorMap.gif | Bin 0 -> 4577 bytes .../default/images/icon_ConnectorMapOver.gif | Bin 0 -> 4797 bytes .../default/images/icon_ConnectorMap_16.gif | Bin 0 -> 594 bytes .../images/icon_ConnectorSearchFields.gif | Bin 0 -> 4548 bytes .../images/icon_ConnectorSearchFieldsOver.gif | Bin 0 -> 4656 bytes .../images/icon_ConnectorSearchFields_16.gif | Bin 0 -> 618 bytes themes/default/images/icon_Connectors.gif | Bin 0 -> 600 bytes themes/default/images/icon_Contacts.gif | Bin 0 -> 1953 bytes themes/default/images/icon_Contacts_32.gif | Bin 0 -> 971 bytes themes/default/images/icon_Contracts_32.gif | Bin 0 -> 762 bytes themes/default/images/icon_ConvertLead.gif | Bin 0 -> 2505 bytes themes/default/images/icon_Dashlet.gif | Bin 0 -> 1435 bytes themes/default/images/icon_Delete.gif | Bin 0 -> 2263 bytes themes/default/images/icon_DeleteFull.gif | Bin 0 -> 2340 bytes themes/default/images/icon_DetailView.gif | Bin 0 -> 1837 bytes themes/default/images/icon_Documents.gif | Bin 0 -> 2054 bytes themes/default/images/icon_Documents_32.gif | Bin 0 -> 1009 bytes themes/default/images/icon_DropDownEditor.gif | Bin 0 -> 3202 bytes themes/default/images/icon_EditView.gif | Bin 0 -> 1903 bytes themes/default/images/icon_EmailAddress.gif | Bin 0 -> 327 bytes .../default/images/icon_EmailAddresses_32.gif | Bin 0 -> 853 bytes .../default/images/icon_EmailTemplates_32.gif | Bin 0 -> 859 bytes themes/default/images/icon_Emails.gif | Bin 0 -> 1873 bytes themes/default/images/icon_Emails_32.gif | Bin 0 -> 859 bytes .../images/icon_FavoriteReports_32.gif | Bin 0 -> 779 bytes themes/default/images/icon_Feeds_32.gif | Bin 0 -> 1240 bytes themes/default/images/icon_Fields.gif | Bin 0 -> 1966 bytes themes/default/images/icon_Forecasts_32.gif | Bin 0 -> 1031 bytes themes/default/images/icon_Invaders_32.gif | Bin 0 -> 1256 bytes themes/default/images/icon_JotPad.gif | Bin 0 -> 2304 bytes themes/default/images/icon_JotPad_32.gif | Bin 0 -> 845 bytes themes/default/images/icon_KBDocuments.gif | Bin 0 -> 2145 bytes themes/default/images/icon_KBDocuments_32.gif | Bin 0 -> 1044 bytes themes/default/images/icon_Labels.gif | Bin 0 -> 2009 bytes themes/default/images/icon_Layouts.gif | Bin 0 -> 2099 bytes themes/default/images/icon_Leads.gif | Bin 0 -> 2513 bytes themes/default/images/icon_Leads_32.gif | Bin 0 -> 1180 bytes themes/default/images/icon_ListView.gif | Bin 0 -> 2019 bytes themes/default/images/icon_Meetings.gif | Bin 0 -> 2484 bytes themes/default/images/icon_Meetings_32.gif | Bin 0 -> 1140 bytes themes/default/images/icon_MobileLayouts.gif | Bin 0 -> 2244 bytes themes/default/images/icon_ModuleBuilder.gif | Bin 0 -> 4427 bytes themes/default/images/icon_MyPortal_32.gif | Bin 0 -> 1042 bytes themes/default/images/icon_MyTasks_32.gif | Bin 0 -> 929 bytes themes/default/images/icon_NewModule.gif | Bin 0 -> 2241 bytes themes/default/images/icon_Notes.gif | Bin 0 -> 2178 bytes themes/default/images/icon_Notes_32.gif | Bin 0 -> 1067 bytes themes/default/images/icon_OpenTasks_32.gif | Bin 0 -> 939 bytes themes/default/images/icon_Opportunities.gif | Bin 0 -> 2081 bytes .../default/images/icon_Opportunities_32.gif | Bin 0 -> 1026 bytes themes/default/images/icon_Phone.gif | Bin 0 -> 344 bytes themes/default/images/icon_Popup.gif | Bin 0 -> 2348 bytes themes/default/images/icon_Portal.gif | Bin 0 -> 2099 bytes .../images/icon_ProductCategories_32.gif | Bin 0 -> 965 bytes .../default/images/icon_ProductTypes_32.gif | Bin 0 -> 1081 bytes .../default/images/icon_Product_Types_32.gif | Bin 0 -> 1081 bytes themes/default/images/icon_Products_32.gif | Bin 0 -> 1055 bytes themes/default/images/icon_Project.gif | Bin 0 -> 1732 bytes themes/default/images/icon_ProjectTask.gif | Bin 0 -> 1758 bytes themes/default/images/icon_ProjectTask_32.gif | Bin 0 -> 876 bytes themes/default/images/icon_Project_32.gif | Bin 0 -> 850 bytes themes/default/images/icon_Projects_32.gif | Bin 0 -> 850 bytes themes/default/images/icon_Prospects.gif | Bin 0 -> 1795 bytes themes/default/images/icon_Prospects_32.gif | Bin 0 -> 881 bytes themes/default/images/icon_QuickCreate.gif | Bin 0 -> 1806 bytes themes/default/images/icon_Quotes_32.gif | Bin 0 -> 1157 bytes themes/default/images/icon_Relationships.gif | Bin 0 -> 1416 bytes themes/default/images/icon_Releases_32.gif | Bin 0 -> 919 bytes themes/default/images/icon_Reports_32.gif | Bin 0 -> 1020 bytes themes/default/images/icon_Rss_32.gif | Bin 0 -> 1240 bytes themes/default/images/icon_SPSync.gif | Bin 0 -> 2170 bytes themes/default/images/icon_SPUploadCSS.gif | Bin 0 -> 2034 bytes themes/default/images/icon_SearchForm.gif | Bin 0 -> 1993 bytes themes/default/images/icon_ShortcutBar.gif | Bin 0 -> 161 bytes themes/default/images/icon_Studio.gif | Bin 0 -> 4786 bytes themes/default/images/icon_Subpanels.gif | Bin 0 -> 1921 bytes themes/default/images/icon_SugarFeed.gif | Bin 0 -> 225 bytes themes/default/images/icon_SugarFeed_32.gif | Bin 0 -> 1337 bytes themes/default/images/icon_SugarNews_32.gif | Bin 0 -> 904 bytes themes/default/images/icon_SugarPortal.gif | Bin 0 -> 4229 bytes themes/default/images/icon_Targets_32.gif | Bin 0 -> 881 bytes themes/default/images/icon_Tasks.gif | Bin 0 -> 1884 bytes themes/default/images/icon_Tasks_32.gif | Bin 0 -> 860 bytes themes/default/images/icon_Teams_32.gif | Bin 0 -> 950 bytes .../default/images/icon_TrackerPerfs_32.gif | Bin 0 -> 982 bytes .../default/images/icon_TrackerQueries_32.gif | Bin 0 -> 987 bytes .../images/icon_TrackerSessions_32.gif | Bin 0 -> 1009 bytes themes/default/images/icon_Trackers_32.gif | Bin 0 -> 984 bytes themes/default/images/icon_Users_32.gif | Bin 0 -> 1081 bytes themes/default/images/icon_assistant.gif | Bin 0 -> 582 bytes themes/default/images/icon_back.gif | Bin 0 -> 538 bytes themes/default/images/icon_basic.gif | Bin 0 -> 2201 bytes themes/default/images/icon_company.gif | Bin 0 -> 2315 bytes themes/default/images/icon_document.gif | Bin 0 -> 2364 bytes .../default/images/icon_email_addressbook.gif | Bin 0 -> 594 bytes themes/default/images/icon_email_archive.gif | Bin 0 -> 372 bytes themes/default/images/icon_email_assign.gif | Bin 0 -> 578 bytes themes/default/images/icon_email_attach.gif | Bin 0 -> 331 bytes themes/default/images/icon_email_check.gif | Bin 0 -> 580 bytes themes/default/images/icon_email_compose.gif | Bin 0 -> 364 bytes themes/default/images/icon_email_create.gif | Bin 0 -> 332 bytes themes/default/images/icon_email_delete.gif | Bin 0 -> 341 bytes themes/default/images/icon_email_folder.gif | Bin 0 -> 1928 bytes .../images/icon_email_folder_archives.gif | Bin 0 -> 353 bytes .../images/icon_email_folder_drafts.gif | Bin 0 -> 609 bytes .../default/images/icon_email_folder_exp.gif | Bin 0 -> 1928 bytes .../default/images/icon_email_folder_grp.gif | Bin 0 -> 1935 bytes .../default/images/icon_email_folder_sent.gif | Bin 0 -> 619 bytes themes/default/images/icon_email_forward.gif | Bin 0 -> 594 bytes .../default/images/icon_email_fullscreen.gif | Bin 0 -> 178 bytes themes/default/images/icon_email_mark.gif | Bin 0 -> 355 bytes themes/default/images/icon_email_options.gif | Bin 0 -> 111 bytes themes/default/images/icon_email_relate.gif | Bin 0 -> 354 bytes themes/default/images/icon_email_reply.gif | Bin 0 -> 579 bytes themes/default/images/icon_email_replyall.gif | Bin 0 -> 379 bytes themes/default/images/icon_email_save.gif | Bin 0 -> 361 bytes themes/default/images/icon_email_send.gif | Bin 0 -> 580 bytes themes/default/images/icon_email_settings.gif | Bin 0 -> 601 bytes .../default/images/icon_email_sugfolder.gif | Bin 0 -> 1940 bytes .../images/icon_email_sugfolder_exp.gif | Bin 0 -> 1927 bytes themes/default/images/icon_email_view.gif | Bin 0 -> 213 bytes themes/default/images/icon_email_view1.gif | Bin 0 -> 122 bytes themes/default/images/icon_email_view2.gif | Bin 0 -> 118 bytes themes/default/images/icon_email_view3.gif | Bin 0 -> 340 bytes .../default/images/icon_expression_types.gif | Bin 0 -> 324 bytes themes/default/images/icon_file.gif | Bin 0 -> 1727 bytes themes/default/images/icon_home.gif | Bin 0 -> 353 bytes themes/default/images/icon_iFrames_32.gif | Bin 0 -> 1042 bytes themes/default/images/icon_issue.gif | Bin 0 -> 2325 bytes themes/default/images/icon_new_package.gif | Bin 0 -> 6599 bytes themes/default/images/icon_opportunity.gif | Bin 0 -> 2273 bytes themes/default/images/icon_package.gif | Bin 0 -> 5677 bytes themes/default/images/icon_package_create.gif | Bin 0 -> 6599 bytes themes/default/images/icon_person.gif | Bin 0 -> 2311 bytes themes/default/images/icon_sale.gif | Bin 0 -> 1682 bytes themes/default/images/icon_therevisions.gif | Bin 0 -> 2054 bytes themes/default/images/id-ff-add.png | Bin 0 -> 220 bytes themes/default/images/id-ff-clear.png | Bin 0 -> 489 bytes themes/default/images/id-ff-copy.png | Bin 0 -> 277 bytes themes/default/images/id-ff-remove.png | Bin 0 -> 404 bytes themes/default/images/id-ff-select.png | Bin 0 -> 3077 bytes themes/default/images/id-ff-vcard.png | Bin 0 -> 192 bytes themes/default/images/img_close_search.gif | Bin 0 -> 118 bytes themes/default/images/img_left_arrow.jpg | Bin 0 -> 849 bytes themes/default/images/img_loading.gif | Bin 0 -> 771 bytes themes/default/images/img_right_arrow.jpg | Bin 0 -> 835 bytes themes/default/images/info-add.gif | Bin 0 -> 82 bytes themes/default/images/info-help.gif | Bin 0 -> 66 bytes themes/default/images/info-layout.gif | Bin 0 -> 83 bytes themes/default/images/info_inline.gif | Bin 0 -> 79 bytes themes/default/images/join_imeeting.gif | Bin 0 -> 118 bytes themes/default/images/join_meeting_inline.png | Bin 0 -> 600 bytes themes/default/images/jscalendar.gif | Bin 0 -> 221 bytes themes/default/images/leftarrow.gif | Bin 0 -> 74 bytes themes/default/images/leftarrow_big.gif | Bin 0 -> 74 bytes themes/default/images/line.gif | Bin 0 -> 1839 bytes themes/default/images/list.gif | Bin 0 -> 352 bytes themes/default/images/listViewBg.gif | Bin 0 -> 147 bytes themes/default/images/listViewHR.gif | Bin 0 -> 43 bytes themes/default/images/loadSignedDocument.gif | Bin 0 -> 82 bytes themes/default/images/loading.gif | Bin 0 -> 1787 bytes themes/default/images/login-bg.png | Bin 0 -> 156 bytes themes/default/images/mass_update.gif | Bin 0 -> 91 bytes themes/default/images/menuarrow.gif | Bin 0 -> 60 bytes themes/default/images/minus.gif | Bin 0 -> 197 bytes themes/default/images/minus_inline.gif | Bin 0 -> 76 bytes themes/default/images/more.gif | Bin 0 -> 58 bytes themes/default/images/new_inline.gif | Bin 0 -> 1437 bytes themes/default/images/next.gif | Bin 0 -> 81 bytes themes/default/images/next_off.gif | Bin 0 -> 64 bytes themes/default/images/no.gif | Bin 0 -> 72 bytes themes/default/images/open_multiple.gif | Bin 0 -> 371 bytes themes/default/images/otherTab.gif | Bin 0 -> 841 bytes themes/default/images/otherTab.png | Bin 0 -> 166 bytes themes/default/images/otherTabBlue.gif | Bin 0 -> 841 bytes themes/default/images/otherTabGray.gif | Bin 0 -> 841 bytes themes/default/images/otherTabGreen.gif | Bin 0 -> 841 bytes themes/default/images/otherTabOcher.gif | Bin 0 -> 841 bytes themes/default/images/otherTabPurple.gif | Bin 0 -> 841 bytes themes/default/images/otherTabRed.gif | Bin 0 -> 841 bytes .../images/pdf_header_logo_SugarCRMheader.jpg | Bin 0 -> 78771 bytes .../images/pdf_header_logo_company_logo.png | Bin 0 -> 2231 bytes .../images/pdf_header_logo_img_left_arrow.jpg | Bin 0 -> 849 bytes ...er_logo_pdf_header_logo_SugarCRMheader.jpg | Bin 0 -> 78651 bytes themes/default/images/pdf_image_inline.gif | Bin 0 -> 588 bytes themes/default/images/pdf_logo.jpg | Bin 0 -> 35792 bytes themes/default/images/pdf_logo_small.jpg | Bin 0 -> 8236 bytes themes/default/images/plug-in_Excel.gif | Bin 0 -> 2625 bytes themes/default/images/plug-in_Outlook.gif | Bin 0 -> 2653 bytes themes/default/images/plug-in_Word.gif | Bin 0 -> 2735 bytes themes/default/images/plus.gif | Bin 0 -> 313 bytes themes/default/images/plus_inline.gif | Bin 0 -> 82 bytes themes/default/images/ppt_image_inline.gif | Bin 0 -> 349 bytes themes/default/images/previous.gif | Bin 0 -> 79 bytes themes/default/images/previous_off.gif | Bin 0 -> 63 bytes themes/default/images/print.gif | Bin 0 -> 68 bytes themes/default/images/publish_inline.gif | Bin 0 -> 80 bytes themes/default/images/red_camp.gif | Bin 0 -> 1944 bytes themes/default/images/rightarrow.gif | Bin 0 -> 75 bytes themes/default/images/rightarrow_big.gif | Bin 0 -> 75 bytes themes/default/images/scheduled_inline.gif | Bin 0 -> 84 bytes themes/default/images/searchMore.gif | Bin 0 -> 105 bytes themes/default/images/shortCutsBg.png | Bin 0 -> 152 bytes themes/default/images/show.gif | Bin 0 -> 158 bytes .../default/images/show_submenu_shortcuts.gif | Bin 0 -> 76 bytes themes/default/images/slot.gif | Bin 0 -> 202 bytes themes/default/images/spacer.gif | Bin 0 -> 49 bytes themes/default/images/sqsWait.gif | Bin 0 -> 849 bytes themes/default/images/start.gif | Bin 0 -> 94 bytes .../default/images/start_meeting_inline.png | Bin 0 -> 579 bytes themes/default/images/start_off.gif | Bin 0 -> 74 bytes themes/default/images/studio_addField.gif | Bin 0 -> 331 bytes themes/default/images/studio_addRows.gif | Bin 0 -> 323 bytes themes/default/images/studio_blank.gif | Bin 0 -> 328 bytes themes/default/images/studio_history.gif | Bin 0 -> 328 bytes themes/default/images/studio_publish.gif | Bin 0 -> 335 bytes themes/default/images/studio_redo.gif | Bin 0 -> 304 bytes themes/default/images/studio_save.gif | Bin 0 -> 306 bytes themes/default/images/studio_undo.gif | Bin 0 -> 330 bytes .../default/images/sugar-yui-sprites-grey.png | Bin 0 -> 2833 bytes themes/default/images/sugarColors.xml | 144 + themes/default/images/sugar_document.png | Bin 0 -> 601 bytes themes/default/images/sugar_icon.ico | Bin 0 -> 894 bytes themes/default/images/sugar_icon.png | Bin 0 -> 2641 bytes themes/default/images/sugarupdate.gif | Bin 0 -> 200 bytes themes/default/images/tabRowBlueBg.gif | Bin 0 -> 99 bytes themes/default/images/tabRowGrayBg.gif | Bin 0 -> 99 bytes themes/default/images/tabRowGreenBg.gif | Bin 0 -> 99 bytes themes/default/images/tabRowOcherBg.gif | Bin 0 -> 99 bytes themes/default/images/tabRowPurpleBg.gif | Bin 0 -> 99 bytes themes/default/images/tabRowRedBg.gif | Bin 0 -> 99 bytes themes/default/images/tentative_inline.gif | Bin 0 -> 97 bytes themes/default/images/themePreview.png | Bin 0 -> 5862 bytes themes/default/images/txt_image_inline.gif | Bin 0 -> 554 bytes themes/default/images/unpublish_inline.gif | Bin 0 -> 82 bytes themes/default/images/unscheduled_inline.gif | Bin 0 -> 84 bytes themes/default/images/uparrow.gif | Bin 0 -> 66 bytes themes/default/images/uparrow_big.gif | Bin 0 -> 66 bytes themes/default/images/uparrow_inline.gif | Bin 0 -> 79 bytes themes/default/images/view.gif | Bin 0 -> 82 bytes themes/default/images/view_inline.gif | Bin 0 -> 82 bytes themes/default/images/view_status.gif | Bin 0 -> 83 bytes themes/default/images/xls_image_inline.gif | Bin 0 -> 352 bytes themes/default/images/yellow_camp.gif | Bin 0 -> 1828 bytes themes/default/images/yes.gif | Bin 0 -> 845 bytes themes/default/js/style.js | 37 + vCard.php | 61 + vcal_server.php | 48 + 5776 files changed, 1110106 insertions(+) create mode 100644 HandleAjaxCall.php create mode 100644 LICENSE.txt create mode 100644 ModuleInstall/ModuleInstaller.php create mode 100644 ModuleInstall/ModuleScanner.php create mode 100644 ModuleInstall/PackageManager/ListViewPackages.php create mode 100644 ModuleInstall/PackageManager/PackageController.php create mode 100644 ModuleInstall/PackageManager/PackageManager.php create mode 100644 ModuleInstall/PackageManager/PackageManagerComm.php create mode 100644 ModuleInstall/PackageManager/PackageManagerDisplay.php create mode 100644 ModuleInstall/PackageManager/PackageManagerDownloader.php create mode 100644 ModuleInstall/PackageManager/metadata/listviewdefs.php create mode 100644 ModuleInstall/PackageManager/tpls/ModuleLoaderListView.tpl create mode 100644 ModuleInstall/PackageManager/tpls/PackageForm.tpl create mode 100644 ModuleInstall/PackageManager/tpls/PackageManagerLicense.tpl create mode 100644 ModuleInstall/PackageManager/tpls/PackageManagerScripts.tpl create mode 100644 SugarSecurity.php create mode 100644 TreeData.php create mode 100644 WebToLeadCapture.php create mode 100644 XTemplate/LICENSE create mode 100644 XTemplate/xtpl.php create mode 100644 Zend/Crypt.php create mode 100644 Zend/Crypt/DiffieHellman.php create mode 100644 Zend/Crypt/DiffieHellman/Exception.php create mode 100644 Zend/Crypt/Exception.php create mode 100644 Zend/Crypt/Hmac.php create mode 100644 Zend/Crypt/Hmac/Exception.php create mode 100644 Zend/Crypt/Math.php create mode 100644 Zend/Crypt/Math/BigInteger.php create mode 100644 Zend/Crypt/Math/BigInteger/Bcmath.php create mode 100644 Zend/Crypt/Math/BigInteger/Exception.php create mode 100644 Zend/Crypt/Math/BigInteger/Gmp.php create mode 100644 Zend/Crypt/Math/BigInteger/Interface.php create mode 100644 Zend/Crypt/Math/Exception.php create mode 100644 Zend/Crypt/Rsa.php create mode 100644 Zend/Crypt/Rsa/Key.php create mode 100644 Zend/Crypt/Rsa/Key/Private.php create mode 100644 Zend/Crypt/Rsa/Key/Public.php create mode 100644 Zend/Exception.php create mode 100644 Zend/Gdata.php create mode 100644 Zend/Gdata/App.php create mode 100644 Zend/Gdata/App/AuthException.php create mode 100644 Zend/Gdata/App/BadMethodCallException.php create mode 100644 Zend/Gdata/App/Base.php create mode 100644 Zend/Gdata/App/BaseMediaSource.php create mode 100644 Zend/Gdata/App/CaptchaRequiredException.php create mode 100644 Zend/Gdata/App/Entry.php create mode 100644 Zend/Gdata/App/Exception.php create mode 100644 Zend/Gdata/App/Extension.php create mode 100644 Zend/Gdata/App/Extension/Author.php create mode 100644 Zend/Gdata/App/Extension/Category.php create mode 100644 Zend/Gdata/App/Extension/Content.php create mode 100644 Zend/Gdata/App/Extension/Contributor.php create mode 100644 Zend/Gdata/App/Extension/Control.php create mode 100644 Zend/Gdata/App/Extension/Draft.php create mode 100644 Zend/Gdata/App/Extension/Edited.php create mode 100644 Zend/Gdata/App/Extension/Element.php create mode 100644 Zend/Gdata/App/Extension/Email.php create mode 100644 Zend/Gdata/App/Extension/Generator.php create mode 100644 Zend/Gdata/App/Extension/Icon.php create mode 100644 Zend/Gdata/App/Extension/Id.php create mode 100644 Zend/Gdata/App/Extension/Link.php create mode 100644 Zend/Gdata/App/Extension/Logo.php create mode 100644 Zend/Gdata/App/Extension/Name.php create mode 100644 Zend/Gdata/App/Extension/Person.php create mode 100644 Zend/Gdata/App/Extension/Published.php create mode 100644 Zend/Gdata/App/Extension/Rights.php create mode 100644 Zend/Gdata/App/Extension/Source.php create mode 100644 Zend/Gdata/App/Extension/Subtitle.php create mode 100644 Zend/Gdata/App/Extension/Summary.php create mode 100644 Zend/Gdata/App/Extension/Text.php create mode 100644 Zend/Gdata/App/Extension/Title.php create mode 100644 Zend/Gdata/App/Extension/Updated.php create mode 100644 Zend/Gdata/App/Extension/Uri.php create mode 100644 Zend/Gdata/App/Feed.php create mode 100644 Zend/Gdata/App/FeedEntryParent.php create mode 100644 Zend/Gdata/App/FeedSourceParent.php create mode 100644 Zend/Gdata/App/HttpException.php create mode 100644 Zend/Gdata/App/IOException.php create mode 100644 Zend/Gdata/App/InvalidArgumentException.php create mode 100644 Zend/Gdata/App/LoggingHttpClientAdapterSocket.php create mode 100644 Zend/Gdata/App/MediaEntry.php create mode 100644 Zend/Gdata/App/MediaFileSource.php create mode 100644 Zend/Gdata/App/MediaSource.php create mode 100644 Zend/Gdata/App/Util.php create mode 100644 Zend/Gdata/App/VersionException.php create mode 100644 Zend/Gdata/AuthSub.php create mode 100644 Zend/Gdata/Books.php create mode 100644 Zend/Gdata/Books/CollectionEntry.php create mode 100644 Zend/Gdata/Books/CollectionFeed.php create mode 100644 Zend/Gdata/Books/Extension/AnnotationLink.php create mode 100644 Zend/Gdata/Books/Extension/BooksCategory.php create mode 100644 Zend/Gdata/Books/Extension/BooksLink.php create mode 100644 Zend/Gdata/Books/Extension/Embeddability.php create mode 100644 Zend/Gdata/Books/Extension/InfoLink.php create mode 100644 Zend/Gdata/Books/Extension/PreviewLink.php create mode 100644 Zend/Gdata/Books/Extension/Review.php create mode 100644 Zend/Gdata/Books/Extension/ThumbnailLink.php create mode 100644 Zend/Gdata/Books/Extension/Viewability.php create mode 100644 Zend/Gdata/Books/VolumeEntry.php create mode 100644 Zend/Gdata/Books/VolumeFeed.php create mode 100644 Zend/Gdata/Books/VolumeQuery.php create mode 100644 Zend/Gdata/Calendar.php create mode 100644 Zend/Gdata/Calendar/EventEntry.php create mode 100644 Zend/Gdata/Calendar/EventFeed.php create mode 100644 Zend/Gdata/Calendar/EventQuery.php create mode 100644 Zend/Gdata/Calendar/Extension/AccessLevel.php create mode 100644 Zend/Gdata/Calendar/Extension/Color.php create mode 100644 Zend/Gdata/Calendar/Extension/Hidden.php create mode 100644 Zend/Gdata/Calendar/Extension/Link.php create mode 100644 Zend/Gdata/Calendar/Extension/QuickAdd.php create mode 100644 Zend/Gdata/Calendar/Extension/Selected.php create mode 100644 Zend/Gdata/Calendar/Extension/SendEventNotifications.php create mode 100644 Zend/Gdata/Calendar/Extension/Timezone.php create mode 100644 Zend/Gdata/Calendar/Extension/WebContent.php create mode 100644 Zend/Gdata/Calendar/ListEntry.php create mode 100644 Zend/Gdata/Calendar/ListFeed.php create mode 100644 Zend/Gdata/ClientLogin.php create mode 100644 Zend/Gdata/Docs.php create mode 100644 Zend/Gdata/Docs/DocumentListEntry.php create mode 100644 Zend/Gdata/Docs/DocumentListFeed.php create mode 100644 Zend/Gdata/Docs/Query.php create mode 100644 Zend/Gdata/DublinCore.php create mode 100644 Zend/Gdata/DublinCore/Extension/Creator.php create mode 100644 Zend/Gdata/DublinCore/Extension/Date.php create mode 100644 Zend/Gdata/DublinCore/Extension/Description.php create mode 100644 Zend/Gdata/DublinCore/Extension/Format.php create mode 100644 Zend/Gdata/DublinCore/Extension/Identifier.php create mode 100644 Zend/Gdata/DublinCore/Extension/Language.php create mode 100644 Zend/Gdata/DublinCore/Extension/Publisher.php create mode 100644 Zend/Gdata/DublinCore/Extension/Rights.php create mode 100644 Zend/Gdata/DublinCore/Extension/Subject.php create mode 100644 Zend/Gdata/DublinCore/Extension/Title.php create mode 100644 Zend/Gdata/Entry.php create mode 100644 Zend/Gdata/Exif.php create mode 100644 Zend/Gdata/Exif/Entry.php create mode 100644 Zend/Gdata/Exif/Extension/Distance.php create mode 100644 Zend/Gdata/Exif/Extension/Exposure.php create mode 100644 Zend/Gdata/Exif/Extension/FStop.php create mode 100644 Zend/Gdata/Exif/Extension/Flash.php create mode 100644 Zend/Gdata/Exif/Extension/FocalLength.php create mode 100644 Zend/Gdata/Exif/Extension/ImageUniqueId.php create mode 100644 Zend/Gdata/Exif/Extension/Iso.php create mode 100644 Zend/Gdata/Exif/Extension/Make.php create mode 100644 Zend/Gdata/Exif/Extension/Model.php create mode 100644 Zend/Gdata/Exif/Extension/Tags.php create mode 100644 Zend/Gdata/Exif/Extension/Time.php create mode 100644 Zend/Gdata/Exif/Feed.php create mode 100644 Zend/Gdata/Extension.php create mode 100644 Zend/Gdata/Extension/AttendeeStatus.php create mode 100644 Zend/Gdata/Extension/AttendeeType.php create mode 100644 Zend/Gdata/Extension/Comments.php create mode 100644 Zend/Gdata/Extension/EntryLink.php create mode 100644 Zend/Gdata/Extension/EventStatus.php create mode 100644 Zend/Gdata/Extension/ExtendedProperty.php create mode 100644 Zend/Gdata/Extension/FeedLink.php create mode 100644 Zend/Gdata/Extension/OpenSearchItemsPerPage.php create mode 100644 Zend/Gdata/Extension/OpenSearchStartIndex.php create mode 100644 Zend/Gdata/Extension/OpenSearchTotalResults.php create mode 100644 Zend/Gdata/Extension/OriginalEvent.php create mode 100644 Zend/Gdata/Extension/Rating.php create mode 100644 Zend/Gdata/Extension/Recurrence.php create mode 100644 Zend/Gdata/Extension/RecurrenceException.php create mode 100644 Zend/Gdata/Extension/Reminder.php create mode 100644 Zend/Gdata/Extension/Transparency.php create mode 100644 Zend/Gdata/Extension/Visibility.php create mode 100644 Zend/Gdata/Extension/When.php create mode 100644 Zend/Gdata/Extension/Where.php create mode 100644 Zend/Gdata/Extension/Who.php create mode 100644 Zend/Gdata/Feed.php create mode 100644 Zend/Gdata/Gapps.php create mode 100644 Zend/Gdata/Gapps/EmailListEntry.php create mode 100644 Zend/Gdata/Gapps/EmailListFeed.php create mode 100644 Zend/Gdata/Gapps/EmailListQuery.php create mode 100644 Zend/Gdata/Gapps/EmailListRecipientEntry.php create mode 100644 Zend/Gdata/Gapps/EmailListRecipientFeed.php create mode 100644 Zend/Gdata/Gapps/EmailListRecipientQuery.php create mode 100644 Zend/Gdata/Gapps/Error.php create mode 100644 Zend/Gdata/Gapps/Extension/EmailList.php create mode 100644 Zend/Gdata/Gapps/Extension/Login.php create mode 100644 Zend/Gdata/Gapps/Extension/Name.php create mode 100644 Zend/Gdata/Gapps/Extension/Nickname.php create mode 100644 Zend/Gdata/Gapps/Extension/Property.php create mode 100644 Zend/Gdata/Gapps/Extension/Quota.php create mode 100644 Zend/Gdata/Gapps/GroupEntry.php create mode 100644 Zend/Gdata/Gapps/GroupFeed.php create mode 100644 Zend/Gdata/Gapps/GroupQuery.php create mode 100644 Zend/Gdata/Gapps/MemberEntry.php create mode 100644 Zend/Gdata/Gapps/MemberFeed.php create mode 100644 Zend/Gdata/Gapps/MemberQuery.php create mode 100644 Zend/Gdata/Gapps/NicknameEntry.php create mode 100644 Zend/Gdata/Gapps/NicknameFeed.php create mode 100644 Zend/Gdata/Gapps/NicknameQuery.php create mode 100644 Zend/Gdata/Gapps/OwnerEntry.php create mode 100644 Zend/Gdata/Gapps/OwnerFeed.php create mode 100644 Zend/Gdata/Gapps/OwnerQuery.php create mode 100644 Zend/Gdata/Gapps/Query.php create mode 100644 Zend/Gdata/Gapps/ServiceException.php create mode 100644 Zend/Gdata/Gapps/UserEntry.php create mode 100644 Zend/Gdata/Gapps/UserFeed.php create mode 100644 Zend/Gdata/Gapps/UserQuery.php create mode 100644 Zend/Gdata/Gbase.php create mode 100644 Zend/Gdata/Gbase/Entry.php create mode 100644 Zend/Gdata/Gbase/Extension/BaseAttribute.php create mode 100644 Zend/Gdata/Gbase/Feed.php create mode 100644 Zend/Gdata/Gbase/ItemEntry.php create mode 100644 Zend/Gdata/Gbase/ItemFeed.php create mode 100644 Zend/Gdata/Gbase/ItemQuery.php create mode 100644 Zend/Gdata/Gbase/Query.php create mode 100644 Zend/Gdata/Gbase/SnippetEntry.php create mode 100644 Zend/Gdata/Gbase/SnippetFeed.php create mode 100644 Zend/Gdata/Gbase/SnippetQuery.php create mode 100644 Zend/Gdata/Geo.php create mode 100644 Zend/Gdata/Geo/Entry.php create mode 100644 Zend/Gdata/Geo/Extension/GeoRssWhere.php create mode 100644 Zend/Gdata/Geo/Extension/GmlPoint.php create mode 100644 Zend/Gdata/Geo/Extension/GmlPos.php create mode 100644 Zend/Gdata/Geo/Feed.php create mode 100644 Zend/Gdata/Health.php create mode 100644 Zend/Gdata/Health/Extension/Ccr.php create mode 100644 Zend/Gdata/Health/ProfileEntry.php create mode 100644 Zend/Gdata/Health/ProfileFeed.php create mode 100644 Zend/Gdata/Health/ProfileListEntry.php create mode 100644 Zend/Gdata/Health/ProfileListFeed.php create mode 100644 Zend/Gdata/Health/Query.php create mode 100644 Zend/Gdata/HttpAdapterStreamingProxy.php create mode 100644 Zend/Gdata/HttpAdapterStreamingSocket.php create mode 100644 Zend/Gdata/HttpClient.php create mode 100644 Zend/Gdata/Kind/EventEntry.php create mode 100644 Zend/Gdata/Media.php create mode 100644 Zend/Gdata/Media/Entry.php create mode 100644 Zend/Gdata/Media/Extension/MediaCategory.php create mode 100644 Zend/Gdata/Media/Extension/MediaContent.php create mode 100644 Zend/Gdata/Media/Extension/MediaCopyright.php create mode 100644 Zend/Gdata/Media/Extension/MediaCredit.php create mode 100644 Zend/Gdata/Media/Extension/MediaDescription.php create mode 100644 Zend/Gdata/Media/Extension/MediaGroup.php create mode 100644 Zend/Gdata/Media/Extension/MediaHash.php create mode 100644 Zend/Gdata/Media/Extension/MediaKeywords.php create mode 100644 Zend/Gdata/Media/Extension/MediaPlayer.php create mode 100644 Zend/Gdata/Media/Extension/MediaRating.php create mode 100644 Zend/Gdata/Media/Extension/MediaRestriction.php create mode 100644 Zend/Gdata/Media/Extension/MediaText.php create mode 100644 Zend/Gdata/Media/Extension/MediaThumbnail.php create mode 100644 Zend/Gdata/Media/Extension/MediaTitle.php create mode 100644 Zend/Gdata/Media/Feed.php create mode 100644 Zend/Gdata/MediaMimeStream.php create mode 100644 Zend/Gdata/MimeBodyString.php create mode 100644 Zend/Gdata/MimeFile.php create mode 100644 Zend/Gdata/Photos.php create mode 100644 Zend/Gdata/Photos/AlbumEntry.php create mode 100644 Zend/Gdata/Photos/AlbumFeed.php create mode 100644 Zend/Gdata/Photos/AlbumQuery.php create mode 100644 Zend/Gdata/Photos/CommentEntry.php create mode 100644 Zend/Gdata/Photos/Extension/Access.php create mode 100644 Zend/Gdata/Photos/Extension/AlbumId.php create mode 100644 Zend/Gdata/Photos/Extension/BytesUsed.php create mode 100644 Zend/Gdata/Photos/Extension/Checksum.php create mode 100644 Zend/Gdata/Photos/Extension/Client.php create mode 100644 Zend/Gdata/Photos/Extension/CommentCount.php create mode 100644 Zend/Gdata/Photos/Extension/CommentingEnabled.php create mode 100644 Zend/Gdata/Photos/Extension/Height.php create mode 100644 Zend/Gdata/Photos/Extension/Id.php create mode 100644 Zend/Gdata/Photos/Extension/Location.php create mode 100644 Zend/Gdata/Photos/Extension/MaxPhotosPerAlbum.php create mode 100644 Zend/Gdata/Photos/Extension/Name.php create mode 100644 Zend/Gdata/Photos/Extension/Nickname.php create mode 100644 Zend/Gdata/Photos/Extension/NumPhotos.php create mode 100644 Zend/Gdata/Photos/Extension/NumPhotosRemaining.php create mode 100644 Zend/Gdata/Photos/Extension/PhotoId.php create mode 100644 Zend/Gdata/Photos/Extension/Position.php create mode 100644 Zend/Gdata/Photos/Extension/QuotaCurrent.php create mode 100644 Zend/Gdata/Photos/Extension/QuotaLimit.php create mode 100644 Zend/Gdata/Photos/Extension/Rotation.php create mode 100644 Zend/Gdata/Photos/Extension/Size.php create mode 100644 Zend/Gdata/Photos/Extension/Thumbnail.php create mode 100644 Zend/Gdata/Photos/Extension/Timestamp.php create mode 100644 Zend/Gdata/Photos/Extension/User.php create mode 100644 Zend/Gdata/Photos/Extension/Version.php create mode 100644 Zend/Gdata/Photos/Extension/Weight.php create mode 100644 Zend/Gdata/Photos/Extension/Width.php create mode 100644 Zend/Gdata/Photos/PhotoEntry.php create mode 100644 Zend/Gdata/Photos/PhotoFeed.php create mode 100644 Zend/Gdata/Photos/PhotoQuery.php create mode 100644 Zend/Gdata/Photos/TagEntry.php create mode 100644 Zend/Gdata/Photos/UserEntry.php create mode 100644 Zend/Gdata/Photos/UserFeed.php create mode 100644 Zend/Gdata/Photos/UserQuery.php create mode 100644 Zend/Gdata/Query.php create mode 100644 Zend/Gdata/Spreadsheets.php create mode 100644 Zend/Gdata/Spreadsheets/CellEntry.php create mode 100644 Zend/Gdata/Spreadsheets/CellFeed.php create mode 100644 Zend/Gdata/Spreadsheets/CellQuery.php create mode 100644 Zend/Gdata/Spreadsheets/DocumentQuery.php create mode 100644 Zend/Gdata/Spreadsheets/Extension/Cell.php create mode 100644 Zend/Gdata/Spreadsheets/Extension/ColCount.php create mode 100644 Zend/Gdata/Spreadsheets/Extension/Custom.php create mode 100644 Zend/Gdata/Spreadsheets/Extension/RowCount.php create mode 100644 Zend/Gdata/Spreadsheets/ListEntry.php create mode 100644 Zend/Gdata/Spreadsheets/ListFeed.php create mode 100644 Zend/Gdata/Spreadsheets/ListQuery.php create mode 100644 Zend/Gdata/Spreadsheets/SpreadsheetEntry.php create mode 100644 Zend/Gdata/Spreadsheets/SpreadsheetFeed.php create mode 100644 Zend/Gdata/Spreadsheets/WorksheetEntry.php create mode 100644 Zend/Gdata/Spreadsheets/WorksheetFeed.php create mode 100644 Zend/Gdata/YouTube.php create mode 100644 Zend/Gdata/YouTube/ActivityEntry.php create mode 100644 Zend/Gdata/YouTube/ActivityFeed.php create mode 100644 Zend/Gdata/YouTube/CommentEntry.php create mode 100644 Zend/Gdata/YouTube/CommentFeed.php create mode 100644 Zend/Gdata/YouTube/ContactEntry.php create mode 100644 Zend/Gdata/YouTube/ContactFeed.php create mode 100644 Zend/Gdata/YouTube/Extension/AboutMe.php create mode 100644 Zend/Gdata/YouTube/Extension/Age.php create mode 100644 Zend/Gdata/YouTube/Extension/Books.php create mode 100644 Zend/Gdata/YouTube/Extension/Company.php create mode 100644 Zend/Gdata/YouTube/Extension/Control.php create mode 100644 Zend/Gdata/YouTube/Extension/CountHint.php create mode 100644 Zend/Gdata/YouTube/Extension/Description.php create mode 100644 Zend/Gdata/YouTube/Extension/Duration.php create mode 100644 Zend/Gdata/YouTube/Extension/FirstName.php create mode 100644 Zend/Gdata/YouTube/Extension/Gender.php create mode 100644 Zend/Gdata/YouTube/Extension/Hobbies.php create mode 100644 Zend/Gdata/YouTube/Extension/Hometown.php create mode 100644 Zend/Gdata/YouTube/Extension/LastName.php create mode 100644 Zend/Gdata/YouTube/Extension/Link.php create mode 100644 Zend/Gdata/YouTube/Extension/Location.php create mode 100644 Zend/Gdata/YouTube/Extension/MediaContent.php create mode 100644 Zend/Gdata/YouTube/Extension/MediaCredit.php create mode 100644 Zend/Gdata/YouTube/Extension/MediaGroup.php create mode 100644 Zend/Gdata/YouTube/Extension/MediaRating.php create mode 100644 Zend/Gdata/YouTube/Extension/Movies.php create mode 100644 Zend/Gdata/YouTube/Extension/Music.php create mode 100644 Zend/Gdata/YouTube/Extension/NoEmbed.php create mode 100644 Zend/Gdata/YouTube/Extension/Occupation.php create mode 100644 Zend/Gdata/YouTube/Extension/PlaylistId.php create mode 100644 Zend/Gdata/YouTube/Extension/PlaylistTitle.php create mode 100644 Zend/Gdata/YouTube/Extension/Position.php create mode 100644 Zend/Gdata/YouTube/Extension/Private.php create mode 100644 Zend/Gdata/YouTube/Extension/QueryString.php create mode 100644 Zend/Gdata/YouTube/Extension/Racy.php create mode 100644 Zend/Gdata/YouTube/Extension/Recorded.php create mode 100644 Zend/Gdata/YouTube/Extension/Relationship.php create mode 100644 Zend/Gdata/YouTube/Extension/ReleaseDate.php create mode 100644 Zend/Gdata/YouTube/Extension/School.php create mode 100644 Zend/Gdata/YouTube/Extension/State.php create mode 100644 Zend/Gdata/YouTube/Extension/Statistics.php create mode 100644 Zend/Gdata/YouTube/Extension/Status.php create mode 100644 Zend/Gdata/YouTube/Extension/Token.php create mode 100644 Zend/Gdata/YouTube/Extension/Uploaded.php create mode 100644 Zend/Gdata/YouTube/Extension/Username.php create mode 100644 Zend/Gdata/YouTube/Extension/VideoId.php create mode 100644 Zend/Gdata/YouTube/InboxEntry.php create mode 100644 Zend/Gdata/YouTube/InboxFeed.php create mode 100644 Zend/Gdata/YouTube/MediaEntry.php create mode 100644 Zend/Gdata/YouTube/PlaylistListEntry.php create mode 100644 Zend/Gdata/YouTube/PlaylistListFeed.php create mode 100644 Zend/Gdata/YouTube/PlaylistVideoEntry.php create mode 100644 Zend/Gdata/YouTube/PlaylistVideoFeed.php create mode 100644 Zend/Gdata/YouTube/SubscriptionEntry.php create mode 100644 Zend/Gdata/YouTube/SubscriptionFeed.php create mode 100644 Zend/Gdata/YouTube/UserProfileEntry.php create mode 100644 Zend/Gdata/YouTube/VideoEntry.php create mode 100644 Zend/Gdata/YouTube/VideoFeed.php create mode 100644 Zend/Gdata/YouTube/VideoQuery.php create mode 100644 Zend/Http/Client.php create mode 100644 Zend/Http/Client/Adapter/Curl.php create mode 100644 Zend/Http/Client/Adapter/Exception.php create mode 100644 Zend/Http/Client/Adapter/Interface.php create mode 100644 Zend/Http/Client/Adapter/Proxy.php create mode 100644 Zend/Http/Client/Adapter/Socket.php create mode 100644 Zend/Http/Client/Adapter/Stream.php create mode 100644 Zend/Http/Client/Adapter/Test.php create mode 100644 Zend/Http/Client/Exception.php create mode 100644 Zend/Http/Exception.php create mode 100644 Zend/Http/Response.php create mode 100644 Zend/Http/Response/Stream.php create mode 100644 Zend/Loader.php create mode 100644 Zend/Oauth.php create mode 100644 Zend/Oauth/Client.php create mode 100644 Zend/Oauth/Config.php create mode 100644 Zend/Oauth/Config/ConfigInterface.php create mode 100644 Zend/Oauth/Consumer.php create mode 100644 Zend/Oauth/Exception.php create mode 100644 Zend/Oauth/Http.php create mode 100644 Zend/Oauth/Http/AccessToken.php create mode 100644 Zend/Oauth/Http/RequestToken.php create mode 100644 Zend/Oauth/Http/UserAuthorization.php create mode 100644 Zend/Oauth/Http/Utility.php create mode 100644 Zend/Oauth/Signature/Hmac.php create mode 100644 Zend/Oauth/Signature/Plaintext.php create mode 100644 Zend/Oauth/Signature/Rsa.php create mode 100644 Zend/Oauth/Signature/SignatureAbstract.php create mode 100644 Zend/Oauth/Token.php create mode 100644 Zend/Oauth/Token/Access.php create mode 100644 Zend/Oauth/Token/AuthorizedRequest.php create mode 100644 Zend/Oauth/Token/Request.php create mode 100644 Zend/Registry.php create mode 100644 Zend/Uri.php create mode 100644 Zend/Uri/Exception.php create mode 100644 Zend/Uri/Http.php create mode 100644 Zend/Validate/Abstract.php create mode 100644 Zend/Validate/Hostname.php create mode 100644 Zend/Validate/Hostname/Biz.php create mode 100644 Zend/Validate/Hostname/Cn.php create mode 100644 Zend/Validate/Hostname/Com.php create mode 100644 Zend/Validate/Hostname/Jp.php create mode 100644 Zend/Validate/Interface.php create mode 100644 Zend/Validate/Ip.php create mode 100644 Zend/Version.php create mode 100644 acceptDecline.php create mode 100644 cache/csv/index.html create mode 100644 cache/feeds/index.html create mode 100644 cache/images/index.html create mode 100644 cache/import/index.html create mode 100644 cache/index.html create mode 100644 cache/layout/index.html create mode 100644 cache/pdf/index.html create mode 100644 cache/upload/index.html create mode 100644 cache/xml/index.html create mode 100644 campaign_tracker.php create mode 100644 campaign_trackerv2.php create mode 100644 config.php create mode 100644 cron.php create mode 100644 custom/index.html create mode 100644 data/Link.php create mode 100644 data/SugarBean.php create mode 100644 data/Tracker.php create mode 100644 data/upload/index.html create mode 100644 dictionary.php create mode 100644 download.php create mode 100644 emailmandelivery.php create mode 100644 examples/EXAMPLES_README.txt create mode 100644 examples/ExampleLeadCapture.php create mode 100644 examples/FormValidationTest.php create mode 100644 examples/ProgressBarTest.php create mode 100644 examples/SoapTest.php create mode 100644 examples/SoapTestPortal.php create mode 100644 examples/SoapTestPortal2.php create mode 100644 export.php create mode 100644 files.md5 create mode 100644 image.php create mode 100644 include/Dashlets/Dashlet.php create mode 100644 include/Dashlets/DashletCacheBuilder.php create mode 100644 include/Dashlets/DashletGeneric.php create mode 100644 include/Dashlets/DashletGenericAutoRefresh.tpl create mode 100644 include/Dashlets/DashletGenericAutoRefreshDynamic.tpl create mode 100644 include/Dashlets/DashletGenericChart.php create mode 100644 include/Dashlets/DashletGenericChartConfigure.tpl create mode 100644 include/Dashlets/DashletGenericConfigure.tpl create mode 100644 include/Dashlets/DashletGenericDisplay.tpl create mode 100644 include/DetailView/DetailView.php create mode 100644 include/DetailView/DetailView.tpl create mode 100644 include/DetailView/DetailView2.php create mode 100644 include/DetailView/footer.tpl create mode 100644 include/DetailView/header.tpl create mode 100644 include/EditView/EditView.php create mode 100644 include/EditView/EditView.tpl create mode 100644 include/EditView/EditView2.php create mode 100644 include/EditView/PopupQuickCreate.php create mode 100644 include/EditView/QuickCreate.php create mode 100644 include/EditView/QuickCreate.tpl create mode 100644 include/EditView/SubpanelQuickCreate.php create mode 100644 include/EditView/SugarVCR.php create mode 100644 include/EditView/footer.tpl create mode 100644 include/EditView/header.tpl create mode 100644 include/GroupedTabs/GroupedTabStructure.php create mode 100644 include/HTTP_WebDAV_Server/README create mode 100644 include/HTTP_WebDAV_Server/Server.php create mode 100644 include/HTTP_WebDAV_Server/Tools/_parse_lockinfo.php create mode 100644 include/HTTP_WebDAV_Server/Tools/_parse_propfind.php create mode 100644 include/HTTP_WebDAV_Server/Tools/_parse_proppatch.php create mode 100644 include/HTTP_WebDAV_Server/dav.txt create mode 100644 include/HTTP_WebDAV_Server/license.txt create mode 100644 include/JSON.js create mode 100644 include/JSON.php create mode 100644 include/ListView/ListView.php create mode 100644 include/ListView/ListViewDCMenu.tpl create mode 100644 include/ListView/ListViewData.php create mode 100644 include/ListView/ListViewDisplay.php create mode 100644 include/ListView/ListViewFacade.php create mode 100644 include/ListView/ListViewGeneric.tpl create mode 100644 include/ListView/ListViewNoMassUpdate.tpl create mode 100644 include/ListView/ListViewPagination.tpl create mode 100644 include/ListView/ListViewSmarty.php create mode 100644 include/ListView/ListViewXTPL.php create mode 100644 include/Localization/Localization.php create mode 100644 include/MVC/Controller/ControllerFactory.php create mode 100644 include/MVC/Controller/SugarController.php create mode 100644 include/MVC/Controller/action_file_map.php create mode 100644 include/MVC/Controller/action_view_map.php create mode 100644 include/MVC/Controller/entry_point_registry.php create mode 100644 include/MVC/Controller/file_access_control_map.php create mode 100644 include/MVC/SugarApplication.php create mode 100644 include/MVC/SugarModule.php create mode 100644 include/MVC/View/SugarView.php create mode 100644 include/MVC/View/ViewFactory.php create mode 100644 include/MVC/View/tpls/Importvcard.tpl create mode 100644 include/MVC/View/tpls/modulelistmenu.tpl create mode 100644 include/MVC/View/tpls/xsrf.tpl create mode 100644 include/MVC/View/views/view.ajax.php create mode 100644 include/MVC/View/views/view.classic.config.php create mode 100644 include/MVC/View/views/view.classic.php create mode 100644 include/MVC/View/views/view.config.php create mode 100644 include/MVC/View/views/view.detail.php create mode 100644 include/MVC/View/views/view.edit.php create mode 100644 include/MVC/View/views/view.html.php create mode 100644 include/MVC/View/views/view.importvcard.php create mode 100644 include/MVC/View/views/view.importvcardsave.php create mode 100644 include/MVC/View/views/view.json.php create mode 100644 include/MVC/View/views/view.list.php create mode 100644 include/MVC/View/views/view.modulelistmenu.php create mode 100644 include/MVC/View/views/view.multiedit.php create mode 100644 include/MVC/View/views/view.noaccess.php create mode 100644 include/MVC/View/views/view.popup.php create mode 100644 include/MVC/View/views/view.quick.php create mode 100644 include/MVC/View/views/view.quickcreate.php create mode 100644 include/MVC/View/views/view.serialized.php create mode 100644 include/MVC/View/views/view.sugarpdf.config.php create mode 100644 include/MVC/View/views/view.sugarpdf.php create mode 100644 include/MVC/View/views/view.vcard.php create mode 100644 include/MVC/View/views/view.xml.php create mode 100644 include/MassUpdate.php create mode 100644 include/MySugar/DashletsDialog/DashletsDialog.php create mode 100644 include/MySugar/MySugar.php create mode 100644 include/MySugar/javascript/MySugar.js create mode 100644 include/MySugar/tpls/MySugar.tpl create mode 100644 include/MySugar/tpls/addDashletsDialog.tpl create mode 100644 include/MySugar/tpls/chartDashletsSearchResults.tpl create mode 100644 include/MySugar/tpls/dashletsSearchResults.tpl create mode 100644 include/MySugar/tpls/retrievePage.tpl create mode 100644 include/MySugar/tpls/retrieveReportCharts.tpl create mode 100644 include/OutboundEmail/OutboundEmail.php create mode 100644 include/Pear/Crypt_Blowfish/Blowfish.php create mode 100644 include/Pear/Crypt_Blowfish/Blowfish/DefaultKey.php create mode 100644 include/Pear/Crypt_Blowfish/license.txt create mode 100644 include/Pear/HTML_Safe/Safe.php create mode 100644 include/Pear/HTML_Safe/license.txt create mode 100644 include/Pear/XML_HTMLSax3/HTMLSax3.php create mode 100644 include/Pear/XML_HTMLSax3/HTMLSax3/Decorators.php create mode 100644 include/Pear/XML_HTMLSax3/HTMLSax3/States.php create mode 100644 include/Pear/XML_HTMLSax3/LICENSE create mode 100644 include/Popups/PopupSmarty.php create mode 100644 include/Popups/Popup_picker.php create mode 100644 include/Popups/tpls/PopupGeneric.tpl create mode 100644 include/Popups/tpls/footer.tpl create mode 100644 include/Popups/tpls/header.tpl create mode 100644 include/QuickSearchDefaults.php create mode 100644 include/SearchForm/SearchForm.php create mode 100644 include/SearchForm/SearchForm2.php create mode 100644 include/SearchForm/SugarSpot.php create mode 100644 include/SearchForm/tpls/SearchFormGeneric.tpl create mode 100644 include/SearchForm/tpls/SearchFormGenericAdvanced.tpl create mode 100644 include/SearchForm/tpls/footer.tpl create mode 100644 include/SearchForm/tpls/header.tpl create mode 100644 include/Smarty/COPYING.lib create mode 100644 include/Smarty/Config_File.class.php create mode 100644 include/Smarty/LICENSE create mode 100644 include/Smarty/README create mode 100644 include/Smarty/Smarty.class.php create mode 100644 include/Smarty/Smarty_Compiler.class.php create mode 100644 include/Smarty/debug.tpl create mode 100644 include/Smarty/internals/core.assemble_plugin_filepath.php create mode 100644 include/Smarty/internals/core.assign_smarty_interface.php create mode 100644 include/Smarty/internals/core.create_dir_structure.php create mode 100644 include/Smarty/internals/core.display_debug_console.php create mode 100644 include/Smarty/internals/core.get_include_path.php create mode 100644 include/Smarty/internals/core.get_microtime.php create mode 100644 include/Smarty/internals/core.get_php_resource.php create mode 100644 include/Smarty/internals/core.is_secure.php create mode 100644 include/Smarty/internals/core.is_trusted.php create mode 100644 include/Smarty/internals/core.load_plugins.php create mode 100644 include/Smarty/internals/core.load_resource_plugin.php create mode 100644 include/Smarty/internals/core.process_cached_inserts.php create mode 100644 include/Smarty/internals/core.process_compiled_include.php create mode 100644 include/Smarty/internals/core.read_cache_file.php create mode 100644 include/Smarty/internals/core.rm_auto.php create mode 100644 include/Smarty/internals/core.rmdir.php create mode 100644 include/Smarty/internals/core.run_insert_handler.php create mode 100644 include/Smarty/internals/core.smarty_include_php.php create mode 100644 include/Smarty/internals/core.write_cache_file.php create mode 100644 include/Smarty/internals/core.write_compiled_include.php create mode 100644 include/Smarty/internals/core.write_compiled_resource.php create mode 100644 include/Smarty/internals/core.write_file.php create mode 100644 include/Smarty/plugins/block.textformat.php create mode 100644 include/Smarty/plugins/compiler.assign.php create mode 100644 include/Smarty/plugins/function.assign_debug_info.php create mode 100644 include/Smarty/plugins/function.config_load.php create mode 100644 include/Smarty/plugins/function.counter.php create mode 100644 include/Smarty/plugins/function.cycle.php create mode 100644 include/Smarty/plugins/function.debug.php create mode 100644 include/Smarty/plugins/function.eval.php create mode 100644 include/Smarty/plugins/function.ext_includes.php create mode 100644 include/Smarty/plugins/function.fetch.php create mode 100644 include/Smarty/plugins/function.html_checkboxes.php create mode 100644 include/Smarty/plugins/function.html_image.php create mode 100644 include/Smarty/plugins/function.html_options.php create mode 100644 include/Smarty/plugins/function.html_radios.php create mode 100644 include/Smarty/plugins/function.html_select_date.php create mode 100644 include/Smarty/plugins/function.html_select_time.php create mode 100644 include/Smarty/plugins/function.html_table.php create mode 100644 include/Smarty/plugins/function.mailto.php create mode 100644 include/Smarty/plugins/function.math.php create mode 100644 include/Smarty/plugins/function.multienum_to_array.php create mode 100644 include/Smarty/plugins/function.overlib_includes.php create mode 100644 include/Smarty/plugins/function.popup.php create mode 100644 include/Smarty/plugins/function.popup_init.php create mode 100644 include/Smarty/plugins/function.sugar_button.php create mode 100644 include/Smarty/plugins/function.sugar_button_slider.php create mode 100644 include/Smarty/plugins/function.sugar_connector_display.php create mode 100644 include/Smarty/plugins/function.sugar_currency_format.php create mode 100644 include/Smarty/plugins/function.sugar_evalcolumn.php create mode 100644 include/Smarty/plugins/function.sugar_evalcolumn_old.php create mode 100644 include/Smarty/plugins/function.sugar_fetch.php create mode 100644 include/Smarty/plugins/function.sugar_field.php create mode 100644 include/Smarty/plugins/function.sugar_getimagepath.php create mode 100644 include/Smarty/plugins/function.sugar_getjspath.php create mode 100644 include/Smarty/plugins/function.sugar_getwebpath.php create mode 100644 include/Smarty/plugins/function.sugar_help.php create mode 100644 include/Smarty/plugins/function.sugar_image.php create mode 100644 include/Smarty/plugins/function.sugar_include.php create mode 100644 include/Smarty/plugins/function.sugar_link.php create mode 100644 include/Smarty/plugins/function.sugar_number_format.php create mode 100644 include/Smarty/plugins/function.sugar_phone.php create mode 100644 include/Smarty/plugins/function.sugar_replace_vars.php create mode 100644 include/Smarty/plugins/function.sugar_run_helper.php create mode 100644 include/Smarty/plugins/function.sugar_translate.php create mode 100644 include/Smarty/plugins/function.sugar_variable_constructor.php create mode 100644 include/Smarty/plugins/function.sugarvar.php create mode 100644 include/Smarty/plugins/function.sugarvar_connector.php create mode 100644 include/Smarty/plugins/modifier.capitalize.php create mode 100644 include/Smarty/plugins/modifier.cat.php create mode 100644 include/Smarty/plugins/modifier.count_characters.php create mode 100644 include/Smarty/plugins/modifier.count_paragraphs.php create mode 100644 include/Smarty/plugins/modifier.count_sentences.php create mode 100644 include/Smarty/plugins/modifier.count_words.php create mode 100644 include/Smarty/plugins/modifier.date_format.php create mode 100644 include/Smarty/plugins/modifier.debug_print_var.php create mode 100644 include/Smarty/plugins/modifier.default.php create mode 100644 include/Smarty/plugins/modifier.default_date_value.php create mode 100644 include/Smarty/plugins/modifier.escape.php create mode 100644 include/Smarty/plugins/modifier.in_array.php create mode 100644 include/Smarty/plugins/modifier.indent.php create mode 100644 include/Smarty/plugins/modifier.lower.php create mode 100644 include/Smarty/plugins/modifier.nl2br.php create mode 100644 include/Smarty/plugins/modifier.regex_replace.php create mode 100644 include/Smarty/plugins/modifier.replace.php create mode 100644 include/Smarty/plugins/modifier.spacify.php create mode 100644 include/Smarty/plugins/modifier.string_format.php create mode 100644 include/Smarty/plugins/modifier.strip.php create mode 100644 include/Smarty/plugins/modifier.strip_semicolon.php create mode 100644 include/Smarty/plugins/modifier.strip_tags.php create mode 100644 include/Smarty/plugins/modifier.to_url.php create mode 100644 include/Smarty/plugins/modifier.truncate.php create mode 100644 include/Smarty/plugins/modifier.upper.php create mode 100644 include/Smarty/plugins/modifier.wordwrap.php create mode 100644 include/Smarty/plugins/outputfilter.trimwhitespace.php create mode 100644 include/Smarty/plugins/shared.escape_special_chars.php create mode 100644 include/Smarty/plugins/shared.make_timestamp.php create mode 100644 include/SubPanel/SubPanel.php create mode 100644 include/SubPanel/SubPanelDefinitions.php create mode 100644 include/SubPanel/SubPanelDynamic.html create mode 100644 include/SubPanel/SubPanelTiles.js create mode 100644 include/SubPanel/SubPanelTiles.php create mode 100644 include/SubPanel/SubPanelTilesTabs.php create mode 100644 include/SubPanel/SubPanelViewer.php create mode 100644 include/SubPanel/SugarTab.php create mode 100644 include/SubPanel/registered_layout_defs.php create mode 100644 include/SubPanel/subpanels.txt create mode 100644 include/SubPanel/tpls/singletabmenu.tpl create mode 100644 include/SugarCache/SugarCache.php create mode 100644 include/SugarCache/SugarCacheAPC.php create mode 100644 include/SugarCache/SugarCacheAbstract.php create mode 100644 include/SugarCache/SugarCacheFile.php create mode 100644 include/SugarCache/SugarCacheMemcache.php create mode 100644 include/SugarCache/SugarCacheMemcached.php create mode 100644 include/SugarCache/SugarCacheMemory.php create mode 100644 include/SugarCache/SugarCacheRedis.php create mode 100644 include/SugarCache/SugarCacheWincache.php create mode 100644 include/SugarCache/SugarCacheZend.php create mode 100644 include/SugarCache/SugarCachesMash.php create mode 100644 include/SugarCharts/Jit/FlashCanvas/canvas2png.js create mode 100644 include/SugarCharts/Jit/FlashCanvas/flashcanvas.js create mode 100644 include/SugarCharts/Jit/FlashCanvas/flashcanvas.swf create mode 100644 include/SugarCharts/Jit/FlashCanvas/proxy.php create mode 100644 include/SugarCharts/Jit/FlashCanvas/save.php create mode 100644 include/SugarCharts/Jit/Jit.php create mode 100644 include/SugarCharts/Jit/JitReports.php create mode 100644 include/SugarCharts/Jit/css/base.css create mode 100644 include/SugarCharts/Jit/js/Jit/jit.js create mode 100644 include/SugarCharts/Jit/js/mySugarCharts.js create mode 100644 include/SugarCharts/Jit/js/sugarCharts.js create mode 100644 include/SugarCharts/Jit/tpls/DashletGenericChartScript.tpl create mode 100644 include/SugarCharts/Jit/tpls/chart.tpl create mode 100644 include/SugarCharts/JsChart.php create mode 100644 include/SugarCharts/SugarChart.php create mode 100644 include/SugarCharts/SugarChartFactory.php create mode 100644 include/SugarCharts/swf/barChart.swf create mode 100644 include/SugarCharts/swf/chart.swf create mode 100644 include/SugarCharts/swf/groupByChart.swf create mode 100644 include/SugarCharts/swf/horizontalBarChart.swf create mode 100644 include/SugarCharts/swf/horizontalGroupByChart.swf create mode 100644 include/SugarCharts/swf/lineChart.swf create mode 100644 include/SugarCharts/swf/pieChart.swf create mode 100644 include/SugarCharts/swf/stackedGroupByChart.swf create mode 100644 include/SugarDateTime.php create mode 100644 include/SugarDependentDropdown/SugarDependentDropdown.php create mode 100644 include/SugarDependentDropdown/javascript/SugarDependentDropdown.js create mode 100644 include/SugarDependentDropdown/metadata/dependentDropdown.php create mode 100644 include/SugarEmailAddress/SugarEmailAddress.js create mode 100644 include/SugarEmailAddress/SugarEmailAddress.php create mode 100644 include/SugarEmailAddress/templates/forDetailView.tpl create mode 100644 include/SugarEmailAddress/templates/forDuplicatesView.tpl create mode 100644 include/SugarEmailAddress/templates/forEditView.tpl create mode 100644 include/SugarEmailAddress/templates/forWideFormBodyView.tpl create mode 100644 include/SugarFields/Fields/Address/DetailView.tpl create mode 100644 include/SugarFields/Fields/Address/EditView.tpl create mode 100644 include/SugarFields/Fields/Address/SugarFieldAddress.js create mode 100644 include/SugarFields/Fields/Address/SugarFieldAddress.php create mode 100644 include/SugarFields/Fields/Address/en_us.DetailView.tpl create mode 100644 include/SugarFields/Fields/Address/en_us.EditView.tpl create mode 100644 include/SugarFields/Fields/Assigned_user_name/EditViewFunction.tpl create mode 100644 include/SugarFields/Fields/Assigned_user_name/SearchView.tpl create mode 100644 include/SugarFields/Fields/Assigned_user_name/SugarFieldAssigned_user_name.php create mode 100644 include/SugarFields/Fields/Base/DetailView.tpl create mode 100644 include/SugarFields/Fields/Base/DetailViewFunction.tpl create mode 100644 include/SugarFields/Fields/Base/EditView.tpl create mode 100644 include/SugarFields/Fields/Base/EditViewFunction.tpl create mode 100644 include/SugarFields/Fields/Base/ImportViewFunction.tpl create mode 100644 include/SugarFields/Fields/Base/InlineEdit.tpl create mode 100644 include/SugarFields/Fields/Base/InlineEditView.tpl create mode 100644 include/SugarFields/Fields/Base/ListView.tpl create mode 100644 include/SugarFields/Fields/Base/SearchForm.tpl create mode 100644 include/SugarFields/Fields/Base/SugarFieldBase.php create mode 100644 include/SugarFields/Fields/Bool/DetailView.tpl create mode 100644 include/SugarFields/Fields/Bool/EditView.tpl create mode 100644 include/SugarFields/Fields/Bool/InlineEdit.tpl create mode 100644 include/SugarFields/Fields/Bool/InlineEditView.tpl create mode 100644 include/SugarFields/Fields/Bool/ListView.tpl create mode 100644 include/SugarFields/Fields/Bool/SearchView.tpl create mode 100644 include/SugarFields/Fields/Bool/SugarFieldBool.php create mode 100644 include/SugarFields/Fields/Collection/CollectionDetailView.tpl create mode 100644 include/SugarFields/Fields/Collection/CollectionEditView.tpl create mode 100644 include/SugarFields/Fields/Collection/CollectionEditViewRow.tpl create mode 100644 include/SugarFields/Fields/Collection/DetailView.tpl create mode 100644 include/SugarFields/Fields/Collection/EditView.tpl create mode 100644 include/SugarFields/Fields/Collection/SugarFieldCollection.js create mode 100644 include/SugarFields/Fields/Collection/SugarFieldCollection.php create mode 100644 include/SugarFields/Fields/Collection/ViewSugarFieldCollection.php create mode 100644 include/SugarFields/Fields/Collection/view.sugarfieldcollection.php create mode 100644 include/SugarFields/Fields/Currency/DetailView.tpl create mode 100644 include/SugarFields/Fields/Currency/EditView.tpl create mode 100644 include/SugarFields/Fields/Currency/ListView.tpl create mode 100644 include/SugarFields/Fields/Currency/SugarFieldCurrency.php create mode 100644 include/SugarFields/Fields/Datetime/EditView.tpl create mode 100644 include/SugarFields/Fields/Datetime/SugarFieldDatetime.php create mode 100644 include/SugarFields/Fields/Datetimecombo/Datetimecombo.js create mode 100644 include/SugarFields/Fields/Datetimecombo/EditView.tpl create mode 100644 include/SugarFields/Fields/Datetimecombo/RangeSearchForm.tpl create mode 100644 include/SugarFields/Fields/Datetimecombo/SearchView.tpl create mode 100644 include/SugarFields/Fields/Datetimecombo/SugarFieldDatetimecombo.php create mode 100644 include/SugarFields/Fields/Download/DetailView.tpl create mode 100644 include/SugarFields/Fields/Download/SugarFieldDownload.php create mode 100644 include/SugarFields/Fields/Enum/DetailView.tpl create mode 100644 include/SugarFields/Fields/Enum/DetailViewFunction.tpl create mode 100644 include/SugarFields/Fields/Enum/EditView.tpl create mode 100644 include/SugarFields/Fields/Enum/EditViewFunction.tpl create mode 100644 include/SugarFields/Fields/Enum/SearchView.tpl create mode 100644 include/SugarFields/Fields/Enum/SugarFieldEnum.php create mode 100644 include/SugarFields/Fields/File/DetailView.tpl create mode 100644 include/SugarFields/Fields/File/EditView.tpl create mode 100644 include/SugarFields/Fields/File/ListView.tpl create mode 100644 include/SugarFields/Fields/File/SearchView.tpl create mode 100644 include/SugarFields/Fields/File/SugarFieldFile.js create mode 100644 include/SugarFields/Fields/File/SugarFieldFile.php create mode 100644 include/SugarFields/Fields/Float/DetailView.tpl create mode 100644 include/SugarFields/Fields/Float/EditView.tpl create mode 100644 include/SugarFields/Fields/Float/SugarFieldFloat.php create mode 100644 include/SugarFields/Fields/Fullname/DetailView.tpl create mode 100644 include/SugarFields/Fields/Fullname/SugarFieldFullname.php create mode 100644 include/SugarFields/Fields/Html/DetailView.tpl create mode 100644 include/SugarFields/Fields/Html/SugarFieldHtml.php create mode 100644 include/SugarFields/Fields/Id/SugarFieldId.php create mode 100644 include/SugarFields/Fields/Iframe/DetailView.tpl create mode 100644 include/SugarFields/Fields/Iframe/EditView.tpl create mode 100644 include/SugarFields/Fields/Int/DetailView.tpl create mode 100644 include/SugarFields/Fields/Int/EditView.tpl create mode 100644 include/SugarFields/Fields/Int/RangeSearchForm.tpl create mode 100644 include/SugarFields/Fields/Int/SearchForm.tpl create mode 100644 include/SugarFields/Fields/Int/SugarFieldInt.php create mode 100644 include/SugarFields/Fields/Link/DetailView.tpl create mode 100644 include/SugarFields/Fields/Link/EditView.tpl create mode 100644 include/SugarFields/Fields/Link/ListView.tpl create mode 100644 include/SugarFields/Fields/Multienum/DetailView.tpl create mode 100644 include/SugarFields/Fields/Multienum/EditView.tpl create mode 100644 include/SugarFields/Fields/Multienum/EditViewFunction.tpl create mode 100644 include/SugarFields/Fields/Multienum/ListView.tpl create mode 100644 include/SugarFields/Fields/Multienum/SearchView.tpl create mode 100644 include/SugarFields/Fields/Multienum/SugarFieldMultienum.php create mode 100644 include/SugarFields/Fields/Parent/DetailView.tpl create mode 100644 include/SugarFields/Fields/Parent/EditView.tpl create mode 100644 include/SugarFields/Fields/Parent/SearchView.tpl create mode 100644 include/SugarFields/Fields/Parent/SugarFieldParent.php create mode 100644 include/SugarFields/Fields/Password/EditView.tpl create mode 100644 include/SugarFields/Fields/Password/SugarFieldPassword.php create mode 100644 include/SugarFields/Fields/Phone/EditView.tpl create mode 100644 include/SugarFields/Fields/Phone/SugarFieldPhone.php create mode 100644 include/SugarFields/Fields/Radioenum/DetailView.tpl create mode 100644 include/SugarFields/Fields/Radioenum/EditView.tpl create mode 100644 include/SugarFields/Fields/Readonly/SugarFieldReadonly.php create mode 100644 include/SugarFields/Fields/Relate/DetailView.tpl create mode 100644 include/SugarFields/Fields/Relate/EditView.tpl create mode 100644 include/SugarFields/Fields/Relate/SearchView.tpl create mode 100644 include/SugarFields/Fields/Relate/SugarFieldRelate.php create mode 100644 include/SugarFields/Fields/Text/ClassicEditView.tpl create mode 100644 include/SugarFields/Fields/Text/DetailView.tpl create mode 100644 include/SugarFields/Fields/Text/EditView.tpl create mode 100644 include/SugarFields/Fields/Text/SugarFieldText.php create mode 100644 include/SugarFields/Fields/URL/DetailView.tpl create mode 100644 include/SugarFields/Fields/URL/EditView.tpl create mode 100644 include/SugarFields/Fields/URL/ListView.tpl create mode 100644 include/SugarFields/Fields/Username/DetailView.tpl create mode 100644 include/SugarFields/Fields/Username/SugarFieldUsername.php create mode 100644 include/SugarFields/Parsers/DetailViewMetaParser.php create mode 100644 include/SugarFields/Parsers/EditViewMetaParser.php create mode 100644 include/SugarFields/Parsers/MetaParser.php create mode 100644 include/SugarFields/Parsers/QuickCreateMetaParser.php create mode 100644 include/SugarFields/Parsers/Rules/AccountsParseRule.php create mode 100644 include/SugarFields/Parsers/Rules/ActivitiesParseRule.php create mode 100644 include/SugarFields/Parsers/Rules/AddressRule.php create mode 100644 include/SugarFields/Parsers/Rules/BaseRule.php create mode 100644 include/SugarFields/Parsers/Rules/BugsParseRule.php create mode 100644 include/SugarFields/Parsers/Rules/CallsParseRule.php create mode 100644 include/SugarFields/Parsers/Rules/CampaignsParseRule.php create mode 100644 include/SugarFields/Parsers/Rules/ContactsParseRule.php create mode 100644 include/SugarFields/Parsers/Rules/ContractsParseRule.php create mode 100644 include/SugarFields/Parsers/Rules/DocumentsParseRule.php create mode 100644 include/SugarFields/Parsers/Rules/EmailAddressRule.php create mode 100644 include/SugarFields/Parsers/Rules/EmptyRowRule.php create mode 100644 include/SugarFields/Parsers/Rules/LeadsParseRule.php create mode 100644 include/SugarFields/Parsers/Rules/MeetingsParseRule.php create mode 100644 include/SugarFields/Parsers/Rules/NotesParseRule.php create mode 100644 include/SugarFields/Parsers/Rules/OpportunitiesParseRule.php create mode 100644 include/SugarFields/Parsers/Rules/ParseRules.php create mode 100644 include/SugarFields/Parsers/Rules/ProductsParseRule.php create mode 100644 include/SugarFields/Parsers/Rules/QuotesParseRule.php create mode 100644 include/SugarFields/Parsers/Rules/UndefinedVardefRule.php create mode 100644 include/SugarFields/Parsers/Rules/VariableCleanupRule.php create mode 100644 include/SugarFields/Parsers/Rules/VariableSubstitutionRule.php create mode 100644 include/SugarFields/Parsers/SearchFormMetaParser.php create mode 100644 include/SugarFields/SugarFieldHandler.php create mode 100644 include/SugarFolders/SugarFolders.php create mode 100644 include/SugarLogger/LoggerManager.php create mode 100644 include/SugarLogger/LoggerTemplate.php create mode 100644 include/SugarLogger/SugarLogger.php create mode 100644 include/SugarOauth.php create mode 100644 include/SugarObjects/LanguageManager.php create mode 100644 include/SugarObjects/SugarConfig.php create mode 100644 include/SugarObjects/SugarRegistry.php create mode 100644 include/SugarObjects/SugarSession.php create mode 100644 include/SugarObjects/VardefManager.php create mode 100644 include/SugarObjects/implements/assignable/language/en_us.lang.php create mode 100644 include/SugarObjects/implements/assignable/vardefs.php create mode 100644 include/SugarObjects/implements/team_security/language/en_us.lang.php create mode 100644 include/SugarObjects/implements/team_security/vardefs.php create mode 100644 include/SugarObjects/templates/basic/Basic.php create mode 100644 include/SugarObjects/templates/basic/Dashlets/Dashlet/m-n-Dashlet.meta.php create mode 100644 include/SugarObjects/templates/basic/Dashlets/Dashlet/m-n-Dashlet.php create mode 100644 include/SugarObjects/templates/basic/icons/Createbasic.gif create mode 100644 include/SugarObjects/templates/basic/icons/basic.gif create mode 100644 include/SugarObjects/templates/basic/icons/basic_32.gif create mode 100644 include/SugarObjects/templates/basic/language/en_us.lang.php create mode 100644 include/SugarObjects/templates/basic/metadata/SearchFields.php create mode 100644 include/SugarObjects/templates/basic/metadata/dashletviewdefs.php create mode 100644 include/SugarObjects/templates/basic/metadata/detailviewdefs.php create mode 100644 include/SugarObjects/templates/basic/metadata/editviewdefs.php create mode 100644 include/SugarObjects/templates/basic/metadata/listviewdefs.php create mode 100644 include/SugarObjects/templates/basic/metadata/metafiles.php create mode 100644 include/SugarObjects/templates/basic/metadata/popupdefs.php create mode 100644 include/SugarObjects/templates/basic/metadata/quickcreatedefs.php create mode 100644 include/SugarObjects/templates/basic/metadata/searchdefs.php create mode 100644 include/SugarObjects/templates/basic/metadata/subpanels/default.php create mode 100644 include/SugarObjects/templates/basic/vardefs.php create mode 100644 include/SugarObjects/templates/company/Company.php create mode 100644 include/SugarObjects/templates/company/config.php create mode 100644 include/SugarObjects/templates/company/icons/Createcompany.gif create mode 100644 include/SugarObjects/templates/company/icons/company.gif create mode 100644 include/SugarObjects/templates/company/icons/company_32.gif create mode 100644 include/SugarObjects/templates/company/language/application/en_us.lang.php create mode 100644 include/SugarObjects/templates/company/language/en_us.lang.php create mode 100644 include/SugarObjects/templates/company/metadata/SearchFields.php create mode 100644 include/SugarObjects/templates/company/metadata/dashletviewdefs.php create mode 100644 include/SugarObjects/templates/company/metadata/detailviewdefs.php create mode 100644 include/SugarObjects/templates/company/metadata/editviewdefs.php create mode 100644 include/SugarObjects/templates/company/metadata/listviewdefs.php create mode 100644 include/SugarObjects/templates/company/metadata/metafiles.php create mode 100644 include/SugarObjects/templates/company/metadata/popupdefs.php create mode 100644 include/SugarObjects/templates/company/metadata/quickcreatedefs.php create mode 100644 include/SugarObjects/templates/company/metadata/searchdefs.php create mode 100644 include/SugarObjects/templates/company/metadata/subpanels/default.php create mode 100644 include/SugarObjects/templates/company/vardefs.php create mode 100644 include/SugarObjects/templates/file/File.php create mode 100644 include/SugarObjects/templates/file/controller.php create mode 100644 include/SugarObjects/templates/file/icons/Createfile.gif create mode 100644 include/SugarObjects/templates/file/icons/file.gif create mode 100644 include/SugarObjects/templates/file/icons/file_32.gif create mode 100644 include/SugarObjects/templates/file/language/application/en_us.lang.php create mode 100644 include/SugarObjects/templates/file/language/en_us.lang.php create mode 100644 include/SugarObjects/templates/file/metadata/SearchFields.php create mode 100644 include/SugarObjects/templates/file/metadata/dashletviewdefs.php create mode 100644 include/SugarObjects/templates/file/metadata/detailviewdefs.php create mode 100644 include/SugarObjects/templates/file/metadata/editviewdefs.php create mode 100644 include/SugarObjects/templates/file/metadata/listviewdefs.php create mode 100644 include/SugarObjects/templates/file/metadata/metafiles.php create mode 100644 include/SugarObjects/templates/file/metadata/quickcreatedefs.php create mode 100644 include/SugarObjects/templates/file/metadata/searchdefs.php create mode 100644 include/SugarObjects/templates/file/metadata/subpanels/default.php create mode 100644 include/SugarObjects/templates/file/vardefs.php create mode 100644 include/SugarObjects/templates/file/views/view.edit.php create mode 100644 include/SugarObjects/templates/issue/Issue.php create mode 100644 include/SugarObjects/templates/issue/config.php create mode 100644 include/SugarObjects/templates/issue/icons/Createissue.gif create mode 100644 include/SugarObjects/templates/issue/icons/issue.gif create mode 100644 include/SugarObjects/templates/issue/icons/issue_32.gif create mode 100644 include/SugarObjects/templates/issue/language/application/en_us.lang.php create mode 100644 include/SugarObjects/templates/issue/language/en_us.lang.php create mode 100644 include/SugarObjects/templates/issue/metadata/SearchFields.php create mode 100644 include/SugarObjects/templates/issue/metadata/dashletviewdefs.php create mode 100644 include/SugarObjects/templates/issue/metadata/detailviewdefs.php create mode 100644 include/SugarObjects/templates/issue/metadata/editviewdefs.php create mode 100644 include/SugarObjects/templates/issue/metadata/listviewdefs.php create mode 100644 include/SugarObjects/templates/issue/metadata/metafiles.php create mode 100644 include/SugarObjects/templates/issue/metadata/popupdefs.php create mode 100644 include/SugarObjects/templates/issue/metadata/quickcreatedefs.php create mode 100644 include/SugarObjects/templates/issue/metadata/searchdefs.php create mode 100644 include/SugarObjects/templates/issue/metadata/subpanels/default.php create mode 100644 include/SugarObjects/templates/issue/vardefs.php create mode 100644 include/SugarObjects/templates/person/Person.php create mode 100644 include/SugarObjects/templates/person/config.php create mode 100644 include/SugarObjects/templates/person/icons/Createperson.gif create mode 100644 include/SugarObjects/templates/person/icons/person.gif create mode 100644 include/SugarObjects/templates/person/icons/person_32.gif create mode 100644 include/SugarObjects/templates/person/language/en_us.lang.php create mode 100644 include/SugarObjects/templates/person/metadata/SearchFields.php create mode 100644 include/SugarObjects/templates/person/metadata/dashletviewdefs.php create mode 100644 include/SugarObjects/templates/person/metadata/detailviewdefs.php create mode 100644 include/SugarObjects/templates/person/metadata/editviewdefs.php create mode 100644 include/SugarObjects/templates/person/metadata/listviewdefs.php create mode 100644 include/SugarObjects/templates/person/metadata/metafiles.php create mode 100644 include/SugarObjects/templates/person/metadata/popupdefs.php create mode 100644 include/SugarObjects/templates/person/metadata/quickcreatedefs.php create mode 100644 include/SugarObjects/templates/person/metadata/searchdefs.php create mode 100644 include/SugarObjects/templates/person/metadata/subpanels/default.php create mode 100644 include/SugarObjects/templates/person/vardefs.php create mode 100644 include/SugarObjects/templates/sale/Chance.php create mode 100644 include/SugarObjects/templates/sale/Sale.php create mode 100644 include/SugarObjects/templates/sale/config.php create mode 100644 include/SugarObjects/templates/sale/icons/Createchance.gif create mode 100644 include/SugarObjects/templates/sale/icons/Createsale.gif create mode 100644 include/SugarObjects/templates/sale/icons/chance.gif create mode 100644 include/SugarObjects/templates/sale/icons/chance_32.gif create mode 100644 include/SugarObjects/templates/sale/icons/sale.gif create mode 100644 include/SugarObjects/templates/sale/icons/sale_32.gif create mode 100644 include/SugarObjects/templates/sale/language/application/en_us.lang.php create mode 100644 include/SugarObjects/templates/sale/language/en_us.lang.php create mode 100644 include/SugarObjects/templates/sale/metadata/SearchFields.php create mode 100644 include/SugarObjects/templates/sale/metadata/dashletviewdefs.php create mode 100644 include/SugarObjects/templates/sale/metadata/detailviewdefs.php create mode 100644 include/SugarObjects/templates/sale/metadata/editviewdefs.php create mode 100644 include/SugarObjects/templates/sale/metadata/listviewdefs.php create mode 100644 include/SugarObjects/templates/sale/metadata/metafiles.php create mode 100644 include/SugarObjects/templates/sale/metadata/popupdefs.php create mode 100644 include/SugarObjects/templates/sale/metadata/quickcreatedefs.php create mode 100644 include/SugarObjects/templates/sale/metadata/searchdefs.php create mode 100644 include/SugarObjects/templates/sale/metadata/subpanels/default.php create mode 100644 include/SugarObjects/templates/sale/vardefs.php create mode 100644 include/SugarPHPMailer.php create mode 100644 include/SugarTheme/SugarTheme.php create mode 100644 include/SugarTheme/cssmin.php create mode 100644 include/SugarTheme/getImage.php create mode 100644 include/SugarTinyMCE.php create mode 100644 include/Sugar_Smarty.php create mode 100644 include/Sugarpdf/FontManager.php create mode 100644 include/Sugarpdf/Sugarpdf.php create mode 100644 include/Sugarpdf/SugarpdfFactory.php create mode 100644 include/Sugarpdf/SugarpdfHelper.php create mode 100644 include/Sugarpdf/sugarpdf/sugarpdf.smarty.php create mode 100644 include/Sugarpdf/sugarpdf_config.php create mode 100644 include/Sugarpdf/sugarpdf_default.php create mode 100644 include/TemplateHandler/TemplateHandler.php create mode 100644 include/TimeDate.php create mode 100644 include/VarDefHandler/VarDefHandler.php create mode 100644 include/VarDefHandler/listvardefoverride.php create mode 100644 include/VarDefHandler/vardef_meta_arrays.php create mode 100644 include/connectors/ConnectorFactory.php create mode 100644 include/connectors/component.php create mode 100644 include/connectors/filters/FilterFactory.php create mode 100644 include/connectors/filters/default/filter.php create mode 100644 include/connectors/formatters/FormatterFactory.php create mode 100644 include/connectors/formatters/default/company_detail.js create mode 100644 include/connectors/formatters/default/formatter.php create mode 100644 include/connectors/formatters/ext/rest/tpls/default.tpl create mode 100644 include/connectors/formatters/ext/soap/tpls/default.tpl create mode 100644 include/connectors/sources/SourceFactory.php create mode 100644 include/connectors/sources/default/source.php create mode 100644 include/connectors/sources/ext/rest/rest.php create mode 100644 include/connectors/sources/ext/soap/soap.php create mode 100644 include/connectors/sources/loc/xml.php create mode 100644 include/connectors/utils/ConnectorUtils.php create mode 100644 include/contextMenus/contextMenu.php create mode 100644 include/contextMenus/menuDefs/sugarAccount.php create mode 100644 include/contextMenus/menuDefs/sugarObject.php create mode 100644 include/contextMenus/menuDefs/sugarPerson.php create mode 100644 include/controller/Controller.php create mode 100644 include/database/DBHelper.php create mode 100644 include/database/DBManager.php create mode 100644 include/database/DBManagerFactory.php create mode 100644 include/database/FreeTDSHelper.php create mode 100644 include/database/FreeTDSManager.php create mode 100644 include/database/MssqlHelper.php create mode 100644 include/database/MssqlManager.php create mode 100644 include/database/MysqlHelper.php create mode 100644 include/database/MysqlManager.php create mode 100644 include/database/MysqliHelper.php create mode 100644 include/database/MysqliManager.php create mode 100644 include/database/PearDatabase.php create mode 100644 include/database/SqlsrvHelper.php create mode 100644 include/database/SqlsrvManager.php create mode 100644 include/dir_inc.php create mode 100644 include/entryPoint.php create mode 100644 include/export_utils.php create mode 100644 include/externalAPI/Base/ExternalAPIBase.php create mode 100644 include/externalAPI/Base/ExternalAPIPlugin.php create mode 100644 include/externalAPI/Base/ExternalOAuthAPIPlugin.php create mode 100644 include/externalAPI/Base/OAuthPluginBase.php create mode 100644 include/externalAPI/Base/WebDocument.php create mode 100644 include/externalAPI/Base/WebFeed.php create mode 100644 include/externalAPI/Base/WebMeeting.php create mode 100644 include/externalAPI/ExternalAPIFactory.php create mode 100644 include/fonts/Courier-Bold.afm create mode 100644 include/fonts/Courier-BoldOblique.afm create mode 100644 include/fonts/Courier-Oblique.afm create mode 100644 include/fonts/Courier.afm create mode 100644 include/fonts/Helvetica-Bold.afm create mode 100644 include/fonts/Helvetica-BoldOblique.afm create mode 100644 include/fonts/Helvetica-Oblique.afm create mode 100644 include/fonts/Helvetica.afm create mode 100644 include/fonts/License.html create mode 100644 include/fonts/Times-Bold.afm create mode 100644 include/fonts/Times-BoldItalic.afm create mode 100644 include/fonts/Times-Italic.afm create mode 100644 include/fonts/Times-Roman.afm create mode 100644 include/formbase.php create mode 100644 include/generic/DeleteRelationship.php create mode 100644 include/generic/LayoutManager.php create mode 100644 include/generic/Save2.php create mode 100644 include/generic/SugarWidgets/SugarWidget.php create mode 100644 include/generic/SugarWidgets/SugarWidgetField.php create mode 100644 include/generic/SugarWidgets/SugarWidgetFieldbool.php create mode 100644 include/generic/SugarWidgets/SugarWidgetFieldchar.php create mode 100644 include/generic/SugarWidgets/SugarWidgetFieldcurrency.php create mode 100644 include/generic/SugarWidgets/SugarWidgetFielddate.php create mode 100644 include/generic/SugarWidgets/SugarWidgetFielddatepicker.php create mode 100644 include/generic/SugarWidgets/SugarWidgetFielddatetime.php create mode 100644 include/generic/SugarWidgets/SugarWidgetFielddatetimecombo.php create mode 100644 include/generic/SugarWidgets/SugarWidgetFielddecimal.php create mode 100644 include/generic/SugarWidgets/SugarWidgetFielddouble.php create mode 100644 include/generic/SugarWidgets/SugarWidgetFieldemail.php create mode 100644 include/generic/SugarWidgets/SugarWidgetFieldenum.php create mode 100644 include/generic/SugarWidgets/SugarWidgetFieldfile.php create mode 100644 include/generic/SugarWidgets/SugarWidgetFieldfloat.php create mode 100644 include/generic/SugarWidgets/SugarWidgetFieldfullname.php create mode 100644 include/generic/SugarWidgets/SugarWidgetFieldid.php create mode 100644 include/generic/SugarWidgets/SugarWidgetFieldimage.php create mode 100644 include/generic/SugarWidgets/SugarWidgetFieldint.php create mode 100644 include/generic/SugarWidgets/SugarWidgetFieldlongtext.php create mode 100644 include/generic/SugarWidgets/SugarWidgetFieldmultienum.php create mode 100644 include/generic/SugarWidgets/SugarWidgetFieldname.php create mode 100644 include/generic/SugarWidgets/SugarWidgetFieldnum.php create mode 100644 include/generic/SugarWidgets/SugarWidgetFieldparent_type.php create mode 100644 include/generic/SugarWidgets/SugarWidgetFieldphone.php create mode 100644 include/generic/SugarWidgets/SugarWidgetFieldradioenum.php create mode 100644 include/generic/SugarWidgets/SugarWidgetFieldrelate.php create mode 100644 include/generic/SugarWidgets/SugarWidgetFieldsingleenum.php create mode 100644 include/generic/SugarWidgets/SugarWidgetFieldtext.php create mode 100644 include/generic/SugarWidgets/SugarWidgetFieldtime.php create mode 100644 include/generic/SugarWidgets/SugarWidgetFieldurl.php create mode 100644 include/generic/SugarWidgets/SugarWidgetFielduser_name.php create mode 100644 include/generic/SugarWidgets/SugarWidgetFieldvarchar.php create mode 100644 include/generic/SugarWidgets/SugarWidgetReportField.php create mode 100644 include/generic/SugarWidgets/SugarWidgetSubPanelActivitiesStatusField.php create mode 100644 include/generic/SugarWidgets/SugarWidgetSubPanelCloseButton.php create mode 100644 include/generic/SugarWidgets/SugarWidgetSubPanelConcat.php create mode 100644 include/generic/SugarWidgets/SugarWidgetSubPanelDetailViewLink.php create mode 100644 include/generic/SugarWidgets/SugarWidgetSubPanelEditButton.php create mode 100644 include/generic/SugarWidgets/SugarWidgetSubPanelEditRoleButton.php create mode 100644 include/generic/SugarWidgets/SugarWidgetSubPanelEmailLink.php create mode 100644 include/generic/SugarWidgets/SugarWidgetSubPanelGetLatestButton.php create mode 100644 include/generic/SugarWidgets/SugarWidgetSubPanelIcon.php create mode 100644 include/generic/SugarWidgets/SugarWidgetSubPanelLoadSignedButton.php create mode 100644 include/generic/SugarWidgets/SugarWidgetSubPanelRemoveButton.php create mode 100644 include/generic/SugarWidgets/SugarWidgetSubPanelRemoveButtonMeetings.php create mode 100644 include/generic/SugarWidgets/SugarWidgetSubPanelRemoveButtonProjects.php create mode 100644 include/generic/SugarWidgets/SugarWidgetSubPanelTopArchiveEmailButton.php create mode 100644 include/generic/SugarWidgets/SugarWidgetSubPanelTopButton.php create mode 100644 include/generic/SugarWidgets/SugarWidgetSubPanelTopButtonQuickCreate.php create mode 100644 include/generic/SugarWidgets/SugarWidgetSubPanelTopComposeEmailButton.php create mode 100644 include/generic/SugarWidgets/SugarWidgetSubPanelTopCreateAccountNameButton.php create mode 100644 include/generic/SugarWidgets/SugarWidgetSubPanelTopCreateCampaignLogEntryButton.php create mode 100644 include/generic/SugarWidgets/SugarWidgetSubPanelTopCreateLeadNameButton.php create mode 100644 include/generic/SugarWidgets/SugarWidgetSubPanelTopCreateNoteButton.php create mode 100644 include/generic/SugarWidgets/SugarWidgetSubPanelTopCreateTaskButton.php create mode 100644 include/generic/SugarWidgets/SugarWidgetSubPanelTopScheduleCallButton.php create mode 100644 include/generic/SugarWidgets/SugarWidgetSubPanelTopScheduleMeetingButton.php create mode 100644 include/generic/SugarWidgets/SugarWidgetSubPanelTopSelectButton.php create mode 100644 include/generic/SugarWidgets/SugarWidgetSubPanelTopSelectContactsButton.php create mode 100644 include/generic/SugarWidgets/SugarWidgetSubPanelTopSelectUsersButton.php create mode 100644 include/generic/SugarWidgets/SugarWidgetSubPanelTopSummaryButton.php create mode 100644 include/globalControlLinks.php create mode 100644 include/images/1.gif create mode 100644 include/images/SugarPlanet.swf create mode 100644 include/images/blank.gif create mode 100644 include/images/cube_bg.gif create mode 100644 include/images/default_user_feed_picture.png create mode 100644 include/images/docs.png create mode 100644 include/images/forums.png create mode 100644 include/images/install_themes.jpg create mode 100644 include/images/iphone-listArrow.png create mode 100644 include/images/iphone-toolbar.png create mode 100644 include/images/kb.png create mode 100644 include/images/options.gif create mode 100644 include/images/options_up.gif create mode 100644 include/images/powered_by_sugarcrm.gif create mode 100644 include/images/poweredby_sugarcrm.png create mode 100644 include/images/rss_xml.gif create mode 100644 include/images/seed_chris_id.gif create mode 100644 include/images/seed_jim_id.gif create mode 100644 include/images/seed_max_id.gif create mode 100644 include/images/seed_sally_id.gif create mode 100644 include/images/seed_sarah_id.gif create mode 100644 include/images/seed_will_id.gif create mode 100644 include/images/spacer.png create mode 100644 include/images/sugar_icon.ico create mode 100644 include/images/sugar_md_open.png create mode 100644 include/images/sugar_wizard_welcome.jpg create mode 100644 include/images/sugarcrm_about_logo.gif create mode 100644 include/images/sugarcrm_copyright_logo.jpg create mode 100644 include/images/sugarcrm_login.png create mode 100644 include/images/sugarsales_myarea.png create mode 100644 include/images/university.png create mode 100644 include/images/wiki.png create mode 100644 include/javascript/calendar.js create mode 100644 include/javascript/cookie.js create mode 100644 include/javascript/dashlets.js create mode 100644 include/javascript/getYUIComboFile.php create mode 100644 include/javascript/include.js create mode 100644 include/javascript/iscroll.js create mode 100644 include/javascript/javascript.php create mode 100644 include/javascript/jsAlerts.php create mode 100644 include/javascript/jsclass_async.js create mode 100644 include/javascript/jsclass_base.js create mode 100644 include/javascript/menu.js create mode 100644 include/javascript/overlibmws.js create mode 100644 include/javascript/overlibmws_iframe.js create mode 100644 include/javascript/popup_helper.js create mode 100644 include/javascript/popup_parent_helper.js create mode 100644 include/javascript/quickCompose.js create mode 100644 include/javascript/quicksearch.js create mode 100644 include/javascript/report_additionals.js create mode 100644 include/javascript/sugar_3.js create mode 100644 include/javascript/sugar_connection_event_listener.js create mode 100644 include/javascript/sugar_grp1.js create mode 100644 include/javascript/sugar_grp1_yui.js create mode 100644 include/javascript/sugar_grp_emails.js create mode 100644 include/javascript/sugar_grp_overlib.js create mode 100644 include/javascript/sugar_grp_quickcomp.js create mode 100644 include/javascript/sugar_grp_yui2.js create mode 100644 include/javascript/sugar_grp_yui_widgets.css create mode 100644 include/javascript/sugar_grp_yui_widgets.js create mode 100644 include/javascript/sugarwidgets/SugarYUILoader.js create mode 100644 include/javascript/sugarwidgets/SugarYUIWidgets.js create mode 100644 include/javascript/swfobject.js create mode 100644 include/javascript/tiny_mce/langs/en.js create mode 100644 include/javascript/tiny_mce/license.txt create mode 100644 include/javascript/tiny_mce/plugins/advhr/css/advhr.css create mode 100644 include/javascript/tiny_mce/plugins/advhr/editor_plugin.js create mode 100644 include/javascript/tiny_mce/plugins/advhr/editor_plugin_src.js create mode 100644 include/javascript/tiny_mce/plugins/advhr/js/rule.js create mode 100644 include/javascript/tiny_mce/plugins/advhr/langs/en_dlg.js create mode 100644 include/javascript/tiny_mce/plugins/advhr/rule.htm create mode 100644 include/javascript/tiny_mce/plugins/advimage/css/advimage.css create mode 100644 include/javascript/tiny_mce/plugins/advimage/editor_plugin.js create mode 100644 include/javascript/tiny_mce/plugins/advimage/editor_plugin_src.js create mode 100644 include/javascript/tiny_mce/plugins/advimage/image.htm create mode 100644 include/javascript/tiny_mce/plugins/advimage/img/sample.gif create mode 100644 include/javascript/tiny_mce/plugins/advimage/js/image.js create mode 100644 include/javascript/tiny_mce/plugins/advimage/langs/en_dlg.js create mode 100644 include/javascript/tiny_mce/plugins/advlink/css/advlink.css create mode 100644 include/javascript/tiny_mce/plugins/advlink/editor_plugin.js create mode 100644 include/javascript/tiny_mce/plugins/advlink/editor_plugin_src.js create mode 100644 include/javascript/tiny_mce/plugins/advlink/js/advlink.js create mode 100644 include/javascript/tiny_mce/plugins/advlink/langs/en_dlg.js create mode 100644 include/javascript/tiny_mce/plugins/advlink/link.htm create mode 100644 include/javascript/tiny_mce/plugins/autosave/editor_plugin.js create mode 100644 include/javascript/tiny_mce/plugins/autosave/editor_plugin_src.js create mode 100644 include/javascript/tiny_mce/plugins/bbcode/editor_plugin.js create mode 100644 include/javascript/tiny_mce/plugins/bbcode/editor_plugin_src.js create mode 100644 include/javascript/tiny_mce/plugins/compat2x/editor_plugin.js create mode 100644 include/javascript/tiny_mce/plugins/compat2x/editor_plugin_src.js create mode 100644 include/javascript/tiny_mce/plugins/contextmenu/editor_plugin.js create mode 100644 include/javascript/tiny_mce/plugins/contextmenu/editor_plugin_src.js create mode 100644 include/javascript/tiny_mce/plugins/directionality/editor_plugin.js create mode 100644 include/javascript/tiny_mce/plugins/directionality/editor_plugin_src.js create mode 100644 include/javascript/tiny_mce/plugins/emotions/editor_plugin.js create mode 100644 include/javascript/tiny_mce/plugins/emotions/editor_plugin_src.js create mode 100644 include/javascript/tiny_mce/plugins/emotions/emotions.htm create mode 100644 include/javascript/tiny_mce/plugins/emotions/img/smiley-cool.gif create mode 100644 include/javascript/tiny_mce/plugins/emotions/img/smiley-cry.gif create mode 100644 include/javascript/tiny_mce/plugins/emotions/img/smiley-embarassed.gif create mode 100644 include/javascript/tiny_mce/plugins/emotions/img/smiley-foot-in-mouth.gif create mode 100644 include/javascript/tiny_mce/plugins/emotions/img/smiley-frown.gif create mode 100644 include/javascript/tiny_mce/plugins/emotions/img/smiley-innocent.gif create mode 100644 include/javascript/tiny_mce/plugins/emotions/img/smiley-kiss.gif create mode 100644 include/javascript/tiny_mce/plugins/emotions/img/smiley-laughing.gif create mode 100644 include/javascript/tiny_mce/plugins/emotions/img/smiley-money-mouth.gif create mode 100644 include/javascript/tiny_mce/plugins/emotions/img/smiley-sealed.gif create mode 100644 include/javascript/tiny_mce/plugins/emotions/img/smiley-smile.gif create mode 100644 include/javascript/tiny_mce/plugins/emotions/img/smiley-surprised.gif create mode 100644 include/javascript/tiny_mce/plugins/emotions/img/smiley-tongue-out.gif create mode 100644 include/javascript/tiny_mce/plugins/emotions/img/smiley-undecided.gif create mode 100644 include/javascript/tiny_mce/plugins/emotions/img/smiley-wink.gif create mode 100644 include/javascript/tiny_mce/plugins/emotions/img/smiley-yell.gif create mode 100644 include/javascript/tiny_mce/plugins/emotions/js/emotions.js create mode 100644 include/javascript/tiny_mce/plugins/emotions/langs/en_dlg.js create mode 100644 include/javascript/tiny_mce/plugins/example/dialog.htm create mode 100644 include/javascript/tiny_mce/plugins/example/editor_plugin.js create mode 100644 include/javascript/tiny_mce/plugins/example/editor_plugin_src.js create mode 100644 include/javascript/tiny_mce/plugins/example/img/example.gif create mode 100644 include/javascript/tiny_mce/plugins/example/js/dialog.js create mode 100644 include/javascript/tiny_mce/plugins/example/langs/en.js create mode 100644 include/javascript/tiny_mce/plugins/example/langs/en_dlg.js create mode 100644 include/javascript/tiny_mce/plugins/fullpage/css/fullpage.css create mode 100644 include/javascript/tiny_mce/plugins/fullpage/editor_plugin.js create mode 100644 include/javascript/tiny_mce/plugins/fullpage/editor_plugin_src.js create mode 100644 include/javascript/tiny_mce/plugins/fullpage/fullpage.htm create mode 100644 include/javascript/tiny_mce/plugins/fullpage/js/fullpage.js create mode 100644 include/javascript/tiny_mce/plugins/fullpage/langs/en_dlg.js create mode 100644 include/javascript/tiny_mce/plugins/fullscreen/editor_plugin.js create mode 100644 include/javascript/tiny_mce/plugins/fullscreen/editor_plugin_src.js create mode 100644 include/javascript/tiny_mce/plugins/fullscreen/fullscreen.htm create mode 100644 include/javascript/tiny_mce/plugins/iespell/editor_plugin.js create mode 100644 include/javascript/tiny_mce/plugins/iespell/editor_plugin_src.js create mode 100644 include/javascript/tiny_mce/plugins/inlinepopups/editor_plugin.js create mode 100644 include/javascript/tiny_mce/plugins/inlinepopups/editor_plugin_src.js create mode 100644 include/javascript/tiny_mce/plugins/inlinepopups/skins/clearlooks2/img/alert.gif create mode 100644 include/javascript/tiny_mce/plugins/inlinepopups/skins/clearlooks2/img/button.gif create mode 100644 include/javascript/tiny_mce/plugins/inlinepopups/skins/clearlooks2/img/buttons.gif create mode 100644 include/javascript/tiny_mce/plugins/inlinepopups/skins/clearlooks2/img/confirm.gif create mode 100644 include/javascript/tiny_mce/plugins/inlinepopups/skins/clearlooks2/img/corners.gif create mode 100644 include/javascript/tiny_mce/plugins/inlinepopups/skins/clearlooks2/img/horizontal.gif create mode 100644 include/javascript/tiny_mce/plugins/inlinepopups/skins/clearlooks2/img/vertical.gif create mode 100644 include/javascript/tiny_mce/plugins/inlinepopups/skins/clearlooks2/window.css create mode 100644 include/javascript/tiny_mce/plugins/inlinepopups/template.htm create mode 100644 include/javascript/tiny_mce/plugins/insertdatetime/editor_plugin.js create mode 100644 include/javascript/tiny_mce/plugins/insertdatetime/editor_plugin_src.js create mode 100644 include/javascript/tiny_mce/plugins/layer/editor_plugin.js create mode 100644 include/javascript/tiny_mce/plugins/layer/editor_plugin_src.js create mode 100644 include/javascript/tiny_mce/plugins/media/css/content.css create mode 100644 include/javascript/tiny_mce/plugins/media/css/media.css create mode 100644 include/javascript/tiny_mce/plugins/media/editor_plugin.js create mode 100644 include/javascript/tiny_mce/plugins/media/editor_plugin_src.js create mode 100644 include/javascript/tiny_mce/plugins/media/img/flash.gif create mode 100644 include/javascript/tiny_mce/plugins/media/img/flv_player.swf create mode 100644 include/javascript/tiny_mce/plugins/media/img/quicktime.gif create mode 100644 include/javascript/tiny_mce/plugins/media/img/realmedia.gif create mode 100644 include/javascript/tiny_mce/plugins/media/img/shockwave.gif create mode 100644 include/javascript/tiny_mce/plugins/media/img/trans.gif create mode 100644 include/javascript/tiny_mce/plugins/media/img/windowsmedia.gif create mode 100644 include/javascript/tiny_mce/plugins/media/js/embed.js create mode 100644 include/javascript/tiny_mce/plugins/media/js/media.js create mode 100644 include/javascript/tiny_mce/plugins/media/langs/en_dlg.js create mode 100644 include/javascript/tiny_mce/plugins/media/media.htm create mode 100644 include/javascript/tiny_mce/plugins/nonbreaking/editor_plugin.js create mode 100644 include/javascript/tiny_mce/plugins/nonbreaking/editor_plugin_src.js create mode 100644 include/javascript/tiny_mce/plugins/noneditable/editor_plugin.js create mode 100644 include/javascript/tiny_mce/plugins/noneditable/editor_plugin_src.js create mode 100644 include/javascript/tiny_mce/plugins/pagebreak/css/content.css create mode 100644 include/javascript/tiny_mce/plugins/pagebreak/editor_plugin.js create mode 100644 include/javascript/tiny_mce/plugins/pagebreak/editor_plugin_src.js create mode 100644 include/javascript/tiny_mce/plugins/pagebreak/img/pagebreak.gif create mode 100644 include/javascript/tiny_mce/plugins/pagebreak/img/trans.gif create mode 100644 include/javascript/tiny_mce/plugins/paste/blank.htm create mode 100644 include/javascript/tiny_mce/plugins/paste/css/blank.css create mode 100644 include/javascript/tiny_mce/plugins/paste/css/pasteword.css create mode 100644 include/javascript/tiny_mce/plugins/paste/editor_plugin.js create mode 100644 include/javascript/tiny_mce/plugins/paste/editor_plugin_src.js create mode 100644 include/javascript/tiny_mce/plugins/paste/js/pastetext.js create mode 100644 include/javascript/tiny_mce/plugins/paste/js/pasteword.js create mode 100644 include/javascript/tiny_mce/plugins/paste/langs/en_dlg.js create mode 100644 include/javascript/tiny_mce/plugins/paste/pastetext.htm create mode 100644 include/javascript/tiny_mce/plugins/paste/pasteword.htm create mode 100644 include/javascript/tiny_mce/plugins/preview/editor_plugin.js create mode 100644 include/javascript/tiny_mce/plugins/preview/editor_plugin_src.js create mode 100644 include/javascript/tiny_mce/plugins/preview/example.html create mode 100644 include/javascript/tiny_mce/plugins/preview/jscripts/embed.js create mode 100644 include/javascript/tiny_mce/plugins/preview/preview.html create mode 100644 include/javascript/tiny_mce/plugins/print/editor_plugin.js create mode 100644 include/javascript/tiny_mce/plugins/print/editor_plugin_src.js create mode 100644 include/javascript/tiny_mce/plugins/safari/blank.htm create mode 100644 include/javascript/tiny_mce/plugins/safari/editor_plugin.js create mode 100644 include/javascript/tiny_mce/plugins/safari/editor_plugin_src.js create mode 100644 include/javascript/tiny_mce/plugins/save/editor_plugin.js create mode 100644 include/javascript/tiny_mce/plugins/save/editor_plugin_src.js create mode 100644 include/javascript/tiny_mce/plugins/searchreplace/css/searchreplace.css create mode 100644 include/javascript/tiny_mce/plugins/searchreplace/editor_plugin.js create mode 100644 include/javascript/tiny_mce/plugins/searchreplace/editor_plugin_src.js create mode 100644 include/javascript/tiny_mce/plugins/searchreplace/js/searchreplace.js create mode 100644 include/javascript/tiny_mce/plugins/searchreplace/langs/en_dlg.js create mode 100644 include/javascript/tiny_mce/plugins/searchreplace/searchreplace.htm create mode 100644 include/javascript/tiny_mce/plugins/spellchecker/css/content.css create mode 100644 include/javascript/tiny_mce/plugins/spellchecker/editor_plugin.js create mode 100644 include/javascript/tiny_mce/plugins/spellchecker/editor_plugin_src.js create mode 100644 include/javascript/tiny_mce/plugins/spellchecker/img/wline.gif create mode 100644 include/javascript/tiny_mce/plugins/style/css/props.css create mode 100644 include/javascript/tiny_mce/plugins/style/editor_plugin.js create mode 100644 include/javascript/tiny_mce/plugins/style/editor_plugin_src.js create mode 100644 include/javascript/tiny_mce/plugins/style/js/props.js create mode 100644 include/javascript/tiny_mce/plugins/style/langs/en_dlg.js create mode 100644 include/javascript/tiny_mce/plugins/style/props.htm create mode 100644 include/javascript/tiny_mce/plugins/table/cell.htm create mode 100644 include/javascript/tiny_mce/plugins/table/css/cell.css create mode 100644 include/javascript/tiny_mce/plugins/table/css/row.css create mode 100644 include/javascript/tiny_mce/plugins/table/css/table.css create mode 100644 include/javascript/tiny_mce/plugins/table/editor_plugin.js create mode 100644 include/javascript/tiny_mce/plugins/table/editor_plugin_src.js create mode 100644 include/javascript/tiny_mce/plugins/table/js/cell.js create mode 100644 include/javascript/tiny_mce/plugins/table/js/merge_cells.js create mode 100644 include/javascript/tiny_mce/plugins/table/js/row.js create mode 100644 include/javascript/tiny_mce/plugins/table/js/table.js create mode 100644 include/javascript/tiny_mce/plugins/table/langs/en_dlg.js create mode 100644 include/javascript/tiny_mce/plugins/table/merge_cells.htm create mode 100644 include/javascript/tiny_mce/plugins/table/row.htm create mode 100644 include/javascript/tiny_mce/plugins/table/table.htm create mode 100644 include/javascript/tiny_mce/plugins/template/blank.htm create mode 100644 include/javascript/tiny_mce/plugins/template/css/template.css create mode 100644 include/javascript/tiny_mce/plugins/template/editor_plugin.js create mode 100644 include/javascript/tiny_mce/plugins/template/editor_plugin_src.js create mode 100644 include/javascript/tiny_mce/plugins/template/js/template.js create mode 100644 include/javascript/tiny_mce/plugins/template/langs/en_dlg.js create mode 100644 include/javascript/tiny_mce/plugins/template/template.htm create mode 100644 include/javascript/tiny_mce/plugins/visualchars/editor_plugin.js create mode 100644 include/javascript/tiny_mce/plugins/visualchars/editor_plugin_src.js create mode 100644 include/javascript/tiny_mce/plugins/xhtmlxtras/abbr.htm create mode 100644 include/javascript/tiny_mce/plugins/xhtmlxtras/acronym.htm create mode 100644 include/javascript/tiny_mce/plugins/xhtmlxtras/attributes.htm create mode 100644 include/javascript/tiny_mce/plugins/xhtmlxtras/cite.htm create mode 100644 include/javascript/tiny_mce/plugins/xhtmlxtras/css/attributes.css create mode 100644 include/javascript/tiny_mce/plugins/xhtmlxtras/css/popup.css create mode 100644 include/javascript/tiny_mce/plugins/xhtmlxtras/del.htm create mode 100644 include/javascript/tiny_mce/plugins/xhtmlxtras/editor_plugin.js create mode 100644 include/javascript/tiny_mce/plugins/xhtmlxtras/editor_plugin_src.js create mode 100644 include/javascript/tiny_mce/plugins/xhtmlxtras/ins.htm create mode 100644 include/javascript/tiny_mce/plugins/xhtmlxtras/js/abbr.js create mode 100644 include/javascript/tiny_mce/plugins/xhtmlxtras/js/acronym.js create mode 100644 include/javascript/tiny_mce/plugins/xhtmlxtras/js/attributes.js create mode 100644 include/javascript/tiny_mce/plugins/xhtmlxtras/js/cite.js create mode 100644 include/javascript/tiny_mce/plugins/xhtmlxtras/js/del.js create mode 100644 include/javascript/tiny_mce/plugins/xhtmlxtras/js/element_common.js create mode 100644 include/javascript/tiny_mce/plugins/xhtmlxtras/js/ins.js create mode 100644 include/javascript/tiny_mce/plugins/xhtmlxtras/langs/en_dlg.js create mode 100644 include/javascript/tiny_mce/themes/advanced/about.htm create mode 100644 include/javascript/tiny_mce/themes/advanced/anchor.htm create mode 100644 include/javascript/tiny_mce/themes/advanced/charmap.htm create mode 100644 include/javascript/tiny_mce/themes/advanced/color_picker.htm create mode 100644 include/javascript/tiny_mce/themes/advanced/editor_template.js create mode 100644 include/javascript/tiny_mce/themes/advanced/editor_template_src.js create mode 100644 include/javascript/tiny_mce/themes/advanced/image.htm create mode 100644 include/javascript/tiny_mce/themes/advanced/img/colorpicker.jpg create mode 100644 include/javascript/tiny_mce/themes/advanced/img/icons.gif create mode 100644 include/javascript/tiny_mce/themes/advanced/js/about.js create mode 100644 include/javascript/tiny_mce/themes/advanced/js/anchor.js create mode 100644 include/javascript/tiny_mce/themes/advanced/js/charmap.js create mode 100644 include/javascript/tiny_mce/themes/advanced/js/color_picker.js create mode 100644 include/javascript/tiny_mce/themes/advanced/js/image.js create mode 100644 include/javascript/tiny_mce/themes/advanced/js/link.js create mode 100644 include/javascript/tiny_mce/themes/advanced/js/source_editor.js create mode 100644 include/javascript/tiny_mce/themes/advanced/langs/en.js create mode 100644 include/javascript/tiny_mce/themes/advanced/langs/en_dlg.js create mode 100644 include/javascript/tiny_mce/themes/advanced/link.htm create mode 100644 include/javascript/tiny_mce/themes/advanced/skins/default/content.css create mode 100644 include/javascript/tiny_mce/themes/advanced/skins/default/dialog.css create mode 100644 include/javascript/tiny_mce/themes/advanced/skins/default/img/buttons.png create mode 100644 include/javascript/tiny_mce/themes/advanced/skins/default/img/items.gif create mode 100644 include/javascript/tiny_mce/themes/advanced/skins/default/img/menu_arrow.gif create mode 100644 include/javascript/tiny_mce/themes/advanced/skins/default/img/menu_check.gif create mode 100644 include/javascript/tiny_mce/themes/advanced/skins/default/img/progress.gif create mode 100644 include/javascript/tiny_mce/themes/advanced/skins/default/img/tabs.gif create mode 100644 include/javascript/tiny_mce/themes/advanced/skins/default/ui.css create mode 100644 include/javascript/tiny_mce/themes/advanced/skins/o2k7/content.css create mode 100644 include/javascript/tiny_mce/themes/advanced/skins/o2k7/dialog.css create mode 100644 include/javascript/tiny_mce/themes/advanced/skins/o2k7/img/button_bg.png create mode 100644 include/javascript/tiny_mce/themes/advanced/skins/o2k7/img/button_bg_black.png create mode 100644 include/javascript/tiny_mce/themes/advanced/skins/o2k7/img/button_bg_silver.png create mode 100644 include/javascript/tiny_mce/themes/advanced/skins/o2k7/ui.css create mode 100644 include/javascript/tiny_mce/themes/advanced/skins/o2k7/ui_black.css create mode 100644 include/javascript/tiny_mce/themes/advanced/skins/o2k7/ui_silver.css create mode 100644 include/javascript/tiny_mce/themes/advanced/source_editor.htm create mode 100644 include/javascript/tiny_mce/themes/simple/editor_template.js create mode 100644 include/javascript/tiny_mce/themes/simple/editor_template_src.js create mode 100644 include/javascript/tiny_mce/themes/simple/img/icons.gif create mode 100644 include/javascript/tiny_mce/themes/simple/langs/en.js create mode 100644 include/javascript/tiny_mce/themes/simple/skins/default/content.css create mode 100644 include/javascript/tiny_mce/themes/simple/skins/default/ui.css create mode 100644 include/javascript/tiny_mce/themes/simple/skins/o2k7/content.css create mode 100644 include/javascript/tiny_mce/themes/simple/skins/o2k7/img/button_bg.png create mode 100644 include/javascript/tiny_mce/themes/simple/skins/o2k7/ui.css create mode 100644 include/javascript/tiny_mce/tiny_mce.js create mode 100644 include/javascript/tiny_mce/tiny_mce_popup.js create mode 100644 include/javascript/tiny_mce/tiny_mce_src.js create mode 100644 include/javascript/tiny_mce/utils/editable_selects.js create mode 100644 include/javascript/tiny_mce/utils/form_utils.js create mode 100644 include/javascript/tiny_mce/utils/mctabs.js create mode 100644 include/javascript/tiny_mce/utils/validate.js create mode 100644 include/javascript/yui/LICENSE.txt create mode 100644 include/javascript/yui/README create mode 100644 include/javascript/yui/build/animation/animation-min.js create mode 100644 include/javascript/yui/build/animation/animation.js create mode 100644 include/javascript/yui/build/assets/skins/sam/ajax-loader.gif create mode 100644 include/javascript/yui/build/assets/skins/sam/asc.gif create mode 100644 include/javascript/yui/build/assets/skins/sam/autocomplete.css create mode 100644 include/javascript/yui/build/assets/skins/sam/back-h.png create mode 100644 include/javascript/yui/build/assets/skins/sam/back-v.png create mode 100644 include/javascript/yui/build/assets/skins/sam/bar-h.png create mode 100644 include/javascript/yui/build/assets/skins/sam/bar-v.png create mode 100644 include/javascript/yui/build/assets/skins/sam/bg-h.gif create mode 100644 include/javascript/yui/build/assets/skins/sam/bg-v.gif create mode 100644 include/javascript/yui/build/assets/skins/sam/blankimage.png create mode 100644 include/javascript/yui/build/assets/skins/sam/button.css create mode 100644 include/javascript/yui/build/assets/skins/sam/calendar.css create mode 100644 include/javascript/yui/build/assets/skins/sam/carousel.css create mode 100644 include/javascript/yui/build/assets/skins/sam/check0.gif create mode 100644 include/javascript/yui/build/assets/skins/sam/check1.gif create mode 100644 include/javascript/yui/build/assets/skins/sam/check2.gif create mode 100644 include/javascript/yui/build/assets/skins/sam/colorpicker.css create mode 100644 include/javascript/yui/build/assets/skins/sam/container.css create mode 100644 include/javascript/yui/build/assets/skins/sam/datatable.css create mode 100644 include/javascript/yui/build/assets/skins/sam/desc.gif create mode 100644 include/javascript/yui/build/assets/skins/sam/dt-arrow-dn.png create mode 100644 include/javascript/yui/build/assets/skins/sam/dt-arrow-up.png create mode 100644 include/javascript/yui/build/assets/skins/sam/editor-knob.gif create mode 100644 include/javascript/yui/build/assets/skins/sam/editor-sprite-active.gif create mode 100644 include/javascript/yui/build/assets/skins/sam/editor-sprite.gif create mode 100644 include/javascript/yui/build/assets/skins/sam/editor.css create mode 100644 include/javascript/yui/build/assets/skins/sam/header_background.png create mode 100644 include/javascript/yui/build/assets/skins/sam/hue_bg.png create mode 100644 include/javascript/yui/build/assets/skins/sam/imagecropper.css create mode 100644 include/javascript/yui/build/assets/skins/sam/layout.css create mode 100644 include/javascript/yui/build/assets/skins/sam/layout_sprite.png create mode 100644 include/javascript/yui/build/assets/skins/sam/loading.gif create mode 100644 include/javascript/yui/build/assets/skins/sam/logger.css create mode 100644 include/javascript/yui/build/assets/skins/sam/menu-button-arrow-disabled.png create mode 100644 include/javascript/yui/build/assets/skins/sam/menu-button-arrow.png create mode 100644 include/javascript/yui/build/assets/skins/sam/menu.css create mode 100644 include/javascript/yui/build/assets/skins/sam/menubaritem_submenuindicator.png create mode 100644 include/javascript/yui/build/assets/skins/sam/menubaritem_submenuindicator_disabled.png create mode 100644 include/javascript/yui/build/assets/skins/sam/menuitem_checkbox.png create mode 100644 include/javascript/yui/build/assets/skins/sam/menuitem_checkbox_disabled.png create mode 100644 include/javascript/yui/build/assets/skins/sam/menuitem_submenuindicator.png create mode 100644 include/javascript/yui/build/assets/skins/sam/menuitem_submenuindicator_disabled.png create mode 100644 include/javascript/yui/build/assets/skins/sam/paginator.css create mode 100644 include/javascript/yui/build/assets/skins/sam/picker_mask.png create mode 100644 include/javascript/yui/build/assets/skins/sam/profilerviewer.css create mode 100644 include/javascript/yui/build/assets/skins/sam/progressbar.css create mode 100644 include/javascript/yui/build/assets/skins/sam/resize.css create mode 100644 include/javascript/yui/build/assets/skins/sam/simpleeditor.css create mode 100644 include/javascript/yui/build/assets/skins/sam/skin.css create mode 100644 include/javascript/yui/build/assets/skins/sam/slider.css create mode 100644 include/javascript/yui/build/assets/skins/sam/split-button-arrow-active.png create mode 100644 include/javascript/yui/build/assets/skins/sam/split-button-arrow-disabled.png create mode 100644 include/javascript/yui/build/assets/skins/sam/split-button-arrow-focus.png create mode 100644 include/javascript/yui/build/assets/skins/sam/split-button-arrow-hover.png create mode 100644 include/javascript/yui/build/assets/skins/sam/split-button-arrow.png create mode 100644 include/javascript/yui/build/assets/skins/sam/sprite.png create mode 100644 include/javascript/yui/build/assets/skins/sam/sprite.psd create mode 100644 include/javascript/yui/build/assets/skins/sam/tabview.css create mode 100644 include/javascript/yui/build/assets/skins/sam/treeview-loading.gif create mode 100644 include/javascript/yui/build/assets/skins/sam/treeview-sprite.gif create mode 100644 include/javascript/yui/build/assets/skins/sam/treeview.css create mode 100644 include/javascript/yui/build/assets/skins/sam/wait.gif create mode 100644 include/javascript/yui/build/assets/skins/sam/yuitest.css create mode 100644 include/javascript/yui/build/autocomplete/assets/autocomplete-core.css create mode 100644 include/javascript/yui/build/autocomplete/assets/skins/sam/autocomplete-skin.css create mode 100644 include/javascript/yui/build/autocomplete/assets/skins/sam/autocomplete.css create mode 100644 include/javascript/yui/build/autocomplete/autocomplete-min.js create mode 100644 include/javascript/yui/build/autocomplete/autocomplete.js create mode 100644 include/javascript/yui/build/base/base-min.css create mode 100644 include/javascript/yui/build/base/base.css create mode 100644 include/javascript/yui/build/button/assets/button-core.css create mode 100644 include/javascript/yui/build/button/assets/skins/sam/button-skin.css create mode 100644 include/javascript/yui/build/button/assets/skins/sam/button.css create mode 100644 include/javascript/yui/build/button/assets/skins/sam/menu-button-arrow-disabled.png create mode 100644 include/javascript/yui/build/button/assets/skins/sam/menu-button-arrow.png create mode 100644 include/javascript/yui/build/button/assets/skins/sam/split-button-arrow-active.png create mode 100644 include/javascript/yui/build/button/assets/skins/sam/split-button-arrow-disabled.png create mode 100644 include/javascript/yui/build/button/assets/skins/sam/split-button-arrow-focus.png create mode 100644 include/javascript/yui/build/button/assets/skins/sam/split-button-arrow-hover.png create mode 100644 include/javascript/yui/build/button/assets/skins/sam/split-button-arrow.png create mode 100644 include/javascript/yui/build/button/button-min.js create mode 100644 include/javascript/yui/build/button/button.js create mode 100644 include/javascript/yui/build/calendar/assets/calendar-core.css create mode 100644 include/javascript/yui/build/calendar/assets/calendar.css create mode 100644 include/javascript/yui/build/calendar/assets/calgrad.png create mode 100644 include/javascript/yui/build/calendar/assets/callt.gif create mode 100644 include/javascript/yui/build/calendar/assets/calrt.gif create mode 100644 include/javascript/yui/build/calendar/assets/calx.gif create mode 100644 include/javascript/yui/build/calendar/assets/skins/sam/calendar-skin.css create mode 100644 include/javascript/yui/build/calendar/assets/skins/sam/calendar.css create mode 100644 include/javascript/yui/build/calendar/calendar-min.js create mode 100644 include/javascript/yui/build/calendar/calendar.js create mode 100644 include/javascript/yui/build/carousel/assets/ajax-loader.gif create mode 100644 include/javascript/yui/build/carousel/assets/carousel-core.css create mode 100644 include/javascript/yui/build/carousel/assets/skins/sam/ajax-loader.gif create mode 100644 include/javascript/yui/build/carousel/assets/skins/sam/carousel-skin.css create mode 100644 include/javascript/yui/build/carousel/assets/skins/sam/carousel.css create mode 100644 include/javascript/yui/build/carousel/carousel-min.js create mode 100644 include/javascript/yui/build/carousel/carousel.js create mode 100644 include/javascript/yui/build/charts/assets/charts.swf create mode 100644 include/javascript/yui/build/charts/charts-min.js create mode 100644 include/javascript/yui/build/charts/charts.js create mode 100644 include/javascript/yui/build/colorpicker/assets/colorpicker-core.css create mode 100644 include/javascript/yui/build/colorpicker/assets/hue_thumb.png create mode 100644 include/javascript/yui/build/colorpicker/assets/picker_mask.png create mode 100644 include/javascript/yui/build/colorpicker/assets/picker_thumb.png create mode 100644 include/javascript/yui/build/colorpicker/assets/skins/sam/colorpicker-skin.css create mode 100644 include/javascript/yui/build/colorpicker/assets/skins/sam/colorpicker.css create mode 100644 include/javascript/yui/build/colorpicker/assets/skins/sam/hue_bg.png create mode 100644 include/javascript/yui/build/colorpicker/assets/skins/sam/picker_mask.png create mode 100644 include/javascript/yui/build/colorpicker/colorpicker-min.js create mode 100644 include/javascript/yui/build/colorpicker/colorpicker.js create mode 100644 include/javascript/yui/build/connection/connection-min.js create mode 100644 include/javascript/yui/build/connection/connection.js create mode 100644 include/javascript/yui/build/connection/connection.swf create mode 100644 include/javascript/yui/build/connection/connection_core-debug.js create mode 100644 include/javascript/yui/build/connection/connection_core-min.js create mode 100644 include/javascript/yui/build/connection/connection_core.js create mode 100644 include/javascript/yui/build/container/assets/alrt16_1.gif create mode 100644 include/javascript/yui/build/container/assets/blck16_1.gif create mode 100644 include/javascript/yui/build/container/assets/close12_1.gif create mode 100644 include/javascript/yui/build/container/assets/container-core.css create mode 100644 include/javascript/yui/build/container/assets/container.css create mode 100644 include/javascript/yui/build/container/assets/hlp16_1.gif create mode 100644 include/javascript/yui/build/container/assets/info16_1.gif create mode 100644 include/javascript/yui/build/container/assets/skins/sam/container-skin.css create mode 100644 include/javascript/yui/build/container/assets/skins/sam/container.css create mode 100644 include/javascript/yui/build/container/assets/tip16_1.gif create mode 100644 include/javascript/yui/build/container/assets/warn16_1.gif create mode 100644 include/javascript/yui/build/container/container-min.js create mode 100644 include/javascript/yui/build/container/container.js create mode 100644 include/javascript/yui/build/container/container_core-min.js create mode 100644 include/javascript/yui/build/cookie/cookie-min.js create mode 100644 include/javascript/yui/build/cookie/cookie.js create mode 100644 include/javascript/yui/build/datasource/datasource-min.js create mode 100644 include/javascript/yui/build/datasource/datasource.js create mode 100644 include/javascript/yui/build/datatable/assets/datatable-core.css create mode 100644 include/javascript/yui/build/datatable/assets/datatable.css create mode 100644 include/javascript/yui/build/datatable/assets/skins/sam/datatable-skin.css create mode 100644 include/javascript/yui/build/datatable/assets/skins/sam/datatable.css create mode 100644 include/javascript/yui/build/datatable/assets/skins/sam/dt-arrow-dn.png create mode 100644 include/javascript/yui/build/datatable/assets/skins/sam/dt-arrow-up.png create mode 100644 include/javascript/yui/build/datatable/datatable-min.js create mode 100644 include/javascript/yui/build/datatable/datatable.js create mode 100644 include/javascript/yui/build/datemath/datemath-debug.js create mode 100644 include/javascript/yui/build/datemath/datemath-min.js create mode 100644 include/javascript/yui/build/datemath/datemath.js create mode 100644 include/javascript/yui/build/dom/dom-min.js create mode 100644 include/javascript/yui/build/dom/dom.js create mode 100644 include/javascript/yui/build/dragdrop/dragdrop-min.js create mode 100644 include/javascript/yui/build/dragdrop/dragdrop.js create mode 100644 include/javascript/yui/build/editor/assets/editor-core.css create mode 100644 include/javascript/yui/build/editor/assets/simpleeditor-core.css create mode 100644 include/javascript/yui/build/editor/assets/skins/sam/blankimage.png create mode 100644 include/javascript/yui/build/editor/assets/skins/sam/editor-knob.gif create mode 100644 include/javascript/yui/build/editor/assets/skins/sam/editor-skin.css create mode 100644 include/javascript/yui/build/editor/assets/skins/sam/editor-sprite-active.gif create mode 100644 include/javascript/yui/build/editor/assets/skins/sam/editor-sprite.gif create mode 100644 include/javascript/yui/build/editor/assets/skins/sam/editor.css create mode 100644 include/javascript/yui/build/editor/assets/skins/sam/simpleeditor-skin.css create mode 100644 include/javascript/yui/build/editor/assets/skins/sam/simpleeditor.css create mode 100644 include/javascript/yui/build/editor/editor-min.js create mode 100644 include/javascript/yui/build/editor/editor.js create mode 100644 include/javascript/yui/build/editor/simpleeditor-min.js create mode 100644 include/javascript/yui/build/editor/simpleeditor.js create mode 100644 include/javascript/yui/build/element-delegate/element-delegate-debug.js create mode 100644 include/javascript/yui/build/element-delegate/element-delegate-min.js create mode 100644 include/javascript/yui/build/element-delegate/element-delegate.js create mode 100644 include/javascript/yui/build/element/element-min.js create mode 100644 include/javascript/yui/build/element/element.js create mode 100644 include/javascript/yui/build/event-delegate/event-delegate-debug.js create mode 100644 include/javascript/yui/build/event-delegate/event-delegate-min.js create mode 100644 include/javascript/yui/build/event-delegate/event-delegate.js create mode 100644 include/javascript/yui/build/event-mouseenter/event-mouseenter-debug.js create mode 100644 include/javascript/yui/build/event-mouseenter/event-mouseenter-min.js create mode 100644 include/javascript/yui/build/event-mouseenter/event-mouseenter.js create mode 100644 include/javascript/yui/build/event-simulate/event-simulate-debug.js create mode 100644 include/javascript/yui/build/event-simulate/event-simulate-min.js create mode 100644 include/javascript/yui/build/event-simulate/event-simulate.js create mode 100644 include/javascript/yui/build/event/event-min.js create mode 100644 include/javascript/yui/build/event/event.js create mode 100644 include/javascript/yui/build/fonts/fonts-min.css create mode 100644 include/javascript/yui/build/fonts/fonts.css create mode 100644 include/javascript/yui/build/get/get-min.js create mode 100644 include/javascript/yui/build/get/get.js create mode 100644 include/javascript/yui/build/grids/grids-min.css create mode 100644 include/javascript/yui/build/grids/grids.css create mode 100644 include/javascript/yui/build/history/assets/blank.html create mode 100644 include/javascript/yui/build/history/history-min.js create mode 100644 include/javascript/yui/build/history/history.js create mode 100644 include/javascript/yui/build/imagecropper/assets/imagecropper-core.css create mode 100644 include/javascript/yui/build/imagecropper/assets/skins/sam/imagecropper-skin.css create mode 100644 include/javascript/yui/build/imagecropper/assets/skins/sam/imagecropper.css create mode 100644 include/javascript/yui/build/imagecropper/imagecropper-min.js create mode 100644 include/javascript/yui/build/imagecropper/imagecropper.js create mode 100644 include/javascript/yui/build/imageloader/imageloader-min.js create mode 100644 include/javascript/yui/build/imageloader/imageloader.js create mode 100644 include/javascript/yui/build/json/json-min.js create mode 100644 include/javascript/yui/build/json/json.js create mode 100644 include/javascript/yui/build/layout/assets/layout-core.css create mode 100644 include/javascript/yui/build/layout/assets/skins/sam/layout-skin.css create mode 100644 include/javascript/yui/build/layout/assets/skins/sam/layout.css create mode 100644 include/javascript/yui/build/layout/assets/skins/sam/layout_sprite.png create mode 100644 include/javascript/yui/build/layout/layout-min.js create mode 100644 include/javascript/yui/build/layout/layout.js create mode 100644 include/javascript/yui/build/logger/assets/logger-core.css create mode 100644 include/javascript/yui/build/logger/assets/logger.css create mode 100644 include/javascript/yui/build/logger/assets/skins/sam/logger-skin.css create mode 100644 include/javascript/yui/build/logger/assets/skins/sam/logger.css create mode 100644 include/javascript/yui/build/logger/logger-min.js create mode 100644 include/javascript/yui/build/logger/logger.js create mode 100644 include/javascript/yui/build/menu/assets/menu-core.css create mode 100644 include/javascript/yui/build/menu/assets/menu.css create mode 100644 include/javascript/yui/build/menu/assets/menu_down_arrow.png create mode 100644 include/javascript/yui/build/menu/assets/menu_down_arrow_disabled.png create mode 100644 include/javascript/yui/build/menu/assets/menu_up_arrow.png create mode 100644 include/javascript/yui/build/menu/assets/menu_up_arrow_disabled.png create mode 100644 include/javascript/yui/build/menu/assets/menubaritem_submenuindicator.png create mode 100644 include/javascript/yui/build/menu/assets/menubaritem_submenuindicator_disabled.png create mode 100644 include/javascript/yui/build/menu/assets/menubaritem_submenuindicator_selected.png create mode 100644 include/javascript/yui/build/menu/assets/menuitem_checkbox.png create mode 100644 include/javascript/yui/build/menu/assets/menuitem_checkbox_disabled.png create mode 100644 include/javascript/yui/build/menu/assets/menuitem_checkbox_selected.png create mode 100644 include/javascript/yui/build/menu/assets/menuitem_submenuindicator.png create mode 100644 include/javascript/yui/build/menu/assets/menuitem_submenuindicator_disabled.png create mode 100644 include/javascript/yui/build/menu/assets/menuitem_submenuindicator_selected.png create mode 100644 include/javascript/yui/build/menu/assets/skins/sam/menu-skin.css create mode 100644 include/javascript/yui/build/menu/assets/skins/sam/menu.css create mode 100644 include/javascript/yui/build/menu/assets/skins/sam/menubaritem_submenuindicator.png create mode 100644 include/javascript/yui/build/menu/assets/skins/sam/menubaritem_submenuindicator_disabled.png create mode 100644 include/javascript/yui/build/menu/assets/skins/sam/menuitem_checkbox.png create mode 100644 include/javascript/yui/build/menu/assets/skins/sam/menuitem_checkbox_disabled.png create mode 100644 include/javascript/yui/build/menu/assets/skins/sam/menuitem_submenuindicator.png create mode 100644 include/javascript/yui/build/menu/assets/skins/sam/menuitem_submenuindicator_disabled.png create mode 100644 include/javascript/yui/build/menu/menu-min.js create mode 100644 include/javascript/yui/build/menu/menu.js create mode 100644 include/javascript/yui/build/paginator/assets/paginator-core.css create mode 100644 include/javascript/yui/build/paginator/assets/skins/sam/paginator-skin.css create mode 100644 include/javascript/yui/build/paginator/assets/skins/sam/paginator.css create mode 100644 include/javascript/yui/build/paginator/paginator-min.js create mode 100644 include/javascript/yui/build/paginator/paginator.js create mode 100644 include/javascript/yui/build/profiler/profiler-min.js create mode 100644 include/javascript/yui/build/profiler/profiler.js create mode 100644 include/javascript/yui/build/profilerviewer/assets/profilerviewer-core.css create mode 100644 include/javascript/yui/build/profilerviewer/assets/skins/sam/asc.gif create mode 100644 include/javascript/yui/build/profilerviewer/assets/skins/sam/desc.gif create mode 100644 include/javascript/yui/build/profilerviewer/assets/skins/sam/header_background.png create mode 100644 include/javascript/yui/build/profilerviewer/assets/skins/sam/profilerviewer-skin.css create mode 100644 include/javascript/yui/build/profilerviewer/assets/skins/sam/profilerviewer.css create mode 100644 include/javascript/yui/build/profilerviewer/assets/skins/sam/wait.gif create mode 100644 include/javascript/yui/build/profilerviewer/profilerviewer-min.js create mode 100644 include/javascript/yui/build/profilerviewer/profilerviewer.js create mode 100644 include/javascript/yui/build/progressbar/assets/progressbar-core.css create mode 100644 include/javascript/yui/build/progressbar/assets/skins/sam/back-h.png create mode 100644 include/javascript/yui/build/progressbar/assets/skins/sam/back-v.png create mode 100644 include/javascript/yui/build/progressbar/assets/skins/sam/bar-h.png create mode 100644 include/javascript/yui/build/progressbar/assets/skins/sam/bar-v.png create mode 100644 include/javascript/yui/build/progressbar/assets/skins/sam/progressbar-skin.css create mode 100644 include/javascript/yui/build/progressbar/assets/skins/sam/progressbar.css create mode 100644 include/javascript/yui/build/progressbar/progressbar-debug.js create mode 100644 include/javascript/yui/build/progressbar/progressbar-min.js create mode 100644 include/javascript/yui/build/progressbar/progressbar.js create mode 100644 include/javascript/yui/build/reset-fonts-grids/reset-fonts-grids.css create mode 100644 include/javascript/yui/build/reset-fonts/reset-fonts.css create mode 100644 include/javascript/yui/build/reset/reset-min.css create mode 100644 include/javascript/yui/build/reset/reset.css create mode 100644 include/javascript/yui/build/resize/assets/resize-core.css create mode 100644 include/javascript/yui/build/resize/assets/skins/sam/layout_sprite.png create mode 100644 include/javascript/yui/build/resize/assets/skins/sam/resize-skin.css create mode 100644 include/javascript/yui/build/resize/assets/skins/sam/resize.css create mode 100644 include/javascript/yui/build/resize/resize-min.js create mode 100644 include/javascript/yui/build/resize/resize.js create mode 100644 include/javascript/yui/build/selector/selector-min.js create mode 100644 include/javascript/yui/build/selector/selector.js create mode 100644 include/javascript/yui/build/slider/assets/bg-fader.gif create mode 100644 include/javascript/yui/build/slider/assets/bg-h.gif create mode 100644 include/javascript/yui/build/slider/assets/bg-v-e.gif create mode 100644 include/javascript/yui/build/slider/assets/bg-v.gif create mode 100644 include/javascript/yui/build/slider/assets/left-thumb.png create mode 100644 include/javascript/yui/build/slider/assets/right-thumb.png create mode 100644 include/javascript/yui/build/slider/assets/skins/sam/bg-h.gif create mode 100644 include/javascript/yui/build/slider/assets/skins/sam/bg-v.gif create mode 100644 include/javascript/yui/build/slider/assets/skins/sam/slider-skin.css create mode 100644 include/javascript/yui/build/slider/assets/skins/sam/slider.css create mode 100644 include/javascript/yui/build/slider/assets/slider-core.css create mode 100644 include/javascript/yui/build/slider/assets/slider-skin.css create mode 100644 include/javascript/yui/build/slider/assets/thumb-bar.gif create mode 100644 include/javascript/yui/build/slider/assets/thumb-e.gif create mode 100644 include/javascript/yui/build/slider/assets/thumb-fader.gif create mode 100644 include/javascript/yui/build/slider/assets/thumb-n.gif create mode 100644 include/javascript/yui/build/slider/assets/thumb-s.gif create mode 100644 include/javascript/yui/build/slider/assets/thumb-w.gif create mode 100644 include/javascript/yui/build/slider/slider-min.js create mode 100644 include/javascript/yui/build/slider/slider.js create mode 100644 include/javascript/yui/build/storage/storage-debug.js create mode 100644 include/javascript/yui/build/storage/storage-min.js create mode 100644 include/javascript/yui/build/storage/storage.js create mode 100644 include/javascript/yui/build/stylesheet/stylesheet-debug.js create mode 100644 include/javascript/yui/build/stylesheet/stylesheet-min.js create mode 100644 include/javascript/yui/build/stylesheet/stylesheet.js create mode 100644 include/javascript/yui/build/swf/swf-debug.js create mode 100644 include/javascript/yui/build/swf/swf-min.js create mode 100644 include/javascript/yui/build/swf/swf.js create mode 100644 include/javascript/yui/build/swfdetect/swfdetect-debug.js create mode 100644 include/javascript/yui/build/swfdetect/swfdetect-min.js create mode 100644 include/javascript/yui/build/swfdetect/swfdetect.js create mode 100644 include/javascript/yui/build/swfstore/swf.js create mode 100644 include/javascript/yui/build/swfstore/swfstore-debug.js create mode 100644 include/javascript/yui/build/swfstore/swfstore-min.js create mode 100644 include/javascript/yui/build/swfstore/swfstore.js create mode 100644 include/javascript/yui/build/swfstore/swfstore.swf create mode 100644 include/javascript/yui/build/tabview/assets/border_tabs.css create mode 100644 include/javascript/yui/build/tabview/assets/loading.gif create mode 100644 include/javascript/yui/build/tabview/assets/skin-sam.css create mode 100644 include/javascript/yui/build/tabview/assets/skins/sam/tabview-skin.css create mode 100644 include/javascript/yui/build/tabview/assets/skins/sam/tabview.css create mode 100644 include/javascript/yui/build/tabview/assets/tabview-core.css create mode 100644 include/javascript/yui/build/tabview/assets/tabview.css create mode 100644 include/javascript/yui/build/tabview/tabview-min.js create mode 100644 include/javascript/yui/build/tabview/tabview.js create mode 100644 include/javascript/yui/build/treeview/assets/skins/sam/check0.gif create mode 100644 include/javascript/yui/build/treeview/assets/skins/sam/check1.gif create mode 100644 include/javascript/yui/build/treeview/assets/skins/sam/check2.gif create mode 100644 include/javascript/yui/build/treeview/assets/skins/sam/loading.gif create mode 100644 include/javascript/yui/build/treeview/assets/skins/sam/treeview-loading.gif create mode 100644 include/javascript/yui/build/treeview/assets/skins/sam/treeview-skin.css create mode 100644 include/javascript/yui/build/treeview/assets/skins/sam/treeview-sprite.gif create mode 100644 include/javascript/yui/build/treeview/assets/skins/sam/treeview.css create mode 100644 include/javascript/yui/build/treeview/assets/treeview-core.css create mode 100644 include/javascript/yui/build/treeview/treeview-min.js create mode 100644 include/javascript/yui/build/treeview/treeview.js create mode 100644 include/javascript/yui/build/uploader/assets/uploader.swf create mode 100644 include/javascript/yui/build/uploader/uploader-min.js create mode 100644 include/javascript/yui/build/uploader/uploader.js create mode 100644 include/javascript/yui/build/utilities/utilities.js create mode 100644 include/javascript/yui/build/yahoo-dom-event/yahoo-dom-event.js create mode 100644 include/javascript/yui/build/yahoo/yahoo-min.js create mode 100644 include/javascript/yui/build/yahoo/yahoo.js create mode 100644 include/javascript/yui/build/yuiloader-dom-event/yuiloader-dom-event.js create mode 100644 include/javascript/yui/build/yuiloader/yuiloader-min.js create mode 100644 include/javascript/yui/build/yuiloader/yuiloader.js create mode 100644 include/javascript/yui/build/yuitest/assets/skins/sam/yuitest-skin.css create mode 100644 include/javascript/yui/build/yuitest/assets/skins/sam/yuitest.css create mode 100644 include/javascript/yui/build/yuitest/assets/testlogger.css create mode 100644 include/javascript/yui/build/yuitest/assets/yuitest-core.css create mode 100644 include/javascript/yui/build/yuitest/yuitest-min.js create mode 100644 include/javascript/yui/build/yuitest/yuitest.js create mode 100644 include/javascript/yui/build/yuitest/yuitest_core-min.js create mode 100644 include/javascript/yui/build/yuitest/yuitest_core.js create mode 100644 include/javascript/yui/ext/yui-ext.js create mode 100644 include/javascript/yui/index.html create mode 100644 include/javascript/yui/ygDDList.js create mode 100644 include/javascript/yui3/README create mode 100644 include/javascript/yui3/assets/bg_hd.gif create mode 100644 include/javascript/yui3/assets/bullet-box6x6.gif create mode 100644 include/javascript/yui3/assets/bullet4x4.png create mode 100644 include/javascript/yui3/assets/cheatsheet-shadow.jpg create mode 100644 include/javascript/yui3/assets/cheatsheet-thumbnail.png create mode 100644 include/javascript/yui3/assets/download-arrow.png create mode 100644 include/javascript/yui3/assets/dpSyntaxHighlighter.css create mode 100644 include/javascript/yui3/assets/dpSyntaxHighlighter.js create mode 100644 include/javascript/yui3/assets/example-hd-bg.gif create mode 100644 include/javascript/yui3/assets/gradient-ex-box.png create mode 100644 include/javascript/yui3/assets/gradient-mod.png create mode 100644 include/javascript/yui3/assets/gradient-promo.png create mode 100644 include/javascript/yui3/assets/logo.gif create mode 100644 include/javascript/yui3/assets/syntax.js create mode 100644 include/javascript/yui3/assets/title_h_bg.gif create mode 100644 include/javascript/yui3/assets/yui-candy.jpg create mode 100644 include/javascript/yui3/assets/yui.css create mode 100644 include/javascript/yui3/assets/yui.gif create mode 100644 include/javascript/yui3/assets/yuiDistribution.css create mode 100644 include/javascript/yui3/build/anim/anim-base-min.js create mode 100644 include/javascript/yui3/build/anim/anim-base.js create mode 100644 include/javascript/yui3/build/anim/anim-color-min.js create mode 100644 include/javascript/yui3/build/anim/anim-color.js create mode 100644 include/javascript/yui3/build/anim/anim-curve-min.js create mode 100644 include/javascript/yui3/build/anim/anim-curve.js create mode 100644 include/javascript/yui3/build/anim/anim-easing-min.js create mode 100644 include/javascript/yui3/build/anim/anim-easing.js create mode 100644 include/javascript/yui3/build/anim/anim-min.js create mode 100644 include/javascript/yui3/build/anim/anim-node-plugin-min.js create mode 100644 include/javascript/yui3/build/anim/anim-node-plugin.js create mode 100644 include/javascript/yui3/build/anim/anim-scroll-min.js create mode 100644 include/javascript/yui3/build/anim/anim-scroll.js create mode 100644 include/javascript/yui3/build/anim/anim-xy-min.js create mode 100644 include/javascript/yui3/build/anim/anim-xy.js create mode 100644 include/javascript/yui3/build/anim/anim.js create mode 100644 include/javascript/yui3/build/assets/skins/sam/bg.png create mode 100644 include/javascript/yui3/build/assets/skins/sam/console-filters.css create mode 100644 include/javascript/yui3/build/assets/skins/sam/console.css create mode 100644 include/javascript/yui3/build/assets/skins/sam/horizontal-menu-submenu-indicator.png create mode 100644 include/javascript/yui3/build/assets/skins/sam/horizontal-menu-submenu-toggle.png create mode 100644 include/javascript/yui3/build/assets/skins/sam/node-menunav.css create mode 100644 include/javascript/yui3/build/assets/skins/sam/overlay.css create mode 100644 include/javascript/yui3/build/assets/skins/sam/rail-classic-x.png create mode 100644 include/javascript/yui3/build/assets/skins/sam/rail-classic-y.png create mode 100644 include/javascript/yui3/build/assets/skins/sam/skin.css create mode 100644 include/javascript/yui3/build/assets/skins/sam/slider.css create mode 100644 include/javascript/yui3/build/assets/skins/sam/sprite.png create mode 100644 include/javascript/yui3/build/assets/skins/sam/thumb-classic-x.png create mode 100644 include/javascript/yui3/build/assets/skins/sam/thumb-classic-y.png create mode 100644 include/javascript/yui3/build/assets/skins/sam/vertical-menu-submenu-indicator.png create mode 100644 include/javascript/yui3/build/assets/skins/sam/warn_error.png create mode 100644 include/javascript/yui3/build/assets/skins/sam/widget-stack.css create mode 100644 include/javascript/yui3/build/assets/skins/sam/widget.css create mode 100644 include/javascript/yui3/build/async-queue/async-queue-min.js create mode 100644 include/javascript/yui3/build/async-queue/async-queue.js create mode 100644 include/javascript/yui3/build/attribute/attribute-base-min.js create mode 100644 include/javascript/yui3/build/attribute/attribute-base.js create mode 100644 include/javascript/yui3/build/attribute/attribute-complex-min.js create mode 100644 include/javascript/yui3/build/attribute/attribute-complex.js create mode 100644 include/javascript/yui3/build/attribute/attribute-min.js create mode 100644 include/javascript/yui3/build/attribute/attribute.js create mode 100644 include/javascript/yui3/build/base/base-base-min.js create mode 100644 include/javascript/yui3/build/base/base-base.js create mode 100644 include/javascript/yui3/build/base/base-build-min.js create mode 100644 include/javascript/yui3/build/base/base-build.js create mode 100644 include/javascript/yui3/build/base/base-min.js create mode 100644 include/javascript/yui3/build/base/base-pluginhost-min.js create mode 100644 include/javascript/yui3/build/base/base-pluginhost.js create mode 100644 include/javascript/yui3/build/base/base.js create mode 100644 include/javascript/yui3/build/cache/cache-min.js create mode 100644 include/javascript/yui3/build/cache/cache.js create mode 100644 include/javascript/yui3/build/classnamemanager/classnamemanager-min.js create mode 100644 include/javascript/yui3/build/classnamemanager/classnamemanager.js create mode 100644 include/javascript/yui3/build/collection/collection-min.js create mode 100644 include/javascript/yui3/build/collection/collection.js create mode 100644 include/javascript/yui3/build/compat/compat-min.js create mode 100644 include/javascript/yui3/build/compat/compat.js create mode 100644 include/javascript/yui3/build/console/assets/console-core.css create mode 100644 include/javascript/yui3/build/console/assets/console-filters-core.css create mode 100644 include/javascript/yui3/build/console/assets/skins/sam/bg.png create mode 100644 include/javascript/yui3/build/console/assets/skins/sam/console-filters-skin.css create mode 100644 include/javascript/yui3/build/console/assets/skins/sam/console-filters.css create mode 100644 include/javascript/yui3/build/console/assets/skins/sam/console-skin.css create mode 100644 include/javascript/yui3/build/console/assets/skins/sam/console.css create mode 100644 include/javascript/yui3/build/console/assets/skins/sam/warn_error.png create mode 100644 include/javascript/yui3/build/console/assets/warn_error.png create mode 100644 include/javascript/yui3/build/console/console-filters-min.js create mode 100644 include/javascript/yui3/build/console/console-filters.js create mode 100644 include/javascript/yui3/build/console/console-min.js create mode 100644 include/javascript/yui3/build/console/console.js create mode 100644 include/javascript/yui3/build/cookie/cookie-min.js create mode 100644 include/javascript/yui3/build/cookie/cookie.js create mode 100644 include/javascript/yui3/build/cssbase/base-context-min.css create mode 100644 include/javascript/yui3/build/cssbase/base-context.css create mode 100644 include/javascript/yui3/build/cssbase/base-min.css create mode 100644 include/javascript/yui3/build/cssbase/base.css create mode 100644 include/javascript/yui3/build/cssfonts/fonts-context-min.css create mode 100644 include/javascript/yui3/build/cssfonts/fonts-context.css create mode 100644 include/javascript/yui3/build/cssfonts/fonts-min.css create mode 100644 include/javascript/yui3/build/cssfonts/fonts.css create mode 100644 include/javascript/yui3/build/cssgrids/grids-context-min.css create mode 100644 include/javascript/yui3/build/cssgrids/grids-context.css create mode 100644 include/javascript/yui3/build/cssgrids/grids-min.css create mode 100644 include/javascript/yui3/build/cssgrids/grids.css create mode 100644 include/javascript/yui3/build/cssreset/reset-context-min.css create mode 100644 include/javascript/yui3/build/cssreset/reset-context.css create mode 100644 include/javascript/yui3/build/cssreset/reset-min.css create mode 100644 include/javascript/yui3/build/cssreset/reset.css create mode 100644 include/javascript/yui3/build/dataschema/dataschema-array-min.js create mode 100644 include/javascript/yui3/build/dataschema/dataschema-array.js create mode 100644 include/javascript/yui3/build/dataschema/dataschema-base-min.js create mode 100644 include/javascript/yui3/build/dataschema/dataschema-base.js create mode 100644 include/javascript/yui3/build/dataschema/dataschema-json-min.js create mode 100644 include/javascript/yui3/build/dataschema/dataschema-json.js create mode 100644 include/javascript/yui3/build/dataschema/dataschema-min.js create mode 100644 include/javascript/yui3/build/dataschema/dataschema-text-min.js create mode 100644 include/javascript/yui3/build/dataschema/dataschema-text.js create mode 100644 include/javascript/yui3/build/dataschema/dataschema-xml-min.js create mode 100644 include/javascript/yui3/build/dataschema/dataschema-xml.js create mode 100644 include/javascript/yui3/build/dataschema/dataschema.js create mode 100644 include/javascript/yui3/build/datasource/datasource-arrayschema-min.js create mode 100644 include/javascript/yui3/build/datasource/datasource-arrayschema.js create mode 100644 include/javascript/yui3/build/datasource/datasource-cache-min.js create mode 100644 include/javascript/yui3/build/datasource/datasource-cache.js create mode 100644 include/javascript/yui3/build/datasource/datasource-function-min.js create mode 100644 include/javascript/yui3/build/datasource/datasource-function.js create mode 100644 include/javascript/yui3/build/datasource/datasource-get-min.js create mode 100644 include/javascript/yui3/build/datasource/datasource-get.js create mode 100644 include/javascript/yui3/build/datasource/datasource-io-min.js create mode 100644 include/javascript/yui3/build/datasource/datasource-io.js create mode 100644 include/javascript/yui3/build/datasource/datasource-jsonschema-min.js create mode 100644 include/javascript/yui3/build/datasource/datasource-jsonschema.js create mode 100644 include/javascript/yui3/build/datasource/datasource-local-min.js create mode 100644 include/javascript/yui3/build/datasource/datasource-local.js create mode 100644 include/javascript/yui3/build/datasource/datasource-min.js create mode 100644 include/javascript/yui3/build/datasource/datasource-polling-min.js create mode 100644 include/javascript/yui3/build/datasource/datasource-polling.js create mode 100644 include/javascript/yui3/build/datasource/datasource-textschema-min.js create mode 100644 include/javascript/yui3/build/datasource/datasource-textschema.js create mode 100644 include/javascript/yui3/build/datasource/datasource-xmlschema-min.js create mode 100644 include/javascript/yui3/build/datasource/datasource-xmlschema.js create mode 100644 include/javascript/yui3/build/datasource/datasource.js create mode 100644 include/javascript/yui3/build/datatype/datatype-date-format-min.js create mode 100644 include/javascript/yui3/build/datatype/datatype-date-format.js create mode 100644 include/javascript/yui3/build/datatype/datatype-date-min.js create mode 100644 include/javascript/yui3/build/datatype/datatype-date-parse-min.js create mode 100644 include/javascript/yui3/build/datatype/datatype-date-parse.js create mode 100644 include/javascript/yui3/build/datatype/datatype-date.js create mode 100644 include/javascript/yui3/build/datatype/datatype-min.js create mode 100644 include/javascript/yui3/build/datatype/datatype-number-format-min.js create mode 100644 include/javascript/yui3/build/datatype/datatype-number-format.js create mode 100644 include/javascript/yui3/build/datatype/datatype-number-min.js create mode 100644 include/javascript/yui3/build/datatype/datatype-number-parse-min.js create mode 100644 include/javascript/yui3/build/datatype/datatype-number-parse.js create mode 100644 include/javascript/yui3/build/datatype/datatype-number.js create mode 100644 include/javascript/yui3/build/datatype/datatype-xml-format-min.js create mode 100644 include/javascript/yui3/build/datatype/datatype-xml-format.js create mode 100644 include/javascript/yui3/build/datatype/datatype-xml-min.js create mode 100644 include/javascript/yui3/build/datatype/datatype-xml-parse-min.js create mode 100644 include/javascript/yui3/build/datatype/datatype-xml-parse.js create mode 100644 include/javascript/yui3/build/datatype/datatype-xml.js create mode 100644 include/javascript/yui3/build/datatype/datatype.js create mode 100644 include/javascript/yui3/build/dd/dd-constrain-min.js create mode 100644 include/javascript/yui3/build/dd/dd-constrain.js create mode 100644 include/javascript/yui3/build/dd/dd-ddm-base-min.js create mode 100644 include/javascript/yui3/build/dd/dd-ddm-base.js create mode 100644 include/javascript/yui3/build/dd/dd-ddm-drop-min.js create mode 100644 include/javascript/yui3/build/dd/dd-ddm-drop.js create mode 100644 include/javascript/yui3/build/dd/dd-ddm-min.js create mode 100644 include/javascript/yui3/build/dd/dd-ddm.js create mode 100644 include/javascript/yui3/build/dd/dd-drag-min.js create mode 100644 include/javascript/yui3/build/dd/dd-drag.js create mode 100644 include/javascript/yui3/build/dd/dd-drop-min.js create mode 100644 include/javascript/yui3/build/dd/dd-drop-plugin-min.js create mode 100644 include/javascript/yui3/build/dd/dd-drop-plugin.js create mode 100644 include/javascript/yui3/build/dd/dd-drop.js create mode 100644 include/javascript/yui3/build/dd/dd-min.js create mode 100644 include/javascript/yui3/build/dd/dd-plugin-min.js create mode 100644 include/javascript/yui3/build/dd/dd-plugin.js create mode 100644 include/javascript/yui3/build/dd/dd-proxy-min.js create mode 100644 include/javascript/yui3/build/dd/dd-proxy.js create mode 100644 include/javascript/yui3/build/dd/dd-scroll-min.js create mode 100644 include/javascript/yui3/build/dd/dd-scroll.js create mode 100644 include/javascript/yui3/build/dd/dd.js create mode 100644 include/javascript/yui3/build/dom/dom-base-min.js create mode 100644 include/javascript/yui3/build/dom/dom-base.js create mode 100644 include/javascript/yui3/build/dom/dom-min.js create mode 100644 include/javascript/yui3/build/dom/dom-screen-min.js create mode 100644 include/javascript/yui3/build/dom/dom-screen.js create mode 100644 include/javascript/yui3/build/dom/dom-style-min.js create mode 100644 include/javascript/yui3/build/dom/dom-style.js create mode 100644 include/javascript/yui3/build/dom/dom.js create mode 100644 include/javascript/yui3/build/dom/selector-css2-min.js create mode 100644 include/javascript/yui3/build/dom/selector-css2.js create mode 100644 include/javascript/yui3/build/dom/selector-css3-min.js create mode 100644 include/javascript/yui3/build/dom/selector-css3.js create mode 100644 include/javascript/yui3/build/dom/selector-min.js create mode 100644 include/javascript/yui3/build/dom/selector-native-min.js create mode 100644 include/javascript/yui3/build/dom/selector-native.js create mode 100644 include/javascript/yui3/build/dom/selector.js create mode 100644 include/javascript/yui3/build/dump/dump-min.js create mode 100644 include/javascript/yui3/build/dump/dump.js create mode 100644 include/javascript/yui3/build/event-custom/event-custom-base-min.js create mode 100644 include/javascript/yui3/build/event-custom/event-custom-base.js create mode 100644 include/javascript/yui3/build/event-custom/event-custom-complex-min.js create mode 100644 include/javascript/yui3/build/event-custom/event-custom-complex.js create mode 100644 include/javascript/yui3/build/event-custom/event-custom-min.js create mode 100644 include/javascript/yui3/build/event-custom/event-custom.js create mode 100644 include/javascript/yui3/build/event-simulate/event-simulate-min.js create mode 100644 include/javascript/yui3/build/event-simulate/event-simulate.js create mode 100644 include/javascript/yui3/build/event/event-base-min.js create mode 100644 include/javascript/yui3/build/event/event-base.js create mode 100644 include/javascript/yui3/build/event/event-delegate-min.js create mode 100644 include/javascript/yui3/build/event/event-delegate.js create mode 100644 include/javascript/yui3/build/event/event-focus-min.js create mode 100644 include/javascript/yui3/build/event/event-focus.js create mode 100644 include/javascript/yui3/build/event/event-key-min.js create mode 100644 include/javascript/yui3/build/event/event-key.js create mode 100644 include/javascript/yui3/build/event/event-min.js create mode 100644 include/javascript/yui3/build/event/event-mouseenter-min.js create mode 100644 include/javascript/yui3/build/event/event-mouseenter.js create mode 100644 include/javascript/yui3/build/event/event-mousewheel-min.js create mode 100644 include/javascript/yui3/build/event/event-mousewheel.js create mode 100644 include/javascript/yui3/build/event/event-resize-min.js create mode 100644 include/javascript/yui3/build/event/event-resize.js create mode 100644 include/javascript/yui3/build/event/event.js create mode 100644 include/javascript/yui3/build/get/get-min.js create mode 100644 include/javascript/yui3/build/get/get.js create mode 100644 include/javascript/yui3/build/history/history-min.js create mode 100644 include/javascript/yui3/build/history/history.js create mode 100644 include/javascript/yui3/build/imageloader/imageloader-min.js create mode 100644 include/javascript/yui3/build/imageloader/imageloader.js create mode 100644 include/javascript/yui3/build/io/io-base-min.js create mode 100644 include/javascript/yui3/build/io/io-base.js create mode 100644 include/javascript/yui3/build/io/io-form-min.js create mode 100644 include/javascript/yui3/build/io/io-form.js create mode 100644 include/javascript/yui3/build/io/io-min.js create mode 100644 include/javascript/yui3/build/io/io-queue-min.js create mode 100644 include/javascript/yui3/build/io/io-queue.js create mode 100644 include/javascript/yui3/build/io/io-upload-iframe-min.js create mode 100644 include/javascript/yui3/build/io/io-upload-iframe.js create mode 100644 include/javascript/yui3/build/io/io-xdr-min.js create mode 100644 include/javascript/yui3/build/io/io-xdr.js create mode 100644 include/javascript/yui3/build/io/io.js create mode 100644 include/javascript/yui3/build/io/io.swf create mode 100644 include/javascript/yui3/build/json/json-min.js create mode 100644 include/javascript/yui3/build/json/json-parse-min.js create mode 100644 include/javascript/yui3/build/json/json-parse.js create mode 100644 include/javascript/yui3/build/json/json-stringify-min.js create mode 100644 include/javascript/yui3/build/json/json-stringify.js create mode 100644 include/javascript/yui3/build/json/json.js create mode 100644 include/javascript/yui3/build/loader/loader-min.js create mode 100644 include/javascript/yui3/build/loader/loader.js create mode 100644 include/javascript/yui3/build/node-focusmanager/node-focusmanager-min.js create mode 100644 include/javascript/yui3/build/node-focusmanager/node-focusmanager.js create mode 100644 include/javascript/yui3/build/node-menunav/assets/node-menunav-core.css create mode 100644 include/javascript/yui3/build/node-menunav/assets/skins/sam/horizontal-menu-submenu-indicator.png create mode 100644 include/javascript/yui3/build/node-menunav/assets/skins/sam/horizontal-menu-submenu-toggle.png create mode 100644 include/javascript/yui3/build/node-menunav/assets/skins/sam/node-menunav-skin.css create mode 100644 include/javascript/yui3/build/node-menunav/assets/skins/sam/node-menunav.css create mode 100644 include/javascript/yui3/build/node-menunav/assets/skins/sam/vertical-menu-submenu-indicator.png create mode 100644 include/javascript/yui3/build/node-menunav/node-menunav-min.js create mode 100644 include/javascript/yui3/build/node-menunav/node-menunav.js create mode 100644 include/javascript/yui3/build/node/node-aria-min.js create mode 100644 include/javascript/yui3/build/node/node-aria.js create mode 100644 include/javascript/yui3/build/node/node-base-min.js create mode 100644 include/javascript/yui3/build/node/node-base.js create mode 100644 include/javascript/yui3/build/node/node-event-delegate-min.js create mode 100644 include/javascript/yui3/build/node/node-event-delegate.js create mode 100644 include/javascript/yui3/build/node/node-event-simulate-min.js create mode 100644 include/javascript/yui3/build/node/node-event-simulate.js create mode 100644 include/javascript/yui3/build/node/node-min.js create mode 100644 include/javascript/yui3/build/node/node-pluginhost-min.js create mode 100644 include/javascript/yui3/build/node/node-pluginhost.js create mode 100644 include/javascript/yui3/build/node/node-screen-min.js create mode 100644 include/javascript/yui3/build/node/node-screen.js create mode 100644 include/javascript/yui3/build/node/node-style-min.js create mode 100644 include/javascript/yui3/build/node/node-style.js create mode 100644 include/javascript/yui3/build/node/node.js create mode 100644 include/javascript/yui3/build/oop/oop-min.js create mode 100644 include/javascript/yui3/build/oop/oop.js create mode 100644 include/javascript/yui3/build/overlay/assets/overlay-core.css create mode 100644 include/javascript/yui3/build/overlay/assets/skins/sam/overlay-skin.css create mode 100644 include/javascript/yui3/build/overlay/assets/skins/sam/overlay.css create mode 100644 include/javascript/yui3/build/overlay/overlay-min.js create mode 100644 include/javascript/yui3/build/overlay/overlay.js create mode 100644 include/javascript/yui3/build/plugin/plugin-min.js create mode 100644 include/javascript/yui3/build/plugin/plugin.js create mode 100644 include/javascript/yui3/build/pluginhost/pluginhost-min.js create mode 100644 include/javascript/yui3/build/pluginhost/pluginhost.js create mode 100644 include/javascript/yui3/build/profiler/profiler-min.js create mode 100644 include/javascript/yui3/build/profiler/profiler.js create mode 100644 include/javascript/yui3/build/queue-promote/queue-promote-min.js create mode 100644 include/javascript/yui3/build/queue-promote/queue-promote.js create mode 100644 include/javascript/yui3/build/slider/assets/skins/sam/rail-classic-x.png create mode 100644 include/javascript/yui3/build/slider/assets/skins/sam/rail-classic-y.png create mode 100644 include/javascript/yui3/build/slider/assets/skins/sam/slider-skin.css create mode 100644 include/javascript/yui3/build/slider/assets/skins/sam/slider.css create mode 100644 include/javascript/yui3/build/slider/assets/skins/sam/thumb-classic-x.png create mode 100644 include/javascript/yui3/build/slider/assets/skins/sam/thumb-classic-y.png create mode 100644 include/javascript/yui3/build/slider/assets/slider-core.css create mode 100644 include/javascript/yui3/build/slider/slider-min.js create mode 100644 include/javascript/yui3/build/slider/slider.js create mode 100644 include/javascript/yui3/build/stylesheet/stylesheet-min.js create mode 100644 include/javascript/yui3/build/stylesheet/stylesheet.js create mode 100644 include/javascript/yui3/build/substitute/substitute-min.js create mode 100644 include/javascript/yui3/build/substitute/substitute.js create mode 100644 include/javascript/yui3/build/test/assets/test-console.css create mode 100644 include/javascript/yui3/build/test/test-min.js create mode 100644 include/javascript/yui3/build/test/test.js create mode 100644 include/javascript/yui3/build/widget/assets/skins/sam/widget-skin.css create mode 100644 include/javascript/yui3/build/widget/assets/skins/sam/widget-stack-skin.css create mode 100644 include/javascript/yui3/build/widget/assets/skins/sam/widget-stack.css create mode 100644 include/javascript/yui3/build/widget/assets/skins/sam/widget.css create mode 100644 include/javascript/yui3/build/widget/assets/widget-core.css create mode 100644 include/javascript/yui3/build/widget/assets/widget-stack-core.css create mode 100644 include/javascript/yui3/build/widget/widget-min.js create mode 100644 include/javascript/yui3/build/widget/widget-position-ext-min.js create mode 100644 include/javascript/yui3/build/widget/widget-position-ext.js create mode 100644 include/javascript/yui3/build/widget/widget-position-min.js create mode 100644 include/javascript/yui3/build/widget/widget-position.js create mode 100644 include/javascript/yui3/build/widget/widget-stack-min.js create mode 100644 include/javascript/yui3/build/widget/widget-stack.js create mode 100644 include/javascript/yui3/build/widget/widget-stdmod-min.js create mode 100644 include/javascript/yui3/build/widget/widget-stdmod.js create mode 100644 include/javascript/yui3/build/widget/widget.js create mode 100644 include/javascript/yui3/build/yui-base/yui-base-min.js create mode 100644 include/javascript/yui3/build/yui-base/yui-base.js create mode 100644 include/javascript/yui3/build/yui/get-min.js create mode 100644 include/javascript/yui3/build/yui/get.js create mode 100644 include/javascript/yui3/build/yui/yui-base-min.js create mode 100644 include/javascript/yui3/build/yui/yui-base.js create mode 100644 include/javascript/yui3/build/yui/yui-later-min.js create mode 100644 include/javascript/yui3/build/yui/yui-later.js create mode 100644 include/javascript/yui3/build/yui/yui-log-min.js create mode 100644 include/javascript/yui3/build/yui/yui-log.js create mode 100644 include/javascript/yui3/build/yui/yui-min.js create mode 100644 include/javascript/yui3/build/yui/yui.js create mode 100644 include/javascript/yui3/index.html create mode 100644 include/jsolait/LICENSE create mode 100644 include/jsolait/copying.txt create mode 100644 include/jsolait/init.js create mode 100644 include/jsolait/lib/codecs.js create mode 100644 include/jsolait/lib/crypto.js create mode 100644 include/jsolait/lib/jsonrpc.js create mode 100644 include/jsolait/lib/jsonrpclite.js create mode 100644 include/jsolait/lib/lang.js create mode 100644 include/jsolait/lib/langlite.js create mode 100644 include/jsolait/lib/urllib.js create mode 100644 include/jsolait/lib/xml.js create mode 100644 include/jsolait/lib/xmlrpc.js create mode 100644 include/jsolait/missingmixin.js create mode 100644 include/json_config.php create mode 100644 include/language/en_us.lang.php create mode 100644 include/language/en_us.notify_template.html create mode 100644 include/language/jsLanguage.php create mode 100644 include/modules.php create mode 100644 include/nusoap/changelog create mode 100644 include/nusoap/class.nusoap_base.php create mode 100644 include/nusoap/class.soap_fault.php create mode 100644 include/nusoap/class.soap_parser.php create mode 100644 include/nusoap/class.soap_server.php create mode 100644 include/nusoap/class.soap_transport_http.php create mode 100644 include/nusoap/class.soap_val.php create mode 100644 include/nusoap/class.soapclient.php create mode 100644 include/nusoap/class.wsdl.php create mode 100644 include/nusoap/class.wsdlcache.php create mode 100644 include/nusoap/class.xmlschema.php create mode 100644 include/nusoap/license.txt create mode 100644 include/nusoap/nusoap.php create mode 100644 include/nusoap/nusoapmime.php create mode 100644 include/pclzip/gnu-lgpl.txt create mode 100644 include/pclzip/pclzip.lib.php create mode 100644 include/pclzip/readme.txt create mode 100644 include/phpmailer/README create mode 100644 include/phpmailer/class.phpmailer.php create mode 100644 include/phpmailer/class.smtp.php create mode 100644 include/phpmailer/language/phpmailer.lang-ar.php create mode 100644 include/phpmailer/language/phpmailer.lang-br.php create mode 100644 include/phpmailer/language/phpmailer.lang-ca.php create mode 100644 include/phpmailer/language/phpmailer.lang-cz.php create mode 100644 include/phpmailer/language/phpmailer.lang-de.php create mode 100644 include/phpmailer/language/phpmailer.lang-dk.php create mode 100644 include/phpmailer/language/phpmailer.lang-en.php create mode 100644 include/phpmailer/language/phpmailer.lang-es.php create mode 100644 include/phpmailer/language/phpmailer.lang-et.php create mode 100644 include/phpmailer/language/phpmailer.lang-fi.php create mode 100644 include/phpmailer/language/phpmailer.lang-fo.php create mode 100644 include/phpmailer/language/phpmailer.lang-fr.php create mode 100644 include/phpmailer/language/phpmailer.lang-hu.php create mode 100644 include/phpmailer/language/phpmailer.lang-it.php create mode 100644 include/phpmailer/language/phpmailer.lang-ja.php create mode 100644 include/phpmailer/language/phpmailer.lang-nl.php create mode 100644 include/phpmailer/language/phpmailer.lang-no.php create mode 100644 include/phpmailer/language/phpmailer.lang-pl.php create mode 100644 include/phpmailer/language/phpmailer.lang-ro.php create mode 100644 include/phpmailer/language/phpmailer.lang-ru.php create mode 100644 include/phpmailer/language/phpmailer.lang-se.php create mode 100644 include/phpmailer/language/phpmailer.lang-tr.php create mode 100644 include/phpmailer/license.txt create mode 100644 include/reCaptcha/LICENSE create mode 100644 include/reCaptcha/README create mode 100644 include/reCaptcha/recaptchalib.php create mode 100644 include/resource/Observers/ResourceObserver.php create mode 100644 include/resource/Observers/SoapResourceObserver.php create mode 100644 include/resource/Observers/WebResourceObserver.php create mode 100644 include/resource/ResourceManager.php create mode 100644 include/tabConfig.php create mode 100644 include/tabs.php create mode 100644 include/tcpdf/2dbarcodes.php create mode 100644 include/tcpdf/CHANGELOG.TXT create mode 100644 include/tcpdf/LICENSE.TXT create mode 100644 include/tcpdf/README.TXT create mode 100644 include/tcpdf/barcodes.php create mode 100644 include/tcpdf/config/lang/eng.php create mode 100644 include/tcpdf/config/lang/ita.php create mode 100644 include/tcpdf/config/tcpdf_config.php create mode 100644 include/tcpdf/config/tcpdf_config_alt.php create mode 100644 include/tcpdf/fonts/uni2cid_ac15.php create mode 100644 include/tcpdf/fonts/uni2cid_ag15.php create mode 100644 include/tcpdf/fonts/uni2cid_aj16.php create mode 100644 include/tcpdf/fonts/uni2cid_ak12.php create mode 100644 include/tcpdf/fonts/utils/enc/cp1250.map create mode 100644 include/tcpdf/fonts/utils/enc/cp1251.map create mode 100644 include/tcpdf/fonts/utils/enc/cp1252.map create mode 100644 include/tcpdf/fonts/utils/enc/cp1253.map create mode 100644 include/tcpdf/fonts/utils/enc/cp1254.map create mode 100644 include/tcpdf/fonts/utils/enc/cp1255.map create mode 100644 include/tcpdf/fonts/utils/enc/cp1257.map create mode 100644 include/tcpdf/fonts/utils/enc/cp1258.map create mode 100644 include/tcpdf/fonts/utils/enc/cp874.map create mode 100644 include/tcpdf/fonts/utils/enc/iso-8859-1.map create mode 100644 include/tcpdf/fonts/utils/enc/iso-8859-11.map create mode 100644 include/tcpdf/fonts/utils/enc/iso-8859-15.map create mode 100644 include/tcpdf/fonts/utils/enc/iso-8859-16.map create mode 100644 include/tcpdf/fonts/utils/enc/iso-8859-2.map create mode 100644 include/tcpdf/fonts/utils/enc/iso-8859-4.map create mode 100644 include/tcpdf/fonts/utils/enc/iso-8859-5.map create mode 100644 include/tcpdf/fonts/utils/enc/iso-8859-7.map create mode 100644 include/tcpdf/fonts/utils/enc/iso-8859-9.map create mode 100644 include/tcpdf/fonts/utils/enc/koi8-r.map create mode 100644 include/tcpdf/fonts/utils/enc/koi8-u.map create mode 100644 include/tcpdf/fonts/utils/makefont.php create mode 100644 include/tcpdf/htmlcolors.php create mode 100644 include/tcpdf/tcpdf.php create mode 100644 include/tcpdf/unicode_data.php create mode 100644 include/templates/Template.php create mode 100644 include/templates/TemplateDragDropChooser.php create mode 100644 include/templates/TemplateGroupChooser.php create mode 100644 include/timezone/timezones.php create mode 100644 include/upload_file.php create mode 100644 include/utils.php create mode 100644 include/utils/LogicHook.php create mode 100644 include/utils/activity_utils.php create mode 100644 include/utils/array_utils.php create mode 100644 include/utils/autoloader.php create mode 100644 include/utils/db_utils.php create mode 100644 include/utils/encryption_utils.php create mode 100644 include/utils/external_cache.php create mode 100644 include/utils/file_utils.php create mode 100644 include/utils/layout_utils.php create mode 100644 include/utils/logic_utils.php create mode 100644 include/utils/mvc_utils.php create mode 100644 include/utils/php_zip_utils.php create mode 100644 include/utils/progress_bar_utils.php create mode 100644 include/utils/security_utils.php create mode 100644 include/utils/sugar_file_utils.php create mode 100644 include/utils/zip_utils.php create mode 100644 include/vCard.php create mode 100644 include/ytree/ExtNode.php create mode 100644 include/ytree/Node.php create mode 100644 include/ytree/Tree.php create mode 100644 include/ytree/TreeView/HTMLNode.js create mode 100644 include/ytree/TreeView/MenuNode.js create mode 100644 include/ytree/TreeView/Node.js create mode 100644 include/ytree/TreeView/RootNode.js create mode 100644 include/ytree/TreeView/TaskNode.js create mode 100644 include/ytree/TreeView/TextNode.js create mode 100644 include/ytree/TreeView/TreeView.js create mode 100644 include/ytree/TreeView/anim/TVAnim.js create mode 100644 include/ytree/TreeView/anim/TVFadeIn.js create mode 100644 include/ytree/TreeView/anim/TVFadeOut.js create mode 100644 include/ytree/TreeView/css/check/tree.css create mode 100644 include/ytree/TreeView/css/default/tree.css create mode 100644 include/ytree/TreeView/css/folders/tree.css create mode 100644 include/ytree/TreeView/css/forecasts/tree.css create mode 100644 include/ytree/TreeView/img/bullet.gif create mode 100644 include/ytree/TreeView/img/check/Thumbs.db create mode 100644 include/ytree/TreeView/img/check/check0.gif create mode 100644 include/ytree/TreeView/img/check/check1.gif create mode 100644 include/ytree/TreeView/img/check/check2.gif create mode 100644 include/ytree/TreeView/img/check/lm.gif create mode 100644 include/ytree/TreeView/img/check/lmh.gif create mode 100644 include/ytree/TreeView/img/check/ln.gif create mode 100644 include/ytree/TreeView/img/check/loading.gif create mode 100644 include/ytree/TreeView/img/check/lp.gif create mode 100644 include/ytree/TreeView/img/check/lph.gif create mode 100644 include/ytree/TreeView/img/check/tm.gif create mode 100644 include/ytree/TreeView/img/check/tmh.gif create mode 100644 include/ytree/TreeView/img/check/tn.gif create mode 100644 include/ytree/TreeView/img/check/tp.gif create mode 100644 include/ytree/TreeView/img/check/tph.gif create mode 100644 include/ytree/TreeView/img/check/vline.gif create mode 100644 include/ytree/TreeView/img/default/lm.gif create mode 100644 include/ytree/TreeView/img/default/lmh.gif create mode 100644 include/ytree/TreeView/img/default/ln.gif create mode 100644 include/ytree/TreeView/img/default/loading.gif create mode 100644 include/ytree/TreeView/img/default/lp.gif create mode 100644 include/ytree/TreeView/img/default/lph.gif create mode 100644 include/ytree/TreeView/img/default/tm.gif create mode 100644 include/ytree/TreeView/img/default/tmh.gif create mode 100644 include/ytree/TreeView/img/default/tn.gif create mode 100644 include/ytree/TreeView/img/default/tp.gif create mode 100644 include/ytree/TreeView/img/default/tph.gif create mode 100644 include/ytree/TreeView/img/default/vline.gif create mode 100644 include/ytree/TreeView/img/folders/lm.gif create mode 100644 include/ytree/TreeView/img/folders/lmh.gif create mode 100644 include/ytree/TreeView/img/folders/ln.gif create mode 100644 include/ytree/TreeView/img/folders/loading.gif create mode 100644 include/ytree/TreeView/img/folders/lp.gif create mode 100644 include/ytree/TreeView/img/folders/lph.gif create mode 100644 include/ytree/TreeView/img/folders/minus.gif create mode 100644 include/ytree/TreeView/img/folders/plus.gif create mode 100644 include/ytree/TreeView/img/folders/tm.gif create mode 100644 include/ytree/TreeView/img/folders/tmh.gif create mode 100644 include/ytree/TreeView/img/folders/tn.gif create mode 100644 include/ytree/TreeView/img/folders/tp.gif create mode 100644 include/ytree/TreeView/img/folders/tph.gif create mode 100644 include/ytree/TreeView/img/folders/vline.gif create mode 100644 include/ytree/TreeView/img/greybg.png create mode 100644 include/ytree/TreeView/img/header.gif create mode 100644 include/ytree/TreeView/img/logo.gif create mode 100644 include/ytree/TreeView/img/navHover2.png create mode 100644 include/ytree/TreeView/img/qbottom.png create mode 100644 include/ytree/TreeView/img/qmiddle.png create mode 100644 include/ytree/TreeView/img/qtop.png create mode 100644 include/ytree/TreeView/license.txt create mode 100644 include/ytree/treeutil.js create mode 100644 index.php create mode 100644 install.php create mode 100644 install/TeamDemoData.php create mode 100644 install/UploadLangFileCheck.php create mode 100644 install/UserDemoData.php create mode 100644 install/checkDBSettings.php create mode 100644 install/confirmSettings.php create mode 100644 install/data/disc_client.php create mode 100644 install/dbConfig.js create mode 100644 install/dbConfig_a.php create mode 100644 install/demoData.en_us.php create mode 100644 install/download_modules.php create mode 100644 install/download_patches.php create mode 100644 install/install.css create mode 100644 install/installCommon.js create mode 100644 install/installDisabled.php create mode 100644 install/installHelp.php create mode 100644 install/installSystemCheck.php create mode 100644 install/installType.php create mode 100644 install/install_defaults.php create mode 100644 install/install_utils.php create mode 100644 install/language/en_us.lang.php create mode 100644 install/license.js create mode 100644 install/license.php create mode 100644 install/licensePrint.php create mode 100644 install/oc_convert.js create mode 100644 install/oc_install.js create mode 100644 install/performSetup.php create mode 100644 install/populateSeedData.php create mode 100644 install/processing.gif create mode 100644 install/ready.php create mode 100644 install/register.js create mode 100644 install/register.php create mode 100644 install/seed_data/Advanced_Password_SeedData.php create mode 100644 install/seed_data/quotes_SeedData.php create mode 100644 install/siteConfig.js create mode 100644 install/siteConfig_a.php create mode 100644 install/siteConfig_b.php create mode 100644 install/systemOptions.php create mode 100644 install/welcome.php create mode 100644 json.php create mode 100644 json_server.php create mode 100644 jssource/JSGroupings.php create mode 100644 jssource/jsmin.php create mode 100644 jssource/minify.php create mode 100644 jssource/minify_utils.php create mode 100644 jssource/src_files/include/JSON.js create mode 100644 jssource/src_files/include/MySugar/javascript/MySugar.js create mode 100644 jssource/src_files/include/SubPanel/SubPanelTiles.js create mode 100644 jssource/src_files/include/SugarCharts/Jit/FlashCanvas/canvas2png.js create mode 100644 jssource/src_files/include/SugarCharts/Jit/FlashCanvas/flashcanvas.js create mode 100644 jssource/src_files/include/SugarCharts/Jit/js/Jit/jit.js create mode 100644 jssource/src_files/include/SugarCharts/Jit/js/mySugarCharts.js create mode 100644 jssource/src_files/include/SugarCharts/Jit/js/sugarCharts.js create mode 100644 jssource/src_files/include/SugarDependentDropdown/javascript/SugarDependentDropdown.js create mode 100644 jssource/src_files/include/SugarEmailAddress/SugarEmailAddress.js create mode 100644 jssource/src_files/include/SugarFields/Fields/Address/SugarFieldAddress.js create mode 100644 jssource/src_files/include/SugarFields/Fields/Collection/SugarFieldCollection.js create mode 100644 jssource/src_files/include/SugarFields/Fields/Datetimecombo/Datetimecombo.js create mode 100644 jssource/src_files/include/SugarFields/Fields/File/SugarFieldFile.js create mode 100644 jssource/src_files/include/connectors/formatters/default/company_detail.js create mode 100644 jssource/src_files/include/javascript/calendar.js create mode 100644 jssource/src_files/include/javascript/cookie.js create mode 100644 jssource/src_files/include/javascript/dashlets.js create mode 100644 jssource/src_files/include/javascript/include.js create mode 100644 jssource/src_files/include/javascript/iscroll.js create mode 100644 jssource/src_files/include/javascript/jsclass_async.js create mode 100644 jssource/src_files/include/javascript/jsclass_base.js create mode 100644 jssource/src_files/include/javascript/menu.js create mode 100644 jssource/src_files/include/javascript/overlibmws.js create mode 100644 jssource/src_files/include/javascript/overlibmws_iframe.js create mode 100644 jssource/src_files/include/javascript/popup_helper.js create mode 100644 jssource/src_files/include/javascript/popup_parent_helper.js create mode 100644 jssource/src_files/include/javascript/quickCompose.js create mode 100644 jssource/src_files/include/javascript/quicksearch.js create mode 100644 jssource/src_files/include/javascript/report_additionals.js create mode 100644 jssource/src_files/include/javascript/sugar_3.js create mode 100644 jssource/src_files/include/javascript/sugar_connection_event_listener.js create mode 100644 jssource/src_files/include/javascript/sugarwidgets/SugarYUILoader.js create mode 100644 jssource/src_files/include/javascript/sugarwidgets/SugarYUIWidgets.js create mode 100644 jssource/src_files/include/javascript/swfobject.js create mode 100644 jssource/src_files/include/javascript/yui3/assets/dpSyntaxHighlighter.js create mode 100644 jssource/src_files/include/javascript/yui3/assets/syntax.js create mode 100644 jssource/src_files/include/javascript/yui3/build/anim/anim-base-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/anim/anim-base.js create mode 100644 jssource/src_files/include/javascript/yui3/build/anim/anim-color-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/anim/anim-color.js create mode 100644 jssource/src_files/include/javascript/yui3/build/anim/anim-curve-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/anim/anim-curve.js create mode 100644 jssource/src_files/include/javascript/yui3/build/anim/anim-easing-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/anim/anim-easing.js create mode 100644 jssource/src_files/include/javascript/yui3/build/anim/anim-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/anim/anim-node-plugin-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/anim/anim-node-plugin.js create mode 100644 jssource/src_files/include/javascript/yui3/build/anim/anim-scroll-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/anim/anim-scroll.js create mode 100644 jssource/src_files/include/javascript/yui3/build/anim/anim-xy-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/anim/anim-xy.js create mode 100644 jssource/src_files/include/javascript/yui3/build/anim/anim.js create mode 100644 jssource/src_files/include/javascript/yui3/build/async-queue/async-queue-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/async-queue/async-queue.js create mode 100644 jssource/src_files/include/javascript/yui3/build/attribute/attribute-base-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/attribute/attribute-base.js create mode 100644 jssource/src_files/include/javascript/yui3/build/attribute/attribute-complex-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/attribute/attribute-complex.js create mode 100644 jssource/src_files/include/javascript/yui3/build/attribute/attribute-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/attribute/attribute.js create mode 100644 jssource/src_files/include/javascript/yui3/build/base/base-base-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/base/base-base.js create mode 100644 jssource/src_files/include/javascript/yui3/build/base/base-build-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/base/base-build.js create mode 100644 jssource/src_files/include/javascript/yui3/build/base/base-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/base/base-pluginhost-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/base/base-pluginhost.js create mode 100644 jssource/src_files/include/javascript/yui3/build/base/base.js create mode 100644 jssource/src_files/include/javascript/yui3/build/cache/cache-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/cache/cache.js create mode 100644 jssource/src_files/include/javascript/yui3/build/classnamemanager/classnamemanager-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/classnamemanager/classnamemanager.js create mode 100644 jssource/src_files/include/javascript/yui3/build/collection/collection-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/collection/collection.js create mode 100644 jssource/src_files/include/javascript/yui3/build/compat/compat-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/compat/compat.js create mode 100644 jssource/src_files/include/javascript/yui3/build/console/console-filters-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/console/console-filters.js create mode 100644 jssource/src_files/include/javascript/yui3/build/console/console-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/console/console.js create mode 100644 jssource/src_files/include/javascript/yui3/build/cookie/cookie-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/cookie/cookie.js create mode 100644 jssource/src_files/include/javascript/yui3/build/dataschema/dataschema-array-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/dataschema/dataschema-array.js create mode 100644 jssource/src_files/include/javascript/yui3/build/dataschema/dataschema-base-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/dataschema/dataschema-base.js create mode 100644 jssource/src_files/include/javascript/yui3/build/dataschema/dataschema-json-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/dataschema/dataschema-json.js create mode 100644 jssource/src_files/include/javascript/yui3/build/dataschema/dataschema-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/dataschema/dataschema-text-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/dataschema/dataschema-text.js create mode 100644 jssource/src_files/include/javascript/yui3/build/dataschema/dataschema-xml-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/dataschema/dataschema-xml.js create mode 100644 jssource/src_files/include/javascript/yui3/build/dataschema/dataschema.js create mode 100644 jssource/src_files/include/javascript/yui3/build/datasource/datasource-arrayschema-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/datasource/datasource-arrayschema.js create mode 100644 jssource/src_files/include/javascript/yui3/build/datasource/datasource-cache-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/datasource/datasource-cache.js create mode 100644 jssource/src_files/include/javascript/yui3/build/datasource/datasource-function-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/datasource/datasource-function.js create mode 100644 jssource/src_files/include/javascript/yui3/build/datasource/datasource-get-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/datasource/datasource-get.js create mode 100644 jssource/src_files/include/javascript/yui3/build/datasource/datasource-io-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/datasource/datasource-io.js create mode 100644 jssource/src_files/include/javascript/yui3/build/datasource/datasource-jsonschema-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/datasource/datasource-jsonschema.js create mode 100644 jssource/src_files/include/javascript/yui3/build/datasource/datasource-local-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/datasource/datasource-local.js create mode 100644 jssource/src_files/include/javascript/yui3/build/datasource/datasource-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/datasource/datasource-polling-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/datasource/datasource-polling.js create mode 100644 jssource/src_files/include/javascript/yui3/build/datasource/datasource-textschema-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/datasource/datasource-textschema.js create mode 100644 jssource/src_files/include/javascript/yui3/build/datasource/datasource-xmlschema-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/datasource/datasource-xmlschema.js create mode 100644 jssource/src_files/include/javascript/yui3/build/datasource/datasource.js create mode 100644 jssource/src_files/include/javascript/yui3/build/datatype/datatype-date-format-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/datatype/datatype-date-format.js create mode 100644 jssource/src_files/include/javascript/yui3/build/datatype/datatype-date-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/datatype/datatype-date-parse-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/datatype/datatype-date-parse.js create mode 100644 jssource/src_files/include/javascript/yui3/build/datatype/datatype-date.js create mode 100644 jssource/src_files/include/javascript/yui3/build/datatype/datatype-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/datatype/datatype-number-format-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/datatype/datatype-number-format.js create mode 100644 jssource/src_files/include/javascript/yui3/build/datatype/datatype-number-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/datatype/datatype-number-parse-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/datatype/datatype-number-parse.js create mode 100644 jssource/src_files/include/javascript/yui3/build/datatype/datatype-number.js create mode 100644 jssource/src_files/include/javascript/yui3/build/datatype/datatype-xml-format-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/datatype/datatype-xml-format.js create mode 100644 jssource/src_files/include/javascript/yui3/build/datatype/datatype-xml-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/datatype/datatype-xml-parse-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/datatype/datatype-xml-parse.js create mode 100644 jssource/src_files/include/javascript/yui3/build/datatype/datatype-xml.js create mode 100644 jssource/src_files/include/javascript/yui3/build/datatype/datatype.js create mode 100644 jssource/src_files/include/javascript/yui3/build/dd/dd-constrain-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/dd/dd-constrain.js create mode 100644 jssource/src_files/include/javascript/yui3/build/dd/dd-ddm-base-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/dd/dd-ddm-base.js create mode 100644 jssource/src_files/include/javascript/yui3/build/dd/dd-ddm-drop-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/dd/dd-ddm-drop.js create mode 100644 jssource/src_files/include/javascript/yui3/build/dd/dd-ddm-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/dd/dd-ddm.js create mode 100644 jssource/src_files/include/javascript/yui3/build/dd/dd-drag-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/dd/dd-drag.js create mode 100644 jssource/src_files/include/javascript/yui3/build/dd/dd-drop-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/dd/dd-drop-plugin-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/dd/dd-drop-plugin.js create mode 100644 jssource/src_files/include/javascript/yui3/build/dd/dd-drop.js create mode 100644 jssource/src_files/include/javascript/yui3/build/dd/dd-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/dd/dd-plugin-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/dd/dd-plugin.js create mode 100644 jssource/src_files/include/javascript/yui3/build/dd/dd-proxy-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/dd/dd-proxy.js create mode 100644 jssource/src_files/include/javascript/yui3/build/dd/dd-scroll-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/dd/dd-scroll.js create mode 100644 jssource/src_files/include/javascript/yui3/build/dd/dd.js create mode 100644 jssource/src_files/include/javascript/yui3/build/dom/dom-base-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/dom/dom-base.js create mode 100644 jssource/src_files/include/javascript/yui3/build/dom/dom-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/dom/dom-screen-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/dom/dom-screen.js create mode 100644 jssource/src_files/include/javascript/yui3/build/dom/dom-style-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/dom/dom-style.js create mode 100644 jssource/src_files/include/javascript/yui3/build/dom/dom.js create mode 100644 jssource/src_files/include/javascript/yui3/build/dom/selector-css2-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/dom/selector-css2.js create mode 100644 jssource/src_files/include/javascript/yui3/build/dom/selector-css3-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/dom/selector-css3.js create mode 100644 jssource/src_files/include/javascript/yui3/build/dom/selector-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/dom/selector-native-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/dom/selector-native.js create mode 100644 jssource/src_files/include/javascript/yui3/build/dom/selector.js create mode 100644 jssource/src_files/include/javascript/yui3/build/dump/dump-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/dump/dump.js create mode 100644 jssource/src_files/include/javascript/yui3/build/event-custom/event-custom-base-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/event-custom/event-custom-base.js create mode 100644 jssource/src_files/include/javascript/yui3/build/event-custom/event-custom-complex-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/event-custom/event-custom-complex.js create mode 100644 jssource/src_files/include/javascript/yui3/build/event-custom/event-custom-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/event-custom/event-custom.js create mode 100644 jssource/src_files/include/javascript/yui3/build/event-simulate/event-simulate-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/event-simulate/event-simulate.js create mode 100644 jssource/src_files/include/javascript/yui3/build/event/event-base-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/event/event-base.js create mode 100644 jssource/src_files/include/javascript/yui3/build/event/event-delegate-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/event/event-delegate.js create mode 100644 jssource/src_files/include/javascript/yui3/build/event/event-focus-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/event/event-focus.js create mode 100644 jssource/src_files/include/javascript/yui3/build/event/event-key-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/event/event-key.js create mode 100644 jssource/src_files/include/javascript/yui3/build/event/event-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/event/event-mouseenter-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/event/event-mouseenter.js create mode 100644 jssource/src_files/include/javascript/yui3/build/event/event-mousewheel-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/event/event-mousewheel.js create mode 100644 jssource/src_files/include/javascript/yui3/build/event/event-resize-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/event/event-resize.js create mode 100644 jssource/src_files/include/javascript/yui3/build/event/event.js create mode 100644 jssource/src_files/include/javascript/yui3/build/get/get-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/get/get.js create mode 100644 jssource/src_files/include/javascript/yui3/build/history/history-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/history/history.js create mode 100644 jssource/src_files/include/javascript/yui3/build/imageloader/imageloader-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/imageloader/imageloader.js create mode 100644 jssource/src_files/include/javascript/yui3/build/io/io-base-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/io/io-base.js create mode 100644 jssource/src_files/include/javascript/yui3/build/io/io-form-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/io/io-form.js create mode 100644 jssource/src_files/include/javascript/yui3/build/io/io-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/io/io-queue-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/io/io-queue.js create mode 100644 jssource/src_files/include/javascript/yui3/build/io/io-upload-iframe-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/io/io-upload-iframe.js create mode 100644 jssource/src_files/include/javascript/yui3/build/io/io-xdr-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/io/io-xdr.js create mode 100644 jssource/src_files/include/javascript/yui3/build/io/io.js create mode 100644 jssource/src_files/include/javascript/yui3/build/json/json-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/json/json-parse-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/json/json-parse.js create mode 100644 jssource/src_files/include/javascript/yui3/build/json/json-stringify-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/json/json-stringify.js create mode 100644 jssource/src_files/include/javascript/yui3/build/json/json.js create mode 100644 jssource/src_files/include/javascript/yui3/build/loader/loader-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/loader/loader.js create mode 100644 jssource/src_files/include/javascript/yui3/build/node-focusmanager/node-focusmanager-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/node-focusmanager/node-focusmanager.js create mode 100644 jssource/src_files/include/javascript/yui3/build/node-menunav/node-menunav-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/node-menunav/node-menunav.js create mode 100644 jssource/src_files/include/javascript/yui3/build/node/node-aria-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/node/node-aria.js create mode 100644 jssource/src_files/include/javascript/yui3/build/node/node-base-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/node/node-base.js create mode 100644 jssource/src_files/include/javascript/yui3/build/node/node-event-delegate-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/node/node-event-delegate.js create mode 100644 jssource/src_files/include/javascript/yui3/build/node/node-event-simulate-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/node/node-event-simulate.js create mode 100644 jssource/src_files/include/javascript/yui3/build/node/node-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/node/node-pluginhost-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/node/node-pluginhost.js create mode 100644 jssource/src_files/include/javascript/yui3/build/node/node-screen-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/node/node-screen.js create mode 100644 jssource/src_files/include/javascript/yui3/build/node/node-style-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/node/node-style.js create mode 100644 jssource/src_files/include/javascript/yui3/build/node/node.js create mode 100644 jssource/src_files/include/javascript/yui3/build/oop/oop-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/oop/oop.js create mode 100644 jssource/src_files/include/javascript/yui3/build/overlay/overlay-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/overlay/overlay.js create mode 100644 jssource/src_files/include/javascript/yui3/build/plugin/plugin-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/plugin/plugin.js create mode 100644 jssource/src_files/include/javascript/yui3/build/pluginhost/pluginhost-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/pluginhost/pluginhost.js create mode 100644 jssource/src_files/include/javascript/yui3/build/profiler/profiler-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/profiler/profiler.js create mode 100644 jssource/src_files/include/javascript/yui3/build/queue-promote/queue-promote-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/queue-promote/queue-promote.js create mode 100644 jssource/src_files/include/javascript/yui3/build/slider/slider-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/slider/slider.js create mode 100644 jssource/src_files/include/javascript/yui3/build/stylesheet/stylesheet-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/stylesheet/stylesheet.js create mode 100644 jssource/src_files/include/javascript/yui3/build/substitute/substitute-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/substitute/substitute.js create mode 100644 jssource/src_files/include/javascript/yui3/build/test/test-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/test/test.js create mode 100644 jssource/src_files/include/javascript/yui3/build/widget/widget-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/widget/widget-position-ext-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/widget/widget-position-ext.js create mode 100644 jssource/src_files/include/javascript/yui3/build/widget/widget-position-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/widget/widget-position.js create mode 100644 jssource/src_files/include/javascript/yui3/build/widget/widget-stack-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/widget/widget-stack.js create mode 100644 jssource/src_files/include/javascript/yui3/build/widget/widget-stdmod-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/widget/widget-stdmod.js create mode 100644 jssource/src_files/include/javascript/yui3/build/widget/widget.js create mode 100644 jssource/src_files/include/javascript/yui3/build/yui-base/yui-base-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/yui-base/yui-base.js create mode 100644 jssource/src_files/include/javascript/yui3/build/yui/get-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/yui/get.js create mode 100644 jssource/src_files/include/javascript/yui3/build/yui/yui-base-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/yui/yui-base.js create mode 100644 jssource/src_files/include/javascript/yui3/build/yui/yui-later-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/yui/yui-later.js create mode 100644 jssource/src_files/include/javascript/yui3/build/yui/yui-log-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/yui/yui-log.js create mode 100644 jssource/src_files/include/javascript/yui3/build/yui/yui-min.js create mode 100644 jssource/src_files/include/javascript/yui3/build/yui/yui.js create mode 100644 jssource/src_files/include/jsolait/init.js create mode 100644 jssource/src_files/include/jsolait/lib/codecs.js create mode 100644 jssource/src_files/include/jsolait/lib/crypto.js create mode 100644 jssource/src_files/include/jsolait/lib/jsonrpc.js create mode 100644 jssource/src_files/include/jsolait/lib/jsonrpclite.js create mode 100644 jssource/src_files/include/jsolait/lib/lang.js create mode 100644 jssource/src_files/include/jsolait/lib/langlite.js create mode 100644 jssource/src_files/include/jsolait/lib/urllib.js create mode 100644 jssource/src_files/include/jsolait/lib/xml.js create mode 100644 jssource/src_files/include/jsolait/lib/xmlrpc.js create mode 100644 jssource/src_files/include/jsolait/missingmixin.js create mode 100644 jssource/src_files/include/ytree/TreeView/HTMLNode.js create mode 100644 jssource/src_files/include/ytree/TreeView/MenuNode.js create mode 100644 jssource/src_files/include/ytree/TreeView/Node.js create mode 100644 jssource/src_files/include/ytree/TreeView/RootNode.js create mode 100644 jssource/src_files/include/ytree/TreeView/TaskNode.js create mode 100644 jssource/src_files/include/ytree/TreeView/TextNode.js create mode 100644 jssource/src_files/include/ytree/TreeView/TreeView.js create mode 100644 jssource/src_files/include/ytree/TreeView/anim/TVAnim.js create mode 100644 jssource/src_files/include/ytree/TreeView/anim/TVFadeIn.js create mode 100644 jssource/src_files/include/ytree/TreeView/anim/TVFadeOut.js create mode 100644 jssource/src_files/include/ytree/treeutil.js create mode 100644 jssource/src_files/install/dbConfig.js create mode 100644 jssource/src_files/install/installCommon.js create mode 100644 jssource/src_files/install/license.js create mode 100644 jssource/src_files/install/oc_convert.js create mode 100644 jssource/src_files/install/oc_install.js create mode 100644 jssource/src_files/install/register.js create mode 100644 jssource/src_files/install/siteConfig.js create mode 100644 jssource/src_files/modules/ACLRoles/ACLRoles.js create mode 100644 jssource/src_files/modules/Accounts/Account.js create mode 100644 jssource/src_files/modules/Administration/javascript/Administration.js create mode 100644 jssource/src_files/modules/Administration/javascript/Async.js create mode 100644 jssource/src_files/modules/Campaigns/DetailView.js create mode 100644 jssource/src_files/modules/Campaigns/WebToLead.js create mode 100644 jssource/src_files/modules/Campaigns/wizard.js create mode 100644 jssource/src_files/modules/Connectors/Connector.js create mode 100644 jssource/src_files/modules/Contacts/Contact.js create mode 100644 jssource/src_files/modules/Currencies/EditView.js create mode 100644 jssource/src_files/modules/Documents/documents.js create mode 100644 jssource/src_files/modules/EAPM/EAPMEdit.js create mode 100644 jssource/src_files/modules/EmailTemplates/EmailTemplate.js create mode 100644 jssource/src_files/modules/Home/about.js create mode 100644 jssource/src_files/modules/InboundEmail/InboundEmail.js create mode 100644 jssource/src_files/modules/Leads/Lead.js create mode 100644 jssource/src_files/modules/Meetings/jsclass_scheduler.js create mode 100644 jssource/src_files/modules/MergeRecords/Merge.js create mode 100644 jssource/src_files/modules/Project/Project.js create mode 100644 jssource/src_files/modules/ProjectTask/ProjectTask.js create mode 100644 jssource/src_files/modules/Studio/JSTransaction.js create mode 100644 jssource/src_files/modules/Studio/studio.js create mode 100644 jssource/src_files/modules/Studio/studiodd.js create mode 100644 jssource/src_files/modules/Studio/studiotabgroups.js create mode 100644 jssource/src_files/modules/Studio/ygDDListStudio.js create mode 100644 jssource/src_files/modules/UpgradeWizard/upgradeWizard.js create mode 100644 jssource/src_files/modules/Users/DetailView.js create mode 100644 jssource/src_files/modules/Users/PasswordRequirementBox.js create mode 100644 jssource/src_files/modules/Users/User.js create mode 100644 jssource/src_files/modules/Users/login.js create mode 100644 jssource/src_files/service/utils/SugarRest.js create mode 100644 jssource/src_files/themes/Sugar5/js/style.js create mode 100644 jssource/src_files/themes/default/js/style.js create mode 100644 leadCapture.php create mode 100644 log4php/LoggerManager.php create mode 100644 log_file_restricted.html create mode 100644 maintenance.php create mode 100644 metadata/accounts_bugsMetaData.php create mode 100644 metadata/accounts_casesMetaData.php create mode 100644 metadata/accounts_contactsMetaData.php create mode 100644 metadata/accounts_opportunitiesMetaData.php create mode 100644 metadata/acl_roles_actionsMetaData.php create mode 100644 metadata/acl_roles_usersMetaData.php create mode 100644 metadata/addressBookMetaData.php create mode 100644 metadata/audit_templateMetaData.php create mode 100644 metadata/calls_contactsMetaData.php create mode 100644 metadata/calls_leadsMetaData.php create mode 100644 metadata/calls_usersMetaData.php create mode 100644 metadata/cases_bugsMetaData.php create mode 100644 metadata/configMetaData.php create mode 100644 metadata/contacts_bugsMetaData.php create mode 100644 metadata/contacts_casesMetaData.php create mode 100644 metadata/contacts_usersMetaData.php create mode 100644 metadata/custom_fieldsMetaData.php create mode 100644 metadata/documents_accountsMetaData.php create mode 100644 metadata/documents_bugsMetaData.php create mode 100644 metadata/documents_casesMetaData.php create mode 100644 metadata/documents_contactsMetaData.php create mode 100644 metadata/documents_opportunitiesMetaData.php create mode 100644 metadata/email_addressesMetaData.php create mode 100644 metadata/email_cacheMetaData.php create mode 100644 metadata/email_marketing_prospect_listsMetaData.php create mode 100644 metadata/emails_beansMetaData.php create mode 100644 metadata/fields_meta_dataMetaData.php create mode 100644 metadata/foldersMetaData.php create mode 100644 metadata/import_mapsMetaData.php create mode 100644 metadata/inboundEmail_autoreplyMetaData.php create mode 100644 metadata/inboundEmail_cacheTimestampMetaData.php create mode 100644 metadata/kbdocuments_views_ratingsMetaData.php create mode 100644 metadata/linked_documentsMetaData.php create mode 100644 metadata/meetings_contactsMetaData.php create mode 100644 metadata/meetings_leadsMetaData.php create mode 100644 metadata/meetings_usersMetaData.php create mode 100644 metadata/opportunities_contactsMetaData.php create mode 100644 metadata/outboundEmailMetaData.php create mode 100644 metadata/project_bugsMetaData.php create mode 100644 metadata/project_casesMetaData.php create mode 100644 metadata/project_productsMetaData.php create mode 100644 metadata/project_relationMetaData.php create mode 100644 metadata/project_task_project_tasksMetaData.php create mode 100644 metadata/projects_accountsMetaData.php create mode 100644 metadata/projects_contactsMetaData.php create mode 100644 metadata/projects_opportunitiesMetaData.php create mode 100644 metadata/projects_quotesMetaData.php create mode 100644 metadata/prospect_list_campaignsMetaData.php create mode 100644 metadata/prospect_lists_prospectsMetaData.php create mode 100644 metadata/queues_beansMetaData.php create mode 100644 metadata/queues_queueMetaData.php create mode 100644 metadata/roles_modulesMetaData.php create mode 100644 metadata/roles_usersMetaData.php create mode 100644 metadata/schedulers_timesMetaData.php create mode 100644 metadata/user_feedsMetaData.php create mode 100644 metadata/usersMetaData.php create mode 100644 metadata/users_last_importMetaData.php create mode 100644 metadata/users_passwordLinkMetaData.php create mode 100644 metadata/users_signaturesMetaData.php create mode 100644 metagen.php create mode 100644 modules/ACL/ACLController.php create mode 100644 modules/ACL/ACLJSController.php create mode 100644 modules/ACL/Forms.php create mode 100644 modules/ACL/List.php create mode 100644 modules/ACL/Menu.php create mode 100644 modules/ACL/Save.php create mode 100644 modules/ACL/install_actions.php create mode 100644 modules/ACL/language/en_us.lang.php create mode 100644 modules/ACL/metadata/subpaneldefs.php create mode 100644 modules/ACL/remove_actions.php create mode 100644 modules/ACL/vardefs.php create mode 100644 modules/ACLActions/ACLAction.php create mode 100644 modules/ACLActions/Forms.php create mode 100644 modules/ACLActions/Menu.php create mode 100644 modules/ACLActions/actiondefs.php create mode 100644 modules/ACLActions/language/en_us.lang.php create mode 100644 modules/ACLActions/metadata/subpaneldefs.php create mode 100644 modules/ACLActions/vardefs.php create mode 100644 modules/ACLRoles/ACLRole.php create mode 100644 modules/ACLRoles/ACLRoles.js create mode 100644 modules/ACLRoles/Delete.php create mode 100644 modules/ACLRoles/DetailUserRole.php create mode 100644 modules/ACLRoles/DetailView.php create mode 100644 modules/ACLRoles/DetailView.tpl create mode 100644 modules/ACLRoles/DetailViewBody.tpl create mode 100644 modules/ACLRoles/DetailViewUser.tpl create mode 100644 modules/ACLRoles/EditAllBody.tpl create mode 100644 modules/ACLRoles/EditRole.php create mode 100644 modules/ACLRoles/EditRole.tpl create mode 100644 modules/ACLRoles/EditView.php create mode 100644 modules/ACLRoles/EditView.tpl create mode 100644 modules/ACLRoles/EditViewBody.tpl create mode 100644 modules/ACLRoles/Forms.php create mode 100644 modules/ACLRoles/ListUsers.php create mode 100644 modules/ACLRoles/Menu.php create mode 100644 modules/ACLRoles/Popup_picker.html create mode 100644 modules/ACLRoles/Popup_picker.php create mode 100644 modules/ACLRoles/Save.php create mode 100644 modules/ACLRoles/language/en_us.lang.php create mode 100644 modules/ACLRoles/metadata/SearchFields.php create mode 100644 modules/ACLRoles/metadata/listviewdefs.php create mode 100644 modules/ACLRoles/metadata/popupdefs.php create mode 100644 modules/ACLRoles/metadata/searchdefs.php create mode 100644 modules/ACLRoles/metadata/subpaneldefs.php create mode 100644 modules/ACLRoles/metadata/subpanels/admin.php create mode 100644 modules/ACLRoles/metadata/subpanels/default.php create mode 100644 modules/ACLRoles/popup.tpl create mode 100644 modules/ACLRoles/vardefs.php create mode 100644 modules/ACLRoles/views/view.list.php create mode 100644 modules/Accounts/Account.js create mode 100644 modules/Accounts/Account.php create mode 100644 modules/Accounts/AccountFormBase.php create mode 100644 modules/Accounts/AccountsQuickCreate.php create mode 100644 modules/Accounts/Dashlets/MyAccountsDashlet/MyAccountsDashlet.data.php create mode 100644 modules/Accounts/Dashlets/MyAccountsDashlet/MyAccountsDashlet.meta.php create mode 100644 modules/Accounts/Dashlets/MyAccountsDashlet/MyAccountsDashlet.php create mode 100644 modules/Accounts/Menu.php create mode 100644 modules/Accounts/Popup_picker.html create mode 100644 modules/Accounts/Save.php create mode 100644 modules/Accounts/ShowDuplicates.html create mode 100644 modules/Accounts/ShowDuplicates.php create mode 100644 modules/Accounts/field_arrays.php create mode 100644 modules/Accounts/language/en_us.lang.php create mode 100644 modules/Accounts/metadata/SearchFields.php create mode 100644 modules/Accounts/metadata/acldefs.php create mode 100644 modules/Accounts/metadata/additionalDetails.php create mode 100644 modules/Accounts/metadata/detailviewdefs.php create mode 100644 modules/Accounts/metadata/editviewdefs.php create mode 100644 modules/Accounts/metadata/fieldGroups.php create mode 100644 modules/Accounts/metadata/listviewdefs.php create mode 100644 modules/Accounts/metadata/metafiles.php create mode 100644 modules/Accounts/metadata/popupdefs.php create mode 100644 modules/Accounts/metadata/quickcreatedefs.php create mode 100644 modules/Accounts/metadata/searchdefs.php create mode 100644 modules/Accounts/metadata/studio.php create mode 100644 modules/Accounts/metadata/subpaneldefs.php create mode 100644 modules/Accounts/metadata/subpanels/ForEmails.php create mode 100644 modules/Accounts/metadata/subpanels/ForProspectLists.php create mode 100644 modules/Accounts/metadata/subpanels/default.php create mode 100644 modules/Accounts/tpls/QuickCreate.tpl create mode 100644 modules/Accounts/vardefs.php create mode 100644 modules/Accounts/views/view.detail.php create mode 100644 modules/Accounts/views/view.list.php create mode 100644 modules/Activities/Forms.php create mode 100644 modules/Activities/Menu.php create mode 100644 modules/Activities/OpenListView.html create mode 100644 modules/Activities/OpenListView.php create mode 100644 modules/Activities/Popup_picker.html create mode 100644 modules/Activities/Popup_picker.php create mode 100644 modules/Activities/SetAcceptStatus.php create mode 100644 modules/Activities/SubPanelView.html create mode 100644 modules/Activities/SubPanelView.php create mode 100644 modules/Activities/SubPanelViewContacts.html create mode 100644 modules/Activities/config.php create mode 100644 modules/Activities/language/en_us.lang.php create mode 100644 modules/Activities/metadata/subpaneldefs.php create mode 100644 modules/Activities/views/view.list.php create mode 100644 modules/Activities/views/view.modulelistmenu.php create mode 100644 modules/Administration/Administration.php create mode 100644 modules/Administration/Async.php create mode 100644 modules/Administration/Common.php create mode 100644 modules/Administration/CustomizeFields.php create mode 100644 modules/Administration/Development.php create mode 100644 modules/Administration/Diagnostic.php create mode 100644 modules/Administration/Diagnostic.tpl create mode 100644 modules/Administration/DiagnosticDelete.php create mode 100644 modules/Administration/DiagnosticDownload.php create mode 100644 modules/Administration/DiagnosticRun.php create mode 100644 modules/Administration/DisplayWarnings.php create mode 100644 modules/Administration/DstFix.php create mode 100644 modules/Administration/ExportCustomFieldStructure.php create mode 100644 modules/Administration/Forms.php create mode 100644 modules/Administration/ImportCustomFieldStructure.php create mode 100644 modules/Administration/Locale.php create mode 100644 modules/Administration/Locale.tpl create mode 100644 modules/Administration/Menu.php create mode 100644 modules/Administration/PasswordManager.php create mode 100644 modules/Administration/PasswordManager.tpl create mode 100644 modules/Administration/QuickRepairAndRebuild.php create mode 100644 modules/Administration/RebuildAudit.php create mode 100644 modules/Administration/RebuildConfig.html create mode 100644 modules/Administration/RebuildConfig.php create mode 100644 modules/Administration/RebuildDashlets.php create mode 100644 modules/Administration/RebuildExpressionPlugins.php create mode 100644 modules/Administration/RebuildFulltextIndices.php create mode 100644 modules/Administration/RebuildJSLang.php create mode 100644 modules/Administration/RebuildRelationship.php create mode 100644 modules/Administration/RebuildSchedulers.php create mode 100644 modules/Administration/RepairActivities.php create mode 100644 modules/Administration/RepairFieldCasing.php create mode 100644 modules/Administration/RepairIE.php create mode 100644 modules/Administration/RepairIndex.php create mode 100644 modules/Administration/RepairJSFile.php create mode 100644 modules/Administration/RepairSeedUsers.php create mode 100644 modules/Administration/RepairXSS.php create mode 100644 modules/Administration/Save.php create mode 100644 modules/Administration/SupportPortal.php create mode 100644 modules/Administration/SupportPortal.tpl create mode 100644 modules/Administration/Updater.html create mode 100644 modules/Administration/Updater.php create mode 100644 modules/Administration/Upgrade.php create mode 100644 modules/Administration/UpgradeAccess.php create mode 100644 modules/Administration/UpgradeFields.php create mode 100644 modules/Administration/UpgradeHistory.php create mode 100644 modules/Administration/UpgradeIISAccess.php create mode 100644 modules/Administration/UpgradeWizard.php create mode 100644 modules/Administration/UpgradeWizardCommon.php create mode 100644 modules/Administration/UpgradeWizard_commit.php create mode 100644 modules/Administration/UpgradeWizard_prepare.php create mode 100644 modules/Administration/action_view_map.php create mode 100644 modules/Administration/callJSRepair.php create mode 100644 modules/Administration/clear_chart_cache.php create mode 100644 modules/Administration/controller.php create mode 100644 modules/Administration/expandDatabase.php create mode 100644 modules/Administration/index.html create mode 100644 modules/Administration/index.php create mode 100644 modules/Administration/index.tpl create mode 100644 modules/Administration/javascript/Administration.js create mode 100644 modules/Administration/javascript/Async.js create mode 100644 modules/Administration/language/en_us.lang.php create mode 100644 modules/Administration/metadata/SearchFields.php create mode 100644 modules/Administration/metadata/adminpaneldefs.php create mode 100644 modules/Administration/ncc_config.php create mode 100644 modules/Administration/repairDatabase.php create mode 100644 modules/Administration/repairSelectModule.php create mode 100644 modules/Administration/repairUniSearch.php create mode 100644 modules/Administration/templates/ConfigureTabs.tpl create mode 100644 modules/Administration/templates/GlobalSearchSettings.tpl create mode 100644 modules/Administration/templates/Languages.tpl create mode 100644 modules/Administration/templates/QuickRepairAndRebuild.tpl create mode 100644 modules/Administration/templates/RepairDatabase.tpl create mode 100644 modules/Administration/templates/RepairXSS.tpl create mode 100644 modules/Administration/templates/ShortcutBar.tpl create mode 100644 modules/Administration/templates/themeSettings.tpl create mode 100644 modules/Administration/undoupdateclass.php create mode 100644 modules/Administration/updateTimezonePrefs.php create mode 100644 modules/Administration/updateclass.php create mode 100644 modules/Administration/updater_utils.php create mode 100644 modules/Administration/upgrade_custom_relationships.php create mode 100644 modules/Administration/vardefs.php create mode 100644 modules/Administration/views/view.backups.php create mode 100644 modules/Administration/views/view.configuretabs.php create mode 100644 modules/Administration/views/view.globalsearchsettings.php create mode 100644 modules/Administration/views/view.languages.php create mode 100644 modules/Administration/views/view.repair.php create mode 100644 modules/Administration/views/view.themesettings.php create mode 100644 modules/Audit/Audit.php create mode 100644 modules/Audit/Popup_picker.html create mode 100644 modules/Audit/Popup_picker.php create mode 100644 modules/Audit/field_assoc.php create mode 100644 modules/Audit/language/en_us.lang.php create mode 100644 modules/Audit/vardefs.php create mode 100644 modules/BeanDictionary.php create mode 100644 modules/Bugs/Bug.php create mode 100644 modules/Bugs/BugsQuickCreate.php create mode 100644 modules/Bugs/Dashlets/MyBugsDashlet/MyBugsDashlet.data.php create mode 100644 modules/Bugs/Dashlets/MyBugsDashlet/MyBugsDashlet.meta.php create mode 100644 modules/Bugs/Dashlets/MyBugsDashlet/MyBugsDashlet.php create mode 100644 modules/Bugs/Menu.php create mode 100644 modules/Bugs/field_arrays.php create mode 100644 modules/Bugs/language/en_us.lang.php create mode 100644 modules/Bugs/metadata/SearchFields.php create mode 100644 modules/Bugs/metadata/additionalDetails.php create mode 100644 modules/Bugs/metadata/detailviewdefs.php create mode 100644 modules/Bugs/metadata/editviewdefs.php create mode 100644 modules/Bugs/metadata/listviewdefs.php create mode 100644 modules/Bugs/metadata/metafiles.php create mode 100644 modules/Bugs/metadata/popupdefs.php create mode 100644 modules/Bugs/metadata/quickcreatedefs.php create mode 100644 modules/Bugs/metadata/searchdefs.php create mode 100644 modules/Bugs/metadata/studio.php create mode 100644 modules/Bugs/metadata/subpaneldefs.php create mode 100644 modules/Bugs/metadata/subpanels/ForEmails.php create mode 100644 modules/Bugs/metadata/subpanels/default.php create mode 100644 modules/Bugs/tpls/QuickCreate.tpl create mode 100644 modules/Bugs/vardefs.php create mode 100644 modules/Bugs/views/view.detail.php create mode 100644 modules/Bugs/views/view.edit.php create mode 100644 modules/Calendar/Calendar.php create mode 100644 modules/Calendar/DateTimeUtil.php create mode 100644 modules/Calendar/Forms.php create mode 100644 modules/Calendar/Menu.php create mode 100644 modules/Calendar/SubPanelSharedCalendar.php create mode 100644 modules/Calendar/TasksListView.html create mode 100644 modules/Calendar/TasksListView.php create mode 100644 modules/Calendar/index.php create mode 100644 modules/Calendar/language/en_us.lang.php create mode 100644 modules/Calendar/metadata/listviewdefs.php create mode 100644 modules/Calendar/small_month.php create mode 100644 modules/Calendar/templates/template_shared_calendar.php create mode 100644 modules/Calendar/templates/templates_calendar.php create mode 100644 modules/Calendar/views/view.list.php create mode 100644 modules/Calls/Call.php create mode 100644 modules/Calls/CallFormBase.php create mode 100644 modules/Calls/CallHelper.php create mode 100644 modules/Calls/CallsQuickCreate.php create mode 100644 modules/Calls/Dashlets/MyCallsDashlet/MyCallsDashlet.data.php create mode 100644 modules/Calls/Dashlets/MyCallsDashlet/MyCallsDashlet.meta.php create mode 100644 modules/Calls/Dashlets/MyCallsDashlet/MyCallsDashlet.php create mode 100644 modules/Calls/Menu.php create mode 100644 modules/Calls/Save.php create mode 100644 modules/Calls/SubPanelViewInvitees.html create mode 100644 modules/Calls/SubPanelViewInvitees.php create mode 100644 modules/Calls/field_arrays.php create mode 100644 modules/Calls/language/en_us.lang.php create mode 100644 modules/Calls/metadata/SearchFields.php create mode 100644 modules/Calls/metadata/additionalDetails.php create mode 100644 modules/Calls/metadata/detailviewdefs.php create mode 100644 modules/Calls/metadata/editviewdefs.php create mode 100644 modules/Calls/metadata/listviewdefs.php create mode 100644 modules/Calls/metadata/quickcreatedefs.php create mode 100644 modules/Calls/metadata/searchdefs.php create mode 100644 modules/Calls/metadata/studio.php create mode 100644 modules/Calls/metadata/subpaneldefs.php create mode 100644 modules/Calls/metadata/subpanels/ForActivities.php create mode 100644 modules/Calls/metadata/subpanels/ForHistory.php create mode 100644 modules/Calls/metadata/subpanels/default.php create mode 100644 modules/Calls/tpls/QuickCreate.tpl create mode 100644 modules/Calls/tpls/footer.tpl create mode 100644 modules/Calls/vardefs.php create mode 100644 modules/Calls/views/view.edit.php create mode 100644 modules/CampaignLog/CampaignLog.php create mode 100644 modules/CampaignLog/Menu.php create mode 100644 modules/CampaignLog/Popup_picker.html create mode 100644 modules/CampaignLog/Popup_picker.php create mode 100644 modules/CampaignLog/language/en_us.lang.php create mode 100644 modules/CampaignLog/metadata/subpanels/ForTargets.php create mode 100644 modules/CampaignLog/metadata/subpanels/default.php create mode 100644 modules/CampaignLog/vardefs.php create mode 100644 modules/CampaignTrackers/CampaignTracker.php create mode 100644 modules/CampaignTrackers/DetailView.html create mode 100644 modules/CampaignTrackers/DetailView.php create mode 100644 modules/CampaignTrackers/EditView.html create mode 100644 modules/CampaignTrackers/EditView.php create mode 100644 modules/CampaignTrackers/Forms.html create mode 100644 modules/CampaignTrackers/Forms.php create mode 100644 modules/CampaignTrackers/Menu.php create mode 100644 modules/CampaignTrackers/Save.php create mode 100644 modules/CampaignTrackers/language/en_us.lang.php create mode 100644 modules/CampaignTrackers/metadata/subpanels/default.php create mode 100644 modules/CampaignTrackers/vardefs.php create mode 100644 modules/Campaigns/Campaign.php create mode 100644 modules/Campaigns/CampaignDiagnostic.html create mode 100644 modules/Campaigns/CampaignDiagnostic.php create mode 100644 modules/Campaigns/CaptchaValidate.php create mode 100644 modules/Campaigns/Charts.php create mode 100644 modules/Campaigns/Charts1.php create mode 100644 modules/Campaigns/Dashlets/TopCampaignsDashlet/TopCampaignsDashlet.meta.php create mode 100644 modules/Campaigns/Dashlets/TopCampaignsDashlet/TopCampaignsDashlet.php create mode 100644 modules/Campaigns/Dashlets/TopCampaignsDashlet/TopCampaignsDashlet.tpl create mode 100644 modules/Campaigns/Dashlets/TopCampaignsDashlet/TopCampaignsDashletConfigure.tpl create mode 100644 modules/Campaigns/Delete.php create mode 100644 modules/Campaigns/DetailView.js create mode 100644 modules/Campaigns/EmailQueue.php create mode 100644 modules/Campaigns/GenerateWebToLeadForm.php create mode 100644 modules/Campaigns/MailMerge.php create mode 100644 modules/Campaigns/Menu.php create mode 100644 modules/Campaigns/PopupCampaignRoi.html create mode 100644 modules/Campaigns/PopupCampaignRoi.php create mode 100644 modules/Campaigns/Popup_picker.html create mode 100644 modules/Campaigns/Popup_picker.php create mode 100644 modules/Campaigns/ProcessBouncedEmails.php create mode 100644 modules/Campaigns/QueueCampaign.php create mode 100644 modules/Campaigns/RemoveMe.php create mode 100644 modules/Campaigns/RoiDetailView.php create mode 100644 modules/Campaigns/RoiDetailView.tpl create mode 100644 modules/Campaigns/Save.php create mode 100644 modules/Campaigns/Schedule.html create mode 100644 modules/Campaigns/Schedule.php create mode 100644 modules/Campaigns/SearchForm_NewsLetter.html create mode 100644 modules/Campaigns/SubPanelViewer.php create mode 100644 modules/Campaigns/Subscriptions.html create mode 100644 modules/Campaigns/Subscriptions.php create mode 100644 modules/Campaigns/Subscriptions.tpl create mode 100644 modules/Campaigns/TrackDetailView.php create mode 100644 modules/Campaigns/TrackDetailView.tpl create mode 100644 modules/Campaigns/Tracker.php create mode 100644 modules/Campaigns/WebToLead.js create mode 100644 modules/Campaigns/WebToLeadCapture.php create mode 100644 modules/Campaigns/WebToLeadCreation.html create mode 100644 modules/Campaigns/WebToLeadCreation.php create mode 100644 modules/Campaigns/WebToLeadDownloadForm.html create mode 100644 modules/Campaigns/WebToLeadForm.html create mode 100644 modules/Campaigns/WebToLeadFormSave.php create mode 100644 modules/Campaigns/WizardEmailSetup.html create mode 100644 modules/Campaigns/WizardEmailSetup.php create mode 100644 modules/Campaigns/WizardEmailSetupSave.php create mode 100644 modules/Campaigns/WizardHome.html create mode 100644 modules/Campaigns/WizardHome.php create mode 100644 modules/Campaigns/WizardMarketing.html create mode 100644 modules/Campaigns/WizardMarketing.php create mode 100644 modules/Campaigns/WizardMarketingSave.php create mode 100644 modules/Campaigns/WizardNewsletter.html create mode 100644 modules/Campaigns/WizardNewsletter.php create mode 100644 modules/Campaigns/WizardNewsletterSave.php create mode 100644 modules/Campaigns/action_file_map.php create mode 100644 modules/Campaigns/chart.tpl create mode 100644 modules/Campaigns/controller.php create mode 100644 modules/Campaigns/field_arrays.php create mode 100644 modules/Campaigns/image.php create mode 100644 modules/Campaigns/language/en_us.lang.php create mode 100644 modules/Campaigns/metadata/SearchFields.php create mode 100644 modules/Campaigns/metadata/additionalDetails.php create mode 100644 modules/Campaigns/metadata/detailviewdefs.php create mode 100644 modules/Campaigns/metadata/editviewdefs.php create mode 100644 modules/Campaigns/metadata/listviewdefs.php create mode 100644 modules/Campaigns/metadata/popupdefs.php create mode 100644 modules/Campaigns/metadata/searchdefs.php create mode 100644 modules/Campaigns/metadata/studio.php create mode 100644 modules/Campaigns/metadata/subpaneldefs.php create mode 100644 modules/Campaigns/metadata/subpanels/ForEmailMarketing.php create mode 100644 modules/Campaigns/metadata/subpanels/default.php create mode 100644 modules/Campaigns/tpls/WizardCampaignBudget.tpl create mode 100644 modules/Campaigns/tpls/WizardCampaignHeader.tpl create mode 100644 modules/Campaigns/tpls/WizardCampaignTargetList.tpl create mode 100644 modules/Campaigns/tpls/WizardCampaignTargetListForNonNewsLetter.tpl create mode 100644 modules/Campaigns/tpls/WizardCampaignTracker.tpl create mode 100644 modules/Campaigns/tpls/WizardHomeStart.tpl create mode 100644 modules/Campaigns/tpls/WizardNewsletter.tpl create mode 100644 modules/Campaigns/utils.php create mode 100644 modules/Campaigns/vardefs.php create mode 100644 modules/Campaigns/views/view.classic.php create mode 100644 modules/Campaigns/views/view.detail.php create mode 100644 modules/Campaigns/views/view.modulelistmenu.php create mode 100644 modules/Campaigns/views/view.newsletterlist.php create mode 100644 modules/Campaigns/wizard.js create mode 100644 modules/Cases/Case.php create mode 100644 modules/Cases/CasesQuickCreate.php create mode 100644 modules/Cases/Dashlets/MyCasesDashlet/MyCasesDashlet.data.php create mode 100644 modules/Cases/Dashlets/MyCasesDashlet/MyCasesDashlet.meta.php create mode 100644 modules/Cases/Dashlets/MyCasesDashlet/MyCasesDashlet.php create mode 100644 modules/Cases/Menu.php create mode 100644 modules/Cases/SugarFeeds/CaseFeed.php create mode 100644 modules/Cases/field_arrays.php create mode 100644 modules/Cases/language/en_us.lang.php create mode 100644 modules/Cases/metadata/SearchFields.php create mode 100644 modules/Cases/metadata/accountsquickcreatedefs.php create mode 100644 modules/Cases/metadata/additionalDetails.php create mode 100644 modules/Cases/metadata/detailviewdefs.php create mode 100644 modules/Cases/metadata/editviewdefs.php create mode 100644 modules/Cases/metadata/listviewdefs.php create mode 100644 modules/Cases/metadata/popupdefs.php create mode 100644 modules/Cases/metadata/quickcreatedefs.php create mode 100644 modules/Cases/metadata/searchdefs.php create mode 100644 modules/Cases/metadata/studio.php create mode 100644 modules/Cases/metadata/subpaneldefs.php create mode 100644 modules/Cases/metadata/subpanels/ForAccounts.php create mode 100644 modules/Cases/metadata/subpanels/ForEmails.php create mode 100644 modules/Cases/metadata/subpanels/default.php create mode 100644 modules/Cases/tpls/QuickCreate.tpl create mode 100644 modules/Cases/vardefs.php create mode 100644 modules/Charts/Dashlets/CampaignROIChartDashlet/CampaignROIChartConfigure.tpl create mode 100644 modules/Charts/Dashlets/CampaignROIChartDashlet/CampaignROIChartDashlet.data.php create mode 100644 modules/Charts/Dashlets/CampaignROIChartDashlet/CampaignROIChartDashlet.en_us.lang.php create mode 100644 modules/Charts/Dashlets/CampaignROIChartDashlet/CampaignROIChartDashlet.meta.php create mode 100644 modules/Charts/Dashlets/CampaignROIChartDashlet/CampaignROIChartDashlet.php create mode 100644 modules/Charts/Dashlets/MyPipelineBySalesStageDashlet/MyPipelineBySalesStageConfigure.tpl create mode 100644 modules/Charts/Dashlets/MyPipelineBySalesStageDashlet/MyPipelineBySalesStageDashlet.data.php create mode 100644 modules/Charts/Dashlets/MyPipelineBySalesStageDashlet/MyPipelineBySalesStageDashlet.en_us.lang.php create mode 100644 modules/Charts/Dashlets/MyPipelineBySalesStageDashlet/MyPipelineBySalesStageDashlet.meta.php create mode 100644 modules/Charts/Dashlets/MyPipelineBySalesStageDashlet/MyPipelineBySalesStageDashlet.php create mode 100644 modules/Charts/Dashlets/OppByLeadOutcomeDashlet/OppByLeadOutcomeConfigure.tpl create mode 100644 modules/Charts/Dashlets/OppByLeadOutcomeDashlet/OppByLeadOutcomeDashlet.data.php create mode 100644 modules/Charts/Dashlets/OppByLeadOutcomeDashlet/OppByLeadOutcomeDashlet.en_us.lang.php create mode 100644 modules/Charts/Dashlets/OppByLeadOutcomeDashlet/OppByLeadOutcomeDashlet.meta.php create mode 100644 modules/Charts/Dashlets/OppByLeadOutcomeDashlet/OppByLeadOutcomeDashlet.php create mode 100644 modules/Charts/Dashlets/OppByLeadSourceDashlet/OppByLeadSourceConfigure.tpl create mode 100644 modules/Charts/Dashlets/OppByLeadSourceDashlet/OppByLeadSourceDashlet.data.php create mode 100644 modules/Charts/Dashlets/OppByLeadSourceDashlet/OppByLeadSourceDashlet.en_us.lang.php create mode 100644 modules/Charts/Dashlets/OppByLeadSourceDashlet/OppByLeadSourceDashlet.meta.php create mode 100644 modules/Charts/Dashlets/OppByLeadSourceDashlet/OppByLeadSourceDashlet.php create mode 100644 modules/Charts/Dashlets/OutcomeByMonthDashlet/OutcomeByMonthConfigure.tpl create mode 100644 modules/Charts/Dashlets/OutcomeByMonthDashlet/OutcomeByMonthDashlet.data.php create mode 100644 modules/Charts/Dashlets/OutcomeByMonthDashlet/OutcomeByMonthDashlet.en_us.lang.php create mode 100644 modules/Charts/Dashlets/OutcomeByMonthDashlet/OutcomeByMonthDashlet.meta.php create mode 100644 modules/Charts/Dashlets/OutcomeByMonthDashlet/OutcomeByMonthDashlet.php create mode 100644 modules/Charts/Dashlets/PipelineBySalesStageDashlet/PipelineBySalesStageConfigure.tpl create mode 100644 modules/Charts/Dashlets/PipelineBySalesStageDashlet/PipelineBySalesStageDashlet.data.php create mode 100644 modules/Charts/Dashlets/PipelineBySalesStageDashlet/PipelineBySalesStageDashlet.en_us.lang.php create mode 100644 modules/Charts/Dashlets/PipelineBySalesStageDashlet/PipelineBySalesStageDashlet.meta.php create mode 100644 modules/Charts/Dashlets/PipelineBySalesStageDashlet/PipelineBySalesStageDashlet.php create mode 100644 modules/Charts/Dashlets/PredefinedChartDashletScript.tpl create mode 100644 modules/Charts/DynamicAction.php create mode 100644 modules/Charts/PredefinedChart.php create mode 100644 modules/Charts/chartdefs.php create mode 100644 modules/Charts/code/Chart_lead_source_by_outcome.php create mode 100644 modules/Charts/code/Chart_my_pipeline_by_sales_stage.php create mode 100644 modules/Charts/code/Chart_outcome_by_month.php create mode 100644 modules/Charts/code/Chart_pipeline_by_lead_source.php create mode 100644 modules/Charts/code/Chart_pipeline_by_sales_stage.php create mode 100644 modules/Charts/code/predefined_charts.php create mode 100644 modules/Charts/language/en_us.lang.php create mode 100644 modules/Configurator/Configurator.php create mode 100644 modules/Configurator/Forms.php create mode 100644 modules/Configurator/LogView.php create mode 100644 modules/Configurator/Menu.php create mode 100644 modules/Configurator/UploadFileCheck.php create mode 100644 modules/Configurator/action_view_map.php create mode 100644 modules/Configurator/controller.php create mode 100644 modules/Configurator/language/en_us.lang.php create mode 100644 modules/Configurator/metadata/SugarpdfSettingsdefs.php create mode 100644 modules/Configurator/tpls/EditView.tpl create mode 100644 modules/Configurator/tpls/SugarpdfSettings.tpl create mode 100644 modules/Configurator/tpls/SugarpdfSettingsFields.tpl create mode 100644 modules/Configurator/tpls/addFontResult.tpl create mode 100644 modules/Configurator/tpls/addFontView.tpl create mode 100644 modules/Configurator/tpls/adminwizard.tpl create mode 100644 modules/Configurator/tpls/fontmanager.tpl create mode 100644 modules/Configurator/views/view.addfontresult.php create mode 100644 modules/Configurator/views/view.addfontview.php create mode 100644 modules/Configurator/views/view.adminwizard.php create mode 100644 modules/Configurator/views/view.edit.php create mode 100644 modules/Configurator/views/view.fontmanager.php create mode 100644 modules/Configurator/views/view.sugarpdfsettings.php create mode 100644 modules/Connectors/Connector.js create mode 100644 modules/Connectors/ConnectorRecord.php create mode 100644 modules/Connectors/Forms.php create mode 100644 modules/Connectors/InstallDefaultConnectors.php create mode 100644 modules/Connectors/Menu.php create mode 100644 modules/Connectors/action_view_map.php create mode 100644 modules/Connectors/connectors/formatters/ext/rest/linkedin/linkedin.php create mode 100644 modules/Connectors/connectors/formatters/ext/rest/linkedin/tpls/default.tpl create mode 100644 modules/Connectors/connectors/formatters/ext/rest/linkedin/tpls/linkedin.gif create mode 100644 modules/Connectors/connectors/formatters/ext/rest/twitter/tpls/twitter.gif create mode 100644 modules/Connectors/connectors/sources/ext/rest/linkedin/config.php create mode 100644 modules/Connectors/connectors/sources/ext/rest/linkedin/language/en_us.lang.php create mode 100644 modules/Connectors/connectors/sources/ext/rest/linkedin/linkedin.php create mode 100644 modules/Connectors/connectors/sources/ext/rest/linkedin/mapping.php create mode 100644 modules/Connectors/connectors/sources/ext/rest/linkedin/vardefs.php create mode 100644 modules/Connectors/controller.php create mode 100644 modules/Connectors/language/en_us.lang.php create mode 100644 modules/Connectors/metadata/searchdefs.php create mode 100644 modules/Connectors/tpls/administration.tpl create mode 100644 modules/Connectors/tpls/display_properties.tpl create mode 100644 modules/Connectors/tpls/listview.tpl create mode 100644 modules/Connectors/tpls/mapping_properties.tpl create mode 100644 modules/Connectors/tpls/modify_display.tpl create mode 100644 modules/Connectors/tpls/modify_mapping.tpl create mode 100644 modules/Connectors/tpls/modify_properties.tpl create mode 100644 modules/Connectors/tpls/modify_search.tpl create mode 100644 modules/Connectors/tpls/search_form.tpl create mode 100644 modules/Connectors/tpls/search_properties.tpl create mode 100644 modules/Connectors/tpls/source_properties.tpl create mode 100644 modules/Connectors/tpls/tabs.css create mode 100644 modules/Connectors/views/view.connectorsettings.php create mode 100644 modules/Connectors/views/view.displayproperties.php create mode 100644 modules/Connectors/views/view.mappingproperties.php create mode 100644 modules/Connectors/views/view.modifydisplay.php create mode 100644 modules/Connectors/views/view.modifymapping.php create mode 100644 modules/Connectors/views/view.modifyproperties.php create mode 100644 modules/Connectors/views/view.modifysearch.php create mode 100644 modules/Connectors/views/view.searchproperties.php create mode 100644 modules/Connectors/views/view.sourceproperties.php create mode 100644 modules/Contacts/AcceptDecline.php create mode 100644 modules/Contacts/Address_picker.html create mode 100644 modules/Contacts/BusinessCard.html create mode 100644 modules/Contacts/BusinessCard.php create mode 100644 modules/Contacts/Contact.js create mode 100644 modules/Contacts/Contact.php create mode 100644 modules/Contacts/ContactFormBase.php create mode 100644 modules/Contacts/ContactOpportunityRelationship.php create mode 100644 modules/Contacts/ContactOpportunityRelationshipEdit.html create mode 100644 modules/Contacts/ContactOpportunityRelationshipEdit.php create mode 100644 modules/Contacts/ContactsQuickCreate.php create mode 100644 modules/Contacts/Dashlets/MyContactsDashlet/MyContactsDashlet.data.php create mode 100644 modules/Contacts/Dashlets/MyContactsDashlet/MyContactsDashlet.meta.php create mode 100644 modules/Contacts/Dashlets/MyContactsDashlet/MyContactsDashlet.php create mode 100644 modules/Contacts/Email_picker.html create mode 100644 modules/Contacts/MailMergePicker.html create mode 100644 modules/Contacts/Menu.php create mode 100644 modules/Contacts/Popup_picker.php create mode 100644 modules/Contacts/Save.php create mode 100644 modules/Contacts/SaveContactOpportunityRelationship.php create mode 100644 modules/Contacts/ShowDuplicates.html create mode 100644 modules/Contacts/ShowDuplicates.php create mode 100644 modules/Contacts/SugarFeeds/ContactFeed.php create mode 100644 modules/Contacts/controller.php create mode 100644 modules/Contacts/field_arrays.php create mode 100644 modules/Contacts/language/en_us.lang.php create mode 100644 modules/Contacts/metadata/SearchFields.php create mode 100644 modules/Contacts/metadata/additionalDetails.php create mode 100644 modules/Contacts/metadata/detailviewdefs.php create mode 100644 modules/Contacts/metadata/editviewdefs.php create mode 100644 modules/Contacts/metadata/listviewdefs.php create mode 100644 modules/Contacts/metadata/metafiles.php create mode 100644 modules/Contacts/metadata/popupdefs.php create mode 100644 modules/Contacts/metadata/popupdefsEmail.php create mode 100644 modules/Contacts/metadata/quickcreatedefs.php create mode 100644 modules/Contacts/metadata/searchdefs.php create mode 100644 modules/Contacts/metadata/studio.php create mode 100644 modules/Contacts/metadata/subpaneldefs.php create mode 100644 modules/Contacts/metadata/subpanels/ForAccounts.php create mode 100644 modules/Contacts/metadata/subpanels/ForCalls.php create mode 100644 modules/Contacts/metadata/subpanels/ForCases.php create mode 100644 modules/Contacts/metadata/subpanels/ForContacts.php create mode 100644 modules/Contacts/metadata/subpanels/ForEmails.php create mode 100644 modules/Contacts/metadata/subpanels/ForMeetings.php create mode 100644 modules/Contacts/metadata/subpanels/ForOpportunities.php create mode 100644 modules/Contacts/metadata/subpanels/ForProject.php create mode 100644 modules/Contacts/metadata/subpanels/default.php create mode 100644 modules/Contacts/tpls/QuickCreate.tpl create mode 100644 modules/Contacts/vardefs.php create mode 100644 modules/Contacts/views/view.closecontactaddresspopup.php create mode 100644 modules/Contacts/views/view.contactaddresspopup.php create mode 100644 modules/Contacts/views/view.detail.php create mode 100644 modules/Contacts/views/view.edit.php create mode 100644 modules/Contacts/views/view.list.php create mode 100644 modules/Contacts/views/view.mailmergepopup.php create mode 100644 modules/Contacts/views/view.retrieveemail.php create mode 100644 modules/Contacts/views/view.validportalusername.php create mode 100644 modules/Currencies/Currency.php create mode 100644 modules/Currencies/EditCurrency.php create mode 100644 modules/Currencies/EditView.js create mode 100644 modules/Currencies/EditView.tpl create mode 100644 modules/Currencies/Forms.php create mode 100644 modules/Currencies/ListCurrency.php create mode 100644 modules/Currencies/ListView.html create mode 100644 modules/Currencies/Menu.php create mode 100644 modules/Currencies/field_arrays.php create mode 100644 modules/Currencies/index.php create mode 100644 modules/Currencies/iso4217.php create mode 100644 modules/Currencies/language/en_us.lang.php create mode 100644 modules/Currencies/vardefs.php create mode 100644 modules/DocumentRevisions/DocumentRevision.php create mode 100644 modules/DocumentRevisions/Forms.php create mode 100644 modules/DocumentRevisions/ListView.html create mode 100644 modules/DocumentRevisions/Menu.php create mode 100644 modules/DocumentRevisions/field_arrays.php create mode 100644 modules/DocumentRevisions/language/en_us.lang.php create mode 100644 modules/DocumentRevisions/metadata/detailviewdefs.php create mode 100644 modules/DocumentRevisions/metadata/editviewdefs.php create mode 100644 modules/DocumentRevisions/metadata/subpanels/default.php create mode 100644 modules/DocumentRevisions/subpanels/default.php create mode 100644 modules/DocumentRevisions/vardefs.php create mode 100644 modules/Documents/Dashlets/MyDocumentsDashlet/MyDocumentsDashlet.data.php create mode 100644 modules/Documents/Dashlets/MyDocumentsDashlet/MyDocumentsDashlet.meta.php create mode 100644 modules/Documents/Dashlets/MyDocumentsDashlet/MyDocumentsDashlet.php create mode 100644 modules/Documents/Delete.php create mode 100644 modules/Documents/Document.php create mode 100644 modules/Documents/DocumentExternalApiDropDown.php create mode 100644 modules/Documents/DocumentSoap.php create mode 100644 modules/Documents/GetLatestRevision.php create mode 100644 modules/Documents/Menu.php create mode 100644 modules/Documents/Popup.php create mode 100644 modules/Documents/Popup_picker.html create mode 100644 modules/Documents/Popup_picker.php create mode 100644 modules/Documents/TreeData.php create mode 100644 modules/Documents/action_view_map.php create mode 100644 modules/Documents/documents.js create mode 100644 modules/Documents/field_arrays.php create mode 100644 modules/Documents/language/en_us.lang.php create mode 100644 modules/Documents/metadata/SearchFields.php create mode 100644 modules/Documents/metadata/detailviewdefs.php create mode 100644 modules/Documents/metadata/editviewdefs.php create mode 100644 modules/Documents/metadata/listviewdefs.php create mode 100644 modules/Documents/metadata/quickcreatedefs.php create mode 100644 modules/Documents/metadata/searchdefs.php create mode 100644 modules/Documents/metadata/studio.php create mode 100644 modules/Documents/metadata/subpaneldefs.php create mode 100644 modules/Documents/metadata/subpanels/ForContractType.php create mode 100644 modules/Documents/metadata/subpanels/default.php create mode 100644 modules/Documents/tpls/view.extdoc.tpl create mode 100644 modules/Documents/vardefs.php create mode 100644 modules/Documents/views/view.detail.php create mode 100644 modules/Documents/views/view.edit.php create mode 100644 modules/Documents/views/view.extdoc.php create mode 100644 modules/DynamicFields/DynamicField.php create mode 100644 modules/DynamicFields/FieldCases.php create mode 100644 modules/DynamicFields/FieldViewer.php create mode 100644 modules/DynamicFields/FieldsMetaData.php create mode 100644 modules/DynamicFields/Save.php create mode 100644 modules/DynamicFields/UpgradeFields.php create mode 100644 modules/DynamicFields/language/en_us.lang.php create mode 100644 modules/DynamicFields/templates/Fields/Forms/address.tpl create mode 100644 modules/DynamicFields/templates/Fields/Forms/bool.tpl create mode 100644 modules/DynamicFields/templates/Fields/Forms/coreBottom.tpl create mode 100644 modules/DynamicFields/templates/Fields/Forms/coreTop.tpl create mode 100644 modules/DynamicFields/templates/Fields/Forms/currency.tpl create mode 100644 modules/DynamicFields/templates/Fields/Forms/date.php create mode 100644 modules/DynamicFields/templates/Fields/Forms/date.tpl create mode 100644 modules/DynamicFields/templates/Fields/Forms/datetimecombo.php create mode 100644 modules/DynamicFields/templates/Fields/Forms/datetimecombo.tpl create mode 100644 modules/DynamicFields/templates/Fields/Forms/encrypt.php create mode 100644 modules/DynamicFields/templates/Fields/Forms/encrypt.tpl create mode 100644 modules/DynamicFields/templates/Fields/Forms/enum.tpl create mode 100644 modules/DynamicFields/templates/Fields/Forms/enum2.php create mode 100644 modules/DynamicFields/templates/Fields/Forms/float.tpl create mode 100644 modules/DynamicFields/templates/Fields/Forms/html.php create mode 100644 modules/DynamicFields/templates/Fields/Forms/html.tpl create mode 100644 modules/DynamicFields/templates/Fields/Forms/iframe.php create mode 100644 modules/DynamicFields/templates/Fields/Forms/iframe.tpl create mode 100644 modules/DynamicFields/templates/Fields/Forms/image.php create mode 100644 modules/DynamicFields/templates/Fields/Forms/image.tpl create mode 100644 modules/DynamicFields/templates/Fields/Forms/int.tpl create mode 100644 modules/DynamicFields/templates/Fields/Forms/multienum.php create mode 100644 modules/DynamicFields/templates/Fields/Forms/multienum.tpl create mode 100644 modules/DynamicFields/templates/Fields/Forms/parent.php create mode 100644 modules/DynamicFields/templates/Fields/Forms/parent.tpl create mode 100644 modules/DynamicFields/templates/Fields/Forms/phone.php create mode 100644 modules/DynamicFields/templates/Fields/Forms/phone.tpl create mode 100644 modules/DynamicFields/templates/Fields/Forms/radioenum.php create mode 100644 modules/DynamicFields/templates/Fields/Forms/relate.php create mode 100644 modules/DynamicFields/templates/Fields/Forms/relate.tpl create mode 100644 modules/DynamicFields/templates/Fields/Forms/text.tpl create mode 100644 modules/DynamicFields/templates/Fields/Forms/url.php create mode 100644 modules/DynamicFields/templates/Fields/Forms/url.tpl create mode 100644 modules/DynamicFields/templates/Fields/Forms/varchar.tpl create mode 100644 modules/DynamicFields/templates/Fields/TemplateAddress.php create mode 100644 modules/DynamicFields/templates/Fields/TemplateAddressCountry.php create mode 100644 modules/DynamicFields/templates/Fields/TemplateBoolean.php create mode 100644 modules/DynamicFields/templates/Fields/TemplateCurrency.php create mode 100644 modules/DynamicFields/templates/Fields/TemplateCurrencyId.php create mode 100644 modules/DynamicFields/templates/Fields/TemplateDate.php create mode 100644 modules/DynamicFields/templates/Fields/TemplateDatetimecombo.php create mode 100644 modules/DynamicFields/templates/Fields/TemplateDecimal.php create mode 100644 modules/DynamicFields/templates/Fields/TemplateEmail.php create mode 100644 modules/DynamicFields/templates/Fields/TemplateEncrypt.php create mode 100644 modules/DynamicFields/templates/Fields/TemplateEnum.php create mode 100644 modules/DynamicFields/templates/Fields/TemplateField.php create mode 100644 modules/DynamicFields/templates/Fields/TemplateFloat.php create mode 100644 modules/DynamicFields/templates/Fields/TemplateHTML.php create mode 100644 modules/DynamicFields/templates/Fields/TemplateIFrame.php create mode 100644 modules/DynamicFields/templates/Fields/TemplateId.php create mode 100644 modules/DynamicFields/templates/Fields/TemplateImage.php create mode 100644 modules/DynamicFields/templates/Fields/TemplateInt.php create mode 100644 modules/DynamicFields/templates/Fields/TemplateMultiEnum.php create mode 100644 modules/DynamicFields/templates/Fields/TemplateParent.php create mode 100644 modules/DynamicFields/templates/Fields/TemplateParentType.php create mode 100644 modules/DynamicFields/templates/Fields/TemplatePhone.php create mode 100644 modules/DynamicFields/templates/Fields/TemplateRadioEnum.php create mode 100644 modules/DynamicFields/templates/Fields/TemplateRange.php create mode 100644 modules/DynamicFields/templates/Fields/TemplateRelatedTextField.php create mode 100644 modules/DynamicFields/templates/Fields/TemplateText.php create mode 100644 modules/DynamicFields/templates/Fields/TemplateTextArea.php create mode 100644 modules/DynamicFields/templates/Fields/TemplateURL.php create mode 100644 modules/DynamicFields/templates/Files/DetailView.php create mode 100644 modules/DynamicFields/templates/Files/EditView.php create mode 100644 modules/DynamicFields/vardefs.php create mode 100644 modules/EAPM/CheckLogins.php create mode 100644 modules/EAPM/EAPM.php create mode 100644 modules/EAPM/EAPMEdit.js create mode 100644 modules/EAPM/action_view_map.php create mode 100644 modules/EAPM/controller.php create mode 100644 modules/EAPM/language/en_us.lang.php create mode 100644 modules/EAPM/metadata/SearchFields.php create mode 100644 modules/EAPM/metadata/detailviewdefs.php create mode 100644 modules/EAPM/metadata/editviewdefs.php create mode 100644 modules/EAPM/metadata/listviewdefs.php create mode 100644 modules/EAPM/metadata/metafiles.php create mode 100644 modules/EAPM/metadata/popupdefs.php create mode 100644 modules/EAPM/metadata/quickcreatedefs.php create mode 100644 modules/EAPM/metadata/searchdefs.php create mode 100644 modules/EAPM/metadata/subpanels/default.php create mode 100644 modules/EAPM/tpls/DetailViewFooter.tpl create mode 100644 modules/EAPM/tpls/EditViewFooter.tpl create mode 100644 modules/EAPM/tpls/EditViewHeader.tpl create mode 100644 modules/EAPM/vardefs.php create mode 100644 modules/EAPM/views/view.detail.php create mode 100644 modules/EAPM/views/view.edit.php create mode 100644 modules/EmailAddresses/EmailAddress.php create mode 100644 modules/EmailAddresses/language/en_us.lang.php create mode 100644 modules/EmailAddresses/vardefs.php create mode 100644 modules/EmailMan/EmailMan.php create mode 100644 modules/EmailMan/EmailManDelivery.php create mode 100644 modules/EmailMan/Forms.php create mode 100644 modules/EmailMan/Menu.php create mode 100644 modules/EmailMan/Save.php create mode 100644 modules/EmailMan/action_view_map.php create mode 100644 modules/EmailMan/field_arrays.php create mode 100644 modules/EmailMan/language/en_us.lang.php create mode 100644 modules/EmailMan/metadata/SearchFields.php create mode 100644 modules/EmailMan/metadata/listviewdefs.php create mode 100644 modules/EmailMan/metadata/searchdefs.php create mode 100644 modules/EmailMan/metadata/subpanels/default.php create mode 100644 modules/EmailMan/subpanels/default.php create mode 100644 modules/EmailMan/testOutboundEmail.php create mode 100644 modules/EmailMan/tpls/campaignconfig.tpl create mode 100644 modules/EmailMan/tpls/config.tpl create mode 100644 modules/EmailMan/vardefs.php create mode 100644 modules/EmailMan/views/view.campaignconfig.php create mode 100644 modules/EmailMan/views/view.config.php create mode 100644 modules/EmailMan/views/view.list.php create mode 100644 modules/EmailMarketing/Delete.php create mode 100644 modules/EmailMarketing/DetailView.html create mode 100644 modules/EmailMarketing/DetailView.php create mode 100644 modules/EmailMarketing/EditView.html create mode 100644 modules/EmailMarketing/EditView.php create mode 100644 modules/EmailMarketing/EmailMarketing.php create mode 100644 modules/EmailMarketing/Forms.php create mode 100644 modules/EmailMarketing/Menu.php create mode 100644 modules/EmailMarketing/Save.php create mode 100644 modules/EmailMarketing/SubPanelView.html create mode 100644 modules/EmailMarketing/SubPanelView.php create mode 100644 modules/EmailMarketing/field_arrays.php create mode 100644 modules/EmailMarketing/language/en_us.lang.php create mode 100644 modules/EmailMarketing/metadata/subpaneldefs.php create mode 100644 modules/EmailMarketing/metadata/subpanels/default.php create mode 100644 modules/EmailMarketing/subpanels/default.php create mode 100644 modules/EmailMarketing/vardefs.php create mode 100644 modules/EmailTemplates/AttachFiles.php create mode 100644 modules/EmailTemplates/CheckDeletable.php create mode 100644 modules/EmailTemplates/Delete.php create mode 100644 modules/EmailTemplates/DetailView.html create mode 100644 modules/EmailTemplates/DetailView.php create mode 100644 modules/EmailTemplates/EditView.html create mode 100644 modules/EmailTemplates/EditView.php create mode 100644 modules/EmailTemplates/EditViewMain.html create mode 100644 modules/EmailTemplates/EmailTemplate.js create mode 100644 modules/EmailTemplates/EmailTemplate.php create mode 100644 modules/EmailTemplates/EmailTemplateFormBase.php create mode 100644 modules/EmailTemplates/Menu.php create mode 100644 modules/EmailTemplates/PopupDocumentsCampaignTemplate.html create mode 100644 modules/EmailTemplates/PopupDocumentsCampaignTemplate.php create mode 100644 modules/EmailTemplates/Save.php create mode 100644 modules/EmailTemplates/field_arrays.php create mode 100644 modules/EmailTemplates/language/en_us.lang.php create mode 100644 modules/EmailTemplates/metadata/SearchFields.php create mode 100644 modules/EmailTemplates/metadata/listviewdefs.php create mode 100644 modules/EmailTemplates/metadata/searchdefs.php create mode 100644 modules/EmailTemplates/vardefs.php create mode 100644 modules/Emails/Check.php create mode 100644 modules/Emails/Compose.php create mode 100644 modules/Emails/Dashlets/MyEmailsDashlet/MyEmailsDashlet.data.php create mode 100644 modules/Emails/Dashlets/MyEmailsDashlet/MyEmailsDashlet.meta.php create mode 100644 modules/Emails/Dashlets/MyEmailsDashlet/MyEmailsDashlet.php create mode 100644 modules/Emails/Delete.php create mode 100644 modules/Emails/DetailView.html create mode 100644 modules/Emails/DetailView.php create mode 100644 modules/Emails/DetailViewSent.html create mode 100644 modules/Emails/EditView.html create mode 100644 modules/Emails/EditView.php create mode 100644 modules/Emails/EditViewArchive.html create mode 100644 modules/Emails/Email.php create mode 100644 modules/Emails/EmailUI.css create mode 100644 modules/Emails/EmailUI.php create mode 100644 modules/Emails/EmailUIAjax.php create mode 100644 modules/Emails/GenerateQuickComposeFrame.php create mode 100644 modules/Emails/Grab.php create mode 100644 modules/Emails/ListViewDrafts.html create mode 100644 modules/Emails/ListViewGroup.php create mode 100644 modules/Emails/ListViewGroupInbox.html create mode 100644 modules/Emails/ListViewHome.html create mode 100644 modules/Emails/ListViewHome.php create mode 100644 modules/Emails/ListViewMyInbox.html create mode 100644 modules/Emails/ListViewSent.html create mode 100644 modules/Emails/MassDelete.php create mode 100644 modules/Emails/Menu.php create mode 100644 modules/Emails/PessimisticLock.php create mode 100644 modules/Emails/Popup.php create mode 100644 modules/Emails/PopupDocuments.html create mode 100644 modules/Emails/PopupDocuments.php create mode 100644 modules/Emails/Popup_picker.html create mode 100644 modules/Emails/Popup_picker.php create mode 100644 modules/Emails/Save.php create mode 100644 modules/Emails/SearchForm.html create mode 100644 modules/Emails/SearchFormGroupInbox.html create mode 100644 modules/Emails/SearchFormMyInbox.html create mode 100644 modules/Emails/SearchFormSent.html create mode 100644 modules/Emails/Status.html create mode 100644 modules/Emails/Status.php create mode 100644 modules/Emails/SubPanelViewRecipients.html create mode 100644 modules/Emails/SubPanelViewRecipients.php create mode 100644 modules/Emails/SugarRoutingAsync.php create mode 100644 modules/Emails/field_arrays.php create mode 100644 modules/Emails/images/autofit.gif create mode 100644 modules/Emails/images/colsView.gif create mode 100644 modules/Emails/images/email.gif create mode 100644 modules/Emails/images/emailGroup.gif create mode 100644 modules/Emails/images/fullscreen.gif create mode 100644 modules/Emails/images/leftarrow_inline.gif create mode 100644 modules/Emails/images/rightarrow_inline.gif create mode 100644 modules/Emails/images/rowsView.gif create mode 100644 modules/Emails/images/sugar.gif create mode 100644 modules/Emails/images/sugarDynamic.gif create mode 100644 modules/Emails/images/sugarGroup.gif create mode 100644 modules/Emails/index.php create mode 100644 modules/Emails/javascript/Email.js create mode 100644 modules/Emails/javascript/EmailUI.js create mode 100644 modules/Emails/javascript/EmailUICompose.js create mode 100644 modules/Emails/javascript/EmailUIShared.js create mode 100644 modules/Emails/javascript/ajax.js create mode 100644 modules/Emails/javascript/complexLayout.js create mode 100644 modules/Emails/javascript/composeEmailTemplate.js create mode 100644 modules/Emails/javascript/displayOneEmailTemplate.js create mode 100644 modules/Emails/javascript/email_popup_helper.js create mode 100644 modules/Emails/javascript/grid.js create mode 100644 modules/Emails/javascript/init.js create mode 100644 modules/Emails/javascript/vars.js create mode 100644 modules/Emails/javascript/viewPrintable.js create mode 100644 modules/Emails/language/en_us.lang.php create mode 100644 modules/Emails/metadata/additionalDetails.php create mode 100644 modules/Emails/metadata/popupdefs.php create mode 100644 modules/Emails/metadata/qcmodulesdefs.php create mode 100644 modules/Emails/metadata/subpaneldefs.php create mode 100644 modules/Emails/metadata/subpanels/ForContacts.php create mode 100644 modules/Emails/metadata/subpanels/ForHistory.php create mode 100644 modules/Emails/metadata/subpanels/ForQueues.php create mode 100644 modules/Emails/metadata/subpanels/ForUnlinkedEmailHistory.php create mode 100644 modules/Emails/metadata/subpanels/ForUsers.php create mode 100644 modules/Emails/subpanels/ForContacts.php create mode 100644 modules/Emails/subpanels/ForHistory.php create mode 100644 modules/Emails/subpanels/ForQueues.php create mode 100644 modules/Emails/subpanels/ForUsers.php create mode 100644 modules/Emails/templates/_baseConfigData.tpl create mode 100644 modules/Emails/templates/_baseEmail.tpl create mode 100644 modules/Emails/templates/_baseJsVars.tpl create mode 100644 modules/Emails/templates/_blank.html create mode 100644 modules/Emails/templates/_createGroupFolder.tpl create mode 100644 modules/Emails/templates/addressBook.tpl create mode 100644 modules/Emails/templates/addressSearch.tpl create mode 100644 modules/Emails/templates/addressSearchContent.tpl create mode 100644 modules/Emails/templates/advancedSearch.tpl create mode 100644 modules/Emails/templates/assignTo.tpl create mode 100644 modules/Emails/templates/dceMenuQuickCreate.tpl create mode 100644 modules/Emails/templates/editAccountDialogue.tpl create mode 100644 modules/Emails/templates/editContact.tpl create mode 100644 modules/Emails/templates/editMailingList.tpl create mode 100644 modules/Emails/templates/emailDetailView.tpl create mode 100644 modules/Emails/templates/emailSettings.tpl create mode 100644 modules/Emails/templates/emailSettingsAccountDetails.tpl create mode 100644 modules/Emails/templates/emailSettingsAccounts.tpl create mode 100644 modules/Emails/templates/emailSettingsFolders.tpl create mode 100644 modules/Emails/templates/emailSettingsGeneral.tpl create mode 100644 modules/Emails/templates/emailSettingsRules.tpl create mode 100644 modules/Emails/templates/importRelate.tpl create mode 100644 modules/Emails/templates/outboundDialog.tpl create mode 100644 modules/Emails/templates/outboundDialogTest.tpl create mode 100644 modules/Emails/templates/overlay.tpl create mode 100644 modules/Emails/templates/successMessage.tpl create mode 100644 modules/Emails/vardefs.php create mode 100644 modules/Emails/views/view.classic.config.php create mode 100644 modules/Emails/views/view.modulelistmenu.php create mode 100644 modules/Emails/views/view.quickcreate.php create mode 100644 modules/Employees/Employee.php create mode 100644 modules/Employees/Error.php create mode 100644 modules/Employees/Forms.php create mode 100644 modules/Employees/Menu.php create mode 100644 modules/Employees/Popup_picker.html create mode 100644 modules/Employees/Popup_picker.php create mode 100644 modules/Employees/Save.php create mode 100644 modules/Employees/WapAuthenticate.php create mode 100644 modules/Employees/WapMenu.php create mode 100644 modules/Employees/controller.php create mode 100644 modules/Employees/field_arrays.php create mode 100644 modules/Employees/language/en_us.lang.php create mode 100644 modules/Employees/metadata/SearchFields.php create mode 100644 modules/Employees/metadata/detailviewdefs.php create mode 100644 modules/Employees/metadata/editviewdefs.php create mode 100644 modules/Employees/metadata/listviewdefs.php create mode 100644 modules/Employees/metadata/searchdefs.php create mode 100644 modules/Employees/vardefs.php create mode 100644 modules/Employees/views/view.detail.php create mode 100644 modules/Employees/views/view.edit.php create mode 100644 modules/Employees/views/view.list.php create mode 100644 modules/Groups/Delete.php create mode 100644 modules/Groups/DetailView.html create mode 100644 modules/Groups/DetailView.php create mode 100644 modules/Groups/EditView.html create mode 100644 modules/Groups/EditView.php create mode 100644 modules/Groups/Forms.php create mode 100644 modules/Groups/Group.php create mode 100644 modules/Groups/ListView.html create mode 100644 modules/Groups/ListView.php create mode 100644 modules/Groups/Menu.php create mode 100644 modules/Groups/Save.php create mode 100644 modules/Groups/index.php create mode 100644 modules/Groups/language/en_us.lang.php create mode 100644 modules/Groups/vardefs.php create mode 100644 modules/Help/Menu.php create mode 100644 modules/Help/index.php create mode 100644 modules/Help/language/en_us.lang.php create mode 100644 modules/History/language/en_us.lang.php create mode 100644 modules/History/metadata/subpaneldefs.php create mode 100644 modules/Home/About.php create mode 100644 modules/Home/AddToFavorites.php create mode 100644 modules/Home/Dashlets/ChartsDashlet/ChartsDashlet.en_us.lang.php create mode 100644 modules/Home/Dashlets/ChartsDashlet/ChartsDashlet.meta.php create mode 100644 modules/Home/Dashlets/ChartsDashlet/ChartsDashlet.php create mode 100644 modules/Home/Dashlets/ChartsDashlet/ChartsDashletScript.tpl create mode 100644 modules/Home/Dashlets/InvadersDashlet/InvadersDashlet.en_us.lang.php create mode 100644 modules/Home/Dashlets/InvadersDashlet/InvadersDashlet.icon.jpg create mode 100644 modules/Home/Dashlets/InvadersDashlet/InvadersDashlet.meta.php create mode 100644 modules/Home/Dashlets/InvadersDashlet/InvadersDashlet.php create mode 100644 modules/Home/Dashlets/InvadersDashlet/InvadersDashlet.tpl create mode 100644 modules/Home/Dashlets/InvadersDashlet/InvadersDashletScript.tpl create mode 100644 modules/Home/Dashlets/InvadersDashlet/InvadersOptions.tpl create mode 100644 modules/Home/Dashlets/InvadersDashlet/sprites/alien.png create mode 100644 modules/Home/Dashlets/InvadersDashlet/sprites/bg.png create mode 100644 modules/Home/Dashlets/InvadersDashlet/sprites/cube.png create mode 100644 modules/Home/Dashlets/InvadersDashlet/sprites/player.png create mode 100644 modules/Home/Dashlets/JotPadDashlet/JotPadDashlet.en_us.lang.php create mode 100644 modules/Home/Dashlets/JotPadDashlet/JotPadDashlet.meta.php create mode 100644 modules/Home/Dashlets/JotPadDashlet/JotPadDashlet.php create mode 100644 modules/Home/Dashlets/JotPadDashlet/JotPadDashlet.tpl create mode 100644 modules/Home/Dashlets/JotPadDashlet/JotPadDashletOptions.tpl create mode 100644 modules/Home/Dashlets/JotPadDashlet/JotPadDashletScript.tpl create mode 100644 modules/Home/Dashlets/RSSDashlet/RSSDashlet.en_us.lang.php create mode 100644 modules/Home/Dashlets/RSSDashlet/RSSDashlet.icon.jpg create mode 100644 modules/Home/Dashlets/RSSDashlet/RSSDashlet.meta.php create mode 100644 modules/Home/Dashlets/RSSDashlet/RSSDashlet.php create mode 100644 modules/Home/Dashlets/RSSDashlet/RSSDashlet.tpl create mode 100644 modules/Home/Dashlets/RSSDashlet/RSSDashletOptions.tpl create mode 100644 modules/Home/Dashlets/SugarNewsDashlet/SugarNewsDashlet.meta.php create mode 100644 modules/Home/Dashlets/SugarNewsDashlet/SugarNewsDashlet.php create mode 100644 modules/Home/Dashlets/SugarNewsDashlet/configure.tpl create mode 100644 modules/Home/Dashlets/iFrameDashlet/configure.tpl create mode 100644 modules/Home/Dashlets/iFrameDashlet/iFrameDashlet.meta.php create mode 100644 modules/Home/Dashlets/iFrameDashlet/iFrameDashlet.php create mode 100644 modules/Home/DynamicAction.php create mode 100644 modules/Home/Home.html create mode 100644 modules/Home/Home.tpl create mode 100644 modules/Home/LastViewed.php create mode 100644 modules/Home/Menu.php create mode 100644 modules/Home/PopupSugar.php create mode 100644 modules/Home/SaveSubpanelLayout.php create mode 100644 modules/Home/SubpanelCreates.php create mode 100644 modules/Home/TrainingPortal.php create mode 100644 modules/Home/TrainingPortal.tpl create mode 100644 modules/Home/UnifiedSearch.php create mode 100644 modules/Home/UnifiedSearchAdvanced.php create mode 100644 modules/Home/UnifiedSearchAdvanced.tpl create mode 100644 modules/Home/UnifiedSearchAdvancedForm.tpl create mode 100644 modules/Home/UnifiedSearchAdvancedResults.tpl create mode 100644 modules/Home/about.js create mode 100644 modules/Home/action_view_map.php create mode 100644 modules/Home/dashlets.php create mode 100644 modules/Home/index.php create mode 100644 modules/Home/language/en_us.lang.php create mode 100644 modules/Home/quicksearchQuery.php create mode 100644 modules/Home/sitemap.php create mode 100644 modules/Home/sitemap.tpl create mode 100644 modules/Home/views/view.additionaldetailsretrieve.php create mode 100644 modules/Home/views/view.list.php create mode 100644 modules/Home/views/view.modulelistmenu.php create mode 100644 modules/Import/Forms.php create mode 100644 modules/Import/ImportCacheFiles.php create mode 100644 modules/Import/ImportDuplicateCheck.php create mode 100644 modules/Import/ImportFieldSanitize.php create mode 100644 modules/Import/ImportFile.php create mode 100644 modules/Import/ImportFileSplitter.php create mode 100644 modules/Import/ImportMap.php create mode 100644 modules/Import/ImportMapAct.php create mode 100644 modules/Import/ImportMapCsv.php create mode 100644 modules/Import/ImportMapOther.php create mode 100644 modules/Import/ImportMapOutlook.php create mode 100644 modules/Import/ImportMapSalesforce.php create mode 100644 modules/Import/ImportMapTab.php create mode 100644 modules/Import/Menu.php create mode 100644 modules/Import/UsersLastImport.php create mode 100644 modules/Import/controller.php create mode 100644 modules/Import/language/en_us.lang.php create mode 100644 modules/Import/tpls/error.tpl create mode 100644 modules/Import/tpls/last.tpl create mode 100644 modules/Import/tpls/step1.tpl create mode 100644 modules/Import/tpls/step2.tpl create mode 100644 modules/Import/tpls/step3.tpl create mode 100644 modules/Import/tpls/undo.tpl create mode 100644 modules/Import/vardefs.php create mode 100644 modules/Import/views/view.error.php create mode 100644 modules/Import/views/view.last.php create mode 100644 modules/Import/views/view.step1.php create mode 100644 modules/Import/views/view.step2.php create mode 100644 modules/Import/views/view.step3.php create mode 100644 modules/Import/views/view.step4.php create mode 100644 modules/Import/views/view.undo.php create mode 100644 modules/InboundEmail/Delete.php create mode 100644 modules/InboundEmail/DetailView.html create mode 100644 modules/InboundEmail/DetailView.php create mode 100644 modules/InboundEmail/EditGroupFolder.php create mode 100644 modules/InboundEmail/EditView.html create mode 100644 modules/InboundEmail/EditView.php create mode 100644 modules/InboundEmail/InboundEmail.js create mode 100644 modules/InboundEmail/InboundEmail.php create mode 100644 modules/InboundEmail/InboundEmailTest.php create mode 100644 modules/InboundEmail/ListView.html create mode 100644 modules/InboundEmail/ListView.php create mode 100644 modules/InboundEmail/Menu.php create mode 100644 modules/InboundEmail/Popup.php create mode 100644 modules/InboundEmail/Save.php create mode 100644 modules/InboundEmail/SaveGroupFolder.php create mode 100644 modules/InboundEmail/ShowInboundFoldersList.php create mode 100644 modules/InboundEmail/View.html create mode 100644 modules/InboundEmail/field_arrays.php create mode 100644 modules/InboundEmail/index.php create mode 100644 modules/InboundEmail/language/en_us.lang.php create mode 100644 modules/InboundEmail/vardefs.php create mode 100644 modules/LabelEditor/EditView.html create mode 100644 modules/LabelEditor/EditView.php create mode 100644 modules/LabelEditor/Forms.php create mode 100644 modules/LabelEditor/LabelList.php create mode 100644 modules/LabelEditor/Menu.php create mode 100644 modules/LabelEditor/Save.php create mode 100644 modules/LabelEditor/language/en_us.lang.php create mode 100644 modules/Leads/Capture.php create mode 100644 modules/Leads/Dashlets/MyLeadsDashlet/MyLeadsDashlet.data.php create mode 100644 modules/Leads/Dashlets/MyLeadsDashlet/MyLeadsDashlet.meta.php create mode 100644 modules/Leads/Dashlets/MyLeadsDashlet/MyLeadsDashlet.php create mode 100644 modules/Leads/Lead.js create mode 100644 modules/Leads/Lead.php create mode 100644 modules/Leads/LeadFormBase.php create mode 100644 modules/Leads/LeadsQuickCreate.php create mode 100644 modules/Leads/Menu.php create mode 100644 modules/Leads/MyLeads.html create mode 100644 modules/Leads/MyLeads.php create mode 100644 modules/Leads/Popup_picker.html create mode 100644 modules/Leads/Save.php create mode 100644 modules/Leads/SubPanelView.html create mode 100644 modules/Leads/SubPanelView.php create mode 100644 modules/Leads/SugarFeeds/LeadFeed.php create mode 100644 modules/Leads/action_view_map.php create mode 100644 modules/Leads/controller.php create mode 100644 modules/Leads/field_arrays.php create mode 100644 modules/Leads/language/en_us.lang.php create mode 100644 modules/Leads/metadata/SearchFields.php create mode 100644 modules/Leads/metadata/additionalDetails.php create mode 100644 modules/Leads/metadata/convertdefs.php create mode 100644 modules/Leads/metadata/detailviewdefs.php create mode 100644 modules/Leads/metadata/editviewdefs.php create mode 100644 modules/Leads/metadata/listviewdefs.php create mode 100644 modules/Leads/metadata/popupdefs.php create mode 100644 modules/Leads/metadata/quickcreatedefs.php create mode 100644 modules/Leads/metadata/searchdefs.php create mode 100644 modules/Leads/metadata/studio.php create mode 100644 modules/Leads/metadata/subpaneldefs.php create mode 100644 modules/Leads/metadata/subpanels/ForCalls.php create mode 100644 modules/Leads/metadata/subpanels/ForEmails.php create mode 100644 modules/Leads/metadata/subpanels/ForMeetings.php create mode 100644 modules/Leads/metadata/subpanels/default.php create mode 100644 modules/Leads/tpls/ConvertLead.tpl create mode 100644 modules/Leads/tpls/ConvertLeadFooter.tpl create mode 100644 modules/Leads/tpls/ConvertLeadHeader.tpl create mode 100644 modules/Leads/tpls/DetailViewHeader.tpl create mode 100644 modules/Leads/tpls/QuickCreate.tpl create mode 100644 modules/Leads/vardefs.php create mode 100644 modules/Leads/views/view.convertlead.php create mode 100644 modules/Leads/views/view.list.php create mode 100644 modules/MailMerge/DetailView.php create mode 100644 modules/MailMerge/EditView.php create mode 100644 modules/MailMerge/MailMerge.php create mode 100644 modules/MailMerge/Menu.php create mode 100644 modules/MailMerge/Merge.html create mode 100644 modules/MailMerge/Merge.php create mode 100644 modules/MailMerge/Save.php create mode 100644 modules/MailMerge/Step1.html create mode 100644 modules/MailMerge/Step1.php create mode 100644 modules/MailMerge/Step2.html create mode 100644 modules/MailMerge/Step2.php create mode 100644 modules/MailMerge/Step3.html create mode 100644 modules/MailMerge/Step3.php create mode 100644 modules/MailMerge/Step4.html create mode 100644 modules/MailMerge/Step4.php create mode 100644 modules/MailMerge/Step5.html create mode 100644 modules/MailMerge/Step5.php create mode 100644 modules/MailMerge/get_doc.php create mode 100644 modules/MailMerge/index.php create mode 100644 modules/MailMerge/language/en_us.lang.php create mode 100644 modules/MailMerge/modules_array.php create mode 100644 modules/Meetings/Dashlets/MyMeetingsDashlet/MyMeetingsDashlet.data.php create mode 100644 modules/Meetings/Dashlets/MyMeetingsDashlet/MyMeetingsDashlet.meta.php create mode 100644 modules/Meetings/Dashlets/MyMeetingsDashlet/MyMeetingsDashlet.php create mode 100644 modules/Meetings/JoinExternalMeeting.php create mode 100644 modules/Meetings/Meeting.php create mode 100644 modules/Meetings/MeetingFormBase.php create mode 100644 modules/Meetings/MeetingsQuickCreate.php create mode 100644 modules/Meetings/Menu.php create mode 100644 modules/Meetings/Save.php create mode 100644 modules/Meetings/SubPanelViewInvitees.html create mode 100644 modules/Meetings/SubPanelViewInvitees.php create mode 100644 modules/Meetings/action_view_map.php create mode 100644 modules/Meetings/field_arrays.php create mode 100644 modules/Meetings/jsclass_scheduler.js create mode 100644 modules/Meetings/language/en_us.lang.php create mode 100644 modules/Meetings/metadata/SearchFields.php create mode 100644 modules/Meetings/metadata/additionalDetails.php create mode 100644 modules/Meetings/metadata/detailviewdefs.php create mode 100644 modules/Meetings/metadata/editviewdefs.php create mode 100644 modules/Meetings/metadata/listviewdefs.php create mode 100644 modules/Meetings/metadata/quickcreatedefs.php create mode 100644 modules/Meetings/metadata/searchdefs.php create mode 100644 modules/Meetings/metadata/studio.php create mode 100644 modules/Meetings/metadata/subpaneldefs.php create mode 100644 modules/Meetings/metadata/subpanels/ForActivities.php create mode 100644 modules/Meetings/metadata/subpanels/ForHistory.php create mode 100644 modules/Meetings/metadata/subpanels/default.php create mode 100644 modules/Meetings/tpls/QuickCreate.tpl create mode 100644 modules/Meetings/tpls/extMeetingNoStart.tpl create mode 100644 modules/Meetings/tpls/extMeetingNotInvited.tpl create mode 100644 modules/Meetings/tpls/footer.tpl create mode 100644 modules/Meetings/tpls/header.tpl create mode 100644 modules/Meetings/vardefs.php create mode 100644 modules/Meetings/views/view.edit.php create mode 100644 modules/Meetings/views/view.listbytype.php create mode 100644 modules/MergeRecords/Menu.php create mode 100644 modules/MergeRecords/Merge.js create mode 100644 modules/MergeRecords/MergeField.html create mode 100644 modules/MergeRecords/MergeRecord.php create mode 100644 modules/MergeRecords/SaveMerge.php create mode 100644 modules/MergeRecords/SearchForm.html create mode 100644 modules/MergeRecords/Step1.html create mode 100644 modules/MergeRecords/Step1.php create mode 100644 modules/MergeRecords/Step2.html create mode 100644 modules/MergeRecords/Step2.php create mode 100644 modules/MergeRecords/Step3.html create mode 100644 modules/MergeRecords/Step3.php create mode 100644 modules/MergeRecords/controller.php create mode 100644 modules/MergeRecords/index.php create mode 100644 modules/MergeRecords/language/en_us.lang.php create mode 100644 modules/MergeRecords/vardefs.php create mode 100644 modules/ModuleBuilder/Forms.php create mode 100644 modules/ModuleBuilder/MB/AjaxCompose.php create mode 100644 modules/ModuleBuilder/MB/MBField.php create mode 100644 modules/ModuleBuilder/MB/MBLanguage.php create mode 100644 modules/ModuleBuilder/MB/MBModule.php create mode 100644 modules/ModuleBuilder/MB/MBPackage.php create mode 100644 modules/ModuleBuilder/MB/MBPackageTree.php create mode 100644 modules/ModuleBuilder/MB/MBRelationship.php create mode 100644 modules/ModuleBuilder/MB/MBVardefs.php create mode 100644 modules/ModuleBuilder/MB/ModuleBuilder.php create mode 100644 modules/ModuleBuilder/MB/header.php create mode 100644 modules/ModuleBuilder/Module/DropDownBrowser.php create mode 100644 modules/ModuleBuilder/Module/DropDownTree.php create mode 100644 modules/ModuleBuilder/Module/MainTree.php create mode 100644 modules/ModuleBuilder/Module/StudioBrowser.php create mode 100644 modules/ModuleBuilder/Module/StudioModule.php create mode 100644 modules/ModuleBuilder/Module/StudioModuleFactory.php create mode 100644 modules/ModuleBuilder/Module/StudioTree.php create mode 100644 modules/ModuleBuilder/action_view_map.php create mode 100644 modules/ModuleBuilder/controller.php create mode 100644 modules/ModuleBuilder/javascript/JSTransaction.js create mode 100644 modules/ModuleBuilder/javascript/ModuleBuilder.js create mode 100644 modules/ModuleBuilder/javascript/SimpleList.js create mode 100644 modules/ModuleBuilder/javascript/studio2.js create mode 100644 modules/ModuleBuilder/javascript/studio2FieldDD.js create mode 100644 modules/ModuleBuilder/javascript/studio2ListDD.js create mode 100644 modules/ModuleBuilder/javascript/studio2PanelDD.js create mode 100644 modules/ModuleBuilder/javascript/studio2RowDD.js create mode 100644 modules/ModuleBuilder/javascript/studiotabgroups.js create mode 100644 modules/ModuleBuilder/javascript/wizardTemplate.js create mode 100644 modules/ModuleBuilder/language/en_us.lang.php create mode 100644 modules/ModuleBuilder/parsers/ModuleBuilderParser.php create mode 100644 modules/ModuleBuilder/parsers/ParserFactory.php create mode 100644 modules/ModuleBuilder/parsers/StandardField.php create mode 100644 modules/ModuleBuilder/parsers/constants.php create mode 100644 modules/ModuleBuilder/parsers/parser.dropdown.php create mode 100644 modules/ModuleBuilder/parsers/parser.label.php create mode 100644 modules/ModuleBuilder/parsers/parser.modifylayoutview.php create mode 100644 modules/ModuleBuilder/parsers/parser.modifylistview.php create mode 100644 modules/ModuleBuilder/parsers/parser.modifysubpanel.php create mode 100644 modules/ModuleBuilder/parsers/relationships/AbstractRelationship.php create mode 100644 modules/ModuleBuilder/parsers/relationships/AbstractRelationships.php create mode 100644 modules/ModuleBuilder/parsers/relationships/ActivitiesRelationship.php create mode 100644 modules/ModuleBuilder/parsers/relationships/DeployedRelationships.php create mode 100644 modules/ModuleBuilder/parsers/relationships/ManyToManyRelationship.php create mode 100644 modules/ModuleBuilder/parsers/relationships/ManyToOneRelationship.php create mode 100644 modules/ModuleBuilder/parsers/relationships/OneToManyRelationship.php create mode 100644 modules/ModuleBuilder/parsers/relationships/OneToOneRelationship.php create mode 100644 modules/ModuleBuilder/parsers/relationships/RelationshipFactory.php create mode 100644 modules/ModuleBuilder/parsers/relationships/RelationshipsInterface.php create mode 100644 modules/ModuleBuilder/parsers/relationships/UndeployedRelationships.php create mode 100644 modules/ModuleBuilder/parsers/views/AbstractMetaDataImplementation.php create mode 100644 modules/ModuleBuilder/parsers/views/AbstractMetaDataParser.php create mode 100644 modules/ModuleBuilder/parsers/views/DashletMetaDataParser.php create mode 100644 modules/ModuleBuilder/parsers/views/DeployedMetaDataImplementation.php create mode 100644 modules/ModuleBuilder/parsers/views/DeployedSubpanelImplementation.php create mode 100644 modules/ModuleBuilder/parsers/views/GridLayoutMetaDataParser.php create mode 100644 modules/ModuleBuilder/parsers/views/History.php create mode 100644 modules/ModuleBuilder/parsers/views/HistoryInterface.php create mode 100644 modules/ModuleBuilder/parsers/views/ListLayoutMetaDataParser.php create mode 100644 modules/ModuleBuilder/parsers/views/MetaDataImplementationInterface.php create mode 100644 modules/ModuleBuilder/parsers/views/MetaDataParserInterface.php create mode 100644 modules/ModuleBuilder/parsers/views/PopupMetaDataParser.php create mode 100644 modules/ModuleBuilder/parsers/views/SearchViewMetaDataParser.php create mode 100644 modules/ModuleBuilder/parsers/views/SubpanelMetaDataParser.php create mode 100644 modules/ModuleBuilder/parsers/views/UndeployedMetaDataImplementation.php create mode 100644 modules/ModuleBuilder/parsers/views/UndeployedSubpanelImplementation.php create mode 100644 modules/ModuleBuilder/tpls/LayoutEditor.css create mode 100644 modules/ModuleBuilder/tpls/ListEditor.css create mode 100644 modules/ModuleBuilder/tpls/MB.css create mode 100644 modules/ModuleBuilder/tpls/MBModule/Class.tpl create mode 100644 modules/ModuleBuilder/tpls/MBModule/DeveloperClass.tpl create mode 100644 modules/ModuleBuilder/tpls/MBModule/Menu.tpl create mode 100644 modules/ModuleBuilder/tpls/MBModule/Studio.tpl create mode 100644 modules/ModuleBuilder/tpls/MBModule/dropdown.css create mode 100644 modules/ModuleBuilder/tpls/MBModule/dropdown.tpl create mode 100644 modules/ModuleBuilder/tpls/MBModule/dropdowns.tpl create mode 100644 modules/ModuleBuilder/tpls/MBModule/field.tpl create mode 100644 modules/ModuleBuilder/tpls/MBModule/fields.tpl create mode 100644 modules/ModuleBuilder/tpls/MBModule/form.tpl create mode 100644 modules/ModuleBuilder/tpls/MBModule/language.tpl create mode 100644 modules/ModuleBuilder/tpls/MBModule/main.tpl create mode 100644 modules/ModuleBuilder/tpls/MBModule/module.tpl create mode 100644 modules/ModuleBuilder/tpls/MBModule/vardef.tpl create mode 100644 modules/ModuleBuilder/tpls/MBPackage/appLanguage.tpl create mode 100644 modules/ModuleBuilder/tpls/MBPackage/deploy.tpl create mode 100644 modules/ModuleBuilder/tpls/MBPackage/package.tpl create mode 100644 modules/ModuleBuilder/tpls/Preview/layoutView.tpl create mode 100644 modules/ModuleBuilder/tpls/Preview/listView.tpl create mode 100644 modules/ModuleBuilder/tpls/assistantJavascript.tpl create mode 100644 modules/ModuleBuilder/tpls/editProperty.tpl create mode 100644 modules/ModuleBuilder/tpls/exportcustomizations.tpl create mode 100644 modules/ModuleBuilder/tpls/history.tpl create mode 100644 modules/ModuleBuilder/tpls/includes.tpl create mode 100644 modules/ModuleBuilder/tpls/index.tpl create mode 100644 modules/ModuleBuilder/tpls/labels.tpl create mode 100644 modules/ModuleBuilder/tpls/layoutView.tpl create mode 100644 modules/ModuleBuilder/tpls/listView.tpl create mode 100644 modules/ModuleBuilder/tpls/main.tpl create mode 100644 modules/ModuleBuilder/tpls/resetModule.tpl create mode 100644 modules/ModuleBuilder/tpls/studioRelationship.tpl create mode 100644 modules/ModuleBuilder/tpls/studioRelationships.tpl create mode 100644 modules/ModuleBuilder/tpls/tabBG.png create mode 100644 modules/ModuleBuilder/tpls/wizard.tpl create mode 100644 modules/ModuleBuilder/views/view.dashlet.php create mode 100644 modules/ModuleBuilder/views/view.deletemodule.php create mode 100644 modules/ModuleBuilder/views/view.deletepackage.php create mode 100644 modules/ModuleBuilder/views/view.displaydeploy.php create mode 100644 modules/ModuleBuilder/views/view.displaydeployresult.php create mode 100644 modules/ModuleBuilder/views/view.dropdown.php create mode 100644 modules/ModuleBuilder/views/view.dropdowns.php create mode 100644 modules/ModuleBuilder/views/view.exportcustomizations.php create mode 100644 modules/ModuleBuilder/views/view.history.php create mode 100644 modules/ModuleBuilder/views/view.home.php create mode 100644 modules/ModuleBuilder/views/view.labels.php create mode 100644 modules/ModuleBuilder/views/view.layoutview.php create mode 100644 modules/ModuleBuilder/views/view.listview.php create mode 100644 modules/ModuleBuilder/views/view.main.php create mode 100644 modules/ModuleBuilder/views/view.module.php create mode 100644 modules/ModuleBuilder/views/view.modulefield.php create mode 100644 modules/ModuleBuilder/views/view.modulefields.php create mode 100644 modules/ModuleBuilder/views/view.modulelabels.php create mode 100644 modules/ModuleBuilder/views/view.package.php create mode 100644 modules/ModuleBuilder/views/view.popupview.php create mode 100644 modules/ModuleBuilder/views/view.property.php create mode 100644 modules/ModuleBuilder/views/view.relationship.php create mode 100644 modules/ModuleBuilder/views/view.relationships.php create mode 100644 modules/ModuleBuilder/views/view.resetmodule.php create mode 100644 modules/ModuleBuilder/views/view.searchview.php create mode 100644 modules/ModuleBuilder/views/view.tree.php create mode 100644 modules/ModuleBuilder/views/view.wizard.php create mode 100644 modules/MySettings/LoadTabSubpanels.php create mode 100644 modules/MySettings/StoreQuery.php create mode 100644 modules/MySettings/TabController.php create mode 100644 modules/MySettings/language/en_us.lang.php create mode 100644 modules/Notes/Dashlets/MyNotesDashlet/MyNotesDashlet.data.php create mode 100644 modules/Notes/Dashlets/MyNotesDashlet/MyNotesDashlet.meta.php create mode 100644 modules/Notes/Dashlets/MyNotesDashlet/MyNotesDashlet.php create mode 100644 modules/Notes/Menu.php create mode 100644 modules/Notes/Note.php create mode 100644 modules/Notes/NoteSoap.php create mode 100644 modules/Notes/NotesQuickCreate.php create mode 100644 modules/Notes/SubPanelView.html create mode 100644 modules/Notes/SubPanelView.php create mode 100644 modules/Notes/controller.php create mode 100644 modules/Notes/field_arrays.php create mode 100644 modules/Notes/language/en_us.lang.php create mode 100644 modules/Notes/metadata/SearchFields.php create mode 100644 modules/Notes/metadata/additionalDetails.php create mode 100644 modules/Notes/metadata/detailviewdefs.php create mode 100644 modules/Notes/metadata/editviewdefs.php create mode 100644 modules/Notes/metadata/listviewdefs.php create mode 100644 modules/Notes/metadata/quickcreatedefs.php create mode 100644 modules/Notes/metadata/searchdefs.php create mode 100644 modules/Notes/metadata/studio.php create mode 100644 modules/Notes/metadata/subpanels/ForCalls.php create mode 100644 modules/Notes/metadata/subpanels/ForHistory.php create mode 100644 modules/Notes/metadata/subpanels/ForMeetings.php create mode 100644 modules/Notes/metadata/subpanels/default.php create mode 100644 modules/Notes/tpls/EditViewHeader.tpl create mode 100644 modules/Notes/tpls/QuickCreate.tpl create mode 100644 modules/Notes/vardefs.php create mode 100644 modules/Opportunities/Dashlets/MyClosedOpportunitiesDashlet/MyClosedOpportunitiesDashlet.meta.php create mode 100644 modules/Opportunities/Dashlets/MyClosedOpportunitiesDashlet/MyClosedOpportunitiesDashlet.php create mode 100644 modules/Opportunities/Dashlets/MyClosedOpportunitiesDashlet/MyClosedOpportunitiesDashlet.tpl create mode 100644 modules/Opportunities/Dashlets/MyClosedOpportunitiesDashlet/MyClosedOpportunitiesDashletConfigure.tpl create mode 100644 modules/Opportunities/Dashlets/MyClosedOpportunitiesDashlet/MyClosedOpportunitiesDashletOptions.tpl create mode 100644 modules/Opportunities/Dashlets/MyOpportunitiesDashlet/MyOpportunitiesDashlet.data.php create mode 100644 modules/Opportunities/Dashlets/MyOpportunitiesDashlet/MyOpportunitiesDashlet.meta.php create mode 100644 modules/Opportunities/Dashlets/MyOpportunitiesDashlet/MyOpportunitiesDashlet.php create mode 100644 modules/Opportunities/ListViewTop.html create mode 100644 modules/Opportunities/ListViewTop.php create mode 100644 modules/Opportunities/Menu.php create mode 100644 modules/Opportunities/OpportunitiesQuickCreate.php create mode 100644 modules/Opportunities/Opportunity.php create mode 100644 modules/Opportunities/OpportunityFormBase.php create mode 100644 modules/Opportunities/Save.php create mode 100644 modules/Opportunities/SaveOverload.php create mode 100644 modules/Opportunities/SubPanelView.html create mode 100644 modules/Opportunities/SubPanelView.php create mode 100644 modules/Opportunities/SubPanelViewProjects.html create mode 100644 modules/Opportunities/SubPanelViewProjects.php create mode 100644 modules/Opportunities/SugarFeeds/OppFeed.php create mode 100644 modules/Opportunities/field_arrays.php create mode 100644 modules/Opportunities/language/en_us.lang.php create mode 100644 modules/Opportunities/metadata/SearchFields.php create mode 100644 modules/Opportunities/metadata/acldefs.php create mode 100644 modules/Opportunities/metadata/additionalDetails.php create mode 100644 modules/Opportunities/metadata/detailviewdefs.php create mode 100644 modules/Opportunities/metadata/editviewdefs.php create mode 100644 modules/Opportunities/metadata/listviewdefs.php create mode 100644 modules/Opportunities/metadata/metafiles.php create mode 100644 modules/Opportunities/metadata/popupdefs.php create mode 100644 modules/Opportunities/metadata/quickcreatedefs.php create mode 100644 modules/Opportunities/metadata/searchdefs.php create mode 100644 modules/Opportunities/metadata/studio.php create mode 100644 modules/Opportunities/metadata/subpaneldefs.php create mode 100644 modules/Opportunities/metadata/subpanels/ForAccounts.php create mode 100644 modules/Opportunities/metadata/subpanels/ForEmails.php create mode 100644 modules/Opportunities/metadata/subpanels/default.php create mode 100644 modules/Opportunities/tpls/QuickCreate.tpl create mode 100644 modules/Opportunities/vardefs.php create mode 100644 modules/Opportunities/views/view.detail.php create mode 100644 modules/Opportunities/views/view.edit.php create mode 100644 modules/OptimisticLock/Forms.php create mode 100644 modules/OptimisticLock/LockResolve.php create mode 100644 modules/OptimisticLock/Menu.php create mode 100644 modules/OptimisticLock/language/en_us.lang.php create mode 100644 modules/Project/Delete.php create mode 100644 modules/Project/Menu.php create mode 100644 modules/Project/Project.js create mode 100644 modules/Project/Project.php create mode 100644 modules/Project/ProjectQuickCreate.php create mode 100644 modules/Project/Save.php create mode 100644 modules/Project/SubPanelView.html create mode 100644 modules/Project/SubPanelView.php create mode 100644 modules/Project/action_view_map.php create mode 100644 modules/Project/field_arrays.php create mode 100644 modules/Project/language/en_us.lang.php create mode 100644 modules/Project/metadata/SearchFields.php create mode 100644 modules/Project/metadata/additionalDetails.php create mode 100644 modules/Project/metadata/detailviewdefs.php create mode 100644 modules/Project/metadata/editviewdefs.php create mode 100644 modules/Project/metadata/listviewdefs.php create mode 100644 modules/Project/metadata/metafiles.php create mode 100644 modules/Project/metadata/popupdefs.php create mode 100644 modules/Project/metadata/quickcreatedefs.php create mode 100644 modules/Project/metadata/searchdefs.php create mode 100644 modules/Project/metadata/studio.php create mode 100644 modules/Project/metadata/subpaneldefs.php create mode 100644 modules/Project/metadata/subpanels/ForEmails.php create mode 100644 modules/Project/metadata/subpanels/default.php create mode 100644 modules/Project/tpls/QuickCreate.tpl create mode 100644 modules/Project/vardefs.php create mode 100644 modules/Project/views/view.detail.php create mode 100644 modules/Project/views/view.edit.php create mode 100644 modules/Project/views/view.list.php create mode 100644 modules/Project/views/view.templatesdetail.php create mode 100644 modules/Project/views/view.templatesedit.php create mode 100644 modules/ProjectTask/Dashlets/MyProjectTaskDashlet/MyProjectTaskDashlet.data.php create mode 100644 modules/ProjectTask/Dashlets/MyProjectTaskDashlet/MyProjectTaskDashlet.meta.php create mode 100644 modules/ProjectTask/Dashlets/MyProjectTaskDashlet/MyProjectTaskDashlet.php create mode 100644 modules/ProjectTask/Delete.php create mode 100644 modules/ProjectTask/Forms.html create mode 100644 modules/ProjectTask/Menu.php create mode 100644 modules/ProjectTask/MyProjectTasks.html create mode 100644 modules/ProjectTask/MyProjectTasks.php create mode 100644 modules/ProjectTask/Popup.html create mode 100644 modules/ProjectTask/Popup.php create mode 100644 modules/ProjectTask/Popup_picker.html create mode 100644 modules/ProjectTask/ProjectTask.js create mode 100644 modules/ProjectTask/ProjectTask.php create mode 100644 modules/ProjectTask/ProjectTaskQuickCreate.php create mode 100644 modules/ProjectTask/Save.php create mode 100644 modules/ProjectTask/SubPanelView.html create mode 100644 modules/ProjectTask/SubPanelView.php create mode 100644 modules/ProjectTask/field_arrays.php create mode 100644 modules/ProjectTask/language/en_us.lang.php create mode 100644 modules/ProjectTask/metadata/SearchFields.php create mode 100644 modules/ProjectTask/metadata/acldefs.php create mode 100644 modules/ProjectTask/metadata/additionalDetails.php create mode 100644 modules/ProjectTask/metadata/detailviewdefs.php create mode 100644 modules/ProjectTask/metadata/editviewdefs.php create mode 100644 modules/ProjectTask/metadata/listviewdefs.php create mode 100644 modules/ProjectTask/metadata/popupdefs.php create mode 100644 modules/ProjectTask/metadata/searchdefs.php create mode 100644 modules/ProjectTask/metadata/studio.php create mode 100644 modules/ProjectTask/metadata/subpaneldefs.php create mode 100644 modules/ProjectTask/metadata/subpanels/default.php create mode 100644 modules/ProjectTask/tpls/QuickCreate.tpl create mode 100644 modules/ProjectTask/vardefs.php create mode 100644 modules/ProjectTask/views/view.list.php create mode 100644 modules/ProspectLists/Delete.php create mode 100644 modules/ProspectLists/Duplicate.php create mode 100644 modules/ProspectLists/Forms.html create mode 100644 modules/ProspectLists/Forms.php create mode 100644 modules/ProspectLists/Menu.php create mode 100644 modules/ProspectLists/Popup_picker.html create mode 100644 modules/ProspectLists/ProspectList.php create mode 100644 modules/ProspectLists/ProspectListFormBase.php create mode 100644 modules/ProspectLists/Save.php create mode 100644 modules/ProspectLists/SubPanelView.html create mode 100644 modules/ProspectLists/SubPanelView.php create mode 100644 modules/ProspectLists/TargetListUpdate.php create mode 100644 modules/ProspectLists/field_arrays.php create mode 100644 modules/ProspectLists/language/en_us.lang.php create mode 100644 modules/ProspectLists/metadata/SearchFields.php create mode 100644 modules/ProspectLists/metadata/detailviewdefs.php create mode 100644 modules/ProspectLists/metadata/editviewdefs.php create mode 100644 modules/ProspectLists/metadata/listviewdefs.php create mode 100644 modules/ProspectLists/metadata/popupdefs.php create mode 100644 modules/ProspectLists/metadata/searchdefs.php create mode 100644 modules/ProspectLists/metadata/subpaneldefs.php create mode 100644 modules/ProspectLists/metadata/subpanels/default.php create mode 100644 modules/ProspectLists/vardefs.php create mode 100644 modules/Prospects/Delete.php create mode 100644 modules/Prospects/Import.php create mode 100644 modules/Prospects/Menu.php create mode 100644 modules/Prospects/Popup_picker.html create mode 100644 modules/Prospects/Prospect.php create mode 100644 modules/Prospects/ProspectFormBase.php create mode 100644 modules/Prospects/Save.php create mode 100644 modules/Prospects/field_arrays.php create mode 100644 modules/Prospects/language/en_us.lang.php create mode 100644 modules/Prospects/metadata/SearchFields.php create mode 100644 modules/Prospects/metadata/additionalDetails.php create mode 100644 modules/Prospects/metadata/detailviewdefs.php create mode 100644 modules/Prospects/metadata/editviewdefs.php create mode 100644 modules/Prospects/metadata/listviewdefs.php create mode 100644 modules/Prospects/metadata/popupdefs.php create mode 100644 modules/Prospects/metadata/quickcreatedefs.php create mode 100644 modules/Prospects/metadata/searchdefs.php create mode 100644 modules/Prospects/metadata/studio.php create mode 100644 modules/Prospects/metadata/subpaneldefs.php create mode 100644 modules/Prospects/metadata/subpanels/default.php create mode 100644 modules/Prospects/tpls/DetailViewHeader.tpl create mode 100644 modules/Prospects/vardefs.php create mode 100644 modules/Prospects/views/view.detail.php create mode 100644 modules/Prospects/views/view.list.php create mode 100644 modules/Relationships/Relationship.php create mode 100644 modules/Relationships/RelationshipHandler.php create mode 100644 modules/Relationships/field_arrays.php create mode 100644 modules/Relationships/language/en_us.lang.php create mode 100644 modules/Relationships/vardefs.php create mode 100644 modules/Releases/DetailView.php create mode 100644 modules/Releases/EditView.html create mode 100644 modules/Releases/EditView.php create mode 100644 modules/Releases/ListView.html create mode 100644 modules/Releases/Menu.php create mode 100644 modules/Releases/Popup_picker.html create mode 100644 modules/Releases/Popup_picker.php create mode 100644 modules/Releases/Release.php create mode 100644 modules/Releases/Save.php create mode 100644 modules/Releases/field_arrays.php create mode 100644 modules/Releases/index.php create mode 100644 modules/Releases/language/en_us.lang.php create mode 100644 modules/Releases/vardefs.php create mode 100644 modules/Roles/Delete.php create mode 100644 modules/Roles/DeleteUserRelationship.php create mode 100644 modules/Roles/DetailView.html create mode 100644 modules/Roles/DetailView.php create mode 100644 modules/Roles/EditView.html create mode 100644 modules/Roles/EditView.php create mode 100644 modules/Roles/Forms.php create mode 100644 modules/Roles/Menu.php create mode 100644 modules/Roles/Role.php create mode 100644 modules/Roles/Save.php create mode 100644 modules/Roles/SaveUserRelationship.php create mode 100644 modules/Roles/SubPanelViewUsers.html create mode 100644 modules/Roles/SubPanelViewUsers.php create mode 100644 modules/Roles/field_arrays.php create mode 100644 modules/Roles/language/en_us.lang.php create mode 100644 modules/Roles/metadata/SearchFields.php create mode 100644 modules/Roles/metadata/listviewdefs.php create mode 100644 modules/Roles/metadata/searchdefs.php create mode 100644 modules/Roles/metadata/subpaneldefs.php create mode 100644 modules/Roles/metadata/subpanels/default.php create mode 100644 modules/Roles/vardefs.php create mode 100644 modules/Roles/views/view.list.php create mode 100644 modules/SavedSearch/ListView.php create mode 100644 modules/SavedSearch/Menu.php create mode 100644 modules/SavedSearch/SavedSearch.php create mode 100644 modules/SavedSearch/SavedSearchForm.tpl create mode 100644 modules/SavedSearch/SavedSearchSelects.tpl create mode 100644 modules/SavedSearch/SearchForm.html create mode 100644 modules/SavedSearch/UpgradeSavedSearch.php create mode 100644 modules/SavedSearch/field_arrays.php create mode 100644 modules/SavedSearch/index.php create mode 100644 modules/SavedSearch/language/en_us.lang.php create mode 100644 modules/SavedSearch/metadata/listviewdefs.php create mode 100644 modules/SavedSearch/vardefs.php create mode 100644 modules/Schedulers/Delete.php create mode 100644 modules/Schedulers/DeleteScheduled.php create mode 100644 modules/Schedulers/DetailView.html create mode 100644 modules/Schedulers/DetailView.php create mode 100644 modules/Schedulers/EditView.html create mode 100644 modules/Schedulers/EditView.php create mode 100644 modules/Schedulers/JobThread.php create mode 100644 modules/Schedulers/ListView.html create mode 100644 modules/Schedulers/ListView.php create mode 100644 modules/Schedulers/Menu.php create mode 100644 modules/Schedulers/Save.php create mode 100644 modules/Schedulers/Scheduled.html create mode 100644 modules/Schedulers/Scheduled.php create mode 100644 modules/Schedulers/Scheduler.php create mode 100644 modules/Schedulers/SchedulerDaemon.php create mode 100644 modules/Schedulers/_AddJobsHere.php create mode 100644 modules/Schedulers/field_arrays.php create mode 100644 modules/Schedulers/index.php create mode 100644 modules/Schedulers/language/en_us.lang.php create mode 100644 modules/Schedulers/metadata/subpaneldefs.php create mode 100644 modules/Schedulers/metadata/subpanels/default.php create mode 100644 modules/Schedulers/vardefs.php create mode 100644 modules/SchedulersJobs/SchedulersJob.php create mode 100644 modules/SchedulersJobs/field_arrays.php create mode 100644 modules/SchedulersJobs/language/en_us.lang.php create mode 100644 modules/SchedulersJobs/metadata/subpanels/default.php create mode 100644 modules/SchedulersJobs/vardefs.php create mode 100644 modules/Studio/DropDowns/DropDownHelper.php create mode 100644 modules/Studio/DropDowns/EditView.php create mode 100644 modules/Studio/DropDowns/EditView.tpl create mode 100644 modules/Studio/Forms.php create mode 100644 modules/Studio/JSTransaction.js create mode 100644 modules/Studio/SaveTabs.php create mode 100644 modules/Studio/TabGroups.php create mode 100644 modules/Studio/TabGroups/EditViewTabs.php create mode 100644 modules/Studio/TabGroups/EditViewTabs.tpl create mode 100644 modules/Studio/TabGroups/TabGroupHelper.php create mode 100644 modules/Studio/config.php create mode 100644 modules/Studio/language/en_us.Portal.html create mode 100644 modules/Studio/language/en_us.lang.php create mode 100644 modules/Studio/parsers/StudioParser.php create mode 100644 modules/Studio/studio.js create mode 100644 modules/Studio/studiodd.js create mode 100644 modules/Studio/studiotabgroups.js create mode 100644 modules/Studio/wizard.php create mode 100644 modules/Studio/wizards/EditDropDownWizard.php create mode 100644 modules/Studio/wizards/StudioWizard.php create mode 100644 modules/Studio/ygDDListStudio.js create mode 100644 modules/SugarFeed/AdminSettings.php create mode 100644 modules/SugarFeed/Dashlets/SugarFeedDashlet/Options.tpl create mode 100644 modules/SugarFeed/Dashlets/SugarFeedDashlet/SugarFeedDashlet.meta.php create mode 100644 modules/SugarFeed/Dashlets/SugarFeedDashlet/SugarFeedDashlet.php create mode 100644 modules/SugarFeed/Dashlets/SugarFeedDashlet/SugarFeedScript.tpl create mode 100644 modules/SugarFeed/Dashlets/SugarFeedDashlet/UserPostForm.tpl create mode 100644 modules/SugarFeed/Forms.php create mode 100644 modules/SugarFeed/Menu.php create mode 100644 modules/SugarFeed/SugarFeed.php create mode 100644 modules/SugarFeed/SugarFeedFlush.php create mode 100644 modules/SugarFeed/action_view_map.php create mode 100644 modules/SugarFeed/feedLogicBase.php create mode 100644 modules/SugarFeed/language/en_us.lang.php create mode 100644 modules/SugarFeed/linkHandlers/Image.php create mode 100644 modules/SugarFeed/linkHandlers/Link.php create mode 100644 modules/SugarFeed/linkHandlers/YouTube.php create mode 100644 modules/SugarFeed/metadata/SearchFields.php create mode 100644 modules/SugarFeed/metadata/dashletviewdefs.php create mode 100644 modules/SugarFeed/metadata/detailviewdefs.php create mode 100644 modules/SugarFeed/metadata/editviewdefs.php create mode 100644 modules/SugarFeed/metadata/listviewdefs.php create mode 100644 modules/SugarFeed/metadata/metafiles.php create mode 100644 modules/SugarFeed/metadata/popupdefs.php create mode 100644 modules/SugarFeed/metadata/searchdefs.php create mode 100644 modules/SugarFeed/metadata/subpanels/default.php create mode 100644 modules/SugarFeed/tpls/AdminSettings.tpl create mode 100644 modules/SugarFeed/vardefs.php create mode 100644 modules/SugarFeed/views/view.adminsettings.php create mode 100644 modules/TableDictionary.php create mode 100644 modules/Tasks/Dashlets/MyTasksDashlet/MyTasksDashlet.data.php create mode 100644 modules/Tasks/Dashlets/MyTasksDashlet/MyTasksDashlet.meta.php create mode 100644 modules/Tasks/Dashlets/MyTasksDashlet/MyTasksDashlet.php create mode 100644 modules/Tasks/Menu.php create mode 100644 modules/Tasks/MyTasks.html create mode 100644 modules/Tasks/MyTasks.php create mode 100644 modules/Tasks/Save.php create mode 100644 modules/Tasks/Task.php create mode 100644 modules/Tasks/TasksQuickCreate.php create mode 100644 modules/Tasks/field_arrays.php create mode 100644 modules/Tasks/language/en_us.lang.php create mode 100644 modules/Tasks/metadata/SearchFields.php create mode 100644 modules/Tasks/metadata/additionalDetails.php create mode 100644 modules/Tasks/metadata/detailviewdefs.php create mode 100644 modules/Tasks/metadata/editviewdefs.php create mode 100644 modules/Tasks/metadata/listviewdefs.php create mode 100644 modules/Tasks/metadata/quickcreatedefs.php create mode 100644 modules/Tasks/metadata/searchdefs.php create mode 100644 modules/Tasks/metadata/studio.php create mode 100644 modules/Tasks/metadata/subpanels/ForActivities.php create mode 100644 modules/Tasks/metadata/subpanels/ForEmails.php create mode 100644 modules/Tasks/metadata/subpanels/ForHistory.php create mode 100644 modules/Tasks/metadata/subpanels/default.php create mode 100644 modules/Tasks/tpls/QuickCreate.tpl create mode 100644 modules/Tasks/vardefs.php create mode 100644 modules/Tasks/views/view.edit.php create mode 100644 modules/Trackers/BreadCrumbStack.php create mode 100644 modules/Trackers/Metric.php create mode 100644 modules/Trackers/Trackable.php create mode 100644 modules/Trackers/Tracker.php create mode 100644 modules/Trackers/TrackerManager.php create mode 100644 modules/Trackers/config.php create mode 100644 modules/Trackers/language/en_us.lang.php create mode 100644 modules/Trackers/monitor/BlankMonitor.php create mode 100644 modules/Trackers/monitor/Monitor.php create mode 100644 modules/Trackers/monitor/tracker_monitor.php create mode 100644 modules/Trackers/populateSeedData.php create mode 100644 modules/Trackers/store/DatabaseStore.php create mode 100644 modules/Trackers/store/Store.php create mode 100644 modules/Trackers/store/SugarLogStore.php create mode 100644 modules/Trackers/store/TrackerQueriesDatabaseStore.php create mode 100644 modules/Trackers/store/TrackerSessionsDatabaseStore.php create mode 100644 modules/Trackers/vardefs.php create mode 100644 modules/UpgradeWizard/Menu.php create mode 100644 modules/UpgradeWizard/SILENTUPGRADE.txt create mode 100644 modules/UpgradeWizard/SugarMerge/DetailViewMerge.php create mode 100644 modules/UpgradeWizard/SugarMerge/EditViewMerge.php create mode 100644 modules/UpgradeWizard/SugarMerge/ListViewMerge.php create mode 100644 modules/UpgradeWizard/SugarMerge/QuickCreateMerge.php create mode 100644 modules/UpgradeWizard/SugarMerge/SearchMerge.php create mode 100644 modules/UpgradeWizard/SugarMerge/SubpanelMerge.php create mode 100644 modules/UpgradeWizard/SugarMerge/SugarMerge.php create mode 100644 modules/UpgradeWizard/UploadFileCheck.php create mode 100644 modules/UpgradeWizard/cancel.php create mode 100644 modules/UpgradeWizard/commit.php create mode 100644 modules/UpgradeWizard/commitJson.php create mode 100644 modules/UpgradeWizard/deleteCache.php create mode 100644 modules/UpgradeWizard/end.php create mode 100644 modules/UpgradeWizard/index.php create mode 100644 modules/UpgradeWizard/language/en_us.lang.php create mode 100644 modules/UpgradeWizard/layouts.php create mode 100644 modules/UpgradeWizard/populateColumns.php create mode 100644 modules/UpgradeWizard/preflight.php create mode 100644 modules/UpgradeWizard/preflightJson.php create mode 100644 modules/UpgradeWizard/processing.gif create mode 100644 modules/UpgradeWizard/silentUpgrade.php create mode 100644 modules/UpgradeWizard/silentUpgrade_dce_step1.php create mode 100644 modules/UpgradeWizard/silentUpgrade_dce_step2.php create mode 100644 modules/UpgradeWizard/silentUpgrade_step1.php create mode 100644 modules/UpgradeWizard/silentUpgrade_step2.php create mode 100644 modules/UpgradeWizard/start.php create mode 100644 modules/UpgradeWizard/systemCheck.php create mode 100644 modules/UpgradeWizard/systemCheckJson.php create mode 100644 modules/UpgradeWizard/tpls/layoutsMerge.tpl create mode 100644 modules/UpgradeWizard/upgradeMetaHelper.php create mode 100644 modules/UpgradeWizard/upgradeTimeCounter.php create mode 100644 modules/UpgradeWizard/upgradeWizard.js create mode 100644 modules/UpgradeWizard/upload.php create mode 100644 modules/UpgradeWizard/uw_ajax.php create mode 100644 modules/UpgradeWizard/uw_emptyFunctions.php create mode 100644 modules/UpgradeWizard/uw_files.php create mode 100644 modules/UpgradeWizard/uw_main.tpl create mode 100644 modules/UpgradeWizard/uw_utils.php create mode 100644 modules/UserPreferences/UserPreference.php create mode 100644 modules/UserPreferences/controller.php create mode 100644 modules/UserPreferences/field_arrays.php create mode 100644 modules/UserPreferences/index.php create mode 100644 modules/UserPreferences/vardefs.php create mode 100644 modules/Users/Authenticate.php create mode 100644 modules/Users/ChangeGroupTab.php create mode 100644 modules/Users/ChangePassword.php create mode 100644 modules/Users/Changenewpassword.php create mode 100644 modules/Users/Changenewpassword.tpl create mode 100644 modules/Users/DetailView.js create mode 100644 modules/Users/DetailView.php create mode 100644 modules/Users/DetailView.tpl create mode 100644 modules/Users/EditView.php create mode 100644 modules/Users/EditView.tpl create mode 100644 modules/Users/Error.php create mode 100644 modules/Users/Forms.php create mode 100644 modules/Users/GeneratePassword.php create mode 100644 modules/Users/ListRoles.php create mode 100644 modules/Users/Login.php create mode 100644 modules/Users/Logout.php create mode 100644 modules/Users/Menu.php create mode 100644 modules/Users/PasswordRequirementBox.css create mode 100644 modules/Users/PasswordRequirementBox.js create mode 100644 modules/Users/PopupSignature.php create mode 100644 modules/Users/PopupUsers.php create mode 100644 modules/Users/Popup_Users_picker.html create mode 100644 modules/Users/Popup_picker.html create mode 100644 modules/Users/Save.php create mode 100644 modules/Users/SaveSignature.php create mode 100644 modules/Users/SaveTimezone.php create mode 100644 modules/Users/SetTimezone.php create mode 100644 modules/Users/SetTimezone.tpl create mode 100644 modules/Users/User.js create mode 100644 modules/Users/User.php create mode 100644 modules/Users/UserSignature.php create mode 100644 modules/Users/UserSignatureEditView.html create mode 100644 modules/Users/authentication/AuthenticationController.php create mode 100644 modules/Users/authentication/EmailAuthenticate/EmailAuthenticate.php create mode 100644 modules/Users/authentication/EmailAuthenticate/EmailAuthenticateUser.php create mode 100644 modules/Users/authentication/LDAPAuthenticate/LDAPAuthenticate.php create mode 100644 modules/Users/authentication/LDAPAuthenticate/LDAPAuthenticateUser.php create mode 100644 modules/Users/authentication/LDAPAuthenticate/LDAPConfigs/default.php create mode 100644 modules/Users/authentication/SAMLAuthenticate/SAMLAuthenticate.php create mode 100644 modules/Users/authentication/SAMLAuthenticate/SAMLAuthenticateUser.php create mode 100644 modules/Users/authentication/SAMLAuthenticate/index.php create mode 100644 modules/Users/authentication/SAMLAuthenticate/lib/onelogin/saml.php create mode 100644 modules/Users/authentication/SAMLAuthenticate/lib/onelogin/saml/authrequest.php create mode 100644 modules/Users/authentication/SAMLAuthenticate/lib/onelogin/saml/response.php create mode 100644 modules/Users/authentication/SAMLAuthenticate/lib/onelogin/saml/settings.php create mode 100644 modules/Users/authentication/SAMLAuthenticate/lib/onelogin/saml/xmlsec.php create mode 100644 modules/Users/authentication/SAMLAuthenticate/lib/xmlseclibs/CHANGELOG.txt create mode 100644 modules/Users/authentication/SAMLAuthenticate/lib/xmlseclibs/xmlseclibs.php create mode 100644 modules/Users/authentication/SAMLAuthenticate/settings.php create mode 100644 modules/Users/authentication/SugarAuthenticate/SugarAuthenticate.php create mode 100644 modules/Users/authentication/SugarAuthenticate/SugarAuthenticateUser.php create mode 100644 modules/Users/controller.php create mode 100644 modules/Users/field_arrays.php create mode 100644 modules/Users/language/en_us.lang.php create mode 100644 modules/Users/login.css create mode 100644 modules/Users/login.js create mode 100644 modules/Users/login.tpl create mode 100644 modules/Users/metadata/SearchFields.php create mode 100644 modules/Users/metadata/listviewdefs.php create mode 100644 modules/Users/metadata/popupdefs.php create mode 100644 modules/Users/metadata/reassignScriptMetadata.php create mode 100644 modules/Users/metadata/searchdefs.php create mode 100644 modules/Users/metadata/subpaneldefs.php create mode 100644 modules/Users/metadata/subpanels/ForCalls.php create mode 100644 modules/Users/metadata/subpanels/ForEmails.php create mode 100644 modules/Users/metadata/subpanels/ForMeetings.php create mode 100644 modules/Users/metadata/subpanels/ForProject.php create mode 100644 modules/Users/metadata/subpanels/ForProspectLists.php create mode 100644 modules/Users/metadata/subpanels/ForTeams.php create mode 100644 modules/Users/metadata/subpanels/default.php create mode 100644 modules/Users/password_utils.php create mode 100644 modules/Users/reassignUserRecords.php create mode 100644 modules/Users/tpls/wizard.tpl create mode 100644 modules/Users/vardefs.php create mode 100644 modules/Users/views/view.list.php create mode 100644 modules/Users/views/view.wizard.php create mode 100644 modules/Versions/CheckVersions.php create mode 100644 modules/Versions/DefaultVersions.php create mode 100644 modules/Versions/ExpectedVersions.php create mode 100644 modules/Versions/InstallDefaultVersions.php create mode 100644 modules/Versions/Version.php create mode 100644 modules/Versions/field_arrays.php create mode 100644 modules/Versions/index.html create mode 100644 modules/Versions/language/en_us.lang.php create mode 100644 modules/Versions/vardefs.php create mode 100644 modules/vCals/HTTP_WebDAV_Server_vCal.php create mode 100644 modules/vCals/Server.php create mode 100644 modules/vCals/field_arrays.php create mode 100644 modules/vCals/vCal.php create mode 100644 modules/vCals/vardefs.php create mode 100644 pdf.php create mode 100644 removeme.php create mode 100644 robots.txt create mode 100644 service/core/NusoapSoap.php create mode 100644 service/core/PHP5Soap.php create mode 100644 service/core/REST/SugarRest.php create mode 100644 service/core/REST/SugarRestJSON.php create mode 100644 service/core/REST/SugarRestRSS.php create mode 100644 service/core/REST/SugarRestSerialize.php create mode 100644 service/core/SoapHelperWebService.php create mode 100644 service/core/SugarRestService.php create mode 100644 service/core/SugarRestServiceImpl.php create mode 100644 service/core/SugarRestUtils.php create mode 100644 service/core/SugarSoapService.php create mode 100644 service/core/SugarWebService.php create mode 100644 service/core/SugarWebServiceImpl.php create mode 100644 service/core/WSDL.tpl create mode 100644 service/core/webservice.php create mode 100644 service/example/Rest_Proxy.php create mode 100644 service/example/example.html create mode 100644 service/example/test.html create mode 100644 service/utils/SugarRest.js create mode 100644 service/v2/SugarSoapService2.php create mode 100644 service/v2/registry.php create mode 100644 service/v2/rest.php create mode 100644 service/v2/soap.php create mode 100644 service/v2_1/SugarWebServiceImplv2_1.php create mode 100644 service/v2_1/registry.php create mode 100644 service/v2_1/rest.php create mode 100644 service/v2_1/soap.php create mode 100644 service/v3/SugarWebServiceImplv3.php create mode 100644 service/v3/SugarWebServiceUtilv3.php create mode 100644 service/v3/registry.php create mode 100644 service/v3/rest.php create mode 100644 service/v3/soap.php create mode 100644 service/v3_1/SugarWebServiceImplv3_1.php create mode 100644 service/v3_1/SugarWebServiceUtilv3_1.php create mode 100644 service/v3_1/registry.php create mode 100644 service/v3_1/rest.php create mode 100644 service/v3_1/soap.php create mode 100644 service/v4/SugarWebServiceImplv4.php create mode 100644 service/v4/SugarWebServiceUtilv4.php create mode 100644 service/v4/registry.php create mode 100644 service/v4/rest.php create mode 100644 service/v4/soap.php create mode 100644 soap.php create mode 100644 soap/SoapData.php create mode 100644 soap/SoapDeprecated.php create mode 100644 soap/SoapError.php create mode 100644 soap/SoapErrorDefinitions.php create mode 100644 soap/SoapHelperFunctions.php create mode 100644 soap/SoapPortalHelper.php create mode 100644 soap/SoapPortalUsers.php create mode 100644 soap/SoapRelationshipHelper.php create mode 100644 soap/SoapStudio.php create mode 100644 soap/SoapSugarUsers.php create mode 100644 soap/SoapTypes.php create mode 100644 sugar_version.php create mode 100644 themes/Sugar5/css/chart.css create mode 100644 themes/Sugar5/css/deprecated.css create mode 100644 themes/Sugar5/css/print.css create mode 100644 themes/Sugar5/css/style.css create mode 100644 themes/Sugar5/css/wizard.css create mode 100644 themes/Sugar5/css/yui.css create mode 100644 themes/Sugar5/images/ACLRoles.gif create mode 100644 themes/Sugar5/images/AccountReports.gif create mode 100644 themes/Sugar5/images/Accounts.gif create mode 100644 themes/Sugar5/images/ActivitiesReports.gif create mode 100644 themes/Sugar5/images/Administration.gif create mode 100644 themes/Sugar5/images/AlertEmailTemplates.gif create mode 100644 themes/Sugar5/images/AllNews.gif create mode 100644 themes/Sugar5/images/AllRSS.gif create mode 100644 themes/Sugar5/images/ArrowButtons.png create mode 100644 themes/Sugar5/images/Backup.gif create mode 100644 themes/Sugar5/images/Backups.gif create mode 100644 themes/Sugar5/images/BugReports.gif create mode 100644 themes/Sugar5/images/Bugs.gif create mode 100644 themes/Sugar5/images/Calendar.gif create mode 100644 themes/Sugar5/images/CallReports.gif create mode 100644 themes/Sugar5/images/Calls.gif create mode 100644 themes/Sugar5/images/Campaigns.gif create mode 100644 themes/Sugar5/images/CampaignsWizard.gif create mode 100644 themes/Sugar5/images/CaseReports.gif create mode 100644 themes/Sugar5/images/Cases.gif create mode 100644 themes/Sugar5/images/ConfigureSubPanels.gif create mode 100644 themes/Sugar5/images/ConfigureTabs.gif create mode 100644 themes/Sugar5/images/ContactReports.gif create mode 100644 themes/Sugar5/images/Contacts.gif create mode 100644 themes/Sugar5/images/ContractReports.gif create mode 100644 themes/Sugar5/images/Contracts.gif create mode 100644 themes/Sugar5/images/CreateAccounts.gif create mode 100644 themes/Sugar5/images/CreateBugs.gif create mode 100644 themes/Sugar5/images/CreateCalls.gif create mode 100644 themes/Sugar5/images/CreateCampaigns.gif create mode 100644 themes/Sugar5/images/CreateCases.gif create mode 100644 themes/Sugar5/images/CreateContacts.gif create mode 100644 themes/Sugar5/images/CreateContracts.gif create mode 100644 themes/Sugar5/images/CreateCustomQuery.gif create mode 100644 themes/Sugar5/images/CreateDCEClusters.gif create mode 100644 themes/Sugar5/images/CreateDCEDataBases.gif create mode 100644 themes/Sugar5/images/CreateDCEInstances.gif create mode 100644 themes/Sugar5/images/CreateDCETemplates.gif create mode 100644 themes/Sugar5/images/CreateDataSet.gif create mode 100644 themes/Sugar5/images/CreateDocuments.gif create mode 100644 themes/Sugar5/images/CreateDropdown.gif create mode 100644 themes/Sugar5/images/CreateEmails.gif create mode 100644 themes/Sugar5/images/CreateEmployees.gif create mode 100644 themes/Sugar5/images/CreateHolidays.gif create mode 100644 themes/Sugar5/images/CreateKBArticle.gif create mode 100644 themes/Sugar5/images/CreateLeads.gif create mode 100644 themes/Sugar5/images/CreateMailboxes.gif create mode 100644 themes/Sugar5/images/CreateMeetings.gif create mode 100644 themes/Sugar5/images/CreateNotes.gif create mode 100644 themes/Sugar5/images/CreateOpportunities.gif create mode 100644 themes/Sugar5/images/CreateProducts.gif create mode 100644 themes/Sugar5/images/CreateProject.gif create mode 100644 themes/Sugar5/images/CreateProjectTask.gif create mode 100644 themes/Sugar5/images/CreateProjectTemplate.gif create mode 100644 themes/Sugar5/images/CreateProspectLists.gif create mode 100644 themes/Sugar5/images/CreateProspects.gif create mode 100644 themes/Sugar5/images/CreateQuery.gif create mode 100644 themes/Sugar5/images/CreateQuotes.gif create mode 100644 themes/Sugar5/images/CreateReport.gif create mode 100644 themes/Sugar5/images/CreateRoles.gif create mode 100644 themes/Sugar5/images/CreateScheduler.gif create mode 100644 themes/Sugar5/images/CreateTasks.gif create mode 100644 themes/Sugar5/images/CreateTeams.gif create mode 100644 themes/Sugar5/images/CreateTimePeriods.gif create mode 100644 themes/Sugar5/images/CreateUsers.gif create mode 100644 themes/Sugar5/images/CreateWebToLeadForm.gif create mode 100644 themes/Sugar5/images/CreateWorkflowDefinition.gif create mode 100644 themes/Sugar5/images/CreateiFrames.gif create mode 100644 themes/Sugar5/images/Currencies.gif create mode 100644 themes/Sugar5/images/CustomQueries.gif create mode 100644 themes/Sugar5/images/DCEActions.gif create mode 100644 themes/Sugar5/images/DCEClusters.gif create mode 100644 themes/Sugar5/images/DCEDataBases.gif create mode 100644 themes/Sugar5/images/DCEInstances.gif create mode 100644 themes/Sugar5/images/DCELicensingReport.gif create mode 100644 themes/Sugar5/images/DCETemplates.gif create mode 100644 themes/Sugar5/images/Dashboard.gif create mode 100644 themes/Sugar5/images/DataSets.gif create mode 100644 themes/Sugar5/images/Diagnostic.gif create mode 100644 themes/Sugar5/images/DocumentRevisions.gif create mode 100644 themes/Sugar5/images/Documents.gif create mode 100644 themes/Sugar5/images/Dropdown.gif create mode 100644 themes/Sugar5/images/EditLayout.gif create mode 100644 themes/Sugar5/images/EmailDiagnostic.gif create mode 100644 themes/Sugar5/images/EmailFolder.gif create mode 100644 themes/Sugar5/images/EmailMan.gif create mode 100644 themes/Sugar5/images/EmailReports.gif create mode 100644 themes/Sugar5/images/EmailSetupWizard.gif create mode 100644 themes/Sugar5/images/EmailTemplates.gif create mode 100644 themes/Sugar5/images/Emails.gif create mode 100644 themes/Sugar5/images/Employees.gif create mode 100644 themes/Sugar5/images/ExportCustomFields.gif create mode 100644 themes/Sugar5/images/FavoriteReports.gif create mode 100644 themes/Sugar5/images/Feeds.gif create mode 100644 themes/Sugar5/images/FieldLabels.gif create mode 100644 themes/Sugar5/images/ForecastReports.gif create mode 100644 themes/Sugar5/images/ForecastWorksheet.gif create mode 100644 themes/Sugar5/images/Forecasts.gif create mode 100644 themes/Sugar5/images/Holidays.gif create mode 100644 themes/Sugar5/images/Import.gif create mode 100644 themes/Sugar5/images/ImportCustomFields.gif create mode 100644 themes/Sugar5/images/InboundEmail.gif create mode 100644 themes/Sugar5/images/KB.gif create mode 100644 themes/Sugar5/images/KBArticle.gif create mode 100644 themes/Sugar5/images/KBDocuments.gif create mode 100644 themes/Sugar5/images/LanguagePacks.gif create mode 100644 themes/Sugar5/images/Layout.gif create mode 100644 themes/Sugar5/images/LeadReports.gif create mode 100644 themes/Sugar5/images/Leads.gif create mode 100644 themes/Sugar5/images/License.gif create mode 100644 themes/Sugar5/images/MailboxesTestImport.gif create mode 100644 themes/Sugar5/images/Manufacturers.gif create mode 100644 themes/Sugar5/images/MatrixReport.gif create mode 100644 themes/Sugar5/images/MatrixReportOver.gif create mode 100644 themes/Sugar5/images/MeetingReports.gif create mode 100644 themes/Sugar5/images/Meetings.gif create mode 100644 themes/Sugar5/images/MigrateFields.gif create mode 100644 themes/Sugar5/images/ModuleBuilder.gif create mode 100644 themes/Sugar5/images/ModuleLoader.gif create mode 100644 themes/Sugar5/images/MoreDetail.png create mode 100644 themes/Sugar5/images/MyProject.gif create mode 100644 themes/Sugar5/images/MyReports.gif create mode 100644 themes/Sugar5/images/Newsletters.gif create mode 100644 themes/Sugar5/images/Notes.gif create mode 100644 themes/Sugar5/images/OfflineClient.gif create mode 100644 themes/Sugar5/images/OnlineDocumentation.gif create mode 100644 themes/Sugar5/images/Opportunities.gif create mode 100644 themes/Sugar5/images/OpportunityReports.gif create mode 100644 themes/Sugar5/images/Password.gif create mode 100644 themes/Sugar5/images/PatchUpgrades.gif create mode 100644 themes/Sugar5/images/PriceList.gif create mode 100644 themes/Sugar5/images/Price_List.gif create mode 100644 themes/Sugar5/images/Print_Email.gif create mode 100644 themes/Sugar5/images/ProductCategories.gif create mode 100644 themes/Sugar5/images/ProductTemplates.gif create mode 100644 themes/Sugar5/images/ProductTypes.gif create mode 100644 themes/Sugar5/images/Product_Categories.gif create mode 100644 themes/Sugar5/images/Product_Types.gif create mode 100644 themes/Sugar5/images/Products.gif create mode 100644 themes/Sugar5/images/Project.gif create mode 100644 themes/Sugar5/images/Project2Weeks.gif create mode 100644 themes/Sugar5/images/ProjectCollapseAll.gif create mode 100644 themes/Sugar5/images/ProjectCopy.gif create mode 100644 themes/Sugar5/images/ProjectCut.gif create mode 100644 themes/Sugar5/images/ProjectDelete.gif create mode 100644 themes/Sugar5/images/ProjectExpandAll.gif create mode 100644 themes/Sugar5/images/ProjectIndent.gif create mode 100644 themes/Sugar5/images/ProjectInsertRows.gif create mode 100644 themes/Sugar5/images/ProjectMinus.gif create mode 100644 themes/Sugar5/images/ProjectMonth.gif create mode 100644 themes/Sugar5/images/ProjectOutdent.gif create mode 100644 themes/Sugar5/images/ProjectPaste.gif create mode 100644 themes/Sugar5/images/ProjectPlus.gif create mode 100644 themes/Sugar5/images/ProjectSave.gif create mode 100644 themes/Sugar5/images/ProjectTask.gif create mode 100644 themes/Sugar5/images/ProjectTemplate.gif create mode 100644 themes/Sugar5/images/ProjectWeek.gif create mode 100644 themes/Sugar5/images/ProspectLists.gif create mode 100644 themes/Sugar5/images/Prospects.gif create mode 100644 themes/Sugar5/images/QueryBuilder.gif create mode 100644 themes/Sugar5/images/QuoteReports.gif create mode 100644 themes/Sugar5/images/Quotes.gif create mode 100644 themes/Sugar5/images/RSS.gif create mode 100644 themes/Sugar5/images/ReassignRecords.gif create mode 100644 themes/Sugar5/images/Rebuild.gif create mode 100644 themes/Sugar5/images/Rebuild2.gif create mode 100644 themes/Sugar5/images/Releases.gif create mode 100644 themes/Sugar5/images/RenameTabs.gif create mode 100644 themes/Sugar5/images/Repair.gif create mode 100644 themes/Sugar5/images/ReportMaker.gif create mode 100644 themes/Sugar5/images/Reports.gif create mode 100644 themes/Sugar5/images/Roles.gif create mode 100644 themes/Sugar5/images/RowsAndColumns.gif create mode 100644 themes/Sugar5/images/RowsAndColumnsOver.gif create mode 100644 themes/Sugar5/images/SchedulerTest.gif create mode 100644 themes/Sugar5/images/Schedulers.gif create mode 100644 themes/Sugar5/images/Search.gif create mode 100644 themes/Sugar5/images/Shippers.gif create mode 100644 themes/Sugar5/images/StickyThread.gif create mode 100644 themes/Sugar5/images/Studio.gif create mode 100644 themes/Sugar5/images/SugarPortal.gif create mode 100644 themes/Sugar5/images/Summation.gif create mode 100644 themes/Sugar5/images/SummationOver.gif create mode 100644 themes/Sugar5/images/SummationWithDetails.gif create mode 100644 themes/Sugar5/images/SummationWithDetailsOver.gif create mode 100644 themes/Sugar5/images/Support.gif create mode 100644 themes/Sugar5/images/TaskReports.gif create mode 100644 themes/Sugar5/images/Tasks.gif create mode 100644 themes/Sugar5/images/TaxRates.gif create mode 100644 themes/Sugar5/images/Teams.gif create mode 100644 themes/Sugar5/images/Themes.gif create mode 100644 themes/Sugar5/images/TimePeriods.gif create mode 100644 themes/Sugar5/images/Trackers.gif create mode 100644 themes/Sugar5/images/Upgrade.gif create mode 100644 themes/Sugar5/images/UpgradeDCEInstances.gif create mode 100644 themes/Sugar5/images/Users.gif create mode 100644 themes/Sugar5/images/WorkFlow.gif create mode 100644 themes/Sugar5/images/WorkflowSequence.gif create mode 100644 themes/Sugar5/images/_blank.png create mode 100644 themes/Sugar5/images/accept_inline.gif create mode 100644 themes/Sugar5/images/advanced_search.gif create mode 100644 themes/Sugar5/images/arrow.gif create mode 100644 themes/Sugar5/images/arrow_down.gif create mode 100644 themes/Sugar5/images/arrow_up.gif create mode 100644 themes/Sugar5/images/attachment.gif create mode 100644 themes/Sugar5/images/bar_loader.gif create mode 100644 themes/Sugar5/images/basic_search.gif create mode 100644 themes/Sugar5/images/bg.gif create mode 100644 themes/Sugar5/images/bgBlue.gif create mode 100644 themes/Sugar5/images/bgBtn.gif create mode 100644 themes/Sugar5/images/bgBtnBlue.gif create mode 100644 themes/Sugar5/images/bgBtnGray.gif create mode 100644 themes/Sugar5/images/bgBtnGreen.gif create mode 100644 themes/Sugar5/images/bgBtnOrange.gif create mode 100644 themes/Sugar5/images/bgBtnPurple.gif create mode 100644 themes/Sugar5/images/bgGray.gif create mode 100644 themes/Sugar5/images/bgGreen.gif create mode 100644 themes/Sugar5/images/bgOcher.gif create mode 100644 themes/Sugar5/images/bgPurple.gif create mode 100644 themes/Sugar5/images/bgRed.gif create mode 100644 themes/Sugar5/images/blank.gif create mode 100644 themes/Sugar5/images/calendarHeaderBg.gif create mode 100644 themes/Sugar5/images/calendar_next.gif create mode 100644 themes/Sugar5/images/calendar_previous.gif create mode 100644 themes/Sugar5/images/check_inline.gif create mode 100644 themes/Sugar5/images/clear.gif create mode 100644 themes/Sugar5/images/close.gif create mode 100644 themes/Sugar5/images/close_dashboard.gif create mode 100644 themes/Sugar5/images/close_inline.gif create mode 100644 themes/Sugar5/images/colors.blue.icon.gif create mode 100644 themes/Sugar5/images/colors.gray.icon.gif create mode 100644 themes/Sugar5/images/colors.green.icon.gif create mode 100644 themes/Sugar5/images/colors.orange.icon.gif create mode 100644 themes/Sugar5/images/colors.purple.icon.gif create mode 100644 themes/Sugar5/images/colors.red.icon.gif create mode 100644 themes/Sugar5/images/colors.sugar.icon.gif create mode 100644 themes/Sugar5/images/currentTab.gif create mode 100644 themes/Sugar5/images/currentTabBlue.gif create mode 100644 themes/Sugar5/images/currentTabGray.gif create mode 100644 themes/Sugar5/images/currentTabGreen.gif create mode 100644 themes/Sugar5/images/currentTabLinkBg.gif create mode 100644 themes/Sugar5/images/currentTabOcher.gif create mode 100644 themes/Sugar5/images/currentTabOff.gif create mode 100644 themes/Sugar5/images/currentTabPurple.gif create mode 100644 themes/Sugar5/images/currentTabRed.gif create mode 100644 themes/Sugar5/images/dce_Settings.gif create mode 100644 themes/Sugar5/images/decline_inline.gif create mode 100644 themes/Sugar5/images/def_image_inline.gif create mode 100644 themes/Sugar5/images/delete.gif create mode 100644 themes/Sugar5/images/delete_inline.gif create mode 100644 themes/Sugar5/images/detailViewBg.gif create mode 100644 themes/Sugar5/images/detailview.gif create mode 100644 themes/Sugar5/images/doc_image_inline.gif create mode 100644 themes/Sugar5/images/downarrow.gif create mode 100644 themes/Sugar5/images/downarrow_big.gif create mode 100644 themes/Sugar5/images/downarrow_inline.gif create mode 100644 themes/Sugar5/images/edit.gif create mode 100644 themes/Sugar5/images/edit_inline.gif create mode 100644 themes/Sugar5/images/edit_wizard.gif create mode 100644 themes/Sugar5/images/editfields.gif create mode 100644 themes/Sugar5/images/editlabels.gif create mode 100644 themes/Sugar5/images/editview.gif create mode 100644 themes/Sugar5/images/emptyTabSpace.gif create mode 100644 themes/Sugar5/images/end.gif create mode 100644 themes/Sugar5/images/end_off.gif create mode 100644 themes/Sugar5/images/export.gif create mode 100644 themes/Sugar5/images/fonts.larger.icon.gif create mode 100644 themes/Sugar5/images/fonts.largest.icon.gif create mode 100644 themes/Sugar5/images/fonts.normal.icon.gif create mode 100644 themes/Sugar5/images/formButtonBg.gif create mode 100644 themes/Sugar5/images/formButtonBgOn.gif create mode 100644 themes/Sugar5/images/getLatestDocument.gif create mode 100644 themes/Sugar5/images/green_camp.gif create mode 100644 themes/Sugar5/images/h3Arrow.gif create mode 100644 themes/Sugar5/images/help.gif create mode 100644 themes/Sugar5/images/helpInline.gif create mode 100644 themes/Sugar5/images/hide.gif create mode 100644 themes/Sugar5/images/hide_submenu_shortcuts.gif create mode 100644 themes/Sugar5/images/iFrames.gif create mode 100644 themes/Sugar5/images/icon_A1_newmod.gif create mode 100644 themes/Sugar5/images/icon_Accounts.gif create mode 100644 themes/Sugar5/images/icon_Accounts_32.gif create mode 100644 themes/Sugar5/images/icon_Activities.gif create mode 100644 themes/Sugar5/images/icon_Address.gif create mode 100644 themes/Sugar5/images/icon_AdminMobile.gif create mode 100644 themes/Sugar5/images/icon_AdminPDF.gif create mode 100644 themes/Sugar5/images/icon_AdminThemes.gif create mode 100644 themes/Sugar5/images/icon_AdvancedSearch.gif create mode 100644 themes/Sugar5/images/icon_Application.gif create mode 100644 themes/Sugar5/images/icon_BasicSearch.gif create mode 100644 themes/Sugar5/images/icon_Bugs.gif create mode 100644 themes/Sugar5/images/icon_Bugs_32.gif create mode 100644 themes/Sugar5/images/icon_Calls.gif create mode 100644 themes/Sugar5/images/icon_Calls_32.gif create mode 100644 themes/Sugar5/images/icon_CampaignLog_32.gif create mode 100644 themes/Sugar5/images/icon_Campaigns.gif create mode 100644 themes/Sugar5/images/icon_Campaigns_32.gif create mode 100644 themes/Sugar5/images/icon_Cases.gif create mode 100644 themes/Sugar5/images/icon_Cases_32.gif create mode 100644 themes/Sugar5/images/icon_Charts_Funnel.gif create mode 100644 themes/Sugar5/images/icon_Charts_Funnel_32.gif create mode 100644 themes/Sugar5/images/icon_Charts_Gauge.gif create mode 100644 themes/Sugar5/images/icon_Charts_Gauge_32.gif create mode 100644 themes/Sugar5/images/icon_Charts_GroupBy.gif create mode 100644 themes/Sugar5/images/icon_Charts_GroupBy_32.gif create mode 100644 themes/Sugar5/images/icon_Charts_Horizontal.gif create mode 100644 themes/Sugar5/images/icon_Charts_Horizontal_32.gif create mode 100644 themes/Sugar5/images/icon_Charts_Pie.gif create mode 100644 themes/Sugar5/images/icon_Charts_Pie_32.gif create mode 100644 themes/Sugar5/images/icon_Charts_Vertical.gif create mode 100644 themes/Sugar5/images/icon_Charts_Vertical_32.gif create mode 100644 themes/Sugar5/images/icon_Column_1.gif create mode 100644 themes/Sugar5/images/icon_Column_2.gif create mode 100644 themes/Sugar5/images/icon_Column_3.gif create mode 100644 themes/Sugar5/images/icon_ConnectorConfig.gif create mode 100644 themes/Sugar5/images/icon_ConnectorConfigOver.gif create mode 100644 themes/Sugar5/images/icon_ConnectorConfig_16.gif create mode 100644 themes/Sugar5/images/icon_ConnectorEnable.gif create mode 100644 themes/Sugar5/images/icon_ConnectorEnableOver.gif create mode 100644 themes/Sugar5/images/icon_ConnectorEnable_16.gif create mode 100644 themes/Sugar5/images/icon_ConnectorMap.gif create mode 100644 themes/Sugar5/images/icon_ConnectorMapOver.gif create mode 100644 themes/Sugar5/images/icon_ConnectorMap_16.gif create mode 100644 themes/Sugar5/images/icon_ConnectorSearchFields.gif create mode 100644 themes/Sugar5/images/icon_ConnectorSearchFieldsOver.gif create mode 100644 themes/Sugar5/images/icon_ConnectorSearchFields_16.gif create mode 100644 themes/Sugar5/images/icon_Connectors.gif create mode 100644 themes/Sugar5/images/icon_Contacts.gif create mode 100644 themes/Sugar5/images/icon_Contacts_32.gif create mode 100644 themes/Sugar5/images/icon_Contracts.gif create mode 100644 themes/Sugar5/images/icon_Contracts_32.gif create mode 100644 themes/Sugar5/images/icon_DCEActions_32.gif create mode 100644 themes/Sugar5/images/icon_DCEClusters_32.gif create mode 100644 themes/Sugar5/images/icon_DCEDataBases_32.gif create mode 100644 themes/Sugar5/images/icon_DCEInstances_32.gif create mode 100644 themes/Sugar5/images/icon_DCEReports_32.gif create mode 100644 themes/Sugar5/images/icon_DCETemplates_32.gif create mode 100644 themes/Sugar5/images/icon_Dashlet.gif create mode 100644 themes/Sugar5/images/icon_Delete.gif create mode 100644 themes/Sugar5/images/icon_DeleteFull.gif create mode 100644 themes/Sugar5/images/icon_DetailView.gif create mode 100644 themes/Sugar5/images/icon_Documents.gif create mode 100644 themes/Sugar5/images/icon_Documents_32.gif create mode 100644 themes/Sugar5/images/icon_DropDownEditor.gif create mode 100644 themes/Sugar5/images/icon_EditView.gif create mode 100644 themes/Sugar5/images/icon_EmailAddress.gif create mode 100644 themes/Sugar5/images/icon_EmailAddresses_32.gif create mode 100644 themes/Sugar5/images/icon_Emails.gif create mode 100644 themes/Sugar5/images/icon_Emails_32.gif create mode 100644 themes/Sugar5/images/icon_FavoriteReports.gif create mode 100644 themes/Sugar5/images/icon_FavoriteReports_32.gif create mode 100644 themes/Sugar5/images/icon_Feeds_32.gif create mode 100644 themes/Sugar5/images/icon_Fields.gif create mode 100644 themes/Sugar5/images/icon_Forecasts.gif create mode 100644 themes/Sugar5/images/icon_Forecasts_32.gif create mode 100644 themes/Sugar5/images/icon_Invaders_32.gif create mode 100644 themes/Sugar5/images/icon_JotPad.gif create mode 100644 themes/Sugar5/images/icon_JotPad_32.gif create mode 100644 themes/Sugar5/images/icon_KBDocuments.gif create mode 100644 themes/Sugar5/images/icon_KBDocuments_32.gif create mode 100644 themes/Sugar5/images/icon_Labels.gif create mode 100644 themes/Sugar5/images/icon_Layouts.gif create mode 100644 themes/Sugar5/images/icon_Leads.gif create mode 100644 themes/Sugar5/images/icon_Leads_32.gif create mode 100644 themes/Sugar5/images/icon_ListView.gif create mode 100644 themes/Sugar5/images/icon_Meetings.gif create mode 100644 themes/Sugar5/images/icon_Meetings_32.gif create mode 100644 themes/Sugar5/images/icon_MobileLayouts.gif create mode 100644 themes/Sugar5/images/icon_ModuleBuilder.gif create mode 100644 themes/Sugar5/images/icon_MyPortal_32.gif create mode 100644 themes/Sugar5/images/icon_MyTasks_32.gif create mode 100644 themes/Sugar5/images/icon_NewModule.gif create mode 100644 themes/Sugar5/images/icon_Notes.gif create mode 100644 themes/Sugar5/images/icon_Notes_32.gif create mode 100644 themes/Sugar5/images/icon_OpenTasks_32.gif create mode 100644 themes/Sugar5/images/icon_Opportunities.gif create mode 100644 themes/Sugar5/images/icon_Opportunities_32.gif create mode 100644 themes/Sugar5/images/icon_Phone.gif create mode 100644 themes/Sugar5/images/icon_Portal.gif create mode 100644 themes/Sugar5/images/icon_ProductCategories_32.gif create mode 100644 themes/Sugar5/images/icon_ProductTemplates.gif create mode 100644 themes/Sugar5/images/icon_ProductTypes_32.gif create mode 100644 themes/Sugar5/images/icon_Product_Types_32.gif create mode 100644 themes/Sugar5/images/icon_Products.gif create mode 100644 themes/Sugar5/images/icon_Products_32.gif create mode 100644 themes/Sugar5/images/icon_Project.gif create mode 100644 themes/Sugar5/images/icon_ProjectTask.gif create mode 100644 themes/Sugar5/images/icon_ProjectTask_32.gif create mode 100644 themes/Sugar5/images/icon_Project_32.gif create mode 100644 themes/Sugar5/images/icon_Projects_32.gif create mode 100644 themes/Sugar5/images/icon_Prospects.gif create mode 100644 themes/Sugar5/images/icon_Prospects_32.gif create mode 100644 themes/Sugar5/images/icon_QuickCreate.gif create mode 100644 themes/Sugar5/images/icon_Quotes.gif create mode 100644 themes/Sugar5/images/icon_Quotes_32.gif create mode 100644 themes/Sugar5/images/icon_Relationships.gif create mode 100644 themes/Sugar5/images/icon_Releases_32.gif create mode 100644 themes/Sugar5/images/icon_Reports_32.gif create mode 100644 themes/Sugar5/images/icon_Rss_32.gif create mode 100644 themes/Sugar5/images/icon_SPSync.gif create mode 100644 themes/Sugar5/images/icon_SPUploadCSS.gif create mode 100644 themes/Sugar5/images/icon_SearchForm.gif create mode 100644 themes/Sugar5/images/icon_Studio.gif create mode 100644 themes/Sugar5/images/icon_Subpanels.gif create mode 100644 themes/Sugar5/images/icon_SugarFeed.gif create mode 100644 themes/Sugar5/images/icon_SugarFeed_32.gif create mode 100644 themes/Sugar5/images/icon_SugarNews_32.gif create mode 100644 themes/Sugar5/images/icon_SugarPortal.gif create mode 100644 themes/Sugar5/images/icon_Targets_32.gif create mode 100644 themes/Sugar5/images/icon_Tasks.gif create mode 100644 themes/Sugar5/images/icon_Tasks_32.gif create mode 100644 themes/Sugar5/images/icon_Teams_32.gif create mode 100644 themes/Sugar5/images/icon_TrackerPerfs_32.gif create mode 100644 themes/Sugar5/images/icon_TrackerQueries_32.gif create mode 100644 themes/Sugar5/images/icon_TrackerSessions_32.gif create mode 100644 themes/Sugar5/images/icon_Trackers_32.gif create mode 100644 themes/Sugar5/images/icon_Users_32.gif create mode 100644 themes/Sugar5/images/icon_assistant.gif create mode 100644 themes/Sugar5/images/icon_back.gif create mode 100644 themes/Sugar5/images/icon_basic.gif create mode 100644 themes/Sugar5/images/icon_company.gif create mode 100644 themes/Sugar5/images/icon_document.gif create mode 100644 themes/Sugar5/images/icon_email_addressbook.gif create mode 100644 themes/Sugar5/images/icon_email_archive.gif create mode 100644 themes/Sugar5/images/icon_email_assign.gif create mode 100644 themes/Sugar5/images/icon_email_attach.gif create mode 100644 themes/Sugar5/images/icon_email_check.gif create mode 100644 themes/Sugar5/images/icon_email_compose.gif create mode 100644 themes/Sugar5/images/icon_email_create.gif create mode 100644 themes/Sugar5/images/icon_email_delete.gif create mode 100644 themes/Sugar5/images/icon_email_folder.gif create mode 100644 themes/Sugar5/images/icon_email_folder_archives.gif create mode 100644 themes/Sugar5/images/icon_email_folder_drafts.gif create mode 100644 themes/Sugar5/images/icon_email_folder_exp.gif create mode 100644 themes/Sugar5/images/icon_email_folder_grp.gif create mode 100644 themes/Sugar5/images/icon_email_folder_sent.gif create mode 100644 themes/Sugar5/images/icon_email_forward.gif create mode 100644 themes/Sugar5/images/icon_email_fullscreen.gif create mode 100644 themes/Sugar5/images/icon_email_mark.gif create mode 100644 themes/Sugar5/images/icon_email_options.gif create mode 100644 themes/Sugar5/images/icon_email_relate.gif create mode 100644 themes/Sugar5/images/icon_email_reply.gif create mode 100644 themes/Sugar5/images/icon_email_replyall.gif create mode 100644 themes/Sugar5/images/icon_email_save.gif create mode 100644 themes/Sugar5/images/icon_email_send.gif create mode 100644 themes/Sugar5/images/icon_email_settings.gif create mode 100644 themes/Sugar5/images/icon_email_sugfolder.gif create mode 100644 themes/Sugar5/images/icon_email_sugfolder_exp.gif create mode 100644 themes/Sugar5/images/icon_email_view.gif create mode 100644 themes/Sugar5/images/icon_email_view1.gif create mode 100644 themes/Sugar5/images/icon_email_view2.gif create mode 100644 themes/Sugar5/images/icon_email_view3.gif create mode 100644 themes/Sugar5/images/icon_expression_types.gif create mode 100644 themes/Sugar5/images/icon_file.gif create mode 100644 themes/Sugar5/images/icon_home.gif create mode 100644 themes/Sugar5/images/icon_iFrames_32.gif create mode 100644 themes/Sugar5/images/icon_issue.gif create mode 100644 themes/Sugar5/images/icon_new_package.gif create mode 100644 themes/Sugar5/images/icon_opportunity.gif create mode 100644 themes/Sugar5/images/icon_package.gif create mode 100644 themes/Sugar5/images/icon_package_create.gif create mode 100644 themes/Sugar5/images/icon_person.gif create mode 100644 themes/Sugar5/images/icon_sale.gif create mode 100644 themes/Sugar5/images/icon_therevisions.gif create mode 100644 themes/Sugar5/images/img_close_search.gif create mode 100644 themes/Sugar5/images/img_left_arrow.jpg create mode 100644 themes/Sugar5/images/img_loading.gif create mode 100644 themes/Sugar5/images/img_right_arrow.jpg create mode 100644 themes/Sugar5/images/info-add-page.png create mode 100644 themes/Sugar5/images/info-del.png create mode 100644 themes/Sugar5/images/info_inline.gif create mode 100644 themes/Sugar5/images/jscalendar.gif create mode 100644 themes/Sugar5/images/leftarrow.gif create mode 100644 themes/Sugar5/images/leftarrow_big.gif create mode 100644 themes/Sugar5/images/line.gif create mode 100644 themes/Sugar5/images/list.gif create mode 100644 themes/Sugar5/images/listViewBg.gif create mode 100644 themes/Sugar5/images/listViewHR.gif create mode 100644 themes/Sugar5/images/loadSignedDocument.gif create mode 100644 themes/Sugar5/images/loading.gif create mode 100644 themes/Sugar5/images/mass_update.gif create mode 100644 themes/Sugar5/images/menuarrow.gif create mode 100644 themes/Sugar5/images/minus.gif create mode 100644 themes/Sugar5/images/minus_inline.gif create mode 100644 themes/Sugar5/images/more.gif create mode 100644 themes/Sugar5/images/new_inline.gif create mode 100644 themes/Sugar5/images/next.gif create mode 100644 themes/Sugar5/images/next_off.gif create mode 100644 themes/Sugar5/images/no.gif create mode 100644 themes/Sugar5/images/open_multiple.gif create mode 100644 themes/Sugar5/images/otherTab.gif create mode 100644 themes/Sugar5/images/otherTabBlue.gif create mode 100644 themes/Sugar5/images/otherTabGray.gif create mode 100644 themes/Sugar5/images/otherTabGreen.gif create mode 100644 themes/Sugar5/images/otherTabOcher.gif create mode 100644 themes/Sugar5/images/otherTabPurple.gif create mode 100644 themes/Sugar5/images/otherTabRed.gif create mode 100644 themes/Sugar5/images/pdf_header_logo_SugarCRMheader.jpg create mode 100644 themes/Sugar5/images/pdf_header_logo_img_left_arrow.jpg create mode 100644 themes/Sugar5/images/pdf_header_logo_pdf_header_logo_SugarCRMheader.jpg create mode 100644 themes/Sugar5/images/pdf_image_inline.gif create mode 100644 themes/Sugar5/images/pdf_logo.jpg create mode 100644 themes/Sugar5/images/pdf_logo_small.jpg create mode 100644 themes/Sugar5/images/plus.gif create mode 100644 themes/Sugar5/images/plus_inline.gif create mode 100644 themes/Sugar5/images/ppt_image_inline.gif create mode 100644 themes/Sugar5/images/previous.gif create mode 100644 themes/Sugar5/images/previous_off.gif create mode 100644 themes/Sugar5/images/print.gif create mode 100644 themes/Sugar5/images/publish_inline.gif create mode 100644 themes/Sugar5/images/red_camp.gif create mode 100644 themes/Sugar5/images/refresh.gif create mode 100644 themes/Sugar5/images/rightarrow.gif create mode 100644 themes/Sugar5/images/rightarrow_big.gif create mode 100644 themes/Sugar5/images/scheduled_inline.gif create mode 100644 themes/Sugar5/images/searchMore.gif create mode 100644 themes/Sugar5/images/select.gif create mode 100644 themes/Sugar5/images/show.gif create mode 100644 themes/Sugar5/images/show_submenu_shortcuts.gif create mode 100644 themes/Sugar5/images/slot.gif create mode 100644 themes/Sugar5/images/spacer.gif create mode 100644 themes/Sugar5/images/sqsWait.gif create mode 100644 themes/Sugar5/images/start.gif create mode 100644 themes/Sugar5/images/start_off.gif create mode 100644 themes/Sugar5/images/studio_addField.gif create mode 100644 themes/Sugar5/images/studio_addRows.gif create mode 100644 themes/Sugar5/images/studio_blank.gif create mode 100644 themes/Sugar5/images/studio_history.gif create mode 100644 themes/Sugar5/images/studio_publish.gif create mode 100644 themes/Sugar5/images/studio_redo.gif create mode 100644 themes/Sugar5/images/studio_save.gif create mode 100644 themes/Sugar5/images/studio_undo.gif create mode 100644 themes/Sugar5/images/sugar-yui-sprites-green.png create mode 100644 themes/Sugar5/images/sugar-yui-sprites-grey.png create mode 100644 themes/Sugar5/images/sugar-yui-sprites-purple.png create mode 100644 themes/Sugar5/images/sugar-yui-sprites-red.png create mode 100644 themes/Sugar5/images/sugar-yui-sprites.png create mode 100644 themes/Sugar5/images/sugarColors.xml create mode 100644 themes/Sugar5/images/sugar_document.png create mode 100644 themes/Sugar5/images/sugar_icon.ico create mode 100644 themes/Sugar5/images/sugar_icon.png create mode 100644 themes/Sugar5/images/sugarupdate.gif create mode 100644 themes/Sugar5/images/tabRowBg.gif create mode 100644 themes/Sugar5/images/tabRowBlueBg.gif create mode 100644 themes/Sugar5/images/tabRowGrayBg.gif create mode 100644 themes/Sugar5/images/tabRowGreenBg.gif create mode 100644 themes/Sugar5/images/tabRowOcherBg.gif create mode 100644 themes/Sugar5/images/tabRowPurpleBg.gif create mode 100644 themes/Sugar5/images/tabRowRedBg.gif create mode 100644 themes/Sugar5/images/tentative_inline.gif create mode 100644 themes/Sugar5/images/themePreview.png create mode 100644 themes/Sugar5/images/txt_image_inline.gif create mode 100644 themes/Sugar5/images/unpublish_inline.gif create mode 100644 themes/Sugar5/images/unscheduled_inline.gif create mode 100644 themes/Sugar5/images/uparrow.gif create mode 100644 themes/Sugar5/images/uparrow_big.gif create mode 100644 themes/Sugar5/images/uparrow_inline.gif create mode 100644 themes/Sugar5/images/view.gif create mode 100644 themes/Sugar5/images/view_inline.gif create mode 100644 themes/Sugar5/images/view_status.gif create mode 100644 themes/Sugar5/images/xls_image_inline.gif create mode 100644 themes/Sugar5/images/yellow_camp.gif create mode 100644 themes/Sugar5/images/yes.gif create mode 100644 themes/Sugar5/js/style.js create mode 100644 themes/Sugar5/layout_utils.php create mode 100644 themes/Sugar5/themedef.php create mode 100644 themes/Sugar5/tpls/_companyLogo.tpl create mode 100644 themes/Sugar5/tpls/_globalLinks.tpl create mode 100644 themes/Sugar5/tpls/_head.tpl create mode 100644 themes/Sugar5/tpls/_headerLastViewed.tpl create mode 100644 themes/Sugar5/tpls/_headerModuleList.tpl create mode 100644 themes/Sugar5/tpls/_headerSearch.tpl create mode 100644 themes/Sugar5/tpls/_headerShortcuts.tpl create mode 100644 themes/Sugar5/tpls/_welcome.tpl create mode 100644 themes/Sugar5/tpls/footer.tpl create mode 100644 themes/Sugar5/tpls/header.tpl create mode 100644 themes/default/css/chart.css create mode 100644 themes/default/css/deprecated.css create mode 100644 themes/default/css/print.css create mode 100644 themes/default/css/style.css create mode 100644 themes/default/css/wizard.css create mode 100644 themes/default/images/Accounts.gif create mode 100644 themes/default/images/ActivitiesReports.gif create mode 100644 themes/default/images/Administration.gif create mode 100644 themes/default/images/AlertEmailTemplates.gif create mode 100644 themes/default/images/AllNews.gif create mode 100644 themes/default/images/AllRSS.gif create mode 100644 themes/default/images/ArrowButtons.png create mode 100644 themes/default/images/Backup.gif create mode 100644 themes/default/images/Backups.gif create mode 100644 themes/default/images/BugReports.gif create mode 100644 themes/default/images/Bugs.gif create mode 100644 themes/default/images/Calendar.gif create mode 100644 themes/default/images/Calls.gif create mode 100644 themes/default/images/Campaigns.gif create mode 100644 themes/default/images/CampaignsWizard.gif create mode 100644 themes/default/images/Cases.gif create mode 100644 themes/default/images/ConfigureSubPanels.gif create mode 100644 themes/default/images/ConfigureTabs.gif create mode 100644 themes/default/images/Contacts.gif create mode 100644 themes/default/images/CreateAccounts.gif create mode 100644 themes/default/images/CreateBugs.gif create mode 100644 themes/default/images/CreateCalls.gif create mode 100644 themes/default/images/CreateCampaigns.gif create mode 100644 themes/default/images/CreateCases.gif create mode 100644 themes/default/images/CreateContacts.gif create mode 100644 themes/default/images/CreateDCEClusters.gif create mode 100644 themes/default/images/CreateDCEDataBases.gif create mode 100644 themes/default/images/CreateDCEInstances.gif create mode 100644 themes/default/images/CreateDCETemplates.gif create mode 100644 themes/default/images/CreateDocuments.gif create mode 100644 themes/default/images/CreateDropdown.gif create mode 100644 themes/default/images/CreateEmails.gif create mode 100644 themes/default/images/CreateEmployees.gif create mode 100644 themes/default/images/CreateHolidays.gif create mode 100644 themes/default/images/CreateKBArticle.gif create mode 100644 themes/default/images/CreateLeads.gif create mode 100644 themes/default/images/CreateMailboxes.gif create mode 100644 themes/default/images/CreateMeetings.gif create mode 100644 themes/default/images/CreateNotes.gif create mode 100644 themes/default/images/CreateOpportunities.gif create mode 100644 themes/default/images/CreateProject.gif create mode 100644 themes/default/images/CreateProjectTask.gif create mode 100644 themes/default/images/CreateProjectTemplate.gif create mode 100644 themes/default/images/CreateProspectLists.gif create mode 100644 themes/default/images/CreateProspects.gif create mode 100644 themes/default/images/CreateQuery.gif create mode 100644 themes/default/images/CreateQuotes.gif create mode 100644 themes/default/images/CreateRoles.gif create mode 100644 themes/default/images/CreateScheduler.gif create mode 100644 themes/default/images/CreateTasks.gif create mode 100644 themes/default/images/CreateTeams.gif create mode 100644 themes/default/images/CreateUsers.gif create mode 100644 themes/default/images/CreateWebToLeadForm.gif create mode 100644 themes/default/images/CreateiFrames.gif create mode 100644 themes/default/images/Currencies.gif create mode 100644 themes/default/images/CustomQueries.gif create mode 100644 themes/default/images/DCEActions.gif create mode 100644 themes/default/images/DCELicensingReport.gif create mode 100644 themes/default/images/Dashboard.gif create mode 100644 themes/default/images/DataSets.gif create mode 100644 themes/default/images/Diagnostic.gif create mode 100644 themes/default/images/DocumentRevisions.gif create mode 100644 themes/default/images/Documents.gif create mode 100644 themes/default/images/Dropdown.gif create mode 100644 themes/default/images/EditLayout.gif create mode 100644 themes/default/images/EmailDiagnostic.gif create mode 100644 themes/default/images/EmailFolder.gif create mode 100644 themes/default/images/EmailMan.gif create mode 100644 themes/default/images/EmailSetupWizard.gif create mode 100644 themes/default/images/EmailTemplates.gif create mode 100644 themes/default/images/Emails.gif create mode 100644 themes/default/images/Employees.gif create mode 100644 themes/default/images/ExportCustomFields.gif create mode 100644 themes/default/images/FavoriteReports.gif create mode 100644 themes/default/images/Feeds.gif create mode 100644 themes/default/images/FieldLabels.gif create mode 100644 themes/default/images/Holidays.gif create mode 100644 themes/default/images/Import.gif create mode 100644 themes/default/images/ImportCustomFields.gif create mode 100644 themes/default/images/InboundEmail.gif create mode 100644 themes/default/images/KB.gif create mode 100644 themes/default/images/KBArticle.gif create mode 100644 themes/default/images/KBDocuments.gif create mode 100644 themes/default/images/LanguagePacks.gif create mode 100644 themes/default/images/Layout.gif create mode 100644 themes/default/images/Leads.gif create mode 100644 themes/default/images/License.gif create mode 100644 themes/default/images/MailboxesTestImport.gif create mode 100644 themes/default/images/Manufacturers.gif create mode 100644 themes/default/images/MatrixReport.gif create mode 100644 themes/default/images/MatrixReportOver.gif create mode 100644 themes/default/images/Meetings.gif create mode 100644 themes/default/images/MigrateFields.gif create mode 100644 themes/default/images/ModuleBuilder.gif create mode 100644 themes/default/images/ModuleLoader.gif create mode 100644 themes/default/images/MoreDetail.png create mode 100644 themes/default/images/MyProject.gif create mode 100644 themes/default/images/Newsletters.gif create mode 100644 themes/default/images/Notes.gif create mode 100644 themes/default/images/OnlineDocumentation.gif create mode 100644 themes/default/images/Opportunities.gif create mode 100644 themes/default/images/OpportunityReports.gif create mode 100644 themes/default/images/Password.gif create mode 100644 themes/default/images/PatchUpgrades.gif create mode 100644 themes/default/images/Print_Email.gif create mode 100644 themes/default/images/ProductTemplates.gif create mode 100644 themes/default/images/Product_Types.gif create mode 100644 themes/default/images/Project.gif create mode 100644 themes/default/images/Project2Weeks.gif create mode 100644 themes/default/images/ProjectCollapseAll.gif create mode 100644 themes/default/images/ProjectCopy.gif create mode 100644 themes/default/images/ProjectCut.gif create mode 100644 themes/default/images/ProjectDelete.gif create mode 100644 themes/default/images/ProjectExpandAll.gif create mode 100644 themes/default/images/ProjectIndent.gif create mode 100644 themes/default/images/ProjectInsertRows.gif create mode 100644 themes/default/images/ProjectMinus.gif create mode 100644 themes/default/images/ProjectMonth.gif create mode 100644 themes/default/images/ProjectOutdent.gif create mode 100644 themes/default/images/ProjectPaste.gif create mode 100644 themes/default/images/ProjectPlus.gif create mode 100644 themes/default/images/ProjectSave.gif create mode 100644 themes/default/images/ProjectTask.gif create mode 100644 themes/default/images/ProjectTemplate.gif create mode 100644 themes/default/images/ProjectWeek.gif create mode 100644 themes/default/images/ProspectLists.gif create mode 100644 themes/default/images/Prospects.gif create mode 100644 themes/default/images/QueryBuilder.gif create mode 100644 themes/default/images/RSS.gif create mode 100644 themes/default/images/ReassignRecords.gif create mode 100644 themes/default/images/Rebuild.gif create mode 100644 themes/default/images/Rebuild2.gif create mode 100644 themes/default/images/Releases.gif create mode 100644 themes/default/images/RenameTabs.gif create mode 100644 themes/default/images/Repair.gif create mode 100644 themes/default/images/Roles.gif create mode 100644 themes/default/images/RowsAndColumns.gif create mode 100644 themes/default/images/RowsAndColumnsOver.gif create mode 100644 themes/default/images/SchedulerTest.gif create mode 100644 themes/default/images/Schedulers.gif create mode 100644 themes/default/images/Search.gif create mode 100644 themes/default/images/Shippers.gif create mode 100644 themes/default/images/StickyThread.gif create mode 100644 themes/default/images/Studio.gif create mode 100644 themes/default/images/SugarLogic/icon_bool_16.png create mode 100644 themes/default/images/SugarLogic/icon_date_16.png create mode 100644 themes/default/images/SugarLogic/icon_enum_16.png create mode 100644 themes/default/images/SugarLogic/icon_generic_16.png create mode 100644 themes/default/images/SugarLogic/icon_num_16.png create mode 100644 themes/default/images/SugarLogic/icon_string_16.png create mode 100644 themes/default/images/SugarPortal.gif create mode 100644 themes/default/images/Summation.gif create mode 100644 themes/default/images/SummationOver.gif create mode 100644 themes/default/images/SummationWithDetails.gif create mode 100644 themes/default/images/SummationWithDetailsOver.gif create mode 100644 themes/default/images/Support.gif create mode 100644 themes/default/images/Tasks.gif create mode 100644 themes/default/images/Teams.gif create mode 100644 themes/default/images/Themes.gif create mode 100644 themes/default/images/Trackers.gif create mode 100644 themes/default/images/Upgrade.gif create mode 100644 themes/default/images/UpgradeDCEInstances.gif create mode 100644 themes/default/images/Users.gif create mode 100644 themes/default/images/WorkFlow.gif create mode 100644 themes/default/images/_blank.png create mode 100644 themes/default/images/accept_inline.gif create mode 100644 themes/default/images/advanced_search.gif create mode 100644 themes/default/images/arrow.gif create mode 100644 themes/default/images/arrow_down.gif create mode 100644 themes/default/images/arrow_up.gif create mode 100644 themes/default/images/attachment.gif create mode 100644 themes/default/images/backtotop.gif create mode 100644 themes/default/images/bar_loader.gif create mode 100644 themes/default/images/basic_search.gif create mode 100644 themes/default/images/bg.gif create mode 100644 themes/default/images/bgBlue.gif create mode 100644 themes/default/images/bgBtn.gif create mode 100644 themes/default/images/bgBtnBlue.gif create mode 100644 themes/default/images/bgBtnGray.gif create mode 100644 themes/default/images/bgBtnGreen.gif create mode 100644 themes/default/images/bgBtnOrange.gif create mode 100644 themes/default/images/bgBtnPurple.gif create mode 100644 themes/default/images/bgGray.gif create mode 100644 themes/default/images/bgGreen.gif create mode 100644 themes/default/images/bgOcher.gif create mode 100644 themes/default/images/bgPurple.gif create mode 100644 themes/default/images/bgRed.gif create mode 100644 themes/default/images/blank.gif create mode 100644 themes/default/images/calendarHeaderBg.gif create mode 100644 themes/default/images/calendar_next.gif create mode 100644 themes/default/images/calendar_previous.gif create mode 100644 themes/default/images/chartBg.png create mode 100644 themes/default/images/check_inline.gif create mode 100644 themes/default/images/close.gif create mode 100644 themes/default/images/close_button_24.png create mode 100644 themes/default/images/close_inline.gif create mode 100644 themes/default/images/colors.blue.icon.gif create mode 100644 themes/default/images/colors.gray.icon.gif create mode 100644 themes/default/images/colors.green.icon.gif create mode 100644 themes/default/images/colors.orange.icon.gif create mode 100644 themes/default/images/colors.purple.icon.gif create mode 100644 themes/default/images/colors.red.icon.gif create mode 100644 themes/default/images/colors.sugar.icon.gif create mode 100644 themes/default/images/company_logo.png create mode 100644 themes/default/images/create-record.gif create mode 100644 themes/default/images/currentTab.gif create mode 100644 themes/default/images/currentTab.png create mode 100644 themes/default/images/currentTabBlue.gif create mode 100644 themes/default/images/currentTabGray.gif create mode 100644 themes/default/images/currentTabGreen.gif create mode 100644 themes/default/images/currentTabLinkBg.gif create mode 100644 themes/default/images/currentTabOcher.gif create mode 100644 themes/default/images/currentTabOff.gif create mode 100644 themes/default/images/currentTabPurple.gif create mode 100644 themes/default/images/currentTabRed.gif create mode 100644 themes/default/images/dashlet-header-close.gif create mode 100644 themes/default/images/dashlet-header-edit.gif create mode 100644 themes/default/images/dashlet-header-refresh.gif create mode 100644 themes/default/images/dcMenuDivider.png create mode 100644 themes/default/images/dce_Settings.gif create mode 100644 themes/default/images/dcmenugrade.png create mode 100644 themes/default/images/decline_inline.gif create mode 100644 themes/default/images/def_image_inline.gif create mode 100644 themes/default/images/delete.gif create mode 100644 themes/default/images/delete_inline.gif create mode 100644 themes/default/images/detailViewBg.gif create mode 100644 themes/default/images/detailview.gif create mode 100644 themes/default/images/doc_image_inline.gif create mode 100644 themes/default/images/downarrow.gif create mode 100644 themes/default/images/downarrow_big.gif create mode 100644 themes/default/images/downarrow_inline.gif create mode 100644 themes/default/images/dp-bd-dc.png create mode 100644 themes/default/images/dp-bd-menu.png create mode 100644 themes/default/images/dp-bd-top-menu.png create mode 100644 themes/default/images/dp-bd.png create mode 100644 themes/default/images/dp-bl-dc.png create mode 100644 themes/default/images/dp-bl-menu.png create mode 100644 themes/default/images/dp-bl.png create mode 100644 themes/default/images/dp-br-dc.png create mode 100644 themes/default/images/dp-br-menu.png create mode 100644 themes/default/images/dp-br.png create mode 100644 themes/default/images/dp-ft-dc.png create mode 100644 themes/default/images/dp-ft-menu.png create mode 100644 themes/default/images/dp-ft.png create mode 100644 themes/default/images/dp-hd-dc.png create mode 100644 themes/default/images/dp-hd-menu.png create mode 100644 themes/default/images/dp-hd-plain.png create mode 100644 themes/default/images/dp-hd.png create mode 100644 themes/default/images/dp-ml-dc.png create mode 100644 themes/default/images/dp-ml-menu.png create mode 100644 themes/default/images/dp-ml.png create mode 100644 themes/default/images/dp-mr-dc.png create mode 100644 themes/default/images/dp-mr-menu.png create mode 100644 themes/default/images/dp-mr.png create mode 100644 themes/default/images/dp-tl-dc.png create mode 100644 themes/default/images/dp-tl-menu.png create mode 100644 themes/default/images/dp-tl-plain.png create mode 100644 themes/default/images/dp-tl.png create mode 100644 themes/default/images/dp-tr-dc.png create mode 100644 themes/default/images/dp-tr-menu.png create mode 100644 themes/default/images/dp-tr-plain.png create mode 100644 themes/default/images/dp-tr.png create mode 100644 themes/default/images/edit_inline.gif create mode 100644 themes/default/images/edit_wizard.gif create mode 100644 themes/default/images/editfields.gif create mode 100644 themes/default/images/editlabels.gif create mode 100644 themes/default/images/editview.gif create mode 100644 themes/default/images/emptyTabSpace.gif create mode 100644 themes/default/images/end.gif create mode 100644 themes/default/images/end_off.gif create mode 100644 themes/default/images/export.gif create mode 100644 themes/default/images/fonts.larger.icon.gif create mode 100644 themes/default/images/fonts.largest.icon.gif create mode 100644 themes/default/images/fonts.normal.icon.gif create mode 100644 themes/default/images/form-button-bg.png create mode 100644 themes/default/images/form-button-bg2.png create mode 100644 themes/default/images/form-button-primary-bg.png create mode 100644 themes/default/images/formButtonBg.gif create mode 100644 themes/default/images/formButtonBgOn.gif create mode 100644 themes/default/images/getLatestDocument.gif create mode 100644 themes/default/images/green_camp.gif create mode 100644 themes/default/images/grouped-menu-arrow.png create mode 100644 themes/default/images/grouped-menu.png create mode 100644 themes/default/images/h3Arrow.gif create mode 100644 themes/default/images/help-dashlet.gif create mode 100644 themes/default/images/help.gif create mode 100644 themes/default/images/helpInline.gif create mode 100644 themes/default/images/hide.gif create mode 100644 themes/default/images/hide_submenu_shortcuts.gif create mode 100644 themes/default/images/iFrames.gif create mode 100644 themes/default/images/icon_A1_newmod.gif create mode 100644 themes/default/images/icon_Accounts.gif create mode 100644 themes/default/images/icon_Accounts_32.gif create mode 100644 themes/default/images/icon_Activities.gif create mode 100644 themes/default/images/icon_Address.gif create mode 100644 themes/default/images/icon_AdminMobile.gif create mode 100644 themes/default/images/icon_AdminPDF.gif create mode 100644 themes/default/images/icon_AdminThemes.gif create mode 100644 themes/default/images/icon_AdvancedSearch.gif create mode 100644 themes/default/images/icon_Application.gif create mode 100644 themes/default/images/icon_BasicSearch.gif create mode 100644 themes/default/images/icon_Bugs.gif create mode 100644 themes/default/images/icon_Bugs_32.gif create mode 100644 themes/default/images/icon_Calendar_32.gif create mode 100644 themes/default/images/icon_Calls.gif create mode 100644 themes/default/images/icon_Calls_32.gif create mode 100644 themes/default/images/icon_CampaignLog_32.gif create mode 100644 themes/default/images/icon_Campaigns.gif create mode 100644 themes/default/images/icon_Campaigns_32.gif create mode 100644 themes/default/images/icon_Cases.gif create mode 100644 themes/default/images/icon_Cases_32.gif create mode 100644 themes/default/images/icon_Charts_Funnel.gif create mode 100644 themes/default/images/icon_Charts_Funnel_32.gif create mode 100644 themes/default/images/icon_Charts_Gauge_32.gif create mode 100644 themes/default/images/icon_Charts_GroupBy.gif create mode 100644 themes/default/images/icon_Charts_GroupBy_32.gif create mode 100644 themes/default/images/icon_Charts_Horizontal.gif create mode 100644 themes/default/images/icon_Charts_Horizontal_32.gif create mode 100644 themes/default/images/icon_Charts_Pie.gif create mode 100644 themes/default/images/icon_Charts_Pie_32.gif create mode 100644 themes/default/images/icon_Charts_Vertical.gif create mode 100644 themes/default/images/icon_Charts_Vertical_32.gif create mode 100644 themes/default/images/icon_Column_1.gif create mode 100644 themes/default/images/icon_Column_2.gif create mode 100644 themes/default/images/icon_Column_3.gif create mode 100644 themes/default/images/icon_ConnectorConfig.gif create mode 100644 themes/default/images/icon_ConnectorConfigOver.gif create mode 100644 themes/default/images/icon_ConnectorConfig_16.gif create mode 100644 themes/default/images/icon_ConnectorEnable.gif create mode 100644 themes/default/images/icon_ConnectorEnableOver.gif create mode 100644 themes/default/images/icon_ConnectorEnable_16.gif create mode 100644 themes/default/images/icon_ConnectorMap.gif create mode 100644 themes/default/images/icon_ConnectorMapOver.gif create mode 100644 themes/default/images/icon_ConnectorMap_16.gif create mode 100644 themes/default/images/icon_ConnectorSearchFields.gif create mode 100644 themes/default/images/icon_ConnectorSearchFieldsOver.gif create mode 100644 themes/default/images/icon_ConnectorSearchFields_16.gif create mode 100644 themes/default/images/icon_Connectors.gif create mode 100644 themes/default/images/icon_Contacts.gif create mode 100644 themes/default/images/icon_Contacts_32.gif create mode 100644 themes/default/images/icon_Contracts_32.gif create mode 100644 themes/default/images/icon_ConvertLead.gif create mode 100644 themes/default/images/icon_Dashlet.gif create mode 100644 themes/default/images/icon_Delete.gif create mode 100644 themes/default/images/icon_DeleteFull.gif create mode 100644 themes/default/images/icon_DetailView.gif create mode 100644 themes/default/images/icon_Documents.gif create mode 100644 themes/default/images/icon_Documents_32.gif create mode 100644 themes/default/images/icon_DropDownEditor.gif create mode 100644 themes/default/images/icon_EditView.gif create mode 100644 themes/default/images/icon_EmailAddress.gif create mode 100644 themes/default/images/icon_EmailAddresses_32.gif create mode 100644 themes/default/images/icon_EmailTemplates_32.gif create mode 100644 themes/default/images/icon_Emails.gif create mode 100644 themes/default/images/icon_Emails_32.gif create mode 100644 themes/default/images/icon_FavoriteReports_32.gif create mode 100644 themes/default/images/icon_Feeds_32.gif create mode 100644 themes/default/images/icon_Fields.gif create mode 100644 themes/default/images/icon_Forecasts_32.gif create mode 100644 themes/default/images/icon_Invaders_32.gif create mode 100644 themes/default/images/icon_JotPad.gif create mode 100644 themes/default/images/icon_JotPad_32.gif create mode 100644 themes/default/images/icon_KBDocuments.gif create mode 100644 themes/default/images/icon_KBDocuments_32.gif create mode 100644 themes/default/images/icon_Labels.gif create mode 100644 themes/default/images/icon_Layouts.gif create mode 100644 themes/default/images/icon_Leads.gif create mode 100644 themes/default/images/icon_Leads_32.gif create mode 100644 themes/default/images/icon_ListView.gif create mode 100644 themes/default/images/icon_Meetings.gif create mode 100644 themes/default/images/icon_Meetings_32.gif create mode 100644 themes/default/images/icon_MobileLayouts.gif create mode 100644 themes/default/images/icon_ModuleBuilder.gif create mode 100644 themes/default/images/icon_MyPortal_32.gif create mode 100644 themes/default/images/icon_MyTasks_32.gif create mode 100644 themes/default/images/icon_NewModule.gif create mode 100644 themes/default/images/icon_Notes.gif create mode 100644 themes/default/images/icon_Notes_32.gif create mode 100644 themes/default/images/icon_OpenTasks_32.gif create mode 100644 themes/default/images/icon_Opportunities.gif create mode 100644 themes/default/images/icon_Opportunities_32.gif create mode 100644 themes/default/images/icon_Phone.gif create mode 100644 themes/default/images/icon_Popup.gif create mode 100644 themes/default/images/icon_Portal.gif create mode 100644 themes/default/images/icon_ProductCategories_32.gif create mode 100644 themes/default/images/icon_ProductTypes_32.gif create mode 100644 themes/default/images/icon_Product_Types_32.gif create mode 100644 themes/default/images/icon_Products_32.gif create mode 100644 themes/default/images/icon_Project.gif create mode 100644 themes/default/images/icon_ProjectTask.gif create mode 100644 themes/default/images/icon_ProjectTask_32.gif create mode 100644 themes/default/images/icon_Project_32.gif create mode 100644 themes/default/images/icon_Projects_32.gif create mode 100644 themes/default/images/icon_Prospects.gif create mode 100644 themes/default/images/icon_Prospects_32.gif create mode 100644 themes/default/images/icon_QuickCreate.gif create mode 100644 themes/default/images/icon_Quotes_32.gif create mode 100644 themes/default/images/icon_Relationships.gif create mode 100644 themes/default/images/icon_Releases_32.gif create mode 100644 themes/default/images/icon_Reports_32.gif create mode 100644 themes/default/images/icon_Rss_32.gif create mode 100644 themes/default/images/icon_SPSync.gif create mode 100644 themes/default/images/icon_SPUploadCSS.gif create mode 100644 themes/default/images/icon_SearchForm.gif create mode 100644 themes/default/images/icon_ShortcutBar.gif create mode 100644 themes/default/images/icon_Studio.gif create mode 100644 themes/default/images/icon_Subpanels.gif create mode 100644 themes/default/images/icon_SugarFeed.gif create mode 100644 themes/default/images/icon_SugarFeed_32.gif create mode 100644 themes/default/images/icon_SugarNews_32.gif create mode 100644 themes/default/images/icon_SugarPortal.gif create mode 100644 themes/default/images/icon_Targets_32.gif create mode 100644 themes/default/images/icon_Tasks.gif create mode 100644 themes/default/images/icon_Tasks_32.gif create mode 100644 themes/default/images/icon_Teams_32.gif create mode 100644 themes/default/images/icon_TrackerPerfs_32.gif create mode 100644 themes/default/images/icon_TrackerQueries_32.gif create mode 100644 themes/default/images/icon_TrackerSessions_32.gif create mode 100644 themes/default/images/icon_Trackers_32.gif create mode 100644 themes/default/images/icon_Users_32.gif create mode 100644 themes/default/images/icon_assistant.gif create mode 100644 themes/default/images/icon_back.gif create mode 100644 themes/default/images/icon_basic.gif create mode 100644 themes/default/images/icon_company.gif create mode 100644 themes/default/images/icon_document.gif create mode 100644 themes/default/images/icon_email_addressbook.gif create mode 100644 themes/default/images/icon_email_archive.gif create mode 100644 themes/default/images/icon_email_assign.gif create mode 100644 themes/default/images/icon_email_attach.gif create mode 100644 themes/default/images/icon_email_check.gif create mode 100644 themes/default/images/icon_email_compose.gif create mode 100644 themes/default/images/icon_email_create.gif create mode 100644 themes/default/images/icon_email_delete.gif create mode 100644 themes/default/images/icon_email_folder.gif create mode 100644 themes/default/images/icon_email_folder_archives.gif create mode 100644 themes/default/images/icon_email_folder_drafts.gif create mode 100644 themes/default/images/icon_email_folder_exp.gif create mode 100644 themes/default/images/icon_email_folder_grp.gif create mode 100644 themes/default/images/icon_email_folder_sent.gif create mode 100644 themes/default/images/icon_email_forward.gif create mode 100644 themes/default/images/icon_email_fullscreen.gif create mode 100644 themes/default/images/icon_email_mark.gif create mode 100644 themes/default/images/icon_email_options.gif create mode 100644 themes/default/images/icon_email_relate.gif create mode 100644 themes/default/images/icon_email_reply.gif create mode 100644 themes/default/images/icon_email_replyall.gif create mode 100644 themes/default/images/icon_email_save.gif create mode 100644 themes/default/images/icon_email_send.gif create mode 100644 themes/default/images/icon_email_settings.gif create mode 100644 themes/default/images/icon_email_sugfolder.gif create mode 100644 themes/default/images/icon_email_sugfolder_exp.gif create mode 100644 themes/default/images/icon_email_view.gif create mode 100644 themes/default/images/icon_email_view1.gif create mode 100644 themes/default/images/icon_email_view2.gif create mode 100644 themes/default/images/icon_email_view3.gif create mode 100644 themes/default/images/icon_expression_types.gif create mode 100644 themes/default/images/icon_file.gif create mode 100644 themes/default/images/icon_home.gif create mode 100644 themes/default/images/icon_iFrames_32.gif create mode 100644 themes/default/images/icon_issue.gif create mode 100644 themes/default/images/icon_new_package.gif create mode 100644 themes/default/images/icon_opportunity.gif create mode 100644 themes/default/images/icon_package.gif create mode 100644 themes/default/images/icon_package_create.gif create mode 100644 themes/default/images/icon_person.gif create mode 100644 themes/default/images/icon_sale.gif create mode 100644 themes/default/images/icon_therevisions.gif create mode 100644 themes/default/images/id-ff-add.png create mode 100644 themes/default/images/id-ff-clear.png create mode 100644 themes/default/images/id-ff-copy.png create mode 100644 themes/default/images/id-ff-remove.png create mode 100644 themes/default/images/id-ff-select.png create mode 100644 themes/default/images/id-ff-vcard.png create mode 100644 themes/default/images/img_close_search.gif create mode 100644 themes/default/images/img_left_arrow.jpg create mode 100644 themes/default/images/img_loading.gif create mode 100644 themes/default/images/img_right_arrow.jpg create mode 100644 themes/default/images/info-add.gif create mode 100644 themes/default/images/info-help.gif create mode 100644 themes/default/images/info-layout.gif create mode 100644 themes/default/images/info_inline.gif create mode 100644 themes/default/images/join_imeeting.gif create mode 100644 themes/default/images/join_meeting_inline.png create mode 100644 themes/default/images/jscalendar.gif create mode 100644 themes/default/images/leftarrow.gif create mode 100644 themes/default/images/leftarrow_big.gif create mode 100644 themes/default/images/line.gif create mode 100644 themes/default/images/list.gif create mode 100644 themes/default/images/listViewBg.gif create mode 100644 themes/default/images/listViewHR.gif create mode 100644 themes/default/images/loadSignedDocument.gif create mode 100644 themes/default/images/loading.gif create mode 100644 themes/default/images/login-bg.png create mode 100644 themes/default/images/mass_update.gif create mode 100644 themes/default/images/menuarrow.gif create mode 100644 themes/default/images/minus.gif create mode 100644 themes/default/images/minus_inline.gif create mode 100644 themes/default/images/more.gif create mode 100644 themes/default/images/new_inline.gif create mode 100644 themes/default/images/next.gif create mode 100644 themes/default/images/next_off.gif create mode 100644 themes/default/images/no.gif create mode 100644 themes/default/images/open_multiple.gif create mode 100644 themes/default/images/otherTab.gif create mode 100644 themes/default/images/otherTab.png create mode 100644 themes/default/images/otherTabBlue.gif create mode 100644 themes/default/images/otherTabGray.gif create mode 100644 themes/default/images/otherTabGreen.gif create mode 100644 themes/default/images/otherTabOcher.gif create mode 100644 themes/default/images/otherTabPurple.gif create mode 100644 themes/default/images/otherTabRed.gif create mode 100644 themes/default/images/pdf_header_logo_SugarCRMheader.jpg create mode 100644 themes/default/images/pdf_header_logo_company_logo.png create mode 100644 themes/default/images/pdf_header_logo_img_left_arrow.jpg create mode 100644 themes/default/images/pdf_header_logo_pdf_header_logo_SugarCRMheader.jpg create mode 100644 themes/default/images/pdf_image_inline.gif create mode 100644 themes/default/images/pdf_logo.jpg create mode 100644 themes/default/images/pdf_logo_small.jpg create mode 100644 themes/default/images/plug-in_Excel.gif create mode 100644 themes/default/images/plug-in_Outlook.gif create mode 100644 themes/default/images/plug-in_Word.gif create mode 100644 themes/default/images/plus.gif create mode 100644 themes/default/images/plus_inline.gif create mode 100644 themes/default/images/ppt_image_inline.gif create mode 100644 themes/default/images/previous.gif create mode 100644 themes/default/images/previous_off.gif create mode 100644 themes/default/images/print.gif create mode 100644 themes/default/images/publish_inline.gif create mode 100644 themes/default/images/red_camp.gif create mode 100644 themes/default/images/rightarrow.gif create mode 100644 themes/default/images/rightarrow_big.gif create mode 100644 themes/default/images/scheduled_inline.gif create mode 100644 themes/default/images/searchMore.gif create mode 100644 themes/default/images/shortCutsBg.png create mode 100644 themes/default/images/show.gif create mode 100644 themes/default/images/show_submenu_shortcuts.gif create mode 100644 themes/default/images/slot.gif create mode 100644 themes/default/images/spacer.gif create mode 100644 themes/default/images/sqsWait.gif create mode 100644 themes/default/images/start.gif create mode 100644 themes/default/images/start_meeting_inline.png create mode 100644 themes/default/images/start_off.gif create mode 100644 themes/default/images/studio_addField.gif create mode 100644 themes/default/images/studio_addRows.gif create mode 100644 themes/default/images/studio_blank.gif create mode 100644 themes/default/images/studio_history.gif create mode 100644 themes/default/images/studio_publish.gif create mode 100644 themes/default/images/studio_redo.gif create mode 100644 themes/default/images/studio_save.gif create mode 100644 themes/default/images/studio_undo.gif create mode 100644 themes/default/images/sugar-yui-sprites-grey.png create mode 100644 themes/default/images/sugarColors.xml create mode 100644 themes/default/images/sugar_document.png create mode 100644 themes/default/images/sugar_icon.ico create mode 100644 themes/default/images/sugar_icon.png create mode 100644 themes/default/images/sugarupdate.gif create mode 100644 themes/default/images/tabRowBlueBg.gif create mode 100644 themes/default/images/tabRowGrayBg.gif create mode 100644 themes/default/images/tabRowGreenBg.gif create mode 100644 themes/default/images/tabRowOcherBg.gif create mode 100644 themes/default/images/tabRowPurpleBg.gif create mode 100644 themes/default/images/tabRowRedBg.gif create mode 100644 themes/default/images/tentative_inline.gif create mode 100644 themes/default/images/themePreview.png create mode 100644 themes/default/images/txt_image_inline.gif create mode 100644 themes/default/images/unpublish_inline.gif create mode 100644 themes/default/images/unscheduled_inline.gif create mode 100644 themes/default/images/uparrow.gif create mode 100644 themes/default/images/uparrow_big.gif create mode 100644 themes/default/images/uparrow_inline.gif create mode 100644 themes/default/images/view.gif create mode 100644 themes/default/images/view_inline.gif create mode 100644 themes/default/images/view_status.gif create mode 100644 themes/default/images/xls_image_inline.gif create mode 100644 themes/default/images/yellow_camp.gif create mode 100644 themes/default/images/yes.gif create mode 100644 themes/default/js/style.js create mode 100644 vCard.php create mode 100644 vcal_server.php diff --git a/HandleAjaxCall.php b/HandleAjaxCall.php new file mode 100644 index 00000000..20ea22a3 --- /dev/null +++ b/HandleAjaxCall.php @@ -0,0 +1,56 @@ +$requestedMethod(); + } + else { + echo 'no method'; + } + // sugar_cleanup(); +?> diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 00000000..8d85809d --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,661 @@ + GNU AFFERO GENERAL PUBLIC LICENSE + Version 3, 19 November 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 Affero General Public License is a free, copyleft license for +software and other kinds of works, specifically designed to ensure +cooperation with the community in the case of network server software. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +our General Public Licenses are 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. + + 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. + + Developers that use our General Public Licenses protect your rights +with two steps: (1) assert copyright on the software, and (2) offer +you this License which gives you legal permission to copy, distribute +and/or modify the software. + + A secondary benefit of defending all users' freedom is that +improvements made in alternate versions of the program, if they +receive widespread use, become available for other developers to +incorporate. Many developers of free software are heartened and +encouraged by the resulting cooperation. However, in the case of +software used on network servers, this result may fail to come about. +The GNU General Public License permits making a modified version and +letting the public access it on a server without ever releasing its +source code to the public. + + The GNU Affero General Public License is designed specifically to +ensure that, in such cases, the modified source code becomes available +to the community. It requires the operator of a network server to +provide the source code of the modified version running there to the +users of that server. Therefore, public use of a modified version, on +a publicly accessible server, gives the public access to the source +code of the modified version. + + An older license, called the Affero General Public License and +published by Affero, was designed to accomplish similar goals. This is +a different license, not a version of the Affero GPL, but Affero has +released a new version of the Affero GPL which permits relicensing under +this license. + + 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 Affero 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. Remote Network Interaction; Use with the GNU General Public License. + + Notwithstanding any other provision of this License, if you modify the +Program, your modified version must prominently offer all users +interacting with it remotely through a computer network (if your version +supports such interaction) an opportunity to receive the Corresponding +Source of your version by providing access to the Corresponding Source +from a network server at no charge, through some standard or customary +means of facilitating copying of software. This Corresponding Source +shall include the Corresponding Source for any work covered by version 3 +of the GNU General Public License that is incorporated pursuant to the +following paragraph. + + 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 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 work with which it is combined will remain governed by version +3 of the GNU General Public License. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU Affero 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 Affero 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 Affero 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 Affero 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 Affero 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 Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If your software can interact with users remotely through a computer +network, you should also make sure that it provides a way for users to +get its source. For example, if your program is a web application, its +interface could display a "Source" link that leads users to an archive +of the code. There are many ways you could offer source, and different +solutions will be better for different programs; see section 13 for the +specific requirements. + + 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 AGPL, see +. \ No newline at end of file diff --git a/ModuleInstall/ModuleInstaller.php b/ModuleInstall/ModuleInstaller.php new file mode 100644 index 00000000..45901b44 --- /dev/null +++ b/ModuleInstall/ModuleInstaller.php @@ -0,0 +1,2351 @@ +custom_fields->addField + * 2. installing relationships - calls createTableParams to build the relationship table, and createRelationshipMeta to add the relationship to the relationship table + * 3. rebuilding the relationships - at almost the last step in install(), calls modules/Administration/RebuildRelationship.php + * 4. repair indices - uses "modules/Administration/RepairIndex.php"; + */ + + + +require_once('include/utils/progress_bar_utils.php'); + +require_once('ModuleInstall/ModuleScanner.php'); +define('DISABLED_PATH', 'Disabled'); + +class ModuleInstaller{ + var $modules = array(); + var $silent = false; + var $base_dir = ''; + var $modulesInPackage = array(); + + function ModuleInstaller(){ + $this->ms = new ModuleScanner(); + $this->modules = get_module_dir_list(); + $this->db = & DBManagerFactory::getInstance(); + + } + + /* + * ModuleInstaller->install includes the manifest.php from the base directory it has been given. If it has been asked to do an upgrade it checks to see if there is + * an upgrade_manifest defined in the manifest; if not it errors. It then adds the bean into the custom/Extension/application/Ext/Include/.php - sets beanList, beanFiles + * and moduleList - and then calls ModuleInstaller->merge_files('Ext/Include', 'modules.ext.php', '', true) to merge the individual module files into a combined file + * /custom/Extension/application/Ext/Include/modules.ext.php (which now contains a list of all $beanList, $beanFiles and $moduleList for all extension modules) - + * this file modules.ext.php is included at the end of modules.php. + * + * Finally it runs over a list of defined tasks; then install_beans, then install_custom_fields, then clear the Vardefs, run a RepairAndClear, then finally call rebuild_relationships. + */ + function install($base_dir, $is_upgrade = false, $previous_version = ''){ + if(defined('TEMPLATE_URL'))SugarTemplateUtilities::disableCache(); + if(!empty($GLOBALS['sugar_config']['moduleInstaller']['packageScan'])){ + $this->ms->scanPackage($base_dir); + if($this->ms->hasIssues()){ + $this->ms->displayIssues(); + sugar_cleanup(true); + } + } + + global $app_strings, $mod_strings; + $this->base_dir = $base_dir; + $total_steps = 5; //minimum number of steps with no tasks + $current_step = 0; + $tasks = array( + 'pre_execute', + 'install_copy', + 'install_images', + 'install_menus', + 'install_dcactions', + 'install_userpage', + 'install_dashlets', + 'install_administration', + 'install_connectors', + 'install_vardefs', + 'install_layoutdefs', + 'install_layoutfields', + 'install_relationships', + 'install_languages', + 'install_logichooks', + 'post_execute', + 'reset_opcodes', + ); + + $total_steps += count($tasks); + if(file_exists($this->base_dir . '/manifest.php')){ + if(!$this->silent){ + $current_step++; + display_progress_bar('install', $current_step, $total_steps); + echo ''; + } + if(!$this->silent){ + $current_step++; + update_progress_bar('install', $current_step, $total_steps); + echo ''; + } + $selectedActions = array( + 'clearTpls', + 'clearJsFiles', + 'clearDashlets', + 'clearVardefs', + 'clearJsLangFiles', + 'rebuildAuditTables', + 'repairDatabase', + ); + VardefManager::clearVardef(); + global $beanList, $beanFiles, $moduleList; + if (file_exists('custom/application/Ext/Include/modules.ext.php')) + { + include('custom/application/Ext/Include/modules.ext.php'); + } + require_once("modules/Administration/upgrade_custom_relationships.php"); + upgrade_custom_relationships($installed_modules); + $this->rebuild_all(true); + require_once('modules/Administration/QuickRepairAndRebuild.php'); + $rac = new RepairAndClear(); + $rac->repairAndClearAll($selectedActions, $installed_modules,true, false); + $this->rebuild_relationships(); + UpdateSystemTabs('Add',$tab_modules); + + //clear the unified_search_module.php file + require_once('modules/Home/UnifiedSearchAdvanced.php'); + UnifiedSearchAdvanced::unlinkUnifiedSearchModulesFile(); + + $this->log('
' . translate('LBL_MI_COMPLETE') . ''); + }else{ + die("No \$installdefs Defined In $this->base_dir/manifest.php"); + } + + } + + function install_user_prefs($module, $hide_from_user=false){ + UserPreference::updateAllUserPrefs('display_tabs', $module, '', true, !$hide_from_user); + UserPreference::updateAllUserPrefs('hide_tabs', $module, '', true, $hide_from_user); + UserPreference::updateAllUserPrefs('remove_tabs', $module, '', true, $hide_from_user); + } + function uninstall_user_prefs($module){ + UserPreference::updateAllUserPrefs('display_tabs', $module, '', true, true); + UserPreference::updateAllUserPrefs('hide_tabs', $module, '', true, true); + UserPreference::updateAllUserPrefs('remove_tabs', $module, '', true, true); + } + + function pre_execute(){ + require_once($this->base_dir . '/manifest.php'); + if(isset($this->installdefs['pre_execute']) && is_array($this->installdefs['pre_execute'])){ + foreach($this->installdefs['pre_execute'] as $includefile){ + require_once(str_replace('', $this->base_dir, $includefile)); + } + } + } + + function post_execute(){ + require_once($this->base_dir . '/manifest.php'); + if(isset($this->installdefs['post_execute']) && is_array($this->installdefs['post_execute'])){ + foreach($this->installdefs['post_execute'] as $includefile){ + require_once(str_replace('', $this->base_dir, $includefile)); + } + } + } + + function pre_uninstall(){ + require_once($this->base_dir . '/manifest.php'); + if(isset($this->installdefs['pre_uninstall']) && is_array($this->installdefs['pre_uninstall'])){ + foreach($this->installdefs['pre_uninstall'] as $includefile){ + require_once(str_replace('', $this->base_dir, $includefile)); + } + } + } + + function post_uninstall(){ + require_once($this->base_dir . '/manifest.php'); + if(isset($this->installdefs['post_uninstall']) && is_array($this->installdefs['post_uninstall'])){ + foreach($this->installdefs['post_uninstall'] as $includefile){ + require_once(str_replace('', $this->base_dir, $includefile)); + } + } + } + + /* + * ModuleInstaller->install_copy gets the copy section of installdefs in the manifest and calls copy_path to copy each path (file or directory) to its final location + * (specified as from and to in the manifest), replacing by the base_dir value passed in to install. + */ + function install_copy(){ + if(isset($this->installdefs['copy'])){ + /* BEGIN - RESTORE POINT - by MR. MILK August 31, 2005 02:22:11 PM */ + $backup_path = clean_path( remove_file_extension(urldecode(hashToFile($_REQUEST['install_file'])))."-restore" ); + /* END - RESTORE POINT - by MR. MILK August 31, 2005 02:22:18 PM */ + foreach($this->installdefs['copy'] as $cp){ + $GLOBALS['log']->debug("Copying ..." . $cp['from']. " to " .$cp['to'] ); + /* BEGIN - RESTORE POINT - by MR. MILK August 31, 2005 02:22:11 PM */ + //$this->copy_path($cp['from'], $cp['to']); + $this->copy_path($cp['from'], $cp['to'], $backup_path); + /* END - RESTORE POINT - by MR. MILK August 31, 2005 02:22:18 PM */ + } + //here we should get the module list again as we could have copied something to the modules dir + $this->modules = get_module_dir_list(); + } + } + function uninstall_copy(){ + if(!empty($this->installdefs['copy'])){ + foreach($this->installdefs['copy'] as $cp){ + $cp['to'] = clean_path(str_replace('', $this->base_dir, $cp['to'])); + $cp['from'] = clean_path(str_replace('', $this->base_dir, $cp['from'])); + $GLOBALS['log']->debug('Unlink ' . $cp['to']); + /* BEGIN - RESTORE POINT - by MR. MILK August 31, 2005 02:22:11 PM */ + //rmdir_recursive($cp['to']); + + $backup_path = clean_path( remove_file_extension(urldecode(hashToFile($_REQUEST['install_file'])))."-restore/".$cp['to'] ); + $this->uninstall_new_files($cp, $backup_path); + $this->copy_path($backup_path, $cp['to'], $backup_path, true); + /* END - RESTORE POINT - by MR. MILK August 31, 2005 02:22:18 PM */ + } + $backup_path = clean_path( remove_file_extension(urldecode(hashToFile($_REQUEST['install_file'])))."-restore"); + if(file_exists($backup_path)) + rmdir_recursive($backup_path); + } + } + + + /** + * Removes any files that were added by the loaded module. If the files already existed prior to install + * it will be handled by copy_path with the uninstall parameter. + * + */ + function uninstall_new_files($cp, $backup_path){ + $zip_files = $this->dir_get_files($cp['from'],$cp['from']); + $backup_files = $this->dir_get_files($backup_path, $backup_path); + foreach($zip_files as $k=>$v){ + //if it's not a backup then it is probably a new file but we'll check that it is not in the md5.files first + if(!isset($backup_files[$k])){ + $to = $cp['to'] . $k; + //if it's not a sugar file then we remove it otherwise we can't restor it + if(!$this->ms->sugarFileExists($to)){ + $GLOBALS['log']->debug('ModuleInstaller[uninstall_new_file] deleting file ' . $to); + if(file_exists($to)) { + unlink($to); + } + }else{ + $GLOBALS['log']->fatal('ModuleInstaller[uninstall_new_file] Could not remove file ' . $to . ' as no backup file was found to restore to'); + } + } + } + //lets check if the directory is empty if it is we will delete it as well + $files_remaining = $this->dir_file_count($cp['to']); + if(file_exists($cp['to']) && $files_remaining == 0){ + $GLOBALS['log']->debug('ModuleInstaller[uninstall_new_file] deleting directory ' . $cp['to']); + rmdir_recursive($cp['to']); + } + + } + + + function install_dashlets(){ + if(isset($this->installdefs['dashlets'])){ + foreach($this->installdefs['dashlets'] as $cp){ + $this->log(translate('LBL_MI_IN_DASHLETS') . $cp['name']); + $cp['from'] = str_replace('', $this->base_dir, $cp['from']); + $path = 'custom/modules/Home/Dashlets/' . $cp['name'] . '/'; + $GLOBALS['log']->debug("Installing Dashlet " . $cp['name'] . "..." . $cp['from'] ); + if(!file_exists($path)){ + mkdir_recursive($path, true); + } + copy_recursive($cp['from'] , $path); + } + include('modules/Administration/RebuildDashlets.php'); + + } + } + + function uninstall_dashlets(){ + if(isset($this->installdefs['dashlets'])){ + foreach($this->installdefs['dashlets'] as $cp){ + $this->log(translate('LBL_MI_UN_DASHLETS') . $cp['name']); + $path = 'custom/modules/Home/Dashlets/' . $cp['name']; + $GLOBALS['log']->debug('Unlink ' .$path); + if (file_exists($path)) + rmdir_recursive($path); + } + include('modules/Administration/RebuildDashlets.php'); + } + } + + + function install_images(){ + if(isset($this->installdefs['image_dir'])){ + $this->log( translate('LBL_MI_IN_IMAGES') ); + $this->copy_path($this->installdefs['image_dir'] , 'custom/themes'); + + } + } + + function install_menus(){ + if(isset($this->installdefs['menu'])){ + $this->log(translate('LBL_MI_IN_MENUS')); + foreach($this->installdefs['menu'] as $menu){ + $menu['from'] = str_replace('', $this->base_dir, $menu['from']); + $GLOBALS['log']->debug("Installing Menu ..." . $menu['from']. " for " .$menu['to_module'] ); + $path = 'custom/Extension/modules/' . $menu['to_module']. '/Ext/Menus'; + if($menu['to_module'] == 'application'){ + $path ='custom/Extension/' . $menu['to_module']. '/Ext/Menus'; + } + if(!file_exists($path)){ + mkdir_recursive($path, true); + + } + copy_recursive($menu['from'] , $path . '/'. $this->id_name . '.php'); + } + $this->rebuild_menus(); + } + } + + function uninstall_menus(){ + if(isset($this->installdefs['menu'])){ + $this->log(translate('LBL_MI_UN_MENUS')); + foreach($this->installdefs['menu'] as $menu){ + $menu['from'] = str_replace('', $this->base_dir, $menu['from']); + $GLOBALS['log']->debug("Uninstalling Menu ..." . $menu['from']. " for " .$menu['to_module'] ); + $path = 'custom/Extension/modules/' . $menu['to_module']. '/Ext/Menus'; + if($menu['to_module'] == 'application'){ + $path ='custom/Extension/' . $menu['to_module']. '/Ext/Menus'; + } + if (sugar_is_file($path . '/'. $this->id_name . '.php', 'w')) + { + rmdir_recursive( $path . '/'. $this->id_name . '.php'); + } + else if (sugar_is_file($path . '/'. DISABLED_PATH . '/'. $this->id_name . '.php', 'w')) + { + rmdir_recursive( $path . '/'. DISABLED_PATH . '/'. $this->id_name . '.php'); + } + } + $this->rebuild_menus(); + } + } + + function install_dcactions(){ + if(isset($this->installdefs['dcaction'])){ + $this->log(translate('LBL_MI_IN_MENUS')); + foreach($this->installdefs['dcaction'] as $action){ + $action['from'] = str_replace('', $this->base_dir, $action['from']); + $GLOBALS['log']->debug("Installing DCActions ..." . $action['from']); + $path = 'custom/Extension/application/Ext/DashletContainer/Containers'; + if(!file_exists($path)){ + mkdir_recursive($path, true); + } + copy_recursive($action['from'] , $path . '/'. $this->id_name . '.php'); + } + $this->rebuild_dashletcontainers(); + } + } + + function uninstall_dcactions(){ + if(isset($this->installdefs['dcaction'])){ + $this->log(translate('LBL_MI_UN_MENUS')); + foreach($this->installdefs['dcaction'] as $action){ + $action['from'] = str_replace('', $this->base_dir, $action['from']); + $GLOBALS['log']->debug("Uninstalling DCActions ..." . $action['from'] ); + $path = 'custom/Extension/application/Ext/DashletContainer/Containers'; + if (sugar_is_file($path . '/'. $this->id_name . '.php', 'w')) + { + rmdir_recursive( $path . '/'. $this->id_name . '.php'); + } + else if (sugar_is_file($path . '/'. DISABLED_PATH . '/'. $this->id_name . '.php', 'w')) + { + rmdir_recursive( $path . '/'. DISABLED_PATH . '/'. $this->id_name . '.php'); + } + } + $this->rebuild_dashletcontainers(); + } + } + + function install_administration(){ + if(isset($this->installdefs['administration'])){ + $this->log(translate('LBL_MI_IN_ADMIN')); + foreach($this->installdefs['administration'] as $administration){ + $administration['from'] = str_replace('', $this->base_dir, $administration['from']); + $GLOBALS['log']->debug("Installing Administration Section ..." . $administration['from'] ); + $path = 'custom/Extension/modules/Administration/Ext/Administration'; + if(!file_exists($path)){ + mkdir_recursive($path, true); + + } + copy_recursive($administration['from'] , $path . '/'. $this->id_name . '.php'); + } + $this->rebuild_administration(); + } + + } + function uninstall_administration(){ + if(isset($this->installdefs['administration'])){ + $this->log(translate('LBL_MI_UN_ADMIN')); + foreach($this->installdefs['administration'] as $administration){ + $administration['from'] = str_replace('', $this->base_dir, $administration['from']); + $GLOBALS['log']->debug("Uninstalling Administration Section ..." . $administration['from'] ); + $path = 'custom/Extension/modules/Administration/Ext/Administration'; + if (sugar_is_file($path . '/'. $this->id_name . '.php', "w")) + rmdir_recursive( $path . '/'. $this->id_name . '.php'); + else if (sugar_is_file($path . '/'. DISABLED_PATH . "/" . $this->id_name . '.php', "w")) + rmdir_recursive( $path . '/'. DISABLED_PATH . "/" . $this->id_name . '.php'); + } + $this->rebuild_administration(); + } + } + + function install_connectors(){ + if(isset($this->installdefs['connectors'])){ + foreach($this->installdefs['connectors'] as $cp){ + $this->log(translate('LBL_MI_IN_CONNECTORS') . $cp['name']); + $dir = str_replace('_','/',$cp['name']); + $cp['connector'] = str_replace('', $this->base_dir, $cp['connector']); + $source_path = 'custom/modules/Connectors/connectors/sources/' . $dir. '/'; + $GLOBALS['log']->debug("Installing Connector " . $cp['name'] . "..." . $cp['connector'] ); + if(!file_exists($source_path)){ + mkdir_recursive($source_path, true); + } + copy_recursive($cp['connector'] , $source_path); + + //Install optional formatter code if it is specified + if(!empty($cp['formatter'])) { + $cp['formatter'] = str_replace('', $this->base_dir, $cp['formatter']); + $formatter_path = 'custom/modules/Connectors/connectors/formatters/' . $dir. '/'; + if(!file_exists($formatter_path)){ + mkdir_recursive($formatter_path, true); + } + copy_recursive($cp['formatter'] , $formatter_path); + } + } + require_once('include/connectors/utils/ConnectorUtils.php'); + ConnectorUtils::installSource($cp['name']); + } + + } + function uninstall_connectors(){ + if(isset($this->installdefs['connectors'])){ + foreach($this->installdefs['connectors'] as $cp){ + $this->log(translate('LBL_MI_UN_CONNECTORS') . $cp['name']); + $dir = str_replace('_','/',$cp['name']); + $source_path = 'custom/modules/Connectors/connectors/sources/' . $dir; + $formatter_path = 'custom/modules/Connectors/connectors/formatters/' . $dir; + $GLOBALS['log']->debug('Unlink ' .$source_path); + rmdir_recursive($source_path); + rmdir_recursive($formatter_path); + } + require_once('include/connectors/utils/ConnectorUtils.php'); + //ConnectorUtils::getConnectors(true); + ConnectorUtils::uninstallSource($cp['name']); + } + } + + function install_userpage(){ + if(isset($this->installdefs['user_page'])){ + $this->log(translate('LBL_MI_IN_USER')); + foreach($this->installdefs['user_page'] as $userpage){ + $userpage['from'] = str_replace('', $this->base_dir, $userpage['from']); + $GLOBALS['log']->debug("Installing User Page Section ..." . $userpage['from'] ); + $path = 'custom/Extension/modules/Users/Ext/UserPage'; + if(!file_exists($path)){ + mkdir_recursive($path, true); + + } + copy_recursive($userpage['from'] , $path . '/'. $this->id_name . '.php'); + } + $this->rebuild_userpage(); + } + + } + function uninstall_userpage(){ + if(isset($this->installdefs['user_page'])){ + $this->log(translate('LBL_MI_UN_USER') ); + foreach($this->installdefs['user_page'] as $userpage){ + $userpage['from'] = str_replace('', $this->base_dir, $userpage['from']); + $GLOBALS['log']->debug("Uninstalling User Page Section ..." . $userpage['from'] ); + $path = 'custom/Extension/modules/Users/Ext/UserPage'; + rmdir_recursive( $path . '/'. $this->id_name . '.php'); + } + $this->rebuild_userpage(); + } + } + + /* + * ModuleInstaller->install_vardefs uses the vardefs section of the installdefs and copies from the 'from' path (replacing as usual) to either + * custom/Extension/modules//Ext/Vardefs or custom/Extension//Ext/Vardefs if the 'to_module' value in the installdefs is set to 'application'. + * Finally rebuild_vardefs() is used to merge /Ext/Vardefs into vardefs.ext.php + */ + function install_vardefs(){ + if(isset($this->installdefs['vardefs'])){ + $this->log(translate('LBL_MI_IN_VAR') ); + foreach($this->installdefs['vardefs'] as $vardefs){ + $vardefs['from'] = str_replace('', $this->base_dir, $vardefs['from']); + $this->install_vardef($vardefs['from'], $vardefs['to_module'], $this->id_name); + } + $this->rebuild_vardefs(); + } + } + function uninstall_vardefs(){ + if(isset($this->installdefs['vardefs'])){ + $this->log(translate('LBL_MI_UN_VAR') ); + foreach($this->installdefs['vardefs'] as $vardefs){ + $vardefs['from'] = str_replace('', $this->base_dir, $vardefs['from']); + $GLOBALS['log']->debug("Uninstalling Vardefs ..." . $vardefs['from'] . " for " .$vardefs['to_module']); + $path = 'custom/Extension/modules/' . $vardefs['to_module']. '/Ext/Vardefs'; + if($vardefs['to_module'] == 'application'){ + $path ='custom/Extension/' . $vardefs['to_module']. '/Ext/Vardefs'; + } + if(file_exists($path . '/'. $this->id_name . '.php')) + { + rmdir_recursive( $path . '/'. $this->id_name . '.php'); + } + else if(file_exists($path . '/'. DISABLED_PATH . '/'. $this->id_name . '.php')) + { + rmdir_recursive($path . '/'. DISABLED_PATH . '/'. $this->id_name . '.php'); + } + else if (file_exists($path . '/'. basename($vardefs['from'] ))) + { + rmdir_recursive( $path . '/'. basename($vardefs['from'] )); + } + else if(file_exists($path . '/'. DISABLED_PATH . '/'. basename($vardefs['from']))) + { + rmdir_recursive($path . '/'. DISABLED_PATH . '/'. basename($vardefs['from'])); + } + } + $this->rebuild_vardefs(); + } + } + function install_vardef($from, $to_module){ + $GLOBALS['log']->debug("Installing Vardefs ..." . $from . " for " .$to_module); + $path = 'custom/Extension/modules/' . $to_module. '/Ext/Vardefs'; + if($to_module == 'application'){ + $path ='custom/Extension/' . $to_module. '/Ext/Vardefs'; + } + if(!file_exists($path)){ + mkdir_recursive($path, true); + } + copy_recursive($from , $path.'/'. basename($from)); + } + + /* + * ModuleInstaller->install_layoutdefs installs the $layout_defs variable (subpanel definitions) from Ext/Layoutdefs to the to_module location of + * custom/Extension/modules/' . $to_module. '/Ext/Layoutdefs/<$module>.php. before calling rebuild_layoutdefs which merge_files Ext/Layoutdefs/, 'layoutdefs.ext.php'. Note that this is not used for the viewdefs in the metadata directory - they are installed through the install_copy() operation that just takes the contents of the module directory and places it in the /modules area. + */ + function install_layoutdefs(){ + if(isset($this->installdefs['layoutdefs'])){ + $this->log(translate('LBL_MI_IN_SUBPANEL') ); + foreach($this->installdefs['layoutdefs'] as $layoutdefs){ + $layoutdefs['from'] = str_replace('', $this->base_dir, $layoutdefs['from']); + $this->install_layoutdef($layoutdefs['from'], $layoutdefs['to_module'], $this->id_name); + } + $this->rebuild_layoutdefs(); + } + } + function uninstall_layoutdefs(){ + if(isset($this->installdefs['layoutdefs'])){ + $this->log(translate('LBL_MI_UN_SUBPANEL') ); + foreach($this->installdefs['layoutdefs'] as $layoutdefs){ + $layoutdefs['from'] = str_replace('', $this->base_dir, $layoutdefs['from']); + $GLOBALS['log']->debug("Uninstalling Layoutdefs ..." . $layoutdefs['from'] . " for " .$layoutdefs['to_module']); + $path = 'custom/Extension/modules/' . $layoutdefs['to_module']. '/Ext/Layoutdefs'; + if($layoutdefs['to_module'] == 'application'){ + $path ='custom/Extension/' . $layoutdefs['to_module']. '/Ext/Layoutdefs'; + } + if (file_exists($path . '/'. $this->id_name . '.php')) + { + rmdir_recursive( $path . '/'. $this->id_name . '.php'); + } + else if (file_exists($path . '/'. DISABLED_PATH . '/' . $this->id_name . '.php')) + { + rmdir_recursive($path . '/'. DISABLED_PATH . '/' . $this->id_name . '.php'); + } + else if (file_exists($path . '/'. basename($layoutdefs['from'] ))) + { + rmdir_recursive( $path . '/'. basename($layoutdefs['from'] )); + } + else if(file_exists($path . '/'. DISABLED_PATH . '/'. basename($layoutdefs['from']))) + { + rmdir_recursive($path . '/'. DISABLED_PATH . '/'. basename($layoutdefs['from'])); + } + } + $this->rebuild_layoutdefs(); + } + } + function install_layoutdef($from, $to_module){ + $GLOBALS['log']->debug("Installing Layout Defs ..." . $from . " for " .$to_module); + $path = 'custom/Extension/modules/' . $to_module. '/Ext/Layoutdefs'; + if($to_module == 'application'){ + $path ='custom/Extension/' . $to_module. '/Ext/Layoutdefs'; + } + if(!file_exists($path)){ + mkdir_recursive($path, true); + } + copy_recursive($from , $path.'/'. basename($from)); + } + + function install_languages() + { + $languages = array(); + if(isset($this->installdefs['language'])) + { + $this->log(translate('LBL_MI_IN_LANG') ); + foreach($this->installdefs['language'] as $packs) + { + $modules[]=$packs['to_module']; + $languages[$packs['language']] = $packs['language']; + $packs['from'] = str_replace('', $this->base_dir, $packs['from']); + $GLOBALS['log']->debug("Installing Language Pack ..." . $packs['from'] . " for " .$packs['to_module']); + $path = 'custom/Extension/modules/' . $packs['to_module']. '/Ext/Language'; + if($packs['to_module'] == 'application'){ + $path ='custom/Extension/' . $packs['to_module']. '/Ext/Language'; + } + + if(!file_exists($path)){ + mkdir_recursive($path, true); + } + copy_recursive($packs['from'] , $path.'/'.$packs['language'].'.'. $this->id_name . '.php'); + } + $this->rebuild_languages($languages, $modules); + + } + } + + function uninstall_languages(){ + $languages = array(); + if(isset($this->installdefs['language'])){ + $this->log(translate('LBL_MI_UN_LANG') ); + foreach($this->installdefs['language'] as $packs){ + $modules[]=$packs['to_module']; + $languages[$packs['language']] = $packs['language']; + $packs['from'] = str_replace('', $this->base_dir, $packs['from']); + $GLOBALS['log']->debug("Uninstalling Language Pack ..." . $packs['from'] . " for " .$packs['to_module']); + $path = 'custom/Extension/modules/' . $packs['to_module']. '/Ext/Language'; + if($packs['to_module'] == 'application'){ + $path ='custom/Extension/' . $packs['to_module']. '/Ext/Language'; + } + if (sugar_is_file($path.'/'.$packs['language'].'.'. $this->id_name . '.php', 'w')) { + rmdir_recursive( $path.'/'.$packs['language'].'.'. $this->id_name . '.php'); + } else if (sugar_is_file($path.'/'.DISABLED_PATH.'/'.$packs['language'].'.'. $this->id_name . '.php', 'w')) { + rmdir_recursive($path.'/'.DISABLED_PATH.'/'.$packs['language'].'.'. $this->id_name . '.php', 'w'); + } + } + $this->rebuild_languages($languages, $modules); + + } + } + + // Functions for adding and removing logic hooks from uploaded files + // Since one class/file can be used by multiple logic hooks, I'm not going to touch the file labeled in the logic_hook entry + /* The module hook definition should look like this: + $installdefs = array( + ... blah blah ... + 'logic_hooks' => array( + array('module' => 'Accounts', + 'hook' => 'after_save', + 'order' => 99, + 'description' => 'Account sample logic hook', + 'file' => 'modules/Sample/sample_account_logic_hook_file.php', + 'class' => 'SampleLogicClass', + 'function' => 'accountAfterSave', + ), + ), + ... blah blah ... + ); + */ + function install_logichooks() { + // Since the logic hook files get copied over with the rest of the module directory, we just need to enable them + $this->enable_logichooks(); + } + + function uninstall_logichooks() { + // Since the logic hook files get removed with the rest of the module directory, we just need to disable them + $this->disable_logichooks(); + } + + function enable_logichooks() { + if(empty($this->installdefs['logic_hooks']) || !is_array($this->installdefs['logic_hooks'])) { + return; + } + + + + foreach($this->installdefs['logic_hooks'] as $hook ) { + check_logic_hook_file($hook['module'], $hook['hook'], array($hook['order'], $hook['description'], $hook['file'], $hook['class'], $hook['function'])); + } + } + + function disable_logichooks() { + if(empty($this->installdefs['logic_hooks']) || !is_array($this->installdefs['logic_hooks'])) { + return; + } + + + foreach($this->installdefs['logic_hooks'] as $hook ) { + remove_logic_hook($hook['module'], $hook['hook'], array($hook['order'], $hook['description'], $hook['file'], $hook['class'], $hook['function'])); + } + } + +/* BEGIN - RESTORE POINT - by MR. MILK August 31, 2005 02:22:18 PM */ + function copy_path($from, $to, $backup_path='', $uninstall=false){ + //function copy_path($from, $to){ +/* END - RESTORE POINT - by MR. MILK August 31, 2005 02:22:18 PM */ + $to = str_replace('', $this->base_dir, $to); + + if(!$uninstall) { + $from = str_replace('', $this->base_dir, $from); + $GLOBALS['log']->debug('Copy ' . $from); + } + else { + $from = str_replace('', $backup_path, $from); + //$GLOBALS['log']->debug('Restore ' . $from); + } + $from = clean_path($from); + $to = clean_path($to); + + $dir = dirname($to); + //there are cases where if we need to create a directory in the root directory + if($dir == '.' && is_dir($from)){ + $dir = $to; + } + if(!sugar_is_dir($dir, 'instance')) + mkdir_recursive($dir, true); +/* BEGIN - RESTORE POINT - by MR. MILK August 31, 2005 02:22:18 PM */ + if(empty($backup_path)) { +/* END - RESTORE POINT - by MR. MILK August 31, 2005 02:22:18 PM */ + if(!copy_recursive($from, $to)){ + die('Failed to copy ' . $from. ' ' . $to); + } +/* BEGIN - RESTORE POINT - by MR. MILK August 31, 2005 02:22:18 PM */ + } + elseif(!$this->copy_recursive_with_backup($from, $to, $backup_path, $uninstall)){ + die('Failed to copy ' . $from. ' to ' . $to); + } +/* END - RESTORE POINT - by MR. MILK August 31, 2005 02:22:18 PM */ + } + + function install_custom_fields($fields){ + global $beanList, $beanFiles; + include('include/modules.php'); + require_once('modules/DynamicFields/FieldCases.php'); + foreach($fields as $field){ + $installed = false; + if(isset($beanList[ $field['module']])){ + $class = $beanList[ $field['module']]; + if(!isset($field['ext4']))$field['ext4'] = ''; + if(!isset($field['mass_update']))$field['mass_update'] = 0; + if(!isset($field['duplicate_merge']))$field['duplicate_merge'] = 0; + if(!isset($field['help']))$field['help'] = ''; + + if(file_exists($beanFiles[$class])){ + require_once($beanFiles[$class]); + $mod = new $class(); + $installed = true; + $fieldObject = get_widget($field['type']); + $fieldObject->populateFromRow($field); + $mod->custom_fields->use_existing_labels = true; + $mod->custom_fields->addFieldObject($fieldObject); + } + } + if(!$installed){ + $GLOBALS['log']->debug('Could not install custom field ' . $field['name'] . ' for module ' . $field['module'] . ': Module does not exist'); + } + } + } + + function uninstall_custom_fields($fields){ + global $beanList, $beanFiles; + require_once('modules/DynamicFields/DynamicField.php'); + $dyField = new DynamicField(); + + foreach($fields as $field){ + $class = $beanList[ $field['module']]; + if(file_exists($beanFiles[$class])){ + require_once($beanFiles[$class]); + $mod = new $class(); + $dyField->bean = $mod; + $dyField->module = $field['module']; + $dyField->deleteField($field['name']); + } + } + } + + /* + * ModuleInstaller->install_relationships calls install_relationship for every file included in the module package that defines a relationship, and then + * writes a custom/Extension/application/Ext/TableDictionary/$module.php file containing an include_once for every relationship metadata file passed to install_relationship. + * Next it calls install_vardef and install_layoutdef. Finally, it rebuilds the vardefs and layoutdefs (by calling merge_files as usual), and then calls merge_files to merge + * everything in 'Ext/TableDictionary/' into 'tabledictionary.ext.php' + */ + function install_relationships () + { + if (isset ( $this->installdefs [ 'relationships' ] )) + { + $this->log ( translate ( 'LBL_MI_IN_RELATIONSHIPS' ) ) ; + $str = "installdefs [ 'relationships' ] as $key => $relationship ) + { + $filename = basename ( $relationship [ 'meta_data' ] ) ; + $this->copy_path ( $relationship [ 'meta_data' ], 'custom/metadata/' . $filename ) ; + $this->install_relationship ( 'custom/metadata/' . $filename ) ; + $save_table_dictionary = true ; + + if (! empty ( $relationship [ 'module_vardefs' ] )) + { + $relationship [ 'module_vardefs' ] = str_replace ( '', $this->base_dir, $relationship [ 'module_vardefs' ] ) ; + $this->install_vardef ( $relationship [ 'module_vardefs' ], $relationship [ 'module' ] ) ; + } + + if (! empty ( $relationship [ 'module_layoutdefs' ] )) + { + $relationship [ 'module_layoutdefs' ] = str_replace ( '', $this->base_dir, $relationship [ 'module_layoutdefs' ] ) ; + $this->install_layoutdef ( $relationship [ 'module_layoutdefs' ], $relationship [ 'module' ] ) ; + } + + $relName = strpos($filename, "MetaData") !== false ? substr($filename, 0, strlen($filename) - 12) : $filename; + $out = sugar_fopen ( "custom/Extension/application/Ext/TableDictionary/$relName.php", 'w' ) ; + fwrite ( $out, $str . "include('custom/metadata/$filename');\n\n?>" ) ; + fclose ( $out ) ; + } + + + + $this->rebuild_vardefs () ; + $this->rebuild_layoutdefs () ; + if ($save_table_dictionary) + { + $this->rebuild_tabledictionary () ; + } + + } + } + + /* + * Install_relationship obtains a set of relationship definitions from the filename passed in as a parameter. + * For each definition it calls db->createTableParams to build the relationships table if it does not exist, + * and SugarBean::createRelationshipMeta to add the relationship into the 'relationships' table. + */ + function install_relationship($file) + { + $_REQUEST['moduleInstaller'] = true; + if(!file_exists($file)) + { + $GLOBALS['log']->debug( 'File does not exists : '.$file); + return; + } + include($file); + $rel_dictionary = $dictionary; + foreach ($rel_dictionary as $rel_name => $rel_data) + { + $table = ''; // table is actually optional + // check if we have a table definition - not all relationships require a join table + if ( isset( $rel_data[ 'table' ] ) ) + { + $table = $rel_data[ 'table' ]; + + if(!$this->db->tableExists($table)) + { + $this->db->createTableParams($table, $rel_data[ 'fields' ], $rel_data[ 'indices' ]); + } + } + + if(!$this->silent) + $GLOBALS['log']->debug("Processing relationship meta for ". $rel_name."..."); + SugarBean::createRelationshipMeta($rel_name, $this->db,$table,$rel_dictionary,''); + Relationship::delete_cache(); + if(!$this->silent) + $GLOBALS['log']->debug( 'done
'); + } + } + + function install_layoutfields() { + if (!empty ( $this->installdefs [ 'layoutfields' ] )) + { + foreach ( $this->installdefs [ 'layoutfields' ] as $fieldSet ) + { + if (!empty($fieldSet['additional_fields'])) + { + $this->addFieldsToLayout($fieldSet['additional_fields']); + } + } + } + } + + function uninstall_layoutfields() { + if (!empty ( $this->installdefs [ 'layoutfields' ] )) + { + foreach ( $this->installdefs [ 'layoutfields' ] as $fieldSet ) + { + if (!empty($fieldSet['additional_fields'])) + { + $this->removeFieldsFromLayout($fieldSet['additional_fields']); + } + } + } + } + + function uninstall_relationship($file, $rel_dictionary = null){ + if ($rel_dictionary == null) + { + if(!file_exists($file)){ + $GLOBALS['log']->debug( 'File does not exists : '.$file); + return; + } + include($file); + $rel_dictionary = $dictionary; + } + + foreach ($rel_dictionary as $rel_name => $rel_data) + { + if (!empty($rel_data['table'])){ + $table = $rel_data['table']; + } + else{ + $table = ' One-to-Many '; + } + + if ($this->db->tableExists($table) && isset($GLOBALS['mi_remove_tables']) && $GLOBALS['mi_remove_tables']) + { + SugarBean::removeRelationshipMeta($rel_name, $this->db,$table,$rel_dictionary,''); + $this->db->dropTableName($table); + if(!$this->silent) $this->log( translate('LBL_MI_UN_RELATIONSHIPS_DROP') . $table); + } + + //Delete Layout defs + // check to see if we have any vardef or layoutdef entries to remove - must have a relationship['module'] parameter if we do + if (!isset($rel_data[ 'module' ])) + $mods = array( + $rel_data['relationships'][$rel_name]['lhs_module'], + $rel_data['relationships'][$rel_name]['rhs_module'], + ); + else + $mods = array($rel_data[ 'module' ]); + + $filename = "$rel_name.php"; + + foreach($mods as $mod) { + if ($mod != 'application' ) { + $basepath = "custom/Extension/modules/$mod/Ext/"; + } else { + $basepath = "custom/Extension/application/Ext/"; + } + + foreach (array($filename , "custom" . $filename) as $fn) { + //remove any vardefs + $path = $basepath . "Vardefs/$fn" ; + if (file_exists( $path )) + rmdir_recursive( $path ); + + //remove any layoutdefs + $path = $basepath . "Layoutdefs/$fn" ; + if( file_exists( $path )) + { + rmdir_recursive( $path ); + } + } + } + + foreach (array($filename , "custom" . $filename) as $fn) { + // remove the table dictionary extension + if ( file_exists("custom/Extension/application/Ext/TableDictionary/$fn")) + unlink("custom/Extension/application/Ext/TableDictionary/$fn"); + + if (file_exists("custom/metadata/{$rel_name}MetaData.php")) + unlink( "custom/metadata/{$rel_name}MetaData.php" ); + } + } + } + + function uninstall_relationships($include_studio_relationships = false){ + $relationships = array(); + + //Find and remove studio created relationships. + global $beanList, $beanFiles, $dictionary; + //Load up the custom relationship definitions. + if(file_exists('custom/application/Ext/TableDictionary/tabledictionary.ext.php')){ + include('custom/application/Ext/TableDictionary/tabledictionary.ext.php'); + } + //Find all the relatioships/relate fields involving this module. + $rels_to_remove = array(); + foreach($beanList as $mod => $bean) { + VardefManager::loadVardef($mod, $bean); + //We can skip modules that are in this package as they will be removed anyhow + if (!in_array($mod, $this->modulesInPackage) && !empty($dictionary[$bean]) && !empty($dictionary[$bean]['fields'])) + { + $field_defs = $dictionary[$bean]['fields']; + foreach($field_defs as $field => $def) + { + //Weed out most fields first + if (isset ($def['type'])) + { + //Custom relationships created in the relationship editor + if ($def['type'] == "link" && !empty($def['relationship']) && !empty($dictionary[$def['relationship']])) + { + $rel_name = $def['relationship']; + + $rel_def = $dictionary[$rel_name]['relationships'][$rel_name]; + + //Check against mods to be removed. + foreach($this->modulesInPackage as $removed_mod) { + if ($rel_def['lhs_module'] == $removed_mod || $rel_def['rhs_module'] == $removed_mod ) + { + $dictionary[$rel_name]['from_studio'] = true; + $relationships[$rel_name] = $dictionary[$rel_name]; + } + } + } + //Custom "relate" fields created in studio also need to be removed + if ($def['type'] == 'relate' && isset($def['module'])) { + foreach($this->modulesInPackage as $removed_mod) { + if ($def['module'] == $removed_mod) + { + require_once 'modules/ModuleBuilder/Module/StudioModule.php' ; + $studioMod = new StudioModule ( $mod ); + $studioMod->removeFieldFromLayouts( $field ); + if (isset($def['custom_module'])) { + require_once ('modules/DynamicFields/DynamicField.php') ; + require_once ($beanFiles [ $bean ]) ; + $seed = new $bean ( ) ; + $df = new DynamicField ( $mod ) ; + $df->setup ( $seed ) ; + //Need to load the entire field_meta_data for some field types + $field_obj = $df->getFieldWidget($mod, $field); + $field_obj->delete ( $df ) ; + } + } + } + } + } + } + } + } + + + + $this->uninstall_relationship(null, $relationships); + + if(isset($this->installdefs['relationships'])) { + $relationships = $this->installdefs['relationships']; + $this->log(translate('LBL_MI_UN_RELATIONSHIPS') ); + foreach($relationships as $relationship) + { + // remove the metadata entry + $filename = basename ( $relationship['meta_data'] ); + $pathname = (file_exists("custom/metadata/$filename")) ? "custom/metadata/$filename" : "metadata/$filename" ; + if(isset($GLOBALS['mi_remove_tables']) && $GLOBALS['mi_remove_tables']) + $this->uninstall_relationship( $pathname ); + if (file_exists($pathname)) + unlink( $pathname ); + } + } + + if (file_exists("custom/Extension/application/Ext/TableDictionary/{$this->id_name}.php")) + unlink("custom/Extension/application/Ext/TableDictionary/{$this->id_name}.php"); + Relationship::delete_cache(); + $this->rebuild_tabledictionary(); + } + + + + + function uninstall($base_dir){ + if(defined('TEMPLATE_URL'))SugarTemplateUtilities::disableCache(); + global $app_strings; + $total_steps = 5; //min steps with no tasks + $current_step = 0; + $this->base_dir = $base_dir; + $tasks = array( + 'pre_uninstall', + 'uninstall_relationships', + 'uninstall_copy', + 'uninstall_dcactions', + 'uninstall_menus', + 'uninstall_dashlets', + 'uninstall_userpage', + 'uninstall_administration', + 'uninstall_connectors', + 'uninstall_vardefs', + 'uninstall_layoutdefs', + 'uninstall_layoutfields', + 'uninstall_languages', + 'uninstall_logichooks', + 'post_uninstall', + ); + $total_steps += count($tasks); //now the real number of steps + if(file_exists($this->base_dir . '/manifest.php')){ + if(!$this->silent){ + $current_step++; + display_progress_bar('install', $current_step, $total_steps); + echo ''; + } + //since we are passing $silent = true to rebuildAll() in that method it will set $this->silent = true, so + //we need to save the setting to set it back after rebuildAll() completes. + $silentBak = $this->silent; + $this->rebuild_all(true); + $this->silent = $silentBak; + + //#27877, If the request from MB redeploy a custom module , we will not remove the ACL actions for this package. + if( !isset($_REQUEST['action']) || $_REQUEST['action']!='DeployPackage' ){ + $this->remove_acl_actions(); + } + //end + + if(!$this->silent){ + $current_step++; + update_progress_bar('install', $current_step, $total_steps); + echo ''; + } + + UpdateSystemTabs('Restore',$installed_modules); + + //clear the unified_search_module.php file + require_once('modules/Home/UnifiedSearchAdvanced.php'); + UnifiedSearchAdvanced::unlinkUnifiedSearchModulesFile(); + + $this->log('
' . translate('LBL_MI_COMPLETE') . ''); + if(!$this->silent){ + update_progress_bar('install', $total_steps, $total_steps); + } + }else{ + die("No manifest.php Defined In $this->base_dir/manifest.php"); + } + } + + function rebuild_languages($languages, $modules=""){ + foreach($languages as $language=>$value){ + $this->log(translate('LBL_MI_REBUILDING') . " Language...$language"); + $this->merge_files('Ext/Language/', $language.'.lang.ext.php', $language); + if($modules!=""){ + foreach($modules as $module){ + LanguageManager::clearLanguageCache($module, $language); + } + } + } + sugar_cache_reset(); + + } + + function rebuild_vardefs(){ + $this->log(translate('LBL_MI_REBUILDING') . " Vardefs..."); + $this->merge_files('Ext/Vardefs/', 'vardefs.ext.php'); + sugar_cache_reset(); + } + + function rebuild_layoutdefs(){ + $this->log(translate('LBL_MI_REBUILDING') . " Layoutdefs..."); + $this->merge_files('Ext/Layoutdefs/', 'layoutdefs.ext.php'); + + } + + function rebuild_menus(){ + $this->log(translate('LBL_MI_REBUILDING') . " Menus..."); + $this->merge_files('Ext/Menus/', 'menu.ext.php'); + } + + function rebuild_dashletcontainers(){ + $this->log(translate('LBL_MI_REBUILDING') . " DC Actions..."); + $this->merge_files('Ext/DashletContainer/Containers/', 'dcactions.ext.php'); + } + + function rebuild_modules(){ + $this->log(translate('LBL_MI_REBUILDING') . " Modules..."); + $this->merge_files('Ext/Include/', 'modules.ext.php', '', true); + } + + function rebuild_administration(){ + $this->log(translate('LBL_MI_REBUILDING') . " administration " . translate('LBL_MI_SECTION')); + $this->merge_files('Ext/Administration/', 'administration.ext.php'); + } + function rebuild_userpage(){ + $this->log(translate('LBL_MI_REBUILDING') . " User Page " . translate('LBL_MI_SECTION')); + $this->merge_files('Ext/UserPage/', 'userpage.ext.php'); + } + function rebuild_tabledictionary(){ + $this->log(translate('LBL_MI_REBUILDING') . " administration " . translate('LBL_MI_SECTION')); + $this->merge_files('Ext/TableDictionary/', 'tabledictionary.ext.php'); + } + + function rebuild_relationships() { + if(!$this->silent) echo translate('LBL_MI_REBUILDING') . ' Relationships'; + $_REQUEST['silent'] = true; + global $beanFiles; + include('include/modules.php'); + include("modules/Administration/RebuildRelationship.php"); + } + + function remove_acl_actions() { + global $beanFiles, $beanList, $current_user; + include('include/modules.php'); + include("modules/ACL/remove_actions.php"); + } + + /** + * Wrapper call to modules/Administration/RepairIndex.php + */ + function repair_indices() { + global $current_user,$beanFiles,$dictionary; + $this->log(translate('LBL_MI_REPAIR_INDICES')); + $_REQUEST['silent'] = true; // local var flagging echo'd output in repair script + $_REQUEST['mode'] = 'execute'; // flag to just go ahead and run the script + include("modules/Administration/RepairIndex.php"); + } + + /** + * Rebuilds the extension files found in custom/Extension + * @param boolean $silent + */ + function rebuild_all($silent=false){ + if(defined('TEMPLATE_URL'))SugarTemplateUtilities::disableCache(); + $this->silent=$silent; + global $sugar_config; + + //Check for new module extensions + $this->rebuild_modules(); + + $this->rebuild_languages($sugar_config['languages']); + $this->rebuild_vardefs(); + $this->rebuild_layoutdefs(); + $this->rebuild_menus(); + $this->rebuild_dashletcontainers(); + $this->rebuild_userpage(); + $this->rebuild_administration(); + $this->rebuild_relationships(); + $this->rebuild_tabledictionary(); + //$this->repair_indices(); + $this->reset_opcodes(); + sugar_cache_reset(); + } + + /* + * ModuleInstaller->merge_files runs over the list of all modules already installed in /modules. For each $module it reads the contents of every file in + * custom/Extension/modules/$module/ (_override files last) and concatenates them to custom/modules/$module//. + * Then it does the same thing in custom/Extension/application/, concatenating those files and copying the result to custom/application// + */ + function merge_files($path, $name, $filter = '', $application = false){ + if(!$application){ + $GLOBALS['log']->debug( get_class($this)."->merge_files() : merging module files in custom/Extension/modules//$path to custom/modules//$path$name"); + foreach($this->modules as $module){ + //$GLOBALS['log']->debug("Merging Files for: ".$module); + //$GLOBALS['log']->debug("Merging Files for path: ".$path); + $extension = "read()){ + if((empty($filter) || substr_count($entry, $filter) > 0) && is_file($module_install.'/'.$entry) + && $entry != '.' && $entry != '..' && strtolower(substr($entry, -4)) == ".php") + { + if (substr($entry, 0, 9) == '_override') { + $override[] = $entry; + } else { + $file = file_get_contents($module_install . '/' . $entry); + $GLOBALS['log']->debug(get_class($this)."->merge_files(): found {$module_install}{$entry}") ; + $extension .= "\n". str_replace(array('', '', '"; + + if($shouldSave){ + if(!file_exists("custom/$extpath")){ + mkdir_recursive("custom/$extpath", true); + } + $out = sugar_fopen("custom/$extpath/$name", 'w'); + fwrite($out,$extension); + fclose($out); + }else{ + if(file_exists("custom/$extpath/$name")){ + unlink("custom/$extpath/$name"); + } + } + } + + } + + $GLOBALS['log']->debug("Merging application files for $name in $path"); + //Now the application stuff + $extension = "read()){ + $shouldSave = true; + if((empty($filter) || substr_count($entry, $filter) > 0) && is_file($module_install.'/'.$entry) + && $entry != '.' && $entry != '..' && strtolower(substr($entry, -4)) == ".php") + { + $file = file_get_contents($module_install . '/' . $entry); + $extension .= "\n". str_replace(array('', '"; + if($shouldSave){ + if(!file_exists("custom/$extpath")){ + mkdir_recursive("custom/$extpath", true); + } + $out = sugar_fopen("custom/$extpath/$name", 'w'); + fwrite($out,$extension); + fclose($out); + }else{ + if(file_exists("custom/$extpath/$name")){ + unlink("custom/$extpath/$name"); + } + } + +} + + /* + * ModuleInstaller->install_beans runs through the list of beans given, instantiates each bean, calls bean->create_tables, and then calls SugarBean::createRelationshipMeta for the + * bean/module. + */ + function install_beans($beans){ + include('include/modules.php'); + foreach($beans as $bean){ + $this->log( translate('LBL_MI_IN_BEAN') . " $bean"); + if(isset($beanList[$bean])){ + $class = $beanList[$bean]; + if(file_exists($beanFiles[$class])){ + require_once($beanFiles[$class]); + $mod = new $class(); + //#30273 + if(is_subclass_of($mod, 'SugarBean') && $mod->disable_vardefs == false ){ + $GLOBALS['log']->debug( "Creating Tables Bean : $bean"); + $mod->create_tables(); + SugarBean::createRelationshipMeta($mod->getObjectName(), $mod->db,$mod->table_name,'',$mod->module_dir); + } + }else{ + $GLOBALS['log']->debug( "File Does Not Exist:" . $beanFiles[$class] ); + } + } + } + } + + function uninstall_beans($beans){ + include('include/modules.php'); + foreach($beans as $bean){ + $this->log( translate('LBL_MI_UN_BEAN') . " $bean"); + if(isset($beanList[$bean])){ + $class = $beanList[$bean]; + + if(file_exists($beanFiles[$class])){ + require_once($beanFiles[$class]); + $mod = new $class(); + + if(is_subclass_of($mod, 'SugarBean')){ + $GLOBALS['log']->debug( "Drop Tables : $bean"); + if(isset($GLOBALS['mi_remove_tables']) && $GLOBALS['mi_remove_tables']) + $mod->drop_tables(); + } + }else{ + $GLOBALS['log']->debug( "File Does Not Exist:" . $beanFiles[$class] ); + } + } + } + } + + /** + * Remove any customizations made within Studio while the module was installed. + */ + function uninstall_customizations($beans){ + foreach($beans as $bean){ + $dirs = array( + 'custom/modules/' . $bean, + 'custom/Extension/modules/' . $bean + ); + foreach($dirs as $dir) + { + if(is_dir($dir)){ + rmdir_recursive($dir); + } + } + } + } + + function log($str){ + $GLOBALS['log']->debug('ModuleInstaller:'. $str); + if(!$this->silent){ + echo $str . '
'; + } + } + +/* BEGIN - RESTORE POINT - by MR. MILK August 31, 2005 02:15:18 PM */ +function copy_recursive_with_backup( $source, $dest, $backup_path, $uninstall=false ) { + if(is_file($source)) { + if($uninstall) { + $GLOBALS['log']->debug("Restoring ... " . $source. " to " .$dest ); + if(copy( $source, $dest)) { + if(is_writable($dest)) + sugar_touch( $dest, filemtime($source) ); + return(unlink($source)); + } + else { + $GLOBALS['log']->debug( "Can't restore file: " . $source ); + return true; + } + } + else { + if(file_exists($dest)) { + $rest = clean_path($backup_path."/$dest"); + if( !is_dir(dirname($rest)) ) + mkdir_recursive(dirname($rest), true); + + $GLOBALS['log']->debug("Backup ... " . $dest. " to " .$rest ); + if(copy( $dest, $rest)) { + if(is_writable($rest)) + sugar_touch( $rest, filemtime($dest) ); + } + else { + $GLOBALS['log']->debug( "Can't backup file: " . $dest ); + } + } + return( copy( $source, $dest ) ); + } + } + elseif(!is_dir($source)) { + if($uninstall) { + if(is_file($dest)) + return(unlink($dest)); + else { + //don't do anything we already cleaned up the files using uninstall_new_files + return true; + } + } + else + return false; + } + + if( !is_dir($dest) && !$uninstall){ + sugar_mkdir( $dest ); + } + + $status = true; + + $d = dir( $source ); + while( $f = $d->read() ){ + if( $f == "." || $f == ".." ){ + continue; + } + $status &= $this->copy_recursive_with_backup( "$source/$f", "$dest/$f", $backup_path, $uninstall ); + } + $d->close(); + return( $status ); +} + +private function dir_get_files($path, $base_path){ + $files = array(); + if(!is_dir($path))return $files; + $d = dir($path); + while ($e = $d->read()){ + //ignore invisible files . .. ._MACOSX + if(substr($e, 0, 1) == '.')continue; + if(is_file($path . '/' . $e))$files[str_replace($base_path , '', $path . '/' . $e)] = str_replace($base_path , '', $path . '/' . $e); + if(is_dir($path . '/' . $e))$files = array_merge($files, $this->dir_get_files($path . '/' . $e, $base_path)); + } + $d->close(); + return $files; + +} + +private function dir_file_count($path){ + //if its a file then it has at least 1 file in the directory + if(is_file($path)) return 1; + if(!is_dir($path)) return 0; + $d = dir($path); + $count = 0; + while ($e = $d->read()){ + //ignore invisible files . .. ._MACOSX + if(substr($e, 0, 1) == '.')continue; + if(is_file($path . '/' . $e))$count++; + if(is_dir($path . '/' . $e))$count += $this->dir_file_count($path . '/' . $e); + } + $d->close(); + return $count; + + +} +/* END - RESTORE POINT - by MR. MILK August 31, 2005 02:15:34 PM */ + + + /** + * Static function which allows a module developer to abort their progress, pass in an array of errors and + * redirect back to the main module loader page + * + * @param errors an array of error messages which will be displayed on the + * main module loader page once it is loaded. + */ + function abort($errors = array()){ + //set the errors onto the session so we can display them one the moduler loader page loads + $_SESSION['MODULEINSTALLER_ERRORS'] = $errors; + echo ''; + die(); + //header('Location: index.php?module=Administration&action=UpgradeWizard&view=module'); + } + + /** + * Return the set of errors stored in the SESSION + * + * @return an array of errors + */ + function getErrors(){ + if(!empty($_SESSION['MODULEINSTALLER_ERRORS'])){ + $errors = $_SESSION['MODULEINSTALLER_ERRORS']; + unset($_SESSION['MODULEINSTALLER_ERRORS']); + return $errors; + } + else + return null; + } + + /* + * Add any fields to the DetailView and EditView of the appropriate modules + * Only add into deployed modules, as addFieldsToUndeployedLayouts has done this already for undeployed modules (and the admin might have edited the layouts already) + * @param array $layoutAdditions An array of module => fieldname + * return null + */ + function addFieldsToLayout($layoutAdditions) { + require_once 'modules/ModuleBuilder/parsers/views/GridLayoutMetaDataParser.php' ; + + // these modules either lack editviews/detailviews or use custom mechanisms for the editview/detailview. + // In either case, we don't want to attempt to add a relate field to them + // would be better if GridLayoutMetaDataParser could handle this gracefully, so we don't have to maintain this list here + $invalidModules = array ( 'emails' , 'kbdocuments' ) ; + + foreach ( $layoutAdditions as $deployedModuleName => $fieldName ) + { + if ( ! in_array( strtolower ( $deployedModuleName ) , $invalidModules ) ) + { + foreach ( array ( MB_EDITVIEW , MB_DETAILVIEW ) as $view ) + { + $GLOBALS [ 'log' ]->debug ( get_class ( $this ) . ": adding $fieldName to $view layout for module $deployedModuleName" ) ; + $parser = new GridLayoutMetaDataParser ( $view, $deployedModuleName ) ; + $parser->addField ( array ( 'name' => $fieldName ) ) ; + $parser->handleSave ( false ) ; + } + } + } + + } + + function removeFieldsFromLayout($layoutAdditions) { + require_once 'modules/ModuleBuilder/parsers/views/GridLayoutMetaDataParser.php' ; + + // these modules either lack editviews/detailviews or use custom mechanisms for the editview/detailview. + // In either case, we don't want to attempt to add a relate field to them + // would be better if GridLayoutMetaDataParser could handle this gracefully, so we don't have to maintain this list here + $invalidModules = array ( 'emails' , 'kbdocuments' ) ; + + foreach ( $layoutAdditions as $deployedModuleName => $fieldName ) + { + if ( ! in_array( strtolower ( $deployedModuleName ) , $invalidModules ) ) + { + foreach ( array ( MB_EDITVIEW , MB_DETAILVIEW ) as $view ) + { + $GLOBALS [ 'log' ]->debug ( get_class ( $this ) . ": adding $fieldName to $view layout for module $deployedModuleName" ) ; + $parser = new GridLayoutMetaDataParser ( $view, $deployedModuleName ) ; + $parser->removeField ( $fieldName ) ; + $parser->handleSave ( false ) ; + } + } + } + + } + + /////////////////// + //********** DISABLE/ENABLE FUNCTIONS + /////////////////// + function enable($base_dir, $is_upgrade = false, $previous_version = ''){ + global $app_strings; + $this->base_dir = $base_dir; + $total_steps = 3; //minimum number of steps with no tasks + $current_step = 0; + $tasks = array( + 'enable_copy', + 'enable_menus', + 'enable_userpage', + 'enable_dashlets', + 'enable_administration', + 'enable_vardefs', + 'enable_layoutdefs', + 'enable_relationships', + 'enable_languages', + 'enable_logichooks', + 'reset_opcodes', + ); + $total_steps += count($tasks); + if(file_exists($this->base_dir . '/manifest.php')){ + if(!$this->silent){ + $current_step++; + display_progress_bar('install', $current_step, $total_steps); + echo ''; + } + UpdateSystemTabs('Add',$installed_modules); + $GLOBALS['log']->debug('Complete'); + + }else{ + die("No \$installdefs Defined In $this->base_dir/manifest.php"); + } + + } + function disable($base_dir){ + global $app_strings; + $total_steps = 3; //min steps with no tasks + $current_step = 0; + $this->base_dir = $base_dir; + $tasks = array( + 'disable_copy', + 'disable_menus', + 'disable_dashlets', + 'disable_userpage', + 'disable_administration', + 'disable_vardefs', + 'disable_layoutdefs', + 'disable_relationships', + 'disable_languages', + 'disable_logichooks', + 'reset_opcodes', + ); + $total_steps += count($tasks); //now the real number of steps + if(file_exists($this->base_dir . '/manifest.php')){ + if(!$this->silent){ + $current_step++; + display_progress_bar('install', $current_step, $total_steps); + echo ''; + } + UpdateSystemTabs('Restore',$installed_modules); + + }else{ + die("No manifest.php Defined In $this->base_dir/manifest.php"); + } + } + function enable_vardef($to_module){ + if(isset($this->installdefs['vardefs'])){ + foreach($this->installdefs['vardefs'] as $vardefs){ + $GLOBALS['log']->debug("Enabling Vardefs ..." .$to_module); + $path = 'custom/Extension/modules/' . $to_module. '/Ext/Vardefs'; + if($to_module == 'application'){ + $path ='custom/Extension/' . $to_module. '/Ext/Vardefs'; + } + if(!file_exists($path)){ + mkdir_recursive($path, true); + } + if (file_exists($path . '/'.DISABLED_PATH.'/'. $this->id_name . '.php')) + rename($path . '/'.DISABLED_PATH.'/'. $this->id_name . '.php', $path . '/'. $this->id_name . '.php'); + if (file_exists($path . '/'.DISABLED_PATH.'/'. basename($vardefs['from']))) + rename($path . '/'.DISABLED_PATH.'/'. basename($vardefs['from']), $path . '/'. basename($vardefs['from'])); + } + } + } + function enable_vardefs(){ + if(isset($this->installdefs['vardefs'])){ + foreach($this->installdefs['vardefs'] as $vardefs){ + $vardefs['from'] = str_replace('', $this->base_dir, $vardefs['from']); + $GLOBALS['log']->debug("Enabling Vardefs ..." . $vardefs['from'] . " for " .$vardefs['to_module']); + $path = 'custom/Extension/modules/' . $vardefs['to_module']. '/Ext/Vardefs'; + if($vardefs['to_module'] == 'application'){ + $path ='custom/Extension/' . $vardefs['to_module']. '/Ext/Vardefs'; + } + if(file_exists($path . '/'.DISABLED_PATH.'/'. $this->id_name . '.php')) + rename( $path . '/'.DISABLED_PATH.'/'. $this->id_name . '.php', $path . '/'. $this->id_name . '.php'); + + if (file_exists($path . '/'.DISABLED_PATH.'/'. basename($vardefs['from']))) + rename($path . '/'.DISABLED_PATH.'/'. basename($vardefs['from']), $path . '/'. basename($vardefs['from'])); + + } + $this->rebuild_vardefs(); + } + } + function disable_vardefs(){ + $GLOBALS['log']->debug("Disabling Vardefs ".var_export($this->installdefs, true)); + if(isset($this->installdefs['vardefs'])){ + foreach($this->installdefs['vardefs'] as $vardefs){ + $vardefs['from'] = str_replace('', $this->base_dir, $vardefs['from']); + $GLOBALS['log']->debug("Disabling Vardefs ..." . $vardefs['from'] . " for " .$vardefs['to_module']); + $path = 'custom/Extension/modules/' . $vardefs['to_module']. '/Ext/Vardefs'; + if($vardefs['to_module'] == 'application'){ + $path ='custom/Extension/' . $vardefs['to_module']. '/Ext/Vardefs'; + } + if(file_exists($path . '/'. $this->id_name . '.php')) { + mkdir_recursive($path . '/'.DISABLED_PATH, true); + rename( $path . '/'. $this->id_name . '.php', $path . '/'.DISABLED_PATH.'/'. $this->id_name . '.php'); + } + if(file_exists($path . '/'. basename($vardefs['from']))) + { + mkdir_recursive($path . '/'.DISABLED_PATH, true); + rename( $path . '/'. basename($vardefs['from']), $path . '/'.DISABLED_PATH.'/'.basename($vardefs['from'])); + } + } + $this->rebuild_vardefs(); + } + } + + function enable_relationships(){ + if(isset($this->installdefs['relationships'])){ + $str = "installdefs['relationships'] as $relationship){ + $filename =basename($relationship['meta_data']); + + $save_table_dictionary = true; + $str .= "include_once('metadata/$filename');\n"; + if (empty($relationship['module'])) + continue; + + if(!empty($relationship['module_vardefs'])){ + $this->enable_vardef($relationship['module']); + } + if(!empty($relationship['module_layoutdefs'])){ + $this->enable_layoutdef($relationship['module']); + } + } + $this->rebuild_vardefs(); + $this->rebuild_layoutdefs(); + if($save_table_dictionary){ + if(!file_exists("custom/Extension/application/Ext/TableDictionary")){ + mkdir_recursive("custom/Extension/application/Ext/TableDictionary", true); + } + if (file_exists("custom/Extension/application/Ext/TableDictionary/".DISABLED_PATH."/$this->id_name.php")) + rename("custom/Extension/application/Ext/TableDictionary/".DISABLED_PATH."/$this->id_name.php", "custom/Extension/application/Ext/TableDictionary/$this->id_name.php"); + $this->rebuild_tabledictionary(); + } + } + } + + function disable_relationships($action = 'disable'){ + if(isset($this->installdefs['relationships'])){ + foreach($this->installdefs['relationships'] as $relationship){ + $filename = basename($relationship['meta_data']); + $relName = substr($filename, -12) == "MetaData.php" ? substr($filename,0,strlen($filename) - 12) : ""; + if (empty($relationship['module']) && empty($relName)) + continue; + + //remove the vardefs + if (empty($relName)) + $path = 'custom/Extension/modules/' . $relationship['module']. '/Ext/Vardefs'; + if(!empty($relationship['module']) && $relationship['module'] == 'application'){ + $path ='custom/Extension/' . $relationship['module']. '/Ext/Vardefs'; + } + if(!empty($relationship['module_vardefs']) && file_exists($path . '/'. $this->id_name . '.php')){ + mkdir_recursive($path . '/'.DISABLED_PATH, true); + rename( $path . '/'. $this->id_name . '.php', $path . '/'.DISABLED_PATH.'/'. $this->id_name . '.php'); + } + //remove the layoutdefs + if ( !empty($relationship['module']) ) { + $path = 'custom/Extension/modules/' . $relationship['module']. '/Ext/Layoutdefs'; + if($relationship['module'] == 'application'){ + $path ='custom/Extension/' . $relationship['module']. '/Ext/Layoutdefs'; + } + } + + if(!empty($relationship['module_layoutdefs']) && file_exists($path . '/'. $this->id_name . '.php')){ + mkdir_recursive($path . '/'.DISABLED_PATH, true); + rename( $path . '/'. $this->id_name . '.php', $path . '/'.DISABLED_PATH.'/'. $this->id_name . '.php'); + } + + } + if(file_exists("custom/Extension/application/Ext/TableDictionary/$this->id_name.php")){ + mkdir_recursive("custom/Extension/application/Ext/TableDictionary/".DISABLED_PATH, true); + rename("custom/Extension/application/Ext/TableDictionary/$this->id_name.php", "custom/Extension/application/Ext/TableDictionary/".DISABLED_PATH."/$this->id_name.php"); + } + $this->rebuild_tabledictionary(); + $this->rebuild_vardefs(); + $this->rebuild_layoutdefs(); + } + } + + function enable_layoutdefs(){ + if(isset($this->installdefs['layoutdefs'])){ + foreach($this->installdefs['layoutdefs'] as $layoutdefs){ + $this->enable_layoutdef($layoutdefs['to_module'], $this->id_name); + } + $this->rebuild_layoutdefs(); + } + } + function enable_layoutdef($to_module){ + $GLOBALS['log']->debug("Enabling Layout Defs ..." .$to_module); + if(isset($this->installdefs['layoutdefs'])){ + foreach($this->installdefs['layoutdefs'] as $layoutdefs){ + $path = 'custom/Extension/modules/' . $to_module. '/Ext/Layoutdefs'; + if($to_module == 'application'){ + $path ='custom/Extension/' . $to_module. '/Ext/Layoutdefs'; + } + if (file_exists($path . '/'.DISABLED_PATH.'/'. $this->id_name . '.php')) + { + rename($path . '/'.DISABLED_PATH.'/'. $this->id_name . '.php', $path . '/'. $this->id_name . '.php'); + } + if (file_exists($path . '/'.DISABLED_PATH.'/'. basename($layoutdefs['from']))) + { + rename($path . '/'.DISABLED_PATH.'/'. basename($layoutdefs['from']), $path . '/'. basename($layoutdefs['from'])); + } + } + } + } + + function disable_layoutdefs(){ + if(isset($this->installdefs['layoutdefs'])){ + foreach($this->installdefs['layoutdefs'] as $layoutdefs){ + $layoutdefs['from'] = str_replace('', $this->base_dir, $layoutdefs['from']); + $GLOBALS['log']->debug("Disabling Layoutdefs ..." . $layoutdefs['from'] . " for " .$layoutdefs['to_module']); + $path = 'custom/Extension/modules/' . $layoutdefs['to_module']. '/Ext/Layoutdefs'; + if($layoutdefs['to_module'] == 'application'){ + $path ='custom/Extension/' . $layoutdefs['to_module']. '/Ext/Layoutdefs'; + } + if (file_exists($path . '/'. $this->id_name . '.php')) + { + mkdir_recursive($path . '/'.DISABLED_PATH, true); + rename( $path . '/'. $this->id_name . '.php', $path . '/'.DISABLED_PATH.'/'. $this->id_name . '.php'); + }else if (file_exists($path . '/'. basename($layoutdefs['from']))) + { + mkdir_recursive($path . '/'.DISABLED_PATH, true); + rename( $path . '/'. basename($layoutdefs['from']), $path . '/'.DISABLED_PATH.'/'. basename($layoutdefs['from'])); + } + } + $this->rebuild_layoutdefs(); + } + } + + function enable_menus(){ + if(isset($this->installdefs['menu'])){ + foreach($this->installdefs['menu'] as $menu){ + $menu['from'] = str_replace('', $this->base_dir, $menu['from']); + $GLOBALS['log']->debug("Enabling Menu ..." . $menu['from']. " for " .$menu['to_module'] ); + $path = 'custom/Extension/modules/' . $menu['to_module']. '/Ext/Menus'; + if($menu['to_module'] == 'application'){ + $path ='custom/Extension/' . $menu['to_module']. '/Ext/Menus'; + } + + if(file_exists($path . '/'.DISABLED_PATH.'/'. $this->id_name . '.php')){ + rename($path . '/'.DISABLED_PATH.'/'. $this->id_name . '.php', $path . '/'. $this->id_name . '.php'); + } + + } + $this->rebuild_menus(); + } + + } + + function disable_menus(){ + if(isset($this->installdefs['menu'])){ + foreach($this->installdefs['menu'] as $menu){ + $menu['from'] = str_replace('', $this->base_dir, $menu['from']); + $GLOBALS['log']->debug("Disabling Menu ..." . $menu['from']. " for " .$menu['to_module'] ); + $path = 'custom/Extension/modules/' . $menu['to_module']. '/Ext/Menus'; + if($menu['to_module'] == 'application'){ + $path ='custom/Extension/' . $menu['to_module']. '/Ext/Menus'; + } + if (file_exists( $path . '/'. $this->id_name . '.php')) + { + mkdir_recursive($path . '/'.DISABLED_PATH, true); + rename( $path . '/'. $this->id_name . '.php', $path . '/'.DISABLED_PATH.'/'. $this->id_name . '.php'); + } + } + $this->rebuild_menus(); + } + } + + function enable_administration(){ + if(isset($this->installdefs['administration'])){ + foreach($this->installdefs['administration'] as $administration){ + $administration['from'] = str_replace('', $this->base_dir, $administration['from']); + $GLOBALS['log']->debug("Installing Administration Section ..." . $administration['from'] ); + $path = 'custom/Extension/modules/Administration/Ext/Administration'; + + if(file_exists($path . '/'.DISABLED_PATH.'/'. $this->id_name . '.php')){ + rename($path . '/'.DISABLED_PATH.'/'. $this->id_name . '.php', $path . '/'. $this->id_name . '.php'); + } + } + $this->rebuild_administration(); + } + + } + function disable_administration(){ + if(isset($this->installdefs['administration'])){ + foreach($this->installdefs['administration'] as $administration){ + $administration['from'] = str_replace('', $this->base_dir, $administration['from']); + $GLOBALS['log']->debug("Uninstalling Administration Section ..." . $administration['from'] ); + $path = 'custom/Extension/modules/Administration/Ext/Administration'; + if (file_exists($path . '/'. $this->id_name . '.php')) + { + mkdir_recursive($path . '/'.DISABLED_PATH, true); + rename( $path . '/'. $this->id_name . '.php', $path . '/'.DISABLED_PATH.'/'. $this->id_name . '.php'); + } + } + $this->rebuild_administration(); + } + } + + function enable_dashlets(){ + if(isset($this->installdefs['dashlets'])){ + foreach($this->installdefs['dashlets'] as $cp){ + $cp['from'] = str_replace('', $this->base_dir, $cp['from']); + $path = 'custom/modules/Home/Dashlets/' . $cp['name'] . '/'; + $disabled_path = 'custom/modules/Home/'.DISABLED_PATH.'Dashlets/' . $cp['name']; + $GLOBALS['log']->debug("Enabling Dashlet " . $cp['name'] . "..." . $cp['from'] ); + if (file_exists($disabled_path)) + { + rename($disabled_path, $path); + } + } + include('modules/Administration/RebuildDashlets.php'); + + } + } + + function disable_dashlets(){ + if(isset($this->installdefs['dashlets'])){ + foreach($this->installdefs['dashlets'] as $cp){ + $path = 'custom/modules/Home/Dashlets/' . $cp['name']; + $disabled_path = 'custom/modules/Home/'.DISABLED_PATH.'Dashlets/' . $cp['name']; + $GLOBALS['log']->debug('Disabling ' .$path); + if (file_exists($path)) + { + mkdir_recursive('custom/modules/Home/'.DISABLED_PATH.'Dashlets/', true); + rename( $path, $disabled_path); + } + } + include('modules/Administration/RebuildDashlets.php'); + } + } + + function enable_languages(){ + $languages = array(); + if(isset($this->installdefs['language'])){ + foreach($this->installdefs['language'] as $packs){ + $languages[$packs['language']] = $packs['language']; + $packs['from'] = str_replace('', $this->base_dir, $packs['from']); + $GLOBALS['log']->debug("Installing Language Pack ..." . $packs['from'] . " for " .$packs['to_module']); + $path = 'custom/Extension/modules/' . $packs['to_module']. '/Ext/Language'; + if($packs['to_module'] == 'application'){ + $path ='custom/Extension/' . $packs['to_module']. '/Ext/Language'; + } + + if(!file_exists($path)){ + mkdir_recursive($path, true); + } + if (file_exists($path.'/'.DISABLED_PATH.'/'.$packs['language'].'.'. $this->id_name . '.php')) + rename($path.'/'.DISABLED_PATH.'/'.$packs['language'].'.'. $this->id_name . '.php', $path.'/'.$packs['language'].'.'. $this->id_name . '.php'); + } + $this->rebuild_languages($languages); + } + } + + function disable_languages(){ + $languages = array(); + if(isset($this->installdefs['language'])){ + foreach($this->installdefs['language'] as $packs){ + $languages[$packs['language']] = $packs['language']; + $packs['from'] = str_replace('', $this->base_dir, $packs['from']); + $GLOBALS['log']->debug("Uninstalling Language Pack ..." . $packs['from'] . " for " .$packs['to_module']); + $path = 'custom/Extension/modules/' . $packs['to_module']. '/Ext/Language'; + if($packs['to_module'] == 'application'){ + $path ='custom/Extension/' . $packs['to_module']. '/Ext/Language'; + } + mkdir_recursive($path . '/'.DISABLED_PATH, true); + if (file_exists($path.'/'.$packs['language'].'.'. $this->id_name . '.php')) + rename($path.'/'.$packs['language'].'.'. $this->id_name . '.php', $path.'/'.DISABLED_PATH.'/'.$packs['language'].'.'. $this->id_name . '.php'); + + } + $this->rebuild_languages($languages); + } + } + + function enable_userpage(){ + if(isset($this->installdefs['user_page'])){ + foreach($this->installdefs['user_page'] as $userpage){ + $userpage['from'] = str_replace('', $this->base_dir, $userpage['from']); + $GLOBALS['log']->debug("Installing User Page Section ..." . $userpage['from'] ); + $path = 'custom/Extension/modules/Users/Ext/UserPage'; + if(file_exists($path . '/'.DISABLED_PATH.'/'. $this->id_name . '.php')){ + rename($path . '/'.DISABLED_PATH.'/'. $this->id_name . '.php', $path . '/'. $this->id_name . '.php'); + } + + } + $this->rebuild_userpage(); + } + + } + function disable_userpage(){ + if(isset($this->installdefs['user_page'])){ + foreach($this->installdefs['user_page'] as $userpage){ + $userpage['from'] = str_replace('', $this->base_dir, $userpage['from']); + $GLOBALS['log']->debug("Uninstalling User Page Section ..." . $userpage['from'] ); + $path = 'custom/Extension/modules/Users/Ext/UserPage'; + if (file_exists( $path . '/'. $this->id_name . '.php')) { + mkdir_recursive($path . '/'.DISABLED_PATH, true); + rename( $path . '/'. $this->id_name . '.php', $path . '/'.DISABLED_PATH.'/'. $this->id_name . '.php'); + } + } + $this->rebuild_userpage(); + } + } + + function enable_copy(){ + //copy files back onto file system. first perform md5 check to determine if anything has been modified + //here we should just go through the files in the -restore directory and copy those back + if(isset($GLOBALS['mi_overwrite_files']) && $GLOBALS['mi_overwrite_files']){ + if(!empty($this->installdefs['copy'])){ + foreach($this->installdefs['copy'] as $cp){ + $cp['to'] = clean_path(str_replace('', $this->base_dir, $cp['to'])); + $backup_path = clean_path( remove_file_extension(urldecode(hashToFile($_REQUEST['install_file'])))."-restore/".$cp['to'] ); + + //check if this file exists in the -restore directory + if(file_exists($backup_path)){ + //since the file exists, then we want do an md5 of the install version and the file system version + //if(is_file($backup_path) && md5_file($backup_path) == md5_file($cp['to'])){ + //since the files are the same then we can safely move back from the -restore + //directory into the file system + $GLOBALS['log']->debug("ENABLE COPY:: FROM: ".$cp['from']. " TO: ".$cp['to']); + $this->copy_path($cp['from'], $cp['to']); + /*}else{ + //since they are not equal then we need to prompt the user + }*/ + }//fi + }//rof + }//fi + }//fi + } + + function disable_copy(){ + //when we disable we want to copy the -restore files back into the file system + //but we should check the version in the module install against the version on the file system + //if they match then we can copy the file back, but otherwise we should ask the user. + +// $GLOBALS['log']->debug('ModuleInstaller.php->disable_copy()'); + if(isset($GLOBALS['mi_overwrite_files']) && $GLOBALS['mi_overwrite_files']){ +// $GLOBALS['log']->debug('ModuleInstaller.php->disable_copy():mi_overwrite_files=true'); + if(!empty($this->installdefs['copy'])){ +// $GLOBALS['log']->debug('ModuleInstaller.php->disable_copy(): installdefs not empty'); + foreach($this->installdefs['copy'] as $cp){ + $cp['to'] = clean_path(str_replace('', $this->base_dir, $cp['to'])); + $backup_path = clean_path( remove_file_extension(urldecode(hashToFile($_REQUEST['install_file'])))."-restore/".$cp['to'] ); // bug 16966 tyoung - replaced missing assignment to $backup_path + //check if this file exists in the -restore directory +// $GLOBALS['log']->debug("ModuleInstaller.php->disable_copy(): backup_path=".$backup_path); + if(file_exists($backup_path)){ + //since the file exists, then we want do an md5 of the install version and the file system version + $from = str_replace('', $this->base_dir, $cp['from']); + + //if(is_file($from) && md5_file($from) == md5_file($cp['to'])){ + //since the files are the same then we can safely move back from the -restore + //directory into the file system + $GLOBALS['log']->debug("DISABLE COPY:: FROM: ".$backup_path. " TO: ".$cp['to']); + $this->copy_path($backup_path, $cp['to']); + /*}else{ + //since they are not equal then we need to prompt the user + }*/ + }//fi + }//rof + }//fi + }//fi + } + + public function reset_opcodes() + { + /* Bug 39354 - added function_exists check. Not optimal fix, but safe nonetheless. + * This is for the upgrade to 6.1 from pre 6.1, since the utils files haven't been updated to 6.1 when this is called, + * but this file has been updated to 6.1 + */ + if(function_exists('sugar_clean_opcodes')){ + sugar_clean_opcodes(); + } + } + +} + + function UpdateSystemTabs($action, $installed_modules){ + require_once("modules/MySettings/TabController.php"); + $controller = new TabController(); + $isSystemTabsInDB = $controller->is_system_tabs_in_db(); + if ($isSystemTabsInDB && !empty($installed_modules)) + { + global $moduleList; + switch ($action) + { + case 'Restore' : + $currentTabs = $controller->get_system_tabs(); + foreach ($installed_modules as $module) + { + if(in_array($module, $currentTabs)){ + unset($currentTabs[$module]); + } + } + $controller->set_system_tabs($currentTabs);; + break; + case 'Add' : + $currentTabs = $controller->get_system_tabs(); + foreach ($installed_modules as $module) + { + if(!in_array($module, $currentTabs)){ + $currentTabs[$module] = $module; + } + } + $controller->set_system_tabs($currentTabs); + default: + break; + } + } + +} + + +?> diff --git a/ModuleInstall/ModuleScanner.php b/ModuleInstall/ModuleScanner.php new file mode 100644 index 00000000..ac9aa547 --- /dev/null +++ b/ModuleInstall/ModuleScanner.php @@ -0,0 +1,436 @@ +'pre_execute', + 'install_mkdirs'=>'mkdir', + 'install_copy'=>'copy', + 'install_images'=>'image_dir', + 'install_menus'=>'menu', + 'install_userpage'=>'user_page', + 'install_dashlets'=>'dashlets', + 'install_administration'=>'administration', + 'install_connectors'=>'connectors', + 'install_vardefs'=>'vardefs', + 'install_layoutdefs'=>'layoutdefs', + 'install_layoutfields'=>'layoutfields', + 'install_relationships'=>'relationships', + 'install_languages'=>'language', + 'install_logichooks'=>'logic_hooks', + 'post_execute'=>'post_execute', + + ); + + private $blackListExempt = array(); + + private $validExt = array('png', 'gif', 'jpg', 'css', 'js', 'php', 'txt', 'html', 'htm', 'tpl', 'pdf', 'md5', 'xml'); + private $blackList = array( + 'eval', + 'exec', + 'system', + 'shell_exec', + 'passthru', + 'chgrp', + 'chmod', + 'chwown', + 'file_put_contents', + 'file', + 'fileatime', + 'filectime', + 'filegroup', + 'fileinode', + 'filemtime', + 'fileowner', + 'fileperms', + 'fopen', + 'is_executable', + 'is_writable', + 'is_writeable', + 'lchgrp', + 'lchown', + 'linkinfo', + 'lstat', + 'mkdir', + 'parse_ini_file', + 'rmdir', + 'stat', + 'tempnam', + 'touch', + 'unlink', + 'getimagesize', + 'call_user_func', + 'call_user_func_array', + 'create_function', + + + //mutliple files per function call + 'copy', + 'link', + 'rename', + 'symlink', + 'move_uploaded_file', + 'chdir', + 'chroot', + 'create_cache_directory', + 'mk_temp_dir', + 'write_array_to_file', + 'write_encoded_file', + 'create_custom_directory', + 'sugar_rename', + 'sugar_chown', + 'sugar_fopen', + 'sugar_mkdir', + 'sugar_file_put_contents', + 'sugar_chgrp', + 'sugar_chmod', + 'sugar_touch', + +); + + public function printToWiki(){ + echo "'''Default Extensions'''
"; + foreach($this->validExt as $b){ + echo '#' . $b . '
'; + + } + echo "'''Default Black Listed Functions'''
"; + foreach($this->blackList as $b){ + echo '#' . $b . '
'; + + } + + } + + public function __construct(){ + if(!empty($GLOBALS['sugar_config']['moduleInstaller']['blackListExempt'])){ + $this->blackListExempt = array_merge($this->blackListExempt, $GLOBALS['sugar_config']['moduleInstaller']['blackListExempt']); + } + if(!empty($GLOBALS['sugar_config']['moduleInstaller']['blackList'])){ + $this->blackList = array_merge($this->blackList, $GLOBALS['sugar_config']['moduleInstaller']['blackList']); + } + if(!empty($GLOBALS['sugar_config']['moduleInstaller']['validExt'])){ + $this->validExt = array_merge($this->validExt, $GLOBALS['sugar_config']['moduleInstaller']['validExt']); + } + + } + + private $issues = array(); + private $pathToModule = ''; + + /** + *returns a list of issues + */ + public function getIssues(){ + return $this->issues; + } + + /** + *returns true or false if any issues were found + */ + public function hasIssues(){ + return !empty($this->issues); + } + + /** + *Ensures that a file has a valid extension + */ + private function isValidExtension($file){ + $file = strtolower($file); + + $extPos = strrpos($file, '.'); + //make sure they don't override the files.md5 + if($extPos === false || $file == 'files.md5')return false; + $ext = substr($file, $extPos + 1); + return in_array($ext, $this->validExt); + + } + + /** + *Scans a directory and calls on scan file for each file + **/ + public function scanDir($path){ + static $startPath = ''; + if(empty($startPath))$startPath = $path; + if(!is_dir($path))return false; + $d = dir($path); + while($e = $d->read()){ + $next = $path . '/' . $e; + if(is_dir($next)){ + if(substr($e, 0, 1) == '.')continue; + $this->scanDir($next); + }else{ + $issues = $this->scanFile($next); + + + } + } + return true; + } + + + /** + * Given a file it will open it's contents and check if it is a PHP file (not safe to just rely on extensions) if it finds isValidExtension($file)){ + $issues[] = translate('ML_INVALID_EXT'); + $this->issues['file'][$file] = $issues; + return $issues; + } + $contents = file_get_contents($file); + if(stripos($contents,'$token){ + if(is_string($token[0])){ + switch($token[0]){ + case '`': + $issues['backtick'] = translate('ML_INVALID_FUNCTION') . " '`'"; + case '(': + if($checkFunction)$issues[] = $possibleIssue; + break; + } + $checkFunction = false; + $possibleIssue = ''; + }else{ + $token['_msi'] = token_name($token[0]); + switch($token[0]){ + case T_WHITESPACE: continue; + case T_EVAL: + if(in_array('eval', $this->blackList) && !in_array('eval', $this->blackListExempt)) + $issues[]= translate('ML_INVALID_FUNCTION') . ' eval()'; + break; + case T_STRING: + $token[1] = strtolower($token[1]); + if(!in_array($token[1], $this->blackList))break; + if(in_array($token[1], $this->blackListExempt))break; + if ($lastToken !== false && + ($lastToken[0] == T_NEW || $lastToken[0] == T_OBJECT_OPERATOR || $lastToken[0] == T_DOUBLE_COLON)) + { + break; + } + case T_VARIABLE: + $checkFunction = true; + $possibleIssue = translate('ML_INVALID_FUNCTION') . ' ' . $token[1] . '()'; + break; + + default: + $checkFunction = false; + $possibleIssue = ''; + + } + if ($token[0] != T_WHITESPACE) + { + $lastToken = $token; + } + } + + } + if(!empty($issues)){ + $this->issues['file'][$file] = $issues; + } + + return $issues; + } + + + /* + * checks files.md5 file to see if the file is from sugar + * ONLY WORKS ON FILES + */ + public function sugarFileExists($path){ + static $md5 = array(); + if(empty($md5)){ + include('files.md5'); + $md5 = $md5_string; + } + if(isset($md5['./' . $path]))return true; + + + } + + + /** + *This function will scan the Manifest for disabled actions specified in $GLOBALS['sugar_config']['moduleInstaller']['disableActions'] + *if $GLOBALS['sugar_config']['moduleInstaller']['disableRestrictedCopy'] is set to false or not set it will call on scanCopy to ensure that it is not overriding files + */ + public function scanManifest($manifestPath){ + $issues = array(); + if(!file_exists($manifestPath)){ + $this->issues['manifest'][$manifestPath] = translate('ML_NO_MANIFEST'); + return $issues; + } + $fileIssues = $this->scanFile($manifestPath); + //if the manifest contains malicious code do not open it + if(!empty($fileIssues)){ + return $fileIssues; + } + include($manifestPath); + + + //scan for disabled actions + if(isset($GLOBALS['sugar_config']['moduleInstaller']['disableActions'])){ + foreach($GLOBALS['sugar_config']['moduleInstaller']['disableActions'] as $action){ + if(isset($installdefs[$this->manifestMap[$action]])){ + $issues[] = translate('ML_INVALID_ACTION_IN_MANIFEST') . $this->manifestMap[$action]; + } + } + } + + //now lets scan for files that will override our files + if(empty($GLOBALS['sugar_config']['moduleInstaller']['disableRestrictedCopy']) && isset($installdefs['copy'])){ + foreach($installdefs['copy'] as $copy){ + $from = str_replace('', $this->pathToModule, $copy['from']); + $to = $copy['to']; + if(substr_count($from, '..')){ + $this->issues['copy'][$from] = translate('ML_PATH_MAY_NOT_CONTAIN').' ".." -' . $from; + } + if(substr_count($to, '..')){ + $this->issues['copy'][$to] = translate('ML_PATH_MAY_NOT_CONTAIN'). ' ".." -' . $to; + } + while(substr_count($from, '//')){ + $from = str_replace('//', '/', $from); + } + while(substr_count($to, '//')){ + $to = str_replace('//', '/', $to); + } + $this->scanCopy($from, $to); + } + } + if(!empty($issues)){ + $this->issues['manifest'][$manifestPath] = $issues; + } + + + + } + + + + /** + * Takes in where the file will is specified to be copied from and to + * and ensures that there is no official sugar file there. If the file exists it will check + * against the MD5 file list to see if Sugar Created the file + * + */ + function scanCopy($from, $to){ + //if the file doesn't exist for the $to then it is not overriding anything + if(!file_exists($to))return; + //if $to is a dir and $from is a file then make $to a full file path as well + if(is_dir($to) && is_file($from)){ + if(substr($to,-1) === '/'){ + $to = substr($to, 0 , strlen($to) - 1); + } + $to .= '/'. basename($from); + } + //if the $to is a file and it is found in sugarFileExists then don't allow overriding it + if(is_file($to) && $this->sugarFileExists($to)){ + $this->issues['copy'][$from] = translate('ML_OVERRIDE_CORE_FILES') . '(' . $to . ')'; + } + + if(is_dir($from)){ + $d = dir($from); + while($e = $d->read()){ + if($e == '.' || $e == '..')continue; + $this->scanCopy($from .'/'. $e, $to .'/' . $e); + } + } + + + + + + } + + + /** + *Main external function that takes in a path to a package and then scans + *that package's manifest for disabled actions and then it scans the PHP files + *for restricted function calls + * + */ + public function scanPackage($path){ + $this->pathToModule = $path; + $this->scanManifest($path . '/manifest.php'); + if(empty($GLOBALS['sugar_config']['moduleInstaller']['disableFileScan'])){ + $this->scanDir($path); + } + } + + /** + *This function will take all issues of the current instance and print them to the screen + **/ + public function displayIssues($package='Package'){ + echo '

'.str_replace('{PACKAGE}' , $package ,translate('ML_PACKAGE_SCANNING')). '


' . translate('ML_INSTALLATION_FAILED') . '


' .str_replace('{PACKAGE}' , $package ,translate('ML_PACKAGE_NOT_CONFIRM')). '

  • '. translate('ML_OBTAIN_NEW_PACKAGE') . '
  • ' . translate('ML_RELAX_LOCAL'). +'


' . translate('ML_SUGAR_LOADING_POLICY') . ' ' . translate('ML_SUGAR_KB') . '.'. +'
' . translate('ML_AVAIL_RESTRICTION'). ' ' . translate('ML_SUGAR_DZ') . '.

'; + + + foreach($this->issues as $type=>$issues){ + echo '

'. ucfirst($type) .' ' . translate('ML_ISSUES') . '

'; + echo '
'; + foreach($issues as $file=>$issue){ + $file = str_replace($this->pathToModule . '/', '', $file); + echo '
' . $file . '
'; + if(is_array($issue)){ + foreach($issue as $i){ + echo "$i
"; + } + }else{ + echo "$issue
"; + } + echo "
"; + } + echo '
'; + + } + echo "
"; + + } + + +} + + +?> \ No newline at end of file diff --git a/ModuleInstall/PackageManager/ListViewPackages.php b/ModuleInstall/PackageManager/ListViewPackages.php new file mode 100644 index 00000000..b31b3fe3 --- /dev/null +++ b/ModuleInstall/PackageManager/ListViewPackages.php @@ -0,0 +1,72 @@ +data = $data; + $this->tpl = $file; + } + + /** + * Override the display method + */ + function display(){ + global $odd_bg, $even_bg, $app_strings; + $this->ss->assign('rowColor', array('oddListRow', 'evenListRow')); + $this->ss->assign('bgColor', array($odd_bg, $even_bg)); + $this->ss->assign('displayColumns', $this->displayColumns); + $this->ss->assign('secondaryDisplayColumns', $this->secondaryDisplayColumns); + $this->ss->assign('data', $this->data); + return $this->ss->fetch($this->tpl); + } +} +?> diff --git a/ModuleInstall/PackageManager/PackageController.php b/ModuleInstall/PackageManager/PackageController.php new file mode 100644 index 00000000..d4082035 --- /dev/null +++ b/ModuleInstall/PackageManager/PackageController.php @@ -0,0 +1,356 @@ +_pm = new PackageManager(); + } + + function performBasicSearch(){ + $json = getJSONobj(); + $search_term = ''; + $node_id = ''; + if(isset($_REQUEST['search_term'])) { + $search_term = nl2br($_REQUEST['search_term']); + } + if(isset($_REQUEST['node_id'])) { + $node_id = nl2br($_REQUEST['node_id']); + } + $xml = PackageManager::getPackages($node_id); + echo 'result = ' . $json->encode(array('packages' => $xml)); + } + + /** + * Retrieve a list of packages which belong to the corresponding category + * + * @param category_id this is passed via POST and is the category id of packages + * we wish to retrieve + * @return packages xml string consisting of the packages and releases which belong to + * the category + */ + function getPackages(){ + $json = getJSONobj(); + $category_id = ''; + + if(isset($_REQUEST['category_id'])) { + $category_id = nl2br($_REQUEST['category_id']); + } + $xml = PackageManager::getPackages($category_id); + echo 'result = ' . $json->encode(array('package_output' => $xml)); + } + + /** + * Obtain a list of releases from the server. This function is currently used for generating the patches/langpacks for upgrade wizard + * as well as during installation + */ + function getReleases(){ + $json = getJSONobj(); + $category_id = ''; + $package_id = ''; + $types = ''; + if(isset($_REQUEST['category_id'])) { + $category_id = nl2br($_REQUEST['category_id']); + } + if(isset($_REQUEST['package_id'])) { + $package_id = nl2br($_REQUEST['package_id']); + } + if(isset($_REQUEST['types'])) { + $types = nl2br($_REQUEST['types']); + } + $types = explode(',', $types); + + $filter = array(); + $count = count($types); + $index = 1; + $type_str = ''; + foreach($types as $type){ + $type_str .= "'".$type."'"; + if($index < $count) + $type_str .= ","; + $index++; + } + + $filter = array('type' => $type_str); + $filter = PackageManager::toNameValueList($filter); + $releases = PackageManager::getReleases($category_id, $package_id, $filter); + $nodes = array(); + $release_map = array(); + foreach($releases['packages'] as $release){ + $release = PackageManager::fromNameValueList($release); + $nodes[] = array('description' => $release['description'], 'version' => $release['version'], 'build_number' => $release['build_number'], 'id' => $release['id']); + $release_map[$release['id']] = array('package_id' => $release['package_id'], 'category_id' => $release['category_id']); + } + $_SESSION['ML_PATCHES'] = $release_map; + echo 'result = ' . $json->encode(array('releases' => $nodes)); + } + + /** + * Obtain a promotion from the depot + */ + function getPromotion(){ + $json = getJSONobj(); + + $header = PackageManager::getPromotion(); + + echo 'result = ' . $json->encode(array('promotion' => $header)); + } + + /** + * Download the given release + * + * @param category_id this is passed via POST and is the category id of the release we wish to download + * @param package_id this is passed via POST and is the package id of the release we wish to download + * @param release_id this is passed via POST and is the release id of the release we wish to download + * @return bool true is successful in downloading, false otherwise + */ + function download(){ + global $sugar_config; + $json = getJSONobj(); + $package_id = ''; + $category_id = ''; + $release_id = ''; + if(isset($_REQUEST['package_id'])) { + $package_id = nl2br($_REQUEST['package_id']); + } + if(isset($_REQUEST['category_id'])) { + $category_id = nl2br($_REQUEST['category_id']); + } + if(isset($_REQUEST['release_id'])) { + $release_id = nl2br($_REQUEST['release_id']); + } + $GLOBALS['log']->debug("PACKAGE ID: ".$package_id); + $GLOBALS['log']->debug("CATEGORY ID: ".$category_id); + $GLOBALS['log']->debug("RELEASE ID: ".$release_id); + $result = $this->_pm->download($category_id, $package_id, $release_id, getcwd().'/'.$sugar_config['upload_dir']); + $GLOBALS['log']->debug("RESULT: ".print_r($result,true)); + $success = 'false'; + if($result != null){ + $GLOBALS['log']->debug("Performing Setup"); + $this->_pm->performSetup($result, 'module', false); + $GLOBALS['log']->debug("Complete Setup"); + $success = 'true'; + } + echo 'result = ' . $json->encode(array('success' => $success)); + } + + /** + * Retrieve a list of categories that are subcategories to the selected category + * + * @param id - the id of the parent_category, -1 if this is the root + * @return array - a list of categories/nodes which are underneath this node + */ + function getCategories(){ + $json = getJSONobj(); + $node_id = ''; + if(isset($_REQUEST['category_id'])) { + $node_id = nl2br($_REQUEST['category_id']); + } + $GLOBALS['log']->debug("NODE ID: ".$node_id); + $nodes = PackageManager::getCategories($node_id); + echo 'result = ' . $json->encode(array('nodes' => $nodes)); + } + + function getNodes(){ + $json = getJSONobj(); + $category_id = ''; + if(isset($_REQUEST['category_id'])) { + $category_id = nl2br($_REQUEST['category_id']); + } + $GLOBALS['log']->debug("CATEGORY ID: ".$category_id); + $nodes = PackageManager::getModuleLoaderCategoryPackages($category_id); + $GLOBALS['log']->debug(var_export($nodes, true)); + echo 'result = ' . $json->encode(array('nodes' => $nodes)); + } + + /** + * Check the SugarDepot for updates for the given type as passed in via POST + * @param type the type to check for + * @return array return an array of releases for each given installed object if an update is found + */ + function checkForUpdates(){ + $json = getJSONobj(); + $type = ''; + if(isset($_REQUEST['type'])) { + $type = nl2br($_REQUEST['type']); + } + $pm = new PackageManager(); + $updates = $pm->checkForUpdates(); + $nodes = array(); + $release_map = array(); + if(!empty($updates)){ + foreach($updates as $update){ + $update = PackageManager::fromNameValueList($update); + $nodes[] = array('label' => $update['name'], 'description' => $update['description'], 'version' => $update['version'], 'build_number' => $update['build_number'], 'id' => $update['id'], 'type' => $update['type']); + $release_map[$update['id']] = array('package_id' => $update['package_id'], 'category_id' => $update['category_id'], 'type' => $update['type']); + } + } + //patches + $filter = array(array('name' => 'type', 'value' => "'patch'")); + $releases = $pm->getReleases('', '', $filter); + if(!empty($releases['packages'])){ + foreach($releases['packages'] as $update){ + $update = PackageManager::fromNameValueList($update); + $nodes[] = array('label' => $update['name'], 'description' => $update['description'], 'version' => $update['version'], 'build_number' => $update['build_number'], 'id' => $update['id'], 'type' => $update['type']); + $release_map[$update['id']] = array('package_id' => $update['package_id'], 'category_id' => $update['category_id'], 'type' => $update['type']); + } + } + $_SESSION['ML_PATCHES'] = $release_map; + echo 'result = ' . $json->encode(array('updates' => $nodes)); + } + + function getLicenseText(){ + $json = getJSONobj(); + $file = ''; + if(isset($_REQUEST['file'])) { + $file = hashToFile($_REQUEST['file']); + } + $GLOBALS['log']->debug("FILE : ".$file); + echo 'result = ' . $json->encode(array('license_display' => PackageManagerDisplay::buildLicenseOutput($file))); + } + + /** + * build the list of modules that are currently in the staging area waiting to be installed + */ + function getPackagesInStaging(){ + $packages = $this->_pm->getPackagesInStaging('module'); + $json = getJSONobj(); + + echo 'result = ' . $json->encode(array('packages' => $packages)); + } + + /** + * build the list of modules that are currently in the staging area waiting to be installed + */ + function performInstall(){ + $file = ''; + if(isset($_REQUEST['file'])) { + $file = hashToFile($_REQUEST['file']); + } + if(!empty($file)){ + $this->_pm->performInstall($file); + } + $json = getJSONobj(); + + echo 'result = ' . $json->encode(array('result' => 'success')); + } + + function authenticate(){ + $json = getJSONobj(); + $username = ''; + $password = ''; + $servername = ''; + $terms_checked = ''; + if(isset($_REQUEST['username'])) { + $username = nl2br($_REQUEST['username']); + } + if(isset($_REQUEST['password'])) { + $password = nl2br($_REQUEST['password']); + } + if(isset($_REQUEST['servername'])) { + $servername = $_REQUEST['servername']; + } + if(isset($_REQUEST['terms_checked'])) { + $terms_checked = $_REQUEST['terms_checked']; + if($terms_checked == 'on') + $terms_checked = true; + } + + if(!empty($username) && !empty($password)){ + $password = md5($password); + $result = PackageManager::authenticate($username, $password, $servername, $terms_checked); + if(!is_array($result) && $result == true) + $status = 'success'; + else + $status = $result['faultstring']; + }else{ + $status = 'failed'; + } + + echo 'result = ' . $json->encode(array('status' => $status)); + } + + function getDocumentation(){ + $json = getJSONobj(); + $package_id = ''; + $release_id = ''; + + if(isset($_REQUEST['package_id'])) { + $package_id = nl2br($_REQUEST['package_id']); + } + if(isset($_REQUEST['release_id'])) { + $release_id = nl2br($_REQUEST['release_id']); + } + + $documents = PackageManager::getDocumentation($package_id, $release_id); + $GLOBALS['log']->debug("DOCUMENTS: ".var_export($documents, true)); + echo 'result = ' . $json->encode(array('documents' => $documents)); + } + + function downloadedDocumentation(){ + $json = getJSONobj(); + $document_id = ''; + + if(isset($_REQUEST['document_id'])) { + $document_id = nl2br($_REQUEST['document_id']); + } + $GLOBALS['log']->debug("Downloading Document: ".$document_id); + PackageManagerComm::downloadedDocumentation($document_id); + echo 'result = ' . $json->encode(array('result' => 'true')); + } + + function remove(){ + $json = getJSONobj(); + $file = ''; + + if(isset($_REQUEST['file'])) { + $file = urldecode(hashToFile($_REQUEST['file'])); + } + $GLOBALS['log']->debug("FILE TO REMOVE: ".$file); + if(!empty($file)){ + unlink($file); + } + echo 'result = ' . $json->encode(array('result' => 'true')); + } + } +?> diff --git a/ModuleInstall/PackageManager/PackageManager.php b/ModuleInstall/PackageManager/PackageManager.php new file mode 100644 index 00000000..49a174a7 --- /dev/null +++ b/ModuleInstall/PackageManager/PackageManager.php @@ -0,0 +1,878 @@ +db = & DBManagerFactory::getInstance(); + } + + function initializeComm(){ + + } + + /** + * Obtain a promotion from SugarDepot + * @return string the string from the promotion + */ + function getPromotion(){ + $name_value_list = PackageManagerComm::getPromotion(); + if(!empty($name_value_list)){ + $name_value_list = PackageManager::fromNameValueList($name_value_list); + return $name_value_list['description']; + }else { + return ''; + } + } + + /** + * Obtain a list of category/packages/releases for use within the module loader + */ + function getModuleLoaderCategoryPackages($category_id = ''){ + $filter = array(); + $filter = array('type' => "'module', 'theme', 'langpack'"); + $filter = PackageManager::toNameValueList($filter); + return PackageManager::getCategoryPackages($category_id, $filter); + } + + /** + * Obtain the list of category_packages from SugarDepot + * @return category_packages + */ + function getCategoryPackages($category_id = '', $filter = array()){ + $results = PackageManagerComm::getCategoryPackages($category_id, $filter); + PackageManagerComm::errorCheck(); + $nodes = array(); + + $nodes[$category_id]['packages'] = array(); + if(!empty($results['categories'])){ + foreach($results['categories'] as $category){ + $mycat = PackageManager::fromNameValueList($category); + $nodes[$mycat['id']] = array('id' => $mycat['id'], 'label' => $mycat['name'], 'description' => $mycat['description'], 'type' => 'cat', 'parent' => $mycat['parent_id']); + $nodes[$mycat['id']]['packages'] = array(); + } + } + if(!empty($results['packages'])){ + $uh = new UpgradeHistory(); + foreach($results['packages'] as $package){ + $mypack = PackageManager::fromNameValueList($package); + $nodes[$mypack['category_id']]['packages'][$mypack['id']] = array('id' => $mypack['id'], 'label' => $mypack['name'], 'description' => $mypack['description'], 'category_id' => $mypack['category_id'], 'type' => 'package'); + $releases = PackageManager::getReleases($category_id, $mypack['id'], $filter); + $arr_releases = array(); + $nodes[$mypack['category_id']]['packages'][$mypack['id']]['releases'] = array(); + if(!empty($releases['packages'])){ + foreach($releases['packages'] as $release){ + $myrelease = PackageManager::fromNameValueList($release); + //check to see if we already this one installed + $result = $uh->determineIfUpgrade($myrelease['id_name'], $myrelease['version']); + $enable = false; + if($result == true || is_array($result)) + $enable = true; + $nodes[$mypack['category_id']]['packages'][$mypack['id']]['releases'][$myrelease['id']] = array('id' => $myrelease['id'], 'version' => $myrelease['version'], 'label' => $myrelease['description'], 'category_id' => $mypack['category_id'], 'package_id' => $mypack['id'], 'type' => 'release', 'enable' => $enable); + } + } + //array_push($nodes[$mypack['category_id']]['packages'], $package_arr); + } + } + $GLOBALS['log']->debug("NODES". var_export($nodes, true)); + return $nodes; + } + + /** + * Get a list of categories from the SugarDepot + * @param category_id the category id of parent to obtain + * @param filter an array of filters to pass to limit the query + * @return array an array of categories for display on the client + */ + function getCategories($category_id, $filter = array()){ + $nodes = array(); + $results = PackageManagerComm::getCategories($category_id, $filter); + PackageManagerComm::errorCheck(); + if(!empty($results['categories'])){ + foreach($results['categories'] as $category){ + $mycat = PackageManager::fromNameValueList($category); + $nodes[] = array('id' => $mycat['id'], 'label' => $mycat['name'], 'description' => $mycat['description'], 'type' => 'cat', 'parent' => $mycat['parent_id']); + } + } + return $nodes; + } + + function getPackages($category_id, $filter = array()){ + $nodes = array(); + $results = PackageManagerComm::getPackages($category_id, $filter); + PackageManagerComm::errorCheck(); + $packages = array(); + //$xml = ''; + //$xml .= ''; + if(!empty($results['packages'])){ + foreach($results['packages'] as $package){ + $mypack = PackageManager::fromNameValueList($package); + $packages[$mypack['id']] = array('package_id' => $mypack['id'], 'name' => $mypack['name'], 'description' => $mypack['description'], 'category_id' => $mypack['category_id']); + $releases = PackageManager::getReleases($category_id, $mypack['id']); + $arr_releases = array(); + foreach($releases['packages'] as $release){ + $myrelease = PackageManager::fromNameValueList($release); + $arr_releases[$myrelease['id']] = array('release_id' => $myrelease['id'], 'version' => $myrelease['version'], 'description' => $myrelease['description'], 'category_id' => $mypack['category_id'], 'package_id' => $mypack['id']); + } + $packages[$mypack['id']]['releases'] = $arr_releases; + } + } + return $packages; + } + + function getReleases($category_id, $package_id, $filter = array()){ + $releases = PackageManagerComm::getReleases($category_id, $package_id, $filter); + PackageManagerComm::errorCheck(); + return $releases; + } + + /** + * Retrieve the package as specified by the $id from the heartbeat server + * + * @param category_id the category_id to which the release belongs + * @param package_id the package_id to which the release belongs + * @param release_id the release_id to download + * @return filename - the path to which the zip file was saved + */ + function download($category_id, $package_id, $release_id, $save_dir = ''){ + $GLOBALS['log']->debug('RELEASE _ID: '.$release_id); + if(!empty($release_id)){ + $filename = PackageManagerComm::addDownload($category_id, $package_id, $release_id); + if($filename){ + $GLOBALS['log']->debug('RESULT: '.$filename); + PackageManagerComm::errorCheck(); + $filepath = PackageManagerComm::performDownload($filename, $save_dir); + return $filepath; + /*if(!empty($result) && !empty($result['filename']) && !empty($save_dir)){ + $GLOBALS['log']->debug('Saving Package to: '.$save_dir); + $GLOBALS['log']->debug('Saving package to the local file system:'.$result['filename']); + return write_encoded_file ($result, $save_dir); + }else{ + return null; + }*/ + } + }else{ + return null; + } + } + + /** + * Given the Mambo username, password, and download key attempt to authenticate, if + * successful then store these credentials + * + * @param username Mambo username + * @param password Mambo password + * @param systemname the user's download key + * @return true if successful, false otherwise + */ + function authenticate($username, $password, $systemname='', $terms_checked = true){ + PackageManager::setCredentials($username, $password, $systemname); + PackageManagerComm::clearSession(); + $result = PackageManagerComm::login($terms_checked); + if(is_array($result)) + return $result; + else + return true; + } + + function setCredentials($username, $password, $systemname){ + + $admin = new Administration(); + $admin->retrieveSettings(); + $admin->saveSetting(CREDENTIAL_CATEGORY, CREDENTIAL_USERNAME, $username); + $admin->saveSetting(CREDENTIAL_CATEGORY, CREDENTIAL_PASSWORD, $password); + if(!empty($systemname)){ + $admin->saveSetting('system', 'name', $systemname); + } + } + + function getCredentials(){ + + $admin = new Administration(); + $admin->retrieveSettings(CREDENTIAL_CATEGORY, true); + $credentials = array(); + $credentials['username'] = ''; + $credentials['password'] = ''; + $credentials['system_name'] = ''; + if(!empty($admin->settings[CREDENTIAL_CATEGORY.'_'.CREDENTIAL_USERNAME])){ + $credentials['username'] = $admin->settings[CREDENTIAL_CATEGORY.'_'.CREDENTIAL_USERNAME]; + } + if(!empty($admin->settings[CREDENTIAL_CATEGORY.'_'.CREDENTIAL_USERNAME])){ + $credentials['password'] = $admin->settings[CREDENTIAL_CATEGORY.'_'.CREDENTIAL_PASSWORD]; + } + if(!empty($admin->settings['system_name'])){ + $credentials['system_name'] = $admin->settings['system_name']; + } + return $credentials; + } + + function getTermsAndConditions(){ + return PackageManagerComm::getTermsAndConditions(); + + } + + /** + * Retrieve documentation for the given release or package + * + * @param package_id the specified package to retrieve documentation + * @param release_id the specified release to retrieve documentation + * + * @return documents + */ + function getDocumentation($package_id, $release_id){ + if(!empty($release_id) || !empty($package_id)){ + $documents = PackageManagerComm::getDocumentation($package_id, $release_id); + return $documents; + }else{ + return null; + } + } + + /** + * Grab the list of installed modules and send that list to the depot. + * The depot will then send back a list of modules that need to be updated + */ + function checkForUpdates(){ + $lists = $this->buildInstalledReleases(array('module'), true); + $updates = array(); + if(!empty($lists)){ + $updates = PackageManagerComm::checkForUpdates($lists); + }//fi + return $updates; + } + + //////////////////////////////////////////////////////// + /////////// HELPER FUNCTIONS + function toNameValueList($array){ + $list = array(); + foreach($array as $name=>$value){ + $list[] = array('name'=>$name, 'value'=>$value); + } + return $list; + } + + function toNameValueLists($arrays){ + $lists = array(); + foreach($arrays as $array){ + $lists[] = PackageManager::toNameValueList($array); + } + return $lists; + } + + function fromNameValueList($nvl){ + $array = array(); + foreach($nvl as $list){ + $array[$list['name']] = $list['value']; + } + return $array; + } + + function buildInstalledReleases($types = array('module')){ + //1) get list of installed modules + $installeds = $this->getInstalled($types); + $releases = array(); + foreach($installeds as $installed){ + $releases[] = array('name' => $installed->name, 'id_name' => $installed->id_name, 'version' => $installed->version, 'filename' => $installed->filename, 'type' => $installed->type); + } + + $lists = array(); + $name_value_list = array(); + if(!empty($releases)){ + $lists = $this->toNameValueLists($releases); + }//fi + return $lists; + } + + function buildPackageXML($package, $releases = array()){ + $xml = ''; + $xml .= ''.$package['id'].''; + $xml .= ''.$package['name'].''; + $xml .= ''.$package['description'].''; + if(!empty($releases)){ + $xml .= ''; + foreach($releases['packages'] as $release){ + + $myrelease = PackageManager::fromNameValueList($release); + $xml .= ''; + $xml .= ''.$myrelease['id'].''; + $xml .= ''.$myrelease['version'].''; + $xml .= ''.$myrelease['description'].''; + $xml .= ''.$package['id'].''; + $xml .= ''.$package['category_id'].''; + $xml .= ''; + } + $xml .= ''; + } + $xml .= ''; + return $xml; + } + + ////////////////////////////////////////////////////////////////////// + /////////// INSTALL SECTION + function extractFile( $zip_file, $file_in_zip, $base_tmp_upgrade_dir){ + $my_zip_dir = mk_temp_dir( $base_tmp_upgrade_dir ); + unzip_file( $zip_file, $file_in_zip, $my_zip_dir ); + return( "$my_zip_dir/$file_in_zip" ); + } + + function extractManifest( $zip_file,$base_tmp_upgrade_dir ) { + global $sugar_config; + $base_upgrade_dir = $sugar_config['upload_dir'] . "/upgrades"; + $base_tmp_upgrade_dir = "$base_upgrade_dir/temp"; + return( $this->extractFile( $zip_file, "manifest.php",$base_tmp_upgrade_dir ) ); + } + + function validate_manifest( $manifest ){ + // takes a manifest.php manifest array and validates contents + global $subdirs; + global $sugar_version; + global $sugar_flavor; + global $mod_strings; + + if( !isset($manifest['type']) ){ + die($mod_strings['ERROR_MANIFEST_TYPE']); + } + $type = $manifest['type']; + $GLOBALS['log']->debug("Getting InstallType"); + if( $this->getInstallType( "/$type/" ) == "" ){ + $GLOBALS['log']->debug("Error with InstallType".$type); + die($mod_strings['ERROR_PACKAGE_TYPE']. ": '" . $type . "'." ); + } + $GLOBALS['log']->debug("Passed with InstallType"); + if( isset($manifest['acceptable_sugar_versions']) ){ + $version_ok = false; + $matches_empty = true; + if( isset($manifest['acceptable_sugar_versions']['exact_matches']) ){ + $matches_empty = false; + foreach( $manifest['acceptable_sugar_versions']['exact_matches'] as $match ){ + if( $match == $sugar_version ){ + $version_ok = true; + } + } + } + if( !$version_ok && isset($manifest['acceptable_sugar_versions']['regex_matches']) ){ + $matches_empty = false; + foreach( $manifest['acceptable_sugar_versions']['regex_matches'] as $match ){ + if( preg_match( "/$match/", $sugar_version ) ){ + $version_ok = true; + } + } + } + + if( !$matches_empty && !$version_ok ){ + die( $mod_strings['ERROR_VERSION_INCOMPATIBLE'] . $sugar_version ); + } + } + + if( isset($manifest['acceptable_sugar_flavors']) && sizeof($manifest['acceptable_sugar_flavors']) > 0 ){ + $flavor_ok = false; + foreach( $manifest['acceptable_sugar_flavors'] as $match ){ + if( $match == $sugar_flavor ){ + $flavor_ok = true; + } + } + if( !$flavor_ok ){ + //die( $mod_strings['ERROR_FLAVOR_INCOMPATIBLE'] . $sugar_flavor ); + } + } + } + + function getInstallType( $type_string ){ + // detect file type + global $subdirs; + $subdirs = array('full', 'langpack', 'module', 'patch', 'theme', 'temp'); + + + foreach( $subdirs as $subdir ){ + if( preg_match( "#/$subdir/#", $type_string ) ){ + return( $subdir ); + } + } + // return empty if no match + return( "" ); + } + + function performSetup($tempFile, $view = 'module', $display_messages = true){ + global $sugar_config; + $base_filename = urldecode($tempFile); + $GLOBALS['log']->debug("BaseFileName: ".$base_filename); + $base_upgrade_dir = $sugar_config['upload_dir'] . "/upgrades"; + $base_tmp_upgrade_dir = "$base_upgrade_dir/temp"; + $manifest_file = $this->extractManifest( $base_filename,$base_tmp_upgrade_dir); + $GLOBALS['log']->debug("Manifest: ".$manifest_file); + if($view == 'module') + $license_file = $this->extractFile($base_filename, 'LICENSE.txt', $base_tmp_upgrade_dir); + if(is_file($manifest_file)){ + $GLOBALS['log']->debug("VALIDATING MANIFEST". $manifest_file); + require_once( $manifest_file ); + $this->validate_manifest($manifest ); + $upgrade_zip_type = $manifest['type']; + $GLOBALS['log']->debug("VALIDATED MANIFEST"); + // exclude the bad permutations + if( $view == "module" ){ + if ($upgrade_zip_type != "module" && $upgrade_zip_type != "theme" && $upgrade_zip_type != "langpack"){ + $this->unlinkTempFiles(); + if($display_messages) + die($mod_strings['ERR_UW_NOT_ACCEPTIBLE_TYPE']); + } + }elseif( $view == "default" ){ + if($upgrade_zip_type != "patch" ){ + $this->unlinkTempFiles(); + if($display_messages) + die($mod_strings['ERR_UW_ONLY_PATCHES']); + } + } + + $base_filename = preg_replace( "#\\\\#", "/", $base_filename ); + $base_filename = basename( $base_filename ); + mkdir_recursive( "$base_upgrade_dir/$upgrade_zip_type" ); + $target_path = "$base_upgrade_dir/$upgrade_zip_type/$base_filename"; + $target_manifest = remove_file_extension( $target_path ) . "-manifest.php"; + + if( isset($manifest['icon']) && $manifest['icon'] != "" ){ + $icon_location = $this->extractFile( $tempFile ,$manifest['icon'], $base_tmp_upgrade_dir ); + $path_parts = pathinfo( $icon_location ); + copy( $icon_location, remove_file_extension( $target_path ) . "-icon." . $path_parts['extension'] ); + } + + if( copy( $tempFile , $target_path ) ){ + copy( $manifest_file, $target_manifest ); + if($display_messages) + $messages = ''; + }else{ + if($display_messages) + $messages = ''; + } + }//fi + else{ + $this->unlinkTempFiles(); + if($display_messages) + die($mod_strings['ERR_UW_NO_MANIFEST']); + } + if(isset($messages)) + return $messages; + } + + function unlinkTempFiles() { + global $sugar_config; + @unlink($_FILES['upgrade_zip']['tmp_name']); + @unlink(getcwd().'/'.$sugar_config['upload_dir'].$_FILES['upgrade_zip']['name']); + } + + function performInstall($file, $silent=true){ + global $sugar_config; + global $mod_strings; + global $current_language; + $base_upgrade_dir = $sugar_config['upload_dir'] . "/upgrades"; + $base_tmp_upgrade_dir = "$base_upgrade_dir/temp"; + if(!file_exists($base_tmp_upgrade_dir)){ + mkdir_recursive($base_tmp_upgrade_dir, true); + } + + $GLOBALS['log']->debug("INSTALLING: ".$file); + $mi = new ModuleInstaller(); + $mi->silent = $silent; + $mod_strings = return_module_language($current_language, "Administration"); + $GLOBALS['log']->debug("ABOUT TO INSTALL: ".$file); + if(preg_match("#.*\.zip\$#", $file)) { + $GLOBALS['log']->debug("1: ".$file); + // handle manifest.php + $target_manifest = remove_file_extension( $file ) . '-manifest.php'; + include($target_manifest); + $GLOBALS['log']->debug("2: ".$file); + $unzip_dir = mk_temp_dir( $base_tmp_upgrade_dir ); + unzip($file, $unzip_dir ); + $GLOBALS['log']->debug("3: ".$unzip_dir); + $id_name = $installdefs['id']; + $version = $manifest['version']; + $uh = new UpgradeHistory(); + $previous_install = array(); + if(!empty($id_name) & !empty($version)) + $previous_install = $uh->determineIfUpgrade($id_name, $version); + $previous_version = (empty($previous_install['version'])) ? '' : $previous_install['version']; + $previous_id = (empty($previous_install['id'])) ? '' : $previous_install['id']; + + if(!empty($previous_version)){ + $mi->install($unzip_dir, true, $previous_version); + }else{ + $mi->install($unzip_dir); + } + $GLOBALS['log']->debug("INSTALLED: ".$file); + $new_upgrade = new UpgradeHistory(); + $new_upgrade->filename = $file; + $new_upgrade->md5sum = md5_file($file); + $new_upgrade->type = $manifest['type']; + $new_upgrade->version = $manifest['version']; + $new_upgrade->status = "installed"; + //$new_upgrade->author = $manifest['author']; + $new_upgrade->name = $manifest['name']; + $new_upgrade->description = $manifest['description']; + $new_upgrade->id_name = $id_name; + $serial_manifest = array(); + $serial_manifest['manifest'] = (isset($manifest) ? $manifest : ''); + $serial_manifest['installdefs'] = (isset($installdefs) ? $installdefs : ''); + $serial_manifest['upgrade_manifest'] = (isset($upgrade_manifest) ? $upgrade_manifest : ''); + $new_upgrade->manifest = base64_encode(serialize($serial_manifest)); + //$new_upgrade->unique_key = (isset($manifest['unique_key'])) ? $manifest['unique_key'] : ''; + $new_upgrade->save(); + //unlink($file); + }//fi + } + + function performUninstall($name){ + $uh = new UpgradeHistory(); + $uh->name = $name; + $uh->id_name = $name; + $found = $uh->checkForExisting($uh); + if($found != null){ + + global $sugar_config; + global $mod_strings; + global $current_language; + $base_upgrade_dir = $sugar_config['upload_dir'] . "/upgrades"; + $base_tmp_upgrade_dir = "$base_upgrade_dir/temp"; + if(!isset($GLOBALS['mi_remove_tables']))$GLOBALS['mi_remove_tables'] = true; + $unzip_dir = mk_temp_dir( $base_tmp_upgrade_dir ); + unzip($found->filename, $unzip_dir ); + $mi = new ModuleInstaller(); + $mi->silent = true; + $mi->uninstall( "$unzip_dir"); + $found->delete(); + unlink(remove_file_extension( $found->filename ) . '-manifest.php'); + unlink($found->filename); + } + } + + function getUITextForType( $type ){ + if( $type == "full" ){ + return( "Full Upgrade" ); + } + if( $type == "langpack" ){ + return( "Language Pack" ); + } + if( $type == "module" ){ + return( "Module" ); + } + if( $type == "patch" ){ + return( "Patch" ); + } + if( $type == "theme" ){ + return( "Theme" ); + } + } + + function getImageForType( $type ){ + + $icon = ""; + switch( $type ){ + case "full": + $icon = SugarThemeRegistry::current()->getImage("Upgrade", "" ); + break; + case "langpack": + $icon = SugarThemeRegistry::current()->getImage("LanguagePacks", "" ); + break; + case "module": + $icon = SugarThemeRegistry::current()->getImage("ModuleLoader", "" ); + break; + case "patch": + $icon = SugarThemeRegistry::current()->getImage("PatchUpgrades", "" ); + break; + case "theme": + $icon = SugarThemeRegistry::current()->getImage("Themes", "" ); + break; + default: + break; + } + return( $icon ); + } + + function getPackagesInStaging($view = 'module'){ + global $sugar_config; + global $current_language; + $uh = new UpgradeHistory(); + $base_upgrade_dir = $sugar_config['upload_dir'] . "/upgrades"; + $base_tmp_upgrade_dir = "$base_upgrade_dir/temp"; + $uContent = findAllFiles( "$base_upgrade_dir", array() , false, 'zip',$base_tmp_upgrade_dir); + //other variations of zip file i.e. ZIP, zIp,zIP,Zip,ZIp,ZiP + $extns = array( 'ZIP','ZIp','ZiP','Zip','zIP','zIp','ziP'); + foreach($extns as $extn){ + $uContent = array_merge($uContent,findAllFiles( "$base_upgrade_dir", array() , false, $extn,$base_tmp_upgrade_dir)); + } + $upgrade_contents = array(); + $content_values = array_values($uContent); + $alreadyProcessed = array(); + foreach($content_values as $val){ + if(empty($alreadyProcessed[$val])){ + $upgrade_contents[] = $val; + $alreadyProcessed["$val"] = true; + } + } + + $upgrades_available = 0; + $packages = array(); + $mod_strings = return_module_language($current_language, "Administration"); + foreach($upgrade_contents as $upgrade_content) + { + if(!preg_match("#.*\.zip\$#", strtolower($upgrade_content)) || preg_match("#.*./zips/.*#", strtolower($upgrade_content))) + { + continue; + } + + $upgrade_content = clean_path($upgrade_content); + // Bug 22285 - fix for UNC paths + if ( substr($upgrade_content,0,2) == '\\\\' ) + $upgrade_content = '\\\\'.$upgrade_content; + $the_base = basename($upgrade_content); + $the_md5 = md5_file($upgrade_content); + $md5_matches = $uh->findByMd5($the_md5); + $file_install = $upgrade_content; + if(0 == sizeof($md5_matches)) + { + $target_manifest = remove_file_extension( $upgrade_content ) . '-manifest.php'; + require_once($target_manifest); + + $name = empty($manifest['name']) ? $upgrade_content : $manifest['name']; + $version = empty($manifest['version']) ? '' : $manifest['version']; + $published_date = empty($manifest['published_date']) ? '' : $manifest['published_date']; + $icon = ''; + $description = empty($manifest['description']) ? 'None' : $manifest['description']; + $uninstallable = empty($manifest['is_uninstallable']) ? 'No' : 'Yes'; + $type = $this->getUITextForType( $manifest['type'] ); + $manifest_type = $manifest['type']; + $dependencies = array(); + if( isset( $manifest['dependencies']) ){ + $dependencies = $manifest['dependencies']; + } + + //check dependencies first + if(!empty($dependencies)){ + + $uh = new UpgradeHistory(); + $not_found = $uh->checkDependencies($dependencies); + if(!empty($not_found) && count($not_found) > 0){ + $file_install = 'errors_'.$mod_strings['ERR_UW_NO_DEPENDENCY']."[".implode(',', $not_found)."]"; + }//fi + } + + if($view == 'default' && $manifest_type != 'patch') + { + continue; + } + + if($view == 'module' + && $manifest_type != 'module' && $manifest_type != 'theme' && $manifest_type != 'langpack') + { + continue; + } + + if(empty($manifest['icon'])){ + $icon = $this->getImageForType( $manifest['type'] ); + }else{ + $path_parts = pathinfo( $manifest['icon'] ); + $icon = ""; + } + + $upgrades_available++; + + // uploaded file in cache/upload + $fileS = explode('/', $upgrade_content); + $c = count($fileS); + $fileName = (isset($fileS[$c-1]) && !empty($fileS[$c-1])) ? $fileS[$c-1] : $fileS[$c-2]; + $upload_file = $sugar_config['upload_dir'].$fileName; + + $upgrade_content = urlencode($upgrade_content); + $upload_content = urlencode($upload_file); + $packages[] = array('name' => $name, 'version' => $version, 'published_date' => $published_date, 'description' => $description, 'uninstallable' =>$uninstallable, 'type' => $type, 'file_install' => fileToHash($file_install), 'file' => fileToHash($upgrade_content), 'upload_file' => $upload_content); + }//fi + }//rof + return $packages; + } + + function getLicenseFromFile($file){ + global $sugar_config; + $base_upgrade_dir = $sugar_config['upload_dir'] . "/upgrades"; + $base_tmp_upgrade_dir = "$base_upgrade_dir/temp"; + $license_file = $this->extractFile($file, 'LICENSE.txt', $base_tmp_upgrade_dir); + if(is_file($license_file)){ + $contents = file_get_contents($license_file); + return $contents; + }else{ + return null; + } + } + + /** + * Run the query to obtain the list of installed types as specified by the type param + * + * @param type an array of types you would like to search for + * type options include (theme, langpack, module, patch) + * + * @return an array of installed upgrade_history objects + */ + function getInstalled($types = array('module')){ + $uh = new UpgradeHistory(); + $in = ""; + for($i = 0; $i < count($types); $i++){ + $in .= "'".$types[$i]."'"; + if(($i+1) < count($types)){ + $in .= ","; + } + } + $query = "SELECT * FROM ".$uh->table_name." WHERE type IN (".$in.")"; + return $uh->getList($query); + } + + function getinstalledPackages($types = array('module', 'langpack')){ + global $sugar_config; + $installeds = $this->getInstalled($types); + $packages = array(); + $upgrades_installed = 0; + $uh = new UpgradeHistory(); + $base_upgrade_dir = $sugar_config['upload_dir'] . "/upgrades"; + $base_tmp_upgrade_dir = "$base_upgrade_dir/temp"; + foreach($installeds as $installed) + { + $populate = false; + $filename = from_html($installed->filename); + $date_entered = $installed->date_entered; + $type = $installed->type; + $version = $installed->version; + $uninstallable = false; + $link = ""; + $description = $installed->description; + $name = $installed->name; + $enabled = true; + $enabled_string = 'ENABLED'; + //if the name is empty then we should try to pull from manifest and populate upgrade_history_table + if(empty($name)){ + $populate = true; + } + $upgrades_installed++; + switch($type) + { + case "theme": + case "langpack": + case "module": + case "patch": + if($populate){ + $manifest_file = $this->extractManifest($filename, $base_tmp_upgrade_dir); + require_once($manifest_file); + $GLOBALS['log']->info("Filling in upgrade_history table"); + $populate = false; + if( isset( $manifest['name'] ) ){ + $name = $manifest['name']; + $installed->name = $name; + } + if( isset( $manifest['description'] ) ){ + $description = $manifest['description']; + $installed->description = $description; + } + if(isset($installdefs) && isset( $installdefs['id'] ) ){ + $id_name = $installdefs['id']; + $installed->id_name = $id_name; + } + + $serial_manifest = array(); + $serial_manifest['manifest'] = (isset($manifest) ? $manifest : ''); + $serial_manifest['installdefs'] = (isset($installdefs) ? $installdefs : ''); + $serial_manifest['upgrade_manifest'] = (isset($upgrade_manifest) ? $upgrade_manifest : ''); + $installed->manifest = base64_encode(serialize($serial_manifest)); + $installed->save(); + }else{ + $serial_manifest = unserialize(base64_decode($installed->manifest)); + $manifest = $serial_manifest['manifest']; + } + if(($upgrades_installed==0 || $uh->UninstallAvailable($installeds, $installed)) + && is_file($filename) && !empty($manifest['is_uninstallable'])) + { + $uninstallable = true; + } + $enabled = $installed->enabled; + if(!$enabled) + $enabled_string = 'DISABLED'; + $file_uninstall = $filename; + if(!$uninstallable){ + $file_uninstall = 'UNINSTALLABLE'; + $enabled_string = 'UNINSTALLABLE'; + } else { + $file_uninstall = fileToHash( $file_uninstall ); + } + + $packages[] = array( + 'name' => $name, + 'version' => $version, + 'type' => $type, + 'published_date' => $date_entered, + 'description' => $description, + 'uninstallable' =>$uninstallable, + 'file_install' => $file_uninstall , + 'file' => fileToHash($filename), + 'enabled' => $enabled_string + ); + break; + default: + break; + } + + }//rof + return $packages; + } + } +?> diff --git a/ModuleInstall/PackageManager/PackageManagerComm.php b/ModuleInstall/PackageManager/PackageManagerComm.php new file mode 100644 index 00000000..cbebb366 --- /dev/null +++ b/ModuleInstall/PackageManager/PackageManagerComm.php @@ -0,0 +1,309 @@ +debug('USING HTTPS TO CONNECT TO HEARTBEAT'); + $soap_client = new nusoapclient(HTTPS_URL, false); + $ping = $soap_client->call('sugarPing', array()); + $GLOBALS['SugarDepot'] = $soap_client; + } + //if we do not have a session, then try to login + if($login && empty($_SESSION['SugarDepotSessionID'])){ + PackageManagerComm::login(); + } + } + + /** + * Check for errors in the response or error_str + */ + function errorCheck(){ + if(!empty($GLOBALS['SugarDepot']->error_str)){ + $GLOBALS['log']->fatal($GLOBALS['SugarDepot']->error_str); + $GLOBALS['log']->fatal($GLOBALS['SugarDepot']->response); + } + } + + /** + * Set the credentials for use during login + * + * @param username Mambo username + * @param password Mambo password + * @param download_key User's download key + */ + function setCredentials($username, $password, $download_key){ + $_SESSION['SugarDepotUsername'] = $username; + $_SESSION['SugarDepotPassword'] = $password; + $_SESSION['SugarDepotDownloadKey'] = $download_key; + } + + /** + * Clears out the session so we can reauthenticate. + */ + function clearSession(){ + $_SESSION['SugarDepotSessionID'] = null; + unset($_SESSION['SugarDepotSessionID']); + } + ///////////////////////////////////////////////////////// + ////////// BEGIN: Base Functions for Communicating with the depot + /** + * Login to the depot + * + * @return true if successful, false otherwise + */ + function login($terms_checked = true){ + if(empty($_SESSION['SugarDepotSessionID'])){ + global $license; + $GLOBALS['log']->debug("Begin SugarDepot Login"); + PackageManagerComm::initialize(false); + require('sugar_version.php'); + require('config.php'); + $credentials = PackageManager::getCredentials(); + if(empty($license))loadLicense(); + $info = sugarEncode('2813', serialize(getSystemInfo(true))); + $pm = new PackageManager(); + $installed = $pm->buildInstalledReleases(); + $installed = base64_encode(serialize($installed)); + $params = array('installed_modules' => $installed, 'terms_checked' => $terms_checked, 'system_name' => $credentials['system_name']); + $terms_version = (!empty($_SESSION['SugarDepot_TermsVersion']) ? $_SESSION['SugarDepot_TermsVersion'] : ''); + if(!empty($terms_version)) + $params['terms_version'] = $terms_version; + + $result = $GLOBALS['SugarDepot']->call('depotLogin', array(array('user_name' => $credentials['username'], 'password' => $credentials['password']),'info'=>$info, 'params' => $params)); + PackageManagerComm::errorCheck(); + if(!is_array($result)) + $_SESSION['SugarDepotSessionID'] = $result; + $GLOBALS['log']->debug("End SugarDepot Login"); + return $result; + } + else + return $_SESSION['SugarDepotSessionID']; + } + + /** + * Logout from the depot + */ + function logout(){ + PackageManagerComm::initialize(); + $result = $GLOBALS['SugarDepot']->call('depotLogout', array('session_id' => $_SESSION['SugarDepotSessionID'])); + } + + /** + * Get all promotions from the depot + */ + function getPromotion(){ + PackageManagerComm::initialize(); + //check for fault first and then return + $name_value_list = $GLOBALS['SugarDepot']->call('depotGetPromotion', array('session_id' => $_SESSION['SugarDepotSessionID'])); + return $name_value_list; + } + + /** + * A generic function which given a category_id some filter will + * return an object which contains categories and packages + * + * @param category_id the category_id to fetch + * @param filter a filter which will limit theh number of results returned + * @return categories_and_packages + * @see categories_and_packages + */ + function getCategoryPackages($category_id, $filter = array()){ + PackageManagerComm::initialize(); + //check for fault + return $GLOBALS['SugarDepot']->call('depotGetCategoriesPackages', array('session_id' => $_SESSION['SugarDepotSessionID'], 'category_id' => $category_id, 'filter' => $filter)); + } + + /** + * Return a list of child categories to the parent specified in category_id + * + * @param category_id the parent category_id + * @param filter a filter which will limit theh number of results returned + * @return categories_and_packages + * @see categories_and_packages + */ + function getCategories($category_id, $filter = array()){ + PackageManagerComm::initialize(); + //check for fault + return $GLOBALS['SugarDepot']->call('depotGetCategories', array('session_id' => $_SESSION['SugarDepotSessionID'], 'category_id' => $category_id, 'filter' => $filter)); + } + + /** + * Return a list of packages which belong to the parent category_id + * + * @param category_id the category_id to fetch + * @param filter a filter which will limit theh number of results returned + * @return packages + * @see packages + */ + function getPackages($category_id, $filter = array()){ + PackageManagerComm::initialize(); + //check for fault + return $GLOBALS['SugarDepot']->call('depotGetPackages', array('session_id' => $_SESSION['SugarDepotSessionID'], 'category_id' => $category_id, 'filter' => $filter)); + } + + /** + * Return a list of releases belong to a package + * + * @param category_id the category_id to fetch + * @param package_id the package id which the release belongs to + * @return packages + * @see packages + */ + function getReleases($category_id, $package_id, $filter = array()){ + PackageManagerComm::initialize(); + //check for fault + return $GLOBALS['SugarDepot']->call('depotGetReleases', array('session_id' => $_SESSION['SugarDepotSessionID'], 'category_id' => $category_id, 'package_id' => $package_id, 'filter' => $filter)); + } + + /** + * Download a given release + * + * @param category_id the category_id to fetch + * @param package_id the package id which the release belongs to + * @param release_id the release we want to download + * @return download + * @see download + */ + function download($category_id, $package_id, $release_id){ + PackageManagerComm::initialize(); + //check for fault + return $GLOBALS['SugarDepot']->call('depotDownloadRelease', array('session_id' => $_SESSION['SugarDepotSessionID'], 'category_id' => $category_id, 'package_id' => $package_id, 'release_id' => $release_id)); + } + + /** + * Add a requested download to the queue + * + * @param category_id the category_id to fetch + * @param package_id the package id which the release belongs to + * @param release_id the release we want to download + * @return the filename to download + */ + function addDownload($category_id, $package_id, $release_id){ + PackageManagerComm::initialize(); + //check for fault + return $GLOBALS['SugarDepot']->call('depotAddDownload', array('session_id' => $_SESSION['SugarDepotSessionID'], 'category_id' => $category_id, 'package_id' => $package_id, 'release_id' => $release_id, 'download_key' => '123')); + } + + /** + * Call the PackageManagerDownloader function which uses curl in order to download the specified file + * + * @param filename the file to download + * @return path to downloaded file + */ + function performDownload($filename, $save_dir){ + PackageManagerComm::initialize(); + //check for fault + $GLOBALS['log']->debug("Performing download from depot: Session ID: ".$_SESSION['SugarDepotSessionID']." Filename: ".$filename); + return PackageManagerDownloader::download($_SESSION['SugarDepotSessionID'], $filename, $save_dir); + } + + /** + * Retrieve documentation for the given release or package + * + * @param package_id the specified package to retrieve documentation + * @param release_id the specified release to retrieve documentation + * + * @return documents + */ + function getDocumentation($package_id, $release_id){ + PackageManagerComm::initialize(); + //check for fault + return $GLOBALS['SugarDepot']->call('depotGetDocumentation', array('session_id' => $_SESSION['SugarDepotSessionID'], 'package_id' => $package_id, 'release_id' => $release_id)); + } + + function getTermsAndConditions(){ + PackageManagerComm::initialize(false); + return $GLOBALS['SugarDepot']->call('depotTermsAndConditions',array()); + } + + /** + * Log that the user has clicked on a document + * + * @param document_id the document the user has clicked on + */ + function downloadedDocumentation($document_id){ + PackageManagerComm::initialize(); + //check for fault + $GLOBALS['log']->debug("Logging Document: ".$document_id); + $GLOBALS['SugarDepot']->call('depotDownloadedDocumentation', array('session_id' => $_SESSION['SugarDepotSessionID'], 'document_id' => $document_id)); + } + + /** + * Send the list of installed objects, could be patches, or modules, .. to the depot and allow the depot to send back + * a list of corresponding updates + * + * @param objects_to_check an array of name_value_lists which contain the appropriate values + * which will allow the depot to check for updates + * + * @return array of name_value_lists of corresponding updates + */ + function checkForUpdates($objects_to_check){ + PackageManagerComm::initialize(); + //check for fault + return $GLOBALS['SugarDepot']->call('depotCheckForUpdates', array('session_id' => $_SESSION['SugarDepotSessionID'], 'objects' => $objects_to_check)); + } + /** + * Ping the server to determine if we have established proper communication + * + * @return true if we can communicate with the server and false otherwise + */ + function isAlive(){ + PackageManagerComm::initialize(false); + + $status = $GLOBALS['SugarDepot']->call('sugarPing', array()); + if(empty($status) || $GLOBALS['SugarDepot']->getError() || $status != ACTIVE_STATUS){ + return false; + }else{ + return true; + } + } + ////////// END: Base Functions for Communicating with the depot + //////////////////////////////////////////////////////// +} + +?> diff --git a/ModuleInstall/PackageManager/PackageManagerDisplay.php b/ModuleInstall/PackageManager/PackageManagerDisplay.php new file mode 100644 index 00000000..096d38ae --- /dev/null +++ b/ModuleInstall/PackageManager/PackageManagerDisplay.php @@ -0,0 +1,606 @@ +assign('FORM_1_PLACE_HOLDER', $form1); + $ss->assign('form_action', $form_action); + $ss->assign('hidden_fields', $hidden_fields); + + $result = PackageManagerDisplay::getHeader(); + $header_text = $result['text']; + $isAlive = $result['isAlive']; + $show_login = $result['show_login']; + $mi_errors = ModuleInstaller::getErrors(); + $error_html = ""; + if(!empty($mi_errors)){ + $error_html = ""; + foreach($mi_errors as $error){ + $error_html .= "".$error."
"; + } + $error_html .= "
"; + } + + $form2 = ""; + $form2 .= $error_html; + if(!$isAlive) + $form2 .= ""; + $form2 .= "
".$header_text."
"; + + $tree = null; + //if($isAlive){ + $tree = PackageManagerDisplay::buildTreeView('treeview', $isAlive); + $tree->tree_style= 'include/ytree/TreeView/css/check/tree.css'; + $ss->assign('TREEHEADER',$tree->generate_header()); + //} + //$form2 .= PackageManagerDisplay::buildLoginPanel($mod_strings); + $form2 .= ""; + $form2 .= "
"; + if($isAlive){ + $form2 .= ""; + }else{ + $form2 .= ""; + } + $form2 .= ""; + if($isAlive){ + $form2 .= " Collapse"; + }else{ + $form2 .= ""; + } + $form2 .= "
"; + $form2 = ''; //Commenting out the form as part of sugar depot hiding. + $ss->assign('installation', ($install ? 'true' : 'false')); + + + $mod_strings = return_module_language($current_language, "Administration"); + + $ss->assign('MOD', $mod_strings); + $ss->assign('module_load', 'true'); + $ss->assign('scripts', PackageManagerDisplay::getDisplayScript($install)); + $show_login = false; //hiding install from sugar + $ss->assign('MODULE_SELECTOR', PackageManagerDisplay::buildGridOutput($tree, $mod_strings, $isAlive, $show_login)); + $ss->assign('FORM_2_PLACE_HOLDER', $form2); + $ss->assign('MOD', $mod_strings); + $descItemsInstalled = $mod_strings['LBL_UW_DESC_MODULES_INSTALLED']; + $ss->assign('INSTALLED_PACKAGES_HOLDER', PackageManagerDisplay::buildInstalledGrid($mod_strings, $types)); + + $str = $ss->fetch('ModuleInstall/PackageManager/tpls/PackageForm.tpl'); + return $str; + } + + /** + * A Static method to Build the display for the package manager + * + * @param String form1 - the form to display for manual downloading + * @param String hidden_fields - the hidden fields related to downloading a package + * @param String form_action - the form_action to be used when downloading from the server + * @param String types - the types of objects we will request from the server + * @param String active_form - the form to display first + * @return String - a string of html which will be used to display the forms + */ + function buildPatchDisplay($form1, $hidden_fields, $form_action, $types = array('module'), $active_form = 'form1'){ + global $current_language; + $mod_strings = return_module_language($current_language, "Administration"); + $ss = new Sugar_Smarty(); + $ss->assign('FORM_1_PLACE_HOLDER', $form1); + $ss->assign('form_action', $form_action); + $ss->assign('hidden_fields', $hidden_fields); + $mod_strings = return_module_language($current_language, "Administration"); + + $ss->assign('MOD', $mod_strings); + $result = PackageManagerDisplay::getHeader(); + $header_text = $result['text']; + $isAlive = $result['isAlive']; + $show_login = $result['show_login']; + $display = 'none'; + //if($isAlive){ + $display = 'block'; + //} + $form2 = ""; + if(!$isAlive) + $form2 .= ""; + $form2 .= "
".$header_text."
"; + $form2 .= "
"; + if($show_login){ + $form2 .= ""; + } + $form2 .= "
"; + $loginViewStyle = ($isAlive ? 'none' : 'block'); + $selectViewStyle = ($isAlive ? 'block' : 'none'); + $form2 .= "
"; + $form2 .= "
"; + $form2 .= "
"; + if(!$show_login) + $loginViewStyle = 'none'; + //$form2 .= "
"; + //$form2 .= PackageManagerDisplay::buildLoginPanel($mod_strings, $isAlive); + //$form2 .= "
"; + + $form2 .= "
"; + $form2 = ''; + $packages = array(); + $releases = array(); + if($isAlive){ + $filter = array(); + $count = count($types); + $index = 1; + $type_str = '"'; + foreach($types as $type){ + $type_str .= "'".$type."'"; + if($index < $count) + $type_str .= ","; + $index++; + } + $type_str .= '"'; + $filter = array('type' => $type_str); + $filter = PackageManager::toNameValueList($filter); + $pm = new PackageManager(); + /*if(in_array('patch', $types)){ + $releases = $pm->getReleases('3', '3', $filter); + }else{ + $releases = $pm->getReleases('', '', $filter); + }*/ + } + if($form_action == 'install.php' && (empty($releases) || count($releases['packages']) == 0)){ + //return false; + } + $tree = PackageManagerDisplay::buildTreeView('treeview', $isAlive); + $tree->tree_style= 'include/ytree/TreeView/css/check/tree.css'; + $ss->assign('TREEHEADER',$tree->generate_header()); + $ss->assign('module_load', 'false'); + $ss->assign('MODULE_SELECTOR', PackageManagerDisplay::buildGridOutput($tree, $mod_strings, $isAlive, $show_login)); + $ss->assign('FORM_2_PLACE_HOLDER', $form2); + $ss->assign('scripts', PackageManagerDisplay::getDisplayScript(false, 'patch', $releases, $types, $isAlive)); + $str = $ss->fetch('ModuleInstall/PackageManager/tpls/PackageForm.tpl'); + return $str; + } + + function buildInstalledGrid($mod_strings, $types = array('modules')){ + $descItemsInstalled = $mod_strings['LBL_UW_DESC_MODULES_INSTALLED']; + $output = ''; + $output .= '
'.$descItemsInstalled.'
'; + $output .= "
"; + return $output; + } + + function buildLoginPanel($mod_strings, $display_cancel){ + $credentials = PackageManager::getCredentials(); + $output = "
".$mod_strings['HDR_LOGIN_PANEL']."
"; + $output .= "
"; + + $output .= ""; + + $terms = PackageManager::getTermsAndConditions(); + $output .= "'; + $_SESSION['SugarDepot_TermsVersion'] = (!empty($terms['version']) ? $terms['version'] : ''); + + $output .= ""; + $output .= ""; + $output .= ""; + $output .= "
".$mod_strings['LBL_USERNAME']."".$mod_strings['LNK_NEW_ACCOUNT']."
".$mod_strings['LBL_PASSWORD']."".$mod_strings['LNK_FORGOT_PASS']."
".$mod_strings['LBL_TERMS_AND_CONDITIONS']."
".$mod_strings['LBL_ACCEPT_TERMS']."
"; + $output .= ""; + + if($display_cancel){ + $output .= " "; + } + $output .= "
"; + $output .= "
"; + return $output; + } + + /** + * Build html in order to display the grids relevant for module loader + * + * @param Tree tree - the tree which we are using to display the categories + * @param Array mod_strings - the local mod strings to display + * @return String - a string of html + */ + function buildGridOutput($tree, $mod_strings, $display = true, $show_login = true){ + $output = "
"; + $loginViewStyle = ($display ? 'none' : 'block'); + $selectViewStyle = ($display ? 'block' : 'none'); + $output .= "
"; + //if($display){ + $output .= ""; + $output .= ""; + $output .= "
"; + $output .= "
"; + $output .= $tree->generate_nodes_array(); + $output .= "
"; + $output .= "
"; + $output .= "
"; + $output .= "
"; + $output .= ""; + $output .= "
"; + // } + $output .= "
"; + if(!$show_login) + $loginViewStyle = 'none'; + // $output .= "
"; + // jchi ,#24296 :commented code because we are currently not using depot, in the future this may change so you can put this code back in. + //$output .= PackageManagerDisplay::buildLoginPanel($mod_strings, $display); + //$output .= "
"; + //$output .= "
"; + $output .= "
"; + + return $output; + } + + /** + * A Static method used to build the initial treeview when the page is first displayed + * + * @param String div_id - this div in which to display the tree + * @return Tree - the tree that is built + */ + function buildTreeView($div_id, $isAlive = true){ + $tree = new Tree($div_id); + $nodes = array(); + if($isAlive) + $nodes = PackageManager::getCategories(''); + + foreach($nodes as $arr_node){ + $node = new Node($arr_node['id'], $arr_node['label']); + $node->dynamicloadfunction = 'PackageManager.loadDataForNodeForPackage'; + $node->expanded = false; + $node->dynamic_load = true; + $node->set_property('href',"javascript:PackageManager.catClick('treeview');"); + $tree->add_node($node); + $node->set_property('description', $arr_node['description']); + } + return $tree; + } + + /** + * A Static method used to obtain the div for the license + * + * @param String license_file - the path to the license file + * @param String form_action - the form action when accepting the license file + * @param String next_step - the value for the next step in the installation process + * @param String zipFile - a string representing the path to the zip file + * @param String type - module/patch.... + * @param String manifest - the path to the manifest file + * @param String modify_field - the field to update when the radio button is changed + * @return String - a form used to display the license + */ + function getLicenseDisplay($license_file, $form_action, $next_step, $zipFile, $type, $manifest, $modify_field){ + global $current_language; + $mod_strings = return_module_language($current_language, "Administration"); + $contents = sugar_file_get_contents($license_file); + $div_id = urlencode($zipFile); + $display = "
"; + $display .= ""; + $display .= ""; + $display .= ""; + $display .= ""; + $display .= ""; + $display .= ""; + $display .= ""; + $display .= ""; + $display .= ""; + $display .= "
"; + $display .= "{$mod_strings['LBL_MODULE_LICENSE']}"; + $display .= ""; + $display .= " Expand
"; + $display .= "
"; + $display .= ""; + $display .= ""; + $display .= ""; + $display .= ""; + $display .= ""; + $display .= ""; + $display .= ""; + $display .= "
"; + $display .= ""; + $display .= "
"; + $display .= "{$mod_strings['LBL_ACCEPT']} "; + $display .= "{$mod_strings['LBL_DENY']}"; + $display .= "
"; + $display .= "
"; + $display .= "
"; + return $display; + } + + /** + * A Static method used to generate the javascript for the page + * + * @return String - the javascript required for the page + */ + function getDisplayScript($install = false, $type = 'module', $releases = null, $types = array(), $isAlive = true){ + global $sugar_version, $sugar_config; + global $current_language; + + $mod_strings = return_module_language($current_language, "Administration"); + $ss = new Sugar_Smarty(); + $ss->assign('MOD', $mod_strings); + if(!$install){ + $install = 0; + } + $ss->assign('INSTALLATION', $install); + $ss->assign('WAIT_IMAGE', SugarThemeRegistry::current()->getImage("loading","border='0' align='bottom'")); + $ss->assign('sugar_version', $sugar_version); + $ss->assign('js_custom_version', $sugar_config['js_custom_version']); + $ss->assign('IS_ALIVE', $isAlive); + //if($type == 'patch' && $releases != null){ + if($type == 'patch'){ + $ss->assign('module_load', 'false'); + $patches = PackageManagerDisplay::createJavascriptPackageArray($releases); + $ss->assign('PATCHES', $patches); + $ss->assign('GRID_TYPE', implode(',', $types)); + }else{ + $pm = new PackageManager(); + $releases = $pm->getPackagesInStaging(); + $patches = PackageManagerDisplay::createJavascriptModuleArray($releases); + $ss->assign('PATCHES', $patches); + $installeds = $pm->getinstalledPackages(); + $patches = PackageManagerDisplay::createJavascriptModuleArray($installeds, 'mti_installed_data'); + $ss->assign('INSTALLED_MODULES', $patches); + $ss->assign('UPGARDE_WIZARD_URL', 'index.php?module=UpgradeWizard&action=index'); + $ss->assign('module_load', 'true'); + } + if(!empty($GLOBALS['ML_STATUS_MESSAGE'])) + $ss->assign('ML_STATUS_MESSAGE',$GLOBALS['ML_STATUS_MESSAGE']); + + //Bug 24064. Checking and Defining labels since these might not be cached during Upgrade + if(!isset($mod_strings['LBL_ML_INSTALL']) || empty($mod_strings['LBL_ML_INSTALL'])){ + $mod_strings['LBL_ML_INSTALL'] = 'Install'; + } + if(!isset($mod_strings['LBL_ML_ENABLE_OR_DISABLE']) || empty($mod_strings['LBL_ML_ENABLE_OR_DISABLE'])) { + $mod_strings['LBL_ML_ENABLE_OR_DISABLE'] = 'Enable/Disable'; + } + if(!isset($mod_strings['LBL_ML_DELETE'])|| empty($mod_strings['LBL_ML_DELETE'])){ + $mod_strings['LBL_ML_DELETE'] = 'Delete'; + } + //Add by jchi 6/23/2008 to fix the bug 21667 + $filegrid_column_ary = array( + 'Name' => $mod_strings['LBL_ML_NAME'], + 'Install' => $mod_strings['LBL_ML_INSTALL'], + 'Delete' => $mod_strings['LBL_ML_DELETE'], + 'Type' => $mod_strings['LBL_ML_TYPE'], + 'Version' => $mod_strings['LBL_ML_VERSION'], + 'Published' => $mod_strings['LBL_ML_PUBLISHED'], + 'Uninstallable' => $mod_strings['LBL_ML_UNINSTALLABLE'], + 'Description' => $mod_strings['LBL_ML_DESCRIPTION'] + ); + + $filegridinstalled_column_ary = array( + 'Name' => $mod_strings['LBL_ML_NAME'], + 'Install' => $mod_strings['LBL_ML_INSTALL'], + 'Action' => $mod_strings['LBL_ML_ACTION'], + 'Enable_Or_Disable' => $mod_strings['LBL_ML_ENABLE_OR_DISABLE'], + 'Type' => $mod_strings['LBL_ML_TYPE'], + 'Version' => $mod_strings['LBL_ML_VERSION'], + 'Date_Installed' => $mod_strings['LBL_ML_INSTALLED'], + 'Uninstallable' => $mod_strings['LBL_ML_UNINSTALLABLE'], + 'Description' => $mod_strings['LBL_ML_DESCRIPTION'] + ); + + $ss->assign('ML_FILEGRID_COLUMN',$filegrid_column_ary); + $ss->assign('ML_FILEGRIDINSTALLED_COLUMN',$filegridinstalled_column_ary); + //end + + $str = $ss->fetch('ModuleInstall/PackageManager/tpls/PackageManagerScripts.tpl'); + return $str; + } + + function createJavascriptPackageArray($releases){ + $output = "var mti_data = ["; + $count = count($releases); + $index = 1; + if(!empty($releases['packages'])){ + foreach($releases['packages'] as $release){ + $release = PackageManager::fromNameValueList($release); + $output .= "["; + $output .= "'".$release['description']."', '".$release['version']."', '".$release['build_number']."', '".$release['id']."'"; + $output .= "]"; + if($index < $count) + $output .= ","; + $index++; + } + } + $output .= "]\n;"; + return $output; + } + + function createJavascriptModuleArray($modules, $variable_name = 'mti_data'){ + $output = "var ".$variable_name." = ["; + $count = count($modules); + $index = 1; + if(!empty($modules)){ + foreach($modules as $module){ + $output .= "["; + $output .= "'".$module['name']."', '".$module['file_install']."', '".$module['file']."', '"; + if(!empty($module['enabled'])) + $output .= $module['enabled'].'_'.$module['file']."', '"; + + $description = js_escape($module['description']); + $output .= $module['type']."', '".$module['version']."', '".$module['published_date']."', '".$module['uninstallable']."', '".$description."'".(isset($module['upload_file'])?" , '".$module['upload_file']."']":"]"); + if($index < $count) + $output .= ","; + $index++; + } + + } + $output .= "]\n;"; + return $output; + } + + /** + * This method is meant to be used to display the license agreement inline on the page + * if the system would like to perform the installation on the same page via an Ajax call + */ + function buildLicenseOutput($file){ + global $current_language; + + $mod_strings = return_module_language($current_language, "Administration"); + $contents = ''; + $pm = new PackageManager(); + $contents = $pm->getLicenseFromFile($file); + $ss = new Sugar_Smarty(); + $ss->assign('MOD', $mod_strings); + $ss->assign('LICENSE_CONTENTS', $contents); + $ss->assign('FILE', $file); + $str = $ss->fetch('ModuleInstall/PackageManagerLicense.tpl'); + $GLOBALS['log']->debug('LICENSE OUTPUT: '.$str); + return $str; + } + + function getHeader(){ + global $current_language; + + $mod_strings = return_module_language($current_language, "Administration"); + $header_text = ''; + $isAlive = false; + $show_login = false; + if(!function_exists('curl_init') && $show_login){ + $header_text = "".$mod_strings['ERR_ENABLE_CURL'].""; + $show_login = false; + }else{ + $credentials = PackageManager::getCredentials(); + if(empty($credentials['username']) || empty($credentials['password'])){ + //$header_text = "".$mod_strings['ERR_CREDENTIALS_MISSING'].""; + } + else{ + $result = PackageManagerComm::login(); + if((is_array($result) && !empty($result['faultcode'])) || $result == false){ + $header_text = "".$result['faultstring'].""; + }else{ + $header_text = PackageManager::getPromotion(); + $isAlive = true; + } + } + } + return array('text' => $header_text, 'isAlive' => $isAlive, 'show_login' => $show_login); + } + + function buildInstallGrid($view){ + $uh = new UpgradeHistory(); + $installeds = $uh->getAll(); + $upgrades_installed = 0; + $installed_objects = array(); + foreach($installeds as $installed) + { + $filename = from_html($installed->filename); + $date_entered = $installed->date_entered; + $type = $installed->type; + $version = $installed->version; + $upgrades_installed++; + $link = ""; + + switch($type) + { + case "theme": + case "langpack": + case "module": + case "patch": + $manifest_file = extractManifest($filename); + require_once($manifest_file); + + $name = empty($manifest['name']) ? $filename : $manifest['name']; + $description = empty($manifest['description']) ? $mod_strings['LBL_UW_NONE'] : $manifest['description']; + if(($upgrades_installed==0 || $uh->UninstallAvailable($installeds, $installed)) + && is_file($filename) && !empty($manifest['is_uninstallable'])) + { + $link = urlencode( $filename ); + } + else + { + $link = 'false'; + } + + break; + default: + break; + } + + if($view == 'default' && $type != 'patch') + { + continue; + } + + if($view == 'module' + && $type != 'module' && $type != 'theme' && $type != 'langpack') + { + continue; + } + + $target_manifest = remove_file_extension( $filename ) . "-manifest.php"; + require_once( "$target_manifest" ); + + if(isset($manifest['icon']) && $manifest['icon'] != "") + { + $manifest_copy_files_to_dir = isset($manifest['copy_files']['to_dir']) ? clean_path($manifest['copy_files']['to_dir']) : ""; + $manifest_copy_files_from_dir = isset($manifest['copy_files']['from_dir']) ? clean_path($manifest['copy_files']['from_dir']) : ""; + $manifest_icon = clean_path($manifest['icon']); + $icon = ""; + } + else + { + $icon = getImageForType( $manifest['type'] ); + } + $installed_objects[] = array('icon' => $icon, 'name' => $name, 'type' => $type, 'version' => $version, 'date_entered' => $date_entered, 'description' => $description, 'file' => $link); + //print( "
\n" ); + //print( "$icon$name$type$version$date_entered$description$link\n" ); + //print( "
\n" ); + } + } + } +?> diff --git a/ModuleInstall/PackageManager/PackageManagerDownloader.php b/ModuleInstall/PackageManager/PackageManagerDownloader.php new file mode 100644 index 00000000..16a816a3 --- /dev/null +++ b/ModuleInstall/PackageManager/PackageManagerDownloader.php @@ -0,0 +1,72 @@ + \ No newline at end of file diff --git a/ModuleInstall/PackageManager/metadata/listviewdefs.php b/ModuleInstall/PackageManager/metadata/listviewdefs.php new file mode 100644 index 00000000..a3fbb136 --- /dev/null +++ b/ModuleInstall/PackageManager/metadata/listviewdefs.php @@ -0,0 +1,64 @@ + array( + 'width' => '5', + 'label' => 'LBL_LIST_NAME', + 'link' => false, + 'default' => true, + 'show' => true), + 'description' => array( + 'width' => '32', + 'label' => 'LBL_ML_DESCRIPTION', + 'default' => true, + 'link' => false, + 'show' => true), +); + +$listViewDefs['module_loader']['releases'] = array( + 'description' => array( + 'width' => '32', + 'label' => 'LBL_LIST_SUBJECT', + 'default' => true, + 'link' => false), + 'version' => array( + 'width' => '32', + 'label' => 'LBL_LIST_SUBJECT', + 'default' => true, + 'link' => false), +); +?> diff --git a/ModuleInstall/PackageManager/tpls/ModuleLoaderListView.tpl b/ModuleInstall/PackageManager/tpls/ModuleLoaderListView.tpl new file mode 100644 index 00000000..40f4f9f3 --- /dev/null +++ b/ModuleInstall/PackageManager/tpls/ModuleLoaderListView.tpl @@ -0,0 +1,97 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + +*} + + + + {counter start=0 name="colCounter" print=false assign="colCounter"} + + {foreach from=$displayColumns key=colHeader item=params} + {if $params.show} + + {/if} + {counter name="colCounter"} + {/foreach} + + + {foreach name=rowIteration from=$data key=package_id item=package} + {if $smarty.foreach.rowIteration.iteration is odd} + {assign var='_bgColor' value=$bgColor[0]} + {assign var='_rowColor' value=$rowColor[0]} + {else} + {assign var='_bgColor' value=$bgColor[1]} + {assign var='_rowColor' value=$rowColor[1]} + {/if} + + + + {counter start=0 name="colCounter" print=false assign="colCounter"} + {foreach from=$displayColumns key=col item=params} + + {counter name="colCounter"} + {/foreach} + + + + + {/foreach} + +
view/hide +
+ {sugar_translate label=$params.label module='Administration'} +
+
Select
Advanced  + {if $params.show} + {$package.$col} + {/if} + + Select
+ {foreach name=releaseIteration from=$package.releases key=release_id item=release} + + {counter start=0 name="colCounter" print=false assign="colCounter"} + {foreach from=$secondaryDisplayColumns key=col item=params} + + {counter name="colCounter"} + {/foreach} + + + {/foreach} +
\ No newline at end of file diff --git a/ModuleInstall/PackageManager/tpls/PackageForm.tpl b/ModuleInstall/PackageManager/tpls/PackageForm.tpl new file mode 100644 index 00000000..3acf94e6 --- /dev/null +++ b/ModuleInstall/PackageManager/tpls/PackageForm.tpl @@ -0,0 +1,106 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + *} +{$scripts} +{$TREEHEADER} +{literal} + + +{/literal} +{$INSTALLED_PACKAGES_HOLDER} +
+ +
+ +{$hidden_fields} +
+{$FORM_2_PLACE_HOLDER} +{$MODULE_SELECTOR} +
+
+
+
+{$FORM_1_PLACE_HOLDER} +
+ +{if $module_load == 'true'} +
+
+
+ +{literal} +{/literal} +{/if} + + + diff --git a/ModuleInstall/PackageManager/tpls/PackageManagerLicense.tpl b/ModuleInstall/PackageManager/tpls/PackageManagerLicense.tpl new file mode 100644 index 00000000..ad87d5cf --- /dev/null +++ b/ModuleInstall/PackageManager/tpls/PackageManagerLicense.tpl @@ -0,0 +1,51 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + *} + + + + + + + + + + + + + +
{$MOD.LBL_MODULE_LICENSE}
{$MOD.LBL_ACCEPT} {$MOD.LBL_DENY}
\ No newline at end of file diff --git a/ModuleInstall/PackageManager/tpls/PackageManagerScripts.tpl b/ModuleInstall/PackageManager/tpls/PackageManagerScripts.tpl new file mode 100644 index 00000000..907450bf --- /dev/null +++ b/ModuleInstall/PackageManager/tpls/PackageManagerScripts.tpl @@ -0,0 +1,1085 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} + +{literal} + +{/literal} diff --git a/SugarSecurity.php b/SugarSecurity.php new file mode 100644 index 00000000..eacc9692 --- /dev/null +++ b/SugarSecurity.php @@ -0,0 +1,167 @@ +'; + foreach($this->results as $result){ + echo '' . nl2br($result) . ''; + } + echo ''; + } + + function save($file=''){ + $fp = fopen($file, 'a'); + foreach($this->results as $result){ + fwrite($fp , $result); + } + fclose($fp); + } + + function scan($path= '.', $ext = '.php'){ + $dir = dir($path); + while($entry = $dir->read()){ + if(is_dir($path . '/' . $entry) && $entry != '.' && $entry != '..'){ + $this->scan($path .'/' . $entry); + } + if(is_file($path . '/'. $entry) && substr($entry, strlen($entry) - strlen($ext), strlen($ext)) == $ext){ + $contents = file_get_contents($path .'/'. $entry); + $this->scanContents($contents, $path .'/'. $entry); + } + } + } + + function scanContents($contents){ + return; + } + + +} + +class ScanFileIncludes extends SugarSecure{ + function scanContents($contents, $file){ + $results = array(); + $found = ''; + /*preg_match_all("'(require_once\([^\)]*\\$[^\)]*\))'si", $contents, $results, PREG_SET_ORDER); + foreach($results as $result){ + + $found .= "\n" . $result[0]; + } + $results = array(); + preg_match_all("'include_once\([^\)]*\\$[^\)]*\)'si", $contents, $results, PREG_SET_ORDER); + foreach($results as $result){ + $found .= "\n" . $result[0]; + } + */ + $results = array(); + preg_match_all("'require\([^\)]*\\$[^\)]*\)'si", $contents, $results, PREG_SET_ORDER); + foreach($results as $result){ + $found .= "\n" . $result[0]; + } + $results = array(); + preg_match_all("'include\([^\)]*\\$[^\)]*\)'si", $contents, $results, PREG_SET_ORDER); + foreach($results as $result){ + $found .= "\n" . $result[0]; + } + $results = array(); + preg_match_all("'require_once\([^\)]*\\$[^\)]*\)'si", $contents, $results, PREG_SET_ORDER); + foreach($results as $result){ + $found .= "\n" . $result[0]; + } + $results = array(); + preg_match_all("'fopen\([^\)]*\\$[^\)]*\)'si", $contents, $results, PREG_SET_ORDER); + foreach($results as $result){ + $found .= "\n" . $result[0]; + } + $results = array(); + preg_match_all("'file_get_contents\([^\)]*\\$[^\)]*\)'si", $contents, $results, PREG_SET_ORDER); + foreach($results as $result){ + $found .= "\n" . $result[0]; + } + if(!empty($found)){ + $this->results[] = $file . $found."\n\n"; + } + + } + + +} + + + +class SugarSecureManager{ + var $scanners = array(); + function registerScan($class){ + $this->scanners[] = new $class(); + } + + function scan(){ + + while($scanner = current($this->scanners)){ + $scanner->scan(); + $scanner = next($this->scanners); + } + reset($this->scanners); + } + + function display(){ + + while($scanner = current($this->scanners)){ + echo 'Scan Results: '; + $scanner->display(); + $scanner = next($this->scanners); + } + reset($this->scanners); + } + + function save(){ + //reset($this->scanners); + $name = 'SugarSecure'. time() . '.txt'; + while($this->scanners = next($this->scanners)){ + $scanner->save($name); + } + } + +} +$secure = new SugarSecureManager(); +$secure->registerScan('ScanFileIncludes'); +$secure->scan(); +$secure->display(); \ No newline at end of file diff --git a/TreeData.php b/TreeData.php new file mode 100644 index 00000000..9ba25da9 --- /dev/null +++ b/TreeData.php @@ -0,0 +1,146 @@ +debug("TreeData:session started"); +$current_language = $GLOBALS['current_language']; + +//process request parameters. consider following parameters. +//function, and all parameters prefixed with PARAM. +//PARAMT_ are tree level parameters. +//PARAMN_ are node level parameters. +//module name and function name parameters are the only ones consumed +//by this file.. +foreach ($_REQUEST as $key=>$value) { + + switch ($key) { + + case "function": + case "call_back_function": + $func_name=$value; + $params1['TREE']['function']=$value; + break; + + default: + $pssplit=explode('_',$key); + if ($pssplit[0] =='PARAMT') { + unset($pssplit[0]); + $params1['TREE'][implode('_',$pssplit)]=$value; + } else { + if ($pssplit[0] =='PARAMN') { + $depth=$pssplit[count($pssplit)-1]; + //parmeter is surrounded by PARAMN_ and depth info. + unset($pssplit[count($pssplit)-1]);unset($pssplit[0]); + $params1['NODES'][$depth][implode('_',$pssplit)]=$value; + } else { + if ($key=='module') { + if (!isset($params1['TREE']['module'])) { + $params1['TREE'][$key]=$value; + } + } else { + $params1['REQUEST'][$key]=$value; + } + } + } + } +} +$modulename=$params1['TREE']['module']; ///module is a required parameter for the tree. +require('include/modules.php'); +if (!empty($modulename) && !empty($func_name) && isset($beanList[$modulename]) ) { + require_once('modules/'.$modulename.'/TreeData.php'); + $TreeDataFunctions = array( + 'ProductTemplates' => array('get_node_data'=>'','get_categories_and_products'=>''), + 'ProductCategories' => array('get_node_data'=>'','get_product_categories'=>''), + 'KBTags' => array( + 'get_node_data'=>'', + 'get_tags_nodes'=>'', + 'get_tags_nodes_cached'=>'', + 'childNodes'=>'', + 'get_searched_tags_nodes'=>'', + 'find_peers'=>'', + 'getRootNode'=>'', + 'getParentNode'=>'', + 'get_tags_modal_nodes'=>'', + 'get_admin_browse_articles'=>'', + 'tagged_documents_count'=>'', + 'tag_count'=>'', + 'get_browse_documents'=>'', + 'get_tag_nodes_for_browsing'=>'', + 'create_browse_node'=>'', + 'untagged_documents_count'=>'', + 'check_tag_child_tags_for_articles'=>'', + 'childTagsHaveArticles'=>'', + ), + 'KBDocuments' => array( + 'get_node_data'=>'', + 'get_category_nodes'=>'', + 'get_documents'=>'', + ), + 'Forecasts' => array( + 'get_node_data'=>'', + 'get_worksheet'=>'', + 'commit_forecast'=>'', + 'save_worksheet'=>'', + 'list_nav'=>'', + 'reset_worksheet'=>'', + 'get_chart'=>'', + ), + 'Documents' => array( + 'get_node_data'=>'', + 'get_category_nodes'=>'', + 'get_documents'=>'', + ), + ); + + if (isset($TreeDataFunctions[$modulename][$func_name])) { + $ret=call_user_func($func_name,$params1); + } +} + +if (!empty($ret)) { + echo $ret; +} + +?> diff --git a/WebToLeadCapture.php b/WebToLeadCapture.php new file mode 100644 index 00000000..c37fc5a7 --- /dev/null +++ b/WebToLeadCapture.php @@ -0,0 +1,47 @@ + \ No newline at end of file diff --git a/XTemplate/LICENSE b/XTemplate/LICENSE new file mode 100644 index 00000000..551cb4ac --- /dev/null +++ b/XTemplate/LICENSE @@ -0,0 +1,502 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +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 and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, 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 library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete 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 distribute a copy of this License along with the +Library. + + 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 Library or any portion +of it, thus forming a work based on the Library, 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) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +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 Library, 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 Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you 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. + + If distribution of 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 satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be 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. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library 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. + + 9. 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 Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +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 with +this License. + + 11. 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 Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library 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 Library. + +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. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library 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. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser 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 Library +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 Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +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 + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "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 +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. 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 LIBRARY 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 +LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), 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 Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. 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 library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License 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. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/XTemplate/xtpl.php b/XTemplate/xtpl.php new file mode 100644 index 00000000..3ce660fb --- /dev/null +++ b/XTemplate/xtpl.php @@ -0,0 +1,567 @@ + 14-march-2001 + latest stable & CVS version always available @ http://sourceforge.net/projects/xtpl + + tested with php 3.0.11 and 4.0.4pl1 + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License + version 2.1 as published by the Free Software Foundation. + + 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. See the + GNU Lesser General Public License for more details at + http://www.gnu.org/copyleft/lgpl.html + + 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. + + +*/ + +/***[ variables ]***********************************************************/ + +var $filecontents=""; /* raw contents of template file */ +var $blocks=array(); /* unparsed blocks */ +var $parsed_blocks=array(); /* parsed blocks */ +var $block_parse_order=array(); /* block parsing order for recursive parsing (sometimes reverse:) */ +var $sub_blocks=array(); /* store sub-block names for fast resetting */ +var $VARS=array(); /* variables array */ +var $alternate_include_directory = ""; + +var $file_delim="/\{FILE\s*\"([^\"]+)\"\s*\}/m"; /* regexp for file includes */ +var $block_start_delim=""; /* block end delimiter */ +var $block_start_word="BEGIN:"; /* block start word */ +var $block_end_word="END:"; /* block end word */ + +/* this makes the delimiters look like: if you use my syntax. */ + +var $NULL_STRING=array(""=>""); /* null string for unassigned vars */ +var $NULL_BLOCK=array(""=>""); /* null string for unassigned blocks */ +var $mainblock=""; +var $ERROR=""; +var $AUTORESET=1; /* auto-reset sub blocks */ + +/***[ constructor ]*********************************************************/ + +function XTemplate ($file, $alt_include = "", $mainblock="main") { + $this->alternate_include_directory = $alt_include; + $this->mainblock=$mainblock; + $this->filecontents=$this->r_getfile($file); /* read in template file */ + //if(substr_count($file, 'backup') == 1)_ppd($this->filecontents); + $this->blocks=$this->maketree($this->filecontents,$mainblock); /* preprocess some stuff */ + //$this->scan_globals(); +} + + +/***************************************************************************/ +/***[ public stuff ]********************************************************/ +/***************************************************************************/ + + +/***[ assign ]**************************************************************/ +/* + assign a variable +*/ + +function assign ($name,$val="") { + if (is_array($name)) { + foreach ($name as $k => $v) { + $this->VARS[$k] = $v; + } + } else { + $this->VARS[$name]=$val; + } +} + +function append ($varname, $name,$val="") { + if(!isset($this->VARS[$varname])){ + $this->VARS[$varname] = array(); + } + if(is_array($this->VARS[$varname])){ + $this->VARS[$varname][$name] = $val; + } +} + +/***[ parse ]***************************************************************/ +/* + parse a block +*/ + +function parse ($bname) { + global $sugar_version, $sugar_config; + + $this->assign('SUGAR_VERSION', $GLOBALS['js_version_key']); + $this->assign('JS_CUSTOM_VERSION', $sugar_config['js_custom_version']); + + if(empty($this->blocks[$bname])) + return; + + $copy=$this->blocks[$bname]; + if (!isset($this->blocks[$bname])) + $this->set_error ("parse: blockname [$bname] does not exist"); + preg_match_all("/\{([A-Za-z0-9\._]+?)}/",$this->blocks[$bname],$var_array); + $var_array=$var_array[1]; + foreach ($var_array as $k => $v) { + $sub=explode(".",$v); + if ($sub[0]=="_BLOCK_") { + unset($sub[0]); + $bname2=implode(".",$sub); + + if(isset($this->parsed_blocks[$bname2])) + { + $var=$this->parsed_blocks[$bname2]; + } + else + { + $var = null; + } + + $nul=(!isset($this->NULL_BLOCK[$bname2])) ? $this->NULL_BLOCK[""] : $this->NULL_BLOCK[$bname2]; + $var=(empty($var))?$nul:trim($var); + // Commented out due to regular expression issue with '$' in replacement string. + //$copy=preg_replace("/\{".$v."\}/","$var",$copy); + // This should be faster and work better for '$' + $copy=str_replace("{".$v."}",$var,$copy); + } else { + $var=$this->VARS; + + foreach ($sub as $k1 => $v1) + { + if(is_array($var) && isset($var[$v1])) + { + $var=$var[$v1]; + } + else + { + $var = null; + } + } + + $nul=(!isset($this->NULL_STRING[$v])) ? ($this->NULL_STRING[""]) : ($this->NULL_STRING[$v]); + $var=(!isset($var))?$nul:$var; + // Commented out due to regular expression issue with '$' in replacement string. + //$copy=preg_replace("/\{$v\}/","$var",$copy); + // This should be faster and work better for '$' + + // this was periodically returning an array to string conversion error.... + if(!is_array($var)) + { + $copy=str_replace("{".$v."}",$var,$copy); + } + } + } + + if(isset($this->parsed_blocks[$bname])) + { + $this->parsed_blocks[$bname].=$copy; + } + else + { + $this->parsed_blocks[$bname]=$copy; + } + + // reset sub-blocks + if ($this->AUTORESET && (!empty($this->sub_blocks[$bname]))) { + reset($this->sub_blocks[$bname]); + foreach ($this->sub_blocks[$bname] as $v) + $this->reset($v); + } +} + +/***[ exists ]**************************************************************/ +/* + returns true if a block exists otherwise returns false. +*/ +function exists($bname){ + return (!empty($this->parsed_blocks[$bname])) || (!empty($this->blocks[$bname])); +} + + +/***[ var_exists ]**************************************************************/ +/* + returns true if a block exists otherwise returns false. +*/ +function var_exists($bname,$vname){ + if(!empty($this->blocks[$bname])){ + return substr_count($this->blocks[$bname], '{'. $vname . '}') >0; + } + return false; +} + + +/***[ rparse ]**************************************************************/ +/* + returns the parsed text for a block, including all sub-blocks. +*/ + +function rparse($bname) { + if (!empty($this->sub_blocks[$bname])) { + reset($this->sub_blocks[$bname]); + while (list($k,$v)=each($this->sub_blocks[$bname])) + if (!empty($v)) + $this->rparse($v,$indent."\t"); + } + $this->parse($bname); +} + +/***[ insert_loop ]*********************************************************/ +/* + inserts a loop ( call assign & parse ) +*/ + +function insert_loop($bname,$var,$value="") { + $this->assign($var,$value); + $this->parse($bname); +} + +/***[ text ]****************************************************************/ +/* + returns the parsed text for a block +*/ + +function text($bname) { + + if(!empty($this->parsed_blocks)){ + return $this->parsed_blocks[isset($bname) ? $bname :$this->mainblock]; + }else{ + return ''; + } +} + +/***[ out ]*****************************************************************/ +/* + prints the parsed text +*/ + +function out ($bname) { + global $focus; + + if(isset($focus)){ + global $action; + + if($focus && is_subclass_of($focus, 'SugarBean') && !$focus->ACLAccess($action)){ + + ACLController::displayNoAccess(true); + + sugar_die(''); + return; + }} + + echo $this->text($bname); +} + +/***[ reset ]***************************************************************/ +/* + resets the parsed text +*/ + +function reset ($bname) { + $this->parsed_blocks[$bname]=""; +} + +/***[ parsed ]**************************************************************/ +/* + returns true if block was parsed, false if not +*/ + +function parsed ($bname) { + return (!empty($this->parsed_blocks[$bname])); +} + +/***[ SetNullString ]*******************************************************/ +/* + sets the string to replace in case the var was not assigned +*/ + +function SetNullString($str,$varname="") { + $this->NULL_STRING[$varname]=$str; +} + +/***[ SetNullBlock ]********************************************************/ +/* + sets the string to replace in case the block was not parsed +*/ + +function SetNullBlock($str,$bname="") { + $this->NULL_BLOCK[$bname]=$str; +} + +/***[ set_autoreset ]*******************************************************/ +/* + sets AUTORESET to 1. (default is 1) + if set to 1, parse() automatically resets the parsed blocks' sub blocks + (for multiple level blocks) +*/ + +function set_autoreset() { + $this->AUTORESET=1; +} + +/***[ clear_autoreset ]*****************************************************/ +/* + sets AUTORESET to 0. (default is 1) + if set to 1, parse() automatically resets the parsed blocks' sub blocks + (for multiple level blocks) +*/ + +function clear_autoreset() { + $this->AUTORESET=0; +} + +/***[ scan_globals ]********************************************************/ +/* + scans global variables +*/ + +function scan_globals() { + reset($GLOBALS); + while (list($k,$v)=each($GLOBALS)) + $GLOB[$k]=$v; + $this->assign("PHP",$GLOB); /* access global variables as {PHP.HTTP_HOST} in your template! */ +} + +/****** + + WARNING + PUBLIC FUNCTIONS BELOW THIS LINE DIDN'T GET TESTED + +******/ + + +/***************************************************************************/ +/***[ private stuff ]*******************************************************/ +/***************************************************************************/ + +/***[ maketree ]************************************************************/ +/* + generates the array containing to-be-parsed stuff: + $blocks["main"],$blocks["main.table"],$blocks["main.table.row"], etc. + also builds the reverse parse order. +*/ + + +function maketree($con,$block) { + $con2=explode($this->block_start_delim,$con); + $level=0; + $block_names=array(); + $blocks=array(); + reset($con2); + while(list($k,$v)=each($con2)) { + $patt="($this->block_start_word|$this->block_end_word)\s*(\w+)\s*$this->block_end_delim(.*)"; + if (preg_match_all("/$patt/ims",$v,$res, PREG_SET_ORDER)) { + // $res[0][1] = BEGIN or END + // $res[0][2] = block name + // $res[0][3] = kinda content + if ($res[0][1]==$this->block_start_word) { + $parent_name=implode(".",$block_names); + $block_names[++$level]=$res[0][2]; /* add one level - array("main","table","row")*/ + $cur_block_name=implode(".",$block_names); /* make block name (main.table.row) */ + $this->block_parse_order[]=$cur_block_name; /* build block parsing order (reverse) */ + + if(array_key_exists($cur_block_name, $blocks)) + { + $blocks[$cur_block_name].=$res[0][3]; /* add contents */ + } + else + { + $blocks[$cur_block_name]=$res[0][3]; /* add contents */ + } + + /* add {_BLOCK_.blockname} string to parent block */ + if(array_key_exists($parent_name, $blocks)) + { + $blocks[$parent_name].="{_BLOCK_.$cur_block_name}"; + } + else + { + $blocks[$parent_name]="{_BLOCK_.$cur_block_name}"; + } + + $this->sub_blocks[$parent_name][]=$cur_block_name; /* store sub block names for autoresetting and recursive parsing */ + $this->sub_blocks[$cur_block_name][]=""; /* store sub block names for autoresetting */ + } else if ($res[0][1]==$this->block_end_word) { + unset($block_names[$level--]); + $parent_name=implode(".",$block_names); + $blocks[$parent_name].=$res[0][3]; /* add rest of block to parent block */ + } + } else { /* no block delimiters found */ + $index = implode(".",$block_names); + if(array_key_exists($index, $blocks)) + { + $blocks[].=$this->block_start_delim.$v; + } + else + { + $blocks[]=$this->block_start_delim.$v; + } + } + } + return $blocks; +} + + + +/***[ error stuff ]*********************************************************/ +/* + sets and gets error +*/ + +function get_error() { + return ($this->ERROR=="")?0:$this->ERROR; +} + + +function set_error($str) { + $this->ERROR=$str; +} + +/***[ getfile ]*************************************************************/ +/* + returns the contents of a file +*/ + +function getfile($file) { + if (!isset($file)) { + $this->set_error("!isset file name!"); + return ""; + } + + // Pick which folder we should include from + // Prefer the local directory, then try the theme directory. + if (!is_file($file)) + $file = $this->alternate_include_directory.$file; + + if(is_file($file)) + { + $file_text=file_get_contents($file); + + } else { + $this->set_error("[$file] does not exist"); + $file_text="__XTemplate fatal error: file [$file] does not exist__"; + } + + return $file_text; +} + +/***[ r_getfile ]***********************************************************/ +/* + recursively gets the content of a file with {FILE "filename.tpl"} directives +*/ + + +function r_getfile($file) { + $text=$this->getfile($file); + while (preg_match($this->file_delim,$text,$res)) { + $text2=$this->getfile($res[1]); + $text=preg_replace("'".preg_quote($res[0])."'",$text2,$text); + } + return $text; +} + +} /* end of XTemplate class. */ + +?> diff --git a/Zend/Crypt.php b/Zend/Crypt.php new file mode 100644 index 00000000..a05d9e0a --- /dev/null +++ b/Zend/Crypt.php @@ -0,0 +1,167 @@ +setPrime($prime); + $this->setGenerator($generator); + if ($privateKey !== null) { + $this->setPrivateKey($privateKey, $privateKeyType); + } + $this->setBigIntegerMath(); + } + + /** + * Generate own public key. If a private number has not already been + * set, one will be generated at this stage. + * + * @return Zend_Crypt_DiffieHellman + */ + public function generateKeys() + { + if (function_exists('openssl_dh_compute_key') && self::$useOpenssl !== false) { + $details = array(); + $details['p'] = $this->getPrime(); + $details['g'] = $this->getGenerator(); + if ($this->hasPrivateKey()) { + $details['priv_key'] = $this->getPrivateKey(); + } + $opensslKeyResource = openssl_pkey_new( array('dh' => $details) ); + $data = openssl_pkey_get_details($opensslKeyResource); + $this->setPrivateKey($data['dh']['priv_key'], self::BINARY); + $this->setPublicKey($data['dh']['pub_key'], self::BINARY); + } else { + // Private key is lazy generated in the absence of PHP 5.3's ext/openssl + $publicKey = $this->_math->powmod($this->getGenerator(), $this->getPrivateKey(), $this->getPrime()); + $this->setPublicKey($publicKey); + } + return $this; + } + + /** + * Setter for the value of the public number + * + * @param string $number + * @param string $type + * @return Zend_Crypt_DiffieHellman + */ + public function setPublicKey($number, $type = self::NUMBER) + { + if ($type == self::BINARY) { + $number = $this->_math->fromBinary($number); + } + if (!preg_match("/^\d+$/", $number)) { + require_once('Zend/Crypt/DiffieHellman/Exception.php'); + throw new Zend_Crypt_DiffieHellman_Exception('invalid parameter; not a positive natural number'); + } + $this->_publicKey = (string) $number; + return $this; + } + + /** + * Returns own public key for communication to the second party to this + * transaction. + * + * @param string $type + * @return string + */ + public function getPublicKey($type = self::NUMBER) + { + if ($this->_publicKey === null) { + require_once 'Zend/Crypt/DiffieHellman/Exception.php'; + throw new Zend_Crypt_DiffieHellman_Exception('A public key has not yet been generated using a prior call to generateKeys()'); + } + if ($type == self::BINARY) { + return $this->_math->toBinary($this->_publicKey); + } elseif ($type == self::BTWOC) { + return $this->_math->btwoc($this->_math->toBinary($this->_publicKey)); + } + return $this->_publicKey; + } + + /** + * Compute the shared secret key based on the public key received from the + * the second party to this transaction. This should agree to the secret + * key the second party computes on our own public key. + * Once in agreement, the key is known to only to both parties. + * By default, the function expects the public key to be in binary form + * which is the typical format when being transmitted. + * + * If you need the binary form of the shared secret key, call + * getSharedSecretKey() with the optional parameter for Binary output. + * + * @param string $publicKey + * @param string $type + * @return mixed + */ + public function computeSecretKey($publicKey, $type = self::NUMBER, $output = self::NUMBER) + { + if ($type == self::BINARY) { + $publicKey = $this->_math->fromBinary($publicKey); + } + if (!preg_match("/^\d+$/", $publicKey)) { + require_once('Zend/Crypt/DiffieHellman/Exception.php'); + throw new Zend_Crypt_DiffieHellman_Exception('invalid parameter; not a positive natural number'); + } + if (function_exists('openssl_dh_compute_key') && self::$useOpenssl !== false) { + $this->_secretKey = openssl_dh_compute_key($publicKey, $this->getPublicKey()); + } else { + $this->_secretKey = $this->_math->powmod($publicKey, $this->getPrivateKey(), $this->getPrime()); + } + return $this->getSharedSecretKey($output); + } + + /** + * Return the computed shared secret key from the DiffieHellman transaction + * + * @param string $type + * @return string + */ + public function getSharedSecretKey($type = self::NUMBER) + { + if (!isset($this->_secretKey)) { + require_once('Zend/Crypt/DiffieHellman/Exception.php'); + throw new Zend_Crypt_DiffieHellman_Exception('A secret key has not yet been computed; call computeSecretKey()'); + } + if ($type == self::BINARY) { + return $this->_math->toBinary($this->_secretKey); + } elseif ($type == self::BTWOC) { + return $this->_math->btwoc($this->_math->toBinary($this->_secretKey)); + } + return $this->_secretKey; + } + + /** + * Setter for the value of the prime number + * + * @param string $number + * @return Zend_Crypt_DiffieHellman + */ + public function setPrime($number) + { + if (!preg_match("/^\d+$/", $number) || $number < 11) { + require_once('Zend/Crypt/DiffieHellman/Exception.php'); + throw new Zend_Crypt_DiffieHellman_Exception('invalid parameter; not a positive natural number or too small: should be a large natural number prime'); + } + $this->_prime = (string) $number; + return $this; + } + + /** + * Getter for the value of the prime number + * + * @return string + */ + public function getPrime() + { + if (!isset($this->_prime)) { + require_once('Zend/Crypt/DiffieHellman/Exception.php'); + throw new Zend_Crypt_DiffieHellman_Exception('No prime number has been set'); + } + return $this->_prime; + } + + + /** + * Setter for the value of the generator number + * + * @param string $number + * @return Zend_Crypt_DiffieHellman + */ + public function setGenerator($number) + { + if (!preg_match("/^\d+$/", $number) || $number < 2) { + require_once('Zend/Crypt/DiffieHellman/Exception.php'); + throw new Zend_Crypt_DiffieHellman_Exception('invalid parameter; not a positive natural number greater than 1'); + } + $this->_generator = (string) $number; + return $this; + } + + /** + * Getter for the value of the generator number + * + * @return string + */ + public function getGenerator() + { + if (!isset($this->_generator)) { + require_once('Zend/Crypt/DiffieHellman/Exception.php'); + throw new Zend_Crypt_DiffieHellman_Exception('No generator number has been set'); + } + return $this->_generator; + } + + /** + * Setter for the value of the private number + * + * @param string $number + * @param string $type + * @return Zend_Crypt_DiffieHellman + */ + public function setPrivateKey($number, $type = self::NUMBER) + { + if ($type == self::BINARY) { + $number = $this->_math->fromBinary($number); + } + if (!preg_match("/^\d+$/", $number)) { + require_once('Zend/Crypt/DiffieHellman/Exception.php'); + throw new Zend_Crypt_DiffieHellman_Exception('invalid parameter; not a positive natural number'); + } + $this->_privateKey = (string) $number; + return $this; + } + + /** + * Getter for the value of the private number + * + * @param string $type + * @return string + */ + public function getPrivateKey($type = self::NUMBER) + { + if (!$this->hasPrivateKey()) { + $this->setPrivateKey($this->_generatePrivateKey(), self::BINARY); + } + if ($type == self::BINARY) { + return $this->_math->toBinary($this->_privateKey); + } elseif ($type == self::BTWOC) { + return $this->_math->btwoc($this->_math->toBinary($this->_privateKey)); + } + return $this->_privateKey; + } + + /** + * Check whether a private key currently exists. + * + * @return boolean + */ + public function hasPrivateKey() + { + return isset($this->_privateKey); + } + + /** + * Setter to pass an extension parameter which is used to create + * a specific BigInteger instance for a specific extension type. + * Allows manual setting of the class in case of an extension + * problem or bug. + * + * @param string $extension + * @return void + */ + public function setBigIntegerMath($extension = null) + { + /** + * @see Zend_Crypt_Math + */ + require_once 'Zend/Crypt/Math.php'; + $this->_math = new Zend_Crypt_Math($extension); + } + + /** + * In the event a private number/key has not been set by the user, + * or generated by ext/openssl, a best attempt will be made to + * generate a random key. Having a random number generator installed + * on linux/bsd is highly recommended! The alternative is not recommended + * for production unless without any other option. + * + * @return string + */ + protected function _generatePrivateKey() + { + $rand = $this->_math->rand($this->getGenerator(), $this->getPrime()); + return $rand; + } + +} diff --git a/Zend/Crypt/DiffieHellman/Exception.php b/Zend/Crypt/DiffieHellman/Exception.php new file mode 100644 index 00000000..a41b2165 --- /dev/null +++ b/Zend/Crypt/DiffieHellman/Exception.php @@ -0,0 +1,36 @@ +80 using internal algo) + * @todo Check if mhash() is a required alternative (will be PECL-only soon) + * @category Zend + * @package Zend_Crypt + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +class Zend_Crypt_Hmac extends Zend_Crypt +{ + + /** + * The key to use for the hash + * + * @var string + */ + protected static $_key = null; + + /** + * pack() format to be used for current hashing method + * + * @var string + */ + protected static $_packFormat = null; + + /** + * Hashing algorithm; can be the md5/sha1 functions or any algorithm name + * listed in the output of PHP 5.1.2+ hash_algos(). + * + * @var string + */ + protected static $_hashAlgorithm = 'md5'; + + /** + * List of algorithms supported my mhash() + * + * @var array + */ + protected static $_supportedMhashAlgorithms = array('adler32',' crc32', 'crc32b', 'gost', + 'haval128', 'haval160', 'haval192', 'haval256', 'md4', 'md5', 'ripemd160', + 'sha1', 'sha256', 'tiger', 'tiger128', 'tiger160'); + + /** + * Constants representing the output mode of the hash algorithm + */ + const STRING = 'string'; + const BINARY = 'binary'; + + /** + * Performs a HMAC computation given relevant details such as Key, Hashing + * algorithm, the data to compute MAC of, and an output format of String, + * Binary notation or BTWOC. + * + * @param string $key + * @param string $hash + * @param string $data + * @param string $output + * @param boolean $internal + * @return string + */ + public static function compute($key, $hash, $data, $output = self::STRING) + { + // set the key + if (!isset($key) || empty($key)) { + require_once 'Zend/Crypt/Hmac/Exception.php'; + throw new Zend_Crypt_Hmac_Exception('provided key is null or empty'); + } + self::$_key = $key; + + // set the hash + self::_setHashAlgorithm($hash); + + // perform hashing and return + return self::_hash($data, $output); + } + + /** + * Setter for the hash method. + * + * @param string $hash + * @return Zend_Crypt_Hmac + */ + protected static function _setHashAlgorithm($hash) + { + if (!isset($hash) || empty($hash)) { + require_once 'Zend/Crypt/Hmac/Exception.php'; + throw new Zend_Crypt_Hmac_Exception('provided hash string is null or empty'); + } + + $hash = strtolower($hash); + $hashSupported = false; + + if (function_exists('hash_algos') && in_array($hash, hash_algos())) { + $hashSupported = true; + } + + if ($hashSupported === false && function_exists('mhash') && in_array($hash, self::$_supportedAlgosMhash)) { + $hashSupported = true; + } + + if ($hashSupported === false) { + require_once 'Zend/Crypt/Hmac/Exception.php'; + throw new Zend_Crypt_Hmac_Exception('hash algorithm provided is not supported on this PHP installation; please enable the hash or mhash extensions'); + } + self::$_hashAlgorithm = $hash; + } + + /** + * Perform HMAC and return the keyed data + * + * @param string $data + * @param string $output + * @param bool $internal Option to not use hash() functions for testing + * @return string + */ + protected static function _hash($data, $output = self::STRING, $internal = false) + { + if (function_exists('hash_hmac')) { + if ($output == self::BINARY) { + return hash_hmac(self::$_hashAlgorithm, $data, self::$_key, 1); + } + return hash_hmac(self::$_hashAlgorithm, $data, self::$_key); + } + + if (function_exists('mhash')) { + if ($output == self::BINARY) { + return mhash(self::_getMhashDefinition(self::$_hashAlgorithm), $data, self::$_key); + } + $bin = mhash(self::_getMhashDefinition(self::$_hashAlgorithm), $data, self::$_key); + return bin2hex($bin); + } + } + + /** + * Since MHASH accepts an integer constant representing the hash algorithm + * we need to make a small detour to get the correct integer matching our + * algorithm's name. + * + * @param string $hashAlgorithm + * @return integer + */ + protected static function _getMhashDefinition($hashAlgorithm) + { + for ($i = 0; $i <= mhash_count(); $i++) + { + $types[mhash_get_hash_name($i)] = $i; + } + return $types[strtoupper($hashAlgorithm)]; + } + +} \ No newline at end of file diff --git a/Zend/Crypt/Hmac/Exception.php b/Zend/Crypt/Hmac/Exception.php new file mode 100644 index 00000000..2563c985 --- /dev/null +++ b/Zend/Crypt/Hmac/Exception.php @@ -0,0 +1,36 @@ + 127) { + return "\x00" . $long; + } + return $long; + } + + /** + * Translate a binary form into a big integer string + * + * @param string $binary + * @return string + */ + public function fromBinary($binary) { + return $this->_math->binaryToInteger($binary); + } + + /** + * Translate a big integer string into a binary form + * + * @param string $integer + * @return string + */ + public function toBinary($integer) + { + return $this->_math->integerToBinary($integer); + } + +} diff --git a/Zend/Crypt/Math/BigInteger.php b/Zend/Crypt/Math/BigInteger.php new file mode 100644 index 00000000..e5c4427c --- /dev/null +++ b/Zend/Crypt/Math/BigInteger.php @@ -0,0 +1,117 @@ +_loadAdapter($extension); + } + + /** + * Redirect all public method calls to the wrapped extension object. + * + * @param string $methodName + * @param array $args + * @throws Zend_Crypt_Math_BigInteger_Exception + */ + public function __call($methodName, $args) + { + if(!method_exists($this->_math, $methodName)) { + require_once 'Zend/Crypt/Math/BigInteger/Exception.php'; + throw new Zend_Crypt_Math_BigInteger_Exception('invalid method call: ' . get_class($this->_math) . '::' . $methodName . '() does not exist'); + } + return call_user_func_array(array($this->_math, $methodName), $args); + } + + /** + * @param string $extension + * @throws Zend_Crypt_Math_BigInteger_Exception + */ + protected function _loadAdapter($extension = null) + { + if ($extension === null) { + if (extension_loaded('gmp')) { + $extension = 'gmp'; + //} elseif (extension_loaded('big_int')) { + // $extension = 'big_int'; + } else { + $extension = 'bcmath'; + } + } + if($extension == 'gmp' && extension_loaded('gmp')) { + require_once 'Zend/Crypt/Math/BigInteger/Gmp.php'; + $this->_math = new Zend_Crypt_Math_BigInteger_Gmp(); + //} elseif($extension == 'bigint' && extension_loaded('big_int')) { + // require_once 'Zend/Crypt_Math/BigInteger/Bigint.php'; + // $this->_math = new Zend_Crypt_Math_BigInteger_Bigint(); + } elseif ($extension == 'bcmath') { + require_once 'Zend/Crypt/Math/BigInteger/Bcmath.php'; + $this->_math = new Zend_Crypt_Math_BigInteger_Bcmath(); + } else { + require_once 'Zend/Crypt/Math/BigInteger/Exception.php'; + throw new Zend_Crypt_Math_BigInteger_Exception($extension . ' big integer precision math support not detected'); + } + } + +} \ No newline at end of file diff --git a/Zend/Crypt/Math/BigInteger/Bcmath.php b/Zend/Crypt/Math/BigInteger/Bcmath.php new file mode 100644 index 00000000..0d83ffc5 --- /dev/null +++ b/Zend/Crypt/Math/BigInteger/Bcmath.php @@ -0,0 +1,203 @@ + 0) { + $return = chr(bcmod($operand, 256)) . $return; + $operand = bcdiv($operand, 256); + } + if (ord($return[0]) > 127) { + $return = "\0" . $return; + } + return $return; + } + + /**public function integerToBinary($operand) + { + $return = ''; + while(bccomp($operand, '0')) { + $return .= chr(bcmod($operand, '256')); + $operand = bcdiv($operand, '256'); + } + return $return; + }**/ // Prior version for referenced offset + + + public function hexToDecimal($operand) + { + $return = '0'; + while(strlen($hex)) { + $hex = hexdec(substr($operand, 0, 4)); + $dec = bcadd(bcmul($return, 65536), $hex); + $operand = substr($operand, 4); + } + return $return; + } + +} \ No newline at end of file diff --git a/Zend/Crypt/Math/BigInteger/Exception.php b/Zend/Crypt/Math/BigInteger/Exception.php new file mode 100644 index 00000000..66fd8bc4 --- /dev/null +++ b/Zend/Crypt/Math/BigInteger/Exception.php @@ -0,0 +1,36 @@ + '7') { + $bigInt = '00' . $bigInt; + } + $return = pack("H*", $bigInt); + return $return; + } + + + public function hexToDecimal($operand) + { + $return = '0'; + while(strlen($hex)) { + $hex = hexdec(substr($operand, 0, 4)); + $dec = gmp_add(gmp_mul($return, 65536), $hex); + $operand = substr($operand, 4); + } + return $return; + } + +} \ No newline at end of file diff --git a/Zend/Crypt/Math/BigInteger/Interface.php b/Zend/Crypt/Math/BigInteger/Interface.php new file mode 100644 index 00000000..cf7aea10 --- /dev/null +++ b/Zend/Crypt/Math/BigInteger/Interface.php @@ -0,0 +1,51 @@ +setOptions($options); + } + } + + public function setOptions(array $options) + { + if (isset($options['passPhrase'])) { + $this->_passPhrase = $options['passPhrase']; + } + foreach ($options as $option=>$value) { + switch ($option) { + case 'pemString': + $this->setPemString($value); + break; + case 'pemPath': + $this->setPemPath($value); + break; + case 'certificateString': + $this->setCertificateString($value); + break; + case 'certificatePath': + $this->setCertificatePath($value); + break; + case 'hashAlgorithm': + $this->setHashAlgorithm($value); + break; + } + } + } + + public function getPrivateKey() + { + return $this->_privateKey; + } + + public function getPublicKey() + { + return $this->_publicKey; + } + + /** + * @param string $data + * @param Zend_Crypt_Rsa_Key_Private $privateKey + * @param string $format + * @return string + */ + public function sign($data, Zend_Crypt_Rsa_Key_Private $privateKey = null, $format = null) + { + $signature = ''; + if (isset($privateKey)) { + $opensslKeyResource = $privateKey->getOpensslKeyResource(); + } else { + $opensslKeyResource = $this->_privateKey->getOpensslKeyResource(); + } + $result = openssl_sign( + $data, $signature, + $opensslKeyResource, + $this->getHashAlgorithm() + ); + if ($format == self::BASE64) { + return base64_encode($signature); + } + return $signature; + } + + /** + * @param string $data + * @param string $signature + * @param string $format + * @return string + */ + public function verifySignature($data, $signature, $format = null) + { + if ($format == self::BASE64) { + $signature = base64_decode($signature); + } + $result = openssl_verify($data, $signature, + $this->getPublicKey()->getOpensslKeyResource(), + $this->getHashAlgorithm()); + return $result; + } + + /** + * @param string $data + * @param Zend_Crypt_Rsa_Key $key + * @param string $format + * @return string + */ + public function encrypt($data, Zend_Crypt_Rsa_Key $key, $format = null) + { + $encrypted = ''; + $function = 'openssl_public_encrypt'; + if ($key instanceof Zend_Crypt_Rsa_Key_Private) { + $function = 'openssl_private_encrypt'; + } + $function($data, $encrypted, $key->getOpensslKeyResource()); + if ($format == self::BASE64) { + return base64_encode($encrypted); + } + return $encrypted; + } + + /** + * @param string $data + * @param Zend_Crypt_Rsa_Key $key + * @param string $format + * @return string + */ + public function decrypt($data, Zend_Crypt_Rsa_Key $key, $format = null) + { + $decrypted = ''; + if ($format == self::BASE64) { + $data = base64_decode($data); + } + $function = 'openssl_private_decrypt'; + if ($key instanceof Zend_Crypt_Rsa_Key_Public) { + $function = 'openssl_public_decrypt'; + } + $function($data, $decrypted, $key->getOpensslKeyResource()); + return $decrypted; + } + + public function generateKeys(array $configargs = null) + { + $config = null; + $passPhrase = null; + if ($configargs !== null) { + if (isset($configargs['passPhrase'])) { + $passPhrase = $configargs['passPhrase']; + unset($configargs['passPhrase']); + } + $config = $this->_parseConfigArgs($configargs); + } + $privateKey = null; + $publicKey = null; + $resource = openssl_pkey_new($config); + // above fails on PHP 5.3 + openssl_pkey_export($resource, $private, $passPhrase); + $privateKey = new Zend_Crypt_Rsa_Key_Private($private, $passPhrase); + $details = openssl_pkey_get_details($resource); + $publicKey = new Zend_Crypt_Rsa_Key_Public($details['key']); + $return = new ArrayObject(array( + 'privateKey'=>$privateKey, + 'publicKey'=>$publicKey + ), ArrayObject::ARRAY_AS_PROPS); + return $return; + } + + /** + * @param string $value + */ + public function setPemString($value) + { + $this->_pemString = $value; + try { + $this->_privateKey = new Zend_Crypt_Rsa_Key_Private($this->_pemString, $this->_passPhrase); + $this->_publicKey = $this->_privateKey->getPublicKey(); + } catch (Zend_Crypt_Exception $e) { + $this->_privateKey = null; + $this->_publicKey = new Zend_Crypt_Rsa_Key_Public($this->_pemString); + } + } + + public function setPemPath($value) + { + $this->_pemPath = $value; + $this->setPemString(file_get_contents($this->_pemPath)); + } + + public function setCertificateString($value) + { + $this->_certificateString = $value; + $this->_publicKey = new Zend_Crypt_Rsa_Key_Public($this->_certificateString, $this->_passPhrase); + } + + public function setCertificatePath($value) + { + $this->_certificatePath = $value; + $this->setCertificateString(file_get_contents($this->_certificatePath)); + } + + public function setHashAlgorithm($name) + { + switch (strtolower($name)) { + case 'md2': + $this->_hashAlgorithm = OPENSSL_ALGO_MD2; + break; + case 'md4': + $this->_hashAlgorithm = OPENSSL_ALGO_MD4; + break; + case 'md5': + $this->_hashAlgorithm = OPENSSL_ALGO_MD5; + break; + case 'sha1': + $this->_hashAlgorithm = OPENSSL_ALGO_SHA1; + break; + case 'dss1': + $this->_hashAlgorithm = OPENSSL_ALGO_DSS1; + break; + } + } + + /** + * @return string + */ + public function getPemString() + { + return $this->_pemString; + } + + public function getPemPath() + { + return $this->_pemPath; + } + + public function getCertificateString() + { + return $this->_certificateString; + } + + public function getCertificatePath() + { + return $this->_certificatePath; + } + + public function getHashAlgorithm() + { + return $this->_hashAlgorithm; + } + + protected function _parseConfigArgs(array $config = null) + { + $configs = array(); + if (isset($config['privateKeyBits'])) { + $configs['private_key_bits'] = $config['privateKeyBits']; + } + if (!empty($configs)) { + return $configs; + } + return null; + } + +} diff --git a/Zend/Crypt/Rsa/Key.php b/Zend/Crypt/Rsa/Key.php new file mode 100644 index 00000000..9b18abe4 --- /dev/null +++ b/Zend/Crypt/Rsa/Key.php @@ -0,0 +1,95 @@ +_opensslKeyResource; + } + + /** + * @return string + * @throws Zend_Crypt_Exception + */ + public function toString() + { + if (!empty($this->_pemString)) { + return $this->_pemString; + } elseif (!empty($this->_certificateString)) { + return $this->_certificateString; + } + /** + * @see Zend_Crypt_Exception + */ + require_once 'Zend/Crypt/Exception.php'; + throw new Zend_Crypt_Exception('No public key string representation is available'); + } + + /** + * @return string + */ + public function __toString() + { + return $this->toString(); + } + + public function count() + { + return $this->_details['bits']; + } + + public function getType() + { + return $this->_details['type']; + } +} \ No newline at end of file diff --git a/Zend/Crypt/Rsa/Key/Private.php b/Zend/Crypt/Rsa/Key/Private.php new file mode 100644 index 00000000..560ac8df --- /dev/null +++ b/Zend/Crypt/Rsa/Key/Private.php @@ -0,0 +1,75 @@ +_pemString = $pemString; + $this->_parse($passPhrase); + } + + /** + * @param string $passPhrase + * @throws Zend_Crypt_Exception + */ + protected function _parse($passPhrase) + { + $result = openssl_get_privatekey($this->_pemString, $passPhrase); + if (!$result) { + /** + * @see Zend_Crypt_Exception + */ + require_once 'Zend/Crypt/Exception.php'; + throw new Zend_Crypt_Exception('Unable to load private key'); + } + $this->_opensslKeyResource = $result; + $this->_details = openssl_pkey_get_details($this->_opensslKeyResource); + } + + public function getPublicKey() + { + if ($this->_publicKey === null) { + /** + * @see Zend_Crypt_Rsa_Key_Public + */ + require_once 'Zend/Crypt/Rsa/Key/Public.php'; + $this->_publicKey = new Zend_Crypt_Rsa_Key_Public($this->_details['key']); + } + return $this->_publicKey; + } + +} \ No newline at end of file diff --git a/Zend/Crypt/Rsa/Key/Public.php b/Zend/Crypt/Rsa/Key/Public.php new file mode 100644 index 00000000..c07bd5e1 --- /dev/null +++ b/Zend/Crypt/Rsa/Key/Public.php @@ -0,0 +1,74 @@ +_parse($string); + } + + /** + * @param string $string + * @throws Zend_Crypt_Exception + */ + protected function _parse($string) + { + if (preg_match("/^-----BEGIN CERTIFICATE-----/", $string)) { + $this->_certificateString = $string; + } else { + $this->_pemString = $string; + } + $result = openssl_get_publickey($string); + if (!$result) { + /** + * @see Zend_Crypt_Exception + */ + require_once 'Zend/Crypt/Exception.php'; + throw new Zend_Crypt_Exception('Unable to load public key'); + } + //openssl_pkey_export($result, $public); + //$this->_pemString = $public; + $this->_opensslKeyResource = $result; + $this->_details = openssl_pkey_get_details($this->_opensslKeyResource); + } + + public function getCertificate() + { + return $this->_certificateString; + } + +} \ No newline at end of file diff --git a/Zend/Exception.php b/Zend/Exception.php new file mode 100644 index 00000000..bbfb792e --- /dev/null +++ b/Zend/Exception.php @@ -0,0 +1,95 @@ +_previous = $previous; + } else { + parent::__construct($msg, (int) $code, $previous); + } + } + + /** + * Overloading + * + * For PHP < 5.3.0, provides access to the getPrevious() method. + * + * @param string $method + * @param array $args + * @return mixed + */ + public function __call($method, array $args) + { + if ('getprevious' == strtolower($method)) { + return $this->_getPrevious(); + } + return null; + } + + /** + * String representation of the exception + * + * @return string + */ + public function __toString() + { + if (version_compare(PHP_VERSION, '5.3.0', '<')) { + if (null !== ($e = $this->getPrevious())) { + return $e->__toString() + . "\n\nNext " + . parent::__toString(); + } + } + return parent::__toString(); + } + + /** + * Returns previous Exception + * + * @return Exception|null + */ + protected function _getPrevious() + { + return $this->_previous; + } +} diff --git a/Zend/Gdata.php b/Zend/Gdata.php new file mode 100644 index 00000000..0f864480 --- /dev/null +++ b/Zend/Gdata.php @@ -0,0 +1,241 @@ +decodeRequest('GET', $uri); + $response = $app->performHttpRequest($requestData['method'], $requestData['url']); + + $feedContent = $response->getBody(); + + $feed = self::importString($feedContent, $className); + if ($client != null) { + $feed->setHttpClient($client); + } + return $feed; + } + + /** + * Retrieve feed as string or object + * + * @param mixed $location The location as string or Zend_Gdata_Query + * @param string $className The class type to use for returning the feed + * @throws Zend_Gdata_App_InvalidArgumentException + * @return string|Zend_Gdata_App_Feed Returns string only if the object + * mapping has been disabled explicitly + * by passing false to the + * useObjectMapping() function. + */ + public function getFeed($location, $className='Zend_Gdata_Feed') + { + if (is_string($location)) { + $uri = $location; + } elseif ($location instanceof Zend_Gdata_Query) { + $uri = $location->getQueryUrl(); + } else { + require_once 'Zend/Gdata/App/InvalidArgumentException.php'; + throw new Zend_Gdata_App_InvalidArgumentException( + 'You must specify the location as either a string URI ' . + 'or a child of Zend_Gdata_Query'); + } + return parent::getFeed($uri, $className); + } + + /** + * Retrieve entry as string or object + * + * @param mixed $location The location as string or Zend_Gdata_Query + * @throws Zend_Gdata_App_InvalidArgumentException + * @return string|Zend_Gdata_App_Entry Returns string only if the object + * mapping has been disabled explicitly + * by passing false to the + * useObjectMapping() function. + */ + public function getEntry($location, $className='Zend_Gdata_Entry') + { + if (is_string($location)) { + $uri = $location; + } elseif ($location instanceof Zend_Gdata_Query) { + $uri = $location->getQueryUrl(); + } else { + require_once 'Zend/Gdata/App/InvalidArgumentException.php'; + throw new Zend_Gdata_App_InvalidArgumentException( + 'You must specify the location as either a string URI ' . + 'or a child of Zend_Gdata_Query'); + } + return parent::getEntry($uri, $className); + } + + /** + * Performs a HTTP request using the specified method. + * + * Overrides the definition in the parent (Zend_Gdata_App) + * and uses the Zend_Gdata_HttpClient functionality + * to filter the HTTP requests and responses. + * + * @param string $method The HTTP method for the request - + * 'GET', 'POST', 'PUT', 'DELETE' + * @param string $url The URL to which this request is being performed, + * or null if found in $data + * @param array $headers An associative array of HTTP headers + * for this request + * @param string $body The body of the HTTP request + * @param string $contentType The value for the content type of the + * request body + * @param int $remainingRedirects Number of redirects to follow + * if requests results in one + * @return Zend_Http_Response The response object + */ + public function performHttpRequest($method, $url, $headers = array(), $body = null, $contentType = null, $remainingRedirects = null) + { + if ($this->_httpClient instanceof Zend_Gdata_HttpClient) { + $filterResult = $this->_httpClient->filterHttpRequest($method, $url, $headers, $body, $contentType); + $method = $filterResult['method']; + $url = $filterResult['url']; + $body = $filterResult['body']; + $headers = $filterResult['headers']; + $contentType = $filterResult['contentType']; + return $this->_httpClient->filterHttpResponse(parent::performHttpRequest($method, $url, $headers, $body, $contentType, $remainingRedirects)); + } else { + return parent::performHttpRequest($method, $url, $headers, $body, $contentType, $remainingRedirects); + } + } + + /** + * Determines whether service object is authenticated. + * + * @return boolean True if service object is authenticated, false otherwise. + */ + public function isAuthenticated() + { + $client = parent::getHttpClient(); + if ($client->getClientLoginToken() || + $client->getAuthSubToken()) { + return true; + } + + return false; + } + +} diff --git a/Zend/Gdata/App.php b/Zend/Gdata/App.php new file mode 100644 index 00000000..db519938 --- /dev/null +++ b/Zend/Gdata/App.php @@ -0,0 +1,1234 @@ += 1 is considered valid. + * + * Under most circumtances, this will be automatically set by + * Zend_Gdata_App subclasses. + * + * @see setMajorProtocolVersion() + * @see getMajorProtocolVersion() + */ + protected $_majorProtocolVersion; + + /** + * Indicates the minor protocol version that should be used. Can be set + * to either an integer >= 0, or NULL if no minor version should be sent + * to the server. + * + * At present, this field is not used by any Google services, but may be + * used in the future. + * + * Under most circumtances, this will be automatically set by + * Zend_Gdata_App subclasses. + * + * @see setMinorProtocolVersion() + * @see getMinorProtocolVersion() + */ + protected $_minorProtocolVersion; + + /** + * Whether we want to use XML to object mapping when fetching data. + * + * @var boolean + */ + protected $_useObjectMapping = true; + + /** + * Create Gdata object + * + * @param Zend_Http_Client $client + * @param string $applicationId + */ + public function __construct($client = null, $applicationId = 'MyCompany-MyApp-1.0') + { + $this->setHttpClient($client, $applicationId); + // Set default protocol version. Subclasses should override this as + // needed once a given service supports a new version. + $this->setMajorProtocolVersion(self::DEFAULT_MAJOR_PROTOCOL_VERSION); + $this->setMinorProtocolVersion(self::DEFAULT_MINOR_PROTOCOL_VERSION); + } + + /** + * Adds a Zend Framework package to the $_registeredPackages array. + * This array is searched when using the magic __call method below + * to instantiante new objects. + * + * @param string $name The name of the package (eg Zend_Gdata_App) + * @return void + */ + public function registerPackage($name) + { + array_unshift($this->_registeredPackages, $name); + } + + /** + * Retrieve feed as string or object + * + * @param string $uri The uri from which to retrieve the feed + * @param string $className The class which is used as the return type + * @return string|Zend_Gdata_App_Feed Returns string only if the object + * mapping has been disabled explicitly + * by passing false to the + * useObjectMapping() function. + */ + public function getFeed($uri, $className='Zend_Gdata_App_Feed') + { + return $this->importUrl($uri, $className, null); + } + + /** + * Retrieve entry as string or object + * + * @param string $uri + * @param string $className The class which is used as the return type + * @return string|Zend_Gdata_App_Entry Returns string only if the object + * mapping has been disabled explicitly + * by passing false to the + * useObjectMapping() function. + */ + public function getEntry($uri, $className='Zend_Gdata_App_Entry') + { + return $this->importUrl($uri, $className, null); + } + + /** + * Get the Zend_Http_Client object used for communication + * + * @return Zend_Http_Client + */ + public function getHttpClient() + { + return $this->_httpClient; + } + + /** + * Set the Zend_Http_Client object used for communication + * + * @param Zend_Http_Client $client The client to use for communication + * @throws Zend_Gdata_App_HttpException + * @return Zend_Gdata_App Provides a fluent interface + */ + public function setHttpClient($client, + $applicationId = 'MyCompany-MyApp-1.0') + { + if ($client === null) { + $client = new Zend_Http_Client(); + } + if (!$client instanceof Zend_Http_Client) { + require_once 'Zend/Gdata/App/HttpException.php'; + throw new Zend_Gdata_App_HttpException( + 'Argument is not an instance of Zend_Http_Client.'); + } + $userAgent = $applicationId . ' Zend_Framework_Gdata/' . + Zend_Version::VERSION; + $client->setHeaders('User-Agent', $userAgent); + $client->setConfig(array( + 'strictredirects' => true + ) + ); + $this->_httpClient = $client; + self::setStaticHttpClient($client); + return $this; + } + + /** + * Set the static HTTP client instance + * + * Sets the static HTTP client object to use for retrieving the feed. + * + * @param Zend_Http_Client $httpClient + * @return void + */ + public static function setStaticHttpClient(Zend_Http_Client $httpClient) + { + self::$_staticHttpClient = $httpClient; + } + + + /** + * Gets the HTTP client object. If none is set, a new Zend_Http_Client will be used. + * + * @return Zend_Http_Client + */ + public static function getStaticHttpClient() + { + if (!self::$_staticHttpClient instanceof Zend_Http_Client) { + $client = new Zend_Http_Client(); + $userAgent = 'Zend_Framework_Gdata/' . Zend_Version::VERSION; + $client->setHeaders('User-Agent', $userAgent); + $client->setConfig(array( + 'strictredirects' => true + ) + ); + self::$_staticHttpClient = $client; + } + return self::$_staticHttpClient; + } + + /** + * Toggle using POST instead of PUT and DELETE HTTP methods + * + * Some feed implementations do not accept PUT and DELETE HTTP + * methods, or they can't be used because of proxies or other + * measures. This allows turning on using POST where PUT and + * DELETE would normally be used; in addition, an + * X-Method-Override header will be sent with a value of PUT or + * DELETE as appropriate. + * + * @param boolean $override Whether to override PUT and DELETE with POST. + * @return void + */ + public static function setHttpMethodOverride($override = true) + { + self::$_httpMethodOverride = $override; + } + + /** + * Get the HTTP override state + * + * @return boolean + */ + public static function getHttpMethodOverride() + { + return self::$_httpMethodOverride; + } + + /** + * Toggle requesting gzip encoded responses + * + * @param boolean $enabled Whether or not to enable gzipped responses + * @return void + */ + public static function setGzipEnabled($enabled = false) + { + if ($enabled && !function_exists('gzinflate')) { + require_once 'Zend/Gdata/App/InvalidArgumentException.php'; + throw new Zend_Gdata_App_InvalidArgumentException( + 'You cannot enable gzipped responses if the zlib module ' . + 'is not enabled in your PHP installation.'); + + } + self::$_gzipEnabled = $enabled; + } + + /** + * Get the HTTP override state + * + * @return boolean + */ + public static function getGzipEnabled() + { + return self::$_gzipEnabled; + } + + /** + * Get whether to use verbose exception messages + * + * In the case of HTTP errors, use the body of the HTTP response + * in the exception message. + * + * @return boolean + */ + public static function getVerboseExceptionMessages() + { + return self::$_verboseExceptionMessages; + } + + /** + * Set whether to use verbose exception messages + * + * In the case of HTTP errors, use the body of the HTTP response + * in the exception message. + * + * @param boolean $verbose Whether to use verbose exception messages + */ + public static function setVerboseExceptionMessages($verbose) + { + self::$_verboseExceptionMessages = $verbose; + } + + /** + * Set the maximum number of redirects to follow during HTTP operations + * + * @param int $maxRedirects Maximum number of redirects to follow + * @return void + */ + public static function setMaxRedirects($maxRedirects) + { + self::$_maxRedirects = $maxRedirects; + } + + /** + * Get the maximum number of redirects to follow during HTTP operations + * + * @return int Maximum number of redirects to follow + */ + public static function getMaxRedirects() + { + return self::$_maxRedirects; + } + + /** + * Set the major protocol version that should be used. Values < 1 will + * cause a Zend_Gdata_App_InvalidArgumentException to be thrown. + * + * @see _majorProtocolVersion + * @param int $value The major protocol version to use. + * @throws Zend_Gdata_App_InvalidArgumentException + */ + public function setMajorProtocolVersion($value) + { + if (!($value >= 1)) { + require_once('Zend/Gdata/App/InvalidArgumentException.php'); + throw new Zend_Gdata_App_InvalidArgumentException( + 'Major protocol version must be >= 1'); + } + $this->_majorProtocolVersion = $value; + } + + /** + * Get the major protocol version that is in use. + * + * @see _majorProtocolVersion + * @return int The major protocol version in use. + */ + public function getMajorProtocolVersion() + { + return $this->_majorProtocolVersion; + } + + /** + * Set the minor protocol version that should be used. If set to NULL, no + * minor protocol version will be sent to the server. Values < 0 will + * cause a Zend_Gdata_App_InvalidArgumentException to be thrown. + * + * @see _minorProtocolVersion + * @param (int|NULL) $value The minor protocol version to use. + * @throws Zend_Gdata_App_InvalidArgumentException + */ + public function setMinorProtocolVersion($value) + { + if (!($value >= 0)) { + require_once('Zend/Gdata/App/InvalidArgumentException.php'); + throw new Zend_Gdata_App_InvalidArgumentException( + 'Minor protocol version must be >= 0'); + } + $this->_minorProtocolVersion = $value; + } + + /** + * Get the minor protocol version that is in use. + * + * @see _minorProtocolVersion + * @return (int|NULL) The major protocol version in use, or NULL if no + * minor version is specified. + */ + public function getMinorProtocolVersion() + { + return $this->_minorProtocolVersion; + } + + /** + * Provides pre-processing for HTTP requests to APP services. + * + * 1. Checks the $data element and, if it's an entry, extracts the XML, + * multipart data, edit link (PUT,DELETE), etc. + * 2. If $data is a string, sets the default content-type header as + * 'application/atom+xml' if it's not already been set. + * 3. Adds a x-http-method override header and changes the HTTP method + * to 'POST' if necessary as per getHttpMethodOverride() + * + * @param string $method The HTTP method for the request - 'GET', 'POST', + * 'PUT', 'DELETE' + * @param string $url The URL to which this request is being performed, + * or null if found in $data + * @param array $headers An associative array of HTTP headers for this + * request + * @param mixed $data The Zend_Gdata_App_Entry or XML for the + * body of the request + * @param string $contentTypeOverride The override value for the + * content type of the request body + * @return array An associative array containing the determined + * 'method', 'url', 'data', 'headers', 'contentType' + */ + public function prepareRequest($method, + $url = null, + $headers = array(), + $data = null, + $contentTypeOverride = null) + { + // As a convenience, if $headers is null, we'll convert it back to + // an empty array. + if ($headers === null) { + $headers = array(); + } + + $rawData = null; + $finalContentType = null; + if ($url == null) { + $url = $this->_defaultPostUri; + } + + if (is_string($data)) { + $rawData = $data; + if ($contentTypeOverride === null) { + $finalContentType = 'application/atom+xml'; + } + } elseif ($data instanceof Zend_Gdata_App_MediaEntry) { + $rawData = $data->encode(); + if ($data->getMediaSource() !== null) { + $finalContentType = $rawData->getContentType(); + $headers['MIME-version'] = '1.0'; + $headers['Slug'] = $data->getMediaSource()->getSlug(); + } else { + $finalContentType = 'application/atom+xml'; + } + if ($method == 'PUT' || $method == 'DELETE') { + $editLink = $data->getEditLink(); + if ($editLink != null && $url == null) { + $url = $editLink->getHref(); + } + } + } elseif ($data instanceof Zend_Gdata_App_Entry) { + $rawData = $data->saveXML(); + $finalContentType = 'application/atom+xml'; + if ($method == 'PUT' || $method == 'DELETE') { + $editLink = $data->getEditLink(); + if ($editLink != null) { + $url = $editLink->getHref(); + } + } + } elseif ($data instanceof Zend_Gdata_App_MediaSource) { + $rawData = $data->encode(); + if ($data->getSlug() !== null) { + $headers['Slug'] = $data->getSlug(); + } + $finalContentType = $data->getContentType(); + } + + if ($method == 'DELETE') { + $rawData = null; + } + + // Set an If-Match header if: + // - This isn't a DELETE + // - If this isn't a GET, the Etag isn't weak + // - A similar header (If-Match/If-None-Match) hasn't already been + // set. + if ($method != 'DELETE' && ( + !array_key_exists('If-Match', $headers) && + !array_key_exists('If-None-Match', $headers) + ) ) { + $allowWeak = $method == 'GET'; + if ($ifMatchHeader = $this->generateIfMatchHeaderData( + $data, $allowWeak)) { + $headers['If-Match'] = $ifMatchHeader; + } + } + + if ($method != 'POST' && $method != 'GET' && Zend_Gdata_App::getHttpMethodOverride()) { + $headers['x-http-method-override'] = $method; + $method = 'POST'; + } else { + $headers['x-http-method-override'] = null; + } + + if ($contentTypeOverride != null) { + $finalContentType = $contentTypeOverride; + } + + return array('method' => $method, 'url' => $url, + 'data' => $rawData, 'headers' => $headers, + 'contentType' => $finalContentType); + } + + /** + * Performs a HTTP request using the specified method + * + * @param string $method The HTTP method for the request - 'GET', 'POST', + * 'PUT', 'DELETE' + * @param string $url The URL to which this request is being performed + * @param array $headers An associative array of HTTP headers + * for this request + * @param string $body The body of the HTTP request + * @param string $contentType The value for the content type + * of the request body + * @param int $remainingRedirects Number of redirects to follow if request + * s results in one + * @return Zend_Http_Response The response object + */ + public function performHttpRequest($method, $url, $headers = null, + $body = null, $contentType = null, $remainingRedirects = null) + { + require_once 'Zend/Http/Client/Exception.php'; + if ($remainingRedirects === null) { + $remainingRedirects = self::getMaxRedirects(); + } + if ($headers === null) { + $headers = array(); + } + // Append a Gdata version header if protocol v2 or higher is in use. + // (Protocol v1 does not use this header.) + $major = $this->getMajorProtocolVersion(); + $minor = $this->getMinorProtocolVersion(); + if ($major >= 2) { + $headers['GData-Version'] = $major + + (($minor === null) ? '.' + $minor : ''); + } + + // check the overridden method + if (($method == 'POST' || $method == 'PUT') && $body === null && + $headers['x-http-method-override'] != 'DELETE') { + require_once 'Zend/Gdata/App/InvalidArgumentException.php'; + throw new Zend_Gdata_App_InvalidArgumentException( + 'You must specify the data to post as either a ' . + 'string or a child of Zend_Gdata_App_Entry'); + } + if ($url === null) { + require_once 'Zend/Gdata/App/InvalidArgumentException.php'; + throw new Zend_Gdata_App_InvalidArgumentException( + 'You must specify an URI to which to post.'); + } + $headers['Content-Type'] = $contentType; + if (Zend_Gdata_App::getGzipEnabled()) { + // some services require the word 'gzip' to be in the user-agent + // header in addition to the accept-encoding header + if (strpos($this->_httpClient->getHeader('User-Agent'), + 'gzip') === false) { + $headers['User-Agent'] = + $this->_httpClient->getHeader('User-Agent') . ' (gzip)'; + } + $headers['Accept-encoding'] = 'gzip, deflate'; + } else { + $headers['Accept-encoding'] = 'identity'; + } + + // Make sure the HTTP client object is 'clean' before making a request + // In addition to standard headers to reset via resetParameters(), + // also reset the Slug and If-Match headers + $this->_httpClient->resetParameters(); + $this->_httpClient->setHeaders(array('Slug', 'If-Match')); + + // Set the params for the new request to be performed + $this->_httpClient->setHeaders($headers); + $uri = Zend_Uri_Http::fromString($url); + preg_match("/^(.*?)(\?.*)?$/", $url, $matches); + $this->_httpClient->setUri($matches[1]); + $queryArray = $uri->getQueryAsArray(); + foreach ($queryArray as $name => $value) { + $this->_httpClient->setParameterGet($name, $value); + } + + + $this->_httpClient->setConfig(array('maxredirects' => 0)); + + // Set the proper adapter if we are handling a streaming upload + $usingMimeStream = false; + $oldHttpAdapter = null; + + if ($body instanceof Zend_Gdata_MediaMimeStream) { + $usingMimeStream = true; + $this->_httpClient->setRawDataStream($body, $contentType); + $oldHttpAdapter = $this->_httpClient->getAdapter(); + + if ($oldHttpAdapter instanceof Zend_Http_Client_Adapter_Proxy) { + require_once 'Zend/Gdata/HttpAdapterStreamingProxy.php'; + $newAdapter = new Zend_Gdata_HttpAdapterStreamingProxy(); + } else { + require_once 'Zend/Gdata/HttpAdapterStreamingSocket.php'; + $newAdapter = new Zend_Gdata_HttpAdapterStreamingSocket(); + } + $this->_httpClient->setAdapter($newAdapter); + } else { + $this->_httpClient->setRawData($body, $contentType); + } + + try { + $response = $this->_httpClient->request($method); + // reset adapter + if ($usingMimeStream) { + $this->_httpClient->setAdapter($oldHttpAdapter); + } + } catch (Zend_Http_Client_Exception $e) { + // reset adapter + if ($usingMimeStream) { + $this->_httpClient->setAdapter($oldHttpAdapter); + } + require_once 'Zend/Gdata/App/HttpException.php'; + throw new Zend_Gdata_App_HttpException($e->getMessage(), $e); + } + if ($response->isRedirect() && $response->getStatus() != '304') { + if ($remainingRedirects > 0) { + $newUrl = $response->getHeader('Location'); + $response = $this->performHttpRequest( + $method, $newUrl, $headers, $body, + $contentType, $remainingRedirects); + } else { + require_once 'Zend/Gdata/App/HttpException.php'; + throw new Zend_Gdata_App_HttpException( + 'Number of redirects exceeds maximum', null, $response); + } + } + if (!$response->isSuccessful()) { + require_once 'Zend/Gdata/App/HttpException.php'; + $exceptionMessage = 'Expected response code 200, got ' . + $response->getStatus(); + if (self::getVerboseExceptionMessages()) { + $exceptionMessage .= "\n" . $response->getBody(); + } + $exception = new Zend_Gdata_App_HttpException($exceptionMessage); + $exception->setResponse($response); + throw $exception; + } + return $response; + } + + /** + * Imports a feed located at $uri. + * + * @param string $uri + * @param Zend_Http_Client $client The client used for communication + * @param string $className The class which is used as the return type + * @throws Zend_Gdata_App_Exception + * @return string|Zend_Gdata_App_Feed Returns string only if the object + * mapping has been disabled explicitly + * by passing false to the + * useObjectMapping() function. + */ + public static function import($uri, $client = null, + $className='Zend_Gdata_App_Feed') + { + $app = new Zend_Gdata_App($client); + $requestData = $app->prepareRequest('GET', $uri); + $response = $app->performHttpRequest( + $requestData['method'], $requestData['url']); + + $feedContent = $response->getBody(); + if (!$this->_useObjectMapping) { + return $feedContent; + } + $feed = self::importString($feedContent, $className); + if ($client != null) { + $feed->setHttpClient($client); + } + return $feed; + } + + /** + * Imports the specified URL (non-statically). + * + * @param string $url The URL to import + * @param string $className The class which is used as the return type + * @param array $extraHeaders Extra headers to add to the request, as an + * array of string-based key/value pairs. + * @throws Zend_Gdata_App_Exception + * @return string|Zend_Gdata_App_Feed Returns string only if the object + * mapping has been disabled explicitly + * by passing false to the + * useObjectMapping() function. + */ + public function importUrl($url, $className='Zend_Gdata_App_Feed', + $extraHeaders = array()) + { + $response = $this->get($url, $extraHeaders); + + $feedContent = $response->getBody(); + if (!$this->_useObjectMapping) { + return $feedContent; + } + + $protocolVersionStr = $response->getHeader('GData-Version'); + $majorProtocolVersion = null; + $minorProtocolVersion = null; + if ($protocolVersionStr !== null) { + // Extract protocol major and minor version from header + $delimiterPos = strpos($protocolVersionStr, '.'); + $length = strlen($protocolVersionStr); + $major = substr($protocolVersionStr, 0, $delimiterPos); + $minor = substr($protocolVersionStr, $delimiterPos + 1, $length); + $majorProtocolVersion = $major; + $minorProtocolVersion = $minor; + } + + $feed = self::importString($feedContent, $className, + $majorProtocolVersion, $minorProtocolVersion); + if ($this->getHttpClient() != null) { + $feed->setHttpClient($this->getHttpClient()); + } + $etag = $response->getHeader('ETag'); + if ($etag !== null) { + $feed->setEtag($etag); + } + return $feed; + } + + + /** + * Imports a feed represented by $string. + * + * @param string $string + * @param string $className The class which is used as the return type + * @param integer $majorProcolVersion (optional) The major protocol version + * of the data model object that is to be created. + * @param integer $minorProcolVersion (optional) The minor protocol version + * of the data model object that is to be created. + * @throws Zend_Gdata_App_Exception + * @return Zend_Gdata_App_Feed + */ + public static function importString($string, + $className='Zend_Gdata_App_Feed', $majorProtocolVersion = null, + $minorProtocolVersion = null) + { + if (!class_exists($className, false)) { + require_once 'Zend/Loader.php'; + @Zend_Loader::loadClass($className); + } + + // Load the feed as an XML DOMDocument object + @ini_set('track_errors', 1); + $doc = new DOMDocument(); + $success = @$doc->loadXML($string); + @ini_restore('track_errors'); + + if (!$success) { + require_once 'Zend/Gdata/App/Exception.php'; + throw new Zend_Gdata_App_Exception( + "DOMDocument cannot parse XML: $php_errormsg"); + } + + $feed = new $className(); + $feed->setMajorProtocolVersion($majorProtocolVersion); + $feed->setMinorProtocolVersion($minorProtocolVersion); + $feed->transferFromXML($string); + $feed->setHttpClient(self::getstaticHttpClient()); + return $feed; + } + + + /** + * Imports a feed from a file located at $filename. + * + * @param string $filename + * @param string $className The class which is used as the return type + * @param string $useIncludePath Whether the include_path should be searched + * @throws Zend_Gdata_App_Exception + * @return Zend_Gdata_App_Feed + */ + public static function importFile($filename, + $className='Zend_Gdata_App_Feed', $useIncludePath = false) + { + @ini_set('track_errors', 1); + $feed = @file_get_contents($filename, $useIncludePath); + @ini_restore('track_errors'); + if ($feed === false) { + require_once 'Zend/Gdata/App/Exception.php'; + throw new Zend_Gdata_App_Exception( + "File could not be loaded: $php_errormsg"); + } + return self::importString($feed, $className); + } + + /** + * GET a URI using client object. + * + * @param string $uri GET URI + * @param array $extraHeaders Extra headers to add to the request, as an + * array of string-based key/value pairs. + * @throws Zend_Gdata_App_HttpException + * @return Zend_Http_Response + */ + public function get($uri, $extraHeaders = array()) + { + $requestData = $this->prepareRequest('GET', $uri, $extraHeaders); + return $this->performHttpRequest( + $requestData['method'], $requestData['url'], + $requestData['headers']); + } + + /** + * POST data with client object + * + * @param mixed $data The Zend_Gdata_App_Entry or XML to post + * @param string $uri POST URI + * @param array $headers Additional HTTP headers to insert. + * @param string $contentType Content-type of the data + * @param array $extraHeaders Extra headers to add to the request, as an + * array of string-based key/value pairs. + * @return Zend_Http_Response + * @throws Zend_Gdata_App_Exception + * @throws Zend_Gdata_App_HttpException + * @throws Zend_Gdata_App_InvalidArgumentException + */ + public function post($data, $uri = null, $remainingRedirects = null, + $contentType = null, $extraHeaders = null) + { + $requestData = $this->prepareRequest( + 'POST', $uri, $extraHeaders, $data, $contentType); + return $this->performHttpRequest( + $requestData['method'], $requestData['url'], + $requestData['headers'], $requestData['data'], + $requestData['contentType']); + } + + /** + * PUT data with client object + * + * @param mixed $data The Zend_Gdata_App_Entry or XML to post + * @param string $uri PUT URI + * @param array $headers Additional HTTP headers to insert. + * @param string $contentType Content-type of the data + * @param array $extraHeaders Extra headers to add to the request, as an + * array of string-based key/value pairs. + * @return Zend_Http_Response + * @throws Zend_Gdata_App_Exception + * @throws Zend_Gdata_App_HttpException + * @throws Zend_Gdata_App_InvalidArgumentException + */ + public function put($data, $uri = null, $remainingRedirects = null, + $contentType = null, $extraHeaders = null) + { + $requestData = $this->prepareRequest( + 'PUT', $uri, $extraHeaders, $data, $contentType); + return $this->performHttpRequest( + $requestData['method'], $requestData['url'], + $requestData['headers'], $requestData['data'], + $requestData['contentType']); + } + + /** + * DELETE entry with client object + * + * @param mixed $data The Zend_Gdata_App_Entry or URL to delete + * @return void + * @throws Zend_Gdata_App_Exception + * @throws Zend_Gdata_App_HttpException + * @throws Zend_Gdata_App_InvalidArgumentException + */ + public function delete($data, $remainingRedirects = null) + { + if (is_string($data)) { + $requestData = $this->prepareRequest('DELETE', $data); + } else { + $headers = array(); + + $requestData = $this->prepareRequest( + 'DELETE', null, $headers, $data); + } + return $this->performHttpRequest($requestData['method'], + $requestData['url'], + $requestData['headers'], + '', + $requestData['contentType'], + $remainingRedirects); + } + + /** + * Inserts an entry to a given URI and returns the response as a + * fully formed Entry. + * + * @param mixed $data The Zend_Gdata_App_Entry or XML to post + * @param string $uri POST URI + * @param string $className The class of entry to be returned. + * @param array $extraHeaders Extra headers to add to the request, as an + * array of string-based key/value pairs. + * @return Zend_Gdata_App_Entry The entry returned by the service after + * insertion. + */ + public function insertEntry($data, $uri, $className='Zend_Gdata_App_Entry', + $extraHeaders = array()) + { + if (!class_exists($className, false)) { + require_once 'Zend/Loader.php'; + @Zend_Loader::loadClass($className); + } + + $response = $this->post($data, $uri, null, null, $extraHeaders); + + $returnEntry = new $className($response->getBody()); + $returnEntry->setHttpClient(self::getstaticHttpClient()); + + $etag = $response->getHeader('ETag'); + if ($etag !== null) { + $returnEntry->setEtag($etag); + } + + return $returnEntry; + } + + /** + * Update an entry + * + * @param mixed $data Zend_Gdata_App_Entry or XML (w/ID and link rel='edit') + * @param string|null The URI to send requests to, or null if $data + * contains the URI. + * @param string|null The name of the class that should be deserialized + * from the server response. If null, then 'Zend_Gdata_App_Entry' + * will be used. + * @param array $extraHeaders Extra headers to add to the request, as an + * array of string-based key/value pairs. + * @return Zend_Gdata_App_Entry The entry returned from the server + * @throws Zend_Gdata_App_Exception + */ + public function updateEntry($data, $uri = null, $className = null, + $extraHeaders = array()) + { + if ($className === null && $data instanceof Zend_Gdata_App_Entry) { + $className = get_class($data); + } elseif ($className === null) { + $className = 'Zend_Gdata_App_Entry'; + } + + if (!class_exists($className, false)) { + require_once 'Zend/Loader.php'; + @Zend_Loader::loadClass($className); + } + + $response = $this->put($data, $uri, null, null, $extraHeaders); + $returnEntry = new $className($response->getBody()); + $returnEntry->setHttpClient(self::getstaticHttpClient()); + + $etag = $response->getHeader('ETag'); + if ($etag !== null) { + $returnEntry->setEtag($etag); + } + + return $returnEntry; + } + + /** + * Provides a magic factory method to instantiate new objects with + * shorter syntax than would otherwise be required by the Zend Framework + * naming conventions. For instance, to construct a new + * Zend_Gdata_Calendar_Extension_Color, a developer simply needs to do + * $gCal->newColor(). For this magic constructor, packages are searched + * in the same order as which they appear in the $_registeredPackages + * array + * + * @param string $method The method name being called + * @param array $args The arguments passed to the call + * @throws Zend_Gdata_App_Exception + */ + public function __call($method, $args) + { + if (preg_match('/^new(\w+)/', $method, $matches)) { + $class = $matches[1]; + $foundClassName = null; + foreach ($this->_registeredPackages as $name) { + try { + // Autoloading disabled on next line for compatibility + // with magic factories. See ZF-6660. + if (!class_exists($name . '_' . $class, false)) { + require_once 'Zend/Loader.php'; + @Zend_Loader::loadClass($name . '_' . $class); + } + $foundClassName = $name . '_' . $class; + break; + } catch (Zend_Exception $e) { + // package wasn't here- continue searching + } + } + if ($foundClassName != null) { + $reflectionObj = new ReflectionClass($foundClassName); + $instance = $reflectionObj->newInstanceArgs($args); + if ($instance instanceof Zend_Gdata_App_FeedEntryParent) { + $instance->setHttpClient($this->_httpClient); + + // Propogate version data + $instance->setMajorProtocolVersion( + $this->_majorProtocolVersion); + $instance->setMinorProtocolVersion( + $this->_minorProtocolVersion); + } + return $instance; + } else { + require_once 'Zend/Gdata/App/Exception.php'; + throw new Zend_Gdata_App_Exception( + "Unable to find '${class}' in registered packages"); + } + } else { + require_once 'Zend/Gdata/App/Exception.php'; + throw new Zend_Gdata_App_Exception("No such method ${method}"); + } + } + + /** + * Retrieve all entries for a feed, iterating through pages as necessary. + * Be aware that calling this function on a large dataset will take a + * significant amount of time to complete. In some cases this may cause + * execution to timeout without proper precautions in place. + * + * @param $feed The feed to iterate through. + * @return mixed A new feed of the same type as the one originally + * passed in, containing all relevent entries. + */ + public function retrieveAllEntriesForFeed($feed) { + $feedClass = get_class($feed); + $reflectionObj = new ReflectionClass($feedClass); + $result = $reflectionObj->newInstance(); + do { + foreach ($feed as $entry) { + $result->addEntry($entry); + } + + $next = $feed->getLink('next'); + if ($next !== null) { + $feed = $this->getFeed($next->href, $feedClass); + } else { + $feed = null; + } + } + while ($feed != null); + return $result; + } + + /** + * This method enables logging of requests by changing the + * Zend_Http_Client_Adapter used for performing the requests. + * NOTE: This will not work if you have customized the adapter + * already to use a proxy server or other interface. + * + * @param $logfile The logfile to use when logging the requests + */ + public function enableRequestDebugLogging($logfile) + { + $this->_httpClient->setConfig(array( + 'adapter' => 'Zend_Gdata_App_LoggingHttpClientAdapterSocket', + 'logfile' => $logfile + )); + } + + /** + * Retrieve next set of results based on a given feed. + * + * @param Zend_Gdata_App_Feed $feed The feed from which to + * retreive the next set of results. + * @param string $className (optional) The class of feed to be returned. + * If null, the next feed (if found) will be the same class as + * the feed that was given as the first argument. + * @return Zend_Gdata_App_Feed|null Returns a + * Zend_Gdata_App_Feed or null if no next set of results + * exists. + */ + public function getNextFeed($feed, $className = null) + { + $nextLink = $feed->getNextLink(); + if (!$nextLink) { + return null; + } + $nextLinkHref = $nextLink->getHref(); + + if ($className === null) { + $className = get_class($feed); + } + + return $this->getFeed($nextLinkHref, $className); + } + + /** + * Retrieve previous set of results based on a given feed. + * + * @param Zend_Gdata_App_Feed $feed The feed from which to + * retreive the previous set of results. + * @param string $className (optional) The class of feed to be returned. + * If null, the previous feed (if found) will be the same class as + * the feed that was given as the first argument. + * @return Zend_Gdata_App_Feed|null Returns a + * Zend_Gdata_App_Feed or null if no previous set of results + * exists. + */ + public function getPreviousFeed($feed, $className = null) + { + $previousLink = $feed->getPreviousLink(); + if (!$previousLink) { + return null; + } + $previousLinkHref = $previousLink->getHref(); + + if ($className === null) { + $className = get_class($feed); + } + + return $this->getFeed($previousLinkHref, $className); + } + + /** + * Returns the data for an If-Match header based on the current Etag + * property. If Etags are not supported by the server or cannot be + * extracted from the data, then null will be returned. + * + * @param boolean $allowWeak If false, then if a weak Etag is detected, + * then return null rather than the Etag. + * @return string|null $data + */ + public function generateIfMatchHeaderData($data, $allowWeek) + { + $result = ''; + // Set an If-Match header if an ETag has been set (version >= 2 only) + if ($this->_majorProtocolVersion >= 2 && + $data instanceof Zend_Gdata_App_Entry) { + $etag = $data->getEtag(); + if (($etag !== null) && + ($allowWeek || substr($etag, 0, 2) != 'W/')) { + $result = $data->getEtag(); + } + } + return $result; + } + + /** + * Determine whether service object is using XML to object mapping. + * + * @return boolean True if service object is using XML to object mapping, + * false otherwise. + */ + public function usingObjectMapping() + { + return $this->_useObjectMapping; + } + + /** + * Enable/disable the use of XML to object mapping. + * + * @param boolean $value Pass in true to use the XML to object mapping. + * Pass in false or null to disable it. + * @return void + */ + public function useObjectMapping($value) + { + if ($value === True) { + $this->_useObjectMapping = true; + } else { + $this->_useObjectMapping = false; + } + } + +} diff --git a/Zend/Gdata/App/AuthException.php b/Zend/Gdata/App/AuthException.php new file mode 100644 index 00000000..235a8ef5 --- /dev/null +++ b/Zend/Gdata/App/AuthException.php @@ -0,0 +1,41 @@ + array( + 1 => array( + 0 => 'http://www.w3.org/2005/Atom' + ) + ), + 'app' => array( + 1 => array( + 0 => 'http://purl.org/atom/app#' + ), + 2 => array( + 0 => 'http://www.w3.org/2007/app' + ) + ) + ); + + public function __construct() + { + } + + /** + * Returns the child text node of this element + * This represents any raw text contained within the XML element + * + * @return string Child text node + */ + public function getText($trim = true) + { + if ($trim) { + return trim($this->_text); + } else { + return $this->_text; + } + } + + /** + * Sets the child text node of this element + * This represents any raw text contained within the XML element + * + * @param string $value Child text node + * @return Zend_Gdata_App_Base Returns an object of the same type as 'this' to provide a fluent interface. + */ + public function setText($value) + { + $this->_text = $value; + return $this; + } + + /** + * Returns an array of all elements not matched to data model classes + * during the parsing of the XML + * + * @return array All elements not matched to data model classes during parsing + */ + public function getExtensionElements() + { + return $this->_extensionElements; + } + + /** + * Sets an array of all elements not matched to data model classes + * during the parsing of the XML. This method can be used to add arbitrary + * child XML elements to any data model class. + * + * @param array $value All extension elements + * @return Zend_Gdata_App_Base Returns an object of the same type as 'this' to provide a fluent interface. + */ + public function setExtensionElements($value) + { + $this->_extensionElements = $value; + return $this; + } + + /** + * Returns an array of all extension attributes not transformed into data + * model properties during parsing of the XML. Each element of the array + * is a hashed array of the format: + * array('namespaceUri' => string, 'name' => string, 'value' => string); + * + * @return array All extension attributes + */ + public function getExtensionAttributes() + { + return $this->_extensionAttributes; + } + + /** + * Sets an array of all extension attributes not transformed into data + * model properties during parsing of the XML. Each element of the array + * is a hashed array of the format: + * array('namespaceUri' => string, 'name' => string, 'value' => string); + * This can be used to add arbitrary attributes to any data model element + * + * @param array $value All extension attributes + * @return Zend_Gdata_App_Base Returns an object of the same type as 'this' to provide a fluent interface. + */ + public function setExtensionAttributes($value) + { + $this->_extensionAttributes = $value; + return $this; + } + + /** + * Retrieves a DOMElement which corresponds to this element and all + * child properties. This is used to build an entry back into a DOM + * and eventually XML text for sending to the server upon updates, or + * for application storage/persistence. + * + * @param DOMDocument $doc The DOMDocument used to construct DOMElements + * @return DOMElement The DOMElement representing this element and all + * child properties. + */ + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + if ($doc === null) { + $doc = new DOMDocument('1.0', 'utf-8'); + } + if ($this->_rootNamespaceURI != null) { + $element = $doc->createElementNS($this->_rootNamespaceURI, $this->_rootElement); + } elseif ($this->_rootNamespace !== null) { + if (strpos($this->_rootElement, ':') === false) { + $elementName = $this->_rootNamespace . ':' . $this->_rootElement; + } else { + $elementName = $this->_rootElement; + } + $element = $doc->createElementNS($this->lookupNamespace($this->_rootNamespace), $elementName); + } else { + $element = $doc->createElement($this->_rootElement); + } + if ($this->_text != null) { + $element->appendChild($element->ownerDocument->createTextNode($this->_text)); + } + foreach ($this->_extensionElements as $extensionElement) { + $element->appendChild($extensionElement->getDOM($element->ownerDocument)); + } + foreach ($this->_extensionAttributes as $attribute) { + $element->setAttribute($attribute['name'], $attribute['value']); + } + return $element; + } + + /** + * Given a child DOMNode, tries to determine how to map the data into + * object instance members. If no mapping is defined, Extension_Element + * objects are created and stored in an array. + * + * @param DOMNode $child The DOMNode needed to be handled + */ + protected function takeChildFromDOM($child) + { + if ($child->nodeType == XML_TEXT_NODE) { + $this->_text = $child->nodeValue; + } else { + $extensionElement = new Zend_Gdata_App_Extension_Element(); + $extensionElement->transferFromDOM($child); + $this->_extensionElements[] = $extensionElement; + } + } + + /** + * Given a DOMNode representing an attribute, tries to map the data into + * instance members. If no mapping is defined, the name and value are + * stored in an array. + * + * @param DOMNode $attribute The DOMNode attribute needed to be handled + */ + protected function takeAttributeFromDOM($attribute) + { + $arrayIndex = ($attribute->namespaceURI != '')?( + $attribute->namespaceURI . ':' . $attribute->name): + $attribute->name; + $this->_extensionAttributes[$arrayIndex] = + array('namespaceUri' => $attribute->namespaceURI, + 'name' => $attribute->localName, + 'value' => $attribute->nodeValue); + } + + /** + * Transfers each child and attribute into member variables. + * This is called when XML is received over the wire and the data + * model needs to be built to represent this XML. + * + * @param DOMNode $node The DOMNode that represents this object's data + */ + public function transferFromDOM($node) + { + foreach ($node->childNodes as $child) { + $this->takeChildFromDOM($child); + } + foreach ($node->attributes as $attribute) { + $this->takeAttributeFromDOM($attribute); + } + } + + /** + * Parses the provided XML text and generates data model classes for + * each know element by turning the XML text into a DOM tree and calling + * transferFromDOM($element). The first data model element with the same + * name as $this->_rootElement is used and the child elements are + * recursively parsed. + * + * @param string $xml The XML text to parse + */ + public function transferFromXML($xml) + { + if ($xml) { + // Load the feed as an XML DOMDocument object + @ini_set('track_errors', 1); + $doc = new DOMDocument(); + $success = @$doc->loadXML($xml); + @ini_restore('track_errors'); + if (!$success) { + require_once 'Zend/Gdata/App/Exception.php'; + throw new Zend_Gdata_App_Exception("DOMDocument cannot parse XML: $php_errormsg"); + } + $element = $doc->getElementsByTagName($this->_rootElement)->item(0); + if (!$element) { + require_once 'Zend/Gdata/App/Exception.php'; + throw new Zend_Gdata_App_Exception('No root <' . $this->_rootElement . '> element'); + } + $this->transferFromDOM($element); + } else { + require_once 'Zend/Gdata/App/Exception.php'; + throw new Zend_Gdata_App_Exception('XML passed to transferFromXML cannot be null'); + } + } + + /** + * Converts this element and all children into XML text using getDOM() + * + * @return string XML content + */ + public function saveXML() + { + $element = $this->getDOM(); + return $element->ownerDocument->saveXML($element); + } + + /** + * Alias for saveXML() returns XML content for this element and all + * children + * + * @return string XML content + */ + public function getXML() + { + return $this->saveXML(); + } + + /** + * Alias for saveXML() + * + * Can be overridden by children to provide more complex representations + * of entries. + * + * @return string Encoded string content + */ + public function encode() + { + return $this->saveXML(); + } + + /** + * Get the full version of a namespace prefix + * + * Looks up a prefix (atom:, etc.) in the list of registered + * namespaces and returns the full namespace URI if + * available. Returns the prefix, unmodified, if it's not + * registered. + * + * @param string $prefix The namespace prefix to lookup. + * @param integer $majorVersion The major protocol version in effect. + * Defaults to '1'. + * @param integer $minorVersion The minor protocol version in effect. + * Defaults to null (use latest). + * @return string + */ + public function lookupNamespace($prefix, + $majorVersion = 1, + $minorVersion = null) + { + // Check for a memoized result + $key = $prefix . ' ' . + (is_null($majorVersion) ? 'NULL' : $majorVersion) . + ' '. (is_null($minorVersion) ? 'NULL' : $minorVersion); + if (array_key_exists($key, self::$_namespaceLookupCache)) + return self::$_namespaceLookupCache[$key]; + // If no match, return the prefix by default + $result = $prefix; + + // Find tuple of keys that correspond to the namespace we should use + if (isset($this->_namespaces[$prefix])) { + // Major version search + $nsData = $this->_namespaces[$prefix]; + $foundMajorV = Zend_Gdata_App_Util::findGreatestBoundedValue( + $majorVersion, $nsData); + // Minor version search + $nsData = $nsData[$foundMajorV]; + $foundMinorV = Zend_Gdata_App_Util::findGreatestBoundedValue( + $minorVersion, $nsData); + // Extract NS + $result = $nsData[$foundMinorV]; + } + + // Memoize result + self::$_namespaceLookupCache[$key] = $result; + + return $result; + } + + /** + * Add a namespace and prefix to the registered list + * + * Takes a prefix and a full namespace URI and adds them to the + * list of registered namespaces for use by + * $this->lookupNamespace(). + * + * WARNING: Currently, registering a namespace will NOT invalidate any + * memoized data stored in $_namespaceLookupCache. Under normal + * use, this behavior is acceptable. If you are adding + * contradictory data to the namespace lookup table, you must + * call flushNamespaceLookupCache(). + * + * @param string $prefix The namespace prefix + * @param string $namespaceUri The full namespace URI + * @param integer $majorVersion The major protocol version in effect. + * Defaults to '1'. + * @param integer $minorVersion The minor protocol version in effect. + * Defaults to null (use latest). + * @return void + */ + public function registerNamespace($prefix, + $namespaceUri, + $majorVersion = 1, + $minorVersion = 0) + { + $this->_namespaces[$prefix][$majorVersion][$minorVersion] = + $namespaceUri; + } + + /** + * Flush namespace lookup cache. + * + * Empties the namespace lookup cache. Call this function if you have + * added data to the namespace lookup table that contradicts values that + * may have been cached during a previous call to lookupNamespace(). + */ + public static function flushNamespaceLookupCache() + { + self::$_namespaceLookupCache = array(); + } + + /** + * Add an array of namespaces to the registered list. + * + * Takes an array in the format of: + * namespace prefix, namespace URI, major protocol version, + * minor protocol version and adds them with calls to ->registerNamespace() + * + * @param array $namespaceArray An array of namespaces. + * @return void + */ + public function registerAllNamespaces($namespaceArray) + { + foreach($namespaceArray as $namespace) { + $this->registerNamespace( + $namespace[0], $namespace[1], $namespace[2], $namespace[3]); + } + } + + + /** + * Magic getter to allow access like $entry->foo to call $entry->getFoo() + * Alternatively, if no getFoo() is defined, but a $_foo protected variable + * is defined, this is returned. + * + * TODO Remove ability to bypass getFoo() methods?? + * + * @param string $name The variable name sought + */ + public function __get($name) + { + $method = 'get'.ucfirst($name); + if (method_exists($this, $method)) { + return call_user_func(array(&$this, $method)); + } else if (property_exists($this, "_${name}")) { + return $this->{'_' . $name}; + } else { + require_once 'Zend/Gdata/App/InvalidArgumentException.php'; + throw new Zend_Gdata_App_InvalidArgumentException( + 'Property ' . $name . ' does not exist'); + } + } + + /** + * Magic setter to allow acces like $entry->foo='bar' to call + * $entry->setFoo('bar') automatically. + * + * Alternatively, if no setFoo() is defined, but a $_foo protected variable + * is defined, this is returned. + * + * TODO Remove ability to bypass getFoo() methods?? + * + * @param string $name + * @param string $value + */ + public function __set($name, $val) + { + $method = 'set'.ucfirst($name); + if (method_exists($this, $method)) { + return call_user_func(array(&$this, $method), $val); + } else if (isset($this->{'_' . $name}) || ($this->{'_' . $name} === null)) { + $this->{'_' . $name} = $val; + } else { + require_once 'Zend/Gdata/App/InvalidArgumentException.php'; + throw new Zend_Gdata_App_InvalidArgumentException( + 'Property ' . $name . ' does not exist'); + } + } + + /** + * Magic __isset method + * + * @param string $name + */ + public function __isset($name) + { + $rc = new ReflectionClass(get_class($this)); + $privName = '_' . $name; + if (!($rc->hasProperty($privName))) { + require_once 'Zend/Gdata/App/InvalidArgumentException.php'; + throw new Zend_Gdata_App_InvalidArgumentException( + 'Property ' . $name . ' does not exist'); + } else { + if (isset($this->{$privName})) { + if (is_array($this->{$privName})) { + if (count($this->{$privName}) > 0) { + return true; + } else { + return false; + } + } else { + return true; + } + } else { + return false; + } + } + } + + /** + * Magic __unset method + * + * @param string $name + */ + public function __unset($name) + { + if (isset($this->{'_' . $name})) { + if (is_array($this->{'_' . $name})) { + $this->{'_' . $name} = array(); + } else { + $this->{'_' . $name} = null; + } + } + } + + /** + * Magic toString method allows using this directly via echo + * Works best in PHP >= 4.2.0 + * + * @return string The text representation of this object + */ + public function __toString() + { + return $this->getText(); + } + +} diff --git a/Zend/Gdata/App/BaseMediaSource.php b/Zend/Gdata/App/BaseMediaSource.php new file mode 100644 index 00000000..a5b75385 --- /dev/null +++ b/Zend/Gdata/App/BaseMediaSource.php @@ -0,0 +1,179 @@ +_contentType; + } + + /** + * Set the content type for the file attached (example image/png) + * + * @param string $value The content type + * @return Zend_Gdata_App_MediaFileSource Provides a fluent interface + */ + public function setContentType($value) + { + $this->_contentType = $value; + return $this; + } + + /** + * Returns the Slug header value. Used by some services to determine the + * title for the uploaded file. Returns null if no slug should be used. + * + * @return string + */ + public function getSlug(){ + return $this->_slug; + } + + /** + * Sets the Slug header value. Used by some services to determine the + * title for the uploaded file. A null value indicates no slug header. + * + * @var string The slug value + * @return Zend_Gdata_App_MediaSource Provides a fluent interface + */ + public function setSlug($value){ + $this->_slug = $value; + return $this; + } + + + /** + * Magic getter to allow acces like $source->foo to call $source->getFoo() + * Alternatively, if no getFoo() is defined, but a $_foo protected variable + * is defined, this is returned. + * + * TODO Remove ability to bypass getFoo() methods?? + * + * @param string $name The variable name sought + */ + public function __get($name) + { + $method = 'get'.ucfirst($name); + if (method_exists($this, $method)) { + return call_user_func(array(&$this, $method)); + } else if (property_exists($this, "_${name}")) { + return $this->{'_' . $name}; + } else { + require_once 'Zend/Gdata/App/InvalidArgumentException.php'; + throw new Zend_Gdata_App_InvalidArgumentException( + 'Property ' . $name . ' does not exist'); + } + } + + /** + * Magic setter to allow acces like $source->foo='bar' to call + * $source->setFoo('bar') automatically. + * + * Alternatively, if no setFoo() is defined, but a $_foo protected variable + * is defined, this is returned. + * + * @param string $name + * @param string $value + */ + public function __set($name, $val) + { + $method = 'set'.ucfirst($name); + if (method_exists($this, $method)) { + return call_user_func(array(&$this, $method), $val); + } else if (isset($this->{'_' . $name}) || ($this->{'_' . $name} === null)) { + $this->{'_' . $name} = $val; + } else { + require_once 'Zend/Gdata/App/InvalidArgumentException.php'; + throw new Zend_Gdata_App_InvalidArgumentException( + 'Property ' . $name . ' does not exist'); + } + } + + /** + * Magic __isset method + * + * @param string $name + */ + public function __isset($name) + { + $rc = new ReflectionClass(get_class($this)); + $privName = '_' . $name; + if (!($rc->hasProperty($privName))) { + require_once 'Zend/Gdata/App/InvalidArgumentException.php'; + throw new Zend_Gdata_App_InvalidArgumentException( + 'Property ' . $name . ' does not exist'); + } else { + if (isset($this->{$privName})) { + if (is_array($this->{$privName})) { + if (count($this->{$privName}) > 0) { + return true; + } else { + return false; + } + } else { + return true; + } + } else { + return false; + } + } + } + +} diff --git a/Zend/Gdata/App/CaptchaRequiredException.php b/Zend/Gdata/App/CaptchaRequiredException.php new file mode 100644 index 00000000..38bb8a8d --- /dev/null +++ b/Zend/Gdata/App/CaptchaRequiredException.php @@ -0,0 +1,94 @@ +captchaToken = $captchaToken; + $this->captchaUrl = Zend_Gdata_App_CaptchaRequiredException::ACCOUNTS_URL . $captchaUrl; + parent::__construct('CAPTCHA challenge issued by server'); + } + + /** + * Retrieves the token identifier as provided by the server. + * + * @return string + */ + public function getCaptchaToken() { + return $this->captchaToken; + } + + /** + * Retrieves the URL CAPTCHA image as provided by the server. + * + * @return string + */ + public function getCaptchaUrl() { + return $this->captchaUrl; + } + +} diff --git a/Zend/Gdata/App/Entry.php b/Zend/Gdata/App/Entry.php new file mode 100644 index 00000000..f5f29efe --- /dev/null +++ b/Zend/Gdata/App/Entry.php @@ -0,0 +1,389 @@ +_content != null) { + $element->appendChild($this->_content->getDOM($element->ownerDocument)); + } + if ($this->_published != null) { + $element->appendChild($this->_published->getDOM($element->ownerDocument)); + } + if ($this->_source != null) { + $element->appendChild($this->_source->getDOM($element->ownerDocument)); + } + if ($this->_summary != null) { + $element->appendChild($this->_summary->getDOM($element->ownerDocument)); + } + if ($this->_control != null) { + $element->appendChild($this->_control->getDOM($element->ownerDocument)); + } + if ($this->_edited != null) { + $element->appendChild($this->_edited->getDOM($element->ownerDocument)); + } + return $element; + } + + protected function takeChildFromDOM($child) + { + $absoluteNodeName = $child->namespaceURI . ':' . $child->localName; + switch ($absoluteNodeName) { + case $this->lookupNamespace('atom') . ':' . 'content': + $content = new Zend_Gdata_App_Extension_Content(); + $content->transferFromDOM($child); + $this->_content = $content; + break; + case $this->lookupNamespace('atom') . ':' . 'published': + $published = new Zend_Gdata_App_Extension_Published(); + $published->transferFromDOM($child); + $this->_published = $published; + break; + case $this->lookupNamespace('atom') . ':' . 'source': + $source = new Zend_Gdata_App_Extension_Source(); + $source->transferFromDOM($child); + $this->_source = $source; + break; + case $this->lookupNamespace('atom') . ':' . 'summary': + $summary = new Zend_Gdata_App_Extension_Summary(); + $summary->transferFromDOM($child); + $this->_summary = $summary; + break; + case $this->lookupNamespace('app') . ':' . 'control': + $control = new Zend_Gdata_App_Extension_Control(); + $control->transferFromDOM($child); + $this->_control = $control; + break; + case $this->lookupNamespace('app') . ':' . 'edited': + $edited = new Zend_Gdata_App_Extension_Edited(); + $edited->transferFromDOM($child); + $this->_edited = $edited; + break; + default: + parent::takeChildFromDOM($child); + break; + } + } + + /** + * Uploads changes in this entry to the server using Zend_Gdata_App + * + * @param string|null $uri The URI to send requests to, or null if $data + * contains the URI. + * @param string|null $className The name of the class that should we + * deserializing the server response. If null, then + * 'Zend_Gdata_App_Entry' will be used. + * @param array $extraHeaders Extra headers to add to the request, as an + * array of string-based key/value pairs. + * @return Zend_Gdata_App_Entry The updated entry. + * @throws Zend_Gdata_App_Exception + */ + public function save($uri = null, $className = null, $extraHeaders = array()) + { + return $this->getService()->updateEntry($this, + $uri, + $className, + $extraHeaders); + } + + /** + * Deletes this entry to the server using the referenced + * Zend_Http_Client to do a HTTP DELETE to the edit link stored in this + * entry's link collection. + * + * @return void + * @throws Zend_Gdata_App_Exception + */ + public function delete() + { + $this->getService()->delete($this); + } + + /** + * Reload the current entry. Returns a new copy of the entry as returned + * by the server, or null if no changes exist. This does not + * modify the current entry instance. + * + * @param string|null The URI to send requests to, or null if $data + * contains the URI. + * @param string|null The name of the class that should we deserializing + * the server response. If null, then 'Zend_Gdata_App_Entry' will + * be used. + * @param array $extraHeaders Extra headers to add to the request, as an + * array of string-based key/value pairs. + * @return mixed A new instance of the current entry with updated data, or + * null if the server reports that no changes have been made. + * @throws Zend_Gdata_App_Exception + */ + public function reload($uri = null, $className = null, $extraHeaders = array()) + { + // Get URI + $editLink = $this->getEditLink(); + if (($uri === null) && $editLink != null) { + $uri = $editLink->getHref(); + } + + // Set classname to current class, if not otherwise set + if ($className === null) { + $className = get_class($this); + } + + // Append ETag, if present (Gdata v2 and above, only) and doesn't + // conflict with existing headers + if ($this->_etag != null + && !array_key_exists('If-Match', $extraHeaders) + && !array_key_exists('If-None-Match', $extraHeaders)) { + $extraHeaders['If-None-Match'] = $this->_etag; + } + + // If an HTTP 304 status (Not Modified)is returned, then we return + // null. + $result = null; + try { + $result = $this->service->importUrl($uri, $className, $extraHeaders); + } catch (Zend_Gdata_App_HttpException $e) { + if ($e->getResponse()->getStatus() != '304') + throw $e; + } + + return $result; + } + + /** + * Gets the value of the atom:content element + * + * @return Zend_Gdata_App_Extension_Content + */ + public function getContent() + { + return $this->_content; + } + + /** + * Sets the value of the atom:content element + * + * @param Zend_Gdata_App_Extension_Content $value + * @return Zend_Gdata_App_Entry Provides a fluent interface + */ + public function setContent($value) + { + $this->_content = $value; + return $this; + } + + /** + * Sets the value of the atom:published element + * This represents the publishing date for an entry + * + * @return Zend_Gdata_App_Extension_Published + */ + public function getPublished() + { + return $this->_published; + } + + /** + * Sets the value of the atom:published element + * This represents the publishing date for an entry + * + * @param Zend_Gdata_App_Extension_Published $value + * @return Zend_Gdata_App_Entry Provides a fluent interface + */ + public function setPublished($value) + { + $this->_published = $value; + return $this; + } + + /** + * Gets the value of the atom:source element + * + * @return Zend_Gdata_App_Extension_Source + */ + public function getSource() + { + return $this->_source; + } + + /** + * Sets the value of the atom:source element + * + * @param Zend_Gdata_App_Extension_Source $value + * @return Zend_Gdata_App_Entry Provides a fluent interface + */ + public function setSource($value) + { + $this->_source = $value; + return $this; + } + + /** + * Gets the value of the atom:summary element + * This represents a textual summary of this entry's content + * + * @return Zend_Gdata_App_Extension_Summary + */ + public function getSummary() + { + return $this->_summary; + } + + /** + * Sets the value of the atom:summary element + * This represents a textual summary of this entry's content + * + * @param Zend_Gdata_App_Extension_Summary $value + * @return Zend_Gdata_App_Entry Provides a fluent interface + */ + public function setSummary($value) + { + $this->_summary = $value; + return $this; + } + + /** + * Gets the value of the app:control element + * + * @return Zend_Gdata_App_Extension_Control + */ + public function getControl() + { + return $this->_control; + } + + /** + * Sets the value of the app:control element + * + * @param Zend_Gdata_App_Extension_Control $value + * @return Zend_Gdata_App_Entry Provides a fluent interface + */ + public function setControl($value) + { + $this->_control = $value; + return $this; + } + +} diff --git a/Zend/Gdata/App/Exception.php b/Zend/Gdata/App/Exception.php new file mode 100644 index 00000000..facdddeb --- /dev/null +++ b/Zend/Gdata/App/Exception.php @@ -0,0 +1,43 @@ +_term = $term; + $this->_scheme = $scheme; + $this->_label = $label; + } + + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc, $majorVersion, $minorVersion); + if ($this->_term !== null) { + $element->setAttribute('term', $this->_term); + } + if ($this->_scheme !== null) { + $element->setAttribute('scheme', $this->_scheme); + } + if ($this->_label !== null) { + $element->setAttribute('label', $this->_label); + } + return $element; + } + + protected function takeAttributeFromDOM($attribute) + { + switch ($attribute->localName) { + case 'term': + $this->_term = $attribute->nodeValue; + break; + case 'scheme': + $this->_scheme = $attribute->nodeValue; + break; + case 'label': + $this->_label = $attribute->nodeValue; + break; + default: + parent::takeAttributeFromDOM($attribute); + } + } + + /** + * @return string|null + */ + public function getTerm() + { + return $this->_term; + } + + /** + * @param string|null $value + * @return Zend_Gdata_App_Extension_Category Provides a fluent interface + */ + public function setTerm($value) + { + $this->_term = $value; + return $this; + } + + /** + * @return string|null + */ + public function getScheme() + { + return $this->_scheme; + } + + /** + * @param string|null $value + * @return Zend_Gdata_App_Extension_Category Provides a fluent interface + */ + public function setScheme($value) + { + $this->_scheme = $value; + return $this; + } + + /** + * @return string|null + */ + public function getLabel() + { + return $this->_label; + } + + /** + * @param string|null $value + * @return Zend_Gdata_App_Extension_Category Provides a fluent interface + */ + public function setLabel($value) + { + $this->_label = $value; + return $this; + } + +} diff --git a/Zend/Gdata/App/Extension/Content.php b/Zend/Gdata/App/Extension/Content.php new file mode 100644 index 00000000..5bafde59 --- /dev/null +++ b/Zend/Gdata/App/Extension/Content.php @@ -0,0 +1,88 @@ +_src = $src; + } + + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc, $majorVersion, $minorVersion); + if ($this->_src !== null) { + $element->setAttribute('src', $this->_src); + } + return $element; + } + + protected function takeAttributeFromDOM($attribute) + { + switch ($attribute->localName) { + case 'src': + $this->_src = $attribute->nodeValue; + break; + default: + parent::takeAttributeFromDOM($attribute); + } + } + + /** + * @return string + */ + public function getSrc() + { + return $this->_src; + } + + /** + * @param string $value + * @return Zend_Gdata_App_Entry Provides a fluent interface + */ + public function setSrc($value) + { + $this->_src = $value; + return $this; + } + +} diff --git a/Zend/Gdata/App/Extension/Contributor.php b/Zend/Gdata/App/Extension/Contributor.php new file mode 100644 index 00000000..6340923c --- /dev/null +++ b/Zend/Gdata/App/Extension/Contributor.php @@ -0,0 +1,43 @@ +_draft = $draft; + } + + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc, $majorVersion, $minorVersion); + if ($this->_draft != null) { + $element->appendChild($this->_draft->getDOM($element->ownerDocument)); + } + return $element; + } + + protected function takeChildFromDOM($child) + { + $absoluteNodeName = $child->namespaceURI . ':' . $child->localName; + switch ($absoluteNodeName) { + case $this->lookupNamespace('app') . ':' . 'draft': + $draft = new Zend_Gdata_App_Extension_Draft(); + $draft->transferFromDOM($child); + $this->_draft = $draft; + break; + default: + parent::takeChildFromDOM($child); + break; + } + } + + /** + * @return Zend_Gdata_App_Extension_Draft + */ + public function getDraft() + { + return $this->_draft; + } + + /** + * @param Zend_Gdata_App_Extension_Draft $value + * @return Zend_Gdata_App_Entry Provides a fluent interface + */ + public function setDraft($value) + { + $this->_draft = $value; + return $this; + } + +} diff --git a/Zend/Gdata/App/Extension/Draft.php b/Zend/Gdata/App/Extension/Draft.php new file mode 100644 index 00000000..b14f1ed6 --- /dev/null +++ b/Zend/Gdata/App/Extension/Draft.php @@ -0,0 +1,50 @@ +_text = $text; + } + +} diff --git a/Zend/Gdata/App/Extension/Edited.php b/Zend/Gdata/App/Extension/Edited.php new file mode 100644 index 00000000..a33df51f --- /dev/null +++ b/Zend/Gdata/App/Extension/Edited.php @@ -0,0 +1,49 @@ +_text = $text; + } + +} diff --git a/Zend/Gdata/App/Extension/Element.php b/Zend/Gdata/App/Extension/Element.php new file mode 100644 index 00000000..c87ace00 --- /dev/null +++ b/Zend/Gdata/App/Extension/Element.php @@ -0,0 +1,58 @@ +_rootElement = $rootElement; + $this->_rootNamespace = $rootNamespace; + $this->_rootNamespaceURI = $rootNamespaceURI; + $this->_text = $text; + } + + public function transferFromDOM($node) + { + parent::transferFromDOM($node); + $this->_rootNamespace = null; + $this->_rootNamespaceURI = $node->namespaceURI; + $this->_rootElement = $node->localName; + } + +} diff --git a/Zend/Gdata/App/Extension/Email.php b/Zend/Gdata/App/Extension/Email.php new file mode 100644 index 00000000..232f7126 --- /dev/null +++ b/Zend/Gdata/App/Extension/Email.php @@ -0,0 +1,49 @@ +_text = $text; + } + +} diff --git a/Zend/Gdata/App/Extension/Generator.php b/Zend/Gdata/App/Extension/Generator.php new file mode 100644 index 00000000..d557ac41 --- /dev/null +++ b/Zend/Gdata/App/Extension/Generator.php @@ -0,0 +1,115 @@ +_text = $text; + $this->_uri = $uri; + $this->_version = $version; + } + + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc, $majorVersion, $minorVersion); + if ($this->_uri !== null) { + $element->setAttribute('uri', $this->_uri); + } + if ($this->_version !== null) { + $element->setAttribute('version', $this->_version); + } + return $element; + } + + protected function takeAttributeFromDOM($attribute) + { + switch ($attribute->localName) { + case 'uri': + $this->_uri = $attribute->nodeValue; + break; + case 'version': + $this->_version= $attribute->nodeValue; + break; + default: + parent::takeAttributeFromDOM($attribute); + } + } + + /** + * @return Zend_Gdata_App_Extension_Uri + */ + public function getUri() + { + return $this->_uri; + } + + /** + * @param Zend_Gdata_App_Extension_Uri $value + * @return Zend_Gdata_App_Entry Provides a fluent interface + */ + public function setUri($value) + { + $this->_uri = $value; + return $this; + } + + /** + * @return Zend_Gdata_App_Extension_Version + */ + public function getVersion() + { + return $this->_version; + } + + /** + * @param Zend_Gdata_App_Extension_Version $value + * @return Zend_Gdata_App_Entry Provides a fluent interface + */ + public function setVersion($value) + { + $this->_version = $value; + return $this; + } + +} diff --git a/Zend/Gdata/App/Extension/Icon.php b/Zend/Gdata/App/Extension/Icon.php new file mode 100644 index 00000000..1f3d6665 --- /dev/null +++ b/Zend/Gdata/App/Extension/Icon.php @@ -0,0 +1,49 @@ +_text = $text; + } + +} diff --git a/Zend/Gdata/App/Extension/Id.php b/Zend/Gdata/App/Extension/Id.php new file mode 100644 index 00000000..42094f37 --- /dev/null +++ b/Zend/Gdata/App/Extension/Id.php @@ -0,0 +1,49 @@ +_text = $text; + } + +} diff --git a/Zend/Gdata/App/Extension/Link.php b/Zend/Gdata/App/Extension/Link.php new file mode 100644 index 00000000..78a80e49 --- /dev/null +++ b/Zend/Gdata/App/Extension/Link.php @@ -0,0 +1,219 @@ +_href = $href; + $this->_rel = $rel; + $this->_type = $type; + $this->_hrefLang = $hrefLang; + $this->_title = $title; + $this->_length = $length; + } + + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc, $majorVersion, $minorVersion); + if ($this->_href !== null) { + $element->setAttribute('href', $this->_href); + } + if ($this->_rel !== null) { + $element->setAttribute('rel', $this->_rel); + } + if ($this->_type !== null) { + $element->setAttribute('type', $this->_type); + } + if ($this->_hrefLang !== null) { + $element->setAttribute('hreflang', $this->_hrefLang); + } + if ($this->_title !== null) { + $element->setAttribute('title', $this->_title); + } + if ($this->_length !== null) { + $element->setAttribute('length', $this->_length); + } + return $element; + } + + protected function takeAttributeFromDOM($attribute) + { + switch ($attribute->localName) { + case 'href': + $this->_href = $attribute->nodeValue; + break; + case 'rel': + $this->_rel = $attribute->nodeValue; + break; + case 'type': + $this->_type = $attribute->nodeValue; + break; + case 'hreflang': + $this->_hrefLang = $attribute->nodeValue; + break; + case 'title': + $this->_title = $attribute->nodeValue; + break; + case 'length': + $this->_length = $attribute->nodeValue; + break; + default: + parent::takeAttributeFromDOM($attribute); + } + } + + /** + * @return string|null + */ + public function getHref() + { + return $this->_href; + } + + /** + * @param string|null $value + * @return Zend_Gdata_App_Entry Provides a fluent interface + */ + public function setHref($value) + { + $this->_href = $value; + return $this; + } + + /** + * @return string|null + */ + public function getRel() + { + return $this->_rel; + } + + /** + * @param string|null $value + * @return Zend_Gdata_App_Entry Provides a fluent interface + */ + public function setRel($value) + { + $this->_rel = $value; + return $this; + } + + /** + * @return string|null + */ + public function getType() + { + return $this->_type; + } + + /** + * @param string|null $value + * @return Zend_Gdata_App_Entry Provides a fluent interface + */ + public function setType($value) + { + $this->_type = $value; + return $this; + } + + /** + * @return string|null + */ + public function getHrefLang() + { + return $this->_hrefLang; + } + + /** + * @param string|null $value + * @return Zend_Gdata_App_Entry Provides a fluent interface + */ + public function setHrefLang($value) + { + $this->_hrefLang = $value; + return $this; + } + + /** + * @return string|null + */ + public function getTitle() + { + return $this->_title; + } + + /** + * @param string|null $value + * @return Zend_Gdata_App_Entry Provides a fluent interface + */ + public function setTitle($value) + { + $this->_title = $value; + return $this; + } + + /** + * @return string|null + */ + public function getLength() + { + return $this->_length; + } + + /** + * @param string|null $value + * @return Zend_Gdata_App_Entry Provides a fluent interface + */ + public function setLength($value) + { + $this->_length = $value; + return $this; + } + +} diff --git a/Zend/Gdata/App/Extension/Logo.php b/Zend/Gdata/App/Extension/Logo.php new file mode 100644 index 00000000..cf053903 --- /dev/null +++ b/Zend/Gdata/App/Extension/Logo.php @@ -0,0 +1,49 @@ +_text = $text; + } + +} diff --git a/Zend/Gdata/App/Extension/Name.php b/Zend/Gdata/App/Extension/Name.php new file mode 100644 index 00000000..813693b0 --- /dev/null +++ b/Zend/Gdata/App/Extension/Name.php @@ -0,0 +1,48 @@ +_text = $text; + } +} diff --git a/Zend/Gdata/App/Extension/Person.php b/Zend/Gdata/App/Extension/Person.php new file mode 100644 index 00000000..74c6543b --- /dev/null +++ b/Zend/Gdata/App/Extension/Person.php @@ -0,0 +1,163 @@ +_name = $name; + $this->_email = $email; + $this->_uri = $uri; + } + + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc, $majorVersion, $minorVersion); + if ($this->_name != null) { + $element->appendChild($this->_name->getDOM($element->ownerDocument)); + } + if ($this->_email != null) { + $element->appendChild($this->_email->getDOM($element->ownerDocument)); + } + if ($this->_uri != null) { + $element->appendChild($this->_uri->getDOM($element->ownerDocument)); + } + return $element; + } + + protected function takeChildFromDOM($child) + { + $absoluteNodeName = $child->namespaceURI . ':' . $child->localName; + switch ($absoluteNodeName) { + case $this->lookupNamespace('atom') . ':' . 'name': + $name = new Zend_Gdata_App_Extension_Name(); + $name->transferFromDOM($child); + $this->_name = $name; + break; + case $this->lookupNamespace('atom') . ':' . 'email': + $email = new Zend_Gdata_App_Extension_Email(); + $email->transferFromDOM($child); + $this->_email = $email; + break; + case $this->lookupNamespace('atom') . ':' . 'uri': + $uri = new Zend_Gdata_App_Extension_Uri(); + $uri->transferFromDOM($child); + $this->_uri = $uri; + break; + default: + parent::takeChildFromDOM($child); + break; + } + } + + /** + * @return Zend_Gdata_App_Extension_Name + */ + public function getName() + { + return $this->_name; + } + + /** + * @param Zend_Gdata_App_Extension_Name $value + * @return Zend_Gdata_App_Entry Provides a fluent interface + */ + public function setName($value) + { + $this->_name = $value; + return $this; + } + + /** + * @return Zend_Gdata_App_Extension_Email + */ + public function getEmail() + { + return $this->_email; + } + + /** + * @param Zend_Gdata_App_Extension_Email $value + * @return Zend_Gdata_App_Extension_Person Provides a fluent interface + */ + public function setEmail($value) + { + $this->_email = $value; + return $this; + } + + /** + * @return Zend_Gdata_App_Extension_Uri + */ + public function getUri() + { + return $this->_uri; + } + + /** + * @param Zend_Gdata_App_Extension_Uri $value + * @return Zend_Gdata_App_Extension_Person Provides a fluent interface + */ + public function setUri($value) + { + $this->_uri = $value; + return $this; + } + +} diff --git a/Zend/Gdata/App/Extension/Published.php b/Zend/Gdata/App/Extension/Published.php new file mode 100644 index 00000000..dece31dc --- /dev/null +++ b/Zend/Gdata/App/Extension/Published.php @@ -0,0 +1,49 @@ +_text = $text; + } + +} diff --git a/Zend/Gdata/App/Extension/Rights.php b/Zend/Gdata/App/Extension/Rights.php new file mode 100644 index 00000000..b770f688 --- /dev/null +++ b/Zend/Gdata/App/Extension/Rights.php @@ -0,0 +1,49 @@ +_text = $text; + } + +} diff --git a/Zend/Gdata/App/Extension/Source.php b/Zend/Gdata/App/Extension/Source.php new file mode 100644 index 00000000..16bf4405 --- /dev/null +++ b/Zend/Gdata/App/Extension/Source.php @@ -0,0 +1,46 @@ +_text = $text; + $this->_type = $type; + } + + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc, $majorVersion, $minorVersion); + if ($this->_type !== null) { + $element->setAttribute('type', $this->_type); + } + return $element; + } + + protected function takeAttributeFromDOM($attribute) + { + switch ($attribute->localName) { + case 'type': + $this->_type = $attribute->nodeValue; + break; + default: + parent::takeAttributeFromDOM($attribute); + } + } + + /* + * @return Zend_Gdata_App_Extension_Type + */ + public function getType() + { + return $this->_type; + } + + /* + * @param string $value + * @return Zend_Gdata_App_Extension_Text Provides a fluent interface + */ + public function setType($value) + { + $this->_type = $value; + return $this; + } + +} diff --git a/Zend/Gdata/App/Extension/Title.php b/Zend/Gdata/App/Extension/Title.php new file mode 100644 index 00000000..008922cb --- /dev/null +++ b/Zend/Gdata/App/Extension/Title.php @@ -0,0 +1,43 @@ +_text = $text; + } + +} diff --git a/Zend/Gdata/App/Extension/Uri.php b/Zend/Gdata/App/Extension/Uri.php new file mode 100644 index 00000000..f60e6aa7 --- /dev/null +++ b/Zend/Gdata/App/Extension/Uri.php @@ -0,0 +1,49 @@ +_text = $text; + } + +} diff --git a/Zend/Gdata/App/Feed.php b/Zend/Gdata/App/Feed.php new file mode 100644 index 00000000..d7c713a6 --- /dev/null +++ b/Zend/Gdata/App/Feed.php @@ -0,0 +1,352 @@ +entries as $entry) or foreach + * ($feed->entry as $entry). + * + * @param string $var The property to get. + * @return mixed + */ + public function __get($var) + { + switch ($var) { + case 'entries': + return $this; + default: + return parent::__get($var); + } + } + + /** + * Retrieves the DOM model representing this object and all children + * + * @param DOMDocument $doc + * @return DOMElement + */ + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc, $majorVersion, $minorVersion); + foreach ($this->_entry as $entry) { + $element->appendChild($entry->getDOM($element->ownerDocument)); + } + return $element; + } + + /** + * Creates individual Entry objects of the appropriate type and + * stores them in the $_entry array based upon DOM data. + * + * @param DOMNode $child The DOMNode to process + */ + protected function takeChildFromDOM($child) + { + $absoluteNodeName = $child->namespaceURI . ':' . $child->localName; + switch ($absoluteNodeName) { + case $this->lookupNamespace('atom') . ':' . 'entry': + $newEntry = new $this->_entryClassName($child); + $newEntry->setHttpClient($this->getHttpClient()); + $newEntry->setMajorProtocolVersion($this->getMajorProtocolVersion()); + $newEntry->setMinorProtocolVersion($this->getMinorProtocolVersion()); + $this->_entry[] = $newEntry; + break; + default: + parent::takeChildFromDOM($child); + break; + } + } + + /** + * Get the number of entries in this feed object. + * + * @return integer Entry count. + */ + public function count() + { + return count($this->_entry); + } + + /** + * Required by the Iterator interface. + * + * @return void + */ + public function rewind() + { + $this->_entryIndex = 0; + } + + /** + * Required by the Iterator interface. + * + * @return mixed The current row, or null if no rows. + */ + public function current() + { + return $this->_entry[$this->_entryIndex]; + } + + /** + * Required by the Iterator interface. + * + * @return mixed The current row number (starts at 0), or NULL if no rows + */ + public function key() + { + return $this->_entryIndex; + } + + /** + * Required by the Iterator interface. + * + * @return mixed The next row, or null if no more rows. + */ + public function next() + { + ++$this->_entryIndex; + } + + /** + * Required by the Iterator interface. + * + * @return boolean Whether the iteration is valid + */ + public function valid() + { + return 0 <= $this->_entryIndex && $this->_entryIndex < $this->count(); + } + + /** + * Gets the array of atom:entry elements contained within this + * atom:feed representation + * + * @return array Zend_Gdata_App_Entry array + */ + public function getEntry() + { + return $this->_entry; + } + + /** + * Sets the array of atom:entry elements contained within this + * atom:feed representation + * + * @param array $value The array of Zend_Gdata_App_Entry elements + * @return Zend_Gdata_App_Feed Provides a fluent interface + */ + public function setEntry($value) + { + $this->_entry = $value; + return $this; + } + + /** + * Adds an entry representation to the array of entries + * contained within this feed + * + * @param Zend_Gdata_App_Entry An individual entry to add. + * @return Zend_Gdata_App_Feed Provides a fluent interface + */ + public function addEntry($value) + { + $this->_entry[] = $value; + return $this; + } + + /** + * Required by the ArrayAccess interface + * + * @param int $key The index to set + * @param Zend_Gdata_App_Entry $value The value to set + * @return void + */ + public function offsetSet($key, $value) + { + $this->_entry[$key] = $value; + } + + /** + * Required by the ArrayAccess interface + * + * @param int $key The index to get + * @param Zend_Gdata_App_Entry $value The value to set + */ + public function offsetGet($key) + { + if (array_key_exists($key, $this->_entry)) { + return $this->_entry[$key]; + } + } + + /** + * Required by the ArrayAccess interface + * + * @param int $key The index to set + * @param Zend_Gdata_App_Entry $value The value to set + */ + public function offsetUnset($key) + { + if (array_key_exists($key, $this->_entry)) { + unset($this->_entry[$key]); + } + } + + /** + * Required by the ArrayAccess interface + * + * @param int $key The index to check for existence + * @return boolean + */ + public function offsetExists($key) + { + return (array_key_exists($key, $this->_entry)); + } + + /** + * Retrieve the next set of results from this feed. + * + * @throws Zend_Gdata_App_Exception + * @return mixed|null Returns the next set of results as a feed of the same + * class as this feed, or null if no results exist. + */ + public function getNextFeed() + { + $nextLink = $this->getNextLink(); + if (!$nextLink) { + require_once 'Zend/Gdata/App/HttpException.php'; + throw new Zend_Gdata_App_Exception('No link to next set ' . + 'of results found.'); + } + $nextLinkHref = $nextLink->getHref(); + $service = new Zend_Gdata_App($this->getHttpClient()); + + return $service->getFeed($nextLinkHref, get_class($this)); + } + + /** + * Retrieve the previous set of results from this feed. + * + * @throws Zend_Gdata_App_Exception + * @return mixed|null Returns the previous set of results as a feed of + * the same class as this feed, or null if no results exist. + */ + public function getPreviousFeed() + { + $previousLink = $this->getPreviousLink(); + if (!$previousLink) { + require_once 'Zend/Gdata/App/HttpException.php'; + throw new Zend_Gdata_App_Exception('No link to previous set ' . + 'of results found.'); + } + $previousLinkHref = $previousLink->getHref(); + $service = new Zend_Gdata_App($this->getHttpClient()); + + return $service->getFeed($previousLinkHref, get_class($this)); + } + + /** + * Set the major protocol version that should be used. Values < 1 will + * cause a Zend_Gdata_App_InvalidArgumentException to be thrown. + * + * This value will be propogated to all child entries. + * + * @see _majorProtocolVersion + * @param (int|NULL) $value The major protocol version to use. + * @throws Zend_Gdata_App_InvalidArgumentException + */ + public function setMajorProtocolVersion($value) + { + parent::setMajorProtocolVersion($value); + foreach ($this->entries as $entry) { + $entry->setMajorProtocolVersion($value); + } + } + + /** + * Set the minor protocol version that should be used. If set to NULL, no + * minor protocol version will be sent to the server. Values < 0 will + * cause a Zend_Gdata_App_InvalidArgumentException to be thrown. + * + * This value will be propogated to all child entries. + * + * @see _minorProtocolVersion + * @param (int|NULL) $value The minor protocol version to use. + * @throws Zend_Gdata_App_InvalidArgumentException + */ + public function setMinorProtocolVersion($value) + { + parent::setMinorProtocolVersion($value); + foreach ($this->entries as $entry) { + $entry->setMinorProtocolVersion($value); + } + } + +} diff --git a/Zend/Gdata/App/FeedEntryParent.php b/Zend/Gdata/App/FeedEntryParent.php new file mode 100644 index 00000000..d92e639a --- /dev/null +++ b/Zend/Gdata/App/FeedEntryParent.php @@ -0,0 +1,681 @@ += 1 is considered valid. + * + * @see setMajorProtocolVersion() + * @see getMajorProtocolVersion() + */ + protected $_majorProtocolVersion = 1; + + /** + * Indicates the minor protocol version that should be used. Can be set + * to either an integer >= 0, or NULL if no minor version should be sent + * to the server. + * + * @see setMinorProtocolVersion() + * @see getMinorProtocolVersion() + */ + protected $_minorProtocolVersion = null; + + /** + * Constructs a Feed or Entry + */ + public function __construct($element = null) + { + if (!($element instanceof DOMElement)) { + if ($element) { + $this->transferFromXML($element); + } + } else { + $this->transferFromDOM($element); + } + } + + /** + * Set the HTTP client instance + * + * Sets the HTTP client object to use for retrieving the feed. + * + * @deprecated Deprecated as of Zend Framework 1.7. Use + * setService() instead. + * @param Zend_Http_Client $httpClient + * @return Zend_Gdata_App_FeedEntryParent Provides a fluent interface + */ + public function setHttpClient(Zend_Http_Client $httpClient) + { + if (!$this->_service) { + $this->_service = new Zend_Gdata_App(); + } + $this->_service->setHttpClient($httpClient); + return $this; + } + + /** + * Gets the HTTP client object. If none is set, a new Zend_Http_Client + * will be used. + * + * @deprecated Deprecated as of Zend Framework 1.7. Use + * getService() instead. + * @return Zend_Http_Client_Abstract + */ + public function getHttpClient() + { + if (!$this->_service) { + $this->_service = new Zend_Gdata_App(); + } + $client = $this->_service->getHttpClient(); + return $client; + } + + /** + * Set the active service instance for this object. This will be used to + * perform network requests, such as when calling save() and delete(). + * + * @param Zend_Gdata_App $instance The new service instance. + * @return Zend_Gdata_App_FeedEntryParent Provides a fluent interface. + */ + public function setService($instance) + { + $this->_service = $instance; + return $this; + } + + /** + * Get the active service instance for this object. This will be used to + * perform network requests, such as when calling save() and delete(). + * + * @return Zend_Gdata_App|null The current service instance, or null if + * not set. + */ + public function getService() + { + return $this->_service; + } + + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc, $majorVersion, $minorVersion); + foreach ($this->_author as $author) { + $element->appendChild($author->getDOM($element->ownerDocument)); + } + foreach ($this->_category as $category) { + $element->appendChild($category->getDOM($element->ownerDocument)); + } + foreach ($this->_contributor as $contributor) { + $element->appendChild($contributor->getDOM($element->ownerDocument)); + } + if ($this->_id != null) { + $element->appendChild($this->_id->getDOM($element->ownerDocument)); + } + foreach ($this->_link as $link) { + $element->appendChild($link->getDOM($element->ownerDocument)); + } + if ($this->_rights != null) { + $element->appendChild($this->_rights->getDOM($element->ownerDocument)); + } + if ($this->_title != null) { + $element->appendChild($this->_title->getDOM($element->ownerDocument)); + } + if ($this->_updated != null) { + $element->appendChild($this->_updated->getDOM($element->ownerDocument)); + } + return $element; + } + + protected function takeChildFromDOM($child) + { + $absoluteNodeName = $child->namespaceURI . ':' . $child->localName; + switch ($absoluteNodeName) { + case $this->lookupNamespace('atom') . ':' . 'author': + $author = new Zend_Gdata_App_Extension_Author(); + $author->transferFromDOM($child); + $this->_author[] = $author; + break; + case $this->lookupNamespace('atom') . ':' . 'category': + $category = new Zend_Gdata_App_Extension_Category(); + $category->transferFromDOM($child); + $this->_category[] = $category; + break; + case $this->lookupNamespace('atom') . ':' . 'contributor': + $contributor = new Zend_Gdata_App_Extension_Contributor(); + $contributor->transferFromDOM($child); + $this->_contributor[] = $contributor; + break; + case $this->lookupNamespace('atom') . ':' . 'id': + $id = new Zend_Gdata_App_Extension_Id(); + $id->transferFromDOM($child); + $this->_id = $id; + break; + case $this->lookupNamespace('atom') . ':' . 'link': + $link = new Zend_Gdata_App_Extension_Link(); + $link->transferFromDOM($child); + $this->_link[] = $link; + break; + case $this->lookupNamespace('atom') . ':' . 'rights': + $rights = new Zend_Gdata_App_Extension_Rights(); + $rights->transferFromDOM($child); + $this->_rights = $rights; + break; + case $this->lookupNamespace('atom') . ':' . 'title': + $title = new Zend_Gdata_App_Extension_Title(); + $title->transferFromDOM($child); + $this->_title = $title; + break; + case $this->lookupNamespace('atom') . ':' . 'updated': + $updated = new Zend_Gdata_App_Extension_Updated(); + $updated->transferFromDOM($child); + $this->_updated = $updated; + break; + default: + parent::takeChildFromDOM($child); + break; + } + } + + /** + * @return Zend_Gdata_App_Extension_Author + */ + public function getAuthor() + { + return $this->_author; + } + + /** + * Sets the list of the authors of this feed/entry. In an atom feed, each + * author is represented by an atom:author element + * + * @param array $value + * @return Zend_Gdata_App_FeedEntryParent Provides a fluent interface + */ + public function setAuthor($value) + { + $this->_author = $value; + return $this; + } + + /** + * Returns the array of categories that classify this feed/entry. Each + * category is represented in an atom feed by an atom:category element. + * + * @return array Array of Zend_Gdata_App_Extension_Category + */ + public function getCategory() + { + return $this->_category; + } + + /** + * Sets the array of categories that classify this feed/entry. Each + * category is represented in an atom feed by an atom:category element. + * + * @param array $value Array of Zend_Gdata_App_Extension_Category + * @return Zend_Gdata_App_FeedEntryParent Provides a fluent interface + */ + public function setCategory($value) + { + $this->_category = $value; + return $this; + } + + /** + * Returns the array of contributors to this feed/entry. Each contributor + * is represented in an atom feed by an atom:contributor XML element + * + * @return array An array of Zend_Gdata_App_Extension_Contributor + */ + public function getContributor() + { + return $this->_contributor; + } + + /** + * Sets the array of contributors to this feed/entry. Each contributor + * is represented in an atom feed by an atom:contributor XML element + * + * @param array $value + * @return Zend_Gdata_App_FeedEntryParent Provides a fluent interface + */ + public function setContributor($value) + { + $this->_contributor = $value; + return $this; + } + + /** + * @return Zend_Gdata_App_Extension_Id + */ + public function getId() + { + return $this->_id; + } + + /** + * @param Zend_Gdata_App_Extension_Id $value + * @return Zend_Gdata_App_FeedEntryParent Provides a fluent interface + */ + public function setId($value) + { + $this->_id = $value; + return $this; + } + + /** + * Given a particular 'rel' value, this method returns a matching + * Zend_Gdata_App_Extension_Link element. If the 'rel' value + * is not provided, the full array of Zend_Gdata_App_Extension_Link + * elements is returned. In an atom feed, each link is represented + * by an atom:link element. The 'rel' value passed to this function + * is the atom:link/@rel attribute. Example rel values include 'self', + * 'edit', and 'alternate'. + * + * @param string $rel The rel value of the link to be found. If null, + * the array of Zend_Gdata_App_Extension_link elements is returned + * @return mixed Either a single Zend_Gdata_App_Extension_link element, + * an array of the same or null is returned depending on the rel value + * supplied as the argument to this function + */ + public function getLink($rel = null) + { + if ($rel == null) { + return $this->_link; + } else { + foreach ($this->_link as $link) { + if ($link->rel == $rel) { + return $link; + } + } + return null; + } + } + + /** + * Returns the Zend_Gdata_App_Extension_Link element which represents + * the URL used to edit this resource. This link is in the atom feed/entry + * as an atom:link with a rel attribute value of 'edit'. + * + * @return Zend_Gdata_App_Extension_Link The link, or null if not found + */ + public function getEditLink() + { + return $this->getLink('edit'); + } + + /** + * Returns the Zend_Gdata_App_Extension_Link element which represents + * the URL used to retrieve the next chunk of results when paging through + * a feed. This link is in the atom feed as an atom:link with a + * rel attribute value of 'next'. + * + * @return Zend_Gdata_App_Extension_Link The link, or null if not found + */ + public function getNextLink() + { + return $this->getLink('next'); + } + + /** + * Returns the Zend_Gdata_App_Extension_Link element which represents + * the URL used to retrieve the previous chunk of results when paging + * through a feed. This link is in the atom feed as an atom:link with a + * rel attribute value of 'previous'. + * + * @return Zend_Gdata_App_Extension_Link The link, or null if not found + */ + public function getPreviousLink() + { + return $this->getLink('previous'); + } + + /** + * @return Zend_Gdata_App_Extension_Link + */ + public function getLicenseLink() + { + return $this->getLink('license'); + } + + /** + * Returns the Zend_Gdata_App_Extension_Link element which represents + * the URL used to retrieve the entry or feed represented by this object + * This link is in the atom feed/entry as an atom:link with a + * rel attribute value of 'self'. + * + * @return Zend_Gdata_App_Extension_Link The link, or null if not found + */ + public function getSelfLink() + { + return $this->getLink('self'); + } + + /** + * Returns the Zend_Gdata_App_Extension_Link element which represents + * the URL for an alternate view of the data represented by this feed or + * entry. This alternate view is commonly a user-facing webpage, blog + * post, etc. The MIME type for the data at the URL is available from the + * returned Zend_Gdata_App_Extension_Link element. + * This link is in the atom feed/entry as an atom:link with a + * rel attribute value of 'self'. + * + * @return Zend_Gdata_App_Extension_Link The link, or null if not found + */ + public function getAlternateLink() + { + return $this->getLink('alternate'); + } + + /** + * @param array $value The array of Zend_Gdata_App_Extension_Link elements + * @return Zend_Gdata_App_FeedEntryParent Provides a fluent interface + */ + public function setLink($value) + { + $this->_link = $value; + return $this; + } + + /** + * @return Zend_Gdata_AppExtension_Rights + */ + public function getRights() + { + return $this->_rights; + } + + /** + * @param Zend_Gdata_App_Extension_Rights $value + * @return Zend_Gdata_App_FeedEntryParent Provides a fluent interface + */ + public function setRights($value) + { + $this->_rights = $value; + return $this; + } + + /** + * Returns the title of this feed or entry. The title is an extremely + * short textual representation of this resource and is found as + * an atom:title element in a feed or entry + * + * @return Zend_Gdata_App_Extension_Title + */ + public function getTitle() + { + return $this->_title; + } + + /** + * Returns a string representation of the title of this feed or entry. + * The title is an extremely short textual representation of this + * resource and is found as an atom:title element in a feed or entry + * + * @return string + */ + public function getTitleValue() + { + if (($titleObj = $this->getTitle()) != null) { + return $titleObj->getText(); + } else { + return null; + } + } + + /** + * Returns the title of this feed or entry. The title is an extremely + * short textual representation of this resource and is found as + * an atom:title element in a feed or entry + * + * @param Zend_Gdata_App_Extension_Title $value + * @return Zend_Gdata_App_FeedEntryParent Provides a fluent interface + */ + public function setTitle($value) + { + $this->_title = $value; + return $this; + } + + /** + * @return Zend_Gdata_App_Extension_Updated + */ + public function getUpdated() + { + return $this->_updated; + } + + /** + * @param Zend_Gdata_App_Extension_Updated $value + * @return Zend_Gdata_App_FeedEntryParent Provides a fluent interface + */ + public function setUpdated($value) + { + $this->_updated = $value; + return $this; + } + + /** + * Set the Etag for the current entry to $value. Setting $value to null + * unsets the Etag. + * + * @param string|null $value + * @return Zend_Gdata_App_Entry Provides a fluent interface + */ + public function setEtag($value) { + $this->_etag = $value; + return $this; + } + + /** + * Return the Etag for the current entry, or null if not set. + * + * @return string|null + */ + public function getEtag() { + return $this->_etag; + } + + /** + * Set the major protocol version that should be used. Values < 1 + * (excluding NULL) will cause a Zend_Gdata_App_InvalidArgumentException + * to be thrown. + * + * @see _majorProtocolVersion + * @param (int|NULL) $value The major protocol version to use. + * @throws Zend_Gdata_App_InvalidArgumentException + */ + public function setMajorProtocolVersion($value) + { + if (!($value >= 1) && ($value !== null)) { + require_once('Zend/Gdata/App/InvalidArgumentException.php'); + throw new Zend_Gdata_App_InvalidArgumentException( + 'Major protocol version must be >= 1'); + } + $this->_majorProtocolVersion = $value; + } + + /** + * Get the major protocol version that is in use. + * + * @see _majorProtocolVersion + * @return (int|NULL) The major protocol version in use. + */ + public function getMajorProtocolVersion() + { + return $this->_majorProtocolVersion; + } + + /** + * Set the minor protocol version that should be used. If set to NULL, no + * minor protocol version will be sent to the server. Values < 0 will + * cause a Zend_Gdata_App_InvalidArgumentException to be thrown. + * + * @see _minorProtocolVersion + * @param (int|NULL) $value The minor protocol version to use. + * @throws Zend_Gdata_App_InvalidArgumentException + */ + public function setMinorProtocolVersion($value) + { + if (!($value >= 0)) { + require_once('Zend/Gdata/App/InvalidArgumentException.php'); + throw new Zend_Gdata_App_InvalidArgumentException( + 'Minor protocol version must be >= 0 or null'); + } + $this->_minorProtocolVersion = $value; + } + + /** + * Get the minor protocol version that is in use. + * + * @see _minorProtocolVersion + * @return (int|NULL) The major protocol version in use, or NULL if no + * minor version is specified. + */ + public function getMinorProtocolVersion() + { + return $this->_minorProtocolVersion; + } + + /** + * Get the full version of a namespace prefix + * + * Looks up a prefix (atom:, etc.) in the list of registered + * namespaces and returns the full namespace URI if + * available. Returns the prefix, unmodified, if it's not + * registered. + * + * The current entry or feed's version will be used when performing the + * namespace lookup unless overridden using $majorVersion and + * $minorVersion. If the entry/fee has a null version, then the latest + * protocol version will be used by default. + * + * @param string $prefix The namespace prefix to lookup. + * @param integer $majorVersion The major protocol version in effect. + * Defaults to null (auto-select). + * @param integer $minorVersion The minor protocol version in effect. + * Defaults to null (auto-select). + * @return string + */ + public function lookupNamespace($prefix, + $majorVersion = null, + $minorVersion = null) + { + // Auto-select current version + if ($majorVersion === null) { + $majorVersion = $this->getMajorProtocolVersion(); + } + if ($minorVersion === null) { + $minorVersion = $this->getMinorProtocolVersion(); + } + + // Perform lookup + return parent::lookupNamespace($prefix, $majorVersion, $minorVersion); + } + +} diff --git a/Zend/Gdata/App/FeedSourceParent.php b/Zend/Gdata/App/FeedSourceParent.php new file mode 100644 index 00000000..d1f08f96 --- /dev/null +++ b/Zend/Gdata/App/FeedSourceParent.php @@ -0,0 +1,267 @@ +_entry as $entry) { + $entry->setHttpClient($httpClient); + } + return $this; + } + + /** + * Set the active service instance for this feed and all enclosed entries. + * This will be used to perform network requests, such as when calling + * save() and delete(). + * + * @param Zend_Gdata_App $instance The new service instance. + * @return Zend_Gdata_App_FeedEntryParent Provides a fluent interface. + */ + public function setService($instance) + { + parent::setService($instance); + foreach ($this->_entry as $entry) { + $entry->setService($instance); + } + return $this; + } + + /** + * Make accessing some individual elements of the feed easier. + * + * Special accessors 'entry' and 'entries' are provided so that if + * you wish to iterate over an Atom feed's entries, you can do so + * using foreach ($feed->entries as $entry) or foreach + * ($feed->entry as $entry). + * + * @param string $var The property to access. + * @return mixed + */ + public function __get($var) + { + switch ($var) { + default: + return parent::__get($var); + } + } + + + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc, $majorVersion, $minorVersion); + if ($this->_generator != null) { + $element->appendChild($this->_generator->getDOM($element->ownerDocument)); + } + if ($this->_icon != null) { + $element->appendChild($this->_icon->getDOM($element->ownerDocument)); + } + if ($this->_logo != null) { + $element->appendChild($this->_logo->getDOM($element->ownerDocument)); + } + if ($this->_subtitle != null) { + $element->appendChild($this->_subtitle->getDOM($element->ownerDocument)); + } + return $element; + } + + /** + * Creates individual Entry objects of the appropriate type and + * stores them in the $_entry array based upon DOM data. + * + * @param DOMNode $child The DOMNode to process + */ + protected function takeChildFromDOM($child) + { + $absoluteNodeName = $child->namespaceURI . ':' . $child->localName; + switch ($absoluteNodeName) { + case $this->lookupNamespace('atom') . ':' . 'generator': + $generator = new Zend_Gdata_App_Extension_Generator(); + $generator->transferFromDOM($child); + $this->_generator = $generator; + break; + case $this->lookupNamespace('atom') . ':' . 'icon': + $icon = new Zend_Gdata_App_Extension_Icon(); + $icon->transferFromDOM($child); + $this->_icon = $icon; + break; + case $this->lookupNamespace('atom') . ':' . 'logo': + $logo = new Zend_Gdata_App_Extension_Logo(); + $logo->transferFromDOM($child); + $this->_logo = $logo; + break; + case $this->lookupNamespace('atom') . ':' . 'subtitle': + $subtitle = new Zend_Gdata_App_Extension_Subtitle(); + $subtitle->transferFromDOM($child); + $this->_subtitle = $subtitle; + break; + default: + parent::takeChildFromDOM($child); + break; + } + } + + /** + * @return Zend_Gdata_AppExtension_Generator + */ + public function getGenerator() + { + return $this->_generator; + } + + /** + * @param Zend_Gdata_App_Extension_Generator $value + * @return Zend_Gdata_App_FeedSourceParent Provides a fluent interface + */ + public function setGenerator($value) + { + $this->_generator = $value; + return $this; + } + + /** + * @return Zend_Gdata_AppExtension_Icon + */ + public function getIcon() + { + return $this->_icon; + } + + /** + * @param Zend_Gdata_App_Extension_Icon $value + * @return Zend_Gdata_App_FeedSourceParent Provides a fluent interface + */ + public function setIcon($value) + { + $this->_icon = $value; + return $this; + } + + /** + * @return Zend_Gdata_AppExtension_logo + */ + public function getlogo() + { + return $this->_logo; + } + + /** + * @param Zend_Gdata_App_Extension_logo $value + * @return Zend_Gdata_App_FeedSourceParent Provides a fluent interface + */ + public function setlogo($value) + { + $this->_logo = $value; + return $this; + } + + /** + * @return Zend_Gdata_AppExtension_Subtitle + */ + public function getSubtitle() + { + return $this->_subtitle; + } + + /** + * @param Zend_Gdata_App_Extension_Subtitle $value + * @return Zend_Gdata_App_FeedSourceParent Provides a fluent interface + */ + public function setSubtitle($value) + { + $this->_subtitle = $value; + return $this; + } + +} diff --git a/Zend/Gdata/App/HttpException.php b/Zend/Gdata/App/HttpException.php new file mode 100644 index 00000000..92ba020d --- /dev/null +++ b/Zend/Gdata/App/HttpException.php @@ -0,0 +1,121 @@ +_httpClientException = $e; + $this->_response = $response; + parent::__construct($message); + } + + /** + * Get the Zend_Http_Client_Exception. + * + * @return Zend_Http_Client_Exception + */ + public function getHttpClientException() + { + return $this->_httpClientException; + } + + /** + * Set the Zend_Http_Client_Exception. + * + * @param Zend_Http_Client_Exception $value + */ + public function setHttpClientException($value) + { + $this->_httpClientException = $value; + return $this; + } + + /** + * Set the Zend_Http_Response. + * + * @param Zend_Http_Response $response + */ + public function setResponse($response) + { + $this->_response = $response; + return $this; + } + + /** + * Get the Zend_Http_Response. + * + * @return Zend_Http_Response + */ + public function getResponse() + { + return $this->_response; + } + + /** + * Get the body of the Zend_Http_Response + * + * @return string + */ + public function getRawResponseBody() + { + if ($this->getResponse()) { + $response = $this->getResponse(); + return $response->getRawBody(); + } + return null; + } + +} diff --git a/Zend/Gdata/App/IOException.php b/Zend/Gdata/App/IOException.php new file mode 100644 index 00000000..f8308e02 --- /dev/null +++ b/Zend/Gdata/App/IOException.php @@ -0,0 +1,43 @@ +log_handle == null) { + $this->log_handle = fopen($this->config['logfile'], 'a'); + } + fwrite($this->log_handle, $message); + } + + /** + * Connect to the remote server + * + * @param string $host + * @param int $port + * @param boolean $secure + * @param int $timeout + */ + public function connect($host, $port = 80, $secure = false) + { + $this->log("Connecting to: ${host}:${port}"); + return parent::connect($host, $port, $secure); + } + + /** + * Send request to the remote server + * + * @param string $method + * @param Zend_Uri_Http $uri + * @param string $http_ver + * @param array $headers + * @param string $body + * @return string Request as string + */ + public function write($method, $uri, $http_ver = '1.1', $headers = array(), $body = '') + { + $request = parent::write($method, $uri, $http_ver, $headers, $body); + $this->log("\n\n" . $request); + return $request; + } + + /** + * Read response from server + * + * @return string + */ + public function read() + { + $response = parent::read(); + $this->log("${response}\n\n"); + return $response; + } + + /** + * Close the connection to the server + * + */ + public function close() + { + $this->log("Closing socket\n\n"); + parent::close(); + } + +} diff --git a/Zend/Gdata/App/MediaEntry.php b/Zend/Gdata/App/MediaEntry.php new file mode 100644 index 00000000..0d6a90de --- /dev/null +++ b/Zend/Gdata/App/MediaEntry.php @@ -0,0 +1,119 @@ +_mediaSource = $mediaSource; + } + + /** + * Return the MIME multipart representation of this MediaEntry. + * + * @return string|Zend_Gdata_MediaMimeStream The MIME multipart + * representation of this MediaEntry. If the entry consisted only + * of XML, a string is returned. + */ + public function encode() + { + $xmlData = $this->saveXML(); + $mediaSource = $this->getMediaSource(); + if ($mediaSource === null) { + // No attachment, just send XML for entry + return $xmlData; + } else { + return new Zend_Gdata_MediaMimeStream($xmlData, + $mediaSource->getFilename(), $mediaSource->getContentType()); + } + } + + /** + * Return the MediaSource object representing the file attached to this + * MediaEntry. + * + * @return Zend_Gdata_App_MediaSource The attached MediaSource/file + */ + public function getMediaSource() + { + return $this->_mediaSource; + } + + /** + * Set the MediaSource object (file) for this MediaEntry + * + * @param Zend_Gdata_App_MediaSource $value The attached MediaSource/file + * @return Zend_Gdata_App_MediaEntry Provides a fluent interface + */ + public function setMediaSource($value) + { + if ($value instanceof Zend_Gdata_App_MediaSource) { + $this->_mediaSource = $value; + } else { + require_once 'Zend/Gdata/App/InvalidArgumentException.php'; + throw new Zend_Gdata_App_InvalidArgumentException( + 'You must specify the media data as a class that conforms to Zend_Gdata_App_MediaSource.'); + } + return $this; + } + +} diff --git a/Zend/Gdata/App/MediaFileSource.php b/Zend/Gdata/App/MediaFileSource.php new file mode 100644 index 00000000..b860968d --- /dev/null +++ b/Zend/Gdata/App/MediaFileSource.php @@ -0,0 +1,146 @@ +setFilename($filename); + } + + /** + * Return the MIME multipart representation of this MediaEntry. + * + * @return string + * @throws Zend_Gdata_App_IOException + */ + public function encode() + { + if ($this->getFilename() !== null && + is_readable($this->getFilename())) { + + // Retrieves the file, using the include path + $fileHandle = fopen($this->getFilename(), 'r', true); + $result = fread($fileHandle, filesize($this->getFilename())); + if ($result === false) { + require_once 'Zend/Gdata/App/IOException.php'; + throw new Zend_Gdata_App_IOException("Error reading file - " . + $this->getFilename() . '. Read failed.'); + } + fclose($fileHandle); + return $result; + } else { + require_once 'Zend/Gdata/App/IOException.php'; + throw new Zend_Gdata_App_IOException("Error reading file - " . + $this->getFilename() . '. File is not readable.'); + } + } + + /** + * Get the filename associated with this reader. + * + * @return string + */ + public function getFilename() + { + return $this->_filename; + } + + /** + * Set the filename which is to be read. + * + * @param string $value The desired file handle. + * @return Zend_Gdata_App_MediaFileSource Provides a fluent interface. + */ + public function setFilename($value) + { + $this->_filename = $value; + return $this; + } + + /** + * The content type for the file attached (example image/png) + * + * @return string The content type + */ + public function getContentType() + { + return $this->_contentType; + } + + /** + * Set the content type for the file attached (example image/png) + * + * @param string $value The content type + * @return Zend_Gdata_App_MediaFileSource Provides a fluent interface + */ + public function setContentType($value) + { + $this->_contentType = $value; + return $this; + } + + /** + * Alias for getFilename(). + * + * @return string + */ + public function __toString() + { + return $this->getFilename(); + } + +} diff --git a/Zend/Gdata/App/MediaSource.php b/Zend/Gdata/App/MediaSource.php new file mode 100644 index 00000000..d8d89238 --- /dev/null +++ b/Zend/Gdata/App/MediaSource.php @@ -0,0 +1,73 @@ + 0) { + // timestamp is already properly formatted + return $timestamp; + } else { + $ts = strtotime($timestamp); + if ($ts === false) { + require_once 'Zend/Gdata/App/InvalidArgumentException.php'; + throw new Zend_Gdata_App_InvalidArgumentException("Invalid timestamp: $timestamp."); + } + return date('Y-m-d\TH:i:s', $ts); + } + } + + /** Find the greatest key that is less than or equal to a given upper + * bound, and return the value associated with that key. + * + * @param integer|null $maximumKey The upper bound for keys. If null, the + * maxiumum valued key will be found. + * @param array $collection An two-dimensional array of key/value pairs + * to search through. + * @returns mixed The value corresponding to the located key. + * @throws Zend_Gdata_App_Exception Thrown if $collection is empty. + */ + public static function findGreatestBoundedValue($maximumKey, $collection) + { + $found = false; + $foundKey = $maximumKey; + + // Sanity check: Make sure that the collection isn't empty + if (sizeof($collection) == 0) { + require_once 'Zend/Gdata/App/Exception.php'; + throw new Zend_Gdata_App_Exception("Empty namespace collection encountered."); + } + + if ($maximumKey === null) { + // If the key is null, then we return the maximum available + $keys = array_keys($collection); + sort($keys); + $found = true; + $foundKey = end($keys); + } else { + // Otherwise, we optimistically guess that the current version + // will have a matching namespce. If that fails, we decrement the + // version until we find a match. + while (!$found && $foundKey >= 0) { + if (array_key_exists($foundKey, $collection)) + $found = true; + else + $foundKey--; + } + } + + // Guard: A namespace wasn't found. Either none were registered, or + // the current protcol version is lower than the maximum namespace. + if (!$found) { + require_once 'Zend/Gdata/App/Exception.php'; + throw new Zend_Gdata_App_Exception("Namespace compatible with current protocol not found."); + } + + return $foundKey; + } + +} diff --git a/Zend/Gdata/App/VersionException.php b/Zend/Gdata/App/VersionException.php new file mode 100644 index 00000000..77c7366d --- /dev/null +++ b/Zend/Gdata/App/VersionException.php @@ -0,0 +1,42 @@ +filterHttpRequest('GET', $request_uri); + $url = $filterResult['url']; + $headers = $filterResult['headers']; + $client->setHeaders($headers); + $client->setUri($url); + } else { + $client->setUri($request_uri); + } + + try { + $response = $client->request('GET'); + } catch (Zend_Http_Client_Exception $e) { + require_once 'Zend/Gdata/App/HttpException.php'; + throw new Zend_Gdata_App_HttpException($e->getMessage(), $e); + } + + // Parse Google's response + if ($response->isSuccessful()) { + $goog_resp = array(); + foreach (explode("\n", $response->getBody()) as $l) { + $l = chop($l); + if ($l) { + list($key, $val) = explode('=', chop($l), 2); + $goog_resp[$key] = $val; + } + } + return $goog_resp['Token']; + } else { + require_once 'Zend/Gdata/App/AuthException.php'; + throw new Zend_Gdata_App_AuthException( + 'Token upgrade failed. Reason: ' . $response->getBody()); + } + } + + /** + * Revoke a token + * + * @param string $token The token to revoke + * @param Zend_Http_Client $client (optional) HTTP client to use to make the request + * @param string $request_uri (optional) URI to which to direct the revokation request + * @return boolean Whether the revokation was successful + * @throws Zend_Gdata_App_HttpException + */ + public static function AuthSubRevokeToken($token, $client = null, + $request_uri = self::AUTHSUB_REVOKE_TOKEN_URI) + { + $client = self::getHttpClient($token, $client); + + if ($client instanceof Zend_Gdata_HttpClient) { + $filterResult = $client->filterHttpRequest('GET', $request_uri); + $url = $filterResult['url']; + $headers = $filterResult['headers']; + $client->setHeaders($headers); + $client->setUri($url); + $client->resetParameters(); + } else { + $client->setUri($request_uri); + } + + ob_start(); + try { + $response = $client->request('GET'); + } catch (Zend_Http_Client_Exception $e) { + require_once 'Zend/Gdata/App/HttpException.php'; + throw new Zend_Gdata_App_HttpException($e->getMessage(), $e); + } + ob_end_clean(); + // Parse Google's response + if ($response->isSuccessful()) { + return true; + } else { + return false; + } + } + + + /** + * get token information + * + * @param string $token The token to retrieve information about + * @param Zend_Http_Client $client (optional) HTTP client to use to + * make the request + * @param string $request_uri (optional) URI to which to direct + * the information request + */ + public static function getAuthSubTokenInfo( + $token, $client = null, $request_uri = self::AUTHSUB_TOKEN_INFO_URI) + { + $client = self::getHttpClient($token, $client); + + if ($client instanceof Zend_Gdata_HttpClient) { + $filterResult = $client->filterHttpRequest('GET', $request_uri); + $url = $filterResult['url']; + $headers = $filterResult['headers']; + $client->setHeaders($headers); + $client->setUri($url); + } else { + $client->setUri($request_uri); + } + + ob_start(); + try { + $response = $client->request('GET'); + } catch (Zend_Http_Client_Exception $e) { + require_once 'Zend/Gdata/App/HttpException.php'; + throw new Zend_Gdata_App_HttpException($e->getMessage(), $e); + } + ob_end_clean(); + return $response->getBody(); + } + + /** + * Retrieve a HTTP client object with AuthSub credentials attached + * as the Authorization header + * + * @param string $token The token to retrieve information about + * @param Zend_Gdata_HttpClient $client (optional) HTTP client to use to make the request + */ + public static function getHttpClient($token, $client = null) + { + if ($client == null) { + $client = new Zend_Gdata_HttpClient(); + } + if (!$client instanceof Zend_Http_Client) { + require_once 'Zend/Gdata/App/HttpException.php'; + throw new Zend_Gdata_App_HttpException('Client is not an instance of Zend_Http_Client.'); + } + $useragent = 'Zend_Framework_Gdata/' . Zend_Version::VERSION; + $client->setConfig(array( + 'strictredirects' => true, + 'useragent' => $useragent + ) + ); + $client->setAuthSubToken($token); + return $client; + } + +} diff --git a/Zend/Gdata/Books.php b/Zend/Gdata/Books.php new file mode 100644 index 00000000..db77c8eb --- /dev/null +++ b/Zend/Gdata/Books.php @@ -0,0 +1,204 @@ +registerPackage('Zend_Gdata_Books'); + $this->registerPackage('Zend_Gdata_Books_Extension'); + parent::__construct($client, $applicationId); + $this->_httpClient->setParameterPost('service', self::AUTH_SERVICE_NAME); + } + + /** + * Retrieves a feed of volumes. + * + * @param Zend_Gdata_Query|string|null $location (optional) The URL to + * query or a Zend_Gdata_Query object from which a URL can be + * determined. + * @return Zend_Gdata_Books_VolumeFeed The feed of volumes found at the + * specified URL. + */ + public function getVolumeFeed($location = null) + { + if ($location == null) { + $uri = self::VOLUME_FEED_URI; + } else if ($location instanceof Zend_Gdata_Query) { + $uri = $location->getQueryUrl(); + } else { + $uri = $location; + } + return parent::getFeed($uri, 'Zend_Gdata_Books_VolumeFeed'); + } + + /** + * Retrieves a specific volume entry. + * + * @param string|null $volumeId The volumeId of interest. + * @param Zend_Gdata_Query|string|null $location (optional) The URL to + * query or a Zend_Gdata_Query object from which a URL can be + * determined. + * @return Zend_Gdata_Books_VolumeEntry The feed of volumes found at the + * specified URL. + */ + public function getVolumeEntry($volumeId = null, $location = null) + { + if ($volumeId !== null) { + $uri = self::VOLUME_FEED_URI . "/" . $volumeId; + } else if ($location instanceof Zend_Gdata_Query) { + $uri = $location->getQueryUrl(); + } else { + $uri = $location; + } + return parent::getEntry($uri, 'Zend_Gdata_Books_VolumeEntry'); + } + + /** + * Retrieves a feed of volumes, by default the User library feed. + * + * @param Zend_Gdata_Query|string|null $location (optional) The URL to + * query. + * @return Zend_Gdata_Books_VolumeFeed The feed of volumes found at the + * specified URL. + */ + public function getUserLibraryFeed($location = null) + { + if ($location == null) { + $uri = self::MY_LIBRARY_FEED_URI; + } else { + $uri = $location; + } + return parent::getFeed($uri, 'Zend_Gdata_Books_VolumeFeed'); + } + + /** + * Retrieves a feed of volumes, by default the User annotation feed + * + * @param Zend_Gdata_Query|string|null $location (optional) The URL to + * query. + * @return Zend_Gdata_Books_VolumeFeed The feed of volumes found at the + * specified URL. + */ + public function getUserAnnotationFeed($location = null) + { + if ($location == null) { + $uri = self::MY_ANNOTATION_FEED_URI; + } else { + $uri = $location; + } + return parent::getFeed($uri, 'Zend_Gdata_Books_VolumeFeed'); + } + + /** + * Insert a Volume / Annotation + * + * @param Zend_Gdata_Books_VolumeEntry $entry + * @param Zend_Gdata_Query|string|null $location (optional) The URL to + * query + * @return Zend_Gdata_Books_VolumeEntry The inserted volume entry. + */ + public function insertVolume($entry, $location = null) + { + if ($location == null) { + $uri = self::MY_LIBRARY_FEED_URI; + } else { + $uri = $location; + } + return parent::insertEntry( + $entry, $uri, 'Zend_Gdata_Books_VolumeEntry'); + } + + /** + * Delete a Volume + * + * @param Zend_Gdata_Books_VolumeEntry $entry + * @return void + */ + public function deleteVolume($entry) + { + $entry->delete(); + } + +} diff --git a/Zend/Gdata/Books/CollectionEntry.php b/Zend/Gdata/Books/CollectionEntry.php new file mode 100644 index 00000000..39625b6d --- /dev/null +++ b/Zend/Gdata/Books/CollectionEntry.php @@ -0,0 +1,56 @@ +registerAllNamespaces(Zend_Gdata_Books::$namespaces); + parent::__construct($element); + } + + +} + diff --git a/Zend/Gdata/Books/CollectionFeed.php b/Zend/Gdata/Books/CollectionFeed.php new file mode 100644 index 00000000..04f7e0b7 --- /dev/null +++ b/Zend/Gdata/Books/CollectionFeed.php @@ -0,0 +1,62 @@ +registerAllNamespaces(Zend_Gdata_Books::$namespaces); + parent::__construct($element); + } + + /** + * The classname for individual feed elements. + * + * @var string + */ + protected $_entryClassName = 'Zend_Gdata_Books_CollectionEntry'; + +} + diff --git a/Zend/Gdata/Books/Extension/AnnotationLink.php b/Zend/Gdata/Books/Extension/AnnotationLink.php new file mode 100644 index 00000000..590fbcd1 --- /dev/null +++ b/Zend/Gdata/Books/Extension/AnnotationLink.php @@ -0,0 +1,63 @@ +registerAllNamespaces(Zend_Gdata_Books::$namespaces); + parent::__construct($href, $rel, $type, $hrefLang, $title, $length); + } + +} + diff --git a/Zend/Gdata/Books/Extension/BooksCategory.php b/Zend/Gdata/Books/Extension/BooksCategory.php new file mode 100644 index 00000000..52d8ea35 --- /dev/null +++ b/Zend/Gdata/Books/Extension/BooksCategory.php @@ -0,0 +1,59 @@ +registerAllNamespaces(Zend_Gdata_Books::$namespaces); + parent::__construct($term, $scheme, $label); + } + +} diff --git a/Zend/Gdata/Books/Extension/BooksLink.php b/Zend/Gdata/Books/Extension/BooksLink.php new file mode 100644 index 00000000..1336cf6a --- /dev/null +++ b/Zend/Gdata/Books/Extension/BooksLink.php @@ -0,0 +1,61 @@ +registerAllNamespaces(Zend_Gdata_Books::$namespaces); + parent::__construct($href, $rel, $type, $hrefLang, $title, $length); + } + + +} + diff --git a/Zend/Gdata/Books/Extension/Embeddability.php b/Zend/Gdata/Books/Extension/Embeddability.php new file mode 100644 index 00000000..af15b947 --- /dev/null +++ b/Zend/Gdata/Books/Extension/Embeddability.php @@ -0,0 +1,122 @@ +registerAllNamespaces(Zend_Gdata_Books::$namespaces); + parent::__construct(); + $this->_value = $value; + } + + /** + * Retrieves DOMElement which corresponds to this element and all + * child properties. This is used to build this object back into a DOM + * and eventually XML text for sending to the server upon updates, or + * for application storage/persistance. + * + * @param DOMDocument $doc The DOMDocument used to construct DOMElements + * @return DOMElement The DOMElement representing this element and all + * child properties. + */ + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc); + if ($this->_value !== null) { + $element->setAttribute('value', $this->_value); + } + return $element; + } + + /** + * Extracts XML attributes from the DOM and converts them to the + * appropriate object members. + * + * @param DOMNode $attribute The DOMNode attribute to be handled. + */ + protected function takeAttributeFromDOM($attribute) + { + switch ($attribute->localName) { + case 'value': + $this->_value = $attribute->nodeValue; + break; + default: + parent::takeAttributeFromDOM($attribute); + } + } + + /** + * Returns the programmatic value that describes the embeddability of a + * volume in Google Book Search + * + * @return string|null The value + */ + public function getValue() + { + return $this->_value; + } + + /** + * Sets the programmatic value that describes the embeddability of a + * volume in Google Book Search + * + * @param string|null $value Programmatic value that describes the + * embeddability of a volume in Google Book Search + * @return Zend_Gdata_Books_Extension_Embeddability Provides a fluent + * interface + */ + public function setValue($value) + { + $this->_value = $value; + return $this; + } + +} + diff --git a/Zend/Gdata/Books/Extension/InfoLink.php b/Zend/Gdata/Books/Extension/InfoLink.php new file mode 100644 index 00000000..8fc9827d --- /dev/null +++ b/Zend/Gdata/Books/Extension/InfoLink.php @@ -0,0 +1,59 @@ +registerAllNamespaces(Zend_Gdata_Books::$namespaces); + parent::__construct($href, $rel, $type, $hrefLang, $title, $length); + } + +} diff --git a/Zend/Gdata/Books/Extension/PreviewLink.php b/Zend/Gdata/Books/Extension/PreviewLink.php new file mode 100644 index 00000000..5362b4c9 --- /dev/null +++ b/Zend/Gdata/Books/Extension/PreviewLink.php @@ -0,0 +1,60 @@ +registerAllNamespaces(Zend_Gdata_Books::$namespaces); + parent::__construct($href, $rel, $type, $hrefLang, $title, $length); + } + +} diff --git a/Zend/Gdata/Books/Extension/Review.php b/Zend/Gdata/Books/Extension/Review.php new file mode 100644 index 00000000..ffa76eb2 --- /dev/null +++ b/Zend/Gdata/Books/Extension/Review.php @@ -0,0 +1,152 @@ +registerAllNamespaces(Zend_Gdata_Books::$namespaces); + parent::__construct(); + $this->_lang = $lang; + $this->_type = $type; + $this->_text = $value; + } + + /** + * Retrieves DOMElement which corresponds to this element and all + * child properties. This is used to build this object back into a DOM + * and eventually XML text for sending to the server upon updates, or + * for application storage/persistance. + * + * @param DOMDocument $doc The DOMDocument used to construct DOMElements + * @return DOMElement The DOMElement representing this element and all + * child properties. + */ + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc); + if ($this->_lang !== null) { + $element->setAttribute('lang', $this->_lang); + } + if ($this->_type !== null) { + $element->setAttribute('type', $this->_type); + } + return $element; + } + + /** + * Extracts XML attributes from the DOM and converts them to the + * appropriate object members. + * + * @param DOMNode $attribute The DOMNode attribute to be handled. + */ + protected function takeAttributeFromDOM($attribute) + { + switch ($attribute->localName) { + case 'lang': + $this->_lang = $attribute->nodeValue; + break; + case 'type': + $this->_type = $attribute->nodeValue; + break; + default: + parent::takeAttributeFromDOM($attribute); + } + } + + /** + * Returns the language of link title + * + * @return string The lang + */ + public function getLang() + { + return $this->_lang; + } + + /** + * Returns the type of text construct (typically 'text', 'html' or 'xhtml') + * + * @return string The type + */ + public function getType() + { + return $this->_type; + } + + /** + * Sets the language of link title + * + * @param string $lang language of link title + * @return Zend_Gdata_Books_Extension_Review Provides a fluent interface + */ + public function setLang($lang) + { + $this->_lang = $lang; + return $this; + } + + /** + * Sets the type of text construct (typically 'text', 'html' or 'xhtml') + * + * @param string $type type of text construct (typically 'text', 'html' or 'xhtml') + * @return Zend_Gdata_Books_Extension_Review Provides a fluent interface + */ + public function setType($type) + { + $this->_type = $type; + return $this; + } + + +} + diff --git a/Zend/Gdata/Books/Extension/ThumbnailLink.php b/Zend/Gdata/Books/Extension/ThumbnailLink.php new file mode 100644 index 00000000..8aae3317 --- /dev/null +++ b/Zend/Gdata/Books/Extension/ThumbnailLink.php @@ -0,0 +1,60 @@ +registerAllNamespaces(Zend_Gdata_Books::$namespaces); + parent::__construct($href, $rel, $type, $hrefLang, $title, $length); + } + +} diff --git a/Zend/Gdata/Books/Extension/Viewability.php b/Zend/Gdata/Books/Extension/Viewability.php new file mode 100644 index 00000000..bba7900a --- /dev/null +++ b/Zend/Gdata/Books/Extension/Viewability.php @@ -0,0 +1,123 @@ +registerAllNamespaces(Zend_Gdata_Books::$namespaces); + parent::__construct(); + $this->_value = $value; + } + + /** + * Retrieves DOMElement which corresponds to this element and all + * child properties. This is used to build this object back into a DOM + * and eventually XML text for sending to the server upon updates, or + * for application storage/persistance. + * + * @param DOMDocument $doc The DOMDocument used to construct DOMElements + * @return DOMElement The DOMElement representing this element and all + * child properties. + */ + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc); + if ($this->_value !== null) { + $element->setAttribute('value', $this->_value); + } + return $element; + } + + /** + * Extracts XML attributes from the DOM and converts them to the + * appropriate object members. + * + * @param DOMNode $attribute The DOMNode attribute to be handled. + */ + protected function takeAttributeFromDOM($attribute) + { + switch ($attribute->localName) { + case 'value': + $this->_value = $attribute->nodeValue; + break; + default: + parent::takeAttributeFromDOM($attribute); + } + } + + /** + * Returns the programmatic value that describes the viewability of a volume + * in Google Book Search + * + * @return string The value + */ + public function getValue() + { + return $this->_value; + } + + /** + * Sets the programmatic value that describes the viewability of a volume in + * Google Book Search + * + * @param string $value programmatic value that describes the viewability + * of a volume in Googl eBook Search + * @return Zend_Gdata_Books_Extension_Viewability Provides a fluent + * interface + */ + public function setValue($value) + { + $this->_value = $value; + return $this; + } + + +} + diff --git a/Zend/Gdata/Books/VolumeEntry.php b/Zend/Gdata/Books/VolumeEntry.php new file mode 100644 index 00000000..67481fea --- /dev/null +++ b/Zend/Gdata/Books/VolumeEntry.php @@ -0,0 +1,687 @@ +registerAllNamespaces(Zend_Gdata_Books::$namespaces); + parent::__construct($element); + } + + /** + * Retrieves DOMElement which corresponds to this element and all + * child properties. This is used to build this object back into a DOM + * and eventually XML text for sending to the server upon updates, or + * for application storage/persistance. + * + * @param DOMDocument $doc The DOMDocument used to construct DOMElements + * @return DOMElement The DOMElement representing this element and all + * child properties. + */ + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc); + if ($this->_creators !== null) { + foreach ($this->_creators as $creators) { + $element->appendChild($creators->getDOM( + $element->ownerDocument)); + } + } + if ($this->_dates !== null) { + foreach ($this->_dates as $dates) { + $element->appendChild($dates->getDOM($element->ownerDocument)); + } + } + if ($this->_descriptions !== null) { + foreach ($this->_descriptions as $descriptions) { + $element->appendChild($descriptions->getDOM( + $element->ownerDocument)); + } + } + if ($this->_formats !== null) { + foreach ($this->_formats as $formats) { + $element->appendChild($formats->getDOM( + $element->ownerDocument)); + } + } + if ($this->_identifiers !== null) { + foreach ($this->_identifiers as $identifiers) { + $element->appendChild($identifiers->getDOM( + $element->ownerDocument)); + } + } + if ($this->_languages !== null) { + foreach ($this->_languages as $languages) { + $element->appendChild($languages->getDOM( + $element->ownerDocument)); + } + } + if ($this->_publishers !== null) { + foreach ($this->_publishers as $publishers) { + $element->appendChild($publishers->getDOM( + $element->ownerDocument)); + } + } + if ($this->_subjects !== null) { + foreach ($this->_subjects as $subjects) { + $element->appendChild($subjects->getDOM( + $element->ownerDocument)); + } + } + if ($this->_titles !== null) { + foreach ($this->_titles as $titles) { + $element->appendChild($titles->getDOM($element->ownerDocument)); + } + } + if ($this->_comments !== null) { + $element->appendChild($this->_comments->getDOM( + $element->ownerDocument)); + } + if ($this->_embeddability !== null) { + $element->appendChild($this->_embeddability->getDOM( + $element->ownerDocument)); + } + if ($this->_rating !== null) { + $element->appendChild($this->_rating->getDOM( + $element->ownerDocument)); + } + if ($this->_review !== null) { + $element->appendChild($this->_review->getDOM( + $element->ownerDocument)); + } + if ($this->_viewability !== null) { + $element->appendChild($this->_viewability->getDOM( + $element->ownerDocument)); + } + return $element; + } + + /** + * Creates individual objects of the appropriate type and stores + * them in this object based upon DOM data. + * + * @param DOMNode $child The DOMNode to process. + */ + protected function takeChildFromDOM($child) + { + $absoluteNodeName = $child->namespaceURI . ':' . $child->localName; + switch ($absoluteNodeName) { + case $this->lookupNamespace('dc') . ':' . 'creator': + $creators = new Zend_Gdata_DublinCore_Extension_Creator(); + $creators->transferFromDOM($child); + $this->_creators[] = $creators; + break; + case $this->lookupNamespace('dc') . ':' . 'date': + $dates = new Zend_Gdata_DublinCore_Extension_Date(); + $dates->transferFromDOM($child); + $this->_dates[] = $dates; + break; + case $this->lookupNamespace('dc') . ':' . 'description': + $descriptions = new Zend_Gdata_DublinCore_Extension_Description(); + $descriptions->transferFromDOM($child); + $this->_descriptions[] = $descriptions; + break; + case $this->lookupNamespace('dc') . ':' . 'format': + $formats = new Zend_Gdata_DublinCore_Extension_Format(); + $formats->transferFromDOM($child); + $this->_formats[] = $formats; + break; + case $this->lookupNamespace('dc') . ':' . 'identifier': + $identifiers = new Zend_Gdata_DublinCore_Extension_Identifier(); + $identifiers->transferFromDOM($child); + $this->_identifiers[] = $identifiers; + break; + case $this->lookupNamespace('dc') . ':' . 'language': + $languages = new Zend_Gdata_DublinCore_Extension_Language(); + $languages->transferFromDOM($child); + $this->_languages[] = $languages; + break; + case $this->lookupNamespace('dc') . ':' . 'publisher': + $publishers = new Zend_Gdata_DublinCore_Extension_Publisher(); + $publishers->transferFromDOM($child); + $this->_publishers[] = $publishers; + break; + case $this->lookupNamespace('dc') . ':' . 'subject': + $subjects = new Zend_Gdata_DublinCore_Extension_Subject(); + $subjects->transferFromDOM($child); + $this->_subjects[] = $subjects; + break; + case $this->lookupNamespace('dc') . ':' . 'title': + $titles = new Zend_Gdata_DublinCore_Extension_Title(); + $titles->transferFromDOM($child); + $this->_titles[] = $titles; + break; + case $this->lookupNamespace('gd') . ':' . 'comments': + $comments = new Zend_Gdata_Extension_Comments(); + $comments->transferFromDOM($child); + $this->_comments = $comments; + break; + case $this->lookupNamespace('gbs') . ':' . 'embeddability': + $embeddability = new Zend_Gdata_Books_Extension_Embeddability(); + $embeddability->transferFromDOM($child); + $this->_embeddability = $embeddability; + break; + case $this->lookupNamespace('gd') . ':' . 'rating': + $rating = new Zend_Gdata_Extension_Rating(); + $rating->transferFromDOM($child); + $this->_rating = $rating; + break; + case $this->lookupNamespace('gbs') . ':' . 'review': + $review = new Zend_Gdata_Books_Extension_Review(); + $review->transferFromDOM($child); + $this->_review = $review; + break; + case $this->lookupNamespace('gbs') . ':' . 'viewability': + $viewability = new Zend_Gdata_Books_Extension_Viewability(); + $viewability->transferFromDOM($child); + $this->_viewability = $viewability; + break; + default: + parent::takeChildFromDOM($child); + break; + } + } + + /** + * Returns the Comments class + * + * @return Zend_Gdata_Extension_Comments|null The comments + */ + public function getComments() + { + return $this->_comments; + } + + /** + * Returns the creators + * + * @return array The creators + */ + public function getCreators() + { + return $this->_creators; + } + + /** + * Returns the dates + * + * @return array The dates + */ + public function getDates() + { + return $this->_dates; + } + + /** + * Returns the descriptions + * + * @return array The descriptions + */ + public function getDescriptions() + { + return $this->_descriptions; + } + + /** + * Returns the embeddability + * + * @return Zend_Gdata_Books_Extension_Embeddability|null The embeddability + */ + public function getEmbeddability() + { + return $this->_embeddability; + } + + /** + * Returns the formats + * + * @return array The formats + */ + public function getFormats() + { + return $this->_formats; + } + + /** + * Returns the identifiers + * + * @return array The identifiers + */ + public function getIdentifiers() + { + return $this->_identifiers; + } + + /** + * Returns the languages + * + * @return array The languages + */ + public function getLanguages() + { + return $this->_languages; + } + + /** + * Returns the publishers + * + * @return array The publishers + */ + public function getPublishers() + { + return $this->_publishers; + } + + /** + * Returns the rating + * + * @return Zend_Gdata_Extension_Rating|null The rating + */ + public function getRating() + { + return $this->_rating; + } + + /** + * Returns the review + * + * @return Zend_Gdata_Books_Extension_Review|null The review + */ + public function getReview() + { + return $this->_review; + } + + /** + * Returns the subjects + * + * @return array The subjects + */ + public function getSubjects() + { + return $this->_subjects; + } + + /** + * Returns the titles + * + * @return array The titles + */ + public function getTitles() + { + return $this->_titles; + } + + /** + * Returns the viewability + * + * @return Zend_Gdata_Books_Extension_Viewability|null The viewability + */ + public function getViewability() + { + return $this->_viewability; + } + + /** + * Sets the Comments class + * + * @param Zend_Gdata_Extension_Comments|null $comments Comments class + * @return Zend_Gdata_Books_VolumeEntry Provides a fluent interface + */ + public function setComments($comments) + { + $this->_comments = $comments; + return $this; + } + + /** + * Sets the creators + * + * @param array $creators Creators|null + * @return Zend_Gdata_Books_VolumeEntry Provides a fluent interface + */ + public function setCreators($creators) + { + $this->_creators = $creators; + return $this; + } + + /** + * Sets the dates + * + * @param array $dates dates + * @return Zend_Gdata_Books_VolumeEntry Provides a fluent interface + */ + public function setDates($dates) + { + $this->_dates = $dates; + return $this; + } + + /** + * Sets the descriptions + * + * @param array $descriptions descriptions + * @return Zend_Gdata_Books_VolumeEntry Provides a fluent interface + */ + public function setDescriptions($descriptions) + { + $this->_descriptions = $descriptions; + return $this; + } + + /** + * Sets the embeddability + * + * @param Zend_Gdata_Books_Extension_Embeddability|null $embeddability + * embeddability + * @return Zend_Gdata_Books_VolumeEntry Provides a fluent interface + */ + public function setEmbeddability($embeddability) + { + $this->_embeddability = $embeddability; + return $this; + } + + /** + * Sets the formats + * + * @param array $formats formats + * @return Zend_Gdata_Books_VolumeEntry Provides a fluent interface + */ + public function setFormats($formats) + { + $this->_formats = $formats; + return $this; + } + + /** + * Sets the identifiers + * + * @param array $identifiers identifiers + * @return Zend_Gdata_Books_VolumeEntry Provides a fluent interface + */ + public function setIdentifiers($identifiers) + { + $this->_identifiers = $identifiers; + return $this; + } + + /** + * Sets the languages + * + * @param array $languages languages + * @return Zend_Gdata_Books_VolumeEntry Provides a fluent interface + */ + public function setLanguages($languages) + { + $this->_languages = $languages; + return $this; + } + + /** + * Sets the publishers + * + * @param array $publishers publishers + * @return Zend_Gdata_Books_VolumeEntry Provides a fluent interface + */ + public function setPublishers($publishers) + { + $this->_publishers = $publishers; + return $this; + } + + /** + * Sets the rating + * + * @param Zend_Gdata_Extension_Rating|null $rating rating + * @return Zend_Gdata_Books_VolumeEntry Provides a fluent interface + */ + public function setRating($rating) + { + $this->_rating = $rating; + return $this; + } + + /** + * Sets the review + * + * @param Zend_Gdata_Books_Extension_Review|null $review review + * @return Zend_Gdata_Books_VolumeEntry Provides a fluent interface + */ + public function setReview($review) + { + $this->_review = $review; + return $this; + } + + /** + * Sets the subjects + * + * @param array $subjects subjects + * @return Zend_Gdata_Books_VolumeEntry Provides a fluent interface + */ + public function setSubjects($subjects) + { + $this->_subjects = $subjects; + return $this; + } + + /** + * Sets the titles + * + * @param array $titles titles + * @return Zend_Gdata_Books_VolumeEntry Provides a fluent interface + */ + public function setTitles($titles) + { + $this->_titles = $titles; + return $this; + } + + /** + * Sets the viewability + * + * @param Zend_Gdata_Books_Extension_Viewability|null $viewability + * viewability + * @return Zend_Gdata_Books_VolumeEntry Provides a fluent interface + */ + public function setViewability($viewability) + { + $this->_viewability = $viewability; + return $this; + } + + + /** + * Gets the volume ID based upon the atom:id value + * + * @return string The volume ID + * @throws Zend_Gdata_App_Exception + */ + public function getVolumeId() + { + $fullId = $this->getId()->getText(); + $position = strrpos($fullId, '/'); + if ($position === false) { + require_once 'Zend/Gdata/App/Exception.php'; + throw new Zend_Gdata_App_Exception('Slash not found in atom:id'); + } else { + return substr($fullId, strrpos($fullId,'/') + 1); + } + } + + /** + * Gets the thumbnail link + * + * @return Zend_Gdata_App_Extension_link|null The thumbnail link + */ + public function getThumbnailLink() + { + return $this->getLink(self::THUMBNAIL_LINK_REL); + } + + /** + * Gets the preview link + * + * @return Zend_Gdata_App_Extension_Link|null The preview link + */ + public function getPreviewLink() + { + return $this->getLink(self::PREVIEW_LINK_REL); + } + + /** + * Gets the info link + * + * @return Zend_Gdata_App_Extension_Link|null The info link + */ + public function getInfoLink() + { + return $this->getLink(self::INFO_LINK_REL); + } + + /** + * Gets the annotations link + * + * @return Zend_Gdata_App_Extension_Link|null The annotations link + */ + public function getAnnotationLink() + { + return $this->getLink(self::ANNOTATION_LINK_REL); + } + +} diff --git a/Zend/Gdata/Books/VolumeFeed.php b/Zend/Gdata/Books/VolumeFeed.php new file mode 100644 index 00000000..130ed3a0 --- /dev/null +++ b/Zend/Gdata/Books/VolumeFeed.php @@ -0,0 +1,62 @@ +registerAllNamespaces(Zend_Gdata_Books::$namespaces); + parent::__construct($element); + } + + /** + * The classname for individual feed elements. + * + * @var string + */ + protected $_entryClassName = 'Zend_Gdata_Books_VolumeEntry'; + +} + diff --git a/Zend/Gdata/Books/VolumeQuery.php b/Zend/Gdata/Books/VolumeQuery.php new file mode 100644 index 00000000..8d284747 --- /dev/null +++ b/Zend/Gdata/Books/VolumeQuery.php @@ -0,0 +1,112 @@ +_params['min-viewability'] = 'full'; + break; + case 'partial_view': + $this->_params['min-viewability'] = 'partial'; + break; + case null: + unset($this->_params['min-viewability']); + break; + } + return $this; + } + + /** + * Minimum viewability of volumes to include in search results + * + * @return string|null min-viewability + */ + public function getMinViewability() + { + if (array_key_exists('min-viewability', $this->_params)) { + return $this->_params['min-viewability']; + } else { + return null; + } + } + + /** + * Returns the generated full query URL + * + * @return string The URL + */ + public function getQueryUrl() + { + if (isset($this->_url)) { + $url = $this->_url; + } else { + $url = Zend_Gdata_Books::VOLUME_FEED_URI; + } + if ($this->getCategory() !== null) { + $url .= '/-/' . $this->getCategory(); + } + $url = $url . $this->getQueryString(); + return $url; + } + +} diff --git a/Zend/Gdata/Calendar.php b/Zend/Gdata/Calendar.php new file mode 100644 index 00000000..2d368bb1 --- /dev/null +++ b/Zend/Gdata/Calendar.php @@ -0,0 +1,169 @@ +registerPackage('Zend_Gdata_Calendar'); + $this->registerPackage('Zend_Gdata_Calendar_Extension'); + parent::__construct($client, $applicationId); + $this->_httpClient->setParameterPost('service', self::AUTH_SERVICE_NAME); + } + + /** + * Retreive feed object + * + * @param mixed $location The location for the feed, as a URL or Query + * @return Zend_Gdata_Calendar_EventFeed + */ + public function getCalendarEventFeed($location = null) + { + if ($location == null) { + $uri = self::CALENDAR_EVENT_FEED_URI; + } else if ($location instanceof Zend_Gdata_Query) { + $uri = $location->getQueryUrl(); + } else { + $uri = $location; + } + return parent::getFeed($uri, 'Zend_Gdata_Calendar_EventFeed'); + } + + /** + * Retreive entry object + * + * @return Zend_Gdata_Calendar_EventEntry + */ + public function getCalendarEventEntry($location = null) + { + if ($location == null) { + require_once 'Zend/Gdata/App/InvalidArgumentException.php'; + throw new Zend_Gdata_App_InvalidArgumentException( + 'Location must not be null'); + } else if ($location instanceof Zend_Gdata_Query) { + $uri = $location->getQueryUrl(); + } else { + $uri = $location; + } + return parent::getEntry($uri, 'Zend_Gdata_Calendar_EventEntry'); + } + + + /** + * Retrieve feed object + * + * @return Zend_Gdata_Calendar_ListFeed + */ + public function getCalendarListFeed() + { + $uri = self::CALENDAR_FEED_URI . '/default'; + return parent::getFeed($uri,'Zend_Gdata_Calendar_ListFeed'); + } + + /** + * Retreive entryobject + * + * @return Zend_Gdata_Calendar_ListEntry + */ + public function getCalendarListEntry($location = null) + { + if ($location == null) { + require_once 'Zend/Gdata/App/InvalidArgumentException.php'; + throw new Zend_Gdata_App_InvalidArgumentException( + 'Location must not be null'); + } else if ($location instanceof Zend_Gdata_Query) { + $uri = $location->getQueryUrl(); + } else { + $uri = $location; + } + return parent::getEntry($uri,'Zend_Gdata_Calendar_ListEntry'); + } + + public function insertEvent($event, $uri=null) + { + if ($uri == null) { + $uri = $this->_defaultPostUri; + } + $newEvent = $this->insertEntry($event, $uri, 'Zend_Gdata_Calendar_EventEntry'); + return $newEvent; + } + +} diff --git a/Zend/Gdata/Calendar/EventEntry.php b/Zend/Gdata/Calendar/EventEntry.php new file mode 100644 index 00000000..7cc13845 --- /dev/null +++ b/Zend/Gdata/Calendar/EventEntry.php @@ -0,0 +1,164 @@ +registerAllNamespaces(Zend_Gdata_Calendar::$namespaces); + parent::__construct($element); + } + + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc, $majorVersion, $minorVersion); + if ($this->_sendEventNotifications != null) { + $element->appendChild($this->_sendEventNotifications->getDOM($element->ownerDocument)); + } + if ($this->_timezone != null) { + $element->appendChild($this->_timezone->getDOM($element->ownerDocument)); + } + if ($this->_quickadd != null) { + $element->appendChild($this->_quickadd->getDOM($element->ownerDocument)); + } + return $element; + } + + protected function takeChildFromDOM($child) + { + $absoluteNodeName = $child->namespaceURI . ':' . $child->localName; + + switch ($absoluteNodeName) { + case $this->lookupNamespace('gCal') . ':' . 'sendEventNotifications'; + $sendEventNotifications = new Zend_Gdata_Calendar_Extension_SendEventNotifications(); + $sendEventNotifications->transferFromDOM($child); + $this->_sendEventNotifications = $sendEventNotifications; + break; + case $this->lookupNamespace('gCal') . ':' . 'timezone'; + $timezone = new Zend_Gdata_Calendar_Extension_Timezone(); + $timezone->transferFromDOM($child); + $this->_timezone = $timezone; + break; + case $this->lookupNamespace('atom') . ':' . 'link'; + $link = new Zend_Gdata_Calendar_Extension_Link(); + $link->transferFromDOM($child); + $this->_link[] = $link; + break; + case $this->lookupNamespace('gCal') . ':' . 'quickadd'; + $quickadd = new Zend_Gdata_Calendar_Extension_QuickAdd(); + $quickadd->transferFromDOM($child); + $this->_quickadd = $quickadd; + break; + default: + parent::takeChildFromDOM($child); + break; + } + } + + public function getSendEventNotifications() + { + return $this->_sendEventNotifications; + } + + public function setSendEventNotifications($value) + { + $this->_sendEventNotifications = $value; + return $this; + } + + public function getTimezone() + { + return $this->_timezone; + } + + /** + * @param Zend_Gdata_Calendar_Extension_Timezone $value + * @return Zend_Gdata_Extension_EventEntry Provides a fluent interface + */ + public function setTimezone($value) + { + $this->_timezone = $value; + return $this; + } + + public function getQuickAdd() + { + return $this->_quickadd; + } + + /** + * @param Zend_Gdata_Calendar_Extension_QuickAdd $value + * @return Zend_Gdata_Extension_ListEntry Provides a fluent interface + */ + public function setQuickAdd($value) + { + $this->_quickadd = $value; + return $this; + } + +} diff --git a/Zend/Gdata/Calendar/EventFeed.php b/Zend/Gdata/Calendar/EventFeed.php new file mode 100644 index 00000000..f6618ea6 --- /dev/null +++ b/Zend/Gdata/Calendar/EventFeed.php @@ -0,0 +1,106 @@ +registerAllNamespaces(Zend_Gdata_Calendar::$namespaces); + parent::__construct($element); + } + + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc, $majorVersion, $minorVersion); + if ($this->_timezone != null) { + $element->appendChild($this->_timezone->getDOM($element->ownerDocument)); + } + + return $element; + } + + protected function takeChildFromDOM($child) + { + $absoluteNodeName = $child->namespaceURI . ':' . $child->localName; + + switch ($absoluteNodeName) { + case $this->lookupNamespace('gCal') . ':' . 'timezone'; + $timezone = new Zend_Gdata_Calendar_Extension_Timezone(); + $timezone->transferFromDOM($child); + $this->_timezone = $timezone; + break; + + default: + parent::takeChildFromDOM($child); + break; + } + } + + public function getTimezone() + { + return $this->_timezone; + } + + public function setTimezone($value) + { + $this->_timezone = $value; + return $this; + } + +} diff --git a/Zend/Gdata/Calendar/EventQuery.php b/Zend/Gdata/Calendar/EventQuery.php new file mode 100644 index 00000000..95e89e62 --- /dev/null +++ b/Zend/Gdata/Calendar/EventQuery.php @@ -0,0 +1,491 @@ +_comments = $value; + return $this; + } + + /** + * @see $_event + * @param string $value + * @return Zend_Gdata_Calendar_EventQuery Provides a fluent interface + */ + public function setEvent($value) + { + $this->_event = $value; + return $this; + } + + /** + * @see $_projection + * @param string $value + * @return Zend_Gdata_Calendar_EventQuery Provides a fluent interface + */ + public function setProjection($value) + { + $this->_projection = $value; + return $this; + } + + /** + * @see $_user + * @param string $value + * @return Zend_Gdata_Calendar_EventQuery Provides a fluent interface + */ + public function setUser($value) + { + $this->_user = $value; + return $this; + } + + /** + * @see $_visibility + * @param bool $value + * @return Zend_Gdata_Calendar_EventQuery Provides a fluent interface + */ + public function setVisibility($value) + { + $this->_visibility = $value; + return $this; + } + + /** + * @see $_comments; + * @return string comments + */ + public function getComments() + { + return $this->_comments; + } + + /** + * @see $_event; + * @return string event + */ + public function getEvent() + { + return $this->_event; + } + + /** + * @see $_projection + * @return string projection + */ + public function getProjection() + { + return $this->_projection; + } + + /** + * @see $_user + * @return string user + */ + public function getUser() + { + return $this->_user; + } + + /** + * @see $_visibility + * @return string visibility + */ + public function getVisibility() + { + return $this->_visibility; + } + + /** + * @param int $value + * @return Zend_Gdata_Calendar_EventQuery Provides a fluent interface + */ + public function setStartMax($value) + { + if ($value != null) { + $this->_params['start-max'] = Zend_Gdata_App_Util::formatTimestamp($value); + } else { + unset($this->_params['start-max']); + } + return $this; + } + + /** + * @param int $value + * @return Zend_Gdata_Calendar_EventQuery Provides a fluent interface + */ + public function setStartMin($value) + { + if ($value != null) { + $this->_params['start-min'] = Zend_Gdata_App_Util::formatTimestamp($value); + } else { + unset($this->_params['start-min']); + } + return $this; + } + + /** + * @param string $value + * @return Zend_Gdata_Calendar_EventQuery Provides a fluent interface + */ + public function setOrderBy($value) + { + if ($value != null) { + $this->_params['orderby'] = $value; + } else { + unset($this->_params['orderby']); + } + return $this; + } + + /** + * @return int start-max + */ + public function getStartMax() + { + if (array_key_exists('start-max', $this->_params)) { + return $this->_params['start-max']; + } else { + return null; + } + } + + /** + * @return int start-min + */ + public function getStartMin() + { + if (array_key_exists('start-min', $this->_params)) { + return $this->_params['start-min']; + } else { + return null; + } + } + + /** + * @return string orderby + */ + public function getOrderBy() + { + if (array_key_exists('orderby', $this->_params)) { + return $this->_params['orderby']; + } else { + return null; + } + } + + /** + * @return string sortorder + */ + public function getSortOrder() + { + if (array_key_exists('sortorder', $this->_params)) { + return $this->_params['sortorder']; + } else { + return null; + } + } + + /** + * @return string sortorder + */ + public function setSortOrder($value) + { + if ($value != null) { + $this->_params['sortorder'] = $value; + } else { + unset($this->_params['sortorder']); + } + return $this; + } + + /** + * @return string recurrence-expansion-start + */ + public function getRecurrenceExpansionStart() + { + if (array_key_exists('recurrence-expansion-start', $this->_params)) { + return $this->_params['recurrence-expansion-start']; + } else { + return null; + } + } + + /** + * @return string recurrence-expansion-start + */ + public function setRecurrenceExpansionStart($value) + { + if ($value != null) { + $this->_params['recurrence-expansion-start'] = Zend_Gdata_App_Util::formatTimestamp($value); + } else { + unset($this->_params['recurrence-expansion-start']); + } + return $this; + } + + + /** + * @return string recurrence-expansion-end + */ + public function getRecurrenceExpansionEnd() + { + if (array_key_exists('recurrence-expansion-end', $this->_params)) { + return $this->_params['recurrence-expansion-end']; + } else { + return null; + } + } + + /** + * @return string recurrence-expansion-end + */ + public function setRecurrenceExpansionEnd($value) + { + if ($value != null) { + $this->_params['recurrence-expansion-end'] = Zend_Gdata_App_Util::formatTimestamp($value); + } else { + unset($this->_params['recurrence-expansion-end']); + } + return $this; + } + + /** + * @param string $value Also accepts bools. + * @return Zend_Gdata_Calendar_EventQuery Provides a fluent interface + */ + public function getSingleEvents() + { + if (array_key_exists('singleevents', $this->_params)) { + $value = $this->_params['singleevents']; + switch ($value) { + case 'true': + return true; + break; + case 'false': + return false; + break; + default: + require_once 'Zend/Gdata/App/Exception.php'; + throw new Zend_Gdata_App_Exception( + 'Invalid query param value for futureevents: ' . + $value . ' It must be a boolean.'); + } + } else { + return null; + } + } + + /** + * @param string $value Also accepts bools. If using a string, must be either "true" or "false". + * @return Zend_Gdata_Calendar_EventQuery Provides a fluent interface + */ + public function setSingleEvents($value) + { + if ($value !== null) { + if (is_bool($value)) { + $this->_params['singleevents'] = ($value?'true':'false'); + } elseif ($value == 'true' | $value == 'false') { + $this->_params['singleevents'] = $value; + } else { + require_once 'Zend/Gdata/App/Exception.php'; + throw new Zend_Gdata_App_Exception( + 'Invalid query param value for futureevents: ' . + $value . ' It must be a boolean.'); + } + } else { + unset($this->_params['singleevents']); + } + return $this; + } + + /** + * @return string futureevents + */ + public function getFutureEvents() + { + if (array_key_exists('futureevents', $this->_params)) { + $value = $this->_params['futureevents']; + switch ($value) { + case 'true': + return true; + break; + case 'false': + return false; + break; + default: + require_once 'Zend/Gdata/App/Exception.php'; + throw new Zend_Gdata_App_Exception( + 'Invalid query param value for futureevents: ' . + $value . ' It must be a boolean.'); + } + } else { + return null; + } + } + + /** + * @param string $value Also accepts bools. If using a string, must be either "true" or "false" or + * an exception will be thrown on retrieval. + * @return Zend_Gdata_Calendar_EventQuery Provides a fluent interface + */ + public function setFutureEvents($value) + { + if ($value !== null) { + if (is_bool($value)) { + $this->_params['futureevents'] = ($value?'true':'false'); + } elseif ($value == 'true' | $value == 'false') { + $this->_params['futureevents'] = $value; + } else { + require_once 'Zend/Gdata/App/Exception.php'; + throw new Zend_Gdata_App_Exception( + 'Invalid query param value for futureevents: ' . + $value . ' It must be a boolean.'); + } + } else { + unset($this->_params['futureevents']); + } + return $this; + } + + /** + * @return string url + */ + public function getQueryUrl() + { + if (isset($this->_url)) { + $uri = $this->_url; + } else { + $uri = $this->_defaultFeedUri; + } + if ($this->getUser() != null) { + $uri .= '/' . $this->getUser(); + } + if ($this->getVisibility() != null) { + $uri .= '/' . $this->getVisibility(); + } + if ($this->getProjection() != null) { + $uri .= '/' . $this->getProjection(); + } + if ($this->getEvent() != null) { + $uri .= '/' . $this->getEvent(); + if ($this->getComments() != null) { + $uri .= '/comments/' . $this->getComments(); + } + } + $uri .= $this->getQueryString(); + return $uri; + } + +} diff --git a/Zend/Gdata/Calendar/Extension/AccessLevel.php b/Zend/Gdata/Calendar/Extension/AccessLevel.php new file mode 100644 index 00000000..40fbb4b5 --- /dev/null +++ b/Zend/Gdata/Calendar/Extension/AccessLevel.php @@ -0,0 +1,125 @@ +registerAllNamespaces(Zend_Gdata_Calendar::$namespaces); + parent::__construct(); + $this->_value = $value; + } + + /** + * Retrieves a DOMElement which corresponds to this element and all + * child properties. This is used to build an entry back into a DOM + * and eventually XML text for sending to the server upon updates, or + * for application storage/persistence. + * + * @param DOMDocument $doc The DOMDocument used to construct DOMElements + * @return DOMElement The DOMElement representing this element and all + * child properties. + */ + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc, $majorVersion, $minorVersion); + if ($this->_value != null) { + $element->setAttribute('value', $this->_value); + } + return $element; + } + + /** + * Given a DOMNode representing an attribute, tries to map the data into + * instance members. If no mapping is defined, the name and value are + * stored in an array. + * + * @param DOMNode $attribute The DOMNode attribute needed to be handled + */ + protected function takeAttributeFromDOM($attribute) + { + switch ($attribute->localName) { + case 'value': + $this->_value = $attribute->nodeValue; + break; + default: + parent::takeAttributeFromDOM($attribute); + } + } + + /** + * Get the value for this element's value attribute. + * + * @return string The attribute being modified. + */ + public function getValue() + { + return $this->_value; + } + + + /** + * Set the value for this element's value attribute. + * + * @param string $value The desired value for this attribute. + * @return Zend_Gdata_Calendar_Extension_Selected The element being modified. + */ + public function setValue($value) + { + $this->_value = $value; + return $this; + } + + /** + * Magic toString method allows using this directly via echo + * Works best in PHP >= 4.2.0 + */ + public function __toString() + { + return $this->getValue(); + } + +} diff --git a/Zend/Gdata/Calendar/Extension/Color.php b/Zend/Gdata/Calendar/Extension/Color.php new file mode 100644 index 00000000..a209168b --- /dev/null +++ b/Zend/Gdata/Calendar/Extension/Color.php @@ -0,0 +1,125 @@ +registerAllNamespaces(Zend_Gdata_Calendar::$namespaces); + parent::__construct(); + $this->_value = $value; + } + + /** + * Retrieves a DOMElement which corresponds to this element and all + * child properties. This is used to build an entry back into a DOM + * and eventually XML text for sending to the server upon updates, or + * for application storage/persistence. + * + * @param DOMDocument $doc The DOMDocument used to construct DOMElements + * @return DOMElement The DOMElement representing this element and all + * child properties. + */ + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc, $majorVersion, $minorVersion); + if ($this->_value != null) { + $element->setAttribute('value', $this->_value); + } + return $element; + } + + /** + * Given a DOMNode representing an attribute, tries to map the data into + * instance members. If no mapping is defined, the name and value are + * stored in an array. + * + * @param DOMNode $attribute The DOMNode attribute needed to be handled + */ + protected function takeAttributeFromDOM($attribute) + { + switch ($attribute->localName) { + case 'value': + $this->_value = $attribute->nodeValue; + break; + default: + parent::takeAttributeFromDOM($attribute); + } + } + + /** + * Get the value for this element's value attribute. + * + * @return string The value associated with this attribute. + */ + public function getValue() + { + return $this->_value; + } + + /** + * Set the value for this element's value attribute. + * + * @param string $value The desired value for this attribute. + * @return Zend_Gdata_Calendar_Extension_Color The element being modified. + */ + public function setValue($value) + { + $this->_value = $value; + return $this; + } + + /** + * Magic toString method allows using this directly via echo + * Works best in PHP >= 4.2.0 + */ + public function __toString() + { + return $this->_value; + } + +} diff --git a/Zend/Gdata/Calendar/Extension/Hidden.php b/Zend/Gdata/Calendar/Extension/Hidden.php new file mode 100644 index 00000000..1d757f5b --- /dev/null +++ b/Zend/Gdata/Calendar/Extension/Hidden.php @@ -0,0 +1,134 @@ +registerAllNamespaces(Zend_Gdata_Calendar::$namespaces); + parent::__construct(); + $this->_value = $value; + } + + /** + * Retrieves a DOMElement which corresponds to this element and all + * child properties. This is used to build an entry back into a DOM + * and eventually XML text for sending to the server upon updates, or + * for application storage/persistence. + * + * @param DOMDocument $doc The DOMDocument used to construct DOMElements + * @return DOMElement The DOMElement representing this element and all + * child properties. + */ + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc, $majorVersion, $minorVersion); + if ($this->_value !== null) { + $element->setAttribute('value', ($this->_value ? "true" : "false")); + } + return $element; + } + + /** + * Given a DOMNode representing an attribute, tries to map the data into + * instance members. If no mapping is defined, the name and value are + * stored in an array. + * + * @param DOMNode $attribute The DOMNode attribute needed to be handled + */ + protected function takeAttributeFromDOM($attribute) + { + switch ($attribute->localName) { + case 'value': + if ($attribute->nodeValue == "true") { + $this->_value = true; + } + else if ($attribute->nodeValue == "false") { + $this->_value = false; + } + else { + require_once 'Zend/Gdata/App/InvalidArgumentException.php'; + throw new Zend_Gdata_App_InvalidArgumentException("Expected 'true' or 'false' for gCal:selected#value."); + } + break; + default: + parent::takeAttributeFromDOM($attribute); + } + } + + /** + * Get the value for this element's value attribute. + * + * @return string The requested attribute. + */ + public function getValue() + { + return $this->_value; + } + + /** + * Set the value for this element's value attribute. + * + * @param bool $value The desired value for this attribute. + * @return Zend_Gdata_Calendar_Extension_Hidden The element being modified. + */ + public function setValue($value) + { + $this->_value = $value; + return $this; + } + + /** + * Magic toString method allows using this directly via echo + * Works best in PHP >= 4.2.0 + */ + public function __toString() + { + return $this->_value; + } + +} + diff --git a/Zend/Gdata/Calendar/Extension/Link.php b/Zend/Gdata/Calendar/Extension/Link.php new file mode 100644 index 00000000..3c0cbdfa --- /dev/null +++ b/Zend/Gdata/Calendar/Extension/Link.php @@ -0,0 +1,125 @@ +registerAllNamespaces(Zend_Gdata_Calendar::$namespaces); + parent::__construct($href, $rel, $type, $hrefLang, $title, $length); + $this->_webContent = $webContent; + } + + /** + * Retrieves a DOMElement which corresponds to this element and all + * child properties. This is used to build an entry back into a DOM + * and eventually XML text for sending to the server upon updates, or + * for application storage/persistence. + * + * @param DOMDocument $doc The DOMDocument used to construct DOMElements + * @return DOMElement The DOMElement representing this element and all + * child properties. + */ + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc, $majorVersion, $minorVersion); + if ($this->_webContent != null) { + $element->appendChild($this->_webContent->getDOM($element->ownerDocument)); + } + return $element; + } + + /** + * Creates individual Entry objects of the appropriate type and + * stores them as members of this entry based upon DOM data. + * + * @param DOMNode $child The DOMNode to process + */ + protected function takeChildFromDOM($child) + { + $absoluteNodeName = $child->namespaceURI . ':' . $child->localName; + switch ($absoluteNodeName) { + case $this->lookupNamespace('gCal') . ':' . 'webContent': + $webContent = new Zend_Gdata_Calendar_Extension_WebContent(); + $webContent->transferFromDOM($child); + $this->_webContent = $webContent; + break; + default: + parent::takeChildFromDOM($child); + break; + } + } + + /** + * Get the value for this element's WebContent attribute. + * + * @return Zend_Gdata_Calendar_Extension_Webcontent The WebContent value + */ + public function getWebContent() + { + return $this->_webContent; + } + + /** + * Set the value for this element's WebContent attribute. + * + * @param Zend_Gdata_Calendar_Extension_WebContent $value The desired value for this attribute. + * @return Zend_Calendar_Extension_Link The element being modified. Provides a fluent interface. + */ + public function setWebContent($value) + { + $this->_webContent = $value; + return $this; + } + + +} + diff --git a/Zend/Gdata/Calendar/Extension/QuickAdd.php b/Zend/Gdata/Calendar/Extension/QuickAdd.php new file mode 100644 index 00000000..dbea50c8 --- /dev/null +++ b/Zend/Gdata/Calendar/Extension/QuickAdd.php @@ -0,0 +1,132 @@ +registerAllNamespaces(Zend_Gdata_Calendar::$namespaces); + parent::__construct(); + $this->_value = $value; + } + + /** + * Retrieves a DOMElement which corresponds to this element and all + * child properties. This is used to build an entry back into a DOM + * and eventually XML text for sending to the server upon updates, or + * for application storage/persistence. + * + * @param DOMDocument $doc The DOMDocument used to construct DOMElements + * @return DOMElement The DOMElement representing this element and all + * child properties. + */ + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc, $majorVersion, $minorVersion); + if ($this->_value !== null) { + $element->setAttribute('value', ($this->_value ? "true" : "false")); + } + return $element; + } + + /** + * Given a DOMNode representing an attribute, tries to map the data into + * instance members. If no mapping is defined, the name and value are + * stored in an array. + * + * @param DOMNode $attribute The DOMNode attribute needed to be handled + */ + protected function takeAttributeFromDOM($attribute) + { + switch ($attribute->localName) { + case 'value': + if ($attribute->nodeValue == "true") { + $this->_value = true; + } + else if ($attribute->nodeValue == "false") { + $this->_value = false; + } + else { + throw new Zend_Gdata_App_InvalidArgumentException("Expected 'true' or 'false' for gCal:selected#value."); + } + break; + default: + parent::takeAttributeFromDOM($attribute); + } + } + + /** + * Get the value for this element's value attribute. + * + * @return string The value associated with this attribute. + */ + public function getValue() + { + return $this->_value; + } + + /** + * Set the value for this element's value attribute. + * + * @param string $value The desired value for this attribute. + * @return Zend_Gdata_Calendar_Extension_QuickAdd The element being modified. + */ + public function setValue($value) + { + $this->_value = $value; + return $this; + } + + /** + * Magic toString method allows using this directly via echo + * Works best in PHP >= 4.2.0 + */ + public function __toString() + { + return $this->getValue(); + } + +} diff --git a/Zend/Gdata/Calendar/Extension/Selected.php b/Zend/Gdata/Calendar/Extension/Selected.php new file mode 100644 index 00000000..b6447f0e --- /dev/null +++ b/Zend/Gdata/Calendar/Extension/Selected.php @@ -0,0 +1,133 @@ +registerAllNamespaces(Zend_Gdata_Calendar::$namespaces); + parent::__construct(); + $this->_value = $value; + } + + /** + * Retrieves a DOMElement which corresponds to this element and all + * child properties. This is used to build an entry back into a DOM + * and eventually XML text for sending to the server upon updates, or + * for application storage/persistence. + * + * @param DOMDocument $doc The DOMDocument used to construct DOMElements + * @return DOMElement The DOMElement representing this element and all + * child properties. + */ + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc, $majorVersion, $minorVersion); + if ($this->_value !== null) { + $element->setAttribute('value', ($this->_value ? "true" : "false")); + } + return $element; + } + + /** + * Given a DOMNode representing an attribute, tries to map the data into + * instance members. If no mapping is defined, the name and value are + * stored in an array. + * + * @param DOMNode $attribute The DOMNode attribute needed to be handled + */ + protected function takeAttributeFromDOM($attribute) + { + switch ($attribute->localName) { + case 'value': + if ($attribute->nodeValue == "true") { + $this->_value = true; + } + else if ($attribute->nodeValue == "false") { + $this->_value = false; + } + else { + require_once 'Zend/Gdata/App/InvalidArgumentException.php'; + throw new Zend_Gdata_App_InvalidArgumentException("Expected 'true' or 'false' for gCal:selected#value."); + } + break; + default: + parent::takeAttributeFromDOM($attribute); + } + } + + /** + * Get the value for this element's value attribute. + * + * @return bool The value associated with this attribute. + */ + public function getValue() + { + return $this->_value; + } + + /** + * Set the value for this element's value attribute. + * + * @param bool $value The desired value for this attribute. + * @return Zend_Gdata_Calendar_Extension_Selected The element being modified. + */ + public function setValue($value) + { + $this->_value = $value; + return $this; + } + + /** + * Magic toString method allows using this directly via echo + * Works best in PHP >= 4.2.0 + */ + public function __toString() + { + return $this->_value; + } + +} diff --git a/Zend/Gdata/Calendar/Extension/SendEventNotifications.php b/Zend/Gdata/Calendar/Extension/SendEventNotifications.php new file mode 100644 index 00000000..55bc36df --- /dev/null +++ b/Zend/Gdata/Calendar/Extension/SendEventNotifications.php @@ -0,0 +1,132 @@ +registerAllNamespaces(Zend_Gdata_Calendar::$namespaces); + parent::__construct(); + $this->_value = $value; + } + + /** + * Retrieves a DOMElement which corresponds to this element and all + * child properties. This is used to build an entry back into a DOM + * and eventually XML text for sending to the server upon updates, or + * for application storage/persistence. + * + * @param DOMDocument $doc The DOMDocument used to construct DOMElements + * @return DOMElement The DOMElement representing this element and all + * child properties. + */ + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc, $majorVersion, $minorVersion); + if ($this->_value !== null) { + $element->setAttribute('value', ($this->_value ? "true" : "false")); + } + return $element; + } + + /** + * Given a DOMNode representing an attribute, tries to map the data into + * instance members. If no mapping is defined, the name and value are + * stored in an array. + * + * @param DOMNode $attribute The DOMNode attribute needed to be handled + */ + protected function takeAttributeFromDOM($attribute) + { + switch ($attribute->localName) { + case 'value': + if ($attribute->nodeValue == "true") { + $this->_value = true; + } + else if ($attribute->nodeValue == "false") { + $this->_value = false; + } + else { + throw new Zend_Gdata_App_InvalidArgumentException("Expected 'true' or 'false' for gCal:selected#value."); + } + break; + default: + parent::takeAttributeFromDOM($attribute); + } + } + + /** + * Get the value for this element's Value attribute. + * + * @return string The requested attribute. + */ + public function getValue() + { + return $this->_value; + } + + /** + * Set the value for this element's Value attribute. + * + * @param string $value The desired value for this attribute. + * @return Zend_Gdata_Extension_SendEventNotifications The element being modified. + */ + public function setValue($value) + { + $this->_value = $value; + return $this; + } + + /** + * Magic toString method allows using this directly via echo + * Works best in PHP >= 4.2.0 + */ + public function __toString() + { + return $this->getValue(); + } + +} + diff --git a/Zend/Gdata/Calendar/Extension/Timezone.php b/Zend/Gdata/Calendar/Extension/Timezone.php new file mode 100644 index 00000000..bbd0f148 --- /dev/null +++ b/Zend/Gdata/Calendar/Extension/Timezone.php @@ -0,0 +1,124 @@ +registerAllNamespaces(Zend_Gdata_Calendar::$namespaces); + parent::__construct(); + $this->_value = $value; + } + + /** + * Retrieves a DOMElement which corresponds to this element and all + * child properties. This is used to build an entry back into a DOM + * and eventually XML text for sending to the server upon updates, or + * for application storage/persistence. + * + * @param DOMDocument $doc The DOMDocument used to construct DOMElements + * @return DOMElement The DOMElement representing this element and all + * child properties. + */ + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc, $majorVersion, $minorVersion); + if ($this->_value != null) { + $element->setAttribute('value', $this->_value); + } + return $element; + } + + /** + * Given a DOMNode representing an attribute, tries to map the data into + * instance members. If no mapping is defined, the name and value are + * stored in an array. + * + * @param DOMNode $attribute The DOMNode attribute needed to be handled + */ + protected function takeAttributeFromDOM($attribute) + { + switch ($attribute->localName) { + case 'value': + $this->_value = $attribute->nodeValue; + break; + default: + parent::takeAttributeFromDOM($attribute); + } + } + + /** + * Get the value for this element's value attribute. + * + * @return string The value associated with this attribute. + */ + public function getValue() + { + return $this->_value; + } + + /** + * Set the value for this element's value attribute. + * + * @param string $value The desired value for this attribute. + * @return Zend_Gdata_Calendar_Extension_Timezone The element being modified. + */ + public function setValue($value) + { + $this->_value = $value; + return $this; + } + + /** + * Magic toString method allows using this directly via echo + * Works best in PHP >= 4.2.0 + */ + public function __toString() + { + return $this->getValue(); + } + +} diff --git a/Zend/Gdata/Calendar/Extension/WebContent.php b/Zend/Gdata/Calendar/Extension/WebContent.php new file mode 100644 index 00000000..e0a04829 --- /dev/null +++ b/Zend/Gdata/Calendar/Extension/WebContent.php @@ -0,0 +1,177 @@ +registerAllNamespaces(Zend_Gdata_Calendar::$namespaces); + parent::__construct(); + $this->_url = $url; + $this->_height = $height; + $this->_width = $width; + } + + /** + * Retrieves a DOMElement which corresponds to this element and all + * child properties. This is used to build an entry back into a DOM + * and eventually XML text for sending to the server upon updates, or + * for application storage/persistence. + * + * @param DOMDocument $doc The DOMDocument used to construct DOMElements + * @return DOMElement The DOMElement representing this element and all + * child properties. + */ + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc, $majorVersion, $minorVersion); + if ($this->url != null) { + $element->setAttribute('url', $this->_url); + } + if ($this->height != null) { + $element->setAttribute('height', $this->_height); + } + if ($this->width != null) { + $element->setAttribute('width', $this->_width); + } + return $element; + } + + /** + * Given a DOMNode representing an attribute, tries to map the data into + * instance members. If no mapping is defined, the name and value are + * stored in an array. + * + * @param DOMNode $attribute The DOMNode attribute needed to be handled + */ + protected function takeAttributeFromDOM($attribute) + { + switch ($attribute->localName) { + case 'url': + $this->_url = $attribute->nodeValue; + break; + case 'height': + $this->_height = $attribute->nodeValue; + break; + case 'width': + $this->_width = $attribute->nodeValue; + break; + default: + parent::takeAttributeFromDOM($attribute); + } + } + + /** + * Get the value for this element's URL attribute. + * + * @return string The desired value for this attribute. + */ + public function getURL() + { + return $this->_url; + } + + /** + * Set the value for this element's URL attribute. + * + * @param bool $value The desired value for this attribute. + * @return Zend_Gdata_Calendar_Extension_WebContent The element being modified. + */ + public function setURL($value) + { + $this->_url = $value; + return $this; + } + + /** + * Get the value for this element's height attribute. + * + * @return int The desired value for this attribute. + */ + public function getHeight() + { + return $this->_height; + } + + /** + * Set the value for this element's height attribute. + * + * @param int $value The desired value for this attribute. + * @return Zend_Gdata_Calendar_Extension_WebContent The element being modified. + */ + public function setHeight($value) + { + $this->_height = $value; + return $this; + } + + /** + * Get the value for this element's height attribute. + * + * @return int The desired value for this attribute. + */ + public function getWidth() + { + return $this->_width; + } + + /** + * Set the value for this element's height attribute. + * + * @param int $value The desired value for this attribute. + * @return Zend_Gdata_Calendar_Extension_WebContent The element being modified. + */ + public function setWidth($value) + { + $this->_width = $value; + return $this; + } + +} diff --git a/Zend/Gdata/Calendar/ListEntry.php b/Zend/Gdata/Calendar/ListEntry.php new file mode 100644 index 00000000..af7447bc --- /dev/null +++ b/Zend/Gdata/Calendar/ListEntry.php @@ -0,0 +1,246 @@ +registerAllNamespaces(Zend_Gdata_Calendar::$namespaces); + parent::__construct($element); + } + + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc, $majorVersion, $minorVersion); + if ($this->_accessLevel != null) { + $element->appendChild($this->_accessLevel->getDOM($element->ownerDocument)); + } + if ($this->_color != null) { + $element->appendChild($this->_color->getDOM($element->ownerDocument)); + } + if ($this->_hidden != null) { + $element->appendChild($this->_hidden->getDOM($element->ownerDocument)); + } + if ($this->_selected != null) { + $element->appendChild($this->_selected->getDOM($element->ownerDocument)); + } + if ($this->_timezone != null) { + $element->appendChild($this->_timezone->getDOM($element->ownerDocument)); + } + if ($this->_where != null) { + foreach ($this->_where as $where) { + $element->appendChild($where->getDOM($element->ownerDocument)); + } + } + return $element; + } + + protected function takeChildFromDOM($child) + { + $absoluteNodeName = $child->namespaceURI . ':' . $child->localName; + switch ($absoluteNodeName) { + case $this->lookupNamespace('gCal') . ':' . 'accesslevel'; + $accessLevel = new Zend_Gdata_Calendar_Extension_AccessLevel(); + $accessLevel->transferFromDOM($child); + $this->_accessLevel = $accessLevel; + break; + case $this->lookupNamespace('gCal') . ':' . 'color'; + $color = new Zend_Gdata_Calendar_Extension_Color(); + $color->transferFromDOM($child); + $this->_color = $color; + break; + case $this->lookupNamespace('gCal') . ':' . 'hidden'; + $hidden = new Zend_Gdata_Calendar_Extension_Hidden(); + $hidden->transferFromDOM($child); + $this->_hidden = $hidden; + break; + case $this->lookupNamespace('gCal') . ':' . 'selected'; + $selected = new Zend_Gdata_Calendar_Extension_Selected(); + $selected->transferFromDOM($child); + $this->_selected = $selected; + break; + case $this->lookupNamespace('gCal') . ':' . 'timezone'; + $timezone = new Zend_Gdata_Calendar_Extension_Timezone(); + $timezone->transferFromDOM($child); + $this->_timezone = $timezone; + break; + case $this->lookupNamespace('gd') . ':' . 'where'; + $where = new Zend_Gdata_Extension_Where(); + $where->transferFromDOM($child); + $this->_where[] = $where; + break; + default: + parent::takeChildFromDOM($child); + break; + } + } + + public function getAccessLevel() + { + return $this->_accessLevel; + } + + /** + * @param Zend_Gdata_Calendar_Extension_AccessLevel $value + * @return Zend_Gdata_Extension_ListEntry Provides a fluent interface + */ + public function setAccessLevel($value) + { + $this->_accessLevel = $value; + return $this; + } + public function getColor() + { + return $this->_color; + } + + /** + * @param Zend_Gdata_Calendar_Extension_Color $value + * @return Zend_Gdata_Extension_ListEntry Provides a fluent interface + */ + public function setColor($value) + { + $this->_color = $value; + return $this; + } + + public function getHidden() + { + return $this->_hidden; + } + + /** + * @param Zend_Gdata_Calendar_Extension_Hidden $value + * @return Zend_Gdata_Extension_ListEntry Provides a fluent interface + */ + public function setHidden($value) + { + $this->_hidden = $value; + return $this; + } + + public function getSelected() + { + return $this->_selected; + } + + /** + * @param Zend_Gdata_Calendar_Extension_Selected $value + * @return Zend_Gdata_Extension_ListEntry Provides a fluent interface + */ + public function setSelected($value) + { + $this->_selected = $value; + return $this; + } + + public function getTimezone() + { + return $this->_timezone; + } + + /** + * @param Zend_Gdata_Calendar_Extension_Timezone $value + * @return Zend_Gdata_Extension_ListEntry Provides a fluent interface + */ + public function setTimezone($value) + { + $this->_timezone = $value; + return $this; + } + + public function getWhere() + { + return $this->_where; + } + + /** + * @param Zend_Gdata_Extension_Where $value + * @return Zend_Gdata_Extension_ListEntry Provides a fluent interface + */ + public function setWhere($value) + { + $this->_where = $value; + return $this; + } + +} diff --git a/Zend/Gdata/Calendar/ListFeed.php b/Zend/Gdata/Calendar/ListFeed.php new file mode 100644 index 00000000..5d44c394 --- /dev/null +++ b/Zend/Gdata/Calendar/ListFeed.php @@ -0,0 +1,106 @@ +registerAllNamespaces(Zend_Gdata_Calendar::$namespaces); + parent::__construct($element); + } + + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc, $majorVersion, $minorVersion); + if ($this->_timezone != null) { + $element->appendChild($this->_timezone->getDOM($element->ownerDocument)); + } + return $element; + } + + protected function takeChildFromDOM($child) + { + $absoluteNodeName = $child->namespaceURI . ':' . $child->localName; + switch ($absoluteNodeName) { + case $this->lookupNamespace('gCal') . ':' . 'timezone'; + $timezone = new Zend_Gdata_Calendar_Extension_Timezone(); + $timezone->transferFromDOM($child); + $this->_timezone = $timezone; + break; + default: + parent::takeChildFromDOM($child); + break; + } + } + + public function getTimezone() + { + return $this->_timezone; + } + + /** + * @param Zend_Gdata_Calendar_Extension_Timezone $value + * @return Zend_Gdata_Extension_ListEntry Provides a fluent interface + */ + public function setTimezone($value) + { + $this->_timezone = $value; + return $this; + } + +} diff --git a/Zend/Gdata/ClientLogin.php b/Zend/Gdata/ClientLogin.php new file mode 100644 index 00000000..b38937fb --- /dev/null +++ b/Zend/Gdata/ClientLogin.php @@ -0,0 +1,182 @@ +setUri($loginUri); + $useragent = $source . ' Zend_Framework_Gdata/' . Zend_Version::VERSION; + $client->setConfig(array( + 'maxredirects' => 0, + 'strictredirects' => true, + 'useragent' => $useragent + ) + ); + $client->setParameterPost('accountType', $accountType); + $client->setParameterPost('Email', (string) $email); + $client->setParameterPost('Passwd', (string) $password); + $client->setParameterPost('service', (string) $service); + $client->setParameterPost('source', (string) $source); + if ($loginToken || $loginCaptcha) { + if($loginToken && $loginCaptcha) { + $client->setParameterPost('logintoken', (string) $loginToken); + $client->setParameterPost('logincaptcha', + (string) $loginCaptcha); + } + else { + require_once 'Zend/Gdata/App/AuthException.php'; + throw new Zend_Gdata_App_AuthException( + 'Please provide both a token ID and a user\'s response ' . + 'to the CAPTCHA challenge.'); + } + } + + // Send the authentication request + // For some reason Google's server causes an SSL error. We use the + // output buffer to supress an error from being shown. Ugly - but works! + ob_start(); + try { + $response = $client->request('POST'); + } catch (Zend_Http_Client_Exception $e) { + require_once 'Zend/Gdata/App/HttpException.php'; + throw new Zend_Gdata_App_HttpException($e->getMessage(), $e); + } + ob_end_clean(); + + // Parse Google's response + $goog_resp = array(); + foreach (explode("\n", $response->getBody()) as $l) { + $l = chop($l); + if ($l) { + list($key, $val) = explode('=', chop($l), 2); + $goog_resp[$key] = $val; + } + } + + if ($response->getStatus() == 200) { + $client->setClientLoginToken($goog_resp['Auth']); + $useragent = $source . ' Zend_Framework_Gdata/' . Zend_Version::VERSION; + $client->setConfig(array( + 'strictredirects' => true, + 'useragent' => $useragent + ) + ); + return $client; + + } elseif ($response->getStatus() == 403) { + // Check if the server asked for a CAPTCHA + if (array_key_exists('Error', $goog_resp) && + $goog_resp['Error'] == 'CaptchaRequired') { + require_once 'Zend/Gdata/App/CaptchaRequiredException.php'; + throw new Zend_Gdata_App_CaptchaRequiredException( + $goog_resp['CaptchaToken'], $goog_resp['CaptchaUrl']); + } + else { + require_once 'Zend/Gdata/App/AuthException.php'; + throw new Zend_Gdata_App_AuthException('Authentication with Google failed. Reason: ' . + (isset($goog_resp['Error']) ? $goog_resp['Error'] : 'Unspecified.')); + } + } + } + +} + diff --git a/Zend/Gdata/Docs.php b/Zend/Gdata/Docs.php new file mode 100644 index 00000000..98eae82f --- /dev/null +++ b/Zend/Gdata/Docs.php @@ -0,0 +1,319 @@ + 'text/csv', + 'DOC' => 'application/msword', + 'DOCX' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', + 'HTML' =>'text/html', + 'HTM' => 'text/html', + 'JPG' => 'image/jpeg', + 'ODS' => 'application/vnd.oasis.opendocument.spreadsheet', + 'ODT' => 'application/vnd.oasis.opendocument.text', + 'PDF' => 'application/pdf', + 'PNG' => 'image/png', + 'PPT' => 'application/vnd.ms-powerpoint', + 'PPS' => 'application/vnd.ms-powerpoint', + 'RTF' => 'application/rtf', + 'SXW' => 'application/vnd.sun.xml.writer', + 'TAB' => 'text/tab-separated-values', + 'TXT' => 'text/plain', + 'TEXT' => 'text/plain', + 'TSV' => 'text/tab-separated-values', + 'XLS' => 'application/vnd.ms-excel', + 'XLSX' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'); + + /** + * Create Gdata_Docs object + * + * @param Zend_Http_Client $client (optional) The HTTP client to use when + * when communicating with the Google servers. + * @param string $applicationId The identity of the app in the form of Company-AppName-Version + */ + public function __construct($client = null, $applicationName) + { + $this->registerPackage('Zend_Gdata_Docs'); + $this->registerPackage('Zend_Gdata_Docs_Extension_WritersCanInvite'); + parent::__construct($client, $applicationName); + $this->_httpClient->setParameterPost('service', self::AUTH_SERVICE_NAME); + $this->setMajorProtocolVersion(self::DEFAULT_MAJOR_PROTOCOL_VERSION); + } + + /** + * Looks up the mime type based on the file name extension. For example, + * calling this method with 'csv' would return + * 'text/comma-separated-values'. The Mime type is sent as a header in + * the upload HTTP POST request. + * + * @param string $fileExtension + * @return string The mime type to be sent to the server to tell it how the + * multipart mime data should be interpreted. + */ + public static function lookupMimeType($fileExtension) { + return self::$SUPPORTED_FILETYPES[strtoupper($fileExtension)]; + } + + /** + * Retrieve feed object containing entries for the user's documents. + * + * @param mixed $location The location for the feed, as a URL or Query + * @return Zend_Gdata_Docs_DocumentListFeed + */ + public function getDocumentListFeed($location = null) + { + if ($location === null) { + $uri = self::DOCUMENTS_LIST_FEED_URI; + } else if ($location instanceof Zend_Gdata_Query) { + $uri = $location->getQueryUrl(); + } else { + $uri = $location; + } + return parent::getFeed($uri, 'Zend_Gdata_Docs_DocumentListFeed'); + } + + /** + * Retrieve entry object representing a single document. + * + * @param mixed $location The location for the entry, as a URL or Query + * @return Zend_Gdata_Docs_DocumentListEntry + */ + public function getDocumentListEntry($location = null) + { + if ($location === null) { + require_once 'Zend/Gdata/App/InvalidArgumentException.php'; + throw new Zend_Gdata_App_InvalidArgumentException( + 'Location must not be null'); + } else if ($location instanceof Zend_Gdata_Query) { + $uri = $location->getQueryUrl(); + } else { + $uri = $location; + } + return parent::getEntry($uri, 'Zend_Gdata_Docs_DocumentListEntry'); + } + + /** + * Retrieve a document entry representing a single document. + * + * @param string $resourceId The document resource id. Examples: + * document:dcmg89gw_62hfjj8m, spreadsheet:pKq0CzjiF3YmGd0AIlHKqeg, + * pdf:asdf89hfjjddfg + * @return Zend_Gdata_Docs_DocumentListEntry + */ + public function getResource($resourceId) { + $uri = 'http://docs.google.com/feeds/documents/private/full/' . $resourceId; + return $this->getDocumentListEntry($uri); + } + + /** + * Retrieve entry object representing a single document. + * + * This method builds the URL where this item is stored using the type + * and the id of the document. + * @param string $docId The URL key for the document. Examples: + * dcmg89gw_62hfjj8m, pKq0CzjiF3YmGd0AIlHKqeg + * @param string $docType The type of the document as used in the Google + * Document List URLs. Examples: document, spreadsheet, presentation + * @return Zend_Gdata_Docs_DocumentListEntry + * @deprecated Use getResource($resourceId) instead. + */ + public function getDoc($docId, $docType) { + $location = 'http://docs.google.com/feeds/documents/private/full/' . + $docType . '%3A' . $docId; + return $this->getDocumentListEntry($location); + } + + /** + * Retrieve entry object for the desired word processing document. + * + * @param string $id The URL id for the document. Example: + * dcmg89gw_62hfjj8m + * @deprecated Use getResource($resourceId) instead. + */ + public function getDocument($id) { + return $this->getDoc('document%3A' . $id); + } + + /** + * Retrieve entry object for the desired spreadsheet. + * + * @param string $id The URL id for the spreadsheet. Example: + * pKq0CzjiF3YmGd0AIlHKqeg + * @deprecated Use getResource($resourceId) instead. + */ + public function getSpreadsheet($id) { + return $this->getDoc('spreadsheet%3A' . $id); + } + + /** + * Retrieve entry object for the desired presentation. + * + * @param string $id The URL id for the presentation. Example: + * dcmg89gw_21gtrjcn + * @deprecated Use getResource($resourceId) instead. + */ + public function getPresentation($id) { + return $this->getDoc('presentation%3A' . $id); + } + + /** + * Upload a local file to create a new Google Document entry. + * + * @param string $fileLocation The full or relative path of the file to + * be uploaded. + * @param string $title The name that this document should have on the + * server. If set, the title is used as the slug header in the + * POST request. If no title is provided, the location of the + * file will be used as the slug header in the request. If no + * mimeType is provided, this method attempts to determine the + * mime type based on the slugHeader by looking for .doc, + * .csv, .txt, etc. at the end of the file name. + * Example value: 'test.doc'. + * @param string $mimeType Describes the type of data which is being sent + * to the server. This must be one of the accepted mime types + * which are enumerated in SUPPORTED_FILETYPES. + * @param string $uri (optional) The URL to which the upload should be + * made. + * Example: 'http://docs.google.com/feeds/default/private/full'. + * @return Zend_Gdata_Docs_DocumentListEntry The entry for the newly + * created Google Document. + */ + public function uploadFile($fileLocation, $title=null, $mimeType=null, + $uri=null) + { + // Set the URI to which the file will be uploaded. + if ($uri === null) { + $uri = $this->_defaultPostUri; + } + + // Create the media source which describes the file. + $fs = $this->newMediaFileSource($fileLocation); + if ($title !== null) { + $slugHeader = $title; + } else { + $slugHeader = $fileLocation; + } + + // Set the slug header to tell the Google Documents server what the + // title of the document should be and what the file extension was + // for the original file. + $fs->setSlug($slugHeader); + + // Set the mime type of the data. + if ($mimeType === null) { + $slugHeader = $fs->getSlug(); + $filenameParts = explode('.', $slugHeader); + $fileExtension = end($filenameParts); + $mimeType = self::lookupMimeType($fileExtension); + } + + // Set the mime type for the upload request. + $fs->setContentType($mimeType); + + // Send the data to the server. + return $this->insertDocument($fs, $uri); + } + + /** + * Inserts an entry to a given URI and returns the response as an Entry. + * + * @param mixed $data The Zend_Gdata_Docs_DocumentListEntry or media + * source to post. If it is a DocumentListEntry, the mediaSource + * should already have been set. If $data is a mediaSource, it + * should have the correct slug header and mime type. + * @param string $uri POST URI + * @param string $className (optional) The class of entry to be returned. + * The default is a 'Zend_Gdata_Docs_DocumentListEntry'. + * @return Zend_Gdata_Docs_DocumentListEntry The entry returned by the + * service after insertion. + */ + public function insertDocument($data, $uri, + $className='Zend_Gdata_Docs_DocumentListEntry') + { + return $this->insertEntry($data, $uri, $className); + } + + /** + * Return the supported mime types and file extensions. + * + * @return array + * @author Andreas Sandberg + */ + public static function getSupportedMimeTypes() { + return self::$SUPPORTED_FILETYPES; + } + +} diff --git a/Zend/Gdata/Docs/DocumentListEntry.php b/Zend/Gdata/Docs/DocumentListEntry.php new file mode 100644 index 00000000..3dc97d24 --- /dev/null +++ b/Zend/Gdata/Docs/DocumentListEntry.php @@ -0,0 +1,54 @@ +registerAllNamespaces(Zend_Gdata_Docs::$namespaces); + parent::__construct($element); + } + +} diff --git a/Zend/Gdata/Docs/DocumentListFeed.php b/Zend/Gdata/Docs/DocumentListFeed.php new file mode 100644 index 00000000..b1dbbf2b --- /dev/null +++ b/Zend/Gdata/Docs/DocumentListFeed.php @@ -0,0 +1,68 @@ +registerAllNamespaces(Zend_Gdata_Docs::$namespaces); + parent::__construct($element); + } + +} diff --git a/Zend/Gdata/Docs/Query.php b/Zend/Gdata/Docs/Query.php new file mode 100644 index 00000000..fb80f0fb --- /dev/null +++ b/Zend/Gdata/Docs/Query.php @@ -0,0 +1,228 @@ +_projection = $value; + return $this; + } + + /** + * Sets the visibility for this query. Common values for visibility + * include 'private'. + * + * @return Zend_Gdata_Docs_Query Provides a fluent interface + */ + public function setVisibility($value) + { + $this->_visibility = $value; + return $this; + } + + /** + * Gets the projection for this query. + * + * @return string projection + */ + public function getProjection() + { + return $this->_projection; + } + + /** + * Gets the visibility for this query. + * + * @return string visibility + */ + public function getVisibility() + { + return $this->_visibility; + } + + /** + * Sets the title attribute for this query. The title parameter is used + * to restrict the results to documents whose titles either contain or + * completely match the title. + * + * @param string $value + * @return Zend_Gdata_Docs_Query Provides a fluent interface + */ + public function setTitle($value) + { + if ($value !== null) { + $this->_params['title'] = $value; + } else { + unset($this->_params['title']); + } + return $this; + } + + /** + * Gets the title attribute for this query. + * + * @return string title + */ + public function getTitle() + { + if (array_key_exists('title', $this->_params)) { + return $this->_params['title']; + } else { + return null; + } + } + + /** + * Sets the title-exact attribute for this query. + * If title-exact is set to true, the title query parameter will be used + * in an exact match. Only documents with a title identical to the + * title parameter will be returned. + * + * @param boolean $value Use either true or false + * @return Zend_Gdata_Docs_Query Provides a fluent interface + */ + public function setTitleExact($value) + { + if ($value) { + $this->_params['title-exact'] = $value; + } else { + unset($this->_params['title-exact']); + } + return $this; + } + + /** + * Gets the title-exact attribute for this query. + * + * @return string title-exact + */ + public function getTitleExact() + { + if (array_key_exists('title-exact', $this->_params)) { + return $this->_params['title-exact']; + } else { + return false; + } + } + + /** + * Gets the full query URL for this query. + * + * @return string url + */ + public function getQueryUrl() + { + $uri = $this->_defaultFeedUri; + + if ($this->_visibility !== null) { + $uri .= '/' . $this->_visibility; + } else { + require_once 'Zend/Gdata/App/Exception.php'; + throw new Zend_Gdata_App_Exception( + 'A visibility must be provided for cell queries.'); + } + + if ($this->_projection !== null) { + $uri .= '/' . $this->_projection; + } else { + require_once 'Zend/Gdata/App/Exception.php'; + throw new Zend_Gdata_App_Exception( + 'A projection must be provided for cell queries.'); + } + + $uri .= $this->getQueryString(); + return $uri; + } + +} diff --git a/Zend/Gdata/DublinCore.php b/Zend/Gdata/DublinCore.php new file mode 100644 index 00000000..032786fd --- /dev/null +++ b/Zend/Gdata/DublinCore.php @@ -0,0 +1,65 @@ +registerPackage('Zend_Gdata_DublinCore'); + $this->registerPackage('Zend_Gdata_DublinCore_Extension'); + parent::__construct($client, $applicationId); + } + +} diff --git a/Zend/Gdata/DublinCore/Extension/Creator.php b/Zend/Gdata/DublinCore/Extension/Creator.php new file mode 100644 index 00000000..00492bcb --- /dev/null +++ b/Zend/Gdata/DublinCore/Extension/Creator.php @@ -0,0 +1,58 @@ +registerAllNamespaces(Zend_Gdata_DublinCore::$namespaces); + parent::__construct(); + $this->_text = $value; + } + +} diff --git a/Zend/Gdata/DublinCore/Extension/Date.php b/Zend/Gdata/DublinCore/Extension/Date.php new file mode 100644 index 00000000..ca9ffae2 --- /dev/null +++ b/Zend/Gdata/DublinCore/Extension/Date.php @@ -0,0 +1,60 @@ +registerAllNamespaces(Zend_Gdata_DublinCore::$namespaces); + parent::__construct(); + $this->_text = $value; + } + +} diff --git a/Zend/Gdata/DublinCore/Extension/Description.php b/Zend/Gdata/DublinCore/Extension/Description.php new file mode 100644 index 00000000..a538b2d0 --- /dev/null +++ b/Zend/Gdata/DublinCore/Extension/Description.php @@ -0,0 +1,58 @@ +registerAllNamespaces(Zend_Gdata_DublinCore::$namespaces); + parent::__construct(); + $this->_text = $value; + } + +} diff --git a/Zend/Gdata/DublinCore/Extension/Format.php b/Zend/Gdata/DublinCore/Extension/Format.php new file mode 100644 index 00000000..97aa51db --- /dev/null +++ b/Zend/Gdata/DublinCore/Extension/Format.php @@ -0,0 +1,58 @@ +registerAllNamespaces(Zend_Gdata_DublinCore::$namespaces); + parent::__construct(); + $this->_text = $value; + } + +} diff --git a/Zend/Gdata/DublinCore/Extension/Identifier.php b/Zend/Gdata/DublinCore/Extension/Identifier.php new file mode 100644 index 00000000..c1f9a22e --- /dev/null +++ b/Zend/Gdata/DublinCore/Extension/Identifier.php @@ -0,0 +1,58 @@ +registerAllNamespaces(Zend_Gdata_DublinCore::$namespaces); + parent::__construct(); + $this->_text = $value; + } + +} diff --git a/Zend/Gdata/DublinCore/Extension/Language.php b/Zend/Gdata/DublinCore/Extension/Language.php new file mode 100644 index 00000000..2f8e9b62 --- /dev/null +++ b/Zend/Gdata/DublinCore/Extension/Language.php @@ -0,0 +1,58 @@ +registerAllNamespaces(Zend_Gdata_DublinCore::$namespaces); + parent::__construct(); + $this->_text = $value; + } + +} diff --git a/Zend/Gdata/DublinCore/Extension/Publisher.php b/Zend/Gdata/DublinCore/Extension/Publisher.php new file mode 100644 index 00000000..d609ed0d --- /dev/null +++ b/Zend/Gdata/DublinCore/Extension/Publisher.php @@ -0,0 +1,58 @@ +registerAllNamespaces(Zend_Gdata_DublinCore::$namespaces); + parent::__construct(); + $this->_text = $value; + } + +} diff --git a/Zend/Gdata/DublinCore/Extension/Rights.php b/Zend/Gdata/DublinCore/Extension/Rights.php new file mode 100644 index 00000000..e8365dfc --- /dev/null +++ b/Zend/Gdata/DublinCore/Extension/Rights.php @@ -0,0 +1,58 @@ +registerAllNamespaces(Zend_Gdata_DublinCore::$namespaces); + parent::__construct(); + $this->_text = $value; + } + +} diff --git a/Zend/Gdata/DublinCore/Extension/Subject.php b/Zend/Gdata/DublinCore/Extension/Subject.php new file mode 100644 index 00000000..d7f63ece --- /dev/null +++ b/Zend/Gdata/DublinCore/Extension/Subject.php @@ -0,0 +1,58 @@ +registerAllNamespaces(Zend_Gdata_DublinCore::$namespaces); + parent::__construct(); + $this->_text = $value; + } + +} diff --git a/Zend/Gdata/DublinCore/Extension/Title.php b/Zend/Gdata/DublinCore/Extension/Title.php new file mode 100644 index 00000000..04f6833d --- /dev/null +++ b/Zend/Gdata/DublinCore/Extension/Title.php @@ -0,0 +1,58 @@ +registerAllNamespaces(Zend_Gdata_DublinCore::$namespaces); + parent::__construct(); + $this->_text = $value; + } + +} diff --git a/Zend/Gdata/Entry.php b/Zend/Gdata/Entry.php new file mode 100644 index 00000000..b29518b7 --- /dev/null +++ b/Zend/Gdata/Entry.php @@ -0,0 +1,132 @@ +registerAllNamespaces(Zend_Gdata::$namespaces); + parent::__construct($element); + } + + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc, $majorVersion, $minorVersion); + // ETags are special. We only support them in protocol >= 2.X. + // This will be duplicated by the HTTP ETag header. + if ($majorVersion >= 2) { + if ($this->_etag != null) { + $element->setAttributeNS($this->lookupNamespace('gd'), + 'gd:etag', + $this->_etag); + } + } + return $element; + } + + protected function takeChildFromDOM($child) + { + $absoluteNodeName = $child->namespaceURI . ':' . $child->localName; + switch ($absoluteNodeName) { + case $this->lookupNamespace('atom') . ':' . 'content': + $content = new Zend_Gdata_App_Extension_Content(); + $content->transferFromDOM($child); + $this->_content = $content; + break; + case $this->lookupNamespace('atom') . ':' . 'published': + $published = new Zend_Gdata_App_Extension_Published(); + $published->transferFromDOM($child); + $this->_published = $published; + break; + case $this->lookupNamespace('atom') . ':' . 'source': + $source = new Zend_Gdata_App_Extension_Source(); + $source->transferFromDOM($child); + $this->_source = $source; + break; + case $this->lookupNamespace('atom') . ':' . 'summary': + $summary = new Zend_Gdata_App_Extension_Summary(); + $summary->transferFromDOM($child); + $this->_summary = $summary; + break; + case $this->lookupNamespace('app') . ':' . 'control': + $control = new Zend_Gdata_App_Extension_Control(); + $control->transferFromDOM($child); + $this->_control = $control; + break; + default: + parent::takeChildFromDOM($child); + break; + } + } + + /** + * Given a DOMNode representing an attribute, tries to map the data into + * instance members. If no mapping is defined, the name and value are + * stored in an array. + * + * @param DOMNode $attribute The DOMNode attribute needed to be handled + */ + protected function takeAttributeFromDOM($attribute) + { + switch ($attribute->localName) { + case 'etag': + // ETags are special, since they can be conveyed by either the + // HTTP ETag header or as an XML attribute. + $etag = $attribute->nodeValue; + if ($this->_etag === null) { + $this->_etag = $etag; + } + elseif ($this->_etag != $etag) { + require_once('Zend/Gdata/App/IOException.php'); + throw new Zend_Gdata_App_IOException("ETag mismatch"); + } + break; + default: + parent::takeAttributeFromDOM($attribute); + break; + } + } + +} diff --git a/Zend/Gdata/Exif.php b/Zend/Gdata/Exif.php new file mode 100644 index 00000000..bea6250d --- /dev/null +++ b/Zend/Gdata/Exif.php @@ -0,0 +1,65 @@ +registerPackage('Zend_Gdata_Exif'); + $this->registerPackage('Zend_Gdata_Exif_Extension'); + parent::__construct($client, $applicationId); + } + +} diff --git a/Zend/Gdata/Exif/Entry.php b/Zend/Gdata/Exif/Entry.php new file mode 100644 index 00000000..da33cbc4 --- /dev/null +++ b/Zend/Gdata/Exif/Entry.php @@ -0,0 +1,145 @@ +registerAllNamespaces(Zend_Gdata_Exif::$namespaces); + parent::__construct($element); + } + + /** + * Retrieves a DOMElement which corresponds to this element and all + * child properties. This is used to build an entry back into a DOM + * and eventually XML text for sending to the server upon updates, or + * for application storage/persistence. + * + * @param DOMDocument $doc The DOMDocument used to construct DOMElements + * @return DOMElement The DOMElement representing this element and all + * child properties. + */ + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc, $majorVersion, $minorVersion); + if ($this->_tags != null) { + $element->appendChild($this->_tags->getDOM($element->ownerDocument)); + } + return $element; + } + + /** + * Creates individual Entry objects of the appropriate type and + * stores them as members of this entry based upon DOM data. + * + * @param DOMNode $child The DOMNode to process + */ + protected function takeChildFromDOM($child) + { + $absoluteNodeName = $child->namespaceURI . ':' . $child->localName; + switch ($absoluteNodeName) { + case $this->lookupNamespace('exif') . ':' . 'tags': + $tags = new Zend_Gdata_Exif_Extension_Tags(); + $tags->transferFromDOM($child); + $this->_tags = $tags; + break; + default: + parent::takeChildFromDOM($child); + break; + } + } + + /** + * Retrieve the tags for this entry. + * + * @see setTags + * @return Zend_Gdata_Exif_Extension_Tags The requested object + * or null if not set. + */ + public function getTags() + { + return $this->_tags; + } + + /** + * Set the tags property for this entry. This property contains + * various Exif data. + * + * This corresponds to the property in the Google Data + * protocol. + * + * @param Zend_Gdata_Exif_Extension_Tags $value The desired value + * this element, or null to unset. + * @return Zend_Gdata_Exif_Entry Provides a fluent interface + */ + public function setTags($value) + { + $this->_tags = $value; + return $this; + } + +} diff --git a/Zend/Gdata/Exif/Extension/Distance.php b/Zend/Gdata/Exif/Extension/Distance.php new file mode 100644 index 00000000..44d08827 --- /dev/null +++ b/Zend/Gdata/Exif/Extension/Distance.php @@ -0,0 +1,61 @@ +registerAllNamespaces(Zend_Gdata_Exif::$namespaces); + parent::__construct(); + $this->setText($text); + } + +} diff --git a/Zend/Gdata/Exif/Extension/Exposure.php b/Zend/Gdata/Exif/Extension/Exposure.php new file mode 100644 index 00000000..052d67ff --- /dev/null +++ b/Zend/Gdata/Exif/Extension/Exposure.php @@ -0,0 +1,61 @@ +registerAllNamespaces(Zend_Gdata_Exif::$namespaces); + parent::__construct(); + $this->setText($text); + } + +} diff --git a/Zend/Gdata/Exif/Extension/FStop.php b/Zend/Gdata/Exif/Extension/FStop.php new file mode 100644 index 00000000..78bb3475 --- /dev/null +++ b/Zend/Gdata/Exif/Extension/FStop.php @@ -0,0 +1,61 @@ +registerAllNamespaces(Zend_Gdata_Exif::$namespaces); + parent::__construct(); + $this->setText($text); + } + +} diff --git a/Zend/Gdata/Exif/Extension/Flash.php b/Zend/Gdata/Exif/Extension/Flash.php new file mode 100644 index 00000000..c1473ddf --- /dev/null +++ b/Zend/Gdata/Exif/Extension/Flash.php @@ -0,0 +1,61 @@ +registerAllNamespaces(Zend_Gdata_Exif::$namespaces); + parent::__construct(); + $this->setText($text); + } + +} diff --git a/Zend/Gdata/Exif/Extension/FocalLength.php b/Zend/Gdata/Exif/Extension/FocalLength.php new file mode 100644 index 00000000..6f6ab3e7 --- /dev/null +++ b/Zend/Gdata/Exif/Extension/FocalLength.php @@ -0,0 +1,61 @@ +registerAllNamespaces(Zend_Gdata_Exif::$namespaces); + parent::__construct(); + $this->setText($text); + } + +} diff --git a/Zend/Gdata/Exif/Extension/ImageUniqueId.php b/Zend/Gdata/Exif/Extension/ImageUniqueId.php new file mode 100644 index 00000000..910d6ea3 --- /dev/null +++ b/Zend/Gdata/Exif/Extension/ImageUniqueId.php @@ -0,0 +1,61 @@ +registerAllNamespaces(Zend_Gdata_Exif::$namespaces); + parent::__construct(); + $this->setText($text); + } + +} diff --git a/Zend/Gdata/Exif/Extension/Iso.php b/Zend/Gdata/Exif/Extension/Iso.php new file mode 100644 index 00000000..fddf025e --- /dev/null +++ b/Zend/Gdata/Exif/Extension/Iso.php @@ -0,0 +1,61 @@ +registerAllNamespaces(Zend_Gdata_Exif::$namespaces); + parent::__construct(); + $this->setText($text); + } + +} diff --git a/Zend/Gdata/Exif/Extension/Make.php b/Zend/Gdata/Exif/Extension/Make.php new file mode 100644 index 00000000..b090f072 --- /dev/null +++ b/Zend/Gdata/Exif/Extension/Make.php @@ -0,0 +1,61 @@ +registerAllNamespaces(Zend_Gdata_Exif::$namespaces); + parent::__construct(); + $this->setText($text); + } + +} diff --git a/Zend/Gdata/Exif/Extension/Model.php b/Zend/Gdata/Exif/Extension/Model.php new file mode 100644 index 00000000..230bb57a --- /dev/null +++ b/Zend/Gdata/Exif/Extension/Model.php @@ -0,0 +1,61 @@ +registerAllNamespaces(Zend_Gdata_Exif::$namespaces); + parent::__construct(); + $this->setText($text); + } + +} diff --git a/Zend/Gdata/Exif/Extension/Tags.php b/Zend/Gdata/Exif/Extension/Tags.php new file mode 100644 index 00000000..38c7cc57 --- /dev/null +++ b/Zend/Gdata/Exif/Extension/Tags.php @@ -0,0 +1,549 @@ +registerAllNamespaces(Zend_Gdata_Exif::$namespaces); + parent::__construct(); + $this->setDistance($distance); + $this->setExposure($exposure); + $this->setFlash($flash); + $this->setFocalLength($focalLength); + $this->setFStop($fStop); + $this->setImageUniqueId($imageUniqueId); + $this->setIso($iso); + $this->setMake($make); + $this->setModel($model); + $this->setTime($time); + } + + /** + * Retrieves a DOMElement which corresponds to this element and all + * child properties. This is used to build an entry back into a DOM + * and eventually XML text for application storage/persistence. + * + * @param DOMDocument $doc The DOMDocument used to construct DOMElements + * @return DOMElement The DOMElement representing this element and all + * child properties. + */ + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc, $majorVersion, $minorVersion); + if ($this->_distance !== null) { + $element->appendChild($this->_distance->getDOM($element->ownerDocument)); + } + if ($this->_exposure !== null) { + $element->appendChild($this->_exposure->getDOM($element->ownerDocument)); + } + if ($this->_flash !== null) { + $element->appendChild($this->_flash->getDOM($element->ownerDocument)); + } + if ($this->_focalLength !== null) { + $element->appendChild($this->_focalLength->getDOM($element->ownerDocument)); + } + if ($this->_fStop !== null) { + $element->appendChild($this->_fStop->getDOM($element->ownerDocument)); + } + if ($this->_imageUniqueId !== null) { + $element->appendChild($this->_imageUniqueId->getDOM($element->ownerDocument)); + } + if ($this->_iso !== null) { + $element->appendChild($this->_iso->getDOM($element->ownerDocument)); + } + if ($this->_make !== null) { + $element->appendChild($this->_make->getDOM($element->ownerDocument)); + } + if ($this->_model !== null) { + $element->appendChild($this->_model->getDOM($element->ownerDocument)); + } + if ($this->_time !== null) { + $element->appendChild($this->_time->getDOM($element->ownerDocument)); + } + return $element; + } + + /** + * Creates individual Entry objects of the appropriate type and + * stores them as members of this entry based upon DOM data. + * + * @param DOMNode $child The DOMNode to process + */ + protected function takeChildFromDOM($child) + { + $absoluteNodeName = $child->namespaceURI . ':' . $child->localName; + switch ($absoluteNodeName) { + case $this->lookupNamespace('exif') . ':' . 'distance'; + $distance = new Zend_Gdata_Exif_Extension_Distance(); + $distance->transferFromDOM($child); + $this->_distance = $distance; + break; + case $this->lookupNamespace('exif') . ':' . 'exposure'; + $exposure = new Zend_Gdata_Exif_Extension_Exposure(); + $exposure->transferFromDOM($child); + $this->_exposure = $exposure; + break; + case $this->lookupNamespace('exif') . ':' . 'flash'; + $flash = new Zend_Gdata_Exif_Extension_Flash(); + $flash->transferFromDOM($child); + $this->_flash = $flash; + break; + case $this->lookupNamespace('exif') . ':' . 'focallength'; + $focalLength = new Zend_Gdata_Exif_Extension_FocalLength(); + $focalLength->transferFromDOM($child); + $this->_focalLength = $focalLength; + break; + case $this->lookupNamespace('exif') . ':' . 'fstop'; + $fStop = new Zend_Gdata_Exif_Extension_FStop(); + $fStop->transferFromDOM($child); + $this->_fStop = $fStop; + break; + case $this->lookupNamespace('exif') . ':' . 'imageUniqueID'; + $imageUniqueId = new Zend_Gdata_Exif_Extension_ImageUniqueId(); + $imageUniqueId->transferFromDOM($child); + $this->_imageUniqueId = $imageUniqueId; + break; + case $this->lookupNamespace('exif') . ':' . 'iso'; + $iso = new Zend_Gdata_Exif_Extension_Iso(); + $iso->transferFromDOM($child); + $this->_iso = $iso; + break; + case $this->lookupNamespace('exif') . ':' . 'make'; + $make = new Zend_Gdata_Exif_Extension_Make(); + $make->transferFromDOM($child); + $this->_make = $make; + break; + case $this->lookupNamespace('exif') . ':' . 'model'; + $model = new Zend_Gdata_Exif_Extension_Model(); + $model->transferFromDOM($child); + $this->_model = $model; + break; + case $this->lookupNamespace('exif') . ':' . 'time'; + $time = new Zend_Gdata_Exif_Extension_Time(); + $time->transferFromDOM($child); + $this->_time = $time; + break; + } + } + + /** + * Get the value for this element's distance attribute. + * + * @see setDistance + * @return Zend_Gdata_Exif_Extension_Distance The requested attribute. + */ + public function getDistance() + { + return $this->_distance; + } + + /** + * Set the value for this element's distance attribute. + * + * @param Zend_Gdata_Exif_Extension_Distance $value The desired value for this attribute. + * @return Zend_Gdata_Exif_Extension_Tags Provides a fluent interface + */ + public function setDistance($value) + { + $this->_distance = $value; + return $this; + } + + /** + * Get the value for this element's exposure attribute. + * + * @see setExposure + * @return Zend_Gdata_Exif_Extension_Exposure The requested attribute. + */ + public function getExposure() + { + return $this->_exposure; + } + + /** + * Set the value for this element's exposure attribute. + * + * @param Zend_Gdata_Exif_Extension_Exposure $value The desired value for this attribute. + * @return Zend_Gdata_Exif_Extension_Tags Provides a fluent interface + */ + public function setExposure($value) + { + $this->_exposure = $value; + return $this; + } + + /** + * Get the value for this element's flash attribute. + * + * @see setFlash + * @return Zend_Gdata_Exif_Extension_Flash The requested attribute. + */ + public function getFlash() + { + return $this->_flash; + } + + /** + * Set the value for this element's flash attribute. + * + * @param Zend_Gdata_Exif_Extension_Flash $value The desired value for this attribute. + * @return Zend_Gdata_Exif_Extension_Tags Provides a fluent interface + */ + public function setFlash($value) + { + $this->_flash = $value; + return $this; + } + + /** + * Get the value for this element's name attribute. + * + * @see setFocalLength + * @return Zend_Gdata_Exif_Extension_FocalLength The requested attribute. + */ + public function getFocalLength() + { + return $this->_focalLength; + } + + /** + * Set the value for this element's focalLength attribute. + * + * @param Zend_Gdata_Exif_Extension_FocalLength $value The desired value for this attribute. + * @return Zend_Gdata_Exif_Extension_Tags Provides a fluent interface + */ + public function setFocalLength($value) + { + $this->_focalLength = $value; + return $this; + } + + /** + * Get the value for this element's fStop attribute. + * + * @see setFStop + * @return Zend_Gdata_Exif_Extension_FStop The requested attribute. + */ + public function getFStop() + { + return $this->_fStop; + } + + /** + * Set the value for this element's fStop attribute. + * + * @param Zend_Gdata_Exif_Extension_FStop $value The desired value for this attribute. + * @return Zend_Gdata_Exif_Extension_Tags Provides a fluent interface + */ + public function setFStop($value) + { + $this->_fStop = $value; + return $this; + } + + /** + * Get the value for this element's imageUniqueId attribute. + * + * @see setImageUniqueId + * @return Zend_Gdata_Exif_Extension_ImageUniqueId The requested attribute. + */ + public function getImageUniqueId() + { + return $this->_imageUniqueId; + } + + /** + * Set the value for this element's imageUniqueId attribute. + * + * @param Zend_Gdata_Exif_Extension_ImageUniqueId $value The desired value for this attribute. + * @return Zend_Gdata_Exif_Extension_Tags Provides a fluent interface + */ + public function setImageUniqueId($value) + { + $this->_imageUniqueId = $value; + return $this; + } + + /** + * Get the value for this element's iso attribute. + * + * @see setIso + * @return Zend_Gdata_Exif_Extension_Iso The requested attribute. + */ + public function getIso() + { + return $this->_iso; + } + + /** + * Set the value for this element's iso attribute. + * + * @param Zend_Gdata_Exif_Extension_Iso $value The desired value for this attribute. + * @return Zend_Gdata_Exif_Extension_Tags Provides a fluent interface + */ + public function setIso($value) + { + $this->_iso = $value; + return $this; + } + /** + * Get the value for this element's make attribute. + * + * @see setMake + * @return Zend_Gdata_Exif_Extension_Make The requested attribute. + */ + public function getMake() + { + return $this->_make; + } + + /** + * Set the value for this element's make attribute. + * + * @param Zend_Gdata_Exif_Extension_Make $value The desired value for this attribute. + * @return Zend_Gdata_Exif_Extension_Tags Provides a fluent interface + */ + public function setMake($value) + { + $this->_make = $value; + return $this; + } + + /** + * Get the value for this element's model attribute. + * + * @see setModel + * @return Zend_Gdata_Exif_Extension_Model The requested attribute. + */ + public function getModel() + { + return $this->_model; + } + + /** + * Set the value for this element's model attribute. + * + * @param Zend_Gdata_Exif_Extension_Model $value The desired value for this attribute. + * @return Zend_Gdata_Exif_Extension_Tags Provides a fluent interface + */ + public function setModel($value) + { + $this->_model = $value; + return $this; + } + + /** + * Get the value for this element's time attribute. + * + * @see setTime + * @return Zend_Gdata_Exif_Extension_Time The requested attribute. + */ + public function getTime() + { + return $this->_time; + } + + /** + * Set the value for this element's time attribute. + * + * @param Zend_Gdata_Exif_Extension_Time $value The desired value for this attribute. + * @return Zend_Gdata_Exif_Extension_Tags Provides a fluent interface + */ + public function setTime($value) + { + $this->_time = $value; + return $this; + } + +} diff --git a/Zend/Gdata/Exif/Extension/Time.php b/Zend/Gdata/Exif/Extension/Time.php new file mode 100644 index 00000000..5fe3ee85 --- /dev/null +++ b/Zend/Gdata/Exif/Extension/Time.php @@ -0,0 +1,61 @@ +registerAllNamespaces(Zend_Gdata_Exif::$namespaces); + parent::__construct(); + $this->setText($text); + } + +} diff --git a/Zend/Gdata/Exif/Feed.php b/Zend/Gdata/Exif/Feed.php new file mode 100644 index 00000000..b100ccee --- /dev/null +++ b/Zend/Gdata/Exif/Feed.php @@ -0,0 +1,70 @@ +registerAllNamespaces(Zend_Gdata_Exif::$namespaces); + parent::__construct($element); + } + +} diff --git a/Zend/Gdata/Extension.php b/Zend/Gdata/Extension.php new file mode 100644 index 00000000..233a084a --- /dev/null +++ b/Zend/Gdata/Extension.php @@ -0,0 +1,58 @@ +registerNamespace('gd', + 'http://schemas.google.com/g/2005'); + $this->registerNamespace('openSearch', + 'http://a9.com/-/spec/opensearchrss/1.0/', 1, 0); + $this->registerNamespace('openSearch', + 'http://a9.com/-/spec/opensearch/1.1/', 2, 0); + $this->registerNamespace('rss', + 'http://blogs.law.harvard.edu/tech/rss'); + + parent::__construct(); + } + +} diff --git a/Zend/Gdata/Extension/AttendeeStatus.php b/Zend/Gdata/Extension/AttendeeStatus.php new file mode 100644 index 00000000..42866fab --- /dev/null +++ b/Zend/Gdata/Extension/AttendeeStatus.php @@ -0,0 +1,123 @@ +_value = $value; + } + + /** + * Retrieves a DOMElement which corresponds to this element and all + * child properties. This is used to build an entry back into a DOM + * and eventually XML text for sending to the server upon updates, or + * for application storage/persistence. + * + * @param DOMDocument $doc The DOMDocument used to construct DOMElements + * @return DOMElement The DOMElement representing this element and all + * child properties. + */ + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc, $majorVersion, $minorVersion); + if ($this->_value !== null) { + $element->setAttribute('value', $this->_value); + } + return $element; + } + + /** + * Given a DOMNode representing an attribute, tries to map the data into + * instance members. If no mapping is defined, the name and value are + * stored in an array. + * + * @param DOMNode $attribute The DOMNode attribute needed to be handled + */ + protected function takeAttributeFromDOM($attribute) + { + switch ($attribute->localName) { + case 'value': + $this->_value = $attribute->nodeValue; + break; + default: + parent::takeAttributeFromDOM($attribute); + } + } + + /** + * Get the value for this element's Value attribute. + * + * @return string The requested attribute. + */ + public function getValue() + { + return $this->_value; + } + + /** + * Set the value for this element's Value attribute. + * + * @param string $value The desired value for this attribute. + * @return Zend_Gdata_Extension_Visibility The element being modified. + */ + public function setValue($value) + { + $this->_value = $value; + return $this; + } + + /** + * Magic toString method allows using this directly via echo + * Works best in PHP >= 4.2.0 + */ + public function __toString() + { + return $this->getValue(); + } + +} + diff --git a/Zend/Gdata/Extension/AttendeeType.php b/Zend/Gdata/Extension/AttendeeType.php new file mode 100644 index 00000000..1127f226 --- /dev/null +++ b/Zend/Gdata/Extension/AttendeeType.php @@ -0,0 +1,123 @@ +_value = $value; + } + + /** + * Retrieves a DOMElement which corresponds to this element and all + * child properties. This is used to build an entry back into a DOM + * and eventually XML text for sending to the server upon updates, or + * for application storage/persistence. + * + * @param DOMDocument $doc The DOMDocument used to construct DOMElements + * @return DOMElement The DOMElement representing this element and all + * child properties. + */ + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc, $majorVersion, $minorVersion); + if ($this->_value !== null) { + $element->setAttribute('value', $this->_value); + } + return $element; + } + + /** + * Given a DOMNode representing an attribute, tries to map the data into + * instance members. If no mapping is defined, the name and value are + * stored in an array. + * + * @param DOMNode $attribute The DOMNode attribute needed to be handled + */ + protected function takeAttributeFromDOM($attribute) + { + switch ($attribute->localName) { + case 'value': + $this->_value = $attribute->nodeValue; + break; + default: + parent::takeAttributeFromDOM($attribute); + } + } + + /** + * Get the value for this element's Value attribute. + * + * @return string The requested attribute. + */ + public function getValue() + { + return $this->_value; + } + + /** + * Set the value for this element's Value attribute. + * + * @param string $value The desired value for this attribute. + * @return Zend_Gdata_Extension_Visibility The element being modified. + */ + public function setValue($value) + { + $this->_value = $value; + return $this; + } + + /** + * Magic toString method allows using this directly via echo + * Works best in PHP >= 4.2.0 + */ + public function __toString() + { + return $this->getValue(); + } + +} + diff --git a/Zend/Gdata/Extension/Comments.php b/Zend/Gdata/Extension/Comments.php new file mode 100644 index 00000000..0397f525 --- /dev/null +++ b/Zend/Gdata/Extension/Comments.php @@ -0,0 +1,117 @@ +_rel = $rel; + $this->_feedLink = $feedLink; + } + + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc, $majorVersion, $minorVersion); + if ($this->_rel !== null) { + $element->setAttribute('rel', $this->_rel); + } + if ($this->_feedLink !== null) { + $element->appendChild($this->_feedLink->getDOM($element->ownerDocument)); + } + return $element; + } + + protected function takeChildFromDOM($child) + { + $absoluteNodeName = $child->namespaceURI . ':' . $child->localName; + switch ($absoluteNodeName) { + case $this->lookupNamespace('gd') . ':' . 'feedLink'; + $feedLink = new Zend_Gdata_Extension_FeedLink(); + $feedLink->transferFromDOM($child); + $this->_feedLink = $feedLink; + break; + default: + parent::takeChildFromDOM($child); + break; + } + } + + protected function takeAttributeFromDOM($attribute) + { + switch ($attribute->localName) { + case 'rel': + $this->_rel = $attribute->nodeValue; + break; + default: + parent::takeAttributeFromDOM($attribute); + } + } + + public function getRel() + { + return $this->_rel; + } + + public function setRel($value) + { + $this->_rel = $value; + return $this; + } + + public function getFeedLink() + { + return $this->_feedLink; + } + + public function setFeedLink($value) + { + $this->_feedLink = $value; + return $this; + } + +} diff --git a/Zend/Gdata/Extension/EntryLink.php b/Zend/Gdata/Extension/EntryLink.php new file mode 100644 index 00000000..5da4710b --- /dev/null +++ b/Zend/Gdata/Extension/EntryLink.php @@ -0,0 +1,167 @@ +_href = $href; + $this->_readOnly = $readOnly; + $this->_rel = $rel; + $this->_entry = $entry; + } + + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc, $majorVersion, $minorVersion); + if ($this->_href !== null) { + $element->setAttribute('href', $this->_href); + } + if ($this->_readOnly !== null) { + $element->setAttribute('readOnly', ($this->_readOnly ? "true" : "false")); + } + if ($this->_rel !== null) { + $element->setAttribute('rel', $this->_rel); + } + if ($this->_entry !== null) { + $element->appendChild($this->_entry->getDOM($element->ownerDocument)); + } + return $element; + } + + protected function takeChildFromDOM($child) + { + $absoluteNodeName = $child->namespaceURI . ':' . $child->localName; + switch ($absoluteNodeName) { + case $this->lookupNamespace('atom') . ':' . 'entry'; + $entry = new Zend_Gdata_Entry(); + $entry->transferFromDOM($child); + $this->_entry = $entry; + break; + default: + parent::takeChildFromDOM($child); + break; + } + } + + protected function takeAttributeFromDOM($attribute) + { + switch ($attribute->localName) { + case 'href': + $this->_href = $attribute->nodeValue; + break; + case 'readOnly': + if ($attribute->nodeValue == "true") { + $this->_readOnly = true; + } + else if ($attribute->nodeValue == "false") { + $this->_readOnly = false; + } + else { + throw new Zend_Gdata_App_InvalidArgumentException("Expected 'true' or 'false' for gCal:selected#value."); + } + break; + case 'rel': + $this->_rel = $attribute->nodeValue; + break; + default: + parent::takeAttributeFromDOM($attribute); + } + } + + /** + * @return string + */ + public function getHref() + { + return $this->_href; + } + + public function setHref($value) + { + $this->_href = $value; + return $this; + } + + public function getReadOnly() + { + return $this->_readOnly; + } + + public function setReadOnly($value) + { + $this->_readOnly = $value; + return $this; + } + + public function getRel() + { + return $this->_rel; + } + + public function setRel($value) + { + $this->_rel = $value; + return $this; + } + + public function getEntry() + { + return $this->_entry; + } + + public function setEntry($value) + { + $this->_entry = $value; + return $this; + } + +} diff --git a/Zend/Gdata/Extension/EventStatus.php b/Zend/Gdata/Extension/EventStatus.php new file mode 100644 index 00000000..6d8ee00d --- /dev/null +++ b/Zend/Gdata/Extension/EventStatus.php @@ -0,0 +1,101 @@ +_value = $value; + } + + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc, $majorVersion, $minorVersion); + if ($this->_value !== null) { + $element->setAttribute('value', $this->_value); + } + return $element; + } + + protected function takeAttributeFromDOM($attribute) + { + switch ($attribute->localName) { + case 'value': + $this->_value = $attribute->nodeValue; + break; + default: + parent::takeAttributeFromDOM($attribute); + } + } + + /** + * Get the value for this element's Value attribute. + * + * @return string The requested attribute. + */ + public function getValue() + { + return $this->_value; + } + + /** + * Set the value for this element's Value attribute. + * + * @param string $value The desired value for this attribute. + * @return Zend_Gdata_Extension_Visibility The element being modified. + */ + public function setValue($value) + { + $this->_value = $value; + return $this; + } + + /** + * Magic toString method allows using this directly via echo + * Works best in PHP >= 4.2.0 + */ + public function __toString() + { + return $this->getValue(); + } + +} diff --git a/Zend/Gdata/Extension/ExtendedProperty.php b/Zend/Gdata/Extension/ExtendedProperty.php new file mode 100644 index 00000000..d7a41b76 --- /dev/null +++ b/Zend/Gdata/Extension/ExtendedProperty.php @@ -0,0 +1,106 @@ +_name = $name; + $this->_value = $value; + } + + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc, $majorVersion, $minorVersion); + if ($this->_name !== null) { + $element->setAttribute('name', $this->_name); + } + if ($this->_value !== null) { + $element->setAttribute('value', $this->_value); + } + return $element; + } + + protected function takeAttributeFromDOM($attribute) + { + switch ($attribute->localName) { + case 'name': + $this->_name = $attribute->nodeValue; + break; + case 'value': + $this->_value = $attribute->nodeValue; + break; + default: + parent::takeAttributeFromDOM($attribute); + } + } + + public function __toString() + { + return $this->getName() . '=' . $this->getValue(); + } + + public function getName() + { + return $this->_name; + } + + public function setName($value) + { + $this->_name = $value; + return $this; + } + + public function getValue() + { + return $this->_value; + } + + public function setValue($value) + { + $this->_value = $value; + return $this; + } + +} diff --git a/Zend/Gdata/Extension/FeedLink.php b/Zend/Gdata/Extension/FeedLink.php new file mode 100644 index 00000000..1e3918b0 --- /dev/null +++ b/Zend/Gdata/Extension/FeedLink.php @@ -0,0 +1,175 @@ +_countHint = $countHint; + $this->_href = $href; + $this->_readOnly = $readOnly; + $this->_rel = $rel; + $this->_feed = $feed; + } + + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc, $majorVersion, $minorVersion); + if ($this->_countHint !== null) { + $element->setAttribute('countHint', $this->_countHint); + } + if ($this->_href !== null) { + $element->setAttribute('href', $this->_href); + } + if ($this->_readOnly !== null) { + $element->setAttribute('readOnly', ($this->_readOnly ? "true" : "false")); + } + if ($this->_rel !== null) { + $element->setAttribute('rel', $this->_rel); + } + if ($this->_feed !== null) { + $element->appendChild($this->_feed->getDOM($element->ownerDocument)); + } + return $element; + } + + protected function takeChildFromDOM($child) + { + $absoluteNodeName = $child->namespaceURI . ':' . $child->localName; + switch ($absoluteNodeName) { + case $this->lookupNamespace('atom') . ':' . 'feed'; + $feed = new Zend_Gdata_Feed(); + $feed->transferFromDOM($child); + $this->_feed = $feed; + break; + default: + parent::takeChildFromDOM($child); + break; + } + } + + protected function takeAttributeFromDOM($attribute) + { + switch ($attribute->localName) { + case 'countHint': + $this->_countHint = $attribute->nodeValue; + break; + case 'href': + $this->_href = $attribute->nodeValue; + break; + case 'readOnly': + if ($attribute->nodeValue == "true") { + $this->_readOnly = true; + } + else if ($attribute->nodeValue == "false") { + $this->_readOnly = false; + } + else { + throw new Zend_Gdata_App_InvalidArgumentException("Expected 'true' or 'false' for gCal:selected#value."); + } + break; + case 'rel': + $this->_rel = $attribute->nodeValue; + break; + default: + parent::takeAttributeFromDOM($attribute); + } + } + + /** + * @return string + */ + public function getHref() + { + return $this->_href; + } + + public function setHref($value) + { + $this->_href = $value; + return $this; + } + + public function getReadOnly() + { + return $this->_readOnly; + } + + public function setReadOnly($value) + { + $this->_readOnly = $value; + return $this; + } + + public function getRel() + { + return $this->_rel; + } + + public function setRel($value) + { + $this->_rel = $value; + return $this; + } + + public function getFeed() + { + return $this->_feed; + } + + public function setFeed($value) + { + $this->_feed = $value; + return $this; + } + +} diff --git a/Zend/Gdata/Extension/OpenSearchItemsPerPage.php b/Zend/Gdata/Extension/OpenSearchItemsPerPage.php new file mode 100644 index 00000000..d97a414b --- /dev/null +++ b/Zend/Gdata/Extension/OpenSearchItemsPerPage.php @@ -0,0 +1,50 @@ +_text = $text; + } + +} diff --git a/Zend/Gdata/Extension/OpenSearchStartIndex.php b/Zend/Gdata/Extension/OpenSearchStartIndex.php new file mode 100644 index 00000000..c1a6cedb --- /dev/null +++ b/Zend/Gdata/Extension/OpenSearchStartIndex.php @@ -0,0 +1,50 @@ +_text = $text; + } + +} diff --git a/Zend/Gdata/Extension/OpenSearchTotalResults.php b/Zend/Gdata/Extension/OpenSearchTotalResults.php new file mode 100644 index 00000000..83e43bf4 --- /dev/null +++ b/Zend/Gdata/Extension/OpenSearchTotalResults.php @@ -0,0 +1,50 @@ +_text = $text; + } + +} diff --git a/Zend/Gdata/Extension/OriginalEvent.php b/Zend/Gdata/Extension/OriginalEvent.php new file mode 100644 index 00000000..28254a11 --- /dev/null +++ b/Zend/Gdata/Extension/OriginalEvent.php @@ -0,0 +1,142 @@ +_id = $id; + $this->_href = $href; + $this->_when = $when; + } + + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc, $majorVersion, $minorVersion); + if ($this->_id !== null) { + $element->setAttribute('id', $this->_id); + } + if ($this->_href !== null) { + $element->setAttribute('href', $this->_href); + } + if ($this->_when !== null) { + $element->appendChild($this->_when->getDOM($element->ownerDocument)); + } + return $element; + } + + protected function takeAttributeFromDOM($attribute) + { + switch ($attribute->localName) { + case 'id': + $this->_id = $attribute->nodeValue; + break; + case 'href': + $this->_href = $attribute->nodeValue; + break; + default: + parent::takeAttributeFromDOM($attribute); + } + } + + protected function takeChildFromDOM($child) + { + $absoluteNodeName = $child->namespaceURI . ':' . $child->localName; + switch ($absoluteNodeName) { + case $this->lookupNamespace('gd') . ':' . 'when'; + $when = new Zend_Gdata_Extension_When(); + $when->transferFromDOM($child); + $this->_when = $when; + break; + default: + parent::takeChildFromDOM($child); + break; + } + } + + public function getId() + { + return $this->_id; + } + + public function setId($value) + { + $this->_id = $value; + return $this; + } + + public function getHref() + { + return $this->_href; + } + + public function setHref($value) + { + $this->_href = $value; + return $this; + } + + public function getWhen() + { + return $this->_when; + } + + public function setWhen($value) + { + $this->_when = $value; + return $this; + } + + +} diff --git a/Zend/Gdata/Extension/Rating.php b/Zend/Gdata/Extension/Rating.php new file mode 100644 index 00000000..942cabfb --- /dev/null +++ b/Zend/Gdata/Extension/Rating.php @@ -0,0 +1,240 @@ +_average = $average; + $this->_min = $min; + $this->_max = $max; + $this->_numRaters = $numRaters; + $this->_value = $value; + } + + /** + * Retrieves a DOMElement which corresponds to this element and all + * child properties. This is used to build an entry back into a DOM + * and eventually XML text for sending to the server upon updates, or + * for application storage/persistence. + * + * @param DOMDocument $doc The DOMDocument used to construct DOMElements + * @return DOMElement The DOMElement representing this element and all + * child properties. + */ + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc, $majorVersion, $minorVersion); + if ($this->_min !== null) { + $element->setAttribute('min', $this->_min); + } + if ($this->_max !== null) { + $element->setAttribute('max', $this->_max); + } + if ($this->_numRaters !== null) { + $element->setAttribute('numRaters', $this->_numRaters); + } + if ($this->_average !== null) { + $element->setAttribute('average', $this->_average); + } + if ($this->_value !== null) { + $element->setAttribute('value', $this->_value); + } + + return $element; + } + + /** + * Given a DOMNode representing an attribute, tries to map the data into + * instance members. If no mapping is defined, the name and value are + * stored in an array. + * + * @param DOMNode $attribute The DOMNode attribute needed to be handled + */ + protected function takeAttributeFromDOM($attribute) + { + switch ($attribute->localName) { + case 'min': + $this->_min = $attribute->nodeValue; + break; + case 'max': + $this->_max = $attribute->nodeValue; + break; + case 'numRaters': + $this->_numRaters = $attribute->nodeValue; + break; + case 'average': + $this->_average = $attribute->nodeValue; + break; + case 'value': + $this->_value = $attribute->nodeValue; + default: + parent::takeAttributeFromDOM($attribute); + } + } + + /** + * Get the value for this element's min attribute. + * + * @return integer The requested attribute. + */ + public function getMin() + { + return $this->_min; + } + + /** + * Set the value for this element's min attribute. + * + * @param bool $value The desired value for this attribute. + * @return Zend_Gdata_Extension_Rating The element being modified. + */ + public function setMin($value) + { + $this->_min = $value; + return $this; + } + + /** + * Get the value for this element's numRaters attribute. + * + * @return integer The requested attribute. + */ + public function getNumRaters() + { + return $this->_numRaters; + } + + /** + * Set the value for this element's numRaters attribute. + * + * @param bool $value The desired value for this attribute. + * @return Zend_Gdata_Extension_Rating The element being modified. + */ + public function setNumRaters($value) + { + $this->_numRaters = $value; + return $this; + } + + /** + * Get the value for this element's average attribute. + * + * @return integer The requested attribute. + */ + public function getAverage() + { + return $this->_average; + } + + /** + * Set the value for this element's average attribute. + * + * @param bool $value The desired value for this attribute. + * @return Zend_Gdata_Extension_Rating The element being modified. + */ + public function setAverage($value) + { + $this->_average = $value; + return $this; + } + + /** + * Get the value for this element's max attribute. + * + * @return integer The requested attribute. + */ + public function getMax() + { + return $this->_max; + } + + /** + * Set the value for this element's max attribute. + * + * @param bool $value The desired value for this attribute. + * @return Zend_Gdata_Extension_Rating The element being modified. + */ + public function setMax($value) + { + $this->_max = $value; + return $this; + } + + /** + * Get the value for this element's value attribute. + * + * @return integer The requested attribute. + */ + public function getValue() + { + return $this->_value; + } + + /** + * Set the value for this element's value attribute. + * + * @param bool $value The desired value for this attribute. + * @return Zend_Gdata_Extension_Rating The element being modified. + */ + public function setValue($value) + { + $this->_value = $value; + return $this; + } + +} diff --git a/Zend/Gdata/Extension/Recurrence.php b/Zend/Gdata/Extension/Recurrence.php new file mode 100644 index 00000000..ce730385 --- /dev/null +++ b/Zend/Gdata/Extension/Recurrence.php @@ -0,0 +1,49 @@ +_text = $text; + } + +} diff --git a/Zend/Gdata/Extension/RecurrenceException.php b/Zend/Gdata/Extension/RecurrenceException.php new file mode 100644 index 00000000..456b4d15 --- /dev/null +++ b/Zend/Gdata/Extension/RecurrenceException.php @@ -0,0 +1,215 @@ +_specialized = $specialized; + $this->_entryLink = $entryLink; + $this->_originalEvent = $originalEvent; + } + + /** + * Retrieves a DOMElement which corresponds to this element and all + * child properties. This is used to build an entry back into a DOM + * and eventually XML text for sending to the server upon updates, or + * for application storage/persistence. + * + * @param DOMDocument $doc The DOMDocument used to construct DOMElements + * @return DOMElement The DOMElement representing this element and all + * child properties. + */ + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc, $majorVersion, $minorVersion); + if ($this->_specialized !== null) { + $element->setAttribute('specialized', ($this->_specialized ? "true" : "false")); + } + if ($this->_entryLink !== null) { + $element->appendChild($this->_entryLink->getDOM($element->ownerDocument)); + } + if ($this->_originalEvent !== null) { + $element->appendChild($this->_originalEvent->getDOM($element->ownerDocument)); + } + return $element; + } + + /** + * Given a DOMNode representing an attribute, tries to map the data into + * instance members. If no mapping is defined, the name and value are + * stored in an array. + * + * @param DOMNode $attribute The DOMNode attribute needed to be handled + */ + protected function takeAttributeFromDOM($attribute) + { + switch ($attribute->localName) { + case 'specialized': + if ($attribute->nodeValue == "true") { + $this->_specialized = true; + } + else if ($attribute->nodeValue == "false") { + $this->_specialized = false; + } + else { + throw new Zend_Gdata_App_InvalidArgumentException("Expected 'true' or 'false' for gCal:selected#value."); + } + break; + default: + parent::takeAttributeFromDOM($attribute); + } + } + + /** + * Creates individual Entry objects of the appropriate type and + * stores them as members of this entry based upon DOM data. + * + * @param DOMNode $child The DOMNode to process + */ + protected function takeChildFromDOM($child) + { + $absoluteNodeName = $child->namespaceURI . ':' . $child->localName; + switch ($absoluteNodeName) { + case $this->lookupNamespace('gd') . ':' . 'entryLink': + $entryLink = new Zend_Gdata_Extension_EntryLink(); + $entryLink->transferFromDOM($child); + $this->_entryLink = $entryLink; + break; + case $this->lookupNamespace('gd') . ':' . 'originalEvent': + $originalEvent = new Zend_Gdata_Extension_OriginalEvent(); + $originalEvent->transferFromDOM($child); + $this->_originalEvent = $originalEvent; + break; + default: + parent::takeChildFromDOM($child); + break; + } + } + + /** + * Get the value for this element's Specialized attribute. + * + * @return bool The requested attribute. + */ + public function getSpecialized() + { + return $this->_specialized; + } + + /** + * Set the value for this element's Specialized attribute. + * + * @param bool $value The desired value for this attribute. + * @return Zend_Gdata_Extension_RecurrenceException The element being modified. + */ + public function setSpecialized($value) + { + $this->_specialized = $value; + return $this; + } + + /** + * Get the value for this element's EntryLink attribute. + * + * @return Zend_Gdata_Extension_EntryLink The requested attribute. + */ + public function getEntryLink() + { + return $this->_entryLink; + } + + /** + * Set the value for this element's EntryLink attribute. + * + * @param Zend_Gdata_Extension_EntryLink $value The desired value for this attribute. + * @return Zend_Gdata_Extension_RecurrenceException The element being modified. + */ + public function setEntryLink($value) + { + $this->_entryLink = $value; + return $this; + } + + /** + * Get the value for this element's Specialized attribute. + * + * @return Zend_Gdata_Extension_OriginalEvent The requested attribute. + */ + public function getOriginalEvent() + { + return $this->_originalEvent; + } + + /** + * Set the value for this element's Specialized attribute. + * + * @param Zend_Gdata_Extension_OriginalEvent $value The desired value for this attribute. + * @return Zend_Gdata_Extension_RecurrenceException The element being modified. + */ + public function setOriginalEvent($value) + { + $this->_originalEvent = $value; + return $this; + } + +} + diff --git a/Zend/Gdata/Extension/Reminder.php b/Zend/Gdata/Extension/Reminder.php new file mode 100644 index 00000000..82b72826 --- /dev/null +++ b/Zend/Gdata/Extension/Reminder.php @@ -0,0 +1,171 @@ +_absoluteTime = $absoluteTime; + $this->_method = $method; + $this->_days = $days; + $this->_hours = $hours; + $this->_minutes = $minutes; + } + + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc, $majorVersion, $minorVersion); + if ($this->_absoluteTime !== null) { + $element->setAttribute('absoluteTime', $this->_absoluteTime); + } + if ($this->_method !== null) { + $element->setAttribute('method', $this->_method); + } + if ($this->_days !== null) { + $element->setAttribute('days', $this->_days); + } + if ($this->_hours !== null) { + $element->setAttribute('hours', $this->_hours); + } + if ($this->_minutes !== null) { + $element->setAttribute('minutes', $this->_minutes); + } + return $element; + } + + protected function takeAttributeFromDOM($attribute) + { + switch ($attribute->localName) { + case 'absoluteTime': + $this->_absoluteTime = $attribute->nodeValue; + break; + case 'method': + $this->_method = $attribute->nodeValue; + break; + case 'days': + $this->_days = $attribute->nodeValue; + break; + case 'hours': + $this->_hours = $attribute->nodeValue; + break; + case 'minutes': + $this->_minutes = $attribute->nodeValue; + break; + default: + parent::takeAttributeFromDOM($attribute); + } + } + + public function __toString() + { + $s = ''; + if ($this->_absoluteTime) + $s = " at " . $this->_absoluteTime; + else if ($this->_days) + $s = " in " . $this->_days . " days"; + else if ($this->_hours) + $s = " in " . $this->_hours . " hours"; + else if ($this->_minutes) + $s = " in " . $this->_minutes . " minutes"; + return $this->_method . $s; + } + + public function getAbsoluteTime() + { + return $this->_absoluteTime; + } + + public function setAbsoluteTime($value) + { + $this->_absoluteTime = $value; + return $this; + } + + public function getDays() + { + return $this->_days; + } + + public function setDays($value) + { + $this->_days = $value; + return $this; + } + public function getHours() + { + return $this->_hours; + } + + public function setHours($value) + { + $this->_hours = $value; + return $this; + } + + public function getMinutes() + { + return $this->_minutes; + } + + public function setMinutes($value) + { + $this->_minutes = $value; + return $this; + } + + public function getMethod() + { + return $this->_method; + } + + public function setMethod($value) + { + $this->_method = $value; + return $this; + } + +} diff --git a/Zend/Gdata/Extension/Transparency.php b/Zend/Gdata/Extension/Transparency.php new file mode 100644 index 00000000..d271740d --- /dev/null +++ b/Zend/Gdata/Extension/Transparency.php @@ -0,0 +1,123 @@ +_value = $value; + } + + /** + * Retrieves a DOMElement which corresponds to this element and all + * child properties. This is used to build an entry back into a DOM + * and eventually XML text for sending to the server upon updates, or + * for application storage/persistence. + * + * @param DOMDocument $doc The DOMDocument used to construct DOMElements + * @return DOMElement The DOMElement representing this element and all + * child properties. + */ + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc, $majorVersion, $minorVersion); + if ($this->_value !== null) { + $element->setAttribute('value', $this->_value); + } + return $element; + } + + /** + * Given a DOMNode representing an attribute, tries to map the data into + * instance members. If no mapping is defined, the name and value are + * stored in an array. + * + * @param DOMNode $attribute The DOMNode attribute needed to be handled + */ + protected function takeAttributeFromDOM($attribute) + { + switch ($attribute->localName) { + case 'value': + $this->_value = $attribute->nodeValue; + break; + default: + parent::takeAttributeFromDOM($attribute); + } + } + + /** + * Get the value for this element's Value attribute. + * + * @return bool The requested attribute. + */ + public function getValue() + { + return $this->_value; + } + + /** + * Set the value for this element's Value attribute. + * + * @param bool $value The desired value for this attribute. + * @return Zend_Gdata_Extension_Transparency The element being modified. + */ + public function setValue($value) + { + $this->_value = $value; + return $this; + } + + /** + * Magic toString method allows using this directly via echo + * Works best in PHP >= 4.2.0 + */ + public function __toString() + { + return $this->getValue(); + } + +} + diff --git a/Zend/Gdata/Extension/Visibility.php b/Zend/Gdata/Extension/Visibility.php new file mode 100644 index 00000000..bdd84daf --- /dev/null +++ b/Zend/Gdata/Extension/Visibility.php @@ -0,0 +1,123 @@ +_value = $value; + } + + /** + * Retrieves a DOMElement which corresponds to this element and all + * child properties. This is used to build an entry back into a DOM + * and eventually XML text for sending to the server upon updates, or + * for application storage/persistence. + * + * @param DOMDocument $doc The DOMDocument used to construct DOMElements + * @return DOMElement The DOMElement representing this element and all + * child properties. + */ + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc, $majorVersion, $minorVersion); + if ($this->_value !== null) { + $element->setAttribute('value', $this->_value); + } + return $element; + } + + /** + * Given a DOMNode representing an attribute, tries to map the data into + * instance members. If no mapping is defined, the name and value are + * stored in an array. + * + * @param DOMNode $attribute The DOMNode attribute needed to be handled + */ + protected function takeAttributeFromDOM($attribute) + { + switch ($attribute->localName) { + case 'value': + $this->_value = $attribute->nodeValue; + break; + default: + parent::takeAttributeFromDOM($attribute); + } + } + + /** + * Get the value for this element's Value attribute. + * + * @return bool The requested attribute. + */ + public function getValue() + { + return $this->_value; + } + + /** + * Set the value for this element's Value attribute. + * + * @param bool $value The desired value for this attribute. + * @return Zend_Gdata_Extension_Visibility The element being modified. + */ + public function setValue($value) + { + $this->_value = $value; + return $this; + } + + /** + * Magic toString method allows using this directly via echo + * Works best in PHP >= 4.2.0 + */ + public function __toString() + { + return $this->getValue(); + } + +} + diff --git a/Zend/Gdata/Extension/When.php b/Zend/Gdata/Extension/When.php new file mode 100644 index 00000000..5cdac8b0 --- /dev/null +++ b/Zend/Gdata/Extension/When.php @@ -0,0 +1,169 @@ +_startTime = $startTime; + $this->_endTime = $endTime; + $this->_valueString = $valueString; + $this->_reminders = $reminders; + } + + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc, $majorVersion, $minorVersion); + if ($this->_startTime !== null) { + $element->setAttribute('startTime', $this->_startTime); + } + if ($this->_endTime !== null) { + $element->setAttribute('endTime', $this->_endTime); + } + if ($this->_valueString !== null) { + $element->setAttribute('valueString', $this->_valueString); + } + if ($this->_reminders !== null) { + foreach ($this->_reminders as $reminder) { + $element->appendChild( + $reminder->getDOM($element->ownerDocument)); + } + } + return $element; + } + + protected function takeChildFromDOM($child) + { + $absoluteNodeName = $child->namespaceURI . ':' . $child->localName; + switch ($absoluteNodeName) { + case $this->lookupNamespace('gd') . ':' . 'reminder'; + $reminder = new Zend_Gdata_Extension_Reminder(); + $reminder->transferFromDOM($child); + $this->_reminders[] = $reminder; + break; + default: + parent::takeChildFromDOM($child); + break; + } + } + + protected function takeAttributeFromDOM($attribute) + { + switch ($attribute->localName) { + case 'startTime': + $this->_startTime = $attribute->nodeValue; + break; + case 'endTime': + $this->_endTime = $attribute->nodeValue; + break; + case 'valueString': + $this->_valueString = $attribute->nodeValue; + break; + default: + parent::takeAttributeFromDOM($attribute); + } + } + + public function __toString() + { + if ($this->_valueString) + return $this->_valueString; + else { + return 'Starts: ' . $this->getStartTime() . ' ' . + 'Ends: ' . $this->getEndTime(); + } + } + + public function getStartTime() + { + return $this->_startTime; + } + + public function setStartTime($value) + { + $this->_startTime = $value; + return $this; + } + + public function getEndTime() + { + return $this->_endTime; + } + + public function setEndTime($value) + { + $this->_endTime = $value; + return $this; + } + + public function getValueString() + { + return $this->_valueString; + } + + public function setValueString($value) + { + $this->_valueString = $value; + return $this; + } + + public function getReminders() + { + return $this->_reminders; + } + + public function setReminders($value) + { + $this->_reminders = $value; + return $this; + } + +} diff --git a/Zend/Gdata/Extension/Where.php b/Zend/Gdata/Extension/Where.php new file mode 100644 index 00000000..cd36bc21 --- /dev/null +++ b/Zend/Gdata/Extension/Where.php @@ -0,0 +1,171 @@ +_valueString = $valueString; + $this->_label = $label; + $this->_rel = $rel; + $this->_entryLink = $entryLink; + } + + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc, $majorVersion, $minorVersion); + if ($this->_label !== null) { + $element->setAttribute('label', $this->_label); + } + if ($this->_rel !== null) { + $element->setAttribute('rel', $this->_rel); + } + if ($this->_valueString !== null) { + $element->setAttribute('valueString', $this->_valueString); + } + if ($this->entryLink !== null) { + $element->appendChild($this->_entryLink->getDOM($element->ownerDocument)); + } + return $element; + } + + protected function takeAttributeFromDOM($attribute) + { + switch ($attribute->localName) { + case 'label': + $this->_label = $attribute->nodeValue; + break; + case 'rel': + $this->_rel = $attribute->nodeValue; + break; + case 'valueString': + $this->_valueString = $attribute->nodeValue; + break; + default: + parent::takeAttributeFromDOM($attribute); + } + } + + /** + * Creates individual Entry objects of the appropriate type and + * stores them in the $_entry array based upon DOM data. + * + * @param DOMNode $child The DOMNode to process + */ + protected function takeChildFromDOM($child) + { + $absoluteNodeName = $child->namespaceURI . ':' . $child->localName; + switch ($absoluteNodeName) { + case $this->lookupNamespace('gd') . ':' . 'entryLink': + $entryLink = new Zend_Gdata_Extension_EntryLink(); + $entryLink->transferFromDOM($child); + $this->_entryLink = $entryLink; + break; + default: + parent::takeChildFromDOM($child); + break; + } + } + + public function __toString() + { + if ($this->_valueString != null) { + return $this->_valueString; + } + else { + return parent::__toString(); + } + } + + public function getLabel() + { + return $this->_label; + } + + public function setLabel($value) + { + $this->_label = $value; + return $this; + } + + public function getRel() + { + return $this->_rel; + } + + public function setRel($value) + { + $this->_rel = $value; + return $this; + } + + public function getValueString() + { + return $this->_valueString; + } + + public function setValueString($value) + { + $this->_valueString = $value; + return $this; + } + + public function getEntryLink() + { + return $this->_entryLink; + } + + public function setEntryLink($value) + { + $this->_entryLink = $value; + return $this; + } + +} diff --git a/Zend/Gdata/Extension/Who.php b/Zend/Gdata/Extension/Who.php new file mode 100644 index 00000000..d1477461 --- /dev/null +++ b/Zend/Gdata/Extension/Who.php @@ -0,0 +1,299 @@ +_email = $email; + $this->_rel = $rel; + $this->_valueString = $valueString; + $this->_attendeeStatus = $attendeeStatus; + $this->_attendeeType = $attendeeType; + $this->_entryLink = $entryLink; + } + + /** + * Retrieves a DOMElement which corresponds to this element and all + * child properties. This is used to build an entry back into a DOM + * and eventually XML text for sending to the server upon updates, or + * for application storage/persistence. + * + * @param DOMDocument $doc The DOMDocument used to construct DOMElements + * @return DOMElement The DOMElement representing this element and all + * child properties. + */ + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc, $majorVersion, $minorVersion); + if ($this->_email !== null) { + $element->setAttribute('email', $this->_email); + } + if ($this->_rel !== null) { + $element->setAttribute('rel', $this->_rel); + } + if ($this->_valueString !== null) { + $element->setAttribute('valueString', $this->_valueString); + } + if ($this->_attendeeStatus !== null) { + $element->appendChild($this->_attendeeStatus->getDOM($element->ownerDocument)); + } + if ($this->_attendeeType !== null) { + $element->appendChild($this->_attendeeType->getDOM($element->ownerDocument)); + } + if ($this->_entryLink !== null) { + $element->appendChild($this->_entryLink->getDOM($element->ownerDocument)); + } + return $element; + } + + /** + * Given a DOMNode representing an attribute, tries to map the data into + * instance members. If no mapping is defined, the name and value are + * stored in an array. + * + * @param DOMNode $attribute The DOMNode attribute needed to be handled + */ + protected function takeAttributeFromDOM($attribute) + { + switch ($attribute->localName) { + case 'email': + $this->_email = $attribute->nodeValue; + break; + case 'rel': + $this->_rel = $attribute->nodeValue; + break; + case 'valueString': + $this->_valueString = $attribute->nodeValue; + break; + default: + parent::takeAttributeFromDOM($attribute); + } + } + + /** + * Creates individual Entry objects of the appropriate type and + * stores them as members of this entry based upon DOM data. + * + * @param DOMNode $child The DOMNode to process + */ + protected function takeChildFromDOM($child) + { + $absoluteNodeName = $child->namespaceURI . ':' . $child->localName; + switch ($absoluteNodeName) { + case $this->lookupNamespace('gd') . ':' . 'attendeeStatus': + $attendeeStatus = new Zend_Gdata_Extension_AttendeeStatus(); + $attendeeStatus->transferFromDOM($child); + $this->_attendeeStatus = $attendeeStatus; + break; + case $this->lookupNamespace('gd') . ':' . 'attendeeType': + $attendeeType = new Zend_Gdata_Extension_AttendeeType(); + $attendeeType->transferFromDOM($child); + $this->_attendeeType = $attendeeType; + break; + case $this->lookupNamespace('gd') . ':' . 'entryLink': + $entryLink = new Zend_Gdata_Extension_EntryLink(); + $entryLink->transferFromDOM($child); + $this->_entryLink = $entryLink; + break; + default: + parent::takeChildFromDOM($child); + break; + } + } + + /** + * Retrieves a human readable string describing this attribute's value. + * + * @return string The attribute value. + */ + public function __toString() + { + if ($this->_valueString != null) { + return $this->_valueString; + } + else { + return parent::__toString(); + } + } + + /** + * Get the value for this element's ValueString attribute. + * + * @return string The requested attribute. + */ + public function getValueString() + { + return $this->_valueString; + } + + /** + * Set the value for this element's ValueString attribute. + * + * @param string $value The desired value for this attribute. + * @return Zend_Gdata_Extension_Who The element being modified. + */ + public function setValueString($value) + { + $this->_valueString = $value; + return $this; + } + + /** + * Get the value for this element's Email attribute. + * + * @return string The requested attribute. + */ + public function getEmail() + { + return $this->_email; + } + + /** + * Set the value for this element's Email attribute. + * + * @param string $value The desired value for this attribute. + * @return Zend_Gdata_Extension_Who The element being modified. + */ + public function setEmail($value) + { + $this->_email = $value; + return $this; + } + + /** + * Get the value for this element's Rel attribute. + * + * @return string The requested attribute. + */ + public function getRel() + { + return $this->_rel; + } + + /** + * Set the value for this element's Rel attribute. + * + * @param string $value The desired value for this attribute. + * @return Zend_Gdata_Extension_Who The element being modified. + */ + public function setRel($value) + { + $this->_rel = $value; + return $this; + } + + /** + * Get this entry's AttendeeStatus element. + * + * @return Zend_Gdata_Extension_AttendeeStatus The requested entry. + */ + public function getAttendeeStatus() + { + return $this->_attendeeStatus; + } + + /** + * Set the child's AttendeeStatus element. + * + * @param Zend_Gdata_Extension_AttendeeStatus $value The desired value for this attribute. + * @return Zend_Gdata_Extension_Who The element being modified. + */ + public function setAttendeeStatus($value) + { + $this->_attendeeStatus = $value; + return $this; + } + + /** + * Get this entry's AttendeeType element. + * + * @return Zend_Gdata_Extension_AttendeeType The requested entry. + */ + public function getAttendeeType() + { + return $this->_attendeeType; + } + + /** + * Set the child's AttendeeType element. + * + * @param Zend_Gdata_Extension_AttendeeType $value The desired value for this attribute. + * @return Zend_Gdata_Extension_Who The element being modified. + */ + public function setAttendeeType($value) + { + $this->_attendeeType = $value; + return $this; + } + +} diff --git a/Zend/Gdata/Feed.php b/Zend/Gdata/Feed.php new file mode 100644 index 00000000..c3e89224 --- /dev/null +++ b/Zend/Gdata/Feed.php @@ -0,0 +1,251 @@ +registerAllNamespaces(Zend_Gdata::$namespaces); + parent::__construct($element); + } + + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc, $majorVersion, $minorVersion); + if ($this->_totalResults != null) { + $element->appendChild($this->_totalResults->getDOM($element->ownerDocument)); + } + if ($this->_startIndex != null) { + $element->appendChild($this->_startIndex->getDOM($element->ownerDocument)); + } + if ($this->_itemsPerPage != null) { + $element->appendChild($this->_itemsPerPage->getDOM($element->ownerDocument)); + } + + // ETags are special. We only support them in protocol >= 2.X. + // This will be duplicated by the HTTP ETag header. + if ($majorVersion >= 2) { + if ($this->_etag != null) { + $element->setAttributeNS($this->lookupNamespace('gd'), + 'gd:etag', + $this->_etag); + } + } + + return $element; + } + + /** + * Creates individual Entry objects of the appropriate type and + * stores them in the $_entry array based upon DOM data. + * + * @param DOMNode $child The DOMNode to process + */ + protected function takeChildFromDOM($child) + { + $absoluteNodeName = $child->namespaceURI . ':' . $child->localName; + switch ($absoluteNodeName) { + case $this->lookupNamespace('openSearch') . ':' . 'totalResults': + $totalResults = new Zend_Gdata_Extension_OpenSearchTotalResults(); + $totalResults->transferFromDOM($child); + $this->_totalResults = $totalResults; + break; + case $this->lookupNamespace('openSearch') . ':' . 'startIndex': + $startIndex = new Zend_Gdata_Extension_OpenSearchStartIndex(); + $startIndex->transferFromDOM($child); + $this->_startIndex = $startIndex; + break; + case $this->lookupNamespace('openSearch') . ':' . 'itemsPerPage': + $itemsPerPage = new Zend_Gdata_Extension_OpenSearchItemsPerPage(); + $itemsPerPage->transferFromDOM($child); + $this->_itemsPerPage = $itemsPerPage; + break; + default: + parent::takeChildFromDOM($child); + break; + } + } + + /** + * Given a DOMNode representing an attribute, tries to map the data into + * instance members. If no mapping is defined, the name and value are + * stored in an array. + * + * @param DOMNode $attribute The DOMNode attribute needed to be handled + */ + protected function takeAttributeFromDOM($attribute) + { + switch ($attribute->localName) { + case 'etag': + // ETags are special, since they can be conveyed by either the + // HTTP ETag header or as an XML attribute. + $etag = $attribute->nodeValue; + if ($this->_etag === null) { + $this->_etag = $etag; + } + elseif ($this->_etag != $etag) { + require_once('Zend/Gdata/App/IOException.php'); + throw new Zend_Gdata_App_IOException("ETag mismatch"); + } + break; + default: + parent::takeAttributeFromDOM($attribute); + break; + } + } + + /** + * Set the value of the totalResults property. + * + * @param Zend_Gdata_Extension_OpenSearchTotalResults|null $value The + * value of the totalResults property. Use null to unset. + * @return Zend_Gdata_Feed Provides a fluent interface. + */ + function setTotalResults($value) { + $this->_totalResults = $value; + return $this; + } + + /** + * Get the value of the totalResults property. + * + * @return Zend_Gdata_Extension_OpenSearchTotalResults|null The value of + * the totalResults property, or null if unset. + */ + function getTotalResults() { + return $this->_totalResults; + } + + /** + * Set the start index property for feed paging. + * + * @param Zend_Gdata_Extension_OpenSearchStartIndex|null $value The value + * for the startIndex property. Use null to unset. + * @return Zend_Gdata_Feed Provides a fluent interface. + */ + function setStartIndex($value) { + $this->_startIndex = $value; + return $this; + } + + /** + * Get the value of the startIndex property. + * + * @return Zend_Gdata_Extension_OpenSearchStartIndex|null The value of the + * startIndex property, or null if unset. + */ + function getStartIndex() { + return $this->_startIndex; + } + + /** + * Set the itemsPerPage property. + * + * @param Zend_Gdata_Extension_OpenSearchItemsPerPage|null $value The + * value for the itemsPerPage property. Use nul to unset. + * @return Zend_Gdata_Feed Provides a fluent interface. + */ + function setItemsPerPage($value) { + $this->_itemsPerPage = $value; + return $this; + } + + /** + * Get the value of the itemsPerPage property. + * + * @return Zend_Gdata_Extension_OpenSearchItemsPerPage|null The value of + * the itemsPerPage property, or null if unset. + */ + function getItemsPerPage() { + return $this->_itemsPerPage; + } + +} diff --git a/Zend/Gdata/Gapps.php b/Zend/Gdata/Gapps.php new file mode 100644 index 00000000..410da5a1 --- /dev/null +++ b/Zend/Gdata/Gapps.php @@ -0,0 +1,1683 @@ +registerPackage('Zend_Gdata_Gapps'); + $this->registerPackage('Zend_Gdata_Gapps_Extension'); + parent::__construct($client, $applicationId); + $this->_httpClient->setParameterPost('service', self::AUTH_SERVICE_NAME); + $this->_domain = $domain; + } + + /** + * Convert an exception to an ServiceException if an AppsForYourDomain + * XML document is contained within the original exception's HTTP + * response. If conversion fails, throw the original error. + * + * @param Zend_Gdata_Exception $e The exception to convert. + * @throws Zend_Gdata_Gapps_ServiceException + * @throws mixed + */ + public static function throwServiceExceptionIfDetected($e) { + // Check to make sure that there actually response! + // This can happen if the connection dies before the request + // completes. (See ZF-5949) + $response = $e->getResponse(); + if (!$response) { + require_once('Zend/Gdata/App/IOException.php'); + throw new Zend_Gdata_App_IOException('No HTTP response received (possible connection failure)'); + } + + try { + // Check to see if there is an AppsForYourDomainErrors + // datastructure in the response. If so, convert it to + // an exception and throw it. + require_once 'Zend/Gdata/Gapps/ServiceException.php'; + $error = new Zend_Gdata_Gapps_ServiceException(); + $error->importFromString($response->getBody()); + throw $error; + } catch (Zend_Gdata_App_Exception $e2) { + // Unable to convert the response to a ServiceException, + // most likely because the server didn't return an + // AppsForYourDomainErrors document. Throw the original + // exception. + throw $e; + } + } + + /** + * Imports a feed located at $uri. + * This method overrides the default behavior of Zend_Gdata_App, + * providing support for Zend_Gdata_Gapps_ServiceException. + * + * @param string $uri + * @param Zend_Http_Client $client (optional) The client used for + * communication + * @param string $className (optional) The class which is used as the + * return type + * @throws Zend_Gdata_App_Exception + * @throws Zend_Gdata_App_HttpException + * @throws Zend_Gdata_Gapps_ServiceException + * @return Zend_Gdata_App_Feed + */ + public static function import($uri, $client = null, $className='Zend_Gdata_App_Feed') + { + try { + return parent::import($uri, $client, $className); + } catch (Zend_Gdata_App_HttpException $e) { + self::throwServiceExceptionIfDetected($e); + } + } + + /** + * GET a URI using client object. + * This method overrides the default behavior of Zend_Gdata_App, + * providing support for Zend_Gdata_Gapps_ServiceException. + * + * @param string $uri GET URI + * @param array $extraHeaders Extra headers to add to the request, as an + * array of string-based key/value pairs. + * @throws Zend_Gdata_App_HttpException + * @throws Zend_Gdata_Gapps_ServiceException + * @return Zend_Http_Response + */ + public function get($uri, $extraHeaders = array()) + { + try { + return parent::get($uri, $extraHeaders); + } catch (Zend_Gdata_App_HttpException $e) { + self::throwServiceExceptionIfDetected($e); + } + } + + /** + * POST data with client object. + * This method overrides the default behavior of Zend_Gdata_App, + * providing support for Zend_Gdata_Gapps_ServiceException. + * + * @param mixed $data The Zend_Gdata_App_Entry or XML to post + * @param string $uri (optional) POST URI + * @param integer $remainingRedirects (optional) + * @param string $contentType Content-type of the data + * @param array $extraHaders Extra headers to add tot he request + * @return Zend_Http_Response + * @throws Zend_Gdata_App_HttpException + * @throws Zend_Gdata_App_InvalidArgumentException + * @throws Zend_Gdata_Gapps_ServiceException + */ + public function post($data, $uri = null, $remainingRedirects = null, + $contentType = null, $extraHeaders = null) + { + try { + return parent::post($data, $uri, $remainingRedirects, $contentType, $extraHeaders); + } catch (Zend_Gdata_App_HttpException $e) { + self::throwServiceExceptionIfDetected($e); + } + } + + /** + * PUT data with client object + * This method overrides the default behavior of Zend_Gdata_App, + * providing support for Zend_Gdata_Gapps_ServiceException. + * + * @param mixed $data The Zend_Gdata_App_Entry or XML to post + * @param string $uri (optional) PUT URI + * @param integer $remainingRedirects (optional) + * @param string $contentType Content-type of the data + * @param array $extraHaders Extra headers to add tot he request + * @return Zend_Http_Response + * @throws Zend_Gdata_App_HttpException + * @throws Zend_Gdata_App_InvalidArgumentException + * @throws Zend_Gdata_Gapps_ServiceException + */ + public function put($data, $uri = null, $remainingRedirects = null, + $contentType = null, $extraHeaders = null) + { + try { + return parent::put($data, $uri, $remainingRedirects, $contentType, $extraHeaders); + } catch (Zend_Gdata_App_HttpException $e) { + self::throwServiceExceptionIfDetected($e); + } + } + + /** + * DELETE entry with client object + * This method overrides the default behavior of Zend_Gdata_App, + * providing support for Zend_Gdata_Gapps_ServiceException. + * + * @param mixed $data The Zend_Gdata_App_Entry or URL to delete + * @param integer $remainingRedirects (optional) + * @return void + * @throws Zend_Gdata_App_HttpException + * @throws Zend_Gdata_App_InvalidArgumentException + * @throws Zend_Gdata_Gapps_ServiceException + */ + public function delete($data, $remainingRedirects = null) + { + try { + return parent::delete($data, $remainingRedirects); + } catch (Zend_Gdata_App_HttpException $e) { + self::throwServiceExceptionIfDetected($e); + } + } + + /** + * Set domain for this service instance. This should be a fully qualified + * domain, such as 'foo.example.com'. + * + * This value is used when calculating URLs for retrieving and posting + * entries. If no value is specified, a URL will have to be manually + * constructed prior to using any methods which interact with the Google + * Apps provisioning service. + * + * @param string $value The domain to be used for this session. + */ + public function setDomain($value) + { + $this->_domain = $value; + } + + /** + * Get domain for this service instance. This should be a fully qualified + * domain, such as 'foo.example.com'. If no domain is set, null will be + * returned. + * + * @return string The domain to be used for this session, or null if not + * set. + */ + public function getDomain() + { + return $this->_domain; + } + + /** + * Returns the base URL used to access the Google Apps service, based + * on the current domain. The current domain can be temporarily + * overridden by providing a fully qualified domain as $domain. + * + * @param string $domain (optional) A fully-qualified domain to use + * instead of the default domain for this service instance. + * @throws Zend_Gdata_App_InvalidArgumentException + */ + public function getBaseUrl($domain = null) + { + if ($domain !== null) { + return self::APPS_BASE_FEED_URI . '/' . $domain; + } else if ($this->_domain !== null) { + return self::APPS_BASE_FEED_URI . '/' . $this->_domain; + } else { + require_once 'Zend/Gdata/App/InvalidArgumentException.php'; + throw new Zend_Gdata_App_InvalidArgumentException( + 'Domain must be specified.'); + } + } + + /** + * Retrieve a UserFeed containing multiple UserEntry objects. + * + * @param mixed $location (optional) The location for the feed, as a URL + * or Query. + * @return Zend_Gdata_Gapps_UserFeed + * @throws Zend_Gdata_App_Exception + * @throws Zend_Gdata_App_HttpException + * @throws Zend_Gdata_Gapps_ServiceException + */ + public function getUserFeed($location = null) + { + if ($location === null) { + $uri = $this->getBaseUrl() . self::APPS_USER_PATH; + } else if ($location instanceof Zend_Gdata_Query) { + $uri = $location->getQueryUrl(); + } else { + $uri = $location; + } + return parent::getFeed($uri, 'Zend_Gdata_Gapps_UserFeed'); + } + + /** + * Retreive NicknameFeed object containing multiple NicknameEntry objects. + * + * @param mixed $location (optional) The location for the feed, as a URL + * or Query. + * @return Zend_Gdata_Gapps_NicknameFeed + * @throws Zend_Gdata_App_Exception + * @throws Zend_Gdata_App_HttpException + * @throws Zend_Gdata_Gapps_ServiceException + */ + public function getNicknameFeed($location = null) + { + if ($location === null) { + $uri = $this->getBaseUrl() . self::APPS_NICKNAME_PATH; + } else if ($location instanceof Zend_Gdata_Query) { + $uri = $location->getQueryUrl(); + } else { + $uri = $location; + } + return parent::getFeed($uri, 'Zend_Gdata_Gapps_NicknameFeed'); + } + + /** + * Retreive GroupFeed object containing multiple GroupEntry + * objects. + * + * @param mixed $location (optional) The location for the feed, as a URL + * or Query. + * @return Zend_Gdata_Gapps_GroupFeed + * @throws Zend_Gdata_App_Exception + * @throws Zend_Gdata_App_HttpException + * @throws Zend_Gdata_Gapps_ServiceException + */ + public function getGroupFeed($location = null) + { + if ($location === null) { + $uri = self::APPS_BASE_FEED_URI . self::APPS_GROUP_PATH . '/'; + $uri .= $this->getDomain(); + } else if ($location instanceof Zend_Gdata_Query) { + $uri = $location->getQueryUrl(); + } else { + $uri = $location; + } + return parent::getFeed($uri, 'Zend_Gdata_Gapps_GroupFeed'); + } + + /** + * Retreive MemberFeed object containing multiple MemberEntry + * objects. + * + * @param mixed $location (optional) The location for the feed, as a URL + * or Query. + * @return Zend_Gdata_Gapps_MemberFeed + * @throws Zend_Gdata_App_Exception + * @throws Zend_Gdata_App_HttpException + * @throws Zend_Gdata_Gapps_ServiceException + */ + public function getMemberFeed($location = null) + { + if ($location === null) { + require_once 'Zend/Gdata/App/InvalidArgumentException.php'; + throw new Zend_Gdata_App_InvalidArgumentException( + 'Location must not be null'); + } else if ($location instanceof Zend_Gdata_Query) { + $uri = $location->getQueryUrl(); + } else { + $uri = $location; + } + return parent::getFeed($uri, 'Zend_Gdata_Gapps_MemberFeed'); + } + + /** + * Retreive OwnerFeed object containing multiple OwnerEntry + * objects. + * + * @param mixed $location (optional) The location for the feed, as a URL + * or Query. + * @return Zend_Gdata_Gapps_OwnerFeed + * @throws Zend_Gdata_App_Exception + * @throws Zend_Gdata_App_HttpException + * @throws Zend_Gdata_Gapps_ServiceException + */ + public function getOwnerFeed($location = null) + { + if ($location === null) { + require_once 'Zend/Gdata/App/InvalidArgumentException.php'; + throw new Zend_Gdata_App_InvalidArgumentException( + 'Location must not be null'); + } else if ($location instanceof Zend_Gdata_Query) { + $uri = $location->getQueryUrl(); + } else { + $uri = $location; + } + return parent::getFeed($uri, 'Zend_Gdata_Gapps_OwnerFeed'); + } + + /** + * Retreive EmailListFeed object containing multiple EmailListEntry + * objects. + * + * @param mixed $location (optional) The location for the feed, as a URL + * or Query. + * @return Zend_Gdata_Gapps_EmailListFeed + * @throws Zend_Gdata_App_Exception + * @throws Zend_Gdata_App_HttpException + * @throws Zend_Gdata_Gapps_ServiceException + */ + public function getEmailListFeed($location = null) + { + if ($location === null) { + $uri = $this->getBaseUrl() . self::APPS_NICKNAME_PATH; + } else if ($location instanceof Zend_Gdata_Query) { + $uri = $location->getQueryUrl(); + } else { + $uri = $location; + } + return parent::getFeed($uri, 'Zend_Gdata_Gapps_EmailListFeed'); + } + + /** + * Retreive EmailListRecipientFeed object containing multiple + * EmailListRecipientEntry objects. + * + * @param mixed $location The location for the feed, as a URL or Query. + * @return Zend_Gdata_Gapps_EmailListRecipientFeed + * @throws Zend_Gdata_App_Exception + * @throws Zend_Gdata_App_HttpException + * @throws Zend_Gdata_Gapps_ServiceException + */ + public function getEmailListRecipientFeed($location) + { + if ($location === null) { + require_once 'Zend/Gdata/App/InvalidArgumentException.php'; + throw new Zend_Gdata_App_InvalidArgumentException( + 'Location must not be null'); + } else if ($location instanceof Zend_Gdata_Query) { + $uri = $location->getQueryUrl(); + } else { + $uri = $location; + } + return parent::getFeed($uri, 'Zend_Gdata_Gapps_EmailListRecipientFeed'); + } + + /** + * Retreive a single UserEntry object. + * + * @param mixed $location The location for the feed, as a URL or Query. + * @return Zend_Gdata_Gapps_UserEntry + * @throws Zend_Gdata_App_Exception + * @throws Zend_Gdata_App_HttpException + * @throws Zend_Gdata_Gapps_ServiceException + */ + public function getUserEntry($location) + { + if ($location === null) { + require_once 'Zend/Gdata/App/InvalidArgumentException.php'; + throw new Zend_Gdata_App_InvalidArgumentException( + 'Location must not be null'); + } else if ($location instanceof Zend_Gdata_Query) { + $uri = $location->getQueryUrl(); + } else { + $uri = $location; + } + return parent::getEntry($uri, 'Zend_Gdata_Gapps_UserEntry'); + } + + /** + * Retreive a single NicknameEntry object. + * + * @param mixed $location The location for the feed, as a URL or Query. + * @return Zend_Gdata_Gapps_NicknameEntry + * @throws Zend_Gdata_App_Exception + * @throws Zend_Gdata_App_HttpException + * @throws Zend_Gdata_Gapps_ServiceException + */ + public function getNicknameEntry($location) + { + if ($location === null) { + require_once 'Zend/Gdata/App/InvalidArgumentException.php'; + throw new Zend_Gdata_App_InvalidArgumentException( + 'Location must not be null'); + } else if ($location instanceof Zend_Gdata_Query) { + $uri = $location->getQueryUrl(); + } else { + $uri = $location; + } + return parent::getEntry($uri, 'Zend_Gdata_Gapps_NicknameEntry'); + } + + /** + * Retreive a single GroupEntry object. + * + * @param mixed $location The location for the feed, as a URL or Query. + * @return Zend_Gdata_Gapps_GroupEntry + * @throws Zend_Gdata_App_Exception + * @throws Zend_Gdata_App_HttpException + * @throws Zend_Gdata_Gapps_ServiceException + */ + public function getGroupEntry($location = null) + { + if ($location === null) { + require_once 'Zend/Gdata/App/InvalidArgumentException.php'; + throw new Zend_Gdata_App_InvalidArgumentException( + 'Location must not be null'); + } else if ($location instanceof Zend_Gdata_Query) { + $uri = $location->getQueryUrl(); + } else { + $uri = $location; + } + return parent::getEntry($uri, 'Zend_Gdata_Gapps_GroupEntry'); + } + + /** + * Retreive a single MemberEntry object. + * + * @param mixed $location The location for the feed, as a URL or Query. + * @return Zend_Gdata_Gapps_MemberEntry + * @throws Zend_Gdata_App_Exception + * @throws Zend_Gdata_App_HttpException + * @throws Zend_Gdata_Gapps_ServiceException + */ + public function getMemberEntry($location = null) + { + if ($location === null) { + require_once 'Zend/Gdata/App/InvalidArgumentException.php'; + throw new Zend_Gdata_App_InvalidArgumentException( + 'Location must not be null'); + } else if ($location instanceof Zend_Gdata_Query) { + $uri = $location->getQueryUrl(); + } else { + $uri = $location; + } + return parent::getEntry($uri, 'Zend_Gdata_Gapps_MemberEntry'); + } + + /** + * Retreive a single OwnerEntry object. + * + * @param mixed $location The location for the feed, as a URL or Query. + * @return Zend_Gdata_Gapps_OwnerEntry + * @throws Zend_Gdata_App_Exception + * @throws Zend_Gdata_App_HttpException + * @throws Zend_Gdata_Gapps_ServiceException + */ + public function getOwnerEntry($location = null) + { + if ($location === null) { + require_once 'Zend/Gdata/App/InvalidArgumentException.php'; + throw new Zend_Gdata_App_InvalidArgumentException( + 'Location must not be null'); + } else if ($location instanceof Zend_Gdata_Query) { + $uri = $location->getQueryUrl(); + } else { + $uri = $location; + } + return parent::getEntry($uri, 'Zend_Gdata_Gapps_OwnerEntry'); + } + + /** + * Retreive a single EmailListEntry object. + * + * @param mixed $location The location for the feed, as a URL or Query. + * @return Zend_Gdata_Gapps_EmailListEntry + * @throws Zend_Gdata_App_Exception + * @throws Zend_Gdata_App_HttpException + * @throws Zend_Gdata_Gapps_ServiceException + */ + public function getEmailListEntry($location) + { + if ($location === null) { + require_once 'Zend/Gdata/App/InvalidArgumentException.php'; + throw new Zend_Gdata_App_InvalidArgumentException( + 'Location must not be null'); + } else if ($location instanceof Zend_Gdata_Query) { + $uri = $location->getQueryUrl(); + } else { + $uri = $location; + } + return parent::getEntry($uri, 'Zend_Gdata_Gapps_EmailListEntry'); + } + + /** + * Retreive a single EmailListRecipientEntry object. + * + * @param mixed $location The location for the feed, as a URL or Query. + * @return Zend_Gdata_Gapps_EmailListRecipientEntry + * @throws Zend_Gdata_App_Exception + * @throws Zend_Gdata_App_HttpException + * @throws Zend_Gdata_Gapps_ServiceException + */ + public function getEmailListRecipientEntry($location) + { + if ($location === null) { + require_once 'Zend/Gdata/App/InvalidArgumentException.php'; + throw new Zend_Gdata_App_InvalidArgumentException( + 'Location must not be null'); + } else if ($location instanceof Zend_Gdata_Query) { + $uri = $location->getQueryUrl(); + } else { + $uri = $location; + } + return parent::getEntry($uri, 'Zend_Gdata_Gapps_EmailListRecipientEntry'); + } + + /** + * Create a new user from a UserEntry. + * + * @param Zend_Gdata_Gapps_UserEntry $user The user entry to insert. + * @param string $uri (optional) The URI where the user should be + * uploaded to. If null, the default user creation URI for + * this domain will be used. + * @return Zend_Gdata_Gapps_UserEntry The inserted user entry as + * returned by the server. + * @throws Zend_Gdata_App_Exception + * @throws Zend_Gdata_App_HttpException + * @throws Zend_Gdata_Gapps_ServiceException + */ + public function insertUser($user, $uri = null) + { + if ($uri === null) { + $uri = $this->getBaseUrl() . self::APPS_USER_PATH; + } + $newEntry = $this->insertEntry($user, $uri, 'Zend_Gdata_Gapps_UserEntry'); + return $newEntry; + } + + /** + * Create a new nickname from a NicknameEntry. + * + * @param Zend_Gdata_Gapps_NicknameEntry $nickname The nickname entry to + * insert. + * @param string $uri (optional) The URI where the nickname should be + * uploaded to. If null, the default nickname creation URI for + * this domain will be used. + * @return Zend_Gdata_Gapps_NicknameEntry The inserted nickname entry as + * returned by the server. + * @throws Zend_Gdata_App_Exception + * @throws Zend_Gdata_App_HttpException + * @throws Zend_Gdata_Gapps_ServiceException + */ + public function insertNickname($nickname, $uri = null) + { + if ($uri === null) { + $uri = $this->getBaseUrl() . self::APPS_NICKNAME_PATH; + } + $newEntry = $this->insertEntry($nickname, $uri, 'Zend_Gdata_Gapps_NicknameEntry'); + return $newEntry; + } + + /** + * Create a new group from a GroupEntry. + * + * @param Zend_Gdata_Gapps_GroupEntry $group The group entry to insert. + * @param string $uri (optional) The URI where the group should be + * uploaded to. If null, the default user creation URI for + * this domain will be used. + * @return Zend_Gdata_Gapps_GroupEntry The inserted group entry as + * returned by the server. + * @throws Zend_Gdata_App_Exception + * @throws Zend_Gdata_App_HttpException + * @throws Zend_Gdata_Gapps_ServiceException + */ + public function insertGroup($group, $uri = null) + { + if ($uri === null) { + $uri = self::APPS_BASE_FEED_URI . self::APPS_GROUP_PATH . '/'; + $uri .= $this->getDomain(); + } + $newEntry = $this->insertEntry($group, $uri, 'Zend_Gdata_Gapps_GroupEntry'); + return $newEntry; + } + + /** + * Create a new member from a MemberEntry. + * + * @param Zend_Gdata_Gapps_MemberEntry $member The member entry to insert. + * @param string $uri (optional) The URI where the group should be + * uploaded to. If null, the default user creation URI for + * this domain will be used. + * @return Zend_Gdata_Gapps_MemberEntry The inserted member entry as + * returned by the server. + * @throws Zend_Gdata_App_Exception + * @throws Zend_Gdata_App_HttpException + * @throws Zend_Gdata_Gapps_ServiceException + */ + public function insertMember($member, $uri = null) + { + if ($uri === null) { + require_once 'Zend/Gdata/App/InvalidArgumentException.php'; + throw new Zend_Gdata_App_InvalidArgumentException( + 'URI must not be null'); + } + $newEntry = $this->insertEntry($member, $uri, 'Zend_Gdata_Gapps_MemberEntry'); + return $newEntry; + } + + /** + * Create a new group from a OwnerEntry. + * + * @param Zend_Gdata_Gapps_OwnerEntry $owner The owner entry to insert. + * @param string $uri (optional) The URI where the owner should be + * uploaded to. If null, the default user creation URI for + * this domain will be used. + * @return Zend_Gdata_Gapps_OwnerEntry The inserted owner entry as + * returned by the server. + * @throws Zend_Gdata_App_Exception + * @throws Zend_Gdata_App_HttpException + * @throws Zend_Gdata_Gapps_ServiceException + */ + public function insertOwner($owner, $uri = null) + { + if ($uri === null) { + require_once 'Zend/Gdata/App/InvalidArgumentException.php'; + throw new Zend_Gdata_App_InvalidArgumentException( + 'URI must not be null'); + } + $newEntry = $this->insertEntry($owner, $uri, 'Zend_Gdata_Gapps_OwnerEntry'); + return $newEntry; + } + + /** + * Create a new email list from an EmailListEntry. + * + * @param Zend_Gdata_Gapps_EmailListEntry $emailList The email list entry + * to insert. + * @param string $uri (optional) The URI where the email list should be + * uploaded to. If null, the default email list creation URI for + * this domain will be used. + * @return Zend_Gdata_Gapps_EmailListEntry The inserted email list entry + * as returned by the server. + * @throws Zend_Gdata_App_Exception + * @throws Zend_Gdata_App_HttpException + * @throws Zend_Gdata_Gapps_ServiceException + */ + public function insertEmailList($emailList, $uri = null) + { + if ($uri === null) { + $uri = $this->getBaseUrl() . self::APPS_EMAIL_LIST_PATH; + } + $newEntry = $this->insertEntry($emailList, $uri, 'Zend_Gdata_Gapps_EmailListEntry'); + return $newEntry; + } + + /** + * Create a new email list recipient from an EmailListRecipientEntry. + * + * @param Zend_Gdata_Gapps_EmailListRecipientEntry $recipient The recipient + * entry to insert. + * @param string $uri (optional) The URI where the recipient should be + * uploaded to. If null, the default recipient creation URI for + * this domain will be used. + * @return Zend_Gdata_Gapps_EmailListRecipientEntry The inserted + * recipient entry as returned by the server. + * @throws Zend_Gdata_App_Exception + * @throws Zend_Gdata_App_HttpException + * @throws Zend_Gdata_Gapps_ServiceException + */ + public function insertEmailListRecipient($recipient, $uri = null) + { + if ($uri === null) { + require_once 'Zend/Gdata/App/InvalidArgumentException.php'; + throw new Zend_Gdata_App_InvalidArgumentException( + 'URI must not be null'); + } elseif ($uri instanceof Zend_Gdata_Gapps_EmailListEntry) { + $uri = $uri->getLink('edit')->href; + } + $newEntry = $this->insertEntry($recipient, $uri, 'Zend_Gdata_Gapps_EmailListRecipientEntry'); + return $newEntry; + } + + /** + * Provides a magic factory method to instantiate new objects with + * shorter syntax than would otherwise be required by the Zend Framework + * naming conventions. For more information, see Zend_Gdata_App::__call(). + * + * This overrides the default behavior of __call() so that query classes + * do not need to have their domain manually set when created with + * a magic factory method. + * + * @see Zend_Gdata_App::__call() + * @param string $method The method name being called + * @param array $args The arguments passed to the call + * @throws Zend_Gdata_App_Exception + */ + public function __call($method, $args) { + if (preg_match('/^new(\w+Query)/', $method, $matches)) { + $class = $matches[1]; + $foundClassName = null; + foreach ($this->_registeredPackages as $name) { + try { + // Autoloading disabled on next line for compatibility + // with magic factories. See ZF-6660. + if (!class_exists($name . '_' . $class, false)) { + require_once 'Zend/Loader.php'; + @Zend_Loader::loadClass($name . '_' . $class); + } + $foundClassName = $name . '_' . $class; + break; + } catch (Zend_Exception $e) { + // package wasn't here- continue searching + } + } + if ($foundClassName != null) { + $reflectionObj = new ReflectionClass($foundClassName); + // Prepend the domain to the query + $args = array_merge(array($this->getDomain()), $args); + return $reflectionObj->newInstanceArgs($args); + } else { + require_once 'Zend/Gdata/App/Exception.php'; + throw new Zend_Gdata_App_Exception( + "Unable to find '${class}' in registered packages"); + } + } else { + return parent::__call($method, $args); + } + + } + + // Convenience methods + // Specified at http://code.google.com/apis/apps/gdata_provisioning_api_v2.0_reference.html#appendix_e + + /** + * Create a new user entry and send it to the Google Apps servers. + * + * @param string $username The username for the new user. + * @param string $givenName The given name for the new user. + * @param string $familyName The family name for the new user. + * @param string $password The password for the new user as a plaintext string + * (if $passwordHashFunction is null) or a SHA-1 hashed + * value (if $passwordHashFunction = 'SHA-1'). + * @param string $quotaLimitInMB (optional) The quota limit for the new user in MB. + * @return Zend_Gdata_Gapps_UserEntry (optional) The new user entry as returned by + * server. + * @throws Zend_Gdata_App_Exception + * @throws Zend_Gdata_App_HttpException + * @throws Zend_Gdata_Gapps_ServiceException + */ + public function createUser ($username, $givenName, $familyName, $password, + $passwordHashFunction = null, $quotaLimitInMB = null) { + $user = $this->newUserEntry(); + $user->login = $this->newLogin(); + $user->login->username = $username; + $user->login->password = $password; + $user->login->hashFunctionName = $passwordHashFunction; + $user->name = $this->newName(); + $user->name->givenName = $givenName; + $user->name->familyName = $familyName; + if ($quotaLimitInMB !== null) { + $user->quota = $this->newQuota(); + $user->quota->limit = $quotaLimitInMB; + } + return $this->insertUser($user); + } + + /** + * Retrieve a user based on their username. + * + * @param string $username The username to search for. + * @return Zend_Gdata_Gapps_UserEntry The username to search for, or null + * if no match found. + * @throws Zend_Gdata_App_InvalidArgumentException + * @throws Zend_Gdata_App_HttpException + */ + public function retrieveUser ($username) { + $query = $this->newUserQuery($username); + try { + $user = $this->getUserEntry($query); + } catch (Zend_Gdata_Gapps_ServiceException $e) { + // Set the user to null if not found + if ($e->hasError(Zend_Gdata_Gapps_Error::ENTITY_DOES_NOT_EXIST)) { + $user = null; + } else { + throw $e; + } + } + return $user; + } + + /** + * Retrieve a page of users in alphabetical order, starting with the + * provided username. + * + * @param string $startUsername (optional) The first username to retrieve. + * If null or not declared, the page will begin with the first + * user in the domain. + * @return Zend_Gdata_Gapps_UserFeed Collection of Zend_Gdata_UserEntry + * objects representing all users in the domain. + * @throws Zend_Gdata_App_Exception + * @throws Zend_Gdata_App_HttpException + * @throws Zend_Gdata_Gapps_ServiceException + */ + public function retrievePageOfUsers ($startUsername = null) { + $query = $this->newUserQuery(); + $query->setStartUsername($startUsername); + return $this->getUserFeed($query); + } + + /** + * Retrieve all users in the current domain. Be aware that + * calling this function on a domain with many users will take a + * signifigant amount of time to complete. On larger domains this may + * may cause execution to timeout without proper precautions in place. + * + * @return Zend_Gdata_Gapps_UserFeed Collection of Zend_Gdata_UserEntry + * objects representing all users in the domain. + * @throws Zend_Gdata_App_Exception + * @throws Zend_Gdata_App_HttpException + * @throws Zend_Gdata_Gapps_ServiceException + */ + public function retrieveAllUsers () { + return $this->retrieveAllEntriesForFeed($this->retrievePageOfUsers()); + } + + /** + * Overwrite a specified username with the provided UserEntry. The + * UserEntry does not need to contain an edit link. + * + * This method is provided for compliance with the Google Apps + * Provisioning API specification. Normally users will instead want to + * call UserEntry::save() instead. + * + * @see Zend_Gdata_App_Entry::save + * @param string $username The username whose data will be overwritten. + * @param Zend_Gdata_Gapps_UserEntry $userEntry The user entry which + * will be overwritten. + * @return Zend_Gdata_Gapps_UserEntry The UserEntry returned by the + * server. + * @throws Zend_Gdata_App_Exception + * @throws Zend_Gdata_App_HttpException + * @throws Zend_Gdata_Gapps_ServiceException + */ + public function updateUser($username, $userEntry) { + return $this->updateEntry($userEntry, $this->getBaseUrl() . + self::APPS_USER_PATH . '/' . $username); + } + + /** + * Mark a given user as suspended. + * + * @param string $username The username associated with the user who + * should be suspended. + * @return Zend_Gdata_Gapps_UserEntry The UserEntry for the modified + * user. + * @throws Zend_Gdata_App_Exception + * @throws Zend_Gdata_App_HttpException + * @throws Zend_Gdata_Gapps_ServiceException + */ + public function suspendUser($username) { + $user = $this->retrieveUser($username); + $user->login->suspended = true; + return $user->save(); + } + + /** + * Mark a given user as not suspended. + * + * @param string $username The username associated with the user who + * should be restored. + * @return Zend_Gdata_Gapps_UserEntry The UserEntry for the modified + * user. + * @throws Zend_Gdata_App_Exception + * @throws Zend_Gdata_App_HttpException + * @throws Zend_Gdata_Gapps_ServiceException + */ + public function restoreUser($username) { + $user = $this->retrieveUser($username); + $user->login->suspended = false; + return $user->save(); + } + + /** + * Delete a user by username. + * + * @param string $username The username associated with the user who + * should be deleted. + * @throws Zend_Gdata_App_Exception + * @throws Zend_Gdata_App_HttpException + * @throws Zend_Gdata_Gapps_ServiceException + */ + public function deleteUser($username) { + $this->delete($this->getBaseUrl() . self::APPS_USER_PATH . '/' . + $username); + } + + /** + * Create a nickname for a given user. + * + * @param string $username The username to which the new nickname should + * be associated. + * @param string $nickname The new nickname to be created. + * @return Zend_Gdata_Gapps_NicknameEntry The nickname entry which was + * created by the server. + * @throws Zend_Gdata_App_Exception + * @throws Zend_Gdata_App_HttpException + * @throws Zend_Gdata_Gapps_ServiceException + */ + public function createNickname($username, $nickname) { + $entry = $this->newNicknameEntry(); + $nickname = $this->newNickname($nickname); + $login = $this->newLogin($username); + $entry->nickname = $nickname; + $entry->login = $login; + return $this->insertNickname($entry); + } + + /** + * Retrieve the entry for a specified nickname. + * + * @param string $nickname The nickname to be retrieved. + * @return Zend_Gdata_Gapps_NicknameEntry The requested nickname entry. + * @throws Zend_Gdata_App_Exception + * @throws Zend_Gdata_App_HttpException + * @throws Zend_Gdata_Gapps_ServiceException + */ + public function retrieveNickname($nickname) { + $query = $this->newNicknameQuery(); + $query->setNickname($nickname); + try { + $nickname = $this->getNicknameEntry($query); + } catch (Zend_Gdata_Gapps_ServiceException $e) { + // Set the nickname to null if not found + if ($e->hasError(Zend_Gdata_Gapps_Error::ENTITY_DOES_NOT_EXIST)) { + $nickname = null; + } else { + throw $e; + } + } + return $nickname; + } + + /** + * Retrieve all nicknames associated with a specific username. + * + * @param string $username The username whose nicknames should be + * returned. + * @return Zend_Gdata_Gapps_NicknameFeed A feed containing all nicknames + * for the given user, or null if + * @throws Zend_Gdata_App_Exception + * @throws Zend_Gdata_App_HttpException + * @throws Zend_Gdata_Gapps_ServiceException + */ + public function retrieveNicknames($username) { + $query = $this->newNicknameQuery(); + $query->setUsername($username); + $nicknameFeed = $this->retrieveAllEntriesForFeed( + $this->getNicknameFeed($query)); + return $nicknameFeed; + } + + /** + * Retrieve a page of nicknames in alphabetical order, starting with the + * provided nickname. + * + * @param string $startNickname (optional) The first nickname to + * retrieve. If null or not declared, the page will begin with + * the first nickname in the domain. + * @return Zend_Gdata_Gapps_NicknameFeed Collection of Zend_Gdata_NicknameEntry + * objects representing all nicknames in the domain. + * @throws Zend_Gdata_App_Exception + * @throws Zend_Gdata_App_HttpException + * @throws Zend_Gdata_Gapps_ServiceException + */ + public function retrievePageOfNicknames ($startNickname = null) { + $query = $this->newNicknameQuery(); + $query->setStartNickname($startNickname); + return $this->getNicknameFeed($query); + } + + /** + * Retrieve all nicknames in the current domain. Be aware that + * calling this function on a domain with many nicknames will take a + * signifigant amount of time to complete. On larger domains this may + * may cause execution to timeout without proper precautions in place. + * + * @return Zend_Gdata_Gapps_NicknameFeed Collection of Zend_Gdata_NicknameEntry + * objects representing all nicknames in the domain. + * @throws Zend_Gdata_App_Exception + * @throws Zend_Gdata_App_HttpException + * @throws Zend_Gdata_Gapps_ServiceException + */ + public function retrieveAllNicknames () { + return $this->retrieveAllEntriesForFeed($this->retrievePageOfNicknames()); + } + + /** + * Delete a specified nickname. + * + * @param string $nickname The name of the nickname to be deleted. + * @throws Zend_Gdata_App_Exception + * @throws Zend_Gdata_App_HttpException + * @throws Zend_Gdata_Gapps_ServiceException + */ + public function deleteNickname($nickname) { + $this->delete($this->getBaseUrl() . self::APPS_NICKNAME_PATH . '/' . $nickname); + } + + /** + * Create a new group. + * + * @param string $groupId A unique identifier for the group + * @param string $groupName The name of the group + * @param string $description A description of the group + * @param string $emailPermission The subscription permission of the group + * @return Zend_Gdata_Gapps_GroupEntry The group entry as created on the server. + */ + public function createGroup($groupId, $groupName, $description = null, $emailPermission = null) + { + $i = 0; + $group = $this->newGroupEntry(); + + $properties[$i] = $this->newProperty(); + $properties[$i]->name = 'groupId'; + $properties[$i]->value = $groupId; + $i++; + $properties[$i] = $this->newProperty(); + $properties[$i]->name = 'groupName'; + $properties[$i]->value = $groupName; + $i++; + + if($description != null) { + $properties[$i] = $this->newProperty(); + $properties[$i]->name = 'description'; + $properties[$i]->value = $description; + $i++; + } + + if($emailPermission != null) { + $properties[$i] = $this->newProperty(); + $properties[$i]->name = 'emailPermission'; + $properties[$i]->value = $emailPermission; + $i++; + } + + $group->property = $properties; + + return $this->insertGroup($group); + } + + /** + * Retrieves a group based on group id + * + * @param string $groupId The unique identifier for the group + * @return Zend_Gdata_Gapps_GroupEntry The group entry as returned by the server. + */ + public function retrieveGroup($groupId) + { + $query = $this->newGroupQuery($groupId); + //$query->setGroupId($groupId); + + try { + $group = $this->getGroupEntry($query); + } catch (Zend_Gdata_Gapps_ServiceException $e) { + // Set the group to null if not found + if ($e->hasError(Zend_Gdata_Gapps_Error::ENTITY_DOES_NOT_EXIST)) { + $group = null; + } else { + throw $e; + } + } + return $group; + } + + /** + * Retrieve all groups in the current domain. Be aware that + * calling this function on a domain with many groups will take a + * signifigant amount of time to complete. On larger domains this may + * may cause execution to timeout without proper precautions in place. + * + * @return Zend_Gdata_Gapps_GroupFeed Collection of Zend_Gdata_GroupEntry objects + * representing all groups apart of the domain. + */ + public function retrieveAllGroups() + { + return $this->retrieveAllEntriesForFeed($this->retrievePageOfGroups()); + } + + /** + * Delete a group + * + * @param string $groupId The unique identifier for the group + */ + public function deleteGroup($groupId) + { + $uri = self::APPS_BASE_FEED_URI . self::APPS_GROUP_PATH . '/'; + $uri .= $this->getDomain() . '/' . $groupId; + + $this->delete($uri); + } + + /** + * Check to see if a member id or group id is a member of group + * + * @param string $memberId Member id or group group id + * @param string $groupId Group to be checked for + * @return bool True, if given entity is a member + */ + public function isMember($memberId, $groupId) + { + $uri = self::APPS_BASE_FEED_URI . self::APPS_GROUP_PATH . '/'; + $uri .= $this->getDomain() . '/' . $groupId . '/member/' . $memberId; + + //if the enitiy is not a member, an exception is thrown + try { + $results = $this->get($uri); + } catch (Exception $e) { + $results = false; + } + + if($results) { + return TRUE; + } else { + return FALSE; + } + } + + /** + * Add an email address to a group as a member + * + * @param string $recipientAddress Email address, member id, or group id + * @param string $groupId The unique id of the group + * @return Zend_Gdata_Gapps_MemberEntry The member entry returned by the server + */ + public function addMemberToGroup($recipientAddress, $groupId) + { + $member = $this->newMemberEntry(); + + $properties[] = $this->newProperty(); + $properties[0]->name = 'memberId'; + $properties[0]->value = $recipientAddress; + + $member->property = $properties; + + $uri = self::APPS_BASE_FEED_URI . self::APPS_GROUP_PATH . '/'; + $uri .= $this->getDomain() . '/' . $groupId . '/member'; + + return $this->insertMember($member, $uri); + } + + /** + * Remove a member id from a group + * + * @param string $memberId Member id or group id + * @param string $groupId The unique id of the group + */ + public function removeMemberFromGroup($memberId, $groupId) + { + $uri = self::APPS_BASE_FEED_URI . self::APPS_GROUP_PATH . '/'; + $uri .= $this->getDomain() . '/' . $groupId . '/member/' . $memberId; + + return $this->delete($uri); + } + + /** + * Retrieves all the members of a group + * + * @param string $groupId The unique id of the group + * @return Zend_Gdata_Gapps_MemberFeed Collection of MemberEntry objects + * representing all members apart of the group. + */ + public function retrieveAllMembers($groupId) + { + return $this->retrieveAllEntriesForFeed( + $this->retrievePageOfMembers($groupId)); + } + + /** + * Add an email as an owner of a group + * + * @param string $email Owner's email + * @param string $groupId Group ownership to be checked for + * @return Zend_Gdata_Gapps_OwnerEntry The OwnerEntry returned by the server + */ + public function addOwnerToGroup($email, $groupId) + { + $owner = $this->newOwnerEntry(); + + $properties[] = $this->newProperty(); + $properties[0]->name = 'email'; + $properties[0]->value = $email; + + $owner->property = $properties; + + $uri = self::APPS_BASE_FEED_URI . self::APPS_GROUP_PATH . '/'; + $uri .= $this->getDomain() . '/' . $groupId . '/owner'; + + return $this->insertOwner($owner, $uri); + } + + /** + * Retrieves all the owners of a group + * + * @param string $groupId The unique identifier for the group + * @return Zend_Gdata_Gapps_OwnerFeed Collection of Zend_Gdata_OwnerEntry + * objects representing all owners apart of the group. + */ + public function retrieveGroupOwners($groupId) + { + $uri = self::APPS_BASE_FEED_URI . self::APPS_GROUP_PATH . '/'; + $uri .= $this->getDomain() . '/' . $groupId . '/owner'; + + return $this->getOwnerFeed($uri); + } + + /** + * Checks to see if an email is an owner of a group + * + * @param string $email Owner's email + * @param string $groupId Group ownership to be checked for + * @return bool True, if given entity is an owner + */ + public function isOwner($email, $groupId) + { + $uri = self::APPS_BASE_FEED_URI . self::APPS_GROUP_PATH . '/'; + $uri .= $this->getDomain() . '/' . $groupId . '/owner/' . $email; + + //if the enitiy is not an owner of the group, an exception is thrown + try { + $results = $this->get($uri); + } catch (Exception $e) { + $results = false; + } + + if($results) { + return TRUE; + } else { + return FALSE; + } + } + + /** + * Remove email as an owner of a group + * + * @param string $email Owner's email + * @param string $groupId The unique identifier for the group + */ + public function removeOwnerFromGroup($email, $groupId) + { + $uri = self::APPS_BASE_FEED_URI . self::APPS_GROUP_PATH . '/'; + $uri .= $this->getDomain() . '/' . $groupId . '/owner/' . $email; + + return $this->delete($uri); + } + + /** + * Update group properties with new values. any property not defined will not + * be updated + * + * @param string $groupId A unique identifier for the group + * @param string $groupName The name of the group + * @param string $description A description of the group + * @param string $emailPermission The subscription permission of the group + * @return Zend_Gdata_Gapps_GroupEntry The group entry as updated on the server. + */ + public function updateGroup($groupId, $groupName = null, $description = null, + $emailPermission = null) + { + $i = 0; + $group = $this->newGroupEntry(); + + $properties[$i] = $this->newProperty(); + $properties[$i]->name = 'groupId'; + $properties[$i]->value = $groupId; + $i++; + + if($groupName != null) { + $properties[$i] = $this->newProperty(); + $properties[$i]->name = 'groupName'; + $properties[$i]->value = $groupName; + $i++; + } + + if($description != null) { + $properties[$i] = $this->newProperty(); + $properties[$i]->name = 'description'; + $properties[$i]->value = $description; + $i++; + } + + if($emailPermission != null) { + $properties[$i] = $this->newProperty(); + $properties[$i]->name = 'emailPermission'; + $properties[$i]->value = $emailPermission; + $i++; + } + + $group->property = $properties; + + $uri = self::APPS_BASE_FEED_URI . self::APPS_GROUP_PATH . '/'; + $uri .= $this->getDomain() . '/' . $groupId; + + return $this->updateEntry($group, $uri, 'Zend_Gdata_Gapps_GroupEntry'); + } + + /** + * Retrieve all of the groups that a user is a member of + * + * @param string $memberId Member username + * @param bool $directOnly (Optional) If true, members with direct association + * only will be considered + * @return Zend_Gdata_Gapps_GroupFeed Collection of Zend_Gdata_GroupEntry + * objects representing all groups member is apart of in the domain. + */ + public function retrieveGroups($memberId, $directOnly = null) + { + $query = $this->newGroupQuery(); + $query->setMember($memberId); + if($directOnly != null) { + $query->setDirectOnly($directOnly); + } + return $this->getGroupFeed($query); + } + + /** + * Retrieve a page of groups in alphabetical order, starting with the + * provided group. + * + * @param string $startGroup (optional) The first group to + * retrieve. If null or not defined, the page will begin + * with the first group in the domain. + * @return Zend_Gdata_Gapps_GroupFeed Collection of Zend_Gdata_GroupEntry + * objects representing the groups in the domain. + * @throws Zend_Gdata_App_Exception + * @throws Zend_Gdata_App_HttpException + * @throws Zend_Gdata_Gapps_ServiceException + */ + public function retrievePageOfGroups ($startGroup = null) + { + $query = $this->newGroupQuery(); + $query->setStartGroupId($startGroup); + return $this->getGroupFeed($query); + } + + /** + * Gets page of Members + * + * @param string $groupId The group id which should be searched. + * @param string $startMember (optinal) The address of the first member, + * or null to start with the first member in the list. + * @return Zend_Gdata_Gapps_MemberFeed Collection of Zend_Gdata_MemberEntry + * objects + */ + public function retrievePageOfMembers($groupId, $startMember = null) + { + $query = $this->newMemberQuery($groupId); + $query->setStartMemberId($startMember); + return $this->getMemberFeed($query); + } + + /** + * Create a new email list. + * + * @param string $emailList The name of the email list to be created. + * @return Zend_Gdata_Gapps_EmailListEntry The email list entry + * as created on the server. + * @throws Zend_Gdata_App_Exception + * @throws Zend_Gdata_App_HttpException + * @throws Zend_Gdata_Gapps_ServiceException + */ + public function createEmailList($emailList) { + $entry = $this->newEmailListEntry(); + $list = $this->newEmailList(); + $list->name = $emailList; + $entry->emailList = $list; + return $this->insertEmailList($entry); + } + + /** + * Retrieve all email lists associated with a recipient. + * + * @param string $username The recipient whose associated email lists + * should be returned. + * @return Zend_Gdata_Gapps_EmailListFeed The list of email lists found as + * Zend_Gdata_EmailListEntry objects. + * @throws Zend_Gdata_App_Exception + * @throws Zend_Gdata_App_HttpException + * @throws Zend_Gdata_Gapps_ServiceException + */ + public function retrieveEmailLists($recipient) { + $query = $this->newEmailListQuery(); + $query->recipient = $recipient; + return $this->getEmailListFeed($query); + } + + /** + * Retrieve a page of email lists in alphabetical order, starting with the + * provided email list. + * + * @param string $startEmailListName (optional) The first list to + * retrieve. If null or not defined, the page will begin + * with the first email list in the domain. + * @return Zend_Gdata_Gapps_EmailListFeed Collection of Zend_Gdata_EmailListEntry + * objects representing all nicknames in the domain. + * @throws Zend_Gdata_App_Exception + * @throws Zend_Gdata_App_HttpException + * @throws Zend_Gdata_Gapps_ServiceException + */ + public function retrievePageOfEmailLists ($startNickname = null) { + $query = $this->newEmailListQuery(); + $query->setStartEmailListName($startNickname); + return $this->getEmailListFeed($query); + } + + /** + * Retrieve all email lists associated with the curent domain. Be aware that + * calling this function on a domain with many email lists will take a + * signifigant amount of time to complete. On larger domains this may + * may cause execution to timeout without proper precautions in place. + * + * @return Zend_Gdata_Gapps_EmailListFeed The list of email lists found + * as Zend_Gdata_Gapps_EmailListEntry objects. + * @throws Zend_Gdata_App_Exception + * @throws Zend_Gdata_App_HttpException + * @throws Zend_Gdata_Gapps_ServiceException + */ + public function retrieveAllEmailLists() { + return $this->retrieveAllEntriesForFeed($this->retrievePageOfEmailLists()); + } + + /** + * Delete a specified email list. + * + * @param string $emailList The name of the emailList to be deleted. + * @throws Zend_Gdata_App_Exception + * @throws Zend_Gdata_App_HttpException + * @throws Zend_Gdata_Gapps_ServiceException + */ + public function deleteEmailList($emailList) { + $this->delete($this->getBaseUrl() . self::APPS_EMAIL_LIST_PATH . '/' + . $emailList); + } + + /** + * Add a specified recipient to an existing emailList. + * + * @param string $recipientAddress The address of the recipient to be + * added to the email list. + * @param string $emailList The name of the email address to which the + * recipient should be added. + * @return Zend_Gdata_Gapps_EmailListRecipientEntry The recipient entry + * created by the server. + * @throws Zend_Gdata_App_Exception + * @throws Zend_Gdata_App_HttpException + * @throws Zend_Gdata_Gapps_ServiceException + */ + public function addRecipientToEmailList($recipientAddress, $emailList) { + $entry = $this->newEmailListRecipientEntry(); + $who = $this->newWho(); + $who->email = $recipientAddress; + $entry->who = $who; + $address = $this->getBaseUrl() . self::APPS_EMAIL_LIST_PATH . '/' . + $emailList . self::APPS_EMAIL_LIST_RECIPIENT_POSTFIX . '/'; + return $this->insertEmailListRecipient($entry, $address); + } + + /** + * Retrieve a page of email list recipients in alphabetical order, + * starting with the provided email list recipient. + * + * @param string $emaiList The email list which should be searched. + * @param string $startRecipient (optinal) The address of the first + * recipient, or null to start with the first recipient in + * the list. + * @return Zend_Gdata_Gapps_EmailListRecipientFeed Collection of + * Zend_Gdata_EmailListRecipientEntry objects representing all + * recpients in the specified list. + * @throws Zend_Gdata_App_Exception + * @throws Zend_Gdata_App_HttpException + * @throws Zend_Gdata_Gapps_ServiceException + */ + public function retrievePageOfRecipients ($emailList, + $startRecipient = null) { + $query = $this->newEmailListRecipientQuery(); + $query->setEmailListName($emailList); + $query->setStartRecipient($startRecipient); + return $this->getEmailListRecipientFeed($query); + } + + /** + * Retrieve all recipients associated with an email list. Be aware that + * calling this function on a domain with many email lists will take a + * signifigant amount of time to complete. On larger domains this may + * may cause execution to timeout without proper precautions in place. + * + * @param string $emaiList The email list which should be searched. + * @return Zend_Gdata_Gapps_EmailListRecipientFeed The list of email lists + * found as Zend_Gdata_Gapps_EmailListRecipientEntry objects. + * @throws Zend_Gdata_App_Exception + * @throws Zend_Gdata_App_HttpException + * @throws Zend_Gdata_Gapps_ServiceException + */ + public function retrieveAllRecipients($emailList) { + return $this->retrieveAllEntriesForFeed( + $this->retrievePageOfRecipients($emailList)); + } + + /** + * Remove a specified recipient from an email list. + * + * @param string $recipientAddress The recipient to be removed. + * @param string $emailList The list from which the recipient should + * be removed. + * @throws Zend_Gdata_App_Exception + * @throws Zend_Gdata_App_HttpException + * @throws Zend_Gdata_Gapps_ServiceException + */ + public function removeRecipientFromEmailList($recipientAddress, $emailList) { + $this->delete($this->getBaseUrl() . self::APPS_EMAIL_LIST_PATH . '/' + . $emailList . self::APPS_EMAIL_LIST_RECIPIENT_POSTFIX . '/' + . $recipientAddress); + } + +} diff --git a/Zend/Gdata/Gapps/EmailListEntry.php b/Zend/Gdata/Gapps/EmailListEntry.php new file mode 100644 index 00000000..52bbab93 --- /dev/null +++ b/Zend/Gdata/Gapps/EmailListEntry.php @@ -0,0 +1,214 @@ + in the Google Data protocol. + * + * @category Zend + * @package Zend_Gdata + * @subpackage Gapps + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +class Zend_Gdata_Gapps_EmailListEntry extends Zend_Gdata_Entry +{ + + protected $_entryClassName = 'Zend_Gdata_Gapps_EmailListEntry'; + + /** + * child element containing general information about + * this email list. + * + * @var Zend_Gdata_Gapps_Extension_EmailList + */ + protected $_emailList = null; + + /** + * element containing information about other feeds + * relevant to this entry. + * + * @var Zend_Gdata_Extension_FeedLink + */ + protected $_feedLink = array(); + + /** + * Create a new instance. + * + * @param DOMElement $element (optional) DOMElement from which this + * object should be constructed. + */ + public function __construct($element = null) + { + $this->registerAllNamespaces(Zend_Gdata_Gapps::$namespaces); + parent::__construct($element); + } + + /** + * Retrieves a DOMElement which corresponds to this element and all + * child properties. This is used to build an entry back into a DOM + * and eventually XML text for application storage/persistence. + * + * @param DOMDocument $doc The DOMDocument used to construct DOMElements + * @return DOMElement The DOMElement representing this element and all + * child properties. + */ + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc, $majorVersion, $minorVersion); + if ($this->_emailList !== null) { + $element->appendChild($this->_emailList->getDOM($element->ownerDocument)); + } + foreach ($this->_feedLink as $feedLink) { + $element->appendChild($feedLink->getDOM($element->ownerDocument)); + } + return $element; + } + + /** + * Creates individual Entry objects of the appropriate type and + * stores them as members of this entry based upon DOM data. + * + * @param DOMNode $child The DOMNode to process + */ + protected function takeChildFromDOM($child) + { + $absoluteNodeName = $child->namespaceURI . ':' . $child->localName; + + switch ($absoluteNodeName) { + case $this->lookupNamespace('apps') . ':' . 'emailList'; + $emailList = new Zend_Gdata_Gapps_Extension_EmailList(); + $emailList->transferFromDOM($child); + $this->_emailList = $emailList; + break; + case $this->lookupNamespace('gd') . ':' . 'feedLink'; + $feedLink = new Zend_Gdata_Extension_FeedLink(); + $feedLink->transferFromDOM($child); + $this->_feedLink[] = $feedLink; + break; + default: + parent::takeChildFromDOM($child); + break; + } + } + + /** + * Retrieve the email list property for this entry. + * + * @see setEmailList + * @return Zend_Gdata_Gapps_Extension_EmailList The requested object + * or null if not set. + */ + public function getEmailList() + { + return $this->_emailList; + } + + /** + * Set the email list property for this entry. This property contains + * information such as the name of this email list. + * + * This corresponds to the property in the Google Data + * protocol. + * + * @param Zend_Gdata_Gapps_Extension_EmailList $value The desired value + * this element, or null to unset. + * @return Zend_Gdata_Gapps_EventEntry Provides a fluent interface + */ + public function setEmailList($value) + { + $this->_emailList = $value; + return $this; + } + + /** + * Get the feed link property for this entry. + * + * @see setFeedLink + * @param string $rel (optional) The rel value of the link to be found. + * If null, the array of links is returned. + * @return mixed If $rel is specified, a Zend_Gdata_Extension_FeedLink + * object corresponding to the requested rel value is returned + * if found, or null if the requested value is not found. If + * $rel is null or not specified, an array of all available + * feed links for this entry is returned, or null if no feed + * links are set. + */ + public function getFeedLink($rel = null) + { + if ($rel == null) { + return $this->_feedLink; + } else { + foreach ($this->_feedLink as $feedLink) { + if ($feedLink->rel == $rel) { + return $feedLink; + } + } + return null; + } + } + + /** + * Set the feed link property for this entry. Feed links provide + * information about other feeds associated with this entry. + * + * This corresponds to the property in the Google Data + * protocol. + * + * @param array $value A collection of Zend_Gdata_Gapps_Extension_FeedLink + * instances representing all feed links for this entry, or + * null to unset. + * @return Zend_Gdata_Gapps_EventEntry Provides a fluent interface + */ + public function setFeedLink($value) + { + $this->_feedLink = $value; + return $this; + } + +} diff --git a/Zend/Gdata/Gapps/EmailListFeed.php b/Zend/Gdata/Gapps/EmailListFeed.php new file mode 100644 index 00000000..4f730dc5 --- /dev/null +++ b/Zend/Gdata/Gapps/EmailListFeed.php @@ -0,0 +1,53 @@ +setEmailListName($emailListName); + $this->setRecipient($recipient); + $this->setStartEmailListName($startEmailListName); + } + + /** + * Set the email list name to query for. When set, only lists with a name + * matching this value will be returned in search results. Set to + * null to disable filtering by list name. + * + * @param string $value The email list name to filter search results by, + * or null to disable. + */ + public function setEmailListName($value) + { + $this->_emailListName = $value; + } + + /** + * Get the email list name to query for. If no name is set, null will be + * returned. + * + * @see setEmailListName + * @return string The email list name to filter search results by, or null + * if disabled. + */ + public function getEmailListName() + { + return $this->_emailListName; + } + + /** + * Set the recipient to query for. When set, only subscribers with an + * email address matching this value will be returned in search results. + * Set to null to disable filtering by username. + * + * @param string $value The recipient email address to filter search + * results by, or null to disable. + */ + public function setRecipient($value) + { + if ($value !== null) { + $this->_params['recipient'] = $value; + } + else { + unset($this->_params['recipient']); + } + } + + /** + * Get the recipient email address to query for. If no recipient is set, + * null will be returned. + * + * @see setRecipient + * @return string The recipient email address to filter search results by, + * or null if disabled. + */ + public function getRecipient() + { + if (array_key_exists('recipient', $this->_params)) { + return $this->_params['recipient']; + } else { + return null; + } + } + + /** + * Set the first email list which should be displayed when retrieving + * a list of email lists. + * + * @param string $value The first email list to be returned, or null to + * disable. + */ + public function setStartEmailListName($value) + { + if ($value !== null) { + $this->_params['startEmailListName'] = $value; + } else { + unset($this->_params['startEmailListName']); + } + } + + /** + * Get the first email list which should be displayed when retrieving + * a list of email lists. + * + * @return string The first email list to be returned, or null to + * disable. + */ + public function getStartEmailListName() + { + if (array_key_exists('startEmailListName', $this->_params)) { + return $this->_params['startEmailListName']; + } else { + return null; + } + } + + /** + * Returns the URL generated for this query, based on it's current + * parameters. + * + * @return string A URL generated based on the state of this query. + * @throws Zend_Gdata_App_InvalidArgumentException + */ + public function getQueryUrl() + { + + $uri = $this->getBaseUrl(); + $uri .= Zend_Gdata_Gapps::APPS_EMAIL_LIST_PATH; + if ($this->_emailListName !== null) { + $uri .= '/' . $this->_emailListName; + } + $uri .= $this->getQueryString(); + return $uri; + } + +} diff --git a/Zend/Gdata/Gapps/EmailListRecipientEntry.php b/Zend/Gdata/Gapps/EmailListRecipientEntry.php new file mode 100644 index 00000000..f3c4450a --- /dev/null +++ b/Zend/Gdata/Gapps/EmailListRecipientEntry.php @@ -0,0 +1,146 @@ + in the Google Data protocol. + * + * @category Zend + * @package Zend_Gdata + * @subpackage Gapps + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +class Zend_Gdata_Gapps_EmailListRecipientEntry extends Zend_Gdata_Entry +{ + + protected $_entryClassName = 'Zend_Gdata_Gapps_EmailListRecipientEntry'; + + /** + * element used to store the email address of the current + * recipient. Only the email property of this element should be + * populated. + * + * @var Zend_Gdata_Extension_Who + */ + protected $_who = null; + + /** + * Create a new instance. + * + * @param DOMElement $element (optional) DOMElement from which this + * object should be constructed. + */ + public function __construct($element = null) + { + $this->registerAllNamespaces(Zend_Gdata_Gapps::$namespaces); + parent::__construct($element); + } + + /** + * Retrieves a DOMElement which corresponds to this element and all + * child properties. This is used to build an entry back into a DOM + * and eventually XML text for application storage/persistence. + * + * @param DOMDocument $doc The DOMDocument used to construct DOMElements + * @return DOMElement The DOMElement representing this element and all + * child properties. + */ + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc, $majorVersion, $minorVersion); + if ($this->_who !== null) { + $element->appendChild($this->_who->getDOM($element->ownerDocument)); + } + return $element; + } + + /** + * Creates individual Entry objects of the appropriate type and + * stores them as members of this entry based upon DOM data. + * + * @param DOMNode $child The DOMNode to process + */ + protected function takeChildFromDOM($child) + { + $absoluteNodeName = $child->namespaceURI . ':' . $child->localName; + + switch ($absoluteNodeName) { + case $this->lookupNamespace('gd') . ':' . 'who'; + $who = new Zend_Gdata_Extension_Who(); + $who->transferFromDOM($child); + $this->_who = $who; + break; + default: + parent::takeChildFromDOM($child); + break; + } + } + + /** + * Get the value of the who property for this object. + * + * @see setWho + * @return Zend_Gdata_Extension_Who The requested object. + */ + public function getWho() + { + return $this->_who; + } + + /** + * Set the value of the who property for this object. This property + * is used to store the email address of the current recipient. + * + * @param Zend_Gdata_Extension_Who $value The desired value for this + * instance's who property. + * @return Zend_Gdata_Gapps_EventEntry Provides a fluent interface. + */ + public function setWho($value) + { + $this->_who = $value; + return $this; + } + +} diff --git a/Zend/Gdata/Gapps/EmailListRecipientFeed.php b/Zend/Gdata/Gapps/EmailListRecipientFeed.php new file mode 100644 index 00000000..72a6b3fa --- /dev/null +++ b/Zend/Gdata/Gapps/EmailListRecipientFeed.php @@ -0,0 +1,53 @@ +setEmailListName($emailListName); + $this->setStartRecipient($startRecipient); + } + + /** + * Set the email list name to query for. When set, only lists with a name + * matching this value will be returned in search results. Set to + * null to disable filtering by list name. + * + * @param string $value The email list name to filter search results by, + * or null to disable. + */ + public function setEmailListName($value) + { + $this->_emailListName = $value; + } + + /** + * Get the email list name to query for. If no name is set, null will be + * returned. + * + * @param string $value The email list name to filter search results by, + * or null if disabled. + */ + public function getEmailListName() + { + return $this->_emailListName; + } + + /** + * Set the first recipient which should be displayed when retrieving + * a list of email list recipients. + * + * @param string $value The first recipient to be returned, or null to + * disable. + */ + public function setStartRecipient($value) + { + if ($value !== null) { + $this->_params['startRecipient'] = $value; + } else { + unset($this->_params['startRecipient']); + } + } + + /** + * Get the first recipient which should be displayed when retrieving + * a list of email list recipients. + * + * @return string The first recipient to be returned, or null if + * disabled. + */ + public function getStartRecipient() + { + if (array_key_exists('startRecipient', $this->_params)) { + return $this->_params['startRecipient']; + } else { + return null; + } + } + + /** + * Returns the URL generated for this query, based on it's current + * parameters. + * + * @return string A URL generated based on the state of this query. + * @throws Zend_Gdata_App_InvalidArgumentException + */ + public function getQueryUrl() + { + + $uri = $this->getBaseUrl(); + $uri .= Zend_Gdata_Gapps::APPS_EMAIL_LIST_PATH; + if ($this->_emailListName !== null) { + $uri .= '/' . $this->_emailListName; + } else { + require_once 'Zend/Gdata/App/InvalidArgumentException.php'; + throw new Zend_Gdata_App_InvalidArgumentException( + 'EmailListName must not be null'); + } + $uri .= Zend_Gdata_Gapps::APPS_EMAIL_LIST_RECIPIENT_POSTFIX . '/'; + $uri .= $this->getQueryString(); + return $uri; + } + +} diff --git a/Zend/Gdata/Gapps/Error.php b/Zend/Gdata/Gapps/Error.php new file mode 100644 index 00000000..937538df --- /dev/null +++ b/Zend/Gdata/Gapps/Error.php @@ -0,0 +1,233 @@ +_errorCode = $errorCode; + $this->_reason = $reason; + $this->_invalidInput = $invalidInput; + } + + /** + * Set the error code for this exception. For more information about + * error codes, see getErrorCode. + * + * @see getErrorCode + * @param integer $value The new value for the error code. + */ + public function setErrorCode($value) { + $this->_errorCode = $value; + } + + /** + * Get the error code for this exception. Currently valid values are + * available as constants within this class. These values are: + * + * UNKNOWN_ERROR (1000) + * USER_DELETED_RECENTLY (1100) + * USER_SUSPENDED (1101) + * DOMAIN_USER_LIMIT_EXCEEDED (1200) + * DOMAIN_ALIAS_LIMIT_EXCEEDED (1201) + * DOMAIN_SUSPENDED (1202) + * DOMAIN_FEATURE_UNAVAILABLE (1203) + * ENTITY_EXISTS (1300) + * ENTITY_DOES_NOT_EXIST (1301) + * ENTITY_NAME_IS_RESERVED (1302) + * ENTITY_NAME_NOT_VALID (1303) + * INVALID_GIVEN_NAME (1400) + * INVALID_FAMILY_NAME (1401) + * INVALID_PASSWORD (1402) + * INVALID_USERNAME (1403) + * INVALID_HASH_FUNCTION_NAME (1404) + * INVALID_HASH_DIGEST_LENGTH (1405) + * INVALID_EMAIL_ADDRESS (1406) + * INVALID_QUERY_PARAMETER_VALUE (1407) + * TOO_MANY_RECIPIENTS_ON_EMAIL_LIST (1500) + * + * Numbers in parenthesis indicate the actual integer value of the + * constant. This list should not be treated as exhaustive, as additional + * error codes may be added at any time. + * + * For more information about these codes and their meaning, please + * see Appendix D of the Google Apps Provisioning API Reference. + * + * @link http://code.google.com/apis/apps/gdata_provisioning_api_v2.0_reference.html#appendix_d Google Apps Provisioning API Reference: Appendix D - Gdata Error Codes + * @see setErrorCode + * @return integer The error code returned by the Google Apps server. + */ + public function getErrorCode() { + return $this->_errorCode; + } + + /** + * Set human-readable text describing the reason this exception occurred. + * + * @see getReason + * @param string $value The reason this exception occurred. + */ + public function setReason($value) { + $this->_reason = $value; + } + + /** + * Get human-readable text describing the reason this exception occurred. + * + * @see setReason + * @return string The reason this exception occurred. + */ + public function getReason() { + return $this->_reason; + } + + /** + * Set the invalid input which caused this exception. + * + * @see getInvalidInput + * @param string $value The invalid input that triggered this exception. + */ + public function setInvalidInput($value) { + $this->_invalidInput = $value; + } + + /** + * Set the invalid input which caused this exception. + * + * @see setInvalidInput + * @return string The reason this exception occurred. + */ + public function getInvalidInput() { + return $this->_invalidInput; + } + + /** + * Retrieves a DOMElement which corresponds to this element and all + * child properties. This is used to build an entry back into a DOM + * and eventually XML text for application storage/persistence. + * + * @param DOMDocument $doc The DOMDocument used to construct DOMElements + * @return DOMElement The DOMElement representing this element and all + * child properties. + */ + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc, $majorVersion, $minorVersion); + if ($this->_errorCode !== null) { + $element->setAttribute('errorCode', $this->_errorCode); + } + if ($this->_reason !== null) { + $element->setAttribute('reason', $this->_reason); + } + if ($this->_invalidInput !== null) { + $element->setAttribute('invalidInput', $this->_invalidInput); + } + return $element; + } + + /** + * Given a DOMNode representing an attribute, tries to map the data into + * instance members. If no mapping is defined, the name and value are + * stored in an array. + * + * @param DOMNode $attribute The DOMNode attribute needed to be handled + */ + protected function takeAttributeFromDOM($attribute) + { + switch ($attribute->localName) { + case 'errorCode': + $this->_errorCode = $attribute->nodeValue; + break; + case 'reason': + $this->_reason = $attribute->nodeValue; + break; + case 'invalidInput': + $this->_invalidInput = $attribute->nodeValue; + break; + default: + parent::takeAttributeFromDOM($attribute); + } + } + + /** + * Get a human readable version of this exception. + * + * @return string + */ + public function __toString() { + return "Error " . $this->getErrorCode() . ": " . $this->getReason() . + "\n\tInvalid Input: \"" . $this->getInvalidInput() . "\""; + } + +} diff --git a/Zend/Gdata/Gapps/Extension/EmailList.php b/Zend/Gdata/Gapps/Extension/EmailList.php new file mode 100644 index 00000000..dd21d0fa --- /dev/null +++ b/Zend/Gdata/Gapps/Extension/EmailList.php @@ -0,0 +1,144 @@ +registerAllNamespaces(Zend_Gdata_Gapps::$namespaces); + parent::__construct(); + $this->_name = $name; + } + + /** + * Retrieves a DOMElement which corresponds to this element and all + * child properties. This is used to build an entry back into a DOM + * and eventually XML text for sending to the server upon updates, or + * for application storage/persistence. + * + * @param DOMDocument $doc The DOMDocument used to construct DOMElements + * @return DOMElement The DOMElement representing this element and all + * child properties. + */ + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc, $majorVersion, $minorVersion); + if ($this->_name !== null) { + $element->setAttribute('name', $this->_name); + } + return $element; + } + + /** + * Given a DOMNode representing an attribute, tries to map the data into + * instance members. If no mapping is defined, the name and value are + * stored in an array. + * + * @param DOMNode $attribute The DOMNode attribute needed to be handled + */ + protected function takeAttributeFromDOM($attribute) + { + switch ($attribute->localName) { + case 'name': + $this->_name = $attribute->nodeValue; + break; + default: + parent::takeAttributeFromDOM($attribute); + } + } + + /** + * Get the value for this element's name attribute. + * + * @see setName + * @return string The requested attribute. + */ + public function getName() + { + return $this->_name; + } + + /** + * Set the value for this element's name attribute. This is the unique + * name which will be used to identify this email list within this + * domain, and will be used to form this email list's email address. + * + * @param string $value The desired value for this attribute. + * @return Zend_Gdata_Gapps_Extension_EmailList The element being modified. + */ + public function setName($value) + { + $this->_name = $value; + return $this; + } + + /** + * Magic toString method allows using this directly via echo + * Works best in PHP >= 4.2.0 + * + * @return string + */ + public function __toString() + { + return $this->getName(); + } + +} diff --git a/Zend/Gdata/Gapps/Extension/Login.php b/Zend/Gdata/Gapps/Extension/Login.php new file mode 100644 index 00000000..9fddb222 --- /dev/null +++ b/Zend/Gdata/Gapps/Extension/Login.php @@ -0,0 +1,485 @@ +registerAllNamespaces(Zend_Gdata_Gapps::$namespaces); + parent::__construct(); + $this->_username = $username; + $this->_password = $password; + $this->_hashFunctionName = $hashFunctionName; + $this->_admin = $admin; + $this->_agreedToTerms = $agreedToTerms; + $this->_suspended = $suspended; + $this->_changePasswordAtNextLogin = $changePasswordAtNextLogin; + } + + /** + * Retrieves a DOMElement which corresponds to this element and all + * child properties. This is used to build an entry back into a DOM + * and eventually XML text for sending to the server upon updates, or + * for application storage/persistence. + * + * @param DOMDocument $doc The DOMDocument used to construct DOMElements + * @return DOMElement The DOMElement representing this element and all + * child properties. + */ + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc, $majorVersion, $minorVersion); + if ($this->_username !== null) { + $element->setAttribute('userName', $this->_username); + } + if ($this->_password !== null) { + $element->setAttribute('password', $this->_password); + } + if ($this->_hashFunctionName !== null) { + $element->setAttribute('hashFunctionName', $this->_hashFunctionName); + } + if ($this->_admin !== null) { + $element->setAttribute('admin', ($this->_admin ? "true" : "false")); + } + if ($this->_agreedToTerms !== null) { + $element->setAttribute('agreedToTerms', ($this->_agreedToTerms ? "true" : "false")); + } + if ($this->_suspended !== null) { + $element->setAttribute('suspended', ($this->_suspended ? "true" : "false")); + } + if ($this->_changePasswordAtNextLogin !== null) { + $element->setAttribute('changePasswordAtNextLogin', ($this->_changePasswordAtNextLogin ? "true" : "false")); + } + + return $element; + } + + /** + * Given a DOMNode representing an attribute, tries to map the data into + * instance members. If no mapping is defined, the name and value are + * stored in an array. + * + * @param DOMNode $attribute The DOMNode attribute needed to be handled + * @throws Zend_Gdata_App_InvalidArgumentException + */ + protected function takeAttributeFromDOM($attribute) + { + switch ($attribute->localName) { + case 'userName': + $this->_username = $attribute->nodeValue; + break; + case 'password': + $this->_password = $attribute->nodeValue; + break; + case 'hashFunctionName': + $this->_hashFunctionName = $attribute->nodeValue; + break; + case 'admin': + if ($attribute->nodeValue == "true") { + $this->_admin = true; + } + else if ($attribute->nodeValue == "false") { + $this->_admin = false; + } + else { + require_once('Zend/Gdata/App/InvalidArgumentException.php'); + throw new Zend_Gdata_App_InvalidArgumentException("Expected 'true' or 'false' for apps:login#admin."); + } + break; + case 'agreedToTerms': + if ($attribute->nodeValue == "true") { + $this->_agreedToTerms = true; + } + else if ($attribute->nodeValue == "false") { + $this->_agreedToTerms = false; + } + else { + require_once('Zend/Gdata/App/InvalidArgumentException.php'); + throw new Zend_Gdata_App_InvalidArgumentException("Expected 'true' or 'false' for apps:login#agreedToTerms."); + } + break; + case 'suspended': + if ($attribute->nodeValue == "true") { + $this->_suspended = true; + } + else if ($attribute->nodeValue == "false") { + $this->_suspended = false; + } + else { + require_once('Zend/Gdata/App/InvalidArgumentException.php'); + throw new Zend_Gdata_App_InvalidArgumentException("Expected 'true' or 'false' for apps:login#suspended."); + } + break; + case 'changePasswordAtNextLogin': + if ($attribute->nodeValue == "true") { + $this->_changePasswordAtNextLogin = true; + } + else if ($attribute->nodeValue == "false") { + $this->_changePasswordAtNextLogin = false; + } + else { + require_once('Zend/Gdata/App/InvalidArgumentException.php'); + throw new Zend_Gdata_App_InvalidArgumentException("Expected 'true' or 'false' for apps:login#changePasswordAtNextLogin."); + } + break; + default: + parent::takeAttributeFromDOM($attribute); + } + } + + /** + * Get the value for this element's username attribute. + * + * @see setUsername + * @return string The attribute being modified. + */ + public function getUsername() + { + return $this->_username; + } + + /** + * Set the value for this element's username attribute. This string + * is used to uniquely identify the user in this domian and is used + * to form this user's email address. + * + * @param string $value The desired value for this attribute. + * @return Zend_Gdata_Gapps_Extension_Login Provides a fluent interface. + */ + public function setUsername($value) + { + $this->_username = $value; + return $this; + } + + /** + * Get the value for this element's password attribute. + * + * @see setPassword + * @return string The requested attribute. + */ + public function getPassword() + { + return $this->_password; + } + + /** + * Set the value for this element's password attribute. As of this + * writing, this can be either be provided as plaintext or hashed using + * the SHA-1 algorithm for protection. If using a hash function, + * this must be indicated by calling setHashFunctionName(). + * + * @param string $value The desired value for this attribute. + * @return Zend_Gdata_Gapps_Extension_Login Provides a fluent interface. + */ + public function setPassword($value) + { + $this->_password = $value; + return $this; + } + + /** + * Get the value for this element's hashFunctionName attribute. + * + * @see setHashFunctionName + * @return string The requested attribute. + */ + public function getHashFunctionName() + { + return $this->_hashFunctionName; + } + + /** + * Set the value for this element's hashFunctionName attribute. This + * indicates whether the password supplied with setPassword() is in + * plaintext or has had a hash function applied to it. If null, + * plaintext is assumed. As of this writing, the only valid hash + * function is 'SHA-1'. + * + * @param string $value The desired value for this attribute. + * @return Zend_Gdata_Gapps_Extension_Login Provides a fluent interface. + */ + public function setHashFunctionName($value) + { + $this->_hashFunctionName = $value; + return $this; + } + + /** + * Get the value for this element's admin attribute. + * + * @see setAdmin + * @return boolean The requested attribute. + * @throws Zend_Gdata_App_InvalidArgumentException + */ + public function getAdmin() + { + if (!(is_bool($this->_admin))) { + require_once('Zend/Gdata/App/InvalidArgumentException.php'); + throw new Zend_Gdata_App_InvalidArgumentException('Expected boolean for admin.'); + } + return $this->_admin; + } + + /** + * Set the value for this element's admin attribute. This indicates + * whether this user is an administrator for this domain. + * + * @param boolean $value The desired value for this attribute. + * @return Zend_Gdata_Gapps_Extension_Login Provides a fluent interface. + * @throws Zend_Gdata_App_InvalidArgumentException + */ + public function setAdmin($value) + { + if (!(is_bool($value))) { + require_once('Zend/Gdata/App/InvalidArgumentException.php'); + throw new Zend_Gdata_App_InvalidArgumentException('Expected boolean for $value.'); + } + $this->_admin = $value; + return $this; + } + + /** + * Get the value for this element's agreedToTerms attribute. + * + * @see setAgreedToTerms + * @return boolean The requested attribute. + * @throws Zend_Gdata_App_InvalidArgumentException + */ + public function getAgreedToTerms() + { + if (!(is_bool($this->_agreedToTerms))) { + require_once('Zend/Gdata/App/InvalidArgumentException.php'); + throw new Zend_Gdata_App_InvalidArgumentException('Expected boolean for agreedToTerms.'); + } + return $this->_agreedToTerms; + } + + /** + * Set the value for this element's agreedToTerms attribute. This + * indicates whether this user has agreed to the terms of service. + * + * @param boolean $value The desired value for this attribute. + * @return Zend_Gdata_Gapps_Extension_Login Provides a fluent interface. + * @throws Zend_Gdata_App_InvalidArgumentException + */ + public function setAgreedToTerms($value) + { + if (!(is_bool($value))) { + require_once('Zend/Gdata/App/InvalidArgumentException.php'); + throw new Zend_Gdata_App_InvalidArgumentException('Expected boolean for $value.'); + } + $this->_agreedToTerms = $value; + return $this; + } + + /** + * Get the value for this element's suspended attribute. + * + * @see setSuspended + * @return boolean The requested attribute. + * @throws Zend_Gdata_App_InvalidArgumentException + */ + public function getSuspended() + { + if (!(is_bool($this->_suspended))) { + require_once('Zend/Gdata/App/InvalidArgumentException.php'); + throw new Zend_Gdata_App_InvalidArgumentException('Expected boolean for suspended.'); + } + return $this->_suspended; + } + + /** + * Set the value for this element's suspended attribute. If true, the + * user will not be able to login to this domain until unsuspended. + * + * @param boolean $value The desired value for this attribute. + * @return Zend_Gdata_Gapps_Extension_Login Provides a fluent interface. + * @throws Zend_Gdata_App_InvalidArgumentException + */ + public function setSuspended($value) + { + if (!(is_bool($value))) { + require_once('Zend/Gdata/App/InvalidArgumentException.php'); + throw new Zend_Gdata_App_InvalidArgumentException('Expected boolean for $value.'); + } + $this->_suspended = $value; + return $this; + } + + /** + * Get the value for this element's changePasswordAtNextLogin attribute. + * + * @see setChangePasswordAtNextLogin + * @return boolean The requested attribute. + * @throws Zend_Gdata_App_InvalidArgumentException + */ + public function getChangePasswordAtNextLogin() + { + if (!(is_bool($this->_changePasswordAtNextLogin))) { + require_once('Zend/Gdata/App/InvalidArgumentException.php'); + throw new Zend_Gdata_App_InvalidArgumentException('Expected boolean for changePasswordAtNextLogin.'); + } + return $this->_changePasswordAtNextLogin; + } + + /** + * Set the value for this element's changePasswordAtNextLogin attribute. + * If true, the user will be forced to set a new password the next + * time they login. + * + * @param boolean $value The desired value for this attribute. + * @return Zend_Gdata_Gapps_Extension_Login Provides a fluent interface. + * @throws Zend_Gdata_App_InvalidArgumentException + */ + public function setChangePasswordAtNextLogin($value) + { + if (!(is_bool($value))) { + require_once('Zend/Gdata/App/InvalidArgumentException.php'); + throw new Zend_Gdata_App_InvalidArgumentException('Expected boolean for $value.'); + } + $this->_changePasswordAtNextLogin = $value; + return $this; + } + + /** + * Magic toString method allows using this directly via echo + * Works best in PHP >= 4.2.0 + */ + public function __toString() + { + return "Username: " . $this->getUsername() . + "\nPassword: " . (($this->getPassword() === null) ? "NOT SET" : "SET") . + "\nPassword Hash Function: " . $this->getHashFunctionName() . + "\nAdministrator: " . ($this->getAdmin() ? "Yes" : "No") . + "\nAgreed To Terms: " . ($this->getAgreedToTerms() ? "Yes" : "No") . + "\nSuspended: " . ($this->getSuspended() ? "Yes" : "No"); + } +} diff --git a/Zend/Gdata/Gapps/Extension/Name.php b/Zend/Gdata/Gapps/Extension/Name.php new file mode 100644 index 00000000..1eabb55d --- /dev/null +++ b/Zend/Gdata/Gapps/Extension/Name.php @@ -0,0 +1,181 @@ +registerAllNamespaces(Zend_Gdata_Gapps::$namespaces); + parent::__construct(); + $this->_familyName = $familyName; + $this->_givenName = $givenName; + } + + /** + * Retrieves a DOMElement which corresponds to this element and all + * child properties. This is used to build an entry back into a DOM + * and eventually XML text for sending to the server upon updates, or + * for application storage/persistence. + * + * @param DOMDocument $doc The DOMDocument used to construct DOMElements + * @return DOMElement The DOMElement representing this element and all + * child properties. + */ + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc, $majorVersion, $minorVersion); + if ($this->_familyName !== null) { + $element->setAttribute('familyName', $this->_familyName); + } + if ($this->_givenName !== null) { + $element->setAttribute('givenName', $this->_givenName); + } + return $element; + } + + /** + * Given a DOMNode representing an attribute, tries to map the data into + * instance members. If no mapping is defined, the name and value are + * stored in an array. + * + * @param DOMNode $attribute The DOMNode attribute needed to be handled + */ + protected function takeAttributeFromDOM($attribute) + { + switch ($attribute->localName) { + case 'familyName': + $this->_familyName = $attribute->nodeValue; + break; + case 'givenName': + $this->_givenName = $attribute->nodeValue; + break; + default: + parent::takeAttributeFromDOM($attribute); + } + } + + /** + * Get the value for this element's familyName attribute. + * + * @see setFamilyName + * @return string The requested attribute. + */ + public function getFamilyName() + { + return $this->_familyName; + } + + /** + * Set the value for this element's familyName attribute. This + * represents a user's family name. + * + * @param string $value The desired value for this attribute. + * @return Zend_Gdata_Gapps_Extension_Name Provides a fluent interface.. + */ + public function setFamilyName($value) + { + $this->_familyName = $value; + return $this; + } + + /** + * Get the value for this element's givenName attribute. + * + * @see setGivenName + * @return string The requested attribute. + */ + public function getGivenName() + { + return $this->_givenName; + } + + /** + * Set the value for this element's givenName attribute. This + * represents a user's given name. + * + * @param string $value The desired value for this attribute. + * @return Zend_Gdata_Gapps_Extension_Name Provides a fluent interface. + */ + public function setGivenName($value) + { + $this->_givenName = $value; + return $this; + } + + /** + * Magic toString method allows using this directly via echo + * Works best in PHP >= 4.2.0 + */ + public function __toString() + { + return $this->getGivenName() . ' ' . $this->getFamilyName(); + } + +} diff --git a/Zend/Gdata/Gapps/Extension/Nickname.php b/Zend/Gdata/Gapps/Extension/Nickname.php new file mode 100644 index 00000000..25c1397b --- /dev/null +++ b/Zend/Gdata/Gapps/Extension/Nickname.php @@ -0,0 +1,142 @@ +registerAllNamespaces(Zend_Gdata_Gapps::$namespaces); + parent::__construct(); + $this->_name = $name; + } + + /** + * Retrieves a DOMElement which corresponds to this element and all + * child properties. This is used to build an entry back into a DOM + * and eventually XML text for sending to the server upon updates, or + * for application storage/persistence. + * + * @param DOMDocument $doc The DOMDocument used to construct DOMElements + * @return DOMElement The DOMElement representing this element and all + * child properties. + */ + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc, $majorVersion, $minorVersion); + if ($this->_name !== null) { + $element->setAttribute('name', $this->_name); + } + return $element; + } + + /** + * Given a DOMNode representing an attribute, tries to map the data into + * instance members. If no mapping is defined, the name and value are + * stored in an array. + * + * @param DOMNode $attribute The DOMNode attribute needed to be handled + */ + protected function takeAttributeFromDOM($attribute) + { + switch ($attribute->localName) { + case 'name': + $this->_name = $attribute->nodeValue; + break; + default: + parent::takeAttributeFromDOM($attribute); + } + } + + /** + * Get the value for this element's name attribute. + * + * @see setName + * @return string The requested attribute. + */ + public function getName() + { + return $this->_name; + } + + /** + * Set the value for this element's name attribute. This name uniquely + * describes this nickname within the domain. Emails addressed to this + * name will be delivered to the user who owns this nickname. + * + * @param string $value The desired value for this attribute. + * @return Zend_Gdata_Gapps_Extension_Nickname Provides a fluent + * interface. + */ + public function setName($value) + { + $this->_name = $value; + return $this; + } + + /** + * Magic toString method allows using this directly via echo + * Works best in PHP >= 4.2.0 + */ + public function __toString() + { + return $this->getName(); + } + +} diff --git a/Zend/Gdata/Gapps/Extension/Property.php b/Zend/Gdata/Gapps/Extension/Property.php new file mode 100644 index 00000000..f2c16cfb --- /dev/null +++ b/Zend/Gdata/Gapps/Extension/Property.php @@ -0,0 +1,180 @@ +registerAllNamespaces(Zend_Gdata_Gapps::$namespaces); + parent::__construct(); + $this->_name = $name; + $this->_value = $value; + + } + + + /** + * Retrieves a DOMElement which corresponds to this element and all + * child properties. This is used to build an entry back into a DOM + * and eventually XML text for sending to the server upon updates, or + * for application storage/persistence. + * + * @param DOMDocument $doc The DOMDocument used to construct DOMElements + * @return DOMElement The DOMElement representing this element and all + * child properties. + */ + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc, $majorVersion, $minorVersion); + if ($this->_name !== null) { + $element->setAttribute('name', $this->_name); + } + if ($this->_value !== null) { + $element->setAttribute('value', $this->_value); + } + + return $element; + + } + + /** + * Given a DOMNode representing an attribute, tries to map the data into + * instance members. If no mapping is defined, the name and value are + * stored in an array. + * + * @param DOMNode $attribute The DOMNode attribute needed to be handled + */ + protected function takeAttributeFromDOM($attribute) + { + switch ($attribute->localName) { + case 'name': + $this->_name = $attribute->nodeValue; + break; + case 'value': + $this->_value = $attribute->nodeValue; + break; + default: + parent::takeAttributeFromDOM($attribute); + } + } + + /** + * Get the value for this element's name attribute. + * + * @see setName + * @return string The requested attribute. + */ + public function getName() + { + return $this->_name; + } + + /** + * Set the value for this element's name attribute. + * @param string $value The desired value for this attribute. + * @return Zend_Gdata_Gapps_Extension_Property The element being modified. + */ + public function setName($value) + { + $this->_name = $value; + return $this; + } + + /** + * Get the value for this element's value attribute. + * + * @see setName + * @return string The requested attribute. + */ + public function getValue() + { + return $this->_value; + } + + /** + * Set the value for this element's value attribute. + * + * @param string $value The desired value for this attribute. + * @return Zend_Gdata_Gapps_Extension_Property The element being modified. + */ + public function setValue($value) + { + $this->_value = $value; + return $this; + } + + /** + * Magic toString method allows using this directly via echo + * Works best in PHP >= 4.2.0 + * + * @return string + */ + public function __toString() + { + return "Property Name: " . $this->getName() . + "\nProperty Value: " . $this->getValue(); + } +} +?> \ No newline at end of file diff --git a/Zend/Gdata/Gapps/Extension/Quota.php b/Zend/Gdata/Gapps/Extension/Quota.php new file mode 100644 index 00000000..2dbc7fc9 --- /dev/null +++ b/Zend/Gdata/Gapps/Extension/Quota.php @@ -0,0 +1,142 @@ +registerAllNamespaces(Zend_Gdata_Gapps::$namespaces); + parent::__construct(); + $this->_limit = $limit; + } + + /** + * Retrieves a DOMElement which corresponds to this element and all + * child properties. This is used to build an entry back into a DOM + * and eventually XML text for sending to the server upon updates, or + * for application storage/persistence. + * + * @param DOMDocument $doc The DOMDocument used to construct DOMElements + * @return DOMElement The DOMElement representing this element and all + * child properties. + */ + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc, $majorVersion, $minorVersion); + if ($this->_limit !== null) { + $element->setAttribute('limit', $this->_limit); + } + return $element; + } + + /** + * Given a DOMNode representing an attribute, tries to map the data into + * instance members. If no mapping is defined, the name and value are + * stored in an array. + * + * @param DOMNode $attribute The DOMNode attribute needed to be handled + */ + protected function takeAttributeFromDOM($attribute) + { + switch ($attribute->localName) { + case 'limit': + $this->_limit = $attribute->nodeValue; + break; + default: + parent::takeAttributeFromDOM($attribute); + } + } + + /** + * Get the value for this element's limit attribute. + * + * @see setLimit + * @return string The requested attribute. + */ + public function getLimit() + { + return $this->_limit; + } + + /** + * Set the value for this element's limit attribute. This is the amount + * of storage space, in bytes, that should be made available to + * the associated user. + * + * @param string $value The desired value for this attribute. + * @return Zend_Gdata_Gapps_Extension_Quota Provides a fluent interface. + */ + public function setLimit($value) + { + $this->_limit = $value; + return $this; + } + + /** + * Magic toString method allows using this directly via echo + * Works best in PHP >= 4.2.0 + */ + public function __toString() + { + return $this->getLimit(); + } + +} diff --git a/Zend/Gdata/Gapps/GroupEntry.php b/Zend/Gdata/Gapps/GroupEntry.php new file mode 100644 index 00000000..d345969c --- /dev/null +++ b/Zend/Gdata/Gapps/GroupEntry.php @@ -0,0 +1,158 @@ + in the Google Data protocol. + * + * @category Zend + * @package Zend_Gdata + * @subpackage Gapps + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +class Zend_Gdata_Gapps_GroupEntry extends Zend_Gdata_Entry +{ + + protected $_entryClassName = 'Zend_Gdata_Gapps_GroupEntry'; + + /** + * element containing information about other items + * relevant to this entry. + * + * @var Zend_Gdata_Gapps_Extension_Property + */ + protected $_property = array(); + + /** + * Create a new instance. + * + * @param DOMElement $element (optional) DOMElement from which this + * object should be constructed. + */ + public function __construct($element = null) + { + $this->registerAllNamespaces(Zend_Gdata_Gapps::$namespaces); + parent::__construct($element); + } + + /** + * Retrieves a DOMElement which corresponds to this element and all + * child properties. This is used to build an entry back into a DOM + * and eventually XML text for application storage/persistence. + * + * @param DOMDocument $doc The DOMDocument used to construct DOMElements + * @return DOMElement The DOMElement representing this element and all + * child properties. + */ + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc, $majorVersion, $minorVersion); + + foreach ($this->_property as $p) { + $element->appendChild($p->getDOM($element->ownerDocument)); + } + return $element; + } + + /** + * Creates individual Entry objects of the appropriate type and + * stores them as members of this entry based upon DOM data. + * + * @param DOMNode $child The DOMNode to process + */ + protected function takeChildFromDOM($child) + { + $absoluteNodeName = $child->namespaceURI . ':' . $child->localName; + + switch ($absoluteNodeName) { + + case $this->lookupNamespace('apps') . ':' . 'property'; + $property = new Zend_Gdata_Gapps_Extension_Property(); + $property->transferFromDOM($child); + $this->_property[] = $property; + break; + default: + parent::takeChildFromDOM($child); + break; + } + } + + /** + * Returns all property tags for this entry + * + * @param string $rel The rel value of the property to be found. If null, + * the array of properties is returned instead. + * @return mixed Either an array of Zend_Gdata_Gapps_Extension_Property + * objects if $rel is null, a single + * Zend_Gdata_Gapps_Extension_Property object if $rel is specified + * and a matching feed link is found, or null if $rel is + * specified and no matching property is found. + */ + public function getProperty($rel = null) + { + if ($rel == null) { + return $this->_property; + } else { + foreach ($this->_property as $p) { + if ($p->rel == $rel) { + return $p; + } + } + return null; + } + } + + /** + * Set the value of the property property for this object. + * + * @param array $value A collection of + * Zend_Gdata_Gapps_Extension_Property objects. + * @return Zend_Gdata_Gapps_GroupEntry Provides a fluent interface. + */ + public function setProperty($value) + { + $this->_property = $value; + return $this; + } + +} + diff --git a/Zend/Gdata/Gapps/GroupFeed.php b/Zend/Gdata/Gapps/GroupFeed.php new file mode 100644 index 00000000..250984f1 --- /dev/null +++ b/Zend/Gdata/Gapps/GroupFeed.php @@ -0,0 +1,53 @@ +setGroupId($groupId); + $this->setStartGroupId($startGroupId); + } + + /** + * Set the group id to query for. When set, only groups with a group id + * matching this value will be returned in search results. Set to + * null to disable filtering by group id. + * + * @see getGroupId + * @param string $value The group id to filter search results by, or null to + * disable. + */ + public function setGroupId($value) + { + $this->_groupId = $value; + } + + /** + * Get the group id to query for. If no group id is set, null will be + * returned. + * + * @param string $value The group id to filter search results by, or + * null if disabled. + */ + public function getGroupId() + { + return $this->_groupId; + } + + /** + * Set the member to query for. When set, only subscribers with an + * email address matching this value will be returned in search results. + * Set to null to disable filtering by username. + * + * @param string $value The member email address to filter search + * results by, or null to disable. + */ + public function setMember($value) + { + if ($value !== null) { + $this->_params['member'] = $value; + } + else { + unset($this->_params['member']); + } + } + + /** + * Get the member email address to query for. If no member is set, + * null will be returned. + * + * @see setMember + * @return string The member email address to filter search + * results by, or null if disabled. + */ + public function getMember() + { + if (array_key_exists('member', $this->_params)) { + return $this->_params['member']; + } else { + return null; + } + } + + + /** + * Sets the query parameter directOnly + * @param bool $value + */ + public function setDirectOnly($value) + { + if ($value !== null) { + if($value == true) { + $this->_params['directOnly'] = 'true'; + } else { + $this->_params['directOnly'] = 'false'; + } + } else { + unset($this->_params['directOnly']); + } + } + + /** + * + * @see setDirectOnly + * @return bool + */ + public function getDirectOnly() + { + if (array_key_exists('directOnly', $this->_params)) { + + if($this->_params['directOnly'] == 'true') { + return true; + } else { + return false; + } + } else { + return null; + } + } + + /** + * Set the first group id which should be displayed when retrieving + * a list of groups. + * + * @param string $value The first group id to be returned, or null to + * disable. + */ + public function setStartGroupId($value) + { + if ($value !== null) { + $this->_params['start'] = $value; + } else { + unset($this->_params['start']); + } + } + + /** + * Get the first group id which should be displayed when retrieving + * a list of groups. + * + * @see setStartGroupId + * @return string The first group id to be returned, or null if + * disabled. + */ + public function getStartGroupId() + { + if (array_key_exists('start', $this->_params)) { + return $this->_params['start']; + } else { + return null; + } + } + + /** + * Returns the query URL generated by this query instance. + * + * @return string The query URL for this instance. + */ + public function getQueryUrl() + { + + $uri = Zend_Gdata_Gapps::APPS_BASE_FEED_URI; + $uri .= Zend_Gdata_Gapps::APPS_GROUP_PATH; + $uri .= '/' . $this->_domain; + + if ($this->_groupId !== null) { + $uri .= '/' . $this->_groupId; + } + + if(array_key_exists('member', $this->_params)) { + $uri .= '/'; + } + + $uri .= $this->getQueryString(); + return $uri; + } + +} diff --git a/Zend/Gdata/Gapps/MemberEntry.php b/Zend/Gdata/Gapps/MemberEntry.php new file mode 100644 index 00000000..5bf08f28 --- /dev/null +++ b/Zend/Gdata/Gapps/MemberEntry.php @@ -0,0 +1,159 @@ + in the Google Data protocol. + * + * @category Zend + * @package Zend_Gdata + * @subpackage Gapps + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +class Zend_Gdata_Gapps_MemberEntry extends Zend_Gdata_Entry +{ + + protected $_entryClassName = 'Zend_Gdata_Gapps_MemberEntry'; + + /** + * element containing information about other items + * relevant to this entry. + * + * @var Zend_Gdata_Gapps_Extension_Property + */ + protected $_property = array(); + + /** + * Create a new instance. + * + * @param DOMElement $element (optional) DOMElement from which this + * object should be constructed. + */ + public function __construct($element = null) + { + $this->registerAllNamespaces(Zend_Gdata_Gapps::$namespaces); + parent::__construct($element); + } + + /** + * Retrieves a DOMElement which corresponds to this element and all + * child properties. This is used to build an entry back into a DOM + * and eventually XML text for application storage/persistence. + * + * @param DOMDocument $doc The DOMDocument used to construct DOMElements + * @return DOMElement The DOMElement representing this element and all + * child properties. + */ + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc, $majorVersion, $minorVersion); + + foreach ($this->_property as $p) { + $element->appendChild($p->getDOM($element->ownerDocument)); + } + return $element; + } + + /** + * Creates individual Entry objects of the appropriate type and + * stores them as members of this entry based upon DOM data. + * + * @param DOMNode $child The DOMNode to process + */ + protected function takeChildFromDOM($child) + { + $absoluteNodeName = $child->namespaceURI . ':' . $child->localName; + + switch ($absoluteNodeName) { + + case $this->lookupNamespace('apps') . ':' . 'property'; + $property = new Zend_Gdata_Gapps_Extension_Property(); + $property->transferFromDOM($child); + $this->_property[] = $property; + break; + default: + parent::takeChildFromDOM($child); + break; + } + } + + /** + * Returns all property tags for this entry + * + * @param string $rel The rel value of the property to be found. If null, + * the array of properties is returned instead. + * @return mixed Either an array of Zend_Gdata_Gapps_Extension_Property + * objects if $rel is null, a single + * Zend_Gdata_Gapps_Extension_Property object if $rel is specified + * and a matching feed link is found, or null if $rel is + * specified and no matching property is found. + */ + public function getProperty($rel = null) + { + if ($rel == null) { + return $this->_property; + } else { + foreach ($this->_property as $p) { + if ($p->rel == $rel) { + return $p; + } + } + return null; + } + } + + /** + * Set the value of the property property for this object. + * + * @param array $value A collection of + * Zend_Gdata_Gapps_Extension_Property objects. + * @return Zend_Gdata_Gapps_MemberEntry Provides a fluent interface. + */ + public function setProperty($value) + { + $this->_property = $value; + return $this; + } + +} + + diff --git a/Zend/Gdata/Gapps/MemberFeed.php b/Zend/Gdata/Gapps/MemberFeed.php new file mode 100644 index 00000000..688ed298 --- /dev/null +++ b/Zend/Gdata/Gapps/MemberFeed.php @@ -0,0 +1,53 @@ +setGroupId($groupId); + $this->setMemberId($memberId); + $this->setStartMemberId($startMemberId); + } + + /** + * Set the group id to query for. + * + * @see getGroupId + * @param string $value The group id to filter search results by, or null to + * disable. + */ + public function setGroupId($value) + { + $this->_groupId = $value; + } + + /** + * Get the group id to query for. If no group id is set, null will be + * returned. + * + * @param string $value The group id to filter search results by, or + * null if disabled. + * @return string The group id + */ + public function getGroupId() + { + return $this->_groupId; + } + + + /** + * Set the member id to query for. When set, only users with a member id + * matching this value will be returned in search results. Set to + * null to disable filtering by member id. + * + * @see getMemberId + * @param string $value The member id to filter search results by, or null to + * disable. + */ + public function setMemberId($value) + { + $this->_memberId = $value; + } + + /** + * Get the member id to query for. If no member id is set, null will be + * returned. + * + * @param string $value The member id to filter search results by, or + * null if disabled. + * @return The member id + */ + public function getMemberId() + { + return $this->_memberId; + } + + /** + * Set the first member id which should be displayed when retrieving + * a list of members. + * + * @param string $value The first member id to be returned, or null to + * disable. + */ + public function setStartMemberId($value) + { + if ($value !== null) { + $this->_params['start'] = $value; + } else { + unset($this->_params['start']); + } + } + + /** + * Get the first username which should be displayed when retrieving + * a list of users. + * + * @see setStartUsername + * @return string The first username to be returned, or null if + * disabled. + */ + public function getStartMemberId() + { + if (array_key_exists('start', $this->_params)) { + return $this->_params['start']; + } else { + return null; + } + } + + /** + * Returns the query URL generated by this query instance. + * + * @return string The query URL for this instance. + */ + public function getQueryUrl() + { + + $uri = Zend_Gdata_Gapps::APPS_BASE_FEED_URI; + $uri .= Zend_Gdata_Gapps::APPS_GROUP_PATH; + $uri .= '/' . $this->_domain; + if ($this->_groupId !== null) { + $uri .= '/' . $this->_groupId; + } else { + require_once 'Zend/Gdata/App/InvalidArgumentException.php'; + throw new Zend_Gdata_App_InvalidArgumentException( + 'groupId must not be null'); + } + + $uri .= '/member'; + + if ($this->_memberId !== null) { + $uri .= '/' . $this->_memberId; + } + $uri .= $this->getQueryString(); + return $uri; + } + +} diff --git a/Zend/Gdata/Gapps/NicknameEntry.php b/Zend/Gdata/Gapps/NicknameEntry.php new file mode 100644 index 00000000..fb12ea46 --- /dev/null +++ b/Zend/Gdata/Gapps/NicknameEntry.php @@ -0,0 +1,189 @@ + in the Google Data protocol. + * + * @category Zend + * @package Zend_Gdata + * @subpackage Gapps + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +class Zend_Gdata_Gapps_NicknameEntry extends Zend_Gdata_Entry +{ + + protected $_entryClassName = 'Zend_Gdata_Gapps_NicknameEntry'; + + /** + * element used to hold information about the owner + * of this nickname, including their username. + * + * @var Zend_Gdata_Gapps_Extension_Login + */ + protected $_login = null; + + /** + * element used to hold the name of this nickname. + * + * @var Zend_Gdata_Gapps_Extension_Nickname + */ + protected $_nickname = null; + + /** + * Create a new instance. + * + * @param DOMElement $element (optional) DOMElement from which this + * object should be constructed. + */ + public function __construct($element = null) + { + $this->registerAllNamespaces(Zend_Gdata_Gapps::$namespaces); + parent::__construct($element); + } + + /** + * Retrieves a DOMElement which corresponds to this element and all + * child properties. This is used to build an entry back into a DOM + * and eventually XML text for application storage/persistence. + * + * @param DOMDocument $doc The DOMDocument used to construct DOMElements + * @return DOMElement The DOMElement representing this element and all + * child properties. + */ + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc, $majorVersion, $minorVersion); + if ($this->_login !== null) { + $element->appendChild($this->_login->getDOM($element->ownerDocument)); + } + if ($this->_nickname !== null) { + $element->appendChild($this->_nickname->getDOM($element->ownerDocument)); + } + return $element; + } + + /** + * Creates individual Entry objects of the appropriate type and + * stores them as members of this entry based upon DOM data. + * + * @param DOMNode $child The DOMNode to process + */ + protected function takeChildFromDOM($child) + { + $absoluteNodeName = $child->namespaceURI . ':' . $child->localName; + + switch ($absoluteNodeName) { + case $this->lookupNamespace('apps') . ':' . 'login'; + $login = new Zend_Gdata_Gapps_Extension_Login(); + $login->transferFromDOM($child); + $this->_login = $login; + break; + case $this->lookupNamespace('apps') . ':' . 'nickname'; + $nickname = new Zend_Gdata_Gapps_Extension_Nickname(); + $nickname->transferFromDOM($child); + $this->_nickname = $nickname; + break; + default: + parent::takeChildFromDOM($child); + break; + } + } + + /** + * Get the value of the login property for this object. + * + * @see setLogin + * @return Zend_Gdata_Gapps_Extension_Login The requested object. + */ + public function getLogin() + { + return $this->_login; + } + + /** + * Set the value of the login property for this object. This property + * is used to store the username address of the current user. + * + * @param Zend_Gdata_Gapps_Extension_Login $value The desired value for + * this instance's login property. + * @return Zend_Gdata_Gapps_NicknameEntry Provides a fluent interface. + */ + public function setLogin($value) + { + $this->_login = $value; + return $this; + } + + /** + * Get the value of the nickname property for this object. + * + * @see setNickname + * @return Zend_Gdata_Gapps_Extension_Nickname The requested object. + */ + public function getNickname() + { + return $this->_nickname; + } + + /** + * Set the value of the nickname property for this object. This property + * is used to store the the name of the current nickname. + * + * @param Zend_Gdata_Gapps_Extension_Nickname $value The desired value for + * this instance's nickname property. + * @return Zend_Gdata_Gapps_NicknameEntry Provides a fluent interface. + */ + public function setNickname($value) + { + $this->_nickname = $value; + return $this; + } + +} diff --git a/Zend/Gdata/Gapps/NicknameFeed.php b/Zend/Gdata/Gapps/NicknameFeed.php new file mode 100644 index 00000000..afa9f996 --- /dev/null +++ b/Zend/Gdata/Gapps/NicknameFeed.php @@ -0,0 +1,53 @@ +setNickname($nickname); + $this->setUsername($username); + $this->setStartNickname($startNickname); + } + + /** + * Set the nickname to query for. When set, only users with a nickname + * matching this value will be returned in search results. Set to + * null to disable filtering by username. + * + * @param string $value The nickname to filter search results by, or null + * to disable. + */ + public function setNickname($value) + { + $this->_nickname = $value; + } + + /** + * Get the nickname to query for. If no nickname is set, null will be + * returned. + * + * @see setNickname + * @return string The nickname to filter search results by, or null if + * disabled. + */ + public function getNickname() + { + return $this->_nickname; + } + + /** + * Set the username to query for. When set, only users with a username + * matching this value will be returned in search results. Set to + * null to disable filtering by username. + * + * @param string $value The username to filter search results by, or null + * to disable. + */ + public function setUsername($value) + { + if ($value !== null) { + $this->_params['username'] = $value; + } + else { + unset($this->_params['username']); + } + } + + /** + * Get the username to query for. If no username is set, null will be + * returned. + * + * @see setUsername + * @return string The username to filter search results by, or null if + * disabled. + */ + public function getUsername() + { + if (array_key_exists('username', $this->_params)) { + return $this->_params['username']; + } else { + return null; + } + } + + /** + * Set the first nickname which should be displayed when retrieving + * a list of nicknames. + * + * @param string $value The first nickname to be returned, or null to + * disable. + */ + public function setStartNickname($value) + { + if ($value !== null) { + $this->_params['startNickname'] = $value; + } else { + unset($this->_params['startNickname']); + } + } + + /** + * Get the first nickname which should be displayed when retrieving + * a list of nicknames. + * + * @return string The first nickname to be returned, or null to + * disable. + */ + public function getStartNickname() + { + if (array_key_exists('startNickname', $this->_params)) { + return $this->_params['startNickname']; + } else { + return null; + } + } + + /** + * Returns the URL generated for this query, based on it's current + * parameters. + * + * @return string A URL generated based on the state of this query. + */ + public function getQueryUrl() + { + + $uri = $this->getBaseUrl(); + $uri .= Zend_Gdata_Gapps::APPS_NICKNAME_PATH; + if ($this->_nickname !== null) { + $uri .= '/' . $this->_nickname; + } + $uri .= $this->getQueryString(); + return $uri; + } + +} diff --git a/Zend/Gdata/Gapps/OwnerEntry.php b/Zend/Gdata/Gapps/OwnerEntry.php new file mode 100644 index 00000000..4ba12240 --- /dev/null +++ b/Zend/Gdata/Gapps/OwnerEntry.php @@ -0,0 +1,158 @@ + in the Google Data protocol. + * + * @category Zend + * @package Zend_Gdata + * @subpackage Gapps + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +class Zend_Gdata_Gapps_OwnerEntry extends Zend_Gdata_Entry +{ + + protected $_entryClassName = 'Zend_Gdata_Gapps_OwnerEntry'; + + /** + * element containing information about other items + * relevant to this entry. + * + * @var Zend_Gdata_Gapps_Extension_Property + */ + protected $_property = array(); + + /** + * Create a new instance. + * + * @param DOMElement $element (optional) DOMElement from which this + * object should be constructed. + */ + public function __construct($element = null) + { + $this->registerAllNamespaces(Zend_Gdata_Gapps::$namespaces); + parent::__construct($element); + } + + /** + * Retrieves a DOMElement which corresponds to this element and all + * child properties. This is used to build an entry back into a DOM + * and eventually XML text for application storage/persistence. + * + * @param DOMDocument $doc The DOMDocument used to construct DOMElements + * @return DOMElement The DOMElement representing this element and all + * child properties. + */ + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc, $majorVersion, $minorVersion); + + foreach ($this->_property as $p) { + $element->appendChild($p->getDOM($element->ownerDocument)); + } + return $element; + } + + /** + * Creates individual Entry objects of the appropriate type and + * stores them as owners of this entry based upon DOM data. + * + * @param DOMNode $child The DOMNode to process + */ + protected function takeChildFromDOM($child) + { + $absoluteNodeName = $child->namespaceURI . ':' . $child->localName; + + switch ($absoluteNodeName) { + + case $this->lookupNamespace('apps') . ':' . 'property'; + $property = new Zend_Gdata_Gapps_Extension_Property(); + $property->transferFromDOM($child); + $this->_property[] = $property; + break; + default: + parent::takeChildFromDOM($child); + break; + } + } + + /** + * Returns all property tags for this entry + * + * @param string $rel The rel value of the property to be found. If null, + * the array of properties is returned instead. + * @return mixed Either an array of Zend_Gdata_Gapps_Extension_Property + * objects if $rel is null, a single + * Zend_Gdata_Gapps_Extension_Property object if $rel is specified + * and a matching feed link is found, or null if $rel is + * specified and no matching property is found. + */ + public function getProperty($rel = null) + { + if ($rel == null) { + return $this->_property; + } else { + foreach ($this->_property as $p) { + if ($p->rel == $rel) { + return $p; + } + } + return null; + } + } + + /** + * Set the value of the property property for this object. + * + * @param array $value A collection of + * Zend_Gdata_Gapps_Extension_Property objects. + * @return Zend_Gdata_Gapps_OwnerEntry Provides a fluent interface. + */ + public function setProperty($value) + { + $this->_property = $value; + return $this; + } + +} + diff --git a/Zend/Gdata/Gapps/OwnerFeed.php b/Zend/Gdata/Gapps/OwnerFeed.php new file mode 100644 index 00000000..7d627965 --- /dev/null +++ b/Zend/Gdata/Gapps/OwnerFeed.php @@ -0,0 +1,53 @@ +setGroupId($groupId); + $this->setOwnerEmail($ownerEmail); + } + + /** + * Set the group id to query for. + * + * @see getGroupId + * @param string $value + */ + public function setGroupId($value) + { + $this->_groupId = $value; + } + + /** + * Get the group id to query for. + * + * @return string + * + */ + public function getGroupId() + { + return $this->_groupId; + } + + /** + * Set the owner email to query for. + * + * @see getOwnerEmail + * @param string $value + */ + public function setOwnerEmail($value) + { + $this->_ownerEmail = $value; + } + + /** + * Get the owner email to query for. + * + * @return string + * + */ + public function getOwnerEmail() + { + return $this->_ownerEmail; + } + + /** + * Returns the query URL generated by this query instance. + * + * @return string The query URL for this instance. + */ + public function getQueryUrl() + { + $uri = Zend_Gdata_Gapps::APPS_BASE_FEED_URI; + $uri .= Zend_Gdata_Gapps::APPS_GROUP_PATH; + $uri .= '/' . $this->_domain; + if ($this->_groupId !== null) { + $uri .= '/' . $this->_groupId; + } else { + require_once 'Zend/Gdata/App/InvalidArgumentException.php'; + throw new Zend_Gdata_App_InvalidArgumentException( + 'groupId must not be null'); + } + + $uri .= '/owner'; + + if ($this->_ownerEmail !== null) { + $uri .= '/' . $this->_ownerEmail; + } + + $uri .= $this->getQueryString(); + return $uri; + } + +} diff --git a/Zend/Gdata/Gapps/Query.php b/Zend/Gdata/Gapps/Query.php new file mode 100644 index 00000000..96a0831b --- /dev/null +++ b/Zend/Gdata/Gapps/Query.php @@ -0,0 +1,123 @@ +_domain = $domain; + } + + /** + * Set domain for this service instance. This should be a fully qualified + * domain, such as 'foo.example.com'. + * + * This value is used when calculating URLs for retrieving and posting + * entries. If no value is specified, a URL will have to be manually + * constructed prior to using any methods which interact with the Google + * Apps provisioning service. + * + * @param string $value The domain to be used for this session. + */ + public function setDomain($value) + { + $this->_domain = $value; + } + + /** + * Get domain for this service instance. This should be a fully qualified + * domain, such as 'foo.example.com'. If no domain is set, null will be + * returned. + * + * @see setDomain + * @return string The domain to be used for this session, or null if not + * set. + */ + public function getDomain() + { + return $this->_domain; + } + + /** + * Returns the base URL used to access the Google Apps service, based + * on the current domain. The current domain can be temporarily + * overridden by providing a fully qualified domain as $domain. + * + * @see setDomain + * @param string $domain (optional) A fully-qualified domain to use + * instead of the default domain for this service instance. + */ + public function getBaseUrl($domain = null) + { + if ($domain !== null) { + return Zend_Gdata_Gapps::APPS_BASE_FEED_URI . '/' . $domain; + } + else if ($this->_domain !== null) { + return Zend_Gdata_Gapps::APPS_BASE_FEED_URI . '/' . $this->_domain; + } + else { + require_once 'Zend/Gdata/App/InvalidArgumentException.php'; + throw new Zend_Gdata_App_InvalidArgumentException( + 'Domain must be specified.'); + } + } + +} diff --git a/Zend/Gdata/Gapps/ServiceException.php b/Zend/Gdata/Gapps/ServiceException.php new file mode 100644 index 00000000..63e68df7 --- /dev/null +++ b/Zend/Gdata/Gapps/ServiceException.php @@ -0,0 +1,208 @@ +setErrors($errors); + } + } + + /** + * Add a single Error object to the list of errors received by the + * server. + * + * @param Zend_Gdata_Gapps_Error $error An instance of an error returned + * by the server. The error's errorCode must be set. + * @throws Zend_Gdata_App_Exception + */ + public function addError($error) { + // Make sure that we don't try to index an error that doesn't + // contain an index value. + if ($error->getErrorCode() == null) { + require_once 'Zend/Gdata/App/Exception.php'; + throw new Zend_Gdata_App_Exception("Error encountered without corresponding error code."); + } + + $this->_errors[$error->getErrorCode()] = $error; + } + + /** + * Set the list of errors as sent by the server inside of an + * AppsForYourDomainErrors tag. + * + * @param array $array An associative array containing a collection of + * Zend_Gdata_Gapps_Error objects. All errors must have their + * errorCode value set. + * @throws Zend_Gdata_App_Exception + */ + public function setErrors($array) { + $this->_errors = array(); + foreach ($array as $error) { + $this->addError($error); + } + } + + /** + * Get the list of errors as sent by the server inside of an + * AppsForYourDomainErrors tag. + * + * @return array An associative array containing a collection of + * Zend_Gdata_Gapps_Error objects, indexed by error code. + */ + public function getErrors() { + return $this->_errors; + } + + /** + * Return the Error object associated with a specific error code. + * + * @return Zend_Gdata_Gapps_Error The Error object requested, or null + * if not found. + */ + public function getError($errorCode) { + if (array_key_exists($errorCode, $this->_errors)) { + $result = $this->_errors[$errorCode]; + return $result; + } else { + return null; + } + } + + /** + * Check whether or not a particular error code was returned by the + * server. + * + * @param integer $errorCode The error code to check against. + * @return boolean Whether or not the supplied error code was returned + * by the server. + */ + public function hasError($errorCode) { + return array_key_exists($errorCode, $this->_errors); + } + + /** + * Import an AppsForYourDomain error from XML. + * + * @param string $string The XML data to be imported + * @return Zend_Gdata_Gapps_ServiceException Provides a fluent interface. + * @throws Zend_Gdata_App_Exception + */ + public function importFromString($string) { + if ($string) { + // Check to see if an AppsForYourDomainError exists + // + // track_errors is temporarily enabled so that if an error + // occurs while parsing the XML we can append it to an + // exception by referencing $php_errormsg + @ini_set('track_errors', 1); + $doc = new DOMDocument(); + $success = @$doc->loadXML($string); + @ini_restore('track_errors'); + + if (!$success) { + require_once 'Zend/Gdata/App/Exception.php'; + // $php_errormsg is automatically generated by PHP if + // an error occurs while calling loadXML(), above. + throw new Zend_Gdata_App_Exception("DOMDocument cannot parse XML: $php_errormsg"); + } + + // Ensure that the outermost node is an AppsForYourDomain error. + // If it isn't, something has gone horribly wrong. + $rootElement = $doc->getElementsByTagName($this->_rootElement)->item(0); + if (!$rootElement) { + require_once 'Zend/Gdata/App/Exception.php'; + throw new Zend_Gdata_App_Exception('No root <' . $this->_rootElement . '> element found, cannot parse feed.'); + } + + foreach ($rootElement->childNodes as $errorNode) { + if (!($errorNode instanceof DOMText)) { + $error = new Zend_Gdata_Gapps_Error(); + $error->transferFromDom($errorNode); + $this->addError($error); + } + } + return $this; + } else { + require_once 'Zend/Gdata/App/Exception.php'; + throw new Zend_Gdata_App_Exception('XML passed to transferFromXML cannot be null'); + } + + } + + /** + * Get a human readable version of this exception. + * + * @return string + */ + public function __toString() { + $result = "The server encountered the following errors processing the request:"; + foreach ($this->_errors as $error) { + $result .= "\n" . $error->__toString(); + } + return $result; + } +} diff --git a/Zend/Gdata/Gapps/UserEntry.php b/Zend/Gdata/Gapps/UserEntry.php new file mode 100644 index 00000000..7b652839 --- /dev/null +++ b/Zend/Gdata/Gapps/UserEntry.php @@ -0,0 +1,295 @@ + in the Google Data protocol. + * + * @category Zend + * @package Zend_Gdata + * @subpackage Gapps + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +class Zend_Gdata_Gapps_UserEntry extends Zend_Gdata_Entry +{ + + protected $_entryClassName = 'Zend_Gdata_Gapps_UserEntry'; + + /** + * element containing information about this user's + * account, including their username and permissions. + * + * @var Zend_Gdata_Gapps_Extension_Login + */ + protected $_login = null; + + /** + * element containing the user's actual name. + * + * @var Zend_Gdata_Gapps_Extension_Name + */ + protected $_name = null; + + /** + * element describing any storage quotas in place for + * this user. + * + * @var Zend_Gdata_Gapps_Extension_Quota + */ + protected $_quota = null; + + /** + * element containing information about other feeds + * relevant to this entry. + * + * @var Zend_Gdata_Extension_FeedLink + */ + protected $_feedLink = array(); + + /** + * Create a new instance. + * + * @param DOMElement $element (optional) DOMElement from which this + * object should be constructed. + */ + public function __construct($element = null) + { + $this->registerAllNamespaces(Zend_Gdata_Gapps::$namespaces); + parent::__construct($element); + } + + /** + * Retrieves a DOMElement which corresponds to this element and all + * child properties. This is used to build an entry back into a DOM + * and eventually XML text for application storage/persistence. + * + * @param DOMDocument $doc The DOMDocument used to construct DOMElements + * @return DOMElement The DOMElement representing this element and all + * child properties. + */ + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc, $majorVersion, $minorVersion); + if ($this->_login !== null) { + $element->appendChild($this->_login->getDOM($element->ownerDocument)); + } + if ($this->_name !== null) { + $element->appendChild($this->_name->getDOM($element->ownerDocument)); + } + if ($this->_quota !== null) { + $element->appendChild($this->_quota->getDOM($element->ownerDocument)); + } + foreach ($this->_feedLink as $feedLink) { + $element->appendChild($feedLink->getDOM($element->ownerDocument)); + } + return $element; + } + + /** + * Creates individual Entry objects of the appropriate type and + * stores them as members of this entry based upon DOM data. + * + * @param DOMNode $child The DOMNode to process + */ + protected function takeChildFromDOM($child) + { + $absoluteNodeName = $child->namespaceURI . ':' . $child->localName; + + switch ($absoluteNodeName) { + case $this->lookupNamespace('apps') . ':' . 'login'; + $login = new Zend_Gdata_Gapps_Extension_Login(); + $login->transferFromDOM($child); + $this->_login = $login; + break; + case $this->lookupNamespace('apps') . ':' . 'name'; + $name = new Zend_Gdata_Gapps_Extension_Name(); + $name->transferFromDOM($child); + $this->_name = $name; + break; + case $this->lookupNamespace('apps') . ':' . 'quota'; + $quota = new Zend_Gdata_Gapps_Extension_Quota(); + $quota->transferFromDOM($child); + $this->_quota = $quota; + break; + case $this->lookupNamespace('gd') . ':' . 'feedLink'; + $feedLink = new Zend_Gdata_Extension_FeedLink(); + $feedLink->transferFromDOM($child); + $this->_feedLink[] = $feedLink; + break; + default: + parent::takeChildFromDOM($child); + break; + } + } + + /** + * Get the value of the login property for this object. + * + * @see setLogin + * @return Zend_Gdata_Gapps_Extension_Login The requested object. + */ + public function getLogin() + { + return $this->_login; + } + + /** + * Set the value of the login property for this object. This property + * is used to store the username address of the current user. + * + * @param Zend_Gdata_Gapps_Extension_Login $value The desired value for + * this instance's login property. + * @return Zend_Gdata_Gapps_UserEntry Provides a fluent interface. + */ + public function setLogin($value) + { + $this->_login = $value; + return $this; + } + + /** + * Get the value of the name property for this object. + * + * @see setName + * @return Zend_Gdata_Gapps_Extension_Name The requested object. + */ + public function getName() + { + return $this->_name; + } + + /** + * Set the value of the name property for this object. This property + * is used to store the full name of the current user. + * + * @param Zend_Gdata_Gapps_Extension_Name $value The desired value for + * this instance's name property. + * @return Zend_Gdata_Gapps_UserEntry Provides a fluent interface. + */ + public function setName($value) + { + $this->_name = $value; + return $this; + } + + /** + * Get the value of the quota property for this object. + * + * @see setQuota + * @return Zend_Gdata_Gapps_Extension_Quota The requested object. + */ + public function getQuota() + { + return $this->_quota; + } + + /** + * Set the value of the quota property for this object. This property + * is used to store the amount of storage available for the current + * user. Quotas may not be modifiable depending on the domain used. + * + * @param Zend_Gdata_Gapps_Extension_Quota $value The desired value for + * this instance's quota property. + * @return Zend_Gdata_Gapps_UserEntry Provides a fluent interface. + */ + public function setQuota($value) + { + $this->_quota = $value; + return $this; + } + + /** + * Returns all feed links for this entry, or if a rel value is + * specified, the feed link associated with that value is returned. + * + * @param string $rel The rel value of the link to be found. If null, + * the array of links is returned instead. + * @return mixed Either an array of Zend_Gdata_Extension_FeedLink + * objects if $rel is null, a single + * Zend_Gdata_Extension_FeedLink object if $rel is specified + * and a matching feed link is found, or null if $rel is + * specified and no matching feed link is found. + */ + public function getFeedLink($rel = null) + { + if ($rel == null) { + return $this->_feedLink; + } else { + foreach ($this->_feedLink as $feedLink) { + if ($feedLink->rel == $rel) { + return $feedLink; + } + } + return null; + } + } + + /** + * Set the value of the feed link property for this object. This property + * is used to provide links to alternative feeds relevant to this entry. + * + * @param array $value A collection of + * Zend_Gdata_Gapps_Extension_FeedLink objects. + * @return Zend_Gdata_Gapps_EventEntry Provides a fluent interface. + */ + public function setFeedLink($value) + { + $this->_feedLink = $value; + return $this; + } + +} diff --git a/Zend/Gdata/Gapps/UserFeed.php b/Zend/Gdata/Gapps/UserFeed.php new file mode 100644 index 00000000..f186d053 --- /dev/null +++ b/Zend/Gdata/Gapps/UserFeed.php @@ -0,0 +1,53 @@ +setUsername($username); + $this->setStartUsername($startUsername); + } + + /** + * Set the username to query for. When set, only users with a username + * matching this value will be returned in search results. Set to + * null to disable filtering by username. + * + * @see getUsername + * @param string $value The username to filter search results by, or null to + * disable. + */ + public function setUsername($value) + { + $this->_username = $value; + } + + /** + * Get the username to query for. If no username is set, null will be + * returned. + * + * @param string $value The username to filter search results by, or + * null if disabled. + */ + public function getUsername() + { + return $this->_username; + } + + /** + * Set the first username which should be displayed when retrieving + * a list of users. + * + * @param string $value The first username to be returned, or null to + * disable. + */ + public function setStartUsername($value) + { + if ($value !== null) { + $this->_params['startUsername'] = $value; + } else { + unset($this->_params['startUsername']); + } + } + + /** + * Get the first username which should be displayed when retrieving + * a list of users. + * + * @see setStartUsername + * @return string The first username to be returned, or null if + * disabled. + */ + public function getStartUsername() + { + if (array_key_exists('startUsername', $this->_params)) { + return $this->_params['startUsername']; + } else { + return null; + } + } + + /** + * Returns the query URL generated by this query instance. + * + * @return string The query URL for this instance. + */ + public function getQueryUrl() + { + $uri = $this->getBaseUrl(); + $uri .= Zend_Gdata_Gapps::APPS_USER_PATH; + if ($this->_username !== null) { + $uri .= '/' . $this->_username; + } + $uri .= $this->getQueryString(); + return $uri; + } + +} diff --git a/Zend/Gdata/Gbase.php b/Zend/Gdata/Gbase.php new file mode 100644 index 00000000..160b74d0 --- /dev/null +++ b/Zend/Gdata/Gbase.php @@ -0,0 +1,209 @@ +registerPackage('Zend_Gdata_Gbase'); + $this->registerPackage('Zend_Gdata_Gbase_Extension'); + parent::__construct($client, $applicationId); + $this->_httpClient->setParameterPost('service', self::AUTH_SERVICE_NAME); + } + + /** + * Retreive feed object + * + * @param mixed $location The location for the feed, as a URL or Query + * @return Zend_Gdata_Gbase_ItemFeed + */ + public function getGbaseItemFeed($location = null) + { + if ($location === null) { + $uri = self::GBASE_ITEM_FEED_URI; + } else if ($location instanceof Zend_Gdata_Query) { + $uri = $location->getQueryUrl(); + } else { + $uri = $location; + } + return parent::getFeed($uri, 'Zend_Gdata_Gbase_ItemFeed'); + } + + /** + * Retreive entry object + * + * @param mixed $location The location for the feed, as a URL or Query + * @return Zend_Gdata_Gbase_ItemEntry + */ + public function getGbaseItemEntry($location = null) + { + if ($location === null) { + require_once 'Zend/Gdata/App/InvalidArgumentException.php'; + throw new Zend_Gdata_App_InvalidArgumentException( + 'Location must not be null'); + } else if ($location instanceof Zend_Gdata_Query) { + $uri = $location->getQueryUrl(); + } else { + $uri = $location; + } + return parent::getEntry($uri, 'Zend_Gdata_Gbase_ItemEntry'); + } + + /** + * Insert an entry + * + * @param Zend_Gdata_Gbase_ItemEntry $entry The Base entry to upload + * @param boolean $dryRun Flag for the 'dry-run' parameter + * @return Zend_Gdata_Gbase_ItemFeed + */ + public function insertGbaseItem($entry, $dryRun = false) + { + if ($dryRun == false) { + $uri = $this->_defaultPostUri; + } else { + $uri = $this->_defaultPostUri . '?dry-run=true'; + } + $newitem = $this->insertEntry($entry, $uri, 'Zend_Gdata_Gbase_ItemEntry'); + return $newitem; + } + + /** + * Update an entry + * + * @param Zend_Gdata_Gbase_ItemEntry $entry The Base entry to be updated + * @param boolean $dryRun Flag for the 'dry-run' parameter + * @return Zend_Gdata_Gbase_ItemEntry + */ + public function updateGbaseItem($entry, $dryRun = false) + { + $returnedEntry = $entry->save($dryRun); + return $returnedEntry; + } + + /** + * Delete an entry + * + * @param Zend_Gdata_Gbase_ItemEntry $entry The Base entry to remove + * @param boolean $dryRun Flag for the 'dry-run' parameter + * @return Zend_Gdata_Gbase_ItemFeed + */ + public function deleteGbaseItem($entry, $dryRun = false) + { + $entry->delete($dryRun); + return $this; + } + + /** + * Retrieve feed object + * + * @param mixed $location The location for the feed, as a URL or Query + * @return Zend_Gdata_Gbase_SnippetFeed + */ + public function getGbaseSnippetFeed($location = null) + { + if ($location === null) { + $uri = self::GBASE_SNIPPET_FEED_URI; + } else if ($location instanceof Zend_Gdata_Query) { + $uri = $location->getQueryUrl(); + } else { + $uri = $location; + } + return parent::getFeed($uri, 'Zend_Gdata_Gbase_SnippetFeed'); + } +} diff --git a/Zend/Gdata/Gbase/Entry.php b/Zend/Gdata/Gbase/Entry.php new file mode 100644 index 00000000..23a244a6 --- /dev/null +++ b/Zend/Gdata/Gbase/Entry.php @@ -0,0 +1,151 @@ +registerAllNamespaces(Zend_Gdata_Gbase::$namespaces); + parent::__construct($element); + } + + /** + * Retrieves a DOMElement which corresponds to this element and all + * child properties. This is used to build an entry back into a DOM + * and eventually XML text for application storage/persistence. + * + * @param DOMDocument $doc The DOMDocument used to construct DOMElements + * @return DOMElement The DOMElement representing this element and all + * child properties. + */ + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc, $majorVersion, $minorVersion); + foreach ($this->_baseAttributes as $baseAttribute) { + $element->appendChild($baseAttribute->getDOM($element->ownerDocument)); + } + return $element; + } + + /** + * Creates individual Entry objects of the appropriate type and + * stores them as members of this entry based upon DOM data. + * + * @param DOMNode $child The DOMNode to process + */ + protected function takeChildFromDOM($child) + { + $absoluteNodeName = $child->namespaceURI . ':' . $child->localName; + + if (strstr($absoluteNodeName, $this->lookupNamespace('g') . ':')) { + $baseAttribute = new Zend_Gdata_Gbase_Extension_BaseAttribute(); + $baseAttribute->transferFromDOM($child); + $this->_baseAttributes[] = $baseAttribute; + } else { + parent::takeChildFromDOM($child); + } + } + + /** + * Get the value of the itme_type + * + * @return Zend_Gdata_Gbase_Extension_ItemType The requested object. + */ + public function getItemType() + { + $itemType = $this->getGbaseAttribute('item_type'); + if (is_object($itemType[0])) { + return $itemType[0]; + } else { + return null; + } + } + + /** + * Return all the Base attributes + * @return Zend_Gdata_Gbase_Extension_BaseAttribute + */ + public function getGbaseAttributes() { + return $this->_baseAttributes; + } + + /** + * Return an array of Base attributes that match the given attribute name + * + * @param string $name The name of the Base attribute to look for + * @return array $matches Array that contains the matching list of Base attributes + */ + public function getGbaseAttribute($name) + { + $matches = array(); + for ($i = 0; $i < count($this->_baseAttributes); $i++) { + $baseAttribute = $this->_baseAttributes[$i]; + if ($baseAttribute->rootElement == $name && + $baseAttribute->rootNamespaceURI == $this->lookupNamespace('g')) { + $matches[] = &$this->_baseAttributes[$i]; + } + } + return $matches; + } + +} diff --git a/Zend/Gdata/Gbase/Extension/BaseAttribute.php b/Zend/Gdata/Gbase/Extension/BaseAttribute.php new file mode 100644 index 00000000..ddb63065 --- /dev/null +++ b/Zend/Gdata/Gbase/Extension/BaseAttribute.php @@ -0,0 +1,115 @@ +registerAllNamespaces(Zend_Gdata_Gbase::$namespaces); + if ($type !== null) { + $attr = array('name' => 'type', 'value' => $type); + $typeAttr = array('type' => $attr); + $this->setExtensionAttributes($typeAttr); + } + parent::__construct($name, + $this->_rootNamespace, + $this->lookupNamespace($this->_rootNamespace), + $text); + } + + /** + * Get the name of the attribute + * + * @return attribute name The requested object. + */ + public function getName() { + return $this->_rootElement; + } + + /** + * Get the type of the attribute + * + * @return attribute type The requested object. + */ + public function getType() { + $typeAttr = $this->getExtensionAttributes(); + return $typeAttr['type']['value']; + } + + /** + * Set the 'name' of the Base attribute object: + * <g:[$name] type='[$type]'>[$value]</g:[$name]> + * + * @param Zend_Gdata_App_Extension_Element $attribute The attribute object + * @param string $name The name of the Base attribute + * @return Zend_Gdata_Extension_ItemEntry Provides a fluent interface + */ + public function setName($name) { + $this->_rootElement = $name; + return $this; + } + + /** + * Set the 'type' of the Base attribute object: + * <g:[$name] type='[$type]'>[$value]</g:[$name]> + * + * @param Zend_Gdata_App_Extension_Element $attribute The attribute object + * @param string $type The type of the Base attribute + * @return Zend_Gdata_Extension_ItemEntry Provides a fluent interface + */ + public function setType($type) { + $attr = array('name' => 'type', 'value' => $type); + $typeAttr = array('type' => $attr); + $this->setExtensionAttributes($typeAttr); + return $this; + } + +} diff --git a/Zend/Gdata/Gbase/Feed.php b/Zend/Gdata/Gbase/Feed.php new file mode 100644 index 00000000..8706d045 --- /dev/null +++ b/Zend/Gdata/Gbase/Feed.php @@ -0,0 +1,60 @@ +registerAllNamespaces(Zend_Gdata_Gbase::$namespaces); + parent::__construct($element); + } +} diff --git a/Zend/Gdata/Gbase/ItemEntry.php b/Zend/Gdata/Gbase/ItemEntry.php new file mode 100644 index 00000000..f8bcbb10 --- /dev/null +++ b/Zend/Gdata/Gbase/ItemEntry.php @@ -0,0 +1,161 @@ +addGbaseAttribute('item_type', $value, 'text'); + return $this; + } + + /** + * Adds a custom attribute to the entry in the following format: + * <g:[$name] type='[$type]'>[$value]</g:[$name]> + * + * @param string $name The name of the attribute + * @param string $value The text value of the attribute + * @param string $type (optional) The type of the attribute. + * e.g.: 'text', 'number', 'floatUnit' + * @return Zend_Gdata_Gbase_ItemEntry Provides a fluent interface + */ + public function addGbaseAttribute($name, $text, $type = null) { + $newBaseAttribute = new Zend_Gdata_Gbase_Extension_BaseAttribute($name, $text, $type); + $this->_baseAttributes[] = $newBaseAttribute; + return $this; + } + + /** + * Removes a Base attribute from the current list of Base attributes + * + * @param Zend_Gdata_Gbase_Extension_BaseAttribute $baseAttribute The attribute to be removed + * @return Zend_Gdata_Gbase_ItemEntry Provides a fluent interface + */ + public function removeGbaseAttribute($baseAttribute) { + $baseAttributes = $this->_baseAttributes; + for ($i = 0; $i < count($this->_baseAttributes); $i++) { + if ($this->_baseAttributes[$i] == $baseAttribute) { + array_splice($baseAttributes, $i, 1); + break; + } + } + $this->_baseAttributes = $baseAttributes; + return $this; + } + + /** + * Uploads changes in this entry to the server using Zend_Gdata_App + * + * @param boolean $dryRun Whether the transaction is dry run or not. + * @param string|null $uri The URI to send requests to, or null if $data + * contains the URI. + * @param string|null $className The name of the class that should we + * deserializing the server response. If null, then + * 'Zend_Gdata_App_Entry' will be used. + * @param array $extraHeaders Extra headers to add to the request, as an + * array of string-based key/value pairs. + * @return Zend_Gdata_App_Entry The updated entry + * @throws Zend_Gdata_App_Exception + */ + public function save($dryRun = false, + $uri = null, + $className = null, + $extraHeaders = array()) + { + if ($dryRun == true) { + $editLink = $this->getEditLink(); + if ($uri == null && $editLink !== null) { + $uri = $editLink->getHref() . '?dry-run=true'; + } + if ($uri === null) { + require_once 'Zend/Gdata/App/InvalidArgumentException.php'; + throw new Zend_Gdata_App_InvalidArgumentException('You must specify an URI which needs deleted.'); + } + $service = new Zend_Gdata_App($this->getHttpClient()); + return $service->updateEntry($this, + $uri, + $className, + $extraHeaders); + } else { + parent::save($uri, $className, $extraHeaders); + } + } + + /** + * Deletes this entry to the server using the referenced + * Zend_Http_Client to do a HTTP DELETE to the edit link stored in this + * entry's link collection. + * + * @param boolean $dyrRun Whether the transaction is dry run or not + * @return void + * @throws Zend_Gdata_App_Exception + */ + public function delete($dryRun = false) + { + $uri = null; + + if ($dryRun == true) { + $editLink = $this->getEditLink(); + if ($editLink !== null) { + $uri = $editLink->getHref() . '?dry-run=true'; + } + if ($uri === null) { + require_once 'Zend/Gdata/App/InvalidArgumentException.php'; + throw new Zend_Gdata_App_InvalidArgumentException('You must specify an URI which needs deleted.'); + } + parent::delete($uri); + } else { + parent::delete(); + } + } + +} diff --git a/Zend/Gdata/Gbase/ItemFeed.php b/Zend/Gdata/Gbase/ItemFeed.php new file mode 100644 index 00000000..e71cc1cf --- /dev/null +++ b/Zend/Gdata/Gbase/ItemFeed.php @@ -0,0 +1,48 @@ +_id = $value; + return $this; + } + + /* + * @return string id + */ + public function getId() + { + return $this->_id; + } + + /** + * Returns the query URL generated by this query instance. + * + * @return string The query URL for this instance. + */ + public function getQueryUrl() + { + $uri = $this->_defaultFeedUri; + if ($this->getId() !== null) { + $uri .= '/' . $this->getId(); + } else { + $uri .= $this->getQueryString(); + } + return $uri; + } + +} diff --git a/Zend/Gdata/Gbase/Query.php b/Zend/Gdata/Gbase/Query.php new file mode 100644 index 00000000..e8064de6 --- /dev/null +++ b/Zend/Gdata/Gbase/Query.php @@ -0,0 +1,268 @@ +_params['key'] = $value; + } else { + unset($this->_params['key']); + } + return $this; + } + + /** + * @param string $value + * @return Zend_Gdata_Gbase_ItemQuery Provides a fluent interface + */ + public function setBq($value) + { + if ($value !== null) { + $this->_params['bq'] = $value; + } else { + unset($this->_params['bq']); + } + return $this; + } + + /** + * @param string $value + * @return Zend_Gdata_Gbase_ItemQuery Provides a fluent interface + */ + public function setRefine($value) + { + if ($value !== null) { + $this->_params['refine'] = $value; + } else { + unset($this->_params['refine']); + } + return $this; + } + + /** + * @param string $value + * @return Zend_Gdata_Gbase_ItemQuery Provides a fluent interface + */ + public function setContent($value) + { + if ($value !== null) { + $this->_params['content'] = $value; + } else { + unset($this->_params['content']); + } + return $this; + } + + /** + * @param string $value + * @return Zend_Gdata_Gbase_ItemQuery Provides a fluent interface + */ + public function setOrderBy($value) + { + if ($value !== null) { + $this->_params['orderby'] = $value; + } else { + unset($this->_params['orderby']); + } + return $this; + } + + /** + * @param string $value + * @return Zend_Gdata_Gbase_ItemQuery Provides a fluent interface + */ + public function setSortOrder($value) + { + if ($value !== null) { + $this->_params['sortorder'] = $value; + } else { + unset($this->_params['sortorder']); + } + return $this; + } + + /** + * @param string $value + * @return Zend_Gdata_Gbase_ItemQuery Provides a fluent interface + */ + public function setCrowdBy($value) + { + if ($value !== null) { + $this->_params['crowdby'] = $value; + } else { + unset($this->_params['crowdby']); + } + return $this; + } + + /** + * @param string $value + * @return Zend_Gdata_Gbase_ItemQuery Provides a fluent interface + */ + public function setAdjust($value) + { + if ($value !== null) { + $this->_params['adjust'] = $value; + } else { + unset($this->_params['adjust']); + } + return $this; + } + + /** + * @return string key + */ + public function getKey() + { + if (array_key_exists('key', $this->_params)) { + return $this->_params['key']; + } else { + return null; + } + } + + /** + * @return string bq + */ + public function getBq() + { + if (array_key_exists('bq', $this->_params)) { + return $this->_params['bq']; + } else { + return null; + } + } + + /** + * @return string refine + */ + public function getRefine() + { + if (array_key_exists('refine', $this->_params)) { + return $this->_params['refine']; + } else { + return null; + } + } + + /** + * @return string content + */ + public function getContent() + { + if (array_key_exists('content', $this->_params)) { + return $this->_params['content']; + } else { + return null; + } + } + + /** + * @return string orderby + */ + public function getOrderBy() + { + if (array_key_exists('orderby', $this->_params)) { + return $this->_params['orderby']; + } else { + return null; + } + } + + /** + * @return string sortorder + */ + public function getSortOrder() + { + if (array_key_exists('sortorder', $this->_params)) { + return $this->_params['sortorder']; + } else { + return null; + } + } + + /** + * @return string crowdby + */ + public function getCrowdBy() + { + if (array_key_exists('crowdby', $this->_params)) { + return $this->_params['crowdby']; + } else { + return null; + } + } + + /** + * @return string adjust + */ + public function getAdjust() + { + if (array_key_exists('adjust', $this->_params)) { + return $this->_params['adjust']; + } else { + return null; + } + } + +} diff --git a/Zend/Gdata/Gbase/SnippetEntry.php b/Zend/Gdata/Gbase/SnippetEntry.php new file mode 100644 index 00000000..0a443cc4 --- /dev/null +++ b/Zend/Gdata/Gbase/SnippetEntry.php @@ -0,0 +1,48 @@ +_defaultFeedUri; + if ($this->getCategory() !== null) { + $uri .= '/-/' . $this->getCategory(); + } + $uri .= $this->getQueryString(); + return $uri; + } + +} diff --git a/Zend/Gdata/Geo.php b/Zend/Gdata/Geo.php new file mode 100644 index 00000000..31634efc --- /dev/null +++ b/Zend/Gdata/Geo.php @@ -0,0 +1,70 @@ +registerPackage('Zend_Gdata_Geo'); + $this->registerPackage('Zend_Gdata_Geo_Extension'); + parent::__construct($client, $applicationId); + } + +} diff --git a/Zend/Gdata/Geo/Entry.php b/Zend/Gdata/Geo/Entry.php new file mode 100644 index 00000000..c9255e26 --- /dev/null +++ b/Zend/Gdata/Geo/Entry.php @@ -0,0 +1,97 @@ +registerAllNamespaces(Zend_Gdata_Geo::$namespaces); + parent::__construct($element); + } + + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc, $majorVersion, $minorVersion); + if ($this->_where != null) { + $element->appendChild($this->_where->getDOM($element->ownerDocument)); + } + return $element; + } + + protected function takeChildFromDOM($child) + { + $absoluteNodeName = $child->namespaceURI . ':' . $child->localName; + switch ($absoluteNodeName) { + case $this->lookupNamespace('georss') . ':' . 'where': + $where = new Zend_Gdata_Geo_Extension_GeoRssWhere(); + $where->transferFromDOM($child); + $this->_where = $where; + break; + default: + parent::takeChildFromDOM($child); + break; + } + } + + public function getWhere() + { + return $this->_where; + } + + public function setWhere($value) + { + $this->_where = $value; + return $this; + } + + +} diff --git a/Zend/Gdata/Geo/Extension/GeoRssWhere.php b/Zend/Gdata/Geo/Extension/GeoRssWhere.php new file mode 100644 index 00000000..89eb2d8b --- /dev/null +++ b/Zend/Gdata/Geo/Extension/GeoRssWhere.php @@ -0,0 +1,135 @@ +registerAllNamespaces(Zend_Gdata_Geo::$namespaces); + parent::__construct(); + $this->setPoint($point); + } + + /** + * Retrieves a DOMElement which corresponds to this element and all + * child properties. This is used to build an entry back into a DOM + * and eventually XML text for application storage/persistence. + * + * @param DOMDocument $doc The DOMDocument used to construct DOMElements + * @return DOMElement The DOMElement representing this element and all + * child properties. + */ + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc, $majorVersion, $minorVersion); + if ($this->_point !== null) { + $element->appendChild($this->_point->getDOM($element->ownerDocument)); + } + return $element; + } + + /** + * Creates individual Entry objects of the appropriate type and + * stores them as members of this entry based upon DOM data. + * + * @param DOMNode $child The DOMNode to process + */ + protected function takeChildFromDOM($child) + { + $absoluteNodeName = $child->namespaceURI . ':' . $child->localName; + + switch ($absoluteNodeName) { + case $this->lookupNamespace('gml') . ':' . 'Point'; + $point = new Zend_Gdata_Geo_Extension_GmlPoint(); + $point->transferFromDOM($child); + $this->_point = $point; + break; + } + } + + /** + * Get the value for this element's point attribute. + * + * @see setPoint + * @return Zend_Gdata_Geo_Extension_GmlPoint The requested attribute. + */ + public function getPoint() + { + return $this->_point; + } + + /** + * Set the value for this element's point attribute. + * + * @param Zend_Gdata_Geo_Extension_GmlPoint $value The desired value for this attribute. + * @return Zend_Gdata_Geo_Extension_GeoRssWhere Provides a fluent interface + */ + public function setPoint($value) + { + $this->_point = $value; + return $this; + } + +} diff --git a/Zend/Gdata/Geo/Extension/GmlPoint.php b/Zend/Gdata/Geo/Extension/GmlPoint.php new file mode 100644 index 00000000..7fec2c88 --- /dev/null +++ b/Zend/Gdata/Geo/Extension/GmlPoint.php @@ -0,0 +1,136 @@ +registerAllNamespaces(Zend_Gdata_Geo::$namespaces); + parent::__construct(); + $this->setPos($pos); + } + + /** + * Retrieves a DOMElement which corresponds to this element and all + * child properties. This is used to build an entry back into a DOM + * and eventually XML text for application storage/persistence. + * + * @param DOMDocument $doc The DOMDocument used to construct DOMElements + * @return DOMElement The DOMElement representing this element and all + * child properties. + */ + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc, $majorVersion, $minorVersion); + if ($this->_pos !== null) { + $element->appendChild($this->_pos->getDOM($element->ownerDocument)); + } + return $element; + } + + /** + * Creates individual Entry objects of the appropriate type and + * stores them as members of this entry based upon DOM data. + * + * @param DOMNode $child The DOMNode to process + */ + protected function takeChildFromDOM($child) + { + $absoluteNodeName = $child->namespaceURI . ':' . $child->localName; + + switch ($absoluteNodeName) { + case $this->lookupNamespace('gml') . ':' . 'pos'; + $pos = new Zend_Gdata_Geo_Extension_GmlPos(); + $pos->transferFromDOM($child); + $this->_pos = $pos; + break; + } + } + + /** + * Get the value for this element's pos attribute. + * + * @see setPos + * @return Zend_Gdata_Geo_Extension_GmlPos The requested attribute. + */ + public function getPos() + { + return $this->_pos; + } + + /** + * Set the value for this element's distance attribute. + * + * @param Zend_Gdata_Geo_Extension_GmlPos $value The desired value for this attribute + * @return Zend_Gdata_Geo_Extension_GmlPoint Provides a fluent interface + */ + public function setPos($value) + { + $this->_pos = $value; + return $this; + } + + +} diff --git a/Zend/Gdata/Geo/Extension/GmlPos.php b/Zend/Gdata/Geo/Extension/GmlPos.php new file mode 100644 index 00000000..16a5fad7 --- /dev/null +++ b/Zend/Gdata/Geo/Extension/GmlPos.php @@ -0,0 +1,61 @@ +registerAllNamespaces(Zend_Gdata_Geo::$namespaces); + parent::__construct(); + $this->setText($text); + } + +} diff --git a/Zend/Gdata/Geo/Feed.php b/Zend/Gdata/Geo/Feed.php new file mode 100644 index 00000000..bf9a0c26 --- /dev/null +++ b/Zend/Gdata/Geo/Feed.php @@ -0,0 +1,64 @@ +registerAllNamespaces(Zend_Gdata_Geo::$namespaces); + parent::__construct($element); + } + +} diff --git a/Zend/Gdata/Health.php b/Zend/Gdata/Health.php new file mode 100644 index 00000000..ee428b71 --- /dev/null +++ b/Zend/Gdata/Health.php @@ -0,0 +1,274 @@ + 'urn:astm-org:CCR', + 'batch' => 'http://schemas.google.com/gdata/batch', + 'h9m' => 'http://schemas.google.com/health/metadata', + 'gAcl' => 'http://schemas.google.com/acl/2007', + 'gd' => 'http://schemas.google.com/g/2005'); + + /** + * Create Zend_Gdata_Health object + * + * @param Zend_Http_Client $client (optional) The HTTP client to use when + * when communicating with the Google Health servers. + * @param string $applicationId The identity of the application in the form + * of Company-AppName-Version + * @param bool $useH9Sandbox True if the H9 Developer's Sandbox should be + * used instead of production Google Health. + */ + public function __construct($client = null, $applicationId = 'MyCompany-MyApp-1.0', $useH9Sandbox = false) + { + $this->registerPackage('Zend_Gdata_Health'); + $this->registerPackage('Zend_Gdata_Health_Extension_Ccr'); + parent::__construct($client, $applicationId); + $this->_useH9Sandbox = $useH9Sandbox; + } + + /** + * Gets the id of the user's profile + * + * @return string The profile id + */ + public function getProfileID() + { + return $this->_profileID; + } + + /** + * Sets which of the user's profiles will be used + * + * @param string $id The profile ID + * @return Zend_Gdata_Health Provides a fluent interface + */ + public function setProfileID($id) { + $this->_profileID = $id; + return $this; + } + + /** + * Retrieves the list of profiles associated with the user's ClientLogin + * credentials. + * + * @param string $query The query of the feed as a URL or Query object + * @return Zend_Gdata_Feed + */ + public function getHealthProfileListFeed($query = null) + { + if ($this->_httpClient->getClientLoginToken() === null) { + require_once 'Zend/Gdata/App/AuthException.php'; + throw new Zend_Gdata_App_AuthException( + 'Profiles list feed is only available when using ClientLogin'); + } + + if($query === null) { + $uri = self::CLIENTLOGIN_PROFILELIST_FEED_URI; + } else if ($query instanceof Zend_Gdata_Query) { + $uri = $query->getQueryUrl(); + } else { + $uri = $query; + } + + // use correct feed for /h9 or /health + if ($this->_useH9Sandbox) { + $uri = preg_replace('/\/health\//', '/h9/', $uri); + } + + return parent::getFeed($uri, 'Zend_Gdata_Health_ProfileListFeed'); + } + + /** + * Retrieve a user's profile as a feed object. If ClientLogin is used, the + * profile associated with $this->_profileID is returned, otherwise + * the profile associated with the AuthSub token is read. + * + * @param mixed $query The query for the feed, as a URL or Query + * @return Zend_Gdata_Health_ProfileFeed + */ + public function getHealthProfileFeed($query = null) + { + if ($this->_httpClient->getClientLoginToken() !== null && + $this->getProfileID() == null) { + require_once 'Zend/Gdata/App/AuthException.php'; + throw new Zend_Gdata_App_AuthException( + 'Profile ID must not be null. Did you call setProfileID()?'); + } + + if ($query instanceof Zend_Gdata_Query) { + $uri = $query->getQueryUrl(); + } else if ($this->_httpClient->getClientLoginToken() !== null && + $query == null) { + $uri = self::CLIENTLOGIN_PROFILE_FEED_URI . '/' . $this->getProfileID(); + } else if ($query === null) { + $uri = self::AUTHSUB_PROFILE_FEED_URI; + } else { + $uri = $query; + } + + // use correct feed for /h9 or /health + if ($this->_useH9Sandbox) { + $uri = preg_replace('/\/health\//', '/h9/', $uri); + } + + return parent::getFeed($uri, 'Zend_Gdata_Health_ProfileFeed'); + } + + /** + * Retrieve a profile entry object + * + * @param mixed $query The query for the feed, as a URL or Query + * @return Zend_Gdata_Health_ProfileEntry + */ + public function getHealthProfileEntry($query = null) + { + if ($query === null) { + require_once 'Zend/Gdata/App/InvalidArgumentException.php'; + throw new Zend_Gdata_App_InvalidArgumentException( + 'Query must not be null'); + } else if ($query instanceof Zend_Gdata_Query) { + $uri = $query->getQueryUrl(); + } else { + $uri = $query; + } + return parent::getEntry($uri, 'Zend_Gdata_Health_ProfileEntry'); + } + + /** + * Posts a new notice using the register feed. This function constructs + * the atom profile entry. + * + * @param string $subject The subject line of the notice + * @param string $body The message body of the notice + * @param string $bodyType The (optional) type of message body + * (text, xhtml, html, etc.) + * @param string $ccrXML The (optional) CCR to add to the user's profile + * @return Zend_Gdata_Health_ProfileEntry + */ + public function sendHealthNotice($subject, $body, $bodyType = null, $ccrXML = null) + { + if ($this->_httpClient->getClientLoginToken()) { + $profileID = $this->getProfileID(); + if ($profileID !== null) { + $uri = self::CLIENTLOGIN_REGISTER_FEED_URI . '/' . $profileID; + } else { + require_once 'Zend/Gdata/App/AuthException.php'; + throw new Zend_Gdata_App_AuthException( + 'Profile ID must not be null. Did you call setProfileID()?'); + } + } else { + $uri = self::AUTHSUB_REGISTER_FEED_URI; + } + + $entry = new Zend_Gdata_Health_ProfileEntry(); + $entry->title = $this->newTitle($subject); + $entry->content = $this->newContent($body); + $entry->content->type = $bodyType ? $bodyType : 'text'; + $entry->setCcr($ccrXML); + + // use correct feed for /h9 or /health + if ($this->_useH9Sandbox) { + $uri = preg_replace('/\/health\//', '/h9/', $uri); + } + + return $this->insertEntry($entry, $uri, 'Zend_Gdata_Health_ProfileEntry'); + } +} diff --git a/Zend/Gdata/Health/Extension/Ccr.php b/Zend/Gdata/Health/Extension/Ccr.php new file mode 100644 index 00000000..05bd8ca6 --- /dev/null +++ b/Zend/Gdata/Health/Extension/Ccr.php @@ -0,0 +1,124 @@ + $nsUri) { + $this->registerNamespace($nsPrefix, $nsUri); + } + } + + /** + * Transfers each child and attribute into member variables. + * This is called when XML is received over the wire and the data + * model needs to be built to represent this XML. + * + * @param DOMNode $node The DOMNode that represents this object's data + */ + public function transferFromDOM($node) + { + $this->_ccrDom = $node; + } + + /** + * Retrieves a DOMElement which corresponds to this element and all + * child properties. This is used to build an entry back into a DOM + * and eventually XML text for sending to the server upon updates, or + * for application storage/persistence. + * + * @param DOMDocument $doc The DOMDocument used to construct DOMElements + * @return DOMElement The DOMElement representing this element and all + * child properties. + */ + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + if ($doc === null) { + $doc = new DOMDocument('1.0', 'utf-8'); + } + $domElement = $doc->importNode($this->_ccrDom, true); + return $domElement; + } + + /** + * Magic helper that allows drilling down and returning specific elements + * in the CCR. For example, to retrieve the users medications + * (/ContinuityOfCareRecord/Body/Medications) from the entry's CCR, call + * $entry->getCcr()->getMedications(). Similarly, getConditions() would + * return extract the user's conditions. + * + * @param string $name Name of the function to call + * @param unknown $args + * @return array. A list of the appropriate CCR data + */ + public function __call($name, $args) + { + if (substr($name, 0, 3) === 'get') { + $category = substr($name, 3); + + switch ($category) { + case 'Conditions': + $category = 'Problems'; + break; + case 'Allergies': + $category = 'Alerts'; + break; + case 'TestResults': + // TestResults is an alias for LabResults + case 'LabResults': + $category = 'Results'; + break; + default: + // $category is already well formatted + } + + return $this->_ccrDom->getElementsByTagNameNS($this->lookupNamespace('ccr'), $category); + } else { + return null; + } + } +} diff --git a/Zend/Gdata/Health/ProfileEntry.php b/Zend/Gdata/Health/ProfileEntry.php new file mode 100644 index 00000000..8a00bf8a --- /dev/null +++ b/Zend/Gdata/Health/ProfileEntry.php @@ -0,0 +1,135 @@ + $nsUri) { + $this->registerNamespace($nsPrefix, $nsUri); + } + parent::__construct($element); + } + + /** + * Retrieves a DOMElement which corresponds to this element and all + * child properties. This is used to build an entry back into a DOM + * and eventually XML text for application storage/persistence. + * + * @param DOMDocument $doc The DOMDocument used to construct DOMElements + * @return DOMElement The DOMElement representing this element and all + * child properties. + */ + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc, $majorVersion, $minorVersion); + if ($this->_ccrData !== null) { + $element->appendChild($this->_ccrData->getDOM($element->ownerDocument)); + } + + return $element; + } + + /** + * Creates individual Entry objects of the appropriate type and + * stores them as members of this entry based upon DOM data. + * + * @param DOMNode $child The DOMNode to process + */ + protected function takeChildFromDOM($child) + { + $absoluteNodeName = $child->namespaceURI . ':' . $child->localName; + + if (strstr($absoluteNodeName, $this->lookupNamespace('ccr') . ':')) { + $ccrElement = new Zend_Gdata_Health_Extension_Ccr(); + $ccrElement->transferFromDOM($child); + $this->_ccrData = $ccrElement; + } else { + parent::takeChildFromDOM($child); + + } + } + + /** + * Sets the profile entry's CCR data + * @param string $ccrXMLStr The CCR as an xml string + * @return Zend_Gdata_Health_Extension_Ccr + */ + public function setCcr($ccrXMLStr) { + $ccrElement = null; + if ($ccrXMLStr != null) { + $ccrElement = new Zend_Gdata_Health_Extension_Ccr(); + $ccrElement->transferFromXML($ccrXMLStr); + $this->_ccrData = $ccrElement; + } + return $ccrElement; + } + + + /** + * Returns all the CCR data in a profile entry + * @return Zend_Gdata_Health_Extension_Ccr + */ + public function getCcr() { + return $this->_ccrData; + } +} diff --git a/Zend/Gdata/Health/ProfileFeed.php b/Zend/Gdata/Health/ProfileFeed.php new file mode 100644 index 00000000..769d96f8 --- /dev/null +++ b/Zend/Gdata/Health/ProfileFeed.php @@ -0,0 +1,67 @@ + $nsUri) { + $this->registerNamespace($nsPrefix, $nsUri); + } + parent::__construct($element); + } + + public function getEntries() + { + return $this->entry; + } +} diff --git a/Zend/Gdata/Health/ProfileListEntry.php b/Zend/Gdata/Health/ProfileListEntry.php new file mode 100644 index 00000000..ce84601e --- /dev/null +++ b/Zend/Gdata/Health/ProfileListEntry.php @@ -0,0 +1,100 @@ + + * @return string The profile id + */ + public function getProfileID() { + return $this->getContent()->text; + } + + /** + * Retrieves the profile's title, which is contained in + * @return string The profile name + */ + public function getProfileName() { + return $this->getTitle()->text; + } + +} diff --git a/Zend/Gdata/Health/ProfileListFeed.php b/Zend/Gdata/Health/ProfileListFeed.php new file mode 100644 index 00000000..055b8f73 --- /dev/null +++ b/Zend/Gdata/Health/ProfileListFeed.php @@ -0,0 +1,53 @@ +entry; + } +} diff --git a/Zend/Gdata/Health/Query.php b/Zend/Gdata/Health/Query.php new file mode 100644 index 00000000..f7fbda70 --- /dev/null +++ b/Zend/Gdata/Health/Query.php @@ -0,0 +1,285 @@ +_params['digest'] = $value; + } + return $this; + } + + /** + * Returns the digest parameter's value. + * + * @return string The value set for the digest parameter. + */ + public function getDigest() + { + if (array_key_exists('digest', $this->_params)) { + return $this->_params['digest']; + } else { + return null; + } + } + + /** + * Setter for category queries. + * + * @param string $item A category to query. + * @param string $name (optional) A specific item to search a category for. + * An example would be 'Lipitor' if $item is set to 'medication'. + * @return Zend_Gdata_Health_Query Provides a fluent interface + */ + public function setCategory($item, $name = null) + { + $this->_category = $item . + ($name ? '/' . urlencode('{' . self::ITEM_CATEGORY_NS . '}' . $name) : null); + return $this; + } + + /** + * Returns the query object's category. + * + * @return string id + */ + public function getCategory() + { + return $this->_category; + } + + /** + * Setter for the grouped parameter. + * + * @param string $value setting a count of results per group. + * @return Zend_Gdata_Health_Query Provides a fluent interface + */ + public function setGrouped($value) + { + if ($value !== null) { + $this->_params['grouped'] = $value; + } + return $this; + } + + /** + * Returns the value set for the grouped parameter. + * + * @return string grouped parameter. + */ + public function getGrouped() + { + if (array_key_exists('grouped', $this->_params)) { + return $this->_params['grouped']; + } else { + return null; + } + } + + /** + * Setter for the max-results-group parameter. + * + * @param int $value Specifies the maximum number of groups to be + * retrieved. Must be an integer value greater than zero. This parameter + * is only valid if grouped=true. + * @return Zend_Gdata_Health_Query Provides a fluent interface + */ + public function setMaxResultsGroup($value) + { + if ($value !== null) { + if ($value <= 0 || $this->getGrouped() !== 'true') { + require_once 'Zend/Gdata/App/InvalidArgumentException.php'; + throw new Zend_Gdata_App_InvalidArgumentException( + 'The max-results-group parameter must be set to a value + greater than 0 and can only be used if grouped=true'); + } else { + $this->_params['max-results-group'] = $value; + } + } + return $this; + } + + /** + * Returns the value set for max-results-group. + * + * @return int Returns max-results-group parameter. + */ + public function getMaxResultsGroup() + { + if (array_key_exists('max-results-group', $this->_params)) { + return $this->_params['max-results-group']; + } else { + return null; + } + } + + /** + * Setter for the max-results-group parameter. + * + * @param int $value Specifies the maximum number of records to be + * retrieved from each group. The limits that you specify with this + * parameter apply to all groups. Must be an integer value greater than + * zero. This parameter is only valid if grouped=true. + * @return Zend_Gdata_Health_Query Provides a fluent interface + */ + public function setMaxResultsInGroup($value) + { + if ($value !== null) { + if ($value <= 0 || $this->getGrouped() !== 'true') { + throw new Zend_Gdata_App_InvalidArgumentException( + 'The max-results-in-group parameter must be set to a value + greater than 0 and can only be used if grouped=true'); + } else { + $this->_params['max-results-in-group'] = $value; + } + } + return $this; + } + + /** + * Returns the value set for max-results-in-group. + * + * @return int Returns max-results-in-group parameter. + */ + public function getMaxResultsInGroup() + { + if (array_key_exists('max-results-in-group', $this->_params)) { + return $this->_params['max-results-in-group']; + } else { + return null; + } + } + + /** + * Setter for the start-index-group parameter. + * + * @param int $value Retrieves only items whose group ranking is at + * least start-index-group. This should be set to a 1-based index of the + * first group to be retrieved. The range is applied per category. + * This parameter is only valid if grouped=true. + * @return Zend_Gdata_Health_Query Provides a fluent interface + */ + public function setStartIndexGroup($value) + { + if ($value !== null && $this->getGrouped() !== 'true') { + throw new Zend_Gdata_App_InvalidArgumentException( + 'The start-index-group can only be used if grouped=true'); + } else { + $this->_params['start-index-group'] = $value; + } + return $this; + } + + /** + * Returns the value set for start-index-group. + * + * @return int Returns start-index-group parameter. + */ + public function getStartIndexGroup() + { + if (array_key_exists('start-index-group', $this->_params)) { + return $this->_params['start-index-group']; + } else { + return null; + } + } + + /** + * Setter for the start-index-in-group parameter. + * + * @param int $value A 1-based index of the records to be retrieved from + * each group. This parameter is only valid if grouped=true. + * @return Zend_Gdata_Health_Query Provides a fluent interface + */ + public function setStartIndexInGroup($value) + { + if ($value !== null && $this->getGrouped() !== 'true') { + throw new Zend_Gdata_App_InvalidArgumentException('start-index-in-group'); + } else { + $this->_params['start-index-in-group'] = $value; + } + return $this; + } + + /** + * Returns the value set for start-index-in-group. + * + * @return int Returns start-index-in-group parameter. + */ + public function getStartIndexInGroup() + { + if (array_key_exists('start-index-in-group', $this->_params)) { + return $this->_params['start-index-in-group']; + } else { + return null; + } + } +} diff --git a/Zend/Gdata/HttpAdapterStreamingProxy.php b/Zend/Gdata/HttpAdapterStreamingProxy.php new file mode 100644 index 00000000..1c48b849 --- /dev/null +++ b/Zend/Gdata/HttpAdapterStreamingProxy.php @@ -0,0 +1,127 @@ +config['proxy_host']) { + require_once 'Zend/Http/Client/Adapter/Exception.php'; + throw new Zend_Http_Client_Adapter_Exception('No proxy host set!'); + } + + // Make sure we're properly connected + if (! $this->socket) { + require_once 'Zend/Http/Client/Adapter/Exception.php'; + throw new Zend_Http_Client_Adapter_Exception( + 'Trying to write but we are not connected'); + } + + $host = $this->config['proxy_host']; + $port = $this->config['proxy_port']; + + if ($this->connected_to[0] != $host || $this->connected_to[1] != $port) { + require_once 'Zend/Http/Client/Adapter/Exception.php'; + throw new Zend_Http_Client_Adapter_Exception( + 'Trying to write but we are connected to the wrong proxy ' . + 'server'); + } + + // Add Proxy-Authorization header + if ($this->config['proxy_user'] && ! isset($headers['proxy-authorization'])) { + $headers['proxy-authorization'] = Zend_Http_Client::encodeAuthHeader( + $this->config['proxy_user'], $this->config['proxy_pass'], $this->config['proxy_auth'] + ); + } + + // if we are proxying HTTPS, preform CONNECT handshake with the proxy + if ($uri->getScheme() == 'https' && (! $this->negotiated)) { + $this->connectHandshake($uri->getHost(), $uri->getPort(), $http_ver, $headers); + $this->negotiated = true; + } + + // Save request method for later + $this->method = $method; + + // Build request headers + $request = "{$method} {$uri->__toString()} HTTP/{$http_ver}\r\n"; + + // Add all headers to the request string + foreach ($headers as $k => $v) { + if (is_string($k)) $v = "$k: $v"; + $request .= "$v\r\n"; + } + + $request .= "\r\n"; + + // Send the request headers + if (! @fwrite($this->socket, $request)) { + require_once 'Zend/Http/Client/Adapter/Exception.php'; + throw new Zend_Http_Client_Adapter_Exception( + 'Error writing request to proxy server'); + } + + //read from $body, write to socket + while ($body->hasData()) { + if (! @fwrite($this->socket, $body->read(self::CHUNK_SIZE))) { + require_once 'Zend/Http/Client/Adapter/Exception.php'; + throw new Zend_Http_Client_Adapter_Exception( + 'Error writing request to server'); + } + } + return 'Large upload, request is not cached.'; + } +} diff --git a/Zend/Gdata/HttpAdapterStreamingSocket.php b/Zend/Gdata/HttpAdapterStreamingSocket.php new file mode 100644 index 00000000..e1d5d2cc --- /dev/null +++ b/Zend/Gdata/HttpAdapterStreamingSocket.php @@ -0,0 +1,111 @@ +socket) { + require_once 'Zend/Http/Client/Adapter/Exception.php'; + throw new Zend_Http_Client_Adapter_Exception( + 'Trying to write but we are not connected'); + } + + $host = $uri->getHost(); + $host = (strtolower($uri->getScheme()) == 'https' ? $this->config['ssltransport'] : 'tcp') . '://' . $host; + if ($this->connected_to[0] != $host || $this->connected_to[1] != $uri->getPort()) { + require_once 'Zend/Http/Client/Adapter/Exception.php'; + throw new Zend_Http_Client_Adapter_Exception( + 'Trying to write but we are connected to the wrong host'); + } + + // Save request method for later + $this->method = $method; + + // Build request headers + $path = $uri->getPath(); + if ($uri->getQuery()) $path .= '?' . $uri->getQuery(); + $request = "{$method} {$path} HTTP/{$http_ver}\r\n"; + foreach ($headers as $k => $v) { + if (is_string($k)) $v = ucfirst($k) . ": $v"; + $request .= "$v\r\n"; + } + + // Send the headers over + $request .= "\r\n"; + if (! @fwrite($this->socket, $request)) { + require_once 'Zend/Http/Client/Adapter/Exception.php'; + throw new Zend_Http_Client_Adapter_Exception( + 'Error writing request to server'); + } + + + //read from $body, write to socket + $chunk = $body->read(self::CHUNK_SIZE); + while ($chunk !== FALSE) { + if (! @fwrite($this->socket, $chunk)) { + require_once 'Zend/Http/Client/Adapter/Exception.php'; + throw new Zend_Http_Client_Adapter_Exception( + 'Error writing request to server'); + } + $chunk = $body->read(self::CHUNK_SIZE); + } + $body->closeFileHandle(); + return 'Large upload, request is not cached.'; + } +} diff --git a/Zend/Gdata/HttpClient.php b/Zend/Gdata/HttpClient.php new file mode 100644 index 00000000..23022a94 --- /dev/null +++ b/Zend/Gdata/HttpClient.php @@ -0,0 +1,352 @@ +setAuthSubPrivateKey($key, $passphrase); + fclose($fp); + } + + /** + * Sets the PEM formatted private key to be used for secure AuthSub auth. + * + * In order to call this method, openssl must be enabled in your PHP + * installation. Otherwise, a Zend_Gdata_App_InvalidArgumentException + * will be thrown. + * + * @param string $key The private key + * @param string $passphrase The optional private key passphrase + * @throws Zend_Gdata_App_InvalidArgumentException + * @return Zend_Gdata_HttpClient Provides a fluent interface + */ + public function setAuthSubPrivateKey($key, $passphrase = null) { + if ($key != null && !function_exists('openssl_pkey_get_private')) { + require_once 'Zend/Gdata/App/InvalidArgumentException.php'; + throw new Zend_Gdata_App_InvalidArgumentException( + 'You cannot enable secure AuthSub if the openssl module ' . + 'is not enabled in your PHP installation.'); + } + $this->_authSubPrivateKeyId = openssl_pkey_get_private( + $key, $passphrase); + return $this; + } + + /** + * Gets the openssl private key id + * + * @return string The private key + */ + public function getAuthSubPrivateKeyId() { + return $this->_authSubPrivateKeyId; + } + + /** + * Gets the AuthSub token used for authentication + * + * @return string The token + */ + public function getAuthSubToken() { + return $this->_authSubToken; + } + + /** + * Sets the AuthSub token used for authentication + * + * @param string $token The token + * @return Zend_Gdata_HttpClient Provides a fluent interface + */ + public function setAuthSubToken($token) { + $this->_authSubToken = $token; + return $this; + } + + /** + * Gets the ClientLogin token used for authentication + * + * @return string The token + */ + public function getClientLoginToken() { + return $this->_clientLoginToken; + } + + /** + * Sets the ClientLogin token used for authentication + * + * @param string $token The token + * @return Zend_Gdata_HttpClient Provides a fluent interface + */ + public function setClientLoginToken($token) { + $this->_clientLoginToken = $token; + return $this; + } + + /** + * Filters the HTTP requests being sent to add the Authorization header. + * + * If both AuthSub and ClientLogin tokens are set, + * AuthSub takes precedence. If an AuthSub key is set, then + * secure AuthSub authentication is used, and the request is signed. + * Requests must be signed only with the private key corresponding to the + * public key registered with Google. If an AuthSub key is set, but + * openssl support is not enabled in the PHP installation, an exception is + * thrown. + * + * @param string $method The HTTP method + * @param string $url The URL + * @param array $headers An associate array of headers to be + * sent with the request or null + * @param string $body The body of the request or null + * @param string $contentType The MIME content type of the body or null + * @throws Zend_Gdata_App_Exception if there was a signing failure + * @return array The processed values in an associative array, + * using the same names as the params + */ + public function filterHttpRequest($method, $url, $headers = array(), $body = null, $contentType = null) { + if ($this->getAuthSubToken() != null) { + // AuthSub authentication + if ($this->getAuthSubPrivateKeyId() != null) { + // secure AuthSub + $time = time(); + $nonce = mt_rand(0, 999999999); + $dataToSign = $method . ' ' . $url . ' ' . $time . ' ' . $nonce; + + // compute signature + $pKeyId = $this->getAuthSubPrivateKeyId(); + $signSuccess = openssl_sign($dataToSign, $signature, $pKeyId, + OPENSSL_ALGO_SHA1); + if (!$signSuccess) { + require_once 'Zend/Gdata/App/Exception.php'; + throw new Zend_Gdata_App_Exception( + 'openssl_signing failure - returned false'); + } + // encode signature + $encodedSignature = base64_encode($signature); + + // final header + $headers['authorization'] = 'AuthSub token="' . $this->getAuthSubToken() . '" ' . + 'data="' . $dataToSign . '" ' . + 'sig="' . $encodedSignature . '" ' . + 'sigalg="rsa-sha1"'; + } else { + // AuthSub without secure tokens + $headers['authorization'] = 'AuthSub token="' . $this->getAuthSubToken() . '"'; + } + } elseif ($this->getClientLoginToken() != null) { + $headers['authorization'] = 'GoogleLogin auth=' . $this->getClientLoginToken(); + } + return array('method' => $method, 'url' => $url, 'body' => $body, 'headers' => $headers, 'contentType' => $contentType); + } + + /** + * Method for filtering the HTTP response, though no filtering is + * currently done. + * + * @param Zend_Http_Response $response The response object to filter + * @return Zend_Http_Response The filterd response object + */ + public function filterHttpResponse($response) { + return $response; + } + + /** + * Return the current connection adapter + * + * @return Zend_Http_Client_Adapter_Interface|string $adapter + */ + public function getAdapter() + { + return $this->adapter; + } + + /** + * Load the connection adapter + * + * @param Zend_Http_Client_Adapter_Interface $adapter + * @return void + */ + public function setAdapter($adapter) + { + if ($adapter == null) { + $this->adapter = $adapter; + } else { + parent::setAdapter($adapter); + } + } + + /** + * Set the streamingRequest variable which controls whether we are + * sending the raw (already encoded) POST data from a stream source. + * + * @param boolean $value The value to set. + * @return void + */ + public function setStreamingRequest($value) + { + $this->_streamingRequest = $value; + } + + /** + * Check whether the client is set to perform streaming requests. + * + * @return boolean True if yes, false otherwise. + */ + public function getStreamingRequest() + { + if ($this->_streamingRequest()) { + return true; + } else { + return false; + } + } + + /** + * Prepare the request body (for POST and PUT requests) + * + * @return string + * @throws Zend_Http_Client_Exception + */ + protected function _prepareBody() + { + if($this->_streamingRequest) { + $this->setHeaders(self::CONTENT_LENGTH, + $this->raw_post_data->getTotalSize()); + return $this->raw_post_data; + } + else { + return parent::_prepareBody(); + } + } + + /** + * Clear all custom parameters we set. + * + * @return Zend_Http_Client + */ + public function resetParameters($clearAll = false) + { + $this->_streamingRequest = false; + + return parent::resetParameters($clearAll); + } + + /** + * Set the raw (already encoded) POST data from a stream source. + * + * This is used to support POSTing from open file handles without + * caching the entire body into memory. It is a wrapper around + * Zend_Http_Client::setRawData(). + * + * @param string $data The request data + * @param string $enctype The encoding type + * @return Zend_Http_Client + */ + public function setRawDataStream($data, $enctype = null) + { + $this->_streamingRequest = true; + return $this->setRawData($data, $enctype); + } + +} diff --git a/Zend/Gdata/Kind/EventEntry.php b/Zend/Gdata/Kind/EventEntry.php new file mode 100644 index 00000000..bc55de65 --- /dev/null +++ b/Zend/Gdata/Kind/EventEntry.php @@ -0,0 +1,428 @@ +_who != null) { + foreach ($this->_who as $who) { + $element->appendChild($who->getDOM($element->ownerDocument)); + } + } + if ($this->_when != null) { + foreach ($this->_when as $when) { + $element->appendChild($when->getDOM($element->ownerDocument)); + } + } + if ($this->_where != null) { + foreach ($this->_where as $where) { + $element->appendChild($where->getDOM($element->ownerDocument)); + } + } + if ($this->_recurrenceException != null) { + foreach ($this->_recurrenceException as $recurrenceException) { + $element->appendChild($recurrenceException->getDOM($element->ownerDocument)); + } + } + if ($this->_extendedProperty != null) { + foreach ($this->_extendedProperty as $extProp) { + $element->appendChild($extProp->getDOM($element->ownerDocument)); + } + } + + if ($this->_recurrence != null) { + $element->appendChild($this->_recurrence->getDOM($element->ownerDocument)); + } + if ($this->_eventStatus != null) { + $element->appendChild($this->_eventStatus->getDOM($element->ownerDocument)); + } + if ($this->_comments != null) { + $element->appendChild($this->_comments->getDOM($element->ownerDocument)); + } + if ($this->_transparency != null) { + $element->appendChild($this->_transparency->getDOM($element->ownerDocument)); + } + if ($this->_visibility != null) { + $element->appendChild($this->_visibility->getDOM($element->ownerDocument)); + } + if ($this->_originalEvent != null) { + $element->appendChild($this->_originalEvent->getDOM($element->ownerDocument)); + } + if ($this->_entryLink != null) { + $element->appendChild($this->_entryLink->getDOM($element->ownerDocument)); + } + + + return $element; + } + + protected function takeChildFromDOM($child) + { + $absoluteNodeName = $child->namespaceURI . ':' . $child->localName; + switch ($absoluteNodeName) { + case $this->lookupNamespace('gd') . ':' . 'where'; + $where = new Zend_Gdata_Extension_Where(); + $where->transferFromDOM($child); + $this->_where[] = $where; + break; + case $this->lookupNamespace('gd') . ':' . 'when'; + $when = new Zend_Gdata_Extension_When(); + $when->transferFromDOM($child); + $this->_when[] = $when; + break; + case $this->lookupNamespace('gd') . ':' . 'who'; + $who = new Zend_Gdata_Extension_Who(); + $who ->transferFromDOM($child); + $this->_who[] = $who; + break; + case $this->lookupNamespace('gd') . ':' . 'recurrence'; + $recurrence = new Zend_Gdata_Extension_Recurrence(); + $recurrence->transferFromDOM($child); + $this->_recurrence = $recurrence; + break; + case $this->lookupNamespace('gd') . ':' . 'eventStatus'; + $eventStatus = new Zend_Gdata_Extension_EventStatus(); + $eventStatus->transferFromDOM($child); + $this->_eventStatus = $eventStatus; + break; + case $this->lookupNamespace('gd') . ':' . 'comments'; + $comments = new Zend_Gdata_Extension_Comments(); + $comments->transferFromDOM($child); + $this->_comments = $comments; + break; + case $this->lookupNamespace('gd') . ':' . 'transparency'; + $transparency = new Zend_Gdata_Extension_Transparency(); + $transparency ->transferFromDOM($child); + $this->_transparency = $transparency; + break; + case $this->lookupNamespace('gd') . ':' . 'visibility'; + $visiblity = new Zend_Gdata_Extension_Visibility(); + $visiblity ->transferFromDOM($child); + $this->_visibility = $visiblity; + break; + case $this->lookupNamespace('gd') . ':' . 'recurrenceException'; + require_once 'Zend/Gdata/Extension/RecurrenceException.php'; + $recurrenceException = new Zend_Gdata_Extension_RecurrenceException(); + $recurrenceException ->transferFromDOM($child); + $this->_recurrenceException[] = $recurrenceException; + break; + case $this->lookupNamespace('gd') . ':' . 'originalEvent'; + $originalEvent = new Zend_Gdata_Extension_OriginalEvent(); + $originalEvent ->transferFromDOM($child); + $this->_originalEvent = $originalEvent; + break; + case $this->lookupNamespace('gd') . ':' . 'extendedProperty'; + $extProp = new Zend_Gdata_Extension_ExtendedProperty(); + $extProp->transferFromDOM($child); + $this->_extendedProperty[] = $extProp; + break; + case $this->lookupNamespace('gd') . ':' . 'entryLink': + $entryLink = new Zend_Gdata_Extension_EntryLink(); + $entryLink->transferFromDOM($child); + $this->_entryLink = $entryLink; + break; + + default: + parent::takeChildFromDOM($child); + break; + } + } + + public function getWhen() + { + return $this->_when; + } + + /** + * @param array $value + * @return Zend_Gdata_Kind_EventEntry Provides a fluent interface + */ + public function setWhen($value) + { + $this->_when = $value; + return $this; + } + + public function getWhere() + { + return $this->_where; + } + + /** + * @param array $value + * @return Zend_Gdata_Kind_EventEntry Provides a fluent interface + */ + public function setWhere($value) + { + $this->_where = $value; + return $this; + } + + public function getWho() + { + return $this->_who; + } + + /** + * @param array $value + * @return Zend_Gdata_Kind_EventEntry Provides a fluent interface + */ + public function setWho($value) + { + $this->_who = $value; + return $this; + } + + public function getRecurrence() + { + return $this->_recurrence; + } + + /** + * @param array $value + * @return Zend_Gdata_Kind_EventEntry Provides a fluent interface + */ + public function setRecurrence($value) + { + $this->_recurrence = $value; + return $this; + } + + public function getEventStatus() + { + return $this->_eventStatus; + } + + /** + * @param array $value + * @return Zend_Gdata_Kind_EventEntry Provides a fluent interface + */ + public function setEventStatus($value) + { + $this->_eventStatus = $value; + return $this; + } + + public function getComments() + { + return $this->_comments; + } + + /** + * @param array $value + * @return Zend_Gdata_Kind_EventEntry Provides a fluent interface + */ + public function setComments($value) + { + $this->_comments = $value; + return $this; + } + + public function getTransparency() + { + return $this->_transparency; + } + + /** + * @param Zend_Gdata_Transparency $value + * @return Zend_Gdata_Kind_EventEntry Provides a fluent interface + */ + public function setTransparency($value) + { + $this->_transparency = $value; + return $this; + } + + public function getVisibility() + { + return $this->_visibility; + } + + /** + * @param Zend_Gdata_Visibility $value + * @return Zend_Gdata_Kind_EventEntry Provides a fluent interface + */ + public function setVisibility($value) + { + $this->_visibility = $value; + return $this; + } + + public function getRecurrenceExcption() + { + return $this->_recurrenceException; + } + + /** + * @param array $value + * @return Zend_Gdata_Kind_EventEntry Provides a fluent interface + */ + public function setRecurrenceException($value) + { + $this->_recurrenceException = $value; + return $this; + } + + public function getExtendedProperty() + { + return $this->_extendedProperty; + } + + /** + * @param array $value + * @return Zend_Gdata_Kind_EventEntry Provides a fluent interface + */ + public function setExtendedProperty($value) + { + $this->_extendedProperty = $value; + return $this; + } + + public function getOriginalEvent() + { + return $this->_originalEvent; + } + + /** + * @param Zend_Gdata_Extension_OriginalEvent $value + * @return Zend_Gdata_Kind_EventEntry Provides a fluent interface + */ + public function setOriginalEvent($value) + { + $this->_originalEvent = $value; + return $this; + } + + /** + * Get this entry's EntryLink element. + * + * @return Zend_Gdata_Extension_EntryLink The requested entry. + */ + public function getEntryLink() + { + return $this->_entryLink; + } + + /** + * Set the child's EntryLink element. + * + * @param Zend_Gdata_Extension_EntryLink $value The desired value for this attribute. + * @return Zend_Gdata_Extension_Who The element being modified. + */ + public function setEntryLink($value) + { + $this->_entryLink = $value; + return $this; + } + + +} diff --git a/Zend/Gdata/Media.php b/Zend/Gdata/Media.php new file mode 100644 index 00000000..b8b4aee7 --- /dev/null +++ b/Zend/Gdata/Media.php @@ -0,0 +1,65 @@ +registerPackage('Zend_Gdata_Media'); + $this->registerPackage('Zend_Gdata_Media_Extension'); + parent::__construct($client, $applicationId); + } + +} diff --git a/Zend/Gdata/Media/Entry.php b/Zend/Gdata/Media/Entry.php new file mode 100644 index 00000000..1315f9a9 --- /dev/null +++ b/Zend/Gdata/Media/Entry.php @@ -0,0 +1,134 @@ +registerAllNamespaces(Zend_Gdata_Media::$namespaces); + parent::__construct($element); + } + + /** + * Retrieves a DOMElement which corresponds to this element and all + * child properties. This is used to build an entry back into a DOM + * and eventually XML text for application storage/persistence. + * + * @param DOMDocument $doc The DOMDocument used to construct DOMElements + * @return DOMElement The DOMElement representing this element and all + * child properties. + */ + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc, $majorVersion, $minorVersion); + if ($this->_mediaGroup != null) { + $element->appendChild($this->_mediaGroup->getDOM($element->ownerDocument)); + } + return $element; + } + + /** + * Creates individual Entry objects of the appropriate type and + * stores them as members of this entry based upon DOM data. + * + * @param DOMNode $child The DOMNode to process + */ + protected function takeChildFromDOM($child) + { + $absoluteNodeName = $child->namespaceURI . ':' . $child->localName; + switch ($absoluteNodeName) { + case $this->lookupNamespace('media') . ':' . 'group': + $mediaGroup = new Zend_Gdata_Media_Extension_MediaGroup(); + $mediaGroup->transferFromDOM($child); + $this->_mediaGroup = $mediaGroup; + break; + default: + parent::takeChildFromDOM($child); + break; + } + } + + /** + * Returns the entry's mediaGroup object. + * + * @return Zend_Gdata_Media_Extension_MediaGroup + */ + public function getMediaGroup() + { + return $this->_mediaGroup; + } + + /** + * Sets the entry's mediaGroup object. + * + * @param Zend_Gdata_Media_Extension_MediaGroup $mediaGroup + * @return Zend_Gdata_Media_Entry Provides a fluent interface + */ + public function setMediaGroup($mediaGroup) + { + $this->_mediaGroup = $mediaGroup; + return $this; + } + + +} diff --git a/Zend/Gdata/Media/Extension/MediaCategory.php b/Zend/Gdata/Media/Extension/MediaCategory.php new file mode 100644 index 00000000..1852f584 --- /dev/null +++ b/Zend/Gdata/Media/Extension/MediaCategory.php @@ -0,0 +1,148 @@ +registerAllNamespaces(Zend_Gdata_Media::$namespaces); + parent::__construct(); + $this->_text = $text; + $this->_scheme = $scheme; + $this->_label = $label; + } + + /** + * Retrieves a DOMElement which corresponds to this element and all + * child properties. This is used to build an entry back into a DOM + * and eventually XML text for sending to the server upon updates, or + * for application storage/persistence. + * + * @param DOMDocument $doc The DOMDocument used to construct DOMElements + * @return DOMElement The DOMElement representing this element and all + * child properties. + */ + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc, $majorVersion, $minorVersion); + if ($this->_scheme !== null) { + $element->setAttribute('scheme', $this->_scheme); + } + if ($this->_label !== null) { + $element->setAttribute('label', $this->_label); + } + return $element; + } + + /** + * Given a DOMNode representing an attribute, tries to map the data into + * instance members. If no mapping is defined, the name and value are + * stored in an array. + * + * @param DOMNode $attribute The DOMNode attribute needed to be handled + */ + protected function takeAttributeFromDOM($attribute) + { + switch ($attribute->localName) { + case 'scheme': + $this->_scheme = $attribute->nodeValue; + break; + case 'label': + $this->_label = $attribute->nodeValue; + break; + default: + parent::takeAttributeFromDOM($attribute); + } + } + + /** + * Returns the URI that identifies the categorization scheme + * Optional. + * + * @return string URI that identifies the categorization scheme + */ + public function getScheme() + { + return $this->_scheme; + } + + /** + * @param string $value URI that identifies the categorization scheme + * @return Zend_Gdata_Media_Extension_MediaCategory Provides a fluent interface + */ + public function setScheme($value) + { + $this->_scheme = $value; + return $this; + } + + /** + * @return string Human-readable label to be displayed in applications + */ + public function getLabel() + { + return $this->_label; + } + + /** + * @param string $value Human-readable label to be displayed in applications + * @return Zend_Gdata_Media_Extension_MediaCategory Provides a fluent interface + */ + public function setLabel($value) + { + $this->_label = $value; + return $this; + } + +} diff --git a/Zend/Gdata/Media/Extension/MediaContent.php b/Zend/Gdata/Media/Extension/MediaContent.php new file mode 100644 index 00000000..88d7cc94 --- /dev/null +++ b/Zend/Gdata/Media/Extension/MediaContent.php @@ -0,0 +1,522 @@ +registerAllNamespaces(Zend_Gdata_Media::$namespaces); + parent::__construct(); + $this->_url = $url; + $this->_fileSize = $fileSize; + $this->_type = $type; + $this->_medium = $medium; + $this->_isDefault = $isDefault; + $this->_expression = $expression; + $this->_bitrate = $bitrate; + $this->_framerate = $framerate; + $this->_samplingrate = $samplingrate; + $this->_channels = $channels; + $this->_duration = $duration; + $this->_height = $height; + $this->_width = $width; + $this->_lang = $lang; + } + + + /** + * Retrieves a DOMElement which corresponds to this element and all + * child properties. This is used to build an entry back into a DOM + * and eventually XML text for sending to the server upon updates, or + * for application storage/persistence. + * + * @param DOMDocument $doc The DOMDocument used to construct DOMElements + * @return DOMElement The DOMElement representing this element and all + * child properties. + */ + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc, $majorVersion, $minorVersion); + if ($this->_url !== null) { + $element->setAttribute('url', $this->_url); + } + if ($this->_fileSize !== null) { + $element->setAttribute('fileSize', $this->_fileSize); + } + if ($this->_type !== null) { + $element->setAttribute('type', $this->_type); + } + if ($this->_medium !== null) { + $element->setAttribute('medium', $this->_medium); + } + if ($this->_isDefault !== null) { + $element->setAttribute('isDefault', $this->_isDefault); + } + if ($this->_expression !== null) { + $element->setAttribute('expression', $this->_expression); + } + if ($this->_bitrate !== null) { + $element->setAttribute('bitrate', $this->_bitrate); + } + if ($this->_framerate !== null) { + $element->setAttribute('framerate', $this->_framerate); + } + if ($this->_samplingrate !== null) { + $element->setAttribute('samplingrate', $this->_samplingrate); + } + if ($this->_channels !== null) { + $element->setAttribute('channels', $this->_channels); + } + if ($this->_duration !== null) { + $element->setAttribute('duration', $this->_duration); + } + if ($this->_height !== null) { + $element->setAttribute('height', $this->_height); + } + if ($this->_width !== null) { + $element->setAttribute('width', $this->_width); + } + if ($this->_lang !== null) { + $element->setAttribute('lang', $this->_lang); + } + return $element; + } + + /** + * Given a DOMNode representing an attribute, tries to map the data into + * instance members. If no mapping is defined, the name and value are + * stored in an array. + * + * @param DOMNode $attribute The DOMNode attribute needed to be handled + */ + protected function takeAttributeFromDOM($attribute) + { + switch ($attribute->localName) { + case 'url': + $this->_url = $attribute->nodeValue; + break; + case 'fileSize': + $this->_fileSize = $attribute->nodeValue; + break; + case 'type': + $this->_type = $attribute->nodeValue; + break; + case 'medium': + $this->_medium = $attribute->nodeValue; + break; + case 'isDefault': + $this->_isDefault = $attribute->nodeValue; + break; + case 'expression': + $this->_expression = $attribute->nodeValue; + break; + case 'bitrate': + $this->_bitrate = $attribute->nodeValue; + break; + case 'framerate': + $this->_framerate = $attribute->nodeValue; + break; + case 'samplingrate': + $this->_samplingrate = $attribute->nodeValue; + break; + case 'channels': + $this->_channels = $attribute->nodeValue; + break; + case 'duration': + $this->_duration = $attribute->nodeValue; + break; + case 'height': + $this->_height = $attribute->nodeValue; + break; + case 'width': + $this->_width = $attribute->nodeValue; + break; + case 'lang': + $this->_lang = $attribute->nodeValue; + break; + default: + parent::takeAttributeFromDOM($attribute); + } + } + + /** + * Returns the URL representing this MediaContent object + * + * @return string The URL representing this MediaContent object. + */ + public function __toString() + { + return $this->getUrl(); + } + + /** + * @return string The direct URL to the media object + */ + public function getUrl() + { + return $this->_url; + } + + /** + * @param string $value The direct URL to the media object + * @return Zend_Gdata_Media_Extension_MediaContent Provides a fluent interface + */ + public function setUrl($value) + { + $this->_url = $value; + return $this; + } + + /** + * @return int The size of the media in bytes + */ + public function getFileSize() + { + return $this->_fileSize; + } + + /** + * @param int $value + * @return Zend_Gdata_Media_Extension_MediaContent Provides a fluent interface + */ + public function setFileSize($value) + { + $this->_fileSize = $value; + return $this; + } + + /** + * @return string + */ + public function getType() + { + return $this->_type; + } + + /** + * @param string $value + * @return Zend_Gdata_Media_Extension_MediaContent Provides a fluent interface + */ + public function setType($value) + { + $this->_type = $value; + return $this; + } + + /** + * @return string + */ + public function getMedium() + { + return $this->_medium; + } + + /** + * @param string $value + * @return Zend_Gdata_Media_Extension_MediaContent Provides a fluent interface + */ + public function setMedium($value) + { + $this->_medium = $value; + return $this; + } + + /** + * @return bool + */ + public function getIsDefault() + { + return $this->_isDefault; + } + + /** + * @param bool $value + * @return Zend_Gdata_Media_Extension_MediaContent Provides a fluent interface + */ + public function setIsDefault($value) + { + $this->_isDefault = $value; + return $this; + } + + /** + * @return string + */ + public function getExpression() + { + return $this->_expression; + } + + /** + * @param string + * @return Zend_Gdata_Media_Extension_MediaContent Provides a fluent interface + */ + public function setExpression($value) + { + $this->_expression = $value; + return $this; + } + + /** + * @return int + */ + public function getBitrate() + { + return $this->_bitrate; + } + + /** + * @param int + * @return Zend_Gdata_Media_Extension_MediaContent Provides a fluent interface + */ + public function setBitrate($value) + { + $this->_bitrate = $value; + return $this; + } + + /** + * @return int + */ + public function getFramerate() + { + return $this->_framerate; + } + + /** + * @param int + * @return Zend_Gdata_Media_Extension_MediaContent Provides a fluent interface + */ + public function setFramerate($value) + { + $this->_framerate = $value; + return $this; + } + + /** + * @return int + */ + public function getSamplingrate() + { + return $this->_samplingrate; + } + + /** + * @param int + * @return Zend_Gdata_Media_Extension_MediaContent Provides a fluent interface + */ + public function setSamplingrate($value) + { + $this->_samplingrate = $value; + return $this; + } + + /** + * @return int + */ + public function getChannels() + { + return $this->_channels; + } + + /** + * @param int + * @return Zend_Gdata_Media_Extension_MediaContent Provides a fluent interface + */ + public function setChannels($value) + { + $this->_channels = $value; + return $this; + } + + /** + * @return int + */ + public function getDuration() + { + return $this->_duration; + } + + /** + * + * @param int + * @return Zend_Gdata_Media_Extension_MediaContent Provides a fluent interface + */ + public function setDuration($value) + { + $this->_duration = $value; + return $this; + } + + /** + * @return int + */ + public function getHeight() + { + return $this->_height; + } + + /** + * @param int + * @return Zend_Gdata_Media_Extension_MediaContent Provides a fluent interface + */ + public function setHeight($value) + { + $this->_height = $value; + return $this; + } + + /** + * @return int + */ + public function getWidth() + { + return $this->_width; + } + + /** + * @param int + * @return Zend_Gdata_Media_Extension_MediaContent Provides a fluent interface + */ + public function setWidth($value) + { + $this->_width = $value; + return $this; + } + + /** + * @return string + */ + public function getLang() + { + return $this->_lang; + } + + /** + * @param string + * @return Zend_Gdata_Media_Extension_MediaContent Provides a fluent interface + */ + public function setLang($value) + { + $this->_lang = $value; + return $this; + } + +} diff --git a/Zend/Gdata/Media/Extension/MediaCopyright.php b/Zend/Gdata/Media/Extension/MediaCopyright.php new file mode 100644 index 00000000..4e88cff9 --- /dev/null +++ b/Zend/Gdata/Media/Extension/MediaCopyright.php @@ -0,0 +1,116 @@ +registerAllNamespaces(Zend_Gdata_Media::$namespaces); + parent::__construct(); + $this->_text = $text; + $this->_url = $url; + } + + /** + * Retrieves a DOMElement which corresponds to this element and all + * child properties. This is used to build an entry back into a DOM + * and eventually XML text for sending to the server upon updates, or + * for application storage/persistence. + * + * @param DOMDocument $doc The DOMDocument used to construct DOMElements + * @return DOMElement The DOMElement representing this element and all + * child properties. + */ + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc, $majorVersion, $minorVersion); + if ($this->_url !== null) { + $element->setAttribute('url', $this->_url); + } + return $element; + } + + /** + * Given a DOMNode representing an attribute, tries to map the data into + * instance members. If no mapping is defined, the name and value are + * stored in an array. + * + * @param DOMNode $attribute The DOMNode attribute needed to be handled + */ + protected function takeAttributeFromDOM($attribute) + { + switch ($attribute->localName) { + case 'url': + $this->_url = $attribute->nodeValue; + break; + default: + parent::takeAttributeFromDOM($attribute); + } + } + + /** + * @return string + */ + public function getUrl() + { + return $this->_url; + } + + /** + * @param string $value + * @return Zend_Gdata_Media_Extension_MediaCopyright Provides a fluent interface + */ + public function setUrl($value) + { + $this->_url = $value; + return $this; + } + +} diff --git a/Zend/Gdata/Media/Extension/MediaCredit.php b/Zend/Gdata/Media/Extension/MediaCredit.php new file mode 100644 index 00000000..84172c35 --- /dev/null +++ b/Zend/Gdata/Media/Extension/MediaCredit.php @@ -0,0 +1,149 @@ +registerAllNamespaces(Zend_Gdata_Media::$namespaces); + parent::__construct(); + $this->_text = $text; + $this->_role = $role; + $this->_scheme = $scheme; + } + + /** + * Retrieves a DOMElement which corresponds to this element and all + * child properties. This is used to build an entry back into a DOM + * and eventually XML text for sending to the server upon updates, or + * for application storage/persistence. + * + * @param DOMDocument $doc The DOMDocument used to construct DOMElements + * @return DOMElement The DOMElement representing this element and all + * child properties. + */ + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc, $majorVersion, $minorVersion); + if ($this->_role !== null) { + $element->setAttribute('role', $this->_role); + } + if ($this->_scheme !== null) { + $element->setAttribute('scheme', $this->_scheme); + } + return $element; + } + + /** + * Given a DOMNode representing an attribute, tries to map the data into + * instance members. If no mapping is defined, the name and value are + * stored in an array. + * + * @param DOMNode $attribute The DOMNode attribute needed to be handled + */ + protected function takeAttributeFromDOM($attribute) + { + switch ($attribute->localName) { + case 'role': + $this->_role = $attribute->nodeValue; + break; + case 'scheme': + $this->_scheme = $attribute->nodeValue; + break; + default: + parent::takeAttributeFromDOM($attribute); + } + } + + /** + * @return string + */ + public function getRole() + { + return $this->_role; + } + + /** + * @param string $value + * @return Zend_Gdata_Media_Extension_MediaCredit Provides a fluent interface + */ + public function setRole($value) + { + $this->_role = $value; + return $this; + } + + /** + * @return string + */ + public function getScheme() + { + return $this->_scheme; + } + + /** + * @param string $value + * @return Zend_Gdata_Media_Extension_MediaCredit Provides a fluent interface + */ + public function setScheme($value) + { + $this->_scheme = $value; + return $this; + } + +} diff --git a/Zend/Gdata/Media/Extension/MediaDescription.php b/Zend/Gdata/Media/Extension/MediaDescription.php new file mode 100644 index 00000000..6f57e304 --- /dev/null +++ b/Zend/Gdata/Media/Extension/MediaDescription.php @@ -0,0 +1,116 @@ +registerAllNamespaces(Zend_Gdata_Media::$namespaces); + parent::__construct(); + $this->_type = $type; + $this->_text = $text; + } + + /** + * Retrieves a DOMElement which corresponds to this element and all + * child properties. This is used to build an entry back into a DOM + * and eventually XML text for sending to the server upon updates, or + * for application storage/persistence. + * + * @param DOMDocument $doc The DOMDocument used to construct DOMElements + * @return DOMElement The DOMElement representing this element and all + * child properties. + */ + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc, $majorVersion, $minorVersion); + if ($this->_type !== null) { + $element->setAttribute('type', $this->_type); + } + return $element; + } + + /** + * Given a DOMNode representing an attribute, tries to map the data into + * instance members. If no mapping is defined, the name and value are + * stored in an array. + * + * @param DOMNode $attribute The DOMNode attribute needed to be handled + */ + protected function takeAttributeFromDOM($attribute) + { + switch ($attribute->localName) { + case 'type': + $this->_type = $attribute->nodeValue; + break; + default: + parent::takeAttributeFromDOM($attribute); + } + } + + /** + * @return string + */ + public function getType() + { + return $this->_type; + } + + /** + * @param string $value + * @return Zend_Gdata_Media_Extension_MediaDescription Provides a fluent interface + */ + public function setType($value) + { + $this->_type = $value; + return $this; + } + +} diff --git a/Zend/Gdata/Media/Extension/MediaGroup.php b/Zend/Gdata/Media/Extension/MediaGroup.php new file mode 100644 index 00000000..d890115a --- /dev/null +++ b/Zend/Gdata/Media/Extension/MediaGroup.php @@ -0,0 +1,566 @@ +registerAllNamespaces(Zend_Gdata_Media::$namespaces); + parent::__construct($element); + } + + /** + * Retrieves a DOMElement which corresponds to this element and all + * child properties. This is used to build an entry back into a DOM + * and eventually XML text for sending to the server upon updates, or + * for application storage/persistence. + * + * @param DOMDocument $doc The DOMDocument used to construct DOMElements + * @return DOMElement The DOMElement representing this element and all + * child properties. + */ + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc, $majorVersion, $minorVersion); + foreach ($this->_content as $content) { + $element->appendChild($content->getDOM($element->ownerDocument)); + } + foreach ($this->_category as $category) { + $element->appendChild($category->getDOM($element->ownerDocument)); + } + foreach ($this->_credit as $credit) { + $element->appendChild($credit->getDOM($element->ownerDocument)); + } + foreach ($this->_player as $player) { + $element->appendChild($player->getDOM($element->ownerDocument)); + } + foreach ($this->_rating as $rating) { + $element->appendChild($rating->getDOM($element->ownerDocument)); + } + foreach ($this->_restriction as $restriction) { + $element->appendChild($restriction->getDOM($element->ownerDocument)); + } + foreach ($this->_mediaText as $text) { + $element->appendChild($text->getDOM($element->ownerDocument)); + } + foreach ($this->_thumbnail as $thumbnail) { + $element->appendChild($thumbnail->getDOM($element->ownerDocument)); + } + if ($this->_copyright != null) { + $element->appendChild( + $this->_copyright->getDOM($element->ownerDocument)); + } + if ($this->_description != null) { + $element->appendChild( + $this->_description->getDOM($element->ownerDocument)); + } + foreach ($this->_hash as $hash) { + $element->appendChild($hash->getDOM($element->ownerDocument)); + } + if ($this->_keywords != null) { + $element->appendChild( + $this->_keywords->getDOM($element->ownerDocument)); + } + if ($this->_title != null) { + $element->appendChild( + $this->_title->getDOM($element->ownerDocument)); + } + return $element; + } + + /** + * Creates individual Entry objects of the appropriate type and + * stores them in the $_entry array based upon DOM data. + * + * @param DOMNode $child The DOMNode to process + */ + protected function takeChildFromDOM($child) + { + $absoluteNodeName = $child->namespaceURI . ':' . $child->localName; + switch ($absoluteNodeName) { + case $this->lookupNamespace('media') . ':' . 'content'; + $content = new Zend_Gdata_Media_Extension_MediaContent(); + $content->transferFromDOM($child); + $this->_content[] = $content; + break; + case $this->lookupNamespace('media') . ':' . 'category'; + $category = new Zend_Gdata_Media_Extension_MediaCategory(); + $category->transferFromDOM($child); + $this->_category[] = $category; + break; + case $this->lookupNamespace('media') . ':' . 'copyright'; + $copyright = new Zend_Gdata_Media_Extension_MediaCopyright(); + $copyright->transferFromDOM($child); + $this->_copyright = $copyright; + break; + case $this->lookupNamespace('media') . ':' . 'credit'; + $credit = new Zend_Gdata_Media_Extension_MediaCredit(); + $credit->transferFromDOM($child); + $this->_credit[] = $credit; + break; + case $this->lookupNamespace('media') . ':' . 'description'; + $description = new Zend_Gdata_Media_Extension_MediaDescription(); + $description->transferFromDOM($child); + $this->_description = $description; + break; + case $this->lookupNamespace('media') . ':' . 'hash'; + $hash = new Zend_Gdata_Media_Extension_MediaHash(); + $hash->transferFromDOM($child); + $this->_hash[] = $hash; + break; + case $this->lookupNamespace('media') . ':' . 'keywords'; + $keywords = new Zend_Gdata_Media_Extension_MediaKeywords(); + $keywords->transferFromDOM($child); + $this->_keywords = $keywords; + break; + case $this->lookupNamespace('media') . ':' . 'player'; + $player = new Zend_Gdata_Media_Extension_MediaPlayer(); + $player->transferFromDOM($child); + $this->_player[] = $player; + break; + case $this->lookupNamespace('media') . ':' . 'rating'; + $rating = new Zend_Gdata_Media_Extension_MediaRating(); + $rating->transferFromDOM($child); + $this->_rating[] = $rating; + break; + case $this->lookupNamespace('media') . ':' . 'restriction'; + $restriction = new Zend_Gdata_Media_Extension_MediaRestriction(); + $restriction->transferFromDOM($child); + $this->_restriction[] = $restriction; + break; + case $this->lookupNamespace('media') . ':' . 'text'; + $text = new Zend_Gdata_Media_Extension_MediaText(); + $text->transferFromDOM($child); + $this->_mediaText[] = $text; + break; + case $this->lookupNamespace('media') . ':' . 'thumbnail'; + $thumbnail = new Zend_Gdata_Media_Extension_MediaThumbnail(); + $thumbnail->transferFromDOM($child); + $this->_thumbnail[] = $thumbnail; + break; + case $this->lookupNamespace('media') . ':' . 'title'; + $title = new Zend_Gdata_Media_Extension_MediaTitle(); + $title->transferFromDOM($child); + $this->_title = $title; + break; + default: + parent::takeChildFromDOM($child); + break; + } + } + + /** + * @return array + */ + public function getContent() + { + return $this->_content; + } + + /** + * @param array $value + * @return Zend_Gdata_Media_MediaGroup Provides a fluent interface + */ + public function setContent($value) + { + $this->_content = $value; + return $this; + } + + /** + * @return array + */ + public function getCategory() + { + return $this->_category; + } + + /** + * @param array $value + * @return Zend_Gdata_Media_Extension_MediaGroup + */ + public function setCategory($value) + { + $this->_category = $value; + return $this; + } + + /** + * @return Zend_Gdata_Media_Extension_MediaCopyright + */ + public function getCopyright() + { + return $this->_copyright; + } + + /** + * @param Zend_Gdata_Media_Extension_MediaCopyright $value + * @return Zend_Gdata_Media_Extension_MediaGroup + */ + public function setCopyright($value) + { + $this->_copyright = $value; + return $this; + } + + /** + * @return array + */ + public function getCredit() + { + return $this->_credit; + } + + /** + * @param array $value + * @return Zend_Gdata_Media_Extension_MediaGroup + */ + public function setCredit($value) + { + $this->_credit = $value; + return $this; + } + + /** + * @return Zend_Gdata_Media_Extension_MediaTitle + */ + public function getTitle() + { + return $this->_title; + } + + /** + * @param Zend_Gdata_Media_Extension_MediaTitle $value + * @return Zend_Gdata_Media_Extension_MediaGroup + */ + public function setTitle($value) + { + $this->_title = $value; + return $this; + } + + /** + * @return Zend_Gdata_Media_Extension_MediaDescription + */ + public function getDescription() + { + return $this->_description; + } + + /** + * @param Zend_Gdata_Media_Extension_MediaDescription $value + * @return Zend_Gdata_Media_Extension_MediaGroup + */ + public function setDescription($value) + { + $this->_description = $value; + return $this; + } + + /** + * @return array + */ + public function getHash() + { + return $this->_hash; + } + + /** + * @param array $value + * @return Zend_Gdata_Media_Extension_MediaGroup + */ + public function setHash($value) + { + $this->_hash = $value; + return $this; + } + + /** + * @return Zend_Gdata_Media_Extension_MediaKeywords + */ + public function getKeywords() + { + return $this->_keywords; + } + + /** + * @param array $value + * @return Zend_Gdata_Media_Extension_MediaGroup Provides a fluent interface + */ + public function setKeywords($value) + { + $this->_keywords = $value; + return $this; + } + + /** + * @return array + */ + public function getPlayer() + { + return $this->_player; + } + + /** + * @param array + * @return Zend_Gdata_Media_Extension_MediaGroup + */ + public function setPlayer($value) + { + $this->_player = $value; + return $this; + } + + /** + * @return array + */ + public function getRating() + { + return $this->_rating; + } + + /** + * @param array + * @return Zend_Gdata_Media_Extension_MediaGroup + */ + public function setRating($value) + { + $this->_rating = $value; + return $this; + } + + /** + * @return array + */ + public function getRestriction() + { + return $this->_restriction; + } + + /** + * @param array + * @return Zend_Gdata_Media_Extension_MediaGroup + */ + public function setRestriction($value) + { + $this->_restriction = $value; + return $this; + } + + /** + * @return array + */ + public function getThumbnail() + { + return $this->_thumbnail; + } + + /** + * @param array + * @return Zend_Gdata_Media_Extension_MediaGroup + */ + public function setThumbnail($value) + { + $this->_thumbnail = $value; + return $this; + } + + /** + * @return array + */ + public function getMediaText() + { + return $this->_mediaText; + } + + /** + * @param array + * @return Zend_Gdata_Media_Extension_MediaGroup + */ + public function setMediaText($value) + { + $this->_mediaText = $value; + return $this; + } + +} diff --git a/Zend/Gdata/Media/Extension/MediaHash.php b/Zend/Gdata/Media/Extension/MediaHash.php new file mode 100644 index 00000000..a348630c --- /dev/null +++ b/Zend/Gdata/Media/Extension/MediaHash.php @@ -0,0 +1,115 @@ +registerAllNamespaces(Zend_Gdata_Media::$namespaces); + parent::__construct(); + $this->_text = $text; + $this->_algo = $algo; + } + + /** + * Retrieves a DOMElement which corresponds to this element and all + * child properties. This is used to build an entry back into a DOM + * and eventually XML text for sending to the server upon updates, or + * for application storage/persistence. + * + * @param DOMDocument $doc The DOMDocument used to construct DOMElements + * @return DOMElement The DOMElement representing this element and all + * child properties. + */ + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc, $majorVersion, $minorVersion); + if ($this->_algo !== null) { + $element->setAttribute('algo', $this->_algo); + } + return $element; + } + + /** + * Given a DOMNode representing an attribute, tries to map the data into + * instance members. If no mapping is defined, the name and value are + * stored in an array. + * + * @param DOMNode $attribute The DOMNode attribute needed to be handled + * @throws Zend_Gdata_App_InvalidArgumentException + */ + protected function takeAttributeFromDOM($attribute) + { + switch ($attribute->localName) { + case 'algo': + $this->_algo = $attribute->nodeValue; + break; + default: + parent::takeAttributeFromDOM($attribute); + } + } + + /** + * @return string The algo + */ + public function getAlgo() + { + return $this->_algo; + } + + /** + * @param string $value + * @return Zend_Gdata_Media_Extension_MediaHash Provides a fluent interface + */ + public function setAlgo($value) + { + $this->_algo = $value; + return $this; + } + +} diff --git a/Zend/Gdata/Media/Extension/MediaKeywords.php b/Zend/Gdata/Media/Extension/MediaKeywords.php new file mode 100644 index 00000000..309359c6 --- /dev/null +++ b/Zend/Gdata/Media/Extension/MediaKeywords.php @@ -0,0 +1,52 @@ +registerAllNamespaces(Zend_Gdata_Media::$namespaces); + parent::__construct(); + } + +} diff --git a/Zend/Gdata/Media/Extension/MediaPlayer.php b/Zend/Gdata/Media/Extension/MediaPlayer.php new file mode 100644 index 00000000..07439d90 --- /dev/null +++ b/Zend/Gdata/Media/Extension/MediaPlayer.php @@ -0,0 +1,178 @@ +registerAllNamespaces(Zend_Gdata_Media::$namespaces); + parent::__construct(); + $this->_url = $url; + $this->_width = $width; + $this->_height = $height; + } + + /** + * Retrieves a DOMElement which corresponds to this element and all + * child properties. This is used to build an entry back into a DOM + * and eventually XML text for sending to the server upon updates, or + * for application storage/persistence. + * + * @param DOMDocument $doc The DOMDocument used to construct DOMElements + * @return DOMElement The DOMElement representing this element and all + * child properties. + */ + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc, $majorVersion, $minorVersion); + if ($this->_url !== null) { + $element->setAttribute('url', $this->_url); + } + if ($this->_width !== null) { + $element->setAttribute('width', $this->_width); + } + if ($this->_height !== null) { + $element->setAttribute('height', $this->_height); + } + return $element; + } + + /** + * Given a DOMNode representing an attribute, tries to map the data into + * instance members. If no mapping is defined, the name and value are + * stored in an array. + * + * @param DOMNode $attribute The DOMNode attribute needed to be handled + */ + protected function takeAttributeFromDOM($attribute) + { + switch ($attribute->localName) { + case 'url': + $this->_url = $attribute->nodeValue; + break; + case 'width': + $this->_width = $attribute->nodeValue; + break; + case 'height': + $this->_height = $attribute->nodeValue; + break; + default: + parent::takeAttributeFromDOM($attribute); + } + } + + /** + * @return string + */ + public function getUrl() + { + return $this->_url; + } + + /** + * @param string $value + * @return Zend_Gdata_Media_Extension_MediaPlayer Provides a fluent interface + */ + public function setUrl($value) + { + $this->_url = $value; + return $this; + } + + /** + * @return int + */ + public function getWidth() + { + return $this->_width; + } + + /** + * @param int $value + * @return Zend_Gdata_Media_Extension_MediaPlayer Provides a fluent interface + */ + public function setWidth($value) + { + $this->_width = $value; + return $this; + } + + /** + * @return int + */ + public function getHeight() + { + return $this->_height; + } + + /** + * @param int $value + * @return Zend_Gdata_Media_Extension_MediaPlayer Provides a fluent interface + */ + public function setHeight($value) + { + $this->_height = $value; + return $this; + } + +} diff --git a/Zend/Gdata/Media/Extension/MediaRating.php b/Zend/Gdata/Media/Extension/MediaRating.php new file mode 100644 index 00000000..33cf1e41 --- /dev/null +++ b/Zend/Gdata/Media/Extension/MediaRating.php @@ -0,0 +1,118 @@ +registerAllNamespaces(Zend_Gdata_Media::$namespaces); + parent::__construct(); + $this->_scheme = $scheme; + $this->_text = $text; + } + + /** + * Retrieves a DOMElement which corresponds to this element and all + * child properties. This is used to build an entry back into a DOM + * and eventually XML text for sending to the server upon updates, or + * for application storage/persistence. + * + * @param DOMDocument $doc The DOMDocument used to construct DOMElements + * @return DOMElement The DOMElement representing this element and all + * child properties. + */ + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc, $majorVersion, $minorVersion); + if ($this->_scheme !== null) { + $element->setAttribute('scheme', $this->_scheme); + } + return $element; + } + + /** + * Given a DOMNode representing an attribute, tries to map the data into + * instance members. If no mapping is defined, the name and value are + * stored in an array. + * + * @param DOMNode $attribute The DOMNode attribute needed to be handled + */ + protected function takeAttributeFromDOM($attribute) + { + switch ($attribute->localName) { + case 'scheme': + $this->_scheme = $attribute->nodeValue; + break; + default: + parent::takeAttributeFromDOM($attribute); + } + } + + /** + * @return string + */ + public function getScheme() + { + return $this->_scheme; + } + + /** + * @param string $value + * @return Zend_Gdata_Media_Extension_MediaRating Provides a fluent interface + */ + public function setScheme($value) + { + $this->_scheme = $value; + return $this; + } + +} diff --git a/Zend/Gdata/Media/Extension/MediaRestriction.php b/Zend/Gdata/Media/Extension/MediaRestriction.php new file mode 100644 index 00000000..971419ad --- /dev/null +++ b/Zend/Gdata/Media/Extension/MediaRestriction.php @@ -0,0 +1,149 @@ +registerAllNamespaces(Zend_Gdata_Media::$namespaces); + parent::__construct(); + $this->_text = $text; + $this->_relationship = $relationship; + $this->_type = $type; + } + + /** + * Retrieves a DOMElement which corresponds to this element and all + * child properties. This is used to build an entry back into a DOM + * and eventually XML text for sending to the server upon updates, or + * for application storage/persistence. + * + * @param DOMDocument $doc The DOMDocument used to construct DOMElements + * @return DOMElement The DOMElement representing this element and all + * child properties. + */ + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc, $majorVersion, $minorVersion); + if ($this->_relationship !== null) { + $element->setAttribute('relationship', $this->_relationship); + } + if ($this->_type !== null) { + $element->setAttribute('type', $this->_type); + } + return $element; + } + + /** + * Given a DOMNode representing an attribute, tries to map the data into + * instance members. If no mapping is defined, the name and value are + * stored in an array. + * + * @param DOMNode $attribute The DOMNode attribute needed to be handled + */ + protected function takeAttributeFromDOM($attribute) + { + switch ($attribute->localName) { + case 'relationship': + $this->_relationship = $attribute->nodeValue; + break; + case 'type': + $this->_type = $attribute->nodeValue; + break; + default: + parent::takeAttributeFromDOM($attribute); + } + } + + /** + * @return string + */ + public function getRelationship() + { + return $this->_relationship; + } + + /** + * @param string $value + * @return Zend_Gdata_Media_Extension_MediaRestriction Provides a fluent interface + */ + public function setRelationship($value) + { + $this->_relationship = $value; + return $this; + } + + /** + * @return string + */ + public function getType() + { + return $this->_type; + } + + /** + * @param string $value + * @return Zend_Gdata_Media_Extension_MediaRestriction Provides a fluent interface + */ + public function setType($value) + { + $this->_type = $value; + return $this; + } + +} diff --git a/Zend/Gdata/Media/Extension/MediaText.php b/Zend/Gdata/Media/Extension/MediaText.php new file mode 100644 index 00000000..67329428 --- /dev/null +++ b/Zend/Gdata/Media/Extension/MediaText.php @@ -0,0 +1,211 @@ +registerAllNamespaces(Zend_Gdata_Media::$namespaces); + parent::__construct(); + $this->_text = $text; + $this->_type = $type; + $this->_lang = $lang; + $this->_start = $start; + $this->_end = $end; + } + + /** + * Retrieves a DOMElement which corresponds to this element and all + * child properties. This is used to build an entry back into a DOM + * and eventually XML text for sending to the server upon updates, or + * for application storage/persistence. + * + * @param DOMDocument $doc The DOMDocument used to construct DOMElements + * @return DOMElement The DOMElement representing this element and all + * child properties. + */ + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc, $majorVersion, $minorVersion); + if ($this->_type !== null) { + $element->setAttribute('type', $this->_type); + } + if ($this->_lang !== null) { + $element->setAttribute('lang', $this->_lang); + } + if ($this->_start !== null) { + $element->setAttribute('start', $this->_start); + } + if ($this->_end !== null) { + $element->setAttribute('end', $this->_end); + } + return $element; + } + + /** + * Given a DOMNode representing an attribute, tries to map the data into + * instance members. If no mapping is defined, the name and value are + * stored in an array. + * + * @param DOMNode $attribute The DOMNode attribute needed to be handled + */ + protected function takeAttributeFromDOM($attribute) + { + switch ($attribute->localName) { + case 'type': + $this->_type = $attribute->nodeValue; + break; + case 'lang': + $this->_lang = $attribute->nodeValue; + break; + case 'start': + $this->_start = $attribute->nodeValue; + break; + case 'end': + $this->_end = $attribute->nodeValue; + break; + default: + parent::takeAttributeFromDOM($attribute); + } + } + + /** + * @return string + */ + public function getType() + { + return $this->_type; + } + + /** + * @param string $value + * @return Zend_Gdata_Media_Extension_MediaText Provides a fluent interface + */ + public function setType($value) + { + $this->_type = $value; + return $this; + } + + /** + * @return string + */ + public function getLang() + { + return $this->_lang; + } + + /** + * @param string $value + * @return Zend_Gdata_Media_Extension_MediaText Provides a fluent interface + */ + public function setLang($value) + { + $this->_lang = $value; + return $this; + } + + /** + * @return string + */ + public function getStart() + { + return $this->_start; + } + + /** + * @param string $value + * @return Zend_Gdata_Media_Extension_MediaText Provides a fluent interface + */ + public function setStart($value) + { + $this->_start = $value; + return $this; + } + + /** + * @return string + */ + public function getEnd() + { + return $this->_end; + } + + /** + * @param string $value + * @return Zend_Gdata_Media_Extension_MediaText Provides a fluent interface + */ + public function setEnd($value) + { + $this->_end = $value; + return $this; + } +} diff --git a/Zend/Gdata/Media/Extension/MediaThumbnail.php b/Zend/Gdata/Media/Extension/MediaThumbnail.php new file mode 100644 index 00000000..c347f811 --- /dev/null +++ b/Zend/Gdata/Media/Extension/MediaThumbnail.php @@ -0,0 +1,210 @@ +registerAllNamespaces(Zend_Gdata_Media::$namespaces); + parent::__construct(); + $this->_url = $url; + $this->_width = $width; + $this->_height = $height; + $this->_time = $time ; + } + + /** + * Retrieves a DOMElement which corresponds to this element and all + * child properties. This is used to build an entry back into a DOM + * and eventually XML text for sending to the server upon updates, or + * for application storage/persistence. + * + * @param DOMDocument $doc The DOMDocument used to construct DOMElements + * @return DOMElement The DOMElement representing this element and all + * child properties. + */ + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc, $majorVersion, $minorVersion); + if ($this->_url !== null) { + $element->setAttribute('url', $this->_url); + } + if ($this->_width !== null) { + $element->setAttribute('width', $this->_width); + } + if ($this->_height !== null) { + $element->setAttribute('height', $this->_height); + } + if ($this->_time !== null) { + $element->setAttribute('time', $this->_time); + } + return $element; + } + + /** + * Given a DOMNode representing an attribute, tries to map the data into + * instance members. If no mapping is defined, the name and value are + * stored in an array. + * + * @param DOMNode $attribute The DOMNode attribute needed to be handled + */ + protected function takeAttributeFromDOM($attribute) + { + switch ($attribute->localName) { + case 'url': + $this->_url = $attribute->nodeValue; + break; + case 'width': + $this->_width = $attribute->nodeValue; + break; + case 'height': + $this->_height = $attribute->nodeValue; + break; + case 'time': + $this->_time = $attribute->nodeValue; + break; + default: + parent::takeAttributeFromDOM($attribute); + } + } + + /** + * @return string + */ + public function getUrl() + { + return $this->_url; + } + + /** + * @param string $value + * @return Zend_Gdata_Media_Extension_MediaThumbnail Provides a fluent interface + */ + public function setUrl($value) + { + $this->_url = $value; + return $this; + } + + /** + * @return int + */ + public function getWidth() + { + return $this->_width; + } + + /** + * @param int $value + * @return Zend_Gdata_Media_Extension_MediaThumbnail Provides a fluent interface + */ + public function setWidth($value) + { + $this->_width = $value; + return $this; + } + + /** + * @return int + */ + public function getHeight() + { + return $this->_height; + } + + /** + * @param int $value + * @return Zend_Gdata_Media_Extension_MediaThumbnail Provides a fluent interface + */ + public function setHeight($value) + { + $this->_height = $value; + return $this; + } + + /** + * @return string + */ + public function getTime() + { + return $this->_time; + } + + /** + * @param string $value + * @return Zend_Gdata_Media_Extension_MediaThumbnail Provides a fluent interface + */ + public function setTime($value) + { + $this->_time = $value; + return $this; + } + +} diff --git a/Zend/Gdata/Media/Extension/MediaTitle.php b/Zend/Gdata/Media/Extension/MediaTitle.php new file mode 100644 index 00000000..93589db3 --- /dev/null +++ b/Zend/Gdata/Media/Extension/MediaTitle.php @@ -0,0 +1,118 @@ +registerAllNamespaces(Zend_Gdata_Media::$namespaces); + parent::__construct(); + $this->_type = $type; + $this->_text = $text; + } + + /** + * Retrieves a DOMElement which corresponds to this element and all + * child properties. This is used to build an entry back into a DOM + * and eventually XML text for sending to the server upon updates, or + * for application storage/persistence. + * + * @param DOMDocument $doc The DOMDocument used to construct DOMElements + * @return DOMElement The DOMElement representing this element and all + * child properties. + */ + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc, $majorVersion, $minorVersion); + if ($this->_type !== null) { + $element->setAttribute('type', $this->_type); + } + return $element; + } + + /** + * Given a DOMNode representing an attribute, tries to map the data into + * instance members. If no mapping is defined, the name and value are + * stored in an array. + * + * @param DOMNode $attribute The DOMNode attribute needed to be handled + */ + protected function takeAttributeFromDOM($attribute) + { + switch ($attribute->localName) { + case 'type': + $this->_type = $attribute->nodeValue; + break; + default: + parent::takeAttributeFromDOM($attribute); + } + } + + /** + * @return string + */ + public function getType() + { + return $this->_type; + } + + /** + * @param string $value + * @return Zend_Gdata_Media_Extension_MediaTitle Provides a fluent interface + */ + public function setType($value) + { + $this->_type = $value; + return $this; + } + +} diff --git a/Zend/Gdata/Media/Feed.php b/Zend/Gdata/Media/Feed.php new file mode 100644 index 00000000..779a1566 --- /dev/null +++ b/Zend/Gdata/Media/Feed.php @@ -0,0 +1,70 @@ +registerAllNamespaces(Zend_Gdata_Media::$namespaces); + parent::__construct($element); + } + +} diff --git a/Zend/Gdata/MediaMimeStream.php b/Zend/Gdata/MediaMimeStream.php new file mode 100644 index 00000000..eb8fe701 --- /dev/null +++ b/Zend/Gdata/MediaMimeStream.php @@ -0,0 +1,190 @@ + 1. + */ + public function __construct($xmlString = null, $filePath = null, + $fileContentType = null) + { + if (!file_exists($filePath) || !is_readable($filePath)) { + require_once 'Zend/Gdata/App/IOException.php'; + throw new Zend_Gdata_App_IOException('File to be uploaded at ' . + $filePath . ' does not exist or is not readable.'); + } + + $this->_fileHandle = fopen($filePath, 'rb', TRUE); + $this->_boundaryString = '=_' . md5(microtime(1) . rand(1,20)); + $entry = $this->wrapEntry($xmlString, $fileContentType); + $closingBoundary = new Zend_Gdata_MimeBodyString("\r\n--{$this->_boundaryString}--\r\n"); + $file = new Zend_Gdata_MimeFile($this->_fileHandle); + $this->_parts = array($entry, $file, $closingBoundary); + + $fileSize = filesize($filePath); + $this->_totalSize = $entry->getSize() + $fileSize + + $closingBoundary->getSize(); + + } + + /** + * Sandwiches the entry body into a MIME message + * + * @return void + */ + private function wrapEntry($entry, $fileMimeType) + { + $wrappedEntry = "--{$this->_boundaryString}\r\n"; + $wrappedEntry .= "Content-Type: application/atom+xml\r\n\r\n"; + $wrappedEntry .= $entry; + $wrappedEntry .= "\r\n--{$this->_boundaryString}\r\n"; + $wrappedEntry .= "Content-Type: $fileMimeType\r\n\r\n"; + return new Zend_Gdata_MimeBodyString($wrappedEntry); + } + + /** + * Read a specific chunk of the the MIME multipart message. + * + * @param integer $bufferSize The size of the chunk that is to be read, + * must be lower than MAX_BUFFER_SIZE. + * @return string A corresponding piece of the message. This could be + * binary or regular text. + */ + public function read($bytesRequested) + { + if($this->_currentPart >= count($this->_parts)) { + return FALSE; + } + + $activePart = $this->_parts[$this->_currentPart]; + $buffer = $activePart->read($bytesRequested); + + while(strlen($buffer) < $bytesRequested) { + $this->_currentPart += 1; + $nextBuffer = $this->read($bytesRequested - strlen($buffer)); + if($nextBuffer === FALSE) { + break; + } + $buffer .= $nextBuffer; + } + + return $buffer; + } + + /** + * Return the total size of the mime message. + * + * @return integer Total size of the message to be sent. + */ + public function getTotalSize() + { + return $this->_totalSize; + } + + /** + * Close the internal file that we are streaming to the socket. + * + * @return void + */ + public function closeFileHandle() + { + if ($this->_fileHandle !== null) { + fclose($this->_fileHandle); + } + } + + /** + * Return a Content-type header that includes the current boundary string. + * + * @return string A valid HTTP Content-Type header. + */ + public function getContentType() + { + return 'multipart/related;boundary="' . + $this->_boundaryString . '"' . "\r\n"; + } + +} diff --git a/Zend/Gdata/MimeBodyString.php b/Zend/Gdata/MimeBodyString.php new file mode 100644 index 00000000..9de67889 --- /dev/null +++ b/Zend/Gdata/MimeBodyString.php @@ -0,0 +1,92 @@ +_sourceString = $sourceString; + $this->_bytesRead = 0; + } + + /** + * Read the next chunk of the string. + * + * @param integer $bytesRequested The size of the chunk that is to be read. + * @return string A corresponding piece of the string. + */ + public function read($bytesRequested) + { + $len = strlen($this->_sourceString); + if($this->_bytesRead == $len) { + return FALSE; + } else if($bytesRequested > $len - $this->_bytesRead) { + $bytesRequested = $len - $this->_bytesRead; + } + + $buffer = substr($this->_sourceString, $this->_bytesRead, $bytesRequested); + $this->_bytesRead += $bytesRequested; + + return $buffer; + } + + /** + * The length of the string. + * + * @return int The length of the string contained in the object. + */ + public function getSize() + { + return strlen($this->_sourceString); + } + + +} diff --git a/Zend/Gdata/MimeFile.php b/Zend/Gdata/MimeFile.php new file mode 100644 index 00000000..7930e96d --- /dev/null +++ b/Zend/Gdata/MimeFile.php @@ -0,0 +1,66 @@ +_fileHandle = $fileHandle; + } + + /** + * Read the next chunk of the file. + * + * @param integer $bytesRequested The size of the chunk that is to be read. + * @return string A corresponding piece of the message. This could be + * binary or regular text. + */ + public function read($bytesRequested) + { + return fread($this->_fileHandle, $bytesRequested); + } + +} diff --git a/Zend/Gdata/Photos.php b/Zend/Gdata/Photos.php new file mode 100644 index 00000000..3405ad81 --- /dev/null +++ b/Zend/Gdata/Photos.php @@ -0,0 +1,576 @@ +registerPackage('Zend_Gdata_Photos'); + $this->registerPackage('Zend_Gdata_Photos_Extension'); + parent::__construct($client, $applicationId); + $this->_httpClient->setParameterPost('service', self::AUTH_SERVICE_NAME); + } + + /** + * Retrieve a UserFeed containing AlbumEntries, PhotoEntries and + * TagEntries associated with a given user. + * + * @param string $userName The userName of interest + * @param mixed $location (optional) The location for the feed, as a URL + * or Query. If not provided, a default URL will be used instead. + * @return Zend_Gdata_Photos_UserFeed + * @throws Zend_Gdata_App_Exception + * @throws Zend_Gdata_App_HttpException + */ + public function getUserFeed($userName = null, $location = null) + { + if ($location instanceof Zend_Gdata_Photos_UserQuery) { + $location->setType('feed'); + if ($userName !== null) { + $location->setUser($userName); + } + $uri = $location->getQueryUrl(); + } else if ($location instanceof Zend_Gdata_Query) { + if ($userName !== null) { + $location->setUser($userName); + } + $uri = $location->getQueryUrl(); + } else if ($location !== null) { + $uri = $location; + } else if ($userName !== null) { + $uri = self::PICASA_BASE_FEED_URI . '/' . + self::DEFAULT_PROJECTION . '/' . self::USER_PATH . '/' . + $userName; + } else { + $uri = self::PICASA_BASE_FEED_URI . '/' . + self::DEFAULT_PROJECTION . '/' . self::USER_PATH . '/' . + self::DEFAULT_USER; + } + + return parent::getFeed($uri, 'Zend_Gdata_Photos_UserFeed'); + } + + /** + * Retreive AlbumFeed object containing multiple PhotoEntry or TagEntry + * objects. + * + * @param mixed $location (optional) The location for the feed, as a URL or Query. + * @return Zend_Gdata_Photos_AlbumFeed + * @throws Zend_Gdata_App_Exception + * @throws Zend_Gdata_App_HttpException + */ + public function getAlbumFeed($location = null) + { + if ($location === null) { + require_once 'Zend/Gdata/App/InvalidArgumentException.php'; + throw new Zend_Gdata_App_InvalidArgumentException( + 'Location must not be null'); + } else if ($location instanceof Zend_Gdata_Photos_UserQuery) { + $location->setType('feed'); + $uri = $location->getQueryUrl(); + } else if ($location instanceof Zend_Gdata_Query) { + $uri = $location->getQueryUrl(); + } else { + $uri = $location; + } + return parent::getFeed($uri, 'Zend_Gdata_Photos_AlbumFeed'); + } + + /** + * Retreive PhotoFeed object containing comments and tags associated + * with a given photo. + * + * @param mixed $location (optional) The location for the feed, as a URL + * or Query. If not specified, the community search feed will + * be returned instead. + * @return Zend_Gdata_Photos_PhotoFeed + * @throws Zend_Gdata_App_Exception + * @throws Zend_Gdata_App_HttpException + */ + public function getPhotoFeed($location = null) + { + if ($location === null) { + $uri = self::PICASA_BASE_FEED_URI . '/' . + self::DEFAULT_PROJECTION . '/' . + self::COMMUNITY_SEARCH_PATH; + } else if ($location instanceof Zend_Gdata_Photos_UserQuery) { + $location->setType('feed'); + $uri = $location->getQueryUrl(); + } else if ($location instanceof Zend_Gdata_Query) { + $uri = $location->getQueryUrl(); + } else { + $uri = $location; + } + return parent::getFeed($uri, 'Zend_Gdata_Photos_PhotoFeed'); + } + + /** + * Retreive a single UserEntry object. + * + * @param mixed $location The location for the feed, as a URL or Query. + * @return Zend_Gdata_Photos_UserEntry + * @throws Zend_Gdata_App_Exception + * @throws Zend_Gdata_App_HttpException + */ + public function getUserEntry($location) + { + if ($location === null) { + require_once 'Zend/Gdata/App/InvalidArgumentException.php'; + throw new Zend_Gdata_App_InvalidArgumentException( + 'Location must not be null'); + } else if ($location instanceof Zend_Gdata_Photos_UserQuery) { + $location->setType('entry'); + $uri = $location->getQueryUrl(); + } else if ($location instanceof Zend_Gdata_Query) { + $uri = $location->getQueryUrl(); + } else { + $uri = $location; + } + return parent::getEntry($uri, 'Zend_Gdata_Photos_UserEntry'); + } + + /** + * Retreive a single AlbumEntry object. + * + * @param mixed $location The location for the feed, as a URL or Query. + * @return Zend_Gdata_Photos_AlbumEntry + * @throws Zend_Gdata_App_Exception + * @throws Zend_Gdata_App_HttpException + */ + public function getAlbumEntry($location) + { + if ($location === null) { + require_once 'Zend/Gdata/App/InvalidArgumentException.php'; + throw new Zend_Gdata_App_InvalidArgumentException( + 'Location must not be null'); + } else if ($location instanceof Zend_Gdata_Photos_UserQuery) { + $location->setType('entry'); + $uri = $location->getQueryUrl(); + } else if ($location instanceof Zend_Gdata_Query) { + $uri = $location->getQueryUrl(); + } else { + $uri = $location; + } + return parent::getEntry($uri, 'Zend_Gdata_Photos_AlbumEntry'); + } + + /** + * Retreive a single PhotoEntry object. + * + * @param mixed $location The location for the feed, as a URL or Query. + * @return Zend_Gdata_Photos_PhotoEntry + * @throws Zend_Gdata_App_Exception + * @throws Zend_Gdata_App_HttpException + */ + public function getPhotoEntry($location) + { + if ($location === null) { + require_once 'Zend/Gdata/App/InvalidArgumentException.php'; + throw new Zend_Gdata_App_InvalidArgumentException( + 'Location must not be null'); + } else if ($location instanceof Zend_Gdata_Photos_UserQuery) { + $location->setType('entry'); + $uri = $location->getQueryUrl(); + } else if ($location instanceof Zend_Gdata_Query) { + $uri = $location->getQueryUrl(); + } else { + $uri = $location; + } + return parent::getEntry($uri, 'Zend_Gdata_Photos_PhotoEntry'); + } + + /** + * Retreive a single TagEntry object. + * + * @param mixed $location The location for the feed, as a URL or Query. + * @return Zend_Gdata_Photos_TagEntry + * @throws Zend_Gdata_App_Exception + * @throws Zend_Gdata_App_HttpException + */ + public function getTagEntry($location) + { + if ($location === null) { + require_once 'Zend/Gdata/App/InvalidArgumentException.php'; + throw new Zend_Gdata_App_InvalidArgumentException( + 'Location must not be null'); + } else if ($location instanceof Zend_Gdata_Photos_UserQuery) { + $location->setType('entry'); + $uri = $location->getQueryUrl(); + } else if ($location instanceof Zend_Gdata_Query) { + $uri = $location->getQueryUrl(); + } else { + $uri = $location; + } + return parent::getEntry($uri, 'Zend_Gdata_Photos_TagEntry'); + } + + /** + * Retreive a single CommentEntry object. + * + * @param mixed $location The location for the feed, as a URL or Query. + * @return Zend_Gdata_Photos_CommentEntry + * @throws Zend_Gdata_App_Exception + * @throws Zend_Gdata_App_HttpException + */ + public function getCommentEntry($location) + { + if ($location === null) { + require_once 'Zend/Gdata/App/InvalidArgumentException.php'; + throw new Zend_Gdata_App_InvalidArgumentException( + 'Location must not be null'); + } else if ($location instanceof Zend_Gdata_Photos_UserQuery) { + $location->setType('entry'); + $uri = $location->getQueryUrl(); + } else if ($location instanceof Zend_Gdata_Query) { + $uri = $location->getQueryUrl(); + } else { + $uri = $location; + } + return parent::getEntry($uri, 'Zend_Gdata_Photos_CommentEntry'); + } + + /** + * Create a new album from a AlbumEntry. + * + * @param Zend_Gdata_Photos_AlbumEntry $album The album entry to + * insert. + * @param string $url (optional) The URI that the album should be + * uploaded to. If null, the default album creation URI for + * this domain will be used. + * @return Zend_Gdata_Photos_AlbumEntry The inserted album entry as + * returned by the server. + * @throws Zend_Gdata_App_Exception + * @throws Zend_Gdata_App_HttpException + */ + public function insertAlbumEntry($album, $uri = null) + { + if ($uri === null) { + $uri = self::PICASA_BASE_FEED_URI . '/' . + self::DEFAULT_PROJECTION . '/' . self::USER_PATH . '/' . + self::DEFAULT_USER; + } + $newEntry = $this->insertEntry($album, $uri, 'Zend_Gdata_Photos_AlbumEntry'); + return $newEntry; + } + + /** + * Create a new photo from a PhotoEntry. + * + * @param Zend_Gdata_Photos_PhotoEntry $photo The photo to insert. + * @param string $url The URI that the photo should be uploaded + * to. Alternatively, an AlbumEntry can be provided and the + * photo will be added to that album. + * @return Zend_Gdata_Photos_PhotoEntry The inserted photo entry + * as returned by the server. + * @throws Zend_Gdata_App_Exception + * @throws Zend_Gdata_App_HttpException + */ + public function insertPhotoEntry($photo, $uri = null) + { + if ($uri instanceof Zend_Gdata_Photos_AlbumEntry) { + $uri = $uri->getLink(self::FEED_LINK_PATH)->href; + } + if ($uri === null) { + require_once 'Zend/Gdata/App/InvalidArgumentException.php'; + throw new Zend_Gdata_App_InvalidArgumentException( + 'URI must not be null'); + } + $newEntry = $this->insertEntry($photo, $uri, 'Zend_Gdata_Photos_PhotoEntry'); + return $newEntry; + } + + /** + * Create a new tag from a TagEntry. + * + * @param Zend_Gdata_Photos_TagEntry $tag The tag entry to insert. + * @param string $url The URI where the tag should be + * uploaded to. Alternatively, a PhotoEntry can be provided and + * the tag will be added to that photo. + * @return Zend_Gdata_Photos_TagEntry The inserted tag entry as returned + * by the server. + * @throws Zend_Gdata_App_Exception + * @throws Zend_Gdata_App_HttpException + */ + public function insertTagEntry($tag, $uri = null) + { + if ($uri instanceof Zend_Gdata_Photos_PhotoEntry) { + $uri = $uri->getLink(self::FEED_LINK_PATH)->href; + } + if ($uri === null) { + require_once 'Zend/Gdata/App/InvalidArgumentException.php'; + throw new Zend_Gdata_App_InvalidArgumentException( + 'URI must not be null'); + } + $newEntry = $this->insertEntry($tag, $uri, 'Zend_Gdata_Photos_TagEntry'); + return $newEntry; + } + + /** + * Create a new comment from a CommentEntry. + * + * @param Zend_Gdata_Photos_CommentEntry $comment The comment entry to + * insert. + * @param string $url The URI where the comment should be uploaded to. + * Alternatively, a PhotoEntry can be provided and + * the comment will be added to that photo. + * @return Zend_Gdata_Photos_CommentEntry The inserted comment entry + * as returned by the server. + * @throws Zend_Gdata_App_Exception + * @throws Zend_Gdata_App_HttpException + */ + public function insertCommentEntry($comment, $uri = null) + { + if ($uri instanceof Zend_Gdata_Photos_PhotoEntry) { + $uri = $uri->getLink(self::FEED_LINK_PATH)->href; + } + if ($uri === null) { + require_once 'Zend/Gdata/App/InvalidArgumentException.php'; + throw new Zend_Gdata_App_InvalidArgumentException( + 'URI must not be null'); + } + $newEntry = $this->insertEntry($comment, $uri, 'Zend_Gdata_Photos_CommentEntry'); + return $newEntry; + } + + /** + * Delete an AlbumEntry. + * + * @param Zend_Gdata_Photos_AlbumEntry $album The album entry to + * delete. + * @param boolean $catch Whether to catch an exception when + * modified and re-delete or throw + * @return void. + * @throws Zend_Gdata_App_Exception + * @throws Zend_Gdata_App_HttpException + */ + public function deleteAlbumEntry($album, $catch) + { + if ($catch) { + try { + $this->delete($album); + } catch (Zend_Gdata_App_HttpException $e) { + if ($e->getResponse()->getStatus() === 409) { + $entry = new Zend_Gdata_Photos_AlbumEntry($e->getResponse()->getBody()); + $this->delete($entry->getLink('edit')->href); + } else { + throw $e; + } + } + } else { + $this->delete($album); + } + } + + /** + * Delete a PhotoEntry. + * + * @param Zend_Gdata_Photos_PhotoEntry $photo The photo entry to + * delete. + * @param boolean $catch Whether to catch an exception when + * modified and re-delete or throw + * @return void. + * @throws Zend_Gdata_App_Exception + * @throws Zend_Gdata_App_HttpException + */ + public function deletePhotoEntry($photo, $catch) + { + if ($catch) { + try { + $this->delete($photo); + } catch (Zend_Gdata_App_HttpException $e) { + if ($e->getResponse()->getStatus() === 409) { + $entry = new Zend_Gdata_Photos_PhotoEntry($e->getResponse()->getBody()); + $this->delete($entry->getLink('edit')->href); + } else { + throw $e; + } + } + } else { + $this->delete($photo); + } + } + + /** + * Delete a CommentEntry. + * + * @param Zend_Gdata_Photos_CommentEntry $comment The comment entry to + * delete. + * @param boolean $catch Whether to catch an exception when + * modified and re-delete or throw + * @return void. + * @throws Zend_Gdata_App_Exception + * @throws Zend_Gdata_App_HttpException + */ + public function deleteCommentEntry($comment, $catch) + { + if ($catch) { + try { + $this->delete($comment); + } catch (Zend_Gdata_App_HttpException $e) { + if ($e->getResponse()->getStatus() === 409) { + $entry = new Zend_Gdata_Photos_CommentEntry($e->getResponse()->getBody()); + $this->delete($entry->getLink('edit')->href); + } else { + throw $e; + } + } + } else { + $this->delete($comment); + } + } + + /** + * Delete a TagEntry. + * + * @param Zend_Gdata_Photos_TagEntry $tag The tag entry to + * delete. + * @param boolean $catch Whether to catch an exception when + * modified and re-delete or throw + * @return void. + * @throws Zend_Gdata_App_Exception + * @throws Zend_Gdata_App_HttpException + */ + public function deleteTagEntry($tag, $catch) + { + if ($catch) { + try { + $this->delete($tag); + } catch (Zend_Gdata_App_HttpException $e) { + if ($e->getResponse()->getStatus() === 409) { + $entry = new Zend_Gdata_Photos_TagEntry($e->getResponse()->getBody()); + $this->delete($entry->getLink('edit')->href); + } else { + throw $e; + } + } + } else { + $this->delete($tag); + } + } + +} diff --git a/Zend/Gdata/Photos/AlbumEntry.php b/Zend/Gdata/Photos/AlbumEntry.php new file mode 100644 index 00000000..b888c463 --- /dev/null +++ b/Zend/Gdata/Photos/AlbumEntry.php @@ -0,0 +1,610 @@ + in the Google Data protocol. + * + * @category Zend + * @package Zend_Gdata + * @subpackage Photos + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +class Zend_Gdata_Photos_AlbumEntry extends Zend_Gdata_Entry +{ + + protected $_entryClassName = 'Zend_Gdata_Photos_AlbumEntry'; + + /** + * gphoto:id element + * + * @var Zend_Gdata_Photos_Extension_Id + */ + protected $_gphotoId = null; + + /** + * gphoto:access element + * + * @var Zend_Gdata_Photos_Extension_Access + */ + protected $_gphotoAccess = null; + + /** + * gphoto:location element + * + * @var Zend_Gdata_Photos_Extension_Location + */ + protected $_gphotoLocation = null; + + /** + * gphoto:user element + * + * @var Zend_Gdata_Photos_Extension_User + */ + protected $_gphotoUser = null; + + /** + * gphoto:nickname element + * + * @var Zend_Gdata_Photos_Extension_Nickname + */ + protected $_gphotoNickname = null; + + /** + * gphoto:timestamp element + * + * @var Zend_Gdata_Photos_Extension_Timestamp + */ + protected $_gphotoTimestamp = null; + + /** + * gphoto:name element + * + * @var Zend_Gdata_Photos_Extension_Name + */ + protected $_gphotoName = null; + + /** + * gphoto:numphotos element + * + * @var Zend_Gdata_Photos_Extension_NumPhotos + */ + protected $_gphotoNumPhotos = null; + + /** + * gphoto:commentCount element + * + * @var Zend_Gdata_Photos_Extension_CommentCount + */ + protected $_gphotoCommentCount = null; + + /** + * gphoto:commentingEnabled element + * + * @var Zend_Gdata_Photos_Extension_CommentingEnabled + */ + protected $_gphotoCommentingEnabled = null; + + /** + * media:group element + * + * @var Zend_Gdata_Media_MediaGroup + */ + protected $_mediaGroup = null; + + /** + * georss:where element + * + * @var Zend_Gdata_Geo_Extension_GeoRssWhere + */ + protected $_geoRssWhere = null; + + /** + * Create a new instance. + * + * @param DOMElement $element (optional) DOMElement from which this + * object should be constructed. + */ + public function __construct($element = null) + { + $this->registerAllNamespaces(Zend_Gdata_Photos::$namespaces); + parent::__construct($element); + + $category = new Zend_Gdata_App_Extension_Category( + 'http://schemas.google.com/photos/2007#album', + 'http://schemas.google.com/g/2005#kind'); + $this->setCategory(array($category)); + } + + /** + * Retrieves a DOMElement which corresponds to this element and all + * child properties. This is used to build an entry back into a DOM + * and eventually XML text for application storage/persistence. + * + * @param DOMDocument $doc The DOMDocument used to construct DOMElements + * @return DOMElement The DOMElement representing this element and all + * child properties. + */ + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc, $majorVersion, $minorVersion); + if ($this->_gphotoTimestamp !== null) { + $element->appendChild($this->_gphotoTimestamp->getDOM($element->ownerDocument)); + } + if ($this->_gphotoUser !== null) { + $element->appendChild($this->_gphotoUser->getDOM($element->ownerDocument)); + } + if ($this->_gphotoNickname !== null) { + $element->appendChild($this->_gphotoNickname->getDOM($element->ownerDocument)); + } + if ($this->_gphotoAccess !== null) { + $element->appendChild($this->_gphotoAccess->getDOM($element->ownerDocument)); + } + if ($this->_gphotoLocation !== null) { + $element->appendChild($this->_gphotoLocation->getDOM($element->ownerDocument)); + } + if ($this->_gphotoName !== null) { + $element->appendChild($this->_gphotoName->getDOM($element->ownerDocument)); + } + if ($this->_gphotoNumPhotos !== null) { + $element->appendChild($this->_gphotoNumPhotos->getDOM($element->ownerDocument)); + } + if ($this->_gphotoCommentCount !== null) { + $element->appendChild($this->_gphotoCommentCount->getDOM($element->ownerDocument)); + } + if ($this->_gphotoCommentingEnabled !== null) { + $element->appendChild($this->_gphotoCommentingEnabled->getDOM($element->ownerDocument)); + } + if ($this->_gphotoId !== null) { + $element->appendChild($this->_gphotoId->getDOM($element->ownerDocument)); + } + if ($this->_mediaGroup !== null) { + $element->appendChild($this->_mediaGroup->getDOM($element->ownerDocument)); + } + return $element; + } + + /** + * Creates individual Entry objects of the appropriate type and + * stores them as members of this entry based upon DOM data. + * + * @param DOMNode $child The DOMNode to process + */ + protected function takeChildFromDOM($child) + { + $absoluteNodeName = $child->namespaceURI . ':' . $child->localName; + + switch ($absoluteNodeName) { + case $this->lookupNamespace('gphoto') . ':' . 'access'; + $access = new Zend_Gdata_Photos_Extension_Access(); + $access->transferFromDOM($child); + $this->_gphotoAccess = $access; + break; + case $this->lookupNamespace('gphoto') . ':' . 'location'; + $location = new Zend_Gdata_Photos_Extension_Location(); + $location->transferFromDOM($child); + $this->_gphotoLocation = $location; + break; + case $this->lookupNamespace('gphoto') . ':' . 'name'; + $name = new Zend_Gdata_Photos_Extension_Name(); + $name->transferFromDOM($child); + $this->_gphotoName = $name; + break; + case $this->lookupNamespace('gphoto') . ':' . 'numphotos'; + $numPhotos = new Zend_Gdata_Photos_Extension_NumPhotos(); + $numPhotos->transferFromDOM($child); + $this->_gphotoNumPhotos = $numPhotos; + break; + case $this->lookupNamespace('gphoto') . ':' . 'commentCount'; + $commentCount = new Zend_Gdata_Photos_Extension_CommentCount(); + $commentCount->transferFromDOM($child); + $this->_gphotoCommentCount = $commentCount; + break; + case $this->lookupNamespace('gphoto') . ':' . 'commentingEnabled'; + $commentingEnabled = new Zend_Gdata_Photos_Extension_CommentingEnabled(); + $commentingEnabled->transferFromDOM($child); + $this->_gphotoCommentingEnabled = $commentingEnabled; + break; + case $this->lookupNamespace('gphoto') . ':' . 'id'; + $id = new Zend_Gdata_Photos_Extension_Id(); + $id->transferFromDOM($child); + $this->_gphotoId = $id; + break; + case $this->lookupNamespace('gphoto') . ':' . 'user'; + $user = new Zend_Gdata_Photos_Extension_User(); + $user->transferFromDOM($child); + $this->_gphotoUser = $user; + break; + case $this->lookupNamespace('gphoto') . ':' . 'timestamp'; + $timestamp = new Zend_Gdata_Photos_Extension_Timestamp(); + $timestamp->transferFromDOM($child); + $this->_gphotoTimestamp = $timestamp; + break; + case $this->lookupNamespace('gphoto') . ':' . 'nickname'; + $nickname = new Zend_Gdata_Photos_Extension_Nickname(); + $nickname->transferFromDOM($child); + $this->_gphotoNickname = $nickname; + break; + case $this->lookupNamespace('georss') . ':' . 'where'; + $geoRssWhere = new Zend_Gdata_Geo_Extension_GeoRssWhere(); + $geoRssWhere->transferFromDOM($child); + $this->_geoRssWhere = $geoRssWhere; + break; + case $this->lookupNamespace('media') . ':' . 'group'; + $mediaGroup = new Zend_Gdata_Media_Extension_MediaGroup(); + $mediaGroup->transferFromDOM($child); + $this->_mediaGroup = $mediaGroup; + break; + default: + parent::takeChildFromDOM($child); + break; + } + } + + /** + * Get the value for this element's gphoto:access attribute. + * + * @see setGphotoAccess + * @return string The requested attribute. + */ + public function getGphotoAccess() + { + return $this->_gphotoAccess; + } + + /** + * Set the value for this element's gphoto:access attribute. + * + * @param string $value The desired value for this attribute. + * @return Zend_Gdata_Photos_Extension_Access The element being modified. + */ + public function setGphotoAccess($value) + { + $this->_gphotoAccess = $value; + return $this; + } + + /** + * Get the value for this element's gphoto:location attribute. + * + * @see setGphotoLocation + * @return string The requested attribute. + */ + public function getGphotoLocation() + { + return $this->_gphotoLocation; + } + + /** + * Set the value for this element's gphoto:location attribute. + * + * @param string $value The desired value for this attribute. + * @return Zend_Gdata_Photos_Extension_Location The element being modified. + */ + public function setGphotoLocation($value) + { + $this->_location = $value; + return $this; + } + + /** + * Get the value for this element's gphoto:name attribute. + * + * @see setGphotoName + * @return string The requested attribute. + */ + public function getGphotoName() + { + return $this->_gphotoName; + } + + /** + * Set the value for this element's gphoto:name attribute. + * + * @param string $value The desired value for this attribute. + * @return Zend_Gdata_Photos_Extension_Name The element being modified. + */ + public function setGphotoName($value) + { + $this->_gphotoName = $value; + return $this; + } + + /** + * Get the value for this element's gphoto:numphotos attribute. + * + * @see setGphotoNumPhotos + * @return string The requested attribute. + */ + public function getGphotoNumPhotos() + { + return $this->_gphotoNumPhotos; + } + + /** + * Set the value for this element's gphoto:numphotos attribute. + * + * @param string $value The desired value for this attribute. + * @return Zend_Gdata_Photos_Extension_NumPhotos The element being modified. + */ + public function setGphotoNumPhotos($value) + { + $this->_gphotoNumPhotos = $value; + return $this; + } + + /** + * Get the value for this element's gphoto:commentCount attribute. + * + * @see setGphotoCommentCount + * @return string The requested attribute. + */ + public function getGphotoCommentCount() + { + return $this->_gphotoCommentCount; + } + + /** + * Set the value for this element's gphoto:commentCount attribute. + * + * @param string $value The desired value for this attribute. + * @return Zend_Gdata_Photos_Extension_CommentCount The element being modified. + */ + public function setGphotoCommentCount($value) + { + $this->_gphotoCommentCount = $value; + return $this; + } + + /** + * Get the value for this element's gphoto:commentingEnabled attribute. + * + * @see setGphotoCommentingEnabled + * @return string The requested attribute. + */ + public function getGphotoCommentingEnabled() + { + return $this->_gphotoCommentingEnabled; + } + + /** + * Set the value for this element's gphoto:commentingEnabled attribute. + * + * @param string $value The desired value for this attribute. + * @return Zend_Gdata_Photos_Extension_CommentingEnabled The element being modified. + */ + public function setGphotoCommentingEnabled($value) + { + $this->_gphotoCommentingEnabled = $value; + return $this; + } + + /** + * Get the value for this element's gphoto:id attribute. + * + * @see setGphotoId + * @return string The requested attribute. + */ + public function getGphotoId() + { + return $this->_gphotoId; + } + + /** + * Set the value for this element's gphoto:id attribute. + * + * @param string $value The desired value for this attribute. + * @return Zend_Gdata_Photos_Extension_Id The element being modified. + */ + public function setGphotoId($value) + { + $this->_gphotoId = $value; + return $this; + } + + /** + * Get the value for this element's georss:where attribute. + * + * @see setGeoRssWhere + * @return string The requested attribute. + */ + public function getGeoRssWhere() + { + return $this->_geoRssWhere; + } + + /** + * Set the value for this element's georss:where attribute. + * + * @param string $value The desired value for this attribute. + * @return Zend_Gdata_Geo_Extension_GeoRssWhere The element being modified. + */ + public function setGeoRssWhere($value) + { + $this->_geoRssWhere = $value; + return $this; + } + + /** + * Get the value for this element's media:group attribute. + * + * @see setMediaGroup + * @return string The requested attribute. + */ + public function getMediaGroup() + { + return $this->_mediaGroup; + } + + /** + * Set the value for this element's media:group attribute. + * + * @param string $value The desired value for this attribute. + * @return Zend_Gdata_Media_Extension_MediaGroup The element being modified. + */ + public function setMediaGroup($value) + { + $this->_mediaGroup = $value; + return $this; + } + + /** + * Get the value for this element's gphoto:user attribute. + * + * @see setGphotoUser + * @return string The requested attribute. + */ + public function getGphotoUser() + { + return $this->_gphotoUser; + } + + /** + * Set the value for this element's gphoto:user attribute. + * + * @param string $value The desired value for this attribute. + * @return Zend_Gdata_Photos_Extension_User The element being modified. + */ + public function setGphotoUser($value) + { + $this->_gphotoUser = $value; + return $this; + } + + /** + * Get the value for this element's gphoto:nickname attribute. + * + * @see setGphotoNickname + * @return string The requested attribute. + */ + public function getGphotoNickname() + { + return $this->_gphotoNickname; + } + + /** + * Set the value for this element's gphoto:nickname attribute. + * + * @param string $value The desired value for this attribute. + * @return Zend_Gdata_Photos_Extension_Nickname The element being modified. + */ + public function setGphotoNickname($value) + { + $this->_gphotoNickname = $value; + return $this; + } + + /** + * Get the value for this element's gphoto:timestamp attribute. + * + * @see setGphotoTimestamp + * @return string The requested attribute. + */ + public function getGphotoTimestamp() + { + return $this->_gphotoTimestamp; + } + + /** + * Set the value for this element's gphoto:timestamp attribute. + * + * @param string $value The desired value for this attribute. + * @return Zend_Gdata_Photos_Extension_Timestamp The element being modified. + */ + public function setGphotoTimestamp($value) + { + $this->_gphotoTimestamp = $value; + return $this; + } +} diff --git a/Zend/Gdata/Photos/AlbumFeed.php b/Zend/Gdata/Photos/AlbumFeed.php new file mode 100644 index 00000000..99f93165 --- /dev/null +++ b/Zend/Gdata/Photos/AlbumFeed.php @@ -0,0 +1,509 @@ + 'Zend_Gdata_Photos_PhotoEntry', + 'http://schemas.google.com/photos/2007#comment' => 'Zend_Gdata_Photos_CommentEntry', + 'http://schemas.google.com/photos/2007#tag' => 'Zend_Gdata_Photos_TagEntry' + ); + + public function __construct($element = null) + { + $this->registerAllNamespaces(Zend_Gdata_Photos::$namespaces); + parent::__construct($element); + } + + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc, $majorVersion, $minorVersion); + if ($this->_gphotoId != null) { + $element->appendChild($this->_gphotoId->getDOM($element->ownerDocument)); + } + if ($this->_gphotoUser != null) { + $element->appendChild($this->_gphotoUser->getDOM($element->ownerDocument)); + } + if ($this->_gphotoNickname != null) { + $element->appendChild($this->_gphotoNickname->getDOM($element->ownerDocument)); + } + if ($this->_gphotoName != null) { + $element->appendChild($this->_gphotoName->getDOM($element->ownerDocument)); + } + if ($this->_gphotoLocation != null) { + $element->appendChild($this->_gphotoLocation->getDOM($element->ownerDocument)); + } + if ($this->_gphotoAccess != null) { + $element->appendChild($this->_gphotoAccess->getDOM($element->ownerDocument)); + } + if ($this->_gphotoTimestamp != null) { + $element->appendChild($this->_gphotoTimestamp->getDOM($element->ownerDocument)); + } + if ($this->_gphotoNumPhotos != null) { + $element->appendChild($this->_gphotoNumPhotos->getDOM($element->ownerDocument)); + } + if ($this->_gphotoCommentingEnabled != null) { + $element->appendChild($this->_gphotoCommentingEnabled->getDOM($element->ownerDocument)); + } + if ($this->_gphotoCommentCount != null) { + $element->appendChild($this->_gphotoCommentCount->getDOM($element->ownerDocument)); + } + + return $element; + } + + protected function takeChildFromDOM($child) + { + $absoluteNodeName = $child->namespaceURI . ':' . $child->localName; + + switch ($absoluteNodeName) { + case $this->lookupNamespace('gphoto') . ':' . 'id'; + $id = new Zend_Gdata_Photos_Extension_Id(); + $id->transferFromDOM($child); + $this->_gphotoId = $id; + break; + case $this->lookupNamespace('gphoto') . ':' . 'user'; + $user = new Zend_Gdata_Photos_Extension_User(); + $user->transferFromDOM($child); + $this->_gphotoUser = $user; + break; + case $this->lookupNamespace('gphoto') . ':' . 'nickname'; + $nickname = new Zend_Gdata_Photos_Extension_Nickname(); + $nickname->transferFromDOM($child); + $this->_gphotoNickname = $nickname; + break; + case $this->lookupNamespace('gphoto') . ':' . 'name'; + $name = new Zend_Gdata_Photos_Extension_Name(); + $name->transferFromDOM($child); + $this->_gphotoName = $name; + break; + case $this->lookupNamespace('gphoto') . ':' . 'location'; + $location = new Zend_Gdata_Photos_Extension_Location(); + $location->transferFromDOM($child); + $this->_gphotoLocation = $location; + break; + case $this->lookupNamespace('gphoto') . ':' . 'access'; + $access = new Zend_Gdata_Photos_Extension_Access(); + $access->transferFromDOM($child); + $this->_gphotoAccess = $access; + break; + case $this->lookupNamespace('gphoto') . ':' . 'timestamp'; + $timestamp = new Zend_Gdata_Photos_Extension_Timestamp(); + $timestamp->transferFromDOM($child); + $this->_gphotoTimestamp = $timestamp; + break; + case $this->lookupNamespace('gphoto') . ':' . 'numphotos'; + $numphotos = new Zend_Gdata_Photos_Extension_NumPhotos(); + $numphotos->transferFromDOM($child); + $this->_gphotoNumPhotos = $numphotos; + break; + case $this->lookupNamespace('gphoto') . ':' . 'commentingEnabled'; + $commentingEnabled = new Zend_Gdata_Photos_Extension_CommentingEnabled(); + $commentingEnabled->transferFromDOM($child); + $this->_gphotoCommentingEnabled = $commentingEnabled; + break; + case $this->lookupNamespace('gphoto') . ':' . 'commentCount'; + $commentCount = new Zend_Gdata_Photos_Extension_CommentCount(); + $commentCount->transferFromDOM($child); + $this->_gphotoCommentCount = $commentCount; + break; + case $this->lookupNamespace('atom') . ':' . 'entry': + $entryClassName = $this->_entryClassName; + $tmpEntry = new Zend_Gdata_App_Entry($child); + $categories = $tmpEntry->getCategory(); + foreach ($categories as $category) { + if ($category->scheme == Zend_Gdata_Photos::KIND_PATH && + $this->_entryKindClassMapping[$category->term] != "") { + $entryClassName = $this->_entryKindClassMapping[$category->term]; + break; + } else { + require_once 'Zend/Gdata/App/Exception.php'; + throw new Zend_Gdata_App_Exception('Entry is missing kind declaration.'); + } + } + + $newEntry = new $entryClassName($child); + $newEntry->setHttpClient($this->getHttpClient()); + $this->_entry[] = $newEntry; + break; + default: + parent::takeChildFromDOM($child); + break; + } + } + + /** + * Get the value for this element's gphoto:user attribute. + * + * @see setGphotoUser + * @return string The requested attribute. + */ + public function getGphotoUser() + { + return $this->_gphotoUser; + } + + /** + * Set the value for this element's gphoto:user attribute. + * + * @param string $value The desired value for this attribute. + * @return Zend_Gdata_Photos_Extension_User The element being modified. + */ + public function setGphotoUser($value) + { + $this->_gphotoUser = $value; + return $this; + } + + /** + * Get the value for this element's gphoto:access attribute. + * + * @see setGphotoAccess + * @return string The requested attribute. + */ + public function getGphotoAccess() + { + return $this->_gphotoAccess; + } + + /** + * Set the value for this element's gphoto:access attribute. + * + * @param string $value The desired value for this attribute. + * @return Zend_Gdata_Photos_Extension_Access The element being modified. + */ + public function setGphotoAccess($value) + { + $this->_gphotoAccess = $value; + return $this; + } + + /** + * Get the value for this element's gphoto:location attribute. + * + * @see setGphotoLocation + * @return string The requested attribute. + */ + public function getGphotoLocation() + { + return $this->_gphotoLocation; + } + + /** + * Set the value for this element's gphoto:location attribute. + * + * @param string $value The desired value for this attribute. + * @return Zend_Gdata_Photos_Extension_Location The element being modified. + */ + public function setGphotoLocation($value) + { + $this->_gphotoLocation = $value; + return $this; + } + + /** + * Get the value for this element's gphoto:name attribute. + * + * @see setGphotoName + * @return string The requested attribute. + */ + public function getGphotoName() + { + return $this->_gphotoName; + } + + /** + * Set the value for this element's gphoto:name attribute. + * + * @param string $value The desired value for this attribute. + * @return Zend_Gdata_Photos_Extension_Name The element being modified. + */ + public function setGphotoName($value) + { + $this->_gphotoName = $value; + return $this; + } + + /** + * Get the value for this element's gphoto:numphotos attribute. + * + * @see setGphotoNumPhotos + * @return string The requested attribute. + */ + public function getGphotoNumPhotos() + { + return $this->_gphotoNumPhotos; + } + + /** + * Set the value for this element's gphoto:numphotos attribute. + * + * @param string $value The desired value for this attribute. + * @return Zend_Gdata_Photos_Extension_NumPhotos The element being modified. + */ + public function setGphotoNumPhotos($value) + { + $this->_gphotoNumPhotos = $value; + return $this; + } + + /** + * Get the value for this element's gphoto:commentCount attribute. + * + * @see setGphotoCommentCount + * @return string The requested attribute. + */ + public function getGphotoCommentCount() + { + return $this->_gphotoCommentCount; + } + + /** + * Set the value for this element's gphoto:commentCount attribute. + * + * @param string $value The desired value for this attribute. + * @return Zend_Gdata_Photos_Extension_CommentCount The element being modified. + */ + public function setGphotoCommentCount($value) + { + $this->_gphotoCommentCount = $value; + return $this; + } + + /** + * Get the value for this element's gphoto:commentingEnabled attribute. + * + * @see setGphotoCommentingEnabled + * @return string The requested attribute. + */ + public function getGphotoCommentingEnabled() + { + return $this->_gphotoCommentingEnabled; + } + + /** + * Set the value for this element's gphoto:commentingEnabled attribute. + * + * @param string $value The desired value for this attribute. + * @return Zend_Gdata_Photos_Extension_CommentingEnabled The element being modified. + */ + public function setGphotoCommentingEnabled($value) + { + $this->_gphotoCommentingEnabled = $value; + return $this; + } + + /** + * Get the value for this element's gphoto:id attribute. + * + * @see setGphotoId + * @return string The requested attribute. + */ + public function getGphotoId() + { + return $this->_gphotoId; + } + + /** + * Set the value for this element's gphoto:id attribute. + * + * @param string $value The desired value for this attribute. + * @return Zend_Gdata_Photos_Extension_Id The element being modified. + */ + public function setGphotoId($value) + { + $this->_gphotoId = $value; + return $this; + } + + /** + * Get the value for this element's georss:where attribute. + * + * @see setGeoRssWhere + * @return string The requested attribute. + */ + public function getGeoRssWhere() + { + return $this->_geoRssWhere; + } + + /** + * Set the value for this element's georss:where attribute. + * + * @param string $value The desired value for this attribute. + * @return Zend_Gdata_Geo_Extension_GeoRssWhere The element being modified. + */ + public function setGeoRssWhere($value) + { + $this->_geoRssWhere = $value; + return $this; + } + + /** + * Get the value for this element's gphoto:nickname attribute. + * + * @see setGphotoNickname + * @return string The requested attribute. + */ + public function getGphotoNickname() + { + return $this->_gphotoNickname; + } + + /** + * Set the value for this element's gphoto:nickname attribute. + * + * @param string $value The desired value for this attribute. + * @return Zend_Gdata_Photos_Extension_Nickname The element being modified. + */ + public function setGphotoNickname($value) + { + $this->_gphotoNickname = $value; + return $this; + } + + /** + * Get the value for this element's gphoto:timestamp attribute. + * + * @see setGphotoTimestamp + * @return string The requested attribute. + */ + public function getGphotoTimestamp() + { + return $this->_gphotoTimestamp; + } + + /** + * Set the value for this element's gphoto:timestamp attribute. + * + * @param string $value The desired value for this attribute. + * @return Zend_Gdata_Photos_Extension_Timestamp The element being modified. + */ + public function setGphotoTimestamp($value) + { + $this->_gphotoTimestamp = $value; + return $this; + } + +} diff --git a/Zend/Gdata/Photos/AlbumQuery.php b/Zend/Gdata/Photos/AlbumQuery.php new file mode 100644 index 00000000..25388dc0 --- /dev/null +++ b/Zend/Gdata/Photos/AlbumQuery.php @@ -0,0 +1,149 @@ +_albumId = null; + $this->_albumName = $value; + + return $this; + } + + /** + * Get the album name which is to be returned. + * + * @see setAlbumName + * @return string The name of the album to retrieve. + */ + public function getAlbumName() + { + return $this->_albumName; + } + + /** + * Set the album ID to query for. When set, this album's photographs + * be returned. If not set or null, the default user's feed will be + * returned instead. + * + * NOTE: Album and AlbumId are mutually exclusive. Setting one will + * automatically set the other to null. + * + * @param string $value The ID of the album to retrieve, or null to + * clear. + * @return Zend_Gdata_Photos_AlbumQuery The query object. + */ + public function setAlbumId($value) + { + $this->_albumName = null; + $this->_albumId = $value; + + return $this; + } + + /** + * Get the album ID which is to be returned. + * + * @see setAlbum + * @return string The ID of the album to retrieve. + */ + public function getAlbumId() + { + return $this->_albumId; + } + + /** + * Returns the URL generated for this query, based on it's current + * parameters. + * + * @return string A URL generated based on the state of this query. + * @throws Zend_Gdata_App_InvalidArgumentException + */ + public function getQueryUrl($incomingUri = '') + { + $uri = ''; + if ($this->getAlbumName() !== null && $this->getAlbumId() === null) { + $uri .= '/album/' . $this->getAlbumName(); + } elseif ($this->getAlbumName() === null && $this->getAlbumId() !== null) { + $uri .= '/albumid/' . $this->getAlbumId(); + } elseif ($this->getAlbumName() !== null && $this->getAlbumId() !== null) { + require_once 'Zend/Gdata/App/InvalidArgumentException.php'; + throw new Zend_Gdata_App_InvalidArgumentException( + 'AlbumName and AlbumId cannot both be non-null'); + } else { + require_once 'Zend/Gdata/App/InvalidArgumentException.php'; + throw new Zend_Gdata_App_InvalidArgumentException( + 'AlbumName and AlbumId cannot both be null'); + } + $uri .= $incomingUri; + return parent::getQueryUrl($uri); + } + +} diff --git a/Zend/Gdata/Photos/CommentEntry.php b/Zend/Gdata/Photos/CommentEntry.php new file mode 100644 index 00000000..d6293f2d --- /dev/null +++ b/Zend/Gdata/Photos/CommentEntry.php @@ -0,0 +1,195 @@ + in the Google Data protocol. + * + * @category Zend + * @package Zend_Gdata + * @subpackage Photos + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +class Zend_Gdata_Photos_CommentEntry extends Zend_Gdata_Entry +{ + + protected $_entryClassName = 'Zend_Gdata_Photos_CommentEntry'; + + /** + * gphoto:id element + * + * @var Zend_Gdata_Photos_Extension_Id + */ + protected $_gphotoId = null; + + /** + * gphoto:photoid element, differs from gphoto:id as this is an + * actual identification number unique exclusively to photo entries, + * whereas gphoto:id can refer to all gphoto objects + * + * @var Zend_Gdata_Photos_Extension_PhotoId + */ + protected $_gphotoPhotoId = null; + + /** + * Create a new instance. + * + * @param DOMElement $element (optional) DOMElement from which this + * object should be constructed. + */ + public function __construct($element = null) + { + $this->registerAllNamespaces(Zend_Gdata_Photos::$namespaces); + parent::__construct($element); + + $category = new Zend_Gdata_App_Extension_Category( + 'http://schemas.google.com/photos/2007#comment', + 'http://schemas.google.com/g/2005#kind'); + $this->setCategory(array($category)); + } + + /** + * Retrieves a DOMElement which corresponds to this element and all + * child properties. This is used to build an entry back into a DOM + * and eventually XML text for application storage/persistence. + * + * @param DOMDocument $doc The DOMDocument used to construct DOMElements + * @return DOMElement The DOMElement representing this element and all + * child properties. + */ + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc, $majorVersion, $minorVersion); + if ($this->_gphotoId !== null) { + $element->appendChild($this->_gphotoId->getDOM($element->ownerDocument)); + } + if ($this->_gphotoPhotoId !== null) { + $element->appendChild($this->_gphotoPhotoId->getDOM($element->ownerDocument)); + } + return $element; + } + + /** + * Creates individual Entry objects of the appropriate type and + * stores them as members of this entry based upon DOM data. + * + * @param DOMNode $child The DOMNode to process + */ + protected function takeChildFromDOM($child) + { + $absoluteNodeName = $child->namespaceURI . ':' . $child->localName; + + switch ($absoluteNodeName) { + case $this->lookupNamespace('gphoto') . ':' . 'id'; + $id = new Zend_Gdata_Photos_Extension_Id(); + $id->transferFromDOM($child); + $this->_gphotoId = $id; + break; + case $this->lookupNamespace('gphoto') . ':' . 'photoid'; + $photoid = new Zend_Gdata_Photos_Extension_PhotoId(); + $photoid->transferFromDOM($child); + $this->_gphotoPhotoId = $photoid; + break; + default: + parent::takeChildFromDOM($child); + break; + } + } + + /** + * Get the value for this element's gphoto:photoid attribute. + * + * @see setGphotoPhotoId + * @return string The requested attribute. + */ + public function getGphotoPhotoId() + { + return $this->_gphotoPhotoId; + } + + /** + * Set the value for this element's gphoto:photoid attribute. + * + * @param string $value The desired value for this attribute. + * @return Zend_Gdata_Photos_Extension_PhotoId The element being modified. + */ + public function setGphotoPhotoId($value) + { + $this->_gphotoPhotoId = $value; + return $this; + } + + /** + * Get the value for this element's gphoto:id attribute. + * + * @see setGphotoId + * @return string The requested attribute. + */ + public function getGphotoId() + { + return $this->_gphotoId; + } + + /** + * Set the value for this element's gphoto:id attribute. + * + * @param string $value The desired value for this attribute. + * @return Zend_Gdata_Photos_Extension_Id The element being modified. + */ + public function setGphotoId($value) + { + $this->_gphotoId = $value; + return $this; + } +} diff --git a/Zend/Gdata/Photos/Extension/Access.php b/Zend/Gdata/Photos/Extension/Access.php new file mode 100644 index 00000000..994f7019 --- /dev/null +++ b/Zend/Gdata/Photos/Extension/Access.php @@ -0,0 +1,63 @@ +registerAllNamespaces(Zend_Gdata_Photos::$namespaces); + parent::__construct(); + $this->setText($text); + } + +} diff --git a/Zend/Gdata/Photos/Extension/AlbumId.php b/Zend/Gdata/Photos/Extension/AlbumId.php new file mode 100644 index 00000000..b4ec5119 --- /dev/null +++ b/Zend/Gdata/Photos/Extension/AlbumId.php @@ -0,0 +1,63 @@ +registerAllNamespaces(Zend_Gdata_Photos::$namespaces); + parent::__construct(); + $this->setText($text); + } + +} diff --git a/Zend/Gdata/Photos/Extension/BytesUsed.php b/Zend/Gdata/Photos/Extension/BytesUsed.php new file mode 100644 index 00000000..f5ec94b4 --- /dev/null +++ b/Zend/Gdata/Photos/Extension/BytesUsed.php @@ -0,0 +1,62 @@ +registerAllNamespaces(Zend_Gdata_Photos::$namespaces); + parent::__construct(); + $this->setText($text); + } + +} diff --git a/Zend/Gdata/Photos/Extension/Checksum.php b/Zend/Gdata/Photos/Extension/Checksum.php new file mode 100644 index 00000000..53152b76 --- /dev/null +++ b/Zend/Gdata/Photos/Extension/Checksum.php @@ -0,0 +1,63 @@ +registerAllNamespaces(Zend_Gdata_Photos::$namespaces); + parent::__construct(); + $this->setText($text); + } + +} diff --git a/Zend/Gdata/Photos/Extension/Client.php b/Zend/Gdata/Photos/Extension/Client.php new file mode 100644 index 00000000..7c2b1966 --- /dev/null +++ b/Zend/Gdata/Photos/Extension/Client.php @@ -0,0 +1,63 @@ +registerAllNamespaces(Zend_Gdata_Photos::$namespaces); + parent::__construct(); + $this->setText($text); + } + +} diff --git a/Zend/Gdata/Photos/Extension/CommentCount.php b/Zend/Gdata/Photos/Extension/CommentCount.php new file mode 100644 index 00000000..1af32f8d --- /dev/null +++ b/Zend/Gdata/Photos/Extension/CommentCount.php @@ -0,0 +1,63 @@ +registerAllNamespaces(Zend_Gdata_Photos::$namespaces); + parent::__construct(); + $this->setText($text); + } + +} diff --git a/Zend/Gdata/Photos/Extension/CommentingEnabled.php b/Zend/Gdata/Photos/Extension/CommentingEnabled.php new file mode 100644 index 00000000..deee3c49 --- /dev/null +++ b/Zend/Gdata/Photos/Extension/CommentingEnabled.php @@ -0,0 +1,64 @@ +registerAllNamespaces(Zend_Gdata_Photos::$namespaces); + parent::__construct(); + $this->setText($text); + } + +} diff --git a/Zend/Gdata/Photos/Extension/Height.php b/Zend/Gdata/Photos/Extension/Height.php new file mode 100644 index 00000000..f4d7c498 --- /dev/null +++ b/Zend/Gdata/Photos/Extension/Height.php @@ -0,0 +1,62 @@ +registerAllNamespaces(Zend_Gdata_Photos::$namespaces); + parent::__construct(); + $this->setText($text); + } + +} diff --git a/Zend/Gdata/Photos/Extension/Id.php b/Zend/Gdata/Photos/Extension/Id.php new file mode 100644 index 00000000..0c86453e --- /dev/null +++ b/Zend/Gdata/Photos/Extension/Id.php @@ -0,0 +1,62 @@ +registerAllNamespaces(Zend_Gdata_Photos::$namespaces); + parent::__construct(); + $this->setText($text); + } + +} diff --git a/Zend/Gdata/Photos/Extension/Location.php b/Zend/Gdata/Photos/Extension/Location.php new file mode 100644 index 00000000..a94e9b3f --- /dev/null +++ b/Zend/Gdata/Photos/Extension/Location.php @@ -0,0 +1,62 @@ +registerAllNamespaces(Zend_Gdata_Photos::$namespaces); + parent::__construct(); + $this->setText($text); + } + +} diff --git a/Zend/Gdata/Photos/Extension/MaxPhotosPerAlbum.php b/Zend/Gdata/Photos/Extension/MaxPhotosPerAlbum.php new file mode 100644 index 00000000..f72b6782 --- /dev/null +++ b/Zend/Gdata/Photos/Extension/MaxPhotosPerAlbum.php @@ -0,0 +1,63 @@ +registerAllNamespaces(Zend_Gdata_Photos::$namespaces); + parent::__construct(); + $this->setText($text); + } + +} diff --git a/Zend/Gdata/Photos/Extension/Name.php b/Zend/Gdata/Photos/Extension/Name.php new file mode 100644 index 00000000..bdbb3dcd --- /dev/null +++ b/Zend/Gdata/Photos/Extension/Name.php @@ -0,0 +1,62 @@ +registerAllNamespaces(Zend_Gdata_Photos::$namespaces); + parent::__construct(); + $this->setText($text); + } + +} diff --git a/Zend/Gdata/Photos/Extension/Nickname.php b/Zend/Gdata/Photos/Extension/Nickname.php new file mode 100644 index 00000000..d33f83d9 --- /dev/null +++ b/Zend/Gdata/Photos/Extension/Nickname.php @@ -0,0 +1,62 @@ +registerAllNamespaces(Zend_Gdata_Photos::$namespaces); + parent::__construct(); + $this->setText($text); + } + +} diff --git a/Zend/Gdata/Photos/Extension/NumPhotos.php b/Zend/Gdata/Photos/Extension/NumPhotos.php new file mode 100644 index 00000000..eb3db51c --- /dev/null +++ b/Zend/Gdata/Photos/Extension/NumPhotos.php @@ -0,0 +1,62 @@ +registerAllNamespaces(Zend_Gdata_Photos::$namespaces); + parent::__construct(); + $this->setText($text); + } + +} diff --git a/Zend/Gdata/Photos/Extension/NumPhotosRemaining.php b/Zend/Gdata/Photos/Extension/NumPhotosRemaining.php new file mode 100644 index 00000000..4c89bc65 --- /dev/null +++ b/Zend/Gdata/Photos/Extension/NumPhotosRemaining.php @@ -0,0 +1,62 @@ +registerAllNamespaces(Zend_Gdata_Photos::$namespaces); + parent::__construct(); + $this->setText($text); + } + +} diff --git a/Zend/Gdata/Photos/Extension/PhotoId.php b/Zend/Gdata/Photos/Extension/PhotoId.php new file mode 100644 index 00000000..b18a7519 --- /dev/null +++ b/Zend/Gdata/Photos/Extension/PhotoId.php @@ -0,0 +1,61 @@ +registerAllNamespaces(Zend_Gdata_Photos::$namespaces); + parent::__construct(); + $this->setText($text); + } + +} diff --git a/Zend/Gdata/Photos/Extension/Position.php b/Zend/Gdata/Photos/Extension/Position.php new file mode 100644 index 00000000..e9721726 --- /dev/null +++ b/Zend/Gdata/Photos/Extension/Position.php @@ -0,0 +1,62 @@ +registerAllNamespaces(Zend_Gdata_Photos::$namespaces); + parent::__construct(); + $this->setText($text); + } + +} diff --git a/Zend/Gdata/Photos/Extension/QuotaCurrent.php b/Zend/Gdata/Photos/Extension/QuotaCurrent.php new file mode 100644 index 00000000..c023fec5 --- /dev/null +++ b/Zend/Gdata/Photos/Extension/QuotaCurrent.php @@ -0,0 +1,62 @@ +registerAllNamespaces(Zend_Gdata_Photos::$namespaces); + parent::__construct(); + $this->setText($text); + } + +} diff --git a/Zend/Gdata/Photos/Extension/QuotaLimit.php b/Zend/Gdata/Photos/Extension/QuotaLimit.php new file mode 100644 index 00000000..860ac67c --- /dev/null +++ b/Zend/Gdata/Photos/Extension/QuotaLimit.php @@ -0,0 +1,63 @@ +registerAllNamespaces(Zend_Gdata_Photos::$namespaces); + parent::__construct(); + $this->setText($text); + } + +} diff --git a/Zend/Gdata/Photos/Extension/Rotation.php b/Zend/Gdata/Photos/Extension/Rotation.php new file mode 100644 index 00000000..69db345a --- /dev/null +++ b/Zend/Gdata/Photos/Extension/Rotation.php @@ -0,0 +1,63 @@ +registerAllNamespaces(Zend_Gdata_Photos::$namespaces); + parent::__construct(); + $this->setText($text); + } + +} diff --git a/Zend/Gdata/Photos/Extension/Size.php b/Zend/Gdata/Photos/Extension/Size.php new file mode 100644 index 00000000..0990ead6 --- /dev/null +++ b/Zend/Gdata/Photos/Extension/Size.php @@ -0,0 +1,62 @@ +registerAllNamespaces(Zend_Gdata_Photos::$namespaces); + parent::__construct(); + $this->setText($text); + } + +} diff --git a/Zend/Gdata/Photos/Extension/Thumbnail.php b/Zend/Gdata/Photos/Extension/Thumbnail.php new file mode 100644 index 00000000..aa875540 --- /dev/null +++ b/Zend/Gdata/Photos/Extension/Thumbnail.php @@ -0,0 +1,62 @@ +registerAllNamespaces(Zend_Gdata_Photos::$namespaces); + parent::__construct(); + $this->setText($text); + } + +} diff --git a/Zend/Gdata/Photos/Extension/Timestamp.php b/Zend/Gdata/Photos/Extension/Timestamp.php new file mode 100644 index 00000000..fbdda208 --- /dev/null +++ b/Zend/Gdata/Photos/Extension/Timestamp.php @@ -0,0 +1,63 @@ +registerAllNamespaces(Zend_Gdata_Photos::$namespaces); + parent::__construct(); + $this->setText($text); + } + +} diff --git a/Zend/Gdata/Photos/Extension/User.php b/Zend/Gdata/Photos/Extension/User.php new file mode 100644 index 00000000..cb58eb8e --- /dev/null +++ b/Zend/Gdata/Photos/Extension/User.php @@ -0,0 +1,62 @@ +registerAllNamespaces(Zend_Gdata_Photos::$namespaces); + parent::__construct(); + $this->setText($text); + } + +} diff --git a/Zend/Gdata/Photos/Extension/Version.php b/Zend/Gdata/Photos/Extension/Version.php new file mode 100644 index 00000000..b8f6d984 --- /dev/null +++ b/Zend/Gdata/Photos/Extension/Version.php @@ -0,0 +1,63 @@ +registerAllNamespaces(Zend_Gdata_Photos::$namespaces); + parent::__construct(); + $this->setText($text); + } + +} diff --git a/Zend/Gdata/Photos/Extension/Weight.php b/Zend/Gdata/Photos/Extension/Weight.php new file mode 100644 index 00000000..7b7ee5bd --- /dev/null +++ b/Zend/Gdata/Photos/Extension/Weight.php @@ -0,0 +1,63 @@ +registerAllNamespaces(Zend_Gdata_Photos::$namespaces); + parent::__construct(); + $this->setText($text); + } + +} diff --git a/Zend/Gdata/Photos/Extension/Width.php b/Zend/Gdata/Photos/Extension/Width.php new file mode 100644 index 00000000..e9741cb7 --- /dev/null +++ b/Zend/Gdata/Photos/Extension/Width.php @@ -0,0 +1,62 @@ +registerAllNamespaces(Zend_Gdata_Photos::$namespaces); + parent::__construct(); + $this->setText($text); + } + +} diff --git a/Zend/Gdata/Photos/PhotoEntry.php b/Zend/Gdata/Photos/PhotoEntry.php new file mode 100644 index 00000000..fd2e289d --- /dev/null +++ b/Zend/Gdata/Photos/PhotoEntry.php @@ -0,0 +1,691 @@ + in the Google Data protocol. + * + * @category Zend + * @package Zend_Gdata + * @subpackage Photos + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +class Zend_Gdata_Photos_PhotoEntry extends Zend_Gdata_Media_Entry +{ + + protected $_entryClassName = 'Zend_Gdata_Photos_PhotoEntry'; + + /** + * gphoto:id element + * + * @var Zend_Gdata_Photos_Extension_Id + */ + protected $_gphotoId = null; + + /** + * gphoto:albumid element + * + * @var Zend_Gdata_Photos_Extension_AlbumId + */ + protected $_gphotoAlbumId = null; + + /** + * gphoto:version element + * + * @var Zend_Gdata_Photos_Extension_Version + */ + protected $_gphotoVersion = null; + + /** + * gphoto:width element + * + * @var Zend_Gdata_Photos_Extension_Width + */ + protected $_gphotoWidth = null; + + /** + * gphoto:height element + * + * @var Zend_Gdata_Photos_Extension_Height + */ + protected $_gphotoHeight = null; + + /** + * gphoto:size element + * + * @var Zend_Gdata_Photos_Extension_Size + */ + protected $_gphotoSize = null; + + /** + * gphoto:client element + * + * @var Zend_Gdata_Photos_Extension_Client + */ + protected $_gphotoClient = null; + + /** + * gphoto:checksum element + * + * @var Zend_Gdata_Photos_Extension_Checksum + */ + protected $_gphotoChecksum = null; + + /** + * gphoto:timestamp element + * + * @var Zend_Gdata_Photos_Extension_Timestamp + */ + protected $_gphotoTimestamp = null; + + /** + * gphoto:commentCount element + * + * @var Zend_Gdata_Photos_Extension_CommentCount + */ + protected $_gphotoCommentCount = null; + + /** + * gphoto:commentingEnabled element + * + * @var Zend_Gdata_Photos_Extension_CommentingEnabled + */ + protected $_gphotoCommentingEnabled = null; + + /** + * exif:tags element + * + * @var Zend_Gdata_Exif_Extension_Tags + */ + protected $_exifTags = null; + + /** + * georss:where element + * + * @var Zend_Gdata_Geo_Extension_GeoRssWhere + */ + protected $_geoRssWhere = null; + + /** + * Create a new instance. + * + * @param DOMElement $element (optional) DOMElement from which this + * object should be constructed. + */ + public function __construct($element = null) + { + $this->registerAllNamespaces(Zend_Gdata_Photos::$namespaces); + parent::__construct($element); + + $category = new Zend_Gdata_App_Extension_Category( + 'http://schemas.google.com/photos/2007#photo', + 'http://schemas.google.com/g/2005#kind'); + $this->setCategory(array($category)); + } + + /** + * Retrieves a DOMElement which corresponds to this element and all + * child properties. This is used to build an entry back into a DOM + * and eventually XML text for application storage/persistence. + * + * @param DOMDocument $doc The DOMDocument used to construct DOMElements + * @return DOMElement The DOMElement representing this element and all + * child properties. + */ + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc, $majorVersion, $minorVersion); + if ($this->_gphotoAlbumId !== null) { + $element->appendChild($this->_gphotoAlbumId->getDOM($element->ownerDocument)); + } + if ($this->_gphotoId !== null) { + $element->appendChild($this->_gphotoId->getDOM($element->ownerDocument)); + } + if ($this->_gphotoVersion !== null) { + $element->appendChild($this->_gphotoVersion->getDOM($element->ownerDocument)); + } + if ($this->_gphotoWidth !== null) { + $element->appendChild($this->_gphotoWidth->getDOM($element->ownerDocument)); + } + if ($this->_gphotoHeight !== null) { + $element->appendChild($this->_gphotoHeight->getDOM($element->ownerDocument)); + } + if ($this->_gphotoSize !== null) { + $element->appendChild($this->_gphotoSize->getDOM($element->ownerDocument)); + } + if ($this->_gphotoClient !== null) { + $element->appendChild($this->_gphotoClient->getDOM($element->ownerDocument)); + } + if ($this->_gphotoChecksum !== null) { + $element->appendChild($this->_gphotoChecksum->getDOM($element->ownerDocument)); + } + if ($this->_gphotoTimestamp !== null) { + $element->appendChild($this->_gphotoTimestamp->getDOM($element->ownerDocument)); + } + if ($this->_gphotoCommentingEnabled !== null) { + $element->appendChild($this->_gphotoCommentingEnabled->getDOM($element->ownerDocument)); + } + if ($this->_gphotoCommentCount !== null) { + $element->appendChild($this->_gphotoCommentCount->getDOM($element->ownerDocument)); + } + if ($this->_exifTags !== null) { + $element->appendChild($this->_exifTags->getDOM($element->ownerDocument)); + } + if ($this->_geoRssWhere !== null) { + $element->appendChild($this->_geoRssWhere->getDOM($element->ownerDocument)); + } + return $element; + } + + /** + * Creates individual Entry objects of the appropriate type and + * stores them as members of this entry based upon DOM data. + * + * @param DOMNode $child The DOMNode to process + */ + protected function takeChildFromDOM($child) + { + $absoluteNodeName = $child->namespaceURI . ':' . $child->localName; + + switch ($absoluteNodeName) { + case $this->lookupNamespace('gphoto') . ':' . 'albumid'; + $albumId = new Zend_Gdata_Photos_Extension_AlbumId(); + $albumId->transferFromDOM($child); + $this->_gphotoAlbumId = $albumId; + break; + case $this->lookupNamespace('gphoto') . ':' . 'id'; + $id = new Zend_Gdata_Photos_Extension_Id(); + $id->transferFromDOM($child); + $this->_gphotoId = $id; + break; + case $this->lookupNamespace('gphoto') . ':' . 'version'; + $version = new Zend_Gdata_Photos_Extension_Version(); + $version->transferFromDOM($child); + $this->_gphotoVersion = $version; + break; + case $this->lookupNamespace('gphoto') . ':' . 'width'; + $width = new Zend_Gdata_Photos_Extension_Width(); + $width->transferFromDOM($child); + $this->_gphotoWidth = $width; + break; + case $this->lookupNamespace('gphoto') . ':' . 'height'; + $height = new Zend_Gdata_Photos_Extension_Height(); + $height->transferFromDOM($child); + $this->_gphotoHeight = $height; + break; + case $this->lookupNamespace('gphoto') . ':' . 'size'; + $size = new Zend_Gdata_Photos_Extension_Size(); + $size->transferFromDOM($child); + $this->_gphotoSize = $size; + break; + case $this->lookupNamespace('gphoto') . ':' . 'client'; + $client = new Zend_Gdata_Photos_Extension_Client(); + $client->transferFromDOM($child); + $this->_gphotoClient = $client; + break; + case $this->lookupNamespace('gphoto') . ':' . 'checksum'; + $checksum = new Zend_Gdata_Photos_Extension_Checksum(); + $checksum->transferFromDOM($child); + $this->_gphotoChecksum = $checksum; + break; + case $this->lookupNamespace('gphoto') . ':' . 'timestamp'; + $timestamp = new Zend_Gdata_Photos_Extension_Timestamp(); + $timestamp->transferFromDOM($child); + $this->_gphotoTimestamp = $timestamp; + break; + case $this->lookupNamespace('gphoto') . ':' . 'commentingEnabled'; + $commentingEnabled = new Zend_Gdata_Photos_Extension_CommentingEnabled(); + $commentingEnabled->transferFromDOM($child); + $this->_gphotoCommentingEnabled = $commentingEnabled; + break; + case $this->lookupNamespace('gphoto') . ':' . 'commentCount'; + $commentCount = new Zend_Gdata_Photos_Extension_CommentCount(); + $commentCount->transferFromDOM($child); + $this->_gphotoCommentCount = $commentCount; + break; + case $this->lookupNamespace('exif') . ':' . 'tags'; + $exifTags = new Zend_Gdata_Exif_Extension_Tags(); + $exifTags->transferFromDOM($child); + $this->_exifTags = $exifTags; + break; + case $this->lookupNamespace('georss') . ':' . 'where'; + $geoRssWhere = new Zend_Gdata_Geo_Extension_GeoRssWhere(); + $geoRssWhere->transferFromDOM($child); + $this->_geoRssWhere = $geoRssWhere; + break; + default: + parent::takeChildFromDOM($child); + break; + + } + } + + /** + * Get the value for this element's gphoto:albumid attribute. + * + * @see setGphotoAlbumId + * @return string The requested attribute. + */ + public function getGphotoAlbumId() + { + return $this->_gphotoAlbumId; + } + + /** + * Set the value for this element's gphoto:albumid attribute. + * + * @param string $value The desired value for this attribute. + * @return Zend_Gdata_Photos_Extension_AlbumId The element being modified. + */ + public function setGphotoAlbumId($value) + { + $this->_gphotoAlbumId = $value; + return $this; + } + + /** + * Get the value for this element's gphoto:id attribute. + * + * @see setGphotoId + * @return string The requested attribute. + */ + public function getGphotoId() + { + return $this->_gphotoId; + } + + /** + * Set the value for this element's gphoto:id attribute. + * + * @param string $value The desired value for this attribute. + * @return Zend_Gdata_Photos_Extension_Id The element being modified. + */ + public function setGphotoId($value) + { + $this->_gphotoId = $value; + return $this; + } + + /** + * Get the value for this element's gphoto:version attribute. + * + * @see setGphotoVersion + * @return string The requested attribute. + */ + public function getGphotoVersion() + { + return $this->_gphotoVersion; + } + + /** + * Set the value for this element's gphoto:version attribute. + * + * @param string $value The desired value for this attribute. + * @return Zend_Gdata_Photos_Extension_Version The element being modified. + */ + public function setGphotoVersion($value) + { + $this->_gphotoVersion = $value; + return $this; + } + + /** + * Get the value for this element's gphoto:width attribute. + * + * @see setGphotoWidth + * @return string The requested attribute. + */ + public function getGphotoWidth() + { + return $this->_gphotoWidth; + } + + /** + * Set the value for this element's gphoto:width attribute. + * + * @param string $value The desired value for this attribute. + * @return Zend_Gdata_Photos_Extension_Width The element being modified. + */ + public function setGphotoWidth($value) + { + $this->_gphotoWidth = $value; + return $this; + } + + /** + * Get the value for this element's gphoto:height attribute. + * + * @see setGphotoHeight + * @return string The requested attribute. + */ + public function getGphotoHeight() + { + return $this->_gphotoHeight; + } + + /** + * Set the value for this element's gphoto:height attribute. + * + * @param string $value The desired value for this attribute. + * @return Zend_Gdata_Photos_Extension_Height The element being modified. + */ + public function setGphotoHeight($value) + { + $this->_gphotoHeight = $value; + return $this; + } + + /** + * Get the value for this element's gphoto:size attribute. + * + * @see setGphotoSize + * @return string The requested attribute. + */ + public function getGphotoSize() + { + return $this->_gphotoSize; + } + + /** + * Set the value for this element's gphoto:size attribute. + * + * @param string $value The desired value for this attribute. + * @return Zend_Gdata_Photos_Extension_Size The element being modified. + */ + public function setGphotoSize($value) + { + $this->_gphotoSize = $value; + return $this; + } + + /** + * Get the value for this element's gphoto:client attribute. + * + * @see setGphotoClient + * @return string The requested attribute. + */ + public function getGphotoClient() + { + return $this->_gphotoClient; + } + + /** + * Set the value for this element's gphoto:client attribute. + * + * @param string $value The desired value for this attribute. + * @return Zend_Gdata_Photos_Extension_Client The element being modified. + */ + public function setGphotoClient($value) + { + $this->_gphotoClient = $value; + return $this; + } + + /** + * Get the value for this element's gphoto:checksum attribute. + * + * @see setGphotoChecksum + * @return string The requested attribute. + */ + public function getGphotoChecksum() + { + return $this->_gphotoChecksum; + } + + /** + * Set the value for this element's gphoto:checksum attribute. + * + * @param string $value The desired value for this attribute. + * @return Zend_Gdata_Photos_Extension_Checksum The element being modified. + */ + public function setGphotoChecksum($value) + { + $this->_gphotoChecksum = $value; + return $this; + } + + /** + * Get the value for this element's gphoto:timestamp attribute. + * + * @see setGphotoTimestamp + * @return string The requested attribute. + */ + public function getGphotoTimestamp() + { + return $this->_gphotoTimestamp; + } + + /** + * Set the value for this element's gphoto:timestamp attribute. + * + * @param string $value The desired value for this attribute. + * @return Zend_Gdata_Photos_Extension_Timestamp The element being modified. + */ + public function setGphotoTimestamp($value) + { + $this->_gphotoTimestamp = $value; + return $this; + } + + /** + * Get the value for this element's gphoto:commentCount attribute. + * + * @see setGphotoCommentCount + * @return string The requested attribute. + */ + public function getGphotoCommentCount() + { + return $this->_gphotoCommentCount; + } + + /** + * Set the value for this element's gphoto:commentCount attribute. + * + * @param string $value The desired value for this attribute. + * @return Zend_Gdata_Photos_Extension_CommentCount The element being modified. + */ + public function setGphotoCommentCount($value) + { + $this->_gphotoCommentCount = $value; + return $this; + } + + /** + * Get the value for this element's gphoto:commentingEnabled attribute. + * + * @see setGphotoCommentingEnabled + * @return string The requested attribute. + */ + public function getGphotoCommentingEnabled() + { + return $this->_gphotoCommentingEnabled; + } + + /** + * Set the value for this element's gphoto:commentingEnabled attribute. + * + * @param string $value The desired value for this attribute. + * @return Zend_Gdata_Photos_Extension_CommentingEnabled The element being modified. + */ + public function setGphotoCommentingEnabled($value) + { + $this->_gphotoCommentingEnabled = $value; + return $this; + } + + /** + * Get the value for this element's exif:tags attribute. + * + * @see setExifTags + * @return string The requested attribute. + */ + public function getExifTags() + { + return $this->_exifTags; + } + + /** + * Set the value for this element's exif:tags attribute. + * + * @param string $value The desired value for this attribute. + * @return Zend_Gdata_Exif_Extension_Tags The element being modified. + */ + public function setExifTags($value) + { + $this->_exifTags = $value; + return $this; + } + + /** + * Get the value for this element's georss:where attribute. + * + * @see setGeoRssWhere + * @return string The requested attribute. + */ + public function getGeoRssWhere() + { + return $this->_geoRssWhere; + } + + /** + * Set the value for this element's georss:where attribute. + * + * @param string $value The desired value for this attribute. + * @return Zend_Gdata_Geo_Extension_GeoRssWhere The element being modified. + */ + public function setGeoRssWhere($value) + { + $this->_geoRssWhere = $value; + return $this; + } + + /** + * Get the value for this element's media:group attribute. + * + * @see setMediaGroup + * @return string The requested attribute. + */ + public function getMediaGroup() + { + return $this->_mediaGroup; + } + + /** + * Set the value for this element's media:group attribute. + * + * @param string $value The desired value for this attribute. + * @return Zend_Gdata_Media_Extension_MediaGroup The element being modified. + */ + public function setMediaGroup($value) + { + $this->_mediaGroup = $value; + return $this; + } + +} diff --git a/Zend/Gdata/Photos/PhotoFeed.php b/Zend/Gdata/Photos/PhotoFeed.php new file mode 100644 index 00000000..21a314a7 --- /dev/null +++ b/Zend/Gdata/Photos/PhotoFeed.php @@ -0,0 +1,559 @@ + 'Zend_Gdata_Photos_CommentEntry', + 'http://schemas.google.com/photos/2007#tag' => 'Zend_Gdata_Photos_TagEntry' + ); + + public function __construct($element = null) + { + $this->registerAllNamespaces(Zend_Gdata_Photos::$namespaces); + parent::__construct($element); + } + + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc, $majorVersion, $minorVersion); + if ($this->_gphotoId != null) { + $element->appendChild($this->_gphotoId->getDOM($element->ownerDocument)); + } + if ($this->_gphotoVersion != null) { + $element->appendChild($this->_gphotoVersion->getDOM($element->ownerDocument)); + } + if ($this->_gphotoWidth != null) { + $element->appendChild($this->_gphotoWidth->getDOM($element->ownerDocument)); + } + if ($this->_gphotoHeight != null) { + $element->appendChild($this->_gphotoHeight->getDOM($element->ownerDocument)); + } + if ($this->_gphotoSize != null) { + $element->appendChild($this->_gphotoSize->getDOM($element->ownerDocument)); + } + if ($this->_gphotoClient != null) { + $element->appendChild($this->_gphotoClient->getDOM($element->ownerDocument)); + } + if ($this->_gphotoChecksum != null) { + $element->appendChild($this->_gphotoChecksum->getDOM($element->ownerDocument)); + } + if ($this->_gphotoTimestamp != null) { + $element->appendChild($this->_gphotoTimestamp->getDOM($element->ownerDocument)); + } + if ($this->_gphotoCommentingEnabled != null) { + $element->appendChild($this->_gphotoCommentingEnabled->getDOM($element->ownerDocument)); + } + if ($this->_gphotoCommentCount != null) { + $element->appendChild($this->_gphotoCommentCount->getDOM($element->ownerDocument)); + } + if ($this->_mediaGroup != null) { + $element->appendChild($this->_mediaGroup->getDOM($element->ownerDocument)); + } + + return $element; + } + + protected function takeChildFromDOM($child) + { + $absoluteNodeName = $child->namespaceURI . ':' . $child->localName; + + switch ($absoluteNodeName) { + case $this->lookupNamespace('gphoto') . ':' . 'id'; + $id = new Zend_Gdata_Photos_Extension_Id(); + $id->transferFromDOM($child); + $this->_gphotoId = $id; + break; + case $this->lookupNamespace('gphoto') . ':' . 'version'; + $version = new Zend_Gdata_Photos_Extension_Version(); + $version->transferFromDOM($child); + $this->_gphotoVersion = $version; + break; + case $this->lookupNamespace('gphoto') . ':' . 'albumid'; + $albumid = new Zend_Gdata_Photos_Extension_AlbumId(); + $albumid->transferFromDOM($child); + $this->_gphotoAlbumId = $albumid; + break; + case $this->lookupNamespace('gphoto') . ':' . 'width'; + $width = new Zend_Gdata_Photos_Extension_Width(); + $width->transferFromDOM($child); + $this->_gphotoWidth = $width; + break; + case $this->lookupNamespace('gphoto') . ':' . 'height'; + $height = new Zend_Gdata_Photos_Extension_Height(); + $height->transferFromDOM($child); + $this->_gphotoHeight = $height; + break; + case $this->lookupNamespace('gphoto') . ':' . 'size'; + $size = new Zend_Gdata_Photos_Extension_Size(); + $size->transferFromDOM($child); + $this->_gphotoSize = $size; + break; + case $this->lookupNamespace('gphoto') . ':' . 'client'; + $client = new Zend_Gdata_Photos_Extension_Client(); + $client->transferFromDOM($child); + $this->_gphotoClient = $client; + break; + case $this->lookupNamespace('gphoto') . ':' . 'checksum'; + $checksum = new Zend_Gdata_Photos_Extension_Checksum(); + $checksum->transferFromDOM($child); + $this->_gphotoChecksum = $checksum; + break; + case $this->lookupNamespace('gphoto') . ':' . 'timestamp'; + $timestamp = new Zend_Gdata_Photos_Extension_Timestamp(); + $timestamp->transferFromDOM($child); + $this->_gphotoTimestamp = $timestamp; + break; + case $this->lookupNamespace('gphoto') . ':' . 'commentingEnabled'; + $commentingEnabled = new Zend_Gdata_Photos_Extension_CommentingEnabled(); + $commentingEnabled->transferFromDOM($child); + $this->_gphotoCommentingEnabled = $commentingEnabled; + break; + case $this->lookupNamespace('gphoto') . ':' . 'commentCount'; + $commentCount = new Zend_Gdata_Photos_Extension_CommentCount(); + $commentCount->transferFromDOM($child); + $this->_gphotoCommentCount = $commentCount; + break; + case $this->lookupNamespace('media') . ':' . 'group'; + $mediaGroup = new Zend_Gdata_Media_Extension_MediaGroup(); + $mediaGroup->transferFromDOM($child); + $this->_mediaGroup = $mediaGroup; + break; + case $this->lookupNamespace('atom') . ':' . 'entry': + $entryClassName = $this->_entryClassName; + $tmpEntry = new Zend_Gdata_App_Entry($child); + $categories = $tmpEntry->getCategory(); + foreach ($categories as $category) { + if ($category->scheme == Zend_Gdata_Photos::KIND_PATH && + $this->_entryKindClassMapping[$category->term] != "") { + $entryClassName = $this->_entryKindClassMapping[$category->term]; + break; + } else { + require_once 'Zend/Gdata/App/Exception.php'; + throw new Zend_Gdata_App_Exception('Entry is missing kind declaration.'); + } + } + + $newEntry = new $entryClassName($child); + $newEntry->setHttpClient($this->getHttpClient()); + $this->_entry[] = $newEntry; + break; + default: + parent::takeChildFromDOM($child); + break; + } + } + + /** + * Get the value for this element's gphoto:id attribute. + * + * @see setGphotoId + * @return string The requested attribute. + */ + public function getGphotoId() + { + return $this->_gphotoId; + } + + /** + * Set the value for this element's gphoto:id attribute. + * + * @param string $value The desired value for this attribute. + * @return Zend_Gdata_Photos_Extension_Id The element being modified. + */ + public function setGphotoId($value) + { + $this->_gphotoId = $value; + return $this; + } + + /** + * Get the value for this element's gphoto:version attribute. + * + * @see setGphotoVersion + * @return string The requested attribute. + */ + public function getGphotoVersion() + { + return $this->_gphotoVersion; + } + + /** + * Set the value for this element's gphoto:version attribute. + * + * @param string $value The desired value for this attribute. + * @return Zend_Gdata_Photos_Extension_Version The element being modified. + */ + public function setGphotoVersion($value) + { + $this->_gphotoVersion = $value; + return $this; + } + + /** + * Get the value for this element's gphoto:albumid attribute. + * + * @see setGphotoAlbumId + * @return string The requested attribute. + */ + public function getGphotoAlbumId() + { + return $this->_gphotoAlbumId; + } + + /** + * Set the value for this element's gphoto:albumid attribute. + * + * @param string $value The desired value for this attribute. + * @return Zend_Gdata_Photos_Extension_AlbumId The element being modified. + */ + public function setGphotoAlbumId($value) + { + $this->_gphotoAlbumId = $value; + return $this; + } + + /** + * Get the value for this element's gphoto:width attribute. + * + * @see setGphotoWidth + * @return string The requested attribute. + */ + public function getGphotoWidth() + { + return $this->_gphotoWidth; + } + + /** + * Set the value for this element's gphoto:width attribute. + * + * @param string $value The desired value for this attribute. + * @return Zend_Gdata_Photos_Extension_Width The element being modified. + */ + public function setGphotoWidth($value) + { + $this->_gphotoWidth = $value; + return $this; + } + + /** + * Get the value for this element's gphoto:height attribute. + * + * @see setGphotoHeight + * @return string The requested attribute. + */ + public function getGphotoHeight() + { + return $this->_gphotoHeight; + } + + /** + * Set the value for this element's gphoto:height attribute. + * + * @param string $value The desired value for this attribute. + * @return Zend_Gdata_Photos_Extension_Height The element being modified. + */ + public function setGphotoHeight($value) + { + $this->_gphotoHeight = $value; + return $this; + } + + /** + * Get the value for this element's gphoto:size attribute. + * + * @see setGphotoSize + * @return string The requested attribute. + */ + public function getGphotoSize() + { + return $this->_gphotoSize; + } + + /** + * Set the value for this element's gphoto:size attribute. + * + * @param string $value The desired value for this attribute. + * @return Zend_Gdata_Photos_Extension_Size The element being modified. + */ + public function setGphotoSize($value) + { + $this->_gphotoSize = $value; + return $this; + } + + /** + * Get the value for this element's gphoto:client attribute. + * + * @see setGphotoClient + * @return string The requested attribute. + */ + public function getGphotoClient() + { + return $this->_gphotoClient; + } + + /** + * Set the value for this element's gphoto:client attribute. + * + * @param string $value The desired value for this attribute. + * @return Zend_Gdata_Photos_Extension_Client The element being modified. + */ + public function setGphotoClient($value) + { + $this->_gphotoClient = $value; + return $this; + } + + /** + * Get the value for this element's gphoto:checksum attribute. + * + * @see setGphotoChecksum + * @return string The requested attribute. + */ + public function getGphotoChecksum() + { + return $this->_gphotoChecksum; + } + + /** + * Set the value for this element's gphoto:checksum attribute. + * + * @param string $value The desired value for this attribute. + * @return Zend_Gdata_Photos_Extension_Checksum The element being modified. + */ + public function setGphotoChecksum($value) + { + $this->_gphotoChecksum = $value; + return $this; + } + + /** + * Get the value for this element's gphoto:timestamp attribute. + * + * @see setGphotoTimestamp + * @return string The requested attribute. + */ + public function getGphotoTimestamp() + { + return $this->_gphotoTimestamp; + } + + /** + * Set the value for this element's gphoto:timestamp attribute. + * + * @param string $value The desired value for this attribute. + * @return Zend_Gdata_Photos_Extension_Timestamp The element being modified. + */ + public function setGphotoTimestamp($value) + { + $this->_gphotoTimestamp = $value; + return $this; + } + + /** + * Get the value for this element's gphoto:commentCount attribute. + * + * @see setGphotoCommentCount + * @return string The requested attribute. + */ + public function getGphotoCommentCount() + { + return $this->_gphotoCommentCount; + } + + /** + * Set the value for this element's gphoto:commentCount attribute. + * + * @param string $value The desired value for this attribute. + * @return Zend_Gdata_Photos_Extension_CommentCount The element being modified. + */ + public function setGphotoCommentCount($value) + { + $this->_gphotoCommentCount = $value; + return $this; + } + + /** + * Get the value for this element's gphoto:commentingEnabled attribute. + * + * @see setGphotoCommentingEnabled + * @return string The requested attribute. + */ + public function getGphotoCommentingEnabled() + { + return $this->_gphotoCommentingEnabled; + } + + /** + * Set the value for this element's gphoto:commentingEnabled attribute. + * + * @param string $value The desired value for this attribute. + * @return Zend_Gdata_Photos_Extension_CommentingEnabled The element being modified. + */ + public function setGphotoCommentingEnabled($value) + { + $this->_gphotoCommentingEnabled = $value; + return $this; + } + + /** + * Get the value for this element's media:group attribute. + * + * @see setMediaGroup + * @return string The requested attribute. + */ + public function getMediaGroup() + { + return $this->_mediaGroup; + } + + /** + * Set the value for this element's media:group attribute. + * + * @param string $value The desired value for this attribute. + * @return Zend_Gdata_Media_Extension_MediaGroup The element being modified. + */ + public function setMediaGroup($value) + { + $this->_mediaGroup = $value; + return $this; + } + +} diff --git a/Zend/Gdata/Photos/PhotoQuery.php b/Zend/Gdata/Photos/PhotoQuery.php new file mode 100644 index 00000000..1fc94c74 --- /dev/null +++ b/Zend/Gdata/Photos/PhotoQuery.php @@ -0,0 +1,98 @@ +_photoId = $value; + } + + /** + * Get the photo ID which is to be returned. + * + * @see setPhoto + * @return string The ID of the photo to retrieve. + */ + public function getPhotoId() + { + return $this->_photoId; + } + + /** + * Returns the URL generated for this query, based on it's current + * parameters. + * + * @return string A URL generated based on the state of this query. + * @throws Zend_Gdata_App_InvalidArgumentException + */ + public function getQueryUrl($incomingUri = '') + { + $uri = ''; + if ($this->getPhotoId() !== null) { + $uri .= '/photoid/' . $this->getPhotoId(); + } else { + require_once 'Zend/Gdata/App/InvalidArgumentException.php'; + throw new Zend_Gdata_App_InvalidArgumentException( + 'PhotoId cannot be null'); + } + $uri .= $incomingUri; + return parent::getQueryUrl($uri); + } + +} diff --git a/Zend/Gdata/Photos/TagEntry.php b/Zend/Gdata/Photos/TagEntry.php new file mode 100644 index 00000000..908674cd --- /dev/null +++ b/Zend/Gdata/Photos/TagEntry.php @@ -0,0 +1,140 @@ + in the Google Data protocol. + * + * @category Zend + * @package Zend_Gdata + * @subpackage Photos + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +class Zend_Gdata_Photos_TagEntry extends Zend_Gdata_Entry +{ + + protected $_entryClassName = 'Zend_Gdata_Photos_TagEntry'; + + protected $_gphotoWeight = null; + + /** + * Create a new instance. + * + * @param DOMElement $element (optional) DOMElement from which this + * object should be constructed. + */ + public function __construct($element = null) + { + $this->registerAllNamespaces(Zend_Gdata_Photos::$namespaces); + parent::__construct($element); + + $category = new Zend_Gdata_App_Extension_Category( + 'http://schemas.google.com/photos/2007#tag', + 'http://schemas.google.com/g/2005#kind'); + $this->setCategory(array($category)); + } + + /** + * Retrieves a DOMElement which corresponds to this element and all + * child properties. This is used to build an entry back into a DOM + * and eventually XML text for application storage/persistence. + * + * @param DOMDocument $doc The DOMDocument used to construct DOMElements + * @return DOMElement The DOMElement representing this element and all + * child properties. + */ + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc, $majorVersion, $minorVersion); + if ($this->_gphotoWeight !== null) { + $element->appendChild($this->_gphotoWeight->getDOM($element->ownerDocument)); + } + return $element; + } + + /** + * Creates individual Entry objects of the appropriate type and + * stores them as members of this entry based upon DOM data. + * + * @param DOMNode $child The DOMNode to process + */ + protected function takeChildFromDOM($child) + { + $absoluteNodeName = $child->namespaceURI . ':' . $child->localName; + + switch ($absoluteNodeName) { + case $this->lookupNamespace('gphoto') . ':' . 'weight'; + $weight = new Zend_Gdata_Photos_Extension_Weight(); + $weight->transferFromDOM($child); + $this->_gphotoWeight = $weight; + break; + default: + parent::takeChildFromDOM($child); + break; + } + } + + /** + * Get the value for this element's gphoto:weight attribute. + * + * @see setGphotoWeight + * @return string The requested attribute. + */ + public function getGphotoWeight() + { + return $this->_gphotoWeight; + } + + /** + * Set the value for this element's gphoto:weight attribute. + * + * @param string $value The desired value for this attribute. + * @return Zend_Gdata_Photos_Extension_Weight The element being modified. + */ + public function setGphotoWeight($value) + { + $this->_gphotoWeight = $value; + return $this; + } +} diff --git a/Zend/Gdata/Photos/UserEntry.php b/Zend/Gdata/Photos/UserEntry.php new file mode 100644 index 00000000..a21c6367 --- /dev/null +++ b/Zend/Gdata/Photos/UserEntry.php @@ -0,0 +1,366 @@ + in the Google Data protocol. + * + * @category Zend + * @package Zend_Gdata + * @subpackage Photos + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +class Zend_Gdata_Photos_UserEntry extends Zend_Gdata_Entry +{ + + protected $_entryClassName = 'Zend_Gdata_Photos_UserEntry'; + + /** + * gphoto:nickname element + * + * @var Zend_Gdata_Photos_Extension_Nickname + */ + protected $_gphotoNickname = null; + + /** + * gphoto:user element + * + * @var Zend_Gdata_Photos_Extension_User + */ + protected $_gphotoUser = null; + + /** + * gphoto:thumbnail element + * + * @var Zend_Gdata_Photos_Extension_Thumbnail + */ + protected $_gphotoThumbnail = null; + + /** + * gphoto:quotalimit element + * + * @var Zend_Gdata_Photos_Extension_QuotaLimit + */ + protected $_gphotoQuotaLimit = null; + + /** + * gphoto:quotacurrent element + * + * @var Zend_Gdata_Photos_Extension_QuotaCurrent + */ + protected $_gphotoQuotaCurrent = null; + + /** + * gphoto:maxPhotosPerAlbum element + * + * @var Zend_Gdata_Photos_Extension_MaxPhotosPerAlbum + */ + protected $_gphotoMaxPhotosPerAlbum = null; + + /** + * Create a new instance. + * + * @param DOMElement $element (optional) DOMElement from which this + * object should be constructed. + */ + public function __construct($element = null) + { + $this->registerAllNamespaces(Zend_Gdata_Photos::$namespaces); + parent::__construct($element); + + $category = new Zend_Gdata_App_Extension_Category( + 'http://schemas.google.com/photos/2007#user', + 'http://schemas.google.com/g/2005#kind'); + $this->setCategory(array($category)); + } + + /** + * Retrieves a DOMElement which corresponds to this element and all + * child properties. This is used to build an entry back into a DOM + * and eventually XML text for application storage/persistence. + * + * @param DOMDocument $doc The DOMDocument used to construct DOMElements + * @return DOMElement The DOMElement representing this element and all + * child properties. + */ + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc, $majorVersion, $minorVersion); + if ($this->_gphotoNickname !== null) { + $element->appendChild($this->_gphotoNickname->getDOM($element->ownerDocument)); + } + if ($this->_gphotoThumbnail !== null) { + $element->appendChild($this->_gphotoThumbnail->getDOM($element->ownerDocument)); + } + if ($this->_gphotoUser !== null) { + $element->appendChild($this->_gphotoUser->getDOM($element->ownerDocument)); + } + if ($this->_gphotoQuotaCurrent !== null) { + $element->appendChild($this->_gphotoQuotaCurrent->getDOM($element->ownerDocument)); + } + if ($this->_gphotoQuotaLimit !== null) { + $element->appendChild($this->_gphotoQuotaLimit->getDOM($element->ownerDocument)); + } + if ($this->_gphotoMaxPhotosPerAlbum !== null) { + $element->appendChild($this->_gphotoMaxPhotosPerAlbum->getDOM($element->ownerDocument)); + } + return $element; + } + + /** + * Creates individual Entry objects of the appropriate type and + * stores them as members of this entry based upon DOM data. + * + * @param DOMNode $child The DOMNode to process + */ + protected function takeChildFromDOM($child) + { + $absoluteNodeName = $child->namespaceURI . ':' . $child->localName; + + switch ($absoluteNodeName) { + case $this->lookupNamespace('gphoto') . ':' . 'nickname'; + $nickname = new Zend_Gdata_Photos_Extension_Nickname(); + $nickname->transferFromDOM($child); + $this->_gphotoNickname = $nickname; + break; + case $this->lookupNamespace('gphoto') . ':' . 'thumbnail'; + $thumbnail = new Zend_Gdata_Photos_Extension_Thumbnail(); + $thumbnail->transferFromDOM($child); + $this->_gphotoThumbnail = $thumbnail; + break; + case $this->lookupNamespace('gphoto') . ':' . 'user'; + $user = new Zend_Gdata_Photos_Extension_User(); + $user->transferFromDOM($child); + $this->_gphotoUser = $user; + break; + case $this->lookupNamespace('gphoto') . ':' . 'quotacurrent'; + $quotaCurrent = new Zend_Gdata_Photos_Extension_QuotaCurrent(); + $quotaCurrent->transferFromDOM($child); + $this->_gphotoQuotaCurrent = $quotaCurrent; + break; + case $this->lookupNamespace('gphoto') . ':' . 'quotalimit'; + $quotaLimit = new Zend_Gdata_Photos_Extension_QuotaLimit(); + $quotaLimit->transferFromDOM($child); + $this->_gphotoQuotaLimit = $quotaLimit; + break; + case $this->lookupNamespace('gphoto') . ':' . 'maxPhotosPerAlbum'; + $maxPhotosPerAlbum = new Zend_Gdata_Photos_Extension_MaxPhotosPerAlbum(); + $maxPhotosPerAlbum->transferFromDOM($child); + $this->_gphotoMaxPhotosPerAlbum = $maxPhotosPerAlbum; + break; + default: + parent::takeChildFromDOM($child); + break; + } + } + + /** + * Get the value for this element's gphoto:nickname attribute. + * + * @see setGphotoNickname + * @return string The requested attribute. + */ + public function getGphotoNickname() + { + return $this->_gphotoNickname; + } + + /** + * Set the value for this element's gphoto:nickname attribute. + * + * @param string $value The desired value for this attribute. + * @return Zend_Gdata_Photos_Extension_Nickname The element being modified. + */ + public function setGphotoNickname($value) + { + $this->_gphotoNickname = $value; + return $this; + } + + /** + * Get the value for this element's gphoto:thumbnail attribute. + * + * @see setGphotoThumbnail + * @return string The requested attribute. + */ + public function getGphotoThumbnail() + { + return $this->_gphotoThumbnail; + } + + /** + * Set the value for this element's gphoto:thumbnail attribute. + * + * @param string $value The desired value for this attribute. + * @return Zend_Gdata_Photos_Extension_Thumbnail The element being modified. + */ + public function setGphotoThumbnail($value) + { + $this->_gphotoThumbnail = $value; + return $this; + } + + /** + * Get the value for this element's gphoto:quotacurrent attribute. + * + * @see setGphotoQuotaCurrent + * @return string The requested attribute. + */ + public function getGphotoQuotaCurrent() + { + return $this->_gphotoQuotaCurrent; + } + + /** + * Set the value for this element's gphoto:quotacurrent attribute. + * + * @param string $value The desired value for this attribute. + * @return Zend_Gdata_Photos_Extension_QuotaCurrent The element being modified. + */ + public function setGphotoQuotaCurrent($value) + { + $this->_gphotoQuotaCurrent = $value; + return $this; + } + + /** + * Get the value for this element's gphoto:quotalimit attribute. + * + * @see setGphotoQuotaLimit + * @return string The requested attribute. + */ + public function getGphotoQuotaLimit() + { + return $this->_gphotoQuotaLimit; + } + + /** + * Set the value for this element's gphoto:quotalimit attribute. + * + * @param string $value The desired value for this attribute. + * @return Zend_Gdata_Photos_Extension_QuotaLimit The element being modified. + */ + public function setGphotoQuotaLimit($value) + { + $this->_gphotoQuotaLimit = $value; + return $this; + } + + /** + * Get the value for this element's gphoto:maxPhotosPerAlbum attribute. + * + * @see setGphotoMaxPhotosPerAlbum + * @return string The requested attribute. + */ + public function getGphotoMaxPhotosPerAlbum() + { + return $this->_gphotoMaxPhotosPerAlbum; + } + + /** + * Set the value for this element's gphoto:maxPhotosPerAlbum attribute. + * + * @param string $value The desired value for this attribute. + * @return Zend_Gdata_Photos_Extension_MaxPhotosPerAlbum The element being modified. + */ + public function setGphotoMaxPhotosPerAlbum($value) + { + $this->_gphotoMaxPhotosPerAlbum = $value; + return $this; + } + + /** + * Get the value for this element's gphoto:user attribute. + * + * @see setGphotoUser + * @return string The requested attribute. + */ + public function getGphotoUser() + { + return $this->_gphotoUser; + } + + /** + * Set the value for this element's gphoto:user attribute. + * + * @param string $value The desired value for this attribute. + * @return Zend_Gdata_Photos_Extension_User The element being modified. + */ + public function setGphotoUser($value) + { + $this->_gphotoUser = $value; + return $this; + } + +} diff --git a/Zend/Gdata/Photos/UserFeed.php b/Zend/Gdata/Photos/UserFeed.php new file mode 100644 index 00000000..5d67eff8 --- /dev/null +++ b/Zend/Gdata/Photos/UserFeed.php @@ -0,0 +1,247 @@ + 'Zend_Gdata_Photos_AlbumEntry', + 'http://schemas.google.com/photos/2007#photo' => 'Zend_Gdata_Photos_PhotoEntry', + 'http://schemas.google.com/photos/2007#comment' => 'Zend_Gdata_Photos_CommentEntry', + 'http://schemas.google.com/photos/2007#tag' => 'Zend_Gdata_Photos_TagEntry' + ); + + public function __construct($element = null) + { + $this->registerAllNamespaces(Zend_Gdata_Photos::$namespaces); + parent::__construct($element); + } + + /** + * Creates individual Entry objects of the appropriate type and + * stores them in the $_entry array based upon DOM data. + * + * @param DOMNode $child The DOMNode to process + */ + protected function takeChildFromDOM($child) + { + $absoluteNodeName = $child->namespaceURI . ':' . $child->localName; + switch ($absoluteNodeName) { + case $this->lookupNamespace('gphoto') . ':' . 'user'; + $user = new Zend_Gdata_Photos_Extension_User(); + $user->transferFromDOM($child); + $this->_gphotoUser = $user; + break; + case $this->lookupNamespace('gphoto') . ':' . 'nickname'; + $nickname = new Zend_Gdata_Photos_Extension_Nickname(); + $nickname->transferFromDOM($child); + $this->_gphotoNickname = $nickname; + break; + case $this->lookupNamespace('gphoto') . ':' . 'thumbnail'; + $thumbnail = new Zend_Gdata_Photos_Extension_Thumbnail(); + $thumbnail->transferFromDOM($child); + $this->_gphotoThumbnail = $thumbnail; + break; + case $this->lookupNamespace('atom') . ':' . 'entry': + $entryClassName = $this->_entryClassName; + $tmpEntry = new Zend_Gdata_App_Entry($child); + $categories = $tmpEntry->getCategory(); + foreach ($categories as $category) { + if ($category->scheme == Zend_Gdata_Photos::KIND_PATH && + $this->_entryKindClassMapping[$category->term] != "") { + $entryClassName = $this->_entryKindClassMapping[$category->term]; + break; + } else { + require_once 'Zend/Gdata/App/Exception.php'; + throw new Zend_Gdata_App_Exception('Entry is missing kind declaration.'); + } + } + + $newEntry = new $entryClassName($child); + $newEntry->setHttpClient($this->getHttpClient()); + $this->_entry[] = $newEntry; + break; + default: + parent::takeChildFromDOM($child); + break; + } + } + + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc, $majorVersion, $minorVersion); + if ($this->_gphotoUser != null) { + $element->appendChild($this->_gphotoUser->getDOM($element->ownerDocument)); + } + if ($this->_gphotoNickname != null) { + $element->appendChild($this->_gphotoNickname->getDOM($element->ownerDocument)); + } + if ($this->_gphotoThumbnail != null) { + $element->appendChild($this->_gphotoThumbnail->getDOM($element->ownerDocument)); + } + + return $element; + } + + /** + * Get the value for this element's gphoto:user attribute. + * + * @see setGphotoUser + * @return string The requested attribute. + */ + public function getGphotoUser() + { + return $this->_gphotoUser; + } + + /** + * Set the value for this element's gphoto:user attribute. + * + * @param string $value The desired value for this attribute. + * @return Zend_Gdata_Photos_Extension_User The element being modified. + */ + public function setGphotoUser($value) + { + $this->_gphotoUser = $value; + return $this; + } + + /** + * Get the value for this element's gphoto:nickname attribute. + * + * @see setGphotoNickname + * @return string The requested attribute. + */ + public function getGphotoNickname() + { + return $this->_gphotoNickname; + } + + /** + * Set the value for this element's gphoto:nickname attribute. + * + * @param string $value The desired value for this attribute. + * @return Zend_Gdata_Photos_Extension_Nickname The element being modified. + */ + public function setGphotoNickname($value) + { + $this->_gphotoNickname = $value; + return $this; + } + + /** + * Get the value for this element's gphoto:thumbnail attribute. + * + * @see setGphotoThumbnail + * @return string The requested attribute. + */ + public function getGphotoThumbnail() + { + return $this->_gphotoThumbnail; + } + + /** + * Set the value for this element's gphoto:thumbnail attribute. + * + * @param string $value The desired value for this attribute. + * @return Zend_Gdata_Photos_Extension_Thumbnail The element being modified. + */ + public function setGphotoThumbnail($value) + { + $this->_gphotoThumbnail = $value; + return $this; + } + +} diff --git a/Zend/Gdata/Photos/UserQuery.php b/Zend/Gdata/Photos/UserQuery.php new file mode 100644 index 00000000..79f0ba9f --- /dev/null +++ b/Zend/Gdata/Photos/UserQuery.php @@ -0,0 +1,355 @@ +_projection = $value; + return $this; + } + + /** + * Gets the format of data in returned in Atom feeds. + * + * @see setProjection + * @return string projection + */ + public function getProjection() + { + return $this->_projection; + } + + /** + * Set's the type of data returned in queries. Can be either + * 'feed' or 'entry'. Normally, 'feed' will be desired. Default is 'feed'. + * + * @param string $value + * @return Zend_Gdata_Photos_UserQuery Provides a fluent interface + */ + public function setType($value) + { + $this->_type = $value; + return $this; + } + + /** + * Gets the type of data in returned in queries. + * + * @see setType + * @return string type + */ + public function getType() + { + return $this->_type; + } + + /** + * Set the user to query for. When set, this user's feed will be + * returned. If not set or null, the default user's feed will be returned + * instead. + * + * @param string $value The user to retrieve, or null for the default + * user. + */ + public function setUser($value) + { + if ($value !== null) { + $this->_user = $value; + } else { + $this->_user = Zend_Gdata_Photos::DEFAULT_USER; + } + } + + /** + * Get the user which is to be returned. + * + * @see setUser + * @return string The visibility to retrieve. + */ + public function getUser() + { + return $this->_user; + } + + /** + * Set the visibility filter for entries returned. Only entries which + * match this value will be returned. If null or unset, the default + * value will be used instead. + * + * Valid values are 'all' (default), 'public', and 'private'. + * + * @param string $value The visibility to filter by, or null to use the + * default value. + */ + public function setAccess($value) + { + if ($value !== null) { + $this->_params['access'] = $value; + } else { + unset($this->_params['access']); + } + } + + /** + * Get the visibility filter for entries returned. + * + * @see setAccess + * @return string The visibility to filter by, or null for the default + * user. + */ + public function getAccess() + { + return $this->_params['access']; + } + + /** + * Set the tag for entries that are returned. Only entries which + * match this value will be returned. If null or unset, this filter will + * not be applied. + * + * See http://code.google.com/apis/picasaweb/reference.html#Parameters + * for a list of valid values. + * + * @param string $value The tag to filter by, or null if no + * filter is to be applied. + */ + public function setTag($value) + { + if ($value !== null) { + $this->_params['tag'] = $value; + } else { + unset($this->_params['tag']); + } + } + + /** + * Get the tag filter for entries returned. + * + * @see setTag + * @return string The tag to filter by, or null if no filter + * is to be applied. + */ + public function getTag() + { + return $this->_params['tag']; + } + + /** + * Set the kind of entries that are returned. Only entries which + * match this value will be returned. If null or unset, this filter will + * not be applied. + * + * See http://code.google.com/apis/picasaweb/reference.html#Parameters + * for a list of valid values. + * + * @param string $value The kind to filter by, or null if no + * filter is to be applied. + */ + public function setKind($value) + { + if ($value !== null) { + $this->_params['kind'] = $value; + } else { + unset($this->_params['kind']); + } + } + + /** + * Get the kind of entries to be returned. + * + * @see setKind + * @return string The kind to filter by, or null if no filter + * is to be applied. + */ + public function getKind() + { + return $this->_params['kind']; + } + + /** + * Set the maximum image size for entries returned. Only entries which + * match this value will be returned. If null or unset, this filter will + * not be applied. + * + * See http://code.google.com/apis/picasaweb/reference.html#Parameters + * for a list of valid values. + * + * @param string $value The image size to filter by, or null if no + * filter is to be applied. + */ + public function setImgMax($value) + { + if ($value !== null) { + $this->_params['imgmax'] = $value; + } else { + unset($this->_params['imgmax']); + } + } + + /** + * Get the maximum image size filter for entries returned. + * + * @see setImgMax + * @return string The image size size to filter by, or null if no filter + * is to be applied. + */ + public function getImgMax() + { + return $this->_params['imgmax']; + } + + /** + * Set the thumbnail size filter for entries returned. Only entries which + * match this value will be returned. If null or unset, this filter will + * not be applied. + * + * See http://code.google.com/apis/picasaweb/reference.html#Parameters + * for a list of valid values. + * + * @param string $value The thumbnail size to filter by, or null if no + * filter is to be applied. + */ + public function setThumbsize($value) + { + if ($value !== null) { + $this->_params['thumbsize'] = $value; + } else { + unset($this->_params['thumbsize']); + } + } + + /** + * Get the thumbnail size filter for entries returned. + * + * @see setThumbsize + * @return string The thumbnail size to filter by, or null if no filter + * is to be applied. + */ + public function getThumbsize() + { + return $this->_params['thumbsize']; + } + + /** + * Returns the URL generated for this query, based on it's current + * parameters. + * + * @return string A URL generated based on the state of this query. + * @throws Zend_Gdata_App_InvalidArgumentException + */ + public function getQueryUrl($incomingUri = null) + { + $uri = Zend_Gdata_Photos::PICASA_BASE_URI; + + if ($this->getType() !== null) { + $uri .= '/' . $this->getType(); + } else { + require_once 'Zend/Gdata/App/InvalidArgumentException.php'; + throw new Zend_Gdata_App_InvalidArgumentException( + 'Type must be feed or entry, not null'); + } + + if ($this->getProjection() !== null) { + $uri .= '/' . $this->getProjection(); + } else { + require_once 'Zend/Gdata/App/InvalidArgumentException.php'; + throw new Zend_Gdata_App_InvalidArgumentException( + 'Projection must not be null'); + } + + if ($this->getUser() !== null) { + $uri .= '/user/' . $this->getUser(); + } else { + // Should never occur due to setter behavior + require_once 'Zend/Gdata/App/InvalidArgumentException.php'; + throw new Zend_Gdata_App_InvalidArgumentException( + 'User must not be null'); + } + + $uri .= $incomingUri; + $uri .= $this->getQueryString(); + return $uri; + } + +} diff --git a/Zend/Gdata/Query.php b/Zend/Gdata/Query.php new file mode 100644 index 00000000..d37329f9 --- /dev/null +++ b/Zend/Gdata/Query.php @@ -0,0 +1,418 @@ +_url = $url; + } + + /** + * @return string querystring + */ + public function getQueryString() + { + $queryArray = array(); + foreach ($this->_params as $name => $value) { + if (substr($name, 0, 1) == '_') { + continue; + } + $queryArray[] = urlencode($name) . '=' . urlencode($value); + } + if (count($queryArray) > 0) { + return '?' . implode('&', $queryArray); + } else { + return ''; + } + } + + /** + * + */ + public function resetParameters() + { + $this->_params = array(); + } + + /** + * @return string url + */ + public function getQueryUrl() + { + if ($this->_url == null) { + $url = $this->_defaultFeedUri; + } else { + $url = $this->_url; + } + if ($this->getCategory() !== null) { + $url .= '/-/' . $this->getCategory(); + } + $url .= $this->getQueryString(); + return $url; + } + + /** + * @param string $name + * @param string $value + * @return Zend_Gdata_Query Provides a fluent interface + */ + public function setParam($name, $value) + { + $this->_params[$name] = $value; + return $this; + } + + /** + * @param string $name + */ + public function getParam($name) + { + return $this->_params[$name]; + } + + /** + * @param string $value + * @return Zend_Gdata_Query Provides a fluent interface + */ + public function setAlt($value) + { + if ($value != null) { + $this->_params['alt'] = $value; + } else { + unset($this->_params['alt']); + } + return $this; + } + + /** + * @param int $value + * @return Zend_Gdata_Query Provides a fluent interface + */ + public function setMaxResults($value) + { + if ($value != null) { + $this->_params['max-results'] = $value; + } else { + unset($this->_params['max-results']); + } + return $this; + } + + /** + * @param string $value + * @return Zend_Gdata_Query Provides a fluent interface + */ + public function setQuery($value) + { + if ($value != null) { + $this->_params['q'] = $value; + } else { + unset($this->_params['q']); + } + return $this; + } + + /** + * @param int $value + * @return Zend_Gdata_Query Provides a fluent interface + */ + public function setStartIndex($value) + { + if ($value != null) { + $this->_params['start-index'] = $value; + } else { + unset($this->_params['start-index']); + } + return $this; + } + + /** + * @param string $value + * @return Zend_Gdata_Query Provides a fluent interface + */ + public function setUpdatedMax($value) + { + if ($value != null) { + $this->_params['updated-max'] = Zend_Gdata_App_Util::formatTimestamp($value); + } else { + unset($this->_params['updated-max']); + } + return $this; + } + + /** + * @param string $value + * @return Zend_Gdata_Query Provides a fluent interface + */ + public function setUpdatedMin($value) + { + if ($value != null) { + $this->_params['updated-min'] = Zend_Gdata_App_Util::formatTimestamp($value); + } else { + unset($this->_params['updated-min']); + } + return $this; + } + + /** + * @param string $value + * @return Zend_Gdata_Query Provides a fluent interface + */ + public function setPublishedMax($value) + { + if ($value !== null) { + $this->_params['published-max'] = Zend_Gdata_App_Util::formatTimestamp($value); + } else { + unset($this->_params['published-max']); + } + return $this; + } + + /** + * @param string $value + * @return Zend_Gdata_Query Provides a fluent interface + */ + public function setPublishedMin($value) + { + if ($value != null) { + $this->_params['published-min'] = Zend_Gdata_App_Util::formatTimestamp($value); + } else { + unset($this->_params['published-min']); + } + return $this; + } + + /** + * @param string $value + * @return Zend_Gdata_Query Provides a fluent interface + */ + public function setAuthor($value) + { + if ($value != null) { + $this->_params['author'] = $value; + } else { + unset($this->_params['author']); + } + return $this; + } + + /** + * @return string rss or atom + */ + public function getAlt() + { + if (array_key_exists('alt', $this->_params)) { + return $this->_params['alt']; + } else { + return null; + } + } + + /** + * @return int maxResults + */ + public function getMaxResults() + { + if (array_key_exists('max-results', $this->_params)) { + return intval($this->_params['max-results']); + } else { + return null; + } + } + + /** + * @return string query + */ + public function getQuery() + { + if (array_key_exists('q', $this->_params)) { + return $this->_params['q']; + } else { + return null; + } + } + + /** + * @return int startIndex + */ + public function getStartIndex() + { + if (array_key_exists('start-index', $this->_params)) { + return intval($this->_params['start-index']); + } else { + return null; + } + } + + /** + * @return string updatedMax + */ + public function getUpdatedMax() + { + if (array_key_exists('updated-max', $this->_params)) { + return $this->_params['updated-max']; + } else { + return null; + } + } + + /** + * @return string updatedMin + */ + public function getUpdatedMin() + { + if (array_key_exists('updated-min', $this->_params)) { + return $this->_params['updated-min']; + } else { + return null; + } + } + + /** + * @return string publishedMax + */ + public function getPublishedMax() + { + if (array_key_exists('published-max', $this->_params)) { + return $this->_params['published-max']; + } else { + return null; + } + } + + /** + * @return string publishedMin + */ + public function getPublishedMin() + { + if (array_key_exists('published-min', $this->_params)) { + return $this->_params['published-min']; + } else { + return null; + } + } + + /** + * @return string author + */ + public function getAuthor() + { + if (array_key_exists('author', $this->_params)) { + return $this->_params['author']; + } else { + return null; + } + } + + /** + * @param string $value + * @return Zend_Gdata_Query Provides a fluent interface + */ + public function setCategory($value) + { + $this->_category = $value; + return $this; + } + + /* + * @return string id + */ + public function getCategory() + { + return $this->_category; + } + + + public function __get($name) + { + $method = 'get'.ucfirst($name); + if (method_exists($this, $method)) { + return call_user_func(array(&$this, $method)); + } else { + require_once 'Zend/Gdata/App/Exception.php'; + throw new Zend_Gdata_App_Exception('Property ' . $name . ' does not exist'); + } + } + + public function __set($name, $val) + { + $method = 'set'.ucfirst($name); + if (method_exists($this, $method)) { + return call_user_func(array(&$this, $method), $val); + } else { + require_once 'Zend/Gdata/App/Exception.php'; + throw new Zend_Gdata_App_Exception('Property ' . $name . ' does not exist'); + } + } + +} diff --git a/Zend/Gdata/Spreadsheets.php b/Zend/Gdata/Spreadsheets.php new file mode 100644 index 00000000..f30e3500 --- /dev/null +++ b/Zend/Gdata/Spreadsheets.php @@ -0,0 +1,445 @@ +registerPackage('Zend_Gdata_Spreadsheets'); + $this->registerPackage('Zend_Gdata_Spreadsheets_Extension'); + parent::__construct($client, $applicationId); + $this->_httpClient->setParameterPost('service', self::AUTH_SERVICE_NAME); + $this->_server = 'spreadsheets.google.com'; + } + + /** + * Gets a spreadsheet feed. + * + * @param mixed $location A DocumentQuery or a string URI specifying the feed location. + * @return Zend_Gdata_Spreadsheets_SpreadsheetFeed + */ + public function getSpreadsheetFeed($location = null) + { + if ($location == null) { + $uri = self::SPREADSHEETS_FEED_URI; + } else if ($location instanceof Zend_Gdata_Spreadsheets_DocumentQuery) { + if ($location->getDocumentType() == null) { + $location->setDocumentType('spreadsheets'); + } + $uri = $location->getQueryUrl(); + } else { + $uri = $location; + } + + return parent::getFeed($uri, 'Zend_Gdata_Spreadsheets_SpreadsheetFeed'); + } + + /** + * Gets a spreadsheet entry. + * + * @param string $location A DocumentQuery or a URI specifying the entry location. + * @return SpreadsheetEntry + */ + public function getSpreadsheetEntry($location) + { + if ($location instanceof Zend_Gdata_Spreadsheets_DocumentQuery) { + if ($location->getDocumentType() == null) { + $location->setDocumentType('spreadsheets'); + } + $uri = $location->getQueryUrl(); + } else { + $uri = $location; + } + + return parent::getEntry($uri, 'Zend_Gdata_Spreadsheets_SpreadsheetEntry'); + } + + /** + * Gets a worksheet feed. + * + * @param mixed $location A DocumentQuery, SpreadsheetEntry, or a string URI + * @return Zend_Gdata_Spreadsheets_WorksheetFeed The feed of worksheets + */ + public function getWorksheetFeed($location) + { + if ($location instanceof Zend_Gdata_Spreadsheets_DocumentQuery) { + if ($location->getDocumentType() == null) { + $location->setDocumentType('worksheets'); + } + $uri = $location->getQueryUrl(); + } else if ($location instanceof Zend_Gdata_Spreadsheets_SpreadsheetEntry) { + $uri = $location->getLink(self::WORKSHEETS_FEED_LINK_URI)->href; + } else { + $uri = $location; + } + + return parent::getFeed($uri, 'Zend_Gdata_Spreadsheets_WorksheetFeed'); + } + + /** + * Gets a worksheet entry. + * + * @param string $location A DocumentQuery or a URI specifying the entry location. + * @return WorksheetEntry + */ + public function GetWorksheetEntry($location) + { + if ($location instanceof Zend_Gdata_Spreadsheets_DocumentQuery) { + if ($location->getDocumentType() == null) { + $location->setDocumentType('worksheets'); + } + $uri = $location->getQueryUrl(); + } else { + $uri = $location; + } + + return parent::getEntry($uri, 'Zend_Gdata_Spreadsheets_WorksheetEntry'); + } + + /** + * Gets a cell feed. + * + * @param string $location A CellQuery, WorksheetEntry or a URI specifying the feed location. + * @return CellFeed + */ + public function getCellFeed($location) + { + if ($location instanceof Zend_Gdata_Spreadsheets_CellQuery) { + $uri = $location->getQueryUrl(); + } else if ($location instanceof Zend_Gdata_Spreadsheets_WorksheetEntry) { + $uri = $location->getLink(self::CELL_FEED_LINK_URI)->href; + } else { + $uri = $location; + } + return parent::getFeed($uri, 'Zend_Gdata_Spreadsheets_CellFeed'); + } + + /** + * Gets a cell entry. + * + * @param string $location A CellQuery or a URI specifying the entry location. + * @return CellEntry + */ + public function getCellEntry($location) + { + if ($location instanceof Zend_Gdata_Spreadsheets_CellQuery) { + $uri = $location->getQueryUrl(); + } else { + $uri = $location; + } + + return parent::getEntry($uri, 'Zend_Gdata_Spreadsheets_CellEntry'); + } + + /** + * Gets a list feed. + * + * @param mixed $location A ListQuery, WorksheetEntry or string URI specifying the feed location. + * @return ListFeed + */ + public function getListFeed($location) + { + if ($location instanceof Zend_Gdata_Spreadsheets_ListQuery) { + $uri = $location->getQueryUrl(); + } else if ($location instanceof Zend_Gdata_Spreadsheets_WorksheetEntry) { + $uri = $location->getLink(self::LIST_FEED_LINK_URI)->href; + } else { + $uri = $location; + } + + return parent::getFeed($uri, 'Zend_Gdata_Spreadsheets_ListFeed'); + } + + /** + * Gets a list entry. + * + * @param string $location A ListQuery or a URI specifying the entry location. + * @return ListEntry + */ + public function getListEntry($location) + { + if ($location instanceof Zend_Gdata_Spreadsheets_ListQuery) { + $uri = $location->getQueryUrl(); + } else { + $uri = $location; + } + + return parent::getEntry($uri, 'Zend_Gdata_Spreadsheets_ListEntry'); + } + + /** + * Updates an existing cell. + * + * @param int $row The row containing the cell to update + * @param int $col The column containing the cell to update + * @param int $inputValue The new value for the cell + * @param string $key The key for the spreadsheet to be updated + * @param string $wkshtId (optional) The worksheet to be updated + * @return CellEntry The updated cell entry. + */ + public function updateCell($row, $col, $inputValue, $key, $wkshtId = 'default') + { + $cell = 'R'.$row.'C'.$col; + + $query = new Zend_Gdata_Spreadsheets_CellQuery(); + $query->setSpreadsheetKey($key); + $query->setWorksheetId($wkshtId); + $query->setCellId($cell); + + $entry = $this->getCellEntry($query); + $entry->setCell(new Zend_Gdata_Spreadsheets_Extension_Cell(null, $row, $col, $inputValue)); + $response = $entry->save(); + return $response; + } + + /** + * Inserts a new row with provided data. + * + * @param array $rowData An array of column header to row data + * @param string $key The key of the spreadsheet to modify + * @param string $wkshtId (optional) The worksheet to modify + * @return ListEntry The inserted row + */ + public function insertRow($rowData, $key, $wkshtId = 'default') + { + $newEntry = new Zend_Gdata_Spreadsheets_ListEntry(); + $newCustomArr = array(); + foreach ($rowData as $k => $v) { + $newCustom = new Zend_Gdata_Spreadsheets_Extension_Custom(); + $newCustom->setText($v)->setColumnName($k); + $newEntry->addCustom($newCustom); + } + + $query = new Zend_Gdata_Spreadsheets_ListQuery(); + $query->setSpreadsheetKey($key); + $query->setWorksheetId($wkshtId); + + $feed = $this->getListFeed($query); + $editLink = $feed->getLink('http://schemas.google.com/g/2005#post'); + + return $this->insertEntry($newEntry->saveXML(), $editLink->href, 'Zend_Gdata_Spreadsheets_ListEntry'); + } + + /** + * Updates an existing row with provided data. + * + * @param ListEntry $entry The row entry to update + * @param array $newRowData An array of column header to row data + */ + public function updateRow($entry, $newRowData) + { + $newCustomArr = array(); + foreach ($newRowData as $k => $v) { + $newCustom = new Zend_Gdata_Spreadsheets_Extension_Custom(); + $newCustom->setText($v)->setColumnName($k); + $newCustomArr[] = $newCustom; + } + $entry->setCustom($newCustomArr); + + return $entry->save(); + } + + /** + * Deletes an existing row . + * + * @param ListEntry $entry The row to delete + */ + public function deleteRow($entry) + { + $entry->delete(); + } + + /** + * Returns the content of all rows as an associative array + * + * @param mixed $location A ListQuery or string URI specifying the feed location. + * @return array An array of rows. Each element of the array is an associative array of data + */ + public function getSpreadsheetListFeedContents($location) + { + $listFeed = $this->getListFeed($location); + $listFeed = $this->retrieveAllEntriesForFeed($listFeed); + $spreadsheetContents = array(); + foreach ($listFeed as $listEntry) { + $rowContents = array(); + $customArray = $listEntry->getCustom(); + foreach ($customArray as $custom) { + $rowContents[$custom->getColumnName()] = $custom->getText(); + } + $spreadsheetContents[] = $rowContents; + } + return $spreadsheetContents; + } + + /** + * Returns the content of all cells as an associative array, indexed + * off the cell location (ie 'A1', 'D4', etc). Each element of + * the array is an associative array with a 'value' and a 'function'. + * Only non-empty cells are returned by default. 'range' is the + * value of the 'range' query parameter specified at: + * http://code.google.com/apis/spreadsheets/reference.html#cells_Parameters + * + * @param mixed $location A CellQuery, WorksheetEntry or a URL (w/o query string) specifying the feed location. + * @param string $range The range of cells to retrieve + * @param boolean $empty Whether to retrieve empty cells + * @return array An associative array of cells + */ + public function getSpreadsheetCellFeedContents($location, $range = null, $empty = false) + { + $cellQuery = null; + if ($location instanceof Zend_Gdata_Spreadsheets_CellQuery) { + $cellQuery = $location; + } else if ($location instanceof Zend_Gdata_Spreadsheets_WorksheetEntry) { + $url = $location->getLink(self::CELL_FEED_LINK_URI)->href; + $cellQuery = new Zend_Gdata_Spreadsheets_CellQuery($url); + } else { + $url = $location; + $cellQuery = new Zend_Gdata_Spreadsheets_CellQuery($url); + } + + if ($range != null) { + $cellQuery->setRange($range); + } + $cellQuery->setReturnEmpty($empty); + + $cellFeed = $this->getCellFeed($cellQuery); + $cellFeed = $this->retrieveAllEntriesForFeed($cellFeed); + $spreadsheetContents = array(); + foreach ($cellFeed as $cellEntry) { + $cellContents = array(); + $cell = $cellEntry->getCell(); + $cellContents['formula'] = $cell->getInputValue(); + $cellContents['value'] = $cell->getText(); + $spreadsheetContents[$cellEntry->getTitle()->getText()] = $cellContents; + } + return $spreadsheetContents; + } + + /** + * Alias for getSpreadsheetFeed + * + * @param mixed $location A DocumentQuery or a string URI specifying the feed location. + * @return Zend_Gdata_Spreadsheets_SpreadsheetFeed + */ + public function getSpreadsheets($location = null) + { + return $this->getSpreadsheetFeed($location = null); + } + +} diff --git a/Zend/Gdata/Spreadsheets/CellEntry.php b/Zend/Gdata/Spreadsheets/CellEntry.php new file mode 100644 index 00000000..abf11ce4 --- /dev/null +++ b/Zend/Gdata/Spreadsheets/CellEntry.php @@ -0,0 +1,103 @@ +registerAllNamespaces(Zend_Gdata_Spreadsheets::$namespaces); + parent::__construct($element); + } + + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc, $majorVersion, $minorVersion); + if ($this->_cell != null) { + $element->appendChild($this->_cell->getDOM($element->ownerDocument)); + } + return $element; + } + + protected function takeChildFromDOM($child) + { + $absoluteNodeName = $child->namespaceURI . ':' . $child->localName; + switch ($absoluteNodeName) { + case $this->lookupNamespace('gs') . ':' . 'cell'; + $cell = new Zend_Gdata_Spreadsheets_Extension_Cell(); + $cell->transferFromDOM($child); + $this->_cell = $cell; + break; + default: + parent::takeChildFromDOM($child); + break; + } + } + + /** + * Gets the Cell element of this Cell Entry. + * @return Zend_Gdata_Spreadsheets_Extension_Cell + */ + public function getCell() + { + return $this->_cell; + } + + /** + * Sets the Cell element of this Cell Entry. + * @param $cell Zend_Gdata_Spreadsheets_Extension_Cell $cell + */ + public function setCell($cell) + { + $this->_cell = $cell; + return $this; + } + +} diff --git a/Zend/Gdata/Spreadsheets/CellFeed.php b/Zend/Gdata/Spreadsheets/CellFeed.php new file mode 100644 index 00000000..871774a9 --- /dev/null +++ b/Zend/Gdata/Spreadsheets/CellFeed.php @@ -0,0 +1,158 @@ +registerAllNamespaces(Zend_Gdata_Spreadsheets::$namespaces); + parent::__construct($element); + } + + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc, $majorVersion, $minorVersion); + if ($this->rowCount != null) { + $element->appendChild($this->_rowCount->getDOM($element->ownerDocument)); + } + if ($this->colCount != null) { + $element->appendChild($this->_colCount->getDOM($element->ownerDocument)); + } + return $element; + } + + protected function takeChildFromDOM($child) + { + $absoluteNodeName = $child->namespaceURI . ':' . $child->localName; + switch ($absoluteNodeName) { + case $this->lookupNamespace('gs') . ':' . 'rowCount'; + $rowCount = new Zend_Gdata_Spreadsheets_Extension_RowCount(); + $rowCount->transferFromDOM($child); + $this->_rowCount = $rowCount; + break; + case $this->lookupNamespace('gs') . ':' . 'colCount'; + $colCount = new Zend_Gdata_Spreadsheets_Extension_ColCount(); + $colCount->transferFromDOM($child); + $this->_colCount = $colCount; + break; + default: + parent::takeChildFromDOM($child); + break; + } + } + + /** + * Gets the row count for this feed. + * @return string The row count for the feed. + */ + public function getRowCount() + { + return $this->_rowCount; + } + + /** + * Gets the column count for this feed. + * @return string The column count for the feed. + */ + public function getColumnCount() + { + return $this->_colCount; + } + + /** + * Sets the row count for this feed. + * @param string $rowCount The new row count for the feed. + */ + public function setRowCount($rowCount) + { + $this->_rowCount = $rowCount; + return $this; + } + + /** + * Sets the column count for this feed. + * @param string $colCount The new column count for the feed. + */ + public function setColumnCount($colCount) + { + $this->_colCount = $colCount; + return $this; + } + +} diff --git a/Zend/Gdata/Spreadsheets/CellQuery.php b/Zend/Gdata/Spreadsheets/CellQuery.php new file mode 100644 index 00000000..97661f35 --- /dev/null +++ b/Zend/Gdata/Spreadsheets/CellQuery.php @@ -0,0 +1,417 @@ +_spreadsheetKey = $value; + return $this; + } + + /** + * Gets the spreadsheet key for this query. + * + * @return string spreadsheet key + */ + public function getSpreadsheetKey() + { + return $this->_spreadsheetKey; + } + + /** + * Sets the worksheet id for this query. + * + * @param string $value + * @return Zend_Gdata_Spreadsheets_CellQuery Provides a fluent interface + */ + public function setWorksheetId($value) + { + $this->_worksheetId = $value; + return $this; + } + + /** + * Gets the worksheet id for this query. + * + * @return string worksheet id + */ + public function getWorksheetId() + { + return $this->_worksheetId; + } + + /** + * Sets the cell id for this query. + * + * @param string $value + * @return Zend_Gdata_Spreadsheets_CellQuery Provides a fluent interface + */ + public function setCellId($value) + { + $this->_cellId = $value; + return $this; + } + + /** + * Gets the cell id for this query. + * + * @return string cell id + */ + public function getCellId() + { + return $this->_cellId; + } + + /** + * Sets the projection for this query. + * + * @param string $value + * @return Zend_Gdata_Spreadsheets_CellQuery Provides a fluent interface + */ + public function setProjection($value) + { + $this->_projection = $value; + return $this; + } + + /** + * Sets the visibility for this query. + * + * @return Zend_Gdata_Spreadsheets_CellQuery Provides a fluent interface + */ + public function setVisibility($value) + { + $this->_visibility = $value; + return $this; + } + + /** + * Gets the projection for this query. + * + * @return string projection + */ + public function getProjection() + { + return $this->_projection; + } + + /** + * Gets the visibility for this query. + * + * @return string visibility + */ + public function getVisibility() + { + return $this->_visibility; + } + + /** + * Sets the min-row attribute for this query. + * + * @param string $value + * @return Zend_Gdata_Spreadsheets_CellQuery Provides a fluent interface + */ + public function setMinRow($value) + { + if ($value != null) { + $this->_params['min-row'] = $value; + } else { + unset($this->_params['min-row']); + } + return $this; + } + + /** + * Gets the min-row attribute for this query. + * + * @return string min-row + */ + public function getMinRow() + { + if (array_key_exists('min-row', $this->_params)) { + return $this->_params['min-row']; + } else { + return null; + } + } + + /** + * Sets the max-row attribute for this query. + * + * @param string $value + * @return Zend_Gdata_Spreadsheets_CellQuery Provides a fluent interface + */ + public function setMaxRow($value) + { + if ($value != null) { + $this->_params['max-row'] = $value; + } else { + unset($this->_params['max-row']); + } + return $this; + } + + /** + * Gets the max-row attribute for this query. + * + * @return string max-row + */ + public function getMaxRow() + { + if (array_key_exists('max-row', $this->_params)) { + return $this->_params['max-row']; + } else { + return null; + } + } + + /** + * Sets the min-col attribute for this query. + * + * @param string $value + * @return Zend_Gdata_Spreadsheets_CellQuery Provides a fluent interface + */ + public function setMinCol($value) + { + if ($value != null) { + $this->_params['min-col'] = $value; + } else { + unset($this->_params['min-col']); + } + return $this; + } + + /** + * Gets the min-col attribute for this query. + * + * @return string min-col + */ + public function getMinCol() + { + if (array_key_exists('min-col', $this->_params)) { + return $this->_params['min-col']; + } else { + return null; + } + } + + /** + * Sets the max-col attribute for this query. + * + * @param string $value + * @return Zend_Gdata_Spreadsheets_CellQuery Provides a fluent interface + */ + public function setMaxCol($value) + { + if ($value != null) { + $this->_params['max-col'] = $value; + } else { + unset($this->_params['max-col']); + } + return $this; + } + + /** + * Gets the max-col attribute for this query. + * + * @return string max-col + */ + public function getMaxCol() + { + if (array_key_exists('max-col', $this->_params)) { + return $this->_params['max-col']; + } else { + return null; + } + } + + /** + * Sets the range attribute for this query. + * + * @param string $value + * @return Zend_Gdata_Spreadsheets_CellQuery Provides a fluent interface + */ + public function setRange($value) + { + if ($value != null) { + $this->_params['range'] = $value; + } else { + unset($this->_params['range']); + } + return $this; + } + + /** + * Gets the range attribute for this query. + * + * @return string range + */ + public function getRange() + { + if (array_key_exists('range', $this->_params)) { + return $this->_params['range']; + } else { + return null; + } + } + + /** + * Sets the return-empty attribute for this query. + * + * @param mixed $value String or bool value for whether to return empty cells + * @return Zend_Gdata_Spreadsheets_CellQuery Provides a fluent interface + */ + public function setReturnEmpty($value) + { + if (is_bool($value)) { + $this->_params['return-empty'] = ($value?'true':'false'); + } else if ($value != null) { + $this->_params['return-empty'] = $value; + } else { + unset($this->_params['return-empty']); + } + return $this; + } + + /** + * Gets the return-empty attribute for this query. + * + * @return string return-empty + */ + public function getReturnEmpty() + { + if (array_key_exists('return-empty', $this->_params)) { + return $this->_params['return-empty']; + } else { + return null; + } + } + + /** + * Gets the full query URL for this query. + * + * @return string url + */ + public function getQueryUrl() + { + if ($this->_url == null) { + $uri = $this->_defaultFeedUri; + + if ($this->_spreadsheetKey != null) { + $uri .= '/'.$this->_spreadsheetKey; + } else { + require_once 'Zend/Gdata/App/Exception.php'; + throw new Zend_Gdata_App_Exception('A spreadsheet key must be provided for cell queries.'); + } + + if ($this->_worksheetId != null) { + $uri .= '/'.$this->_worksheetId; + } else { + require_once 'Zend/Gdata/App/Exception.php'; + throw new Zend_Gdata_App_Exception('A worksheet id must be provided for cell queries.'); + } + + if ($this->_visibility != null) { + $uri .= '/'.$this->_visibility; + } else { + require_once 'Zend/Gdata/App/Exception.php'; + throw new Zend_Gdata_App_Exception('A visibility must be provided for cell queries.'); + } + + if ($this->_projection != null) { + $uri .= '/'.$this->_projection; + } else { + require_once 'Zend/Gdata/App/Exception.php'; + throw new Zend_Gdata_App_Exception('A projection must be provided for cell queries.'); + } + + if ($this->_cellId != null) { + $uri .= '/'.$this->_cellId; + } + } else { + $uri = $this->_url; + } + + $uri .= $this->getQueryString(); + return $uri; + } + + /** + * Gets the attribute query string for this query. + * + * @return string query string + */ + public function getQueryString() + { + return parent::getQueryString(); + } + +} diff --git a/Zend/Gdata/Spreadsheets/DocumentQuery.php b/Zend/Gdata/Spreadsheets/DocumentQuery.php new file mode 100644 index 00000000..c5b4dc31 --- /dev/null +++ b/Zend/Gdata/Spreadsheets/DocumentQuery.php @@ -0,0 +1,288 @@ +_spreadsheetKey = $value; + return $this; + } + + /** + * Gets the spreadsheet key for this query. + * @return string spreadsheet key + */ + public function getSpreadsheetKey() + { + return $this->_spreadsheetKey; + } + + /** + * Sets the worksheet id for this query. + * @param string $value + * @return Zend_Gdata_Spreadsheets_CellQuery Provides a fluent interface + */ + public function setWorksheetId($value) + { + $this->_worksheetId = $value; + return $this; + } + + /** + * Gets the worksheet id for this query. + * @return string worksheet id + */ + public function getWorksheetId() + { + return $this->_worksheetId; + } + + /** + * Sets the document type for this query. + * @param string $value spreadsheets or worksheets + * @return Zend_Gdata_Spreadsheets_DocumentQuery Provides a fluent interface + */ + public function setDocumentType($value) + { + $this->_documentType = $value; + return $this; + } + + /** + * Gets the document type for this query. + * @return string document type + */ + public function getDocumentType() + { + return $this->_documentType; + } + + /** + * Sets the projection for this query. + * @param string $value + * @return Zend_Gdata_Spreadsheets_DocumentQuery Provides a fluent interface + */ + public function setProjection($value) + { + $this->_projection = $value; + return $this; + } + + /** + * Sets the visibility for this query. + * @return Zend_Gdata_Spreadsheets_DocumentQuery Provides a fluent interface + */ + public function setVisibility($value) + { + $this->_visibility = $value; + return $this; + } + + /** + * Gets the projection for this query. + * @return string projection + */ + public function getProjection() + { + return $this->_projection; + } + + /** + * Gets the visibility for this query. + * @return string visibility + */ + public function getVisibility() + { + return $this->_visibility; + } + + /** + * Sets the title attribute for this query. + * @param string $value + * @return Zend_Gdata_Spreadsheets_DocumentQuery Provides a fluent interface + */ + public function setTitle($value) + { + if ($value != null) { + $this->_params['title'] = $value; + } else { + unset($this->_params['title']); + } + return $this; + } + + /** + * Sets the title-exact attribute for this query. + * @param string $value + * @return Zend_Gdata_Spreadsheets_DocumentQuery Provides a fluent interface + */ + public function setTitleExact($value) + { + if ($value != null) { + $this->_params['title-exact'] = $value; + } else { + unset($this->_params['title-exact']); + } + return $this; + } + + /** + * Gets the title attribute for this query. + * @return string title + */ + public function getTitle() + { + if (array_key_exists('title', $this->_params)) { + return $this->_params['title']; + } else { + return null; + } + } + + /** + * Gets the title-exact attribute for this query. + * @return string title-exact + */ + public function getTitleExact() + { + if (array_key_exists('title-exact', $this->_params)) { + return $this->_params['title-exact']; + } else { + return null; + } + } + + private function appendVisibilityProjection() + { + $uri = ''; + + if ($this->_visibility != null) { + $uri .= '/'.$this->_visibility; + } else { + require_once 'Zend/Gdata/App/Exception.php'; + throw new Zend_Gdata_App_Exception('A visibility must be provided for document queries.'); + } + + if ($this->_projection != null) { + $uri .= '/'.$this->_projection; + } else { + require_once 'Zend/Gdata/App/Exception.php'; + throw new Zend_Gdata_App_Exception('A projection must be provided for document queries.'); + } + + return $uri; + } + + + /** + * Gets the full query URL for this query. + * @return string url + */ + public function getQueryUrl() + { + $uri = $this->_defaultFeedUri; + + if ($this->_documentType != null) { + $uri .= '/'.$this->_documentType; + } else { + require_once 'Zend/Gdata/App/Exception.php'; + throw new Zend_Gdata_App_Exception('A document type must be provided for document queries.'); + } + + if ($this->_documentType == 'spreadsheets') { + $uri .= $this->appendVisibilityProjection(); + if ($this->_spreadsheetKey != null) { + $uri .= '/'.$this->_spreadsheetKey; + } + } else if ($this->_documentType == 'worksheets') { + if ($this->_spreadsheetKey != null) { + $uri .= '/'.$this->_spreadsheetKey; + } else { + require_once 'Zend/Gdata/App/Exception.php'; + throw new Zend_Gdata_App_Exception('A spreadsheet key must be provided for worksheet document queries.'); + } + $uri .= $this->appendVisibilityProjection(); + if ($this->_worksheetId != null) { + $uri .= '/'.$this->_worksheetId; + } + } + + $uri .= $this->getQueryString(); + return $uri; + } + + /** + * Gets the attribute query string for this query. + * @return string query string + */ + public function getQueryString() + { + return parent::getQueryString(); + } + +} diff --git a/Zend/Gdata/Spreadsheets/Extension/Cell.php b/Zend/Gdata/Spreadsheets/Extension/Cell.php new file mode 100644 index 00000000..26f043b7 --- /dev/null +++ b/Zend/Gdata/Spreadsheets/Extension/Cell.php @@ -0,0 +1,201 @@ +registerAllNamespaces(Zend_Gdata_Spreadsheets::$namespaces); + parent::__construct(); + $this->_text = $text; + $this->_row = $row; + $this->_col = $col; + $this->_inputValue = $inputValue; + $this->_numericValue = $numericValue; + } + + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc, $majorVersion, $minorVersion); + $element->setAttribute('row', $this->_row); + $element->setAttribute('col', $this->_col); + if ($this->_inputValue) $element->setAttribute('inputValue', $this->_inputValue); + if ($this->_numericValue) $element->setAttribute('numericValue', $this->_numericValue); + return $element; + } + + protected function takeAttributeFromDOM($attribute) + { + switch ($attribute->localName) { + case 'row': + $this->_row = $attribute->nodeValue; + break; + case 'col': + $this->_col = $attribute->nodeValue; + break; + case 'inputValue': + $this->_inputValue = $attribute->nodeValue; + break; + case 'numericValue': + $this->_numericValue = $attribute->nodeValue; + break; + default: + parent::takeAttributeFromDOM($attribute); + } + } + + /** + * Gets the row attribute of the Cell element. + * @return string Row of the Cell. + */ + public function getRow() + { + return $this->_row; + } + + /** + * Gets the column attribute of the Cell element. + * @return string Column of the Cell. + */ + public function getColumn() + { + return $this->_col; + } + + /** + * Gets the input value attribute of the Cell element. + * @return string Input value of the Cell. + */ + public function getInputValue() + { + return $this->_inputValue; + } + + /** + * Gets the numeric value attribute of the Cell element. + * @return string Numeric value of the Cell. + */ + public function getNumericValue() + { + return $this->_numericValue; + } + + /** + * Sets the row attribute of the Cell element. + * @param string $row New row of the Cell. + */ + public function setRow($row) + { + $this->_row = $row; + return $this; + } + + /** + * Sets the column attribute of the Cell element. + * @param string $col New column of the Cell. + */ + public function setColumn($col) + { + $this->_col = $col; + return $this; + } + + /** + * Sets the input value attribute of the Cell element. + * @param string $inputValue New input value of the Cell. + */ + public function setInputValue($inputValue) + { + $this->_inputValue = $inputValue; + return $this; + } + + /** + * Sets the numeric value attribute of the Cell element. + * @param string $numericValue New numeric value of the Cell. + */ + public function setNumericValue($numericValue) + { + $this->_numericValue = $numericValue; + } + +} diff --git a/Zend/Gdata/Spreadsheets/Extension/ColCount.php b/Zend/Gdata/Spreadsheets/Extension/ColCount.php new file mode 100644 index 00000000..840033aa --- /dev/null +++ b/Zend/Gdata/Spreadsheets/Extension/ColCount.php @@ -0,0 +1,59 @@ +registerAllNamespaces(Zend_Gdata_Spreadsheets::$namespaces); + parent::__construct(); + $this->_text = $text; + } +} diff --git a/Zend/Gdata/Spreadsheets/Extension/Custom.php b/Zend/Gdata/Spreadsheets/Extension/Custom.php new file mode 100644 index 00000000..e1f56cb0 --- /dev/null +++ b/Zend/Gdata/Spreadsheets/Extension/Custom.php @@ -0,0 +1,100 @@ +registerAllNamespaces(Zend_Gdata_Spreadsheets::$namespaces); + parent::__construct(); + $this->_text = $value; + $this->_rootElement = $column; + } + + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc, $majorVersion, $minorVersion); + return $element; + } + + /** + * Transfers each child and attribute into member variables. + * This is called when XML is received over the wire and the data + * model needs to be built to represent this XML. + * + * @param DOMNode $node The DOMNode that represents this object's data + */ + public function transferFromDOM($node) + { + parent::transferFromDOM($node); + $this->_rootElement = $node->localName; + } + + /** + * Sets the column/tag name of the element. + * @param string $column The new column name. + */ + public function setColumnName($column) + { + $this->_rootElement = $column; + return $this; + } + + /** + * Gets the column name of the element + * @return string The column name. + */ + public function getColumnName() + { + return $this->_rootElement; + } + +} diff --git a/Zend/Gdata/Spreadsheets/Extension/RowCount.php b/Zend/Gdata/Spreadsheets/Extension/RowCount.php new file mode 100644 index 00000000..310c9be6 --- /dev/null +++ b/Zend/Gdata/Spreadsheets/Extension/RowCount.php @@ -0,0 +1,60 @@ +registerAllNamespaces(Zend_Gdata_Spreadsheets::$namespaces); + parent::__construct(); + $this->_text = $text; + } + +} diff --git a/Zend/Gdata/Spreadsheets/ListEntry.php b/Zend/Gdata/Spreadsheets/ListEntry.php new file mode 100644 index 00000000..e1ac7087 --- /dev/null +++ b/Zend/Gdata/Spreadsheets/ListEntry.php @@ -0,0 +1,208 @@ +registerAllNamespaces(Zend_Gdata_Spreadsheets::$namespaces); + parent::__construct($element); + } + + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc, $majorVersion, $minorVersion); + if (!empty($this->_custom)) { + foreach ($this->_custom as $custom) { + $element->appendChild($custom->getDOM($element->ownerDocument)); + } + } + return $element; + } + + protected function takeChildFromDOM($child) + { + switch ($child->namespaceURI) { + case $this->lookupNamespace('gsx'); + $custom = new Zend_Gdata_Spreadsheets_Extension_Custom($child->localName); + $custom->transferFromDOM($child); + $this->addCustom($custom); + break; + default: + parent::takeChildFromDOM($child); + break; + } + } + + /** + * Gets the row elements contained by this list entry. + * @return array The custom row elements in this list entry + */ + public function getCustom() + { + return $this->_custom; + } + + /** + * Gets a single row element contained by this list entry using its name. + * @param string $name The name of a custom element to return. If null + * or not defined, an array containing all custom elements + * indexed by name will be returned. + * @return mixed If a name is specified, the + * Zend_Gdata_Spreadsheets_Extension_Custom element requested, + * is returned or null if not found. Otherwise, an array of all + * Zend_Gdata_Spreadsheets_Extension_Custom elements is returned + * indexed by name. + */ + public function getCustomByName($name = null) + { + if ($name === null) { + return $this->_customByName; + } else { + if (array_key_exists($name, $this->customByName)) { + return $this->_customByName[$name]; + } else { + return null; + } + } + } + + /** + * Sets the row elements contained by this list entry. If any + * custom row elements were previously stored, they will be overwritten. + * @param array $custom The custom row elements to be contained in this + * list entry. + * @return Zend_Gdata_Spreadsheets_ListEntry Provides a fluent interface. + */ + public function setCustom($custom) + { + $this->_custom = array(); + foreach ($custom as $c) { + $this->addCustom($c); + } + return $this; + } + + /** + * Add an individual custom row element to this list entry. + * @param Zend_Gdata_Spreadsheets_Extension_Custom $custom The custom + * element to be added. + * @return Zend_Gdata_Spreadsheets_ListEntry Provides a fluent interface. + */ + public function addCustom($custom) + { + $this->_custom[] = $custom; + $this->_customByName[$custom->getColumnName()] = $custom; + return $this; + } + + /** + * Remove an individual row element from this list entry by index. This + * will cause the array to be re-indexed. + * @param int $index The index of the custom element to be deleted. + * @return Zend_Gdata_Spreadsheets_ListEntry Provides a fluent interface. + * @throws Zend_Gdata_App_InvalidArgumentException + */ + public function removeCustom($index) + { + if (array_key_exists($index, $this->_custom)) { + $element = $this->_custom[$index]; + // Remove element + unset($this->_custom[$index]); + // Re-index the array + $this->_custom = array_values($this->_custom); + // Be sure to delete form both arrays! + $key = array_search($element, $this->_customByName); + unset($this->_customByName[$key]); + } else { + require_once 'Zend/Gdata/App/InvalidArgumentException.php'; + throw new Zend_Gdata_App_InvalidArgumentException( + 'Element does not exist.'); + } + return $this; + } + + /** + * Remove an individual row element from this list entry by name. + * @param string $name The name of the custom element to be deleted. + * @return Zend_Gdata_Spreadsheets_ListEntry Provides a fluent interface. + * @throws Zend_Gdata_App_InvalidArgumentException + */ + public function removeCustomByName($name) + { + if (array_key_exists($name, $this->_customByName)) { + $element = $this->_customByName[$name]; + // Remove element + unset($this->_customByName[$name]); + // Be sure to delete from both arrays! + $key = array_search($element, $this->_custom); + unset($this->_custom[$key]); + } else { + require_once 'Zend/Gdata/App/InvalidArgumentException.php'; + throw new Zend_Gdata_App_InvalidArgumentException( + 'Element does not exist.'); + } + return $this; + } + +} diff --git a/Zend/Gdata/Spreadsheets/ListFeed.php b/Zend/Gdata/Spreadsheets/ListFeed.php new file mode 100644 index 00000000..b925838e --- /dev/null +++ b/Zend/Gdata/Spreadsheets/ListFeed.php @@ -0,0 +1,64 @@ +registerAllNamespaces(Zend_Gdata_Spreadsheets::$namespaces); + parent::__construct($element); + } + +} diff --git a/Zend/Gdata/Spreadsheets/ListQuery.php b/Zend/Gdata/Spreadsheets/ListQuery.php new file mode 100644 index 00000000..1fb17b86 --- /dev/null +++ b/Zend/Gdata/Spreadsheets/ListQuery.php @@ -0,0 +1,305 @@ +_spreadsheetKey = $value; + return $this; + } + + /** + * Gets the spreadsheet key for the query. + * @return string spreadsheet key + */ + public function getSpreadsheetKey() + { + return $this->_spreadsheetKey; + } + + /** + * Sets the worksheet id for the query. + * @param string $value + * @return Zend_Gdata_Spreadsheets_CellQuery Provides a fluent interface + */ + public function setWorksheetId($value) + { + $this->_worksheetId = $value; + return $this; + } + + /** + * Gets the worksheet id for the query. + * @return string worksheet id + */ + public function getWorksheetId() + { + return $this->_worksheetId; + } + + /** + * Sets the row id for the query. + * @param string $value row id + * @return Zend_Gdata_Spreadsheets_CellQuery Provides a fluent interface + */ + public function setRowId($value) + { + $this->_rowId = $value; + return $this; + } + + /** + * Gets the row id for the query. + * @return string row id + */ + public function getRowId() + { + return $this->_rowId; + } + + /** + * Sets the projection for the query. + * @param string $value Projection + * @return Zend_Gdata_Spreadsheets_ListQuery Provides a fluent interface + */ + public function setProjection($value) + { + $this->_projection = $value; + return $this; + } + + /** + * Sets the visibility for this query. + * @param string $value visibility + * @return Zend_Gdata_Spreadsheets_ListQuery Provides a fluent interface + */ + public function setVisibility($value) + { + $this->_visibility = $value; + return $this; + } + + /** + * Gets the projection for this query. + * @return string projection + */ + public function getProjection() + { + return $this->_projection; + } + + /** + * Gets the visibility for this query. + * @return string visibility + */ + public function getVisibility() + { + return $this->_visibility; + } + + /** + * Sets the spreadsheet key for this query. + * @param string $value + * @return Zend_Gdata_Spreadsheets_DocumentQuery Provides a fluent interface + */ + public function setSpreadsheetQuery($value) + { + if ($value != null) { + $this->_params['sq'] = $value; + } else { + unset($this->_params['sq']); + } + return $this; + } + + /** + * Gets the spreadsheet key for this query. + * @return string spreadsheet query + */ + public function getSpreadsheetQuery() + { + if (array_key_exists('sq', $this->_params)) { + return $this->_params['sq']; + } else { + return null; + } + } + + /** + * Sets the orderby attribute for this query. + * @param string $value + * @return Zend_Gdata_Spreadsheets_DocumentQuery Provides a fluent interface + */ + public function setOrderBy($value) + { + if ($value != null) { + $this->_params['orderby'] = $value; + } else { + unset($this->_params['orderby']); + } + return $this; + } + + /** + * Gets the orderby attribute for this query. + * @return string orderby + */ + public function getOrderBy() + { + if (array_key_exists('orderby', $this->_params)) { + return $this->_params['orderby']; + } else { + return null; + } + } + + /** + * Sets the reverse attribute for this query. + * @param string $value + * @return Zend_Gdata_Spreadsheets_DocumentQuery Provides a fluent interface + */ + public function setReverse($value) + { + if ($value != null) { + $this->_params['reverse'] = $value; + } else { + unset($this->_params['reverse']); + } + return $this; + } + + /** + * Gets the reverse attribute for this query. + * @return string reverse + */ + public function getReverse() + { + + + if (array_key_exists('reverse', $this->_params)) { + return $this->_params['reverse']; + } else { + return null; + } + } + + /** + * Gets the full query URL for this query. + * @return string url + */ + public function getQueryUrl() + { + + $uri = $this->_defaultFeedUri; + + if ($this->_spreadsheetKey != null) { + $uri .= '/'.$this->_spreadsheetKey; + } else { + require_once 'Zend/Gdata/App/Exception.php'; + throw new Zend_Gdata_App_Exception('A spreadsheet key must be provided for list queries.'); + } + + if ($this->_worksheetId != null) { + $uri .= '/'.$this->_worksheetId; + } else { + require_once 'Zend/Gdata/App/Exception.php'; + throw new Zend_Gdata_App_Exception('A worksheet id must be provided for list queries.'); + } + + if ($this->_visibility != null) { + $uri .= '/'.$this->_visibility; + } else { + require_once 'Zend/Gdata/App/Exception.php'; + throw new Zend_Gdata_App_Exception('A visibility must be provided for list queries.'); + } + + if ($this->_projection != null) { + $uri .= '/'.$this->_projection; + } else { + require_once 'Zend/Gdata/App/Exception.php'; + throw new Zend_Gdata_App_Exception('A projection must be provided for list queries.'); + } + + if ($this->_rowId != null) { + $uri .= '/'.$this->_rowId; + } + + $uri .= $this->getQueryString(); + return $uri; + } + + /** + * Gets the attribute query string for this query. + * @return string query string + */ + public function getQueryString() + { + return parent::getQueryString(); + } + +} diff --git a/Zend/Gdata/Spreadsheets/SpreadsheetEntry.php b/Zend/Gdata/Spreadsheets/SpreadsheetEntry.php new file mode 100644 index 00000000..b6781cc4 --- /dev/null +++ b/Zend/Gdata/Spreadsheets/SpreadsheetEntry.php @@ -0,0 +1,64 @@ +registerAllNamespaces(Zend_Gdata_Spreadsheets::$namespaces); + parent::__construct($element); + } + + /** + * Returns the worksheets in this spreadsheet + * + * @return Zend_Gdata_Spreadsheets_WorksheetFeed The worksheets + */ + public function getWorksheets() + { + $service = new Zend_Gdata_Spreadsheets($this->getHttpClient()); + return $service->getWorksheetFeed($this); + } + +} diff --git a/Zend/Gdata/Spreadsheets/SpreadsheetFeed.php b/Zend/Gdata/Spreadsheets/SpreadsheetFeed.php new file mode 100644 index 00000000..efca3b18 --- /dev/null +++ b/Zend/Gdata/Spreadsheets/SpreadsheetFeed.php @@ -0,0 +1,64 @@ +registerAllNamespaces(Zend_Gdata_Spreadsheets::$namespaces); + parent::__construct($element); + } + +} diff --git a/Zend/Gdata/Spreadsheets/WorksheetEntry.php b/Zend/Gdata/Spreadsheets/WorksheetEntry.php new file mode 100644 index 00000000..92278e9e --- /dev/null +++ b/Zend/Gdata/Spreadsheets/WorksheetEntry.php @@ -0,0 +1,187 @@ +registerAllNamespaces(Zend_Gdata_Spreadsheets::$namespaces); + parent::__construct($element); + } + + /** + * Retrieves a DOMElement which corresponds to this element and all + * child properties. This is used to build an entry back into a DOM + * and eventually XML text for sending to the server upon updates, or + * for application storage/persistence. + * + * @param DOMDocument $doc The DOMDocument used to construct DOMElements + * @return DOMElement The DOMElement representing this element and all + * child properties. + */ + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc, $majorVersion, $minorVersion); + if ($this->_rowCount != null) { + $element->appendChild($this->_rowCount->getDOM($element->ownerDocument)); + } + if ($this->_colCount != null) { + $element->appendChild($this->_colCount->getDOM($element->ownerDocument)); + } + return $element; + } + + /** + * Creates individual Entry objects of the appropriate type and + * stores them in the $_entry array based upon DOM data. + * + * @param DOMNode $child The DOMNode to process + */ + protected function takeChildFromDOM($child) + { + $absoluteNodeName = $child->namespaceURI . ':' . $child->localName; + switch ($absoluteNodeName) { + case $this->lookupNamespace('gs') . ':' . 'rowCount'; + $rowCount = new Zend_Gdata_Spreadsheets_Extension_RowCount(); + $rowCount->transferFromDOM($child); + $this->_rowCount = $rowCount; + break; + case $this->lookupNamespace('gs') . ':' . 'colCount'; + $colCount = new Zend_Gdata_Spreadsheets_Extension_ColCount(); + $colCount->transferFromDOM($child); + $this->_colCount = $colCount; + break; + default: + parent::takeChildFromDOM($child); + break; + } + } + + + /** + * Gets the row count for this entry. + * + * @return string The row count for the entry. + */ + public function getRowCount() + { + return $this->_rowCount; + } + + /** + * Gets the column count for this entry. + * + * @return string The column count for the entry. + */ + public function getColumnCount() + { + return $this->_colCount; + } + + /** + * Sets the row count for this entry. + * + * @param string $rowCount The new row count for the entry. + */ + public function setRowCount($rowCount) + { + $this->_rowCount = $rowCount; + return $this; + } + + /** + * Sets the column count for this entry. + * + * @param string $colCount The new column count for the entry. + */ + public function setColumnCount($colCount) + { + $this->_colCount = $colCount; + return $this; + } + + /** + * Returns the content of all rows as an associative array + * + * @return array An array of rows. Each element of the array is an associative array of data + */ + public function getContentsAsRows() + { + $service = new Zend_Gdata_Spreadsheets($this->getHttpClient()); + return $service->getSpreadsheetListFeedContents($this); + } + + /** + * Returns the content of all cells as an associative array, indexed + * off the cell location (ie 'A1', 'D4', etc). Each element of + * the array is an associative array with a 'value' and a 'function'. + * Only non-empty cells are returned by default. 'range' is the + * value of the 'range' query parameter specified at: + * http://code.google.com/apis/spreadsheets/reference.html#cells_Parameters + * + * @param string $range The range of cells to retrieve + * @param boolean $empty Whether to retrieve empty cells + * @return array An associative array of cells + */ + public function getContentsAsCells($range = null, $empty = false) + { + $service = new Zend_Gdata_Spreadsheets($this->getHttpClient()); + return $service->getSpreadsheetCellFeedContents($this, $range, $empty); + } + +} diff --git a/Zend/Gdata/Spreadsheets/WorksheetFeed.php b/Zend/Gdata/Spreadsheets/WorksheetFeed.php new file mode 100644 index 00000000..0c43234b --- /dev/null +++ b/Zend/Gdata/Spreadsheets/WorksheetFeed.php @@ -0,0 +1,64 @@ +registerAllNamespaces(Zend_Gdata_Spreadsheets::$namespaces); + parent::__construct($element); + } + + /** + * The classname for individual feed elements. + * + * @var string + */ + protected $_entryClassName = 'Zend_Gdata_Spreadsheets_WorksheetEntry'; + + /** + * The classname for the feed. + * + * @var string + */ + protected $_feedClassName = 'Zend_Gdata_Spreadsheets_WorksheetFeed'; + +} diff --git a/Zend/Gdata/YouTube.php b/Zend/Gdata/YouTube.php new file mode 100644 index 00000000..b3f56f05 --- /dev/null +++ b/Zend/Gdata/YouTube.php @@ -0,0 +1,874 @@ +registerPackage('Zend_Gdata_YouTube'); + $this->registerPackage('Zend_Gdata_YouTube_Extension'); + $this->registerPackage('Zend_Gdata_Media'); + $this->registerPackage('Zend_Gdata_Media_Extension'); + + // NOTE This constructor no longer calls the parent constructor + $this->setHttpClient($client, $applicationId, $clientId, $developerKey); + } + + /** + * Set the Zend_Http_Client object used for communication + * + * @param Zend_Http_Client $client The client to use for communication + * @throws Zend_Gdata_App_HttpException + * @return Zend_Gdata_App Provides a fluent interface + */ + public function setHttpClient($client, + $applicationId = 'MyCompany-MyApp-1.0', $clientId = null, + $developerKey = null) + { + if ($client === null) { + $client = new Zend_Http_Client(); + } + if (!$client instanceof Zend_Http_Client) { + require_once 'Zend/Gdata/App/HttpException.php'; + throw new Zend_Gdata_App_HttpException( + 'Argument is not an instance of Zend_Http_Client.'); + } + + if ($clientId != null) { + $client->setHeaders('X-GData-Client', $clientId); + } + + if ($developerKey != null) { + $client->setHeaders('X-GData-Key', 'key='. $developerKey); + } + + return parent::setHttpClient($client, $applicationId); + } + + /** + * Retrieves a feed of videos. + * + * @param mixed $location (optional) The URL to query or a + * Zend_Gdata_Query object from which a URL can be determined + * @return Zend_Gdata_YouTube_VideoFeed The feed of videos found at the + * specified URL. + */ + public function getVideoFeed($location = null) + { + if ($location == null) { + $uri = self::VIDEO_URI; + } else if ($location instanceof Zend_Gdata_Query) { + $uri = $location->getQueryUrl(); + } else { + $uri = $location; + } + return parent::getFeed($uri, 'Zend_Gdata_YouTube_VideoFeed'); + } + + /** + * Retrieves a specific video entry. + * + * @param mixed $videoId The ID of the video to retrieve. + * @param mixed $location (optional) The URL to query or a + * Zend_Gdata_Query object from which a URL can be determined. + * @param boolean $fullEntry (optional) Retrieve the full metadata for the + * entry. Only possible if entry belongs to currently authenticated + * user. An exception will be thrown otherwise. + * @throws Zend_Gdata_App_HttpException + * @return Zend_Gdata_YouTube_VideoEntry The video entry found at the + * specified URL. + */ + public function getVideoEntry($videoId = null, $location = null, + $fullEntry = false) + { + if ($videoId !== null) { + if ($fullEntry) { + return $this->getFullVideoEntry($videoId); + } else { + $uri = self::VIDEO_URI . "/" . $videoId; + } + } else if ($location instanceof Zend_Gdata_Query) { + $uri = $location->getQueryUrl(); + } else { + $uri = $location; + } + return parent::getEntry($uri, 'Zend_Gdata_YouTube_VideoEntry'); + } + + /** + * Retrieves a video entry from the user's upload feed. + * + * @param mixed $videoID The ID of the video to retrieve. + * @throws Zend_Gdata_App_HttpException + * @return Zend_Gdata_YouTube_VideoEntry|null The video entry to be + * retrieved, or null if it was not found or the user requesting it + * did not have the appropriate permissions. + */ + public function getFullVideoEntry($videoId) + { + $uri = self::USER_URI . "/default/" . + self::UPLOADS_URI_SUFFIX . "/$videoId"; + return parent::getEntry($uri, 'Zend_Gdata_YouTube_VideoEntry'); + } + + /** + * Retrieves a feed of videos related to the specified video ID. + * + * @param string $videoId The videoId of interest + * @param mixed $location (optional) The URL to query or a + * Zend_Gdata_Query object from which a URL can be determined + * @return Zend_Gdata_YouTube_VideoFeed The feed of videos found at the + * specified URL. + */ + public function getRelatedVideoFeed($videoId = null, $location = null) + { + if ($videoId !== null) { + $uri = self::VIDEO_URI . "/" . $videoId . "/" . + self::RELATED_URI_SUFFIX; + } else if ($location instanceof Zend_Gdata_Query) { + $uri = $location->getQueryUrl(); + } else { + $uri = $location; + } + return parent::getFeed($uri, 'Zend_Gdata_YouTube_VideoFeed'); + } + + /** + * Retrieves a feed of video responses related to the specified video ID. + * + * @param string $videoId The videoId of interest + * @param mixed $location (optional) The URL to query or a + * Zend_Gdata_Query object from which a URL can be determined + * @return Zend_Gdata_YouTube_VideoFeed The feed of videos found at the + * specified URL. + */ + public function getVideoResponseFeed($videoId = null, $location = null) + { + if ($videoId !== null) { + $uri = self::VIDEO_URI . "/" . $videoId . "/" . + self::RESPONSES_URI_SUFFIX; + } else if ($location instanceof Zend_Gdata_Query) { + $uri = $location->getQueryUrl(); + } else { + $uri = $location; + } + return parent::getFeed($uri, 'Zend_Gdata_YouTube_VideoFeed'); + } + + /** + * Retrieves a feed of comments related to the specified video ID. + * + * @param string $videoId The videoId of interest + * @param mixed $location (optional) The URL to query or a + * Zend_Gdata_Query object from which a URL can be determined + * @return Zend_Gdata_YouTube_CommentFeed The feed of videos found at the + * specified URL. + */ + public function getVideoCommentFeed($videoId = null, $location = null) + { + if ($videoId !== null) { + $uri = self::VIDEO_URI . "/" . $videoId . "/comments"; + } else if ($location instanceof Zend_Gdata_Query) { + $uri = $location->getQueryUrl(); + } else { + $uri = $location; + } + return parent::getFeed($uri, 'Zend_Gdata_YouTube_CommentFeed'); + } + + /** + * Retrieves a feed of comments related to the specified video ID. + * + * @param mixed $location (optional) The URL to query or a + * Zend_Gdata_Query object from which a URL can be determined + * @return Zend_Gdata_YouTube_CommentFeed The feed of videos found at the + * specified URL. + */ + public function getTopRatedVideoFeed($location = null) + { + $standardFeedUri = self::STANDARD_TOP_RATED_URI; + + if ($this->getMajorProtocolVersion() == 2) { + $standardFeedUri = self::STANDARD_TOP_RATED_URI_V2; + } + + if ($location == null) { + $uri = $standardFeedUri; + } else if ($location instanceof Zend_Gdata_Query) { + if ($location instanceof Zend_Gdata_YouTube_VideoQuery) { + if (!isset($location->url)) { + $location->setFeedType('top rated'); + } + } + $uri = $location->getQueryUrl(); + } else { + $uri = $location; + } + return parent::getFeed($uri, 'Zend_Gdata_YouTube_VideoFeed'); + } + + + /** + * Retrieves a feed of the most viewed videos. + * + * @param mixed $location (optional) The URL to query or a + * Zend_Gdata_Query object from which a URL can be determined + * @return Zend_Gdata_YouTube_VideoFeed The feed of videos found at the + * specified URL. + */ + public function getMostViewedVideoFeed($location = null) + { + $standardFeedUri = self::STANDARD_MOST_VIEWED_URI; + + if ($this->getMajorProtocolVersion() == 2) { + $standardFeedUri = self::STANDARD_MOST_VIEWED_URI_V2; + } + + if ($location == null) { + $uri = $standardFeedUri; + } else if ($location instanceof Zend_Gdata_Query) { + if ($location instanceof Zend_Gdata_YouTube_VideoQuery) { + if (!isset($location->url)) { + $location->setFeedType('most viewed'); + } + } + $uri = $location->getQueryUrl(); + } else { + $uri = $location; + } + return parent::getFeed($uri, 'Zend_Gdata_YouTube_VideoFeed'); + } + + /** + * Retrieves a feed of recently featured videos. + * + * @param mixed $location (optional) The URL to query or a + * Zend_Gdata_Query object from which a URL can be determined + * @return Zend_Gdata_YouTube_VideoFeed The feed of videos found at the + * specified URL. + */ + public function getRecentlyFeaturedVideoFeed($location = null) + { + $standardFeedUri = self::STANDARD_RECENTLY_FEATURED_URI; + + if ($this->getMajorProtocolVersion() == 2) { + $standardFeedUri = self::STANDARD_RECENTLY_FEATURED_URI_V2; + } + + if ($location == null) { + $uri = $standardFeedUri; + } else if ($location instanceof Zend_Gdata_Query) { + if ($location instanceof Zend_Gdata_YouTube_VideoQuery) { + if (!isset($location->url)) { + $location->setFeedType('recently featured'); + } + } + $uri = $location->getQueryUrl(); + } else { + $uri = $location; + } + return parent::getFeed($uri, 'Zend_Gdata_YouTube_VideoFeed'); + } + + /** + * Retrieves a feed of videos recently featured for mobile devices. + * These videos will have RTSP links in the $entry->mediaGroup->content + * + * @param mixed $location (optional) The URL to query or a + * Zend_Gdata_Query object from which a URL can be determined + * @return Zend_Gdata_YouTube_VideoFeed The feed of videos found at the + * specified URL. + */ + public function getWatchOnMobileVideoFeed($location = null) + { + $standardFeedUri = self::STANDARD_WATCH_ON_MOBILE_URI; + + if ($this->getMajorProtocolVersion() == 2) { + $standardFeedUri = self::STANDARD_WATCH_ON_MOBILE_URI_V2; + } + + if ($location == null) { + $uri = $standardFeedUri; + } else if ($location instanceof Zend_Gdata_Query) { + if ($location instanceof Zend_Gdata_YouTube_VideoQuery) { + if (!isset($location->url)) { + $location->setFeedType('watch on mobile'); + } + } + $uri = $location->getQueryUrl(); + } else { + $uri = $location; + } + return parent::getFeed($uri, 'Zend_Gdata_YouTube_VideoFeed'); + } + + /** + * Retrieves a feed which lists a user's playlist + * + * @param string $user (optional) The username of interest + * @param mixed $location (optional) The URL to query or a + * Zend_Gdata_Query object from which a URL can be determined + * @return Zend_Gdata_YouTube_PlaylistListFeed The feed of playlists + */ + public function getPlaylistListFeed($user = null, $location = null) + { + if ($user !== null) { + $uri = self::USER_URI . '/' . $user . '/playlists'; + } else if ($location instanceof Zend_Gdata_Query) { + $uri = $location->getQueryUrl(); + } else { + $uri = $location; + } + return parent::getFeed($uri, 'Zend_Gdata_YouTube_PlaylistListFeed'); + } + + /** + * Retrieves a feed of videos in a particular playlist + * + * @param mixed $location (optional) The URL to query or a + * Zend_Gdata_Query object from which a URL can be determined + * @return Zend_Gdata_YouTube_PlaylistVideoFeed The feed of videos found at + * the specified URL. + */ + public function getPlaylistVideoFeed($location) + { + if ($location instanceof Zend_Gdata_Query) { + $uri = $location->getQueryUrl(); + } else { + $uri = $location; + } + return parent::getFeed($uri, 'Zend_Gdata_YouTube_PlaylistVideoFeed'); + } + + /** + * Retrieves a feed of a user's subscriptions + * + * @param string $user (optional) The username of interest + * @param mixed $location (optional) The URL to query or a + * Zend_Gdata_Query object from which a URL can be determined + * @return Zend_Gdata_YouTube_SubscriptionListFeed The feed of subscriptions + */ + public function getSubscriptionFeed($user = null, $location = null) + { + if ($user !== null) { + $uri = self::USER_URI . '/' . $user . '/subscriptions'; + } else if ($location instanceof Zend_Gdata_Query) { + $uri = $location->getQueryUrl(); + } else { + $uri = $location; + } + return parent::getFeed($uri, 'Zend_Gdata_YouTube_SubscriptionFeed'); + } + + /** + * Retrieves a feed of a user's contacts + * + * @param string $user (optional) The username of interest + * @param mixed $location (optional) The URL to query or a + * Zend_Gdata_Query object from which a URL can be determined + * @return Zend_Gdata_YouTube_ContactFeed The feed of contacts + */ + public function getContactFeed($user = null, $location = null) + { + if ($user !== null) { + $uri = self::USER_URI . '/' . $user . '/contacts'; + } else if ($location instanceof Zend_Gdata_Query) { + $uri = $location->getQueryUrl(); + } else { + $uri = $location; + } + return parent::getFeed($uri, 'Zend_Gdata_YouTube_ContactFeed'); + } + + /** + * Retrieves a user's uploads + * + * @param string $user (optional) The username of interest + * @param mixed $location (optional) The URL to query or a + * Zend_Gdata_Query object from which a URL can be determined + * @return Zend_Gdata_YouTube_VideoFeed The videos uploaded by the user + */ + public function getUserUploads($user = null, $location = null) + { + if ($user !== null) { + $uri = self::USER_URI . '/' . $user . '/' . + self::UPLOADS_URI_SUFFIX; + } else if ($location instanceof Zend_Gdata_Query) { + $uri = $location->getQueryUrl(); + } else { + $uri = $location; + } + return parent::getFeed($uri, 'Zend_Gdata_YouTube_VideoFeed'); + } + + /** + * Retrieves a user's favorites + * + * @param string $user (optional) The username of interest + * @param mixed $location (optional) The URL to query or a + * Zend_Gdata_Query object from which a URL can be determined + * @return Zend_Gdata_YouTube_VideoFeed The videos favorited by the user + */ + public function getUserFavorites($user = null, $location = null) + { + if ($user !== null) { + $uri = self::USER_URI . '/' . $user . '/' . + self::FAVORITES_URI_SUFFIX; + } else if ($location instanceof Zend_Gdata_Query) { + $uri = $location->getQueryUrl(); + } else { + $uri = $location; + } + return parent::getFeed($uri, 'Zend_Gdata_YouTube_VideoFeed'); + } + + /** + * Retrieves a user's profile as an entry + * + * @param string $user (optional) The username of interest + * @param mixed $location (optional) The URL to query or a + * Zend_Gdata_Query object from which a URL can be determined + * @return Zend_Gdata_YouTube_UserProfileEntry The user profile entry + */ + public function getUserProfile($user = null, $location = null) + { + if ($user !== null) { + $uri = self::USER_URI . '/' . $user; + } else if ($location instanceof Zend_Gdata_Query) { + $uri = $location->getQueryUrl(); + } else { + $uri = $location; + } + return parent::getEntry($uri, 'Zend_Gdata_YouTube_UserProfileEntry'); + } + + /** + * Helper function for parsing a YouTube token response + * + * @param string $response The service response + * @throws Zend_Gdata_App_Exception + * @return array An array containing the token and URL + */ + public static function parseFormUploadTokenResponse($response) + { + // Load the feed as an XML DOMDocument object + @ini_set('track_errors', 1); + $doc = new DOMDocument(); + $success = @$doc->loadXML($response); + @ini_restore('track_errors'); + + if (!$success) { + require_once 'Zend/Gdata/App/Exception.php'; + throw new Zend_Gdata_App_Exception( + "Zend_Gdata_YouTube::parseFormUploadTokenResponse - " . + "DOMDocument cannot parse XML: $php_errormsg"); + } + $responseElement = $doc->getElementsByTagName('response')->item(0); + + $urlText = null; + $tokenText = null; + if ($responseElement != null) { + $urlElement = + $responseElement->getElementsByTagName('url')->item(0); + $tokenElement = + $responseElement->getElementsByTagName('token')->item(0); + + if ($urlElement && $urlElement->hasChildNodes() && + $tokenElement && $tokenElement->hasChildNodes()) { + + $urlText = $urlElement->firstChild->nodeValue; + $tokenText = $tokenElement->firstChild->nodeValue; + } + } + + if ($tokenText != null && $urlText != null) { + return array('token' => $tokenText, 'url' => $urlText); + } else { + require_once 'Zend/Gdata/App/Exception.php'; + throw new Zend_Gdata_App_Exception( + 'Form upload token not found in response'); + } + } + + /** + * Retrieves a YouTube token + * + * @param Zend_Gdata_YouTube_VideoEntry $videoEntry The video entry + * @param string $url The location as a string URL + * @throws Zend_Gdata_App_Exception + * @return array An array containing a token and URL + */ + public function getFormUploadToken($videoEntry, + $url='http://gdata.youtube.com/action/GetUploadToken') + { + if ($url != null && is_string($url)) { + // $response is a Zend_Http_response object + $response = $this->post($videoEntry, $url); + return self::parseFormUploadTokenResponse($response->getBody()); + } else { + require_once 'Zend/Gdata/App/Exception.php'; + throw new Zend_Gdata_App_Exception( + 'Url must be provided as a string URL'); + } + } + + /** + * Retrieves the activity feed for users + * + * @param mixed $usernames A string identifying the usernames for which to + * retrieve activity for. This can also be a Zend_Gdata_Query + * object from which a URL can be determined. + * @throws Zend_Gdata_App_VersionException if using version less than 2. + * @return Zend_Gdata_YouTube_ActivityFeed + */ + public function getActivityForUser($username) + { + if ($this->getMajorProtocolVersion() == 1) { + require_once 'Zend/Gdata/App/VersionException.php'; + throw new Zend_Gdata_App_VersionException('User activity feeds ' . + 'are not available in API version 1.'); + } + + $uri = null; + if ($username instanceof Zend_Gdata_Query) { + $uri = $username->getQueryUrl(); + } else { + if (count(explode(',', $username)) > + self::ACTIVITY_FEED_MAX_USERS) { + require_once 'Zend/Gdata/App/InvalidArgumentException.php'; + throw new Zend_Gdata_App_InvalidArgumentException( + 'Activity feed can only retrieve for activity for up to ' . + self::ACTIVITY_FEED_MAX_USERS . ' users per request'); + } + $uri = self::ACTIVITY_FEED_URI . '?author=' . $username; + } + + return parent::getFeed($uri, 'Zend_Gdata_YouTube_ActivityFeed'); + } + + /** + * Retrieve the activity of the currently authenticated users friend. + * + * @throws Zend_Gdata_App_Exception if not logged in. + * @return Zend_Gdata_YouTube_ActivityFeed + */ + public function getFriendActivityForCurrentUser() + { + if (!$this->isAuthenticated()) { + require_once 'Zend/Gdata/App/Exception.php'; + throw new Zend_Gdata_App_Exception('You must be authenticated to ' . + 'use the getFriendActivityForCurrentUser function in Zend_' . + 'Gdata_YouTube.'); + } + return parent::getFeed(self::FRIEND_ACTIVITY_FEED_URI, + 'Zend_Gdata_YouTube_ActivityFeed'); + } + + /** + * Retrieve a feed of messages in the currently authenticated user's inbox. + * + * @throws Zend_Gdata_App_Exception if not logged in. + * @return Zend_Gdata_YouTube_InboxFeed|null + */ + public function getInboxFeedForCurrentUser() + { + if (!$this->isAuthenticated()) { + require_once 'Zend/Gdata/App/Exception.php'; + throw new Zend_Gdata_App_Exception('You must be authenticated to ' . + 'use the getInboxFeedForCurrentUser function in Zend_' . + 'Gdata_YouTube.'); + } + + return parent::getFeed(self::INBOX_FEED_URI, + 'Zend_Gdata_YouTube_InboxFeed'); + } + + /** + * Send a video message. + * + * Note: Either a Zend_Gdata_YouTube_VideoEntry or a valid video ID must + * be provided. + * + * @param string $body The body of the message + * @param Zend_Gdata_YouTube_VideoEntry (optional) The video entry to send + * @param string $videoId The id of the video to send + * @param string $recipientUserName The username of the recipient + * @throws Zend_Gdata_App_InvalidArgumentException if no valid + * Zend_Gdata_YouTube_VideoEntry or videoId were provided + * @return Zend_Gdata_YouTube_InboxEntry|null The + * Zend_Gdata_YouTube_Inbox_Entry representing the sent message. + * + */ + public function sendVideoMessage($body, $videoEntry = null, + $videoId = null, $recipientUserName) + { + if (!$videoId && !$videoEntry) { + require_once 'Zend/Gdata/App/InvalidArgumentException.php'; + throw new Zend_Gdata_App_InvalidArgumentException( + 'Expecting either a valid videoID or a videoEntry object in ' . + 'Zend_Gdata_YouTube->sendVideoMessage().'); + } + + $messageEntry = new Zend_Gdata_YouTube_InboxEntry(); + + if ($this->getMajorProtocolVersion() == null || + $this->getMajorProtocolVersion() == 1) { + + if (!$videoId) { + $videoId = $videoEntry->getVideoId(); + } elseif (strlen($videoId) < 12) { + //Append the full URI + $videoId = self::VIDEO_URI . '/' . $videoId; + } + + $messageEntry->setId($this->newId($videoId)); + // TODO there seems to be a bug where v1 inbox entries dont + // retain their description... + $messageEntry->setDescription( + new Zend_Gdata_YouTube_Extension_Description($body)); + + } else { + if (!$videoId) { + $videoId = $videoEntry->getVideoId(); + $videoId = substr($videoId, strrpos($videoId, ':')); + } + $messageEntry->setId($this->newId($videoId)); + $messageEntry->setSummary($this->newSummary($body)); + } + + $insertUrl = 'http://gdata.youtube.com/feeds/api/users/' . + $recipientUserName . '/inbox'; + $response = $this->insertEntry($messageEntry, $insertUrl, + 'Zend_Gdata_YouTube_InboxEntry'); + return $response; + } + + /** + * Post a comment in reply to an existing comment + * + * @param $commentEntry Zend_Gdata_YouTube_CommentEntry The comment entry + * to reply to + * @param $commentText string The text of the comment to post + * @return A Zend_Gdata_YouTube_CommentEntry representing the posted + * comment + */ + public function replyToCommentEntry($commentEntry, $commentText) + { + $newComment = $this->newCommentEntry(); + $newComment->content = $this->newContent()->setText($commentText); + $commentId = $commentEntry->getId(); + $commentIdArray = explode(':', $commentId); + + // create a new link element + $inReplyToLinkHref = self::VIDEO_URI . '/' . $commentIdArray[3] . + '/comments/' . $commentIdArray[5]; + $inReplyToLink = $this->newLink($inReplyToLinkHref, + self::IN_REPLY_TO_SCHEME, $type="application/atom+xml"); + $links = $newComment->getLink(); + $links[] = $inReplyToLink; + $newComment->setLink($links); + $commentFeedPostUrl = self::VIDEO_URI . '/' . $commentIdArray[3] . + '/comments'; + return $this->insertEntry($newComment, + $commentFeedPostUrl, 'Zend_Gdata_YouTube_CommentEntry'); + } + +} diff --git a/Zend/Gdata/YouTube/ActivityEntry.php b/Zend/Gdata/YouTube/ActivityEntry.php new file mode 100644 index 00000000..e1f1aee6 --- /dev/null +++ b/Zend/Gdata/YouTube/ActivityEntry.php @@ -0,0 +1,232 @@ +registerAllNamespaces(Zend_Gdata_YouTube::$namespaces); + parent::__construct($element); + } + + /** + * Retrieves a DOMElement which corresponds to this element and all + * child properties. This is used to build an entry back into a DOM + * and eventually XML text for application storage/persistence. + * + * @param DOMDocument $doc The DOMDocument used to construct DOMElements + * @return DOMElement The DOMElement representing this element and all + * child properties. + */ + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc, $majorVersion, $minorVersion); + if ($this->_videoId !== null) { + $element->appendChild($this->_videoId->getDOM( + $element->ownerDocument)); + } + if ($this->_username !== null) { + $element->appendChild($this->_username->getDOM( + $element->ownerDocument)); + } + if ($this->_rating !== null) { + $element->appendChild($this->_rating->getDOM( + $element->ownerDocument)); + } + return $element; + } + + /** + * Creates individual Entry objects of the appropriate type and + * stores them as members of this entry based upon DOM data. + * + * @param DOMNode $child The DOMNode to process + */ + protected function takeChildFromDOM($child) + { + $absoluteNodeName = $child->namespaceURI . ':' . $child->localName; + switch ($absoluteNodeName) { + case $this->lookupNamespace('yt') . ':' . 'videoid': + $videoId = new Zend_Gdata_YouTube_Extension_VideoId(); + $videoId->transferFromDOM($child); + $this->_videoId = $videoId; + break; + case $this->lookupNamespace('yt') . ':' . 'username': + $username = new Zend_Gdata_YouTube_Extension_Username(); + $username->transferFromDOM($child); + $this->_username = $username; + break; + case $this->lookupNamespace('gd') . ':' . 'rating': + $rating = new Zend_Gdata_Extension_Rating(); + $rating->transferFromDOM($child); + $this->_rating = $rating; + break; + default: + parent::takeChildFromDOM($child); + break; + } + } + + /** + * Returns the video ID for this activity entry. + * + * @return null|Zend_Gdata_YouTube_Extension_VideoId + */ + public function getVideoId() + { + return $this->_videoId; + } + + /** + * Returns the username for this activity entry. + * + * @return null|Zend_Gdata_YouTube_Extension_Username + */ + public function getUsername() + { + return $this->_username; + } + + /** + * Returns the rating for this activity entry. + * + * @return null|Zend_Gdata_YouTube_Extension_Rating + */ + public function getRating() + { + return $this->_rating; + } + + /** + * Return the value of the rating for this video entry. + * + * Convenience method to save needless typing. + * + * @return integer|null The value of the rating that was created, if found. + */ + public function getRatingValue() + { + $rating = $this->_rating; + if ($rating) { + return $rating->getValue(); + } + return null; + } + + /** + * Return the activity type that was performed. + * + * Convenience method that inspects category where scheme is + * http://gdata.youtube.com/schemas/2007/userevents.cat. + * + * @return string|null The activity category if found. + */ + public function getActivityType() + { + $categories = $this->getCategory(); + foreach($categories as $category) { + if ($category->getScheme() == self::ACTIVITY_CATEGORY_SCHEME) { + return $category->getTerm(); + } + } + return null; + } + + /** + * Convenience method to quickly get access to the author of the activity + * + * @return string The author of the activity + */ + public function getAuthorName() + { + $authors = $this->getAuthor(); + return $authors[0]->getName()->getText(); + } +} diff --git a/Zend/Gdata/YouTube/ActivityFeed.php b/Zend/Gdata/YouTube/ActivityFeed.php new file mode 100644 index 00000000..3c3978fa --- /dev/null +++ b/Zend/Gdata/YouTube/ActivityFeed.php @@ -0,0 +1,66 @@ +registerAllNamespaces(Zend_Gdata_YouTube::$namespaces); + parent::__construct($element); + } + +} diff --git a/Zend/Gdata/YouTube/CommentEntry.php b/Zend/Gdata/YouTube/CommentEntry.php new file mode 100644 index 00000000..3248b789 --- /dev/null +++ b/Zend/Gdata/YouTube/CommentEntry.php @@ -0,0 +1,59 @@ +registerAllNamespaces(Zend_Gdata_YouTube::$namespaces); + parent::__construct($element); + } + +} diff --git a/Zend/Gdata/YouTube/CommentFeed.php b/Zend/Gdata/YouTube/CommentFeed.php new file mode 100644 index 00000000..6aa9ec01 --- /dev/null +++ b/Zend/Gdata/YouTube/CommentFeed.php @@ -0,0 +1,66 @@ +registerAllNamespaces(Zend_Gdata_YouTube::$namespaces); + parent::__construct($element); + } + +} diff --git a/Zend/Gdata/YouTube/ContactEntry.php b/Zend/Gdata/YouTube/ContactEntry.php new file mode 100644 index 00000000..2c350f22 --- /dev/null +++ b/Zend/Gdata/YouTube/ContactEntry.php @@ -0,0 +1,136 @@ +registerAllNamespaces(Zend_Gdata_YouTube::$namespaces); + parent::__construct($element); + } + + /** + * Retrieves a DOMElement which corresponds to this element and all + * child properties. This is used to build an entry back into a DOM + * and eventually XML text for sending to the server upon updates, or + * for application storage/persistence. + * + * @param DOMDocument $doc The DOMDocument used to construct DOMElements + * @return DOMElement The DOMElement representing this element and all + * child properties. + */ + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc, $majorVersion, $minorVersion); + if ($this->_status != null) { + $element->appendChild($this->_status->getDOM($element->ownerDocument)); + } + return $element; + } + + /** + * Creates individual Entry objects of the appropriate type and + * stores them in the $_entry array based upon DOM data. + * + * @param DOMNode $child The DOMNode to process + */ + protected function takeChildFromDOM($child) + { + $absoluteNodeName = $child->namespaceURI . ':' . $child->localName; + switch ($absoluteNodeName) { + case $this->lookupNamespace('yt') . ':' . 'status': + $status = new Zend_Gdata_YouTube_Extension_Status(); + $status->transferFromDOM($child); + $this->_status = $status; + break; + default: + parent::takeChildFromDOM($child); + break; + } + } + + /** + * Sets the status + * + * @param Zend_Gdata_YouTube_Extension_Status $status The status + * @return Zend_Gdata_YouTube_ContactEntry Provides a fluent interface + */ + public function setStatus($status = null) + { + $this->_status = $status; + return $this; + } + + /** + * Returns the status + * + * @return Zend_Gdata_YouTube_Extension_Status The status + */ + public function getStatus() + { + return $this->_status; + } + +} diff --git a/Zend/Gdata/YouTube/ContactFeed.php b/Zend/Gdata/YouTube/ContactFeed.php new file mode 100644 index 00000000..60e4c4c3 --- /dev/null +++ b/Zend/Gdata/YouTube/ContactFeed.php @@ -0,0 +1,68 @@ +registerAllNamespaces(Zend_Gdata_YouTube::$namespaces); + parent::__construct($element); + } + +} diff --git a/Zend/Gdata/YouTube/Extension/AboutMe.php b/Zend/Gdata/YouTube/Extension/AboutMe.php new file mode 100644 index 00000000..20858efb --- /dev/null +++ b/Zend/Gdata/YouTube/Extension/AboutMe.php @@ -0,0 +1,51 @@ +registerAllNamespaces(Zend_Gdata_YouTube::$namespaces); + parent::__construct(); + $this->_text = $text; + } + +} diff --git a/Zend/Gdata/YouTube/Extension/Age.php b/Zend/Gdata/YouTube/Extension/Age.php new file mode 100644 index 00000000..d0c17b56 --- /dev/null +++ b/Zend/Gdata/YouTube/Extension/Age.php @@ -0,0 +1,51 @@ +registerAllNamespaces(Zend_Gdata_YouTube::$namespaces); + parent::__construct(); + $this->_text = $text; + } + +} diff --git a/Zend/Gdata/YouTube/Extension/Books.php b/Zend/Gdata/YouTube/Extension/Books.php new file mode 100644 index 00000000..2221c821 --- /dev/null +++ b/Zend/Gdata/YouTube/Extension/Books.php @@ -0,0 +1,51 @@ +registerAllNamespaces(Zend_Gdata_YouTube::$namespaces); + parent::__construct(); + $this->_text = $text; + } + +} diff --git a/Zend/Gdata/YouTube/Extension/Company.php b/Zend/Gdata/YouTube/Extension/Company.php new file mode 100644 index 00000000..ecd44f68 --- /dev/null +++ b/Zend/Gdata/YouTube/Extension/Company.php @@ -0,0 +1,51 @@ +registerAllNamespaces(Zend_Gdata_YouTube::$namespaces); + parent::__construct(); + $this->_text = $text; + } + +} diff --git a/Zend/Gdata/YouTube/Extension/Control.php b/Zend/Gdata/YouTube/Extension/Control.php new file mode 100644 index 00000000..618bc038 --- /dev/null +++ b/Zend/Gdata/YouTube/Extension/Control.php @@ -0,0 +1,133 @@ +registerAllNamespaces(Zend_Gdata_YouTube::$namespaces); + parent::__construct($draft); + $this->_state = $state; + } + + /** + * Retrieves a DOMElement which corresponds to this element and all + * child properties. This is used to build an entry back into a DOM + * and eventually XML text for sending to the server upon updates, or + * for application storage/persistence. + * + * @param DOMDocument $doc The DOMDocument used to construct DOMElements + * @return DOMElement The DOMElement representing this element and all + * child properties. + */ + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc, $majorVersion, $minorVersion); + if ($this->_state != null) { + $element->appendChild($this->_state->getDOM($element->ownerDocument)); + } + return $element; + } + + /** + * Creates individual Entry objects of the appropriate type and + * stores them as members of this entry based upon DOM data. + * + * @param DOMNode $child The DOMNode to process + */ + protected function takeChildFromDOM($child) + { + $absoluteNodeName = $child->namespaceURI . ':' . $child->localName; + switch ($absoluteNodeName) { + case $this->lookupNamespace('yt') . ':' . 'state': + $state = new Zend_Gdata_YouTube_Extension_State(); + $state->transferFromDOM($child); + $this->_state = $state; + break; + default: + parent::takeChildFromDOM($child); + break; + } + } + + /** + * Get the value for this element's state attribute. + * + * @return Zend_Gdata_YouTube_Extension_State The state element. + */ + public function getState() + { + return $this->_state; + } + + /** + * Set the value for this element's state attribute. + * + * @param Zend_Gdata_YouTube_Extension_State $value The desired value for this attribute. + * @return Zend_YouTube_Extension_Control The element being modified. + */ + public function setState($value) + { + $this->_state = $value; + return $this; + } + + /** + * Get the value of this element's state attribute. + * + * @return string The state's text value + */ + public function getStateValue() + { + return $this->getState()->getText(); + } + +} diff --git a/Zend/Gdata/YouTube/Extension/CountHint.php b/Zend/Gdata/YouTube/Extension/CountHint.php new file mode 100644 index 00000000..2eacf12c --- /dev/null +++ b/Zend/Gdata/YouTube/Extension/CountHint.php @@ -0,0 +1,51 @@ +registerAllNamespaces(Zend_Gdata_YouTube::$namespaces); + parent::__construct(); + $this->_text = $text; + } + +} diff --git a/Zend/Gdata/YouTube/Extension/Description.php b/Zend/Gdata/YouTube/Extension/Description.php new file mode 100644 index 00000000..1ec3b2aa --- /dev/null +++ b/Zend/Gdata/YouTube/Extension/Description.php @@ -0,0 +1,51 @@ +registerAllNamespaces(Zend_Gdata_YouTube::$namespaces); + parent::__construct(); + $this->_text = $text; + } + +} diff --git a/Zend/Gdata/YouTube/Extension/Duration.php b/Zend/Gdata/YouTube/Extension/Duration.php new file mode 100644 index 00000000..18b66931 --- /dev/null +++ b/Zend/Gdata/YouTube/Extension/Duration.php @@ -0,0 +1,126 @@ +registerAllNamespaces(Zend_Gdata_YouTube::$namespaces); + parent::__construct(); + $this->_seconds = $seconds; + } + + /** + * Retrieves a DOMElement which corresponds to this element and all + * child properties. This is used to build an entry back into a DOM + * and eventually XML text for sending to the server upon updates, or + * for application storage/persistence. + * + * @param DOMDocument $doc The DOMDocument used to construct DOMElements + * @return DOMElement The DOMElement representing this element and all + * child properties. + */ + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc, $majorVersion, $minorVersion); + if ($this->_seconds !== null) { + $element->setAttribute('seconds', $this->_seconds); + } + return $element; + } + + /** + * Given a DOMNode representing an attribute, tries to map the data into + * instance members. If no mapping is defined, the name and valueare + * stored in an array. + * + * @param DOMNode $attribute The DOMNode attribute needed to be handled + */ + protected function takeAttributeFromDOM($attribute) + { + switch ($attribute->localName) { + case 'seconds': + $this->_seconds = $attribute->nodeValue; + break; + default: + parent::takeAttributeFromDOM($attribute); + } + } + + /** + * Get the value for this element's seconds attribute. + * + * @return int The value associated with this attribute. + */ + public function getSeconds() + { + return $this->_seconds; + } + + /** + * Set the value for this element's seconds attribute. + * + * @param int $value The desired value for this attribute. + * @return Zend_Gdata_YouTube_Extension_Duration The element being modified. + */ + public function setSeconds($value) + { + $this->_seconds = $value; + return $this; + } + + /** + * Magic toString method allows using this directly via echo + * Works best in PHP >= 4.2.0 + * + * @return string The duration in seconds + */ + public function __toString() + { + return $this->_seconds; + } + +} diff --git a/Zend/Gdata/YouTube/Extension/FirstName.php b/Zend/Gdata/YouTube/Extension/FirstName.php new file mode 100644 index 00000000..c577af57 --- /dev/null +++ b/Zend/Gdata/YouTube/Extension/FirstName.php @@ -0,0 +1,51 @@ +registerAllNamespaces(Zend_Gdata_YouTube::$namespaces); + parent::__construct(); + $this->_text = $text; + } + +} diff --git a/Zend/Gdata/YouTube/Extension/Gender.php b/Zend/Gdata/YouTube/Extension/Gender.php new file mode 100644 index 00000000..ce5f79a9 --- /dev/null +++ b/Zend/Gdata/YouTube/Extension/Gender.php @@ -0,0 +1,51 @@ +registerAllNamespaces(Zend_Gdata_YouTube::$namespaces); + parent::__construct(); + $this->_text = $text; + } + +} diff --git a/Zend/Gdata/YouTube/Extension/Hobbies.php b/Zend/Gdata/YouTube/Extension/Hobbies.php new file mode 100644 index 00000000..4916edc3 --- /dev/null +++ b/Zend/Gdata/YouTube/Extension/Hobbies.php @@ -0,0 +1,51 @@ +registerAllNamespaces(Zend_Gdata_YouTube::$namespaces); + parent::__construct(); + $this->_text = $text; + } + +} diff --git a/Zend/Gdata/YouTube/Extension/Hometown.php b/Zend/Gdata/YouTube/Extension/Hometown.php new file mode 100644 index 00000000..7c281680 --- /dev/null +++ b/Zend/Gdata/YouTube/Extension/Hometown.php @@ -0,0 +1,51 @@ +registerAllNamespaces(Zend_Gdata_YouTube::$namespaces); + parent::__construct(); + $this->_text = $text; + } + +} diff --git a/Zend/Gdata/YouTube/Extension/LastName.php b/Zend/Gdata/YouTube/Extension/LastName.php new file mode 100644 index 00000000..a9a3aa8d --- /dev/null +++ b/Zend/Gdata/YouTube/Extension/LastName.php @@ -0,0 +1,51 @@ +registerAllNamespaces(Zend_Gdata_YouTube::$namespaces); + parent::__construct(); + $this->_text = $text; + } + +} diff --git a/Zend/Gdata/YouTube/Extension/Link.php b/Zend/Gdata/YouTube/Extension/Link.php new file mode 100644 index 00000000..c05b6920 --- /dev/null +++ b/Zend/Gdata/YouTube/Extension/Link.php @@ -0,0 +1,133 @@ +registerAllNamespaces(Zend_Gdata_YouTube::$namespaces); + parent::__construct($href, $rel, $type, $hrefLang, $title, $length); + $this->_token = $token; + } + + /** + * Retrieves a DOMElement which corresponds to this element and all + * child properties. This is used to build an entry back into a DOM + * and eventually XML text for sending to the server upon updates, or + * for application storage/persistence. + * + * @param DOMDocument $doc The DOMDocument used to construct DOMElements + * @return DOMElement The DOMElement representing this element and all + * child properties. + */ + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc, $majorVersion, $minorVersion); + if ($this->_token != null) { + $element->appendChild($this->_token->getDOM($element->ownerDocument)); + } + return $element; + } + + /** + * Creates individual Entry objects of the appropriate type and + * stores them as members of this entry based upon DOM data. + * + * @param DOMNode $child The DOMNode to process + */ + protected function takeChildFromDOM($child) + { + $absoluteNodeName = $child->namespaceURI . ':' . $child->localName; + switch ($absoluteNodeName) { + case $this->lookupNamespace('yt') . ':' . 'token': + $token = new Zend_Gdata_YouTube_Extension_Token(); + $token->transferFromDOM($child); + $this->_token = $token; + break; + default: + parent::takeChildFromDOM($child); + break; + } + } + + /** + * Get the value for this element's token attribute. + * + * @return Zend_Gdata_YouTube_Extension_Token The token element. + */ + public function getToken() + { + return $this->_token; + } + + /** + * Set the value for this element's token attribute. + * + * @param Zend_Gdata_YouTube_Extension_Token $value The desired value for this attribute. + * @return Zend_YouTube_Extension_Link The element being modified. + */ + public function setToken($value) + { + $this->_token = $value; + return $this; + } + + /** + * Get the value of this element's token attribute. + * + * @return string The token's text value + */ + public function getTokenValue() + { + return $this->getToken()->getText(); + } + +} diff --git a/Zend/Gdata/YouTube/Extension/Location.php b/Zend/Gdata/YouTube/Extension/Location.php new file mode 100644 index 00000000..d355bb26 --- /dev/null +++ b/Zend/Gdata/YouTube/Extension/Location.php @@ -0,0 +1,51 @@ +registerAllNamespaces(Zend_Gdata_YouTube::$namespaces); + parent::__construct(); + $this->_text = $text; + } + +} diff --git a/Zend/Gdata/YouTube/Extension/MediaContent.php b/Zend/Gdata/YouTube/Extension/MediaContent.php new file mode 100644 index 00000000..50e5d4fc --- /dev/null +++ b/Zend/Gdata/YouTube/Extension/MediaContent.php @@ -0,0 +1,120 @@ +registerAllNamespaces(Zend_Gdata_YouTube::$namespaces); + parent::__construct(); + } + + /** + * Retrieves a DOMElement which corresponds to this element and all + * child properties. This is used to build an entry back into a DOM + * and eventually XML text for sending to the server upon updates, or + * for application storage/persistence. + * + * @param DOMDocument $doc The DOMDocument used to construct DOMElements + * @return DOMElement The DOMElement representing this element and all + * child properties. + */ + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc, $majorVersion, $minorVersion); + if ($this->_format!= null) { + $element->setAttributeNS($this->lookupNamespace('yt'), 'yt:format', $this->_format); + } + return $element; + } + + /** + * Given a DOMNode representing an attribute, tries to map the data into + * instance members. If no mapping is defined, the name and value are + * stored in an array. + * + * @param DOMNode $attribute The DOMNode attribute needed to be handled + */ + protected function takeAttributeFromDOM($attribute) + { + $absoluteAttrName = $attribute->namespaceURI . ':' . $attribute->localName; + if ($absoluteAttrName == $this->lookupNamespace('yt') . ':' . 'format') { + $this->_format = $attribute->nodeValue; + } else { + parent::takeAttributeFromDOM($attribute); + } + } + + /** + * Returns the format of the media + * Optional. + * + * @return int The format of the media + */ + public function getFormat() + { + return $this->_format; + } + + /** + * Sets the format of the media + * + * @param int $value Format of the media + * @return Zend_Gdata_YouTube_Extension_MediaContent Provides a fluent interface + * + */ + public function setFormat($value) + { + $this->_format = $value; + return $this; + } + +} diff --git a/Zend/Gdata/YouTube/Extension/MediaCredit.php b/Zend/Gdata/YouTube/Extension/MediaCredit.php new file mode 100644 index 00000000..5831dad2 --- /dev/null +++ b/Zend/Gdata/YouTube/Extension/MediaCredit.php @@ -0,0 +1,189 @@ +registerAllNamespaces(Zend_Gdata_Media::$namespaces); + parent::__construct(); + $this->_text = $text; + $this->_role = $role; + $this->_scheme = $scheme; + $this->_yttype = $yttype; + } + + /** + * Retrieves a DOMElement which corresponds to this element and all + * child properties. This is used to build an entry back into a DOM + * and eventually XML text for sending to the server upon updates, or + * for application storage/persistence. + * + * @param DOMDocument $doc The DOMDocument used to construct DOMElements + * @return DOMElement The DOMElement representing this element and all + * child properties. + */ + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc, $majorVersion, $minorVersion); + if ($this->_role !== null) { + $element->setAttribute('role', $this->_role); + } + if ($this->_scheme !== null) { + $element->setAttribute('scheme', $this->_scheme); + } + if ($this->_yttype !== null) { + $element->setAttributeNS('http://gdata.youtube.com/schemas/2007', + 'yt:type', $this->_yttype); + } + return $element; + } + + /** + * Given a DOMNode representing an attribute, tries to map the data into + * instance members. If no mapping is defined, the name and value are + * stored in an array. + * + * @param DOMNode $attribute The DOMNode attribute needed to be handled + */ + protected function takeAttributeFromDOM($attribute) + { + switch ($attribute->localName) { + case 'role': + $this->_role = $attribute->nodeValue; + break; + case 'scheme': + $this->_scheme = $attribute->nodeValue; + break; + case 'type': + $this->_yttype = $attribute->nodeValue; + break; + default: + parent::takeAttributeFromDOM($attribute); + } + } + + /** + * @return string + */ + public function getRole() + { + return $this->_role; + } + + /** + * @param string $value + * @return Zend_Gdata_Media_Extension_MediaCredit Provides a fluent + * interface + */ + public function setRole($value) + { + $this->_role = $value; + return $this; + } + + /** + * @return string + */ + public function getScheme() + { + return $this->_scheme; + } + + /** + * @param string $value + * @return Zend_Gdata_Media_Extension_MediaCredit Provides a fluent + * interface + */ + public function setScheme($value) + { + $this->_scheme = $value; + return $this; + } + + /** + * @return string + */ + public function getYTtype() + { + return $this->_yttype; + } + + /** + * @param string $value + * @return Zend_Gdata_Media_Extension_MediaCredit Provides a fluent + * interface + */ + public function setYTtype($value) + { + $this->_yttype = $value; + return $this; + } + +} diff --git a/Zend/Gdata/YouTube/Extension/MediaGroup.php b/Zend/Gdata/YouTube/Extension/MediaGroup.php new file mode 100644 index 00000000..e630cb18 --- /dev/null +++ b/Zend/Gdata/YouTube/Extension/MediaGroup.php @@ -0,0 +1,336 @@ +registerAllNamespaces(Zend_Gdata_YouTube::$namespaces); + parent::__construct($element); + } + + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc, $majorVersion, $minorVersion); + if ($this->_duration !== null) { + $element->appendChild( + $this->_duration->getDOM($element->ownerDocument)); + } + if ($this->_private !== null) { + $element->appendChild( + $this->_private->getDOM($element->ownerDocument)); + } + if ($this->_videoid != null) { + $element->appendChild( + $this->_videoid->getDOM($element->ownerDocument)); + } + if ($this->_uploaded != null) { + $element->appendChild( + $this->_uploaded->getDOM($element->ownerDocument)); + } + if ($this->_mediacredit != null) { + $element->appendChild( + $this->_mediacredit->getDOM($element->ownerDocument)); + } + if ($this->_mediarating != null) { + $element->appendChild( + $this->_mediarating->getDOM($element->ownerDocument)); + } + return $element; + } + + /** + * Creates individual Entry objects of the appropriate type and + * stores them in the $_entry array based upon DOM data. + * + * @param DOMNode $child The DOMNode to process + */ + protected function takeChildFromDOM($child) + { + $absoluteNodeName = $child->namespaceURI . ':' . $child->localName; + switch ($absoluteNodeName) { + case $this->lookupNamespace('media') . ':' . 'content': + $content = new Zend_Gdata_YouTube_Extension_MediaContent(); + $content->transferFromDOM($child); + $this->_content[] = $content; + break; + case $this->lookupNamespace('media') . ':' . 'rating': + $mediarating = new Zend_Gdata_YouTube_Extension_MediaRating(); + $mediarating->transferFromDOM($child); + $this->_mediarating = $mediarating; + break; + case $this->lookupNamespace('media') . ':' . 'credit': + $mediacredit = new Zend_Gdata_YouTube_Extension_MediaCredit(); + $mediacredit->transferFromDOM($child); + $this->_mediacredit = $mediacredit; + break; + case $this->lookupNamespace('yt') . ':' . 'duration': + $duration = new Zend_Gdata_YouTube_Extension_Duration(); + $duration->transferFromDOM($child); + $this->_duration = $duration; + break; + case $this->lookupNamespace('yt') . ':' . 'private': + $private = new Zend_Gdata_YouTube_Extension_Private(); + $private->transferFromDOM($child); + $this->_private = $private; + break; + case $this->lookupNamespace('yt') . ':' . 'videoid': + $videoid = new Zend_Gdata_YouTube_Extension_VideoId(); + $videoid ->transferFromDOM($child); + $this->_videoid = $videoid; + break; + case $this->lookupNamespace('yt') . ':' . 'uploaded': + $uploaded = new Zend_Gdata_YouTube_Extension_Uploaded(); + $uploaded ->transferFromDOM($child); + $this->_uploaded = $uploaded; + break; + default: + parent::takeChildFromDOM($child); + break; + } + } + + /** + * Returns the duration value of this element + * + * @return Zend_Gdata_YouTube_Extension_Duration + */ + public function getDuration() + { + return $this->_duration; + } + + /** + * Sets the duration value of this element + * + * @param Zend_Gdata_YouTube_Extension_Duration $value The duration value + * @return Zend_Gdata_YouTube_Extension_MediaGroup Provides a fluent + * interface + */ + public function setDuration($value) + { + $this->_duration = $value; + return $this; + } + + /** + * Returns the videoid value of this element + * + * @return Zend_Gdata_YouTube_Extension_VideoId + */ + public function getVideoId() + { + return $this->_videoid; + } + + /** + * Sets the videoid value of this element + * + * @param Zend_Gdata_YouTube_Extension_VideoId $value The video id value + * @return Zend_Gdata_YouTube_Extension_MediaGroup Provides a fluent + * interface + */ + public function setVideoId($value) + { + $this->_videoid = $value; + return $this; + } + + /** + * Returns the yt:uploaded element + * + * @return Zend_Gdata_YouTube_Extension_Uploaded + */ + public function getUploaded() + { + return $this->_uploaded; + } + + /** + * Sets the yt:uploaded element + * + * @param Zend_Gdata_YouTube_Extension_Uploaded $value The uploaded value + * @return Zend_Gdata_YouTube_Extension_MediaGroup Provides a fluent + * interface + */ + public function setUploaded($value) + { + $this->_uploaded = $value; + return $this; + } + + /** + * Returns the private value of this element + * + * @return Zend_Gdata_YouTube_Extension_Private + */ + public function getPrivate() + { + return $this->_private; + } + + /** + * Sets the private value of this element + * + * @param Zend_Gdata_YouTube_Extension_Private $value The private value + * @return Zend_Gdata_YouTube_Extension_MediaGroup Provides a fluent + * interface + */ + public function setPrivate($value) + { + $this->_private = $value; + return $this; + } + + /** + * Returns the rating value of this element + * + * @return Zend_Gdata_YouTube_Extension_MediaRating + */ + public function getMediaRating() + { + return $this->_mediarating; + } + + /** + * Sets the media:rating value of this element + * + * @param Zend_Gdata_YouTube_Extension_MediaRating $value The rating element + * @return Zend_Gdata_YouTube_Extension_MediaGroup Provides a fluent + * interface + */ + public function setMediaRating($value) + { + $this->_mediarating = $value; + return $this; + } + + /** + * Returns the media:credit value of this element + * + * @return Zend_Gdata_YouTube_Extension_MediaCredit + */ + public function getMediaCredit() + { + return $this->_mediacredit; + } + + /** + * Sets the media:credit value of this element + * + * @param Zend_Gdata_YouTube_Extension_MediaCredit $value The credit element + * @return Zend_Gdata_YouTube_Extension_MediaGroup Provides a fluent + * interface + */ + public function setMediaCredit($value) + { + $this->_mediacredit = $value; + return $this; + } +} diff --git a/Zend/Gdata/YouTube/Extension/MediaRating.php b/Zend/Gdata/YouTube/Extension/MediaRating.php new file mode 100644 index 00000000..50e0309e --- /dev/null +++ b/Zend/Gdata/YouTube/Extension/MediaRating.php @@ -0,0 +1,150 @@ +registerAllNamespaces(Zend_Gdata_Media::$namespaces); + parent::__construct(); + $this->_scheme = $scheme; + $this->_country = $country; + $this->_text = $text; + } + + /** + * Retrieves a DOMElement which corresponds to this element and all + * child properties. This is used to build an entry back into a DOM + * and eventually XML text for sending to the server upon updates, or + * for application storage/persistence. + * + * @param DOMDocument $doc The DOMDocument used to construct DOMElements + * @return DOMElement The DOMElement representing this element and all + * child properties. + */ + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc, $majorVersion, $minorVersion); + if ($this->_scheme !== null) { + $element->setAttribute('scheme', $this->_scheme); + } + if ($this->_country != null) { + $element->setAttribute('country', $this->_country); + } + return $element; + } + + /** + * Given a DOMNode representing an attribute, tries to map the data into + * instance members. If no mapping is defined, the name and value are + * stored in an array. + * + * @param DOMNode $attribute The DOMNode attribute needed to be handled + */ + protected function takeAttributeFromDOM($attribute) + { + switch ($attribute->localName) { + case 'scheme': + $this->_scheme = $attribute->nodeValue; + break; + case 'country': + $this->_country = $attribute->nodeValue; + break; + default: + parent::takeAttributeFromDOM($attribute); + } + } + + /** + * @return string + */ + public function getScheme() + { + return $this->_scheme; + } + + /** + * @param string $value + * @return Zend_Gdata_YouTube_Extension_MediaRating Provides a fluent interface + */ + public function setScheme($value) + { + $this->_scheme = $value; + return $this; + } + + /** + * @return string + */ + public function getCountry() + { + return $this->_country; + } + + /** + * @param string $value + * @return Zend_Gdata_YouTube_Extension_MediaRating Provides a fluent interface + */ + public function setCountry($value) + { + $this->_country = $value; + return $this; + } + + +} diff --git a/Zend/Gdata/YouTube/Extension/Movies.php b/Zend/Gdata/YouTube/Extension/Movies.php new file mode 100644 index 00000000..dd0cb986 --- /dev/null +++ b/Zend/Gdata/YouTube/Extension/Movies.php @@ -0,0 +1,51 @@ +registerAllNamespaces(Zend_Gdata_YouTube::$namespaces); + parent::__construct(); + $this->_text = $text; + } + +} diff --git a/Zend/Gdata/YouTube/Extension/Music.php b/Zend/Gdata/YouTube/Extension/Music.php new file mode 100644 index 00000000..1d0e6c01 --- /dev/null +++ b/Zend/Gdata/YouTube/Extension/Music.php @@ -0,0 +1,51 @@ +registerAllNamespaces(Zend_Gdata_YouTube::$namespaces); + parent::__construct(); + $this->_text = $text; + } + +} diff --git a/Zend/Gdata/YouTube/Extension/NoEmbed.php b/Zend/Gdata/YouTube/Extension/NoEmbed.php new file mode 100644 index 00000000..28f732ea --- /dev/null +++ b/Zend/Gdata/YouTube/Extension/NoEmbed.php @@ -0,0 +1,54 @@ +registerAllNamespaces(Zend_Gdata_YouTube::$namespaces); + parent::__construct(); + } + +} diff --git a/Zend/Gdata/YouTube/Extension/Occupation.php b/Zend/Gdata/YouTube/Extension/Occupation.php new file mode 100644 index 00000000..a49ccd55 --- /dev/null +++ b/Zend/Gdata/YouTube/Extension/Occupation.php @@ -0,0 +1,51 @@ +registerAllNamespaces(Zend_Gdata_YouTube::$namespaces); + parent::__construct(); + $this->_text = $text; + } + +} diff --git a/Zend/Gdata/YouTube/Extension/PlaylistId.php b/Zend/Gdata/YouTube/Extension/PlaylistId.php new file mode 100644 index 00000000..266493a3 --- /dev/null +++ b/Zend/Gdata/YouTube/Extension/PlaylistId.php @@ -0,0 +1,51 @@ +registerAllNamespaces(Zend_Gdata_YouTube::$namespaces); + parent::__construct(); + $this->_text = $text; + } + +} diff --git a/Zend/Gdata/YouTube/Extension/PlaylistTitle.php b/Zend/Gdata/YouTube/Extension/PlaylistTitle.php new file mode 100644 index 00000000..896decbb --- /dev/null +++ b/Zend/Gdata/YouTube/Extension/PlaylistTitle.php @@ -0,0 +1,51 @@ +registerAllNamespaces(Zend_Gdata_YouTube::$namespaces); + parent::__construct(); + $this->_text = $text; + } + +} diff --git a/Zend/Gdata/YouTube/Extension/Position.php b/Zend/Gdata/YouTube/Extension/Position.php new file mode 100644 index 00000000..07a8b532 --- /dev/null +++ b/Zend/Gdata/YouTube/Extension/Position.php @@ -0,0 +1,90 @@ +registerAllNamespaces(Zend_Gdata_YouTube::$namespaces); + parent::__construct(); + $this->_text = $value; + } + + /** + * Get the value for the position in the playlist + * + * @return int The 1-based position in the playlist + */ + public function getValue() + { + return $this->_text; + } + + /** + * Set the value for the position in the playlist + * + * @param int $value The 1-based position in the playlist + * @return Zend_Gdata_Extension_Visibility The element being modified + */ + public function setValue($value) + { + $this->_text = $value; + return $this; + } + + /** + * Magic toString method allows using this directly via echo + * Works best in PHP >= 4.2.0 + * + * @return string + */ + public function __toString() + { + return $this->getValue(); + } + +} + diff --git a/Zend/Gdata/YouTube/Extension/Private.php b/Zend/Gdata/YouTube/Extension/Private.php new file mode 100644 index 00000000..469feb78 --- /dev/null +++ b/Zend/Gdata/YouTube/Extension/Private.php @@ -0,0 +1,81 @@ +registerAllNamespaces(Zend_Gdata_YouTube::$namespaces); + parent::__construct(); + } + + /** + * Retrieves a DOMElement which corresponds to this element and all + * child properties. This is used to build an entry back into a DOM + * and eventually XML text for sending to the server upon updates, or + * for application storage/persistence. + * + * @param DOMDocument $doc The DOMDocument used to construct DOMElements + * @return DOMElement The DOMElement representing this element and all + * child properties. + */ + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc, $majorVersion, $minorVersion); + return $element; + } + + /** + * Given a DOMNode representing an attribute, tries to map the data into + * instance members. If no mapping is defined, the name and valueare + * stored in an array. + * + * @param DOMNode $attribute The DOMNode attribute needed to be handled + */ + protected function takeAttributeFromDOM($attribute) + { + parent::takeAttributeFromDOM($attribute); + } + +} diff --git a/Zend/Gdata/YouTube/Extension/QueryString.php b/Zend/Gdata/YouTube/Extension/QueryString.php new file mode 100644 index 00000000..8d4b2ba9 --- /dev/null +++ b/Zend/Gdata/YouTube/Extension/QueryString.php @@ -0,0 +1,51 @@ +registerAllNamespaces(Zend_Gdata_YouTube::$namespaces); + parent::__construct(); + $this->_text = $text; + } + +} diff --git a/Zend/Gdata/YouTube/Extension/Racy.php b/Zend/Gdata/YouTube/Extension/Racy.php new file mode 100644 index 00000000..408fb77d --- /dev/null +++ b/Zend/Gdata/YouTube/Extension/Racy.php @@ -0,0 +1,124 @@ +registerAllNamespaces(Zend_Gdata_YouTube::$namespaces); + parent::__construct(); + $this->_state = $state; + } + + /** + * Retrieves a DOMElement which corresponds to this element and all + * child properties. This is used to build an entry back into a DOM + * and eventually XML text for sending to the server upon updates, or + * for application storage/persistence. + * + * @param DOMDocument $doc The DOMDocument used to construct DOMElements + * @return DOMElement The DOMElement representing this element and all + * child properties. + */ + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc, $majorVersion, $minorVersion); + if ($this->_state !== null) { + $element->setAttribute('state', $this->_state); + } + return $element; + } + + /** + * Given a DOMNode representing an attribute, tries to map the data into + * instance members. If no mapping is defined, the name and value are + * stored in an array. + * + * @param DOMNode $attribute The DOMNode attribute needed to be handled + */ + protected function takeAttributeFromDOM($attribute) + { + switch ($attribute->localName) { + case 'state': + $this->_state = $attribute->nodeValue; + break; + default: + parent::takeAttributeFromDOM($attribute); + } + } + + /** + * Get the value for this element's state attribute. + * + * @return bool The value associated with this attribute. + */ + public function getState() + { + return $this->_state; + } + + /** + * Set the value for this element's state attribute. + * + * @param bool $value The desired value for this attribute. + * @return Zend_Gdata_YouTube_Extension_Racy The element being modified. + */ + public function setState($value) + { + $this->_state = $value; + return $this; + } + + /** + * Magic toString method allows using this directly via echo + * Works best in PHP >= 4.2.0 + */ + public function __toString() + { + return $this->_state; + } + +} diff --git a/Zend/Gdata/YouTube/Extension/Recorded.php b/Zend/Gdata/YouTube/Extension/Recorded.php new file mode 100644 index 00000000..20363641 --- /dev/null +++ b/Zend/Gdata/YouTube/Extension/Recorded.php @@ -0,0 +1,51 @@ +registerAllNamespaces(Zend_Gdata_YouTube::$namespaces); + parent::__construct(); + $this->_text = $text; + } + +} diff --git a/Zend/Gdata/YouTube/Extension/Relationship.php b/Zend/Gdata/YouTube/Extension/Relationship.php new file mode 100644 index 00000000..e2e09369 --- /dev/null +++ b/Zend/Gdata/YouTube/Extension/Relationship.php @@ -0,0 +1,51 @@ +registerAllNamespaces(Zend_Gdata_YouTube::$namespaces); + parent::__construct(); + $this->_text = $text; + } + +} diff --git a/Zend/Gdata/YouTube/Extension/ReleaseDate.php b/Zend/Gdata/YouTube/Extension/ReleaseDate.php new file mode 100644 index 00000000..a0658086 --- /dev/null +++ b/Zend/Gdata/YouTube/Extension/ReleaseDate.php @@ -0,0 +1,51 @@ +registerAllNamespaces(Zend_Gdata_YouTube::$namespaces); + parent::__construct(); + $this->_text = $text; + } + +} diff --git a/Zend/Gdata/YouTube/Extension/School.php b/Zend/Gdata/YouTube/Extension/School.php new file mode 100644 index 00000000..a922917f --- /dev/null +++ b/Zend/Gdata/YouTube/Extension/School.php @@ -0,0 +1,51 @@ +registerAllNamespaces(Zend_Gdata_YouTube::$namespaces); + parent::__construct(); + $this->_text = $text; + } + +} diff --git a/Zend/Gdata/YouTube/Extension/State.php b/Zend/Gdata/YouTube/Extension/State.php new file mode 100644 index 00000000..7215a996 --- /dev/null +++ b/Zend/Gdata/YouTube/Extension/State.php @@ -0,0 +1,193 @@ +registerAllNamespaces(Zend_Gdata_YouTube::$namespaces); + parent::__construct(); + $this->_text = $explanation; + $this->_name = $name; + $this->_reasonCode = $reasonCode; + $this->_helpUrl = $reasonCode; + } + + /** + * Retrieves a DOMElement which corresponds to this element and all + * child properties. This is used to build an entry back into a DOM + * and eventually XML text for sending to the server upon updates, or + * for application storage/persistence. + * + * @param DOMDocument $doc The DOMDocument used to construct DOMElements + * @return DOMElement The DOMElement representing this element and all + * child properties. + */ + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc, $majorVersion, $minorVersion); + if ($this->_name !== null) { + $element->setAttribute('name', $this->_name); + } + if ($this->_reasonCode !== null) { + $element->setAttribute('reasonCode', $this->_reasonCode); + } + if ($this->_helpUrl !== null) { + $element->setAttribute('helpUrl', $this->_helpUrl); + } + return $element; + } + + /** + * Given a DOMNode representing an attribute, tries to map the data into + * instance members. If no mapping is defined, the name and valueare + * stored in an array. + * TODO: Convert attributes to proper types + * + * @param DOMNode $attribute The DOMNode attribute needed to be handled + */ + protected function takeAttributeFromDOM($attribute) + { + switch ($attribute->localName) { + case 'name': + $this->_name = $attribute->nodeValue; + break; + case 'reasonCode': + $this->_reasonCode = $attribute->nodeValue; + break; + case 'helpUrl': + $this->_helpUrl = $attribute->nodeValue; + break; + default: + parent::takeAttributeFromDOM($attribute); + } + } + + /** + * Get the value for this element's name attribute. + * + * @return int The value associated with this attribute. + */ + public function getName() + { + return $this->_name; + } + + /** + * Set the value for this element's name attribute. + * + * @param int $value The desired value for this attribute. + * @return Zend_Gdata_YouTube_Extension_State The element being modified. + */ + public function setName($value) + { + $this->_name = $value; + return $this; + } + + /** + * Get the value for this element's reasonCode attribute. + * + * @return int The value associated with this attribute. + */ + public function getReasonCode() + { + return $this->_reasonCode; + } + + /** + * Set the value for this element's reasonCode attribute. + * + * @param int $value The desired value for this attribute. + * @return Zend_Gdata_YouTube_Extension_State The element being modified. + */ + public function setReasonCode($value) + { + $this->_reasonCode = $value; + return $this; + } + + /** + * Get the value for this element's helpUrl attribute. + * + * @return int The value associated with this attribute. + */ + public function getHelpUrl() + { + return $this->_helpUrl; + } + + /** + * Set the value for this element's helpUrl attribute. + * + * @param int $value The desired value for this attribute. + * @return Zend_Gdata_YouTube_Extension_State The element being modified. + */ + public function setHelpUrl($value) + { + $this->_helpUrl = $value; + return $this; + } + + /** + * Magic toString method allows using this directly via echo + * Works best in PHP >= 4.2.0 + * + * @return string + */ + public function __toString() + { + return $this->_text; + } + +} diff --git a/Zend/Gdata/YouTube/Extension/Statistics.php b/Zend/Gdata/YouTube/Extension/Statistics.php new file mode 100644 index 00000000..23598d80 --- /dev/null +++ b/Zend/Gdata/YouTube/Extension/Statistics.php @@ -0,0 +1,309 @@ + tag appears within a + * user profile entry. + * + * @var integer + */ + protected $_videoWatchCount = null; + + /** + * When the viewCount attribute refers to a video entry, the attribute + * specifies the number of times that the video has been viewed. + * When the viewCount attribute refers to a user profile, the attribute + * specifies the number of times that the user's profile has been + * viewed. + * + * @var integer + */ + protected $_viewCount = null; + + /** + * The subscriberCount attribute specifies the number of YouTube users + * who have subscribed to a particular user's YouTube channel. + * The subscriberCount attribute is only specified when the + * tag appears within a user profile entry. + * + * @var integer + */ + protected $_subscriberCount = null; + + /** + * The lastWebAccess attribute indicates the most recent time that + * a particular user used YouTube. + * + * @var string + */ + protected $_lastWebAccess = null; + + /** + * The favoriteCount attribute specifies the number of YouTube users + * who have added a video to their list of favorite videos. The + * favoriteCount attribute is only specified when the + * tag appears within a video entry. + * + * @var integer + */ + protected $_favoriteCount = null; + + /** + * Constructs a new Zend_Gdata_YouTube_Extension_Statistics object. + * @param string $viewCount(optional) The viewCount value + * @param string $videoWatchCount(optional) The videoWatchCount value + * @param string $subscriberCount(optional) The subscriberCount value + * @param string $lastWebAccess(optional) The lastWebAccess value + * @param string $favoriteCount(optional) The favoriteCount value + */ + public function __construct($viewCount = null, $videoWatchCount = null, + $subscriberCount = null, $lastWebAccess = null, + $favoriteCount = null) + { + $this->registerAllNamespaces(Zend_Gdata_YouTube::$namespaces); + parent::__construct(); + $this->_viewCount = $viewCount; + $this->_videoWatchCount = $videoWatchCount; + $this->_subscriberCount = $subscriberCount; + $this->_lastWebAccess = $lastWebAccess; + $this->_favoriteCount = $favoriteCount; + } + + /** + * Retrieves a DOMElement which corresponds to this element and all + * child properties. This is used to build an entry back into a DOM + * and eventually XML text for sending to the server upon updates, or + * for application storage/persistence. + * + * @param DOMDocument $doc The DOMDocument used to construct DOMElements + * @return DOMElement The DOMElement representing this element and all + * child properties. + */ + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc, $majorVersion, $minorVersion); + if ($this->_videoWatchCount !== null) { + $element->setAttribute('watchCount', $this->_videoWatchCount); + } + if ($this->_viewCount !== null) { + $element->setAttribute('viewCount', $this->_viewCount); + } + if ($this->_subscriberCount !== null) { + $element->setAttribute('subscriberCount', + $this->_subscriberCount); + } + if ($this->_lastWebAccess !== null) { + $element->setAttribute('lastWebAccess', + $this->_lastWebAccess); + } + if ($this->_favoriteCount !== null) { + $element->setAttribute('favoriteCount', + $this->_favoriteCount); + } + return $element; + } + + /** + * Given a DOMNode representing an attribute, tries to map the data into + * instance members. If no mapping is defined, the name and valueare + * stored in an array. + * TODO: Convert attributes to proper types + * + * @param DOMNode $attribute The DOMNode attribute needed to be handled + */ + protected function takeAttributeFromDOM($attribute) + { + switch ($attribute->localName) { + case 'videoWatchCount': + $this->_videoWatchCount = $attribute->nodeValue; + break; + case 'viewCount': + $this->_viewCount = $attribute->nodeValue; + break; + case 'subscriberCount': + $this->_subscriberCount = $attribute->nodeValue; + break; + case 'lastWebAccess': + $this->_lastWebAccess = $attribute->nodeValue; + break; + case 'favoriteCount': + $this->_favoriteCount = $attribute->nodeValue; + break; + default: + parent::takeAttributeFromDOM($attribute); + } + } + + /** + * Get the value for this element's viewCount attribute. + * + * @return int The value associated with this attribute. + */ + public function getViewCount() + { + return $this->_viewCount; + } + + /** + * Set the value for this element's viewCount attribute. + * + * @param int $value The desired value for this attribute. + * @return Zend_Gdata_YouTube_Extension_Statistics The element being + * modified. + */ + public function setViewCount($value) + { + $this->_viewCount = $value; + return $this; + } + + /** + * Get the value for this element's videoWatchCount attribute. + * + * @return int The value associated with this attribute. + */ + public function getVideoWatchCount() + { + return $this->_videoWatchCount; + } + + /** + * Set the value for this element's videoWatchCount attribute. + * + * @param int $value The desired value for this attribute. + * @return Zend_Gdata_YouTube_Extension_Statistics The element being + * modified. + */ + public function setVideoWatchCount($value) + { + $this->_videoWatchCount = $value; + return $this; + } + + /** + * Get the value for this element's subscriberCount attribute. + * + * @return int The value associated with this attribute. + */ + public function getSubscriberCount() + { + return $this->_subscriberCount; + } + + /** + * Set the value for this element's subscriberCount attribute. + * + * @param int $value The desired value for this attribute. + * @return Zend_Gdata_YouTube_Extension_Statistics The element being + * modified. + */ + public function setSubscriberCount($value) + { + $this->_subscriberCount = $value; + return $this; + } + + /** + * Get the value for this element's lastWebAccess attribute. + * + * @return int The value associated with this attribute. + */ + public function getLastWebAccess() + { + return $this->_lastWebAccess; + } + + /** + * Set the value for this element's lastWebAccess attribute. + * + * @param int $value The desired value for this attribute. + * @return Zend_Gdata_YouTube_Extension_Statistics The element being + * modified. + */ + public function setLastWebAccess($value) + { + $this->_lastWebAccess = $value; + return $this; + } + + /** + * Get the value for this element's favoriteCount attribute. + * + * @return int The value associated with this attribute. + */ + public function getFavoriteCount() + { + return $this->_favoriteCount; + } + + /** + * Set the value for this element's favoriteCount attribute. + * + * @param int $value The desired value for this attribute. + * @return Zend_Gdata_YouTube_Extension_Statistics The element being + * modified. + */ + public function setFavoriteCount($value) + { + $this->_favoriteCount = $value; + return $this; + } + + /** + * Magic toString method allows using this directly via echo + * Works best in PHP >= 4.2.0 + * + * @return string + */ + public function __toString() + { + return 'View Count=' . $this->_viewCount . + ' VideoWatchCount=' . $this->_videoWatchCount . + ' SubscriberCount=' . $this->_subscriberCount . + ' LastWebAccess=' . $this->_lastWebAccess . + ' FavoriteCount=' . $this->_favoriteCount; + } + +} diff --git a/Zend/Gdata/YouTube/Extension/Status.php b/Zend/Gdata/YouTube/Extension/Status.php new file mode 100644 index 00000000..d3690355 --- /dev/null +++ b/Zend/Gdata/YouTube/Extension/Status.php @@ -0,0 +1,51 @@ +registerAllNamespaces(Zend_Gdata_YouTube::$namespaces); + parent::__construct(); + $this->_text = $text; + } + +} diff --git a/Zend/Gdata/YouTube/Extension/Token.php b/Zend/Gdata/YouTube/Extension/Token.php new file mode 100644 index 00000000..c4b7b5d7 --- /dev/null +++ b/Zend/Gdata/YouTube/Extension/Token.php @@ -0,0 +1,70 @@ +registerAllNamespaces(Zend_Gdata_YouTube::$namespaces); + parent::__construct(); + $this->_text = $text; + } + + /** + * Retrieves a DOMElement which corresponds to this element and all + * child properties. This is used to build an entry back into a DOM + * and eventually XML text for sending to the server upon updates, or + * for application storage/persistence. + * + * @param DOMDocument $doc The DOMDocument used to construct DOMElements + * @return DOMElement The DOMElement representing this element and all + * child properties. + */ + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc, $majorVersion, $minorVersion); + return $element; + } + +} diff --git a/Zend/Gdata/YouTube/Extension/Uploaded.php b/Zend/Gdata/YouTube/Extension/Uploaded.php new file mode 100644 index 00000000..d23c6501 --- /dev/null +++ b/Zend/Gdata/YouTube/Extension/Uploaded.php @@ -0,0 +1,51 @@ +registerAllNamespaces(Zend_Gdata_YouTube::$namespaces); + parent::__construct(); + $this->_text = $text; + } + +} diff --git a/Zend/Gdata/YouTube/Extension/Username.php b/Zend/Gdata/YouTube/Extension/Username.php new file mode 100644 index 00000000..dacca105 --- /dev/null +++ b/Zend/Gdata/YouTube/Extension/Username.php @@ -0,0 +1,51 @@ +registerAllNamespaces(Zend_Gdata_YouTube::$namespaces); + parent::__construct(); + $this->_text = $text; + } + +} diff --git a/Zend/Gdata/YouTube/Extension/VideoId.php b/Zend/Gdata/YouTube/Extension/VideoId.php new file mode 100644 index 00000000..0a87fa37 --- /dev/null +++ b/Zend/Gdata/YouTube/Extension/VideoId.php @@ -0,0 +1,51 @@ +registerAllNamespaces(Zend_Gdata_YouTube::$namespaces); + parent::__construct(); + $this->_text = $text; + } + +} diff --git a/Zend/Gdata/YouTube/InboxEntry.php b/Zend/Gdata/YouTube/InboxEntry.php new file mode 100644 index 00000000..cdac634f --- /dev/null +++ b/Zend/Gdata/YouTube/InboxEntry.php @@ -0,0 +1,281 @@ +registerAllNamespaces(Zend_Gdata_YouTube::$namespaces); + parent::__construct($element); + } + + /** + * Retrieves a DOMElement which corresponds to this element and all + * child properties. This is used to build an entry back into a DOM + * and eventually XML text for sending to the server upon updates, or + * for application storage/persistence. + * + * @param DOMDocument $doc The DOMDocument used to construct DOMElements + * @return DOMElement The DOMElement representing this element and all + * child properties. + */ + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc, $majorVersion, $minorVersion); + if ($this->_description != null) { + $element->appendChild( + $this->_description->getDOM($element->ownerDocument)); + } + if ($this->_rating != null) { + $element->appendChild( + $this->_rating->getDOM($element->ownerDocument)); + } + if ($this->_statistics != null) { + $element->appendChild( + $this->_statistics->getDOM($element->ownerDocument)); + } + if ($this->_comments != null) { + $element->appendChild( + $this->_comments->getDOM($element->ownerDocument)); + } + return $element; + } + + /** + * Creates individual Entry objects of the appropriate type and + * stores them in the $_entry array based upon DOM data. + * + * @param DOMNode $child The DOMNode to process + */ + protected function takeChildFromDOM($child) + { + $absoluteNodeName = $child->namespaceURI . ':' . $child->localName; + switch ($absoluteNodeName) { + case $this->lookupNamespace('gd') . ':' . 'comments': + $comments = new Zend_Gdata_Extension_Comments(); + $comments->transferFromDOM($child); + $this->_comments = $comments; + break; + case $this->lookupNamespace('gd') . ':' . 'rating': + $rating = new Zend_Gdata_Extension_Rating(); + $rating->transferFromDOM($child); + $this->_rating = $rating; + break; + case $this->lookupNamespace('yt') . ':' . 'description': + $description = new Zend_Gdata_YouTube_Extension_Description(); + $description->transferFromDOM($child); + $this->_description = $description; + break; + case $this->lookupNamespace('yt') . ':' . 'statistics': + $statistics = new Zend_Gdata_YouTube_Extension_Statistics(); + $statistics->transferFromDOM($child); + $this->_statistics = $statistics; + break; + default: + parent::takeChildFromDOM($child); + break; + } + } + + /** + * Get the yt:description + * + * @throws Zend_Gdata_App_VersionException + * @return Zend_Gdata_YouTube_Extension_Description|null + */ + public function getDescription() + { + if ($this->getMajorProtocolVersion() == 2) { + require_once 'Zend/Gdata/App/VersionException.php'; + throw new Zend_Gdata_App_VersionException('The getDescription ' . + ' method is only supported in version 1 of the YouTube ' . + 'API.'); + } else { + return $this->_description; + } + } + + /** + * Sets the yt:description element for a new inbox entry. + * + * @param Zend_Gdata_YouTube_Extension_Description $description The + * description. + * @throws Zend_Gdata_App_VersionException + * @return Zend_Gdata_YouTube_InboxEntry Provides a fluent interface + */ + public function setDescription($description = null) + { + if ($this->getMajorProtocolVersion() == 2) { + require_once 'Zend/Gdata/App/VersionException.php'; + throw new Zend_Gdata_App_VersionException('The setDescription ' . + ' method is only supported in version 1 of the YouTube ' . + 'API.'); + } else { + $this->_description = $description; + return $this; + } + } + + /** + * Get the gd:rating element for the inbox entry + * + * @return Zend_Gdata_Extension_Rating|null + */ + public function getRating() + { + return $this->_rating; + } + + /** + * Sets the gd:rating element for the inbox entry + * + * @param Zend_Gdata_Extension_Rating $rating The rating for the video in + * the message + * @return Zend_Gdata_YouTube_InboxEntry Provides a fluent interface + */ + public function setRating($rating = null) + { + $this->_rating = $rating; + return $this; + } + + /** + * Get the gd:comments element of the inbox entry. + * + * @return Zend_Gdata_Extension_Comments|null + */ + public function getComments() + { + return $this->_comments; + } + + /** + * Sets the gd:comments element for the inbox entry + * + * @param Zend_Gdata_Extension_Comments $comments The comments feed link + * @return Zend_Gdata_YouTube_InboxEntry Provides a fluent interface + */ + public function setComments($comments = null) + { + $this->_comments = $comments; + return $this; + } + + /** + * Get the yt:statistics element for the inbox entry + * + * @return Zend_Gdata_YouTube_Extension_Statistics|null + */ + public function getStatistics() + { + return $this->_statistics; + } + + /** + * Sets the yt:statistics element for the inbox entry + * + * @param Zend_Gdata_YouTube_Extension_Statistics $statistics The + * statistics element for the video in the message + * @return Zend_Gdata_YouTube_InboxEntry Provides a fluent interface + */ + public function setStatistics($statistics = null) + { + $this->_statistics = $statistics; + return $this; + } + + +} diff --git a/Zend/Gdata/YouTube/InboxFeed.php b/Zend/Gdata/YouTube/InboxFeed.php new file mode 100644 index 00000000..79ae87b1 --- /dev/null +++ b/Zend/Gdata/YouTube/InboxFeed.php @@ -0,0 +1,68 @@ +registerAllNamespaces(Zend_Gdata_YouTube::$namespaces); + parent::__construct($element); + } + +} diff --git a/Zend/Gdata/YouTube/MediaEntry.php b/Zend/Gdata/YouTube/MediaEntry.php new file mode 100644 index 00000000..b193ae60 --- /dev/null +++ b/Zend/Gdata/YouTube/MediaEntry.php @@ -0,0 +1,81 @@ +namespaceURI . ':' . $child->localName; + switch ($absoluteNodeName) { + case $this->lookupNamespace('media') . ':' . 'group': + $mediaGroup = new Zend_Gdata_YouTube_Extension_MediaGroup(); + $mediaGroup->transferFromDOM($child); + $this->_mediaGroup = $mediaGroup; + break; + default: + parent::takeChildFromDOM($child); + break; + } + } + +} diff --git a/Zend/Gdata/YouTube/PlaylistListEntry.php b/Zend/Gdata/YouTube/PlaylistListEntry.php new file mode 100644 index 00000000..196533bf --- /dev/null +++ b/Zend/Gdata/YouTube/PlaylistListEntry.php @@ -0,0 +1,300 @@ +registerAllNamespaces(Zend_Gdata_YouTube::$namespaces); + parent::__construct($element); + } + + /** + * Retrieves a DOMElement which corresponds to this element and all + * child properties. This is used to build an entry back into a DOM + * and eventually XML text for sending to the server upon updates, or + * for application storage/persistence. + * + * @param DOMDocument $doc The DOMDocument used to construct DOMElements + * @return DOMElement The DOMElement representing this element and all + * child properties. + */ + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc, $majorVersion, $minorVersion); + if ($this->_description != null) { + $element->appendChild($this->_description->getDOM($element->ownerDocument)); + } + if ($this->_countHint != null) { + $element->appendChild($this->_countHint->getDOM($element->ownerDocument)); + } + if ($this->_playlistId != null) { + $element->appendChild($this->_playlistId->getDOM($element->ownerDocument)); + } + if ($this->_feedLink != null) { + foreach ($this->_feedLink as $feedLink) { + $element->appendChild($feedLink->getDOM($element->ownerDocument)); + } + } + return $element; + } + + /** + * Creates individual Entry objects of the appropriate type and + * stores them in the $_entry array based upon DOM data. + * + * @param DOMNode $child The DOMNode to process + */ + protected function takeChildFromDOM($child) + { + $absoluteNodeName = $child->namespaceURI . ':' . $child->localName; + switch ($absoluteNodeName) { + case $this->lookupNamespace('yt') . ':' . 'description': + $description = new Zend_Gdata_YouTube_Extension_Description(); + $description->transferFromDOM($child); + $this->_description = $description; + break; + case $this->lookupNamespace('yt') . ':' . 'countHint': + $countHint = new Zend_Gdata_YouTube_Extension_CountHint(); + $countHint->transferFromDOM($child); + $this->_countHint = $countHint; + break; + case $this->lookupNamespace('yt') . ':' . 'playlistId': + $playlistId = new Zend_Gdata_YouTube_Extension_PlaylistId(); + $playlistId->transferFromDOM($child); + $this->_playlistId = $playlistId; + break; + case $this->lookupNamespace('gd') . ':' . 'feedLink': + $feedLink = new Zend_Gdata_Extension_FeedLink(); + $feedLink->transferFromDOM($child); + $this->_feedLink[] = $feedLink; + break; + default: + parent::takeChildFromDOM($child); + break; + } + } + + /** + * Sets the description relating to the playlist. + * + * @deprecated Deprecated as of version 2 of the YouTube API. + * @param Zend_Gdata_YouTube_Extension_Description $description The description relating to the video + * @return Zend_Gdata_YouTube_PlaylistListEntry Provides a fluent interface + */ + public function setDescription($description = null) + { + if ($this->getMajorProtocolVersion() >= 2) { + $this->setSummary($description); + } else { + $this->_description = $description; + } + return $this; + } + + /** + * Returns the description relating to the video. + * + * @return Zend_Gdata_YouTube_Extension_Description The description + * relating to the video + */ + public function getDescription() + { + if ($this->getMajorProtocolVersion() >= 2) { + return $this->getSummary(); + } else { + return $this->_description; + } + } + + /** + * Returns the countHint relating to the playlist. + * + * The countHint is the number of videos on a playlist. + * + * @throws Zend_Gdata_App_VersionException + * @return Zend_Gdata_YouTube_Extension_CountHint The count of videos on + * a playlist. + */ + public function getCountHint() + { + if (($this->getMajorProtocolVersion() == null) || + ($this->getMajorProtocolVersion() == 1)) { + require_once 'Zend/Gdata/App/VersionException.php'; + throw new Zend_Gdata_App_VersionException('The yt:countHint ' . + 'element is not supported in versions earlier than 2.'); + } else { + return $this->_countHint; + } + } + + /** + * Returns the Id relating to the playlist. + * + * @throws Zend_Gdata_App_VersionException + * @return Zend_Gdata_YouTube_Extension_PlaylistId The id of this playlist. + */ + public function getPlaylistId() + { + if (($this->getMajorProtocolVersion() == null) || + ($this->getMajorProtocolVersion() == 1)) { + require_once 'Zend/Gdata/App/VersionException.php'; + throw new Zend_Gdata_App_VersionException('The yt:playlistId ' . + 'element is not supported in versions earlier than 2.'); + } else { + return $this->_playlistId; + } + } + + /** + * Sets the array of embedded feeds related to the playlist + * + * @param array $feedLink The array of embedded feeds relating to the video + * @return Zend_Gdata_YouTube_PlaylistListEntry Provides a fluent interface + */ + public function setFeedLink($feedLink = null) + { + $this->_feedLink = $feedLink; + return $this; + } + + /** + * Get the feed link property for this entry. + * + * @see setFeedLink + * @param string $rel (optional) The rel value of the link to be found. + * If null, the array of links is returned. + * @return mixed If $rel is specified, a Zend_Gdata_Extension_FeedLink + * object corresponding to the requested rel value is returned + * if found, or null if the requested value is not found. If + * $rel is null or not specified, an array of all available + * feed links for this entry is returned, or null if no feed + * links are set. + */ + public function getFeedLink($rel = null) + { + if ($rel == null) { + return $this->_feedLink; + } else { + foreach ($this->_feedLink as $feedLink) { + if ($feedLink->rel == $rel) { + return $feedLink; + } + } + return null; + } + } + + /** + * Returns the URL of the playlist video feed + * + * @return string The URL of the playlist video feed + */ + public function getPlaylistVideoFeedUrl() + { + if ($this->getMajorProtocolVersion() >= 2) { + return $this->getContent()->getSrc(); + } else { + return $this->getFeedLink(Zend_Gdata_YouTube::PLAYLIST_REL)->href; + } + } + +} diff --git a/Zend/Gdata/YouTube/PlaylistListFeed.php b/Zend/Gdata/YouTube/PlaylistListFeed.php new file mode 100644 index 00000000..9b8736b4 --- /dev/null +++ b/Zend/Gdata/YouTube/PlaylistListFeed.php @@ -0,0 +1,68 @@ +registerAllNamespaces(Zend_Gdata_YouTube::$namespaces); + parent::__construct($element); + } + +} diff --git a/Zend/Gdata/YouTube/PlaylistVideoEntry.php b/Zend/Gdata/YouTube/PlaylistVideoEntry.php new file mode 100644 index 00000000..699e1b47 --- /dev/null +++ b/Zend/Gdata/YouTube/PlaylistVideoEntry.php @@ -0,0 +1,132 @@ +registerAllNamespaces(Zend_Gdata_YouTube::$namespaces); + parent::__construct($element); + } + + /** + * Retrieves a DOMElement which corresponds to this element and all + * child properties. This is used to build an entry back into a DOM + * and eventually XML text for sending to the server upon updates, or + * for application storage/persistence. + * + * @param DOMDocument $doc The DOMDocument used to construct DOMElements + * @return DOMElement The DOMElement representing this element and all + * child properties. + */ + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc, $majorVersion, $minorVersion); + if ($this->_position !== null) { + $element->appendChild($this->_position->getDOM($element->ownerDocument)); + } + return $element; + } + + /** + * Creates individual Entry objects of the appropriate type and + * stores them in the $_entry array based upon DOM data. + * + * @param DOMNode $child The DOMNode to process + */ + protected function takeChildFromDOM($child) + { + $absoluteNodeName = $child->namespaceURI . ':' . $child->localName; + switch ($absoluteNodeName) { + case $this->lookupNamespace('yt') . ':' . 'position': + $position = new Zend_Gdata_YouTube_Extension_Position(); + $position->transferFromDOM($child); + $this->_position = $position; + break; + default: + parent::takeChildFromDOM($child); + break; + } + } + + + /** + * Sets the array of embedded feeds related to the video + * + * @param Zend_Gdata_YouTube_Extension_Position $position + * The position of the entry in the feed, as specified by the user. + * @return Zend_Gdata_YouTube_PlaylistVideoEntry Provides a fluent interface + */ + public function setPosition($position = null) + { + $this->_position = $position; + return $this; + } + + /** + * Returns the position of the entry in the feed, as specified by the user + * + * @return Zend_Gdata_YouTube_Extension_Position The position + */ + public function getPosition() + { + return $this->_position; + } + +} diff --git a/Zend/Gdata/YouTube/PlaylistVideoFeed.php b/Zend/Gdata/YouTube/PlaylistVideoFeed.php new file mode 100644 index 00000000..e2ddb312 --- /dev/null +++ b/Zend/Gdata/YouTube/PlaylistVideoFeed.php @@ -0,0 +1,68 @@ +registerAllNamespaces(Zend_Gdata_YouTube::$namespaces); + parent::__construct($element); + } + +} diff --git a/Zend/Gdata/YouTube/SubscriptionEntry.php b/Zend/Gdata/YouTube/SubscriptionEntry.php new file mode 100644 index 00000000..fa1ddcc9 --- /dev/null +++ b/Zend/Gdata/YouTube/SubscriptionEntry.php @@ -0,0 +1,446 @@ +registerAllNamespaces(Zend_Gdata_YouTube::$namespaces); + parent::__construct($element); + } + + /** + * Retrieves a DOMElement which corresponds to this element and all + * child properties. This is used to build an entry back into a DOM + * and eventually XML text for sending to the server upon updates, or + * for application storage/persistence. + * + * @param DOMDocument $doc The DOMDocument used to construct DOMElements + * @return DOMElement The DOMElement representing this element and all + * child properties. + */ + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc, $majorVersion, $minorVersion); + if ($this->_countHint != null) { + $element->appendChild($this->_countHint->getDOM($element->ownerDocument)); + } + if ($this->_playlistTitle != null) { + $element->appendChild($this->_playlistTitle->getDOM($element->ownerDocument)); + } + if ($this->_playlistId != null) { + $element->appendChild($this->_playlistId->getDOM($element->ownerDocument)); + } + if ($this->_mediaThumbnail != null) { + $element->appendChild($this->_mediaThumbnail->getDOM($element->ownerDocument)); + } + if ($this->_username != null) { + $element->appendChild($this->_username->getDOM($element->ownerDocument)); + } + if ($this->_queryString != null) { + $element->appendChild($this->_queryString->getDOM($element->ownerDocument)); + } + if ($this->_feedLink != null) { + foreach ($this->_feedLink as $feedLink) { + $element->appendChild($feedLink->getDOM($element->ownerDocument)); + } + } + return $element; + } + + /** + * Creates individual Entry objects of the appropriate type and + * stores them in the $_entry array based upon DOM data. + * + * @param DOMNode $child The DOMNode to process + */ + protected function takeChildFromDOM($child) + { + $absoluteNodeName = $child->namespaceURI . ':' . $child->localName; + switch ($absoluteNodeName) { + case $this->lookupNamespace('gd') . ':' . 'feedLink': + $feedLink = new Zend_Gdata_Extension_FeedLink(); + $feedLink->transferFromDOM($child); + $this->_feedLink[] = $feedLink; + break; + case $this->lookupNamespace('media') . ':' . 'thumbnail': + $mediaThumbnail = new Zend_Gdata_Media_Extension_MediaThumbnail(); + $mediaThumbnail->transferFromDOM($child); + $this->_mediaThumbnail = $mediaThumbnail; + break; + case $this->lookupNamespace('yt') . ':' . 'countHint': + $countHint = new Zend_Gdata_YouTube_Extension_CountHint(); + $countHint->transferFromDOM($child); + $this->_countHint = $countHint; + break; + case $this->lookupNamespace('yt') . ':' . 'playlistTitle': + $playlistTitle = new Zend_Gdata_YouTube_Extension_PlaylistTitle(); + $playlistTitle->transferFromDOM($child); + $this->_playlistTitle = $playlistTitle; + break; + case $this->lookupNamespace('yt') . ':' . 'playlistId': + $playlistId = new Zend_Gdata_YouTube_Extension_PlaylistId(); + $playlistId->transferFromDOM($child); + $this->_playlistId = $playlistId; + break; + case $this->lookupNamespace('yt') . ':' . 'queryString': + $queryString = new Zend_Gdata_YouTube_Extension_QueryString(); + $queryString->transferFromDOM($child); + $this->_queryString = $queryString; + break; + case $this->lookupNamespace('yt') . ':' . 'username': + $username = new Zend_Gdata_YouTube_Extension_Username(); + $username->transferFromDOM($child); + $this->_username = $username; + break; + default: + parent::takeChildFromDOM($child); + break; + } + } + + /** + * Sets the array of embedded feeds related to the video + * + * @param array $feedLink The array of embedded feeds relating to the video + * @return Zend_Gdata_YouTube_SubscriptionEntry Provides a fluent interface + */ + public function setFeedLink($feedLink = null) + { + $this->_feedLink = $feedLink; + return $this; + } + + /** + * Get the feed link property for this entry. + * + * @see setFeedLink + * @param string $rel (optional) The rel value of the link to be found. + * If null, the array of links is returned. + * @return mixed If $rel is specified, a Zend_Gdata_Extension_FeedLink + * object corresponding to the requested rel value is returned + * if found, or null if the requested value is not found. If + * $rel is null or not specified, an array of all available + * feed links for this entry is returned, or null if no feed + * links are set. + */ + public function getFeedLink($rel = null) + { + if ($rel == null) { + return $this->_feedLink; + } else { + foreach ($this->_feedLink as $feedLink) { + if ($feedLink->rel == $rel) { + return $feedLink; + } + } + return null; + } + } + + /** + * Get the playlist title for a 'playlist' subscription. + * + * @throws Zend_Gdata_App_VersionException + * @return Zend_Gdata_YouTube_Extension_PlaylistId + */ + public function getPlaylistId() + { + if (($this->getMajorProtocolVersion() == null) || + ($this->getMajorProtocolVersion() == 1)) { + require_once 'Zend/Gdata/App/VersionException.php'; + throw new Zend_Gdata_App_VersionException('The getPlaylistId ' . + ' method is only supported as of version 2 of the YouTube ' . + 'API.'); + } else { + return $this->_playlistId; + } + } + + /** + * Sets the yt:playlistId element for a new playlist subscription. + * + * @param Zend_Gdata_YouTube_Extension_PlaylistId $id The id of + * the playlist to which to subscribe to. + * @throws Zend_Gdata_App_VersionException + * @return Zend_Gdata_YouTube_SubscriptionEntry Provides a fluent interface + */ + public function setPlaylistId($id = null) + { + if (($this->getMajorProtocolVersion() == null) || + ($this->getMajorProtocolVersion() == 1)) { + require_once 'Zend/Gdata/App/VersionException.php'; + throw new Zend_Gdata_App_VersionException('The setPlaylistTitle ' . + ' method is only supported as of version 2 of the YouTube ' . + 'API.'); + } else { + $this->_playlistId = $id; + return $this; + } + } + + /** + * Get the queryString of the subscription + * + * @return Zend_Gdata_YouTube_Extension_QueryString + */ + public function getQueryString() + { + return $this->_queryString; + } + + /** + * Sets the yt:queryString element for a new keyword subscription. + * + * @param Zend_Gdata_YouTube_Extension_QueryString $queryString The query + * string to subscribe to + * @return Zend_Gdata_YouTube_SubscriptionEntry Provides a fluent interface + */ + public function setQueryString($queryString = null) + { + $this->_queryString = $queryString; + return $this; + } + + /** + * Get the playlist title for a 'playlist' subscription. + * + * @throws Zend_Gdata_App_VersionException + * @return Zend_Gdata_YouTube_Extension_PlaylistTitle + */ + public function getPlaylistTitle() + { + if (($this->getMajorProtocolVersion() == null) || + ($this->getMajorProtocolVersion() == 1)) { + require_once 'Zend/Gdata/App/VersionException.php'; + throw new Zend_Gdata_App_VersionException('The getPlaylistTitle ' . + ' method is only supported as of version 2 of the YouTube ' . + 'API.'); + } else { + return $this->_playlistTitle; + } + } + + /** + * Sets the yt:playlistTitle element for a new playlist subscription. + * + * @param Zend_Gdata_YouTube_Extension_PlaylistTitle $title The title of + * the playlist to which to subscribe to. + * @throws Zend_Gdata_App_VersionException + * @return Zend_Gdata_YouTube_SubscriptionEntry Provides a fluent interface + */ + public function setPlaylistTitle($title = null) + { + if (($this->getMajorProtocolVersion() == null) || + ($this->getMajorProtocolVersion() == 1)) { + require_once 'Zend/Gdata/App/VersionException.php'; + throw new Zend_Gdata_App_VersionException('The setPlaylistTitle ' . + ' method is only supported as of version 2 of the YouTube ' . + 'API.'); + } else { + $this->_playlistTitle = $title; + return $this; + } + } + + /** + * Get the counthint for a subscription. + * + * @throws Zend_Gdata_App_VersionException + * @return Zend_Gdata_YouTube_Extension_CountHint + */ + public function getCountHint() + { + if (($this->getMajorProtocolVersion() == null) || + ($this->getMajorProtocolVersion() == 1)) { + require_once 'Zend/Gdata/App/VersionException.php'; + throw new Zend_Gdata_App_VersionException('The getCountHint ' . + ' method is only supported as of version 2 of the YouTube ' . + 'API.'); + } else { + return $this->_countHint; + } + } + + /** + * Get the thumbnail for a subscription. + * + * @throws Zend_Gdata_App_VersionException + * @return Zend_Gdata_Media_Extension_MediaThumbnail + */ + public function getMediaThumbnail() + { + if (($this->getMajorProtocolVersion() == null) || + ($this->getMajorProtocolVersion() == 1)) { + require_once 'Zend/Gdata/App/VersionException.php'; + throw new Zend_Gdata_App_VersionException('The getMediaThumbnail ' . + ' method is only supported as of version 2 of the YouTube ' . + 'API.'); + } else { + return $this->_mediaThumbnail; + } + } + + /** + * Get the username for a channel subscription. + * + * @return Zend_Gdata_YouTube_Extension_Username + */ + public function getUsername() + { + return $this->_username; + } + + /** + * Sets the username for a new channel subscription. + * + * @param Zend_Gdata_YouTube_Extension_Username $username The username of + * the channel to which to subscribe to. + * @return Zend_Gdata_YouTube_SubscriptionEntry Provides a fluent interface + */ + public function setUsername($username = null) + { + $this->_username = $username; + return $this; + } + +} diff --git a/Zend/Gdata/YouTube/SubscriptionFeed.php b/Zend/Gdata/YouTube/SubscriptionFeed.php new file mode 100644 index 00000000..bb71af8e --- /dev/null +++ b/Zend/Gdata/YouTube/SubscriptionFeed.php @@ -0,0 +1,68 @@ +registerAllNamespaces(Zend_Gdata_YouTube::$namespaces); + parent::__construct($element); + } + +} diff --git a/Zend/Gdata/YouTube/UserProfileEntry.php b/Zend/Gdata/YouTube/UserProfileEntry.php new file mode 100644 index 00000000..deb79491 --- /dev/null +++ b/Zend/Gdata/YouTube/UserProfileEntry.php @@ -0,0 +1,1041 @@ +registerAllNamespaces(Zend_Gdata_YouTube::$namespaces); + parent::__construct($element); + } + + /** + * Retrieves a DOMElement which corresponds to this element and all + * child properties. This is used to build an entry back into a DOM + * and eventually XML text for sending to the server upon updates, or + * for application storage/persistence. + * + * @param DOMDocument $doc The DOMDocument used to construct DOMElements + * @return DOMElement The DOMElement representing this element and all + * child properties. + */ + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc, $majorVersion, $minorVersion); + if ($this->_description != null) { + $element->appendChild($this->_description->getDOM($element->ownerDocument)); + } + if ($this->_aboutMe != null) { + $element->appendChild($this->_aboutMe->getDOM($element->ownerDocument)); + } + if ($this->_age != null) { + $element->appendChild($this->_age->getDOM($element->ownerDocument)); + } + if ($this->_username != null) { + $element->appendChild($this->_username->getDOM($element->ownerDocument)); + } + if ($this->_books != null) { + $element->appendChild($this->_books->getDOM($element->ownerDocument)); + } + if ($this->_company != null) { + $element->appendChild($this->_company->getDOM($element->ownerDocument)); + } + if ($this->_hobbies != null) { + $element->appendChild($this->_hobbies->getDOM($element->ownerDocument)); + } + if ($this->_hometown != null) { + $element->appendChild($this->_hometown->getDOM($element->ownerDocument)); + } + if ($this->_location != null) { + $element->appendChild($this->_location->getDOM($element->ownerDocument)); + } + if ($this->_movies != null) { + $element->appendChild($this->_movies->getDOM($element->ownerDocument)); + } + if ($this->_music != null) { + $element->appendChild($this->_music->getDOM($element->ownerDocument)); + } + if ($this->_occupation != null) { + $element->appendChild($this->_occupation->getDOM($element->ownerDocument)); + } + if ($this->_school != null) { + $element->appendChild($this->_school->getDOM($element->ownerDocument)); + } + if ($this->_gender != null) { + $element->appendChild($this->_gender->getDOM($element->ownerDocument)); + } + if ($this->_relationship != null) { + $element->appendChild($this->_relationship->getDOM($element->ownerDocument)); + } + if ($this->_firstName != null) { + $element->appendChild($this->_firstName->getDOM($element->ownerDocument)); + } + if ($this->_lastName != null) { + $element->appendChild($this->_lastName->getDOM($element->ownerDocument)); + } + if ($this->_statistics != null) { + $element->appendChild($this->_statistics->getDOM($element->ownerDocument)); + } + if ($this->_thumbnail != null) { + $element->appendChild($this->_thumbnail->getDOM($element->ownerDocument)); + } + if ($this->_feedLink != null) { + foreach ($this->_feedLink as $feedLink) { + $element->appendChild($feedLink->getDOM($element->ownerDocument)); + } + } + return $element; + } + + /** + * Creates individual Entry objects of the appropriate type and + * stores them in the $_entry array based upon DOM data. + * + * @param DOMNode $child The DOMNode to process + */ + protected function takeChildFromDOM($child) + { + $absoluteNodeName = $child->namespaceURI . ':' . $child->localName; + switch ($absoluteNodeName) { + case $this->lookupNamespace('yt') . ':' . 'description': + $description = new Zend_Gdata_YouTube_Extension_Description(); + $description->transferFromDOM($child); + $this->_description = $description; + break; + case $this->lookupNamespace('yt') . ':' . 'aboutMe': + $aboutMe = new Zend_Gdata_YouTube_Extension_AboutMe(); + $aboutMe->transferFromDOM($child); + $this->_aboutMe = $aboutMe; + break; + case $this->lookupNamespace('yt') . ':' . 'age': + $age = new Zend_Gdata_YouTube_Extension_Age(); + $age->transferFromDOM($child); + $this->_age = $age; + break; + case $this->lookupNamespace('yt') . ':' . 'username': + $username = new Zend_Gdata_YouTube_Extension_Username(); + $username->transferFromDOM($child); + $this->_username = $username; + break; + case $this->lookupNamespace('yt') . ':' . 'books': + $books = new Zend_Gdata_YouTube_Extension_Books(); + $books->transferFromDOM($child); + $this->_books = $books; + break; + case $this->lookupNamespace('yt') . ':' . 'company': + $company = new Zend_Gdata_YouTube_Extension_Company(); + $company->transferFromDOM($child); + $this->_company = $company; + break; + case $this->lookupNamespace('yt') . ':' . 'hobbies': + $hobbies = new Zend_Gdata_YouTube_Extension_Hobbies(); + $hobbies->transferFromDOM($child); + $this->_hobbies = $hobbies; + break; + case $this->lookupNamespace('yt') . ':' . 'hometown': + $hometown = new Zend_Gdata_YouTube_Extension_Hometown(); + $hometown->transferFromDOM($child); + $this->_hometown = $hometown; + break; + case $this->lookupNamespace('yt') . ':' . 'location': + $location = new Zend_Gdata_YouTube_Extension_Location(); + $location->transferFromDOM($child); + $this->_location = $location; + break; + case $this->lookupNamespace('yt') . ':' . 'movies': + $movies = new Zend_Gdata_YouTube_Extension_Movies(); + $movies->transferFromDOM($child); + $this->_movies = $movies; + break; + case $this->lookupNamespace('yt') . ':' . 'music': + $music = new Zend_Gdata_YouTube_Extension_Music(); + $music->transferFromDOM($child); + $this->_music = $music; + break; + case $this->lookupNamespace('yt') . ':' . 'occupation': + $occupation = new Zend_Gdata_YouTube_Extension_Occupation(); + $occupation->transferFromDOM($child); + $this->_occupation = $occupation; + break; + case $this->lookupNamespace('yt') . ':' . 'school': + $school = new Zend_Gdata_YouTube_Extension_School(); + $school->transferFromDOM($child); + $this->_school = $school; + break; + case $this->lookupNamespace('yt') . ':' . 'gender': + $gender = new Zend_Gdata_YouTube_Extension_Gender(); + $gender->transferFromDOM($child); + $this->_gender = $gender; + break; + case $this->lookupNamespace('yt') . ':' . 'relationship': + $relationship = new Zend_Gdata_YouTube_Extension_Relationship(); + $relationship->transferFromDOM($child); + $this->_relationship = $relationship; + break; + case $this->lookupNamespace('yt') . ':' . 'firstName': + $firstName = new Zend_Gdata_YouTube_Extension_FirstName(); + $firstName->transferFromDOM($child); + $this->_firstName = $firstName; + break; + case $this->lookupNamespace('yt') . ':' . 'lastName': + $lastName = new Zend_Gdata_YouTube_Extension_LastName(); + $lastName->transferFromDOM($child); + $this->_lastName = $lastName; + break; + case $this->lookupNamespace('yt') . ':' . 'statistics': + $statistics = new Zend_Gdata_YouTube_Extension_Statistics(); + $statistics->transferFromDOM($child); + $this->_statistics = $statistics; + break; + case $this->lookupNamespace('media') . ':' . 'thumbnail': + $thumbnail = new Zend_Gdata_Media_Extension_MediaThumbnail(); + $thumbnail->transferFromDOM($child); + $this->_thumbnail = $thumbnail; + break; + case $this->lookupNamespace('gd') . ':' . 'feedLink': + $feedLink = new Zend_Gdata_Extension_FeedLink(); + $feedLink->transferFromDOM($child); + $this->_feedLink[] = $feedLink; + break; + default: + parent::takeChildFromDOM($child); + break; + } + } + + /** + * Sets the content of the 'about me' field. + * + * @param Zend_Gdata_YouTube_Extension_AboutMe $aboutMe The 'about me' + * information. + * @throws Zend_Gdata_App_VersionException + * @return Zend_Gdata_YouTube_UserProfileEntry Provides a fluent interface + */ + public function setAboutMe($aboutMe = null) + { + if (($this->getMajorProtocolVersion() == null) || + ($this->getMajorProtocolVersion() == 1)) { + require_once 'Zend/Gdata/App/VersionException.php'; + throw new Zend_Gdata_App_VersionException('The setAboutMe ' . + ' method is only supported as of version 2 of the YouTube ' . + 'API.'); + } else { + $this->_aboutMe = $aboutMe; + return $this; + } + } + + /** + * Returns the contents of the 'about me' field. + * + * @throws Zend_Gdata_App_VersionException + * @return Zend_Gdata_YouTube_Extension_AboutMe The 'about me' information + */ + public function getAboutMe() + { + if (($this->getMajorProtocolVersion() == null) || + ($this->getMajorProtocolVersion() == 1)) { + require_once 'Zend/Gdata/App/VersionException.php'; + throw new Zend_Gdata_App_VersionException('The getAboutMe ' . + ' method is only supported as of version 2 of the YouTube ' . + 'API.'); + } else { + return $this->_aboutMe; + } + } + + /** + * Sets the content of the 'first name' field. + * + * @param Zend_Gdata_YouTube_Extension_FirstName $firstName The first name + * @throws Zend_Gdata_App_VersionException + * @return Zend_Gdata_YouTube_UserProfileEntry Provides a fluent interface + */ + public function setFirstName($firstName = null) + { + if (($this->getMajorProtocolVersion() == null) || + ($this->getMajorProtocolVersion() == 1)) { + require_once 'Zend/Gdata/App/VersionException.php'; + throw new Zend_Gdata_App_VersionException('The setFirstName ' . + ' method is only supported as of version 2 of the YouTube ' . + 'API.'); + } else { + $this->_firstName = $firstName; + return $this; + } + } + + /** + * Returns the first name + * + * @throws Zend_Gdata_App_VersionException + * @return Zend_Gdata_YouTube_Extension_FirstName The first name + */ + public function getFirstName() + { + if (($this->getMajorProtocolVersion() == null) || + ($this->getMajorProtocolVersion() == 1)) { + require_once 'Zend/Gdata/App/VersionException.php'; + throw new Zend_Gdata_App_VersionException('The getFirstName ' . + ' method is only supported as of version 2 of the YouTube ' . + 'API.'); + } else { + return $this->_firstName; + } + } + + /** + * Sets the content of the 'last name' field. + * + * @param Zend_Gdata_YouTube_Extension_LastName $lastName The last name + * @throws Zend_Gdata_App_VersionException + * @return Zend_Gdata_YouTube_UserProfileEntry Provides a fluent interface + */ + public function setLastName($lastName = null) + { + if (($this->getMajorProtocolVersion() == null) || + ($this->getMajorProtocolVersion() == 1)) { + require_once 'Zend/Gdata/App/VersionException.php'; + throw new Zend_Gdata_App_VersionException('The setLastName ' . + ' method is only supported as of version 2 of the YouTube ' . + 'API.'); + } else { + $this->_lastName = $lastName; + return $this; + } + } + + /** + * Returns the last name + * + * @throws Zend_Gdata_App_VersionException + * @return Zend_Gdata_YouTube_Extension_LastName The last name + */ + public function getLastName() + { + if (($this->getMajorProtocolVersion() == null) || + ($this->getMajorProtocolVersion() == 1)) { + require_once 'Zend/Gdata/App/VersionException.php'; + throw new Zend_Gdata_App_VersionException('The getLastName ' . + ' method is only supported as of version 2 of the YouTube ' . + 'API.'); + } else { + return $this->_lastName; + } + } + + /** + * Returns the statistics + * + * @throws Zend_Gdata_App_VersionException + * @return Zend_Gdata_YouTube_Extension_Statistics The profile statistics + */ + public function getStatistics() + { + if (($this->getMajorProtocolVersion() == null) || + ($this->getMajorProtocolVersion() == 1)) { + require_once 'Zend/Gdata/App/VersionException.php'; + throw new Zend_Gdata_App_VersionException('The getStatistics ' . + ' method is only supported as of version 2 of the YouTube ' . + 'API.'); + } else { + return $this->_statistics; + } + } + + /** + * Returns the thumbnail + * + * @throws Zend_Gdata_App_VersionException + * @return Zend_Gdata_Media_Extension_MediaThumbnail The profile thumbnail + */ + public function getThumbnail() + { + if (($this->getMajorProtocolVersion() == null) || + ($this->getMajorProtocolVersion() == 1)) { + require_once 'Zend/Gdata/App/VersionException.php'; + throw new Zend_Gdata_App_VersionException('The getThumbnail ' . + ' method is only supported as of version 2 of the YouTube ' . + 'API.'); + } else { + return $this->_thumbnail; + } + } + + /** + * Sets the age + * + * @param Zend_Gdata_YouTube_Extension_Age $age The age + * @return Zend_Gdata_YouTube_UserProfileEntry Provides a fluent interface + */ + public function setAge($age = null) + { + $this->_age = $age; + return $this; + } + + /** + * Returns the age + * + * @return Zend_Gdata_YouTube_Extension_Age The age + */ + public function getAge() + { + return $this->_age; + } + + /** + * Sets the username + * + * @param Zend_Gdata_YouTube_Extension_Username $username The username + * @return Zend_Gdata_YouTube_UserProfileEntry Provides a fluent interface + */ + public function setUsername($username = null) + { + $this->_username = $username; + return $this; + } + + /** + * Returns the username + * + * @return Zend_Gdata_YouTube_Extension_Username The username + */ + public function getUsername() + { + return $this->_username; + } + + /** + * Sets the books + * + * @param Zend_Gdata_YouTube_Extension_Books $books The books + * @return Zend_Gdata_YouTube_UserProfileEntry Provides a fluent interface + */ + public function setBooks($books = null) + { + $this->_books = $books; + return $this; + } + + /** + * Returns the books + * + * @return Zend_Gdata_YouTube_Extension_Books The books + */ + public function getBooks() + { + return $this->_books; + } + + /** + * Sets the company + * + * @param Zend_Gdata_YouTube_Extension_Company $company The company + * @return Zend_Gdata_YouTube_UserProfileEntry Provides a fluent interface + */ + public function setCompany($company = null) + { + $this->_company = $company; + return $this; + } + + /** + * Returns the company + * + * @return Zend_Gdata_YouTube_Extension_Company The company + */ + public function getCompany() + { + return $this->_company; + } + + /** + * Sets the hobbies + * + * @param Zend_Gdata_YouTube_Extension_Hobbies $hobbies The hobbies + * @return Zend_Gdata_YouTube_UserProfileEntry Provides a fluent interface + */ + public function setHobbies($hobbies = null) + { + $this->_hobbies = $hobbies; + return $this; + } + + /** + * Returns the hobbies + * + * @return Zend_Gdata_YouTube_Extension_Hobbies The hobbies + */ + public function getHobbies() + { + return $this->_hobbies; + } + + /** + * Sets the hometown + * + * @param Zend_Gdata_YouTube_Extension_Hometown $hometown The hometown + * @return Zend_Gdata_YouTube_UserProfileEntry Provides a fluent interface + */ + public function setHometown($hometown = null) + { + $this->_hometown = $hometown; + return $this; + } + + /** + * Returns the hometown + * + * @return Zend_Gdata_YouTube_Extension_Hometown The hometown + */ + public function getHometown() + { + return $this->_hometown; + } + + /** + * Sets the location + * + * @param Zend_Gdata_YouTube_Extension_Location $location The location + * @return Zend_Gdata_YouTube_UserProfileEntry Provides a fluent interface + */ + public function setLocation($location = null) + { + $this->_location = $location; + return $this; + } + + /** + * Returns the location + * + * @return Zend_Gdata_YouTube_Extension_Location The location + */ + public function getLocation() + { + return $this->_location; + } + + /** + * Sets the movies + * + * @param Zend_Gdata_YouTube_Extension_Movies $movies The movies + * @return Zend_Gdata_YouTube_UserProfileEntry Provides a fluent interface + */ + public function setMovies($movies = null) + { + $this->_movies = $movies; + return $this; + } + + /** + * Returns the movies + * + * @return Zend_Gdata_YouTube_Extension_Movies The movies + */ + public function getMovies() + { + return $this->_movies; + } + + /** + * Sets the music + * + * @param Zend_Gdata_YouTube_Extension_Music $music The music + * @return Zend_Gdata_YouTube_UserProfileEntry Provides a fluent interface + */ + public function setMusic($music = null) + { + $this->_music = $music; + return $this; + } + + /** + * Returns the music + * + * @return Zend_Gdata_YouTube_Extension_Music The music + */ + public function getMusic() + { + return $this->_music; + } + + /** + * Sets the occupation + * + * @param Zend_Gdata_YouTube_Extension_Occupation $occupation The occupation + * @return Zend_Gdata_YouTube_UserProfileEntry Provides a fluent interface + */ + public function setOccupation($occupation = null) + { + $this->_occupation = $occupation; + return $this; + } + + /** + * Returns the occupation + * + * @return Zend_Gdata_YouTube_Extension_Occupation The occupation + */ + public function getOccupation() + { + return $this->_occupation; + } + + /** + * Sets the school + * + * @param Zend_Gdata_YouTube_Extension_School $school The school + * @return Zend_Gdata_YouTube_UserProfileEntry Provides a fluent interface + */ + public function setSchool($school = null) + { + $this->_school = $school; + return $this; + } + + /** + * Returns the school + * + * @return Zend_Gdata_YouTube_Extension_School The school + */ + public function getSchool() + { + return $this->_school; + } + + /** + * Sets the gender + * + * @param Zend_Gdata_YouTube_Extension_Gender $gender The gender + * @return Zend_Gdata_YouTube_UserProfileEntry Provides a fluent interface + */ + public function setGender($gender = null) + { + $this->_gender = $gender; + return $this; + } + + /** + * Returns the gender + * + * @return Zend_Gdata_YouTube_Extension_Gender The gender + */ + public function getGender() + { + return $this->_gender; + } + + /** + * Sets the relationship + * + * @param Zend_Gdata_YouTube_Extension_Relationship $relationship The relationship + * @return Zend_Gdata_YouTube_UserProfileEntry Provides a fluent interface + */ + public function setRelationship($relationship = null) + { + $this->_relationship = $relationship; + return $this; + } + + /** + * Returns the relationship + * + * @return Zend_Gdata_YouTube_Extension_Relationship The relationship + */ + public function getRelationship() + { + return $this->_relationship; + } + + /** + * Sets the array of embedded feeds related to the video + * + * @param array $feedLink The array of embedded feeds relating to the video + * @return Zend_Gdata_YouTube_UserProfileEntry Provides a fluent interface + */ + public function setFeedLink($feedLink = null) + { + $this->_feedLink = $feedLink; + return $this; + } + + /** + * Get the feed link property for this entry. + * + * @see setFeedLink + * @param string $rel (optional) The rel value of the link to be found. + * If null, the array of links is returned. + * @return mixed If $rel is specified, a Zend_Gdata_Extension_FeedLink + * object corresponding to the requested rel value is returned + * if found, or null if the requested value is not found. If + * $rel is null or not specified, an array of all available + * feed links for this entry is returned, or null if no feed + * links are set. + */ + public function getFeedLink($rel = null) + { + if ($rel == null) { + return $this->_feedLink; + } else { + foreach ($this->_feedLink as $feedLink) { + if ($feedLink->rel == $rel) { + return $feedLink; + } + } + return null; + } + } + + /** + * Returns the URL in the gd:feedLink with the provided rel value + * + * @param string $rel The rel value to find + * @return mixed Either the URL as a string or null if a feedLink wasn't + * found with the provided rel value + */ + public function getFeedLinkHref($rel) + { + $feedLink = $this->getFeedLink($rel); + if ($feedLink !== null) { + return $feedLink->href; + } else { + return null; + } + } + + /** + * Returns the URL of the playlist list feed + * + * @return string The URL of the playlist video feed + */ + public function getPlaylistListFeedUrl() + { + return $this->getFeedLinkHref(Zend_Gdata_YouTube::USER_PLAYLISTS_REL); + } + + /** + * Returns the URL of the uploads feed + * + * @return string The URL of the uploads video feed + */ + public function getUploadsFeedUrl() + { + return $this->getFeedLinkHref(Zend_Gdata_YouTube::USER_UPLOADS_REL); + } + + /** + * Returns the URL of the subscriptions feed + * + * @return string The URL of the subscriptions feed + */ + public function getSubscriptionsFeedUrl() + { + return $this->getFeedLinkHref(Zend_Gdata_YouTube::USER_SUBSCRIPTIONS_REL); + } + + /** + * Returns the URL of the contacts feed + * + * @return string The URL of the contacts feed + */ + public function getContactsFeedUrl() + { + return $this->getFeedLinkHref(Zend_Gdata_YouTube::USER_CONTACTS_REL); + } + + /** + * Returns the URL of the favorites feed + * + * @return string The URL of the favorites feed + */ + public function getFavoritesFeedUrl() + { + return $this->getFeedLinkHref(Zend_Gdata_YouTube::USER_FAVORITES_REL); + } + +} diff --git a/Zend/Gdata/YouTube/VideoEntry.php b/Zend/Gdata/YouTube/VideoEntry.php new file mode 100644 index 00000000..fff6156f --- /dev/null +++ b/Zend/Gdata/YouTube/VideoEntry.php @@ -0,0 +1,1095 @@ +registerAllNamespaces(Zend_Gdata_YouTube::$namespaces); + parent::__construct($element); + } + + /** + * Retrieves a DOMElement which corresponds to this element and all + * child properties. This is used to build an entry back into a DOM + * and eventually XML text for sending to the server upon updates, or + * for application storage/persistence. + * + * @param DOMDocument $doc The DOMDocument used to construct DOMElements + * @return DOMElement The DOMElement representing this element and all + * child properties. + */ + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc, $majorVersion, $minorVersion); + if ($this->_noEmbed != null) { + $element->appendChild($this->_noEmbed->getDOM( + $element->ownerDocument)); + } + if ($this->_statistics != null) { + $element->appendChild($this->_statistics->getDOM( + $element->ownerDocument)); + } + if ($this->_racy != null) { + $element->appendChild($this->_racy->getDOM( + $element->ownerDocument)); + } + if ($this->_recorded != null) { + $element->appendChild($this->_recorded->getDOM( + $element->ownerDocument)); + } + if ($this->_location != null) { + $element->appendChild($this->_location->getDOM( + $element->ownerDocument)); + } + if ($this->_rating != null) { + $element->appendChild($this->_rating->getDOM( + $element->ownerDocument)); + } + if ($this->_comments != null) { + $element->appendChild($this->_comments->getDOM( + $element->ownerDocument)); + } + if ($this->_feedLink != null) { + foreach ($this->_feedLink as $feedLink) { + $element->appendChild($feedLink->getDOM( + $element->ownerDocument)); + } + } + if ($this->_where != null) { + $element->appendChild($this->_where->getDOM( + $element->ownerDocument)); + } + return $element; + } + + /** + * Creates individual Entry objects of the appropriate type and + * stores them in the $_entry array based upon DOM data. + * + * @param DOMNode $child The DOMNode to process + */ + protected function takeChildFromDOM($child) + { + $absoluteNodeName = $child->namespaceURI . ':' . $child->localName; + + switch ($absoluteNodeName) { + case $this->lookupNamespace('yt') . ':' . 'statistics': + $statistics = new Zend_Gdata_YouTube_Extension_Statistics(); + $statistics->transferFromDOM($child); + $this->_statistics = $statistics; + break; + case $this->lookupNamespace('yt') . ':' . 'racy': + $racy = new Zend_Gdata_YouTube_Extension_Racy(); + $racy->transferFromDOM($child); + $this->_racy = $racy; + break; + case $this->lookupNamespace('yt') . ':' . 'recorded': + $recorded = new Zend_Gdata_YouTube_Extension_Recorded(); + $recorded->transferFromDOM($child); + $this->_recorded = $recorded; + break; + case $this->lookupNamespace('yt') . ':' . 'location': + $location = new Zend_Gdata_YouTube_Extension_Location(); + $location->transferFromDOM($child); + $this->_location = $location; + break; + case $this->lookupNamespace('gd') . ':' . 'rating': + $rating = new Zend_Gdata_Extension_Rating(); + $rating->transferFromDOM($child); + $this->_rating = $rating; + break; + case $this->lookupNamespace('gd') . ':' . 'comments': + $comments = new Zend_Gdata_Extension_Comments(); + $comments->transferFromDOM($child); + $this->_comments = $comments; + break; + case $this->lookupNamespace('yt') . ':' . 'noembed': + $noEmbed = new Zend_Gdata_YouTube_Extension_NoEmbed(); + $noEmbed->transferFromDOM($child); + $this->_noEmbed = $noEmbed; + break; + case $this->lookupNamespace('gd') . ':' . 'feedLink': + $feedLink = new Zend_Gdata_Extension_FeedLink(); + $feedLink->transferFromDOM($child); + $this->_feedLink[] = $feedLink; + break; + case $this->lookupNamespace('georss') . ':' . 'where': + $where = new Zend_Gdata_Geo_Extension_GeoRssWhere(); + $where->transferFromDOM($child); + $this->_where = $where; + break; + case $this->lookupNamespace('atom') . ':' . 'link'; + $link = new Zend_Gdata_YouTube_Extension_Link(); + $link->transferFromDOM($child); + $this->_link[] = $link; + break; + case $this->lookupNamespace('app') . ':' . 'control': + $control = new Zend_Gdata_YouTube_Extension_Control(); + $control->transferFromDOM($child); + $this->_control = $control; + break; + default: + parent::takeChildFromDOM($child); + break; + } + } + + /** + * Sets when the video was recorded. + * + * @param Zend_Gdata_YouTube_Extension_Recorded $recorded When the video was recorded + * @return Zend_Gdata_YouTube_VideoEntry Provides a fluent interface + */ + public function setRecorded($recorded = null) + { + $this->_recorded = $recorded; + return $this; + } + + /** + * Gets the date that the video was recorded. + * + * @return Zend_Gdata_YouTube_Extension_Recorded|null + */ + public function getRecorded() + { + return $this->_recorded; + } + + /** + * Sets the location information. + * + * @param Zend_Gdata_YouTube_Extension_Location $location Where the video + * was recorded + * @return Zend_Gdata_YouTube_VideoEntry Provides a fluent interface + */ + public function setLocation($location = null) + { + $this->_location = $location; + return $this; + } + + /** + * Gets the location where the video was recorded. + * + * @return Zend_Gdata_YouTube_Extension_Location|null + */ + public function getLocation() + { + return $this->_location; + } + + /** + * If an instance of Zend_Gdata_YouTube_Extension_NoEmbed is passed in, + * the video cannot be embedded. Otherwise, if null is passsed in, the + * video is able to be embedded. + * + * @param Zend_Gdata_YouTube_Extension_NoEmbed $noEmbed Whether or not the + * video can be embedded. + * @return Zend_Gdata_YouTube_VideoEntry Provides a fluent interface + */ + public function setNoEmbed($noEmbed = null) + { + $this->_noEmbed = $noEmbed; + return $this; + } + + /** + * If the return value is an instance of + * Zend_Gdata_YouTube_Extension_NoEmbed, this video cannot be embedded. + * + * @return Zend_Gdata_YouTube_Extension_NoEmbed|null Whether or not the video can be embedded + */ + public function getNoEmbed() + { + return $this->_noEmbed; + } + + /** + * Checks whether the video is embeddable. + * + * @return bool Returns true if the video is embeddable. + */ + public function isVideoEmbeddable() + { + if ($this->getNoEmbed() == null) { + return true; + } else { + return false; + } + } + + /** + * Sets the statistics relating to the video. + * + * @param Zend_Gdata_YouTube_Extension_Statistics $statistics The statistics relating to the video + * @return Zend_Gdata_YouTube_VideoEntry Provides a fluent interface + */ + public function setStatistics($statistics = null) + { + $this->_statistics = $statistics; + return $this; + } + + /** + * Returns the statistics relating to the video. + * + * @return Zend_Gdata_YouTube_Extension_Statistics The statistics relating to the video + */ + public function getStatistics() + { + return $this->_statistics; + } + + /** + * Specifies that the video has racy content. + * + * @param Zend_Gdata_YouTube_Extension_Racy $racy The racy flag object + * @throws Zend_Gdata_App_VersionException + * @return Zend_Gdata_YouTube_VideoEntry Provides a fluent interface + */ + public function setRacy($racy = null) + { + if ($this->getMajorProtocolVersion() == 2) { + require_once 'Zend/Gdata/App/VersionException.php'; + throw new Zend_Gdata_App_VersionException( + 'Calling getRacy() on a YouTube VideoEntry is deprecated ' . + 'as of version 2 of the API.'); + } + + $this->_racy = $racy; + return $this; + } + + /** + * Returns the racy flag object. + * + * @throws Zend_Gdata_App_VersionException + * @return Zend_Gdata_YouTube_Extension_Racy|null The racy flag object + */ + public function getRacy() + { + if ($this->getMajorProtocolVersion() == 2) { + require_once 'Zend/Gdata/App/VersionException.php'; + throw new Zend_Gdata_App_VersionException( + 'Calling getRacy() on a YouTube VideoEntry is deprecated ' . + 'as of version 2 of the API.'); + } + return $this->_racy; + } + + /** + * Sets the rating relating to the video. + * + * @param Zend_Gdata_Extension_Rating $rating The rating relating to the video + * @return Zend_Gdata_YouTube_VideoEntry Provides a fluent interface + */ + public function setRating($rating = null) + { + $this->_rating = $rating; + return $this; + } + + /** + * Returns the rating relating to the video. + * + * @return Zend_Gdata_Extension_Rating The rating relating to the video + */ + public function getRating() + { + return $this->_rating; + } + + /** + * Sets the comments relating to the video. + * + * @param Zend_Gdata_Extension_Comments $comments The comments relating to the video + * @return Zend_Gdata_YouTube_VideoEntry Provides a fluent interface + */ + public function setComments($comments = null) + { + $this->_comments = $comments; + return $this; + } + + /** + * Returns the comments relating to the video. + * + * @return Zend_Gdata_Extension_Comments The comments relating to the video + */ + public function getComments() + { + return $this->_comments; + } + + /** + * Sets the array of embedded feeds related to the video + * + * @param array $feedLink The array of embedded feeds relating to the video + * @return Zend_Gdata_YouTube_VideoEntry Provides a fluent interface + */ + public function setFeedLink($feedLink = null) + { + $this->_feedLink = $feedLink; + return $this; + } + + /** + * Get the feed link property for this entry. + * + * @see setFeedLink + * @param string $rel (optional) The rel value of the link to be found. + * If null, the array of links is returned. + * @return mixed If $rel is specified, a Zend_Gdata_Extension_FeedLink + * object corresponding to the requested rel value is returned + * if found, or null if the requested value is not found. If + * $rel is null or not specified, an array of all available + * feed links for this entry is returned, or null if no feed + * links are set. + */ + public function getFeedLink($rel = null) + { + if ($rel == null) { + return $this->_feedLink; + } else { + foreach ($this->_feedLink as $feedLink) { + if ($feedLink->rel == $rel) { + return $feedLink; + } + } + return null; + } + } + + /** + * Returns the link element relating to video responses. + * + * @return Zend_Gdata_App_Extension_Link + */ + public function getVideoResponsesLink() + { + return $this->getLink(Zend_Gdata_YouTube::VIDEO_RESPONSES_REL); + } + + /** + * Returns the link element relating to video ratings. + * + * @return Zend_Gdata_App_Extension_Link + */ + public function getVideoRatingsLink() + { + return $this->getLink(Zend_Gdata_YouTube::VIDEO_RATINGS_REL); + } + + /** + * Returns the link element relating to video complaints. + * + * @return Zend_Gdata_App_Extension_Link + */ + public function getVideoComplaintsLink() + { + return $this->getLink(Zend_Gdata_YouTube::VIDEO_COMPLAINTS_REL); + } + + /** + * Gets the YouTube video ID based upon the atom:id value + * + * @return string The video ID + */ + public function getVideoId() + { + if ($this->getMajorProtocolVersion() == 2) { + $videoId = $this->getMediaGroup()->getVideoId()->text; + } else { + $fullId = $this->getId()->getText(); + $position = strrpos($fullId, '/'); + if ($position === false) { + require_once 'Zend/Gdata/App/Exception.php'; + throw new Zend_Gdata_App_Exception( + 'Slash not found in atom:id of ' . $fullId); + } else { + $videoId = substr($fullId, $position + 1); + } + } + return $videoId; + } + + /** + * Gets the date that the video was recorded. + * + * @return string|null The date that the video was recorded + */ + public function getVideoRecorded() + { + $recorded = $this->getRecorded(); + if ($recorded != null) { + return $recorded->getText(); + } else { + return null; + } + } + + /** + * Sets the date that the video was recorded. + * + * @param string $recorded The date that the video was recorded, in the + * format of '2001-06-19' + */ + public function setVideoRecorded($recorded) + { + $this->setRecorded( + new Zend_Gdata_YouTube_Extension_Recorded($recorded)); + return $this; + } + + /** + * Gets the georss:where element + * + * @return Zend_Gdata_Geo_Extension_GeoRssWhere + */ + public function getWhere() + { + return $this->_where; + } + + /** + * Sets the georss:where element + * + * @param Zend_Gdata_Geo_Extension_GeoRssWhere $value The georss:where class value + * @return Zend_Gdata_YouTube_VideoEntry Provides a fluent interface + */ + public function setWhere($value) + { + $this->_where = $value; + return $this; + } + + /** + * Gets the title of the video as a string. null is returned + * if the video title is not available. + * + * @return string|null The title of the video + */ + public function getVideoTitle() + { + $this->ensureMediaGroupIsNotNull(); + if ($this->getMediaGroup()->getTitle() != null) { + return $this->getMediaGroup()->getTitle()->getText(); + } else { + return null; + } + } + + /** + * Sets the title of the video as a string. + * + * @param string $title Title for the video + * @return Zend_Gdata_YouTube_VideoEntry Provides a fluent interface + */ + public function setVideoTitle($title) + { + $this->ensureMediaGroupIsNotNull(); + $this->getMediaGroup()->setTitle( + new Zend_Gdata_Media_Extension_MediaTitle($title)); + return $this; + } + + /** + * Sets the description of the video as a string. + * + * @param string $description Description for the video + * @return Zend_Gdata_YouTube_VideoEntry Provides a fluent interface + */ + public function setVideoDescription($description) + { + $this->ensureMediaGroupIsNotNull(); + $this->getMediaGroup()->setDescription( + new Zend_Gdata_Media_Extension_MediaDescription($description)); + return $this; + } + + + /** + * Gets the description of the video as a string. null is returned + * if the video description is not available. + * + * @return string|null The description of the video + */ + public function getVideoDescription() + { + $this->ensureMediaGroupIsNotNull(); + if ($this->getMediaGroup()->getDescription() != null) { + return $this->getMediaGroup()->getDescription()->getText(); + } else { + return null; + } + } + + /** + * Gets the URL of the YouTube video watch page. null is returned + * if the video watch page URL is not available. + * + * @return string|null The URL of the YouTube video watch page + */ + public function getVideoWatchPageUrl() + { + $this->ensureMediaGroupIsNotNull(); + if ($this->getMediaGroup()->getPlayer() != null && + array_key_exists(0, $this->getMediaGroup()->getPlayer())) { + $players = $this->getMediaGroup()->getPlayer(); + return $players[0]->getUrl(); + } else { + return null; + } + } + + /** + * Gets an array of the thumbnails representing the video. + * Each thumbnail is an element of the array, and is an + * array of the thumbnail properties - time, height, width, + * and url. For convient usage inside a foreach loop, an + * empty array is returned if there are no thumbnails. + * + * @return array An array of video thumbnails. + */ + public function getVideoThumbnails() + { + $this->ensureMediaGroupIsNotNull(); + if ($this->getMediaGroup()->getThumbnail() != null) { + + $thumbnailArray = array(); + + foreach ($this->getMediaGroup()->getThumbnail() as $thumbnailObj) { + $thumbnail = array(); + $thumbnail['time'] = $thumbnailObj->time; + $thumbnail['height'] = $thumbnailObj->height; + $thumbnail['width'] = $thumbnailObj->width; + $thumbnail['url'] = $thumbnailObj->url; + $thumbnailArray[] = $thumbnail; + } + return $thumbnailArray; + } else { + return array(); + } + } + + /** + * Gets the URL of the flash player SWF. null is returned if the + * duration value is not available. + * + * @return string|null The URL of the flash player SWF + */ + public function getFlashPlayerUrl() + { + $this->ensureMediaGroupIsNotNull(); + foreach ($this->getMediaGroup()->getContent() as $content) { + if ($content->getType() === 'application/x-shockwave-flash') { + return $content->getUrl(); + } + } + return null; + } + + /** + * Gets the duration of the video, in seconds. null is returned + * if the duration value is not available. + * + * @return string|null The duration of the video, in seconds. + */ + public function getVideoDuration() + { + $this->ensureMediaGroupIsNotNull(); + if ($this->getMediaGroup()->getDuration() != null) { + return $this->getMediaGroup()->getDuration()->getSeconds(); + } else { + return null; + } + } + + /** + * Checks whether the video is private. + * + * @return bool Return true if video is private + */ + public function isVideoPrivate() + { + $this->ensureMediaGroupIsNotNull(); + if ($this->getMediaGroup()->getPrivate() != null) { + return true; + } else { + return false; + } + } + + /** + * Sets video to private. + * + * @return Zend_Gdata_YouTube_VideoEntry Provides a fluent interface + */ + public function setVideoPrivate() + { + $this->ensureMediaGroupIsNotNull(); + $this->getMediaGroup()->setPrivate(new Zend_Gdata_YouTube_Extension_Private()); + return $this; + } + + /** + * Sets a private video to be public. + * + * @return Zend_Gdata_YouTube_VideoEntry Provides a fluent interface + */ + public function setVideoPublic() + { + $this->ensureMediaGroupIsNotNull(); + $this->getMediaGroup()->private = null; + return $this; + } + + /** + * Gets an array of the tags assigned to this video. For convient + * usage inside a foreach loop, an empty array is returned when there + * are no tags assigned. + * + * @return array An array of the tags assigned to this video + */ + public function getVideoTags() + { + $this->ensureMediaGroupIsNotNull(); + if ($this->getMediaGroup()->getKeywords() != null) { + + $keywords = $this->getMediaGroup()->getKeywords(); + $keywordsString = $keywords->getText(); + if (strlen(trim($keywordsString)) > 0) { + return preg_split('/(, *)|,/', $keywordsString); + } + } + return array(); + } + + /** + * Sets the keyword tags for a video. + * + * @param mixed $tags Either a comma-separated string or an array + * of tags for the video + * @return Zend_Gdata_YouTube_VideoEntry Provides a fluent interface + */ + public function setVideoTags($tags) + { + $this->ensureMediaGroupIsNotNull(); + $keywords = new Zend_Gdata_Media_Extension_MediaKeywords(); + if (is_array($tags)) { + $tags = implode(', ', $tags); + } + $keywords->setText($tags); + $this->getMediaGroup()->setKeywords($keywords); + return $this; + } + + /** + * Gets the number of views for this video. null is returned if the + * number of views is not available. + * + * @return string|null The number of views for this video + */ + public function getVideoViewCount() + { + if ($this->getStatistics() != null) { + return $this->getStatistics()->getViewCount(); + } else { + return null; + } + } + + /** + * Gets the location specified for this video, if available. The location + * is returned as an array containing the keys 'longitude' and 'latitude'. + * null is returned if the location is not available. + * + * @return array|null The location specified for this video + */ + public function getVideoGeoLocation() + { + if ($this->getWhere() != null && + $this->getWhere()->getPoint() != null && + ($position = $this->getWhere()->getPoint()->getPos()) != null) { + + $positionString = $position->__toString(); + + if (strlen(trim($positionString)) > 0) { + $positionArray = explode(' ', trim($positionString)); + if (count($positionArray) == 2) { + $returnArray = array(); + $returnArray['latitude'] = $positionArray[0]; + $returnArray['longitude'] = $positionArray[1]; + return $returnArray; + } + } + } + return null; + } + + /** + * Gets the rating information for this video, if available. The rating + * is returned as an array containing the keys 'average' and 'numRaters'. + * null is returned if the rating information is not available. + * + * @return array|null The rating information for this video + */ + public function getVideoRatingInfo() + { + if ($this->getRating() != null) { + $returnArray = array(); + $returnArray['average'] = $this->getRating()->getAverage(); + $returnArray['numRaters'] = $this->getRating()->getNumRaters(); + return $returnArray; + } else { + return null; + } + } + + /** + * Gets the category of this video, if available. The category is returned + * as a string. Valid categories are found at: + * http://gdata.youtube.com/schemas/2007/categories.cat + * If the category is not set, null is returned. + * + * @return string|null The category of this video + */ + public function getVideoCategory() + { + $this->ensureMediaGroupIsNotNull(); + $categories = $this->getMediaGroup()->getCategory(); + if ($categories != null) { + foreach($categories as $category) { + if ($category->getScheme() == self::YOUTUBE_CATEGORY_SCHEMA) { + return $category->getText(); + } + } + } + return null; + } + + /** + * Sets the category of the video as a string. + * + * @param string $category Categories for the video + * @return Zend_Gdata_YouTube_VideoEntry Provides a fluent interface + */ + public function setVideoCategory($category) + { + $this->ensureMediaGroupIsNotNull(); + $this->getMediaGroup()->setCategory(array(new Zend_Gdata_Media_Extension_MediaCategory($category, self::YOUTUBE_CATEGORY_SCHEMA))); + return $this; + } + + /** + * Gets the developer tags for the video, if available and if client is + * authenticated with a valid developerKey. The tags are returned + * as an array. + * If no tags are set, null is returned. + * + * @return array|null The developer tags for this video or null if none were set. + */ + public function getVideoDeveloperTags() + { + $developerTags = null; + $this->ensureMediaGroupIsNotNull(); + + $categoryArray = $this->getMediaGroup()->getCategory(); + if ($categoryArray != null) { + foreach ($categoryArray as $category) { + if ($category instanceof Zend_Gdata_Media_Extension_MediaCategory) { + if ($category->getScheme() == self::YOUTUBE_DEVELOPER_TAGS_SCHEMA) { + $developerTags[] = $category->getText(); + } + } + } + return $developerTags; + } + return null; + } + + /** + * Adds a developer tag to array of tags for the video. + * + * @param string $developerTag DeveloperTag for the video + * @return Zend_Gdata_YouTube_VideoEntry Provides a fluent interface + */ + public function addVideoDeveloperTag($developerTag) + { + $this->ensureMediaGroupIsNotNull(); + $newCategory = new Zend_Gdata_Media_Extension_MediaCategory($developerTag, self::YOUTUBE_DEVELOPER_TAGS_SCHEMA); + + if ($this->getMediaGroup()->getCategory() == null) { + $this->getMediaGroup()->setCategory($newCategory); + } else { + $categories = $this->getMediaGroup()->getCategory(); + $categories[] = $newCategory; + $this->getMediaGroup()->setCategory($categories); + } + return $this; + } + + /** + * Set multiple developer tags for the video as strings. + * + * @param array $developerTags Array of developerTag for the video + * @return Zend_Gdata_YouTube_VideoEntry Provides a fluent interface + */ + public function setVideoDeveloperTags($developerTags) + { + foreach($developerTags as $developerTag) { + $this->addVideoDeveloperTag($developerTag); + } + return $this; + } + + + /** + * Get the current publishing state of the video. + * + * @return Zend_Gdata_YouTube_Extension_State|null The publishing state of this video + */ + public function getVideoState() + { + $control = $this->getControl(); + if ($control != null && + $control->getDraft() != null && + $control->getDraft()->getText() == 'yes') { + + return $control->getState(); + } + return null; + } + + /** + * Get the VideoEntry's Zend_Gdata_YouTube_Extension_MediaGroup object. + * If the mediaGroup does not exist, then set it. + * + * @return void + */ + public function ensureMediaGroupIsNotNull() + { + if ($this->getMediagroup() == null) { + $this->setMediagroup(new Zend_Gdata_YouTube_Extension_MediaGroup()); + } + } + + /** + * Helper function to conveniently set a video's rating. + * + * @param integer $ratingValue A number representing the rating. Must + * be between 1 and 5 inclusive. + * @throws Zend_Gdata_Exception + * @return Zend_Gdata_YouTube_VideoEntry Provides a fluent interface. + */ + public function setVideoRating($ratingValue) + { + if ($ratingValue < 1 || $ratingValue > 5) { + require_once 'Zend/Gdata/App/InvalidArgumentException.php'; + throw new Zend_Gdata_App_InvalidArgumentException( + 'Rating for video entry must be between 1 and 5 inclusive.'); + } + + require_once 'Zend/Gdata/Extension/Rating.php'; + $rating = new Zend_Gdata_Extension_Rating(null, 1, 5, null, + $ratingValue); + $this->setRating($rating); + return $this; + } + + /** + * Retrieve the URL for a video's comment feed. + * + * @return string|null The URL if found, or null if not found. + */ + public function getVideoCommentFeedUrl() + { + $commentsExtension = $this->getComments(); + $commentsFeedUrl = null; + if ($commentsExtension) { + $commentsFeedLink = $commentsExtension->getFeedLink(); + if ($commentsFeedLink) { + $commentsFeedUrl = $commentsFeedLink->getHref(); + } + } + return $commentsFeedUrl; + } + +} diff --git a/Zend/Gdata/YouTube/VideoFeed.php b/Zend/Gdata/YouTube/VideoFeed.php new file mode 100644 index 00000000..702a93ac --- /dev/null +++ b/Zend/Gdata/YouTube/VideoFeed.php @@ -0,0 +1,65 @@ +registerAllNamespaces(Zend_Gdata_YouTube::$namespaces); + parent::__construct($element); + } + +} diff --git a/Zend/Gdata/YouTube/VideoQuery.php b/Zend/Gdata/YouTube/VideoQuery.php new file mode 100644 index 00000000..7f3f20c3 --- /dev/null +++ b/Zend/Gdata/YouTube/VideoQuery.php @@ -0,0 +1,540 @@ +_url = Zend_Gdata_YouTube::STANDARD_TOP_RATED_URI; + break; + case 'most viewed': + $this->_url = Zend_Gdata_YouTube::STANDARD_MOST_VIEWED_URI; + break; + case 'recently featured': + $this->_url = Zend_Gdata_YouTube::STANDARD_RECENTLY_FEATURED_URI; + break; + case 'mobile': + $this->_url = Zend_Gdata_YouTube::STANDARD_WATCH_ON_MOBILE_URI; + break; + case 'related': + if ($videoId === null) { + require_once 'Zend/Gdata/App/InvalidArgumentException.php'; + throw new Zend_Gdata_App_InvalidArgumentException( + 'Video ID must be set for feed of type: ' . $feedType); + } else { + $this->_url = Zend_Gdata_YouTube::VIDEO_URI . '/' . $videoId . + '/related'; + } + break; + case 'responses': + if ($videoId === null) { + require_once 'Zend/Gdata/App/InvalidArgumentException.php'; + throw new Zend_Gdata_App_Exception( + 'Video ID must be set for feed of type: ' . $feedType); + } else { + $this->_url = Zend_Gdata_YouTube::VIDEO_URI . '/' . $videoId . + 'responses'; + } + break; + case 'comments': + if ($videoId === null) { + require_once 'Zend/Gdata/App/InvalidArgumentException.php'; + throw new Zend_Gdata_App_Exception( + 'Video ID must be set for feed of type: ' . $feedType); + } else { + $this->_url = Zend_Gdata_YouTube::VIDEO_URI . '/' . + $videoId . 'comments'; + if ($entry !== null) { + $this->_url .= '/' . $entry; + } + } + break; + default: + require_once 'Zend/Gdata/App/Exception.php'; + throw new Zend_Gdata_App_Exception('Unknown feed type'); + break; + } + } + + /** + * Sets the location parameter for the query + * + * @param string $value + * @throws Zend_Gdata_App_InvalidArgumentException + * @return Zend_Gdata_YouTube_VideoQuery Provides a fluent interface + */ + public function setLocation($value) + { + switch($value) { + case null: + unset($this->_params['location']); + default: + $parameters = explode(',', $value); + if (count($parameters) != 2) { + require_once 'Zend/Gdata/App/InvalidArgumentException.php'; + throw new Zend_Gdata_App_InvalidArgumentException( + 'You must provide 2 coordinates to the location ' . + 'URL parameter'); + } + + foreach($parameters as $param) { + $temp = trim($param); + // strip off the optional exclamation mark for numeric check + if (substr($temp, -1) == '!') { + $temp = substr($temp, 0, -1); + } + if (!is_numeric($temp)) { + require_once 'Zend/Gdata/App/InvalidArgumentException.php'; + throw new Zend_Gdata_App_InvalidArgumentException( + 'Value provided to location parameter must' . + ' be in the form of two coordinates'); + } + } + $this->_params['location'] = $value; + } + } + + /** + * Get the value of the location parameter + * + * @return string|null Return the location if it exists, null otherwise. + */ + public function getLocation() + { + if (array_key_exists('location', $this->_params)) { + return $this->_params['location']; + } else { + return null; + } + } + + + /** + * Sets the location-radius parameter for the query + * + * @param string $value + * @return Zend_Gdata_YouTube_VideoQuery Provides a fluent interface + */ + public function setLocationRadius($value) + { + switch($value) { + case null: + unset($this->_params['location-radius']); + default: + $this->_params['location-radius'] = $value; + } + } + + /** + * Get the value of the location-radius parameter + * + * @return string|null Return the location-radius if it exists, + * null otherwise. + */ + public function getLocationRadius() + { + if (array_key_exists('location-radius', $this->_params)) { + return $this->_params['location-radius']; + } else { + return null; + } + } + + /** + * Sets the time period over which this query should apply + * + * @param string $value + * @throws Zend_Gdata_App_InvalidArgumentException + * @return Zend_Gdata_YouTube_VideoQuery Provides a fluent interface + */ + public function setTime($value = null) + { + switch ($value) { + case 'today': + $this->_params['time'] = 'today'; + break; + case 'this_week': + $this->_params['time'] = 'this_week'; + break; + case 'this_month': + $this->_params['time'] = 'this_month'; + break; + case 'all_time': + $this->_params['time'] = 'all_time'; + break; + case null: + unset($this->_params['time']); + default: + require_once 'Zend/Gdata/App/InvalidArgumentException.php'; + throw new Zend_Gdata_App_InvalidArgumentException( + 'Unknown time value'); + break; + } + return $this; + } + + /** + * Sets the value of the uploader parameter + * + * @param string $value The value of the uploader parameter. Currently this + * can only be set to the value of 'partner'. + * @throws Zend_Gdata_App_InvalidArgumentException + * @return Zend_Gdata_YouTube_VideoQuery Provides a fluent interface + */ + public function setUploader($value = null) + { + switch ($value) { + case 'partner': + $this->_params['uploader'] = 'partner'; + break; + case null: + unset($this->_params['uploader']); + break; + default: + require_once 'Zend/Gdata/App/InvalidArgumentException.php'; + throw new Zend_Gdata_App_InvalidArgumentException( + 'Unknown value for uploader'); + } + return $this; + } + + /** + * Sets the formatted video query (vq) URL param value + * + * @param string $value + * @return Zend_Gdata_YouTube_VideoQuery Provides a fluent interface + */ + public function setVideoQuery($value = null) + { + if ($value != null) { + $this->_params['vq'] = $value; + } else { + unset($this->_params['vq']); + } + return $this; + } + + /** + * Sets the param to return videos of a specific format + * + * @param string $value + * @return Zend_Gdata_YouTube_VideoQuery Provides a fluent interface + */ + public function setFormat($value = null) + { + if ($value != null) { + $this->_params['format'] = $value; + } else { + unset($this->_params['format']); + } + return $this; + } + + /** + * Sets whether or not to include racy videos in the search results + * + * @param string $value + * @return Zend_Gdata_YouTube_VideoQuery Provides a fluent interface + */ + public function setRacy($value = null) + { + switch ($value) { + case 'include': + $this->_params['racy'] = $value; + break; + case 'exclude': + $this->_params['racy'] = $value; + break; + case null: + unset($this->_params['racy']); + break; + } + return $this; + } + + /** + * Whether or not to include racy videos in the search results + * + * @return string|null The value of racy if it exists, null otherwise. + */ + public function getRacy() + { + if (array_key_exists('racy', $this->_params)) { + return $this->_params['racy']; + } else { + return null; + } + } + + /** + * Set the safeSearch parameter + * + * @param string $value The value of the parameter, currently only 'none', + * 'moderate' or 'strict' are allowed values. + * @throws Zend_Gdata_App_InvalidArgumentException + * @return Zend_Gdata_YouTube_VideoQuery Provides a fluent interface + */ + public function setSafeSearch($value) + { + switch ($value) { + case 'none': + $this->_params['safeSearch'] = 'none'; + break; + case 'moderate': + $this->_params['safeSearch'] = 'moderate'; + break; + case 'strict': + $this->_params['safeSearch'] = 'strict'; + break; + case null: + unset($this->_params['safeSearch']); + default: + require_once 'Zend/Gdata/App/InvalidArgumentException.php'; + throw new Zend_Gdata_App_InvalidArgumentException( + 'The safeSearch parameter only supports the values '. + '\'none\', \'moderate\' or \'strict\'.'); + } + } + + /** + * Return the value of the safeSearch parameter + * + * @return string|null The value of the safeSearch parameter if it has been + * set, null otherwise. + */ + public function getSafeSearch() + { + if (array_key_exists('safeSearch', $this->_params)) { + return $this->_params['safeSearch']; + } + return $this; + } + + /** + * Set the value of the orderby parameter + * + * @param string $value + * @return Zend_Gdata_YouTube_Query Provides a fluent interface + */ + public function setOrderBy($value) + { + if ($value != null) { + $this->_params['orderby'] = $value; + } else { + unset($this->_params['orderby']); + } + return $this; + } + + /** + * Return the value of the format parameter + * + * @return string|null The value of format if it exists, null otherwise. + */ + public function getFormat() + { + if (array_key_exists('format', $this->_params)) { + return $this->_params['format']; + } else { + return null; + } + } + + /** + * Return the value of the video query that has been set + * + * @return string|null The value of the video query if it exists, + * null otherwise. + */ + public function getVideoQuery() + { + if (array_key_exists('vq', $this->_params)) { + return $this->_params['vq']; + } else { + return null; + } + } + + /** + * Return the value of the time parameter + * + * @return string|null The time parameter if it exists, null otherwise. + */ + public function getTime() + { + if (array_key_exists('time', $this->_params)) { + return $this->_params['time']; + } else { + return null; + } + } + + /** + * Return the value of the orderby parameter if it exists + * + * @return string|null The value of orderby if it exists, null otherwise. + */ + public function getOrderBy() + { + if (array_key_exists('orderby', $this->_params)) { + return $this->_params['orderby']; + } else { + return null; + } + } + + /** + * Generate the query string from the URL parameters, optionally modifying + * them based on protocol version. + * + * @param integer $majorProtocolVersion The major protocol version + * @param integer $minorProtocolVersion The minor protocol version + * @throws Zend_Gdata_App_VersionException + * @return string querystring + */ + public function getQueryString($majorProtocolVersion = null, + $minorProtocolVersion = null) + { + $queryArray = array(); + + foreach ($this->_params as $name => $value) { + if (substr($name, 0, 1) == '_') { + continue; + } + + switch($name) { + case 'location-radius': + if ($majorProtocolVersion == 1) { + require_once 'Zend/Gdata/App/VersionException.php'; + throw new Zend_Gdata_App_VersionException("The $name " . + "parameter is only supported in version 2."); + } + break; + + case 'racy': + if ($majorProtocolVersion == 2) { + require_once 'Zend/Gdata/App/VersionException.php'; + throw new Zend_Gdata_App_VersionException("The $name " . + "parameter is not supported in version 2. " . + "Please use 'safeSearch'."); + } + break; + + case 'safeSearch': + if ($majorProtocolVersion == 1) { + require_once 'Zend/Gdata/App/VersionException.php'; + throw new Zend_Gdata_App_VersionException("The $name " . + "parameter is only supported in version 2. " . + "Please use 'racy'."); + } + break; + + case 'uploader': + if ($majorProtocolVersion == 1) { + require_once 'Zend/Gdata/App/VersionException.php'; + throw new Zend_Gdata_App_VersionException("The $name " . + "parameter is only supported in version 2."); + } + break; + + case 'vq': + if ($majorProtocolVersion == 2) { + $name = 'q'; + } + break; + } + + $queryArray[] = urlencode($name) . '=' . urlencode($value); + + } + if (count($queryArray) > 0) { + return '?' . implode('&', $queryArray); + } else { + return ''; + } + } + + /** + * Returns the generated full query URL, optionally modifying it based on + * the protocol version. + * + * @param integer $majorProtocolVersion The major protocol version + * @param integer $minorProtocolVersion The minor protocol version + * @return string The URL + */ + public function getQueryUrl($majorProtocolVersion = null, + $minorProtocolVersion = null) + { + if (isset($this->_url)) { + $url = $this->_url; + } else { + $url = Zend_Gdata_YouTube::VIDEO_URI; + } + if ($this->getCategory() !== null) { + $url .= '/-/' . $this->getCategory(); + } + $url = $url . $this->getQueryString($majorProtocolVersion, + $minorProtocolVersion); + return $url; + } + +} diff --git a/Zend/Http/Client.php b/Zend/Http/Client.php new file mode 100644 index 00000000..7627a638 --- /dev/null +++ b/Zend/Http/Client.php @@ -0,0 +1,1453 @@ + 5, + 'strictredirects' => false, + 'useragent' => 'Zend_Http_Client', + 'timeout' => 10, + 'adapter' => 'Zend_Http_Client_Adapter_Socket', + 'httpversion' => self::HTTP_1, + 'keepalive' => false, + 'storeresponse' => true, + 'strict' => true, + 'output_stream' => false, + 'encodecookies' => true, + ); + + /** + * The adapter used to preform the actual connection to the server + * + * @var Zend_Http_Client_Adapter_Interface + */ + protected $adapter = null; + + /** + * Request URI + * + * @var Zend_Uri_Http + */ + protected $uri = null; + + /** + * Associative array of request headers + * + * @var array + */ + protected $headers = array(); + + /** + * HTTP request method + * + * @var string + */ + protected $method = self::GET; + + /** + * Associative array of GET parameters + * + * @var array + */ + protected $paramsGet = array(); + + /** + * Assiciative array of POST parameters + * + * @var array + */ + protected $paramsPost = array(); + + /** + * Request body content type (for POST requests) + * + * @var string + */ + protected $enctype = null; + + /** + * The raw post data to send. Could be set by setRawData($data, $enctype). + * + * @var string + */ + protected $raw_post_data = null; + + /** + * HTTP Authentication settings + * + * Expected to be an associative array with this structure: + * $this->auth = array('user' => 'username', 'password' => 'password', 'type' => 'basic') + * Where 'type' should be one of the supported authentication types (see the AUTH_* + * constants), for example 'basic' or 'digest'. + * + * If null, no authentication will be used. + * + * @var array|null + */ + protected $auth; + + /** + * File upload arrays (used in POST requests) + * + * An associative array, where each element is of the format: + * 'name' => array('filename.txt', 'text/plain', 'This is the actual file contents') + * + * @var array + */ + protected $files = array(); + + /** + * The client's cookie jar + * + * @var Zend_Http_CookieJar + */ + protected $cookiejar = null; + + /** + * The last HTTP request sent by the client, as string + * + * @var string + */ + protected $last_request = null; + + /** + * The last HTTP response received by the client + * + * @var Zend_Http_Response + */ + protected $last_response = null; + + /** + * Redirection counter + * + * @var int + */ + protected $redirectCounter = 0; + + /** + * Fileinfo magic database resource + * + * This varaiable is populated the first time _detectFileMimeType is called + * and is then reused on every call to this method + * + * @var resource + */ + static protected $_fileInfoDb = null; + + /** + * Contructor method. Will create a new HTTP client. Accepts the target + * URL and optionally configuration array. + * + * @param Zend_Uri_Http|string $uri + * @param array $config Configuration key-value pairs. + */ + public function __construct($uri = null, $config = null) + { + if ($uri !== null) { + $this->setUri($uri); + } + if ($config !== null) { + $this->setConfig($config); + } + } + + /** + * Set the URI for the next request + * + * @param Zend_Uri_Http|string $uri + * @return Zend_Http_Client + * @throws Zend_Http_Client_Exception + */ + public function setUri($uri) + { + if (is_string($uri)) { + $uri = Zend_Uri::factory($uri); + } + + if (!$uri instanceof Zend_Uri_Http) { + /** @see Zend_Http_Client_Exception */ + require_once 'Zend/Http/Client/Exception.php'; + throw new Zend_Http_Client_Exception('Passed parameter is not a valid HTTP URI.'); + } + + // Set auth if username and password has been specified in the uri + if ($uri->getUsername() && $uri->getPassword()) { + $this->setAuth($uri->getUsername(), $uri->getPassword()); + } + + // We have no ports, set the defaults + if (! $uri->getPort()) { + $uri->setPort(($uri->getScheme() == 'https' ? 443 : 80)); + } + + $this->uri = $uri; + + return $this; + } + + /** + * Get the URI for the next request + * + * @param boolean $as_string If true, will return the URI as a string + * @return Zend_Uri_Http|string + */ + public function getUri($as_string = false) + { + if ($as_string && $this->uri instanceof Zend_Uri_Http) { + return $this->uri->__toString(); + } else { + return $this->uri; + } + } + + /** + * Set configuration parameters for this HTTP client + * + * @param Zend_Config | array $config + * @return Zend_Http_Client + * @throws Zend_Http_Client_Exception + */ + public function setConfig($config = array()) + { + if ($config instanceof Zend_Config) { + $config = $config->toArray(); + + } elseif (! is_array($config)) { + /** @see Zend_Http_Client_Exception */ + require_once 'Zend/Http/Client/Exception.php'; + throw new Zend_Http_Client_Exception('Array or Zend_Config object expected, got ' . gettype($config)); + } + + foreach ($config as $k => $v) { + $this->config[strtolower($k)] = $v; + } + + // Pass configuration options to the adapter if it exists + if ($this->adapter instanceof Zend_Http_Client_Adapter_Interface) { + $this->adapter->setConfig($config); + } + + return $this; + } + + /** + * Set the next request's method + * + * Validated the passed method and sets it. If we have files set for + * POST requests, and the new method is not POST, the files are silently + * dropped. + * + * @param string $method + * @return Zend_Http_Client + * @throws Zend_Http_Client_Exception + */ + public function setMethod($method = self::GET) + { + if (! preg_match('/^[^\x00-\x1f\x7f-\xff\(\)<>@,;:\\\\"\/\[\]\?={}\s]+$/', $method)) { + /** @see Zend_Http_Client_Exception */ + require_once 'Zend/Http/Client/Exception.php'; + throw new Zend_Http_Client_Exception("'{$method}' is not a valid HTTP request method."); + } + + if ($method == self::POST && $this->enctype === null) { + $this->setEncType(self::ENC_URLENCODED); + } + + $this->method = $method; + + return $this; + } + + /** + * Set one or more request headers + * + * This function can be used in several ways to set the client's request + * headers: + * 1. By providing two parameters: $name as the header to set (eg. 'Host') + * and $value as it's value (eg. 'www.example.com'). + * 2. By providing a single header string as the only parameter + * eg. 'Host: www.example.com' + * 3. By providing an array of headers as the first parameter + * eg. array('host' => 'www.example.com', 'x-foo: bar'). In This case + * the function will call itself recursively for each array item. + * + * @param string|array $name Header name, full header string ('Header: value') + * or an array of headers + * @param mixed $value Header value or null + * @return Zend_Http_Client + * @throws Zend_Http_Client_Exception + */ + public function setHeaders($name, $value = null) + { + // If we got an array, go recusive! + if (is_array($name)) { + foreach ($name as $k => $v) { + if (is_string($k)) { + $this->setHeaders($k, $v); + } else { + $this->setHeaders($v, null); + } + } + } else { + // Check if $name needs to be split + if ($value === null && (strpos($name, ':') > 0)) { + list($name, $value) = explode(':', $name, 2); + } + + // Make sure the name is valid if we are in strict mode + if ($this->config['strict'] && (! preg_match('/^[a-zA-Z0-9-]+$/', $name))) { + /** @see Zend_Http_Client_Exception */ + require_once 'Zend/Http/Client/Exception.php'; + throw new Zend_Http_Client_Exception("{$name} is not a valid HTTP header name"); + } + + $normalized_name = strtolower($name); + + // If $value is null or false, unset the header + if ($value === null || $value === false) { + unset($this->headers[$normalized_name]); + + // Else, set the header + } else { + // Header names are stored lowercase internally. + if (is_string($value)) { + $value = trim($value); + } + $this->headers[$normalized_name] = array($name, $value); + } + } + + return $this; + } + + /** + * Get the value of a specific header + * + * Note that if the header has more than one value, an array + * will be returned. + * + * @param string $key + * @return string|array|null The header value or null if it is not set + */ + public function getHeader($key) + { + $key = strtolower($key); + if (isset($this->headers[$key])) { + return $this->headers[$key][1]; + } else { + return null; + } + } + + /** + * Set a GET parameter for the request. Wrapper around _setParameter + * + * @param string|array $name + * @param string $value + * @return Zend_Http_Client + */ + public function setParameterGet($name, $value = null) + { + if (is_array($name)) { + foreach ($name as $k => $v) + $this->_setParameter('GET', $k, $v); + } else { + $this->_setParameter('GET', $name, $value); + } + + return $this; + } + + /** + * Set a POST parameter for the request. Wrapper around _setParameter + * + * @param string|array $name + * @param string $value + * @return Zend_Http_Client + */ + public function setParameterPost($name, $value = null) + { + if (is_array($name)) { + foreach ($name as $k => $v) + $this->_setParameter('POST', $k, $v); + } else { + $this->_setParameter('POST', $name, $value); + } + + return $this; + } + + /** + * Set a GET or POST parameter - used by SetParameterGet and SetParameterPost + * + * @param string $type GET or POST + * @param string $name + * @param string $value + * @return null + */ + protected function _setParameter($type, $name, $value) + { + $parray = array(); + $type = strtolower($type); + switch ($type) { + case 'get': + $parray = &$this->paramsGet; + break; + case 'post': + $parray = &$this->paramsPost; + break; + } + + if ($value === null) { + if (isset($parray[$name])) unset($parray[$name]); + } else { + $parray[$name] = $value; + } + } + + /** + * Get the number of redirections done on the last request + * + * @return int + */ + public function getRedirectionsCount() + { + return $this->redirectCounter; + } + + /** + * Set HTTP authentication parameters + * + * $type should be one of the supported types - see the self::AUTH_* + * constants. + * + * To enable authentication: + * + * $this->setAuth('shahar', 'secret', Zend_Http_Client::AUTH_BASIC); + * + * + * To disable authentication: + * + * $this->setAuth(false); + * + * + * @see http://www.faqs.org/rfcs/rfc2617.html + * @param string|false $user User name or false disable authentication + * @param string $password Password + * @param string $type Authentication type + * @return Zend_Http_Client + * @throws Zend_Http_Client_Exception + */ + public function setAuth($user, $password = '', $type = self::AUTH_BASIC) + { + // If we got false or null, disable authentication + if ($user === false || $user === null) { + $this->auth = null; + + // Clear the auth information in the uri instance as well + if ($this->uri instanceof Zend_Uri_Http) { + $this->getUri()->setUsername(''); + $this->getUri()->setPassword(''); + } + // Else, set up authentication + } else { + // Check we got a proper authentication type + if (! defined('self::AUTH_' . strtoupper($type))) { + /** @see Zend_Http_Client_Exception */ + require_once 'Zend/Http/Client/Exception.php'; + throw new Zend_Http_Client_Exception("Invalid or not supported authentication type: '$type'"); + } + + $this->auth = array( + 'user' => (string) $user, + 'password' => (string) $password, + 'type' => $type + ); + } + + return $this; + } + + /** + * Set the HTTP client's cookie jar. + * + * A cookie jar is an object that holds and maintains cookies across HTTP requests + * and responses. + * + * @param Zend_Http_CookieJar|boolean $cookiejar Existing cookiejar object, true to create a new one, false to disable + * @return Zend_Http_Client + * @throws Zend_Http_Client_Exception + */ + public function setCookieJar($cookiejar = true) + { + Zend_Loader::loadClass('Zend_Http_CookieJar'); + + if ($cookiejar instanceof Zend_Http_CookieJar) { + $this->cookiejar = $cookiejar; + } elseif ($cookiejar === true) { + $this->cookiejar = new Zend_Http_CookieJar(); + } elseif (! $cookiejar) { + $this->cookiejar = null; + } else { + /** @see Zend_Http_Client_Exception */ + require_once 'Zend/Http/Client/Exception.php'; + throw new Zend_Http_Client_Exception('Invalid parameter type passed as CookieJar'); + } + + return $this; + } + + /** + * Return the current cookie jar or null if none. + * + * @return Zend_Http_CookieJar|null + */ + public function getCookieJar() + { + return $this->cookiejar; + } + + /** + * Add a cookie to the request. If the client has no Cookie Jar, the cookies + * will be added directly to the headers array as "Cookie" headers. + * + * @param Zend_Http_Cookie|string $cookie + * @param string|null $value If "cookie" is a string, this is the cookie value. + * @return Zend_Http_Client + * @throws Zend_Http_Client_Exception + */ + public function setCookie($cookie, $value = null) + { + Zend_Loader::loadClass('Zend_Http_Cookie'); + + if (is_array($cookie)) { + foreach ($cookie as $c => $v) { + if (is_string($c)) { + $this->setCookie($c, $v); + } else { + $this->setCookie($v); + } + } + + return $this; + } + + if ($value !== null && $this->config['encodecookies']) { + $value = urlencode($value); + } + + if (isset($this->cookiejar)) { + if ($cookie instanceof Zend_Http_Cookie) { + $this->cookiejar->addCookie($cookie); + } elseif (is_string($cookie) && $value !== null) { + $cookie = Zend_Http_Cookie::fromString("{$cookie}={$value}", + $this->uri, + $this->config['encodecookies']); + $this->cookiejar->addCookie($cookie); + } + } else { + if ($cookie instanceof Zend_Http_Cookie) { + $name = $cookie->getName(); + $value = $cookie->getValue(); + $cookie = $name; + } + + if (preg_match("/[=,; \t\r\n\013\014]/", $cookie)) { + /** @see Zend_Http_Client_Exception */ + require_once 'Zend/Http/Client/Exception.php'; + throw new Zend_Http_Client_Exception("Cookie name cannot contain these characters: =,; \t\r\n\013\014 ({$cookie})"); + } + + $value = addslashes($value); + + if (! isset($this->headers['cookie'])) { + $this->headers['cookie'] = array('Cookie', ''); + } + $this->headers['cookie'][1] .= $cookie . '=' . $value . '; '; + } + + return $this; + } + + /** + * Set a file to upload (using a POST request) + * + * Can be used in two ways: + * + * 1. $data is null (default): $filename is treated as the name if a local file which + * will be read and sent. Will try to guess the content type using mime_content_type(). + * 2. $data is set - $filename is sent as the file name, but $data is sent as the file + * contents and no file is read from the file system. In this case, you need to + * manually set the Content-Type ($ctype) or it will default to + * application/octet-stream. + * + * @param string $filename Name of file to upload, or name to save as + * @param string $formname Name of form element to send as + * @param string $data Data to send (if null, $filename is read and sent) + * @param string $ctype Content type to use (if $data is set and $ctype is + * null, will be application/octet-stream) + * @return Zend_Http_Client + * @throws Zend_Http_Client_Exception + */ + public function setFileUpload($filename, $formname, $data = null, $ctype = null) + { + if ($data === null) { + if (($data = @file_get_contents($filename)) === false) { + /** @see Zend_Http_Client_Exception */ + require_once 'Zend/Http/Client/Exception.php'; + throw new Zend_Http_Client_Exception("Unable to read file '{$filename}' for upload"); + } + + if (! $ctype) { + $ctype = $this->_detectFileMimeType($filename); + } + } + + // Force enctype to multipart/form-data + $this->setEncType(self::ENC_FORMDATA); + + $this->files[] = array( + 'formname' => $formname, + 'filename' => basename($filename), + 'ctype' => $ctype, + 'data' => $data + ); + + return $this; + } + + /** + * Set the encoding type for POST data + * + * @param string $enctype + * @return Zend_Http_Client + */ + public function setEncType($enctype = self::ENC_URLENCODED) + { + $this->enctype = $enctype; + + return $this; + } + + /** + * Set the raw (already encoded) POST data. + * + * This function is here for two reasons: + * 1. For advanced user who would like to set their own data, already encoded + * 2. For backwards compatibilty: If someone uses the old post($data) method. + * this method will be used to set the encoded data. + * + * $data can also be stream (such as file) from which the data will be read. + * + * @param string|resource $data + * @param string $enctype + * @return Zend_Http_Client + */ + public function setRawData($data, $enctype = null) + { + $this->raw_post_data = $data; + $this->setEncType($enctype); + if (is_resource($data)) { + // We've got stream data + $stat = @fstat($data); + if($stat) { + $this->setHeaders(self::CONTENT_LENGTH, $stat['size']); + } + } + return $this; + } + + /** + * Clear all GET and POST parameters + * + * Should be used to reset the request parameters if the client is + * used for several concurrent requests. + * + * clearAll parameter controls if we clean just parameters or also + * headers and last_* + * + * @param bool $clearAll Should all data be cleared? + * @return Zend_Http_Client + */ + public function resetParameters($clearAll = false) + { + // Reset parameter data + $this->paramsGet = array(); + $this->paramsPost = array(); + $this->files = array(); + $this->raw_post_data = null; + + if($clearAll) { + $this->headers = array(); + $this->last_request = null; + $this->last_response = null; + } else { + // Clear outdated headers + if (isset($this->headers[strtolower(self::CONTENT_TYPE)])) { + unset($this->headers[strtolower(self::CONTENT_TYPE)]); + } + if (isset($this->headers[strtolower(self::CONTENT_LENGTH)])) { + unset($this->headers[strtolower(self::CONTENT_LENGTH)]); + } + } + + return $this; + } + + /** + * Get the last HTTP request as string + * + * @return string + */ + public function getLastRequest() + { + return $this->last_request; + } + + /** + * Get the last HTTP response received by this client + * + * If $config['storeresponse'] is set to false, or no response was + * stored yet, will return null + * + * @return Zend_Http_Response or null if none + */ + public function getLastResponse() + { + return $this->last_response; + } + + /** + * Load the connection adapter + * + * While this method is not called more than one for a client, it is + * seperated from ->request() to preserve logic and readability + * + * @param Zend_Http_Client_Adapter_Interface|string $adapter + * @return null + * @throws Zend_Http_Client_Exception + */ + public function setAdapter($adapter) + { + if (is_string($adapter)) { + try { + Zend_Loader::loadClass($adapter); + } catch (Zend_Exception $e) { + /** @see Zend_Http_Client_Exception */ + require_once 'Zend/Http/Client/Exception.php'; + throw new Zend_Http_Client_Exception("Unable to load adapter '$adapter': {$e->getMessage()}", 0, $e); + } + + $adapter = new $adapter; + } + + if (! $adapter instanceof Zend_Http_Client_Adapter_Interface) { + /** @see Zend_Http_Client_Exception */ + require_once 'Zend/Http/Client/Exception.php'; + throw new Zend_Http_Client_Exception('Passed adapter is not a HTTP connection adapter'); + } + + $this->adapter = $adapter; + $config = $this->config; + unset($config['adapter']); + $this->adapter->setConfig($config); + } + + /** + * Load the connection adapter + * + * @return Zend_Http_Client_Adapter_Interface $adapter + */ + public function getAdapter() + { + return $this->adapter; + } + + /** + * Set streaming for received data + * + * @param string|boolean $streamfile Stream file, true for temp file, false/null for no streaming + * @return Zend_Http_Client + */ + public function setStream($streamfile = true) + { + $this->setConfig(array("output_stream" => $streamfile)); + return $this; + } + + /** + * Get status of streaming for received data + * @return boolean|string + */ + public function getStream() + { + return $this->config["output_stream"]; + } + + /** + * Create temporary stream + * + * @return resource + */ + protected function _openTempStream() + { + $this->_stream_name = $this->config['output_stream']; + if(!is_string($this->_stream_name)) { + // If name is not given, create temp name + $this->_stream_name = tempnam(isset($this->config['stream_tmp_dir'])?$this->config['stream_tmp_dir']:sys_get_temp_dir(), + 'Zend_Http_Client'); + } + + if (false === ($fp = @fopen($this->_stream_name, "w+b"))) { + if ($this->adapter instanceof Zend_Http_Client_Adapter_Interface) { + $this->adapter->close(); + } + require_once 'Zend/Http/Client/Exception.php'; + throw new Zend_Http_Client_Exception("Could not open temp file {$this->_stream_name}"); + } + + return $fp; + } + + /** + * Send the HTTP request and return an HTTP response object + * + * @param string $method + * @return Zend_Http_Response + * @throws Zend_Http_Client_Exception + */ + public function request($method = null) + { + if (! $this->uri instanceof Zend_Uri_Http) { + /** @see Zend_Http_Client_Exception */ + require_once 'Zend/Http/Client/Exception.php'; + throw new Zend_Http_Client_Exception('No valid URI has been passed to the client'); + } + + if ($method) { + $this->setMethod($method); + } + $this->redirectCounter = 0; + $response = null; + + // Make sure the adapter is loaded + if ($this->adapter == null) { + $this->setAdapter($this->config['adapter']); + } + + // Send the first request. If redirected, continue. + do { + // Clone the URI and add the additional GET parameters to it + $uri = clone $this->uri; + if (! empty($this->paramsGet)) { + $query = $uri->getQuery(); + if (! empty($query)) { + $query .= '&'; + } + $query .= http_build_query($this->paramsGet, null, '&'); + + $uri->setQuery($query); + } + + $body = $this->_prepareBody(); + $headers = $this->_prepareHeaders(); + + // check that adapter supports streaming before using it + if(is_resource($body) && !($this->adapter instanceof Zend_Http_Client_Adapter_Stream)) { + /** @see Zend_Http_Client_Exception */ + require_once 'Zend/Http/Client/Exception.php'; + throw new Zend_Http_Client_Exception('Adapter does not support streaming'); + } + + // Open the connection, send the request and read the response + $this->adapter->connect($uri->getHost(), $uri->getPort(), + ($uri->getScheme() == 'https' ? true : false)); + + if($this->config['output_stream']) { + if($this->adapter instanceof Zend_Http_Client_Adapter_Stream) { + $stream = $this->_openTempStream(); + $this->adapter->setOutputStream($stream); + } else { + /** @see Zend_Http_Client_Exception */ + require_once 'Zend/Http/Client/Exception.php'; + throw new Zend_Http_Client_Exception('Adapter does not support streaming'); + } + } + + $this->last_request = $this->adapter->write($this->method, + $uri, $this->config['httpversion'], $headers, $body); + + $response = $this->adapter->read(); + if (! $response) { + /** @see Zend_Http_Client_Exception */ + require_once 'Zend/Http/Client/Exception.php'; + throw new Zend_Http_Client_Exception('Unable to read response, or response is empty'); + } + + if($this->config['output_stream']) { + rewind($stream); + // cleanup the adapter + $this->adapter->setOutputStream(null); + $response = Zend_Http_Response_Stream::fromStream($response, $stream); + $response->setStreamName($this->_stream_name); + if(!is_string($this->config['output_stream'])) { + // we used temp name, will need to clean up + $response->setCleanup(true); + } + } else { + $response = Zend_Http_Response::fromString($response); + } + + if ($this->config['storeresponse']) { + $this->last_response = $response; + } + + // Load cookies into cookie jar + if (isset($this->cookiejar)) { + $this->cookiejar->addCookiesFromResponse($response, $uri); + } + + // If we got redirected, look for the Location header + if ($response->isRedirect() && ($location = $response->getHeader('location'))) { + + // Check whether we send the exact same request again, or drop the parameters + // and send a GET request + if ($response->getStatus() == 303 || + ((! $this->config['strictredirects']) && ($response->getStatus() == 302 || + $response->getStatus() == 301))) { + + $this->resetParameters(); + $this->setMethod(self::GET); + } + + // If we got a well formed absolute URI + if (Zend_Uri_Http::check($location)) { + $this->setHeaders('host', null); + $this->setUri($location); + + } else { + + // Split into path and query and set the query + if (strpos($location, '?') !== false) { + list($location, $query) = explode('?', $location, 2); + } else { + $query = ''; + } + $this->uri->setQuery($query); + + // Else, if we got just an absolute path, set it + if(strpos($location, '/') === 0) { + $this->uri->setPath($location); + + // Else, assume we have a relative path + } else { + // Get the current path directory, removing any trailing slashes + $path = $this->uri->getPath(); + $path = rtrim(substr($path, 0, strrpos($path, '/')), "/"); + $this->uri->setPath($path . '/' . $location); + } + } + ++$this->redirectCounter; + + } else { + // If we didn't get any location, stop redirecting + break; + } + + } while ($this->redirectCounter < $this->config['maxredirects']); + + return $response; + } + + /** + * Prepare the request headers + * + * @return array + */ + protected function _prepareHeaders() + { + $headers = array(); + + // Set the host header + if (! isset($this->headers['host'])) { + $host = $this->uri->getHost(); + + // If the port is not default, add it + if (! (($this->uri->getScheme() == 'http' && $this->uri->getPort() == 80) || + ($this->uri->getScheme() == 'https' && $this->uri->getPort() == 443))) { + $host .= ':' . $this->uri->getPort(); + } + + $headers[] = "Host: {$host}"; + } + + // Set the connection header + if (! isset($this->headers['connection'])) { + if (! $this->config['keepalive']) { + $headers[] = "Connection: close"; + } + } + + // Set the Accept-encoding header if not set - depending on whether + // zlib is available or not. + if (! isset($this->headers['accept-encoding'])) { + if (function_exists('gzinflate')) { + $headers[] = 'Accept-encoding: gzip, deflate'; + } else { + $headers[] = 'Accept-encoding: identity'; + } + } + + // Set the Content-Type header + if ($this->method == self::POST && + (! isset($this->headers[strtolower(self::CONTENT_TYPE)]) && isset($this->enctype))) { + + $headers[] = self::CONTENT_TYPE . ': ' . $this->enctype; + } + + // Set the user agent header + if (! isset($this->headers['user-agent']) && isset($this->config['useragent'])) { + $headers[] = "User-Agent: {$this->config['useragent']}"; + } + + // Set HTTP authentication if needed + if (is_array($this->auth)) { + $auth = self::encodeAuthHeader($this->auth['user'], $this->auth['password'], $this->auth['type']); + $headers[] = "Authorization: {$auth}"; + } + + // Load cookies from cookie jar + if (isset($this->cookiejar)) { + $cookstr = $this->cookiejar->getMatchingCookies($this->uri, + true, Zend_Http_CookieJar::COOKIE_STRING_CONCAT); + + if ($cookstr) { + $headers[] = "Cookie: {$cookstr}"; + } + } + + // Add all other user defined headers + foreach ($this->headers as $header) { + list($name, $value) = $header; + if (is_array($value)) { + $value = implode(', ', $value); + } + + $headers[] = "$name: $value"; + } + + return $headers; + } + + /** + * Prepare the request body (for POST and PUT requests) + * + * @return string + * @throws Zend_Http_Client_Exception + */ + protected function _prepareBody() + { + // According to RFC2616, a TRACE request should not have a body. + if ($this->method == self::TRACE) { + return ''; + } + + if (isset($this->raw_post_data) && is_resource($this->raw_post_data)) { + return $this->raw_post_data; + } + // If mbstring overloads substr and strlen functions, we have to + // override it's internal encoding + if (function_exists('mb_internal_encoding') && + ((int) ini_get('mbstring.func_overload')) & 2) { + + $mbIntEnc = mb_internal_encoding(); + mb_internal_encoding('ASCII'); + } + + // If we have raw_post_data set, just use it as the body. + if (isset($this->raw_post_data)) { + $this->setHeaders(self::CONTENT_LENGTH, strlen($this->raw_post_data)); + if (isset($mbIntEnc)) { + mb_internal_encoding($mbIntEnc); + } + + return $this->raw_post_data; + } + + $body = ''; + + // If we have files to upload, force enctype to multipart/form-data + if (count ($this->files) > 0) { + $this->setEncType(self::ENC_FORMDATA); + } + + // If we have POST parameters or files, encode and add them to the body + if (count($this->paramsPost) > 0 || count($this->files) > 0) { + switch($this->enctype) { + case self::ENC_FORMDATA: + // Encode body as multipart/form-data + $boundary = '---ZENDHTTPCLIENT-' . md5(microtime()); + $this->setHeaders(self::CONTENT_TYPE, self::ENC_FORMDATA . "; boundary={$boundary}"); + + // Get POST parameters and encode them + $params = self::_flattenParametersArray($this->paramsPost); + foreach ($params as $pp) { + $body .= self::encodeFormData($boundary, $pp[0], $pp[1]); + } + + // Encode files + foreach ($this->files as $file) { + $fhead = array(self::CONTENT_TYPE => $file['ctype']); + $body .= self::encodeFormData($boundary, $file['formname'], $file['data'], $file['filename'], $fhead); + } + + $body .= "--{$boundary}--\r\n"; + break; + + case self::ENC_URLENCODED: + // Encode body as application/x-www-form-urlencoded + $this->setHeaders(self::CONTENT_TYPE, self::ENC_URLENCODED); + $body = http_build_query($this->paramsPost, '', '&'); + break; + + default: + if (isset($mbIntEnc)) { + mb_internal_encoding($mbIntEnc); + } + + /** @see Zend_Http_Client_Exception */ + require_once 'Zend/Http/Client/Exception.php'; + throw new Zend_Http_Client_Exception("Cannot handle content type '{$this->enctype}' automatically." . + " Please use Zend_Http_Client::setRawData to send this kind of content."); + break; + } + } + + // Set the Content-Length if we have a body or if request is POST/PUT + if ($body || $this->method == self::POST || $this->method == self::PUT) { + $this->setHeaders(self::CONTENT_LENGTH, strlen($body)); + } + + if (isset($mbIntEnc)) { + mb_internal_encoding($mbIntEnc); + } + + return $body; + } + + /** + * Helper method that gets a possibly multi-level parameters array (get or + * post) and flattens it. + * + * The method returns an array of (key, value) pairs (because keys are not + * necessarily unique. If one of the parameters in as array, it will also + * add a [] suffix to the key. + * + * This method is deprecated since Zend Framework 1.9 in favour of + * self::_flattenParametersArray() and will be dropped in 2.0 + * + * @deprecated since 1.9 + * + * @param array $parray The parameters array + * @param bool $urlencode Whether to urlencode the name and value + * @return array + */ + protected function _getParametersRecursive($parray, $urlencode = false) + { + // Issue a deprecated notice + trigger_error("The " . __METHOD__ . " method is deprecated and will be dropped in 2.0.", + E_USER_NOTICE); + + if (! is_array($parray)) { + return $parray; + } + $parameters = array(); + + foreach ($parray as $name => $value) { + if ($urlencode) { + $name = urlencode($name); + } + + // If $value is an array, iterate over it + if (is_array($value)) { + $name .= ($urlencode ? '%5B%5D' : '[]'); + foreach ($value as $subval) { + if ($urlencode) { + $subval = urlencode($subval); + } + $parameters[] = array($name, $subval); + } + } else { + if ($urlencode) { + $value = urlencode($value); + } + $parameters[] = array($name, $value); + } + } + + return $parameters; + } + + /** + * Attempt to detect the MIME type of a file using available extensions + * + * This method will try to detect the MIME type of a file. If the fileinfo + * extension is available, it will be used. If not, the mime_magic + * extension which is deprected but is still available in many PHP setups + * will be tried. + * + * If neither extension is available, the default application/octet-stream + * MIME type will be returned + * + * @param string $file File path + * @return string MIME type + */ + protected function _detectFileMimeType($file) + { + $type = null; + + // First try with fileinfo functions + if (function_exists('finfo_open')) { + if (self::$_fileInfoDb === null) { + self::$_fileInfoDb = @finfo_open(FILEINFO_MIME); + } + + if (self::$_fileInfoDb) { + $type = finfo_file(self::$_fileInfoDb, $file); + } + + } elseif (function_exists('mime_content_type')) { + $type = mime_content_type($file); + } + + // Fallback to the default application/octet-stream + if (! $type) { + $type = 'application/octet-stream'; + } + + return $type; + } + + /** + * Encode data to a multipart/form-data part suitable for a POST request. + * + * @param string $boundary + * @param string $name + * @param mixed $value + * @param string $filename + * @param array $headers Associative array of optional headers @example ("Content-Transfer-Encoding" => "binary") + * @return string + */ + public static function encodeFormData($boundary, $name, $value, $filename = null, $headers = array()) { + $ret = "--{$boundary}\r\n" . + 'Content-Disposition: form-data; name="' . $name .'"'; + + if ($filename) { + $ret .= '; filename="' . $filename . '"'; + } + $ret .= "\r\n"; + + foreach ($headers as $hname => $hvalue) { + $ret .= "{$hname}: {$hvalue}\r\n"; + } + $ret .= "\r\n"; + + $ret .= "{$value}\r\n"; + + return $ret; + } + + /** + * Create a HTTP authentication "Authorization:" header according to the + * specified user, password and authentication method. + * + * @see http://www.faqs.org/rfcs/rfc2617.html + * @param string $user + * @param string $password + * @param string $type + * @return string + * @throws Zend_Http_Client_Exception + */ + public static function encodeAuthHeader($user, $password, $type = self::AUTH_BASIC) + { + $authHeader = null; + + switch ($type) { + case self::AUTH_BASIC: + // In basic authentication, the user name cannot contain ":" + if (strpos($user, ':') !== false) { + /** @see Zend_Http_Client_Exception */ + require_once 'Zend/Http/Client/Exception.php'; + throw new Zend_Http_Client_Exception("The user name cannot contain ':' in 'Basic' HTTP authentication"); + } + + $authHeader = 'Basic ' . base64_encode($user . ':' . $password); + break; + + //case self::AUTH_DIGEST: + /** + * @todo Implement digest authentication + */ + // break; + + default: + /** @see Zend_Http_Client_Exception */ + require_once 'Zend/Http/Client/Exception.php'; + throw new Zend_Http_Client_Exception("Not a supported HTTP authentication type: '$type'"); + } + + return $authHeader; + } + + /** + * Convert an array of parameters into a flat array of (key, value) pairs + * + * Will flatten a potentially multi-dimentional array of parameters (such + * as POST parameters) into a flat array of (key, value) paris. In case + * of multi-dimentional arrays, square brackets ([]) will be added to the + * key to indicate an array. + * + * @since 1.9 + * + * @param array $parray + * @param string $prefix + * @return array + */ + static protected function _flattenParametersArray($parray, $prefix = null) + { + if (! is_array($parray)) { + return $parray; + } + + $parameters = array(); + + foreach($parray as $name => $value) { + + // Calculate array key + if ($prefix) { + if (is_int($name)) { + $key = $prefix . '[]'; + } else { + $key = $prefix . "[$name]"; + } + } else { + $key = $name; + } + + if (is_array($value)) { + $parameters = array_merge($parameters, self::_flattenParametersArray($value, $key)); + + } else { + $parameters[] = array($key, $value); + } + } + + return $parameters; + } + +} diff --git a/Zend/Http/Client/Adapter/Curl.php b/Zend/Http/Client/Adapter/Curl.php new file mode 100644 index 00000000..617bc643 --- /dev/null +++ b/Zend/Http/Client/Adapter/Curl.php @@ -0,0 +1,507 @@ +_invalidOverwritableCurlOptions = array( + CURLOPT_HTTPGET, + CURLOPT_POST, + CURLOPT_PUT, + CURLOPT_CUSTOMREQUEST, + CURLOPT_HEADER, + CURLOPT_RETURNTRANSFER, + CURLOPT_HTTPHEADER, + CURLOPT_POSTFIELDS, + CURLOPT_INFILE, + CURLOPT_INFILESIZE, + CURLOPT_PORT, + CURLOPT_MAXREDIRS, + CURLOPT_CONNECTTIMEOUT, + CURL_HTTP_VERSION_1_1, + CURL_HTTP_VERSION_1_0, + ); + } + + /** + * Set the configuration array for the adapter + * + * @throws Zend_Http_Client_Adapter_Exception + * @param Zend_Config | array $config + * @return Zend_Http_Client_Adapter_Curl + */ + public function setConfig($config = array()) + { + if ($config instanceof Zend_Config) { + $config = $config->toArray(); + + } elseif (! is_array($config)) { + require_once 'Zend/Http/Client/Adapter/Exception.php'; + throw new Zend_Http_Client_Adapter_Exception( + 'Array or Zend_Config object expected, got ' . gettype($config) + ); + } + + if(isset($config['proxy_user']) && isset($config['proxy_pass'])) { + $this->setCurlOption(CURLOPT_PROXYUSERPWD, $config['proxy_user'].":".$config['proxy_pass']); + unset($config['proxy_user'], $config['proxy_pass']); + } + + foreach ($config as $k => $v) { + $option = strtolower($k); + switch($option) { + case 'proxy_host': + $this->setCurlOption(CURLOPT_PROXY, $v); + break; + case 'proxy_port': + $this->setCurlOption(CURLOPT_PROXYPORT, $v); + break; + default: + $this->_config[$option] = $v; + break; + } + } + + return $this; + } + + /** + * Retrieve the array of all configuration options + * + * @return array + */ + public function getConfig() + { + return $this->_config; + } + + /** + * Direct setter for cURL adapter related options. + * + * @param string|int $option + * @param mixed $value + * @return Zend_Http_Adapter_Curl + */ + public function setCurlOption($option, $value) + { + if (!isset($this->_config['curloptions'])) { + $this->_config['curloptions'] = array(); + } + $this->_config['curloptions'][$option] = $value; + return $this; + } + + /** + * Initialize curl + * + * @param string $host + * @param int $port + * @param boolean $secure + * @return void + * @throws Zend_Http_Client_Adapter_Exception if unable to connect + */ + public function connect($host, $port = 80, $secure = false) + { + // If we're already connected, disconnect first + if ($this->_curl) { + $this->close(); + } + + // If we are connected to a different server or port, disconnect first + if ($this->_curl + && is_array($this->_connected_to) + && ($this->_connected_to[0] != $host + || $this->_connected_to[1] != $port) + ) { + $this->close(); + } + + // Do the actual connection + $this->_curl = curl_init(); + if ($port != 80) { + curl_setopt($this->_curl, CURLOPT_PORT, intval($port)); + } + + // Set timeout + curl_setopt($this->_curl, CURLOPT_CONNECTTIMEOUT, $this->_config['timeout']); + + // Set Max redirects + curl_setopt($this->_curl, CURLOPT_MAXREDIRS, $this->_config['maxredirects']); + + if (!$this->_curl) { + $this->close(); + + require_once 'Zend/Http/Client/Adapter/Exception.php'; + throw new Zend_Http_Client_Adapter_Exception('Unable to Connect to ' . $host . ':' . $port); + } + + if ($secure !== false) { + // Behave the same like Zend_Http_Adapter_Socket on SSL options. + if (isset($this->_config['sslcert'])) { + curl_setopt($this->_curl, CURLOPT_SSLCERT, $this->_config['sslcert']); + } + if (isset($this->_config['sslpassphrase'])) { + curl_setopt($this->_curl, CURLOPT_SSLCERTPASSWD, $this->_config['sslpassphrase']); + } + } + + // Update connected_to + $this->_connected_to = array($host, $port); + } + + /** + * Send request to the remote server + * + * @param string $method + * @param Zend_Uri_Http $uri + * @param float $http_ver + * @param array $headers + * @param string $body + * @return string $request + * @throws Zend_Http_Client_Adapter_Exception If connection fails, connected to wrong host, no PUT file defined, unsupported method, or unsupported cURL option + */ + public function write($method, $uri, $httpVersion = 1.1, $headers = array(), $body = '') + { + // Make sure we're properly connected + if (!$this->_curl) { + require_once 'Zend/Http/Client/Adapter/Exception.php'; + throw new Zend_Http_Client_Adapter_Exception("Trying to write but we are not connected"); + } + + if ($this->_connected_to[0] != $uri->getHost() || $this->_connected_to[1] != $uri->getPort()) { + require_once 'Zend/Http/Client/Adapter/Exception.php'; + throw new Zend_Http_Client_Adapter_Exception("Trying to write but we are connected to the wrong host"); + } + + // set URL + curl_setopt($this->_curl, CURLOPT_URL, $uri->__toString()); + + // ensure correct curl call + $curlValue = true; + switch ($method) { + case Zend_Http_Client::GET: + $curlMethod = CURLOPT_HTTPGET; + break; + + case Zend_Http_Client::POST: + $curlMethod = CURLOPT_POST; + break; + + case Zend_Http_Client::PUT: + // There are two different types of PUT request, either a Raw Data string has been set + // or CURLOPT_INFILE and CURLOPT_INFILESIZE are used. + if(is_resource($body)) { + $this->_config['curloptions'][CURLOPT_INFILE] = $body; + } + if (isset($this->_config['curloptions'][CURLOPT_INFILE])) { + // Now we will probably already have Content-Length set, so that we have to delete it + // from $headers at this point: + foreach ($headers AS $k => $header) { + if (preg_match('/Content-Length:\s*(\d+)/i', $header, $m)) { + if(is_resource($body)) { + $this->_config['curloptions'][CURLOPT_INFILESIZE] = (int)$m[1]; + } + unset($headers[$k]); + } + } + + if (!isset($this->_config['curloptions'][CURLOPT_INFILESIZE])) { + require_once 'Zend/Http/Client/Adapter/Exception.php'; + throw new Zend_Http_Client_Adapter_Exception("Cannot set a file-handle for cURL option CURLOPT_INFILE without also setting its size in CURLOPT_INFILESIZE."); + } + + if(is_resource($body)) { + $body = ''; + } + + $curlMethod = CURLOPT_PUT; + } else { + $curlMethod = CURLOPT_CUSTOMREQUEST; + $curlValue = "PUT"; + } + break; + + case Zend_Http_Client::DELETE: + $curlMethod = CURLOPT_CUSTOMREQUEST; + $curlValue = "DELETE"; + break; + + case Zend_Http_Client::OPTIONS: + $curlMethod = CURLOPT_CUSTOMREQUEST; + $curlValue = "OPTIONS"; + break; + + case Zend_Http_Client::TRACE: + $curlMethod = CURLOPT_CUSTOMREQUEST; + $curlValue = "TRACE"; + break; + + case Zend_Http_Client::HEAD: + $curlMethod = CURLOPT_CUSTOMREQUEST; + $curlValue = "HEAD"; + break; + + default: + // For now, through an exception for unsupported request methods + require_once 'Zend/Http/Client/Adapter/Exception.php'; + throw new Zend_Http_Client_Adapter_Exception("Method currently not supported"); + } + + if(is_resource($body) && $curlMethod != CURLOPT_PUT) { + require_once 'Zend/Http/Client/Adapter/Exception.php'; + throw new Zend_Http_Client_Adapter_Exception("Streaming requests are allowed only with PUT"); + } + + // get http version to use + $curlHttp = ($httpVersion == 1.1) ? CURL_HTTP_VERSION_1_1 : CURL_HTTP_VERSION_1_0; + + // mark as HTTP request and set HTTP method + curl_setopt($this->_curl, $curlHttp, true); + curl_setopt($this->_curl, $curlMethod, $curlValue); + + if($this->out_stream) { + // headers will be read into the response + curl_setopt($this->_curl, CURLOPT_HEADER, false); + curl_setopt($this->_curl, CURLOPT_HEADERFUNCTION, array($this, "readHeader")); + // and data will be written into the file + curl_setopt($this->_curl, CURLOPT_FILE, $this->out_stream); + } else { + // ensure headers are also returned + curl_setopt($this->_curl, CURLOPT_HEADER, true); + + // ensure actual response is returned + curl_setopt($this->_curl, CURLOPT_RETURNTRANSFER, true); + } + + // set additional headers + $headers['Accept'] = ''; + curl_setopt($this->_curl, CURLOPT_HTTPHEADER, $headers); + + /** + * Make sure POSTFIELDS is set after $curlMethod is set: + * @link http://de2.php.net/manual/en/function.curl-setopt.php#81161 + */ + if ($method == Zend_Http_Client::POST) { + curl_setopt($this->_curl, CURLOPT_POSTFIELDS, $body); + } elseif ($curlMethod == CURLOPT_PUT) { + // this covers a PUT by file-handle: + // Make the setting of this options explicit (rather than setting it through the loop following a bit lower) + // to group common functionality together. + curl_setopt($this->_curl, CURLOPT_INFILE, $this->_config['curloptions'][CURLOPT_INFILE]); + curl_setopt($this->_curl, CURLOPT_INFILESIZE, $this->_config['curloptions'][CURLOPT_INFILESIZE]); + unset($this->_config['curloptions'][CURLOPT_INFILE]); + unset($this->_config['curloptions'][CURLOPT_INFILESIZE]); + } elseif ($method == Zend_Http_Client::PUT) { + // This is a PUT by a setRawData string, not by file-handle + curl_setopt($this->_curl, CURLOPT_POSTFIELDS, $body); + } + + // set additional curl options + if (isset($this->_config['curloptions'])) { + foreach ((array)$this->_config['curloptions'] as $k => $v) { + if (!in_array($k, $this->_invalidOverwritableCurlOptions)) { + if (curl_setopt($this->_curl, $k, $v) == false) { + require_once 'Zend/Http/Client/Exception.php'; + throw new Zend_Http_Client_Exception(sprintf("Unknown or erroreous cURL option '%s' set", $k)); + } + } + } + } + + // send the request + $response = curl_exec($this->_curl); + + // if we used streaming, headers are already there + if(!is_resource($this->out_stream)) { + $this->_response = $response; + } + + $request = curl_getinfo($this->_curl, CURLINFO_HEADER_OUT); + $request .= $body; + + if (empty($this->_response)) { + require_once 'Zend/Http/Client/Exception.php'; + throw new Zend_Http_Client_Exception("Error in cURL request: " . curl_error($this->_curl)); + } + + // cURL automatically decodes chunked-messages, this means we have to disallow the Zend_Http_Response to do it again + if (stripos($this->_response, "Transfer-Encoding: chunked\r\n")) { + $this->_response = str_ireplace("Transfer-Encoding: chunked\r\n", '', $this->_response); + } + + // Eliminate multiple HTTP responses. + do { + $parts = preg_split('|(?:\r?\n){2}|m', $this->_response, 2); + $again = false; + + if (isset($parts[1]) && preg_match("|^HTTP/1\.[01](.*?)\r\n|mi", $parts[1])) { + $this->_response = $parts[1]; + $again = true; + } + } while ($again); + + // cURL automatically handles Proxy rewrites, remove the "HTTP/1.0 200 Connection established" string: + if (stripos($this->_response, "HTTP/1.0 200 Connection established\r\n\r\n") !== false) { + $this->_response = str_ireplace("HTTP/1.0 200 Connection established\r\n\r\n", '', $this->_response); + } + + return $request; + } + + /** + * Return read response from server + * + * @return string + */ + public function read() + { + return $this->_response; + } + + /** + * Close the connection to the server + * + */ + public function close() + { + if(is_resource($this->_curl)) { + curl_close($this->_curl); + } + $this->_curl = null; + $this->_connected_to = array(null, null); + } + + /** + * Get cUrl Handle + * + * @return resource + */ + public function getHandle() + { + return $this->_curl; + } + + /** + * Set output stream for the response + * + * @param resource $stream + * @return Zend_Http_Client_Adapter_Socket + */ + public function setOutputStream($stream) + { + $this->out_stream = $stream; + return $this; + } + + /** + * Header reader function for CURL + * + * @param resource $curl + * @param string $header + * @return int + */ + public function readHeader($curl, $header) + { + $this->_response .= $header; + return strlen($header); + } +} diff --git a/Zend/Http/Client/Adapter/Exception.php b/Zend/Http/Client/Adapter/Exception.php new file mode 100644 index 00000000..c278cb4f --- /dev/null +++ b/Zend/Http/Client/Adapter/Exception.php @@ -0,0 +1,38 @@ + 'ssl', + 'sslcert' => null, + 'sslpassphrase' => null, + 'sslusecontext' => false, + 'proxy_host' => '', + 'proxy_port' => 8080, + 'proxy_user' => '', + 'proxy_pass' => '', + 'proxy_auth' => Zend_Http_Client::AUTH_BASIC, + 'persistent' => false + ); + + /** + * Whether HTTPS CONNECT was already negotiated with the proxy or not + * + * @var boolean + */ + protected $negotiated = false; + + /** + * Connect to the remote server + * + * Will try to connect to the proxy server. If no proxy was set, will + * fall back to the target server (behave like regular Socket adapter) + * + * @param string $host + * @param int $port + * @param boolean $secure + */ + public function connect($host, $port = 80, $secure = false) + { + // If no proxy is set, fall back to Socket adapter + if (! $this->config['proxy_host']) { + return parent::connect($host, $port, $secure); + } + + /* Url might require stream context even if proxy connection doesn't */ + if ($secure) { + $this->config['sslusecontext'] = true; + } + + // Connect (a non-secure connection) to the proxy server + return parent::connect( + $this->config['proxy_host'], + $this->config['proxy_port'], + false + ); + } + + /** + * Send request to the proxy server + * + * @param string $method + * @param Zend_Uri_Http $uri + * @param string $http_ver + * @param array $headers + * @param string $body + * @return string Request as string + */ + public function write($method, $uri, $http_ver = '1.1', $headers = array(), $body = '') + { + // If no proxy is set, fall back to default Socket adapter + if (! $this->config['proxy_host']) return parent::write($method, $uri, $http_ver, $headers, $body); + + // Make sure we're properly connected + if (! $this->socket) { + require_once 'Zend/Http/Client/Adapter/Exception.php'; + throw new Zend_Http_Client_Adapter_Exception("Trying to write but we are not connected"); + } + + $host = $this->config['proxy_host']; + $port = $this->config['proxy_port']; + + if ($this->connected_to[0] != "tcp://$host" || $this->connected_to[1] != $port) { + require_once 'Zend/Http/Client/Adapter/Exception.php'; + throw new Zend_Http_Client_Adapter_Exception("Trying to write but we are connected to the wrong proxy server"); + } + + // Add Proxy-Authorization header + if ($this->config['proxy_user'] && ! isset($headers['proxy-authorization'])) { + $headers['proxy-authorization'] = Zend_Http_Client::encodeAuthHeader( + $this->config['proxy_user'], $this->config['proxy_pass'], $this->config['proxy_auth'] + ); + } + + // if we are proxying HTTPS, preform CONNECT handshake with the proxy + if ($uri->getScheme() == 'https' && (! $this->negotiated)) { + $this->connectHandshake($uri->getHost(), $uri->getPort(), $http_ver, $headers); + $this->negotiated = true; + } + + // Save request method for later + $this->method = $method; + + // Build request headers + if ($this->negotiated) { + $path = $uri->getPath(); + if ($uri->getQuery()) { + $path .= '?' . $uri->getQuery(); + } + $request = "$method $path HTTP/$http_ver\r\n"; + } else { + $request = "$method $uri HTTP/$http_ver\r\n"; + } + + // Add all headers to the request string + foreach ($headers as $k => $v) { + if (is_string($k)) $v = "$k: $v"; + $request .= "$v\r\n"; + } + + if(is_resource($body)) { + $request .= "\r\n"; + } else { + // Add the request body + $request .= "\r\n" . $body; + } + + // Send the request + if (! @fwrite($this->socket, $request)) { + require_once 'Zend/Http/Client/Adapter/Exception.php'; + throw new Zend_Http_Client_Adapter_Exception("Error writing request to proxy server"); + } + + if(is_resource($body)) { + if(stream_copy_to_stream($body, $this->socket) == 0) { + require_once 'Zend/Http/Client/Adapter/Exception.php'; + throw new Zend_Http_Client_Adapter_Exception('Error writing request to server'); + } + } + + return $request; + } + + /** + * Preform handshaking with HTTPS proxy using CONNECT method + * + * @param string $host + * @param integer $port + * @param string $http_ver + * @param array $headers + */ + protected function connectHandshake($host, $port = 443, $http_ver = '1.1', array &$headers = array()) + { + $request = "CONNECT $host:$port HTTP/$http_ver\r\n" . + "Host: " . $this->config['proxy_host'] . "\r\n"; + + // Add the user-agent header + if (isset($this->config['useragent'])) { + $request .= "User-agent: " . $this->config['useragent'] . "\r\n"; + } + + // If the proxy-authorization header is set, send it to proxy but remove + // it from headers sent to target host + if (isset($headers['proxy-authorization'])) { + $request .= "Proxy-authorization: " . $headers['proxy-authorization'] . "\r\n"; + unset($headers['proxy-authorization']); + } + + $request .= "\r\n"; + + // Send the request + if (! @fwrite($this->socket, $request)) { + require_once 'Zend/Http/Client/Adapter/Exception.php'; + throw new Zend_Http_Client_Adapter_Exception("Error writing request to proxy server"); + } + + // Read response headers only + $response = ''; + $gotStatus = false; + while ($line = @fgets($this->socket)) { + $gotStatus = $gotStatus || (strpos($line, 'HTTP') !== false); + if ($gotStatus) { + $response .= $line; + if (!chop($line)) break; + } + } + + // Check that the response from the proxy is 200 + if (Zend_Http_Response::extractCode($response) != 200) { + require_once 'Zend/Http/Client/Adapter/Exception.php'; + throw new Zend_Http_Client_Adapter_Exception("Unable to connect to HTTPS proxy. Server response: " . $response); + } + + // If all is good, switch socket to secure mode. We have to fall back + // through the different modes + $modes = array( + STREAM_CRYPTO_METHOD_TLS_CLIENT, + STREAM_CRYPTO_METHOD_SSLv3_CLIENT, + STREAM_CRYPTO_METHOD_SSLv23_CLIENT, + STREAM_CRYPTO_METHOD_SSLv2_CLIENT + ); + + $success = false; + foreach($modes as $mode) { + $success = stream_socket_enable_crypto($this->socket, true, $mode); + if ($success) break; + } + + if (! $success) { + require_once 'Zend/Http/Client/Adapter/Exception.php'; + throw new Zend_Http_Client_Adapter_Exception("Unable to connect to" . + " HTTPS server through proxy: could not negotiate secure connection."); + } + } + + /** + * Close the connection to the server + * + */ + public function close() + { + parent::close(); + $this->negotiated = false; + } + + /** + * Destructor: make sure the socket is disconnected + * + */ + public function __destruct() + { + if ($this->socket) $this->close(); + } +} diff --git a/Zend/Http/Client/Adapter/Socket.php b/Zend/Http/Client/Adapter/Socket.php new file mode 100644 index 00000000..5ec334c6 --- /dev/null +++ b/Zend/Http/Client/Adapter/Socket.php @@ -0,0 +1,544 @@ + false, + 'ssltransport' => 'ssl', + 'sslcert' => null, + 'sslpassphrase' => null, + 'sslusecontext' => false + ); + + /** + * Request method - will be set by write() and might be used by read() + * + * @var string + */ + protected $method = null; + + /** + * Stream context + * + * @var resource + */ + protected $_context = null; + + /** + * Adapter constructor, currently empty. Config is set using setConfig() + * + */ + public function __construct() + { + } + + /** + * Set the configuration array for the adapter + * + * @param Zend_Config | array $config + */ + public function setConfig($config = array()) + { + if ($config instanceof Zend_Config) { + $config = $config->toArray(); + + } elseif (! is_array($config)) { + require_once 'Zend/Http/Client/Adapter/Exception.php'; + throw new Zend_Http_Client_Adapter_Exception( + 'Array or Zend_Config object expected, got ' . gettype($config) + ); + } + + foreach ($config as $k => $v) { + $this->config[strtolower($k)] = $v; + } + } + + /** + * Retrieve the array of all configuration options + * + * @return array + */ + public function getConfig() + { + return $this->config; + } + + /** + * Set the stream context for the TCP connection to the server + * + * Can accept either a pre-existing stream context resource, or an array + * of stream options, similar to the options array passed to the + * stream_context_create() PHP function. In such case a new stream context + * will be created using the passed options. + * + * @since Zend Framework 1.9 + * + * @param mixed $context Stream context or array of context options + * @return Zend_Http_Client_Adapter_Socket + */ + public function setStreamContext($context) + { + if (is_resource($context) && get_resource_type($context) == 'stream-context') { + $this->_context = $context; + + } elseif (is_array($context)) { + $this->_context = stream_context_create($context); + + } else { + // Invalid parameter + require_once 'Zend/Http/Client/Adapter/Exception.php'; + throw new Zend_Http_Client_Adapter_Exception( + "Expecting either a stream context resource or array, got " . gettype($context) + ); + } + + return $this; + } + + /** + * Get the stream context for the TCP connection to the server. + * + * If no stream context is set, will create a default one. + * + * @return resource + */ + public function getStreamContext() + { + if (! $this->_context) { + $this->_context = stream_context_create(); + } + + return $this->_context; + } + + /** + * Connect to the remote server + * + * @param string $host + * @param int $port + * @param boolean $secure + */ + public function connect($host, $port = 80, $secure = false) + { + // If the URI should be accessed via SSL, prepend the Hostname with ssl:// + $host = ($secure ? $this->config['ssltransport'] : 'tcp') . '://' . $host; + + // If we are connected to the wrong host, disconnect first + if (($this->connected_to[0] != $host || $this->connected_to[1] != $port)) { + if (is_resource($this->socket)) $this->close(); + } + + // Now, if we are not connected, connect + if (! is_resource($this->socket) || ! $this->config['keepalive']) { + $context = $this->getStreamContext(); + if ($secure || $this->config['sslusecontext']) { + if ($this->config['sslcert'] !== null) { + if (! stream_context_set_option($context, 'ssl', 'local_cert', + $this->config['sslcert'])) { + require_once 'Zend/Http/Client/Adapter/Exception.php'; + throw new Zend_Http_Client_Adapter_Exception('Unable to set sslcert option'); + } + } + if ($this->config['sslpassphrase'] !== null) { + if (! stream_context_set_option($context, 'ssl', 'passphrase', + $this->config['sslpassphrase'])) { + require_once 'Zend/Http/Client/Adapter/Exception.php'; + throw new Zend_Http_Client_Adapter_Exception('Unable to set sslpassphrase option'); + } + } + } + + $flags = STREAM_CLIENT_CONNECT; + if ($this->config['persistent']) $flags |= STREAM_CLIENT_PERSISTENT; + + $this->socket = @stream_socket_client($host . ':' . $port, + $errno, + $errstr, + (int) $this->config['timeout'], + $flags, + $context); + + if (! $this->socket) { + $this->close(); + require_once 'Zend/Http/Client/Adapter/Exception.php'; + throw new Zend_Http_Client_Adapter_Exception( + 'Unable to Connect to ' . $host . ':' . $port . '. Error #' . $errno . ': ' . $errstr); + } + + // Set the stream timeout + if (! stream_set_timeout($this->socket, (int) $this->config['timeout'])) { + require_once 'Zend/Http/Client/Adapter/Exception.php'; + throw new Zend_Http_Client_Adapter_Exception('Unable to set the connection timeout'); + } + + // Update connected_to + $this->connected_to = array($host, $port); + } + } + + /** + * Send request to the remote server + * + * @param string $method + * @param Zend_Uri_Http $uri + * @param string $http_ver + * @param array $headers + * @param string $body + * @return string Request as string + */ + public function write($method, $uri, $http_ver = '1.1', $headers = array(), $body = '') + { + // Make sure we're properly connected + if (! $this->socket) { + require_once 'Zend/Http/Client/Adapter/Exception.php'; + throw new Zend_Http_Client_Adapter_Exception('Trying to write but we are not connected'); + } + + $host = $uri->getHost(); + $host = (strtolower($uri->getScheme()) == 'https' ? $this->config['ssltransport'] : 'tcp') . '://' . $host; + if ($this->connected_to[0] != $host || $this->connected_to[1] != $uri->getPort()) { + require_once 'Zend/Http/Client/Adapter/Exception.php'; + throw new Zend_Http_Client_Adapter_Exception('Trying to write but we are connected to the wrong host'); + } + + // Save request method for later + $this->method = $method; + + // Build request headers + $path = $uri->getPath(); + if ($uri->getQuery()) $path .= '?' . $uri->getQuery(); + $request = "{$method} {$path} HTTP/{$http_ver}\r\n"; + foreach ($headers as $k => $v) { + if (is_string($k)) $v = ucfirst($k) . ": $v"; + $request .= "$v\r\n"; + } + + if(is_resource($body)) { + $request .= "\r\n"; + } else { + // Add the request body + $request .= "\r\n" . $body; + } + + // Send the request + if (! @fwrite($this->socket, $request)) { + require_once 'Zend/Http/Client/Adapter/Exception.php'; + throw new Zend_Http_Client_Adapter_Exception('Error writing request to server'); + } + + if(is_resource($body)) { + if(stream_copy_to_stream($body, $this->socket) == 0) { + require_once 'Zend/Http/Client/Adapter/Exception.php'; + throw new Zend_Http_Client_Adapter_Exception('Error writing request to server'); + } + } + + return $request; + } + + /** + * Read response from server + * + * @return string + */ + public function read() + { + // First, read headers only + $response = ''; + $gotStatus = false; + $stream = !empty($this->config['stream']); + + while (($line = @fgets($this->socket)) !== false) { + $gotStatus = $gotStatus || (strpos($line, 'HTTP') !== false); + if ($gotStatus) { + $response .= $line; + if (rtrim($line) === '') break; + } + } + + $this->_checkSocketReadTimeout(); + + $statusCode = Zend_Http_Response::extractCode($response); + + // Handle 100 and 101 responses internally by restarting the read again + if ($statusCode == 100 || $statusCode == 101) return $this->read(); + + // Check headers to see what kind of connection / transfer encoding we have + $headers = Zend_Http_Response::extractHeaders($response); + + /** + * Responses to HEAD requests and 204 or 304 responses are not expected + * to have a body - stop reading here + */ + if ($statusCode == 304 || $statusCode == 204 || + $this->method == Zend_Http_Client::HEAD) { + + // Close the connection if requested to do so by the server + if (isset($headers['connection']) && $headers['connection'] == 'close') { + $this->close(); + } + return $response; + } + + // If we got a 'transfer-encoding: chunked' header + if (isset($headers['transfer-encoding'])) { + + if (strtolower($headers['transfer-encoding']) == 'chunked') { + + do { + $line = @fgets($this->socket); + $this->_checkSocketReadTimeout(); + + $chunk = $line; + + // Figure out the next chunk size + $chunksize = trim($line); + if (! ctype_xdigit($chunksize)) { + $this->close(); + require_once 'Zend/Http/Client/Adapter/Exception.php'; + throw new Zend_Http_Client_Adapter_Exception('Invalid chunk size "' . + $chunksize . '" unable to read chunked body'); + } + + // Convert the hexadecimal value to plain integer + $chunksize = hexdec($chunksize); + + // Read next chunk + $read_to = ftell($this->socket) + $chunksize; + + do { + $current_pos = ftell($this->socket); + if ($current_pos >= $read_to) break; + + if($this->out_stream) { + if(stream_copy_to_stream($this->socket, $this->out_stream, $read_to - $current_pos) == 0) { + $this->_checkSocketReadTimeout(); + break; + } + } else { + $line = @fread($this->socket, $read_to - $current_pos); + if ($line === false || strlen($line) === 0) { + $this->_checkSocketReadTimeout(); + break; + } + $chunk .= $line; + } + } while (! feof($this->socket)); + + $chunk .= @fgets($this->socket); + $this->_checkSocketReadTimeout(); + + if(!$this->out_stream) { + $response .= $chunk; + } + } while ($chunksize > 0); + } else { + $this->close(); + require_once 'Zend/Http/Client/Adapter/Exception.php'; + throw new Zend_Http_Client_Adapter_Exception('Cannot handle "' . + $headers['transfer-encoding'] . '" transfer encoding'); + } + + // We automatically decode chunked-messages when writing to a stream + // this means we have to disallow the Zend_Http_Response to do it again + if ($this->out_stream) { + $response = str_ireplace("Transfer-Encoding: chunked\r\n", '', $response); + } + // Else, if we got the content-length header, read this number of bytes + } elseif (isset($headers['content-length'])) { + + // If we got more than one Content-Length header (see ZF-9404) use + // the last value sent + if (is_array($headers['content-length'])) { + $contentLength = $headers['content-length'][count($headers['content-length']) - 1]; + } else { + $contentLength = $headers['content-length']; + } + + $current_pos = ftell($this->socket); + $chunk = ''; + + for ($read_to = $current_pos + $contentLength; + $read_to > $current_pos; + $current_pos = ftell($this->socket)) { + + if($this->out_stream) { + if(@stream_copy_to_stream($this->socket, $this->out_stream, $read_to - $current_pos) == 0) { + $this->_checkSocketReadTimeout(); + break; + } + } else { + $chunk = @fread($this->socket, $read_to - $current_pos); + if ($chunk === false || strlen($chunk) === 0) { + $this->_checkSocketReadTimeout(); + break; + } + + $response .= $chunk; + } + + // Break if the connection ended prematurely + if (feof($this->socket)) break; + } + + // Fallback: just read the response until EOF + } else { + + do { + if($this->out_stream) { + if(@stream_copy_to_stream($this->socket, $this->out_stream) == 0) { + $this->_checkSocketReadTimeout(); + break; + } + } else { + $buff = @fread($this->socket, 8192); + if ($buff === false || strlen($buff) === 0) { + $this->_checkSocketReadTimeout(); + break; + } else { + $response .= $buff; + } + } + + } while (feof($this->socket) === false); + + $this->close(); + } + + // Close the connection if requested to do so by the server + if (isset($headers['connection']) && $headers['connection'] == 'close') { + $this->close(); + } + + return $response; + } + + /** + * Close the connection to the server + * + */ + public function close() + { + if (is_resource($this->socket)) @fclose($this->socket); + $this->socket = null; + $this->connected_to = array(null, null); + } + + /** + * Check if the socket has timed out - if so close connection and throw + * an exception + * + * @throws Zend_Http_Client_Adapter_Exception with READ_TIMEOUT code + */ + protected function _checkSocketReadTimeout() + { + if ($this->socket) { + $info = stream_get_meta_data($this->socket); + $timedout = $info['timed_out']; + if ($timedout) { + $this->close(); + require_once 'Zend/Http/Client/Adapter/Exception.php'; + throw new Zend_Http_Client_Adapter_Exception( + "Read timed out after {$this->config['timeout']} seconds", + Zend_Http_Client_Adapter_Exception::READ_TIMEOUT + ); + } + } + } + + /** + * Set output stream for the response + * + * @param resource $stream + * @return Zend_Http_Client_Adapter_Socket + */ + public function setOutputStream($stream) + { + $this->out_stream = $stream; + return $this; + } + + /** + * Destructor: make sure the socket is disconnected + * + * If we are in persistent TCP mode, will not close the connection + * + */ + public function __destruct() + { + if (! $this->config['persistent']) { + if ($this->socket) $this->close(); + } + } +} diff --git a/Zend/Http/Client/Adapter/Stream.php b/Zend/Http/Client/Adapter/Stream.php new file mode 100644 index 00000000..5ca86aa7 --- /dev/null +++ b/Zend/Http/Client/Adapter/Stream.php @@ -0,0 +1,46 @@ +_nextRequestWillFail = (bool) $flag; + + return $this; + } + + /** + * Set the configuration array for the adapter + * + * @param Zend_Config | array $config + */ + public function setConfig($config = array()) + { + if ($config instanceof Zend_Config) { + $config = $config->toArray(); + + } elseif (! is_array($config)) { + require_once 'Zend/Http/Client/Adapter/Exception.php'; + throw new Zend_Http_Client_Adapter_Exception( + 'Array or Zend_Config object expected, got ' . gettype($config) + ); + } + + foreach ($config as $k => $v) { + $this->config[strtolower($k)] = $v; + } + } + + + /** + * Connect to the remote server + * + * @param string $host + * @param int $port + * @param boolean $secure + * @param int $timeout + * @throws Zend_Http_Client_Adapter_Exception + */ + public function connect($host, $port = 80, $secure = false) + { + if ($this->_nextRequestWillFail) { + $this->_nextRequestWillFail = false; + require_once 'Zend/Http/Client/Adapter/Exception.php'; + throw new Zend_Http_Client_Adapter_Exception('Request failed'); + } + } + + /** + * Send request to the remote server + * + * @param string $method + * @param Zend_Uri_Http $uri + * @param string $http_ver + * @param array $headers + * @param string $body + * @return string Request as string + */ + public function write($method, $uri, $http_ver = '1.1', $headers = array(), $body = '') + { + $host = $uri->getHost(); + $host = (strtolower($uri->getScheme()) == 'https' ? 'sslv2://' . $host : $host); + + // Build request headers + $path = $uri->getPath(); + if ($uri->getQuery()) $path .= '?' . $uri->getQuery(); + $request = "{$method} {$path} HTTP/{$http_ver}\r\n"; + foreach ($headers as $k => $v) { + if (is_string($k)) $v = ucfirst($k) . ": $v"; + $request .= "$v\r\n"; + } + + // Add the request body + $request .= "\r\n" . $body; + + // Do nothing - just return the request as string + + return $request; + } + + /** + * Return the response set in $this->setResponse() + * + * @return string + */ + public function read() + { + if ($this->responseIndex >= count($this->responses)) { + $this->responseIndex = 0; + } + return $this->responses[$this->responseIndex++]; + } + + /** + * Close the connection (dummy) + * + */ + public function close() + { } + + /** + * Set the HTTP response(s) to be returned by this adapter + * + * @param Zend_Http_Response|array|string $response + */ + public function setResponse($response) + { + if ($response instanceof Zend_Http_Response) { + $response = $response->asString("\r\n"); + } + + $this->responses = (array)$response; + $this->responseIndex = 0; + } + + /** + * Add another response to the response buffer. + * + * @param string Zend_Http_Response|$response + */ + public function addResponse($response) + { + if ($response instanceof Zend_Http_Response) { + $response = $response->asString("\r\n"); + } + + $this->responses[] = $response; + } + + /** + * Sets the position of the response buffer. Selects which + * response will be returned on the next call to read(). + * + * @param integer $index + */ + public function setResponseIndex($index) + { + if ($index < 0 || $index >= count($this->responses)) { + require_once 'Zend/Http/Client/Adapter/Exception.php'; + throw new Zend_Http_Client_Adapter_Exception( + 'Index out of range of response buffer size'); + } + $this->responseIndex = $index; + } +} diff --git a/Zend/Http/Client/Exception.php b/Zend/Http/Client/Exception.php new file mode 100644 index 00000000..b1d5ccc8 --- /dev/null +++ b/Zend/Http/Client/Exception.php @@ -0,0 +1,36 @@ + 'Continue', + 101 => 'Switching Protocols', + + // Success 2xx + 200 => 'OK', + 201 => 'Created', + 202 => 'Accepted', + 203 => 'Non-Authoritative Information', + 204 => 'No Content', + 205 => 'Reset Content', + 206 => 'Partial Content', + + // Redirection 3xx + 300 => 'Multiple Choices', + 301 => 'Moved Permanently', + 302 => 'Found', // 1.1 + 303 => 'See Other', + 304 => 'Not Modified', + 305 => 'Use Proxy', + // 306 is deprecated but reserved + 307 => 'Temporary Redirect', + + // Client Error 4xx + 400 => 'Bad Request', + 401 => 'Unauthorized', + 402 => 'Payment Required', + 403 => 'Forbidden', + 404 => 'Not Found', + 405 => 'Method Not Allowed', + 406 => 'Not Acceptable', + 407 => 'Proxy Authentication Required', + 408 => 'Request Timeout', + 409 => 'Conflict', + 410 => 'Gone', + 411 => 'Length Required', + 412 => 'Precondition Failed', + 413 => 'Request Entity Too Large', + 414 => 'Request-URI Too Long', + 415 => 'Unsupported Media Type', + 416 => 'Requested Range Not Satisfiable', + 417 => 'Expectation Failed', + + // Server Error 5xx + 500 => 'Internal Server Error', + 501 => 'Not Implemented', + 502 => 'Bad Gateway', + 503 => 'Service Unavailable', + 504 => 'Gateway Timeout', + 505 => 'HTTP Version Not Supported', + 509 => 'Bandwidth Limit Exceeded' + ); + + /** + * The HTTP version (1.0, 1.1) + * + * @var string + */ + protected $version; + + /** + * The HTTP response code + * + * @var int + */ + protected $code; + + /** + * The HTTP response code as string + * (e.g. 'Not Found' for 404 or 'Internal Server Error' for 500) + * + * @var string + */ + protected $message; + + /** + * The HTTP response headers array + * + * @var array + */ + protected $headers = array(); + + /** + * The HTTP response body + * + * @var string + */ + protected $body; + + /** + * HTTP response constructor + * + * In most cases, you would use Zend_Http_Response::fromString to parse an HTTP + * response string and create a new Zend_Http_Response object. + * + * NOTE: The constructor no longer accepts nulls or empty values for the code and + * headers and will throw an exception if the passed values do not form a valid HTTP + * responses. + * + * If no message is passed, the message will be guessed according to the response code. + * + * @param int $code Response code (200, 404, ...) + * @param array $headers Headers array + * @param string $body Response body + * @param string $version HTTP version + * @param string $message Response code as text + * @throws Zend_Http_Exception + */ + public function __construct($code, array $headers, $body = null, $version = '1.1', $message = null) + { + // Make sure the response code is valid and set it + if (self::responseCodeAsText($code) === null) { + require_once 'Zend/Http/Exception.php'; + throw new Zend_Http_Exception("{$code} is not a valid HTTP response code"); + } + + $this->code = $code; + + foreach ($headers as $name => $value) { + if (is_int($name)) { + $header = explode(":", $value, 2); + if (count($header) != 2) { + require_once 'Zend/Http/Exception.php'; + throw new Zend_Http_Exception("'{$value}' is not a valid HTTP header"); + } + + $name = trim($header[0]); + $value = trim($header[1]); + } + + $this->headers[ucwords(strtolower($name))] = $value; + } + + // Set the body + $this->body = $body; + + // Set the HTTP version + if (! preg_match('|^\d\.\d$|', $version)) { + require_once 'Zend/Http/Exception.php'; + throw new Zend_Http_Exception("Invalid HTTP response version: $version"); + } + + $this->version = $version; + + // If we got the response message, set it. Else, set it according to + // the response code + if (is_string($message)) { + $this->message = $message; + } else { + $this->message = self::responseCodeAsText($code); + } + } + + /** + * Check whether the response is an error + * + * @return boolean + */ + public function isError() + { + $restype = floor($this->code / 100); + if ($restype == 4 || $restype == 5) { + return true; + } + + return false; + } + + /** + * Check whether the response in successful + * + * @return boolean + */ + public function isSuccessful() + { + $restype = floor($this->code / 100); + if ($restype == 2 || $restype == 1) { // Shouldn't 3xx count as success as well ??? + return true; + } + + return false; + } + + /** + * Check whether the response is a redirection + * + * @return boolean + */ + public function isRedirect() + { + $restype = floor($this->code / 100); + if ($restype == 3) { + return true; + } + + return false; + } + + /** + * Get the response body as string + * + * This method returns the body of the HTTP response (the content), as it + * should be in it's readable version - that is, after decoding it (if it + * was decoded), deflating it (if it was gzip compressed), etc. + * + * If you want to get the raw body (as transfered on wire) use + * $this->getRawBody() instead. + * + * @return string + */ + public function getBody() + { + $body = ''; + + // Decode the body if it was transfer-encoded + switch (strtolower($this->getHeader('transfer-encoding'))) { + + // Handle chunked body + case 'chunked': + $body = self::decodeChunkedBody($this->body); + break; + + // No transfer encoding, or unknown encoding extension: + // return body as is + default: + $body = $this->body; + break; + } + + // Decode any content-encoding (gzip or deflate) if needed + switch (strtolower($this->getHeader('content-encoding'))) { + + // Handle gzip encoding + case 'gzip': + $body = self::decodeGzip($body); + break; + + // Handle deflate encoding + case 'deflate': + $body = self::decodeDeflate($body); + break; + + default: + break; + } + + return $body; + } + + /** + * Get the raw response body (as transfered "on wire") as string + * + * If the body is encoded (with Transfer-Encoding, not content-encoding - + * IE "chunked" body), gzip compressed, etc. it will not be decoded. + * + * @return string + */ + public function getRawBody() + { + return $this->body; + } + + /** + * Get the HTTP version of the response + * + * @return string + */ + public function getVersion() + { + return $this->version; + } + + /** + * Get the HTTP response status code + * + * @return int + */ + public function getStatus() + { + return $this->code; + } + + /** + * Return a message describing the HTTP response code + * (Eg. "OK", "Not Found", "Moved Permanently") + * + * @return string + */ + public function getMessage() + { + return $this->message; + } + + /** + * Get the response headers + * + * @return array + */ + public function getHeaders() + { + return $this->headers; + } + + /** + * Get a specific header as string, or null if it is not set + * + * @param string$header + * @return string|array|null + */ + public function getHeader($header) + { + $header = ucwords(strtolower($header)); + if (! is_string($header) || ! isset($this->headers[$header])) return null; + + return $this->headers[$header]; + } + + /** + * Get all headers as string + * + * @param boolean $status_line Whether to return the first status line (IE "HTTP 200 OK") + * @param string $br Line breaks (eg. "\n", "\r\n", "
") + * @return string + */ + public function getHeadersAsString($status_line = true, $br = "\n") + { + $str = ''; + + if ($status_line) { + $str = "HTTP/{$this->version} {$this->code} {$this->message}{$br}"; + } + + // Iterate over the headers and stringify them + foreach ($this->headers as $name => $value) + { + if (is_string($value)) + $str .= "{$name}: {$value}{$br}"; + + elseif (is_array($value)) { + foreach ($value as $subval) { + $str .= "{$name}: {$subval}{$br}"; + } + } + } + + return $str; + } + + /** + * Get the entire response as string + * + * @param string $br Line breaks (eg. "\n", "\r\n", "
") + * @return string + */ + public function asString($br = "\n") + { + return $this->getHeadersAsString(true, $br) . $br . $this->getRawBody(); + } + + /** + * Implements magic __toString() + * + * @return string + */ + public function __toString() + { + return $this->asString(); + } + + /** + * A convenience function that returns a text representation of + * HTTP response codes. Returns 'Unknown' for unknown codes. + * Returns array of all codes, if $code is not specified. + * + * Conforms to HTTP/1.1 as defined in RFC 2616 (except for 'Unknown') + * See http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10 for reference + * + * @param int $code HTTP response code + * @param boolean $http11 Use HTTP version 1.1 + * @return string + */ + public static function responseCodeAsText($code = null, $http11 = true) + { + $messages = self::$messages; + if (! $http11) $messages[302] = 'Moved Temporarily'; + + if ($code === null) { + return $messages; + } elseif (isset($messages[$code])) { + return $messages[$code]; + } else { + return 'Unknown'; + } + } + + /** + * Extract the response code from a response string + * + * @param string $response_str + * @return int + */ + public static function extractCode($response_str) + { + preg_match("|^HTTP/[\d\.x]+ (\d+)|", $response_str, $m); + + if (isset($m[1])) { + return (int) $m[1]; + } else { + return false; + } + } + + /** + * Extract the HTTP message from a response + * + * @param string $response_str + * @return string + */ + public static function extractMessage($response_str) + { + preg_match("|^HTTP/[\d\.x]+ \d+ ([^\r\n]+)|", $response_str, $m); + + if (isset($m[1])) { + return $m[1]; + } else { + return false; + } + } + + /** + * Extract the HTTP version from a response + * + * @param string $response_str + * @return string + */ + public static function extractVersion($response_str) + { + preg_match("|^HTTP/([\d\.x]+) \d+|", $response_str, $m); + + if (isset($m[1])) { + return $m[1]; + } else { + return false; + } + } + + /** + * Extract the headers from a response string + * + * @param string $response_str + * @return array + */ + public static function extractHeaders($response_str) + { + $headers = array(); + + // First, split body and headers + $parts = preg_split('|(?:\r?\n){2}|m', $response_str, 2); + if (! $parts[0]) return $headers; + + // Split headers part to lines + $lines = explode("\n", $parts[0]); + unset($parts); + $last_header = null; + + foreach($lines as $line) { + $line = trim($line, "\r\n"); + if ($line == "") break; + + // Locate headers like 'Location: ...' and 'Location:...' (note the missing space) + if (preg_match("|^([\w-]+):\s*(.+)|", $line, $m)) { + unset($last_header); + $h_name = strtolower($m[1]); + $h_value = $m[2]; + + if (isset($headers[$h_name])) { + if (! is_array($headers[$h_name])) { + $headers[$h_name] = array($headers[$h_name]); + } + + $headers[$h_name][] = $h_value; + } else { + $headers[$h_name] = $h_value; + } + $last_header = $h_name; + } elseif (preg_match("|^\s+(.+)$|", $line, $m) && $last_header !== null) { + if (is_array($headers[$last_header])) { + end($headers[$last_header]); + $last_header_key = key($headers[$last_header]); + $headers[$last_header][$last_header_key] .= $m[1]; + } else { + $headers[$last_header] .= $m[1]; + } + } + } + + return $headers; + } + + /** + * Extract the body from a response string + * + * @param string $response_str + * @return string + */ + public static function extractBody($response_str) + { + $parts = preg_split('|(?:\r?\n){2}|m', $response_str, 2); + if (isset($parts[1])) { + return $parts[1]; + } + return ''; + } + + /** + * Decode a "chunked" transfer-encoded body and return the decoded text + * + * @param string $body + * @return string + */ + public static function decodeChunkedBody($body) + { + $decBody = ''; + + // If mbstring overloads substr and strlen functions, we have to + // override it's internal encoding + if (function_exists('mb_internal_encoding') && + ((int) ini_get('mbstring.func_overload')) & 2) { + + $mbIntEnc = mb_internal_encoding(); + mb_internal_encoding('ASCII'); + } + + while (trim($body)) { + if (! preg_match("/^([\da-fA-F]+)[^\r\n]*\r\n/sm", $body, $m)) { + require_once 'Zend/Http/Exception.php'; + throw new Zend_Http_Exception("Error parsing body - doesn't seem to be a chunked message"); + } + + $length = hexdec(trim($m[1])); + $cut = strlen($m[0]); + $decBody .= substr($body, $cut, $length); + $body = substr($body, $cut + $length + 2); + } + + if (isset($mbIntEnc)) { + mb_internal_encoding($mbIntEnc); + } + + return $decBody; + } + + /** + * Decode a gzip encoded message (when Content-encoding = gzip) + * + * Currently requires PHP with zlib support + * + * @param string $body + * @return string + */ + public static function decodeGzip($body) + { + if (! function_exists('gzinflate')) { + require_once 'Zend/Http/Exception.php'; + throw new Zend_Http_Exception( + 'zlib extension is required in order to decode "gzip" encoding' + ); + } + + return gzinflate(substr($body, 10)); + } + + /** + * Decode a zlib deflated message (when Content-encoding = deflate) + * + * Currently requires PHP with zlib support + * + * @param string $body + * @return string + */ + public static function decodeDeflate($body) + { + if (! function_exists('gzuncompress')) { + require_once 'Zend/Http/Exception.php'; + throw new Zend_Http_Exception( + 'zlib extension is required in order to decode "deflate" encoding' + ); + } + + /** + * Some servers (IIS ?) send a broken deflate response, without the + * RFC-required zlib header. + * + * We try to detect the zlib header, and if it does not exsit we + * teat the body is plain DEFLATE content. + * + * This method was adapted from PEAR HTTP_Request2 by (c) Alexey Borzov + * + * @link http://framework.zend.com/issues/browse/ZF-6040 + */ + $zlibHeader = unpack('n', substr($body, 0, 2)); + if ($zlibHeader[1] % 31 == 0) { + return gzuncompress($body); + } else { + return gzinflate($body); + } + } + + /** + * Create a new Zend_Http_Response object from a string + * + * @param string $response_str + * @return Zend_Http_Response + */ + public static function fromString($response_str) + { + $code = self::extractCode($response_str); + $headers = self::extractHeaders($response_str); + $body = self::extractBody($response_str); + $version = self::extractVersion($response_str); + $message = self::extractMessage($response_str); + + return new Zend_Http_Response($code, $headers, $body, $version, $message); + } +} diff --git a/Zend/Http/Response/Stream.php b/Zend/Http/Response/Stream.php new file mode 100644 index 00000000..63758158 --- /dev/null +++ b/Zend/Http/Response/Stream.php @@ -0,0 +1,235 @@ +stream; + } + + /** + * Set the response stream + * + * @param resourse $stream + * @return Zend_Http_Response_Stream + */ + public function setStream($stream) + { + $this->stream = $stream; + return $this; + } + + /** + * Get the cleanup trigger + * + * @return boolean + */ + public function getCleanup() { + return $this->_cleanup; + } + + /** + * Set the cleanup trigger + * + * @param $cleanup Set cleanup trigger + */ + public function setCleanup($cleanup = true) { + $this->_cleanup = $cleanup; + } + + /** + * Get file name associated with the stream + * + * @return string + */ + public function getStreamName() { + return $this->stream_name; + } + + /** + * Set file name associated with the stream + * + * @param string $stream_name Name to set + * @return Zend_Http_Response_Stream + */ + public function setStreamName($stream_name) { + $this->stream_name = $stream_name; + return $this; + } + + + /** + * HTTP response constructor + * + * In most cases, you would use Zend_Http_Response::fromString to parse an HTTP + * response string and create a new Zend_Http_Response object. + * + * NOTE: The constructor no longer accepts nulls or empty values for the code and + * headers and will throw an exception if the passed values do not form a valid HTTP + * responses. + * + * If no message is passed, the message will be guessed according to the response code. + * + * @param int $code Response code (200, 404, ...) + * @param array $headers Headers array + * @param string $body Response body + * @param string $version HTTP version + * @param string $message Response code as text + * @throws Zend_Http_Exception + */ + public function __construct($code, $headers, $body = null, $version = '1.1', $message = null) + { + + if(is_resource($body)) { + $this->setStream($body); + $body = ''; + } + parent::__construct($code, $headers, $body, $version, $message); + } + + /** + * Create a new Zend_Http_Response_Stream object from a string + * + * @param string $response_str + * @param resource $stream + * @return Zend_Http_Response_Stream + */ + public static function fromStream($response_str, $stream) + { + $code = self::extractCode($response_str); + $headers = self::extractHeaders($response_str); + $version = self::extractVersion($response_str); + $message = self::extractMessage($response_str); + + return new self($code, $headers, $stream, $version, $message); + } + + /** + * Get the response body as string + * + * This method returns the body of the HTTP response (the content), as it + * should be in it's readable version - that is, after decoding it (if it + * was decoded), deflating it (if it was gzip compressed), etc. + * + * If you want to get the raw body (as transfered on wire) use + * $this->getRawBody() instead. + * + * @return string + */ + public function getBody() + { + if($this->stream != null) { + $this->readStream(); + } + return parent::getBody(); + } + + /** + * Get the raw response body (as transfered "on wire") as string + * + * If the body is encoded (with Transfer-Encoding, not content-encoding - + * IE "chunked" body), gzip compressed, etc. it will not be decoded. + * + * @return string + */ + public function getRawBody() + { + if($this->stream) { + $this->readStream(); + } + return $this->body; + } + + /** + * Read stream content and return it as string + * + * Function reads the remainder of the body from the stream and closes the stream. + * + * @return string + */ + protected function readStream() + { + if(!is_resource($this->stream)) { + return ''; + } + + if(isset($headers['content-length'])) { + $this->body = stream_get_contents($this->stream, $headers['content-length']); + } else { + $this->body = stream_get_contents($this->stream); + } + fclose($this->stream); + $this->stream = null; + } + + public function __destruct() + { + if(is_resource($this->stream)) { + fclose($this->stream); + $this->stream = null; + } + if($this->_cleanup) { + @unlink($this->stream_name); + } + } + +} diff --git a/Zend/Loader.php b/Zend/Loader.php new file mode 100644 index 00000000..2fc35d61 --- /dev/null +++ b/Zend/Loader.php @@ -0,0 +1,329 @@ + $dir) { + if ($dir == '.') { + $dirs[$key] = $dirPath; + } else { + $dir = rtrim($dir, '\\/'); + $dirs[$key] = $dir . DIRECTORY_SEPARATOR . $dirPath; + } + } + $file = basename($file); + self::loadFile($file, $dirs, true); + } else { + self::loadFile($file, null, true); + } + + if (!class_exists($class, false) && !interface_exists($class, false)) { + require_once 'Zend/Exception.php'; + throw new Zend_Exception("File \"$file\" does not exist or class \"$class\" was not found in the file"); + } + } + + /** + * Loads a PHP file. This is a wrapper for PHP's include() function. + * + * $filename must be the complete filename, including any + * extension such as ".php". Note that a security check is performed that + * does not permit extended characters in the filename. This method is + * intended for loading Zend Framework files. + * + * If $dirs is a string or an array, it will search the directories + * in the order supplied, and attempt to load the first matching file. + * + * If the file was not found in the $dirs, or if no $dirs were specified, + * it will attempt to load it from PHP's include_path. + * + * If $once is TRUE, it will use include_once() instead of include(). + * + * @param string $filename + * @param string|array $dirs - OPTIONAL either a path or array of paths + * to search. + * @param boolean $once + * @return boolean + * @throws Zend_Exception + */ + public static function loadFile($filename, $dirs = null, $once = false) + { + self::_securityCheck($filename); + + /** + * Search in provided directories, as well as include_path + */ + $incPath = false; + if (!empty($dirs) && (is_array($dirs) || is_string($dirs))) { + if (is_array($dirs)) { + $dirs = implode(PATH_SEPARATOR, $dirs); + } + $incPath = get_include_path(); + set_include_path($dirs . PATH_SEPARATOR . $incPath); + } + + /** + * Try finding for the plain filename in the include_path. + */ + if ($once) { + include_once $filename; + } else { + include $filename; + } + + /** + * If searching in directories, reset include_path + */ + if ($incPath) { + set_include_path($incPath); + } + + return true; + } + + /** + * Returns TRUE if the $filename is readable, or FALSE otherwise. + * This function uses the PHP include_path, where PHP's is_readable() + * does not. + * + * Note from ZF-2900: + * If you use custom error handler, please check whether return value + * from error_reporting() is zero or not. + * At mark of fopen() can not suppress warning if the handler is used. + * + * @param string $filename + * @return boolean + */ + public static function isReadable($filename) + { + if (is_readable($filename)) { + // Return early if the filename is readable without needing the + // include_path + return true; + } + + if (strtoupper(substr(PHP_OS, 0, 3)) == 'WIN' + && preg_match('/^[a-z]:/i', $filename) + ) { + // If on windows, and path provided is clearly an absolute path, + // return false immediately + return false; + } + + foreach (self::explodeIncludePath() as $path) { + if ($path == '.') { + if (is_readable($filename)) { + return true; + } + continue; + } + $file = $path . '/' . $filename; + if (is_readable($file)) { + return true; + } + } + return false; + } + + /** + * Explode an include path into an array + * + * If no path provided, uses current include_path. Works around issues that + * occur when the path includes stream schemas. + * + * @param string|null $path + * @return array + */ + public static function explodeIncludePath($path = null) + { + if (null === $path) { + $path = get_include_path(); + } + + if (PATH_SEPARATOR == ':') { + // On *nix systems, include_paths which include paths with a stream + // schema cannot be safely explode'd, so we have to be a bit more + // intelligent in the approach. + $paths = preg_split('#:(?!//)#', $path); + } else { + $paths = explode(PATH_SEPARATOR, $path); + } + return $paths; + } + + /** + * spl_autoload() suitable implementation for supporting class autoloading. + * + * Attach to spl_autoload() using the following: + * + * spl_autoload_register(array('Zend_Loader', 'autoload')); + * + * + * @deprecated Since 1.8.0 + * @param string $class + * @return string|false Class name on success; false on failure + */ + public static function autoload($class) + { + trigger_error(__CLASS__ . '::' . __METHOD__ . ' is deprecated as of 1.8.0 and will be removed with 2.0.0; use Zend_Loader_Autoloader instead', E_USER_NOTICE); + try { + @self::loadClass($class); + return $class; + } catch (Exception $e) { + return false; + } + } + + /** + * Register {@link autoload()} with spl_autoload() + * + * @deprecated Since 1.8.0 + * @param string $class (optional) + * @param boolean $enabled (optional) + * @return void + * @throws Zend_Exception if spl_autoload() is not found + * or if the specified class does not have an autoload() method. + */ + public static function registerAutoload($class = 'Zend_Loader', $enabled = true) + { + trigger_error(__CLASS__ . '::' . __METHOD__ . ' is deprecated as of 1.8.0 and will be removed with 2.0.0; use Zend_Loader_Autoloader instead', E_USER_NOTICE); + require_once 'Zend/Loader/Autoloader.php'; + $autoloader = Zend_Loader_Autoloader::getInstance(); + $autoloader->setFallbackAutoloader(true); + + if ('Zend_Loader' != $class) { + self::loadClass($class); + $methods = get_class_methods($class); + if (!in_array('autoload', (array) $methods)) { + require_once 'Zend/Exception.php'; + throw new Zend_Exception("The class \"$class\" does not have an autoload() method"); + } + + $callback = array($class, 'autoload'); + + if ($enabled) { + $autoloader->pushAutoloader($callback); + } else { + $autoloader->removeAutoloader($callback); + } + } + } + + /** + * Ensure that filename does not contain exploits + * + * @param string $filename + * @return void + * @throws Zend_Exception + */ + protected static function _securityCheck($filename) + { + /** + * Security check + */ + if (preg_match('/[^a-z0-9\\/\\\\_.:-]/i', $filename)) { + require_once 'Zend/Exception.php'; + throw new Zend_Exception('Security check: Illegal character in filename'); + } + } + + /** + * Attempt to include() the file. + * + * include() is not prefixed with the @ operator because if + * the file is loaded and contains a parse error, execution + * will halt silently and this is difficult to debug. + * + * Always set display_errors = Off on production servers! + * + * @param string $filespec + * @param boolean $once + * @return boolean + * @deprecated Since 1.5.0; use loadFile() instead + */ + protected static function _includeFile($filespec, $once = false) + { + if ($once) { + return include_once $filespec; + } else { + return include $filespec ; + } + } +} diff --git a/Zend/Oauth.php b/Zend/Oauth.php new file mode 100644 index 00000000..6bc33b58 --- /dev/null +++ b/Zend/Oauth.php @@ -0,0 +1,89 @@ +setHeaders('Authorization', null); + self::$httpClient->resetParameters(); + } + return self::$httpClient; + } + + /** + * Simple mechanism to delete the entire singleton HTTP Client instance + * which forces an new instantiation for subsequent requests. + * + * @return void + */ + public static function clearHttpClient() + { + self::$httpClient = null; + } +} diff --git a/Zend/Oauth/Client.php b/Zend/Oauth/Client.php new file mode 100644 index 00000000..7390693b --- /dev/null +++ b/Zend/Oauth/Client.php @@ -0,0 +1,336 @@ +_config = new Zend_Oauth_Config; + if ($oauthOptions !== null) { + if ($oauthOptions instanceof Zend_Config) { + $oauthOptions = $oauthOptions->toArray(); + } + $this->_config->setOptions($oauthOptions); + } + } + + /** + * Return the current connection adapter + * + * @return Zend_Http_Client_Adapter_Interface|string $adapter + */ + public function getAdapter() + { + return $this->adapter; + } + + /** + * Load the connection adapter + * + * @param Zend_Http_Client_Adapter_Interface $adapter + * @return void + */ + public function setAdapter($adapter) + { + if ($adapter == null) { + $this->adapter = $adapter; + } else { + parent::setAdapter($adapter); + } + } + + /** + * Set the streamingRequest variable which controls whether we are + * sending the raw (already encoded) POST data from a stream source. + * + * @param boolean $value The value to set. + * @return void + */ + public function setStreamingRequest($value) + { + $this->_streamingRequest = $value; + } + + /** + * Check whether the client is set to perform streaming requests. + * + * @return boolean True if yes, false otherwise. + */ + public function getStreamingRequest() + { + if ($this->_streamingRequest) { + return true; + } else { + return false; + } + } + + /** + * Prepare the request body (for POST and PUT requests) + * + * @return string + * @throws Zend_Http_Client_Exception + */ + protected function _prepareBody() + { + if($this->_streamingRequest) { + $this->setHeaders(self::CONTENT_LENGTH, + $this->raw_post_data->getTotalSize()); + return $this->raw_post_data; + } + else { + return parent::_prepareBody(); + } + } + + /** + * Clear all custom parameters we set. + * + * @return Zend_Http_Client + */ + public function resetParameters($clearAll = false) + { + $this->_streamingRequest = false; + return parent::resetParameters($clearAll); + } + + /** + * Set the raw (already encoded) POST data from a stream source. + * + * This is used to support POSTing from open file handles without + * caching the entire body into memory. It is a wrapper around + * Zend_Http_Client::setRawData(). + * + * @param string $data The request data + * @param string $enctype The encoding type + * @return Zend_Http_Client + */ + public function setRawDataStream($data, $enctype = null) + { + $this->_streamingRequest = true; + return $this->setRawData($data, $enctype); + } + + /** + * Same as Zend_Http_Client::setMethod() except it also creates an + * Oauth specific reference to the method type. + * Might be defunct and removed in a later iteration. + * + * @param string $method + * @return Zend_Http_Client + */ + public function setMethod($method = self::GET) + { + if ($method == self::GET) { + $this->setRequestMethod(self::GET); + } elseif($method == self::POST) { + $this->setRequestMethod(self::POST); + } elseif($method == self::PUT) { + $this->setRequestMethod(self::PUT); + } elseif($method == self::DELETE) { + $this->setRequestMethod(self::DELETE); + } elseif($method == self::HEAD) { + $this->setRequestMethod(self::HEAD); + } + return parent::setMethod($method); + } + + /** + * Same as Zend_Http_Client::request() except just before the request is + * executed, we automatically append any necessary OAuth parameters and + * sign the request using the relevant signature method. + * + * @param string $method + * @return Zend_Http_Response + */ + public function request($method = null) + { + if ($method !== null) { + $this->setMethod($method); + } + $this->prepareOauth(); + return parent::request(); + } + + /** + * Performs OAuth preparation on the request before sending. + * + * This primarily means taking a request, correctly encoding and signing + * all parameters, and applying the correct OAuth scheme to the method + * being used. + * + * @return void + * @throws Zend_Oauth_Exception If POSTBODY scheme requested, but GET request method used; or if invalid request scheme provided + */ + public function prepareOauth() + { + $requestScheme = $this->getRequestScheme(); + $requestMethod = $this->getRequestMethod(); + $query = null; + if ($requestScheme == Zend_Oauth::REQUEST_SCHEME_HEADER) { + $oauthHeaderValue = $this->getToken()->toHeader( + $this->getUri(true), + $this->_config, + $this->_getSignableParametersAsQueryString() + ); + $this->setHeaders('Authorization', $oauthHeaderValue); + } elseif ($requestScheme == Zend_Oauth::REQUEST_SCHEME_POSTBODY) { + if ($requestMethod == self::GET) { + require_once 'Zend/Oauth/Exception.php'; + throw new Zend_Oauth_Exception( + 'The client is configured to' + . ' pass OAuth parameters through a POST body but request method' + . ' is set to GET' + ); + } + $raw = $this->getToken()->toQueryString( + $this->getUri(true), + $this->_config, + $this->_getSignableParametersAsQueryString() + ); + $this->setRawData($raw); + $this->paramsPost = array(); + } elseif ($requestScheme == Zend_Oauth::REQUEST_SCHEME_QUERYSTRING) { + $params = array(); + $query = $this->getUri()->getQuery(); + if ($query) { + $queryParts = explode('&', $this->getUri()->getQuery()); + foreach ($queryParts as $queryPart) { + $kvTuple = explode('=', $queryPart); + $params[$kvTuple[0]] = + (array_key_exists(1, $kvTuple) ? $kvTuple[1] : NULL); + } + } + if (!empty($this->paramsPost)) { + $params = array_merge($params, $this->paramsPost); + $query = $this->getToken()->toQueryString( + $this->getUri(true), $this->_config, $params + ); + } + $query = $this->getToken()->toQueryString( + $this->getUri(true), $this->_config, $params + ); + $this->getUri()->setQuery($query); + $this->paramsGet = array(); + } else { + require_once 'Zend/Oauth/Exception.php'; + throw new Zend_Oauth_Exception('Invalid request scheme: ' . $requestScheme); + } + } + + /** + * Collect all signable parameters into a single array across query string + * and POST body. These are returned as a properly formatted single + * query string. + * + * @return string + */ + protected function _getSignableParametersAsQueryString() + { + $params = array(); + if (!empty($this->paramsGet)) { + $params = array_merge($params, $this->paramsGet); + $query = $this->getToken()->toQueryString( + $this->getUri(true), $this->_config, $params + ); + } + if (!empty($this->paramsPost)) { + $params = array_merge($params, $this->paramsPost); + $query = $this->getToken()->toQueryString( + $this->getUri(true), $this->_config, $params + ); + } + return $params; + } + + /** + * Simple Proxy to the current Zend_Oauth_Config method. It's that instance + * which holds all configuration methods and values this object also presents + * as it's API. + * + * @param string $method + * @param array $args + * @return mixed + * @throws Zend_Oauth_Exception if method does not exist in config object + */ + public function __call($method, array $args) + { + if (!method_exists($this->_config, $method)) { + require_once 'Zend/Oauth/Exception.php'; + throw new Zend_Oauth_Exception('Method does not exist: ' . $method); + } + return call_user_func_array(array($this->_config,$method), $args); + } +} diff --git a/Zend/Oauth/Config.php b/Zend/Oauth/Config.php new file mode 100644 index 00000000..be708ebe --- /dev/null +++ b/Zend/Oauth/Config.php @@ -0,0 +1,658 @@ +toArray(); + } + $this->setOptions($options); + } + } + + /** + * Parse option array or Zend_Config instance and setup options using their + * relevant mutators. + * + * @param array|Zend_Config $options + * @return Zend_Oauth_Config + */ + public function setOptions(array $options) + { + foreach ($options as $key => $value) { + switch ($key) { + case 'consumerKey': + $this->setConsumerKey($value); + break; + case 'consumerSecret': + $this->setConsumerSecret($value); + break; + case 'signatureMethod': + $this->setSignatureMethod($value); + break; + case 'version': + $this->setVersion($value); + break; + case 'callbackUrl': + $this->setCallbackUrl($value); + break; + case 'siteUrl': + $this->setSiteUrl($value); + break; + case 'requestTokenUrl': + $this->setRequestTokenUrl($value); + break; + case 'accessTokenUrl': + $this->setAccessTokenUrl($value); + break; + case 'userAuthorizationUrl': + $this->setUserAuthorizationUrl($value); + break; + case 'authorizeUrl': + $this->setAuthorizeUrl($value); + break; + case 'requestMethod': + $this->setRequestMethod($value); + break; + case 'rsaPrivateKey': + $this->setRsaPrivateKey($value); + break; + case 'rsaPublicKey': + $this->setRsaPublicKey($value); + break; + } + } + if (isset($options['requestScheme'])) { + $this->setRequestScheme($options['requestScheme']); + } + + return $this; + } + + /** + * Set consumer key + * + * @param string $key + * @return Zend_Oauth_Config + */ + public function setConsumerKey($key) + { + $this->_consumerKey = $key; + return $this; + } + + /** + * Get consumer key + * + * @return string + */ + public function getConsumerKey() + { + return $this->_consumerKey; + } + + /** + * Set consumer secret + * + * @param string $secret + * @return Zend_Oauth_Config + */ + public function setConsumerSecret($secret) + { + $this->_consumerSecret = $secret; + return $this; + } + + /** + * Get consumer secret + * + * Returns RSA private key if set; otherwise, returns any previously set + * consumer secret. + * + * @return string + */ + public function getConsumerSecret() + { + if ($this->_rsaPrivateKey !== null) { + return $this->_rsaPrivateKey; + } + return $this->_consumerSecret; + } + + /** + * Set signature method + * + * @param string $method + * @return Zend_Oauth_Config + * @throws Zend_Oauth_Exception if unsupported signature method specified + */ + public function setSignatureMethod($method) + { + $method = strtoupper($method); + if (!in_array($method, array( + 'HMAC-SHA1', 'HMAC-SHA256', 'RSA-SHA1', 'PLAINTEXT' + )) + ) { + require_once 'Zend/Oauth/Exception.php'; + throw new Zend_Oauth_Exception('Unsupported signature method: ' + . $method + . '. Supported are HMAC-SHA1, RSA-SHA1, PLAINTEXT and HMAC-SHA256'); + } + $this->_signatureMethod = $method;; + return $this; + } + + /** + * Get signature method + * + * @return string + */ + public function getSignatureMethod() + { + return $this->_signatureMethod; + } + + /** + * Set request scheme + * + * @param string $scheme + * @return Zend_Oauth_Config + * @throws Zend_Oauth_Exception if invalid scheme specified, or if POSTBODY set when request method of GET is specified + */ + public function setRequestScheme($scheme) + { + $scheme = strtolower($scheme); + if (!in_array($scheme, array( + Zend_Oauth::REQUEST_SCHEME_HEADER, + Zend_Oauth::REQUEST_SCHEME_POSTBODY, + Zend_Oauth::REQUEST_SCHEME_QUERYSTRING, + )) + ) { + require_once 'Zend/Oauth/Exception.php'; + throw new Zend_Oauth_Exception( + '\'' . $scheme . '\' is an unsupported request scheme' + ); + } + if ($scheme == Zend_Oauth::REQUEST_SCHEME_POSTBODY + && $this->getRequestMethod() == Zend_Oauth::GET + ) { + require_once 'Zend/Oauth/Exception.php'; + throw new Zend_Oauth_Exception( + 'Cannot set POSTBODY request method if HTTP method set to GET' + ); + } + $this->_requestScheme = $scheme; + return $this; + } + + /** + * Get request scheme + * + * @return string + */ + public function getRequestScheme() + { + return $this->_requestScheme; + } + + /** + * Set version + * + * @param string $version + * @return Zend_Oauth_Config + */ + public function setVersion($version) + { + $this->_version = $version; + return $this; + } + + /** + * Get version + * + * @return string + */ + public function getVersion() + { + return $this->_version; + } + + /** + * Set callback URL + * + * @param string $url + * @return Zend_Oauth_Config + * @throws Zend_Oauth_Exception for invalid URLs + */ + public function setCallbackUrl($url) + { + if (!Zend_Uri::check($url)) { + require_once 'Zend/Oauth/Exception.php'; + throw new Zend_Oauth_Exception( + '\'' . $url . '\' is not a valid URI' + ); + } + $this->_callbackUrl = $url; + return $this; + } + + /** + * Get callback URL + * + * @return string + */ + public function getCallbackUrl() + { + return $this->_callbackUrl; + } + + /** + * Set site URL + * + * @param string $url + * @return Zend_Oauth_Config + * @throws Zend_Oauth_Exception for invalid URLs + */ + public function setSiteUrl($url) + { + if (!Zend_Uri::check($url)) { + require_once 'Zend/Oauth/Exception.php'; + throw new Zend_Oauth_Exception( + '\'' . $url . '\' is not a valid URI' + ); + } + $this->_siteUrl = $url; + return $this; + } + + /** + * Get site URL + * + * @return string + */ + public function getSiteUrl() + { + return $this->_siteUrl; + } + + /** + * Set request token URL + * + * @param string $url + * @return Zend_Oauth_Config + * @throws Zend_Oauth_Exception for invalid URLs + */ + public function setRequestTokenUrl($url) + { + if (!Zend_Uri::check($url)) { + require_once 'Zend/Oauth/Exception.php'; + throw new Zend_Oauth_Exception( + '\'' . $url . '\' is not a valid URI' + ); + } + $this->_requestTokenUrl = rtrim($url, '/'); + return $this; + } + + /** + * Get request token URL + * + * If no request token URL has been set, but a site URL has, returns the + * site URL with the string "/request_token" appended. + * + * @return string + */ + public function getRequestTokenUrl() + { + if (!$this->_requestTokenUrl && $this->_siteUrl) { + return $this->_siteUrl . '/request_token'; + } + return $this->_requestTokenUrl; + } + + /** + * Set access token URL + * + * @param string $url + * @return Zend_Oauth_Config + * @throws Zend_Oauth_Exception for invalid URLs + */ + public function setAccessTokenUrl($url) + { + if (!Zend_Uri::check($url)) { + require_once 'Zend/Oauth/Exception.php'; + throw new Zend_Oauth_Exception( + '\'' . $url . '\' is not a valid URI' + ); + } + $this->_accessTokenUrl = rtrim($url, '/'); + return $this; + } + + /** + * Get access token URL + * + * If no access token URL has been set, but a site URL has, returns the + * site URL with the string "/access_token" appended. + * + * @return string + */ + public function getAccessTokenUrl() + { + if (!$this->_accessTokenUrl && $this->_siteUrl) { + return $this->_siteUrl . '/access_token'; + } + return $this->_accessTokenUrl; + } + + /** + * Set user authorization URL + * + * @param string $url + * @return Zend_Oauth_Config + * @throws Zend_Oauth_Exception for invalid URLs + */ + public function setUserAuthorizationUrl($url) + { + return $this->setAuthorizeUrl($url); + } + + /** + * Set authorization URL + * + * @param string $url + * @return Zend_Oauth_Config + * @throws Zend_Oauth_Exception for invalid URLs + */ + public function setAuthorizeUrl($url) + { + if (!Zend_Uri::check($url)) { + require_once 'Zend/Oauth/Exception.php'; + throw new Zend_Oauth_Exception( + '\'' . $url . '\' is not a valid URI' + ); + } + $this->_authorizeUrl = rtrim($url, '/'); + return $this; + } + + /** + * Get user authorization URL + * + * @return string + */ + public function getUserAuthorizationUrl() + { + return $this->getAuthorizeUrl(); + } + + /** + * Get authorization URL + * + * If no authorization URL has been set, but a site URL has, returns the + * site URL with the string "/authorize" appended. + * + * @return string + */ + public function getAuthorizeUrl() + { + if (!$this->_authorizeUrl && $this->_siteUrl) { + return $this->_siteUrl . '/authorize'; + } + return $this->_authorizeUrl; + } + + /** + * Set request method + * + * @param string $method + * @return Zend_Oauth_Config + * @throws Zend_Oauth_Exception for invalid request methods + */ + public function setRequestMethod($method) + { + $method = strtoupper($method); + if (!in_array($method, array( + Zend_Oauth::GET, + Zend_Oauth::POST, + Zend_Oauth::PUT, + Zend_Oauth::DELETE, + )) + ) { + require_once 'Zend/Oauth/Exception.php'; + throw new Zend_Oauth_Exception('Invalid method: ' . $method); + } + $this->_requestMethod = $method; + return $this; + } + + /** + * Get request method + * + * @return string + */ + public function getRequestMethod() + { + return $this->_requestMethod; + } + + /** + * Set RSA public key + * + * @param Zend_Crypt_Rsa_Key_Public $key + * @return Zend_Oauth_Config + */ + public function setRsaPublicKey(Zend_Crypt_Rsa_Key_Public $key) + { + $this->_rsaPublicKey = $key; + return $this; + } + + /** + * Get RSA public key + * + * @return Zend_Crypt_Rsa_Key_Public + */ + public function getRsaPublicKey() + { + return $this->_rsaPublicKey; + } + + /** + * Set RSA private key + * + * @param Zend_Crypt_Rsa_Key_Private $key + * @return Zend_Oauth_Config + */ + public function setRsaPrivateKey(Zend_Crypt_Rsa_Key_Private $key) + { + $this->_rsaPrivateKey = $key; + return $this; + } + + /** + * Get RSA private key + * + * @return Zend_Crypt_Rsa_Key_Private + */ + public function getRsaPrivateKey() + { + return $this->_rsaPrivateKey; + } + + /** + * Set OAuth token + * + * @param Zend_Oauth_Token $token + * @return Zend_Oauth_Config + */ + public function setToken(Zend_Oauth_Token $token) + { + $this->_token = $token; + return $this; + } + + /** + * Get OAuth token + * + * @return Zend_Oauth_Token + */ + public function getToken() + { + return $this->_token; + } +} diff --git a/Zend/Oauth/Config/ConfigInterface.php b/Zend/Oauth/Config/ConfigInterface.php new file mode 100644 index 00000000..82526a7b --- /dev/null +++ b/Zend/Oauth/Config/ConfigInterface.php @@ -0,0 +1,75 @@ +_config = new Zend_Oauth_Config; + if ($options !== null) { + if ($options instanceof Zend_Config) { + $options = $options->toArray(); + } + $this->_config->setOptions($options); + } + } + + /** + * Attempts to retrieve a Request Token from an OAuth Provider which is + * later exchanged for an authorized Access Token used to access the + * protected resources exposed by a web service API. + * + * @param null|array $customServiceParameters Non-OAuth Provider-specified parameters + * @param null|string $httpMethod + * @param null|Zend_Oauth_Http_RequestToken $request + * @return Zend_Oauth_Token_Request + */ + public function getRequestToken( + array $customServiceParameters = null, + $httpMethod = null, + Zend_Oauth_Http_RequestToken $request = null + ) { + if ($request === null) { + $request = new Zend_Oauth_Http_RequestToken($this, $customServiceParameters); + } elseif($customServiceParameters !== null) { + $request->setParameters($customServiceParameters); + } + if ($httpMethod !== null) { + $request->setMethod($httpMethod); + } else { + $request->setMethod($this->getRequestMethod()); + } + $this->_requestToken = $request->execute(); + return $this->_requestToken; + } + + /** + * After a Request Token is retrieved, the user may be redirected to the + * OAuth Provider to authorize the application's access to their + * protected resources - the redirect URL being provided by this method. + * Once the user has authorized the application for access, they are + * redirected back to the application which can now exchange the previous + * Request Token for a fully authorized Access Token. + * + * @param null|array $customServiceParameters + * @param null|Zend_Oauth_Token_Request $token + * @param null|Zend_OAuth_Http_UserAuthorization $redirect + * @return string + */ + public function getRedirectUrl( + array $customServiceParameters = null, + Zend_Oauth_Token_Request $token = null, + Zend_Oauth_Http_UserAuthorization $redirect = null + ) { + if ($redirect === null) { + $redirect = new Zend_Oauth_Http_UserAuthorization($this, $customServiceParameters); + } elseif($customServiceParameters !== null) { + $redirect->setParameters($customServiceParameters); + } + if ($token !== null) { + $this->_requestToken = $token; + } + return $redirect->getUrl(); + } + + /** + * Rather than retrieve a redirect URL for use, e.g. from a controller, + * one may perform an immediate redirect. + * + * Sends headers and exit()s on completion. + * + * @param null|array $customServiceParameters + * @param null|Zend_Oauth_Http_UserAuthorization $request + * @return void + */ + public function redirect( + array $customServiceParameters = null, + Zend_Oauth_Http_UserAuthorization $request = null + ) { + $redirectUrl = $this->getRedirectUrl($customServiceParameters, $request); + header('Location: ' . $redirectUrl); + exit(1); + } + + /** + * Retrieve an Access Token in exchange for a previously received/authorized + * Request Token. + * + * @param array $queryData GET data returned in user's redirect from Provider + * @param Zend_Oauth_Token_Request Request Token information + * @param string $httpMethod + * @param Zend_Oauth_Http_AccessToken $request + * @return Zend_Oauth_Token_Access + * @throws Zend_Oauth_Exception on invalid authorization token, non-matching response authorization token, or unprovided authorization token + */ + public function getAccessToken( + $queryData, + Zend_Oauth_Token_Request $token, + $httpMethod = null, + Zend_Oauth_Http_AccessToken $request = null + ) { + $authorizedToken = new Zend_Oauth_Token_AuthorizedRequest($queryData); + if (!$authorizedToken->isValid()) { + require_once 'Zend/Oauth/Exception.php'; + throw new Zend_Oauth_Exception( + 'Response from Service Provider is not a valid authorized request token'); + } + if ($request === null) { + $request = new Zend_Oauth_Http_AccessToken($this); + } + + // OAuth 1.0a Verifier + if (!is_null($authorizedToken->getParam('oauth_verifier'))) { + $params = array_merge($request->getParameters(), array( + 'oauth_verifier' => $authorizedToken->getParam('oauth_verifier') + )); + $request->setParameters($params); + } + if ($httpMethod !== null) { + $request->setMethod($httpMethod); + } else { + $request->setMethod($this->getRequestMethod()); + } + if (isset($token)) { + if ($authorizedToken->getToken() !== $token->getToken()) { + require_once 'Zend/Oauth/Exception.php'; + throw new Zend_Oauth_Exception( + 'Authorized token from Service Provider does not match' + . ' supplied Request Token details' + ); + } + } else { + require_once 'Zend/Oauth/Exception.php'; + throw new Zend_Oauth_Exception('Request token must be passed to method'); + } + $this->_requestToken = $token; + $this->_accessToken = $request->execute(); + return $this->_accessToken; + } + + /** + * Return whatever the last Request Token retrieved was while using the + * current Consumer instance. + * + * @return Zend_Oauth_Token_Request + */ + public function getLastRequestToken() + { + return $this->_requestToken; + } + + /** + * Return whatever the last Access Token retrieved was while using the + * current Consumer instance. + * + * @return Zend_Oauth_Token_Access + */ + public function getLastAccessToken() + { + return $this->_accessToken; + } + + /** + * Alias to self::getLastAccessToken() + * + * @return Zend_Oauth_Token_Access + */ + public function getToken() + { + return $this->_accessToken; + } + + /** + * Simple Proxy to the current Zend_Oauth_Config method. It's that instance + * which holds all configuration methods and values this object also presents + * as it's API. + * + * @param string $method + * @param array $args + * @return mixed + * @throws Zend_Oauth_Exception if method does not exist in config object + */ + public function __call($method, array $args) + { + if (!method_exists($this->_config, $method)) { + require_once 'Zend/Oauth/Exception.php'; + throw new Zend_Oauth_Exception('Method does not exist: '.$method); + } + return call_user_func_array(array($this->_config,$method), $args); + } +} diff --git a/Zend/Oauth/Exception.php b/Zend/Oauth/Exception.php new file mode 100644 index 00000000..046920ec --- /dev/null +++ b/Zend/Oauth/Exception.php @@ -0,0 +1,33 @@ +_consumer = $consumer; + $this->_preferredRequestScheme = $this->_consumer->getRequestScheme(); + if ($parameters !== null) { + $this->setParameters($parameters); + } + if ($utility !== null) { + $this->_httpUtility = $utility; + } else { + $this->_httpUtility = new Zend_Oauth_Http_Utility; + } + } + + /** + * Set a preferred HTTP request method. + * + * @param string $method + * @return Zend_Oauth_Http + */ + public function setMethod($method) + { + if (!in_array($method, array(Zend_Oauth::POST, Zend_Oauth::GET))) { + require_once 'Zend/Oauth/Exception.php'; + throw new Zend_Oauth_Exception('invalid HTTP method: ' . $method); + } + $this->_preferredRequestMethod = $method; + return $this; + } + + /** + * Preferred HTTP request method accessor. + * + * @return string + */ + public function getMethod() + { + return $this->_preferredRequestMethod; + } + + /** + * Mutator to set an array of custom parameters for the HTTP request. + * + * @param array $customServiceParameters + * @return Zend_Oauth_Http + */ + public function setParameters(array $customServiceParameters) + { + $this->_parameters = $customServiceParameters; + return $this; + } + + /** + * Accessor for an array of custom parameters. + * + * @return array + */ + public function getParameters() + { + return $this->_parameters; + } + + /** + * Return the Consumer instance in use. + * + * @return Zend_Oauth_Consumer + */ + public function getConsumer() + { + return $this->_consumer; + } + + /** + * Commence a request cycle where the current HTTP method and OAuth + * request scheme set an upper preferred HTTP request style and where + * failures generate a new HTTP request style further down the OAuth + * preference list for OAuth Request Schemes. + * On success, return the Request object that results for processing. + * + * @param array $params + * @return Zend_Http_Response + * @throws Zend_Oauth_Exception on HTTP request errors + * @todo Remove cycling?; Replace with upfront do-or-die configuration + */ + public function startRequestCycle(array $params) + { + $response = null; + $body = null; + $status = null; + try { + $response = $this->_attemptRequest($params); + } catch (Zend_Http_Client_Exception $e) { + require_once 'Zend/Oauth/Exception.php'; + throw new Zend_Oauth_Exception('Error in HTTP request', null, $e); + } + if ($response !== null) { + $body = $response->getBody(); + $status = $response->getStatus(); + } + if ($response === null // Request failure/exception + || $status == 500 // Internal Server Error + || $status == 400 // Bad Request + || $status == 401 // Unauthorized + || empty($body) // Missing token + ) { + $this->_assessRequestAttempt($response); + $response = $this->startRequestCycle($params); + } + return $response; + } + + /** + * Return an instance of Zend_Http_Client configured to use the Query + * String scheme for an OAuth driven HTTP request. + * + * @param array $params + * @param string $url + * @return Zend_Http_Client + */ + public function getRequestSchemeQueryStringClient(array $params, $url) + { + $client = Zend_Oauth::getHttpClient(); + $client->setUri($url); + $client->getUri()->setQuery( + $this->_httpUtility->toEncodedQueryString($params) + ); + $client->setMethod($this->_preferredRequestMethod); + return $client; + } + + /** + * Manages the switch from OAuth request scheme to another lower preference + * scheme during a request cycle. + * + * @param Zend_Http_Response + * @return void + * @throws Zend_Oauth_Exception if unable to retrieve valid token response + */ + protected function _assessRequestAttempt(Zend_Http_Response $response = null) + { + switch ($this->_preferredRequestScheme) { + case Zend_Oauth::REQUEST_SCHEME_HEADER: + $this->_preferredRequestScheme = Zend_Oauth::REQUEST_SCHEME_POSTBODY; + break; + case Zend_Oauth::REQUEST_SCHEME_POSTBODY: + $this->_preferredRequestScheme = Zend_Oauth::REQUEST_SCHEME_QUERYSTRING; + break; + default: + require_once 'Zend/Oauth/Exception.php'; + throw new Zend_Oauth_Exception( + 'Could not retrieve a valid Token response from Token URL:' + . ($response !== null + ? PHP_EOL . $response->getBody() + : ' No body - check for headers') + ); + } + } + + /** + * Generates a valid OAuth Authorization header based on the provided + * parameters and realm. + * + * @param array $params + * @param string $realm + * @return string + */ + protected function _toAuthorizationHeader(array $params, $realm = null) + { + $headerValue = array(); + $headerValue[] = 'OAuth realm="' . $realm . '"'; + foreach ($params as $key => $value) { + if (!preg_match("/^oauth_/", $key)) { + continue; + } + $headerValue[] = Zend_Oauth_Http_Utility::urlEncode($key) + . '="' + . Zend_Oauth_Http_Utility::urlEncode($value) + . '"'; + } + return implode(",", $headerValue); + } +} diff --git a/Zend/Oauth/Http/AccessToken.php b/Zend/Oauth/Http/AccessToken.php new file mode 100644 index 00000000..d234617f --- /dev/null +++ b/Zend/Oauth/Http/AccessToken.php @@ -0,0 +1,189 @@ +assembleParams(); + $response = $this->startRequestCycle($params); + $return = new Zend_Oauth_Token_Access($response); + return $return; + } + + /** + * Assemble all parameters for an OAuth Access Token request. + * + * @return array + */ + public function assembleParams() + { + $params = array( + 'oauth_consumer_key' => $this->_consumer->getConsumerKey(), + 'oauth_nonce' => $this->_httpUtility->generateNonce(), + 'oauth_signature_method' => $this->_consumer->getSignatureMethod(), + 'oauth_timestamp' => $this->_httpUtility->generateTimestamp(), + 'oauth_token' => $this->_consumer->getLastRequestToken()->getToken(), + 'oauth_version' => $this->_consumer->getVersion(), + ); + + if (!empty($this->_parameters)) { + $params = array_merge($params, $this->_parameters); + } + + $params['oauth_signature'] = $this->_httpUtility->sign( + $params, + $this->_consumer->getSignatureMethod(), + $this->_consumer->getConsumerSecret(), + $this->_consumer->getLastRequestToken()->getTokenSecret(), + $this->_preferredRequestMethod, + $this->_consumer->getAccessTokenUrl() + ); + + return $params; + } + + /** + * Generate and return a HTTP Client configured for the Header Request Scheme + * specified by OAuth, for use in requesting an Access Token. + * + * @param array $params + * @return Zend_Http_Client + */ + public function getRequestSchemeHeaderClient(array $params) + { + $params = $this->_cleanParamsOfIllegalCustomParameters($params); + $headerValue = $this->_toAuthorizationHeader($params); + $client = Zend_Oauth::getHttpClient(); + + $client->setUri($this->_consumer->getAccessTokenUrl()); + $client->setHeaders('Authorization', $headerValue); + $client->setMethod($this->_preferredRequestMethod); + + return $client; + } + + /** + * Generate and return a HTTP Client configured for the POST Body Request + * Scheme specified by OAuth, for use in requesting an Access Token. + * + * @param array $params + * @return Zend_Http_Client + */ + public function getRequestSchemePostBodyClient(array $params) + { + $params = $this->_cleanParamsOfIllegalCustomParameters($params); + $client = Zend_Oauth::getHttpClient(); + $client->setUri($this->_consumer->getAccessTokenUrl()); + $client->setMethod($this->_preferredRequestMethod); + $client->setRawData( + $this->_httpUtility->toEncodedQueryString($params) + ); + $client->setHeaders( + Zend_Http_Client::CONTENT_TYPE, + Zend_Http_Client::ENC_URLENCODED + ); + return $client; + } + + /** + * Generate and return a HTTP Client configured for the Query String Request + * Scheme specified by OAuth, for use in requesting an Access Token. + * + * @param array $params + * @param string $url + * @return Zend_Http_Client + */ + public function getRequestSchemeQueryStringClient(array $params, $url) + { + $params = $this->_cleanParamsOfIllegalCustomParameters($params); + return parent::getRequestSchemeQueryStringClient($params, $url); + } + + /** + * Attempt a request based on the current configured OAuth Request Scheme and + * return the resulting HTTP Response. + * + * @param array $params + * @return Zend_Http_Response + */ + protected function _attemptRequest(array $params) + { + switch ($this->_preferredRequestScheme) { + case Zend_Oauth::REQUEST_SCHEME_HEADER: + $httpClient = $this->getRequestSchemeHeaderClient($params); + break; + case Zend_Oauth::REQUEST_SCHEME_POSTBODY: + $httpClient = $this->getRequestSchemePostBodyClient($params); + break; + case Zend_Oauth::REQUEST_SCHEME_QUERYSTRING: + $httpClient = $this->getRequestSchemeQueryStringClient($params, + $this->_consumer->getAccessTokenUrl()); + break; + } + return $httpClient->request(); + } + + /** + * Access Token requests specifically may not contain non-OAuth parameters. + * So these should be striped out and excluded. Detection is easy since + * specified OAuth parameters start with "oauth_", Extension params start + * with "xouth_", and no other parameters should use these prefixes. + * + * xouth params are not currently allowable. + * + * @param array $params + * @return array + */ + protected function _cleanParamsOfIllegalCustomParameters(array $params) + { + foreach ($params as $key=>$value) { + if (!preg_match("/^oauth_/", $key)) { + unset($params[$key]); + } + } + return $params; + } +} diff --git a/Zend/Oauth/Http/RequestToken.php b/Zend/Oauth/Http/RequestToken.php new file mode 100644 index 00000000..812ce2df --- /dev/null +++ b/Zend/Oauth/Http/RequestToken.php @@ -0,0 +1,162 @@ +assembleParams(); + $response = $this->startRequestCycle($params); + $return = new Zend_Oauth_Token_Request($response); + return $return; + } + + /** + * Assemble all parameters for an OAuth Request Token request. + * + * @return array + */ + public function assembleParams() + { + $params = array( + 'oauth_consumer_key' => $this->_consumer->getConsumerKey(), + 'oauth_nonce' => $this->_httpUtility->generateNonce(), + 'oauth_timestamp' => $this->_httpUtility->generateTimestamp(), + 'oauth_signature_method' => $this->_consumer->getSignatureMethod(), + 'oauth_version' => $this->_consumer->getVersion(), + ); + + // indicates we support 1.0a + if ($this->_consumer->getCallbackUrl()) { + $params['oauth_callback'] = $this->_consumer->getCallbackUrl(); + } else { + $params['oauth_callback'] = 'oob'; + } + + if (!empty($this->_parameters)) { + $params = array_merge($params, $this->_parameters); + } + + $params['oauth_signature'] = $this->_httpUtility->sign( + $params, + $this->_consumer->getSignatureMethod(), + $this->_consumer->getConsumerSecret(), + null, + $this->_preferredRequestMethod, + $this->_consumer->getRequestTokenUrl() + ); + + return $params; + } + + /** + * Generate and return a HTTP Client configured for the Header Request Scheme + * specified by OAuth, for use in requesting a Request Token. + * + * @param array $params + * @return Zend_Http_Client + */ + public function getRequestSchemeHeaderClient(array $params) + { + $headerValue = $this->_httpUtility->toAuthorizationHeader( + $params + ); + $client = Zend_Oauth::getHttpClient(); + $client->setUri($this->_consumer->getRequestTokenUrl()); + $client->setHeaders('Authorization', $headerValue); + $rawdata = $this->_httpUtility->toEncodedQueryString($params, true); + if (!empty($rawdata)) { + $client->setRawData($rawdata); + } + $client->setMethod($this->_preferredRequestMethod); + return $client; + } + + /** + * Generate and return a HTTP Client configured for the POST Body Request + * Scheme specified by OAuth, for use in requesting a Request Token. + * + * @param array $params + * @return Zend_Http_Client + */ + public function getRequestSchemePostBodyClient(array $params) + { + $client = Zend_Oauth::getHttpClient(); + $client->setUri($this->_consumer->getRequestTokenUrl()); + $client->setMethod($this->_preferredRequestMethod); + $client->setRawData( + $this->_httpUtility->toEncodedQueryString($params) + ); + $client->setHeaders( + Zend_Http_Client::CONTENT_TYPE, + Zend_Http_Client::ENC_URLENCODED + ); + return $client; + } + + /** + * Attempt a request based on the current configured OAuth Request Scheme and + * return the resulting HTTP Response. + * + * @param array $params + * @return Zend_Http_Response + */ + protected function _attemptRequest(array $params) + { + switch ($this->_preferredRequestScheme) { + case Zend_Oauth::REQUEST_SCHEME_HEADER: + $httpClient = $this->getRequestSchemeHeaderClient($params); + break; + case Zend_Oauth::REQUEST_SCHEME_POSTBODY: + $httpClient = $this->getRequestSchemePostBodyClient($params); + break; + case Zend_Oauth::REQUEST_SCHEME_QUERYSTRING: + $httpClient = $this->getRequestSchemeQueryStringClient($params, + $this->_consumer->getRequestTokenUrl()); + break; + } + return $httpClient->request(); + } +} diff --git a/Zend/Oauth/Http/UserAuthorization.php b/Zend/Oauth/Http/UserAuthorization.php new file mode 100644 index 00000000..02c0c3a8 --- /dev/null +++ b/Zend/Oauth/Http/UserAuthorization.php @@ -0,0 +1,78 @@ +assembleParams(); + $uri = Zend_Uri_Http::fromString($this->_consumer->getUserAuthorizationUrl()); + + $uri->setQuery( + $this->_httpUtility->toEncodedQueryString($params) + ); + + return $uri->getUri(); + } + + /** + * Assemble all parameters for inclusion in a redirect URL. + * + * @return array + */ + public function assembleParams() + { + $params = array( + 'oauth_token' => $this->_consumer->getLastRequestToken()->getToken(), + ); + + if (!Zend_Oauth_Client::$supportsRevisionA) { + $callback = $this->_consumer->getCallbackUrl(); + if (!empty($callback)) { + $params['oauth_callback'] = $callback; + } + } + + if (!empty($this->_parameters)) { + $params = array_merge($params, $this->_parameters); + } + + return $params; + } +} diff --git a/Zend/Oauth/Http/Utility.php b/Zend/Oauth/Http/Utility.php new file mode 100644 index 00000000..26215a6d --- /dev/null +++ b/Zend/Oauth/Http/Utility.php @@ -0,0 +1,217 @@ + $config->getConsumerKey(), + 'oauth_nonce' => $this->generateNonce(), + 'oauth_signature_method' => $config->getSignatureMethod(), + 'oauth_timestamp' => $this->generateTimestamp(), + 'oauth_version' => $config->getVersion(), + ); + + if ($config->getToken()->getToken() != null) { + $params['oauth_token'] = $config->getToken()->getToken(); + } + + + if ($serviceProviderParams !== null) { + $params = array_merge($params, $serviceProviderParams); + } + + $params['oauth_signature'] = $this->sign( + $params, + $config->getSignatureMethod(), + $config->getConsumerSecret(), + $config->getToken()->getTokenSecret(), + $config->getRequestMethod(), + $url + ); + + return $params; + } + + /** + * Given both OAuth parameters and any custom parametere, generate an + * encoded query string. This method expects parameters to have been + * assembled and signed beforehand. + * + * @param array $params + * @param bool $customParamsOnly Ignores OAuth params e.g. for requests using OAuth Header + * @return string + */ + public function toEncodedQueryString(array $params, $customParamsOnly = false) + { + if ($customParamsOnly) { + foreach ($params as $key=>$value) { + if (preg_match("/^oauth_/", $key)) { + unset($params[$key]); + } + } + } + $encodedParams = array(); + foreach ($params as $key => $value) { + $encodedParams[] = self::urlEncode($key) + . '=' + . self::urlEncode($value); + } + return implode('&', $encodedParams); + } + + /** + * Cast to authorization header + * + * @param array $params + * @param null|string $realm + * @param bool $excludeCustomParams + * @return void + */ + public function toAuthorizationHeader(array $params, $realm = null, $excludeCustomParams = true) + { + $headerValue = array( + 'OAuth realm="' . $realm . '"', + ); + + foreach ($params as $key => $value) { + if ($excludeCustomParams) { + if (!preg_match("/^oauth_/", $key)) { + continue; + } + } + $headerValue[] = self::urlEncode($key) + . '="' + . self::urlEncode($value) . '"'; + } + return implode(",", $headerValue); + } + + /** + * Sign request + * + * @param array $params + * @param string $signatureMethod + * @param string $consumerSecret + * @param null|string $tokenSecret + * @param null|string $method + * @param null|string $url + * @return string + */ + public function sign( + array $params, $signatureMethod, $consumerSecret, $tokenSecret = null, $method = null, $url = null + ) { + $className = ''; + $hashAlgo = null; + $parts = explode('-', $signatureMethod); + if (count($parts) > 1) { + $className = 'Zend_Oauth_Signature_' . ucfirst(strtolower($parts[0])); + $hashAlgo = $parts[1]; + } else { + $className = 'Zend_Oauth_Signature_' . ucfirst(strtolower($signatureMethod)); + } + + require_once str_replace('_', '/', $className) . '.php'; + $signatureObject = new $className($consumerSecret, $tokenSecret, $hashAlgo); + return $signatureObject->sign($params, $method, $url); + } + + /** + * Parse query string + * + * @param mixed $query + * @return array + */ + public function parseQueryString($query) + { + $params = array(); + if (empty($query)) { + return array(); + } + + // Not remotely perfect but beats parse_str() which converts + // periods and uses urldecode, not rawurldecode. + $parts = explode('&', $query); + foreach ($parts as $pair) { + $kv = explode('=', $pair); + $params[rawurldecode($kv[0])] = rawurldecode($kv[1]); + } + return $params; + } + + /** + * Generate nonce + * + * @return string + */ + public function generateNonce() + { + return md5(uniqid(rand(), true)); + } + + /** + * Generate timestamp + * + * @return int + */ + public function generateTimestamp() + { + return time(); + } + + /** + * urlencode a value + * + * @param string $value + * @return string + */ + public static function urlEncode($value) + { + $encoded = rawurlencode($value); + $encoded = str_replace('%7E', '~', $encoded); + return $encoded; + } +} diff --git a/Zend/Oauth/Signature/Hmac.php b/Zend/Oauth/Signature/Hmac.php new file mode 100644 index 00000000..e24be170 --- /dev/null +++ b/Zend/Oauth/Signature/Hmac.php @@ -0,0 +1,54 @@ +_key, + $this->_hashAlgorithm, + $this->_getBaseSignatureString($params, $method, $url), + Zend_Crypt_Hmac::BINARY + ); + return base64_encode($binaryHash); + } +} diff --git a/Zend/Oauth/Signature/Plaintext.php b/Zend/Oauth/Signature/Plaintext.php new file mode 100644 index 00000000..5486d5b4 --- /dev/null +++ b/Zend/Oauth/Signature/Plaintext.php @@ -0,0 +1,49 @@ +_tokenSecret === null) { + return $this->_consumerSecret . '&'; + } + $return = implode('&', array($this->_consumerSecret, $this->_tokenSecret)); + return $return; + } +} diff --git a/Zend/Oauth/Signature/Rsa.php b/Zend/Oauth/Signature/Rsa.php new file mode 100644 index 00000000..1226a727 --- /dev/null +++ b/Zend/Oauth/Signature/Rsa.php @@ -0,0 +1,65 @@ +setHashAlgorithm($this->_hashAlgorithm); + $sign = $rsa->sign( + $this->_getBaseSignatureString($params, $method, $url), + $this->_key, + Zend_Crypt_Rsa::BASE64 + ); + return $sign; + } + + /** + * Assemble encryption key + * + * @return string + */ + protected function _assembleKey() + { + return $this->_consumerSecret; + } +} diff --git a/Zend/Oauth/Signature/SignatureAbstract.php b/Zend/Oauth/Signature/SignatureAbstract.php new file mode 100644 index 00000000..8bf84368 --- /dev/null +++ b/Zend/Oauth/Signature/SignatureAbstract.php @@ -0,0 +1,183 @@ +_consumerSecret = $consumerSecret; + if (isset($tokenSecret)) { + $this->_tokenSecret = $tokenSecret; + } + $this->_key = $this->_assembleKey(); + if (isset($hashAlgo)) { + $this->_hashAlgorithm = $hashAlgo; + } + } + + /** + * Sign a request + * + * @param array $params + * @param null|string $method + * @param null|string $url + * @return string + */ + public abstract function sign(array $params, $method = null, $url = null); + + /** + * Normalize the base signature URL + * + * @param string $url + * @return string + */ + public function normaliseBaseSignatureUrl($url) + { + $uri = Zend_Uri_Http::fromString($url); + if ($uri->getScheme() == 'http' && $uri->getPort() == '80') { + $uri->setPort(''); + } elseif ($uri->getScheme() == 'https' && $uri->getPort() == '443') { + $uri->setPort(''); + } + $uri->setQuery(''); + $uri->setFragment(''); + $uri->setHost(strtolower($uri->getHost())); + return $uri->getUri(true); + } + + /** + * Assemble key from consumer and token secrets + * + * @return string + */ + protected function _assembleKey() + { + $parts = array($this->_consumerSecret); + if ($this->_tokenSecret !== null) { + $parts[] = $this->_tokenSecret; + } + foreach ($parts as $key => $secret) { + $parts[$key] = Zend_Oauth_Http_Utility::urlEncode($secret); + } + return implode('&', $parts); + } + + /** + * Get base signature string + * + * @param array $params + * @param null|string $method + * @param null|string $url + * @return string + */ + protected function _getBaseSignatureString(array $params, $method = null, $url = null) + { + $encodedParams = array(); + foreach ($params as $key => $value) { + $encodedParams[Zend_Oauth_Http_Utility::urlEncode($key)] = + Zend_Oauth_Http_Utility::urlEncode($value); + } + $baseStrings = array(); + if (isset($method)) { + $baseStrings[] = strtoupper($method); + } + if (isset($url)) { + // should normalise later + $baseStrings[] = Zend_Oauth_Http_Utility::urlEncode( + $this->normaliseBaseSignatureUrl($url) + ); + } + if (isset($encodedParams['oauth_signature'])) { + unset($encodedParams['oauth_signature']); + } + $baseStrings[] = Zend_Oauth_Http_Utility::urlEncode( + $this->_toByteValueOrderedQueryString($encodedParams) + ); + return implode('&', $baseStrings); + } + + /** + * Transform an array to a byte value ordered query string + * + * @param array $params + * @return string + */ + protected function _toByteValueOrderedQueryString(array $params) + { + $return = array(); + uksort($params, 'strnatcmp'); + foreach ($params as $key => $value) { + if (is_array($value)) { + natsort($value); + foreach ($value as $keyduplicate) { + $return[] = $key . '=' . $keyduplicate; + } + } else { + $return[] = $key . '=' . $value; + } + } + return implode('&', $return); + } +} diff --git a/Zend/Oauth/Token.php b/Zend/Oauth/Token.php new file mode 100644 index 00000000..c706699d --- /dev/null +++ b/Zend/Oauth/Token.php @@ -0,0 +1,285 @@ +_response = $response; + $params = $this->_parseParameters($response); + if (count($params) > 0) { + $this->setParams($params); + } + } + if ($utility !== null) { + $this->_httpUtility = $utility; + } else { + $this->_httpUtility = new Zend_Oauth_Http_Utility; + } + } + + /** + * Attempts to validate the Token parsed from the HTTP response - really + * it's just very basic existence checks which are minimal. + * + * @return bool + */ + public function isValid() + { + if (isset($this->_params[self::TOKEN_PARAM_KEY]) + && !empty($this->_params[self::TOKEN_PARAM_KEY]) + && isset($this->_params[self::TOKEN_SECRET_PARAM_KEY]) + ) { + return true; + } + return false; + } + + /** + * Return the HTTP response object used to initialise this instance. + * + * @return Zend_Http_Response + */ + public function getResponse() + { + return $this->_response; + } + + /** + * Sets the value for the this Token's secret which may be used when signing + * requests with this Token. + * + * @param string $secret + * @return Zend_Oauth_Token + */ + public function setTokenSecret($secret) + { + $this->setParam(self::TOKEN_SECRET_PARAM_KEY, $secret); + return $this; + } + + /** + * Retrieve this Token's secret which may be used when signing + * requests with this Token. + * + * @return string + */ + public function getTokenSecret() + { + return $this->getParam(self::TOKEN_SECRET_PARAM_KEY); + } + + /** + * Sets the value for a parameter (e.g. token secret or other) and run + * a simple filter to remove any trailing newlines. + * + * @param string $key + * @param string $value + * @return Zend_Oauth_Token + */ + public function setParam($key, $value) + { + $this->_params[$key] = trim($value, "\n"); + return $this; + } + + /** + * Sets the value for some parameters (e.g. token secret or other) and run + * a simple filter to remove any trailing newlines. + * + * @param array $params + * @return Zend_Oauth_Token + */ + public function setParams(array $params) + { + foreach ($params as $key=>$value) { + $this->setParam($key, $value); + } + return $this; + } + + /** + * Get the value for a parameter (e.g. token secret or other). + * + * @param string $key + * @return mixed + */ + public function getParam($key) + { + if (isset($this->_params[$key])) { + return $this->_params[$key]; + } + return null; + } + + /** + * Sets the value for a Token. + * + * @param string $token + * @return Zend_Oauth_Token + */ + public function setToken($token) + { + $this->setParam(self::TOKEN_PARAM_KEY, $token); + return $this; + } + + /** + * Gets the value for a Token. + * + * @return string + */ + public function getToken() + { + return $this->getParam(self::TOKEN_PARAM_KEY); + } + + /** + * Generic accessor to enable access as public properties. + * + * @return string + */ + public function __get($key) + { + return $this->getParam($key); + } + + /** + * Generic mutator to enable access as public properties. + * + * @param string $key + * @param string $value + * @return void + */ + public function __set($key, $value) + { + $this->setParam($key, $value); + } + + /** + * Convert Token to a string, specifically a raw encoded query string. + * + * @return string + */ + public function toString() + { + return $this->_httpUtility->toEncodedQueryString($this->_params); + } + + /** + * Convert Token to a string, specifically a raw encoded query string. + * Aliases to self::toString() + * + * @return string + */ + public function __toString() + { + return $this->toString(); + } + + /** + * Parse a HTTP response body and collect returned parameters + * as raw url decoded key-value pairs in an associative array. + * + * @param Zend_Http_Response $response + * @return array + */ + protected function _parseParameters(Zend_Http_Response $response) + { + $params = array(); + $body = $response->getBody(); + if (empty($body)) { + return; + } + + // validate body based on acceptable characters...todo + $parts = explode('&', $body); + foreach ($parts as $kvpair) { + $pair = explode('=', $kvpair); + $params[rawurldecode($pair[0])] = rawurldecode($pair[1]); + } + return $params; + } + + /** + * Limit serialisation stored data to the parameters + */ + public function __sleep() + { + return array('_params'); + } + + /** + * After serialisation, re-instantiate a HTTP utility class for use + */ + public function __wakeup() + { + if ($this->_httpUtility === null) { + $this->_httpUtility = new Zend_Oauth_Http_Utility; + } + } +} diff --git a/Zend/Oauth/Token/Access.php b/Zend/Oauth/Token/Access.php new file mode 100644 index 00000000..071cee55 --- /dev/null +++ b/Zend/Oauth/Token/Access.php @@ -0,0 +1,99 @@ +_httpUtility->assembleParams($url, $config, $customParams); + return $this->_httpUtility->toAuthorizationHeader($params, $realm); + } + + /** + * Cast to HTTP query string + * + * @param mixed $url + * @param Zend_Oauth_Config_ConfigInterface $config + * @param null|array $params + * @return string + */ + public function toQueryString($url, Zend_Oauth_Config_ConfigInterface $config, array $params = null) + { + if (!Zend_Uri::check($url)) { + require_once 'Zend/Oauth/Exception.php'; + throw new Zend_Oauth_Exception( + '\'' . $url . '\' is not a valid URI' + ); + } + $params = $this->_httpUtility->assembleParams($url, $config, $params); + return $this->_httpUtility->toEncodedQueryString($params); + } + + /** + * Get OAuth client + * + * @param array $oauthOptions + * @param null|string $uri + * @param null|array|Zend_Config $config + * @param bool $excludeCustomParamsFromHeader + * @return Zend_Oauth_Client + */ + public function getHttpClient(array $oauthOptions, $uri = null, $config = null, $excludeCustomParamsFromHeader = true) + { + $client = new Zend_Oauth_Client($oauthOptions, $uri, $config, $excludeCustomParamsFromHeader); + $client->setToken($this); + return $client; + } +} diff --git a/Zend/Oauth/Token/AuthorizedRequest.php b/Zend/Oauth/Token/AuthorizedRequest.php new file mode 100644 index 00000000..b1d946be --- /dev/null +++ b/Zend/Oauth/Token/AuthorizedRequest.php @@ -0,0 +1,102 @@ +_data = $data; + $params = $this->_parseData(); + if (count($params) > 0) { + $this->setParams($params); + } + } + if ($utility !== null) { + $this->_httpUtility = $utility; + } else { + $this->_httpUtility = new Zend_Oauth_Http_Utility; + } + } + + /** + * Retrieve token data + * + * @return array + */ + public function getData() + { + return $this->_data; + } + + /** + * Indicate if token is valid + * + * @return bool + */ + public function isValid() + { + if (isset($this->_params[self::TOKEN_PARAM_KEY]) + && !empty($this->_params[self::TOKEN_PARAM_KEY]) + ) { + return true; + } + return false; + } + + /** + * Parse string data into array + * + * @return array + */ + protected function _parseData() + { + $params = array(); + if (empty($this->_data)) { + return; + } + foreach ($this->_data as $key => $value) { + $params[rawurldecode($key)] = rawurldecode($value); + } + return $params; + } +} diff --git a/Zend/Oauth/Token/Request.php b/Zend/Oauth/Token/Request.php new file mode 100644 index 00000000..59f1695b --- /dev/null +++ b/Zend/Oauth/Token/Request.php @@ -0,0 +1,50 @@ +_params[Zend_Oauth_Token::TOKEN_PARAM_CALLBACK_CONFIRMED])) { + Zend_Oauth_Client::$supportsRevisionA = true; + } + } +} diff --git a/Zend/Registry.php b/Zend/Registry.php new file mode 100644 index 00000000..1d003ef9 --- /dev/null +++ b/Zend/Registry.php @@ -0,0 +1,209 @@ +offsetExists($index)) { + require_once 'Zend/Exception.php'; + throw new Zend_Exception("No entry is registered for key '$index'"); + } + + return $instance->offsetGet($index); + } + + /** + * setter method, basically same as offsetSet(). + * + * This method can be called from an object of type Zend_Registry, or it + * can be called statically. In the latter case, it uses the default + * static instance stored in the class. + * + * @param string $index The location in the ArrayObject in which to store + * the value. + * @param mixed $value The object to store in the ArrayObject. + * @return void + */ + public static function set($index, $value) + { + $instance = self::getInstance(); + $instance->offsetSet($index, $value); + } + + /** + * Returns TRUE if the $index is a named value in the registry, + * or FALSE if $index was not found in the registry. + * + * @param string $index + * @return boolean + */ + public static function isRegistered($index) + { + if (self::$_registry === null) { + return false; + } + return self::$_registry->offsetExists($index); + } + + /** + * Constructs a parent ArrayObject with default + * ARRAY_AS_PROPS to allow acces as an object + * + * @param array $array data array + * @param integer $flags ArrayObject flags + */ + public function __construct($array = array(), $flags = parent::ARRAY_AS_PROPS) + { + parent::__construct($array, $flags); + } + + /** + * @param string $index + * @returns mixed + * + * Workaround for http://bugs.php.net/bug.php?id=40442 (ZF-960). + */ + public function offsetExists($index) + { + return array_key_exists($index, $this); + } + +} diff --git a/Zend/Uri.php b/Zend/Uri.php new file mode 100644 index 00000000..b4f88b32 --- /dev/null +++ b/Zend/Uri.php @@ -0,0 +1,202 @@ + false + ); + + /** + * Return a string representation of this URI. + * + * @see getUri() + * @return string + */ + public function __toString() + { + return $this->getUri(); + } + + /** + * Convenience function, checks that a $uri string is well-formed + * by validating it but not returning an object. Returns TRUE if + * $uri is a well-formed URI, or FALSE otherwise. + * + * @param string $uri The URI to check + * @return boolean + */ + public static function check($uri) + { + try { + $uri = self::factory($uri); + } catch (Exception $e) { + return false; + } + + return $uri->valid(); + } + + /** + * Create a new Zend_Uri object for a URI. If building a new URI, then $uri should contain + * only the scheme (http, ftp, etc). Otherwise, supply $uri with the complete URI. + * + * @param string $uri The URI form which a Zend_Uri instance is created + * @param string $className The name of the class to use in order to manipulate URI + * @throws Zend_Uri_Exception When an empty string was supplied for the scheme + * @throws Zend_Uri_Exception When an illegal scheme is supplied + * @throws Zend_Uri_Exception When the scheme is not supported + * @throws Zend_Uri_Exception When $className doesn't exist or doesn't implements Zend_Uri + * @return Zend_Uri + * @link http://www.faqs.org/rfcs/rfc2396.html + */ + public static function factory($uri = 'http', $className = null) + { + // Separate the scheme from the scheme-specific parts + $uri = explode(':', $uri, 2); + $scheme = strtolower($uri[0]); + $schemeSpecific = isset($uri[1]) === true ? $uri[1] : ''; + + if (strlen($scheme) === 0) { + require_once 'Zend/Uri/Exception.php'; + throw new Zend_Uri_Exception('An empty string was supplied for the scheme'); + } + + // Security check: $scheme is used to load a class file, so only alphanumerics are allowed. + if (ctype_alnum($scheme) === false) { + require_once 'Zend/Uri/Exception.php'; + throw new Zend_Uri_Exception('Illegal scheme supplied, only alphanumeric characters are permitted'); + } + + if ($className === null) { + /** + * Create a new Zend_Uri object for the $uri. If a subclass of Zend_Uri exists for the + * scheme, return an instance of that class. Otherwise, a Zend_Uri_Exception is thrown. + */ + switch ($scheme) { + case 'http': + // Break intentionally omitted + case 'https': + $className = 'Zend_Uri_Http'; + break; + + case 'mailto': + // TODO + default: + require_once 'Zend/Uri/Exception.php'; + throw new Zend_Uri_Exception("Scheme \"$scheme\" is not supported"); + break; + } + } + + require_once 'Zend/Loader.php'; + try { + Zend_Loader::loadClass($className); + } catch (Exception $e) { + require_once 'Zend/Uri/Exception.php'; + throw new Zend_Uri_Exception("\"$className\" not found"); + } + + $schemeHandler = new $className($scheme, $schemeSpecific); + + if (! $schemeHandler instanceof Zend_Uri) { + require_once 'Zend/Uri/Exception.php'; + throw new Zend_Uri_Exception("\"$className\" is not an instance of Zend_Uri"); + } + + return $schemeHandler; + } + + /** + * Get the URI's scheme + * + * @return string|false Scheme or false if no scheme is set. + */ + public function getScheme() + { + if (empty($this->_scheme) === false) { + return $this->_scheme; + } else { + return false; + } + } + + /** + * Set global configuration options + * + * @param Zend_Config|array $config + */ + static public function setConfig($config) + { + if ($config instanceof Zend_Config) { + $config = $config->toArray(); + } elseif (!is_array($config)) { + throw new Zend_Uri_Exception("Config must be an array or an instance of Zend_Config."); + } + + foreach ($config as $k => $v) { + self::$_config[$k] = $v; + } + } + + /** + * Zend_Uri and its subclasses cannot be instantiated directly. + * Use Zend_Uri::factory() to return a new Zend_Uri object. + * + * @param string $scheme The scheme of the URI + * @param string $schemeSpecific The scheme-specific part of the URI + */ + abstract protected function __construct($scheme, $schemeSpecific = ''); + + /** + * Return a string representation of this URI. + * + * @return string + */ + abstract public function getUri(); + + /** + * Returns TRUE if this URI is valid, or FALSE otherwise. + * + * @return boolean + */ + abstract public function valid(); +} diff --git a/Zend/Uri/Exception.php b/Zend/Uri/Exception.php new file mode 100644 index 00000000..53cd3335 --- /dev/null +++ b/Zend/Uri/Exception.php @@ -0,0 +1,37 @@ +_scheme = $scheme; + + // Set up grammar rules for validation via regular expressions. These + // are to be used with slash-delimited regular expression strings. + + // Escaped special characters (eg. '%25' for '%') + $this->_regex['escaped'] = '%[[:xdigit:]]{2}'; + + // Unreserved characters + $this->_regex['unreserved'] = '[' . self::CHAR_ALNUM . self::CHAR_MARK . ']'; + + // Segment can use escaped, unreserved or a set of additional chars + $this->_regex['segment'] = '(?:' . $this->_regex['escaped'] . '|[' . + self::CHAR_ALNUM . self::CHAR_MARK . self::CHAR_SEGMENT . '])*'; + + // Path can be a series of segmets char strings seperated by '/' + $this->_regex['path'] = '(?:\/(?:' . $this->_regex['segment'] . ')?)+'; + + // URI characters can be escaped, alphanumeric, mark or reserved chars + $this->_regex['uric'] = '(?:' . $this->_regex['escaped'] . '|[' . + self::CHAR_ALNUM . self::CHAR_MARK . self::CHAR_RESERVED . + + // If unwise chars are allowed, add them to the URI chars class + (self::$_config['allow_unwise'] ? self::CHAR_UNWISE : '') . '])'; + + // If no scheme-specific part was supplied, the user intends to create + // a new URI with this object. No further parsing is required. + if (strlen($schemeSpecific) === 0) { + return; + } + + // Parse the scheme-specific URI parts into the instance variables. + $this->_parseUri($schemeSpecific); + + // Validate the URI + if ($this->valid() === false) { + require_once 'Zend/Uri/Exception.php'; + throw new Zend_Uri_Exception('Invalid URI supplied'); + } + } + + /** + * Creates a Zend_Uri_Http from the given string + * + * @param string $uri String to create URI from, must start with + * 'http://' or 'https://' + * @throws InvalidArgumentException When the given $uri is not a string or + * does not start with http:// or https:// + * @throws Zend_Uri_Exception When the given $uri is invalid + * @return Zend_Uri_Http + */ + public static function fromString($uri) + { + if (is_string($uri) === false) { + require_once 'Zend/Uri/Exception.php'; + throw new Zend_Uri_Exception('$uri is not a string'); + } + + $uri = explode(':', $uri, 2); + $scheme = strtolower($uri[0]); + $schemeSpecific = isset($uri[1]) === true ? $uri[1] : ''; + + if (in_array($scheme, array('http', 'https')) === false) { + require_once 'Zend/Uri/Exception.php'; + throw new Zend_Uri_Exception("Invalid scheme: '$scheme'"); + } + + $schemeHandler = new Zend_Uri_Http($scheme, $schemeSpecific); + return $schemeHandler; + } + + /** + * Parse the scheme-specific portion of the URI and place its parts into instance variables. + * + * @param string $schemeSpecific The scheme-specific portion to parse + * @throws Zend_Uri_Exception When scheme-specific decoposition fails + * @throws Zend_Uri_Exception When authority decomposition fails + * @return void + */ + protected function _parseUri($schemeSpecific) + { + // High-level decomposition parser + $pattern = '~^((//)([^/?#]*))([^?#]*)(\?([^#]*))?(#(.*))?$~'; + $status = @preg_match($pattern, $schemeSpecific, $matches); + if ($status === false) { + require_once 'Zend/Uri/Exception.php'; + throw new Zend_Uri_Exception('Internal error: scheme-specific decomposition failed'); + } + + // Failed decomposition; no further processing needed + if ($status === false) { + return; + } + + // Save URI components that need no further decomposition + $this->_path = isset($matches[4]) === true ? $matches[4] : ''; + $this->_query = isset($matches[6]) === true ? $matches[6] : ''; + $this->_fragment = isset($matches[8]) === true ? $matches[8] : ''; + + // Additional decomposition to get username, password, host, and port + $combo = isset($matches[3]) === true ? $matches[3] : ''; + $pattern = '~^(([^:@]*)(:([^@]*))?@)?([^:]+)(:(.*))?$~'; + $status = @preg_match($pattern, $combo, $matches); + if ($status === false) { + require_once 'Zend/Uri/Exception.php'; + throw new Zend_Uri_Exception('Internal error: authority decomposition failed'); + } + + // Failed decomposition; no further processing needed + if ($status === false) { + return; + } + + // Save remaining URI components + $this->_username = isset($matches[2]) === true ? $matches[2] : ''; + $this->_password = isset($matches[4]) === true ? $matches[4] : ''; + $this->_host = isset($matches[5]) === true ? $matches[5] : ''; + $this->_port = isset($matches[7]) === true ? $matches[7] : ''; + + } + + /** + * Returns a URI based on current values of the instance variables. If any + * part of the URI does not pass validation, then an exception is thrown. + * + * @throws Zend_Uri_Exception When one or more parts of the URI are invalid + * @return string + */ + public function getUri() + { + if ($this->valid() === false) { + require_once 'Zend/Uri/Exception.php'; + throw new Zend_Uri_Exception('One or more parts of the URI are invalid'); + } + + $password = strlen($this->_password) > 0 ? ":$this->_password" : ''; + $auth = strlen($this->_username) > 0 ? "$this->_username$password@" : ''; + $port = strlen($this->_port) > 0 ? ":$this->_port" : ''; + $query = strlen($this->_query) > 0 ? "?$this->_query" : ''; + $fragment = strlen($this->_fragment) > 0 ? "#$this->_fragment" : ''; + + return $this->_scheme + . '://' + . $auth + . $this->_host + . $port + . $this->_path + . $query + . $fragment; + } + + /** + * Validate the current URI from the instance variables. Returns true if and only if all + * parts pass validation. + * + * @return boolean + */ + public function valid() + { + // Return true if and only if all parts of the URI have passed validation + return $this->validateUsername() + and $this->validatePassword() + and $this->validateHost() + and $this->validatePort() + and $this->validatePath() + and $this->validateQuery() + and $this->validateFragment(); + } + + /** + * Returns the username portion of the URL, or FALSE if none. + * + * @return string + */ + public function getUsername() + { + return strlen($this->_username) > 0 ? $this->_username : false; + } + + /** + * Returns true if and only if the username passes validation. If no username is passed, + * then the username contained in the instance variable is used. + * + * @param string $username The HTTP username + * @throws Zend_Uri_Exception When username validation fails + * @return boolean + * @link http://www.faqs.org/rfcs/rfc2396.html + */ + public function validateUsername($username = null) + { + if ($username === null) { + $username = $this->_username; + } + + // If the username is empty, then it is considered valid + if (strlen($username) === 0) { + return true; + } + + // Check the username against the allowed values + $status = @preg_match('/^(?:' . $this->_regex['escaped'] . '|[' . + self::CHAR_ALNUM . self::CHAR_MARK . ';:&=+$,' . '])+$/', $username); + + if ($status === false) { + require_once 'Zend/Uri/Exception.php'; + throw new Zend_Uri_Exception('Internal error: username validation failed'); + } + + return $status === 1; + } + + /** + * Sets the username for the current URI, and returns the old username + * + * @param string $username The HTTP username + * @throws Zend_Uri_Exception When $username is not a valid HTTP username + * @return string + */ + public function setUsername($username) + { + if ($this->validateUsername($username) === false) { + require_once 'Zend/Uri/Exception.php'; + throw new Zend_Uri_Exception("Username \"$username\" is not a valid HTTP username"); + } + + $oldUsername = $this->_username; + $this->_username = $username; + + return $oldUsername; + } + + /** + * Returns the password portion of the URL, or FALSE if none. + * + * @return string + */ + public function getPassword() + { + return strlen($this->_password) > 0 ? $this->_password : false; + } + + /** + * Returns true if and only if the password passes validation. If no password is passed, + * then the password contained in the instance variable is used. + * + * @param string $password The HTTP password + * @throws Zend_Uri_Exception When password validation fails + * @return boolean + * @link http://www.faqs.org/rfcs/rfc2396.html + */ + public function validatePassword($password = null) + { + if ($password === null) { + $password = $this->_password; + } + + // If the password is empty, then it is considered valid + if (strlen($password) === 0) { + return true; + } + + // If the password is nonempty, but there is no username, then it is considered invalid + if (strlen($password) > 0 and strlen($this->_username) === 0) { + return false; + } + + // Check the password against the allowed values + $status = @preg_match('/^(?:' . $this->_regex['escaped'] . '|[' . + self::CHAR_ALNUM . self::CHAR_MARK . ';:&=+$,' . '])+$/', $password); + + if ($status === false) { + require_once 'Zend/Uri/Exception.php'; + throw new Zend_Uri_Exception('Internal error: password validation failed.'); + } + + return $status == 1; + } + + /** + * Sets the password for the current URI, and returns the old password + * + * @param string $password The HTTP password + * @throws Zend_Uri_Exception When $password is not a valid HTTP password + * @return string + */ + public function setPassword($password) + { + if ($this->validatePassword($password) === false) { + require_once 'Zend/Uri/Exception.php'; + throw new Zend_Uri_Exception("Password \"$password\" is not a valid HTTP password."); + } + + $oldPassword = $this->_password; + $this->_password = $password; + + return $oldPassword; + } + + /** + * Returns the domain or host IP portion of the URL, or FALSE if none. + * + * @return string + */ + public function getHost() + { + return strlen($this->_host) > 0 ? $this->_host : false; + } + + /** + * Returns true if and only if the host string passes validation. If no host is passed, + * then the host contained in the instance variable is used. + * + * @param string $host The HTTP host + * @return boolean + * @uses Zend_Filter + */ + public function validateHost($host = null) + { + if ($host === null) { + $host = $this->_host; + } + + // If the host is empty, then it is considered invalid + if (strlen($host) === 0) { + return false; + } + + // Check the host against the allowed values; delegated to Zend_Filter. + $validate = new Zend_Validate_Hostname(Zend_Validate_Hostname::ALLOW_ALL); + + return $validate->isValid($host); + } + + /** + * Sets the host for the current URI, and returns the old host + * + * @param string $host The HTTP host + * @throws Zend_Uri_Exception When $host is nota valid HTTP host + * @return string + */ + public function setHost($host) + { + if ($this->validateHost($host) === false) { + require_once 'Zend/Uri/Exception.php'; + throw new Zend_Uri_Exception("Host \"$host\" is not a valid HTTP host"); + } + + $oldHost = $this->_host; + $this->_host = $host; + + return $oldHost; + } + + /** + * Returns the TCP port, or FALSE if none. + * + * @return string + */ + public function getPort() + { + return strlen($this->_port) > 0 ? $this->_port : false; + } + + /** + * Returns true if and only if the TCP port string passes validation. If no port is passed, + * then the port contained in the instance variable is used. + * + * @param string $port The HTTP port + * @return boolean + */ + public function validatePort($port = null) + { + if ($port === null) { + $port = $this->_port; + } + + // If the port is empty, then it is considered valid + if (strlen($port) === 0) { + return true; + } + + // Check the port against the allowed values + return ctype_digit((string) $port) and 1 <= $port and $port <= 65535; + } + + /** + * Sets the port for the current URI, and returns the old port + * + * @param string $port The HTTP port + * @throws Zend_Uri_Exception When $port is not a valid HTTP port + * @return string + */ + public function setPort($port) + { + if ($this->validatePort($port) === false) { + require_once 'Zend/Uri/Exception.php'; + throw new Zend_Uri_Exception("Port \"$port\" is not a valid HTTP port."); + } + + $oldPort = $this->_port; + $this->_port = $port; + + return $oldPort; + } + + /** + * Returns the path and filename portion of the URL, or FALSE if none. + * + * @return string + */ + public function getPath() + { + return strlen($this->_path) > 0 ? $this->_path : '/'; + } + + /** + * Returns true if and only if the path string passes validation. If no path is passed, + * then the path contained in the instance variable is used. + * + * @param string $path The HTTP path + * @throws Zend_Uri_Exception When path validation fails + * @return boolean + */ + public function validatePath($path = null) + { + if ($path === null) { + $path = $this->_path; + } + + // If the path is empty, then it is considered valid + if (strlen($path) === 0) { + return true; + } + + // Determine whether the path is well-formed + $pattern = '/^' . $this->_regex['path'] . '$/'; + $status = @preg_match($pattern, $path); + if ($status === false) { + require_once 'Zend/Uri/Exception.php'; + throw new Zend_Uri_Exception('Internal error: path validation failed'); + } + + return (boolean) $status; + } + + /** + * Sets the path for the current URI, and returns the old path + * + * @param string $path The HTTP path + * @throws Zend_Uri_Exception When $path is not a valid HTTP path + * @return string + */ + public function setPath($path) + { + if ($this->validatePath($path) === false) { + require_once 'Zend/Uri/Exception.php'; + throw new Zend_Uri_Exception("Path \"$path\" is not a valid HTTP path"); + } + + $oldPath = $this->_path; + $this->_path = $path; + + return $oldPath; + } + + /** + * Returns the query portion of the URL (after ?), or FALSE if none. + * + * @return string + */ + public function getQuery() + { + return strlen($this->_query) > 0 ? $this->_query : false; + } + + /** + * Returns the query portion of the URL (after ?) as a + * key-value-array. If the query is empty an empty array + * is returned + * + * @return array + */ + public function getQueryAsArray() + { + $query = $this->getQuery(); + $querryArray = array(); + if ($query !== false) { + parse_str($query, $querryArray); + } + return $querryArray; + } + + /** + * Returns true if and only if the query string passes validation. If no query is passed, + * then the query string contained in the instance variable is used. + * + * @param string $query The query to validate + * @throws Zend_Uri_Exception When query validation fails + * @return boolean + * @link http://www.faqs.org/rfcs/rfc2396.html + */ + public function validateQuery($query = null) + { + if ($query === null) { + $query = $this->_query; + } + + // If query is empty, it is considered to be valid + if (strlen($query) === 0) { + return true; + } + + // Determine whether the query is well-formed + $pattern = '/^' . $this->_regex['uric'] . '*$/'; + $status = @preg_match($pattern, $query); + if ($status === false) { + require_once 'Zend/Uri/Exception.php'; + throw new Zend_Uri_Exception('Internal error: query validation failed'); + } + + return $status == 1; + } + + /** + * Add or replace params in the query string for the current URI, and + * return the old query. + * + * @param array $queryParams + * @return string Old query string + */ + public function addReplaceQueryParameters(array $queryParams) + { + $queryParams = array_merge($this->getQueryAsArray(), $queryParams); + return $this->setQuery($queryParams); + } + + /** + * Remove params in the query string for the current URI, and + * return the old query. + * + * @param array $queryParamKeys + * @return string Old query string + */ + public function removeQueryParameters(array $queryParamKeys) + { + $queryParams = array_diff_key($this->getQueryAsArray(), array_fill_keys($queryParamKeys, 0)); + return $this->setQuery($queryParams); + } + + /** + * Set the query string for the current URI, and return the old query + * string This method accepts both strings and arrays. + * + * @param string|array $query The query string or array + * @throws Zend_Uri_Exception When $query is not a valid query string + * @return string Old query string + */ + public function setQuery($query) + { + $oldQuery = $this->_query; + + // If query is empty, set an empty string + if (empty($query) === true) { + $this->_query = ''; + return $oldQuery; + } + + // If query is an array, make a string out of it + if (is_array($query) === true) { + $query = http_build_query($query, '', '&'); + } else { + // If it is a string, make sure it is valid. If not parse and encode it + $query = (string) $query; + if ($this->validateQuery($query) === false) { + parse_str($query, $queryArray); + $query = http_build_query($queryArray, '', '&'); + } + } + + // Make sure the query is valid, and set it + if ($this->validateQuery($query) === false) { + require_once 'Zend/Uri/Exception.php'; + throw new Zend_Uri_Exception("'$query' is not a valid query string"); + } + + $this->_query = $query; + + return $oldQuery; + } + + /** + * Returns the fragment portion of the URL (after #), or FALSE if none. + * + * @return string|false + */ + public function getFragment() + { + return strlen($this->_fragment) > 0 ? $this->_fragment : false; + } + + /** + * Returns true if and only if the fragment passes validation. If no fragment is passed, + * then the fragment contained in the instance variable is used. + * + * @param string $fragment Fragment of an URI + * @throws Zend_Uri_Exception When fragment validation fails + * @return boolean + * @link http://www.faqs.org/rfcs/rfc2396.html + */ + public function validateFragment($fragment = null) + { + if ($fragment === null) { + $fragment = $this->_fragment; + } + + // If fragment is empty, it is considered to be valid + if (strlen($fragment) === 0) { + return true; + } + + // Determine whether the fragment is well-formed + $pattern = '/^' . $this->_regex['uric'] . '*$/'; + $status = @preg_match($pattern, $fragment); + if ($status === false) { + require_once 'Zend/Uri/Exception.php'; + throw new Zend_Uri_Exception('Internal error: fragment validation failed'); + } + + return (boolean) $status; + } + + /** + * Sets the fragment for the current URI, and returns the old fragment + * + * @param string $fragment Fragment of the current URI + * @throws Zend_Uri_Exception When $fragment is not a valid HTTP fragment + * @return string + */ + public function setFragment($fragment) + { + if ($this->validateFragment($fragment) === false) { + require_once 'Zend/Uri/Exception.php'; + throw new Zend_Uri_Exception("Fragment \"$fragment\" is not a valid HTTP fragment"); + } + + $oldFragment = $this->_fragment; + $this->_fragment = $fragment; + + return $oldFragment; + } +} diff --git a/Zend/Validate/Abstract.php b/Zend/Validate/Abstract.php new file mode 100644 index 00000000..c4e3ffd1 --- /dev/null +++ b/Zend/Validate/Abstract.php @@ -0,0 +1,456 @@ +_messages; + } + + /** + * Returns an array of the names of variables that are used in constructing validation failure messages + * + * @return array + */ + public function getMessageVariables() + { + return array_keys($this->_messageVariables); + } + + /** + * Returns the message templates from the validator + * + * @return array + */ + public function getMessageTemplates() + { + return $this->_messageTemplates; + } + + /** + * Sets the validation failure message template for a particular key + * + * @param string $messageString + * @param string $messageKey OPTIONAL + * @return Zend_Validate_Abstract Provides a fluent interface + * @throws Zend_Validate_Exception + */ + public function setMessage($messageString, $messageKey = null) + { + if ($messageKey === null) { + $keys = array_keys($this->_messageTemplates); + foreach($keys as $key) { + $this->setMessage($messageString, $key); + } + return $this; + } + + if (!isset($this->_messageTemplates[$messageKey])) { + require_once 'Zend/Validate/Exception.php'; + throw new Zend_Validate_Exception("No message template exists for key '$messageKey'"); + } + + $this->_messageTemplates[$messageKey] = $messageString; + return $this; + } + + /** + * Sets validation failure message templates given as an array, where the array keys are the message keys, + * and the array values are the message template strings. + * + * @param array $messages + * @return Zend_Validate_Abstract + */ + public function setMessages(array $messages) + { + foreach ($messages as $key => $message) { + $this->setMessage($message, $key); + } + return $this; + } + + /** + * Magic function returns the value of the requested property, if and only if it is the value or a + * message variable. + * + * @param string $property + * @return mixed + * @throws Zend_Validate_Exception + */ + public function __get($property) + { + if ($property == 'value') { + return $this->_value; + } + if (array_key_exists($property, $this->_messageVariables)) { + return $this->{$this->_messageVariables[$property]}; + } + /** + * @see Zend_Validate_Exception + */ + require_once 'Zend/Validate/Exception.php'; + throw new Zend_Validate_Exception("No property exists by the name '$property'"); + } + + /** + * Constructs and returns a validation failure message with the given message key and value. + * + * Returns null if and only if $messageKey does not correspond to an existing template. + * + * If a translator is available and a translation exists for $messageKey, + * the translation will be used. + * + * @param string $messageKey + * @param string $value + * @return string + */ + protected function _createMessage($messageKey, $value) + { + if (!isset($this->_messageTemplates[$messageKey])) { + return null; + } + + $message = $this->_messageTemplates[$messageKey]; + + if (null !== ($translator = $this->getTranslator())) { + if ($translator->isTranslated($messageKey)) { + $message = $translator->translate($messageKey); + } else { + $message = $translator->translate($message); + } + } + + if (is_object($value)) { + if (!in_array('__toString', get_class_methods($value))) { + $value = get_class($value) . ' object'; + } else { + $value = $value->__toString(); + } + } else { + $value = (string)$value; + } + + if ($this->getObscureValue()) { + $value = str_repeat('*', strlen($value)); + } + + $message = str_replace('%value%', (string) $value, $message); + foreach ($this->_messageVariables as $ident => $property) { + $message = str_replace("%$ident%", (string) $this->$property, $message); + } + + $length = self::getMessageLength(); + if (($length > -1) && (strlen($message) > $length)) { + $message = substr($message, 0, (self::getMessageLength() - 3)) . '...'; + } + + return $message; + } + + /** + * @param string $messageKey + * @param string $value OPTIONAL + * @return void + */ + protected function _error($messageKey, $value = null) + { + if ($messageKey === null) { + $keys = array_keys($this->_messageTemplates); + $messageKey = current($keys); + } + if ($value === null) { + $value = $this->_value; + } + $this->_errors[] = $messageKey; + $this->_messages[$messageKey] = $this->_createMessage($messageKey, $value); + } + + /** + * Sets the value to be validated and clears the messages and errors arrays + * + * @param mixed $value + * @return void + */ + protected function _setValue($value) + { + $this->_value = $value; + $this->_messages = array(); + $this->_errors = array(); + } + + /** + * Returns array of validation failure message codes + * + * @return array + * @deprecated Since 1.5.0 + */ + public function getErrors() + { + return $this->_errors; + } + + /** + * Set flag indicating whether or not value should be obfuscated in messages + * + * @param bool $flag + * @return Zend_Validate_Abstract + */ + public function setObscureValue($flag) + { + $this->_obscureValue = (bool) $flag; + return $this; + } + + /** + * Retrieve flag indicating whether or not value should be obfuscated in + * messages + * + * @return bool + */ + public function getObscureValue() + { + return $this->_obscureValue; + } + + /** + * Set translation object + * + * @param Zend_Translate|Zend_Translate_Adapter|null $translator + * @return Zend_Validate_Abstract + */ + public function setTranslator($translator = null) + { + if ((null === $translator) || ($translator instanceof Zend_Translate_Adapter)) { + $this->_translator = $translator; + } elseif ($translator instanceof Zend_Translate) { + $this->_translator = $translator->getAdapter(); + } else { + require_once 'Zend/Validate/Exception.php'; + throw new Zend_Validate_Exception('Invalid translator specified'); + } + return $this; + } + + /** + * Return translation object + * + * @return Zend_Translate_Adapter|null + */ + public function getTranslator() + { + if ($this->translatorIsDisabled()) { + return null; + } + + if (null === $this->_translator) { + return self::getDefaultTranslator(); + } + + return $this->_translator; + } + + /** + * Does this validator have its own specific translator? + * + * @return bool + */ + public function hasTranslator() + { + return (bool)$this->_translator; + } + + /** + * Set default translation object for all validate objects + * + * @param Zend_Translate|Zend_Translate_Adapter|null $translator + * @return void + */ + public static function setDefaultTranslator($translator = null) + { + if ((null === $translator) || ($translator instanceof Zend_Translate_Adapter)) { + self::$_defaultTranslator = $translator; + } elseif ($translator instanceof Zend_Translate) { + self::$_defaultTranslator = $translator->getAdapter(); + } else { + require_once 'Zend/Validate/Exception.php'; + throw new Zend_Validate_Exception('Invalid translator specified'); + } + } + + /** + * Get default translation object for all validate objects + * + * @return Zend_Translate_Adapter|null + */ + public static function getDefaultTranslator() + { + if (null === self::$_defaultTranslator) { + require_once 'Zend/Registry.php'; + if (Zend_Registry::isRegistered('Zend_Translate')) { + $translator = Zend_Registry::get('Zend_Translate'); + if ($translator instanceof Zend_Translate_Adapter) { + return $translator; + } elseif ($translator instanceof Zend_Translate) { + return $translator->getAdapter(); + } + } + } + + return self::$_defaultTranslator; + } + + /** + * Is there a default translation object set? + * + * @return boolean + */ + public static function hasDefaultTranslator() + { + return (bool)self::$_defaultTranslator; + } + + /** + * Indicate whether or not translation should be disabled + * + * @param bool $flag + * @return Zend_Validate_Abstract + */ + public function setDisableTranslator($flag) + { + $this->_translatorDisabled = (bool) $flag; + return $this; + } + + /** + * Is translation disabled? + * + * @return bool + */ + public function translatorIsDisabled() + { + return $this->_translatorDisabled; + } + + /** + * Returns the maximum allowed message length + * + * @return integer + */ + public static function getMessageLength() + { + return self::$_messageLength; + } + + /** + * Sets the maximum allowed message length + * + * @param integer $length + */ + public static function setMessageLength($length = -1) + { + self::$_messageLength = $length; + } +} diff --git a/Zend/Validate/Hostname.php b/Zend/Validate/Hostname.php new file mode 100644 index 00000000..06a38f90 --- /dev/null +++ b/Zend/Validate/Hostname.php @@ -0,0 +1,740 @@ + "Invalid type given, value should be a string", + self::IP_ADDRESS_NOT_ALLOWED => "'%value%' appears to be an IP address, but IP addresses are not allowed", + self::UNKNOWN_TLD => "'%value%' appears to be a DNS hostname but cannot match TLD against known list", + self::INVALID_DASH => "'%value%' appears to be a DNS hostname but contains a dash in an invalid position", + self::INVALID_HOSTNAME_SCHEMA => "'%value%' appears to be a DNS hostname but cannot match against hostname schema for TLD '%tld%'", + self::UNDECIPHERABLE_TLD => "'%value%' appears to be a DNS hostname but cannot extract TLD part", + self::INVALID_HOSTNAME => "'%value%' does not match the expected structure for a DNS hostname", + self::INVALID_LOCAL_NAME => "'%value%' does not appear to be a valid local network name", + self::LOCAL_NAME_NOT_ALLOWED => "'%value%' appears to be a local network name but local network names are not allowed", + self::CANNOT_DECODE_PUNYCODE => "'%value%' appears to be a DNS hostname but the given punycode notation cannot be decoded", + ); + + /** + * @var array + */ + protected $_messageVariables = array( + 'tld' => '_tld' + ); + + /** + * Allows Internet domain names (e.g., example.com) + */ + const ALLOW_DNS = 1; + + /** + * Allows IP addresses + */ + const ALLOW_IP = 2; + + /** + * Allows local network names (e.g., localhost, www.localdomain) + */ + const ALLOW_LOCAL = 4; + + /** + * Allows all types of hostnames + */ + const ALLOW_ALL = 7; + + /** + * Array of valid top-level-domains + * + * @see ftp://data.iana.org/TLD/tlds-alpha-by-domain.txt List of all TLDs by domain + * @see http://www.iana.org/domains/root/db/ Official list of supported TLDs + * @var array + */ + protected $_validTlds = array( + 'ac', 'ad', 'ae', 'aero', 'af', 'ag', 'ai', 'al', 'am', 'an', 'ao', 'aq', 'ar', 'arpa', + 'as', 'asia', 'at', 'au', 'aw', 'ax', 'az', 'ba', 'bb', 'bd', 'be', 'bf', 'bg', 'bh', 'bi', + 'biz', 'bj', 'bm', 'bn', 'bo', 'br', 'bs', 'bt', 'bv', 'bw', 'by', 'bz', 'ca', 'cat', 'cc', + 'cd', 'cf', 'cg', 'ch', 'ci', 'ck', 'cl', 'cm', 'cn', 'co', 'com', 'coop', 'cr', 'cu', + 'cv', 'cx', 'cy', 'cz', 'de', 'dj', 'dk', 'dm', 'do', 'dz', 'ec', 'edu', 'ee', 'eg', 'er', + 'es', 'et', 'eu', 'fi', 'fj', 'fk', 'fm', 'fo', 'fr', 'ga', 'gb', 'gd', 'ge', 'gf', 'gg', + 'gh', 'gi', 'gl', 'gm', 'gn', 'gov', 'gp', 'gq', 'gr', 'gs', 'gt', 'gu', 'gw', 'gy', 'hk', + 'hm', 'hn', 'hr', 'ht', 'hu', 'id', 'ie', 'il', 'im', 'in', 'info', 'int', 'io', 'iq', + 'ir', 'is', 'it', 'je', 'jm', 'jo', 'jobs', 'jp', 'ke', 'kg', 'kh', 'ki', 'km', 'kn', 'kp', + 'kr', 'kw', 'ky', 'kz', 'la', 'lb', 'lc', 'li', 'lk', 'lr', 'ls', 'lt', 'lu', 'lv', 'ly', + 'ma', 'mc', 'md', 'me', 'mg', 'mh', 'mil', 'mk', 'ml', 'mm', 'mn', 'mo', 'mobi', 'mp', + 'mq', 'mr', 'ms', 'mt', 'mu', 'museum', 'mv', 'mw', 'mx', 'my', 'mz', 'na', 'name', 'nc', + 'ne', 'net', 'nf', 'ng', 'ni', 'nl', 'no', 'np', 'nr', 'nu', 'nz', 'om', 'org', 'pa', 'pe', + 'pf', 'pg', 'ph', 'pk', 'pl', 'pm', 'pn', 'pr', 'pro', 'ps', 'pt', 'pw', 'py', 'qa', 're', + 'ro', 'rs', 'ru', 'rw', 'sa', 'sb', 'sc', 'sd', 'se', 'sg', 'sh', 'si', 'sj', 'sk', 'sl', + 'sm', 'sn', 'so', 'sr', 'st', 'su', 'sv', 'sy', 'sz', 'tc', 'td', 'tel', 'tf', 'tg', 'th', + 'tj', 'tk', 'tl', 'tm', 'tn', 'to', 'tp', 'tr', 'travel', 'tt', 'tv', 'tw', 'tz', 'ua', + 'ug', 'uk', 'um', 'us', 'uy', 'uz', 'va', 'vc', 've', 'vg', 'vi', 'vn', 'vu', 'wf', 'ws', + 'ye', 'yt', 'yu', 'za', 'zm', 'zw' + ); + + /** + * @var string + */ + protected $_tld; + + /** + * Array for valid Idns + * @see http://www.iana.org/domains/idn-tables/ Official list of supported IDN Chars + * (.AC) Ascension Island http://www.nic.ac/pdf/AC-IDN-Policy.pdf + * (.AR) Argentinia http://www.nic.ar/faqidn.html + * (.AS) American Samoa http://www.nic.as/idn/chars.cfm + * (.AT) Austria http://www.nic.at/en/service/technical_information/idn/charset_converter/ + * (.BIZ) International http://www.iana.org/domains/idn-tables/ + * (.BR) Brazil http://registro.br/faq/faq6.html + * (.BV) Bouvett Island http://www.norid.no/domeneregistrering/idn/idn_nyetegn.en.html + * (.CAT) Catalan http://www.iana.org/domains/idn-tables/tables/cat_ca_1.0.html + * (.CH) Switzerland https://nic.switch.ch/reg/ocView.action?res=EF6GW2JBPVTG67DLNIQXU234MN6SC33JNQQGI7L6#anhang1 + * (.CL) Chile http://www.iana.org/domains/idn-tables/tables/cl_latn_1.0.html + * (.COM) International http://www.verisign.com/information-services/naming-services/internationalized-domain-names/index.html + * (.DE) Germany http://www.denic.de/en/domains/idns/liste.html + * (.DK) Danmark http://www.dk-hostmaster.dk/index.php?id=151 + * (.ES) Spain https://www.nic.es/media/2008-05/1210147705287.pdf + * (.FI) Finland http://www.ficora.fi/en/index/palvelut/fiverkkotunnukset/aakkostenkaytto.html + * (.GR) Greece https://grweb.ics.forth.gr/CharacterTable1_en.jsp + * (.HU) Hungary http://www.domain.hu/domain/English/szabalyzat/szabalyzat.html + * (.INFO) International http://www.nic.info/info/idn + * (.IO) British Indian Ocean Territory http://www.nic.io/IO-IDN-Policy.pdf + * (.IR) Iran http://www.nic.ir/Allowable_Characters_dot-iran + * (.IS) Iceland http://www.isnic.is/domain/rules.php + * (.KR) Korea http://www.iana.org/domains/idn-tables/tables/kr_ko-kr_1.0.html + * (.LI) Liechtenstein https://nic.switch.ch/reg/ocView.action?res=EF6GW2JBPVTG67DLNIQXU234MN6SC33JNQQGI7L6#anhang1 + * (.LT) Lithuania http://www.domreg.lt/static/doc/public/idn_symbols-en.pdf + * (.MD) Moldova http://www.register.md/ + * (.MUSEUM) International http://www.iana.org/domains/idn-tables/tables/museum_latn_1.0.html + * (.NET) International http://www.verisign.com/information-services/naming-services/internationalized-domain-names/index.html + * (.NO) Norway http://www.norid.no/domeneregistrering/idn/idn_nyetegn.en.html + * (.NU) Niue http://www.worldnames.net/ + * (.ORG) International http://www.pir.org/index.php?db=content/FAQs&tbl=FAQs_Registrant&id=2 + * (.PE) Peru https://www.nic.pe/nuevas_politicas_faq_2.php + * (.PL) Poland http://www.dns.pl/IDN/allowed_character_sets.pdf + * (.PR) Puerto Rico http://www.nic.pr/idn_rules.asp + * (.PT) Portugal https://online.dns.pt/dns_2008/do?com=DS;8216320233;111;+PAGE(4000058)+K-CAT-CODIGO(C.125)+RCNT(100); + * (.RU) Russia http://www.iana.org/domains/idn-tables/tables/ru_ru-ru_1.0.html + * (.SA) Saudi Arabia http://www.iana.org/domains/idn-tables/tables/sa_ar_1.0.html + * (.SE) Sweden http://www.iis.se/english/IDN_campaignsite.shtml?lang=en + * (.SH) Saint Helena http://www.nic.sh/SH-IDN-Policy.pdf + * (.SJ) Svalbard and Jan Mayen http://www.norid.no/domeneregistrering/idn/idn_nyetegn.en.html + * (.TH) Thailand http://www.iana.org/domains/idn-tables/tables/th_th-th_1.0.html + * (.TM) Turkmenistan http://www.nic.tm/TM-IDN-Policy.pdf + * (.TR) Turkey https://www.nic.tr/index.php + * (.VE) Venice http://www.iana.org/domains/idn-tables/tables/ve_es_1.0.html + * (.VN) Vietnam http://www.vnnic.vn/english/5-6-300-2-2-04-20071115.htm#1.%20Introduction + * + * @var array + */ + protected $_validIdns = array( + 'AC' => array(1 => '/^[\x{002d}0-9a-zà-öø-ÿāăąćĉċčďđēėęěĝġģĥħīįĵķĺļľŀłńņňŋőœŕŗřśŝşšţťŧūŭůűųŵŷźżž]{1,63}$/iu'), + 'AR' => array(1 => '/^[\x{002d}0-9a-zà-ãç-êìíñ-õü]{1,63}$/iu'), + 'AS' => array(1 => '/^[\x{002d}0-9a-zà-öø-ÿāăąćĉċčďđēĕėęěĝğġģĥħĩīĭįıĵķĸĺļľłńņňŋōŏőœŕŗřśŝşšţťŧũūŭůűųŵŷźż]{1,63}$/iu'), + 'AT' => array(1 => '/^[\x{002d}0-9a-zà-öø-ÿœšž]{1,63}$/iu'), + 'BIZ' => 'Hostname/Biz.php', + 'BR' => array(1 => '/^[\x{002d}0-9a-zà-ãçéíó-õúü]{1,63}$/iu'), + 'BV' => array(1 => '/^[\x{002d}0-9a-zàáä-éêñ-ôöøüčđńŋšŧž]{1,63}$/iu'), + 'CAT' => array(1 => '/^[\x{002d}0-9a-z·àç-éíïòóúü]{1,63}$/iu'), + 'CH' => array(1 => '/^[\x{002d}0-9a-zà-öø-ÿœ]{1,63}$/iu'), + 'CL' => array(1 => '/^[\x{002d}0-9a-záéíñóúü]{1,63}$/iu'), + 'CN' => 'Hostname/Cn.php', + 'COM' => 'Zend/Validate/Hostname/Com.php', + 'DE' => array(1 => '/^[\x{002d}0-9a-zà-öø-ÿăąāćĉčċďđĕěėęēğĝġģĥħĭĩįīıĵķĺľļłńňņŋŏőōœĸŕřŗśŝšşťţŧŭůűũųūŵŷźžż]{1,63}$/iu'), + 'DK' => array(1 => '/^[\x{002d}0-9a-zäéöü]{1,63}$/iu'), + 'ES' => array(1 => '/^[\x{002d}0-9a-zàáçèéíïñòóúü·]{1,63}$/iu'), + 'EU' => array(1 => '/^[\x{002d}0-9a-zà-öø-ÿ]{1,63}$/iu', + 2 => '/^[\x{002d}0-9a-zāăąćĉċčďđēĕėęěĝğġģĥħĩīĭįıĵķĺļľŀłńņňʼnŋōŏőœŕŗřśŝšťŧũūŭůűųŵŷźżž]{1,63}$/iu', + 3 => '/^[\x{002d}0-9a-zșț]{1,63}$/iu', + 4 => '/^[\x{002d}0-9a-zΐάέήίΰαβγδεζηθικλμνξοπρςστυφχψωϊϋόύώ]{1,63}$/iu', + 5 => '/^[\x{002d}0-9a-zабвгдежзийклмнопрстуфхцчшщъыьэюя]{1,63}$/iu', + 6 => '/^[\x{002d}0-9a-zἀ-ἇἐ-ἕἠ-ἧἰ-ἷὀ-ὅὐ-ὗὠ-ὧὰ-ώᾀ-ᾇᾐ-ᾗᾠ-ᾧᾰ-ᾴᾶᾷῂῃῄῆῇῐ-ΐῖῗῠ-ῧῲῳῴῶῷ]{1,63}$/iu'), + 'FI' => array(1 => '/^[\x{002d}0-9a-zäåö]{1,63}$/iu'), + 'GR' => array(1 => '/^[\x{002d}0-9a-zΆΈΉΊΌΎ-ΡΣ-ώἀ-ἕἘ-Ἕἠ-ὅὈ-Ὅὐ-ὗὙὛὝὟ-ώᾀ-ᾴᾶ-ᾼῂῃῄῆ-ῌῐ-ΐῖ-Ίῠ-Ῥῲῳῴῶ-ῼ]{1,63}$/iu'), + 'HK' => 'Zend/Validate/Hostname/Cn.php', + 'HU' => array(1 => '/^[\x{002d}0-9a-záéíóöúüőű]{1,63}$/iu'), + 'INFO'=> array(1 => '/^[\x{002d}0-9a-zäåæéöøü]{1,63}$/iu', + 2 => '/^[\x{002d}0-9a-záéíóöúüőű]{1,63}$/iu', + 3 => '/^[\x{002d}0-9a-záæéíðóöúýþ]{1,63}$/iu', + 4 => '/^[\x{AC00}-\x{D7A3}]{1,17}$/iu', + 5 => '/^[\x{002d}0-9a-zāčēģīķļņōŗšūž]{1,63}$/iu', + 6 => '/^[\x{002d}0-9a-ząčėęįšūųž]{1,63}$/iu', + 7 => '/^[\x{002d}0-9a-zóąćęłńśźż]{1,63}$/iu', + 8 => '/^[\x{002d}0-9a-záéíñóúü]{1,63}$/iu'), + 'IO' => array(1 => '/^[\x{002d}0-9a-zà-öø-ÿăąāćĉčċďđĕěėęēğĝġģĥħĭĩįīıĵķĺľļłńňņŋŏőōœĸŕřŗśŝšşťţŧŭůűũųūŵŷźžż]{1,63}$/iu'), + 'IS' => array(1 => '/^[\x{002d}0-9a-záéýúíóþæöð]{1,63}$/iu'), + 'JP' => 'Zend/Validate/Hostname/Jp.php', + 'KR' => array(1 => '/^[\x{AC00}-\x{D7A3}]{1,17}$/iu'), + 'LI' => array(1 => '/^[\x{002d}0-9a-zà-öø-ÿœ]{1,63}$/iu'), + 'LT' => array(1 => '/^[\x{002d}0-9ąčęėįšųūž]{1,63}$/iu'), + 'MD' => array(1 => '/^[\x{002d}0-9ăâîşţ]{1,63}$/iu'), + 'MUSEUM' => array(1 => '/^[\x{002d}0-9a-zà-öø-ÿāăąćċčďđēėęěğġģħīįıķĺļľłńņňŋōőœŕŗřśşšţťŧūůűųŵŷźżžǎǐǒǔ\x{01E5}\x{01E7}\x{01E9}\x{01EF}ə\x{0292}ẁẃẅỳ]{1,63}$/iu'), + 'NET' => 'Zend/Validate/Hostname/Com.php', + 'NO' => array(1 => '/^[\x{002d}0-9a-zàáä-éêñ-ôöøüčđńŋšŧž]{1,63}$/iu'), + 'NU' => 'Zend/Validate/Hostname/Com.php', + 'ORG' => array(1 => '/^[\x{002d}0-9a-záéíñóúü]{1,63}$/iu', + 2 => '/^[\x{002d}0-9a-zóąćęłńśźż]{1,63}$/iu', + 3 => '/^[\x{002d}0-9a-záäåæéëíðóöøúüýþ]{1,63}$/iu', + 4 => '/^[\x{002d}0-9a-záéíóöúüőű]{1,63}$/iu', + 5 => '/^[\x{002d}0-9a-ząčėęįšūųž]{1,63}$/iu', + 6 => '/^[\x{AC00}-\x{D7A3}]{1,17}$/iu', + 7 => '/^[\x{002d}0-9a-zāčēģīķļņōŗšūž]{1,63}$/iu'), + 'PE' => array(1 => '/^[\x{002d}0-9a-zñáéíóúü]{1,63}$/iu'), + 'PL' => array(1 => '/^[\x{002d}0-9a-zāčēģīķļņōŗšūž]{1,63}$/iu', + 2 => '/^[\x{002d}а-ик-ш\x{0450}ѓѕјљњќџ]{1,63}$/iu', + 3 => '/^[\x{002d}0-9a-zâîăşţ]{1,63}$/iu', + 4 => '/^[\x{002d}0-9а-яё\x{04C2}]{1,63}$/iu', + 5 => '/^[\x{002d}0-9a-zàáâèéêìíîòóôùúûċġħż]{1,63}$/iu', + 6 => '/^[\x{002d}0-9a-zàäåæéêòóôöøü]{1,63}$/iu', + 7 => '/^[\x{002d}0-9a-zóąćęłńśźż]{1,63}$/iu', + 8 => '/^[\x{002d}0-9a-zàáâãçéêíòóôõúü]{1,63}$/iu', + 9 => '/^[\x{002d}0-9a-zâîăşţ]{1,63}$/iu', + 10=> '/^[\x{002d}0-9a-záäéíóôúýčďĺľňŕšťž]{1,63}$/iu', + 11=> '/^[\x{002d}0-9a-zçë]{1,63}$/iu', + 12=> '/^[\x{002d}0-9а-ик-шђјљњћџ]{1,63}$/iu', + 13=> '/^[\x{002d}0-9a-zćčđšž]{1,63}$/iu', + 14=> '/^[\x{002d}0-9a-zâçöûüğış]{1,63}$/iu', + 15=> '/^[\x{002d}0-9a-záéíñóúü]{1,63}$/iu', + 16=> '/^[\x{002d}0-9a-zäõöüšž]{1,63}$/iu', + 17=> '/^[\x{002d}0-9a-zĉĝĥĵŝŭ]{1,63}$/iu', + 18=> '/^[\x{002d}0-9a-zâäéëîô]{1,63}$/iu', + 19=> '/^[\x{002d}0-9a-zàáâäåæçèéêëìíîïðñòôöøùúûüýćčłńřśš]{1,63}$/iu', + 20=> '/^[\x{002d}0-9a-zäåæõöøüšž]{1,63}$/iu', + 21=> '/^[\x{002d}0-9a-zàáçèéìíòóùú]{1,63}$/iu', + 22=> '/^[\x{002d}0-9a-zàáéíóöúüőű]{1,63}$/iu', + 23=> '/^[\x{002d}0-9ΐά-ώ]{1,63}$/iu', + 24=> '/^[\x{002d}0-9a-zàáâåæçèéêëðóôöøüþœ]{1,63}$/iu', + 25=> '/^[\x{002d}0-9a-záäéíóöúüýčďěňřšťůž]{1,63}$/iu', + 26=> '/^[\x{002d}0-9a-z·àçèéíïòóúü]{1,63}$/iu', + 27=> '/^[\x{002d}0-9а-ъьюя\x{0450}\x{045D}]{1,63}$/iu', + 28=> '/^[\x{002d}0-9а-яёіў]{1,63}$/iu', + 29=> '/^[\x{002d}0-9a-ząčėęįšūųž]{1,63}$/iu', + 30=> '/^[\x{002d}0-9a-záäåæéëíðóöøúüýþ]{1,63}$/iu', + 31=> '/^[\x{002d}0-9a-zàâæçèéêëîïñôùûüÿœ]{1,63}$/iu', + 32=> '/^[\x{002d}0-9а-щъыьэюяёєіїґ]{1,63}$/iu', + 33=> '/^[\x{002d}0-9א-ת]{1,63}$/iu'), + 'PR' => array(1 => '/^[\x{002d}0-9a-záéíóúñäëïüöâêîôûàèùæçœãõ]{1,63}$/iu'), + 'PT' => array(1 => '/^[\x{002d}0-9a-záàâãçéêíóôõú]{1,63}$/iu'), + 'RU' => array(1 => '/^[\x{002d}0-9а-яё]{1,63}$/iu'), + 'SA' => array(1 => '/^[\x{002d}.0-9\x{0621}-\x{063A}\x{0641}-\x{064A}\x{0660}-\x{0669}]{1,63}$/iu'), + 'SE' => array(1 => '/^[\x{002d}0-9a-zäåéöü]{1,63}$/iu'), + 'SH' => array(1 => '/^[\x{002d}0-9a-zà-öø-ÿăąāćĉčċďđĕěėęēğĝġģĥħĭĩįīıĵķĺľļłńňņŋŏőōœĸŕřŗśŝšşťţŧŭůűũųūŵŷźžż]{1,63}$/iu'), + 'SJ' => array(1 => '/^[\x{002d}0-9a-zàáä-éêñ-ôöøüčđńŋšŧž]{1,63}$/iu'), + 'TH' => array(1 => '/^[\x{002d}0-9a-z\x{0E01}-\x{0E3A}\x{0E40}-\x{0E4D}\x{0E50}-\x{0E59}]{1,63}$/iu'), + 'TM' => array(1 => '/^[\x{002d}0-9a-zà-öø-ÿāăąćĉċčďđēėęěĝġģĥħīįĵķĺļľŀłńņňŋőœŕŗřśŝşšţťŧūŭůűųŵŷźżž]{1,63}$/iu'), + 'TW' => 'Zend/Validate/Hostname/Cn.php', + 'TR' => array(1 => '/^[\x{002d}0-9a-zğıüşöç]{1,63}$/iu'), + 'VE' => array(1 => '/^[\x{002d}0-9a-záéíóúüñ]{1,63}$/iu'), + 'VN' => array(1 => '/^[ÀÁÂÃÈÉÊÌÍÒÓÔÕÙÚÝàáâãèéêìíòóôõùúýĂăĐđĨĩŨũƠơƯư\x{1EA0}-\x{1EF9}]{1,63}$/iu'), + 'ایران' => array(1 => '/^[\x{0621}-\x{0624}\x{0626}-\x{063A}\x{0641}\x{0642}\x{0644}-\x{0648}\x{067E}\x{0686}\x{0698}\x{06A9}\x{06AF}\x{06CC}\x{06F0}-\x{06F9}]{1,30}$/iu'), + '中国' => 'Zend/Validate/Hostname/Cn.php', + '公司' => 'Zend/Validate/Hostname/Cn.php', + '网络' => 'Zend/Validate/Hostname/Cn.php' + ); + + protected $_idnLength = array( + 'BIZ' => array(5 => 17, 11 => 15, 12 => 20), + 'CN' => array(1 => 20), + 'COM' => array(3 => 17, 5 => 20), + 'HK' => array(1 => 15), + 'INFO'=> array(4 => 17), + 'KR' => array(1 => 17), + 'NET' => array(3 => 17, 5 => 20), + 'ORG' => array(6 => 17), + 'TW' => array(1 => 20), + 'ایران' => array(1 => 30), + '中国' => array(1 => 20), + '公司' => array(1 => 20), + '网络' => array(1 => 20), + ); + + protected $_options = array( + 'allow' => self::ALLOW_DNS, + 'idn' => true, + 'tld' => true, + 'ip' => null + ); + + /** + * Sets validator options + * + * @param integer $allow OPTIONAL Set what types of hostname to allow (default ALLOW_DNS) + * @param boolean $validateIdn OPTIONAL Set whether IDN domains are validated (default true) + * @param boolean $validateTld OPTIONAL Set whether the TLD element of a hostname is validated (default true) + * @param Zend_Validate_Ip $ipValidator OPTIONAL + * @return void + * @see http://www.iana.org/cctld/specifications-policies-cctlds-01apr02.htm Technical Specifications for ccTLDs + */ + public function __construct($options = array()) + { + if ($options instanceof Zend_Config) { + $options = $options->toArray(); + } else if (!is_array($options)) { + $options = func_get_args(); + $temp['allow'] = array_shift($options); + if (!empty($options)) { + $temp['idn'] = array_shift($options); + } + + if (!empty($options)) { + $temp['tld'] = array_shift($options); + } + + if (!empty($options)) { + $temp['ip'] = array_shift($options); + } + + $options = $temp; + } + + $options += $this->_options; + $this->setOptions($options); + } + + /** + * Returns all set options + * + * @return array + */ + public function getOptions() + { + return $this->_options; + } + + /** + * Sets the options for this validator + * + * @param array $options + * @return Zend_Validate_Hostname + */ + public function setOptions($options) + { + if (array_key_exists('allow', $options)) { + $this->setAllow($options['allow']); + } + + if (array_key_exists('idn', $options)) { + $this->setValidateIdn($options['idn']); + } + + if (array_key_exists('tld', $options)) { + $this->setValidateTld($options['tld']); + } + + if (array_key_exists('ip', $options)) { + $this->setIpValidator($options['ip']); + } + + return $this; + } + + /** + * Returns the set ip validator + * + * @return Zend_Validate_Ip + */ + public function getIpValidator() + { + return $this->_options['ip']; + } + + /** + * @param Zend_Validate_Ip $ipValidator OPTIONAL + * @return void; + */ + public function setIpValidator(Zend_Validate_Ip $ipValidator = null) + { + if ($ipValidator === null) { + $ipValidator = new Zend_Validate_Ip(); + } + + $this->_options['ip'] = $ipValidator; + return $this; + } + + /** + * Returns the allow option + * + * @return integer + */ + public function getAllow() + { + return $this->_options['allow']; + } + + /** + * Sets the allow option + * + * @param integer $allow + * @return Zend_Validate_Hostname Provides a fluent interface + */ + public function setAllow($allow) + { + $this->_options['allow'] = $allow; + return $this; + } + + /** + * Returns the set idn option + * + * @return boolean + */ + public function getValidateIdn() + { + return $this->_options['idn']; + } + + /** + * Set whether IDN domains are validated + * + * This only applies when DNS hostnames are validated + * + * @param boolean $allowed Set allowed to true to validate IDNs, and false to not validate them + */ + public function setValidateIdn ($allowed) + { + $this->_options['idn'] = (bool) $allowed; + return $this; + } + + /** + * Returns the set tld option + * + * @return boolean + */ + public function getValidateTld() + { + return $this->_options['tld']; + } + + /** + * Set whether the TLD element of a hostname is validated + * + * This only applies when DNS hostnames are validated + * + * @param boolean $allowed Set allowed to true to validate TLDs, and false to not validate them + */ + public function setValidateTld ($allowed) + { + $this->_options['tld'] = (bool) $allowed; + return $this; + } + + /** + * Defined by Zend_Validate_Interface + * + * Returns true if and only if the $value is a valid hostname with respect to the current allow option + * + * @param string $value + * @throws Zend_Validate_Exception if a fatal error occurs for validation process + * @return boolean + */ + public function isValid($value) + { + if (!is_string($value)) { + $this->_error(self::INVALID); + return false; + } + + $this->_setValue($value); + // Check input against IP address schema + if (preg_match('/^[0-9.a-e:.]*$/i', $value) && + $this->_options['ip']->setTranslator($this->getTranslator())->isValid($value)) { + if (!($this->_options['allow'] & self::ALLOW_IP)) { + $this->_error(self::IP_ADDRESS_NOT_ALLOWED); + return false; + } else { + return true; + } + } + + // Check input against DNS hostname schema + $domainParts = explode('.', $value); + if ((count($domainParts) > 1) && (strlen($value) >= 4) && (strlen($value) <= 254)) { + $status = false; + + $origenc = iconv_get_encoding('internal_encoding'); + iconv_set_encoding('internal_encoding', 'UTF-8'); + do { + // First check TLD + $matches = array(); + if (preg_match('/([^.]{2,10})$/i', end($domainParts), $matches) || + (end($domainParts) == 'ایران') || (end($domainParts) == '中国') || + (end($domainParts) == '公司') || (end($domainParts) == '网络')) { + + reset($domainParts); + + // Hostname characters are: *(label dot)(label dot label); max 254 chars + // label: id-prefix [*ldh{61} id-prefix]; max 63 chars + // id-prefix: alpha / digit + // ldh: alpha / digit / dash + + // Match TLD against known list + $this->_tld = strtolower($matches[1]); + if ($this->_options['tld']) { + if (!in_array($this->_tld, $this->_validTlds)) { + $this->_error(self::UNKNOWN_TLD); + $status = false; + break; + } + } + + /** + * Match against IDN hostnames + * Note: Keep label regex short to avoid issues with long patterns when matching IDN hostnames + * @see Zend_Validate_Hostname_Interface + */ + $regexChars = array(0 => '/^[a-z0-9\x2d]{1,63}$/i'); + if ($this->_options['idn'] && isset($this->_validIdns[strtoupper($this->_tld)])) { + if (is_string($this->_validIdns[strtoupper($this->_tld)])) { + $regexChars += include($this->_validIdns[strtoupper($this->_tld)]); + } else { + $regexChars += $this->_validIdns[strtoupper($this->_tld)]; + } + } + + // Check each hostname part + $check = 0; + foreach ($domainParts as $domainPart) { + // Decode Punycode domainnames to IDN + if (strpos($domainPart, 'xn--') === 0) { + $domainPart = $this->decodePunycode(substr($domainPart, 4)); + if ($domainPart === false) { + return false; + } + } + + // Check dash (-) does not start, end or appear in 3rd and 4th positions + if ((strpos($domainPart, '-') === 0) + || ((strlen($domainPart) > 2) && (strpos($domainPart, '-', 2) == 2) && (strpos($domainPart, '-', 3) == 3)) + || (strpos($domainPart, '-') === (strlen($domainPart) - 1))) { + $this->_error(self::INVALID_DASH); + $status = false; + break 2; + } + + // Check each domain part + $checked = false; + foreach($regexChars as $regexKey => $regexChar) { + $status = @preg_match($regexChar, $domainPart); + if ($status > 0) { + $length = 63; + if (array_key_exists(strtoupper($this->_tld), $this->_idnLength) + && (array_key_exists($regexKey, $this->_idnLength[strtoupper($this->_tld)]))) { + $length = $this->_idnLength[strtoupper($this->_tld)]; + } + + if (iconv_strlen($domainPart, 'UTF-8') > $length) { + $this->_error(self::INVALID_HOSTNAME); + } else { + $checked = true; + break; + } + } + } + + if ($checked) { + ++$check; + } + } + + // If one of the labels doesn't match, the hostname is invalid + if ($check !== count($domainParts)) { + $this->_error(self::INVALID_HOSTNAME_SCHEMA); + $status = false; + } + } else { + // Hostname not long enough + $this->_error(self::UNDECIPHERABLE_TLD); + $status = false; + } + } while (false); + + iconv_set_encoding('internal_encoding', $origenc); + // If the input passes as an Internet domain name, and domain names are allowed, then the hostname + // passes validation + if ($status && ($this->_options['allow'] & self::ALLOW_DNS)) { + return true; + } + } else if ($this->_options['allow'] & self::ALLOW_DNS) { + $this->_error(self::INVALID_HOSTNAME); + } + + // Check input against local network name schema; last chance to pass validation + $regexLocal = '/^(([a-zA-Z0-9\x2d]{1,63}\x2e)*[a-zA-Z0-9\x2d]{1,63}){1,254}$/'; + $status = @preg_match($regexLocal, $value); + + // If the input passes as a local network name, and local network names are allowed, then the + // hostname passes validation + $allowLocal = $this->_options['allow'] & self::ALLOW_LOCAL; + if ($status && $allowLocal) { + return true; + } + + // If the input does not pass as a local network name, add a message + if (!$status) { + $this->_error(self::INVALID_LOCAL_NAME); + } + + // If local network names are not allowed, add a message + if ($status && !$allowLocal) { + $this->_error(self::LOCAL_NAME_NOT_ALLOWED); + } + + return false; + } + + /** + * Decodes a punycode encoded string to it's original utf8 string + * In case of a decoding failure the original string is returned + * + * @param string $encoded Punycode encoded string to decode + * @return string + */ + protected function decodePunycode($encoded) + { + $found = preg_match('/([^a-z0-9\x2d]{1,10})$/i', $encoded); + if (empty($encoded) || ($found > 0)) { + // no punycode encoded string, return as is + $this->_error(self::CANNOT_DECODE_PUNYCODE); + return false; + } + + $separator = strrpos($encoded, '-'); + if ($separator > 0) { + for ($x = 0; $x < $separator; ++$x) { + // prepare decoding matrix + $decoded[] = ord($encoded[$x]); + } + } else { + $this->_error(self::CANNOT_DECODE_PUNYCODE); + return false; + } + + $lengthd = count($decoded); + $lengthe = strlen($encoded); + + // decoding + $init = true; + $base = 72; + $index = 0; + $char = 0x80; + + for ($indexe = ($separator) ? ($separator + 1) : 0; $indexe < $lengthe; ++$lengthd) { + for ($old_index = $index, $pos = 1, $key = 36; 1 ; $key += 36) { + $hex = ord($encoded[$indexe++]); + $digit = ($hex - 48 < 10) ? $hex - 22 + : (($hex - 65 < 26) ? $hex - 65 + : (($hex - 97 < 26) ? $hex - 97 + : 36)); + + $index += $digit * $pos; + $tag = ($key <= $base) ? 1 : (($key >= $base + 26) ? 26 : ($key - $base)); + if ($digit < $tag) { + break; + } + + $pos = (int) ($pos * (36 - $tag)); + } + + $delta = intval($init ? (($index - $old_index) / 700) : (($index - $old_index) / 2)); + $delta += intval($delta / ($lengthd + 1)); + for ($key = 0; $delta > 910 / 2; $key += 36) { + $delta = intval($delta / 35); + } + + $base = intval($key + 36 * $delta / ($delta + 38)); + $init = false; + $char += (int) ($index / ($lengthd + 1)); + $index %= ($lengthd + 1); + if ($lengthd > 0) { + for ($i = $lengthd; $i > $index; $i--) { + $decoded[$i] = $decoded[($i - 1)]; + } + } + + $decoded[$index++] = $char; + } + + // convert decoded ucs4 to utf8 string + foreach ($decoded as $key => $value) { + if ($value < 128) { + $decoded[$key] = chr($value); + } elseif ($value < (1 << 11)) { + $decoded[$key] = chr(192 + ($value >> 6)); + $decoded[$key] .= chr(128 + ($value & 63)); + } elseif ($value < (1 << 16)) { + $decoded[$key] = chr(224 + ($value >> 12)); + $decoded[$key] .= chr(128 + (($value >> 6) & 63)); + $decoded[$key] .= chr(128 + ($value & 63)); + } elseif ($value < (1 << 21)) { + $decoded[$key] = chr(240 + ($value >> 18)); + $decoded[$key] .= chr(128 + (($value >> 12) & 63)); + $decoded[$key] .= chr(128 + (($value >> 6) & 63)); + $decoded[$key] .= chr(128 + ($value & 63)); + } else { + $this->_error(self::CANNOT_DECODE_PUNYCODE); + return false; + } + } + + return implode($decoded); + } +} diff --git a/Zend/Validate/Hostname/Biz.php b/Zend/Validate/Hostname/Biz.php new file mode 100644 index 00000000..36105f91 --- /dev/null +++ b/Zend/Validate/Hostname/Biz.php @@ -0,0 +1,2917 @@ + '/^[\x{002d}0-9a-zäåæéöøü]{1,63}$/iu', + 2 => '/^[\x{002d}0-9a-záéíñóúü]{1,63}$/iu', + 3 => '/^[\x{002d}0-9a-záéíóöúüőű]{1,63}$/iu', + 4 => '/^[\x{002d}0-9a-záæéíðóöúýþ]{1,63}$/iu', + 5 => '/^[\x{AC00}-\x{D7A3}]{1,17}$/iu', + 6 => '/^[\x{002d}0-9a-ząčėęįšūųž]{1,63}$/iu', + 7 => '/^[\x{002d}0-9a-zāčēģīķļņōŗšūž]{1,63}$/iu', + 8 => '/^[\x{002d}0-9a-zàáä-éêñ-ôöøüčđńŋšŧž]{1,63}$/iu', + 9 => '/^[\x{002d}0-9a-zóąćęłńśźż]{1,63}$/iu', + 10 => '/^[\x{002d}0-9a-záàâãçéêíóôõú]{1,63}$/iu', + 11 => '/^[\x{002d}0-9a-z\x{3005}-\x{3007}\x{3041}-\x{3093}\x{309D}\x{309E}\x{30A1}-\x{30F6}\x{30FC}' . +'\x{30FD}\x{30FE}\x{4E00}\x{4E01}\x{4E03}\x{4E07}\x{4E08}\x{4E09}\x{4E0A}' . +'\x{4E0B}\x{4E0D}\x{4E0E}\x{4E10}\x{4E11}\x{4E14}\x{4E15}\x{4E16}\x{4E17}' . +'\x{4E18}\x{4E19}\x{4E1E}\x{4E21}\x{4E26}\x{4E2A}\x{4E2D}\x{4E31}\x{4E32}' . +'\x{4E36}\x{4E38}\x{4E39}\x{4E3B}\x{4E3C}\x{4E3F}\x{4E42}\x{4E43}\x{4E45}' . +'\x{4E4B}\x{4E4D}\x{4E4E}\x{4E4F}\x{4E55}\x{4E56}\x{4E57}\x{4E58}\x{4E59}' . +'\x{4E5D}\x{4E5E}\x{4E5F}\x{4E62}\x{4E71}\x{4E73}\x{4E7E}\x{4E80}\x{4E82}' . +'\x{4E85}\x{4E86}\x{4E88}\x{4E89}\x{4E8A}\x{4E8B}\x{4E8C}\x{4E8E}\x{4E91}' . +'\x{4E92}\x{4E94}\x{4E95}\x{4E98}\x{4E99}\x{4E9B}\x{4E9C}\x{4E9E}\x{4E9F}' . +'\x{4EA0}\x{4EA1}\x{4EA2}\x{4EA4}\x{4EA5}\x{4EA6}\x{4EA8}\x{4EAB}\x{4EAC}' . +'\x{4EAD}\x{4EAE}\x{4EB0}\x{4EB3}\x{4EB6}\x{4EBA}\x{4EC0}\x{4EC1}\x{4EC2}' . +'\x{4EC4}\x{4EC6}\x{4EC7}\x{4ECA}\x{4ECB}\x{4ECD}\x{4ECE}\x{4ECF}\x{4ED4}' . +'\x{4ED5}\x{4ED6}\x{4ED7}\x{4ED8}\x{4ED9}\x{4EDD}\x{4EDE}\x{4EDF}\x{4EE3}' . +'\x{4EE4}\x{4EE5}\x{4EED}\x{4EEE}\x{4EF0}\x{4EF2}\x{4EF6}\x{4EF7}\x{4EFB}' . +'\x{4F01}\x{4F09}\x{4F0A}\x{4F0D}\x{4F0E}\x{4F0F}\x{4F10}\x{4F11}\x{4F1A}' . +'\x{4F1C}\x{4F1D}\x{4F2F}\x{4F30}\x{4F34}\x{4F36}\x{4F38}\x{4F3A}\x{4F3C}' . +'\x{4F3D}\x{4F43}\x{4F46}\x{4F47}\x{4F4D}\x{4F4E}\x{4F4F}\x{4F50}\x{4F51}' . +'\x{4F53}\x{4F55}\x{4F57}\x{4F59}\x{4F5A}\x{4F5B}\x{4F5C}\x{4F5D}\x{4F5E}' . +'\x{4F69}\x{4F6F}\x{4F70}\x{4F73}\x{4F75}\x{4F76}\x{4F7B}\x{4F7C}\x{4F7F}' . +'\x{4F83}\x{4F86}\x{4F88}\x{4F8B}\x{4F8D}\x{4F8F}\x{4F91}\x{4F96}\x{4F98}' . +'\x{4F9B}\x{4F9D}\x{4FA0}\x{4FA1}\x{4FAB}\x{4FAD}\x{4FAE}\x{4FAF}\x{4FB5}' . +'\x{4FB6}\x{4FBF}\x{4FC2}\x{4FC3}\x{4FC4}\x{4FCA}\x{4FCE}\x{4FD0}\x{4FD1}' . +'\x{4FD4}\x{4FD7}\x{4FD8}\x{4FDA}\x{4FDB}\x{4FDD}\x{4FDF}\x{4FE1}\x{4FE3}' . +'\x{4FE4}\x{4FE5}\x{4FEE}\x{4FEF}\x{4FF3}\x{4FF5}\x{4FF6}\x{4FF8}\x{4FFA}' . +'\x{4FFE}\x{5005}\x{5006}\x{5009}\x{500B}\x{500D}\x{500F}\x{5011}\x{5012}' . +'\x{5014}\x{5016}\x{5019}\x{501A}\x{501F}\x{5021}\x{5023}\x{5024}\x{5025}' . +'\x{5026}\x{5028}\x{5029}\x{502A}\x{502B}\x{502C}\x{502D}\x{5036}\x{5039}' . +'\x{5043}\x{5047}\x{5048}\x{5049}\x{504F}\x{5050}\x{5055}\x{5056}\x{505A}' . +'\x{505C}\x{5065}\x{506C}\x{5072}\x{5074}\x{5075}\x{5076}\x{5078}\x{507D}' . +'\x{5080}\x{5085}\x{508D}\x{5091}\x{5098}\x{5099}\x{509A}\x{50AC}\x{50AD}' . +'\x{50B2}\x{50B3}\x{50B4}\x{50B5}\x{50B7}\x{50BE}\x{50C2}\x{50C5}\x{50C9}' . +'\x{50CA}\x{50CD}\x{50CF}\x{50D1}\x{50D5}\x{50D6}\x{50DA}\x{50DE}\x{50E3}' . +'\x{50E5}\x{50E7}\x{50ED}\x{50EE}\x{50F5}\x{50F9}\x{50FB}\x{5100}\x{5101}' . +'\x{5102}\x{5104}\x{5109}\x{5112}\x{5114}\x{5115}\x{5116}\x{5118}\x{511A}' . +'\x{511F}\x{5121}\x{512A}\x{5132}\x{5137}\x{513A}\x{513B}\x{513C}\x{513F}' . +'\x{5140}\x{5141}\x{5143}\x{5144}\x{5145}\x{5146}\x{5147}\x{5148}\x{5149}' . +'\x{514B}\x{514C}\x{514D}\x{514E}\x{5150}\x{5152}\x{5154}\x{515A}\x{515C}' . +'\x{5162}\x{5165}\x{5168}\x{5169}\x{516A}\x{516B}\x{516C}\x{516D}\x{516E}' . +'\x{5171}\x{5175}\x{5176}\x{5177}\x{5178}\x{517C}\x{5180}\x{5182}\x{5185}' . +'\x{5186}\x{5189}\x{518A}\x{518C}\x{518D}\x{518F}\x{5190}\x{5191}\x{5192}' . +'\x{5193}\x{5195}\x{5196}\x{5197}\x{5199}\x{51A0}\x{51A2}\x{51A4}\x{51A5}' . +'\x{51A6}\x{51A8}\x{51A9}\x{51AA}\x{51AB}\x{51AC}\x{51B0}\x{51B1}\x{51B2}' . +'\x{51B3}\x{51B4}\x{51B5}\x{51B6}\x{51B7}\x{51BD}\x{51C4}\x{51C5}\x{51C6}' . +'\x{51C9}\x{51CB}\x{51CC}\x{51CD}\x{51D6}\x{51DB}\x{51DC}\x{51DD}\x{51E0}' . +'\x{51E1}\x{51E6}\x{51E7}\x{51E9}\x{51EA}\x{51ED}\x{51F0}\x{51F1}\x{51F5}' . +'\x{51F6}\x{51F8}\x{51F9}\x{51FA}\x{51FD}\x{51FE}\x{5200}\x{5203}\x{5204}' . +'\x{5206}\x{5207}\x{5208}\x{520A}\x{520B}\x{520E}\x{5211}\x{5214}\x{5217}' . +'\x{521D}\x{5224}\x{5225}\x{5227}\x{5229}\x{522A}\x{522E}\x{5230}\x{5233}' . +'\x{5236}\x{5237}\x{5238}\x{5239}\x{523A}\x{523B}\x{5243}\x{5244}\x{5247}' . +'\x{524A}\x{524B}\x{524C}\x{524D}\x{524F}\x{5254}\x{5256}\x{525B}\x{525E}' . +'\x{5263}\x{5264}\x{5265}\x{5269}\x{526A}\x{526F}\x{5270}\x{5271}\x{5272}' . +'\x{5273}\x{5274}\x{5275}\x{527D}\x{527F}\x{5283}\x{5287}\x{5288}\x{5289}' . +'\x{528D}\x{5291}\x{5292}\x{5294}\x{529B}\x{529F}\x{52A0}\x{52A3}\x{52A9}' . +'\x{52AA}\x{52AB}\x{52AC}\x{52AD}\x{52B1}\x{52B4}\x{52B5}\x{52B9}\x{52BC}' . +'\x{52BE}\x{52C1}\x{52C3}\x{52C5}\x{52C7}\x{52C9}\x{52CD}\x{52D2}\x{52D5}' . +'\x{52D7}\x{52D8}\x{52D9}\x{52DD}\x{52DE}\x{52DF}\x{52E0}\x{52E2}\x{52E3}' . +'\x{52E4}\x{52E6}\x{52E7}\x{52F2}\x{52F3}\x{52F5}\x{52F8}\x{52F9}\x{52FA}' . +'\x{52FE}\x{52FF}\x{5301}\x{5302}\x{5305}\x{5306}\x{5308}\x{530D}\x{530F}' . +'\x{5310}\x{5315}\x{5316}\x{5317}\x{5319}\x{531A}\x{531D}\x{5320}\x{5321}' . +'\x{5323}\x{532A}\x{532F}\x{5331}\x{5333}\x{5338}\x{5339}\x{533A}\x{533B}' . +'\x{533F}\x{5340}\x{5341}\x{5343}\x{5345}\x{5346}\x{5347}\x{5348}\x{5349}' . +'\x{534A}\x{534D}\x{5351}\x{5352}\x{5353}\x{5354}\x{5357}\x{5358}\x{535A}' . +'\x{535C}\x{535E}\x{5360}\x{5366}\x{5369}\x{536E}\x{536F}\x{5370}\x{5371}' . +'\x{5373}\x{5374}\x{5375}\x{5377}\x{5378}\x{537B}\x{537F}\x{5382}\x{5384}' . +'\x{5396}\x{5398}\x{539A}\x{539F}\x{53A0}\x{53A5}\x{53A6}\x{53A8}\x{53A9}' . +'\x{53AD}\x{53AE}\x{53B0}\x{53B3}\x{53B6}\x{53BB}\x{53C2}\x{53C3}\x{53C8}' . +'\x{53C9}\x{53CA}\x{53CB}\x{53CC}\x{53CD}\x{53CE}\x{53D4}\x{53D6}\x{53D7}' . +'\x{53D9}\x{53DB}\x{53DF}\x{53E1}\x{53E2}\x{53E3}\x{53E4}\x{53E5}\x{53E8}' . +'\x{53E9}\x{53EA}\x{53EB}\x{53EC}\x{53ED}\x{53EE}\x{53EF}\x{53F0}\x{53F1}' . +'\x{53F2}\x{53F3}\x{53F6}\x{53F7}\x{53F8}\x{53FA}\x{5401}\x{5403}\x{5404}' . +'\x{5408}\x{5409}\x{540A}\x{540B}\x{540C}\x{540D}\x{540E}\x{540F}\x{5410}' . +'\x{5411}\x{541B}\x{541D}\x{541F}\x{5420}\x{5426}\x{5429}\x{542B}\x{542C}' . +'\x{542D}\x{542E}\x{5436}\x{5438}\x{5439}\x{543B}\x{543C}\x{543D}\x{543E}' . +'\x{5440}\x{5442}\x{5446}\x{5448}\x{5449}\x{544A}\x{544E}\x{5451}\x{545F}' . +'\x{5468}\x{546A}\x{5470}\x{5471}\x{5473}\x{5475}\x{5476}\x{5477}\x{547B}' . +'\x{547C}\x{547D}\x{5480}\x{5484}\x{5486}\x{548B}\x{548C}\x{548E}\x{548F}' . +'\x{5490}\x{5492}\x{54A2}\x{54A4}\x{54A5}\x{54A8}\x{54AB}\x{54AC}\x{54AF}' . +'\x{54B2}\x{54B3}\x{54B8}\x{54BC}\x{54BD}\x{54BE}\x{54C0}\x{54C1}\x{54C2}' . +'\x{54C4}\x{54C7}\x{54C8}\x{54C9}\x{54D8}\x{54E1}\x{54E2}\x{54E5}\x{54E6}' . +'\x{54E8}\x{54E9}\x{54ED}\x{54EE}\x{54F2}\x{54FA}\x{54FD}\x{5504}\x{5506}' . +'\x{5507}\x{550F}\x{5510}\x{5514}\x{5516}\x{552E}\x{552F}\x{5531}\x{5533}' . +'\x{5538}\x{5539}\x{553E}\x{5540}\x{5544}\x{5545}\x{5546}\x{554C}\x{554F}' . +'\x{5553}\x{5556}\x{5557}\x{555C}\x{555D}\x{5563}\x{557B}\x{557C}\x{557E}' . +'\x{5580}\x{5583}\x{5584}\x{5587}\x{5589}\x{558A}\x{558B}\x{5598}\x{5599}' . +'\x{559A}\x{559C}\x{559D}\x{559E}\x{559F}\x{55A7}\x{55A8}\x{55A9}\x{55AA}' . +'\x{55AB}\x{55AC}\x{55AE}\x{55B0}\x{55B6}\x{55C4}\x{55C5}\x{55C7}\x{55D4}' . +'\x{55DA}\x{55DC}\x{55DF}\x{55E3}\x{55E4}\x{55F7}\x{55F9}\x{55FD}\x{55FE}' . +'\x{5606}\x{5609}\x{5614}\x{5616}\x{5617}\x{5618}\x{561B}\x{5629}\x{562F}' . +'\x{5631}\x{5632}\x{5634}\x{5636}\x{5638}\x{5642}\x{564C}\x{564E}\x{5650}' . +'\x{565B}\x{5664}\x{5668}\x{566A}\x{566B}\x{566C}\x{5674}\x{5678}\x{567A}' . +'\x{5680}\x{5686}\x{5687}\x{568A}\x{568F}\x{5694}\x{56A0}\x{56A2}\x{56A5}' . +'\x{56AE}\x{56B4}\x{56B6}\x{56BC}\x{56C0}\x{56C1}\x{56C2}\x{56C3}\x{56C8}' . +'\x{56CE}\x{56D1}\x{56D3}\x{56D7}\x{56D8}\x{56DA}\x{56DB}\x{56DE}\x{56E0}' . +'\x{56E3}\x{56EE}\x{56F0}\x{56F2}\x{56F3}\x{56F9}\x{56FA}\x{56FD}\x{56FF}' . +'\x{5700}\x{5703}\x{5704}\x{5708}\x{5709}\x{570B}\x{570D}\x{570F}\x{5712}' . +'\x{5713}\x{5716}\x{5718}\x{571C}\x{571F}\x{5726}\x{5727}\x{5728}\x{572D}' . +'\x{5730}\x{5737}\x{5738}\x{573B}\x{5740}\x{5742}\x{5747}\x{574A}\x{574E}' . +'\x{574F}\x{5750}\x{5751}\x{5761}\x{5764}\x{5766}\x{5769}\x{576A}\x{577F}' . +'\x{5782}\x{5788}\x{5789}\x{578B}\x{5793}\x{57A0}\x{57A2}\x{57A3}\x{57A4}' . +'\x{57AA}\x{57B0}\x{57B3}\x{57C0}\x{57C3}\x{57C6}\x{57CB}\x{57CE}\x{57D2}' . +'\x{57D3}\x{57D4}\x{57D6}\x{57DC}\x{57DF}\x{57E0}\x{57E3}\x{57F4}\x{57F7}' . +'\x{57F9}\x{57FA}\x{57FC}\x{5800}\x{5802}\x{5805}\x{5806}\x{580A}\x{580B}' . +'\x{5815}\x{5819}\x{581D}\x{5821}\x{5824}\x{582A}\x{582F}\x{5830}\x{5831}' . +'\x{5834}\x{5835}\x{583A}\x{583D}\x{5840}\x{5841}\x{584A}\x{584B}\x{5851}' . +'\x{5852}\x{5854}\x{5857}\x{5858}\x{5859}\x{585A}\x{585E}\x{5862}\x{5869}' . +'\x{586B}\x{5870}\x{5872}\x{5875}\x{5879}\x{587E}\x{5883}\x{5885}\x{5893}' . +'\x{5897}\x{589C}\x{589F}\x{58A8}\x{58AB}\x{58AE}\x{58B3}\x{58B8}\x{58B9}' . +'\x{58BA}\x{58BB}\x{58BE}\x{58C1}\x{58C5}\x{58C7}\x{58CA}\x{58CC}\x{58D1}' . +'\x{58D3}\x{58D5}\x{58D7}\x{58D8}\x{58D9}\x{58DC}\x{58DE}\x{58DF}\x{58E4}' . +'\x{58E5}\x{58EB}\x{58EC}\x{58EE}\x{58EF}\x{58F0}\x{58F1}\x{58F2}\x{58F7}' . +'\x{58F9}\x{58FA}\x{58FB}\x{58FC}\x{58FD}\x{5902}\x{5909}\x{590A}\x{590F}' . +'\x{5910}\x{5915}\x{5916}\x{5918}\x{5919}\x{591A}\x{591B}\x{591C}\x{5922}' . +'\x{5925}\x{5927}\x{5929}\x{592A}\x{592B}\x{592C}\x{592D}\x{592E}\x{5931}' . +'\x{5932}\x{5937}\x{5938}\x{593E}\x{5944}\x{5947}\x{5948}\x{5949}\x{594E}' . +'\x{594F}\x{5950}\x{5951}\x{5954}\x{5955}\x{5957}\x{5958}\x{595A}\x{5960}' . +'\x{5962}\x{5965}\x{5967}\x{5968}\x{5969}\x{596A}\x{596C}\x{596E}\x{5973}' . +'\x{5974}\x{5978}\x{597D}\x{5981}\x{5982}\x{5983}\x{5984}\x{598A}\x{598D}' . +'\x{5993}\x{5996}\x{5999}\x{599B}\x{599D}\x{59A3}\x{59A5}\x{59A8}\x{59AC}' . +'\x{59B2}\x{59B9}\x{59BB}\x{59BE}\x{59C6}\x{59C9}\x{59CB}\x{59D0}\x{59D1}' . +'\x{59D3}\x{59D4}\x{59D9}\x{59DA}\x{59DC}\x{59E5}\x{59E6}\x{59E8}\x{59EA}' . +'\x{59EB}\x{59F6}\x{59FB}\x{59FF}\x{5A01}\x{5A03}\x{5A09}\x{5A11}\x{5A18}' . +'\x{5A1A}\x{5A1C}\x{5A1F}\x{5A20}\x{5A25}\x{5A29}\x{5A2F}\x{5A35}\x{5A36}' . +'\x{5A3C}\x{5A40}\x{5A41}\x{5A46}\x{5A49}\x{5A5A}\x{5A62}\x{5A66}\x{5A6A}' . +'\x{5A6C}\x{5A7F}\x{5A92}\x{5A9A}\x{5A9B}\x{5ABC}\x{5ABD}\x{5ABE}\x{5AC1}' . +'\x{5AC2}\x{5AC9}\x{5ACB}\x{5ACC}\x{5AD0}\x{5AD6}\x{5AD7}\x{5AE1}\x{5AE3}' . +'\x{5AE6}\x{5AE9}\x{5AFA}\x{5AFB}\x{5B09}\x{5B0B}\x{5B0C}\x{5B16}\x{5B22}' . +'\x{5B2A}\x{5B2C}\x{5B30}\x{5B32}\x{5B36}\x{5B3E}\x{5B40}\x{5B43}\x{5B45}' . +'\x{5B50}\x{5B51}\x{5B54}\x{5B55}\x{5B57}\x{5B58}\x{5B5A}\x{5B5B}\x{5B5C}' . +'\x{5B5D}\x{5B5F}\x{5B63}\x{5B64}\x{5B65}\x{5B66}\x{5B69}\x{5B6B}\x{5B70}' . +'\x{5B71}\x{5B73}\x{5B75}\x{5B78}\x{5B7A}\x{5B80}\x{5B83}\x{5B85}\x{5B87}' . +'\x{5B88}\x{5B89}\x{5B8B}\x{5B8C}\x{5B8D}\x{5B8F}\x{5B95}\x{5B97}\x{5B98}' . +'\x{5B99}\x{5B9A}\x{5B9B}\x{5B9C}\x{5B9D}\x{5B9F}\x{5BA2}\x{5BA3}\x{5BA4}' . +'\x{5BA5}\x{5BA6}\x{5BAE}\x{5BB0}\x{5BB3}\x{5BB4}\x{5BB5}\x{5BB6}\x{5BB8}' . +'\x{5BB9}\x{5BBF}\x{5BC2}\x{5BC3}\x{5BC4}\x{5BC5}\x{5BC6}\x{5BC7}\x{5BC9}' . +'\x{5BCC}\x{5BD0}\x{5BD2}\x{5BD3}\x{5BD4}\x{5BDB}\x{5BDD}\x{5BDE}\x{5BDF}' . +'\x{5BE1}\x{5BE2}\x{5BE4}\x{5BE5}\x{5BE6}\x{5BE7}\x{5BE8}\x{5BE9}\x{5BEB}' . +'\x{5BEE}\x{5BF0}\x{5BF3}\x{5BF5}\x{5BF6}\x{5BF8}\x{5BFA}\x{5BFE}\x{5BFF}' . +'\x{5C01}\x{5C02}\x{5C04}\x{5C05}\x{5C06}\x{5C07}\x{5C08}\x{5C09}\x{5C0A}' . +'\x{5C0B}\x{5C0D}\x{5C0E}\x{5C0F}\x{5C11}\x{5C13}\x{5C16}\x{5C1A}\x{5C20}' . +'\x{5C22}\x{5C24}\x{5C28}\x{5C2D}\x{5C31}\x{5C38}\x{5C39}\x{5C3A}\x{5C3B}' . +'\x{5C3C}\x{5C3D}\x{5C3E}\x{5C3F}\x{5C40}\x{5C41}\x{5C45}\x{5C46}\x{5C48}' . +'\x{5C4A}\x{5C4B}\x{5C4D}\x{5C4E}\x{5C4F}\x{5C50}\x{5C51}\x{5C53}\x{5C55}' . +'\x{5C5E}\x{5C60}\x{5C61}\x{5C64}\x{5C65}\x{5C6C}\x{5C6E}\x{5C6F}\x{5C71}' . +'\x{5C76}\x{5C79}\x{5C8C}\x{5C90}\x{5C91}\x{5C94}\x{5CA1}\x{5CA8}\x{5CA9}' . +'\x{5CAB}\x{5CAC}\x{5CB1}\x{5CB3}\x{5CB6}\x{5CB7}\x{5CB8}\x{5CBB}\x{5CBC}' . +'\x{5CBE}\x{5CC5}\x{5CC7}\x{5CD9}\x{5CE0}\x{5CE1}\x{5CE8}\x{5CE9}\x{5CEA}' . +'\x{5CED}\x{5CEF}\x{5CF0}\x{5CF6}\x{5CFA}\x{5CFB}\x{5CFD}\x{5D07}\x{5D0B}' . +'\x{5D0E}\x{5D11}\x{5D14}\x{5D15}\x{5D16}\x{5D17}\x{5D18}\x{5D19}\x{5D1A}' . +'\x{5D1B}\x{5D1F}\x{5D22}\x{5D29}\x{5D4B}\x{5D4C}\x{5D4E}\x{5D50}\x{5D52}' . +'\x{5D5C}\x{5D69}\x{5D6C}\x{5D6F}\x{5D73}\x{5D76}\x{5D82}\x{5D84}\x{5D87}' . +'\x{5D8B}\x{5D8C}\x{5D90}\x{5D9D}\x{5DA2}\x{5DAC}\x{5DAE}\x{5DB7}\x{5DBA}' . +'\x{5DBC}\x{5DBD}\x{5DC9}\x{5DCC}\x{5DCD}\x{5DD2}\x{5DD3}\x{5DD6}\x{5DDB}' . +'\x{5DDD}\x{5DDE}\x{5DE1}\x{5DE3}\x{5DE5}\x{5DE6}\x{5DE7}\x{5DE8}\x{5DEB}' . +'\x{5DEE}\x{5DF1}\x{5DF2}\x{5DF3}\x{5DF4}\x{5DF5}\x{5DF7}\x{5DFB}\x{5DFD}' . +'\x{5DFE}\x{5E02}\x{5E03}\x{5E06}\x{5E0B}\x{5E0C}\x{5E11}\x{5E16}\x{5E19}' . +'\x{5E1A}\x{5E1B}\x{5E1D}\x{5E25}\x{5E2B}\x{5E2D}\x{5E2F}\x{5E30}\x{5E33}' . +'\x{5E36}\x{5E37}\x{5E38}\x{5E3D}\x{5E40}\x{5E43}\x{5E44}\x{5E45}\x{5E47}' . +'\x{5E4C}\x{5E4E}\x{5E54}\x{5E55}\x{5E57}\x{5E5F}\x{5E61}\x{5E62}\x{5E63}' . +'\x{5E64}\x{5E72}\x{5E73}\x{5E74}\x{5E75}\x{5E76}\x{5E78}\x{5E79}\x{5E7A}' . +'\x{5E7B}\x{5E7C}\x{5E7D}\x{5E7E}\x{5E7F}\x{5E81}\x{5E83}\x{5E84}\x{5E87}' . +'\x{5E8A}\x{5E8F}\x{5E95}\x{5E96}\x{5E97}\x{5E9A}\x{5E9C}\x{5EA0}\x{5EA6}' . +'\x{5EA7}\x{5EAB}\x{5EAD}\x{5EB5}\x{5EB6}\x{5EB7}\x{5EB8}\x{5EC1}\x{5EC2}' . +'\x{5EC3}\x{5EC8}\x{5EC9}\x{5ECA}\x{5ECF}\x{5ED0}\x{5ED3}\x{5ED6}\x{5EDA}' . +'\x{5EDB}\x{5EDD}\x{5EDF}\x{5EE0}\x{5EE1}\x{5EE2}\x{5EE3}\x{5EE8}\x{5EE9}' . +'\x{5EEC}\x{5EF0}\x{5EF1}\x{5EF3}\x{5EF4}\x{5EF6}\x{5EF7}\x{5EF8}\x{5EFA}' . +'\x{5EFB}\x{5EFC}\x{5EFE}\x{5EFF}\x{5F01}\x{5F03}\x{5F04}\x{5F09}\x{5F0A}' . +'\x{5F0B}\x{5F0C}\x{5F0D}\x{5F0F}\x{5F10}\x{5F11}\x{5F13}\x{5F14}\x{5F15}' . +'\x{5F16}\x{5F17}\x{5F18}\x{5F1B}\x{5F1F}\x{5F25}\x{5F26}\x{5F27}\x{5F29}' . +'\x{5F2D}\x{5F2F}\x{5F31}\x{5F35}\x{5F37}\x{5F38}\x{5F3C}\x{5F3E}\x{5F41}' . +'\x{5F48}\x{5F4A}\x{5F4C}\x{5F4E}\x{5F51}\x{5F53}\x{5F56}\x{5F57}\x{5F59}' . +'\x{5F5C}\x{5F5D}\x{5F61}\x{5F62}\x{5F66}\x{5F69}\x{5F6A}\x{5F6B}\x{5F6C}' . +'\x{5F6D}\x{5F70}\x{5F71}\x{5F73}\x{5F77}\x{5F79}\x{5F7C}\x{5F7F}\x{5F80}' . +'\x{5F81}\x{5F82}\x{5F83}\x{5F84}\x{5F85}\x{5F87}\x{5F88}\x{5F8A}\x{5F8B}' . +'\x{5F8C}\x{5F90}\x{5F91}\x{5F92}\x{5F93}\x{5F97}\x{5F98}\x{5F99}\x{5F9E}' . +'\x{5FA0}\x{5FA1}\x{5FA8}\x{5FA9}\x{5FAA}\x{5FAD}\x{5FAE}\x{5FB3}\x{5FB4}' . +'\x{5FB9}\x{5FBC}\x{5FBD}\x{5FC3}\x{5FC5}\x{5FCC}\x{5FCD}\x{5FD6}\x{5FD7}' . +'\x{5FD8}\x{5FD9}\x{5FDC}\x{5FDD}\x{5FE0}\x{5FE4}\x{5FEB}\x{5FF0}\x{5FF1}' . +'\x{5FF5}\x{5FF8}\x{5FFB}\x{5FFD}\x{5FFF}\x{600E}\x{600F}\x{6010}\x{6012}' . +'\x{6015}\x{6016}\x{6019}\x{601B}\x{601C}\x{601D}\x{6020}\x{6021}\x{6025}' . +'\x{6026}\x{6027}\x{6028}\x{6029}\x{602A}\x{602B}\x{602F}\x{6031}\x{603A}' . +'\x{6041}\x{6042}\x{6043}\x{6046}\x{604A}\x{604B}\x{604D}\x{6050}\x{6052}' . +'\x{6055}\x{6059}\x{605A}\x{605F}\x{6060}\x{6062}\x{6063}\x{6064}\x{6065}' . +'\x{6068}\x{6069}\x{606A}\x{606B}\x{606C}\x{606D}\x{606F}\x{6070}\x{6075}' . +'\x{6077}\x{6081}\x{6083}\x{6084}\x{6089}\x{608B}\x{608C}\x{608D}\x{6092}' . +'\x{6094}\x{6096}\x{6097}\x{609A}\x{609B}\x{609F}\x{60A0}\x{60A3}\x{60A6}' . +'\x{60A7}\x{60A9}\x{60AA}\x{60B2}\x{60B3}\x{60B4}\x{60B5}\x{60B6}\x{60B8}' . +'\x{60BC}\x{60BD}\x{60C5}\x{60C6}\x{60C7}\x{60D1}\x{60D3}\x{60D8}\x{60DA}' . +'\x{60DC}\x{60DF}\x{60E0}\x{60E1}\x{60E3}\x{60E7}\x{60E8}\x{60F0}\x{60F1}' . +'\x{60F3}\x{60F4}\x{60F6}\x{60F7}\x{60F9}\x{60FA}\x{60FB}\x{6100}\x{6101}' . +'\x{6103}\x{6106}\x{6108}\x{6109}\x{610D}\x{610E}\x{610F}\x{6115}\x{611A}' . +'\x{611B}\x{611F}\x{6121}\x{6127}\x{6128}\x{612C}\x{6134}\x{613C}\x{613D}' . +'\x{613E}\x{613F}\x{6142}\x{6144}\x{6147}\x{6148}\x{614A}\x{614B}\x{614C}' . +'\x{614D}\x{614E}\x{6153}\x{6155}\x{6158}\x{6159}\x{615A}\x{615D}\x{615F}' . +'\x{6162}\x{6163}\x{6165}\x{6167}\x{6168}\x{616B}\x{616E}\x{616F}\x{6170}' . +'\x{6171}\x{6173}\x{6174}\x{6175}\x{6176}\x{6177}\x{617E}\x{6182}\x{6187}' . +'\x{618A}\x{618E}\x{6190}\x{6191}\x{6194}\x{6196}\x{6199}\x{619A}\x{61A4}' . +'\x{61A7}\x{61A9}\x{61AB}\x{61AC}\x{61AE}\x{61B2}\x{61B6}\x{61BA}\x{61BE}' . +'\x{61C3}\x{61C6}\x{61C7}\x{61C8}\x{61C9}\x{61CA}\x{61CB}\x{61CC}\x{61CD}' . +'\x{61D0}\x{61E3}\x{61E6}\x{61F2}\x{61F4}\x{61F6}\x{61F7}\x{61F8}\x{61FA}' . +'\x{61FC}\x{61FD}\x{61FE}\x{61FF}\x{6200}\x{6208}\x{6209}\x{620A}\x{620C}' . +'\x{620D}\x{620E}\x{6210}\x{6211}\x{6212}\x{6214}\x{6216}\x{621A}\x{621B}' . +'\x{621D}\x{621E}\x{621F}\x{6221}\x{6226}\x{622A}\x{622E}\x{622F}\x{6230}' . +'\x{6232}\x{6233}\x{6234}\x{6238}\x{623B}\x{623F}\x{6240}\x{6241}\x{6247}' . +'\x{6248}\x{6249}\x{624B}\x{624D}\x{624E}\x{6253}\x{6255}\x{6258}\x{625B}' . +'\x{625E}\x{6260}\x{6263}\x{6268}\x{626E}\x{6271}\x{6276}\x{6279}\x{627C}' . +'\x{627E}\x{627F}\x{6280}\x{6282}\x{6283}\x{6284}\x{6289}\x{628A}\x{6291}' . +'\x{6292}\x{6293}\x{6294}\x{6295}\x{6296}\x{6297}\x{6298}\x{629B}\x{629C}' . +'\x{629E}\x{62AB}\x{62AC}\x{62B1}\x{62B5}\x{62B9}\x{62BB}\x{62BC}\x{62BD}' . +'\x{62C2}\x{62C5}\x{62C6}\x{62C7}\x{62C8}\x{62C9}\x{62CA}\x{62CC}\x{62CD}' . +'\x{62CF}\x{62D0}\x{62D1}\x{62D2}\x{62D3}\x{62D4}\x{62D7}\x{62D8}\x{62D9}' . +'\x{62DB}\x{62DC}\x{62DD}\x{62E0}\x{62E1}\x{62EC}\x{62ED}\x{62EE}\x{62EF}' . +'\x{62F1}\x{62F3}\x{62F5}\x{62F6}\x{62F7}\x{62FE}\x{62FF}\x{6301}\x{6302}' . +'\x{6307}\x{6308}\x{6309}\x{630C}\x{6311}\x{6319}\x{631F}\x{6327}\x{6328}' . +'\x{632B}\x{632F}\x{633A}\x{633D}\x{633E}\x{633F}\x{6349}\x{634C}\x{634D}' . +'\x{634F}\x{6350}\x{6355}\x{6357}\x{635C}\x{6367}\x{6368}\x{6369}\x{636B}' . +'\x{636E}\x{6372}\x{6376}\x{6377}\x{637A}\x{637B}\x{6380}\x{6383}\x{6388}' . +'\x{6389}\x{638C}\x{638E}\x{638F}\x{6392}\x{6396}\x{6398}\x{639B}\x{639F}' . +'\x{63A0}\x{63A1}\x{63A2}\x{63A3}\x{63A5}\x{63A7}\x{63A8}\x{63A9}\x{63AA}' . +'\x{63AB}\x{63AC}\x{63B2}\x{63B4}\x{63B5}\x{63BB}\x{63BE}\x{63C0}\x{63C3}' . +'\x{63C4}\x{63C6}\x{63C9}\x{63CF}\x{63D0}\x{63D2}\x{63D6}\x{63DA}\x{63DB}' . +'\x{63E1}\x{63E3}\x{63E9}\x{63EE}\x{63F4}\x{63F6}\x{63FA}\x{6406}\x{640D}' . +'\x{640F}\x{6413}\x{6416}\x{6417}\x{641C}\x{6426}\x{6428}\x{642C}\x{642D}' . +'\x{6434}\x{6436}\x{643A}\x{643E}\x{6442}\x{644E}\x{6458}\x{6467}\x{6469}' . +'\x{646F}\x{6476}\x{6478}\x{647A}\x{6483}\x{6488}\x{6492}\x{6493}\x{6495}' . +'\x{649A}\x{649E}\x{64A4}\x{64A5}\x{64A9}\x{64AB}\x{64AD}\x{64AE}\x{64B0}' . +'\x{64B2}\x{64B9}\x{64BB}\x{64BC}\x{64C1}\x{64C2}\x{64C5}\x{64C7}\x{64CD}' . +'\x{64D2}\x{64D4}\x{64D8}\x{64DA}\x{64E0}\x{64E1}\x{64E2}\x{64E3}\x{64E6}' . +'\x{64E7}\x{64EC}\x{64EF}\x{64F1}\x{64F2}\x{64F4}\x{64F6}\x{64FA}\x{64FD}' . +'\x{64FE}\x{6500}\x{6505}\x{6518}\x{651C}\x{651D}\x{6523}\x{6524}\x{652A}' . +'\x{652B}\x{652C}\x{652F}\x{6534}\x{6535}\x{6536}\x{6537}\x{6538}\x{6539}' . +'\x{653B}\x{653E}\x{653F}\x{6545}\x{6548}\x{654D}\x{654F}\x{6551}\x{6555}' . +'\x{6556}\x{6557}\x{6558}\x{6559}\x{655D}\x{655E}\x{6562}\x{6563}\x{6566}' . +'\x{656C}\x{6570}\x{6572}\x{6574}\x{6575}\x{6577}\x{6578}\x{6582}\x{6583}' . +'\x{6587}\x{6588}\x{6589}\x{658C}\x{658E}\x{6590}\x{6591}\x{6597}\x{6599}' . +'\x{659B}\x{659C}\x{659F}\x{65A1}\x{65A4}\x{65A5}\x{65A7}\x{65AB}\x{65AC}' . +'\x{65AD}\x{65AF}\x{65B0}\x{65B7}\x{65B9}\x{65BC}\x{65BD}\x{65C1}\x{65C3}' . +'\x{65C4}\x{65C5}\x{65C6}\x{65CB}\x{65CC}\x{65CF}\x{65D2}\x{65D7}\x{65D9}' . +'\x{65DB}\x{65E0}\x{65E1}\x{65E2}\x{65E5}\x{65E6}\x{65E7}\x{65E8}\x{65E9}' . +'\x{65EC}\x{65ED}\x{65F1}\x{65FA}\x{65FB}\x{6602}\x{6603}\x{6606}\x{6607}' . +'\x{660A}\x{660C}\x{660E}\x{660F}\x{6613}\x{6614}\x{661C}\x{661F}\x{6620}' . +'\x{6625}\x{6627}\x{6628}\x{662D}\x{662F}\x{6634}\x{6635}\x{6636}\x{663C}' . +'\x{663F}\x{6641}\x{6642}\x{6643}\x{6644}\x{6649}\x{664B}\x{664F}\x{6652}' . +'\x{665D}\x{665E}\x{665F}\x{6662}\x{6664}\x{6666}\x{6667}\x{6668}\x{6669}' . +'\x{666E}\x{666F}\x{6670}\x{6674}\x{6676}\x{667A}\x{6681}\x{6683}\x{6684}' . +'\x{6687}\x{6688}\x{6689}\x{668E}\x{6691}\x{6696}\x{6697}\x{6698}\x{669D}' . +'\x{66A2}\x{66A6}\x{66AB}\x{66AE}\x{66B4}\x{66B8}\x{66B9}\x{66BC}\x{66BE}' . +'\x{66C1}\x{66C4}\x{66C7}\x{66C9}\x{66D6}\x{66D9}\x{66DA}\x{66DC}\x{66DD}' . +'\x{66E0}\x{66E6}\x{66E9}\x{66F0}\x{66F2}\x{66F3}\x{66F4}\x{66F5}\x{66F7}' . +'\x{66F8}\x{66F9}\x{66FC}\x{66FD}\x{66FE}\x{66FF}\x{6700}\x{6703}\x{6708}' . +'\x{6709}\x{670B}\x{670D}\x{670F}\x{6714}\x{6715}\x{6716}\x{6717}\x{671B}' . +'\x{671D}\x{671E}\x{671F}\x{6726}\x{6727}\x{6728}\x{672A}\x{672B}\x{672C}' . +'\x{672D}\x{672E}\x{6731}\x{6734}\x{6736}\x{6737}\x{6738}\x{673A}\x{673D}' . +'\x{673F}\x{6741}\x{6746}\x{6749}\x{674E}\x{674F}\x{6750}\x{6751}\x{6753}' . +'\x{6756}\x{6759}\x{675C}\x{675E}\x{675F}\x{6760}\x{6761}\x{6762}\x{6763}' . +'\x{6764}\x{6765}\x{676A}\x{676D}\x{676F}\x{6770}\x{6771}\x{6772}\x{6773}' . +'\x{6775}\x{6777}\x{677C}\x{677E}\x{677F}\x{6785}\x{6787}\x{6789}\x{678B}' . +'\x{678C}\x{6790}\x{6795}\x{6797}\x{679A}\x{679C}\x{679D}\x{67A0}\x{67A1}' . +'\x{67A2}\x{67A6}\x{67A9}\x{67AF}\x{67B3}\x{67B4}\x{67B6}\x{67B7}\x{67B8}' . +'\x{67B9}\x{67C1}\x{67C4}\x{67C6}\x{67CA}\x{67CE}\x{67CF}\x{67D0}\x{67D1}' . +'\x{67D3}\x{67D4}\x{67D8}\x{67DA}\x{67DD}\x{67DE}\x{67E2}\x{67E4}\x{67E7}' . +'\x{67E9}\x{67EC}\x{67EE}\x{67EF}\x{67F1}\x{67F3}\x{67F4}\x{67F5}\x{67FB}' . +'\x{67FE}\x{67FF}\x{6802}\x{6803}\x{6804}\x{6813}\x{6816}\x{6817}\x{681E}' . +'\x{6821}\x{6822}\x{6829}\x{682A}\x{682B}\x{6832}\x{6834}\x{6838}\x{6839}' . +'\x{683C}\x{683D}\x{6840}\x{6841}\x{6842}\x{6843}\x{6846}\x{6848}\x{684D}' . +'\x{684E}\x{6850}\x{6851}\x{6853}\x{6854}\x{6859}\x{685C}\x{685D}\x{685F}' . +'\x{6863}\x{6867}\x{6874}\x{6876}\x{6877}\x{687E}\x{687F}\x{6881}\x{6883}' . +'\x{6885}\x{688D}\x{688F}\x{6893}\x{6894}\x{6897}\x{689B}\x{689D}\x{689F}' . +'\x{68A0}\x{68A2}\x{68A6}\x{68A7}\x{68A8}\x{68AD}\x{68AF}\x{68B0}\x{68B1}' . +'\x{68B3}\x{68B5}\x{68B6}\x{68B9}\x{68BA}\x{68BC}\x{68C4}\x{68C6}\x{68C9}' . +'\x{68CA}\x{68CB}\x{68CD}\x{68D2}\x{68D4}\x{68D5}\x{68D7}\x{68D8}\x{68DA}' . +'\x{68DF}\x{68E0}\x{68E1}\x{68E3}\x{68E7}\x{68EE}\x{68EF}\x{68F2}\x{68F9}' . +'\x{68FA}\x{6900}\x{6901}\x{6904}\x{6905}\x{6908}\x{690B}\x{690C}\x{690D}' . +'\x{690E}\x{690F}\x{6912}\x{6919}\x{691A}\x{691B}\x{691C}\x{6921}\x{6922}' . +'\x{6923}\x{6925}\x{6926}\x{6928}\x{692A}\x{6930}\x{6934}\x{6936}\x{6939}' . +'\x{693D}\x{693F}\x{694A}\x{6953}\x{6954}\x{6955}\x{6959}\x{695A}\x{695C}' . +'\x{695D}\x{695E}\x{6960}\x{6961}\x{6962}\x{696A}\x{696B}\x{696D}\x{696E}' . +'\x{696F}\x{6973}\x{6974}\x{6975}\x{6977}\x{6978}\x{6979}\x{697C}\x{697D}' . +'\x{697E}\x{6981}\x{6982}\x{698A}\x{698E}\x{6991}\x{6994}\x{6995}\x{699B}' . +'\x{699C}\x{69A0}\x{69A7}\x{69AE}\x{69B1}\x{69B2}\x{69B4}\x{69BB}\x{69BE}' . +'\x{69BF}\x{69C1}\x{69C3}\x{69C7}\x{69CA}\x{69CB}\x{69CC}\x{69CD}\x{69CE}' . +'\x{69D0}\x{69D3}\x{69D8}\x{69D9}\x{69DD}\x{69DE}\x{69E7}\x{69E8}\x{69EB}' . +'\x{69ED}\x{69F2}\x{69F9}\x{69FB}\x{69FD}\x{69FF}\x{6A02}\x{6A05}\x{6A0A}' . +'\x{6A0B}\x{6A0C}\x{6A12}\x{6A13}\x{6A14}\x{6A17}\x{6A19}\x{6A1B}\x{6A1E}' . +'\x{6A1F}\x{6A21}\x{6A22}\x{6A23}\x{6A29}\x{6A2A}\x{6A2B}\x{6A2E}\x{6A35}' . +'\x{6A36}\x{6A38}\x{6A39}\x{6A3A}\x{6A3D}\x{6A44}\x{6A47}\x{6A48}\x{6A4B}' . +'\x{6A58}\x{6A59}\x{6A5F}\x{6A61}\x{6A62}\x{6A66}\x{6A72}\x{6A78}\x{6A7F}' . +'\x{6A80}\x{6A84}\x{6A8D}\x{6A8E}\x{6A90}\x{6A97}\x{6A9C}\x{6AA0}\x{6AA2}' . +'\x{6AA3}\x{6AAA}\x{6AAC}\x{6AAE}\x{6AB3}\x{6AB8}\x{6ABB}\x{6AC1}\x{6AC2}' . +'\x{6AC3}\x{6AD1}\x{6AD3}\x{6ADA}\x{6ADB}\x{6ADE}\x{6ADF}\x{6AE8}\x{6AEA}' . +'\x{6AFA}\x{6AFB}\x{6B04}\x{6B05}\x{6B0A}\x{6B12}\x{6B16}\x{6B1D}\x{6B1F}' . +'\x{6B20}\x{6B21}\x{6B23}\x{6B27}\x{6B32}\x{6B37}\x{6B38}\x{6B39}\x{6B3A}' . +'\x{6B3D}\x{6B3E}\x{6B43}\x{6B47}\x{6B49}\x{6B4C}\x{6B4E}\x{6B50}\x{6B53}' . +'\x{6B54}\x{6B59}\x{6B5B}\x{6B5F}\x{6B61}\x{6B62}\x{6B63}\x{6B64}\x{6B66}' . +'\x{6B69}\x{6B6A}\x{6B6F}\x{6B73}\x{6B74}\x{6B78}\x{6B79}\x{6B7B}\x{6B7F}' . +'\x{6B80}\x{6B83}\x{6B84}\x{6B86}\x{6B89}\x{6B8A}\x{6B8B}\x{6B8D}\x{6B95}' . +'\x{6B96}\x{6B98}\x{6B9E}\x{6BA4}\x{6BAA}\x{6BAB}\x{6BAF}\x{6BB1}\x{6BB2}' . +'\x{6BB3}\x{6BB4}\x{6BB5}\x{6BB7}\x{6BBA}\x{6BBB}\x{6BBC}\x{6BBF}\x{6BC0}' . +'\x{6BC5}\x{6BC6}\x{6BCB}\x{6BCD}\x{6BCE}\x{6BD2}\x{6BD3}\x{6BD4}\x{6BD8}' . +'\x{6BDB}\x{6BDF}\x{6BEB}\x{6BEC}\x{6BEF}\x{6BF3}\x{6C08}\x{6C0F}\x{6C11}' . +'\x{6C13}\x{6C14}\x{6C17}\x{6C1B}\x{6C23}\x{6C24}\x{6C34}\x{6C37}\x{6C38}' . +'\x{6C3E}\x{6C40}\x{6C41}\x{6C42}\x{6C4E}\x{6C50}\x{6C55}\x{6C57}\x{6C5A}' . +'\x{6C5D}\x{6C5E}\x{6C5F}\x{6C60}\x{6C62}\x{6C68}\x{6C6A}\x{6C70}\x{6C72}' . +'\x{6C73}\x{6C7A}\x{6C7D}\x{6C7E}\x{6C81}\x{6C82}\x{6C83}\x{6C88}\x{6C8C}' . +'\x{6C8D}\x{6C90}\x{6C92}\x{6C93}\x{6C96}\x{6C99}\x{6C9A}\x{6C9B}\x{6CA1}' . +'\x{6CA2}\x{6CAB}\x{6CAE}\x{6CB1}\x{6CB3}\x{6CB8}\x{6CB9}\x{6CBA}\x{6CBB}' . +'\x{6CBC}\x{6CBD}\x{6CBE}\x{6CBF}\x{6CC1}\x{6CC4}\x{6CC5}\x{6CC9}\x{6CCA}' . +'\x{6CCC}\x{6CD3}\x{6CD5}\x{6CD7}\x{6CD9}\x{6CDB}\x{6CDD}\x{6CE1}\x{6CE2}' . +'\x{6CE3}\x{6CE5}\x{6CE8}\x{6CEA}\x{6CEF}\x{6CF0}\x{6CF1}\x{6CF3}\x{6D0B}' . +'\x{6D0C}\x{6D12}\x{6D17}\x{6D19}\x{6D1B}\x{6D1E}\x{6D1F}\x{6D25}\x{6D29}' . +'\x{6D2A}\x{6D2B}\x{6D32}\x{6D33}\x{6D35}\x{6D36}\x{6D38}\x{6D3B}\x{6D3D}' . +'\x{6D3E}\x{6D41}\x{6D44}\x{6D45}\x{6D59}\x{6D5A}\x{6D5C}\x{6D63}\x{6D64}' . +'\x{6D66}\x{6D69}\x{6D6A}\x{6D6C}\x{6D6E}\x{6D74}\x{6D77}\x{6D78}\x{6D79}' . +'\x{6D85}\x{6D88}\x{6D8C}\x{6D8E}\x{6D93}\x{6D95}\x{6D99}\x{6D9B}\x{6D9C}' . +'\x{6DAF}\x{6DB2}\x{6DB5}\x{6DB8}\x{6DBC}\x{6DC0}\x{6DC5}\x{6DC6}\x{6DC7}' . +'\x{6DCB}\x{6DCC}\x{6DD1}\x{6DD2}\x{6DD5}\x{6DD8}\x{6DD9}\x{6DDE}\x{6DE1}' . +'\x{6DE4}\x{6DE6}\x{6DE8}\x{6DEA}\x{6DEB}\x{6DEC}\x{6DEE}\x{6DF1}\x{6DF3}' . +'\x{6DF5}\x{6DF7}\x{6DF9}\x{6DFA}\x{6DFB}\x{6E05}\x{6E07}\x{6E08}\x{6E09}' . +'\x{6E0A}\x{6E0B}\x{6E13}\x{6E15}\x{6E19}\x{6E1A}\x{6E1B}\x{6E1D}\x{6E1F}' . +'\x{6E20}\x{6E21}\x{6E23}\x{6E24}\x{6E25}\x{6E26}\x{6E29}\x{6E2B}\x{6E2C}' . +'\x{6E2D}\x{6E2E}\x{6E2F}\x{6E38}\x{6E3A}\x{6E3E}\x{6E43}\x{6E4A}\x{6E4D}' . +'\x{6E4E}\x{6E56}\x{6E58}\x{6E5B}\x{6E5F}\x{6E67}\x{6E6B}\x{6E6E}\x{6E6F}' . +'\x{6E72}\x{6E76}\x{6E7E}\x{6E7F}\x{6E80}\x{6E82}\x{6E8C}\x{6E8F}\x{6E90}' . +'\x{6E96}\x{6E98}\x{6E9C}\x{6E9D}\x{6E9F}\x{6EA2}\x{6EA5}\x{6EAA}\x{6EAF}' . +'\x{6EB2}\x{6EB6}\x{6EB7}\x{6EBA}\x{6EBD}\x{6EC2}\x{6EC4}\x{6EC5}\x{6EC9}' . +'\x{6ECB}\x{6ECC}\x{6ED1}\x{6ED3}\x{6ED4}\x{6ED5}\x{6EDD}\x{6EDE}\x{6EEC}' . +'\x{6EEF}\x{6EF2}\x{6EF4}\x{6EF7}\x{6EF8}\x{6EFE}\x{6EFF}\x{6F01}\x{6F02}' . +'\x{6F06}\x{6F09}\x{6F0F}\x{6F11}\x{6F13}\x{6F14}\x{6F15}\x{6F20}\x{6F22}' . +'\x{6F23}\x{6F2B}\x{6F2C}\x{6F31}\x{6F32}\x{6F38}\x{6F3E}\x{6F3F}\x{6F41}' . +'\x{6F45}\x{6F54}\x{6F58}\x{6F5B}\x{6F5C}\x{6F5F}\x{6F64}\x{6F66}\x{6F6D}' . +'\x{6F6E}\x{6F6F}\x{6F70}\x{6F74}\x{6F78}\x{6F7A}\x{6F7C}\x{6F80}\x{6F81}' . +'\x{6F82}\x{6F84}\x{6F86}\x{6F8E}\x{6F91}\x{6F97}\x{6FA1}\x{6FA3}\x{6FA4}' . +'\x{6FAA}\x{6FB1}\x{6FB3}\x{6FB9}\x{6FC0}\x{6FC1}\x{6FC2}\x{6FC3}\x{6FC6}' . +'\x{6FD4}\x{6FD5}\x{6FD8}\x{6FDB}\x{6FDF}\x{6FE0}\x{6FE1}\x{6FE4}\x{6FEB}' . +'\x{6FEC}\x{6FEE}\x{6FEF}\x{6FF1}\x{6FF3}\x{6FF6}\x{6FFA}\x{6FFE}\x{7001}' . +'\x{7009}\x{700B}\x{700F}\x{7011}\x{7015}\x{7018}\x{701A}\x{701B}\x{701D}' . +'\x{701E}\x{701F}\x{7026}\x{7027}\x{702C}\x{7030}\x{7032}\x{703E}\x{704C}' . +'\x{7051}\x{7058}\x{7063}\x{706B}\x{706F}\x{7070}\x{7078}\x{707C}\x{707D}' . +'\x{7089}\x{708A}\x{708E}\x{7092}\x{7099}\x{70AC}\x{70AD}\x{70AE}\x{70AF}' . +'\x{70B3}\x{70B8}\x{70B9}\x{70BA}\x{70C8}\x{70CB}\x{70CF}\x{70D9}\x{70DD}' . +'\x{70DF}\x{70F1}\x{70F9}\x{70FD}\x{7109}\x{7114}\x{7119}\x{711A}\x{711C}' . +'\x{7121}\x{7126}\x{7136}\x{713C}\x{7149}\x{714C}\x{714E}\x{7155}\x{7156}' . +'\x{7159}\x{7162}\x{7164}\x{7165}\x{7166}\x{7167}\x{7169}\x{716C}\x{716E}' . +'\x{717D}\x{7184}\x{7188}\x{718A}\x{718F}\x{7194}\x{7195}\x{7199}\x{719F}' . +'\x{71A8}\x{71AC}\x{71B1}\x{71B9}\x{71BE}\x{71C3}\x{71C8}\x{71C9}\x{71CE}' . +'\x{71D0}\x{71D2}\x{71D4}\x{71D5}\x{71D7}\x{71DF}\x{71E0}\x{71E5}\x{71E6}' . +'\x{71E7}\x{71EC}\x{71ED}\x{71EE}\x{71F5}\x{71F9}\x{71FB}\x{71FC}\x{71FF}' . +'\x{7206}\x{720D}\x{7210}\x{721B}\x{7228}\x{722A}\x{722C}\x{722D}\x{7230}' . +'\x{7232}\x{7235}\x{7236}\x{723A}\x{723B}\x{723C}\x{723D}\x{723E}\x{723F}' . +'\x{7240}\x{7246}\x{7247}\x{7248}\x{724B}\x{724C}\x{7252}\x{7258}\x{7259}' . +'\x{725B}\x{725D}\x{725F}\x{7261}\x{7262}\x{7267}\x{7269}\x{7272}\x{7274}' . +'\x{7279}\x{727D}\x{727E}\x{7280}\x{7281}\x{7282}\x{7287}\x{7292}\x{7296}' . +'\x{72A0}\x{72A2}\x{72A7}\x{72AC}\x{72AF}\x{72B2}\x{72B6}\x{72B9}\x{72C2}' . +'\x{72C3}\x{72C4}\x{72C6}\x{72CE}\x{72D0}\x{72D2}\x{72D7}\x{72D9}\x{72DB}' . +'\x{72E0}\x{72E1}\x{72E2}\x{72E9}\x{72EC}\x{72ED}\x{72F7}\x{72F8}\x{72F9}' . +'\x{72FC}\x{72FD}\x{730A}\x{7316}\x{7317}\x{731B}\x{731C}\x{731D}\x{731F}' . +'\x{7325}\x{7329}\x{732A}\x{732B}\x{732E}\x{732F}\x{7334}\x{7336}\x{7337}' . +'\x{733E}\x{733F}\x{7344}\x{7345}\x{734E}\x{734F}\x{7357}\x{7363}\x{7368}' . +'\x{736A}\x{7370}\x{7372}\x{7375}\x{7378}\x{737A}\x{737B}\x{7384}\x{7387}' . +'\x{7389}\x{738B}\x{7396}\x{73A9}\x{73B2}\x{73B3}\x{73BB}\x{73C0}\x{73C2}' . +'\x{73C8}\x{73CA}\x{73CD}\x{73CE}\x{73DE}\x{73E0}\x{73E5}\x{73EA}\x{73ED}' . +'\x{73EE}\x{73F1}\x{73F8}\x{73FE}\x{7403}\x{7405}\x{7406}\x{7409}\x{7422}' . +'\x{7425}\x{7432}\x{7433}\x{7434}\x{7435}\x{7436}\x{743A}\x{743F}\x{7441}' . +'\x{7455}\x{7459}\x{745A}\x{745B}\x{745C}\x{745E}\x{745F}\x{7460}\x{7463}' . +'\x{7464}\x{7469}\x{746A}\x{746F}\x{7470}\x{7473}\x{7476}\x{747E}\x{7483}' . +'\x{748B}\x{749E}\x{74A2}\x{74A7}\x{74B0}\x{74BD}\x{74CA}\x{74CF}\x{74D4}' . +'\x{74DC}\x{74E0}\x{74E2}\x{74E3}\x{74E6}\x{74E7}\x{74E9}\x{74EE}\x{74F0}' . +'\x{74F1}\x{74F2}\x{74F6}\x{74F7}\x{74F8}\x{7503}\x{7504}\x{7505}\x{750C}' . +'\x{750D}\x{750E}\x{7511}\x{7513}\x{7515}\x{7518}\x{751A}\x{751C}\x{751E}' . +'\x{751F}\x{7523}\x{7525}\x{7526}\x{7528}\x{752B}\x{752C}\x{7530}\x{7531}' . +'\x{7532}\x{7533}\x{7537}\x{7538}\x{753A}\x{753B}\x{753C}\x{7544}\x{7546}' . +'\x{7549}\x{754A}\x{754B}\x{754C}\x{754D}\x{754F}\x{7551}\x{7554}\x{7559}' . +'\x{755A}\x{755B}\x{755C}\x{755D}\x{7560}\x{7562}\x{7564}\x{7565}\x{7566}' . +'\x{7567}\x{7569}\x{756A}\x{756B}\x{756D}\x{7570}\x{7573}\x{7574}\x{7576}' . +'\x{7577}\x{7578}\x{757F}\x{7582}\x{7586}\x{7587}\x{7589}\x{758A}\x{758B}' . +'\x{758E}\x{758F}\x{7591}\x{7594}\x{759A}\x{759D}\x{75A3}\x{75A5}\x{75AB}' . +'\x{75B1}\x{75B2}\x{75B3}\x{75B5}\x{75B8}\x{75B9}\x{75BC}\x{75BD}\x{75BE}' . +'\x{75C2}\x{75C3}\x{75C5}\x{75C7}\x{75CA}\x{75CD}\x{75D2}\x{75D4}\x{75D5}' . +'\x{75D8}\x{75D9}\x{75DB}\x{75DE}\x{75E2}\x{75E3}\x{75E9}\x{75F0}\x{75F2}' . +'\x{75F3}\x{75F4}\x{75FA}\x{75FC}\x{75FE}\x{75FF}\x{7601}\x{7609}\x{760B}' . +'\x{760D}\x{761F}\x{7620}\x{7621}\x{7622}\x{7624}\x{7627}\x{7630}\x{7634}' . +'\x{763B}\x{7642}\x{7646}\x{7647}\x{7648}\x{764C}\x{7652}\x{7656}\x{7658}' . +'\x{765C}\x{7661}\x{7662}\x{7667}\x{7668}\x{7669}\x{766A}\x{766C}\x{7670}' . +'\x{7672}\x{7676}\x{7678}\x{767A}\x{767B}\x{767C}\x{767D}\x{767E}\x{7680}' . +'\x{7683}\x{7684}\x{7686}\x{7687}\x{7688}\x{768B}\x{768E}\x{7690}\x{7693}' . +'\x{7696}\x{7699}\x{769A}\x{76AE}\x{76B0}\x{76B4}\x{76B7}\x{76B8}\x{76B9}' . +'\x{76BA}\x{76BF}\x{76C2}\x{76C3}\x{76C6}\x{76C8}\x{76CA}\x{76CD}\x{76D2}' . +'\x{76D6}\x{76D7}\x{76DB}\x{76DC}\x{76DE}\x{76DF}\x{76E1}\x{76E3}\x{76E4}' . +'\x{76E5}\x{76E7}\x{76EA}\x{76EE}\x{76F2}\x{76F4}\x{76F8}\x{76FB}\x{76FE}' . +'\x{7701}\x{7704}\x{7707}\x{7708}\x{7709}\x{770B}\x{770C}\x{771B}\x{771E}' . +'\x{771F}\x{7720}\x{7724}\x{7725}\x{7726}\x{7729}\x{7737}\x{7738}\x{773A}' . +'\x{773C}\x{7740}\x{7747}\x{775A}\x{775B}\x{7761}\x{7763}\x{7765}\x{7766}' . +'\x{7768}\x{776B}\x{7779}\x{777E}\x{777F}\x{778B}\x{778E}\x{7791}\x{779E}' . +'\x{77A0}\x{77A5}\x{77AC}\x{77AD}\x{77B0}\x{77B3}\x{77B6}\x{77B9}\x{77BB}' . +'\x{77BC}\x{77BD}\x{77BF}\x{77C7}\x{77CD}\x{77D7}\x{77DA}\x{77DB}\x{77DC}' . +'\x{77E2}\x{77E3}\x{77E5}\x{77E7}\x{77E9}\x{77ED}\x{77EE}\x{77EF}\x{77F3}' . +'\x{77FC}\x{7802}\x{780C}\x{7812}\x{7814}\x{7815}\x{7820}\x{7825}\x{7826}' . +'\x{7827}\x{7832}\x{7834}\x{783A}\x{783F}\x{7845}\x{785D}\x{786B}\x{786C}' . +'\x{786F}\x{7872}\x{7874}\x{787C}\x{7881}\x{7886}\x{7887}\x{788C}\x{788D}' . +'\x{788E}\x{7891}\x{7893}\x{7895}\x{7897}\x{789A}\x{78A3}\x{78A7}\x{78A9}' . +'\x{78AA}\x{78AF}\x{78B5}\x{78BA}\x{78BC}\x{78BE}\x{78C1}\x{78C5}\x{78C6}' . +'\x{78CA}\x{78CB}\x{78D0}\x{78D1}\x{78D4}\x{78DA}\x{78E7}\x{78E8}\x{78EC}' . +'\x{78EF}\x{78F4}\x{78FD}\x{7901}\x{7907}\x{790E}\x{7911}\x{7912}\x{7919}' . +'\x{7926}\x{792A}\x{792B}\x{792C}\x{793A}\x{793C}\x{793E}\x{7940}\x{7941}' . +'\x{7947}\x{7948}\x{7949}\x{7950}\x{7953}\x{7955}\x{7956}\x{7957}\x{795A}' . +'\x{795D}\x{795E}\x{795F}\x{7960}\x{7962}\x{7965}\x{7968}\x{796D}\x{7977}' . +'\x{797A}\x{797F}\x{7980}\x{7981}\x{7984}\x{7985}\x{798A}\x{798D}\x{798E}' . +'\x{798F}\x{799D}\x{79A6}\x{79A7}\x{79AA}\x{79AE}\x{79B0}\x{79B3}\x{79B9}' . +'\x{79BA}\x{79BD}\x{79BE}\x{79BF}\x{79C0}\x{79C1}\x{79C9}\x{79CB}\x{79D1}' . +'\x{79D2}\x{79D5}\x{79D8}\x{79DF}\x{79E1}\x{79E3}\x{79E4}\x{79E6}\x{79E7}' . +'\x{79E9}\x{79EC}\x{79F0}\x{79FB}\x{7A00}\x{7A08}\x{7A0B}\x{7A0D}\x{7A0E}' . +'\x{7A14}\x{7A17}\x{7A18}\x{7A19}\x{7A1A}\x{7A1C}\x{7A1F}\x{7A20}\x{7A2E}' . +'\x{7A31}\x{7A32}\x{7A37}\x{7A3B}\x{7A3C}\x{7A3D}\x{7A3E}\x{7A3F}\x{7A40}' . +'\x{7A42}\x{7A43}\x{7A46}\x{7A49}\x{7A4D}\x{7A4E}\x{7A4F}\x{7A50}\x{7A57}' . +'\x{7A61}\x{7A62}\x{7A63}\x{7A69}\x{7A6B}\x{7A70}\x{7A74}\x{7A76}\x{7A79}' . +'\x{7A7A}\x{7A7D}\x{7A7F}\x{7A81}\x{7A83}\x{7A84}\x{7A88}\x{7A92}\x{7A93}' . +'\x{7A95}\x{7A96}\x{7A97}\x{7A98}\x{7A9F}\x{7AA9}\x{7AAA}\x{7AAE}\x{7AAF}' . +'\x{7AB0}\x{7AB6}\x{7ABA}\x{7ABF}\x{7AC3}\x{7AC4}\x{7AC5}\x{7AC7}\x{7AC8}' . +'\x{7ACA}\x{7ACB}\x{7ACD}\x{7ACF}\x{7AD2}\x{7AD3}\x{7AD5}\x{7AD9}\x{7ADA}' . +'\x{7ADC}\x{7ADD}\x{7ADF}\x{7AE0}\x{7AE1}\x{7AE2}\x{7AE3}\x{7AE5}\x{7AE6}' . +'\x{7AEA}\x{7AED}\x{7AEF}\x{7AF0}\x{7AF6}\x{7AF8}\x{7AF9}\x{7AFA}\x{7AFF}' . +'\x{7B02}\x{7B04}\x{7B06}\x{7B08}\x{7B0A}\x{7B0B}\x{7B0F}\x{7B11}\x{7B18}' . +'\x{7B19}\x{7B1B}\x{7B1E}\x{7B20}\x{7B25}\x{7B26}\x{7B28}\x{7B2C}\x{7B33}' . +'\x{7B35}\x{7B36}\x{7B39}\x{7B45}\x{7B46}\x{7B48}\x{7B49}\x{7B4B}\x{7B4C}' . +'\x{7B4D}\x{7B4F}\x{7B50}\x{7B51}\x{7B52}\x{7B54}\x{7B56}\x{7B5D}\x{7B65}' . +'\x{7B67}\x{7B6C}\x{7B6E}\x{7B70}\x{7B71}\x{7B74}\x{7B75}\x{7B7A}\x{7B86}' . +'\x{7B87}\x{7B8B}\x{7B8D}\x{7B8F}\x{7B92}\x{7B94}\x{7B95}\x{7B97}\x{7B98}' . +'\x{7B99}\x{7B9A}\x{7B9C}\x{7B9D}\x{7B9F}\x{7BA1}\x{7BAA}\x{7BAD}\x{7BB1}' . +'\x{7BB4}\x{7BB8}\x{7BC0}\x{7BC1}\x{7BC4}\x{7BC6}\x{7BC7}\x{7BC9}\x{7BCB}' . +'\x{7BCC}\x{7BCF}\x{7BDD}\x{7BE0}\x{7BE4}\x{7BE5}\x{7BE6}\x{7BE9}\x{7BED}' . +'\x{7BF3}\x{7BF6}\x{7BF7}\x{7C00}\x{7C07}\x{7C0D}\x{7C11}\x{7C12}\x{7C13}' . +'\x{7C14}\x{7C17}\x{7C1F}\x{7C21}\x{7C23}\x{7C27}\x{7C2A}\x{7C2B}\x{7C37}' . +'\x{7C38}\x{7C3D}\x{7C3E}\x{7C3F}\x{7C40}\x{7C43}\x{7C4C}\x{7C4D}\x{7C4F}' . +'\x{7C50}\x{7C54}\x{7C56}\x{7C58}\x{7C5F}\x{7C60}\x{7C64}\x{7C65}\x{7C6C}' . +'\x{7C73}\x{7C75}\x{7C7E}\x{7C81}\x{7C82}\x{7C83}\x{7C89}\x{7C8B}\x{7C8D}' . +'\x{7C90}\x{7C92}\x{7C95}\x{7C97}\x{7C98}\x{7C9B}\x{7C9F}\x{7CA1}\x{7CA2}' . +'\x{7CA4}\x{7CA5}\x{7CA7}\x{7CA8}\x{7CAB}\x{7CAD}\x{7CAE}\x{7CB1}\x{7CB2}' . +'\x{7CB3}\x{7CB9}\x{7CBD}\x{7CBE}\x{7CC0}\x{7CC2}\x{7CC5}\x{7CCA}\x{7CCE}' . +'\x{7CD2}\x{7CD6}\x{7CD8}\x{7CDC}\x{7CDE}\x{7CDF}\x{7CE0}\x{7CE2}\x{7CE7}' . +'\x{7CEF}\x{7CF2}\x{7CF4}\x{7CF6}\x{7CF8}\x{7CFA}\x{7CFB}\x{7CFE}\x{7D00}' . +'\x{7D02}\x{7D04}\x{7D05}\x{7D06}\x{7D0A}\x{7D0B}\x{7D0D}\x{7D10}\x{7D14}' . +'\x{7D15}\x{7D17}\x{7D18}\x{7D19}\x{7D1A}\x{7D1B}\x{7D1C}\x{7D20}\x{7D21}' . +'\x{7D22}\x{7D2B}\x{7D2C}\x{7D2E}\x{7D2F}\x{7D30}\x{7D32}\x{7D33}\x{7D35}' . +'\x{7D39}\x{7D3A}\x{7D3F}\x{7D42}\x{7D43}\x{7D44}\x{7D45}\x{7D46}\x{7D4B}' . +'\x{7D4C}\x{7D4E}\x{7D4F}\x{7D50}\x{7D56}\x{7D5B}\x{7D5E}\x{7D61}\x{7D62}' . +'\x{7D63}\x{7D66}\x{7D68}\x{7D6E}\x{7D71}\x{7D72}\x{7D73}\x{7D75}\x{7D76}' . +'\x{7D79}\x{7D7D}\x{7D89}\x{7D8F}\x{7D93}\x{7D99}\x{7D9A}\x{7D9B}\x{7D9C}' . +'\x{7D9F}\x{7DA2}\x{7DA3}\x{7DAB}\x{7DAC}\x{7DAD}\x{7DAE}\x{7DAF}\x{7DB0}' . +'\x{7DB1}\x{7DB2}\x{7DB4}\x{7DB5}\x{7DB8}\x{7DBA}\x{7DBB}\x{7DBD}\x{7DBE}' . +'\x{7DBF}\x{7DC7}\x{7DCA}\x{7DCB}\x{7DCF}\x{7DD1}\x{7DD2}\x{7DD5}\x{7DD8}' . +'\x{7DDA}\x{7DDC}\x{7DDD}\x{7DDE}\x{7DE0}\x{7DE1}\x{7DE4}\x{7DE8}\x{7DE9}' . +'\x{7DEC}\x{7DEF}\x{7DF2}\x{7DF4}\x{7DFB}\x{7E01}\x{7E04}\x{7E05}\x{7E09}' . +'\x{7E0A}\x{7E0B}\x{7E12}\x{7E1B}\x{7E1E}\x{7E1F}\x{7E21}\x{7E22}\x{7E23}' . +'\x{7E26}\x{7E2B}\x{7E2E}\x{7E31}\x{7E32}\x{7E35}\x{7E37}\x{7E39}\x{7E3A}' . +'\x{7E3B}\x{7E3D}\x{7E3E}\x{7E41}\x{7E43}\x{7E46}\x{7E4A}\x{7E4B}\x{7E4D}' . +'\x{7E54}\x{7E55}\x{7E56}\x{7E59}\x{7E5A}\x{7E5D}\x{7E5E}\x{7E66}\x{7E67}' . +'\x{7E69}\x{7E6A}\x{7E6D}\x{7E70}\x{7E79}\x{7E7B}\x{7E7C}\x{7E7D}\x{7E7F}' . +'\x{7E82}\x{7E83}\x{7E88}\x{7E89}\x{7E8C}\x{7E8E}\x{7E8F}\x{7E90}\x{7E92}' . +'\x{7E93}\x{7E94}\x{7E96}\x{7E9B}\x{7E9C}\x{7F36}\x{7F38}\x{7F3A}\x{7F45}' . +'\x{7F4C}\x{7F4D}\x{7F4E}\x{7F50}\x{7F51}\x{7F54}\x{7F55}\x{7F58}\x{7F5F}' . +'\x{7F60}\x{7F67}\x{7F68}\x{7F69}\x{7F6A}\x{7F6B}\x{7F6E}\x{7F70}\x{7F72}' . +'\x{7F75}\x{7F77}\x{7F78}\x{7F79}\x{7F82}\x{7F83}\x{7F85}\x{7F86}\x{7F87}' . +'\x{7F88}\x{7F8A}\x{7F8C}\x{7F8E}\x{7F94}\x{7F9A}\x{7F9D}\x{7F9E}\x{7FA3}' . +'\x{7FA4}\x{7FA8}\x{7FA9}\x{7FAE}\x{7FAF}\x{7FB2}\x{7FB6}\x{7FB8}\x{7FB9}' . +'\x{7FBD}\x{7FC1}\x{7FC5}\x{7FC6}\x{7FCA}\x{7FCC}\x{7FD2}\x{7FD4}\x{7FD5}' . +'\x{7FE0}\x{7FE1}\x{7FE6}\x{7FE9}\x{7FEB}\x{7FF0}\x{7FF3}\x{7FF9}\x{7FFB}' . +'\x{7FFC}\x{8000}\x{8001}\x{8003}\x{8004}\x{8005}\x{8006}\x{800B}\x{800C}' . +'\x{8010}\x{8012}\x{8015}\x{8017}\x{8018}\x{8019}\x{801C}\x{8021}\x{8028}' . +'\x{8033}\x{8036}\x{803B}\x{803D}\x{803F}\x{8046}\x{804A}\x{8052}\x{8056}' . +'\x{8058}\x{805A}\x{805E}\x{805F}\x{8061}\x{8062}\x{8068}\x{806F}\x{8070}' . +'\x{8072}\x{8073}\x{8074}\x{8076}\x{8077}\x{8079}\x{807D}\x{807E}\x{807F}' . +'\x{8084}\x{8085}\x{8086}\x{8087}\x{8089}\x{808B}\x{808C}\x{8093}\x{8096}' . +'\x{8098}\x{809A}\x{809B}\x{809D}\x{80A1}\x{80A2}\x{80A5}\x{80A9}\x{80AA}' . +'\x{80AC}\x{80AD}\x{80AF}\x{80B1}\x{80B2}\x{80B4}\x{80BA}\x{80C3}\x{80C4}' . +'\x{80C6}\x{80CC}\x{80CE}\x{80D6}\x{80D9}\x{80DA}\x{80DB}\x{80DD}\x{80DE}' . +'\x{80E1}\x{80E4}\x{80E5}\x{80EF}\x{80F1}\x{80F4}\x{80F8}\x{80FC}\x{80FD}' . +'\x{8102}\x{8105}\x{8106}\x{8107}\x{8108}\x{8109}\x{810A}\x{811A}\x{811B}' . +'\x{8123}\x{8129}\x{812F}\x{8131}\x{8133}\x{8139}\x{813E}\x{8146}\x{814B}' . +'\x{814E}\x{8150}\x{8151}\x{8153}\x{8154}\x{8155}\x{815F}\x{8165}\x{8166}' . +'\x{816B}\x{816E}\x{8170}\x{8171}\x{8174}\x{8178}\x{8179}\x{817A}\x{817F}' . +'\x{8180}\x{8182}\x{8183}\x{8188}\x{818A}\x{818F}\x{8193}\x{8195}\x{819A}' . +'\x{819C}\x{819D}\x{81A0}\x{81A3}\x{81A4}\x{81A8}\x{81A9}\x{81B0}\x{81B3}' . +'\x{81B5}\x{81B8}\x{81BA}\x{81BD}\x{81BE}\x{81BF}\x{81C0}\x{81C2}\x{81C6}' . +'\x{81C8}\x{81C9}\x{81CD}\x{81D1}\x{81D3}\x{81D8}\x{81D9}\x{81DA}\x{81DF}' . +'\x{81E0}\x{81E3}\x{81E5}\x{81E7}\x{81E8}\x{81EA}\x{81ED}\x{81F3}\x{81F4}' . +'\x{81FA}\x{81FB}\x{81FC}\x{81FE}\x{8201}\x{8202}\x{8205}\x{8207}\x{8208}' . +'\x{8209}\x{820A}\x{820C}\x{820D}\x{820E}\x{8210}\x{8212}\x{8216}\x{8217}' . +'\x{8218}\x{821B}\x{821C}\x{821E}\x{821F}\x{8229}\x{822A}\x{822B}\x{822C}' . +'\x{822E}\x{8233}\x{8235}\x{8236}\x{8237}\x{8238}\x{8239}\x{8240}\x{8247}' . +'\x{8258}\x{8259}\x{825A}\x{825D}\x{825F}\x{8262}\x{8264}\x{8266}\x{8268}' . +'\x{826A}\x{826B}\x{826E}\x{826F}\x{8271}\x{8272}\x{8276}\x{8277}\x{8278}' . +'\x{827E}\x{828B}\x{828D}\x{8292}\x{8299}\x{829D}\x{829F}\x{82A5}\x{82A6}' . +'\x{82AB}\x{82AC}\x{82AD}\x{82AF}\x{82B1}\x{82B3}\x{82B8}\x{82B9}\x{82BB}' . +'\x{82BD}\x{82C5}\x{82D1}\x{82D2}\x{82D3}\x{82D4}\x{82D7}\x{82D9}\x{82DB}' . +'\x{82DC}\x{82DE}\x{82DF}\x{82E1}\x{82E3}\x{82E5}\x{82E6}\x{82E7}\x{82EB}' . +'\x{82F1}\x{82F3}\x{82F4}\x{82F9}\x{82FA}\x{82FB}\x{8302}\x{8303}\x{8304}' . +'\x{8305}\x{8306}\x{8309}\x{830E}\x{8316}\x{8317}\x{8318}\x{831C}\x{8323}' . +'\x{8328}\x{832B}\x{832F}\x{8331}\x{8332}\x{8334}\x{8335}\x{8336}\x{8338}' . +'\x{8339}\x{8340}\x{8345}\x{8349}\x{834A}\x{834F}\x{8350}\x{8352}\x{8358}' . +'\x{8373}\x{8375}\x{8377}\x{837B}\x{837C}\x{8385}\x{8387}\x{8389}\x{838A}' . +'\x{838E}\x{8393}\x{8396}\x{839A}\x{839E}\x{839F}\x{83A0}\x{83A2}\x{83A8}' . +'\x{83AA}\x{83AB}\x{83B1}\x{83B5}\x{83BD}\x{83C1}\x{83C5}\x{83CA}\x{83CC}' . +'\x{83CE}\x{83D3}\x{83D6}\x{83D8}\x{83DC}\x{83DF}\x{83E0}\x{83E9}\x{83EB}' . +'\x{83EF}\x{83F0}\x{83F1}\x{83F2}\x{83F4}\x{83F7}\x{83FB}\x{83FD}\x{8403}' . +'\x{8404}\x{8407}\x{840B}\x{840C}\x{840D}\x{840E}\x{8413}\x{8420}\x{8422}' . +'\x{8429}\x{842A}\x{842C}\x{8431}\x{8435}\x{8438}\x{843C}\x{843D}\x{8446}' . +'\x{8449}\x{844E}\x{8457}\x{845B}\x{8461}\x{8462}\x{8463}\x{8466}\x{8469}' . +'\x{846B}\x{846C}\x{846D}\x{846E}\x{846F}\x{8471}\x{8475}\x{8477}\x{8479}' . +'\x{847A}\x{8482}\x{8484}\x{848B}\x{8490}\x{8494}\x{8499}\x{849C}\x{849F}' . +'\x{84A1}\x{84AD}\x{84B2}\x{84B8}\x{84B9}\x{84BB}\x{84BC}\x{84BF}\x{84C1}' . +'\x{84C4}\x{84C6}\x{84C9}\x{84CA}\x{84CB}\x{84CD}\x{84D0}\x{84D1}\x{84D6}' . +'\x{84D9}\x{84DA}\x{84EC}\x{84EE}\x{84F4}\x{84FC}\x{84FF}\x{8500}\x{8506}' . +'\x{8511}\x{8513}\x{8514}\x{8515}\x{8517}\x{8518}\x{851A}\x{851F}\x{8521}' . +'\x{8526}\x{852C}\x{852D}\x{8535}\x{853D}\x{8540}\x{8541}\x{8543}\x{8548}' . +'\x{8549}\x{854A}\x{854B}\x{854E}\x{8555}\x{8557}\x{8558}\x{855A}\x{8563}' . +'\x{8568}\x{8569}\x{856A}\x{856D}\x{8577}\x{857E}\x{8580}\x{8584}\x{8587}' . +'\x{8588}\x{858A}\x{8590}\x{8591}\x{8594}\x{8597}\x{8599}\x{859B}\x{859C}' . +'\x{85A4}\x{85A6}\x{85A8}\x{85A9}\x{85AA}\x{85AB}\x{85AC}\x{85AE}\x{85AF}' . +'\x{85B9}\x{85BA}\x{85C1}\x{85C9}\x{85CD}\x{85CF}\x{85D0}\x{85D5}\x{85DC}' . +'\x{85DD}\x{85E4}\x{85E5}\x{85E9}\x{85EA}\x{85F7}\x{85F9}\x{85FA}\x{85FB}' . +'\x{85FE}\x{8602}\x{8606}\x{8607}\x{860A}\x{860B}\x{8613}\x{8616}\x{8617}' . +'\x{861A}\x{8622}\x{862D}\x{862F}\x{8630}\x{863F}\x{864D}\x{864E}\x{8650}' . +'\x{8654}\x{8655}\x{865A}\x{865C}\x{865E}\x{865F}\x{8667}\x{866B}\x{8671}' . +'\x{8679}\x{867B}\x{868A}\x{868B}\x{868C}\x{8693}\x{8695}\x{86A3}\x{86A4}' . +'\x{86A9}\x{86AA}\x{86AB}\x{86AF}\x{86B0}\x{86B6}\x{86C4}\x{86C6}\x{86C7}' . +'\x{86C9}\x{86CB}\x{86CD}\x{86CE}\x{86D4}\x{86D9}\x{86DB}\x{86DE}\x{86DF}' . +'\x{86E4}\x{86E9}\x{86EC}\x{86ED}\x{86EE}\x{86EF}\x{86F8}\x{86F9}\x{86FB}' . +'\x{86FE}\x{8700}\x{8702}\x{8703}\x{8706}\x{8708}\x{8709}\x{870A}\x{870D}' . +'\x{8711}\x{8712}\x{8718}\x{871A}\x{871C}\x{8725}\x{8729}\x{8734}\x{8737}' . +'\x{873B}\x{873F}\x{8749}\x{874B}\x{874C}\x{874E}\x{8753}\x{8755}\x{8757}' . +'\x{8759}\x{875F}\x{8760}\x{8763}\x{8766}\x{8768}\x{876A}\x{876E}\x{8774}' . +'\x{8776}\x{8778}\x{877F}\x{8782}\x{878D}\x{879F}\x{87A2}\x{87AB}\x{87AF}' . +'\x{87B3}\x{87BA}\x{87BB}\x{87BD}\x{87C0}\x{87C4}\x{87C6}\x{87C7}\x{87CB}' . +'\x{87D0}\x{87D2}\x{87E0}\x{87EF}\x{87F2}\x{87F6}\x{87F7}\x{87F9}\x{87FB}' . +'\x{87FE}\x{8805}\x{880D}\x{880E}\x{880F}\x{8811}\x{8815}\x{8816}\x{8821}' . +'\x{8822}\x{8823}\x{8827}\x{8831}\x{8836}\x{8839}\x{883B}\x{8840}\x{8842}' . +'\x{8844}\x{8846}\x{884C}\x{884D}\x{8852}\x{8853}\x{8857}\x{8859}\x{885B}' . +'\x{885D}\x{885E}\x{8861}\x{8862}\x{8863}\x{8868}\x{886B}\x{8870}\x{8872}' . +'\x{8875}\x{8877}\x{887D}\x{887E}\x{887F}\x{8881}\x{8882}\x{8888}\x{888B}' . +'\x{888D}\x{8892}\x{8896}\x{8897}\x{8899}\x{889E}\x{88A2}\x{88A4}\x{88AB}' . +'\x{88AE}\x{88B0}\x{88B1}\x{88B4}\x{88B5}\x{88B7}\x{88BF}\x{88C1}\x{88C2}' . +'\x{88C3}\x{88C4}\x{88C5}\x{88CF}\x{88D4}\x{88D5}\x{88D8}\x{88D9}\x{88DC}' . +'\x{88DD}\x{88DF}\x{88E1}\x{88E8}\x{88F2}\x{88F3}\x{88F4}\x{88F8}\x{88F9}' . +'\x{88FC}\x{88FD}\x{88FE}\x{8902}\x{8904}\x{8907}\x{890A}\x{890C}\x{8910}' . +'\x{8912}\x{8913}\x{891D}\x{891E}\x{8925}\x{892A}\x{892B}\x{8936}\x{8938}' . +'\x{893B}\x{8941}\x{8943}\x{8944}\x{894C}\x{894D}\x{8956}\x{895E}\x{895F}' . +'\x{8960}\x{8964}\x{8966}\x{896A}\x{896D}\x{896F}\x{8972}\x{8974}\x{8977}' . +'\x{897E}\x{897F}\x{8981}\x{8983}\x{8986}\x{8987}\x{8988}\x{898A}\x{898B}' . +'\x{898F}\x{8993}\x{8996}\x{8997}\x{8998}\x{899A}\x{89A1}\x{89A6}\x{89A7}' . +'\x{89A9}\x{89AA}\x{89AC}\x{89AF}\x{89B2}\x{89B3}\x{89BA}\x{89BD}\x{89BF}' . +'\x{89C0}\x{89D2}\x{89DA}\x{89DC}\x{89DD}\x{89E3}\x{89E6}\x{89E7}\x{89F4}' . +'\x{89F8}\x{8A00}\x{8A02}\x{8A03}\x{8A08}\x{8A0A}\x{8A0C}\x{8A0E}\x{8A10}' . +'\x{8A13}\x{8A16}\x{8A17}\x{8A18}\x{8A1B}\x{8A1D}\x{8A1F}\x{8A23}\x{8A25}' . +'\x{8A2A}\x{8A2D}\x{8A31}\x{8A33}\x{8A34}\x{8A36}\x{8A3A}\x{8A3B}\x{8A3C}' . +'\x{8A41}\x{8A46}\x{8A48}\x{8A50}\x{8A51}\x{8A52}\x{8A54}\x{8A55}\x{8A5B}' . +'\x{8A5E}\x{8A60}\x{8A62}\x{8A63}\x{8A66}\x{8A69}\x{8A6B}\x{8A6C}\x{8A6D}' . +'\x{8A6E}\x{8A70}\x{8A71}\x{8A72}\x{8A73}\x{8A7C}\x{8A82}\x{8A84}\x{8A85}' . +'\x{8A87}\x{8A89}\x{8A8C}\x{8A8D}\x{8A91}\x{8A93}\x{8A95}\x{8A98}\x{8A9A}' . +'\x{8A9E}\x{8AA0}\x{8AA1}\x{8AA3}\x{8AA4}\x{8AA5}\x{8AA6}\x{8AA8}\x{8AAC}' . +'\x{8AAD}\x{8AB0}\x{8AB2}\x{8AB9}\x{8ABC}\x{8ABF}\x{8AC2}\x{8AC4}\x{8AC7}' . +'\x{8ACB}\x{8ACC}\x{8ACD}\x{8ACF}\x{8AD2}\x{8AD6}\x{8ADA}\x{8ADB}\x{8ADC}' . +'\x{8ADE}\x{8AE0}\x{8AE1}\x{8AE2}\x{8AE4}\x{8AE6}\x{8AE7}\x{8AEB}\x{8AED}' . +'\x{8AEE}\x{8AF1}\x{8AF3}\x{8AF7}\x{8AF8}\x{8AFA}\x{8AFE}\x{8B00}\x{8B01}' . +'\x{8B02}\x{8B04}\x{8B07}\x{8B0C}\x{8B0E}\x{8B10}\x{8B14}\x{8B16}\x{8B17}' . +'\x{8B19}\x{8B1A}\x{8B1B}\x{8B1D}\x{8B20}\x{8B21}\x{8B26}\x{8B28}\x{8B2B}' . +'\x{8B2C}\x{8B33}\x{8B39}\x{8B3E}\x{8B41}\x{8B49}\x{8B4C}\x{8B4E}\x{8B4F}' . +'\x{8B56}\x{8B58}\x{8B5A}\x{8B5B}\x{8B5C}\x{8B5F}\x{8B66}\x{8B6B}\x{8B6C}' . +'\x{8B6F}\x{8B70}\x{8B71}\x{8B72}\x{8B74}\x{8B77}\x{8B7D}\x{8B80}\x{8B83}' . +'\x{8B8A}\x{8B8C}\x{8B8E}\x{8B90}\x{8B92}\x{8B93}\x{8B96}\x{8B99}\x{8B9A}' . +'\x{8C37}\x{8C3A}\x{8C3F}\x{8C41}\x{8C46}\x{8C48}\x{8C4A}\x{8C4C}\x{8C4E}' . +'\x{8C50}\x{8C55}\x{8C5A}\x{8C61}\x{8C62}\x{8C6A}\x{8C6B}\x{8C6C}\x{8C78}' . +'\x{8C79}\x{8C7A}\x{8C7C}\x{8C82}\x{8C85}\x{8C89}\x{8C8A}\x{8C8C}\x{8C8D}' . +'\x{8C8E}\x{8C94}\x{8C98}\x{8C9D}\x{8C9E}\x{8CA0}\x{8CA1}\x{8CA2}\x{8CA7}' . +'\x{8CA8}\x{8CA9}\x{8CAA}\x{8CAB}\x{8CAC}\x{8CAD}\x{8CAE}\x{8CAF}\x{8CB0}' . +'\x{8CB2}\x{8CB3}\x{8CB4}\x{8CB6}\x{8CB7}\x{8CB8}\x{8CBB}\x{8CBC}\x{8CBD}' . +'\x{8CBF}\x{8CC0}\x{8CC1}\x{8CC2}\x{8CC3}\x{8CC4}\x{8CC7}\x{8CC8}\x{8CCA}' . +'\x{8CCD}\x{8CCE}\x{8CD1}\x{8CD3}\x{8CDA}\x{8CDB}\x{8CDC}\x{8CDE}\x{8CE0}' . +'\x{8CE2}\x{8CE3}\x{8CE4}\x{8CE6}\x{8CEA}\x{8CED}\x{8CFA}\x{8CFB}\x{8CFC}' . +'\x{8CFD}\x{8D04}\x{8D05}\x{8D07}\x{8D08}\x{8D0A}\x{8D0B}\x{8D0D}\x{8D0F}' . +'\x{8D10}\x{8D13}\x{8D14}\x{8D16}\x{8D64}\x{8D66}\x{8D67}\x{8D6B}\x{8D6D}' . +'\x{8D70}\x{8D71}\x{8D73}\x{8D74}\x{8D77}\x{8D81}\x{8D85}\x{8D8A}\x{8D99}' . +'\x{8DA3}\x{8DA8}\x{8DB3}\x{8DBA}\x{8DBE}\x{8DC2}\x{8DCB}\x{8DCC}\x{8DCF}' . +'\x{8DD6}\x{8DDA}\x{8DDB}\x{8DDD}\x{8DDF}\x{8DE1}\x{8DE3}\x{8DE8}\x{8DEA}' . +'\x{8DEB}\x{8DEF}\x{8DF3}\x{8DF5}\x{8DFC}\x{8DFF}\x{8E08}\x{8E09}\x{8E0A}' . +'\x{8E0F}\x{8E10}\x{8E1D}\x{8E1E}\x{8E1F}\x{8E2A}\x{8E30}\x{8E34}\x{8E35}' . +'\x{8E42}\x{8E44}\x{8E47}\x{8E48}\x{8E49}\x{8E4A}\x{8E4C}\x{8E50}\x{8E55}' . +'\x{8E59}\x{8E5F}\x{8E60}\x{8E63}\x{8E64}\x{8E72}\x{8E74}\x{8E76}\x{8E7C}' . +'\x{8E81}\x{8E84}\x{8E85}\x{8E87}\x{8E8A}\x{8E8B}\x{8E8D}\x{8E91}\x{8E93}' . +'\x{8E94}\x{8E99}\x{8EA1}\x{8EAA}\x{8EAB}\x{8EAC}\x{8EAF}\x{8EB0}\x{8EB1}' . +'\x{8EBE}\x{8EC5}\x{8EC6}\x{8EC8}\x{8ECA}\x{8ECB}\x{8ECC}\x{8ECD}\x{8ED2}' . +'\x{8EDB}\x{8EDF}\x{8EE2}\x{8EE3}\x{8EEB}\x{8EF8}\x{8EFB}\x{8EFC}\x{8EFD}' . +'\x{8EFE}\x{8F03}\x{8F05}\x{8F09}\x{8F0A}\x{8F0C}\x{8F12}\x{8F13}\x{8F14}' . +'\x{8F15}\x{8F19}\x{8F1B}\x{8F1C}\x{8F1D}\x{8F1F}\x{8F26}\x{8F29}\x{8F2A}' . +'\x{8F2F}\x{8F33}\x{8F38}\x{8F39}\x{8F3B}\x{8F3E}\x{8F3F}\x{8F42}\x{8F44}' . +'\x{8F45}\x{8F46}\x{8F49}\x{8F4C}\x{8F4D}\x{8F4E}\x{8F57}\x{8F5C}\x{8F5F}' . +'\x{8F61}\x{8F62}\x{8F63}\x{8F64}\x{8F9B}\x{8F9C}\x{8F9E}\x{8F9F}\x{8FA3}' . +'\x{8FA7}\x{8FA8}\x{8FAD}\x{8FAE}\x{8FAF}\x{8FB0}\x{8FB1}\x{8FB2}\x{8FB7}' . +'\x{8FBA}\x{8FBB}\x{8FBC}\x{8FBF}\x{8FC2}\x{8FC4}\x{8FC5}\x{8FCE}\x{8FD1}' . +'\x{8FD4}\x{8FDA}\x{8FE2}\x{8FE5}\x{8FE6}\x{8FE9}\x{8FEA}\x{8FEB}\x{8FED}' . +'\x{8FEF}\x{8FF0}\x{8FF4}\x{8FF7}\x{8FF8}\x{8FF9}\x{8FFA}\x{8FFD}\x{9000}' . +'\x{9001}\x{9003}\x{9005}\x{9006}\x{900B}\x{900D}\x{900E}\x{900F}\x{9010}' . +'\x{9011}\x{9013}\x{9014}\x{9015}\x{9016}\x{9017}\x{9019}\x{901A}\x{901D}' . +'\x{901E}\x{901F}\x{9020}\x{9021}\x{9022}\x{9023}\x{9027}\x{902E}\x{9031}' . +'\x{9032}\x{9035}\x{9036}\x{9038}\x{9039}\x{903C}\x{903E}\x{9041}\x{9042}' . +'\x{9045}\x{9047}\x{9049}\x{904A}\x{904B}\x{904D}\x{904E}\x{904F}\x{9050}' . +'\x{9051}\x{9052}\x{9053}\x{9054}\x{9055}\x{9056}\x{9058}\x{9059}\x{905C}' . +'\x{905E}\x{9060}\x{9061}\x{9063}\x{9065}\x{9068}\x{9069}\x{906D}\x{906E}' . +'\x{906F}\x{9072}\x{9075}\x{9076}\x{9077}\x{9078}\x{907A}\x{907C}\x{907D}' . +'\x{907F}\x{9080}\x{9081}\x{9082}\x{9083}\x{9084}\x{9087}\x{9089}\x{908A}' . +'\x{908F}\x{9091}\x{90A3}\x{90A6}\x{90A8}\x{90AA}\x{90AF}\x{90B1}\x{90B5}' . +'\x{90B8}\x{90C1}\x{90CA}\x{90CE}\x{90DB}\x{90E1}\x{90E2}\x{90E4}\x{90E8}' . +'\x{90ED}\x{90F5}\x{90F7}\x{90FD}\x{9102}\x{9112}\x{9119}\x{912D}\x{9130}' . +'\x{9132}\x{9149}\x{914A}\x{914B}\x{914C}\x{914D}\x{914E}\x{9152}\x{9154}' . +'\x{9156}\x{9158}\x{9162}\x{9163}\x{9165}\x{9169}\x{916A}\x{916C}\x{9172}' . +'\x{9173}\x{9175}\x{9177}\x{9178}\x{9182}\x{9187}\x{9189}\x{918B}\x{918D}' . +'\x{9190}\x{9192}\x{9197}\x{919C}\x{91A2}\x{91A4}\x{91AA}\x{91AB}\x{91AF}' . +'\x{91B4}\x{91B5}\x{91B8}\x{91BA}\x{91C0}\x{91C1}\x{91C6}\x{91C7}\x{91C8}' . +'\x{91C9}\x{91CB}\x{91CC}\x{91CD}\x{91CE}\x{91CF}\x{91D0}\x{91D1}\x{91D6}' . +'\x{91D8}\x{91DB}\x{91DC}\x{91DD}\x{91DF}\x{91E1}\x{91E3}\x{91E6}\x{91E7}' . +'\x{91F5}\x{91F6}\x{91FC}\x{91FF}\x{920D}\x{920E}\x{9211}\x{9214}\x{9215}' . +'\x{921E}\x{9229}\x{922C}\x{9234}\x{9237}\x{923F}\x{9244}\x{9245}\x{9248}' . +'\x{9249}\x{924B}\x{9250}\x{9257}\x{925A}\x{925B}\x{925E}\x{9262}\x{9264}' . +'\x{9266}\x{9271}\x{927E}\x{9280}\x{9283}\x{9285}\x{9291}\x{9293}\x{9295}' . +'\x{9296}\x{9298}\x{929A}\x{929B}\x{929C}\x{92AD}\x{92B7}\x{92B9}\x{92CF}' . +'\x{92D2}\x{92E4}\x{92E9}\x{92EA}\x{92ED}\x{92F2}\x{92F3}\x{92F8}\x{92FA}' . +'\x{92FC}\x{9306}\x{930F}\x{9310}\x{9318}\x{9319}\x{931A}\x{9320}\x{9322}' . +'\x{9323}\x{9326}\x{9328}\x{932B}\x{932C}\x{932E}\x{932F}\x{9332}\x{9335}' . +'\x{933A}\x{933B}\x{9344}\x{934B}\x{934D}\x{9354}\x{9356}\x{935B}\x{935C}' . +'\x{9360}\x{936C}\x{936E}\x{9375}\x{937C}\x{937E}\x{938C}\x{9394}\x{9396}' . +'\x{9397}\x{939A}\x{93A7}\x{93AC}\x{93AD}\x{93AE}\x{93B0}\x{93B9}\x{93C3}' . +'\x{93C8}\x{93D0}\x{93D1}\x{93D6}\x{93D7}\x{93D8}\x{93DD}\x{93E1}\x{93E4}' . +'\x{93E5}\x{93E8}\x{9403}\x{9407}\x{9410}\x{9413}\x{9414}\x{9418}\x{9419}' . +'\x{941A}\x{9421}\x{942B}\x{9435}\x{9436}\x{9438}\x{943A}\x{9441}\x{9444}' . +'\x{9451}\x{9452}\x{9453}\x{945A}\x{945B}\x{945E}\x{9460}\x{9462}\x{946A}' . +'\x{9470}\x{9475}\x{9477}\x{947C}\x{947D}\x{947E}\x{947F}\x{9481}\x{9577}' . +'\x{9580}\x{9582}\x{9583}\x{9587}\x{9589}\x{958A}\x{958B}\x{958F}\x{9591}' . +'\x{9593}\x{9594}\x{9596}\x{9598}\x{9599}\x{95A0}\x{95A2}\x{95A3}\x{95A4}' . +'\x{95A5}\x{95A7}\x{95A8}\x{95AD}\x{95B2}\x{95B9}\x{95BB}\x{95BC}\x{95BE}' . +'\x{95C3}\x{95C7}\x{95CA}\x{95CC}\x{95CD}\x{95D4}\x{95D5}\x{95D6}\x{95D8}' . +'\x{95DC}\x{95E1}\x{95E2}\x{95E5}\x{961C}\x{9621}\x{9628}\x{962A}\x{962E}' . +'\x{962F}\x{9632}\x{963B}\x{963F}\x{9640}\x{9642}\x{9644}\x{964B}\x{964C}' . +'\x{964D}\x{964F}\x{9650}\x{965B}\x{965C}\x{965D}\x{965E}\x{965F}\x{9662}' . +'\x{9663}\x{9664}\x{9665}\x{9666}\x{966A}\x{966C}\x{9670}\x{9672}\x{9673}' . +'\x{9675}\x{9676}\x{9677}\x{9678}\x{967A}\x{967D}\x{9685}\x{9686}\x{9688}' . +'\x{968A}\x{968B}\x{968D}\x{968E}\x{968F}\x{9694}\x{9695}\x{9697}\x{9698}' . +'\x{9699}\x{969B}\x{969C}\x{96A0}\x{96A3}\x{96A7}\x{96A8}\x{96AA}\x{96B0}' . +'\x{96B1}\x{96B2}\x{96B4}\x{96B6}\x{96B7}\x{96B8}\x{96B9}\x{96BB}\x{96BC}' . +'\x{96C0}\x{96C1}\x{96C4}\x{96C5}\x{96C6}\x{96C7}\x{96C9}\x{96CB}\x{96CC}' . +'\x{96CD}\x{96CE}\x{96D1}\x{96D5}\x{96D6}\x{96D9}\x{96DB}\x{96DC}\x{96E2}' . +'\x{96E3}\x{96E8}\x{96EA}\x{96EB}\x{96F0}\x{96F2}\x{96F6}\x{96F7}\x{96F9}' . +'\x{96FB}\x{9700}\x{9704}\x{9706}\x{9707}\x{9708}\x{970A}\x{970D}\x{970E}' . +'\x{970F}\x{9711}\x{9713}\x{9716}\x{9719}\x{971C}\x{971E}\x{9724}\x{9727}' . +'\x{972A}\x{9730}\x{9732}\x{9738}\x{9739}\x{973D}\x{973E}\x{9742}\x{9744}' . +'\x{9746}\x{9748}\x{9749}\x{9752}\x{9756}\x{9759}\x{975C}\x{975E}\x{9760}' . +'\x{9761}\x{9762}\x{9764}\x{9766}\x{9768}\x{9769}\x{976B}\x{976D}\x{9771}' . +'\x{9774}\x{9779}\x{977A}\x{977C}\x{9781}\x{9784}\x{9785}\x{9786}\x{978B}' . +'\x{978D}\x{978F}\x{9790}\x{9798}\x{979C}\x{97A0}\x{97A3}\x{97A6}\x{97A8}' . +'\x{97AB}\x{97AD}\x{97B3}\x{97B4}\x{97C3}\x{97C6}\x{97C8}\x{97CB}\x{97D3}' . +'\x{97DC}\x{97ED}\x{97EE}\x{97F2}\x{97F3}\x{97F5}\x{97F6}\x{97FB}\x{97FF}' . +'\x{9801}\x{9802}\x{9803}\x{9805}\x{9806}\x{9808}\x{980C}\x{980F}\x{9810}' . +'\x{9811}\x{9812}\x{9813}\x{9817}\x{9818}\x{981A}\x{9821}\x{9824}\x{982C}' . +'\x{982D}\x{9834}\x{9837}\x{9838}\x{983B}\x{983C}\x{983D}\x{9846}\x{984B}' . +'\x{984C}\x{984D}\x{984E}\x{984F}\x{9854}\x{9855}\x{9858}\x{985B}\x{985E}' . +'\x{9867}\x{986B}\x{986F}\x{9870}\x{9871}\x{9873}\x{9874}\x{98A8}\x{98AA}' . +'\x{98AF}\x{98B1}\x{98B6}\x{98C3}\x{98C4}\x{98C6}\x{98DB}\x{98DC}\x{98DF}' . +'\x{98E2}\x{98E9}\x{98EB}\x{98ED}\x{98EE}\x{98EF}\x{98F2}\x{98F4}\x{98FC}' . +'\x{98FD}\x{98FE}\x{9903}\x{9905}\x{9909}\x{990A}\x{990C}\x{9910}\x{9912}' . +'\x{9913}\x{9914}\x{9918}\x{991D}\x{991E}\x{9920}\x{9921}\x{9924}\x{9928}' . +'\x{992C}\x{992E}\x{993D}\x{993E}\x{9942}\x{9945}\x{9949}\x{994B}\x{994C}' . +'\x{9950}\x{9951}\x{9952}\x{9955}\x{9957}\x{9996}\x{9997}\x{9998}\x{9999}' . +'\x{99A5}\x{99A8}\x{99AC}\x{99AD}\x{99AE}\x{99B3}\x{99B4}\x{99BC}\x{99C1}' . +'\x{99C4}\x{99C5}\x{99C6}\x{99C8}\x{99D0}\x{99D1}\x{99D2}\x{99D5}\x{99D8}' . +'\x{99DB}\x{99DD}\x{99DF}\x{99E2}\x{99ED}\x{99EE}\x{99F1}\x{99F2}\x{99F8}' . +'\x{99FB}\x{99FF}\x{9A01}\x{9A05}\x{9A0E}\x{9A0F}\x{9A12}\x{9A13}\x{9A19}' . +'\x{9A28}\x{9A2B}\x{9A30}\x{9A37}\x{9A3E}\x{9A40}\x{9A42}\x{9A43}\x{9A45}' . +'\x{9A4D}\x{9A55}\x{9A57}\x{9A5A}\x{9A5B}\x{9A5F}\x{9A62}\x{9A64}\x{9A65}' . +'\x{9A69}\x{9A6A}\x{9A6B}\x{9AA8}\x{9AAD}\x{9AB0}\x{9AB8}\x{9ABC}\x{9AC0}' . +'\x{9AC4}\x{9ACF}\x{9AD1}\x{9AD3}\x{9AD4}\x{9AD8}\x{9ADE}\x{9ADF}\x{9AE2}' . +'\x{9AE3}\x{9AE6}\x{9AEA}\x{9AEB}\x{9AED}\x{9AEE}\x{9AEF}\x{9AF1}\x{9AF4}' . +'\x{9AF7}\x{9AFB}\x{9B06}\x{9B18}\x{9B1A}\x{9B1F}\x{9B22}\x{9B23}\x{9B25}' . +'\x{9B27}\x{9B28}\x{9B29}\x{9B2A}\x{9B2E}\x{9B2F}\x{9B31}\x{9B32}\x{9B3B}' . +'\x{9B3C}\x{9B41}\x{9B42}\x{9B43}\x{9B44}\x{9B45}\x{9B4D}\x{9B4E}\x{9B4F}' . +'\x{9B51}\x{9B54}\x{9B58}\x{9B5A}\x{9B6F}\x{9B74}\x{9B83}\x{9B8E}\x{9B91}' . +'\x{9B92}\x{9B93}\x{9B96}\x{9B97}\x{9B9F}\x{9BA0}\x{9BA8}\x{9BAA}\x{9BAB}' . +'\x{9BAD}\x{9BAE}\x{9BB4}\x{9BB9}\x{9BC0}\x{9BC6}\x{9BC9}\x{9BCA}\x{9BCF}' . +'\x{9BD1}\x{9BD2}\x{9BD4}\x{9BD6}\x{9BDB}\x{9BE1}\x{9BE2}\x{9BE3}\x{9BE4}' . +'\x{9BE8}\x{9BF0}\x{9BF1}\x{9BF2}\x{9BF5}\x{9C04}\x{9C06}\x{9C08}\x{9C09}' . +'\x{9C0A}\x{9C0C}\x{9C0D}\x{9C10}\x{9C12}\x{9C13}\x{9C14}\x{9C15}\x{9C1B}' . +'\x{9C21}\x{9C24}\x{9C25}\x{9C2D}\x{9C2E}\x{9C2F}\x{9C30}\x{9C32}\x{9C39}' . +'\x{9C3A}\x{9C3B}\x{9C3E}\x{9C46}\x{9C47}\x{9C48}\x{9C52}\x{9C57}\x{9C5A}' . +'\x{9C60}\x{9C67}\x{9C76}\x{9C78}\x{9CE5}\x{9CE7}\x{9CE9}\x{9CEB}\x{9CEC}' . +'\x{9CF0}\x{9CF3}\x{9CF4}\x{9CF6}\x{9D03}\x{9D06}\x{9D07}\x{9D08}\x{9D09}' . +'\x{9D0E}\x{9D12}\x{9D15}\x{9D1B}\x{9D1F}\x{9D23}\x{9D26}\x{9D28}\x{9D2A}' . +'\x{9D2B}\x{9D2C}\x{9D3B}\x{9D3E}\x{9D3F}\x{9D41}\x{9D44}\x{9D46}\x{9D48}' . +'\x{9D50}\x{9D51}\x{9D59}\x{9D5C}\x{9D5D}\x{9D5E}\x{9D60}\x{9D61}\x{9D64}' . +'\x{9D6C}\x{9D6F}\x{9D72}\x{9D7A}\x{9D87}\x{9D89}\x{9D8F}\x{9D9A}\x{9DA4}' . +'\x{9DA9}\x{9DAB}\x{9DAF}\x{9DB2}\x{9DB4}\x{9DB8}\x{9DBA}\x{9DBB}\x{9DC1}' . +'\x{9DC2}\x{9DC4}\x{9DC6}\x{9DCF}\x{9DD3}\x{9DD9}\x{9DE6}\x{9DED}\x{9DEF}' . +'\x{9DF2}\x{9DF8}\x{9DF9}\x{9DFA}\x{9DFD}\x{9E1A}\x{9E1B}\x{9E1E}\x{9E75}' . +'\x{9E78}\x{9E79}\x{9E7D}\x{9E7F}\x{9E81}\x{9E88}\x{9E8B}\x{9E8C}\x{9E91}' . +'\x{9E92}\x{9E93}\x{9E95}\x{9E97}\x{9E9D}\x{9E9F}\x{9EA5}\x{9EA6}\x{9EA9}' . +'\x{9EAA}\x{9EAD}\x{9EB8}\x{9EB9}\x{9EBA}\x{9EBB}\x{9EBC}\x{9EBE}\x{9EBF}' . +'\x{9EC4}\x{9ECC}\x{9ECD}\x{9ECE}\x{9ECF}\x{9ED0}\x{9ED2}\x{9ED4}\x{9ED8}' . +'\x{9ED9}\x{9EDB}\x{9EDC}\x{9EDD}\x{9EDE}\x{9EE0}\x{9EE5}\x{9EE8}\x{9EEF}' . +'\x{9EF4}\x{9EF6}\x{9EF7}\x{9EF9}\x{9EFB}\x{9EFC}\x{9EFD}\x{9F07}\x{9F08}' . +'\x{9F0E}\x{9F13}\x{9F15}\x{9F20}\x{9F21}\x{9F2C}\x{9F3B}\x{9F3E}\x{9F4A}' . +'\x{9F4B}\x{9F4E}\x{9F4F}\x{9F52}\x{9F54}\x{9F5F}\x{9F60}\x{9F61}\x{9F62}' . +'\x{9F63}\x{9F66}\x{9F67}\x{9F6A}\x{9F6C}\x{9F72}\x{9F76}\x{9F77}\x{9F8D}' . +'\x{9F95}\x{9F9C}\x{9F9D}\x{9FA0}]{1,15}$/iu', + 12 => '/^[\x{002d}0-9a-z\x{3447}\x{3473}\x{359E}\x{360E}\x{361A}\x{3918}\x{396E}\x{39CF}\x{39D0}' . +'\x{39DF}\x{3A73}\x{3B4E}\x{3C6E}\x{3CE0}\x{4056}\x{415F}\x{4337}\x{43AC}' . +'\x{43B1}\x{43DD}\x{44D6}\x{464C}\x{4661}\x{4723}\x{4729}\x{477C}\x{478D}' . +'\x{4947}\x{497A}\x{497D}\x{4982}\x{4983}\x{4985}\x{4986}\x{499B}\x{499F}' . +'\x{49B6}\x{49B7}\x{4C77}\x{4C9F}\x{4CA0}\x{4CA1}\x{4CA2}\x{4CA3}\x{4D13}' . +'\x{4D14}\x{4D15}\x{4D16}\x{4D17}\x{4D18}\x{4D19}\x{4DAE}\x{4E00}\x{4E01}' . +'\x{4E02}\x{4E03}\x{4E04}\x{4E05}\x{4E06}\x{4E07}\x{4E08}\x{4E09}\x{4E0A}' . +'\x{4E0B}\x{4E0C}\x{4E0D}\x{4E0E}\x{4E0F}\x{4E10}\x{4E11}\x{4E13}\x{4E14}' . +'\x{4E15}\x{4E16}\x{4E17}\x{4E18}\x{4E19}\x{4E1A}\x{4E1B}\x{4E1C}\x{4E1D}' . +'\x{4E1E}\x{4E1F}\x{4E20}\x{4E21}\x{4E22}\x{4E23}\x{4E24}\x{4E25}\x{4E26}' . +'\x{4E27}\x{4E28}\x{4E2A}\x{4E2B}\x{4E2C}\x{4E2D}\x{4E2E}\x{4E2F}\x{4E30}' . +'\x{4E31}\x{4E32}\x{4E33}\x{4E34}\x{4E35}\x{4E36}\x{4E37}\x{4E38}\x{4E39}' . +'\x{4E3A}\x{4E3B}\x{4E3C}\x{4E3D}\x{4E3E}\x{4E3F}\x{4E40}\x{4E41}\x{4E42}' . +'\x{4E43}\x{4E44}\x{4E45}\x{4E46}\x{4E47}\x{4E48}\x{4E49}\x{4E4A}\x{4E4B}' . +'\x{4E4C}\x{4E4D}\x{4E4E}\x{4E4F}\x{4E50}\x{4E51}\x{4E52}\x{4E53}\x{4E54}' . +'\x{4E56}\x{4E57}\x{4E58}\x{4E59}\x{4E5A}\x{4E5B}\x{4E5C}\x{4E5D}\x{4E5E}' . +'\x{4E5F}\x{4E60}\x{4E61}\x{4E62}\x{4E63}\x{4E64}\x{4E65}\x{4E66}\x{4E67}' . +'\x{4E69}\x{4E6A}\x{4E6B}\x{4E6C}\x{4E6D}\x{4E6E}\x{4E6F}\x{4E70}\x{4E71}' . +'\x{4E72}\x{4E73}\x{4E74}\x{4E75}\x{4E76}\x{4E77}\x{4E78}\x{4E7A}\x{4E7B}' . +'\x{4E7C}\x{4E7D}\x{4E7E}\x{4E7F}\x{4E80}\x{4E81}\x{4E82}\x{4E83}\x{4E84}' . +'\x{4E85}\x{4E86}\x{4E87}\x{4E88}\x{4E89}\x{4E8B}\x{4E8C}\x{4E8D}\x{4E8E}' . +'\x{4E8F}\x{4E90}\x{4E91}\x{4E92}\x{4E93}\x{4E94}\x{4E95}\x{4E97}\x{4E98}' . +'\x{4E99}\x{4E9A}\x{4E9B}\x{4E9C}\x{4E9D}\x{4E9E}\x{4E9F}\x{4EA0}\x{4EA1}' . +'\x{4EA2}\x{4EA4}\x{4EA5}\x{4EA6}\x{4EA7}\x{4EA8}\x{4EA9}\x{4EAA}\x{4EAB}' . +'\x{4EAC}\x{4EAD}\x{4EAE}\x{4EAF}\x{4EB0}\x{4EB1}\x{4EB2}\x{4EB3}\x{4EB4}' . +'\x{4EB5}\x{4EB6}\x{4EB7}\x{4EB8}\x{4EB9}\x{4EBA}\x{4EBB}\x{4EBD}\x{4EBE}' . +'\x{4EBF}\x{4EC0}\x{4EC1}\x{4EC2}\x{4EC3}\x{4EC4}\x{4EC5}\x{4EC6}\x{4EC7}' . +'\x{4EC8}\x{4EC9}\x{4ECA}\x{4ECB}\x{4ECD}\x{4ECE}\x{4ECF}\x{4ED0}\x{4ED1}' . +'\x{4ED2}\x{4ED3}\x{4ED4}\x{4ED5}\x{4ED6}\x{4ED7}\x{4ED8}\x{4ED9}\x{4EDA}' . +'\x{4EDB}\x{4EDC}\x{4EDD}\x{4EDE}\x{4EDF}\x{4EE0}\x{4EE1}\x{4EE2}\x{4EE3}' . +'\x{4EE4}\x{4EE5}\x{4EE6}\x{4EE8}\x{4EE9}\x{4EEA}\x{4EEB}\x{4EEC}\x{4EEF}' . +'\x{4EF0}\x{4EF1}\x{4EF2}\x{4EF3}\x{4EF4}\x{4EF5}\x{4EF6}\x{4EF7}\x{4EFB}' . +'\x{4EFD}\x{4EFF}\x{4F00}\x{4F01}\x{4F02}\x{4F03}\x{4F04}\x{4F05}\x{4F06}' . +'\x{4F08}\x{4F09}\x{4F0A}\x{4F0B}\x{4F0C}\x{4F0D}\x{4F0E}\x{4F0F}\x{4F10}' . +'\x{4F11}\x{4F12}\x{4F13}\x{4F14}\x{4F15}\x{4F17}\x{4F18}\x{4F19}\x{4F1A}' . +'\x{4F1B}\x{4F1C}\x{4F1D}\x{4F1E}\x{4F1F}\x{4F20}\x{4F21}\x{4F22}\x{4F23}' . +'\x{4F24}\x{4F25}\x{4F26}\x{4F27}\x{4F29}\x{4F2A}\x{4F2B}\x{4F2C}\x{4F2D}' . +'\x{4F2E}\x{4F2F}\x{4F30}\x{4F32}\x{4F33}\x{4F34}\x{4F36}\x{4F38}\x{4F39}' . +'\x{4F3A}\x{4F3B}\x{4F3C}\x{4F3D}\x{4F3E}\x{4F3F}\x{4F41}\x{4F42}\x{4F43}' . +'\x{4F45}\x{4F46}\x{4F47}\x{4F48}\x{4F49}\x{4F4A}\x{4F4B}\x{4F4C}\x{4F4D}' . +'\x{4F4E}\x{4F4F}\x{4F50}\x{4F51}\x{4F52}\x{4F53}\x{4F54}\x{4F55}\x{4F56}' . +'\x{4F57}\x{4F58}\x{4F59}\x{4F5A}\x{4F5B}\x{4F5C}\x{4F5D}\x{4F5E}\x{4F5F}' . +'\x{4F60}\x{4F61}\x{4F62}\x{4F63}\x{4F64}\x{4F65}\x{4F66}\x{4F67}\x{4F68}' . +'\x{4F69}\x{4F6A}\x{4F6B}\x{4F6C}\x{4F6D}\x{4F6E}\x{4F6F}\x{4F70}\x{4F72}' . +'\x{4F73}\x{4F74}\x{4F75}\x{4F76}\x{4F77}\x{4F78}\x{4F79}\x{4F7A}\x{4F7B}' . +'\x{4F7C}\x{4F7D}\x{4F7E}\x{4F7F}\x{4F80}\x{4F81}\x{4F82}\x{4F83}\x{4F84}' . +'\x{4F85}\x{4F86}\x{4F87}\x{4F88}\x{4F89}\x{4F8A}\x{4F8B}\x{4F8D}\x{4F8F}' . +'\x{4F90}\x{4F91}\x{4F92}\x{4F93}\x{4F94}\x{4F95}\x{4F96}\x{4F97}\x{4F98}' . +'\x{4F99}\x{4F9A}\x{4F9B}\x{4F9C}\x{4F9D}\x{4F9E}\x{4F9F}\x{4FA0}\x{4FA1}' . +'\x{4FA3}\x{4FA4}\x{4FA5}\x{4FA6}\x{4FA7}\x{4FA8}\x{4FA9}\x{4FAA}\x{4FAB}' . +'\x{4FAC}\x{4FAE}\x{4FAF}\x{4FB0}\x{4FB1}\x{4FB2}\x{4FB3}\x{4FB4}\x{4FB5}' . +'\x{4FB6}\x{4FB7}\x{4FB8}\x{4FB9}\x{4FBA}\x{4FBB}\x{4FBC}\x{4FBE}\x{4FBF}' . +'\x{4FC0}\x{4FC1}\x{4FC2}\x{4FC3}\x{4FC4}\x{4FC5}\x{4FC7}\x{4FC9}\x{4FCA}' . +'\x{4FCB}\x{4FCD}\x{4FCE}\x{4FCF}\x{4FD0}\x{4FD1}\x{4FD2}\x{4FD3}\x{4FD4}' . +'\x{4FD5}\x{4FD6}\x{4FD7}\x{4FD8}\x{4FD9}\x{4FDA}\x{4FDB}\x{4FDC}\x{4FDD}' . +'\x{4FDE}\x{4FDF}\x{4FE0}\x{4FE1}\x{4FE3}\x{4FE4}\x{4FE5}\x{4FE6}\x{4FE7}' . +'\x{4FE8}\x{4FE9}\x{4FEA}\x{4FEB}\x{4FEC}\x{4FED}\x{4FEE}\x{4FEF}\x{4FF0}' . +'\x{4FF1}\x{4FF2}\x{4FF3}\x{4FF4}\x{4FF5}\x{4FF6}\x{4FF7}\x{4FF8}\x{4FF9}' . +'\x{4FFA}\x{4FFB}\x{4FFE}\x{4FFF}\x{5000}\x{5001}\x{5002}\x{5003}\x{5004}' . +'\x{5005}\x{5006}\x{5007}\x{5008}\x{5009}\x{500A}\x{500B}\x{500C}\x{500D}' . +'\x{500E}\x{500F}\x{5011}\x{5012}\x{5013}\x{5014}\x{5015}\x{5016}\x{5017}' . +'\x{5018}\x{5019}\x{501A}\x{501B}\x{501C}\x{501D}\x{501E}\x{501F}\x{5020}' . +'\x{5021}\x{5022}\x{5023}\x{5024}\x{5025}\x{5026}\x{5027}\x{5028}\x{5029}' . +'\x{502A}\x{502B}\x{502C}\x{502D}\x{502E}\x{502F}\x{5030}\x{5031}\x{5032}' . +'\x{5033}\x{5035}\x{5036}\x{5037}\x{5039}\x{503A}\x{503B}\x{503C}\x{503E}' . +'\x{503F}\x{5040}\x{5041}\x{5043}\x{5044}\x{5045}\x{5046}\x{5047}\x{5048}' . +'\x{5049}\x{504A}\x{504B}\x{504C}\x{504D}\x{504E}\x{504F}\x{5051}\x{5053}' . +'\x{5054}\x{5055}\x{5056}\x{5057}\x{5059}\x{505A}\x{505B}\x{505C}\x{505D}' . +'\x{505E}\x{505F}\x{5060}\x{5061}\x{5062}\x{5063}\x{5064}\x{5065}\x{5066}' . +'\x{5067}\x{5068}\x{5069}\x{506A}\x{506B}\x{506C}\x{506D}\x{506E}\x{506F}' . +'\x{5070}\x{5071}\x{5072}\x{5073}\x{5074}\x{5075}\x{5076}\x{5077}\x{5078}' . +'\x{5079}\x{507A}\x{507B}\x{507D}\x{507E}\x{507F}\x{5080}\x{5082}\x{5083}' . +'\x{5084}\x{5085}\x{5086}\x{5087}\x{5088}\x{5089}\x{508A}\x{508B}\x{508C}' . +'\x{508D}\x{508E}\x{508F}\x{5090}\x{5091}\x{5092}\x{5094}\x{5095}\x{5096}' . +'\x{5098}\x{5099}\x{509A}\x{509B}\x{509C}\x{509D}\x{509E}\x{50A2}\x{50A3}' . +'\x{50A4}\x{50A5}\x{50A6}\x{50A7}\x{50A8}\x{50A9}\x{50AA}\x{50AB}\x{50AC}' . +'\x{50AD}\x{50AE}\x{50AF}\x{50B0}\x{50B1}\x{50B2}\x{50B3}\x{50B4}\x{50B5}' . +'\x{50B6}\x{50B7}\x{50B8}\x{50BA}\x{50BB}\x{50BC}\x{50BD}\x{50BE}\x{50BF}' . +'\x{50C0}\x{50C1}\x{50C2}\x{50C4}\x{50C5}\x{50C6}\x{50C7}\x{50C8}\x{50C9}' . +'\x{50CA}\x{50CB}\x{50CC}\x{50CD}\x{50CE}\x{50CF}\x{50D0}\x{50D1}\x{50D2}' . +'\x{50D3}\x{50D4}\x{50D5}\x{50D6}\x{50D7}\x{50D9}\x{50DA}\x{50DB}\x{50DC}' . +'\x{50DD}\x{50DE}\x{50E0}\x{50E3}\x{50E4}\x{50E5}\x{50E6}\x{50E7}\x{50E8}' . +'\x{50E9}\x{50EA}\x{50EC}\x{50ED}\x{50EE}\x{50EF}\x{50F0}\x{50F1}\x{50F2}' . +'\x{50F3}\x{50F5}\x{50F6}\x{50F8}\x{50F9}\x{50FA}\x{50FB}\x{50FC}\x{50FD}' . +'\x{50FE}\x{50FF}\x{5100}\x{5101}\x{5102}\x{5103}\x{5104}\x{5105}\x{5106}' . +'\x{5107}\x{5108}\x{5109}\x{510A}\x{510B}\x{510C}\x{510D}\x{510E}\x{510F}' . +'\x{5110}\x{5111}\x{5112}\x{5113}\x{5114}\x{5115}\x{5116}\x{5117}\x{5118}' . +'\x{5119}\x{511A}\x{511C}\x{511D}\x{511E}\x{511F}\x{5120}\x{5121}\x{5122}' . +'\x{5123}\x{5124}\x{5125}\x{5126}\x{5127}\x{5129}\x{512A}\x{512C}\x{512D}' . +'\x{512E}\x{512F}\x{5130}\x{5131}\x{5132}\x{5133}\x{5134}\x{5135}\x{5136}' . +'\x{5137}\x{5138}\x{5139}\x{513A}\x{513B}\x{513C}\x{513D}\x{513E}\x{513F}' . +'\x{5140}\x{5141}\x{5143}\x{5144}\x{5145}\x{5146}\x{5147}\x{5148}\x{5149}' . +'\x{514B}\x{514C}\x{514D}\x{514E}\x{5150}\x{5151}\x{5152}\x{5154}\x{5155}' . +'\x{5156}\x{5157}\x{5159}\x{515A}\x{515B}\x{515C}\x{515D}\x{515E}\x{515F}' . +'\x{5161}\x{5162}\x{5163}\x{5165}\x{5166}\x{5167}\x{5168}\x{5169}\x{516A}' . +'\x{516B}\x{516C}\x{516D}\x{516E}\x{516F}\x{5170}\x{5171}\x{5173}\x{5174}' . +'\x{5175}\x{5176}\x{5177}\x{5178}\x{5179}\x{517A}\x{517B}\x{517C}\x{517D}' . +'\x{517F}\x{5180}\x{5181}\x{5182}\x{5185}\x{5186}\x{5187}\x{5188}\x{5189}' . +'\x{518A}\x{518B}\x{518C}\x{518D}\x{518F}\x{5190}\x{5191}\x{5192}\x{5193}' . +'\x{5194}\x{5195}\x{5196}\x{5197}\x{5198}\x{5199}\x{519A}\x{519B}\x{519C}' . +'\x{519D}\x{519E}\x{519F}\x{51A0}\x{51A2}\x{51A4}\x{51A5}\x{51A6}\x{51A7}' . +'\x{51A8}\x{51AA}\x{51AB}\x{51AC}\x{51AE}\x{51AF}\x{51B0}\x{51B1}\x{51B2}' . +'\x{51B3}\x{51B5}\x{51B6}\x{51B7}\x{51B9}\x{51BB}\x{51BC}\x{51BD}\x{51BE}' . +'\x{51BF}\x{51C0}\x{51C1}\x{51C3}\x{51C4}\x{51C5}\x{51C6}\x{51C7}\x{51C8}' . +'\x{51C9}\x{51CA}\x{51CB}\x{51CC}\x{51CD}\x{51CE}\x{51CF}\x{51D0}\x{51D1}' . +'\x{51D4}\x{51D5}\x{51D6}\x{51D7}\x{51D8}\x{51D9}\x{51DA}\x{51DB}\x{51DC}' . +'\x{51DD}\x{51DE}\x{51E0}\x{51E1}\x{51E2}\x{51E3}\x{51E4}\x{51E5}\x{51E7}' . +'\x{51E8}\x{51E9}\x{51EA}\x{51EB}\x{51ED}\x{51EF}\x{51F0}\x{51F1}\x{51F3}' . +'\x{51F4}\x{51F5}\x{51F6}\x{51F7}\x{51F8}\x{51F9}\x{51FA}\x{51FB}\x{51FC}' . +'\x{51FD}\x{51FE}\x{51FF}\x{5200}\x{5201}\x{5202}\x{5203}\x{5204}\x{5205}' . +'\x{5206}\x{5207}\x{5208}\x{5209}\x{520A}\x{520B}\x{520C}\x{520D}\x{520E}' . +'\x{520F}\x{5210}\x{5211}\x{5212}\x{5213}\x{5214}\x{5215}\x{5216}\x{5217}' . +'\x{5218}\x{5219}\x{521A}\x{521B}\x{521C}\x{521D}\x{521E}\x{521F}\x{5220}' . +'\x{5221}\x{5222}\x{5223}\x{5224}\x{5225}\x{5226}\x{5228}\x{5229}\x{522A}' . +'\x{522B}\x{522C}\x{522D}\x{522E}\x{522F}\x{5230}\x{5231}\x{5232}\x{5233}' . +'\x{5234}\x{5235}\x{5236}\x{5237}\x{5238}\x{5239}\x{523A}\x{523B}\x{523C}' . +'\x{523D}\x{523E}\x{523F}\x{5240}\x{5241}\x{5242}\x{5243}\x{5244}\x{5245}' . +'\x{5246}\x{5247}\x{5248}\x{5249}\x{524A}\x{524B}\x{524C}\x{524D}\x{524E}' . +'\x{5250}\x{5251}\x{5252}\x{5254}\x{5255}\x{5256}\x{5257}\x{5258}\x{5259}' . +'\x{525A}\x{525B}\x{525C}\x{525D}\x{525E}\x{525F}\x{5260}\x{5261}\x{5262}' . +'\x{5263}\x{5264}\x{5265}\x{5267}\x{5268}\x{5269}\x{526A}\x{526B}\x{526C}' . +'\x{526D}\x{526E}\x{526F}\x{5270}\x{5272}\x{5273}\x{5274}\x{5275}\x{5276}' . +'\x{5277}\x{5278}\x{527A}\x{527B}\x{527C}\x{527D}\x{527E}\x{527F}\x{5280}' . +'\x{5281}\x{5282}\x{5283}\x{5284}\x{5286}\x{5287}\x{5288}\x{5289}\x{528A}' . +'\x{528B}\x{528C}\x{528D}\x{528F}\x{5290}\x{5291}\x{5292}\x{5293}\x{5294}' . +'\x{5295}\x{5296}\x{5297}\x{5298}\x{5299}\x{529A}\x{529B}\x{529C}\x{529D}' . +'\x{529E}\x{529F}\x{52A0}\x{52A1}\x{52A2}\x{52A3}\x{52A5}\x{52A6}\x{52A7}' . +'\x{52A8}\x{52A9}\x{52AA}\x{52AB}\x{52AC}\x{52AD}\x{52AE}\x{52AF}\x{52B0}' . +'\x{52B1}\x{52B2}\x{52B3}\x{52B4}\x{52B5}\x{52B6}\x{52B7}\x{52B8}\x{52B9}' . +'\x{52BA}\x{52BB}\x{52BC}\x{52BD}\x{52BE}\x{52BF}\x{52C0}\x{52C1}\x{52C2}' . +'\x{52C3}\x{52C6}\x{52C7}\x{52C9}\x{52CA}\x{52CB}\x{52CD}\x{52CF}\x{52D0}' . +'\x{52D2}\x{52D3}\x{52D5}\x{52D6}\x{52D7}\x{52D8}\x{52D9}\x{52DA}\x{52DB}' . +'\x{52DC}\x{52DD}\x{52DE}\x{52DF}\x{52E0}\x{52E2}\x{52E3}\x{52E4}\x{52E6}' . +'\x{52E7}\x{52E8}\x{52E9}\x{52EA}\x{52EB}\x{52EC}\x{52ED}\x{52EF}\x{52F0}' . +'\x{52F1}\x{52F2}\x{52F3}\x{52F4}\x{52F5}\x{52F6}\x{52F7}\x{52F8}\x{52F9}' . +'\x{52FA}\x{52FB}\x{52FC}\x{52FD}\x{52FE}\x{52FF}\x{5300}\x{5301}\x{5302}' . +'\x{5305}\x{5306}\x{5307}\x{5308}\x{5309}\x{530A}\x{530B}\x{530C}\x{530D}' . +'\x{530E}\x{530F}\x{5310}\x{5311}\x{5312}\x{5313}\x{5314}\x{5315}\x{5316}' . +'\x{5317}\x{5319}\x{531A}\x{531C}\x{531D}\x{531F}\x{5320}\x{5321}\x{5322}' . +'\x{5323}\x{5324}\x{5325}\x{5326}\x{5328}\x{532A}\x{532B}\x{532C}\x{532D}' . +'\x{532E}\x{532F}\x{5330}\x{5331}\x{5333}\x{5334}\x{5337}\x{5339}\x{533A}' . +'\x{533B}\x{533C}\x{533D}\x{533E}\x{533F}\x{5340}\x{5341}\x{5343}\x{5344}' . +'\x{5345}\x{5346}\x{5347}\x{5348}\x{5349}\x{534A}\x{534B}\x{534C}\x{534D}' . +'\x{534E}\x{534F}\x{5350}\x{5351}\x{5352}\x{5353}\x{5354}\x{5355}\x{5356}' . +'\x{5357}\x{5358}\x{5359}\x{535A}\x{535C}\x{535E}\x{535F}\x{5360}\x{5361}' . +'\x{5362}\x{5363}\x{5364}\x{5365}\x{5366}\x{5367}\x{5369}\x{536B}\x{536C}' . +'\x{536E}\x{536F}\x{5370}\x{5371}\x{5372}\x{5373}\x{5374}\x{5375}\x{5376}' . +'\x{5377}\x{5378}\x{5379}\x{537A}\x{537B}\x{537C}\x{537D}\x{537E}\x{537F}' . +'\x{5381}\x{5382}\x{5383}\x{5384}\x{5385}\x{5386}\x{5387}\x{5388}\x{5389}' . +'\x{538A}\x{538B}\x{538C}\x{538D}\x{538E}\x{538F}\x{5390}\x{5391}\x{5392}' . +'\x{5393}\x{5394}\x{5395}\x{5396}\x{5397}\x{5398}\x{5399}\x{539A}\x{539B}' . +'\x{539C}\x{539D}\x{539E}\x{539F}\x{53A0}\x{53A2}\x{53A3}\x{53A4}\x{53A5}' . +'\x{53A6}\x{53A7}\x{53A8}\x{53A9}\x{53AC}\x{53AD}\x{53AE}\x{53B0}\x{53B1}' . +'\x{53B2}\x{53B3}\x{53B4}\x{53B5}\x{53B6}\x{53B7}\x{53B8}\x{53B9}\x{53BB}' . +'\x{53BC}\x{53BD}\x{53BE}\x{53BF}\x{53C0}\x{53C1}\x{53C2}\x{53C3}\x{53C4}' . +'\x{53C6}\x{53C7}\x{53C8}\x{53C9}\x{53CA}\x{53CB}\x{53CC}\x{53CD}\x{53CE}' . +'\x{53D0}\x{53D1}\x{53D2}\x{53D3}\x{53D4}\x{53D5}\x{53D6}\x{53D7}\x{53D8}' . +'\x{53D9}\x{53DB}\x{53DC}\x{53DF}\x{53E0}\x{53E1}\x{53E2}\x{53E3}\x{53E4}' . +'\x{53E5}\x{53E6}\x{53E8}\x{53E9}\x{53EA}\x{53EB}\x{53EC}\x{53ED}\x{53EE}' . +'\x{53EF}\x{53F0}\x{53F1}\x{53F2}\x{53F3}\x{53F4}\x{53F5}\x{53F6}\x{53F7}' . +'\x{53F8}\x{53F9}\x{53FA}\x{53FB}\x{53FC}\x{53FD}\x{53FE}\x{5401}\x{5402}' . +'\x{5403}\x{5404}\x{5405}\x{5406}\x{5407}\x{5408}\x{5409}\x{540A}\x{540B}' . +'\x{540C}\x{540D}\x{540E}\x{540F}\x{5410}\x{5411}\x{5412}\x{5413}\x{5414}' . +'\x{5415}\x{5416}\x{5417}\x{5418}\x{5419}\x{541B}\x{541C}\x{541D}\x{541E}' . +'\x{541F}\x{5420}\x{5421}\x{5423}\x{5424}\x{5425}\x{5426}\x{5427}\x{5428}' . +'\x{5429}\x{542A}\x{542B}\x{542C}\x{542D}\x{542E}\x{542F}\x{5430}\x{5431}' . +'\x{5432}\x{5433}\x{5434}\x{5435}\x{5436}\x{5437}\x{5438}\x{5439}\x{543A}' . +'\x{543B}\x{543C}\x{543D}\x{543E}\x{543F}\x{5440}\x{5441}\x{5442}\x{5443}' . +'\x{5444}\x{5445}\x{5446}\x{5447}\x{5448}\x{5449}\x{544A}\x{544B}\x{544D}' . +'\x{544E}\x{544F}\x{5450}\x{5451}\x{5452}\x{5453}\x{5454}\x{5455}\x{5456}' . +'\x{5457}\x{5458}\x{5459}\x{545A}\x{545B}\x{545C}\x{545E}\x{545F}\x{5460}' . +'\x{5461}\x{5462}\x{5463}\x{5464}\x{5465}\x{5466}\x{5467}\x{5468}\x{546A}' . +'\x{546B}\x{546C}\x{546D}\x{546E}\x{546F}\x{5470}\x{5471}\x{5472}\x{5473}' . +'\x{5474}\x{5475}\x{5476}\x{5477}\x{5478}\x{5479}\x{547A}\x{547B}\x{547C}' . +'\x{547D}\x{547E}\x{547F}\x{5480}\x{5481}\x{5482}\x{5483}\x{5484}\x{5485}' . +'\x{5486}\x{5487}\x{5488}\x{5489}\x{548B}\x{548C}\x{548D}\x{548E}\x{548F}' . +'\x{5490}\x{5491}\x{5492}\x{5493}\x{5494}\x{5495}\x{5496}\x{5497}\x{5498}' . +'\x{5499}\x{549A}\x{549B}\x{549C}\x{549D}\x{549E}\x{549F}\x{54A0}\x{54A1}' . +'\x{54A2}\x{54A3}\x{54A4}\x{54A5}\x{54A6}\x{54A7}\x{54A8}\x{54A9}\x{54AA}' . +'\x{54AB}\x{54AC}\x{54AD}\x{54AE}\x{54AF}\x{54B0}\x{54B1}\x{54B2}\x{54B3}' . +'\x{54B4}\x{54B6}\x{54B7}\x{54B8}\x{54B9}\x{54BA}\x{54BB}\x{54BC}\x{54BD}' . +'\x{54BE}\x{54BF}\x{54C0}\x{54C1}\x{54C2}\x{54C3}\x{54C4}\x{54C5}\x{54C6}' . +'\x{54C7}\x{54C8}\x{54C9}\x{54CA}\x{54CB}\x{54CC}\x{54CD}\x{54CE}\x{54CF}' . +'\x{54D0}\x{54D1}\x{54D2}\x{54D3}\x{54D4}\x{54D5}\x{54D6}\x{54D7}\x{54D8}' . +'\x{54D9}\x{54DA}\x{54DB}\x{54DC}\x{54DD}\x{54DE}\x{54DF}\x{54E0}\x{54E1}' . +'\x{54E2}\x{54E3}\x{54E4}\x{54E5}\x{54E6}\x{54E7}\x{54E8}\x{54E9}\x{54EA}' . +'\x{54EB}\x{54EC}\x{54ED}\x{54EE}\x{54EF}\x{54F0}\x{54F1}\x{54F2}\x{54F3}' . +'\x{54F4}\x{54F5}\x{54F7}\x{54F8}\x{54F9}\x{54FA}\x{54FB}\x{54FC}\x{54FD}' . +'\x{54FE}\x{54FF}\x{5500}\x{5501}\x{5502}\x{5503}\x{5504}\x{5505}\x{5506}' . +'\x{5507}\x{5508}\x{5509}\x{550A}\x{550B}\x{550C}\x{550D}\x{550E}\x{550F}' . +'\x{5510}\x{5511}\x{5512}\x{5513}\x{5514}\x{5516}\x{5517}\x{551A}\x{551B}' . +'\x{551C}\x{551D}\x{551E}\x{551F}\x{5520}\x{5521}\x{5522}\x{5523}\x{5524}' . +'\x{5525}\x{5526}\x{5527}\x{5528}\x{5529}\x{552A}\x{552B}\x{552C}\x{552D}' . +'\x{552E}\x{552F}\x{5530}\x{5531}\x{5532}\x{5533}\x{5534}\x{5535}\x{5536}' . +'\x{5537}\x{5538}\x{5539}\x{553A}\x{553B}\x{553C}\x{553D}\x{553E}\x{553F}' . +'\x{5540}\x{5541}\x{5542}\x{5543}\x{5544}\x{5545}\x{5546}\x{5548}\x{5549}' . +'\x{554A}\x{554B}\x{554C}\x{554D}\x{554E}\x{554F}\x{5550}\x{5551}\x{5552}' . +'\x{5553}\x{5554}\x{5555}\x{5556}\x{5557}\x{5558}\x{5559}\x{555A}\x{555B}' . +'\x{555C}\x{555D}\x{555E}\x{555F}\x{5561}\x{5562}\x{5563}\x{5564}\x{5565}' . +'\x{5566}\x{5567}\x{5568}\x{5569}\x{556A}\x{556B}\x{556C}\x{556D}\x{556E}' . +'\x{556F}\x{5570}\x{5571}\x{5572}\x{5573}\x{5574}\x{5575}\x{5576}\x{5577}' . +'\x{5578}\x{5579}\x{557B}\x{557C}\x{557D}\x{557E}\x{557F}\x{5580}\x{5581}' . +'\x{5582}\x{5583}\x{5584}\x{5585}\x{5586}\x{5587}\x{5588}\x{5589}\x{558A}' . +'\x{558B}\x{558C}\x{558D}\x{558E}\x{558F}\x{5590}\x{5591}\x{5592}\x{5593}' . +'\x{5594}\x{5595}\x{5596}\x{5597}\x{5598}\x{5599}\x{559A}\x{559B}\x{559C}' . +'\x{559D}\x{559E}\x{559F}\x{55A0}\x{55A1}\x{55A2}\x{55A3}\x{55A4}\x{55A5}' . +'\x{55A6}\x{55A7}\x{55A8}\x{55A9}\x{55AA}\x{55AB}\x{55AC}\x{55AD}\x{55AE}' . +'\x{55AF}\x{55B0}\x{55B1}\x{55B2}\x{55B3}\x{55B4}\x{55B5}\x{55B6}\x{55B7}' . +'\x{55B8}\x{55B9}\x{55BA}\x{55BB}\x{55BC}\x{55BD}\x{55BE}\x{55BF}\x{55C0}' . +'\x{55C1}\x{55C2}\x{55C3}\x{55C4}\x{55C5}\x{55C6}\x{55C7}\x{55C8}\x{55C9}' . +'\x{55CA}\x{55CB}\x{55CC}\x{55CD}\x{55CE}\x{55CF}\x{55D0}\x{55D1}\x{55D2}' . +'\x{55D3}\x{55D4}\x{55D5}\x{55D6}\x{55D7}\x{55D8}\x{55D9}\x{55DA}\x{55DB}' . +'\x{55DC}\x{55DD}\x{55DE}\x{55DF}\x{55E1}\x{55E2}\x{55E3}\x{55E4}\x{55E5}' . +'\x{55E6}\x{55E7}\x{55E8}\x{55E9}\x{55EA}\x{55EB}\x{55EC}\x{55ED}\x{55EE}' . +'\x{55EF}\x{55F0}\x{55F1}\x{55F2}\x{55F3}\x{55F4}\x{55F5}\x{55F6}\x{55F7}' . +'\x{55F9}\x{55FA}\x{55FB}\x{55FC}\x{55FD}\x{55FE}\x{55FF}\x{5600}\x{5601}' . +'\x{5602}\x{5603}\x{5604}\x{5606}\x{5607}\x{5608}\x{5609}\x{560C}\x{560D}' . +'\x{560E}\x{560F}\x{5610}\x{5611}\x{5612}\x{5613}\x{5614}\x{5615}\x{5616}' . +'\x{5617}\x{5618}\x{5619}\x{561A}\x{561B}\x{561C}\x{561D}\x{561E}\x{561F}' . +'\x{5621}\x{5622}\x{5623}\x{5624}\x{5625}\x{5626}\x{5627}\x{5628}\x{5629}' . +'\x{562A}\x{562C}\x{562D}\x{562E}\x{562F}\x{5630}\x{5631}\x{5632}\x{5633}' . +'\x{5634}\x{5635}\x{5636}\x{5638}\x{5639}\x{563A}\x{563B}\x{563D}\x{563E}' . +'\x{563F}\x{5640}\x{5641}\x{5642}\x{5643}\x{5645}\x{5646}\x{5647}\x{5648}' . +'\x{5649}\x{564A}\x{564C}\x{564D}\x{564E}\x{564F}\x{5650}\x{5652}\x{5653}' . +'\x{5654}\x{5655}\x{5657}\x{5658}\x{5659}\x{565A}\x{565B}\x{565C}\x{565D}' . +'\x{565E}\x{5660}\x{5662}\x{5663}\x{5664}\x{5665}\x{5666}\x{5667}\x{5668}' . +'\x{5669}\x{566A}\x{566B}\x{566C}\x{566D}\x{566E}\x{566F}\x{5670}\x{5671}' . +'\x{5672}\x{5673}\x{5674}\x{5676}\x{5677}\x{5678}\x{5679}\x{567A}\x{567B}' . +'\x{567C}\x{567E}\x{567F}\x{5680}\x{5681}\x{5682}\x{5683}\x{5684}\x{5685}' . +'\x{5686}\x{5687}\x{568A}\x{568C}\x{568D}\x{568E}\x{568F}\x{5690}\x{5691}' . +'\x{5692}\x{5693}\x{5694}\x{5695}\x{5697}\x{5698}\x{5699}\x{569A}\x{569B}' . +'\x{569C}\x{569D}\x{569F}\x{56A0}\x{56A1}\x{56A3}\x{56A4}\x{56A5}\x{56A6}' . +'\x{56A7}\x{56A8}\x{56A9}\x{56AA}\x{56AB}\x{56AC}\x{56AD}\x{56AE}\x{56AF}' . +'\x{56B0}\x{56B1}\x{56B2}\x{56B3}\x{56B4}\x{56B5}\x{56B6}\x{56B7}\x{56B8}' . +'\x{56B9}\x{56BB}\x{56BC}\x{56BD}\x{56BE}\x{56BF}\x{56C0}\x{56C1}\x{56C2}' . +'\x{56C3}\x{56C4}\x{56C5}\x{56C6}\x{56C7}\x{56C8}\x{56C9}\x{56CA}\x{56CB}' . +'\x{56CC}\x{56CD}\x{56CE}\x{56D0}\x{56D1}\x{56D2}\x{56D3}\x{56D4}\x{56D5}' . +'\x{56D6}\x{56D7}\x{56D8}\x{56DA}\x{56DB}\x{56DC}\x{56DD}\x{56DE}\x{56DF}' . +'\x{56E0}\x{56E1}\x{56E2}\x{56E3}\x{56E4}\x{56E5}\x{56E7}\x{56E8}\x{56E9}' . +'\x{56EA}\x{56EB}\x{56EC}\x{56ED}\x{56EE}\x{56EF}\x{56F0}\x{56F1}\x{56F2}' . +'\x{56F3}\x{56F4}\x{56F5}\x{56F7}\x{56F9}\x{56FA}\x{56FD}\x{56FE}\x{56FF}' . +'\x{5700}\x{5701}\x{5702}\x{5703}\x{5704}\x{5706}\x{5707}\x{5708}\x{5709}' . +'\x{570A}\x{570B}\x{570C}\x{570D}\x{570E}\x{570F}\x{5710}\x{5712}\x{5713}' . +'\x{5714}\x{5715}\x{5716}\x{5718}\x{5719}\x{571A}\x{571B}\x{571C}\x{571D}' . +'\x{571E}\x{571F}\x{5720}\x{5722}\x{5723}\x{5725}\x{5726}\x{5727}\x{5728}' . +'\x{5729}\x{572A}\x{572B}\x{572C}\x{572D}\x{572E}\x{572F}\x{5730}\x{5731}' . +'\x{5732}\x{5733}\x{5734}\x{5735}\x{5736}\x{5737}\x{5738}\x{5739}\x{573A}' . +'\x{573B}\x{573C}\x{573E}\x{573F}\x{5740}\x{5741}\x{5742}\x{5744}\x{5745}' . +'\x{5746}\x{5747}\x{5749}\x{574A}\x{574B}\x{574C}\x{574D}\x{574E}\x{574F}' . +'\x{5750}\x{5751}\x{5752}\x{5753}\x{5754}\x{5757}\x{5759}\x{575A}\x{575B}' . +'\x{575C}\x{575D}\x{575E}\x{575F}\x{5760}\x{5761}\x{5762}\x{5764}\x{5765}' . +'\x{5766}\x{5767}\x{5768}\x{5769}\x{576A}\x{576B}\x{576C}\x{576D}\x{576F}' . +'\x{5770}\x{5771}\x{5772}\x{5773}\x{5774}\x{5775}\x{5776}\x{5777}\x{5779}' . +'\x{577A}\x{577B}\x{577C}\x{577D}\x{577E}\x{577F}\x{5780}\x{5782}\x{5783}' . +'\x{5784}\x{5785}\x{5786}\x{5788}\x{5789}\x{578A}\x{578B}\x{578C}\x{578D}' . +'\x{578E}\x{578F}\x{5790}\x{5791}\x{5792}\x{5793}\x{5794}\x{5795}\x{5797}' . +'\x{5798}\x{5799}\x{579A}\x{579B}\x{579C}\x{579D}\x{579E}\x{579F}\x{57A0}' . +'\x{57A1}\x{57A2}\x{57A3}\x{57A4}\x{57A5}\x{57A6}\x{57A7}\x{57A9}\x{57AA}' . +'\x{57AB}\x{57AC}\x{57AD}\x{57AE}\x{57AF}\x{57B0}\x{57B1}\x{57B2}\x{57B3}' . +'\x{57B4}\x{57B5}\x{57B6}\x{57B7}\x{57B8}\x{57B9}\x{57BA}\x{57BB}\x{57BC}' . +'\x{57BD}\x{57BE}\x{57BF}\x{57C0}\x{57C1}\x{57C2}\x{57C3}\x{57C4}\x{57C5}' . +'\x{57C6}\x{57C7}\x{57C8}\x{57C9}\x{57CB}\x{57CC}\x{57CD}\x{57CE}\x{57CF}' . +'\x{57D0}\x{57D2}\x{57D3}\x{57D4}\x{57D5}\x{57D6}\x{57D8}\x{57D9}\x{57DA}' . +'\x{57DC}\x{57DD}\x{57DF}\x{57E0}\x{57E1}\x{57E2}\x{57E3}\x{57E4}\x{57E5}' . +'\x{57E6}\x{57E7}\x{57E8}\x{57E9}\x{57EA}\x{57EB}\x{57EC}\x{57ED}\x{57EE}' . +'\x{57EF}\x{57F0}\x{57F1}\x{57F2}\x{57F3}\x{57F4}\x{57F5}\x{57F6}\x{57F7}' . +'\x{57F8}\x{57F9}\x{57FA}\x{57FB}\x{57FC}\x{57FD}\x{57FE}\x{57FF}\x{5800}' . +'\x{5801}\x{5802}\x{5803}\x{5804}\x{5805}\x{5806}\x{5807}\x{5808}\x{5809}' . +'\x{580A}\x{580B}\x{580C}\x{580D}\x{580E}\x{580F}\x{5810}\x{5811}\x{5812}' . +'\x{5813}\x{5814}\x{5815}\x{5816}\x{5819}\x{581A}\x{581B}\x{581C}\x{581D}' . +'\x{581E}\x{581F}\x{5820}\x{5821}\x{5822}\x{5823}\x{5824}\x{5825}\x{5826}' . +'\x{5827}\x{5828}\x{5829}\x{582A}\x{582B}\x{582C}\x{582D}\x{582E}\x{582F}' . +'\x{5830}\x{5831}\x{5832}\x{5833}\x{5834}\x{5835}\x{5836}\x{5837}\x{5838}' . +'\x{5839}\x{583A}\x{583B}\x{583C}\x{583D}\x{583E}\x{583F}\x{5840}\x{5842}' . +'\x{5843}\x{5844}\x{5845}\x{5846}\x{5847}\x{5848}\x{5849}\x{584A}\x{584B}' . +'\x{584C}\x{584D}\x{584E}\x{584F}\x{5851}\x{5852}\x{5853}\x{5854}\x{5855}' . +'\x{5857}\x{5858}\x{5859}\x{585A}\x{585B}\x{585C}\x{585D}\x{585E}\x{585F}' . +'\x{5861}\x{5862}\x{5863}\x{5864}\x{5865}\x{5868}\x{5869}\x{586A}\x{586B}' . +'\x{586C}\x{586D}\x{586E}\x{586F}\x{5870}\x{5871}\x{5872}\x{5873}\x{5874}' . +'\x{5875}\x{5876}\x{5878}\x{5879}\x{587A}\x{587B}\x{587C}\x{587D}\x{587E}' . +'\x{587F}\x{5880}\x{5881}\x{5882}\x{5883}\x{5884}\x{5885}\x{5886}\x{5887}' . +'\x{5888}\x{5889}\x{588A}\x{588B}\x{588C}\x{588D}\x{588E}\x{588F}\x{5890}' . +'\x{5891}\x{5892}\x{5893}\x{5894}\x{5896}\x{5897}\x{5898}\x{5899}\x{589A}' . +'\x{589B}\x{589C}\x{589D}\x{589E}\x{589F}\x{58A0}\x{58A1}\x{58A2}\x{58A3}' . +'\x{58A4}\x{58A5}\x{58A6}\x{58A7}\x{58A8}\x{58A9}\x{58AB}\x{58AC}\x{58AD}' . +'\x{58AE}\x{58AF}\x{58B0}\x{58B1}\x{58B2}\x{58B3}\x{58B4}\x{58B7}\x{58B8}' . +'\x{58B9}\x{58BA}\x{58BB}\x{58BC}\x{58BD}\x{58BE}\x{58BF}\x{58C1}\x{58C2}' . +'\x{58C5}\x{58C6}\x{58C7}\x{58C8}\x{58C9}\x{58CA}\x{58CB}\x{58CE}\x{58CF}' . +'\x{58D1}\x{58D2}\x{58D3}\x{58D4}\x{58D5}\x{58D6}\x{58D7}\x{58D8}\x{58D9}' . +'\x{58DA}\x{58DB}\x{58DD}\x{58DE}\x{58DF}\x{58E0}\x{58E2}\x{58E3}\x{58E4}' . +'\x{58E5}\x{58E7}\x{58E8}\x{58E9}\x{58EA}\x{58EB}\x{58EC}\x{58ED}\x{58EE}' . +'\x{58EF}\x{58F0}\x{58F1}\x{58F2}\x{58F3}\x{58F4}\x{58F6}\x{58F7}\x{58F8}' . +'\x{58F9}\x{58FA}\x{58FB}\x{58FC}\x{58FD}\x{58FE}\x{58FF}\x{5900}\x{5902}' . +'\x{5903}\x{5904}\x{5906}\x{5907}\x{5909}\x{590A}\x{590B}\x{590C}\x{590D}' . +'\x{590E}\x{590F}\x{5910}\x{5912}\x{5914}\x{5915}\x{5916}\x{5917}\x{5918}' . +'\x{5919}\x{591A}\x{591B}\x{591C}\x{591D}\x{591E}\x{591F}\x{5920}\x{5921}' . +'\x{5922}\x{5924}\x{5925}\x{5926}\x{5927}\x{5928}\x{5929}\x{592A}\x{592B}' . +'\x{592C}\x{592D}\x{592E}\x{592F}\x{5930}\x{5931}\x{5932}\x{5934}\x{5935}' . +'\x{5937}\x{5938}\x{5939}\x{593A}\x{593B}\x{593C}\x{593D}\x{593E}\x{593F}' . +'\x{5940}\x{5941}\x{5942}\x{5943}\x{5944}\x{5945}\x{5946}\x{5947}\x{5948}' . +'\x{5949}\x{594A}\x{594B}\x{594C}\x{594D}\x{594E}\x{594F}\x{5950}\x{5951}' . +'\x{5952}\x{5953}\x{5954}\x{5955}\x{5956}\x{5957}\x{5958}\x{595A}\x{595C}' . +'\x{595D}\x{595E}\x{595F}\x{5960}\x{5961}\x{5962}\x{5963}\x{5964}\x{5965}' . +'\x{5966}\x{5967}\x{5968}\x{5969}\x{596A}\x{596B}\x{596C}\x{596D}\x{596E}' . +'\x{596F}\x{5970}\x{5971}\x{5972}\x{5973}\x{5974}\x{5975}\x{5976}\x{5977}' . +'\x{5978}\x{5979}\x{597A}\x{597B}\x{597C}\x{597D}\x{597E}\x{597F}\x{5980}' . +'\x{5981}\x{5982}\x{5983}\x{5984}\x{5985}\x{5986}\x{5987}\x{5988}\x{5989}' . +'\x{598A}\x{598B}\x{598C}\x{598D}\x{598E}\x{598F}\x{5990}\x{5991}\x{5992}' . +'\x{5993}\x{5994}\x{5995}\x{5996}\x{5997}\x{5998}\x{5999}\x{599A}\x{599C}' . +'\x{599D}\x{599E}\x{599F}\x{59A0}\x{59A1}\x{59A2}\x{59A3}\x{59A4}\x{59A5}' . +'\x{59A6}\x{59A7}\x{59A8}\x{59A9}\x{59AA}\x{59AB}\x{59AC}\x{59AD}\x{59AE}' . +'\x{59AF}\x{59B0}\x{59B1}\x{59B2}\x{59B3}\x{59B4}\x{59B5}\x{59B6}\x{59B8}' . +'\x{59B9}\x{59BA}\x{59BB}\x{59BC}\x{59BD}\x{59BE}\x{59BF}\x{59C0}\x{59C1}' . +'\x{59C2}\x{59C3}\x{59C4}\x{59C5}\x{59C6}\x{59C7}\x{59C8}\x{59C9}\x{59CA}' . +'\x{59CB}\x{59CC}\x{59CD}\x{59CE}\x{59CF}\x{59D0}\x{59D1}\x{59D2}\x{59D3}' . +'\x{59D4}\x{59D5}\x{59D6}\x{59D7}\x{59D8}\x{59D9}\x{59DA}\x{59DB}\x{59DC}' . +'\x{59DD}\x{59DE}\x{59DF}\x{59E0}\x{59E1}\x{59E2}\x{59E3}\x{59E4}\x{59E5}' . +'\x{59E6}\x{59E8}\x{59E9}\x{59EA}\x{59EB}\x{59EC}\x{59ED}\x{59EE}\x{59EF}' . +'\x{59F0}\x{59F1}\x{59F2}\x{59F3}\x{59F4}\x{59F5}\x{59F6}\x{59F7}\x{59F8}' . +'\x{59F9}\x{59FA}\x{59FB}\x{59FC}\x{59FD}\x{59FE}\x{59FF}\x{5A00}\x{5A01}' . +'\x{5A02}\x{5A03}\x{5A04}\x{5A05}\x{5A06}\x{5A07}\x{5A08}\x{5A09}\x{5A0A}' . +'\x{5A0B}\x{5A0C}\x{5A0D}\x{5A0E}\x{5A0F}\x{5A10}\x{5A11}\x{5A12}\x{5A13}' . +'\x{5A14}\x{5A15}\x{5A16}\x{5A17}\x{5A18}\x{5A19}\x{5A1A}\x{5A1B}\x{5A1C}' . +'\x{5A1D}\x{5A1E}\x{5A1F}\x{5A20}\x{5A21}\x{5A22}\x{5A23}\x{5A25}\x{5A27}' . +'\x{5A28}\x{5A29}\x{5A2A}\x{5A2B}\x{5A2D}\x{5A2E}\x{5A2F}\x{5A31}\x{5A32}' . +'\x{5A33}\x{5A34}\x{5A35}\x{5A36}\x{5A37}\x{5A38}\x{5A39}\x{5A3A}\x{5A3B}' . +'\x{5A3C}\x{5A3D}\x{5A3E}\x{5A3F}\x{5A40}\x{5A41}\x{5A42}\x{5A43}\x{5A44}' . +'\x{5A45}\x{5A46}\x{5A47}\x{5A48}\x{5A49}\x{5A4A}\x{5A4B}\x{5A4C}\x{5A4D}' . +'\x{5A4E}\x{5A4F}\x{5A50}\x{5A51}\x{5A52}\x{5A53}\x{5A55}\x{5A56}\x{5A57}' . +'\x{5A58}\x{5A5A}\x{5A5B}\x{5A5C}\x{5A5D}\x{5A5E}\x{5A5F}\x{5A60}\x{5A61}' . +'\x{5A62}\x{5A63}\x{5A64}\x{5A65}\x{5A66}\x{5A67}\x{5A68}\x{5A69}\x{5A6A}' . +'\x{5A6B}\x{5A6C}\x{5A6D}\x{5A6E}\x{5A70}\x{5A72}\x{5A73}\x{5A74}\x{5A75}' . +'\x{5A76}\x{5A77}\x{5A78}\x{5A79}\x{5A7A}\x{5A7B}\x{5A7C}\x{5A7D}\x{5A7E}' . +'\x{5A7F}\x{5A80}\x{5A81}\x{5A82}\x{5A83}\x{5A84}\x{5A85}\x{5A86}\x{5A88}' . +'\x{5A89}\x{5A8A}\x{5A8B}\x{5A8C}\x{5A8E}\x{5A8F}\x{5A90}\x{5A91}\x{5A92}' . +'\x{5A93}\x{5A94}\x{5A95}\x{5A96}\x{5A97}\x{5A98}\x{5A99}\x{5A9A}\x{5A9B}' . +'\x{5A9C}\x{5A9D}\x{5A9E}\x{5A9F}\x{5AA0}\x{5AA1}\x{5AA2}\x{5AA3}\x{5AA4}' . +'\x{5AA5}\x{5AA6}\x{5AA7}\x{5AA8}\x{5AA9}\x{5AAA}\x{5AAC}\x{5AAD}\x{5AAE}' . +'\x{5AAF}\x{5AB0}\x{5AB1}\x{5AB2}\x{5AB3}\x{5AB4}\x{5AB5}\x{5AB6}\x{5AB7}' . +'\x{5AB8}\x{5AB9}\x{5ABA}\x{5ABB}\x{5ABC}\x{5ABD}\x{5ABE}\x{5ABF}\x{5AC0}' . +'\x{5AC1}\x{5AC2}\x{5AC3}\x{5AC4}\x{5AC5}\x{5AC6}\x{5AC7}\x{5AC8}\x{5AC9}' . +'\x{5ACA}\x{5ACB}\x{5ACC}\x{5ACD}\x{5ACE}\x{5ACF}\x{5AD1}\x{5AD2}\x{5AD4}' . +'\x{5AD5}\x{5AD6}\x{5AD7}\x{5AD8}\x{5AD9}\x{5ADA}\x{5ADB}\x{5ADC}\x{5ADD}' . +'\x{5ADE}\x{5ADF}\x{5AE0}\x{5AE1}\x{5AE2}\x{5AE3}\x{5AE4}\x{5AE5}\x{5AE6}' . +'\x{5AE7}\x{5AE8}\x{5AE9}\x{5AEA}\x{5AEB}\x{5AEC}\x{5AED}\x{5AEE}\x{5AF1}' . +'\x{5AF2}\x{5AF3}\x{5AF4}\x{5AF5}\x{5AF6}\x{5AF7}\x{5AF8}\x{5AF9}\x{5AFA}' . +'\x{5AFB}\x{5AFC}\x{5AFD}\x{5AFE}\x{5AFF}\x{5B00}\x{5B01}\x{5B02}\x{5B03}' . +'\x{5B04}\x{5B05}\x{5B06}\x{5B07}\x{5B08}\x{5B09}\x{5B0B}\x{5B0C}\x{5B0E}' . +'\x{5B0F}\x{5B10}\x{5B11}\x{5B12}\x{5B13}\x{5B14}\x{5B15}\x{5B16}\x{5B17}' . +'\x{5B18}\x{5B19}\x{5B1A}\x{5B1B}\x{5B1C}\x{5B1D}\x{5B1E}\x{5B1F}\x{5B20}' . +'\x{5B21}\x{5B22}\x{5B23}\x{5B24}\x{5B25}\x{5B26}\x{5B27}\x{5B28}\x{5B29}' . +'\x{5B2A}\x{5B2B}\x{5B2C}\x{5B2D}\x{5B2E}\x{5B2F}\x{5B30}\x{5B31}\x{5B32}' . +'\x{5B33}\x{5B34}\x{5B35}\x{5B36}\x{5B37}\x{5B38}\x{5B3A}\x{5B3B}\x{5B3C}' . +'\x{5B3D}\x{5B3E}\x{5B3F}\x{5B40}\x{5B41}\x{5B42}\x{5B43}\x{5B44}\x{5B45}' . +'\x{5B47}\x{5B48}\x{5B49}\x{5B4A}\x{5B4B}\x{5B4C}\x{5B4D}\x{5B4E}\x{5B50}' . +'\x{5B51}\x{5B53}\x{5B54}\x{5B55}\x{5B56}\x{5B57}\x{5B58}\x{5B59}\x{5B5A}' . +'\x{5B5B}\x{5B5C}\x{5B5D}\x{5B5E}\x{5B5F}\x{5B62}\x{5B63}\x{5B64}\x{5B65}' . +'\x{5B66}\x{5B67}\x{5B68}\x{5B69}\x{5B6A}\x{5B6B}\x{5B6C}\x{5B6D}\x{5B6E}' . +'\x{5B70}\x{5B71}\x{5B72}\x{5B73}\x{5B74}\x{5B75}\x{5B76}\x{5B77}\x{5B78}' . +'\x{5B7A}\x{5B7B}\x{5B7C}\x{5B7D}\x{5B7F}\x{5B80}\x{5B81}\x{5B82}\x{5B83}' . +'\x{5B84}\x{5B85}\x{5B87}\x{5B88}\x{5B89}\x{5B8A}\x{5B8B}\x{5B8C}\x{5B8D}' . +'\x{5B8E}\x{5B8F}\x{5B91}\x{5B92}\x{5B93}\x{5B94}\x{5B95}\x{5B96}\x{5B97}' . +'\x{5B98}\x{5B99}\x{5B9A}\x{5B9B}\x{5B9C}\x{5B9D}\x{5B9E}\x{5B9F}\x{5BA0}' . +'\x{5BA1}\x{5BA2}\x{5BA3}\x{5BA4}\x{5BA5}\x{5BA6}\x{5BA7}\x{5BA8}\x{5BAA}' . +'\x{5BAB}\x{5BAC}\x{5BAD}\x{5BAE}\x{5BAF}\x{5BB0}\x{5BB1}\x{5BB3}\x{5BB4}' . +'\x{5BB5}\x{5BB6}\x{5BB8}\x{5BB9}\x{5BBA}\x{5BBB}\x{5BBD}\x{5BBE}\x{5BBF}' . +'\x{5BC0}\x{5BC1}\x{5BC2}\x{5BC3}\x{5BC4}\x{5BC5}\x{5BC6}\x{5BC7}\x{5BCA}' . +'\x{5BCB}\x{5BCC}\x{5BCD}\x{5BCE}\x{5BCF}\x{5BD0}\x{5BD1}\x{5BD2}\x{5BD3}' . +'\x{5BD4}\x{5BD5}\x{5BD6}\x{5BD8}\x{5BD9}\x{5BDB}\x{5BDC}\x{5BDD}\x{5BDE}' . +'\x{5BDF}\x{5BE0}\x{5BE1}\x{5BE2}\x{5BE3}\x{5BE4}\x{5BE5}\x{5BE6}\x{5BE7}' . +'\x{5BE8}\x{5BE9}\x{5BEA}\x{5BEB}\x{5BEC}\x{5BED}\x{5BEE}\x{5BEF}\x{5BF0}' . +'\x{5BF1}\x{5BF2}\x{5BF3}\x{5BF4}\x{5BF5}\x{5BF6}\x{5BF7}\x{5BF8}\x{5BF9}' . +'\x{5BFA}\x{5BFB}\x{5BFC}\x{5BFD}\x{5BFF}\x{5C01}\x{5C03}\x{5C04}\x{5C05}' . +'\x{5C06}\x{5C07}\x{5C08}\x{5C09}\x{5C0A}\x{5C0B}\x{5C0C}\x{5C0D}\x{5C0E}' . +'\x{5C0F}\x{5C10}\x{5C11}\x{5C12}\x{5C13}\x{5C14}\x{5C15}\x{5C16}\x{5C17}' . +'\x{5C18}\x{5C19}\x{5C1A}\x{5C1C}\x{5C1D}\x{5C1E}\x{5C1F}\x{5C20}\x{5C21}' . +'\x{5C22}\x{5C24}\x{5C25}\x{5C27}\x{5C28}\x{5C2A}\x{5C2B}\x{5C2C}\x{5C2D}' . +'\x{5C2E}\x{5C2F}\x{5C30}\x{5C31}\x{5C32}\x{5C33}\x{5C34}\x{5C35}\x{5C37}' . +'\x{5C38}\x{5C39}\x{5C3A}\x{5C3B}\x{5C3C}\x{5C3D}\x{5C3E}\x{5C3F}\x{5C40}' . +'\x{5C41}\x{5C42}\x{5C43}\x{5C44}\x{5C45}\x{5C46}\x{5C47}\x{5C48}\x{5C49}' . +'\x{5C4A}\x{5C4B}\x{5C4C}\x{5C4D}\x{5C4E}\x{5C4F}\x{5C50}\x{5C51}\x{5C52}' . +'\x{5C53}\x{5C54}\x{5C55}\x{5C56}\x{5C57}\x{5C58}\x{5C59}\x{5C5B}\x{5C5C}' . +'\x{5C5D}\x{5C5E}\x{5C5F}\x{5C60}\x{5C61}\x{5C62}\x{5C63}\x{5C64}\x{5C65}' . +'\x{5C66}\x{5C67}\x{5C68}\x{5C69}\x{5C6A}\x{5C6B}\x{5C6C}\x{5C6D}\x{5C6E}' . +'\x{5C6F}\x{5C70}\x{5C71}\x{5C72}\x{5C73}\x{5C74}\x{5C75}\x{5C76}\x{5C77}' . +'\x{5C78}\x{5C79}\x{5C7A}\x{5C7B}\x{5C7C}\x{5C7D}\x{5C7E}\x{5C7F}\x{5C80}' . +'\x{5C81}\x{5C82}\x{5C83}\x{5C84}\x{5C86}\x{5C87}\x{5C88}\x{5C89}\x{5C8A}' . +'\x{5C8B}\x{5C8C}\x{5C8D}\x{5C8E}\x{5C8F}\x{5C90}\x{5C91}\x{5C92}\x{5C93}' . +'\x{5C94}\x{5C95}\x{5C96}\x{5C97}\x{5C98}\x{5C99}\x{5C9A}\x{5C9B}\x{5C9C}' . +'\x{5C9D}\x{5C9E}\x{5C9F}\x{5CA0}\x{5CA1}\x{5CA2}\x{5CA3}\x{5CA4}\x{5CA5}' . +'\x{5CA6}\x{5CA7}\x{5CA8}\x{5CA9}\x{5CAA}\x{5CAB}\x{5CAC}\x{5CAD}\x{5CAE}' . +'\x{5CAF}\x{5CB0}\x{5CB1}\x{5CB2}\x{5CB3}\x{5CB5}\x{5CB6}\x{5CB7}\x{5CB8}' . +'\x{5CBA}\x{5CBB}\x{5CBC}\x{5CBD}\x{5CBE}\x{5CBF}\x{5CC1}\x{5CC2}\x{5CC3}' . +'\x{5CC4}\x{5CC5}\x{5CC6}\x{5CC7}\x{5CC8}\x{5CC9}\x{5CCA}\x{5CCB}\x{5CCC}' . +'\x{5CCD}\x{5CCE}\x{5CCF}\x{5CD0}\x{5CD1}\x{5CD2}\x{5CD3}\x{5CD4}\x{5CD6}' . +'\x{5CD7}\x{5CD8}\x{5CD9}\x{5CDA}\x{5CDB}\x{5CDC}\x{5CDE}\x{5CDF}\x{5CE0}' . +'\x{5CE1}\x{5CE2}\x{5CE3}\x{5CE4}\x{5CE5}\x{5CE6}\x{5CE7}\x{5CE8}\x{5CE9}' . +'\x{5CEA}\x{5CEB}\x{5CEC}\x{5CED}\x{5CEE}\x{5CEF}\x{5CF0}\x{5CF1}\x{5CF2}' . +'\x{5CF3}\x{5CF4}\x{5CF6}\x{5CF7}\x{5CF8}\x{5CF9}\x{5CFA}\x{5CFB}\x{5CFC}' . +'\x{5CFD}\x{5CFE}\x{5CFF}\x{5D00}\x{5D01}\x{5D02}\x{5D03}\x{5D04}\x{5D05}' . +'\x{5D06}\x{5D07}\x{5D08}\x{5D09}\x{5D0A}\x{5D0B}\x{5D0C}\x{5D0D}\x{5D0E}' . +'\x{5D0F}\x{5D10}\x{5D11}\x{5D12}\x{5D13}\x{5D14}\x{5D15}\x{5D16}\x{5D17}' . +'\x{5D18}\x{5D19}\x{5D1A}\x{5D1B}\x{5D1C}\x{5D1D}\x{5D1E}\x{5D1F}\x{5D20}' . +'\x{5D21}\x{5D22}\x{5D23}\x{5D24}\x{5D25}\x{5D26}\x{5D27}\x{5D28}\x{5D29}' . +'\x{5D2A}\x{5D2C}\x{5D2D}\x{5D2E}\x{5D30}\x{5D31}\x{5D32}\x{5D33}\x{5D34}' . +'\x{5D35}\x{5D36}\x{5D37}\x{5D38}\x{5D39}\x{5D3A}\x{5D3C}\x{5D3D}\x{5D3E}' . +'\x{5D3F}\x{5D40}\x{5D41}\x{5D42}\x{5D43}\x{5D44}\x{5D45}\x{5D46}\x{5D47}' . +'\x{5D48}\x{5D49}\x{5D4A}\x{5D4B}\x{5D4C}\x{5D4D}\x{5D4E}\x{5D4F}\x{5D50}' . +'\x{5D51}\x{5D52}\x{5D54}\x{5D55}\x{5D56}\x{5D58}\x{5D59}\x{5D5A}\x{5D5B}' . +'\x{5D5D}\x{5D5E}\x{5D5F}\x{5D61}\x{5D62}\x{5D63}\x{5D64}\x{5D65}\x{5D66}' . +'\x{5D67}\x{5D68}\x{5D69}\x{5D6A}\x{5D6B}\x{5D6C}\x{5D6D}\x{5D6E}\x{5D6F}' . +'\x{5D70}\x{5D71}\x{5D72}\x{5D73}\x{5D74}\x{5D75}\x{5D76}\x{5D77}\x{5D78}' . +'\x{5D79}\x{5D7A}\x{5D7B}\x{5D7C}\x{5D7D}\x{5D7E}\x{5D7F}\x{5D80}\x{5D81}' . +'\x{5D82}\x{5D84}\x{5D85}\x{5D86}\x{5D87}\x{5D88}\x{5D89}\x{5D8A}\x{5D8B}' . +'\x{5D8C}\x{5D8D}\x{5D8E}\x{5D8F}\x{5D90}\x{5D91}\x{5D92}\x{5D93}\x{5D94}' . +'\x{5D95}\x{5D97}\x{5D98}\x{5D99}\x{5D9A}\x{5D9B}\x{5D9C}\x{5D9D}\x{5D9E}' . +'\x{5D9F}\x{5DA0}\x{5DA1}\x{5DA2}\x{5DA5}\x{5DA6}\x{5DA7}\x{5DA8}\x{5DA9}' . +'\x{5DAA}\x{5DAC}\x{5DAD}\x{5DAE}\x{5DAF}\x{5DB0}\x{5DB1}\x{5DB2}\x{5DB4}' . +'\x{5DB5}\x{5DB6}\x{5DB7}\x{5DB8}\x{5DBA}\x{5DBB}\x{5DBC}\x{5DBD}\x{5DBE}' . +'\x{5DBF}\x{5DC0}\x{5DC1}\x{5DC2}\x{5DC3}\x{5DC5}\x{5DC6}\x{5DC7}\x{5DC8}' . +'\x{5DC9}\x{5DCA}\x{5DCB}\x{5DCC}\x{5DCD}\x{5DCE}\x{5DCF}\x{5DD0}\x{5DD1}' . +'\x{5DD2}\x{5DD3}\x{5DD4}\x{5DD5}\x{5DD6}\x{5DD8}\x{5DD9}\x{5DDB}\x{5DDD}' . +'\x{5DDE}\x{5DDF}\x{5DE0}\x{5DE1}\x{5DE2}\x{5DE3}\x{5DE4}\x{5DE5}\x{5DE6}' . +'\x{5DE7}\x{5DE8}\x{5DE9}\x{5DEA}\x{5DEB}\x{5DEC}\x{5DED}\x{5DEE}\x{5DEF}' . +'\x{5DF0}\x{5DF1}\x{5DF2}\x{5DF3}\x{5DF4}\x{5DF5}\x{5DF7}\x{5DF8}\x{5DF9}' . +'\x{5DFA}\x{5DFB}\x{5DFC}\x{5DFD}\x{5DFE}\x{5DFF}\x{5E00}\x{5E01}\x{5E02}' . +'\x{5E03}\x{5E04}\x{5E05}\x{5E06}\x{5E07}\x{5E08}\x{5E09}\x{5E0A}\x{5E0B}' . +'\x{5E0C}\x{5E0D}\x{5E0E}\x{5E0F}\x{5E10}\x{5E11}\x{5E13}\x{5E14}\x{5E15}' . +'\x{5E16}\x{5E17}\x{5E18}\x{5E19}\x{5E1A}\x{5E1B}\x{5E1C}\x{5E1D}\x{5E1E}' . +'\x{5E1F}\x{5E20}\x{5E21}\x{5E22}\x{5E23}\x{5E24}\x{5E25}\x{5E26}\x{5E27}' . +'\x{5E28}\x{5E29}\x{5E2A}\x{5E2B}\x{5E2C}\x{5E2D}\x{5E2E}\x{5E2F}\x{5E30}' . +'\x{5E31}\x{5E32}\x{5E33}\x{5E34}\x{5E35}\x{5E36}\x{5E37}\x{5E38}\x{5E39}' . +'\x{5E3A}\x{5E3B}\x{5E3C}\x{5E3D}\x{5E3E}\x{5E40}\x{5E41}\x{5E42}\x{5E43}' . +'\x{5E44}\x{5E45}\x{5E46}\x{5E47}\x{5E49}\x{5E4A}\x{5E4B}\x{5E4C}\x{5E4D}' . +'\x{5E4E}\x{5E4F}\x{5E50}\x{5E52}\x{5E53}\x{5E54}\x{5E55}\x{5E56}\x{5E57}' . +'\x{5E58}\x{5E59}\x{5E5A}\x{5E5B}\x{5E5C}\x{5E5D}\x{5E5E}\x{5E5F}\x{5E60}' . +'\x{5E61}\x{5E62}\x{5E63}\x{5E64}\x{5E65}\x{5E66}\x{5E67}\x{5E68}\x{5E69}' . +'\x{5E6A}\x{5E6B}\x{5E6C}\x{5E6D}\x{5E6E}\x{5E6F}\x{5E70}\x{5E71}\x{5E72}' . +'\x{5E73}\x{5E74}\x{5E75}\x{5E76}\x{5E77}\x{5E78}\x{5E79}\x{5E7A}\x{5E7B}' . +'\x{5E7C}\x{5E7D}\x{5E7E}\x{5E7F}\x{5E80}\x{5E81}\x{5E82}\x{5E83}\x{5E84}' . +'\x{5E85}\x{5E86}\x{5E87}\x{5E88}\x{5E89}\x{5E8A}\x{5E8B}\x{5E8C}\x{5E8D}' . +'\x{5E8E}\x{5E8F}\x{5E90}\x{5E91}\x{5E93}\x{5E94}\x{5E95}\x{5E96}\x{5E97}' . +'\x{5E98}\x{5E99}\x{5E9A}\x{5E9B}\x{5E9C}\x{5E9D}\x{5E9E}\x{5E9F}\x{5EA0}' . +'\x{5EA1}\x{5EA2}\x{5EA3}\x{5EA4}\x{5EA5}\x{5EA6}\x{5EA7}\x{5EA8}\x{5EA9}' . +'\x{5EAA}\x{5EAB}\x{5EAC}\x{5EAD}\x{5EAE}\x{5EAF}\x{5EB0}\x{5EB1}\x{5EB2}' . +'\x{5EB3}\x{5EB4}\x{5EB5}\x{5EB6}\x{5EB7}\x{5EB8}\x{5EB9}\x{5EBB}\x{5EBC}' . +'\x{5EBD}\x{5EBE}\x{5EBF}\x{5EC1}\x{5EC2}\x{5EC3}\x{5EC4}\x{5EC5}\x{5EC6}' . +'\x{5EC7}\x{5EC8}\x{5EC9}\x{5ECA}\x{5ECB}\x{5ECC}\x{5ECD}\x{5ECE}\x{5ECF}' . +'\x{5ED0}\x{5ED1}\x{5ED2}\x{5ED3}\x{5ED4}\x{5ED5}\x{5ED6}\x{5ED7}\x{5ED8}' . +'\x{5ED9}\x{5EDA}\x{5EDB}\x{5EDC}\x{5EDD}\x{5EDE}\x{5EDF}\x{5EE0}\x{5EE1}' . +'\x{5EE2}\x{5EE3}\x{5EE4}\x{5EE5}\x{5EE6}\x{5EE7}\x{5EE8}\x{5EE9}\x{5EEA}' . +'\x{5EEC}\x{5EED}\x{5EEE}\x{5EEF}\x{5EF0}\x{5EF1}\x{5EF2}\x{5EF3}\x{5EF4}' . +'\x{5EF5}\x{5EF6}\x{5EF7}\x{5EF8}\x{5EFA}\x{5EFB}\x{5EFC}\x{5EFD}\x{5EFE}' . +'\x{5EFF}\x{5F00}\x{5F01}\x{5F02}\x{5F03}\x{5F04}\x{5F05}\x{5F06}\x{5F07}' . +'\x{5F08}\x{5F0A}\x{5F0B}\x{5F0C}\x{5F0D}\x{5F0F}\x{5F11}\x{5F12}\x{5F13}' . +'\x{5F14}\x{5F15}\x{5F16}\x{5F17}\x{5F18}\x{5F19}\x{5F1A}\x{5F1B}\x{5F1C}' . +'\x{5F1D}\x{5F1E}\x{5F1F}\x{5F20}\x{5F21}\x{5F22}\x{5F23}\x{5F24}\x{5F25}' . +'\x{5F26}\x{5F27}\x{5F28}\x{5F29}\x{5F2A}\x{5F2B}\x{5F2C}\x{5F2D}\x{5F2E}' . +'\x{5F2F}\x{5F30}\x{5F31}\x{5F32}\x{5F33}\x{5F34}\x{5F35}\x{5F36}\x{5F37}' . +'\x{5F38}\x{5F39}\x{5F3A}\x{5F3C}\x{5F3E}\x{5F3F}\x{5F40}\x{5F41}\x{5F42}' . +'\x{5F43}\x{5F44}\x{5F45}\x{5F46}\x{5F47}\x{5F48}\x{5F49}\x{5F4A}\x{5F4B}' . +'\x{5F4C}\x{5F4D}\x{5F4E}\x{5F4F}\x{5F50}\x{5F51}\x{5F52}\x{5F53}\x{5F54}' . +'\x{5F55}\x{5F56}\x{5F57}\x{5F58}\x{5F59}\x{5F5A}\x{5F5B}\x{5F5C}\x{5F5D}' . +'\x{5F5E}\x{5F5F}\x{5F60}\x{5F61}\x{5F62}\x{5F63}\x{5F64}\x{5F65}\x{5F66}' . +'\x{5F67}\x{5F68}\x{5F69}\x{5F6A}\x{5F6B}\x{5F6C}\x{5F6D}\x{5F6E}\x{5F6F}' . +'\x{5F70}\x{5F71}\x{5F72}\x{5F73}\x{5F74}\x{5F75}\x{5F76}\x{5F77}\x{5F78}' . +'\x{5F79}\x{5F7A}\x{5F7B}\x{5F7C}\x{5F7D}\x{5F7E}\x{5F7F}\x{5F80}\x{5F81}' . +'\x{5F82}\x{5F83}\x{5F84}\x{5F85}\x{5F86}\x{5F87}\x{5F88}\x{5F89}\x{5F8A}' . +'\x{5F8B}\x{5F8C}\x{5F8D}\x{5F8E}\x{5F90}\x{5F91}\x{5F92}\x{5F93}\x{5F94}' . +'\x{5F95}\x{5F96}\x{5F97}\x{5F98}\x{5F99}\x{5F9B}\x{5F9C}\x{5F9D}\x{5F9E}' . +'\x{5F9F}\x{5FA0}\x{5FA1}\x{5FA2}\x{5FA5}\x{5FA6}\x{5FA7}\x{5FA8}\x{5FA9}' . +'\x{5FAA}\x{5FAB}\x{5FAC}\x{5FAD}\x{5FAE}\x{5FAF}\x{5FB1}\x{5FB2}\x{5FB3}' . +'\x{5FB4}\x{5FB5}\x{5FB6}\x{5FB7}\x{5FB8}\x{5FB9}\x{5FBA}\x{5FBB}\x{5FBC}' . +'\x{5FBD}\x{5FBE}\x{5FBF}\x{5FC0}\x{5FC1}\x{5FC3}\x{5FC4}\x{5FC5}\x{5FC6}' . +'\x{5FC7}\x{5FC8}\x{5FC9}\x{5FCA}\x{5FCB}\x{5FCC}\x{5FCD}\x{5FCF}\x{5FD0}' . +'\x{5FD1}\x{5FD2}\x{5FD3}\x{5FD4}\x{5FD5}\x{5FD6}\x{5FD7}\x{5FD8}\x{5FD9}' . +'\x{5FDA}\x{5FDC}\x{5FDD}\x{5FDE}\x{5FE0}\x{5FE1}\x{5FE3}\x{5FE4}\x{5FE5}' . +'\x{5FE6}\x{5FE7}\x{5FE8}\x{5FE9}\x{5FEA}\x{5FEB}\x{5FED}\x{5FEE}\x{5FEF}' . +'\x{5FF0}\x{5FF1}\x{5FF2}\x{5FF3}\x{5FF4}\x{5FF5}\x{5FF6}\x{5FF7}\x{5FF8}' . +'\x{5FF9}\x{5FFA}\x{5FFB}\x{5FFD}\x{5FFE}\x{5FFF}\x{6000}\x{6001}\x{6002}' . +'\x{6003}\x{6004}\x{6005}\x{6006}\x{6007}\x{6008}\x{6009}\x{600A}\x{600B}' . +'\x{600C}\x{600D}\x{600E}\x{600F}\x{6010}\x{6011}\x{6012}\x{6013}\x{6014}' . +'\x{6015}\x{6016}\x{6017}\x{6018}\x{6019}\x{601A}\x{601B}\x{601C}\x{601D}' . +'\x{601E}\x{601F}\x{6020}\x{6021}\x{6022}\x{6024}\x{6025}\x{6026}\x{6027}' . +'\x{6028}\x{6029}\x{602A}\x{602B}\x{602C}\x{602D}\x{602E}\x{602F}\x{6030}' . +'\x{6031}\x{6032}\x{6033}\x{6034}\x{6035}\x{6036}\x{6037}\x{6038}\x{6039}' . +'\x{603A}\x{603B}\x{603C}\x{603D}\x{603E}\x{603F}\x{6040}\x{6041}\x{6042}' . +'\x{6043}\x{6044}\x{6045}\x{6046}\x{6047}\x{6048}\x{6049}\x{604A}\x{604B}' . +'\x{604C}\x{604D}\x{604E}\x{604F}\x{6050}\x{6051}\x{6052}\x{6053}\x{6054}' . +'\x{6055}\x{6057}\x{6058}\x{6059}\x{605A}\x{605B}\x{605C}\x{605D}\x{605E}' . +'\x{605F}\x{6062}\x{6063}\x{6064}\x{6065}\x{6066}\x{6067}\x{6068}\x{6069}' . +'\x{606A}\x{606B}\x{606C}\x{606D}\x{606E}\x{606F}\x{6070}\x{6072}\x{6073}' . +'\x{6075}\x{6076}\x{6077}\x{6078}\x{6079}\x{607A}\x{607B}\x{607C}\x{607D}' . +'\x{607E}\x{607F}\x{6080}\x{6081}\x{6082}\x{6083}\x{6084}\x{6085}\x{6086}' . +'\x{6087}\x{6088}\x{6089}\x{608A}\x{608B}\x{608C}\x{608D}\x{608E}\x{608F}' . +'\x{6090}\x{6092}\x{6094}\x{6095}\x{6096}\x{6097}\x{6098}\x{6099}\x{609A}' . +'\x{609B}\x{609C}\x{609D}\x{609E}\x{609F}\x{60A0}\x{60A1}\x{60A2}\x{60A3}' . +'\x{60A4}\x{60A6}\x{60A7}\x{60A8}\x{60AA}\x{60AB}\x{60AC}\x{60AD}\x{60AE}' . +'\x{60AF}\x{60B0}\x{60B1}\x{60B2}\x{60B3}\x{60B4}\x{60B5}\x{60B6}\x{60B7}' . +'\x{60B8}\x{60B9}\x{60BA}\x{60BB}\x{60BC}\x{60BD}\x{60BE}\x{60BF}\x{60C0}' . +'\x{60C1}\x{60C2}\x{60C3}\x{60C4}\x{60C5}\x{60C6}\x{60C7}\x{60C8}\x{60C9}' . +'\x{60CA}\x{60CB}\x{60CC}\x{60CD}\x{60CE}\x{60CF}\x{60D0}\x{60D1}\x{60D3}' . +'\x{60D4}\x{60D5}\x{60D7}\x{60D8}\x{60D9}\x{60DA}\x{60DB}\x{60DC}\x{60DD}' . +'\x{60DF}\x{60E0}\x{60E1}\x{60E2}\x{60E4}\x{60E6}\x{60E7}\x{60E8}\x{60E9}' . +'\x{60EA}\x{60EB}\x{60EC}\x{60ED}\x{60EE}\x{60EF}\x{60F0}\x{60F1}\x{60F2}' . +'\x{60F3}\x{60F4}\x{60F5}\x{60F6}\x{60F7}\x{60F8}\x{60F9}\x{60FA}\x{60FB}' . +'\x{60FC}\x{60FE}\x{60FF}\x{6100}\x{6101}\x{6103}\x{6104}\x{6105}\x{6106}' . +'\x{6108}\x{6109}\x{610A}\x{610B}\x{610C}\x{610D}\x{610E}\x{610F}\x{6110}' . +'\x{6112}\x{6113}\x{6114}\x{6115}\x{6116}\x{6117}\x{6118}\x{6119}\x{611A}' . +'\x{611B}\x{611C}\x{611D}\x{611F}\x{6120}\x{6122}\x{6123}\x{6124}\x{6125}' . +'\x{6126}\x{6127}\x{6128}\x{6129}\x{612A}\x{612B}\x{612C}\x{612D}\x{612E}' . +'\x{612F}\x{6130}\x{6132}\x{6134}\x{6136}\x{6137}\x{613A}\x{613B}\x{613C}' . +'\x{613D}\x{613E}\x{613F}\x{6140}\x{6141}\x{6142}\x{6143}\x{6144}\x{6145}' . +'\x{6146}\x{6147}\x{6148}\x{6149}\x{614A}\x{614B}\x{614C}\x{614D}\x{614E}' . +'\x{614F}\x{6150}\x{6151}\x{6152}\x{6153}\x{6154}\x{6155}\x{6156}\x{6157}' . +'\x{6158}\x{6159}\x{615A}\x{615B}\x{615C}\x{615D}\x{615E}\x{615F}\x{6161}' . +'\x{6162}\x{6163}\x{6164}\x{6165}\x{6166}\x{6167}\x{6168}\x{6169}\x{616A}' . +'\x{616B}\x{616C}\x{616D}\x{616E}\x{6170}\x{6171}\x{6172}\x{6173}\x{6174}' . +'\x{6175}\x{6176}\x{6177}\x{6178}\x{6179}\x{617A}\x{617C}\x{617E}\x{6180}' . +'\x{6181}\x{6182}\x{6183}\x{6184}\x{6185}\x{6187}\x{6188}\x{6189}\x{618A}' . +'\x{618B}\x{618C}\x{618D}\x{618E}\x{618F}\x{6190}\x{6191}\x{6192}\x{6193}' . +'\x{6194}\x{6195}\x{6196}\x{6198}\x{6199}\x{619A}\x{619B}\x{619D}\x{619E}' . +'\x{619F}\x{61A0}\x{61A1}\x{61A2}\x{61A3}\x{61A4}\x{61A5}\x{61A6}\x{61A7}' . +'\x{61A8}\x{61A9}\x{61AA}\x{61AB}\x{61AC}\x{61AD}\x{61AE}\x{61AF}\x{61B0}' . +'\x{61B1}\x{61B2}\x{61B3}\x{61B4}\x{61B5}\x{61B6}\x{61B7}\x{61B8}\x{61BA}' . +'\x{61BC}\x{61BD}\x{61BE}\x{61BF}\x{61C0}\x{61C1}\x{61C2}\x{61C3}\x{61C4}' . +'\x{61C5}\x{61C6}\x{61C7}\x{61C8}\x{61C9}\x{61CA}\x{61CB}\x{61CC}\x{61CD}' . +'\x{61CE}\x{61CF}\x{61D0}\x{61D1}\x{61D2}\x{61D4}\x{61D6}\x{61D7}\x{61D8}' . +'\x{61D9}\x{61DA}\x{61DB}\x{61DC}\x{61DD}\x{61DE}\x{61DF}\x{61E0}\x{61E1}' . +'\x{61E2}\x{61E3}\x{61E4}\x{61E5}\x{61E6}\x{61E7}\x{61E8}\x{61E9}\x{61EA}' . +'\x{61EB}\x{61ED}\x{61EE}\x{61F0}\x{61F1}\x{61F2}\x{61F3}\x{61F5}\x{61F6}' . +'\x{61F7}\x{61F8}\x{61F9}\x{61FA}\x{61FB}\x{61FC}\x{61FD}\x{61FE}\x{61FF}' . +'\x{6200}\x{6201}\x{6202}\x{6203}\x{6204}\x{6206}\x{6207}\x{6208}\x{6209}' . +'\x{620A}\x{620B}\x{620C}\x{620D}\x{620E}\x{620F}\x{6210}\x{6211}\x{6212}' . +'\x{6213}\x{6214}\x{6215}\x{6216}\x{6217}\x{6218}\x{6219}\x{621A}\x{621B}' . +'\x{621C}\x{621D}\x{621E}\x{621F}\x{6220}\x{6221}\x{6222}\x{6223}\x{6224}' . +'\x{6225}\x{6226}\x{6227}\x{6228}\x{6229}\x{622A}\x{622B}\x{622C}\x{622D}' . +'\x{622E}\x{622F}\x{6230}\x{6231}\x{6232}\x{6233}\x{6234}\x{6236}\x{6237}' . +'\x{6238}\x{623A}\x{623B}\x{623C}\x{623D}\x{623E}\x{623F}\x{6240}\x{6241}' . +'\x{6242}\x{6243}\x{6244}\x{6245}\x{6246}\x{6247}\x{6248}\x{6249}\x{624A}' . +'\x{624B}\x{624C}\x{624D}\x{624E}\x{624F}\x{6250}\x{6251}\x{6252}\x{6253}' . +'\x{6254}\x{6255}\x{6256}\x{6258}\x{6259}\x{625A}\x{625B}\x{625C}\x{625D}' . +'\x{625E}\x{625F}\x{6260}\x{6261}\x{6262}\x{6263}\x{6264}\x{6265}\x{6266}' . +'\x{6267}\x{6268}\x{6269}\x{626A}\x{626B}\x{626C}\x{626D}\x{626E}\x{626F}' . +'\x{6270}\x{6271}\x{6272}\x{6273}\x{6274}\x{6275}\x{6276}\x{6277}\x{6278}' . +'\x{6279}\x{627A}\x{627B}\x{627C}\x{627D}\x{627E}\x{627F}\x{6280}\x{6281}' . +'\x{6283}\x{6284}\x{6285}\x{6286}\x{6287}\x{6288}\x{6289}\x{628A}\x{628B}' . +'\x{628C}\x{628E}\x{628F}\x{6290}\x{6291}\x{6292}\x{6293}\x{6294}\x{6295}' . +'\x{6296}\x{6297}\x{6298}\x{6299}\x{629A}\x{629B}\x{629C}\x{629E}\x{629F}' . +'\x{62A0}\x{62A1}\x{62A2}\x{62A3}\x{62A4}\x{62A5}\x{62A7}\x{62A8}\x{62A9}' . +'\x{62AA}\x{62AB}\x{62AC}\x{62AD}\x{62AE}\x{62AF}\x{62B0}\x{62B1}\x{62B2}' . +'\x{62B3}\x{62B4}\x{62B5}\x{62B6}\x{62B7}\x{62B8}\x{62B9}\x{62BA}\x{62BB}' . +'\x{62BC}\x{62BD}\x{62BE}\x{62BF}\x{62C0}\x{62C1}\x{62C2}\x{62C3}\x{62C4}' . +'\x{62C5}\x{62C6}\x{62C7}\x{62C8}\x{62C9}\x{62CA}\x{62CB}\x{62CC}\x{62CD}' . +'\x{62CE}\x{62CF}\x{62D0}\x{62D1}\x{62D2}\x{62D3}\x{62D4}\x{62D5}\x{62D6}' . +'\x{62D7}\x{62D8}\x{62D9}\x{62DA}\x{62DB}\x{62DC}\x{62DD}\x{62DF}\x{62E0}' . +'\x{62E1}\x{62E2}\x{62E3}\x{62E4}\x{62E5}\x{62E6}\x{62E7}\x{62E8}\x{62E9}' . +'\x{62EB}\x{62EC}\x{62ED}\x{62EE}\x{62EF}\x{62F0}\x{62F1}\x{62F2}\x{62F3}' . +'\x{62F4}\x{62F5}\x{62F6}\x{62F7}\x{62F8}\x{62F9}\x{62FA}\x{62FB}\x{62FC}' . +'\x{62FD}\x{62FE}\x{62FF}\x{6300}\x{6301}\x{6302}\x{6303}\x{6304}\x{6305}' . +'\x{6306}\x{6307}\x{6308}\x{6309}\x{630B}\x{630C}\x{630D}\x{630E}\x{630F}' . +'\x{6310}\x{6311}\x{6312}\x{6313}\x{6314}\x{6315}\x{6316}\x{6318}\x{6319}' . +'\x{631A}\x{631B}\x{631C}\x{631D}\x{631E}\x{631F}\x{6320}\x{6321}\x{6322}' . +'\x{6323}\x{6324}\x{6325}\x{6326}\x{6327}\x{6328}\x{6329}\x{632A}\x{632B}' . +'\x{632C}\x{632D}\x{632E}\x{632F}\x{6330}\x{6332}\x{6333}\x{6334}\x{6336}' . +'\x{6338}\x{6339}\x{633A}\x{633B}\x{633C}\x{633D}\x{633E}\x{6340}\x{6341}' . +'\x{6342}\x{6343}\x{6344}\x{6345}\x{6346}\x{6347}\x{6348}\x{6349}\x{634A}' . +'\x{634B}\x{634C}\x{634D}\x{634E}\x{634F}\x{6350}\x{6351}\x{6352}\x{6353}' . +'\x{6354}\x{6355}\x{6356}\x{6357}\x{6358}\x{6359}\x{635A}\x{635C}\x{635D}' . +'\x{635E}\x{635F}\x{6360}\x{6361}\x{6362}\x{6363}\x{6364}\x{6365}\x{6366}' . +'\x{6367}\x{6368}\x{6369}\x{636A}\x{636B}\x{636C}\x{636D}\x{636E}\x{636F}' . +'\x{6370}\x{6371}\x{6372}\x{6373}\x{6374}\x{6375}\x{6376}\x{6377}\x{6378}' . +'\x{6379}\x{637A}\x{637B}\x{637C}\x{637D}\x{637E}\x{6380}\x{6381}\x{6382}' . +'\x{6383}\x{6384}\x{6385}\x{6386}\x{6387}\x{6388}\x{6389}\x{638A}\x{638C}' . +'\x{638D}\x{638E}\x{638F}\x{6390}\x{6391}\x{6392}\x{6394}\x{6395}\x{6396}' . +'\x{6397}\x{6398}\x{6399}\x{639A}\x{639B}\x{639C}\x{639D}\x{639E}\x{639F}' . +'\x{63A0}\x{63A1}\x{63A2}\x{63A3}\x{63A4}\x{63A5}\x{63A6}\x{63A7}\x{63A8}' . +'\x{63A9}\x{63AA}\x{63AB}\x{63AC}\x{63AD}\x{63AE}\x{63AF}\x{63B0}\x{63B1}' . +'\x{63B2}\x{63B3}\x{63B4}\x{63B5}\x{63B6}\x{63B7}\x{63B8}\x{63B9}\x{63BA}' . +'\x{63BC}\x{63BD}\x{63BE}\x{63BF}\x{63C0}\x{63C1}\x{63C2}\x{63C3}\x{63C4}' . +'\x{63C5}\x{63C6}\x{63C7}\x{63C8}\x{63C9}\x{63CA}\x{63CB}\x{63CC}\x{63CD}' . +'\x{63CE}\x{63CF}\x{63D0}\x{63D2}\x{63D3}\x{63D4}\x{63D5}\x{63D6}\x{63D7}' . +'\x{63D8}\x{63D9}\x{63DA}\x{63DB}\x{63DC}\x{63DD}\x{63DE}\x{63DF}\x{63E0}' . +'\x{63E1}\x{63E2}\x{63E3}\x{63E4}\x{63E5}\x{63E6}\x{63E7}\x{63E8}\x{63E9}' . +'\x{63EA}\x{63EB}\x{63EC}\x{63ED}\x{63EE}\x{63EF}\x{63F0}\x{63F1}\x{63F2}' . +'\x{63F3}\x{63F4}\x{63F5}\x{63F6}\x{63F7}\x{63F8}\x{63F9}\x{63FA}\x{63FB}' . +'\x{63FC}\x{63FD}\x{63FE}\x{63FF}\x{6400}\x{6401}\x{6402}\x{6403}\x{6404}' . +'\x{6405}\x{6406}\x{6408}\x{6409}\x{640A}\x{640B}\x{640C}\x{640D}\x{640E}' . +'\x{640F}\x{6410}\x{6411}\x{6412}\x{6413}\x{6414}\x{6415}\x{6416}\x{6417}' . +'\x{6418}\x{6419}\x{641A}\x{641B}\x{641C}\x{641D}\x{641E}\x{641F}\x{6420}' . +'\x{6421}\x{6422}\x{6423}\x{6424}\x{6425}\x{6426}\x{6427}\x{6428}\x{6429}' . +'\x{642A}\x{642B}\x{642C}\x{642D}\x{642E}\x{642F}\x{6430}\x{6431}\x{6432}' . +'\x{6433}\x{6434}\x{6435}\x{6436}\x{6437}\x{6438}\x{6439}\x{643A}\x{643D}' . +'\x{643E}\x{643F}\x{6440}\x{6441}\x{6443}\x{6444}\x{6445}\x{6446}\x{6447}' . +'\x{6448}\x{644A}\x{644B}\x{644C}\x{644D}\x{644E}\x{644F}\x{6450}\x{6451}' . +'\x{6452}\x{6453}\x{6454}\x{6455}\x{6456}\x{6457}\x{6458}\x{6459}\x{645B}' . +'\x{645C}\x{645D}\x{645E}\x{645F}\x{6460}\x{6461}\x{6462}\x{6463}\x{6464}' . +'\x{6465}\x{6466}\x{6467}\x{6468}\x{6469}\x{646A}\x{646B}\x{646C}\x{646D}' . +'\x{646E}\x{646F}\x{6470}\x{6471}\x{6472}\x{6473}\x{6474}\x{6475}\x{6476}' . +'\x{6477}\x{6478}\x{6479}\x{647A}\x{647B}\x{647C}\x{647D}\x{647F}\x{6480}' . +'\x{6481}\x{6482}\x{6483}\x{6484}\x{6485}\x{6487}\x{6488}\x{6489}\x{648A}' . +'\x{648B}\x{648C}\x{648D}\x{648E}\x{648F}\x{6490}\x{6491}\x{6492}\x{6493}' . +'\x{6494}\x{6495}\x{6496}\x{6497}\x{6498}\x{6499}\x{649A}\x{649B}\x{649C}' . +'\x{649D}\x{649E}\x{649F}\x{64A0}\x{64A2}\x{64A3}\x{64A4}\x{64A5}\x{64A6}' . +'\x{64A7}\x{64A8}\x{64A9}\x{64AA}\x{64AB}\x{64AC}\x{64AD}\x{64AE}\x{64B0}' . +'\x{64B1}\x{64B2}\x{64B3}\x{64B4}\x{64B5}\x{64B7}\x{64B8}\x{64B9}\x{64BA}' . +'\x{64BB}\x{64BC}\x{64BD}\x{64BE}\x{64BF}\x{64C0}\x{64C1}\x{64C2}\x{64C3}' . +'\x{64C4}\x{64C5}\x{64C6}\x{64C7}\x{64C9}\x{64CA}\x{64CB}\x{64CC}\x{64CD}' . +'\x{64CE}\x{64CF}\x{64D0}\x{64D1}\x{64D2}\x{64D3}\x{64D4}\x{64D6}\x{64D7}' . +'\x{64D8}\x{64D9}\x{64DA}\x{64DB}\x{64DC}\x{64DD}\x{64DE}\x{64DF}\x{64E0}' . +'\x{64E2}\x{64E3}\x{64E4}\x{64E6}\x{64E7}\x{64E8}\x{64E9}\x{64EA}\x{64EB}' . +'\x{64EC}\x{64ED}\x{64EF}\x{64F0}\x{64F1}\x{64F2}\x{64F3}\x{64F4}\x{64F6}' . +'\x{64F7}\x{64F8}\x{64FA}\x{64FB}\x{64FC}\x{64FD}\x{64FE}\x{64FF}\x{6500}' . +'\x{6501}\x{6503}\x{6504}\x{6505}\x{6506}\x{6507}\x{6508}\x{6509}\x{650B}' . +'\x{650C}\x{650D}\x{650E}\x{650F}\x{6510}\x{6511}\x{6512}\x{6513}\x{6514}' . +'\x{6515}\x{6516}\x{6517}\x{6518}\x{6519}\x{651A}\x{651B}\x{651C}\x{651D}' . +'\x{651E}\x{6520}\x{6521}\x{6522}\x{6523}\x{6524}\x{6525}\x{6526}\x{6527}' . +'\x{6529}\x{652A}\x{652B}\x{652C}\x{652D}\x{652E}\x{652F}\x{6530}\x{6531}' . +'\x{6532}\x{6533}\x{6534}\x{6535}\x{6536}\x{6537}\x{6538}\x{6539}\x{653A}' . +'\x{653B}\x{653C}\x{653D}\x{653E}\x{653F}\x{6541}\x{6543}\x{6544}\x{6545}' . +'\x{6546}\x{6547}\x{6548}\x{6549}\x{654A}\x{654B}\x{654C}\x{654D}\x{654E}' . +'\x{654F}\x{6550}\x{6551}\x{6552}\x{6553}\x{6554}\x{6555}\x{6556}\x{6557}' . +'\x{6558}\x{6559}\x{655B}\x{655C}\x{655D}\x{655E}\x{6560}\x{6561}\x{6562}' . +'\x{6563}\x{6564}\x{6565}\x{6566}\x{6567}\x{6568}\x{6569}\x{656A}\x{656B}' . +'\x{656C}\x{656E}\x{656F}\x{6570}\x{6571}\x{6572}\x{6573}\x{6574}\x{6575}' . +'\x{6576}\x{6577}\x{6578}\x{6579}\x{657A}\x{657B}\x{657C}\x{657E}\x{657F}' . +'\x{6580}\x{6581}\x{6582}\x{6583}\x{6584}\x{6585}\x{6586}\x{6587}\x{6588}' . +'\x{6589}\x{658B}\x{658C}\x{658D}\x{658E}\x{658F}\x{6590}\x{6591}\x{6592}' . +'\x{6593}\x{6594}\x{6595}\x{6596}\x{6597}\x{6598}\x{6599}\x{659B}\x{659C}' . +'\x{659D}\x{659E}\x{659F}\x{65A0}\x{65A1}\x{65A2}\x{65A3}\x{65A4}\x{65A5}' . +'\x{65A6}\x{65A7}\x{65A8}\x{65A9}\x{65AA}\x{65AB}\x{65AC}\x{65AD}\x{65AE}' . +'\x{65AF}\x{65B0}\x{65B1}\x{65B2}\x{65B3}\x{65B4}\x{65B6}\x{65B7}\x{65B8}' . +'\x{65B9}\x{65BA}\x{65BB}\x{65BC}\x{65BD}\x{65BF}\x{65C0}\x{65C1}\x{65C2}' . +'\x{65C3}\x{65C4}\x{65C5}\x{65C6}\x{65C7}\x{65CA}\x{65CB}\x{65CC}\x{65CD}' . +'\x{65CE}\x{65CF}\x{65D0}\x{65D2}\x{65D3}\x{65D4}\x{65D5}\x{65D6}\x{65D7}' . +'\x{65DA}\x{65DB}\x{65DD}\x{65DE}\x{65DF}\x{65E0}\x{65E1}\x{65E2}\x{65E3}' . +'\x{65E5}\x{65E6}\x{65E7}\x{65E8}\x{65E9}\x{65EB}\x{65EC}\x{65ED}\x{65EE}' . +'\x{65EF}\x{65F0}\x{65F1}\x{65F2}\x{65F3}\x{65F4}\x{65F5}\x{65F6}\x{65F7}' . +'\x{65F8}\x{65FA}\x{65FB}\x{65FC}\x{65FD}\x{6600}\x{6601}\x{6602}\x{6603}' . +'\x{6604}\x{6605}\x{6606}\x{6607}\x{6608}\x{6609}\x{660A}\x{660B}\x{660C}' . +'\x{660D}\x{660E}\x{660F}\x{6610}\x{6611}\x{6612}\x{6613}\x{6614}\x{6615}' . +'\x{6616}\x{6618}\x{6619}\x{661A}\x{661B}\x{661C}\x{661D}\x{661F}\x{6620}' . +'\x{6621}\x{6622}\x{6623}\x{6624}\x{6625}\x{6626}\x{6627}\x{6628}\x{6629}' . +'\x{662A}\x{662B}\x{662D}\x{662E}\x{662F}\x{6630}\x{6631}\x{6632}\x{6633}' . +'\x{6634}\x{6635}\x{6636}\x{6639}\x{663A}\x{663C}\x{663D}\x{663E}\x{6640}' . +'\x{6641}\x{6642}\x{6643}\x{6644}\x{6645}\x{6646}\x{6647}\x{6649}\x{664A}' . +'\x{664B}\x{664C}\x{664E}\x{664F}\x{6650}\x{6651}\x{6652}\x{6653}\x{6654}' . +'\x{6655}\x{6656}\x{6657}\x{6658}\x{6659}\x{665A}\x{665B}\x{665C}\x{665D}' . +'\x{665E}\x{665F}\x{6661}\x{6662}\x{6664}\x{6665}\x{6666}\x{6668}\x{6669}' . +'\x{666A}\x{666B}\x{666C}\x{666D}\x{666E}\x{666F}\x{6670}\x{6671}\x{6672}' . +'\x{6673}\x{6674}\x{6675}\x{6676}\x{6677}\x{6678}\x{6679}\x{667A}\x{667B}' . +'\x{667C}\x{667D}\x{667E}\x{667F}\x{6680}\x{6681}\x{6682}\x{6683}\x{6684}' . +'\x{6685}\x{6686}\x{6687}\x{6688}\x{6689}\x{668A}\x{668B}\x{668C}\x{668D}' . +'\x{668E}\x{668F}\x{6690}\x{6691}\x{6693}\x{6694}\x{6695}\x{6696}\x{6697}' . +'\x{6698}\x{6699}\x{669A}\x{669B}\x{669D}\x{669F}\x{66A0}\x{66A1}\x{66A2}' . +'\x{66A3}\x{66A4}\x{66A5}\x{66A6}\x{66A7}\x{66A8}\x{66A9}\x{66AA}\x{66AB}' . +'\x{66AE}\x{66AF}\x{66B0}\x{66B1}\x{66B2}\x{66B3}\x{66B4}\x{66B5}\x{66B6}' . +'\x{66B7}\x{66B8}\x{66B9}\x{66BA}\x{66BB}\x{66BC}\x{66BD}\x{66BE}\x{66BF}' . +'\x{66C0}\x{66C1}\x{66C2}\x{66C3}\x{66C4}\x{66C5}\x{66C6}\x{66C7}\x{66C8}' . +'\x{66C9}\x{66CA}\x{66CB}\x{66CC}\x{66CD}\x{66CE}\x{66CF}\x{66D1}\x{66D2}' . +'\x{66D4}\x{66D5}\x{66D6}\x{66D8}\x{66D9}\x{66DA}\x{66DB}\x{66DC}\x{66DD}' . +'\x{66DE}\x{66E0}\x{66E1}\x{66E2}\x{66E3}\x{66E4}\x{66E5}\x{66E6}\x{66E7}' . +'\x{66E8}\x{66E9}\x{66EA}\x{66EB}\x{66EC}\x{66ED}\x{66EE}\x{66F0}\x{66F1}' . +'\x{66F2}\x{66F3}\x{66F4}\x{66F5}\x{66F6}\x{66F7}\x{66F8}\x{66F9}\x{66FA}' . +'\x{66FB}\x{66FC}\x{66FE}\x{66FF}\x{6700}\x{6701}\x{6703}\x{6704}\x{6705}' . +'\x{6706}\x{6708}\x{6709}\x{670A}\x{670B}\x{670C}\x{670D}\x{670E}\x{670F}' . +'\x{6710}\x{6711}\x{6712}\x{6713}\x{6714}\x{6715}\x{6716}\x{6717}\x{6718}' . +'\x{671A}\x{671B}\x{671C}\x{671D}\x{671E}\x{671F}\x{6720}\x{6721}\x{6722}' . +'\x{6723}\x{6725}\x{6726}\x{6727}\x{6728}\x{672A}\x{672B}\x{672C}\x{672D}' . +'\x{672E}\x{672F}\x{6730}\x{6731}\x{6732}\x{6733}\x{6734}\x{6735}\x{6736}' . +'\x{6737}\x{6738}\x{6739}\x{673A}\x{673B}\x{673C}\x{673D}\x{673E}\x{673F}' . +'\x{6740}\x{6741}\x{6742}\x{6743}\x{6744}\x{6745}\x{6746}\x{6747}\x{6748}' . +'\x{6749}\x{674A}\x{674B}\x{674C}\x{674D}\x{674E}\x{674F}\x{6750}\x{6751}' . +'\x{6752}\x{6753}\x{6754}\x{6755}\x{6756}\x{6757}\x{6758}\x{6759}\x{675A}' . +'\x{675B}\x{675C}\x{675D}\x{675E}\x{675F}\x{6760}\x{6761}\x{6762}\x{6763}' . +'\x{6764}\x{6765}\x{6766}\x{6768}\x{6769}\x{676A}\x{676B}\x{676C}\x{676D}' . +'\x{676E}\x{676F}\x{6770}\x{6771}\x{6772}\x{6773}\x{6774}\x{6775}\x{6776}' . +'\x{6777}\x{6778}\x{6779}\x{677A}\x{677B}\x{677C}\x{677D}\x{677E}\x{677F}' . +'\x{6780}\x{6781}\x{6782}\x{6783}\x{6784}\x{6785}\x{6786}\x{6787}\x{6789}' . +'\x{678A}\x{678B}\x{678C}\x{678D}\x{678E}\x{678F}\x{6790}\x{6791}\x{6792}' . +'\x{6793}\x{6794}\x{6795}\x{6797}\x{6798}\x{6799}\x{679A}\x{679B}\x{679C}' . +'\x{679D}\x{679E}\x{679F}\x{67A0}\x{67A1}\x{67A2}\x{67A3}\x{67A4}\x{67A5}' . +'\x{67A6}\x{67A7}\x{67A8}\x{67AA}\x{67AB}\x{67AC}\x{67AD}\x{67AE}\x{67AF}' . +'\x{67B0}\x{67B1}\x{67B2}\x{67B3}\x{67B4}\x{67B5}\x{67B6}\x{67B7}\x{67B8}' . +'\x{67B9}\x{67BA}\x{67BB}\x{67BC}\x{67BE}\x{67C0}\x{67C1}\x{67C2}\x{67C3}' . +'\x{67C4}\x{67C5}\x{67C6}\x{67C7}\x{67C8}\x{67C9}\x{67CA}\x{67CB}\x{67CC}' . +'\x{67CD}\x{67CE}\x{67CF}\x{67D0}\x{67D1}\x{67D2}\x{67D3}\x{67D4}\x{67D6}' . +'\x{67D8}\x{67D9}\x{67DA}\x{67DB}\x{67DC}\x{67DD}\x{67DE}\x{67DF}\x{67E0}' . +'\x{67E1}\x{67E2}\x{67E3}\x{67E4}\x{67E5}\x{67E6}\x{67E7}\x{67E8}\x{67E9}' . +'\x{67EA}\x{67EB}\x{67EC}\x{67ED}\x{67EE}\x{67EF}\x{67F0}\x{67F1}\x{67F2}' . +'\x{67F3}\x{67F4}\x{67F5}\x{67F6}\x{67F7}\x{67F8}\x{67FA}\x{67FB}\x{67FC}' . +'\x{67FD}\x{67FE}\x{67FF}\x{6800}\x{6802}\x{6803}\x{6804}\x{6805}\x{6806}' . +'\x{6807}\x{6808}\x{6809}\x{680A}\x{680B}\x{680C}\x{680D}\x{680E}\x{680F}' . +'\x{6810}\x{6811}\x{6812}\x{6813}\x{6814}\x{6816}\x{6817}\x{6818}\x{6819}' . +'\x{681A}\x{681B}\x{681C}\x{681D}\x{681F}\x{6820}\x{6821}\x{6822}\x{6823}' . +'\x{6824}\x{6825}\x{6826}\x{6828}\x{6829}\x{682A}\x{682B}\x{682C}\x{682D}' . +'\x{682E}\x{682F}\x{6831}\x{6832}\x{6833}\x{6834}\x{6835}\x{6836}\x{6837}' . +'\x{6838}\x{6839}\x{683A}\x{683B}\x{683C}\x{683D}\x{683E}\x{683F}\x{6840}' . +'\x{6841}\x{6842}\x{6843}\x{6844}\x{6845}\x{6846}\x{6847}\x{6848}\x{6849}' . +'\x{684A}\x{684B}\x{684C}\x{684D}\x{684E}\x{684F}\x{6850}\x{6851}\x{6852}' . +'\x{6853}\x{6854}\x{6855}\x{6856}\x{6857}\x{685B}\x{685D}\x{6860}\x{6861}' . +'\x{6862}\x{6863}\x{6864}\x{6865}\x{6866}\x{6867}\x{6868}\x{6869}\x{686A}' . +'\x{686B}\x{686C}\x{686D}\x{686E}\x{686F}\x{6870}\x{6871}\x{6872}\x{6873}' . +'\x{6874}\x{6875}\x{6876}\x{6877}\x{6878}\x{6879}\x{687B}\x{687C}\x{687D}' . +'\x{687E}\x{687F}\x{6880}\x{6881}\x{6882}\x{6883}\x{6884}\x{6885}\x{6886}' . +'\x{6887}\x{6888}\x{6889}\x{688A}\x{688B}\x{688C}\x{688D}\x{688E}\x{688F}' . +'\x{6890}\x{6891}\x{6892}\x{6893}\x{6894}\x{6896}\x{6897}\x{6898}\x{689A}' . +'\x{689B}\x{689C}\x{689D}\x{689E}\x{689F}\x{68A0}\x{68A1}\x{68A2}\x{68A3}' . +'\x{68A4}\x{68A6}\x{68A7}\x{68A8}\x{68A9}\x{68AA}\x{68AB}\x{68AC}\x{68AD}' . +'\x{68AE}\x{68AF}\x{68B0}\x{68B1}\x{68B2}\x{68B3}\x{68B4}\x{68B5}\x{68B6}' . +'\x{68B7}\x{68B9}\x{68BB}\x{68BC}\x{68BD}\x{68BE}\x{68BF}\x{68C0}\x{68C1}' . +'\x{68C2}\x{68C4}\x{68C6}\x{68C7}\x{68C8}\x{68C9}\x{68CA}\x{68CB}\x{68CC}' . +'\x{68CD}\x{68CE}\x{68CF}\x{68D0}\x{68D1}\x{68D2}\x{68D3}\x{68D4}\x{68D5}' . +'\x{68D6}\x{68D7}\x{68D8}\x{68DA}\x{68DB}\x{68DC}\x{68DD}\x{68DE}\x{68DF}' . +'\x{68E0}\x{68E1}\x{68E3}\x{68E4}\x{68E6}\x{68E7}\x{68E8}\x{68E9}\x{68EA}' . +'\x{68EB}\x{68EC}\x{68ED}\x{68EE}\x{68EF}\x{68F0}\x{68F1}\x{68F2}\x{68F3}' . +'\x{68F4}\x{68F5}\x{68F6}\x{68F7}\x{68F8}\x{68F9}\x{68FA}\x{68FB}\x{68FC}' . +'\x{68FD}\x{68FE}\x{68FF}\x{6901}\x{6902}\x{6903}\x{6904}\x{6905}\x{6906}' . +'\x{6907}\x{6908}\x{690A}\x{690B}\x{690C}\x{690D}\x{690E}\x{690F}\x{6910}' . +'\x{6911}\x{6912}\x{6913}\x{6914}\x{6915}\x{6916}\x{6917}\x{6918}\x{6919}' . +'\x{691A}\x{691B}\x{691C}\x{691D}\x{691E}\x{691F}\x{6920}\x{6921}\x{6922}' . +'\x{6923}\x{6924}\x{6925}\x{6926}\x{6927}\x{6928}\x{6929}\x{692A}\x{692B}' . +'\x{692C}\x{692D}\x{692E}\x{692F}\x{6930}\x{6931}\x{6932}\x{6933}\x{6934}' . +'\x{6935}\x{6936}\x{6937}\x{6938}\x{6939}\x{693A}\x{693B}\x{693C}\x{693D}' . +'\x{693F}\x{6940}\x{6941}\x{6942}\x{6943}\x{6944}\x{6945}\x{6946}\x{6947}' . +'\x{6948}\x{6949}\x{694A}\x{694B}\x{694C}\x{694E}\x{694F}\x{6950}\x{6951}' . +'\x{6952}\x{6953}\x{6954}\x{6955}\x{6956}\x{6957}\x{6958}\x{6959}\x{695A}' . +'\x{695B}\x{695C}\x{695D}\x{695E}\x{695F}\x{6960}\x{6961}\x{6962}\x{6963}' . +'\x{6964}\x{6965}\x{6966}\x{6967}\x{6968}\x{6969}\x{696A}\x{696B}\x{696C}' . +'\x{696D}\x{696E}\x{696F}\x{6970}\x{6971}\x{6972}\x{6973}\x{6974}\x{6975}' . +'\x{6976}\x{6977}\x{6978}\x{6979}\x{697A}\x{697B}\x{697C}\x{697D}\x{697E}' . +'\x{697F}\x{6980}\x{6981}\x{6982}\x{6983}\x{6984}\x{6985}\x{6986}\x{6987}' . +'\x{6988}\x{6989}\x{698A}\x{698B}\x{698C}\x{698D}\x{698E}\x{698F}\x{6990}' . +'\x{6991}\x{6992}\x{6993}\x{6994}\x{6995}\x{6996}\x{6997}\x{6998}\x{6999}' . +'\x{699A}\x{699B}\x{699C}\x{699D}\x{699E}\x{69A0}\x{69A1}\x{69A3}\x{69A4}' . +'\x{69A5}\x{69A6}\x{69A7}\x{69A8}\x{69A9}\x{69AA}\x{69AB}\x{69AC}\x{69AD}' . +'\x{69AE}\x{69AF}\x{69B0}\x{69B1}\x{69B2}\x{69B3}\x{69B4}\x{69B5}\x{69B6}' . +'\x{69B7}\x{69B8}\x{69B9}\x{69BA}\x{69BB}\x{69BC}\x{69BD}\x{69BE}\x{69BF}' . +'\x{69C1}\x{69C2}\x{69C3}\x{69C4}\x{69C5}\x{69C6}\x{69C7}\x{69C8}\x{69C9}' . +'\x{69CA}\x{69CB}\x{69CC}\x{69CD}\x{69CE}\x{69CF}\x{69D0}\x{69D3}\x{69D4}' . +'\x{69D8}\x{69D9}\x{69DA}\x{69DB}\x{69DC}\x{69DD}\x{69DE}\x{69DF}\x{69E0}' . +'\x{69E1}\x{69E2}\x{69E3}\x{69E4}\x{69E5}\x{69E6}\x{69E7}\x{69E8}\x{69E9}' . +'\x{69EA}\x{69EB}\x{69EC}\x{69ED}\x{69EE}\x{69EF}\x{69F0}\x{69F1}\x{69F2}' . +'\x{69F3}\x{69F4}\x{69F5}\x{69F6}\x{69F7}\x{69F8}\x{69FA}\x{69FB}\x{69FC}' . +'\x{69FD}\x{69FE}\x{69FF}\x{6A00}\x{6A01}\x{6A02}\x{6A04}\x{6A05}\x{6A06}' . +'\x{6A07}\x{6A08}\x{6A09}\x{6A0A}\x{6A0B}\x{6A0D}\x{6A0E}\x{6A0F}\x{6A10}' . +'\x{6A11}\x{6A12}\x{6A13}\x{6A14}\x{6A15}\x{6A16}\x{6A17}\x{6A18}\x{6A19}' . +'\x{6A1A}\x{6A1B}\x{6A1D}\x{6A1E}\x{6A1F}\x{6A20}\x{6A21}\x{6A22}\x{6A23}' . +'\x{6A25}\x{6A26}\x{6A27}\x{6A28}\x{6A29}\x{6A2A}\x{6A2B}\x{6A2C}\x{6A2D}' . +'\x{6A2E}\x{6A2F}\x{6A30}\x{6A31}\x{6A32}\x{6A33}\x{6A34}\x{6A35}\x{6A36}' . +'\x{6A38}\x{6A39}\x{6A3A}\x{6A3B}\x{6A3C}\x{6A3D}\x{6A3E}\x{6A3F}\x{6A40}' . +'\x{6A41}\x{6A42}\x{6A43}\x{6A44}\x{6A45}\x{6A46}\x{6A47}\x{6A48}\x{6A49}' . +'\x{6A4B}\x{6A4C}\x{6A4D}\x{6A4E}\x{6A4F}\x{6A50}\x{6A51}\x{6A52}\x{6A54}' . +'\x{6A55}\x{6A56}\x{6A57}\x{6A58}\x{6A59}\x{6A5A}\x{6A5B}\x{6A5D}\x{6A5E}' . +'\x{6A5F}\x{6A60}\x{6A61}\x{6A62}\x{6A63}\x{6A64}\x{6A65}\x{6A66}\x{6A67}' . +'\x{6A68}\x{6A69}\x{6A6A}\x{6A6B}\x{6A6C}\x{6A6D}\x{6A6F}\x{6A71}\x{6A72}' . +'\x{6A73}\x{6A74}\x{6A75}\x{6A76}\x{6A77}\x{6A78}\x{6A79}\x{6A7A}\x{6A7B}' . +'\x{6A7C}\x{6A7D}\x{6A7E}\x{6A7F}\x{6A80}\x{6A81}\x{6A82}\x{6A83}\x{6A84}' . +'\x{6A85}\x{6A87}\x{6A88}\x{6A89}\x{6A8B}\x{6A8C}\x{6A8D}\x{6A8E}\x{6A90}' . +'\x{6A91}\x{6A92}\x{6A93}\x{6A94}\x{6A95}\x{6A96}\x{6A97}\x{6A98}\x{6A9A}' . +'\x{6A9B}\x{6A9C}\x{6A9E}\x{6A9F}\x{6AA0}\x{6AA1}\x{6AA2}\x{6AA3}\x{6AA4}' . +'\x{6AA5}\x{6AA6}\x{6AA7}\x{6AA8}\x{6AA9}\x{6AAB}\x{6AAC}\x{6AAD}\x{6AAE}' . +'\x{6AAF}\x{6AB0}\x{6AB2}\x{6AB3}\x{6AB4}\x{6AB5}\x{6AB6}\x{6AB7}\x{6AB8}' . +'\x{6AB9}\x{6ABA}\x{6ABB}\x{6ABC}\x{6ABD}\x{6ABF}\x{6AC1}\x{6AC2}\x{6AC3}' . +'\x{6AC5}\x{6AC6}\x{6AC7}\x{6ACA}\x{6ACB}\x{6ACC}\x{6ACD}\x{6ACE}\x{6ACF}' . +'\x{6AD0}\x{6AD1}\x{6AD2}\x{6AD3}\x{6AD4}\x{6AD5}\x{6AD6}\x{6AD7}\x{6AD9}' . +'\x{6ADA}\x{6ADB}\x{6ADC}\x{6ADD}\x{6ADE}\x{6ADF}\x{6AE0}\x{6AE1}\x{6AE2}' . +'\x{6AE3}\x{6AE4}\x{6AE5}\x{6AE6}\x{6AE7}\x{6AE8}\x{6AEA}\x{6AEB}\x{6AEC}' . +'\x{6AED}\x{6AEE}\x{6AEF}\x{6AF0}\x{6AF1}\x{6AF2}\x{6AF3}\x{6AF4}\x{6AF5}' . +'\x{6AF6}\x{6AF7}\x{6AF8}\x{6AF9}\x{6AFA}\x{6AFB}\x{6AFC}\x{6AFD}\x{6AFE}' . +'\x{6AFF}\x{6B00}\x{6B01}\x{6B02}\x{6B03}\x{6B04}\x{6B05}\x{6B06}\x{6B07}' . +'\x{6B08}\x{6B09}\x{6B0A}\x{6B0B}\x{6B0C}\x{6B0D}\x{6B0F}\x{6B10}\x{6B11}' . +'\x{6B12}\x{6B13}\x{6B14}\x{6B15}\x{6B16}\x{6B17}\x{6B18}\x{6B19}\x{6B1A}' . +'\x{6B1C}\x{6B1D}\x{6B1E}\x{6B1F}\x{6B20}\x{6B21}\x{6B22}\x{6B23}\x{6B24}' . +'\x{6B25}\x{6B26}\x{6B27}\x{6B28}\x{6B29}\x{6B2A}\x{6B2B}\x{6B2C}\x{6B2D}' . +'\x{6B2F}\x{6B30}\x{6B31}\x{6B32}\x{6B33}\x{6B34}\x{6B36}\x{6B37}\x{6B38}' . +'\x{6B39}\x{6B3A}\x{6B3B}\x{6B3C}\x{6B3D}\x{6B3E}\x{6B3F}\x{6B41}\x{6B42}' . +'\x{6B43}\x{6B44}\x{6B45}\x{6B46}\x{6B47}\x{6B48}\x{6B49}\x{6B4A}\x{6B4B}' . +'\x{6B4C}\x{6B4D}\x{6B4E}\x{6B4F}\x{6B50}\x{6B51}\x{6B52}\x{6B53}\x{6B54}' . +'\x{6B55}\x{6B56}\x{6B59}\x{6B5A}\x{6B5B}\x{6B5C}\x{6B5E}\x{6B5F}\x{6B60}' . +'\x{6B61}\x{6B62}\x{6B63}\x{6B64}\x{6B65}\x{6B66}\x{6B67}\x{6B69}\x{6B6A}' . +'\x{6B6B}\x{6B6D}\x{6B6F}\x{6B70}\x{6B72}\x{6B73}\x{6B74}\x{6B76}\x{6B77}' . +'\x{6B78}\x{6B79}\x{6B7A}\x{6B7B}\x{6B7C}\x{6B7E}\x{6B7F}\x{6B80}\x{6B81}' . +'\x{6B82}\x{6B83}\x{6B84}\x{6B85}\x{6B86}\x{6B87}\x{6B88}\x{6B89}\x{6B8A}' . +'\x{6B8B}\x{6B8C}\x{6B8D}\x{6B8E}\x{6B8F}\x{6B90}\x{6B91}\x{6B92}\x{6B93}' . +'\x{6B94}\x{6B95}\x{6B96}\x{6B97}\x{6B98}\x{6B99}\x{6B9A}\x{6B9B}\x{6B9C}' . +'\x{6B9D}\x{6B9E}\x{6B9F}\x{6BA0}\x{6BA1}\x{6BA2}\x{6BA3}\x{6BA4}\x{6BA5}' . +'\x{6BA6}\x{6BA7}\x{6BA8}\x{6BA9}\x{6BAA}\x{6BAB}\x{6BAC}\x{6BAD}\x{6BAE}' . +'\x{6BAF}\x{6BB0}\x{6BB2}\x{6BB3}\x{6BB4}\x{6BB5}\x{6BB6}\x{6BB7}\x{6BB9}' . +'\x{6BBA}\x{6BBB}\x{6BBC}\x{6BBD}\x{6BBE}\x{6BBF}\x{6BC0}\x{6BC1}\x{6BC2}' . +'\x{6BC3}\x{6BC4}\x{6BC5}\x{6BC6}\x{6BC7}\x{6BC8}\x{6BC9}\x{6BCA}\x{6BCB}' . +'\x{6BCC}\x{6BCD}\x{6BCE}\x{6BCF}\x{6BD0}\x{6BD1}\x{6BD2}\x{6BD3}\x{6BD4}' . +'\x{6BD5}\x{6BD6}\x{6BD7}\x{6BD8}\x{6BD9}\x{6BDA}\x{6BDB}\x{6BDC}\x{6BDD}' . +'\x{6BDE}\x{6BDF}\x{6BE0}\x{6BE1}\x{6BE2}\x{6BE3}\x{6BE4}\x{6BE5}\x{6BE6}' . +'\x{6BE7}\x{6BE8}\x{6BEA}\x{6BEB}\x{6BEC}\x{6BED}\x{6BEE}\x{6BEF}\x{6BF0}' . +'\x{6BF2}\x{6BF3}\x{6BF5}\x{6BF6}\x{6BF7}\x{6BF8}\x{6BF9}\x{6BFB}\x{6BFC}' . +'\x{6BFD}\x{6BFE}\x{6BFF}\x{6C00}\x{6C01}\x{6C02}\x{6C03}\x{6C04}\x{6C05}' . +'\x{6C06}\x{6C07}\x{6C08}\x{6C09}\x{6C0B}\x{6C0C}\x{6C0D}\x{6C0E}\x{6C0F}' . +'\x{6C10}\x{6C11}\x{6C12}\x{6C13}\x{6C14}\x{6C15}\x{6C16}\x{6C18}\x{6C19}' . +'\x{6C1A}\x{6C1B}\x{6C1D}\x{6C1E}\x{6C1F}\x{6C20}\x{6C21}\x{6C22}\x{6C23}' . +'\x{6C24}\x{6C25}\x{6C26}\x{6C27}\x{6C28}\x{6C29}\x{6C2A}\x{6C2B}\x{6C2C}' . +'\x{6C2E}\x{6C2F}\x{6C30}\x{6C31}\x{6C32}\x{6C33}\x{6C34}\x{6C35}\x{6C36}' . +'\x{6C37}\x{6C38}\x{6C3A}\x{6C3B}\x{6C3D}\x{6C3E}\x{6C3F}\x{6C40}\x{6C41}' . +'\x{6C42}\x{6C43}\x{6C44}\x{6C46}\x{6C47}\x{6C48}\x{6C49}\x{6C4A}\x{6C4B}' . +'\x{6C4C}\x{6C4D}\x{6C4E}\x{6C4F}\x{6C50}\x{6C51}\x{6C52}\x{6C53}\x{6C54}' . +'\x{6C55}\x{6C56}\x{6C57}\x{6C58}\x{6C59}\x{6C5A}\x{6C5B}\x{6C5C}\x{6C5D}' . +'\x{6C5E}\x{6C5F}\x{6C60}\x{6C61}\x{6C62}\x{6C63}\x{6C64}\x{6C65}\x{6C66}' . +'\x{6C67}\x{6C68}\x{6C69}\x{6C6A}\x{6C6B}\x{6C6D}\x{6C6F}\x{6C70}\x{6C71}' . +'\x{6C72}\x{6C73}\x{6C74}\x{6C75}\x{6C76}\x{6C77}\x{6C78}\x{6C79}\x{6C7A}' . +'\x{6C7B}\x{6C7C}\x{6C7D}\x{6C7E}\x{6C7F}\x{6C80}\x{6C81}\x{6C82}\x{6C83}' . +'\x{6C84}\x{6C85}\x{6C86}\x{6C87}\x{6C88}\x{6C89}\x{6C8A}\x{6C8B}\x{6C8C}' . +'\x{6C8D}\x{6C8E}\x{6C8F}\x{6C90}\x{6C91}\x{6C92}\x{6C93}\x{6C94}\x{6C95}' . +'\x{6C96}\x{6C97}\x{6C98}\x{6C99}\x{6C9A}\x{6C9B}\x{6C9C}\x{6C9D}\x{6C9E}' . +'\x{6C9F}\x{6CA1}\x{6CA2}\x{6CA3}\x{6CA4}\x{6CA5}\x{6CA6}\x{6CA7}\x{6CA8}' . +'\x{6CA9}\x{6CAA}\x{6CAB}\x{6CAC}\x{6CAD}\x{6CAE}\x{6CAF}\x{6CB0}\x{6CB1}' . +'\x{6CB2}\x{6CB3}\x{6CB4}\x{6CB5}\x{6CB6}\x{6CB7}\x{6CB8}\x{6CB9}\x{6CBA}' . +'\x{6CBB}\x{6CBC}\x{6CBD}\x{6CBE}\x{6CBF}\x{6CC0}\x{6CC1}\x{6CC2}\x{6CC3}' . +'\x{6CC4}\x{6CC5}\x{6CC6}\x{6CC7}\x{6CC8}\x{6CC9}\x{6CCA}\x{6CCB}\x{6CCC}' . +'\x{6CCD}\x{6CCE}\x{6CCF}\x{6CD0}\x{6CD1}\x{6CD2}\x{6CD3}\x{6CD4}\x{6CD5}' . +'\x{6CD6}\x{6CD7}\x{6CD9}\x{6CDA}\x{6CDB}\x{6CDC}\x{6CDD}\x{6CDE}\x{6CDF}' . +'\x{6CE0}\x{6CE1}\x{6CE2}\x{6CE3}\x{6CE4}\x{6CE5}\x{6CE6}\x{6CE7}\x{6CE8}' . +'\x{6CE9}\x{6CEA}\x{6CEB}\x{6CEC}\x{6CED}\x{6CEE}\x{6CEF}\x{6CF0}\x{6CF1}' . +'\x{6CF2}\x{6CF3}\x{6CF5}\x{6CF6}\x{6CF7}\x{6CF8}\x{6CF9}\x{6CFA}\x{6CFB}' . +'\x{6CFC}\x{6CFD}\x{6CFE}\x{6CFF}\x{6D00}\x{6D01}\x{6D03}\x{6D04}\x{6D05}' . +'\x{6D06}\x{6D07}\x{6D08}\x{6D09}\x{6D0A}\x{6D0B}\x{6D0C}\x{6D0D}\x{6D0E}' . +'\x{6D0F}\x{6D10}\x{6D11}\x{6D12}\x{6D13}\x{6D14}\x{6D15}\x{6D16}\x{6D17}' . +'\x{6D18}\x{6D19}\x{6D1A}\x{6D1B}\x{6D1D}\x{6D1E}\x{6D1F}\x{6D20}\x{6D21}' . +'\x{6D22}\x{6D23}\x{6D25}\x{6D26}\x{6D27}\x{6D28}\x{6D29}\x{6D2A}\x{6D2B}' . +'\x{6D2C}\x{6D2D}\x{6D2E}\x{6D2F}\x{6D30}\x{6D31}\x{6D32}\x{6D33}\x{6D34}' . +'\x{6D35}\x{6D36}\x{6D37}\x{6D38}\x{6D39}\x{6D3A}\x{6D3B}\x{6D3C}\x{6D3D}' . +'\x{6D3E}\x{6D3F}\x{6D40}\x{6D41}\x{6D42}\x{6D43}\x{6D44}\x{6D45}\x{6D46}' . +'\x{6D47}\x{6D48}\x{6D49}\x{6D4A}\x{6D4B}\x{6D4C}\x{6D4D}\x{6D4E}\x{6D4F}' . +'\x{6D50}\x{6D51}\x{6D52}\x{6D53}\x{6D54}\x{6D55}\x{6D56}\x{6D57}\x{6D58}' . +'\x{6D59}\x{6D5A}\x{6D5B}\x{6D5C}\x{6D5D}\x{6D5E}\x{6D5F}\x{6D60}\x{6D61}' . +'\x{6D62}\x{6D63}\x{6D64}\x{6D65}\x{6D66}\x{6D67}\x{6D68}\x{6D69}\x{6D6A}' . +'\x{6D6B}\x{6D6C}\x{6D6D}\x{6D6E}\x{6D6F}\x{6D70}\x{6D72}\x{6D73}\x{6D74}' . +'\x{6D75}\x{6D76}\x{6D77}\x{6D78}\x{6D79}\x{6D7A}\x{6D7B}\x{6D7C}\x{6D7D}' . +'\x{6D7E}\x{6D7F}\x{6D80}\x{6D82}\x{6D83}\x{6D84}\x{6D85}\x{6D86}\x{6D87}' . +'\x{6D88}\x{6D89}\x{6D8A}\x{6D8B}\x{6D8C}\x{6D8D}\x{6D8E}\x{6D8F}\x{6D90}' . +'\x{6D91}\x{6D92}\x{6D93}\x{6D94}\x{6D95}\x{6D97}\x{6D98}\x{6D99}\x{6D9A}' . +'\x{6D9B}\x{6D9D}\x{6D9E}\x{6D9F}\x{6DA0}\x{6DA1}\x{6DA2}\x{6DA3}\x{6DA4}' . +'\x{6DA5}\x{6DA6}\x{6DA7}\x{6DA8}\x{6DA9}\x{6DAA}\x{6DAB}\x{6DAC}\x{6DAD}' . +'\x{6DAE}\x{6DAF}\x{6DB2}\x{6DB3}\x{6DB4}\x{6DB5}\x{6DB7}\x{6DB8}\x{6DB9}' . +'\x{6DBA}\x{6DBB}\x{6DBC}\x{6DBD}\x{6DBE}\x{6DBF}\x{6DC0}\x{6DC1}\x{6DC2}' . +'\x{6DC3}\x{6DC4}\x{6DC5}\x{6DC6}\x{6DC7}\x{6DC8}\x{6DC9}\x{6DCA}\x{6DCB}' . +'\x{6DCC}\x{6DCD}\x{6DCE}\x{6DCF}\x{6DD0}\x{6DD1}\x{6DD2}\x{6DD3}\x{6DD4}' . +'\x{6DD5}\x{6DD6}\x{6DD7}\x{6DD8}\x{6DD9}\x{6DDA}\x{6DDB}\x{6DDC}\x{6DDD}' . +'\x{6DDE}\x{6DDF}\x{6DE0}\x{6DE1}\x{6DE2}\x{6DE3}\x{6DE4}\x{6DE5}\x{6DE6}' . +'\x{6DE7}\x{6DE8}\x{6DE9}\x{6DEA}\x{6DEB}\x{6DEC}\x{6DED}\x{6DEE}\x{6DEF}' . +'\x{6DF0}\x{6DF1}\x{6DF2}\x{6DF3}\x{6DF4}\x{6DF5}\x{6DF6}\x{6DF7}\x{6DF8}' . +'\x{6DF9}\x{6DFA}\x{6DFB}\x{6DFC}\x{6DFD}\x{6E00}\x{6E03}\x{6E04}\x{6E05}' . +'\x{6E07}\x{6E08}\x{6E09}\x{6E0A}\x{6E0B}\x{6E0C}\x{6E0D}\x{6E0E}\x{6E0F}' . +'\x{6E10}\x{6E11}\x{6E14}\x{6E15}\x{6E16}\x{6E17}\x{6E19}\x{6E1A}\x{6E1B}' . +'\x{6E1C}\x{6E1D}\x{6E1E}\x{6E1F}\x{6E20}\x{6E21}\x{6E22}\x{6E23}\x{6E24}' . +'\x{6E25}\x{6E26}\x{6E27}\x{6E28}\x{6E29}\x{6E2B}\x{6E2C}\x{6E2D}\x{6E2E}' . +'\x{6E2F}\x{6E30}\x{6E31}\x{6E32}\x{6E33}\x{6E34}\x{6E35}\x{6E36}\x{6E37}' . +'\x{6E38}\x{6E39}\x{6E3A}\x{6E3B}\x{6E3C}\x{6E3D}\x{6E3E}\x{6E3F}\x{6E40}' . +'\x{6E41}\x{6E42}\x{6E43}\x{6E44}\x{6E45}\x{6E46}\x{6E47}\x{6E48}\x{6E49}' . +'\x{6E4A}\x{6E4B}\x{6E4D}\x{6E4E}\x{6E4F}\x{6E50}\x{6E51}\x{6E52}\x{6E53}' . +'\x{6E54}\x{6E55}\x{6E56}\x{6E57}\x{6E58}\x{6E59}\x{6E5A}\x{6E5B}\x{6E5C}' . +'\x{6E5D}\x{6E5E}\x{6E5F}\x{6E60}\x{6E61}\x{6E62}\x{6E63}\x{6E64}\x{6E65}' . +'\x{6E66}\x{6E67}\x{6E68}\x{6E69}\x{6E6A}\x{6E6B}\x{6E6D}\x{6E6E}\x{6E6F}' . +'\x{6E70}\x{6E71}\x{6E72}\x{6E73}\x{6E74}\x{6E75}\x{6E77}\x{6E78}\x{6E79}' . +'\x{6E7E}\x{6E7F}\x{6E80}\x{6E81}\x{6E82}\x{6E83}\x{6E84}\x{6E85}\x{6E86}' . +'\x{6E87}\x{6E88}\x{6E89}\x{6E8A}\x{6E8D}\x{6E8E}\x{6E8F}\x{6E90}\x{6E91}' . +'\x{6E92}\x{6E93}\x{6E94}\x{6E96}\x{6E97}\x{6E98}\x{6E99}\x{6E9A}\x{6E9B}' . +'\x{6E9C}\x{6E9D}\x{6E9E}\x{6E9F}\x{6EA0}\x{6EA1}\x{6EA2}\x{6EA3}\x{6EA4}' . +'\x{6EA5}\x{6EA6}\x{6EA7}\x{6EA8}\x{6EA9}\x{6EAA}\x{6EAB}\x{6EAC}\x{6EAD}' . +'\x{6EAE}\x{6EAF}\x{6EB0}\x{6EB1}\x{6EB2}\x{6EB3}\x{6EB4}\x{6EB5}\x{6EB6}' . +'\x{6EB7}\x{6EB8}\x{6EB9}\x{6EBA}\x{6EBB}\x{6EBC}\x{6EBD}\x{6EBE}\x{6EBF}' . +'\x{6EC0}\x{6EC1}\x{6EC2}\x{6EC3}\x{6EC4}\x{6EC5}\x{6EC6}\x{6EC7}\x{6EC8}' . +'\x{6EC9}\x{6ECA}\x{6ECB}\x{6ECC}\x{6ECD}\x{6ECE}\x{6ECF}\x{6ED0}\x{6ED1}' . +'\x{6ED2}\x{6ED3}\x{6ED4}\x{6ED5}\x{6ED6}\x{6ED7}\x{6ED8}\x{6ED9}\x{6EDA}' . +'\x{6EDC}\x{6EDE}\x{6EDF}\x{6EE0}\x{6EE1}\x{6EE2}\x{6EE4}\x{6EE5}\x{6EE6}' . +'\x{6EE7}\x{6EE8}\x{6EE9}\x{6EEA}\x{6EEB}\x{6EEC}\x{6EED}\x{6EEE}\x{6EEF}' . +'\x{6EF0}\x{6EF1}\x{6EF2}\x{6EF3}\x{6EF4}\x{6EF5}\x{6EF6}\x{6EF7}\x{6EF8}' . +'\x{6EF9}\x{6EFA}\x{6EFB}\x{6EFC}\x{6EFD}\x{6EFE}\x{6EFF}\x{6F00}\x{6F01}' . +'\x{6F02}\x{6F03}\x{6F05}\x{6F06}\x{6F07}\x{6F08}\x{6F09}\x{6F0A}\x{6F0C}' . +'\x{6F0D}\x{6F0E}\x{6F0F}\x{6F10}\x{6F11}\x{6F12}\x{6F13}\x{6F14}\x{6F15}' . +'\x{6F16}\x{6F17}\x{6F18}\x{6F19}\x{6F1A}\x{6F1B}\x{6F1C}\x{6F1D}\x{6F1E}' . +'\x{6F1F}\x{6F20}\x{6F21}\x{6F22}\x{6F23}\x{6F24}\x{6F25}\x{6F26}\x{6F27}' . +'\x{6F28}\x{6F29}\x{6F2A}\x{6F2B}\x{6F2C}\x{6F2D}\x{6F2E}\x{6F2F}\x{6F30}' . +'\x{6F31}\x{6F32}\x{6F33}\x{6F34}\x{6F35}\x{6F36}\x{6F37}\x{6F38}\x{6F39}' . +'\x{6F3A}\x{6F3B}\x{6F3C}\x{6F3D}\x{6F3E}\x{6F3F}\x{6F40}\x{6F41}\x{6F43}' . +'\x{6F44}\x{6F45}\x{6F46}\x{6F47}\x{6F49}\x{6F4B}\x{6F4C}\x{6F4D}\x{6F4E}' . +'\x{6F4F}\x{6F50}\x{6F51}\x{6F52}\x{6F53}\x{6F54}\x{6F55}\x{6F56}\x{6F57}' . +'\x{6F58}\x{6F59}\x{6F5A}\x{6F5B}\x{6F5C}\x{6F5D}\x{6F5E}\x{6F5F}\x{6F60}' . +'\x{6F61}\x{6F62}\x{6F63}\x{6F64}\x{6F65}\x{6F66}\x{6F67}\x{6F68}\x{6F69}' . +'\x{6F6A}\x{6F6B}\x{6F6C}\x{6F6D}\x{6F6E}\x{6F6F}\x{6F70}\x{6F71}\x{6F72}' . +'\x{6F73}\x{6F74}\x{6F75}\x{6F76}\x{6F77}\x{6F78}\x{6F7A}\x{6F7B}\x{6F7C}' . +'\x{6F7D}\x{6F7E}\x{6F7F}\x{6F80}\x{6F81}\x{6F82}\x{6F83}\x{6F84}\x{6F85}' . +'\x{6F86}\x{6F87}\x{6F88}\x{6F89}\x{6F8A}\x{6F8B}\x{6F8C}\x{6F8D}\x{6F8E}' . +'\x{6F8F}\x{6F90}\x{6F91}\x{6F92}\x{6F93}\x{6F94}\x{6F95}\x{6F96}\x{6F97}' . +'\x{6F99}\x{6F9B}\x{6F9C}\x{6F9D}\x{6F9E}\x{6FA0}\x{6FA1}\x{6FA2}\x{6FA3}' . +'\x{6FA4}\x{6FA5}\x{6FA6}\x{6FA7}\x{6FA8}\x{6FA9}\x{6FAA}\x{6FAB}\x{6FAC}' . +'\x{6FAD}\x{6FAE}\x{6FAF}\x{6FB0}\x{6FB1}\x{6FB2}\x{6FB3}\x{6FB4}\x{6FB5}' . +'\x{6FB6}\x{6FB8}\x{6FB9}\x{6FBA}\x{6FBB}\x{6FBC}\x{6FBD}\x{6FBE}\x{6FBF}' . +'\x{6FC0}\x{6FC1}\x{6FC2}\x{6FC3}\x{6FC4}\x{6FC6}\x{6FC7}\x{6FC8}\x{6FC9}' . +'\x{6FCA}\x{6FCB}\x{6FCC}\x{6FCD}\x{6FCE}\x{6FCF}\x{6FD1}\x{6FD2}\x{6FD4}' . +'\x{6FD5}\x{6FD6}\x{6FD7}\x{6FD8}\x{6FD9}\x{6FDA}\x{6FDB}\x{6FDC}\x{6FDD}' . +'\x{6FDE}\x{6FDF}\x{6FE0}\x{6FE1}\x{6FE2}\x{6FE3}\x{6FE4}\x{6FE5}\x{6FE6}' . +'\x{6FE7}\x{6FE8}\x{6FE9}\x{6FEA}\x{6FEB}\x{6FEC}\x{6FED}\x{6FEE}\x{6FEF}' . +'\x{6FF0}\x{6FF1}\x{6FF2}\x{6FF3}\x{6FF4}\x{6FF6}\x{6FF7}\x{6FF8}\x{6FF9}' . +'\x{6FFA}\x{6FFB}\x{6FFC}\x{6FFE}\x{6FFF}\x{7000}\x{7001}\x{7002}\x{7003}' . +'\x{7004}\x{7005}\x{7006}\x{7007}\x{7008}\x{7009}\x{700A}\x{700B}\x{700C}' . +'\x{700D}\x{700E}\x{700F}\x{7011}\x{7012}\x{7014}\x{7015}\x{7016}\x{7017}' . +'\x{7018}\x{7019}\x{701A}\x{701B}\x{701C}\x{701D}\x{701F}\x{7020}\x{7021}' . +'\x{7022}\x{7023}\x{7024}\x{7025}\x{7026}\x{7027}\x{7028}\x{7029}\x{702A}' . +'\x{702B}\x{702C}\x{702D}\x{702E}\x{702F}\x{7030}\x{7031}\x{7032}\x{7033}' . +'\x{7034}\x{7035}\x{7036}\x{7037}\x{7038}\x{7039}\x{703A}\x{703B}\x{703C}' . +'\x{703D}\x{703E}\x{703F}\x{7040}\x{7041}\x{7042}\x{7043}\x{7044}\x{7045}' . +'\x{7046}\x{7048}\x{7049}\x{704A}\x{704C}\x{704D}\x{704F}\x{7050}\x{7051}' . +'\x{7052}\x{7053}\x{7054}\x{7055}\x{7056}\x{7057}\x{7058}\x{7059}\x{705A}' . +'\x{705B}\x{705C}\x{705D}\x{705E}\x{705F}\x{7060}\x{7061}\x{7062}\x{7063}' . +'\x{7064}\x{7065}\x{7066}\x{7067}\x{7068}\x{7069}\x{706A}\x{706B}\x{706C}' . +'\x{706D}\x{706E}\x{706F}\x{7070}\x{7071}\x{7074}\x{7075}\x{7076}\x{7077}' . +'\x{7078}\x{7079}\x{707A}\x{707C}\x{707D}\x{707E}\x{707F}\x{7080}\x{7082}' . +'\x{7083}\x{7084}\x{7085}\x{7086}\x{7087}\x{7088}\x{7089}\x{708A}\x{708B}' . +'\x{708C}\x{708E}\x{708F}\x{7090}\x{7091}\x{7092}\x{7093}\x{7094}\x{7095}' . +'\x{7096}\x{7098}\x{7099}\x{709A}\x{709C}\x{709D}\x{709E}\x{709F}\x{70A0}' . +'\x{70A1}\x{70A2}\x{70A3}\x{70A4}\x{70A5}\x{70A6}\x{70A7}\x{70A8}\x{70A9}' . +'\x{70AB}\x{70AC}\x{70AD}\x{70AE}\x{70AF}\x{70B0}\x{70B1}\x{70B3}\x{70B4}' . +'\x{70B5}\x{70B7}\x{70B8}\x{70B9}\x{70BA}\x{70BB}\x{70BC}\x{70BD}\x{70BE}' . +'\x{70BF}\x{70C0}\x{70C1}\x{70C2}\x{70C3}\x{70C4}\x{70C5}\x{70C6}\x{70C7}' . +'\x{70C8}\x{70C9}\x{70CA}\x{70CB}\x{70CC}\x{70CD}\x{70CE}\x{70CF}\x{70D0}' . +'\x{70D1}\x{70D2}\x{70D3}\x{70D4}\x{70D6}\x{70D7}\x{70D8}\x{70D9}\x{70DA}' . +'\x{70DB}\x{70DC}\x{70DD}\x{70DE}\x{70DF}\x{70E0}\x{70E1}\x{70E2}\x{70E3}' . +'\x{70E4}\x{70E5}\x{70E6}\x{70E7}\x{70E8}\x{70E9}\x{70EA}\x{70EB}\x{70EC}' . +'\x{70ED}\x{70EE}\x{70EF}\x{70F0}\x{70F1}\x{70F2}\x{70F3}\x{70F4}\x{70F5}' . +'\x{70F6}\x{70F7}\x{70F8}\x{70F9}\x{70FA}\x{70FB}\x{70FC}\x{70FD}\x{70FF}' . +'\x{7100}\x{7101}\x{7102}\x{7103}\x{7104}\x{7105}\x{7106}\x{7107}\x{7109}' . +'\x{710A}\x{710B}\x{710C}\x{710D}\x{710E}\x{710F}\x{7110}\x{7111}\x{7112}' . +'\x{7113}\x{7115}\x{7116}\x{7117}\x{7118}\x{7119}\x{711A}\x{711B}\x{711C}' . +'\x{711D}\x{711E}\x{711F}\x{7120}\x{7121}\x{7122}\x{7123}\x{7125}\x{7126}' . +'\x{7127}\x{7128}\x{7129}\x{712A}\x{712B}\x{712C}\x{712D}\x{712E}\x{712F}' . +'\x{7130}\x{7131}\x{7132}\x{7135}\x{7136}\x{7137}\x{7138}\x{7139}\x{713A}' . +'\x{713B}\x{713D}\x{713E}\x{713F}\x{7140}\x{7141}\x{7142}\x{7143}\x{7144}' . +'\x{7145}\x{7146}\x{7147}\x{7148}\x{7149}\x{714A}\x{714B}\x{714C}\x{714D}' . +'\x{714E}\x{714F}\x{7150}\x{7151}\x{7152}\x{7153}\x{7154}\x{7156}\x{7158}' . +'\x{7159}\x{715A}\x{715B}\x{715C}\x{715D}\x{715E}\x{715F}\x{7160}\x{7161}' . +'\x{7162}\x{7163}\x{7164}\x{7165}\x{7166}\x{7167}\x{7168}\x{7169}\x{716A}' . +'\x{716C}\x{716E}\x{716F}\x{7170}\x{7171}\x{7172}\x{7173}\x{7174}\x{7175}' . +'\x{7176}\x{7177}\x{7178}\x{7179}\x{717A}\x{717B}\x{717C}\x{717D}\x{717E}' . +'\x{717F}\x{7180}\x{7181}\x{7182}\x{7183}\x{7184}\x{7185}\x{7186}\x{7187}' . +'\x{7188}\x{7189}\x{718A}\x{718B}\x{718C}\x{718E}\x{718F}\x{7190}\x{7191}' . +'\x{7192}\x{7193}\x{7194}\x{7195}\x{7197}\x{7198}\x{7199}\x{719A}\x{719B}' . +'\x{719C}\x{719D}\x{719E}\x{719F}\x{71A0}\x{71A1}\x{71A2}\x{71A3}\x{71A4}' . +'\x{71A5}\x{71A7}\x{71A8}\x{71A9}\x{71AA}\x{71AC}\x{71AD}\x{71AE}\x{71AF}' . +'\x{71B0}\x{71B1}\x{71B2}\x{71B3}\x{71B4}\x{71B5}\x{71B7}\x{71B8}\x{71B9}' . +'\x{71BA}\x{71BB}\x{71BC}\x{71BD}\x{71BE}\x{71BF}\x{71C0}\x{71C1}\x{71C2}' . +'\x{71C3}\x{71C4}\x{71C5}\x{71C6}\x{71C7}\x{71C8}\x{71C9}\x{71CA}\x{71CB}' . +'\x{71CD}\x{71CE}\x{71CF}\x{71D0}\x{71D1}\x{71D2}\x{71D4}\x{71D5}\x{71D6}' . +'\x{71D7}\x{71D8}\x{71D9}\x{71DA}\x{71DB}\x{71DC}\x{71DD}\x{71DE}\x{71DF}' . +'\x{71E0}\x{71E1}\x{71E2}\x{71E3}\x{71E4}\x{71E5}\x{71E6}\x{71E7}\x{71E8}' . +'\x{71E9}\x{71EA}\x{71EB}\x{71EC}\x{71ED}\x{71EE}\x{71EF}\x{71F0}\x{71F1}' . +'\x{71F2}\x{71F4}\x{71F5}\x{71F6}\x{71F7}\x{71F8}\x{71F9}\x{71FB}\x{71FC}' . +'\x{71FD}\x{71FE}\x{71FF}\x{7201}\x{7202}\x{7203}\x{7204}\x{7205}\x{7206}' . +'\x{7207}\x{7208}\x{7209}\x{720A}\x{720C}\x{720D}\x{720E}\x{720F}\x{7210}' . +'\x{7212}\x{7213}\x{7214}\x{7216}\x{7218}\x{7219}\x{721A}\x{721B}\x{721C}' . +'\x{721D}\x{721E}\x{721F}\x{7221}\x{7222}\x{7223}\x{7226}\x{7227}\x{7228}' . +'\x{7229}\x{722A}\x{722B}\x{722C}\x{722D}\x{722E}\x{7230}\x{7231}\x{7232}' . +'\x{7233}\x{7235}\x{7236}\x{7237}\x{7238}\x{7239}\x{723A}\x{723B}\x{723C}' . +'\x{723D}\x{723E}\x{723F}\x{7240}\x{7241}\x{7242}\x{7243}\x{7244}\x{7246}' . +'\x{7247}\x{7248}\x{7249}\x{724A}\x{724B}\x{724C}\x{724D}\x{724F}\x{7251}' . +'\x{7252}\x{7253}\x{7254}\x{7256}\x{7257}\x{7258}\x{7259}\x{725A}\x{725B}' . +'\x{725C}\x{725D}\x{725E}\x{725F}\x{7260}\x{7261}\x{7262}\x{7263}\x{7264}' . +'\x{7265}\x{7266}\x{7267}\x{7268}\x{7269}\x{726A}\x{726B}\x{726C}\x{726D}' . +'\x{726E}\x{726F}\x{7270}\x{7271}\x{7272}\x{7273}\x{7274}\x{7275}\x{7276}' . +'\x{7277}\x{7278}\x{7279}\x{727A}\x{727B}\x{727C}\x{727D}\x{727E}\x{727F}' . +'\x{7280}\x{7281}\x{7282}\x{7283}\x{7284}\x{7285}\x{7286}\x{7287}\x{7288}' . +'\x{7289}\x{728A}\x{728B}\x{728C}\x{728D}\x{728E}\x{728F}\x{7290}\x{7291}' . +'\x{7292}\x{7293}\x{7294}\x{7295}\x{7296}\x{7297}\x{7298}\x{7299}\x{729A}' . +'\x{729B}\x{729C}\x{729D}\x{729E}\x{729F}\x{72A1}\x{72A2}\x{72A3}\x{72A4}' . +'\x{72A5}\x{72A6}\x{72A7}\x{72A8}\x{72A9}\x{72AA}\x{72AC}\x{72AD}\x{72AE}' . +'\x{72AF}\x{72B0}\x{72B1}\x{72B2}\x{72B3}\x{72B4}\x{72B5}\x{72B6}\x{72B7}' . +'\x{72B8}\x{72B9}\x{72BA}\x{72BB}\x{72BC}\x{72BD}\x{72BF}\x{72C0}\x{72C1}' . +'\x{72C2}\x{72C3}\x{72C4}\x{72C5}\x{72C6}\x{72C7}\x{72C8}\x{72C9}\x{72CA}' . +'\x{72CB}\x{72CC}\x{72CD}\x{72CE}\x{72CF}\x{72D0}\x{72D1}\x{72D2}\x{72D3}' . +'\x{72D4}\x{72D5}\x{72D6}\x{72D7}\x{72D8}\x{72D9}\x{72DA}\x{72DB}\x{72DC}' . +'\x{72DD}\x{72DE}\x{72DF}\x{72E0}\x{72E1}\x{72E2}\x{72E3}\x{72E4}\x{72E5}' . +'\x{72E6}\x{72E7}\x{72E8}\x{72E9}\x{72EA}\x{72EB}\x{72EC}\x{72ED}\x{72EE}' . +'\x{72EF}\x{72F0}\x{72F1}\x{72F2}\x{72F3}\x{72F4}\x{72F5}\x{72F6}\x{72F7}' . +'\x{72F8}\x{72F9}\x{72FA}\x{72FB}\x{72FC}\x{72FD}\x{72FE}\x{72FF}\x{7300}' . +'\x{7301}\x{7303}\x{7304}\x{7305}\x{7306}\x{7307}\x{7308}\x{7309}\x{730A}' . +'\x{730B}\x{730C}\x{730D}\x{730E}\x{730F}\x{7311}\x{7312}\x{7313}\x{7314}' . +'\x{7315}\x{7316}\x{7317}\x{7318}\x{7319}\x{731A}\x{731B}\x{731C}\x{731D}' . +'\x{731E}\x{7320}\x{7321}\x{7322}\x{7323}\x{7324}\x{7325}\x{7326}\x{7327}' . +'\x{7329}\x{732A}\x{732B}\x{732C}\x{732D}\x{732E}\x{7330}\x{7331}\x{7332}' . +'\x{7333}\x{7334}\x{7335}\x{7336}\x{7337}\x{7338}\x{7339}\x{733A}\x{733B}' . +'\x{733C}\x{733D}\x{733E}\x{733F}\x{7340}\x{7341}\x{7342}\x{7343}\x{7344}' . +'\x{7345}\x{7346}\x{7347}\x{7348}\x{7349}\x{734A}\x{734B}\x{734C}\x{734D}' . +'\x{734E}\x{7350}\x{7351}\x{7352}\x{7354}\x{7355}\x{7356}\x{7357}\x{7358}' . +'\x{7359}\x{735A}\x{735B}\x{735C}\x{735D}\x{735E}\x{735F}\x{7360}\x{7361}' . +'\x{7362}\x{7364}\x{7365}\x{7366}\x{7367}\x{7368}\x{7369}\x{736A}\x{736B}' . +'\x{736C}\x{736D}\x{736E}\x{736F}\x{7370}\x{7371}\x{7372}\x{7373}\x{7374}' . +'\x{7375}\x{7376}\x{7377}\x{7378}\x{7379}\x{737A}\x{737B}\x{737C}\x{737D}' . +'\x{737E}\x{737F}\x{7380}\x{7381}\x{7382}\x{7383}\x{7384}\x{7385}\x{7386}' . +'\x{7387}\x{7388}\x{7389}\x{738A}\x{738B}\x{738C}\x{738D}\x{738E}\x{738F}' . +'\x{7390}\x{7391}\x{7392}\x{7393}\x{7394}\x{7395}\x{7396}\x{7397}\x{7398}' . +'\x{7399}\x{739A}\x{739B}\x{739D}\x{739E}\x{739F}\x{73A0}\x{73A1}\x{73A2}' . +'\x{73A3}\x{73A4}\x{73A5}\x{73A6}\x{73A7}\x{73A8}\x{73A9}\x{73AA}\x{73AB}' . +'\x{73AC}\x{73AD}\x{73AE}\x{73AF}\x{73B0}\x{73B1}\x{73B2}\x{73B3}\x{73B4}' . +'\x{73B5}\x{73B6}\x{73B7}\x{73B8}\x{73B9}\x{73BA}\x{73BB}\x{73BC}\x{73BD}' . +'\x{73BE}\x{73BF}\x{73C0}\x{73C2}\x{73C3}\x{73C4}\x{73C5}\x{73C6}\x{73C7}' . +'\x{73C8}\x{73C9}\x{73CA}\x{73CB}\x{73CC}\x{73CD}\x{73CE}\x{73CF}\x{73D0}' . +'\x{73D1}\x{73D2}\x{73D3}\x{73D4}\x{73D5}\x{73D6}\x{73D7}\x{73D8}\x{73D9}' . +'\x{73DA}\x{73DB}\x{73DC}\x{73DD}\x{73DE}\x{73DF}\x{73E0}\x{73E2}\x{73E3}' . +'\x{73E5}\x{73E6}\x{73E7}\x{73E8}\x{73E9}\x{73EA}\x{73EB}\x{73EC}\x{73ED}' . +'\x{73EE}\x{73EF}\x{73F0}\x{73F1}\x{73F2}\x{73F4}\x{73F5}\x{73F6}\x{73F7}' . +'\x{73F8}\x{73F9}\x{73FA}\x{73FC}\x{73FD}\x{73FE}\x{73FF}\x{7400}\x{7401}' . +'\x{7402}\x{7403}\x{7404}\x{7405}\x{7406}\x{7407}\x{7408}\x{7409}\x{740A}' . +'\x{740B}\x{740C}\x{740D}\x{740E}\x{740F}\x{7410}\x{7411}\x{7412}\x{7413}' . +'\x{7414}\x{7415}\x{7416}\x{7417}\x{7419}\x{741A}\x{741B}\x{741C}\x{741D}' . +'\x{741E}\x{741F}\x{7420}\x{7421}\x{7422}\x{7423}\x{7424}\x{7425}\x{7426}' . +'\x{7427}\x{7428}\x{7429}\x{742A}\x{742B}\x{742C}\x{742D}\x{742E}\x{742F}' . +'\x{7430}\x{7431}\x{7432}\x{7433}\x{7434}\x{7435}\x{7436}\x{7437}\x{7438}' . +'\x{743A}\x{743B}\x{743C}\x{743D}\x{743F}\x{7440}\x{7441}\x{7442}\x{7443}' . +'\x{7444}\x{7445}\x{7446}\x{7448}\x{744A}\x{744B}\x{744C}\x{744D}\x{744E}' . +'\x{744F}\x{7450}\x{7451}\x{7452}\x{7453}\x{7454}\x{7455}\x{7456}\x{7457}' . +'\x{7459}\x{745A}\x{745B}\x{745C}\x{745D}\x{745E}\x{745F}\x{7461}\x{7462}' . +'\x{7463}\x{7464}\x{7465}\x{7466}\x{7467}\x{7468}\x{7469}\x{746A}\x{746B}' . +'\x{746C}\x{746D}\x{746E}\x{746F}\x{7470}\x{7471}\x{7472}\x{7473}\x{7474}' . +'\x{7475}\x{7476}\x{7477}\x{7478}\x{7479}\x{747A}\x{747C}\x{747D}\x{747E}' . +'\x{747F}\x{7480}\x{7481}\x{7482}\x{7483}\x{7485}\x{7486}\x{7487}\x{7488}' . +'\x{7489}\x{748A}\x{748B}\x{748C}\x{748D}\x{748E}\x{748F}\x{7490}\x{7491}' . +'\x{7492}\x{7493}\x{7494}\x{7495}\x{7497}\x{7498}\x{7499}\x{749A}\x{749B}' . +'\x{749C}\x{749E}\x{749F}\x{74A0}\x{74A1}\x{74A3}\x{74A4}\x{74A5}\x{74A6}' . +'\x{74A7}\x{74A8}\x{74A9}\x{74AA}\x{74AB}\x{74AC}\x{74AD}\x{74AE}\x{74AF}' . +'\x{74B0}\x{74B1}\x{74B2}\x{74B3}\x{74B4}\x{74B5}\x{74B6}\x{74B7}\x{74B8}' . +'\x{74B9}\x{74BA}\x{74BB}\x{74BC}\x{74BD}\x{74BE}\x{74BF}\x{74C0}\x{74C1}' . +'\x{74C2}\x{74C3}\x{74C4}\x{74C5}\x{74C6}\x{74CA}\x{74CB}\x{74CD}\x{74CE}' . +'\x{74CF}\x{74D0}\x{74D1}\x{74D2}\x{74D3}\x{74D4}\x{74D5}\x{74D6}\x{74D7}' . +'\x{74D8}\x{74D9}\x{74DA}\x{74DB}\x{74DC}\x{74DD}\x{74DE}\x{74DF}\x{74E0}' . +'\x{74E1}\x{74E2}\x{74E3}\x{74E4}\x{74E5}\x{74E6}\x{74E7}\x{74E8}\x{74E9}' . +'\x{74EA}\x{74EC}\x{74ED}\x{74EE}\x{74EF}\x{74F0}\x{74F1}\x{74F2}\x{74F3}' . +'\x{74F4}\x{74F5}\x{74F6}\x{74F7}\x{74F8}\x{74F9}\x{74FA}\x{74FB}\x{74FC}' . +'\x{74FD}\x{74FE}\x{74FF}\x{7500}\x{7501}\x{7502}\x{7503}\x{7504}\x{7505}' . +'\x{7506}\x{7507}\x{7508}\x{7509}\x{750A}\x{750B}\x{750C}\x{750D}\x{750F}' . +'\x{7510}\x{7511}\x{7512}\x{7513}\x{7514}\x{7515}\x{7516}\x{7517}\x{7518}' . +'\x{7519}\x{751A}\x{751B}\x{751C}\x{751D}\x{751E}\x{751F}\x{7521}\x{7522}' . +'\x{7523}\x{7524}\x{7525}\x{7526}\x{7527}\x{7528}\x{7529}\x{752A}\x{752B}' . +'\x{752C}\x{752D}\x{752E}\x{752F}\x{7530}\x{7531}\x{7532}\x{7533}\x{7535}' . +'\x{7536}\x{7537}\x{7538}\x{7539}\x{753A}\x{753B}\x{753C}\x{753D}\x{753E}' . +'\x{753F}\x{7540}\x{7542}\x{7543}\x{7544}\x{7545}\x{7546}\x{7547}\x{7548}' . +'\x{7549}\x{754B}\x{754C}\x{754D}\x{754E}\x{754F}\x{7550}\x{7551}\x{7553}' . +'\x{7554}\x{7556}\x{7557}\x{7558}\x{7559}\x{755A}\x{755B}\x{755C}\x{755D}' . +'\x{755F}\x{7560}\x{7562}\x{7563}\x{7564}\x{7565}\x{7566}\x{7567}\x{7568}' . +'\x{7569}\x{756A}\x{756B}\x{756C}\x{756D}\x{756E}\x{756F}\x{7570}\x{7572}' . +'\x{7574}\x{7575}\x{7576}\x{7577}\x{7578}\x{7579}\x{757C}\x{757D}\x{757E}' . +'\x{757F}\x{7580}\x{7581}\x{7582}\x{7583}\x{7584}\x{7586}\x{7587}\x{7588}' . +'\x{7589}\x{758A}\x{758B}\x{758C}\x{758D}\x{758F}\x{7590}\x{7591}\x{7592}' . +'\x{7593}\x{7594}\x{7595}\x{7596}\x{7597}\x{7598}\x{7599}\x{759A}\x{759B}' . +'\x{759C}\x{759D}\x{759E}\x{759F}\x{75A0}\x{75A1}\x{75A2}\x{75A3}\x{75A4}' . +'\x{75A5}\x{75A6}\x{75A7}\x{75A8}\x{75AA}\x{75AB}\x{75AC}\x{75AD}\x{75AE}' . +'\x{75AF}\x{75B0}\x{75B1}\x{75B2}\x{75B3}\x{75B4}\x{75B5}\x{75B6}\x{75B8}' . +'\x{75B9}\x{75BA}\x{75BB}\x{75BC}\x{75BD}\x{75BE}\x{75BF}\x{75C0}\x{75C1}' . +'\x{75C2}\x{75C3}\x{75C4}\x{75C5}\x{75C6}\x{75C7}\x{75C8}\x{75C9}\x{75CA}' . +'\x{75CB}\x{75CC}\x{75CD}\x{75CE}\x{75CF}\x{75D0}\x{75D1}\x{75D2}\x{75D3}' . +'\x{75D4}\x{75D5}\x{75D6}\x{75D7}\x{75D8}\x{75D9}\x{75DA}\x{75DB}\x{75DD}' . +'\x{75DE}\x{75DF}\x{75E0}\x{75E1}\x{75E2}\x{75E3}\x{75E4}\x{75E5}\x{75E6}' . +'\x{75E7}\x{75E8}\x{75EA}\x{75EB}\x{75EC}\x{75ED}\x{75EF}\x{75F0}\x{75F1}' . +'\x{75F2}\x{75F3}\x{75F4}\x{75F5}\x{75F6}\x{75F7}\x{75F8}\x{75F9}\x{75FA}' . +'\x{75FB}\x{75FC}\x{75FD}\x{75FE}\x{75FF}\x{7600}\x{7601}\x{7602}\x{7603}' . +'\x{7604}\x{7605}\x{7606}\x{7607}\x{7608}\x{7609}\x{760A}\x{760B}\x{760C}' . +'\x{760D}\x{760E}\x{760F}\x{7610}\x{7611}\x{7612}\x{7613}\x{7614}\x{7615}' . +'\x{7616}\x{7617}\x{7618}\x{7619}\x{761A}\x{761B}\x{761C}\x{761D}\x{761E}' . +'\x{761F}\x{7620}\x{7621}\x{7622}\x{7623}\x{7624}\x{7625}\x{7626}\x{7627}' . +'\x{7628}\x{7629}\x{762A}\x{762B}\x{762D}\x{762E}\x{762F}\x{7630}\x{7631}' . +'\x{7632}\x{7633}\x{7634}\x{7635}\x{7636}\x{7637}\x{7638}\x{7639}\x{763A}' . +'\x{763B}\x{763C}\x{763D}\x{763E}\x{763F}\x{7640}\x{7641}\x{7642}\x{7643}' . +'\x{7646}\x{7647}\x{7648}\x{7649}\x{764A}\x{764B}\x{764C}\x{764D}\x{764F}' . +'\x{7650}\x{7652}\x{7653}\x{7654}\x{7656}\x{7657}\x{7658}\x{7659}\x{765A}' . +'\x{765B}\x{765C}\x{765D}\x{765E}\x{765F}\x{7660}\x{7661}\x{7662}\x{7663}' . +'\x{7664}\x{7665}\x{7666}\x{7667}\x{7668}\x{7669}\x{766A}\x{766B}\x{766C}' . +'\x{766D}\x{766E}\x{766F}\x{7670}\x{7671}\x{7672}\x{7674}\x{7675}\x{7676}' . +'\x{7677}\x{7678}\x{7679}\x{767B}\x{767C}\x{767D}\x{767E}\x{767F}\x{7680}' . +'\x{7681}\x{7682}\x{7683}\x{7684}\x{7685}\x{7686}\x{7687}\x{7688}\x{7689}' . +'\x{768A}\x{768B}\x{768C}\x{768E}\x{768F}\x{7690}\x{7691}\x{7692}\x{7693}' . +'\x{7694}\x{7695}\x{7696}\x{7697}\x{7698}\x{7699}\x{769A}\x{769B}\x{769C}' . +'\x{769D}\x{769E}\x{769F}\x{76A0}\x{76A3}\x{76A4}\x{76A6}\x{76A7}\x{76A9}' . +'\x{76AA}\x{76AB}\x{76AC}\x{76AD}\x{76AE}\x{76AF}\x{76B0}\x{76B1}\x{76B2}' . +'\x{76B4}\x{76B5}\x{76B7}\x{76B8}\x{76BA}\x{76BB}\x{76BC}\x{76BD}\x{76BE}' . +'\x{76BF}\x{76C0}\x{76C2}\x{76C3}\x{76C4}\x{76C5}\x{76C6}\x{76C7}\x{76C8}' . +'\x{76C9}\x{76CA}\x{76CD}\x{76CE}\x{76CF}\x{76D0}\x{76D1}\x{76D2}\x{76D3}' . +'\x{76D4}\x{76D5}\x{76D6}\x{76D7}\x{76D8}\x{76DA}\x{76DB}\x{76DC}\x{76DD}' . +'\x{76DE}\x{76DF}\x{76E0}\x{76E1}\x{76E2}\x{76E3}\x{76E4}\x{76E5}\x{76E6}' . +'\x{76E7}\x{76E8}\x{76E9}\x{76EA}\x{76EC}\x{76ED}\x{76EE}\x{76EF}\x{76F0}' . +'\x{76F1}\x{76F2}\x{76F3}\x{76F4}\x{76F5}\x{76F6}\x{76F7}\x{76F8}\x{76F9}' . +'\x{76FA}\x{76FB}\x{76FC}\x{76FD}\x{76FE}\x{76FF}\x{7701}\x{7703}\x{7704}' . +'\x{7705}\x{7706}\x{7707}\x{7708}\x{7709}\x{770A}\x{770B}\x{770C}\x{770D}' . +'\x{770F}\x{7710}\x{7711}\x{7712}\x{7713}\x{7714}\x{7715}\x{7716}\x{7717}' . +'\x{7718}\x{7719}\x{771A}\x{771B}\x{771C}\x{771D}\x{771E}\x{771F}\x{7720}' . +'\x{7722}\x{7723}\x{7725}\x{7726}\x{7727}\x{7728}\x{7729}\x{772A}\x{772C}' . +'\x{772D}\x{772E}\x{772F}\x{7730}\x{7731}\x{7732}\x{7733}\x{7734}\x{7735}' . +'\x{7736}\x{7737}\x{7738}\x{7739}\x{773A}\x{773B}\x{773C}\x{773D}\x{773E}' . +'\x{7740}\x{7741}\x{7743}\x{7744}\x{7745}\x{7746}\x{7747}\x{7748}\x{7749}' . +'\x{774A}\x{774B}\x{774C}\x{774D}\x{774E}\x{774F}\x{7750}\x{7751}\x{7752}' . +'\x{7753}\x{7754}\x{7755}\x{7756}\x{7757}\x{7758}\x{7759}\x{775A}\x{775B}' . +'\x{775C}\x{775D}\x{775E}\x{775F}\x{7760}\x{7761}\x{7762}\x{7763}\x{7765}' . +'\x{7766}\x{7767}\x{7768}\x{7769}\x{776A}\x{776B}\x{776C}\x{776D}\x{776E}' . +'\x{776F}\x{7770}\x{7771}\x{7772}\x{7773}\x{7774}\x{7775}\x{7776}\x{7777}' . +'\x{7778}\x{7779}\x{777A}\x{777B}\x{777C}\x{777D}\x{777E}\x{777F}\x{7780}' . +'\x{7781}\x{7782}\x{7783}\x{7784}\x{7785}\x{7786}\x{7787}\x{7788}\x{7789}' . +'\x{778A}\x{778B}\x{778C}\x{778D}\x{778E}\x{778F}\x{7790}\x{7791}\x{7792}' . +'\x{7793}\x{7794}\x{7795}\x{7797}\x{7798}\x{7799}\x{779A}\x{779B}\x{779C}' . +'\x{779D}\x{779E}\x{779F}\x{77A0}\x{77A1}\x{77A2}\x{77A3}\x{77A5}\x{77A6}' . +'\x{77A7}\x{77A8}\x{77A9}\x{77AA}\x{77AB}\x{77AC}\x{77AD}\x{77AE}\x{77AF}' . +'\x{77B0}\x{77B1}\x{77B2}\x{77B3}\x{77B4}\x{77B5}\x{77B6}\x{77B7}\x{77B8}' . +'\x{77B9}\x{77BA}\x{77BB}\x{77BC}\x{77BD}\x{77BF}\x{77C0}\x{77C2}\x{77C3}' . +'\x{77C4}\x{77C5}\x{77C6}\x{77C7}\x{77C8}\x{77C9}\x{77CA}\x{77CB}\x{77CC}' . +'\x{77CD}\x{77CE}\x{77CF}\x{77D0}\x{77D1}\x{77D3}\x{77D4}\x{77D5}\x{77D6}' . +'\x{77D7}\x{77D8}\x{77D9}\x{77DA}\x{77DB}\x{77DC}\x{77DE}\x{77DF}\x{77E0}' . +'\x{77E1}\x{77E2}\x{77E3}\x{77E5}\x{77E7}\x{77E8}\x{77E9}\x{77EA}\x{77EB}' . +'\x{77EC}\x{77ED}\x{77EE}\x{77EF}\x{77F0}\x{77F1}\x{77F2}\x{77F3}\x{77F6}' . +'\x{77F7}\x{77F8}\x{77F9}\x{77FA}\x{77FB}\x{77FC}\x{77FD}\x{77FE}\x{77FF}' . +'\x{7800}\x{7801}\x{7802}\x{7803}\x{7804}\x{7805}\x{7806}\x{7808}\x{7809}' . +'\x{780A}\x{780B}\x{780C}\x{780D}\x{780E}\x{780F}\x{7810}\x{7811}\x{7812}' . +'\x{7813}\x{7814}\x{7815}\x{7816}\x{7817}\x{7818}\x{7819}\x{781A}\x{781B}' . +'\x{781C}\x{781D}\x{781E}\x{781F}\x{7820}\x{7821}\x{7822}\x{7823}\x{7825}' . +'\x{7826}\x{7827}\x{7828}\x{7829}\x{782A}\x{782B}\x{782C}\x{782D}\x{782E}' . +'\x{782F}\x{7830}\x{7831}\x{7832}\x{7833}\x{7834}\x{7835}\x{7837}\x{7838}' . +'\x{7839}\x{783A}\x{783B}\x{783C}\x{783D}\x{783E}\x{7840}\x{7841}\x{7843}' . +'\x{7844}\x{7845}\x{7847}\x{7848}\x{7849}\x{784A}\x{784C}\x{784D}\x{784E}' . +'\x{7850}\x{7851}\x{7852}\x{7853}\x{7854}\x{7855}\x{7856}\x{7857}\x{7858}' . +'\x{7859}\x{785A}\x{785B}\x{785C}\x{785D}\x{785E}\x{785F}\x{7860}\x{7861}' . +'\x{7862}\x{7863}\x{7864}\x{7865}\x{7866}\x{7867}\x{7868}\x{7869}\x{786A}' . +'\x{786B}\x{786C}\x{786D}\x{786E}\x{786F}\x{7870}\x{7871}\x{7872}\x{7873}' . +'\x{7874}\x{7875}\x{7877}\x{7878}\x{7879}\x{787A}\x{787B}\x{787C}\x{787D}' . +'\x{787E}\x{787F}\x{7880}\x{7881}\x{7882}\x{7883}\x{7884}\x{7885}\x{7886}' . +'\x{7887}\x{7889}\x{788A}\x{788B}\x{788C}\x{788D}\x{788E}\x{788F}\x{7890}' . +'\x{7891}\x{7892}\x{7893}\x{7894}\x{7895}\x{7896}\x{7897}\x{7898}\x{7899}' . +'\x{789A}\x{789B}\x{789C}\x{789D}\x{789E}\x{789F}\x{78A0}\x{78A1}\x{78A2}' . +'\x{78A3}\x{78A4}\x{78A5}\x{78A6}\x{78A7}\x{78A8}\x{78A9}\x{78AA}\x{78AB}' . +'\x{78AC}\x{78AD}\x{78AE}\x{78AF}\x{78B0}\x{78B1}\x{78B2}\x{78B3}\x{78B4}' . +'\x{78B5}\x{78B6}\x{78B7}\x{78B8}\x{78B9}\x{78BA}\x{78BB}\x{78BC}\x{78BD}' . +'\x{78BE}\x{78BF}\x{78C0}\x{78C1}\x{78C3}\x{78C4}\x{78C5}\x{78C6}\x{78C8}' . +'\x{78C9}\x{78CA}\x{78CB}\x{78CC}\x{78CD}\x{78CE}\x{78CF}\x{78D0}\x{78D1}' . +'\x{78D3}\x{78D4}\x{78D5}\x{78D6}\x{78D7}\x{78D8}\x{78D9}\x{78DA}\x{78DB}' . +'\x{78DC}\x{78DD}\x{78DE}\x{78DF}\x{78E0}\x{78E1}\x{78E2}\x{78E3}\x{78E4}' . +'\x{78E5}\x{78E6}\x{78E7}\x{78E8}\x{78E9}\x{78EA}\x{78EB}\x{78EC}\x{78ED}' . +'\x{78EE}\x{78EF}\x{78F1}\x{78F2}\x{78F3}\x{78F4}\x{78F5}\x{78F6}\x{78F7}' . +'\x{78F9}\x{78FA}\x{78FB}\x{78FC}\x{78FD}\x{78FE}\x{78FF}\x{7901}\x{7902}' . +'\x{7903}\x{7904}\x{7905}\x{7906}\x{7907}\x{7909}\x{790A}\x{790B}\x{790C}' . +'\x{790E}\x{790F}\x{7910}\x{7911}\x{7912}\x{7913}\x{7914}\x{7916}\x{7917}' . +'\x{7918}\x{7919}\x{791A}\x{791B}\x{791C}\x{791D}\x{791E}\x{7921}\x{7922}' . +'\x{7923}\x{7924}\x{7925}\x{7926}\x{7927}\x{7928}\x{7929}\x{792A}\x{792B}' . +'\x{792C}\x{792D}\x{792E}\x{792F}\x{7930}\x{7931}\x{7933}\x{7934}\x{7935}' . +'\x{7937}\x{7938}\x{7939}\x{793A}\x{793B}\x{793C}\x{793D}\x{793E}\x{793F}' . +'\x{7940}\x{7941}\x{7942}\x{7943}\x{7944}\x{7945}\x{7946}\x{7947}\x{7948}' . +'\x{7949}\x{794A}\x{794B}\x{794C}\x{794D}\x{794E}\x{794F}\x{7950}\x{7951}' . +'\x{7952}\x{7953}\x{7954}\x{7955}\x{7956}\x{7957}\x{7958}\x{795A}\x{795B}' . +'\x{795C}\x{795D}\x{795E}\x{795F}\x{7960}\x{7961}\x{7962}\x{7963}\x{7964}' . +'\x{7965}\x{7966}\x{7967}\x{7968}\x{7969}\x{796A}\x{796B}\x{796D}\x{796F}' . +'\x{7970}\x{7971}\x{7972}\x{7973}\x{7974}\x{7977}\x{7978}\x{7979}\x{797A}' . +'\x{797B}\x{797C}\x{797D}\x{797E}\x{797F}\x{7980}\x{7981}\x{7982}\x{7983}' . +'\x{7984}\x{7985}\x{7988}\x{7989}\x{798A}\x{798B}\x{798C}\x{798D}\x{798E}' . +'\x{798F}\x{7990}\x{7991}\x{7992}\x{7993}\x{7994}\x{7995}\x{7996}\x{7997}' . +'\x{7998}\x{7999}\x{799A}\x{799B}\x{799C}\x{799F}\x{79A0}\x{79A1}\x{79A2}' . +'\x{79A3}\x{79A4}\x{79A5}\x{79A6}\x{79A7}\x{79A8}\x{79AA}\x{79AB}\x{79AC}' . +'\x{79AD}\x{79AE}\x{79AF}\x{79B0}\x{79B1}\x{79B2}\x{79B3}\x{79B4}\x{79B5}' . +'\x{79B6}\x{79B7}\x{79B8}\x{79B9}\x{79BA}\x{79BB}\x{79BD}\x{79BE}\x{79BF}' . +'\x{79C0}\x{79C1}\x{79C2}\x{79C3}\x{79C5}\x{79C6}\x{79C8}\x{79C9}\x{79CA}' . +'\x{79CB}\x{79CD}\x{79CE}\x{79CF}\x{79D0}\x{79D1}\x{79D2}\x{79D3}\x{79D5}' . +'\x{79D6}\x{79D8}\x{79D9}\x{79DA}\x{79DB}\x{79DC}\x{79DD}\x{79DE}\x{79DF}' . +'\x{79E0}\x{79E1}\x{79E2}\x{79E3}\x{79E4}\x{79E5}\x{79E6}\x{79E7}\x{79E8}' . +'\x{79E9}\x{79EA}\x{79EB}\x{79EC}\x{79ED}\x{79EE}\x{79EF}\x{79F0}\x{79F1}' . +'\x{79F2}\x{79F3}\x{79F4}\x{79F5}\x{79F6}\x{79F7}\x{79F8}\x{79F9}\x{79FA}' . +'\x{79FB}\x{79FC}\x{79FD}\x{79FE}\x{79FF}\x{7A00}\x{7A02}\x{7A03}\x{7A04}' . +'\x{7A05}\x{7A06}\x{7A08}\x{7A0A}\x{7A0B}\x{7A0C}\x{7A0D}\x{7A0E}\x{7A0F}' . +'\x{7A10}\x{7A11}\x{7A12}\x{7A13}\x{7A14}\x{7A15}\x{7A16}\x{7A17}\x{7A18}' . +'\x{7A19}\x{7A1A}\x{7A1B}\x{7A1C}\x{7A1D}\x{7A1E}\x{7A1F}\x{7A20}\x{7A21}' . +'\x{7A22}\x{7A23}\x{7A24}\x{7A25}\x{7A26}\x{7A27}\x{7A28}\x{7A29}\x{7A2A}' . +'\x{7A2B}\x{7A2D}\x{7A2E}\x{7A2F}\x{7A30}\x{7A31}\x{7A32}\x{7A33}\x{7A34}' . +'\x{7A35}\x{7A37}\x{7A39}\x{7A3B}\x{7A3C}\x{7A3D}\x{7A3E}\x{7A3F}\x{7A40}' . +'\x{7A41}\x{7A42}\x{7A43}\x{7A44}\x{7A45}\x{7A46}\x{7A47}\x{7A48}\x{7A49}' . +'\x{7A4A}\x{7A4B}\x{7A4C}\x{7A4D}\x{7A4E}\x{7A50}\x{7A51}\x{7A52}\x{7A53}' . +'\x{7A54}\x{7A55}\x{7A56}\x{7A57}\x{7A58}\x{7A59}\x{7A5A}\x{7A5B}\x{7A5C}' . +'\x{7A5D}\x{7A5E}\x{7A5F}\x{7A60}\x{7A61}\x{7A62}\x{7A65}\x{7A66}\x{7A67}' . +'\x{7A68}\x{7A69}\x{7A6B}\x{7A6C}\x{7A6D}\x{7A6E}\x{7A70}\x{7A71}\x{7A72}' . +'\x{7A73}\x{7A74}\x{7A75}\x{7A76}\x{7A77}\x{7A78}\x{7A79}\x{7A7A}\x{7A7B}' . +'\x{7A7C}\x{7A7D}\x{7A7E}\x{7A7F}\x{7A80}\x{7A81}\x{7A83}\x{7A84}\x{7A85}' . +'\x{7A86}\x{7A87}\x{7A88}\x{7A89}\x{7A8A}\x{7A8B}\x{7A8C}\x{7A8D}\x{7A8E}' . +'\x{7A8F}\x{7A90}\x{7A91}\x{7A92}\x{7A93}\x{7A94}\x{7A95}\x{7A96}\x{7A97}' . +'\x{7A98}\x{7A99}\x{7A9C}\x{7A9D}\x{7A9E}\x{7A9F}\x{7AA0}\x{7AA1}\x{7AA2}' . +'\x{7AA3}\x{7AA4}\x{7AA5}\x{7AA6}\x{7AA7}\x{7AA8}\x{7AA9}\x{7AAA}\x{7AAB}' . +'\x{7AAC}\x{7AAD}\x{7AAE}\x{7AAF}\x{7AB0}\x{7AB1}\x{7AB2}\x{7AB3}\x{7AB4}' . +'\x{7AB5}\x{7AB6}\x{7AB7}\x{7AB8}\x{7ABA}\x{7ABE}\x{7ABF}\x{7AC0}\x{7AC1}' . +'\x{7AC4}\x{7AC5}\x{7AC7}\x{7AC8}\x{7AC9}\x{7ACA}\x{7ACB}\x{7ACC}\x{7ACD}' . +'\x{7ACE}\x{7ACF}\x{7AD0}\x{7AD1}\x{7AD2}\x{7AD3}\x{7AD4}\x{7AD5}\x{7AD6}' . +'\x{7AD8}\x{7AD9}\x{7ADB}\x{7ADC}\x{7ADD}\x{7ADE}\x{7ADF}\x{7AE0}\x{7AE1}' . +'\x{7AE2}\x{7AE3}\x{7AE4}\x{7AE5}\x{7AE6}\x{7AE7}\x{7AE8}\x{7AEA}\x{7AEB}' . +'\x{7AEC}\x{7AED}\x{7AEE}\x{7AEF}\x{7AF0}\x{7AF1}\x{7AF2}\x{7AF3}\x{7AF4}' . +'\x{7AF6}\x{7AF7}\x{7AF8}\x{7AF9}\x{7AFA}\x{7AFB}\x{7AFD}\x{7AFE}\x{7AFF}' . +'\x{7B00}\x{7B01}\x{7B02}\x{7B03}\x{7B04}\x{7B05}\x{7B06}\x{7B08}\x{7B09}' . +'\x{7B0A}\x{7B0B}\x{7B0C}\x{7B0D}\x{7B0E}\x{7B0F}\x{7B10}\x{7B11}\x{7B12}' . +'\x{7B13}\x{7B14}\x{7B15}\x{7B16}\x{7B17}\x{7B18}\x{7B19}\x{7B1A}\x{7B1B}' . +'\x{7B1C}\x{7B1D}\x{7B1E}\x{7B20}\x{7B21}\x{7B22}\x{7B23}\x{7B24}\x{7B25}' . +'\x{7B26}\x{7B28}\x{7B2A}\x{7B2B}\x{7B2C}\x{7B2D}\x{7B2E}\x{7B2F}\x{7B30}' . +'\x{7B31}\x{7B32}\x{7B33}\x{7B34}\x{7B35}\x{7B36}\x{7B37}\x{7B38}\x{7B39}' . +'\x{7B3A}\x{7B3B}\x{7B3C}\x{7B3D}\x{7B3E}\x{7B3F}\x{7B40}\x{7B41}\x{7B43}' . +'\x{7B44}\x{7B45}\x{7B46}\x{7B47}\x{7B48}\x{7B49}\x{7B4A}\x{7B4B}\x{7B4C}' . +'\x{7B4D}\x{7B4E}\x{7B4F}\x{7B50}\x{7B51}\x{7B52}\x{7B54}\x{7B55}\x{7B56}' . +'\x{7B57}\x{7B58}\x{7B59}\x{7B5A}\x{7B5B}\x{7B5C}\x{7B5D}\x{7B5E}\x{7B5F}' . +'\x{7B60}\x{7B61}\x{7B62}\x{7B63}\x{7B64}\x{7B65}\x{7B66}\x{7B67}\x{7B68}' . +'\x{7B69}\x{7B6A}\x{7B6B}\x{7B6C}\x{7B6D}\x{7B6E}\x{7B70}\x{7B71}\x{7B72}' . +'\x{7B73}\x{7B74}\x{7B75}\x{7B76}\x{7B77}\x{7B78}\x{7B79}\x{7B7B}\x{7B7C}' . +'\x{7B7D}\x{7B7E}\x{7B7F}\x{7B80}\x{7B81}\x{7B82}\x{7B83}\x{7B84}\x{7B85}' . +'\x{7B87}\x{7B88}\x{7B89}\x{7B8A}\x{7B8B}\x{7B8C}\x{7B8D}\x{7B8E}\x{7B8F}' . +'\x{7B90}\x{7B91}\x{7B93}\x{7B94}\x{7B95}\x{7B96}\x{7B97}\x{7B98}\x{7B99}' . +'\x{7B9A}\x{7B9B}\x{7B9C}\x{7B9D}\x{7B9E}\x{7B9F}\x{7BA0}\x{7BA1}\x{7BA2}' . +'\x{7BA4}\x{7BA6}\x{7BA7}\x{7BA8}\x{7BA9}\x{7BAA}\x{7BAB}\x{7BAC}\x{7BAD}' . +'\x{7BAE}\x{7BAF}\x{7BB1}\x{7BB3}\x{7BB4}\x{7BB5}\x{7BB6}\x{7BB7}\x{7BB8}' . +'\x{7BB9}\x{7BBA}\x{7BBB}\x{7BBC}\x{7BBD}\x{7BBE}\x{7BBF}\x{7BC0}\x{7BC1}' . +'\x{7BC2}\x{7BC3}\x{7BC4}\x{7BC5}\x{7BC6}\x{7BC7}\x{7BC8}\x{7BC9}\x{7BCA}' . +'\x{7BCB}\x{7BCC}\x{7BCD}\x{7BCE}\x{7BD0}\x{7BD1}\x{7BD2}\x{7BD3}\x{7BD4}' . +'\x{7BD5}\x{7BD6}\x{7BD7}\x{7BD8}\x{7BD9}\x{7BDA}\x{7BDB}\x{7BDC}\x{7BDD}' . +'\x{7BDE}\x{7BDF}\x{7BE0}\x{7BE1}\x{7BE2}\x{7BE3}\x{7BE4}\x{7BE5}\x{7BE6}' . +'\x{7BE7}\x{7BE8}\x{7BE9}\x{7BEA}\x{7BEB}\x{7BEC}\x{7BED}\x{7BEE}\x{7BEF}' . +'\x{7BF0}\x{7BF1}\x{7BF2}\x{7BF3}\x{7BF4}\x{7BF5}\x{7BF6}\x{7BF7}\x{7BF8}' . +'\x{7BF9}\x{7BFB}\x{7BFC}\x{7BFD}\x{7BFE}\x{7BFF}\x{7C00}\x{7C01}\x{7C02}' . +'\x{7C03}\x{7C04}\x{7C05}\x{7C06}\x{7C07}\x{7C08}\x{7C09}\x{7C0A}\x{7C0B}' . +'\x{7C0C}\x{7C0D}\x{7C0E}\x{7C0F}\x{7C10}\x{7C11}\x{7C12}\x{7C13}\x{7C15}' . +'\x{7C16}\x{7C17}\x{7C18}\x{7C19}\x{7C1A}\x{7C1C}\x{7C1D}\x{7C1E}\x{7C1F}' . +'\x{7C20}\x{7C21}\x{7C22}\x{7C23}\x{7C24}\x{7C25}\x{7C26}\x{7C27}\x{7C28}' . +'\x{7C29}\x{7C2A}\x{7C2B}\x{7C2C}\x{7C2D}\x{7C30}\x{7C31}\x{7C32}\x{7C33}' . +'\x{7C34}\x{7C35}\x{7C36}\x{7C37}\x{7C38}\x{7C39}\x{7C3A}\x{7C3B}\x{7C3C}' . +'\x{7C3D}\x{7C3E}\x{7C3F}\x{7C40}\x{7C41}\x{7C42}\x{7C43}\x{7C44}\x{7C45}' . +'\x{7C46}\x{7C47}\x{7C48}\x{7C49}\x{7C4A}\x{7C4B}\x{7C4C}\x{7C4D}\x{7C4E}' . +'\x{7C50}\x{7C51}\x{7C53}\x{7C54}\x{7C56}\x{7C57}\x{7C58}\x{7C59}\x{7C5A}' . +'\x{7C5B}\x{7C5C}\x{7C5E}\x{7C5F}\x{7C60}\x{7C61}\x{7C62}\x{7C63}\x{7C64}' . +'\x{7C65}\x{7C66}\x{7C67}\x{7C68}\x{7C69}\x{7C6A}\x{7C6B}\x{7C6C}\x{7C6D}' . +'\x{7C6E}\x{7C6F}\x{7C70}\x{7C71}\x{7C72}\x{7C73}\x{7C74}\x{7C75}\x{7C77}' . +'\x{7C78}\x{7C79}\x{7C7A}\x{7C7B}\x{7C7C}\x{7C7D}\x{7C7E}\x{7C7F}\x{7C80}' . +'\x{7C81}\x{7C82}\x{7C84}\x{7C85}\x{7C86}\x{7C88}\x{7C89}\x{7C8A}\x{7C8B}' . +'\x{7C8C}\x{7C8D}\x{7C8E}\x{7C8F}\x{7C90}\x{7C91}\x{7C92}\x{7C94}\x{7C95}' . +'\x{7C96}\x{7C97}\x{7C98}\x{7C99}\x{7C9B}\x{7C9C}\x{7C9D}\x{7C9E}\x{7C9F}' . +'\x{7CA0}\x{7CA1}\x{7CA2}\x{7CA3}\x{7CA4}\x{7CA5}\x{7CA6}\x{7CA7}\x{7CA8}' . +'\x{7CA9}\x{7CAA}\x{7CAD}\x{7CAE}\x{7CAF}\x{7CB0}\x{7CB1}\x{7CB2}\x{7CB3}' . +'\x{7CB4}\x{7CB5}\x{7CB6}\x{7CB7}\x{7CB8}\x{7CB9}\x{7CBA}\x{7CBB}\x{7CBC}' . +'\x{7CBD}\x{7CBE}\x{7CBF}\x{7CC0}\x{7CC1}\x{7CC2}\x{7CC3}\x{7CC4}\x{7CC5}' . +'\x{7CC6}\x{7CC7}\x{7CC8}\x{7CC9}\x{7CCA}\x{7CCB}\x{7CCC}\x{7CCD}\x{7CCE}' . +'\x{7CCF}\x{7CD0}\x{7CD1}\x{7CD2}\x{7CD4}\x{7CD5}\x{7CD6}\x{7CD7}\x{7CD8}' . +'\x{7CD9}\x{7CDC}\x{7CDD}\x{7CDE}\x{7CDF}\x{7CE0}\x{7CE2}\x{7CE4}\x{7CE7}' . +'\x{7CE8}\x{7CE9}\x{7CEA}\x{7CEB}\x{7CEC}\x{7CED}\x{7CEE}\x{7CEF}\x{7CF0}' . +'\x{7CF1}\x{7CF2}\x{7CF3}\x{7CF4}\x{7CF5}\x{7CF6}\x{7CF7}\x{7CF8}\x{7CF9}' . +'\x{7CFA}\x{7CFB}\x{7CFD}\x{7CFE}\x{7D00}\x{7D01}\x{7D02}\x{7D03}\x{7D04}' . +'\x{7D05}\x{7D06}\x{7D07}\x{7D08}\x{7D09}\x{7D0A}\x{7D0B}\x{7D0C}\x{7D0D}' . +'\x{7D0E}\x{7D0F}\x{7D10}\x{7D11}\x{7D12}\x{7D13}\x{7D14}\x{7D15}\x{7D16}' . +'\x{7D17}\x{7D18}\x{7D19}\x{7D1A}\x{7D1B}\x{7D1C}\x{7D1D}\x{7D1E}\x{7D1F}' . +'\x{7D20}\x{7D21}\x{7D22}\x{7D24}\x{7D25}\x{7D26}\x{7D27}\x{7D28}\x{7D29}' . +'\x{7D2B}\x{7D2C}\x{7D2E}\x{7D2F}\x{7D30}\x{7D31}\x{7D32}\x{7D33}\x{7D34}' . +'\x{7D35}\x{7D36}\x{7D37}\x{7D38}\x{7D39}\x{7D3A}\x{7D3B}\x{7D3C}\x{7D3D}' . +'\x{7D3E}\x{7D3F}\x{7D40}\x{7D41}\x{7D42}\x{7D43}\x{7D44}\x{7D45}\x{7D46}' . +'\x{7D47}\x{7D49}\x{7D4A}\x{7D4B}\x{7D4C}\x{7D4E}\x{7D4F}\x{7D50}\x{7D51}' . +'\x{7D52}\x{7D53}\x{7D54}\x{7D55}\x{7D56}\x{7D57}\x{7D58}\x{7D59}\x{7D5B}' . +'\x{7D5C}\x{7D5D}\x{7D5E}\x{7D5F}\x{7D60}\x{7D61}\x{7D62}\x{7D63}\x{7D65}' . +'\x{7D66}\x{7D67}\x{7D68}\x{7D69}\x{7D6A}\x{7D6B}\x{7D6C}\x{7D6D}\x{7D6E}' . +'\x{7D6F}\x{7D70}\x{7D71}\x{7D72}\x{7D73}\x{7D74}\x{7D75}\x{7D76}\x{7D77}' . +'\x{7D79}\x{7D7A}\x{7D7B}\x{7D7C}\x{7D7D}\x{7D7E}\x{7D7F}\x{7D80}\x{7D81}' . +'\x{7D83}\x{7D84}\x{7D85}\x{7D86}\x{7D87}\x{7D88}\x{7D89}\x{7D8A}\x{7D8B}' . +'\x{7D8C}\x{7D8D}\x{7D8E}\x{7D8F}\x{7D90}\x{7D91}\x{7D92}\x{7D93}\x{7D94}' . +'\x{7D96}\x{7D97}\x{7D99}\x{7D9B}\x{7D9C}\x{7D9D}\x{7D9E}\x{7D9F}\x{7DA0}' . +'\x{7DA1}\x{7DA2}\x{7DA3}\x{7DA5}\x{7DA6}\x{7DA7}\x{7DA9}\x{7DAA}\x{7DAB}' . +'\x{7DAC}\x{7DAD}\x{7DAE}\x{7DAF}\x{7DB0}\x{7DB1}\x{7DB2}\x{7DB3}\x{7DB4}' . +'\x{7DB5}\x{7DB6}\x{7DB7}\x{7DB8}\x{7DB9}\x{7DBA}\x{7DBB}\x{7DBC}\x{7DBD}' . +'\x{7DBE}\x{7DBF}\x{7DC0}\x{7DC1}\x{7DC2}\x{7DC3}\x{7DC4}\x{7DC5}\x{7DC6}' . +'\x{7DC7}\x{7DC8}\x{7DC9}\x{7DCA}\x{7DCB}\x{7DCC}\x{7DCE}\x{7DCF}\x{7DD0}' . +'\x{7DD1}\x{7DD2}\x{7DD4}\x{7DD5}\x{7DD6}\x{7DD7}\x{7DD8}\x{7DD9}\x{7DDA}' . +'\x{7DDB}\x{7DDD}\x{7DDE}\x{7DDF}\x{7DE0}\x{7DE1}\x{7DE2}\x{7DE3}\x{7DE6}' . +'\x{7DE7}\x{7DE8}\x{7DE9}\x{7DEA}\x{7DEC}\x{7DED}\x{7DEE}\x{7DEF}\x{7DF0}' . +'\x{7DF1}\x{7DF2}\x{7DF3}\x{7DF4}\x{7DF5}\x{7DF6}\x{7DF7}\x{7DF8}\x{7DF9}' . +'\x{7DFA}\x{7DFB}\x{7DFC}\x{7E00}\x{7E01}\x{7E02}\x{7E03}\x{7E04}\x{7E05}' . +'\x{7E06}\x{7E07}\x{7E08}\x{7E09}\x{7E0A}\x{7E0B}\x{7E0C}\x{7E0D}\x{7E0E}' . +'\x{7E0F}\x{7E10}\x{7E11}\x{7E12}\x{7E13}\x{7E14}\x{7E15}\x{7E16}\x{7E17}' . +'\x{7E19}\x{7E1A}\x{7E1B}\x{7E1C}\x{7E1D}\x{7E1E}\x{7E1F}\x{7E20}\x{7E21}' . +'\x{7E22}\x{7E23}\x{7E24}\x{7E25}\x{7E26}\x{7E27}\x{7E28}\x{7E29}\x{7E2A}' . +'\x{7E2B}\x{7E2C}\x{7E2D}\x{7E2E}\x{7E2F}\x{7E30}\x{7E31}\x{7E32}\x{7E33}' . +'\x{7E34}\x{7E35}\x{7E36}\x{7E37}\x{7E38}\x{7E39}\x{7E3A}\x{7E3B}\x{7E3C}' . +'\x{7E3D}\x{7E3E}\x{7E3F}\x{7E40}\x{7E41}\x{7E42}\x{7E43}\x{7E44}\x{7E45}' . +'\x{7E46}\x{7E47}\x{7E48}\x{7E49}\x{7E4C}\x{7E4D}\x{7E4E}\x{7E4F}\x{7E50}' . +'\x{7E51}\x{7E52}\x{7E53}\x{7E54}\x{7E55}\x{7E56}\x{7E57}\x{7E58}\x{7E59}' . +'\x{7E5A}\x{7E5C}\x{7E5D}\x{7E5E}\x{7E5F}\x{7E60}\x{7E61}\x{7E62}\x{7E63}' . +'\x{7E65}\x{7E66}\x{7E67}\x{7E68}\x{7E69}\x{7E6A}\x{7E6B}\x{7E6C}\x{7E6D}' . +'\x{7E6E}\x{7E6F}\x{7E70}\x{7E71}\x{7E72}\x{7E73}\x{7E74}\x{7E75}\x{7E76}' . +'\x{7E77}\x{7E78}\x{7E79}\x{7E7A}\x{7E7B}\x{7E7C}\x{7E7D}\x{7E7E}\x{7E7F}' . +'\x{7E80}\x{7E81}\x{7E82}\x{7E83}\x{7E84}\x{7E85}\x{7E86}\x{7E87}\x{7E88}' . +'\x{7E89}\x{7E8A}\x{7E8B}\x{7E8C}\x{7E8D}\x{7E8E}\x{7E8F}\x{7E90}\x{7E91}' . +'\x{7E92}\x{7E93}\x{7E94}\x{7E95}\x{7E96}\x{7E97}\x{7E98}\x{7E99}\x{7E9A}' . +'\x{7E9B}\x{7E9C}\x{7E9E}\x{7E9F}\x{7EA0}\x{7EA1}\x{7EA2}\x{7EA3}\x{7EA4}' . +'\x{7EA5}\x{7EA6}\x{7EA7}\x{7EA8}\x{7EA9}\x{7EAA}\x{7EAB}\x{7EAC}\x{7EAD}' . +'\x{7EAE}\x{7EAF}\x{7EB0}\x{7EB1}\x{7EB2}\x{7EB3}\x{7EB4}\x{7EB5}\x{7EB6}' . +'\x{7EB7}\x{7EB8}\x{7EB9}\x{7EBA}\x{7EBB}\x{7EBC}\x{7EBD}\x{7EBE}\x{7EBF}' . +'\x{7EC0}\x{7EC1}\x{7EC2}\x{7EC3}\x{7EC4}\x{7EC5}\x{7EC6}\x{7EC7}\x{7EC8}' . +'\x{7EC9}\x{7ECA}\x{7ECB}\x{7ECC}\x{7ECD}\x{7ECE}\x{7ECF}\x{7ED0}\x{7ED1}' . +'\x{7ED2}\x{7ED3}\x{7ED4}\x{7ED5}\x{7ED6}\x{7ED7}\x{7ED8}\x{7ED9}\x{7EDA}' . +'\x{7EDB}\x{7EDC}\x{7EDD}\x{7EDE}\x{7EDF}\x{7EE0}\x{7EE1}\x{7EE2}\x{7EE3}' . +'\x{7EE4}\x{7EE5}\x{7EE6}\x{7EE7}\x{7EE8}\x{7EE9}\x{7EEA}\x{7EEB}\x{7EEC}' . +'\x{7EED}\x{7EEE}\x{7EEF}\x{7EF0}\x{7EF1}\x{7EF2}\x{7EF3}\x{7EF4}\x{7EF5}' . +'\x{7EF6}\x{7EF7}\x{7EF8}\x{7EF9}\x{7EFA}\x{7EFB}\x{7EFC}\x{7EFD}\x{7EFE}' . +'\x{7EFF}\x{7F00}\x{7F01}\x{7F02}\x{7F03}\x{7F04}\x{7F05}\x{7F06}\x{7F07}' . +'\x{7F08}\x{7F09}\x{7F0A}\x{7F0B}\x{7F0C}\x{7F0D}\x{7F0E}\x{7F0F}\x{7F10}' . +'\x{7F11}\x{7F12}\x{7F13}\x{7F14}\x{7F15}\x{7F16}\x{7F17}\x{7F18}\x{7F19}' . +'\x{7F1A}\x{7F1B}\x{7F1C}\x{7F1D}\x{7F1E}\x{7F1F}\x{7F20}\x{7F21}\x{7F22}' . +'\x{7F23}\x{7F24}\x{7F25}\x{7F26}\x{7F27}\x{7F28}\x{7F29}\x{7F2A}\x{7F2B}' . +'\x{7F2C}\x{7F2D}\x{7F2E}\x{7F2F}\x{7F30}\x{7F31}\x{7F32}\x{7F33}\x{7F34}' . +'\x{7F35}\x{7F36}\x{7F37}\x{7F38}\x{7F39}\x{7F3A}\x{7F3D}\x{7F3E}\x{7F3F}' . +'\x{7F40}\x{7F42}\x{7F43}\x{7F44}\x{7F45}\x{7F47}\x{7F48}\x{7F49}\x{7F4A}' . +'\x{7F4B}\x{7F4C}\x{7F4D}\x{7F4E}\x{7F4F}\x{7F50}\x{7F51}\x{7F52}\x{7F53}' . +'\x{7F54}\x{7F55}\x{7F56}\x{7F57}\x{7F58}\x{7F5A}\x{7F5B}\x{7F5C}\x{7F5D}' . +'\x{7F5E}\x{7F5F}\x{7F60}\x{7F61}\x{7F62}\x{7F63}\x{7F64}\x{7F65}\x{7F66}' . +'\x{7F67}\x{7F68}\x{7F69}\x{7F6A}\x{7F6B}\x{7F6C}\x{7F6D}\x{7F6E}\x{7F6F}' . +'\x{7F70}\x{7F71}\x{7F72}\x{7F73}\x{7F74}\x{7F75}\x{7F76}\x{7F77}\x{7F78}' . +'\x{7F79}\x{7F7A}\x{7F7B}\x{7F7C}\x{7F7D}\x{7F7E}\x{7F7F}\x{7F80}\x{7F81}' . +'\x{7F82}\x{7F83}\x{7F85}\x{7F86}\x{7F87}\x{7F88}\x{7F89}\x{7F8A}\x{7F8B}' . +'\x{7F8C}\x{7F8D}\x{7F8E}\x{7F8F}\x{7F91}\x{7F92}\x{7F93}\x{7F94}\x{7F95}' . +'\x{7F96}\x{7F98}\x{7F9A}\x{7F9B}\x{7F9C}\x{7F9D}\x{7F9E}\x{7F9F}\x{7FA0}' . +'\x{7FA1}\x{7FA2}\x{7FA3}\x{7FA4}\x{7FA5}\x{7FA6}\x{7FA7}\x{7FA8}\x{7FA9}' . +'\x{7FAA}\x{7FAB}\x{7FAC}\x{7FAD}\x{7FAE}\x{7FAF}\x{7FB0}\x{7FB1}\x{7FB2}' . +'\x{7FB3}\x{7FB5}\x{7FB6}\x{7FB7}\x{7FB8}\x{7FB9}\x{7FBA}\x{7FBB}\x{7FBC}' . +'\x{7FBD}\x{7FBE}\x{7FBF}\x{7FC0}\x{7FC1}\x{7FC2}\x{7FC3}\x{7FC4}\x{7FC5}' . +'\x{7FC6}\x{7FC7}\x{7FC8}\x{7FC9}\x{7FCA}\x{7FCB}\x{7FCC}\x{7FCD}\x{7FCE}' . +'\x{7FCF}\x{7FD0}\x{7FD1}\x{7FD2}\x{7FD3}\x{7FD4}\x{7FD5}\x{7FD7}\x{7FD8}' . +'\x{7FD9}\x{7FDA}\x{7FDB}\x{7FDC}\x{7FDE}\x{7FDF}\x{7FE0}\x{7FE1}\x{7FE2}' . +'\x{7FE3}\x{7FE5}\x{7FE6}\x{7FE7}\x{7FE8}\x{7FE9}\x{7FEA}\x{7FEB}\x{7FEC}' . +'\x{7FED}\x{7FEE}\x{7FEF}\x{7FF0}\x{7FF1}\x{7FF2}\x{7FF3}\x{7FF4}\x{7FF5}' . +'\x{7FF6}\x{7FF7}\x{7FF8}\x{7FF9}\x{7FFA}\x{7FFB}\x{7FFC}\x{7FFD}\x{7FFE}' . +'\x{7FFF}\x{8000}\x{8001}\x{8002}\x{8003}\x{8004}\x{8005}\x{8006}\x{8007}' . +'\x{8008}\x{8009}\x{800B}\x{800C}\x{800D}\x{800E}\x{800F}\x{8010}\x{8011}' . +'\x{8012}\x{8013}\x{8014}\x{8015}\x{8016}\x{8017}\x{8018}\x{8019}\x{801A}' . +'\x{801B}\x{801C}\x{801D}\x{801E}\x{801F}\x{8020}\x{8021}\x{8022}\x{8023}' . +'\x{8024}\x{8025}\x{8026}\x{8027}\x{8028}\x{8029}\x{802A}\x{802B}\x{802C}' . +'\x{802D}\x{802E}\x{8030}\x{8031}\x{8032}\x{8033}\x{8034}\x{8035}\x{8036}' . +'\x{8037}\x{8038}\x{8039}\x{803A}\x{803B}\x{803D}\x{803E}\x{803F}\x{8041}' . +'\x{8042}\x{8043}\x{8044}\x{8045}\x{8046}\x{8047}\x{8048}\x{8049}\x{804A}' . +'\x{804B}\x{804C}\x{804D}\x{804E}\x{804F}\x{8050}\x{8051}\x{8052}\x{8053}' . +'\x{8054}\x{8055}\x{8056}\x{8057}\x{8058}\x{8059}\x{805A}\x{805B}\x{805C}' . +'\x{805D}\x{805E}\x{805F}\x{8060}\x{8061}\x{8062}\x{8063}\x{8064}\x{8065}' . +'\x{8067}\x{8068}\x{8069}\x{806A}\x{806B}\x{806C}\x{806D}\x{806E}\x{806F}' . +'\x{8070}\x{8071}\x{8072}\x{8073}\x{8074}\x{8075}\x{8076}\x{8077}\x{8078}' . +'\x{8079}\x{807A}\x{807B}\x{807C}\x{807D}\x{807E}\x{807F}\x{8080}\x{8081}' . +'\x{8082}\x{8083}\x{8084}\x{8085}\x{8086}\x{8087}\x{8089}\x{808A}\x{808B}' . +'\x{808C}\x{808D}\x{808F}\x{8090}\x{8091}\x{8092}\x{8093}\x{8095}\x{8096}' . +'\x{8097}\x{8098}\x{8099}\x{809A}\x{809B}\x{809C}\x{809D}\x{809E}\x{809F}' . +'\x{80A0}\x{80A1}\x{80A2}\x{80A3}\x{80A4}\x{80A5}\x{80A9}\x{80AA}\x{80AB}' . +'\x{80AD}\x{80AE}\x{80AF}\x{80B0}\x{80B1}\x{80B2}\x{80B4}\x{80B5}\x{80B6}' . +'\x{80B7}\x{80B8}\x{80BA}\x{80BB}\x{80BC}\x{80BD}\x{80BE}\x{80BF}\x{80C0}' . +'\x{80C1}\x{80C2}\x{80C3}\x{80C4}\x{80C5}\x{80C6}\x{80C7}\x{80C8}\x{80C9}' . +'\x{80CA}\x{80CB}\x{80CC}\x{80CD}\x{80CE}\x{80CF}\x{80D0}\x{80D1}\x{80D2}' . +'\x{80D3}\x{80D4}\x{80D5}\x{80D6}\x{80D7}\x{80D8}\x{80D9}\x{80DA}\x{80DB}' . +'\x{80DC}\x{80DD}\x{80DE}\x{80E0}\x{80E1}\x{80E2}\x{80E3}\x{80E4}\x{80E5}' . +'\x{80E6}\x{80E7}\x{80E8}\x{80E9}\x{80EA}\x{80EB}\x{80EC}\x{80ED}\x{80EE}' . +'\x{80EF}\x{80F0}\x{80F1}\x{80F2}\x{80F3}\x{80F4}\x{80F5}\x{80F6}\x{80F7}' . +'\x{80F8}\x{80F9}\x{80FA}\x{80FB}\x{80FC}\x{80FD}\x{80FE}\x{80FF}\x{8100}' . +'\x{8101}\x{8102}\x{8105}\x{8106}\x{8107}\x{8108}\x{8109}\x{810A}\x{810B}' . +'\x{810C}\x{810D}\x{810E}\x{810F}\x{8110}\x{8111}\x{8112}\x{8113}\x{8114}' . +'\x{8115}\x{8116}\x{8118}\x{8119}\x{811A}\x{811B}\x{811C}\x{811D}\x{811E}' . +'\x{811F}\x{8120}\x{8121}\x{8122}\x{8123}\x{8124}\x{8125}\x{8126}\x{8127}' . +'\x{8128}\x{8129}\x{812A}\x{812B}\x{812C}\x{812D}\x{812E}\x{812F}\x{8130}' . +'\x{8131}\x{8132}\x{8136}\x{8137}\x{8138}\x{8139}\x{813A}\x{813B}\x{813C}' . +'\x{813D}\x{813E}\x{813F}\x{8140}\x{8141}\x{8142}\x{8143}\x{8144}\x{8145}' . +'\x{8146}\x{8147}\x{8148}\x{8149}\x{814A}\x{814B}\x{814C}\x{814D}\x{814E}' . +'\x{814F}\x{8150}\x{8151}\x{8152}\x{8153}\x{8154}\x{8155}\x{8156}\x{8157}' . +'\x{8158}\x{8159}\x{815A}\x{815B}\x{815C}\x{815D}\x{815E}\x{8160}\x{8161}' . +'\x{8162}\x{8163}\x{8164}\x{8165}\x{8166}\x{8167}\x{8168}\x{8169}\x{816A}' . +'\x{816B}\x{816C}\x{816D}\x{816E}\x{816F}\x{8170}\x{8171}\x{8172}\x{8173}' . +'\x{8174}\x{8175}\x{8176}\x{8177}\x{8178}\x{8179}\x{817A}\x{817B}\x{817C}' . +'\x{817D}\x{817E}\x{817F}\x{8180}\x{8181}\x{8182}\x{8183}\x{8185}\x{8186}' . +'\x{8187}\x{8188}\x{8189}\x{818A}\x{818B}\x{818C}\x{818D}\x{818E}\x{818F}' . +'\x{8191}\x{8192}\x{8193}\x{8194}\x{8195}\x{8197}\x{8198}\x{8199}\x{819A}' . +'\x{819B}\x{819C}\x{819D}\x{819E}\x{819F}\x{81A0}\x{81A1}\x{81A2}\x{81A3}' . +'\x{81A4}\x{81A5}\x{81A6}\x{81A7}\x{81A8}\x{81A9}\x{81AA}\x{81AB}\x{81AC}' . +'\x{81AD}\x{81AE}\x{81AF}\x{81B0}\x{81B1}\x{81B2}\x{81B3}\x{81B4}\x{81B5}' . +'\x{81B6}\x{81B7}\x{81B8}\x{81B9}\x{81BA}\x{81BB}\x{81BC}\x{81BD}\x{81BE}' . +'\x{81BF}\x{81C0}\x{81C1}\x{81C2}\x{81C3}\x{81C4}\x{81C5}\x{81C6}\x{81C7}' . +'\x{81C8}\x{81C9}\x{81CA}\x{81CC}\x{81CD}\x{81CE}\x{81CF}\x{81D0}\x{81D1}' . +'\x{81D2}\x{81D4}\x{81D5}\x{81D6}\x{81D7}\x{81D8}\x{81D9}\x{81DA}\x{81DB}' . +'\x{81DC}\x{81DD}\x{81DE}\x{81DF}\x{81E0}\x{81E1}\x{81E2}\x{81E3}\x{81E5}' . +'\x{81E6}\x{81E7}\x{81E8}\x{81E9}\x{81EA}\x{81EB}\x{81EC}\x{81ED}\x{81EE}' . +'\x{81F1}\x{81F2}\x{81F3}\x{81F4}\x{81F5}\x{81F6}\x{81F7}\x{81F8}\x{81F9}' . +'\x{81FA}\x{81FB}\x{81FC}\x{81FD}\x{81FE}\x{81FF}\x{8200}\x{8201}\x{8202}' . +'\x{8203}\x{8204}\x{8205}\x{8206}\x{8207}\x{8208}\x{8209}\x{820A}\x{820B}' . +'\x{820C}\x{820D}\x{820E}\x{820F}\x{8210}\x{8211}\x{8212}\x{8214}\x{8215}' . +'\x{8216}\x{8218}\x{8219}\x{821A}\x{821B}\x{821C}\x{821D}\x{821E}\x{821F}' . +'\x{8220}\x{8221}\x{8222}\x{8223}\x{8225}\x{8226}\x{8227}\x{8228}\x{8229}' . +'\x{822A}\x{822B}\x{822C}\x{822D}\x{822F}\x{8230}\x{8231}\x{8232}\x{8233}' . +'\x{8234}\x{8235}\x{8236}\x{8237}\x{8238}\x{8239}\x{823A}\x{823B}\x{823C}' . +'\x{823D}\x{823E}\x{823F}\x{8240}\x{8242}\x{8243}\x{8244}\x{8245}\x{8246}' . +'\x{8247}\x{8248}\x{8249}\x{824A}\x{824B}\x{824C}\x{824D}\x{824E}\x{824F}' . +'\x{8250}\x{8251}\x{8252}\x{8253}\x{8254}\x{8255}\x{8256}\x{8257}\x{8258}' . +'\x{8259}\x{825A}\x{825B}\x{825C}\x{825D}\x{825E}\x{825F}\x{8260}\x{8261}' . +'\x{8263}\x{8264}\x{8266}\x{8267}\x{8268}\x{8269}\x{826A}\x{826B}\x{826C}' . +'\x{826D}\x{826E}\x{826F}\x{8270}\x{8271}\x{8272}\x{8273}\x{8274}\x{8275}' . +'\x{8276}\x{8277}\x{8278}\x{8279}\x{827A}\x{827B}\x{827C}\x{827D}\x{827E}' . +'\x{827F}\x{8280}\x{8281}\x{8282}\x{8283}\x{8284}\x{8285}\x{8286}\x{8287}' . +'\x{8288}\x{8289}\x{828A}\x{828B}\x{828D}\x{828E}\x{828F}\x{8290}\x{8291}' . +'\x{8292}\x{8293}\x{8294}\x{8295}\x{8296}\x{8297}\x{8298}\x{8299}\x{829A}' . +'\x{829B}\x{829C}\x{829D}\x{829E}\x{829F}\x{82A0}\x{82A1}\x{82A2}\x{82A3}' . +'\x{82A4}\x{82A5}\x{82A6}\x{82A7}\x{82A8}\x{82A9}\x{82AA}\x{82AB}\x{82AC}' . +'\x{82AD}\x{82AE}\x{82AF}\x{82B0}\x{82B1}\x{82B3}\x{82B4}\x{82B5}\x{82B6}' . +'\x{82B7}\x{82B8}\x{82B9}\x{82BA}\x{82BB}\x{82BC}\x{82BD}\x{82BE}\x{82BF}' . +'\x{82C0}\x{82C1}\x{82C2}\x{82C3}\x{82C4}\x{82C5}\x{82C6}\x{82C7}\x{82C8}' . +'\x{82C9}\x{82CA}\x{82CB}\x{82CC}\x{82CD}\x{82CE}\x{82CF}\x{82D0}\x{82D1}' . +'\x{82D2}\x{82D3}\x{82D4}\x{82D5}\x{82D6}\x{82D7}\x{82D8}\x{82D9}\x{82DA}' . +'\x{82DB}\x{82DC}\x{82DD}\x{82DE}\x{82DF}\x{82E0}\x{82E1}\x{82E3}\x{82E4}' . +'\x{82E5}\x{82E6}\x{82E7}\x{82E8}\x{82E9}\x{82EA}\x{82EB}\x{82EC}\x{82ED}' . +'\x{82EE}\x{82EF}\x{82F0}\x{82F1}\x{82F2}\x{82F3}\x{82F4}\x{82F5}\x{82F6}' . +'\x{82F7}\x{82F8}\x{82F9}\x{82FA}\x{82FB}\x{82FD}\x{82FE}\x{82FF}\x{8300}' . +'\x{8301}\x{8302}\x{8303}\x{8304}\x{8305}\x{8306}\x{8307}\x{8308}\x{8309}' . +'\x{830B}\x{830C}\x{830D}\x{830E}\x{830F}\x{8311}\x{8312}\x{8313}\x{8314}' . +'\x{8315}\x{8316}\x{8317}\x{8318}\x{8319}\x{831A}\x{831B}\x{831C}\x{831D}' . +'\x{831E}\x{831F}\x{8320}\x{8321}\x{8322}\x{8323}\x{8324}\x{8325}\x{8326}' . +'\x{8327}\x{8328}\x{8329}\x{832A}\x{832B}\x{832C}\x{832D}\x{832E}\x{832F}' . +'\x{8331}\x{8332}\x{8333}\x{8334}\x{8335}\x{8336}\x{8337}\x{8338}\x{8339}' . +'\x{833A}\x{833B}\x{833C}\x{833D}\x{833E}\x{833F}\x{8340}\x{8341}\x{8342}' . +'\x{8343}\x{8344}\x{8345}\x{8346}\x{8347}\x{8348}\x{8349}\x{834A}\x{834B}' . +'\x{834C}\x{834D}\x{834E}\x{834F}\x{8350}\x{8351}\x{8352}\x{8353}\x{8354}' . +'\x{8356}\x{8357}\x{8358}\x{8359}\x{835A}\x{835B}\x{835C}\x{835D}\x{835E}' . +'\x{835F}\x{8360}\x{8361}\x{8362}\x{8363}\x{8364}\x{8365}\x{8366}\x{8367}' . +'\x{8368}\x{8369}\x{836A}\x{836B}\x{836C}\x{836D}\x{836E}\x{836F}\x{8370}' . +'\x{8371}\x{8372}\x{8373}\x{8374}\x{8375}\x{8376}\x{8377}\x{8378}\x{8379}' . +'\x{837A}\x{837B}\x{837C}\x{837D}\x{837E}\x{837F}\x{8380}\x{8381}\x{8382}' . +'\x{8383}\x{8384}\x{8385}\x{8386}\x{8387}\x{8388}\x{8389}\x{838A}\x{838B}' . +'\x{838C}\x{838D}\x{838E}\x{838F}\x{8390}\x{8391}\x{8392}\x{8393}\x{8394}' . +'\x{8395}\x{8396}\x{8397}\x{8398}\x{8399}\x{839A}\x{839B}\x{839C}\x{839D}' . +'\x{839E}\x{83A0}\x{83A1}\x{83A2}\x{83A3}\x{83A4}\x{83A5}\x{83A6}\x{83A7}' . +'\x{83A8}\x{83A9}\x{83AA}\x{83AB}\x{83AC}\x{83AD}\x{83AE}\x{83AF}\x{83B0}' . +'\x{83B1}\x{83B2}\x{83B3}\x{83B4}\x{83B6}\x{83B7}\x{83B8}\x{83B9}\x{83BA}' . +'\x{83BB}\x{83BC}\x{83BD}\x{83BF}\x{83C0}\x{83C1}\x{83C2}\x{83C3}\x{83C4}' . +'\x{83C5}\x{83C6}\x{83C7}\x{83C8}\x{83C9}\x{83CA}\x{83CB}\x{83CC}\x{83CD}' . +'\x{83CE}\x{83CF}\x{83D0}\x{83D1}\x{83D2}\x{83D3}\x{83D4}\x{83D5}\x{83D6}' . +'\x{83D7}\x{83D8}\x{83D9}\x{83DA}\x{83DB}\x{83DC}\x{83DD}\x{83DE}\x{83DF}' . +'\x{83E0}\x{83E1}\x{83E2}\x{83E3}\x{83E4}\x{83E5}\x{83E7}\x{83E8}\x{83E9}' . +'\x{83EA}\x{83EB}\x{83EC}\x{83EE}\x{83EF}\x{83F0}\x{83F1}\x{83F2}\x{83F3}' . +'\x{83F4}\x{83F5}\x{83F6}\x{83F7}\x{83F8}\x{83F9}\x{83FA}\x{83FB}\x{83FC}' . +'\x{83FD}\x{83FE}\x{83FF}\x{8400}\x{8401}\x{8402}\x{8403}\x{8404}\x{8405}' . +'\x{8406}\x{8407}\x{8408}\x{8409}\x{840A}\x{840B}\x{840C}\x{840D}\x{840E}' . +'\x{840F}\x{8410}\x{8411}\x{8412}\x{8413}\x{8415}\x{8418}\x{8419}\x{841A}' . +'\x{841B}\x{841C}\x{841D}\x{841E}\x{8421}\x{8422}\x{8423}\x{8424}\x{8425}' . +'\x{8426}\x{8427}\x{8428}\x{8429}\x{842A}\x{842B}\x{842C}\x{842D}\x{842E}' . +'\x{842F}\x{8430}\x{8431}\x{8432}\x{8433}\x{8434}\x{8435}\x{8436}\x{8437}' . +'\x{8438}\x{8439}\x{843A}\x{843B}\x{843C}\x{843D}\x{843E}\x{843F}\x{8440}' . +'\x{8441}\x{8442}\x{8443}\x{8444}\x{8445}\x{8446}\x{8447}\x{8448}\x{8449}' . +'\x{844A}\x{844B}\x{844C}\x{844D}\x{844E}\x{844F}\x{8450}\x{8451}\x{8452}' . +'\x{8453}\x{8454}\x{8455}\x{8456}\x{8457}\x{8459}\x{845A}\x{845B}\x{845C}' . +'\x{845D}\x{845E}\x{845F}\x{8460}\x{8461}\x{8462}\x{8463}\x{8464}\x{8465}' . +'\x{8466}\x{8467}\x{8468}\x{8469}\x{846A}\x{846B}\x{846C}\x{846D}\x{846E}' . +'\x{846F}\x{8470}\x{8471}\x{8472}\x{8473}\x{8474}\x{8475}\x{8476}\x{8477}' . +'\x{8478}\x{8479}\x{847A}\x{847B}\x{847C}\x{847D}\x{847E}\x{847F}\x{8480}' . +'\x{8481}\x{8482}\x{8484}\x{8485}\x{8486}\x{8487}\x{8488}\x{8489}\x{848A}' . +'\x{848B}\x{848C}\x{848D}\x{848E}\x{848F}\x{8490}\x{8491}\x{8492}\x{8493}' . +'\x{8494}\x{8496}\x{8497}\x{8498}\x{8499}\x{849A}\x{849B}\x{849C}\x{849D}' . +'\x{849E}\x{849F}\x{84A0}\x{84A1}\x{84A2}\x{84A3}\x{84A4}\x{84A5}\x{84A6}' . +'\x{84A7}\x{84A8}\x{84A9}\x{84AA}\x{84AB}\x{84AC}\x{84AE}\x{84AF}\x{84B0}' . +'\x{84B1}\x{84B2}\x{84B3}\x{84B4}\x{84B5}\x{84B6}\x{84B8}\x{84B9}\x{84BA}' . +'\x{84BB}\x{84BC}\x{84BD}\x{84BE}\x{84BF}\x{84C0}\x{84C1}\x{84C2}\x{84C4}' . +'\x{84C5}\x{84C6}\x{84C7}\x{84C8}\x{84C9}\x{84CA}\x{84CB}\x{84CC}\x{84CD}' . +'\x{84CE}\x{84CF}\x{84D0}\x{84D1}\x{84D2}\x{84D3}\x{84D4}\x{84D5}\x{84D6}' . +'\x{84D7}\x{84D8}\x{84D9}\x{84DB}\x{84DC}\x{84DD}\x{84DE}\x{84DF}\x{84E0}' . +'\x{84E1}\x{84E2}\x{84E3}\x{84E4}\x{84E5}\x{84E6}\x{84E7}\x{84E8}\x{84E9}' . +'\x{84EA}\x{84EB}\x{84EC}\x{84EE}\x{84EF}\x{84F0}\x{84F1}\x{84F2}\x{84F3}' . +'\x{84F4}\x{84F5}\x{84F6}\x{84F7}\x{84F8}\x{84F9}\x{84FA}\x{84FB}\x{84FC}' . +'\x{84FD}\x{84FE}\x{84FF}\x{8500}\x{8501}\x{8502}\x{8503}\x{8504}\x{8506}' . +'\x{8507}\x{8508}\x{8509}\x{850A}\x{850B}\x{850C}\x{850D}\x{850E}\x{850F}' . +'\x{8511}\x{8512}\x{8513}\x{8514}\x{8515}\x{8516}\x{8517}\x{8518}\x{8519}' . +'\x{851A}\x{851B}\x{851C}\x{851D}\x{851E}\x{851F}\x{8520}\x{8521}\x{8522}' . +'\x{8523}\x{8524}\x{8525}\x{8526}\x{8527}\x{8528}\x{8529}\x{852A}\x{852B}' . +'\x{852C}\x{852D}\x{852E}\x{852F}\x{8530}\x{8531}\x{8534}\x{8535}\x{8536}' . +'\x{8537}\x{8538}\x{8539}\x{853A}\x{853B}\x{853C}\x{853D}\x{853E}\x{853F}' . +'\x{8540}\x{8541}\x{8542}\x{8543}\x{8544}\x{8545}\x{8546}\x{8547}\x{8548}' . +'\x{8549}\x{854A}\x{854B}\x{854D}\x{854E}\x{854F}\x{8551}\x{8552}\x{8553}' . +'\x{8554}\x{8555}\x{8556}\x{8557}\x{8558}\x{8559}\x{855A}\x{855B}\x{855C}' . +'\x{855D}\x{855E}\x{855F}\x{8560}\x{8561}\x{8562}\x{8563}\x{8564}\x{8565}' . +'\x{8566}\x{8567}\x{8568}\x{8569}\x{856A}\x{856B}\x{856C}\x{856D}\x{856E}' . +'\x{856F}\x{8570}\x{8571}\x{8572}\x{8573}\x{8574}\x{8575}\x{8576}\x{8577}' . +'\x{8578}\x{8579}\x{857A}\x{857B}\x{857C}\x{857D}\x{857E}\x{8580}\x{8581}' . +'\x{8582}\x{8583}\x{8584}\x{8585}\x{8586}\x{8587}\x{8588}\x{8589}\x{858A}' . +'\x{858B}\x{858C}\x{858D}\x{858E}\x{858F}\x{8590}\x{8591}\x{8592}\x{8594}' . +'\x{8595}\x{8596}\x{8598}\x{8599}\x{859A}\x{859B}\x{859C}\x{859D}\x{859E}' . +'\x{859F}\x{85A0}\x{85A1}\x{85A2}\x{85A3}\x{85A4}\x{85A5}\x{85A6}\x{85A7}' . +'\x{85A8}\x{85A9}\x{85AA}\x{85AB}\x{85AC}\x{85AD}\x{85AE}\x{85AF}\x{85B0}' . +'\x{85B1}\x{85B3}\x{85B4}\x{85B5}\x{85B6}\x{85B7}\x{85B8}\x{85B9}\x{85BA}' . +'\x{85BC}\x{85BD}\x{85BE}\x{85BF}\x{85C0}\x{85C1}\x{85C2}\x{85C3}\x{85C4}' . +'\x{85C5}\x{85C6}\x{85C7}\x{85C8}\x{85C9}\x{85CA}\x{85CB}\x{85CD}\x{85CE}' . +'\x{85CF}\x{85D0}\x{85D1}\x{85D2}\x{85D3}\x{85D4}\x{85D5}\x{85D6}\x{85D7}' . +'\x{85D8}\x{85D9}\x{85DA}\x{85DB}\x{85DC}\x{85DD}\x{85DE}\x{85DF}\x{85E0}' . +'\x{85E1}\x{85E2}\x{85E3}\x{85E4}\x{85E5}\x{85E6}\x{85E7}\x{85E8}\x{85E9}' . +'\x{85EA}\x{85EB}\x{85EC}\x{85ED}\x{85EF}\x{85F0}\x{85F1}\x{85F2}\x{85F4}' . +'\x{85F5}\x{85F6}\x{85F7}\x{85F8}\x{85F9}\x{85FA}\x{85FB}\x{85FD}\x{85FE}' . +'\x{85FF}\x{8600}\x{8601}\x{8602}\x{8604}\x{8605}\x{8606}\x{8607}\x{8608}' . +'\x{8609}\x{860A}\x{860B}\x{860C}\x{860F}\x{8611}\x{8612}\x{8613}\x{8614}' . +'\x{8616}\x{8617}\x{8618}\x{8619}\x{861A}\x{861B}\x{861C}\x{861E}\x{861F}' . +'\x{8620}\x{8621}\x{8622}\x{8623}\x{8624}\x{8625}\x{8626}\x{8627}\x{8628}' . +'\x{8629}\x{862A}\x{862B}\x{862C}\x{862D}\x{862E}\x{862F}\x{8630}\x{8631}' . +'\x{8632}\x{8633}\x{8634}\x{8635}\x{8636}\x{8638}\x{8639}\x{863A}\x{863B}' . +'\x{863C}\x{863D}\x{863E}\x{863F}\x{8640}\x{8641}\x{8642}\x{8643}\x{8644}' . +'\x{8645}\x{8646}\x{8647}\x{8648}\x{8649}\x{864A}\x{864B}\x{864C}\x{864D}' . +'\x{864E}\x{864F}\x{8650}\x{8651}\x{8652}\x{8653}\x{8654}\x{8655}\x{8656}' . +'\x{8658}\x{8659}\x{865A}\x{865B}\x{865C}\x{865D}\x{865E}\x{865F}\x{8660}' . +'\x{8661}\x{8662}\x{8663}\x{8664}\x{8665}\x{8666}\x{8667}\x{8668}\x{8669}' . +'\x{866A}\x{866B}\x{866C}\x{866D}\x{866E}\x{866F}\x{8670}\x{8671}\x{8672}' . +'\x{8673}\x{8674}\x{8676}\x{8677}\x{8678}\x{8679}\x{867A}\x{867B}\x{867C}' . +'\x{867D}\x{867E}\x{867F}\x{8680}\x{8681}\x{8682}\x{8683}\x{8684}\x{8685}' . +'\x{8686}\x{8687}\x{8688}\x{868A}\x{868B}\x{868C}\x{868D}\x{868E}\x{868F}' . +'\x{8690}\x{8691}\x{8693}\x{8694}\x{8695}\x{8696}\x{8697}\x{8698}\x{8699}' . +'\x{869A}\x{869B}\x{869C}\x{869D}\x{869E}\x{869F}\x{86A1}\x{86A2}\x{86A3}' . +'\x{86A4}\x{86A5}\x{86A7}\x{86A8}\x{86A9}\x{86AA}\x{86AB}\x{86AC}\x{86AD}' . +'\x{86AE}\x{86AF}\x{86B0}\x{86B1}\x{86B2}\x{86B3}\x{86B4}\x{86B5}\x{86B6}' . +'\x{86B7}\x{86B8}\x{86B9}\x{86BA}\x{86BB}\x{86BC}\x{86BD}\x{86BE}\x{86BF}' . +'\x{86C0}\x{86C1}\x{86C2}\x{86C3}\x{86C4}\x{86C5}\x{86C6}\x{86C7}\x{86C8}' . +'\x{86C9}\x{86CA}\x{86CB}\x{86CC}\x{86CE}\x{86CF}\x{86D0}\x{86D1}\x{86D2}' . +'\x{86D3}\x{86D4}\x{86D6}\x{86D7}\x{86D8}\x{86D9}\x{86DA}\x{86DB}\x{86DC}' . +'\x{86DD}\x{86DE}\x{86DF}\x{86E1}\x{86E2}\x{86E3}\x{86E4}\x{86E5}\x{86E6}' . +'\x{86E8}\x{86E9}\x{86EA}\x{86EB}\x{86EC}\x{86ED}\x{86EE}\x{86EF}\x{86F0}' . +'\x{86F1}\x{86F2}\x{86F3}\x{86F4}\x{86F5}\x{86F6}\x{86F7}\x{86F8}\x{86F9}' . +'\x{86FA}\x{86FB}\x{86FC}\x{86FE}\x{86FF}\x{8700}\x{8701}\x{8702}\x{8703}' . +'\x{8704}\x{8705}\x{8706}\x{8707}\x{8708}\x{8709}\x{870A}\x{870B}\x{870C}' . +'\x{870D}\x{870E}\x{870F}\x{8710}\x{8711}\x{8712}\x{8713}\x{8714}\x{8715}' . +'\x{8716}\x{8717}\x{8718}\x{8719}\x{871A}\x{871B}\x{871C}\x{871E}\x{871F}' . +'\x{8720}\x{8721}\x{8722}\x{8723}\x{8724}\x{8725}\x{8726}\x{8727}\x{8728}' . +'\x{8729}\x{872A}\x{872B}\x{872C}\x{872D}\x{872E}\x{8730}\x{8731}\x{8732}' . +'\x{8733}\x{8734}\x{8735}\x{8736}\x{8737}\x{8738}\x{8739}\x{873A}\x{873B}' . +'\x{873C}\x{873E}\x{873F}\x{8740}\x{8741}\x{8742}\x{8743}\x{8744}\x{8746}' . +'\x{8747}\x{8748}\x{8749}\x{874A}\x{874C}\x{874D}\x{874E}\x{874F}\x{8750}' . +'\x{8751}\x{8752}\x{8753}\x{8754}\x{8755}\x{8756}\x{8757}\x{8758}\x{8759}' . +'\x{875A}\x{875B}\x{875C}\x{875D}\x{875E}\x{875F}\x{8760}\x{8761}\x{8762}' . +'\x{8763}\x{8764}\x{8765}\x{8766}\x{8767}\x{8768}\x{8769}\x{876A}\x{876B}' . +'\x{876C}\x{876D}\x{876E}\x{876F}\x{8770}\x{8772}\x{8773}\x{8774}\x{8775}' . +'\x{8776}\x{8777}\x{8778}\x{8779}\x{877A}\x{877B}\x{877C}\x{877D}\x{877E}' . +'\x{8780}\x{8781}\x{8782}\x{8783}\x{8784}\x{8785}\x{8786}\x{8787}\x{8788}' . +'\x{8789}\x{878A}\x{878B}\x{878C}\x{878D}\x{878F}\x{8790}\x{8791}\x{8792}' . +'\x{8793}\x{8794}\x{8795}\x{8796}\x{8797}\x{8798}\x{879A}\x{879B}\x{879C}' . +'\x{879D}\x{879E}\x{879F}\x{87A0}\x{87A1}\x{87A2}\x{87A3}\x{87A4}\x{87A5}' . +'\x{87A6}\x{87A7}\x{87A8}\x{87A9}\x{87AA}\x{87AB}\x{87AC}\x{87AD}\x{87AE}' . +'\x{87AF}\x{87B0}\x{87B1}\x{87B2}\x{87B3}\x{87B4}\x{87B5}\x{87B6}\x{87B7}' . +'\x{87B8}\x{87B9}\x{87BA}\x{87BB}\x{87BC}\x{87BD}\x{87BE}\x{87BF}\x{87C0}' . +'\x{87C1}\x{87C2}\x{87C3}\x{87C4}\x{87C5}\x{87C6}\x{87C7}\x{87C8}\x{87C9}' . +'\x{87CA}\x{87CB}\x{87CC}\x{87CD}\x{87CE}\x{87CF}\x{87D0}\x{87D1}\x{87D2}' . +'\x{87D3}\x{87D4}\x{87D5}\x{87D6}\x{87D7}\x{87D8}\x{87D9}\x{87DB}\x{87DC}' . +'\x{87DD}\x{87DE}\x{87DF}\x{87E0}\x{87E1}\x{87E2}\x{87E3}\x{87E4}\x{87E5}' . +'\x{87E6}\x{87E7}\x{87E8}\x{87E9}\x{87EA}\x{87EB}\x{87EC}\x{87ED}\x{87EE}' . +'\x{87EF}\x{87F1}\x{87F2}\x{87F3}\x{87F4}\x{87F5}\x{87F6}\x{87F7}\x{87F8}' . +'\x{87F9}\x{87FA}\x{87FB}\x{87FC}\x{87FD}\x{87FE}\x{87FF}\x{8800}\x{8801}' . +'\x{8802}\x{8803}\x{8804}\x{8805}\x{8806}\x{8808}\x{8809}\x{880A}\x{880B}' . +'\x{880C}\x{880D}\x{880E}\x{880F}\x{8810}\x{8811}\x{8813}\x{8814}\x{8815}' . +'\x{8816}\x{8817}\x{8818}\x{8819}\x{881A}\x{881B}\x{881C}\x{881D}\x{881E}' . +'\x{881F}\x{8820}\x{8821}\x{8822}\x{8823}\x{8824}\x{8825}\x{8826}\x{8827}' . +'\x{8828}\x{8829}\x{882A}\x{882B}\x{882C}\x{882E}\x{882F}\x{8830}\x{8831}' . +'\x{8832}\x{8833}\x{8834}\x{8835}\x{8836}\x{8837}\x{8838}\x{8839}\x{883B}' . +'\x{883C}\x{883D}\x{883E}\x{883F}\x{8840}\x{8841}\x{8842}\x{8843}\x{8844}' . +'\x{8845}\x{8846}\x{8848}\x{8849}\x{884A}\x{884B}\x{884C}\x{884D}\x{884E}' . +'\x{884F}\x{8850}\x{8851}\x{8852}\x{8853}\x{8854}\x{8855}\x{8856}\x{8857}' . +'\x{8859}\x{885A}\x{885B}\x{885D}\x{885E}\x{8860}\x{8861}\x{8862}\x{8863}' . +'\x{8864}\x{8865}\x{8866}\x{8867}\x{8868}\x{8869}\x{886A}\x{886B}\x{886C}' . +'\x{886D}\x{886E}\x{886F}\x{8870}\x{8871}\x{8872}\x{8873}\x{8874}\x{8875}' . +'\x{8876}\x{8877}\x{8878}\x{8879}\x{887B}\x{887C}\x{887D}\x{887E}\x{887F}' . +'\x{8880}\x{8881}\x{8882}\x{8883}\x{8884}\x{8885}\x{8886}\x{8887}\x{8888}' . +'\x{8889}\x{888A}\x{888B}\x{888C}\x{888D}\x{888E}\x{888F}\x{8890}\x{8891}' . +'\x{8892}\x{8893}\x{8894}\x{8895}\x{8896}\x{8897}\x{8898}\x{8899}\x{889A}' . +'\x{889B}\x{889C}\x{889D}\x{889E}\x{889F}\x{88A0}\x{88A1}\x{88A2}\x{88A3}' . +'\x{88A4}\x{88A5}\x{88A6}\x{88A7}\x{88A8}\x{88A9}\x{88AA}\x{88AB}\x{88AC}' . +'\x{88AD}\x{88AE}\x{88AF}\x{88B0}\x{88B1}\x{88B2}\x{88B3}\x{88B4}\x{88B6}' . +'\x{88B7}\x{88B8}\x{88B9}\x{88BA}\x{88BB}\x{88BC}\x{88BD}\x{88BE}\x{88BF}' . +'\x{88C0}\x{88C1}\x{88C2}\x{88C3}\x{88C4}\x{88C5}\x{88C6}\x{88C7}\x{88C8}' . +'\x{88C9}\x{88CA}\x{88CB}\x{88CC}\x{88CD}\x{88CE}\x{88CF}\x{88D0}\x{88D1}' . +'\x{88D2}\x{88D3}\x{88D4}\x{88D5}\x{88D6}\x{88D7}\x{88D8}\x{88D9}\x{88DA}' . +'\x{88DB}\x{88DC}\x{88DD}\x{88DE}\x{88DF}\x{88E0}\x{88E1}\x{88E2}\x{88E3}' . +'\x{88E4}\x{88E5}\x{88E7}\x{88E8}\x{88EA}\x{88EB}\x{88EC}\x{88EE}\x{88EF}' . +'\x{88F0}\x{88F1}\x{88F2}\x{88F3}\x{88F4}\x{88F5}\x{88F6}\x{88F7}\x{88F8}' . +'\x{88F9}\x{88FA}\x{88FB}\x{88FC}\x{88FD}\x{88FE}\x{88FF}\x{8900}\x{8901}' . +'\x{8902}\x{8904}\x{8905}\x{8906}\x{8907}\x{8908}\x{8909}\x{890A}\x{890B}' . +'\x{890C}\x{890D}\x{890E}\x{8910}\x{8911}\x{8912}\x{8913}\x{8914}\x{8915}' . +'\x{8916}\x{8917}\x{8918}\x{8919}\x{891A}\x{891B}\x{891C}\x{891D}\x{891E}' . +'\x{891F}\x{8920}\x{8921}\x{8922}\x{8923}\x{8925}\x{8926}\x{8927}\x{8928}' . +'\x{8929}\x{892A}\x{892B}\x{892C}\x{892D}\x{892E}\x{892F}\x{8930}\x{8931}' . +'\x{8932}\x{8933}\x{8934}\x{8935}\x{8936}\x{8937}\x{8938}\x{8939}\x{893A}' . +'\x{893B}\x{893C}\x{893D}\x{893E}\x{893F}\x{8940}\x{8941}\x{8942}\x{8943}' . +'\x{8944}\x{8945}\x{8946}\x{8947}\x{8948}\x{8949}\x{894A}\x{894B}\x{894C}' . +'\x{894E}\x{894F}\x{8950}\x{8951}\x{8952}\x{8953}\x{8954}\x{8955}\x{8956}' . +'\x{8957}\x{8958}\x{8959}\x{895A}\x{895B}\x{895C}\x{895D}\x{895E}\x{895F}' . +'\x{8960}\x{8961}\x{8962}\x{8963}\x{8964}\x{8966}\x{8967}\x{8968}\x{8969}' . +'\x{896A}\x{896B}\x{896C}\x{896D}\x{896E}\x{896F}\x{8970}\x{8971}\x{8972}' . +'\x{8973}\x{8974}\x{8976}\x{8977}\x{8978}\x{8979}\x{897A}\x{897B}\x{897C}' . +'\x{897E}\x{897F}\x{8980}\x{8981}\x{8982}\x{8983}\x{8984}\x{8985}\x{8986}' . +'\x{8987}\x{8988}\x{8989}\x{898A}\x{898B}\x{898C}\x{898E}\x{898F}\x{8991}' . +'\x{8992}\x{8993}\x{8995}\x{8996}\x{8997}\x{8998}\x{899A}\x{899B}\x{899C}' . +'\x{899D}\x{899E}\x{899F}\x{89A0}\x{89A1}\x{89A2}\x{89A3}\x{89A4}\x{89A5}' . +'\x{89A6}\x{89A7}\x{89A8}\x{89AA}\x{89AB}\x{89AC}\x{89AD}\x{89AE}\x{89AF}' . +'\x{89B1}\x{89B2}\x{89B3}\x{89B5}\x{89B6}\x{89B7}\x{89B8}\x{89B9}\x{89BA}' . +'\x{89BD}\x{89BE}\x{89BF}\x{89C0}\x{89C1}\x{89C2}\x{89C3}\x{89C4}\x{89C5}' . +'\x{89C6}\x{89C7}\x{89C8}\x{89C9}\x{89CA}\x{89CB}\x{89CC}\x{89CD}\x{89CE}' . +'\x{89CF}\x{89D0}\x{89D1}\x{89D2}\x{89D3}\x{89D4}\x{89D5}\x{89D6}\x{89D7}' . +'\x{89D8}\x{89D9}\x{89DA}\x{89DB}\x{89DC}\x{89DD}\x{89DE}\x{89DF}\x{89E0}' . +'\x{89E1}\x{89E2}\x{89E3}\x{89E4}\x{89E5}\x{89E6}\x{89E7}\x{89E8}\x{89E9}' . +'\x{89EA}\x{89EB}\x{89EC}\x{89ED}\x{89EF}\x{89F0}\x{89F1}\x{89F2}\x{89F3}' . +'\x{89F4}\x{89F6}\x{89F7}\x{89F8}\x{89FA}\x{89FB}\x{89FC}\x{89FE}\x{89FF}' . +'\x{8A00}\x{8A01}\x{8A02}\x{8A03}\x{8A04}\x{8A07}\x{8A08}\x{8A09}\x{8A0A}' . +'\x{8A0B}\x{8A0C}\x{8A0D}\x{8A0E}\x{8A0F}\x{8A10}\x{8A11}\x{8A12}\x{8A13}' . +'\x{8A15}\x{8A16}\x{8A17}\x{8A18}\x{8A1A}\x{8A1B}\x{8A1C}\x{8A1D}\x{8A1E}' . +'\x{8A1F}\x{8A22}\x{8A23}\x{8A24}\x{8A25}\x{8A26}\x{8A27}\x{8A28}\x{8A29}' . +'\x{8A2A}\x{8A2C}\x{8A2D}\x{8A2E}\x{8A2F}\x{8A30}\x{8A31}\x{8A32}\x{8A34}' . +'\x{8A35}\x{8A36}\x{8A37}\x{8A38}\x{8A39}\x{8A3A}\x{8A3B}\x{8A3C}\x{8A3E}' . +'\x{8A3F}\x{8A40}\x{8A41}\x{8A42}\x{8A43}\x{8A44}\x{8A45}\x{8A46}\x{8A47}' . +'\x{8A48}\x{8A49}\x{8A4A}\x{8A4C}\x{8A4D}\x{8A4E}\x{8A4F}\x{8A50}\x{8A51}' . +'\x{8A52}\x{8A53}\x{8A54}\x{8A55}\x{8A56}\x{8A57}\x{8A58}\x{8A59}\x{8A5A}' . +'\x{8A5B}\x{8A5C}\x{8A5D}\x{8A5E}\x{8A5F}\x{8A60}\x{8A61}\x{8A62}\x{8A63}' . +'\x{8A65}\x{8A66}\x{8A67}\x{8A68}\x{8A69}\x{8A6A}\x{8A6B}\x{8A6C}\x{8A6D}' . +'\x{8A6E}\x{8A6F}\x{8A70}\x{8A71}\x{8A72}\x{8A73}\x{8A74}\x{8A75}\x{8A76}' . +'\x{8A77}\x{8A79}\x{8A7A}\x{8A7B}\x{8A7C}\x{8A7E}\x{8A7F}\x{8A80}\x{8A81}' . +'\x{8A82}\x{8A83}\x{8A84}\x{8A85}\x{8A86}\x{8A87}\x{8A89}\x{8A8A}\x{8A8B}' . +'\x{8A8C}\x{8A8D}\x{8A8E}\x{8A8F}\x{8A90}\x{8A91}\x{8A92}\x{8A93}\x{8A94}' . +'\x{8A95}\x{8A96}\x{8A97}\x{8A98}\x{8A99}\x{8A9A}\x{8A9B}\x{8A9C}\x{8A9D}' . +'\x{8A9E}\x{8AA0}\x{8AA1}\x{8AA2}\x{8AA3}\x{8AA4}\x{8AA5}\x{8AA6}\x{8AA7}' . +'\x{8AA8}\x{8AA9}\x{8AAA}\x{8AAB}\x{8AAC}\x{8AAE}\x{8AB0}\x{8AB1}\x{8AB2}' . +'\x{8AB3}\x{8AB4}\x{8AB5}\x{8AB6}\x{8AB8}\x{8AB9}\x{8ABA}\x{8ABB}\x{8ABC}' . +'\x{8ABD}\x{8ABE}\x{8ABF}\x{8AC0}\x{8AC1}\x{8AC2}\x{8AC3}\x{8AC4}\x{8AC5}' . +'\x{8AC6}\x{8AC7}\x{8AC8}\x{8AC9}\x{8ACA}\x{8ACB}\x{8ACC}\x{8ACD}\x{8ACE}' . +'\x{8ACF}\x{8AD1}\x{8AD2}\x{8AD3}\x{8AD4}\x{8AD5}\x{8AD6}\x{8AD7}\x{8AD8}' . +'\x{8AD9}\x{8ADA}\x{8ADB}\x{8ADC}\x{8ADD}\x{8ADE}\x{8ADF}\x{8AE0}\x{8AE1}' . +'\x{8AE2}\x{8AE3}\x{8AE4}\x{8AE5}\x{8AE6}\x{8AE7}\x{8AE8}\x{8AE9}\x{8AEA}' . +'\x{8AEB}\x{8AED}\x{8AEE}\x{8AEF}\x{8AF0}\x{8AF1}\x{8AF2}\x{8AF3}\x{8AF4}' . +'\x{8AF5}\x{8AF6}\x{8AF7}\x{8AF8}\x{8AF9}\x{8AFA}\x{8AFB}\x{8AFC}\x{8AFD}' . +'\x{8AFE}\x{8AFF}\x{8B00}\x{8B01}\x{8B02}\x{8B03}\x{8B04}\x{8B05}\x{8B06}' . +'\x{8B07}\x{8B08}\x{8B09}\x{8B0A}\x{8B0B}\x{8B0D}\x{8B0E}\x{8B0F}\x{8B10}' . +'\x{8B11}\x{8B12}\x{8B13}\x{8B14}\x{8B15}\x{8B16}\x{8B17}\x{8B18}\x{8B19}' . +'\x{8B1A}\x{8B1B}\x{8B1C}\x{8B1D}\x{8B1E}\x{8B1F}\x{8B20}\x{8B21}\x{8B22}' . +'\x{8B23}\x{8B24}\x{8B25}\x{8B26}\x{8B27}\x{8B28}\x{8B2A}\x{8B2B}\x{8B2C}' . +'\x{8B2D}\x{8B2E}\x{8B2F}\x{8B30}\x{8B31}\x{8B33}\x{8B34}\x{8B35}\x{8B36}' . +'\x{8B37}\x{8B39}\x{8B3A}\x{8B3B}\x{8B3C}\x{8B3D}\x{8B3E}\x{8B40}\x{8B41}' . +'\x{8B42}\x{8B43}\x{8B44}\x{8B45}\x{8B46}\x{8B47}\x{8B48}\x{8B49}\x{8B4A}' . +'\x{8B4B}\x{8B4C}\x{8B4D}\x{8B4E}\x{8B4F}\x{8B50}\x{8B51}\x{8B52}\x{8B53}' . +'\x{8B54}\x{8B55}\x{8B56}\x{8B57}\x{8B58}\x{8B59}\x{8B5A}\x{8B5B}\x{8B5C}' . +'\x{8B5D}\x{8B5E}\x{8B5F}\x{8B60}\x{8B63}\x{8B64}\x{8B65}\x{8B66}\x{8B67}' . +'\x{8B68}\x{8B6A}\x{8B6B}\x{8B6C}\x{8B6D}\x{8B6E}\x{8B6F}\x{8B70}\x{8B71}' . +'\x{8B73}\x{8B74}\x{8B76}\x{8B77}\x{8B78}\x{8B79}\x{8B7A}\x{8B7B}\x{8B7D}' . +'\x{8B7E}\x{8B7F}\x{8B80}\x{8B82}\x{8B83}\x{8B84}\x{8B85}\x{8B86}\x{8B88}' . +'\x{8B89}\x{8B8A}\x{8B8B}\x{8B8C}\x{8B8E}\x{8B90}\x{8B91}\x{8B92}\x{8B93}' . +'\x{8B94}\x{8B95}\x{8B96}\x{8B97}\x{8B98}\x{8B99}\x{8B9A}\x{8B9C}\x{8B9D}' . +'\x{8B9E}\x{8B9F}\x{8BA0}\x{8BA1}\x{8BA2}\x{8BA3}\x{8BA4}\x{8BA5}\x{8BA6}' . +'\x{8BA7}\x{8BA8}\x{8BA9}\x{8BAA}\x{8BAB}\x{8BAC}\x{8BAD}\x{8BAE}\x{8BAF}' . +'\x{8BB0}\x{8BB1}\x{8BB2}\x{8BB3}\x{8BB4}\x{8BB5}\x{8BB6}\x{8BB7}\x{8BB8}' . +'\x{8BB9}\x{8BBA}\x{8BBB}\x{8BBC}\x{8BBD}\x{8BBE}\x{8BBF}\x{8BC0}\x{8BC1}' . +'\x{8BC2}\x{8BC3}\x{8BC4}\x{8BC5}\x{8BC6}\x{8BC7}\x{8BC8}\x{8BC9}\x{8BCA}' . +'\x{8BCB}\x{8BCC}\x{8BCD}\x{8BCE}\x{8BCF}\x{8BD0}\x{8BD1}\x{8BD2}\x{8BD3}' . +'\x{8BD4}\x{8BD5}\x{8BD6}\x{8BD7}\x{8BD8}\x{8BD9}\x{8BDA}\x{8BDB}\x{8BDC}' . +'\x{8BDD}\x{8BDE}\x{8BDF}\x{8BE0}\x{8BE1}\x{8BE2}\x{8BE3}\x{8BE4}\x{8BE5}' . +'\x{8BE6}\x{8BE7}\x{8BE8}\x{8BE9}\x{8BEA}\x{8BEB}\x{8BEC}\x{8BED}\x{8BEE}' . +'\x{8BEF}\x{8BF0}\x{8BF1}\x{8BF2}\x{8BF3}\x{8BF4}\x{8BF5}\x{8BF6}\x{8BF7}' . +'\x{8BF8}\x{8BF9}\x{8BFA}\x{8BFB}\x{8BFC}\x{8BFD}\x{8BFE}\x{8BFF}\x{8C00}' . +'\x{8C01}\x{8C02}\x{8C03}\x{8C04}\x{8C05}\x{8C06}\x{8C07}\x{8C08}\x{8C09}' . +'\x{8C0A}\x{8C0B}\x{8C0C}\x{8C0D}\x{8C0E}\x{8C0F}\x{8C10}\x{8C11}\x{8C12}' . +'\x{8C13}\x{8C14}\x{8C15}\x{8C16}\x{8C17}\x{8C18}\x{8C19}\x{8C1A}\x{8C1B}' . +'\x{8C1C}\x{8C1D}\x{8C1E}\x{8C1F}\x{8C20}\x{8C21}\x{8C22}\x{8C23}\x{8C24}' . +'\x{8C25}\x{8C26}\x{8C27}\x{8C28}\x{8C29}\x{8C2A}\x{8C2B}\x{8C2C}\x{8C2D}' . +'\x{8C2E}\x{8C2F}\x{8C30}\x{8C31}\x{8C32}\x{8C33}\x{8C34}\x{8C35}\x{8C36}' . +'\x{8C37}\x{8C39}\x{8C3A}\x{8C3B}\x{8C3C}\x{8C3D}\x{8C3E}\x{8C3F}\x{8C41}' . +'\x{8C42}\x{8C43}\x{8C45}\x{8C46}\x{8C47}\x{8C48}\x{8C49}\x{8C4A}\x{8C4B}' . +'\x{8C4C}\x{8C4D}\x{8C4E}\x{8C4F}\x{8C50}\x{8C54}\x{8C55}\x{8C56}\x{8C57}' . +'\x{8C59}\x{8C5A}\x{8C5B}\x{8C5C}\x{8C5D}\x{8C5E}\x{8C5F}\x{8C60}\x{8C61}' . +'\x{8C62}\x{8C63}\x{8C64}\x{8C65}\x{8C66}\x{8C67}\x{8C68}\x{8C69}\x{8C6A}' . +'\x{8C6B}\x{8C6C}\x{8C6D}\x{8C6E}\x{8C6F}\x{8C70}\x{8C71}\x{8C72}\x{8C73}' . +'\x{8C75}\x{8C76}\x{8C77}\x{8C78}\x{8C79}\x{8C7A}\x{8C7B}\x{8C7D}\x{8C7E}' . +'\x{8C80}\x{8C81}\x{8C82}\x{8C84}\x{8C85}\x{8C86}\x{8C88}\x{8C89}\x{8C8A}' . +'\x{8C8C}\x{8C8D}\x{8C8F}\x{8C90}\x{8C91}\x{8C92}\x{8C93}\x{8C94}\x{8C95}' . +'\x{8C96}\x{8C97}\x{8C98}\x{8C99}\x{8C9A}\x{8C9C}\x{8C9D}\x{8C9E}\x{8C9F}' . +'\x{8CA0}\x{8CA1}\x{8CA2}\x{8CA3}\x{8CA4}\x{8CA5}\x{8CA7}\x{8CA8}\x{8CA9}' . +'\x{8CAA}\x{8CAB}\x{8CAC}\x{8CAD}\x{8CAE}\x{8CAF}\x{8CB0}\x{8CB1}\x{8CB2}' . +'\x{8CB3}\x{8CB4}\x{8CB5}\x{8CB6}\x{8CB7}\x{8CB8}\x{8CB9}\x{8CBA}\x{8CBB}' . +'\x{8CBC}\x{8CBD}\x{8CBE}\x{8CBF}\x{8CC0}\x{8CC1}\x{8CC2}\x{8CC3}\x{8CC4}' . +'\x{8CC5}\x{8CC6}\x{8CC7}\x{8CC8}\x{8CC9}\x{8CCA}\x{8CCC}\x{8CCE}\x{8CCF}' . +'\x{8CD0}\x{8CD1}\x{8CD2}\x{8CD3}\x{8CD4}\x{8CD5}\x{8CD7}\x{8CD9}\x{8CDA}' . +'\x{8CDB}\x{8CDC}\x{8CDD}\x{8CDE}\x{8CDF}\x{8CE0}\x{8CE1}\x{8CE2}\x{8CE3}' . +'\x{8CE4}\x{8CE5}\x{8CE6}\x{8CE7}\x{8CE8}\x{8CEA}\x{8CEB}\x{8CEC}\x{8CED}' . +'\x{8CEE}\x{8CEF}\x{8CF0}\x{8CF1}\x{8CF2}\x{8CF3}\x{8CF4}\x{8CF5}\x{8CF6}' . +'\x{8CF8}\x{8CF9}\x{8CFA}\x{8CFB}\x{8CFC}\x{8CFD}\x{8CFE}\x{8CFF}\x{8D00}' . +'\x{8D02}\x{8D03}\x{8D04}\x{8D05}\x{8D06}\x{8D07}\x{8D08}\x{8D09}\x{8D0A}' . +'\x{8D0B}\x{8D0C}\x{8D0D}\x{8D0E}\x{8D0F}\x{8D10}\x{8D13}\x{8D14}\x{8D15}' . +'\x{8D16}\x{8D17}\x{8D18}\x{8D19}\x{8D1A}\x{8D1B}\x{8D1C}\x{8D1D}\x{8D1E}' . +'\x{8D1F}\x{8D20}\x{8D21}\x{8D22}\x{8D23}\x{8D24}\x{8D25}\x{8D26}\x{8D27}' . +'\x{8D28}\x{8D29}\x{8D2A}\x{8D2B}\x{8D2C}\x{8D2D}\x{8D2E}\x{8D2F}\x{8D30}' . +'\x{8D31}\x{8D32}\x{8D33}\x{8D34}\x{8D35}\x{8D36}\x{8D37}\x{8D38}\x{8D39}' . +'\x{8D3A}\x{8D3B}\x{8D3C}\x{8D3D}\x{8D3E}\x{8D3F}\x{8D40}\x{8D41}\x{8D42}' . +'\x{8D43}\x{8D44}\x{8D45}\x{8D46}\x{8D47}\x{8D48}\x{8D49}\x{8D4A}\x{8D4B}' . +'\x{8D4C}\x{8D4D}\x{8D4E}\x{8D4F}\x{8D50}\x{8D51}\x{8D52}\x{8D53}\x{8D54}' . +'\x{8D55}\x{8D56}\x{8D57}\x{8D58}\x{8D59}\x{8D5A}\x{8D5B}\x{8D5C}\x{8D5D}' . +'\x{8D5E}\x{8D5F}\x{8D60}\x{8D61}\x{8D62}\x{8D63}\x{8D64}\x{8D65}\x{8D66}' . +'\x{8D67}\x{8D68}\x{8D69}\x{8D6A}\x{8D6B}\x{8D6C}\x{8D6D}\x{8D6E}\x{8D6F}' . +'\x{8D70}\x{8D71}\x{8D72}\x{8D73}\x{8D74}\x{8D75}\x{8D76}\x{8D77}\x{8D78}' . +'\x{8D79}\x{8D7A}\x{8D7B}\x{8D7D}\x{8D7E}\x{8D7F}\x{8D80}\x{8D81}\x{8D82}' . +'\x{8D83}\x{8D84}\x{8D85}\x{8D86}\x{8D87}\x{8D88}\x{8D89}\x{8D8A}\x{8D8B}' . +'\x{8D8C}\x{8D8D}\x{8D8E}\x{8D8F}\x{8D90}\x{8D91}\x{8D92}\x{8D93}\x{8D94}' . +'\x{8D95}\x{8D96}\x{8D97}\x{8D98}\x{8D99}\x{8D9A}\x{8D9B}\x{8D9C}\x{8D9D}' . +'\x{8D9E}\x{8D9F}\x{8DA0}\x{8DA1}\x{8DA2}\x{8DA3}\x{8DA4}\x{8DA5}\x{8DA7}' . +'\x{8DA8}\x{8DA9}\x{8DAA}\x{8DAB}\x{8DAC}\x{8DAD}\x{8DAE}\x{8DAF}\x{8DB0}' . +'\x{8DB1}\x{8DB2}\x{8DB3}\x{8DB4}\x{8DB5}\x{8DB6}\x{8DB7}\x{8DB8}\x{8DB9}' . +'\x{8DBA}\x{8DBB}\x{8DBC}\x{8DBD}\x{8DBE}\x{8DBF}\x{8DC1}\x{8DC2}\x{8DC3}' . +'\x{8DC4}\x{8DC5}\x{8DC6}\x{8DC7}\x{8DC8}\x{8DC9}\x{8DCA}\x{8DCB}\x{8DCC}' . +'\x{8DCD}\x{8DCE}\x{8DCF}\x{8DD0}\x{8DD1}\x{8DD2}\x{8DD3}\x{8DD4}\x{8DD5}' . +'\x{8DD6}\x{8DD7}\x{8DD8}\x{8DD9}\x{8DDA}\x{8DDB}\x{8DDC}\x{8DDD}\x{8DDE}' . +'\x{8DDF}\x{8DE0}\x{8DE1}\x{8DE2}\x{8DE3}\x{8DE4}\x{8DE6}\x{8DE7}\x{8DE8}' . +'\x{8DE9}\x{8DEA}\x{8DEB}\x{8DEC}\x{8DED}\x{8DEE}\x{8DEF}\x{8DF0}\x{8DF1}' . +'\x{8DF2}\x{8DF3}\x{8DF4}\x{8DF5}\x{8DF6}\x{8DF7}\x{8DF8}\x{8DF9}\x{8DFA}' . +'\x{8DFB}\x{8DFC}\x{8DFD}\x{8DFE}\x{8DFF}\x{8E00}\x{8E02}\x{8E03}\x{8E04}' . +'\x{8E05}\x{8E06}\x{8E07}\x{8E08}\x{8E09}\x{8E0A}\x{8E0C}\x{8E0D}\x{8E0E}' . +'\x{8E0F}\x{8E10}\x{8E11}\x{8E12}\x{8E13}\x{8E14}\x{8E15}\x{8E16}\x{8E17}' . +'\x{8E18}\x{8E19}\x{8E1A}\x{8E1B}\x{8E1C}\x{8E1D}\x{8E1E}\x{8E1F}\x{8E20}' . +'\x{8E21}\x{8E22}\x{8E23}\x{8E24}\x{8E25}\x{8E26}\x{8E27}\x{8E28}\x{8E29}' . +'\x{8E2A}\x{8E2B}\x{8E2C}\x{8E2D}\x{8E2E}\x{8E2F}\x{8E30}\x{8E31}\x{8E33}' . +'\x{8E34}\x{8E35}\x{8E36}\x{8E37}\x{8E38}\x{8E39}\x{8E3A}\x{8E3B}\x{8E3C}' . +'\x{8E3D}\x{8E3E}\x{8E3F}\x{8E40}\x{8E41}\x{8E42}\x{8E43}\x{8E44}\x{8E45}' . +'\x{8E47}\x{8E48}\x{8E49}\x{8E4A}\x{8E4B}\x{8E4C}\x{8E4D}\x{8E4E}\x{8E50}' . +'\x{8E51}\x{8E52}\x{8E53}\x{8E54}\x{8E55}\x{8E56}\x{8E57}\x{8E58}\x{8E59}' . +'\x{8E5A}\x{8E5B}\x{8E5C}\x{8E5D}\x{8E5E}\x{8E5F}\x{8E60}\x{8E61}\x{8E62}' . +'\x{8E63}\x{8E64}\x{8E65}\x{8E66}\x{8E67}\x{8E68}\x{8E69}\x{8E6A}\x{8E6B}' . +'\x{8E6C}\x{8E6D}\x{8E6F}\x{8E70}\x{8E71}\x{8E72}\x{8E73}\x{8E74}\x{8E76}' . +'\x{8E78}\x{8E7A}\x{8E7B}\x{8E7C}\x{8E7D}\x{8E7E}\x{8E7F}\x{8E80}\x{8E81}' . +'\x{8E82}\x{8E83}\x{8E84}\x{8E85}\x{8E86}\x{8E87}\x{8E88}\x{8E89}\x{8E8A}' . +'\x{8E8B}\x{8E8C}\x{8E8D}\x{8E8E}\x{8E8F}\x{8E90}\x{8E91}\x{8E92}\x{8E93}' . +'\x{8E94}\x{8E95}\x{8E96}\x{8E97}\x{8E98}\x{8E9A}\x{8E9C}\x{8E9D}\x{8E9E}' . +'\x{8E9F}\x{8EA0}\x{8EA1}\x{8EA3}\x{8EA4}\x{8EA5}\x{8EA6}\x{8EA7}\x{8EA8}' . +'\x{8EA9}\x{8EAA}\x{8EAB}\x{8EAC}\x{8EAD}\x{8EAE}\x{8EAF}\x{8EB0}\x{8EB1}' . +'\x{8EB2}\x{8EB4}\x{8EB5}\x{8EB8}\x{8EB9}\x{8EBA}\x{8EBB}\x{8EBC}\x{8EBD}' . +'\x{8EBE}\x{8EBF}\x{8EC0}\x{8EC2}\x{8EC3}\x{8EC5}\x{8EC6}\x{8EC7}\x{8EC8}' . +'\x{8EC9}\x{8ECA}\x{8ECB}\x{8ECC}\x{8ECD}\x{8ECE}\x{8ECF}\x{8ED0}\x{8ED1}' . +'\x{8ED2}\x{8ED3}\x{8ED4}\x{8ED5}\x{8ED6}\x{8ED7}\x{8ED8}\x{8EDA}\x{8EDB}' . +'\x{8EDC}\x{8EDD}\x{8EDE}\x{8EDF}\x{8EE0}\x{8EE1}\x{8EE4}\x{8EE5}\x{8EE6}' . +'\x{8EE7}\x{8EE8}\x{8EE9}\x{8EEA}\x{8EEB}\x{8EEC}\x{8EED}\x{8EEE}\x{8EEF}' . +'\x{8EF1}\x{8EF2}\x{8EF3}\x{8EF4}\x{8EF5}\x{8EF6}\x{8EF7}\x{8EF8}\x{8EF9}' . +'\x{8EFA}\x{8EFB}\x{8EFC}\x{8EFD}\x{8EFE}\x{8EFF}\x{8F00}\x{8F01}\x{8F02}' . +'\x{8F03}\x{8F04}\x{8F05}\x{8F06}\x{8F07}\x{8F08}\x{8F09}\x{8F0A}\x{8F0B}' . +'\x{8F0D}\x{8F0E}\x{8F10}\x{8F11}\x{8F12}\x{8F13}\x{8F14}\x{8F15}\x{8F16}' . +'\x{8F17}\x{8F18}\x{8F1A}\x{8F1B}\x{8F1C}\x{8F1D}\x{8F1E}\x{8F1F}\x{8F20}' . +'\x{8F21}\x{8F22}\x{8F23}\x{8F24}\x{8F25}\x{8F26}\x{8F27}\x{8F28}\x{8F29}' . +'\x{8F2A}\x{8F2B}\x{8F2C}\x{8F2E}\x{8F2F}\x{8F30}\x{8F31}\x{8F32}\x{8F33}' . +'\x{8F34}\x{8F35}\x{8F36}\x{8F37}\x{8F38}\x{8F39}\x{8F3B}\x{8F3C}\x{8F3D}' . +'\x{8F3E}\x{8F3F}\x{8F40}\x{8F42}\x{8F43}\x{8F44}\x{8F45}\x{8F46}\x{8F47}' . +'\x{8F48}\x{8F49}\x{8F4A}\x{8F4B}\x{8F4C}\x{8F4D}\x{8F4E}\x{8F4F}\x{8F50}' . +'\x{8F51}\x{8F52}\x{8F53}\x{8F54}\x{8F55}\x{8F56}\x{8F57}\x{8F58}\x{8F59}' . +'\x{8F5A}\x{8F5B}\x{8F5D}\x{8F5E}\x{8F5F}\x{8F60}\x{8F61}\x{8F62}\x{8F63}' . +'\x{8F64}\x{8F65}\x{8F66}\x{8F67}\x{8F68}\x{8F69}\x{8F6A}\x{8F6B}\x{8F6C}' . +'\x{8F6D}\x{8F6E}\x{8F6F}\x{8F70}\x{8F71}\x{8F72}\x{8F73}\x{8F74}\x{8F75}' . +'\x{8F76}\x{8F77}\x{8F78}\x{8F79}\x{8F7A}\x{8F7B}\x{8F7C}\x{8F7D}\x{8F7E}' . +'\x{8F7F}\x{8F80}\x{8F81}\x{8F82}\x{8F83}\x{8F84}\x{8F85}\x{8F86}\x{8F87}' . +'\x{8F88}\x{8F89}\x{8F8A}\x{8F8B}\x{8F8C}\x{8F8D}\x{8F8E}\x{8F8F}\x{8F90}' . +'\x{8F91}\x{8F92}\x{8F93}\x{8F94}\x{8F95}\x{8F96}\x{8F97}\x{8F98}\x{8F99}' . +'\x{8F9A}\x{8F9B}\x{8F9C}\x{8F9E}\x{8F9F}\x{8FA0}\x{8FA1}\x{8FA2}\x{8FA3}' . +'\x{8FA5}\x{8FA6}\x{8FA7}\x{8FA8}\x{8FA9}\x{8FAA}\x{8FAB}\x{8FAC}\x{8FAD}' . +'\x{8FAE}\x{8FAF}\x{8FB0}\x{8FB1}\x{8FB2}\x{8FB4}\x{8FB5}\x{8FB6}\x{8FB7}' . +'\x{8FB8}\x{8FB9}\x{8FBB}\x{8FBC}\x{8FBD}\x{8FBE}\x{8FBF}\x{8FC0}\x{8FC1}' . +'\x{8FC2}\x{8FC4}\x{8FC5}\x{8FC6}\x{8FC7}\x{8FC8}\x{8FC9}\x{8FCB}\x{8FCC}' . +'\x{8FCD}\x{8FCE}\x{8FCF}\x{8FD0}\x{8FD1}\x{8FD2}\x{8FD3}\x{8FD4}\x{8FD5}' . +'\x{8FD6}\x{8FD7}\x{8FD8}\x{8FD9}\x{8FDA}\x{8FDB}\x{8FDC}\x{8FDD}\x{8FDE}' . +'\x{8FDF}\x{8FE0}\x{8FE1}\x{8FE2}\x{8FE3}\x{8FE4}\x{8FE5}\x{8FE6}\x{8FE8}' . +'\x{8FE9}\x{8FEA}\x{8FEB}\x{8FEC}\x{8FED}\x{8FEE}\x{8FEF}\x{8FF0}\x{8FF1}' . +'\x{8FF2}\x{8FF3}\x{8FF4}\x{8FF5}\x{8FF6}\x{8FF7}\x{8FF8}\x{8FF9}\x{8FFA}' . +'\x{8FFB}\x{8FFC}\x{8FFD}\x{8FFE}\x{8FFF}\x{9000}\x{9001}\x{9002}\x{9003}' . +'\x{9004}\x{9005}\x{9006}\x{9007}\x{9008}\x{9009}\x{900A}\x{900B}\x{900C}' . +'\x{900D}\x{900F}\x{9010}\x{9011}\x{9012}\x{9013}\x{9014}\x{9015}\x{9016}' . +'\x{9017}\x{9018}\x{9019}\x{901A}\x{901B}\x{901C}\x{901D}\x{901E}\x{901F}' . +'\x{9020}\x{9021}\x{9022}\x{9023}\x{9024}\x{9025}\x{9026}\x{9027}\x{9028}' . +'\x{9029}\x{902B}\x{902D}\x{902E}\x{902F}\x{9030}\x{9031}\x{9032}\x{9033}' . +'\x{9034}\x{9035}\x{9036}\x{9038}\x{903A}\x{903B}\x{903C}\x{903D}\x{903E}' . +'\x{903F}\x{9041}\x{9042}\x{9043}\x{9044}\x{9045}\x{9047}\x{9048}\x{9049}' . +'\x{904A}\x{904B}\x{904C}\x{904D}\x{904E}\x{904F}\x{9050}\x{9051}\x{9052}' . +'\x{9053}\x{9054}\x{9055}\x{9056}\x{9057}\x{9058}\x{9059}\x{905A}\x{905B}' . +'\x{905C}\x{905D}\x{905E}\x{905F}\x{9060}\x{9061}\x{9062}\x{9063}\x{9064}' . +'\x{9065}\x{9066}\x{9067}\x{9068}\x{9069}\x{906A}\x{906B}\x{906C}\x{906D}' . +'\x{906E}\x{906F}\x{9070}\x{9071}\x{9072}\x{9073}\x{9074}\x{9075}\x{9076}' . +'\x{9077}\x{9078}\x{9079}\x{907A}\x{907B}\x{907C}\x{907D}\x{907E}\x{907F}' . +'\x{9080}\x{9081}\x{9082}\x{9083}\x{9084}\x{9085}\x{9086}\x{9087}\x{9088}' . +'\x{9089}\x{908A}\x{908B}\x{908C}\x{908D}\x{908E}\x{908F}\x{9090}\x{9091}' . +'\x{9092}\x{9093}\x{9094}\x{9095}\x{9096}\x{9097}\x{9098}\x{9099}\x{909A}' . +'\x{909B}\x{909C}\x{909D}\x{909E}\x{909F}\x{90A0}\x{90A1}\x{90A2}\x{90A3}' . +'\x{90A4}\x{90A5}\x{90A6}\x{90A7}\x{90A8}\x{90A9}\x{90AA}\x{90AC}\x{90AD}' . +'\x{90AE}\x{90AF}\x{90B0}\x{90B1}\x{90B2}\x{90B3}\x{90B4}\x{90B5}\x{90B6}' . +'\x{90B7}\x{90B8}\x{90B9}\x{90BA}\x{90BB}\x{90BC}\x{90BD}\x{90BE}\x{90BF}' . +'\x{90C0}\x{90C1}\x{90C2}\x{90C3}\x{90C4}\x{90C5}\x{90C6}\x{90C7}\x{90C8}' . +'\x{90C9}\x{90CA}\x{90CB}\x{90CE}\x{90CF}\x{90D0}\x{90D1}\x{90D3}\x{90D4}' . +'\x{90D5}\x{90D6}\x{90D7}\x{90D8}\x{90D9}\x{90DA}\x{90DB}\x{90DC}\x{90DD}' . +'\x{90DE}\x{90DF}\x{90E0}\x{90E1}\x{90E2}\x{90E3}\x{90E4}\x{90E5}\x{90E6}' . +'\x{90E7}\x{90E8}\x{90E9}\x{90EA}\x{90EB}\x{90EC}\x{90ED}\x{90EE}\x{90EF}' . +'\x{90F0}\x{90F1}\x{90F2}\x{90F3}\x{90F4}\x{90F5}\x{90F7}\x{90F8}\x{90F9}' . +'\x{90FA}\x{90FB}\x{90FC}\x{90FD}\x{90FE}\x{90FF}\x{9100}\x{9101}\x{9102}' . +'\x{9103}\x{9104}\x{9105}\x{9106}\x{9107}\x{9108}\x{9109}\x{910B}\x{910C}' . +'\x{910D}\x{910E}\x{910F}\x{9110}\x{9111}\x{9112}\x{9113}\x{9114}\x{9115}' . +'\x{9116}\x{9117}\x{9118}\x{9119}\x{911A}\x{911B}\x{911C}\x{911D}\x{911E}' . +'\x{911F}\x{9120}\x{9121}\x{9122}\x{9123}\x{9124}\x{9125}\x{9126}\x{9127}' . +'\x{9128}\x{9129}\x{912A}\x{912B}\x{912C}\x{912D}\x{912E}\x{912F}\x{9130}' . +'\x{9131}\x{9132}\x{9133}\x{9134}\x{9135}\x{9136}\x{9137}\x{9138}\x{9139}' . +'\x{913A}\x{913B}\x{913E}\x{913F}\x{9140}\x{9141}\x{9142}\x{9143}\x{9144}' . +'\x{9145}\x{9146}\x{9147}\x{9148}\x{9149}\x{914A}\x{914B}\x{914C}\x{914D}' . +'\x{914E}\x{914F}\x{9150}\x{9151}\x{9152}\x{9153}\x{9154}\x{9155}\x{9156}' . +'\x{9157}\x{9158}\x{915A}\x{915B}\x{915C}\x{915D}\x{915E}\x{915F}\x{9160}' . +'\x{9161}\x{9162}\x{9163}\x{9164}\x{9165}\x{9166}\x{9167}\x{9168}\x{9169}' . +'\x{916A}\x{916B}\x{916C}\x{916D}\x{916E}\x{916F}\x{9170}\x{9171}\x{9172}' . +'\x{9173}\x{9174}\x{9175}\x{9176}\x{9177}\x{9178}\x{9179}\x{917A}\x{917C}' . +'\x{917D}\x{917E}\x{917F}\x{9180}\x{9181}\x{9182}\x{9183}\x{9184}\x{9185}' . +'\x{9186}\x{9187}\x{9188}\x{9189}\x{918A}\x{918B}\x{918C}\x{918D}\x{918E}' . +'\x{918F}\x{9190}\x{9191}\x{9192}\x{9193}\x{9194}\x{9196}\x{9199}\x{919A}' . +'\x{919B}\x{919C}\x{919D}\x{919E}\x{919F}\x{91A0}\x{91A1}\x{91A2}\x{91A3}' . +'\x{91A5}\x{91A6}\x{91A7}\x{91A8}\x{91AA}\x{91AB}\x{91AC}\x{91AD}\x{91AE}' . +'\x{91AF}\x{91B0}\x{91B1}\x{91B2}\x{91B3}\x{91B4}\x{91B5}\x{91B6}\x{91B7}' . +'\x{91B9}\x{91BA}\x{91BB}\x{91BC}\x{91BD}\x{91BE}\x{91C0}\x{91C1}\x{91C2}' . +'\x{91C3}\x{91C5}\x{91C6}\x{91C7}\x{91C9}\x{91CA}\x{91CB}\x{91CC}\x{91CD}' . +'\x{91CE}\x{91CF}\x{91D0}\x{91D1}\x{91D2}\x{91D3}\x{91D4}\x{91D5}\x{91D7}' . +'\x{91D8}\x{91D9}\x{91DA}\x{91DB}\x{91DC}\x{91DD}\x{91DE}\x{91DF}\x{91E2}' . +'\x{91E3}\x{91E4}\x{91E5}\x{91E6}\x{91E7}\x{91E8}\x{91E9}\x{91EA}\x{91EB}' . +'\x{91EC}\x{91ED}\x{91EE}\x{91F0}\x{91F1}\x{91F2}\x{91F3}\x{91F4}\x{91F5}' . +'\x{91F7}\x{91F8}\x{91F9}\x{91FA}\x{91FB}\x{91FD}\x{91FE}\x{91FF}\x{9200}' . +'\x{9201}\x{9202}\x{9203}\x{9204}\x{9205}\x{9206}\x{9207}\x{9208}\x{9209}' . +'\x{920A}\x{920B}\x{920C}\x{920D}\x{920E}\x{920F}\x{9210}\x{9211}\x{9212}' . +'\x{9214}\x{9215}\x{9216}\x{9217}\x{9218}\x{9219}\x{921A}\x{921B}\x{921C}' . +'\x{921D}\x{921E}\x{9220}\x{9221}\x{9223}\x{9224}\x{9225}\x{9226}\x{9227}' . +'\x{9228}\x{9229}\x{922A}\x{922B}\x{922D}\x{922E}\x{922F}\x{9230}\x{9231}' . +'\x{9232}\x{9233}\x{9234}\x{9235}\x{9236}\x{9237}\x{9238}\x{9239}\x{923A}' . +'\x{923B}\x{923C}\x{923D}\x{923E}\x{923F}\x{9240}\x{9241}\x{9242}\x{9245}' . +'\x{9246}\x{9247}\x{9248}\x{9249}\x{924A}\x{924B}\x{924C}\x{924D}\x{924E}' . +'\x{924F}\x{9250}\x{9251}\x{9252}\x{9253}\x{9254}\x{9255}\x{9256}\x{9257}' . +'\x{9258}\x{9259}\x{925A}\x{925B}\x{925C}\x{925D}\x{925E}\x{925F}\x{9260}' . +'\x{9261}\x{9262}\x{9263}\x{9264}\x{9265}\x{9266}\x{9267}\x{9268}\x{926B}' . +'\x{926C}\x{926D}\x{926E}\x{926F}\x{9270}\x{9272}\x{9273}\x{9274}\x{9275}' . +'\x{9276}\x{9277}\x{9278}\x{9279}\x{927A}\x{927B}\x{927C}\x{927D}\x{927E}' . +'\x{927F}\x{9280}\x{9282}\x{9283}\x{9285}\x{9286}\x{9287}\x{9288}\x{9289}' . +'\x{928A}\x{928B}\x{928C}\x{928D}\x{928E}\x{928F}\x{9290}\x{9291}\x{9292}' . +'\x{9293}\x{9294}\x{9295}\x{9296}\x{9297}\x{9298}\x{9299}\x{929A}\x{929B}' . +'\x{929C}\x{929D}\x{929F}\x{92A0}\x{92A1}\x{92A2}\x{92A3}\x{92A4}\x{92A5}' . +'\x{92A6}\x{92A7}\x{92A8}\x{92A9}\x{92AA}\x{92AB}\x{92AC}\x{92AD}\x{92AE}' . +'\x{92AF}\x{92B0}\x{92B1}\x{92B2}\x{92B3}\x{92B4}\x{92B5}\x{92B6}\x{92B7}' . +'\x{92B8}\x{92B9}\x{92BA}\x{92BB}\x{92BC}\x{92BE}\x{92BF}\x{92C0}\x{92C1}' . +'\x{92C2}\x{92C3}\x{92C4}\x{92C5}\x{92C6}\x{92C7}\x{92C8}\x{92C9}\x{92CA}' . +'\x{92CB}\x{92CC}\x{92CD}\x{92CE}\x{92CF}\x{92D0}\x{92D1}\x{92D2}\x{92D3}' . +'\x{92D5}\x{92D6}\x{92D7}\x{92D8}\x{92D9}\x{92DA}\x{92DC}\x{92DD}\x{92DE}' . +'\x{92DF}\x{92E0}\x{92E1}\x{92E3}\x{92E4}\x{92E5}\x{92E6}\x{92E7}\x{92E8}' . +'\x{92E9}\x{92EA}\x{92EB}\x{92EC}\x{92ED}\x{92EE}\x{92EF}\x{92F0}\x{92F1}' . +'\x{92F2}\x{92F3}\x{92F4}\x{92F5}\x{92F6}\x{92F7}\x{92F8}\x{92F9}\x{92FA}' . +'\x{92FB}\x{92FC}\x{92FD}\x{92FE}\x{92FF}\x{9300}\x{9301}\x{9302}\x{9303}' . +'\x{9304}\x{9305}\x{9306}\x{9307}\x{9308}\x{9309}\x{930A}\x{930B}\x{930C}' . +'\x{930D}\x{930E}\x{930F}\x{9310}\x{9311}\x{9312}\x{9313}\x{9314}\x{9315}' . +'\x{9316}\x{9317}\x{9318}\x{9319}\x{931A}\x{931B}\x{931D}\x{931E}\x{931F}' . +'\x{9320}\x{9321}\x{9322}\x{9323}\x{9324}\x{9325}\x{9326}\x{9327}\x{9328}' . +'\x{9329}\x{932A}\x{932B}\x{932D}\x{932E}\x{932F}\x{9332}\x{9333}\x{9334}' . +'\x{9335}\x{9336}\x{9337}\x{9338}\x{9339}\x{933A}\x{933B}\x{933C}\x{933D}' . +'\x{933E}\x{933F}\x{9340}\x{9341}\x{9342}\x{9343}\x{9344}\x{9345}\x{9346}' . +'\x{9347}\x{9348}\x{9349}\x{934A}\x{934B}\x{934C}\x{934D}\x{934E}\x{934F}' . +'\x{9350}\x{9351}\x{9352}\x{9353}\x{9354}\x{9355}\x{9356}\x{9357}\x{9358}' . +'\x{9359}\x{935A}\x{935B}\x{935C}\x{935D}\x{935E}\x{935F}\x{9360}\x{9361}' . +'\x{9363}\x{9364}\x{9365}\x{9366}\x{9367}\x{9369}\x{936A}\x{936C}\x{936D}' . +'\x{936E}\x{9370}\x{9371}\x{9372}\x{9374}\x{9375}\x{9376}\x{9377}\x{9379}' . +'\x{937A}\x{937B}\x{937C}\x{937D}\x{937E}\x{9380}\x{9382}\x{9383}\x{9384}' . +'\x{9385}\x{9386}\x{9387}\x{9388}\x{9389}\x{938A}\x{938C}\x{938D}\x{938E}' . +'\x{938F}\x{9390}\x{9391}\x{9392}\x{9393}\x{9394}\x{9395}\x{9396}\x{9397}' . +'\x{9398}\x{9399}\x{939A}\x{939B}\x{939D}\x{939E}\x{939F}\x{93A1}\x{93A2}' . +'\x{93A3}\x{93A4}\x{93A5}\x{93A6}\x{93A7}\x{93A8}\x{93A9}\x{93AA}\x{93AC}' . +'\x{93AD}\x{93AE}\x{93AF}\x{93B0}\x{93B1}\x{93B2}\x{93B3}\x{93B4}\x{93B5}' . +'\x{93B6}\x{93B7}\x{93B8}\x{93B9}\x{93BA}\x{93BC}\x{93BD}\x{93BE}\x{93BF}' . +'\x{93C0}\x{93C1}\x{93C2}\x{93C3}\x{93C4}\x{93C5}\x{93C6}\x{93C7}\x{93C8}' . +'\x{93C9}\x{93CA}\x{93CB}\x{93CC}\x{93CD}\x{93CE}\x{93CF}\x{93D0}\x{93D1}' . +'\x{93D2}\x{93D3}\x{93D4}\x{93D5}\x{93D6}\x{93D7}\x{93D8}\x{93D9}\x{93DA}' . +'\x{93DB}\x{93DC}\x{93DD}\x{93DE}\x{93DF}\x{93E1}\x{93E2}\x{93E3}\x{93E4}' . +'\x{93E6}\x{93E7}\x{93E8}\x{93E9}\x{93EA}\x{93EB}\x{93EC}\x{93ED}\x{93EE}' . +'\x{93EF}\x{93F0}\x{93F1}\x{93F2}\x{93F4}\x{93F5}\x{93F6}\x{93F7}\x{93F8}' . +'\x{93F9}\x{93FA}\x{93FB}\x{93FC}\x{93FD}\x{93FE}\x{93FF}\x{9400}\x{9401}' . +'\x{9403}\x{9404}\x{9405}\x{9406}\x{9407}\x{9408}\x{9409}\x{940A}\x{940B}' . +'\x{940C}\x{940D}\x{940E}\x{940F}\x{9410}\x{9411}\x{9412}\x{9413}\x{9414}' . +'\x{9415}\x{9416}\x{9418}\x{9419}\x{941B}\x{941D}\x{9420}\x{9422}\x{9423}' . +'\x{9425}\x{9426}\x{9427}\x{9428}\x{9429}\x{942A}\x{942B}\x{942C}\x{942D}' . +'\x{942E}\x{942F}\x{9430}\x{9431}\x{9432}\x{9433}\x{9434}\x{9435}\x{9436}' . +'\x{9437}\x{9438}\x{9439}\x{943A}\x{943B}\x{943C}\x{943D}\x{943E}\x{943F}' . +'\x{9440}\x{9441}\x{9442}\x{9444}\x{9445}\x{9446}\x{9447}\x{9448}\x{9449}' . +'\x{944A}\x{944B}\x{944C}\x{944D}\x{944F}\x{9450}\x{9451}\x{9452}\x{9453}' . +'\x{9454}\x{9455}\x{9456}\x{9457}\x{9458}\x{9459}\x{945B}\x{945C}\x{945D}' . +'\x{945E}\x{945F}\x{9460}\x{9461}\x{9462}\x{9463}\x{9464}\x{9465}\x{9466}' . +'\x{9467}\x{9468}\x{9469}\x{946A}\x{946B}\x{946D}\x{946E}\x{946F}\x{9470}' . +'\x{9471}\x{9472}\x{9473}\x{9474}\x{9475}\x{9476}\x{9477}\x{9478}\x{9479}' . +'\x{947A}\x{947C}\x{947D}\x{947E}\x{947F}\x{9480}\x{9481}\x{9482}\x{9483}' . +'\x{9484}\x{9485}\x{9486}\x{9487}\x{9488}\x{9489}\x{948A}\x{948B}\x{948C}' . +'\x{948D}\x{948E}\x{948F}\x{9490}\x{9491}\x{9492}\x{9493}\x{9494}\x{9495}' . +'\x{9496}\x{9497}\x{9498}\x{9499}\x{949A}\x{949B}\x{949C}\x{949D}\x{949E}' . +'\x{949F}\x{94A0}\x{94A1}\x{94A2}\x{94A3}\x{94A4}\x{94A5}\x{94A6}\x{94A7}' . +'\x{94A8}\x{94A9}\x{94AA}\x{94AB}\x{94AC}\x{94AD}\x{94AE}\x{94AF}\x{94B0}' . +'\x{94B1}\x{94B2}\x{94B3}\x{94B4}\x{94B5}\x{94B6}\x{94B7}\x{94B8}\x{94B9}' . +'\x{94BA}\x{94BB}\x{94BC}\x{94BD}\x{94BE}\x{94BF}\x{94C0}\x{94C1}\x{94C2}' . +'\x{94C3}\x{94C4}\x{94C5}\x{94C6}\x{94C7}\x{94C8}\x{94C9}\x{94CA}\x{94CB}' . +'\x{94CC}\x{94CD}\x{94CE}\x{94CF}\x{94D0}\x{94D1}\x{94D2}\x{94D3}\x{94D4}' . +'\x{94D5}\x{94D6}\x{94D7}\x{94D8}\x{94D9}\x{94DA}\x{94DB}\x{94DC}\x{94DD}' . +'\x{94DE}\x{94DF}\x{94E0}\x{94E1}\x{94E2}\x{94E3}\x{94E4}\x{94E5}\x{94E6}' . +'\x{94E7}\x{94E8}\x{94E9}\x{94EA}\x{94EB}\x{94EC}\x{94ED}\x{94EE}\x{94EF}' . +'\x{94F0}\x{94F1}\x{94F2}\x{94F3}\x{94F4}\x{94F5}\x{94F6}\x{94F7}\x{94F8}' . +'\x{94F9}\x{94FA}\x{94FB}\x{94FC}\x{94FD}\x{94FE}\x{94FF}\x{9500}\x{9501}' . +'\x{9502}\x{9503}\x{9504}\x{9505}\x{9506}\x{9507}\x{9508}\x{9509}\x{950A}' . +'\x{950B}\x{950C}\x{950D}\x{950E}\x{950F}\x{9510}\x{9511}\x{9512}\x{9513}' . +'\x{9514}\x{9515}\x{9516}\x{9517}\x{9518}\x{9519}\x{951A}\x{951B}\x{951C}' . +'\x{951D}\x{951E}\x{951F}\x{9520}\x{9521}\x{9522}\x{9523}\x{9524}\x{9525}' . +'\x{9526}\x{9527}\x{9528}\x{9529}\x{952A}\x{952B}\x{952C}\x{952D}\x{952E}' . +'\x{952F}\x{9530}\x{9531}\x{9532}\x{9533}\x{9534}\x{9535}\x{9536}\x{9537}' . +'\x{9538}\x{9539}\x{953A}\x{953B}\x{953C}\x{953D}\x{953E}\x{953F}\x{9540}' . +'\x{9541}\x{9542}\x{9543}\x{9544}\x{9545}\x{9546}\x{9547}\x{9548}\x{9549}' . +'\x{954A}\x{954B}\x{954C}\x{954D}\x{954E}\x{954F}\x{9550}\x{9551}\x{9552}' . +'\x{9553}\x{9554}\x{9555}\x{9556}\x{9557}\x{9558}\x{9559}\x{955A}\x{955B}' . +'\x{955C}\x{955D}\x{955E}\x{955F}\x{9560}\x{9561}\x{9562}\x{9563}\x{9564}' . +'\x{9565}\x{9566}\x{9567}\x{9568}\x{9569}\x{956A}\x{956B}\x{956C}\x{956D}' . +'\x{956E}\x{956F}\x{9570}\x{9571}\x{9572}\x{9573}\x{9574}\x{9575}\x{9576}' . +'\x{9577}\x{957A}\x{957B}\x{957C}\x{957D}\x{957F}\x{9580}\x{9581}\x{9582}' . +'\x{9583}\x{9584}\x{9586}\x{9587}\x{9588}\x{9589}\x{958A}\x{958B}\x{958C}' . +'\x{958D}\x{958E}\x{958F}\x{9590}\x{9591}\x{9592}\x{9593}\x{9594}\x{9595}' . +'\x{9596}\x{9598}\x{9599}\x{959A}\x{959B}\x{959C}\x{959D}\x{959E}\x{959F}' . +'\x{95A1}\x{95A2}\x{95A3}\x{95A4}\x{95A5}\x{95A6}\x{95A7}\x{95A8}\x{95A9}' . +'\x{95AA}\x{95AB}\x{95AC}\x{95AD}\x{95AE}\x{95AF}\x{95B0}\x{95B1}\x{95B2}' . +'\x{95B5}\x{95B6}\x{95B7}\x{95B9}\x{95BA}\x{95BB}\x{95BC}\x{95BD}\x{95BE}' . +'\x{95BF}\x{95C0}\x{95C2}\x{95C3}\x{95C4}\x{95C5}\x{95C6}\x{95C7}\x{95C8}' . +'\x{95C9}\x{95CA}\x{95CB}\x{95CC}\x{95CD}\x{95CE}\x{95CF}\x{95D0}\x{95D1}' . +'\x{95D2}\x{95D3}\x{95D4}\x{95D5}\x{95D6}\x{95D7}\x{95D8}\x{95DA}\x{95DB}' . +'\x{95DC}\x{95DE}\x{95DF}\x{95E0}\x{95E1}\x{95E2}\x{95E3}\x{95E4}\x{95E5}' . +'\x{95E6}\x{95E7}\x{95E8}\x{95E9}\x{95EA}\x{95EB}\x{95EC}\x{95ED}\x{95EE}' . +'\x{95EF}\x{95F0}\x{95F1}\x{95F2}\x{95F3}\x{95F4}\x{95F5}\x{95F6}\x{95F7}' . +'\x{95F8}\x{95F9}\x{95FA}\x{95FB}\x{95FC}\x{95FD}\x{95FE}\x{95FF}\x{9600}' . +'\x{9601}\x{9602}\x{9603}\x{9604}\x{9605}\x{9606}\x{9607}\x{9608}\x{9609}' . +'\x{960A}\x{960B}\x{960C}\x{960D}\x{960E}\x{960F}\x{9610}\x{9611}\x{9612}' . +'\x{9613}\x{9614}\x{9615}\x{9616}\x{9617}\x{9618}\x{9619}\x{961A}\x{961B}' . +'\x{961C}\x{961D}\x{961E}\x{961F}\x{9620}\x{9621}\x{9622}\x{9623}\x{9624}' . +'\x{9627}\x{9628}\x{962A}\x{962B}\x{962C}\x{962D}\x{962E}\x{962F}\x{9630}' . +'\x{9631}\x{9632}\x{9633}\x{9634}\x{9635}\x{9636}\x{9637}\x{9638}\x{9639}' . +'\x{963A}\x{963B}\x{963C}\x{963D}\x{963F}\x{9640}\x{9641}\x{9642}\x{9643}' . +'\x{9644}\x{9645}\x{9646}\x{9647}\x{9648}\x{9649}\x{964A}\x{964B}\x{964C}' . +'\x{964D}\x{964E}\x{964F}\x{9650}\x{9651}\x{9652}\x{9653}\x{9654}\x{9655}' . +'\x{9658}\x{9659}\x{965A}\x{965B}\x{965C}\x{965D}\x{965E}\x{965F}\x{9660}' . +'\x{9661}\x{9662}\x{9663}\x{9664}\x{9666}\x{9667}\x{9668}\x{9669}\x{966A}' . +'\x{966B}\x{966C}\x{966D}\x{966E}\x{966F}\x{9670}\x{9671}\x{9672}\x{9673}' . +'\x{9674}\x{9675}\x{9676}\x{9677}\x{9678}\x{967C}\x{967D}\x{967E}\x{9680}' . +'\x{9683}\x{9684}\x{9685}\x{9686}\x{9687}\x{9688}\x{9689}\x{968A}\x{968B}' . +'\x{968D}\x{968E}\x{968F}\x{9690}\x{9691}\x{9692}\x{9693}\x{9694}\x{9695}' . +'\x{9697}\x{9698}\x{9699}\x{969B}\x{969C}\x{969E}\x{96A0}\x{96A1}\x{96A2}' . +'\x{96A3}\x{96A4}\x{96A5}\x{96A6}\x{96A7}\x{96A8}\x{96A9}\x{96AA}\x{96AC}' . +'\x{96AD}\x{96AE}\x{96B0}\x{96B1}\x{96B3}\x{96B4}\x{96B6}\x{96B7}\x{96B8}' . +'\x{96B9}\x{96BA}\x{96BB}\x{96BC}\x{96BD}\x{96BE}\x{96BF}\x{96C0}\x{96C1}' . +'\x{96C2}\x{96C3}\x{96C4}\x{96C5}\x{96C6}\x{96C7}\x{96C8}\x{96C9}\x{96CA}' . +'\x{96CB}\x{96CC}\x{96CD}\x{96CE}\x{96CF}\x{96D0}\x{96D1}\x{96D2}\x{96D3}' . +'\x{96D4}\x{96D5}\x{96D6}\x{96D7}\x{96D8}\x{96D9}\x{96DA}\x{96DB}\x{96DC}' . +'\x{96DD}\x{96DE}\x{96DF}\x{96E0}\x{96E1}\x{96E2}\x{96E3}\x{96E5}\x{96E8}' . +'\x{96E9}\x{96EA}\x{96EB}\x{96EC}\x{96ED}\x{96EE}\x{96EF}\x{96F0}\x{96F1}' . +'\x{96F2}\x{96F3}\x{96F4}\x{96F5}\x{96F6}\x{96F7}\x{96F8}\x{96F9}\x{96FA}' . +'\x{96FB}\x{96FD}\x{96FE}\x{96FF}\x{9700}\x{9701}\x{9702}\x{9703}\x{9704}' . +'\x{9705}\x{9706}\x{9707}\x{9708}\x{9709}\x{970A}\x{970B}\x{970C}\x{970D}' . +'\x{970E}\x{970F}\x{9710}\x{9711}\x{9712}\x{9713}\x{9715}\x{9716}\x{9718}' . +'\x{9719}\x{971C}\x{971D}\x{971E}\x{971F}\x{9720}\x{9721}\x{9722}\x{9723}' . +'\x{9724}\x{9725}\x{9726}\x{9727}\x{9728}\x{9729}\x{972A}\x{972B}\x{972C}' . +'\x{972D}\x{972E}\x{972F}\x{9730}\x{9731}\x{9732}\x{9735}\x{9736}\x{9738}' . +'\x{9739}\x{973A}\x{973B}\x{973C}\x{973D}\x{973E}\x{973F}\x{9742}\x{9743}' . +'\x{9744}\x{9745}\x{9746}\x{9747}\x{9748}\x{9749}\x{974A}\x{974B}\x{974C}' . +'\x{974E}\x{974F}\x{9750}\x{9751}\x{9752}\x{9753}\x{9754}\x{9755}\x{9756}' . +'\x{9758}\x{9759}\x{975A}\x{975B}\x{975C}\x{975D}\x{975E}\x{975F}\x{9760}' . +'\x{9761}\x{9762}\x{9765}\x{9766}\x{9767}\x{9768}\x{9769}\x{976A}\x{976B}' . +'\x{976C}\x{976D}\x{976E}\x{976F}\x{9770}\x{9772}\x{9773}\x{9774}\x{9776}' . +'\x{9777}\x{9778}\x{9779}\x{977A}\x{977B}\x{977C}\x{977D}\x{977E}\x{977F}' . +'\x{9780}\x{9781}\x{9782}\x{9783}\x{9784}\x{9785}\x{9786}\x{9788}\x{978A}' . +'\x{978B}\x{978C}\x{978D}\x{978E}\x{978F}\x{9790}\x{9791}\x{9792}\x{9793}' . +'\x{9794}\x{9795}\x{9796}\x{9797}\x{9798}\x{9799}\x{979A}\x{979C}\x{979D}' . +'\x{979E}\x{979F}\x{97A0}\x{97A1}\x{97A2}\x{97A3}\x{97A4}\x{97A5}\x{97A6}' . +'\x{97A7}\x{97A8}\x{97AA}\x{97AB}\x{97AC}\x{97AD}\x{97AE}\x{97AF}\x{97B2}' . +'\x{97B3}\x{97B4}\x{97B6}\x{97B7}\x{97B8}\x{97B9}\x{97BA}\x{97BB}\x{97BC}' . +'\x{97BD}\x{97BF}\x{97C1}\x{97C2}\x{97C3}\x{97C4}\x{97C5}\x{97C6}\x{97C7}' . +'\x{97C8}\x{97C9}\x{97CA}\x{97CB}\x{97CC}\x{97CD}\x{97CE}\x{97CF}\x{97D0}' . +'\x{97D1}\x{97D3}\x{97D4}\x{97D5}\x{97D6}\x{97D7}\x{97D8}\x{97D9}\x{97DA}' . +'\x{97DB}\x{97DC}\x{97DD}\x{97DE}\x{97DF}\x{97E0}\x{97E1}\x{97E2}\x{97E3}' . +'\x{97E4}\x{97E5}\x{97E6}\x{97E7}\x{97E8}\x{97E9}\x{97EA}\x{97EB}\x{97EC}' . +'\x{97ED}\x{97EE}\x{97EF}\x{97F0}\x{97F1}\x{97F2}\x{97F3}\x{97F4}\x{97F5}' . +'\x{97F6}\x{97F7}\x{97F8}\x{97F9}\x{97FA}\x{97FB}\x{97FD}\x{97FE}\x{97FF}' . +'\x{9800}\x{9801}\x{9802}\x{9803}\x{9804}\x{9805}\x{9806}\x{9807}\x{9808}' . +'\x{9809}\x{980A}\x{980B}\x{980C}\x{980D}\x{980E}\x{980F}\x{9810}\x{9811}' . +'\x{9812}\x{9813}\x{9814}\x{9815}\x{9816}\x{9817}\x{9818}\x{9819}\x{981A}' . +'\x{981B}\x{981C}\x{981D}\x{981E}\x{9820}\x{9821}\x{9822}\x{9823}\x{9824}' . +'\x{9826}\x{9827}\x{9828}\x{9829}\x{982B}\x{982D}\x{982E}\x{982F}\x{9830}' . +'\x{9831}\x{9832}\x{9834}\x{9835}\x{9836}\x{9837}\x{9838}\x{9839}\x{983B}' . +'\x{983C}\x{983D}\x{983F}\x{9840}\x{9841}\x{9843}\x{9844}\x{9845}\x{9846}' . +'\x{9848}\x{9849}\x{984A}\x{984C}\x{984D}\x{984E}\x{984F}\x{9850}\x{9851}' . +'\x{9852}\x{9853}\x{9854}\x{9855}\x{9857}\x{9858}\x{9859}\x{985A}\x{985B}' . +'\x{985C}\x{985D}\x{985E}\x{985F}\x{9860}\x{9861}\x{9862}\x{9863}\x{9864}' . +'\x{9865}\x{9867}\x{9869}\x{986A}\x{986B}\x{986C}\x{986D}\x{986E}\x{986F}' . +'\x{9870}\x{9871}\x{9872}\x{9873}\x{9874}\x{9875}\x{9876}\x{9877}\x{9878}' . +'\x{9879}\x{987A}\x{987B}\x{987C}\x{987D}\x{987E}\x{987F}\x{9880}\x{9881}' . +'\x{9882}\x{9883}\x{9884}\x{9885}\x{9886}\x{9887}\x{9888}\x{9889}\x{988A}' . +'\x{988B}\x{988C}\x{988D}\x{988E}\x{988F}\x{9890}\x{9891}\x{9892}\x{9893}' . +'\x{9894}\x{9895}\x{9896}\x{9897}\x{9898}\x{9899}\x{989A}\x{989B}\x{989C}' . +'\x{989D}\x{989E}\x{989F}\x{98A0}\x{98A1}\x{98A2}\x{98A3}\x{98A4}\x{98A5}' . +'\x{98A6}\x{98A7}\x{98A8}\x{98A9}\x{98AA}\x{98AB}\x{98AC}\x{98AD}\x{98AE}' . +'\x{98AF}\x{98B0}\x{98B1}\x{98B2}\x{98B3}\x{98B4}\x{98B5}\x{98B6}\x{98B8}' . +'\x{98B9}\x{98BA}\x{98BB}\x{98BC}\x{98BD}\x{98BE}\x{98BF}\x{98C0}\x{98C1}' . +'\x{98C2}\x{98C3}\x{98C4}\x{98C5}\x{98C6}\x{98C8}\x{98C9}\x{98CB}\x{98CC}' . +'\x{98CD}\x{98CE}\x{98CF}\x{98D0}\x{98D1}\x{98D2}\x{98D3}\x{98D4}\x{98D5}' . +'\x{98D6}\x{98D7}\x{98D8}\x{98D9}\x{98DA}\x{98DB}\x{98DC}\x{98DD}\x{98DE}' . +'\x{98DF}\x{98E0}\x{98E2}\x{98E3}\x{98E5}\x{98E6}\x{98E7}\x{98E8}\x{98E9}' . +'\x{98EA}\x{98EB}\x{98ED}\x{98EF}\x{98F0}\x{98F2}\x{98F3}\x{98F4}\x{98F5}' . +'\x{98F6}\x{98F7}\x{98F9}\x{98FA}\x{98FC}\x{98FD}\x{98FE}\x{98FF}\x{9900}' . +'\x{9901}\x{9902}\x{9903}\x{9904}\x{9905}\x{9906}\x{9907}\x{9908}\x{9909}' . +'\x{990A}\x{990B}\x{990C}\x{990D}\x{990E}\x{990F}\x{9910}\x{9911}\x{9912}' . +'\x{9913}\x{9914}\x{9915}\x{9916}\x{9917}\x{9918}\x{991A}\x{991B}\x{991C}' . +'\x{991D}\x{991E}\x{991F}\x{9920}\x{9921}\x{9922}\x{9923}\x{9924}\x{9925}' . +'\x{9926}\x{9927}\x{9928}\x{9929}\x{992A}\x{992B}\x{992C}\x{992D}\x{992E}' . +'\x{992F}\x{9930}\x{9931}\x{9932}\x{9933}\x{9934}\x{9935}\x{9936}\x{9937}' . +'\x{9938}\x{9939}\x{993A}\x{993C}\x{993D}\x{993E}\x{993F}\x{9940}\x{9941}' . +'\x{9942}\x{9943}\x{9945}\x{9946}\x{9947}\x{9948}\x{9949}\x{994A}\x{994B}' . +'\x{994C}\x{994E}\x{994F}\x{9950}\x{9951}\x{9952}\x{9953}\x{9954}\x{9955}' . +'\x{9956}\x{9957}\x{9958}\x{9959}\x{995B}\x{995C}\x{995E}\x{995F}\x{9960}' . +'\x{9961}\x{9962}\x{9963}\x{9964}\x{9965}\x{9966}\x{9967}\x{9968}\x{9969}' . +'\x{996A}\x{996B}\x{996C}\x{996D}\x{996E}\x{996F}\x{9970}\x{9971}\x{9972}' . +'\x{9973}\x{9974}\x{9975}\x{9976}\x{9977}\x{9978}\x{9979}\x{997A}\x{997B}' . +'\x{997C}\x{997D}\x{997E}\x{997F}\x{9980}\x{9981}\x{9982}\x{9983}\x{9984}' . +'\x{9985}\x{9986}\x{9987}\x{9988}\x{9989}\x{998A}\x{998B}\x{998C}\x{998D}' . +'\x{998E}\x{998F}\x{9990}\x{9991}\x{9992}\x{9993}\x{9994}\x{9995}\x{9996}' . +'\x{9997}\x{9998}\x{9999}\x{999A}\x{999B}\x{999C}\x{999D}\x{999E}\x{999F}' . +'\x{99A0}\x{99A1}\x{99A2}\x{99A3}\x{99A4}\x{99A5}\x{99A6}\x{99A7}\x{99A8}' . +'\x{99A9}\x{99AA}\x{99AB}\x{99AC}\x{99AD}\x{99AE}\x{99AF}\x{99B0}\x{99B1}' . +'\x{99B2}\x{99B3}\x{99B4}\x{99B5}\x{99B6}\x{99B7}\x{99B8}\x{99B9}\x{99BA}' . +'\x{99BB}\x{99BC}\x{99BD}\x{99BE}\x{99C0}\x{99C1}\x{99C2}\x{99C3}\x{99C4}' . +'\x{99C6}\x{99C7}\x{99C8}\x{99C9}\x{99CA}\x{99CB}\x{99CC}\x{99CD}\x{99CE}' . +'\x{99CF}\x{99D0}\x{99D1}\x{99D2}\x{99D3}\x{99D4}\x{99D5}\x{99D6}\x{99D7}' . +'\x{99D8}\x{99D9}\x{99DA}\x{99DB}\x{99DC}\x{99DD}\x{99DE}\x{99DF}\x{99E1}' . +'\x{99E2}\x{99E3}\x{99E4}\x{99E5}\x{99E7}\x{99E8}\x{99E9}\x{99EA}\x{99EC}' . +'\x{99ED}\x{99EE}\x{99EF}\x{99F0}\x{99F1}\x{99F2}\x{99F3}\x{99F4}\x{99F6}' . +'\x{99F7}\x{99F8}\x{99F9}\x{99FA}\x{99FB}\x{99FC}\x{99FD}\x{99FE}\x{99FF}' . +'\x{9A00}\x{9A01}\x{9A02}\x{9A03}\x{9A04}\x{9A05}\x{9A06}\x{9A07}\x{9A08}' . +'\x{9A09}\x{9A0A}\x{9A0B}\x{9A0C}\x{9A0D}\x{9A0E}\x{9A0F}\x{9A11}\x{9A14}' . +'\x{9A15}\x{9A16}\x{9A19}\x{9A1A}\x{9A1B}\x{9A1C}\x{9A1D}\x{9A1E}\x{9A1F}' . +'\x{9A20}\x{9A21}\x{9A22}\x{9A23}\x{9A24}\x{9A25}\x{9A26}\x{9A27}\x{9A29}' . +'\x{9A2A}\x{9A2B}\x{9A2C}\x{9A2D}\x{9A2E}\x{9A2F}\x{9A30}\x{9A31}\x{9A32}' . +'\x{9A33}\x{9A34}\x{9A35}\x{9A36}\x{9A37}\x{9A38}\x{9A39}\x{9A3A}\x{9A3C}' . +'\x{9A3D}\x{9A3E}\x{9A3F}\x{9A40}\x{9A41}\x{9A42}\x{9A43}\x{9A44}\x{9A45}' . +'\x{9A46}\x{9A47}\x{9A48}\x{9A49}\x{9A4A}\x{9A4B}\x{9A4C}\x{9A4D}\x{9A4E}' . +'\x{9A4F}\x{9A50}\x{9A52}\x{9A53}\x{9A54}\x{9A55}\x{9A56}\x{9A57}\x{9A59}' . +'\x{9A5A}\x{9A5B}\x{9A5C}\x{9A5E}\x{9A5F}\x{9A60}\x{9A61}\x{9A62}\x{9A64}' . +'\x{9A65}\x{9A66}\x{9A67}\x{9A68}\x{9A69}\x{9A6A}\x{9A6B}\x{9A6C}\x{9A6D}' . +'\x{9A6E}\x{9A6F}\x{9A70}\x{9A71}\x{9A72}\x{9A73}\x{9A74}\x{9A75}\x{9A76}' . +'\x{9A77}\x{9A78}\x{9A79}\x{9A7A}\x{9A7B}\x{9A7C}\x{9A7D}\x{9A7E}\x{9A7F}' . +'\x{9A80}\x{9A81}\x{9A82}\x{9A83}\x{9A84}\x{9A85}\x{9A86}\x{9A87}\x{9A88}' . +'\x{9A89}\x{9A8A}\x{9A8B}\x{9A8C}\x{9A8D}\x{9A8E}\x{9A8F}\x{9A90}\x{9A91}' . +'\x{9A92}\x{9A93}\x{9A94}\x{9A95}\x{9A96}\x{9A97}\x{9A98}\x{9A99}\x{9A9A}' . +'\x{9A9B}\x{9A9C}\x{9A9D}\x{9A9E}\x{9A9F}\x{9AA0}\x{9AA1}\x{9AA2}\x{9AA3}' . +'\x{9AA4}\x{9AA5}\x{9AA6}\x{9AA7}\x{9AA8}\x{9AAA}\x{9AAB}\x{9AAC}\x{9AAD}' . +'\x{9AAE}\x{9AAF}\x{9AB0}\x{9AB1}\x{9AB2}\x{9AB3}\x{9AB4}\x{9AB5}\x{9AB6}' . +'\x{9AB7}\x{9AB8}\x{9AB9}\x{9ABA}\x{9ABB}\x{9ABC}\x{9ABE}\x{9ABF}\x{9AC0}' . +'\x{9AC1}\x{9AC2}\x{9AC3}\x{9AC4}\x{9AC5}\x{9AC6}\x{9AC7}\x{9AC9}\x{9ACA}' . +'\x{9ACB}\x{9ACC}\x{9ACD}\x{9ACE}\x{9ACF}\x{9AD0}\x{9AD1}\x{9AD2}\x{9AD3}' . +'\x{9AD4}\x{9AD5}\x{9AD6}\x{9AD8}\x{9AD9}\x{9ADA}\x{9ADB}\x{9ADC}\x{9ADD}' . +'\x{9ADE}\x{9ADF}\x{9AE1}\x{9AE2}\x{9AE3}\x{9AE5}\x{9AE6}\x{9AE7}\x{9AEA}' . +'\x{9AEB}\x{9AEC}\x{9AED}\x{9AEE}\x{9AEF}\x{9AF1}\x{9AF2}\x{9AF3}\x{9AF4}' . +'\x{9AF5}\x{9AF6}\x{9AF7}\x{9AF8}\x{9AF9}\x{9AFA}\x{9AFB}\x{9AFC}\x{9AFD}' . +'\x{9AFE}\x{9AFF}\x{9B01}\x{9B03}\x{9B04}\x{9B05}\x{9B06}\x{9B07}\x{9B08}' . +'\x{9B0A}\x{9B0B}\x{9B0C}\x{9B0D}\x{9B0E}\x{9B0F}\x{9B10}\x{9B11}\x{9B12}' . +'\x{9B13}\x{9B15}\x{9B16}\x{9B17}\x{9B18}\x{9B19}\x{9B1A}\x{9B1C}\x{9B1D}' . +'\x{9B1E}\x{9B1F}\x{9B20}\x{9B21}\x{9B22}\x{9B23}\x{9B24}\x{9B25}\x{9B26}' . +'\x{9B27}\x{9B28}\x{9B29}\x{9B2A}\x{9B2B}\x{9B2C}\x{9B2D}\x{9B2E}\x{9B2F}' . +'\x{9B30}\x{9B31}\x{9B32}\x{9B33}\x{9B35}\x{9B36}\x{9B37}\x{9B38}\x{9B39}' . +'\x{9B3A}\x{9B3B}\x{9B3C}\x{9B3E}\x{9B3F}\x{9B41}\x{9B42}\x{9B43}\x{9B44}' . +'\x{9B45}\x{9B46}\x{9B47}\x{9B48}\x{9B49}\x{9B4A}\x{9B4B}\x{9B4C}\x{9B4D}' . +'\x{9B4E}\x{9B4F}\x{9B51}\x{9B52}\x{9B53}\x{9B54}\x{9B55}\x{9B56}\x{9B58}' . +'\x{9B59}\x{9B5A}\x{9B5B}\x{9B5C}\x{9B5D}\x{9B5E}\x{9B5F}\x{9B60}\x{9B61}' . +'\x{9B63}\x{9B64}\x{9B65}\x{9B66}\x{9B67}\x{9B68}\x{9B69}\x{9B6A}\x{9B6B}' . +'\x{9B6C}\x{9B6D}\x{9B6E}\x{9B6F}\x{9B70}\x{9B71}\x{9B73}\x{9B74}\x{9B75}' . +'\x{9B76}\x{9B77}\x{9B78}\x{9B79}\x{9B7A}\x{9B7B}\x{9B7C}\x{9B7D}\x{9B7E}' . +'\x{9B7F}\x{9B80}\x{9B81}\x{9B82}\x{9B83}\x{9B84}\x{9B85}\x{9B86}\x{9B87}' . +'\x{9B88}\x{9B8A}\x{9B8B}\x{9B8D}\x{9B8E}\x{9B8F}\x{9B90}\x{9B91}\x{9B92}' . +'\x{9B93}\x{9B94}\x{9B95}\x{9B96}\x{9B97}\x{9B98}\x{9B9A}\x{9B9B}\x{9B9C}' . +'\x{9B9D}\x{9B9E}\x{9B9F}\x{9BA0}\x{9BA1}\x{9BA2}\x{9BA3}\x{9BA4}\x{9BA5}' . +'\x{9BA6}\x{9BA7}\x{9BA8}\x{9BA9}\x{9BAA}\x{9BAB}\x{9BAC}\x{9BAD}\x{9BAE}' . +'\x{9BAF}\x{9BB0}\x{9BB1}\x{9BB2}\x{9BB3}\x{9BB4}\x{9BB5}\x{9BB6}\x{9BB7}' . +'\x{9BB8}\x{9BB9}\x{9BBA}\x{9BBB}\x{9BBC}\x{9BBD}\x{9BBE}\x{9BBF}\x{9BC0}' . +'\x{9BC1}\x{9BC3}\x{9BC4}\x{9BC5}\x{9BC6}\x{9BC7}\x{9BC8}\x{9BC9}\x{9BCA}' . +'\x{9BCB}\x{9BCC}\x{9BCD}\x{9BCE}\x{9BCF}\x{9BD0}\x{9BD1}\x{9BD2}\x{9BD3}' . +'\x{9BD4}\x{9BD5}\x{9BD6}\x{9BD7}\x{9BD8}\x{9BD9}\x{9BDA}\x{9BDB}\x{9BDC}' . +'\x{9BDD}\x{9BDE}\x{9BDF}\x{9BE0}\x{9BE1}\x{9BE2}\x{9BE3}\x{9BE4}\x{9BE5}' . +'\x{9BE6}\x{9BE7}\x{9BE8}\x{9BE9}\x{9BEA}\x{9BEB}\x{9BEC}\x{9BED}\x{9BEE}' . +'\x{9BEF}\x{9BF0}\x{9BF1}\x{9BF2}\x{9BF3}\x{9BF4}\x{9BF5}\x{9BF7}\x{9BF8}' . +'\x{9BF9}\x{9BFA}\x{9BFB}\x{9BFC}\x{9BFD}\x{9BFE}\x{9BFF}\x{9C02}\x{9C05}' . +'\x{9C06}\x{9C07}\x{9C08}\x{9C09}\x{9C0A}\x{9C0B}\x{9C0C}\x{9C0D}\x{9C0E}' . +'\x{9C0F}\x{9C10}\x{9C11}\x{9C12}\x{9C13}\x{9C14}\x{9C15}\x{9C16}\x{9C17}' . +'\x{9C18}\x{9C19}\x{9C1A}\x{9C1B}\x{9C1C}\x{9C1D}\x{9C1E}\x{9C1F}\x{9C20}' . +'\x{9C21}\x{9C22}\x{9C23}\x{9C24}\x{9C25}\x{9C26}\x{9C27}\x{9C28}\x{9C29}' . +'\x{9C2A}\x{9C2B}\x{9C2C}\x{9C2D}\x{9C2F}\x{9C30}\x{9C31}\x{9C32}\x{9C33}' . +'\x{9C34}\x{9C35}\x{9C36}\x{9C37}\x{9C38}\x{9C39}\x{9C3A}\x{9C3B}\x{9C3C}' . +'\x{9C3D}\x{9C3E}\x{9C3F}\x{9C40}\x{9C41}\x{9C43}\x{9C44}\x{9C45}\x{9C46}' . +'\x{9C47}\x{9C48}\x{9C49}\x{9C4A}\x{9C4B}\x{9C4C}\x{9C4D}\x{9C4E}\x{9C50}' . +'\x{9C52}\x{9C53}\x{9C54}\x{9C55}\x{9C56}\x{9C57}\x{9C58}\x{9C59}\x{9C5A}' . +'\x{9C5B}\x{9C5C}\x{9C5D}\x{9C5E}\x{9C5F}\x{9C60}\x{9C62}\x{9C63}\x{9C65}' . +'\x{9C66}\x{9C67}\x{9C68}\x{9C69}\x{9C6A}\x{9C6B}\x{9C6C}\x{9C6D}\x{9C6E}' . +'\x{9C6F}\x{9C70}\x{9C71}\x{9C72}\x{9C73}\x{9C74}\x{9C75}\x{9C77}\x{9C78}' . +'\x{9C79}\x{9C7A}\x{9C7C}\x{9C7D}\x{9C7E}\x{9C7F}\x{9C80}\x{9C81}\x{9C82}' . +'\x{9C83}\x{9C84}\x{9C85}\x{9C86}\x{9C87}\x{9C88}\x{9C89}\x{9C8A}\x{9C8B}' . +'\x{9C8C}\x{9C8D}\x{9C8E}\x{9C8F}\x{9C90}\x{9C91}\x{9C92}\x{9C93}\x{9C94}' . +'\x{9C95}\x{9C96}\x{9C97}\x{9C98}\x{9C99}\x{9C9A}\x{9C9B}\x{9C9C}\x{9C9D}' . +'\x{9C9E}\x{9C9F}\x{9CA0}\x{9CA1}\x{9CA2}\x{9CA3}\x{9CA4}\x{9CA5}\x{9CA6}' . +'\x{9CA7}\x{9CA8}\x{9CA9}\x{9CAA}\x{9CAB}\x{9CAC}\x{9CAD}\x{9CAE}\x{9CAF}' . +'\x{9CB0}\x{9CB1}\x{9CB2}\x{9CB3}\x{9CB4}\x{9CB5}\x{9CB6}\x{9CB7}\x{9CB8}' . +'\x{9CB9}\x{9CBA}\x{9CBB}\x{9CBC}\x{9CBD}\x{9CBE}\x{9CBF}\x{9CC0}\x{9CC1}' . +'\x{9CC2}\x{9CC3}\x{9CC4}\x{9CC5}\x{9CC6}\x{9CC7}\x{9CC8}\x{9CC9}\x{9CCA}' . +'\x{9CCB}\x{9CCC}\x{9CCD}\x{9CCE}\x{9CCF}\x{9CD0}\x{9CD1}\x{9CD2}\x{9CD3}' . +'\x{9CD4}\x{9CD5}\x{9CD6}\x{9CD7}\x{9CD8}\x{9CD9}\x{9CDA}\x{9CDB}\x{9CDC}' . +'\x{9CDD}\x{9CDE}\x{9CDF}\x{9CE0}\x{9CE1}\x{9CE2}\x{9CE3}\x{9CE4}\x{9CE5}' . +'\x{9CE6}\x{9CE7}\x{9CE8}\x{9CE9}\x{9CEA}\x{9CEB}\x{9CEC}\x{9CED}\x{9CEE}' . +'\x{9CEF}\x{9CF0}\x{9CF1}\x{9CF2}\x{9CF3}\x{9CF4}\x{9CF5}\x{9CF6}\x{9CF7}' . +'\x{9CF8}\x{9CF9}\x{9CFA}\x{9CFB}\x{9CFC}\x{9CFD}\x{9CFE}\x{9CFF}\x{9D00}' . +'\x{9D01}\x{9D02}\x{9D03}\x{9D04}\x{9D05}\x{9D06}\x{9D07}\x{9D08}\x{9D09}' . +'\x{9D0A}\x{9D0B}\x{9D0F}\x{9D10}\x{9D12}\x{9D13}\x{9D14}\x{9D15}\x{9D16}' . +'\x{9D17}\x{9D18}\x{9D19}\x{9D1A}\x{9D1B}\x{9D1C}\x{9D1D}\x{9D1E}\x{9D1F}' . +'\x{9D20}\x{9D21}\x{9D22}\x{9D23}\x{9D24}\x{9D25}\x{9D26}\x{9D28}\x{9D29}' . +'\x{9D2B}\x{9D2D}\x{9D2E}\x{9D2F}\x{9D30}\x{9D31}\x{9D32}\x{9D33}\x{9D34}' . +'\x{9D36}\x{9D37}\x{9D38}\x{9D39}\x{9D3A}\x{9D3B}\x{9D3D}\x{9D3E}\x{9D3F}' . +'\x{9D40}\x{9D41}\x{9D42}\x{9D43}\x{9D45}\x{9D46}\x{9D47}\x{9D48}\x{9D49}' . +'\x{9D4A}\x{9D4B}\x{9D4C}\x{9D4D}\x{9D4E}\x{9D4F}\x{9D50}\x{9D51}\x{9D52}' . +'\x{9D53}\x{9D54}\x{9D55}\x{9D56}\x{9D57}\x{9D58}\x{9D59}\x{9D5A}\x{9D5B}' . +'\x{9D5C}\x{9D5D}\x{9D5E}\x{9D5F}\x{9D60}\x{9D61}\x{9D62}\x{9D63}\x{9D64}' . +'\x{9D65}\x{9D66}\x{9D67}\x{9D68}\x{9D69}\x{9D6A}\x{9D6B}\x{9D6C}\x{9D6E}' . +'\x{9D6F}\x{9D70}\x{9D71}\x{9D72}\x{9D73}\x{9D74}\x{9D75}\x{9D76}\x{9D77}' . +'\x{9D78}\x{9D79}\x{9D7A}\x{9D7B}\x{9D7C}\x{9D7D}\x{9D7E}\x{9D7F}\x{9D80}' . +'\x{9D81}\x{9D82}\x{9D83}\x{9D84}\x{9D85}\x{9D86}\x{9D87}\x{9D88}\x{9D89}' . +'\x{9D8A}\x{9D8B}\x{9D8C}\x{9D8D}\x{9D8E}\x{9D90}\x{9D91}\x{9D92}\x{9D93}' . +'\x{9D94}\x{9D96}\x{9D97}\x{9D98}\x{9D99}\x{9D9A}\x{9D9B}\x{9D9C}\x{9D9D}' . +'\x{9D9E}\x{9D9F}\x{9DA0}\x{9DA1}\x{9DA2}\x{9DA3}\x{9DA4}\x{9DA5}\x{9DA6}' . +'\x{9DA7}\x{9DA8}\x{9DA9}\x{9DAA}\x{9DAB}\x{9DAC}\x{9DAD}\x{9DAF}\x{9DB0}' . +'\x{9DB1}\x{9DB2}\x{9DB3}\x{9DB4}\x{9DB5}\x{9DB6}\x{9DB7}\x{9DB8}\x{9DB9}' . +'\x{9DBA}\x{9DBB}\x{9DBC}\x{9DBE}\x{9DBF}\x{9DC1}\x{9DC2}\x{9DC3}\x{9DC4}' . +'\x{9DC5}\x{9DC7}\x{9DC8}\x{9DC9}\x{9DCA}\x{9DCB}\x{9DCC}\x{9DCD}\x{9DCE}' . +'\x{9DCF}\x{9DD0}\x{9DD1}\x{9DD2}\x{9DD3}\x{9DD4}\x{9DD5}\x{9DD6}\x{9DD7}' . +'\x{9DD8}\x{9DD9}\x{9DDA}\x{9DDB}\x{9DDC}\x{9DDD}\x{9DDE}\x{9DDF}\x{9DE0}' . +'\x{9DE1}\x{9DE2}\x{9DE3}\x{9DE4}\x{9DE5}\x{9DE6}\x{9DE7}\x{9DE8}\x{9DE9}' . +'\x{9DEB}\x{9DEC}\x{9DED}\x{9DEE}\x{9DEF}\x{9DF0}\x{9DF1}\x{9DF2}\x{9DF3}' . +'\x{9DF4}\x{9DF5}\x{9DF6}\x{9DF7}\x{9DF8}\x{9DF9}\x{9DFA}\x{9DFB}\x{9DFD}' . +'\x{9DFE}\x{9DFF}\x{9E00}\x{9E01}\x{9E02}\x{9E03}\x{9E04}\x{9E05}\x{9E06}' . +'\x{9E07}\x{9E08}\x{9E09}\x{9E0A}\x{9E0B}\x{9E0C}\x{9E0D}\x{9E0F}\x{9E10}' . +'\x{9E11}\x{9E12}\x{9E13}\x{9E14}\x{9E15}\x{9E17}\x{9E18}\x{9E19}\x{9E1A}' . +'\x{9E1B}\x{9E1D}\x{9E1E}\x{9E1F}\x{9E20}\x{9E21}\x{9E22}\x{9E23}\x{9E24}' . +'\x{9E25}\x{9E26}\x{9E27}\x{9E28}\x{9E29}\x{9E2A}\x{9E2B}\x{9E2C}\x{9E2D}' . +'\x{9E2E}\x{9E2F}\x{9E30}\x{9E31}\x{9E32}\x{9E33}\x{9E34}\x{9E35}\x{9E36}' . +'\x{9E37}\x{9E38}\x{9E39}\x{9E3A}\x{9E3B}\x{9E3C}\x{9E3D}\x{9E3E}\x{9E3F}' . +'\x{9E40}\x{9E41}\x{9E42}\x{9E43}\x{9E44}\x{9E45}\x{9E46}\x{9E47}\x{9E48}' . +'\x{9E49}\x{9E4A}\x{9E4B}\x{9E4C}\x{9E4D}\x{9E4E}\x{9E4F}\x{9E50}\x{9E51}' . +'\x{9E52}\x{9E53}\x{9E54}\x{9E55}\x{9E56}\x{9E57}\x{9E58}\x{9E59}\x{9E5A}' . +'\x{9E5B}\x{9E5C}\x{9E5D}\x{9E5E}\x{9E5F}\x{9E60}\x{9E61}\x{9E62}\x{9E63}' . +'\x{9E64}\x{9E65}\x{9E66}\x{9E67}\x{9E68}\x{9E69}\x{9E6A}\x{9E6B}\x{9E6C}' . +'\x{9E6D}\x{9E6E}\x{9E6F}\x{9E70}\x{9E71}\x{9E72}\x{9E73}\x{9E74}\x{9E75}' . +'\x{9E76}\x{9E77}\x{9E79}\x{9E7A}\x{9E7C}\x{9E7D}\x{9E7E}\x{9E7F}\x{9E80}' . +'\x{9E81}\x{9E82}\x{9E83}\x{9E84}\x{9E85}\x{9E86}\x{9E87}\x{9E88}\x{9E89}' . +'\x{9E8A}\x{9E8B}\x{9E8C}\x{9E8D}\x{9E8E}\x{9E91}\x{9E92}\x{9E93}\x{9E94}' . +'\x{9E96}\x{9E97}\x{9E99}\x{9E9A}\x{9E9B}\x{9E9C}\x{9E9D}\x{9E9F}\x{9EA0}' . +'\x{9EA1}\x{9EA3}\x{9EA4}\x{9EA5}\x{9EA6}\x{9EA7}\x{9EA8}\x{9EA9}\x{9EAA}' . +'\x{9EAD}\x{9EAE}\x{9EAF}\x{9EB0}\x{9EB2}\x{9EB3}\x{9EB4}\x{9EB5}\x{9EB6}' . +'\x{9EB7}\x{9EB8}\x{9EBB}\x{9EBC}\x{9EBD}\x{9EBE}\x{9EBF}\x{9EC0}\x{9EC1}' . +'\x{9EC2}\x{9EC3}\x{9EC4}\x{9EC5}\x{9EC6}\x{9EC7}\x{9EC8}\x{9EC9}\x{9ECA}' . +'\x{9ECB}\x{9ECC}\x{9ECD}\x{9ECE}\x{9ECF}\x{9ED0}\x{9ED1}\x{9ED2}\x{9ED3}' . +'\x{9ED4}\x{9ED5}\x{9ED6}\x{9ED7}\x{9ED8}\x{9ED9}\x{9EDA}\x{9EDB}\x{9EDC}' . +'\x{9EDD}\x{9EDE}\x{9EDF}\x{9EE0}\x{9EE1}\x{9EE2}\x{9EE3}\x{9EE4}\x{9EE5}' . +'\x{9EE6}\x{9EE7}\x{9EE8}\x{9EE9}\x{9EEA}\x{9EEB}\x{9EED}\x{9EEE}\x{9EEF}' . +'\x{9EF0}\x{9EF2}\x{9EF3}\x{9EF4}\x{9EF5}\x{9EF6}\x{9EF7}\x{9EF8}\x{9EF9}' . +'\x{9EFA}\x{9EFB}\x{9EFC}\x{9EFD}\x{9EFE}\x{9EFF}\x{9F00}\x{9F01}\x{9F02}' . +'\x{9F04}\x{9F05}\x{9F06}\x{9F07}\x{9F08}\x{9F09}\x{9F0A}\x{9F0B}\x{9F0C}' . +'\x{9F0D}\x{9F0E}\x{9F0F}\x{9F10}\x{9F12}\x{9F13}\x{9F15}\x{9F16}\x{9F17}' . +'\x{9F18}\x{9F19}\x{9F1A}\x{9F1B}\x{9F1C}\x{9F1D}\x{9F1E}\x{9F1F}\x{9F20}' . +'\x{9F22}\x{9F23}\x{9F24}\x{9F25}\x{9F27}\x{9F28}\x{9F29}\x{9F2A}\x{9F2B}' . +'\x{9F2C}\x{9F2D}\x{9F2E}\x{9F2F}\x{9F30}\x{9F31}\x{9F32}\x{9F33}\x{9F34}' . +'\x{9F35}\x{9F36}\x{9F37}\x{9F38}\x{9F39}\x{9F3A}\x{9F3B}\x{9F3C}\x{9F3D}' . +'\x{9F3E}\x{9F3F}\x{9F40}\x{9F41}\x{9F42}\x{9F43}\x{9F44}\x{9F46}\x{9F47}' . +'\x{9F48}\x{9F49}\x{9F4A}\x{9F4B}\x{9F4C}\x{9F4D}\x{9F4E}\x{9F4F}\x{9F50}' . +'\x{9F51}\x{9F52}\x{9F54}\x{9F55}\x{9F56}\x{9F57}\x{9F58}\x{9F59}\x{9F5A}' . +'\x{9F5B}\x{9F5C}\x{9F5D}\x{9F5E}\x{9F5F}\x{9F60}\x{9F61}\x{9F63}\x{9F64}' . +'\x{9F65}\x{9F66}\x{9F67}\x{9F68}\x{9F69}\x{9F6A}\x{9F6B}\x{9F6C}\x{9F6E}' . +'\x{9F6F}\x{9F70}\x{9F71}\x{9F72}\x{9F73}\x{9F74}\x{9F75}\x{9F76}\x{9F77}' . +'\x{9F78}\x{9F79}\x{9F7A}\x{9F7B}\x{9F7C}\x{9F7D}\x{9F7E}\x{9F7F}\x{9F80}' . +'\x{9F81}\x{9F82}\x{9F83}\x{9F84}\x{9F85}\x{9F86}\x{9F87}\x{9F88}\x{9F89}' . +'\x{9F8A}\x{9F8B}\x{9F8C}\x{9F8D}\x{9F8E}\x{9F8F}\x{9F90}\x{9F91}\x{9F92}' . +'\x{9F93}\x{9F94}\x{9F95}\x{9F96}\x{9F97}\x{9F98}\x{9F99}\x{9F9A}\x{9F9B}' . +'\x{9F9C}\x{9F9D}\x{9F9E}\x{9F9F}\x{9FA0}\x{9FA2}\x{9FA4}\x{9FA5}]{1,20}$/iu'); diff --git a/Zend/Validate/Hostname/Cn.php b/Zend/Validate/Hostname/Cn.php new file mode 100644 index 00000000..eaa17607 --- /dev/null +++ b/Zend/Validate/Hostname/Cn.php @@ -0,0 +1,2199 @@ + '/^[\x{002d}0-9a-z\x{3447}\x{3473}\x{359E}\x{360E}\x{361A}\x{3918}\x{396E}\x{39CF}\x{39D0}' . +'\x{39DF}\x{3A73}\x{3B4E}\x{3C6E}\x{3CE0}\x{4056}\x{415F}\x{4337}\x{43AC}' . +'\x{43B1}\x{43DD}\x{44D6}\x{464C}\x{4661}\x{4723}\x{4729}\x{477C}\x{478D}' . +'\x{4947}\x{497A}\x{497D}\x{4982}\x{4983}\x{4985}\x{4986}\x{499B}\x{499F}' . +'\x{49B6}\x{49B7}\x{4C77}\x{4C9F}\x{4CA0}\x{4CA1}\x{4CA2}\x{4CA3}\x{4D13}' . +'\x{4D14}\x{4D15}\x{4D16}\x{4D17}\x{4D18}\x{4D19}\x{4DAE}\x{4E00}\x{4E01}' . +'\x{4E02}\x{4E03}\x{4E04}\x{4E05}\x{4E06}\x{4E07}\x{4E08}\x{4E09}\x{4E0A}' . +'\x{4E0B}\x{4E0C}\x{4E0D}\x{4E0E}\x{4E0F}\x{4E10}\x{4E11}\x{4E13}\x{4E14}' . +'\x{4E15}\x{4E16}\x{4E17}\x{4E18}\x{4E19}\x{4E1A}\x{4E1B}\x{4E1C}\x{4E1D}' . +'\x{4E1E}\x{4E1F}\x{4E20}\x{4E21}\x{4E22}\x{4E23}\x{4E24}\x{4E25}\x{4E26}' . +'\x{4E27}\x{4E28}\x{4E2A}\x{4E2B}\x{4E2C}\x{4E2D}\x{4E2E}\x{4E2F}\x{4E30}' . +'\x{4E31}\x{4E32}\x{4E33}\x{4E34}\x{4E35}\x{4E36}\x{4E37}\x{4E38}\x{4E39}' . +'\x{4E3A}\x{4E3B}\x{4E3C}\x{4E3D}\x{4E3E}\x{4E3F}\x{4E40}\x{4E41}\x{4E42}' . +'\x{4E43}\x{4E44}\x{4E45}\x{4E46}\x{4E47}\x{4E48}\x{4E49}\x{4E4A}\x{4E4B}' . +'\x{4E4C}\x{4E4D}\x{4E4E}\x{4E4F}\x{4E50}\x{4E51}\x{4E52}\x{4E53}\x{4E54}' . +'\x{4E56}\x{4E57}\x{4E58}\x{4E59}\x{4E5A}\x{4E5B}\x{4E5C}\x{4E5D}\x{4E5E}' . +'\x{4E5F}\x{4E60}\x{4E61}\x{4E62}\x{4E63}\x{4E64}\x{4E65}\x{4E66}\x{4E67}' . +'\x{4E69}\x{4E6A}\x{4E6B}\x{4E6C}\x{4E6D}\x{4E6E}\x{4E6F}\x{4E70}\x{4E71}' . +'\x{4E72}\x{4E73}\x{4E74}\x{4E75}\x{4E76}\x{4E77}\x{4E78}\x{4E7A}\x{4E7B}' . +'\x{4E7C}\x{4E7D}\x{4E7E}\x{4E7F}\x{4E80}\x{4E81}\x{4E82}\x{4E83}\x{4E84}' . +'\x{4E85}\x{4E86}\x{4E87}\x{4E88}\x{4E89}\x{4E8B}\x{4E8C}\x{4E8D}\x{4E8E}' . +'\x{4E8F}\x{4E90}\x{4E91}\x{4E92}\x{4E93}\x{4E94}\x{4E95}\x{4E97}\x{4E98}' . +'\x{4E99}\x{4E9A}\x{4E9B}\x{4E9C}\x{4E9D}\x{4E9E}\x{4E9F}\x{4EA0}\x{4EA1}' . +'\x{4EA2}\x{4EA4}\x{4EA5}\x{4EA6}\x{4EA7}\x{4EA8}\x{4EA9}\x{4EAA}\x{4EAB}' . +'\x{4EAC}\x{4EAD}\x{4EAE}\x{4EAF}\x{4EB0}\x{4EB1}\x{4EB2}\x{4EB3}\x{4EB4}' . +'\x{4EB5}\x{4EB6}\x{4EB7}\x{4EB8}\x{4EB9}\x{4EBA}\x{4EBB}\x{4EBD}\x{4EBE}' . +'\x{4EBF}\x{4EC0}\x{4EC1}\x{4EC2}\x{4EC3}\x{4EC4}\x{4EC5}\x{4EC6}\x{4EC7}' . +'\x{4EC8}\x{4EC9}\x{4ECA}\x{4ECB}\x{4ECD}\x{4ECE}\x{4ECF}\x{4ED0}\x{4ED1}' . +'\x{4ED2}\x{4ED3}\x{4ED4}\x{4ED5}\x{4ED6}\x{4ED7}\x{4ED8}\x{4ED9}\x{4EDA}' . +'\x{4EDB}\x{4EDC}\x{4EDD}\x{4EDE}\x{4EDF}\x{4EE0}\x{4EE1}\x{4EE2}\x{4EE3}' . +'\x{4EE4}\x{4EE5}\x{4EE6}\x{4EE8}\x{4EE9}\x{4EEA}\x{4EEB}\x{4EEC}\x{4EEF}' . +'\x{4EF0}\x{4EF1}\x{4EF2}\x{4EF3}\x{4EF4}\x{4EF5}\x{4EF6}\x{4EF7}\x{4EFB}' . +'\x{4EFD}\x{4EFF}\x{4F00}\x{4F01}\x{4F02}\x{4F03}\x{4F04}\x{4F05}\x{4F06}' . +'\x{4F08}\x{4F09}\x{4F0A}\x{4F0B}\x{4F0C}\x{4F0D}\x{4F0E}\x{4F0F}\x{4F10}' . +'\x{4F11}\x{4F12}\x{4F13}\x{4F14}\x{4F15}\x{4F17}\x{4F18}\x{4F19}\x{4F1A}' . +'\x{4F1B}\x{4F1C}\x{4F1D}\x{4F1E}\x{4F1F}\x{4F20}\x{4F21}\x{4F22}\x{4F23}' . +'\x{4F24}\x{4F25}\x{4F26}\x{4F27}\x{4F29}\x{4F2A}\x{4F2B}\x{4F2C}\x{4F2D}' . +'\x{4F2E}\x{4F2F}\x{4F30}\x{4F32}\x{4F33}\x{4F34}\x{4F36}\x{4F38}\x{4F39}' . +'\x{4F3A}\x{4F3B}\x{4F3C}\x{4F3D}\x{4F3E}\x{4F3F}\x{4F41}\x{4F42}\x{4F43}' . +'\x{4F45}\x{4F46}\x{4F47}\x{4F48}\x{4F49}\x{4F4A}\x{4F4B}\x{4F4C}\x{4F4D}' . +'\x{4F4E}\x{4F4F}\x{4F50}\x{4F51}\x{4F52}\x{4F53}\x{4F54}\x{4F55}\x{4F56}' . +'\x{4F57}\x{4F58}\x{4F59}\x{4F5A}\x{4F5B}\x{4F5C}\x{4F5D}\x{4F5E}\x{4F5F}' . +'\x{4F60}\x{4F61}\x{4F62}\x{4F63}\x{4F64}\x{4F65}\x{4F66}\x{4F67}\x{4F68}' . +'\x{4F69}\x{4F6A}\x{4F6B}\x{4F6C}\x{4F6D}\x{4F6E}\x{4F6F}\x{4F70}\x{4F72}' . +'\x{4F73}\x{4F74}\x{4F75}\x{4F76}\x{4F77}\x{4F78}\x{4F79}\x{4F7A}\x{4F7B}' . +'\x{4F7C}\x{4F7D}\x{4F7E}\x{4F7F}\x{4F80}\x{4F81}\x{4F82}\x{4F83}\x{4F84}' . +'\x{4F85}\x{4F86}\x{4F87}\x{4F88}\x{4F89}\x{4F8A}\x{4F8B}\x{4F8D}\x{4F8F}' . +'\x{4F90}\x{4F91}\x{4F92}\x{4F93}\x{4F94}\x{4F95}\x{4F96}\x{4F97}\x{4F98}' . +'\x{4F99}\x{4F9A}\x{4F9B}\x{4F9C}\x{4F9D}\x{4F9E}\x{4F9F}\x{4FA0}\x{4FA1}' . +'\x{4FA3}\x{4FA4}\x{4FA5}\x{4FA6}\x{4FA7}\x{4FA8}\x{4FA9}\x{4FAA}\x{4FAB}' . +'\x{4FAC}\x{4FAE}\x{4FAF}\x{4FB0}\x{4FB1}\x{4FB2}\x{4FB3}\x{4FB4}\x{4FB5}' . +'\x{4FB6}\x{4FB7}\x{4FB8}\x{4FB9}\x{4FBA}\x{4FBB}\x{4FBC}\x{4FBE}\x{4FBF}' . +'\x{4FC0}\x{4FC1}\x{4FC2}\x{4FC3}\x{4FC4}\x{4FC5}\x{4FC7}\x{4FC9}\x{4FCA}' . +'\x{4FCB}\x{4FCD}\x{4FCE}\x{4FCF}\x{4FD0}\x{4FD1}\x{4FD2}\x{4FD3}\x{4FD4}' . +'\x{4FD5}\x{4FD6}\x{4FD7}\x{4FD8}\x{4FD9}\x{4FDA}\x{4FDB}\x{4FDC}\x{4FDD}' . +'\x{4FDE}\x{4FDF}\x{4FE0}\x{4FE1}\x{4FE3}\x{4FE4}\x{4FE5}\x{4FE6}\x{4FE7}' . +'\x{4FE8}\x{4FE9}\x{4FEA}\x{4FEB}\x{4FEC}\x{4FED}\x{4FEE}\x{4FEF}\x{4FF0}' . +'\x{4FF1}\x{4FF2}\x{4FF3}\x{4FF4}\x{4FF5}\x{4FF6}\x{4FF7}\x{4FF8}\x{4FF9}' . +'\x{4FFA}\x{4FFB}\x{4FFE}\x{4FFF}\x{5000}\x{5001}\x{5002}\x{5003}\x{5004}' . +'\x{5005}\x{5006}\x{5007}\x{5008}\x{5009}\x{500A}\x{500B}\x{500C}\x{500D}' . +'\x{500E}\x{500F}\x{5011}\x{5012}\x{5013}\x{5014}\x{5015}\x{5016}\x{5017}' . +'\x{5018}\x{5019}\x{501A}\x{501B}\x{501C}\x{501D}\x{501E}\x{501F}\x{5020}' . +'\x{5021}\x{5022}\x{5023}\x{5024}\x{5025}\x{5026}\x{5027}\x{5028}\x{5029}' . +'\x{502A}\x{502B}\x{502C}\x{502D}\x{502E}\x{502F}\x{5030}\x{5031}\x{5032}' . +'\x{5033}\x{5035}\x{5036}\x{5037}\x{5039}\x{503A}\x{503B}\x{503C}\x{503E}' . +'\x{503F}\x{5040}\x{5041}\x{5043}\x{5044}\x{5045}\x{5046}\x{5047}\x{5048}' . +'\x{5049}\x{504A}\x{504B}\x{504C}\x{504D}\x{504E}\x{504F}\x{5051}\x{5053}' . +'\x{5054}\x{5055}\x{5056}\x{5057}\x{5059}\x{505A}\x{505B}\x{505C}\x{505D}' . +'\x{505E}\x{505F}\x{5060}\x{5061}\x{5062}\x{5063}\x{5064}\x{5065}\x{5066}' . +'\x{5067}\x{5068}\x{5069}\x{506A}\x{506B}\x{506C}\x{506D}\x{506E}\x{506F}' . +'\x{5070}\x{5071}\x{5072}\x{5073}\x{5074}\x{5075}\x{5076}\x{5077}\x{5078}' . +'\x{5079}\x{507A}\x{507B}\x{507D}\x{507E}\x{507F}\x{5080}\x{5082}\x{5083}' . +'\x{5084}\x{5085}\x{5086}\x{5087}\x{5088}\x{5089}\x{508A}\x{508B}\x{508C}' . +'\x{508D}\x{508E}\x{508F}\x{5090}\x{5091}\x{5092}\x{5094}\x{5095}\x{5096}' . +'\x{5098}\x{5099}\x{509A}\x{509B}\x{509C}\x{509D}\x{509E}\x{50A2}\x{50A3}' . +'\x{50A4}\x{50A5}\x{50A6}\x{50A7}\x{50A8}\x{50A9}\x{50AA}\x{50AB}\x{50AC}' . +'\x{50AD}\x{50AE}\x{50AF}\x{50B0}\x{50B1}\x{50B2}\x{50B3}\x{50B4}\x{50B5}' . +'\x{50B6}\x{50B7}\x{50B8}\x{50BA}\x{50BB}\x{50BC}\x{50BD}\x{50BE}\x{50BF}' . +'\x{50C0}\x{50C1}\x{50C2}\x{50C4}\x{50C5}\x{50C6}\x{50C7}\x{50C8}\x{50C9}' . +'\x{50CA}\x{50CB}\x{50CC}\x{50CD}\x{50CE}\x{50CF}\x{50D0}\x{50D1}\x{50D2}' . +'\x{50D3}\x{50D4}\x{50D5}\x{50D6}\x{50D7}\x{50D9}\x{50DA}\x{50DB}\x{50DC}' . +'\x{50DD}\x{50DE}\x{50E0}\x{50E3}\x{50E4}\x{50E5}\x{50E6}\x{50E7}\x{50E8}' . +'\x{50E9}\x{50EA}\x{50EC}\x{50ED}\x{50EE}\x{50EF}\x{50F0}\x{50F1}\x{50F2}' . +'\x{50F3}\x{50F5}\x{50F6}\x{50F8}\x{50F9}\x{50FA}\x{50FB}\x{50FC}\x{50FD}' . +'\x{50FE}\x{50FF}\x{5100}\x{5101}\x{5102}\x{5103}\x{5104}\x{5105}\x{5106}' . +'\x{5107}\x{5108}\x{5109}\x{510A}\x{510B}\x{510C}\x{510D}\x{510E}\x{510F}' . +'\x{5110}\x{5111}\x{5112}\x{5113}\x{5114}\x{5115}\x{5116}\x{5117}\x{5118}' . +'\x{5119}\x{511A}\x{511C}\x{511D}\x{511E}\x{511F}\x{5120}\x{5121}\x{5122}' . +'\x{5123}\x{5124}\x{5125}\x{5126}\x{5127}\x{5129}\x{512A}\x{512C}\x{512D}' . +'\x{512E}\x{512F}\x{5130}\x{5131}\x{5132}\x{5133}\x{5134}\x{5135}\x{5136}' . +'\x{5137}\x{5138}\x{5139}\x{513A}\x{513B}\x{513C}\x{513D}\x{513E}\x{513F}' . +'\x{5140}\x{5141}\x{5143}\x{5144}\x{5145}\x{5146}\x{5147}\x{5148}\x{5149}' . +'\x{514B}\x{514C}\x{514D}\x{514E}\x{5150}\x{5151}\x{5152}\x{5154}\x{5155}' . +'\x{5156}\x{5157}\x{5159}\x{515A}\x{515B}\x{515C}\x{515D}\x{515E}\x{515F}' . +'\x{5161}\x{5162}\x{5163}\x{5165}\x{5166}\x{5167}\x{5168}\x{5169}\x{516A}' . +'\x{516B}\x{516C}\x{516D}\x{516E}\x{516F}\x{5170}\x{5171}\x{5173}\x{5174}' . +'\x{5175}\x{5176}\x{5177}\x{5178}\x{5179}\x{517A}\x{517B}\x{517C}\x{517D}' . +'\x{517F}\x{5180}\x{5181}\x{5182}\x{5185}\x{5186}\x{5187}\x{5188}\x{5189}' . +'\x{518A}\x{518B}\x{518C}\x{518D}\x{518F}\x{5190}\x{5191}\x{5192}\x{5193}' . +'\x{5194}\x{5195}\x{5196}\x{5197}\x{5198}\x{5199}\x{519A}\x{519B}\x{519C}' . +'\x{519D}\x{519E}\x{519F}\x{51A0}\x{51A2}\x{51A4}\x{51A5}\x{51A6}\x{51A7}' . +'\x{51A8}\x{51AA}\x{51AB}\x{51AC}\x{51AE}\x{51AF}\x{51B0}\x{51B1}\x{51B2}' . +'\x{51B3}\x{51B5}\x{51B6}\x{51B7}\x{51B9}\x{51BB}\x{51BC}\x{51BD}\x{51BE}' . +'\x{51BF}\x{51C0}\x{51C1}\x{51C3}\x{51C4}\x{51C5}\x{51C6}\x{51C7}\x{51C8}' . +'\x{51C9}\x{51CA}\x{51CB}\x{51CC}\x{51CD}\x{51CE}\x{51CF}\x{51D0}\x{51D1}' . +'\x{51D4}\x{51D5}\x{51D6}\x{51D7}\x{51D8}\x{51D9}\x{51DA}\x{51DB}\x{51DC}' . +'\x{51DD}\x{51DE}\x{51E0}\x{51E1}\x{51E2}\x{51E3}\x{51E4}\x{51E5}\x{51E7}' . +'\x{51E8}\x{51E9}\x{51EA}\x{51EB}\x{51ED}\x{51EF}\x{51F0}\x{51F1}\x{51F3}' . +'\x{51F4}\x{51F5}\x{51F6}\x{51F7}\x{51F8}\x{51F9}\x{51FA}\x{51FB}\x{51FC}' . +'\x{51FD}\x{51FE}\x{51FF}\x{5200}\x{5201}\x{5202}\x{5203}\x{5204}\x{5205}' . +'\x{5206}\x{5207}\x{5208}\x{5209}\x{520A}\x{520B}\x{520C}\x{520D}\x{520E}' . +'\x{520F}\x{5210}\x{5211}\x{5212}\x{5213}\x{5214}\x{5215}\x{5216}\x{5217}' . +'\x{5218}\x{5219}\x{521A}\x{521B}\x{521C}\x{521D}\x{521E}\x{521F}\x{5220}' . +'\x{5221}\x{5222}\x{5223}\x{5224}\x{5225}\x{5226}\x{5228}\x{5229}\x{522A}' . +'\x{522B}\x{522C}\x{522D}\x{522E}\x{522F}\x{5230}\x{5231}\x{5232}\x{5233}' . +'\x{5234}\x{5235}\x{5236}\x{5237}\x{5238}\x{5239}\x{523A}\x{523B}\x{523C}' . +'\x{523D}\x{523E}\x{523F}\x{5240}\x{5241}\x{5242}\x{5243}\x{5244}\x{5245}' . +'\x{5246}\x{5247}\x{5248}\x{5249}\x{524A}\x{524B}\x{524C}\x{524D}\x{524E}' . +'\x{5250}\x{5251}\x{5252}\x{5254}\x{5255}\x{5256}\x{5257}\x{5258}\x{5259}' . +'\x{525A}\x{525B}\x{525C}\x{525D}\x{525E}\x{525F}\x{5260}\x{5261}\x{5262}' . +'\x{5263}\x{5264}\x{5265}\x{5267}\x{5268}\x{5269}\x{526A}\x{526B}\x{526C}' . +'\x{526D}\x{526E}\x{526F}\x{5270}\x{5272}\x{5273}\x{5274}\x{5275}\x{5276}' . +'\x{5277}\x{5278}\x{527A}\x{527B}\x{527C}\x{527D}\x{527E}\x{527F}\x{5280}' . +'\x{5281}\x{5282}\x{5283}\x{5284}\x{5286}\x{5287}\x{5288}\x{5289}\x{528A}' . +'\x{528B}\x{528C}\x{528D}\x{528F}\x{5290}\x{5291}\x{5292}\x{5293}\x{5294}' . +'\x{5295}\x{5296}\x{5297}\x{5298}\x{5299}\x{529A}\x{529B}\x{529C}\x{529D}' . +'\x{529E}\x{529F}\x{52A0}\x{52A1}\x{52A2}\x{52A3}\x{52A5}\x{52A6}\x{52A7}' . +'\x{52A8}\x{52A9}\x{52AA}\x{52AB}\x{52AC}\x{52AD}\x{52AE}\x{52AF}\x{52B0}' . +'\x{52B1}\x{52B2}\x{52B3}\x{52B4}\x{52B5}\x{52B6}\x{52B7}\x{52B8}\x{52B9}' . +'\x{52BA}\x{52BB}\x{52BC}\x{52BD}\x{52BE}\x{52BF}\x{52C0}\x{52C1}\x{52C2}' . +'\x{52C3}\x{52C6}\x{52C7}\x{52C9}\x{52CA}\x{52CB}\x{52CD}\x{52CF}\x{52D0}' . +'\x{52D2}\x{52D3}\x{52D5}\x{52D6}\x{52D7}\x{52D8}\x{52D9}\x{52DA}\x{52DB}' . +'\x{52DC}\x{52DD}\x{52DE}\x{52DF}\x{52E0}\x{52E2}\x{52E3}\x{52E4}\x{52E6}' . +'\x{52E7}\x{52E8}\x{52E9}\x{52EA}\x{52EB}\x{52EC}\x{52ED}\x{52EF}\x{52F0}' . +'\x{52F1}\x{52F2}\x{52F3}\x{52F4}\x{52F5}\x{52F6}\x{52F7}\x{52F8}\x{52F9}' . +'\x{52FA}\x{52FB}\x{52FC}\x{52FD}\x{52FE}\x{52FF}\x{5300}\x{5301}\x{5302}' . +'\x{5305}\x{5306}\x{5307}\x{5308}\x{5309}\x{530A}\x{530B}\x{530C}\x{530D}' . +'\x{530E}\x{530F}\x{5310}\x{5311}\x{5312}\x{5313}\x{5314}\x{5315}\x{5316}' . +'\x{5317}\x{5319}\x{531A}\x{531C}\x{531D}\x{531F}\x{5320}\x{5321}\x{5322}' . +'\x{5323}\x{5324}\x{5325}\x{5326}\x{5328}\x{532A}\x{532B}\x{532C}\x{532D}' . +'\x{532E}\x{532F}\x{5330}\x{5331}\x{5333}\x{5334}\x{5337}\x{5339}\x{533A}' . +'\x{533B}\x{533C}\x{533D}\x{533E}\x{533F}\x{5340}\x{5341}\x{5343}\x{5344}' . +'\x{5345}\x{5346}\x{5347}\x{5348}\x{5349}\x{534A}\x{534B}\x{534C}\x{534D}' . +'\x{534E}\x{534F}\x{5350}\x{5351}\x{5352}\x{5353}\x{5354}\x{5355}\x{5356}' . +'\x{5357}\x{5358}\x{5359}\x{535A}\x{535C}\x{535E}\x{535F}\x{5360}\x{5361}' . +'\x{5362}\x{5363}\x{5364}\x{5365}\x{5366}\x{5367}\x{5369}\x{536B}\x{536C}' . +'\x{536E}\x{536F}\x{5370}\x{5371}\x{5372}\x{5373}\x{5374}\x{5375}\x{5376}' . +'\x{5377}\x{5378}\x{5379}\x{537A}\x{537B}\x{537C}\x{537D}\x{537E}\x{537F}' . +'\x{5381}\x{5382}\x{5383}\x{5384}\x{5385}\x{5386}\x{5387}\x{5388}\x{5389}' . +'\x{538A}\x{538B}\x{538C}\x{538D}\x{538E}\x{538F}\x{5390}\x{5391}\x{5392}' . +'\x{5393}\x{5394}\x{5395}\x{5396}\x{5397}\x{5398}\x{5399}\x{539A}\x{539B}' . +'\x{539C}\x{539D}\x{539E}\x{539F}\x{53A0}\x{53A2}\x{53A3}\x{53A4}\x{53A5}' . +'\x{53A6}\x{53A7}\x{53A8}\x{53A9}\x{53AC}\x{53AD}\x{53AE}\x{53B0}\x{53B1}' . +'\x{53B2}\x{53B3}\x{53B4}\x{53B5}\x{53B6}\x{53B7}\x{53B8}\x{53B9}\x{53BB}' . +'\x{53BC}\x{53BD}\x{53BE}\x{53BF}\x{53C0}\x{53C1}\x{53C2}\x{53C3}\x{53C4}' . +'\x{53C6}\x{53C7}\x{53C8}\x{53C9}\x{53CA}\x{53CB}\x{53CC}\x{53CD}\x{53CE}' . +'\x{53D0}\x{53D1}\x{53D2}\x{53D3}\x{53D4}\x{53D5}\x{53D6}\x{53D7}\x{53D8}' . +'\x{53D9}\x{53DB}\x{53DC}\x{53DF}\x{53E0}\x{53E1}\x{53E2}\x{53E3}\x{53E4}' . +'\x{53E5}\x{53E6}\x{53E8}\x{53E9}\x{53EA}\x{53EB}\x{53EC}\x{53ED}\x{53EE}' . +'\x{53EF}\x{53F0}\x{53F1}\x{53F2}\x{53F3}\x{53F4}\x{53F5}\x{53F6}\x{53F7}' . +'\x{53F8}\x{53F9}\x{53FA}\x{53FB}\x{53FC}\x{53FD}\x{53FE}\x{5401}\x{5402}' . +'\x{5403}\x{5404}\x{5405}\x{5406}\x{5407}\x{5408}\x{5409}\x{540A}\x{540B}' . +'\x{540C}\x{540D}\x{540E}\x{540F}\x{5410}\x{5411}\x{5412}\x{5413}\x{5414}' . +'\x{5415}\x{5416}\x{5417}\x{5418}\x{5419}\x{541B}\x{541C}\x{541D}\x{541E}' . +'\x{541F}\x{5420}\x{5421}\x{5423}\x{5424}\x{5425}\x{5426}\x{5427}\x{5428}' . +'\x{5429}\x{542A}\x{542B}\x{542C}\x{542D}\x{542E}\x{542F}\x{5430}\x{5431}' . +'\x{5432}\x{5433}\x{5434}\x{5435}\x{5436}\x{5437}\x{5438}\x{5439}\x{543A}' . +'\x{543B}\x{543C}\x{543D}\x{543E}\x{543F}\x{5440}\x{5441}\x{5442}\x{5443}' . +'\x{5444}\x{5445}\x{5446}\x{5447}\x{5448}\x{5449}\x{544A}\x{544B}\x{544D}' . +'\x{544E}\x{544F}\x{5450}\x{5451}\x{5452}\x{5453}\x{5454}\x{5455}\x{5456}' . +'\x{5457}\x{5458}\x{5459}\x{545A}\x{545B}\x{545C}\x{545E}\x{545F}\x{5460}' . +'\x{5461}\x{5462}\x{5463}\x{5464}\x{5465}\x{5466}\x{5467}\x{5468}\x{546A}' . +'\x{546B}\x{546C}\x{546D}\x{546E}\x{546F}\x{5470}\x{5471}\x{5472}\x{5473}' . +'\x{5474}\x{5475}\x{5476}\x{5477}\x{5478}\x{5479}\x{547A}\x{547B}\x{547C}' . +'\x{547D}\x{547E}\x{547F}\x{5480}\x{5481}\x{5482}\x{5483}\x{5484}\x{5485}' . +'\x{5486}\x{5487}\x{5488}\x{5489}\x{548B}\x{548C}\x{548D}\x{548E}\x{548F}' . +'\x{5490}\x{5491}\x{5492}\x{5493}\x{5494}\x{5495}\x{5496}\x{5497}\x{5498}' . +'\x{5499}\x{549A}\x{549B}\x{549C}\x{549D}\x{549E}\x{549F}\x{54A0}\x{54A1}' . +'\x{54A2}\x{54A3}\x{54A4}\x{54A5}\x{54A6}\x{54A7}\x{54A8}\x{54A9}\x{54AA}' . +'\x{54AB}\x{54AC}\x{54AD}\x{54AE}\x{54AF}\x{54B0}\x{54B1}\x{54B2}\x{54B3}' . +'\x{54B4}\x{54B6}\x{54B7}\x{54B8}\x{54B9}\x{54BA}\x{54BB}\x{54BC}\x{54BD}' . +'\x{54BE}\x{54BF}\x{54C0}\x{54C1}\x{54C2}\x{54C3}\x{54C4}\x{54C5}\x{54C6}' . +'\x{54C7}\x{54C8}\x{54C9}\x{54CA}\x{54CB}\x{54CC}\x{54CD}\x{54CE}\x{54CF}' . +'\x{54D0}\x{54D1}\x{54D2}\x{54D3}\x{54D4}\x{54D5}\x{54D6}\x{54D7}\x{54D8}' . +'\x{54D9}\x{54DA}\x{54DB}\x{54DC}\x{54DD}\x{54DE}\x{54DF}\x{54E0}\x{54E1}' . +'\x{54E2}\x{54E3}\x{54E4}\x{54E5}\x{54E6}\x{54E7}\x{54E8}\x{54E9}\x{54EA}' . +'\x{54EB}\x{54EC}\x{54ED}\x{54EE}\x{54EF}\x{54F0}\x{54F1}\x{54F2}\x{54F3}' . +'\x{54F4}\x{54F5}\x{54F7}\x{54F8}\x{54F9}\x{54FA}\x{54FB}\x{54FC}\x{54FD}' . +'\x{54FE}\x{54FF}\x{5500}\x{5501}\x{5502}\x{5503}\x{5504}\x{5505}\x{5506}' . +'\x{5507}\x{5508}\x{5509}\x{550A}\x{550B}\x{550C}\x{550D}\x{550E}\x{550F}' . +'\x{5510}\x{5511}\x{5512}\x{5513}\x{5514}\x{5516}\x{5517}\x{551A}\x{551B}' . +'\x{551C}\x{551D}\x{551E}\x{551F}\x{5520}\x{5521}\x{5522}\x{5523}\x{5524}' . +'\x{5525}\x{5526}\x{5527}\x{5528}\x{5529}\x{552A}\x{552B}\x{552C}\x{552D}' . +'\x{552E}\x{552F}\x{5530}\x{5531}\x{5532}\x{5533}\x{5534}\x{5535}\x{5536}' . +'\x{5537}\x{5538}\x{5539}\x{553A}\x{553B}\x{553C}\x{553D}\x{553E}\x{553F}' . +'\x{5540}\x{5541}\x{5542}\x{5543}\x{5544}\x{5545}\x{5546}\x{5548}\x{5549}' . +'\x{554A}\x{554B}\x{554C}\x{554D}\x{554E}\x{554F}\x{5550}\x{5551}\x{5552}' . +'\x{5553}\x{5554}\x{5555}\x{5556}\x{5557}\x{5558}\x{5559}\x{555A}\x{555B}' . +'\x{555C}\x{555D}\x{555E}\x{555F}\x{5561}\x{5562}\x{5563}\x{5564}\x{5565}' . +'\x{5566}\x{5567}\x{5568}\x{5569}\x{556A}\x{556B}\x{556C}\x{556D}\x{556E}' . +'\x{556F}\x{5570}\x{5571}\x{5572}\x{5573}\x{5574}\x{5575}\x{5576}\x{5577}' . +'\x{5578}\x{5579}\x{557B}\x{557C}\x{557D}\x{557E}\x{557F}\x{5580}\x{5581}' . +'\x{5582}\x{5583}\x{5584}\x{5585}\x{5586}\x{5587}\x{5588}\x{5589}\x{558A}' . +'\x{558B}\x{558C}\x{558D}\x{558E}\x{558F}\x{5590}\x{5591}\x{5592}\x{5593}' . +'\x{5594}\x{5595}\x{5596}\x{5597}\x{5598}\x{5599}\x{559A}\x{559B}\x{559C}' . +'\x{559D}\x{559E}\x{559F}\x{55A0}\x{55A1}\x{55A2}\x{55A3}\x{55A4}\x{55A5}' . +'\x{55A6}\x{55A7}\x{55A8}\x{55A9}\x{55AA}\x{55AB}\x{55AC}\x{55AD}\x{55AE}' . +'\x{55AF}\x{55B0}\x{55B1}\x{55B2}\x{55B3}\x{55B4}\x{55B5}\x{55B6}\x{55B7}' . +'\x{55B8}\x{55B9}\x{55BA}\x{55BB}\x{55BC}\x{55BD}\x{55BE}\x{55BF}\x{55C0}' . +'\x{55C1}\x{55C2}\x{55C3}\x{55C4}\x{55C5}\x{55C6}\x{55C7}\x{55C8}\x{55C9}' . +'\x{55CA}\x{55CB}\x{55CC}\x{55CD}\x{55CE}\x{55CF}\x{55D0}\x{55D1}\x{55D2}' . +'\x{55D3}\x{55D4}\x{55D5}\x{55D6}\x{55D7}\x{55D8}\x{55D9}\x{55DA}\x{55DB}' . +'\x{55DC}\x{55DD}\x{55DE}\x{55DF}\x{55E1}\x{55E2}\x{55E3}\x{55E4}\x{55E5}' . +'\x{55E6}\x{55E7}\x{55E8}\x{55E9}\x{55EA}\x{55EB}\x{55EC}\x{55ED}\x{55EE}' . +'\x{55EF}\x{55F0}\x{55F1}\x{55F2}\x{55F3}\x{55F4}\x{55F5}\x{55F6}\x{55F7}' . +'\x{55F9}\x{55FA}\x{55FB}\x{55FC}\x{55FD}\x{55FE}\x{55FF}\x{5600}\x{5601}' . +'\x{5602}\x{5603}\x{5604}\x{5606}\x{5607}\x{5608}\x{5609}\x{560C}\x{560D}' . +'\x{560E}\x{560F}\x{5610}\x{5611}\x{5612}\x{5613}\x{5614}\x{5615}\x{5616}' . +'\x{5617}\x{5618}\x{5619}\x{561A}\x{561B}\x{561C}\x{561D}\x{561E}\x{561F}' . +'\x{5621}\x{5622}\x{5623}\x{5624}\x{5625}\x{5626}\x{5627}\x{5628}\x{5629}' . +'\x{562A}\x{562C}\x{562D}\x{562E}\x{562F}\x{5630}\x{5631}\x{5632}\x{5633}' . +'\x{5634}\x{5635}\x{5636}\x{5638}\x{5639}\x{563A}\x{563B}\x{563D}\x{563E}' . +'\x{563F}\x{5640}\x{5641}\x{5642}\x{5643}\x{5645}\x{5646}\x{5647}\x{5648}' . +'\x{5649}\x{564A}\x{564C}\x{564D}\x{564E}\x{564F}\x{5650}\x{5652}\x{5653}' . +'\x{5654}\x{5655}\x{5657}\x{5658}\x{5659}\x{565A}\x{565B}\x{565C}\x{565D}' . +'\x{565E}\x{5660}\x{5662}\x{5663}\x{5664}\x{5665}\x{5666}\x{5667}\x{5668}' . +'\x{5669}\x{566A}\x{566B}\x{566C}\x{566D}\x{566E}\x{566F}\x{5670}\x{5671}' . +'\x{5672}\x{5673}\x{5674}\x{5676}\x{5677}\x{5678}\x{5679}\x{567A}\x{567B}' . +'\x{567C}\x{567E}\x{567F}\x{5680}\x{5681}\x{5682}\x{5683}\x{5684}\x{5685}' . +'\x{5686}\x{5687}\x{568A}\x{568C}\x{568D}\x{568E}\x{568F}\x{5690}\x{5691}' . +'\x{5692}\x{5693}\x{5694}\x{5695}\x{5697}\x{5698}\x{5699}\x{569A}\x{569B}' . +'\x{569C}\x{569D}\x{569F}\x{56A0}\x{56A1}\x{56A3}\x{56A4}\x{56A5}\x{56A6}' . +'\x{56A7}\x{56A8}\x{56A9}\x{56AA}\x{56AB}\x{56AC}\x{56AD}\x{56AE}\x{56AF}' . +'\x{56B0}\x{56B1}\x{56B2}\x{56B3}\x{56B4}\x{56B5}\x{56B6}\x{56B7}\x{56B8}' . +'\x{56B9}\x{56BB}\x{56BC}\x{56BD}\x{56BE}\x{56BF}\x{56C0}\x{56C1}\x{56C2}' . +'\x{56C3}\x{56C4}\x{56C5}\x{56C6}\x{56C7}\x{56C8}\x{56C9}\x{56CA}\x{56CB}' . +'\x{56CC}\x{56CD}\x{56CE}\x{56D0}\x{56D1}\x{56D2}\x{56D3}\x{56D4}\x{56D5}' . +'\x{56D6}\x{56D7}\x{56D8}\x{56DA}\x{56DB}\x{56DC}\x{56DD}\x{56DE}\x{56DF}' . +'\x{56E0}\x{56E1}\x{56E2}\x{56E3}\x{56E4}\x{56E5}\x{56E7}\x{56E8}\x{56E9}' . +'\x{56EA}\x{56EB}\x{56EC}\x{56ED}\x{56EE}\x{56EF}\x{56F0}\x{56F1}\x{56F2}' . +'\x{56F3}\x{56F4}\x{56F5}\x{56F7}\x{56F9}\x{56FA}\x{56FD}\x{56FE}\x{56FF}' . +'\x{5700}\x{5701}\x{5702}\x{5703}\x{5704}\x{5706}\x{5707}\x{5708}\x{5709}' . +'\x{570A}\x{570B}\x{570C}\x{570D}\x{570E}\x{570F}\x{5710}\x{5712}\x{5713}' . +'\x{5714}\x{5715}\x{5716}\x{5718}\x{5719}\x{571A}\x{571B}\x{571C}\x{571D}' . +'\x{571E}\x{571F}\x{5720}\x{5722}\x{5723}\x{5725}\x{5726}\x{5727}\x{5728}' . +'\x{5729}\x{572A}\x{572B}\x{572C}\x{572D}\x{572E}\x{572F}\x{5730}\x{5731}' . +'\x{5732}\x{5733}\x{5734}\x{5735}\x{5736}\x{5737}\x{5738}\x{5739}\x{573A}' . +'\x{573B}\x{573C}\x{573E}\x{573F}\x{5740}\x{5741}\x{5742}\x{5744}\x{5745}' . +'\x{5746}\x{5747}\x{5749}\x{574A}\x{574B}\x{574C}\x{574D}\x{574E}\x{574F}' . +'\x{5750}\x{5751}\x{5752}\x{5753}\x{5754}\x{5757}\x{5759}\x{575A}\x{575B}' . +'\x{575C}\x{575D}\x{575E}\x{575F}\x{5760}\x{5761}\x{5762}\x{5764}\x{5765}' . +'\x{5766}\x{5767}\x{5768}\x{5769}\x{576A}\x{576B}\x{576C}\x{576D}\x{576F}' . +'\x{5770}\x{5771}\x{5772}\x{5773}\x{5774}\x{5775}\x{5776}\x{5777}\x{5779}' . +'\x{577A}\x{577B}\x{577C}\x{577D}\x{577E}\x{577F}\x{5780}\x{5782}\x{5783}' . +'\x{5784}\x{5785}\x{5786}\x{5788}\x{5789}\x{578A}\x{578B}\x{578C}\x{578D}' . +'\x{578E}\x{578F}\x{5790}\x{5791}\x{5792}\x{5793}\x{5794}\x{5795}\x{5797}' . +'\x{5798}\x{5799}\x{579A}\x{579B}\x{579C}\x{579D}\x{579E}\x{579F}\x{57A0}' . +'\x{57A1}\x{57A2}\x{57A3}\x{57A4}\x{57A5}\x{57A6}\x{57A7}\x{57A9}\x{57AA}' . +'\x{57AB}\x{57AC}\x{57AD}\x{57AE}\x{57AF}\x{57B0}\x{57B1}\x{57B2}\x{57B3}' . +'\x{57B4}\x{57B5}\x{57B6}\x{57B7}\x{57B8}\x{57B9}\x{57BA}\x{57BB}\x{57BC}' . +'\x{57BD}\x{57BE}\x{57BF}\x{57C0}\x{57C1}\x{57C2}\x{57C3}\x{57C4}\x{57C5}' . +'\x{57C6}\x{57C7}\x{57C8}\x{57C9}\x{57CB}\x{57CC}\x{57CD}\x{57CE}\x{57CF}' . +'\x{57D0}\x{57D2}\x{57D3}\x{57D4}\x{57D5}\x{57D6}\x{57D8}\x{57D9}\x{57DA}' . +'\x{57DC}\x{57DD}\x{57DF}\x{57E0}\x{57E1}\x{57E2}\x{57E3}\x{57E4}\x{57E5}' . +'\x{57E6}\x{57E7}\x{57E8}\x{57E9}\x{57EA}\x{57EB}\x{57EC}\x{57ED}\x{57EE}' . +'\x{57EF}\x{57F0}\x{57F1}\x{57F2}\x{57F3}\x{57F4}\x{57F5}\x{57F6}\x{57F7}' . +'\x{57F8}\x{57F9}\x{57FA}\x{57FB}\x{57FC}\x{57FD}\x{57FE}\x{57FF}\x{5800}' . +'\x{5801}\x{5802}\x{5803}\x{5804}\x{5805}\x{5806}\x{5807}\x{5808}\x{5809}' . +'\x{580A}\x{580B}\x{580C}\x{580D}\x{580E}\x{580F}\x{5810}\x{5811}\x{5812}' . +'\x{5813}\x{5814}\x{5815}\x{5816}\x{5819}\x{581A}\x{581B}\x{581C}\x{581D}' . +'\x{581E}\x{581F}\x{5820}\x{5821}\x{5822}\x{5823}\x{5824}\x{5825}\x{5826}' . +'\x{5827}\x{5828}\x{5829}\x{582A}\x{582B}\x{582C}\x{582D}\x{582E}\x{582F}' . +'\x{5830}\x{5831}\x{5832}\x{5833}\x{5834}\x{5835}\x{5836}\x{5837}\x{5838}' . +'\x{5839}\x{583A}\x{583B}\x{583C}\x{583D}\x{583E}\x{583F}\x{5840}\x{5842}' . +'\x{5843}\x{5844}\x{5845}\x{5846}\x{5847}\x{5848}\x{5849}\x{584A}\x{584B}' . +'\x{584C}\x{584D}\x{584E}\x{584F}\x{5851}\x{5852}\x{5853}\x{5854}\x{5855}' . +'\x{5857}\x{5858}\x{5859}\x{585A}\x{585B}\x{585C}\x{585D}\x{585E}\x{585F}' . +'\x{5861}\x{5862}\x{5863}\x{5864}\x{5865}\x{5868}\x{5869}\x{586A}\x{586B}' . +'\x{586C}\x{586D}\x{586E}\x{586F}\x{5870}\x{5871}\x{5872}\x{5873}\x{5874}' . +'\x{5875}\x{5876}\x{5878}\x{5879}\x{587A}\x{587B}\x{587C}\x{587D}\x{587E}' . +'\x{587F}\x{5880}\x{5881}\x{5882}\x{5883}\x{5884}\x{5885}\x{5886}\x{5887}' . +'\x{5888}\x{5889}\x{588A}\x{588B}\x{588C}\x{588D}\x{588E}\x{588F}\x{5890}' . +'\x{5891}\x{5892}\x{5893}\x{5894}\x{5896}\x{5897}\x{5898}\x{5899}\x{589A}' . +'\x{589B}\x{589C}\x{589D}\x{589E}\x{589F}\x{58A0}\x{58A1}\x{58A2}\x{58A3}' . +'\x{58A4}\x{58A5}\x{58A6}\x{58A7}\x{58A8}\x{58A9}\x{58AB}\x{58AC}\x{58AD}' . +'\x{58AE}\x{58AF}\x{58B0}\x{58B1}\x{58B2}\x{58B3}\x{58B4}\x{58B7}\x{58B8}' . +'\x{58B9}\x{58BA}\x{58BB}\x{58BC}\x{58BD}\x{58BE}\x{58BF}\x{58C1}\x{58C2}' . +'\x{58C5}\x{58C6}\x{58C7}\x{58C8}\x{58C9}\x{58CA}\x{58CB}\x{58CE}\x{58CF}' . +'\x{58D1}\x{58D2}\x{58D3}\x{58D4}\x{58D5}\x{58D6}\x{58D7}\x{58D8}\x{58D9}' . +'\x{58DA}\x{58DB}\x{58DD}\x{58DE}\x{58DF}\x{58E0}\x{58E2}\x{58E3}\x{58E4}' . +'\x{58E5}\x{58E7}\x{58E8}\x{58E9}\x{58EA}\x{58EB}\x{58EC}\x{58ED}\x{58EE}' . +'\x{58EF}\x{58F0}\x{58F1}\x{58F2}\x{58F3}\x{58F4}\x{58F6}\x{58F7}\x{58F8}' . +'\x{58F9}\x{58FA}\x{58FB}\x{58FC}\x{58FD}\x{58FE}\x{58FF}\x{5900}\x{5902}' . +'\x{5903}\x{5904}\x{5906}\x{5907}\x{5909}\x{590A}\x{590B}\x{590C}\x{590D}' . +'\x{590E}\x{590F}\x{5910}\x{5912}\x{5914}\x{5915}\x{5916}\x{5917}\x{5918}' . +'\x{5919}\x{591A}\x{591B}\x{591C}\x{591D}\x{591E}\x{591F}\x{5920}\x{5921}' . +'\x{5922}\x{5924}\x{5925}\x{5926}\x{5927}\x{5928}\x{5929}\x{592A}\x{592B}' . +'\x{592C}\x{592D}\x{592E}\x{592F}\x{5930}\x{5931}\x{5932}\x{5934}\x{5935}' . +'\x{5937}\x{5938}\x{5939}\x{593A}\x{593B}\x{593C}\x{593D}\x{593E}\x{593F}' . +'\x{5940}\x{5941}\x{5942}\x{5943}\x{5944}\x{5945}\x{5946}\x{5947}\x{5948}' . +'\x{5949}\x{594A}\x{594B}\x{594C}\x{594D}\x{594E}\x{594F}\x{5950}\x{5951}' . +'\x{5952}\x{5953}\x{5954}\x{5955}\x{5956}\x{5957}\x{5958}\x{595A}\x{595C}' . +'\x{595D}\x{595E}\x{595F}\x{5960}\x{5961}\x{5962}\x{5963}\x{5964}\x{5965}' . +'\x{5966}\x{5967}\x{5968}\x{5969}\x{596A}\x{596B}\x{596C}\x{596D}\x{596E}' . +'\x{596F}\x{5970}\x{5971}\x{5972}\x{5973}\x{5974}\x{5975}\x{5976}\x{5977}' . +'\x{5978}\x{5979}\x{597A}\x{597B}\x{597C}\x{597D}\x{597E}\x{597F}\x{5980}' . +'\x{5981}\x{5982}\x{5983}\x{5984}\x{5985}\x{5986}\x{5987}\x{5988}\x{5989}' . +'\x{598A}\x{598B}\x{598C}\x{598D}\x{598E}\x{598F}\x{5990}\x{5991}\x{5992}' . +'\x{5993}\x{5994}\x{5995}\x{5996}\x{5997}\x{5998}\x{5999}\x{599A}\x{599C}' . +'\x{599D}\x{599E}\x{599F}\x{59A0}\x{59A1}\x{59A2}\x{59A3}\x{59A4}\x{59A5}' . +'\x{59A6}\x{59A7}\x{59A8}\x{59A9}\x{59AA}\x{59AB}\x{59AC}\x{59AD}\x{59AE}' . +'\x{59AF}\x{59B0}\x{59B1}\x{59B2}\x{59B3}\x{59B4}\x{59B5}\x{59B6}\x{59B8}' . +'\x{59B9}\x{59BA}\x{59BB}\x{59BC}\x{59BD}\x{59BE}\x{59BF}\x{59C0}\x{59C1}' . +'\x{59C2}\x{59C3}\x{59C4}\x{59C5}\x{59C6}\x{59C7}\x{59C8}\x{59C9}\x{59CA}' . +'\x{59CB}\x{59CC}\x{59CD}\x{59CE}\x{59CF}\x{59D0}\x{59D1}\x{59D2}\x{59D3}' . +'\x{59D4}\x{59D5}\x{59D6}\x{59D7}\x{59D8}\x{59D9}\x{59DA}\x{59DB}\x{59DC}' . +'\x{59DD}\x{59DE}\x{59DF}\x{59E0}\x{59E1}\x{59E2}\x{59E3}\x{59E4}\x{59E5}' . +'\x{59E6}\x{59E8}\x{59E9}\x{59EA}\x{59EB}\x{59EC}\x{59ED}\x{59EE}\x{59EF}' . +'\x{59F0}\x{59F1}\x{59F2}\x{59F3}\x{59F4}\x{59F5}\x{59F6}\x{59F7}\x{59F8}' . +'\x{59F9}\x{59FA}\x{59FB}\x{59FC}\x{59FD}\x{59FE}\x{59FF}\x{5A00}\x{5A01}' . +'\x{5A02}\x{5A03}\x{5A04}\x{5A05}\x{5A06}\x{5A07}\x{5A08}\x{5A09}\x{5A0A}' . +'\x{5A0B}\x{5A0C}\x{5A0D}\x{5A0E}\x{5A0F}\x{5A10}\x{5A11}\x{5A12}\x{5A13}' . +'\x{5A14}\x{5A15}\x{5A16}\x{5A17}\x{5A18}\x{5A19}\x{5A1A}\x{5A1B}\x{5A1C}' . +'\x{5A1D}\x{5A1E}\x{5A1F}\x{5A20}\x{5A21}\x{5A22}\x{5A23}\x{5A25}\x{5A27}' . +'\x{5A28}\x{5A29}\x{5A2A}\x{5A2B}\x{5A2D}\x{5A2E}\x{5A2F}\x{5A31}\x{5A32}' . +'\x{5A33}\x{5A34}\x{5A35}\x{5A36}\x{5A37}\x{5A38}\x{5A39}\x{5A3A}\x{5A3B}' . +'\x{5A3C}\x{5A3D}\x{5A3E}\x{5A3F}\x{5A40}\x{5A41}\x{5A42}\x{5A43}\x{5A44}' . +'\x{5A45}\x{5A46}\x{5A47}\x{5A48}\x{5A49}\x{5A4A}\x{5A4B}\x{5A4C}\x{5A4D}' . +'\x{5A4E}\x{5A4F}\x{5A50}\x{5A51}\x{5A52}\x{5A53}\x{5A55}\x{5A56}\x{5A57}' . +'\x{5A58}\x{5A5A}\x{5A5B}\x{5A5C}\x{5A5D}\x{5A5E}\x{5A5F}\x{5A60}\x{5A61}' . +'\x{5A62}\x{5A63}\x{5A64}\x{5A65}\x{5A66}\x{5A67}\x{5A68}\x{5A69}\x{5A6A}' . +'\x{5A6B}\x{5A6C}\x{5A6D}\x{5A6E}\x{5A70}\x{5A72}\x{5A73}\x{5A74}\x{5A75}' . +'\x{5A76}\x{5A77}\x{5A78}\x{5A79}\x{5A7A}\x{5A7B}\x{5A7C}\x{5A7D}\x{5A7E}' . +'\x{5A7F}\x{5A80}\x{5A81}\x{5A82}\x{5A83}\x{5A84}\x{5A85}\x{5A86}\x{5A88}' . +'\x{5A89}\x{5A8A}\x{5A8B}\x{5A8C}\x{5A8E}\x{5A8F}\x{5A90}\x{5A91}\x{5A92}' . +'\x{5A93}\x{5A94}\x{5A95}\x{5A96}\x{5A97}\x{5A98}\x{5A99}\x{5A9A}\x{5A9B}' . +'\x{5A9C}\x{5A9D}\x{5A9E}\x{5A9F}\x{5AA0}\x{5AA1}\x{5AA2}\x{5AA3}\x{5AA4}' . +'\x{5AA5}\x{5AA6}\x{5AA7}\x{5AA8}\x{5AA9}\x{5AAA}\x{5AAC}\x{5AAD}\x{5AAE}' . +'\x{5AAF}\x{5AB0}\x{5AB1}\x{5AB2}\x{5AB3}\x{5AB4}\x{5AB5}\x{5AB6}\x{5AB7}' . +'\x{5AB8}\x{5AB9}\x{5ABA}\x{5ABB}\x{5ABC}\x{5ABD}\x{5ABE}\x{5ABF}\x{5AC0}' . +'\x{5AC1}\x{5AC2}\x{5AC3}\x{5AC4}\x{5AC5}\x{5AC6}\x{5AC7}\x{5AC8}\x{5AC9}' . +'\x{5ACA}\x{5ACB}\x{5ACC}\x{5ACD}\x{5ACE}\x{5ACF}\x{5AD1}\x{5AD2}\x{5AD4}' . +'\x{5AD5}\x{5AD6}\x{5AD7}\x{5AD8}\x{5AD9}\x{5ADA}\x{5ADB}\x{5ADC}\x{5ADD}' . +'\x{5ADE}\x{5ADF}\x{5AE0}\x{5AE1}\x{5AE2}\x{5AE3}\x{5AE4}\x{5AE5}\x{5AE6}' . +'\x{5AE7}\x{5AE8}\x{5AE9}\x{5AEA}\x{5AEB}\x{5AEC}\x{5AED}\x{5AEE}\x{5AF1}' . +'\x{5AF2}\x{5AF3}\x{5AF4}\x{5AF5}\x{5AF6}\x{5AF7}\x{5AF8}\x{5AF9}\x{5AFA}' . +'\x{5AFB}\x{5AFC}\x{5AFD}\x{5AFE}\x{5AFF}\x{5B00}\x{5B01}\x{5B02}\x{5B03}' . +'\x{5B04}\x{5B05}\x{5B06}\x{5B07}\x{5B08}\x{5B09}\x{5B0B}\x{5B0C}\x{5B0E}' . +'\x{5B0F}\x{5B10}\x{5B11}\x{5B12}\x{5B13}\x{5B14}\x{5B15}\x{5B16}\x{5B17}' . +'\x{5B18}\x{5B19}\x{5B1A}\x{5B1B}\x{5B1C}\x{5B1D}\x{5B1E}\x{5B1F}\x{5B20}' . +'\x{5B21}\x{5B22}\x{5B23}\x{5B24}\x{5B25}\x{5B26}\x{5B27}\x{5B28}\x{5B29}' . +'\x{5B2A}\x{5B2B}\x{5B2C}\x{5B2D}\x{5B2E}\x{5B2F}\x{5B30}\x{5B31}\x{5B32}' . +'\x{5B33}\x{5B34}\x{5B35}\x{5B36}\x{5B37}\x{5B38}\x{5B3A}\x{5B3B}\x{5B3C}' . +'\x{5B3D}\x{5B3E}\x{5B3F}\x{5B40}\x{5B41}\x{5B42}\x{5B43}\x{5B44}\x{5B45}' . +'\x{5B47}\x{5B48}\x{5B49}\x{5B4A}\x{5B4B}\x{5B4C}\x{5B4D}\x{5B4E}\x{5B50}' . +'\x{5B51}\x{5B53}\x{5B54}\x{5B55}\x{5B56}\x{5B57}\x{5B58}\x{5B59}\x{5B5A}' . +'\x{5B5B}\x{5B5C}\x{5B5D}\x{5B5E}\x{5B5F}\x{5B62}\x{5B63}\x{5B64}\x{5B65}' . +'\x{5B66}\x{5B67}\x{5B68}\x{5B69}\x{5B6A}\x{5B6B}\x{5B6C}\x{5B6D}\x{5B6E}' . +'\x{5B70}\x{5B71}\x{5B72}\x{5B73}\x{5B74}\x{5B75}\x{5B76}\x{5B77}\x{5B78}' . +'\x{5B7A}\x{5B7B}\x{5B7C}\x{5B7D}\x{5B7F}\x{5B80}\x{5B81}\x{5B82}\x{5B83}' . +'\x{5B84}\x{5B85}\x{5B87}\x{5B88}\x{5B89}\x{5B8A}\x{5B8B}\x{5B8C}\x{5B8D}' . +'\x{5B8E}\x{5B8F}\x{5B91}\x{5B92}\x{5B93}\x{5B94}\x{5B95}\x{5B96}\x{5B97}' . +'\x{5B98}\x{5B99}\x{5B9A}\x{5B9B}\x{5B9C}\x{5B9D}\x{5B9E}\x{5B9F}\x{5BA0}' . +'\x{5BA1}\x{5BA2}\x{5BA3}\x{5BA4}\x{5BA5}\x{5BA6}\x{5BA7}\x{5BA8}\x{5BAA}' . +'\x{5BAB}\x{5BAC}\x{5BAD}\x{5BAE}\x{5BAF}\x{5BB0}\x{5BB1}\x{5BB3}\x{5BB4}' . +'\x{5BB5}\x{5BB6}\x{5BB8}\x{5BB9}\x{5BBA}\x{5BBB}\x{5BBD}\x{5BBE}\x{5BBF}' . +'\x{5BC0}\x{5BC1}\x{5BC2}\x{5BC3}\x{5BC4}\x{5BC5}\x{5BC6}\x{5BC7}\x{5BCA}' . +'\x{5BCB}\x{5BCC}\x{5BCD}\x{5BCE}\x{5BCF}\x{5BD0}\x{5BD1}\x{5BD2}\x{5BD3}' . +'\x{5BD4}\x{5BD5}\x{5BD6}\x{5BD8}\x{5BD9}\x{5BDB}\x{5BDC}\x{5BDD}\x{5BDE}' . +'\x{5BDF}\x{5BE0}\x{5BE1}\x{5BE2}\x{5BE3}\x{5BE4}\x{5BE5}\x{5BE6}\x{5BE7}' . +'\x{5BE8}\x{5BE9}\x{5BEA}\x{5BEB}\x{5BEC}\x{5BED}\x{5BEE}\x{5BEF}\x{5BF0}' . +'\x{5BF1}\x{5BF2}\x{5BF3}\x{5BF4}\x{5BF5}\x{5BF6}\x{5BF7}\x{5BF8}\x{5BF9}' . +'\x{5BFA}\x{5BFB}\x{5BFC}\x{5BFD}\x{5BFF}\x{5C01}\x{5C03}\x{5C04}\x{5C05}' . +'\x{5C06}\x{5C07}\x{5C08}\x{5C09}\x{5C0A}\x{5C0B}\x{5C0C}\x{5C0D}\x{5C0E}' . +'\x{5C0F}\x{5C10}\x{5C11}\x{5C12}\x{5C13}\x{5C14}\x{5C15}\x{5C16}\x{5C17}' . +'\x{5C18}\x{5C19}\x{5C1A}\x{5C1C}\x{5C1D}\x{5C1E}\x{5C1F}\x{5C20}\x{5C21}' . +'\x{5C22}\x{5C24}\x{5C25}\x{5C27}\x{5C28}\x{5C2A}\x{5C2B}\x{5C2C}\x{5C2D}' . +'\x{5C2E}\x{5C2F}\x{5C30}\x{5C31}\x{5C32}\x{5C33}\x{5C34}\x{5C35}\x{5C37}' . +'\x{5C38}\x{5C39}\x{5C3A}\x{5C3B}\x{5C3C}\x{5C3D}\x{5C3E}\x{5C3F}\x{5C40}' . +'\x{5C41}\x{5C42}\x{5C43}\x{5C44}\x{5C45}\x{5C46}\x{5C47}\x{5C48}\x{5C49}' . +'\x{5C4A}\x{5C4B}\x{5C4C}\x{5C4D}\x{5C4E}\x{5C4F}\x{5C50}\x{5C51}\x{5C52}' . +'\x{5C53}\x{5C54}\x{5C55}\x{5C56}\x{5C57}\x{5C58}\x{5C59}\x{5C5B}\x{5C5C}' . +'\x{5C5D}\x{5C5E}\x{5C5F}\x{5C60}\x{5C61}\x{5C62}\x{5C63}\x{5C64}\x{5C65}' . +'\x{5C66}\x{5C67}\x{5C68}\x{5C69}\x{5C6A}\x{5C6B}\x{5C6C}\x{5C6D}\x{5C6E}' . +'\x{5C6F}\x{5C70}\x{5C71}\x{5C72}\x{5C73}\x{5C74}\x{5C75}\x{5C76}\x{5C77}' . +'\x{5C78}\x{5C79}\x{5C7A}\x{5C7B}\x{5C7C}\x{5C7D}\x{5C7E}\x{5C7F}\x{5C80}' . +'\x{5C81}\x{5C82}\x{5C83}\x{5C84}\x{5C86}\x{5C87}\x{5C88}\x{5C89}\x{5C8A}' . +'\x{5C8B}\x{5C8C}\x{5C8D}\x{5C8E}\x{5C8F}\x{5C90}\x{5C91}\x{5C92}\x{5C93}' . +'\x{5C94}\x{5C95}\x{5C96}\x{5C97}\x{5C98}\x{5C99}\x{5C9A}\x{5C9B}\x{5C9C}' . +'\x{5C9D}\x{5C9E}\x{5C9F}\x{5CA0}\x{5CA1}\x{5CA2}\x{5CA3}\x{5CA4}\x{5CA5}' . +'\x{5CA6}\x{5CA7}\x{5CA8}\x{5CA9}\x{5CAA}\x{5CAB}\x{5CAC}\x{5CAD}\x{5CAE}' . +'\x{5CAF}\x{5CB0}\x{5CB1}\x{5CB2}\x{5CB3}\x{5CB5}\x{5CB6}\x{5CB7}\x{5CB8}' . +'\x{5CBA}\x{5CBB}\x{5CBC}\x{5CBD}\x{5CBE}\x{5CBF}\x{5CC1}\x{5CC2}\x{5CC3}' . +'\x{5CC4}\x{5CC5}\x{5CC6}\x{5CC7}\x{5CC8}\x{5CC9}\x{5CCA}\x{5CCB}\x{5CCC}' . +'\x{5CCD}\x{5CCE}\x{5CCF}\x{5CD0}\x{5CD1}\x{5CD2}\x{5CD3}\x{5CD4}\x{5CD6}' . +'\x{5CD7}\x{5CD8}\x{5CD9}\x{5CDA}\x{5CDB}\x{5CDC}\x{5CDE}\x{5CDF}\x{5CE0}' . +'\x{5CE1}\x{5CE2}\x{5CE3}\x{5CE4}\x{5CE5}\x{5CE6}\x{5CE7}\x{5CE8}\x{5CE9}' . +'\x{5CEA}\x{5CEB}\x{5CEC}\x{5CED}\x{5CEE}\x{5CEF}\x{5CF0}\x{5CF1}\x{5CF2}' . +'\x{5CF3}\x{5CF4}\x{5CF6}\x{5CF7}\x{5CF8}\x{5CF9}\x{5CFA}\x{5CFB}\x{5CFC}' . +'\x{5CFD}\x{5CFE}\x{5CFF}\x{5D00}\x{5D01}\x{5D02}\x{5D03}\x{5D04}\x{5D05}' . +'\x{5D06}\x{5D07}\x{5D08}\x{5D09}\x{5D0A}\x{5D0B}\x{5D0C}\x{5D0D}\x{5D0E}' . +'\x{5D0F}\x{5D10}\x{5D11}\x{5D12}\x{5D13}\x{5D14}\x{5D15}\x{5D16}\x{5D17}' . +'\x{5D18}\x{5D19}\x{5D1A}\x{5D1B}\x{5D1C}\x{5D1D}\x{5D1E}\x{5D1F}\x{5D20}' . +'\x{5D21}\x{5D22}\x{5D23}\x{5D24}\x{5D25}\x{5D26}\x{5D27}\x{5D28}\x{5D29}' . +'\x{5D2A}\x{5D2C}\x{5D2D}\x{5D2E}\x{5D30}\x{5D31}\x{5D32}\x{5D33}\x{5D34}' . +'\x{5D35}\x{5D36}\x{5D37}\x{5D38}\x{5D39}\x{5D3A}\x{5D3C}\x{5D3D}\x{5D3E}' . +'\x{5D3F}\x{5D40}\x{5D41}\x{5D42}\x{5D43}\x{5D44}\x{5D45}\x{5D46}\x{5D47}' . +'\x{5D48}\x{5D49}\x{5D4A}\x{5D4B}\x{5D4C}\x{5D4D}\x{5D4E}\x{5D4F}\x{5D50}' . +'\x{5D51}\x{5D52}\x{5D54}\x{5D55}\x{5D56}\x{5D58}\x{5D59}\x{5D5A}\x{5D5B}' . +'\x{5D5D}\x{5D5E}\x{5D5F}\x{5D61}\x{5D62}\x{5D63}\x{5D64}\x{5D65}\x{5D66}' . +'\x{5D67}\x{5D68}\x{5D69}\x{5D6A}\x{5D6B}\x{5D6C}\x{5D6D}\x{5D6E}\x{5D6F}' . +'\x{5D70}\x{5D71}\x{5D72}\x{5D73}\x{5D74}\x{5D75}\x{5D76}\x{5D77}\x{5D78}' . +'\x{5D79}\x{5D7A}\x{5D7B}\x{5D7C}\x{5D7D}\x{5D7E}\x{5D7F}\x{5D80}\x{5D81}' . +'\x{5D82}\x{5D84}\x{5D85}\x{5D86}\x{5D87}\x{5D88}\x{5D89}\x{5D8A}\x{5D8B}' . +'\x{5D8C}\x{5D8D}\x{5D8E}\x{5D8F}\x{5D90}\x{5D91}\x{5D92}\x{5D93}\x{5D94}' . +'\x{5D95}\x{5D97}\x{5D98}\x{5D99}\x{5D9A}\x{5D9B}\x{5D9C}\x{5D9D}\x{5D9E}' . +'\x{5D9F}\x{5DA0}\x{5DA1}\x{5DA2}\x{5DA5}\x{5DA6}\x{5DA7}\x{5DA8}\x{5DA9}' . +'\x{5DAA}\x{5DAC}\x{5DAD}\x{5DAE}\x{5DAF}\x{5DB0}\x{5DB1}\x{5DB2}\x{5DB4}' . +'\x{5DB5}\x{5DB6}\x{5DB7}\x{5DB8}\x{5DBA}\x{5DBB}\x{5DBC}\x{5DBD}\x{5DBE}' . +'\x{5DBF}\x{5DC0}\x{5DC1}\x{5DC2}\x{5DC3}\x{5DC5}\x{5DC6}\x{5DC7}\x{5DC8}' . +'\x{5DC9}\x{5DCA}\x{5DCB}\x{5DCC}\x{5DCD}\x{5DCE}\x{5DCF}\x{5DD0}\x{5DD1}' . +'\x{5DD2}\x{5DD3}\x{5DD4}\x{5DD5}\x{5DD6}\x{5DD8}\x{5DD9}\x{5DDB}\x{5DDD}' . +'\x{5DDE}\x{5DDF}\x{5DE0}\x{5DE1}\x{5DE2}\x{5DE3}\x{5DE4}\x{5DE5}\x{5DE6}' . +'\x{5DE7}\x{5DE8}\x{5DE9}\x{5DEA}\x{5DEB}\x{5DEC}\x{5DED}\x{5DEE}\x{5DEF}' . +'\x{5DF0}\x{5DF1}\x{5DF2}\x{5DF3}\x{5DF4}\x{5DF5}\x{5DF7}\x{5DF8}\x{5DF9}' . +'\x{5DFA}\x{5DFB}\x{5DFC}\x{5DFD}\x{5DFE}\x{5DFF}\x{5E00}\x{5E01}\x{5E02}' . +'\x{5E03}\x{5E04}\x{5E05}\x{5E06}\x{5E07}\x{5E08}\x{5E09}\x{5E0A}\x{5E0B}' . +'\x{5E0C}\x{5E0D}\x{5E0E}\x{5E0F}\x{5E10}\x{5E11}\x{5E13}\x{5E14}\x{5E15}' . +'\x{5E16}\x{5E17}\x{5E18}\x{5E19}\x{5E1A}\x{5E1B}\x{5E1C}\x{5E1D}\x{5E1E}' . +'\x{5E1F}\x{5E20}\x{5E21}\x{5E22}\x{5E23}\x{5E24}\x{5E25}\x{5E26}\x{5E27}' . +'\x{5E28}\x{5E29}\x{5E2A}\x{5E2B}\x{5E2C}\x{5E2D}\x{5E2E}\x{5E2F}\x{5E30}' . +'\x{5E31}\x{5E32}\x{5E33}\x{5E34}\x{5E35}\x{5E36}\x{5E37}\x{5E38}\x{5E39}' . +'\x{5E3A}\x{5E3B}\x{5E3C}\x{5E3D}\x{5E3E}\x{5E40}\x{5E41}\x{5E42}\x{5E43}' . +'\x{5E44}\x{5E45}\x{5E46}\x{5E47}\x{5E49}\x{5E4A}\x{5E4B}\x{5E4C}\x{5E4D}' . +'\x{5E4E}\x{5E4F}\x{5E50}\x{5E52}\x{5E53}\x{5E54}\x{5E55}\x{5E56}\x{5E57}' . +'\x{5E58}\x{5E59}\x{5E5A}\x{5E5B}\x{5E5C}\x{5E5D}\x{5E5E}\x{5E5F}\x{5E60}' . +'\x{5E61}\x{5E62}\x{5E63}\x{5E64}\x{5E65}\x{5E66}\x{5E67}\x{5E68}\x{5E69}' . +'\x{5E6A}\x{5E6B}\x{5E6C}\x{5E6D}\x{5E6E}\x{5E6F}\x{5E70}\x{5E71}\x{5E72}' . +'\x{5E73}\x{5E74}\x{5E75}\x{5E76}\x{5E77}\x{5E78}\x{5E79}\x{5E7A}\x{5E7B}' . +'\x{5E7C}\x{5E7D}\x{5E7E}\x{5E7F}\x{5E80}\x{5E81}\x{5E82}\x{5E83}\x{5E84}' . +'\x{5E85}\x{5E86}\x{5E87}\x{5E88}\x{5E89}\x{5E8A}\x{5E8B}\x{5E8C}\x{5E8D}' . +'\x{5E8E}\x{5E8F}\x{5E90}\x{5E91}\x{5E93}\x{5E94}\x{5E95}\x{5E96}\x{5E97}' . +'\x{5E98}\x{5E99}\x{5E9A}\x{5E9B}\x{5E9C}\x{5E9D}\x{5E9E}\x{5E9F}\x{5EA0}' . +'\x{5EA1}\x{5EA2}\x{5EA3}\x{5EA4}\x{5EA5}\x{5EA6}\x{5EA7}\x{5EA8}\x{5EA9}' . +'\x{5EAA}\x{5EAB}\x{5EAC}\x{5EAD}\x{5EAE}\x{5EAF}\x{5EB0}\x{5EB1}\x{5EB2}' . +'\x{5EB3}\x{5EB4}\x{5EB5}\x{5EB6}\x{5EB7}\x{5EB8}\x{5EB9}\x{5EBB}\x{5EBC}' . +'\x{5EBD}\x{5EBE}\x{5EBF}\x{5EC1}\x{5EC2}\x{5EC3}\x{5EC4}\x{5EC5}\x{5EC6}' . +'\x{5EC7}\x{5EC8}\x{5EC9}\x{5ECA}\x{5ECB}\x{5ECC}\x{5ECD}\x{5ECE}\x{5ECF}' . +'\x{5ED0}\x{5ED1}\x{5ED2}\x{5ED3}\x{5ED4}\x{5ED5}\x{5ED6}\x{5ED7}\x{5ED8}' . +'\x{5ED9}\x{5EDA}\x{5EDB}\x{5EDC}\x{5EDD}\x{5EDE}\x{5EDF}\x{5EE0}\x{5EE1}' . +'\x{5EE2}\x{5EE3}\x{5EE4}\x{5EE5}\x{5EE6}\x{5EE7}\x{5EE8}\x{5EE9}\x{5EEA}' . +'\x{5EEC}\x{5EED}\x{5EEE}\x{5EEF}\x{5EF0}\x{5EF1}\x{5EF2}\x{5EF3}\x{5EF4}' . +'\x{5EF5}\x{5EF6}\x{5EF7}\x{5EF8}\x{5EFA}\x{5EFB}\x{5EFC}\x{5EFD}\x{5EFE}' . +'\x{5EFF}\x{5F00}\x{5F01}\x{5F02}\x{5F03}\x{5F04}\x{5F05}\x{5F06}\x{5F07}' . +'\x{5F08}\x{5F0A}\x{5F0B}\x{5F0C}\x{5F0D}\x{5F0F}\x{5F11}\x{5F12}\x{5F13}' . +'\x{5F14}\x{5F15}\x{5F16}\x{5F17}\x{5F18}\x{5F19}\x{5F1A}\x{5F1B}\x{5F1C}' . +'\x{5F1D}\x{5F1E}\x{5F1F}\x{5F20}\x{5F21}\x{5F22}\x{5F23}\x{5F24}\x{5F25}' . +'\x{5F26}\x{5F27}\x{5F28}\x{5F29}\x{5F2A}\x{5F2B}\x{5F2C}\x{5F2D}\x{5F2E}' . +'\x{5F2F}\x{5F30}\x{5F31}\x{5F32}\x{5F33}\x{5F34}\x{5F35}\x{5F36}\x{5F37}' . +'\x{5F38}\x{5F39}\x{5F3A}\x{5F3C}\x{5F3E}\x{5F3F}\x{5F40}\x{5F41}\x{5F42}' . +'\x{5F43}\x{5F44}\x{5F45}\x{5F46}\x{5F47}\x{5F48}\x{5F49}\x{5F4A}\x{5F4B}' . +'\x{5F4C}\x{5F4D}\x{5F4E}\x{5F4F}\x{5F50}\x{5F51}\x{5F52}\x{5F53}\x{5F54}' . +'\x{5F55}\x{5F56}\x{5F57}\x{5F58}\x{5F59}\x{5F5A}\x{5F5B}\x{5F5C}\x{5F5D}' . +'\x{5F5E}\x{5F5F}\x{5F60}\x{5F61}\x{5F62}\x{5F63}\x{5F64}\x{5F65}\x{5F66}' . +'\x{5F67}\x{5F68}\x{5F69}\x{5F6A}\x{5F6B}\x{5F6C}\x{5F6D}\x{5F6E}\x{5F6F}' . +'\x{5F70}\x{5F71}\x{5F72}\x{5F73}\x{5F74}\x{5F75}\x{5F76}\x{5F77}\x{5F78}' . +'\x{5F79}\x{5F7A}\x{5F7B}\x{5F7C}\x{5F7D}\x{5F7E}\x{5F7F}\x{5F80}\x{5F81}' . +'\x{5F82}\x{5F83}\x{5F84}\x{5F85}\x{5F86}\x{5F87}\x{5F88}\x{5F89}\x{5F8A}' . +'\x{5F8B}\x{5F8C}\x{5F8D}\x{5F8E}\x{5F90}\x{5F91}\x{5F92}\x{5F93}\x{5F94}' . +'\x{5F95}\x{5F96}\x{5F97}\x{5F98}\x{5F99}\x{5F9B}\x{5F9C}\x{5F9D}\x{5F9E}' . +'\x{5F9F}\x{5FA0}\x{5FA1}\x{5FA2}\x{5FA5}\x{5FA6}\x{5FA7}\x{5FA8}\x{5FA9}' . +'\x{5FAA}\x{5FAB}\x{5FAC}\x{5FAD}\x{5FAE}\x{5FAF}\x{5FB1}\x{5FB2}\x{5FB3}' . +'\x{5FB4}\x{5FB5}\x{5FB6}\x{5FB7}\x{5FB8}\x{5FB9}\x{5FBA}\x{5FBB}\x{5FBC}' . +'\x{5FBD}\x{5FBE}\x{5FBF}\x{5FC0}\x{5FC1}\x{5FC3}\x{5FC4}\x{5FC5}\x{5FC6}' . +'\x{5FC7}\x{5FC8}\x{5FC9}\x{5FCA}\x{5FCB}\x{5FCC}\x{5FCD}\x{5FCF}\x{5FD0}' . +'\x{5FD1}\x{5FD2}\x{5FD3}\x{5FD4}\x{5FD5}\x{5FD6}\x{5FD7}\x{5FD8}\x{5FD9}' . +'\x{5FDA}\x{5FDC}\x{5FDD}\x{5FDE}\x{5FE0}\x{5FE1}\x{5FE3}\x{5FE4}\x{5FE5}' . +'\x{5FE6}\x{5FE7}\x{5FE8}\x{5FE9}\x{5FEA}\x{5FEB}\x{5FED}\x{5FEE}\x{5FEF}' . +'\x{5FF0}\x{5FF1}\x{5FF2}\x{5FF3}\x{5FF4}\x{5FF5}\x{5FF6}\x{5FF7}\x{5FF8}' . +'\x{5FF9}\x{5FFA}\x{5FFB}\x{5FFD}\x{5FFE}\x{5FFF}\x{6000}\x{6001}\x{6002}' . +'\x{6003}\x{6004}\x{6005}\x{6006}\x{6007}\x{6008}\x{6009}\x{600A}\x{600B}' . +'\x{600C}\x{600D}\x{600E}\x{600F}\x{6010}\x{6011}\x{6012}\x{6013}\x{6014}' . +'\x{6015}\x{6016}\x{6017}\x{6018}\x{6019}\x{601A}\x{601B}\x{601C}\x{601D}' . +'\x{601E}\x{601F}\x{6020}\x{6021}\x{6022}\x{6024}\x{6025}\x{6026}\x{6027}' . +'\x{6028}\x{6029}\x{602A}\x{602B}\x{602C}\x{602D}\x{602E}\x{602F}\x{6030}' . +'\x{6031}\x{6032}\x{6033}\x{6034}\x{6035}\x{6036}\x{6037}\x{6038}\x{6039}' . +'\x{603A}\x{603B}\x{603C}\x{603D}\x{603E}\x{603F}\x{6040}\x{6041}\x{6042}' . +'\x{6043}\x{6044}\x{6045}\x{6046}\x{6047}\x{6048}\x{6049}\x{604A}\x{604B}' . +'\x{604C}\x{604D}\x{604E}\x{604F}\x{6050}\x{6051}\x{6052}\x{6053}\x{6054}' . +'\x{6055}\x{6057}\x{6058}\x{6059}\x{605A}\x{605B}\x{605C}\x{605D}\x{605E}' . +'\x{605F}\x{6062}\x{6063}\x{6064}\x{6065}\x{6066}\x{6067}\x{6068}\x{6069}' . +'\x{606A}\x{606B}\x{606C}\x{606D}\x{606E}\x{606F}\x{6070}\x{6072}\x{6073}' . +'\x{6075}\x{6076}\x{6077}\x{6078}\x{6079}\x{607A}\x{607B}\x{607C}\x{607D}' . +'\x{607E}\x{607F}\x{6080}\x{6081}\x{6082}\x{6083}\x{6084}\x{6085}\x{6086}' . +'\x{6087}\x{6088}\x{6089}\x{608A}\x{608B}\x{608C}\x{608D}\x{608E}\x{608F}' . +'\x{6090}\x{6092}\x{6094}\x{6095}\x{6096}\x{6097}\x{6098}\x{6099}\x{609A}' . +'\x{609B}\x{609C}\x{609D}\x{609E}\x{609F}\x{60A0}\x{60A1}\x{60A2}\x{60A3}' . +'\x{60A4}\x{60A6}\x{60A7}\x{60A8}\x{60AA}\x{60AB}\x{60AC}\x{60AD}\x{60AE}' . +'\x{60AF}\x{60B0}\x{60B1}\x{60B2}\x{60B3}\x{60B4}\x{60B5}\x{60B6}\x{60B7}' . +'\x{60B8}\x{60B9}\x{60BA}\x{60BB}\x{60BC}\x{60BD}\x{60BE}\x{60BF}\x{60C0}' . +'\x{60C1}\x{60C2}\x{60C3}\x{60C4}\x{60C5}\x{60C6}\x{60C7}\x{60C8}\x{60C9}' . +'\x{60CA}\x{60CB}\x{60CC}\x{60CD}\x{60CE}\x{60CF}\x{60D0}\x{60D1}\x{60D3}' . +'\x{60D4}\x{60D5}\x{60D7}\x{60D8}\x{60D9}\x{60DA}\x{60DB}\x{60DC}\x{60DD}' . +'\x{60DF}\x{60E0}\x{60E1}\x{60E2}\x{60E4}\x{60E6}\x{60E7}\x{60E8}\x{60E9}' . +'\x{60EA}\x{60EB}\x{60EC}\x{60ED}\x{60EE}\x{60EF}\x{60F0}\x{60F1}\x{60F2}' . +'\x{60F3}\x{60F4}\x{60F5}\x{60F6}\x{60F7}\x{60F8}\x{60F9}\x{60FA}\x{60FB}' . +'\x{60FC}\x{60FE}\x{60FF}\x{6100}\x{6101}\x{6103}\x{6104}\x{6105}\x{6106}' . +'\x{6108}\x{6109}\x{610A}\x{610B}\x{610C}\x{610D}\x{610E}\x{610F}\x{6110}' . +'\x{6112}\x{6113}\x{6114}\x{6115}\x{6116}\x{6117}\x{6118}\x{6119}\x{611A}' . +'\x{611B}\x{611C}\x{611D}\x{611F}\x{6120}\x{6122}\x{6123}\x{6124}\x{6125}' . +'\x{6126}\x{6127}\x{6128}\x{6129}\x{612A}\x{612B}\x{612C}\x{612D}\x{612E}' . +'\x{612F}\x{6130}\x{6132}\x{6134}\x{6136}\x{6137}\x{613A}\x{613B}\x{613C}' . +'\x{613D}\x{613E}\x{613F}\x{6140}\x{6141}\x{6142}\x{6143}\x{6144}\x{6145}' . +'\x{6146}\x{6147}\x{6148}\x{6149}\x{614A}\x{614B}\x{614C}\x{614D}\x{614E}' . +'\x{614F}\x{6150}\x{6151}\x{6152}\x{6153}\x{6154}\x{6155}\x{6156}\x{6157}' . +'\x{6158}\x{6159}\x{615A}\x{615B}\x{615C}\x{615D}\x{615E}\x{615F}\x{6161}' . +'\x{6162}\x{6163}\x{6164}\x{6165}\x{6166}\x{6167}\x{6168}\x{6169}\x{616A}' . +'\x{616B}\x{616C}\x{616D}\x{616E}\x{6170}\x{6171}\x{6172}\x{6173}\x{6174}' . +'\x{6175}\x{6176}\x{6177}\x{6178}\x{6179}\x{617A}\x{617C}\x{617E}\x{6180}' . +'\x{6181}\x{6182}\x{6183}\x{6184}\x{6185}\x{6187}\x{6188}\x{6189}\x{618A}' . +'\x{618B}\x{618C}\x{618D}\x{618E}\x{618F}\x{6190}\x{6191}\x{6192}\x{6193}' . +'\x{6194}\x{6195}\x{6196}\x{6198}\x{6199}\x{619A}\x{619B}\x{619D}\x{619E}' . +'\x{619F}\x{61A0}\x{61A1}\x{61A2}\x{61A3}\x{61A4}\x{61A5}\x{61A6}\x{61A7}' . +'\x{61A8}\x{61A9}\x{61AA}\x{61AB}\x{61AC}\x{61AD}\x{61AE}\x{61AF}\x{61B0}' . +'\x{61B1}\x{61B2}\x{61B3}\x{61B4}\x{61B5}\x{61B6}\x{61B7}\x{61B8}\x{61BA}' . +'\x{61BC}\x{61BD}\x{61BE}\x{61BF}\x{61C0}\x{61C1}\x{61C2}\x{61C3}\x{61C4}' . +'\x{61C5}\x{61C6}\x{61C7}\x{61C8}\x{61C9}\x{61CA}\x{61CB}\x{61CC}\x{61CD}' . +'\x{61CE}\x{61CF}\x{61D0}\x{61D1}\x{61D2}\x{61D4}\x{61D6}\x{61D7}\x{61D8}' . +'\x{61D9}\x{61DA}\x{61DB}\x{61DC}\x{61DD}\x{61DE}\x{61DF}\x{61E0}\x{61E1}' . +'\x{61E2}\x{61E3}\x{61E4}\x{61E5}\x{61E6}\x{61E7}\x{61E8}\x{61E9}\x{61EA}' . +'\x{61EB}\x{61ED}\x{61EE}\x{61F0}\x{61F1}\x{61F2}\x{61F3}\x{61F5}\x{61F6}' . +'\x{61F7}\x{61F8}\x{61F9}\x{61FA}\x{61FB}\x{61FC}\x{61FD}\x{61FE}\x{61FF}' . +'\x{6200}\x{6201}\x{6202}\x{6203}\x{6204}\x{6206}\x{6207}\x{6208}\x{6209}' . +'\x{620A}\x{620B}\x{620C}\x{620D}\x{620E}\x{620F}\x{6210}\x{6211}\x{6212}' . +'\x{6213}\x{6214}\x{6215}\x{6216}\x{6217}\x{6218}\x{6219}\x{621A}\x{621B}' . +'\x{621C}\x{621D}\x{621E}\x{621F}\x{6220}\x{6221}\x{6222}\x{6223}\x{6224}' . +'\x{6225}\x{6226}\x{6227}\x{6228}\x{6229}\x{622A}\x{622B}\x{622C}\x{622D}' . +'\x{622E}\x{622F}\x{6230}\x{6231}\x{6232}\x{6233}\x{6234}\x{6236}\x{6237}' . +'\x{6238}\x{623A}\x{623B}\x{623C}\x{623D}\x{623E}\x{623F}\x{6240}\x{6241}' . +'\x{6242}\x{6243}\x{6244}\x{6245}\x{6246}\x{6247}\x{6248}\x{6249}\x{624A}' . +'\x{624B}\x{624C}\x{624D}\x{624E}\x{624F}\x{6250}\x{6251}\x{6252}\x{6253}' . +'\x{6254}\x{6255}\x{6256}\x{6258}\x{6259}\x{625A}\x{625B}\x{625C}\x{625D}' . +'\x{625E}\x{625F}\x{6260}\x{6261}\x{6262}\x{6263}\x{6264}\x{6265}\x{6266}' . +'\x{6267}\x{6268}\x{6269}\x{626A}\x{626B}\x{626C}\x{626D}\x{626E}\x{626F}' . +'\x{6270}\x{6271}\x{6272}\x{6273}\x{6274}\x{6275}\x{6276}\x{6277}\x{6278}' . +'\x{6279}\x{627A}\x{627B}\x{627C}\x{627D}\x{627E}\x{627F}\x{6280}\x{6281}' . +'\x{6283}\x{6284}\x{6285}\x{6286}\x{6287}\x{6288}\x{6289}\x{628A}\x{628B}' . +'\x{628C}\x{628E}\x{628F}\x{6290}\x{6291}\x{6292}\x{6293}\x{6294}\x{6295}' . +'\x{6296}\x{6297}\x{6298}\x{6299}\x{629A}\x{629B}\x{629C}\x{629E}\x{629F}' . +'\x{62A0}\x{62A1}\x{62A2}\x{62A3}\x{62A4}\x{62A5}\x{62A7}\x{62A8}\x{62A9}' . +'\x{62AA}\x{62AB}\x{62AC}\x{62AD}\x{62AE}\x{62AF}\x{62B0}\x{62B1}\x{62B2}' . +'\x{62B3}\x{62B4}\x{62B5}\x{62B6}\x{62B7}\x{62B8}\x{62B9}\x{62BA}\x{62BB}' . +'\x{62BC}\x{62BD}\x{62BE}\x{62BF}\x{62C0}\x{62C1}\x{62C2}\x{62C3}\x{62C4}' . +'\x{62C5}\x{62C6}\x{62C7}\x{62C8}\x{62C9}\x{62CA}\x{62CB}\x{62CC}\x{62CD}' . +'\x{62CE}\x{62CF}\x{62D0}\x{62D1}\x{62D2}\x{62D3}\x{62D4}\x{62D5}\x{62D6}' . +'\x{62D7}\x{62D8}\x{62D9}\x{62DA}\x{62DB}\x{62DC}\x{62DD}\x{62DF}\x{62E0}' . +'\x{62E1}\x{62E2}\x{62E3}\x{62E4}\x{62E5}\x{62E6}\x{62E7}\x{62E8}\x{62E9}' . +'\x{62EB}\x{62EC}\x{62ED}\x{62EE}\x{62EF}\x{62F0}\x{62F1}\x{62F2}\x{62F3}' . +'\x{62F4}\x{62F5}\x{62F6}\x{62F7}\x{62F8}\x{62F9}\x{62FA}\x{62FB}\x{62FC}' . +'\x{62FD}\x{62FE}\x{62FF}\x{6300}\x{6301}\x{6302}\x{6303}\x{6304}\x{6305}' . +'\x{6306}\x{6307}\x{6308}\x{6309}\x{630B}\x{630C}\x{630D}\x{630E}\x{630F}' . +'\x{6310}\x{6311}\x{6312}\x{6313}\x{6314}\x{6315}\x{6316}\x{6318}\x{6319}' . +'\x{631A}\x{631B}\x{631C}\x{631D}\x{631E}\x{631F}\x{6320}\x{6321}\x{6322}' . +'\x{6323}\x{6324}\x{6325}\x{6326}\x{6327}\x{6328}\x{6329}\x{632A}\x{632B}' . +'\x{632C}\x{632D}\x{632E}\x{632F}\x{6330}\x{6332}\x{6333}\x{6334}\x{6336}' . +'\x{6338}\x{6339}\x{633A}\x{633B}\x{633C}\x{633D}\x{633E}\x{6340}\x{6341}' . +'\x{6342}\x{6343}\x{6344}\x{6345}\x{6346}\x{6347}\x{6348}\x{6349}\x{634A}' . +'\x{634B}\x{634C}\x{634D}\x{634E}\x{634F}\x{6350}\x{6351}\x{6352}\x{6353}' . +'\x{6354}\x{6355}\x{6356}\x{6357}\x{6358}\x{6359}\x{635A}\x{635C}\x{635D}' . +'\x{635E}\x{635F}\x{6360}\x{6361}\x{6362}\x{6363}\x{6364}\x{6365}\x{6366}' . +'\x{6367}\x{6368}\x{6369}\x{636A}\x{636B}\x{636C}\x{636D}\x{636E}\x{636F}' . +'\x{6370}\x{6371}\x{6372}\x{6373}\x{6374}\x{6375}\x{6376}\x{6377}\x{6378}' . +'\x{6379}\x{637A}\x{637B}\x{637C}\x{637D}\x{637E}\x{6380}\x{6381}\x{6382}' . +'\x{6383}\x{6384}\x{6385}\x{6386}\x{6387}\x{6388}\x{6389}\x{638A}\x{638C}' . +'\x{638D}\x{638E}\x{638F}\x{6390}\x{6391}\x{6392}\x{6394}\x{6395}\x{6396}' . +'\x{6397}\x{6398}\x{6399}\x{639A}\x{639B}\x{639C}\x{639D}\x{639E}\x{639F}' . +'\x{63A0}\x{63A1}\x{63A2}\x{63A3}\x{63A4}\x{63A5}\x{63A6}\x{63A7}\x{63A8}' . +'\x{63A9}\x{63AA}\x{63AB}\x{63AC}\x{63AD}\x{63AE}\x{63AF}\x{63B0}\x{63B1}' . +'\x{63B2}\x{63B3}\x{63B4}\x{63B5}\x{63B6}\x{63B7}\x{63B8}\x{63B9}\x{63BA}' . +'\x{63BC}\x{63BD}\x{63BE}\x{63BF}\x{63C0}\x{63C1}\x{63C2}\x{63C3}\x{63C4}' . +'\x{63C5}\x{63C6}\x{63C7}\x{63C8}\x{63C9}\x{63CA}\x{63CB}\x{63CC}\x{63CD}' . +'\x{63CE}\x{63CF}\x{63D0}\x{63D2}\x{63D3}\x{63D4}\x{63D5}\x{63D6}\x{63D7}' . +'\x{63D8}\x{63D9}\x{63DA}\x{63DB}\x{63DC}\x{63DD}\x{63DE}\x{63DF}\x{63E0}' . +'\x{63E1}\x{63E2}\x{63E3}\x{63E4}\x{63E5}\x{63E6}\x{63E7}\x{63E8}\x{63E9}' . +'\x{63EA}\x{63EB}\x{63EC}\x{63ED}\x{63EE}\x{63EF}\x{63F0}\x{63F1}\x{63F2}' . +'\x{63F3}\x{63F4}\x{63F5}\x{63F6}\x{63F7}\x{63F8}\x{63F9}\x{63FA}\x{63FB}' . +'\x{63FC}\x{63FD}\x{63FE}\x{63FF}\x{6400}\x{6401}\x{6402}\x{6403}\x{6404}' . +'\x{6405}\x{6406}\x{6408}\x{6409}\x{640A}\x{640B}\x{640C}\x{640D}\x{640E}' . +'\x{640F}\x{6410}\x{6411}\x{6412}\x{6413}\x{6414}\x{6415}\x{6416}\x{6417}' . +'\x{6418}\x{6419}\x{641A}\x{641B}\x{641C}\x{641D}\x{641E}\x{641F}\x{6420}' . +'\x{6421}\x{6422}\x{6423}\x{6424}\x{6425}\x{6426}\x{6427}\x{6428}\x{6429}' . +'\x{642A}\x{642B}\x{642C}\x{642D}\x{642E}\x{642F}\x{6430}\x{6431}\x{6432}' . +'\x{6433}\x{6434}\x{6435}\x{6436}\x{6437}\x{6438}\x{6439}\x{643A}\x{643D}' . +'\x{643E}\x{643F}\x{6440}\x{6441}\x{6443}\x{6444}\x{6445}\x{6446}\x{6447}' . +'\x{6448}\x{644A}\x{644B}\x{644C}\x{644D}\x{644E}\x{644F}\x{6450}\x{6451}' . +'\x{6452}\x{6453}\x{6454}\x{6455}\x{6456}\x{6457}\x{6458}\x{6459}\x{645B}' . +'\x{645C}\x{645D}\x{645E}\x{645F}\x{6460}\x{6461}\x{6462}\x{6463}\x{6464}' . +'\x{6465}\x{6466}\x{6467}\x{6468}\x{6469}\x{646A}\x{646B}\x{646C}\x{646D}' . +'\x{646E}\x{646F}\x{6470}\x{6471}\x{6472}\x{6473}\x{6474}\x{6475}\x{6476}' . +'\x{6477}\x{6478}\x{6479}\x{647A}\x{647B}\x{647C}\x{647D}\x{647F}\x{6480}' . +'\x{6481}\x{6482}\x{6483}\x{6484}\x{6485}\x{6487}\x{6488}\x{6489}\x{648A}' . +'\x{648B}\x{648C}\x{648D}\x{648E}\x{648F}\x{6490}\x{6491}\x{6492}\x{6493}' . +'\x{6494}\x{6495}\x{6496}\x{6497}\x{6498}\x{6499}\x{649A}\x{649B}\x{649C}' . +'\x{649D}\x{649E}\x{649F}\x{64A0}\x{64A2}\x{64A3}\x{64A4}\x{64A5}\x{64A6}' . +'\x{64A7}\x{64A8}\x{64A9}\x{64AA}\x{64AB}\x{64AC}\x{64AD}\x{64AE}\x{64B0}' . +'\x{64B1}\x{64B2}\x{64B3}\x{64B4}\x{64B5}\x{64B7}\x{64B8}\x{64B9}\x{64BA}' . +'\x{64BB}\x{64BC}\x{64BD}\x{64BE}\x{64BF}\x{64C0}\x{64C1}\x{64C2}\x{64C3}' . +'\x{64C4}\x{64C5}\x{64C6}\x{64C7}\x{64C9}\x{64CA}\x{64CB}\x{64CC}\x{64CD}' . +'\x{64CE}\x{64CF}\x{64D0}\x{64D1}\x{64D2}\x{64D3}\x{64D4}\x{64D6}\x{64D7}' . +'\x{64D8}\x{64D9}\x{64DA}\x{64DB}\x{64DC}\x{64DD}\x{64DE}\x{64DF}\x{64E0}' . +'\x{64E2}\x{64E3}\x{64E4}\x{64E6}\x{64E7}\x{64E8}\x{64E9}\x{64EA}\x{64EB}' . +'\x{64EC}\x{64ED}\x{64EF}\x{64F0}\x{64F1}\x{64F2}\x{64F3}\x{64F4}\x{64F6}' . +'\x{64F7}\x{64F8}\x{64FA}\x{64FB}\x{64FC}\x{64FD}\x{64FE}\x{64FF}\x{6500}' . +'\x{6501}\x{6503}\x{6504}\x{6505}\x{6506}\x{6507}\x{6508}\x{6509}\x{650B}' . +'\x{650C}\x{650D}\x{650E}\x{650F}\x{6510}\x{6511}\x{6512}\x{6513}\x{6514}' . +'\x{6515}\x{6516}\x{6517}\x{6518}\x{6519}\x{651A}\x{651B}\x{651C}\x{651D}' . +'\x{651E}\x{6520}\x{6521}\x{6522}\x{6523}\x{6524}\x{6525}\x{6526}\x{6527}' . +'\x{6529}\x{652A}\x{652B}\x{652C}\x{652D}\x{652E}\x{652F}\x{6530}\x{6531}' . +'\x{6532}\x{6533}\x{6534}\x{6535}\x{6536}\x{6537}\x{6538}\x{6539}\x{653A}' . +'\x{653B}\x{653C}\x{653D}\x{653E}\x{653F}\x{6541}\x{6543}\x{6544}\x{6545}' . +'\x{6546}\x{6547}\x{6548}\x{6549}\x{654A}\x{654B}\x{654C}\x{654D}\x{654E}' . +'\x{654F}\x{6550}\x{6551}\x{6552}\x{6553}\x{6554}\x{6555}\x{6556}\x{6557}' . +'\x{6558}\x{6559}\x{655B}\x{655C}\x{655D}\x{655E}\x{6560}\x{6561}\x{6562}' . +'\x{6563}\x{6564}\x{6565}\x{6566}\x{6567}\x{6568}\x{6569}\x{656A}\x{656B}' . +'\x{656C}\x{656E}\x{656F}\x{6570}\x{6571}\x{6572}\x{6573}\x{6574}\x{6575}' . +'\x{6576}\x{6577}\x{6578}\x{6579}\x{657A}\x{657B}\x{657C}\x{657E}\x{657F}' . +'\x{6580}\x{6581}\x{6582}\x{6583}\x{6584}\x{6585}\x{6586}\x{6587}\x{6588}' . +'\x{6589}\x{658B}\x{658C}\x{658D}\x{658E}\x{658F}\x{6590}\x{6591}\x{6592}' . +'\x{6593}\x{6594}\x{6595}\x{6596}\x{6597}\x{6598}\x{6599}\x{659B}\x{659C}' . +'\x{659D}\x{659E}\x{659F}\x{65A0}\x{65A1}\x{65A2}\x{65A3}\x{65A4}\x{65A5}' . +'\x{65A6}\x{65A7}\x{65A8}\x{65A9}\x{65AA}\x{65AB}\x{65AC}\x{65AD}\x{65AE}' . +'\x{65AF}\x{65B0}\x{65B1}\x{65B2}\x{65B3}\x{65B4}\x{65B6}\x{65B7}\x{65B8}' . +'\x{65B9}\x{65BA}\x{65BB}\x{65BC}\x{65BD}\x{65BF}\x{65C0}\x{65C1}\x{65C2}' . +'\x{65C3}\x{65C4}\x{65C5}\x{65C6}\x{65C7}\x{65CA}\x{65CB}\x{65CC}\x{65CD}' . +'\x{65CE}\x{65CF}\x{65D0}\x{65D2}\x{65D3}\x{65D4}\x{65D5}\x{65D6}\x{65D7}' . +'\x{65DA}\x{65DB}\x{65DD}\x{65DE}\x{65DF}\x{65E0}\x{65E1}\x{65E2}\x{65E3}' . +'\x{65E5}\x{65E6}\x{65E7}\x{65E8}\x{65E9}\x{65EB}\x{65EC}\x{65ED}\x{65EE}' . +'\x{65EF}\x{65F0}\x{65F1}\x{65F2}\x{65F3}\x{65F4}\x{65F5}\x{65F6}\x{65F7}' . +'\x{65F8}\x{65FA}\x{65FB}\x{65FC}\x{65FD}\x{6600}\x{6601}\x{6602}\x{6603}' . +'\x{6604}\x{6605}\x{6606}\x{6607}\x{6608}\x{6609}\x{660A}\x{660B}\x{660C}' . +'\x{660D}\x{660E}\x{660F}\x{6610}\x{6611}\x{6612}\x{6613}\x{6614}\x{6615}' . +'\x{6616}\x{6618}\x{6619}\x{661A}\x{661B}\x{661C}\x{661D}\x{661F}\x{6620}' . +'\x{6621}\x{6622}\x{6623}\x{6624}\x{6625}\x{6626}\x{6627}\x{6628}\x{6629}' . +'\x{662A}\x{662B}\x{662D}\x{662E}\x{662F}\x{6630}\x{6631}\x{6632}\x{6633}' . +'\x{6634}\x{6635}\x{6636}\x{6639}\x{663A}\x{663C}\x{663D}\x{663E}\x{6640}' . +'\x{6641}\x{6642}\x{6643}\x{6644}\x{6645}\x{6646}\x{6647}\x{6649}\x{664A}' . +'\x{664B}\x{664C}\x{664E}\x{664F}\x{6650}\x{6651}\x{6652}\x{6653}\x{6654}' . +'\x{6655}\x{6656}\x{6657}\x{6658}\x{6659}\x{665A}\x{665B}\x{665C}\x{665D}' . +'\x{665E}\x{665F}\x{6661}\x{6662}\x{6664}\x{6665}\x{6666}\x{6668}\x{6669}' . +'\x{666A}\x{666B}\x{666C}\x{666D}\x{666E}\x{666F}\x{6670}\x{6671}\x{6672}' . +'\x{6673}\x{6674}\x{6675}\x{6676}\x{6677}\x{6678}\x{6679}\x{667A}\x{667B}' . +'\x{667C}\x{667D}\x{667E}\x{667F}\x{6680}\x{6681}\x{6682}\x{6683}\x{6684}' . +'\x{6685}\x{6686}\x{6687}\x{6688}\x{6689}\x{668A}\x{668B}\x{668C}\x{668D}' . +'\x{668E}\x{668F}\x{6690}\x{6691}\x{6693}\x{6694}\x{6695}\x{6696}\x{6697}' . +'\x{6698}\x{6699}\x{669A}\x{669B}\x{669D}\x{669F}\x{66A0}\x{66A1}\x{66A2}' . +'\x{66A3}\x{66A4}\x{66A5}\x{66A6}\x{66A7}\x{66A8}\x{66A9}\x{66AA}\x{66AB}' . +'\x{66AE}\x{66AF}\x{66B0}\x{66B1}\x{66B2}\x{66B3}\x{66B4}\x{66B5}\x{66B6}' . +'\x{66B7}\x{66B8}\x{66B9}\x{66BA}\x{66BB}\x{66BC}\x{66BD}\x{66BE}\x{66BF}' . +'\x{66C0}\x{66C1}\x{66C2}\x{66C3}\x{66C4}\x{66C5}\x{66C6}\x{66C7}\x{66C8}' . +'\x{66C9}\x{66CA}\x{66CB}\x{66CC}\x{66CD}\x{66CE}\x{66CF}\x{66D1}\x{66D2}' . +'\x{66D4}\x{66D5}\x{66D6}\x{66D8}\x{66D9}\x{66DA}\x{66DB}\x{66DC}\x{66DD}' . +'\x{66DE}\x{66E0}\x{66E1}\x{66E2}\x{66E3}\x{66E4}\x{66E5}\x{66E6}\x{66E7}' . +'\x{66E8}\x{66E9}\x{66EA}\x{66EB}\x{66EC}\x{66ED}\x{66EE}\x{66F0}\x{66F1}' . +'\x{66F2}\x{66F3}\x{66F4}\x{66F5}\x{66F6}\x{66F7}\x{66F8}\x{66F9}\x{66FA}' . +'\x{66FB}\x{66FC}\x{66FE}\x{66FF}\x{6700}\x{6701}\x{6703}\x{6704}\x{6705}' . +'\x{6706}\x{6708}\x{6709}\x{670A}\x{670B}\x{670C}\x{670D}\x{670E}\x{670F}' . +'\x{6710}\x{6711}\x{6712}\x{6713}\x{6714}\x{6715}\x{6716}\x{6717}\x{6718}' . +'\x{671A}\x{671B}\x{671C}\x{671D}\x{671E}\x{671F}\x{6720}\x{6721}\x{6722}' . +'\x{6723}\x{6725}\x{6726}\x{6727}\x{6728}\x{672A}\x{672B}\x{672C}\x{672D}' . +'\x{672E}\x{672F}\x{6730}\x{6731}\x{6732}\x{6733}\x{6734}\x{6735}\x{6736}' . +'\x{6737}\x{6738}\x{6739}\x{673A}\x{673B}\x{673C}\x{673D}\x{673E}\x{673F}' . +'\x{6740}\x{6741}\x{6742}\x{6743}\x{6744}\x{6745}\x{6746}\x{6747}\x{6748}' . +'\x{6749}\x{674A}\x{674B}\x{674C}\x{674D}\x{674E}\x{674F}\x{6750}\x{6751}' . +'\x{6752}\x{6753}\x{6754}\x{6755}\x{6756}\x{6757}\x{6758}\x{6759}\x{675A}' . +'\x{675B}\x{675C}\x{675D}\x{675E}\x{675F}\x{6760}\x{6761}\x{6762}\x{6763}' . +'\x{6764}\x{6765}\x{6766}\x{6768}\x{6769}\x{676A}\x{676B}\x{676C}\x{676D}' . +'\x{676E}\x{676F}\x{6770}\x{6771}\x{6772}\x{6773}\x{6774}\x{6775}\x{6776}' . +'\x{6777}\x{6778}\x{6779}\x{677A}\x{677B}\x{677C}\x{677D}\x{677E}\x{677F}' . +'\x{6780}\x{6781}\x{6782}\x{6783}\x{6784}\x{6785}\x{6786}\x{6787}\x{6789}' . +'\x{678A}\x{678B}\x{678C}\x{678D}\x{678E}\x{678F}\x{6790}\x{6791}\x{6792}' . +'\x{6793}\x{6794}\x{6795}\x{6797}\x{6798}\x{6799}\x{679A}\x{679B}\x{679C}' . +'\x{679D}\x{679E}\x{679F}\x{67A0}\x{67A1}\x{67A2}\x{67A3}\x{67A4}\x{67A5}' . +'\x{67A6}\x{67A7}\x{67A8}\x{67AA}\x{67AB}\x{67AC}\x{67AD}\x{67AE}\x{67AF}' . +'\x{67B0}\x{67B1}\x{67B2}\x{67B3}\x{67B4}\x{67B5}\x{67B6}\x{67B7}\x{67B8}' . +'\x{67B9}\x{67BA}\x{67BB}\x{67BC}\x{67BE}\x{67C0}\x{67C1}\x{67C2}\x{67C3}' . +'\x{67C4}\x{67C5}\x{67C6}\x{67C7}\x{67C8}\x{67C9}\x{67CA}\x{67CB}\x{67CC}' . +'\x{67CD}\x{67CE}\x{67CF}\x{67D0}\x{67D1}\x{67D2}\x{67D3}\x{67D4}\x{67D6}' . +'\x{67D8}\x{67D9}\x{67DA}\x{67DB}\x{67DC}\x{67DD}\x{67DE}\x{67DF}\x{67E0}' . +'\x{67E1}\x{67E2}\x{67E3}\x{67E4}\x{67E5}\x{67E6}\x{67E7}\x{67E8}\x{67E9}' . +'\x{67EA}\x{67EB}\x{67EC}\x{67ED}\x{67EE}\x{67EF}\x{67F0}\x{67F1}\x{67F2}' . +'\x{67F3}\x{67F4}\x{67F5}\x{67F6}\x{67F7}\x{67F8}\x{67FA}\x{67FB}\x{67FC}' . +'\x{67FD}\x{67FE}\x{67FF}\x{6800}\x{6802}\x{6803}\x{6804}\x{6805}\x{6806}' . +'\x{6807}\x{6808}\x{6809}\x{680A}\x{680B}\x{680C}\x{680D}\x{680E}\x{680F}' . +'\x{6810}\x{6811}\x{6812}\x{6813}\x{6814}\x{6816}\x{6817}\x{6818}\x{6819}' . +'\x{681A}\x{681B}\x{681C}\x{681D}\x{681F}\x{6820}\x{6821}\x{6822}\x{6823}' . +'\x{6824}\x{6825}\x{6826}\x{6828}\x{6829}\x{682A}\x{682B}\x{682C}\x{682D}' . +'\x{682E}\x{682F}\x{6831}\x{6832}\x{6833}\x{6834}\x{6835}\x{6836}\x{6837}' . +'\x{6838}\x{6839}\x{683A}\x{683B}\x{683C}\x{683D}\x{683E}\x{683F}\x{6840}' . +'\x{6841}\x{6842}\x{6843}\x{6844}\x{6845}\x{6846}\x{6847}\x{6848}\x{6849}' . +'\x{684A}\x{684B}\x{684C}\x{684D}\x{684E}\x{684F}\x{6850}\x{6851}\x{6852}' . +'\x{6853}\x{6854}\x{6855}\x{6856}\x{6857}\x{685B}\x{685D}\x{6860}\x{6861}' . +'\x{6862}\x{6863}\x{6864}\x{6865}\x{6866}\x{6867}\x{6868}\x{6869}\x{686A}' . +'\x{686B}\x{686C}\x{686D}\x{686E}\x{686F}\x{6870}\x{6871}\x{6872}\x{6873}' . +'\x{6874}\x{6875}\x{6876}\x{6877}\x{6878}\x{6879}\x{687B}\x{687C}\x{687D}' . +'\x{687E}\x{687F}\x{6880}\x{6881}\x{6882}\x{6883}\x{6884}\x{6885}\x{6886}' . +'\x{6887}\x{6888}\x{6889}\x{688A}\x{688B}\x{688C}\x{688D}\x{688E}\x{688F}' . +'\x{6890}\x{6891}\x{6892}\x{6893}\x{6894}\x{6896}\x{6897}\x{6898}\x{689A}' . +'\x{689B}\x{689C}\x{689D}\x{689E}\x{689F}\x{68A0}\x{68A1}\x{68A2}\x{68A3}' . +'\x{68A4}\x{68A6}\x{68A7}\x{68A8}\x{68A9}\x{68AA}\x{68AB}\x{68AC}\x{68AD}' . +'\x{68AE}\x{68AF}\x{68B0}\x{68B1}\x{68B2}\x{68B3}\x{68B4}\x{68B5}\x{68B6}' . +'\x{68B7}\x{68B9}\x{68BB}\x{68BC}\x{68BD}\x{68BE}\x{68BF}\x{68C0}\x{68C1}' . +'\x{68C2}\x{68C4}\x{68C6}\x{68C7}\x{68C8}\x{68C9}\x{68CA}\x{68CB}\x{68CC}' . +'\x{68CD}\x{68CE}\x{68CF}\x{68D0}\x{68D1}\x{68D2}\x{68D3}\x{68D4}\x{68D5}' . +'\x{68D6}\x{68D7}\x{68D8}\x{68DA}\x{68DB}\x{68DC}\x{68DD}\x{68DE}\x{68DF}' . +'\x{68E0}\x{68E1}\x{68E3}\x{68E4}\x{68E6}\x{68E7}\x{68E8}\x{68E9}\x{68EA}' . +'\x{68EB}\x{68EC}\x{68ED}\x{68EE}\x{68EF}\x{68F0}\x{68F1}\x{68F2}\x{68F3}' . +'\x{68F4}\x{68F5}\x{68F6}\x{68F7}\x{68F8}\x{68F9}\x{68FA}\x{68FB}\x{68FC}' . +'\x{68FD}\x{68FE}\x{68FF}\x{6901}\x{6902}\x{6903}\x{6904}\x{6905}\x{6906}' . +'\x{6907}\x{6908}\x{690A}\x{690B}\x{690C}\x{690D}\x{690E}\x{690F}\x{6910}' . +'\x{6911}\x{6912}\x{6913}\x{6914}\x{6915}\x{6916}\x{6917}\x{6918}\x{6919}' . +'\x{691A}\x{691B}\x{691C}\x{691D}\x{691E}\x{691F}\x{6920}\x{6921}\x{6922}' . +'\x{6923}\x{6924}\x{6925}\x{6926}\x{6927}\x{6928}\x{6929}\x{692A}\x{692B}' . +'\x{692C}\x{692D}\x{692E}\x{692F}\x{6930}\x{6931}\x{6932}\x{6933}\x{6934}' . +'\x{6935}\x{6936}\x{6937}\x{6938}\x{6939}\x{693A}\x{693B}\x{693C}\x{693D}' . +'\x{693F}\x{6940}\x{6941}\x{6942}\x{6943}\x{6944}\x{6945}\x{6946}\x{6947}' . +'\x{6948}\x{6949}\x{694A}\x{694B}\x{694C}\x{694E}\x{694F}\x{6950}\x{6951}' . +'\x{6952}\x{6953}\x{6954}\x{6955}\x{6956}\x{6957}\x{6958}\x{6959}\x{695A}' . +'\x{695B}\x{695C}\x{695D}\x{695E}\x{695F}\x{6960}\x{6961}\x{6962}\x{6963}' . +'\x{6964}\x{6965}\x{6966}\x{6967}\x{6968}\x{6969}\x{696A}\x{696B}\x{696C}' . +'\x{696D}\x{696E}\x{696F}\x{6970}\x{6971}\x{6972}\x{6973}\x{6974}\x{6975}' . +'\x{6976}\x{6977}\x{6978}\x{6979}\x{697A}\x{697B}\x{697C}\x{697D}\x{697E}' . +'\x{697F}\x{6980}\x{6981}\x{6982}\x{6983}\x{6984}\x{6985}\x{6986}\x{6987}' . +'\x{6988}\x{6989}\x{698A}\x{698B}\x{698C}\x{698D}\x{698E}\x{698F}\x{6990}' . +'\x{6991}\x{6992}\x{6993}\x{6994}\x{6995}\x{6996}\x{6997}\x{6998}\x{6999}' . +'\x{699A}\x{699B}\x{699C}\x{699D}\x{699E}\x{69A0}\x{69A1}\x{69A3}\x{69A4}' . +'\x{69A5}\x{69A6}\x{69A7}\x{69A8}\x{69A9}\x{69AA}\x{69AB}\x{69AC}\x{69AD}' . +'\x{69AE}\x{69AF}\x{69B0}\x{69B1}\x{69B2}\x{69B3}\x{69B4}\x{69B5}\x{69B6}' . +'\x{69B7}\x{69B8}\x{69B9}\x{69BA}\x{69BB}\x{69BC}\x{69BD}\x{69BE}\x{69BF}' . +'\x{69C1}\x{69C2}\x{69C3}\x{69C4}\x{69C5}\x{69C6}\x{69C7}\x{69C8}\x{69C9}' . +'\x{69CA}\x{69CB}\x{69CC}\x{69CD}\x{69CE}\x{69CF}\x{69D0}\x{69D3}\x{69D4}' . +'\x{69D8}\x{69D9}\x{69DA}\x{69DB}\x{69DC}\x{69DD}\x{69DE}\x{69DF}\x{69E0}' . +'\x{69E1}\x{69E2}\x{69E3}\x{69E4}\x{69E5}\x{69E6}\x{69E7}\x{69E8}\x{69E9}' . +'\x{69EA}\x{69EB}\x{69EC}\x{69ED}\x{69EE}\x{69EF}\x{69F0}\x{69F1}\x{69F2}' . +'\x{69F3}\x{69F4}\x{69F5}\x{69F6}\x{69F7}\x{69F8}\x{69FA}\x{69FB}\x{69FC}' . +'\x{69FD}\x{69FE}\x{69FF}\x{6A00}\x{6A01}\x{6A02}\x{6A04}\x{6A05}\x{6A06}' . +'\x{6A07}\x{6A08}\x{6A09}\x{6A0A}\x{6A0B}\x{6A0D}\x{6A0E}\x{6A0F}\x{6A10}' . +'\x{6A11}\x{6A12}\x{6A13}\x{6A14}\x{6A15}\x{6A16}\x{6A17}\x{6A18}\x{6A19}' . +'\x{6A1A}\x{6A1B}\x{6A1D}\x{6A1E}\x{6A1F}\x{6A20}\x{6A21}\x{6A22}\x{6A23}' . +'\x{6A25}\x{6A26}\x{6A27}\x{6A28}\x{6A29}\x{6A2A}\x{6A2B}\x{6A2C}\x{6A2D}' . +'\x{6A2E}\x{6A2F}\x{6A30}\x{6A31}\x{6A32}\x{6A33}\x{6A34}\x{6A35}\x{6A36}' . +'\x{6A38}\x{6A39}\x{6A3A}\x{6A3B}\x{6A3C}\x{6A3D}\x{6A3E}\x{6A3F}\x{6A40}' . +'\x{6A41}\x{6A42}\x{6A43}\x{6A44}\x{6A45}\x{6A46}\x{6A47}\x{6A48}\x{6A49}' . +'\x{6A4B}\x{6A4C}\x{6A4D}\x{6A4E}\x{6A4F}\x{6A50}\x{6A51}\x{6A52}\x{6A54}' . +'\x{6A55}\x{6A56}\x{6A57}\x{6A58}\x{6A59}\x{6A5A}\x{6A5B}\x{6A5D}\x{6A5E}' . +'\x{6A5F}\x{6A60}\x{6A61}\x{6A62}\x{6A63}\x{6A64}\x{6A65}\x{6A66}\x{6A67}' . +'\x{6A68}\x{6A69}\x{6A6A}\x{6A6B}\x{6A6C}\x{6A6D}\x{6A6F}\x{6A71}\x{6A72}' . +'\x{6A73}\x{6A74}\x{6A75}\x{6A76}\x{6A77}\x{6A78}\x{6A79}\x{6A7A}\x{6A7B}' . +'\x{6A7C}\x{6A7D}\x{6A7E}\x{6A7F}\x{6A80}\x{6A81}\x{6A82}\x{6A83}\x{6A84}' . +'\x{6A85}\x{6A87}\x{6A88}\x{6A89}\x{6A8B}\x{6A8C}\x{6A8D}\x{6A8E}\x{6A90}' . +'\x{6A91}\x{6A92}\x{6A93}\x{6A94}\x{6A95}\x{6A96}\x{6A97}\x{6A98}\x{6A9A}' . +'\x{6A9B}\x{6A9C}\x{6A9E}\x{6A9F}\x{6AA0}\x{6AA1}\x{6AA2}\x{6AA3}\x{6AA4}' . +'\x{6AA5}\x{6AA6}\x{6AA7}\x{6AA8}\x{6AA9}\x{6AAB}\x{6AAC}\x{6AAD}\x{6AAE}' . +'\x{6AAF}\x{6AB0}\x{6AB2}\x{6AB3}\x{6AB4}\x{6AB5}\x{6AB6}\x{6AB7}\x{6AB8}' . +'\x{6AB9}\x{6ABA}\x{6ABB}\x{6ABC}\x{6ABD}\x{6ABF}\x{6AC1}\x{6AC2}\x{6AC3}' . +'\x{6AC5}\x{6AC6}\x{6AC7}\x{6ACA}\x{6ACB}\x{6ACC}\x{6ACD}\x{6ACE}\x{6ACF}' . +'\x{6AD0}\x{6AD1}\x{6AD2}\x{6AD3}\x{6AD4}\x{6AD5}\x{6AD6}\x{6AD7}\x{6AD9}' . +'\x{6ADA}\x{6ADB}\x{6ADC}\x{6ADD}\x{6ADE}\x{6ADF}\x{6AE0}\x{6AE1}\x{6AE2}' . +'\x{6AE3}\x{6AE4}\x{6AE5}\x{6AE6}\x{6AE7}\x{6AE8}\x{6AEA}\x{6AEB}\x{6AEC}' . +'\x{6AED}\x{6AEE}\x{6AEF}\x{6AF0}\x{6AF1}\x{6AF2}\x{6AF3}\x{6AF4}\x{6AF5}' . +'\x{6AF6}\x{6AF7}\x{6AF8}\x{6AF9}\x{6AFA}\x{6AFB}\x{6AFC}\x{6AFD}\x{6AFE}' . +'\x{6AFF}\x{6B00}\x{6B01}\x{6B02}\x{6B03}\x{6B04}\x{6B05}\x{6B06}\x{6B07}' . +'\x{6B08}\x{6B09}\x{6B0A}\x{6B0B}\x{6B0C}\x{6B0D}\x{6B0F}\x{6B10}\x{6B11}' . +'\x{6B12}\x{6B13}\x{6B14}\x{6B15}\x{6B16}\x{6B17}\x{6B18}\x{6B19}\x{6B1A}' . +'\x{6B1C}\x{6B1D}\x{6B1E}\x{6B1F}\x{6B20}\x{6B21}\x{6B22}\x{6B23}\x{6B24}' . +'\x{6B25}\x{6B26}\x{6B27}\x{6B28}\x{6B29}\x{6B2A}\x{6B2B}\x{6B2C}\x{6B2D}' . +'\x{6B2F}\x{6B30}\x{6B31}\x{6B32}\x{6B33}\x{6B34}\x{6B36}\x{6B37}\x{6B38}' . +'\x{6B39}\x{6B3A}\x{6B3B}\x{6B3C}\x{6B3D}\x{6B3E}\x{6B3F}\x{6B41}\x{6B42}' . +'\x{6B43}\x{6B44}\x{6B45}\x{6B46}\x{6B47}\x{6B48}\x{6B49}\x{6B4A}\x{6B4B}' . +'\x{6B4C}\x{6B4D}\x{6B4E}\x{6B4F}\x{6B50}\x{6B51}\x{6B52}\x{6B53}\x{6B54}' . +'\x{6B55}\x{6B56}\x{6B59}\x{6B5A}\x{6B5B}\x{6B5C}\x{6B5E}\x{6B5F}\x{6B60}' . +'\x{6B61}\x{6B62}\x{6B63}\x{6B64}\x{6B65}\x{6B66}\x{6B67}\x{6B69}\x{6B6A}' . +'\x{6B6B}\x{6B6D}\x{6B6F}\x{6B70}\x{6B72}\x{6B73}\x{6B74}\x{6B76}\x{6B77}' . +'\x{6B78}\x{6B79}\x{6B7A}\x{6B7B}\x{6B7C}\x{6B7E}\x{6B7F}\x{6B80}\x{6B81}' . +'\x{6B82}\x{6B83}\x{6B84}\x{6B85}\x{6B86}\x{6B87}\x{6B88}\x{6B89}\x{6B8A}' . +'\x{6B8B}\x{6B8C}\x{6B8D}\x{6B8E}\x{6B8F}\x{6B90}\x{6B91}\x{6B92}\x{6B93}' . +'\x{6B94}\x{6B95}\x{6B96}\x{6B97}\x{6B98}\x{6B99}\x{6B9A}\x{6B9B}\x{6B9C}' . +'\x{6B9D}\x{6B9E}\x{6B9F}\x{6BA0}\x{6BA1}\x{6BA2}\x{6BA3}\x{6BA4}\x{6BA5}' . +'\x{6BA6}\x{6BA7}\x{6BA8}\x{6BA9}\x{6BAA}\x{6BAB}\x{6BAC}\x{6BAD}\x{6BAE}' . +'\x{6BAF}\x{6BB0}\x{6BB2}\x{6BB3}\x{6BB4}\x{6BB5}\x{6BB6}\x{6BB7}\x{6BB9}' . +'\x{6BBA}\x{6BBB}\x{6BBC}\x{6BBD}\x{6BBE}\x{6BBF}\x{6BC0}\x{6BC1}\x{6BC2}' . +'\x{6BC3}\x{6BC4}\x{6BC5}\x{6BC6}\x{6BC7}\x{6BC8}\x{6BC9}\x{6BCA}\x{6BCB}' . +'\x{6BCC}\x{6BCD}\x{6BCE}\x{6BCF}\x{6BD0}\x{6BD1}\x{6BD2}\x{6BD3}\x{6BD4}' . +'\x{6BD5}\x{6BD6}\x{6BD7}\x{6BD8}\x{6BD9}\x{6BDA}\x{6BDB}\x{6BDC}\x{6BDD}' . +'\x{6BDE}\x{6BDF}\x{6BE0}\x{6BE1}\x{6BE2}\x{6BE3}\x{6BE4}\x{6BE5}\x{6BE6}' . +'\x{6BE7}\x{6BE8}\x{6BEA}\x{6BEB}\x{6BEC}\x{6BED}\x{6BEE}\x{6BEF}\x{6BF0}' . +'\x{6BF2}\x{6BF3}\x{6BF5}\x{6BF6}\x{6BF7}\x{6BF8}\x{6BF9}\x{6BFB}\x{6BFC}' . +'\x{6BFD}\x{6BFE}\x{6BFF}\x{6C00}\x{6C01}\x{6C02}\x{6C03}\x{6C04}\x{6C05}' . +'\x{6C06}\x{6C07}\x{6C08}\x{6C09}\x{6C0B}\x{6C0C}\x{6C0D}\x{6C0E}\x{6C0F}' . +'\x{6C10}\x{6C11}\x{6C12}\x{6C13}\x{6C14}\x{6C15}\x{6C16}\x{6C18}\x{6C19}' . +'\x{6C1A}\x{6C1B}\x{6C1D}\x{6C1E}\x{6C1F}\x{6C20}\x{6C21}\x{6C22}\x{6C23}' . +'\x{6C24}\x{6C25}\x{6C26}\x{6C27}\x{6C28}\x{6C29}\x{6C2A}\x{6C2B}\x{6C2C}' . +'\x{6C2E}\x{6C2F}\x{6C30}\x{6C31}\x{6C32}\x{6C33}\x{6C34}\x{6C35}\x{6C36}' . +'\x{6C37}\x{6C38}\x{6C3A}\x{6C3B}\x{6C3D}\x{6C3E}\x{6C3F}\x{6C40}\x{6C41}' . +'\x{6C42}\x{6C43}\x{6C44}\x{6C46}\x{6C47}\x{6C48}\x{6C49}\x{6C4A}\x{6C4B}' . +'\x{6C4C}\x{6C4D}\x{6C4E}\x{6C4F}\x{6C50}\x{6C51}\x{6C52}\x{6C53}\x{6C54}' . +'\x{6C55}\x{6C56}\x{6C57}\x{6C58}\x{6C59}\x{6C5A}\x{6C5B}\x{6C5C}\x{6C5D}' . +'\x{6C5E}\x{6C5F}\x{6C60}\x{6C61}\x{6C62}\x{6C63}\x{6C64}\x{6C65}\x{6C66}' . +'\x{6C67}\x{6C68}\x{6C69}\x{6C6A}\x{6C6B}\x{6C6D}\x{6C6F}\x{6C70}\x{6C71}' . +'\x{6C72}\x{6C73}\x{6C74}\x{6C75}\x{6C76}\x{6C77}\x{6C78}\x{6C79}\x{6C7A}' . +'\x{6C7B}\x{6C7C}\x{6C7D}\x{6C7E}\x{6C7F}\x{6C80}\x{6C81}\x{6C82}\x{6C83}' . +'\x{6C84}\x{6C85}\x{6C86}\x{6C87}\x{6C88}\x{6C89}\x{6C8A}\x{6C8B}\x{6C8C}' . +'\x{6C8D}\x{6C8E}\x{6C8F}\x{6C90}\x{6C91}\x{6C92}\x{6C93}\x{6C94}\x{6C95}' . +'\x{6C96}\x{6C97}\x{6C98}\x{6C99}\x{6C9A}\x{6C9B}\x{6C9C}\x{6C9D}\x{6C9E}' . +'\x{6C9F}\x{6CA1}\x{6CA2}\x{6CA3}\x{6CA4}\x{6CA5}\x{6CA6}\x{6CA7}\x{6CA8}' . +'\x{6CA9}\x{6CAA}\x{6CAB}\x{6CAC}\x{6CAD}\x{6CAE}\x{6CAF}\x{6CB0}\x{6CB1}' . +'\x{6CB2}\x{6CB3}\x{6CB4}\x{6CB5}\x{6CB6}\x{6CB7}\x{6CB8}\x{6CB9}\x{6CBA}' . +'\x{6CBB}\x{6CBC}\x{6CBD}\x{6CBE}\x{6CBF}\x{6CC0}\x{6CC1}\x{6CC2}\x{6CC3}' . +'\x{6CC4}\x{6CC5}\x{6CC6}\x{6CC7}\x{6CC8}\x{6CC9}\x{6CCA}\x{6CCB}\x{6CCC}' . +'\x{6CCD}\x{6CCE}\x{6CCF}\x{6CD0}\x{6CD1}\x{6CD2}\x{6CD3}\x{6CD4}\x{6CD5}' . +'\x{6CD6}\x{6CD7}\x{6CD9}\x{6CDA}\x{6CDB}\x{6CDC}\x{6CDD}\x{6CDE}\x{6CDF}' . +'\x{6CE0}\x{6CE1}\x{6CE2}\x{6CE3}\x{6CE4}\x{6CE5}\x{6CE6}\x{6CE7}\x{6CE8}' . +'\x{6CE9}\x{6CEA}\x{6CEB}\x{6CEC}\x{6CED}\x{6CEE}\x{6CEF}\x{6CF0}\x{6CF1}' . +'\x{6CF2}\x{6CF3}\x{6CF5}\x{6CF6}\x{6CF7}\x{6CF8}\x{6CF9}\x{6CFA}\x{6CFB}' . +'\x{6CFC}\x{6CFD}\x{6CFE}\x{6CFF}\x{6D00}\x{6D01}\x{6D03}\x{6D04}\x{6D05}' . +'\x{6D06}\x{6D07}\x{6D08}\x{6D09}\x{6D0A}\x{6D0B}\x{6D0C}\x{6D0D}\x{6D0E}' . +'\x{6D0F}\x{6D10}\x{6D11}\x{6D12}\x{6D13}\x{6D14}\x{6D15}\x{6D16}\x{6D17}' . +'\x{6D18}\x{6D19}\x{6D1A}\x{6D1B}\x{6D1D}\x{6D1E}\x{6D1F}\x{6D20}\x{6D21}' . +'\x{6D22}\x{6D23}\x{6D25}\x{6D26}\x{6D27}\x{6D28}\x{6D29}\x{6D2A}\x{6D2B}' . +'\x{6D2C}\x{6D2D}\x{6D2E}\x{6D2F}\x{6D30}\x{6D31}\x{6D32}\x{6D33}\x{6D34}' . +'\x{6D35}\x{6D36}\x{6D37}\x{6D38}\x{6D39}\x{6D3A}\x{6D3B}\x{6D3C}\x{6D3D}' . +'\x{6D3E}\x{6D3F}\x{6D40}\x{6D41}\x{6D42}\x{6D43}\x{6D44}\x{6D45}\x{6D46}' . +'\x{6D47}\x{6D48}\x{6D49}\x{6D4A}\x{6D4B}\x{6D4C}\x{6D4D}\x{6D4E}\x{6D4F}' . +'\x{6D50}\x{6D51}\x{6D52}\x{6D53}\x{6D54}\x{6D55}\x{6D56}\x{6D57}\x{6D58}' . +'\x{6D59}\x{6D5A}\x{6D5B}\x{6D5C}\x{6D5D}\x{6D5E}\x{6D5F}\x{6D60}\x{6D61}' . +'\x{6D62}\x{6D63}\x{6D64}\x{6D65}\x{6D66}\x{6D67}\x{6D68}\x{6D69}\x{6D6A}' . +'\x{6D6B}\x{6D6C}\x{6D6D}\x{6D6E}\x{6D6F}\x{6D70}\x{6D72}\x{6D73}\x{6D74}' . +'\x{6D75}\x{6D76}\x{6D77}\x{6D78}\x{6D79}\x{6D7A}\x{6D7B}\x{6D7C}\x{6D7D}' . +'\x{6D7E}\x{6D7F}\x{6D80}\x{6D82}\x{6D83}\x{6D84}\x{6D85}\x{6D86}\x{6D87}' . +'\x{6D88}\x{6D89}\x{6D8A}\x{6D8B}\x{6D8C}\x{6D8D}\x{6D8E}\x{6D8F}\x{6D90}' . +'\x{6D91}\x{6D92}\x{6D93}\x{6D94}\x{6D95}\x{6D97}\x{6D98}\x{6D99}\x{6D9A}' . +'\x{6D9B}\x{6D9D}\x{6D9E}\x{6D9F}\x{6DA0}\x{6DA1}\x{6DA2}\x{6DA3}\x{6DA4}' . +'\x{6DA5}\x{6DA6}\x{6DA7}\x{6DA8}\x{6DA9}\x{6DAA}\x{6DAB}\x{6DAC}\x{6DAD}' . +'\x{6DAE}\x{6DAF}\x{6DB2}\x{6DB3}\x{6DB4}\x{6DB5}\x{6DB7}\x{6DB8}\x{6DB9}' . +'\x{6DBA}\x{6DBB}\x{6DBC}\x{6DBD}\x{6DBE}\x{6DBF}\x{6DC0}\x{6DC1}\x{6DC2}' . +'\x{6DC3}\x{6DC4}\x{6DC5}\x{6DC6}\x{6DC7}\x{6DC8}\x{6DC9}\x{6DCA}\x{6DCB}' . +'\x{6DCC}\x{6DCD}\x{6DCE}\x{6DCF}\x{6DD0}\x{6DD1}\x{6DD2}\x{6DD3}\x{6DD4}' . +'\x{6DD5}\x{6DD6}\x{6DD7}\x{6DD8}\x{6DD9}\x{6DDA}\x{6DDB}\x{6DDC}\x{6DDD}' . +'\x{6DDE}\x{6DDF}\x{6DE0}\x{6DE1}\x{6DE2}\x{6DE3}\x{6DE4}\x{6DE5}\x{6DE6}' . +'\x{6DE7}\x{6DE8}\x{6DE9}\x{6DEA}\x{6DEB}\x{6DEC}\x{6DED}\x{6DEE}\x{6DEF}' . +'\x{6DF0}\x{6DF1}\x{6DF2}\x{6DF3}\x{6DF4}\x{6DF5}\x{6DF6}\x{6DF7}\x{6DF8}' . +'\x{6DF9}\x{6DFA}\x{6DFB}\x{6DFC}\x{6DFD}\x{6E00}\x{6E03}\x{6E04}\x{6E05}' . +'\x{6E07}\x{6E08}\x{6E09}\x{6E0A}\x{6E0B}\x{6E0C}\x{6E0D}\x{6E0E}\x{6E0F}' . +'\x{6E10}\x{6E11}\x{6E14}\x{6E15}\x{6E16}\x{6E17}\x{6E19}\x{6E1A}\x{6E1B}' . +'\x{6E1C}\x{6E1D}\x{6E1E}\x{6E1F}\x{6E20}\x{6E21}\x{6E22}\x{6E23}\x{6E24}' . +'\x{6E25}\x{6E26}\x{6E27}\x{6E28}\x{6E29}\x{6E2B}\x{6E2C}\x{6E2D}\x{6E2E}' . +'\x{6E2F}\x{6E30}\x{6E31}\x{6E32}\x{6E33}\x{6E34}\x{6E35}\x{6E36}\x{6E37}' . +'\x{6E38}\x{6E39}\x{6E3A}\x{6E3B}\x{6E3C}\x{6E3D}\x{6E3E}\x{6E3F}\x{6E40}' . +'\x{6E41}\x{6E42}\x{6E43}\x{6E44}\x{6E45}\x{6E46}\x{6E47}\x{6E48}\x{6E49}' . +'\x{6E4A}\x{6E4B}\x{6E4D}\x{6E4E}\x{6E4F}\x{6E50}\x{6E51}\x{6E52}\x{6E53}' . +'\x{6E54}\x{6E55}\x{6E56}\x{6E57}\x{6E58}\x{6E59}\x{6E5A}\x{6E5B}\x{6E5C}' . +'\x{6E5D}\x{6E5E}\x{6E5F}\x{6E60}\x{6E61}\x{6E62}\x{6E63}\x{6E64}\x{6E65}' . +'\x{6E66}\x{6E67}\x{6E68}\x{6E69}\x{6E6A}\x{6E6B}\x{6E6D}\x{6E6E}\x{6E6F}' . +'\x{6E70}\x{6E71}\x{6E72}\x{6E73}\x{6E74}\x{6E75}\x{6E77}\x{6E78}\x{6E79}' . +'\x{6E7E}\x{6E7F}\x{6E80}\x{6E81}\x{6E82}\x{6E83}\x{6E84}\x{6E85}\x{6E86}' . +'\x{6E87}\x{6E88}\x{6E89}\x{6E8A}\x{6E8D}\x{6E8E}\x{6E8F}\x{6E90}\x{6E91}' . +'\x{6E92}\x{6E93}\x{6E94}\x{6E96}\x{6E97}\x{6E98}\x{6E99}\x{6E9A}\x{6E9B}' . +'\x{6E9C}\x{6E9D}\x{6E9E}\x{6E9F}\x{6EA0}\x{6EA1}\x{6EA2}\x{6EA3}\x{6EA4}' . +'\x{6EA5}\x{6EA6}\x{6EA7}\x{6EA8}\x{6EA9}\x{6EAA}\x{6EAB}\x{6EAC}\x{6EAD}' . +'\x{6EAE}\x{6EAF}\x{6EB0}\x{6EB1}\x{6EB2}\x{6EB3}\x{6EB4}\x{6EB5}\x{6EB6}' . +'\x{6EB7}\x{6EB8}\x{6EB9}\x{6EBA}\x{6EBB}\x{6EBC}\x{6EBD}\x{6EBE}\x{6EBF}' . +'\x{6EC0}\x{6EC1}\x{6EC2}\x{6EC3}\x{6EC4}\x{6EC5}\x{6EC6}\x{6EC7}\x{6EC8}' . +'\x{6EC9}\x{6ECA}\x{6ECB}\x{6ECC}\x{6ECD}\x{6ECE}\x{6ECF}\x{6ED0}\x{6ED1}' . +'\x{6ED2}\x{6ED3}\x{6ED4}\x{6ED5}\x{6ED6}\x{6ED7}\x{6ED8}\x{6ED9}\x{6EDA}' . +'\x{6EDC}\x{6EDE}\x{6EDF}\x{6EE0}\x{6EE1}\x{6EE2}\x{6EE4}\x{6EE5}\x{6EE6}' . +'\x{6EE7}\x{6EE8}\x{6EE9}\x{6EEA}\x{6EEB}\x{6EEC}\x{6EED}\x{6EEE}\x{6EEF}' . +'\x{6EF0}\x{6EF1}\x{6EF2}\x{6EF3}\x{6EF4}\x{6EF5}\x{6EF6}\x{6EF7}\x{6EF8}' . +'\x{6EF9}\x{6EFA}\x{6EFB}\x{6EFC}\x{6EFD}\x{6EFE}\x{6EFF}\x{6F00}\x{6F01}' . +'\x{6F02}\x{6F03}\x{6F05}\x{6F06}\x{6F07}\x{6F08}\x{6F09}\x{6F0A}\x{6F0C}' . +'\x{6F0D}\x{6F0E}\x{6F0F}\x{6F10}\x{6F11}\x{6F12}\x{6F13}\x{6F14}\x{6F15}' . +'\x{6F16}\x{6F17}\x{6F18}\x{6F19}\x{6F1A}\x{6F1B}\x{6F1C}\x{6F1D}\x{6F1E}' . +'\x{6F1F}\x{6F20}\x{6F21}\x{6F22}\x{6F23}\x{6F24}\x{6F25}\x{6F26}\x{6F27}' . +'\x{6F28}\x{6F29}\x{6F2A}\x{6F2B}\x{6F2C}\x{6F2D}\x{6F2E}\x{6F2F}\x{6F30}' . +'\x{6F31}\x{6F32}\x{6F33}\x{6F34}\x{6F35}\x{6F36}\x{6F37}\x{6F38}\x{6F39}' . +'\x{6F3A}\x{6F3B}\x{6F3C}\x{6F3D}\x{6F3E}\x{6F3F}\x{6F40}\x{6F41}\x{6F43}' . +'\x{6F44}\x{6F45}\x{6F46}\x{6F47}\x{6F49}\x{6F4B}\x{6F4C}\x{6F4D}\x{6F4E}' . +'\x{6F4F}\x{6F50}\x{6F51}\x{6F52}\x{6F53}\x{6F54}\x{6F55}\x{6F56}\x{6F57}' . +'\x{6F58}\x{6F59}\x{6F5A}\x{6F5B}\x{6F5C}\x{6F5D}\x{6F5E}\x{6F5F}\x{6F60}' . +'\x{6F61}\x{6F62}\x{6F63}\x{6F64}\x{6F65}\x{6F66}\x{6F67}\x{6F68}\x{6F69}' . +'\x{6F6A}\x{6F6B}\x{6F6C}\x{6F6D}\x{6F6E}\x{6F6F}\x{6F70}\x{6F71}\x{6F72}' . +'\x{6F73}\x{6F74}\x{6F75}\x{6F76}\x{6F77}\x{6F78}\x{6F7A}\x{6F7B}\x{6F7C}' . +'\x{6F7D}\x{6F7E}\x{6F7F}\x{6F80}\x{6F81}\x{6F82}\x{6F83}\x{6F84}\x{6F85}' . +'\x{6F86}\x{6F87}\x{6F88}\x{6F89}\x{6F8A}\x{6F8B}\x{6F8C}\x{6F8D}\x{6F8E}' . +'\x{6F8F}\x{6F90}\x{6F91}\x{6F92}\x{6F93}\x{6F94}\x{6F95}\x{6F96}\x{6F97}' . +'\x{6F99}\x{6F9B}\x{6F9C}\x{6F9D}\x{6F9E}\x{6FA0}\x{6FA1}\x{6FA2}\x{6FA3}' . +'\x{6FA4}\x{6FA5}\x{6FA6}\x{6FA7}\x{6FA8}\x{6FA9}\x{6FAA}\x{6FAB}\x{6FAC}' . +'\x{6FAD}\x{6FAE}\x{6FAF}\x{6FB0}\x{6FB1}\x{6FB2}\x{6FB3}\x{6FB4}\x{6FB5}' . +'\x{6FB6}\x{6FB8}\x{6FB9}\x{6FBA}\x{6FBB}\x{6FBC}\x{6FBD}\x{6FBE}\x{6FBF}' . +'\x{6FC0}\x{6FC1}\x{6FC2}\x{6FC3}\x{6FC4}\x{6FC6}\x{6FC7}\x{6FC8}\x{6FC9}' . +'\x{6FCA}\x{6FCB}\x{6FCC}\x{6FCD}\x{6FCE}\x{6FCF}\x{6FD1}\x{6FD2}\x{6FD4}' . +'\x{6FD5}\x{6FD6}\x{6FD7}\x{6FD8}\x{6FD9}\x{6FDA}\x{6FDB}\x{6FDC}\x{6FDD}' . +'\x{6FDE}\x{6FDF}\x{6FE0}\x{6FE1}\x{6FE2}\x{6FE3}\x{6FE4}\x{6FE5}\x{6FE6}' . +'\x{6FE7}\x{6FE8}\x{6FE9}\x{6FEA}\x{6FEB}\x{6FEC}\x{6FED}\x{6FEE}\x{6FEF}' . +'\x{6FF0}\x{6FF1}\x{6FF2}\x{6FF3}\x{6FF4}\x{6FF6}\x{6FF7}\x{6FF8}\x{6FF9}' . +'\x{6FFA}\x{6FFB}\x{6FFC}\x{6FFE}\x{6FFF}\x{7000}\x{7001}\x{7002}\x{7003}' . +'\x{7004}\x{7005}\x{7006}\x{7007}\x{7008}\x{7009}\x{700A}\x{700B}\x{700C}' . +'\x{700D}\x{700E}\x{700F}\x{7011}\x{7012}\x{7014}\x{7015}\x{7016}\x{7017}' . +'\x{7018}\x{7019}\x{701A}\x{701B}\x{701C}\x{701D}\x{701F}\x{7020}\x{7021}' . +'\x{7022}\x{7023}\x{7024}\x{7025}\x{7026}\x{7027}\x{7028}\x{7029}\x{702A}' . +'\x{702B}\x{702C}\x{702D}\x{702E}\x{702F}\x{7030}\x{7031}\x{7032}\x{7033}' . +'\x{7034}\x{7035}\x{7036}\x{7037}\x{7038}\x{7039}\x{703A}\x{703B}\x{703C}' . +'\x{703D}\x{703E}\x{703F}\x{7040}\x{7041}\x{7042}\x{7043}\x{7044}\x{7045}' . +'\x{7046}\x{7048}\x{7049}\x{704A}\x{704C}\x{704D}\x{704F}\x{7050}\x{7051}' . +'\x{7052}\x{7053}\x{7054}\x{7055}\x{7056}\x{7057}\x{7058}\x{7059}\x{705A}' . +'\x{705B}\x{705C}\x{705D}\x{705E}\x{705F}\x{7060}\x{7061}\x{7062}\x{7063}' . +'\x{7064}\x{7065}\x{7066}\x{7067}\x{7068}\x{7069}\x{706A}\x{706B}\x{706C}' . +'\x{706D}\x{706E}\x{706F}\x{7070}\x{7071}\x{7074}\x{7075}\x{7076}\x{7077}' . +'\x{7078}\x{7079}\x{707A}\x{707C}\x{707D}\x{707E}\x{707F}\x{7080}\x{7082}' . +'\x{7083}\x{7084}\x{7085}\x{7086}\x{7087}\x{7088}\x{7089}\x{708A}\x{708B}' . +'\x{708C}\x{708E}\x{708F}\x{7090}\x{7091}\x{7092}\x{7093}\x{7094}\x{7095}' . +'\x{7096}\x{7098}\x{7099}\x{709A}\x{709C}\x{709D}\x{709E}\x{709F}\x{70A0}' . +'\x{70A1}\x{70A2}\x{70A3}\x{70A4}\x{70A5}\x{70A6}\x{70A7}\x{70A8}\x{70A9}' . +'\x{70AB}\x{70AC}\x{70AD}\x{70AE}\x{70AF}\x{70B0}\x{70B1}\x{70B3}\x{70B4}' . +'\x{70B5}\x{70B7}\x{70B8}\x{70B9}\x{70BA}\x{70BB}\x{70BC}\x{70BD}\x{70BE}' . +'\x{70BF}\x{70C0}\x{70C1}\x{70C2}\x{70C3}\x{70C4}\x{70C5}\x{70C6}\x{70C7}' . +'\x{70C8}\x{70C9}\x{70CA}\x{70CB}\x{70CC}\x{70CD}\x{70CE}\x{70CF}\x{70D0}' . +'\x{70D1}\x{70D2}\x{70D3}\x{70D4}\x{70D6}\x{70D7}\x{70D8}\x{70D9}\x{70DA}' . +'\x{70DB}\x{70DC}\x{70DD}\x{70DE}\x{70DF}\x{70E0}\x{70E1}\x{70E2}\x{70E3}' . +'\x{70E4}\x{70E5}\x{70E6}\x{70E7}\x{70E8}\x{70E9}\x{70EA}\x{70EB}\x{70EC}' . +'\x{70ED}\x{70EE}\x{70EF}\x{70F0}\x{70F1}\x{70F2}\x{70F3}\x{70F4}\x{70F5}' . +'\x{70F6}\x{70F7}\x{70F8}\x{70F9}\x{70FA}\x{70FB}\x{70FC}\x{70FD}\x{70FF}' . +'\x{7100}\x{7101}\x{7102}\x{7103}\x{7104}\x{7105}\x{7106}\x{7107}\x{7109}' . +'\x{710A}\x{710B}\x{710C}\x{710D}\x{710E}\x{710F}\x{7110}\x{7111}\x{7112}' . +'\x{7113}\x{7115}\x{7116}\x{7117}\x{7118}\x{7119}\x{711A}\x{711B}\x{711C}' . +'\x{711D}\x{711E}\x{711F}\x{7120}\x{7121}\x{7122}\x{7123}\x{7125}\x{7126}' . +'\x{7127}\x{7128}\x{7129}\x{712A}\x{712B}\x{712C}\x{712D}\x{712E}\x{712F}' . +'\x{7130}\x{7131}\x{7132}\x{7135}\x{7136}\x{7137}\x{7138}\x{7139}\x{713A}' . +'\x{713B}\x{713D}\x{713E}\x{713F}\x{7140}\x{7141}\x{7142}\x{7143}\x{7144}' . +'\x{7145}\x{7146}\x{7147}\x{7148}\x{7149}\x{714A}\x{714B}\x{714C}\x{714D}' . +'\x{714E}\x{714F}\x{7150}\x{7151}\x{7152}\x{7153}\x{7154}\x{7156}\x{7158}' . +'\x{7159}\x{715A}\x{715B}\x{715C}\x{715D}\x{715E}\x{715F}\x{7160}\x{7161}' . +'\x{7162}\x{7163}\x{7164}\x{7165}\x{7166}\x{7167}\x{7168}\x{7169}\x{716A}' . +'\x{716C}\x{716E}\x{716F}\x{7170}\x{7171}\x{7172}\x{7173}\x{7174}\x{7175}' . +'\x{7176}\x{7177}\x{7178}\x{7179}\x{717A}\x{717B}\x{717C}\x{717D}\x{717E}' . +'\x{717F}\x{7180}\x{7181}\x{7182}\x{7183}\x{7184}\x{7185}\x{7186}\x{7187}' . +'\x{7188}\x{7189}\x{718A}\x{718B}\x{718C}\x{718E}\x{718F}\x{7190}\x{7191}' . +'\x{7192}\x{7193}\x{7194}\x{7195}\x{7197}\x{7198}\x{7199}\x{719A}\x{719B}' . +'\x{719C}\x{719D}\x{719E}\x{719F}\x{71A0}\x{71A1}\x{71A2}\x{71A3}\x{71A4}' . +'\x{71A5}\x{71A7}\x{71A8}\x{71A9}\x{71AA}\x{71AC}\x{71AD}\x{71AE}\x{71AF}' . +'\x{71B0}\x{71B1}\x{71B2}\x{71B3}\x{71B4}\x{71B5}\x{71B7}\x{71B8}\x{71B9}' . +'\x{71BA}\x{71BB}\x{71BC}\x{71BD}\x{71BE}\x{71BF}\x{71C0}\x{71C1}\x{71C2}' . +'\x{71C3}\x{71C4}\x{71C5}\x{71C6}\x{71C7}\x{71C8}\x{71C9}\x{71CA}\x{71CB}' . +'\x{71CD}\x{71CE}\x{71CF}\x{71D0}\x{71D1}\x{71D2}\x{71D4}\x{71D5}\x{71D6}' . +'\x{71D7}\x{71D8}\x{71D9}\x{71DA}\x{71DB}\x{71DC}\x{71DD}\x{71DE}\x{71DF}' . +'\x{71E0}\x{71E1}\x{71E2}\x{71E3}\x{71E4}\x{71E5}\x{71E6}\x{71E7}\x{71E8}' . +'\x{71E9}\x{71EA}\x{71EB}\x{71EC}\x{71ED}\x{71EE}\x{71EF}\x{71F0}\x{71F1}' . +'\x{71F2}\x{71F4}\x{71F5}\x{71F6}\x{71F7}\x{71F8}\x{71F9}\x{71FB}\x{71FC}' . +'\x{71FD}\x{71FE}\x{71FF}\x{7201}\x{7202}\x{7203}\x{7204}\x{7205}\x{7206}' . +'\x{7207}\x{7208}\x{7209}\x{720A}\x{720C}\x{720D}\x{720E}\x{720F}\x{7210}' . +'\x{7212}\x{7213}\x{7214}\x{7216}\x{7218}\x{7219}\x{721A}\x{721B}\x{721C}' . +'\x{721D}\x{721E}\x{721F}\x{7221}\x{7222}\x{7223}\x{7226}\x{7227}\x{7228}' . +'\x{7229}\x{722A}\x{722B}\x{722C}\x{722D}\x{722E}\x{7230}\x{7231}\x{7232}' . +'\x{7233}\x{7235}\x{7236}\x{7237}\x{7238}\x{7239}\x{723A}\x{723B}\x{723C}' . +'\x{723D}\x{723E}\x{723F}\x{7240}\x{7241}\x{7242}\x{7243}\x{7244}\x{7246}' . +'\x{7247}\x{7248}\x{7249}\x{724A}\x{724B}\x{724C}\x{724D}\x{724F}\x{7251}' . +'\x{7252}\x{7253}\x{7254}\x{7256}\x{7257}\x{7258}\x{7259}\x{725A}\x{725B}' . +'\x{725C}\x{725D}\x{725E}\x{725F}\x{7260}\x{7261}\x{7262}\x{7263}\x{7264}' . +'\x{7265}\x{7266}\x{7267}\x{7268}\x{7269}\x{726A}\x{726B}\x{726C}\x{726D}' . +'\x{726E}\x{726F}\x{7270}\x{7271}\x{7272}\x{7273}\x{7274}\x{7275}\x{7276}' . +'\x{7277}\x{7278}\x{7279}\x{727A}\x{727B}\x{727C}\x{727D}\x{727E}\x{727F}' . +'\x{7280}\x{7281}\x{7282}\x{7283}\x{7284}\x{7285}\x{7286}\x{7287}\x{7288}' . +'\x{7289}\x{728A}\x{728B}\x{728C}\x{728D}\x{728E}\x{728F}\x{7290}\x{7291}' . +'\x{7292}\x{7293}\x{7294}\x{7295}\x{7296}\x{7297}\x{7298}\x{7299}\x{729A}' . +'\x{729B}\x{729C}\x{729D}\x{729E}\x{729F}\x{72A1}\x{72A2}\x{72A3}\x{72A4}' . +'\x{72A5}\x{72A6}\x{72A7}\x{72A8}\x{72A9}\x{72AA}\x{72AC}\x{72AD}\x{72AE}' . +'\x{72AF}\x{72B0}\x{72B1}\x{72B2}\x{72B3}\x{72B4}\x{72B5}\x{72B6}\x{72B7}' . +'\x{72B8}\x{72B9}\x{72BA}\x{72BB}\x{72BC}\x{72BD}\x{72BF}\x{72C0}\x{72C1}' . +'\x{72C2}\x{72C3}\x{72C4}\x{72C5}\x{72C6}\x{72C7}\x{72C8}\x{72C9}\x{72CA}' . +'\x{72CB}\x{72CC}\x{72CD}\x{72CE}\x{72CF}\x{72D0}\x{72D1}\x{72D2}\x{72D3}' . +'\x{72D4}\x{72D5}\x{72D6}\x{72D7}\x{72D8}\x{72D9}\x{72DA}\x{72DB}\x{72DC}' . +'\x{72DD}\x{72DE}\x{72DF}\x{72E0}\x{72E1}\x{72E2}\x{72E3}\x{72E4}\x{72E5}' . +'\x{72E6}\x{72E7}\x{72E8}\x{72E9}\x{72EA}\x{72EB}\x{72EC}\x{72ED}\x{72EE}' . +'\x{72EF}\x{72F0}\x{72F1}\x{72F2}\x{72F3}\x{72F4}\x{72F5}\x{72F6}\x{72F7}' . +'\x{72F8}\x{72F9}\x{72FA}\x{72FB}\x{72FC}\x{72FD}\x{72FE}\x{72FF}\x{7300}' . +'\x{7301}\x{7303}\x{7304}\x{7305}\x{7306}\x{7307}\x{7308}\x{7309}\x{730A}' . +'\x{730B}\x{730C}\x{730D}\x{730E}\x{730F}\x{7311}\x{7312}\x{7313}\x{7314}' . +'\x{7315}\x{7316}\x{7317}\x{7318}\x{7319}\x{731A}\x{731B}\x{731C}\x{731D}' . +'\x{731E}\x{7320}\x{7321}\x{7322}\x{7323}\x{7324}\x{7325}\x{7326}\x{7327}' . +'\x{7329}\x{732A}\x{732B}\x{732C}\x{732D}\x{732E}\x{7330}\x{7331}\x{7332}' . +'\x{7333}\x{7334}\x{7335}\x{7336}\x{7337}\x{7338}\x{7339}\x{733A}\x{733B}' . +'\x{733C}\x{733D}\x{733E}\x{733F}\x{7340}\x{7341}\x{7342}\x{7343}\x{7344}' . +'\x{7345}\x{7346}\x{7347}\x{7348}\x{7349}\x{734A}\x{734B}\x{734C}\x{734D}' . +'\x{734E}\x{7350}\x{7351}\x{7352}\x{7354}\x{7355}\x{7356}\x{7357}\x{7358}' . +'\x{7359}\x{735A}\x{735B}\x{735C}\x{735D}\x{735E}\x{735F}\x{7360}\x{7361}' . +'\x{7362}\x{7364}\x{7365}\x{7366}\x{7367}\x{7368}\x{7369}\x{736A}\x{736B}' . +'\x{736C}\x{736D}\x{736E}\x{736F}\x{7370}\x{7371}\x{7372}\x{7373}\x{7374}' . +'\x{7375}\x{7376}\x{7377}\x{7378}\x{7379}\x{737A}\x{737B}\x{737C}\x{737D}' . +'\x{737E}\x{737F}\x{7380}\x{7381}\x{7382}\x{7383}\x{7384}\x{7385}\x{7386}' . +'\x{7387}\x{7388}\x{7389}\x{738A}\x{738B}\x{738C}\x{738D}\x{738E}\x{738F}' . +'\x{7390}\x{7391}\x{7392}\x{7393}\x{7394}\x{7395}\x{7396}\x{7397}\x{7398}' . +'\x{7399}\x{739A}\x{739B}\x{739D}\x{739E}\x{739F}\x{73A0}\x{73A1}\x{73A2}' . +'\x{73A3}\x{73A4}\x{73A5}\x{73A6}\x{73A7}\x{73A8}\x{73A9}\x{73AA}\x{73AB}' . +'\x{73AC}\x{73AD}\x{73AE}\x{73AF}\x{73B0}\x{73B1}\x{73B2}\x{73B3}\x{73B4}' . +'\x{73B5}\x{73B6}\x{73B7}\x{73B8}\x{73B9}\x{73BA}\x{73BB}\x{73BC}\x{73BD}' . +'\x{73BE}\x{73BF}\x{73C0}\x{73C2}\x{73C3}\x{73C4}\x{73C5}\x{73C6}\x{73C7}' . +'\x{73C8}\x{73C9}\x{73CA}\x{73CB}\x{73CC}\x{73CD}\x{73CE}\x{73CF}\x{73D0}' . +'\x{73D1}\x{73D2}\x{73D3}\x{73D4}\x{73D5}\x{73D6}\x{73D7}\x{73D8}\x{73D9}' . +'\x{73DA}\x{73DB}\x{73DC}\x{73DD}\x{73DE}\x{73DF}\x{73E0}\x{73E2}\x{73E3}' . +'\x{73E5}\x{73E6}\x{73E7}\x{73E8}\x{73E9}\x{73EA}\x{73EB}\x{73EC}\x{73ED}' . +'\x{73EE}\x{73EF}\x{73F0}\x{73F1}\x{73F2}\x{73F4}\x{73F5}\x{73F6}\x{73F7}' . +'\x{73F8}\x{73F9}\x{73FA}\x{73FC}\x{73FD}\x{73FE}\x{73FF}\x{7400}\x{7401}' . +'\x{7402}\x{7403}\x{7404}\x{7405}\x{7406}\x{7407}\x{7408}\x{7409}\x{740A}' . +'\x{740B}\x{740C}\x{740D}\x{740E}\x{740F}\x{7410}\x{7411}\x{7412}\x{7413}' . +'\x{7414}\x{7415}\x{7416}\x{7417}\x{7419}\x{741A}\x{741B}\x{741C}\x{741D}' . +'\x{741E}\x{741F}\x{7420}\x{7421}\x{7422}\x{7423}\x{7424}\x{7425}\x{7426}' . +'\x{7427}\x{7428}\x{7429}\x{742A}\x{742B}\x{742C}\x{742D}\x{742E}\x{742F}' . +'\x{7430}\x{7431}\x{7432}\x{7433}\x{7434}\x{7435}\x{7436}\x{7437}\x{7438}' . +'\x{743A}\x{743B}\x{743C}\x{743D}\x{743F}\x{7440}\x{7441}\x{7442}\x{7443}' . +'\x{7444}\x{7445}\x{7446}\x{7448}\x{744A}\x{744B}\x{744C}\x{744D}\x{744E}' . +'\x{744F}\x{7450}\x{7451}\x{7452}\x{7453}\x{7454}\x{7455}\x{7456}\x{7457}' . +'\x{7459}\x{745A}\x{745B}\x{745C}\x{745D}\x{745E}\x{745F}\x{7461}\x{7462}' . +'\x{7463}\x{7464}\x{7465}\x{7466}\x{7467}\x{7468}\x{7469}\x{746A}\x{746B}' . +'\x{746C}\x{746D}\x{746E}\x{746F}\x{7470}\x{7471}\x{7472}\x{7473}\x{7474}' . +'\x{7475}\x{7476}\x{7477}\x{7478}\x{7479}\x{747A}\x{747C}\x{747D}\x{747E}' . +'\x{747F}\x{7480}\x{7481}\x{7482}\x{7483}\x{7485}\x{7486}\x{7487}\x{7488}' . +'\x{7489}\x{748A}\x{748B}\x{748C}\x{748D}\x{748E}\x{748F}\x{7490}\x{7491}' . +'\x{7492}\x{7493}\x{7494}\x{7495}\x{7497}\x{7498}\x{7499}\x{749A}\x{749B}' . +'\x{749C}\x{749E}\x{749F}\x{74A0}\x{74A1}\x{74A3}\x{74A4}\x{74A5}\x{74A6}' . +'\x{74A7}\x{74A8}\x{74A9}\x{74AA}\x{74AB}\x{74AC}\x{74AD}\x{74AE}\x{74AF}' . +'\x{74B0}\x{74B1}\x{74B2}\x{74B3}\x{74B4}\x{74B5}\x{74B6}\x{74B7}\x{74B8}' . +'\x{74B9}\x{74BA}\x{74BB}\x{74BC}\x{74BD}\x{74BE}\x{74BF}\x{74C0}\x{74C1}' . +'\x{74C2}\x{74C3}\x{74C4}\x{74C5}\x{74C6}\x{74CA}\x{74CB}\x{74CD}\x{74CE}' . +'\x{74CF}\x{74D0}\x{74D1}\x{74D2}\x{74D3}\x{74D4}\x{74D5}\x{74D6}\x{74D7}' . +'\x{74D8}\x{74D9}\x{74DA}\x{74DB}\x{74DC}\x{74DD}\x{74DE}\x{74DF}\x{74E0}' . +'\x{74E1}\x{74E2}\x{74E3}\x{74E4}\x{74E5}\x{74E6}\x{74E7}\x{74E8}\x{74E9}' . +'\x{74EA}\x{74EC}\x{74ED}\x{74EE}\x{74EF}\x{74F0}\x{74F1}\x{74F2}\x{74F3}' . +'\x{74F4}\x{74F5}\x{74F6}\x{74F7}\x{74F8}\x{74F9}\x{74FA}\x{74FB}\x{74FC}' . +'\x{74FD}\x{74FE}\x{74FF}\x{7500}\x{7501}\x{7502}\x{7503}\x{7504}\x{7505}' . +'\x{7506}\x{7507}\x{7508}\x{7509}\x{750A}\x{750B}\x{750C}\x{750D}\x{750F}' . +'\x{7510}\x{7511}\x{7512}\x{7513}\x{7514}\x{7515}\x{7516}\x{7517}\x{7518}' . +'\x{7519}\x{751A}\x{751B}\x{751C}\x{751D}\x{751E}\x{751F}\x{7521}\x{7522}' . +'\x{7523}\x{7524}\x{7525}\x{7526}\x{7527}\x{7528}\x{7529}\x{752A}\x{752B}' . +'\x{752C}\x{752D}\x{752E}\x{752F}\x{7530}\x{7531}\x{7532}\x{7533}\x{7535}' . +'\x{7536}\x{7537}\x{7538}\x{7539}\x{753A}\x{753B}\x{753C}\x{753D}\x{753E}' . +'\x{753F}\x{7540}\x{7542}\x{7543}\x{7544}\x{7545}\x{7546}\x{7547}\x{7548}' . +'\x{7549}\x{754B}\x{754C}\x{754D}\x{754E}\x{754F}\x{7550}\x{7551}\x{7553}' . +'\x{7554}\x{7556}\x{7557}\x{7558}\x{7559}\x{755A}\x{755B}\x{755C}\x{755D}' . +'\x{755F}\x{7560}\x{7562}\x{7563}\x{7564}\x{7565}\x{7566}\x{7567}\x{7568}' . +'\x{7569}\x{756A}\x{756B}\x{756C}\x{756D}\x{756E}\x{756F}\x{7570}\x{7572}' . +'\x{7574}\x{7575}\x{7576}\x{7577}\x{7578}\x{7579}\x{757C}\x{757D}\x{757E}' . +'\x{757F}\x{7580}\x{7581}\x{7582}\x{7583}\x{7584}\x{7586}\x{7587}\x{7588}' . +'\x{7589}\x{758A}\x{758B}\x{758C}\x{758D}\x{758F}\x{7590}\x{7591}\x{7592}' . +'\x{7593}\x{7594}\x{7595}\x{7596}\x{7597}\x{7598}\x{7599}\x{759A}\x{759B}' . +'\x{759C}\x{759D}\x{759E}\x{759F}\x{75A0}\x{75A1}\x{75A2}\x{75A3}\x{75A4}' . +'\x{75A5}\x{75A6}\x{75A7}\x{75A8}\x{75AA}\x{75AB}\x{75AC}\x{75AD}\x{75AE}' . +'\x{75AF}\x{75B0}\x{75B1}\x{75B2}\x{75B3}\x{75B4}\x{75B5}\x{75B6}\x{75B8}' . +'\x{75B9}\x{75BA}\x{75BB}\x{75BC}\x{75BD}\x{75BE}\x{75BF}\x{75C0}\x{75C1}' . +'\x{75C2}\x{75C3}\x{75C4}\x{75C5}\x{75C6}\x{75C7}\x{75C8}\x{75C9}\x{75CA}' . +'\x{75CB}\x{75CC}\x{75CD}\x{75CE}\x{75CF}\x{75D0}\x{75D1}\x{75D2}\x{75D3}' . +'\x{75D4}\x{75D5}\x{75D6}\x{75D7}\x{75D8}\x{75D9}\x{75DA}\x{75DB}\x{75DD}' . +'\x{75DE}\x{75DF}\x{75E0}\x{75E1}\x{75E2}\x{75E3}\x{75E4}\x{75E5}\x{75E6}' . +'\x{75E7}\x{75E8}\x{75EA}\x{75EB}\x{75EC}\x{75ED}\x{75EF}\x{75F0}\x{75F1}' . +'\x{75F2}\x{75F3}\x{75F4}\x{75F5}\x{75F6}\x{75F7}\x{75F8}\x{75F9}\x{75FA}' . +'\x{75FB}\x{75FC}\x{75FD}\x{75FE}\x{75FF}\x{7600}\x{7601}\x{7602}\x{7603}' . +'\x{7604}\x{7605}\x{7606}\x{7607}\x{7608}\x{7609}\x{760A}\x{760B}\x{760C}' . +'\x{760D}\x{760E}\x{760F}\x{7610}\x{7611}\x{7612}\x{7613}\x{7614}\x{7615}' . +'\x{7616}\x{7617}\x{7618}\x{7619}\x{761A}\x{761B}\x{761C}\x{761D}\x{761E}' . +'\x{761F}\x{7620}\x{7621}\x{7622}\x{7623}\x{7624}\x{7625}\x{7626}\x{7627}' . +'\x{7628}\x{7629}\x{762A}\x{762B}\x{762D}\x{762E}\x{762F}\x{7630}\x{7631}' . +'\x{7632}\x{7633}\x{7634}\x{7635}\x{7636}\x{7637}\x{7638}\x{7639}\x{763A}' . +'\x{763B}\x{763C}\x{763D}\x{763E}\x{763F}\x{7640}\x{7641}\x{7642}\x{7643}' . +'\x{7646}\x{7647}\x{7648}\x{7649}\x{764A}\x{764B}\x{764C}\x{764D}\x{764F}' . +'\x{7650}\x{7652}\x{7653}\x{7654}\x{7656}\x{7657}\x{7658}\x{7659}\x{765A}' . +'\x{765B}\x{765C}\x{765D}\x{765E}\x{765F}\x{7660}\x{7661}\x{7662}\x{7663}' . +'\x{7664}\x{7665}\x{7666}\x{7667}\x{7668}\x{7669}\x{766A}\x{766B}\x{766C}' . +'\x{766D}\x{766E}\x{766F}\x{7670}\x{7671}\x{7672}\x{7674}\x{7675}\x{7676}' . +'\x{7677}\x{7678}\x{7679}\x{767B}\x{767C}\x{767D}\x{767E}\x{767F}\x{7680}' . +'\x{7681}\x{7682}\x{7683}\x{7684}\x{7685}\x{7686}\x{7687}\x{7688}\x{7689}' . +'\x{768A}\x{768B}\x{768C}\x{768E}\x{768F}\x{7690}\x{7691}\x{7692}\x{7693}' . +'\x{7694}\x{7695}\x{7696}\x{7697}\x{7698}\x{7699}\x{769A}\x{769B}\x{769C}' . +'\x{769D}\x{769E}\x{769F}\x{76A0}\x{76A3}\x{76A4}\x{76A6}\x{76A7}\x{76A9}' . +'\x{76AA}\x{76AB}\x{76AC}\x{76AD}\x{76AE}\x{76AF}\x{76B0}\x{76B1}\x{76B2}' . +'\x{76B4}\x{76B5}\x{76B7}\x{76B8}\x{76BA}\x{76BB}\x{76BC}\x{76BD}\x{76BE}' . +'\x{76BF}\x{76C0}\x{76C2}\x{76C3}\x{76C4}\x{76C5}\x{76C6}\x{76C7}\x{76C8}' . +'\x{76C9}\x{76CA}\x{76CD}\x{76CE}\x{76CF}\x{76D0}\x{76D1}\x{76D2}\x{76D3}' . +'\x{76D4}\x{76D5}\x{76D6}\x{76D7}\x{76D8}\x{76DA}\x{76DB}\x{76DC}\x{76DD}' . +'\x{76DE}\x{76DF}\x{76E0}\x{76E1}\x{76E2}\x{76E3}\x{76E4}\x{76E5}\x{76E6}' . +'\x{76E7}\x{76E8}\x{76E9}\x{76EA}\x{76EC}\x{76ED}\x{76EE}\x{76EF}\x{76F0}' . +'\x{76F1}\x{76F2}\x{76F3}\x{76F4}\x{76F5}\x{76F6}\x{76F7}\x{76F8}\x{76F9}' . +'\x{76FA}\x{76FB}\x{76FC}\x{76FD}\x{76FE}\x{76FF}\x{7701}\x{7703}\x{7704}' . +'\x{7705}\x{7706}\x{7707}\x{7708}\x{7709}\x{770A}\x{770B}\x{770C}\x{770D}' . +'\x{770F}\x{7710}\x{7711}\x{7712}\x{7713}\x{7714}\x{7715}\x{7716}\x{7717}' . +'\x{7718}\x{7719}\x{771A}\x{771B}\x{771C}\x{771D}\x{771E}\x{771F}\x{7720}' . +'\x{7722}\x{7723}\x{7725}\x{7726}\x{7727}\x{7728}\x{7729}\x{772A}\x{772C}' . +'\x{772D}\x{772E}\x{772F}\x{7730}\x{7731}\x{7732}\x{7733}\x{7734}\x{7735}' . +'\x{7736}\x{7737}\x{7738}\x{7739}\x{773A}\x{773B}\x{773C}\x{773D}\x{773E}' . +'\x{7740}\x{7741}\x{7743}\x{7744}\x{7745}\x{7746}\x{7747}\x{7748}\x{7749}' . +'\x{774A}\x{774B}\x{774C}\x{774D}\x{774E}\x{774F}\x{7750}\x{7751}\x{7752}' . +'\x{7753}\x{7754}\x{7755}\x{7756}\x{7757}\x{7758}\x{7759}\x{775A}\x{775B}' . +'\x{775C}\x{775D}\x{775E}\x{775F}\x{7760}\x{7761}\x{7762}\x{7763}\x{7765}' . +'\x{7766}\x{7767}\x{7768}\x{7769}\x{776A}\x{776B}\x{776C}\x{776D}\x{776E}' . +'\x{776F}\x{7770}\x{7771}\x{7772}\x{7773}\x{7774}\x{7775}\x{7776}\x{7777}' . +'\x{7778}\x{7779}\x{777A}\x{777B}\x{777C}\x{777D}\x{777E}\x{777F}\x{7780}' . +'\x{7781}\x{7782}\x{7783}\x{7784}\x{7785}\x{7786}\x{7787}\x{7788}\x{7789}' . +'\x{778A}\x{778B}\x{778C}\x{778D}\x{778E}\x{778F}\x{7790}\x{7791}\x{7792}' . +'\x{7793}\x{7794}\x{7795}\x{7797}\x{7798}\x{7799}\x{779A}\x{779B}\x{779C}' . +'\x{779D}\x{779E}\x{779F}\x{77A0}\x{77A1}\x{77A2}\x{77A3}\x{77A5}\x{77A6}' . +'\x{77A7}\x{77A8}\x{77A9}\x{77AA}\x{77AB}\x{77AC}\x{77AD}\x{77AE}\x{77AF}' . +'\x{77B0}\x{77B1}\x{77B2}\x{77B3}\x{77B4}\x{77B5}\x{77B6}\x{77B7}\x{77B8}' . +'\x{77B9}\x{77BA}\x{77BB}\x{77BC}\x{77BD}\x{77BF}\x{77C0}\x{77C2}\x{77C3}' . +'\x{77C4}\x{77C5}\x{77C6}\x{77C7}\x{77C8}\x{77C9}\x{77CA}\x{77CB}\x{77CC}' . +'\x{77CD}\x{77CE}\x{77CF}\x{77D0}\x{77D1}\x{77D3}\x{77D4}\x{77D5}\x{77D6}' . +'\x{77D7}\x{77D8}\x{77D9}\x{77DA}\x{77DB}\x{77DC}\x{77DE}\x{77DF}\x{77E0}' . +'\x{77E1}\x{77E2}\x{77E3}\x{77E5}\x{77E7}\x{77E8}\x{77E9}\x{77EA}\x{77EB}' . +'\x{77EC}\x{77ED}\x{77EE}\x{77EF}\x{77F0}\x{77F1}\x{77F2}\x{77F3}\x{77F6}' . +'\x{77F7}\x{77F8}\x{77F9}\x{77FA}\x{77FB}\x{77FC}\x{77FD}\x{77FE}\x{77FF}' . +'\x{7800}\x{7801}\x{7802}\x{7803}\x{7804}\x{7805}\x{7806}\x{7808}\x{7809}' . +'\x{780A}\x{780B}\x{780C}\x{780D}\x{780E}\x{780F}\x{7810}\x{7811}\x{7812}' . +'\x{7813}\x{7814}\x{7815}\x{7816}\x{7817}\x{7818}\x{7819}\x{781A}\x{781B}' . +'\x{781C}\x{781D}\x{781E}\x{781F}\x{7820}\x{7821}\x{7822}\x{7823}\x{7825}' . +'\x{7826}\x{7827}\x{7828}\x{7829}\x{782A}\x{782B}\x{782C}\x{782D}\x{782E}' . +'\x{782F}\x{7830}\x{7831}\x{7832}\x{7833}\x{7834}\x{7835}\x{7837}\x{7838}' . +'\x{7839}\x{783A}\x{783B}\x{783C}\x{783D}\x{783E}\x{7840}\x{7841}\x{7843}' . +'\x{7844}\x{7845}\x{7847}\x{7848}\x{7849}\x{784A}\x{784C}\x{784D}\x{784E}' . +'\x{7850}\x{7851}\x{7852}\x{7853}\x{7854}\x{7855}\x{7856}\x{7857}\x{7858}' . +'\x{7859}\x{785A}\x{785B}\x{785C}\x{785D}\x{785E}\x{785F}\x{7860}\x{7861}' . +'\x{7862}\x{7863}\x{7864}\x{7865}\x{7866}\x{7867}\x{7868}\x{7869}\x{786A}' . +'\x{786B}\x{786C}\x{786D}\x{786E}\x{786F}\x{7870}\x{7871}\x{7872}\x{7873}' . +'\x{7874}\x{7875}\x{7877}\x{7878}\x{7879}\x{787A}\x{787B}\x{787C}\x{787D}' . +'\x{787E}\x{787F}\x{7880}\x{7881}\x{7882}\x{7883}\x{7884}\x{7885}\x{7886}' . +'\x{7887}\x{7889}\x{788A}\x{788B}\x{788C}\x{788D}\x{788E}\x{788F}\x{7890}' . +'\x{7891}\x{7892}\x{7893}\x{7894}\x{7895}\x{7896}\x{7897}\x{7898}\x{7899}' . +'\x{789A}\x{789B}\x{789C}\x{789D}\x{789E}\x{789F}\x{78A0}\x{78A1}\x{78A2}' . +'\x{78A3}\x{78A4}\x{78A5}\x{78A6}\x{78A7}\x{78A8}\x{78A9}\x{78AA}\x{78AB}' . +'\x{78AC}\x{78AD}\x{78AE}\x{78AF}\x{78B0}\x{78B1}\x{78B2}\x{78B3}\x{78B4}' . +'\x{78B5}\x{78B6}\x{78B7}\x{78B8}\x{78B9}\x{78BA}\x{78BB}\x{78BC}\x{78BD}' . +'\x{78BE}\x{78BF}\x{78C0}\x{78C1}\x{78C3}\x{78C4}\x{78C5}\x{78C6}\x{78C8}' . +'\x{78C9}\x{78CA}\x{78CB}\x{78CC}\x{78CD}\x{78CE}\x{78CF}\x{78D0}\x{78D1}' . +'\x{78D3}\x{78D4}\x{78D5}\x{78D6}\x{78D7}\x{78D8}\x{78D9}\x{78DA}\x{78DB}' . +'\x{78DC}\x{78DD}\x{78DE}\x{78DF}\x{78E0}\x{78E1}\x{78E2}\x{78E3}\x{78E4}' . +'\x{78E5}\x{78E6}\x{78E7}\x{78E8}\x{78E9}\x{78EA}\x{78EB}\x{78EC}\x{78ED}' . +'\x{78EE}\x{78EF}\x{78F1}\x{78F2}\x{78F3}\x{78F4}\x{78F5}\x{78F6}\x{78F7}' . +'\x{78F9}\x{78FA}\x{78FB}\x{78FC}\x{78FD}\x{78FE}\x{78FF}\x{7901}\x{7902}' . +'\x{7903}\x{7904}\x{7905}\x{7906}\x{7907}\x{7909}\x{790A}\x{790B}\x{790C}' . +'\x{790E}\x{790F}\x{7910}\x{7911}\x{7912}\x{7913}\x{7914}\x{7916}\x{7917}' . +'\x{7918}\x{7919}\x{791A}\x{791B}\x{791C}\x{791D}\x{791E}\x{7921}\x{7922}' . +'\x{7923}\x{7924}\x{7925}\x{7926}\x{7927}\x{7928}\x{7929}\x{792A}\x{792B}' . +'\x{792C}\x{792D}\x{792E}\x{792F}\x{7930}\x{7931}\x{7933}\x{7934}\x{7935}' . +'\x{7937}\x{7938}\x{7939}\x{793A}\x{793B}\x{793C}\x{793D}\x{793E}\x{793F}' . +'\x{7940}\x{7941}\x{7942}\x{7943}\x{7944}\x{7945}\x{7946}\x{7947}\x{7948}' . +'\x{7949}\x{794A}\x{794B}\x{794C}\x{794D}\x{794E}\x{794F}\x{7950}\x{7951}' . +'\x{7952}\x{7953}\x{7954}\x{7955}\x{7956}\x{7957}\x{7958}\x{795A}\x{795B}' . +'\x{795C}\x{795D}\x{795E}\x{795F}\x{7960}\x{7961}\x{7962}\x{7963}\x{7964}' . +'\x{7965}\x{7966}\x{7967}\x{7968}\x{7969}\x{796A}\x{796B}\x{796D}\x{796F}' . +'\x{7970}\x{7971}\x{7972}\x{7973}\x{7974}\x{7977}\x{7978}\x{7979}\x{797A}' . +'\x{797B}\x{797C}\x{797D}\x{797E}\x{797F}\x{7980}\x{7981}\x{7982}\x{7983}' . +'\x{7984}\x{7985}\x{7988}\x{7989}\x{798A}\x{798B}\x{798C}\x{798D}\x{798E}' . +'\x{798F}\x{7990}\x{7991}\x{7992}\x{7993}\x{7994}\x{7995}\x{7996}\x{7997}' . +'\x{7998}\x{7999}\x{799A}\x{799B}\x{799C}\x{799F}\x{79A0}\x{79A1}\x{79A2}' . +'\x{79A3}\x{79A4}\x{79A5}\x{79A6}\x{79A7}\x{79A8}\x{79AA}\x{79AB}\x{79AC}' . +'\x{79AD}\x{79AE}\x{79AF}\x{79B0}\x{79B1}\x{79B2}\x{79B3}\x{79B4}\x{79B5}' . +'\x{79B6}\x{79B7}\x{79B8}\x{79B9}\x{79BA}\x{79BB}\x{79BD}\x{79BE}\x{79BF}' . +'\x{79C0}\x{79C1}\x{79C2}\x{79C3}\x{79C5}\x{79C6}\x{79C8}\x{79C9}\x{79CA}' . +'\x{79CB}\x{79CD}\x{79CE}\x{79CF}\x{79D0}\x{79D1}\x{79D2}\x{79D3}\x{79D5}' . +'\x{79D6}\x{79D8}\x{79D9}\x{79DA}\x{79DB}\x{79DC}\x{79DD}\x{79DE}\x{79DF}' . +'\x{79E0}\x{79E1}\x{79E2}\x{79E3}\x{79E4}\x{79E5}\x{79E6}\x{79E7}\x{79E8}' . +'\x{79E9}\x{79EA}\x{79EB}\x{79EC}\x{79ED}\x{79EE}\x{79EF}\x{79F0}\x{79F1}' . +'\x{79F2}\x{79F3}\x{79F4}\x{79F5}\x{79F6}\x{79F7}\x{79F8}\x{79F9}\x{79FA}' . +'\x{79FB}\x{79FC}\x{79FD}\x{79FE}\x{79FF}\x{7A00}\x{7A02}\x{7A03}\x{7A04}' . +'\x{7A05}\x{7A06}\x{7A08}\x{7A0A}\x{7A0B}\x{7A0C}\x{7A0D}\x{7A0E}\x{7A0F}' . +'\x{7A10}\x{7A11}\x{7A12}\x{7A13}\x{7A14}\x{7A15}\x{7A16}\x{7A17}\x{7A18}' . +'\x{7A19}\x{7A1A}\x{7A1B}\x{7A1C}\x{7A1D}\x{7A1E}\x{7A1F}\x{7A20}\x{7A21}' . +'\x{7A22}\x{7A23}\x{7A24}\x{7A25}\x{7A26}\x{7A27}\x{7A28}\x{7A29}\x{7A2A}' . +'\x{7A2B}\x{7A2D}\x{7A2E}\x{7A2F}\x{7A30}\x{7A31}\x{7A32}\x{7A33}\x{7A34}' . +'\x{7A35}\x{7A37}\x{7A39}\x{7A3B}\x{7A3C}\x{7A3D}\x{7A3E}\x{7A3F}\x{7A40}' . +'\x{7A41}\x{7A42}\x{7A43}\x{7A44}\x{7A45}\x{7A46}\x{7A47}\x{7A48}\x{7A49}' . +'\x{7A4A}\x{7A4B}\x{7A4C}\x{7A4D}\x{7A4E}\x{7A50}\x{7A51}\x{7A52}\x{7A53}' . +'\x{7A54}\x{7A55}\x{7A56}\x{7A57}\x{7A58}\x{7A59}\x{7A5A}\x{7A5B}\x{7A5C}' . +'\x{7A5D}\x{7A5E}\x{7A5F}\x{7A60}\x{7A61}\x{7A62}\x{7A65}\x{7A66}\x{7A67}' . +'\x{7A68}\x{7A69}\x{7A6B}\x{7A6C}\x{7A6D}\x{7A6E}\x{7A70}\x{7A71}\x{7A72}' . +'\x{7A73}\x{7A74}\x{7A75}\x{7A76}\x{7A77}\x{7A78}\x{7A79}\x{7A7A}\x{7A7B}' . +'\x{7A7C}\x{7A7D}\x{7A7E}\x{7A7F}\x{7A80}\x{7A81}\x{7A83}\x{7A84}\x{7A85}' . +'\x{7A86}\x{7A87}\x{7A88}\x{7A89}\x{7A8A}\x{7A8B}\x{7A8C}\x{7A8D}\x{7A8E}' . +'\x{7A8F}\x{7A90}\x{7A91}\x{7A92}\x{7A93}\x{7A94}\x{7A95}\x{7A96}\x{7A97}' . +'\x{7A98}\x{7A99}\x{7A9C}\x{7A9D}\x{7A9E}\x{7A9F}\x{7AA0}\x{7AA1}\x{7AA2}' . +'\x{7AA3}\x{7AA4}\x{7AA5}\x{7AA6}\x{7AA7}\x{7AA8}\x{7AA9}\x{7AAA}\x{7AAB}' . +'\x{7AAC}\x{7AAD}\x{7AAE}\x{7AAF}\x{7AB0}\x{7AB1}\x{7AB2}\x{7AB3}\x{7AB4}' . +'\x{7AB5}\x{7AB6}\x{7AB7}\x{7AB8}\x{7ABA}\x{7ABE}\x{7ABF}\x{7AC0}\x{7AC1}' . +'\x{7AC4}\x{7AC5}\x{7AC7}\x{7AC8}\x{7AC9}\x{7ACA}\x{7ACB}\x{7ACC}\x{7ACD}' . +'\x{7ACE}\x{7ACF}\x{7AD0}\x{7AD1}\x{7AD2}\x{7AD3}\x{7AD4}\x{7AD5}\x{7AD6}' . +'\x{7AD8}\x{7AD9}\x{7ADB}\x{7ADC}\x{7ADD}\x{7ADE}\x{7ADF}\x{7AE0}\x{7AE1}' . +'\x{7AE2}\x{7AE3}\x{7AE4}\x{7AE5}\x{7AE6}\x{7AE7}\x{7AE8}\x{7AEA}\x{7AEB}' . +'\x{7AEC}\x{7AED}\x{7AEE}\x{7AEF}\x{7AF0}\x{7AF1}\x{7AF2}\x{7AF3}\x{7AF4}' . +'\x{7AF6}\x{7AF7}\x{7AF8}\x{7AF9}\x{7AFA}\x{7AFB}\x{7AFD}\x{7AFE}\x{7AFF}' . +'\x{7B00}\x{7B01}\x{7B02}\x{7B03}\x{7B04}\x{7B05}\x{7B06}\x{7B08}\x{7B09}' . +'\x{7B0A}\x{7B0B}\x{7B0C}\x{7B0D}\x{7B0E}\x{7B0F}\x{7B10}\x{7B11}\x{7B12}' . +'\x{7B13}\x{7B14}\x{7B15}\x{7B16}\x{7B17}\x{7B18}\x{7B19}\x{7B1A}\x{7B1B}' . +'\x{7B1C}\x{7B1D}\x{7B1E}\x{7B20}\x{7B21}\x{7B22}\x{7B23}\x{7B24}\x{7B25}' . +'\x{7B26}\x{7B28}\x{7B2A}\x{7B2B}\x{7B2C}\x{7B2D}\x{7B2E}\x{7B2F}\x{7B30}' . +'\x{7B31}\x{7B32}\x{7B33}\x{7B34}\x{7B35}\x{7B36}\x{7B37}\x{7B38}\x{7B39}' . +'\x{7B3A}\x{7B3B}\x{7B3C}\x{7B3D}\x{7B3E}\x{7B3F}\x{7B40}\x{7B41}\x{7B43}' . +'\x{7B44}\x{7B45}\x{7B46}\x{7B47}\x{7B48}\x{7B49}\x{7B4A}\x{7B4B}\x{7B4C}' . +'\x{7B4D}\x{7B4E}\x{7B4F}\x{7B50}\x{7B51}\x{7B52}\x{7B54}\x{7B55}\x{7B56}' . +'\x{7B57}\x{7B58}\x{7B59}\x{7B5A}\x{7B5B}\x{7B5C}\x{7B5D}\x{7B5E}\x{7B5F}' . +'\x{7B60}\x{7B61}\x{7B62}\x{7B63}\x{7B64}\x{7B65}\x{7B66}\x{7B67}\x{7B68}' . +'\x{7B69}\x{7B6A}\x{7B6B}\x{7B6C}\x{7B6D}\x{7B6E}\x{7B70}\x{7B71}\x{7B72}' . +'\x{7B73}\x{7B74}\x{7B75}\x{7B76}\x{7B77}\x{7B78}\x{7B79}\x{7B7B}\x{7B7C}' . +'\x{7B7D}\x{7B7E}\x{7B7F}\x{7B80}\x{7B81}\x{7B82}\x{7B83}\x{7B84}\x{7B85}' . +'\x{7B87}\x{7B88}\x{7B89}\x{7B8A}\x{7B8B}\x{7B8C}\x{7B8D}\x{7B8E}\x{7B8F}' . +'\x{7B90}\x{7B91}\x{7B93}\x{7B94}\x{7B95}\x{7B96}\x{7B97}\x{7B98}\x{7B99}' . +'\x{7B9A}\x{7B9B}\x{7B9C}\x{7B9D}\x{7B9E}\x{7B9F}\x{7BA0}\x{7BA1}\x{7BA2}' . +'\x{7BA4}\x{7BA6}\x{7BA7}\x{7BA8}\x{7BA9}\x{7BAA}\x{7BAB}\x{7BAC}\x{7BAD}' . +'\x{7BAE}\x{7BAF}\x{7BB1}\x{7BB3}\x{7BB4}\x{7BB5}\x{7BB6}\x{7BB7}\x{7BB8}' . +'\x{7BB9}\x{7BBA}\x{7BBB}\x{7BBC}\x{7BBD}\x{7BBE}\x{7BBF}\x{7BC0}\x{7BC1}' . +'\x{7BC2}\x{7BC3}\x{7BC4}\x{7BC5}\x{7BC6}\x{7BC7}\x{7BC8}\x{7BC9}\x{7BCA}' . +'\x{7BCB}\x{7BCC}\x{7BCD}\x{7BCE}\x{7BD0}\x{7BD1}\x{7BD2}\x{7BD3}\x{7BD4}' . +'\x{7BD5}\x{7BD6}\x{7BD7}\x{7BD8}\x{7BD9}\x{7BDA}\x{7BDB}\x{7BDC}\x{7BDD}' . +'\x{7BDE}\x{7BDF}\x{7BE0}\x{7BE1}\x{7BE2}\x{7BE3}\x{7BE4}\x{7BE5}\x{7BE6}' . +'\x{7BE7}\x{7BE8}\x{7BE9}\x{7BEA}\x{7BEB}\x{7BEC}\x{7BED}\x{7BEE}\x{7BEF}' . +'\x{7BF0}\x{7BF1}\x{7BF2}\x{7BF3}\x{7BF4}\x{7BF5}\x{7BF6}\x{7BF7}\x{7BF8}' . +'\x{7BF9}\x{7BFB}\x{7BFC}\x{7BFD}\x{7BFE}\x{7BFF}\x{7C00}\x{7C01}\x{7C02}' . +'\x{7C03}\x{7C04}\x{7C05}\x{7C06}\x{7C07}\x{7C08}\x{7C09}\x{7C0A}\x{7C0B}' . +'\x{7C0C}\x{7C0D}\x{7C0E}\x{7C0F}\x{7C10}\x{7C11}\x{7C12}\x{7C13}\x{7C15}' . +'\x{7C16}\x{7C17}\x{7C18}\x{7C19}\x{7C1A}\x{7C1C}\x{7C1D}\x{7C1E}\x{7C1F}' . +'\x{7C20}\x{7C21}\x{7C22}\x{7C23}\x{7C24}\x{7C25}\x{7C26}\x{7C27}\x{7C28}' . +'\x{7C29}\x{7C2A}\x{7C2B}\x{7C2C}\x{7C2D}\x{7C30}\x{7C31}\x{7C32}\x{7C33}' . +'\x{7C34}\x{7C35}\x{7C36}\x{7C37}\x{7C38}\x{7C39}\x{7C3A}\x{7C3B}\x{7C3C}' . +'\x{7C3D}\x{7C3E}\x{7C3F}\x{7C40}\x{7C41}\x{7C42}\x{7C43}\x{7C44}\x{7C45}' . +'\x{7C46}\x{7C47}\x{7C48}\x{7C49}\x{7C4A}\x{7C4B}\x{7C4C}\x{7C4D}\x{7C4E}' . +'\x{7C50}\x{7C51}\x{7C53}\x{7C54}\x{7C56}\x{7C57}\x{7C58}\x{7C59}\x{7C5A}' . +'\x{7C5B}\x{7C5C}\x{7C5E}\x{7C5F}\x{7C60}\x{7C61}\x{7C62}\x{7C63}\x{7C64}' . +'\x{7C65}\x{7C66}\x{7C67}\x{7C68}\x{7C69}\x{7C6A}\x{7C6B}\x{7C6C}\x{7C6D}' . +'\x{7C6E}\x{7C6F}\x{7C70}\x{7C71}\x{7C72}\x{7C73}\x{7C74}\x{7C75}\x{7C77}' . +'\x{7C78}\x{7C79}\x{7C7A}\x{7C7B}\x{7C7C}\x{7C7D}\x{7C7E}\x{7C7F}\x{7C80}' . +'\x{7C81}\x{7C82}\x{7C84}\x{7C85}\x{7C86}\x{7C88}\x{7C89}\x{7C8A}\x{7C8B}' . +'\x{7C8C}\x{7C8D}\x{7C8E}\x{7C8F}\x{7C90}\x{7C91}\x{7C92}\x{7C94}\x{7C95}' . +'\x{7C96}\x{7C97}\x{7C98}\x{7C99}\x{7C9B}\x{7C9C}\x{7C9D}\x{7C9E}\x{7C9F}' . +'\x{7CA0}\x{7CA1}\x{7CA2}\x{7CA3}\x{7CA4}\x{7CA5}\x{7CA6}\x{7CA7}\x{7CA8}' . +'\x{7CA9}\x{7CAA}\x{7CAD}\x{7CAE}\x{7CAF}\x{7CB0}\x{7CB1}\x{7CB2}\x{7CB3}' . +'\x{7CB4}\x{7CB5}\x{7CB6}\x{7CB7}\x{7CB8}\x{7CB9}\x{7CBA}\x{7CBB}\x{7CBC}' . +'\x{7CBD}\x{7CBE}\x{7CBF}\x{7CC0}\x{7CC1}\x{7CC2}\x{7CC3}\x{7CC4}\x{7CC5}' . +'\x{7CC6}\x{7CC7}\x{7CC8}\x{7CC9}\x{7CCA}\x{7CCB}\x{7CCC}\x{7CCD}\x{7CCE}' . +'\x{7CCF}\x{7CD0}\x{7CD1}\x{7CD2}\x{7CD4}\x{7CD5}\x{7CD6}\x{7CD7}\x{7CD8}' . +'\x{7CD9}\x{7CDC}\x{7CDD}\x{7CDE}\x{7CDF}\x{7CE0}\x{7CE2}\x{7CE4}\x{7CE7}' . +'\x{7CE8}\x{7CE9}\x{7CEA}\x{7CEB}\x{7CEC}\x{7CED}\x{7CEE}\x{7CEF}\x{7CF0}' . +'\x{7CF1}\x{7CF2}\x{7CF3}\x{7CF4}\x{7CF5}\x{7CF6}\x{7CF7}\x{7CF8}\x{7CF9}' . +'\x{7CFA}\x{7CFB}\x{7CFD}\x{7CFE}\x{7D00}\x{7D01}\x{7D02}\x{7D03}\x{7D04}' . +'\x{7D05}\x{7D06}\x{7D07}\x{7D08}\x{7D09}\x{7D0A}\x{7D0B}\x{7D0C}\x{7D0D}' . +'\x{7D0E}\x{7D0F}\x{7D10}\x{7D11}\x{7D12}\x{7D13}\x{7D14}\x{7D15}\x{7D16}' . +'\x{7D17}\x{7D18}\x{7D19}\x{7D1A}\x{7D1B}\x{7D1C}\x{7D1D}\x{7D1E}\x{7D1F}' . +'\x{7D20}\x{7D21}\x{7D22}\x{7D24}\x{7D25}\x{7D26}\x{7D27}\x{7D28}\x{7D29}' . +'\x{7D2B}\x{7D2C}\x{7D2E}\x{7D2F}\x{7D30}\x{7D31}\x{7D32}\x{7D33}\x{7D34}' . +'\x{7D35}\x{7D36}\x{7D37}\x{7D38}\x{7D39}\x{7D3A}\x{7D3B}\x{7D3C}\x{7D3D}' . +'\x{7D3E}\x{7D3F}\x{7D40}\x{7D41}\x{7D42}\x{7D43}\x{7D44}\x{7D45}\x{7D46}' . +'\x{7D47}\x{7D49}\x{7D4A}\x{7D4B}\x{7D4C}\x{7D4E}\x{7D4F}\x{7D50}\x{7D51}' . +'\x{7D52}\x{7D53}\x{7D54}\x{7D55}\x{7D56}\x{7D57}\x{7D58}\x{7D59}\x{7D5B}' . +'\x{7D5C}\x{7D5D}\x{7D5E}\x{7D5F}\x{7D60}\x{7D61}\x{7D62}\x{7D63}\x{7D65}' . +'\x{7D66}\x{7D67}\x{7D68}\x{7D69}\x{7D6A}\x{7D6B}\x{7D6C}\x{7D6D}\x{7D6E}' . +'\x{7D6F}\x{7D70}\x{7D71}\x{7D72}\x{7D73}\x{7D74}\x{7D75}\x{7D76}\x{7D77}' . +'\x{7D79}\x{7D7A}\x{7D7B}\x{7D7C}\x{7D7D}\x{7D7E}\x{7D7F}\x{7D80}\x{7D81}' . +'\x{7D83}\x{7D84}\x{7D85}\x{7D86}\x{7D87}\x{7D88}\x{7D89}\x{7D8A}\x{7D8B}' . +'\x{7D8C}\x{7D8D}\x{7D8E}\x{7D8F}\x{7D90}\x{7D91}\x{7D92}\x{7D93}\x{7D94}' . +'\x{7D96}\x{7D97}\x{7D99}\x{7D9B}\x{7D9C}\x{7D9D}\x{7D9E}\x{7D9F}\x{7DA0}' . +'\x{7DA1}\x{7DA2}\x{7DA3}\x{7DA5}\x{7DA6}\x{7DA7}\x{7DA9}\x{7DAA}\x{7DAB}' . +'\x{7DAC}\x{7DAD}\x{7DAE}\x{7DAF}\x{7DB0}\x{7DB1}\x{7DB2}\x{7DB3}\x{7DB4}' . +'\x{7DB5}\x{7DB6}\x{7DB7}\x{7DB8}\x{7DB9}\x{7DBA}\x{7DBB}\x{7DBC}\x{7DBD}' . +'\x{7DBE}\x{7DBF}\x{7DC0}\x{7DC1}\x{7DC2}\x{7DC3}\x{7DC4}\x{7DC5}\x{7DC6}' . +'\x{7DC7}\x{7DC8}\x{7DC9}\x{7DCA}\x{7DCB}\x{7DCC}\x{7DCE}\x{7DCF}\x{7DD0}' . +'\x{7DD1}\x{7DD2}\x{7DD4}\x{7DD5}\x{7DD6}\x{7DD7}\x{7DD8}\x{7DD9}\x{7DDA}' . +'\x{7DDB}\x{7DDD}\x{7DDE}\x{7DDF}\x{7DE0}\x{7DE1}\x{7DE2}\x{7DE3}\x{7DE6}' . +'\x{7DE7}\x{7DE8}\x{7DE9}\x{7DEA}\x{7DEC}\x{7DED}\x{7DEE}\x{7DEF}\x{7DF0}' . +'\x{7DF1}\x{7DF2}\x{7DF3}\x{7DF4}\x{7DF5}\x{7DF6}\x{7DF7}\x{7DF8}\x{7DF9}' . +'\x{7DFA}\x{7DFB}\x{7DFC}\x{7E00}\x{7E01}\x{7E02}\x{7E03}\x{7E04}\x{7E05}' . +'\x{7E06}\x{7E07}\x{7E08}\x{7E09}\x{7E0A}\x{7E0B}\x{7E0C}\x{7E0D}\x{7E0E}' . +'\x{7E0F}\x{7E10}\x{7E11}\x{7E12}\x{7E13}\x{7E14}\x{7E15}\x{7E16}\x{7E17}' . +'\x{7E19}\x{7E1A}\x{7E1B}\x{7E1C}\x{7E1D}\x{7E1E}\x{7E1F}\x{7E20}\x{7E21}' . +'\x{7E22}\x{7E23}\x{7E24}\x{7E25}\x{7E26}\x{7E27}\x{7E28}\x{7E29}\x{7E2A}' . +'\x{7E2B}\x{7E2C}\x{7E2D}\x{7E2E}\x{7E2F}\x{7E30}\x{7E31}\x{7E32}\x{7E33}' . +'\x{7E34}\x{7E35}\x{7E36}\x{7E37}\x{7E38}\x{7E39}\x{7E3A}\x{7E3B}\x{7E3C}' . +'\x{7E3D}\x{7E3E}\x{7E3F}\x{7E40}\x{7E41}\x{7E42}\x{7E43}\x{7E44}\x{7E45}' . +'\x{7E46}\x{7E47}\x{7E48}\x{7E49}\x{7E4C}\x{7E4D}\x{7E4E}\x{7E4F}\x{7E50}' . +'\x{7E51}\x{7E52}\x{7E53}\x{7E54}\x{7E55}\x{7E56}\x{7E57}\x{7E58}\x{7E59}' . +'\x{7E5A}\x{7E5C}\x{7E5D}\x{7E5E}\x{7E5F}\x{7E60}\x{7E61}\x{7E62}\x{7E63}' . +'\x{7E65}\x{7E66}\x{7E67}\x{7E68}\x{7E69}\x{7E6A}\x{7E6B}\x{7E6C}\x{7E6D}' . +'\x{7E6E}\x{7E6F}\x{7E70}\x{7E71}\x{7E72}\x{7E73}\x{7E74}\x{7E75}\x{7E76}' . +'\x{7E77}\x{7E78}\x{7E79}\x{7E7A}\x{7E7B}\x{7E7C}\x{7E7D}\x{7E7E}\x{7E7F}' . +'\x{7E80}\x{7E81}\x{7E82}\x{7E83}\x{7E84}\x{7E85}\x{7E86}\x{7E87}\x{7E88}' . +'\x{7E89}\x{7E8A}\x{7E8B}\x{7E8C}\x{7E8D}\x{7E8E}\x{7E8F}\x{7E90}\x{7E91}' . +'\x{7E92}\x{7E93}\x{7E94}\x{7E95}\x{7E96}\x{7E97}\x{7E98}\x{7E99}\x{7E9A}' . +'\x{7E9B}\x{7E9C}\x{7E9E}\x{7E9F}\x{7EA0}\x{7EA1}\x{7EA2}\x{7EA3}\x{7EA4}' . +'\x{7EA5}\x{7EA6}\x{7EA7}\x{7EA8}\x{7EA9}\x{7EAA}\x{7EAB}\x{7EAC}\x{7EAD}' . +'\x{7EAE}\x{7EAF}\x{7EB0}\x{7EB1}\x{7EB2}\x{7EB3}\x{7EB4}\x{7EB5}\x{7EB6}' . +'\x{7EB7}\x{7EB8}\x{7EB9}\x{7EBA}\x{7EBB}\x{7EBC}\x{7EBD}\x{7EBE}\x{7EBF}' . +'\x{7EC0}\x{7EC1}\x{7EC2}\x{7EC3}\x{7EC4}\x{7EC5}\x{7EC6}\x{7EC7}\x{7EC8}' . +'\x{7EC9}\x{7ECA}\x{7ECB}\x{7ECC}\x{7ECD}\x{7ECE}\x{7ECF}\x{7ED0}\x{7ED1}' . +'\x{7ED2}\x{7ED3}\x{7ED4}\x{7ED5}\x{7ED6}\x{7ED7}\x{7ED8}\x{7ED9}\x{7EDA}' . +'\x{7EDB}\x{7EDC}\x{7EDD}\x{7EDE}\x{7EDF}\x{7EE0}\x{7EE1}\x{7EE2}\x{7EE3}' . +'\x{7EE4}\x{7EE5}\x{7EE6}\x{7EE7}\x{7EE8}\x{7EE9}\x{7EEA}\x{7EEB}\x{7EEC}' . +'\x{7EED}\x{7EEE}\x{7EEF}\x{7EF0}\x{7EF1}\x{7EF2}\x{7EF3}\x{7EF4}\x{7EF5}' . +'\x{7EF6}\x{7EF7}\x{7EF8}\x{7EF9}\x{7EFA}\x{7EFB}\x{7EFC}\x{7EFD}\x{7EFE}' . +'\x{7EFF}\x{7F00}\x{7F01}\x{7F02}\x{7F03}\x{7F04}\x{7F05}\x{7F06}\x{7F07}' . +'\x{7F08}\x{7F09}\x{7F0A}\x{7F0B}\x{7F0C}\x{7F0D}\x{7F0E}\x{7F0F}\x{7F10}' . +'\x{7F11}\x{7F12}\x{7F13}\x{7F14}\x{7F15}\x{7F16}\x{7F17}\x{7F18}\x{7F19}' . +'\x{7F1A}\x{7F1B}\x{7F1C}\x{7F1D}\x{7F1E}\x{7F1F}\x{7F20}\x{7F21}\x{7F22}' . +'\x{7F23}\x{7F24}\x{7F25}\x{7F26}\x{7F27}\x{7F28}\x{7F29}\x{7F2A}\x{7F2B}' . +'\x{7F2C}\x{7F2D}\x{7F2E}\x{7F2F}\x{7F30}\x{7F31}\x{7F32}\x{7F33}\x{7F34}' . +'\x{7F35}\x{7F36}\x{7F37}\x{7F38}\x{7F39}\x{7F3A}\x{7F3D}\x{7F3E}\x{7F3F}' . +'\x{7F40}\x{7F42}\x{7F43}\x{7F44}\x{7F45}\x{7F47}\x{7F48}\x{7F49}\x{7F4A}' . +'\x{7F4B}\x{7F4C}\x{7F4D}\x{7F4E}\x{7F4F}\x{7F50}\x{7F51}\x{7F52}\x{7F53}' . +'\x{7F54}\x{7F55}\x{7F56}\x{7F57}\x{7F58}\x{7F5A}\x{7F5B}\x{7F5C}\x{7F5D}' . +'\x{7F5E}\x{7F5F}\x{7F60}\x{7F61}\x{7F62}\x{7F63}\x{7F64}\x{7F65}\x{7F66}' . +'\x{7F67}\x{7F68}\x{7F69}\x{7F6A}\x{7F6B}\x{7F6C}\x{7F6D}\x{7F6E}\x{7F6F}' . +'\x{7F70}\x{7F71}\x{7F72}\x{7F73}\x{7F74}\x{7F75}\x{7F76}\x{7F77}\x{7F78}' . +'\x{7F79}\x{7F7A}\x{7F7B}\x{7F7C}\x{7F7D}\x{7F7E}\x{7F7F}\x{7F80}\x{7F81}' . +'\x{7F82}\x{7F83}\x{7F85}\x{7F86}\x{7F87}\x{7F88}\x{7F89}\x{7F8A}\x{7F8B}' . +'\x{7F8C}\x{7F8D}\x{7F8E}\x{7F8F}\x{7F91}\x{7F92}\x{7F93}\x{7F94}\x{7F95}' . +'\x{7F96}\x{7F98}\x{7F9A}\x{7F9B}\x{7F9C}\x{7F9D}\x{7F9E}\x{7F9F}\x{7FA0}' . +'\x{7FA1}\x{7FA2}\x{7FA3}\x{7FA4}\x{7FA5}\x{7FA6}\x{7FA7}\x{7FA8}\x{7FA9}' . +'\x{7FAA}\x{7FAB}\x{7FAC}\x{7FAD}\x{7FAE}\x{7FAF}\x{7FB0}\x{7FB1}\x{7FB2}' . +'\x{7FB3}\x{7FB5}\x{7FB6}\x{7FB7}\x{7FB8}\x{7FB9}\x{7FBA}\x{7FBB}\x{7FBC}' . +'\x{7FBD}\x{7FBE}\x{7FBF}\x{7FC0}\x{7FC1}\x{7FC2}\x{7FC3}\x{7FC4}\x{7FC5}' . +'\x{7FC6}\x{7FC7}\x{7FC8}\x{7FC9}\x{7FCA}\x{7FCB}\x{7FCC}\x{7FCD}\x{7FCE}' . +'\x{7FCF}\x{7FD0}\x{7FD1}\x{7FD2}\x{7FD3}\x{7FD4}\x{7FD5}\x{7FD7}\x{7FD8}' . +'\x{7FD9}\x{7FDA}\x{7FDB}\x{7FDC}\x{7FDE}\x{7FDF}\x{7FE0}\x{7FE1}\x{7FE2}' . +'\x{7FE3}\x{7FE5}\x{7FE6}\x{7FE7}\x{7FE8}\x{7FE9}\x{7FEA}\x{7FEB}\x{7FEC}' . +'\x{7FED}\x{7FEE}\x{7FEF}\x{7FF0}\x{7FF1}\x{7FF2}\x{7FF3}\x{7FF4}\x{7FF5}' . +'\x{7FF6}\x{7FF7}\x{7FF8}\x{7FF9}\x{7FFA}\x{7FFB}\x{7FFC}\x{7FFD}\x{7FFE}' . +'\x{7FFF}\x{8000}\x{8001}\x{8002}\x{8003}\x{8004}\x{8005}\x{8006}\x{8007}' . +'\x{8008}\x{8009}\x{800B}\x{800C}\x{800D}\x{800E}\x{800F}\x{8010}\x{8011}' . +'\x{8012}\x{8013}\x{8014}\x{8015}\x{8016}\x{8017}\x{8018}\x{8019}\x{801A}' . +'\x{801B}\x{801C}\x{801D}\x{801E}\x{801F}\x{8020}\x{8021}\x{8022}\x{8023}' . +'\x{8024}\x{8025}\x{8026}\x{8027}\x{8028}\x{8029}\x{802A}\x{802B}\x{802C}' . +'\x{802D}\x{802E}\x{8030}\x{8031}\x{8032}\x{8033}\x{8034}\x{8035}\x{8036}' . +'\x{8037}\x{8038}\x{8039}\x{803A}\x{803B}\x{803D}\x{803E}\x{803F}\x{8041}' . +'\x{8042}\x{8043}\x{8044}\x{8045}\x{8046}\x{8047}\x{8048}\x{8049}\x{804A}' . +'\x{804B}\x{804C}\x{804D}\x{804E}\x{804F}\x{8050}\x{8051}\x{8052}\x{8053}' . +'\x{8054}\x{8055}\x{8056}\x{8057}\x{8058}\x{8059}\x{805A}\x{805B}\x{805C}' . +'\x{805D}\x{805E}\x{805F}\x{8060}\x{8061}\x{8062}\x{8063}\x{8064}\x{8065}' . +'\x{8067}\x{8068}\x{8069}\x{806A}\x{806B}\x{806C}\x{806D}\x{806E}\x{806F}' . +'\x{8070}\x{8071}\x{8072}\x{8073}\x{8074}\x{8075}\x{8076}\x{8077}\x{8078}' . +'\x{8079}\x{807A}\x{807B}\x{807C}\x{807D}\x{807E}\x{807F}\x{8080}\x{8081}' . +'\x{8082}\x{8083}\x{8084}\x{8085}\x{8086}\x{8087}\x{8089}\x{808A}\x{808B}' . +'\x{808C}\x{808D}\x{808F}\x{8090}\x{8091}\x{8092}\x{8093}\x{8095}\x{8096}' . +'\x{8097}\x{8098}\x{8099}\x{809A}\x{809B}\x{809C}\x{809D}\x{809E}\x{809F}' . +'\x{80A0}\x{80A1}\x{80A2}\x{80A3}\x{80A4}\x{80A5}\x{80A9}\x{80AA}\x{80AB}' . +'\x{80AD}\x{80AE}\x{80AF}\x{80B0}\x{80B1}\x{80B2}\x{80B4}\x{80B5}\x{80B6}' . +'\x{80B7}\x{80B8}\x{80BA}\x{80BB}\x{80BC}\x{80BD}\x{80BE}\x{80BF}\x{80C0}' . +'\x{80C1}\x{80C2}\x{80C3}\x{80C4}\x{80C5}\x{80C6}\x{80C7}\x{80C8}\x{80C9}' . +'\x{80CA}\x{80CB}\x{80CC}\x{80CD}\x{80CE}\x{80CF}\x{80D0}\x{80D1}\x{80D2}' . +'\x{80D3}\x{80D4}\x{80D5}\x{80D6}\x{80D7}\x{80D8}\x{80D9}\x{80DA}\x{80DB}' . +'\x{80DC}\x{80DD}\x{80DE}\x{80E0}\x{80E1}\x{80E2}\x{80E3}\x{80E4}\x{80E5}' . +'\x{80E6}\x{80E7}\x{80E8}\x{80E9}\x{80EA}\x{80EB}\x{80EC}\x{80ED}\x{80EE}' . +'\x{80EF}\x{80F0}\x{80F1}\x{80F2}\x{80F3}\x{80F4}\x{80F5}\x{80F6}\x{80F7}' . +'\x{80F8}\x{80F9}\x{80FA}\x{80FB}\x{80FC}\x{80FD}\x{80FE}\x{80FF}\x{8100}' . +'\x{8101}\x{8102}\x{8105}\x{8106}\x{8107}\x{8108}\x{8109}\x{810A}\x{810B}' . +'\x{810C}\x{810D}\x{810E}\x{810F}\x{8110}\x{8111}\x{8112}\x{8113}\x{8114}' . +'\x{8115}\x{8116}\x{8118}\x{8119}\x{811A}\x{811B}\x{811C}\x{811D}\x{811E}' . +'\x{811F}\x{8120}\x{8121}\x{8122}\x{8123}\x{8124}\x{8125}\x{8126}\x{8127}' . +'\x{8128}\x{8129}\x{812A}\x{812B}\x{812C}\x{812D}\x{812E}\x{812F}\x{8130}' . +'\x{8131}\x{8132}\x{8136}\x{8137}\x{8138}\x{8139}\x{813A}\x{813B}\x{813C}' . +'\x{813D}\x{813E}\x{813F}\x{8140}\x{8141}\x{8142}\x{8143}\x{8144}\x{8145}' . +'\x{8146}\x{8147}\x{8148}\x{8149}\x{814A}\x{814B}\x{814C}\x{814D}\x{814E}' . +'\x{814F}\x{8150}\x{8151}\x{8152}\x{8153}\x{8154}\x{8155}\x{8156}\x{8157}' . +'\x{8158}\x{8159}\x{815A}\x{815B}\x{815C}\x{815D}\x{815E}\x{8160}\x{8161}' . +'\x{8162}\x{8163}\x{8164}\x{8165}\x{8166}\x{8167}\x{8168}\x{8169}\x{816A}' . +'\x{816B}\x{816C}\x{816D}\x{816E}\x{816F}\x{8170}\x{8171}\x{8172}\x{8173}' . +'\x{8174}\x{8175}\x{8176}\x{8177}\x{8178}\x{8179}\x{817A}\x{817B}\x{817C}' . +'\x{817D}\x{817E}\x{817F}\x{8180}\x{8181}\x{8182}\x{8183}\x{8185}\x{8186}' . +'\x{8187}\x{8188}\x{8189}\x{818A}\x{818B}\x{818C}\x{818D}\x{818E}\x{818F}' . +'\x{8191}\x{8192}\x{8193}\x{8194}\x{8195}\x{8197}\x{8198}\x{8199}\x{819A}' . +'\x{819B}\x{819C}\x{819D}\x{819E}\x{819F}\x{81A0}\x{81A1}\x{81A2}\x{81A3}' . +'\x{81A4}\x{81A5}\x{81A6}\x{81A7}\x{81A8}\x{81A9}\x{81AA}\x{81AB}\x{81AC}' . +'\x{81AD}\x{81AE}\x{81AF}\x{81B0}\x{81B1}\x{81B2}\x{81B3}\x{81B4}\x{81B5}' . +'\x{81B6}\x{81B7}\x{81B8}\x{81B9}\x{81BA}\x{81BB}\x{81BC}\x{81BD}\x{81BE}' . +'\x{81BF}\x{81C0}\x{81C1}\x{81C2}\x{81C3}\x{81C4}\x{81C5}\x{81C6}\x{81C7}' . +'\x{81C8}\x{81C9}\x{81CA}\x{81CC}\x{81CD}\x{81CE}\x{81CF}\x{81D0}\x{81D1}' . +'\x{81D2}\x{81D4}\x{81D5}\x{81D6}\x{81D7}\x{81D8}\x{81D9}\x{81DA}\x{81DB}' . +'\x{81DC}\x{81DD}\x{81DE}\x{81DF}\x{81E0}\x{81E1}\x{81E2}\x{81E3}\x{81E5}' . +'\x{81E6}\x{81E7}\x{81E8}\x{81E9}\x{81EA}\x{81EB}\x{81EC}\x{81ED}\x{81EE}' . +'\x{81F1}\x{81F2}\x{81F3}\x{81F4}\x{81F5}\x{81F6}\x{81F7}\x{81F8}\x{81F9}' . +'\x{81FA}\x{81FB}\x{81FC}\x{81FD}\x{81FE}\x{81FF}\x{8200}\x{8201}\x{8202}' . +'\x{8203}\x{8204}\x{8205}\x{8206}\x{8207}\x{8208}\x{8209}\x{820A}\x{820B}' . +'\x{820C}\x{820D}\x{820E}\x{820F}\x{8210}\x{8211}\x{8212}\x{8214}\x{8215}' . +'\x{8216}\x{8218}\x{8219}\x{821A}\x{821B}\x{821C}\x{821D}\x{821E}\x{821F}' . +'\x{8220}\x{8221}\x{8222}\x{8223}\x{8225}\x{8226}\x{8227}\x{8228}\x{8229}' . +'\x{822A}\x{822B}\x{822C}\x{822D}\x{822F}\x{8230}\x{8231}\x{8232}\x{8233}' . +'\x{8234}\x{8235}\x{8236}\x{8237}\x{8238}\x{8239}\x{823A}\x{823B}\x{823C}' . +'\x{823D}\x{823E}\x{823F}\x{8240}\x{8242}\x{8243}\x{8244}\x{8245}\x{8246}' . +'\x{8247}\x{8248}\x{8249}\x{824A}\x{824B}\x{824C}\x{824D}\x{824E}\x{824F}' . +'\x{8250}\x{8251}\x{8252}\x{8253}\x{8254}\x{8255}\x{8256}\x{8257}\x{8258}' . +'\x{8259}\x{825A}\x{825B}\x{825C}\x{825D}\x{825E}\x{825F}\x{8260}\x{8261}' . +'\x{8263}\x{8264}\x{8266}\x{8267}\x{8268}\x{8269}\x{826A}\x{826B}\x{826C}' . +'\x{826D}\x{826E}\x{826F}\x{8270}\x{8271}\x{8272}\x{8273}\x{8274}\x{8275}' . +'\x{8276}\x{8277}\x{8278}\x{8279}\x{827A}\x{827B}\x{827C}\x{827D}\x{827E}' . +'\x{827F}\x{8280}\x{8281}\x{8282}\x{8283}\x{8284}\x{8285}\x{8286}\x{8287}' . +'\x{8288}\x{8289}\x{828A}\x{828B}\x{828D}\x{828E}\x{828F}\x{8290}\x{8291}' . +'\x{8292}\x{8293}\x{8294}\x{8295}\x{8296}\x{8297}\x{8298}\x{8299}\x{829A}' . +'\x{829B}\x{829C}\x{829D}\x{829E}\x{829F}\x{82A0}\x{82A1}\x{82A2}\x{82A3}' . +'\x{82A4}\x{82A5}\x{82A6}\x{82A7}\x{82A8}\x{82A9}\x{82AA}\x{82AB}\x{82AC}' . +'\x{82AD}\x{82AE}\x{82AF}\x{82B0}\x{82B1}\x{82B3}\x{82B4}\x{82B5}\x{82B6}' . +'\x{82B7}\x{82B8}\x{82B9}\x{82BA}\x{82BB}\x{82BC}\x{82BD}\x{82BE}\x{82BF}' . +'\x{82C0}\x{82C1}\x{82C2}\x{82C3}\x{82C4}\x{82C5}\x{82C6}\x{82C7}\x{82C8}' . +'\x{82C9}\x{82CA}\x{82CB}\x{82CC}\x{82CD}\x{82CE}\x{82CF}\x{82D0}\x{82D1}' . +'\x{82D2}\x{82D3}\x{82D4}\x{82D5}\x{82D6}\x{82D7}\x{82D8}\x{82D9}\x{82DA}' . +'\x{82DB}\x{82DC}\x{82DD}\x{82DE}\x{82DF}\x{82E0}\x{82E1}\x{82E3}\x{82E4}' . +'\x{82E5}\x{82E6}\x{82E7}\x{82E8}\x{82E9}\x{82EA}\x{82EB}\x{82EC}\x{82ED}' . +'\x{82EE}\x{82EF}\x{82F0}\x{82F1}\x{82F2}\x{82F3}\x{82F4}\x{82F5}\x{82F6}' . +'\x{82F7}\x{82F8}\x{82F9}\x{82FA}\x{82FB}\x{82FD}\x{82FE}\x{82FF}\x{8300}' . +'\x{8301}\x{8302}\x{8303}\x{8304}\x{8305}\x{8306}\x{8307}\x{8308}\x{8309}' . +'\x{830B}\x{830C}\x{830D}\x{830E}\x{830F}\x{8311}\x{8312}\x{8313}\x{8314}' . +'\x{8315}\x{8316}\x{8317}\x{8318}\x{8319}\x{831A}\x{831B}\x{831C}\x{831D}' . +'\x{831E}\x{831F}\x{8320}\x{8321}\x{8322}\x{8323}\x{8324}\x{8325}\x{8326}' . +'\x{8327}\x{8328}\x{8329}\x{832A}\x{832B}\x{832C}\x{832D}\x{832E}\x{832F}' . +'\x{8331}\x{8332}\x{8333}\x{8334}\x{8335}\x{8336}\x{8337}\x{8338}\x{8339}' . +'\x{833A}\x{833B}\x{833C}\x{833D}\x{833E}\x{833F}\x{8340}\x{8341}\x{8342}' . +'\x{8343}\x{8344}\x{8345}\x{8346}\x{8347}\x{8348}\x{8349}\x{834A}\x{834B}' . +'\x{834C}\x{834D}\x{834E}\x{834F}\x{8350}\x{8351}\x{8352}\x{8353}\x{8354}' . +'\x{8356}\x{8357}\x{8358}\x{8359}\x{835A}\x{835B}\x{835C}\x{835D}\x{835E}' . +'\x{835F}\x{8360}\x{8361}\x{8362}\x{8363}\x{8364}\x{8365}\x{8366}\x{8367}' . +'\x{8368}\x{8369}\x{836A}\x{836B}\x{836C}\x{836D}\x{836E}\x{836F}\x{8370}' . +'\x{8371}\x{8372}\x{8373}\x{8374}\x{8375}\x{8376}\x{8377}\x{8378}\x{8379}' . +'\x{837A}\x{837B}\x{837C}\x{837D}\x{837E}\x{837F}\x{8380}\x{8381}\x{8382}' . +'\x{8383}\x{8384}\x{8385}\x{8386}\x{8387}\x{8388}\x{8389}\x{838A}\x{838B}' . +'\x{838C}\x{838D}\x{838E}\x{838F}\x{8390}\x{8391}\x{8392}\x{8393}\x{8394}' . +'\x{8395}\x{8396}\x{8397}\x{8398}\x{8399}\x{839A}\x{839B}\x{839C}\x{839D}' . +'\x{839E}\x{83A0}\x{83A1}\x{83A2}\x{83A3}\x{83A4}\x{83A5}\x{83A6}\x{83A7}' . +'\x{83A8}\x{83A9}\x{83AA}\x{83AB}\x{83AC}\x{83AD}\x{83AE}\x{83AF}\x{83B0}' . +'\x{83B1}\x{83B2}\x{83B3}\x{83B4}\x{83B6}\x{83B7}\x{83B8}\x{83B9}\x{83BA}' . +'\x{83BB}\x{83BC}\x{83BD}\x{83BF}\x{83C0}\x{83C1}\x{83C2}\x{83C3}\x{83C4}' . +'\x{83C5}\x{83C6}\x{83C7}\x{83C8}\x{83C9}\x{83CA}\x{83CB}\x{83CC}\x{83CD}' . +'\x{83CE}\x{83CF}\x{83D0}\x{83D1}\x{83D2}\x{83D3}\x{83D4}\x{83D5}\x{83D6}' . +'\x{83D7}\x{83D8}\x{83D9}\x{83DA}\x{83DB}\x{83DC}\x{83DD}\x{83DE}\x{83DF}' . +'\x{83E0}\x{83E1}\x{83E2}\x{83E3}\x{83E4}\x{83E5}\x{83E7}\x{83E8}\x{83E9}' . +'\x{83EA}\x{83EB}\x{83EC}\x{83EE}\x{83EF}\x{83F0}\x{83F1}\x{83F2}\x{83F3}' . +'\x{83F4}\x{83F5}\x{83F6}\x{83F7}\x{83F8}\x{83F9}\x{83FA}\x{83FB}\x{83FC}' . +'\x{83FD}\x{83FE}\x{83FF}\x{8400}\x{8401}\x{8402}\x{8403}\x{8404}\x{8405}' . +'\x{8406}\x{8407}\x{8408}\x{8409}\x{840A}\x{840B}\x{840C}\x{840D}\x{840E}' . +'\x{840F}\x{8410}\x{8411}\x{8412}\x{8413}\x{8415}\x{8418}\x{8419}\x{841A}' . +'\x{841B}\x{841C}\x{841D}\x{841E}\x{8421}\x{8422}\x{8423}\x{8424}\x{8425}' . +'\x{8426}\x{8427}\x{8428}\x{8429}\x{842A}\x{842B}\x{842C}\x{842D}\x{842E}' . +'\x{842F}\x{8430}\x{8431}\x{8432}\x{8433}\x{8434}\x{8435}\x{8436}\x{8437}' . +'\x{8438}\x{8439}\x{843A}\x{843B}\x{843C}\x{843D}\x{843E}\x{843F}\x{8440}' . +'\x{8441}\x{8442}\x{8443}\x{8444}\x{8445}\x{8446}\x{8447}\x{8448}\x{8449}' . +'\x{844A}\x{844B}\x{844C}\x{844D}\x{844E}\x{844F}\x{8450}\x{8451}\x{8452}' . +'\x{8453}\x{8454}\x{8455}\x{8456}\x{8457}\x{8459}\x{845A}\x{845B}\x{845C}' . +'\x{845D}\x{845E}\x{845F}\x{8460}\x{8461}\x{8462}\x{8463}\x{8464}\x{8465}' . +'\x{8466}\x{8467}\x{8468}\x{8469}\x{846A}\x{846B}\x{846C}\x{846D}\x{846E}' . +'\x{846F}\x{8470}\x{8471}\x{8472}\x{8473}\x{8474}\x{8475}\x{8476}\x{8477}' . +'\x{8478}\x{8479}\x{847A}\x{847B}\x{847C}\x{847D}\x{847E}\x{847F}\x{8480}' . +'\x{8481}\x{8482}\x{8484}\x{8485}\x{8486}\x{8487}\x{8488}\x{8489}\x{848A}' . +'\x{848B}\x{848C}\x{848D}\x{848E}\x{848F}\x{8490}\x{8491}\x{8492}\x{8493}' . +'\x{8494}\x{8496}\x{8497}\x{8498}\x{8499}\x{849A}\x{849B}\x{849C}\x{849D}' . +'\x{849E}\x{849F}\x{84A0}\x{84A1}\x{84A2}\x{84A3}\x{84A4}\x{84A5}\x{84A6}' . +'\x{84A7}\x{84A8}\x{84A9}\x{84AA}\x{84AB}\x{84AC}\x{84AE}\x{84AF}\x{84B0}' . +'\x{84B1}\x{84B2}\x{84B3}\x{84B4}\x{84B5}\x{84B6}\x{84B8}\x{84B9}\x{84BA}' . +'\x{84BB}\x{84BC}\x{84BD}\x{84BE}\x{84BF}\x{84C0}\x{84C1}\x{84C2}\x{84C4}' . +'\x{84C5}\x{84C6}\x{84C7}\x{84C8}\x{84C9}\x{84CA}\x{84CB}\x{84CC}\x{84CD}' . +'\x{84CE}\x{84CF}\x{84D0}\x{84D1}\x{84D2}\x{84D3}\x{84D4}\x{84D5}\x{84D6}' . +'\x{84D7}\x{84D8}\x{84D9}\x{84DB}\x{84DC}\x{84DD}\x{84DE}\x{84DF}\x{84E0}' . +'\x{84E1}\x{84E2}\x{84E3}\x{84E4}\x{84E5}\x{84E6}\x{84E7}\x{84E8}\x{84E9}' . +'\x{84EA}\x{84EB}\x{84EC}\x{84EE}\x{84EF}\x{84F0}\x{84F1}\x{84F2}\x{84F3}' . +'\x{84F4}\x{84F5}\x{84F6}\x{84F7}\x{84F8}\x{84F9}\x{84FA}\x{84FB}\x{84FC}' . +'\x{84FD}\x{84FE}\x{84FF}\x{8500}\x{8501}\x{8502}\x{8503}\x{8504}\x{8506}' . +'\x{8507}\x{8508}\x{8509}\x{850A}\x{850B}\x{850C}\x{850D}\x{850E}\x{850F}' . +'\x{8511}\x{8512}\x{8513}\x{8514}\x{8515}\x{8516}\x{8517}\x{8518}\x{8519}' . +'\x{851A}\x{851B}\x{851C}\x{851D}\x{851E}\x{851F}\x{8520}\x{8521}\x{8522}' . +'\x{8523}\x{8524}\x{8525}\x{8526}\x{8527}\x{8528}\x{8529}\x{852A}\x{852B}' . +'\x{852C}\x{852D}\x{852E}\x{852F}\x{8530}\x{8531}\x{8534}\x{8535}\x{8536}' . +'\x{8537}\x{8538}\x{8539}\x{853A}\x{853B}\x{853C}\x{853D}\x{853E}\x{853F}' . +'\x{8540}\x{8541}\x{8542}\x{8543}\x{8544}\x{8545}\x{8546}\x{8547}\x{8548}' . +'\x{8549}\x{854A}\x{854B}\x{854D}\x{854E}\x{854F}\x{8551}\x{8552}\x{8553}' . +'\x{8554}\x{8555}\x{8556}\x{8557}\x{8558}\x{8559}\x{855A}\x{855B}\x{855C}' . +'\x{855D}\x{855E}\x{855F}\x{8560}\x{8561}\x{8562}\x{8563}\x{8564}\x{8565}' . +'\x{8566}\x{8567}\x{8568}\x{8569}\x{856A}\x{856B}\x{856C}\x{856D}\x{856E}' . +'\x{856F}\x{8570}\x{8571}\x{8572}\x{8573}\x{8574}\x{8575}\x{8576}\x{8577}' . +'\x{8578}\x{8579}\x{857A}\x{857B}\x{857C}\x{857D}\x{857E}\x{8580}\x{8581}' . +'\x{8582}\x{8583}\x{8584}\x{8585}\x{8586}\x{8587}\x{8588}\x{8589}\x{858A}' . +'\x{858B}\x{858C}\x{858D}\x{858E}\x{858F}\x{8590}\x{8591}\x{8592}\x{8594}' . +'\x{8595}\x{8596}\x{8598}\x{8599}\x{859A}\x{859B}\x{859C}\x{859D}\x{859E}' . +'\x{859F}\x{85A0}\x{85A1}\x{85A2}\x{85A3}\x{85A4}\x{85A5}\x{85A6}\x{85A7}' . +'\x{85A8}\x{85A9}\x{85AA}\x{85AB}\x{85AC}\x{85AD}\x{85AE}\x{85AF}\x{85B0}' . +'\x{85B1}\x{85B3}\x{85B4}\x{85B5}\x{85B6}\x{85B7}\x{85B8}\x{85B9}\x{85BA}' . +'\x{85BC}\x{85BD}\x{85BE}\x{85BF}\x{85C0}\x{85C1}\x{85C2}\x{85C3}\x{85C4}' . +'\x{85C5}\x{85C6}\x{85C7}\x{85C8}\x{85C9}\x{85CA}\x{85CB}\x{85CD}\x{85CE}' . +'\x{85CF}\x{85D0}\x{85D1}\x{85D2}\x{85D3}\x{85D4}\x{85D5}\x{85D6}\x{85D7}' . +'\x{85D8}\x{85D9}\x{85DA}\x{85DB}\x{85DC}\x{85DD}\x{85DE}\x{85DF}\x{85E0}' . +'\x{85E1}\x{85E2}\x{85E3}\x{85E4}\x{85E5}\x{85E6}\x{85E7}\x{85E8}\x{85E9}' . +'\x{85EA}\x{85EB}\x{85EC}\x{85ED}\x{85EF}\x{85F0}\x{85F1}\x{85F2}\x{85F4}' . +'\x{85F5}\x{85F6}\x{85F7}\x{85F8}\x{85F9}\x{85FA}\x{85FB}\x{85FD}\x{85FE}' . +'\x{85FF}\x{8600}\x{8601}\x{8602}\x{8604}\x{8605}\x{8606}\x{8607}\x{8608}' . +'\x{8609}\x{860A}\x{860B}\x{860C}\x{860F}\x{8611}\x{8612}\x{8613}\x{8614}' . +'\x{8616}\x{8617}\x{8618}\x{8619}\x{861A}\x{861B}\x{861C}\x{861E}\x{861F}' . +'\x{8620}\x{8621}\x{8622}\x{8623}\x{8624}\x{8625}\x{8626}\x{8627}\x{8628}' . +'\x{8629}\x{862A}\x{862B}\x{862C}\x{862D}\x{862E}\x{862F}\x{8630}\x{8631}' . +'\x{8632}\x{8633}\x{8634}\x{8635}\x{8636}\x{8638}\x{8639}\x{863A}\x{863B}' . +'\x{863C}\x{863D}\x{863E}\x{863F}\x{8640}\x{8641}\x{8642}\x{8643}\x{8644}' . +'\x{8645}\x{8646}\x{8647}\x{8648}\x{8649}\x{864A}\x{864B}\x{864C}\x{864D}' . +'\x{864E}\x{864F}\x{8650}\x{8651}\x{8652}\x{8653}\x{8654}\x{8655}\x{8656}' . +'\x{8658}\x{8659}\x{865A}\x{865B}\x{865C}\x{865D}\x{865E}\x{865F}\x{8660}' . +'\x{8661}\x{8662}\x{8663}\x{8664}\x{8665}\x{8666}\x{8667}\x{8668}\x{8669}' . +'\x{866A}\x{866B}\x{866C}\x{866D}\x{866E}\x{866F}\x{8670}\x{8671}\x{8672}' . +'\x{8673}\x{8674}\x{8676}\x{8677}\x{8678}\x{8679}\x{867A}\x{867B}\x{867C}' . +'\x{867D}\x{867E}\x{867F}\x{8680}\x{8681}\x{8682}\x{8683}\x{8684}\x{8685}' . +'\x{8686}\x{8687}\x{8688}\x{868A}\x{868B}\x{868C}\x{868D}\x{868E}\x{868F}' . +'\x{8690}\x{8691}\x{8693}\x{8694}\x{8695}\x{8696}\x{8697}\x{8698}\x{8699}' . +'\x{869A}\x{869B}\x{869C}\x{869D}\x{869E}\x{869F}\x{86A1}\x{86A2}\x{86A3}' . +'\x{86A4}\x{86A5}\x{86A7}\x{86A8}\x{86A9}\x{86AA}\x{86AB}\x{86AC}\x{86AD}' . +'\x{86AE}\x{86AF}\x{86B0}\x{86B1}\x{86B2}\x{86B3}\x{86B4}\x{86B5}\x{86B6}' . +'\x{86B7}\x{86B8}\x{86B9}\x{86BA}\x{86BB}\x{86BC}\x{86BD}\x{86BE}\x{86BF}' . +'\x{86C0}\x{86C1}\x{86C2}\x{86C3}\x{86C4}\x{86C5}\x{86C6}\x{86C7}\x{86C8}' . +'\x{86C9}\x{86CA}\x{86CB}\x{86CC}\x{86CE}\x{86CF}\x{86D0}\x{86D1}\x{86D2}' . +'\x{86D3}\x{86D4}\x{86D6}\x{86D7}\x{86D8}\x{86D9}\x{86DA}\x{86DB}\x{86DC}' . +'\x{86DD}\x{86DE}\x{86DF}\x{86E1}\x{86E2}\x{86E3}\x{86E4}\x{86E5}\x{86E6}' . +'\x{86E8}\x{86E9}\x{86EA}\x{86EB}\x{86EC}\x{86ED}\x{86EE}\x{86EF}\x{86F0}' . +'\x{86F1}\x{86F2}\x{86F3}\x{86F4}\x{86F5}\x{86F6}\x{86F7}\x{86F8}\x{86F9}' . +'\x{86FA}\x{86FB}\x{86FC}\x{86FE}\x{86FF}\x{8700}\x{8701}\x{8702}\x{8703}' . +'\x{8704}\x{8705}\x{8706}\x{8707}\x{8708}\x{8709}\x{870A}\x{870B}\x{870C}' . +'\x{870D}\x{870E}\x{870F}\x{8710}\x{8711}\x{8712}\x{8713}\x{8714}\x{8715}' . +'\x{8716}\x{8717}\x{8718}\x{8719}\x{871A}\x{871B}\x{871C}\x{871E}\x{871F}' . +'\x{8720}\x{8721}\x{8722}\x{8723}\x{8724}\x{8725}\x{8726}\x{8727}\x{8728}' . +'\x{8729}\x{872A}\x{872B}\x{872C}\x{872D}\x{872E}\x{8730}\x{8731}\x{8732}' . +'\x{8733}\x{8734}\x{8735}\x{8736}\x{8737}\x{8738}\x{8739}\x{873A}\x{873B}' . +'\x{873C}\x{873E}\x{873F}\x{8740}\x{8741}\x{8742}\x{8743}\x{8744}\x{8746}' . +'\x{8747}\x{8748}\x{8749}\x{874A}\x{874C}\x{874D}\x{874E}\x{874F}\x{8750}' . +'\x{8751}\x{8752}\x{8753}\x{8754}\x{8755}\x{8756}\x{8757}\x{8758}\x{8759}' . +'\x{875A}\x{875B}\x{875C}\x{875D}\x{875E}\x{875F}\x{8760}\x{8761}\x{8762}' . +'\x{8763}\x{8764}\x{8765}\x{8766}\x{8767}\x{8768}\x{8769}\x{876A}\x{876B}' . +'\x{876C}\x{876D}\x{876E}\x{876F}\x{8770}\x{8772}\x{8773}\x{8774}\x{8775}' . +'\x{8776}\x{8777}\x{8778}\x{8779}\x{877A}\x{877B}\x{877C}\x{877D}\x{877E}' . +'\x{8780}\x{8781}\x{8782}\x{8783}\x{8784}\x{8785}\x{8786}\x{8787}\x{8788}' . +'\x{8789}\x{878A}\x{878B}\x{878C}\x{878D}\x{878F}\x{8790}\x{8791}\x{8792}' . +'\x{8793}\x{8794}\x{8795}\x{8796}\x{8797}\x{8798}\x{879A}\x{879B}\x{879C}' . +'\x{879D}\x{879E}\x{879F}\x{87A0}\x{87A1}\x{87A2}\x{87A3}\x{87A4}\x{87A5}' . +'\x{87A6}\x{87A7}\x{87A8}\x{87A9}\x{87AA}\x{87AB}\x{87AC}\x{87AD}\x{87AE}' . +'\x{87AF}\x{87B0}\x{87B1}\x{87B2}\x{87B3}\x{87B4}\x{87B5}\x{87B6}\x{87B7}' . +'\x{87B8}\x{87B9}\x{87BA}\x{87BB}\x{87BC}\x{87BD}\x{87BE}\x{87BF}\x{87C0}' . +'\x{87C1}\x{87C2}\x{87C3}\x{87C4}\x{87C5}\x{87C6}\x{87C7}\x{87C8}\x{87C9}' . +'\x{87CA}\x{87CB}\x{87CC}\x{87CD}\x{87CE}\x{87CF}\x{87D0}\x{87D1}\x{87D2}' . +'\x{87D3}\x{87D4}\x{87D5}\x{87D6}\x{87D7}\x{87D8}\x{87D9}\x{87DB}\x{87DC}' . +'\x{87DD}\x{87DE}\x{87DF}\x{87E0}\x{87E1}\x{87E2}\x{87E3}\x{87E4}\x{87E5}' . +'\x{87E6}\x{87E7}\x{87E8}\x{87E9}\x{87EA}\x{87EB}\x{87EC}\x{87ED}\x{87EE}' . +'\x{87EF}\x{87F1}\x{87F2}\x{87F3}\x{87F4}\x{87F5}\x{87F6}\x{87F7}\x{87F8}' . +'\x{87F9}\x{87FA}\x{87FB}\x{87FC}\x{87FD}\x{87FE}\x{87FF}\x{8800}\x{8801}' . +'\x{8802}\x{8803}\x{8804}\x{8805}\x{8806}\x{8808}\x{8809}\x{880A}\x{880B}' . +'\x{880C}\x{880D}\x{880E}\x{880F}\x{8810}\x{8811}\x{8813}\x{8814}\x{8815}' . +'\x{8816}\x{8817}\x{8818}\x{8819}\x{881A}\x{881B}\x{881C}\x{881D}\x{881E}' . +'\x{881F}\x{8820}\x{8821}\x{8822}\x{8823}\x{8824}\x{8825}\x{8826}\x{8827}' . +'\x{8828}\x{8829}\x{882A}\x{882B}\x{882C}\x{882E}\x{882F}\x{8830}\x{8831}' . +'\x{8832}\x{8833}\x{8834}\x{8835}\x{8836}\x{8837}\x{8838}\x{8839}\x{883B}' . +'\x{883C}\x{883D}\x{883E}\x{883F}\x{8840}\x{8841}\x{8842}\x{8843}\x{8844}' . +'\x{8845}\x{8846}\x{8848}\x{8849}\x{884A}\x{884B}\x{884C}\x{884D}\x{884E}' . +'\x{884F}\x{8850}\x{8851}\x{8852}\x{8853}\x{8854}\x{8855}\x{8856}\x{8857}' . +'\x{8859}\x{885A}\x{885B}\x{885D}\x{885E}\x{8860}\x{8861}\x{8862}\x{8863}' . +'\x{8864}\x{8865}\x{8866}\x{8867}\x{8868}\x{8869}\x{886A}\x{886B}\x{886C}' . +'\x{886D}\x{886E}\x{886F}\x{8870}\x{8871}\x{8872}\x{8873}\x{8874}\x{8875}' . +'\x{8876}\x{8877}\x{8878}\x{8879}\x{887B}\x{887C}\x{887D}\x{887E}\x{887F}' . +'\x{8880}\x{8881}\x{8882}\x{8883}\x{8884}\x{8885}\x{8886}\x{8887}\x{8888}' . +'\x{8889}\x{888A}\x{888B}\x{888C}\x{888D}\x{888E}\x{888F}\x{8890}\x{8891}' . +'\x{8892}\x{8893}\x{8894}\x{8895}\x{8896}\x{8897}\x{8898}\x{8899}\x{889A}' . +'\x{889B}\x{889C}\x{889D}\x{889E}\x{889F}\x{88A0}\x{88A1}\x{88A2}\x{88A3}' . +'\x{88A4}\x{88A5}\x{88A6}\x{88A7}\x{88A8}\x{88A9}\x{88AA}\x{88AB}\x{88AC}' . +'\x{88AD}\x{88AE}\x{88AF}\x{88B0}\x{88B1}\x{88B2}\x{88B3}\x{88B4}\x{88B6}' . +'\x{88B7}\x{88B8}\x{88B9}\x{88BA}\x{88BB}\x{88BC}\x{88BD}\x{88BE}\x{88BF}' . +'\x{88C0}\x{88C1}\x{88C2}\x{88C3}\x{88C4}\x{88C5}\x{88C6}\x{88C7}\x{88C8}' . +'\x{88C9}\x{88CA}\x{88CB}\x{88CC}\x{88CD}\x{88CE}\x{88CF}\x{88D0}\x{88D1}' . +'\x{88D2}\x{88D3}\x{88D4}\x{88D5}\x{88D6}\x{88D7}\x{88D8}\x{88D9}\x{88DA}' . +'\x{88DB}\x{88DC}\x{88DD}\x{88DE}\x{88DF}\x{88E0}\x{88E1}\x{88E2}\x{88E3}' . +'\x{88E4}\x{88E5}\x{88E7}\x{88E8}\x{88EA}\x{88EB}\x{88EC}\x{88EE}\x{88EF}' . +'\x{88F0}\x{88F1}\x{88F2}\x{88F3}\x{88F4}\x{88F5}\x{88F6}\x{88F7}\x{88F8}' . +'\x{88F9}\x{88FA}\x{88FB}\x{88FC}\x{88FD}\x{88FE}\x{88FF}\x{8900}\x{8901}' . +'\x{8902}\x{8904}\x{8905}\x{8906}\x{8907}\x{8908}\x{8909}\x{890A}\x{890B}' . +'\x{890C}\x{890D}\x{890E}\x{8910}\x{8911}\x{8912}\x{8913}\x{8914}\x{8915}' . +'\x{8916}\x{8917}\x{8918}\x{8919}\x{891A}\x{891B}\x{891C}\x{891D}\x{891E}' . +'\x{891F}\x{8920}\x{8921}\x{8922}\x{8923}\x{8925}\x{8926}\x{8927}\x{8928}' . +'\x{8929}\x{892A}\x{892B}\x{892C}\x{892D}\x{892E}\x{892F}\x{8930}\x{8931}' . +'\x{8932}\x{8933}\x{8934}\x{8935}\x{8936}\x{8937}\x{8938}\x{8939}\x{893A}' . +'\x{893B}\x{893C}\x{893D}\x{893E}\x{893F}\x{8940}\x{8941}\x{8942}\x{8943}' . +'\x{8944}\x{8945}\x{8946}\x{8947}\x{8948}\x{8949}\x{894A}\x{894B}\x{894C}' . +'\x{894E}\x{894F}\x{8950}\x{8951}\x{8952}\x{8953}\x{8954}\x{8955}\x{8956}' . +'\x{8957}\x{8958}\x{8959}\x{895A}\x{895B}\x{895C}\x{895D}\x{895E}\x{895F}' . +'\x{8960}\x{8961}\x{8962}\x{8963}\x{8964}\x{8966}\x{8967}\x{8968}\x{8969}' . +'\x{896A}\x{896B}\x{896C}\x{896D}\x{896E}\x{896F}\x{8970}\x{8971}\x{8972}' . +'\x{8973}\x{8974}\x{8976}\x{8977}\x{8978}\x{8979}\x{897A}\x{897B}\x{897C}' . +'\x{897E}\x{897F}\x{8980}\x{8981}\x{8982}\x{8983}\x{8984}\x{8985}\x{8986}' . +'\x{8987}\x{8988}\x{8989}\x{898A}\x{898B}\x{898C}\x{898E}\x{898F}\x{8991}' . +'\x{8992}\x{8993}\x{8995}\x{8996}\x{8997}\x{8998}\x{899A}\x{899B}\x{899C}' . +'\x{899D}\x{899E}\x{899F}\x{89A0}\x{89A1}\x{89A2}\x{89A3}\x{89A4}\x{89A5}' . +'\x{89A6}\x{89A7}\x{89A8}\x{89AA}\x{89AB}\x{89AC}\x{89AD}\x{89AE}\x{89AF}' . +'\x{89B1}\x{89B2}\x{89B3}\x{89B5}\x{89B6}\x{89B7}\x{89B8}\x{89B9}\x{89BA}' . +'\x{89BD}\x{89BE}\x{89BF}\x{89C0}\x{89C1}\x{89C2}\x{89C3}\x{89C4}\x{89C5}' . +'\x{89C6}\x{89C7}\x{89C8}\x{89C9}\x{89CA}\x{89CB}\x{89CC}\x{89CD}\x{89CE}' . +'\x{89CF}\x{89D0}\x{89D1}\x{89D2}\x{89D3}\x{89D4}\x{89D5}\x{89D6}\x{89D7}' . +'\x{89D8}\x{89D9}\x{89DA}\x{89DB}\x{89DC}\x{89DD}\x{89DE}\x{89DF}\x{89E0}' . +'\x{89E1}\x{89E2}\x{89E3}\x{89E4}\x{89E5}\x{89E6}\x{89E7}\x{89E8}\x{89E9}' . +'\x{89EA}\x{89EB}\x{89EC}\x{89ED}\x{89EF}\x{89F0}\x{89F1}\x{89F2}\x{89F3}' . +'\x{89F4}\x{89F6}\x{89F7}\x{89F8}\x{89FA}\x{89FB}\x{89FC}\x{89FE}\x{89FF}' . +'\x{8A00}\x{8A01}\x{8A02}\x{8A03}\x{8A04}\x{8A07}\x{8A08}\x{8A09}\x{8A0A}' . +'\x{8A0B}\x{8A0C}\x{8A0D}\x{8A0E}\x{8A0F}\x{8A10}\x{8A11}\x{8A12}\x{8A13}' . +'\x{8A15}\x{8A16}\x{8A17}\x{8A18}\x{8A1A}\x{8A1B}\x{8A1C}\x{8A1D}\x{8A1E}' . +'\x{8A1F}\x{8A22}\x{8A23}\x{8A24}\x{8A25}\x{8A26}\x{8A27}\x{8A28}\x{8A29}' . +'\x{8A2A}\x{8A2C}\x{8A2D}\x{8A2E}\x{8A2F}\x{8A30}\x{8A31}\x{8A32}\x{8A34}' . +'\x{8A35}\x{8A36}\x{8A37}\x{8A38}\x{8A39}\x{8A3A}\x{8A3B}\x{8A3C}\x{8A3E}' . +'\x{8A3F}\x{8A40}\x{8A41}\x{8A42}\x{8A43}\x{8A44}\x{8A45}\x{8A46}\x{8A47}' . +'\x{8A48}\x{8A49}\x{8A4A}\x{8A4C}\x{8A4D}\x{8A4E}\x{8A4F}\x{8A50}\x{8A51}' . +'\x{8A52}\x{8A53}\x{8A54}\x{8A55}\x{8A56}\x{8A57}\x{8A58}\x{8A59}\x{8A5A}' . +'\x{8A5B}\x{8A5C}\x{8A5D}\x{8A5E}\x{8A5F}\x{8A60}\x{8A61}\x{8A62}\x{8A63}' . +'\x{8A65}\x{8A66}\x{8A67}\x{8A68}\x{8A69}\x{8A6A}\x{8A6B}\x{8A6C}\x{8A6D}' . +'\x{8A6E}\x{8A6F}\x{8A70}\x{8A71}\x{8A72}\x{8A73}\x{8A74}\x{8A75}\x{8A76}' . +'\x{8A77}\x{8A79}\x{8A7A}\x{8A7B}\x{8A7C}\x{8A7E}\x{8A7F}\x{8A80}\x{8A81}' . +'\x{8A82}\x{8A83}\x{8A84}\x{8A85}\x{8A86}\x{8A87}\x{8A89}\x{8A8A}\x{8A8B}' . +'\x{8A8C}\x{8A8D}\x{8A8E}\x{8A8F}\x{8A90}\x{8A91}\x{8A92}\x{8A93}\x{8A94}' . +'\x{8A95}\x{8A96}\x{8A97}\x{8A98}\x{8A99}\x{8A9A}\x{8A9B}\x{8A9C}\x{8A9D}' . +'\x{8A9E}\x{8AA0}\x{8AA1}\x{8AA2}\x{8AA3}\x{8AA4}\x{8AA5}\x{8AA6}\x{8AA7}' . +'\x{8AA8}\x{8AA9}\x{8AAA}\x{8AAB}\x{8AAC}\x{8AAE}\x{8AB0}\x{8AB1}\x{8AB2}' . +'\x{8AB3}\x{8AB4}\x{8AB5}\x{8AB6}\x{8AB8}\x{8AB9}\x{8ABA}\x{8ABB}\x{8ABC}' . +'\x{8ABD}\x{8ABE}\x{8ABF}\x{8AC0}\x{8AC1}\x{8AC2}\x{8AC3}\x{8AC4}\x{8AC5}' . +'\x{8AC6}\x{8AC7}\x{8AC8}\x{8AC9}\x{8ACA}\x{8ACB}\x{8ACC}\x{8ACD}\x{8ACE}' . +'\x{8ACF}\x{8AD1}\x{8AD2}\x{8AD3}\x{8AD4}\x{8AD5}\x{8AD6}\x{8AD7}\x{8AD8}' . +'\x{8AD9}\x{8ADA}\x{8ADB}\x{8ADC}\x{8ADD}\x{8ADE}\x{8ADF}\x{8AE0}\x{8AE1}' . +'\x{8AE2}\x{8AE3}\x{8AE4}\x{8AE5}\x{8AE6}\x{8AE7}\x{8AE8}\x{8AE9}\x{8AEA}' . +'\x{8AEB}\x{8AED}\x{8AEE}\x{8AEF}\x{8AF0}\x{8AF1}\x{8AF2}\x{8AF3}\x{8AF4}' . +'\x{8AF5}\x{8AF6}\x{8AF7}\x{8AF8}\x{8AF9}\x{8AFA}\x{8AFB}\x{8AFC}\x{8AFD}' . +'\x{8AFE}\x{8AFF}\x{8B00}\x{8B01}\x{8B02}\x{8B03}\x{8B04}\x{8B05}\x{8B06}' . +'\x{8B07}\x{8B08}\x{8B09}\x{8B0A}\x{8B0B}\x{8B0D}\x{8B0E}\x{8B0F}\x{8B10}' . +'\x{8B11}\x{8B12}\x{8B13}\x{8B14}\x{8B15}\x{8B16}\x{8B17}\x{8B18}\x{8B19}' . +'\x{8B1A}\x{8B1B}\x{8B1C}\x{8B1D}\x{8B1E}\x{8B1F}\x{8B20}\x{8B21}\x{8B22}' . +'\x{8B23}\x{8B24}\x{8B25}\x{8B26}\x{8B27}\x{8B28}\x{8B2A}\x{8B2B}\x{8B2C}' . +'\x{8B2D}\x{8B2E}\x{8B2F}\x{8B30}\x{8B31}\x{8B33}\x{8B34}\x{8B35}\x{8B36}' . +'\x{8B37}\x{8B39}\x{8B3A}\x{8B3B}\x{8B3C}\x{8B3D}\x{8B3E}\x{8B40}\x{8B41}' . +'\x{8B42}\x{8B43}\x{8B44}\x{8B45}\x{8B46}\x{8B47}\x{8B48}\x{8B49}\x{8B4A}' . +'\x{8B4B}\x{8B4C}\x{8B4D}\x{8B4E}\x{8B4F}\x{8B50}\x{8B51}\x{8B52}\x{8B53}' . +'\x{8B54}\x{8B55}\x{8B56}\x{8B57}\x{8B58}\x{8B59}\x{8B5A}\x{8B5B}\x{8B5C}' . +'\x{8B5D}\x{8B5E}\x{8B5F}\x{8B60}\x{8B63}\x{8B64}\x{8B65}\x{8B66}\x{8B67}' . +'\x{8B68}\x{8B6A}\x{8B6B}\x{8B6C}\x{8B6D}\x{8B6E}\x{8B6F}\x{8B70}\x{8B71}' . +'\x{8B73}\x{8B74}\x{8B76}\x{8B77}\x{8B78}\x{8B79}\x{8B7A}\x{8B7B}\x{8B7D}' . +'\x{8B7E}\x{8B7F}\x{8B80}\x{8B82}\x{8B83}\x{8B84}\x{8B85}\x{8B86}\x{8B88}' . +'\x{8B89}\x{8B8A}\x{8B8B}\x{8B8C}\x{8B8E}\x{8B90}\x{8B91}\x{8B92}\x{8B93}' . +'\x{8B94}\x{8B95}\x{8B96}\x{8B97}\x{8B98}\x{8B99}\x{8B9A}\x{8B9C}\x{8B9D}' . +'\x{8B9E}\x{8B9F}\x{8BA0}\x{8BA1}\x{8BA2}\x{8BA3}\x{8BA4}\x{8BA5}\x{8BA6}' . +'\x{8BA7}\x{8BA8}\x{8BA9}\x{8BAA}\x{8BAB}\x{8BAC}\x{8BAD}\x{8BAE}\x{8BAF}' . +'\x{8BB0}\x{8BB1}\x{8BB2}\x{8BB3}\x{8BB4}\x{8BB5}\x{8BB6}\x{8BB7}\x{8BB8}' . +'\x{8BB9}\x{8BBA}\x{8BBB}\x{8BBC}\x{8BBD}\x{8BBE}\x{8BBF}\x{8BC0}\x{8BC1}' . +'\x{8BC2}\x{8BC3}\x{8BC4}\x{8BC5}\x{8BC6}\x{8BC7}\x{8BC8}\x{8BC9}\x{8BCA}' . +'\x{8BCB}\x{8BCC}\x{8BCD}\x{8BCE}\x{8BCF}\x{8BD0}\x{8BD1}\x{8BD2}\x{8BD3}' . +'\x{8BD4}\x{8BD5}\x{8BD6}\x{8BD7}\x{8BD8}\x{8BD9}\x{8BDA}\x{8BDB}\x{8BDC}' . +'\x{8BDD}\x{8BDE}\x{8BDF}\x{8BE0}\x{8BE1}\x{8BE2}\x{8BE3}\x{8BE4}\x{8BE5}' . +'\x{8BE6}\x{8BE7}\x{8BE8}\x{8BE9}\x{8BEA}\x{8BEB}\x{8BEC}\x{8BED}\x{8BEE}' . +'\x{8BEF}\x{8BF0}\x{8BF1}\x{8BF2}\x{8BF3}\x{8BF4}\x{8BF5}\x{8BF6}\x{8BF7}' . +'\x{8BF8}\x{8BF9}\x{8BFA}\x{8BFB}\x{8BFC}\x{8BFD}\x{8BFE}\x{8BFF}\x{8C00}' . +'\x{8C01}\x{8C02}\x{8C03}\x{8C04}\x{8C05}\x{8C06}\x{8C07}\x{8C08}\x{8C09}' . +'\x{8C0A}\x{8C0B}\x{8C0C}\x{8C0D}\x{8C0E}\x{8C0F}\x{8C10}\x{8C11}\x{8C12}' . +'\x{8C13}\x{8C14}\x{8C15}\x{8C16}\x{8C17}\x{8C18}\x{8C19}\x{8C1A}\x{8C1B}' . +'\x{8C1C}\x{8C1D}\x{8C1E}\x{8C1F}\x{8C20}\x{8C21}\x{8C22}\x{8C23}\x{8C24}' . +'\x{8C25}\x{8C26}\x{8C27}\x{8C28}\x{8C29}\x{8C2A}\x{8C2B}\x{8C2C}\x{8C2D}' . +'\x{8C2E}\x{8C2F}\x{8C30}\x{8C31}\x{8C32}\x{8C33}\x{8C34}\x{8C35}\x{8C36}' . +'\x{8C37}\x{8C39}\x{8C3A}\x{8C3B}\x{8C3C}\x{8C3D}\x{8C3E}\x{8C3F}\x{8C41}' . +'\x{8C42}\x{8C43}\x{8C45}\x{8C46}\x{8C47}\x{8C48}\x{8C49}\x{8C4A}\x{8C4B}' . +'\x{8C4C}\x{8C4D}\x{8C4E}\x{8C4F}\x{8C50}\x{8C54}\x{8C55}\x{8C56}\x{8C57}' . +'\x{8C59}\x{8C5A}\x{8C5B}\x{8C5C}\x{8C5D}\x{8C5E}\x{8C5F}\x{8C60}\x{8C61}' . +'\x{8C62}\x{8C63}\x{8C64}\x{8C65}\x{8C66}\x{8C67}\x{8C68}\x{8C69}\x{8C6A}' . +'\x{8C6B}\x{8C6C}\x{8C6D}\x{8C6E}\x{8C6F}\x{8C70}\x{8C71}\x{8C72}\x{8C73}' . +'\x{8C75}\x{8C76}\x{8C77}\x{8C78}\x{8C79}\x{8C7A}\x{8C7B}\x{8C7D}\x{8C7E}' . +'\x{8C80}\x{8C81}\x{8C82}\x{8C84}\x{8C85}\x{8C86}\x{8C88}\x{8C89}\x{8C8A}' . +'\x{8C8C}\x{8C8D}\x{8C8F}\x{8C90}\x{8C91}\x{8C92}\x{8C93}\x{8C94}\x{8C95}' . +'\x{8C96}\x{8C97}\x{8C98}\x{8C99}\x{8C9A}\x{8C9C}\x{8C9D}\x{8C9E}\x{8C9F}' . +'\x{8CA0}\x{8CA1}\x{8CA2}\x{8CA3}\x{8CA4}\x{8CA5}\x{8CA7}\x{8CA8}\x{8CA9}' . +'\x{8CAA}\x{8CAB}\x{8CAC}\x{8CAD}\x{8CAE}\x{8CAF}\x{8CB0}\x{8CB1}\x{8CB2}' . +'\x{8CB3}\x{8CB4}\x{8CB5}\x{8CB6}\x{8CB7}\x{8CB8}\x{8CB9}\x{8CBA}\x{8CBB}' . +'\x{8CBC}\x{8CBD}\x{8CBE}\x{8CBF}\x{8CC0}\x{8CC1}\x{8CC2}\x{8CC3}\x{8CC4}' . +'\x{8CC5}\x{8CC6}\x{8CC7}\x{8CC8}\x{8CC9}\x{8CCA}\x{8CCC}\x{8CCE}\x{8CCF}' . +'\x{8CD0}\x{8CD1}\x{8CD2}\x{8CD3}\x{8CD4}\x{8CD5}\x{8CD7}\x{8CD9}\x{8CDA}' . +'\x{8CDB}\x{8CDC}\x{8CDD}\x{8CDE}\x{8CDF}\x{8CE0}\x{8CE1}\x{8CE2}\x{8CE3}' . +'\x{8CE4}\x{8CE5}\x{8CE6}\x{8CE7}\x{8CE8}\x{8CEA}\x{8CEB}\x{8CEC}\x{8CED}' . +'\x{8CEE}\x{8CEF}\x{8CF0}\x{8CF1}\x{8CF2}\x{8CF3}\x{8CF4}\x{8CF5}\x{8CF6}' . +'\x{8CF8}\x{8CF9}\x{8CFA}\x{8CFB}\x{8CFC}\x{8CFD}\x{8CFE}\x{8CFF}\x{8D00}' . +'\x{8D02}\x{8D03}\x{8D04}\x{8D05}\x{8D06}\x{8D07}\x{8D08}\x{8D09}\x{8D0A}' . +'\x{8D0B}\x{8D0C}\x{8D0D}\x{8D0E}\x{8D0F}\x{8D10}\x{8D13}\x{8D14}\x{8D15}' . +'\x{8D16}\x{8D17}\x{8D18}\x{8D19}\x{8D1A}\x{8D1B}\x{8D1C}\x{8D1D}\x{8D1E}' . +'\x{8D1F}\x{8D20}\x{8D21}\x{8D22}\x{8D23}\x{8D24}\x{8D25}\x{8D26}\x{8D27}' . +'\x{8D28}\x{8D29}\x{8D2A}\x{8D2B}\x{8D2C}\x{8D2D}\x{8D2E}\x{8D2F}\x{8D30}' . +'\x{8D31}\x{8D32}\x{8D33}\x{8D34}\x{8D35}\x{8D36}\x{8D37}\x{8D38}\x{8D39}' . +'\x{8D3A}\x{8D3B}\x{8D3C}\x{8D3D}\x{8D3E}\x{8D3F}\x{8D40}\x{8D41}\x{8D42}' . +'\x{8D43}\x{8D44}\x{8D45}\x{8D46}\x{8D47}\x{8D48}\x{8D49}\x{8D4A}\x{8D4B}' . +'\x{8D4C}\x{8D4D}\x{8D4E}\x{8D4F}\x{8D50}\x{8D51}\x{8D52}\x{8D53}\x{8D54}' . +'\x{8D55}\x{8D56}\x{8D57}\x{8D58}\x{8D59}\x{8D5A}\x{8D5B}\x{8D5C}\x{8D5D}' . +'\x{8D5E}\x{8D5F}\x{8D60}\x{8D61}\x{8D62}\x{8D63}\x{8D64}\x{8D65}\x{8D66}' . +'\x{8D67}\x{8D68}\x{8D69}\x{8D6A}\x{8D6B}\x{8D6C}\x{8D6D}\x{8D6E}\x{8D6F}' . +'\x{8D70}\x{8D71}\x{8D72}\x{8D73}\x{8D74}\x{8D75}\x{8D76}\x{8D77}\x{8D78}' . +'\x{8D79}\x{8D7A}\x{8D7B}\x{8D7D}\x{8D7E}\x{8D7F}\x{8D80}\x{8D81}\x{8D82}' . +'\x{8D83}\x{8D84}\x{8D85}\x{8D86}\x{8D87}\x{8D88}\x{8D89}\x{8D8A}\x{8D8B}' . +'\x{8D8C}\x{8D8D}\x{8D8E}\x{8D8F}\x{8D90}\x{8D91}\x{8D92}\x{8D93}\x{8D94}' . +'\x{8D95}\x{8D96}\x{8D97}\x{8D98}\x{8D99}\x{8D9A}\x{8D9B}\x{8D9C}\x{8D9D}' . +'\x{8D9E}\x{8D9F}\x{8DA0}\x{8DA1}\x{8DA2}\x{8DA3}\x{8DA4}\x{8DA5}\x{8DA7}' . +'\x{8DA8}\x{8DA9}\x{8DAA}\x{8DAB}\x{8DAC}\x{8DAD}\x{8DAE}\x{8DAF}\x{8DB0}' . +'\x{8DB1}\x{8DB2}\x{8DB3}\x{8DB4}\x{8DB5}\x{8DB6}\x{8DB7}\x{8DB8}\x{8DB9}' . +'\x{8DBA}\x{8DBB}\x{8DBC}\x{8DBD}\x{8DBE}\x{8DBF}\x{8DC1}\x{8DC2}\x{8DC3}' . +'\x{8DC4}\x{8DC5}\x{8DC6}\x{8DC7}\x{8DC8}\x{8DC9}\x{8DCA}\x{8DCB}\x{8DCC}' . +'\x{8DCD}\x{8DCE}\x{8DCF}\x{8DD0}\x{8DD1}\x{8DD2}\x{8DD3}\x{8DD4}\x{8DD5}' . +'\x{8DD6}\x{8DD7}\x{8DD8}\x{8DD9}\x{8DDA}\x{8DDB}\x{8DDC}\x{8DDD}\x{8DDE}' . +'\x{8DDF}\x{8DE0}\x{8DE1}\x{8DE2}\x{8DE3}\x{8DE4}\x{8DE6}\x{8DE7}\x{8DE8}' . +'\x{8DE9}\x{8DEA}\x{8DEB}\x{8DEC}\x{8DED}\x{8DEE}\x{8DEF}\x{8DF0}\x{8DF1}' . +'\x{8DF2}\x{8DF3}\x{8DF4}\x{8DF5}\x{8DF6}\x{8DF7}\x{8DF8}\x{8DF9}\x{8DFA}' . +'\x{8DFB}\x{8DFC}\x{8DFD}\x{8DFE}\x{8DFF}\x{8E00}\x{8E02}\x{8E03}\x{8E04}' . +'\x{8E05}\x{8E06}\x{8E07}\x{8E08}\x{8E09}\x{8E0A}\x{8E0C}\x{8E0D}\x{8E0E}' . +'\x{8E0F}\x{8E10}\x{8E11}\x{8E12}\x{8E13}\x{8E14}\x{8E15}\x{8E16}\x{8E17}' . +'\x{8E18}\x{8E19}\x{8E1A}\x{8E1B}\x{8E1C}\x{8E1D}\x{8E1E}\x{8E1F}\x{8E20}' . +'\x{8E21}\x{8E22}\x{8E23}\x{8E24}\x{8E25}\x{8E26}\x{8E27}\x{8E28}\x{8E29}' . +'\x{8E2A}\x{8E2B}\x{8E2C}\x{8E2D}\x{8E2E}\x{8E2F}\x{8E30}\x{8E31}\x{8E33}' . +'\x{8E34}\x{8E35}\x{8E36}\x{8E37}\x{8E38}\x{8E39}\x{8E3A}\x{8E3B}\x{8E3C}' . +'\x{8E3D}\x{8E3E}\x{8E3F}\x{8E40}\x{8E41}\x{8E42}\x{8E43}\x{8E44}\x{8E45}' . +'\x{8E47}\x{8E48}\x{8E49}\x{8E4A}\x{8E4B}\x{8E4C}\x{8E4D}\x{8E4E}\x{8E50}' . +'\x{8E51}\x{8E52}\x{8E53}\x{8E54}\x{8E55}\x{8E56}\x{8E57}\x{8E58}\x{8E59}' . +'\x{8E5A}\x{8E5B}\x{8E5C}\x{8E5D}\x{8E5E}\x{8E5F}\x{8E60}\x{8E61}\x{8E62}' . +'\x{8E63}\x{8E64}\x{8E65}\x{8E66}\x{8E67}\x{8E68}\x{8E69}\x{8E6A}\x{8E6B}' . +'\x{8E6C}\x{8E6D}\x{8E6F}\x{8E70}\x{8E71}\x{8E72}\x{8E73}\x{8E74}\x{8E76}' . +'\x{8E78}\x{8E7A}\x{8E7B}\x{8E7C}\x{8E7D}\x{8E7E}\x{8E7F}\x{8E80}\x{8E81}' . +'\x{8E82}\x{8E83}\x{8E84}\x{8E85}\x{8E86}\x{8E87}\x{8E88}\x{8E89}\x{8E8A}' . +'\x{8E8B}\x{8E8C}\x{8E8D}\x{8E8E}\x{8E8F}\x{8E90}\x{8E91}\x{8E92}\x{8E93}' . +'\x{8E94}\x{8E95}\x{8E96}\x{8E97}\x{8E98}\x{8E9A}\x{8E9C}\x{8E9D}\x{8E9E}' . +'\x{8E9F}\x{8EA0}\x{8EA1}\x{8EA3}\x{8EA4}\x{8EA5}\x{8EA6}\x{8EA7}\x{8EA8}' . +'\x{8EA9}\x{8EAA}\x{8EAB}\x{8EAC}\x{8EAD}\x{8EAE}\x{8EAF}\x{8EB0}\x{8EB1}' . +'\x{8EB2}\x{8EB4}\x{8EB5}\x{8EB8}\x{8EB9}\x{8EBA}\x{8EBB}\x{8EBC}\x{8EBD}' . +'\x{8EBE}\x{8EBF}\x{8EC0}\x{8EC2}\x{8EC3}\x{8EC5}\x{8EC6}\x{8EC7}\x{8EC8}' . +'\x{8EC9}\x{8ECA}\x{8ECB}\x{8ECC}\x{8ECD}\x{8ECE}\x{8ECF}\x{8ED0}\x{8ED1}' . +'\x{8ED2}\x{8ED3}\x{8ED4}\x{8ED5}\x{8ED6}\x{8ED7}\x{8ED8}\x{8EDA}\x{8EDB}' . +'\x{8EDC}\x{8EDD}\x{8EDE}\x{8EDF}\x{8EE0}\x{8EE1}\x{8EE4}\x{8EE5}\x{8EE6}' . +'\x{8EE7}\x{8EE8}\x{8EE9}\x{8EEA}\x{8EEB}\x{8EEC}\x{8EED}\x{8EEE}\x{8EEF}' . +'\x{8EF1}\x{8EF2}\x{8EF3}\x{8EF4}\x{8EF5}\x{8EF6}\x{8EF7}\x{8EF8}\x{8EF9}' . +'\x{8EFA}\x{8EFB}\x{8EFC}\x{8EFD}\x{8EFE}\x{8EFF}\x{8F00}\x{8F01}\x{8F02}' . +'\x{8F03}\x{8F04}\x{8F05}\x{8F06}\x{8F07}\x{8F08}\x{8F09}\x{8F0A}\x{8F0B}' . +'\x{8F0D}\x{8F0E}\x{8F10}\x{8F11}\x{8F12}\x{8F13}\x{8F14}\x{8F15}\x{8F16}' . +'\x{8F17}\x{8F18}\x{8F1A}\x{8F1B}\x{8F1C}\x{8F1D}\x{8F1E}\x{8F1F}\x{8F20}' . +'\x{8F21}\x{8F22}\x{8F23}\x{8F24}\x{8F25}\x{8F26}\x{8F27}\x{8F28}\x{8F29}' . +'\x{8F2A}\x{8F2B}\x{8F2C}\x{8F2E}\x{8F2F}\x{8F30}\x{8F31}\x{8F32}\x{8F33}' . +'\x{8F34}\x{8F35}\x{8F36}\x{8F37}\x{8F38}\x{8F39}\x{8F3B}\x{8F3C}\x{8F3D}' . +'\x{8F3E}\x{8F3F}\x{8F40}\x{8F42}\x{8F43}\x{8F44}\x{8F45}\x{8F46}\x{8F47}' . +'\x{8F48}\x{8F49}\x{8F4A}\x{8F4B}\x{8F4C}\x{8F4D}\x{8F4E}\x{8F4F}\x{8F50}' . +'\x{8F51}\x{8F52}\x{8F53}\x{8F54}\x{8F55}\x{8F56}\x{8F57}\x{8F58}\x{8F59}' . +'\x{8F5A}\x{8F5B}\x{8F5D}\x{8F5E}\x{8F5F}\x{8F60}\x{8F61}\x{8F62}\x{8F63}' . +'\x{8F64}\x{8F65}\x{8F66}\x{8F67}\x{8F68}\x{8F69}\x{8F6A}\x{8F6B}\x{8F6C}' . +'\x{8F6D}\x{8F6E}\x{8F6F}\x{8F70}\x{8F71}\x{8F72}\x{8F73}\x{8F74}\x{8F75}' . +'\x{8F76}\x{8F77}\x{8F78}\x{8F79}\x{8F7A}\x{8F7B}\x{8F7C}\x{8F7D}\x{8F7E}' . +'\x{8F7F}\x{8F80}\x{8F81}\x{8F82}\x{8F83}\x{8F84}\x{8F85}\x{8F86}\x{8F87}' . +'\x{8F88}\x{8F89}\x{8F8A}\x{8F8B}\x{8F8C}\x{8F8D}\x{8F8E}\x{8F8F}\x{8F90}' . +'\x{8F91}\x{8F92}\x{8F93}\x{8F94}\x{8F95}\x{8F96}\x{8F97}\x{8F98}\x{8F99}' . +'\x{8F9A}\x{8F9B}\x{8F9C}\x{8F9E}\x{8F9F}\x{8FA0}\x{8FA1}\x{8FA2}\x{8FA3}' . +'\x{8FA5}\x{8FA6}\x{8FA7}\x{8FA8}\x{8FA9}\x{8FAA}\x{8FAB}\x{8FAC}\x{8FAD}' . +'\x{8FAE}\x{8FAF}\x{8FB0}\x{8FB1}\x{8FB2}\x{8FB4}\x{8FB5}\x{8FB6}\x{8FB7}' . +'\x{8FB8}\x{8FB9}\x{8FBB}\x{8FBC}\x{8FBD}\x{8FBE}\x{8FBF}\x{8FC0}\x{8FC1}' . +'\x{8FC2}\x{8FC4}\x{8FC5}\x{8FC6}\x{8FC7}\x{8FC8}\x{8FC9}\x{8FCB}\x{8FCC}' . +'\x{8FCD}\x{8FCE}\x{8FCF}\x{8FD0}\x{8FD1}\x{8FD2}\x{8FD3}\x{8FD4}\x{8FD5}' . +'\x{8FD6}\x{8FD7}\x{8FD8}\x{8FD9}\x{8FDA}\x{8FDB}\x{8FDC}\x{8FDD}\x{8FDE}' . +'\x{8FDF}\x{8FE0}\x{8FE1}\x{8FE2}\x{8FE3}\x{8FE4}\x{8FE5}\x{8FE6}\x{8FE8}' . +'\x{8FE9}\x{8FEA}\x{8FEB}\x{8FEC}\x{8FED}\x{8FEE}\x{8FEF}\x{8FF0}\x{8FF1}' . +'\x{8FF2}\x{8FF3}\x{8FF4}\x{8FF5}\x{8FF6}\x{8FF7}\x{8FF8}\x{8FF9}\x{8FFA}' . +'\x{8FFB}\x{8FFC}\x{8FFD}\x{8FFE}\x{8FFF}\x{9000}\x{9001}\x{9002}\x{9003}' . +'\x{9004}\x{9005}\x{9006}\x{9007}\x{9008}\x{9009}\x{900A}\x{900B}\x{900C}' . +'\x{900D}\x{900F}\x{9010}\x{9011}\x{9012}\x{9013}\x{9014}\x{9015}\x{9016}' . +'\x{9017}\x{9018}\x{9019}\x{901A}\x{901B}\x{901C}\x{901D}\x{901E}\x{901F}' . +'\x{9020}\x{9021}\x{9022}\x{9023}\x{9024}\x{9025}\x{9026}\x{9027}\x{9028}' . +'\x{9029}\x{902B}\x{902D}\x{902E}\x{902F}\x{9030}\x{9031}\x{9032}\x{9033}' . +'\x{9034}\x{9035}\x{9036}\x{9038}\x{903A}\x{903B}\x{903C}\x{903D}\x{903E}' . +'\x{903F}\x{9041}\x{9042}\x{9043}\x{9044}\x{9045}\x{9047}\x{9048}\x{9049}' . +'\x{904A}\x{904B}\x{904C}\x{904D}\x{904E}\x{904F}\x{9050}\x{9051}\x{9052}' . +'\x{9053}\x{9054}\x{9055}\x{9056}\x{9057}\x{9058}\x{9059}\x{905A}\x{905B}' . +'\x{905C}\x{905D}\x{905E}\x{905F}\x{9060}\x{9061}\x{9062}\x{9063}\x{9064}' . +'\x{9065}\x{9066}\x{9067}\x{9068}\x{9069}\x{906A}\x{906B}\x{906C}\x{906D}' . +'\x{906E}\x{906F}\x{9070}\x{9071}\x{9072}\x{9073}\x{9074}\x{9075}\x{9076}' . +'\x{9077}\x{9078}\x{9079}\x{907A}\x{907B}\x{907C}\x{907D}\x{907E}\x{907F}' . +'\x{9080}\x{9081}\x{9082}\x{9083}\x{9084}\x{9085}\x{9086}\x{9087}\x{9088}' . +'\x{9089}\x{908A}\x{908B}\x{908C}\x{908D}\x{908E}\x{908F}\x{9090}\x{9091}' . +'\x{9092}\x{9093}\x{9094}\x{9095}\x{9096}\x{9097}\x{9098}\x{9099}\x{909A}' . +'\x{909B}\x{909C}\x{909D}\x{909E}\x{909F}\x{90A0}\x{90A1}\x{90A2}\x{90A3}' . +'\x{90A4}\x{90A5}\x{90A6}\x{90A7}\x{90A8}\x{90A9}\x{90AA}\x{90AC}\x{90AD}' . +'\x{90AE}\x{90AF}\x{90B0}\x{90B1}\x{90B2}\x{90B3}\x{90B4}\x{90B5}\x{90B6}' . +'\x{90B7}\x{90B8}\x{90B9}\x{90BA}\x{90BB}\x{90BC}\x{90BD}\x{90BE}\x{90BF}' . +'\x{90C0}\x{90C1}\x{90C2}\x{90C3}\x{90C4}\x{90C5}\x{90C6}\x{90C7}\x{90C8}' . +'\x{90C9}\x{90CA}\x{90CB}\x{90CE}\x{90CF}\x{90D0}\x{90D1}\x{90D3}\x{90D4}' . +'\x{90D5}\x{90D6}\x{90D7}\x{90D8}\x{90D9}\x{90DA}\x{90DB}\x{90DC}\x{90DD}' . +'\x{90DE}\x{90DF}\x{90E0}\x{90E1}\x{90E2}\x{90E3}\x{90E4}\x{90E5}\x{90E6}' . +'\x{90E7}\x{90E8}\x{90E9}\x{90EA}\x{90EB}\x{90EC}\x{90ED}\x{90EE}\x{90EF}' . +'\x{90F0}\x{90F1}\x{90F2}\x{90F3}\x{90F4}\x{90F5}\x{90F7}\x{90F8}\x{90F9}' . +'\x{90FA}\x{90FB}\x{90FC}\x{90FD}\x{90FE}\x{90FF}\x{9100}\x{9101}\x{9102}' . +'\x{9103}\x{9104}\x{9105}\x{9106}\x{9107}\x{9108}\x{9109}\x{910B}\x{910C}' . +'\x{910D}\x{910E}\x{910F}\x{9110}\x{9111}\x{9112}\x{9113}\x{9114}\x{9115}' . +'\x{9116}\x{9117}\x{9118}\x{9119}\x{911A}\x{911B}\x{911C}\x{911D}\x{911E}' . +'\x{911F}\x{9120}\x{9121}\x{9122}\x{9123}\x{9124}\x{9125}\x{9126}\x{9127}' . +'\x{9128}\x{9129}\x{912A}\x{912B}\x{912C}\x{912D}\x{912E}\x{912F}\x{9130}' . +'\x{9131}\x{9132}\x{9133}\x{9134}\x{9135}\x{9136}\x{9137}\x{9138}\x{9139}' . +'\x{913A}\x{913B}\x{913E}\x{913F}\x{9140}\x{9141}\x{9142}\x{9143}\x{9144}' . +'\x{9145}\x{9146}\x{9147}\x{9148}\x{9149}\x{914A}\x{914B}\x{914C}\x{914D}' . +'\x{914E}\x{914F}\x{9150}\x{9151}\x{9152}\x{9153}\x{9154}\x{9155}\x{9156}' . +'\x{9157}\x{9158}\x{915A}\x{915B}\x{915C}\x{915D}\x{915E}\x{915F}\x{9160}' . +'\x{9161}\x{9162}\x{9163}\x{9164}\x{9165}\x{9166}\x{9167}\x{9168}\x{9169}' . +'\x{916A}\x{916B}\x{916C}\x{916D}\x{916E}\x{916F}\x{9170}\x{9171}\x{9172}' . +'\x{9173}\x{9174}\x{9175}\x{9176}\x{9177}\x{9178}\x{9179}\x{917A}\x{917C}' . +'\x{917D}\x{917E}\x{917F}\x{9180}\x{9181}\x{9182}\x{9183}\x{9184}\x{9185}' . +'\x{9186}\x{9187}\x{9188}\x{9189}\x{918A}\x{918B}\x{918C}\x{918D}\x{918E}' . +'\x{918F}\x{9190}\x{9191}\x{9192}\x{9193}\x{9194}\x{9196}\x{9199}\x{919A}' . +'\x{919B}\x{919C}\x{919D}\x{919E}\x{919F}\x{91A0}\x{91A1}\x{91A2}\x{91A3}' . +'\x{91A5}\x{91A6}\x{91A7}\x{91A8}\x{91AA}\x{91AB}\x{91AC}\x{91AD}\x{91AE}' . +'\x{91AF}\x{91B0}\x{91B1}\x{91B2}\x{91B3}\x{91B4}\x{91B5}\x{91B6}\x{91B7}' . +'\x{91B9}\x{91BA}\x{91BB}\x{91BC}\x{91BD}\x{91BE}\x{91C0}\x{91C1}\x{91C2}' . +'\x{91C3}\x{91C5}\x{91C6}\x{91C7}\x{91C9}\x{91CA}\x{91CB}\x{91CC}\x{91CD}' . +'\x{91CE}\x{91CF}\x{91D0}\x{91D1}\x{91D2}\x{91D3}\x{91D4}\x{91D5}\x{91D7}' . +'\x{91D8}\x{91D9}\x{91DA}\x{91DB}\x{91DC}\x{91DD}\x{91DE}\x{91DF}\x{91E2}' . +'\x{91E3}\x{91E4}\x{91E5}\x{91E6}\x{91E7}\x{91E8}\x{91E9}\x{91EA}\x{91EB}' . +'\x{91EC}\x{91ED}\x{91EE}\x{91F0}\x{91F1}\x{91F2}\x{91F3}\x{91F4}\x{91F5}' . +'\x{91F7}\x{91F8}\x{91F9}\x{91FA}\x{91FB}\x{91FD}\x{91FE}\x{91FF}\x{9200}' . +'\x{9201}\x{9202}\x{9203}\x{9204}\x{9205}\x{9206}\x{9207}\x{9208}\x{9209}' . +'\x{920A}\x{920B}\x{920C}\x{920D}\x{920E}\x{920F}\x{9210}\x{9211}\x{9212}' . +'\x{9214}\x{9215}\x{9216}\x{9217}\x{9218}\x{9219}\x{921A}\x{921B}\x{921C}' . +'\x{921D}\x{921E}\x{9220}\x{9221}\x{9223}\x{9224}\x{9225}\x{9226}\x{9227}' . +'\x{9228}\x{9229}\x{922A}\x{922B}\x{922D}\x{922E}\x{922F}\x{9230}\x{9231}' . +'\x{9232}\x{9233}\x{9234}\x{9235}\x{9236}\x{9237}\x{9238}\x{9239}\x{923A}' . +'\x{923B}\x{923C}\x{923D}\x{923E}\x{923F}\x{9240}\x{9241}\x{9242}\x{9245}' . +'\x{9246}\x{9247}\x{9248}\x{9249}\x{924A}\x{924B}\x{924C}\x{924D}\x{924E}' . +'\x{924F}\x{9250}\x{9251}\x{9252}\x{9253}\x{9254}\x{9255}\x{9256}\x{9257}' . +'\x{9258}\x{9259}\x{925A}\x{925B}\x{925C}\x{925D}\x{925E}\x{925F}\x{9260}' . +'\x{9261}\x{9262}\x{9263}\x{9264}\x{9265}\x{9266}\x{9267}\x{9268}\x{926B}' . +'\x{926C}\x{926D}\x{926E}\x{926F}\x{9270}\x{9272}\x{9273}\x{9274}\x{9275}' . +'\x{9276}\x{9277}\x{9278}\x{9279}\x{927A}\x{927B}\x{927C}\x{927D}\x{927E}' . +'\x{927F}\x{9280}\x{9282}\x{9283}\x{9285}\x{9286}\x{9287}\x{9288}\x{9289}' . +'\x{928A}\x{928B}\x{928C}\x{928D}\x{928E}\x{928F}\x{9290}\x{9291}\x{9292}' . +'\x{9293}\x{9294}\x{9295}\x{9296}\x{9297}\x{9298}\x{9299}\x{929A}\x{929B}' . +'\x{929C}\x{929D}\x{929F}\x{92A0}\x{92A1}\x{92A2}\x{92A3}\x{92A4}\x{92A5}' . +'\x{92A6}\x{92A7}\x{92A8}\x{92A9}\x{92AA}\x{92AB}\x{92AC}\x{92AD}\x{92AE}' . +'\x{92AF}\x{92B0}\x{92B1}\x{92B2}\x{92B3}\x{92B4}\x{92B5}\x{92B6}\x{92B7}' . +'\x{92B8}\x{92B9}\x{92BA}\x{92BB}\x{92BC}\x{92BE}\x{92BF}\x{92C0}\x{92C1}' . +'\x{92C2}\x{92C3}\x{92C4}\x{92C5}\x{92C6}\x{92C7}\x{92C8}\x{92C9}\x{92CA}' . +'\x{92CB}\x{92CC}\x{92CD}\x{92CE}\x{92CF}\x{92D0}\x{92D1}\x{92D2}\x{92D3}' . +'\x{92D5}\x{92D6}\x{92D7}\x{92D8}\x{92D9}\x{92DA}\x{92DC}\x{92DD}\x{92DE}' . +'\x{92DF}\x{92E0}\x{92E1}\x{92E3}\x{92E4}\x{92E5}\x{92E6}\x{92E7}\x{92E8}' . +'\x{92E9}\x{92EA}\x{92EB}\x{92EC}\x{92ED}\x{92EE}\x{92EF}\x{92F0}\x{92F1}' . +'\x{92F2}\x{92F3}\x{92F4}\x{92F5}\x{92F6}\x{92F7}\x{92F8}\x{92F9}\x{92FA}' . +'\x{92FB}\x{92FC}\x{92FD}\x{92FE}\x{92FF}\x{9300}\x{9301}\x{9302}\x{9303}' . +'\x{9304}\x{9305}\x{9306}\x{9307}\x{9308}\x{9309}\x{930A}\x{930B}\x{930C}' . +'\x{930D}\x{930E}\x{930F}\x{9310}\x{9311}\x{9312}\x{9313}\x{9314}\x{9315}' . +'\x{9316}\x{9317}\x{9318}\x{9319}\x{931A}\x{931B}\x{931D}\x{931E}\x{931F}' . +'\x{9320}\x{9321}\x{9322}\x{9323}\x{9324}\x{9325}\x{9326}\x{9327}\x{9328}' . +'\x{9329}\x{932A}\x{932B}\x{932D}\x{932E}\x{932F}\x{9332}\x{9333}\x{9334}' . +'\x{9335}\x{9336}\x{9337}\x{9338}\x{9339}\x{933A}\x{933B}\x{933C}\x{933D}' . +'\x{933E}\x{933F}\x{9340}\x{9341}\x{9342}\x{9343}\x{9344}\x{9345}\x{9346}' . +'\x{9347}\x{9348}\x{9349}\x{934A}\x{934B}\x{934C}\x{934D}\x{934E}\x{934F}' . +'\x{9350}\x{9351}\x{9352}\x{9353}\x{9354}\x{9355}\x{9356}\x{9357}\x{9358}' . +'\x{9359}\x{935A}\x{935B}\x{935C}\x{935D}\x{935E}\x{935F}\x{9360}\x{9361}' . +'\x{9363}\x{9364}\x{9365}\x{9366}\x{9367}\x{9369}\x{936A}\x{936C}\x{936D}' . +'\x{936E}\x{9370}\x{9371}\x{9372}\x{9374}\x{9375}\x{9376}\x{9377}\x{9379}' . +'\x{937A}\x{937B}\x{937C}\x{937D}\x{937E}\x{9380}\x{9382}\x{9383}\x{9384}' . +'\x{9385}\x{9386}\x{9387}\x{9388}\x{9389}\x{938A}\x{938C}\x{938D}\x{938E}' . +'\x{938F}\x{9390}\x{9391}\x{9392}\x{9393}\x{9394}\x{9395}\x{9396}\x{9397}' . +'\x{9398}\x{9399}\x{939A}\x{939B}\x{939D}\x{939E}\x{939F}\x{93A1}\x{93A2}' . +'\x{93A3}\x{93A4}\x{93A5}\x{93A6}\x{93A7}\x{93A8}\x{93A9}\x{93AA}\x{93AC}' . +'\x{93AD}\x{93AE}\x{93AF}\x{93B0}\x{93B1}\x{93B2}\x{93B3}\x{93B4}\x{93B5}' . +'\x{93B6}\x{93B7}\x{93B8}\x{93B9}\x{93BA}\x{93BC}\x{93BD}\x{93BE}\x{93BF}' . +'\x{93C0}\x{93C1}\x{93C2}\x{93C3}\x{93C4}\x{93C5}\x{93C6}\x{93C7}\x{93C8}' . +'\x{93C9}\x{93CA}\x{93CB}\x{93CC}\x{93CD}\x{93CE}\x{93CF}\x{93D0}\x{93D1}' . +'\x{93D2}\x{93D3}\x{93D4}\x{93D5}\x{93D6}\x{93D7}\x{93D8}\x{93D9}\x{93DA}' . +'\x{93DB}\x{93DC}\x{93DD}\x{93DE}\x{93DF}\x{93E1}\x{93E2}\x{93E3}\x{93E4}' . +'\x{93E6}\x{93E7}\x{93E8}\x{93E9}\x{93EA}\x{93EB}\x{93EC}\x{93ED}\x{93EE}' . +'\x{93EF}\x{93F0}\x{93F1}\x{93F2}\x{93F4}\x{93F5}\x{93F6}\x{93F7}\x{93F8}' . +'\x{93F9}\x{93FA}\x{93FB}\x{93FC}\x{93FD}\x{93FE}\x{93FF}\x{9400}\x{9401}' . +'\x{9403}\x{9404}\x{9405}\x{9406}\x{9407}\x{9408}\x{9409}\x{940A}\x{940B}' . +'\x{940C}\x{940D}\x{940E}\x{940F}\x{9410}\x{9411}\x{9412}\x{9413}\x{9414}' . +'\x{9415}\x{9416}\x{9418}\x{9419}\x{941B}\x{941D}\x{9420}\x{9422}\x{9423}' . +'\x{9425}\x{9426}\x{9427}\x{9428}\x{9429}\x{942A}\x{942B}\x{942C}\x{942D}' . +'\x{942E}\x{942F}\x{9430}\x{9431}\x{9432}\x{9433}\x{9434}\x{9435}\x{9436}' . +'\x{9437}\x{9438}\x{9439}\x{943A}\x{943B}\x{943C}\x{943D}\x{943E}\x{943F}' . +'\x{9440}\x{9441}\x{9442}\x{9444}\x{9445}\x{9446}\x{9447}\x{9448}\x{9449}' . +'\x{944A}\x{944B}\x{944C}\x{944D}\x{944F}\x{9450}\x{9451}\x{9452}\x{9453}' . +'\x{9454}\x{9455}\x{9456}\x{9457}\x{9458}\x{9459}\x{945B}\x{945C}\x{945D}' . +'\x{945E}\x{945F}\x{9460}\x{9461}\x{9462}\x{9463}\x{9464}\x{9465}\x{9466}' . +'\x{9467}\x{9468}\x{9469}\x{946A}\x{946B}\x{946D}\x{946E}\x{946F}\x{9470}' . +'\x{9471}\x{9472}\x{9473}\x{9474}\x{9475}\x{9476}\x{9477}\x{9478}\x{9479}' . +'\x{947A}\x{947C}\x{947D}\x{947E}\x{947F}\x{9480}\x{9481}\x{9482}\x{9483}' . +'\x{9484}\x{9485}\x{9486}\x{9487}\x{9488}\x{9489}\x{948A}\x{948B}\x{948C}' . +'\x{948D}\x{948E}\x{948F}\x{9490}\x{9491}\x{9492}\x{9493}\x{9494}\x{9495}' . +'\x{9496}\x{9497}\x{9498}\x{9499}\x{949A}\x{949B}\x{949C}\x{949D}\x{949E}' . +'\x{949F}\x{94A0}\x{94A1}\x{94A2}\x{94A3}\x{94A4}\x{94A5}\x{94A6}\x{94A7}' . +'\x{94A8}\x{94A9}\x{94AA}\x{94AB}\x{94AC}\x{94AD}\x{94AE}\x{94AF}\x{94B0}' . +'\x{94B1}\x{94B2}\x{94B3}\x{94B4}\x{94B5}\x{94B6}\x{94B7}\x{94B8}\x{94B9}' . +'\x{94BA}\x{94BB}\x{94BC}\x{94BD}\x{94BE}\x{94BF}\x{94C0}\x{94C1}\x{94C2}' . +'\x{94C3}\x{94C4}\x{94C5}\x{94C6}\x{94C7}\x{94C8}\x{94C9}\x{94CA}\x{94CB}' . +'\x{94CC}\x{94CD}\x{94CE}\x{94CF}\x{94D0}\x{94D1}\x{94D2}\x{94D3}\x{94D4}' . +'\x{94D5}\x{94D6}\x{94D7}\x{94D8}\x{94D9}\x{94DA}\x{94DB}\x{94DC}\x{94DD}' . +'\x{94DE}\x{94DF}\x{94E0}\x{94E1}\x{94E2}\x{94E3}\x{94E4}\x{94E5}\x{94E6}' . +'\x{94E7}\x{94E8}\x{94E9}\x{94EA}\x{94EB}\x{94EC}\x{94ED}\x{94EE}\x{94EF}' . +'\x{94F0}\x{94F1}\x{94F2}\x{94F3}\x{94F4}\x{94F5}\x{94F6}\x{94F7}\x{94F8}' . +'\x{94F9}\x{94FA}\x{94FB}\x{94FC}\x{94FD}\x{94FE}\x{94FF}\x{9500}\x{9501}' . +'\x{9502}\x{9503}\x{9504}\x{9505}\x{9506}\x{9507}\x{9508}\x{9509}\x{950A}' . +'\x{950B}\x{950C}\x{950D}\x{950E}\x{950F}\x{9510}\x{9511}\x{9512}\x{9513}' . +'\x{9514}\x{9515}\x{9516}\x{9517}\x{9518}\x{9519}\x{951A}\x{951B}\x{951C}' . +'\x{951D}\x{951E}\x{951F}\x{9520}\x{9521}\x{9522}\x{9523}\x{9524}\x{9525}' . +'\x{9526}\x{9527}\x{9528}\x{9529}\x{952A}\x{952B}\x{952C}\x{952D}\x{952E}' . +'\x{952F}\x{9530}\x{9531}\x{9532}\x{9533}\x{9534}\x{9535}\x{9536}\x{9537}' . +'\x{9538}\x{9539}\x{953A}\x{953B}\x{953C}\x{953D}\x{953E}\x{953F}\x{9540}' . +'\x{9541}\x{9542}\x{9543}\x{9544}\x{9545}\x{9546}\x{9547}\x{9548}\x{9549}' . +'\x{954A}\x{954B}\x{954C}\x{954D}\x{954E}\x{954F}\x{9550}\x{9551}\x{9552}' . +'\x{9553}\x{9554}\x{9555}\x{9556}\x{9557}\x{9558}\x{9559}\x{955A}\x{955B}' . +'\x{955C}\x{955D}\x{955E}\x{955F}\x{9560}\x{9561}\x{9562}\x{9563}\x{9564}' . +'\x{9565}\x{9566}\x{9567}\x{9568}\x{9569}\x{956A}\x{956B}\x{956C}\x{956D}' . +'\x{956E}\x{956F}\x{9570}\x{9571}\x{9572}\x{9573}\x{9574}\x{9575}\x{9576}' . +'\x{9577}\x{957A}\x{957B}\x{957C}\x{957D}\x{957F}\x{9580}\x{9581}\x{9582}' . +'\x{9583}\x{9584}\x{9586}\x{9587}\x{9588}\x{9589}\x{958A}\x{958B}\x{958C}' . +'\x{958D}\x{958E}\x{958F}\x{9590}\x{9591}\x{9592}\x{9593}\x{9594}\x{9595}' . +'\x{9596}\x{9598}\x{9599}\x{959A}\x{959B}\x{959C}\x{959D}\x{959E}\x{959F}' . +'\x{95A1}\x{95A2}\x{95A3}\x{95A4}\x{95A5}\x{95A6}\x{95A7}\x{95A8}\x{95A9}' . +'\x{95AA}\x{95AB}\x{95AC}\x{95AD}\x{95AE}\x{95AF}\x{95B0}\x{95B1}\x{95B2}' . +'\x{95B5}\x{95B6}\x{95B7}\x{95B9}\x{95BA}\x{95BB}\x{95BC}\x{95BD}\x{95BE}' . +'\x{95BF}\x{95C0}\x{95C2}\x{95C3}\x{95C4}\x{95C5}\x{95C6}\x{95C7}\x{95C8}' . +'\x{95C9}\x{95CA}\x{95CB}\x{95CC}\x{95CD}\x{95CE}\x{95CF}\x{95D0}\x{95D1}' . +'\x{95D2}\x{95D3}\x{95D4}\x{95D5}\x{95D6}\x{95D7}\x{95D8}\x{95DA}\x{95DB}' . +'\x{95DC}\x{95DE}\x{95DF}\x{95E0}\x{95E1}\x{95E2}\x{95E3}\x{95E4}\x{95E5}' . +'\x{95E6}\x{95E7}\x{95E8}\x{95E9}\x{95EA}\x{95EB}\x{95EC}\x{95ED}\x{95EE}' . +'\x{95EF}\x{95F0}\x{95F1}\x{95F2}\x{95F3}\x{95F4}\x{95F5}\x{95F6}\x{95F7}' . +'\x{95F8}\x{95F9}\x{95FA}\x{95FB}\x{95FC}\x{95FD}\x{95FE}\x{95FF}\x{9600}' . +'\x{9601}\x{9602}\x{9603}\x{9604}\x{9605}\x{9606}\x{9607}\x{9608}\x{9609}' . +'\x{960A}\x{960B}\x{960C}\x{960D}\x{960E}\x{960F}\x{9610}\x{9611}\x{9612}' . +'\x{9613}\x{9614}\x{9615}\x{9616}\x{9617}\x{9618}\x{9619}\x{961A}\x{961B}' . +'\x{961C}\x{961D}\x{961E}\x{961F}\x{9620}\x{9621}\x{9622}\x{9623}\x{9624}' . +'\x{9627}\x{9628}\x{962A}\x{962B}\x{962C}\x{962D}\x{962E}\x{962F}\x{9630}' . +'\x{9631}\x{9632}\x{9633}\x{9634}\x{9635}\x{9636}\x{9637}\x{9638}\x{9639}' . +'\x{963A}\x{963B}\x{963C}\x{963D}\x{963F}\x{9640}\x{9641}\x{9642}\x{9643}' . +'\x{9644}\x{9645}\x{9646}\x{9647}\x{9648}\x{9649}\x{964A}\x{964B}\x{964C}' . +'\x{964D}\x{964E}\x{964F}\x{9650}\x{9651}\x{9652}\x{9653}\x{9654}\x{9655}' . +'\x{9658}\x{9659}\x{965A}\x{965B}\x{965C}\x{965D}\x{965E}\x{965F}\x{9660}' . +'\x{9661}\x{9662}\x{9663}\x{9664}\x{9666}\x{9667}\x{9668}\x{9669}\x{966A}' . +'\x{966B}\x{966C}\x{966D}\x{966E}\x{966F}\x{9670}\x{9671}\x{9672}\x{9673}' . +'\x{9674}\x{9675}\x{9676}\x{9677}\x{9678}\x{967C}\x{967D}\x{967E}\x{9680}' . +'\x{9683}\x{9684}\x{9685}\x{9686}\x{9687}\x{9688}\x{9689}\x{968A}\x{968B}' . +'\x{968D}\x{968E}\x{968F}\x{9690}\x{9691}\x{9692}\x{9693}\x{9694}\x{9695}' . +'\x{9697}\x{9698}\x{9699}\x{969B}\x{969C}\x{969E}\x{96A0}\x{96A1}\x{96A2}' . +'\x{96A3}\x{96A4}\x{96A5}\x{96A6}\x{96A7}\x{96A8}\x{96A9}\x{96AA}\x{96AC}' . +'\x{96AD}\x{96AE}\x{96B0}\x{96B1}\x{96B3}\x{96B4}\x{96B6}\x{96B7}\x{96B8}' . +'\x{96B9}\x{96BA}\x{96BB}\x{96BC}\x{96BD}\x{96BE}\x{96BF}\x{96C0}\x{96C1}' . +'\x{96C2}\x{96C3}\x{96C4}\x{96C5}\x{96C6}\x{96C7}\x{96C8}\x{96C9}\x{96CA}' . +'\x{96CB}\x{96CC}\x{96CD}\x{96CE}\x{96CF}\x{96D0}\x{96D1}\x{96D2}\x{96D3}' . +'\x{96D4}\x{96D5}\x{96D6}\x{96D7}\x{96D8}\x{96D9}\x{96DA}\x{96DB}\x{96DC}' . +'\x{96DD}\x{96DE}\x{96DF}\x{96E0}\x{96E1}\x{96E2}\x{96E3}\x{96E5}\x{96E8}' . +'\x{96E9}\x{96EA}\x{96EB}\x{96EC}\x{96ED}\x{96EE}\x{96EF}\x{96F0}\x{96F1}' . +'\x{96F2}\x{96F3}\x{96F4}\x{96F5}\x{96F6}\x{96F7}\x{96F8}\x{96F9}\x{96FA}' . +'\x{96FB}\x{96FD}\x{96FE}\x{96FF}\x{9700}\x{9701}\x{9702}\x{9703}\x{9704}' . +'\x{9705}\x{9706}\x{9707}\x{9708}\x{9709}\x{970A}\x{970B}\x{970C}\x{970D}' . +'\x{970E}\x{970F}\x{9710}\x{9711}\x{9712}\x{9713}\x{9715}\x{9716}\x{9718}' . +'\x{9719}\x{971C}\x{971D}\x{971E}\x{971F}\x{9720}\x{9721}\x{9722}\x{9723}' . +'\x{9724}\x{9725}\x{9726}\x{9727}\x{9728}\x{9729}\x{972A}\x{972B}\x{972C}' . +'\x{972D}\x{972E}\x{972F}\x{9730}\x{9731}\x{9732}\x{9735}\x{9736}\x{9738}' . +'\x{9739}\x{973A}\x{973B}\x{973C}\x{973D}\x{973E}\x{973F}\x{9742}\x{9743}' . +'\x{9744}\x{9745}\x{9746}\x{9747}\x{9748}\x{9749}\x{974A}\x{974B}\x{974C}' . +'\x{974E}\x{974F}\x{9750}\x{9751}\x{9752}\x{9753}\x{9754}\x{9755}\x{9756}' . +'\x{9758}\x{9759}\x{975A}\x{975B}\x{975C}\x{975D}\x{975E}\x{975F}\x{9760}' . +'\x{9761}\x{9762}\x{9765}\x{9766}\x{9767}\x{9768}\x{9769}\x{976A}\x{976B}' . +'\x{976C}\x{976D}\x{976E}\x{976F}\x{9770}\x{9772}\x{9773}\x{9774}\x{9776}' . +'\x{9777}\x{9778}\x{9779}\x{977A}\x{977B}\x{977C}\x{977D}\x{977E}\x{977F}' . +'\x{9780}\x{9781}\x{9782}\x{9783}\x{9784}\x{9785}\x{9786}\x{9788}\x{978A}' . +'\x{978B}\x{978C}\x{978D}\x{978E}\x{978F}\x{9790}\x{9791}\x{9792}\x{9793}' . +'\x{9794}\x{9795}\x{9796}\x{9797}\x{9798}\x{9799}\x{979A}\x{979C}\x{979D}' . +'\x{979E}\x{979F}\x{97A0}\x{97A1}\x{97A2}\x{97A3}\x{97A4}\x{97A5}\x{97A6}' . +'\x{97A7}\x{97A8}\x{97AA}\x{97AB}\x{97AC}\x{97AD}\x{97AE}\x{97AF}\x{97B2}' . +'\x{97B3}\x{97B4}\x{97B6}\x{97B7}\x{97B8}\x{97B9}\x{97BA}\x{97BB}\x{97BC}' . +'\x{97BD}\x{97BF}\x{97C1}\x{97C2}\x{97C3}\x{97C4}\x{97C5}\x{97C6}\x{97C7}' . +'\x{97C8}\x{97C9}\x{97CA}\x{97CB}\x{97CC}\x{97CD}\x{97CE}\x{97CF}\x{97D0}' . +'\x{97D1}\x{97D3}\x{97D4}\x{97D5}\x{97D6}\x{97D7}\x{97D8}\x{97D9}\x{97DA}' . +'\x{97DB}\x{97DC}\x{97DD}\x{97DE}\x{97DF}\x{97E0}\x{97E1}\x{97E2}\x{97E3}' . +'\x{97E4}\x{97E5}\x{97E6}\x{97E7}\x{97E8}\x{97E9}\x{97EA}\x{97EB}\x{97EC}' . +'\x{97ED}\x{97EE}\x{97EF}\x{97F0}\x{97F1}\x{97F2}\x{97F3}\x{97F4}\x{97F5}' . +'\x{97F6}\x{97F7}\x{97F8}\x{97F9}\x{97FA}\x{97FB}\x{97FD}\x{97FE}\x{97FF}' . +'\x{9800}\x{9801}\x{9802}\x{9803}\x{9804}\x{9805}\x{9806}\x{9807}\x{9808}' . +'\x{9809}\x{980A}\x{980B}\x{980C}\x{980D}\x{980E}\x{980F}\x{9810}\x{9811}' . +'\x{9812}\x{9813}\x{9814}\x{9815}\x{9816}\x{9817}\x{9818}\x{9819}\x{981A}' . +'\x{981B}\x{981C}\x{981D}\x{981E}\x{9820}\x{9821}\x{9822}\x{9823}\x{9824}' . +'\x{9826}\x{9827}\x{9828}\x{9829}\x{982B}\x{982D}\x{982E}\x{982F}\x{9830}' . +'\x{9831}\x{9832}\x{9834}\x{9835}\x{9836}\x{9837}\x{9838}\x{9839}\x{983B}' . +'\x{983C}\x{983D}\x{983F}\x{9840}\x{9841}\x{9843}\x{9844}\x{9845}\x{9846}' . +'\x{9848}\x{9849}\x{984A}\x{984C}\x{984D}\x{984E}\x{984F}\x{9850}\x{9851}' . +'\x{9852}\x{9853}\x{9854}\x{9855}\x{9857}\x{9858}\x{9859}\x{985A}\x{985B}' . +'\x{985C}\x{985D}\x{985E}\x{985F}\x{9860}\x{9861}\x{9862}\x{9863}\x{9864}' . +'\x{9865}\x{9867}\x{9869}\x{986A}\x{986B}\x{986C}\x{986D}\x{986E}\x{986F}' . +'\x{9870}\x{9871}\x{9872}\x{9873}\x{9874}\x{9875}\x{9876}\x{9877}\x{9878}' . +'\x{9879}\x{987A}\x{987B}\x{987C}\x{987D}\x{987E}\x{987F}\x{9880}\x{9881}' . +'\x{9882}\x{9883}\x{9884}\x{9885}\x{9886}\x{9887}\x{9888}\x{9889}\x{988A}' . +'\x{988B}\x{988C}\x{988D}\x{988E}\x{988F}\x{9890}\x{9891}\x{9892}\x{9893}' . +'\x{9894}\x{9895}\x{9896}\x{9897}\x{9898}\x{9899}\x{989A}\x{989B}\x{989C}' . +'\x{989D}\x{989E}\x{989F}\x{98A0}\x{98A1}\x{98A2}\x{98A3}\x{98A4}\x{98A5}' . +'\x{98A6}\x{98A7}\x{98A8}\x{98A9}\x{98AA}\x{98AB}\x{98AC}\x{98AD}\x{98AE}' . +'\x{98AF}\x{98B0}\x{98B1}\x{98B2}\x{98B3}\x{98B4}\x{98B5}\x{98B6}\x{98B8}' . +'\x{98B9}\x{98BA}\x{98BB}\x{98BC}\x{98BD}\x{98BE}\x{98BF}\x{98C0}\x{98C1}' . +'\x{98C2}\x{98C3}\x{98C4}\x{98C5}\x{98C6}\x{98C8}\x{98C9}\x{98CB}\x{98CC}' . +'\x{98CD}\x{98CE}\x{98CF}\x{98D0}\x{98D1}\x{98D2}\x{98D3}\x{98D4}\x{98D5}' . +'\x{98D6}\x{98D7}\x{98D8}\x{98D9}\x{98DA}\x{98DB}\x{98DC}\x{98DD}\x{98DE}' . +'\x{98DF}\x{98E0}\x{98E2}\x{98E3}\x{98E5}\x{98E6}\x{98E7}\x{98E8}\x{98E9}' . +'\x{98EA}\x{98EB}\x{98ED}\x{98EF}\x{98F0}\x{98F2}\x{98F3}\x{98F4}\x{98F5}' . +'\x{98F6}\x{98F7}\x{98F9}\x{98FA}\x{98FC}\x{98FD}\x{98FE}\x{98FF}\x{9900}' . +'\x{9901}\x{9902}\x{9903}\x{9904}\x{9905}\x{9906}\x{9907}\x{9908}\x{9909}' . +'\x{990A}\x{990B}\x{990C}\x{990D}\x{990E}\x{990F}\x{9910}\x{9911}\x{9912}' . +'\x{9913}\x{9914}\x{9915}\x{9916}\x{9917}\x{9918}\x{991A}\x{991B}\x{991C}' . +'\x{991D}\x{991E}\x{991F}\x{9920}\x{9921}\x{9922}\x{9923}\x{9924}\x{9925}' . +'\x{9926}\x{9927}\x{9928}\x{9929}\x{992A}\x{992B}\x{992C}\x{992D}\x{992E}' . +'\x{992F}\x{9930}\x{9931}\x{9932}\x{9933}\x{9934}\x{9935}\x{9936}\x{9937}' . +'\x{9938}\x{9939}\x{993A}\x{993C}\x{993D}\x{993E}\x{993F}\x{9940}\x{9941}' . +'\x{9942}\x{9943}\x{9945}\x{9946}\x{9947}\x{9948}\x{9949}\x{994A}\x{994B}' . +'\x{994C}\x{994E}\x{994F}\x{9950}\x{9951}\x{9952}\x{9953}\x{9954}\x{9955}' . +'\x{9956}\x{9957}\x{9958}\x{9959}\x{995B}\x{995C}\x{995E}\x{995F}\x{9960}' . +'\x{9961}\x{9962}\x{9963}\x{9964}\x{9965}\x{9966}\x{9967}\x{9968}\x{9969}' . +'\x{996A}\x{996B}\x{996C}\x{996D}\x{996E}\x{996F}\x{9970}\x{9971}\x{9972}' . +'\x{9973}\x{9974}\x{9975}\x{9976}\x{9977}\x{9978}\x{9979}\x{997A}\x{997B}' . +'\x{997C}\x{997D}\x{997E}\x{997F}\x{9980}\x{9981}\x{9982}\x{9983}\x{9984}' . +'\x{9985}\x{9986}\x{9987}\x{9988}\x{9989}\x{998A}\x{998B}\x{998C}\x{998D}' . +'\x{998E}\x{998F}\x{9990}\x{9991}\x{9992}\x{9993}\x{9994}\x{9995}\x{9996}' . +'\x{9997}\x{9998}\x{9999}\x{999A}\x{999B}\x{999C}\x{999D}\x{999E}\x{999F}' . +'\x{99A0}\x{99A1}\x{99A2}\x{99A3}\x{99A4}\x{99A5}\x{99A6}\x{99A7}\x{99A8}' . +'\x{99A9}\x{99AA}\x{99AB}\x{99AC}\x{99AD}\x{99AE}\x{99AF}\x{99B0}\x{99B1}' . +'\x{99B2}\x{99B3}\x{99B4}\x{99B5}\x{99B6}\x{99B7}\x{99B8}\x{99B9}\x{99BA}' . +'\x{99BB}\x{99BC}\x{99BD}\x{99BE}\x{99C0}\x{99C1}\x{99C2}\x{99C3}\x{99C4}' . +'\x{99C6}\x{99C7}\x{99C8}\x{99C9}\x{99CA}\x{99CB}\x{99CC}\x{99CD}\x{99CE}' . +'\x{99CF}\x{99D0}\x{99D1}\x{99D2}\x{99D3}\x{99D4}\x{99D5}\x{99D6}\x{99D7}' . +'\x{99D8}\x{99D9}\x{99DA}\x{99DB}\x{99DC}\x{99DD}\x{99DE}\x{99DF}\x{99E1}' . +'\x{99E2}\x{99E3}\x{99E4}\x{99E5}\x{99E7}\x{99E8}\x{99E9}\x{99EA}\x{99EC}' . +'\x{99ED}\x{99EE}\x{99EF}\x{99F0}\x{99F1}\x{99F2}\x{99F3}\x{99F4}\x{99F6}' . +'\x{99F7}\x{99F8}\x{99F9}\x{99FA}\x{99FB}\x{99FC}\x{99FD}\x{99FE}\x{99FF}' . +'\x{9A00}\x{9A01}\x{9A02}\x{9A03}\x{9A04}\x{9A05}\x{9A06}\x{9A07}\x{9A08}' . +'\x{9A09}\x{9A0A}\x{9A0B}\x{9A0C}\x{9A0D}\x{9A0E}\x{9A0F}\x{9A11}\x{9A14}' . +'\x{9A15}\x{9A16}\x{9A19}\x{9A1A}\x{9A1B}\x{9A1C}\x{9A1D}\x{9A1E}\x{9A1F}' . +'\x{9A20}\x{9A21}\x{9A22}\x{9A23}\x{9A24}\x{9A25}\x{9A26}\x{9A27}\x{9A29}' . +'\x{9A2A}\x{9A2B}\x{9A2C}\x{9A2D}\x{9A2E}\x{9A2F}\x{9A30}\x{9A31}\x{9A32}' . +'\x{9A33}\x{9A34}\x{9A35}\x{9A36}\x{9A37}\x{9A38}\x{9A39}\x{9A3A}\x{9A3C}' . +'\x{9A3D}\x{9A3E}\x{9A3F}\x{9A40}\x{9A41}\x{9A42}\x{9A43}\x{9A44}\x{9A45}' . +'\x{9A46}\x{9A47}\x{9A48}\x{9A49}\x{9A4A}\x{9A4B}\x{9A4C}\x{9A4D}\x{9A4E}' . +'\x{9A4F}\x{9A50}\x{9A52}\x{9A53}\x{9A54}\x{9A55}\x{9A56}\x{9A57}\x{9A59}' . +'\x{9A5A}\x{9A5B}\x{9A5C}\x{9A5E}\x{9A5F}\x{9A60}\x{9A61}\x{9A62}\x{9A64}' . +'\x{9A65}\x{9A66}\x{9A67}\x{9A68}\x{9A69}\x{9A6A}\x{9A6B}\x{9A6C}\x{9A6D}' . +'\x{9A6E}\x{9A6F}\x{9A70}\x{9A71}\x{9A72}\x{9A73}\x{9A74}\x{9A75}\x{9A76}' . +'\x{9A77}\x{9A78}\x{9A79}\x{9A7A}\x{9A7B}\x{9A7C}\x{9A7D}\x{9A7E}\x{9A7F}' . +'\x{9A80}\x{9A81}\x{9A82}\x{9A83}\x{9A84}\x{9A85}\x{9A86}\x{9A87}\x{9A88}' . +'\x{9A89}\x{9A8A}\x{9A8B}\x{9A8C}\x{9A8D}\x{9A8E}\x{9A8F}\x{9A90}\x{9A91}' . +'\x{9A92}\x{9A93}\x{9A94}\x{9A95}\x{9A96}\x{9A97}\x{9A98}\x{9A99}\x{9A9A}' . +'\x{9A9B}\x{9A9C}\x{9A9D}\x{9A9E}\x{9A9F}\x{9AA0}\x{9AA1}\x{9AA2}\x{9AA3}' . +'\x{9AA4}\x{9AA5}\x{9AA6}\x{9AA7}\x{9AA8}\x{9AAA}\x{9AAB}\x{9AAC}\x{9AAD}' . +'\x{9AAE}\x{9AAF}\x{9AB0}\x{9AB1}\x{9AB2}\x{9AB3}\x{9AB4}\x{9AB5}\x{9AB6}' . +'\x{9AB7}\x{9AB8}\x{9AB9}\x{9ABA}\x{9ABB}\x{9ABC}\x{9ABE}\x{9ABF}\x{9AC0}' . +'\x{9AC1}\x{9AC2}\x{9AC3}\x{9AC4}\x{9AC5}\x{9AC6}\x{9AC7}\x{9AC9}\x{9ACA}' . +'\x{9ACB}\x{9ACC}\x{9ACD}\x{9ACE}\x{9ACF}\x{9AD0}\x{9AD1}\x{9AD2}\x{9AD3}' . +'\x{9AD4}\x{9AD5}\x{9AD6}\x{9AD8}\x{9AD9}\x{9ADA}\x{9ADB}\x{9ADC}\x{9ADD}' . +'\x{9ADE}\x{9ADF}\x{9AE1}\x{9AE2}\x{9AE3}\x{9AE5}\x{9AE6}\x{9AE7}\x{9AEA}' . +'\x{9AEB}\x{9AEC}\x{9AED}\x{9AEE}\x{9AEF}\x{9AF1}\x{9AF2}\x{9AF3}\x{9AF4}' . +'\x{9AF5}\x{9AF6}\x{9AF7}\x{9AF8}\x{9AF9}\x{9AFA}\x{9AFB}\x{9AFC}\x{9AFD}' . +'\x{9AFE}\x{9AFF}\x{9B01}\x{9B03}\x{9B04}\x{9B05}\x{9B06}\x{9B07}\x{9B08}' . +'\x{9B0A}\x{9B0B}\x{9B0C}\x{9B0D}\x{9B0E}\x{9B0F}\x{9B10}\x{9B11}\x{9B12}' . +'\x{9B13}\x{9B15}\x{9B16}\x{9B17}\x{9B18}\x{9B19}\x{9B1A}\x{9B1C}\x{9B1D}' . +'\x{9B1E}\x{9B1F}\x{9B20}\x{9B21}\x{9B22}\x{9B23}\x{9B24}\x{9B25}\x{9B26}' . +'\x{9B27}\x{9B28}\x{9B29}\x{9B2A}\x{9B2B}\x{9B2C}\x{9B2D}\x{9B2E}\x{9B2F}' . +'\x{9B30}\x{9B31}\x{9B32}\x{9B33}\x{9B35}\x{9B36}\x{9B37}\x{9B38}\x{9B39}' . +'\x{9B3A}\x{9B3B}\x{9B3C}\x{9B3E}\x{9B3F}\x{9B41}\x{9B42}\x{9B43}\x{9B44}' . +'\x{9B45}\x{9B46}\x{9B47}\x{9B48}\x{9B49}\x{9B4A}\x{9B4B}\x{9B4C}\x{9B4D}' . +'\x{9B4E}\x{9B4F}\x{9B51}\x{9B52}\x{9B53}\x{9B54}\x{9B55}\x{9B56}\x{9B58}' . +'\x{9B59}\x{9B5A}\x{9B5B}\x{9B5C}\x{9B5D}\x{9B5E}\x{9B5F}\x{9B60}\x{9B61}' . +'\x{9B63}\x{9B64}\x{9B65}\x{9B66}\x{9B67}\x{9B68}\x{9B69}\x{9B6A}\x{9B6B}' . +'\x{9B6C}\x{9B6D}\x{9B6E}\x{9B6F}\x{9B70}\x{9B71}\x{9B73}\x{9B74}\x{9B75}' . +'\x{9B76}\x{9B77}\x{9B78}\x{9B79}\x{9B7A}\x{9B7B}\x{9B7C}\x{9B7D}\x{9B7E}' . +'\x{9B7F}\x{9B80}\x{9B81}\x{9B82}\x{9B83}\x{9B84}\x{9B85}\x{9B86}\x{9B87}' . +'\x{9B88}\x{9B8A}\x{9B8B}\x{9B8D}\x{9B8E}\x{9B8F}\x{9B90}\x{9B91}\x{9B92}' . +'\x{9B93}\x{9B94}\x{9B95}\x{9B96}\x{9B97}\x{9B98}\x{9B9A}\x{9B9B}\x{9B9C}' . +'\x{9B9D}\x{9B9E}\x{9B9F}\x{9BA0}\x{9BA1}\x{9BA2}\x{9BA3}\x{9BA4}\x{9BA5}' . +'\x{9BA6}\x{9BA7}\x{9BA8}\x{9BA9}\x{9BAA}\x{9BAB}\x{9BAC}\x{9BAD}\x{9BAE}' . +'\x{9BAF}\x{9BB0}\x{9BB1}\x{9BB2}\x{9BB3}\x{9BB4}\x{9BB5}\x{9BB6}\x{9BB7}' . +'\x{9BB8}\x{9BB9}\x{9BBA}\x{9BBB}\x{9BBC}\x{9BBD}\x{9BBE}\x{9BBF}\x{9BC0}' . +'\x{9BC1}\x{9BC3}\x{9BC4}\x{9BC5}\x{9BC6}\x{9BC7}\x{9BC8}\x{9BC9}\x{9BCA}' . +'\x{9BCB}\x{9BCC}\x{9BCD}\x{9BCE}\x{9BCF}\x{9BD0}\x{9BD1}\x{9BD2}\x{9BD3}' . +'\x{9BD4}\x{9BD5}\x{9BD6}\x{9BD7}\x{9BD8}\x{9BD9}\x{9BDA}\x{9BDB}\x{9BDC}' . +'\x{9BDD}\x{9BDE}\x{9BDF}\x{9BE0}\x{9BE1}\x{9BE2}\x{9BE3}\x{9BE4}\x{9BE5}' . +'\x{9BE6}\x{9BE7}\x{9BE8}\x{9BE9}\x{9BEA}\x{9BEB}\x{9BEC}\x{9BED}\x{9BEE}' . +'\x{9BEF}\x{9BF0}\x{9BF1}\x{9BF2}\x{9BF3}\x{9BF4}\x{9BF5}\x{9BF7}\x{9BF8}' . +'\x{9BF9}\x{9BFA}\x{9BFB}\x{9BFC}\x{9BFD}\x{9BFE}\x{9BFF}\x{9C02}\x{9C05}' . +'\x{9C06}\x{9C07}\x{9C08}\x{9C09}\x{9C0A}\x{9C0B}\x{9C0C}\x{9C0D}\x{9C0E}' . +'\x{9C0F}\x{9C10}\x{9C11}\x{9C12}\x{9C13}\x{9C14}\x{9C15}\x{9C16}\x{9C17}' . +'\x{9C18}\x{9C19}\x{9C1A}\x{9C1B}\x{9C1C}\x{9C1D}\x{9C1E}\x{9C1F}\x{9C20}' . +'\x{9C21}\x{9C22}\x{9C23}\x{9C24}\x{9C25}\x{9C26}\x{9C27}\x{9C28}\x{9C29}' . +'\x{9C2A}\x{9C2B}\x{9C2C}\x{9C2D}\x{9C2F}\x{9C30}\x{9C31}\x{9C32}\x{9C33}' . +'\x{9C34}\x{9C35}\x{9C36}\x{9C37}\x{9C38}\x{9C39}\x{9C3A}\x{9C3B}\x{9C3C}' . +'\x{9C3D}\x{9C3E}\x{9C3F}\x{9C40}\x{9C41}\x{9C43}\x{9C44}\x{9C45}\x{9C46}' . +'\x{9C47}\x{9C48}\x{9C49}\x{9C4A}\x{9C4B}\x{9C4C}\x{9C4D}\x{9C4E}\x{9C50}' . +'\x{9C52}\x{9C53}\x{9C54}\x{9C55}\x{9C56}\x{9C57}\x{9C58}\x{9C59}\x{9C5A}' . +'\x{9C5B}\x{9C5C}\x{9C5D}\x{9C5E}\x{9C5F}\x{9C60}\x{9C62}\x{9C63}\x{9C65}' . +'\x{9C66}\x{9C67}\x{9C68}\x{9C69}\x{9C6A}\x{9C6B}\x{9C6C}\x{9C6D}\x{9C6E}' . +'\x{9C6F}\x{9C70}\x{9C71}\x{9C72}\x{9C73}\x{9C74}\x{9C75}\x{9C77}\x{9C78}' . +'\x{9C79}\x{9C7A}\x{9C7C}\x{9C7D}\x{9C7E}\x{9C7F}\x{9C80}\x{9C81}\x{9C82}' . +'\x{9C83}\x{9C84}\x{9C85}\x{9C86}\x{9C87}\x{9C88}\x{9C89}\x{9C8A}\x{9C8B}' . +'\x{9C8C}\x{9C8D}\x{9C8E}\x{9C8F}\x{9C90}\x{9C91}\x{9C92}\x{9C93}\x{9C94}' . +'\x{9C95}\x{9C96}\x{9C97}\x{9C98}\x{9C99}\x{9C9A}\x{9C9B}\x{9C9C}\x{9C9D}' . +'\x{9C9E}\x{9C9F}\x{9CA0}\x{9CA1}\x{9CA2}\x{9CA3}\x{9CA4}\x{9CA5}\x{9CA6}' . +'\x{9CA7}\x{9CA8}\x{9CA9}\x{9CAA}\x{9CAB}\x{9CAC}\x{9CAD}\x{9CAE}\x{9CAF}' . +'\x{9CB0}\x{9CB1}\x{9CB2}\x{9CB3}\x{9CB4}\x{9CB5}\x{9CB6}\x{9CB7}\x{9CB8}' . +'\x{9CB9}\x{9CBA}\x{9CBB}\x{9CBC}\x{9CBD}\x{9CBE}\x{9CBF}\x{9CC0}\x{9CC1}' . +'\x{9CC2}\x{9CC3}\x{9CC4}\x{9CC5}\x{9CC6}\x{9CC7}\x{9CC8}\x{9CC9}\x{9CCA}' . +'\x{9CCB}\x{9CCC}\x{9CCD}\x{9CCE}\x{9CCF}\x{9CD0}\x{9CD1}\x{9CD2}\x{9CD3}' . +'\x{9CD4}\x{9CD5}\x{9CD6}\x{9CD7}\x{9CD8}\x{9CD9}\x{9CDA}\x{9CDB}\x{9CDC}' . +'\x{9CDD}\x{9CDE}\x{9CDF}\x{9CE0}\x{9CE1}\x{9CE2}\x{9CE3}\x{9CE4}\x{9CE5}' . +'\x{9CE6}\x{9CE7}\x{9CE8}\x{9CE9}\x{9CEA}\x{9CEB}\x{9CEC}\x{9CED}\x{9CEE}' . +'\x{9CEF}\x{9CF0}\x{9CF1}\x{9CF2}\x{9CF3}\x{9CF4}\x{9CF5}\x{9CF6}\x{9CF7}' . +'\x{9CF8}\x{9CF9}\x{9CFA}\x{9CFB}\x{9CFC}\x{9CFD}\x{9CFE}\x{9CFF}\x{9D00}' . +'\x{9D01}\x{9D02}\x{9D03}\x{9D04}\x{9D05}\x{9D06}\x{9D07}\x{9D08}\x{9D09}' . +'\x{9D0A}\x{9D0B}\x{9D0F}\x{9D10}\x{9D12}\x{9D13}\x{9D14}\x{9D15}\x{9D16}' . +'\x{9D17}\x{9D18}\x{9D19}\x{9D1A}\x{9D1B}\x{9D1C}\x{9D1D}\x{9D1E}\x{9D1F}' . +'\x{9D20}\x{9D21}\x{9D22}\x{9D23}\x{9D24}\x{9D25}\x{9D26}\x{9D28}\x{9D29}' . +'\x{9D2B}\x{9D2D}\x{9D2E}\x{9D2F}\x{9D30}\x{9D31}\x{9D32}\x{9D33}\x{9D34}' . +'\x{9D36}\x{9D37}\x{9D38}\x{9D39}\x{9D3A}\x{9D3B}\x{9D3D}\x{9D3E}\x{9D3F}' . +'\x{9D40}\x{9D41}\x{9D42}\x{9D43}\x{9D45}\x{9D46}\x{9D47}\x{9D48}\x{9D49}' . +'\x{9D4A}\x{9D4B}\x{9D4C}\x{9D4D}\x{9D4E}\x{9D4F}\x{9D50}\x{9D51}\x{9D52}' . +'\x{9D53}\x{9D54}\x{9D55}\x{9D56}\x{9D57}\x{9D58}\x{9D59}\x{9D5A}\x{9D5B}' . +'\x{9D5C}\x{9D5D}\x{9D5E}\x{9D5F}\x{9D60}\x{9D61}\x{9D62}\x{9D63}\x{9D64}' . +'\x{9D65}\x{9D66}\x{9D67}\x{9D68}\x{9D69}\x{9D6A}\x{9D6B}\x{9D6C}\x{9D6E}' . +'\x{9D6F}\x{9D70}\x{9D71}\x{9D72}\x{9D73}\x{9D74}\x{9D75}\x{9D76}\x{9D77}' . +'\x{9D78}\x{9D79}\x{9D7A}\x{9D7B}\x{9D7C}\x{9D7D}\x{9D7E}\x{9D7F}\x{9D80}' . +'\x{9D81}\x{9D82}\x{9D83}\x{9D84}\x{9D85}\x{9D86}\x{9D87}\x{9D88}\x{9D89}' . +'\x{9D8A}\x{9D8B}\x{9D8C}\x{9D8D}\x{9D8E}\x{9D90}\x{9D91}\x{9D92}\x{9D93}' . +'\x{9D94}\x{9D96}\x{9D97}\x{9D98}\x{9D99}\x{9D9A}\x{9D9B}\x{9D9C}\x{9D9D}' . +'\x{9D9E}\x{9D9F}\x{9DA0}\x{9DA1}\x{9DA2}\x{9DA3}\x{9DA4}\x{9DA5}\x{9DA6}' . +'\x{9DA7}\x{9DA8}\x{9DA9}\x{9DAA}\x{9DAB}\x{9DAC}\x{9DAD}\x{9DAF}\x{9DB0}' . +'\x{9DB1}\x{9DB2}\x{9DB3}\x{9DB4}\x{9DB5}\x{9DB6}\x{9DB7}\x{9DB8}\x{9DB9}' . +'\x{9DBA}\x{9DBB}\x{9DBC}\x{9DBE}\x{9DBF}\x{9DC1}\x{9DC2}\x{9DC3}\x{9DC4}' . +'\x{9DC5}\x{9DC7}\x{9DC8}\x{9DC9}\x{9DCA}\x{9DCB}\x{9DCC}\x{9DCD}\x{9DCE}' . +'\x{9DCF}\x{9DD0}\x{9DD1}\x{9DD2}\x{9DD3}\x{9DD4}\x{9DD5}\x{9DD6}\x{9DD7}' . +'\x{9DD8}\x{9DD9}\x{9DDA}\x{9DDB}\x{9DDC}\x{9DDD}\x{9DDE}\x{9DDF}\x{9DE0}' . +'\x{9DE1}\x{9DE2}\x{9DE3}\x{9DE4}\x{9DE5}\x{9DE6}\x{9DE7}\x{9DE8}\x{9DE9}' . +'\x{9DEB}\x{9DEC}\x{9DED}\x{9DEE}\x{9DEF}\x{9DF0}\x{9DF1}\x{9DF2}\x{9DF3}' . +'\x{9DF4}\x{9DF5}\x{9DF6}\x{9DF7}\x{9DF8}\x{9DF9}\x{9DFA}\x{9DFB}\x{9DFD}' . +'\x{9DFE}\x{9DFF}\x{9E00}\x{9E01}\x{9E02}\x{9E03}\x{9E04}\x{9E05}\x{9E06}' . +'\x{9E07}\x{9E08}\x{9E09}\x{9E0A}\x{9E0B}\x{9E0C}\x{9E0D}\x{9E0F}\x{9E10}' . +'\x{9E11}\x{9E12}\x{9E13}\x{9E14}\x{9E15}\x{9E17}\x{9E18}\x{9E19}\x{9E1A}' . +'\x{9E1B}\x{9E1D}\x{9E1E}\x{9E1F}\x{9E20}\x{9E21}\x{9E22}\x{9E23}\x{9E24}' . +'\x{9E25}\x{9E26}\x{9E27}\x{9E28}\x{9E29}\x{9E2A}\x{9E2B}\x{9E2C}\x{9E2D}' . +'\x{9E2E}\x{9E2F}\x{9E30}\x{9E31}\x{9E32}\x{9E33}\x{9E34}\x{9E35}\x{9E36}' . +'\x{9E37}\x{9E38}\x{9E39}\x{9E3A}\x{9E3B}\x{9E3C}\x{9E3D}\x{9E3E}\x{9E3F}' . +'\x{9E40}\x{9E41}\x{9E42}\x{9E43}\x{9E44}\x{9E45}\x{9E46}\x{9E47}\x{9E48}' . +'\x{9E49}\x{9E4A}\x{9E4B}\x{9E4C}\x{9E4D}\x{9E4E}\x{9E4F}\x{9E50}\x{9E51}' . +'\x{9E52}\x{9E53}\x{9E54}\x{9E55}\x{9E56}\x{9E57}\x{9E58}\x{9E59}\x{9E5A}' . +'\x{9E5B}\x{9E5C}\x{9E5D}\x{9E5E}\x{9E5F}\x{9E60}\x{9E61}\x{9E62}\x{9E63}' . +'\x{9E64}\x{9E65}\x{9E66}\x{9E67}\x{9E68}\x{9E69}\x{9E6A}\x{9E6B}\x{9E6C}' . +'\x{9E6D}\x{9E6E}\x{9E6F}\x{9E70}\x{9E71}\x{9E72}\x{9E73}\x{9E74}\x{9E75}' . +'\x{9E76}\x{9E77}\x{9E79}\x{9E7A}\x{9E7C}\x{9E7D}\x{9E7E}\x{9E7F}\x{9E80}' . +'\x{9E81}\x{9E82}\x{9E83}\x{9E84}\x{9E85}\x{9E86}\x{9E87}\x{9E88}\x{9E89}' . +'\x{9E8A}\x{9E8B}\x{9E8C}\x{9E8D}\x{9E8E}\x{9E91}\x{9E92}\x{9E93}\x{9E94}' . +'\x{9E96}\x{9E97}\x{9E99}\x{9E9A}\x{9E9B}\x{9E9C}\x{9E9D}\x{9E9F}\x{9EA0}' . +'\x{9EA1}\x{9EA3}\x{9EA4}\x{9EA5}\x{9EA6}\x{9EA7}\x{9EA8}\x{9EA9}\x{9EAA}' . +'\x{9EAD}\x{9EAE}\x{9EAF}\x{9EB0}\x{9EB2}\x{9EB3}\x{9EB4}\x{9EB5}\x{9EB6}' . +'\x{9EB7}\x{9EB8}\x{9EBB}\x{9EBC}\x{9EBD}\x{9EBE}\x{9EBF}\x{9EC0}\x{9EC1}' . +'\x{9EC2}\x{9EC3}\x{9EC4}\x{9EC5}\x{9EC6}\x{9EC7}\x{9EC8}\x{9EC9}\x{9ECA}' . +'\x{9ECB}\x{9ECC}\x{9ECD}\x{9ECE}\x{9ECF}\x{9ED0}\x{9ED1}\x{9ED2}\x{9ED3}' . +'\x{9ED4}\x{9ED5}\x{9ED6}\x{9ED7}\x{9ED8}\x{9ED9}\x{9EDA}\x{9EDB}\x{9EDC}' . +'\x{9EDD}\x{9EDE}\x{9EDF}\x{9EE0}\x{9EE1}\x{9EE2}\x{9EE3}\x{9EE4}\x{9EE5}' . +'\x{9EE6}\x{9EE7}\x{9EE8}\x{9EE9}\x{9EEA}\x{9EEB}\x{9EED}\x{9EEE}\x{9EEF}' . +'\x{9EF0}\x{9EF2}\x{9EF3}\x{9EF4}\x{9EF5}\x{9EF6}\x{9EF7}\x{9EF8}\x{9EF9}' . +'\x{9EFA}\x{9EFB}\x{9EFC}\x{9EFD}\x{9EFE}\x{9EFF}\x{9F00}\x{9F01}\x{9F02}' . +'\x{9F04}\x{9F05}\x{9F06}\x{9F07}\x{9F08}\x{9F09}\x{9F0A}\x{9F0B}\x{9F0C}' . +'\x{9F0D}\x{9F0E}\x{9F0F}\x{9F10}\x{9F12}\x{9F13}\x{9F15}\x{9F16}\x{9F17}' . +'\x{9F18}\x{9F19}\x{9F1A}\x{9F1B}\x{9F1C}\x{9F1D}\x{9F1E}\x{9F1F}\x{9F20}' . +'\x{9F22}\x{9F23}\x{9F24}\x{9F25}\x{9F27}\x{9F28}\x{9F29}\x{9F2A}\x{9F2B}' . +'\x{9F2C}\x{9F2D}\x{9F2E}\x{9F2F}\x{9F30}\x{9F31}\x{9F32}\x{9F33}\x{9F34}' . +'\x{9F35}\x{9F36}\x{9F37}\x{9F38}\x{9F39}\x{9F3A}\x{9F3B}\x{9F3C}\x{9F3D}' . +'\x{9F3E}\x{9F3F}\x{9F40}\x{9F41}\x{9F42}\x{9F43}\x{9F44}\x{9F46}\x{9F47}' . +'\x{9F48}\x{9F49}\x{9F4A}\x{9F4B}\x{9F4C}\x{9F4D}\x{9F4E}\x{9F4F}\x{9F50}' . +'\x{9F51}\x{9F52}\x{9F54}\x{9F55}\x{9F56}\x{9F57}\x{9F58}\x{9F59}\x{9F5A}' . +'\x{9F5B}\x{9F5C}\x{9F5D}\x{9F5E}\x{9F5F}\x{9F60}\x{9F61}\x{9F63}\x{9F64}' . +'\x{9F65}\x{9F66}\x{9F67}\x{9F68}\x{9F69}\x{9F6A}\x{9F6B}\x{9F6C}\x{9F6E}' . +'\x{9F6F}\x{9F70}\x{9F71}\x{9F72}\x{9F73}\x{9F74}\x{9F75}\x{9F76}\x{9F77}' . +'\x{9F78}\x{9F79}\x{9F7A}\x{9F7B}\x{9F7C}\x{9F7D}\x{9F7E}\x{9F7F}\x{9F80}' . +'\x{9F81}\x{9F82}\x{9F83}\x{9F84}\x{9F85}\x{9F86}\x{9F87}\x{9F88}\x{9F89}' . +'\x{9F8A}\x{9F8B}\x{9F8C}\x{9F8D}\x{9F8E}\x{9F8F}\x{9F90}\x{9F91}\x{9F92}' . +'\x{9F93}\x{9F94}\x{9F95}\x{9F96}\x{9F97}\x{9F98}\x{9F99}\x{9F9A}\x{9F9B}' . +'\x{9F9C}\x{9F9D}\x{9F9E}\x{9F9F}\x{9FA0}\x{9FA2}\x{9FA4}\x{9FA5}]{1,20}$/iu'); diff --git a/Zend/Validate/Hostname/Com.php b/Zend/Validate/Hostname/Com.php new file mode 100644 index 00000000..a2e403d0 --- /dev/null +++ b/Zend/Validate/Hostname/Com.php @@ -0,0 +1,198 @@ + '/^[\x{002d}0-9\x{0400}-\x{052f}]{1,63}$/iu', + 2 => '/^[\x{002d}0-9\x{0370}-\x{03ff}]{1,63}$/iu', + 3 => '/^[\x{002d}0-9a-z\x{ac00}-\x{d7a3}]{1,17}$/iu', + 4 => '/^[\x{002d}0-9a-z·à-öø-ÿāăąćĉċčďđēĕėęěĝğġģĥħĩīĭįıĵķĸĺļľłńņňŋōŏőœŕŗřśŝşšţťŧũūŭůűųŵŷźżž]{1,63}$/iu', + 5 => '/^[\x{002d}0-9A-Za-z\x{3400}-\x{3401}\x{3404}-\x{3406}\x{340C}\x{3416}\x{341C}' . +'\x{3421}\x{3424}\x{3428}-\x{3429}\x{342B}-\x{342E}\x{3430}-\x{3434}\x{3436}' . +'\x{3438}-\x{343C}\x{343E}\x{3441}-\x{3445}\x{3447}\x{3449}-\x{3451}\x{3453}' . +'\x{3457}-\x{345F}\x{3463}-\x{3467}\x{346E}-\x{3471}\x{3473}-\x{3477}\x{3479}-\x{348E}\x{3491}-\x{3497}' . +'\x{3499}-\x{34A1}\x{34A4}-\x{34AD}\x{34AF}-\x{34B0}\x{34B2}-\x{34BF}\x{34C2}-\x{34C5}\x{34C7}-\x{34CC}' . +'\x{34CE}-\x{34D1}\x{34D3}-\x{34D8}\x{34DA}-\x{34E4}\x{34E7}-\x{34E9}\x{34EC}-\x{34EF}\x{34F1}-\x{34FE}' . +'\x{3500}-\x{3507}\x{350A}-\x{3513}\x{3515}\x{3517}-\x{351A}\x{351C}-\x{351E}\x{3520}-\x{352A}' . +'\x{352C}-\x{3552}\x{3554}-\x{355C}\x{355E}-\x{3567}\x{3569}-\x{3573}\x{3575}-\x{357C}\x{3580}-\x{3588}' . +'\x{358F}-\x{3598}\x{359E}-\x{35AB}\x{35B4}-\x{35CD}\x{35D0}\x{35D3}-\x{35DC}\x{35E2}-\x{35ED}' . +'\x{35F0}-\x{35F6}\x{35FB}-\x{3602}\x{3605}-\x{360E}\x{3610}-\x{3611}\x{3613}-\x{3616}\x{3619}-\x{362D}' . +'\x{362F}-\x{3634}\x{3636}-\x{363B}\x{363F}-\x{3645}\x{3647}-\x{364B}\x{364D}-\x{3653}\x{3655}' . +'\x{3659}-\x{365E}\x{3660}-\x{3665}\x{3667}-\x{367C}\x{367E}\x{3680}-\x{3685}\x{3687}' . +'\x{3689}-\x{3690}\x{3692}-\x{3698}\x{369A}\x{369C}-\x{36AE}\x{36B0}-\x{36BF}\x{36C1}-\x{36C5}' . +'\x{36C9}-\x{36CA}\x{36CD}-\x{36DE}\x{36E1}-\x{36E2}\x{36E5}-\x{36FE}\x{3701}-\x{3713}\x{3715}-\x{371E}' . +'\x{3720}-\x{372C}\x{372E}-\x{3745}\x{3747}-\x{3748}\x{374A}\x{374C}-\x{3759}\x{375B}-\x{3760}' . +'\x{3762}-\x{3767}\x{3769}-\x{3772}\x{3774}-\x{378C}\x{378F}-\x{379C}\x{379F}\x{37A1}-\x{37AD}' . +'\x{37AF}-\x{37B7}\x{37B9}-\x{37C1}\x{37C3}-\x{37C5}\x{37C7}-\x{37D4}\x{37D6}-\x{37E0}\x{37E2}' . +'\x{37E5}-\x{37ED}\x{37EF}-\x{37F6}\x{37F8}-\x{3802}\x{3804}-\x{381D}\x{3820}-\x{3822}\x{3825}-\x{382A}' . +'\x{382D}-\x{382F}\x{3831}-\x{3832}\x{3834}-\x{384C}\x{384E}-\x{3860}\x{3862}-\x{3863}\x{3865}-\x{386B}' . +'\x{386D}-\x{3886}\x{3888}-\x{38A1}\x{38A3}\x{38A5}-\x{38AA}\x{38AC}\x{38AE}-\x{38B0}' . +'\x{38B2}-\x{38B6}\x{38B8}\x{38BA}-\x{38BE}\x{38C0}-\x{38C9}\x{38CB}-\x{38D4}\x{38D8}-\x{38E0}' . +'\x{38E2}-\x{38E6}\x{38EB}-\x{38ED}\x{38EF}-\x{38F2}\x{38F5}-\x{38F7}\x{38FA}-\x{38FF}\x{3901}-\x{392A}' . +'\x{392C}\x{392E}-\x{393B}\x{393E}-\x{3956}\x{395A}-\x{3969}\x{396B}-\x{397A}\x{397C}-\x{3987}' . +'\x{3989}-\x{3998}\x{399A}-\x{39B0}\x{39B2}\x{39B4}-\x{39D0}\x{39D2}-\x{39DA}\x{39DE}-\x{39DF}' . +'\x{39E1}-\x{39EF}\x{39F1}-\x{3A17}\x{3A19}-\x{3A2A}\x{3A2D}-\x{3A40}\x{3A43}-\x{3A4E}\x{3A50}' . +'\x{3A52}-\x{3A5E}\x{3A60}-\x{3A6D}\x{3A6F}-\x{3A77}\x{3A79}-\x{3A82}\x{3A84}-\x{3A85}\x{3A87}-\x{3A89}' . +'\x{3A8B}-\x{3A8F}\x{3A91}-\x{3A93}\x{3A95}-\x{3A96}\x{3A9A}\x{3A9C}-\x{3AA6}\x{3AA8}-\x{3AA9}' . +'\x{3AAB}-\x{3AB1}\x{3AB4}-\x{3ABC}\x{3ABE}-\x{3AC5}\x{3ACA}-\x{3ACB}\x{3ACD}-\x{3AD5}\x{3AD7}-\x{3AE1}' . +'\x{3AE4}-\x{3AE7}\x{3AE9}-\x{3AEC}\x{3AEE}-\x{3AFD}\x{3B01}-\x{3B10}\x{3B12}-\x{3B15}\x{3B17}-\x{3B1E}' . +'\x{3B20}-\x{3B23}\x{3B25}-\x{3B27}\x{3B29}-\x{3B36}\x{3B38}-\x{3B39}\x{3B3B}-\x{3B3C}\x{3B3F}' . +'\x{3B41}-\x{3B44}\x{3B47}-\x{3B4C}\x{3B4E}\x{3B51}-\x{3B55}\x{3B58}-\x{3B62}\x{3B68}-\x{3B72}' . +'\x{3B78}-\x{3B88}\x{3B8B}-\x{3B9F}\x{3BA1}\x{3BA3}-\x{3BBA}\x{3BBC}\x{3BBF}-\x{3BD0}' . +'\x{3BD3}-\x{3BE6}\x{3BEA}-\x{3BFB}\x{3BFE}-\x{3C12}\x{3C14}-\x{3C1B}\x{3C1D}-\x{3C37}\x{3C39}-\x{3C4F}' . +'\x{3C52}\x{3C54}-\x{3C5C}\x{3C5E}-\x{3C68}\x{3C6A}-\x{3C76}\x{3C78}-\x{3C8F}\x{3C91}-\x{3CA8}' . +'\x{3CAA}-\x{3CAD}\x{3CAF}-\x{3CBE}\x{3CC0}-\x{3CC8}\x{3CCA}-\x{3CD3}\x{3CD6}-\x{3CE0}\x{3CE4}-\x{3CEE}' . +'\x{3CF3}-\x{3D0A}\x{3D0E}-\x{3D1E}\x{3D20}-\x{3D21}\x{3D25}-\x{3D38}\x{3D3B}-\x{3D46}\x{3D4A}-\x{3D59}' . +'\x{3D5D}-\x{3D7B}\x{3D7D}-\x{3D81}\x{3D84}-\x{3D88}\x{3D8C}-\x{3D8F}\x{3D91}-\x{3D98}\x{3D9A}-\x{3D9C}' . +'\x{3D9E}-\x{3DA1}\x{3DA3}-\x{3DB0}\x{3DB2}-\x{3DB5}\x{3DB9}-\x{3DBC}\x{3DBE}-\x{3DCB}\x{3DCD}-\x{3DDB}' . +'\x{3DDF}-\x{3DE8}\x{3DEB}-\x{3DF0}\x{3DF3}-\x{3DF9}\x{3DFB}-\x{3DFC}\x{3DFE}-\x{3E05}\x{3E08}-\x{3E33}' . +'\x{3E35}-\x{3E3E}\x{3E40}-\x{3E47}\x{3E49}-\x{3E67}\x{3E6B}-\x{3E6F}\x{3E71}-\x{3E85}\x{3E87}-\x{3E8C}' . +'\x{3E8E}-\x{3E98}\x{3E9A}-\x{3EA1}\x{3EA3}-\x{3EAE}\x{3EB0}-\x{3EB5}\x{3EB7}-\x{3EBA}\x{3EBD}' . +'\x{3EBF}-\x{3EC4}\x{3EC7}-\x{3ECE}\x{3ED1}-\x{3ED7}\x{3ED9}-\x{3EDA}\x{3EDD}-\x{3EE3}\x{3EE7}-\x{3EE8}' . +'\x{3EEB}-\x{3EF2}\x{3EF5}-\x{3EFF}\x{3F01}-\x{3F02}\x{3F04}-\x{3F07}\x{3F09}-\x{3F44}\x{3F46}-\x{3F4E}' . +'\x{3F50}-\x{3F53}\x{3F55}-\x{3F72}\x{3F74}-\x{3F75}\x{3F77}-\x{3F7B}\x{3F7D}-\x{3FB0}\x{3FB6}-\x{3FBF}' . +'\x{3FC1}-\x{3FCF}\x{3FD1}-\x{3FD3}\x{3FD5}-\x{3FDF}\x{3FE1}-\x{400B}\x{400D}-\x{401C}\x{401E}-\x{4024}' . +'\x{4027}-\x{403F}\x{4041}-\x{4060}\x{4062}-\x{4069}\x{406B}-\x{408A}\x{408C}-\x{40A7}\x{40A9}-\x{40B4}' . +'\x{40B6}-\x{40C2}\x{40C7}-\x{40CF}\x{40D1}-\x{40DE}\x{40E0}-\x{40E7}\x{40E9}-\x{40EE}\x{40F0}-\x{40FB}' . +'\x{40FD}-\x{4109}\x{410B}-\x{4115}\x{4118}-\x{411D}\x{411F}-\x{4122}\x{4124}-\x{4133}\x{4136}-\x{4138}' . +'\x{413A}-\x{4148}\x{414A}-\x{4169}\x{416C}-\x{4185}\x{4188}-\x{418B}\x{418D}-\x{41AD}\x{41AF}-\x{41B3}' . +'\x{41B5}-\x{41C3}\x{41C5}-\x{41C9}\x{41CB}-\x{41F2}\x{41F5}-\x{41FE}\x{4200}-\x{4227}\x{422A}-\x{4246}' . +'\x{4248}-\x{4263}\x{4265}-\x{428B}\x{428D}-\x{42A1}\x{42A3}-\x{42C4}\x{42C8}-\x{42DC}\x{42DE}-\x{430A}' . +'\x{430C}-\x{4335}\x{4337}\x{4342}-\x{435F}\x{4361}-\x{439A}\x{439C}-\x{439D}\x{439F}-\x{43A4}' . +'\x{43A6}-\x{43EC}\x{43EF}-\x{4405}\x{4407}-\x{4429}\x{442B}-\x{4455}\x{4457}-\x{4468}\x{446A}-\x{446D}' . +'\x{446F}-\x{4476}\x{4479}-\x{447D}\x{447F}-\x{4486}\x{4488}-\x{4490}\x{4492}-\x{4498}\x{449A}-\x{44AD}' . +'\x{44B0}-\x{44BD}\x{44C1}-\x{44D3}\x{44D6}-\x{44E7}\x{44EA}\x{44EC}-\x{44FA}\x{44FC}-\x{4541}' . +'\x{4543}-\x{454F}\x{4551}-\x{4562}\x{4564}-\x{4575}\x{4577}-\x{45AB}\x{45AD}-\x{45BD}\x{45BF}-\x{45D5}' . +'\x{45D7}-\x{45EC}\x{45EE}-\x{45F2}\x{45F4}-\x{45FA}\x{45FC}-\x{461A}\x{461C}-\x{461D}\x{461F}-\x{4631}' . +'\x{4633}-\x{4649}\x{464C}\x{464E}-\x{4652}\x{4654}-\x{466A}\x{466C}-\x{4675}\x{4677}-\x{467A}' . +'\x{467C}-\x{4694}\x{4696}-\x{46A3}\x{46A5}-\x{46AB}\x{46AD}-\x{46D2}\x{46D4}-\x{4723}\x{4729}-\x{4732}' . +'\x{4734}-\x{4758}\x{475A}\x{475C}-\x{478B}\x{478D}\x{4791}-\x{47B1}\x{47B3}-\x{47F1}' . +'\x{47F3}-\x{480B}\x{480D}-\x{4815}\x{4817}-\x{4839}\x{483B}-\x{4870}\x{4872}-\x{487A}\x{487C}-\x{487F}' . +'\x{4883}-\x{488E}\x{4890}-\x{4896}\x{4899}-\x{48A2}\x{48A4}-\x{48B9}\x{48BB}-\x{48C8}\x{48CA}-\x{48D1}' . +'\x{48D3}-\x{48E5}\x{48E7}-\x{48F2}\x{48F4}-\x{48FF}\x{4901}-\x{4922}\x{4924}-\x{4928}\x{492A}-\x{4931}' . +'\x{4933}-\x{495B}\x{495D}-\x{4978}\x{497A}\x{497D}\x{4982}-\x{4983}\x{4985}-\x{49A8}' . +'\x{49AA}-\x{49AF}\x{49B1}-\x{49B7}\x{49B9}-\x{49BD}\x{49C1}-\x{49C7}\x{49C9}-\x{49CE}\x{49D0}-\x{49E8}' . +'\x{49EA}\x{49EC}\x{49EE}-\x{4A19}\x{4A1B}-\x{4A43}\x{4A45}-\x{4A4D}\x{4A4F}-\x{4A9E}' . +'\x{4AA0}-\x{4AA9}\x{4AAB}-\x{4B4E}\x{4B50}-\x{4B5B}\x{4B5D}-\x{4B69}\x{4B6B}-\x{4BC2}\x{4BC6}-\x{4BE8}' . +'\x{4BEA}-\x{4BFA}\x{4BFC}-\x{4C06}\x{4C08}-\x{4C2D}\x{4C2F}-\x{4C32}\x{4C34}-\x{4C35}\x{4C37}-\x{4C69}' . +'\x{4C6B}-\x{4C73}\x{4C75}-\x{4C86}\x{4C88}-\x{4C97}\x{4C99}-\x{4C9C}\x{4C9F}-\x{4CA3}\x{4CA5}-\x{4CB5}' . +'\x{4CB7}-\x{4CF8}\x{4CFA}-\x{4D27}\x{4D29}-\x{4DAC}\x{4DAE}-\x{4DB1}\x{4DB3}-\x{4DB5}\x{4E00}-\x{4E54}' . +'\x{4E56}-\x{4E89}\x{4E8B}-\x{4EEC}\x{4EEE}-\x{4FAC}\x{4FAE}-\x{503C}\x{503E}-\x{51E5}\x{51E7}-\x{5270}' . +'\x{5272}-\x{56A1}\x{56A3}-\x{5840}\x{5842}-\x{58B5}\x{58B7}-\x{58CB}\x{58CD}-\x{5BC8}\x{5BCA}-\x{5C01}' . +'\x{5C03}-\x{5C25}\x{5C27}-\x{5D5B}\x{5D5D}-\x{5F08}\x{5F0A}-\x{61F3}\x{61F5}-\x{63BA}\x{63BC}-\x{6441}' . +'\x{6443}-\x{657C}\x{657E}-\x{663E}\x{6640}-\x{66FC}\x{66FE}-\x{6728}\x{672A}-\x{6766}\x{6768}-\x{67A8}' . +'\x{67AA}-\x{685B}\x{685D}-\x{685E}\x{6860}-\x{68B9}\x{68BB}-\x{6AC8}\x{6ACA}-\x{6BB0}\x{6BB2}-\x{6C16}' . +'\x{6C18}-\x{6D9B}\x{6D9D}-\x{6E12}\x{6E14}-\x{6E8B}\x{6E8D}-\x{704D}\x{704F}-\x{7113}\x{7115}-\x{713B}' . +'\x{713D}-\x{7154}\x{7156}-\x{729F}\x{72A1}-\x{731E}\x{7320}-\x{7362}\x{7364}-\x{7533}\x{7535}-\x{7551}' . +'\x{7553}-\x{7572}\x{7574}-\x{75E8}\x{75EA}-\x{7679}\x{767B}-\x{783E}\x{7840}-\x{7A62}\x{7A64}-\x{7AC2}' . +'\x{7AC4}-\x{7B06}\x{7B08}-\x{7B79}\x{7B7B}-\x{7BCE}\x{7BD0}-\x{7D99}\x{7D9B}-\x{7E49}\x{7E4C}-\x{8132}' . +'\x{8134}\x{8136}-\x{81D2}\x{81D4}-\x{8216}\x{8218}-\x{822D}\x{822F}-\x{83B4}\x{83B6}-\x{841F}' . +'\x{8421}-\x{86CC}\x{86CE}-\x{874A}\x{874C}-\x{877E}\x{8780}-\x{8A32}\x{8A34}-\x{8B71}\x{8B73}-\x{8B8E}' . +'\x{8B90}-\x{8DE4}\x{8DE6}-\x{8E9A}\x{8E9C}-\x{8EE1}\x{8EE4}-\x{8F0B}\x{8F0D}-\x{8FB9}\x{8FBB}-\x{9038}' . +'\x{903A}-\x{9196}\x{9198}-\x{91A3}\x{91A5}-\x{91B7}\x{91B9}-\x{91C7}\x{91C9}-\x{91E0}\x{91E2}-\x{91FB}' . +'\x{91FD}-\x{922B}\x{922D}-\x{9270}\x{9272}-\x{9420}\x{9422}-\x{9664}\x{9666}-\x{9679}\x{967B}-\x{9770}' . +'\x{9772}-\x{982B}\x{982D}-\x{98ED}\x{98EF}-\x{99C4}\x{99C6}-\x{9A11}\x{9A14}-\x{9A27}\x{9A29}-\x{9D0D}' . +'\x{9D0F}-\x{9D2B}\x{9D2D}-\x{9D8E}\x{9D90}-\x{9DC5}\x{9DC7}-\x{9E77}\x{9E79}-\x{9EB8}\x{9EBB}-\x{9F20}' . +'\x{9F22}-\x{9F61}\x{9F63}-\x{9FA5}\x{FA28}]{1,20}$/iu', + 6 => '/^[\x{002d}0-9A-Za-z]{1,63}$/iu', + 7 => '/^[\x{00A1}-\x{00FF}]{1,63}$/iu', + 8 => '/^[\x{0100}-\x{017f}]{1,63}$/iu', + 9 => '/^[\x{0180}-\x{024f}]{1,63}$/iu', + 10 => '/^[\x{0250}-\x{02af}]{1,63}$/iu', + 11 => '/^[\x{02b0}-\x{02ff}]{1,63}$/iu', + 12 => '/^[\x{0300}-\x{036f}]{1,63}$/iu', + 13 => '/^[\x{0370}-\x{03ff}]{1,63}$/iu', + 14 => '/^[\x{0400}-\x{04ff}]{1,63}$/iu', + 15 => '/^[\x{0500}-\x{052f}]{1,63}$/iu', + 16 => '/^[\x{0530}-\x{058F}]{1,63}$/iu', + 17 => '/^[\x{0590}-\x{05FF}]{1,63}$/iu', + 18 => '/^[\x{0600}-\x{06FF}]{1,63}$/iu', + 19 => '/^[\x{0700}-\x{074F}]{1,63}$/iu', + 20 => '/^[\x{0780}-\x{07BF}]{1,63}$/iu', + 21 => '/^[\x{0900}-\x{097F}]{1,63}$/iu', + 22 => '/^[\x{0980}-\x{09FF}]{1,63}$/iu', + 23 => '/^[\x{0A00}-\x{0A7F}]{1,63}$/iu', + 24 => '/^[\x{0A80}-\x{0AFF}]{1,63}$/iu', + 25 => '/^[\x{0B00}-\x{0B7F}]{1,63}$/iu', + 26 => '/^[\x{0B80}-\x{0BFF}]{1,63}$/iu', + 27 => '/^[\x{0C00}-\x{0C7F}]{1,63}$/iu', + 28 => '/^[\x{0C80}-\x{0CFF}]{1,63}$/iu', + 29 => '/^[\x{0D00}-\x{0D7F}]{1,63}$/iu', + 30 => '/^[\x{0D80}-\x{0DFF}]{1,63}$/iu', + 31 => '/^[\x{0E00}-\x{0E7F}]{1,63}$/iu', + 32 => '/^[\x{0E80}-\x{0EFF}]{1,63}$/iu', + 33 => '/^[\x{0F00}-\x{0FFF}]{1,63}$/iu', + 34 => '/^[\x{1000}-\x{109F}]{1,63}$/iu', + 35 => '/^[\x{10A0}-\x{10FF}]{1,63}$/iu', + 36 => '/^[\x{1100}-\x{11FF}]{1,63}$/iu', + 37 => '/^[\x{1200}-\x{137F}]{1,63}$/iu', + 38 => '/^[\x{13A0}-\x{13FF}]{1,63}$/iu', + 39 => '/^[\x{1400}-\x{167F}]{1,63}$/iu', + 40 => '/^[\x{1680}-\x{169F}]{1,63}$/iu', + 41 => '/^[\x{16A0}-\x{16FF}]{1,63}$/iu', + 42 => '/^[\x{1700}-\x{171F}]{1,63}$/iu', + 43 => '/^[\x{1720}-\x{173F}]{1,63}$/iu', + 44 => '/^[\x{1740}-\x{175F}]{1,63}$/iu', + 45 => '/^[\x{1760}-\x{177F}]{1,63}$/iu', + 46 => '/^[\x{1780}-\x{17FF}]{1,63}$/iu', + 47 => '/^[\x{1800}-\x{18AF}]{1,63}$/iu', + 48 => '/^[\x{1E00}-\x{1EFF}]{1,63}$/iu', + 49 => '/^[\x{1F00}-\x{1FFF}]{1,63}$/iu', + 50 => '/^[\x{2070}-\x{209F}]{1,63}$/iu', + 51 => '/^[\x{2100}-\x{214F}]{1,63}$/iu', + 52 => '/^[\x{2150}-\x{218F}]{1,63}$/iu', + 53 => '/^[\x{2460}-\x{24FF}]{1,63}$/iu', + 54 => '/^[\x{2E80}-\x{2EFF}]{1,63}$/iu', + 55 => '/^[\x{2F00}-\x{2FDF}]{1,63}$/iu', + 56 => '/^[\x{2FF0}-\x{2FFF}]{1,63}$/iu', + 57 => '/^[\x{3040}-\x{309F}]{1,63}$/iu', + 58 => '/^[\x{30A0}-\x{30FF}]{1,63}$/iu', + 59 => '/^[\x{3100}-\x{312F}]{1,63}$/iu', + 60 => '/^[\x{3130}-\x{318F}]{1,63}$/iu', + 61 => '/^[\x{3190}-\x{319F}]{1,63}$/iu', + 62 => '/^[\x{31A0}-\x{31BF}]{1,63}$/iu', + 63 => '/^[\x{31F0}-\x{31FF}]{1,63}$/iu', + 64 => '/^[\x{3200}-\x{32FF}]{1,63}$/iu', + 65 => '/^[\x{3300}-\x{33FF}]{1,63}$/iu', + 66 => '/^[\x{3400}-\x{4DBF}]{1,63}$/iu', + 67 => '/^[\x{4E00}-\x{9FFF}]{1,63}$/iu', + 68 => '/^[\x{A000}-\x{A48F}]{1,63}$/iu', + 69 => '/^[\x{A490}-\x{A4CF}]{1,63}$/iu', + 70 => '/^[\x{AC00}-\x{D7AF}]{1,63}$/iu', + 71 => '/^[\x{D800}-\x{DB7F}]{1,63}$/iu', + 72 => '/^[\x{DC00}-\x{DFFF}]{1,63}$/iu', + 73 => '/^[\x{F900}-\x{FAFF}]{1,63}$/iu', + 74 => '/^[\x{FB00}-\x{FB4F}]{1,63}$/iu', + 75 => '/^[\x{FB50}-\x{FDFF}]{1,63}$/iu', + 76 => '/^[\x{FE20}-\x{FE2F}]{1,63}$/iu', + 77 => '/^[\x{FE70}-\x{FEFF}]{1,63}$/iu', + 78 => '/^[\x{FF00}-\x{FFEF}]{1,63}$/iu', + 79 => '/^[\x{20000}-\x{2A6DF}]{1,63}$/iu', + 80 => '/^[\x{2F800}-\x{2FA1F}]{1,63}$/iu' + +); \ No newline at end of file diff --git a/Zend/Validate/Hostname/Jp.php b/Zend/Validate/Hostname/Jp.php new file mode 100644 index 00000000..9a97271b --- /dev/null +++ b/Zend/Validate/Hostname/Jp.php @@ -0,0 +1,739 @@ + '/^[\x{002d}0-9a-z\x{3005}-\x{3007}\x{3041}-\x{3093}\x{309D}\x{309E}' . +'\x{30A1}-\x{30F6}\x{30FC}' . +'\x{30FD}\x{30FE}\x{4E00}\x{4E01}\x{4E03}\x{4E07}\x{4E08}\x{4E09}\x{4E0A}' . +'\x{4E0B}\x{4E0D}\x{4E0E}\x{4E10}\x{4E11}\x{4E14}\x{4E15}\x{4E16}\x{4E17}' . +'\x{4E18}\x{4E19}\x{4E1E}\x{4E21}\x{4E26}\x{4E2A}\x{4E2D}\x{4E31}\x{4E32}' . +'\x{4E36}\x{4E38}\x{4E39}\x{4E3B}\x{4E3C}\x{4E3F}\x{4E42}\x{4E43}\x{4E45}' . +'\x{4E4B}\x{4E4D}\x{4E4E}\x{4E4F}\x{4E55}\x{4E56}\x{4E57}\x{4E58}\x{4E59}' . +'\x{4E5D}\x{4E5E}\x{4E5F}\x{4E62}\x{4E71}\x{4E73}\x{4E7E}\x{4E80}\x{4E82}' . +'\x{4E85}\x{4E86}\x{4E88}\x{4E89}\x{4E8A}\x{4E8B}\x{4E8C}\x{4E8E}\x{4E91}' . +'\x{4E92}\x{4E94}\x{4E95}\x{4E98}\x{4E99}\x{4E9B}\x{4E9C}\x{4E9E}\x{4E9F}' . +'\x{4EA0}\x{4EA1}\x{4EA2}\x{4EA4}\x{4EA5}\x{4EA6}\x{4EA8}\x{4EAB}\x{4EAC}' . +'\x{4EAD}\x{4EAE}\x{4EB0}\x{4EB3}\x{4EB6}\x{4EBA}\x{4EC0}\x{4EC1}\x{4EC2}' . +'\x{4EC4}\x{4EC6}\x{4EC7}\x{4ECA}\x{4ECB}\x{4ECD}\x{4ECE}\x{4ECF}\x{4ED4}' . +'\x{4ED5}\x{4ED6}\x{4ED7}\x{4ED8}\x{4ED9}\x{4EDD}\x{4EDE}\x{4EDF}\x{4EE3}' . +'\x{4EE4}\x{4EE5}\x{4EED}\x{4EEE}\x{4EF0}\x{4EF2}\x{4EF6}\x{4EF7}\x{4EFB}' . +'\x{4F01}\x{4F09}\x{4F0A}\x{4F0D}\x{4F0E}\x{4F0F}\x{4F10}\x{4F11}\x{4F1A}' . +'\x{4F1C}\x{4F1D}\x{4F2F}\x{4F30}\x{4F34}\x{4F36}\x{4F38}\x{4F3A}\x{4F3C}' . +'\x{4F3D}\x{4F43}\x{4F46}\x{4F47}\x{4F4D}\x{4F4E}\x{4F4F}\x{4F50}\x{4F51}' . +'\x{4F53}\x{4F55}\x{4F57}\x{4F59}\x{4F5A}\x{4F5B}\x{4F5C}\x{4F5D}\x{4F5E}' . +'\x{4F69}\x{4F6F}\x{4F70}\x{4F73}\x{4F75}\x{4F76}\x{4F7B}\x{4F7C}\x{4F7F}' . +'\x{4F83}\x{4F86}\x{4F88}\x{4F8B}\x{4F8D}\x{4F8F}\x{4F91}\x{4F96}\x{4F98}' . +'\x{4F9B}\x{4F9D}\x{4FA0}\x{4FA1}\x{4FAB}\x{4FAD}\x{4FAE}\x{4FAF}\x{4FB5}' . +'\x{4FB6}\x{4FBF}\x{4FC2}\x{4FC3}\x{4FC4}\x{4FCA}\x{4FCE}\x{4FD0}\x{4FD1}' . +'\x{4FD4}\x{4FD7}\x{4FD8}\x{4FDA}\x{4FDB}\x{4FDD}\x{4FDF}\x{4FE1}\x{4FE3}' . +'\x{4FE4}\x{4FE5}\x{4FEE}\x{4FEF}\x{4FF3}\x{4FF5}\x{4FF6}\x{4FF8}\x{4FFA}' . +'\x{4FFE}\x{5005}\x{5006}\x{5009}\x{500B}\x{500D}\x{500F}\x{5011}\x{5012}' . +'\x{5014}\x{5016}\x{5019}\x{501A}\x{501F}\x{5021}\x{5023}\x{5024}\x{5025}' . +'\x{5026}\x{5028}\x{5029}\x{502A}\x{502B}\x{502C}\x{502D}\x{5036}\x{5039}' . +'\x{5043}\x{5047}\x{5048}\x{5049}\x{504F}\x{5050}\x{5055}\x{5056}\x{505A}' . +'\x{505C}\x{5065}\x{506C}\x{5072}\x{5074}\x{5075}\x{5076}\x{5078}\x{507D}' . +'\x{5080}\x{5085}\x{508D}\x{5091}\x{5098}\x{5099}\x{509A}\x{50AC}\x{50AD}' . +'\x{50B2}\x{50B3}\x{50B4}\x{50B5}\x{50B7}\x{50BE}\x{50C2}\x{50C5}\x{50C9}' . +'\x{50CA}\x{50CD}\x{50CF}\x{50D1}\x{50D5}\x{50D6}\x{50DA}\x{50DE}\x{50E3}' . +'\x{50E5}\x{50E7}\x{50ED}\x{50EE}\x{50F5}\x{50F9}\x{50FB}\x{5100}\x{5101}' . +'\x{5102}\x{5104}\x{5109}\x{5112}\x{5114}\x{5115}\x{5116}\x{5118}\x{511A}' . +'\x{511F}\x{5121}\x{512A}\x{5132}\x{5137}\x{513A}\x{513B}\x{513C}\x{513F}' . +'\x{5140}\x{5141}\x{5143}\x{5144}\x{5145}\x{5146}\x{5147}\x{5148}\x{5149}' . +'\x{514B}\x{514C}\x{514D}\x{514E}\x{5150}\x{5152}\x{5154}\x{515A}\x{515C}' . +'\x{5162}\x{5165}\x{5168}\x{5169}\x{516A}\x{516B}\x{516C}\x{516D}\x{516E}' . +'\x{5171}\x{5175}\x{5176}\x{5177}\x{5178}\x{517C}\x{5180}\x{5182}\x{5185}' . +'\x{5186}\x{5189}\x{518A}\x{518C}\x{518D}\x{518F}\x{5190}\x{5191}\x{5192}' . +'\x{5193}\x{5195}\x{5196}\x{5197}\x{5199}\x{51A0}\x{51A2}\x{51A4}\x{51A5}' . +'\x{51A6}\x{51A8}\x{51A9}\x{51AA}\x{51AB}\x{51AC}\x{51B0}\x{51B1}\x{51B2}' . +'\x{51B3}\x{51B4}\x{51B5}\x{51B6}\x{51B7}\x{51BD}\x{51C4}\x{51C5}\x{51C6}' . +'\x{51C9}\x{51CB}\x{51CC}\x{51CD}\x{51D6}\x{51DB}\x{51DC}\x{51DD}\x{51E0}' . +'\x{51E1}\x{51E6}\x{51E7}\x{51E9}\x{51EA}\x{51ED}\x{51F0}\x{51F1}\x{51F5}' . +'\x{51F6}\x{51F8}\x{51F9}\x{51FA}\x{51FD}\x{51FE}\x{5200}\x{5203}\x{5204}' . +'\x{5206}\x{5207}\x{5208}\x{520A}\x{520B}\x{520E}\x{5211}\x{5214}\x{5217}' . +'\x{521D}\x{5224}\x{5225}\x{5227}\x{5229}\x{522A}\x{522E}\x{5230}\x{5233}' . +'\x{5236}\x{5237}\x{5238}\x{5239}\x{523A}\x{523B}\x{5243}\x{5244}\x{5247}' . +'\x{524A}\x{524B}\x{524C}\x{524D}\x{524F}\x{5254}\x{5256}\x{525B}\x{525E}' . +'\x{5263}\x{5264}\x{5265}\x{5269}\x{526A}\x{526F}\x{5270}\x{5271}\x{5272}' . +'\x{5273}\x{5274}\x{5275}\x{527D}\x{527F}\x{5283}\x{5287}\x{5288}\x{5289}' . +'\x{528D}\x{5291}\x{5292}\x{5294}\x{529B}\x{529F}\x{52A0}\x{52A3}\x{52A9}' . +'\x{52AA}\x{52AB}\x{52AC}\x{52AD}\x{52B1}\x{52B4}\x{52B5}\x{52B9}\x{52BC}' . +'\x{52BE}\x{52C1}\x{52C3}\x{52C5}\x{52C7}\x{52C9}\x{52CD}\x{52D2}\x{52D5}' . +'\x{52D7}\x{52D8}\x{52D9}\x{52DD}\x{52DE}\x{52DF}\x{52E0}\x{52E2}\x{52E3}' . +'\x{52E4}\x{52E6}\x{52E7}\x{52F2}\x{52F3}\x{52F5}\x{52F8}\x{52F9}\x{52FA}' . +'\x{52FE}\x{52FF}\x{5301}\x{5302}\x{5305}\x{5306}\x{5308}\x{530D}\x{530F}' . +'\x{5310}\x{5315}\x{5316}\x{5317}\x{5319}\x{531A}\x{531D}\x{5320}\x{5321}' . +'\x{5323}\x{532A}\x{532F}\x{5331}\x{5333}\x{5338}\x{5339}\x{533A}\x{533B}' . +'\x{533F}\x{5340}\x{5341}\x{5343}\x{5345}\x{5346}\x{5347}\x{5348}\x{5349}' . +'\x{534A}\x{534D}\x{5351}\x{5352}\x{5353}\x{5354}\x{5357}\x{5358}\x{535A}' . +'\x{535C}\x{535E}\x{5360}\x{5366}\x{5369}\x{536E}\x{536F}\x{5370}\x{5371}' . +'\x{5373}\x{5374}\x{5375}\x{5377}\x{5378}\x{537B}\x{537F}\x{5382}\x{5384}' . +'\x{5396}\x{5398}\x{539A}\x{539F}\x{53A0}\x{53A5}\x{53A6}\x{53A8}\x{53A9}' . +'\x{53AD}\x{53AE}\x{53B0}\x{53B3}\x{53B6}\x{53BB}\x{53C2}\x{53C3}\x{53C8}' . +'\x{53C9}\x{53CA}\x{53CB}\x{53CC}\x{53CD}\x{53CE}\x{53D4}\x{53D6}\x{53D7}' . +'\x{53D9}\x{53DB}\x{53DF}\x{53E1}\x{53E2}\x{53E3}\x{53E4}\x{53E5}\x{53E8}' . +'\x{53E9}\x{53EA}\x{53EB}\x{53EC}\x{53ED}\x{53EE}\x{53EF}\x{53F0}\x{53F1}' . +'\x{53F2}\x{53F3}\x{53F6}\x{53F7}\x{53F8}\x{53FA}\x{5401}\x{5403}\x{5404}' . +'\x{5408}\x{5409}\x{540A}\x{540B}\x{540C}\x{540D}\x{540E}\x{540F}\x{5410}' . +'\x{5411}\x{541B}\x{541D}\x{541F}\x{5420}\x{5426}\x{5429}\x{542B}\x{542C}' . +'\x{542D}\x{542E}\x{5436}\x{5438}\x{5439}\x{543B}\x{543C}\x{543D}\x{543E}' . +'\x{5440}\x{5442}\x{5446}\x{5448}\x{5449}\x{544A}\x{544E}\x{5451}\x{545F}' . +'\x{5468}\x{546A}\x{5470}\x{5471}\x{5473}\x{5475}\x{5476}\x{5477}\x{547B}' . +'\x{547C}\x{547D}\x{5480}\x{5484}\x{5486}\x{548B}\x{548C}\x{548E}\x{548F}' . +'\x{5490}\x{5492}\x{54A2}\x{54A4}\x{54A5}\x{54A8}\x{54AB}\x{54AC}\x{54AF}' . +'\x{54B2}\x{54B3}\x{54B8}\x{54BC}\x{54BD}\x{54BE}\x{54C0}\x{54C1}\x{54C2}' . +'\x{54C4}\x{54C7}\x{54C8}\x{54C9}\x{54D8}\x{54E1}\x{54E2}\x{54E5}\x{54E6}' . +'\x{54E8}\x{54E9}\x{54ED}\x{54EE}\x{54F2}\x{54FA}\x{54FD}\x{5504}\x{5506}' . +'\x{5507}\x{550F}\x{5510}\x{5514}\x{5516}\x{552E}\x{552F}\x{5531}\x{5533}' . +'\x{5538}\x{5539}\x{553E}\x{5540}\x{5544}\x{5545}\x{5546}\x{554C}\x{554F}' . +'\x{5553}\x{5556}\x{5557}\x{555C}\x{555D}\x{5563}\x{557B}\x{557C}\x{557E}' . +'\x{5580}\x{5583}\x{5584}\x{5587}\x{5589}\x{558A}\x{558B}\x{5598}\x{5599}' . +'\x{559A}\x{559C}\x{559D}\x{559E}\x{559F}\x{55A7}\x{55A8}\x{55A9}\x{55AA}' . +'\x{55AB}\x{55AC}\x{55AE}\x{55B0}\x{55B6}\x{55C4}\x{55C5}\x{55C7}\x{55D4}' . +'\x{55DA}\x{55DC}\x{55DF}\x{55E3}\x{55E4}\x{55F7}\x{55F9}\x{55FD}\x{55FE}' . +'\x{5606}\x{5609}\x{5614}\x{5616}\x{5617}\x{5618}\x{561B}\x{5629}\x{562F}' . +'\x{5631}\x{5632}\x{5634}\x{5636}\x{5638}\x{5642}\x{564C}\x{564E}\x{5650}' . +'\x{565B}\x{5664}\x{5668}\x{566A}\x{566B}\x{566C}\x{5674}\x{5678}\x{567A}' . +'\x{5680}\x{5686}\x{5687}\x{568A}\x{568F}\x{5694}\x{56A0}\x{56A2}\x{56A5}' . +'\x{56AE}\x{56B4}\x{56B6}\x{56BC}\x{56C0}\x{56C1}\x{56C2}\x{56C3}\x{56C8}' . +'\x{56CE}\x{56D1}\x{56D3}\x{56D7}\x{56D8}\x{56DA}\x{56DB}\x{56DE}\x{56E0}' . +'\x{56E3}\x{56EE}\x{56F0}\x{56F2}\x{56F3}\x{56F9}\x{56FA}\x{56FD}\x{56FF}' . +'\x{5700}\x{5703}\x{5704}\x{5708}\x{5709}\x{570B}\x{570D}\x{570F}\x{5712}' . +'\x{5713}\x{5716}\x{5718}\x{571C}\x{571F}\x{5726}\x{5727}\x{5728}\x{572D}' . +'\x{5730}\x{5737}\x{5738}\x{573B}\x{5740}\x{5742}\x{5747}\x{574A}\x{574E}' . +'\x{574F}\x{5750}\x{5751}\x{5761}\x{5764}\x{5766}\x{5769}\x{576A}\x{577F}' . +'\x{5782}\x{5788}\x{5789}\x{578B}\x{5793}\x{57A0}\x{57A2}\x{57A3}\x{57A4}' . +'\x{57AA}\x{57B0}\x{57B3}\x{57C0}\x{57C3}\x{57C6}\x{57CB}\x{57CE}\x{57D2}' . +'\x{57D3}\x{57D4}\x{57D6}\x{57DC}\x{57DF}\x{57E0}\x{57E3}\x{57F4}\x{57F7}' . +'\x{57F9}\x{57FA}\x{57FC}\x{5800}\x{5802}\x{5805}\x{5806}\x{580A}\x{580B}' . +'\x{5815}\x{5819}\x{581D}\x{5821}\x{5824}\x{582A}\x{582F}\x{5830}\x{5831}' . +'\x{5834}\x{5835}\x{583A}\x{583D}\x{5840}\x{5841}\x{584A}\x{584B}\x{5851}' . +'\x{5852}\x{5854}\x{5857}\x{5858}\x{5859}\x{585A}\x{585E}\x{5862}\x{5869}' . +'\x{586B}\x{5870}\x{5872}\x{5875}\x{5879}\x{587E}\x{5883}\x{5885}\x{5893}' . +'\x{5897}\x{589C}\x{589F}\x{58A8}\x{58AB}\x{58AE}\x{58B3}\x{58B8}\x{58B9}' . +'\x{58BA}\x{58BB}\x{58BE}\x{58C1}\x{58C5}\x{58C7}\x{58CA}\x{58CC}\x{58D1}' . +'\x{58D3}\x{58D5}\x{58D7}\x{58D8}\x{58D9}\x{58DC}\x{58DE}\x{58DF}\x{58E4}' . +'\x{58E5}\x{58EB}\x{58EC}\x{58EE}\x{58EF}\x{58F0}\x{58F1}\x{58F2}\x{58F7}' . +'\x{58F9}\x{58FA}\x{58FB}\x{58FC}\x{58FD}\x{5902}\x{5909}\x{590A}\x{590F}' . +'\x{5910}\x{5915}\x{5916}\x{5918}\x{5919}\x{591A}\x{591B}\x{591C}\x{5922}' . +'\x{5925}\x{5927}\x{5929}\x{592A}\x{592B}\x{592C}\x{592D}\x{592E}\x{5931}' . +'\x{5932}\x{5937}\x{5938}\x{593E}\x{5944}\x{5947}\x{5948}\x{5949}\x{594E}' . +'\x{594F}\x{5950}\x{5951}\x{5954}\x{5955}\x{5957}\x{5958}\x{595A}\x{5960}' . +'\x{5962}\x{5965}\x{5967}\x{5968}\x{5969}\x{596A}\x{596C}\x{596E}\x{5973}' . +'\x{5974}\x{5978}\x{597D}\x{5981}\x{5982}\x{5983}\x{5984}\x{598A}\x{598D}' . +'\x{5993}\x{5996}\x{5999}\x{599B}\x{599D}\x{59A3}\x{59A5}\x{59A8}\x{59AC}' . +'\x{59B2}\x{59B9}\x{59BB}\x{59BE}\x{59C6}\x{59C9}\x{59CB}\x{59D0}\x{59D1}' . +'\x{59D3}\x{59D4}\x{59D9}\x{59DA}\x{59DC}\x{59E5}\x{59E6}\x{59E8}\x{59EA}' . +'\x{59EB}\x{59F6}\x{59FB}\x{59FF}\x{5A01}\x{5A03}\x{5A09}\x{5A11}\x{5A18}' . +'\x{5A1A}\x{5A1C}\x{5A1F}\x{5A20}\x{5A25}\x{5A29}\x{5A2F}\x{5A35}\x{5A36}' . +'\x{5A3C}\x{5A40}\x{5A41}\x{5A46}\x{5A49}\x{5A5A}\x{5A62}\x{5A66}\x{5A6A}' . +'\x{5A6C}\x{5A7F}\x{5A92}\x{5A9A}\x{5A9B}\x{5ABC}\x{5ABD}\x{5ABE}\x{5AC1}' . +'\x{5AC2}\x{5AC9}\x{5ACB}\x{5ACC}\x{5AD0}\x{5AD6}\x{5AD7}\x{5AE1}\x{5AE3}' . +'\x{5AE6}\x{5AE9}\x{5AFA}\x{5AFB}\x{5B09}\x{5B0B}\x{5B0C}\x{5B16}\x{5B22}' . +'\x{5B2A}\x{5B2C}\x{5B30}\x{5B32}\x{5B36}\x{5B3E}\x{5B40}\x{5B43}\x{5B45}' . +'\x{5B50}\x{5B51}\x{5B54}\x{5B55}\x{5B57}\x{5B58}\x{5B5A}\x{5B5B}\x{5B5C}' . +'\x{5B5D}\x{5B5F}\x{5B63}\x{5B64}\x{5B65}\x{5B66}\x{5B69}\x{5B6B}\x{5B70}' . +'\x{5B71}\x{5B73}\x{5B75}\x{5B78}\x{5B7A}\x{5B80}\x{5B83}\x{5B85}\x{5B87}' . +'\x{5B88}\x{5B89}\x{5B8B}\x{5B8C}\x{5B8D}\x{5B8F}\x{5B95}\x{5B97}\x{5B98}' . +'\x{5B99}\x{5B9A}\x{5B9B}\x{5B9C}\x{5B9D}\x{5B9F}\x{5BA2}\x{5BA3}\x{5BA4}' . +'\x{5BA5}\x{5BA6}\x{5BAE}\x{5BB0}\x{5BB3}\x{5BB4}\x{5BB5}\x{5BB6}\x{5BB8}' . +'\x{5BB9}\x{5BBF}\x{5BC2}\x{5BC3}\x{5BC4}\x{5BC5}\x{5BC6}\x{5BC7}\x{5BC9}' . +'\x{5BCC}\x{5BD0}\x{5BD2}\x{5BD3}\x{5BD4}\x{5BDB}\x{5BDD}\x{5BDE}\x{5BDF}' . +'\x{5BE1}\x{5BE2}\x{5BE4}\x{5BE5}\x{5BE6}\x{5BE7}\x{5BE8}\x{5BE9}\x{5BEB}' . +'\x{5BEE}\x{5BF0}\x{5BF3}\x{5BF5}\x{5BF6}\x{5BF8}\x{5BFA}\x{5BFE}\x{5BFF}' . +'\x{5C01}\x{5C02}\x{5C04}\x{5C05}\x{5C06}\x{5C07}\x{5C08}\x{5C09}\x{5C0A}' . +'\x{5C0B}\x{5C0D}\x{5C0E}\x{5C0F}\x{5C11}\x{5C13}\x{5C16}\x{5C1A}\x{5C20}' . +'\x{5C22}\x{5C24}\x{5C28}\x{5C2D}\x{5C31}\x{5C38}\x{5C39}\x{5C3A}\x{5C3B}' . +'\x{5C3C}\x{5C3D}\x{5C3E}\x{5C3F}\x{5C40}\x{5C41}\x{5C45}\x{5C46}\x{5C48}' . +'\x{5C4A}\x{5C4B}\x{5C4D}\x{5C4E}\x{5C4F}\x{5C50}\x{5C51}\x{5C53}\x{5C55}' . +'\x{5C5E}\x{5C60}\x{5C61}\x{5C64}\x{5C65}\x{5C6C}\x{5C6E}\x{5C6F}\x{5C71}' . +'\x{5C76}\x{5C79}\x{5C8C}\x{5C90}\x{5C91}\x{5C94}\x{5CA1}\x{5CA8}\x{5CA9}' . +'\x{5CAB}\x{5CAC}\x{5CB1}\x{5CB3}\x{5CB6}\x{5CB7}\x{5CB8}\x{5CBB}\x{5CBC}' . +'\x{5CBE}\x{5CC5}\x{5CC7}\x{5CD9}\x{5CE0}\x{5CE1}\x{5CE8}\x{5CE9}\x{5CEA}' . +'\x{5CED}\x{5CEF}\x{5CF0}\x{5CF6}\x{5CFA}\x{5CFB}\x{5CFD}\x{5D07}\x{5D0B}' . +'\x{5D0E}\x{5D11}\x{5D14}\x{5D15}\x{5D16}\x{5D17}\x{5D18}\x{5D19}\x{5D1A}' . +'\x{5D1B}\x{5D1F}\x{5D22}\x{5D29}\x{5D4B}\x{5D4C}\x{5D4E}\x{5D50}\x{5D52}' . +'\x{5D5C}\x{5D69}\x{5D6C}\x{5D6F}\x{5D73}\x{5D76}\x{5D82}\x{5D84}\x{5D87}' . +'\x{5D8B}\x{5D8C}\x{5D90}\x{5D9D}\x{5DA2}\x{5DAC}\x{5DAE}\x{5DB7}\x{5DBA}' . +'\x{5DBC}\x{5DBD}\x{5DC9}\x{5DCC}\x{5DCD}\x{5DD2}\x{5DD3}\x{5DD6}\x{5DDB}' . +'\x{5DDD}\x{5DDE}\x{5DE1}\x{5DE3}\x{5DE5}\x{5DE6}\x{5DE7}\x{5DE8}\x{5DEB}' . +'\x{5DEE}\x{5DF1}\x{5DF2}\x{5DF3}\x{5DF4}\x{5DF5}\x{5DF7}\x{5DFB}\x{5DFD}' . +'\x{5DFE}\x{5E02}\x{5E03}\x{5E06}\x{5E0B}\x{5E0C}\x{5E11}\x{5E16}\x{5E19}' . +'\x{5E1A}\x{5E1B}\x{5E1D}\x{5E25}\x{5E2B}\x{5E2D}\x{5E2F}\x{5E30}\x{5E33}' . +'\x{5E36}\x{5E37}\x{5E38}\x{5E3D}\x{5E40}\x{5E43}\x{5E44}\x{5E45}\x{5E47}' . +'\x{5E4C}\x{5E4E}\x{5E54}\x{5E55}\x{5E57}\x{5E5F}\x{5E61}\x{5E62}\x{5E63}' . +'\x{5E64}\x{5E72}\x{5E73}\x{5E74}\x{5E75}\x{5E76}\x{5E78}\x{5E79}\x{5E7A}' . +'\x{5E7B}\x{5E7C}\x{5E7D}\x{5E7E}\x{5E7F}\x{5E81}\x{5E83}\x{5E84}\x{5E87}' . +'\x{5E8A}\x{5E8F}\x{5E95}\x{5E96}\x{5E97}\x{5E9A}\x{5E9C}\x{5EA0}\x{5EA6}' . +'\x{5EA7}\x{5EAB}\x{5EAD}\x{5EB5}\x{5EB6}\x{5EB7}\x{5EB8}\x{5EC1}\x{5EC2}' . +'\x{5EC3}\x{5EC8}\x{5EC9}\x{5ECA}\x{5ECF}\x{5ED0}\x{5ED3}\x{5ED6}\x{5EDA}' . +'\x{5EDB}\x{5EDD}\x{5EDF}\x{5EE0}\x{5EE1}\x{5EE2}\x{5EE3}\x{5EE8}\x{5EE9}' . +'\x{5EEC}\x{5EF0}\x{5EF1}\x{5EF3}\x{5EF4}\x{5EF6}\x{5EF7}\x{5EF8}\x{5EFA}' . +'\x{5EFB}\x{5EFC}\x{5EFE}\x{5EFF}\x{5F01}\x{5F03}\x{5F04}\x{5F09}\x{5F0A}' . +'\x{5F0B}\x{5F0C}\x{5F0D}\x{5F0F}\x{5F10}\x{5F11}\x{5F13}\x{5F14}\x{5F15}' . +'\x{5F16}\x{5F17}\x{5F18}\x{5F1B}\x{5F1F}\x{5F25}\x{5F26}\x{5F27}\x{5F29}' . +'\x{5F2D}\x{5F2F}\x{5F31}\x{5F35}\x{5F37}\x{5F38}\x{5F3C}\x{5F3E}\x{5F41}' . +'\x{5F48}\x{5F4A}\x{5F4C}\x{5F4E}\x{5F51}\x{5F53}\x{5F56}\x{5F57}\x{5F59}' . +'\x{5F5C}\x{5F5D}\x{5F61}\x{5F62}\x{5F66}\x{5F69}\x{5F6A}\x{5F6B}\x{5F6C}' . +'\x{5F6D}\x{5F70}\x{5F71}\x{5F73}\x{5F77}\x{5F79}\x{5F7C}\x{5F7F}\x{5F80}' . +'\x{5F81}\x{5F82}\x{5F83}\x{5F84}\x{5F85}\x{5F87}\x{5F88}\x{5F8A}\x{5F8B}' . +'\x{5F8C}\x{5F90}\x{5F91}\x{5F92}\x{5F93}\x{5F97}\x{5F98}\x{5F99}\x{5F9E}' . +'\x{5FA0}\x{5FA1}\x{5FA8}\x{5FA9}\x{5FAA}\x{5FAD}\x{5FAE}\x{5FB3}\x{5FB4}' . +'\x{5FB9}\x{5FBC}\x{5FBD}\x{5FC3}\x{5FC5}\x{5FCC}\x{5FCD}\x{5FD6}\x{5FD7}' . +'\x{5FD8}\x{5FD9}\x{5FDC}\x{5FDD}\x{5FE0}\x{5FE4}\x{5FEB}\x{5FF0}\x{5FF1}' . +'\x{5FF5}\x{5FF8}\x{5FFB}\x{5FFD}\x{5FFF}\x{600E}\x{600F}\x{6010}\x{6012}' . +'\x{6015}\x{6016}\x{6019}\x{601B}\x{601C}\x{601D}\x{6020}\x{6021}\x{6025}' . +'\x{6026}\x{6027}\x{6028}\x{6029}\x{602A}\x{602B}\x{602F}\x{6031}\x{603A}' . +'\x{6041}\x{6042}\x{6043}\x{6046}\x{604A}\x{604B}\x{604D}\x{6050}\x{6052}' . +'\x{6055}\x{6059}\x{605A}\x{605F}\x{6060}\x{6062}\x{6063}\x{6064}\x{6065}' . +'\x{6068}\x{6069}\x{606A}\x{606B}\x{606C}\x{606D}\x{606F}\x{6070}\x{6075}' . +'\x{6077}\x{6081}\x{6083}\x{6084}\x{6089}\x{608B}\x{608C}\x{608D}\x{6092}' . +'\x{6094}\x{6096}\x{6097}\x{609A}\x{609B}\x{609F}\x{60A0}\x{60A3}\x{60A6}' . +'\x{60A7}\x{60A9}\x{60AA}\x{60B2}\x{60B3}\x{60B4}\x{60B5}\x{60B6}\x{60B8}' . +'\x{60BC}\x{60BD}\x{60C5}\x{60C6}\x{60C7}\x{60D1}\x{60D3}\x{60D8}\x{60DA}' . +'\x{60DC}\x{60DF}\x{60E0}\x{60E1}\x{60E3}\x{60E7}\x{60E8}\x{60F0}\x{60F1}' . +'\x{60F3}\x{60F4}\x{60F6}\x{60F7}\x{60F9}\x{60FA}\x{60FB}\x{6100}\x{6101}' . +'\x{6103}\x{6106}\x{6108}\x{6109}\x{610D}\x{610E}\x{610F}\x{6115}\x{611A}' . +'\x{611B}\x{611F}\x{6121}\x{6127}\x{6128}\x{612C}\x{6134}\x{613C}\x{613D}' . +'\x{613E}\x{613F}\x{6142}\x{6144}\x{6147}\x{6148}\x{614A}\x{614B}\x{614C}' . +'\x{614D}\x{614E}\x{6153}\x{6155}\x{6158}\x{6159}\x{615A}\x{615D}\x{615F}' . +'\x{6162}\x{6163}\x{6165}\x{6167}\x{6168}\x{616B}\x{616E}\x{616F}\x{6170}' . +'\x{6171}\x{6173}\x{6174}\x{6175}\x{6176}\x{6177}\x{617E}\x{6182}\x{6187}' . +'\x{618A}\x{618E}\x{6190}\x{6191}\x{6194}\x{6196}\x{6199}\x{619A}\x{61A4}' . +'\x{61A7}\x{61A9}\x{61AB}\x{61AC}\x{61AE}\x{61B2}\x{61B6}\x{61BA}\x{61BE}' . +'\x{61C3}\x{61C6}\x{61C7}\x{61C8}\x{61C9}\x{61CA}\x{61CB}\x{61CC}\x{61CD}' . +'\x{61D0}\x{61E3}\x{61E6}\x{61F2}\x{61F4}\x{61F6}\x{61F7}\x{61F8}\x{61FA}' . +'\x{61FC}\x{61FD}\x{61FE}\x{61FF}\x{6200}\x{6208}\x{6209}\x{620A}\x{620C}' . +'\x{620D}\x{620E}\x{6210}\x{6211}\x{6212}\x{6214}\x{6216}\x{621A}\x{621B}' . +'\x{621D}\x{621E}\x{621F}\x{6221}\x{6226}\x{622A}\x{622E}\x{622F}\x{6230}' . +'\x{6232}\x{6233}\x{6234}\x{6238}\x{623B}\x{623F}\x{6240}\x{6241}\x{6247}' . +'\x{6248}\x{6249}\x{624B}\x{624D}\x{624E}\x{6253}\x{6255}\x{6258}\x{625B}' . +'\x{625E}\x{6260}\x{6263}\x{6268}\x{626E}\x{6271}\x{6276}\x{6279}\x{627C}' . +'\x{627E}\x{627F}\x{6280}\x{6282}\x{6283}\x{6284}\x{6289}\x{628A}\x{6291}' . +'\x{6292}\x{6293}\x{6294}\x{6295}\x{6296}\x{6297}\x{6298}\x{629B}\x{629C}' . +'\x{629E}\x{62AB}\x{62AC}\x{62B1}\x{62B5}\x{62B9}\x{62BB}\x{62BC}\x{62BD}' . +'\x{62C2}\x{62C5}\x{62C6}\x{62C7}\x{62C8}\x{62C9}\x{62CA}\x{62CC}\x{62CD}' . +'\x{62CF}\x{62D0}\x{62D1}\x{62D2}\x{62D3}\x{62D4}\x{62D7}\x{62D8}\x{62D9}' . +'\x{62DB}\x{62DC}\x{62DD}\x{62E0}\x{62E1}\x{62EC}\x{62ED}\x{62EE}\x{62EF}' . +'\x{62F1}\x{62F3}\x{62F5}\x{62F6}\x{62F7}\x{62FE}\x{62FF}\x{6301}\x{6302}' . +'\x{6307}\x{6308}\x{6309}\x{630C}\x{6311}\x{6319}\x{631F}\x{6327}\x{6328}' . +'\x{632B}\x{632F}\x{633A}\x{633D}\x{633E}\x{633F}\x{6349}\x{634C}\x{634D}' . +'\x{634F}\x{6350}\x{6355}\x{6357}\x{635C}\x{6367}\x{6368}\x{6369}\x{636B}' . +'\x{636E}\x{6372}\x{6376}\x{6377}\x{637A}\x{637B}\x{6380}\x{6383}\x{6388}' . +'\x{6389}\x{638C}\x{638E}\x{638F}\x{6392}\x{6396}\x{6398}\x{639B}\x{639F}' . +'\x{63A0}\x{63A1}\x{63A2}\x{63A3}\x{63A5}\x{63A7}\x{63A8}\x{63A9}\x{63AA}' . +'\x{63AB}\x{63AC}\x{63B2}\x{63B4}\x{63B5}\x{63BB}\x{63BE}\x{63C0}\x{63C3}' . +'\x{63C4}\x{63C6}\x{63C9}\x{63CF}\x{63D0}\x{63D2}\x{63D6}\x{63DA}\x{63DB}' . +'\x{63E1}\x{63E3}\x{63E9}\x{63EE}\x{63F4}\x{63F6}\x{63FA}\x{6406}\x{640D}' . +'\x{640F}\x{6413}\x{6416}\x{6417}\x{641C}\x{6426}\x{6428}\x{642C}\x{642D}' . +'\x{6434}\x{6436}\x{643A}\x{643E}\x{6442}\x{644E}\x{6458}\x{6467}\x{6469}' . +'\x{646F}\x{6476}\x{6478}\x{647A}\x{6483}\x{6488}\x{6492}\x{6493}\x{6495}' . +'\x{649A}\x{649E}\x{64A4}\x{64A5}\x{64A9}\x{64AB}\x{64AD}\x{64AE}\x{64B0}' . +'\x{64B2}\x{64B9}\x{64BB}\x{64BC}\x{64C1}\x{64C2}\x{64C5}\x{64C7}\x{64CD}' . +'\x{64D2}\x{64D4}\x{64D8}\x{64DA}\x{64E0}\x{64E1}\x{64E2}\x{64E3}\x{64E6}' . +'\x{64E7}\x{64EC}\x{64EF}\x{64F1}\x{64F2}\x{64F4}\x{64F6}\x{64FA}\x{64FD}' . +'\x{64FE}\x{6500}\x{6505}\x{6518}\x{651C}\x{651D}\x{6523}\x{6524}\x{652A}' . +'\x{652B}\x{652C}\x{652F}\x{6534}\x{6535}\x{6536}\x{6537}\x{6538}\x{6539}' . +'\x{653B}\x{653E}\x{653F}\x{6545}\x{6548}\x{654D}\x{654F}\x{6551}\x{6555}' . +'\x{6556}\x{6557}\x{6558}\x{6559}\x{655D}\x{655E}\x{6562}\x{6563}\x{6566}' . +'\x{656C}\x{6570}\x{6572}\x{6574}\x{6575}\x{6577}\x{6578}\x{6582}\x{6583}' . +'\x{6587}\x{6588}\x{6589}\x{658C}\x{658E}\x{6590}\x{6591}\x{6597}\x{6599}' . +'\x{659B}\x{659C}\x{659F}\x{65A1}\x{65A4}\x{65A5}\x{65A7}\x{65AB}\x{65AC}' . +'\x{65AD}\x{65AF}\x{65B0}\x{65B7}\x{65B9}\x{65BC}\x{65BD}\x{65C1}\x{65C3}' . +'\x{65C4}\x{65C5}\x{65C6}\x{65CB}\x{65CC}\x{65CF}\x{65D2}\x{65D7}\x{65D9}' . +'\x{65DB}\x{65E0}\x{65E1}\x{65E2}\x{65E5}\x{65E6}\x{65E7}\x{65E8}\x{65E9}' . +'\x{65EC}\x{65ED}\x{65F1}\x{65FA}\x{65FB}\x{6602}\x{6603}\x{6606}\x{6607}' . +'\x{660A}\x{660C}\x{660E}\x{660F}\x{6613}\x{6614}\x{661C}\x{661F}\x{6620}' . +'\x{6625}\x{6627}\x{6628}\x{662D}\x{662F}\x{6634}\x{6635}\x{6636}\x{663C}' . +'\x{663F}\x{6641}\x{6642}\x{6643}\x{6644}\x{6649}\x{664B}\x{664F}\x{6652}' . +'\x{665D}\x{665E}\x{665F}\x{6662}\x{6664}\x{6666}\x{6667}\x{6668}\x{6669}' . +'\x{666E}\x{666F}\x{6670}\x{6674}\x{6676}\x{667A}\x{6681}\x{6683}\x{6684}' . +'\x{6687}\x{6688}\x{6689}\x{668E}\x{6691}\x{6696}\x{6697}\x{6698}\x{669D}' . +'\x{66A2}\x{66A6}\x{66AB}\x{66AE}\x{66B4}\x{66B8}\x{66B9}\x{66BC}\x{66BE}' . +'\x{66C1}\x{66C4}\x{66C7}\x{66C9}\x{66D6}\x{66D9}\x{66DA}\x{66DC}\x{66DD}' . +'\x{66E0}\x{66E6}\x{66E9}\x{66F0}\x{66F2}\x{66F3}\x{66F4}\x{66F5}\x{66F7}' . +'\x{66F8}\x{66F9}\x{66FC}\x{66FD}\x{66FE}\x{66FF}\x{6700}\x{6703}\x{6708}' . +'\x{6709}\x{670B}\x{670D}\x{670F}\x{6714}\x{6715}\x{6716}\x{6717}\x{671B}' . +'\x{671D}\x{671E}\x{671F}\x{6726}\x{6727}\x{6728}\x{672A}\x{672B}\x{672C}' . +'\x{672D}\x{672E}\x{6731}\x{6734}\x{6736}\x{6737}\x{6738}\x{673A}\x{673D}' . +'\x{673F}\x{6741}\x{6746}\x{6749}\x{674E}\x{674F}\x{6750}\x{6751}\x{6753}' . +'\x{6756}\x{6759}\x{675C}\x{675E}\x{675F}\x{6760}\x{6761}\x{6762}\x{6763}' . +'\x{6764}\x{6765}\x{676A}\x{676D}\x{676F}\x{6770}\x{6771}\x{6772}\x{6773}' . +'\x{6775}\x{6777}\x{677C}\x{677E}\x{677F}\x{6785}\x{6787}\x{6789}\x{678B}' . +'\x{678C}\x{6790}\x{6795}\x{6797}\x{679A}\x{679C}\x{679D}\x{67A0}\x{67A1}' . +'\x{67A2}\x{67A6}\x{67A9}\x{67AF}\x{67B3}\x{67B4}\x{67B6}\x{67B7}\x{67B8}' . +'\x{67B9}\x{67C1}\x{67C4}\x{67C6}\x{67CA}\x{67CE}\x{67CF}\x{67D0}\x{67D1}' . +'\x{67D3}\x{67D4}\x{67D8}\x{67DA}\x{67DD}\x{67DE}\x{67E2}\x{67E4}\x{67E7}' . +'\x{67E9}\x{67EC}\x{67EE}\x{67EF}\x{67F1}\x{67F3}\x{67F4}\x{67F5}\x{67FB}' . +'\x{67FE}\x{67FF}\x{6802}\x{6803}\x{6804}\x{6813}\x{6816}\x{6817}\x{681E}' . +'\x{6821}\x{6822}\x{6829}\x{682A}\x{682B}\x{6832}\x{6834}\x{6838}\x{6839}' . +'\x{683C}\x{683D}\x{6840}\x{6841}\x{6842}\x{6843}\x{6846}\x{6848}\x{684D}' . +'\x{684E}\x{6850}\x{6851}\x{6853}\x{6854}\x{6859}\x{685C}\x{685D}\x{685F}' . +'\x{6863}\x{6867}\x{6874}\x{6876}\x{6877}\x{687E}\x{687F}\x{6881}\x{6883}' . +'\x{6885}\x{688D}\x{688F}\x{6893}\x{6894}\x{6897}\x{689B}\x{689D}\x{689F}' . +'\x{68A0}\x{68A2}\x{68A6}\x{68A7}\x{68A8}\x{68AD}\x{68AF}\x{68B0}\x{68B1}' . +'\x{68B3}\x{68B5}\x{68B6}\x{68B9}\x{68BA}\x{68BC}\x{68C4}\x{68C6}\x{68C9}' . +'\x{68CA}\x{68CB}\x{68CD}\x{68D2}\x{68D4}\x{68D5}\x{68D7}\x{68D8}\x{68DA}' . +'\x{68DF}\x{68E0}\x{68E1}\x{68E3}\x{68E7}\x{68EE}\x{68EF}\x{68F2}\x{68F9}' . +'\x{68FA}\x{6900}\x{6901}\x{6904}\x{6905}\x{6908}\x{690B}\x{690C}\x{690D}' . +'\x{690E}\x{690F}\x{6912}\x{6919}\x{691A}\x{691B}\x{691C}\x{6921}\x{6922}' . +'\x{6923}\x{6925}\x{6926}\x{6928}\x{692A}\x{6930}\x{6934}\x{6936}\x{6939}' . +'\x{693D}\x{693F}\x{694A}\x{6953}\x{6954}\x{6955}\x{6959}\x{695A}\x{695C}' . +'\x{695D}\x{695E}\x{6960}\x{6961}\x{6962}\x{696A}\x{696B}\x{696D}\x{696E}' . +'\x{696F}\x{6973}\x{6974}\x{6975}\x{6977}\x{6978}\x{6979}\x{697C}\x{697D}' . +'\x{697E}\x{6981}\x{6982}\x{698A}\x{698E}\x{6991}\x{6994}\x{6995}\x{699B}' . +'\x{699C}\x{69A0}\x{69A7}\x{69AE}\x{69B1}\x{69B2}\x{69B4}\x{69BB}\x{69BE}' . +'\x{69BF}\x{69C1}\x{69C3}\x{69C7}\x{69CA}\x{69CB}\x{69CC}\x{69CD}\x{69CE}' . +'\x{69D0}\x{69D3}\x{69D8}\x{69D9}\x{69DD}\x{69DE}\x{69E7}\x{69E8}\x{69EB}' . +'\x{69ED}\x{69F2}\x{69F9}\x{69FB}\x{69FD}\x{69FF}\x{6A02}\x{6A05}\x{6A0A}' . +'\x{6A0B}\x{6A0C}\x{6A12}\x{6A13}\x{6A14}\x{6A17}\x{6A19}\x{6A1B}\x{6A1E}' . +'\x{6A1F}\x{6A21}\x{6A22}\x{6A23}\x{6A29}\x{6A2A}\x{6A2B}\x{6A2E}\x{6A35}' . +'\x{6A36}\x{6A38}\x{6A39}\x{6A3A}\x{6A3D}\x{6A44}\x{6A47}\x{6A48}\x{6A4B}' . +'\x{6A58}\x{6A59}\x{6A5F}\x{6A61}\x{6A62}\x{6A66}\x{6A72}\x{6A78}\x{6A7F}' . +'\x{6A80}\x{6A84}\x{6A8D}\x{6A8E}\x{6A90}\x{6A97}\x{6A9C}\x{6AA0}\x{6AA2}' . +'\x{6AA3}\x{6AAA}\x{6AAC}\x{6AAE}\x{6AB3}\x{6AB8}\x{6ABB}\x{6AC1}\x{6AC2}' . +'\x{6AC3}\x{6AD1}\x{6AD3}\x{6ADA}\x{6ADB}\x{6ADE}\x{6ADF}\x{6AE8}\x{6AEA}' . +'\x{6AFA}\x{6AFB}\x{6B04}\x{6B05}\x{6B0A}\x{6B12}\x{6B16}\x{6B1D}\x{6B1F}' . +'\x{6B20}\x{6B21}\x{6B23}\x{6B27}\x{6B32}\x{6B37}\x{6B38}\x{6B39}\x{6B3A}' . +'\x{6B3D}\x{6B3E}\x{6B43}\x{6B47}\x{6B49}\x{6B4C}\x{6B4E}\x{6B50}\x{6B53}' . +'\x{6B54}\x{6B59}\x{6B5B}\x{6B5F}\x{6B61}\x{6B62}\x{6B63}\x{6B64}\x{6B66}' . +'\x{6B69}\x{6B6A}\x{6B6F}\x{6B73}\x{6B74}\x{6B78}\x{6B79}\x{6B7B}\x{6B7F}' . +'\x{6B80}\x{6B83}\x{6B84}\x{6B86}\x{6B89}\x{6B8A}\x{6B8B}\x{6B8D}\x{6B95}' . +'\x{6B96}\x{6B98}\x{6B9E}\x{6BA4}\x{6BAA}\x{6BAB}\x{6BAF}\x{6BB1}\x{6BB2}' . +'\x{6BB3}\x{6BB4}\x{6BB5}\x{6BB7}\x{6BBA}\x{6BBB}\x{6BBC}\x{6BBF}\x{6BC0}' . +'\x{6BC5}\x{6BC6}\x{6BCB}\x{6BCD}\x{6BCE}\x{6BD2}\x{6BD3}\x{6BD4}\x{6BD8}' . +'\x{6BDB}\x{6BDF}\x{6BEB}\x{6BEC}\x{6BEF}\x{6BF3}\x{6C08}\x{6C0F}\x{6C11}' . +'\x{6C13}\x{6C14}\x{6C17}\x{6C1B}\x{6C23}\x{6C24}\x{6C34}\x{6C37}\x{6C38}' . +'\x{6C3E}\x{6C40}\x{6C41}\x{6C42}\x{6C4E}\x{6C50}\x{6C55}\x{6C57}\x{6C5A}' . +'\x{6C5D}\x{6C5E}\x{6C5F}\x{6C60}\x{6C62}\x{6C68}\x{6C6A}\x{6C70}\x{6C72}' . +'\x{6C73}\x{6C7A}\x{6C7D}\x{6C7E}\x{6C81}\x{6C82}\x{6C83}\x{6C88}\x{6C8C}' . +'\x{6C8D}\x{6C90}\x{6C92}\x{6C93}\x{6C96}\x{6C99}\x{6C9A}\x{6C9B}\x{6CA1}' . +'\x{6CA2}\x{6CAB}\x{6CAE}\x{6CB1}\x{6CB3}\x{6CB8}\x{6CB9}\x{6CBA}\x{6CBB}' . +'\x{6CBC}\x{6CBD}\x{6CBE}\x{6CBF}\x{6CC1}\x{6CC4}\x{6CC5}\x{6CC9}\x{6CCA}' . +'\x{6CCC}\x{6CD3}\x{6CD5}\x{6CD7}\x{6CD9}\x{6CDB}\x{6CDD}\x{6CE1}\x{6CE2}' . +'\x{6CE3}\x{6CE5}\x{6CE8}\x{6CEA}\x{6CEF}\x{6CF0}\x{6CF1}\x{6CF3}\x{6D0B}' . +'\x{6D0C}\x{6D12}\x{6D17}\x{6D19}\x{6D1B}\x{6D1E}\x{6D1F}\x{6D25}\x{6D29}' . +'\x{6D2A}\x{6D2B}\x{6D32}\x{6D33}\x{6D35}\x{6D36}\x{6D38}\x{6D3B}\x{6D3D}' . +'\x{6D3E}\x{6D41}\x{6D44}\x{6D45}\x{6D59}\x{6D5A}\x{6D5C}\x{6D63}\x{6D64}' . +'\x{6D66}\x{6D69}\x{6D6A}\x{6D6C}\x{6D6E}\x{6D74}\x{6D77}\x{6D78}\x{6D79}' . +'\x{6D85}\x{6D88}\x{6D8C}\x{6D8E}\x{6D93}\x{6D95}\x{6D99}\x{6D9B}\x{6D9C}' . +'\x{6DAF}\x{6DB2}\x{6DB5}\x{6DB8}\x{6DBC}\x{6DC0}\x{6DC5}\x{6DC6}\x{6DC7}' . +'\x{6DCB}\x{6DCC}\x{6DD1}\x{6DD2}\x{6DD5}\x{6DD8}\x{6DD9}\x{6DDE}\x{6DE1}' . +'\x{6DE4}\x{6DE6}\x{6DE8}\x{6DEA}\x{6DEB}\x{6DEC}\x{6DEE}\x{6DF1}\x{6DF3}' . +'\x{6DF5}\x{6DF7}\x{6DF9}\x{6DFA}\x{6DFB}\x{6E05}\x{6E07}\x{6E08}\x{6E09}' . +'\x{6E0A}\x{6E0B}\x{6E13}\x{6E15}\x{6E19}\x{6E1A}\x{6E1B}\x{6E1D}\x{6E1F}' . +'\x{6E20}\x{6E21}\x{6E23}\x{6E24}\x{6E25}\x{6E26}\x{6E29}\x{6E2B}\x{6E2C}' . +'\x{6E2D}\x{6E2E}\x{6E2F}\x{6E38}\x{6E3A}\x{6E3E}\x{6E43}\x{6E4A}\x{6E4D}' . +'\x{6E4E}\x{6E56}\x{6E58}\x{6E5B}\x{6E5F}\x{6E67}\x{6E6B}\x{6E6E}\x{6E6F}' . +'\x{6E72}\x{6E76}\x{6E7E}\x{6E7F}\x{6E80}\x{6E82}\x{6E8C}\x{6E8F}\x{6E90}' . +'\x{6E96}\x{6E98}\x{6E9C}\x{6E9D}\x{6E9F}\x{6EA2}\x{6EA5}\x{6EAA}\x{6EAF}' . +'\x{6EB2}\x{6EB6}\x{6EB7}\x{6EBA}\x{6EBD}\x{6EC2}\x{6EC4}\x{6EC5}\x{6EC9}' . +'\x{6ECB}\x{6ECC}\x{6ED1}\x{6ED3}\x{6ED4}\x{6ED5}\x{6EDD}\x{6EDE}\x{6EEC}' . +'\x{6EEF}\x{6EF2}\x{6EF4}\x{6EF7}\x{6EF8}\x{6EFE}\x{6EFF}\x{6F01}\x{6F02}' . +'\x{6F06}\x{6F09}\x{6F0F}\x{6F11}\x{6F13}\x{6F14}\x{6F15}\x{6F20}\x{6F22}' . +'\x{6F23}\x{6F2B}\x{6F2C}\x{6F31}\x{6F32}\x{6F38}\x{6F3E}\x{6F3F}\x{6F41}' . +'\x{6F45}\x{6F54}\x{6F58}\x{6F5B}\x{6F5C}\x{6F5F}\x{6F64}\x{6F66}\x{6F6D}' . +'\x{6F6E}\x{6F6F}\x{6F70}\x{6F74}\x{6F78}\x{6F7A}\x{6F7C}\x{6F80}\x{6F81}' . +'\x{6F82}\x{6F84}\x{6F86}\x{6F8E}\x{6F91}\x{6F97}\x{6FA1}\x{6FA3}\x{6FA4}' . +'\x{6FAA}\x{6FB1}\x{6FB3}\x{6FB9}\x{6FC0}\x{6FC1}\x{6FC2}\x{6FC3}\x{6FC6}' . +'\x{6FD4}\x{6FD5}\x{6FD8}\x{6FDB}\x{6FDF}\x{6FE0}\x{6FE1}\x{6FE4}\x{6FEB}' . +'\x{6FEC}\x{6FEE}\x{6FEF}\x{6FF1}\x{6FF3}\x{6FF6}\x{6FFA}\x{6FFE}\x{7001}' . +'\x{7009}\x{700B}\x{700F}\x{7011}\x{7015}\x{7018}\x{701A}\x{701B}\x{701D}' . +'\x{701E}\x{701F}\x{7026}\x{7027}\x{702C}\x{7030}\x{7032}\x{703E}\x{704C}' . +'\x{7051}\x{7058}\x{7063}\x{706B}\x{706F}\x{7070}\x{7078}\x{707C}\x{707D}' . +'\x{7089}\x{708A}\x{708E}\x{7092}\x{7099}\x{70AC}\x{70AD}\x{70AE}\x{70AF}' . +'\x{70B3}\x{70B8}\x{70B9}\x{70BA}\x{70C8}\x{70CB}\x{70CF}\x{70D9}\x{70DD}' . +'\x{70DF}\x{70F1}\x{70F9}\x{70FD}\x{7109}\x{7114}\x{7119}\x{711A}\x{711C}' . +'\x{7121}\x{7126}\x{7136}\x{713C}\x{7149}\x{714C}\x{714E}\x{7155}\x{7156}' . +'\x{7159}\x{7162}\x{7164}\x{7165}\x{7166}\x{7167}\x{7169}\x{716C}\x{716E}' . +'\x{717D}\x{7184}\x{7188}\x{718A}\x{718F}\x{7194}\x{7195}\x{7199}\x{719F}' . +'\x{71A8}\x{71AC}\x{71B1}\x{71B9}\x{71BE}\x{71C3}\x{71C8}\x{71C9}\x{71CE}' . +'\x{71D0}\x{71D2}\x{71D4}\x{71D5}\x{71D7}\x{71DF}\x{71E0}\x{71E5}\x{71E6}' . +'\x{71E7}\x{71EC}\x{71ED}\x{71EE}\x{71F5}\x{71F9}\x{71FB}\x{71FC}\x{71FF}' . +'\x{7206}\x{720D}\x{7210}\x{721B}\x{7228}\x{722A}\x{722C}\x{722D}\x{7230}' . +'\x{7232}\x{7235}\x{7236}\x{723A}\x{723B}\x{723C}\x{723D}\x{723E}\x{723F}' . +'\x{7240}\x{7246}\x{7247}\x{7248}\x{724B}\x{724C}\x{7252}\x{7258}\x{7259}' . +'\x{725B}\x{725D}\x{725F}\x{7261}\x{7262}\x{7267}\x{7269}\x{7272}\x{7274}' . +'\x{7279}\x{727D}\x{727E}\x{7280}\x{7281}\x{7282}\x{7287}\x{7292}\x{7296}' . +'\x{72A0}\x{72A2}\x{72A7}\x{72AC}\x{72AF}\x{72B2}\x{72B6}\x{72B9}\x{72C2}' . +'\x{72C3}\x{72C4}\x{72C6}\x{72CE}\x{72D0}\x{72D2}\x{72D7}\x{72D9}\x{72DB}' . +'\x{72E0}\x{72E1}\x{72E2}\x{72E9}\x{72EC}\x{72ED}\x{72F7}\x{72F8}\x{72F9}' . +'\x{72FC}\x{72FD}\x{730A}\x{7316}\x{7317}\x{731B}\x{731C}\x{731D}\x{731F}' . +'\x{7325}\x{7329}\x{732A}\x{732B}\x{732E}\x{732F}\x{7334}\x{7336}\x{7337}' . +'\x{733E}\x{733F}\x{7344}\x{7345}\x{734E}\x{734F}\x{7357}\x{7363}\x{7368}' . +'\x{736A}\x{7370}\x{7372}\x{7375}\x{7378}\x{737A}\x{737B}\x{7384}\x{7387}' . +'\x{7389}\x{738B}\x{7396}\x{73A9}\x{73B2}\x{73B3}\x{73BB}\x{73C0}\x{73C2}' . +'\x{73C8}\x{73CA}\x{73CD}\x{73CE}\x{73DE}\x{73E0}\x{73E5}\x{73EA}\x{73ED}' . +'\x{73EE}\x{73F1}\x{73F8}\x{73FE}\x{7403}\x{7405}\x{7406}\x{7409}\x{7422}' . +'\x{7425}\x{7432}\x{7433}\x{7434}\x{7435}\x{7436}\x{743A}\x{743F}\x{7441}' . +'\x{7455}\x{7459}\x{745A}\x{745B}\x{745C}\x{745E}\x{745F}\x{7460}\x{7463}' . +'\x{7464}\x{7469}\x{746A}\x{746F}\x{7470}\x{7473}\x{7476}\x{747E}\x{7483}' . +'\x{748B}\x{749E}\x{74A2}\x{74A7}\x{74B0}\x{74BD}\x{74CA}\x{74CF}\x{74D4}' . +'\x{74DC}\x{74E0}\x{74E2}\x{74E3}\x{74E6}\x{74E7}\x{74E9}\x{74EE}\x{74F0}' . +'\x{74F1}\x{74F2}\x{74F6}\x{74F7}\x{74F8}\x{7503}\x{7504}\x{7505}\x{750C}' . +'\x{750D}\x{750E}\x{7511}\x{7513}\x{7515}\x{7518}\x{751A}\x{751C}\x{751E}' . +'\x{751F}\x{7523}\x{7525}\x{7526}\x{7528}\x{752B}\x{752C}\x{7530}\x{7531}' . +'\x{7532}\x{7533}\x{7537}\x{7538}\x{753A}\x{753B}\x{753C}\x{7544}\x{7546}' . +'\x{7549}\x{754A}\x{754B}\x{754C}\x{754D}\x{754F}\x{7551}\x{7554}\x{7559}' . +'\x{755A}\x{755B}\x{755C}\x{755D}\x{7560}\x{7562}\x{7564}\x{7565}\x{7566}' . +'\x{7567}\x{7569}\x{756A}\x{756B}\x{756D}\x{7570}\x{7573}\x{7574}\x{7576}' . +'\x{7577}\x{7578}\x{757F}\x{7582}\x{7586}\x{7587}\x{7589}\x{758A}\x{758B}' . +'\x{758E}\x{758F}\x{7591}\x{7594}\x{759A}\x{759D}\x{75A3}\x{75A5}\x{75AB}' . +'\x{75B1}\x{75B2}\x{75B3}\x{75B5}\x{75B8}\x{75B9}\x{75BC}\x{75BD}\x{75BE}' . +'\x{75C2}\x{75C3}\x{75C5}\x{75C7}\x{75CA}\x{75CD}\x{75D2}\x{75D4}\x{75D5}' . +'\x{75D8}\x{75D9}\x{75DB}\x{75DE}\x{75E2}\x{75E3}\x{75E9}\x{75F0}\x{75F2}' . +'\x{75F3}\x{75F4}\x{75FA}\x{75FC}\x{75FE}\x{75FF}\x{7601}\x{7609}\x{760B}' . +'\x{760D}\x{761F}\x{7620}\x{7621}\x{7622}\x{7624}\x{7627}\x{7630}\x{7634}' . +'\x{763B}\x{7642}\x{7646}\x{7647}\x{7648}\x{764C}\x{7652}\x{7656}\x{7658}' . +'\x{765C}\x{7661}\x{7662}\x{7667}\x{7668}\x{7669}\x{766A}\x{766C}\x{7670}' . +'\x{7672}\x{7676}\x{7678}\x{767A}\x{767B}\x{767C}\x{767D}\x{767E}\x{7680}' . +'\x{7683}\x{7684}\x{7686}\x{7687}\x{7688}\x{768B}\x{768E}\x{7690}\x{7693}' . +'\x{7696}\x{7699}\x{769A}\x{76AE}\x{76B0}\x{76B4}\x{76B7}\x{76B8}\x{76B9}' . +'\x{76BA}\x{76BF}\x{76C2}\x{76C3}\x{76C6}\x{76C8}\x{76CA}\x{76CD}\x{76D2}' . +'\x{76D6}\x{76D7}\x{76DB}\x{76DC}\x{76DE}\x{76DF}\x{76E1}\x{76E3}\x{76E4}' . +'\x{76E5}\x{76E7}\x{76EA}\x{76EE}\x{76F2}\x{76F4}\x{76F8}\x{76FB}\x{76FE}' . +'\x{7701}\x{7704}\x{7707}\x{7708}\x{7709}\x{770B}\x{770C}\x{771B}\x{771E}' . +'\x{771F}\x{7720}\x{7724}\x{7725}\x{7726}\x{7729}\x{7737}\x{7738}\x{773A}' . +'\x{773C}\x{7740}\x{7747}\x{775A}\x{775B}\x{7761}\x{7763}\x{7765}\x{7766}' . +'\x{7768}\x{776B}\x{7779}\x{777E}\x{777F}\x{778B}\x{778E}\x{7791}\x{779E}' . +'\x{77A0}\x{77A5}\x{77AC}\x{77AD}\x{77B0}\x{77B3}\x{77B6}\x{77B9}\x{77BB}' . +'\x{77BC}\x{77BD}\x{77BF}\x{77C7}\x{77CD}\x{77D7}\x{77DA}\x{77DB}\x{77DC}' . +'\x{77E2}\x{77E3}\x{77E5}\x{77E7}\x{77E9}\x{77ED}\x{77EE}\x{77EF}\x{77F3}' . +'\x{77FC}\x{7802}\x{780C}\x{7812}\x{7814}\x{7815}\x{7820}\x{7825}\x{7826}' . +'\x{7827}\x{7832}\x{7834}\x{783A}\x{783F}\x{7845}\x{785D}\x{786B}\x{786C}' . +'\x{786F}\x{7872}\x{7874}\x{787C}\x{7881}\x{7886}\x{7887}\x{788C}\x{788D}' . +'\x{788E}\x{7891}\x{7893}\x{7895}\x{7897}\x{789A}\x{78A3}\x{78A7}\x{78A9}' . +'\x{78AA}\x{78AF}\x{78B5}\x{78BA}\x{78BC}\x{78BE}\x{78C1}\x{78C5}\x{78C6}' . +'\x{78CA}\x{78CB}\x{78D0}\x{78D1}\x{78D4}\x{78DA}\x{78E7}\x{78E8}\x{78EC}' . +'\x{78EF}\x{78F4}\x{78FD}\x{7901}\x{7907}\x{790E}\x{7911}\x{7912}\x{7919}' . +'\x{7926}\x{792A}\x{792B}\x{792C}\x{793A}\x{793C}\x{793E}\x{7940}\x{7941}' . +'\x{7947}\x{7948}\x{7949}\x{7950}\x{7953}\x{7955}\x{7956}\x{7957}\x{795A}' . +'\x{795D}\x{795E}\x{795F}\x{7960}\x{7962}\x{7965}\x{7968}\x{796D}\x{7977}' . +'\x{797A}\x{797F}\x{7980}\x{7981}\x{7984}\x{7985}\x{798A}\x{798D}\x{798E}' . +'\x{798F}\x{799D}\x{79A6}\x{79A7}\x{79AA}\x{79AE}\x{79B0}\x{79B3}\x{79B9}' . +'\x{79BA}\x{79BD}\x{79BE}\x{79BF}\x{79C0}\x{79C1}\x{79C9}\x{79CB}\x{79D1}' . +'\x{79D2}\x{79D5}\x{79D8}\x{79DF}\x{79E1}\x{79E3}\x{79E4}\x{79E6}\x{79E7}' . +'\x{79E9}\x{79EC}\x{79F0}\x{79FB}\x{7A00}\x{7A08}\x{7A0B}\x{7A0D}\x{7A0E}' . +'\x{7A14}\x{7A17}\x{7A18}\x{7A19}\x{7A1A}\x{7A1C}\x{7A1F}\x{7A20}\x{7A2E}' . +'\x{7A31}\x{7A32}\x{7A37}\x{7A3B}\x{7A3C}\x{7A3D}\x{7A3E}\x{7A3F}\x{7A40}' . +'\x{7A42}\x{7A43}\x{7A46}\x{7A49}\x{7A4D}\x{7A4E}\x{7A4F}\x{7A50}\x{7A57}' . +'\x{7A61}\x{7A62}\x{7A63}\x{7A69}\x{7A6B}\x{7A70}\x{7A74}\x{7A76}\x{7A79}' . +'\x{7A7A}\x{7A7D}\x{7A7F}\x{7A81}\x{7A83}\x{7A84}\x{7A88}\x{7A92}\x{7A93}' . +'\x{7A95}\x{7A96}\x{7A97}\x{7A98}\x{7A9F}\x{7AA9}\x{7AAA}\x{7AAE}\x{7AAF}' . +'\x{7AB0}\x{7AB6}\x{7ABA}\x{7ABF}\x{7AC3}\x{7AC4}\x{7AC5}\x{7AC7}\x{7AC8}' . +'\x{7ACA}\x{7ACB}\x{7ACD}\x{7ACF}\x{7AD2}\x{7AD3}\x{7AD5}\x{7AD9}\x{7ADA}' . +'\x{7ADC}\x{7ADD}\x{7ADF}\x{7AE0}\x{7AE1}\x{7AE2}\x{7AE3}\x{7AE5}\x{7AE6}' . +'\x{7AEA}\x{7AED}\x{7AEF}\x{7AF0}\x{7AF6}\x{7AF8}\x{7AF9}\x{7AFA}\x{7AFF}' . +'\x{7B02}\x{7B04}\x{7B06}\x{7B08}\x{7B0A}\x{7B0B}\x{7B0F}\x{7B11}\x{7B18}' . +'\x{7B19}\x{7B1B}\x{7B1E}\x{7B20}\x{7B25}\x{7B26}\x{7B28}\x{7B2C}\x{7B33}' . +'\x{7B35}\x{7B36}\x{7B39}\x{7B45}\x{7B46}\x{7B48}\x{7B49}\x{7B4B}\x{7B4C}' . +'\x{7B4D}\x{7B4F}\x{7B50}\x{7B51}\x{7B52}\x{7B54}\x{7B56}\x{7B5D}\x{7B65}' . +'\x{7B67}\x{7B6C}\x{7B6E}\x{7B70}\x{7B71}\x{7B74}\x{7B75}\x{7B7A}\x{7B86}' . +'\x{7B87}\x{7B8B}\x{7B8D}\x{7B8F}\x{7B92}\x{7B94}\x{7B95}\x{7B97}\x{7B98}' . +'\x{7B99}\x{7B9A}\x{7B9C}\x{7B9D}\x{7B9F}\x{7BA1}\x{7BAA}\x{7BAD}\x{7BB1}' . +'\x{7BB4}\x{7BB8}\x{7BC0}\x{7BC1}\x{7BC4}\x{7BC6}\x{7BC7}\x{7BC9}\x{7BCB}' . +'\x{7BCC}\x{7BCF}\x{7BDD}\x{7BE0}\x{7BE4}\x{7BE5}\x{7BE6}\x{7BE9}\x{7BED}' . +'\x{7BF3}\x{7BF6}\x{7BF7}\x{7C00}\x{7C07}\x{7C0D}\x{7C11}\x{7C12}\x{7C13}' . +'\x{7C14}\x{7C17}\x{7C1F}\x{7C21}\x{7C23}\x{7C27}\x{7C2A}\x{7C2B}\x{7C37}' . +'\x{7C38}\x{7C3D}\x{7C3E}\x{7C3F}\x{7C40}\x{7C43}\x{7C4C}\x{7C4D}\x{7C4F}' . +'\x{7C50}\x{7C54}\x{7C56}\x{7C58}\x{7C5F}\x{7C60}\x{7C64}\x{7C65}\x{7C6C}' . +'\x{7C73}\x{7C75}\x{7C7E}\x{7C81}\x{7C82}\x{7C83}\x{7C89}\x{7C8B}\x{7C8D}' . +'\x{7C90}\x{7C92}\x{7C95}\x{7C97}\x{7C98}\x{7C9B}\x{7C9F}\x{7CA1}\x{7CA2}' . +'\x{7CA4}\x{7CA5}\x{7CA7}\x{7CA8}\x{7CAB}\x{7CAD}\x{7CAE}\x{7CB1}\x{7CB2}' . +'\x{7CB3}\x{7CB9}\x{7CBD}\x{7CBE}\x{7CC0}\x{7CC2}\x{7CC5}\x{7CCA}\x{7CCE}' . +'\x{7CD2}\x{7CD6}\x{7CD8}\x{7CDC}\x{7CDE}\x{7CDF}\x{7CE0}\x{7CE2}\x{7CE7}' . +'\x{7CEF}\x{7CF2}\x{7CF4}\x{7CF6}\x{7CF8}\x{7CFA}\x{7CFB}\x{7CFE}\x{7D00}' . +'\x{7D02}\x{7D04}\x{7D05}\x{7D06}\x{7D0A}\x{7D0B}\x{7D0D}\x{7D10}\x{7D14}' . +'\x{7D15}\x{7D17}\x{7D18}\x{7D19}\x{7D1A}\x{7D1B}\x{7D1C}\x{7D20}\x{7D21}' . +'\x{7D22}\x{7D2B}\x{7D2C}\x{7D2E}\x{7D2F}\x{7D30}\x{7D32}\x{7D33}\x{7D35}' . +'\x{7D39}\x{7D3A}\x{7D3F}\x{7D42}\x{7D43}\x{7D44}\x{7D45}\x{7D46}\x{7D4B}' . +'\x{7D4C}\x{7D4E}\x{7D4F}\x{7D50}\x{7D56}\x{7D5B}\x{7D5E}\x{7D61}\x{7D62}' . +'\x{7D63}\x{7D66}\x{7D68}\x{7D6E}\x{7D71}\x{7D72}\x{7D73}\x{7D75}\x{7D76}' . +'\x{7D79}\x{7D7D}\x{7D89}\x{7D8F}\x{7D93}\x{7D99}\x{7D9A}\x{7D9B}\x{7D9C}' . +'\x{7D9F}\x{7DA2}\x{7DA3}\x{7DAB}\x{7DAC}\x{7DAD}\x{7DAE}\x{7DAF}\x{7DB0}' . +'\x{7DB1}\x{7DB2}\x{7DB4}\x{7DB5}\x{7DB8}\x{7DBA}\x{7DBB}\x{7DBD}\x{7DBE}' . +'\x{7DBF}\x{7DC7}\x{7DCA}\x{7DCB}\x{7DCF}\x{7DD1}\x{7DD2}\x{7DD5}\x{7DD8}' . +'\x{7DDA}\x{7DDC}\x{7DDD}\x{7DDE}\x{7DE0}\x{7DE1}\x{7DE4}\x{7DE8}\x{7DE9}' . +'\x{7DEC}\x{7DEF}\x{7DF2}\x{7DF4}\x{7DFB}\x{7E01}\x{7E04}\x{7E05}\x{7E09}' . +'\x{7E0A}\x{7E0B}\x{7E12}\x{7E1B}\x{7E1E}\x{7E1F}\x{7E21}\x{7E22}\x{7E23}' . +'\x{7E26}\x{7E2B}\x{7E2E}\x{7E31}\x{7E32}\x{7E35}\x{7E37}\x{7E39}\x{7E3A}' . +'\x{7E3B}\x{7E3D}\x{7E3E}\x{7E41}\x{7E43}\x{7E46}\x{7E4A}\x{7E4B}\x{7E4D}' . +'\x{7E54}\x{7E55}\x{7E56}\x{7E59}\x{7E5A}\x{7E5D}\x{7E5E}\x{7E66}\x{7E67}' . +'\x{7E69}\x{7E6A}\x{7E6D}\x{7E70}\x{7E79}\x{7E7B}\x{7E7C}\x{7E7D}\x{7E7F}' . +'\x{7E82}\x{7E83}\x{7E88}\x{7E89}\x{7E8C}\x{7E8E}\x{7E8F}\x{7E90}\x{7E92}' . +'\x{7E93}\x{7E94}\x{7E96}\x{7E9B}\x{7E9C}\x{7F36}\x{7F38}\x{7F3A}\x{7F45}' . +'\x{7F4C}\x{7F4D}\x{7F4E}\x{7F50}\x{7F51}\x{7F54}\x{7F55}\x{7F58}\x{7F5F}' . +'\x{7F60}\x{7F67}\x{7F68}\x{7F69}\x{7F6A}\x{7F6B}\x{7F6E}\x{7F70}\x{7F72}' . +'\x{7F75}\x{7F77}\x{7F78}\x{7F79}\x{7F82}\x{7F83}\x{7F85}\x{7F86}\x{7F87}' . +'\x{7F88}\x{7F8A}\x{7F8C}\x{7F8E}\x{7F94}\x{7F9A}\x{7F9D}\x{7F9E}\x{7FA3}' . +'\x{7FA4}\x{7FA8}\x{7FA9}\x{7FAE}\x{7FAF}\x{7FB2}\x{7FB6}\x{7FB8}\x{7FB9}' . +'\x{7FBD}\x{7FC1}\x{7FC5}\x{7FC6}\x{7FCA}\x{7FCC}\x{7FD2}\x{7FD4}\x{7FD5}' . +'\x{7FE0}\x{7FE1}\x{7FE6}\x{7FE9}\x{7FEB}\x{7FF0}\x{7FF3}\x{7FF9}\x{7FFB}' . +'\x{7FFC}\x{8000}\x{8001}\x{8003}\x{8004}\x{8005}\x{8006}\x{800B}\x{800C}' . +'\x{8010}\x{8012}\x{8015}\x{8017}\x{8018}\x{8019}\x{801C}\x{8021}\x{8028}' . +'\x{8033}\x{8036}\x{803B}\x{803D}\x{803F}\x{8046}\x{804A}\x{8052}\x{8056}' . +'\x{8058}\x{805A}\x{805E}\x{805F}\x{8061}\x{8062}\x{8068}\x{806F}\x{8070}' . +'\x{8072}\x{8073}\x{8074}\x{8076}\x{8077}\x{8079}\x{807D}\x{807E}\x{807F}' . +'\x{8084}\x{8085}\x{8086}\x{8087}\x{8089}\x{808B}\x{808C}\x{8093}\x{8096}' . +'\x{8098}\x{809A}\x{809B}\x{809D}\x{80A1}\x{80A2}\x{80A5}\x{80A9}\x{80AA}' . +'\x{80AC}\x{80AD}\x{80AF}\x{80B1}\x{80B2}\x{80B4}\x{80BA}\x{80C3}\x{80C4}' . +'\x{80C6}\x{80CC}\x{80CE}\x{80D6}\x{80D9}\x{80DA}\x{80DB}\x{80DD}\x{80DE}' . +'\x{80E1}\x{80E4}\x{80E5}\x{80EF}\x{80F1}\x{80F4}\x{80F8}\x{80FC}\x{80FD}' . +'\x{8102}\x{8105}\x{8106}\x{8107}\x{8108}\x{8109}\x{810A}\x{811A}\x{811B}' . +'\x{8123}\x{8129}\x{812F}\x{8131}\x{8133}\x{8139}\x{813E}\x{8146}\x{814B}' . +'\x{814E}\x{8150}\x{8151}\x{8153}\x{8154}\x{8155}\x{815F}\x{8165}\x{8166}' . +'\x{816B}\x{816E}\x{8170}\x{8171}\x{8174}\x{8178}\x{8179}\x{817A}\x{817F}' . +'\x{8180}\x{8182}\x{8183}\x{8188}\x{818A}\x{818F}\x{8193}\x{8195}\x{819A}' . +'\x{819C}\x{819D}\x{81A0}\x{81A3}\x{81A4}\x{81A8}\x{81A9}\x{81B0}\x{81B3}' . +'\x{81B5}\x{81B8}\x{81BA}\x{81BD}\x{81BE}\x{81BF}\x{81C0}\x{81C2}\x{81C6}' . +'\x{81C8}\x{81C9}\x{81CD}\x{81D1}\x{81D3}\x{81D8}\x{81D9}\x{81DA}\x{81DF}' . +'\x{81E0}\x{81E3}\x{81E5}\x{81E7}\x{81E8}\x{81EA}\x{81ED}\x{81F3}\x{81F4}' . +'\x{81FA}\x{81FB}\x{81FC}\x{81FE}\x{8201}\x{8202}\x{8205}\x{8207}\x{8208}' . +'\x{8209}\x{820A}\x{820C}\x{820D}\x{820E}\x{8210}\x{8212}\x{8216}\x{8217}' . +'\x{8218}\x{821B}\x{821C}\x{821E}\x{821F}\x{8229}\x{822A}\x{822B}\x{822C}' . +'\x{822E}\x{8233}\x{8235}\x{8236}\x{8237}\x{8238}\x{8239}\x{8240}\x{8247}' . +'\x{8258}\x{8259}\x{825A}\x{825D}\x{825F}\x{8262}\x{8264}\x{8266}\x{8268}' . +'\x{826A}\x{826B}\x{826E}\x{826F}\x{8271}\x{8272}\x{8276}\x{8277}\x{8278}' . +'\x{827E}\x{828B}\x{828D}\x{8292}\x{8299}\x{829D}\x{829F}\x{82A5}\x{82A6}' . +'\x{82AB}\x{82AC}\x{82AD}\x{82AF}\x{82B1}\x{82B3}\x{82B8}\x{82B9}\x{82BB}' . +'\x{82BD}\x{82C5}\x{82D1}\x{82D2}\x{82D3}\x{82D4}\x{82D7}\x{82D9}\x{82DB}' . +'\x{82DC}\x{82DE}\x{82DF}\x{82E1}\x{82E3}\x{82E5}\x{82E6}\x{82E7}\x{82EB}' . +'\x{82F1}\x{82F3}\x{82F4}\x{82F9}\x{82FA}\x{82FB}\x{8302}\x{8303}\x{8304}' . +'\x{8305}\x{8306}\x{8309}\x{830E}\x{8316}\x{8317}\x{8318}\x{831C}\x{8323}' . +'\x{8328}\x{832B}\x{832F}\x{8331}\x{8332}\x{8334}\x{8335}\x{8336}\x{8338}' . +'\x{8339}\x{8340}\x{8345}\x{8349}\x{834A}\x{834F}\x{8350}\x{8352}\x{8358}' . +'\x{8373}\x{8375}\x{8377}\x{837B}\x{837C}\x{8385}\x{8387}\x{8389}\x{838A}' . +'\x{838E}\x{8393}\x{8396}\x{839A}\x{839E}\x{839F}\x{83A0}\x{83A2}\x{83A8}' . +'\x{83AA}\x{83AB}\x{83B1}\x{83B5}\x{83BD}\x{83C1}\x{83C5}\x{83CA}\x{83CC}' . +'\x{83CE}\x{83D3}\x{83D6}\x{83D8}\x{83DC}\x{83DF}\x{83E0}\x{83E9}\x{83EB}' . +'\x{83EF}\x{83F0}\x{83F1}\x{83F2}\x{83F4}\x{83F7}\x{83FB}\x{83FD}\x{8403}' . +'\x{8404}\x{8407}\x{840B}\x{840C}\x{840D}\x{840E}\x{8413}\x{8420}\x{8422}' . +'\x{8429}\x{842A}\x{842C}\x{8431}\x{8435}\x{8438}\x{843C}\x{843D}\x{8446}' . +'\x{8449}\x{844E}\x{8457}\x{845B}\x{8461}\x{8462}\x{8463}\x{8466}\x{8469}' . +'\x{846B}\x{846C}\x{846D}\x{846E}\x{846F}\x{8471}\x{8475}\x{8477}\x{8479}' . +'\x{847A}\x{8482}\x{8484}\x{848B}\x{8490}\x{8494}\x{8499}\x{849C}\x{849F}' . +'\x{84A1}\x{84AD}\x{84B2}\x{84B8}\x{84B9}\x{84BB}\x{84BC}\x{84BF}\x{84C1}' . +'\x{84C4}\x{84C6}\x{84C9}\x{84CA}\x{84CB}\x{84CD}\x{84D0}\x{84D1}\x{84D6}' . +'\x{84D9}\x{84DA}\x{84EC}\x{84EE}\x{84F4}\x{84FC}\x{84FF}\x{8500}\x{8506}' . +'\x{8511}\x{8513}\x{8514}\x{8515}\x{8517}\x{8518}\x{851A}\x{851F}\x{8521}' . +'\x{8526}\x{852C}\x{852D}\x{8535}\x{853D}\x{8540}\x{8541}\x{8543}\x{8548}' . +'\x{8549}\x{854A}\x{854B}\x{854E}\x{8555}\x{8557}\x{8558}\x{855A}\x{8563}' . +'\x{8568}\x{8569}\x{856A}\x{856D}\x{8577}\x{857E}\x{8580}\x{8584}\x{8587}' . +'\x{8588}\x{858A}\x{8590}\x{8591}\x{8594}\x{8597}\x{8599}\x{859B}\x{859C}' . +'\x{85A4}\x{85A6}\x{85A8}\x{85A9}\x{85AA}\x{85AB}\x{85AC}\x{85AE}\x{85AF}' . +'\x{85B9}\x{85BA}\x{85C1}\x{85C9}\x{85CD}\x{85CF}\x{85D0}\x{85D5}\x{85DC}' . +'\x{85DD}\x{85E4}\x{85E5}\x{85E9}\x{85EA}\x{85F7}\x{85F9}\x{85FA}\x{85FB}' . +'\x{85FE}\x{8602}\x{8606}\x{8607}\x{860A}\x{860B}\x{8613}\x{8616}\x{8617}' . +'\x{861A}\x{8622}\x{862D}\x{862F}\x{8630}\x{863F}\x{864D}\x{864E}\x{8650}' . +'\x{8654}\x{8655}\x{865A}\x{865C}\x{865E}\x{865F}\x{8667}\x{866B}\x{8671}' . +'\x{8679}\x{867B}\x{868A}\x{868B}\x{868C}\x{8693}\x{8695}\x{86A3}\x{86A4}' . +'\x{86A9}\x{86AA}\x{86AB}\x{86AF}\x{86B0}\x{86B6}\x{86C4}\x{86C6}\x{86C7}' . +'\x{86C9}\x{86CB}\x{86CD}\x{86CE}\x{86D4}\x{86D9}\x{86DB}\x{86DE}\x{86DF}' . +'\x{86E4}\x{86E9}\x{86EC}\x{86ED}\x{86EE}\x{86EF}\x{86F8}\x{86F9}\x{86FB}' . +'\x{86FE}\x{8700}\x{8702}\x{8703}\x{8706}\x{8708}\x{8709}\x{870A}\x{870D}' . +'\x{8711}\x{8712}\x{8718}\x{871A}\x{871C}\x{8725}\x{8729}\x{8734}\x{8737}' . +'\x{873B}\x{873F}\x{8749}\x{874B}\x{874C}\x{874E}\x{8753}\x{8755}\x{8757}' . +'\x{8759}\x{875F}\x{8760}\x{8763}\x{8766}\x{8768}\x{876A}\x{876E}\x{8774}' . +'\x{8776}\x{8778}\x{877F}\x{8782}\x{878D}\x{879F}\x{87A2}\x{87AB}\x{87AF}' . +'\x{87B3}\x{87BA}\x{87BB}\x{87BD}\x{87C0}\x{87C4}\x{87C6}\x{87C7}\x{87CB}' . +'\x{87D0}\x{87D2}\x{87E0}\x{87EF}\x{87F2}\x{87F6}\x{87F7}\x{87F9}\x{87FB}' . +'\x{87FE}\x{8805}\x{880D}\x{880E}\x{880F}\x{8811}\x{8815}\x{8816}\x{8821}' . +'\x{8822}\x{8823}\x{8827}\x{8831}\x{8836}\x{8839}\x{883B}\x{8840}\x{8842}' . +'\x{8844}\x{8846}\x{884C}\x{884D}\x{8852}\x{8853}\x{8857}\x{8859}\x{885B}' . +'\x{885D}\x{885E}\x{8861}\x{8862}\x{8863}\x{8868}\x{886B}\x{8870}\x{8872}' . +'\x{8875}\x{8877}\x{887D}\x{887E}\x{887F}\x{8881}\x{8882}\x{8888}\x{888B}' . +'\x{888D}\x{8892}\x{8896}\x{8897}\x{8899}\x{889E}\x{88A2}\x{88A4}\x{88AB}' . +'\x{88AE}\x{88B0}\x{88B1}\x{88B4}\x{88B5}\x{88B7}\x{88BF}\x{88C1}\x{88C2}' . +'\x{88C3}\x{88C4}\x{88C5}\x{88CF}\x{88D4}\x{88D5}\x{88D8}\x{88D9}\x{88DC}' . +'\x{88DD}\x{88DF}\x{88E1}\x{88E8}\x{88F2}\x{88F3}\x{88F4}\x{88F8}\x{88F9}' . +'\x{88FC}\x{88FD}\x{88FE}\x{8902}\x{8904}\x{8907}\x{890A}\x{890C}\x{8910}' . +'\x{8912}\x{8913}\x{891D}\x{891E}\x{8925}\x{892A}\x{892B}\x{8936}\x{8938}' . +'\x{893B}\x{8941}\x{8943}\x{8944}\x{894C}\x{894D}\x{8956}\x{895E}\x{895F}' . +'\x{8960}\x{8964}\x{8966}\x{896A}\x{896D}\x{896F}\x{8972}\x{8974}\x{8977}' . +'\x{897E}\x{897F}\x{8981}\x{8983}\x{8986}\x{8987}\x{8988}\x{898A}\x{898B}' . +'\x{898F}\x{8993}\x{8996}\x{8997}\x{8998}\x{899A}\x{89A1}\x{89A6}\x{89A7}' . +'\x{89A9}\x{89AA}\x{89AC}\x{89AF}\x{89B2}\x{89B3}\x{89BA}\x{89BD}\x{89BF}' . +'\x{89C0}\x{89D2}\x{89DA}\x{89DC}\x{89DD}\x{89E3}\x{89E6}\x{89E7}\x{89F4}' . +'\x{89F8}\x{8A00}\x{8A02}\x{8A03}\x{8A08}\x{8A0A}\x{8A0C}\x{8A0E}\x{8A10}' . +'\x{8A13}\x{8A16}\x{8A17}\x{8A18}\x{8A1B}\x{8A1D}\x{8A1F}\x{8A23}\x{8A25}' . +'\x{8A2A}\x{8A2D}\x{8A31}\x{8A33}\x{8A34}\x{8A36}\x{8A3A}\x{8A3B}\x{8A3C}' . +'\x{8A41}\x{8A46}\x{8A48}\x{8A50}\x{8A51}\x{8A52}\x{8A54}\x{8A55}\x{8A5B}' . +'\x{8A5E}\x{8A60}\x{8A62}\x{8A63}\x{8A66}\x{8A69}\x{8A6B}\x{8A6C}\x{8A6D}' . +'\x{8A6E}\x{8A70}\x{8A71}\x{8A72}\x{8A73}\x{8A7C}\x{8A82}\x{8A84}\x{8A85}' . +'\x{8A87}\x{8A89}\x{8A8C}\x{8A8D}\x{8A91}\x{8A93}\x{8A95}\x{8A98}\x{8A9A}' . +'\x{8A9E}\x{8AA0}\x{8AA1}\x{8AA3}\x{8AA4}\x{8AA5}\x{8AA6}\x{8AA8}\x{8AAC}' . +'\x{8AAD}\x{8AB0}\x{8AB2}\x{8AB9}\x{8ABC}\x{8ABF}\x{8AC2}\x{8AC4}\x{8AC7}' . +'\x{8ACB}\x{8ACC}\x{8ACD}\x{8ACF}\x{8AD2}\x{8AD6}\x{8ADA}\x{8ADB}\x{8ADC}' . +'\x{8ADE}\x{8AE0}\x{8AE1}\x{8AE2}\x{8AE4}\x{8AE6}\x{8AE7}\x{8AEB}\x{8AED}' . +'\x{8AEE}\x{8AF1}\x{8AF3}\x{8AF7}\x{8AF8}\x{8AFA}\x{8AFE}\x{8B00}\x{8B01}' . +'\x{8B02}\x{8B04}\x{8B07}\x{8B0C}\x{8B0E}\x{8B10}\x{8B14}\x{8B16}\x{8B17}' . +'\x{8B19}\x{8B1A}\x{8B1B}\x{8B1D}\x{8B20}\x{8B21}\x{8B26}\x{8B28}\x{8B2B}' . +'\x{8B2C}\x{8B33}\x{8B39}\x{8B3E}\x{8B41}\x{8B49}\x{8B4C}\x{8B4E}\x{8B4F}' . +'\x{8B56}\x{8B58}\x{8B5A}\x{8B5B}\x{8B5C}\x{8B5F}\x{8B66}\x{8B6B}\x{8B6C}' . +'\x{8B6F}\x{8B70}\x{8B71}\x{8B72}\x{8B74}\x{8B77}\x{8B7D}\x{8B80}\x{8B83}' . +'\x{8B8A}\x{8B8C}\x{8B8E}\x{8B90}\x{8B92}\x{8B93}\x{8B96}\x{8B99}\x{8B9A}' . +'\x{8C37}\x{8C3A}\x{8C3F}\x{8C41}\x{8C46}\x{8C48}\x{8C4A}\x{8C4C}\x{8C4E}' . +'\x{8C50}\x{8C55}\x{8C5A}\x{8C61}\x{8C62}\x{8C6A}\x{8C6B}\x{8C6C}\x{8C78}' . +'\x{8C79}\x{8C7A}\x{8C7C}\x{8C82}\x{8C85}\x{8C89}\x{8C8A}\x{8C8C}\x{8C8D}' . +'\x{8C8E}\x{8C94}\x{8C98}\x{8C9D}\x{8C9E}\x{8CA0}\x{8CA1}\x{8CA2}\x{8CA7}' . +'\x{8CA8}\x{8CA9}\x{8CAA}\x{8CAB}\x{8CAC}\x{8CAD}\x{8CAE}\x{8CAF}\x{8CB0}' . +'\x{8CB2}\x{8CB3}\x{8CB4}\x{8CB6}\x{8CB7}\x{8CB8}\x{8CBB}\x{8CBC}\x{8CBD}' . +'\x{8CBF}\x{8CC0}\x{8CC1}\x{8CC2}\x{8CC3}\x{8CC4}\x{8CC7}\x{8CC8}\x{8CCA}' . +'\x{8CCD}\x{8CCE}\x{8CD1}\x{8CD3}\x{8CDA}\x{8CDB}\x{8CDC}\x{8CDE}\x{8CE0}' . +'\x{8CE2}\x{8CE3}\x{8CE4}\x{8CE6}\x{8CEA}\x{8CED}\x{8CFA}\x{8CFB}\x{8CFC}' . +'\x{8CFD}\x{8D04}\x{8D05}\x{8D07}\x{8D08}\x{8D0A}\x{8D0B}\x{8D0D}\x{8D0F}' . +'\x{8D10}\x{8D13}\x{8D14}\x{8D16}\x{8D64}\x{8D66}\x{8D67}\x{8D6B}\x{8D6D}' . +'\x{8D70}\x{8D71}\x{8D73}\x{8D74}\x{8D77}\x{8D81}\x{8D85}\x{8D8A}\x{8D99}' . +'\x{8DA3}\x{8DA8}\x{8DB3}\x{8DBA}\x{8DBE}\x{8DC2}\x{8DCB}\x{8DCC}\x{8DCF}' . +'\x{8DD6}\x{8DDA}\x{8DDB}\x{8DDD}\x{8DDF}\x{8DE1}\x{8DE3}\x{8DE8}\x{8DEA}' . +'\x{8DEB}\x{8DEF}\x{8DF3}\x{8DF5}\x{8DFC}\x{8DFF}\x{8E08}\x{8E09}\x{8E0A}' . +'\x{8E0F}\x{8E10}\x{8E1D}\x{8E1E}\x{8E1F}\x{8E2A}\x{8E30}\x{8E34}\x{8E35}' . +'\x{8E42}\x{8E44}\x{8E47}\x{8E48}\x{8E49}\x{8E4A}\x{8E4C}\x{8E50}\x{8E55}' . +'\x{8E59}\x{8E5F}\x{8E60}\x{8E63}\x{8E64}\x{8E72}\x{8E74}\x{8E76}\x{8E7C}' . +'\x{8E81}\x{8E84}\x{8E85}\x{8E87}\x{8E8A}\x{8E8B}\x{8E8D}\x{8E91}\x{8E93}' . +'\x{8E94}\x{8E99}\x{8EA1}\x{8EAA}\x{8EAB}\x{8EAC}\x{8EAF}\x{8EB0}\x{8EB1}' . +'\x{8EBE}\x{8EC5}\x{8EC6}\x{8EC8}\x{8ECA}\x{8ECB}\x{8ECC}\x{8ECD}\x{8ED2}' . +'\x{8EDB}\x{8EDF}\x{8EE2}\x{8EE3}\x{8EEB}\x{8EF8}\x{8EFB}\x{8EFC}\x{8EFD}' . +'\x{8EFE}\x{8F03}\x{8F05}\x{8F09}\x{8F0A}\x{8F0C}\x{8F12}\x{8F13}\x{8F14}' . +'\x{8F15}\x{8F19}\x{8F1B}\x{8F1C}\x{8F1D}\x{8F1F}\x{8F26}\x{8F29}\x{8F2A}' . +'\x{8F2F}\x{8F33}\x{8F38}\x{8F39}\x{8F3B}\x{8F3E}\x{8F3F}\x{8F42}\x{8F44}' . +'\x{8F45}\x{8F46}\x{8F49}\x{8F4C}\x{8F4D}\x{8F4E}\x{8F57}\x{8F5C}\x{8F5F}' . +'\x{8F61}\x{8F62}\x{8F63}\x{8F64}\x{8F9B}\x{8F9C}\x{8F9E}\x{8F9F}\x{8FA3}' . +'\x{8FA7}\x{8FA8}\x{8FAD}\x{8FAE}\x{8FAF}\x{8FB0}\x{8FB1}\x{8FB2}\x{8FB7}' . +'\x{8FBA}\x{8FBB}\x{8FBC}\x{8FBF}\x{8FC2}\x{8FC4}\x{8FC5}\x{8FCE}\x{8FD1}' . +'\x{8FD4}\x{8FDA}\x{8FE2}\x{8FE5}\x{8FE6}\x{8FE9}\x{8FEA}\x{8FEB}\x{8FED}' . +'\x{8FEF}\x{8FF0}\x{8FF4}\x{8FF7}\x{8FF8}\x{8FF9}\x{8FFA}\x{8FFD}\x{9000}' . +'\x{9001}\x{9003}\x{9005}\x{9006}\x{900B}\x{900D}\x{900E}\x{900F}\x{9010}' . +'\x{9011}\x{9013}\x{9014}\x{9015}\x{9016}\x{9017}\x{9019}\x{901A}\x{901D}' . +'\x{901E}\x{901F}\x{9020}\x{9021}\x{9022}\x{9023}\x{9027}\x{902E}\x{9031}' . +'\x{9032}\x{9035}\x{9036}\x{9038}\x{9039}\x{903C}\x{903E}\x{9041}\x{9042}' . +'\x{9045}\x{9047}\x{9049}\x{904A}\x{904B}\x{904D}\x{904E}\x{904F}\x{9050}' . +'\x{9051}\x{9052}\x{9053}\x{9054}\x{9055}\x{9056}\x{9058}\x{9059}\x{905C}' . +'\x{905E}\x{9060}\x{9061}\x{9063}\x{9065}\x{9068}\x{9069}\x{906D}\x{906E}' . +'\x{906F}\x{9072}\x{9075}\x{9076}\x{9077}\x{9078}\x{907A}\x{907C}\x{907D}' . +'\x{907F}\x{9080}\x{9081}\x{9082}\x{9083}\x{9084}\x{9087}\x{9089}\x{908A}' . +'\x{908F}\x{9091}\x{90A3}\x{90A6}\x{90A8}\x{90AA}\x{90AF}\x{90B1}\x{90B5}' . +'\x{90B8}\x{90C1}\x{90CA}\x{90CE}\x{90DB}\x{90E1}\x{90E2}\x{90E4}\x{90E8}' . +'\x{90ED}\x{90F5}\x{90F7}\x{90FD}\x{9102}\x{9112}\x{9119}\x{912D}\x{9130}' . +'\x{9132}\x{9149}\x{914A}\x{914B}\x{914C}\x{914D}\x{914E}\x{9152}\x{9154}' . +'\x{9156}\x{9158}\x{9162}\x{9163}\x{9165}\x{9169}\x{916A}\x{916C}\x{9172}' . +'\x{9173}\x{9175}\x{9177}\x{9178}\x{9182}\x{9187}\x{9189}\x{918B}\x{918D}' . +'\x{9190}\x{9192}\x{9197}\x{919C}\x{91A2}\x{91A4}\x{91AA}\x{91AB}\x{91AF}' . +'\x{91B4}\x{91B5}\x{91B8}\x{91BA}\x{91C0}\x{91C1}\x{91C6}\x{91C7}\x{91C8}' . +'\x{91C9}\x{91CB}\x{91CC}\x{91CD}\x{91CE}\x{91CF}\x{91D0}\x{91D1}\x{91D6}' . +'\x{91D8}\x{91DB}\x{91DC}\x{91DD}\x{91DF}\x{91E1}\x{91E3}\x{91E6}\x{91E7}' . +'\x{91F5}\x{91F6}\x{91FC}\x{91FF}\x{920D}\x{920E}\x{9211}\x{9214}\x{9215}' . +'\x{921E}\x{9229}\x{922C}\x{9234}\x{9237}\x{923F}\x{9244}\x{9245}\x{9248}' . +'\x{9249}\x{924B}\x{9250}\x{9257}\x{925A}\x{925B}\x{925E}\x{9262}\x{9264}' . +'\x{9266}\x{9271}\x{927E}\x{9280}\x{9283}\x{9285}\x{9291}\x{9293}\x{9295}' . +'\x{9296}\x{9298}\x{929A}\x{929B}\x{929C}\x{92AD}\x{92B7}\x{92B9}\x{92CF}' . +'\x{92D2}\x{92E4}\x{92E9}\x{92EA}\x{92ED}\x{92F2}\x{92F3}\x{92F8}\x{92FA}' . +'\x{92FC}\x{9306}\x{930F}\x{9310}\x{9318}\x{9319}\x{931A}\x{9320}\x{9322}' . +'\x{9323}\x{9326}\x{9328}\x{932B}\x{932C}\x{932E}\x{932F}\x{9332}\x{9335}' . +'\x{933A}\x{933B}\x{9344}\x{934B}\x{934D}\x{9354}\x{9356}\x{935B}\x{935C}' . +'\x{9360}\x{936C}\x{936E}\x{9375}\x{937C}\x{937E}\x{938C}\x{9394}\x{9396}' . +'\x{9397}\x{939A}\x{93A7}\x{93AC}\x{93AD}\x{93AE}\x{93B0}\x{93B9}\x{93C3}' . +'\x{93C8}\x{93D0}\x{93D1}\x{93D6}\x{93D7}\x{93D8}\x{93DD}\x{93E1}\x{93E4}' . +'\x{93E5}\x{93E8}\x{9403}\x{9407}\x{9410}\x{9413}\x{9414}\x{9418}\x{9419}' . +'\x{941A}\x{9421}\x{942B}\x{9435}\x{9436}\x{9438}\x{943A}\x{9441}\x{9444}' . +'\x{9451}\x{9452}\x{9453}\x{945A}\x{945B}\x{945E}\x{9460}\x{9462}\x{946A}' . +'\x{9470}\x{9475}\x{9477}\x{947C}\x{947D}\x{947E}\x{947F}\x{9481}\x{9577}' . +'\x{9580}\x{9582}\x{9583}\x{9587}\x{9589}\x{958A}\x{958B}\x{958F}\x{9591}' . +'\x{9593}\x{9594}\x{9596}\x{9598}\x{9599}\x{95A0}\x{95A2}\x{95A3}\x{95A4}' . +'\x{95A5}\x{95A7}\x{95A8}\x{95AD}\x{95B2}\x{95B9}\x{95BB}\x{95BC}\x{95BE}' . +'\x{95C3}\x{95C7}\x{95CA}\x{95CC}\x{95CD}\x{95D4}\x{95D5}\x{95D6}\x{95D8}' . +'\x{95DC}\x{95E1}\x{95E2}\x{95E5}\x{961C}\x{9621}\x{9628}\x{962A}\x{962E}' . +'\x{962F}\x{9632}\x{963B}\x{963F}\x{9640}\x{9642}\x{9644}\x{964B}\x{964C}' . +'\x{964D}\x{964F}\x{9650}\x{965B}\x{965C}\x{965D}\x{965E}\x{965F}\x{9662}' . +'\x{9663}\x{9664}\x{9665}\x{9666}\x{966A}\x{966C}\x{9670}\x{9672}\x{9673}' . +'\x{9675}\x{9676}\x{9677}\x{9678}\x{967A}\x{967D}\x{9685}\x{9686}\x{9688}' . +'\x{968A}\x{968B}\x{968D}\x{968E}\x{968F}\x{9694}\x{9695}\x{9697}\x{9698}' . +'\x{9699}\x{969B}\x{969C}\x{96A0}\x{96A3}\x{96A7}\x{96A8}\x{96AA}\x{96B0}' . +'\x{96B1}\x{96B2}\x{96B4}\x{96B6}\x{96B7}\x{96B8}\x{96B9}\x{96BB}\x{96BC}' . +'\x{96C0}\x{96C1}\x{96C4}\x{96C5}\x{96C6}\x{96C7}\x{96C9}\x{96CB}\x{96CC}' . +'\x{96CD}\x{96CE}\x{96D1}\x{96D5}\x{96D6}\x{96D9}\x{96DB}\x{96DC}\x{96E2}' . +'\x{96E3}\x{96E8}\x{96EA}\x{96EB}\x{96F0}\x{96F2}\x{96F6}\x{96F7}\x{96F9}' . +'\x{96FB}\x{9700}\x{9704}\x{9706}\x{9707}\x{9708}\x{970A}\x{970D}\x{970E}' . +'\x{970F}\x{9711}\x{9713}\x{9716}\x{9719}\x{971C}\x{971E}\x{9724}\x{9727}' . +'\x{972A}\x{9730}\x{9732}\x{9738}\x{9739}\x{973D}\x{973E}\x{9742}\x{9744}' . +'\x{9746}\x{9748}\x{9749}\x{9752}\x{9756}\x{9759}\x{975C}\x{975E}\x{9760}' . +'\x{9761}\x{9762}\x{9764}\x{9766}\x{9768}\x{9769}\x{976B}\x{976D}\x{9771}' . +'\x{9774}\x{9779}\x{977A}\x{977C}\x{9781}\x{9784}\x{9785}\x{9786}\x{978B}' . +'\x{978D}\x{978F}\x{9790}\x{9798}\x{979C}\x{97A0}\x{97A3}\x{97A6}\x{97A8}' . +'\x{97AB}\x{97AD}\x{97B3}\x{97B4}\x{97C3}\x{97C6}\x{97C8}\x{97CB}\x{97D3}' . +'\x{97DC}\x{97ED}\x{97EE}\x{97F2}\x{97F3}\x{97F5}\x{97F6}\x{97FB}\x{97FF}' . +'\x{9801}\x{9802}\x{9803}\x{9805}\x{9806}\x{9808}\x{980C}\x{980F}\x{9810}' . +'\x{9811}\x{9812}\x{9813}\x{9817}\x{9818}\x{981A}\x{9821}\x{9824}\x{982C}' . +'\x{982D}\x{9834}\x{9837}\x{9838}\x{983B}\x{983C}\x{983D}\x{9846}\x{984B}' . +'\x{984C}\x{984D}\x{984E}\x{984F}\x{9854}\x{9855}\x{9858}\x{985B}\x{985E}' . +'\x{9867}\x{986B}\x{986F}\x{9870}\x{9871}\x{9873}\x{9874}\x{98A8}\x{98AA}' . +'\x{98AF}\x{98B1}\x{98B6}\x{98C3}\x{98C4}\x{98C6}\x{98DB}\x{98DC}\x{98DF}' . +'\x{98E2}\x{98E9}\x{98EB}\x{98ED}\x{98EE}\x{98EF}\x{98F2}\x{98F4}\x{98FC}' . +'\x{98FD}\x{98FE}\x{9903}\x{9905}\x{9909}\x{990A}\x{990C}\x{9910}\x{9912}' . +'\x{9913}\x{9914}\x{9918}\x{991D}\x{991E}\x{9920}\x{9921}\x{9924}\x{9928}' . +'\x{992C}\x{992E}\x{993D}\x{993E}\x{9942}\x{9945}\x{9949}\x{994B}\x{994C}' . +'\x{9950}\x{9951}\x{9952}\x{9955}\x{9957}\x{9996}\x{9997}\x{9998}\x{9999}' . +'\x{99A5}\x{99A8}\x{99AC}\x{99AD}\x{99AE}\x{99B3}\x{99B4}\x{99BC}\x{99C1}' . +'\x{99C4}\x{99C5}\x{99C6}\x{99C8}\x{99D0}\x{99D1}\x{99D2}\x{99D5}\x{99D8}' . +'\x{99DB}\x{99DD}\x{99DF}\x{99E2}\x{99ED}\x{99EE}\x{99F1}\x{99F2}\x{99F8}' . +'\x{99FB}\x{99FF}\x{9A01}\x{9A05}\x{9A0E}\x{9A0F}\x{9A12}\x{9A13}\x{9A19}' . +'\x{9A28}\x{9A2B}\x{9A30}\x{9A37}\x{9A3E}\x{9A40}\x{9A42}\x{9A43}\x{9A45}' . +'\x{9A4D}\x{9A55}\x{9A57}\x{9A5A}\x{9A5B}\x{9A5F}\x{9A62}\x{9A64}\x{9A65}' . +'\x{9A69}\x{9A6A}\x{9A6B}\x{9AA8}\x{9AAD}\x{9AB0}\x{9AB8}\x{9ABC}\x{9AC0}' . +'\x{9AC4}\x{9ACF}\x{9AD1}\x{9AD3}\x{9AD4}\x{9AD8}\x{9ADE}\x{9ADF}\x{9AE2}' . +'\x{9AE3}\x{9AE6}\x{9AEA}\x{9AEB}\x{9AED}\x{9AEE}\x{9AEF}\x{9AF1}\x{9AF4}' . +'\x{9AF7}\x{9AFB}\x{9B06}\x{9B18}\x{9B1A}\x{9B1F}\x{9B22}\x{9B23}\x{9B25}' . +'\x{9B27}\x{9B28}\x{9B29}\x{9B2A}\x{9B2E}\x{9B2F}\x{9B31}\x{9B32}\x{9B3B}' . +'\x{9B3C}\x{9B41}\x{9B42}\x{9B43}\x{9B44}\x{9B45}\x{9B4D}\x{9B4E}\x{9B4F}' . +'\x{9B51}\x{9B54}\x{9B58}\x{9B5A}\x{9B6F}\x{9B74}\x{9B83}\x{9B8E}\x{9B91}' . +'\x{9B92}\x{9B93}\x{9B96}\x{9B97}\x{9B9F}\x{9BA0}\x{9BA8}\x{9BAA}\x{9BAB}' . +'\x{9BAD}\x{9BAE}\x{9BB4}\x{9BB9}\x{9BC0}\x{9BC6}\x{9BC9}\x{9BCA}\x{9BCF}' . +'\x{9BD1}\x{9BD2}\x{9BD4}\x{9BD6}\x{9BDB}\x{9BE1}\x{9BE2}\x{9BE3}\x{9BE4}' . +'\x{9BE8}\x{9BF0}\x{9BF1}\x{9BF2}\x{9BF5}\x{9C04}\x{9C06}\x{9C08}\x{9C09}' . +'\x{9C0A}\x{9C0C}\x{9C0D}\x{9C10}\x{9C12}\x{9C13}\x{9C14}\x{9C15}\x{9C1B}' . +'\x{9C21}\x{9C24}\x{9C25}\x{9C2D}\x{9C2E}\x{9C2F}\x{9C30}\x{9C32}\x{9C39}' . +'\x{9C3A}\x{9C3B}\x{9C3E}\x{9C46}\x{9C47}\x{9C48}\x{9C52}\x{9C57}\x{9C5A}' . +'\x{9C60}\x{9C67}\x{9C76}\x{9C78}\x{9CE5}\x{9CE7}\x{9CE9}\x{9CEB}\x{9CEC}' . +'\x{9CF0}\x{9CF3}\x{9CF4}\x{9CF6}\x{9D03}\x{9D06}\x{9D07}\x{9D08}\x{9D09}' . +'\x{9D0E}\x{9D12}\x{9D15}\x{9D1B}\x{9D1F}\x{9D23}\x{9D26}\x{9D28}\x{9D2A}' . +'\x{9D2B}\x{9D2C}\x{9D3B}\x{9D3E}\x{9D3F}\x{9D41}\x{9D44}\x{9D46}\x{9D48}' . +'\x{9D50}\x{9D51}\x{9D59}\x{9D5C}\x{9D5D}\x{9D5E}\x{9D60}\x{9D61}\x{9D64}' . +'\x{9D6C}\x{9D6F}\x{9D72}\x{9D7A}\x{9D87}\x{9D89}\x{9D8F}\x{9D9A}\x{9DA4}' . +'\x{9DA9}\x{9DAB}\x{9DAF}\x{9DB2}\x{9DB4}\x{9DB8}\x{9DBA}\x{9DBB}\x{9DC1}' . +'\x{9DC2}\x{9DC4}\x{9DC6}\x{9DCF}\x{9DD3}\x{9DD9}\x{9DE6}\x{9DED}\x{9DEF}' . +'\x{9DF2}\x{9DF8}\x{9DF9}\x{9DFA}\x{9DFD}\x{9E1A}\x{9E1B}\x{9E1E}\x{9E75}' . +'\x{9E78}\x{9E79}\x{9E7D}\x{9E7F}\x{9E81}\x{9E88}\x{9E8B}\x{9E8C}\x{9E91}' . +'\x{9E92}\x{9E93}\x{9E95}\x{9E97}\x{9E9D}\x{9E9F}\x{9EA5}\x{9EA6}\x{9EA9}' . +'\x{9EAA}\x{9EAD}\x{9EB8}\x{9EB9}\x{9EBA}\x{9EBB}\x{9EBC}\x{9EBE}\x{9EBF}' . +'\x{9EC4}\x{9ECC}\x{9ECD}\x{9ECE}\x{9ECF}\x{9ED0}\x{9ED2}\x{9ED4}\x{9ED8}' . +'\x{9ED9}\x{9EDB}\x{9EDC}\x{9EDD}\x{9EDE}\x{9EE0}\x{9EE5}\x{9EE8}\x{9EEF}' . +'\x{9EF4}\x{9EF6}\x{9EF7}\x{9EF9}\x{9EFB}\x{9EFC}\x{9EFD}\x{9F07}\x{9F08}' . +'\x{9F0E}\x{9F13}\x{9F15}\x{9F20}\x{9F21}\x{9F2C}\x{9F3B}\x{9F3E}\x{9F4A}' . +'\x{9F4B}\x{9F4E}\x{9F4F}\x{9F52}\x{9F54}\x{9F5F}\x{9F60}\x{9F61}\x{9F62}' . +'\x{9F63}\x{9F66}\x{9F67}\x{9F6A}\x{9F6C}\x{9F72}\x{9F76}\x{9F77}\x{9F8D}' . +'\x{9F95}\x{9F9C}\x{9F9D}\x{9FA0}]{1,15}$/iu'); diff --git a/Zend/Validate/Interface.php b/Zend/Validate/Interface.php new file mode 100644 index 00000000..986a7184 --- /dev/null +++ b/Zend/Validate/Interface.php @@ -0,0 +1,54 @@ + "Invalid type given, value should be a string", + self::NOT_IP_ADDRESS => "'%value%' does not appear to be a valid IP address", + ); + + /** + * internal options + * + * @var array + */ + protected $_options = array( + 'allowipv6' => true, + 'allowipv4' => true + ); + + /** + * Sets validator options + * + * @param array $options OPTIONAL Options to set, see the manual for all available options + * @return void + */ + public function __construct($options = array()) + { + if ($options instanceof Zend_Config) { + $options = $options->toArray(); + } else if (!is_array($options)) { + $options = func_get_args(); + $temp['allowipv6'] = array_shift($options); + if (!empty($options)) { + $temp['allowipv4'] = array_shift($options); + } + + $options = $temp; + } + + $options += $this->_options; + $this->setOptions($options); + } + + /** + * Returns all set options + * + * @return array + */ + public function getOptions() + { + return $this->_options; + } + + /** + * Sets the options for this validator + * + * @param array $options + * @return Zend_Validate_Ip + */ + public function setOptions($options) + { + if (array_key_exists('allowipv6', $options)) { + $this->_options['allowipv6'] = (boolean) $options['allowipv6']; + } + + if (array_key_exists('allowipv4', $options)) { + $this->_options['allowipv4'] = (boolean) $options['allowipv4']; + } + + if (!$this->_options['allowipv4'] && !$this->_options['allowipv6']) { + require_once 'Zend/Validate/Exception.php'; + throw new Zend_Validate_Exception('Nothing to validate. Check your options'); + } + + return $this; + } + + /** + * Defined by Zend_Validate_Interface + * + * Returns true if and only if $value is a valid IP address + * + * @param mixed $value + * @return boolean + */ + public function isValid($value) + { + if (!is_string($value)) { + $this->_error(self::INVALID); + return false; + } + + $this->_setValue($value); + if (($this->_options['allowipv4'] && !$this->_options['allowipv6'] && !$this->_validateIPv4($value)) || + (!$this->_options['allowipv4'] && $this->_options['allowipv6'] && !$this->_validateIPv6($value)) || + ($this->_options['allowipv4'] && $this->_options['allowipv6'] && !$this->_validateIPv4($value) && !$this->_validateIPv6($value))) { + $this->_error(self::NOT_IP_ADDRESS); + return false; + } + + return true; + } + + /** + * Validates an IPv4 address + * + * @param string $value + */ + protected function _validateIPv4($value) { + $ip2long = ip2long($value); + if($ip2long === false) { + return false; + } + + return $value == long2ip($ip2long); + } + + /** + * Validates an IPv6 address + * + * @param string $value Value to check against + * @return boolean True when $value is a valid ipv6 address + * False otherwise + */ + protected function _validateIPv6($value) { + if (strlen($value) < 3) { + return $value == '::'; + } + + if (strpos($value, '.')) { + $lastcolon = strrpos($value, ':'); + if (!($lastcolon && $this->_validateIPv4(substr($value, $lastcolon + 1)))) { + return false; + } + + $value = substr($value, 0, $lastcolon) . ':0:0'; + } + + if (strpos($value, '::') === false) { + return preg_match('/\A(?:[a-f0-9]{1,4}:){7}[a-f0-9]{1,4}\z/i', $value); + } + + $colonCount = substr_count($value, ':'); + if ($colonCount < 8) { + return preg_match('/\A(?::|(?:[a-f0-9]{1,4}:)+):(?:(?:[a-f0-9]{1,4}:)*[a-f0-9]{1,4})?\z/i', $value); + } + + // special case with ending or starting double colon + if ($colonCount == 8) { + return preg_match('/\A(?:::)?(?:[a-f0-9]{1,4}:){6}[a-f0-9]{1,4}(?:::)?\z/i', $value); + } + + return false; + } +} diff --git a/Zend/Version.php b/Zend/Version.php new file mode 100644 index 00000000..59ec6fbc --- /dev/null +++ b/Zend/Version.php @@ -0,0 +1,53 @@ + diff --git a/cache/csv/index.html b/cache/csv/index.html new file mode 100644 index 00000000..f9236827 --- /dev/null +++ b/cache/csv/index.html @@ -0,0 +1 @@ +This directory must be writable by the webserver user. \ No newline at end of file diff --git a/cache/feeds/index.html b/cache/feeds/index.html new file mode 100644 index 00000000..f9236827 --- /dev/null +++ b/cache/feeds/index.html @@ -0,0 +1 @@ +This directory must be writable by the webserver user. \ No newline at end of file diff --git a/cache/images/index.html b/cache/images/index.html new file mode 100644 index 00000000..f9236827 --- /dev/null +++ b/cache/images/index.html @@ -0,0 +1 @@ +This directory must be writable by the webserver user. \ No newline at end of file diff --git a/cache/import/index.html b/cache/import/index.html new file mode 100644 index 00000000..f9236827 --- /dev/null +++ b/cache/import/index.html @@ -0,0 +1 @@ +This directory must be writable by the webserver user. \ No newline at end of file diff --git a/cache/index.html b/cache/index.html new file mode 100644 index 00000000..cc72e8ac --- /dev/null +++ b/cache/index.html @@ -0,0 +1 @@ +This directory must be writable by the webserver user. diff --git a/cache/layout/index.html b/cache/layout/index.html new file mode 100644 index 00000000..f9236827 --- /dev/null +++ b/cache/layout/index.html @@ -0,0 +1 @@ +This directory must be writable by the webserver user. \ No newline at end of file diff --git a/cache/pdf/index.html b/cache/pdf/index.html new file mode 100644 index 00000000..f9236827 --- /dev/null +++ b/cache/pdf/index.html @@ -0,0 +1 @@ +This directory must be writable by the webserver user. \ No newline at end of file diff --git a/cache/upload/index.html b/cache/upload/index.html new file mode 100644 index 00000000..f9236827 --- /dev/null +++ b/cache/upload/index.html @@ -0,0 +1 @@ +This directory must be writable by the webserver user. \ No newline at end of file diff --git a/cache/xml/index.html b/cache/xml/index.html new file mode 100644 index 00000000..f9236827 --- /dev/null +++ b/cache/xml/index.html @@ -0,0 +1 @@ +This directory must be writable by the webserver user. \ No newline at end of file diff --git a/campaign_tracker.php b/campaign_tracker.php new file mode 100644 index 00000000..7009359b --- /dev/null +++ b/campaign_tracker.php @@ -0,0 +1,83 @@ +quote($track); + +if(preg_match('/^[0-9A-Za-z\-]*$/', $track)) +{ + $query = "SELECT refer_url FROM campaigns WHERE tracker_key='$track'"; + $res = $db->query($query); + + $row = $db->fetchByAssoc($res); + + $redirect_URL = $row['refer_url']; + sugar_cleanup(); + header("Location: $redirect_URL"); +} +else +{ + sugar_cleanup(); +} +exit; +?> diff --git a/campaign_trackerv2.php b/campaign_trackerv2.php new file mode 100644 index 00000000..0d9f8fdb --- /dev/null +++ b/campaign_trackerv2.php @@ -0,0 +1,46 @@ + diff --git a/config.php b/config.php new file mode 100644 index 00000000..e69de29b diff --git a/cron.php b/cron.php new file mode 100644 index 00000000..4056a56e --- /dev/null +++ b/cron.php @@ -0,0 +1,112 @@ +getSystemUser(); + +/////////////////////////////////////////////////////////////////////////////// +//// PREP FOR SCHEDULER PID +$GLOBALS['log']->debug('--------------------------------------------> at cron.php <--------------------------------------------'); + +$cachePath = $GLOBALS['sugar_config']['cache_dir'].'modules/Schedulers'; +$pid = 'pid.php'; +if(!is_dir($cachePath)) { + mkdir_recursive($cachePath); +} +if(!is_file($cachePath.'/'.$pid)) { + if(is_writable($cachePath)) { // the "file" does not yet exist + write_array_to_file('timestamp', array(strtotime(date('H:i'))) , $cachePath.'/'.$pid); + require_once($cachePath.'/'.$pid); + } else { + $GLOBALS['log']->fatal('Scheduler cannot write PID file. Please check permissions on '.$cachePath); + } +} else { + if(is_writable($cachePath.'/'.$pid)) { + require_once($cachePath.'/'.$pid); + } else { + $GLOBALS['log']->fatal('Scheduler cannot read the PID file. Please check permissions on '.$cachePath); + } +} +//// END PREP FOR SCHEDULER PID +/////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +//// EXECUTE IF VALID TIME (NOT DDOS) + +if($timestamp[0] < strtotime(date('H:i'))) { + if(is_writable($cachePath.'/'.$pid)) { + write_array_to_file('timestamp', array(strtotime(date('H:i'))) , $cachePath.'/'.$pid); + require('modules/Schedulers/Scheduler.php'); + $s = new Scheduler(); + $s->flushDeadJobs(); + $s->checkPendingJobs(); + } else { + $GLOBALS['log']->fatal('Scheduler cannot write PID file. Please check permissions on '.$cachePath); + } +} else { + $GLOBALS['log']->fatal('If you see a whole string of these, there is a chance someone is attacking your system.'); +} +$exit_on_cleanup = true; + +sugar_cleanup($exit_on_cleanup); +?> \ No newline at end of file diff --git a/custom/index.html b/custom/index.html new file mode 100644 index 00000000..78913dd9 --- /dev/null +++ b/custom/index.html @@ -0,0 +1,5 @@ + + +

keep me

+ + diff --git a/data/Link.php b/data/Link.php new file mode 100644 index 00000000..6221c2f4 --- /dev/null +++ b/data/Link.php @@ -0,0 +1,1094 @@ +debug("Link Constructor, relationship name: ".$_rel_name); + $GLOBALS['log']->debug("Link Constructor, Table name: ".$_table_name); + $GLOBALS['log']->debug("Link Constructor, Key name: ".$_key_name); + //_pp(func_get_args()); + $this->_relationship_name=$_rel_name; + $this->relationship_fields = (!empty($fieldDef['rel_fields']))?$fieldDef['rel_fields']: array(); + $this->_bean=&$_bean; + $this->_relationship=new Relationship(); + //$this->_relationship->retrieve_by_string_fields(array('relationship_name'=>$this->_relationship_name)); + $this->_relationship->retrieve_by_name($this->_relationship_name); + + $this->_db = DBManagerFactory::getInstance(); + + //Following behavior is tied to a property(ignore_role) value in the vardef. It alters the values of 2 properties, ignore_role_filter and add_distinct. + //the property values can be altered again before any requests are made. + if (!empty($fieldDef) && is_array($fieldDef)) { + if (array_key_exists('ignore_role', $fieldDef)) { + if ($fieldDef['ignore_role'] == true) { + $this->ignore_role_filter=true; + $this->add_distinct=true; + } + } + } + + $this->_bean_table_name=(!empty($_table_name)) ? $_table_name : $_bean->table_name; + if (!empty($key_name)) { + $this->_bean_key_name=$_key_name; + } else { + + if ($this->_relationship->lhs_table != $this->_relationship->rhs_table) { + + if ($_bean->table_name == $this->_relationship->lhs_table) + $this->_bean_key_name=$this->_relationship->lhs_key; + + if ($_bean->table_name == $this->_relationship->rhs_table) + $this->_bean_key_name=$this->_relationship->rhs_key; + + } + } + + if ($this->_relationship->lhs_table == $this->_relationship->rhs_table && isset($fieldDef['side']) && $fieldDef['side'] == 'right'){ + $this->_swap_sides = true; + } + + if (!empty($fieldDef['rhs_key_override'])) { + $this->_rhs_key_override = true; + } + if (!empty($fieldDef['bean_filter_field'])) { + $this->_bean_filter_field = $fieldDef['bean_filter_field']; + } + + //default to id if not set. + if (empty($this->_bean_key_name))$this->_bean_key_name='id'; + + $GLOBALS['log']->debug("Link Constructor, _bean_table_name: ".$this->_bean_table_name); + $GLOBALS['log']->debug("Link Constructor, _bean_key_name: ".$this->_bean_key_name); + if (!empty($this->_relationship->id)) $GLOBALS['log']->debug("Link Constructor, relationship record found."); + else $GLOBALS['log']->debug("Link Constructor, No relationship record.") ; + + } + + /* This method will return the following based on cardinality of the relationship. + * # one-to-many, many-to-many: empty array if not data is found else array of keys. + * # if many-to-many and $role set to true : empty array if not data is found else + * array of array which contain id+other fields. + * # many-to-one, one-to-one: null if no linked data is found, else key value. + * + * For a self referencing relationship the function will behave as if the user is trying + * to access the child records. To get to the parent records use the getParent() method. + */ + function get($role = false) { + if($role){ + $role_field = $this->_get_link_table_role_field($this->_relationship_name); + if($role_field !== false){ + $query = $this->getQuery(false, array(),0, "", false, "", $role_field); + }else{ + return array(); + } + }else{ + $query = $this->getQuery(); + } + $result = $this->_db->query($query, true); + $list = Array(); + while($row = $this->_db->fetchByAssoc($result)) + { + if($role){ + $list[] = $row; + }else{ + $list[] = $row['id']; + } + } + return $list; + } + + function getRelatedTableName() { + + $bean_is_lhs=$this->_get_bean_position(); + if (!isset($bean_is_lhs)) { + $GLOBALS['log']->debug("Invalid relationship parameters. Exiting.."); + return null; + } + + if ($bean_is_lhs) { + return $this->_relationship->rhs_table; + } else { + return $this->_relationship->lhs_table; + } + } + + function getRelatedModuleName() { + + $bean_is_lhs=$this->_get_bean_position(); + if (!isset($bean_is_lhs)) { + $GLOBALS['log']->debug("Invalid relationship parameters. Exiting.."); + return null; + } + + if ($bean_is_lhs) { + return $this->_relationship->rhs_module; + } else { + return $this->_relationship->lhs_module; + } + } + + + function getRelatedFields(){ + return $this->relationship_fields; + } + + function getRelatedField($name){ + return (!empty($this->relationship_fields[$name]))? $this->relationship_fields[$name]: null; + } + + function getRelationshipObject() { + return $this->_relationship; + } + + function _get_bean_position() { + //current beans module and table are on the left side or the right side. + $position = false; + if ($this->_relationship->lhs_table == $this->_bean_table_name && $this->_relationship->lhs_key == $this->_bean_key_name) { + $position = true; + + } + if ($this->_relationship->rhs_table == $this->_bean_table_name && $this->_relationship->rhs_key == $this->_bean_key_name) { + $position = false; + } + + if($this->_swap_sides){ + return !$position; + } + return $position; + } + + function _is_self_relationship() { + if ($this->_relationship->lhs_table == $this->_relationship->rhs_table) { + return true; + } + return false; + } + + function getJoin($params, $return_array =false) + { + $join_type= ' INNER JOIN '; + if(isset($params['join_type'])){ + $join_type = $params['join_type']; + } + $id = -1; + $join = ''; + $bean_is_lhs=$this->_get_bean_position(); + + if ($this->_relationship->relationship_type=='one-to-one' or $this->_relationship->relationship_type=='many-to-one' or + ($this->_relationship->relationship_type=='one-to-many' && !$bean_is_lhs)) + { + if ($bean_is_lhs) { + $table = $this->_relationship->rhs_table; + $key = $this->_relationship->rhs_key; + // check right table alias + $other_table = (empty($params['left_join_table_alias']) ? $this->_relationship->lhs_table : $params['left_join_table_alias']); + $other_key = $this->_relationship->lhs_key; + } else { + $key = $this->_relationship->lhs_key; + $table = $this->_relationship->lhs_table; + + if ( ! empty($params['join_table_alias'])) + { + $table_with_alias = $table. " ".$params['join_table_alias']; + $table = $params['join_table_alias']; + } + $other_table = (empty($params['right_join_table_alias']) ? $this->_relationship->rhs_table : $params['right_join_table_alias']); + $other_key = $this->_relationship->rhs_key; + } + + $join = $join_type . ' '. $table_with_alias . " ON\n".$table.'.'.$key.'= '.$other_table.'.'.$other_key ." AND ". $table.".deleted=0\n"; + + } + if ($this->_relationship->relationship_type == 'one-to-many' && $bean_is_lhs) { + + $table = $this->_relationship->rhs_table; + $key = $this->_relationship->rhs_key; + $other_table = (empty($params['left_join_table_alias']) ? $this->_relationship->lhs_table : $params['left_join_table_alias']); + $other_key = $this->_relationship->lhs_key; + if ( ! empty($params['join_table_alias'])) + { + $table_with_alias = $table. " ".$params['join_table_alias']; + $table = $params['join_table_alias']; + } + + $join = $join_type . ' '.$table_with_alias . " ON\n".$table.'.'.$key.'= '.$other_table.'.'.$other_key ." AND ". $table.".deleted=0\n"; + + } + + if ($this->_relationship->relationship_type=='many-to-many' ) + { + if ( ! empty($params['join_table_alias'])) + { + $table_with_alias = $this->_relationship->join_table. " ".$params['join_table_alias']; + $table = $params['join_table_alias']; + $rel_table_with_alias = + $this->_relationship->join_table. " ". + $params['join_table_link_alias']; + $rel_table = $params['join_table_link_alias']; + } + + if ( $bean_is_lhs ) + { + $other_table = (empty($params['left_join_table_alias']) ? $this->_relationship->lhs_table : $params['left_join_table_alias']); + $join .= $join_type . ' '.$rel_table_with_alias.' ON '.$other_table.".".$this->_relationship->lhs_key."=".$rel_table.".".$this->_relationship->join_key_lhs." AND ".$rel_table.".deleted=0\n"; + } else + { + $other_table = (empty($params['right_join_table_alias']) ? $this->_relationship->rhs_table : $params['right_join_table_alias']); + $join .= $join_type . ' '.$rel_table_with_alias.' ON '.$other_table.".".$this->_relationship->rhs_key."=".$rel_table.".".$this->_relationship->join_key_rhs." AND ".$rel_table.".deleted=0\n"; + } + if (!empty($this->_relationship->relationship_role_column) && !$this->ignore_role_filter) + { + $join.=" AND ".$rel_table.'.'.$this->_relationship->relationship_role_column; + //role column value. + if (empty($this->_relationship->relationship_role_column_value)) + { + $join.=' IS NULL'; + } else { + $join.= "='".$this->_relationship->relationship_role_column_value."'"; + } + $join.= "\n"; + } + if ( ! empty($params['join_table_alias'])) + { + if ( $bean_is_lhs ) + { + $table_with_alias = $this->_relationship->rhs_table. " ".$params['join_table_alias']; + } else { + $table_with_alias = $this->_relationship->lhs_table. " ".$params['join_table_alias']; + } + $table = $params['join_table_alias']; + } + + if ( $bean_is_lhs ) + { + if($this->_rhs_key_override){ + $join .= $join_type . ' '.$table_with_alias.' ON '.$table.".".$this->_relationship->rhs_key."=".$rel_table.".".$this->_relationship->join_key_rhs." AND ".$table.".deleted=0"; + }else{ + $join .= $join_type . ' '.$table_with_alias.' ON '.$table.".".$this->_relationship->lhs_key."=".$rel_table.".".$this->_relationship->join_key_rhs." AND ".$table.".deleted=0"; + } + } else { + $join .= $join_type . ' '.$table_with_alias.' ON '.$table.".".$this->_relationship->rhs_key."=".$rel_table.".".$this->_relationship->join_key_lhs." AND ".$table.".deleted=0"; + } + $join.= "\n"; + } + + if($return_array){ + $ret_arr = array(); + $ret_arr['join'] = $join; + $ret_arr['type'] = $this->_relationship->relationship_type; + if ( $bean_is_lhs ){ + + $ret_arr['rel_key'] = $this->_relationship->join_key_rhs; + }else{ + + $ret_arr['rel_key'] = $this->_relationship->join_key_lhs; + } + return $ret_arr; + } + return $join; + } + + + function _add_deleted_clause($deleted=0,$add_and='',$prefix='') { + + if (!empty($prefix)) $prefix.='.'; + if (!empty($add_and)) $add_and=' '.$add_and.' '; + + if ($deleted==0) return $add_and.$prefix.'deleted=0'; + if ($deleted==1) return $add_and.$prefix.'deleted=1'; + else return ''; + } + + function _add_optional_where_clause($optional_array, $add_and='',$prefix='') { + + if (!empty($prefix)) $prefix.='.'; + if (!empty($add_and)) $add_and=' '.$add_and.' '; + + if(!empty($optional_array)){ + return $add_and.$prefix."".$optional_array['lhs_field']."".$optional_array['operator']."'".$optional_array['rhs_value']."'"; + } + return ''; + //end function _add_optional_where_clause + } + + + + function getQuery($return_as_array=false, $sort_array = array(),$deleted=0, $optional_where="", $return_join = false, $bean_filter="", $role="", $for_subpanels = false){ + + $select=''; + $from=''; + $join = ''; + $where=''; + $join_tables = array(); + $bean_is_lhs=$this->_get_bean_position(); + + if (!isset($bean_is_lhs)) { + $GLOBALS['log']->debug("Invalid relationship parameters. Exiting.."); + return null; + } + + if (empty($bean_filter)) { + if(!empty($this->_bean_filter_field)){ + $bean_filter_field = $this->_bean_filter_field; + $bean_filter="= '".$this->_bean->$bean_filter_field."'"; + }else{ + $bean_filter="= '".$this->_bean->id."'"; + } + } + + $GLOBALS['log']->debug("getQuery, Bean is LHS: ".$bean_is_lhs); + $GLOBALS['log']->debug("getQuery, Relationship type=".$this->_relationship->relationship_type); + $GLOBALS['log']->debug("getQuery, Relationship role column name=".$this->_relationship->relationship_role_column); + + if ($this->_relationship->relationship_type=='one-to-one' or $this->_relationship->relationship_type=='many-to-one' or + ($this->_relationship->relationship_type=='one-to-many' && !$bean_is_lhs)) { + + $GLOBALS['log']->debug("Processing one-to-one,many-to-one,one-to-many."); + + if ($this->add_distinct) { + $select='SELECT DISTINCT id'; + } else { + $select='SELECT id'; + } + + if ($bean_is_lhs) { + $from= 'FROM '.$this->_relationship->rhs_table; + $where='WHERE '.$this->_relationship->rhs_table.'.'.$this->_relationship->rhs_key.$bean_filter; + if (!empty($this->_relationship->relationship_role_column) && !$this->ignore_role_filter) { + $where.=" AND ".$this->_relationship->rhs_table.'.'.$this->_relationship->relationship_role_column; + + //role column value. + if (empty($this->_relationship->relationship_role_column_value)) { + $where.=' IS NULL'; + } else { + $where.= "='".$this->_relationship->relationship_role_column_value."'"; + } + } + + //add deleted clause - but not if we're dealing with a Custom table which will lack the 'deleted' field + if(substr_count($this->_relationship->rhs_table, '_cstm') == 0) + $where.=$this->_add_deleted_clause($deleted,'AND',$this->_relationship->rhs_table ); + + if($optional_where!=""){ + //process optional where + $where.=$this->_add_optional_where_clause($optional_where,'AND'); + } + + + } + else { + $from= 'FROM '.$this->_relationship->lhs_table; + $where='WHERE '.$this->_relationship->lhs_table.'.'.$this->_relationship->lhs_key."= '".$this->_bean->{$this->_relationship->rhs_key}."'"; + //added deleted clause. + $where.=$this->_add_deleted_clause($deleted,'AND', $this->_relationship->lhs_table); + + + if($optional_where!=""){ + //process optional where + $where.=$this->_add_optional_where_clause($optional_where,'AND'); + } + + } + } + if ($this->_relationship->relationship_type == 'one-to-many' && $bean_is_lhs) { + + $GLOBALS['log']->debug("Processing one-to-many."); + + if ($this->add_distinct) { + $select='SELECT DISTINCT '.$this->_relationship->rhs_table.'.id'; + } else { + $select='SELECT '.$this->_relationship->rhs_table.'.id'; + } + $from= 'FROM '.$this->_relationship->rhs_table; + $where='WHERE '.$this->_relationship->rhs_table.'.'.$this->_relationship->rhs_key.$bean_filter; + if (!empty($this->_relationship->relationship_role_column) && !$this->ignore_role_filter) { + $where.=" AND ".$this->_relationship->rhs_table.'.'.$this->_relationship->relationship_role_column; + //role column value. + if (empty($this->_relationship->relationship_role_column_value)) { + $where.=' IS NULL'; + } else { + $where.= "='".$this->_relationship->relationship_role_column_value."'"; + } + } + + //add deleted clause - but not if we're dealing with a Custom table which will lack the 'deleted' field + if(substr_count($this->_relationship->rhs_table, '_cstm') == 0) + $where.=$this->_add_deleted_clause($deleted,'AND',$this->_relationship->rhs_table); + + if($optional_where!=""){ + //process optional where + $where.=$this->_add_optional_where_clause($optional_where,'AND'); + } + + } + + if ($this->_relationship->relationship_type=='many-to-many' ) { + $GLOBALS['log']->debug("Processing many-to-many."); + + $swap = !$for_subpanels && $this->_swap_sides; + if (($bean_is_lhs && !$swap) || (!$bean_is_lhs && $swap)) { + if ($this->add_distinct) { + $select="SELECT DISTINCT ".$this->_relationship->rhs_table.".id"; + } else { + $select="SELECT ".$this->_relationship->rhs_table.".id"; + } + + $from= 'FROM '.$this->_relationship->rhs_table; + $subjoin=' INNER JOIN '.$this->_relationship->join_table.' ON ('.$this->_relationship->rhs_table.".".$this->_relationship->rhs_key."=".$this->_relationship->join_table.".".$this->_relationship->join_key_rhs." AND ".$this->_relationship->join_table.".".$this->_relationship->join_key_lhs.$bean_filter; + $join_tables[] = $this->_relationship->join_table; + if (!empty($this->_relationship->relationship_role_column) && !$this->ignore_role_filter) { + $subjoin.=" AND ".$this->_relationship->join_table.'.'.$this->_relationship->relationship_role_column; + + //role column value. + if (empty($this->_relationship->relationship_role_column_value)) { + $subjoin.=' IS NULL'; + } else { + $subjoin.= "='".$this->_relationship->relationship_role_column_value."'"; + } + } + $subjoin.=')'; + $join .= $subjoin; + $from .= $subjoin; + + + //add deleted clause. + if ($deleted == 0 or $deleted==1) { + $where.=' WHERE '.$this->_add_deleted_clause($deleted,'',$this->_relationship->join_table).$this->_add_deleted_clause($deleted,'AND',$this->_relationship->rhs_table); + } + + + if($optional_where!=""){ + //process optional where + $where.=$this->_add_optional_where_clause($optional_where,'AND', $this->_relationship->rhs_table); + } + + + } + else { + if ($this->add_distinct) { + $select="SELECT DISTINCT ".$this->_relationship->lhs_table.".id"; + } else { + $select="SELECT ".$this->_relationship->lhs_table.".id"; + } + + $from= 'FROM '.$this->_relationship->lhs_table; + $subjoin=' INNER JOIN '.$this->_relationship->join_table.' ON ('.$this->_relationship->lhs_table.".".$this->_relationship->lhs_key."=".$this->_relationship->join_table.".".$this->_relationship->join_key_lhs." AND ".$this->_relationship->join_table.".".$this->_relationship->join_key_rhs.$bean_filter; + $join_tables[] = $this->_relationship->join_table; + if (!empty($this->_relationship->relationship_role_column) && !$this->ignore_role_filter) { + $subjoin.=" AND ".$this->_relationship->relationship_role_column; + + //role column value. + if (empty($this->_relationship->relationship_role_column_value)) { + $subjoin.=' IS NULL'; + } else { + $subjoin.= "='".$this->_relationship->relationship_role_column_value."'"; + } + } + $subjoin.=')'; + $join .= $subjoin; + $from .= $subjoin; + //add deleted clause. + if ($deleted == 0 or $deleted==1) { + $where.=' WHERE '.$this->_add_deleted_clause($deleted,'',$this->_relationship->join_table).$this->_add_deleted_clause($deleted,'AND',$this->_relationship->lhs_table); + } + + + if($optional_where!=""){ + //process optional where + $where.=$this->_add_optional_where_clause($optional_where,'AND', $this->_relationship->lhs_table); + } + + } + if (!empty($role)){ + $select.=", ".$this->_relationship->join_table.".".$role; + } + } + if ($return_as_array) { + $query_as_array['select']=$select; + $query_as_array['from']=$from; + $query_as_array['where']=$where; + if($return_join){ + $query_as_array['join'] = $join; + $query_as_array['join_tables'] = $join_tables; + } + return $query_as_array; + } + else { + $query = $select.' '.$from.' '.$where; + $GLOBALS['log']->debug("Link Query=".$query); + return $query; + } + } + + function getBeans($template, $sort_array = array(), $begin_index = 0, $end_index = -1, $deleted=0, $optional_where="") { + $query = $this->getQuery(false,array(), $deleted, $optional_where); //get array of IDs + return $this->_bean->build_related_list($query, $template); + } + + function _add_one_to_many_table_based($key,$bean_is_lhs) { + + if ($bean_is_lhs) { + $set_key_value=$this->_bean->id; + $where_key_value=$key; + } + else { + $set_key_value=$key; + $where_key_value=$this->_bean->id; + } + + $query= 'UPDATE '.$this->_relationship->rhs_table; + $query.=' SET '.$this->_relationship->rhs_table.'.'.$this->_relationship->rhs_key."='".$set_key_value."'"; + + //add role column to the query. + if (!empty($this->_relationship->relationship_role_column)) { + $query.=' ,'.$this->_relationship->relationship_role_column."='".$this->_relationship->relationship_role_column_value."'"; + } + $query.=' WHERE '.$this->_relationship->rhs_table.".id='".$where_key_value."'"; + + $GLOBALS['log']->debug("Relationship Query ".$query); + + $result=$this->_db->query($query, true); + } + + /* handles many to one*/ + function _add_many_to_one_bean_based($key) { + + //make a copy of this bean to avoid recursion. + $bean=new $this->_bean->object_name; + $bean->retrieve($this->_bean->id); + + $bean->{$this->_relationship->lhs_key}=$key; + + //set relationship role. + if (!empty($this->_relationship->relationship_role_column)) { + $bean->{$this->_relationship->relationship_role_column}=$this->_relationship->relationship_role_column_value; + } + $bean->save(); + } + + + /* use this function to create link between 2 objects + * 1:1 will be treated like 1 to many. + * todo handle self referencing relationships + * the function also allows for setting of values for additional field in the table being + * updated to save the relationship, in case of many-to-many relationships this would be the join table. + * the values should be passed as key value pairs with column name as the key name and column value as key value. + */ + function add($rel_keys,$additional_values=array()) { + + if (!isset($rel_keys) or empty($rel_keys)) { + $GLOBALS['log']->debug("Link.add, Null key passed, no-op, returning... "); + return; + } + + //check to ensure that we do in fact have an id on the bean. + if(empty($this->_bean->id)){ + $GLOBALS['log']->debug("Link.add, No id on the bean... "); + return; + } + + if (!is_array($rel_keys)) { + $keys[]=$rel_keys; + } else { + $keys=$rel_keys; + } + + $bean_is_lhs=$this->_get_bean_position(); + if (!isset($bean_is_lhs)) { + $GLOBALS['log']->debug("Invalid relationship parameters. Exiting.."); + return null; + } + //if multiple keys are passed then check for unsupported relationship types. + if (count($keys) > 1) { + if (($this->_relationship->relationship_type == 'one-to-one') + or ($this->_relationship->relationship_type == 'one-to-many' and !$bean_is_lhs) + or ($this->_relationship->relationship_type == 'many-to-one')) { + $GLOBALS['log']->error("Invalid parameters passed to function, the relationship does not support addition of multiple records."); + return; + } + } + $GLOBALS['log']->debug("Relationship type = {$this->_relationship->relationship_type}"); + foreach($keys as $key) { + + //fetch the related record using the key and update. + if ($this->_relationship->relationship_type=='one-to-one' or $this->_relationship->relationship_type == 'one-to-many') { + $this->_add_one_to_many_table_based($key,$bean_is_lhs); + } + + //updates the bean passed to the instance.... + //todo remove this case. + if ($this->_relationship->relationship_type=='many-to-one') { + $this->_add_many_to_one_bean_based($key); + } + + //insert record in the link table. + if ($this->_relationship->relationship_type=='many-to-many' ) { + + //Swap the bean positions for self relationships not coming from subpanels. + //such as one-to-many relationship fields generated in studio/MB + $swap = !isset($_REQUEST['subpanel_id']) && $this->_swap_sides; + //add keys from the 2 tables to the additional keys array.. + if (($bean_is_lhs && !$swap) || (!$bean_is_lhs && $swap)) { + $additional_values[$this->_relationship->join_key_lhs]=$this->_bean->id; + $additional_values[$this->_relationship->join_key_rhs]=$key; + } else { + $additional_values[$this->_relationship->join_key_rhs]=$this->_bean->id; + $additional_values[$this->_relationship->join_key_lhs]=$key; + } + //add the role condition. + if (!empty($this->_relationship->relationship_role_column) && !empty($this->_relationship->relationship_role_column_value)) { + $additional_values[$this->_relationship->relationship_role_column]=$this->_relationship->relationship_role_column_value; + } + //add deleted condition. + $additional_values['deleted']=0; + + $this->_add_many_to_many($additional_values); + + //reverse will be set to true only for self-referencing many-to-many relationships. + if ($this->_is_self_relationship() && !empty($GLOBALS['dictionary'][$this->_relationship_name]) && + !empty($GLOBALS['dictionary'][$this->_relationship_name]['true_relationship_type']) && + $GLOBALS['dictionary'][$this->_relationship_name]['true_relationship_type'] == 'many-to-many' || + (!empty($this->_relationship->reverse) && $this->_relationship->reverse == true )){ + //swap key values; + $temp=$additional_values[$this->_relationship->join_key_lhs]; + $additional_values[$this->_relationship->join_key_lhs]=$additional_values[$this->_relationship->join_key_rhs]; + $additional_values[$this->_relationship->join_key_rhs]=$temp; + + $this->_add_many_to_many($additional_values); + } + } + $custom_logic_arguments = array(); + $custom_reverse_arguments = array(); + $custom_logic_arguments['related_id'] = $key; + $custom_logic_arguments['id'] = $this->_bean->id; + $custom_reverse_arguments['related_id'] = $this->_bean->id; + $custom_reverse_arguments['id'] = $key; + if($bean_is_lhs) { + $custom_logic_arguments['module'] = $this->_relationship->lhs_module; + $custom_logic_arguments['related_module'] = $this->_relationship->rhs_module; + $custom_reverse_arguments['module'] = $this->_relationship->rhs_module; + $custom_reverse_arguments['related_module'] = $this->_relationship->lhs_module; + } else { + $custom_logic_arguments['related_module'] = $this->_relationship->lhs_module; + $custom_reverse_arguments['related_module'] = $this->_relationship->rhs_module; + $custom_logic_arguments['module'] = $this->_relationship->rhs_module; + $custom_reverse_arguments['module'] = $this->_relationship->lhs_module; + } + /**** CALL IT FROM THE MAIN BEAN FIRST ********/ + $this->_bean->call_custom_logic('after_relationship_add', $custom_logic_arguments); + /**** NOW WE HAVE TO CALL THE LOGIC HOOK THE OTHER WAY SINCE IT TAKES TWO FOR A RELATIONSHIP****/ + global $beanList; + if ( isset($beanList[$custom_logic_arguments['related_module']]) ) { + $class = $beanList[$custom_logic_arguments['related_module']]; + if ( !empty($class) ) { + $rbean = new $class(); + $rbean->id = $key; + $rbean->call_custom_logic('after_relationship_add', $custom_reverse_arguments); + } + } + } + } + + function _add_many_to_many($add_values) { + + //add date modified. + $add_values['date_modified']= $GLOBALS['timedate']->nowDb(); + + //check whether duplicate exist or not. + if ($this->relationship_exists($this->_relationship->join_table,$add_values)) { + +/* switch($this->when_dup_relationship_found) { + + case 1: //do nothing. + $GLOBALS['log']->debug("Executing default option, no action."); + break; + + case 3: //delete the record first, then create a new entry. + $this->_delete_row($this->_relationship->join_table,$this->_duplicate_key); + $this->_insert_row($add_values); + break; + + default: + case 2: //update the record. +*/ $this->_update_row($add_values,$this->_relationship->join_table,$this->_duplicate_where); +/* break; + }*/ + + } else { + $this->_insert_row($add_values); + } + } + + function _delete_row($table_name,$key) { + $query="UPDATE $table_name SET deleted=1, date_modified='" .$GLOBALS['timedate']->nowDb()."' WHERE id='$key'"; + $GLOBALS['log']->debug("Relationship Delete Statement :".$query); + + $result=$this->_db->query($query, true); + } + + function _update_row(&$value_array,$table_name,$where) { + + $query='UPDATE '.$table_name.' SET '; + $delimiter=''; + foreach ($value_array as $key=>$value) { + $query.=$delimiter.$key."='".$value."' "; + $delimiter=","; + } + $query.=$where; + $GLOBALS['log']->debug("Relationship Update Statement :".$query); + + $result=$this->_db->query($query, true); + } + + function _insert_row(&$value_array) { + //add key column + $value_array['id']= create_guid(); + + $columns_list=''; + $values_list=''; + $delimiter=''; + foreach ($value_array as $key=>$value) { + $columns_list.=$delimiter.$key; + $values_list .=$delimiter."'".$value."'"; + $delimiter=","; + } + $insert_string='INSERT into '.$this->_relationship->join_table.' ('.$columns_list.') VALUES ('.$values_list.')'; + $GLOBALS['log']->debug("Relationship Insert String :".$insert_string); + + $result=$this->_db->query($insert_string, true); + } + + + + /* this method operates on all related record, takes action based on cardinality of the relationship. + * one-to-one, one-to-many: update the rhs table's parent id with null + * many-to-one: update the lhs table's parent-id with null. + * many-to-many: delete rows from the link table. related table must have delted and date_modified column. + * if related_is is null, the methods assumes that the parent bean (whose id is passed) is being deleted. + * if both id and related_id are passed the metod unlinks a single relationship. + * parameters: id of the bean being deleted. + * + */ + function delete($id,$related_id='') { + $GLOBALS['log']->debug(sprintf("delete called with these parameter values. id=%s, related_id=%s",$id,$related_id)); + + $_relationship=&$this->_relationship; + $_bean=&$this->_bean; + + $bean_is_lhs=$this->_get_bean_position(); + if (!isset($bean_is_lhs)) { + $GLOBALS['log']->debug("Invalid relationship parameters. Exiting.."); + return null; + } + if ($_relationship->relationship_type=='one-to-many' or $_relationship->relationship_type=='one-to-one' ) { + if ($bean_is_lhs) { + //update rhs_table set rhs_key = null, relation_column_name = null where rhs_key= this_bean_id + $query='UPDATE '.$_relationship->rhs_table.' SET '.$_relationship->rhs_key."=NULL, date_modified='".$GLOBALS['timedate']->nowDb()."'"; + + if (!empty($_relationship->relationship_role_column) && !empty($_relationship->relationship_role_column_value)) { + $query.=','.$_relationship->relationship_role_column."= NULL "; + $query.=' WHERE '.$_relationship->relationship_role_column."= '".$_relationship->relationship_role_column_value."' AND "; + } else { + $query.=' WHERE '; + } + $query.=$_relationship->rhs_key."= '".$id."' "; + + //restrict to one row if related_id is passed. + if (!empty($related_id)) { + $query.=" AND ".$_relationship->rhs_table.".id='".$related_id."'"; + } + + } + else { + //do nothing because the row that stores the relationship keys is being deleted. + //todo log an error message here. + //if this is the case and related_id is passed then log a message asking the user + //to clear the relationship using the bean. + } + } + + if ($_relationship->relationship_type=='many-to-one') { + //do nothing because the row that stores the relationship keys is being deleted. + //todo log an error message here. + //if this is the case and related_id is passed then log a message asking the user + //to clear the relationship using the bean. + } + + if ($_relationship->relationship_type=='many-to-many' ) { + $use_bean_is_lhs = isset($_REQUEST['ajaxSubpanel']) || $this->_swap_sides !== true; + $query='UPDATE '.$_relationship->join_table." SET deleted=1, date_modified='".$GLOBALS['timedate']->nowDb()."'"; + if ($bean_is_lhs && $use_bean_is_lhs) { + if (!empty($this->_relationship->reverse) && ($this->_relationship->reverse == true or $this->_relationship->reverse == 1)){ + if (empty($related_id)) { + $query.=" WHERE (".$_relationship->join_key_lhs."= '". $id ."' or ".$_relationship->join_key_rhs."='". $id ."')" ; + } else { + $query.=" WHERE (".$_relationship->join_key_lhs."= '". $id ."' AND ".$_relationship->join_key_rhs."='".$related_id."') OR (".$_relationship->join_key_rhs."='". $id ."' AND ".$_relationship->join_key_lhs."='".$related_id."')"; + } + } else { + if (empty($related_id)) { + $query.=" WHERE ".$_relationship->join_key_lhs."= '". $id ."'"; + } else { + $query.=" WHERE ".$_relationship->join_key_lhs."= '". $id ."' AND ".$_relationship->join_key_rhs."= '". $related_id."'"; + } + } + } else { + if (!empty($this->_relationship->reverse) && ($this->_relationship->reverse == true or $this->_relationship->reverse == 1)) { + if (empty($related_id)) { + $query.=" WHERE (".$_relationship->join_key_rhs."= '". $id ."' or ".$_relationship->join_key_lhs."='". $id ."')" ; + } else { + $query.=" WHERE (".$_relationship->join_key_rhs."= '". $id ."' AND ".$_relationship->join_key_lhs."='".$related_id."') OR (".$_relationship->join_key_lhs."='". $id ."' AND ".$_relationship->join_key_rhs."='".$related_id."')"; + } + } else { + if (empty($related_id)) { + $query.=" WHERE ".$_relationship->join_key_rhs."= '". $id ."'" ; + } else { + $query.=" WHERE ".$_relationship->join_key_rhs."= '". $id ."' AND ".$_relationship->join_key_lhs."= '". $related_id."'" ; + } + } + if (!empty($_relationship->relationship_role_column) && !empty($_relationship->relationship_role_column_value)) { + $query.=' AND '.$_relationship->relationship_role_column."= '".$_relationship->relationship_role_column_value."'"; + } + } + } + //if query string is not empty execute it. + if (isset($query)) { + $GLOBALS['log']->debug('Link.Delete:Delete Query: '.$query); + $this->_db->query($query,true); + } + $custom_logic_arguments = array(); + $custom_logic_arguments['id'] = $id; + $custom_logic_arguments['related_id'] = $related_id; + $custom_reverse_arguments = array(); + $custom_reverse_arguments['related_id'] = $id; + $custom_reverse_arguments['id'] = $related_id; + if($bean_is_lhs) { + $custom_logic_arguments['module'] = $this->_relationship->lhs_module; + $custom_logic_arguments['related_module'] = $this->_relationship->rhs_module; + $custom_reverse_arguments['module'] = $this->_relationship->lhs_module; + $custom_reverse_arguments['related_module'] = $this->_relationship->rhs_module; + } else { + $custom_logic_arguments['module'] = $this->_relationship->rhs_module; + $custom_logic_arguments['related_module'] = $this->_relationship->lhs_module; + $custom_reverse_arguments['module'] = $this->_relationship->lhs_module; + $custom_reverse_arguments['related_module'] = $this->_relationship->rhs_module; + } + + if (empty($this->_bean->id)) { + $this->_bean->retrieve($id);//!$bean_is_lhs || empty($related_id) ? $id : $related_id); + } + $this->_bean->call_custom_logic('after_relationship_delete', $custom_logic_arguments); + //NOW THE REVERSE WAY SINCE A RELATIONSHIP TAKES TWO + global $beanList; + if ( isset($beanList[$custom_logic_arguments['related_module']]) ) { + $class = $beanList[$custom_logic_arguments['related_module']]; + if ( !empty($class) ) { + $rbean = new $class(); + $rbean->retrieve(empty($related_id) ? $id : $related_id); + $rbean->call_custom_logic('after_relationship_delete', $custom_reverse_arguments); + } + } + } + + function relationship_exists($table_name, $join_key_values) { + + //find the key values for the table. + $dup_keys=$this->_get_alternate_key_fields($table_name); + if (empty($dup_keys)) { + $GLOBALS['log']->debug("No alternate key define, skipping duplicate check.."); + return false; + } + + $delimiter=''; + $this->_duplicate_where=' WHERE '; + foreach ($dup_keys as $field) { + //look for key in $join_key_values, if found add to filter criteria else abort duplicate checking. + if (isset($join_key_values[$field])) { + + $this->_duplicate_where .= $delimiter.' '.$field."='".$join_key_values[$field]."'"; + $delimiter='AND'; + } else { + $GLOBALS['log']->error('Duplicate checking aborted, Please supply a value for this column '.$field); + return false; + } + } + //add deleted check. + $this->_duplicate_where .= $delimiter.' deleted=0'; + + $query='SELECT id FROM '.$table_name.$this->_duplicate_where; + + $GLOBALS['log']->debug("relationship_exists query(".$query.')'); + + $result=$this->_db->query($query, true); + $row = $this->_db->fetchByAssoc($result); + + if ($row == null) { + return false; + } + else { + $this->_duplicate_key=$row['id']; + return true; + } + } + + /* returns array of keys for duplicate checking, first check for an index of type alternate_key, if not found searches for + * primary key. + * + */ + function _get_alternate_key_fields($table_name) { + $alternateKey=null; + $indices=Link::_get_link_table_definition($table_name,'indices'); + if (!empty($indices)) { + foreach ($indices as $index) { + if ( isset($index['type']) && $index['type'] == 'alternate_key' ) { + return $index['fields']; + } + } + } + $relationships=Link::_get_link_table_definition($table_name,'relationships'); + if (!empty($relationships)) {//bug 32623, when the relationship is built in old version, there is no alternate_key. we have to use join_key_lhs and join_key_lhs. + if(!empty($relationships[$this->_relationship_name]) && !empty($relationships[$this->_relationship_name]['join_key_lhs']) && !empty($relationships[$this->_relationship_name]['join_key_rhs'])) { + return array($relationships[$this->_relationship_name]['join_key_lhs'], $relationships[$this->_relationship_name]['join_key_rhs']); + } + } + } + + /* + */ + function _get_link_table_definition($table_name,$def_name) { + global $dictionary; + + include_once('modules/TableDictionary.php'); + // first check to see if already loaded - assumes hasn't changed in the meantime + if (isset($dictionary[$table_name][$def_name])) + { + return $dictionary[$table_name][$def_name]; + } + else { + if (isset($dictionary[$this->_relationship_name][$def_name])) { + return ($dictionary[$this->_relationship_name][$def_name]); + } + // custom metadata is found in custom/metadata (naturally) and the naming follows the convention $relationship_name_c, and $relationship_name = $table_name$locations = array( 'metadata/' , 'custom/metadata/' ) ; + $relationshipName = preg_replace( '/_c$/' , '' , $table_name ) ; + + $locations = array ( 'metadata/' , 'custom/metadata/' ) ; + + foreach ( $locations as $basepath ) + { + $path = $basepath . $relationshipName . 'MetaData.php' ; + + if (file_exists($path)) + { + include($path); + if (isset($dictionary[$relationshipName][$def_name])) { + return $dictionary[$relationshipName][$def_name]; + } + } + } + // couldn't find the metadata for the table in either the standard or custom locations + $GLOBALS['log']->debug('Error fetching field defs for join table '.$table_name); + + return null; + } + + + + } + /* + * Return the name of the role field for the passed many to many table. + * if there is no role filed : return false + */ + function _get_link_table_role_field($table_name) { + $varDefs = $this->_get_link_table_definition($table_name, 'fields'); + $role_field = false; + if(!empty($varDefs)){ + $role_field = ''; + foreach($varDefs as $v){ + if(strpos($v['name'], '_role') !== false){ + $role_field = $v['name']; + } + } + } + return $role_field; + } + + +} +?> diff --git a/data/SugarBean.php b/data/SugarBean.php new file mode 100644 index 00000000..5a49ccab --- /dev/null +++ b/data/SugarBean.php @@ -0,0 +1,5467 @@ +/Import/views/view.step4.php if a module is being imported + */ + var $in_import = false; + /** + * Constructor for the bean, it performs following tasks: + * + * 1. Initalized a database connections + * 2. Load the vardefs for the module implemeting the class. cache the entries + * if needed + * 3. Setup row-level security preference + * All implementing classes must call this constructor using the parent::SugarBean() class. + * + */ + function SugarBean() + { + global $dictionary, $current_user; + static $loaded_defs = array(); + $this->db = DBManagerFactory::getInstance(); + + $this->dbManager = DBManagerFactory::getInstance(); + if((false == $this->disable_vardefs && empty($loaded_defs[$this->object_name])) || !empty($GLOBALS['reload_vardefs'])) + { + VardefManager::loadVardef($this->module_dir, $this->object_name); + + // build $this->column_fields from the field_defs if they exist + if (!empty($dictionary[$this->object_name]['fields'])) { + foreach ($dictionary[$this->object_name]['fields'] as $key=>$value_array) { + $column_fields[] = $key; + if(!empty($value_array['required']) && !empty($value_array['name'])) { + $this->required_fields[$value_array['name']] = 1; + } + } + $this->column_fields = $column_fields; + } + + //setup custom fields + if(!isset($this->custom_fields) && + empty($this->disable_custom_fields)) + { + $this->setupCustomFields($this->module_dir); + } + //load up field_arrays from CacheHandler; + if(empty($this->list_fields)) + $this->list_fields = $this->_loadCachedArray($this->module_dir, $this->object_name, 'list_fields'); + if(empty($this->column_fields)) + $this->column_fields = $this->_loadCachedArray($this->module_dir, $this->object_name, 'column_fields'); + if(empty($this->required_fields)) + $this->required_fields = $this->_loadCachedArray($this->module_dir, $this->object_name, 'required_fields'); + + if(isset($GLOBALS['dictionary'][$this->object_name]) && !$this->disable_vardefs) + { + $this->field_name_map = $dictionary[$this->object_name]['fields']; + $this->field_defs = $dictionary[$this->object_name]['fields']; + + if(!empty($dictionary[$this->object_name]['optimistic_locking'])) + { + $this->optimistic_lock=true; + } + } + $loaded_defs[$this->object_name]['column_fields'] =& $this->column_fields; + $loaded_defs[$this->object_name]['list_fields'] =& $this->list_fields; + $loaded_defs[$this->object_name]['required_fields'] =& $this->required_fields; + $loaded_defs[$this->object_name]['field_name_map'] =& $this->field_name_map; + $loaded_defs[$this->object_name]['field_defs'] =& $this->field_defs; + } + else + { + $this->column_fields =& $loaded_defs[$this->object_name]['column_fields'] ; + $this->list_fields =& $loaded_defs[$this->object_name]['list_fields']; + $this->required_fields =& $loaded_defs[$this->object_name]['required_fields']; + $this->field_name_map =& $loaded_defs[$this->object_name]['field_name_map']; + $this->field_defs =& $loaded_defs[$this->object_name]['field_defs']; + $this->added_custom_field_defs = true; + + if(!isset($this->custom_fields) && + empty($this->disable_custom_fields)) + { + $this->setupCustomFields($this->module_dir, false); + } + if(!empty($dictionary[$this->object_name]['optimistic_locking'])) + { + $this->optimistic_lock=true; + } + } + + if($this->bean_implements('ACL') && !empty($GLOBALS['current_user'])){ + $this->acl_fields = (isset($dictionary[$this->object_name]['acl_fields']) && $dictionary[$this->object_name]['acl_fields'] === false)?false:true; + } + $this->populateDefaultValues(); + } + + + /** + * Returns the object name. If object_name is not set, table_name is returned. + * + * All implementing classes must set a value for the object_name variable. + * + * @param array $arr row of data fetched from the database. + * @return nothing + * + */ + function getObjectName() + { + if ($this->object_name) + return $this->object_name; + + // This is a quick way out. The generated metadata files have the table name + // as the key. The correct way to do this is to override this function + // in bean and return the object name. That requires changing all the beans + // as well as put the object name in the generator. + return $this->table_name; + } + + /** + * Returns a list of fields with their definitions that have the audited property set to true. + * Before calling this function, check whether audit has been enabled for the table/module or not. + * You would set the audit flag in the implemting module's vardef file. + * + * @return an array of + * @see is_AuditEnabled + * + * Internal function, do not override. + */ + function getAuditEnabledFieldDefinitions() + { + $aclcheck = $this->bean_implements('ACL'); + $is_owner = $this->isOwner($GLOBALS['current_user']->id); + if (!isset($this->audit_enabled_fields)) + { + + $this->audit_enabled_fields=array(); + foreach ($this->field_defs as $field => $properties) + { + + if ( + ( + !empty($properties['Audited']) || !empty($properties['audited'])) + ) + { + + $this->audit_enabled_fields[$field]=$properties; + } + } + + } + return $this->audit_enabled_fields; + } + + /** + * Return true if auditing is enabled for this object + * You would set the audit flag in the implemting module's vardef file. + * + * @return boolean + * + * Internal function, do not override. + */ + function is_AuditEnabled() + { + global $dictionary; + if (isset($dictionary[$this->getObjectName()]['audited'])) + { + return $dictionary[$this->getObjectName()]['audited']; + } + else + { + return false; + } + } + + + + /** + * Returns the name of the audit table. + * Audit table's name is based on implementing class' table name. + * + * @return String Audit table name. + * + * Internal function, do not override. + */ + function get_audit_table_name() + { + return $this->getTableName().'_audit'; + } + + /** + * If auditing is enabled, create the audit table. + * + * Function is used by the install scripts and a repair utility in the admin panel. + * + * Internal function, do not override. + */ + function create_audit_table() + { + global $dictionary; + $table_name=$this->get_audit_table_name(); + + require('metadata/audit_templateMetaData.php'); + + $fieldDefs = $dictionary['audit']['fields']; + $indices = $dictionary['audit']['indices']; + // '0' stands for the first index for all the audit tables + $indices[0]['name'] = 'idx_' . strtolower($this->getTableName()) . '_' . $indices[0]['name']; + $indices[1]['name'] = 'idx_' . strtolower($this->getTableName()) . '_' . $indices[1]['name']; + $engine = null; + if(isset($dictionary['audit']['engine'])) { + $engine = $dictionary['audit']['engine']; + } else if(isset($dictionary[$this->getObjectName()]['engine'])) { + $engine = $dictionary[$this->getObjectName()]['engine']; + } + + $sql=$this->dbManager->helper->createTableSQLParams($table_name, $fieldDefs, $indices, $engine); + + $msg = "Error creating table: ".$table_name. ":"; + $this->dbManager->query($sql,true,$msg); + } + + /** + * Returns the implementing class' table name. + * + * All implementing classes set a value for the table_name variable. This value is returned as the + * table name. If not set, table name is extracted from the implementing module's vardef. + * + * @return String Table name. + * + * Internal function, do not override. + */ + function getTableName() + { + global $dictionary; + if(isset($this->table_name)) + { + return $this->table_name; + } + return $dictionary[$this->getObjectName()]['table']; + } + + /** + * Returns field definitions for the implementing module. + * + * The definitions were loaded in the constructor. + * + * @return Array Field definitions. + * + * Internal function, do not override. + */ + function getFieldDefinitions() + { + return $this->field_defs; + } + + /** + * Returns index definitions for the implementing module. + * + * The definitions were loaded in the constructor. + * + * @return Array Index definitions. + * + * Internal function, do not override. + */ + function getIndices() + { + global $dictionary; + if(isset($dictionary[$this->getObjectName()]['indices'])) + { + return $dictionary[$this->getObjectName()]['indices']; + } + return array(); + } + + /** + * Returns field definition for the requested field name. + * + * The definitions were loaded in the constructor. + * + * @param string field name, + * @return Array Field properties or boolean false if the field doesn't exist + * + * Internal function, do not override. + */ + function getFieldDefinition($name) + { + if ( !isset($this->field_defs[$name]) ) + return false; + + return $this->field_defs[$name]; + } + + /** + * Returnss definition for the id field name. + * + * The definitions were loaded in the constructor. + * + * @return Array Field properties. + * + * Internal function, do not override. + */ + function getPrimaryFieldDefinition() + { + $def = $this->getFieldDefinition("id"); + if (!$def) + $def = $this->getFieldDefinition(0); + return $def; + } + /** + * Returns the value for the requested field. + * + * When a row of data is fetched using the bean, all fields are created as variables in the context + * of the bean and then fetched values are set in these variables. + * + * @param string field name, + * @return varies Field value. + * + * Internal function, do not override. + */ + function getFieldValue($name) + { + if (!isset($this->$name)){ + return FALSE; + } + if($this->$name === TRUE){ + return 1; + } + if($this->$name === FALSE){ + return 0; + } + return $this->$name; + } + + /** + * Basically undoes the effects of SugarBean::populateDefaultValues(); this method is best called right after object + * initialization. + */ + public function unPopulateDefaultValues() + { + if ( !is_array($this->field_defs) ) + return; + + foreach ($this->field_defs as $field => $value) { + if( !empty($this->$field) + && ((isset($value['default']) && $this->$field == $value['default']) || (!empty($value['display_default']) && $this->$field == $value['display_default'])) + ) { + $this->$field = null; + continue; + } + if(!empty($this->$field) && !empty($value['display_default']) && in_array($value['type'], array('date', 'datetime', 'datetimecombo')) && + $this->$field == $this->parseDateDefault($value['display_default'], ($value['type'] != 'date'))) { + $this->$field = null; + } + } + } + + /** + * Create date string from default value + * like '+1 month' + * @param string $value + * @param bool $time Should be expect time set too? + * @return string + */ + protected function parseDateDefault($value, $time = false) + { + global $timedate; + if($time) { + $dtAry = explode('&', $value, 2); + $dateValue = $timedate->getNow(true)->modify($dtAry[0]); + if(!empty($dtAry[1])) { + $timeValue = $timedate->fromString($dtAry[1]); + $dateValue->setTime($timeValue->hour, $timeValue->min, $timeValue->sec); + } + return $timedate->asUser($dateValue); + } else { + return $timedate->asUserDate($timedate->getNow(true)->modify($value)); + } + } + + function populateDefaultValues($force=false){ + if ( !is_array($this->field_defs) ) + return; + foreach($this->field_defs as $field=>$value){ + if((isset($value['default']) || !empty($value['display_default'])) && ($force || empty($this->$field))){ + $type = $value['type']; + + switch($type){ + case 'date': + if(!empty($value['display_default'])){ + $this->$field = $this->parseDateDefault($value['display_default']); + } + break; + case 'datetime': + case 'datetimecombo': + if(!empty($value['display_default'])){ + $this->$field = $this->parseDateDefault($value['display_default'], true); + } + break; + case 'multienum': + if(empty($value['default']) && !empty($value['display_default'])) + $this->$field = $value['display_default']; + else + $this->$field = $value['default']; + break; + default: + if ( isset($value['default']) && $value['default'] !== '' ) { + $this->$field = htmlentities($value['default'], ENT_QUOTES, 'UTF-8'); + } else { + $this->$field = ''; + } + } //switch + } + } //foreach + } + + + /** + * Removes relationship metadata cache. + * + * Every module that has relationships defined with other modules, has this meta data cached. The cache is + * stores in 2 locations: relationships table and file system. This method clears the cache from both locations. + * + * @param string $key module whose meta cache is to be cleared. + * @param string $db database handle. + * @param string $tablename table name + * @param string $dictionary vardef for the module + * @param string $module_dir name of subdirectory where module is installed. + * + * @return Nothing + * @static + * + * Internal function, do not override. + */ + function removeRelationshipMeta($key,$db,$tablename,$dictionary,$module_dir) + { + //load the module dictionary if not supplied. + if ((!isset($dictionary) or empty($dictionary)) && !empty($module_dir)) + { + $filename='modules/'. $module_dir . '/vardefs.php'; + if(file_exists($filename)) + { + include($filename); + } + } + if (!is_array($dictionary) or !array_key_exists($key, $dictionary)) + { + $GLOBALS['log']->fatal("removeRelationshipMeta: Metadata for table ".$tablename. " does not exist"); + display_notice("meta data absent for table ".$tablename." keyed to $key "); + } + else + { + if (isset($dictionary[$key]['relationships'])) + { + $RelationshipDefs = $dictionary[$key]['relationships']; + foreach ($RelationshipDefs as $rel_name) + { + Relationship::delete($rel_name,$db); + } + } + } + } + + + /** + * This method has been deprecated. + * + * @see removeRelationshipMeta() + * @deprecated 4.5.1 - Nov 14, 2006 + * @static + */ + function remove_relationship_meta($key,$db,$log,$tablename,$dictionary,$module_dir) + { + SugarBean::removeRelationshipMeta($key,$db,$tablename,$dictionary,$module_dir); + } + + + /** + * Populates the relationship meta for a module. + * + * It is called during setup/install. It is used statically to create relationship meta data for many-to-many tables. + * + * @param string $key name of the object. + * @param object $db database handle. + * @param string $tablename table, meta data is being populated for. + * @param array dictionary vardef dictionary for the object. * + * @param string module_dir name of subdirectory where module is installed. + * @param boolean $iscustom Optional,set to true if module is installed in a custom directory. Default value is false. + * @static + * + * Internal function, do not override. + */ + function createRelationshipMeta($key,$db,$tablename,$dictionary,$module_dir,$iscustom=false) + { + //load the module dictionary if not supplied. + if (empty($dictionary) && !empty($module_dir)) + { + if($iscustom) + { + $filename='custom/modules/' . $module_dir . '/Ext/Vardefs/vardefs.ext.php'; + } + else + { + if ($key == 'User') + { + // a very special case for the Employees module + // this must be done because the Employees/vardefs.php does an include_once on + // Users/vardefs.php + $filename='modules/Users/vardefs.php'; + } + else + { + $filename='modules/'. $module_dir . '/vardefs.php'; + } + } + + if(file_exists($filename)) + { + include($filename); + // cn: bug 7679 - dictionary entries defined as $GLOBALS['name'] not found + if(empty($dictionary) || !empty($GLOBALS['dictionary'][$key])) + { + $dictionary = $GLOBALS['dictionary']; + } + } + else + { + $GLOBALS['log']->debug("createRelationshipMeta: no metadata file found" . $filename); + return; + } + } + + if (!is_array($dictionary) or !array_key_exists($key, $dictionary)) + { + $GLOBALS['log']->fatal("createRelationshipMeta: Metadata for table ".$tablename. " does not exist"); + display_notice("meta data absent for table ".$tablename." keyed to $key "); + } + else + { + if (isset($dictionary[$key]['relationships'])) + { + + $RelationshipDefs = $dictionary[$key]['relationships']; + + $delimiter=','; + global $beanList; + $beanList_ucase=array_change_key_case ( $beanList ,CASE_UPPER); + foreach ($RelationshipDefs as $rel_name=>$rel_def) + { + if (isset($rel_def['lhs_module']) and !isset($beanList_ucase[strtoupper($rel_def['lhs_module'])])) { + $GLOBALS['log']->debug('skipping orphaned relationship record ' . $rel_name . ' lhs module is missing ' . $rel_def['lhs_module']); + continue; + } + if (isset($rel_def['rhs_module']) and !isset($beanList_ucase[strtoupper($rel_def['rhs_module'])])) { + $GLOBALS['log']->debug('skipping orphaned relationship record ' . $rel_name . ' rhs module is missing ' . $rel_def['rhs_module']); + continue; + } + + + //check whether relationship exists or not first. + if (Relationship::exists($rel_name,$db)) + { + $GLOBALS['log']->debug('Skipping, reltionship already exists '.$rel_name); + } + else + { + // add Id to the insert statement. + $column_list='id'; + $value_list="'".create_guid()."'"; + + //add relationship name to the insert statement. + $column_list .= $delimiter.'relationship_name'; + $value_list .= $delimiter."'".$rel_name."'"; + + //todo check whether $rel_def is an array or not. + //for now make that assumption. + //todo specify defaults if meta not defined. + foreach ($rel_def as $def_key=>$value) + { + $column_list.= $delimiter.$def_key; + $value_list.= $delimiter."'".$value."'"; + } + + //create the record. todo add error check. + $insert_string = "INSERT into relationships (" .$column_list. ") values (".$value_list.")"; + $db->query($insert_string, true); + } + } + } + else + { + //todo + //log informational message stating no relationships meta was set for this bean. + } + } + } + + /** + * This method has been deprecated. + * @see createRelationshipMeta() + * @deprecated 4.5.1 - Nov 14, 2006 + * @static + */ + function create_relationship_meta($key,&$db,&$log,$tablename,$dictionary,$module_dir) + { + SugarBean::createRelationshipMeta($key,$db,$tablename,$dictionary,$module_dir); + } + + + /** + * Loads the request relationship. This method should be called before performing any operations on the related data. + * + * This method searches the vardef array for the requested attribute's definition. If the attribute is of the type + * link then it creates a similary named variable and loads the relationship definition. + * + * @param string $rel_name relationship/attribute name. + * @return nothing. + */ + function load_relationship($rel_name) + { + $GLOBALS['log']->debug("SugarBean.load_relationships, Loading relationship (".$rel_name.")."); + + if (empty($rel_name)) + { + $GLOBALS['log']->error("SugarBean.load_relationships, Null relationship name passed."); + return false; + } + $fieldDefs = $this->getFieldDefinitions(); + + //find all definitions of type link. + if (!empty($fieldDefs)) + { + //if rel_name is provided, search the fieldef array keys by name. + if (array_key_exists($rel_name, $fieldDefs)) + { + if (array_search('link',$fieldDefs[$rel_name]) === 'type') + { + //initialize a variable of type Link + require_once('data/Link.php'); + $class = load_link_class($fieldDefs[$rel_name]); + + $this->$rel_name=new $class($fieldDefs[$rel_name]['relationship'], $this, $fieldDefs[$rel_name]); + + if (empty($this->$rel_name->_relationship->id)) { + unset($this->$rel_name); + return false; + } + return true; + } + } + else + { + $GLOBALS['log']->debug("SugarBean.load_relationships, Error Loading relationship (".$rel_name.")."); + return false; + } + } + + return false; + } + + /** + * Loads all attributes of type link. + * + * Method searches the implmenting module's vardef file for attributes of type link, and for each attribute + * create a similary named variable and load the relationship definition. + * + * @return Nothing + * + * Internal function, do not override. + */ + function load_relationships() + { + + $GLOBALS['log']->debug("SugarBean.load_relationships, Loading all relationships of type link."); + + $linked_fields=$this->get_linked_fields(); + require_once("data/Link.php"); + foreach($linked_fields as $name=>$properties) + { + $class = load_link_class($properties); + + $this->$name=new $class($properties['relationship'], $this, $properties); + } + } + + /** + * Returns an array of beans of related data. + * + * For instance, if an account is related to 10 contacts , this function will return an array of contacts beans (10) + * with each bean representing a contact record. + * Method will load the relationship if not done so already. + * + * @param string $field_name relationship to be loaded. + * @param string $bean name class name of the related bean. + * @param array $sort_array optional, unused + * @param int $begin_index Optional, default 0, unused. + * @param int $end_index Optional, default -1 + * @param int $deleted Optional, Default 0, 0 adds deleted=0 filter, 1 adds deleted=1 filter. + * @param string $optional_where, Optional, default empty. + * + * Internal function, do not override. + */ + function get_linked_beans($field_name,$bean_name, $sort_array = array(), $begin_index = 0, $end_index = -1, + $deleted=0, $optional_where="") + { + + //if bean_name is Case then use aCase + if($bean_name=="Case") + $bean_name = "aCase"; + + //add a references to bean_name if it doe not exist aleady. + if (!(class_exists($bean_name))) + { + + if (isset($GLOBALS['beanList']) && isset($GLOBALS['beanFiles'])) + { + global $beanFiles; + } + else + { + + } + $bean_file=$beanFiles[$bean_name]; + include_once($bean_file); + } + + $this->load_relationship($field_name); + + return $this->$field_name->getBeans(new $bean_name(), $sort_array, $begin_index, $end_index, $deleted, $optional_where); + } + + /** + * Returns an array of fields that are of type link. + * + * @return array List of fields. + * + * Internal function, do not override. + */ + function get_linked_fields() + { + + $linked_fields=array(); + + // require_once('data/Link.php'); + + $fieldDefs = $this->getFieldDefinitions(); + + //find all definitions of type link. + if (!empty($fieldDefs)) + { + foreach ($fieldDefs as $name=>$properties) + { + if (array_search('link',$properties) === 'type') + { + $linked_fields[$name]=$properties; + } + } + } + + return $linked_fields; + } + + /** + * Returns an array of fields that are able to be Imported into + * i.e. 'importable' not set to 'false' + * + * @return array List of fields. + * + * Internal function, do not override. + */ + function get_importable_fields() + { + $importableFields = array(); + + $fieldDefs= $this->getFieldDefinitions(); + + if (!empty($fieldDefs)) { + foreach ($fieldDefs as $key=>$value_array) { + if ( (isset($value_array['importable']) + && (is_string($value_array['importable']) && $value_array['importable'] == 'false' + || is_bool($value_array['importable']) && $value_array['importable'] == false)) + || (isset($value_array['type']) && $value_array['type'] == 'link') + || (isset($value_array['auto_increment']) + && ($value_array['type'] == true || $value_array['type'] == 'true')) ) { + // only allow import if we force it + if (isset($value_array['importable']) + && (is_string($value_array['importable']) && $value_array['importable'] == 'true' + || is_bool($value_array['importable']) && $value_array['importable'] == true)) { + $importableFields[$key]=$value_array; + } + } + else { + $importableFields[$key]=$value_array; + } + } + } + + return $importableFields; + } + + /** + * Returns an array of fields that are of type relate. + * + * @return array List of fields. + * + * Internal function, do not override. + */ + function get_related_fields() + { + + $related_fields=array(); + +// require_once('data/Link.php'); + + $fieldDefs = $this->getFieldDefinitions(); + + //find all definitions of type link. + if (!empty($fieldDefs)) + { + foreach ($fieldDefs as $name=>$properties) + { + if (array_search('relate',$properties) === 'type') + { + $related_fields[$name]=$properties; + } + } + } + + return $related_fields; + } + + /** + * Returns an array of fields that are required for import + * + * @return array + */ + function get_import_required_fields() + { + $importable_fields = $this->get_importable_fields(); + $required_fields = array(); + + foreach ( $importable_fields as $name => $properties ) { + if ( isset($properties['importable']) && is_string($properties['importable']) && $properties['importable'] == 'required' ) { + $required_fields[$name] = $properties; + } + } + + return $required_fields; + } + + /** + * Iterates through all the relationships and deletes all records for reach relationship. + * + * @param string $id Primary key value of the parent reocrd + */ + function delete_linked($id) + { + $linked_fields=$this->get_linked_fields(); + + foreach ($linked_fields as $name => $value) + { + if ($this->load_relationship($name)) + { + $GLOBALS['log']->debug('relationship loaded'); + $this->$name->delete($id); + } + else + { + $GLOBALS['log']->error('error loading relationship'); + } + } + } + + /** + * Creates tables for the module implementing the class. + * If you override this function make sure that your code can handles table creation. + * + */ + function create_tables() + { + global $dictionary; + + $key = $this->getObjectName(); + if (!array_key_exists($key, $dictionary)) + { + $GLOBALS['log']->fatal("create_tables: Metadata for table ".$this->table_name. " does not exist"); + display_notice("meta data absent for table ".$this->table_name." keyed to $key "); + } + else + { + if(!$this->db->tableExists($this->table_name)) + { + $this->dbManager->createTable($this); + if($this->bean_implements('ACL')){ + if(!empty($this->acltype)){ + ACLAction::addActions($this->getACLCategory(), $this->acltype); + }else{ + ACLAction::addActions($this->getACLCategory()); + } + } + } + else + { + echo "Table already exists : $this->table_name
"; + } + if($this->is_AuditEnabled()){ + if (!$this->db->tableExists($this->get_audit_table_name())) { + $this->create_audit_table(); + } + } + + } + } + + /** + * Delete the primary table for the module implementing the class. + * If custom fields were added to this table/module, the custom table will be removed too, along with the cache + * entries that define the custom fields. + * + */ + function drop_tables() + { + global $dictionary; + $key = $this->getObjectName(); + if (!array_key_exists($key, $dictionary)) + { + $GLOBALS['log']->fatal("drop_tables: Metadata for table ".$this->table_name. " does not exist"); + echo "meta data absent for table ".$this->table_name."
\n"; + } else { + if(empty($this->table_name))return; + if ($this->db->tableExists($this->table_name)) + + $this->dbManager->dropTable($this); + if ($this->db->tableExists($this->table_name. '_cstm')) + { + $this->dbManager->dropTableName($this->table_name. '_cstm'); + DynamicField::deleteCache(); + } + if ($this->db->tableExists($this->get_audit_table_name())) { + $this->dbManager->dropTableName($this->get_audit_table_name()); + } + + + } + } + + + /** + * Loads the definition of custom fields defined for the module. + * Local file system cache is created as needed. + * + * @param string $module_name setting up custom fields for this module. + * @param boolean $clean_load Optional, default true, rebuilds the cache if set to true. + */ + function setupCustomFields($module_name, $clean_load=true) + { + $this->custom_fields = new DynamicField($module_name); + $this->custom_fields->setup($this); + + } + + /** + * Cleans char, varchar, text, etc. fields of XSS type materials + */ + function cleanBean() { + foreach($this->field_defs as $key => $def) { + + if (isset($def['type'])) { + $type=$def['type']; + } + if(isset($def['dbType'])) + $type .= $def['dbType']; + + if((strpos($type, 'char') !== false || + strpos($type, 'text') !== false || + $type == 'enum') && + !empty($this->$key) + ) { + $str = from_html($this->$key); + // Julian's XSS cleaner + $potentials = clean_xss($str, false); + + if(is_array($potentials) && !empty($potentials)) { + foreach($potentials as $bad) { + $str = str_replace($bad, "", $str); + } + $this->$key = to_html($str); + } + } + } + } + + /** + * Implements a generic insert and update logic for any SugarBean + * This method only works for subclasses that implement the same variable names. + * This method uses the presence of an id field that is not null to signify and update. + * The id field should not be set otherwise. + * + * @param boolean $check_notify Optional, default false, if set to true assignee of the record is notified via email. + * @todo Add support for field type validation and encoding of parameters. + */ + function save($check_notify = FALSE) + { + // cn: SECURITY - strip XSS potential vectors + $this->cleanBean(); + // This is used so custom/3rd-party code can be upgraded with fewer issues, this will be removed in a future release + $this->fixUpFormatting(); + global $timedate; + global $current_user, $action; + + $isUpdate = true; + if(empty($this->id)) + { + $isUpdate = false; + } + + if ( $this->new_with_id == true ) + { + $isUpdate = false; + } + if(empty($this->date_modified) || $this->update_date_modified) + { + $this->date_modified = $GLOBALS['timedate']->nowDb(); + } + + $this->_checkOptimisticLocking($action, $isUpdate); + + if(!empty($this->modified_by_name)) $this->old_modified_by_name = $this->modified_by_name; + if($this->update_modified_by) + { + $this->modified_user_id = 1; + + if (!empty($current_user)) + { + $this->modified_user_id = $current_user->id; + $this->modified_by_name = $current_user->user_name; + } + } + if ($this->deleted != 1) + $this->deleted = 0; + if($isUpdate) + { + $query = "Update "; + } + else + { + if (empty($this->date_entered)) + { + $this->date_entered = $this->date_modified; + } + if($this->set_created_by == true) + { + // created by should always be this user + $this->created_by = (isset($current_user)) ? $current_user->id : ""; + } + if( $this->new_with_id == false) + { + $this->id = create_guid(); + } + $query = "INSERT into "; + } + if($isUpdate && !$this->update_date_entered) + { + unset($this->date_entered); + } + // call the custom business logic + $custom_logic_arguments['check_notify'] = $check_notify; + + + $this->call_custom_logic("before_save", $custom_logic_arguments); + unset($custom_logic_arguments); + + if(isset($this->custom_fields)) + { + $this->custom_fields->bean = $this; + $this->custom_fields->save($isUpdate); + } + + // use the db independent query generator + $this->preprocess_fields_on_save(); + + //construct the SQL to create the audit record if auditing is enabled. + $dataChanges=array(); + if ($this->is_AuditEnabled()) + { + if ($isUpdate && !isset($this->fetched_row)) + { + $GLOBALS['log']->debug('Auditing: Retrieve was not called, audit record will not be created.'); + } + else + { + $dataChanges=$this->dbManager->helper->getDataChanges($this); + } + } + + $this->_sendNotifications($check_notify); + + if ($this->db->dbType == "oci8") + { + } + if ($this->db->dbType == 'mysql') + { + // write out the SQL statement. + $query .= $this->table_name." set "; + + $firstPass = 0; + + foreach($this->field_defs as $field=>$value) + { + if(!isset($value['source']) || $value['source'] == 'db') + { + // Do not write out the id field on the update statement. + // We are not allowed to change ids. + if($isUpdate && ('id' == $field)) + continue; + //custom fields handle there save seperatley + if(isset($this->field_name_map) && !empty($this->field_name_map[$field]['custom_type'])) + continue; + + // Only assign variables that have been set. + if(isset($this->$field)) + { + //bug: 37908 - this is to handle the issue where the bool value is false, but strlen(false) <= so it will + //set the default value. TODO change this code to esend all fields through getFieldValue() like DbHelper->insertSql + if(!empty($value['type']) && $value['type'] == 'bool'){ + $this->$field = $this->getFieldValue($field); + } + + if(strlen($this->$field) <= 0) + { + if(!$isUpdate && isset($value['default']) && (strlen($value['default']) > 0)) + { + $this->$field = $value['default']; + } + else + { + $this->$field = null; + } + } + // Try comparing this element with the head element. + if(0 == $firstPass) + $firstPass = 1; + else + $query .= ", "; + + if(is_null($this->$field)) + { + $query .= $field."=null"; + } + else + { + //added check for ints because sql-server does not like casting varchar with a decimal value + //into an int. + if(isset($value['type']) and $value['type']=='int') { + $query .= $field."=".$this->db->quote($this->$field); + } elseif ( isset($value['len']) ) { + $query .= $field."='".$this->db->quote($this->db->truncate(from_html($this->$field),$value['len']))."'"; + } else { + $query .= $field."='".$this->db->quote($this->$field)."'"; + } + } + } + } + } + + if($isUpdate) + { + $query = $query." WHERE ID = '$this->id'"; + $GLOBALS['log']->info("Update $this->object_name: ".$query); + } + else + { + $GLOBALS['log']->info("Insert: ".$query); + } + $GLOBALS['log']->info("Save: $query"); + $this->db->query($query, true); + } + //process if type is set to mssql + if ($this->db->dbType == 'mssql') + { + if($isUpdate) + { + // build out the SQL UPDATE statement. + $query = "UPDATE " . $this->table_name." SET "; + $firstPass = 0; + foreach($this->field_defs as $field=>$value) + { + if(!isset($value['source']) || $value['source'] == 'db') + { + // Do not write out the id field on the update statement. + // We are not allowed to change ids. + if($isUpdate && ('id' == $field)) + continue; + + // If the field is an auto_increment field, then we shouldn't be setting it. This was added + // specially for Bugs and Cases which have a number associated with them. + if ($isUpdate && isset($this->field_name_map[$field]['auto_increment']) && + $this->field_name_map[$field]['auto_increment'] == true) + continue; + + //custom fields handle their save seperatley + if(isset($this->field_name_map) && !empty($this->field_name_map[$field]['custom_type'])) + continue; + + // Only assign variables that have been set. + if(isset($this->$field)) + { + //bug: 37908 - this is to handle the issue where the bool value is false, but strlen(false) <= so it will + //set the default value. TODO change this code to esend all fields through getFieldValue() like DbHelper->insertSql + if(!empty($value['type']) && $value['type'] == 'bool'){ + $this->$field = $this->getFieldValue($field); + } + + if(strlen($this->$field) <= 0) + { + if(!$isUpdate && isset($value['default']) && (strlen($value['default']) > 0)) + { + $this->$field = $value['default']; + } + else + { + $this->$field = null; + } + } + // Try comparing this element with the head element. + if(0 == $firstPass) + $firstPass = 1; + else + $query .= ", "; + + if(is_null($this->$field)) + { + $query .= $field."=null"; + } + elseif ( isset($value['len']) ) + { + $query .= $field."='".$this->db->quote($this->db->truncate(from_html($this->$field),$value['len']))."'"; + } + else + { + $query .= $field."='".$this->db->quote($this->$field)."'"; + } + } + } + } + $query = $query." WHERE ID = '$this->id'"; + $GLOBALS['log']->info("Update $this->object_name: ".$query); + } + else + { + $colums = array(); + $values = array(); + foreach($this->field_defs as $field=>$value) + { + if(!isset($value['source']) || $value['source'] == 'db') + { + // Do not write out the id field on the update statement. + // We are not allowed to change ids. + //if($isUpdate && ('id' == $field)) continue; + //custom fields handle there save seperatley + + if(isset($this->field_name_map) && !empty($this->field_name_map[$field]['custom_module'])) + continue; + + // Only assign variables that have been set. + if(isset($this->$field)) + { + //trim the value in case empty space is passed in. + //this will allow default values set in db to take effect, otherwise + //will insert blanks into db + $trimmed_field = trim($this->$field); + //if this value is empty, do not include the field value in statement + if($trimmed_field =='') + { + continue; + } + //bug: 37908 - this is to handle the issue where the bool value is false, but strlen(false) <= so it will + //set the default value. TODO change this code to esend all fields through getFieldValue() like DbHelper->insertSql + if(!empty($value['type']) && $value['type'] == 'bool'){ + $this->$field = $this->getFieldValue($field); + } + //added check for ints because sql-server does not like casting varchar with a decimal value + //into an int. + if(isset($value['type']) and $value['type']=='int') { + $values[] = $this->db->quote($this->$field); + } elseif ( isset($value['len']) ) { + $values[] = "'".$this->db->quote($this->db->truncate(from_html($this->$field),$value['len']))."'"; + } else { + $values[] = "'".$this->db->quote($this->$field)."'"; + + } + $columns[] = $field; + } + } + } + // build out the SQL INSERT statement. + $query = "INSERT INTO $this->table_name (" .implode("," , $columns). " ) VALUES ( ". implode("," , $values). ')'; + $GLOBALS['log']->info("Insert: ".$query); + } + + $GLOBALS['log']->info("Save: $query"); + $this->db->query($query, true); + } + if (!empty($dataChanges) && is_array($dataChanges)) + { + foreach ($dataChanges as $change) + { + $this->dbManager->helper->save_audit_records($this,$change); + } + } + + + // let subclasses save related field changes + $this->save_relationship_changes($isUpdate); + + //If we aren't in setup mode and we have a current user and module, then we track + if(isset($GLOBALS['current_user']) && isset($this->module_dir)) + { + $this->track_view($current_user->id, $this->module_dir, 'save'); + } + + $this->call_custom_logic('after_save', ''); + + return $this->id; + } + + + /** + * Performs a check if the record has been modified since the specified date + * + * @param date $date Datetime for verification + * @param string $modified_user_id User modified by + */ + function has_been_modified_since($date, $modified_user_id) + { + global $current_user; + if (isset($current_user)) + { + if ($this->db->dbType == 'mssql') + $date_modified_string = 'CONVERT(varchar(20), date_modified, 120)'; + else + $date_modified_string = 'date_modified'; + + $query = "SELECT date_modified FROM $this->table_name WHERE id='$this->id' AND modified_user_id != '$current_user->id' AND (modified_user_id != '$modified_user_id' OR $date_modified_string > " . db_convert("'".$date."'", 'datetime') . ')'; + $result = $this->db->query($query); + + if($this->db->fetchByAssoc($result)) + { + return true; + } + } + return false; + } + + /** + * Determines which users receive a notification + */ + function get_notification_recipients() { + $notify_user = new User(); + $notify_user->retrieve($this->assigned_user_id); + $this->new_assigned_user_name = $notify_user->full_name; + + $GLOBALS['log']->info("Notifications: recipient is $this->new_assigned_user_name"); + + $user_list = array($notify_user); + return $user_list; + /* + //send notifications to followers, but ensure to not query for the assigned_user. + return SugarFollowing::getFollowers($this, $notify_user); + */ + } + + /** + * Handles sending out email notifications when items are first assigned to users + * + * @param string $notify_user user to notify + * @param string $admin the admin user that sends out the notification + */ + function send_assignment_notifications($notify_user, $admin) + { + global $current_user; + + if(($this->object_name == 'Meeting' || $this->object_name == 'Call') || $notify_user->receive_notifications) + { + $sendToEmail = $notify_user->emailAddress->getPrimaryAddress($notify_user); + $sendEmail = TRUE; + if(empty($sendToEmail)) { + $GLOBALS['log']->warn("Notifications: no e-mail address set for user {$notify_user->user_name}, cancelling send"); + $sendEmail = FALSE; + } + + $notify_mail = $this->create_notification_email($notify_user); + $notify_mail->setMailerForSystem(); + + if(empty($admin->settings['notify_send_from_assigning_user'])) { + $notify_mail->From = $admin->settings['notify_fromaddress']; + $notify_mail->FromName = (empty($admin->settings['notify_fromname'])) ? "" : $admin->settings['notify_fromname']; + } else { + // Send notifications from the current user's e-mail (ifset) + $fromAddress = $current_user->emailAddress->getReplyToAddress($current_user); + $fromAddress = !empty($fromAddress) ? $fromAddress : $admin->settings['notify_fromaddress']; + $notify_mail->From = $fromAddress; + //Use the users full name is available otherwise default to system name + $from_name = !empty($admin->settings['notify_fromname']) ? $admin->settings['notify_fromname'] : ""; + $from_name = !empty($current_user->full_name) ? $current_user->full_name : $from_name; + $notify_mail->FromName = $from_name; + } + + if($sendEmail && !$notify_mail->Send()) { + $GLOBALS['log']->fatal("Notifications: error sending e-mail (method: {$notify_mail->Mailer}), (error: {$notify_mail->ErrorInfo})"); + } else { + $GLOBALS['log']->fatal("Notifications: e-mail successfully sent"); + } + + } + } + + /** + * This function handles create the email notifications email. + * @param string $notify_user the user to send the notification email to + */ + function create_notification_email($notify_user) { + global $sugar_version; + global $sugar_config; + global $app_list_strings; + global $current_user; + global $locale; + global $beanList; + $OBCharset = $locale->getPrecedentPreference('default_email_charset'); + + + require_once("include/SugarPHPMailer.php"); + + $notify_address = $notify_user->emailAddress->getPrimaryAddress($notify_user); + $notify_name = $notify_user->full_name; + $GLOBALS['log']->debug("Notifications: user has e-mail defined"); + + $notify_mail = new SugarPHPMailer(); + $notify_mail->AddAddress($notify_address,$locale->translateCharsetMIME(trim($notify_name), 'UTF-8', $OBCharset)); + + if(empty($_SESSION['authenticated_user_language'])) { + $current_language = $sugar_config['default_language']; + } else { + $current_language = $_SESSION['authenticated_user_language']; + } + $xtpl = new XTemplate(get_notify_template_file($current_language)); + if($this->module_dir == "Cases") { + $template_name = "Case"; //we should use Case, you can refer to the en_us.notify_template.html. + } + else { + $template_name = $beanList[$this->module_dir]; //bug 20637, in workflow this->object_name = strange chars. + } + + $this->current_notify_user = $notify_user; + + if(in_array('set_notification_body', get_class_methods($this))) { + $xtpl = $this->set_notification_body($xtpl, $this); + } else { + $xtpl->assign("OBJECT", $this->object_name); + $template_name = "Default"; + } + if(!empty($_SESSION["special_notification"]) && $_SESSION["special_notification"]) { + $template_name = $beanList[$this->module_dir].'Special'; + } + if($this->special_notification) { + $template_name = $beanList[$this->module_dir].'Special'; + } + $xtpl->assign("ASSIGNED_USER", $this->new_assigned_user_name); + $xtpl->assign("ASSIGNER", $current_user->name); + $port = ''; + + if(isset($_SERVER['SERVER_PORT']) && $_SERVER['SERVER_PORT'] != 80 && $_SERVER['SERVER_PORT'] != 443) { + $port = $_SERVER['SERVER_PORT']; + } + + if (!isset($_SERVER['HTTP_HOST'])) { + $_SERVER['HTTP_HOST'] = ''; + } + + $httpHost = $_SERVER['HTTP_HOST']; + + if($colon = strpos($httpHost, ':')) { + $httpHost = substr($httpHost, 0, $colon); + } + + $parsedSiteUrl = parse_url($sugar_config['site_url']); + $host = $parsedSiteUrl['host']; + if(!isset($parsedSiteUrl['port'])) { + $parsedSiteUrl['port'] = 80; + } + + $port = ($parsedSiteUrl['port'] != 80) ? ":".$parsedSiteUrl['port'] : ''; + $path = !empty($parsedSiteUrl['path']) ? $parsedSiteUrl['path'] : ""; + $cleanUrl = "{$parsedSiteUrl['scheme']}://{$host}{$port}{$path}"; + + $xtpl->assign("URL", $cleanUrl."/index.php?module={$this->module_dir}&action=DetailView&record={$this->id}"); + $xtpl->assign("SUGAR", "Sugar v{$sugar_version}"); + $xtpl->parse($template_name); + $xtpl->parse($template_name . "_Subject"); + + $notify_mail->Body = from_html(trim($xtpl->text($template_name))); + $notify_mail->Subject = from_html($xtpl->text($template_name . "_Subject")); + + // cn: bug 8568 encode notify email in User's outbound email encoding + $notify_mail->prepForOutbound(); + + return $notify_mail; + } + + /** + * This function is a good location to save changes that have been made to a relationship. + * This should be overriden in subclasses that have something to save. + * + * @param $is_update true if this save is an update. + */ +function save_relationship_changes($is_update, $exclude=array()) + { + $new_rel_id = false; + $new_rel_link = false; + //this allows us to dynamically relate modules without adding it to the relationship_fields array + if(!empty($_REQUEST['relate_id']) && !in_array($_REQUEST['relate_to'], $exclude) && $_REQUEST['relate_id'] != $this->id){ + $new_rel_id = $_REQUEST['relate_id']; + $new_rel_relname = $_REQUEST['relate_to']; + if(!empty($this->in_workflow) && !empty($this->not_use_rel_in_req)) { + $new_rel_id = $this->new_rel_id; + $new_rel_relname = $this->new_rel_relname; + } + $new_rel_link = $new_rel_relname; + //Try to find the link in this bean based on the relationship + foreach ( $this->field_defs as $key => $def ) { + if (isset($def['type']) && $def['type'] == 'link' + && isset($def['relationship']) && $def['relationship'] == $new_rel_relname) { + $new_rel_link = $key; + } + } + } + + // First we handle the preset fields listed in the fixed relationship_fields array hardcoded into the OOB beans + // TODO: remove this mechanism and replace with mechanism exclusively based on the vardefs + if (isset($this->relationship_fields) && is_array($this->relationship_fields)) + { + foreach ($this->relationship_fields as $id=>$rel_name) + { + + if(in_array($id, $exclude))continue; + + if(!empty($this->$id)) + { + $GLOBALS['log']->debug('save_relationship_changes(): From relationship_field array - adding a relationship record: '.$rel_name . ' = ' . $this->$id); + //already related the new relationship id so let's set it to false so we don't add it again using the _REQUEST['relate_i'] mechanism in a later block + if($this->$id == $new_rel_id){ + $new_rel_id = false; + } + $this->load_relationship($rel_name); + $this->$rel_name->add($this->$id); + $related = true; + } + else + { + //if before value is not empty then attempt to delete relationship + if(!empty($this->rel_fields_before_value[$id])) + { + $GLOBALS['log']->debug('save_relationship_changes(): From relationship_field array - attempting to remove the relationship record, using relationship attribute'.$rel_name); + $this->load_relationship($rel_name); + $this->$rel_name->delete($this->id,$this->rel_fields_before_value[$id]); + } + } + } + } + +/* Next, we'll attempt to update all of the remaining relate fields in the vardefs that have 'save' set in their field_def + Only the 'save' fields should be saved as some vardef entries today are not for display only purposes and break the application if saved + If the vardef has entries for field of type relate, where a->id_name = and field of type link + then we receive a value for b from the MVC in the _REQUEST, and it should be set in the bean as $this->$b +*/ + + foreach ( $this->field_defs as $def ) + { + if ($def [ 'type' ] == 'relate' && isset ( $def [ 'id_name'] ) && isset ( $def [ 'link'] ) && isset ( $def[ 'save' ]) ) + { + if ( in_array( $def['id_name'], $exclude) || in_array( $def['id_name'], $this->relationship_fields ) ) + continue ; // continue to honor the exclude array and exclude any relationships that will be handled by the relationship_fields mechanism + + if (isset( $this->field_defs[ $def [ 'link' ] ] )) + { + + $linkfield = $this->field_defs[$def [ 'link' ]] ; + + if ($this->load_relationship ( $def [ 'link' ])){ + if (!empty($this->rel_fields_before_value[$def [ 'id_name' ]])) + { + //if before value is not empty then attempt to delete relationship + $GLOBALS['log']->debug("save_relationship_changes(): From field_defs - attempting to remove the relationship record: {$def [ 'link' ]} = {$this->rel_fields_before_value[$def [ 'id_name' ]]}"); + $this->$def ['link' ]->delete($this->id, $this->rel_fields_before_value[$def [ 'id_name' ]] ); + } + if (!empty($this->$def['id_name']) && is_string($this->$def['id_name'])) + { + $GLOBALS['log']->debug("save_relationship_changes(): From field_defs - attempting to add a relationship record - {$def [ 'link' ]} = {$this->$def [ 'id_name' ]}" ); + $this->$def ['link' ]->add($this->$def['id_name']); + } + } else { + $GLOBALS['log']->fatal("Failed to load relationship {$def [ 'link' ]} while saving {$this->module_dir}"); + } + } + } + } + + // Finally, we update a field listed in the _REQUEST['*/relate_id']/_REQUEST['relate_to'] mechanism (if it hasn't already been updated above) + if(!empty($new_rel_id)){ + + if($this->load_relationship($new_rel_link)){ + $this->$new_rel_link->add($new_rel_id); + + }else{ + $lower_link = strtolower($new_rel_link); + if($this->load_relationship($lower_link)){ + $this->$lower_link->add($new_rel_id); + + }else{ + require_once('data/Link.php'); + $rel = Relationship::retrieve_by_modules($new_rel_link, $this->module_dir, $GLOBALS['db'], 'many-to-many'); + + if(!empty($rel)){ + foreach($this->field_defs as $field=>$def){ + if($def['type'] == 'link' && !empty($def['relationship']) && $def['relationship'] == $rel){ + $this->load_relationship($field); + $this->$field->add($new_rel_id); + return; + + } + + } + //ok so we didn't find it in the field defs let's save it anyway if we have the relationshp + + $this->$rel=new Link($rel, $this, array()); + $this->$rel->add($new_rel_id); + } + } + + } + + } + + } + + /** + * This function retrieves a record of the appropriate type from the DB. + * It fills in all of the fields from the DB into the object it was called on. + * + * @param $id - If ID is specified, it overrides the current value of $this->id. If not specified the current value of $this->id will be used. + * @return this - The object that it was called apon or null if exactly 1 record was not found. + * + */ + + function check_date_relationships_load() + { + global $disable_date_format; + global $timedate; + if (empty($timedate)) + $timedate=TimeDate::getInstance(); + + if(empty($this->field_defs)) + { + return; + } + foreach($this->field_defs as $fieldDef) + { + $field = $fieldDef['name']; + if(!isset($this->processed_dates_times[$field])) + { + $this->processed_dates_times[$field] = '1'; + if(empty($this->$field)) continue; + if($field == 'date_modified' || $field == 'date_entered') + { + $this->$field = from_db_convert($this->$field, 'datetime'); + if(empty($disable_date_format)) { + $this->$field = $timedate->to_display_date_time($this->$field); + } + } + elseif(isset($this->field_name_map[$field]['type'])) + { + $type = $this->field_name_map[$field]['type']; + + if($type == 'relate' && isset($this->field_name_map[$field]['custom_module'])) + { + $type = $this->field_name_map[$field]['type']; + } + + if($type == 'date') + { + $this->$field = from_db_convert($this->$field, 'date'); + + if($this->$field == '0000-00-00') + { + $this->$field = ''; + } elseif(!empty($this->field_name_map[$field]['rel_field'])) + { + $rel_field = $this->field_name_map[$field]['rel_field']; + + if(!empty($this->$rel_field)) + { + $this->$rel_field=from_db_convert($this->$rel_field, 'time'); + if(empty($disable_date_format)) { + $mergetime = $timedate->merge_date_time($this->$field,$this->$rel_field); + $this->$field = $timedate->to_display_date($mergetime); + $this->$rel_field = $timedate->to_display_time($mergetime); + } + } + } + else + { + if(empty($disable_date_format)) { + $this->$field = $timedate->to_display_date($this->$field, false); + } + } + } elseif($type == 'datetime' || $type == 'datetimecombo') + { + if($this->$field == '0000-00-00 00:00:00') + { + $this->$field = ''; + } + else + { + $this->$field = from_db_convert($this->$field, 'datetime'); + if(empty($disable_date_format)) { + $this->$field = $timedate->to_display_date_time($this->$field, true, true); + } + } + } elseif($type == 'time') + { + if($this->$field == '00:00:00') + { + $this->$field = ''; + } else + { + //$this->$field = from_db_convert($this->$field, 'time'); + if(empty($this->field_name_map[$field]['rel_field']) && empty($disable_date_format)) + { + $this->$field = $timedate->to_display_time($this->$field,true, false); + } + } + } elseif($type == 'encrypt' && empty($disable_date_format)){ + $this->$field = $this->decrypt_after_retrieve($this->$field); + } + } + } + } + } + + /** + * This function processes the fields before save. + * Interal function, do not override. + */ + function preprocess_fields_on_save() + { + $GLOBALS['log']->deprecated('SugarBean.php: preprocess_fields_on_save() is deprecated'); + } + + /** + * Removes formatting from values posted from the user interface. + * It only unformats numbers. Function relies on user/system prefernce for format strings. + * + * Internal Function, do not override. + */ + function unformat_all_fields() + { + $GLOBALS['log']->deprecated('SugarBean.php: unformat_all_fields() is deprecated'); + } + + /** + * This functions adds formatting to all number fields before presenting them to user interface. + * + * Internal function, do not override. + */ + function format_all_fields() + { + $GLOBALS['log']->deprecated('SugarBean.php: format_all_fields() is deprecated'); + } + + function format_field($fieldDef) + { + $GLOBALS['log']->deprecated('SugarBean.php: format_field() is deprecated'); + } + + /** + * Function corrects any bad formatting done by 3rd party/custom code + * + * This function will be removed in a future release, it is only here to assist upgrading existing code that expects formatted data in the bean + */ + function fixUpFormatting() + { + global $timedate; + static $boolean_false_values = array('off', 'false', '0', 'no'); + + + foreach($this->field_defs as $field=>$def) + { + if ( !isset($this->$field) ) { + continue; + } + if ( (isset($def['source'])&&$def['source']=='non-db') || $field == 'deleted' ) { + continue; + } + if ( isset($this->fetched_row[$field]) && $this->$field == $this->fetched_row[$field] ) { + // Don't hand out warnings because the field was untouched between retrieval and saving, most database drivers hand pretty much everything back as strings. + continue; + } + $reformatted = false; + switch($def['type']) { + case 'datetime': + case 'datetimecombo': + if(empty($this->$field)) break; + if ( ! preg_match('/^[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}$/',$this->$field) ) { + // This appears to be formatted in user date/time + $this->$field = $timedate->to_db($this->$field); + $reformatted = true; + } + break; + case 'date': + if(empty($this->$field)) break; + if ( ! preg_match('/^[0-9]{4}-[0-9]{2}-[0-9]{2}$/',$this->$field) ) { + // This date appears to be formatted in the user's format + $this->$field = $timedate->to_db_date($this->$field, false); + $reformatted = true; + } + break; + case 'time': + if(empty($this->$field)) break; + if ( preg_match('/(am|pm)/i',$this->$field) ) { + // This time appears to be formatted in the user's format + $this->$field = $timedate->asDbTime($timedate->fromUserTime($this->$field)); + $reformatted = true; + } + break; + case 'double': + case 'decimal': + case 'currency': + case 'float': + if ( $this->$field === '' || $this->$field == NULL || $this->$field == 'NULL') { + continue; + } + if ( is_string($this->$field) ) { + $this->$field = (float)unformat_number($this->$field); + $reformatted = true; + } + break; + case 'uint': + case 'ulong': + case 'long': + case 'short': + case 'tinyint': + case 'int': + if ( $this->$field === '' || $this->$field == NULL || $this->$field == 'NULL') { + continue; + } + if ( is_string($this->$field) ) { + $this->$field = (int)unformat_number($this->$field); + $reformatted = true; + } + break; + case 'bool': + if (empty($this->$field)) { + $this->$field = false; + } else if(true === $this->$field || 1 == $this->$field) { + $this->$field = true; + } else if(in_array(strval($this->$field), $boolean_false_values)) { + $this->$field = false; + $reformatted = true; + } else { + $this->$field = true; + $reformatted = true; + } + break; + case 'encrypt': + $this->$field = $this->encrpyt_before_save($this->$field); + break; + } + if ( $reformatted ) { + $GLOBALS['log']->deprecated('Formatting correction: '.$this->module_dir.'->'.$field.' had formatting automatically corrected. This will be removed in the future, please upgrade your external code'); + } + } + + } + + /** + * Function fetches a single row of data given the primary key value. + * + * The fetched data is then set into the bean. The function also processes the fetched data by formattig + * date/time and numeric values. + * + * @param string $id Optional, default -1, is set to -1 id value from the bean is used, else, passed value is used + * @param boolean $encode Optional, default true, encodes the values fetched from the database. + * @param boolean $deleted Optional, default true, if set to false deleted filter will not be added. + * + * Internal function, do not override. + */ + function retrieve($id = -1, $encode=true,$deleted=true) + { + + $custom_logic_arguments['id'] = $id; + $this->call_custom_logic('before_retrieve', $custom_logic_arguments); + + if ($id == -1) + { + $id = $this->id; + } + if(isset($this->custom_fields)) + { + $custom_join = $this->custom_fields->getJOIN(); + } + else + $custom_join = false; + + if($custom_join) + { + $query = "SELECT $this->table_name.*". $custom_join['select']. " FROM $this->table_name "; + } + else + { + $query = "SELECT $this->table_name.* FROM $this->table_name "; + } + + if($custom_join) + { + $query .= ' ' . $custom_join['join']; + } + $query .= " WHERE $this->table_name.id = '$id' "; + if ($deleted) $query .= " AND $this->table_name.deleted=0"; + $GLOBALS['log']->debug("Retrieve $this->object_name : ".$query); + //requireSingleResult has beeen deprecated. + //$result = $this->db->requireSingleResult($query, true, "Retrieving record by id $this->table_name:$id found "); + $result = $this->db->limitQuery($query,0,1,true, "Retrieving record by id $this->table_name:$id found "); + if(empty($result)) + { + return null; + } + + $row = $this->db->fetchByAssoc($result, -1, $encode); + if(empty($row)) + { + return null; + } + + //make copy of the fetched row for construction of audit record and for business logic/workflow + $this->fetched_row=$row; + $this->populateFromRow($row); + + global $module, $action; + //Just to get optimistic locking working for this release + if($this->optimistic_lock && $module == $this->module_dir && $action =='EditView' ) + { + $_SESSION['o_lock_id']= $id; + $_SESSION['o_lock_dm']= $this->date_modified; + $_SESSION['o_lock_on'] = $this->object_name; + } + $this->processed_dates_times = array(); + $this->check_date_relationships_load(); + + if($custom_join) + { + $this->custom_fields->fill_relationships(); + } + + $this->fill_in_additional_detail_fields(); + $this->fill_in_relationship_fields(); + //make a copy of fields in the relatiosnhip_fields array. these field values will be used to + //clear relatioship. + foreach ( $this->field_defs as $key => $def ) + { + if ($def [ 'type' ] == 'relate' && isset ( $def [ 'id_name'] ) && isset ( $def [ 'link'] ) && isset ( $def[ 'save' ])) { + if (isset($this->$key)) { + $this->rel_fields_before_value[$key]=$this->$key; + if (isset($this->$def [ 'id_name'])) + $this->rel_fields_before_value[$def [ 'id_name']]=$this->$def [ 'id_name']; + } + else + $this->rel_fields_before_value[$key]=null; + } + } + if (isset($this->relationship_fields) && is_array($this->relationship_fields)) + { + foreach ($this->relationship_fields as $rel_id=>$rel_name) + { + if (isset($this->$rel_id)) + $this->rel_fields_before_value[$rel_id]=$this->$rel_id; + else + $this->rel_fields_before_value[$rel_id]=null; + } + } + + // call the custom business logic + $custom_logic_arguments['id'] = $id; + $custom_logic_arguments['encode'] = $encode; + $this->call_custom_logic("after_retrieve", $custom_logic_arguments); + unset($custom_logic_arguments); + return $this; + } + + /** + * Sets value from fetched row into the bean. + * + * @param array $row Fetched row + * @todo loop through vardefs instead + * @internal runs into an issue when populating from field_defs for users - corrupts user prefs + * + * Internal function, do not override. + */ + function populateFromRow($row) + { + $nullvalue=''; + foreach($this->field_defs as $field=>$field_value) + { + if($field == 'user_preferences' && $this->module_dir == 'Users') + continue; + $rfield = $field; // fetch returns it in lowercase only + if(isset($row[$rfield])) + { + $this->$field = $row[$rfield]; + $owner = $rfield . '_owner'; + if(!empty($row[$owner])){ + $this->$owner = $row[$owner]; + } + } + else + { + $this->$field = $nullvalue; + } + } + } + + + + /** + * Add any required joins to the list count query. The joins are required if there + * is a field in the $where clause that needs to be joined. + * + * @param string $query + * @param string $where + * + * Internal Function, do Not override. + */ + function add_list_count_joins(&$query, $where) + { + $custom_join = $this->custom_fields->getJOIN(); + if($custom_join) + { + $query .= $custom_join['join']; + } + + } + + /** + * Changes the select expression of the given query to be 'count(*)' so you + * can get the number of items the query will return. This is used to + * populate the upper limit on ListViews. + * + * @param string $query Select query string + * @return string count query + * + * Internal function, do not override. + */ + function create_list_count_query($query) + { + // remove the 'order by' clause which is expected to be at the end of the query + $pattern = '/\sORDER BY.*/is'; // ignores the case + $replacement = ''; + $query = preg_replace($pattern, $replacement, $query); + //handle distinct clause + $star = '*'; + if(substr_count(strtolower($query), 'distinct')){ + if (!empty($this->seed) && !empty($this->seed->table_name )) + $star = 'DISTINCT ' . $this->seed->table_name . '.id'; + else + $star = 'DISTINCT ' . $this->table_name . '.id'; + + } + + // change the select expression to 'count(*)' + $pattern = '/SELECT(.*?)(\s){1}FROM(\s){1}/is'; // ignores the case + $replacement = 'SELECT count(' . $star . ') c FROM '; + + //if the passed query has union clause then replace all instances of the pattern. + //this is very rare. I have seen this happening only from projects module. + //in addition to this added a condition that has union clause and uses + //sub-selects. + if (strstr($query," UNION ALL ") !== false) { + + //seperate out all the queries. + $union_qs=explode(" UNION ALL ", $query); + foreach ($union_qs as $key=>$union_query) { + $star = '*'; + preg_match($pattern, $union_query, $matches); + if (!empty($matches)) { + if (stristr($matches[0], "distinct")) { + if (!empty($this->seed) && !empty($this->seed->table_name )) + $star = 'DISTINCT ' . $this->seed->table_name . '.id'; + else + $star = 'DISTINCT ' . $this->table_name . '.id'; + } + } // if + $replacement = 'SELECT count(' . $star . ') c FROM '; + $union_qs[$key] = preg_replace($pattern, $replacement, $union_query,1); + } + $modified_select_query=implode(" UNION ALL ",$union_qs); + } else { + $modified_select_query = preg_replace($pattern, $replacement, $query,1); + } + + return $modified_select_query; + } + + /** + * This function returns a paged list of the current object type. It is intended to allow for + * hopping back and forth through pages of data. It only retrieves what is on the current page. + * + * @internal This method must be called on a new instance. It trashes the values of all the fields in the current one. + * @param string $order_by + * @param string $where Additional where clause + * @param int $row_offset Optaional,default 0, starting row number + * @param init $limit Optional, default -1 + * @param int $max Optional, default -1 + * @param boolean $show_deleted Optioanl, default 0, if set to 1 system will show deleted records. + * @return array Fetched data. + * + * Internal function, do not override. + * + */ + function get_list($order_by = "", $where = "", $row_offset = 0, $limit=-1, $max=-1, $show_deleted = 0, $singleSelect=false) + { + $GLOBALS['log']->debug("get_list: order_by = '$order_by' and where = '$where' and limit = '$limit'"); + if(isset($_SESSION['show_deleted'])) + { + $show_deleted = 1; + } + $order_by=$this->process_order_by($order_by, null); + + if($this->bean_implements('ACL') && ACLController::requireOwner($this->module_dir, 'list') ) + { + global $current_user; + $owner_where = $this->getOwnerWhere($current_user->id); + + //rrs - because $this->getOwnerWhere() can return '' we need to be sure to check for it and + //handle it properly else you could get into a situation where you are create a where stmt like + //WHERE .. AND '' + if(!empty($owner_where)){ + if(empty($where)){ + $where = $owner_where; + }else{ + $where .= ' AND '. $owner_where; + } + } + } + $query = $this->create_new_list_query($order_by, $where,array(),array(), $show_deleted,'',false,null,$singleSelect); + return $this->process_list_query($query, $row_offset, $limit, $max, $where); + } + + /** + * Prefixes column names with this bean's table name. + * This call can be ignored for mysql since it does a better job than Oracle in resolving ambiguity. + * + * @param string $order_by Order by clause to be processed + * @param string $submodule name of the module this order by clause is for + * @return string Processed order by clause + * + * Internal function, do not override. + */ + function process_order_by ($order_by, $submodule) + { + if (empty($order_by)) + return $order_by; + $bean_queried = ""; + //submodule is empty,this is for list object in focus + if (empty($submodule)) + { + $bean_queried = &$this; + } + else + { + //submodule is set, so this is for subpanel, use submodule + $bean_queried = $submodule; + } + $elements = explode(',',$order_by); + foreach ($elements as $key=>$value) + { + if (strchr($value,'.') === false) + { + //value might have ascending and descending decorations + $list_column = explode(' ',trim($value)); + if (isset($list_column[0])) + { + $list_column_name=trim($list_column[0]); + if (isset($bean_queried->field_defs[$list_column_name])) + { + $source=isset($bean_queried->field_defs[$list_column_name]['source']) ? $bean_queried->field_defs[$list_column_name]['source']:'db'; + if (empty($bean_queried->field_defs[$list_column_name]['table']) && $source=='db') + { + $list_column[0] = $bean_queried->table_name .".".$list_column[0] ; + } + if (empty($bean_queried->field_defs[$list_column_name]['table']) && $source=='custom_fields') + { + $list_column[0] = $bean_queried->table_name ."_cstm.".$list_column[0] ; + } + $value = implode($list_column,' '); + // Bug 38803 - Use CONVERT() function when doing an order by on ntext, text, and image fields + if ( $this->db->dbType == 'mssql' + && $source != 'non-db' + && in_array( + $this->db->getHelper()->getColumnType($this->db->getHelper()->getFieldType($bean_queried->field_defs[$list_column_name])), + array('ntext','text','image') + ) + ) { + $value = "CONVERT(varchar(500),{$list_column[0]}) {$list_column[1]}"; + } + // Bug 29011 - Use TO_CHAR() function when doing an order by on a clob field + if ( $this->db->dbType == 'oci8' + && $source != 'non-db' + && in_array( + $this->db->getHelper()->getColumnType($this->db->getHelper()->getFieldType($bean_queried->field_defs[$list_column_name])), + array('clob') + ) + ) { + $value = "TO_CHAR({$list_column[0]}) {$list_column[1]}"; + } + } + else + { + $GLOBALS['log']->debug("process_order_by: ($list_column[0]) does not have a vardef entry."); + } + } + } + $elements[$key]=$value; + } + return implode($elements,','); + + } + + + /** + * Returns a detail object like retrieving of the current object type. + * + * It is intended for use in navigation buttons on the DetailView. It will pass an offset and limit argument to the sql query. + * @internal This method must be called on a new instance. It overrides the values of all the fields in the current one. + * + * @param string $order_by + * @param string $where Additional where clause + * @param int $row_offset Optaional,default 0, starting row number + * @param init $limit Optional, default -1 + * @param int $max Optional, default -1 + * @param boolean $show_deleted Optioanl, default 0, if set to 1 system will show deleted records. + * @return array Fetched data. + * + * Internal function, do not override. + */ + function get_detail($order_by = "", $where = "", $offset = 0, $row_offset = 0, $limit=-1, $max=-1, $show_deleted = 0) + { + $GLOBALS['log']->debug("get_detail: order_by = '$order_by' and where = '$where' and limit = '$limit' and offset = '$offset'"); + if(isset($_SESSION['show_deleted'])) + { + $show_deleted = 1; + } + + if($this->bean_implements('ACL') && ACLController::requireOwner($this->module_dir, 'list') ) + { + global $current_user; + $owner_where = $this->getOwnerWhere($current_user->id); + + if(empty($where)) + { + $where = $owner_where; + } + else + { + $where .= ' AND '. $owner_where; + } + } + $query = $this->create_new_list_query($order_by, $where,array(),array(), $show_deleted, $offset); + + //Add Limit and Offset to query + //$query .= " LIMIT 1 OFFSET $offset"; + + return $this->process_detail_query($query, $row_offset, $limit, $max, $where, $offset); + } + + /** + * Fetches data from all related tables. + * + * @param object $child_seed + * @param string $related_field_name relation to fetch data for + * @param string $order_by Optional, default empty + * @param string $where Optional, additional where clause + * @return array Fetched data. + * + * Internal function, do not override. + */ + function get_related_list($child_seed,$related_field_name, $order_by = "", $where = "", + $row_offset = 0, $limit=-1, $max=-1, $show_deleted = 0) + { + global $layout_edit_mode; + if(isset($layout_edit_mode) && $layout_edit_mode) + { + $response = array(); + $child_seed->assign_display_fields($child_seed->module_dir); + $response['list'] = array($child_seed); + $response['row_count'] = 1; + $response['next_offset'] = 0; + $response['previous_offset'] = 0; + + return $response; + } + $GLOBALS['log']->debug("get_related_list: order_by = '$order_by' and where = '$where' and limit = '$limit'"); + if(isset($_SESSION['show_deleted'])) + { + $show_deleted = 1; + } + + $this->load_relationship($related_field_name); + $query_array = $this->$related_field_name->getQuery(true); + $entire_where = $query_array['where']; + if(!empty($where)) + { + if(empty($entire_where)) + { + $entire_where = ' WHERE ' . $where; + } + else + { + $entire_where .= ' AND ' . $where; + } + } + + $query = 'SELECT '.$child_seed->table_name.'.* ' . $query_array['from'] . ' ' . $entire_where; + if(!empty($order_by)) + { + $query .= " ORDER BY " . $order_by; + } + + return $child_seed->process_list_query($query, $row_offset, $limit, $max, $where); + } + + + protected static function build_sub_queries_for_union($subpanel_list, $subpanel_def, $parentbean, $order_by) + { + global $layout_edit_mode, $beanFiles, $beanList; + $subqueries = array(); + foreach($subpanel_list as $this_subpanel) + { + if(!$this_subpanel->isDatasourceFunction() || ($this_subpanel->isDatasourceFunction() + && isset($this_subpanel->_instance_properties['generate_select']) + && $this_subpanel->_instance_properties['generate_select']==true)) + { + //the custom query function must return an array with + if ($this_subpanel->isDatasourceFunction()) { + $shortcut_function_name = $this_subpanel->get_data_source_name(); + $parameters=$this_subpanel->get_function_parameters(); + if (!empty($parameters)) + { + //if the import file function is set, then import the file to call the custom function from + if (is_array($parameters) && isset($parameters['import_function_file'])){ + //this call may happen multiple times, so only require if function does not exist + if(!function_exists($shortcut_function_name)){ + require_once($parameters['import_function_file']); + } + //call function from required file + $query_array = $shortcut_function_name($parameters); + }else{ + //call function from parent bean + $query_array = $parentbean->$shortcut_function_name($parameters); + } + } + else + { + $query_array = $parentbean->$shortcut_function_name(); + } + } else { + $related_field_name = $this_subpanel->get_data_source_name(); + if (!$parentbean->load_relationship($related_field_name)){ + unset ($parentbean->$related_field_name); + continue; + } + $query_array = $parentbean->$related_field_name->getQuery(true,array(),0,'',true, null, null, true); + } + $table_where = $this_subpanel->get_where(); + $where_definition = $query_array['where']; + + if(!empty($table_where)) + { + if(empty($where_definition)) + { + $where_definition = $table_where; + } + else + { + $where_definition .= ' AND ' . $table_where; + } + } + + $submodulename = $this_subpanel->_instance_properties['module']; + $submoduleclass = $beanList[$submodulename]; + //require_once($beanFiles[$submoduleclass]); + $submodule = new $submoduleclass(); + $subwhere = $where_definition; + + + + $subwhere = str_replace('WHERE', '', $subwhere); + $list_fields = $this_subpanel->get_list_fields(); + foreach($list_fields as $list_key=>$list_field) + { + if(isset($list_field['usage']) && $list_field['usage'] == 'display_only') + { + unset($list_fields[$list_key]); + } + } + if(!$subpanel_def->isCollection() && isset($list_fields[$order_by]) && isset($submodule->field_defs[$order_by])&& (!isset($submodule->field_defs[$order_by]['source']) || $submodule->field_defs[$order_by]['source'] == 'db')) + { + $order_by = $submodule->table_name .'.'. $order_by; + } + $table_name = $this_subpanel->table_name; + $panel_name=$this_subpanel->name; + $params = array(); + $params['distinct'] = $this_subpanel->distinct_query(); + + $params['joined_tables'] = $query_array['join_tables']; + $params['include_custom_fields'] = !$subpanel_def->isCollection(); + $params['collection_list'] = $subpanel_def->get_inst_prop_value('collection_list'); + + $subquery = $submodule->create_new_list_query('',$subwhere ,$list_fields,$params, 0,'', true,$parentbean); + + $subquery['select'] = $subquery['select']." , '$panel_name' panel_name "; + $subquery['from'] = $subquery['from'].$query_array['join']; + $subquery['query_array'] = $query_array; + $subquery['params'] = $params; + + $subqueries[] = $subquery; + } + } + return $subqueries; + } + + /** + * Constructs a query to fetch data for supanels and list views + * + * It constructs union queries for activities subpanel. + * + * @param Object $parentbean constructing queries for link attributes in this bean + * @param string $order_by Optional, order by clause + * @param string $sort_order Optional, sort order + * @param string $where Optional, additional where clause + * + * Internal Function, do not overide. + */ + function get_union_related_list($parentbean, $order_by = "", $sort_order='', $where = "", + $row_offset = 0, $limit=-1, $max=-1, $show_deleted = 0, $subpanel_def) + { + $secondary_queries = array(); + global $layout_edit_mode, $beanFiles, $beanList; + + if(isset($_SESSION['show_deleted'])) + { + $show_deleted = 1; + } + $final_query = ''; + $final_query_rows = ''; + $subpanel_list=array(); + if ($subpanel_def->isCollection()) + { + $subpanel_def->load_sub_subpanels(); + $subpanel_list=$subpanel_def->sub_subpanels; + } + else + { + $subpanel_list[]=$subpanel_def; + } + + $first = true; + + //Breaking the building process into two loops. The first loop gets a list of all the sub-queries. + //The second loop merges the queries and forces them to select the same number of columns + //All columns in a sub-subpanel group must have the same aliases + //If the subpanel is a datasource function, it can't be a collection so we just poll that function for the and return that + foreach($subpanel_list as $this_subpanel) + { + if($this_subpanel->isDatasourceFunction() && empty($this_subpanel->_instance_properties['generate_select'])) + { + $shortcut_function_name = $this_subpanel->get_data_source_name(); + $parameters=$this_subpanel->get_function_parameters(); + if (!empty($parameters)) + { + //if the import file function is set, then import the file to call the custom function from + if (is_array($parameters) && isset($parameters['import_function_file'])){ + //this call may happen multiple times, so only require if function does not exist + if(!function_exists($shortcut_function_name)){ + require_once($parameters['import_function_file']); + } + //call function from required file + $tmp_final_query = $shortcut_function_name($parameters); + }else{ + //call function from parent bean + $tmp_final_query = $parentbean->$shortcut_function_name($parameters); + } + } + else + { + $tmp_final_query = $parentbean->$shortcut_function_name(); + } + if(!$first) + { + $final_query_rows .= ' UNION ALL ( '.$parentbean->create_list_count_query($tmp_final_query, $parameters) . ' )'; + $final_query .= ' UNION ALL ( '.$tmp_final_query . ' )'; + } else { + $final_query_rows = '(' . $parentbean->create_list_count_query($tmp_final_query, $parameters) . ')'; + $final_query = '(' . $tmp_final_query . ')'; + $first = false; + } + } + } + //If final_query is still empty, its time to build the sub-queries + if (empty($final_query)) + { + $subqueries = SugarBean::build_sub_queries_for_union($subpanel_list, $subpanel_def, $parentbean, $order_by); + $all_fields = array(); + foreach($subqueries as $i => $subquery) + { + $query_fields = $GLOBALS['db']->helper->getSelectFieldsFromQuery($subquery['select']); + foreach($query_fields as $field => $select) + { + if (!in_array($field, $all_fields)) + $all_fields[] = $field; + } + $subqueries[$i]['query_fields'] = $query_fields; + } + $first = true; + //Now ensure the queries have the same set of fields in the same order. + foreach($subqueries as $subquery) + { + $subquery['select'] = "SELECT"; + foreach($all_fields as $field) + { + if (!isset($subquery['query_fields'][$field])) + { + $subquery['select'] .= " ' ' $field,"; + } + else + { + $subquery['select'] .= " {$subquery['query_fields'][$field]},"; + } + } + $subquery['select'] = substr($subquery['select'], 0 , strlen($subquery['select']) - 1); + //Put the query into the final_query + $query = $subquery['select'] . " " . $subquery['from'] . " " . $subquery['where']; + if(!$first) + { + $query = ' UNION ALL ( '.$query . ' )'; + $final_query_rows .= " UNION ALL "; + } else { + $query = '(' . $query . ')'; + $first = false; + } + $query_array = $subquery['query_array']; + $select_position=strpos($query_array['select'],"SELECT"); + $distinct_position=strpos($query_array['select'],"DISTINCT"); + if ($select_position !== false && $distinct_position!= false) + { + $query_rows = "( ".substr_replace($query_array['select'],"SELECT count(",$select_position,6). ")" . $subquery['from_min'].$query_array['join']. $subquery['where'].' )'; + } + else + { + //resort to default behavior. + $query_rows = "( SELECT count(*)". $subquery['from_min'].$query_array['join']. $subquery['where'].' )'; + } + if(!empty($subquery['secondary_select'])) + { + + $subquerystring= $subquery['secondary_select'] . $subquery['secondary_from'].$query_array['join']. $subquery['where']; + if (!empty($subquery['secondary_where'])) + { + if (empty($subquery['where'])) + { + $subquerystring.=" WHERE " .$subquery['secondary_where']; + } + else + { + $subquerystring.=" AND " .$subquery['secondary_where']; + } + } + $secondary_queries[]=$subquerystring; + } + $final_query .= $query; + $final_query_rows .= $query_rows; + } + } + + if(!empty($order_by)) + { + $submodule = false; + if(!$subpanel_def->isCollection()) + { + $submodulename = $subpanel_def->_instance_properties['module']; + $submoduleclass = $beanList[$submodulename]; + $submodule = new $submoduleclass(); + } + if(!empty($submodule) && !empty($submodule->table_name)) + { + $final_query .= " ORDER BY " .$parentbean->process_order_by($order_by, $submodule); + + } + else + { + $final_query .= " ORDER BY ". $order_by . ' '; + } + if(!empty($sort_order)) + { + $final_query .= ' ' .$sort_order; + } + } + + + if(isset($layout_edit_mode) && $layout_edit_mode) + { + $response = array(); + if(!empty($submodule)) + { + $submodule->assign_display_fields($submodule->module_dir); + $response['list'] = array($submodule); + } + else + { + $response['list'] = array(); + } + $response['parent_data'] = array(); + $response['row_count'] = 1; + $response['next_offset'] = 0; + $response['previous_offset'] = 0; + + return $response; + } + + return $parentbean->process_union_list_query($parentbean, $final_query, $row_offset, $limit, $max, '',$subpanel_def, $final_query_rows, $secondary_queries); + } + + + /** + * Returns a full (ie non-paged) list of the current object type. + * + * @param string $order_by the order by SQL parameter. defaults to "" + * @param string $where where clause. defaults to "" + * @param boolean $check_dates. defaults to false + * @param int $show_deleted show deleted records. defaults to 0 + */ + function get_full_list($order_by = "", $where = "", $check_dates=false, $show_deleted = 0) + { + $GLOBALS['log']->debug("get_full_list: order_by = '$order_by' and where = '$where'"); + if(isset($_SESSION['show_deleted'])) + { + $show_deleted = 1; + } + $query = $this->create_new_list_query($order_by, $where,array(),array(), $show_deleted); + return $this->process_full_list_query($query, $check_dates); + } + + /** + * Return the list query used by the list views and export button. Next generation of create_new_list_query function. + * + * Override this function to return a custom query. + * + * @param string $order_by custom order by clause + * @param string $where custom where clause + * @param array $filter Optioanal + * @param array $params Optional * + * @param int $show_deleted Optional, default 0, show deleted records is set to 1. + * @param string $join_type + * @param boolean $return_array Optional, default false, response as array + * @param object $parentbean creating a subquery for this bean. + * @param boolean $singleSelect Optional, default false. + * @return String select query string, optionally an array value will be returned if $return_array= true. + */ + function create_new_list_query($order_by, $where,$filter=array(),$params=array(), $show_deleted = 0,$join_type='', $return_array = false,$parentbean=null, $singleSelect = false) + { + global $beanFiles, $beanList; + $selectedFields = array(); + $secondarySelectedFields = array(); + $ret_array = array(); + $distinct = ''; + if($this->bean_implements('ACL') && ACLController::requireOwner($this->module_dir, 'list') ) + { + global $current_user; + $owner_where = $this->getOwnerWhere($current_user->id); + if(empty($where)) + { + $where = $owner_where; + } + else + { + $where .= ' AND '. $owner_where; + } + } + if(!empty($params['distinct'])) + { + $distinct = ' DISTINCT '; + } + if(empty($filter)) + { + $ret_array['select'] = " SELECT $distinct $this->table_name.* "; + } + else + { + $ret_array['select'] = " SELECT $distinct $this->table_name.id "; + } + $ret_array['from'] = " FROM $this->table_name "; + $ret_array['from_min'] = $ret_array['from']; + $ret_array['secondary_from'] = $ret_array['from'] ; + $ret_array['where'] = ''; + $ret_array['order_by'] = ''; + //secondary selects are selects that need to be run after the primarty query to retrieve additional info on main + if($singleSelect) + { + $ret_array['secondary_select']=& $ret_array['select']; + $ret_array['secondary_from'] = & $ret_array['from']; + } + else + { + $ret_array['secondary_select'] = ''; + } + $custom_join = false; + if((!isset($params['include_custom_fields']) || $params['include_custom_fields']) && isset($this->custom_fields)) + { + + $custom_join = $this->custom_fields->getJOIN( empty($filter)? true: $filter ); + if($custom_join) + { + $ret_array['select'] .= ' ' .$custom_join['select']; + } + } + if($custom_join) + { + $ret_array['from'] .= ' ' . $custom_join['join']; + } + $jtcount = 0; + //LOOP AROUND FOR FIXIN VARDEF ISSUES + require('include/VarDefHandler/listvardefoverride.php'); + $joined_tables = array(); + if(isset($params['joined_tables'])) + { + foreach($params['joined_tables'] as $table) + { + $joined_tables[$table] = 1; + } + } + + if(!empty($filter)) + { + $filterKeys = array_keys($filter); + if(is_numeric($filterKeys[0])) + { + $fields = array(); + foreach($filter as $field) + { + $field = strtolower($field); + //remove out id field so we don't duplicate it + if ( $field == 'id' && !empty($filter) ) { + continue; + } + if(isset($this->field_defs[$field])) + { + $fields[$field]= $this->field_defs[$field]; + } + else + { + $fields[$field] = array('force_exists'=>true); + } + } + }else{ + $fields = $filter; + } + } + else + { + $fields = $this->field_defs; + } + + $used_join_key = array(); + + foreach($fields as $field=>$value) + { + //alias is used to alias field names + $alias=''; + if (isset($value['alias'])) + { + $alias =' as ' . $value['alias'] . ' '; + } + + if(empty($this->field_defs[$field]) || !empty($value['force_blank']) ) + { + if(!empty($filter) && isset($filter[$field]['force_exists']) && $filter[$field]['force_exists']) + { + if ( isset($filter[$field]['force_default']) ) + $ret_array['select'] .= ", {$filter[$field]['force_default']} $field "; + else + //spaces are a fix for length issue problem with unions. The union only returns the maximum number of characters from the first select statemtn. + $ret_array['select'] .= ", ' ' $field "; + } + continue; + } + else + { + $data = $this->field_defs[$field]; + } + + //ignore fields that are a part of the collection and a field has been removed as a result of + //layout customization.. this happens in subpanel customizations, use case, from the contacts subpanel + //in opportunities module remove the contact_role/opportunity_role field. + $process_field=true; + if (isset($data['relationship_fields']) and !empty($data['relationship_fields'])) + { + foreach ($data['relationship_fields'] as $field_name) + { + if (!isset($fields[$field_name])) + { + $process_field=false; + } + } + } + if (!$process_field) + { + continue; + } + + if( (!isset($data['source']) || $data['source'] == 'db') && (!empty($alias) || !empty($filter) )) + { + $ret_array['select'] .= ", $this->table_name.$field $alias"; + $selectedFields["$this->table_name.$field"] = true; + } + + + + if($data['type'] != 'relate' && isset($data['db_concat_fields'])) + { + $ret_array['select'] .= ", " . db_concat($this->table_name, $data['db_concat_fields']) . " as $field"; + $selectedFields[db_concat($this->table_name, $data['db_concat_fields'])] = true; + } + //Custom relate field or relate fields built in module builder which have no link field associated. + if ($data['type'] == 'relate' && (isset($data['custom_module']) || isset($data['ext2']))) { + $joinTableAlias = 'jt' . $jtcount; + $relateJoinInfo = $this->custom_fields->getRelateJoin($data, $joinTableAlias); + $ret_array['select'] .= $relateJoinInfo['select']; + $ret_array['from'] .= $relateJoinInfo['from']; + //Replace any references to the relationship in the where clause with the new alias + //If the link isn't set, assume that search used the local table for the field + $searchTable = isset($data['link']) ? $relateJoinInfo['rel_table'] : $this->table_name; + $field_name = $relateJoinInfo['rel_table'] . '.' . !empty($data['name'])?$data['name']:'name'; + $where = preg_replace('/(^|[\s(])' . $field_name . '/' , '${1}' . $relateJoinInfo['name_field'], $where); + $jtcount++; + } + //Parent Field + if ($data['type'] == 'parent') { + //See if we need to join anything by inspecting the where clause + $match = preg_match('/(^|[\s(])parent_(\w+)_(\w+)\.name/', $where, $matches); + if ($match) { + $joinTableAlias = 'jt' . $jtcount; + $joinModule = $matches[2]; + $joinTable = $matches[3]; + $localTable = $this->table_name; + if (!empty($data['custom_module'])) { + $localTable .= '_cstm'; + } + global $beanFiles, $beanList, $module; + require_once($beanFiles[$beanList[$joinModule]]); + $rel_mod = new $beanList[$joinModule](); + $nameField = "$joinTableAlias.name"; + if (isset($rel_mod->field_defs['name'])) + { + $name_field_def = $rel_mod->field_defs['name']; + if(isset($name_field_def['db_concat_fields'])) + { + $nameField = db_concat($joinTableAlias, $name_field_def['db_concat_fields']); + } + } + $ret_array['select'] .= ", $nameField {$data['name']} "; + $ret_array['from'] .= " LEFT JOIN $joinTable $joinTableAlias + ON $localTable.{$data['id_name']} = $joinTableAlias.id"; + //Replace any references to the relationship in the where clause with the new alias + $where = preg_replace('/(^|[\s(])parent_' . $joinModule . '_' . $joinTable . '\.name/', '${1}' . $nameField, $where); + $jtcount++; + } + } + if($data['type'] == 'relate' && isset($data['link'])) + { + $this->load_relationship($data['link']); + if(!empty($this->$data['link'])) + { + $params = array(); + if(empty($join_type)) + { + $params['join_type'] = ' LEFT JOIN '; + } + else + { + $params['join_type'] = $join_type; + } + if(isset($data['join_name'])) + { + $params['join_table_alias'] = $data['join_name']; + } + else + { + $params['join_table_alias'] = 'jt' . $jtcount; + + } + if(isset($data['join_link_name'])) + { + $params['join_table_link_alias'] = $data['join_link_name']; + } + else + { + $params['join_table_link_alias'] = 'jtl' . $jtcount; + } + $join_primary = !isset($data['join_primary']) || $data['join_primary']; + + $join = $this->$data['link']->getJoin($params, true); + $used_join_key[] = $join['rel_key']; + $rel_module = $this->$data['link']->getRelatedModuleName(); + $table_joined = !empty($joined_tables[$params['join_table_alias']]) || (!empty($joined_tables[$params['join_table_link_alias']]) && isset($data['link_type']) && $data['link_type'] == 'relationship_info'); + + //if rnanme is set to 'name', and bean files exist, then check if field should be a concatenated name + global $beanFiles, $beanList; + if($data['rname'] && !empty($beanFiles[$beanList[$rel_module]])) { + + //create an instance of the related bean + require_once($beanFiles[$beanList[$rel_module]]); + $rel_mod = new $beanList[$rel_module](); + //if bean has first and last name fields, then name should be concatenated + if(isset($rel_mod->field_name_map['first_name']) && isset($rel_mod->field_name_map['last_name'])){ + $data['db_concat_fields'] = array(0=>'first_name', 1=>'last_name'); + } + } + + + if($join['type'] == 'many-to-many') + { + if(empty($ret_array['secondary_select'])) + { + $ret_array['secondary_select'] = " SELECT $this->table_name.id ref_id "; + + if(!empty($beanFiles[$beanList[$rel_module]]) && $join_primary) + { + require_once($beanFiles[$beanList[$rel_module]]); + $rel_mod = new $beanList[$rel_module](); + if(isset($rel_mod->field_defs['assigned_user_id'])) + { + $ret_array['secondary_select'].= " , ". $params['join_table_alias'] . ".assigned_user_id {$field}_owner, '$rel_module' {$field}_mod"; + + } + else + { + if(isset($rel_mod->field_defs['created_by'])) + { + $ret_array['secondary_select'].= " , ". $params['join_table_alias'] . ".created_by {$field}_owner , '$rel_module' {$field}_mod"; + + } + } + + + } + } + + + + if(isset($data['db_concat_fields'])) + { + $ret_array['secondary_select'] .= ' , ' . db_concat($params['join_table_alias'], $data['db_concat_fields']) . ' ' . $field; + } + else + { + if(!isset($data['relationship_fields'])) + { + $ret_array['secondary_select'] .= ' , ' . $params['join_table_alias'] . '.' . $data['rname'] . ' ' . $field; + } + } + if(!$singleSelect) + { + $ret_array['select'] .= ", ' ' $field "; + $ret_array['select'] .= ", ' ' " . $join['rel_key'] . ' '; + } + $count_used =0; + if($this->db->dbType != 'mysql') {//bug 26801, these codes are just used to duplicate rel_key in the select sql, or it will throw error in MSSQL and Oracle. + foreach($used_join_key as $used_key) { + if($used_key == $join['rel_key']) $count_used++; + } + } + if($count_used <= 1) {//27416, the $ret_array['secondary_select'] should always generate, regardless the dbtype + $ret_array['secondary_select'] .= ', ' . $params['join_table_link_alias'].'.'. $join['rel_key'] .' ' . $join['rel_key']; + } + if(isset($data['relationship_fields'])) + { + foreach($data['relationship_fields'] as $r_name=>$alias_name) + { + if(!empty( $secondarySelectedFields[$alias_name]))continue; + $ret_array['secondary_select'] .= ', ' . $params['join_table_link_alias'].'.'. $r_name .' ' . $alias_name; + $secondarySelectedFields[$alias_name] = true; + } + } + if(!$table_joined) + { + $ret_array['secondary_from'] .= ' ' . $join['join']. ' AND ' . $params['join_table_alias'].'.deleted=0'; + if (isset($data['link_type']) && $data['link_type'] == 'relationship_info' && ($parentbean instanceOf SugarBean)) + { + $ret_array['secondary_where'] = $params['join_table_link_alias'] . '.' . $join['rel_key']. "='" .$parentbean->id . "'"; + } + } + } + else + { + if(isset($data['db_concat_fields'])) + { + $ret_array['select'] .= ' , ' . db_concat($params['join_table_alias'], $data['db_concat_fields']) . ' ' . $field; + } + else + { + $ret_array['select'] .= ' , ' . $params['join_table_alias'] . '.' . $data['rname'] . ' ' . $field; + } + if(isset($data['additionalFields'])){ + foreach($data['additionalFields'] as $k=>$v){ + $ret_array['select'] .= ' , ' . $params['join_table_alias'] . '.' . $k . ' ' . $v; + } + } + if(!$table_joined) + { + $ret_array['from'] .= ' ' . $join['join']. ' AND ' . $params['join_table_alias'].'.deleted=0'; + if(!empty($beanList[$rel_module]) && !empty($beanFiles[$beanList[$rel_module]])) + { + require_once($beanFiles[$beanList[$rel_module]]); + $rel_mod = new $beanList[$rel_module](); + if(isset($value['target_record_key']) && !empty($filter)) + { + $selectedFields[$this->table_name.'.'.$value['target_record_key']] = true; + $ret_array['select'] .= " , $this->table_name.{$value['target_record_key']} "; + } + if(isset($rel_mod->field_defs['assigned_user_id'])) + { + $ret_array['select'] .= ' , ' .$params['join_table_alias'] . '.assigned_user_id ' . $field . '_owner'; + } + else + { + $ret_array['select'] .= ' , ' .$params['join_table_alias'] . '.created_by ' . $field . '_owner'; + } + $ret_array['select'] .= " , '".$rel_module ."' " . $field . '_mod'; + } + } + } + //Replace references to this table in the where clause with the new alias + $join_table_name = $this->$data['link']->getRelatedTableName(); + // To fix SOAP stuff where we are trying to retrieve all the accounts data where accounts.id = .. + // and this code changes accounts to jt4 as there is a self join with the accounts table. + //Martin fix #27494 + if(isset($data['db_concat_fields'])){ + $buildWhere = false; + if(in_array('first_name', $data['db_concat_fields']) && in_array('last_name', $data['db_concat_fields'])) + { + $exp = '/\(\s*?'.$data['name'].'.*?\%\'\s*?\)/'; + if(preg_match($exp, $where, $matches)) + { + $search_expression = $matches[0]; + //Create three search conditions - first + last, first, last + $first_name_search = str_replace($data['name'], $params['join_table_alias'] . '.first_name', $search_expression); + $last_name_search = str_replace($data['name'], $params['join_table_alias'] . '.last_name', $search_expression); + $full_name_search = str_replace($data['name'], db_concat($params['join_table_alias'], $data['db_concat_fields']), $search_expression); + $buildWhere = true; + $where = str_replace($search_expression, '(' . $full_name_search . ' OR ' . $first_name_search . ' OR ' . $last_name_search . ')', $where); + } + } + + if(!$buildWhere) + { + $db_field = db_concat($params['join_table_alias'], $data['db_concat_fields']); + $where = preg_replace('/'.$data['name'].'/', $db_field, $where); + } + }else{ + $where = preg_replace('/(^|[\s(])' . $data['name'] . '/', '${1}' . $params['join_table_alias'] . '.'.$data['rname'], $where); + } + if(!$table_joined) + { + $joined_tables[$params['join_table_alias']]=1; + $joined_tables[$params['join_table_link_alias']]=1; + } + + $jtcount++; + } + } + } + if(!empty($filter)) + { + if(isset($this->field_defs['assigned_user_id']) && empty($selectedFields[$this->table_name.'.assigned_user_id'])) + { + $ret_array['select'] .= ", $this->table_name.assigned_user_id "; + } + else if(isset($this->field_defs['created_by']) && empty($selectedFields[$this->table_name.'.created_by'])) + { + $ret_array['select'] .= ", $this->table_name.created_by "; + } + if(isset($this->field_defs['system_id']) && empty($selectedFields[$this->table_name.'.system_id'])) + { + $ret_array['select'] .= ", $this->table_name.system_id "; + } + + } + $where_auto = '1=1'; + if($show_deleted == 0) + { + $where_auto = "$this->table_name.deleted=0"; + }else if($show_deleted == 1) + { + $where_auto = "$this->table_name.deleted=1"; + } + if($where != "") + $ret_array['where'] = " where ($where) AND $where_auto"; + else + $ret_array['where'] = " where $where_auto"; + if(!empty($order_by)) + { + //make call to process the order by clause + $ret_array['order_by'] = " ORDER BY ". $this->process_order_by($order_by, null); + } + if($singleSelect) + { + unset($ret_array['secondary_where']); + unset($ret_array['secondary_from']); + unset($ret_array['secondary_select']); + } + + if($return_array) + { + return $ret_array; + } + + return $ret_array['select'] . $ret_array['from'] . $ret_array['where']. $ret_array['order_by']; + + + + + } + /** + * Returns parent record data for objects that store relationship information + * + * @param array $type_info + * + * Interal function, do not override. + */ + function retrieve_parent_fields($type_info) + { + $queries = array(); + global $beanList, $beanFiles; + $templates = array(); + $parent_child_map = array(); + foreach($type_info as $children_info) + { + foreach($children_info as $child_info) + { + if($child_info['type'] == 'parent') + { + if(empty($templates[$child_info['parent_type']])) + { + //Test emails will have an invalid parent_type, don't try to load the non-existant parent bean + if ($child_info['parent_type'] == 'test') { + continue; + } + $class = $beanList[$child_info['parent_type']]; + // Added to avoid error below; just silently fail and write message to log + if ( empty($beanFiles[$class]) ) { + $GLOBALS['log']->error($this->object_name.'::retrieve_parent_fields() - cannot load class "'.$class.'", skip loading.'); + continue; + } + require_once($beanFiles[$class]); + $templates[$child_info['parent_type']] = new $class(); + } + + if(empty($queries[$child_info['parent_type']])) + { + $queries[$child_info['parent_type']] = "SELECT id "; + $field_def = $templates[$child_info['parent_type']]->field_defs['name']; + if(isset($field_def['db_concat_fields'])) + { + $queries[$child_info['parent_type']] .= ' , ' . db_concat($templates[$child_info['parent_type']]->table_name, $field_def['db_concat_fields']) . ' parent_name'; + } + else + { + $queries[$child_info['parent_type']] .= ' , name parent_name'; + } + if(isset($templates[$child_info['parent_type']]->field_defs['assigned_user_id'])) + { + $queries[$child_info['parent_type']] .= ", assigned_user_id parent_name_owner , '{$child_info['parent_type']}' parent_name_mod";; + }else if(isset($templates[$child_info['parent_type']]->field_defs['created_by'])) + { + $queries[$child_info['parent_type']] .= ", created_by parent_name_owner, '{$child_info['parent_type']}' parent_name_mod"; + } + $queries[$child_info['parent_type']] .= " FROM " . $templates[$child_info['parent_type']]->table_name ." WHERE id IN ('{$child_info['parent_id']}'"; + } + else + { + if(empty($parent_child_map[$child_info['parent_id']])) + $queries[$child_info['parent_type']] .= " ,'{$child_info['parent_id']}'"; + } + $parent_child_map[$child_info['parent_id']][] = $child_info['child_id']; + } + } + } + $results = array(); + foreach($queries as $query) + { + $result = $this->db->query($query . ')'); + while($row = $this->db->fetchByAssoc($result)) + { + $results[$row['id']] = $row; + } + } + + $child_results = array(); + foreach($parent_child_map as $parent_key=>$parent_child) + { + foreach($parent_child as $child) + { + if(isset( $results[$parent_key])) + { + $child_results[$child] = $results[$parent_key]; + } + } + } + return $child_results; + } + + /** + * Processes the list query and return fetched row. + * + * Internal function, do not override. + * @param string $query select query to be processed. + * @param int $row_offset starting position + * @param int $limit Optioanl, default -1 + * @param int $max_per_page Optional, default -1 + * @param string $where Optional, additional filter criteria. + * @return array Fetched data + */ + function process_list_query($query, $row_offset, $limit= -1, $max_per_page = -1, $where = '') + { + global $sugar_config; + $db = &DBManagerFactory::getInstance('listviews'); + /** + * if the row_offset is set to 'end' go to the end of the list + */ + $toEnd = strval($row_offset) == 'end'; + $GLOBALS['log']->debug("process_list_query: ".$query); + if($max_per_page == -1) + { + $max_per_page = $sugar_config['list_max_entries_per_page']; + } + // Check to see if we have a count query available. + if(empty($sugar_config['disable_count_query']) || $toEnd) + { + $count_query = $this->create_list_count_query($query); + if(!empty($count_query) && (empty($limit) || $limit == -1)) + { + // We have a count query. Run it and get the results. + $result = $db->query($count_query, true, "Error running count query for $this->object_name List: "); + $assoc = $db->fetchByAssoc($result); + if(!empty($assoc['c'])) + { + $rows_found = $assoc['c']; + $limit = $sugar_config['list_max_entries_per_page']; + } + if( $toEnd) + { + $row_offset = (floor(($rows_found -1) / $limit)) * $limit; + } + } + } + else + { + if((empty($limit) || $limit == -1)) + { + $limit = $max_per_page + 1; + $max_per_page = $limit; + } + } + + if(empty($row_offset)) + { + $row_offset = 0; + } + if(!empty($limit) && $limit != -1 && $limit != -99) + { + $result = $db->limitQuery($query, $row_offset, $limit,true,"Error retrieving $this->object_name list: "); + } + else + { + $result = $db->query($query,true,"Error retrieving $this->object_name list: "); + } + + $list = Array(); + + if(empty($rows_found)) + { + $rows_found = $db->getRowCount($result); + } + + $GLOBALS['log']->debug("Found $rows_found ".$this->object_name."s"); + + $previous_offset = $row_offset - $max_per_page; + $next_offset = $row_offset + $max_per_page; + + $class = get_class($this); + if($rows_found != 0 or $db->dbType != 'mysql') + { + //todo Bug? we should remove the magic number -99 + //use -99 to return all + $index = $row_offset; + while ($max_per_page == -99 || ($index < $row_offset + $max_per_page)) + { + + if(!empty($sugar_config['disable_count_query'])) + { + $row = $db->fetchByAssoc($result); + } + else + { + $row = $db->fetchByAssoc($result, $index); + } + if (empty($row)) + { + break; + } + + //instantiate a new class each time. This is because php5 passes + //by reference by default so if we continually update $this, we will + //at the end have a list of all the same objects + $temp = new $class(); + + foreach($this->field_defs as $field=>$value) + { + if (isset($row[$field])) + { + $temp->$field = $row[$field]; + $owner_field = $field . '_owner'; + if(isset($row[$owner_field])) + { + $temp->$owner_field = $row[$owner_field]; + } + + $GLOBALS['log']->debug("$temp->object_name({$row['id']}): ".$field." = ".$temp->$field); + }else if (isset($row[$this->table_name .'.'.$field])) + { + $temp->$field = $row[$this->table_name .'.'.$field]; + } + else + { + $temp->$field = ""; + } + } + + $temp->check_date_relationships_load(); + $temp->fill_in_additional_list_fields(); + if($temp->hasCustomFields()) $temp->custom_fields->fill_relationships(); + $temp->call_custom_logic("process_record"); + + $list[] = $temp; + + $index++; + } + } + if(!empty($sugar_config['disable_count_query']) && !empty($limit)) + { + + $rows_found = $row_offset + count($list); + + unset($list[$limit - 1]); + if(!$toEnd) + { + $next_offset--; + $previous_offset++; + } + } + $response = Array(); + $response['list'] = $list; + $response['row_count'] = $rows_found; + $response['next_offset'] = $next_offset; + $response['previous_offset'] = $previous_offset; + $response['current_offset'] = $row_offset ; + return $response; + } + + /** + * Returns the number of rows that the given SQL query should produce + * + * Internal function, do not override. + * @param string $query valid select query + * @param boolean $is_count_query Optional, Default false, set to true if passed query is a count query. + * @return int count of rows found + */ + function _get_num_rows_in_query($query, $is_count_query=false) + { + $num_rows_in_query = 0; + if (!$is_count_query) + { + $count_query = SugarBean::create_list_count_query($query); + } else + $count_query=$query; + + $result = $this->db->query($count_query, true, "Error running count query for $this->object_name List: "); + $row_num = 0; + $row = $this->db->fetchByAssoc($result, $row_num); + while($row) + { + $num_rows_in_query += current($row); + $row_num++; + $row = $this->db->fetchByAssoc($result, $row_num); + } + + return $num_rows_in_query; + } + + /** + * Applies pagination window to union queries used by list view and subpanels, + * executes the query and returns fetched data. + * + * Internal function, do not override. + * @param object $parent_bean + * @param string $query query to be processed. + * @param int $row_offset + * @param int $limit optional, default -1 + * @param int $max_per_page Optional, default -1 + * @param string $where Custom where clause. + * @param array $subpanel_def definition of sub-panel to be processed + * @param string $query_row_count + * @param array $seconday_queries + * @return array Fetched data. + */ + function process_union_list_query($parent_bean, $query, + $row_offset, $limit= -1, $max_per_page = -1, $where = '', $subpanel_def, $query_row_count='', $secondary_queries = array()) + + { + $db = &DBManagerFactory::getInstance('listviews'); + /** + * if the row_offset is set to 'end' go to the end of the list + */ + $toEnd = strval($row_offset) == 'end'; + global $sugar_config; + $use_count_query=false; + $processing_collection=$subpanel_def->isCollection(); + + $GLOBALS['log']->debug("process_list_query: ".$query); + if($max_per_page == -1) + { + $max_per_page = $sugar_config['list_max_entries_per_subpanel']; + } + if(empty($query_row_count)) + { + $query_row_count = $query; + } + $distinct_position=strpos($query_row_count,"DISTINCT"); + + if ($distinct_position!= false) + { + $use_count_query=true; + } + $performSecondQuery = true; + if(empty($sugar_config['disable_count_query']) || $toEnd) + { + $rows_found = $this->_get_num_rows_in_query($query_row_count,$use_count_query); + if($rows_found < 1) + { + $performSecondQuery = false; + } + if(!empty($rows_found) && (empty($limit) || $limit == -1)) + { + $limit = $sugar_config['list_max_entries_per_subpanel']; + } + if( $toEnd) + { + $row_offset = (floor(($rows_found -1) / $limit)) * $limit; + + } + } + else + { + if((empty($limit) || $limit == -1)) + { + $limit = $max_per_page + 1; + $max_per_page = $limit; + } + } + + if(empty($row_offset)) + { + $row_offset = 0; + } + $list = array(); + $previous_offset = $row_offset - $max_per_page; + $next_offset = $row_offset + $max_per_page; + + if($performSecondQuery) + { + if(!empty($limit) && $limit != -1 && $limit != -99) + { + $result = $db->limitQuery($query, $row_offset, $limit,true,"Error retrieving $parent_bean->object_name list: "); + } + else + { + $result = $db->query($query,true,"Error retrieving $this->object_name list: "); + } + if(empty($rows_found)) + { + $rows_found = $db->getRowCount($result); + } + + $GLOBALS['log']->debug("Found $rows_found ".$parent_bean->object_name."s"); + if($rows_found != 0 or $db->dbType != 'mysql') + { + //use -99 to return all + + // get the current row + $index = $row_offset; + if(!empty($sugar_config['disable_count_query'])) + { + $row = $db->fetchByAssoc($result); + } + else + { + $row = $db->fetchByAssoc($result, $index); + } + + $post_retrieve = array(); + $isFirstTime = true; + while($row) + { + $function_fields = array(); + if(($index < $row_offset + $max_per_page || $max_per_page == -99) or ($db->dbType != 'mysql')) + { + if ($processing_collection) + { + $current_bean =$subpanel_def->sub_subpanels[$row['panel_name']]->template_instance; + if(!$isFirstTime) + { + $class = get_class($subpanel_def->sub_subpanels[$row['panel_name']]->template_instance); + $current_bean = new $class(); + } + } else { + $current_bean=$subpanel_def->template_instance; + if(!$isFirstTime) + { + $class = get_class($subpanel_def->template_instance); + $current_bean = new $class(); + } + } + $isFirstTime = false; + //set the panel name in the bean instance. + if (isset($row['panel_name'])) + { + $current_bean->panel_name=$row['panel_name']; + } + foreach($current_bean->field_defs as $field=>$value) + { + + if (isset($row[$field])) + { + $current_bean->$field = $row[$field]; + unset($row[$field]); + } + else if (isset($row[$this->table_name .'.'.$field])) + { + $current_bean->$field = $row[$current_bean->table_name .'.'.$field]; + unset($row[$current_bean->table_name .'.'.$field]); + } + else + { + $current_bean->$field = ""; + unset($row[$field]); + } + if(isset($value['source']) && $value['source'] == 'function') + { + $function_fields[]=$field; + } + } + foreach($row as $key=>$value) + { + $current_bean->$key = $value; + } + foreach($function_fields as $function_field) + { + $value = $current_bean->field_defs[$function_field]; + $can_execute = true; + $execute_params = array(); + $execute_function = array(); + if(!empty($value['function_class'])) + { + $execute_function[] = $value['function_class']; + $execute_function[] = $value['function_name']; + } + else + { + $execute_function = $value['function_name']; + } + foreach($value['function_params'] as $param ) + { + if (empty($value['function_params_source']) or $value['function_params_source']=='parent') + { + if(empty($this->$param)) + { + $can_execute = false; + } + else + { + $execute_params[] = $this->$param; + } + } else if ($value['function_params_source']=='this') + { + if(empty($current_bean->$param)) + { + $can_execute = false; + } + else + { + $execute_params[] = $current_bean->$param; + } + } + else + { + $can_execute = false; + } + + } + if($can_execute) + { + if(!empty($value['function_require'])) + { + require_once($value['function_require']); + } + $current_bean->$function_field = call_user_func_array($execute_function, $execute_params); + } + } + if(!empty($current_bean->parent_type) && !empty($current_bean->parent_id)) + { + if(!isset($post_retrieve[$current_bean->parent_type])) + { + $post_retrieve[$current_bean->parent_type] = array(); + } + $post_retrieve[$current_bean->parent_type][] = array('child_id'=>$current_bean->id, 'parent_id'=> $current_bean->parent_id, 'parent_type'=>$current_bean->parent_type, 'type'=>'parent'); + } + //$current_bean->fill_in_additional_list_fields(); + $list[$current_bean->id] = $current_bean; + } + // go to the next row + $index++; + $row = $db->fetchByAssoc($result, $index); + } + } + //now handle retrieving many-to-many relationships + if(!empty($list)) + { + foreach($secondary_queries as $query2) + { + $result2 = $db->query($query2); + + $row2 = $db->fetchByAssoc($result2); + while($row2) + { + $id_ref = $row2['ref_id']; + + if(isset($list[$id_ref])) + { + foreach($row2 as $r2key=>$r2value) + { + if($r2key != 'ref_id') + { + $list[$id_ref]->$r2key = $r2value; + } + } + } + $row2 = $db->fetchByAssoc($result2); + } + } + + } + + if(isset($post_retrieve)) + { + $parent_fields = $this->retrieve_parent_fields($post_retrieve); + } + else + { + $parent_fields = array(); + } + if(!empty($sugar_config['disable_count_query']) && !empty($limit)) + { + $rows_found = $row_offset + count($list); + if(count($list) >= $limit) + { + array_pop($list); + } + if(!$toEnd) + { + $next_offset--; + $previous_offset++; + } + } + } + else + { + $row_found = 0; + $parent_fields = array(); + } + $response = array(); + $response['list'] = $list; + $response['parent_data'] = $parent_fields; + $response['row_count'] = $rows_found; + $response['next_offset'] = $next_offset; + $response['previous_offset'] = $previous_offset; + $response['current_offset'] = $row_offset ; + $response['query'] = $query; + + return $response; + } + + /** + * Applies pagination window to select queries used by detail view, + * executes the query and returns fetched data. + * + * Internal function, do not override. + * @param string $query query to be processed. + * @param int $row_offset + * @param int $limit optional, default -1 + * @param int $max_per_page Optional, default -1 + * @param string $where Custom where clause. + * @param int $offset Optional, default 0 + * @return array Fetched data. + * + */ + function process_detail_query($query, $row_offset, $limit= -1, $max_per_page = -1, $where = '', $offset = 0) + { + global $sugar_config; + $GLOBALS['log']->debug("process_list_query: ".$query); + if($max_per_page == -1) + { + $max_per_page = $sugar_config['list_max_entries_per_page']; + } + + // Check to see if we have a count query available. + $count_query = $this->create_list_count_query($query); + + if(!empty($count_query) && (empty($limit) || $limit == -1)) + { + // We have a count query. Run it and get the results. + $result = $this->db->query($count_query, true, "Error running count query for $this->object_name List: "); + $assoc = $this->db->fetchByAssoc($result); + if(!empty($assoc['c'])) + { + $total_rows = $assoc['c']; + } + } + + if(empty($row_offset)) + { + $row_offset = 0; + } + + $result = $this->db->limitQuery($query, $offset, 1, true,"Error retrieving $this->object_name list: "); + + $rows_found = $this->db->getRowCount($result); + + $GLOBALS['log']->debug("Found $rows_found ".$this->object_name."s"); + + $previous_offset = $row_offset - $max_per_page; + $next_offset = $row_offset + $max_per_page; + + if($rows_found != 0 or $this->db->dbType != 'mysql') + { + $index = 0; + $row = $this->db->fetchByAssoc($result, $index); + $this->retrieve($row['id']); + } + + $response = Array(); + $response['bean'] = $this; + if (empty($total_rows)) + $total_rows=0; + $response['row_count'] = $total_rows; + $response['next_offset'] = $next_offset; + $response['previous_offset'] = $previous_offset; + + return $response; + } + + /** + * Processes fetched list view data + * + * Internal function, do not override. + * @param string $query query to be processed. + * @param boolean $check_date Optional, default false. if set to true date time values are processed. + * @return array Fetched data. + * + */ + function process_full_list_query($query, $check_date=false) + { + + $GLOBALS['log']->debug("process_full_list_query: query is ".$query); + $result = $this->db->query($query, false); + $GLOBALS['log']->debug("process_full_list_query: result is ".print_r($result,true)); + $class = get_class($this); + $isFirstTime = true; + $bean = new $class(); + + //if($this->db->getRowCount($result) > 0){ + + + // We have some data. + //while ($row = $this->db->fetchByAssoc($result)) { + while (($row = $bean->db->fetchByAssoc($result)) != null) + { + if(!$isFirstTime) + { + $bean = new $class(); + } + $isFirstTime = false; + + foreach($bean->field_defs as $field=>$value) + { + if (isset($row[$field])) + { + $bean->$field = $row[$field]; + $GLOBALS['log']->debug("process_full_list: $bean->object_name({$row['id']}): ".$field." = ".$bean->$field); + } + else + { + $bean->$field = ''; + } + } + if($check_date) + { + $bean->processed_dates_times = array(); + $bean->check_date_relationships_load(); + } + $bean->fill_in_additional_list_fields(); + $bean->call_custom_logic("process_record"); + $bean->fetched_row = $row; + + $list[] = $bean; + } + //} + if (isset($list)) return $list; + else return null; + } + + /** + * Tracks the viewing of a detail record. + * This leverages get_summary_text() which is object specific. + * + * Internal function, do not override. + * @param string $user_id - String value of the user that is viewing the record. + * @param string $current_module - String value of the module being processed. + * @param string $current_view - String value of the current view + */ + function track_view($user_id, $current_module, $current_view='') + { + $trackerManager = TrackerManager::getInstance(); + if($monitor = $trackerManager->getMonitor('tracker')){ + $monitor->setValue('date_modified', $GLOBALS['timedate']->nowDb()); + $monitor->setValue('user_id', $user_id); + $monitor->setValue('module_name', $current_module); + $monitor->setValue('action', $current_view); + $monitor->setValue('item_id', $this->id); + $monitor->setValue('item_summary', $this->get_summary_text()); + $monitor->setValue('visible', $this->tracker_visibility); + $trackerManager->saveMonitor($monitor); + } + } + + /** + * Returns the summary text that should show up in the recent history list for this object. + * + * @return string + */ + public function get_summary_text() + { + return "Base Implementation. Should be overridden."; + } + + /** + * This is designed to be overridden and add specific fields to each record. + * This allows the generic query to fill in the major fields, and then targeted + * queries to get related fields and add them to the record. The contact's + * account for instance. This method is only used for populating extra fields + * in lists. + */ + function fill_in_additional_list_fields(){ + if(!empty($this->field_defs['parent_name']) && empty($this->parent_name)){ + $this->fill_in_additional_parent_fields(); + } + } + + /** + * This is designed to be overridden and add specific fields to each record. + * This allows the generic query to fill in the major fields, and then targeted + * queries to get related fields and add them to the record. The contact's + * account for instance. This method is only used for populating extra fields + * in the detail form + */ + function fill_in_additional_detail_fields() + { + if(!empty($this->field_defs['assigned_user_name']) && !empty($this->assigned_user_id)){ + + $this->assigned_user_name = get_assigned_user_name($this->assigned_user_id); + + } + if(!empty($this->field_defs['created_by']) && !empty($this->created_by)) + $this->created_by_name = get_assigned_user_name($this->created_by); + if(!empty($this->field_defs['modified_user_id']) && !empty($this->modified_user_id)) + $this->modified_by_name = get_assigned_user_name($this->modified_user_id); + + if(!empty($this->field_defs['parent_name'])){ + $this->fill_in_additional_parent_fields(); + } + } + + /** + * This is desgined to be overridden or called from extending bean. This method + * will fill in any parent_name fields. + */ + function fill_in_additional_parent_fields() { + + if(!empty($this->parent_id) && !empty($this->last_parent_id) && $this->last_parent_id == $this->parent_id){ + return false; + }else{ + $this->parent_name = ''; + } + if(!empty($this->parent_type)) { + $this->last_parent_id = $this->parent_id; + $this->getRelatedFields($this->parent_type, $this->parent_id, array('name'=>'parent_name', 'document_name' => 'parent_document_name', 'first_name'=>'parent_first_name', 'last_name'=>'parent_last_name')); + if(!empty($this->parent_first_name) || !empty($this->parent_last_name) ){ + $this->parent_name = $GLOBALS['locale']->getLocaleFormattedName($this->parent_first_name, $this->parent_last_name); + } else if(!empty($this->parent_document_name)){ + $this->parent_name = $this->parent_document_name; + } + } + } + +/* + * Fill in a link field + */ + + function fill_in_link_field( $linkFieldName ) + { + if ($this->load_relationship($linkFieldName)) + { + $list=$this->$linkFieldName->get(); + $this->$linkFieldName = '' ; // match up with null value in $this->populateFromRow() + if (!empty($list)) + $this->$linkFieldName = $list[0]; + } + } + + /** + * Fill in fields where type = relate + */ + function fill_in_relationship_fields(){ + if(!empty($this->relDepth)) { + if($this->relDepth > 1)return; + }else $this->relDepth = 0; + + foreach($this->field_defs as $field) + { + if(0 == strcmp($field['type'],'relate') && !empty($field['module'])) + { + $name = $field['name']; + if(empty($this->$name)) + { + // set the value of this relate field in this bean ($this->$field['name']) to the value of the 'name' field in the related module for the record identified by the value of $this->$field['id_name'] + $related_module = $field['module']; + $id_name = $field['id_name']; + if (empty($this->$id_name)){ + $this->fill_in_link_field($id_name); + } + if(!empty($this->$id_name) && ( $this->object_name != $related_module || ( $this->object_name == $related_module && $this->$id_name != $this->id ))){ + if(isset($GLOBALS['beanList'][ $related_module])){ + $class = $GLOBALS['beanList'][$related_module]; + + if(!empty($this->$id_name) && file_exists($GLOBALS['beanFiles'][$class]) && isset($this->$name)){ + require_once($GLOBALS['beanFiles'][$class]); + $mod = new $class(); + $mod->relDepth = $this->relDepth + 1; + $mod->retrieve($this->$id_name); + if (!empty($field['rname'])) { + $this->$name = $mod->$field['rname']; + } else if (isset($mod->name)) { + $this->$name = $mod->name; + } + } + } + } + if(!empty($this->$id_name) && isset($this->$name)) + { + if(!isset($field['additionalFields'])) + $field['additionalFields'] = array(); + if(!empty($field['rname'])) + { + $field['additionalFields'][$field['rname']]= $name; + } + else + { + $field['additionalFields']['name']= $name; + } + $this->getRelatedFields($related_module, $this->$id_name, $field['additionalFields']); + } + } + } + } + } + + /** + * This is a helper function that is used to quickly created indexes when creating tables. + */ + function create_index($query) + { + $GLOBALS['log']->info($query); + + $result = $this->db->query($query, true, "Error creating index:"); + } + + /** + * This function should be overridden in each module. It marks an item as deleted. + * + * If it is not overridden, then marking this type of item is not allowed + */ + function mark_deleted($id) + { + global $current_user; + $date_modified = $GLOBALS['timedate']->nowDb(); + if(isset($_SESSION['show_deleted'])) + { + $this->mark_undeleted($id); + } + else + { + // call the custom business logic + $custom_logic_arguments['id'] = $id; + $this->call_custom_logic("before_delete", $custom_logic_arguments); + + if ( isset($this->field_defs['modified_user_id']) ) { + if (!empty($current_user)) { + $this->modified_user_id = $current_user->id; + } else { + $this->modified_user_id = 1; + } + $query = "UPDATE $this->table_name set deleted=1 , date_modified = '$date_modified', modified_user_id = '$this->modified_user_id' where id='$id'"; + } else + $query = "UPDATE $this->table_name set deleted=1 , date_modified = '$date_modified' where id='$id'"; + $this->db->query($query, true,"Error marking record deleted: "); + $this->deleted = 1; + $this->mark_relationships_deleted($id); + + // Take the item off the recently viewed lists + $tracker = new Tracker(); + $tracker->makeInvisibleForAll($id); + + // call the custom business logic + $this->call_custom_logic("after_delete", $custom_logic_arguments); + } + } + + /** + * Restores data deleted by call to mark_deleted() function. + * + * Internal function, do not override. + */ + function mark_undeleted($id) + { + // call the custom business logic + $custom_logic_arguments['id'] = $id; + $this->call_custom_logic("before_restore", $custom_logic_arguments); + + $date_modified = $GLOBALS['timedate']->nowDb(); + $query = "UPDATE $this->table_name set deleted=0 , date_modified = '$date_modified' where id='$id'"; + $this->db->query($query, true,"Error marking record undeleted: "); + + // call the custom business logic + $this->call_custom_logic("after_restore", $custom_logic_arguments); + } + + /** + * This function deletes relationships to this object. It should be overridden + * to handle the relationships of the specific object. + * This function is called when the item itself is being deleted. + * + * @param int $id id of the relationship to delete + */ + function mark_relationships_deleted($id) + { + $this->delete_linked($id); + } + + /** + * This function is used to execute the query and create an array template objects + * from the resulting ids from the query. + * It is currently used for building sub-panel arrays. + * + * @param string $query - the query that should be executed to build the list + * @param object $template - The object that should be used to copy the records. + * @param int $row_offset Optional, default 0 + * @param int $limit Optional, default -1 + * @return array + */ + function build_related_list($query, &$template, $row_offset = 0, $limit = -1) + { + $GLOBALS['log']->debug("Finding linked records $this->object_name: ".$query); + $db = &DBManagerFactory::getInstance('listviews'); + + if(!empty($row_offset) && $row_offset != 0 && !empty($limit) && $limit != -1) + { + $result = $db->limitQuery($query, $row_offset, $limit,true,"Error retrieving $template->object_name list: "); + } + else + { + $result = $db->query($query, true); + } + + $list = Array(); + $isFirstTime = true; + $class = get_class($template); + while($row = $this->db->fetchByAssoc($result)) + { + if(!$isFirstTime) + { + $template = new $class(); + } + $isFirstTime = false; + $record = $template->retrieve($row['id']); + + if($record != null) + { + // this copies the object into the array + $list[] = $template; + } + } + return $list; + } + + /** + * This function is used to execute the query and create an array template objects + * from the resulting ids from the query. + * It is currently used for building sub-panel arrays. It supports an additional + * where clause that is executed as a filter on the results + * + * @param string $query - the query that should be executed to build the list + * @param object $template - The object that should be used to copy the records. + */ + function build_related_list_where($query, &$template, $where='', $in='', $order_by, $limit='', $row_offset = 0) + { + $db = &DBManagerFactory::getInstance('listviews'); + // No need to do an additional query + $GLOBALS['log']->debug("Finding linked records $this->object_name: ".$query); + if(empty($in) && !empty($query)) + { + $idList = $this->build_related_in($query); + $in = $idList['in']; + } + // MFH - Added Support For Custom Fields in Searches + $custom_join=""; + if(isset($this->custom_fields)) { + $custom_join = $this->custom_fields->getJOIN(); + } + + $query = "SELECT id "; + + if (!empty($custom_join)) { + $query .= $custom_join['select']; + } + $query .= " FROM $this->table_name "; + + if (!empty($custom_join) && !empty($custom_join['join'])) { + $query .= " " . $custom_join['join']; + } + + $query .= " WHERE deleted=0 AND id IN $in"; + if(!empty($where)) + { + $query .= " AND $where"; + } + + + if(!empty($order_by)) + { + $query .= "ORDER BY $order_by"; + } + if (!empty($limit)) + { + $result = $db->limitQuery($query, $row_offset, $limit,true,"Error retrieving $this->object_name list: "); + } + else + { + $result = $db->query($query, true); + } + + $list = Array(); + $isFirstTime = true; + $class = get_class($template); + + $disable_security_flag = ($template->disable_row_level_security) ? true : false; + while($row = $db->fetchByAssoc($result)) + { + if(!$isFirstTime) + { + $template = new $class(); + $template->disable_row_level_security = $disable_security_flag; + } + $isFirstTime = false; + $record = $template->retrieve($row['id']); + if($record != null) + { + // this copies the object into the array + $list[] = $template; + } + } + + return $list; + } + + /** + * Constructs an comma seperated list of ids from passed query results. + * + * @param string @query query to be executed. + * + */ + function build_related_in($query) + { + $idList = array(); + $result = $this->db->query($query, true); + $ids = ''; + while($row = $this->db->fetchByAssoc($result)) + { + $idList[] = $row['id']; + if(empty($ids)) + { + $ids = "('" . $row['id'] . "'"; + } + else + { + $ids .= ",'" . $row['id'] . "'"; + } + } + if(empty($ids)) + { + $ids = "('')"; + }else{ + $ids .= ')'; + } + + return array('list'=>$idList, 'in'=>$ids); + } + + /** + * Optionally copies values from fetched row into the bean. + * + * Internal function, do not override. + * + * @param string $query - the query that should be executed to build the list + * @param object $template - The object that should be used to copy the records + * @param array $field_list List of fields. + * @return array + */ + function build_related_list2($query, &$template, &$field_list) + { + $GLOBALS['log']->debug("Finding linked values $this->object_name: ".$query); + + $result = $this->db->query($query, true); + + $list = Array(); + $isFirstTime = true; + $class = get_class($template); + while($row = $this->db->fetchByAssoc($result)) + { + // Create a blank copy + $copy = $template; + if(!$isFirstTime) + { + $copy = new $class(); + } + $isFirstTime = false; + foreach($field_list as $field) + { + // Copy the relevant fields + $copy->$field = $row[$field]; + + } + + // this copies the object into the array + $list[] = $copy; + } + + return $list; + } + + /** + * Let implementing classes to fill in row specific columns of a list view form + * + */ + function list_view_parse_additional_sections(&$list_form) + { + } + + /** + * Assigns all of the values into the template for the list view + */ + function get_list_view_array() + { + static $cache = array(); + // cn: bug 12270 - sensitive fields being passed arbitrarily in listViews + $sensitiveFields = array('user_hash' => ''); + + $return_array = Array(); + global $app_list_strings, $mod_strings; + foreach($this->field_defs as $field=>$value){ + + if(isset($this->$field)){ + + // cn: bug 12270 - sensitive fields being passed arbitrarily in listViews + if(isset($sensitiveFields[$field])) + continue; + if(!isset($cache[$field])) + $cache[$field] = strtoupper($field); + + //Fields hidden by Dependent Fields + if (isset($value['hidden']) && $value['hidden'] === true) { + $return_array[$cache[$field]] = ""; + + } + //cn: if $field is a _dom, detect and return VALUE not KEY + //cl: empty function check for meta-data enum types that have values loaded from a function + else if (((!empty($value['type']) && ($value['type'] == 'enum' || $value['type'] == 'radioenum') )) && empty($value['function'])){ + if(!empty($app_list_strings[$value['options']][$this->$field])){ + $return_array[$cache[$field]] = $app_list_strings[$value['options']][$this->$field]; + } + //nsingh- bug 21672. some modules such as manufacturers, Releases do not have a listing for select fields in the $app_list_strings. Must also check $mod_strings to localize. + elseif(!empty($mod_strings[$value['options']][$this->$field])) + { + $return_array[$cache[$field]] = $mod_strings[$value['options']][$this->$field]; + } + else{ + $return_array[$cache[$field]] = $this->$field; + } + //end bug 21672 +// tjy: no need to do this str_replace as the changes in 29994 for ListViewGeneric.tpl for translation handle this now +// }elseif(!empty($value['type']) && $value['type'] == 'multienum'&& empty($value['function'])){ +// $return_array[strtoupper($field)] = str_replace('^,^', ', ', $this->$field ); + }elseif(!empty($value['custom_module']) && $value['type'] != 'currency'){ +// $this->format_field($value); + $return_array[$cache[$field]] = $this->$field; + }else{ + $return_array[$cache[$field]] = $this->$field; + } + // handle "Assigned User Name" + if($field == 'assigned_user_name'){ + $return_array['ASSIGNED_USER_NAME'] = get_assigned_user_name($this->assigned_user_id); + } + } + } + return $return_array; + } + /** + * Override this function to set values in the array used to render list view data. + * + */ + function get_list_view_data() + { + return $this->get_list_view_array(); + } + + /** + * Construct where clause from a list of name-value pairs. + * + */ + function get_where(&$fields_array) + { + $where_clause = "WHERE "; + $first = 1; + foreach ($fields_array as $name=>$value) + { + if ($first) + { + $first = 0; + } + else + { + $where_clause .= " AND "; + } + + $where_clause .= "$name = '".$this->db->quote($value,false)."'"; + } + $where_clause .= " AND deleted=0"; + return $where_clause; + } + + + /** + * Constructs a select query and fetch 1 row using this query, and then process the row + * + * Internal function, do not override. + * @param array @fields_array array of name value pairs used to construct query. + * @param boolean $encode Optional, default true, encode fetched data. + * @return object Instance of this bean with fetched data. + */ + function retrieve_by_string_fields($fields_array, $encode=true) + { + $where_clause = $this->get_where($fields_array); + if(isset($this->custom_fields)) + $custom_join = $this->custom_fields->getJOIN(); + else $custom_join = false; + if($custom_join) + { + $query = "SELECT $this->table_name.*". $custom_join['select']. " FROM $this->table_name " . $custom_join['join']; + } + else + { + $query = "SELECT $this->table_name.* FROM $this->table_name "; + } + $query .= " $where_clause"; + $GLOBALS['log']->debug("Retrieve $this->object_name: ".$query); + //requireSingleResult has beeen deprecated. + //$result = $this->db->requireSingleResult($query, true, "Retrieving record $where_clause:"); + $result = $this->db->limitQuery($query,0,1,true, "Retrieving record $where_clause:"); + + + if( empty($result)) + { + return null; + } + if($this->db->getRowCount($result) > 1) + { + $this->duplicates_found = true; + } + $row = $this->db->fetchByAssoc($result, -1, $encode); + if(empty($row)) + { + return null; + } + $this->fetched_row = $row; + $this->fromArray($row); + $this->fill_in_additional_detail_fields(); + return $this; + } + + /** + * This method is called during an import before inserting a bean + * Define an associative array called $special_fields + * the keys are user defined, and don't directly map to the bean's fields + * the value is the method name within that bean that will do extra + * processing for that field. example: 'full_name'=>'get_names_from_full_name' + * + */ + function process_special_fields() + { + foreach ($this->special_functions as $func_name) + { + if ( method_exists($this,$func_name) ) + { + $this->$func_name(); + } + } + } + + /** + * Override this function to build a where clause based on the search criteria set into bean . + * @abstract + */ + function build_generic_where_clause($value) + { + } + + function getRelatedFields($module, $id, $fields, $return_array = false){ + if(empty($GLOBALS['beanList'][$module]))return ''; + $object = $GLOBALS['beanList'][$module]; + if ($object == 'aCase') { + $object = 'Case'; + } + + VardefManager::loadVardef($module, $object); + if(empty($GLOBALS['dictionary'][$object]['table']))return ''; + $table = $GLOBALS['dictionary'][$object]['table']; + $query = 'SELECT id'; + foreach($fields as $field=>$alias){ + if(!empty($GLOBALS['dictionary'][$object]['fields'][$field]['db_concat_fields'])){ + $query .= ' ,' .db_concat($table, $GLOBALS['dictionary'][$object]['fields'][$field]['db_concat_fields']) . ' as ' . $alias ; + }else if(!empty($GLOBALS['dictionary'][$object]['fields'][$field]) && + (empty($GLOBALS['dictionary'][$object]['fields'][$field]['source']) || + $GLOBALS['dictionary'][$object]['fields'][$field]['source'] != "non-db")) + { + $query .= ' ,' .$table . '.' . $field . ' as ' . $alias; + } + if(!$return_array)$this->$alias = ''; + } + if($query == 'SELECT id' || empty($id)){ + return ''; + } + + + if(isset($GLOBALS['dictionary'][$object]['fields']['assigned_user_id'])) + { + $query .= " , ". $table . ".assigned_user_id owner"; + + } + else if(isset($GLOBALS['dictionary'][$object]['fields']['created_by'])) + { + $query .= " , ". $table . ".created_by owner"; + + } + $query .= ' FROM ' . $table . ' WHERE deleted=0 AND id='; + $result = $GLOBALS['db']->query($query . "'$id'" ); + $row = $GLOBALS['db']->fetchByAssoc($result); + if($return_array){ + return $row; + } + $owner = (empty($row['owner']))?'':$row['owner']; + foreach($fields as $alias){ + $this->$alias = (!empty($row[$alias]))? $row[$alias]: ''; + $alias = $alias .'_owner'; + $this->$alias = $owner; + $a_mod = $alias .'_mod'; + $this->$a_mod = $module; + } + + + } + + + function &parse_additional_headers(&$list_form, $xTemplateSection) + { + return $list_form; + } + + function assign_display_fields($currentModule) + { + global $timedate; + foreach($this->column_fields as $field) + { + if(isset($this->field_name_map[$field]) && empty($this->$field)) + { + if($this->field_name_map[$field]['type'] != 'date' && $this->field_name_map[$field]['type'] != 'enum') + $this->$field = $field; + if($this->field_name_map[$field]['type'] == 'date') + { + $this->$field = $timedate->to_display_date('1980-07-09'); + } + if($this->field_name_map[$field]['type'] == 'enum') + { + $dom = $this->field_name_map[$field]['options']; + global $current_language, $app_list_strings; + $mod_strings = return_module_language($current_language, $currentModule); + + if(isset($mod_strings[$dom])) + { + $options = $mod_strings[$dom]; + foreach($options as $key=>$value) + { + if(!empty($key) && empty($this->$field )) + { + $this->$field = $key; + } + } + } + if(isset($app_list_strings[$dom])) + { + $options = $app_list_strings[$dom]; + foreach($options as $key=>$value) + { + if(!empty($key) && empty($this->$field )) + { + $this->$field = $key; + } + } + } + + + } + } + } + } + + /* + * RELATIONSHIP HANDLING + */ + + function set_relationship($table, $relate_values, $check_duplicates = true,$do_update=false,$data_values=null) + { + $where = ''; + + // make sure there is a date modified + $date_modified = $this->db->convert("'".$GLOBALS['timedate']->nowDb()."'", 'datetime'); + + $row=null; + if($check_duplicates) + { + $query = "SELECT * FROM $table "; + $where = "WHERE deleted = '0' "; + foreach($relate_values as $name=>$value) + { + $where .= " AND $name = '$value' "; + } + $query .= $where; + $result = $this->db->query($query, false, "Looking For Duplicate Relationship:" . $query); + $row=$this->db->fetchByAssoc($result); + } + + if(!$check_duplicates || empty($row) ) + { + unset($relate_values['id']); + if ( isset($data_values)) + { + $relate_values = array_merge($relate_values,$data_values); + } + $query = "INSERT INTO $table (id, ". implode(',', array_keys($relate_values)) . ", date_modified) VALUES ('" . create_guid() . "', " . "'" . implode("', '", $relate_values) . "', ".$date_modified.")" ; + + $this->db->query($query, false, "Creating Relationship:" . $query); + } + else if ($do_update) + { + $conds = array(); + foreach($data_values as $key=>$value) + { + array_push($conds,$key."='".$this->db->quote($value)."'"); + } + $query = "UPDATE $table SET ". implode(',', $conds).",date_modified=".$date_modified." ".$where; + $this->db->query($query, false, "Updating Relationship:" . $query); + } + } + + function retrieve_relationships($table, $values, $select_id) + { + $query = "SELECT $select_id FROM $table WHERE deleted = 0 "; + foreach($values as $name=>$value) + { + $query .= " AND $name = '$value' "; + } + $query .= " ORDER BY $select_id "; + $result = $this->db->query($query, false, "Retrieving Relationship:" . $query); + $ids = array(); + while($row = $this->db->fetchByAssoc($result)) + { + $ids[] = $row; + } + return $ids; + } + + // TODO: this function needs adjustment + function loadLayoutDefs() + { + global $layout_defs; + if(empty( $this->layout_def) && file_exists('modules/'. $this->module_dir . '/layout_defs.php')) + { + include_once('modules/'. $this->module_dir . '/layout_defs.php'); + if(file_exists('custom/modules/'. $this->module_dir . '/Ext/Layoutdefs/layoutdefs.ext.php')) + { + include_once('custom/modules/'. $this->module_dir . '/Ext/Layoutdefs/layoutdefs.ext.php'); + } + if ( empty( $layout_defs[get_class($this)])) + { + echo "\$layout_defs[" . get_class($this) . "]; does not exist"; + } + + $this->layout_def = $layout_defs[get_class($this)]; + } + } + + /** + * Trigger custom logic for this module that is defined for the provided hook + * The custom logic file is located under custom/modules/[CURRENT_MODULE]/logic_hooks.php. + * That file should define the $hook_version that should be used. + * It should also define the $hook_array. The $hook_array will be a two dimensional array + * the first dimension is the name of the event, the second dimension is the information needed + * to fire the hook. Each entry in the top level array should be defined on a single line to make it + * easier to automatically replace this file. There should be no contents of this file that are not replacable. + * + * $hook_array['before_save'][] = Array(1, testtype, 'custom/modules/Leads/test12.php', 'TestClass', 'lead_before_save_1'); + * This sample line creates a before_save hook. The hooks are procesed in the order in which they + * are added to the array. The second dimension is an array of: + * processing index (for sorting before exporting the array) + * A logic type hook + * label/type + * php file to include + * php class the method is in + * php method to call + * + * The method signature for version 1 hooks is: + * function NAME(&$bean, $event, $arguments) + * $bean - $this bean passed in by reference. + * $event - The string for the current event (i.e. before_save) + * $arguments - An array of arguments that are specific to the event. + */ + function call_custom_logic($event, $arguments = null) + { + if(!isset($this->processed) || $this->processed == false){ + //add some logic to ensure we do not get into an infinite loop + if(!empty($this->logicHookDepth[$event])) { + if($this->logicHookDepth[$event] > 10) + return; + }else + $this->logicHookDepth[$event] = 0; + + //we have to put the increment operator here + //otherwise we may never increase the depth for that event in the case + //where one event will trigger another as in the case of before_save and after_save + //Also keeping the depth per event allow any number of hooks to be called on the bean + //and we only will return if one event gets caught in a loop. We do not increment globally + //for each event called. + $this->logicHookDepth[$event]++; + + //method defined in 'include/utils/LogicHook.php' + + $logicHook = new LogicHook(); + $logicHook->setBean($this); + $logicHook->call_custom_logic($this->module_dir, $event, $arguments); + } + } + + + /* When creating a custom field of type Dropdown, it creates an enum row in the DB. + A typical get_list_view_array() result will have the *KEY* value from that drop-down. + Since custom _dom objects are flat-files included in the $app_list_strings variable, + We need to generate a key-key pair to get the true value like so: + ([module]_cstm->fields_meta_data->$app_list_strings->*VALUE*)*/ + function getRealKeyFromCustomFieldAssignedKey($name) + { + if ($this->custom_fields->avail_fields[$name]['ext1']) + { + $realKey = 'ext1'; + } + elseif ($this->custom_fields->avail_fields[$name]['ext2']) + { + $realKey = 'ext2'; + } + elseif ($this->custom_fields->avail_fields[$name]['ext3']) + { + $realKey = 'ext3'; + } + else + { + $GLOBALS['log']->fatal("SUGARBEAN: cannot find Real Key for custom field of type dropdown - cannot return Value."); + return false; + } + if(isset($realKey)) + { + return $this->custom_fields->avail_fields[$name][$realKey]; + } + } + + function bean_implements($interface) + { + return false; + } + /** + * Check whether the user has access to a particular view for the current bean/module + * @param $view string required, the view to determine access for i.e. DetailView, ListView... + * @param $is_owner bool optional, this is part of the ACL check if the current user is an owner they will receive different access + */ + function ACLAccess($view,$is_owner='not_set') + { + global $current_user; + if(is_admin($current_user)||is_admin_for_module($current_user,$this->getACLCategory()))return true; + $not_set = false; + if($is_owner == 'not_set') + { + $not_set = true; + $is_owner = $this->isOwner($current_user->id); + } + + //if we don't implent acls return true + if(!$this->bean_implements('ACL')) + return true; + $view = strtolower($view); + switch ($view) + { + case 'list': + case 'index': + case 'listview': + return ACLController::checkAccess($this->module_dir,'list', true); + case 'edit': + case 'save': + if( !$is_owner && $not_set && !empty($this->id)){ + $class = get_class($this); + $temp = new $class(); + if(!empty($this->fetched_row) && !empty($this->fetched_row['id']) && !empty($this->fetched_row['assigned_user_id']) && !empty($this->fetched_row['created_by'])){ + $temp->populateFromRow($this->fetched_row); + }else{ + $temp->retrieve($this->id); + } + $is_owner = $temp->isOwner($current_user->id); + } + case 'popupeditview': + case 'editview': + return ACLController::checkAccess($this->module_dir,'edit', $is_owner, $this->acltype); + case 'view': + case 'detail': + case 'detailview': + return ACLController::checkAccess($this->module_dir,'view', $is_owner, $this->acltype); + case 'delete': + return ACLController::checkAccess($this->module_dir,'delete', $is_owner, $this->acltype); + case 'export': + return ACLController::checkAccess($this->module_dir,'export', $is_owner, $this->acltype); + case 'import': + return ACLController::checkAccess($this->module_dir,'import', true, $this->acltype); + } + //if it is not one of the above views then it should be implemented on the page level + return true; + } + /** + * Returns true of false if the user_id passed is the owner + * + * @param GUID $user_id + * @return boolean + */ + function isOwner($user_id) + { + //if we don't have an id we must be the owner as we are creating it + if(!isset($this->id)) + { + return true; + } + //if there is an assigned_user that is the owner + if(isset($this->assigned_user_id)) + { + if($this->assigned_user_id == $user_id) return true; + return false; + } + else + { + //other wise if there is a created_by that is the owner + if(isset($this->created_by) && $this->created_by == $user_id) + { + return true; + } + } + return false; + } + /** + * Gets there where statement for checking if a user is an owner + * + * @param GUID $user_id + * @return STRING + */ + function getOwnerWhere($user_id) + { + if(isset($this->field_defs['assigned_user_id'])) + { + return " $this->table_name.assigned_user_id ='$user_id' "; + } + if(isset($this->field_defs['created_by'])) + { + return " $this->table_name.created_by ='$user_id' "; + } + return ''; + } + + /** + * + * Used in order to manage ListView links and if they should + * links or not based on the ACL permissions of the user + * + * @return ARRAY of STRINGS + */ + function listviewACLHelper() + { + $array_assign = array(); + if($this->ACLAccess('DetailView')) + { + $array_assign['MAIN'] = 'a'; + } + else + { + $array_assign['MAIN'] = 'span'; + } + return $array_assign; + } + + /** + * returns this bean as an array + * + * @return array of fields with id, name, access and category + */ + function toArray($dbOnly = false, $stringOnly = false, $upperKeys=false) + { + static $cache = array(); + $arr = array(); + + foreach($this->field_defs as $field=>$data) + { + if( !$dbOnly || !isset($data['source']) || $data['source'] == 'db') + if(!$stringOnly || is_string($this->$field)) + if($upperKeys) + { + if(!isset($cache[$field])){ + $cache[$field] = strtoupper($field); + } + $arr[$cache[$field]] = $this->$field; + } + else + { + if(isset($this->$field)){ + $arr[$field] = $this->$field; + }else{ + $arr[$field] = ''; + } + } + } + return $arr; + } + + /** + * Converts an array into an acl mapping name value pairs into files + * + * @param Array $arr + */ + function fromArray($arr) + { + foreach($arr as $name=>$value) + { + $this->$name = $value; + } + } + + /** + * Loads a row of data into instance of a bean. The data is passed as an array to this function + * + * @param array $arr row of data fetched from the database. + * @return nothing + * + * Internal function do not override. + */ + function loadFromRow($arr) + { + $this->populateFromRow($arr); + $this->processed_dates_times = array(); + $this->check_date_relationships_load(); + + $this->fill_in_additional_list_fields(); + + if($this->hasCustomFields())$this->custom_fields->fill_relationships(); + $this->call_custom_logic("process_record"); + } + + function hasCustomFields(){ + return !empty($GLOBALS['dictionary'][$this->object_name]['custom_fields']); + } + + /** + * Ensure that fields within order by clauses are properly qualified with + * their tablename. This qualification is a requirement for sql server support. + * + * @param string $order_by original order by from the query + * @param string $qualify prefix for columns in the order by list. + * @return prefixed + * + * Internal function do not override. + */ + function create_qualified_order_by( $order_by, $qualify) + { // if the column is empty, but the sort order is defined, the value will throw an error, so do not proceed if no order by is given + if (empty($order_by)) + { + return $order_by; + } + $order_by_clause = " ORDER BY "; + $tmp = explode(",", $order_by); + $comma = ' '; + foreach ( $tmp as $stmp) + { + $stmp = (substr_count($stmp, ".") > 0?trim($stmp):"$qualify." . trim($stmp)); + $order_by_clause .= $comma . $stmp; + $comma = ", "; + } + return $order_by_clause; + } + + /** + * Combined the contents of street field 2 thru 4 into the main field + * + * @param string $street_field + */ + + function add_address_streets( + $street_field + ) + { + $street_field_2 = $street_field.'_2'; + $street_field_3 = $street_field.'_3'; + $street_field_4 = $street_field.'_4'; + if ( isset($this->$street_field_2)) { + $this->$street_field .= "\n". $this->$street_field_2; + unset($this->$street_field_2); + } + if ( isset($this->$street_field_3)) { + $this->$street_field .= "\n". $this->$street_field_3; + unset($this->$street_field_3); + } + if ( isset($this->$street_field_4)) { + $this->$street_field .= "\n". $this->$street_field_4; + unset($this->$street_field_4); + } + if ( isset($this->$street_field)) { + $this->$street_field = trim($this->$street_field, "\n"); + } + } +/** + * Encrpyt and base64 encode an 'encrypt' field type in the bean using Blowfish. The default system key is stored in cache/Blowfish/{keytype} + * @param STRING value -plain text value of the bean field. + * @return string + */ + function encrpyt_before_save($value) + { + require_once("include/utils/encryption_utils.php"); + return blowfishEncode(blowfishGetKey('encrypt_field'),$value); + } + +/** + * Decode and decrypt a base 64 encoded string with field type 'encrypt' in this bean using Blowfish. + * @param STRING value - an encrypted and base 64 encoded string. + * @return string + */ + function decrypt_after_retrieve($value) + { + require_once("include/utils/encryption_utils.php"); + return blowfishDecode(blowfishGetKey('encrypt_field'), $value); + } + + /** + * Moved from save() method, functionality is the same, but this is intended to handle + * Optimistic locking functionality. + */ + private function _checkOptimisticLocking($action, $isUpdate){ + if($this->optimistic_lock && !isset($_SESSION['o_lock_fs'])){ + if(isset($_SESSION['o_lock_id']) && $_SESSION['o_lock_id'] == $this->id && $_SESSION['o_lock_on'] == $this->object_name) + { + if($action == 'Save' && $isUpdate && isset($this->modified_user_id) && $this->has_been_modified_since($_SESSION['o_lock_dm'], $this->modified_user_id)) + { + $_SESSION['o_lock_class'] = get_class($this); + $_SESSION['o_lock_module'] = $this->module_dir; + $_SESSION['o_lock_object'] = $this->toArray(); + $saveform = "
"; + foreach($_POST as $key=>$arg) + { + $saveform .= ""; + } + $saveform .= "
"; + $_SESSION['o_lock_save'] = $saveform; + header('Location: index.php?module=OptimisticLock&action=LockResolve'); + die(); + } + else + { + unset ($_SESSION['o_lock_object']); + unset ($_SESSION['o_lock_id']); + unset ($_SESSION['o_lock_dm']); + } + } + } + else + { + if(isset($_SESSION['o_lock_object'])) { unset ($_SESSION['o_lock_object']); } + if(isset($_SESSION['o_lock_id'])) { unset ($_SESSION['o_lock_id']); } + if(isset($_SESSION['o_lock_dm'])) { unset ($_SESSION['o_lock_dm']); } + if(isset($_SESSION['o_lock_fs'])) { unset ($_SESSION['o_lock_fs']); } + if(isset($_SESSION['o_lock_save'])) { unset ($_SESSION['o_lock_save']); } + } + } + + /** + * Send assignment notifications and invites for meetings and calls + */ + private function _sendNotifications($check_notify){ + if($check_notify || (isset($this->notify_inworkflow) && $this->notify_inworkflow == true)){ // cn: bug 5795 - no invites sent to Contacts, and also bug 25995, in workflow, it will set the notify_on_save=true. + + $admin = new Administration(); + $admin->retrieveSettings(); + $sendNotifications = false; + + if ($admin->settings['notify_on']) + { + $GLOBALS['log']->info("Notifications: user assignment has changed, checking if user receives notifications"); + $sendNotifications = true; + } + elseif(isset($_REQUEST['send_invites']) && $_REQUEST['send_invites'] == 1) + { + // cn: bug 5795 Send Invites failing for Contacts + $sendNotifications = true; + } + else + { + $GLOBALS['log']->info("Notifications: not sending e-mail, notify_on is set to OFF"); + } + + + if($sendNotifications == true) + { + $notify_list = $this->get_notification_recipients(); + foreach ($notify_list as $notify_user) + { + $this->send_assignment_notifications($notify_user, $admin); + } + } + } + } + + + /** + * Called from ImportFieldSanitize::relate(), when creating a new bean in a related module. Will + * copies fields over from the current bean into the related. Designed to be overriden in child classes. + * + * @param SugarBean $newbean newly created related bean + */ + public function populateRelatedBean( + SugarBean $newbean + ) + { + } + + /** + * Called during the import process before a bean save, to handle any needed pre-save logic when + * importing a record + */ + public function beforeImportSave() + { + } + + /** + * Called during the import process after a bean save, to handle any needed post-save logic when + * importing a record + */ + public function afterImportSave() + { + } + + /** + * This function is designed to cache references to field arrays that were previously stored in the + * bean files and have since been moved to seperate files. Was previously in include/CacheHandler.php + * + * @deprecated + * @param $module_dir string the module directory + * @param $module string the name of the module + * @param $key string the type of field array we are referencing, i.e. list_fields, column_fields, required_fields + **/ + private function _loadCachedArray( + $module_dir, + $module, + $key + ) + { + static $moduleDefs = array(); + + $fileName = 'field_arrays.php'; + + $cache_key = "load_cached_array.$module_dir.$module.$key"; + $result = sugar_cache_retrieve($cache_key); + if(!empty($result)) + { + // Use SugarCache::EXTERNAL_CACHE_NULL_VALUE to store null values in the cache. + if($result == SugarCache::EXTERNAL_CACHE_NULL_VALUE) + { + return null; + } + + return $result; + } + + if(file_exists('modules/'.$module_dir.'/'.$fileName)) + { + // If the data was not loaded, try loading again.... + if(!isset($moduleDefs[$module])) + { + include('modules/'.$module_dir.'/'.$fileName); + $moduleDefs[$module] = $fields_array; + } + // Now that we have tried loading, make sure it was loaded + if(empty($moduleDefs[$module]) || empty($moduleDefs[$module][$module][$key])) + { + // It was not loaded.... Fail. Cache null to prevent future repeats of this calculation + sugar_cache_put($cache_key, SugarCache::EXTERNAL_CACHE_NULL_VALUE); + return null; + } + + // It has been loaded, cache the result. + sugar_cache_put($cache_key, $moduleDefs[$module][$module][$key]); + return $moduleDefs[$module][$module][$key]; + } + + // It was not loaded.... Fail. Cache null to prevent future repeats of this calculation + sugar_cache_put($cache_key, SugarCache::EXTERNAL_CACHE_NULL_VALUE); + return null; + } + + /** + * Returns the ACL category for this module; defaults to the SugarBean::$acl_category if defined + * otherwise it is SugarBean::$module_dir + * + * @return string + */ + public function getACLCategory() + { + return !empty($this->acl_category)?$this->acl_category:$this->module_dir; + } + + /** + * Returns the query used for the export functionality for a module. Override this method if you wish + * to have a custom query to pull this data together instead + * + * @param string $order_by + * @param string $where + * @return string SQL query + */ + public function create_export_query($order_by, $where) + { + return $this->create_new_list_query($order_by, $where, array(), array(), 0, '', false, $this, true); + } +} diff --git a/data/Tracker.php b/data/Tracker.php new file mode 100644 index 00000000..a53f8fed --- /dev/null +++ b/data/Tracker.php @@ -0,0 +1,50 @@ + \ No newline at end of file diff --git a/data/upload/index.html b/data/upload/index.html new file mode 100644 index 00000000..f9236827 --- /dev/null +++ b/data/upload/index.html @@ -0,0 +1 @@ +This directory must be writable by the webserver user. \ No newline at end of file diff --git a/dictionary.php b/dictionary.php new file mode 100644 index 00000000..f3127aa9 --- /dev/null +++ b/dictionary.php @@ -0,0 +1,42 @@ + diff --git a/download.php b/download.php new file mode 100644 index 00000000..e7ef57f6 --- /dev/null +++ b/download.php @@ -0,0 +1,180 @@ +retrieve($_SESSION['authenticated_user_id']); + $GLOBALS['current_language'] = $_SESSION['authenticated_user_language']; + $app_strings = return_application_language($GLOBALS['current_language']); + $mod_strings = return_module_language($GLOBALS['current_language'], 'ACL'); + if(!isset($_REQUEST['isTempFile'])) { + //Custom modules may have capilizations anywhere in thier names. We should check the passed in format first. + require('include/modules.php'); + $module = $db->quote($_REQUEST['type']); + $file_type = strtolower($_REQUEST['type']); + if(empty($beanList[$module])) { + //start guessing at a module name + $module = ucfirst($file_type); + if(empty($beanList[$module])) { + die($app_strings['ERROR_TYPE_NOT_VALID']); + } + } + $bean_name = $beanList[$module]; + if(!file_exists('modules/' . $module . '/' . $bean_name . '.php')) { + die($app_strings['ERROR_TYPE_NOT_VALID']); + } + require_once('modules/' . $module . '/' . $bean_name . '.php'); + $focus = new $bean_name(); + $focus->retrieve($_REQUEST['id']); + if(!$focus->ACLAccess('view')){ + die($mod_strings['LBL_NO_ACCESS']); + } // if + + // Pull up the document revision, if it's of type Document + if ( isset($focus->object_name) && $focus->object_name == 'Document' ) { + // It's a document, get the revision that really stores this file + $focusRevision = new DocumentRevision(); + $focusRevision->retrieve($_REQUEST['id']); + + if ( empty($focusRevision->id) ) { + // This wasn't a document revision id, it's probably actually a document id, we need to grab that, get the latest revision and use that + $focusDocument = new Document(); + $focusDocument->retrieve($_REQUEST['id']); + + $focusRevision->retrieve($focusDocument->document_revision_id); + + if ( !empty($focusRevision->id) ) { + $_REQUEST['id'] = $focusRevision->id; + } + } + } + + // See if it is a remote file, if so, send them that direction + if ( isset($focus->doc_url) && !empty($focus->doc_url) ) { + header('Location: '.$focus->doc_url); + sugar_die(); + } + + if ( isset($focusRevision) && isset($focusRevision->doc_url) && !empty($focusRevision->doc_url) ) { + header('Location: '.$focusRevision->doc_url); + sugar_die(); + } + + } // if + + $local_location = (isset($_REQUEST['isTempFile'])) ? "{$GLOBALS['sugar_config']['cache_dir']}/modules/Emails/{$_REQUEST['ieId']}/attachments/{$_REQUEST['id']}" + : $GLOBALS['sugar_config']['upload_dir']."/".$_REQUEST['id']; + + if(isset($_REQUEST['isTempFile']) && ($_REQUEST['type']=="SugarFieldImage")) { + $local_location = $GLOBALS['sugar_config']['upload_dir']."/".$_REQUEST['id']; + } + + if(!file_exists( $local_location ) || strpos($local_location, "..")) { + die($app_strings['ERR_INVALID_FILE_REFERENCE']); + } + else { + $doQuery = true; + + if($file_type == 'documents') { + // cn: bug 9674 document_revisions table has no 'name' column. + $query = "SELECT filename name FROM document_revisions INNER JOIN documents ON documents.id = document_revisions.document_id "; + $query .= "WHERE document_revisions.id = '".$db->quote($_REQUEST['id'])."' "; + } elseif($file_type == 'kbdocuments') { + $query="SELECT document_revisions.filename name FROM document_revisions INNER JOIN kbdocument_revisions ON document_revisions.id = kbdocument_revisions.document_revision_id INNER JOIN kbdocuments ON kbdocument_revisions.kbdocument_id = kbdocuments.id "; + $query .= "WHERE document_revisions.id = '" . $db->quote($_REQUEST['id']) ."'"; + } elseif($file_type == 'notes') { + $query = "SELECT filename name FROM notes "; + $query .= "WHERE notes.id = '" . $db->quote($_REQUEST['id']) ."'"; + } elseif( !isset($_REQUEST['isTempFile']) && !isset($_REQUEST['tempName'] ) && isset($_REQUEST['type']) && $file_type!='temp' ){ //make sure not email temp file. + $query = "SELECT filename name FROM ". $file_type ." "; + $query .= "WHERE ". $file_type .".id= '".$db->quote($_REQUEST['id'])."'"; + }elseif( $file_type == 'temp'){ + $doQuery = false; + } + + if($doQuery && isset($query)) { + $rs = $GLOBALS['db']->query($query); + $row = $GLOBALS['db']->fetchByAssoc($rs); + + if(empty($row)){ + die($app_strings['ERROR_NO_RECORD']); + } + $name = $row['name']; + $download_location = $GLOBALS['sugar_config']['upload_dir']."/".$_REQUEST['id']; + } else if(isset( $_REQUEST['tempName'] ) && isset($_REQUEST['isTempFile']) ){ + // downloading a temp file (email 2.0) + $download_location = $local_location; + $name = $_REQUEST['tempName']; + } + else if(isset($_REQUEST['isTempFile']) && ($_REQUEST['type']=="SugarFieldImage")) { + $download_location = $local_location; + $name = $_REQUEST['tempName']; + } + + if(isset($_SERVER['HTTP_USER_AGENT']) && preg_match("/MSIE/", $_SERVER['HTTP_USER_AGENT'])) + { + $name = urlencode($name); + $name = str_replace("+", "_", $name); + } + + header("Pragma: public"); + header("Cache-Control: maxage=1, post-check=0, pre-check=0"); + if(isset($_REQUEST['isTempFile']) && ($_REQUEST['type']=="SugarFieldImage")) + header("Content-type: image"); + else { + header("Content-type: application/force-download"); + header("Content-disposition: attachment; filename=\"".$name."\";"); + } + header("Content-Length: " . filesize($local_location)); + header("Expires: 0"); + set_time_limit(0); + + @ob_end_clean(); + ob_start(); + + echo file_get_contents($download_location); + @ob_flush(); + } +} +?> diff --git a/emailmandelivery.php b/emailmandelivery.php new file mode 100644 index 00000000..023b4c2d --- /dev/null +++ b/emailmandelivery.php @@ -0,0 +1,41 @@ + \ No newline at end of file diff --git a/examples/EXAMPLES_README.txt b/examples/EXAMPLES_README.txt new file mode 100644 index 00000000..cf7e212d --- /dev/null +++ b/examples/EXAMPLES_README.txt @@ -0,0 +1,7 @@ +To enable access to the ./examples/ directory, open .htaccess in the main Sugar directory and find the following line: + + RedirectMatch /dev/sugar/maint450/examples/(.*).php http://julian/dev/sugar/maint450/index.php + +Change it to: + + # RedirectMatch /dev/sugar/maint450/examples/(.*).php http://julian/dev/sugar/maint450/index.php \ No newline at end of file diff --git a/examples/ExampleLeadCapture.php b/examples/ExampleLeadCapture.php new file mode 100644 index 00000000..1a69dd74 --- /dev/null +++ b/examples/ExampleLeadCapture.php @@ -0,0 +1,70 @@ + + +
+ + + + +
+ Please fill out this form so we can better server your game playing and food eating needs. It will redirect you to the form validation test. +
+ + + + + + + +
First Name:
Last Name:
Company Name:
Title:
Favorite Game:
Favorite Food:
+ \ No newline at end of file diff --git a/examples/FormValidationTest.php b/examples/FormValidationTest.php new file mode 100644 index 00000000..bb13b626 --- /dev/null +++ b/examples/FormValidationTest.php @@ -0,0 +1,61 @@ + + + +
+ + + + + + + + +
*Name:
*Email:
Address:
Time:
Date:
Amount:$
+ +
+ diff --git a/examples/ProgressBarTest.php b/examples/ProgressBarTest.php new file mode 100644 index 00000000..a791f2aa --- /dev/null +++ b/examples/ProgressBarTest.php @@ -0,0 +1,48 @@ + \ No newline at end of file diff --git a/examples/SoapTest.php b/examples/SoapTest.php new file mode 100644 index 00000000..dd347ba2 --- /dev/null +++ b/examples/SoapTest.php @@ -0,0 +1,122 @@ +$value){ + $$name = $value; +} +echo << + + + + + + +
Enter SugarCRM User Information - this is the same info entered when logging into sugarcrm
USER NAME:USER PASSWORD:
+ + + +EOQ; +if(!empty($user_name)){ +$offset = 0; +if(isset($_REQUEST['offset'])){ + $offset = $_REQUEST['offset'] + 20; + echo $offset; +} +require_once('include/nusoap/nusoap.php'); //must also have the nusoap code on the ClientSide. +$soapclient = new nusoapclient($GLOBALS['sugar_config']['site_url'].'/soap.php'); //define the SOAP Client an + +echo 'LOGIN:
'; +$result = $soapclient->call('login',array('user_auth'=>array('user_name'=>$user_name,'password'=>md5($user_password), 'version'=>'.01'), 'application_name'=>'SoapTest')); +echo 'HERE IS ERRORS:
'; +echo $soapclient->error_str; + +echo '

HERE IS RESPONSE:
'; +echo $soapclient->response; + +echo '

HERE IS RESULT:
'; +echo print_r($result); +$session = $result['id']; + +echo '

GET Case fields:
'; +$result = $soapclient->call('get_module_fields',array('session'=>$session , 'module_name'=>'Cases')); +echo 'HERE IS ERRORS:
'; +echo $soapclient->error_str; + +echo '

HERE IS RESPONSE:
'; +echo $soapclient->response; + +echo '

HERE IS RESULT:
'; +echo print_r($result); + +echo '

Update a portal user fields:
'; +$result = $soapclient->call('update_portal_user',array('session'=>$session,'portal_name'=>'dan','name_value_list'=>array(array('name'=>'email1', 'value'=>'Dan_Aarons@example.com')))); +echo 'HERE IS ERRORS:
'; +echo $soapclient->error_str; + +echo '

HERE IS RESPONSE:
'; +echo $soapclient->response; + +echo '

HERE IS RESULT:
'; +echo print_r($result); + +echo '

Get list of contacts:
'; +$result = $soapclient->call('get_entry_list',array('session'=>$session,'module_name'=>'Contacts','query'=>'','order_by'=>'contacts.last_name asc','offset'=>$offset, 'select_fields'=>array(), 'max_results'=>'5')); +echo 'HERE IS ERRORS:
'; +echo $soapclient->error_str; + +echo '

HERE IS RESPONSE:
'; +echo $soapclient->response; + +echo '

HERE IS RESULT:
'; +echo print_r($result); + +echo '

LOGOUT:
'; +$result = $soapclient->call('logout',array('session'=>$session)); +echo 'HERE IS ERRORS:
'; +echo $soapclient->error_str; + +echo '

HERE IS RESPONSE:
'; +echo $soapclient->response; + +echo '

HERE IS RESULT:
'; +echo print_r($result); + +} +?> \ No newline at end of file diff --git a/examples/SoapTestPortal.php b/examples/SoapTestPortal.php new file mode 100644 index 00000000..34303baf --- /dev/null +++ b/examples/SoapTestPortal.php @@ -0,0 +1,262 @@ +$value){ + $$name = $value; +} +echo << + + + + + + + + + +
Enter SugarCRM Portal User Information (to configure this login to SugarCRM as an admin and go the administration panel then select a user from user management)
PORTAL NAME:PORTAL PASSWORD:
Enter SugarCRM Portal Contact Information (to configure this login to SugarCRM as an admin and edit a contact. You will see Portal Information at the bottom of the Contact EditView Panel)
CONTACT NAME:
+ + + +EOQ; + +if(!empty($portal_name)){ +$portal_password = md5($portal_password); +require_once('../include/nusoap/nusoap.php'); //must also have the nusoap code on the ClientSide. +$soapclient = new nusoapclient('http://localhost/sugarcrm/soap.php'); //define the SOAP Client an +//application_name is the client application connecting to sugar CRM for example mambo +echo 'LOGIN:
'; +$result = $soapclient->call('portal_login',array('portal_auth'=>array('user_name'=>$portal_name,'password'=>$portal_password, 'version'=>'.01'),'user_name'=>$user_name, 'application_name'=>'SoapTestPortal')); +echo 'HERE IS ERRORS:
'; +echo $soapclient->error_str; + +echo '

HERE IS RESPONSE:
'; +echo $soapclient->response; +echo '

'; +echo $soapclient->responseHeaders; + +echo '

HERE IS RESULT:
'; +echo print_r($result); +$session = $result['id']; +echo '

GET CASES:
'; +$result = $soapclient->call('portal_get_entry_list',array('session'=>$session , 'module_name'=>'Cases','where'=>"date_entered > '".date($GLOBALS['timedate']->dbDayFormat) ."'", 'order_by'=>'', 'select_fields'=>array('name', 'description', 'priority', 'status'))); +echo 'HERE IS ERRORS:
'; +echo $soapclient->error_str; + +echo '

HERE IS RESPONSE:
'; +echo $soapclient->response; + +echo '

HERE IS RESULT:
'; +echo print_r($result); +$case_id = $result['entry_list'][0]['id']; + +echo '

GET Case fields:
'; +$result = $soapclient->call('portal_get_module_fields',array('session'=>$session , 'module_name'=>'Cases')); +echo 'HERE IS ERRORS:
'; +echo $soapclient->error_str; + +echo '

HERE IS RESPONSE:
'; +echo $soapclient->response; + +echo '

HERE IS RESULT:
'; +echo print_r($result); + +echo '

CREATE Case:
'; +$result = $soapclient->call('portal_set_entry',array('session'=>$session , 'module_name'=>'Cases', 'name_value_list'=>array(array('name'=>'name', 'value'=>'a case'), array('name'=>'description', 'value'=>'A case created through webservices')))); +echo 'HERE IS ERRORS:
'; +echo $soapclient->error_str; + +echo '

HERE IS RESPONSE:
'; +echo $soapclient->response; + +echo '

HERE IS RESULT:
'; +echo print_r($result); + +$case_id = $result['id']; +echo '

CREATE Note:
'; +$result = $soapclient->call('portal_set_entry',array('session'=>$session , 'module_name'=>'Notes', 'name_value_list'=>array(array('name'=>'name', 'value'=>'a note attached to a case'), array('name'=>'description', 'value'=>'A note created through webservices')))); +echo 'HERE IS ERRORS:
'; +echo $soapclient->error_str; + +echo '

HERE IS RESPONSE:
'; +echo $soapclient->response; + +echo '

HERE IS RESULT:
'; +echo print_r($result); +$note_id = $result['id']; +echo '

ATTACH A FILE:
'; +$file = base64_encode('this would be the contents of your file'); +$result = $soapclient->call('portal_set_note_attachment',array('session'=>$session, 'note_attachment'=>array('id'=>$note_id, 'filename'=>'an attached file', 'file'=>$file))); +echo 'HERE IS ERRORS:
'; +echo $soapclient->error_str; + +echo '

HERE IS RESPONSE:
'; +echo $soapclient->response; + +echo '

HERE IS RESULT:
'; +echo print_r($result); + +echo '

ATTACH NOTE TO THE CASE:
'; + +$result = $soapclient->call('portal_relate_note_to_module',array('session'=>$session, 'note_id'=>$note_id, 'module_name'=>'Cases', 'module_id'=>$case_id)); +echo 'HERE IS ERRORS:
'; +echo $soapclient->error_str; + +echo '

HERE IS RESPONSE:
'; +echo $soapclient->response; + +echo '

HERE IS RESULT:
'; +echo print_r($result); + +echo '

GET NOTES RELATED TO A CASE:
'; +$result = $soapclient->call('portal_get_related_notes',array('session'=>$session , 'module_name'=>'Cases', 'module_id'=>$case_id, 'select_fields'=>array('name', 'description', 'filename'))); +echo 'HERE IS ERRORS:
'; +echo $soapclient->error_str; + +echo '

HERE IS RESPONSE:
'; +echo $soapclient->response; + +echo '

HERE IS RESULT:
'; +echo print_r($result); +$note_id = $result['entry_list'][0]['id']; + +echo '

GET ATTACHMENT TO A NOTE:
'; +$result = $soapclient->call('portal_get_note_attachment',array('session'=>$session , 'id'=>$note_id)); +echo 'HERE IS ERRORS:
'; +echo $soapclient->error_str; + +echo '

HERE IS RESPONSE:
'; +echo $soapclient->response; + +echo '

HERE IS RESULT:
'; +echo print_r($result); + +echo '
It Reads:' . base64_decode($result['note_attachment']['file']); + +echo '

LOGOUT:
'; +$result = $soapclient->call('portal_logout',array('session'=>$session)); +echo 'HERE IS ERRORS:
'; +echo $soapclient->error_str; + +echo '

HERE IS RESPONSE:
'; +echo $soapclient->response; + +echo '

HERE IS RESULT:
'; +echo print_r($result); + + +echo 'LOG BACK IN:
'; +$result = $soapclient->call('portal_login',array('portal_auth'=>array('user_name'=>$portal_name,'password'=>$portal_password, 'version'=>'.01'),'user_name'=>$user_name, 'application_name'=>'SoapTestPortal')); +echo 'HERE IS ERRORS:
'; +echo $soapclient->error_str; + +echo '

HERE IS RESPONSE:
'; +echo $soapclient->response; + +echo '

HERE IS RESULT:
'; +echo print_r($result); +$session = $result['id']; + + +echo '

GET CASES:
'; +$result = $soapclient->call('portal_get_entry_list',array('session'=>$session , 'module_name'=>'Cases','where'=>"date_entered > '".date($GLOBALS['timedate']->dbDayFormat) ."'", 'order_by'=>'', 'select_fields'=>array('name', 'description', 'priority', 'status'))); +echo 'HERE IS ERRORS:
'; +echo $soapclient->error_str; + +echo '

HERE IS RESPONSE:
'; +echo $soapclient->response; + +echo '

HERE IS RESULT:
'; +echo print_r($result); +$case_id = $result['entry_list'][0]['id']; +//FOR AUTHENTICATION YOU MUST DO A LOOK UP OF CASES BEFORE YOU TRY TO GET A NOTE RELATED TO A CASE +echo '

GET NOTES RELATED TO A CASE:
'; +$result = $soapclient->call('portal_get_related_notes',array('session'=>$session , 'module_name'=>'Cases', 'module_id'=>$case_id, 'select_fields'=>array('name', 'description', 'filename'))); +echo 'HERE IS ERRORS:
'; +echo $soapclient->error_str; + +echo '

HERE IS RESPONSE:
'; +echo $soapclient->response; + +echo '

HERE IS RESULT:
'; +echo print_r($result); +$note_id = $result['entry_list'][0]['id']; + +echo '

GET ATTACHMENT TO A NOTE:
'; +$result = $soapclient->call('portal_get_note_attachment',array('session'=>$session , 'id'=>$note_id)); +echo 'HERE IS ERRORS:
'; +echo $soapclient->error_str; + +echo '

HERE IS RESPONSE:
'; +echo $soapclient->response; + +echo '

HERE IS RESULT:
'; +echo print_r($result); +//does not have accesss to this case +$case_id = 'bf90ee6f-c7fa-520c-f4b4-4212a55eb969'; +echo '

GET NOTES RELATED TO A CASE NOT RELATED TO THE LOGGED IN CONTACT:
'; +$result = $soapclient->call('portal_get_related_notes',array('session'=>$session , 'module_name'=>'Cases', 'module_id'=>$case_id, 'select_fields'=>array('name', 'description'))); +echo 'HERE IS ERRORS:
'; +echo $soapclient->error_str; + +echo '

HERE IS RESPONSE:
'; +echo $soapclient->response; + +echo '

HERE IS RESULT:
'; +echo print_r($result); +$note_id = $result['entry_list'][0]['id']; + + + +echo '

LOGOUT:
'; +$result = $soapclient->call('portal_logout',array('session'=>$session)); +echo 'HERE IS ERRORS:
'; +echo $soapclient->error_str; + +echo '

HERE IS RESPONSE:
'; +echo $soapclient->response; + +echo '

HERE IS RESULT:
'; +echo print_r($result); + +} +?> \ No newline at end of file diff --git a/examples/SoapTestPortal2.php b/examples/SoapTestPortal2.php new file mode 100644 index 00000000..2ae5e136 --- /dev/null +++ b/examples/SoapTestPortal2.php @@ -0,0 +1,105 @@ +$value){ + $$name = $value; +} +echo << + + + + + + + + + +
Enter SugarCRM Portal User Information (to configure this login to SugarCRM as an admin and go the administration panel then select a user from user management)
PORTAL NAME:PORTAL PASSWORD:
Use the name 'lead' and password 'lead' for portal lead generation
CONTACT NAME:
+ + + +EOQ; +if(!empty($portal_name)){ +$portal_password = md5($portal_password); +require_once('include/nusoap/nusoap.php'); //must also have the nusoap code on the ClientSide. +$soapclient = new nusoapclient($GLOBALS['sugar_config']['site_url'].'/soap.php'); //define the SOAP Client an + +echo 'LOGIN:
'; +$result = $soapclient->call('portal_login',array('portal_auth'=>array('user_name'=>$portal_name,'password'=>$portal_password, 'version'=>'.01'),'user_name'=>$user_name, 'application_name'=>'SoapTestPortal')); +echo 'HERE IS ERRORS:
'; +echo $soapclient->error_str; + +echo '

HERE IS RESPONSE:
'; +echo $soapclient->response; + +echo '

HERE IS RESULT:
'; +echo print_r($result); +$session = $result['id']; + + +echo '

CREATE LEAD:
'; +$result = $soapclient->call('portal_set_entry',array('session'=>$session , 'module_name'=>'Leads', 'name_value_list'=>array(array('name'=>'first_name', 'value'=>'Test'), array('name'=>'last_name', 'value'=>'Lead'), array('name'=>'portal_name', 'value'=>'portal_name'), array('name'=>'portal_app', 'value'=>'SoapTestPortal'), array('name'=>'description', 'value'=>'A lead created through webservices')))); +echo 'HERE IS ERRORS:
'; +echo $soapclient->error_str; + +echo '

HERE IS RESPONSE:
'; +echo $soapclient->response; + +echo '

HERE IS RESULT:
'; +echo print_r($result); + + + + +echo '

LOGOUT:
'; +$result = $soapclient->call('portal_logout',array('session'=>$session)); +echo 'HERE IS ERRORS:
'; +echo $soapclient->error_str; + +echo '

HERE IS RESPONSE:
'; +echo $soapclient->response; + +echo '

HERE IS RESULT:
'; +echo print_r($result); +} + +?> \ No newline at end of file diff --git a/export.php b/export.php new file mode 100644 index 00000000..ecce4584 --- /dev/null +++ b/export.php @@ -0,0 +1,78 @@ +id,$the_module, 'access') == ACL_ALLOW_ENABLED && + (ACLAction::getUserAccessLevel($current_user->id, $the_module, 'admin') == ACL_ALLOW_ADMIN || + ACLAction::getUserAccessLevel($current_user->id, $the_module, 'admin') == ACL_ALLOW_ADMIN_DEV))))){ + die($GLOBALS['app_strings']['ERR_EXPORT_DISABLED']); +} + +if(!empty($_REQUEST['uid'])){ + $content = export(clean_string($_REQUEST['module']), $_REQUEST['uid'], isset($_REQUEST['members']) ? $_REQUEST['members'] : false); +}else{ + $content = export(clean_string($_REQUEST['module'])); +} +$filename = $_REQUEST['module']; +if($_REQUEST['members'] == true) + $filename .= '_'.'members'; +/////////////////////////////////////////////////////////////////////////////// +//// BUILD THE EXPORT FILE +ob_clean(); +header("Pragma: cache"); +header("Content-type: application/octet-stream; charset=".$GLOBALS['locale']->getExportCharset()); +header("Content-Disposition: attachment; filename={$filename}.csv"); +header("Content-transfer-encoding: binary"); +header("Expires: Mon, 26 Jul 1997 05:00:00 GMT" ); +header("Last-Modified: " . TimeDate::httpTime() ); +header("Cache-Control: post-check=0, pre-check=0", false ); +header("Content-Length: ".strlen($content)); + +print $GLOBALS['locale']->translateCharset($content, 'UTF-8', $GLOBALS['locale']->getExportCharset()); + +sugar_cleanup(true); +?> \ No newline at end of file diff --git a/files.md5 b/files.md5 new file mode 100644 index 00000000..3005a4f5 --- /dev/null +++ b/files.md5 @@ -0,0 +1,5781 @@ + 'd3f150e4a5bed444763ebe8a81742a95', + './.htaccess' => 'd41d8cd98f00b204e9800998ecf8427e', + './config.php' => 'd41d8cd98f00b204e9800998ecf8427e', + './vcal_server.php' => '71af6a5b63afd073c3b9f54346072ef2', + './vCard.php' => 'fad02d68a8a43a6498ecd71b9edc8e90', + './themes/default/js/style.js' => 'de82df7a57a937110f3fa1ed85e752bb', + './themes/default/images/start_meeting_inline.png' => '64eff1bab8d34659c583ca84ce36dd2a', + './themes/default/images/join_meeting_inline.png' => 'edf7837b58451bbfb4e9e827d9a13a22', + './themes/default/images/join_imeeting.gif' => 'efd4a8747417083048b1a256d1d715cd', + './themes/default/images/create-record.gif' => '26aa1d757ecdaa1f886cd2bfb24eddd5', + './themes/default/images/chartBg.png' => 'b2688aa9e2154d8f6c25fc16f94bf6e7', + './themes/default/images/backtotop.gif' => '81711b80ed00519d3c474f5e6cb76062', + './themes/default/images/yes.gif' => '5d3f887e0dbcd70a4708534be3bfa41a', + './themes/default/images/yellow_camp.gif' => '593075b0d0f3dca3343e500f0bc1b4f7', + './themes/default/images/xls_image_inline.gif' => 'e68c72edc63f0f8ab22a9b2cd49909c4', + './themes/default/images/view_status.gif' => '4e9aeb2524553f094d4e3ad9de90839c', + './themes/default/images/view_inline.gif' => 'a2f2198fc7a571a88cf6661ac22b1d8b', + './themes/default/images/view.gif' => 'a2f2198fc7a571a88cf6661ac22b1d8b', + './themes/default/images/uparrow_inline.gif' => '305e2d1a68316e78cf9b7059b1fd632f', + './themes/default/images/uparrow_big.gif' => '52a135285919ae19e94af09fcc8b556c', + './themes/default/images/uparrow.gif' => '52a135285919ae19e94af09fcc8b556c', + './themes/default/images/unscheduled_inline.gif' => 'fa3ecb4c47ae31097e011c514945023b', + './themes/default/images/unpublish_inline.gif' => '75cf70a4e97129cd0a2f9c8edc915d9d', + './themes/default/images/txt_image_inline.gif' => 'd5a939c64c645f0ebc69e436372ca9e0', + './themes/default/images/themePreview.png' => 'c96b4e856127506f10b2bdd2b2c71764', + './themes/default/images/tentative_inline.gif' => '7ce50732e43bbdde45b954694b14ec4b', + './themes/default/images/tabRowRedBg.gif' => '87d0b28828b106e5563dddeff1110544', + './themes/default/images/tabRowPurpleBg.gif' => 'dbd04a0929960614f412bcae69e50d09', + './themes/default/images/tabRowOcherBg.gif' => 'b030681c7db2a9bed844878f13b2d92d', + './themes/default/images/tabRowGreenBg.gif' => '9c7ccd42de0599e6647d9bae6b99d54d', + './themes/default/images/tabRowGrayBg.gif' => '52a8224e5fd67b0dcf27e4ab02759e06', + './themes/default/images/tabRowBlueBg.gif' => '46bde460b237581287809ad4cb0b92d0', + './themes/default/images/sugarupdate.gif' => 'f5ea1dae8f86aeb87a536ceaaa09208d', + './themes/default/images/sugar_icon.png' => '8a98242f1aae07923bf0c7289405b93b', + './themes/default/images/sugar_icon.ico' => '92f1ffd4b2fef157613e48d2d2c7d9c8', + './themes/default/images/sugar_document.png' => '649eeaf6da95e66caa7f961a25995e65', + './themes/default/images/sugarColors.xml' => 'b62043bbf28f32ef441238580ef6cc8a', + './themes/default/images/sugar-yui-sprites-grey.png' => '25009499774224ae1f35d19cd65df6a6', + './themes/default/images/studio_undo.gif' => 'a8e4ca30f12eb152391782ebc1519264', + './themes/default/images/studio_save.gif' => '9a879acb70dda07e06e7719461ac7fe4', + './themes/default/images/studio_redo.gif' => 'd3a7aa42cc4d72047c6e97e36cec2d21', + './themes/default/images/studio_publish.gif' => '17b3a4edb24c576e9056fbf8a7d00576', + './themes/default/images/studio_history.gif' => 'ba2fdf14b162abf38ad809a4849944d8', + './themes/default/images/studio_blank.gif' => 'e2cc44b623bd7213fd8f18e1312f765a', + './themes/default/images/studio_addRows.gif' => 'b34fb09271096f03e497429c62a6c877', + './themes/default/images/studio_addField.gif' => 'f082ee05c412853e73f3e5fda1e0fa0f', + './themes/default/images/start_off.gif' => '0b357d4c67ded4c86d1c70c2c920ba70', + './themes/default/images/start.gif' => '52087392225974936d6ce7d2bb48babd', + './themes/default/images/sqsWait.gif' => '118ce5b9645fbadb2464ef0bd12ff895', + './themes/default/images/spacer.gif' => 'ed280a0ea3cc38f3cbbc747acfbef47d', + './themes/default/images/slot.gif' => '2859963e00e5456e56054fee1bb84964', + './themes/default/images/show_submenu_shortcuts.gif' => '2cf2f044333c693c0235eca6de839532', + './themes/default/images/show.gif' => 'db40a21333e315e8f66b58b8fe7c8663', + './themes/default/images/shortCutsBg.png' => '63e1fd767d54dcf0d43476bb7ac9bb4b', + './themes/default/images/searchMore.gif' => 'a69208b341a41938f65d88abe12f493b', + './themes/default/images/scheduled_inline.gif' => '9812da8482e09a3c4a2a54b99d717c20', + './themes/default/images/rightarrow_big.gif' => '6261e365b6f205ed19984eca672f3d4b', + './themes/default/images/rightarrow.gif' => 'aa8546cb02723ec14c7025159f254ade', + './themes/default/images/red_camp.gif' => '39110cd4e707f3f1ceb24dde98d65a9a', + './themes/default/images/publish_inline.gif' => '8a3c3103256b3592ec15c376835c0f04', + './themes/default/images/print.gif' => '0fc719a26f62a06dbfcacdb9b6447d4f', + './themes/default/images/previous_off.gif' => '62dc03295c496475543d5c3ee2ab51b9', + './themes/default/images/previous.gif' => 'c3d538b6c67aa6ce5fcc911cb062536f', + './themes/default/images/ppt_image_inline.gif' => '23151c677be1d3285d3acc07471ed39d', + './themes/default/images/plus_inline.gif' => '9c0fa5216c6c52a5ba56c2cc8d86740f', + './themes/default/images/plus.gif' => '2246c11e24af9ea5873c1b550e1a3850', + './themes/default/images/plug-in_Word.gif' => '7f1abcf70479023cf72375238bc2ff9f', + './themes/default/images/plug-in_Outlook.gif' => 'f63d982d8892f22bce62907e8ea30f76', + './themes/default/images/plug-in_Excel.gif' => 'ba18135f4a74f4d35f90f786bdbbdb87', + './themes/default/images/pdf_logo_small.jpg' => '683ba9871d516df7eb4725af810f3533', + './themes/default/images/pdf_logo.jpg' => '753f0a7f4f10c9d15de230d8615e2934', + './themes/default/images/pdf_image_inline.gif' => '9c36962a5402ca969451093579cd8261', + './themes/default/images/pdf_header_logo_pdf_header_logo_SugarCRMheader.jpg' => '11d1c10d3e0b0342d0280963a3218c36', + './themes/default/images/pdf_header_logo_img_left_arrow.jpg' => '42a3bd20247df71df2f3b4af7d79469d', + './themes/default/images/pdf_header_logo_company_logo.png' => '8b694e583b9342379a4d57eb313978f7', + './themes/default/images/pdf_header_logo_SugarCRMheader.jpg' => '8c44edddada692f70d809cd003789024', + './themes/default/images/otherTabRed.gif' => '2d7fcbfb0e362659e32b7fe07f8d88b7', + './themes/default/images/otherTabPurple.gif' => '25390753d4f155296e6593ebb01356e9', + './themes/default/images/otherTabOcher.gif' => '7d543589ef9a75e121a149e02adf6040', + './themes/default/images/otherTabGreen.gif' => '250a64b44884e23e183f1f6ee526bb1c', + './themes/default/images/otherTabGray.gif' => '1b5e086627979c27a1eb883db0562afb', + './themes/default/images/otherTabBlue.gif' => 'd7e3090fcbe30db44bba3513c604b913', + './themes/default/images/otherTab.png' => 'cb2887bd33e7adc62cfe69a9f0df1fa0', + './themes/default/images/otherTab.gif' => '87a4aca38528ca5aba1e54d6660e4a31', + './themes/default/images/open_multiple.gif' => 'c372922f378956f6b3bf56931d9ce2c8', + './themes/default/images/no.gif' => '262c91d4e47946e1d4aeff7f0f22614b', + './themes/default/images/next_off.gif' => '75c75524f41553432332b4ec0c99f9c7', + './themes/default/images/next.gif' => '834dc6b2b1b6aadd68f4677af017d5c7', + './themes/default/images/new_inline.gif' => '26aa1d757ecdaa1f886cd2bfb24eddd5', + './themes/default/images/more.gif' => '0fb09987f349939666c7ed893e336e87', + './themes/default/images/minus_inline.gif' => 'f051e7dc179ff6ab3f3c8b380f686501', + './themes/default/images/minus.gif' => '367ebb3ec8e01f8878dc252b56f0ab07', + './themes/default/images/menuarrow.gif' => 'b15abb42a41d475bf9f93755e971737e', + './themes/default/images/mass_update.gif' => '9b855db1e593f1e916dc478fa52648b6', + './themes/default/images/login-bg.png' => 'fbf77f7ca25f06f2fc77076360fb1614', + './themes/default/images/loading.gif' => '50c5e3e79b276c92df6cc52caeb464f0', + './themes/default/images/loadSignedDocument.gif' => 'afcccbee3447ffada5033d0cb7cb2b59', + './themes/default/images/listViewHR.gif' => 'eaa707253f1b7c4aab6f4841034ee7e3', + './themes/default/images/listViewBg.gif' => 'bb253dddfd00429a83bdb9e9a2b25305', + './themes/default/images/list.gif' => 'a4c8b293d7fa762d2c706bd68284cd67', + './themes/default/images/line.gif' => '5da41b8dfa2826bcecd84922b5e30ac7', + './themes/default/images/leftarrow_big.gif' => '1a1e6044a007b7f6be704544c1ab3d9b', + './themes/default/images/leftarrow.gif' => '5d56c1a6a00589aff97b8c9b9911d005', + './themes/default/images/jscalendar.gif' => '753d9d9f7e1e78f0fe75f25f8996692d', + './themes/default/images/info_inline.gif' => '9db230bae1c0ecdf0052806eb1b684f0', + './themes/default/images/info-layout.gif' => '6ba1fa243664fb3cfa0cab4b24592d2d', + './themes/default/images/info-help.gif' => 'ea88b2a7841ae9e84005b5c126df88e3', + './themes/default/images/info-add.gif' => '9c0fa5216c6c52a5ba56c2cc8d86740f', + './themes/default/images/img_right_arrow.jpg' => 'd4f8e8aa3ab1a663d1a55f8e3275e5d7', + './themes/default/images/img_loading.gif' => '00ef871b291bc03a497d608a5bd8ec99', + './themes/default/images/img_left_arrow.jpg' => '42a3bd20247df71df2f3b4af7d79469d', + './themes/default/images/img_close_search.gif' => '357d905eec06febe8ed2d3948f2eadcc', + './themes/default/images/id-ff-vcard.png' => '5f31da1405a984feb4e91bf61d54e336', + './themes/default/images/id-ff-select.png' => '721e35ee703e8c2a903cc34fc34c0160', + './themes/default/images/id-ff-remove.png' => '18ab7c295adec58e3512988e2a8a9326', + './themes/default/images/id-ff-copy.png' => '7e6cc0abddb5e5f368da4457d7fcfc3c', + './themes/default/images/id-ff-clear.png' => 'f47d3cd19fdbfa8540024af7a5831dcc', + './themes/default/images/id-ff-add.png' => '3d14fd627f15f5d8221a2321d0a8f8c4', + './themes/default/images/icon_therevisions.gif' => '3f0f5b717ad53c0d551e5b03e9268f8b', + './themes/default/images/icon_sale.gif' => '709cf48456c82ccbfa4a038817e0c5e1', + './themes/default/images/icon_person.gif' => '19a7896996fac88e1bf4c7314cf126f2', + './themes/default/images/icon_package_create.gif' => 'e728aedae3a86f557a4431bcfb3b11b0', + './themes/default/images/icon_package.gif' => '6fe230ae81d0c1bfdc02f12554bfe5a6', + './themes/default/images/icon_opportunity.gif' => 'e8c75374653922482d1d5b71ee569909', + './themes/default/images/icon_new_package.gif' => 'e728aedae3a86f557a4431bcfb3b11b0', + './themes/default/images/icon_issue.gif' => 'dbe274a88ad4b289cf1f80be391620b3', + './themes/default/images/icon_iFrames_32.gif' => '264e84da5b4c48a4970f71550df86084', + './themes/default/images/icon_home.gif' => '15a02d5f4fd368aff08023822401bd39', + './themes/default/images/icon_file.gif' => '0037a12c8c4b623c5e0ea1803a6e95b5', + './themes/default/images/icon_expression_types.gif' => '34e7314d67aad0251bce11b1f7912aba', + './themes/default/images/icon_email_view3.gif' => '77592a420b9f1fd37da050c94083e9c3', + './themes/default/images/icon_email_view2.gif' => '1702d53e8aa6f660dd29d31b54bfa43e', + './themes/default/images/icon_email_view1.gif' => '7f5675af33f000f9fc9b48519b416c54', + './themes/default/images/icon_email_view.gif' => '0ddc870ec847e406a483d431de0c3b27', + './themes/default/images/icon_email_sugfolder_exp.gif' => '736434e15eb5273ed2adabb66451f7f7', + './themes/default/images/icon_email_sugfolder.gif' => '127016b7228674ac442ec5266caa3f79', + './themes/default/images/icon_email_settings.gif' => '129bbd92f356c68e63a94bcd53a1c225', + './themes/default/images/icon_email_send.gif' => '3069253177ad510279278f69f0cd5d78', + './themes/default/images/icon_email_save.gif' => '0c7f54e7bfee5ea8b782a8df7e52aac2', + './themes/default/images/icon_email_replyall.gif' => '5cad79693b03ece0364497e1538df029', + './themes/default/images/icon_email_reply.gif' => '2df1e0f100bc7e666a3efec19ed87d2d', + './themes/default/images/icon_email_relate.gif' => '74242467860ceb4110ff97449881e913', + './themes/default/images/icon_email_options.gif' => '9417e3643754ebb64efd1c8cdac2574f', + './themes/default/images/icon_email_mark.gif' => '59bd3232c7d2a3797caff08f111e47db', + './themes/default/images/icon_email_fullscreen.gif' => 'dcd3515feee571f3126eb2cda9be9d99', + './themes/default/images/icon_email_forward.gif' => 'ad895eb9b28efafa360141b2d463d07a', + './themes/default/images/icon_email_folder_sent.gif' => '84f050eabd42d189ff7ec33ef604a2a9', + './themes/default/images/icon_email_folder_grp.gif' => '95af0dfe5619fefcbe5e735a2f88e5d2', + './themes/default/images/icon_email_folder_exp.gif' => '34630bcf92e238c09294950a56533de7', + './themes/default/images/icon_email_folder_drafts.gif' => '44aeed88a8c7eaa04ceaa47980c264a4', + './themes/default/images/icon_email_folder_archives.gif' => 'a5d423896f3d34e7dae5a99788b9096d', + './themes/default/images/icon_email_folder.gif' => 'c84e3a04f0553457f2758c17328dcc64', + './themes/default/images/icon_email_delete.gif' => 'de0c2510e40fc90da261c3f24060489f', + './themes/default/images/icon_email_create.gif' => '1ed2501ee71cef192e87836feb66ecb8', + './themes/default/images/icon_email_compose.gif' => 'cbbab42834d7a19f657545f9fdf01dd4', + './themes/default/images/icon_email_check.gif' => '97f4bb665ca71c935b0c0d6a97156c4c', + './themes/default/images/icon_email_attach.gif' => 'cb6c0e533206569e383429c25c4f090d', + './themes/default/images/icon_email_assign.gif' => '892c9f96578002195ec4ea0f233fc8a9', + './themes/default/images/icon_email_archive.gif' => '01fe1cad58260b7bf63788e9ce5b68e9', + './themes/default/images/icon_email_addressbook.gif' => 'd950e8a8497cb37b660281d332a2767c', + './themes/default/images/icon_document.gif' => '167aee1d934419e6e8aa6235fee350ea', + './themes/default/images/icon_company.gif' => 'b2ef078b5afa7f07bbbc13587bc9990b', + './themes/default/images/icon_basic.gif' => '71bcdef4548fad731d44fc681e3a6599', + './themes/default/images/icon_back.gif' => '215aa2a3bcf6e67e0fb2aa25da2e8871', + './themes/default/images/icon_assistant.gif' => '9e75a064532dc80f6c44ffae3aa6501b', + './themes/default/images/icon_Users_32.gif' => 'c63b38ad112782578822a612fb102952', + './themes/default/images/icon_Trackers_32.gif' => '1fd19adde4d7ca809ad287c45a45100c', + './themes/default/images/icon_TrackerSessions_32.gif' => '5071e66a3fa459669f5ad5a2e4a6eaf9', + './themes/default/images/icon_TrackerQueries_32.gif' => '0c8a6bf47267515ea3b2be8b5ea16c73', + './themes/default/images/icon_TrackerPerfs_32.gif' => '998c775c84226d9a6d8d7a2cfee828b8', + './themes/default/images/icon_Teams_32.gif' => '1042e299464990cdbf312460171dbc6b', + './themes/default/images/icon_Tasks_32.gif' => '59dd94dfcfaed6273295f22658c77a75', + './themes/default/images/icon_Tasks.gif' => '91d11b48558775d6f940a4fe2fef9d8f', + './themes/default/images/icon_Targets_32.gif' => 'a791b861efaa860b3f356ce5644982ad', + './themes/default/images/icon_SugarPortal.gif' => 'bd9b140fefd8d3c8d25e5602d34455b1', + './themes/default/images/icon_SugarNews_32.gif' => '13513ac06c13bbcc28acddce996e79ba', + './themes/default/images/icon_SugarFeed_32.gif' => '91906aa110e0737571bdce7e982d6f5b', + './themes/default/images/icon_SugarFeed.gif' => 'c121b4f625c494d54a7c6e60a7159e73', + './themes/default/images/icon_Subpanels.gif' => '99b9a4c23b9d4d52c80db23b65241032', + './themes/default/images/icon_Studio.gif' => '6cff1d99350160b388f5a1ac529c3ff9', + './themes/default/images/icon_ShortcutBar.gif' => '4dd63de4f48c7600a9b463d579cadcb9', + './themes/default/images/icon_SearchForm.gif' => '9246e8668eb71fd1e2ebd20b6cb60ba1', + './themes/default/images/icon_SPUploadCSS.gif' => 'd912a8d76735acc061b566c950976995', + './themes/default/images/icon_SPSync.gif' => 'bc384598e25a00faa9e2efd942b357a0', + './themes/default/images/icon_Rss_32.gif' => 'adf9e9567964a6faf01005e83051d974', + './themes/default/images/icon_Reports_32.gif' => 'e25b26fb6a2a086087c81f9e2176b5e1', + './themes/default/images/icon_Releases_32.gif' => '8151d6de8614fdc220860f7e79b417b9', + './themes/default/images/icon_Relationships.gif' => 'ff28b08d448d6e1c732b2cf29f6096a3', + './themes/default/images/icon_Quotes_32.gif' => '74d821c6b4656e3b5a6548c5a854cb0f', + './themes/default/images/icon_QuickCreate.gif' => '54cd777aafd156c049999c8b783cfa58', + './themes/default/images/icon_Prospects_32.gif' => 'a791b861efaa860b3f356ce5644982ad', + './themes/default/images/icon_Prospects.gif' => '5e5099f8f374fb63cb236e926a575938', + './themes/default/images/icon_Projects_32.gif' => '009174ec22ef8f1af05e0e06f55d5916', + './themes/default/images/icon_Project_32.gif' => '009174ec22ef8f1af05e0e06f55d5916', + './themes/default/images/icon_ProjectTask_32.gif' => '1092296917891851fc078c5e2f4d57df', + './themes/default/images/icon_ProjectTask.gif' => '4c826a1341be8b80fae67d6452ad087e', + './themes/default/images/icon_Project.gif' => '22a4aefdc49f3188585ab8103e4fd7c4', + './themes/default/images/icon_Products_32.gif' => '6e740000d2e08d22d4e24d63e84e8c9c', + './themes/default/images/icon_Product_Types_32.gif' => '1f5728ad9c07d67979eed73af625efbf', + './themes/default/images/icon_ProductTypes_32.gif' => '1f5728ad9c07d67979eed73af625efbf', + './themes/default/images/icon_ProductCategories_32.gif' => 'ce6e3a4a347467957275a5c0eee5e311', + './themes/default/images/icon_Portal.gif' => '4a107249e6596b0e0c724e7734fae92d', + './themes/default/images/icon_Popup.gif' => '0c35a469688f5014198092cca23cc6df', + './themes/default/images/icon_Phone.gif' => '69561dd53df8efc35c0919efcf546d2c', + './themes/default/images/icon_Opportunities_32.gif' => '787b58f02e8c7c118841abbffcf72f42', + './themes/default/images/icon_Opportunities.gif' => 'bb0d0125d317f78b6265fbcd7b6d827d', + './themes/default/images/icon_OpenTasks_32.gif' => 'd0c52359674d719e1e4da4c5ee3b3064', + './themes/default/images/icon_Notes_32.gif' => '38614c8b0fb8673bbf7118bc62d3571b', + './themes/default/images/icon_Notes.gif' => 'cdee31ac66f080bd6e862e0dcfcf1358', + './themes/default/images/icon_NewModule.gif' => '700412f4a1535f58dc358af2c15ddba4', + './themes/default/images/icon_MyTasks_32.gif' => '5af76e5299c5e6a2946ce3ed13d64d5f', + './themes/default/images/icon_MyPortal_32.gif' => '264e84da5b4c48a4970f71550df86084', + './themes/default/images/icon_ModuleBuilder.gif' => 'b0f8e050fa92fd761fce476dc361e9b9', + './themes/default/images/icon_MobileLayouts.gif' => '01d983c77ce576f3fbb42a67cd43b901', + './themes/default/images/icon_Meetings_32.gif' => '7cbed9de72d3c9e9e2aed8997ea4cd82', + './themes/default/images/icon_Meetings.gif' => '6b25f5507719dd934fdad9ae12125935', + './themes/default/images/icon_ListView.gif' => '557ee4b0eaa08c7566f5ff4522207bc1', + './themes/default/images/icon_Leads_32.gif' => '5c7ee135592a05a145456af63077fb3d', + './themes/default/images/icon_Leads.gif' => 'dd27a17fc38fb8b01398e35ac3d39fd0', + './themes/default/images/icon_Layouts.gif' => '4a107249e6596b0e0c724e7734fae92d', + './themes/default/images/icon_Labels.gif' => 'e7d722a222050cb2e92431c460ecad8a', + './themes/default/images/icon_KBDocuments_32.gif' => '605c4a7cac4ccc184ac013b9a6d4016e', + './themes/default/images/icon_KBDocuments.gif' => 'd74530d24f2e0bd57ef6681dbb20fe94', + './themes/default/images/icon_JotPad_32.gif' => '04e2a63f3d3afbe1de3cd6048cec1f50', + './themes/default/images/icon_JotPad.gif' => '1e5d01a07e4f988611af6677a037f318', + './themes/default/images/icon_Invaders_32.gif' => 'c669d4aff0cef7ab73e051c1443d8b3c', + './themes/default/images/icon_Forecasts_32.gif' => '20a3de4d107c962b0847d9dd7174cdbd', + './themes/default/images/icon_Fields.gif' => '39677bcb6670ffd88f083419d9f9d1c5', + './themes/default/images/icon_Feeds_32.gif' => 'adf9e9567964a6faf01005e83051d974', + './themes/default/images/icon_FavoriteReports_32.gif' => '4fe2369941b3672b5c8f6594fcd15825', + './themes/default/images/icon_Emails_32.gif' => '3626aef290eda2f9004d7e4d2c2e0791', + './themes/default/images/icon_Emails.gif' => '35464266090cc9d38551bcd2e0edf969', + './themes/default/images/icon_EmailTemplates_32.gif' => '3626aef290eda2f9004d7e4d2c2e0791', + './themes/default/images/icon_EmailAddresses_32.gif' => '834acafa896baa468fc22186d2cff2e4', + './themes/default/images/icon_EmailAddress.gif' => '6877d848391e0165e1106864b3d6d4cb', + './themes/default/images/icon_EditView.gif' => '2b40c926f5bec858704c1daa83f1eac9', + './themes/default/images/icon_DropDownEditor.gif' => '18036f2acc73b67b6168dec5798600bd', + './themes/default/images/icon_Documents_32.gif' => '945c2c18f5a9e119178cdebdb8f638c4', + './themes/default/images/icon_Documents.gif' => '3f0f5b717ad53c0d551e5b03e9268f8b', + './themes/default/images/icon_DetailView.gif' => '7e52a99c33829596b0a3210c5202a12d', + './themes/default/images/icon_DeleteFull.gif' => 'd9c1deab8458cf93d645d91dfba6207d', + './themes/default/images/icon_Delete.gif' => '501840cefe034dbdc2e4c2b54997cad5', + './themes/default/images/icon_Dashlet.gif' => '13af871521b34dac496b57b0e2c4eaa2', + './themes/default/images/icon_ConvertLead.gif' => 'a06af998d584934fb71a417fbb47de23', + './themes/default/images/icon_Contracts_32.gif' => '5c01388d8c6d287f07d4ade8a71882e3', + './themes/default/images/icon_Contacts_32.gif' => 'eeb8eb818c7813f77b479f7e1001d9d3', + './themes/default/images/icon_Contacts.gif' => '5c25642d0e7373ff3dc8670ef61fcfc1', + './themes/default/images/icon_Connectors.gif' => '741a28001f099adc694252df889a97ab', + './themes/default/images/icon_ConnectorSearchFields_16.gif' => '071b4fa50987f24aa8e439ad2c94977e', + './themes/default/images/icon_ConnectorSearchFieldsOver.gif' => '892037f83ee9b1a78b0968b64f008aa5', + './themes/default/images/icon_ConnectorSearchFields.gif' => '670c96db0ae37d1e7950ceb81f1f22bb', + './themes/default/images/icon_ConnectorMap_16.gif' => '21a1a3515ae02ed5fc0d8492a892f690', + './themes/default/images/icon_ConnectorMapOver.gif' => '5c4beb392911c203ac8ab9f55ca80efb', + './themes/default/images/icon_ConnectorMap.gif' => '28f0ba3ad323e08f917693cd5ef3286f', + './themes/default/images/icon_ConnectorEnable_16.gif' => '139c5d2ed03e09e69c2427aa461d0abb', + './themes/default/images/icon_ConnectorEnableOver.gif' => '4c68d747832656f8a373308a5571aa2c', + './themes/default/images/icon_ConnectorEnable.gif' => '6c53d58521fee6d29e35583f11f80b7c', + './themes/default/images/icon_ConnectorConfig_16.gif' => 'c455945b702d168f0c55f630bc909a03', + './themes/default/images/icon_ConnectorConfigOver.gif' => 'f24b62af2fc23e3c5f675a7454968688', + './themes/default/images/icon_ConnectorConfig.gif' => '1024aa4e200381bf481888131023b5a2', + './themes/default/images/icon_Column_3.gif' => '3a967a62ac79e9be7d953730c550bf14', + './themes/default/images/icon_Column_2.gif' => 'bf25350fb235d301601b87b687160d17', + './themes/default/images/icon_Column_1.gif' => 'b819b73077afdfd13c3f84f77e1cb8c5', + './themes/default/images/icon_Charts_Vertical_32.gif' => 'e8a3b35973d514875fdb9507728357e3', + './themes/default/images/icon_Charts_Vertical.gif' => 'f15275758c20b1c829c9ed3dcc88d3c1', + './themes/default/images/icon_Charts_Pie_32.gif' => '1dd970dabcb5de6a9fa742893ad28c3b', + './themes/default/images/icon_Charts_Pie.gif' => 'b65cc013f3b9c6b50e46722fbc027cf4', + './themes/default/images/icon_Charts_Horizontal_32.gif' => 'e84af669b14b4288b699a0d6d5dd17fc', + './themes/default/images/icon_Charts_Horizontal.gif' => '928245490307b01d3cca736630187fe1', + './themes/default/images/icon_Charts_GroupBy_32.gif' => 'a1c69c3e8be5e54bd2b6be6dd97d1835', + './themes/default/images/icon_Charts_GroupBy.gif' => 'b444f2b91a51489e19c3f56b859121da', + './themes/default/images/icon_Charts_Gauge_32.gif' => 'c4ba44d5ad9209d6e37565ec1faf91ea', + './themes/default/images/icon_Charts_Funnel_32.gif' => '9d60fb449cb26d8f13ff4fd05dd17451', + './themes/default/images/icon_Charts_Funnel.gif' => 'fbbeb7f36751a847b43cbc29042bef83', + './themes/default/images/icon_Cases_32.gif' => 'e74f7b4a4f513c517351fe0e15ec9f7d', + './themes/default/images/icon_Cases.gif' => '86c8c9ce83c9feab641687fa968d1705', + './themes/default/images/icon_Campaigns_32.gif' => '4b2651b74c0df08fb38da1c50ad55540', + './themes/default/images/icon_Campaigns.gif' => 'd326b30e1f37d6b1ae7585bec2603f75', + './themes/default/images/icon_CampaignLog_32.gif' => '4b2651b74c0df08fb38da1c50ad55540', + './themes/default/images/icon_Calls_32.gif' => 'b1396f0d4aad67469aade38e1c1ad57a', + './themes/default/images/icon_Calls.gif' => '70a325dc66ac4330ba4920655cc9d2f1', + './themes/default/images/icon_Calendar_32.gif' => 'b438788c79b226656fc335ab4e3b282d', + './themes/default/images/icon_Bugs_32.gif' => '007a66380bb5ac5a9053c1e3932c4452', + './themes/default/images/icon_Bugs.gif' => 'daa1bafd411fa579d13aeb01832fe018', + './themes/default/images/icon_BasicSearch.gif' => '34138a6f18eda6680e2b6ac129888e74', + './themes/default/images/icon_Application.gif' => '9f19f9a35c1269591cf0f4503fb4b0a4', + './themes/default/images/icon_AdvancedSearch.gif' => '5a13f19316a76136a13e23f39bce0c73', + './themes/default/images/icon_AdminThemes.gif' => '3dabb98180140be0f27983c53fb93fa3', + './themes/default/images/icon_AdminPDF.gif' => 'c4cd278746674615533992c06439c5c5', + './themes/default/images/icon_AdminMobile.gif' => '4aa8c94a81f105a4823afdf79f013e3d', + './themes/default/images/icon_Address.gif' => '01031291c5fb1552e40d63f1b08c0314', + './themes/default/images/icon_Activities.gif' => '1e5d01a07e4f988611af6677a037f318', + './themes/default/images/icon_Accounts_32.gif' => 'b0c893a480c52340a287af42547b4977', + './themes/default/images/icon_Accounts.gif' => '34ca712c6aa6b7ba68882e330423c057', + './themes/default/images/icon_A1_newmod.gif' => '71bcdef4548fad731d44fc681e3a6599', + './themes/default/images/iFrames.gif' => '0a0e964460018c0dc9295d9c48773952', + './themes/default/images/hide_submenu_shortcuts.gif' => '4faa81f7be7484ed9442ad726ec56bcb', + './themes/default/images/hide.gif' => '63afbcf6fa1496c0e933c26bde33e1be', + './themes/default/images/helpInline.gif' => '904c4318b2195909683e239f45fe7543', + './themes/default/images/help.gif' => 'ea88b2a7841ae9e84005b5c126df88e3', + './themes/default/images/help-dashlet.gif' => 'ea88b2a7841ae9e84005b5c126df88e3', + './themes/default/images/h3Arrow.gif' => '0a8858f4bda73af356182ba99ae6b4d4', + './themes/default/images/grouped-menu.png' => 'f502f8f39e6665137b2d5b81f19608c3', + './themes/default/images/grouped-menu-arrow.png' => 'd3d5c430b05cf86a8f0512d31d4bbd1c', + './themes/default/images/green_camp.gif' => 'c2b67c21d37fd3d49b6f01b062f36529', + './themes/default/images/getLatestDocument.gif' => 'ca3c6fbc6d4d6d39a637eed0bfc4a08a', + './themes/default/images/formButtonBgOn.gif' => '668b0ee95cf4b0792c03f91a82fcfb91', + './themes/default/images/formButtonBg.gif' => 'd9a0a446c17015d99879870c0ae585c1', + './themes/default/images/form-button-primary-bg.png' => '29ec1da2209c258fd2b5015546b485a0', + './themes/default/images/form-button-bg2.png' => 'fd1a32fc28d0aaae12634caeb8dc2ce5', + './themes/default/images/form-button-bg.png' => '3f99c9b8e654262ced246accca06bf98', + './themes/default/images/fonts.normal.icon.gif' => 'd15ee190de151df2fc02366847a42333', + './themes/default/images/fonts.largest.icon.gif' => '93227b0e5335d1c749d0c62f932f7246', + './themes/default/images/fonts.larger.icon.gif' => '8ed79085035c19fa3a08a57821ccff68', + './themes/default/images/export.gif' => '3141bb408338e95954f49498ab2074a3', + './themes/default/images/end_off.gif' => '6f2b185bd8b4f04255184d7c3b972be4', + './themes/default/images/end.gif' => '99ec17980972c2227478df9ca2b09abf', + './themes/default/images/emptyTabSpace.gif' => 'e8f77ea4d4936a67560b361411f260ac', + './themes/default/images/editview.gif' => 'a63bb099ded39d833199d47c9fdb3ead', + './themes/default/images/editlabels.gif' => 'a63bb099ded39d833199d47c9fdb3ead', + './themes/default/images/editfields.gif' => '163d3292d1080120c96e991c9d8c411a', + './themes/default/images/edit_wizard.gif' => 'fe64a594539d3561d50fd34fd94143a5', + './themes/default/images/edit_inline.gif' => '6ba1fa243664fb3cfa0cab4b24592d2d', + './themes/default/images/dp-tr.png' => 'dc0c80673320172a14e92ab631d3ed8c', + './themes/default/images/dp-tr-plain.png' => '9a086d27cce5acee324de36d269c4037', + './themes/default/images/dp-tr-menu.png' => 'c45d04f7abaf8ee0ede320bf80901bf5', + './themes/default/images/dp-tr-dc.png' => 'a70774042ea157126e9e9c60f7b5c4ac', + './themes/default/images/dp-tl.png' => 'e156192dca5a7f92013d3ae4de28caec', + './themes/default/images/dp-tl-plain.png' => '3cb7288c2838e1831503ea76385737c9', + './themes/default/images/dp-tl-menu.png' => '8c0262afcfa95ceef0bbde8d8dc27cf9', + './themes/default/images/dp-tl-dc.png' => '0baec93b29924b99fb251a1dc3c48c83', + './themes/default/images/dp-mr.png' => 'fc81419f35c69bedd9c3ca9537459d47', + './themes/default/images/dp-mr-menu.png' => 'c5c544ba6107099bcbc64da39c689958', + './themes/default/images/dp-mr-dc.png' => '6689c998caee352c40a35bc4784cddbf', + './themes/default/images/dp-ml.png' => 'fb83ca1c1205fe18aced640505ce84e1', + './themes/default/images/dp-ml-menu.png' => 'a1b762e0917555e632a19a445fc7d989', + './themes/default/images/dp-ml-dc.png' => '938c8f0a042cbcbac95bf6e25bca6c4c', + './themes/default/images/dp-hd.png' => '3d02379f218609b1f8cc7b9d4cae33ef', + './themes/default/images/dp-hd-plain.png' => 'e2a0b905436223a576c577edfb710824', + './themes/default/images/dp-hd-menu.png' => '0b6b43ea0d1b59b13f2145f206869476', + './themes/default/images/dp-hd-dc.png' => '97e314b313aca983b4703ee09654d204', + './themes/default/images/dp-ft.png' => 'f5138f10cd7684baef4d39e41b83a201', + './themes/default/images/dp-ft-menu.png' => 'b056479142f3273d81f3c74a74b7ada8', + './themes/default/images/dp-ft-dc.png' => '37fc519efa67ff3ea303326ec9a612cf', + './themes/default/images/dp-br.png' => 'e25404e74fa6dc901955602668ea76cf', + './themes/default/images/dp-br-menu.png' => '81098441075f930258a786eefd758af0', + './themes/default/images/dp-br-dc.png' => '85cb39f7aac2fc0f27ead5eb39369704', + './themes/default/images/dp-bl.png' => '55adcc6277ca6d1c41421f4553e02d47', + './themes/default/images/dp-bl-menu.png' => 'a76e8bf715c6896931b70dfa11be4435', + './themes/default/images/dp-bl-dc.png' => '465eb50a7b0f01206dc1a48bfa5bd210', + './themes/default/images/dp-bd.png' => 'c68c1d8c3a75459b069ce94a4ce8f10a', + './themes/default/images/dp-bd-top-menu.png' => '8db395d44db4d024cffdfcac9d56c02e', + './themes/default/images/dp-bd-menu.png' => '9804920a98449b0c35b81204e47adf72', + './themes/default/images/dp-bd-dc.png' => '7db8abd6da3a8026cd980ed9fd5c0ff4', + './themes/default/images/downarrow_inline.gif' => '505e2477efbea90592a169aafbe41794', + './themes/default/images/downarrow_big.gif' => 'b4ffaa11d20c5433c8ce6f392b27c02d', + './themes/default/images/downarrow.gif' => '4d89350bedf353e12294bad2c2fe5ae6', + './themes/default/images/doc_image_inline.gif' => '1f4a7d82e86352ac2121acc844dc6d4a', + './themes/default/images/detailview.gif' => '2645ccf6df6dc9d58ce65f3d1c6d2b67', + './themes/default/images/detailViewBg.gif' => '29d8425fa2b3989a037bf2128584d6f8', + './themes/default/images/delete_inline.gif' => 'd09e3affa3e277be307ec1af748b3364', + './themes/default/images/delete.gif' => '650572d2b216e8e1cc3c2e7ffbad4df1', + './themes/default/images/def_image_inline.gif' => 'b31f890084d972950ae50e513e4ef1c6', + './themes/default/images/decline_inline.gif' => 'd9e006d8758ad871d7395cf931dec405', + './themes/default/images/dcmenugrade.png' => '45ee854213189e9b16b8994292f19c24', + './themes/default/images/dce_Settings.gif' => 'b255bb8ae39976fd6c83c3037d090f36', + './themes/default/images/dcMenuDivider.png' => '7eda7509cde527fbeb7556ee0208cfed', + './themes/default/images/dashlet-header-refresh.gif' => '8f48d8c61ed6dd5890954ded347f6550', + './themes/default/images/dashlet-header-edit.gif' => '1f3d5009fc12cd0117903d8959a559e9', + './themes/default/images/dashlet-header-close.gif' => 'dba10edcd9ab300f2483dc8de161e91a', + './themes/default/images/currentTabRed.gif' => '61f911fae96b5f90d2525613bd3b1dc7', + './themes/default/images/currentTabPurple.gif' => '3cc2d348b8073e73ececbc4ae361220b', + './themes/default/images/currentTabOff.gif' => 'e0a67ebcd0eec021c19f4ab454759e8f', + './themes/default/images/currentTabOcher.gif' => '4852317d212d6e5a1ce7b0036dd77e45', + './themes/default/images/currentTabLinkBg.gif' => 'acc41261d49919fc0b20c3bb009d3af0', + './themes/default/images/currentTabGreen.gif' => '085f9927ac24c8311c3779c3d6733440', + './themes/default/images/currentTabGray.gif' => '95c3cb31673ed2da9e979938a48c09c8', + './themes/default/images/currentTabBlue.gif' => '294f6bb00ba34db9b2227dd7140651ef', + './themes/default/images/currentTab.png' => '48a2b7fa468514d9fe6e00bbf886e201', + './themes/default/images/currentTab.gif' => '6f2002081ed96fd0931f686d24bacd78', + './themes/default/images/company_logo.png' => '4f040bdb68c3b732fa54f2d96fd0df7b', + './themes/default/images/colors.sugar.icon.gif' => 'e38d443ab9b82145d88c0c97fed53789', + './themes/default/images/colors.red.icon.gif' => 'b1168092ee831ee08b535fe066d11246', + './themes/default/images/colors.purple.icon.gif' => 'b89bae62c86fc22236ba93c1f2b1a245', + './themes/default/images/colors.orange.icon.gif' => '3a5a16d7a8c5e411bb63aefe58b75e17', + './themes/default/images/colors.green.icon.gif' => '248e791c8a93cb006b630112a44d71b7', + './themes/default/images/colors.gray.icon.gif' => '77fe1105f4be1d9b336ec346b17891dc', + './themes/default/images/colors.blue.icon.gif' => '48d30c2c20d84f45455008f6254e21e1', + './themes/default/images/close_inline.gif' => '4706ecc190ed6d3cf0024cfdeef7540a', + './themes/default/images/close_button_24.png' => '60a360437a59cd91f613a88f108c6f1b', + './themes/default/images/close.gif' => '00a1e63ea66cad36fd357afcec227e3b', + './themes/default/images/check_inline.gif' => '3fd7b54b12de5ee794dd44c53c7d9b7d', + './themes/default/images/calendar_previous.gif' => '600d00e3bd8a384dc5f851646c513390', + './themes/default/images/calendar_next.gif' => 'f128d2e8cff00f25d3fc6aca822acc54', + './themes/default/images/calendarHeaderBg.gif' => 'e737dc503d8ebfd782d55ecbb9fa3ab7', + './themes/default/images/blank.gif' => 'fc94fb0c3ed8a8f909dbc7630a0987ff', + './themes/default/images/bgRed.gif' => '1df40fd5435907a1fed4d4b181ea6b46', + './themes/default/images/bgPurple.gif' => 'c1b6d97ad95f8388da34d4a4175a81d3', + './themes/default/images/bgOcher.gif' => '982082d036e99833dc1f1a483fce2a5d', + './themes/default/images/bgGreen.gif' => '3bfe3b4d1fc2f0ef39f90507fb4a43d2', + './themes/default/images/bgGray.gif' => '1c6dfddeae3b2d18974506837c29ccef', + './themes/default/images/bgBtnPurple.gif' => '0c88b16eb4908ef062773520a9211fb1', + './themes/default/images/bgBtnOrange.gif' => 'f85be7940606135360db38bb8dc4ad36', + './themes/default/images/bgBtnGreen.gif' => 'f278617bef25b52737a1c1c535c85bca', + './themes/default/images/bgBtnGray.gif' => 'bc636fcc0fde952eee600795e26f3568', + './themes/default/images/bgBtnBlue.gif' => 'd81f5ba78f4717e5723adf3843437ee4', + './themes/default/images/bgBtn.gif' => 'ad46bd5437826c67f8919874f6f3bea0', + './themes/default/images/bgBlue.gif' => 'def431ff46dac5dc23aa47a531b13343', + './themes/default/images/bg.gif' => 'e542169ee5ed28cdb45b3996603193d6', + './themes/default/images/basic_search.gif' => 'afc9992d8567a78b5b7df196549eb29a', + './themes/default/images/bar_loader.gif' => 'e67d85a8d2d4021514815d0ff4d65173', + './themes/default/images/attachment.gif' => 'ad2683b97bcee20be7ba039d3259b2fa', + './themes/default/images/arrow_up.gif' => '3c0164a46adc6ddcb9fec3cf1129e190', + './themes/default/images/arrow_down.gif' => '7ae60aa70170713428e265b1cc695291', + './themes/default/images/arrow.gif' => 'e351c2d5a2ad28ee72a15e1d2ce7e2bd', + './themes/default/images/advanced_search.gif' => 'd0022a5800ff6a11b04c6e27293d717c', + './themes/default/images/accept_inline.gif' => 'bbb0aed40e938669c98b65642a400a7d', + './themes/default/images/_blank.png' => '9bbf8b89dfee264016a5cf95daa02a10', + './themes/default/images/WorkFlow.gif' => '658b40aa9fb3ffcabb432ea328ad8415', + './themes/default/images/Users.gif' => 'a2e9e7731e06a4fdfb2f49563e98af6b', + './themes/default/images/UpgradeDCEInstances.gif' => '31f57a942f93564c75925c5c31f36644', + './themes/default/images/Upgrade.gif' => '31f57a942f93564c75925c5c31f36644', + './themes/default/images/Trackers.gif' => '7982f8a7fda959763e0ddd42bea0af7e', + './themes/default/images/Themes.gif' => '05511600d7087ec404b6aa7f02d2a7b4', + './themes/default/images/Teams.gif' => '8fce7827080693884dc5022b6b473940', + './themes/default/images/Tasks.gif' => 'a4c8b293d7fa762d2c706bd68284cd67', + './themes/default/images/Support.gif' => 'c6fae35bc372012c1a5d5e0b5f22ada5', + './themes/default/images/SummationWithDetailsOver.gif' => '807077e21b5c6ce180a7a1e0afbb4f7b', + './themes/default/images/SummationWithDetails.gif' => '332fa7357f54428c5915518695824a69', + './themes/default/images/SummationOver.gif' => 'fe76f4f7000c4ea19b6c4176a4550887', + './themes/default/images/Summation.gif' => 'd85caef83542e64a75e265fbd0564d3f', + './themes/default/images/SugarPortal.gif' => '5cafb18cdfd6265e77f852dc00b8ff93', + './themes/default/images/SugarLogic/icon_string_16.png' => '23cc7b97a8736c78dfaf6a0967c2d979', + './themes/default/images/SugarLogic/icon_num_16.png' => 'd69a90dc40272f45325f2f8e91595744', + './themes/default/images/SugarLogic/icon_generic_16.png' => '3a123f2ea73a03caf88b822d14692474', + './themes/default/images/SugarLogic/icon_enum_16.png' => '1a4120b6f7a57ac0967791ee1d00bfa1', + './themes/default/images/SugarLogic/icon_date_16.png' => '5d4ba78db2626a9d42ff2c5e611eed6d', + './themes/default/images/SugarLogic/icon_bool_16.png' => '466b13cb6218f6cb1b1c9db6d2a8730c', + './themes/default/images/Studio.gif' => '2941190a8b8f1c37cd373e8474abaff2', + './themes/default/images/StickyThread.gif' => '35afdc080b5426b09be58bf765a1c4a7', + './themes/default/images/Shippers.gif' => 'daa6d24122b0df9fc1dc5943ce449058', + './themes/default/images/Search.gif' => '089000300b21c8ff74c2e258e9b44bd4', + './themes/default/images/Schedulers.gif' => 'c0160825b845a73b070194906e818aee', + './themes/default/images/SchedulerTest.gif' => '635fcbfc6d5eb2785ef2e6c6f8360a91', + './themes/default/images/RowsAndColumnsOver.gif' => 'b09fbec8214a744010e69b6cbc071379', + './themes/default/images/RowsAndColumns.gif' => 'ff458b8e2303ec31d0f6b2ded6140ea0', + './themes/default/images/Roles.gif' => 'dcbf376b885458b1fc8c21de7884284e', + './themes/default/images/Repair.gif' => 'adca1c05640dc8f3cd315afbc8d323e2', + './themes/default/images/RenameTabs.gif' => '895241cf5de9d8519169e2b9ef03e08f', + './themes/default/images/Releases.gif' => 'ff8de6cf41ad9056011973384f2e0602', + './themes/default/images/Rebuild2.gif' => '4e1dd889a93a7131cdb8204ae321fe5a', + './themes/default/images/Rebuild.gif' => 'fa51c1e12cfd77a0a5076b92c2d0b218', + './themes/default/images/ReassignRecords.gif' => 'efc325a2f834ce64b1c7cf195917ed77', + './themes/default/images/RSS.gif' => '0d29ec2ee3476d83dcf7757ea3874ecd', + './themes/default/images/QueryBuilder.gif' => 'd705b041b021686b3b5e286305820163', + './themes/default/images/Prospects.gif' => 'a7bd5ae5e32198b8826d6986d84a8ad1', + './themes/default/images/ProspectLists.gif' => '9b1a622509e5881ec791edf4f68f5e95', + './themes/default/images/ProjectWeek.gif' => '077ad399f8640fb0e166eaed6c29cd35', + './themes/default/images/ProjectTemplate.gif' => 'f30534d557373942ec06aad47f735c01', + './themes/default/images/ProjectTask.gif' => 'f0be8090159b3a874267c3bc27c5a1c3', + './themes/default/images/ProjectSave.gif' => 'e5d6feda33978980d8e1b73446ca0cc3', + './themes/default/images/ProjectPlus.gif' => '23840e38f362cb897374c51441d4379d', + './themes/default/images/ProjectPaste.gif' => 'c5d040c4f0a4075aaa56acfbc393ee44', + './themes/default/images/ProjectOutdent.gif' => 'b117efdc268d2779a0c2f2f4cfee7fc3', + './themes/default/images/ProjectMonth.gif' => '1ef256376cacea730a9b1dd3d58e7463', + './themes/default/images/ProjectMinus.gif' => '126cd19c26aa220d323230c8aa49c98a', + './themes/default/images/ProjectInsertRows.gif' => 'b89dcac2784c2a3376c305b9772c5bdd', + './themes/default/images/ProjectIndent.gif' => 'ab916206b4065192b84964622b7d6735', + './themes/default/images/ProjectExpandAll.gif' => '1910605074d6f26e568dc21aa96e2ce8', + './themes/default/images/ProjectDelete.gif' => '4ef20c4cba758dfb05e48684c3be5ffe', + './themes/default/images/ProjectCut.gif' => '710ffc5a60e29507c0ddda70ffb6d97e', + './themes/default/images/ProjectCopy.gif' => '8287a031948f6d670d90e827af6fce31', + './themes/default/images/ProjectCollapseAll.gif' => '97f5d2f6e6c9d2d967d751d4dfabfcc6', + './themes/default/images/Project2Weeks.gif' => '099efa2eb9e391a6d908eb583915d999', + './themes/default/images/Project.gif' => '0f2bbcc30e50b5eab1d048f2ab765e47', + './themes/default/images/Product_Types.gif' => 'ba210721c31f762ce799b1494a30c3b9', + './themes/default/images/ProductTemplates.gif' => '9ec09d637b692326d91d4d440027fa4b', + './themes/default/images/Print_Email.gif' => '268880a56f51100e33f9a68bf25fb14c', + './themes/default/images/PatchUpgrades.gif' => 'e1bf9565545d0f9db2f91f04a3dfa758', + './themes/default/images/Password.gif' => '086dda11a59db50c8440183881f65c0c', + './themes/default/images/OpportunityReports.gif' => '7d7c840292ae89a66e97afa3e68df9a7', + './themes/default/images/Opportunities.gif' => 'ec7850c09b72c670df154aa110c79dd8', + './themes/default/images/OnlineDocumentation.gif' => 'bd0436d969ff34a660e7b232030d3009', + './themes/default/images/Notes.gif' => '292043a6551d4603e78593e82593ebc8', + './themes/default/images/Newsletters.gif' => '600e2e1f5cac2dbee54a9007205bcd86', + './themes/default/images/MyProject.gif' => '89d4806940ca826bac6410b618dbf5d9', + './themes/default/images/MoreDetail.png' => '1a47ea4ae673fbe8968198bfda6160a6', + './themes/default/images/ModuleLoader.gif' => 'ac4f600f348a8c3bbf32c9082764b03e', + './themes/default/images/ModuleBuilder.gif' => '0fe61ab8532b0383257a0622b946662c', + './themes/default/images/MigrateFields.gif' => 'a79346f2c230cd4c1007a9862ed61924', + './themes/default/images/Meetings.gif' => '2c72354fdd58d87185411e82cc21bf8d', + './themes/default/images/MatrixReportOver.gif' => 'ca3be4462316c7afea373bb8c1dd1675', + './themes/default/images/MatrixReport.gif' => '6c99c710b2e8dab38ad44c00d3077183', + './themes/default/images/Manufacturers.gif' => '766a34c1e1b72f73e3bf1f10967157cd', + './themes/default/images/MailboxesTestImport.gif' => '24805afea32fdc482f4e361f646688bd', + './themes/default/images/License.gif' => '608b6f103f2b754e79434b8b777ad05d', + './themes/default/images/Leads.gif' => 'b175423893fda627ea17f28a56cb6e59', + './themes/default/images/Layout.gif' => '35df00aa3f68c87b0aecabc831845f1d', + './themes/default/images/LanguagePacks.gif' => '05135c460d24ae3e66fb05e9b482665a', + './themes/default/images/KBDocuments.gif' => '1d466eaeda296f54c42a7e473e4f6c0c', + './themes/default/images/KBArticle.gif' => '1d466eaeda296f54c42a7e473e4f6c0c', + './themes/default/images/KB.gif' => 'c2718316fee41c86feb233435b554c36', + './themes/default/images/InboundEmail.gif' => 'fed8e9392ab61a5a44b563ecfc5c0005', + './themes/default/images/ImportCustomFields.gif' => '289a0dbdce175f1965e967472b5c4484', + './themes/default/images/Import.gif' => 'ec8d49ed5fb711f57b417cfe1d0488d4', + './themes/default/images/Holidays.gif' => '92b9af82ee68587554ec248e968df011', + './themes/default/images/FieldLabels.gif' => '163d3292d1080120c96e991c9d8c411a', + './themes/default/images/Feeds.gif' => '0d29ec2ee3476d83dcf7757ea3874ecd', + './themes/default/images/FavoriteReports.gif' => 'c16aa5c7a37ecfa94ab08f910b93e9a4', + './themes/default/images/ExportCustomFields.gif' => '6ddd4192adc8637ccf791e51c793f828', + './themes/default/images/Employees.gif' => '28e6705d0394e3f993a4366a59d1f7ce', + './themes/default/images/Emails.gif' => '2f78dfe83afc2d333fa74d0794630f23', + './themes/default/images/EmailTemplates.gif' => '2f78dfe83afc2d333fa74d0794630f23', + './themes/default/images/EmailSetupWizard.gif' => 'ba3c3a98ea383dc47a87af1f65218031', + './themes/default/images/EmailMan.gif' => '1947b99573ba0d64f5eab2813ce9436b', + './themes/default/images/EmailFolder.gif' => 'c483bfcd31c873a997c360baf703773c', + './themes/default/images/EmailDiagnostic.gif' => '42ac00c64920143627f00c63b737f90f', + './themes/default/images/EditLayout.gif' => 'a63bb099ded39d833199d47c9fdb3ead', + './themes/default/images/Dropdown.gif' => 'da9558529b3727e61e30401e8175e1f7', + './themes/default/images/Documents.gif' => '0c114a3f4cb2d096c724d656c905f2ad', + './themes/default/images/DocumentRevisions.gif' => '3835202af7013415ffae7bdc8fcf4ae6', + './themes/default/images/Diagnostic.gif' => '39b302edd4e3839712d840ac1b3be940', + './themes/default/images/DataSets.gif' => '80b250c42133beaab652ee142ce4e872', + './themes/default/images/Dashboard.gif' => '236427476f3a491e8c7b0b184d85e431', + './themes/default/images/DCELicensingReport.gif' => 'b255bb8ae39976fd6c83c3037d090f36', + './themes/default/images/DCEActions.gif' => 'dde16f8608d3aeef715ed9ad7e57956e', + './themes/default/images/CustomQueries.gif' => '01e9e4094828c8fc64b2e89ba471b830', + './themes/default/images/Currencies.gif' => '8d1421616dcc7965a2995ea286cfb00d', + './themes/default/images/CreateiFrames.gif' => '2def896bb91201710ee131522715616f', + './themes/default/images/CreateWebToLeadForm.gif' => '5c34510b1241c7cf34eb885ddb45117d', + './themes/default/images/CreateUsers.gif' => '4d734abaed2d76e620e61427f22cc38a', + './themes/default/images/CreateTeams.gif' => '421c80edb890544d961afaaf0fb208e6', + './themes/default/images/CreateTasks.gif' => '4d6463cdf79b2c1cd010d601ef52fc07', + './themes/default/images/CreateScheduler.gif' => '2e5fade41c543b2ed1126c9194ed7a51', + './themes/default/images/CreateRoles.gif' => 'ab9c72a16e60764e035ffac6567df86b', + './themes/default/images/CreateQuotes.gif' => 'b38cea113277578a6129720ff6a068da', + './themes/default/images/CreateQuery.gif' => '94d3ce011099602f29ad6b83dfaa2bc4', + './themes/default/images/CreateProspects.gif' => '430421f03ca03f95b3ca5deb00966403', + './themes/default/images/CreateProspectLists.gif' => 'b47839294deb452586135734cc13cdb2', + './themes/default/images/CreateProjectTemplate.gif' => '684bd67db7cca4190dc4b49c0a8e83bb', + './themes/default/images/CreateProjectTask.gif' => '67ac607e90a8860af5fa31d18d9f53e0', + './themes/default/images/CreateProject.gif' => '74dd612dc97d6d2c65b172057040b59c', + './themes/default/images/CreateOpportunities.gif' => 'a9589cfff43f2a16963772a928b93fce', + './themes/default/images/CreateNotes.gif' => '1c001421c72c428f4a5acbc944e43301', + './themes/default/images/CreateMeetings.gif' => '8782a51731204d530a218de9dcf72d0c', + './themes/default/images/CreateMailboxes.gif' => '514b96d819aed1a9a618382cc18f74ef', + './themes/default/images/CreateLeads.gif' => '7a295c6e01b5ed10293dbc942fdc5013', + './themes/default/images/CreateKBArticle.gif' => '5528bfd3ccd117da8ee76453b8fffec8', + './themes/default/images/CreateHolidays.gif' => '74bb94942b330a7353ebfddb3e395710', + './themes/default/images/CreateEmployees.gif' => '4db0f4883525baa72d760602b0d0a9d6', + './themes/default/images/CreateEmails.gif' => 'c73f6fa2d64183c99f6b43fd3e8457cb', + './themes/default/images/CreateDropdown.gif' => '62f0e60bfb25e8210266f0c46a724b7b', + './themes/default/images/CreateDocuments.gif' => 'b6803a3158f8aafb797dcf40e40c7f5a', + './themes/default/images/CreateDCETemplates.gif' => '235a27f63ec69172665a9725de0138ab', + './themes/default/images/CreateDCEInstances.gif' => '37d2083c5656806c41f379de561de12e', + './themes/default/images/CreateDCEDataBases.gif' => '030b11434890898ea46f7eb47e26ca74', + './themes/default/images/CreateDCEClusters.gif' => '7412cac6f131844a2be1b2259bb7bdb2', + './themes/default/images/CreateContacts.gif' => '543275e52941e451c0594dbc10c19ac5', + './themes/default/images/CreateCases.gif' => 'd3e6eb8dd24fbd768cc2a203e035dfe4', + './themes/default/images/CreateCampaigns.gif' => '698c76de164b71478d1fae396248f976', + './themes/default/images/CreateCalls.gif' => 'faf97408d67ad4ab815d81dbfe5dc2c9', + './themes/default/images/CreateBugs.gif' => 'f5d7a5030b9d2f7efb6d1a5a4cc82cef', + './themes/default/images/CreateAccounts.gif' => 'ea824000c6d1db94e57df7cc78cb9b3c', + './themes/default/images/Contacts.gif' => '18553d7e06e2b115dcd8ae18a00c692e', + './themes/default/images/ConfigureTabs.gif' => '58ddcd48ddbbf664fc2a22320ff4cd81', + './themes/default/images/ConfigureSubPanels.gif' => 'd11894b643f3c8350e58a2a279539a08', + './themes/default/images/Cases.gif' => '9ff67484d4e580f7ec6b1c4fadef4e6c', + './themes/default/images/CampaignsWizard.gif' => 'c3d4e57e0dbbf6eb079c79b2bfdb7d70', + './themes/default/images/Campaigns.gif' => 'caf6345d36c8b318148e08eb017fc592', + './themes/default/images/Calls.gif' => 'fb79ca6ff562b6321c30039d577a55cc', + './themes/default/images/Calendar.gif' => 'ac7a361a60069ea66eded3e8fc22d253', + './themes/default/images/Bugs.gif' => 'b147d01e9f226777cf497b92439efdf0', + './themes/default/images/BugReports.gif' => '9edff2df8863ace2cf1e7986e5423523', + './themes/default/images/Backups.gif' => '1e5b888a85fe97b85e32a23544a53d40', + './themes/default/images/Backup.gif' => '4cf4850d478c593d3ab33fb60fdf2b6c', + './themes/default/images/ArrowButtons.png' => '3cc685bfa21913c19ebacce89568b882', + './themes/default/images/AllRSS.gif' => 'c6438ac72aed8be0bb89ad7981d23e92', + './themes/default/images/AllNews.gif' => 'c6438ac72aed8be0bb89ad7981d23e92', + './themes/default/images/AlertEmailTemplates.gif' => '92010f89490e4fdae70a4ecee1bfbd5d', + './themes/default/images/Administration.gif' => 'a68a5b890796251b8947061f696ca15e', + './themes/default/images/ActivitiesReports.gif' => 'ad890a0190fedffa6bcb73557060fa9b', + './themes/default/images/Accounts.gif' => 'e081de07d0263b270d0d306642375901', + './themes/default/css/wizard.css' => '31833a6ae4a11690ff41416a5e0f9b70', + './themes/default/css/style.css' => 'd41d8cd98f00b204e9800998ecf8427e', + './themes/default/css/print.css' => 'a3f18f20167ffd8fa8ece2a1e4a31e13', + './themes/default/css/deprecated.css' => '13f41876c3a31bde4ac2e1223bdd707c', + './themes/default/css/chart.css' => 'dda00a834e88692f3d08bec70db12dc9', + './themes/Sugar5/tpls/header.tpl' => 'a0fba0213a34dccdb5d6e1abafb8525c', + './themes/Sugar5/tpls/footer.tpl' => '7add32de99b51b0cd85086f95ad9ee6e', + './themes/Sugar5/tpls/_welcome.tpl' => 'fcf6220c8e3e3c9549e86e4082354ac2', + './themes/Sugar5/tpls/_headerShortcuts.tpl' => 'b43780c04a2874ee1768845932567b0e', + './themes/Sugar5/tpls/_headerSearch.tpl' => 'a4cd3c3b074d6f21d5bf2d20f2fae0ea', + './themes/Sugar5/tpls/_headerModuleList.tpl' => '2b3d435b2932dad411769c74bc7ca101', + './themes/Sugar5/tpls/_headerLastViewed.tpl' => 'cf8948eaee2c34049ab4b6d9b2e6ffb9', + './themes/Sugar5/tpls/_head.tpl' => '7f87d71644325839a9d490d9284e6674', + './themes/Sugar5/tpls/_globalLinks.tpl' => 'b8d95ed6b2227a463c08f0164816a1f4', + './themes/Sugar5/tpls/_companyLogo.tpl' => 'a3d2e1addc77f8715213e07f94117075', + './themes/Sugar5/themedef.php' => 'b3b0e75757b82719cf012af93901dddf', + './themes/Sugar5/layout_utils.php' => '68fa4045b1668a3d24cc4482f9e25ba9', + './themes/Sugar5/js/style.js' => '16dcc22d1ca9a072fa6d267acf5765e9', + './themes/Sugar5/images/yes.gif' => '5d3f887e0dbcd70a4708534be3bfa41a', + './themes/Sugar5/images/yellow_camp.gif' => '593075b0d0f3dca3343e500f0bc1b4f7', + './themes/Sugar5/images/xls_image_inline.gif' => 'e68c72edc63f0f8ab22a9b2cd49909c4', + './themes/Sugar5/images/view_status.gif' => '4e9aeb2524553f094d4e3ad9de90839c', + './themes/Sugar5/images/view_inline.gif' => 'a2f2198fc7a571a88cf6661ac22b1d8b', + './themes/Sugar5/images/view.gif' => 'a2f2198fc7a571a88cf6661ac22b1d8b', + './themes/Sugar5/images/uparrow_inline.gif' => '305e2d1a68316e78cf9b7059b1fd632f', + './themes/Sugar5/images/uparrow_big.gif' => '52a135285919ae19e94af09fcc8b556c', + './themes/Sugar5/images/uparrow.gif' => '52a135285919ae19e94af09fcc8b556c', + './themes/Sugar5/images/unscheduled_inline.gif' => 'fa3ecb4c47ae31097e011c514945023b', + './themes/Sugar5/images/unpublish_inline.gif' => '75cf70a4e97129cd0a2f9c8edc915d9d', + './themes/Sugar5/images/txt_image_inline.gif' => 'd5a939c64c645f0ebc69e436372ca9e0', + './themes/Sugar5/images/themePreview.png' => 'd75d6f95c236cd069d39ae7505852061', + './themes/Sugar5/images/tentative_inline.gif' => '7ce50732e43bbdde45b954694b14ec4b', + './themes/Sugar5/images/tabRowRedBg.gif' => '87d0b28828b106e5563dddeff1110544', + './themes/Sugar5/images/tabRowPurpleBg.gif' => 'dbd04a0929960614f412bcae69e50d09', + './themes/Sugar5/images/tabRowOcherBg.gif' => 'b030681c7db2a9bed844878f13b2d92d', + './themes/Sugar5/images/tabRowGreenBg.gif' => '9c7ccd42de0599e6647d9bae6b99d54d', + './themes/Sugar5/images/tabRowGrayBg.gif' => '52a8224e5fd67b0dcf27e4ab02759e06', + './themes/Sugar5/images/tabRowBlueBg.gif' => '46bde460b237581287809ad4cb0b92d0', + './themes/Sugar5/images/tabRowBg.gif' => '02d750917380f0e60dd8f293fc910ad5', + './themes/Sugar5/images/sugarupdate.gif' => 'f5ea1dae8f86aeb87a536ceaaa09208d', + './themes/Sugar5/images/sugar_icon.png' => '8a98242f1aae07923bf0c7289405b93b', + './themes/Sugar5/images/sugar_icon.ico' => '92f1ffd4b2fef157613e48d2d2c7d9c8', + './themes/Sugar5/images/sugar_document.png' => '649eeaf6da95e66caa7f961a25995e65', + './themes/Sugar5/images/sugarColors.xml' => 'cf9d69837a95f6167f126bf18d785884', + './themes/Sugar5/images/sugar-yui-sprites.png' => '79e1cc79ea3c01d3a7a3ad8c96de34ec', + './themes/Sugar5/images/sugar-yui-sprites-red.png' => '428926f9a17edbc9fbb714478803e6e4', + './themes/Sugar5/images/sugar-yui-sprites-purple.png' => 'cc60edba84b9b93804eab9ad3775b357', + './themes/Sugar5/images/sugar-yui-sprites-grey.png' => '25009499774224ae1f35d19cd65df6a6', + './themes/Sugar5/images/sugar-yui-sprites-green.png' => '4edc5be053baacacbd7d10f6eb54681c', + './themes/Sugar5/images/studio_undo.gif' => 'a8e4ca30f12eb152391782ebc1519264', + './themes/Sugar5/images/studio_save.gif' => '9a879acb70dda07e06e7719461ac7fe4', + './themes/Sugar5/images/studio_redo.gif' => 'd3a7aa42cc4d72047c6e97e36cec2d21', + './themes/Sugar5/images/studio_publish.gif' => '17b3a4edb24c576e9056fbf8a7d00576', + './themes/Sugar5/images/studio_history.gif' => 'ba2fdf14b162abf38ad809a4849944d8', + './themes/Sugar5/images/studio_blank.gif' => 'e2cc44b623bd7213fd8f18e1312f765a', + './themes/Sugar5/images/studio_addRows.gif' => 'b34fb09271096f03e497429c62a6c877', + './themes/Sugar5/images/studio_addField.gif' => 'f082ee05c412853e73f3e5fda1e0fa0f', + './themes/Sugar5/images/start_off.gif' => '0b357d4c67ded4c86d1c70c2c920ba70', + './themes/Sugar5/images/start.gif' => '52087392225974936d6ce7d2bb48babd', + './themes/Sugar5/images/sqsWait.gif' => '118ce5b9645fbadb2464ef0bd12ff895', + './themes/Sugar5/images/spacer.gif' => 'ed280a0ea3cc38f3cbbc747acfbef47d', + './themes/Sugar5/images/slot.gif' => '2859963e00e5456e56054fee1bb84964', + './themes/Sugar5/images/show_submenu_shortcuts.gif' => '2cf2f044333c693c0235eca6de839532', + './themes/Sugar5/images/show.gif' => 'db40a21333e315e8f66b58b8fe7c8663', + './themes/Sugar5/images/select.gif' => '2090e9761478fb6bee48c197b0f102dc', + './themes/Sugar5/images/searchMore.gif' => 'a69208b341a41938f65d88abe12f493b', + './themes/Sugar5/images/scheduled_inline.gif' => '9812da8482e09a3c4a2a54b99d717c20', + './themes/Sugar5/images/rightarrow_big.gif' => '6261e365b6f205ed19984eca672f3d4b', + './themes/Sugar5/images/rightarrow.gif' => 'aa8546cb02723ec14c7025159f254ade', + './themes/Sugar5/images/refresh.gif' => '8f48d8c61ed6dd5890954ded347f6550', + './themes/Sugar5/images/red_camp.gif' => '39110cd4e707f3f1ceb24dde98d65a9a', + './themes/Sugar5/images/publish_inline.gif' => '8a3c3103256b3592ec15c376835c0f04', + './themes/Sugar5/images/print.gif' => '0fc719a26f62a06dbfcacdb9b6447d4f', + './themes/Sugar5/images/previous_off.gif' => '62dc03295c496475543d5c3ee2ab51b9', + './themes/Sugar5/images/previous.gif' => 'c3d538b6c67aa6ce5fcc911cb062536f', + './themes/Sugar5/images/ppt_image_inline.gif' => '23151c677be1d3285d3acc07471ed39d', + './themes/Sugar5/images/plus_inline.gif' => '663569556d7adacbdc1e707490a7b754', + './themes/Sugar5/images/plus.gif' => '2246c11e24af9ea5873c1b550e1a3850', + './themes/Sugar5/images/pdf_logo_small.jpg' => '882437a1c98056a9c24d21ead8f42c92', + './themes/Sugar5/images/pdf_logo.jpg' => '98deac35a6b79b5f92b3b02f9d08f31a', + './themes/Sugar5/images/pdf_image_inline.gif' => '9c36962a5402ca969451093579cd8261', + './themes/Sugar5/images/pdf_header_logo_pdf_header_logo_SugarCRMheader.jpg' => 'dbd96f2c26aa37ced7ca6f3ffb30f8aa', + './themes/Sugar5/images/pdf_header_logo_img_left_arrow.jpg' => '42a3bd20247df71df2f3b4af7d79469d', + './themes/Sugar5/images/pdf_header_logo_SugarCRMheader.jpg' => 'dbd96f2c26aa37ced7ca6f3ffb30f8aa', + './themes/Sugar5/images/otherTabRed.gif' => '2d7fcbfb0e362659e32b7fe07f8d88b7', + './themes/Sugar5/images/otherTabPurple.gif' => '25390753d4f155296e6593ebb01356e9', + './themes/Sugar5/images/otherTabOcher.gif' => '7d543589ef9a75e121a149e02adf6040', + './themes/Sugar5/images/otherTabGreen.gif' => '250a64b44884e23e183f1f6ee526bb1c', + './themes/Sugar5/images/otherTabGray.gif' => '1b5e086627979c27a1eb883db0562afb', + './themes/Sugar5/images/otherTabBlue.gif' => 'd7e3090fcbe30db44bba3513c604b913', + './themes/Sugar5/images/otherTab.gif' => '87a4aca38528ca5aba1e54d6660e4a31', + './themes/Sugar5/images/open_multiple.gif' => 'c372922f378956f6b3bf56931d9ce2c8', + './themes/Sugar5/images/no.gif' => '262c91d4e47946e1d4aeff7f0f22614b', + './themes/Sugar5/images/next_off.gif' => '75c75524f41553432332b4ec0c99f9c7', + './themes/Sugar5/images/next.gif' => '834dc6b2b1b6aadd68f4677af017d5c7', + './themes/Sugar5/images/new_inline.gif' => '26aa1d757ecdaa1f886cd2bfb24eddd5', + './themes/Sugar5/images/more.gif' => '0fb09987f349939666c7ed893e336e87', + './themes/Sugar5/images/minus_inline.gif' => 'f051e7dc179ff6ab3f3c8b380f686501', + './themes/Sugar5/images/minus.gif' => '367ebb3ec8e01f8878dc252b56f0ab07', + './themes/Sugar5/images/menuarrow.gif' => 'b15abb42a41d475bf9f93755e971737e', + './themes/Sugar5/images/mass_update.gif' => '9b855db1e593f1e916dc478fa52648b6', + './themes/Sugar5/images/loading.gif' => '50c5e3e79b276c92df6cc52caeb464f0', + './themes/Sugar5/images/loadSignedDocument.gif' => 'afcccbee3447ffada5033d0cb7cb2b59', + './themes/Sugar5/images/listViewHR.gif' => 'eaa707253f1b7c4aab6f4841034ee7e3', + './themes/Sugar5/images/listViewBg.gif' => 'bb253dddfd00429a83bdb9e9a2b25305', + './themes/Sugar5/images/list.gif' => 'a4c8b293d7fa762d2c706bd68284cd67', + './themes/Sugar5/images/line.gif' => '5da41b8dfa2826bcecd84922b5e30ac7', + './themes/Sugar5/images/leftarrow_big.gif' => '1a1e6044a007b7f6be704544c1ab3d9b', + './themes/Sugar5/images/leftarrow.gif' => '5d56c1a6a00589aff97b8c9b9911d005', + './themes/Sugar5/images/jscalendar.gif' => '753d9d9f7e1e78f0fe75f25f8996692d', + './themes/Sugar5/images/info_inline.gif' => '9db230bae1c0ecdf0052806eb1b684f0', + './themes/Sugar5/images/info-add-page.png' => '59c6278627f16bc2bde3df34e83f027b', + './themes/Sugar5/images/img_right_arrow.jpg' => 'd4f8e8aa3ab1a663d1a55f8e3275e5d7', + './themes/Sugar5/images/img_loading.gif' => '00ef871b291bc03a497d608a5bd8ec99', + './themes/Sugar5/images/img_left_arrow.jpg' => '42a3bd20247df71df2f3b4af7d79469d', + './themes/Sugar5/images/img_close_search.gif' => '357d905eec06febe8ed2d3948f2eadcc', + './themes/Sugar5/images/icon_therevisions.gif' => '3f0f5b717ad53c0d551e5b03e9268f8b', + './themes/Sugar5/images/icon_sale.gif' => '709cf48456c82ccbfa4a038817e0c5e1', + './themes/Sugar5/images/icon_person.gif' => '19a7896996fac88e1bf4c7314cf126f2', + './themes/Sugar5/images/icon_package_create.gif' => 'e728aedae3a86f557a4431bcfb3b11b0', + './themes/Sugar5/images/icon_package.gif' => '6fe230ae81d0c1bfdc02f12554bfe5a6', + './themes/Sugar5/images/icon_opportunity.gif' => 'e8c75374653922482d1d5b71ee569909', + './themes/Sugar5/images/icon_new_package.gif' => 'e728aedae3a86f557a4431bcfb3b11b0', + './themes/Sugar5/images/icon_issue.gif' => 'dbe274a88ad4b289cf1f80be391620b3', + './themes/Sugar5/images/icon_iFrames_32.gif' => '264e84da5b4c48a4970f71550df86084', + './themes/Sugar5/images/icon_home.gif' => '15a02d5f4fd368aff08023822401bd39', + './themes/Sugar5/images/icon_expression_types.gif' => '34e7314d67aad0251bce11b1f7912aba', + './themes/Sugar5/images/icon_email_view3.gif' => '77592a420b9f1fd37da050c94083e9c3', + './themes/Sugar5/images/icon_file.gif' => '0037a12c8c4b623c5e0ea1803a6e95b5', + './themes/Sugar5/images/icon_email_view2.gif' => '1702d53e8aa6f660dd29d31b54bfa43e', + './themes/Sugar5/images/icon_email_view1.gif' => '7f5675af33f000f9fc9b48519b416c54', + './themes/Sugar5/images/icon_email_view.gif' => '0ddc870ec847e406a483d431de0c3b27', + './themes/Sugar5/images/icon_email_sugfolder_exp.gif' => '736434e15eb5273ed2adabb66451f7f7', + './themes/Sugar5/images/icon_email_sugfolder.gif' => '127016b7228674ac442ec5266caa3f79', + './themes/Sugar5/images/icon_email_settings.gif' => '129bbd92f356c68e63a94bcd53a1c225', + './themes/Sugar5/images/icon_email_send.gif' => '3069253177ad510279278f69f0cd5d78', + './themes/Sugar5/images/icon_email_save.gif' => '0c7f54e7bfee5ea8b782a8df7e52aac2', + './themes/Sugar5/images/icon_email_replyall.gif' => '5cad79693b03ece0364497e1538df029', + './themes/Sugar5/images/icon_email_reply.gif' => '2df1e0f100bc7e666a3efec19ed87d2d', + './themes/Sugar5/images/icon_email_relate.gif' => '74242467860ceb4110ff97449881e913', + './themes/Sugar5/images/icon_email_options.gif' => '9417e3643754ebb64efd1c8cdac2574f', + './themes/Sugar5/images/icon_email_mark.gif' => '59bd3232c7d2a3797caff08f111e47db', + './themes/Sugar5/images/icon_email_fullscreen.gif' => 'dcd3515feee571f3126eb2cda9be9d99', + './themes/Sugar5/images/icon_email_forward.gif' => 'ad895eb9b28efafa360141b2d463d07a', + './themes/Sugar5/images/icon_email_folder_sent.gif' => '84f050eabd42d189ff7ec33ef604a2a9', + './themes/Sugar5/images/icon_email_folder_grp.gif' => '95af0dfe5619fefcbe5e735a2f88e5d2', + './themes/Sugar5/images/icon_email_folder_exp.gif' => '34630bcf92e238c09294950a56533de7', + './themes/Sugar5/images/icon_email_folder_drafts.gif' => '44aeed88a8c7eaa04ceaa47980c264a4', + './themes/Sugar5/images/icon_email_folder_archives.gif' => 'a5d423896f3d34e7dae5a99788b9096d', + './themes/Sugar5/images/icon_email_folder.gif' => 'c84e3a04f0553457f2758c17328dcc64', + './themes/Sugar5/images/icon_email_delete.gif' => 'de0c2510e40fc90da261c3f24060489f', + './themes/Sugar5/images/icon_email_create.gif' => '1ed2501ee71cef192e87836feb66ecb8', + './themes/Sugar5/images/icon_email_compose.gif' => 'cbbab42834d7a19f657545f9fdf01dd4', + './themes/Sugar5/images/icon_email_check.gif' => '97f4bb665ca71c935b0c0d6a97156c4c', + './themes/Sugar5/images/icon_email_attach.gif' => 'cb6c0e533206569e383429c25c4f090d', + './themes/Sugar5/images/icon_email_assign.gif' => '892c9f96578002195ec4ea0f233fc8a9', + './themes/Sugar5/images/icon_email_archive.gif' => '01fe1cad58260b7bf63788e9ce5b68e9', + './themes/Sugar5/images/icon_email_addressbook.gif' => 'd950e8a8497cb37b660281d332a2767c', + './themes/Sugar5/images/icon_document.gif' => '167aee1d934419e6e8aa6235fee350ea', + './themes/Sugar5/images/icon_company.gif' => 'b2ef078b5afa7f07bbbc13587bc9990b', + './themes/Sugar5/images/icon_basic.gif' => '71bcdef4548fad731d44fc681e3a6599', + './themes/Sugar5/images/icon_back.gif' => '215aa2a3bcf6e67e0fb2aa25da2e8871', + './themes/Sugar5/images/icon_assistant.gif' => '9e75a064532dc80f6c44ffae3aa6501b', + './themes/Sugar5/images/icon_Users_32.gif' => 'c63b38ad112782578822a612fb102952', + './themes/Sugar5/images/icon_Trackers_32.gif' => '1fd19adde4d7ca809ad287c45a45100c', + './themes/Sugar5/images/icon_TrackerSessions_32.gif' => '5071e66a3fa459669f5ad5a2e4a6eaf9', + './themes/Sugar5/images/icon_TrackerQueries_32.gif' => '0c8a6bf47267515ea3b2be8b5ea16c73', + './themes/Sugar5/images/icon_TrackerPerfs_32.gif' => '998c775c84226d9a6d8d7a2cfee828b8', + './themes/Sugar5/images/icon_Teams_32.gif' => '1042e299464990cdbf312460171dbc6b', + './themes/Sugar5/images/icon_Tasks_32.gif' => '59dd94dfcfaed6273295f22658c77a75', + './themes/Sugar5/images/icon_Tasks.gif' => '91d11b48558775d6f940a4fe2fef9d8f', + './themes/Sugar5/images/icon_Targets_32.gif' => 'a791b861efaa860b3f356ce5644982ad', + './themes/Sugar5/images/icon_SugarPortal.gif' => 'bd9b140fefd8d3c8d25e5602d34455b1', + './themes/Sugar5/images/icon_SugarNews_32.gif' => '13513ac06c13bbcc28acddce996e79ba', + './themes/Sugar5/images/icon_SugarFeed_32.gif' => '91906aa110e0737571bdce7e982d6f5b', + './themes/Sugar5/images/icon_SugarFeed.gif' => 'c121b4f625c494d54a7c6e60a7159e73', + './themes/Sugar5/images/icon_Subpanels.gif' => '99b9a4c23b9d4d52c80db23b65241032', + './themes/Sugar5/images/icon_Studio.gif' => '6cff1d99350160b388f5a1ac529c3ff9', + './themes/Sugar5/images/icon_SearchForm.gif' => '9246e8668eb71fd1e2ebd20b6cb60ba1', + './themes/Sugar5/images/icon_SPUploadCSS.gif' => 'd912a8d76735acc061b566c950976995', + './themes/Sugar5/images/icon_SPSync.gif' => 'bc384598e25a00faa9e2efd942b357a0', + './themes/Sugar5/images/icon_Rss_32.gif' => 'adf9e9567964a6faf01005e83051d974', + './themes/Sugar5/images/icon_Reports_32.gif' => 'e25b26fb6a2a086087c81f9e2176b5e1', + './themes/Sugar5/images/icon_Releases_32.gif' => '8151d6de8614fdc220860f7e79b417b9', + './themes/Sugar5/images/icon_Relationships.gif' => 'ff28b08d448d6e1c732b2cf29f6096a3', + './themes/Sugar5/images/icon_Quotes_32.gif' => '74d821c6b4656e3b5a6548c5a854cb0f', + './themes/Sugar5/images/icon_Quotes.gif' => '3f1734fcd9e3c7d0885940a83e167e39', + './themes/Sugar5/images/icon_QuickCreate.gif' => '54cd777aafd156c049999c8b783cfa58', + './themes/Sugar5/images/icon_Prospects_32.gif' => 'a791b861efaa860b3f356ce5644982ad', + './themes/Sugar5/images/icon_Prospects.gif' => '5e5099f8f374fb63cb236e926a575938', + './themes/Sugar5/images/icon_Projects_32.gif' => '009174ec22ef8f1af05e0e06f55d5916', + './themes/Sugar5/images/icon_Project_32.gif' => '009174ec22ef8f1af05e0e06f55d5916', + './themes/Sugar5/images/icon_ProjectTask_32.gif' => '1092296917891851fc078c5e2f4d57df', + './themes/Sugar5/images/icon_ProjectTask.gif' => '4c826a1341be8b80fae67d6452ad087e', + './themes/Sugar5/images/icon_Project.gif' => '22a4aefdc49f3188585ab8103e4fd7c4', + './themes/Sugar5/images/icon_Products_32.gif' => '6e740000d2e08d22d4e24d63e84e8c9c', + './themes/Sugar5/images/icon_Products.gif' => 'c2a424dbe47e9e852aec589347348dc7', + './themes/Sugar5/images/icon_Product_Types_32.gif' => '1f5728ad9c07d67979eed73af625efbf', + './themes/Sugar5/images/icon_ProductTypes_32.gif' => '1f5728ad9c07d67979eed73af625efbf', + './themes/Sugar5/images/icon_ProductTemplates.gif' => '4c76239253a30c972bd02aec213e7830', + './themes/Sugar5/images/icon_ProductCategories_32.gif' => 'ce6e3a4a347467957275a5c0eee5e311', + './themes/Sugar5/images/icon_Portal.gif' => '4a107249e6596b0e0c724e7734fae92d', + './themes/Sugar5/images/icon_Phone.gif' => '69561dd53df8efc35c0919efcf546d2c', + './themes/Sugar5/images/icon_Opportunities_32.gif' => '787b58f02e8c7c118841abbffcf72f42', + './themes/Sugar5/images/icon_Opportunities.gif' => 'bb0d0125d317f78b6265fbcd7b6d827d', + './themes/Sugar5/images/icon_OpenTasks_32.gif' => 'd0c52359674d719e1e4da4c5ee3b3064', + './themes/Sugar5/images/icon_Notes_32.gif' => '38614c8b0fb8673bbf7118bc62d3571b', + './themes/Sugar5/images/icon_Notes.gif' => 'cdee31ac66f080bd6e862e0dcfcf1358', + './themes/Sugar5/images/icon_NewModule.gif' => '700412f4a1535f58dc358af2c15ddba4', + './themes/Sugar5/images/icon_MyTasks_32.gif' => '5af76e5299c5e6a2946ce3ed13d64d5f', + './themes/Sugar5/images/icon_MyPortal_32.gif' => '264e84da5b4c48a4970f71550df86084', + './themes/Sugar5/images/icon_ModuleBuilder.gif' => 'b0f8e050fa92fd761fce476dc361e9b9', + './themes/Sugar5/images/icon_MobileLayouts.gif' => '01d983c77ce576f3fbb42a67cd43b901', + './themes/Sugar5/images/icon_Meetings_32.gif' => '7cbed9de72d3c9e9e2aed8997ea4cd82', + './themes/Sugar5/images/icon_Meetings.gif' => '6b25f5507719dd934fdad9ae12125935', + './themes/Sugar5/images/icon_ListView.gif' => '557ee4b0eaa08c7566f5ff4522207bc1', + './themes/Sugar5/images/icon_Leads_32.gif' => '5c7ee135592a05a145456af63077fb3d', + './themes/Sugar5/images/icon_Leads.gif' => 'dd27a17fc38fb8b01398e35ac3d39fd0', + './themes/Sugar5/images/icon_Layouts.gif' => '4a107249e6596b0e0c724e7734fae92d', + './themes/Sugar5/images/icon_Labels.gif' => 'e7d722a222050cb2e92431c460ecad8a', + './themes/Sugar5/images/icon_KBDocuments_32.gif' => '605c4a7cac4ccc184ac013b9a6d4016e', + './themes/Sugar5/images/icon_KBDocuments.gif' => 'd74530d24f2e0bd57ef6681dbb20fe94', + './themes/Sugar5/images/icon_JotPad_32.gif' => '04e2a63f3d3afbe1de3cd6048cec1f50', + './themes/Sugar5/images/icon_JotPad.gif' => '1e5d01a07e4f988611af6677a037f318', + './themes/Sugar5/images/icon_Invaders_32.gif' => 'c669d4aff0cef7ab73e051c1443d8b3c', + './themes/Sugar5/images/icon_Forecasts_32.gif' => '20a3de4d107c962b0847d9dd7174cdbd', + './themes/Sugar5/images/icon_Forecasts.gif' => 'dcb0ee8f452baf1048d0fd9d3ba09312', + './themes/Sugar5/images/icon_Fields.gif' => '39677bcb6670ffd88f083419d9f9d1c5', + './themes/Sugar5/images/icon_Feeds_32.gif' => 'adf9e9567964a6faf01005e83051d974', + './themes/Sugar5/images/icon_FavoriteReports_32.gif' => '4fe2369941b3672b5c8f6594fcd15825', + './themes/Sugar5/images/icon_FavoriteReports.gif' => 'cec6ecb1c7befc7cb52b735bfc2a3e8f', + './themes/Sugar5/images/icon_Emails_32.gif' => '3626aef290eda2f9004d7e4d2c2e0791', + './themes/Sugar5/images/icon_Emails.gif' => '35464266090cc9d38551bcd2e0edf969', + './themes/Sugar5/images/icon_EmailAddresses_32.gif' => '834acafa896baa468fc22186d2cff2e4', + './themes/Sugar5/images/icon_EmailAddress.gif' => '6877d848391e0165e1106864b3d6d4cb', + './themes/Sugar5/images/icon_EditView.gif' => '2b40c926f5bec858704c1daa83f1eac9', + './themes/Sugar5/images/icon_DropDownEditor.gif' => '18036f2acc73b67b6168dec5798600bd', + './themes/Sugar5/images/icon_Documents_32.gif' => '945c2c18f5a9e119178cdebdb8f638c4', + './themes/Sugar5/images/icon_Documents.gif' => '3f0f5b717ad53c0d551e5b03e9268f8b', + './themes/Sugar5/images/icon_DetailView.gif' => '7e52a99c33829596b0a3210c5202a12d', + './themes/Sugar5/images/icon_DeleteFull.gif' => 'd9c1deab8458cf93d645d91dfba6207d', + './themes/Sugar5/images/icon_Delete.gif' => '501840cefe034dbdc2e4c2b54997cad5', + './themes/Sugar5/images/icon_Dashlet.gif' => '13af871521b34dac496b57b0e2c4eaa2', + './themes/Sugar5/images/icon_DCETemplates_32.gif' => 'f92673e7ebfdea9cbbebeab47a6100e0', + './themes/Sugar5/images/icon_DCEReports_32.gif' => 'db721d0bf19687c55bebc55c2922ed72', + './themes/Sugar5/images/icon_DCEInstances_32.gif' => '487fd352fe639c7d37e2826a1f923cbd', + './themes/Sugar5/images/icon_DCEDataBases_32.gif' => '199c8197b7f85857805c7c7266740b50', + './themes/Sugar5/images/icon_DCEClusters_32.gif' => '75e8758e88aa55696b3cd80ceda320bf', + './themes/Sugar5/images/icon_DCEActions_32.gif' => '7c334cfc9755f596e7868bb7993698a0', + './themes/Sugar5/images/icon_Contracts_32.gif' => '5c01388d8c6d287f07d4ade8a71882e3', + './themes/Sugar5/images/icon_Contracts.gif' => 'cf3fdd47fcdf25f23bc7d00781395280', + './themes/Sugar5/images/icon_Contacts_32.gif' => 'eeb8eb818c7813f77b479f7e1001d9d3', + './themes/Sugar5/images/icon_Contacts.gif' => '5c25642d0e7373ff3dc8670ef61fcfc1', + './themes/Sugar5/images/icon_Connectors.gif' => '741a28001f099adc694252df889a97ab', + './themes/Sugar5/images/icon_ConnectorSearchFields_16.gif' => '071b4fa50987f24aa8e439ad2c94977e', + './themes/Sugar5/images/icon_ConnectorSearchFieldsOver.gif' => '892037f83ee9b1a78b0968b64f008aa5', + './themes/Sugar5/images/icon_ConnectorSearchFields.gif' => '670c96db0ae37d1e7950ceb81f1f22bb', + './themes/Sugar5/images/icon_ConnectorMap_16.gif' => '21a1a3515ae02ed5fc0d8492a892f690', + './themes/Sugar5/images/icon_ConnectorMapOver.gif' => '5c4beb392911c203ac8ab9f55ca80efb', + './themes/Sugar5/images/icon_ConnectorMap.gif' => '28f0ba3ad323e08f917693cd5ef3286f', + './themes/Sugar5/images/icon_ConnectorEnable_16.gif' => '139c5d2ed03e09e69c2427aa461d0abb', + './themes/Sugar5/images/icon_ConnectorEnableOver.gif' => '4c68d747832656f8a373308a5571aa2c', + './themes/Sugar5/images/icon_ConnectorEnable.gif' => '6c53d58521fee6d29e35583f11f80b7c', + './themes/Sugar5/images/icon_ConnectorConfig_16.gif' => 'c455945b702d168f0c55f630bc909a03', + './themes/Sugar5/images/info-del.png' => '54d3de3d716db37d7fe7d1b0461e4328', + './themes/Sugar5/images/icon_ConnectorConfigOver.gif' => 'f24b62af2fc23e3c5f675a7454968688', + './themes/Sugar5/images/icon_ConnectorConfig.gif' => '1024aa4e200381bf481888131023b5a2', + './themes/Sugar5/images/icon_Column_3.gif' => '3a967a62ac79e9be7d953730c550bf14', + './themes/Sugar5/images/icon_Column_2.gif' => 'bf25350fb235d301601b87b687160d17', + './themes/Sugar5/images/icon_Column_1.gif' => 'b819b73077afdfd13c3f84f77e1cb8c5', + './themes/Sugar5/images/icon_Charts_Vertical_32.gif' => 'e8a3b35973d514875fdb9507728357e3', + './themes/Sugar5/images/icon_Charts_Vertical.gif' => 'f15275758c20b1c829c9ed3dcc88d3c1', + './themes/Sugar5/images/icon_Charts_Pie_32.gif' => '1dd970dabcb5de6a9fa742893ad28c3b', + './themes/Sugar5/images/icon_Charts_Pie.gif' => 'b65cc013f3b9c6b50e46722fbc027cf4', + './themes/Sugar5/images/icon_Charts_Horizontal_32.gif' => 'e84af669b14b4288b699a0d6d5dd17fc', + './themes/Sugar5/images/icon_Charts_Horizontal.gif' => '928245490307b01d3cca736630187fe1', + './themes/Sugar5/images/icon_Charts_GroupBy_32.gif' => 'a1c69c3e8be5e54bd2b6be6dd97d1835', + './themes/Sugar5/images/icon_Charts_GroupBy.gif' => 'b444f2b91a51489e19c3f56b859121da', + './themes/Sugar5/images/icon_Charts_Gauge_32.gif' => 'c4ba44d5ad9209d6e37565ec1faf91ea', + './themes/Sugar5/images/icon_Charts_Gauge.gif' => 'cb0c4825703e0f816ce5edf7693a4206', + './themes/Sugar5/images/icon_Charts_Funnel_32.gif' => '9d60fb449cb26d8f13ff4fd05dd17451', + './themes/Sugar5/images/icon_Charts_Funnel.gif' => 'fbbeb7f36751a847b43cbc29042bef83', + './themes/Sugar5/images/icon_Cases_32.gif' => 'e74f7b4a4f513c517351fe0e15ec9f7d', + './themes/Sugar5/images/icon_Cases.gif' => '86c8c9ce83c9feab641687fa968d1705', + './themes/Sugar5/images/icon_Campaigns_32.gif' => '4b2651b74c0df08fb38da1c50ad55540', + './themes/Sugar5/images/icon_Campaigns.gif' => 'd326b30e1f37d6b1ae7585bec2603f75', + './themes/Sugar5/images/icon_CampaignLog_32.gif' => '4b2651b74c0df08fb38da1c50ad55540', + './themes/Sugar5/images/icon_Calls_32.gif' => 'b1396f0d4aad67469aade38e1c1ad57a', + './themes/Sugar5/images/icon_Calls.gif' => '70a325dc66ac4330ba4920655cc9d2f1', + './themes/Sugar5/images/icon_Bugs_32.gif' => '007a66380bb5ac5a9053c1e3932c4452', + './themes/Sugar5/images/icon_Bugs.gif' => 'daa1bafd411fa579d13aeb01832fe018', + './themes/Sugar5/images/icon_BasicSearch.gif' => '34138a6f18eda6680e2b6ac129888e74', + './themes/Sugar5/images/icon_Application.gif' => '9f19f9a35c1269591cf0f4503fb4b0a4', + './themes/Sugar5/images/icon_AdvancedSearch.gif' => '5a13f19316a76136a13e23f39bce0c73', + './themes/Sugar5/images/icon_AdminThemes.gif' => '3dabb98180140be0f27983c53fb93fa3', + './themes/Sugar5/images/icon_AdminPDF.gif' => 'c4cd278746674615533992c06439c5c5', + './themes/Sugar5/images/icon_AdminMobile.gif' => '4aa8c94a81f105a4823afdf79f013e3d', + './themes/Sugar5/images/icon_Address.gif' => '01031291c5fb1552e40d63f1b08c0314', + './themes/Sugar5/images/icon_Activities.gif' => '1e5d01a07e4f988611af6677a037f318', + './themes/Sugar5/images/icon_Accounts_32.gif' => 'b0c893a480c52340a287af42547b4977', + './themes/Sugar5/images/icon_Accounts.gif' => '34ca712c6aa6b7ba68882e330423c057', + './themes/Sugar5/images/icon_A1_newmod.gif' => '71bcdef4548fad731d44fc681e3a6599', + './themes/Sugar5/images/iFrames.gif' => '0a0e964460018c0dc9295d9c48773952', + './themes/Sugar5/images/hide_submenu_shortcuts.gif' => '4faa81f7be7484ed9442ad726ec56bcb', + './themes/Sugar5/images/hide.gif' => '63afbcf6fa1496c0e933c26bde33e1be', + './themes/Sugar5/images/helpInline.gif' => '904c4318b2195909683e239f45fe7543', + './themes/Sugar5/images/help.gif' => 'ea88b2a7841ae9e84005b5c126df88e3', + './themes/Sugar5/images/h3Arrow.gif' => '0a8858f4bda73af356182ba99ae6b4d4', + './themes/Sugar5/images/green_camp.gif' => 'c2b67c21d37fd3d49b6f01b062f36529', + './themes/Sugar5/images/getLatestDocument.gif' => 'ca3c6fbc6d4d6d39a637eed0bfc4a08a', + './themes/Sugar5/images/formButtonBgOn.gif' => '668b0ee95cf4b0792c03f91a82fcfb91', + './themes/Sugar5/images/formButtonBg.gif' => 'd9a0a446c17015d99879870c0ae585c1', + './themes/Sugar5/images/fonts.normal.icon.gif' => 'd15ee190de151df2fc02366847a42333', + './themes/Sugar5/images/fonts.largest.icon.gif' => '93227b0e5335d1c749d0c62f932f7246', + './themes/Sugar5/images/fonts.larger.icon.gif' => '8ed79085035c19fa3a08a57821ccff68', + './themes/Sugar5/images/export.gif' => '3141bb408338e95954f49498ab2074a3', + './themes/Sugar5/images/end_off.gif' => '6f2b185bd8b4f04255184d7c3b972be4', + './themes/Sugar5/images/end.gif' => '99ec17980972c2227478df9ca2b09abf', + './themes/Sugar5/images/emptyTabSpace.gif' => 'e8f77ea4d4936a67560b361411f260ac', + './themes/Sugar5/images/editview.gif' => 'a63bb099ded39d833199d47c9fdb3ead', + './themes/Sugar5/images/editlabels.gif' => 'a63bb099ded39d833199d47c9fdb3ead', + './themes/Sugar5/images/editfields.gif' => '163d3292d1080120c96e991c9d8c411a', + './themes/Sugar5/images/edit_wizard.gif' => 'fe64a594539d3561d50fd34fd94143a5', + './themes/Sugar5/images/edit_inline.gif' => '6ba1fa243664fb3cfa0cab4b24592d2d', + './themes/Sugar5/images/edit.gif' => '1f3d5009fc12cd0117903d8959a559e9', + './themes/Sugar5/images/downarrow_inline.gif' => '505e2477efbea90592a169aafbe41794', + './themes/Sugar5/images/downarrow_big.gif' => 'b4ffaa11d20c5433c8ce6f392b27c02d', + './themes/Sugar5/images/downarrow.gif' => '4d89350bedf353e12294bad2c2fe5ae6', + './themes/Sugar5/images/doc_image_inline.gif' => '1f4a7d82e86352ac2121acc844dc6d4a', + './themes/Sugar5/images/detailview.gif' => '2645ccf6df6dc9d58ce65f3d1c6d2b67', + './themes/Sugar5/images/detailViewBg.gif' => '29d8425fa2b3989a037bf2128584d6f8', + './themes/Sugar5/images/delete_inline.gif' => 'ec132bd60b0000543ec4efd32c76c50c', + './themes/Sugar5/images/delete.gif' => '697dc7d112e2ebc278eccea520d520dc', + './themes/Sugar5/images/def_image_inline.gif' => 'b31f890084d972950ae50e513e4ef1c6', + './themes/Sugar5/images/decline_inline.gif' => 'd9e006d8758ad871d7395cf931dec405', + './themes/Sugar5/images/dce_Settings.gif' => 'b255bb8ae39976fd6c83c3037d090f36', + './themes/Sugar5/images/currentTabRed.gif' => '61f911fae96b5f90d2525613bd3b1dc7', + './themes/Sugar5/images/currentTabPurple.gif' => '3cc2d348b8073e73ececbc4ae361220b', + './themes/Sugar5/images/currentTabOff.gif' => 'e0a67ebcd0eec021c19f4ab454759e8f', + './themes/Sugar5/images/currentTabOcher.gif' => '4852317d212d6e5a1ce7b0036dd77e45', + './themes/Sugar5/images/currentTabLinkBg.gif' => 'acc41261d49919fc0b20c3bb009d3af0', + './themes/Sugar5/images/currentTabGreen.gif' => '085f9927ac24c8311c3779c3d6733440', + './themes/Sugar5/images/currentTabGray.gif' => '95c3cb31673ed2da9e979938a48c09c8', + './themes/Sugar5/images/currentTabBlue.gif' => '294f6bb00ba34db9b2227dd7140651ef', + './themes/Sugar5/images/currentTab.gif' => '6f2002081ed96fd0931f686d24bacd78', + './themes/Sugar5/images/colors.sugar.icon.gif' => 'e38d443ab9b82145d88c0c97fed53789', + './themes/Sugar5/images/colors.red.icon.gif' => 'b1168092ee831ee08b535fe066d11246', + './themes/Sugar5/images/colors.purple.icon.gif' => 'b89bae62c86fc22236ba93c1f2b1a245', + './themes/Sugar5/images/colors.orange.icon.gif' => '3a5a16d7a8c5e411bb63aefe58b75e17', + './themes/Sugar5/images/colors.green.icon.gif' => '248e791c8a93cb006b630112a44d71b7', + './themes/Sugar5/images/colors.gray.icon.gif' => '77fe1105f4be1d9b336ec346b17891dc', + './themes/Sugar5/images/colors.blue.icon.gif' => '48d30c2c20d84f45455008f6254e21e1', + './themes/Sugar5/images/close_inline.gif' => '4706ecc190ed6d3cf0024cfdeef7540a', + './themes/Sugar5/images/close_dashboard.gif' => 'dba10edcd9ab300f2483dc8de161e91a', + './themes/Sugar5/images/close.gif' => '00a1e63ea66cad36fd357afcec227e3b', + './themes/Sugar5/images/clear.gif' => '3a6bcb1c1b1ddb11df095f281803433d', + './themes/Sugar5/images/check_inline.gif' => '3fd7b54b12de5ee794dd44c53c7d9b7d', + './themes/Sugar5/images/calendar_previous.gif' => '600d00e3bd8a384dc5f851646c513390', + './themes/Sugar5/images/calendar_next.gif' => 'f128d2e8cff00f25d3fc6aca822acc54', + './themes/Sugar5/images/calendarHeaderBg.gif' => 'e737dc503d8ebfd782d55ecbb9fa3ab7', + './themes/Sugar5/images/blank.gif' => 'fc94fb0c3ed8a8f909dbc7630a0987ff', + './themes/Sugar5/images/bgRed.gif' => '1df40fd5435907a1fed4d4b181ea6b46', + './themes/Sugar5/images/bgPurple.gif' => 'c1b6d97ad95f8388da34d4a4175a81d3', + './themes/Sugar5/images/bgOcher.gif' => '982082d036e99833dc1f1a483fce2a5d', + './themes/Sugar5/images/bgGreen.gif' => '3bfe3b4d1fc2f0ef39f90507fb4a43d2', + './themes/Sugar5/images/bgGray.gif' => '1c6dfddeae3b2d18974506837c29ccef', + './themes/Sugar5/images/bgBtnPurple.gif' => '0c88b16eb4908ef062773520a9211fb1', + './themes/Sugar5/images/bgBtnOrange.gif' => 'f85be7940606135360db38bb8dc4ad36', + './themes/Sugar5/images/bgBtnGreen.gif' => 'f278617bef25b52737a1c1c535c85bca', + './themes/Sugar5/images/bgBtnGray.gif' => 'bc636fcc0fde952eee600795e26f3568', + './themes/Sugar5/images/bgBtnBlue.gif' => 'd81f5ba78f4717e5723adf3843437ee4', + './themes/Sugar5/images/bgBtn.gif' => 'ad46bd5437826c67f8919874f6f3bea0', + './themes/Sugar5/images/bgBlue.gif' => 'def431ff46dac5dc23aa47a531b13343', + './themes/Sugar5/images/bg.gif' => 'e542169ee5ed28cdb45b3996603193d6', + './themes/Sugar5/images/basic_search.gif' => 'afc9992d8567a78b5b7df196549eb29a', + './themes/Sugar5/images/bar_loader.gif' => 'e67d85a8d2d4021514815d0ff4d65173', + './themes/Sugar5/images/attachment.gif' => 'ad2683b97bcee20be7ba039d3259b2fa', + './themes/Sugar5/images/arrow_up.gif' => '3c0164a46adc6ddcb9fec3cf1129e190', + './themes/Sugar5/images/arrow_down.gif' => '7ae60aa70170713428e265b1cc695291', + './themes/Sugar5/images/arrow.gif' => 'e351c2d5a2ad28ee72a15e1d2ce7e2bd', + './themes/Sugar5/images/advanced_search.gif' => 'd0022a5800ff6a11b04c6e27293d717c', + './themes/Sugar5/images/accept_inline.gif' => 'bbb0aed40e938669c98b65642a400a7d', + './themes/Sugar5/images/_blank.png' => '9bbf8b89dfee264016a5cf95daa02a10', + './themes/Sugar5/images/WorkflowSequence.gif' => 'b9e51ce79d65182c0748279018448b7e', + './themes/Sugar5/images/WorkFlow.gif' => '658b40aa9fb3ffcabb432ea328ad8415', + './themes/Sugar5/images/Users.gif' => 'a2e9e7731e06a4fdfb2f49563e98af6b', + './themes/Sugar5/images/UpgradeDCEInstances.gif' => '31f57a942f93564c75925c5c31f36644', + './themes/Sugar5/images/Upgrade.gif' => '31f57a942f93564c75925c5c31f36644', + './themes/Sugar5/images/Trackers.gif' => '7982f8a7fda959763e0ddd42bea0af7e', + './themes/Sugar5/images/TimePeriods.gif' => '8bef1e7f6a0ee77b6647cfc4a0751b72', + './themes/Sugar5/images/Themes.gif' => '05511600d7087ec404b6aa7f02d2a7b4', + './themes/Sugar5/images/Teams.gif' => '8fce7827080693884dc5022b6b473940', + './themes/Sugar5/images/TaxRates.gif' => '396d48130733c340ce8ee093013d94d6', + './themes/Sugar5/images/Tasks.gif' => 'a4c8b293d7fa762d2c706bd68284cd67', + './themes/Sugar5/images/TaskReports.gif' => '294a24ced60317d6a909a714e57f8d56', + './themes/Sugar5/images/Support.gif' => 'c6fae35bc372012c1a5d5e0b5f22ada5', + './themes/Sugar5/images/SummationWithDetailsOver.gif' => '807077e21b5c6ce180a7a1e0afbb4f7b', + './themes/Sugar5/images/SummationWithDetails.gif' => '332fa7357f54428c5915518695824a69', + './themes/Sugar5/images/SummationOver.gif' => 'fe76f4f7000c4ea19b6c4176a4550887', + './themes/Sugar5/images/Summation.gif' => 'd85caef83542e64a75e265fbd0564d3f', + './themes/Sugar5/images/SugarPortal.gif' => '5cafb18cdfd6265e77f852dc00b8ff93', + './themes/Sugar5/images/Studio.gif' => '2941190a8b8f1c37cd373e8474abaff2', + './themes/Sugar5/images/StickyThread.gif' => '35afdc080b5426b09be58bf765a1c4a7', + './themes/Sugar5/images/Shippers.gif' => 'daa6d24122b0df9fc1dc5943ce449058', + './themes/Sugar5/images/Search.gif' => '089000300b21c8ff74c2e258e9b44bd4', + './themes/Sugar5/images/Schedulers.gif' => 'c0160825b845a73b070194906e818aee', + './themes/Sugar5/images/SchedulerTest.gif' => '635fcbfc6d5eb2785ef2e6c6f8360a91', + './themes/Sugar5/images/RowsAndColumnsOver.gif' => 'b09fbec8214a744010e69b6cbc071379', + './themes/Sugar5/images/RowsAndColumns.gif' => 'ff458b8e2303ec31d0f6b2ded6140ea0', + './themes/Sugar5/images/Roles.gif' => 'dcbf376b885458b1fc8c21de7884284e', + './themes/Sugar5/images/Reports.gif' => 'bb24a8be9e6989ac92388904f95ed183', + './themes/Sugar5/images/ReportMaker.gif' => 'd7db8b4fabcfec16fbb25c15296d6f7f', + './themes/Sugar5/images/Repair.gif' => 'adca1c05640dc8f3cd315afbc8d323e2', + './themes/Sugar5/images/RenameTabs.gif' => '895241cf5de9d8519169e2b9ef03e08f', + './themes/Sugar5/images/Releases.gif' => 'ff8de6cf41ad9056011973384f2e0602', + './themes/Sugar5/images/Rebuild2.gif' => '4e1dd889a93a7131cdb8204ae321fe5a', + './themes/Sugar5/images/Rebuild.gif' => 'fa51c1e12cfd77a0a5076b92c2d0b218', + './themes/Sugar5/images/ReassignRecords.gif' => 'efc325a2f834ce64b1c7cf195917ed77', + './themes/Sugar5/images/RSS.gif' => '0d29ec2ee3476d83dcf7757ea3874ecd', + './themes/Sugar5/images/Quotes.gif' => '5affc4f4bfe4676c2a38cf3d3fba411a', + './themes/Sugar5/images/QuoteReports.gif' => 'c6681a4817efaf2a036be75e94c97c98', + './themes/Sugar5/images/QueryBuilder.gif' => 'd705b041b021686b3b5e286305820163', + './themes/Sugar5/images/Prospects.gif' => 'a7bd5ae5e32198b8826d6986d84a8ad1', + './themes/Sugar5/images/ProspectLists.gif' => '9b1a622509e5881ec791edf4f68f5e95', + './themes/Sugar5/images/ProjectWeek.gif' => '077ad399f8640fb0e166eaed6c29cd35', + './themes/Sugar5/images/ProjectTemplate.gif' => 'f30534d557373942ec06aad47f735c01', + './themes/Sugar5/images/ProjectTask.gif' => 'f0be8090159b3a874267c3bc27c5a1c3', + './themes/Sugar5/images/ProjectSave.gif' => 'e5d6feda33978980d8e1b73446ca0cc3', + './themes/Sugar5/images/ProjectPlus.gif' => '23840e38f362cb897374c51441d4379d', + './themes/Sugar5/images/ProjectPaste.gif' => 'c5d040c4f0a4075aaa56acfbc393ee44', + './themes/Sugar5/images/ProjectOutdent.gif' => 'b117efdc268d2779a0c2f2f4cfee7fc3', + './themes/Sugar5/images/ProjectMonth.gif' => '1ef256376cacea730a9b1dd3d58e7463', + './themes/Sugar5/images/ProjectMinus.gif' => '126cd19c26aa220d323230c8aa49c98a', + './themes/Sugar5/images/ProjectInsertRows.gif' => 'b89dcac2784c2a3376c305b9772c5bdd', + './themes/Sugar5/images/ProjectIndent.gif' => 'ab916206b4065192b84964622b7d6735', + './themes/Sugar5/images/ProjectExpandAll.gif' => '1910605074d6f26e568dc21aa96e2ce8', + './themes/Sugar5/images/ProjectDelete.gif' => '4ef20c4cba758dfb05e48684c3be5ffe', + './themes/Sugar5/images/ProjectCut.gif' => '710ffc5a60e29507c0ddda70ffb6d97e', + './themes/Sugar5/images/ProjectCopy.gif' => '8287a031948f6d670d90e827af6fce31', + './themes/Sugar5/images/ProjectCollapseAll.gif' => '97f5d2f6e6c9d2d967d751d4dfabfcc6', + './themes/Sugar5/images/Project2Weeks.gif' => '099efa2eb9e391a6d908eb583915d999', + './themes/Sugar5/images/Project.gif' => '0f2bbcc30e50b5eab1d048f2ab765e47', + './themes/Sugar5/images/Products.gif' => '9ec09d637b692326d91d4d440027fa4b', + './themes/Sugar5/images/Product_Types.gif' => 'ba210721c31f762ce799b1494a30c3b9', + './themes/Sugar5/images/Product_Categories.gif' => '27135ec896a6baa6ad57a2e34ec938da', + './themes/Sugar5/images/ProductTypes.gif' => 'ba210721c31f762ce799b1494a30c3b9', + './themes/Sugar5/images/ProductTemplates.gif' => '9ec09d637b692326d91d4d440027fa4b', + './themes/Sugar5/images/ProductCategories.gif' => '27135ec896a6baa6ad57a2e34ec938da', + './themes/Sugar5/images/Print_Email.gif' => '268880a56f51100e33f9a68bf25fb14c', + './themes/Sugar5/images/Price_List.gif' => '64db64739b3b4b1c9ce76150a751cd03', + './themes/Sugar5/images/PriceList.gif' => '64db64739b3b4b1c9ce76150a751cd03', + './themes/Sugar5/images/PatchUpgrades.gif' => 'e1bf9565545d0f9db2f91f04a3dfa758', + './themes/Sugar5/images/Password.gif' => '086dda11a59db50c8440183881f65c0c', + './themes/Sugar5/images/OpportunityReports.gif' => '7d7c840292ae89a66e97afa3e68df9a7', + './themes/Sugar5/images/Opportunities.gif' => 'ec7850c09b72c670df154aa110c79dd8', + './themes/Sugar5/images/OnlineDocumentation.gif' => 'bd0436d969ff34a660e7b232030d3009', + './themes/Sugar5/images/OfflineClient.gif' => '3dc473e333147502c3e3430de47169ec', + './themes/Sugar5/images/Notes.gif' => '292043a6551d4603e78593e82593ebc8', + './themes/Sugar5/images/Newsletters.gif' => '600e2e1f5cac2dbee54a9007205bcd86', + './themes/Sugar5/images/MyReports.gif' => 'dd67b2a4377927936785cdf65907ba2a', + './themes/Sugar5/images/MyProject.gif' => '89d4806940ca826bac6410b618dbf5d9', + './themes/Sugar5/images/MoreDetail.png' => '1a47ea4ae673fbe8968198bfda6160a6', + './themes/Sugar5/images/ModuleLoader.gif' => 'ac4f600f348a8c3bbf32c9082764b03e', + './themes/Sugar5/images/ModuleBuilder.gif' => '0fe61ab8532b0383257a0622b946662c', + './themes/Sugar5/images/MigrateFields.gif' => 'a79346f2c230cd4c1007a9862ed61924', + './themes/Sugar5/images/Meetings.gif' => '2c72354fdd58d87185411e82cc21bf8d', + './themes/Sugar5/images/MeetingReports.gif' => 'a58134ee43a3f2ab202ad79287d04ed4', + './themes/Sugar5/images/MatrixReportOver.gif' => 'ca3be4462316c7afea373bb8c1dd1675', + './themes/Sugar5/images/MatrixReport.gif' => '6c99c710b2e8dab38ad44c00d3077183', + './themes/Sugar5/images/Manufacturers.gif' => '766a34c1e1b72f73e3bf1f10967157cd', + './themes/Sugar5/images/MailboxesTestImport.gif' => '24805afea32fdc482f4e361f646688bd', + './themes/Sugar5/images/License.gif' => '608b6f103f2b754e79434b8b777ad05d', + './themes/Sugar5/images/Leads.gif' => 'b175423893fda627ea17f28a56cb6e59', + './themes/Sugar5/images/LeadReports.gif' => 'dee66cbcb4b69a663d336ff96fa67568', + './themes/Sugar5/images/Layout.gif' => '35df00aa3f68c87b0aecabc831845f1d', + './themes/Sugar5/images/LanguagePacks.gif' => '05135c460d24ae3e66fb05e9b482665a', + './themes/Sugar5/images/KBDocuments.gif' => '1d466eaeda296f54c42a7e473e4f6c0c', + './themes/Sugar5/images/KBArticle.gif' => '1d466eaeda296f54c42a7e473e4f6c0c', + './themes/Sugar5/images/KB.gif' => 'c2718316fee41c86feb233435b554c36', + './themes/Sugar5/images/InboundEmail.gif' => 'fed8e9392ab61a5a44b563ecfc5c0005', + './themes/Sugar5/images/ImportCustomFields.gif' => '289a0dbdce175f1965e967472b5c4484', + './themes/Sugar5/images/Import.gif' => 'ec8d49ed5fb711f57b417cfe1d0488d4', + './themes/Sugar5/images/Holidays.gif' => '92b9af82ee68587554ec248e968df011', + './themes/Sugar5/images/Forecasts.gif' => '91247a184474f0ee853e02e5eb1a11f5', + './themes/Sugar5/images/ForecastWorksheet.gif' => '26e8216f6a272f569b9fc358b7374c74', + './themes/Sugar5/images/ForecastReports.gif' => '955a99e3f4bc500f36fc111c33485eab', + './themes/Sugar5/images/FieldLabels.gif' => '163d3292d1080120c96e991c9d8c411a', + './themes/Sugar5/images/Feeds.gif' => '0d29ec2ee3476d83dcf7757ea3874ecd', + './themes/Sugar5/images/FavoriteReports.gif' => 'c16aa5c7a37ecfa94ab08f910b93e9a4', + './themes/Sugar5/images/ExportCustomFields.gif' => '6ddd4192adc8637ccf791e51c793f828', + './themes/Sugar5/images/Employees.gif' => '28e6705d0394e3f993a4366a59d1f7ce', + './themes/Sugar5/images/Emails.gif' => '2f78dfe83afc2d333fa74d0794630f23', + './themes/Sugar5/images/EmailTemplates.gif' => '2f78dfe83afc2d333fa74d0794630f23', + './themes/Sugar5/images/EmailSetupWizard.gif' => 'ba3c3a98ea383dc47a87af1f65218031', + './themes/Sugar5/images/EmailReports.gif' => '1e39a4896b8ce38a9d86bccee447e49f', + './themes/Sugar5/images/EmailMan.gif' => '1947b99573ba0d64f5eab2813ce9436b', + './themes/Sugar5/images/EmailFolder.gif' => 'c483bfcd31c873a997c360baf703773c', + './themes/Sugar5/images/EmailDiagnostic.gif' => '42ac00c64920143627f00c63b737f90f', + './themes/Sugar5/images/EditLayout.gif' => 'a63bb099ded39d833199d47c9fdb3ead', + './themes/Sugar5/images/Dropdown.gif' => 'da9558529b3727e61e30401e8175e1f7', + './themes/Sugar5/images/Documents.gif' => '0c114a3f4cb2d096c724d656c905f2ad', + './themes/Sugar5/images/DocumentRevisions.gif' => '3835202af7013415ffae7bdc8fcf4ae6', + './themes/Sugar5/images/Diagnostic.gif' => '39b302edd4e3839712d840ac1b3be940', + './themes/Sugar5/images/DataSets.gif' => '80b250c42133beaab652ee142ce4e872', + './themes/Sugar5/images/Dashboard.gif' => '236427476f3a491e8c7b0b184d85e431', + './themes/Sugar5/images/DCETemplates.gif' => 'b148b8dde915c6326f9bd8b5a9affd8f', + './themes/Sugar5/images/DCELicensingReport.gif' => 'b255bb8ae39976fd6c83c3037d090f36', + './themes/Sugar5/images/DCEInstances.gif' => '1776dee1d1555d49d520f69c0da3d997', + './themes/Sugar5/images/DCEDataBases.gif' => '856fa97c260658dab05fa00f1bc94de9', + './themes/Sugar5/images/DCEClusters.gif' => 'd7cf8d22d3fdc5e1a4fb0daca91e244d', + './themes/Sugar5/images/DCEActions.gif' => 'dde16f8608d3aeef715ed9ad7e57956e', + './themes/Sugar5/images/CustomQueries.gif' => '01e9e4094828c8fc64b2e89ba471b830', + './themes/Sugar5/images/Currencies.gif' => '8d1421616dcc7965a2995ea286cfb00d', + './themes/Sugar5/images/CreateiFrames.gif' => '2def896bb91201710ee131522715616f', + './themes/Sugar5/images/CreateWorkflowDefinition.gif' => '73b406c5f369834fa80a29f0899e5508', + './themes/Sugar5/images/CreateWebToLeadForm.gif' => '5c34510b1241c7cf34eb885ddb45117d', + './themes/Sugar5/images/CreateUsers.gif' => '4d734abaed2d76e620e61427f22cc38a', + './themes/Sugar5/images/CreateTimePeriods.gif' => 'ab2c8949e2dd22b5b61aebc49f44064c', + './themes/Sugar5/images/CreateTeams.gif' => '421c80edb890544d961afaaf0fb208e6', + './themes/Sugar5/images/CreateTasks.gif' => '4d6463cdf79b2c1cd010d601ef52fc07', + './themes/Sugar5/images/CreateScheduler.gif' => '2e5fade41c543b2ed1126c9194ed7a51', + './themes/Sugar5/images/CreateRoles.gif' => 'ab9c72a16e60764e035ffac6567df86b', + './themes/Sugar5/images/CreateReport.gif' => 'a01aa35efd2db58eb027e4dbd47f6d7b', + './themes/Sugar5/images/CreateQuotes.gif' => 'b38cea113277578a6129720ff6a068da', + './themes/Sugar5/images/CreateQuery.gif' => '94d3ce011099602f29ad6b83dfaa2bc4', + './themes/Sugar5/images/CreateProspects.gif' => '430421f03ca03f95b3ca5deb00966403', + './themes/Sugar5/images/CreateProspectLists.gif' => 'b47839294deb452586135734cc13cdb2', + './themes/Sugar5/images/CreateProjectTemplate.gif' => '684bd67db7cca4190dc4b49c0a8e83bb', + './themes/Sugar5/images/CreateProjectTask.gif' => '67ac607e90a8860af5fa31d18d9f53e0', + './themes/Sugar5/images/CreateProject.gif' => '74dd612dc97d6d2c65b172057040b59c', + './themes/Sugar5/images/CreateProducts.gif' => 'c99bdb9ae5677cc441584205e998955c', + './themes/Sugar5/images/CreateOpportunities.gif' => 'a9589cfff43f2a16963772a928b93fce', + './themes/Sugar5/images/CreateNotes.gif' => '1c001421c72c428f4a5acbc944e43301', + './themes/Sugar5/images/CreateMeetings.gif' => '8782a51731204d530a218de9dcf72d0c', + './themes/Sugar5/images/CreateMailboxes.gif' => '514b96d819aed1a9a618382cc18f74ef', + './themes/Sugar5/images/CreateLeads.gif' => '7a295c6e01b5ed10293dbc942fdc5013', + './themes/Sugar5/images/CreateKBArticle.gif' => '5528bfd3ccd117da8ee76453b8fffec8', + './themes/Sugar5/images/CreateHolidays.gif' => '74bb94942b330a7353ebfddb3e395710', + './themes/Sugar5/images/CreateEmployees.gif' => '4db0f4883525baa72d760602b0d0a9d6', + './themes/Sugar5/images/CreateEmails.gif' => 'c73f6fa2d64183c99f6b43fd3e8457cb', + './themes/Sugar5/images/CreateDropdown.gif' => '62f0e60bfb25e8210266f0c46a724b7b', + './themes/Sugar5/images/CreateDocuments.gif' => 'b6803a3158f8aafb797dcf40e40c7f5a', + './themes/Sugar5/images/CreateDataSet.gif' => '1c01e157d2c0f04448aeee5288cd0903', + './themes/Sugar5/images/CreateDCETemplates.gif' => '235a27f63ec69172665a9725de0138ab', + './themes/Sugar5/images/CreateDCEInstances.gif' => '37d2083c5656806c41f379de561de12e', + './themes/Sugar5/images/CreateDCEDataBases.gif' => '030b11434890898ea46f7eb47e26ca74', + './themes/Sugar5/images/CreateDCEClusters.gif' => '7412cac6f131844a2be1b2259bb7bdb2', + './themes/Sugar5/images/CreateCustomQuery.gif' => '7f8b8b8b1649f379e9fa0993833594f4', + './themes/Sugar5/images/CreateContracts.gif' => '432241ea2fbc4b3dfe50ee180b440132', + './themes/Sugar5/images/CreateContacts.gif' => '543275e52941e451c0594dbc10c19ac5', + './themes/Sugar5/images/CreateCases.gif' => 'd3e6eb8dd24fbd768cc2a203e035dfe4', + './themes/Sugar5/images/CreateCampaigns.gif' => '698c76de164b71478d1fae396248f976', + './themes/Sugar5/images/CreateCalls.gif' => 'faf97408d67ad4ab815d81dbfe5dc2c9', + './themes/Sugar5/images/CreateBugs.gif' => 'f5d7a5030b9d2f7efb6d1a5a4cc82cef', + './themes/Sugar5/images/CreateAccounts.gif' => 'ea824000c6d1db94e57df7cc78cb9b3c', + './themes/Sugar5/images/Contracts.gif' => '92d58d7fb871e059005a90b49466645f', + './themes/Sugar5/images/ContractReports.gif' => '3714580af7d9867f1cea0930bf615c16', + './themes/Sugar5/images/Contacts.gif' => '18553d7e06e2b115dcd8ae18a00c692e', + './themes/Sugar5/images/ContactReports.gif' => 'f32df37fe41d3901406fb1b96b73d0d9', + './themes/Sugar5/images/ConfigureTabs.gif' => '58ddcd48ddbbf664fc2a22320ff4cd81', + './themes/Sugar5/images/ConfigureSubPanels.gif' => 'd11894b643f3c8350e58a2a279539a08', + './themes/Sugar5/images/Cases.gif' => '9ff67484d4e580f7ec6b1c4fadef4e6c', + './themes/Sugar5/images/CaseReports.gif' => '8566460850d40f43817bca5f19441509', + './themes/Sugar5/images/CampaignsWizard.gif' => 'c3d4e57e0dbbf6eb079c79b2bfdb7d70', + './themes/Sugar5/images/Campaigns.gif' => 'caf6345d36c8b318148e08eb017fc592', + './themes/Sugar5/images/Calls.gif' => 'fb79ca6ff562b6321c30039d577a55cc', + './themes/Sugar5/images/CallReports.gif' => '9ce20f70f663bcc30232c585533a67fd', + './themes/Sugar5/images/Calendar.gif' => 'ac7a361a60069ea66eded3e8fc22d253', + './themes/Sugar5/images/Bugs.gif' => 'b147d01e9f226777cf497b92439efdf0', + './themes/Sugar5/images/BugReports.gif' => '9edff2df8863ace2cf1e7986e5423523', + './themes/Sugar5/images/Backups.gif' => '1e5b888a85fe97b85e32a23544a53d40', + './themes/Sugar5/images/Backup.gif' => '4cf4850d478c593d3ab33fb60fdf2b6c', + './themes/Sugar5/images/ArrowButtons.png' => '3cc685bfa21913c19ebacce89568b882', + './themes/Sugar5/images/AllRSS.gif' => 'c6438ac72aed8be0bb89ad7981d23e92', + './themes/Sugar5/images/AllNews.gif' => 'c6438ac72aed8be0bb89ad7981d23e92', + './themes/Sugar5/images/AlertEmailTemplates.gif' => '92010f89490e4fdae70a4ecee1bfbd5d', + './themes/Sugar5/images/Administration.gif' => 'a68a5b890796251b8947061f696ca15e', + './themes/Sugar5/images/ActivitiesReports.gif' => 'ad890a0190fedffa6bcb73557060fa9b', + './themes/Sugar5/images/Accounts.gif' => 'e081de07d0263b270d0d306642375901', + './themes/Sugar5/images/AccountReports.gif' => 'c98b4b2eb32be534f8fc1b2ac29fa1a2', + './themes/Sugar5/images/ACLRoles.gif' => 'dcbf376b885458b1fc8c21de7884284e', + './themes/Sugar5/css/yui.css' => 'ab561cd401d774311653f92ff8336fbe', + './themes/Sugar5/css/wizard.css' => '9f23702bef6e6bce98959a25f3e0f71e', + './themes/Sugar5/css/style.css' => '9cda0e41dc2769e0a2825736bed40d1b', + './themes/Sugar5/css/print.css' => '629df961f98baab29b4530b56322a1ca', + './themes/Sugar5/css/deprecated.css' => '13f41876c3a31bde4ac2e1223bdd707c', + './themes/Sugar5/css/chart.css' => 'dda00a834e88692f3d08bec70db12dc9', + './sugar_version.php' => 'ed78e48cba51ae74974d05f0379824b1', + './soap/SoapTypes.php' => 'b44fab9d2a11ee705798529a17ccd24e', + './soap/SoapSugarUsers.php' => '64195c9cdca985b78adaba2860f07f41', + './soap/SoapStudio.php' => '08ff60f88df7da98b081a199510858f8', + './soap/SoapRelationshipHelper.php' => 'b2411195c28a0d05418ec95d7fc85c3d', + './soap/SoapPortalUsers.php' => '3e76580fb0d3f0754ec120ff93c2db85', + './soap/SoapPortalHelper.php' => '9151ef0312f56b2525b86082f5c102ca', + './soap/SoapHelperFunctions.php' => '9bb410a2431677d69c68165723ad79f7', + './soap/SoapErrorDefinitions.php' => 'f39459659519912f55b559e49acdd20b', + './soap/SoapError.php' => 'd6440fe460e7a9f163e5f98ff6dd1157', + './soap/SoapDeprecated.php' => '4f7f3984799fea00f3075dba57b41a64', + './soap/SoapData.php' => '1daea86416c5b9706c6ec200704b6c8b', + './soap.php' => '453ea7dc02b44113fab1f37dd203548a', + './service/v4/soap.php' => '270ed42705d7933e84e0032c4b8fd8ec', + './service/v4/rest.php' => 'f429b2a67d4f5a9302d9169d911da967', + './service/v4/registry.php' => '5eed51c9ea2ec836de9ccabfca13c11d', + './service/v4/SugarWebServiceUtilv4.php' => '3ac21d9fc5585eeba6946fce19df0f01', + './service/v4/SugarWebServiceImplv4.php' => 'c7e8d34adebb4d3c72ff2ef9133bcc18', + './service/v3_1/soap.php' => '1ba337904cc10a3ad9f1609fe14f6ae5', + './service/v3_1/rest.php' => '6ddcf6a263f3e87870155fe66e5cad42', + './service/v3_1/registry.php' => 'cf3ca508bdeef0dbcc53759fa0e4bcd2', + './service/v3_1/SugarWebServiceUtilv3_1.php' => 'da3bb6ef58bae317f5b18e0e07995be0', + './service/v3_1/SugarWebServiceImplv3_1.php' => 'fe73eec4f57dcaafb5e087281caf294e', + './service/v3/soap.php' => '38149ba3c4bc6f68ed38e10d0a341799', + './service/v3/rest.php' => '00cc4ae016b5fbc9506470e2bd84b92b', + './service/v3/registry.php' => '775fd364c36a0e8ef151219ca0f03a8a', + './service/v3/SugarWebServiceUtilv3.php' => '59cec45e51367ab7974e35daf8106825', + './service/v3/SugarWebServiceImplv3.php' => '184093d1ea9d03dd4736a3f0885250c5', + './service/v2_1/soap.php' => '51d80264bab2b10b0cf07b1fa232f5a2', + './service/v2_1/rest.php' => '97716eb170c494d20f4424b851b7ed82', + './service/v2_1/registry.php' => '44dced209606f86f712792d06a7488f3', + './service/v2_1/SugarWebServiceImplv2_1.php' => '35606eaf05d94941c38afc0fd03aa6fd', + './service/v2/soap.php' => '32f23f109f4ff981abf8e9ccc2df3236', + './service/v2/rest.php' => '4e84dc75c44747059d916d213ef15188', + './service/v2/registry.php' => '2a29c657ebbd837c8f49a51ef3780a29', + './service/v2/SugarSoapService2.php' => '9f5cf5ab0a057eee1d009783976d3b2c', + './service/utils/SugarRest.js' => 'f0a5086d019a7cc4a3bca2d8a5f923cf', + './service/example/test.html' => '70a3f7981c7aa315f1093ec38bbc5d91', + './service/example/example.html' => '48b7addac379bd10867aaaeaca7afc60', + './service/example/Rest_Proxy.php' => 'f2067bb8f194b84c29a93cd1b8a5a3c0', + './service/core/webservice.php' => '2b71c40f8b66256b6d350769de002aff', + './service/core/WSDL.tpl' => 'd41d8cd98f00b204e9800998ecf8427e', + './service/core/SugarWebServiceImpl.php' => 'f6375420ad0088e5aa7426d6b60fe2e4', + './service/core/SugarWebService.php' => '53760c0e2e503c35d78f170a275ea59d', + './service/core/SugarSoapService.php' => 'a535e5a1fb0587666b8dcc5ac6046566', + './service/core/SugarRestUtils.php' => '9ac2b9f16e789b2c8e9e3d8e981526aa', + './service/core/SugarRestServiceImpl.php' => 'dcffa0dc980f16730ce498b68c834ccf', + './service/core/SugarRestService.php' => '0a0009b9f881f222eae15bf9086715bc', + './service/core/SoapHelperWebService.php' => 'c3cc8bcbd5e33dbb30acefb1f1c5c150', + './service/core/REST/SugarRestSerialize.php' => '5ec4341d9e56974f1467ff102a4eb5dc', + './service/core/REST/SugarRestRSS.php' => 'dad22f4846e062e40edc6a443009356b', + './service/core/REST/SugarRestJSON.php' => '566fe67c55e0fd3bfb6cf3bd36bf7dfa', + './service/core/REST/SugarRest.php' => 'bfd1b11c826ab05b802535d5b0eb5a9d', + './service/core/PHP5Soap.php' => '4bb99bfb2c2571301c4e7dd038b9e9ce', + './service/core/NusoapSoap.php' => 'af9622b9373bae1b8bc9be13e2c8aead', + './robots.txt' => 'f71d20196d4caf35b6a670db8c70b03d', + './removeme.php' => 'c909fd8a94c02aad0439aa88999580a5', + './pdf.php' => '2175c3d745bb23b7812cb7fea96dfefa', + './modules/EAPM/EAPMEdit.js' => '0da3de9fe26e14c515a820c11664a33a', + './modules/EAPM/views/view.edit.php' => 'f10e48f116d60d793098d27d9f440b14', + './modules/EAPM/views/view.detail.php' => 'ccd14d5ab309c68fbe4a527c967d5c34', + './modules/EAPM/vardefs.php' => '6f8af0161ebb3e033b6f1fbabb82dd74', + './modules/EAPM/tpls/EditViewHeader.tpl' => '9968d21c791e8b2fe89e6ba2265d7b3f', + './modules/EAPM/tpls/EditViewFooter.tpl' => '7e6d67537bacf08df11acf888d5d5b51', + './modules/EAPM/tpls/DetailViewFooter.tpl' => 'b94cc2039971178f1a62e04b7b017cee', + './modules/EAPM/metadata/subpanels/default.php' => 'c205ff13e601a72dde2a5a23d7950bba', + './modules/EAPM/metadata/searchdefs.php' => '4b1f356c95d5ae8405df454c2dc907e1', + './modules/EAPM/metadata/quickcreatedefs.php' => '3b835395a73e38d7f7bfe646f69f259e', + './modules/EAPM/metadata/popupdefs.php' => '40087dc17f8a28447bc181613579502e', + './modules/EAPM/metadata/metafiles.php' => '82cc6b332b2fbfb9c4e95765da6e9dcb', + './modules/EAPM/metadata/listviewdefs.php' => '2bed1cabe6a73878bbfa6007d98ed5b1', + './modules/EAPM/metadata/editviewdefs.php' => 'b6974cf3e104cf605382914081f86af0', + './modules/EAPM/metadata/detailviewdefs.php' => '0c4a3279d990c047c4521db8bcf92129', + './modules/EAPM/metadata/SearchFields.php' => 'e8effa2440f6759dd94173e6170592c8', + './modules/EAPM/language/en_us.lang.php' => 'ac9f45ca95a8a4cf709bfa176685b946', + './modules/EAPM/controller.php' => '261e9cca8e30eb6bbc7cc8c38ebd1bb7', + './modules/EAPM/action_view_map.php' => '7f9d495a7362c0e56dafa364b6a3046e', + './modules/EAPM/EAPM.php' => '02e9f519f5e2cda7139b581fb590d3fc', + './modules/EAPM/CheckLogins.php' => '2a700d0b0feed2831cfe1b1db55404c2', + './modules/vCals/vardefs.php' => '1b1f5d3652b0c84f2af8c444b2b100e7', + './modules/vCals/vCal.php' => 'a8f75d33c72ff614137c08e9cc328356', + './modules/vCals/field_arrays.php' => '23cdf390f157fce35ac36130bff01a43', + './modules/vCals/Server.php' => '4bdac2390625a292adc9a7a3dbc92926', + './modules/vCals/HTTP_WebDAV_Server_vCal.php' => 'b28576b27b86f98cfb18399a10e1d6f7', + './modules/Versions/vardefs.php' => '595403530f1a5f62372ed986c25bd17a', + './modules/Versions/language/en_us.lang.php' => 'd41d8cd98f00b204e9800998ecf8427e', + './modules/Versions/index.html' => 'b1c40cce7e82e5cf396ccad74fe7360c', + './modules/Versions/field_arrays.php' => 'ec6c8cf6e9b775040ea95b0c0bd870b5', + './modules/Versions/Version.php' => 'd1d8f342abe3c3564d85ed24355f9054', + './modules/Versions/InstallDefaultVersions.php' => '6e58099c0876f79214f8238363d8bc39', + './modules/Versions/ExpectedVersions.php' => 'abd307792c9969f56157dbb95e24f267', + './modules/Versions/DefaultVersions.php' => '685176ff71a709facf369caf0259b55e', + './modules/Versions/CheckVersions.php' => 'ec34d2c876c83ff9b20eced20e062487', + './modules/Users/DetailView.js' => '226e76165861456ca3c07a4984f0e98b', + './modules/Users/PasswordRequirementBox.js' => '812d65c03c22c3356cdb889b71dc31da', + './modules/Users/User.js' => '89d0867052db8e00bd24858bffe301f5', + './modules/Users/login.js' => 'd167b63b648c06addd4abf49597c574f', + './modules/Users/views/view.wizard.php' => 'c3ae26a542bbd90586d75f39f5b83662', + './modules/Users/views/view.list.php' => 'fa77f89687ca1092ea0c605dd76303ae', + './modules/Users/vardefs.php' => 'aa468faf100ff528010f39d409c907e3', + './modules/Users/tpls/wizard.tpl' => '257b63ccccb59fac05e73150bc39ca4d', + './modules/Users/reassignUserRecords.php' => '9cc3174c7ffa193fefd6fd9051830fc8', + './modules/Users/password_utils.php' => 'c41679fe7f11523eac0cdd97248306bd', + './modules/Users/metadata/subpanels/default.php' => 'c110665c9c3577b12ca45ec95f7e5b79', + './modules/Users/metadata/subpanels/ForTeams.php' => '5677b1abc77a48c83426dfb0f374d809', + './modules/Users/metadata/subpanels/ForProspectLists.php' => '09b60438c79d6adfdf6cfc9bcbe14230', + './modules/Users/metadata/subpanels/ForProject.php' => 'dbe7cb1aaae960b1b7f9312b98dc8528', + './modules/Users/metadata/subpanels/ForMeetings.php' => '7583a569629ab26f01da7397daa0c21b', + './modules/Users/metadata/subpanels/ForEmails.php' => '3fc8e0af16ed19897ee2f3703229cc6d', + './modules/Users/metadata/subpanels/ForCalls.php' => 'aa17597d596adeeb00b750fc938f72e2', + './modules/Users/metadata/subpaneldefs.php' => '646cb58c8a90c3e914cb318839c97843', + './modules/Users/metadata/searchdefs.php' => '4ef2283a1a35bffe915388166b639de7', + './modules/Users/metadata/reassignScriptMetadata.php' => 'e449cc5da384ffcd3c778c98bed7e87d', + './modules/Users/metadata/popupdefs.php' => '84f62e9e59fd28ae84ecc976f5d5008b', + './modules/Users/metadata/listviewdefs.php' => '5117909dab36844a94643acc44f7a9bb', + './modules/Users/metadata/SearchFields.php' => '6b7ab730dfab23213f6287a2e2036652', + './modules/Users/login.tpl' => '50490eb850a02b01087afccbf85bc814', + './modules/Users/login.css' => '3fc617df6406081f31b2f3306e59c6ed', + './modules/Users/language/en_us.lang.php' => 'a8e84c73463785759093bd66e7c32c79', + './modules/Users/field_arrays.php' => '46dac3bcf42a3641b80eb507f6cc203a', + './modules/Users/controller.php' => 'c5a25f7c913e1d434b628c6bbe7fee7f', + './modules/Users/authentication/SugarAuthenticate/SugarAuthenticateUser.php' => '412dc66d6fedfacdcf69fd23371efe05', + './modules/Users/authentication/SugarAuthenticate/SugarAuthenticate.php' => 'a35a41d26a301fa1f3595dbda55494c4', + './modules/Users/authentication/SAMLAuthenticate/settings.php' => '871bd3ac7732d6172a0320d52b938420', + './modules/Users/authentication/SAMLAuthenticate/lib/xmlseclibs/xmlseclibs.php' => '05070f789165351c2946c679611fe44a', + './modules/Users/authentication/SAMLAuthenticate/lib/xmlseclibs/CHANGELOG.txt' => '113d14ef4333039359236ffed624fb85', + './modules/Users/authentication/SAMLAuthenticate/lib/onelogin/saml/xmlsec.php' => '8cb35c75b9c09e3272ad3c627ed1546d', + './modules/Users/authentication/SAMLAuthenticate/lib/onelogin/saml/settings.php' => '5d1043271a8c7c9460298216a8fa6ef9', + './modules/Users/authentication/SAMLAuthenticate/lib/onelogin/saml/response.php' => 'a53b94607ab662938184a76fce86696d', + './modules/Users/authentication/SAMLAuthenticate/lib/onelogin/saml/authrequest.php' => 'faea297ec834b918f4452a28803c74ac', + './modules/Users/authentication/SAMLAuthenticate/lib/onelogin/saml.php' => '9daa3f46b708efe880c43367cb24dff1', + './modules/Users/authentication/SAMLAuthenticate/index.php' => '0b7cae26cc46589daa26b226054c1b8b', + './modules/Users/authentication/SAMLAuthenticate/SAMLAuthenticateUser.php' => '38cdc9a901ab7d6236da3671f4cf1653', + './modules/Users/authentication/SAMLAuthenticate/SAMLAuthenticate.php' => '5734ed62cd74477dcaf1b81957b8e383', + './modules/Users/authentication/LDAPAuthenticate/LDAPConfigs/default.php' => '324614bec129312bfa042b23e83afba0', + './modules/Users/authentication/LDAPAuthenticate/LDAPAuthenticateUser.php' => '26031af713b483f5b4dc1dfdb6128297', + './modules/Users/authentication/LDAPAuthenticate/LDAPAuthenticate.php' => '5d7c80203aba7b2249f84a3c5407536d', + './modules/Users/authentication/EmailAuthenticate/EmailAuthenticateUser.php' => '062f2c32422c8e6e11e11b3020d1a525', + './modules/Users/authentication/EmailAuthenticate/EmailAuthenticate.php' => 'bedbc545d6c1c13a65a44e00546fa2ac', + './modules/Users/authentication/AuthenticationController.php' => '924d58e79a9910a44334f0fc5e3a8905', + './modules/Users/UserSignatureEditView.html' => 'bbd67cc5332b92df27ca7c014fb6d544', + './modules/Users/UserSignature.php' => '5456216c3e5b1f8db76456303b4dc71f', + './modules/Users/User.php' => '0cb0ec4d4d582ea5c3e6c55b1f213bb8', + './modules/Users/SetTimezone.tpl' => 'cf34dc1b1078752a75434a0384eb2b57', + './modules/Users/SetTimezone.php' => '1e823c77a370ac9711c65c945e426257', + './modules/Users/SaveTimezone.php' => 'fca4ed5d777fbcfab3d55de554de3bef', + './modules/Users/SaveSignature.php' => '1de31710e9c753516fb513eca488e1c6', + './modules/Users/Save.php' => 'e00f12055fe2081dcf1a2abfec2ae377', + './modules/Users/Popup_picker.html' => '5b27b65f225c39e6dab14b381463f324', + './modules/Users/Popup_Users_picker.html' => 'e94231d815056c82437b0e97cc5c1c33', + './modules/Users/PopupUsers.php' => '907d639d7dae8d7fcecd8b7f6465d630', + './modules/Users/PopupSignature.php' => '126dd53e1ebb61733039070efac3c6f1', + './modules/Users/PasswordRequirementBox.css' => 'bb346afe22bafdd935b85fd8fc4b2c06', + './modules/Users/Menu.php' => 'b45197498fc8bd915f18379dbaa06000', + './modules/Users/Logout.php' => '261edee3721dd9ad1e381d3d7d421dac', + './modules/Users/Login.php' => 'af0c080dff82f24dc1c47316d2c45319', + './modules/Users/ListRoles.php' => 'f0724318d9f4d19b0e9d2fe0bdcfe898', + './modules/Users/GeneratePassword.php' => '020ec67f84a5a489af637d9de6e6f43e', + './modules/Users/Forms.php' => '61bb049bc61cde1712a8631bb812accf', + './modules/Users/Error.php' => '4e9cd9d420e137c4ba95633c341b0e24', + './modules/Users/EditView.tpl' => '66c720509c562e4e456d93140a03591d', + './modules/Users/EditView.php' => '08d05d650c11cf3c529f8467f8f88107', + './modules/Users/DetailView.tpl' => 'b0654809a7fea5588ccdae6570353c09', + './modules/Users/DetailView.php' => 'c80852e6712dcbcae0b4e30603ed825f', + './modules/Users/Changenewpassword.tpl' => '7e3894ab32dd3b85ce898aa156e493d4', + './modules/Users/Changenewpassword.php' => '6970f9264bab535e96f4d0b278be4d30', + './modules/Users/ChangePassword.php' => '949feb7d487fb4cae17e1a7417bda3ee', + './modules/Users/ChangeGroupTab.php' => 'fab6b8eaa7260b44d7bfa9c23b014ba7', + './modules/Users/Authenticate.php' => 'd5f53bfed576f3b39f85175e9651e232', + './modules/UserPreferences/vardefs.php' => '3bd284e0ea6a03f1ace7d7707aea83ab', + './modules/UserPreferences/index.php' => 'a56f06c827d512f011a01ceea8802c51', + './modules/UserPreferences/field_arrays.php' => 'd5873bcc7da2c957a90d2a1ad27904d6', + './modules/UserPreferences/controller.php' => 'cc33cbd9645b36a8a9471ed53edab320', + './modules/UserPreferences/UserPreference.php' => '2569c09e4bbe171ff8fd4e07d7d819cb', + './modules/UpgradeWizard/upgradeWizard.js' => '1fed20dbb04bb39a5e3811388dfbd22b', + './modules/UpgradeWizard/uw_utils.php' => '5f914473ef68c93a2abfdd1639d07599', + './modules/UpgradeWizard/uw_main.tpl' => '4543b15b248aca9ada4bb50d7626e5a1', + './modules/UpgradeWizard/uw_files.php' => 'a3591043d2840d87f35e4f3c7750463f', + './modules/UpgradeWizard/uw_emptyFunctions.php' => 'b87a790ffd80c140831a32f03ec06718', + './modules/UpgradeWizard/uw_ajax.php' => '3f1085d921fbaa13c9ceaff45f5c2442', + './modules/UpgradeWizard/upload.php' => '064e98fd37ed3cc802c0bf2d3b803656', + './modules/UpgradeWizard/upgradeTimeCounter.php' => '62edce24d54fc137e1cac51c06993182', + './modules/UpgradeWizard/upgradeMetaHelper.php' => '3b5c67ef5e7513e227c8b32202c84a10', + './modules/UpgradeWizard/tpls/layoutsMerge.tpl' => 'd498c9b5553f028eb2c9bdb093b13f10', + './modules/UpgradeWizard/systemCheckJson.php' => '7a87c2a6eaf73e94a4f2049481cb1420', + './modules/UpgradeWizard/systemCheck.php' => '86d1269ccccdf0cfff9d85e26a5d52ba', + './modules/UpgradeWizard/start.php' => '90631b73109f239d2d461147eae4c25a', + './modules/UpgradeWizard/silentUpgrade_step2.php' => '2e33dfaffa9393e389c60387cfd2753a', + './modules/UpgradeWizard/silentUpgrade_step1.php' => '93813d78ba8cde1a6b0200c26f4a85c2', + './modules/UpgradeWizard/silentUpgrade_dce_step2.php' => 'c36e25dc68e8f6371c14066225432b34', + './modules/UpgradeWizard/silentUpgrade_dce_step1.php' => 'ffc7b7d576e46fa15089df969a234fe3', + './modules/UpgradeWizard/silentUpgrade.php' => '24fac0ff5b213d81224ea49ce4fb1960', + './modules/UpgradeWizard/processing.gif' => 'd7c43fc19181ee59862601bfce100b41', + './modules/UpgradeWizard/preflightJson.php' => '3ab7297c97ebe86905d59bcbead9b5dc', + './modules/UpgradeWizard/preflight.php' => '8df05a9d81df4260e079b23ff269fe05', + './modules/UpgradeWizard/populateColumns.php' => 'f5ac3a6e957abbb79d5ec6770693468d', + './modules/UpgradeWizard/layouts.php' => '016ec71c667a0d130072cf88e6640a39', + './modules/UpgradeWizard/language/en_us.lang.php' => '693b929e6cba2a836c33884082132aff', + './modules/UpgradeWizard/index.php' => '303cb4b78b209399eca7c9cc4a7b97a4', + './modules/UpgradeWizard/end.php' => '0fcf81fabc33028a8360a3df6f36b696', + './modules/UpgradeWizard/deleteCache.php' => 'c1d87d7d28bcb80fd6d0525e9dc00813', + './modules/UpgradeWizard/commitJson.php' => '4f787ab77508307f013b9541470413df', + './modules/UpgradeWizard/commit.php' => '5dffdfea11b038cba94a321a5c9fa6f9', + './modules/UpgradeWizard/cancel.php' => '1a1861b844497c4b565def19369bdee4', + './modules/UpgradeWizard/UploadFileCheck.php' => '78f615eba31bb0f012280c769e895977', + './modules/UpgradeWizard/SugarMerge/SugarMerge.php' => '0d34bb5ba44497d886a8b201762a4ba5', + './modules/UpgradeWizard/SugarMerge/SubpanelMerge.php' => 'ed1e45aeef4c9c67b1a3b2b6d314c5bc', + './modules/UpgradeWizard/SugarMerge/SearchMerge.php' => '8df136e1f77b58c54f0f49a59aedf8ac', + './modules/UpgradeWizard/SugarMerge/QuickCreateMerge.php' => '6e6cc59dcd415d950be5dd845530f62d', + './modules/UpgradeWizard/SugarMerge/ListViewMerge.php' => '5d0a70b44b1c7373178f34359584f681', + './modules/UpgradeWizard/SugarMerge/EditViewMerge.php' => '5871d2fe09f2f99369791510a22f8357', + './modules/UpgradeWizard/SugarMerge/DetailViewMerge.php' => '94856b898734b9aebdb2bdc4138d2887', + './modules/UpgradeWizard/SILENTUPGRADE.txt' => '1b6463c295028ef776dc81f0582a409e', + './modules/UpgradeWizard/Menu.php' => '46177baa2468358d3dbeb04fb55fadaa', + './modules/Trackers/vardefs.php' => 'e4d7369777783f8a07bfbdd44999b7d6', + './modules/Trackers/store/TrackerSessionsDatabaseStore.php' => 'feedd59a686f8a290a3cf738734e972f', + './modules/Trackers/store/TrackerQueriesDatabaseStore.php' => 'ee6a4b845b855827c2133aa9cdd15aba', + './modules/Trackers/store/SugarLogStore.php' => '0abecdbd8a7b97278c524ada4edbe9cd', + './modules/Trackers/store/Store.php' => 'fcdf5d2451d3d88673654e60da6acf6a', + './modules/Trackers/store/DatabaseStore.php' => '46e236bcdd32bb051dc06ea5e7f24ce6', + './modules/Trackers/monitor/tracker_monitor.php' => '16b610c8a86797487dea2a0fa0136e89', + './modules/Trackers/monitor/Monitor.php' => '64495f4d07f067d1b0d39b74f719ed86', + './modules/Trackers/monitor/BlankMonitor.php' => '6767a630898ae9aa008e91cc5150c050', + './modules/Trackers/language/en_us.lang.php' => '1345b3505bb24d495e8e19fbba0ec9bb', + './modules/Trackers/config.php' => '4051c5a73d564237b51e1471fa8c3328', + './modules/Trackers/populateSeedData.php' => '444a12a759370439bfe3f04649488df0', + './modules/Trackers/TrackerManager.php' => 'b93c3c6b7915670318d6d020f844cd67', + './modules/Trackers/Tracker.php' => '680ae5a394f66296a161da0a335cb5eb', + './modules/Trackers/Trackable.php' => 'daea56a5d5fc440036947096f87303b7', + './modules/Trackers/Metric.php' => 'd3dafcf4c7c3da916ccaec7dd1a13ebd', + './modules/Trackers/BreadCrumbStack.php' => '131c50a6ab6e2b7324ec6537930db530', + './modules/Tasks/views/view.edit.php' => '1f87e6702874c411bc695c624ce57a38', + './modules/Tasks/vardefs.php' => '59766579bc73b1dc3091c22adaf89ac4', + './modules/Tasks/tpls/QuickCreate.tpl' => 'a3e76184c8fd107945281b284ebc11fa', + './modules/Tasks/metadata/subpanels/default.php' => '186d3ead2f8c74c638dfe9e5eceabcf7', + './modules/Tasks/metadata/subpanels/ForHistory.php' => '0d5d2b41bb9c1187b5de4c657d330a0c', + './modules/Tasks/metadata/subpanels/ForEmails.php' => '2ae86d7e7ec36d6034edff288766c38c', + './modules/Tasks/metadata/subpanels/ForActivities.php' => '1e6fca2d6773ecb7159c2b9a21bc3b69', + './modules/Tasks/metadata/studio.php' => 'a18e70360a5895dd7c0da4d7f930f33c', + './modules/Tasks/metadata/searchdefs.php' => 'bd3bf1c65daae0206b922a30296f8b57', + './modules/Tasks/metadata/quickcreatedefs.php' => 'fdb993a49bfc078b714d53bd364fcc7f', + './modules/Tasks/metadata/listviewdefs.php' => '35d2cc3b2face83ff13b96e9fa59dce8', + './modules/Tasks/metadata/editviewdefs.php' => 'e7cc85c6c63a8031217705096a0778f4', + './modules/Tasks/metadata/detailviewdefs.php' => 'd45f14a81beaf71702bd230415731de6', + './modules/Tasks/metadata/additionalDetails.php' => '62115b6e9f474ae4d723b25c9d5357fe', + './modules/Tasks/metadata/SearchFields.php' => '0b9e415252241158841c633377f6212a', + './modules/Tasks/language/en_us.lang.php' => '05ad7e321a629e5edd0ea40200518184', + './modules/Tasks/field_arrays.php' => '578586a9d27ef3519ec9bcad0f6b2073', + './modules/Tasks/TasksQuickCreate.php' => '319575147ca931572d8ffe5f86d66479', + './modules/Tasks/Task.php' => 'e47e5c86532c53599f37a6d1de5b731f', + './modules/Tasks/Save.php' => '5901a0e97e3604b1303b95de3248f14b', + './modules/Tasks/MyTasks.php' => '0812e375cea310e135154a07c2233bf4', + './modules/Tasks/MyTasks.html' => 'eef2d088906a4a3ca2ed5c3fb7b8c3b9', + './modules/Tasks/Menu.php' => '06049096d180e77230b22298fe3e008e', + './modules/Tasks/Dashlets/MyTasksDashlet/MyTasksDashlet.php' => 'bb5394ab47efe1853c123ffeead7f1ea', + './modules/Tasks/Dashlets/MyTasksDashlet/MyTasksDashlet.meta.php' => 'e27204f03b222e677251993b263af683', + './modules/Tasks/Dashlets/MyTasksDashlet/MyTasksDashlet.data.php' => '0c5a8cb52b95ff6efd03a71d0160338a', + './modules/TableDictionary.php' => '25ef82d92853bf5d3ed424107a7bb758', + './modules/SugarFeed/views/view.adminsettings.php' => 'a3597caf672ff770a9ba86e62423843b', + './modules/SugarFeed/action_view_map.php' => '3b0679f45ce6cea84ea77d5783a3a024', + './modules/SugarFeed/vardefs.php' => '1c499286c8af124d3a3e10da2284b716', + './modules/SugarFeed/metadata/subpanels/default.php' => '40bda533c59a5a627e1e18111223a33e', + './modules/SugarFeed/metadata/searchdefs.php' => 'f31d790edd5f094f873836952beb35cd', + './modules/SugarFeed/metadata/popupdefs.php' => 'b3c5fdc3a8bf9950dfff1bac559891c9', + './modules/SugarFeed/metadata/metafiles.php' => '37bc261e99c89a111a676c0918f2c036', + './modules/SugarFeed/metadata/listviewdefs.php' => 'e6ba6eb7eaf8d82f15793e269f315dac', + './modules/SugarFeed/metadata/editviewdefs.php' => 'c7fe443df3a4bda848c4669cd85bc960', + './modules/SugarFeed/metadata/detailviewdefs.php' => '255168df0d2024f156affb1fd0b60e65', + './modules/SugarFeed/metadata/dashletviewdefs.php' => 'dec6bef0e6afa31a0178eb260376ee8a', + './modules/SugarFeed/metadata/SearchFields.php' => 'aa8d48635deda3ec77ff1522213f88d3', + './modules/SugarFeed/linkHandlers/YouTube.php' => '5333d1f93f453a09ca91cb3d8d4dbe03', + './modules/SugarFeed/linkHandlers/Link.php' => '030b059d4d21b3e69388afe01a99a4ba', + './modules/SugarFeed/linkHandlers/Image.php' => '57eef89d5eca2a06a69929994a09d4fa', + './modules/SugarFeed/language/en_us.lang.php' => 'c386eb017aa688b08a132b2878e2fd4f', + './modules/SugarFeed/feedLogicBase.php' => '5679ed4e941ac2f28a084af99eec7df9', + './modules/SugarFeed/tpls/AdminSettings.tpl' => '15e26141e5f98784f96f78a14decaee4', + './modules/SugarFeed/SugarFeedFlush.php' => 'd8f0148a9606cd3ea8ceced4a743ec53', + './modules/SugarFeed/Menu.php' => '689b6fac731f80c95a1fbf24da4aa5f9', + './modules/SugarFeed/Forms.php' => 'd41d8cd98f00b204e9800998ecf8427e', + './modules/SugarFeed/Dashlets/SugarFeedDashlet/UserPostForm.tpl' => 'f32a591995f0087b69a9c09cb126d248', + './modules/SugarFeed/Dashlets/SugarFeedDashlet/SugarFeedScript.tpl' => '62dcebb59b5dfb0b297b83257c07b76b', + './modules/SugarFeed/Dashlets/SugarFeedDashlet/SugarFeedDashlet.php' => '311306d8959e193fb7336c06ba94c75d', + './modules/SugarFeed/Dashlets/SugarFeedDashlet/SugarFeedDashlet.meta.php' => '671e67c8cb16fd2393c86741dc531172', + './modules/SugarFeed/Dashlets/SugarFeedDashlet/Options.tpl' => '3e52b000a5e4196dd906f276f6fffc5e', + './modules/SugarFeed/SugarFeed.php' => '43ea72ab8dd8a21f617020f1235f9103', + './modules/SugarFeed/AdminSettings.php' => '4a4e87f638d6408f72adc03d38485350', + './modules/Studio/JSTransaction.js' => '36ddb37e1a173d58a1e8d3ac8c728399', + './modules/Studio/studio.js' => '0ef9ae531b2dfd6710eafc9556c6e9bc', + './modules/Studio/studiodd.js' => '5184cf38b52396d94afaec27b473d0f3', + './modules/Studio/studiotabgroups.js' => '29c08f5ea908bfff0ce3f78656cd7289', + './modules/Studio/ygDDListStudio.js' => '5a89d4bc04b8fe28e36c5d2df393953e', + './modules/Studio/wizards/StudioWizard.php' => '6a1b121436ad862ce331c37cb3d64120', + './modules/Studio/wizards/EditDropDownWizard.php' => '2544faf813d767d5ee1d899f241bbb0b', + './modules/Studio/wizard.php' => 'a3aa2c6e4f90f1ca59c9b27e1b662ae5', + './modules/Studio/parsers/StudioParser.php' => 'c6ad554e8dda163f8d8833a97366e941', + './modules/Studio/language/en_us.lang.php' => '5ce8340c4396eefe1d636388c218e311', + './modules/Studio/language/en_us.Portal.html' => '10ab579e1b9ade129b3f32d0de286f13', + './modules/Studio/config.php' => 'c6a1c6733d94c91cdb40020db6251602', + './modules/Studio/TabGroups/TabGroupHelper.php' => '85916f7c571c0b1aecebe5c8e01c41a5', + './modules/Studio/TabGroups/EditViewTabs.tpl' => 'ed1a9cba42a9baea7ec049969f101941', + './modules/Studio/TabGroups/EditViewTabs.php' => '3bce6ba3449444f0532d8df0d8c4c8d3', + './modules/Studio/TabGroups.php' => '3044dc610184d333ebb4c3bb38a24ee5', + './modules/Studio/SaveTabs.php' => '7a1bce049bb131087351407a91703c2e', + './modules/Studio/Forms.php' => '81c69876362d18fb55b89e59735b2bee', + './modules/Studio/DropDowns/EditView.tpl' => '62ee6ce084e14d75b2b812f571ff60d9', + './modules/Studio/DropDowns/EditView.php' => '8258a7a1ee8b2acef05b7688597a9a99', + './modules/Studio/DropDowns/DropDownHelper.php' => 'f312b9c50a862addcbb8d04f61048206', + './modules/SchedulersJobs/vardefs.php' => '3753fe65bb3e2b57182741b03d06b103', + './modules/SchedulersJobs/metadata/subpanels/default.php' => '0fe13add4d444631a0185bef78a8a9d6', + './modules/SchedulersJobs/language/en_us.lang.php' => '03324f484d6a373e8350d0248ffa155e', + './modules/SchedulersJobs/field_arrays.php' => '13aae3a0ab1f82eb46affc848ad25ace', + './modules/SchedulersJobs/SchedulersJob.php' => '2a7d2796404109dd20bfa744b26ea340', + './modules/Schedulers/vardefs.php' => '5841af67faf74658d311e7c9b6f8fe62', + './modules/Schedulers/metadata/subpanels/default.php' => '211c31e39227d3a7f847f6df832260cc', + './modules/Schedulers/metadata/subpaneldefs.php' => '2e8f77cf8125cb5617d69739192625ec', + './modules/Schedulers/language/en_us.lang.php' => '3a5297c79088ad18cbe1145031eea605', + './modules/Schedulers/index.php' => '725d0499fe99123816fb1132fd28c0dc', + './modules/Schedulers/field_arrays.php' => '7f556e11519f16ca7a2ca174efd196b9', + './modules/Schedulers/_AddJobsHere.php' => '30568dc7b8552ad338c7bdc364ee62c9', + './modules/Schedulers/SchedulerDaemon.php' => '75b412a5a0d4c06593139ddb0cae774c', + './modules/Schedulers/Scheduler.php' => 'c50dc4769f49dfeb3684d5de7c403c64', + './modules/Schedulers/Scheduled.php' => 'ff2907aa3f299ef7167a938f42116004', + './modules/Schedulers/Scheduled.html' => 'f6623756056847129c8c60b9b7209783', + './modules/Schedulers/Save.php' => '10a6b3f889665314db290da1c967f977', + './modules/Schedulers/Menu.php' => 'bce50cadfc1d4295d063c5b8a9909fca', + './modules/Schedulers/ListView.php' => '67f433a9a7f2d28cd23d97ffabd122db', + './modules/Schedulers/ListView.html' => '6e3ed1e28a2024c6dd8d3ed95c951b28', + './modules/Schedulers/JobThread.php' => '0501ccb1835c3ee8e2c48bd1c2705749', + './modules/Schedulers/EditView.php' => '5dd090303f4e62fcfa19f5ff4a38808e', + './modules/Schedulers/EditView.html' => 'ef6cfa5254f2b6afb37da045d148101d', + './modules/Schedulers/DetailView.php' => '2a107f341c14d5e8e8fedca898ca56d4', + './modules/Schedulers/DetailView.html' => '6c143319127bea5c8f12fdc0f663b1a1', + './modules/Schedulers/DeleteScheduled.php' => '4c316e04b8b1e166e4075d184bb3dd4c', + './modules/Schedulers/Delete.php' => 'efd2fdd9222ba66e5343251681e4447a', + './modules/SavedSearch/vardefs.php' => '8170e468e6f1f82a000847df49c3bcd2', + './modules/SavedSearch/metadata/listviewdefs.php' => '192cbaf9da9556966576a9ed5e0b3512', + './modules/SavedSearch/language/en_us.lang.php' => 'e8cfb480cc94c076f2ea83952941264e', + './modules/SavedSearch/index.php' => 'efaefa81ecee8146203b2a5ae2c21a1e', + './modules/SavedSearch/field_arrays.php' => '25b090694e486adc18ce183cacb9d643', + './modules/SavedSearch/UpgradeSavedSearch.php' => '795be93009d7775a516ad02e35befc2b', + './modules/SavedSearch/SearchForm.html' => '3e0e486147cc248570d85c55e4d8950d', + './modules/SavedSearch/SavedSearchSelects.tpl' => 'e14b466d89ca1482ba925fadcdd05588', + './modules/SavedSearch/SavedSearchForm.tpl' => 'da3645cf5c9f21e2c6d11016e8d7102d', + './modules/SavedSearch/SavedSearch.php' => 'eb6d703feb1b5e95f0696a53572445c0', + './modules/SavedSearch/Menu.php' => '76c48e25df51f1a0a32e78aa08cf05d8', + './modules/SavedSearch/ListView.php' => 'd0dd70645af34446ebfb7b7c2a0b6572', + './modules/Roles/views/view.list.php' => '392d4bb043944c45287d3f4bdcd360ba', + './modules/Roles/vardefs.php' => '5b7de081974cec1074d575a245c0925d', + './modules/Roles/metadata/subpanels/default.php' => '2246d76c8778b443088e62d5ddbc4595', + './modules/Roles/metadata/subpaneldefs.php' => '84309164c22abb4c2f688c1d8fc511fe', + './modules/Roles/metadata/searchdefs.php' => '0b686b6e1ee2fc58b61754749784f5d5', + './modules/Roles/metadata/listviewdefs.php' => 'eb8c0fffc25382723dce28f060018686', + './modules/Roles/metadata/SearchFields.php' => 'a0297ea6907a89f59dd169d18edac897', + './modules/Roles/language/en_us.lang.php' => 'd08455d2d7f498163d97f0287fe1ce6e', + './modules/Roles/field_arrays.php' => '59fe4fc278b0c1bdeab449beb06e8731', + './modules/Roles/SubPanelViewUsers.php' => 'a2b377abb3b7592ebb9cd51328d95bb6', + './modules/Roles/SubPanelViewUsers.html' => '1a57e7edd64a3a3ab7b154fbd770a39a', + './modules/Roles/SaveUserRelationship.php' => 'b44722019bde48112faa0e0f59d8cc97', + './modules/Roles/Save.php' => '793d861058e96cd69134a1b87ef9722e', + './modules/Roles/Role.php' => '840f5e2e77ffde3fef8713377ad0f11d', + './modules/Roles/Menu.php' => '9998ce5ca80ace0a3ec538c5e87fa7b5', + './modules/Roles/Forms.php' => '86d7155dd64c40a91d7e7f25ee01fe08', + './modules/Roles/EditView.php' => 'd87986b438b3a43a5c3feb71cc71c7d8', + './modules/Roles/EditView.html' => '85eb9914e8401320bad6dcecda33a70b', + './modules/Roles/DetailView.php' => 'fc296ea8b5ad617eace9f1e7b81dedd3', + './modules/Roles/DetailView.html' => 'e978da97c0f1567d1ae8aff98cf217c6', + './modules/Roles/DeleteUserRelationship.php' => 'cb0f087d7215b0d54f7a7238efce4d98', + './modules/Roles/Delete.php' => '1c5335b304b91abddd25a5b121d44cd1', + './modules/Releases/vardefs.php' => 'eda3b2695643ab8cbaf2e8799ff4e403', + './modules/Releases/language/en_us.lang.php' => '1868fa24b2b9db7528a57bbf14b1c3aa', + './modules/Releases/index.php' => 'b56b041809f81b7be8770e795a73b097', + './modules/Releases/field_arrays.php' => 'a7ad1478be87c4c28a336e71e780d885', + './modules/Releases/Save.php' => '3836c0f3fc25ae9689f4e64cae875c8b', + './modules/Releases/Release.php' => '7cd3b0714dd0e6176a4dde8a21840c06', + './modules/Releases/Popup_picker.php' => '50d6e1847bc03fd948e4d62b219fdab1', + './modules/Releases/Popup_picker.html' => 'c951953dba287fef4f2a1e04c8858f46', + './modules/Releases/Menu.php' => '6bd026361a892e7f2b1cdde2d8b417e3', + './modules/Releases/ListView.html' => 'c2501accf7836e8d97bea99b20172074', + './modules/Releases/EditView.php' => '9eee379213e94b6555ee9be803094173', + './modules/Releases/EditView.html' => '830fd8fa8f60c8e42bc2c315cfc160c3', + './modules/Releases/DetailView.php' => 'f49097744c4fbb00df4b3a80b634516b', + './modules/Relationships/vardefs.php' => 'fcc33d4741cb1495a8c969827f30d559', + './modules/Relationships/language/en_us.lang.php' => '979b1106f5ab083765cddfaddc9bb17e', + './modules/Relationships/field_arrays.php' => '45cd3e9bb1f7a0fe2bbfc15b95248c58', + './modules/Relationships/RelationshipHandler.php' => 'f7cfdd20a3a14bf5c2d62ee52703c939', + './modules/Relationships/Relationship.php' => '8e22b233f0c1cd7eb98a934548a967b3', + './modules/Prospects/views/view.list.php' => 'dffbd8d46cf6f37bf409596a8306d2d1', + './modules/Prospects/views/view.detail.php' => '524460f732a66b8829430df637a4e9be', + './modules/Prospects/vardefs.php' => '87b7d11c7dc6ddbd893c78741fe39dde', + './modules/Prospects/tpls/DetailViewHeader.tpl' => '3f7b93710019238efa92653766cc748b', + './modules/Prospects/metadata/subpanels/default.php' => '1339522c9eeec38f2a45541d189ce59f', + './modules/Prospects/metadata/subpaneldefs.php' => 'c657fdaaa87dd0ee910c5295b95003d4', + './modules/Prospects/metadata/studio.php' => '0786db2e28dbe43e51f47e9771841d00', + './modules/Prospects/metadata/searchdefs.php' => 'dace2a3e6018d1cb79e9d500a0ae2f23', + './modules/Prospects/metadata/quickcreatedefs.php' => 'c97898e1ba07f72f0f4f29a9135fb82a', + './modules/Prospects/metadata/popupdefs.php' => '880e8450e847fcd39dc8a6a6487ffb14', + './modules/Prospects/metadata/listviewdefs.php' => '30c27f7f365a14974413ab73273b7f8f', + './modules/Prospects/metadata/editviewdefs.php' => '77d1d32d21e6f0034cc9eeb89213de81', + './modules/Prospects/metadata/detailviewdefs.php' => '1ef40c7f0819f99c212a425c4f4e238c', + './modules/Prospects/metadata/additionalDetails.php' => 'f183e1b69fb95f7fa30a35b5f8b821aa', + './modules/Prospects/metadata/SearchFields.php' => '1e7ccc95eab7a01d885899825a2a435f', + './modules/Prospects/language/en_us.lang.php' => '51d25f98e3699f8a2f5f1e04af5dd5fa', + './modules/Prospects/field_arrays.php' => '51241a0004e0bb358a236fa8655258cd', + './modules/Prospects/Save.php' => '774b5ad6afb0822f8b56afd85dde4d25', + './modules/Prospects/ProspectFormBase.php' => '50497a920fc4b5155dd4c324e148315a', + './modules/Prospects/Prospect.php' => '6b69a8fa590f81f86ec12b402a2fd6e3', + './modules/Prospects/Popup_picker.html' => '0cab856872d14ffad67db705f9fac5c4', + './modules/Prospects/Menu.php' => 'cf73810172808b53ed5befcd8258e61f', + './modules/Prospects/Import.php' => '901946e285e08b4e8edab5ecdc2a72aa', + './modules/Prospects/Delete.php' => '8dd12fcb031cfad26cc8b0e6bac2ff27', + './modules/ProspectLists/vardefs.php' => '5a3361bd1b82da9910f92daa2864ac62', + './modules/ProspectLists/metadata/subpanels/default.php' => '3fbedc002f64433b6f50d7b64f0bc489', + './modules/ProspectLists/metadata/subpaneldefs.php' => '87eaec0a7e33121dd60f0769f1dc3603', + './modules/ProspectLists/metadata/searchdefs.php' => '1fb83db39751ba9e583a3d2019b46cf3', + './modules/ProspectLists/metadata/popupdefs.php' => 'e5b406f2dd6981ef5925a11519f59f1e', + './modules/ProspectLists/metadata/listviewdefs.php' => '5a1861c39bd93d36e4445d0b5cb0dd18', + './modules/ProspectLists/metadata/editviewdefs.php' => '09c4c64e5ea7adf58deebc4b3623aab6', + './modules/ProspectLists/metadata/detailviewdefs.php' => '710d9ce60f9fdcf00d01bdf7facf92c6', + './modules/ProspectLists/metadata/SearchFields.php' => '51bc2a44632ab09db184cbe82c0653f4', + './modules/ProspectLists/language/en_us.lang.php' => 'edd03416cf7d8102abdfa253fee45111', + './modules/ProspectLists/field_arrays.php' => 'c9ef4935b8a184a886e2b330ede6f4ce', + './modules/ProspectLists/TargetListUpdate.php' => 'eaaf076c5c0dd2c8353fa4ce5d96caba', + './modules/ProspectLists/SubPanelView.php' => '647be549716dd760cf29be7aa9630916', + './modules/ProspectLists/SubPanelView.html' => '21e44461a9595bad1cce017d2058d2ad', + './modules/ProspectLists/Save.php' => 'c0025df53ae0797b7787fd9b1737602f', + './modules/ProspectLists/ProspectListFormBase.php' => 'bfaaf6b451bae7635bed05ad102fc3f9', + './modules/ProspectLists/ProspectList.php' => '64a539a55212fbcd0ec762231dcb5e5e', + './modules/ProspectLists/Popup_picker.html' => '6902311909d092e893ec8d583863ac35', + './modules/ProspectLists/Menu.php' => '45c02816fd458c1bf8e8c0a62411a57b', + './modules/ProspectLists/Forms.php' => 'e3e083f6f6892fb028f8e30bf5bffc1e', + './modules/ProspectLists/Forms.html' => '15ef1dc459471b67c351282d3e00f836', + './modules/ProspectLists/Duplicate.php' => 'd89a7f0d0bd285a0930280c738527a63', + './modules/ProspectLists/Delete.php' => '796118b7ceafc8f816c6f772798e9da1', + './modules/ProjectTask/ProjectTask.js' => 'ada54f7db9ad037c753a6befdfee4791', + './modules/ProjectTask/views/view.list.php' => '71ea6bd90ec0ad45455f98b8e3e5256a', + './modules/ProjectTask/vardefs.php' => '0d34b70b22bd6811ec3ef2d2b2f896fa', + './modules/ProjectTask/tpls/QuickCreate.tpl' => '4dd0099e05fdeaf25b578bea811b26cf', + './modules/ProjectTask/metadata/subpanels/default.php' => 'ef6e514d97f20d3dfbb2073be6846378', + './modules/ProjectTask/metadata/subpaneldefs.php' => 'ace4e4a48a923d36d07ca55a64634e24', + './modules/ProjectTask/metadata/studio.php' => 'e56e0a14e6ed2664e3e19a433ba1dc29', + './modules/ProjectTask/metadata/searchdefs.php' => '2c48053cdc23e150746d45e6bf70b45d', + './modules/ProjectTask/metadata/popupdefs.php' => '0129a2d82e1f6333221592376da8484d', + './modules/ProjectTask/metadata/listviewdefs.php' => '10ed314b9940738bdc41e40e04844081', + './modules/ProjectTask/metadata/editviewdefs.php' => '5ddf2e7b95ac8ce945b5576c5d9d07af', + './modules/ProjectTask/metadata/detailviewdefs.php' => 'c891578c9ffb78c39d980c6b130aa9c4', + './modules/ProjectTask/metadata/additionalDetails.php' => '3debf7d4223659965db368d9072236fa', + './modules/ProjectTask/metadata/acldefs.php' => 'c3ff3175b906ede34a4c8b97439096d1', + './modules/ProjectTask/metadata/SearchFields.php' => 'ad9e6d2c7dd40f37075ed1e769a15893', + './modules/ProjectTask/language/en_us.lang.php' => 'a3133e507944685ba101edb0576cd622', + './modules/ProjectTask/field_arrays.php' => '99e9c75602079ee1ebe4483e96d48669', + './modules/ProjectTask/SubPanelView.php' => 'ef83d3a0508bcccfb820913d4676918e', + './modules/ProjectTask/SubPanelView.html' => 'eae194d95cffea13900ecf9614a02208', + './modules/ProjectTask/Save.php' => '613de85e3c64b187f8906a78dc9ce806', + './modules/ProjectTask/ProjectTaskQuickCreate.php' => '0096422fcc5afd8ee12582155cb462bf', + './modules/ProjectTask/ProjectTask.php' => 'd4bbc572e70e877c40dc1ad38fde8a75', + './modules/ProjectTask/Popup_picker.html' => '5954d35200b3998993c6d3834bb79d69', + './modules/ProjectTask/Popup.php' => 'c3edbfbdc357850743bfe913750e13d2', + './modules/ProjectTask/Popup.html' => 'bd269239afeb5a9865df3eec230ec7f6', + './modules/ProjectTask/MyProjectTasks.php' => '8b0258241c7860ad9cd420743d435574', + './modules/ProjectTask/MyProjectTasks.html' => '63f6b95493b9f5bbe06c4673d573b4b6', + './modules/ProjectTask/Menu.php' => '5d44b3b3bd99d4546ca82baed21c62fe', + './modules/ProjectTask/Forms.html' => 'b30faeb6fdb596c4dd425ecd22bcbb73', + './modules/ProjectTask/Delete.php' => '53df2a460c75bc1cb87aa419bfdb9131', + './modules/ProjectTask/Dashlets/MyProjectTaskDashlet/MyProjectTaskDashlet.php' => '2d3a7f29955a657bd22b28a11e96129b', + './modules/ProjectTask/Dashlets/MyProjectTaskDashlet/MyProjectTaskDashlet.meta.php' => 'a7cb681795e78b00e9037ebda350a593', + './modules/ProjectTask/Dashlets/MyProjectTaskDashlet/MyProjectTaskDashlet.data.php' => '6adec2dfd0e401f5e97a4fadd53bc055', + './modules/Project/Project.js' => '8b1002794632e9b0a91758b0be180c13', + './modules/Project/views/view.templatesedit.php' => '665c813d9c54d2e76ce0d2d6fd65db97', + './modules/Project/views/view.templatesdetail.php' => 'b87bced26b8e42afbf9208a307b57487', + './modules/Project/views/view.list.php' => '415b99993db68bcf349aaab12a7301c8', + './modules/Project/views/view.edit.php' => '7585a5def6ad87871dde511e01d518f3', + './modules/Project/views/view.detail.php' => 'f16e046281cd919a30dafa8f7d62b613', + './modules/Project/vardefs.php' => '0d8065e157c71059c36945be102877bc', + './modules/Project/tpls/QuickCreate.tpl' => 'f945805bd5ddb1963cef79413c5c9cdd', + './modules/Project/metadata/subpanels/default.php' => '6e4dd1edba8ea8d26a90bc2b47eeb146', + './modules/Project/metadata/subpanels/ForEmails.php' => '3005add91d6d61f247093f9232af2570', + './modules/Project/metadata/subpaneldefs.php' => '063079fbf6e22dbf09f41bd7e2bc61c5', + './modules/Project/metadata/studio.php' => 'b236f2ddd07671e55086596bbac02ccb', + './modules/Project/metadata/searchdefs.php' => 'dc4684e05e95216dba9ece5ec9786abb', + './modules/Project/metadata/quickcreatedefs.php' => '80bcfcddfdce79f7c1c535410cf6150c', + './modules/Project/metadata/popupdefs.php' => '83bd0e0d8e72c1f6b90bad6240479908', + './modules/Project/metadata/metafiles.php' => '1911d61a0a285ce8e1f4fd4d29703701', + './modules/Project/metadata/listviewdefs.php' => '155c6c174aecbd2303175119901fec54', + './modules/Project/metadata/editviewdefs.php' => '12684f40300a74aacd71923485acfb8c', + './modules/Project/metadata/detailviewdefs.php' => '8286ec435357279811f854b06d4f944d', + './modules/Project/metadata/additionalDetails.php' => 'a9ec9af1f3c83e5439695acce93911e2', + './modules/Project/metadata/SearchFields.php' => 'a3e27edbfa0063a91622ddff91a2c772', + './modules/Project/language/en_us.lang.php' => '1758b6b050bb6e2aa9c6c3a8dceed672', + './modules/Project/field_arrays.php' => '9d093e2a0ce97c512be35f3af7f1df81', + './modules/Project/action_view_map.php' => '04326954b793fc76db528f949f541c8c', + './modules/Project/SubPanelView.php' => 'a69b4eabcf7b8091a2438712bf97d93c', + './modules/Project/SubPanelView.html' => '2096fc5b39062f64191a3f27f4709532', + './modules/Project/Save.php' => 'b70640108a1dac870d8e93ef05aeff36', + './modules/Project/ProjectQuickCreate.php' => 'f59a98b8e20d89720b8d8258a71345cc', + './modules/Project/Project.php' => '10ad3258d0bda1e52051d456cfbe3018', + './modules/Project/Menu.php' => '57d1ba844804c2cedee57ce92df78152', + './modules/Project/Delete.php' => '3d90ac7e15a52de01d264d6514a50990', + './modules/OptimisticLock/language/en_us.lang.php' => 'da108687fe1ad5a2f517b4be760b4500', + './modules/OptimisticLock/Menu.php' => 'ab2d8a3388a4ad15ba2a8702d8167438', + './modules/OptimisticLock/LockResolve.php' => 'af27e2702d189f540f87112c3ec7f060', + './modules/OptimisticLock/Forms.php' => '1426ca53f6b7d0dfa8d2c12164ab814e', + './modules/Opportunities/views/view.edit.php' => '7d5f91f50318796a197ed5911ca89090', + './modules/Opportunities/views/view.detail.php' => '2031e46f2fe3f86bfed2cb000d8152e7', + './modules/Opportunities/vardefs.php' => '66b2b45cd7f71db459e6d0e533d4d540', + './modules/Opportunities/tpls/QuickCreate.tpl' => 'a97086f3b05fd812fa5aa13c8934d518', + './modules/Opportunities/metadata/subpanels/default.php' => '9055b5051763913602c1b0cfcec6a6a8', + './modules/Opportunities/metadata/subpanels/ForEmails.php' => 'a23e3862c9ed6a4eafd63c2f6bd6926b', + './modules/Opportunities/metadata/subpanels/ForAccounts.php' => '1c7dc76af48c49c5d32bf619f9fe58c3', + './modules/Opportunities/metadata/subpaneldefs.php' => '2e61a5d755c197597eef47005cbeefd2', + './modules/Opportunities/metadata/studio.php' => '2ecdfdc439cb4586bbe539e63d037c91', + './modules/Opportunities/metadata/searchdefs.php' => 'a2cf2aa25373055ba1557fb1ef259f7a', + './modules/Opportunities/metadata/quickcreatedefs.php' => 'ce950482bcd273362f97c4da063ac262', + './modules/Opportunities/metadata/popupdefs.php' => 'b33714d9154fb5f4ffaba5c01fc14021', + './modules/Opportunities/metadata/metafiles.php' => '8c2f3857e7a218748033ea5ac9c72438', + './modules/Opportunities/metadata/listviewdefs.php' => '488ff35629356b012435b17b50190d99', + './modules/Opportunities/metadata/editviewdefs.php' => '89552e6704b61aae1ac0c29ab856148e', + './modules/Opportunities/metadata/detailviewdefs.php' => '130c67be8848ca23ee84adcd7d578cdd', + './modules/Opportunities/metadata/additionalDetails.php' => '4e4a3f43d59864fa1d605ad1bd974c09', + './modules/Opportunities/metadata/acldefs.php' => '5268a3225576dff2be5ed567f7754ea3', + './modules/Opportunities/metadata/SearchFields.php' => '408a3bc249b78244ce465c7cdd8f6ea4', + './modules/Opportunities/language/en_us.lang.php' => 'e4795af2749d63783d2de150f6368d3f', + './modules/Opportunities/field_arrays.php' => 'fa73b1cbef1a90e6ff67dd27dac3dd94', + './modules/Opportunities/SugarFeeds/OppFeed.php' => '6de18f1cdf081e6ea21d337d0dd0588c', + './modules/Opportunities/SubPanelViewProjects.php' => 'd265850f1189b7af991f5d53f4a495d6', + './modules/Opportunities/SubPanelViewProjects.html' => 'a61c46eabae260242f80e4395c6271ba', + './modules/Opportunities/SubPanelView.php' => 'b526538005e43c951ad309ffaf8d87a0', + './modules/Opportunities/SubPanelView.html' => '6b51451724f37acdb37afc007775e52d', + './modules/Opportunities/SaveOverload.php' => '50296d5a9749d0cca36d0a2d7b851a67', + './modules/Opportunities/Save.php' => '7fbc793c50fecad076ac08d121a5d87d', + './modules/Opportunities/OpportunityFormBase.php' => '96d3099b41d15333f2c32a63ceb2f1de', + './modules/Opportunities/Opportunity.php' => '4d1a149fa8ce8cd5fc7ad799eaf529ca', + './modules/Opportunities/OpportunitiesQuickCreate.php' => '6019102062aa4d93ef001e1d06691ea8', + './modules/Opportunities/Menu.php' => 'c1213ce80b4cac1298505d3ef84b69d2', + './modules/Opportunities/ListViewTop.php' => 'e77a90af42ace6193feab7d3893a9631', + './modules/Opportunities/ListViewTop.html' => '352b5cf148dfd8143d61fd79191dab0d', + './modules/Opportunities/Dashlets/MyOpportunitiesDashlet/MyOpportunitiesDashlet.php' => 'f038dcbab37f2c7b3412a533328d299b', + './modules/Opportunities/Dashlets/MyOpportunitiesDashlet/MyOpportunitiesDashlet.meta.php' => '30c2ef6dc2728b55feefa6059c15166b', + './modules/Opportunities/Dashlets/MyOpportunitiesDashlet/MyOpportunitiesDashlet.data.php' => '7ca8885c9c7d621bf6a362b6333bf8d7', + './modules/Opportunities/Dashlets/MyClosedOpportunitiesDashlet/MyClosedOpportunitiesDashletOptions.tpl' => 'af2e87f986e73938a4df665c3baa219f', + './modules/Opportunities/Dashlets/MyClosedOpportunitiesDashlet/MyClosedOpportunitiesDashletConfigure.tpl' => '85a1f82b9edf6d5c867fdbb49b645cda', + './modules/Opportunities/Dashlets/MyClosedOpportunitiesDashlet/MyClosedOpportunitiesDashlet.tpl' => 'b9cddf9611a364e83fffe6e70e25a466', + './modules/Opportunities/Dashlets/MyClosedOpportunitiesDashlet/MyClosedOpportunitiesDashlet.php' => '9ae01144105194e42072e3d378ef9fe7', + './modules/Opportunities/Dashlets/MyClosedOpportunitiesDashlet/MyClosedOpportunitiesDashlet.meta.php' => 'cd8466622b1201d34fcbb7d13e3084f2', + './modules/Notes/Dashlets/MyNotesDashlet/MyNotesDashlet.php' => 'f9ab3897fc09f21ea1ecb3f953dad090', + './modules/Notes/Dashlets/MyNotesDashlet/MyNotesDashlet.meta.php' => '0184797e2c51448e2a176ff7c0d1cdaf', + './modules/Notes/Dashlets/MyNotesDashlet/MyNotesDashlet.data.php' => 'ab49b04a87d38c96bf763dccff5fda0f', + './modules/Notes/vardefs.php' => 'da3a3314abfc2360532518ce50e8c685', + './modules/Notes/tpls/QuickCreate.tpl' => '0a9fb5e76a39a8a830f38e98c95b20db', + './modules/Notes/tpls/EditViewHeader.tpl' => '6d17efa511b050306ad8917250a55612', + './modules/Notes/metadata/subpanels/ForMeetings.php' => '96a261d7cb62b23e280e0ed951838cc1', + './modules/Notes/metadata/subpanels/ForCalls.php' => '96a261d7cb62b23e280e0ed951838cc1', + './modules/Notes/metadata/subpanels/default.php' => '4be031ba9baa81f049e0a913e74699cd', + './modules/Notes/metadata/subpanels/ForHistory.php' => '6764b710d1f251c025ce769e23ae9362', + './modules/Notes/metadata/studio.php' => '1f44d8404cbd0338366d6c8fa46736de', + './modules/Notes/metadata/searchdefs.php' => 'e8bd7141325af729998e8c28628987b0', + './modules/Notes/metadata/quickcreatedefs.php' => 'c00836e71bd882f126294c06a259bcb8', + './modules/Notes/metadata/listviewdefs.php' => 'c41f85e58d565bf47a82d6c81eb31c4a', + './modules/Notes/metadata/editviewdefs.php' => 'a56c4ca60082b5bf7e6e5e2033c8e77a', + './modules/Notes/metadata/detailviewdefs.php' => '826afd0a9cab3b34cef8bda901108828', + './modules/Notes/metadata/additionalDetails.php' => 'dee7ede2f0db07e060ef69e7d193b862', + './modules/Notes/metadata/SearchFields.php' => 'b1a7b3ea5cbfbe90e3f675278a64d52c', + './modules/Notes/language/en_us.lang.php' => 'a943d66117c8118f2603227b6066c392', + './modules/Notes/field_arrays.php' => '400e52fbc9b6eadf5db444f142fa6fa7', + './modules/Notes/controller.php' => '5f0c26c4e8eb71dcab090cce6b5730f0', + './modules/Notes/SubPanelView.php' => 'f099efee6491848eda33f1bb61a927b2', + './modules/Notes/SubPanelView.html' => 'f3e126cc96a15934186b9c069d6feb2f', + './modules/Notes/NotesQuickCreate.php' => 'b83915d88ed4d6317ffd84edc69e025a', + './modules/Notes/NoteSoap.php' => 'a4f0c48060767dcd129e7c53cfc0bc5c', + './modules/Notes/Note.php' => 'b87b2da97c012ae6e06df8e354432e0c', + './modules/Notes/Menu.php' => '80e4a5be7e5f7a316f11f43e646e7dab', + './modules/MySettings/language/en_us.lang.php' => '7ab73e2c534ab7d66597730282c87ae3', + './modules/MySettings/TabController.php' => '5bccbc225eae09c59583f438f1525a1b', + './modules/MySettings/StoreQuery.php' => '352d80fb2aabd3075a5411d20dd9a4a6', + './modules/MySettings/LoadTabSubpanels.php' => 'a255e18695ce5a628f77ea5ee52cf87e', + './modules/ModuleBuilder/views/view.wizard.php' => 'c78cb93efd113dde2af478dfc573e804', + './modules/ModuleBuilder/views/view.tree.php' => '0b0b0db7b37c683bc7849394162c3222', + './modules/ModuleBuilder/views/view.searchview.php' => '4db474573b87f1c477d1a4fe27957938', + './modules/ModuleBuilder/views/view.resetmodule.php' => '133a265b7a93a0ba424bef0e518451bf', + './modules/ModuleBuilder/views/view.relationships.php' => 'd66fd2c1ef2b4cca10372f00718bf5d6', + './modules/ModuleBuilder/views/view.relationship.php' => '197a5b2f70e75fb4eecb70845d8f2c6d', + './modules/ModuleBuilder/views/view.property.php' => '1b93903fc16f80366722ea4e866e6556', + './modules/ModuleBuilder/views/view.popupview.php' => '226f20d1a309ada7dd37e7d33673d144', + './modules/ModuleBuilder/views/view.package.php' => '87f70506bf8828439178f39d894caf91', + './modules/ModuleBuilder/views/view.modulelabels.php' => '9dd48dfb5ba54814317ab9caa59a90ce', + './modules/ModuleBuilder/views/view.modulefields.php' => '552a0daeba8fbffc9ec8de6ef4adc687', + './modules/ModuleBuilder/views/view.modulefield.php' => '2da87211a7afadb1fd2a25d7ab84e423', + './modules/ModuleBuilder/views/view.module.php' => '5999056216764952a42fc53d30186e57', + './modules/ModuleBuilder/views/view.main.php' => '0f8f0d634d1370ca67726859d2dc9ca6', + './modules/ModuleBuilder/views/view.listview.php' => 'c2013e0c055b6ad7019a46d201e82c25', + './modules/ModuleBuilder/views/view.layoutview.php' => 'de45ac3a3d6bc24e53d664ae53877b9c', + './modules/ModuleBuilder/views/view.labels.php' => 'eb8d62e1dcc22b1aa1345ec4b2e39c23', + './modules/ModuleBuilder/views/view.home.php' => '52a4628291c14dad6755a3ad43895e82', + './modules/ModuleBuilder/views/view.history.php' => '9aa48373bfbe8324b69facbf2c89aff7', + './modules/ModuleBuilder/views/view.exportcustomizations.php' => '24a0779e56fdfc38baf0f7cf642c5d5e', + './modules/ModuleBuilder/views/view.dropdowns.php' => 'b702280afdb3e55fe695b1959d8e2c85', + './modules/ModuleBuilder/views/view.dropdown.php' => '0281c3b567a564c2a561af85c3fc9168', + './modules/ModuleBuilder/views/view.displaydeployresult.php' => '547cd6a7cbf757cba95ac2d899665cd5', + './modules/ModuleBuilder/views/view.displaydeploy.php' => '3ae8aa51e9e8c51004656380fe505429', + './modules/ModuleBuilder/views/view.deletepackage.php' => '48cac1895df4eb9517b3c10d94a32fac', + './modules/ModuleBuilder/views/view.deletemodule.php' => '7a2dc62d2d18191a6d0119e31037be02', + './modules/ModuleBuilder/views/view.dashlet.php' => '810c4c14c78e698e583dd95c7090eab0', + './modules/ModuleBuilder/tpls/wizard.tpl' => 'a16245f3694aaface1daf7cea52d235f', + './modules/ModuleBuilder/tpls/tabBG.png' => '8e2561b0bba66f327d602e6c5f06aa08', + './modules/ModuleBuilder/tpls/studioRelationships.tpl' => '63559e6743033f514eed689f5d458afa', + './modules/ModuleBuilder/tpls/studioRelationship.tpl' => '8d7177bfcec39edddafae33573525c76', + './modules/ModuleBuilder/tpls/resetModule.tpl' => '237bb16f4bfcd274404bfd261cc86d9c', + './modules/ModuleBuilder/tpls/main.tpl' => '0a16177d0083d8db2c2821333164ee60', + './modules/ModuleBuilder/tpls/listView.tpl' => '232f172456a901a19f8ddf43510bc101', + './modules/ModuleBuilder/tpls/layoutView.tpl' => 'c12c505cde12cc8aec12c98f3a5b6eff', + './modules/ModuleBuilder/tpls/labels.tpl' => 'a7b10e70775c426d60830ea5e28ca413', + './modules/ModuleBuilder/tpls/index.tpl' => '9d267e68e0a713836dab11f5af3eb128', + './modules/ModuleBuilder/tpls/includes.tpl' => '957fb37ef63708de02f5ff7495adb210', + './modules/ModuleBuilder/tpls/history.tpl' => 'e75aad72381176b2b21a711956bcc025', + './modules/ModuleBuilder/tpls/exportcustomizations.tpl' => '3f3a4edb5afbf1a87407de76ffd73b99', + './modules/ModuleBuilder/tpls/editProperty.tpl' => '3e857e332bc62ea5849d60e262e57acc', + './modules/ModuleBuilder/tpls/assistantJavascript.tpl' => '698546e9a25c7d0fdd69010b61ce5c0e', + './modules/ModuleBuilder/tpls/Preview/listView.tpl' => 'fc840cefbd0db68cad7dc06c3438bfbf', + './modules/ModuleBuilder/tpls/Preview/layoutView.tpl' => '656d3caf168fbccc5e5021e2916c72ae', + './modules/ModuleBuilder/tpls/MBPackage/package.tpl' => '2452daa01c1eca76c302600e0d08c4ba', + './modules/ModuleBuilder/tpls/MBPackage/deploy.tpl' => 'f7a7d0f2489b9caaef8f9cdfb25b4341', + './modules/ModuleBuilder/tpls/MBPackage/appLanguage.tpl' => 'd41d8cd98f00b204e9800998ecf8427e', + './modules/ModuleBuilder/tpls/MBModule/vardef.tpl' => '760c0eb16b8c95e971cfd0c7f01fc721', + './modules/ModuleBuilder/tpls/MBModule/module.tpl' => 'c211e3fe7226fa5e8e9db3ef854b536f', + './modules/ModuleBuilder/tpls/MBModule/main.tpl' => 'd41d8cd98f00b204e9800998ecf8427e', + './modules/ModuleBuilder/tpls/MBModule/language.tpl' => 'f27ee7b7829bcb7f1306eb2153311f52', + './modules/ModuleBuilder/tpls/MBModule/form.tpl' => 'd41d8cd98f00b204e9800998ecf8427e', + './modules/ModuleBuilder/tpls/MBModule/fields.tpl' => '1bf6aabbf8867f70b65df84518225b2f', + './modules/ModuleBuilder/tpls/MBModule/field.tpl' => '02bd0401451644635445f344cdb3c6ba', + './modules/ModuleBuilder/tpls/MBModule/dropdowns.tpl' => 'fb5fef35a8894f518fe2f968c475977b', + './modules/ModuleBuilder/tpls/MBModule/dropdown.tpl' => '62a3119527321d55ba7dbc3aa63dae9c', + './modules/ModuleBuilder/tpls/MBModule/dropdown.css' => 'd80cad459209446b7e37eb50cc587402', + './modules/ModuleBuilder/tpls/MBModule/Studio.tpl' => 'b22f8728a3a2587c2fb320b41f98e7f7', + './modules/ModuleBuilder/tpls/MBModule/Menu.tpl' => '5c3fb02c1df609001b6b1befbf279fa7', + './modules/ModuleBuilder/tpls/MBModule/DeveloperClass.tpl' => 'f88daf535fbee9bcace71677a659e750', + './modules/ModuleBuilder/tpls/MBModule/Class.tpl' => '6b2e3d2e8cf7d24a444db0bdf833ee62', + './modules/ModuleBuilder/tpls/MB.css' => '5b3eb2ed2f3f390d28eea73c8cd38078', + './modules/ModuleBuilder/tpls/ListEditor.css' => 'f602eca9103560b387d46714b556e9d4', + './modules/ModuleBuilder/tpls/LayoutEditor.css' => 'e7f0eba7b6239f17056c9cf08b47a442', + './modules/ModuleBuilder/parsers/views/UndeployedSubpanelImplementation.php' => '8bf52486443c355c8b79e5fd1dc9cbbc', + './modules/ModuleBuilder/parsers/views/UndeployedMetaDataImplementation.php' => '051fd6d8a11da5401ae81beaf4e113e5', + './modules/ModuleBuilder/parsers/views/SubpanelMetaDataParser.php' => '542f456cb1cc63ec56e19ae90fe30fcb', + './modules/ModuleBuilder/parsers/views/SearchViewMetaDataParser.php' => '6d82587411329201dc37249f8528f2ab', + './modules/ModuleBuilder/parsers/views/PopupMetaDataParser.php' => 'b14ee5d20098eae316c670beccc64d59', + './modules/ModuleBuilder/parsers/views/MetaDataParserInterface.php' => '9d05e19877d06257eaaa968336df70b2', + './modules/ModuleBuilder/parsers/views/MetaDataImplementationInterface.php' => 'b162f891343be882c5592f2739565698', + './modules/ModuleBuilder/parsers/views/ListLayoutMetaDataParser.php' => '6a6a48db17770889a0196bdc9ab3401f', + './modules/ModuleBuilder/parsers/views/HistoryInterface.php' => 'eaccd7749cff5a9691088dce27bca75b', + './modules/ModuleBuilder/parsers/views/History.php' => 'c5165637f19abda0bdc5d643c479a6a5', + './modules/ModuleBuilder/parsers/views/GridLayoutMetaDataParser.php' => '0e4184f03a851dcbb669dbbcbcb32a49', + './modules/ModuleBuilder/parsers/views/DeployedSubpanelImplementation.php' => '2c71bd7109457cb13c47e58a62c93272', + './modules/ModuleBuilder/parsers/views/DeployedMetaDataImplementation.php' => 'bf6dd668cd14bf4e144951464af6a866', + './modules/ModuleBuilder/parsers/views/DashletMetaDataParser.php' => '3b4e0e01a297836dcd1082a5ba8c32ea', + './modules/ModuleBuilder/parsers/views/AbstractMetaDataParser.php' => '1676f510869784d571936d48bba17a58', + './modules/ModuleBuilder/parsers/views/AbstractMetaDataImplementation.php' => '1cec425320c098a6cf3e280695ec7597', + './modules/ModuleBuilder/parsers/relationships/UndeployedRelationships.php' => '198956b7f5e0b2503f887b34ca47c520', + './modules/ModuleBuilder/parsers/relationships/RelationshipsInterface.php' => 'a3a82ab6f159ecffbe915f6ee51306cb', + './modules/ModuleBuilder/parsers/relationships/RelationshipFactory.php' => '039abce7908918481d134f8fb2bb4585', + './modules/ModuleBuilder/parsers/relationships/OneToOneRelationship.php' => '8626df0f0f5690a07eb5815b9bb765e7', + './modules/ModuleBuilder/parsers/relationships/OneToManyRelationship.php' => '76396e8d76dda04e4b907df7903a6a95', + './modules/ModuleBuilder/parsers/relationships/ManyToOneRelationship.php' => '41d2a9d5654fd04996e24e34d237e4b6', + './modules/ModuleBuilder/parsers/relationships/ManyToManyRelationship.php' => 'c585937c42e7f7d3922f5a79d98b3e88', + './modules/ModuleBuilder/parsers/relationships/DeployedRelationships.php' => '0541d0eefaba34110ca17fa25d2f5f37', + './modules/ModuleBuilder/parsers/relationships/ActivitiesRelationship.php' => '7fbd2c704593caf04aa9931c8cfe51b9', + './modules/ModuleBuilder/parsers/relationships/AbstractRelationships.php' => '22af5ffa09c436902cb68c41735cd999', + './modules/ModuleBuilder/parsers/relationships/AbstractRelationship.php' => '4c2f2157798042c7d48ff8f92c59c22d', + './modules/ModuleBuilder/parsers/parser.modifysubpanel.php' => 'fb93686dcd29da10fccd9cca776665f5', + './modules/ModuleBuilder/parsers/parser.modifylistview.php' => '12e5f85436196e5716253850bff129d9', + './modules/ModuleBuilder/parsers/parser.modifylayoutview.php' => '491f9ca2bd0dc9f0f8e671b4476b788e', + './modules/ModuleBuilder/parsers/parser.label.php' => 'a964a5c343d8cb136cd8832ec5bc5e86', + './modules/ModuleBuilder/parsers/parser.dropdown.php' => '0ef3cd0b11a27b01aa2c0f157f16b972', + './modules/ModuleBuilder/parsers/constants.php' => '878317c7a56c70704155d04d03af5990', + './modules/ModuleBuilder/parsers/StandardField.php' => 'a3c5f7fe7ff730579b881375e8e8a4de', + './modules/ModuleBuilder/parsers/ParserFactory.php' => 'f89c6c2f309d0e0f126e00ed79b58cd2', + './modules/ModuleBuilder/parsers/ModuleBuilderParser.php' => 'aaa840032d534a6f9feb5d0fe2f472ad', + './modules/ModuleBuilder/language/en_us.lang.php' => '053510ff32cbe2ec9fa439b938e304f4', + './modules/ModuleBuilder/javascript/wizardTemplate.js' => '9060030ef8eec5650ec7d47c2559aa3b', + './modules/ModuleBuilder/javascript/studiotabgroups.js' => '0f917259b698ddac0270c8a6220ffad4', + './modules/ModuleBuilder/javascript/studio2RowDD.js' => 'ee99ce0578e0505cb0a7fe4c2597141d', + './modules/ModuleBuilder/javascript/studio2PanelDD.js' => '86360bf67c978fe29aaa786a046d625f', + './modules/ModuleBuilder/javascript/studio2ListDD.js' => '6711ade762b75e9fa47c6d7cf1796c3b', + './modules/ModuleBuilder/javascript/studio2FieldDD.js' => 'e779f376e6e70d5815404581effc3cfc', + './modules/ModuleBuilder/javascript/studio2.js' => '9f36fc7bf59b444a8e36409efe1299b4', + './modules/ModuleBuilder/javascript/SimpleList.js' => '27e1aa030d4084001416b400b8fc0dae', + './modules/ModuleBuilder/javascript/ModuleBuilder.js' => '0a94445bf3c4c2a4146913dfbb35c8ce', + './modules/ModuleBuilder/javascript/JSTransaction.js' => '33c082aaee31dd249e66c6a929e66dea', + './modules/ModuleBuilder/controller.php' => '06d73ecafdf17c991f34ad8945a786ac', + './modules/ModuleBuilder/action_view_map.php' => 'd1b1c375b7ebecd14628498dcad8dbe6', + './modules/ModuleBuilder/Module/StudioTree.php' => '7aab267a0af104084a1b23c4ecab97e0', + './modules/ModuleBuilder/Module/StudioModuleFactory.php' => '864942db27c8f1414dd0da5e63ee4a82', + './modules/ModuleBuilder/Module/StudioModule.php' => 'b9e23500a786f49783889a89b161eedb', + './modules/ModuleBuilder/Module/StudioBrowser.php' => 'eef1b0c4be2ae9351cf1c7656ac28c9e', + './modules/ModuleBuilder/Module/MainTree.php' => '6152c924303fe20769cdbc48b2185913', + './modules/ModuleBuilder/Module/DropDownTree.php' => '6d733cb3e2975569079ff8b059087392', + './modules/ModuleBuilder/Module/DropDownBrowser.php' => 'b41d9d36bc5f500447f1db68bd62ce8a', + './modules/ModuleBuilder/MB/header.php' => 'c8492063d04ce650cf50ce1cdb0e0be9', + './modules/ModuleBuilder/MB/ModuleBuilder.php' => '7cb647f9f6d7ecc2271f11fff2afd166', + './modules/ModuleBuilder/MB/MBVardefs.php' => 'f4170e6c5a68c8e315863d1693fbc0ba', + './modules/ModuleBuilder/MB/MBRelationship.php' => '798e37becc33cfb9eb779b0eebf620c8', + './modules/ModuleBuilder/MB/MBPackageTree.php' => '16ec5240bb853fa7595523b1b4f9f759', + './modules/ModuleBuilder/MB/MBPackage.php' => 'e4cd835c9c6e5f03ba7cbd73ce225467', + './modules/ModuleBuilder/MB/MBModule.php' => '8866b13863363e31859883301835c378', + './modules/ModuleBuilder/MB/MBLanguage.php' => '3d19c7397e80b0a6f9ee3d5b37650966', + './modules/ModuleBuilder/MB/MBField.php' => '7d1e217fe809e63a3b4e6194ab0205dc', + './modules/ModuleBuilder/MB/AjaxCompose.php' => '5482b26bfd548f815c4fdac0668f5075', + './modules/ModuleBuilder/Forms.php' => 'e773d1cb9319008bb56c2522ab5021c4', + './modules/MergeRecords/Merge.js' => '87d60172b31ff1a67ec5bb451db58a66', + './modules/MergeRecords/vardefs.php' => '3ce697d50bfc595a8bb0241a7ca7455e', + './modules/MergeRecords/language/en_us.lang.php' => 'f00c0932118f3adb4e78e2dc2411e6b8', + './modules/MergeRecords/index.php' => '3f1c68981f5902a648a17018e24ca43a', + './modules/MergeRecords/controller.php' => '0865944914ee968c2bc1892da8940b31', + './modules/MergeRecords/Step3.php' => '729eee15723be80eb1ff81ca80201d2a', + './modules/MergeRecords/Step3.html' => '5fde8a3ec87d93058ec6045c2c012f9a', + './modules/MergeRecords/Step2.php' => 'be0020ae7d92d5e0eeeb6478f34058b0', + './modules/MergeRecords/Step2.html' => 'ccf7c2669435aa24c38921880ad863e9', + './modules/MergeRecords/Step1.php' => 'a0c5f45d20afaabb59a7d54eec167c9f', + './modules/MergeRecords/Step1.html' => '0141495f28378923446c97f24e17029f', + './modules/MergeRecords/SearchForm.html' => '11f0b679a10c34338e9758ede1e86e93', + './modules/MergeRecords/SaveMerge.php' => '9b196e0c0d3a1df0fc1748881bc72de8', + './modules/MergeRecords/MergeRecord.php' => 'a1e9378d97dd8f76b6314e5973381791', + './modules/MergeRecords/MergeField.html' => 'c00b7430a29310be7eccf3f9791634a0', + './modules/MergeRecords/Menu.php' => 'ad435ab227b7f339d340692eb81630d7', + './modules/Meetings/jsclass_scheduler.js' => 'd2cd2f86a5c7792d7dd5976c7b410477', + './modules/Meetings/action_view_map.php' => '9353afb9cdccf0e50f984924645ea51e', + './modules/Meetings/JoinExternalMeeting.php' => 'd72c9518022c7b61fc939e27c9812437', + './modules/Meetings/views/view.listbytype.php' => '3942bad99c026b8e31166be85fedd59a', + './modules/Meetings/views/view.edit.php' => 'dc124e1a3d940c169ef609916851f634', + './modules/Meetings/vardefs.php' => 'f67ecb02f108bead3a03713fc5c12258', + './modules/Meetings/tpls/extMeetingNotInvited.tpl' => 'a16fac6c2878a546b25b7b8f96db6fd7', + './modules/Meetings/tpls/extMeetingNoStart.tpl' => '8f26c8850c6c4b011169f7703a301037', + './modules/Meetings/tpls/header.tpl' => '66489a8b22323aff40e2d825ccb17a9b', + './modules/Meetings/tpls/footer.tpl' => 'c21ee3bf6df9db67b7ca95e0103ed207', + './modules/Meetings/tpls/QuickCreate.tpl' => '3059bfc6a2c0b602aec17947eed77342', + './modules/Meetings/metadata/subpanels/default.php' => '35394792be32e74f512ee190915aba45', + './modules/Meetings/metadata/subpanels/ForHistory.php' => '7f8e8880c8454608aa5c245221d1e13b', + './modules/Meetings/metadata/subpanels/ForActivities.php' => '956443c7fefc8526ea83d54cd6952309', + './modules/Meetings/metadata/subpaneldefs.php' => 'e50d977f6a64ce9f6846b4f3dcd87668', + './modules/Meetings/metadata/studio.php' => '1981fa5a4500fc8baa39805f20774581', + './modules/Meetings/metadata/searchdefs.php' => '88c16d8f11fd6069d31377b27661dbfa', + './modules/Meetings/metadata/quickcreatedefs.php' => '114fac63f776dd420fde02d967e3b67f', + './modules/Meetings/metadata/listviewdefs.php' => 'ad9666beb71a77b362266866b0d9a7ac', + './modules/Meetings/metadata/editviewdefs.php' => '9322e10ac0c22822659c7cb362b15015', + './modules/Meetings/metadata/detailviewdefs.php' => '3a24ccd7bcb969cf3a56851cd871353b', + './modules/Meetings/metadata/additionalDetails.php' => '17521ec60172b283b5f70d0530554f19', + './modules/Meetings/metadata/SearchFields.php' => 'ac6b61f3370200cbd09d80308774f41f', + './modules/Meetings/language/en_us.lang.php' => '72aa9397c10cc6dc1739c7645ba4d87f', + './modules/Meetings/field_arrays.php' => '841aa6a94d88a3ded39d98a1fca9ef1f', + './modules/Meetings/SubPanelViewInvitees.php' => '1b7e228b1f978364ef44d6c685ea8a43', + './modules/Meetings/SubPanelViewInvitees.html' => 'b326b8407ec99cf7bf729b4abb1ebdbd', + './modules/Meetings/Save.php' => '78a9978019f2574a6cb3e245d50c2271', + './modules/Meetings/Menu.php' => '1228f556ef6077e055d6a3c3c54961b2', + './modules/Meetings/MeetingsQuickCreate.php' => 'fe1af8fffc9869640fbced53801515ab', + './modules/Meetings/MeetingFormBase.php' => '0b976469ad53ec8902864c9febfb089d', + './modules/Meetings/Meeting.php' => '84eef79555d3b39b393efedcdccbaee3', + './modules/Meetings/Dashlets/MyMeetingsDashlet/MyMeetingsDashlet.php' => '2a3fa5ad5e35ee01c5cb9517dbdd4924', + './modules/Meetings/Dashlets/MyMeetingsDashlet/MyMeetingsDashlet.meta.php' => '17de05e1c0f4594e7e6fae86634c1871', + './modules/Meetings/Dashlets/MyMeetingsDashlet/MyMeetingsDashlet.data.php' => 'bf07be2a58971f99255feb513e3c4a68', + './modules/MailMerge/modules_array.php' => 'd7429db3ce45e1f3892bae3c16f7c648', + './modules/MailMerge/language/en_us.lang.php' => 'b4f2b23f8c783c30d9bd978504f71244', + './modules/MailMerge/index.php' => '83016d79c0d5339fb29cbf810f2db535', + './modules/MailMerge/get_doc.php' => 'd244583dae7a38dcdf808f6e162d382e', + './modules/MailMerge/Step5.php' => 'c5196b6ed569e3aad2ddb19e988d46c3', + './modules/MailMerge/Step5.html' => '26db7d29f0b2e0cff3916ea640192a84', + './modules/MailMerge/Step4.php' => '29241896250224de06c596cb8f8ac035', + './modules/MailMerge/Step4.html' => '56977de1515277840c4e4ad92c351bdb', + './modules/MailMerge/Step3.php' => '401bc7d3564b5e39fabdf35992b81972', + './modules/MailMerge/Step3.html' => 'eb56b14c55aeda67fa0fcbb20389972e', + './modules/MailMerge/Step2.php' => 'f9aefe6dc3ea6918799f6b702e5ef583', + './modules/MailMerge/Step2.html' => '8b7a503eec1252b74963375cd95f84db', + './modules/MailMerge/Step1.php' => '08d7c525f2d4e7c884370e7a9c537907', + './modules/MailMerge/Step1.html' => 'f931d9d6a0068e27fbfe2fd7eb1d6c1a', + './modules/MailMerge/Save.php' => '46e066bc591a9bab82b3045eeb54c01a', + './modules/MailMerge/Merge.php' => '1fb9ec1f8b2b00da9902e3285c81552a', + './modules/MailMerge/Merge.html' => '154631ef3dea42357140c9d5c2fabe92', + './modules/MailMerge/Menu.php' => 'cfc24dcc3be57f9d81154ab4a8dd5760', + './modules/MailMerge/MailMerge.php' => '8def99841e9123eb70b513e5d4f39f90', + './modules/MailMerge/EditView.php' => '8af659df9972420db817b302cdf6d2e7', + './modules/MailMerge/DetailView.php' => '75ff223c12372a4313b3de488108fef1', + './modules/Leads/Lead.js' => '8cddbfd55de6fb05ae7feaf42a68c700', + './modules/Leads/views/view.list.php' => '79cee6cbb0929820b27cacc3ae3cea68', + './modules/Leads/views/view.convertlead.php' => '1ac0edb8f44834e9235bd5229b556e03', + './modules/Leads/vardefs.php' => 'e2410b82291f154d12877b5e4e61f847', + './modules/Leads/tpls/QuickCreate.tpl' => 'a76c0c529eadb1bef44454e7c7f5ebd9', + './modules/Leads/tpls/DetailViewHeader.tpl' => 'f075c3a6effa72926e1a0f8a5cd5e6a6', + './modules/Leads/tpls/ConvertLeadHeader.tpl' => '6ca934f6a0fb7829c2df9efc1c752108', + './modules/Leads/tpls/ConvertLeadFooter.tpl' => 'a9096026969ab32e7904ca5401abd0c6', + './modules/Leads/tpls/ConvertLead.tpl' => '462df9f18bb2dbe093887ec471679707', + './modules/Leads/metadata/subpanels/default.php' => 'a9323ca8f714372b1cd48ebb97a34edd', + './modules/Leads/metadata/subpanels/ForMeetings.php' => '6cce6e61c8f9f460c98d781476821243', + './modules/Leads/metadata/subpanels/ForEmails.php' => '10b4f0e2731083e598749c4ac3915f50', + './modules/Leads/metadata/subpanels/ForCalls.php' => 'b3c3c02da24f25cce0a7cf478de67809', + './modules/Leads/metadata/subpaneldefs.php' => 'e8771108264fcc6a9c01794505f4b003', + './modules/Leads/metadata/studio.php' => '1d2702e596cf568c7705f857b207b481', + './modules/Leads/metadata/searchdefs.php' => '7839892852980e0f4f1196fd29f0b95c', + './modules/Leads/metadata/quickcreatedefs.php' => '211f03435d7664712fc459ed0d396def', + './modules/Leads/metadata/popupdefs.php' => '8bd61ecd2395b404135d6a2444d04566', + './modules/Leads/metadata/listviewdefs.php' => 'f3d23bdd5032749f94537349ff4c94f3', + './modules/Leads/metadata/editviewdefs.php' => 'ac0c2ae2f4302dff9957ee83606a4e94', + './modules/Leads/metadata/detailviewdefs.php' => '8c2dd819d9e99e5546f973c983605670', + './modules/Leads/metadata/convertdefs.php' => '5b9422be772856ad372ff43cf37d1cab', + './modules/Leads/metadata/additionalDetails.php' => '7a0e37d6e021a4c3ae185f17f9bf56c0', + './modules/Leads/metadata/SearchFields.php' => '1105a52bed12ef1761e91ad890946140', + './modules/Leads/language/en_us.lang.php' => '034728e804b4cd847563a7b688f78fa0', + './modules/Leads/field_arrays.php' => '43f3d073ac584e5347be1edcd18e269c', + './modules/Leads/controller.php' => '23f4cec6b391edf5ffa887e12120a7ad', + './modules/Leads/action_view_map.php' => '667e4d332ea94abca24d8ee7f2feeb45', + './modules/Leads/SugarFeeds/LeadFeed.php' => '9f45be730bf02e1caf63e6dd7d198bff', + './modules/Leads/SubPanelView.php' => '94f76a3cc9b66e946a6cb2eeb90b22cd', + './modules/Leads/SubPanelView.html' => 'b90b3d11c1510f8fffc44e274e1701b0', + './modules/Leads/Save.php' => '2d1e5faa00ad9ee1c6635e9a91de7463', + './modules/Leads/Popup_picker.html' => 'f2317124eeaa249b64a72e4d9ed939a5', + './modules/Leads/MyLeads.php' => '5a7f8947cfcc67c21fe07fed4bad4d0a', + './modules/Leads/MyLeads.html' => '221c652a4a6a54c53c80d95a4f8b0dfa', + './modules/Leads/Menu.php' => '9ff4db24b9e03909f7de8f0d3d89282f', + './modules/Leads/LeadsQuickCreate.php' => '07ed1970eab3cbe82f3378aa43cfa54a', + './modules/Leads/LeadFormBase.php' => 'd4ec745504b5dd5eb0d9cbff540eb38b', + './modules/Leads/Lead.php' => '761737b8018b56465224b8387b7248d3', + './modules/Leads/Dashlets/MyLeadsDashlet/MyLeadsDashlet.php' => 'd7e1e39172ab361dbfe553bad41145b5', + './modules/Leads/Dashlets/MyLeadsDashlet/MyLeadsDashlet.meta.php' => '854c043c1061766f86fad727cc3f8b82', + './modules/Leads/Dashlets/MyLeadsDashlet/MyLeadsDashlet.data.php' => 'd9d36456f7df31eec9941743f4a5b740', + './modules/Leads/Capture.php' => '243892d927a146c5873c985f7d675105', + './modules/LabelEditor/language/en_us.lang.php' => '0dd99b6b8d7a0fddb04ce49bc2d2e01a', + './modules/LabelEditor/Save.php' => 'b33e2d79bf8f5a009c59beec2d43c0a4', + './modules/LabelEditor/Menu.php' => 'afc3a627ab78a69c58b586095e79864a', + './modules/LabelEditor/LabelList.php' => 'f23746d552d021ad5a19d2fb3d226f3d', + './modules/LabelEditor/Forms.php' => 'fbafcea6235be8a109124d1870e5c76d', + './modules/LabelEditor/EditView.php' => '2eeb9a92ec8f14e4ecb1587aa59c3ff5', + './modules/LabelEditor/EditView.html' => 'd26998cd92945e931f4207509bd8444f', + './modules/InboundEmail/InboundEmail.js' => '40dcced2eee76088930804d810e19eb4', + './modules/InboundEmail/vardefs.php' => 'b502ad0ed0fbd0756c8dbfea8e6f0c3b', + './modules/InboundEmail/language/en_us.lang.php' => '6efdc5c47a673ba196569159bb1da72f', + './modules/InboundEmail/index.php' => '8b465dd0e7055136f21eaddba390a92f', + './modules/InboundEmail/field_arrays.php' => 'a4337fd64c1ff5c5a78d6c3d1dda4960', + './modules/InboundEmail/View.html' => '58f26da62e64f0630806e6dde187a357', + './modules/InboundEmail/ShowInboundFoldersList.php' => '45d7e8bfbff96456cb27a9f1ef3eea3c', + './modules/InboundEmail/SaveGroupFolder.php' => 'b25cf3f6fae0a6220773c43966dfccdc', + './modules/InboundEmail/Save.php' => 'd1fa0cd35ffbb8b3e17687ee2225dde9', + './modules/InboundEmail/Popup.php' => 'dae5482f102fb7cbbcedd46b2cf6a550', + './modules/InboundEmail/Menu.php' => '79c0619ae84aa23303de599889406019', + './modules/InboundEmail/ListView.php' => '693d6cb94dede156a0ddf15b031ff031', + './modules/InboundEmail/ListView.html' => 'd198339eed60a1f901c0082646ac3707', + './modules/InboundEmail/InboundEmailTest.php' => '18e54a84dd10ebbdb875c4a0c2887bc9', + './modules/InboundEmail/InboundEmail.php' => '2f8914619fa8d6e4f1208dffd2f72be2', + './modules/InboundEmail/EditView.php' => '97e92df283f59d8beeafabe686c65a3e', + './modules/InboundEmail/EditView.html' => 'ae48de7b568c54f7891f5751651059d6', + './modules/InboundEmail/EditGroupFolder.php' => '52d841e00eeb5d43c736de0adbc5293f', + './modules/InboundEmail/DetailView.php' => '90c04ee9076496043b423a96ae44d155', + './modules/InboundEmail/DetailView.html' => 'c26f51c1f5b4d301c56e773de896758d', + './modules/InboundEmail/Delete.php' => '783bea5996b38be48d88bef0edf1189c', + './modules/Import/views/view.undo.php' => '57d944180c9f39b54a7a435fa2095154', + './modules/Import/views/view.step4.php' => 'b6022b98fe0d660c6bb842e8525097c6', + './modules/Import/views/view.step3.php' => 'afc16e641c2e311a1b1e6d800c14f3de', + './modules/Import/views/view.step2.php' => '942f30486caf79d52ae3e86af9c8f7a9', + './modules/Import/views/view.step1.php' => '9e56c783069b59b6513b0fccbc48fc40', + './modules/Import/views/view.last.php' => 'e3499c1f445cbae2ec6ec326ce8dafe8', + './modules/Import/views/view.error.php' => 'c19b5de391cdd9f4106ae85b9e0f4d51', + './modules/Import/vardefs.php' => 'f386f7b3e194e8c0b6175b60671b4f11', + './modules/Import/tpls/undo.tpl' => '07c0a5ae1d14facd9cb291f1d1c19f87', + './modules/Import/tpls/step3.tpl' => '821dd850badcf325d7f817ec164919df', + './modules/Import/tpls/step2.tpl' => '79a84e8cb8caafc13d4636c6d5230914', + './modules/Import/tpls/step1.tpl' => 'd5be2d2396844d8e542a5be53b0cafb9', + './modules/Import/tpls/last.tpl' => 'cd2f76b2e8991cacaa7cb6504360e67d', + './modules/Import/tpls/error.tpl' => '4c561e896c8cf26a72f934fc83b08ab6', + './modules/Import/language/en_us.lang.php' => '83f1561638750f5f5f9c4e773aa86cf7', + './modules/Import/controller.php' => 'e81e3c248c0f2533bc3a30bae4adda96', + './modules/Import/UsersLastImport.php' => '9537110142dab755d1536ef0e438df91', + './modules/Import/Menu.php' => '4231e11718ef59bbaca20b46ea195950', + './modules/Import/ImportMapTab.php' => 'c34339dd1b1c691ad605f7b2316c56e6', + './modules/Import/ImportMapSalesforce.php' => '539a104896e214c018c8c81669236220', + './modules/Import/ImportMapOutlook.php' => '606cf0efd7a8c98e8e8fdfcaa5a7acd2', + './modules/Import/ImportMapOther.php' => 'fe11a14b72acbe9cde4511c5d7e4a09e', + './modules/Import/ImportMapCsv.php' => '448d8931c85cacc4179120c2a20c4bc7', + './modules/Import/ImportMapAct.php' => '78df0dfb26f4c89dd23eda4329917d70', + './modules/Import/ImportMap.php' => '8c3c3445cd1109331517d0f2be193c35', + './modules/Import/ImportFileSplitter.php' => 'ff77217515cea4fe6bef98f72efbca20', + './modules/Import/ImportFile.php' => '1e67c950bc97e690c4c39dc58f3694ad', + './modules/Import/ImportFieldSanitize.php' => 'ef42108beab1cae966874ee9d12b9e70', + './modules/Import/ImportDuplicateCheck.php' => 'ffa9c7513f3ad00c70645e86ef686264', + './modules/Import/ImportCacheFiles.php' => '7ccd3d16e86f7e244afa2c3ec79d6585', + './modules/Import/Forms.php' => 'aa21c1468d24d31d1c1a8c2071acb940', + './modules/Home/about.js' => 'd15c260b194de31361e331b841bff4fc', + './modules/Home/action_view_map.php' => '0fb6609851be65b5c71cb78738cddfda', + './modules/Home/views/view.additionaldetailsretrieve.php' => '4c1b017c7466a4d08e2fca1b5210e5a7', + './modules/Home/views/view.modulelistmenu.php' => '53cad4dd9a279abd1f93be32d4c2249a', + './modules/Home/views/view.list.php' => '24f2acac32fc46bba2b65617f742021b', + './modules/Home/sitemap.tpl' => '0aaf71c46029f50c65cfc40244f4c123', + './modules/Home/sitemap.php' => 'dc0b3803d35cd2a5dafb7ab98dd881b1', + './modules/Home/quicksearchQuery.php' => '7b3025ec8d69ab7e770a187f02d0f020', + './modules/Home/language/en_us.lang.php' => 'a412cb38ef330fac398279e30352fe42', + './modules/Home/dashlets.php' => '3336d96f1a154c5e8bb4486666d1e343', + './modules/Home/UnifiedSearchAdvancedResults.tpl' => 'ece94de0e868fd044c148642e5b821d0', + './modules/Home/UnifiedSearchAdvancedForm.tpl' => '3afe71c2a3ab906e6d832a909b8a4f73', + './modules/Home/index.php' => '65bacfb3bc4d126ebabe55e645f8a193', + './modules/Home/UnifiedSearchAdvanced.tpl' => '5133d64ca90bb45329fcb9fa8bad2e01', + './modules/Home/UnifiedSearchAdvanced.php' => '94d5fb5eede6e6fd92334d7c71bdbff1', + './modules/Home/TrainingPortal.tpl' => '0049d2a11e2aa770d91965fa140490e6', + './modules/Home/TrainingPortal.php' => '355a092e948ab2740e8b63ecacd8110d', + './modules/Home/UnifiedSearch.php' => '8b1fd77832d3067cb6bd5c64296928e5', + './modules/Home/SaveSubpanelLayout.php' => 'e338069c63a8aad2c3c27ed0dda7611e', + './modules/Home/PopupSugar.php' => 'f95d5b92fb0d367436d09f9a235dda3d', + './modules/Home/Menu.php' => '3fa23b2242e96d9891d841b336f351f5', + './modules/Home/LastViewed.php' => 'c59382fac20f91b5081513da98827ad3', + './modules/Home/Home.tpl' => '22ea7307a163b643d2fdc57833bed091', + './modules/Home/Home.html' => '1cfd71deea974236ad79b5a59a39ac96', + './modules/Home/DynamicAction.php' => '8de09f545e517b5a91039b605898627e', + './modules/Home/Dashlets/iFrameDashlet/iFrameDashlet.php' => '093c0b3886c49e37d542936e4fb3f325', + './modules/Home/Dashlets/iFrameDashlet/iFrameDashlet.meta.php' => '4227913d52f981f847c48e63e71b2d07', + './modules/Home/Dashlets/iFrameDashlet/configure.tpl' => 'af2e87f986e73938a4df665c3baa219f', + './modules/Home/Dashlets/SugarNewsDashlet/configure.tpl' => 'af2e87f986e73938a4df665c3baa219f', + './modules/Home/Dashlets/SugarNewsDashlet/SugarNewsDashlet.php' => 'a9bf3c4562700024d4089f87a0d5000c', + './modules/Home/Dashlets/SugarNewsDashlet/SugarNewsDashlet.meta.php' => 'c61db581e2b16a9ae9459091a494c921', + './modules/Home/Dashlets/RSSDashlet/RSSDashletOptions.tpl' => 'd0077fe1045f2468f91b81a4f8e6435d', + './modules/Home/Dashlets/RSSDashlet/RSSDashlet.tpl' => '6736755324f99b169fd55cfb5186a039', + './modules/Home/Dashlets/RSSDashlet/RSSDashlet.php' => '01b329ff8f38eaef94475e176cf0d3d0', + './modules/Home/Dashlets/RSSDashlet/RSSDashlet.meta.php' => '2868db4815ce439503871be342c6aaba', + './modules/Home/Dashlets/RSSDashlet/RSSDashlet.icon.jpg' => '7b0cb2ec97ce8e71d74d60a0da81ba53', + './modules/Home/Dashlets/RSSDashlet/RSSDashlet.en_us.lang.php' => 'ec24eac2fde553b6a7190b0ac40b9068', + './modules/Home/Dashlets/JotPadDashlet/JotPadDashletScript.tpl' => '44fe1cc9a5d2fc4d43207d37d9facba9', + './modules/Home/Dashlets/JotPadDashlet/JotPadDashletOptions.tpl' => '3dec6d95f5b5297b9f184e2be3afb8fe', + './modules/Home/Dashlets/JotPadDashlet/JotPadDashlet.tpl' => '99b1f580406b7aa128719886b73e64e8', + './modules/Home/Dashlets/JotPadDashlet/JotPadDashlet.php' => 'c2d3c87ddfae95bd4bbfc80d0a3f43a1', + './modules/Home/Dashlets/JotPadDashlet/JotPadDashlet.meta.php' => 'f684f24e9455ff722136faf5ec2ce552', + './modules/Home/Dashlets/JotPadDashlet/JotPadDashlet.en_us.lang.php' => '05b9d95822105ffd36ffb87c09b94ef7', + './modules/Home/Dashlets/InvadersDashlet/sprites/player.png' => 'e5cac3126e8afc4a33374c12651669ab', + './modules/Home/Dashlets/InvadersDashlet/sprites/cube.png' => '2e8e87c58816e987578025e21a19c3e7', + './modules/Home/Dashlets/InvadersDashlet/sprites/bg.png' => 'cd531b08b65ec6ed046d182122d54b3a', + './modules/Home/Dashlets/InvadersDashlet/sprites/alien.png' => '30696cdec3d5ae84a3150d426cea9d12', + './modules/Home/Dashlets/InvadersDashlet/InvadersOptions.tpl' => '9d3147b44f9f89b4499391e00db3d3d2', + './modules/Home/Dashlets/InvadersDashlet/InvadersDashletScript.tpl' => '67f59f04e3458dacb3cac344841e6296', + './modules/Home/Dashlets/InvadersDashlet/InvadersDashlet.tpl' => '7874271cdf42994f3043a00dce93c446', + './modules/Home/Dashlets/InvadersDashlet/InvadersDashlet.php' => '54619be90827d7aa860a4af530856f9d', + './modules/Home/Dashlets/InvadersDashlet/InvadersDashlet.meta.php' => '4dfe49727e4a60650b8b23d39dd6460c', + './modules/Home/Dashlets/InvadersDashlet/InvadersDashlet.icon.jpg' => '7b0cb2ec97ce8e71d74d60a0da81ba53', + './modules/Home/Dashlets/InvadersDashlet/InvadersDashlet.en_us.lang.php' => '55dfa5c7a2a87a8c07a823a739defa9e', + './modules/Home/Dashlets/ChartsDashlet/ChartsDashletScript.tpl' => 'dd411a07bad4a9ff68676d92bccf8235', + './modules/Home/Dashlets/ChartsDashlet/ChartsDashlet.php' => '24a3ca162a3be8d9dbbdd950c9756a19', + './modules/Home/Dashlets/ChartsDashlet/ChartsDashlet.meta.php' => 'b63a2caee0d5d33921fab2017e0dc61d', + './modules/Home/Dashlets/ChartsDashlet/ChartsDashlet.en_us.lang.php' => 'a17865b601f0870d5e864f76839a47ee', + './modules/Home/SubpanelCreates.php' => 'b65d7d8997f074f8b981a3888ac76d81', + './modules/Home/AddToFavorites.php' => '4e113ab3ea13a302ce66e89a4ecce74d', + './modules/Home/About.php' => 'c799b63f8d13901a079d553ffe6df17e', + './modules/History/metadata/subpaneldefs.php' => 'f3986a34f5d8bb4a79b44903c3598144', + './modules/History/language/en_us.lang.php' => '0daa27d2314c4abfed502f3cb5234cc7', + './modules/Help/language/en_us.lang.php' => '344bf51c077fc8fdffe33f5fd238be25', + './modules/Help/index.php' => '8001cc9a2eaac900eeb07f528b7a64e9', + './modules/Help/Menu.php' => '5d40b90cb2c96497c439b5ab1d1a1242', + './modules/Groups/vardefs.php' => '3d78ea13abcc58a854ecb205320afc77', + './modules/Groups/language/en_us.lang.php' => 'a234b6d219d2f793b60f50ddb7590587', + './modules/Groups/index.php' => '2cef162dc968cd4475d1bcabc3d047a7', + './modules/Groups/Save.php' => 'bcdd33e478e3d6221fc4da3d4fb7dc5d', + './modules/Groups/Menu.php' => '4c44bf811052dcac45902c161b49257a', + './modules/Groups/ListView.php' => '0acdda7db7d88ed6fd8572cde7f811d6', + './modules/Groups/ListView.html' => 'c94c29c0800a97cf7bf85aaff058b8f2', + './modules/Groups/Group.php' => '3c9c86fda7e9f7fcfd2e1e1d2224cf3f', + './modules/Groups/Forms.php' => '3d78ea13abcc58a854ecb205320afc77', + './modules/Groups/EditView.php' => '4aafca0e9a90ea125b2e481a1d20f394', + './modules/Groups/EditView.html' => '5aa0ae8440621955c98ac8c973021f2e', + './modules/Groups/DetailView.php' => '2fb58d8e395a508e6acad046b4068c2c', + './modules/Groups/DetailView.html' => '9dab041fc1be503de6769ea70911cba5', + './modules/Groups/Delete.php' => '6766206f16b826890facdfc4be15e92c', + './modules/Employees/views/view.list.php' => 'e15d1d43c1d43b3cb62743447e260e6d', + './modules/Employees/views/view.edit.php' => 'd3e44391b0f1abe2c37716004a28e1ad', + './modules/Employees/views/view.detail.php' => 'b360b199402973c454b791bcf4034b35', + './modules/Employees/vardefs.php' => '8479de606f3beb25e119178b5b46e646', + './modules/Employees/metadata/searchdefs.php' => '1340db5e164cece39b1470a2a0a9c778', + './modules/Employees/metadata/listviewdefs.php' => '874253a6f56c264596721353f8cc5e3b', + './modules/Employees/metadata/editviewdefs.php' => 'c5f55fa972ce09fbd845ff49af6b04b2', + './modules/Employees/metadata/detailviewdefs.php' => '929da865fd722196b482d18a20e4fe77', + './modules/Employees/metadata/SearchFields.php' => 'fb28c93f3ebafbf436d4ca2e3e746200', + './modules/Employees/language/en_us.lang.php' => '2ce4ae0dddca70df365b0e7fc9cc5365', + './modules/Employees/field_arrays.php' => 'c20bc0f73165e17d3b7683966ab81181', + './modules/Employees/controller.php' => '1e78e15e871835524a935d1d131fb73e', + './modules/Employees/WapMenu.php' => '3e2aa5ebfe0cadb963b254b89edbea6f', + './modules/Employees/WapAuthenticate.php' => '0884c8b0884ef63b2cdfa9752ff4368d', + './modules/Employees/Popup_picker.php' => '09ef8ea00509c554cfdee141283b66f3', + './modules/Employees/Popup_picker.html' => '92f9604067d1279e038c64e52f3a0ae4', + './modules/Employees/Menu.php' => 'f18a2a7887a5ef61b1feeb7deb894556', + './modules/Employees/Forms.php' => '9ed5ba9fb7e1e06adf0346c68f23361c', + './modules/Employees/Error.php' => 'c651b08c57c2b78dfa68520822cc6bc1', + './modules/Employees/Save.php' => '1a61bfa66090a2d66b6a0abc9f334c72', + './modules/Employees/Employee.php' => 'fdad9e9d9766399e8a7048f0e77b0bb2', + './modules/Emails/views/view.quickcreate.php' => '58e2115f8d2a69f4afc2a04976fac02b', + './modules/Emails/views/view.modulelistmenu.php' => 'e9ca39c1e0e3abc394b1a9dad2804ebd', + './modules/Emails/views/view.classic.config.php' => 'bfb5df976e677f3b7ea82de5b403e2e4', + './modules/Emails/vardefs.php' => '49943485f43e7102d02842430c513b59', + './modules/Emails/templates/successMessage.tpl' => 'f2a5b761c0f480ded16d358e0e650ae4', + './modules/Emails/templates/overlay.tpl' => '064c362704b97dd6f41ba062d16f2552', + './modules/Emails/templates/outboundDialogTest.tpl' => 'db35198ac6efcdb06604504a5e3fd5cb', + './modules/Emails/templates/outboundDialog.tpl' => '910c40e39314d9035af1c41746fedd0c', + './modules/Emails/templates/importRelate.tpl' => 'b3897fb62f70b64c9fc202320e176a8b', + './modules/Emails/templates/emailSettingsRules.tpl' => '6fe8b27d9e161596113223f607b13c80', + './modules/Emails/templates/emailSettingsGeneral.tpl' => '3563cc551b3103b1b50244843c121dfd', + './modules/Emails/templates/emailSettingsFolders.tpl' => '651283dc3f1a228aa989c416127d8b2f', + './modules/Emails/templates/emailSettingsAccounts.tpl' => '45883d0df275997a0d353a0b0d91b6e1', + './modules/Emails/templates/emailSettingsAccountDetails.tpl' => 'b81fe2355184a51c9f3f4987d95c065e', + './modules/Emails/templates/emailSettings.tpl' => '7dfced6223a7c43cb6827504b86eb341', + './modules/Emails/templates/emailDetailView.tpl' => 'f3c6f5cc2a662f08da043caca50e16c4', + './modules/Emails/templates/editMailingList.tpl' => 'b4fb8c08aa00f663ffd01d51525be2fa', + './modules/Emails/templates/editContact.tpl' => 'da032deef1d61f195ffe396292384aa3', + './modules/Emails/templates/editAccountDialogue.tpl' => '8296045e10b01f885218bd15349ceb1c', + './modules/Emails/templates/dceMenuQuickCreate.tpl' => 'e954a3bd597aa2fe455c9048acf822d8', + './modules/Emails/templates/assignTo.tpl' => '79446b8acf76f9440bdcee11787a37d2', + './modules/Emails/templates/advancedSearch.tpl' => 'ba3419272ea3549ed31ee7e84470b64a', + './modules/Emails/templates/addressSearchContent.tpl' => '742860f9399e347935682184334ea250', + './modules/Emails/templates/addressSearch.tpl' => 'a51678c98ec0d8962f0376c241d439e1', + './modules/Emails/templates/addressBook.tpl' => 'd97ea06ba14fa80442685621698cd467', + './modules/Emails/templates/_createGroupFolder.tpl' => '909a49586dd69be9f465e753ec0b9f7e', + './modules/Emails/templates/_blank.html' => 'e629bac7136292395f2a281da41c68e2', + './modules/Emails/templates/_baseJsVars.tpl' => '70f2e0a7e263630e3389cdb1c24f7983', + './modules/Emails/templates/_baseEmail.tpl' => '06f33256be4041305df49164b78afa36', + './modules/Emails/templates/_baseConfigData.tpl' => '49a2fa95eaa4599a8e5bd9d4774d760c', + './modules/Emails/subpanels/ForUsers.php' => '3f1cb8aa8dc7407fd9e98575d4d9c65e', + './modules/Emails/subpanels/ForQueues.php' => '0b9d30578ba6ab100603332f15c333eb', + './modules/Emails/subpanels/ForHistory.php' => 'c646947f0bd46cfbee6554b6caea8c3e', + './modules/Emails/subpanels/ForContacts.php' => '125bee776e196e52371122f9abfcdde3', + './modules/Emails/metadata/qcmodulesdefs.php' => '81404f499637aa9c798863361f4720c5', + './modules/Emails/metadata/subpanels/ForUsers.php' => '3f1cb8aa8dc7407fd9e98575d4d9c65e', + './modules/Emails/metadata/subpanels/ForUnlinkedEmailHistory.php' => 'e50fbe692c61e34002ce0a3d37267f9b', + './modules/Emails/metadata/subpanels/ForQueues.php' => '0b9d30578ba6ab100603332f15c333eb', + './modules/Emails/metadata/subpanels/ForHistory.php' => '7559b8ed8cddd188da8b341d7b045fe3', + './modules/Emails/metadata/subpanels/ForContacts.php' => '125bee776e196e52371122f9abfcdde3', + './modules/Emails/metadata/subpaneldefs.php' => 'c36b83707f89bb561749d97fa5dafb6b', + './modules/Emails/metadata/popupdefs.php' => '0275329aead4baf66320f834ed573115', + './modules/Emails/metadata/additionalDetails.php' => '31f34aadd311817bb2d43c0acb85b452', + './modules/Emails/language/en_us.lang.php' => 'edb317cb70b160089640bf448aa38c7a', + './modules/Emails/javascript/viewPrintable.js' => '5aab03393cdc54f2dd875441953c33fc', + './modules/Emails/javascript/vars.js' => 'f33408357602a43c032aa90d7c751ee3', + './modules/Emails/javascript/init.js' => '1499225ea83f183744425213102bd030', + './modules/Emails/javascript/grid.js' => 'd14d32123de014fabb7ad605883f4339', + './modules/Emails/javascript/email_popup_helper.js' => 'd554d0576666510cd702a418e1fe47ae', + './modules/Emails/javascript/displayOneEmailTemplate.js' => '36286f4d5dfa7b3ecb989eaa1347fc74', + './modules/Emails/javascript/composeEmailTemplate.js' => '1d3a616e3192d976bc3dec881ec9e0e2', + './modules/Emails/javascript/complexLayout.js' => '05a5609d5457d093993b06cac8fbc145', + './modules/Emails/javascript/ajax.js' => '9ef0d1b8d475f971c0e14f773343c246', + './modules/Emails/javascript/EmailUIShared.js' => 'a7be59721553f5754aa4a5b1ca719c08', + './modules/Emails/javascript/EmailUICompose.js' => '0c49c07f04baeac647dbbadb45a5f81b', + './modules/Emails/javascript/EmailUI.js' => 'b4d2307e6918292281961860bcdf5cff', + './modules/Emails/javascript/Email.js' => '9c505070f1ff470ab07ab79374a15cbd', + './modules/Emails/index.php' => '6cc6a189db79619fe86fe1469e9ff7d3', + './modules/Emails/images/sugarGroup.gif' => 'ad21210176b6a2a10a7a9b8f876ad83b', + './modules/Emails/images/sugarDynamic.gif' => '82285d963771975b2def7f19e6438a8c', + './modules/Emails/images/sugar.gif' => '7596d03d810578248397bd29e7d708da', + './modules/Emails/images/rowsView.gif' => 'd1e22c7c55eff098bd0d1fea1a42b289', + './modules/Emails/images/rightarrow_inline.gif' => 'd4cde743094e6e6c59d547f296456e98', + './modules/Emails/images/leftarrow_inline.gif' => '505062559e730bf5451d037be485cfc4', + './modules/Emails/images/fullscreen.gif' => '2f2d93eb81fdf22a91a2dda873eb883a', + './modules/Emails/images/emailGroup.gif' => 'b2acc4673f0eec0fd3f74d9c972bec42', + './modules/Emails/images/email.gif' => '359e9214dc577e10de38d286a30a5113', + './modules/Emails/images/colsView.gif' => '05a47212195473198ec86bc7cc152730', + './modules/Emails/images/autofit.gif' => '3c3e9c06b10b0ea41d89edef7c0b947e', + './modules/Emails/field_arrays.php' => '2abd13368de95a97236118469af2cf14', + './modules/Emails/SugarRoutingAsync.php' => '1a0be585c1d2bee11481b0e241a2a63c', + './modules/Emails/SubPanelViewRecipients.php' => '732be5c347a5817672a6489ee90d5e89', + './modules/Emails/SubPanelViewRecipients.html' => 'f07c4e81fa6c04a47fd45d727c4ea751', + './modules/Emails/Status.php' => 'bcb357445138451929653364e7ae07c5', + './modules/Emails/Status.html' => '1801ca32d3646ee0c98306f604919607', + './modules/Emails/SearchFormSent.html' => '5b9f23633463ed27da895b70a17725e4', + './modules/Emails/SearchFormMyInbox.html' => 'c339d9af64cfe5d63148f1f639730dad', + './modules/Emails/SearchFormGroupInbox.html' => 'cc514802ad41c7c2a39651bbfc4c672f', + './modules/Emails/SearchForm.html' => 'cf30409165e6f78d6341281e8de9845c', + './modules/Emails/Save.php' => 'fae1087bee2de233cb78d82833e1a2f6', + './modules/Emails/Popup_picker.php' => 'f7a97994261d17eef56d3909bd046efa', + './modules/Emails/Popup_picker.html' => 'b64e7ed7ebea9b23d3a2becb000efacb', + './modules/Emails/PopupDocuments.php' => '5b833ead51454c4200f744890d271bae', + './modules/Emails/PopupDocuments.html' => '2dc8dd008819e903f069a7c8fd5ba51f', + './modules/Emails/Popup.php' => 'b9d8fd64d2ebf2b89fdb65df7ae65d23', + './modules/Emails/PessimisticLock.php' => '5b25ed2ea1f768ace3381178c57b39d1', + './modules/Emails/Menu.php' => '0f68402e34f3e4c64869216b208851c7', + './modules/Emails/MassDelete.php' => 'cc57671b3dc0adcdc83cf8e192056fb2', + './modules/Emails/ListViewSent.html' => '01160346dead8739eb4ed9def4bad364', + './modules/Emails/ListViewMyInbox.html' => 'f02418a857d211e4902052188e94bd0c', + './modules/Emails/ListViewHome.php' => '6cae8e0431e69db98940d4cc5f717ded', + './modules/Emails/ListViewHome.html' => '171e189b1ab65677602f2e3d43c77901', + './modules/Emails/ListViewGroupInbox.html' => '7069de21f85a2596a8bf3b4ddea21448', + './modules/Emails/ListViewGroup.php' => '35787a4cf90680cc47634e073225be41', + './modules/Emails/ListViewDrafts.html' => '67e8857521daaf70fc1468a363d9ec3f', + './modules/Emails/Grab.php' => '95a6e008baa1cdeebbf72a74bf72db68', + './modules/Emails/GenerateQuickComposeFrame.php' => '0c9dbc7d32d522b624198d21f57f6338', + './modules/Emails/EmailUIAjax.php' => '1a07741d81c08b0b7ab4173ac56a6669', + './modules/Emails/EmailUI.php' => 'e3149cad51065fc936964d51e140d156', + './modules/Emails/EmailUI.css' => 'daf7eb7d61e5b8777613d4f550bfa572', + './modules/Emails/Email.php' => 'edf545a223eca70ec14fddfabcc348e4', + './modules/Emails/EditViewArchive.html' => 'ad802e567b75e39a6c7885bbb8fb9fcc', + './modules/Emails/EditView.php' => '26af8ed4744f4029ac287aab737c1dc0', + './modules/Emails/EditView.html' => 'dd94b8950eeac04fb7663ba68a54440c', + './modules/Emails/DetailViewSent.html' => 'affa0cffa08a90c174a039d78230f7e1', + './modules/Emails/DetailView.php' => '6c69821e3d9e42d6af23760c707a2645', + './modules/Emails/DetailView.html' => 'ef22c46096ec2e20e74582bcc2812b64', + './modules/Emails/Delete.php' => '0b9f91d0aef5219b1be1d50592f3979f', + './modules/Emails/Dashlets/MyEmailsDashlet/MyEmailsDashlet.php' => '30bf4eeabbd41decbef1747ebc8f8b56', + './modules/Emails/Dashlets/MyEmailsDashlet/MyEmailsDashlet.meta.php' => '1d1f601cfbea07b1d59850fee27393ac', + './modules/Emails/Dashlets/MyEmailsDashlet/MyEmailsDashlet.data.php' => 'e04693eb309f98f4afb83d419d9a5f5e', + './modules/Emails/Compose.php' => 'f39afb096cf094dec08d6f7b8b079e3f', + './modules/Emails/Check.php' => '3643d7c5f3a716ac2f59ab358090badf', + './modules/EmailTemplates/EmailTemplate.js' => '41a0f2088124d487d8134fc0d522a162', + './modules/EmailTemplates/vardefs.php' => 'c1db0f25697a39b8a2e458c383aec8c8', + './modules/EmailTemplates/metadata/searchdefs.php' => 'afa314da331a40d53c5ae14c1eed1bcc', + './modules/EmailTemplates/metadata/listviewdefs.php' => 'c82edfad0756cb59915633e81a304fee', + './modules/EmailTemplates/metadata/SearchFields.php' => '210c298a3aea2b198e3aa6219026fe29', + './modules/EmailTemplates/language/en_us.lang.php' => 'bf4c44ff40160b7ae1217b2be2709905', + './modules/EmailTemplates/field_arrays.php' => '6da2acc09f343043e3e624d424aea6e9', + './modules/EmailTemplates/Save.php' => '3ef908df02a47472b47f810c1dcd6499', + './modules/EmailTemplates/PopupDocumentsCampaignTemplate.php' => '383a7ad98ff501f3d5e408a1a0ca5d7a', + './modules/EmailTemplates/PopupDocumentsCampaignTemplate.html' => '042f740f594f4ff5b463bc8ad258fe6c', + './modules/EmailTemplates/Menu.php' => '75d3b7fadc146b1bf2fd0b465a2099f1', + './modules/EmailTemplates/EmailTemplateFormBase.php' => '78c467f8ae5ac646d95ec93e4c6a3526', + './modules/EmailTemplates/EmailTemplate.php' => 'c556a2a2fec319201b500e2318e6a8fc', + './modules/EmailTemplates/EditViewMain.html' => '198347cfe799371733dcc1929c5b0f07', + './modules/EmailTemplates/EditView.php' => '3893991b1768f0aef3a95f9870f1c4df', + './modules/EmailTemplates/EditView.html' => '7f83285c5c1b9763a4f085d3e83ea6c8', + './modules/EmailTemplates/DetailView.php' => '2d6718ce402a490aaf5b3b856bc0a9c1', + './modules/EmailTemplates/DetailView.html' => '4e07f3f529aa4dd7aa17ccc0f635700b', + './modules/EmailTemplates/Delete.php' => 'd26b04de325778d192333d1b4d1be8ce', + './modules/EmailTemplates/CheckDeletable.php' => '613ca7e81baf06d12df1117363b76b24', + './modules/EmailTemplates/AttachFiles.php' => '6d997841491bd058bfaaea67f2c6baf8', + './modules/EmailMarketing/vardefs.php' => '3db38c851ee5b051461860f05d2754f4', + './modules/EmailMarketing/subpanels/default.php' => '05cba11a3fc14ecd377696301a9c0a35', + './modules/EmailMarketing/metadata/subpanels/default.php' => '69c9b30a0a5cd2e74d719db0164958e1', + './modules/EmailMarketing/metadata/subpaneldefs.php' => 'b8d167fcfbe7d88635939a394535cd46', + './modules/EmailMarketing/language/en_us.lang.php' => '477217ffccc85950b9f26ee82ecb914d', + './modules/EmailMarketing/field_arrays.php' => '726e7f9319b1753ee3a82c5e2ad966ea', + './modules/EmailMarketing/SubPanelView.php' => '9af7ad5c01b8ea8b09f8e572c459f9f7', + './modules/EmailMarketing/SubPanelView.html' => 'f0fbf5a76a52153e15456438ea6022e2', + './modules/EmailMarketing/Save.php' => 'b9fdcfb143d84fb5c5b8e6e3fc5d4cf0', + './modules/EmailMarketing/Menu.php' => '22676bda0f00f43d9aa328268026869a', + './modules/EmailMarketing/Forms.php' => 'b1b36a92909246484fea795acb03d363', + './modules/EmailMarketing/EmailMarketing.php' => '6684471a20ef6dfa07aaa9ba755a5bff', + './modules/EmailMarketing/EditView.php' => '1db6cc5c64860de04a1d5b0bed3e5f2b', + './modules/EmailMarketing/EditView.html' => '91cf42cad9202f2062af36934049c8d5', + './modules/EmailMarketing/DetailView.php' => 'd070fb2de3d73129261c0a877e12e406', + './modules/EmailMarketing/DetailView.html' => '7b65b4ff73fb5e80a0dc6f9e7d78b932', + './modules/EmailMarketing/Delete.php' => '3c915ebc36fe5bbb3b785211465c0899', + './modules/EmailMan/views/view.list.php' => '6d4902b6cf464c45ef6b7b368b450136', + './modules/EmailMan/views/view.config.php' => '6aab29db0bb8706f46a523003dd943a0', + './modules/EmailMan/views/view.campaignconfig.php' => '35d5be99f58836dbf2ded6d05189911f', + './modules/EmailMan/vardefs.php' => '11ea605c45446d341bd8590c2455340e', + './modules/EmailMan/tpls/config.tpl' => 'cf708f8e63b0ac2e1f6885d165f06748', + './modules/EmailMan/tpls/campaignconfig.tpl' => '1374e1451a901d40270fedc86ecd942f', + './modules/EmailMan/testOutboundEmail.php' => 'f426713a1bee0bda8ee5e623094e62ce', + './modules/EmailMan/subpanels/default.php' => 'a5bfe693b6607b29e6a7eedf0ae018d1', + './modules/EmailMan/metadata/subpanels/default.php' => 'a5bfe693b6607b29e6a7eedf0ae018d1', + './modules/EmailMan/metadata/searchdefs.php' => 'b03aec4d6d6af23ddac8788394f34367', + './modules/EmailMan/metadata/listviewdefs.php' => '00a5290dd11f4d2e12ff80df3e975191', + './modules/EmailMan/metadata/SearchFields.php' => '3366b325da4e03e28df43c1ec6864fab', + './modules/EmailMan/language/en_us.lang.php' => '729f9dc0d3d90be0fadd3225b3894550', + './modules/EmailMan/field_arrays.php' => '89e4e98aa8bf3c3f00b74d175e17be44', + './modules/EmailMan/action_view_map.php' => '137158647e55f119ece5ef3106e08bd9', + './modules/EmailMan/Save.php' => '53866932041c1e0b684e61813ee19b3f', + './modules/EmailMan/Menu.php' => '935f5e5e9940e2b115c0862dff26e96a', + './modules/EmailMan/Forms.php' => '712377fd87dd4176905b4b927fe39cbd', + './modules/EmailMan/EmailManDelivery.php' => '46d4d9c43c6f97251f54646d9b3fbc63', + './modules/EmailMan/EmailMan.php' => '95934f08c69cc52b3259152b0f5781cc', + './modules/EmailAddresses/vardefs.php' => '8464b804f5be7f2e7ab271babb910ed7', + './modules/EmailAddresses/language/en_us.lang.php' => '682d246e21989b838797f677b0517fda', + './modules/EmailAddresses/EmailAddress.php' => '9c55bd8a741f19c7048d2fb1f28b11f1', + './modules/DynamicFields/vardefs.php' => '1940251900df925de38b31049bb5fb3c', + './modules/DynamicFields/templates/Files/EditView.php' => '96c1b1ae2d80412e5f9d9b8881c9c9fa', + './modules/DynamicFields/templates/Files/DetailView.php' => '1049de42d76a8d790b31ab2156cd49b3', + './modules/DynamicFields/templates/Fields/TemplateRange.php' => 'c6f10b2314ac8ac1c11741a481c35388', + './modules/DynamicFields/templates/Fields/TemplateURL.php' => 'e916b152a08645abf170f7848670a667', + './modules/DynamicFields/templates/Fields/TemplateTextArea.php' => 'a44b7ca6cb1e9bf6a441abe6025412c3', + './modules/DynamicFields/templates/Fields/TemplateText.php' => '4a19bab77eb7427451c1ed5a10aeb43c', + './modules/DynamicFields/templates/Fields/TemplateRelatedTextField.php' => 'a865d9b0d83eb33186d53cd077f49e0c', + './modules/DynamicFields/templates/Fields/TemplateRadioEnum.php' => '6b8f1c4a074f726e7c19ca1664c6ba69', + './modules/DynamicFields/templates/Fields/TemplatePhone.php' => '3222ca1ab2170b5221c6b71dc6024b24', + './modules/DynamicFields/templates/Fields/TemplateParentType.php' => '968bd9527d214ed6e9ff6d02c675fd3b', + './modules/DynamicFields/templates/Fields/TemplateParent.php' => '52bac9df03d7b11cd4007a651db97d54', + './modules/DynamicFields/templates/Fields/TemplateMultiEnum.php' => '3bac9768ea7855733e163ca6962d5480', + './modules/DynamicFields/templates/Fields/TemplateInt.php' => 'a776d6dc3ae3316530134413c8643e78', + './modules/DynamicFields/templates/Fields/TemplateImage.php' => '804aee08f3169fa2f33a8889b8ba3692', + './modules/DynamicFields/templates/Fields/TemplateId.php' => '64616dede55f5f1fa8cc9e0a48b5c02a', + './modules/DynamicFields/templates/Fields/TemplateIFrame.php' => '86e361840afad1c98ec7565ce5e5146d', + './modules/DynamicFields/templates/Fields/TemplateHTML.php' => 'de047ceef03750cf2c7a446b8c222c08', + './modules/DynamicFields/templates/Fields/TemplateFloat.php' => 'a692b82633c68b963b1839b5975f47a6', + './modules/DynamicFields/templates/Fields/TemplateField.php' => '09ab55dc404802b1716d2058c7087944', + './modules/DynamicFields/templates/Fields/TemplateEnum.php' => '68afaa64599ad85713df76ff57c479cd', + './modules/DynamicFields/templates/Fields/TemplateEncrypt.php' => '581e09a06f8fb69ca495dde60fc2c9ad', + './modules/DynamicFields/templates/Fields/TemplateEmail.php' => '61d3983c998fc97b75132b323da82e37', + './modules/DynamicFields/templates/Fields/TemplateDecimal.php' => '726f6c5b927e968a0e64352428210fd8', + './modules/DynamicFields/templates/Fields/TemplateDatetimecombo.php' => '3d407715f96102e426cef14e3576ebc1', + './modules/DynamicFields/templates/Fields/TemplateDate.php' => '1c89210c5d7cd32d2319a44e8ae538b7', + './modules/DynamicFields/templates/Fields/TemplateCurrencyId.php' => 'dc91f2deb794748114de23cc7b4cdc09', + './modules/DynamicFields/templates/Fields/TemplateCurrency.php' => '3cee6d3c8507486227baa80243a29fd4', + './modules/DynamicFields/templates/Fields/TemplateBoolean.php' => '060d4349e3756351791ac862a8814af6', + './modules/DynamicFields/templates/Fields/TemplateAddressCountry.php' => '522ab825c2c18d722df9d9d0dda5c13b', + './modules/DynamicFields/templates/Fields/TemplateAddress.php' => '9f24e128e05ad01de87b8e323c36c3e7', + './modules/DynamicFields/templates/Fields/Forms/phone.tpl' => '97581b77ffde48b0dbe8aef9a1a9f705', + './modules/DynamicFields/templates/Fields/Forms/phone.php' => '45a60141bef3af6ac5dd71259649e324', + './modules/DynamicFields/templates/Fields/Forms/varchar.tpl' => '05aea29acabb0987bca9b932e70f61b1', + './modules/DynamicFields/templates/Fields/Forms/url.tpl' => '4fbced3e9414687494d53fb40e535d87', + './modules/DynamicFields/templates/Fields/Forms/url.php' => '21b0e80433b0cc07dccd3c6dbd2606bd', + './modules/DynamicFields/templates/Fields/Forms/text.tpl' => 'b745f2b359fc21c1f8d6a3f000ef78a0', + './modules/DynamicFields/templates/Fields/Forms/relate.tpl' => 'c04f3abe417f433d21da6854a8cabd7a', + './modules/DynamicFields/templates/Fields/Forms/relate.php' => '2776ceb54ad1e580d9311fbd44c32e41', + './modules/DynamicFields/templates/Fields/Forms/radioenum.php' => '457c1027437211ad734331974c50513b', + './modules/DynamicFields/templates/Fields/Forms/parent.tpl' => '8664691eee2fe9fa52ccbfd6502882b3', + './modules/DynamicFields/templates/Fields/Forms/parent.php' => '6f73a276856953fe2bebcfb1a3c60fcc', + './modules/DynamicFields/templates/Fields/Forms/multienum.tpl' => 'f76bbb109e3915416df7141ad2d6c7dd', + './modules/DynamicFields/templates/Fields/Forms/multienum.php' => '17ad63f685ea5f289e42c3e973b01e1d', + './modules/DynamicFields/templates/Fields/Forms/int.tpl' => 'b00e937d643eb478200c61a8be35f913', + './modules/DynamicFields/templates/Fields/Forms/image.tpl' => '8819674e601946cb15a4de99f9a6e10e', + './modules/DynamicFields/templates/Fields/Forms/image.php' => '31df95d5969eed1a0f8bfdf356f6bc4a', + './modules/DynamicFields/templates/Fields/Forms/iframe.tpl' => '6a99ae96432266b24229c988a742f037', + './modules/DynamicFields/templates/Fields/Forms/iframe.php' => 'c6d042efca51ca0a99eb58f5840fa132', + './modules/DynamicFields/templates/Fields/Forms/html.tpl' => 'a1bc8985dd422758b674c1e5047bfad6', + './modules/DynamicFields/templates/Fields/Forms/html.php' => '8bf209be25d0e3459470268685b5b1cd', + './modules/DynamicFields/templates/Fields/Forms/float.tpl' => 'eec764e851c0ebfd92f98b257cf5c942', + './modules/DynamicFields/templates/Fields/Forms/enum2.php' => 'fd3a49996fcd8ad2cfddde0df6666b22', + './modules/DynamicFields/templates/Fields/Forms/enum.tpl' => 'adc4c505d67fcd9c18febcf5d7aa34e0', + './modules/DynamicFields/templates/Fields/Forms/encrypt.tpl' => 'd680507b7d44a7732be8e46c8cfd2cf8', + './modules/DynamicFields/templates/Fields/Forms/encrypt.php' => '41f5d5ff83df9e288f881b7f3bda4209', + './modules/DynamicFields/templates/Fields/Forms/datetimecombo.tpl' => '0aa8d6c1e37c646926b957b5e552b6d1', + './modules/DynamicFields/templates/Fields/Forms/datetimecombo.php' => 'e95cc013b77efa88984ddde6a1ee41e3', + './modules/DynamicFields/templates/Fields/Forms/date.tpl' => 'b79d0cc53eababe4d1c0f3fcd036cbd3', + './modules/DynamicFields/templates/Fields/Forms/date.php' => '09b7d866f9654631c223410ee94a34e3', + './modules/DynamicFields/templates/Fields/Forms/currency.tpl' => '6edc5e3318e62f4b46b636a60a4cbf2a', + './modules/DynamicFields/templates/Fields/Forms/coreTop.tpl' => '5271cfdffa816a609b623cd6179fa65c', + './modules/DynamicFields/templates/Fields/Forms/coreBottom.tpl' => '991541c474e4333e9757485d0dbaf7ad', + './modules/DynamicFields/templates/Fields/Forms/bool.tpl' => 'b44e01f200cf8e243c3d9a4602019056', + './modules/DynamicFields/templates/Fields/Forms/address.tpl' => 'bfaee150ccca6370715adfa01bd204d0', + './modules/DynamicFields/language/en_us.lang.php' => 'e904f9c5240dedc3cee49c5e3709b632', + './modules/DynamicFields/UpgradeFields.php' => 'a1880f6a70750840063205c16bc4e2ca', + './modules/DynamicFields/Save.php' => 'f47bc3a9fc4e35bb867d92b77676fee1', + './modules/DynamicFields/FieldsMetaData.php' => '296f6d11e6572e1e4ac9f230b3b3dd45', + './modules/DynamicFields/FieldViewer.php' => '2050b8802e13802b36d4ca2dd0069417', + './modules/DynamicFields/FieldCases.php' => '8147d93a82ca4a415a38b744d36c50a2', + './modules/DynamicFields/DynamicField.php' => '7aa8f24fd5be276dbd2c47be8c220369', + './modules/Documents/documents.js' => '58425e6b28feb5424a1a44cc11e5e927', + './modules/Documents/tpls/view.extdoc.tpl' => 'b5c9539ff7427f60b075adbc04f4f0a1', + './modules/Documents/action_view_map.php' => 'e0852de31b1bbbbb80218205c2f2fbf7', + './modules/Documents/DocumentExternalApiDropDown.php' => '073eef6ba2b79bb25204419ebf96ddbe', + './modules/Documents/views/view.extdoc.php' => 'be76032ab4c036957cde42f5ccd75054', + './modules/Documents/views/view.edit.php' => '02b497a597f4c64e33f63932d41fb9f6', + './modules/Documents/views/view.detail.php' => '120516f7a34b3aad7c3542903a220d0d', + './modules/Documents/Dashlets/MyDocumentsDashlet/MyDocumentsDashlet.php' => '5de53713106c0ae6b5ad378fd156e5a0', + './modules/Documents/Dashlets/MyDocumentsDashlet/MyDocumentsDashlet.meta.php' => '646b19ac73a520c331a9cae4e8b7fde9', + './modules/Documents/Dashlets/MyDocumentsDashlet/MyDocumentsDashlet.data.php' => 'ebbef0679a8b5bb7e02a4987cb6332f5', + './modules/Documents/vardefs.php' => '57ab47aaa2ca3fab68e244d29058ce9a', + './modules/Documents/metadata/subpanels/default.php' => 'c8eaa7900e9c63168f7bb080eed86aa4', + './modules/Documents/metadata/subpanels/ForContractType.php' => 'e4a3e73968acf2d0a2f211a291e6fcb5', + './modules/Documents/metadata/subpaneldefs.php' => 'e58d020bdf070a67368e346b56da70f7', + './modules/Documents/metadata/studio.php' => 'ef88e2e795f36cb9dddf39c59daf767e', + './modules/Documents/metadata/searchdefs.php' => '4d411dae4fd25c153fd398f7f6e3f4d6', + './modules/Documents/metadata/quickcreatedefs.php' => 'f0ae983deec7432bf0f98e581fbd9988', + './modules/Documents/metadata/listviewdefs.php' => '4ea73f783cf4c96fd94fc5050847ae02', + './modules/Documents/metadata/editviewdefs.php' => '17a1301aa3dc33229b9d03d65ff3f01a', + './modules/Documents/metadata/detailviewdefs.php' => '2f2e9944602d987b9312c9008be1e006', + './modules/Documents/metadata/SearchFields.php' => '9183287ac55da0719114a8e9f093b43b', + './modules/Documents/language/en_us.lang.php' => '2eab3bc37ccf0843360c55ec415a9430', + './modules/Documents/field_arrays.php' => '17ab246ffa0317da253689361f1dfb3a', + './modules/Documents/TreeData.php' => '16ad8acdfecb80e79b2c6838ca5f6113', + './modules/Documents/Popup_picker.php' => '975912e51cc22c5c8354843297b16ba6', + './modules/Documents/Popup_picker.html' => '7e2f68d3ed1d18cdb6c658a661ff2659', + './modules/Documents/Popup.php' => '468c860fd3edb73570cd47420165ab21', + './modules/Documents/Menu.php' => '333b4909040dd17503600c4db615cdd7', + './modules/Documents/GetLatestRevision.php' => '3f0f3ab61f376d3cf50b759d8f655b8a', + './modules/Documents/DocumentSoap.php' => 'ea6ba67ff29c16ef8f22379ce4682a94', + './modules/Documents/Document.php' => '48a7eec0d4b328fbe31be84ce410f613', + './modules/Documents/Delete.php' => '8620d185f38b20a32a492e02ee9d248c', + './modules/DocumentRevisions/subpanels/default.php' => 'dbc240b4c77f5ee6b8fb8e09c4c66d86', + './modules/DocumentRevisions/metadata/editviewdefs.php' => '62dbcf0f9879e49727b626caec71c64f', + './modules/DocumentRevisions/metadata/detailviewdefs.php' => '065930313ea614dff0044e40743a4e3d', + './modules/DocumentRevisions/metadata/subpanels/default.php' => '0733fa74d8c63d07f3ddeb1464bf2b0e', + './modules/DocumentRevisions/language/en_us.lang.php' => '50f782d58ab988825e177eb716318c63', + './modules/DocumentRevisions/field_arrays.php' => '8946268a3f327b347bd6e6dbadd99927', + './modules/DocumentRevisions/Menu.php' => 'e37e3e5bcfdeb6990f12b73ccfb49413', + './modules/DocumentRevisions/ListView.html' => 'c4abed4e08f852d67f13884377595b1e', + './modules/DocumentRevisions/Forms.php' => '45fa36924dbe3290cb54734c640bc549', + './modules/DocumentRevisions/vardefs.php' => '5dc107ecc501ac49924533b31cd4c1c4', + './modules/DocumentRevisions/DocumentRevision.php' => '7744d6c6f4d978e84818eacbab787e1e', + './modules/Currencies/EditView.js' => '0556649f3fca63b880c53bbe8a8cfc64', + './modules/Currencies/vardefs.php' => 'd6b4b591dda346931bee3509c3636428', + './modules/Currencies/language/en_us.lang.php' => '3c96645089ad8919955df4351a3f4b80', + './modules/Currencies/iso4217.php' => 'e4b97cb7b108bfbb56a0f4b4ed634244', + './modules/Currencies/index.php' => '0200e0104be4d3e86c088ba274796c35', + './modules/Currencies/field_arrays.php' => 'c6056d9901110e8e5b11a48dfd4b7bfa', + './modules/Currencies/Menu.php' => '733f57c3acdbccd062a4dda2bb551c9f', + './modules/Currencies/ListView.html' => '3d4e93cbef259fc09d386cc04fdd2b41', + './modules/Currencies/ListCurrency.php' => '4f77eabdbd1a9d25d8a6ed8b33d855f1', + './modules/Currencies/Forms.php' => '4c8798c62061fc02a93699b90be1ae5f', + './modules/Currencies/EditView.tpl' => '4987de1dbad853674eaaaabeb5126be2', + './modules/Currencies/EditCurrency.php' => '8b484f51f73f2e2d7f308fed49c5bfd2', + './modules/Currencies/Currency.php' => '14fc560933dee2e5d04c2677392cc6ce', + './modules/Contacts/Contact.js' => 'c25c0f38cc8da0ed4dcf514593dc4015', + './modules/Contacts/views/view.list.php' => '0926c2683a1e47f09c90b6699022714a', + './modules/Contacts/views/view.validportalusername.php' => 'd931af4e4d45c3bb81f6e35d93185c10', + './modules/Contacts/views/view.retrieveemail.php' => '9640acc692cd227bb9eb62f5e093f5e7', + './modules/Contacts/views/view.mailmergepopup.php' => '48644b73c9fd9d28f577756de1047d19', + './modules/Contacts/views/view.edit.php' => '616587437c988dea31c3bcf6f164199a', + './modules/Contacts/views/view.detail.php' => 'ddc36d7454144420ca368a40d34c85d8', + './modules/Contacts/views/view.contactaddresspopup.php' => '5527c284f39b5b5a8f5b6442c66418e3', + './modules/Contacts/views/view.closecontactaddresspopup.php' => 'ea49918991a66737c59935aab4b95868', + './modules/Contacts/tpls/QuickCreate.tpl' => 'bc8b3245dd9829b8e3c43b368f03f535', + './modules/Contacts/metadata/subpanels/default.php' => 'dafdcd6f26d232719006723883815f27', + './modules/Contacts/metadata/subpanels/ForProject.php' => 'de0f32c9a1a9cdaa9564f24274317e85', + './modules/Contacts/metadata/subpanels/ForOpportunities.php' => '90e4952a5da71178ed18e33f1ddf1603', + './modules/Contacts/metadata/subpanels/ForMeetings.php' => '2e9a131214adb2f99710a780fb84f8ee', + './modules/Contacts/metadata/subpanels/ForEmails.php' => 'dc93d730f7e6c5e9aa975c0257cf532a', + './modules/Contacts/metadata/subpanels/ForContacts.php' => '555c8550cbc7ef6e6331679a3b25cb83', + './modules/Contacts/metadata/subpanels/ForCases.php' => '11977517e432f540e8818390579b50be', + './modules/Contacts/metadata/subpanels/ForCalls.php' => '05728178cd78cad474a8a0970b86d44c', + './modules/Contacts/metadata/subpanels/ForAccounts.php' => 'dc4bc95c9ab4fa1a94932f0623c6b516', + './modules/Contacts/metadata/subpaneldefs.php' => 'eb042ef2d0bf11346e2f593f8b41a91d', + './modules/Contacts/metadata/studio.php' => 'cd366f7f66c095df7ad089dc16c56dbf', + './modules/Contacts/metadata/searchdefs.php' => 'd14992c1c5b35bf3ea9ff33f3c412f1a', + './modules/Contacts/metadata/quickcreatedefs.php' => 'f3071587fe73499a7436a46c73b20dc6', + './modules/Contacts/metadata/popupdefsEmail.php' => 'ce9d210c9205a052bc4abd020301cf54', + './modules/Contacts/metadata/popupdefs.php' => '29d9a8b0823c22649d62ab00d1e0b22e', + './modules/Contacts/metadata/metafiles.php' => 'de7d02f5eed16516f68c430cd353bb9a', + './modules/Contacts/metadata/listviewdefs.php' => '45a70da06f20f60052498ff35bfc4fee', + './modules/Contacts/metadata/editviewdefs.php' => '2ff317404ec6cb66e3cbd33ec94db87f', + './modules/Contacts/metadata/detailviewdefs.php' => '75d4d4a0456df3d76f97ca46e1e1c791', + './modules/Contacts/metadata/additionalDetails.php' => 'c3253504941c2f8c61adb49647875de9', + './modules/Contacts/metadata/SearchFields.php' => 'c7ec0d2d5f13a516ec5a6898ffcefcc2', + './modules/Contacts/language/en_us.lang.php' => '9de3bfac54f4df57d472ba0259bc9e57', + './modules/Contacts/field_arrays.php' => '7979238d640cc613dcb97ef7b8369520', + './modules/Contacts/controller.php' => 'b2385209924456abde6cabff56a4afd5', + './modules/Contacts/vardefs.php' => 'ceb5a8b6dd43a21f3b8276f79d8097c4', + './modules/Contacts/SugarFeeds/ContactFeed.php' => '7660842c3373bb38fb4ea53066daabee', + './modules/Contacts/ShowDuplicates.php' => '1eab54c20a91e829674014ece2775ea0', + './modules/Contacts/ShowDuplicates.html' => 'c326e91ae04dfa6833ddce04ee60d769', + './modules/Contacts/SaveContactOpportunityRelationship.php' => '8ac7f5cbffc192f6322416d3d16bed96', + './modules/Contacts/Save.php' => '1b4ce85e609248a628125166c5030077', + './modules/Contacts/Popup_picker.php' => '4de07c7a6064d7cb6cefb2036c3b8662', + './modules/Contacts/Menu.php' => '8ddaf15eb43427d158a48ee8599442e3', + './modules/Contacts/MailMergePicker.html' => 'a8cba0cba92b774e25ead5b3f976b74c', + './modules/Contacts/Email_picker.html' => '78bdb107df9c0222aadaa98ae35ff69b', + './modules/Contacts/Dashlets/MyContactsDashlet/MyContactsDashlet.php' => 'd34a72276371f7304f99f4aab38cecee', + './modules/Contacts/Dashlets/MyContactsDashlet/MyContactsDashlet.meta.php' => '3044ab418bf29f2ee89b06548dad7d07', + './modules/Contacts/Dashlets/MyContactsDashlet/MyContactsDashlet.data.php' => '0d778c85679f45a9ae3b4a9bb7a49f49', + './modules/Contacts/ContactsQuickCreate.php' => '461a6331753225577ea1b5c74815a052', + './modules/Contacts/ContactOpportunityRelationshipEdit.php' => 'd1946dd0e5403b21bbe9733e920c7678', + './modules/Contacts/ContactOpportunityRelationshipEdit.html' => 'f2eeb01bb169f5bd9a43c9985473583d', + './modules/Contacts/ContactOpportunityRelationship.php' => '23e4e969874e613f7e55a37c4bbf96e8', + './modules/Contacts/ContactFormBase.php' => 'd6c1e53d1c119722feedec3c4251f7a6', + './modules/Contacts/Contact.php' => 'f807fed9e5e4044a84b401d705a74ae6', + './modules/Contacts/BusinessCard.php' => '32d5200d10e7996dd416c39a20401512', + './modules/Contacts/BusinessCard.html' => 'c2bfce3507bdfd8b438c67f0a9e60cde', + './modules/Contacts/Address_picker.html' => '7232668a97db6fa8eb87c87f0b033401', + './modules/Contacts/AcceptDecline.php' => '09d9c0c134fa2488bf6cc22b2b0f7257', + './modules/Connectors/Connector.js' => '448a920b04476b7e61ad78fc4c5c4123', + './modules/Connectors/views/view.sourceproperties.php' => '5f43019c57e6c94cfa0b97694662c92a', + './modules/Connectors/views/view.searchproperties.php' => 'b3a55332662378c058a05d75bcf00015', + './modules/Connectors/views/view.modifysearch.php' => 'a1c1d1b9410c593d8995bfbd4fa1f15b', + './modules/Connectors/views/view.modifyproperties.php' => 'ffb71afd16610191accf19caa1246d4a', + './modules/Connectors/views/view.modifymapping.php' => 'c46ba78f560ac98c7c634245ead59cb7', + './modules/Connectors/views/view.modifydisplay.php' => 'd317001974987b5783a313b102a89519', + './modules/Connectors/views/view.mappingproperties.php' => '332325d9ec58a2e269a1773086c64468', + './modules/Connectors/views/view.displayproperties.php' => '031a0fb4f29803b4aaa55bdf19160cd3', + './modules/Connectors/views/view.connectorsettings.php' => 'b8a5bcb2dd0688d4cb51f169d9ab9942', + './modules/Connectors/tpls/tabs.css' => 'cdac9cfd5fb156606b441ec785bc677f', + './modules/Connectors/tpls/source_properties.tpl' => '7f469c2832dd3dba7a14fdbb23ae1302', + './modules/Connectors/tpls/search_properties.tpl' => 'a2f98440eb1dcb34dd0a465a6409b1cd', + './modules/Connectors/tpls/search_form.tpl' => 'e69676baf219ad0e51cc2265a6503fe9', + './modules/Connectors/tpls/modify_search.tpl' => 'c2ffa75bfd81a2e53c89fa4cc2ecdf2e', + './modules/Connectors/tpls/modify_properties.tpl' => '1f18a624b7123d56d93aa03ba8f99f57', + './modules/Connectors/tpls/modify_mapping.tpl' => '2559ca3fb736e336e4776300099c1fc2', + './modules/Connectors/tpls/modify_display.tpl' => '4c578aecdf3b8194d9f4b62b1b53ae4d', + './modules/Connectors/tpls/mapping_properties.tpl' => 'bca2954c7d96ba94ad4fd3c107348854', + './modules/Connectors/tpls/listview.tpl' => '4264ad6abd2ae56dbb0eea70300f7b63', + './modules/Connectors/tpls/display_properties.tpl' => 'b91385de219f5edb96681477869c088c', + './modules/Connectors/tpls/administration.tpl' => '5593390a3a543f00dc7abb6fd6582349', + './modules/Connectors/metadata/searchdefs.php' => 'ac41e08a95787079b76e1b4214b48536', + './modules/Connectors/language/en_us.lang.php' => '7de2c6735b830221701cae546e0b0688', + './modules/Connectors/controller.php' => '6b664c1df209c9ec3c50807cad2ea55c', + './modules/Connectors/connectors/sources/ext/rest/linkedin/vardefs.php' => 'f58cabfef259cdfdd1c7f5c451579e9f', + './modules/Connectors/connectors/sources/ext/rest/linkedin/mapping.php' => 'bdcb08f59c7f7190c89d522f8a8eb1bd', + './modules/Connectors/connectors/sources/ext/rest/linkedin/linkedin.php' => '02d33b07337483103e4ed86c4fbafcf2', + './modules/Connectors/connectors/sources/ext/rest/linkedin/language/en_us.lang.php' => 'a28f344139465e4d57275f2b3c1462d9', + './modules/Connectors/connectors/sources/ext/rest/linkedin/config.php' => 'de7e0716993ecb8a65438c0ca6c57d8a', + './modules/Connectors/connectors/formatters/ext/rest/twitter/tpls/twitter.gif' => '025ad081fbafed4577cc09c9eddb9a8d', + './modules/Connectors/connectors/formatters/ext/rest/linkedin/tpls/linkedin.gif' => '3440ba160f32d8eb17a5b2ed03be60c6', + './modules/Connectors/connectors/formatters/ext/rest/linkedin/tpls/default.tpl' => 'b04c46cb0025aeecc37a13119b45f3e1', + './modules/Connectors/connectors/formatters/ext/rest/linkedin/linkedin.php' => 'e5f3dc4e58123f2ed7c45e49c13cca2a', + './modules/Connectors/action_view_map.php' => 'c7c6db82bfb2579b3e1cf60d32c60122', + './modules/Connectors/Menu.php' => '6dc050c32fc631c5f5835272a95ca16e', + './modules/Connectors/InstallDefaultConnectors.php' => '134be513282c4d9c24bbb95b645b1c67', + './modules/Connectors/Forms.php' => 'e773d1cb9319008bb56c2522ab5021c4', + './modules/Connectors/ConnectorRecord.php' => 'ab7b51444082460d55cb5f62dd83a716', + './modules/Configurator/views/view.sugarpdfsettings.php' => 'dde9cc7d75d3f19f8ebc4358154b0ce3', + './modules/Configurator/views/view.fontmanager.php' => '89fc1754f7943bbab734a64f0786e5b1', + './modules/Configurator/views/view.edit.php' => '1cb57776f2d139bed2b0088f30ccde02', + './modules/Configurator/views/view.adminwizard.php' => '6826936013bd84bcacf9e11337354ab7', + './modules/Configurator/views/view.addfontview.php' => '1465d6c0ee67ce9ee85e8b94abcf751a', + './modules/Configurator/views/view.addfontresult.php' => 'a22a73b6b915a13dce62431a27160a89', + './modules/Configurator/tpls/fontmanager.tpl' => '45f58b42e0a31f0ce33be60e420155e1', + './modules/Configurator/tpls/adminwizard.tpl' => 'afc0eac0c32019a82dab648f1619606d', + './modules/Configurator/tpls/addFontView.tpl' => '730f5df9fcf9b30c3cb9aa58d0045c7b', + './modules/Configurator/tpls/addFontResult.tpl' => '0788b5174905d3013feb14f7ec4381be', + './modules/Configurator/tpls/SugarpdfSettingsFields.tpl' => '7a8b844ca3e554a8050ffc9a4bdbb294', + './modules/Configurator/tpls/SugarpdfSettings.tpl' => '186fed1d7dffb54c8319d439d63c35de', + './modules/Configurator/tpls/EditView.tpl' => '8bc868d1724ef38a042f93d3acbcebd6', + './modules/Configurator/metadata/SugarpdfSettingsdefs.php' => 'd9b13b9d6b0ef655942d094d116f509d', + './modules/Configurator/language/en_us.lang.php' => '5d121c096948caf0675e743dafcba16f', + './modules/Configurator/controller.php' => '8304c1c649cb5549328ab56b406045b3', + './modules/Configurator/UploadFileCheck.php' => '9ea5cae1af2a1f9eec3bb6b48945dc27', + './modules/Configurator/action_view_map.php' => '5ae1cc06862e145e7726734cfd89d9a2', + './modules/Configurator/Menu.php' => 'f978c89aacc457107486e53fe5768f80', + './modules/Configurator/LogView.php' => '77668af21cdf1132cbbff065419e56c0', + './modules/Configurator/Forms.php' => 'a904600913c726e07c3ae5d7c81a9803', + './modules/Configurator/Configurator.php' => 'bf225a3445d6fb2111756c04e223311b', + './modules/Charts/DynamicAction.php' => '006d59c830fae1d8d2f61e66936dcb28', + './modules/Charts/language/en_us.lang.php' => '35fb7000f67e1a0a80e4082e07eee3ee', + './modules/Charts/code/predefined_charts.php' => '26bb40f32bad05579ed73a87e07c3c32', + './modules/Charts/code/Chart_pipeline_by_sales_stage.php' => '6ddf4d467fbf5f66796fcc961e8df518', + './modules/Charts/code/Chart_pipeline_by_lead_source.php' => '7dfd55d4b930670002fee0f0e62e8c40', + './modules/Charts/code/Chart_outcome_by_month.php' => '725b9cd7b67a7ad88d266065a90e8add', + './modules/Charts/code/Chart_my_pipeline_by_sales_stage.php' => '801b0f178cd47f2e25eff2f7ab9da185', + './modules/Charts/code/Chart_lead_source_by_outcome.php' => '52f6db752fe424c66980c71d788dc480', + './modules/Charts/chartdefs.php' => '9abdf4acefb1bf18df7d12cc9edb1ed1', + './modules/Charts/PredefinedChart.php' => 'd72fef32d4b54638fd16f2f2a9f0780d', + './modules/Charts/Dashlets/PredefinedChartDashletScript.tpl' => 'a6cb84b6eb49a5a777bd84179f3d7fb3', + './modules/Charts/Dashlets/PipelineBySalesStageDashlet/PipelineBySalesStageDashlet.php' => '0a3fb878b1dc6750d8978c9534f13ef9', + './modules/Charts/Dashlets/PipelineBySalesStageDashlet/PipelineBySalesStageDashlet.meta.php' => '596379d45a15cbfcab6df35fa7aea504', + './modules/Charts/Dashlets/PipelineBySalesStageDashlet/PipelineBySalesStageDashlet.en_us.lang.php' => '1cfcb557f086058718227e063fb51174', + './modules/Charts/Dashlets/PipelineBySalesStageDashlet/PipelineBySalesStageDashlet.data.php' => '6fa623f04ca10da8cd5daa927308920c', + './modules/Charts/Dashlets/PipelineBySalesStageDashlet/PipelineBySalesStageConfigure.tpl' => '4c26515a8f4654ff635cec79d87fa18b', + './modules/Charts/Dashlets/OutcomeByMonthDashlet/OutcomeByMonthDashlet.php' => 'e79d8cbc1b3e709c1bd4e238c37d36ce', + './modules/Charts/Dashlets/OutcomeByMonthDashlet/OutcomeByMonthDashlet.meta.php' => 'eb83981e07033343210913c8552e98cb', + './modules/Charts/Dashlets/OutcomeByMonthDashlet/OutcomeByMonthDashlet.en_us.lang.php' => 'ad28142c5393a17c71b561466a09509a', + './modules/Charts/Dashlets/OutcomeByMonthDashlet/OutcomeByMonthDashlet.data.php' => '320e1e77b43d882254febbbc151d15ac', + './modules/Charts/Dashlets/OutcomeByMonthDashlet/OutcomeByMonthConfigure.tpl' => '387bdbb2e000cd674ff76919f6e0d334', + './modules/Charts/Dashlets/OppByLeadSourceDashlet/OppByLeadSourceDashlet.php' => 'ad404e86d38ea1f603fa7fd79b58db55', + './modules/Charts/Dashlets/OppByLeadSourceDashlet/OppByLeadSourceDashlet.meta.php' => '1b0aef72159327751b70f28d56348a3b', + './modules/Charts/Dashlets/OppByLeadSourceDashlet/OppByLeadSourceDashlet.en_us.lang.php' => '31b731d78ef6ff8fc6c1ae685e65bd5b', + './modules/Charts/Dashlets/OppByLeadSourceDashlet/OppByLeadSourceDashlet.data.php' => 'b57e760d1e0be35e53cec4290d54a80d', + './modules/Charts/Dashlets/OppByLeadSourceDashlet/OppByLeadSourceConfigure.tpl' => '26e1153049e0ec20b9b6092d1c274f37', + './modules/Charts/Dashlets/OppByLeadOutcomeDashlet/OppByLeadOutcomeDashlet.php' => 'e2b735735dbbfd483e6a2257756ac45c', + './modules/Charts/Dashlets/OppByLeadOutcomeDashlet/OppByLeadOutcomeDashlet.meta.php' => 'f410571259098d9c5351df98fe586a58', + './modules/Charts/Dashlets/OppByLeadOutcomeDashlet/OppByLeadOutcomeDashlet.en_us.lang.php' => 'f7f11fcc59acfc96595206d38442773d', + './modules/Charts/Dashlets/OppByLeadOutcomeDashlet/OppByLeadOutcomeDashlet.data.php' => 'd8337b4ff674acf896f15aa59598cf81', + './modules/Charts/Dashlets/OppByLeadOutcomeDashlet/OppByLeadOutcomeConfigure.tpl' => '431b0d628ad92789389e58ba84f3715c', + './modules/Charts/Dashlets/MyPipelineBySalesStageDashlet/MyPipelineBySalesStageDashlet.php' => 'f470b9e8c9959ea9409c73a8ea0d2d65', + './modules/Charts/Dashlets/MyPipelineBySalesStageDashlet/MyPipelineBySalesStageDashlet.meta.php' => '80a6fb7ae30d669bbde56b908907d381', + './modules/Charts/Dashlets/MyPipelineBySalesStageDashlet/MyPipelineBySalesStageDashlet.en_us.lang.php' => 'af53f692afb8c957a29ebc997d034cc5', + './modules/Charts/Dashlets/MyPipelineBySalesStageDashlet/MyPipelineBySalesStageDashlet.data.php' => '69ac6d4207accac35af17dc7faea66ef', + './modules/Charts/Dashlets/MyPipelineBySalesStageDashlet/MyPipelineBySalesStageConfigure.tpl' => '37eafb5d1b8ef3df4e074a7d672f32dd', + './modules/Charts/Dashlets/CampaignROIChartDashlet/CampaignROIChartDashlet.php' => 'ddf0a69768bc1b44bd0aaa2008b5f720', + './modules/Charts/Dashlets/CampaignROIChartDashlet/CampaignROIChartDashlet.meta.php' => '6b2964ec3b17a25ed8dfdcb61492f913', + './modules/Charts/Dashlets/CampaignROIChartDashlet/CampaignROIChartDashlet.en_us.lang.php' => '4851b79a0581975e1b4e78aa4676e82b', + './modules/Charts/Dashlets/CampaignROIChartDashlet/CampaignROIChartDashlet.data.php' => 'c8da14210aa4478fa84d9ed10f215349', + './modules/Charts/Dashlets/CampaignROIChartDashlet/CampaignROIChartConfigure.tpl' => 'e2f8e61a236a9f10a44909accac0777b', + './modules/Cases/vardefs.php' => 'c7659b74521095cb41152d2b494ed1af', + './modules/Cases/tpls/QuickCreate.tpl' => '797858191cb07c7ca91d09fd93126694', + './modules/Cases/metadata/subpanels/default.php' => '3c1eba43b601bd86dd4c7b8703d2a46f', + './modules/Cases/metadata/subpanels/ForEmails.php' => '6facba33a069dc4ee000b6dcc358058a', + './modules/Cases/metadata/subpanels/ForAccounts.php' => 'a1bfe3a4423771972a2a3773e8caa1ec', + './modules/Cases/metadata/subpaneldefs.php' => 'd137d32a50230212d86792f2776edf68', + './modules/Cases/metadata/studio.php' => '11e821aac94c253d481d5a7be2a8a662', + './modules/Cases/metadata/searchdefs.php' => '467c870d47f30abe975501354935a2eb', + './modules/Cases/metadata/quickcreatedefs.php' => '027b0adfdcf631f290d51db06b8a991e', + './modules/Cases/metadata/popupdefs.php' => '944fabacbbbb5e1b7c8108e7dced46c0', + './modules/Cases/metadata/listviewdefs.php' => 'fbaffa79fc817cc6bacab216cd98e37b', + './modules/Cases/metadata/editviewdefs.php' => '9c7b9d83c0b7410112dcac58fb8c6100', + './modules/Cases/metadata/detailviewdefs.php' => '456060728ba6c23a7c21fca8eff48234', + './modules/Cases/metadata/additionalDetails.php' => 'b5fdd019a481f19c1ce2eca6791857f3', + './modules/Cases/metadata/accountsquickcreatedefs.php' => '3356167b784bbcbb3eaabf31fd2b6f3f', + './modules/Cases/metadata/SearchFields.php' => 'efc6859977ba842d18c2942a5a230f95', + './modules/Cases/language/en_us.lang.php' => 'a1f9017806b75f77a704736b8280bcb8', + './modules/Cases/field_arrays.php' => '3b9c8352d892a4e19ca7ff5005a85f30', + './modules/Cases/SugarFeeds/CaseFeed.php' => 'b9d038b0508335b872b2df25574140df', + './modules/Cases/Menu.php' => '86f7bab5fd40631e0565b376c201a5b0', + './modules/Cases/Dashlets/MyCasesDashlet/MyCasesDashlet.php' => '994eb878596fa41a8e14744d18cf8b46', + './modules/Cases/Dashlets/MyCasesDashlet/MyCasesDashlet.meta.php' => 'cb8284529059186a4c16765170ddff96', + './modules/Cases/Dashlets/MyCasesDashlet/MyCasesDashlet.data.php' => 'eb93b8b1caa0cfe15eaae4212014daed', + './modules/Cases/CasesQuickCreate.php' => 'b879a8dcfbf3a942dce6fb262c823d74', + './modules/Cases/Case.php' => 'f2962240f2d093a7f47f5d1615dea6fa', + './modules/Campaigns/DetailView.js' => '9c71b63bea528bbf482fac49f0e38113', + './modules/Campaigns/WebToLead.js' => 'da75713a096d89079d4ff82ebc385c7e', + './modules/Campaigns/wizard.js' => 'f53e95ad336d9649168d18c5c6c4319b', + './modules/Campaigns/views/view.newsletterlist.php' => '2015b9de130f1e78e94eedca04893be3', + './modules/Campaigns/views/view.modulelistmenu.php' => '1751b4ef7f8b269f3b0af2d19f488e2f', + './modules/Campaigns/views/view.detail.php' => 'af18d9f32a40b17ee42d7eab081cf2b7', + './modules/Campaigns/views/view.classic.php' => 'c21fffc7f64f157157aa94b046b98d5f', + './modules/Campaigns/vardefs.php' => 'd0278b4d89bb664c57f676d72787458e', + './modules/Campaigns/utils.php' => '9dac051dd98e886c7e8dcfb07f5f5747', + './modules/Campaigns/tpls/WizardNewsletter.tpl' => 'b5269b70c8f7dce81302806d37308738', + './modules/Campaigns/tpls/WizardHomeStart.tpl' => 'b2c166db9c1b6d84f5e06fda0906d002', + './modules/Campaigns/tpls/WizardCampaignTracker.tpl' => 'b99769ad295f43da1955b4f5ca99d6c8', + './modules/Campaigns/tpls/WizardCampaignTargetListForNonNewsLetter.tpl' => 'c0e4dbb5ac73d179ca47beb48da1ca5e', + './modules/Campaigns/tpls/WizardCampaignTargetList.tpl' => '97ac788a3940113c7449916b0966a66b', + './modules/Campaigns/tpls/WizardCampaignHeader.tpl' => 'cd06160635248ed576d795547568dfe9', + './modules/Campaigns/tpls/WizardCampaignBudget.tpl' => '1ce4df30bbad4f8449aea58b6bffe3a7', + './modules/Campaigns/metadata/subpanels/default.php' => 'ccd38c1082a6bc4fbda39b830ef6a13e', + './modules/Campaigns/metadata/subpanels/ForEmailMarketing.php' => '8acc990d657f278da67a12d19840a2a2', + './modules/Campaigns/metadata/subpaneldefs.php' => '7a8cedd24d8a05f422bc57d1fcaa27c3', + './modules/Campaigns/metadata/studio.php' => '141bd1ea7d7209a4d349fdc8ba795d38', + './modules/Campaigns/metadata/searchdefs.php' => 'cd57f35951f25372ed5317aab5f2c74e', + './modules/Campaigns/metadata/popupdefs.php' => 'b73f6ffbd1768594c157645e88d495dc', + './modules/Campaigns/metadata/listviewdefs.php' => 'ae1c799286ec57c7b997608036c89013', + './modules/Campaigns/metadata/editviewdefs.php' => '5974e03290fce92dfab03fdaf67ae0ee', + './modules/Campaigns/metadata/detailviewdefs.php' => '6e53e967b9a001f0b85bcc2dba94eb3c', + './modules/Campaigns/metadata/additionalDetails.php' => 'dadbd74bc0e5c908e63786758b706d17', + './modules/Campaigns/metadata/SearchFields.php' => 'a9fcb8e72d83353cb2f39af139b30492', + './modules/Campaigns/language/en_us.lang.php' => 'c35bb1c0ec0cb28f3680db743939527a', + './modules/Campaigns/image.php' => '3fcaeccb6fd036d4b250be1f030ae4a9', + './modules/Campaigns/field_arrays.php' => '933825db8adca7af782b2dc8104e36cc', + './modules/Campaigns/controller.php' => '241be0ccc9559c9a86c941cb6c961589', + './modules/Campaigns/chart.tpl' => '323ee5c2992ae57303a540ba97ae9a4b', + './modules/Campaigns/action_file_map.php' => 'fa8777d95f02d8105263d70f2d0856c7', + './modules/Campaigns/WizardNewsletterSave.php' => '380e4d734a2bf0d7a03101fc98b19597', + './modules/Campaigns/WizardNewsletter.php' => '0a31e62d9373465c8b261ca4bca9bfbc', + './modules/Campaigns/WizardNewsletter.html' => '005541645fa95275b0a607e1beff83af', + './modules/Campaigns/WizardMarketingSave.php' => '74336fd83c554fa45c81dfcbac6d2c1d', + './modules/Campaigns/WizardMarketing.php' => '46ba7cdcface748a224e1188a7dbd71e', + './modules/Campaigns/WizardMarketing.html' => '9c790a08a611ef353b29108fc7619f49', + './modules/Campaigns/WizardHome.php' => '5ba81d74b4a335f4f8bf9d5706e125a9', + './modules/Campaigns/WizardHome.html' => '546c0d6b0954c035a7109927b77e6565', + './modules/Campaigns/WizardEmailSetupSave.php' => '374734a4576af66f12c5698d80f48867', + './modules/Campaigns/WizardEmailSetup.php' => '6459fad4a6876e6b31da710d4eb07e6d', + './modules/Campaigns/WizardEmailSetup.html' => 'e0d0ed0cc9f4bbb7e188118aa5365dfb', + './modules/Campaigns/WebToLeadFormSave.php' => '266c2ee48c66ea479c6a3ae1e0bf34d8', + './modules/Campaigns/WebToLeadForm.html' => 'd5b07a69b1f449361777d289323bb3e5', + './modules/Campaigns/WebToLeadDownloadForm.html' => '0dad56489a4f4ee750ece5fb5a39c87b', + './modules/Campaigns/WebToLeadCreation.php' => 'fe2eb3bf194f8e0657531aa3b6c9837d', + './modules/Campaigns/WebToLeadCreation.html' => '2bc9da494178149c4f9c96eac5964392', + './modules/Campaigns/WebToLeadCapture.php' => '8165676b95d18de0c07aac4970e7dad5', + './modules/Campaigns/Tracker.php' => '88f83ca5e269791b2672e041484d018a', + './modules/Campaigns/TrackDetailView.tpl' => 'ccc80278e8a3043169831651120a28f8', + './modules/Campaigns/TrackDetailView.php' => 'dcc740690b11ec19085065c5d4415e44', + './modules/Campaigns/Subscriptions.tpl' => 'c4c0ce84e79bc1cb51cf675e1d78e940', + './modules/Campaigns/Subscriptions.php' => '5ab4f874103d5b4a2885b5bc86a42d88', + './modules/Campaigns/Subscriptions.html' => 'c48c2e2ee5ad0a6d71d9bd3d424e311b', + './modules/Campaigns/SubPanelViewer.php' => '685d8a558a788f75783c2fe27b0163b8', + './modules/Campaigns/SearchForm_NewsLetter.html' => 'b63e7dff9a0bd5821d9edc4afca44700', + './modules/Campaigns/Schedule.php' => '66284d35a57831c6970c503b48e70c9d', + './modules/Campaigns/Schedule.html' => '0a8fcc4b6f67cf99dab1efb104bba071', + './modules/Campaigns/Save.php' => '5cc149ddf1dc50ce8ebe13893615417a', + './modules/Campaigns/RoiDetailView.tpl' => '2cb5ff9612b303b9b83708b9584d958c', + './modules/Campaigns/RoiDetailView.php' => 'f52966766f1c651fdc9be9cbf8ac6eef', + './modules/Campaigns/RemoveMe.php' => '101b10e4dfbc2ded6217050feab4061d', + './modules/Campaigns/QueueCampaign.php' => '2339dd5a8e48272dc23edb41dd329af7', + './modules/Campaigns/ProcessBouncedEmails.php' => '0646fc980371a2060a816bcb73903853', + './modules/Campaigns/Popup_picker.php' => '16904e33546e9e4f7c831c3b47ad7f10', + './modules/Campaigns/Popup_picker.html' => '98b49c1bbf13fc6c83007ab48f978a42', + './modules/Campaigns/PopupCampaignRoi.php' => 'b524b8d0e13b50886519077673ceb34f', + './modules/Campaigns/PopupCampaignRoi.html' => 'e6fce810a3f3191cd0ca321c2fea0159', + './modules/Campaigns/Menu.php' => 'ed5ab9b80037a9013a96ebdbe23a38db', + './modules/Campaigns/MailMerge.php' => 'f875b21b8c8f5e60d256a09558f17799', + './modules/Campaigns/GenerateWebToLeadForm.php' => '56437b51720d89222126161b881e2672', + './modules/Campaigns/EmailQueue.php' => '79151d29eef076a928194529519f530f', + './modules/Campaigns/Delete.php' => 'aae524b404a661c8ff3709219a1f9712', + './modules/Campaigns/Dashlets/TopCampaignsDashlet/TopCampaignsDashletConfigure.tpl' => '85a1f82b9edf6d5c867fdbb49b645cda', + './modules/Campaigns/Dashlets/TopCampaignsDashlet/TopCampaignsDashlet.tpl' => 'c2f9905521e83c1af638f83e4988fc67', + './modules/Campaigns/Dashlets/TopCampaignsDashlet/TopCampaignsDashlet.php' => 'ec101f3befe73ca359fae4f6251c6d26', + './modules/Campaigns/Dashlets/TopCampaignsDashlet/TopCampaignsDashlet.meta.php' => '6da4b31958931a8f5138fecb7925b7c4', + './modules/Campaigns/Charts1.php' => '3e0262e983a12a06565b6865be74670a', + './modules/Campaigns/Charts.php' => '9199f1b68c7a79fdddf26859fb07bc33', + './modules/Campaigns/CaptchaValidate.php' => 'ba5f2ca64c8efd231363692da67be91a', + './modules/Campaigns/CampaignDiagnostic.php' => '3a22574096c9a30c12332d6c666bb7cc', + './modules/Campaigns/CampaignDiagnostic.html' => '8fab01d12a48e429496c63d383fbbb88', + './modules/Campaigns/Campaign.php' => '1ec8c6e4a91c517b60354f67647e74b1', + './modules/CampaignTrackers/vardefs.php' => 'f3a7c681ec09bbbb2e5771494acaf0ce', + './modules/CampaignTrackers/metadata/subpanels/default.php' => 'be3e6ba5ec9b5d8fa840aa0e96bda115', + './modules/CampaignTrackers/language/en_us.lang.php' => 'de5f4597b9f33db1aa92383f631a82f4', + './modules/CampaignTrackers/Save.php' => '45d01ff1f43f76e58d5b9679adc67fdf', + './modules/CampaignTrackers/Menu.php' => '757e41606b50ef3bd765688c58da6ab6', + './modules/CampaignTrackers/Forms.php' => '1cfbf63c2df97772313450ef33f404c2', + './modules/CampaignTrackers/Forms.html' => 'fba11af98aec13a0240fdb1995649fab', + './modules/CampaignTrackers/EditView.php' => '1cd0eba6aecfdb1d2a2e610d2d64d3f4', + './modules/CampaignTrackers/EditView.html' => '080d867a1b0fac32edbbffc2a1d565e9', + './modules/CampaignTrackers/DetailView.php' => '4ef4d9972013f7790404a43d3f3b19c3', + './modules/CampaignTrackers/DetailView.html' => '4f5b76bc757284ac2a7dc029d733496d', + './modules/CampaignTrackers/CampaignTracker.php' => 'eaf4cb5ad33c4cd5aa497d94a89188de', + './modules/CampaignLog/vardefs.php' => '6d64865931155de64f176d507ba0ac30', + './modules/CampaignLog/metadata/subpanels/default.php' => 'd29a247f61cf3e64cfec8c6bab63821d', + './modules/CampaignLog/metadata/subpanels/ForTargets.php' => 'aea0656fb66b1762d3139bf70000d101', + './modules/CampaignLog/language/en_us.lang.php' => '03e85595b5c4cb5b27425763e9592e76', + './modules/CampaignLog/Popup_picker.php' => '355e51e3620b3d03c4417b7547c2d279', + './modules/CampaignLog/Popup_picker.html' => '45f8b45d8730af406dddfdf19a6c7756', + './modules/CampaignLog/Menu.php' => '72cee4346bd510cecbc46485b04ade14', + './modules/CampaignLog/CampaignLog.php' => 'ba7bff8e1cbbfbbc4cd511e1ff63935f', + './modules/Calls/views/view.edit.php' => '2de3014f25fd6bb22f2657ddf6d94d43', + './modules/Calls/vardefs.php' => '35b6a6a0024b522fbf9645f762972ea4', + './modules/Calls/tpls/footer.tpl' => '6082af4d775df02784dc2e6038cc1cbf', + './modules/Calls/tpls/QuickCreate.tpl' => 'd3152acfc1a288743f3a617d1051334c', + './modules/Calls/metadata/subpanels/default.php' => '69cc2557c0ee5092e31e0e15dc3ccef0', + './modules/Calls/metadata/subpanels/ForHistory.php' => '8f647c21eee39024e543e526579ce90d', + './modules/Calls/metadata/subpanels/ForActivities.php' => '85ba197064ce84a95d0f863d0b42ef0a', + './modules/Calls/metadata/subpaneldefs.php' => '37cf3687ca0e24f995d7f3c9a998fdbe', + './modules/Calls/metadata/studio.php' => '6e05d6a206af3864af7b2fe2e00ce5dc', + './modules/Calls/metadata/searchdefs.php' => 'ed1582ec1c2f8aec4268b00b60cbeffb', + './modules/Calls/metadata/quickcreatedefs.php' => 'e32f8243306633414f4e5fc074c52a7c', + './modules/Calls/metadata/listviewdefs.php' => '89051fa7faf2c02ecc5623604fd919fe', + './modules/Calls/metadata/editviewdefs.php' => '16d8c43a17106fc34cd6995fd862c090', + './modules/Calls/metadata/detailviewdefs.php' => 'fa642df7f3da9169e36da510579fd574', + './modules/Calls/metadata/additionalDetails.php' => '97f403bbf8c0989ec3db860f49e6db84', + './modules/Calls/metadata/SearchFields.php' => '1f35a511c44a9040f634ecd9c3c222ee', + './modules/Calls/language/en_us.lang.php' => 'cebca26458070b491b9e459a928e6e0b', + './modules/Calls/field_arrays.php' => 'f4523e1742b9106acfaac6cb4f61175e', + './modules/Calls/SubPanelViewInvitees.php' => '5cb02de48efd780fe2c4925cbebf7237', + './modules/Calls/SubPanelViewInvitees.html' => '81983d6f2c7415c8602e21b33a60c896', + './modules/Calls/Save.php' => 'ce8a54c0bd9cb48c0d680c7873674895', + './modules/Calls/Menu.php' => 'e1fd861118213c1367bc3ab5df6b5cfa', + './modules/Calls/Dashlets/MyCallsDashlet/MyCallsDashlet.php' => '1a4e4aaebab7532336ee5860e931bffc', + './modules/Calls/Dashlets/MyCallsDashlet/MyCallsDashlet.meta.php' => '67b5354cb664fb2f64c7d7d4778c0f0c', + './modules/Calls/Dashlets/MyCallsDashlet/MyCallsDashlet.data.php' => '128bb818a9174f56cc03a574aa6f378c', + './modules/Calls/CallsQuickCreate.php' => '29ce9ba05e059e7c66d576a93935c1c4', + './modules/Calls/CallHelper.php' => 'd772215c0ab7f719711d3546d7529094', + './modules/Calls/CallFormBase.php' => '418352a6f8ab4c42d39789c20b1ef11b', + './modules/Calls/Call.php' => '9b1b2fec4fcd3e0f7ba1bb4002b0b4a1', + './modules/Calendar/views/view.list.php' => 'd0828a61e0acb41956f815c41e6cf609', + './modules/Calendar/templates/templates_calendar.php' => 'a840f71ec99db9c4dcc24d33371a7f9c', + './modules/Calendar/templates/template_shared_calendar.php' => 'db4237ff405a53de6c8711f69433921a', + './modules/Calendar/small_month.php' => '3365291aab18318106c40107d6d34dbb', + './modules/Calendar/metadata/listviewdefs.php' => '7a5882bd93cc1353b402b5d2542f033e', + './modules/Calendar/language/en_us.lang.php' => 'eea61667d4e8fb2063b9826ddfa33a82', + './modules/Calendar/index.php' => '8820c0fbe6db19c497a838d567137a8c', + './modules/Calendar/TasksListView.php' => '9bd353c2ca21b290be495aa47b6241db', + './modules/Calendar/TasksListView.html' => '9e88f3dfbaa5334dffa19fdb60413428', + './modules/Calendar/SubPanelSharedCalendar.php' => '31f7f9a358e80cdc5f5bac5a30904760', + './modules/Calendar/Forms.php' => 'a7fe2be5ad8ae8abbd68ce16c70c1825', + './modules/Calendar/Menu.php' => '9ff62f2ed70cdf0feec71ac6d7a7cd56', + './modules/Calendar/DateTimeUtil.php' => '65cd9a6db1d67bf825fabe9343c136a8', + './modules/Calendar/Calendar.php' => '10d12a54e83dce736365cb6d7fc2ef94', + './modules/Bugs/views/view.edit.php' => 'e2ac75d46479fe3748b11782913ec248', + './modules/Bugs/views/view.detail.php' => '4a33cf87111a05df094d38cead553683', + './modules/Bugs/vardefs.php' => '6398740b5e910547bc945b7fafe0ef35', + './modules/Bugs/tpls/QuickCreate.tpl' => '34574e6b44da09c734660ee3e027ff24', + './modules/Bugs/metadata/subpanels/default.php' => '66f7415c0f6bb180d4fa6b8099956c77', + './modules/Bugs/metadata/subpanels/ForEmails.php' => '74fe97a99990f83e1bd3de1a8054036e', + './modules/Bugs/metadata/subpaneldefs.php' => '7b8507aeaf8a489c802f68bdd26db965', + './modules/Bugs/metadata/studio.php' => '051b0e5dce864dec9c2a0c0279afee0f', + './modules/Bugs/metadata/searchdefs.php' => '36e62774c552c9706b1c4429e3437607', + './modules/Bugs/metadata/quickcreatedefs.php' => 'acd4c7d420aba7e8ed8769983fb13152', + './modules/Bugs/metadata/popupdefs.php' => 'e94d05768bb0cb4071b84aae03ab3e3c', + './modules/Bugs/metadata/metafiles.php' => 'eb37f1cc4850e60e296ece70506aa4fe', + './modules/Bugs/metadata/listviewdefs.php' => '6d7ca22bca5bcc3c8239c86830aaefe7', + './modules/Bugs/metadata/editviewdefs.php' => '7157e347cc165de5660354c6b67a5fe0', + './modules/Bugs/metadata/detailviewdefs.php' => '9465de63c8330e1fd96c2c30fab49c3e', + './modules/Bugs/metadata/additionalDetails.php' => '2d84911e0e5b611ebf5713106c24c6af', + './modules/Bugs/metadata/SearchFields.php' => 'c594a4a3436cf2f79792303faf1d4e54', + './modules/Bugs/language/en_us.lang.php' => 'f853c51736708c728c8baa40b2ef3b3e', + './modules/Bugs/field_arrays.php' => '905bf453c39714dc786f94d7f252c7f8', + './modules/Bugs/Menu.php' => 'f4eb9960fc4e7795d22b5d720d65e0cd', + './modules/Bugs/Dashlets/MyBugsDashlet/MyBugsDashlet.php' => '82f002f167c39ef796f9122d46183377', + './modules/Bugs/Dashlets/MyBugsDashlet/MyBugsDashlet.meta.php' => '3af77ac99657ab6d4e12ae7271644ad6', + './modules/Bugs/Dashlets/MyBugsDashlet/MyBugsDashlet.data.php' => '8e009899a2873cac3a1d2d48cc0de0fe', + './modules/Bugs/BugsQuickCreate.php' => '0ea39a55511d497bb16842e929687b28', + './modules/Bugs/Bug.php' => 'd8e05547c44c993d42ff4f189a45ded7', + './modules/BeanDictionary.php' => '2573609224ce688c56607c9450d6688e', + './modules/Audit/vardefs.php' => 'bb43929bc96abb7d89824a2bf1b6fe8f', + './modules/Audit/language/en_us.lang.php' => '00a5222fcdd00a246ca5ff6f139a6236', + './modules/Audit/field_assoc.php' => '9a7307afa1f8c6ebd45a2596fd44798b', + './modules/Audit/Popup_picker.php' => 'be9ec35605bed7b59aee3ea1c6fcdc37', + './modules/Audit/Popup_picker.html' => '6789fbb26a2fb173f0318eaa7aa54a2c', + './modules/Audit/Audit.php' => 'b24c748105c5a3787c67c3eabc834d2a', + './modules/Administration/views/view.languages.php' => '1cfa32f9c7f164c9163f17791d8ab848', + './modules/Administration/views/view.globalsearchsettings.php' => 'a5e8d3ad998f88ee347411e5b58ea8c5', + './modules/Administration/views/view.backups.php' => '516c2b886d0b0e7cab06b9d9a7ab30c7', + './modules/Administration/views/view.themesettings.php' => 'e2fc584638ded589a4a45dcce7c3737e', + './modules/Administration/views/view.repair.php' => 'bd8a7f2a8c082b08482954355f1a6a6d', + './modules/Administration/views/view.configuretabs.php' => '92e1e1ddf483fb3f9062821a7efc6809', + './modules/Administration/vardefs.php' => '60e43233b0b2fa7a8495a300bca6a01b', + './modules/Administration/upgrade_custom_relationships.php' => '025c57943e189ae2fb5793f725238001', + './modules/Administration/updateclass.php' => 'a317ca3f3b24fb656a999c2730f0e883', + './modules/Administration/updateTimezonePrefs.php' => '8a0baf4e4fdf997aa1c125c640a5232f', + './modules/Administration/undoupdateclass.php' => 'bb8da501b8bd927812a9cf694da79c7b', + './modules/Administration/templates/Languages.tpl' => 'b858359aa8fa24dd9705a07a3022a93e', + './modules/Administration/templates/GlobalSearchSettings.tpl' => 'af3e174b2dc44eb2d6ba6221b53655b9', + './modules/Administration/templates/themeSettings.tpl' => '6f9ad6507725e0caa54087efa21cec74', + './modules/Administration/templates/ShortcutBar.tpl' => 'fb74964e1d7bfbb1f9ad8dbe4ea07dec', + './modules/Administration/templates/RepairXSS.tpl' => 'a936c8f3386ac244bc600b60b0a42773', + './modules/Administration/templates/RepairDatabase.tpl' => 'a26068c872051ebbdd727ee5e2475a7a', + './modules/Administration/templates/QuickRepairAndRebuild.tpl' => '75659804131a655f3f79e628023bbba0', + './modules/Administration/templates/ConfigureTabs.tpl' => '5d5afb070db596dc828be765fb78cd3d', + './modules/Administration/repairUniSearch.php' => 'e687dbc61a6575390e985e05cbbaba1f', + './modules/Administration/repairSelectModule.php' => 'dbda01e72f1bb45430b700e4e143914b', + './modules/Administration/ncc_config.php' => 'aa5cbf334ba0430d97b0c370b5f1e83c', + './modules/Administration/metadata/adminpaneldefs.php' => '7415b75ef50d852c795af5714025b7a6', + './modules/Administration/metadata/SearchFields.php' => '4ad8c4a214135a7a1dc307aaf1576d9a', + './modules/Administration/language/en_us.lang.php' => 'c7c7a9d07fd42a14b8e0e1fecdf9ab1f', + './modules/Administration/javascript/Administration.js' => '47ab364695829994ccac9df0da22b960', + './modules/Administration/javascript/Async.js' => 'dbab93ac538b27db2097547870bb798d', + './modules/Administration/index.tpl' => 'd1f99979c433724a009c13b847a96b5e', + './modules/Administration/index.html' => '5faed788211b0d671bf982f89b68d339', + './modules/Administration/clear_chart_cache.php' => '5aaf3f5813aae9666dcb6490f12d9859', + './modules/Administration/callJSRepair.php' => 'e1854b35f5e12e29aa44b7effd53dfff', + './modules/Administration/UpgradeWizard_prepare.php' => '0a5a65e0fcb335799ccec1a0b7ef72b8', + './modules/Administration/UpgradeWizard_commit.php' => '391e96a960d0942100541687e8ded4ab', + './modules/Administration/UpgradeWizard.php' => '09e311f0515cc62200e39b535ad7ccfd', + './modules/Administration/UpgradeIISAccess.php' => 'f28b5f8203d1e759f9720f90137bbc1c', + './modules/Administration/updater_utils.php' => '626cdbf8ace9069bd1a012963e5ec481', + './modules/Administration/UpgradeFields.php' => '0d4606783c2ae9e605e8511a0e118191', + './modules/Administration/UpgradeAccess.php' => '2d8230957ce0ac95d4764956202bd2cf', + './modules/Administration/index.php' => '6ab549226783a8a6ad5628ab0a4c7550', + './modules/Administration/expandDatabase.php' => '88e6e137e945db23dcc3c3b3a1b79d38', + './modules/Administration/UpgradeWizardCommon.php' => '65de6441fc6d0f94ce1f5db904512626', + './modules/Administration/SupportPortal.tpl' => 'c2608013eda58535ad7ceaff45fbb2db', + './modules/Administration/Diagnostic.tpl' => 'cf1ec6c5b37859ba006458fe925bf1f1', + './modules/Administration/repairDatabase.php' => '0ee1055a74ed8e6936ae7fe5df0ecbe9', + './modules/Administration/Save.php' => '8820d9ec573f90bb107616f0e5a344b1', + './modules/Administration/RepairXSS.php' => '344293c69d1cfd206a81dc16f65ba903', + './modules/Administration/controller.php' => 'efbecd1f823622ba6c3ccb251274d277', + './modules/Administration/RepairSeedUsers.php' => 'aa568a6f3019b773ab86496d610ecbb6', + './modules/Administration/RepairJSFile.php' => '9f7634a710ea20fbcd87752ab13effb0', + './modules/Administration/RepairIndex.php' => '3992ab770c32db420d7fd560f2ae95d1', + './modules/Administration/RepairIE.php' => 'e902626f208e5a41a87cfd53c0d1fddd', + './modules/Administration/action_view_map.php' => '02226b63be1e133468f6047838997115', + './modules/Administration/UpgradeHistory.php' => '82dd740b6973fde52bafdb5e0e5f4691', + './modules/Administration/RebuildSchedulers.php' => 'd6830c651d51d966aa8aaf72053e49c8', + './modules/Administration/RebuildRelationship.php' => 'aefd2a3512ddc04ae46ad377c01d1c19', + './modules/Administration/RebuildJSLang.php' => '296049405f80d81f416cba73bc3c0969', + './modules/Administration/RebuildFulltextIndices.php' => '0a3187381e10da07834e3acb6a3577a3', + './modules/Administration/RebuildExpressionPlugins.php' => 'dbc337c8c58047aa0f64e79877bdf7f7', + './modules/Administration/RebuildDashlets.php' => 'ad5955e7b098f886da230b6228e140b3', + './modules/Administration/RebuildConfig.php' => 'f0cfcb9081364d92d1f5b64ad00528ef', + './modules/Administration/RebuildConfig.html' => 'e168d267267af1313aef423e5132ecab', + './modules/Administration/RebuildAudit.php' => '742edda237b3ea73675cf4a4b5414ad9', + './modules/Administration/QuickRepairAndRebuild.php' => '8edec44758e4622cac3ca403855a09ad', + './modules/Administration/PasswordManager.tpl' => 'a83bea75b5efad137994959162140dad', + './modules/Administration/Upgrade.php' => '30550d2d80a3bc25431344f1ea1b0c22', + './modules/Administration/Updater.php' => 'ac82b60037d73b1027948bcfdda1cba6', + './modules/Administration/SupportPortal.php' => 'aa08f5ea1a3aa708030163074cdf0089', + './modules/Administration/Menu.php' => 'b3d795eeb0207fd94afa809483eef0a5', + './modules/Administration/Locale.tpl' => '21cd1751ab0e347953cde5789ddfd65e', + './modules/Administration/RepairFieldCasing.php' => 'b19b00ee9fb585d0f0ed76f37474dbc9', + './modules/Administration/RepairActivities.php' => '3451129c5fb2238cd4474ea63ee2854c', + './modules/Administration/PasswordManager.php' => 'ac854237850e85bdbda11202b3134ec4', + './modules/Administration/ImportCustomFieldStructure.php' => '647f9b22ecd0a9c25ceafcffe44ee52b', + './modules/Administration/Forms.php' => '7069bf25e2ea8f0dea84f57888342ffa', + './modules/Administration/ExportCustomFieldStructure.php' => '96ae8db0f2bc6899ab2b64fc8172c932', + './modules/Administration/DstFix.php' => '055ec23e49d4e004e94af374b51ac21a', + './modules/Administration/DisplayWarnings.php' => '34df220bbe489ae2383d0712dd447adc', + './modules/Administration/DiagnosticRun.php' => 'fc7d37418eef959a335a53e2cb819e02', + './modules/Administration/DiagnosticDownload.php' => 'c83c765b948c58dd7c49b7bf0659bf41', + './modules/Administration/DiagnosticDelete.php' => 'dc08fd1ccf4dbf7eeed96b7c283d27a8', + './modules/Administration/Updater.html' => '04c70c9ff003335c4bea8de0382c973b', + './modules/Administration/Locale.php' => 'a42121cabed35bddcda16b1d07f73666', + './modules/Administration/Development.php' => '4c00066a4bfc60b2f2b8b5299957eb66', + './modules/Administration/CustomizeFields.php' => '35b0082f266f25617ed2099b9f15b228', + './modules/Administration/Diagnostic.php' => '2b63dd6c2b61b54e17becea02670981e', + './modules/Administration/Common.php' => 'a6d5797b16d8e8cccf53fc6aa84e6919', + './modules/Administration/Async.php' => '584be9abcffc33646555e2a3d8c7e031', + './modules/Administration/Administration.php' => '69f113587c5acb66659f8ac19de46d1e', + './modules/Activities/views/view.modulelistmenu.php' => '9efa778eae448089cb84a562f506d768', + './modules/Activities/views/view.list.php' => '02c5c45c2b372377b8cb6bf5b5c24899', + './modules/Activities/metadata/subpaneldefs.php' => '14e67382d41c1872b88fb385db9b358e', + './modules/Activities/language/en_us.lang.php' => '2cf2bd9f916453b28661237c5322e6b4', + './modules/Activities/config.php' => '3b2627039e24f44515ccdfc74ebfcc44', + './modules/Activities/SubPanelViewContacts.html' => '9f2971c6ce64f5c5cc7167b594220ce7', + './modules/Activities/SubPanelView.php' => '3eb692371455ab4315ee730ff074128d', + './modules/Activities/SubPanelView.html' => '441a3dac1aff1ba0c2307fbb6142310b', + './modules/Activities/SetAcceptStatus.php' => '56c167c5c05adb3850806573a6475e05', + './modules/Activities/Popup_picker.php' => '49b1309a0a5253f2c129b03e81c29447', + './modules/Activities/Popup_picker.html' => 'a47cea076ad0cf062049f81bf6c0671f', + './modules/Activities/OpenListView.php' => '7f437aabb36cb3095afc755dd2d6151f', + './modules/Activities/OpenListView.html' => '602ec3f7ea1feb0015d8db34cee32175', + './modules/Activities/Menu.php' => '7c068e6241e35dfccf6adf5a3ed66a7a', + './modules/Activities/Forms.php' => '8cb762e9eb0ed07d33a25fcfce415d0e', + './modules/Accounts/Account.js' => 'aaadd93f63957d23c664defeeb4974a4', + './modules/Accounts/views/view.list.php' => '640d1efee8cbd6d341551888e616302a', + './modules/Accounts/views/view.detail.php' => '1db788034f47c0f7acf536cbda3d1e5c', + './modules/Accounts/vardefs.php' => '2ccb7872aa489baa97cc45b4b009cd02', + './modules/Accounts/tpls/QuickCreate.tpl' => 'af5def51e0cf961b8bdb37e81d292b94', + './modules/Accounts/metadata/subpanels/default.php' => '5d06b046d9953c23a18b2b65cdb2b06b', + './modules/Accounts/metadata/subpanels/ForProspectLists.php' => '2c2510cc71ae4fef661e52e9ba71a005', + './modules/Accounts/metadata/subpanels/ForEmails.php' => 'd01a68523d5f403deb8f365f81e59d67', + './modules/Accounts/metadata/subpaneldefs.php' => '68279085f4821bf2cac4be2f34c7106c', + './modules/Accounts/metadata/studio.php' => '60b423a0edb569abd941710ca3383438', + './modules/Accounts/metadata/searchdefs.php' => '98e718406aa9654f709f87dfcb643f05', + './modules/Accounts/metadata/quickcreatedefs.php' => '8126f101291cd19f2546c5fc2bd724fd', + './modules/Accounts/metadata/popupdefs.php' => 'a14dbb8989162637577dc18fb75e2501', + './modules/Accounts/metadata/metafiles.php' => '0563265a72e7938964052220f440019d', + './modules/Accounts/metadata/listviewdefs.php' => 'e98b01acea18e487334a94e7117fd38a', + './modules/Accounts/metadata/fieldGroups.php' => 'e773d1cb9319008bb56c2522ab5021c4', + './modules/Accounts/metadata/editviewdefs.php' => 'b6368fe684631549be229924278ecea7', + './modules/Accounts/metadata/detailviewdefs.php' => 'e8cb94fd84edcf11f1c6115abc057a52', + './modules/Accounts/metadata/additionalDetails.php' => '47166be7d697144cca990a877b05375e', + './modules/Accounts/metadata/acldefs.php' => '8b931397415eb8cdc913a163c207cf9e', + './modules/Accounts/metadata/SearchFields.php' => 'c5bbe8c8bbf3abfd68e180ab1707d743', + './modules/Accounts/language/en_us.lang.php' => '38e5b559daa2bc85753db511b6549eb9', + './modules/Accounts/field_arrays.php' => '106c36b4c76a9be3cc79fcc93c740536', + './modules/Accounts/ShowDuplicates.php' => '20f5314b5d295100748fe56e330f03e8', + './modules/Accounts/ShowDuplicates.html' => 'e7e020a2998798b0035d4274d91ee6ff', + './modules/Accounts/Save.php' => '97cd93a301ffd3f067420b583f5c9606', + './modules/Accounts/Popup_picker.html' => '1bde804fee020802014194059f937976', + './modules/Accounts/Menu.php' => '99cbaac77be307095e364b76f6bb1b00', + './modules/Accounts/Dashlets/MyAccountsDashlet/MyAccountsDashlet.php' => '3a3af600ce95426444c110954e0a5550', + './modules/Accounts/Dashlets/MyAccountsDashlet/MyAccountsDashlet.meta.php' => '03f72a153c4075edddc3ba3ce7be9fba', + './modules/Accounts/Dashlets/MyAccountsDashlet/MyAccountsDashlet.data.php' => 'c82b508ee4f8f2368a755262dfec3964', + './modules/Accounts/AccountsQuickCreate.php' => '753f5606d9517aa9d1905dfa9b3f38ea', + './modules/Accounts/AccountFormBase.php' => '61c19c1c1e91292db336a74fa92da84b', + './modules/Accounts/Account.php' => 'b763b482d669dd38167c682e57c8b2c6', + './modules/ACLRoles/ACLRoles.js' => '0bd3ee68360d56e1d30c308a3e41aee6', + './modules/ACLRoles/views/view.list.php' => '3322a80f428bd1e850cdf0a7cff465bf', + './modules/ACLRoles/vardefs.php' => '74b07d76833db7fe1de3135940326f14', + './modules/ACLRoles/popup.tpl' => '3dfda18f986393f5b48e007573b24c72', + './modules/ACLRoles/metadata/subpanels/default.php' => '1f1796d75be2ba7c12707168f8e8b0f5', + './modules/ACLRoles/metadata/subpanels/admin.php' => '3542104728fc157a481e742e7c4f1ea5', + './modules/ACLRoles/metadata/subpaneldefs.php' => 'b331d588a8e29a1eee6fd3cf88964c6e', + './modules/ACLRoles/metadata/searchdefs.php' => '34d0cde4c0da69f86c71203d4a122bb0', + './modules/ACLRoles/metadata/popupdefs.php' => 'fcbc192e90e3c3c1413c9bc2e70bf387', + './modules/ACLRoles/metadata/listviewdefs.php' => '502ff91ae4c2307645d1a0400a30b606', + './modules/ACLRoles/metadata/SearchFields.php' => '611839f897c04352be3c04a520255ea8', + './modules/ACLRoles/language/en_us.lang.php' => '8b9830b485b9b81c80c6965ff013c1af', + './modules/ACLRoles/Save.php' => '96a53590c707b0d49acb6868523f1c35', + './modules/ACLRoles/Popup_picker.php' => '0746d71f28fc3079e04882890af40375', + './modules/ACLRoles/Popup_picker.html' => '770647d71db7a99f56a9a49d220d6e70', + './modules/ACLRoles/Menu.php' => '81d7c462edd2f34ef74afdb1e7d0c80e', + './modules/ACLRoles/ListUsers.php' => 'b1aa49e880af4f2eba3fcbe768f0ada0', + './modules/ACLRoles/Forms.php' => 'd41d8cd98f00b204e9800998ecf8427e', + './modules/ACLRoles/EditViewBody.tpl' => 'b14fe85dd531ebcae5ffe2544e3dce8a', + './modules/ACLRoles/EditView.tpl' => 'd4e46bbab0273ccbd0cbdcc2dbed3f9d', + './modules/ACLRoles/EditView.php' => '913812dcb3b030f4210ac9d74d69720a', + './modules/ACLRoles/EditRole.tpl' => '2351443b01ebeffcd46a4d36fbc38a72', + './modules/ACLRoles/EditRole.php' => '4adb16d298a49f87702c9479f833754e', + './modules/ACLRoles/EditAllBody.tpl' => 'ae4adc42ac97354c095c29b10d85b51f', + './modules/ACLRoles/DetailViewUser.tpl' => '657b774282f68fc37dc8c8d8b9b77751', + './modules/ACLRoles/DetailViewBody.tpl' => 'bd46bb5d18ae394f19ff7e9aec909beb', + './modules/ACLRoles/DetailView.tpl' => '91dce288c76628529a523c80425c6bf0', + './modules/ACLRoles/DetailView.php' => 'ef51f8b1296deebfe6271ba2ccd34132', + './modules/ACLRoles/DetailUserRole.php' => '00f1101abf19e5e012b5c9c06dc75cd0', + './modules/ACLRoles/Delete.php' => '52df20fce849f424f27eaf23dad7d166', + './modules/ACLRoles/ACLRole.php' => '80ba5c9f82fbf1161e0da056c5a6737e', + './modules/ACLActions/vardefs.php' => '56901797986eb3077d243e42f7c07b27', + './modules/ACLActions/metadata/subpaneldefs.php' => '44fde78af7fc63c493207f50a84cfb0c', + './modules/ACLActions/language/en_us.lang.php' => 'e02750afad49f3660d697497767c8460', + './modules/ACLActions/actiondefs.php' => '260cf35c9f8f54a3bd901205c957ae15', + './modules/ACLActions/Menu.php' => '4e419af53d8e00ec63e6b54d25d4607f', + './modules/ACLActions/Forms.php' => 'd41d8cd98f00b204e9800998ecf8427e', + './modules/ACLActions/ACLAction.php' => 'f673ef7bced8513bf68431771800fb2e', + './modules/ACL/vardefs.php' => 'a0bb6947c5dd41edd02000f4fa3583e4', + './modules/ACL/remove_actions.php' => '1d521e3e7b37b81fb05a24c7f7eb0709', + './modules/ACL/metadata/subpaneldefs.php' => '44fde78af7fc63c493207f50a84cfb0c', + './modules/ACL/language/en_us.lang.php' => '370abfe5b94cd3997332aebb6f73bec5', + './modules/ACL/install_actions.php' => 'a02b58a42ce84ab7318a720426edae39', + './modules/ACL/Save.php' => '17f5017f24502538bbbf399128e74111', + './modules/ACL/Menu.php' => '4e419af53d8e00ec63e6b54d25d4607f', + './modules/ACL/List.php' => '863a968e6e27b80fc2501120c1683994', + './modules/ACL/Forms.php' => 'd41d8cd98f00b204e9800998ecf8427e', + './modules/ACL/ACLJSController.php' => 'a8cefd0b088bae46168acbf514b6ce74', + './modules/ACL/ACLController.php' => 'a7ee7846c43fd81c606b246592c3a590', + './metagen.php' => '80dfab586cf8640852d36683d4007cad', + './metadata/documents_opportunitiesMetaData.php' => 'b776892c7a27b7e666b6bb4e23e94774', + './metadata/documents_contactsMetaData.php' => '6941f4fe0715d55f9aa7cea3af00b561', + './metadata/documents_casesMetaData.php' => 'ca42c730a65e33487f1bee05a80cb0a5', + './metadata/documents_bugsMetaData.php' => '60526589bfad1dabea30dd1e0bff7e7d', + './metadata/documents_accountsMetaData.php' => '1a40c95528106d1fba63e1dea97f961e', + './metadata/users_signaturesMetaData.php' => '67c651bc9ed014ea15ac9fdd2f6bab61', + './metadata/users_passwordLinkMetaData.php' => '142fbf7843981a13065b0d9ecc767302', + './metadata/users_last_importMetaData.php' => '9ab931c7b2e6ef9dbd8a3505ec1814dd', + './metadata/usersMetaData.php' => 'fbd92f30ed0272e500754a7c57b92eac', + './metadata/user_feedsMetaData.php' => 'd3bd694d277da6b2aa8d2bcdd1835d8b', + './metadata/schedulers_timesMetaData.php' => '72f76139cf0b648e5f519d3e00066d35', + './metadata/roles_usersMetaData.php' => 'ec1920cb8a866a2d705d9e18eb52260d', + './metadata/roles_modulesMetaData.php' => 'f8c0fe75cfd118f31eaf01b9057595f7', + './metadata/queues_queueMetaData.php' => '4e60ab7d775111fe5a88bdb76a6cb75f', + './metadata/queues_beansMetaData.php' => 'a6fb690f6b43654b110eacd7ea1ebbf2', + './metadata/prospect_lists_prospectsMetaData.php' => '0560912ae453e085ef73237f2551c978', + './metadata/prospect_list_campaignsMetaData.php' => 'ca02ac08ff94c6ab02b28a6ae0c4dbb1', + './metadata/projects_quotesMetaData.php' => '4be3d068e848b5d473f5cfbcd0b8daa5', + './metadata/projects_opportunitiesMetaData.php' => '8a5cca0c5090e54b4a37bd72094ba14f', + './metadata/projects_contactsMetaData.php' => 'd568b27baa934ce1cd34b43b9ae784dd', + './metadata/projects_accountsMetaData.php' => 'b542add1efa244747882d1d5091902aa', + './metadata/project_task_project_tasksMetaData.php' => 'e3e041e24142483bce72ab9cb3fc41f3', + './metadata/project_relationMetaData.php' => '81a6b4aa262d6ec95671033fd3cf2a17', + './metadata/project_productsMetaData.php' => 'b195958e9cd92435ddefc1f29f59af6c', + './metadata/project_casesMetaData.php' => 'b1c44dcc5b91d3d6b2090f8a768530ef', + './metadata/project_bugsMetaData.php' => '7d70027464ad16b62cc8f320bd8d767b', + './metadata/outboundEmailMetaData.php' => 'daa846dade10e9f93ebbdc244b88b2d6', + './metadata/opportunities_contactsMetaData.php' => '4cbcf355929ce9fff264fcb85cb74f74', + './metadata/meetings_usersMetaData.php' => '7572c7925f3eacf2bf812ddfda582d9f', + './metadata/meetings_leadsMetaData.php' => 'e0af35e3e18940eef9f07e2d63a66b29', + './metadata/meetings_contactsMetaData.php' => 'f060b980ab328a2c07cee26a060f8b91', + './metadata/linked_documentsMetaData.php' => '4912a3b9a7dd02184d75e5af45102056', + './metadata/kbdocuments_views_ratingsMetaData.php' => '96d7a46c751de8f677978d355e837e37', + './metadata/inboundEmail_cacheTimestampMetaData.php' => 'b0a12c16859f8eb5c622a5056b492152', + './metadata/inboundEmail_autoreplyMetaData.php' => 'b380d666de5b57f4276d18432cbde141', + './metadata/import_mapsMetaData.php' => 'fbd92f30ed0272e500754a7c57b92eac', + './metadata/foldersMetaData.php' => 'a9263e7f6e7001c15c129b9c57b37a0f', + './metadata/fields_meta_dataMetaData.php' => 'fbd92f30ed0272e500754a7c57b92eac', + './metadata/emails_beansMetaData.php' => '4e01d0385cb35201c84cf3be307250af', + './metadata/email_marketing_prospect_listsMetaData.php' => 'f7830fe5246d2932ad4c4a717ad2a956', + './metadata/email_cacheMetaData.php' => '067d13920f88864eacc1ae54b2b0df3a', + './metadata/email_addressesMetaData.php' => '36d7a888e737eeebb1bd7100dbf8ed98', + './metadata/custom_fieldsMetaData.php' => '469a0e40bb1cbe229a15326eb664243d', + './metadata/contacts_usersMetaData.php' => '45a4a253009fbfa71fcb8ba4d179968c', + './metadata/contacts_casesMetaData.php' => '691a92b305bb34e379d16a0119d4dd31', + './metadata/contacts_bugsMetaData.php' => '37ac1fbd8d92c3eac21766f8e3535e0c', + './metadata/configMetaData.php' => 'fbd92f30ed0272e500754a7c57b92eac', + './metadata/cases_bugsMetaData.php' => '71298125bde0aded1619c232e07f65bb', + './metadata/calls_usersMetaData.php' => '635f8011edf4d11c4e31bb63064c7b8f', + './metadata/calls_leadsMetaData.php' => '6e480abab966a8e3604d09db8de9eaa6', + './metadata/calls_contactsMetaData.php' => '3dcf697cd830cd731ac73621a72e1442', + './metadata/audit_templateMetaData.php' => '7ffbb7f84bb4e387018fc836716a828d', + './metadata/addressBookMetaData.php' => '7f741cceddf56ded991313ae29a45e84', + './metadata/acl_roles_usersMetaData.php' => '674bb5e51c78aa11540d6cc834f6fca3', + './metadata/acl_roles_actionsMetaData.php' => '6cdac7aa5fed3c23a7c1f4979f277d32', + './metadata/accounts_opportunitiesMetaData.php' => '7a8f9cd199bc54e6e15f6f4771b8fdac', + './metadata/accounts_contactsMetaData.php' => 'c8f05d76641a9df3a8f160e80341bb0b', + './metadata/accounts_casesMetaData.php' => '3210123d15c162e4e406ca0b24759991', + './metadata/accounts_bugsMetaData.php' => 'a04724023df98e4ee65831f5e1b942e7', + './maintenance.php' => 'b8f1850c321a12bf41d7b91385858f1c', + './log_file_restricted.html' => 'db7ac0ce0822e215c1c62e5592e56eac', + './log4php/LoggerManager.php' => 'fa34194306cd50c01b71d8d5060ee362', + './leadCapture.php' => '6acff84b622ac060efef67d110f8f10b', + './jssource/src_files/include/JSON.js' => '513eb0113124c215e17c1495f8a202dd', + './jssource/src_files/include/MySugar/javascript/MySugar.js' => '320180d49455ae9978863f9d211a858f', + './jssource/src_files/include/SubPanel/SubPanelTiles.js' => 'a3f311e30548aa66e34a8a8542bb9eea', + './jssource/src_files/include/SugarCharts/Jit/FlashCanvas/canvas2png.js' => '4c95a8c2071e0d5b4ae1531a790f1492', + './jssource/src_files/include/SugarCharts/Jit/FlashCanvas/flashcanvas.js' => 'c06bd0d01f1daa8ee7c54b83fe33f03a', + './jssource/src_files/include/SugarCharts/Jit/js/Jit/jit.js' => '569389f06a8902b9ca8ee28d1526149b', + './jssource/src_files/include/SugarCharts/Jit/js/mySugarCharts.js' => 'ea73d4e9be70f83c81fbea0e6864fe5a', + './jssource/src_files/include/SugarCharts/Jit/js/sugarCharts.js' => '5274ef040f4f386cd89b552b613644e6', + './jssource/src_files/include/SugarDependentDropdown/javascript/SugarDependentDropdown.js' => 'c7d0f70a1f6108ad01b66065d07ce3b0', + './jssource/src_files/include/SugarEmailAddress/SugarEmailAddress.js' => 'd1f2d39aeb58defc6c9e647792459621', + './jssource/src_files/include/SugarFields/Fields/Address/SugarFieldAddress.js' => '2230e649a72034d4e7aefe81fb964ccf', + './jssource/src_files/include/SugarFields/Fields/Collection/SugarFieldCollection.js' => 'd453a1b2ee708c96b17fe9e43c676c68', + './jssource/src_files/include/SugarFields/Fields/Datetimecombo/Datetimecombo.js' => 'f5868f390ce9f214331f1c0c4feddf9f', + './jssource/src_files/include/SugarFields/Fields/File/SugarFieldFile.js' => 'ec13311644ef4adddd6933491047492f', + './jssource/src_files/include/connectors/formatters/default/company_detail.js' => 'bf41167826e3fd4019fb46a69e7d7560', + './jssource/src_files/include/javascript/cookie.js' => 'eb329b102eecc7a6278e7c2712a531b5', + './jssource/src_files/include/javascript/dashlets.js' => 'aa8ae5e5853d88389628f36feca2554d', + './jssource/src_files/include/javascript/include.js' => '4fd5d7da5c00e4c0a9a83b4b65a493f1', + './jssource/src_files/include/javascript/jsclass_async.js' => '616ca1070d5e3f3bf6dcb210a59b302c', + './jssource/src_files/include/javascript/jsclass_base.js' => '3f5f1bd86e7b3c501431a71269200cdd', + './jssource/src_files/include/javascript/menu.js' => '21f57ea7c6d0ab2166021bb928d98251', + './jssource/src_files/include/javascript/overlibmws.js' => '9fb2df046948fb09baf9bf62cf8d7877', + './jssource/src_files/include/javascript/overlibmws_iframe.js' => '3714ae1a5be03f1470b30e8920386d14', + './jssource/src_files/include/javascript/popup_helper.js' => 'b329eaa528e55e17a70bca7e450ee865', + './jssource/src_files/include/javascript/popup_parent_helper.js' => '2753b1b6d525a4e1245605d544252465', + './jssource/src_files/include/javascript/quickCompose.js' => 'c87742cdae04b75afc7e59c9e9440d39', + './jssource/src_files/include/javascript/quicksearch.js' => 'f1660fd0ecb23c3ce215e0f1992442a6', + './jssource/src_files/include/javascript/report_additionals.js' => '7d8f86186481775d3f2b9577f62d7e01', + './jssource/src_files/include/javascript/sugar_3.js' => 'c9fb3f4ee58114e99226229c9f24a350', + './jssource/src_files/include/javascript/sugar_connection_event_listener.js' => '3f0ed5a6340391e82521b208d6b39e8d', + './jssource/src_files/include/javascript/sugarwidgets/SugarYUILoader.js' => '91ce3f8311a938d63f6f4f41a2780855', + './jssource/src_files/include/javascript/sugarwidgets/SugarYUIWidgets.js' => '18d0fbff67ee96b852f8d3bf2d033978', + './jssource/src_files/include/javascript/swfobject.js' => 'a7dc61c4ada3b828e0e09e51f943c6db', + './jssource/src_files/include/javascript/yui3/assets/dpSyntaxHighlighter.js' => '9f8e259fd1682f21971db93c2465812a', + './jssource/src_files/include/javascript/yui3/assets/syntax.js' => '3dcb7c2cccb0b8d6eaa0bf2700a14645', + './jssource/src_files/include/javascript/yui3/build/anim/anim-base-min.js' => '5cd35b730551e2f143f8b2aeb3dc43f0', + './jssource/src_files/include/javascript/yui3/build/anim/anim-base.js' => '18155aa48babf0db52f49ef2df3fa355', + './jssource/src_files/include/javascript/yui3/build/anim/anim-color-min.js' => 'faec1c0ed471704a006e95b4865f2a61', + './jssource/src_files/include/javascript/yui3/build/anim/anim-color.js' => 'dbfbd467f74fd9706942a4dcc1798508', + './jssource/src_files/include/javascript/yui3/build/anim/anim-curve-min.js' => '1867dfb160e262228341cc1a7da74d3f', + './jssource/src_files/include/javascript/yui3/build/anim/anim-curve.js' => 'a8fa1f8d3176b2b77228d7324d7e28cc', + './jssource/src_files/include/javascript/yui3/build/anim/anim-easing-min.js' => '3b25c5521f9a0eba5c761b42f1d7c90a', + './jssource/src_files/include/javascript/yui3/build/anim/anim-easing.js' => '1936ddcbb402ea9772b9bffa41e1d85b', + './jssource/src_files/include/javascript/yui3/build/anim/anim-min.js' => '6d754f4c4fee88a77c5939babc20b08d', + './jssource/src_files/include/javascript/yui3/build/anim/anim-node-plugin-min.js' => 'b74864d9fe6ce5bb68002950abb7f4d9', + './jssource/src_files/include/javascript/yui3/build/anim/anim-node-plugin.js' => '0e8bb8913787d98c7dbd6842a783b068', + './jssource/src_files/include/javascript/yui3/build/anim/anim-scroll-min.js' => 'c2e2f8abedb377ad656bf4cb79600a6d', + './jssource/src_files/include/javascript/yui3/build/anim/anim-scroll.js' => '64f2edf606cbd8bdf2763b6321e28801', + './jssource/src_files/include/javascript/yui3/build/anim/anim-xy-min.js' => '6850aba5ef84ad2912ed491e2eae46ce', + './jssource/src_files/include/javascript/yui3/build/anim/anim-xy.js' => '78ca48b8bbe8b917e818def37804b9aa', + './jssource/src_files/include/javascript/yui3/build/anim/anim.js' => '58e7b584e85972b486c9e1d3f0647428', + './jssource/src_files/include/javascript/yui3/build/async-queue/async-queue-min.js' => 'ffd73da1dcddab565bbd50c16873581d', + './jssource/src_files/include/javascript/yui3/build/async-queue/async-queue.js' => '04d2c0f553fff5b53f4b239662c99806', + './jssource/src_files/include/javascript/yui3/build/attribute/attribute-base-min.js' => 'f62e92ea97016fe0125d224eb5ff8272', + './jssource/src_files/include/javascript/yui3/build/attribute/attribute-base.js' => 'd88e857d7401b689cedc605f290d9f96', + './jssource/src_files/include/javascript/yui3/build/attribute/attribute-complex-min.js' => 'ca78452cabfa8a6d001ccb05aa442bf3', + './jssource/src_files/include/javascript/yui3/build/attribute/attribute-complex.js' => '87957b017c75b79ecd9c1f586ab3b621', + './jssource/src_files/include/javascript/yui3/build/attribute/attribute-min.js' => '4b846745a8c917c6885c7c75ce630c45', + './jssource/src_files/include/javascript/yui3/build/attribute/attribute.js' => '39d35aa02bb83866ea2efbfcbeaa3631', + './jssource/src_files/include/javascript/yui3/build/base/base-base-min.js' => 'd3574e77aedcb6d77fe42f65ba82d90c', + './jssource/src_files/include/javascript/yui3/build/base/base-base.js' => '0f3295ad24f08dc27a7774af785a65b8', + './jssource/src_files/include/javascript/yui3/build/base/base-build-min.js' => '477ad185b0b7d00376a84a20b4e8845b', + './jssource/src_files/include/javascript/yui3/build/base/base-build.js' => 'c8dc5087a3d3fb24af6a83efe1ac4a27', + './jssource/src_files/include/javascript/yui3/build/base/base-min.js' => 'ec3f0972e25534ac6d174100f64a9463', + './jssource/src_files/include/javascript/yui3/build/base/base-pluginhost-min.js' => 'c7fece0a58c7e24a82df90083af76d55', + './jssource/src_files/include/javascript/yui3/build/base/base-pluginhost.js' => '3555cba0946209ec58d6c7fa298083eb', + './jssource/src_files/include/javascript/yui3/build/base/base.js' => 'a0726f5ded064913b374a218d52fadb0', + './jssource/src_files/include/javascript/yui3/build/cache/cache-min.js' => '3d336358405079ad391fd1f456239a88', + './jssource/src_files/include/javascript/yui3/build/cache/cache.js' => 'd3ffbda96ddeb5b2eb1643dda354b5cc', + './jssource/src_files/include/javascript/yui3/build/classnamemanager/classnamemanager-min.js' => '9618fe08329cb8ab8858db0457bc7beb', + './jssource/src_files/include/javascript/yui3/build/classnamemanager/classnamemanager.js' => '0d314e7fb9508e153dcddbb6790585f3', + './jssource/src_files/include/javascript/yui3/build/collection/collection-min.js' => 'a42ba321627b043c58d75996416af1d1', + './jssource/src_files/include/javascript/yui3/build/collection/collection.js' => '19c11e1ef14f56a57e32fbd4cd14035c', + './jssource/src_files/include/javascript/yui3/build/compat/compat-min.js' => '8c2cd1bbe7e4641a318f534180683b9f', + './jssource/src_files/include/javascript/yui3/build/compat/compat.js' => '4dab80fb6d64ac22fa3b1ddc7d829970', + './jssource/src_files/include/javascript/yui3/build/console/console-filters-min.js' => '6f81e8637d5241e3859a3843a73de5f7', + './jssource/src_files/include/javascript/yui3/build/console/console-filters.js' => 'bbffa94dca8a3f0bd780537db226438e', + './jssource/src_files/include/javascript/yui3/build/console/console-min.js' => '909d1783e8842e0dcd45e6623066cc66', + './jssource/src_files/include/javascript/yui3/build/console/console.js' => '8ac45ef6432e7d80506570ecbe7aff59', + './jssource/src_files/include/javascript/yui3/build/cookie/cookie-min.js' => '138949f035bc27916e29082e0388d187', + './jssource/src_files/include/javascript/yui3/build/cookie/cookie.js' => '3344f4c1cab1d944cc0d480fd2d06b7c', + './jssource/src_files/include/javascript/yui3/build/dataschema/dataschema-array-min.js' => '69031268bd2e02eb1a580107d6e4fa3f', + './jssource/src_files/include/javascript/yui3/build/dataschema/dataschema-array.js' => '6f50a80e0a683c75a4eb8bd14771ef5f', + './jssource/src_files/include/javascript/yui3/build/dataschema/dataschema-base-min.js' => '1c98550b0a52d7523b8d8a4793a8b8b6', + './jssource/src_files/include/javascript/yui3/build/dataschema/dataschema-base.js' => '93a950bbb44e09ad53eca42a0b925872', + './jssource/src_files/include/javascript/yui3/build/dataschema/dataschema-json-min.js' => 'a779e5c234d4642ec8edf66ed15ccd34', + './jssource/src_files/include/javascript/yui3/build/dataschema/dataschema-json.js' => '14578f749fdffa3242912b0b60c58edd', + './jssource/src_files/include/javascript/yui3/build/dataschema/dataschema-min.js' => '9678fbae88ef1ab62804a6dfd1b7735c', + './jssource/src_files/include/javascript/yui3/build/dataschema/dataschema-text-min.js' => 'f2a605ce4c79fcfd4c17776a65ffb6e4', + './jssource/src_files/include/javascript/yui3/build/dataschema/dataschema-text.js' => '35c103827e2aa0c7c2449300c9153c4c', + './jssource/src_files/include/javascript/yui3/build/dataschema/dataschema-xml-min.js' => '8be1c2da27fee8c14f9a727e83365252', + './jssource/src_files/include/javascript/yui3/build/dataschema/dataschema-xml.js' => 'd32406b650edfb570bdf9e7f9207bc57', + './jssource/src_files/include/javascript/yui3/build/dataschema/dataschema.js' => 'fb1cf323354ac9963cec4dc7b38c9051', + './jssource/src_files/include/javascript/yui3/build/datasource/datasource-arrayschema-min.js' => 'f1f52de48b844a3bb82b2599beb32a9e', + './jssource/src_files/include/javascript/yui3/build/datasource/datasource-arrayschema.js' => 'd1b1d57aeabf70cf99f55c7c5a1660a8', + './jssource/src_files/include/javascript/yui3/build/datasource/datasource-cache-min.js' => '2aaf531204f8be7cd34254f79979b522', + './jssource/src_files/include/javascript/yui3/build/datasource/datasource-cache.js' => '137a174c1d2a2aa30eead39bfed62303', + './jssource/src_files/include/javascript/yui3/build/datasource/datasource-function-min.js' => 'ca1c83fd7d2878cfc403571e4900b66f', + './jssource/src_files/include/javascript/yui3/build/datasource/datasource-function.js' => '0b3c1a9cf7fa787752b6e127aa7b54e0', + './jssource/src_files/include/javascript/yui3/build/datasource/datasource-get-min.js' => '0bd20dcfc0b4cda1b603f64d48a393ac', + './jssource/src_files/include/javascript/yui3/build/datasource/datasource-get.js' => 'b55289d7ffc274e4a8186b60fcf29df1', + './jssource/src_files/include/javascript/yui3/build/datasource/datasource-io-min.js' => '32d0bd2aa6343f731573ae3dc7f27216', + './jssource/src_files/include/javascript/yui3/build/datasource/datasource-io.js' => '1eb4521e16ed47a09f4b1b09f39aee5f', + './jssource/src_files/include/javascript/yui3/build/datasource/datasource-jsonschema-min.js' => '128f90bd4e596a1684555d1efef42206', + './jssource/src_files/include/javascript/yui3/build/datasource/datasource-jsonschema.js' => 'cf391fbe5cb2f7045b181dae657e80cc', + './jssource/src_files/include/javascript/yui3/build/datasource/datasource-local-min.js' => '92065f142e10742bac58ef4e7e2bff81', + './jssource/src_files/include/javascript/yui3/build/datasource/datasource-local.js' => 'dce1f44b2c2b6956749fe77e03d7fc95', + './jssource/src_files/include/javascript/yui3/build/datasource/datasource-min.js' => 'c7cbbcb655a90fbc60cb37963e30d1d8', + './jssource/src_files/include/javascript/yui3/build/datasource/datasource-polling-min.js' => '7190cb146692fd7dcfab60e9dd741964', + './jssource/src_files/include/javascript/yui3/build/datasource/datasource-polling.js' => '5b564a1d5b9c1d32a8da581083ad48ae', + './jssource/src_files/include/javascript/yui3/build/datasource/datasource-textschema-min.js' => '88f44a6a3e9a27abb14e15c30f2f87af', + './jssource/src_files/include/javascript/yui3/build/datasource/datasource-textschema.js' => '625a4210d8f4a98dcfe4925acfb7a476', + './jssource/src_files/include/javascript/yui3/build/datasource/datasource-xmlschema-min.js' => '79d203f0961fba519b55abb1c25643ad', + './jssource/src_files/include/javascript/yui3/build/datasource/datasource-xmlschema.js' => '400580b0f55aeeb56b68901a3ef74db5', + './jssource/src_files/include/javascript/yui3/build/datasource/datasource.js' => '643d0b46d35a2c005c65f416adce84ad', + './jssource/src_files/include/javascript/yui3/build/datatype/datatype-date-format-min.js' => 'd3fe986624bef00a9a86b4ebe3edacd9', + './jssource/src_files/include/javascript/yui3/build/datatype/datatype-date-format.js' => '4ada5cec6d940400dc29c9314154fa39', + './jssource/src_files/include/javascript/yui3/build/datatype/datatype-date-min.js' => '1cb868ef524784e77410177dedd757d4', + './jssource/src_files/include/javascript/yui3/build/datatype/datatype-date-parse-min.js' => 'f63578c4a13a7d84f67a205e0e1f99cb', + './jssource/src_files/include/javascript/yui3/build/datatype/datatype-date-parse.js' => '0e5e71d81afa0ca4d2f4bd85a28464b0', + './jssource/src_files/include/javascript/yui3/build/datatype/datatype-date.js' => 'fa2fecc54e9316cbc6a4963cccd1d2fc', + './jssource/src_files/include/javascript/yui3/build/datatype/datatype-min.js' => '75f35499ef8780e116e938d20c2e9079', + './jssource/src_files/include/javascript/yui3/build/datatype/datatype-number-format-min.js' => 'e49e62c36cbdc8b8c72a69c01ac48a12', + './jssource/src_files/include/javascript/yui3/build/datatype/datatype-number-format.js' => 'c53b2d6afcb2b8c6f2f756cc5e9f7078', + './jssource/src_files/include/javascript/yui3/build/datatype/datatype-number-min.js' => 'dfe5cb43cf7af2029d7d505829fd84d4', + './jssource/src_files/include/javascript/yui3/build/datatype/datatype-number-parse-min.js' => '186fe53982cf5aba044c145d80c2867e', + './jssource/src_files/include/javascript/yui3/build/datatype/datatype-number-parse.js' => 'e08c5f42a825d5da46e0d9f81afe078b', + './jssource/src_files/include/javascript/yui3/build/datatype/datatype-number.js' => '02638e9474f696e9ce67be34df9916ea', + './jssource/src_files/include/javascript/yui3/build/datatype/datatype-xml-format-min.js' => 'f4169b2bfb1999706dcf27a318e37724', + './jssource/src_files/include/javascript/yui3/build/datatype/datatype-xml-format.js' => '8fb5d6f4700e05ed35f1f0adae94f59c', + './jssource/src_files/include/javascript/yui3/build/datatype/datatype-xml-min.js' => '86b666d7dba4c6e507737619f40a1e84', + './jssource/src_files/include/javascript/yui3/build/datatype/datatype-xml-parse-min.js' => '15ff7616eee27f39f16c442bafc797cf', + './jssource/src_files/include/javascript/yui3/build/datatype/datatype-xml-parse.js' => 'e381b39554519005af7735336711fd6c', + './jssource/src_files/include/javascript/yui3/build/datatype/datatype-xml.js' => '9f973a51339581182cf415a43dc0bd8e', + './jssource/src_files/include/javascript/yui3/build/datatype/datatype.js' => 'd6b74d0063e70bd61f94ebc5e88a9cfe', + './jssource/src_files/include/javascript/yui3/build/dd/dd-constrain-min.js' => '16c59fa7174b49d467bdb9258e6abc45', + './jssource/src_files/include/javascript/yui3/build/dd/dd-constrain.js' => '55f2690d7ad3cd4887efc7603d1ed871', + './jssource/src_files/include/javascript/yui3/build/dd/dd-ddm-base-min.js' => '7415c15fa8289ca08efd42c7befc2b2d', + './jssource/src_files/include/javascript/yui3/build/dd/dd-ddm-base.js' => '6affa269ba6a632a0de33e2b0f165786', + './jssource/src_files/include/javascript/yui3/build/dd/dd-ddm-drop-min.js' => '7a396b76f4ad26c47ce7043f03cd09f1', + './jssource/src_files/include/javascript/yui3/build/dd/dd-ddm-drop.js' => '6da4459840d66f7a800b981531d398fa', + './jssource/src_files/include/javascript/yui3/build/dd/dd-ddm-min.js' => 'e26291c55920472473f007de55414040', + './jssource/src_files/include/javascript/yui3/build/dd/dd-ddm.js' => '14f5bb96096d9cae1aae54e12ce9bc9c', + './jssource/src_files/include/javascript/yui3/build/dd/dd-drag-min.js' => '3a69676605e4b1ca934bef31c0e2a1a0', + './jssource/src_files/include/javascript/yui3/build/dd/dd-drag.js' => 'c13d52831074aa270dfb2568bceb64f2', + './jssource/src_files/include/javascript/yui3/build/dd/dd-drop-min.js' => '1c6f5bff30addd2fdd52453887710d5e', + './jssource/src_files/include/javascript/yui3/build/dd/dd-drop-plugin-min.js' => '37ee9d8832740430d8a59c3c9580c36f', + './jssource/src_files/include/javascript/yui3/build/dd/dd-drop-plugin.js' => 'df088492b3aa8526f836f4fabd5e8886', + './jssource/src_files/include/javascript/yui3/build/dd/dd-drop.js' => 'c9cf6631655ffd33a0f4f799dfcec08d', + './jssource/src_files/include/javascript/yui3/build/dd/dd-min.js' => '4928b5e84cdb8cb9e4db74242536de93', + './jssource/src_files/include/javascript/yui3/build/dd/dd-plugin-min.js' => '8a6843fc23fb0236c7bc149da7cd4a7e', + './jssource/src_files/include/javascript/yui3/build/dd/dd-plugin.js' => '3e377fe4cdcfba84863246ec64eead6a', + './jssource/src_files/include/javascript/yui3/build/dd/dd-proxy-min.js' => '58718da0577fbaac45f29bc1dc5598fe', + './jssource/src_files/include/javascript/yui3/build/dd/dd-proxy.js' => '08d6db9329dc183e9ab3862eef222cff', + './jssource/src_files/include/javascript/yui3/build/dd/dd-scroll-min.js' => '8b090928f1a78df880fa07be309f06b4', + './jssource/src_files/include/javascript/yui3/build/dd/dd-scroll.js' => '511f2cfccf52fb287f3d77b860f86a4e', + './jssource/src_files/include/javascript/yui3/build/dd/dd.js' => '98b8dc6b71ab1ecf70d178408c838339', + './jssource/src_files/include/javascript/yui3/build/dom/dom-base-min.js' => 'af6d5a8b6932e73a1898b46e9a49c34e', + './jssource/src_files/include/javascript/yui3/build/dom/dom-base.js' => 'ff2ddc03dfca759433dab25e52dcc756', + './jssource/src_files/include/javascript/yui3/build/dom/dom-min.js' => 'ac34ca5cb5df6256359b5e8c96bc3d35', + './jssource/src_files/include/javascript/yui3/build/dom/dom-screen-min.js' => 'd48e1e218269e223538aa6c55213449e', + './jssource/src_files/include/javascript/yui3/build/dom/dom-screen.js' => 'ad227284062ab1ff108be855dc9dd92d', + './jssource/src_files/include/javascript/yui3/build/dom/dom-style-min.js' => 'b2d4524328a6fe2c92447902e7245854', + './jssource/src_files/include/javascript/yui3/build/dom/dom-style.js' => '46499a455dcab9bfe96b744e72a05a36', + './jssource/src_files/include/javascript/yui3/build/dom/dom.js' => '973e38e8aa8d341262f11170fd71c572', + './jssource/src_files/include/javascript/yui3/build/dom/selector-css2-min.js' => 'ecfafbd6551dafd6889d74270e09cc15', + './jssource/src_files/include/javascript/yui3/build/dom/selector-css2.js' => '15cb5d0f8af3670c6d9fa52dbc0394b3', + './jssource/src_files/include/javascript/yui3/build/dom/selector-css3-min.js' => '1636b87c8be9baa58b3e29fcf911f8f3', + './jssource/src_files/include/javascript/yui3/build/dom/selector-css3.js' => '8aa951fc273ef8cf3559d5ff23aec74d', + './jssource/src_files/include/javascript/yui3/build/dom/selector-min.js' => 'd985864d04368bf3a0a2ab926d7cc6e5', + './jssource/src_files/include/javascript/yui3/build/dom/selector-native-min.js' => 'f2c02fb0e7bc3aef48dbd38618a1296f', + './jssource/src_files/include/javascript/yui3/build/dom/selector-native.js' => '2f48d39b9cfbcc94a152493c95d691e7', + './jssource/src_files/include/javascript/yui3/build/dom/selector.js' => '46e7510a714f115ae38df8acf5afd8e2', + './jssource/src_files/include/javascript/yui3/build/dump/dump-min.js' => '8931348bb06babc4b466c52053f20763', + './jssource/src_files/include/javascript/yui3/build/dump/dump.js' => '1ffbaba6c42a7d8051c419e5304c2248', + './jssource/src_files/include/javascript/yui3/build/event-custom/event-custom-base-min.js' => '409f4cf4d5ea4881f88228715de9e1a4', + './jssource/src_files/include/javascript/yui3/build/event-custom/event-custom-base.js' => '0d5d16aeba48c23e7c5986fab181761f', + './jssource/src_files/include/javascript/yui3/build/event-custom/event-custom-complex-min.js' => '6d360c63f782bf22e97025ffc8bb4e50', + './jssource/src_files/include/javascript/yui3/build/event-custom/event-custom-complex.js' => 'e14a79e33d4d78bb00c6d7bac0bc20df', + './jssource/src_files/include/javascript/yui3/build/event-custom/event-custom-min.js' => 'd86742304c0b2c5d551cc30a2f30def4', + './jssource/src_files/include/javascript/yui3/build/event-custom/event-custom.js' => '65f477457358d76b42bb7463357d42d4', + './jssource/src_files/include/javascript/yui3/build/event-simulate/event-simulate-min.js' => 'f1b5f16529537e2931e95e0d6dfa5e1e', + './jssource/src_files/include/javascript/yui3/build/event-simulate/event-simulate.js' => '3bafb16813ddf414f80fc898dfb0cfc1', + './jssource/src_files/include/javascript/yui3/build/event/event-base-min.js' => '52c133eedcd782428299dd98b96850b6', + './jssource/src_files/include/javascript/yui3/build/event/event-base.js' => '98952d7c2486e19f428bdd35922886ec', + './jssource/src_files/include/javascript/yui3/build/event/event-delegate-min.js' => 'e775d7a6ce602d63537a6492f7c9639b', + './jssource/src_files/include/javascript/yui3/build/event/event-delegate.js' => '633b634152c8e0017109ef8070aa321d', + './jssource/src_files/include/javascript/yui3/build/event/event-focus-min.js' => 'd421b02d12c98a5ece975dcec6bc5673', + './jssource/src_files/include/javascript/yui3/build/event/event-focus.js' => '1b2e6919bf0d0c7f73952898baf1db5f', + './jssource/src_files/include/javascript/yui3/build/event/event-key-min.js' => '14b3c30e812ba583952da0f54fa0a72a', + './jssource/src_files/include/javascript/yui3/build/event/event-key.js' => '5b11552a5699e40a7ea7a26ad6153a34', + './jssource/src_files/include/javascript/yui3/build/event/event-min.js' => 'bf7dd7b1b59bf79616197332a24e10b9', + './jssource/src_files/include/javascript/yui3/build/event/event-mouseenter-min.js' => '8c0a6e0e9d7990792faefbf1792fb26f', + './jssource/src_files/include/javascript/yui3/build/event/event-mouseenter.js' => 'a9efbd15212583e8c493f746e3d8b7fb', + './jssource/src_files/include/javascript/yui3/build/event/event-mousewheel-min.js' => 'a905b66143ea8ff6a40fce21415ca815', + './jssource/src_files/include/javascript/yui3/build/event/event-mousewheel.js' => '7ae089ca40cd2a2fc2896a99b9448e79', + './jssource/src_files/include/javascript/yui3/build/event/event-resize-min.js' => '35ac1a26f54703c42b3a5f2a941064a6', + './jssource/src_files/include/javascript/yui3/build/event/event-resize.js' => '8169feb99c34ee02acaf40539ca6e34c', + './jssource/src_files/include/javascript/yui3/build/event/event.js' => 'eee21c85b735076d77f7c1cdbdae6f9d', + './jssource/src_files/include/javascript/yui3/build/get/get-min.js' => 'f34507a2bb860f2e50526f9ccbd4bb7a', + './jssource/src_files/include/javascript/yui3/build/get/get.js' => 'e4816a57e845571bb96178b460a7f45f', + './jssource/src_files/include/javascript/yui3/build/history/history-min.js' => '15c4fc68c7b3a987e08a0bd904aef254', + './jssource/src_files/include/javascript/yui3/build/history/history.js' => '8e279fc9ba70f25d70dd9e44745fcf81', + './jssource/src_files/include/javascript/yui3/build/imageloader/imageloader-min.js' => '8b012dc064ae76119d25c564df0368ab', + './jssource/src_files/include/javascript/yui3/build/imageloader/imageloader.js' => '542f1e7f66cf56b09eb1e64dbfdeb2fe', + './jssource/src_files/include/javascript/yui3/build/io/io-base-min.js' => 'd38b67f618736d205f44482a661dfa2b', + './jssource/src_files/include/javascript/yui3/build/io/io-base.js' => '6df56770995472c20366072e46b3afe6', + './jssource/src_files/include/javascript/yui3/build/io/io-form-min.js' => 'ab2cdbf1e0939a0cb137aac241e44914', + './jssource/src_files/include/javascript/yui3/build/io/io-form.js' => 'ec9e4743ddb4c80070960e00c03d56bb', + './jssource/src_files/include/javascript/yui3/build/io/io-min.js' => '9ebc7d9ae14077fd9fe272cca55a7f04', + './jssource/src_files/include/javascript/yui3/build/io/io-queue-min.js' => '793809982910a9f006317dec0d77b0a9', + './jssource/src_files/include/javascript/yui3/build/io/io-queue.js' => '3f932ebb72f8c3988385a8474b6dd71a', + './jssource/src_files/include/javascript/yui3/build/io/io-upload-iframe-min.js' => 'd74e63c9dca71dd9122bc24e56e62147', + './jssource/src_files/include/javascript/yui3/build/io/io-upload-iframe.js' => 'fd4cdaf2809d13ddd336e83cef2de7b1', + './jssource/src_files/include/javascript/yui3/build/io/io-xdr-min.js' => 'cf66f503d2555d8aafaff5f22a932e4b', + './jssource/src_files/include/javascript/yui3/build/io/io-xdr.js' => 'f5e4471349f4015e9a7d93a7352950aa', + './jssource/src_files/include/javascript/yui3/build/io/io.js' => '60422e16edb10cc8f6eea0f50a658637', + './jssource/src_files/include/javascript/yui3/build/json/json-min.js' => 'c629bd6ed7f71360a35926dcc5ae45f3', + './jssource/src_files/include/javascript/yui3/build/json/json-parse-min.js' => 'f9742cbeb6728545f0ff1eb5dd044a32', + './jssource/src_files/include/javascript/yui3/build/json/json-parse.js' => '0968fe85a68300b8aae1268028f561f1', + './jssource/src_files/include/javascript/yui3/build/json/json-stringify-min.js' => 'a81e72a3b3da8187c23a5960e67ec482', + './jssource/src_files/include/javascript/yui3/build/json/json-stringify.js' => '8c292082b315d80fed6a77be57f64371', + './jssource/src_files/include/javascript/yui3/build/json/json.js' => 'ac0fd97c8584d1f0c10114bb4657a58c', + './jssource/src_files/include/javascript/yui3/build/loader/loader-min.js' => 'e2ecdba3f8f4db3029edbbea9cb1ef14', + './jssource/src_files/include/javascript/yui3/build/loader/loader.js' => '70918ebfcfb2489d0e6ce7f9c2efa8a4', + './jssource/src_files/include/javascript/yui3/build/node-focusmanager/node-focusmanager-min.js' => '5828f08b2bce3e1349333d5669ba7484', + './jssource/src_files/include/javascript/yui3/build/node-focusmanager/node-focusmanager.js' => '5e753c5afea81d073780dce8c63efa3c', + './jssource/src_files/include/javascript/yui3/build/node-menunav/node-menunav-min.js' => '5201169bdaf00dce96a2ecf52c3b9bf9', + './jssource/src_files/include/javascript/yui3/build/node-menunav/node-menunav.js' => 'f6bd7cdac5f5b3bb9c7fa3712ad180a7', + './jssource/src_files/include/javascript/yui3/build/node/node-aria-min.js' => '8c0d9db1e9928a89b162e19b44355257', + './jssource/src_files/include/javascript/yui3/build/node/node-aria.js' => 'f180186d04eb58df60bc72fac66a86cd', + './jssource/src_files/include/javascript/yui3/build/node/node-base-min.js' => '573bf8f8667da0182b4a16b585086d12', + './jssource/src_files/include/javascript/yui3/build/node/node-base.js' => '510f173b3b7800a5b49b2fc0a2c3cbdf', + './jssource/src_files/include/javascript/yui3/build/node/node-event-delegate-min.js' => '3a77c1605b375845f04fd06d9ad0d90e', + './jssource/src_files/include/javascript/yui3/build/node/node-event-delegate.js' => '6c4f82d611504925defcc97c9abeff52', + './jssource/src_files/include/javascript/yui3/build/node/node-event-simulate-min.js' => 'c303f12d80efb16c109031b9518117ab', + './jssource/src_files/include/javascript/yui3/build/node/node-event-simulate.js' => '4aaeff9a2f60add686bd4a377fc1cc69', + './jssource/src_files/include/javascript/yui3/build/node/node-min.js' => 'ab40f9701022b3c69a536398278873d8', + './jssource/src_files/include/javascript/yui3/build/node/node-pluginhost-min.js' => '783096e27985e7a9ba27fce6542bb2f4', + './jssource/src_files/include/javascript/yui3/build/node/node-pluginhost.js' => '70466040ac0f1d2e555b39159bac0ac0', + './jssource/src_files/include/javascript/yui3/build/node/node-screen-min.js' => 'f20aee7885b1d94e3365b8da1c5d13d1', + './jssource/src_files/include/javascript/yui3/build/node/node-screen.js' => '471e3f6ca4e99a5f40c7b4b170fbc42e', + './jssource/src_files/include/javascript/yui3/build/node/node-style-min.js' => 'fdcab2a7ec731d1a4696ea4a6a80041f', + './jssource/src_files/include/javascript/yui3/build/node/node-style.js' => '14ad213d86f086af91f3fc1c04b8958e', + './jssource/src_files/include/javascript/yui3/build/node/node.js' => '5e613289d3bff3db17fb7407e48110bb', + './jssource/src_files/include/javascript/yui3/build/oop/oop-min.js' => '1cd195757d9bdf889ba954efb0e9dc60', + './jssource/src_files/include/javascript/yui3/build/oop/oop.js' => 'db6972479283899df4a6a069dd02f331', + './jssource/src_files/include/javascript/yui3/build/overlay/overlay-min.js' => '338aa25cc08c1810f943caa1fdee0b78', + './jssource/src_files/include/javascript/yui3/build/overlay/overlay.js' => 'd7ff4cda4b1ccd4218717d7cd53972be', + './jssource/src_files/include/javascript/yui3/build/plugin/plugin-min.js' => '69f7fea872c4a77090b92ca3356300c6', + './jssource/src_files/include/javascript/yui3/build/plugin/plugin.js' => '7840fcc0b1e5d47f9e8251388ddf8b7c', + './jssource/src_files/include/javascript/yui3/build/pluginhost/pluginhost-min.js' => '35b7c91eb9020cae7792aed0eb9f2830', + './jssource/src_files/include/javascript/yui3/build/pluginhost/pluginhost.js' => '5ae0acc449941efdfc3737a533221077', + './jssource/src_files/include/javascript/yui3/build/profiler/profiler-min.js' => '2f479e3c711a7481fccd7acda1fa1291', + './jssource/src_files/include/javascript/yui3/build/profiler/profiler.js' => '4ef3fe8390933622310743dad9a2e08f', + './jssource/src_files/include/javascript/yui3/build/queue-promote/queue-promote-min.js' => '0461b7b91829eb19e16737b6459f63f2', + './jssource/src_files/include/javascript/yui3/build/queue-promote/queue-promote.js' => '89593256adf72d55aaaf1b035b43ef27', + './jssource/src_files/include/javascript/yui3/build/slider/slider-min.js' => 'cf1e617aaa120f8bf3104d523986b516', + './jssource/src_files/include/javascript/yui3/build/slider/slider.js' => '520f158df9280140d44a644612c5fcd6', + './jssource/src_files/include/javascript/yui3/build/stylesheet/stylesheet-min.js' => '9d6162ed02bd3a25321f4423faaad1ae', + './jssource/src_files/include/javascript/yui3/build/stylesheet/stylesheet.js' => '77929f4ace234fbfa1f5af5b73b1a5d3', + './jssource/src_files/include/javascript/yui3/build/substitute/substitute-min.js' => 'b4373237b784afac69d9b3cd5d5876f5', + './jssource/src_files/include/javascript/yui3/build/substitute/substitute.js' => '8d218c1788e5aa21cad2b17ce2f2c222', + './jssource/src_files/include/javascript/yui3/build/test/test-min.js' => 'a4a4307e711084d0ec4da53f415e3a29', + './jssource/src_files/include/javascript/yui3/build/test/test.js' => '0d4ba61680d004993d270cf7722435b2', + './jssource/src_files/include/javascript/yui3/build/widget/widget-min.js' => 'b47d518383d791d39fba9b113fa253de', + './jssource/src_files/include/javascript/yui3/build/widget/widget-position-ext-min.js' => '52ab08bb21e9455cafbc4d3b9ff80c64', + './jssource/src_files/include/javascript/yui3/build/widget/widget-position-ext.js' => '16dadc8a3116d32fc08d6adf1363c4e9', + './jssource/src_files/include/javascript/yui3/build/widget/widget-position-min.js' => '18248af08d2b1d68ddcc17efe70db0a4', + './jssource/src_files/include/javascript/yui3/build/widget/widget-position.js' => '4f26a65e718507a95947ff9dc5972001', + './jssource/src_files/include/javascript/yui3/build/widget/widget-stack-min.js' => '3ca2decac01d64839c3d37f0897baacd', + './jssource/src_files/include/javascript/yui3/build/widget/widget-stack.js' => 'c43e23543ef86e1e664dfa0963ee1559', + './jssource/src_files/include/javascript/yui3/build/widget/widget-stdmod-min.js' => 'ccd562ecdaea4be08befaaa7c0c2f907', + './jssource/src_files/include/javascript/yui3/build/widget/widget-stdmod.js' => '888c93b81457f03144ea8f74bfba4c2b', + './jssource/src_files/include/javascript/yui3/build/widget/widget.js' => '20fc302af794947681dc47bebfb8ec36', + './jssource/src_files/include/javascript/yui3/build/yui-base/yui-base-min.js' => '4019801f562a2a976013c444c30b0875', + './jssource/src_files/include/javascript/yui3/build/yui-base/yui-base.js' => 'cb71cfade0802cf74b6dd1a6d8c4b5a7', + './jssource/src_files/include/javascript/yui3/build/yui/get-min.js' => 'f34507a2bb860f2e50526f9ccbd4bb7a', + './jssource/src_files/include/javascript/yui3/build/yui/get.js' => 'e4816a57e845571bb96178b460a7f45f', + './jssource/src_files/include/javascript/yui3/build/yui/yui-base-min.js' => 'd7bfae9ab4e40960f9c0c59b1ab9fc6f', + './jssource/src_files/include/javascript/yui3/build/yui/yui-base.js' => '4dda10770e6c51f085198b811bbdb9d5', + './jssource/src_files/include/javascript/yui3/build/yui/yui-later-min.js' => '752d639c7bcbdcb75804d739fab44d38', + './jssource/src_files/include/javascript/yui3/build/yui/yui-later.js' => '0c95fe70b5182558001aaa0c60404960', + './jssource/src_files/include/javascript/yui3/build/yui/yui-log-min.js' => '9ff98f2c7ba8d79c8abf702a36191e24', + './jssource/src_files/include/javascript/yui3/build/yui/yui-log.js' => '22c5382de3ed58bda76dccc819529f0e', + './jssource/src_files/include/javascript/yui3/build/yui/yui-min.js' => '79d543e9fe1ef95df39f721d4a1d23a9', + './jssource/src_files/include/javascript/yui3/build/yui/yui.js' => '934ea2f120407922bc5631d51f90120c', + './jssource/src_files/include/javascript/calendar.js' => '9081f811752c095c74ba09a03e3ec6de', + './jssource/src_files/include/javascript/iscroll.js' => 'b6c232e3c54b2a1320b22c7ad920c842', + './jssource/src_files/include/jsolait/init.js' => '8523493b1d0ccfc3ed8110a093672ebf', + './jssource/src_files/include/jsolait/lib/codecs.js' => 'd3d41752845b924a0f69e1b3d0ad6c3e', + './jssource/src_files/include/jsolait/lib/crypto.js' => '2b012a4eccd9ba700d54bb843b4728d5', + './jssource/src_files/include/jsolait/lib/jsonrpc.js' => '86989d622fc00dd19a08e91e97080a19', + './jssource/src_files/include/jsolait/lib/jsonrpclite.js' => '0f2c76b00723aad1651180e9abb1333c', + './jssource/src_files/include/jsolait/lib/lang.js' => 'a229cd0758f3c58cb246ec0179ff870a', + './jssource/src_files/include/jsolait/lib/langlite.js' => '2823f3cf579b60fc8846d1a64fcdeee4', + './jssource/src_files/include/jsolait/lib/urllib.js' => '4c55cf9f1a01aa0979ef43ea7f268c51', + './jssource/src_files/include/jsolait/lib/xml.js' => 'e1559fd5cd5d259f2a8f7fd07a2d2b51', + './jssource/src_files/include/jsolait/lib/xmlrpc.js' => 'fb50af7f64c53c58d1f700c63c9823b9', + './jssource/src_files/include/jsolait/missingmixin.js' => 'b07c5d5a0215126b989a6756c96a59c9', + './jssource/src_files/include/ytree/TreeView/HTMLNode.js' => '80d3d7b998e77999da2cd4fb0168ab68', + './jssource/src_files/include/ytree/TreeView/MenuNode.js' => '78c155839f99bc3564183e1557d15d3f', + './jssource/src_files/include/ytree/TreeView/Node.js' => '5558862b65a50dcfb297660196998435', + './jssource/src_files/include/ytree/TreeView/RootNode.js' => '84e59f27cdc5626482e0aab754afaaee', + './jssource/src_files/include/ytree/TreeView/TaskNode.js' => 'eb7b39df715ad52c70168cf8aae0d826', + './jssource/src_files/include/ytree/TreeView/TextNode.js' => '24a9bca371d9892ccd28455bd06d8f79', + './jssource/src_files/include/ytree/TreeView/TreeView.js' => '3ddc27c3f35d55471a451f9f4dad0394', + './jssource/src_files/include/ytree/TreeView/anim/TVAnim.js' => '1b2f5f2dfb95977adf382b57d61e8ee5', + './jssource/src_files/include/ytree/TreeView/anim/TVFadeIn.js' => '036c5e47e6c096f468fa30288b9c18fb', + './jssource/src_files/include/ytree/TreeView/anim/TVFadeOut.js' => '7bda0243ee0f0ae64829c57e387145f3', + './jssource/src_files/include/ytree/treeutil.js' => 'b4010d3a23933b3f78e48089b47ceeee', + './jssource/src_files/install/dbConfig.js' => '0a69acd054311be6b0d62a4a8c56c002', + './jssource/src_files/install/installCommon.js' => 'a64e04c8c9e02fc918d90dfc7463985f', + './jssource/src_files/install/license.js' => '6144c34a4d7d444fa4249b177ad5142f', + './jssource/src_files/install/oc_convert.js' => '769f06f998f3f03d81aa235f4880103a', + './jssource/src_files/install/oc_install.js' => '74c31efa214e2d2fdaffabd5a96bdb20', + './jssource/src_files/install/register.js' => 'c376eca14316971fc8aed938a6eec80a', + './jssource/src_files/install/siteConfig.js' => 'df40d7f62ea42c29a8bef70997243033', + './jssource/src_files/modules/ACLRoles/ACLRoles.js' => '28e1b60370ee538a2b80fa7a69119f85', + './jssource/src_files/modules/Accounts/Account.js' => 'ea1ade4e9754d4c81f998cfb4e4ae5ee', + './jssource/src_files/modules/Administration/javascript/Administration.js' => 'd87ec1872365dee9ec6a7746eeb5be0d', + './jssource/src_files/modules/Administration/javascript/Async.js' => '736e48313d8f98a1d3004cf1f4a9f758', + './jssource/src_files/modules/Campaigns/DetailView.js' => '1b33f45850335fcedb98e2919f4a5b7e', + './jssource/src_files/modules/Campaigns/WebToLead.js' => '7eb7bb9602f605dda23b051a68ff01a6', + './jssource/src_files/modules/Campaigns/wizard.js' => '46e43f16676665bdc14ec31ecc2e2758', + './jssource/src_files/modules/Connectors/Connector.js' => 'cbd618a5273c129f5e506582a8c035d3', + './jssource/src_files/modules/Contacts/Contact.js' => '340c4f111e6bbfc76f2167defbebc169', + './jssource/src_files/modules/Currencies/EditView.js' => '1f414bf3517628dfb9dd445739b9074e', + './jssource/src_files/modules/Documents/documents.js' => '869b8d2d02d44e4f7804405426b35aaf', + './jssource/src_files/modules/EmailTemplates/EmailTemplate.js' => 'f9043c6f84a7b077f0fb44b725a5b0f6', + './jssource/src_files/modules/Home/about.js' => '21f5494869cd5700b0c552747ad8c0f7', + './jssource/src_files/modules/InboundEmail/InboundEmail.js' => 'd01fb6beb97fbff465106ede1b300ed1', + './jssource/src_files/modules/Leads/Lead.js' => 'd06ef9e18d4c85fa7aedf57cdb5fc9e7', + './jssource/src_files/modules/Meetings/jsclass_scheduler.js' => '007c932cc101de1394d949008ed79c68', + './jssource/src_files/modules/MergeRecords/Merge.js' => '753cc64c1b94ed8f161112d17a3e0b0e', + './jssource/src_files/modules/Project/Project.js' => '2a60fb114abad5d5ac42e102f83ef3d9', + './jssource/src_files/modules/ProjectTask/ProjectTask.js' => 'b87b7fcdca7f326d7bca5fcbc2ef8e8c', + './jssource/src_files/modules/Studio/JSTransaction.js' => '33c082aaee31dd249e66c6a929e66dea', + './jssource/src_files/modules/Studio/studio.js' => 'c9a08187fa2817c18571a0b0814263a4', + './jssource/src_files/modules/Studio/studiodd.js' => '042fd5bfbbf1b4075e7da9b384a64ed1', + './jssource/src_files/modules/Studio/studiotabgroups.js' => '0a407c2375736a58bdc9d46267776831', + './jssource/src_files/modules/Studio/ygDDListStudio.js' => '1e565e41bc3053bde86338180ed32fdf', + './jssource/src_files/modules/UpgradeWizard/upgradeWizard.js' => '22592c6a2b6f28d8271a057047de3b3b', + './jssource/src_files/modules/Users/DetailView.js' => 'c8891d42c83727227db91137fae65337', + './jssource/src_files/modules/Users/PasswordRequirementBox.js' => '66744f0b7d5350ced33adaae7b85c09a', + './jssource/src_files/modules/Users/User.js' => 'eef706110eb0afe0aa0cebc117f59af7', + './jssource/src_files/modules/Users/login.js' => '4072981132901aad89bf2c26279b4a4e', + './jssource/src_files/modules/EAPM/EAPMEdit.js' => 'c16277ba5f134d888974539e11bb6a5a', + './jssource/src_files/service/utils/SugarRest.js' => '050aa9a51d9de8b4a77b301d36223656', + './jssource/src_files/themes/Sugar5/js/style.js' => '0342dbdcb579b8db6e1ce37adbb8f9f3', + './jssource/src_files/themes/default/js/style.js' => 'bff5ec579bd904092b693f765ec9f95e', + './jssource/minify_utils.php' => '451d68994be2696da311409a880d57fc', + './jssource/minify.php' => 'b8960cda18806ed133dc05159c7f6bc9', + './jssource/jsmin.php' => '1a523af482b74cfb955570e7473c0bf1', + './jssource/JSGroupings.php' => '93b7a444871b2427c7e2991b64e79958', + './json.php' => '14eaa93f6fd401f83e7f4420186391b4', + './install/dbConfig.js' => '50e0834bb5e0cdc64348eabcfe56a9fc', + './install/installCommon.js' => '28c286b2ad390526f43df07a56546cee', + './install/license.js' => '78f1f4a2e54982ad1419f1ad93315dd9', + './install/oc_convert.js' => 'c6770fd8d6367f84efcabb279ae11db2', + './install/oc_install.js' => '8f235dd0d14b80df459b2cec2d98822a', + './install/register.js' => '8a0db266f6f9c0dab41335bad0a74b3e', + './install/siteConfig.js' => '54fde32e90061faa425cc547606c7190', + './install/welcome.php' => 'f22cf6a4f9b5c80560191b9a30af6561', + './install/systemOptions.php' => 'dda99195980f856f2eaaacb92b5bf729', + './install/siteConfig_b.php' => '0460d2110f0fa9cd31f649029564d865', + './install/siteConfig_a.php' => '069857546bf6f42053bc3d30ae18264e', + './install/seed_data/quotes_SeedData.php' => 'e7299ed86d47891705fd23fe617d96d6', + './install/seed_data/Advanced_Password_SeedData.php' => '6bc0432f3b1afcaf9870036f40c1b696', + './install/register.php' => '4b966e2b08bf929bb42c2c39ab22ddf7', + './install/ready.php' => 'd839502c0b117ba30e8ff39a866c6fe7', + './install/processing.gif' => 'd7c43fc19181ee59862601bfce100b41', + './install/licensePrint.php' => '729a22dff5007140b80a0f2b74004e39', + './install/license.php' => '1677efd52688a75b1e117ab893c98838', + './install/language/en_us.lang.php' => 'f470d7bb93e7819a4ce7f51b68d69fd5', + './install/performSetup.php' => 'f4da6a9200f7f9256b5d84e924d1f419', + './install/install_defaults.php' => 'd1f7954042d157bf247339d6287d3cfb', + './install/installType.php' => 'f2e5190e2b1c6f479e27105274ce699e', + './install/installSystemCheck.php' => '536855633fb59c458b580a44e5fa2ce0', + './install/installHelp.php' => 'b508e56bcf24baa43128cce37f256b65', + './install/installDisabled.php' => 'c8ddd0efea951af37d0c70422d23bdfd', + './install/install.css' => '3dbd8161ac8e4fb86eec530a1500bd21', + './install/download_patches.php' => '1546b155f73b31ab560a5455390ecb67', + './install/download_modules.php' => 'f368a12c71aecf9e08494fd3f8c4a218', + './install/install_utils.php' => '7f9779e4e5219b4b4f04e167c260f3f6', + './install/populateSeedData.php' => '6fc3d9148c6c7decab9851329652c63d', + './install/demoData.en_us.php' => '4e0ba9101da24a0074a58744a21d992b', + './install/dbConfig_a.php' => '72c6aa33afa0ed595f88a3d9102fdb25', + './install/data/disc_client.php' => 'b7f7853de0b429b9be5fdbc9532ecbe0', + './install/confirmSettings.php' => '7293087c8d9398db4a643bc46b1e39c1', + './install/checkDBSettings.php' => '769cfd353424087bcada73508e5efea8', + './install/UserDemoData.php' => 'ca3d776503efa97372447c010084f39c', + './install/UploadLangFileCheck.php' => '261dc5321de4bb91d785421bf1256e69', + './install/TeamDemoData.php' => '8c63181ad6d759ac25e980851b41b50f', + './index.php' => 'ec6eb0c76d968e336e1721d1f6e31d42', + './include/JSON.js' => '603ba7c5edab1ce11d7d1ab3fd98e808', + './include/externalAPI/ExternalAPIFactory.php' => '99d142a5f3eeef813c4164fe16ef8f66', + './include/externalAPI/Base/WebMeeting.php' => 'f98a2dd54e431d4063d19c4e17c24d93', + './include/externalAPI/Base/WebFeed.php' => '05211420bd0fe9e85a1415f9a855442b', + './include/externalAPI/Base/WebDocument.php' => '44a5ad44ad8c272f39635eabe98a35c9', + './include/externalAPI/Base/OAuthPluginBase.php' => '0f482afe47428fa58613ba0b98e68b39', + './include/externalAPI/Base/ExternalOAuthAPIPlugin.php' => '3df84091ecb79be92c4fbd8930fee13d', + './include/externalAPI/Base/ExternalAPIPlugin.php' => '1cab79f253d174e349726f786429a52b', + './include/externalAPI/Base/ExternalAPIBase.php' => '5f3bc85035eae7832b79d57ae4d0ad84', + './include/SugarOauth.php' => '1a0d9ab6285929101d4b16ebf667a1b2', + './include/SugarDateTime.php' => '90a27d03de3ccb118a2d43e5200893d9', + './include/ytree/treeutil.js' => '3ed885ac4154b25eb80fb2c272e63bca', + './include/ytree/TreeView/HTMLNode.js' => '84858f719e9b3740d1c58991b0f50d44', + './include/ytree/TreeView/MenuNode.js' => '8d001c1014dc6755f150cd83c1dfe07b', + './include/ytree/TreeView/Node.js' => '3932d3c94081e6b06eca764d715d8336', + './include/ytree/TreeView/RootNode.js' => 'd69d0bab9738e0772368d8a4cd65d031', + './include/ytree/TreeView/TaskNode.js' => '705d97683a5d0f9ed47ec82a5b3f94e6', + './include/ytree/TreeView/TextNode.js' => '736fa145ec95723013aaf44d3f17fdbb', + './include/ytree/TreeView/TreeView.js' => '938b1c6bf4d2fedd1811eadaa7036801', + './include/ytree/TreeView/license.txt' => 'a49b2f02abb652b7d30356b10661c18d', + './include/ytree/TreeView/img/qtop.png' => '6c5cfe5abcdd98f795456d6c4b07dcef', + './include/ytree/TreeView/img/qmiddle.png' => '37835a6f515fd99bf5f8db07e53c9152', + './include/ytree/TreeView/img/qbottom.png' => 'c20068ca30513e1889d77a08b4bc3f85', + './include/ytree/TreeView/img/navHover2.png' => '474350463d139c3b695f82458621019d', + './include/ytree/TreeView/img/logo.gif' => 'b6c525fba741bb9d7409ffd81617e4c0', + './include/ytree/TreeView/img/header.gif' => '6e3b4dadd01281fa538f99d8fefc9971', + './include/ytree/TreeView/img/greybg.png' => '8044723473c3284f16b941f0b30a4b50', + './include/ytree/TreeView/img/folders/vline.gif' => 'b1e532ebb090f9a8b0ff615ad2fd4c5f', + './include/ytree/TreeView/img/folders/tph.gif' => '60164cbb3e19f4c7ed2bba9586138c13', + './include/ytree/TreeView/img/folders/tp.gif' => '5e116271e871a0d77bd078a5fa155643', + './include/ytree/TreeView/img/folders/tn.gif' => 'c95cb41671230a97395284737f8150b8', + './include/ytree/TreeView/img/folders/tmh.gif' => '45a194853e0dd0d646bbf21aa58b7b4c', + './include/ytree/TreeView/img/folders/tm.gif' => '6c18f25ac052f5b239d2f361a626b944', + './include/ytree/TreeView/img/folders/plus.gif' => 'e4f6417645e9b0526b73a4c7471cc668', + './include/ytree/TreeView/img/folders/minus.gif' => '9b2c20dc4fed5a951d10b067a402ecd2', + './include/ytree/TreeView/img/folders/lph.gif' => 'f2d2976bcde012539f24c0460c4da6b7', + './include/ytree/TreeView/img/folders/lp.gif' => 'df6c5a8c9cd674c83d1b2212be6f35c1', + './include/ytree/TreeView/img/folders/loading.gif' => '746da00bdbc68a4002a01bba50762057', + './include/ytree/TreeView/img/folders/ln.gif' => '2f8a02d3be989aaeb70c83180051aad1', + './include/ytree/TreeView/img/folders/lmh.gif' => '97d52e3168253f298a09be30fa4a839e', + './include/ytree/TreeView/img/folders/lm.gif' => 'ea5c0b17107fac67fedfbe88f1f48c5e', + './include/ytree/TreeView/img/default/vline.gif' => 'b1e532ebb090f9a8b0ff615ad2fd4c5f', + './include/ytree/TreeView/img/default/tph.gif' => '6ca162eb3adeb0f1a3b5e764d9cc6de3', + './include/ytree/TreeView/img/default/tp.gif' => '10b5c85f091ee8578bd20e10098085e4', + './include/ytree/TreeView/img/default/tn.gif' => 'c95cb41671230a97395284737f8150b8', + './include/ytree/TreeView/img/default/tmh.gif' => 'bf244a8869eadaebe0ffbdea9b1a18b6', + './include/ytree/TreeView/img/default/tm.gif' => '61a3d3de076fe6ac2c13fe41a7cdf12e', + './include/ytree/TreeView/img/default/lph.gif' => '3dfb6f00e3f2d3db38ea9e116506586c', + './include/ytree/TreeView/img/default/lp.gif' => 'c3b1a88a19bf2613cdc2457d72af2391', + './include/ytree/TreeView/img/default/loading.gif' => '8f1310bf9e7aa892d2dc09c4058c7bd3', + './include/ytree/TreeView/img/default/ln.gif' => '2f8a02d3be989aaeb70c83180051aad1', + './include/ytree/TreeView/img/default/lmh.gif' => '778f9acfb5c8a455c84b82b0893a6e9e', + './include/ytree/TreeView/img/default/lm.gif' => '8bfefc209352d78c1fe73f966c3e1a98', + './include/ytree/TreeView/img/check/vline.gif' => 'b1e532ebb090f9a8b0ff615ad2fd4c5f', + './include/ytree/TreeView/img/check/tph.gif' => '6ca162eb3adeb0f1a3b5e764d9cc6de3', + './include/ytree/TreeView/img/check/tp.gif' => '10b5c85f091ee8578bd20e10098085e4', + './include/ytree/TreeView/img/check/tn.gif' => 'c95cb41671230a97395284737f8150b8', + './include/ytree/TreeView/img/check/tmh.gif' => 'bf244a8869eadaebe0ffbdea9b1a18b6', + './include/ytree/TreeView/img/check/tm.gif' => '61a3d3de076fe6ac2c13fe41a7cdf12e', + './include/ytree/TreeView/img/check/lph.gif' => '3dfb6f00e3f2d3db38ea9e116506586c', + './include/ytree/TreeView/img/check/lp.gif' => 'c3b1a88a19bf2613cdc2457d72af2391', + './include/ytree/TreeView/img/check/loading.gif' => '8f1310bf9e7aa892d2dc09c4058c7bd3', + './include/ytree/TreeView/img/check/ln.gif' => '2f8a02d3be989aaeb70c83180051aad1', + './include/ytree/TreeView/img/check/lmh.gif' => '778f9acfb5c8a455c84b82b0893a6e9e', + './include/ytree/TreeView/img/check/lm.gif' => '8bfefc209352d78c1fe73f966c3e1a98', + './include/ytree/TreeView/img/check/check2.gif' => '691389bb26f429e79666599992a384b3', + './include/ytree/TreeView/img/check/check1.gif' => '3544088604d6d6e519a3a392db89c38d', + './include/ytree/TreeView/img/check/check0.gif' => 'd3e7d474e008b8cb585eb05c5baafe5a', + './include/ytree/TreeView/img/check/Thumbs.db' => '3cf8fd69dbfff71a14b3ad14dadb05b2', + './include/ytree/TreeView/img/bullet.gif' => '856d0243cbbf9bd9466c760530b28b9d', + './include/ytree/TreeView/css/forecasts/tree.css' => '59797a1f43dc5602932f826d687d398f', + './include/ytree/TreeView/css/folders/tree.css' => '59797a1f43dc5602932f826d687d398f', + './include/ytree/TreeView/css/default/tree.css' => '20814fc9a87f0aa930984569bd77fd2c', + './include/ytree/TreeView/css/check/tree.css' => '724cc963f0904fe2ed1f443cef791197', + './include/ytree/TreeView/anim/TVAnim.js' => 'cf0ce06993b1e732fb7626c429b5dd9d', + './include/ytree/TreeView/anim/TVFadeIn.js' => 'a49bd8604c75d29778602f346001a761', + './include/ytree/TreeView/anim/TVFadeOut.js' => 'd1fc4b1340b7430688b0866493d11685', + './include/ytree/Tree.php' => 'dba7bc832c460882de6606b42fec5110', + './include/ytree/Node.php' => '3fbb0e6b0a874dcec7e00120f6a67238', + './include/ytree/ExtNode.php' => 'e79a18d84454f59a3d6041e3bc923e36', + './include/vCard.php' => 'f6b2d22c63948aaedc60e32b21cb33ef', + './include/utils/php_zip_utils.php' => 'e73ff6906b73e6e7f342ade77c532902', + './include/utils/sugar_file_utils.php' => '172fe11f930d93669caca3a1b933c8c5', + './include/utils/security_utils.php' => '1fd66ac45eb2d7a812efeff2cab267fc', + './include/utils/progress_bar_utils.php' => '72633b667109464bafa8fc027c9938d4', + './include/utils/zip_utils.php' => '31f3c36e8262b2c459aac59324a5e122', + './include/utils/logic_utils.php' => 'a59013e866e3bed66ea19d404dad3a5d', + './include/utils/layout_utils.php' => 'fbfbcf40a528c3f3d668aa3e534f9ce2', + './include/utils/file_utils.php' => '32a767ca3b41d57f6bd03bb8b6c896d0', + './include/utils/external_cache.php' => '466fe3b797c84f8dae0747999ab6b8dc', + './include/utils/mvc_utils.php' => 'cc4dbe47244ec12a530eed1c2df15605', + './include/utils/encryption_utils.php' => '18ee99143ae59f50d72b3c022fea5a39', + './include/utils/db_utils.php' => '4b5f58235f45f5ba81951abb6443dcd1', + './include/utils/autoloader.php' => 'c17b72066f14f04cf397612ca6406d35', + './include/utils/array_utils.php' => 'f0e351c9612a903fefdac36e9894097c', + './include/utils/activity_utils.php' => 'fc0b073a8b715799ec088c1452378686', + './include/utils/LogicHook.php' => '6dbc41ebec77d4359d1df5f411ccd2ff', + './include/utils.php' => 'a545314158d73488c9317566402e269c', + './include/upload_file.php' => 'fef35543cc9ff150f8ad13eb38ac0fb3', + './include/timezone/timezones.php' => 'c1b535767fd4bb7fdb04d03a91ceed6c', + './include/templates/TemplateGroupChooser.php' => '1971bdb38d86951c192a3f97e38a2ead', + './include/templates/TemplateDragDropChooser.php' => 'dd202c795367f01e884d5e2e95e48ec3', + './include/templates/Template.php' => 'aa5a008f2461eef7ae668afb0e95a6fa', + './include/tcpdf/unicode_data.php' => 'd20008bba6110e94611ac0939a92913b', + './include/tcpdf/tcpdf.php' => '2d63d36838205a8d52725d0c888bbab5', + './include/tcpdf/htmlcolors.php' => '0015bab537767d694b0304d91a87c5f1', + './include/tcpdf/fonts/utils/makefont.php' => '07068b0cd9415eaa2c4165f0bc980e7d', + './include/tcpdf/fonts/utils/enc/koi8-u.map' => '9046b7222af56cb6bbc349cac9dbabdf', + './include/tcpdf/fonts/utils/enc/koi8-r.map' => '04f520a75d940d47dec77f1cc0539fbb', + './include/tcpdf/fonts/utils/enc/iso-8859-9.map' => '8647a52d390b37e26ed05e5ed6793b76', + './include/tcpdf/fonts/utils/enc/iso-8859-7.map' => 'd0712d80739797b3495f67490d328d08', + './include/tcpdf/fonts/utils/enc/iso-8859-5.map' => '82a2003dbd3b5e359ea6b19898d4bc89', + './include/tcpdf/fonts/utils/enc/iso-8859-4.map' => '0355d40c58aa1db273ced4e7697b15b0', + './include/tcpdf/fonts/utils/enc/iso-8859-2.map' => '47507c221cb986421905861794102889', + './include/tcpdf/fonts/utils/enc/iso-8859-16.map' => 'b56b0749d1ac137491e3714039009960', + './include/tcpdf/fonts/utils/enc/iso-8859-15.map' => '3d09f07dd446c6a2fc13a609c084e854', + './include/tcpdf/fonts/utils/enc/iso-8859-11.map' => '83ecaf01ee009dc60c74e4fdaff0aa26', + './include/tcpdf/fonts/utils/enc/iso-8859-1.map' => '53bffea6677269f073516bb10d28de02', + './include/tcpdf/fonts/utils/enc/cp874.map' => '4fbafebd9ea29f4e10889749ec414113', + './include/tcpdf/fonts/utils/enc/cp1258.map' => '86a4dee852783cc5b85ac83a82729d47', + './include/tcpdf/fonts/utils/enc/cp1257.map' => 'fe87c493f46ddfd8b57212cbc52e25ac', + './include/tcpdf/fonts/utils/enc/cp1255.map' => 'c469cfdac7010e50b7fbcabaaf1393b1', + './include/tcpdf/fonts/utils/enc/cp1254.map' => '46e48666d54b3bc0d7eba59e1fc768f3', + './include/tcpdf/fonts/utils/enc/cp1253.map' => '907301f283e7457d037fee0adb5ce187', + './include/tcpdf/fonts/utils/enc/cp1252.map' => '8d7358daa8b750747694e822111898f9', + './include/tcpdf/fonts/utils/enc/cp1251.map' => 'ee2f10b8198819a33d4aa566a7df4ec6', + './include/tcpdf/fonts/utils/enc/cp1250.map' => '8a021bf2c9796273f4b2c3824efefc1d', + './include/tcpdf/fonts/uni2cid_ak12.php' => '48e09bff813f4b234c6b7e9c467512d2', + './include/tcpdf/fonts/uni2cid_aj16.php' => 'f3ccaedbf079a409290fbfcdbaabb8bb', + './include/tcpdf/fonts/uni2cid_ag15.php' => '1305b98f6f8418b9f87d241e39e22cbe', + './include/tcpdf/fonts/uni2cid_ac15.php' => '6504890ef8fbceb731846f0bdc687c9f', + './include/tcpdf/config/tcpdf_config_alt.php' => 'c76e0654a76ace127b7bbac643a56adf', + './include/tcpdf/config/tcpdf_config.php' => '8a16a8d652025639c269b86e8131c942', + './include/tcpdf/config/lang/ita.php' => '6799df637c7ddbb4d3bec7585ca54467', + './include/tcpdf/config/lang/eng.php' => '8e9d665646ab2bb94fd7479a05a834d9', + './include/tcpdf/barcodes.php' => 'ae6a844d3c0d140c53e0f8fa29256714', + './include/tcpdf/README.TXT' => 'f64835b5e9149a89515a9eb589d13a38', + './include/tcpdf/LICENSE.TXT' => '7fbc338309ac38fefcd64b04bb903e34', + './include/tcpdf/CHANGELOG.TXT' => 'b41664d05748e067b3d52ba1eba1e9c3', + './include/tcpdf/2dbarcodes.php' => 'ffd7b4d2b008aeffecb7967041777c44', + './include/tabs.php' => '040d7f98904ecbf8228d2cc907ca9be2', + './include/tabConfig.php' => '7cc5eece0701fae3dfeade19d4469039', + './include/resource/ResourceManager.php' => '362f6d3f49acde341c5c2cec87dc4bfd', + './include/resource/Observers/WebResourceObserver.php' => 'ce9c1f7d7429a4bcab42ea6a5136aee4', + './include/resource/Observers/SoapResourceObserver.php' => 'a89ef8aa12efcee5ff1e8eb6eef61432', + './include/resource/Observers/ResourceObserver.php' => 'b6b3994aaf19825c9caabd867dc11313', + './include/reCaptcha/recaptchalib.php' => '198a9ad0abe0be3729926245915d6dc0', + './include/reCaptcha/README' => 'd6cc7bf9298e02f88ee8872859a324f8', + './include/reCaptcha/LICENSE' => '8c863d134de86e9f4623b04127051732', + './include/phpmailer/license.txt' => '278f2557e3b277b94e9a8430f6a6d0a9', + './include/phpmailer/language/phpmailer.lang-tr.php' => '7ddc04019a3ab315429a01d1eac1ac10', + './include/phpmailer/language/phpmailer.lang-se.php' => '3c06baba1b6ab4d8acf0602cd7e3700a', + './include/phpmailer/language/phpmailer.lang-ru.php' => '1ba9cde2e2ad42a3f367bc3ffa070342', + './include/phpmailer/language/phpmailer.lang-ro.php' => 'cba42902cc751ea7e80720e5ba6b9d1a', + './include/phpmailer/language/phpmailer.lang-pl.php' => '72d18cb4146127e89db0a402fb18e10d', + './include/phpmailer/language/phpmailer.lang-no.php' => '60a01ff00af72c21a9afa8b906cb160a', + './include/phpmailer/language/phpmailer.lang-nl.php' => '69c2fb42974c0e5046c83182238608b3', + './include/phpmailer/language/phpmailer.lang-ja.php' => '0a79142a326c7f23f4ebcac251b9a1e2', + './include/phpmailer/language/phpmailer.lang-it.php' => '6d9025ba4f6b9dbe9bbf0044f77f407c', + './include/phpmailer/language/phpmailer.lang-hu.php' => '49bdceec325435adae3b5f9c4d3f86de', + './include/phpmailer/language/phpmailer.lang-fr.php' => 'c693b4a9214c28fe10c65072833e5bd7', + './include/phpmailer/language/phpmailer.lang-fo.php' => '19c5f009920dff72a02675dad3c6c749', + './include/phpmailer/language/phpmailer.lang-fi.php' => '1d0b14ace9b7c075be51756462fdcbd7', + './include/phpmailer/language/phpmailer.lang-et.php' => '50e92cd6a80d425bf79b0347b27c7364', + './include/phpmailer/language/phpmailer.lang-es.php' => '84174963798d08a7ccdc4ca9c969e3d6', + './include/phpmailer/language/phpmailer.lang-en.php' => '50e6e86986c7f547b7e1e4406eb6b54b', + './include/phpmailer/language/phpmailer.lang-dk.php' => 'e3bebecccdbd1b7b07f32989d44420f1', + './include/phpmailer/language/phpmailer.lang-de.php' => 'b825169df27b56b0592992f13d6eeecb', + './include/phpmailer/language/phpmailer.lang-cz.php' => '71777a5d541217d10f85bdd3ee09f3c9', + './include/phpmailer/language/phpmailer.lang-ca.php' => '228a8e6e6eb5fee58942f5d0740314ce', + './include/phpmailer/language/phpmailer.lang-br.php' => 'd294ef50bd7d57e70e866a7618528048', + './include/phpmailer/language/phpmailer.lang-ar.php' => '007791fbed48cbc28248a543e023ddbf', + './include/phpmailer/class.smtp.php' => '64255208cd6f263a69d58918dcb7138d', + './include/phpmailer/class.phpmailer.php' => 'a78d163362a44ff475e9141c3c75ed99', + './include/phpmailer/README' => '9522b5930919ec251b6f4edda0584480', + './include/pclzip/readme.txt' => '2265cad9ccb84cfcd4093ce26b22dc97', + './include/pclzip/pclzip.lib.php' => 'f42cfbdfccc2dcd85df39638ae2d141c', + './include/pclzip/gnu-lgpl.txt' => '7fbc338309ac38fefcd64b04bb903e34', + './include/nusoap/nusoapmime.php' => '03ad5f19e5f8ca40b6ecc8bb5ff7d06d', + './include/nusoap/nusoap.php' => '08f16a90957ec98acd49a1a5a43458dc', + './include/nusoap/license.txt' => '25823f4a2e463ab2c6b5873f07e428e1', + './include/nusoap/class.xmlschema.php' => '619375dc901a69c6ed625cc2e38beae9', + './include/nusoap/class.wsdlcache.php' => 'f8f80fa3fa56b0d0c3169cff60bfc3c2', + './include/nusoap/class.wsdl.php' => 'cd7f1a43ca08891ac1ce04d4d1282c49', + './include/nusoap/class.soapclient.php' => 'b013aebcb51815543091c4914cb16157', + './include/nusoap/class.soap_val.php' => '084a898ecf261c201427fd41d4ee40e0', + './include/nusoap/class.soap_transport_http.php' => 'fc8d8de37eeea8b79c9963bd8ef1357b', + './include/nusoap/class.soap_server.php' => '4fb2dcda6452dfa5b147d5032b325be3', + './include/nusoap/class.soap_parser.php' => '9498d0e4b5b3bf69032a72ca147c2f7a', + './include/nusoap/class.soap_fault.php' => 'bf058747b0ecefe183194300dbd73dff', + './include/nusoap/class.nusoap_base.php' => 'cf8310e722c8fc7e310dc5ba413b1ea6', + './include/nusoap/changelog' => 'd75ed67ec93c02e5bce94eee8205b425', + './include/modules.php' => '78c531f6122d2ba38aa8c211d9ceb2db', + './include/language/jsLanguage.php' => 'c44b0ccdccdfbd7eb0e1eb36f6628c56', + './include/language/en_us.notify_template.html' => 'dc07fa34ed74873ba996cc637f8889a8', + './include/language/en_us.lang.php' => '3ffcc22b71675543a578164f674f2290', + './include/json_config.php' => '8c301d204675cf3efe0e2d72d40abe43', + './include/jsolait/init.js' => '15b8d113066ad400aa80d9dfc35b544b', + './include/jsolait/missingmixin.js' => 'e87a7ee61bd9e134791325d98ca72d9b', + './include/jsolait/lib/codecs.js' => 'c3e9eb73b3187f1b69e33bde1a635712', + './include/jsolait/lib/crypto.js' => '3f96a9c701df13c7e3439dc66ac9cc83', + './include/jsolait/lib/jsonrpc.js' => '1dc4f35a1cc650dceae36463fc421751', + './include/jsolait/lib/jsonrpclite.js' => '087168595f8d7d4633b0d5ebc5efa0ad', + './include/jsolait/lib/lang.js' => '4680e079a4114db6ef54d0ced899547f', + './include/jsolait/lib/langlite.js' => 'd76525f7eeffc76252d0be3cb72081bb', + './include/jsolait/lib/urllib.js' => '7dfb28b9ac9435bee4a1d1aa8721050b', + './include/jsolait/lib/xml.js' => '778da59ff6d89d7c6cde9814db71f63e', + './include/jsolait/lib/xmlrpc.js' => '561bc3aca65261c577ab56b9908d6b78', + './include/jsolait/copying.txt' => '7fbc338309ac38fefcd64b04bb903e34', + './include/jsolait/LICENSE' => '7fbc338309ac38fefcd64b04bb903e34', + './include/javascript/sugar_grp_quickcomp.js' => '3b337ebfdd4305d5d33c23b120effb5c', + './include/javascript/sugar_grp_emails.js' => '4c4ab7968fe0d9a61e35f8625b4d8365', + './include/javascript/sugar_grp_overlib.js' => '697dc29858751a3a9848ded2d5cc9638', + './include/javascript/sugar_grp_yui2.js' => '810b0d52b0d73ca309673fa8c88f7275', + './include/javascript/sugar_grp_yui_widgets.css' => '9fead3f803643c74f997b323e0a7b4e7', + './include/javascript/sugar_grp_yui_widgets.js' => '284e935d82048407ad58bb58b17e9f51', + './include/javascript/sugar_grp1_yui.js' => '49bb537e8497adc31c6eef821140542e', + './include/javascript/sugar_grp1.js' => 'a13d69863100d17adb938b1287dbf2cb', + './include/javascript/cookie.js' => 'de61d7b1eb4ba59186984d89f628eae2', + './include/javascript/dashlets.js' => '8ce96c35d117268f854ee736ce3f8726', + './include/javascript/include.js' => '111549b33d8ca4011ca99a23105050fe', + './include/javascript/jsclass_async.js' => '4c176f9adec386d72d222e4b52da0229', + './include/javascript/jsclass_base.js' => '757af42039add740fb838fac2d8baa4a', + './include/javascript/menu.js' => '3abcb7c05eff710b8fa52d18d7a14834', + './include/javascript/overlibmws.js' => 'f4bac256b9f8dc64ba4b22a8e1259ea2', + './include/javascript/overlibmws_iframe.js' => 'e3c045ac5f7b73aeb761395339d82f30', + './include/javascript/popup_helper.js' => 'b71cea0d43e03dd24bbef622e1b94e73', + './include/javascript/popup_parent_helper.js' => 'a6c24762a5082cd5c3714f5d6c817db5', + './include/javascript/quickCompose.js' => '8702e1904189f22c31f88b05e22398e7', + './include/javascript/quicksearch.js' => '31ff4f0a3ab8b060848420e09d9b7973', + './include/javascript/report_additionals.js' => 'bfb26a986bc020109f20b703fa6a6a9d', + './include/javascript/sugar_3.js' => '85fa75ab053d349298e1bd07e2498127', + './include/javascript/sugar_connection_event_listener.js' => '119ff2a497fd3c53d9f9a9b3d2226357', + './include/javascript/swfobject.js' => 'be72d27dc0b8bf006dcb764e41153465', + './include/javascript/calendar.js' => 'd6c576e0d7ddcb1dd04cf788e8215846', + './include/javascript/iscroll.js' => '0b9c55c0f6a677ef7ca628f156527456', + './include/javascript/yui3/index.html' => '9ff89ada5571d6d03eccc45dad57bb16', + './include/javascript/yui3/build/yui/get-min.js' => '1ef08bacb464ead1fbdb74d45addca6f', + './include/javascript/yui3/build/yui/get.js' => '1b0ea131a29adf2a1957ad11be4547ff', + './include/javascript/yui3/build/yui/yui-base-min.js' => 'de6b8b73e1c8e76f133d11558e7c4bc1', + './include/javascript/yui3/build/yui/yui-base.js' => '29bd3f7d9d24e14f1466ca6cf3af0621', + './include/javascript/yui3/build/yui/yui-later-min.js' => 'de7018bad67d935f79056f53c4b9bae8', + './include/javascript/yui3/build/yui/yui-later.js' => '07f60f940e65cba323f7d1ea7770d6c4', + './include/javascript/yui3/build/yui/yui-log-min.js' => 'dcf94ddce82e2f7cfab2fd161cd1aa00', + './include/javascript/yui3/build/yui/yui-log.js' => '7c3b34cc3d8859dd9e02de454ba709bd', + './include/javascript/yui3/build/yui/yui-min.js' => '0ca4f321bfeed095cb08925a08b114cf', + './include/javascript/yui3/build/yui/yui.js' => '634b41d7fe986424d3e7763f1b18e9b2', + './include/javascript/yui3/build/yui-base/yui-base-min.js' => 'a20b8b96c0821cce4cc20ab3b99878dd', + './include/javascript/yui3/build/yui-base/yui-base.js' => '3a83e55089053158f8ec7423e2eeff57', + './include/javascript/yui3/build/widget/widget-min.js' => '24928861ac270e600b2ea3277612c5f1', + './include/javascript/yui3/build/widget/widget-position-ext-min.js' => '416976f75c79b425008d728aa253db16', + './include/javascript/yui3/build/widget/widget-position-ext.js' => 'afb3f01c231512ef5a280dda464dd5e1', + './include/javascript/yui3/build/widget/widget-position-min.js' => '3391301b7af5dea8c5163d0ddc63b480', + './include/javascript/yui3/build/widget/widget-position.js' => 'dfcee3d06222c8fc165b3627fed4502d', + './include/javascript/yui3/build/widget/widget-stack-min.js' => '4a4ab3267d670687cd8e815fb078d72c', + './include/javascript/yui3/build/widget/widget-stack.js' => 'cd97ea674bbe04b6a407d41df4f9c227', + './include/javascript/yui3/build/widget/widget-stdmod-min.js' => 'a846de3ea9c28347e820e1d89e2a6e8d', + './include/javascript/yui3/build/widget/widget-stdmod.js' => '7c224c854eee925dfcafe3721b4097e8', + './include/javascript/yui3/build/widget/widget.js' => '8679113a40a66836f11ce5599a12466a', + './include/javascript/yui3/build/widget/assets/widget-stack-core.css' => 'a919053fece78808dea8cf75726a2538', + './include/javascript/yui3/build/widget/assets/widget-core.css' => 'b5179c8ccb369156c4f06f95a0b8e990', + './include/javascript/yui3/build/widget/assets/skins/sam/widget.css' => 'decf1eca11ec8631869f28489f971cdb', + './include/javascript/yui3/build/widget/assets/skins/sam/widget-stack.css' => '49c59b028955c4d2636b68b2611fffc9', + './include/javascript/yui3/build/widget/assets/skins/sam/widget-stack-skin.css' => '59812846f1a49258858027fdff6fbaf3', + './include/javascript/yui3/build/widget/assets/skins/sam/widget-skin.css' => '59812846f1a49258858027fdff6fbaf3', + './include/javascript/yui3/build/test/test-min.js' => '033ba1b211a9e4d70660aa05826991de', + './include/javascript/yui3/build/test/test.js' => 'f50abfdd993e09d5da39e7ce7d50a18c', + './include/javascript/yui3/build/test/assets/test-console.css' => 'b0ea686a876f14fce6954adf5d36529f', + './include/javascript/yui3/build/substitute/substitute-min.js' => 'fc6b84ff1528df7994ed6356bf01f86e', + './include/javascript/yui3/build/substitute/substitute.js' => 'ab69725d254c9f349e344ac960172dab', + './include/javascript/yui3/build/stylesheet/stylesheet-min.js' => '2a4cdbf63bc1ca5dda092977b190a1ae', + './include/javascript/yui3/build/stylesheet/stylesheet.js' => 'f0d67c55d1fd7da85968ed7c2b9262ba', + './include/javascript/yui3/build/slider/slider-min.js' => 'e303db37ce46472d8f55e34d54a04137', + './include/javascript/yui3/build/slider/slider.js' => '540f11a0718a9a074b87f3430a509ae9', + './include/javascript/yui3/build/slider/assets/slider-core.css' => '9885637b85e819c60399de5f884077a0', + './include/javascript/yui3/build/slider/assets/skins/sam/thumb-classic-y.png' => 'e6e4114cf7d61a20a5dbd4c76a5be209', + './include/javascript/yui3/build/slider/assets/skins/sam/thumb-classic-x.png' => 'deb8a33ec9ce90048552b7e5a1037e7d', + './include/javascript/yui3/build/slider/assets/skins/sam/slider.css' => '326cae4687cb2c94162dee17c396bc93', + './include/javascript/yui3/build/slider/assets/skins/sam/slider-skin.css' => '9c8fb03e5edee0a7bd72977c65cfcecd', + './include/javascript/yui3/build/slider/assets/skins/sam/rail-classic-y.png' => '3a6d3464ade27ee27bda07164ea29522', + './include/javascript/yui3/build/slider/assets/skins/sam/rail-classic-x.png' => '0e63959f97250c7508a51156d6b14485', + './include/javascript/yui3/build/queue-promote/queue-promote-min.js' => '5325cd2a3927bc2604d215bda814086b', + './include/javascript/yui3/build/queue-promote/queue-promote.js' => 'c638f4003c43efd4e7a0514efb800a29', + './include/javascript/yui3/build/profiler/profiler-min.js' => 'f2edfec26e251a0c0e8ab2a60d8ae1d1', + './include/javascript/yui3/build/profiler/profiler.js' => '76c49beb7cbb35b363926fb62caf369c', + './include/javascript/yui3/build/pluginhost/pluginhost-min.js' => '1b6d52125e55f93b4d838d6f10bd07fb', + './include/javascript/yui3/build/pluginhost/pluginhost.js' => '8f9921dd73f6d2b3aca74cd0bcc378a3', + './include/javascript/yui3/build/plugin/plugin-min.js' => '9a6f05085e5789cc81b7bdf7f4416a86', + './include/javascript/yui3/build/plugin/plugin.js' => 'e874af2b2ce922f57d54decbc7e4a1d1', + './include/javascript/yui3/build/overlay/overlay-min.js' => 'b4436b95349403bef12b7a487abda44d', + './include/javascript/yui3/build/overlay/overlay.js' => '0ffa172f3345c7272130a8641a865879', + './include/javascript/yui3/build/overlay/assets/skins/sam/overlay.css' => '219eebcee501b42ad383b829b2769f04', + './include/javascript/yui3/build/overlay/assets/skins/sam/overlay-skin.css' => '59812846f1a49258858027fdff6fbaf3', + './include/javascript/yui3/build/overlay/assets/overlay-core.css' => 'ff18ef1ceac2fc47dc0a920ca0c6d5bd', + './include/javascript/yui3/build/oop/oop-min.js' => '94e8be1ddfeb4e286058df79e159b989', + './include/javascript/yui3/build/oop/oop.js' => '89ce994a0c43467881bf18a64b5001c0', + './include/javascript/yui3/build/node/node-aria-min.js' => '07baaf24f1a0b26bb8937d79f2012d83', + './include/javascript/yui3/build/node/node-aria.js' => 'a14fb15d9ce6b7bde2a0df7c70d5a2b5', + './include/javascript/yui3/build/node/node-base-min.js' => '16c579707a142ca35e59a415be9909d1', + './include/javascript/yui3/build/node/node-base.js' => '975e3f3e54f6c690d5995929dd283b24', + './include/javascript/yui3/build/node/node-event-delegate-min.js' => 'a2a8d53ca7b2393dc6d05da83ecfaf64', + './include/javascript/yui3/build/node/node-event-delegate.js' => '13125b0d67d12074bc6a9269c116c021', + './include/javascript/yui3/build/node/node-event-simulate-min.js' => '1de193e0c6ea9165fe0138c2d1efb1eb', + './include/javascript/yui3/build/node/node-event-simulate.js' => '8e03b149d0194d62b216a3f223b1cf22', + './include/javascript/yui3/build/node/node-min.js' => 'aa20c92139c922aa82c04e3f64405ee9', + './include/javascript/yui3/build/node/node-pluginhost-min.js' => '618bbd8e8143f23e519aade581751a93', + './include/javascript/yui3/build/node/node-pluginhost.js' => 'e367d2d1cb5a0b61213eacd6f2a2c7b6', + './include/javascript/yui3/build/node/node-screen-min.js' => '5e5e2b782c37dd0d55dfeb48d9d103f7', + './include/javascript/yui3/build/node/node-screen.js' => 'bb21fc6905894c310cc6e0f06b416ada', + './include/javascript/yui3/build/node/node-style-min.js' => 'c152d2219859cb6b990d528dd6b2dd7d', + './include/javascript/yui3/build/node/node-style.js' => 'af32e340c2380c0bbb5d8bc1ea651913', + './include/javascript/yui3/build/node/node.js' => 'f3a1b3164d28dbce4a782bd411d37ffe', + './include/javascript/yui3/build/node-menunav/node-menunav-min.js' => '47cb82e5f624fce3a7ba0ad0271f881e', + './include/javascript/yui3/build/node-menunav/node-menunav.js' => '18138e58f4fe46fef9dfa837aef72951', + './include/javascript/yui3/build/node-menunav/assets/skins/sam/vertical-menu-submenu-indicator.png' => '87184ef3556eee00e54a1f851c12207f', + './include/javascript/yui3/build/node-menunav/assets/skins/sam/node-menunav.css' => '341ba353588269be14ed6d93c46ca237', + './include/javascript/yui3/build/node-menunav/assets/skins/sam/node-menunav-skin.css' => 'a66ff1364052f54d7572d85dfe8661c7', + './include/javascript/yui3/build/node-menunav/assets/skins/sam/horizontal-menu-submenu-toggle.png' => 'e1b5111045cdbae5f59e6df43a2bcafd', + './include/javascript/yui3/build/node-menunav/assets/skins/sam/horizontal-menu-submenu-indicator.png' => '62b769d3a600489aea50fb253739d7f5', + './include/javascript/yui3/build/node-menunav/assets/node-menunav-core.css' => '9b56a6d04e68a3e5f1687245a6084a7e', + './include/javascript/yui3/build/node-focusmanager/node-focusmanager-min.js' => '1ca23d0d868386205fdb5acacdc4cddb', + './include/javascript/yui3/build/node-focusmanager/node-focusmanager.js' => '00faeecf0efad5efdf4b56ea6d31a28b', + './include/javascript/yui3/build/loader/loader-min.js' => 'f943f3e274fddf2e937a7bab9bc70323', + './include/javascript/yui3/build/loader/loader.js' => 'd82357d912f5af368f970c11eb0c1618', + './include/javascript/yui3/build/json/json-min.js' => 'bd246199d39cab10193ccabf17452fcc', + './include/javascript/yui3/build/json/json-parse-min.js' => '443cd2c26a853b2263b712c1b0ed91a2', + './include/javascript/yui3/build/json/json-parse.js' => '6b19d09358150539ab07206e67806693', + './include/javascript/yui3/build/json/json-stringify-min.js' => '1891fce482a008b15809fbd87e27e64f', + './include/javascript/yui3/build/json/json-stringify.js' => 'bc92bf8e7f328098af98dc56a5c66628', + './include/javascript/yui3/build/json/json.js' => 'e717d955bf0c1984683ea676806b418c', + './include/javascript/yui3/build/io/io-base-min.js' => 'ad093d327db9acd44e96c7bec01834c2', + './include/javascript/yui3/build/io/io-base.js' => '3c2749e169c78fd48f454bcb1296eac9', + './include/javascript/yui3/build/io/io-form-min.js' => 'd4c1b128c4b17011dfa59b7090a065a1', + './include/javascript/yui3/build/io/io-form.js' => 'f8ef8a53c0bb9eb7911ec2c26f17f331', + './include/javascript/yui3/build/io/io-min.js' => 'cb6737d563147a205a22c71e869e52f4', + './include/javascript/yui3/build/io/io-queue-min.js' => 'c004a8cfff9e76fa239812993e7e526b', + './include/javascript/yui3/build/io/io-queue.js' => 'c3833ccde8ad3aca5a4a862d131c10d9', + './include/javascript/yui3/build/io/io-upload-iframe-min.js' => 'efe6317a865d54dc3897825311ac5a56', + './include/javascript/yui3/build/io/io-upload-iframe.js' => '2f289cab687bd8637766064f1aea23b1', + './include/javascript/yui3/build/io/io-xdr-min.js' => '1dcd16c0c601c972c41579c7051a2a13', + './include/javascript/yui3/build/io/io-xdr.js' => '25dda989d81d33b916cb5a5f2bcf284d', + './include/javascript/yui3/build/io/io.js' => '1f71b1743c41fa870c0626b8bfd82341', + './include/javascript/yui3/build/io/io.swf' => '7f22020ec768608f2620681547e5cfbc', + './include/javascript/yui3/build/imageloader/imageloader-min.js' => '0dd73afb8af9fa4c103a5de38bbec440', + './include/javascript/yui3/build/imageloader/imageloader.js' => 'eb1dccf51b62a4c59b3da3a5b2ffee14', + './include/javascript/yui3/build/history/history-min.js' => '22140bf6f377d6b725937e900e68dab4', + './include/javascript/yui3/build/history/history.js' => '5a8a024b8e896200e698ae241fe4c707', + './include/javascript/yui3/build/get/get-min.js' => '1ef08bacb464ead1fbdb74d45addca6f', + './include/javascript/yui3/build/get/get.js' => '1b0ea131a29adf2a1957ad11be4547ff', + './include/javascript/yui3/build/event/event-base-min.js' => 'bd248be116bba85823265a8206cbe36d', + './include/javascript/yui3/build/event/event-base.js' => '92ccc471cdee58198eab607943360562', + './include/javascript/yui3/build/event/event-delegate-min.js' => '428983af53d0b8b858fb46c13f516e1c', + './include/javascript/yui3/build/event/event-delegate.js' => 'eb1d77f335a5b34fe73a0c94b414ada6', + './include/javascript/yui3/build/event/event-focus-min.js' => 'ec401fcab4159c03540d063bef4d9b22', + './include/javascript/yui3/build/event/event-focus.js' => 'ff7884f68c5470538f166cbe52d5e55d', + './include/javascript/yui3/build/event/event-key-min.js' => '821d19630010257815fb0b44b3aadfe9', + './include/javascript/yui3/build/event/event-key.js' => 'b3416de8b050f1abe6bb3cea6e523ad3', + './include/javascript/yui3/build/event/event-min.js' => 'a315bf56377bccb7ac2b43331a4b1cd8', + './include/javascript/yui3/build/event/event-mouseenter-min.js' => '85690f5f025129474a8e06aa70625b89', + './include/javascript/yui3/build/event/event-mouseenter.js' => 'c2e50e17beaaa3e5b0d4eb182fd294f8', + './include/javascript/yui3/build/event/event-mousewheel-min.js' => '2121a34c9a737efbf048f8616a8e1369', + './include/javascript/yui3/build/event/event-mousewheel.js' => '2e25fb70f46d98b7e96782f8251fad2d', + './include/javascript/yui3/build/event/event-resize-min.js' => '3bd4f239792c2098d5b8f66dbc1a7ad1', + './include/javascript/yui3/build/event/event-resize.js' => '48e0b8e089fc4fc81f7ea5da8b16dc0e', + './include/javascript/yui3/build/event/event.js' => '04a6c39b6b5e65fcf9668a8d86b7cbd7', + './include/javascript/yui3/build/event-simulate/event-simulate-min.js' => '7818508cf6a0e25499c24688b2b20406', + './include/javascript/yui3/build/event-simulate/event-simulate.js' => '6f662a708dc2340ca13036fda5bab4f3', + './include/javascript/yui3/build/event-custom/event-custom-base-min.js' => '4b625cecad442abbb569a0cdd0887493', + './include/javascript/yui3/build/event-custom/event-custom-base.js' => '1a5dd6bf38d5c749fead00d2e553bddd', + './include/javascript/yui3/build/event-custom/event-custom-complex-min.js' => '1e6c6cf8ea2edee2a161a718dccc2837', + './include/javascript/yui3/build/event-custom/event-custom-complex.js' => '180cac471b923c24a13f78844f019d83', + './include/javascript/yui3/build/event-custom/event-custom-min.js' => 'dea28503b25756864b17e10eda54d61c', + './include/javascript/yui3/build/event-custom/event-custom.js' => 'c668094f09a9b0bc5578791e47fd2893', + './include/javascript/yui3/build/dump/dump-min.js' => '068e9eea50bfb83a9c12afe83cf499b7', + './include/javascript/yui3/build/dump/dump.js' => '91be1ba2820235cf17e38bcb605f8b78', + './include/javascript/yui3/build/dom/dom-base-min.js' => '9c3ad02ffbb1f3db1be7da64f8623c9e', + './include/javascript/yui3/build/dom/dom-base.js' => 'd76d66b67ec8e36fe28592b4c6c5a30f', + './include/javascript/yui3/build/dom/dom-min.js' => '37e86bf4f93713df95b9b938567334d7', + './include/javascript/yui3/build/dom/dom-screen-min.js' => '08251d3308d9b44f1dde4acf1e15d633', + './include/javascript/yui3/build/dom/dom-screen.js' => 'd0bc1069b22426d73d10462d7776cd89', + './include/javascript/yui3/build/dom/dom-style-min.js' => 'e4d4f74b8c5732a916dcfba24273c591', + './include/javascript/yui3/build/dom/dom-style.js' => '1dbebcf7708ba19422ba4f5620a692a9', + './include/javascript/yui3/build/dom/dom.js' => '70c65fddd32a406f977fdb42a7e9ff68', + './include/javascript/yui3/build/dom/selector-css2-min.js' => '86238f9e2e3f3f90b263232fd974d4b3', + './include/javascript/yui3/build/dom/selector-css2.js' => 'c21d5d8d7a4e62e845ce6a447fedbb12', + './include/javascript/yui3/build/dom/selector-css3-min.js' => '1503711971a495b7d46978d189cf7007', + './include/javascript/yui3/build/dom/selector-css3.js' => '8b54097671f146aded273102d54cb4b5', + './include/javascript/yui3/build/dom/selector-min.js' => 'b5de0d7b3c29ece2f52cd9ef6ba88301', + './include/javascript/yui3/build/dom/selector-native-min.js' => 'd2197f895ad4fc7b5145f75c84944fc7', + './include/javascript/yui3/build/dom/selector-native.js' => '75083100c6ba1c87cc3c06ffa226f062', + './include/javascript/yui3/build/dom/selector.js' => '18548cdecaf34f0de097c010263f580c', + './include/javascript/yui3/build/dd/dd-constrain-min.js' => '6290d829f810688e2739af1c6ce6272d', + './include/javascript/yui3/build/dd/dd-constrain.js' => '038557ace27eec892e0d9daf918b4fb9', + './include/javascript/yui3/build/dd/dd-ddm-base-min.js' => '079b40427f308dc212255df488856794', + './include/javascript/yui3/build/dd/dd-ddm-base.js' => '65c29a76aa5ef5e81707a7c3c7b9f809', + './include/javascript/yui3/build/dd/dd-ddm-drop-min.js' => 'bba8ae8124f7ec4e68ed6a8e55161700', + './include/javascript/yui3/build/dd/dd-ddm-drop.js' => 'd4a35881e54a4b7f28a5ba85fa7895c2', + './include/javascript/yui3/build/dd/dd-ddm-min.js' => '3ddfd9710761a3064531718cebf95187', + './include/javascript/yui3/build/dd/dd-ddm.js' => '5083a97504632d87cd5e740730ac532a', + './include/javascript/yui3/build/dd/dd-drag-min.js' => '1bdc422b1923a0bc4d0c99a8851b6d1c', + './include/javascript/yui3/build/dd/dd-drag.js' => '70341cc3db548498ba8f7c047abc1616', + './include/javascript/yui3/build/dd/dd-drop-min.js' => '691d9acd4f668984dbae5d0fb856cbcd', + './include/javascript/yui3/build/dd/dd-drop-plugin-min.js' => '1b0846bca964a4e99693647acce1beaa', + './include/javascript/yui3/build/dd/dd-drop-plugin.js' => 'a8207858c656cd4ebb0a2f5412fb826a', + './include/javascript/yui3/build/dd/dd-drop.js' => '8e0e0340d4be9da07a30b9e6666066f4', + './include/javascript/yui3/build/dd/dd-min.js' => '8c2fd5421915946f56b6132c5bfe4f9f', + './include/javascript/yui3/build/dd/dd-plugin-min.js' => '73a8bf0154c958a356c1c12e3c48060f', + './include/javascript/yui3/build/dd/dd-plugin.js' => '2d4a2f2dc320427c83cf36990e201316', + './include/javascript/yui3/build/dd/dd-proxy-min.js' => 'ee714c93f2f6f64f64bc60cb5bdf6018', + './include/javascript/yui3/build/dd/dd-proxy.js' => '9d077cc1499ab15ffee62053d9307745', + './include/javascript/yui3/build/dd/dd-scroll-min.js' => '177a1ca26fa69cc996e05996af597271', + './include/javascript/yui3/build/dd/dd-scroll.js' => '17a73b129856a743aa67394ae9f9ff57', + './include/javascript/yui3/build/dd/dd.js' => '094be9ccf4245a1fcf6d6f1509aa2fb3', + './include/javascript/yui3/build/datatype/datatype-date-format-min.js' => 'c4a90c61683379637587b76b7a3eda5b', + './include/javascript/yui3/build/datatype/datatype-date-format.js' => '059876d6b1d1ba2258baf9573199c815', + './include/javascript/yui3/build/datatype/datatype-date-min.js' => '67ef0b57f36f1c082dde681b5dc4cac9', + './include/javascript/yui3/build/datatype/datatype-date-parse-min.js' => '83d946fd571f24dab5eef8e275e5a88a', + './include/javascript/yui3/build/datatype/datatype-date-parse.js' => '01774df34d3d1c1e0e5fdbe89d279eef', + './include/javascript/yui3/build/datatype/datatype-date.js' => '8aa84c5fd30a42fc87fbfdf5c7e8b18c', + './include/javascript/yui3/build/datatype/datatype-min.js' => '5ad6a4a794cc685364ed914001ea4963', + './include/javascript/yui3/build/datatype/datatype-number-format-min.js' => 'e7dc0ee322c84b81280456a23970661e', + './include/javascript/yui3/build/datatype/datatype-number-format.js' => '98a41dcf87ed49b4542153e4f9948ecf', + './include/javascript/yui3/build/datatype/datatype-number-min.js' => '5b8d7927725ed27e1a9941f2a2dc3476', + './include/javascript/yui3/build/datatype/datatype-number-parse-min.js' => 'ea00cc89968546a56296e36a13a83fca', + './include/javascript/yui3/build/datatype/datatype-number-parse.js' => 'e11fd0bfdd7f84d167fa81df7ad06e02', + './include/javascript/yui3/build/datatype/datatype-number.js' => '5267cfb4bbdcf58ca3a1cc1e976c23d0', + './include/javascript/yui3/build/datatype/datatype-xml-format-min.js' => 'c5ed66f244249172c501fd4365ca723c', + './include/javascript/yui3/build/datatype/datatype-xml-format.js' => 'c3630d07c01dcf68a0506a49645273f7', + './include/javascript/yui3/build/datatype/datatype-xml-min.js' => '372e21766c256f78afd4e93402084176', + './include/javascript/yui3/build/datatype/datatype-xml-parse-min.js' => '78ddb4361d34fa01f71ea6b22cf5fc67', + './include/javascript/yui3/build/datatype/datatype-xml-parse.js' => '41b61808a06550c0d6b4015ae0757cba', + './include/javascript/yui3/build/datatype/datatype-xml.js' => '4eb36e4855f607d4d1223116a60c6d96', + './include/javascript/yui3/build/datatype/datatype.js' => 'bbb56fb027edbd2bd83d4c7bb0cdb492', + './include/javascript/yui3/build/datasource/datasource-arrayschema-min.js' => '54a3f31550dfc779bdf7ff3badfb0b42', + './include/javascript/yui3/build/datasource/datasource-arrayschema.js' => '0d50e9272104d7c7c95ee777558aa943', + './include/javascript/yui3/build/datasource/datasource-cache-min.js' => 'd8084fda943fab9ce469dda2c4e2457d', + './include/javascript/yui3/build/datasource/datasource-cache.js' => 'c93d1b23e37c2305c48db36537075a67', + './include/javascript/yui3/build/datasource/datasource-function-min.js' => '093a0fa4464a0c80b79252ae24d5c5b6', + './include/javascript/yui3/build/datasource/datasource-function.js' => 'd7cdd6bfa8a846a3dbaf01af8a77efd3', + './include/javascript/yui3/build/datasource/datasource-get-min.js' => 'e89e61c3ab703c0820917c6cdc99ff03', + './include/javascript/yui3/build/datasource/datasource-get.js' => '47560101c731893a1bbf083f1084083a', + './include/javascript/yui3/build/datasource/datasource-io-min.js' => 'f6232b38432e577ea1a030a479b5467e', + './include/javascript/yui3/build/datasource/datasource-io.js' => '73d1888f5c2264b1808347e113aeb01a', + './include/javascript/yui3/build/datasource/datasource-jsonschema-min.js' => '6c0a0b15fc15bb76b7295997b18b9c99', + './include/javascript/yui3/build/datasource/datasource-jsonschema.js' => '3afaf4b857ae45b972adcdd7186a4a44', + './include/javascript/yui3/build/datasource/datasource-local-min.js' => '66895699cf49802a7f1a0420160a1632', + './include/javascript/yui3/build/datasource/datasource-local.js' => '2adc1e3db8e2629e55d2c14cf929cc6f', + './include/javascript/yui3/build/datasource/datasource-min.js' => '904efd35e9081b5f6df7e7dcf823b57d', + './include/javascript/yui3/build/datasource/datasource-polling-min.js' => '74d4d6dc75a9fc21377a27b55b4db1e4', + './include/javascript/yui3/build/datasource/datasource-polling.js' => '974f135f59c95b9c432f85d2dbe402a3', + './include/javascript/yui3/build/datasource/datasource-textschema-min.js' => 'aacfb74656f75d1ec557b8369e84b825', + './include/javascript/yui3/build/datasource/datasource-textschema.js' => '9d06a4ea4ea528cb81d14018dcada0d7', + './include/javascript/yui3/build/datasource/datasource-xmlschema-min.js' => 'f6c390a5e74debc110ce87ef24b9ed8a', + './include/javascript/yui3/build/datasource/datasource-xmlschema.js' => 'f486482e659d075719ad32d65019d06c', + './include/javascript/yui3/build/datasource/datasource.js' => 'ec2844604a261f1d9ae7a239817a6f03', + './include/javascript/yui3/build/dataschema/dataschema-array-min.js' => '1da125ea08ae73cb62231e1b510c4ea5', + './include/javascript/yui3/build/dataschema/dataschema-array.js' => '832de48fde2a6dfd8a1646a674751a7b', + './include/javascript/yui3/build/dataschema/dataschema-base-min.js' => '41aa325522c432a9ae37d25aae6f0831', + './include/javascript/yui3/build/dataschema/dataschema-base.js' => '4d81eca661f31765fb7cb150227a584e', + './include/javascript/yui3/build/dataschema/dataschema-json-min.js' => '4b463cd540353e1444926ee4e4c9a6e5', + './include/javascript/yui3/build/dataschema/dataschema-json.js' => 'ab616e53d0b4e9676a573eec0a38e5c2', + './include/javascript/yui3/build/dataschema/dataschema-min.js' => '0753babed0c9001e18d5b099e1cd1633', + './include/javascript/yui3/build/dataschema/dataschema-text-min.js' => '5c8f1fc336008532beabfcd0f479a864', + './include/javascript/yui3/build/dataschema/dataschema-text.js' => 'c990b48e76d4406b717442fc6c696b42', + './include/javascript/yui3/build/dataschema/dataschema-xml-min.js' => '8b717693f65c950faaaf848a30fc98f2', + './include/javascript/yui3/build/dataschema/dataschema-xml.js' => '990766bdcf296cd54ae928cbeb62e207', + './include/javascript/yui3/build/dataschema/dataschema.js' => '596041b46c646351a5a490d4124ee2dc', + './include/javascript/yui3/build/cssreset/reset.css' => '4620c834f141d4527d38f470c855b964', + './include/javascript/yui3/build/cssreset/reset-min.css' => '0fc84044bc23bb989184e82f3989dc65', + './include/javascript/yui3/build/cssreset/reset-context.css' => 'aac508dbeb6503ca26b2b4434bba4ce1', + './include/javascript/yui3/build/cssreset/reset-context-min.css' => '9b934f6839f956fcafff6bfb4466f848', + './include/javascript/yui3/build/cssgrids/grids.css' => '5fac4246059e2bd304fe401603491a36', + './include/javascript/yui3/build/cssgrids/grids-min.css' => 'd3915ec4650723a7deefcc135709d431', + './include/javascript/yui3/build/cssgrids/grids-context.css' => 'f22f5c7c935d3e399cf8159a1fe0dc36', + './include/javascript/yui3/build/cssgrids/grids-context-min.css' => '4350943c5368220f078c7921781bb704', + './include/javascript/yui3/build/cssfonts/fonts.css' => '8a50b73116a8af42861533a78632a72d', + './include/javascript/yui3/build/cssfonts/fonts-min.css' => '67f666465e2ddaea2843e62ebca3cc9e', + './include/javascript/yui3/build/cssfonts/fonts-context.css' => 'b2027737dec2b597295f0b3d5b3aac17', + './include/javascript/yui3/build/cssfonts/fonts-context-min.css' => '25aeaa650efa70be99939f484aca165d', + './include/javascript/yui3/build/cssbase/base.css' => '49460517794eb5d71e4965caac8e3ac0', + './include/javascript/yui3/build/cssbase/base-min.css' => 'c93f66a2750f6402a620ae0ba9784928', + './include/javascript/yui3/build/cssbase/base-context.css' => '592d9bc8b4188e02313de63db250780a', + './include/javascript/yui3/build/cssbase/base-context-min.css' => '771b3d5f2384525a3c8b887d7ddd40ce', + './include/javascript/yui3/build/cookie/cookie-min.js' => 'be1afb25070e3a5eddc0b20e44fe2097', + './include/javascript/yui3/build/cookie/cookie.js' => '7656833d613e0137f4ebb8a43587d440', + './include/javascript/yui3/build/console/console-filters-min.js' => 'ad8e6eaa1c01016556ac5cba11092467', + './include/javascript/yui3/build/console/console-filters.js' => '65ee22b67d6c4272e144dbdc067dac8e', + './include/javascript/yui3/build/console/console-min.js' => 'cd61cb88ce9857df6e48d1a4f1b3ecb8', + './include/javascript/yui3/build/console/console.js' => '2be4b0cf026e8beee786a1f19c0a5a75', + './include/javascript/yui3/build/console/assets/warn_error.png' => 'e01a08081fe9a53ae4a2c7a5b60a1a48', + './include/javascript/yui3/build/console/assets/skins/sam/warn_error.png' => 'e01a08081fe9a53ae4a2c7a5b60a1a48', + './include/javascript/yui3/build/console/assets/skins/sam/console.css' => '4bf25a1e6d77ae224a609ebfd6d7a016', + './include/javascript/yui3/build/console/assets/skins/sam/console-skin.css' => '5bf304893499dcd980e53b6a003b0f47', + './include/javascript/yui3/build/console/assets/skins/sam/console-filters.css' => '9f9fa29cde9bce61394823a8a643c7f7', + './include/javascript/yui3/build/console/assets/skins/sam/console-filters-skin.css' => '89a1200557889da682fa346bdb484f4e', + './include/javascript/yui3/build/console/assets/skins/sam/bg.png' => 'f6e5fc4c034f96c68f446745a2881982', + './include/javascript/yui3/build/console/assets/console-filters-core.css' => '59812846f1a49258858027fdff6fbaf3', + './include/javascript/yui3/build/console/assets/console-core.css' => '59812846f1a49258858027fdff6fbaf3', + './include/javascript/yui3/build/compat/compat-min.js' => '3a7288f0d4b97257340f7dce096dd790', + './include/javascript/yui3/build/compat/compat.js' => '0361cb333f0c10fc16aa6330883d8cb6', + './include/javascript/yui3/build/collection/collection-min.js' => '27507198b7648cb044051b5dadd32790', + './include/javascript/yui3/build/collection/collection.js' => '3f0f937772af5258120d9bcaf1d8fab0', + './include/javascript/yui3/build/classnamemanager/classnamemanager-min.js' => '3e4b3d6d44863d14d50308c5b3604aa5', + './include/javascript/yui3/build/classnamemanager/classnamemanager.js' => '6460e339c1c7d3b03af1064e65def703', + './include/javascript/yui3/build/cache/cache-min.js' => 'b964ef4fc9869e1e536073226037ba7b', + './include/javascript/yui3/build/cache/cache.js' => '1e45c8d426e20b6ff7dcca6e9e5448bb', + './include/javascript/yui3/build/base/base-base-min.js' => '0b99f4c71261bec9d2118f55444deb8f', + './include/javascript/yui3/build/base/base-base.js' => 'a1d66a494770906742d50510eef34af2', + './include/javascript/yui3/build/base/base-build-min.js' => 'be15f4401563fc297401a7df32cde00f', + './include/javascript/yui3/build/base/base-build.js' => 'cf23c606697a7bb9dac1adfbc0e35e7c', + './include/javascript/yui3/build/base/base-min.js' => '470bdcf6dd32055f9589b59209482c39', + './include/javascript/yui3/build/base/base-pluginhost-min.js' => '109d2f7c66169ba3d95fdc7fded3823b', + './include/javascript/yui3/build/base/base-pluginhost.js' => '39a9d89846690bdb56044b4f92bc3971', + './include/javascript/yui3/build/base/base.js' => '2ebc14e446712d22b646fe6921227c99', + './include/javascript/yui3/build/attribute/attribute-base-min.js' => '1f598cd27c3d1eadc991f18c83627894', + './include/javascript/yui3/build/attribute/attribute-base.js' => '61c540b1f48a5d21982b1d9a58b40f90', + './include/javascript/yui3/build/attribute/attribute-complex-min.js' => 'e74ae70bc5491c792d83e195ee440a99', + './include/javascript/yui3/build/attribute/attribute-complex.js' => '741e91761924be8142dfd7d7e42422e9', + './include/javascript/yui3/build/attribute/attribute-min.js' => 'fc92d332455940e09fca12659987ebb1', + './include/javascript/yui3/build/attribute/attribute.js' => '2f2c9f75435f80ed9124db3aadc98f1a', + './include/javascript/yui3/build/async-queue/async-queue-min.js' => '38c208830472dd9fa0e0080be1d30304', + './include/javascript/yui3/build/async-queue/async-queue.js' => 'c036daac1a6511659ccf63eae26ab85d', + './include/javascript/yui3/build/assets/skins/sam/widget.css' => 'decf1eca11ec8631869f28489f971cdb', + './include/javascript/yui3/build/assets/skins/sam/widget-stack.css' => '49c59b028955c4d2636b68b2611fffc9', + './include/javascript/yui3/build/assets/skins/sam/warn_error.png' => 'e01a08081fe9a53ae4a2c7a5b60a1a48', + './include/javascript/yui3/build/assets/skins/sam/vertical-menu-submenu-indicator.png' => '87184ef3556eee00e54a1f851c12207f', + './include/javascript/yui3/build/assets/skins/sam/thumb-classic-y.png' => 'e6e4114cf7d61a20a5dbd4c76a5be209', + './include/javascript/yui3/build/assets/skins/sam/thumb-classic-x.png' => 'deb8a33ec9ce90048552b7e5a1037e7d', + './include/javascript/yui3/build/assets/skins/sam/sprite.png' => '4ea9c76ddccae0835ba727ee902809f3', + './include/javascript/yui3/build/assets/skins/sam/slider.css' => '326cae4687cb2c94162dee17c396bc93', + './include/javascript/yui3/build/assets/skins/sam/skin.css' => '8d5469df09b7b6a9bad72751ed4e4b0f', + './include/javascript/yui3/build/assets/skins/sam/rail-classic-y.png' => '3a6d3464ade27ee27bda07164ea29522', + './include/javascript/yui3/build/assets/skins/sam/rail-classic-x.png' => '0e63959f97250c7508a51156d6b14485', + './include/javascript/yui3/build/assets/skins/sam/overlay.css' => '219eebcee501b42ad383b829b2769f04', + './include/javascript/yui3/build/assets/skins/sam/node-menunav.css' => '6de96ec7ff0f35f61bc93064a020c5ff', + './include/javascript/yui3/build/assets/skins/sam/horizontal-menu-submenu-toggle.png' => 'e1b5111045cdbae5f59e6df43a2bcafd', + './include/javascript/yui3/build/assets/skins/sam/horizontal-menu-submenu-indicator.png' => '62b769d3a600489aea50fb253739d7f5', + './include/javascript/yui3/build/assets/skins/sam/console.css' => '4bf25a1e6d77ae224a609ebfd6d7a016', + './include/javascript/yui3/build/assets/skins/sam/console-filters.css' => '9f9fa29cde9bce61394823a8a643c7f7', + './include/javascript/yui3/build/assets/skins/sam/bg.png' => 'f6e5fc4c034f96c68f446745a2881982', + './include/javascript/yui3/build/anim/anim-base-min.js' => '91662c77dfa4ad009efee3489a246d01', + './include/javascript/yui3/build/anim/anim-base.js' => 'cac937b2ca252c6266279899a5de0bc0', + './include/javascript/yui3/build/anim/anim-color-min.js' => 'a41b18d7cd6bff118bd78941fa198e61', + './include/javascript/yui3/build/anim/anim-color.js' => 'f7185fad505c2b57342a399d8bac4cd7', + './include/javascript/yui3/build/anim/anim-curve-min.js' => '3a384e737322f61804e34c54393b4809', + './include/javascript/yui3/build/anim/anim-curve.js' => 'de090c4d26560e406a8b5c56c4bb6543', + './include/javascript/yui3/build/anim/anim-easing-min.js' => '7900d73784f5affdfa8862f1720820dd', + './include/javascript/yui3/build/anim/anim-easing.js' => '9982c65fb7258854b26a10c8e97e4cb6', + './include/javascript/yui3/build/anim/anim-min.js' => '76ce9b1c0457bdd6da70a09ab4c41419', + './include/javascript/yui3/build/anim/anim-node-plugin-min.js' => '0cb4158426369fc59a33ea477e29b28e', + './include/javascript/yui3/build/anim/anim-node-plugin.js' => '211a2225128f134bdebe7fde816351f1', + './include/javascript/yui3/build/anim/anim-scroll-min.js' => '41ef20a94de29f1cad55965d3d795f71', + './include/javascript/yui3/build/anim/anim-scroll.js' => 'b3dddd491c08d1e2cfae861f825f6508', + './include/javascript/yui3/build/anim/anim-xy-min.js' => '2643b18f3ee1bcc09bc8a12ceec10606', + './include/javascript/yui3/build/anim/anim-xy.js' => '38dea1e654a4e335118deaa246bbfe58', + './include/javascript/yui3/build/anim/anim.js' => 'fd0530bc935a92dd7ec1d8d9729b6574', + './include/javascript/yui3/assets/dpSyntaxHighlighter.js' => '0bfd5d587be32798fe8bd154a1841741', + './include/javascript/yui3/assets/syntax.js' => '8c29456f20e51920755725052aedb62e', + './include/javascript/yui3/assets/yuiDistribution.css' => 'd41d8cd98f00b204e9800998ecf8427e', + './include/javascript/yui3/assets/yui.gif' => '8ba75836301307e25bf940af92414d20', + './include/javascript/yui3/assets/yui.css' => '17630f5861c6e063db0f7f193f96aff4', + './include/javascript/yui3/assets/yui-candy.jpg' => '0623c401d53acb36baa31f8c0c38f3da', + './include/javascript/yui3/assets/title_h_bg.gif' => '3683c5c7fa614fb5bc5f18176a22bf8c', + './include/javascript/yui3/assets/logo.gif' => '96f44b0eb09ee44f75c5f78f0593741a', + './include/javascript/yui3/assets/gradient-promo.png' => 'fbdd8e0af587f4863bf5666c41a3f969', + './include/javascript/yui3/assets/gradient-mod.png' => 'b8c21c70eb39b9ba11d295bfed0ddf28', + './include/javascript/yui3/assets/gradient-ex-box.png' => 'ea2931d4cd5ee440539d43e97a740b9d', + './include/javascript/yui3/assets/example-hd-bg.gif' => '5c5c0e34d0e6b3013063e0cb36978034', + './include/javascript/yui3/assets/dpSyntaxHighlighter.css' => '09fd49eb6c58f17aecdb994aecf1e9e1', + './include/javascript/yui3/assets/download-arrow.png' => '82d9b5b77f9222008b6c361e34353f6e', + './include/javascript/yui3/assets/cheatsheet-thumbnail.png' => '0e818b16c5932f24ba5e34ec44672e83', + './include/javascript/yui3/assets/cheatsheet-shadow.jpg' => '9c9a0ebb39022282f6475dcb2f5d897a', + './include/javascript/yui3/assets/bullet4x4.png' => 'ee724d824e5f1deb1b2eeba335b9b911', + './include/javascript/yui3/assets/bullet-box6x6.gif' => 'a6379354fa59c989cb7ae65e2a7aa360', + './include/javascript/yui3/assets/bg_hd.gif' => '0a295c3fab0790f5c65a806c56dc2836', + './include/javascript/yui3/README' => 'b3cd942e83fcdbdc12917233609b4edf', + './include/javascript/yui/ygDDList.js' => '863df2609cd089430316027e7238561f', + './include/javascript/yui/index.html' => 'e42f1c8fdae8ca33f4816e5305997dbe', + './include/javascript/yui/ext/yui-ext.js' => '942c45c9f9f78724af53b364a3b9d361', + './include/javascript/yui/build/yuitest/yuitest_core.js' => 'd666571a5c06fd516f5d7fb637955253', + './include/javascript/yui/build/yuitest/yuitest_core-min.js' => 'c2fb5eef18d517e9f02e91de6c1340dc', + './include/javascript/yui/build/yuitest/yuitest.js' => '72d90cd6eb9c201aaabca4f30f5f1bae', + './include/javascript/yui/build/yuitest/yuitest-min.js' => '4cf56a06375f215cbb77bc4bf2013e93', + './include/javascript/yui/build/yuitest/assets/yuitest-core.css' => '793339721d8f8dea54c60348fe4a853e', + './include/javascript/yui/build/yuitest/assets/testlogger.css' => 'bbcd5b021e71b0c9d7f5c0c751294e78', + './include/javascript/yui/build/yuitest/assets/skins/sam/yuitest.css' => '793339721d8f8dea54c60348fe4a853e', + './include/javascript/yui/build/yuitest/assets/skins/sam/yuitest-skin.css' => '793339721d8f8dea54c60348fe4a853e', + './include/javascript/yui/build/yuiloader/yuiloader.js' => '5ecccf3367864d9d150a33432eae7d60', + './include/javascript/yui/build/yuiloader/yuiloader-min.js' => '11ea66c5bc6689358864d4c6207a03ba', + './include/javascript/yui/build/yuiloader-dom-event/yuiloader-dom-event.js' => '4c647048cabe1cb781c8f322b0981ba7', + './include/javascript/yui/build/yahoo/yahoo.js' => '486529fd3525b9bcbaaca728b5fe1172', + './include/javascript/yui/build/yahoo/yahoo-min.js' => '77aaedc174f0cbc57a706c09b2342a90', + './include/javascript/yui/build/yahoo-dom-event/yahoo-dom-event.js' => '3ae37167c141a29c1c11f254de0d7abf', + './include/javascript/yui/build/utilities/utilities.js' => '54daab1bb64dbe576b51e12ad9a63658', + './include/javascript/yui/build/uploader/uploader.js' => '16e1ad4f188237681ad726573ddaf52d', + './include/javascript/yui/build/uploader/uploader-min.js' => '8f09d6ce891046f386a5e86309d08614', + './include/javascript/yui/build/uploader/assets/uploader.swf' => '52f36a13ac4ee2743531de3e29c0b55c', + './include/javascript/yui/build/treeview/treeview.js' => '2678dd6d0fba93e223c33738a8ab2e45', + './include/javascript/yui/build/treeview/treeview-min.js' => '0b3fe246a06eac9a57f1a0dbade36245', + './include/javascript/yui/build/treeview/assets/treeview-core.css' => '9f1c2687bab335e4a0f822734461bf66', + './include/javascript/yui/build/treeview/assets/skins/sam/treeview.css' => 'cf472192f2e3c5e89098f9d83732c746', + './include/javascript/yui/build/treeview/assets/skins/sam/treeview-sprite.gif' => '115a1070e1398629700a11d4f5d546bb', + './include/javascript/yui/build/treeview/assets/skins/sam/treeview-skin.css' => '89d70f2c42ecca5633a2df7bce2698f4', + './include/javascript/yui/build/treeview/assets/skins/sam/treeview-loading.gif' => '8f1310bf9e7aa892d2dc09c4058c7bd3', + './include/javascript/yui/build/treeview/assets/skins/sam/loading.gif' => '8f1310bf9e7aa892d2dc09c4058c7bd3', + './include/javascript/yui/build/treeview/assets/skins/sam/check2.gif' => '3544088604d6d6e519a3a392db89c38d', + './include/javascript/yui/build/treeview/assets/skins/sam/check1.gif' => '691389bb26f429e79666599992a384b3', + './include/javascript/yui/build/treeview/assets/skins/sam/check0.gif' => 'd3e7d474e008b8cb585eb05c5baafe5a', + './include/javascript/yui/build/tabview/tabview.js' => 'c83792b51d4bd8ec2fc8994da1e8a118', + './include/javascript/yui/build/tabview/tabview-min.js' => '43be75d958658b98fc5cffc3e65716a2', + './include/javascript/yui/build/tabview/assets/tabview.css' => 'b94fe6019b5dec4aa7aa1f6b959f5b31', + './include/javascript/yui/build/tabview/assets/tabview-core.css' => '44c5638a67a0ca601474358c472022c1', + './include/javascript/yui/build/tabview/assets/skins/sam/tabview.css' => '3f056254db4fa5cf31fd90b2e5565fd8', + './include/javascript/yui/build/tabview/assets/skins/sam/tabview-skin.css' => '238f3ee3362c44a0c0394030346c6340', + './include/javascript/yui/build/tabview/assets/skin-sam.css' => 'f6fac582b70ad0d67e8956b1ec2623f3', + './include/javascript/yui/build/tabview/assets/loading.gif' => 'c8ad9845c9414424cb5854238af212b0', + './include/javascript/yui/build/tabview/assets/border_tabs.css' => 'dce2811d325e5a856321732e0440afcd', + './include/javascript/yui/build/swfstore/swfstore.swf' => 'f619420748b08a2d453c049ef190e2f3', + './include/javascript/yui/build/swfstore/swfstore.js' => 'ac89b5a9745250c94cbcc68b618f85ce', + './include/javascript/yui/build/swfstore/swfstore-min.js' => 'ca4adbcee388561e209433449009b1da', + './include/javascript/yui/build/swfstore/swfstore-debug.js' => 'd66fda76f6a7d9a1c90e30db0659b0f3', + './include/javascript/yui/build/swfstore/swf.js' => 'be78c3c95997313d704c49b97e788b35', + './include/javascript/yui/build/swfdetect/swfdetect.js' => 'ebeaad88ce7a268f1772f0b4e7418831', + './include/javascript/yui/build/swfdetect/swfdetect-min.js' => '0af595e80b22026d746c9cdfbb0ffaef', + './include/javascript/yui/build/swfdetect/swfdetect-debug.js' => 'ebeaad88ce7a268f1772f0b4e7418831', + './include/javascript/yui/build/swf/swf.js' => 'bd21dfaf72392b5d80cd3c73e4f896b4', + './include/javascript/yui/build/swf/swf-min.js' => '13ba9a2beb92c3d7cc2c08e2ca2507a0', + './include/javascript/yui/build/swf/swf-debug.js' => '70ca534287813be497d683055270289d', + './include/javascript/yui/build/stylesheet/stylesheet.js' => 'a32f1772028a92d37c44c155b2f538fe', + './include/javascript/yui/build/stylesheet/stylesheet-min.js' => 'ea1f7d01349ca0b84c34d9140424231d', + './include/javascript/yui/build/stylesheet/stylesheet-debug.js' => 'd8eb31878d3759f1005b9227ff390669', + './include/javascript/yui/build/storage/storage.js' => 'e80f2b4ed0ac24f1c9af0f034f2362a6', + './include/javascript/yui/build/storage/storage-min.js' => '75d3116953b72bfcaf5941d3e1e7a103', + './include/javascript/yui/build/storage/storage-debug.js' => 'a5af17949aa0532435f13a70b27201da', + './include/javascript/yui/build/slider/slider.js' => 'c924262c640f884f7d6a1f3deec8a93a', + './include/javascript/yui/build/slider/slider-min.js' => '27e7e4aeacd791f08c90568f4e79b43e', + './include/javascript/yui/build/slider/assets/thumb-w.gif' => 'f1af28a0a7a0b4b76e973e7988d20dea', + './include/javascript/yui/build/slider/assets/thumb-s.gif' => '60824e3c3c961ca92fd80dc1d55e4243', + './include/javascript/yui/build/slider/assets/thumb-n.gif' => '449f6baf5f9377f95653d5c076efb659', + './include/javascript/yui/build/slider/assets/thumb-fader.gif' => '0267805612e4e9fed7ccaa3da9fc0f2a', + './include/javascript/yui/build/slider/assets/thumb-e.gif' => '3d879ac8ed946408795c33c20e32577f', + './include/javascript/yui/build/slider/assets/thumb-bar.gif' => 'e0575ef16dce100560ba893ff4723916', + './include/javascript/yui/build/slider/assets/slider-skin.css' => '6c05532041c0ba689947ebf10c4ec0b0', + './include/javascript/yui/build/slider/assets/slider-core.css' => '929d2b3257800724e51bbfa109081d30', + './include/javascript/yui/build/slider/assets/skins/sam/slider.css' => '71f7bccc93416362d854d66c50383d3d', + './include/javascript/yui/build/slider/assets/skins/sam/slider-skin.css' => 'ce979fdbee3ed431bc82e068c540ef92', + './include/javascript/yui/build/slider/assets/skins/sam/bg-v.gif' => '220b443b77004914d4293a655299e2ce', + './include/javascript/yui/build/slider/assets/skins/sam/bg-h.gif' => '4d4b3a56c225f8f21f7d839ba2b03823', + './include/javascript/yui/build/slider/assets/right-thumb.png' => 'fe58c629da3f86f895948ec31b0dbfbc', + './include/javascript/yui/build/slider/assets/left-thumb.png' => 'b632385b388c15469ddc0bfdc1a3171f', + './include/javascript/yui/build/slider/assets/bg-v.gif' => '220b443b77004914d4293a655299e2ce', + './include/javascript/yui/build/slider/assets/bg-v-e.gif' => '73d2cdb479eb4707285df7c2dbb28062', + './include/javascript/yui/build/slider/assets/bg-h.gif' => '4d4b3a56c225f8f21f7d839ba2b03823', + './include/javascript/yui/build/slider/assets/bg-fader.gif' => '0c9eb4a1518994aa9786ff6f81a74cec', + './include/javascript/yui/build/selector/selector.js' => '8571aa5258087bb561f328fc31ecc843', + './include/javascript/yui/build/selector/selector-min.js' => '49bd722cb23d1c2db6fd7bb2e0183b4c', + './include/javascript/yui/build/resize/resize.js' => '610bdd65b4fe6370cdd1c802e467311e', + './include/javascript/yui/build/resize/resize-min.js' => 'c45230b8375ab231ffbb9a284d378a21', + './include/javascript/yui/build/resize/assets/skins/sam/resize.css' => '9c978b19e16ad208645904c9323d5a31', + './include/javascript/yui/build/resize/assets/skins/sam/resize-skin.css' => '46eb43f9766fd1dc7ae2d9d61d4d6401', + './include/javascript/yui/build/resize/assets/skins/sam/layout_sprite.png' => '0f5a66998a0b88cabfe0489a6a11e28a', + './include/javascript/yui/build/resize/assets/resize-core.css' => 'af00fd53873d777cb499ae008f9e0d20', + './include/javascript/yui/build/reset/reset.css' => '87c995762e9c3571fab20d3d66d65cd5', + './include/javascript/yui/build/reset/reset-min.css' => '7064a8abc350d6dba25c20d076f7dd27', + './include/javascript/yui/build/reset-fonts/reset-fonts.css' => '318520f77ef065ae80c2b86959d4e18f', + './include/javascript/yui/build/reset-fonts-grids/reset-fonts-grids.css' => '2162df6e1ab29d6d2e5cc3748dac9bcc', + './include/javascript/yui/build/progressbar/progressbar.js' => 'b655118de0fd819c39726a71e32a2558', + './include/javascript/yui/build/progressbar/progressbar-min.js' => '08a63d34f5fbae4661fd4c5a7ca1dea1', + './include/javascript/yui/build/progressbar/progressbar-debug.js' => '47f02484fcc5b33634045afa77a1fb22', + './include/javascript/yui/build/progressbar/assets/skins/sam/progressbar.css' => 'f39fc4327836dbf61b7e433f6246e0ab', + './include/javascript/yui/build/progressbar/assets/skins/sam/progressbar-skin.css' => '5f51c6363ad92b2d5128989b8c8deea0', + './include/javascript/yui/build/progressbar/assets/skins/sam/bar-v.png' => '54cd63ec61c91525f081428bc784021c', + './include/javascript/yui/build/progressbar/assets/skins/sam/bar-h.png' => 'a4182c879e01c66bfaf9c188202c326b', + './include/javascript/yui/build/progressbar/assets/skins/sam/back-v.png' => 'f0179d9bbb6e6f7796caed9d1b0b9795', + './include/javascript/yui/build/progressbar/assets/skins/sam/back-h.png' => '972e692bc2c40a33fa30f3333c5e5821', + './include/javascript/yui/build/progressbar/assets/progressbar-core.css' => '2c9f30552602be5e6daf29344a99de86', + './include/javascript/yui/build/profilerviewer/profilerviewer.js' => 'f0a5893b36d97f98888ade53e1ddd4c9', + './include/javascript/yui/build/profilerviewer/profilerviewer-min.js' => 'da0e88a3081b58466c732a17678ebfb0', + './include/javascript/yui/build/profilerviewer/assets/skins/sam/wait.gif' => 'b0cd5a5dc070c705ebf8814a909802c3', + './include/javascript/yui/build/profilerviewer/assets/skins/sam/profilerviewer.css' => 'e07d72c12fc6c0028b89d88da7ec53d2', + './include/javascript/yui/build/profilerviewer/assets/skins/sam/profilerviewer-skin.css' => '2bc47f550e74e5d9b9ef651cbcc22a7b', + './include/javascript/yui/build/profilerviewer/assets/skins/sam/header_background.png' => '412285f6b44f1d7757fc005680c2ecf5', + './include/javascript/yui/build/profilerviewer/assets/skins/sam/desc.gif' => '4708d3f08d550225360a43cd8ca2fab4', + './include/javascript/yui/build/profilerviewer/assets/skins/sam/asc.gif' => '7053becd07a62f576bb8767a5d9875f0', + './include/javascript/yui/build/profilerviewer/assets/profilerviewer-core.css' => '9f1c2687bab335e4a0f822734461bf66', + './include/javascript/yui/build/profiler/profiler.js' => 'dd7475150e312ac555719de0878b53f3', + './include/javascript/yui/build/profiler/profiler-min.js' => 'ee66b42f20934e38d037b2071a915e14', + './include/javascript/yui/build/paginator/paginator.js' => '68bffc0ceb2284e0dd8c9cd3d4df51ee', + './include/javascript/yui/build/paginator/paginator-min.js' => '36567e4352247721e1290389ba0dd63e', + './include/javascript/yui/build/paginator/assets/skins/sam/paginator.css' => '2bb7f5bf775e4770dd2b6f9e36611b92', + './include/javascript/yui/build/paginator/assets/skins/sam/paginator-skin.css' => '7c8c3b867d33822a9611d625cc74145c', + './include/javascript/yui/build/paginator/assets/paginator-core.css' => '9f1c2687bab335e4a0f822734461bf66', + './include/javascript/yui/build/menu/menu.js' => 'a752c70e244872c18a5af5c85027f7f9', + './include/javascript/yui/build/menu/menu-min.js' => 'b5f52e06eb6ab1b34810aa301608b830', + './include/javascript/yui/build/menu/assets/skins/sam/menuitem_submenuindicator_disabled.png' => '42a8a785ecb430826ebd4748fc77ebc0', + './include/javascript/yui/build/menu/assets/skins/sam/menuitem_submenuindicator.png' => '10f0de223bc3688a8986c23f71f081f1', + './include/javascript/yui/build/menu/assets/skins/sam/menuitem_checkbox_disabled.png' => '6d9c1ef2cc0823c45226e43f9ef0e3dd', + './include/javascript/yui/build/menu/assets/skins/sam/menuitem_checkbox.png' => '01d544275d0ee95fae025242d1eab1d5', + './include/javascript/yui/build/menu/assets/skins/sam/menubaritem_submenuindicator_disabled.png' => 'd8c20340be4484d2153ecd1a8b21f57f', + './include/javascript/yui/build/menu/assets/skins/sam/menubaritem_submenuindicator.png' => '1424f886ef59424f1aa19fa94771fb3f', + './include/javascript/yui/build/menu/assets/skins/sam/menu.css' => '6ed5f2e057f115daa8bb71bfd0c643ce', + './include/javascript/yui/build/menu/assets/skins/sam/menu-skin.css' => '21ae432798614782779386aa734ff2f3', + './include/javascript/yui/build/menu/assets/menuitem_submenuindicator_selected.png' => '13fbc56317c32fb2373241d25e46ad87', + './include/javascript/yui/build/menu/assets/menuitem_submenuindicator_disabled.png' => '52394cd1c23abd1dab175b16b286497b', + './include/javascript/yui/build/menu/assets/menuitem_submenuindicator.png' => '4a40c951dbf145003d19187e8b9944d0', + './include/javascript/yui/build/menu/assets/menuitem_checkbox_selected.png' => '8f8cbed03723933c7dcaf670cd0090a7', + './include/javascript/yui/build/menu/assets/menuitem_checkbox_disabled.png' => 'f49b45a246054c901510263300f4d273', + './include/javascript/yui/build/menu/assets/menuitem_checkbox.png' => '04046d854aa5030f00e639b036b10e0f', + './include/javascript/yui/build/menu/assets/menubaritem_submenuindicator_selected.png' => '5afb62ba90af5ca8b0fb6a149206b09d', + './include/javascript/yui/build/menu/assets/menubaritem_submenuindicator_disabled.png' => '4e06a53613fe60385001f776a5f5b5f4', + './include/javascript/yui/build/menu/assets/menubaritem_submenuindicator.png' => '6a52342f4112f75ec3a670bca249be1f', + './include/javascript/yui/build/menu/assets/menu_up_arrow_disabled.png' => '139ba64f9b14bd36c9c35a6cb0f71848', + './include/javascript/yui/build/menu/assets/menu_up_arrow.png' => 'dc52888b3dcb56f0860d78175bf4dd4f', + './include/javascript/yui/build/menu/assets/menu_down_arrow_disabled.png' => '22ac9a93738dffb391180047c187a182', + './include/javascript/yui/build/menu/assets/menu_down_arrow.png' => 'c61639e305e930102297f479ef1f84c7', + './include/javascript/yui/build/menu/assets/menu.css' => '64a6367a10897df76ffc68f817be4b2f', + './include/javascript/yui/build/menu/assets/menu-core.css' => 'a42bb56e4386a4d0c696d8b8622a2b43', + './include/javascript/yui/build/logger/logger.js' => '19e92542b867cda010214412d85f4102', + './include/javascript/yui/build/logger/logger-min.js' => '6179587106331f50b94963768b59a9af', + './include/javascript/yui/build/logger/assets/skins/sam/logger.css' => '34c9d2d0dc2dfecd76703d3ac210088a', + './include/javascript/yui/build/logger/assets/skins/sam/logger-skin.css' => '0f5a4c1fbca60b78976a41591cabd31e', + './include/javascript/yui/build/logger/assets/logger.css' => '94a94bbe5199376f2df542be57a2820c', + './include/javascript/yui/build/logger/assets/logger-core.css' => '02f2ac7e6bf5753422fbddab521c7d19', + './include/javascript/yui/build/layout/layout.js' => 'fe1bd86243ec2910f0cf2b9a3866132a', + './include/javascript/yui/build/layout/layout-min.js' => '788b7a42e45df3c4c385e559bd4e6d99', + './include/javascript/yui/build/layout/assets/skins/sam/layout_sprite.png' => '0f5a66998a0b88cabfe0489a6a11e28a', + './include/javascript/yui/build/layout/assets/skins/sam/layout.css' => '795b3d611aa7b6a06687f6b400b7e5fe', + './include/javascript/yui/build/layout/assets/skins/sam/layout-skin.css' => 'a329332ae9d0f5f7b57298e95e7b3aaf', + './include/javascript/yui/build/layout/assets/layout-core.css' => '20d7cb32c0585bbdf2ecc47927a91335', + './include/javascript/yui/build/json/json.js' => 'a31d483a89e83e72cbb3c42d2f5fdd4e', + './include/javascript/yui/build/json/json-min.js' => '595bc1f3b948cbcb9a7d5b934dbdb107', + './include/javascript/yui/build/imageloader/imageloader.js' => 'e6eecb6483d125156c77c4cee74412a1', + './include/javascript/yui/build/imageloader/imageloader-min.js' => '41f7ad72e42fb68f20e951d305c12347', + './include/javascript/yui/build/imagecropper/imagecropper.js' => '82022d024606947e9d12976b657e4783', + './include/javascript/yui/build/imagecropper/imagecropper-min.js' => '8a39f3974407001667353cecfcf3b660', + './include/javascript/yui/build/imagecropper/assets/skins/sam/imagecropper.css' => '14b933dace6b55ff4bd29dfa532049e9', + './include/javascript/yui/build/imagecropper/assets/skins/sam/imagecropper-skin.css' => '9b492c16276e1d6e41057538cfa2276a', + './include/javascript/yui/build/imagecropper/assets/imagecropper-core.css' => 'f7fc7105b9b60f4f66954eb22fe1461e', + './include/javascript/yui/build/history/history.js' => '594d929e9baf0354bdf6c9207ee5d88e', + './include/javascript/yui/build/history/history-min.js' => '6dc74b45c3844bec37992f8b56c911b3', + './include/javascript/yui/build/history/assets/blank.html' => '09773fd08c1f040b898ee77b06a2bf59', + './include/javascript/yui/build/grids/grids.css' => '878da0a5fa669f9f9f1b59409358340b', + './include/javascript/yui/build/grids/grids-min.css' => '8939896c332468eceefba2a9fda6e037', + './include/javascript/yui/build/get/get.js' => 'd653c2732adee0eedf7cd78a1ee2e5c5', + './include/javascript/yui/build/get/get-min.js' => '1c0629c2127a03dfd7e3ba0429efbe78', + './include/javascript/yui/build/fonts/fonts.css' => '7b0bb1861e071b874d5716b73936a6e7', + './include/javascript/yui/build/fonts/fonts-min.css' => 'd05af6e8046cc0253b910915db60d914', + './include/javascript/yui/build/event/event.js' => '81f1e87eef011560419df89386589fe8', + './include/javascript/yui/build/event/event-min.js' => 'f88a53dea300de8b15a062b0bfd18d7c', + './include/javascript/yui/build/event-simulate/event-simulate.js' => 'efb152b50f9c402d144262307a8f1b4d', + './include/javascript/yui/build/event-simulate/event-simulate-min.js' => '20714ece167eec20224e4b7113d83d19', + './include/javascript/yui/build/event-simulate/event-simulate-debug.js' => 'efb152b50f9c402d144262307a8f1b4d', + './include/javascript/yui/build/event-mouseenter/event-mouseenter.js' => 'e6fd23465f95c297f0ec01779f33903d', + './include/javascript/yui/build/event-mouseenter/event-mouseenter-min.js' => 'a6785052ee0782fec75d1ceeec60b837', + './include/javascript/yui/build/event-mouseenter/event-mouseenter-debug.js' => 'e6fd23465f95c297f0ec01779f33903d', + './include/javascript/yui/build/event-delegate/event-delegate.js' => 'eef0bf026f2a9646e0696f7cc8f1d442', + './include/javascript/yui/build/event-delegate/event-delegate-min.js' => '9ee8bb35a45bc8b7aee4508a1c89fdac', + './include/javascript/yui/build/event-delegate/event-delegate-debug.js' => '2fa529a1c98f5fa12e69cdd317bc525e', + './include/javascript/yui/build/element/element.js' => '0516e4cd68b5f4206ecaa2c7389ca32a', + './include/javascript/yui/build/element/element-min.js' => '7bbdd2ed1c177b4ce569a2e6ebf3cbec', + './include/javascript/yui/build/element-delegate/element-delegate.js' => '3c91b3c19d07c72ceb96ab21c0b07694', + './include/javascript/yui/build/element-delegate/element-delegate-min.js' => '9a4bc305125538fcb01f1fc7ee9b3007', + './include/javascript/yui/build/element-delegate/element-delegate-debug.js' => '2e65e0cbbb2aff875c31da05623195ea', + './include/javascript/yui/build/editor/simpleeditor.js' => '17876a6c67ac89b184a7f10b72e23e17', + './include/javascript/yui/build/editor/simpleeditor-min.js' => '7af8a4b28a5e3b011b3c00c5623e5130', + './include/javascript/yui/build/editor/editor.js' => 'd44b945458f40c48424ed286c4bee3be', + './include/javascript/yui/build/editor/editor-min.js' => '8e882e7b303dfc66d558751ace1e20fe', + './include/javascript/yui/build/editor/assets/skins/sam/simpleeditor.css' => 'b3ed43c0ca0bbd76103ecf20bb7ec7c4', + './include/javascript/yui/build/editor/assets/skins/sam/simpleeditor-skin.css' => '1db14802c579aa8624bc1d5e223a8630', + './include/javascript/yui/build/editor/assets/skins/sam/editor.css' => 'b3ed43c0ca0bbd76103ecf20bb7ec7c4', + './include/javascript/yui/build/editor/assets/skins/sam/editor-sprite.gif' => 'b72bb0d8d92b3a946cb6be25d2c885fa', + './include/javascript/yui/build/editor/assets/skins/sam/editor-sprite-active.gif' => 'e7a74b72201d29021d6d04d85f86f0c9', + './include/javascript/yui/build/editor/assets/skins/sam/editor-skin.css' => '1db14802c579aa8624bc1d5e223a8630', + './include/javascript/yui/build/editor/assets/skins/sam/editor-knob.gif' => '43c236afae83c3032ca8da61d3a021b6', + './include/javascript/yui/build/editor/assets/skins/sam/blankimage.png' => '91c1defa5830c414bd5d43fb63d30101', + './include/javascript/yui/build/editor/assets/simpleeditor-core.css' => 'a2db28ddf0c13e2af9d03208aca9a3e2', + './include/javascript/yui/build/editor/assets/editor-core.css' => 'a2db28ddf0c13e2af9d03208aca9a3e2', + './include/javascript/yui/build/dragdrop/dragdrop.js' => 'f9773ee345b034e09b8fefda2eb7bac5', + './include/javascript/yui/build/dragdrop/dragdrop-min.js' => '0ae226bcb211ae563e67ff3cd97c4548', + './include/javascript/yui/build/dom/dom.js' => '69d95eb94e21d1a11da374bd1026b14c', + './include/javascript/yui/build/dom/dom-min.js' => 'aa706bc9d70ae282bae9f9ea9a1f60d0', + './include/javascript/yui/build/datemath/datemath.js' => 'd4ca29daf116014dba21a7d44e2c7814', + './include/javascript/yui/build/datemath/datemath-min.js' => 'e432af5fe30c1ddd7aa0fe84f02a995d', + './include/javascript/yui/build/datemath/datemath-debug.js' => 'd4ca29daf116014dba21a7d44e2c7814', + './include/javascript/yui/build/datatable/datatable.js' => '26bcff411750ea512e59a3d9400c3b86', + './include/javascript/yui/build/datatable/datatable-min.js' => '4fc2bf26c727937a77e0183bffcdac4a', + './include/javascript/yui/build/datatable/assets/skins/sam/dt-arrow-up.png' => '27498450164be1b258cae9dfdd534b69', + './include/javascript/yui/build/datatable/assets/skins/sam/dt-arrow-dn.png' => 'ee0dd66007d4f34b5e6660b4abbb5a65', + './include/javascript/yui/build/datatable/assets/skins/sam/datatable.css' => 'e04ce2e139377129b079205ceba06aaf', + './include/javascript/yui/build/datatable/assets/skins/sam/datatable-skin.css' => '559062062b6bc27a055ba2a18f8b1b7f', + './include/javascript/yui/build/datatable/assets/datatable.css' => '51d6b383f8719cfc553db8bfc474f03e', + './include/javascript/yui/build/datatable/assets/datatable-core.css' => 'e752ddeddca76df907de990f85416eda', + './include/javascript/yui/build/datasource/datasource.js' => '354713e9ed0a1d2760cd15ea48675837', + './include/javascript/yui/build/datasource/datasource-min.js' => '3f8c54286dc2c062186d92333bb0533f', + './include/javascript/yui/build/cookie/cookie.js' => '8c27ac9e9c9e6d113ac2d743875d8c25', + './include/javascript/yui/build/cookie/cookie-min.js' => 'd1fc139547c85105a0e55f04878deffd', + './include/javascript/yui/build/container/container_core-min.js' => 'ddde4174c11b3c7a41bb650190bcf951', + './include/javascript/yui/build/container/container.js' => '46d95c9cb3d54a3edb859c7542fac680', + './include/javascript/yui/build/container/container-min.js' => 'cac1924c31ce2ac5ec14a0a95583696f', + './include/javascript/yui/build/container/assets/warn16_1.gif' => 'ba0ca370e1f04a406b8188d3ab892b7b', + './include/javascript/yui/build/container/assets/tip16_1.gif' => '0b540d1e06e818d180ca0534be963159', + './include/javascript/yui/build/container/assets/skins/sam/container.css' => '8cdcbf8555a601d011c96a9053c40c88', + './include/javascript/yui/build/container/assets/skins/sam/container-skin.css' => '116e9cc3499f508b04f79c1794802fc2', + './include/javascript/yui/build/container/assets/info16_1.gif' => '38d37e309cca60bfac2ad2881f7fe58e', + './include/javascript/yui/build/container/assets/hlp16_1.gif' => 'b593fbd4d06a98522efa285e1709aa36', + './include/javascript/yui/build/container/assets/container.css' => '30d926224d525d460a79e393b2eac872', + './include/javascript/yui/build/container/assets/container-core.css' => '0b777a30b4f40eafe30a76399f151afa', + './include/javascript/yui/build/container/assets/close12_1.gif' => '770d9c592b4300457ae025448c4c6816', + './include/javascript/yui/build/container/assets/blck16_1.gif' => 'b9aeaed783a1c845f699daf2c6ee563a', + './include/javascript/yui/build/container/assets/alrt16_1.gif' => '7764b275c2e10a40bff0061f94e9b8e9', + './include/javascript/yui/build/connection/connection_core.js' => '4be1743c83638c7cc479799f4fb7ddb1', + './include/javascript/yui/build/connection/connection_core-min.js' => '4b494585224308f921d115f17e21b426', + './include/javascript/yui/build/connection/connection_core-debug.js' => '2b5180cc72b9050d21a658a8bf38833c', + './include/javascript/yui/build/connection/connection.swf' => 'b4f652fc6f38593551ab5298b1077901', + './include/javascript/yui/build/connection/connection.js' => '1f5039e1aad61c3db45dc48097188b96', + './include/javascript/yui/build/connection/connection-min.js' => '6ae7d4c034ce5f44c66fc116a3504511', + './include/javascript/yui/build/colorpicker/colorpicker.js' => 'b32bc4124e866857485f3d9b074b93b2', + './include/javascript/yui/build/colorpicker/colorpicker-min.js' => '36de5bb3a2e4a172bc26d7125bfce5f0', + './include/javascript/yui/build/colorpicker/assets/skins/sam/picker_mask.png' => 'a4d3b14fbcc5b8f112d3635f981d6a1c', + './include/javascript/yui/build/colorpicker/assets/skins/sam/hue_bg.png' => '73ae3465d3dcbd95ebb4165760fac8e8', + './include/javascript/yui/build/colorpicker/assets/skins/sam/colorpicker.css' => '21eaa2969dd55fe80afc1928fd37e7b5', + './include/javascript/yui/build/colorpicker/assets/skins/sam/colorpicker-skin.css' => '18cc2d8bac896cc6e95a222ee217c4eb', + './include/javascript/yui/build/colorpicker/assets/picker_thumb.png' => '96aa37e578d0428346e4c7170ac9a230', + './include/javascript/yui/build/colorpicker/assets/picker_mask.png' => 'a4d3b14fbcc5b8f112d3635f981d6a1c', + './include/javascript/yui/build/colorpicker/assets/hue_thumb.png' => 'b1a887427b558af46f17262784da3583', + './include/javascript/yui/build/colorpicker/assets/colorpicker-core.css' => '9f1c2687bab335e4a0f822734461bf66', + './include/javascript/yui/build/charts/charts.js' => '09127fabb0fcfc57ce3d15ff2d569533', + './include/javascript/yui/build/charts/charts-min.js' => '392da34fb5198a77e25a3442e4b42a03', + './include/javascript/yui/build/charts/assets/charts.swf' => '59c6e2c9ae7de87f11dd3db3336de8b6', + './include/javascript/yui/build/carousel/carousel.js' => '604b54e0dd9cde8344e2828d51cb331f', + './include/javascript/yui/build/carousel/carousel-min.js' => 'da0d2e1b6b141c02c83328b61ccd23df', + './include/javascript/yui/build/carousel/assets/skins/sam/carousel.css' => '0d1ed494db742ffbfd471f41eaee1840', + './include/javascript/yui/build/carousel/assets/skins/sam/carousel-skin.css' => '06ad5ed644ae41fd61603890a29cf3a1', + './include/javascript/yui/build/carousel/assets/skins/sam/ajax-loader.gif' => '734023ef4fd81fb5638c9d5c3d6a8fdf', + './include/javascript/yui/build/carousel/assets/carousel-core.css' => '32accad6ca1819bf19da7c546b8aae88', + './include/javascript/yui/build/carousel/assets/ajax-loader.gif' => '734023ef4fd81fb5638c9d5c3d6a8fdf', + './include/javascript/yui/build/calendar/calendar.js' => '3fa723bf49850ee19651ccac34d0ac2e', + './include/javascript/yui/build/calendar/calendar-min.js' => '852c2c3bc8c283b712d99c6c24e510ed', + './include/javascript/yui/build/calendar/assets/skins/sam/calendar.css' => 'ad3ccb220f106da477a25f9a637f5053', + './include/javascript/yui/build/calendar/assets/skins/sam/calendar-skin.css' => '215ba5a2c5a1dbd219db05a58f13b60c', + './include/javascript/yui/build/calendar/assets/calx.gif' => 'acc1427b926515c1ec846e04e3b635cd', + './include/javascript/yui/build/calendar/assets/calrt.gif' => 'ba0b2098813b15aa3cc655e881c92d0a', + './include/javascript/yui/build/calendar/assets/callt.gif' => '0718c393fbd4095b219803cb6b7bcbf8', + './include/javascript/yui/build/calendar/assets/calgrad.png' => 'd028abaadeebb310606448cfc7ba2bfe', + './include/javascript/yui/build/calendar/assets/calendar.css' => 'cdee21e708db89a3f21611de213b4d9f', + './include/javascript/yui/build/calendar/assets/calendar-core.css' => 'be61597ae2a5d6745f4295f4e281a211', + './include/javascript/yui/build/button/button.js' => '5513a50284659e706665a98f9b23835e', + './include/javascript/yui/build/button/button-min.js' => '3442458b76b17709d00135e8e9c8ddc1', + './include/javascript/yui/build/button/assets/skins/sam/split-button-arrow.png' => 'ced974d5c685e5dfa0a37b824a6b5d48', + './include/javascript/yui/build/button/assets/skins/sam/split-button-arrow-hover.png' => '36e66540d2feba76b8991e18b76fe93b', + './include/javascript/yui/build/button/assets/skins/sam/split-button-arrow-focus.png' => '36e66540d2feba76b8991e18b76fe93b', + './include/javascript/yui/build/button/assets/skins/sam/split-button-arrow-disabled.png' => 'db73dce6da2f5c5f02399c93488ce69e', + './include/javascript/yui/build/button/assets/skins/sam/split-button-arrow-active.png' => '890272b241c1d8a0db3ce5680b71fab0', + './include/javascript/yui/build/button/assets/skins/sam/menu-button-arrow.png' => '6305efb37fa05af65c79b58b9d4c1b03', + './include/javascript/yui/build/button/assets/skins/sam/menu-button-arrow-disabled.png' => '4df7235ca027f2546b2a216e59f81fb0', + './include/javascript/yui/build/button/assets/skins/sam/button.css' => '8dd40560e2b5695c02d91e59f2e787c9', + './include/javascript/yui/build/button/assets/skins/sam/button-skin.css' => 'a3c353c70c804be0a38d441251be4c8a', + './include/javascript/yui/build/button/assets/button-core.css' => 'ef05faed4ff9d4dd92815da7a8485718', + './include/javascript/yui/build/base/base.css' => 'f8e14c2b50188a4bd7553863579cd965', + './include/javascript/yui/build/base/base-min.css' => '2ba459363a0b19b112ad16be03da005f', + './include/javascript/yui/build/autocomplete/autocomplete.js' => '82e7b838b2a4ac953d218d4369fdcc2e', + './include/javascript/yui/build/autocomplete/autocomplete-min.js' => 'd87853c9b79ab88bff32909fa686e76c', + './include/javascript/yui/build/autocomplete/assets/skins/sam/autocomplete.css' => 'df782e1c9722d460b294cf30d536143c', + './include/javascript/yui/build/autocomplete/assets/skins/sam/autocomplete-skin.css' => 'd11e8caba6ebc10943fa7d5b0c592406', + './include/javascript/yui/build/autocomplete/assets/autocomplete-core.css' => '02f2ac7e6bf5753422fbddab521c7d19', + './include/javascript/yui/build/assets/skins/sam/yuitest.css' => '793339721d8f8dea54c60348fe4a853e', + './include/javascript/yui/build/assets/skins/sam/wait.gif' => 'b0cd5a5dc070c705ebf8814a909802c3', + './include/javascript/yui/build/assets/skins/sam/treeview.css' => 'cf472192f2e3c5e89098f9d83732c746', + './include/javascript/yui/build/assets/skins/sam/treeview-sprite.gif' => '115a1070e1398629700a11d4f5d546bb', + './include/javascript/yui/build/assets/skins/sam/treeview-loading.gif' => '8f1310bf9e7aa892d2dc09c4058c7bd3', + './include/javascript/yui/build/assets/skins/sam/tabview.css' => 'a87041d15dbd06a27f7d8b94100bafae', + './include/javascript/yui/build/assets/skins/sam/sprite.psd' => '1c35d9ed1d8f86b406b376c66e41ef01', + './include/javascript/yui/build/assets/skins/sam/sprite.png' => '96b257a32a932f7739d7dab52b38ee8f', + './include/javascript/yui/build/assets/skins/sam/split-button-arrow.png' => 'ced974d5c685e5dfa0a37b824a6b5d48', + './include/javascript/yui/build/assets/skins/sam/split-button-arrow-hover.png' => '36e66540d2feba76b8991e18b76fe93b', + './include/javascript/yui/build/assets/skins/sam/split-button-arrow-focus.png' => '36e66540d2feba76b8991e18b76fe93b', + './include/javascript/yui/build/assets/skins/sam/split-button-arrow-disabled.png' => 'db73dce6da2f5c5f02399c93488ce69e', + './include/javascript/yui/build/assets/skins/sam/split-button-arrow-active.png' => '890272b241c1d8a0db3ce5680b71fab0', + './include/javascript/yui/build/assets/skins/sam/slider.css' => '71f7bccc93416362d854d66c50383d3d', + './include/javascript/yui/build/assets/skins/sam/skin.css' => '3767651bc262bb1f86042a3f47213e95', + './include/javascript/yui/build/assets/skins/sam/simpleeditor.css' => '1ccd68dda0b071fa28dc70b2f154cb4c', + './include/javascript/yui/build/assets/skins/sam/resize.css' => '9c978b19e16ad208645904c9323d5a31', + './include/javascript/yui/build/assets/skins/sam/progressbar.css' => 'f39fc4327836dbf61b7e433f6246e0ab', + './include/javascript/yui/build/assets/skins/sam/profilerviewer.css' => 'e07d72c12fc6c0028b89d88da7ec53d2', + './include/javascript/yui/build/assets/skins/sam/picker_mask.png' => 'a4d3b14fbcc5b8f112d3635f981d6a1c', + './include/javascript/yui/build/assets/skins/sam/paginator.css' => '2bb7f5bf775e4770dd2b6f9e36611b92', + './include/javascript/yui/build/assets/skins/sam/menuitem_submenuindicator_disabled.png' => '42a8a785ecb430826ebd4748fc77ebc0', + './include/javascript/yui/build/assets/skins/sam/menuitem_submenuindicator.png' => '10f0de223bc3688a8986c23f71f081f1', + './include/javascript/yui/build/assets/skins/sam/menuitem_checkbox_disabled.png' => '6d9c1ef2cc0823c45226e43f9ef0e3dd', + './include/javascript/yui/build/assets/skins/sam/menuitem_checkbox.png' => '01d544275d0ee95fae025242d1eab1d5', + './include/javascript/yui/build/assets/skins/sam/menubaritem_submenuindicator_disabled.png' => 'd8c20340be4484d2153ecd1a8b21f57f', + './include/javascript/yui/build/assets/skins/sam/menubaritem_submenuindicator.png' => '1424f886ef59424f1aa19fa94771fb3f', + './include/javascript/yui/build/assets/skins/sam/menu.css' => '6f10107d3d986fdad286d5f6d5e5002f', + './include/javascript/yui/build/assets/skins/sam/menu-button-arrow.png' => '6305efb37fa05af65c79b58b9d4c1b03', + './include/javascript/yui/build/assets/skins/sam/menu-button-arrow-disabled.png' => '4df7235ca027f2546b2a216e59f81fb0', + './include/javascript/yui/build/assets/skins/sam/logger.css' => '34c9d2d0dc2dfecd76703d3ac210088a', + './include/javascript/yui/build/assets/skins/sam/loading.gif' => '8f1310bf9e7aa892d2dc09c4058c7bd3', + './include/javascript/yui/build/assets/skins/sam/layout_sprite.png' => '0f5a66998a0b88cabfe0489a6a11e28a', + './include/javascript/yui/build/assets/skins/sam/layout.css' => '65d50fedbdcb941e774d8ed0bfdce3c7', + './include/javascript/yui/build/assets/skins/sam/imagecropper.css' => '14b933dace6b55ff4bd29dfa532049e9', + './include/javascript/yui/build/assets/skins/sam/hue_bg.png' => '73ae3465d3dcbd95ebb4165760fac8e8', + './include/javascript/yui/build/assets/skins/sam/header_background.png' => '412285f6b44f1d7757fc005680c2ecf5', + './include/javascript/yui/build/assets/skins/sam/editor.css' => '1ccd68dda0b071fa28dc70b2f154cb4c', + './include/javascript/yui/build/assets/skins/sam/editor-sprite.gif' => 'b72bb0d8d92b3a946cb6be25d2c885fa', + './include/javascript/yui/build/assets/skins/sam/editor-sprite-active.gif' => 'e7a74b72201d29021d6d04d85f86f0c9', + './include/javascript/yui/build/assets/skins/sam/editor-knob.gif' => '43c236afae83c3032ca8da61d3a021b6', + './include/javascript/yui/build/assets/skins/sam/dt-arrow-up.png' => '27498450164be1b258cae9dfdd534b69', + './include/javascript/yui/build/assets/skins/sam/dt-arrow-dn.png' => 'ee0dd66007d4f34b5e6660b4abbb5a65', + './include/javascript/yui/build/assets/skins/sam/desc.gif' => '4708d3f08d550225360a43cd8ca2fab4', + './include/javascript/yui/build/assets/skins/sam/datatable.css' => 'd2398264754747241f8eebdcd18d69d2', + './include/javascript/yui/build/assets/skins/sam/container.css' => 'e436622acdb4bc6986de749c426f1c04', + './include/javascript/yui/build/assets/skins/sam/colorpicker.css' => '21eaa2969dd55fe80afc1928fd37e7b5', + './include/javascript/yui/build/assets/skins/sam/check2.gif' => '3544088604d6d6e519a3a392db89c38d', + './include/javascript/yui/build/assets/skins/sam/check1.gif' => '691389bb26f429e79666599992a384b3', + './include/javascript/yui/build/assets/skins/sam/check0.gif' => 'd3e7d474e008b8cb585eb05c5baafe5a', + './include/javascript/yui/build/assets/skins/sam/carousel.css' => '71339651dc17bd504e1865b38de5acff', + './include/javascript/yui/build/assets/skins/sam/calendar.css' => '98bc5824a4a03d18bba4b8f145092b79', + './include/javascript/yui/build/assets/skins/sam/button.css' => '44e8590c6db616e71956614da45a13a3', + './include/javascript/yui/build/assets/skins/sam/blankimage.png' => '91c1defa5830c414bd5d43fb63d30101', + './include/javascript/yui/build/assets/skins/sam/bg-v.gif' => '220b443b77004914d4293a655299e2ce', + './include/javascript/yui/build/assets/skins/sam/bg-h.gif' => '4d4b3a56c225f8f21f7d839ba2b03823', + './include/javascript/yui/build/assets/skins/sam/bar-v.png' => '54cd63ec61c91525f081428bc784021c', + './include/javascript/yui/build/assets/skins/sam/bar-h.png' => 'a4182c879e01c66bfaf9c188202c326b', + './include/javascript/yui/build/assets/skins/sam/back-v.png' => 'f0179d9bbb6e6f7796caed9d1b0b9795', + './include/javascript/yui/build/assets/skins/sam/back-h.png' => '972e692bc2c40a33fa30f3333c5e5821', + './include/javascript/yui/build/assets/skins/sam/autocomplete.css' => 'df782e1c9722d460b294cf30d536143c', + './include/javascript/yui/build/assets/skins/sam/asc.gif' => '7053becd07a62f576bb8767a5d9875f0', + './include/javascript/yui/build/assets/skins/sam/ajax-loader.gif' => '734023ef4fd81fb5638c9d5c3d6a8fdf', + './include/javascript/yui/build/animation/animation.js' => '1dd52b9ff5b763668113153d3c26c3df', + './include/javascript/yui/build/animation/animation-min.js' => '87ab37459d9aed17838e38af78fee22d', + './include/javascript/yui/README' => '4dc7cd50545b8e539199a9d582f711ed', + './include/javascript/yui/LICENSE.txt' => '8836083506dadbf2735da1d444429ede', + './include/javascript/tiny_mce/utils/validate.js' => 'fe7d3b49f9c3587e40a9e29cd1ad9550', + './include/javascript/tiny_mce/utils/mctabs.js' => '0d310e7ec0cc85e584ef4bc456735b35', + './include/javascript/tiny_mce/utils/form_utils.js' => '7f898490f1e26b91192ebde3791b7e28', + './include/javascript/tiny_mce/utils/editable_selects.js' => 'a67bc4b79368958a0b8e8bd6e9c0d751', + './include/javascript/tiny_mce/tiny_mce_src.js' => '484235a72704170be94e2a5ba59e2285', + './include/javascript/tiny_mce/tiny_mce_popup.js' => 'c51f86c7aad0344e8c6b15e5edb67106', + './include/javascript/tiny_mce/tiny_mce.js' => '2ed1dddf27f0dc995e2c369c4b6fcc77', + './include/javascript/tiny_mce/themes/simple/skins/o2k7/ui.css' => '6649913256b2a0e48a1337d1c73d31d1', + './include/javascript/tiny_mce/themes/simple/skins/o2k7/img/button_bg.png' => '405ca3d63b48667ef485553192507f59', + './include/javascript/tiny_mce/themes/simple/skins/o2k7/content.css' => 'db914acf7c5b603d641bca3ef9141a7e', + './include/javascript/tiny_mce/themes/simple/skins/default/ui.css' => '8f5fb8a371d03eb652b1d14e4b879c24', + './include/javascript/tiny_mce/themes/simple/skins/default/content.css' => '3b5ee10accbe8f436bd551b7bb7067b0', + './include/javascript/tiny_mce/themes/simple/langs/en.js' => '38c39321c50f9c8e58b757618399043a', + './include/javascript/tiny_mce/themes/simple/img/icons.gif' => '749151955998f915596270f8c452af6e', + './include/javascript/tiny_mce/themes/simple/editor_template_src.js' => 'f4b951c7a3b88dcb16718661362baf73', + './include/javascript/tiny_mce/themes/simple/editor_template.js' => '45f4d2bf0007e3f8fef1e8bdccff214c', + './include/javascript/tiny_mce/themes/advanced/source_editor.htm' => 'ad4599870c78219ce16abd5dc75159dc', + './include/javascript/tiny_mce/themes/advanced/skins/o2k7/ui_silver.css' => '623a420867f1da38168b5ab0eac1afcc', + './include/javascript/tiny_mce/themes/advanced/skins/o2k7/ui_black.css' => 'dd03578fd4e33798de6d86c4564e4c66', + './include/javascript/tiny_mce/themes/advanced/skins/o2k7/ui.css' => 'b9db394d414b1d2f0d8930522e676c5d', + './include/javascript/tiny_mce/themes/advanced/skins/o2k7/img/button_bg_silver.png' => '5690ef573f4dc74ec3eb4d101806976e', + './include/javascript/tiny_mce/themes/advanced/skins/o2k7/img/button_bg_black.png' => 'a5ad448e9c25120cb7e05fffe4a6234f', + './include/javascript/tiny_mce/themes/advanced/skins/o2k7/img/button_bg.png' => '8c9b1f0ee9deb6374983650edbd6ddfc', + './include/javascript/tiny_mce/themes/advanced/skins/o2k7/dialog.css' => '32d8369bcd5f49067b6c0905b2bb6971', + './include/javascript/tiny_mce/themes/advanced/skins/o2k7/content.css' => '4a0a94603795b7bfc41ff76ea8889db7', + './include/javascript/tiny_mce/themes/advanced/skins/default/ui.css' => '95f5bbc6ea992fcb641f0275025dc438', + './include/javascript/tiny_mce/themes/advanced/skins/default/img/tabs.gif' => '93f97588a35da1f45fdcb975d4380913', + './include/javascript/tiny_mce/themes/advanced/skins/default/img/progress.gif' => '50c5e3e79b276c92df6cc52caeb464f0', + './include/javascript/tiny_mce/themes/advanced/skins/default/img/menu_check.gif' => 'c7d003885737f94768eecae49dcbca63', + './include/javascript/tiny_mce/themes/advanced/skins/default/img/menu_arrow.gif' => 'e21752451a9d80e276fef7b602bdbdba', + './include/javascript/tiny_mce/themes/advanced/skins/default/img/items.gif' => '5cb42865ce70a58d420786854fed4ae1', + './include/javascript/tiny_mce/themes/advanced/skins/default/img/buttons.png' => '1e0acdc2135897e6a95bb40cfde2fbc6', + './include/javascript/tiny_mce/themes/advanced/skins/default/dialog.css' => '2c50db59d058317010775677fee63ac3', + './include/javascript/tiny_mce/themes/advanced/skins/default/content.css' => '2f921f2c07fa24953530b23bf2000e0a', + './include/javascript/tiny_mce/themes/advanced/link.htm' => '2951c33235fe77a9b2d20b50ade5bdfd', + './include/javascript/tiny_mce/themes/advanced/langs/en_dlg.js' => '9a83ef13d214953214b354ca5b657867', + './include/javascript/tiny_mce/themes/advanced/langs/en.js' => '6cfaa5303f0e96e2fbe1ff210ba1f65b', + './include/javascript/tiny_mce/themes/advanced/js/source_editor.js' => '4b3abeb1908bef7872238e184a5a40d9', + './include/javascript/tiny_mce/themes/advanced/js/link.js' => 'e4eaaa5fcee50264e9b24370cc802b76', + './include/javascript/tiny_mce/themes/advanced/js/image.js' => 'fd66296c6168ac8b5bd72cf2b027c3d4', + './include/javascript/tiny_mce/themes/advanced/js/color_picker.js' => '2ce934aa3086cba10c51c6d055177f8f', + './include/javascript/tiny_mce/themes/advanced/js/charmap.js' => '27f30d99721bd0ff665a443c49a22702', + './include/javascript/tiny_mce/themes/advanced/js/anchor.js' => '8988b8d83a5d753ddcb3600b976780fd', + './include/javascript/tiny_mce/themes/advanced/js/about.js' => 'cd4f25e57d9c7c3c5eaed2b4234c8787', + './include/javascript/tiny_mce/themes/advanced/img/icons.gif' => 'e893a1f9e0c9c6240ba28756cf838f5f', + './include/javascript/tiny_mce/themes/advanced/img/colorpicker.jpg' => '02ae48639aa5729e6a40fb64455c32a2', + './include/javascript/tiny_mce/themes/advanced/image.htm' => '8008302022a40226c46f87fceac11f62', + './include/javascript/tiny_mce/themes/advanced/editor_template_src.js' => 'c6ca13b7383944ab9dca14b27f2a8240', + './include/javascript/tiny_mce/themes/advanced/editor_template.js' => 'ed03663b2f2feeca90dc23e6add11eef', + './include/javascript/tiny_mce/themes/advanced/color_picker.htm' => '01474b7f41da7d851c5a7f27aa2f2ff0', + './include/javascript/tiny_mce/themes/advanced/charmap.htm' => 'b3f3e37cff43d90e2fec656b52f1b67a', + './include/javascript/tiny_mce/themes/advanced/anchor.htm' => 'fece56d073731444af6747bf65fbb257', + './include/javascript/tiny_mce/themes/advanced/about.htm' => '2102cad8b48c2e05fa8ec2fd6be6c7e9', + './include/javascript/tiny_mce/plugins/xhtmlxtras/langs/en_dlg.js' => 'e845f30954520a5113ca623b017fb723', + './include/javascript/tiny_mce/plugins/xhtmlxtras/js/ins.js' => 'ced8412e867557ead95fb2146e73dab1', + './include/javascript/tiny_mce/plugins/xhtmlxtras/js/element_common.js' => 'f8e0a80427f8bac56c369cd8b43e12dd', + './include/javascript/tiny_mce/plugins/xhtmlxtras/js/del.js' => 'e2c424ec61e25750fabd5bb0c8de74d7', + './include/javascript/tiny_mce/plugins/xhtmlxtras/js/cite.js' => 'b493826c114ded7a7c950d42bedc6192', + './include/javascript/tiny_mce/plugins/xhtmlxtras/js/attributes.js' => '9a57a3801c04bb20eb79b47a6ac9a9d2', + './include/javascript/tiny_mce/plugins/xhtmlxtras/js/acronym.js' => 'aee35e665ca5cbe78baef305ba9dfd0a', + './include/javascript/tiny_mce/plugins/xhtmlxtras/js/abbr.js' => '76f004b5aea36c9471e7612f4560a286', + './include/javascript/tiny_mce/plugins/xhtmlxtras/ins.htm' => '513ab8c5155b01f641be6a7e5dbf06a3', + './include/javascript/tiny_mce/plugins/xhtmlxtras/editor_plugin_src.js' => '9cdc869de54673668f57743e32012133', + './include/javascript/tiny_mce/plugins/xhtmlxtras/editor_plugin.js' => '6c2389c55cc2d835a14d181554fe23fb', + './include/javascript/tiny_mce/plugins/xhtmlxtras/del.htm' => '90ca26878395f58b40a728c3f3613c8d', + './include/javascript/tiny_mce/plugins/xhtmlxtras/css/popup.css' => '80b339ec8c041f8adc5aecb03c7d6f99', + './include/javascript/tiny_mce/plugins/xhtmlxtras/css/attributes.css' => '289bd1e4958e04caf7fac5e4613732fd', + './include/javascript/tiny_mce/plugins/xhtmlxtras/cite.htm' => '8e546c512946df4e064cd93ae89154d9', + './include/javascript/tiny_mce/plugins/xhtmlxtras/attributes.htm' => '66f06ee6805756a2ede60121a9aac0b1', + './include/javascript/tiny_mce/plugins/xhtmlxtras/acronym.htm' => '90610e1e803e4a2c70283fe54ead82d7', + './include/javascript/tiny_mce/plugins/xhtmlxtras/abbr.htm' => '6902034abc4b6cef1bc1b0ef66407403', + './include/javascript/tiny_mce/plugins/visualchars/editor_plugin_src.js' => 'b6e6e4adbc2a55c1cdfdeae004aa4da1', + './include/javascript/tiny_mce/plugins/visualchars/editor_plugin.js' => '8fec0ef8561966c627ef5997a4b76ce6', + './include/javascript/tiny_mce/plugins/template/template.htm' => 'd69375f0253c27fbe1f600eb8b3f3890', + './include/javascript/tiny_mce/plugins/template/langs/en_dlg.js' => 'e672f0d31c3cf67114d1ad72bd1d1147', + './include/javascript/tiny_mce/plugins/template/js/template.js' => 'e65e4c8007b1528670790af8c48e07dc', + './include/javascript/tiny_mce/plugins/template/editor_plugin_src.js' => '9abd7e5d1f38a52bf1f15bb1baf43f6f', + './include/javascript/tiny_mce/plugins/template/editor_plugin.js' => '345d085ce78d9bb1e14ab6fe4f151e44', + './include/javascript/tiny_mce/plugins/template/css/template.css' => '6cc98d131d493071f2b14dac07f2cdbd', + './include/javascript/tiny_mce/plugins/template/blank.htm' => '9089127d1ef7411473edea629d4be1ce', + './include/javascript/tiny_mce/plugins/table/table.htm' => 'c655392d87b67af8331c7d2a8cdda4b5', + './include/javascript/tiny_mce/plugins/table/row.htm' => '3a44d6da2354b63f96ce6fc1ebb9ce25', + './include/javascript/tiny_mce/plugins/table/merge_cells.htm' => '031d824351b82c36fba89fadabb38951', + './include/javascript/tiny_mce/plugins/table/langs/en_dlg.js' => '15e65841dce0729b82812f84753fb529', + './include/javascript/tiny_mce/plugins/table/js/table.js' => '449a03ea6b9b5a738c294665fdd3a85e', + './include/javascript/tiny_mce/plugins/table/js/row.js' => '727574d09d5158bcccada83601bd4e46', + './include/javascript/tiny_mce/plugins/table/js/merge_cells.js' => 'a1c44cc854082e3d4f4824ff06cee170', + './include/javascript/tiny_mce/plugins/table/js/cell.js' => 'bad736ef8478a61a6e1b5316b4bd561e', + './include/javascript/tiny_mce/plugins/table/editor_plugin_src.js' => '72247df7a8c8b4ce6ad4797c0d5e3d30', + './include/javascript/tiny_mce/plugins/table/editor_plugin.js' => 'aa25f98e7fc772c84c3a5e822417c781', + './include/javascript/tiny_mce/plugins/table/css/table.css' => '541baebf7d11536dd4d31d6383e2d22d', + './include/javascript/tiny_mce/plugins/table/css/row.css' => 'fcb6c71f2226f482a0ac9e48494ca87b', + './include/javascript/tiny_mce/plugins/table/css/cell.css' => '4662497b8afb4b1c32eae399d37073e8', + './include/javascript/tiny_mce/plugins/table/cell.htm' => '31736b89077edd83afd52ffab4a8a83a', + './include/javascript/tiny_mce/plugins/style/props.htm' => 'd4e3d92f757881513ad4200472b1e87c', + './include/javascript/tiny_mce/plugins/style/langs/en_dlg.js' => '62b2b463ed9cf072aa8e7d09428287aa', + './include/javascript/tiny_mce/plugins/style/js/props.js' => '98186487c1acc6febb4fb0cb76bb9bfa', + './include/javascript/tiny_mce/plugins/style/editor_plugin_src.js' => '6a030e35ef8b6409ceb92c38556152db', + './include/javascript/tiny_mce/plugins/style/editor_plugin.js' => 'a33cf070cce70e0aaa4dd395366d9911', + './include/javascript/tiny_mce/plugins/style/css/props.css' => 'd1a2f4faed2da4947a309f32d912968a', + './include/javascript/tiny_mce/plugins/spellchecker/img/wline.gif' => 'c136c9f8e00718a98947a21d8adbcc56', + './include/javascript/tiny_mce/plugins/spellchecker/editor_plugin_src.js' => '849d4a2113fdecc2685fb896d65dcdca', + './include/javascript/tiny_mce/plugins/spellchecker/editor_plugin.js' => 'aed898ab6ffa523d8967696445630198', + './include/javascript/tiny_mce/plugins/spellchecker/css/content.css' => 'd236d4333281b4eae7a1e2b514b691f4', + './include/javascript/tiny_mce/plugins/searchreplace/searchreplace.htm' => 'ae3fd1271c4d96722acbe34a10e43dc2', + './include/javascript/tiny_mce/plugins/searchreplace/langs/en_dlg.js' => '8d4507bdc22c3d39fa0b1537172c8af3', + './include/javascript/tiny_mce/plugins/searchreplace/js/searchreplace.js' => '6fbb74616637579241653a12e3a9219f', + './include/javascript/tiny_mce/plugins/searchreplace/editor_plugin_src.js' => '5275f11680d34249afb562eb123c3957', + './include/javascript/tiny_mce/plugins/searchreplace/editor_plugin.js' => '3154c3cb319e9dd9c5994ae7125ad4f2', + './include/javascript/tiny_mce/plugins/searchreplace/css/searchreplace.css' => 'd4f8026713b4f1394d9977196a9de1bd', + './include/javascript/tiny_mce/plugins/save/editor_plugin_src.js' => 'd6f8bb16c56f49e1dfb5b711b10fc7df', + './include/javascript/tiny_mce/plugins/save/editor_plugin.js' => 'b9cc817b9e834924aca4af95b3d0c1bf', + './include/javascript/tiny_mce/plugins/safari/editor_plugin_src.js' => 'd203cbb96fd7eee16254a2997efd67c9', + './include/javascript/tiny_mce/plugins/safari/editor_plugin.js' => '9d7a37a26a6773ae236ed7a75f4617da', + './include/javascript/tiny_mce/plugins/safari/blank.htm' => 'c9a4909a579f24cd23fc0ae847e06241', + './include/javascript/tiny_mce/plugins/print/editor_plugin_src.js' => '2891244215e0e9229d0286308408f50b', + './include/javascript/tiny_mce/plugins/print/editor_plugin.js' => '6557fd2bd935aefa392ba71679edbebe', + './include/javascript/tiny_mce/plugins/preview/preview.html' => '1ee9766ccdeb6a63dc55ff3b6b53186a', + './include/javascript/tiny_mce/plugins/preview/jscripts/embed.js' => '5df3783492b848adde42124a1e9cf383', + './include/javascript/tiny_mce/plugins/preview/example.html' => 'f6ae5a579ef4ef3b8648329395e6d0de', + './include/javascript/tiny_mce/plugins/preview/editor_plugin_src.js' => '825fe1643314038a2c3a2c0518a2898d', + './include/javascript/tiny_mce/plugins/preview/editor_plugin.js' => '7bcbf12854d82cd45f7b4a9ec17f7391', + './include/javascript/tiny_mce/plugins/paste/pasteword.htm' => 'ce42817c01ddd922c3f1c5c9701c0036', + './include/javascript/tiny_mce/plugins/paste/pastetext.htm' => 'a83b2f9eb0861b1bd5db22e57da4280d', + './include/javascript/tiny_mce/plugins/paste/langs/en_dlg.js' => 'e5cf25d2ec374f911c7d009a19fa5474', + './include/javascript/tiny_mce/plugins/paste/js/pasteword.js' => '7f69babced989fb799e0f7a617441c71', + './include/javascript/tiny_mce/plugins/paste/js/pastetext.js' => '05482c276313c900e2a2b55508712b13', + './include/javascript/tiny_mce/plugins/paste/editor_plugin_src.js' => '7744bd032e98df4fe576a68418241008', + './include/javascript/tiny_mce/plugins/paste/editor_plugin.js' => '5b145b1c56b55c90b4aea900fce25880', + './include/javascript/tiny_mce/plugins/paste/css/pasteword.css' => '2042313f6628ef2b742c74aba0fd9b60', + './include/javascript/tiny_mce/plugins/paste/css/blank.css' => 'c15c875a4c54efa8554bca63aee6ecb9', + './include/javascript/tiny_mce/plugins/paste/blank.htm' => '88783f6e539184616896268bca04c25e', + './include/javascript/tiny_mce/plugins/pagebreak/img/trans.gif' => '12bf9e19374920de3146a64775f46a5e', + './include/javascript/tiny_mce/plugins/pagebreak/img/pagebreak.gif' => '48872075f721bf57a517e3275d61c0ba', + './include/javascript/tiny_mce/plugins/pagebreak/editor_plugin_src.js' => '8df9dc2e60f32b9429b592d3545f9bf5', + './include/javascript/tiny_mce/plugins/pagebreak/editor_plugin.js' => 'a1c5a59a36f772bc526411a9c8e74c63', + './include/javascript/tiny_mce/plugins/pagebreak/css/content.css' => 'd9664762a610f2b5f7b10b5781f3299a', + './include/javascript/tiny_mce/plugins/noneditable/editor_plugin_src.js' => '62077ede3d5f9a404297ef3f73e0a4a5', + './include/javascript/tiny_mce/plugins/noneditable/editor_plugin.js' => 'f305bdb3dbef3b880e69c48dfa4e40f4', + './include/javascript/tiny_mce/plugins/nonbreaking/editor_plugin_src.js' => 'c15a04691f8463cb0232e23f317a6b82', + './include/javascript/tiny_mce/plugins/nonbreaking/editor_plugin.js' => '9374e65064dfda87e93cd0163f236e5e', + './include/javascript/tiny_mce/plugins/media/media.htm' => '1f101c10c8c369f4466e95724148d454', + './include/javascript/tiny_mce/plugins/media/langs/en_dlg.js' => '26a49066e61ae69b5f837505afdea871', + './include/javascript/tiny_mce/plugins/media/js/media.js' => '1e782a443c073b57897597a0720e2a82', + './include/javascript/tiny_mce/plugins/media/js/embed.js' => '5df3783492b848adde42124a1e9cf383', + './include/javascript/tiny_mce/plugins/media/img/windowsmedia.gif' => 'c327cd167b3a7bc263d908b0d0154ead', + './include/javascript/tiny_mce/plugins/media/img/trans.gif' => '12bf9e19374920de3146a64775f46a5e', + './include/javascript/tiny_mce/plugins/media/img/shockwave.gif' => 'baa643b587565755157618032dc93e3c', + './include/javascript/tiny_mce/plugins/media/img/realmedia.gif' => 'b9734ee16d790e67bea01046feba28b7', + './include/javascript/tiny_mce/plugins/media/img/quicktime.gif' => '9a6a9fdead205b125c07ea37e71ed4f1', + './include/javascript/tiny_mce/plugins/media/img/flv_player.swf' => 'fe011e9725b2722b59bb8ef4991bf6bb', + './include/javascript/tiny_mce/plugins/media/img/flash.gif' => '6c69b02015d09280332ff8b07e4ea2f3', + './include/javascript/tiny_mce/plugins/media/editor_plugin_src.js' => 'ce9e21974624ae9aab32d2e3778bb443', + './include/javascript/tiny_mce/plugins/media/editor_plugin.js' => '9beecec5d5cbdc86bee17eadc0f5a545', + './include/javascript/tiny_mce/plugins/media/css/media.css' => '51795abbefc981b9f77083afd672a495', + './include/javascript/tiny_mce/plugins/media/css/content.css' => 'ebcad73e7f6785a308328129aa90d5cb', + './include/javascript/tiny_mce/plugins/layer/editor_plugin_src.js' => '5bf57b578756d293cf9be7845264158c', + './include/javascript/tiny_mce/plugins/layer/editor_plugin.js' => '67ea96e3d63b98215b64435bb9ea06d9', + './include/javascript/tiny_mce/plugins/insertdatetime/editor_plugin_src.js' => 'cee2d9a9ed09e51627350510b4f59b92', + './include/javascript/tiny_mce/plugins/insertdatetime/editor_plugin.js' => '0fba6e5bec7725b88b910721f1ba17a7', + './include/javascript/tiny_mce/plugins/inlinepopups/template.htm' => 'c01f15cd357d8dba4610c3eae6321930', + './include/javascript/tiny_mce/plugins/inlinepopups/skins/clearlooks2/window.css' => '5e33280ecbcbc97d23f44ba1d23b578a', + './include/javascript/tiny_mce/plugins/inlinepopups/skins/clearlooks2/img/vertical.gif' => '193884a332e91059643448ed4bde2e04', + './include/javascript/tiny_mce/plugins/inlinepopups/skins/clearlooks2/img/horizontal.gif' => '0365e75dd4a9ad61dc98dcb641207c21', + './include/javascript/tiny_mce/plugins/inlinepopups/skins/clearlooks2/img/corners.gif' => '2e89a17a473f0e488f3e789ce998f064', + './include/javascript/tiny_mce/plugins/inlinepopups/skins/clearlooks2/img/confirm.gif' => '44f1d55b14fbc66b98f3899d90611c3c', + './include/javascript/tiny_mce/plugins/inlinepopups/skins/clearlooks2/img/buttons.gif' => '1743ac9f7f2267a6edafefc536a2265d', + './include/javascript/tiny_mce/plugins/inlinepopups/skins/clearlooks2/img/button.gif' => '9e911a2c3cb4720d44844ef2d1832a51', + './include/javascript/tiny_mce/plugins/inlinepopups/skins/clearlooks2/img/alert.gif' => '56646a5e811547c8bc3d1b9790496b89', + './include/javascript/tiny_mce/plugins/inlinepopups/editor_plugin_src.js' => '8b90c63f48655787e47151ec44be119a', + './include/javascript/tiny_mce/plugins/inlinepopups/editor_plugin.js' => 'a7b58f0ddb0e55f591c00f06e21ada67', + './include/javascript/tiny_mce/plugins/iespell/editor_plugin_src.js' => 'bd46ad6daae27f6c9e7e7921386e1945', + './include/javascript/tiny_mce/plugins/iespell/editor_plugin.js' => 'e4e460c920b31b94153caacbf170851d', + './include/javascript/tiny_mce/plugins/fullscreen/fullscreen.htm' => '109958d17d54b93b827796c1a3bf0629', + './include/javascript/tiny_mce/plugins/fullscreen/editor_plugin_src.js' => 'e14f7ae502989882514d6c95fcb3c733', + './include/javascript/tiny_mce/plugins/fullscreen/editor_plugin.js' => 'd1ef8dc9ab08b7a58c5d96a56145ab4e', + './include/javascript/tiny_mce/plugins/fullpage/langs/en_dlg.js' => '785c97d3367c6d1e38ef0992b1353bdf', + './include/javascript/tiny_mce/plugins/fullpage/js/fullpage.js' => 'e8068fa9708f9457d4d1ee62ae7b13dc', + './include/javascript/tiny_mce/plugins/fullpage/fullpage.htm' => 'a035917ad7ab45825b1aa44ceebc084c', + './include/javascript/tiny_mce/plugins/fullpage/editor_plugin_src.js' => '3da0187e0e166ffd1cee9d09c3449fbb', + './include/javascript/tiny_mce/plugins/fullpage/editor_plugin.js' => '91acc45c66aaf73e58318072ff1bc7cd', + './include/javascript/tiny_mce/plugins/fullpage/css/fullpage.css' => '5aacff00f15c644c2edda317d39d480e', + './include/javascript/tiny_mce/plugins/example/langs/en_dlg.js' => '1edfe310d7cc45357de7093b47c863fd', + './include/javascript/tiny_mce/plugins/example/langs/en.js' => 'e3c958c51f74663e53d1fb5fe90c979f', + './include/javascript/tiny_mce/plugins/example/js/dialog.js' => 'ff7c6a3db0d905ae655a273b87d42c78', + './include/javascript/tiny_mce/plugins/example/img/example.gif' => '6036655a01df362267183a8b23fead10', + './include/javascript/tiny_mce/plugins/example/editor_plugin_src.js' => '6c83458b6d2857adf8855fd24e123195', + './include/javascript/tiny_mce/plugins/example/editor_plugin.js' => '82586c79393ca177140794c465f3719f', + './include/javascript/tiny_mce/plugins/example/dialog.htm' => '2790971b13eb7487d45504f98e574e27', + './include/javascript/tiny_mce/plugins/emotions/langs/en_dlg.js' => 'f6f80d840918e4bab3cb68fa135bb51b', + './include/javascript/tiny_mce/plugins/emotions/js/emotions.js' => '768ed76617dbe7fca0e7394c0f208681', + './include/javascript/tiny_mce/plugins/emotions/img/smiley-yell.gif' => '19bb8ebfe3c2f5ef3ffb9aa4a027900d', + './include/javascript/tiny_mce/plugins/emotions/img/smiley-wink.gif' => '4ae6aa98aa63363c16ea74f927696bd9', + './include/javascript/tiny_mce/plugins/emotions/img/smiley-undecided.gif' => '3c0c011d16b1a2331385ed97e160a42a', + './include/javascript/tiny_mce/plugins/emotions/img/smiley-tongue-out.gif' => '5ec3bb4781c8e43a51d3a1a948b98fc0', + './include/javascript/tiny_mce/plugins/emotions/img/smiley-surprised.gif' => 'eff5a6fbfb80ca2d3ae929b0a1c15638', + './include/javascript/tiny_mce/plugins/emotions/img/smiley-smile.gif' => 'c676407db519bdf42481870746f097d8', + './include/javascript/tiny_mce/plugins/emotions/img/smiley-sealed.gif' => '28b9401b59fb7ad10b96f57aaa2630c4', + './include/javascript/tiny_mce/plugins/emotions/img/smiley-money-mouth.gif' => '11c14bd1496afd0e21df115d25b68e96', + './include/javascript/tiny_mce/plugins/emotions/img/smiley-laughing.gif' => 'b691cfd07d8181059f8a4b041d534cc4', + './include/javascript/tiny_mce/plugins/emotions/img/smiley-kiss.gif' => '4ae8945f3960751b5d294f18242e144d', + './include/javascript/tiny_mce/plugins/emotions/img/smiley-innocent.gif' => 'ec0477c8a206ff250782e40f9bae4b4c', + './include/javascript/tiny_mce/plugins/emotions/img/smiley-frown.gif' => '59930208822fe755f651a67ef4b70530', + './include/javascript/tiny_mce/plugins/emotions/img/smiley-foot-in-mouth.gif' => '905294088277f201be5a8e0285fb7998', + './include/javascript/tiny_mce/plugins/emotions/img/smiley-embarassed.gif' => 'd59171236e6b0b96091eeda1f7b57ce3', + './include/javascript/tiny_mce/plugins/emotions/img/smiley-cry.gif' => 'e72bf995ceca9230273ed9909c5db9c8', + './include/javascript/tiny_mce/plugins/emotions/img/smiley-cool.gif' => 'e26e97a318f82ec144b0818e5a8f8edb', + './include/javascript/tiny_mce/plugins/emotions/emotions.htm' => 'df4b3424e331c7146510f61892ca6fa9', + './include/javascript/tiny_mce/plugins/emotions/editor_plugin_src.js' => 'b03aacb7f6d0010ba11cbcf8433327e7', + './include/javascript/tiny_mce/plugins/emotions/editor_plugin.js' => 'fc11ff82324f77c41e1a44c1044d79ff', + './include/javascript/tiny_mce/plugins/directionality/editor_plugin_src.js' => '62860b40fe8fc26a6ba2a6d8777bd3b3', + './include/javascript/tiny_mce/plugins/directionality/editor_plugin.js' => '7713d6e3e2531ea5047b4e2532448d43', + './include/javascript/tiny_mce/plugins/contextmenu/editor_plugin_src.js' => '79844351ba38362467267631cad31e30', + './include/javascript/tiny_mce/plugins/contextmenu/editor_plugin.js' => '47f5b7af1ec73bf958d29045b968cea2', + './include/javascript/tiny_mce/plugins/compat2x/editor_plugin_src.js' => '3f7fe550b6d08203ef20f7f9b75f4493', + './include/javascript/tiny_mce/plugins/compat2x/editor_plugin.js' => 'c3d0aefeb6c5853d66654cc63e7cd3d9', + './include/javascript/tiny_mce/plugins/bbcode/editor_plugin_src.js' => '8ec9b5c2ff78959fa189ebe54376ba78', + './include/javascript/tiny_mce/plugins/bbcode/editor_plugin.js' => '19384072defc93532c0ecb7da2cf8f80', + './include/javascript/tiny_mce/plugins/autosave/editor_plugin_src.js' => '1badd9a8ebfeeeaa4293fac97be6bb66', + './include/javascript/tiny_mce/plugins/autosave/editor_plugin.js' => 'f54e4df3a63237afd7471c95d8484f6e', + './include/javascript/tiny_mce/plugins/advlink/link.htm' => '28b4e8b3b295a9aad181667a71ad5a5a', + './include/javascript/tiny_mce/plugins/advlink/langs/en_dlg.js' => 'a8f914a5c88714aee11eda0d75c98e71', + './include/javascript/tiny_mce/plugins/advlink/js/advlink.js' => 'd27775961d02693ef20d36dd8206c95a', + './include/javascript/tiny_mce/plugins/advlink/editor_plugin_src.js' => '565fc5493ec00039570ac605e3b5f01c', + './include/javascript/tiny_mce/plugins/advlink/editor_plugin.js' => '519f312b12dbc801f5d199f19ea650bb', + './include/javascript/tiny_mce/plugins/advlink/css/advlink.css' => '19558f5e2b7a7d11968aacdc37e6e436', + './include/javascript/tiny_mce/plugins/advimage/langs/en_dlg.js' => '11192eee56b945762dd843279ba34b81', + './include/javascript/tiny_mce/plugins/advimage/js/image.js' => '5d1229957e7e297beb11e5cc931bd636', + './include/javascript/tiny_mce/plugins/advimage/img/sample.gif' => 'b9c7057c46716340e8967340ad11766e', + './include/javascript/tiny_mce/plugins/advimage/image.htm' => '9c047eccb30c3073ebdf58abb7239a35', + './include/javascript/tiny_mce/plugins/advimage/editor_plugin_src.js' => '83575eef2712b169d8ca3548dc9a7efd', + './include/javascript/tiny_mce/plugins/advimage/editor_plugin.js' => '848ad22a9baff75c57d0d7f645f361ba', + './include/javascript/tiny_mce/plugins/advimage/css/advimage.css' => 'cce2bc7334ac52894124133d62c8d09c', + './include/javascript/tiny_mce/plugins/advhr/rule.htm' => 'c7f2e7569234a4ee4650ecde6d5053ac', + './include/javascript/tiny_mce/plugins/advhr/langs/en_dlg.js' => 'ba874544a2e8a6c07c476a25c48deb16', + './include/javascript/tiny_mce/plugins/advhr/js/rule.js' => '2fa441f1684a33d3ea89bb31cdea1ba5', + './include/javascript/tiny_mce/plugins/advhr/editor_plugin_src.js' => 'e2e474ebf2f1351c85f249fd5c948183', + './include/javascript/tiny_mce/plugins/advhr/editor_plugin.js' => '713492f5963523fcc075d873cccfdacf', + './include/javascript/tiny_mce/plugins/advhr/css/advhr.css' => '2d33b4333e29436b2102747f2ee2f395', + './include/javascript/tiny_mce/license.txt' => '045d04e17422d99e338da75b9c749b7c', + './include/javascript/tiny_mce/langs/en.js' => '5a1cd3c93501e4f7c75267d5617e7c9a', + './include/javascript/sugarwidgets/SugarYUILoader.js' => '3004b379974f68076dc298ab70e1f62d', + './include/javascript/sugarwidgets/SugarYUIWidgets.js' => '101a53f750187962cd209b1cfe531099', + './include/javascript/jsAlerts.php' => 'b026aec8b25d773ffc2e2562d51991d8', + './include/javascript/javascript.php' => '688f6f9c621400fe6d8c60874d54c382', + './include/javascript/getYUIComboFile.php' => '301a1c825ce73b706c0d84a028bc40ef', + './include/images/seed_will_id.gif' => '2f106be21d1591fcb91636594eeb1689', + './include/images/seed_sarah_id.gif' => 'e2f269d97a3a3f500dff75b770d6c6b1', + './include/images/seed_sally_id.gif' => 'cf29cdbd09b88a5f0f8f038b5f6b1db6', + './include/images/seed_max_id.gif' => 'e208059a38b9899e47b9e3dad65e8888', + './include/images/seed_jim_id.gif' => 'ccdaf0d492f924e8af2611b374550abd', + './include/images/seed_chris_id.gif' => 'ec816fe3d80053c5225890e838a5813e', + './include/images/default_user_feed_picture.png' => '76d7a79b8b448b05b7e0107d72222b95', + './include/images/1.gif' => '9560abd50536d3d57c23316c75f93fe7', + './include/images/wiki.png' => '6d21a744511a1b55378fbc985daac0e4', + './include/images/university.png' => '346083109b89352e3a4b77cc249c56df', + './include/images/sugarsales_myarea.png' => '32a23fbbf16b4d48f2e07292818d8ace', + './include/images/sugarcrm_login.png' => 'afc309ed136be87743408f886b2c50b2', + './include/images/sugarcrm_copyright_logo.jpg' => 'cab0f0a114f2df12d8a5a4ec3fe3ad2a', + './include/images/sugarcrm_about_logo.gif' => '3b5367037b236499ea9ecb95c901f654', + './include/images/sugar_wizard_welcome.jpg' => '523c31a42a62812e815cb5f413edb0ff', + './include/images/sugar_md_open.png' => 'b16339fb0a08fc2b35ba9d7d811bfb69', + './include/images/sugar_icon.ico' => '92f1ffd4b2fef157613e48d2d2c7d9c8', + './include/images/spacer.png' => '7df3dbe42ba6f94e0373ba374a2c5a74', + './include/images/rss_xml.gif' => 'd69bb576307f6ccb889d7acc96303edf', + './include/images/poweredby_sugarcrm.png' => 'f3ad3d8f733c7326a8affbdc94a2e707', + './include/images/powered_by_sugarcrm.gif' => 'fbc4de76cab648346bd7273823e0a0e2', + './include/images/options_up.gif' => '9307eb60df1cc0151bae58e5a64506c1', + './include/images/options.gif' => '8670274891572e477026ce53702ba140', + './include/images/kb.png' => 'c2ca9ff53826ae025ea68f861957dcc9', + './include/images/iphone-toolbar.png' => 'e58c24e451aea4e82cfa1a5cb2c00ea8', + './include/images/iphone-listArrow.png' => '3d059e6b6957c1be7a1bfdb4316776e6', + './include/images/install_themes.jpg' => '01fe7a67fb311afe5e93e9819ca36b12', + './include/images/forums.png' => '6079f5d08a4d4b3504223209e1ae5b46', + './include/images/docs.png' => '0752db044e772d50293561053acac995', + './include/images/cube_bg.gif' => 'bb01880551373dc9a2056697be69e5c1', + './include/images/blank.gif' => 'fc94fb0c3ed8a8f909dbc7630a0987ff', + './include/images/SugarPlanet.swf' => '5af57f2ee896225c65d9411aa2a1b971', + './include/globalControlLinks.php' => 'ce7bc3b7f32aafef2a9796cde652b356', + './include/generic/SugarWidgets/SugarWidgetFieldfile.php' => 'c5bc9bca34c26513b98edc87521c26e5', + './include/generic/SugarWidgets/SugarWidgetSubPanelTopSummaryButton.php' => '5696649565fb5a9d4ce9026896ccfc5f', + './include/generic/SugarWidgets/SugarWidgetSubPanelTopSelectUsersButton.php' => '9fae334284b2425e0793eac8e786e57c', + './include/generic/SugarWidgets/SugarWidgetSubPanelTopSelectContactsButton.php' => 'e762dcee7db8e1cf6e4e2a00ee7026ba', + './include/generic/SugarWidgets/SugarWidgetSubPanelTopSelectButton.php' => 'ace464efc2015de1c6387f3086726bfc', + './include/generic/SugarWidgets/SugarWidgetSubPanelTopScheduleMeetingButton.php' => '80202780d705fc3820af718521967ac3', + './include/generic/SugarWidgets/SugarWidgetSubPanelTopScheduleCallButton.php' => '27c611e9a26d941e662520034e0fd05d', + './include/generic/SugarWidgets/SugarWidgetSubPanelTopCreateTaskButton.php' => 'ffea8c95fa8a3aaa35ab5392245515a8', + './include/generic/SugarWidgets/SugarWidgetSubPanelTopCreateNoteButton.php' => '7b5567ea71baa16d9c168378abb69a81', + './include/generic/SugarWidgets/SugarWidgetSubPanelTopCreateLeadNameButton.php' => '8b965c92591f1f6aadc56be9bebe77f2', + './include/generic/SugarWidgets/SugarWidgetSubPanelTopCreateCampaignLogEntryButton.php' => 'af0d6f1ec98b54b267fcc9fbba3e3563', + './include/generic/SugarWidgets/SugarWidgetSubPanelTopCreateAccountNameButton.php' => 'bf9f9158ad56ac876c1608fe3e4c28ed', + './include/generic/SugarWidgets/SugarWidgetSubPanelTopComposeEmailButton.php' => '981a63a7c741406101e24d99890f9eba', + './include/generic/SugarWidgets/SugarWidgetSubPanelTopButtonQuickCreate.php' => 'e7982b2e1db4ec5bd1d3544e0da26a0c', + './include/generic/SugarWidgets/SugarWidgetSubPanelTopButton.php' => 'a585b852abf10a6c8ca3580d841f9cad', + './include/generic/SugarWidgets/SugarWidgetSubPanelTopArchiveEmailButton.php' => 'dc3ec22caf6297d2372565748171afbe', + './include/generic/SugarWidgets/SugarWidgetSubPanelRemoveButtonProjects.php' => '95410891867c4aa7c3ecf1d22f05960a', + './include/generic/SugarWidgets/SugarWidgetSubPanelRemoveButtonMeetings.php' => 'f0a69da4a6bcf4834f4bf95ed14f9152', + './include/generic/SugarWidgets/SugarWidgetSubPanelRemoveButton.php' => 'd2a945db662c90388b569a79bc18d712', + './include/generic/SugarWidgets/SugarWidgetSubPanelLoadSignedButton.php' => 'd85482cfc0b3a551a12dfcf11c11c492', + './include/generic/SugarWidgets/SugarWidgetSubPanelIcon.php' => 'f53fa357004d47f82484f967aeacbf68', + './include/generic/SugarWidgets/SugarWidgetSubPanelGetLatestButton.php' => '902c0450d1778518168e9a9f9ccfa6f5', + './include/generic/SugarWidgets/SugarWidgetSubPanelEmailLink.php' => '95ff0dc2d42b1b25107ef128ab096a9e', + './include/generic/SugarWidgets/SugarWidgetSubPanelEditRoleButton.php' => '69b53a79d5ef87686e296fbc05e2ec56', + './include/generic/SugarWidgets/SugarWidgetSubPanelEditButton.php' => 'f9584779332d60db9491e0319e74427c', + './include/generic/SugarWidgets/SugarWidgetSubPanelDetailViewLink.php' => '37e4981c6986c4e73cac346e2b63d2bd', + './include/generic/SugarWidgets/SugarWidgetSubPanelConcat.php' => '0e697509261a028df51ceb692a6ea068', + './include/generic/SugarWidgets/SugarWidgetSubPanelCloseButton.php' => '0ca0857af92ee67860aa46f9c9e46e07', + './include/generic/SugarWidgets/SugarWidgetSubPanelActivitiesStatusField.php' => '44eb88e248bef0ba23221ab83b6cae6a', + './include/generic/SugarWidgets/SugarWidgetReportField.php' => 'a97fcf5a523af0b705b84152a644afab', + './include/generic/SugarWidgets/SugarWidgetFieldvarchar.php' => '5cce3ce38cf44dfa33a0ad08a3564752', + './include/generic/SugarWidgets/SugarWidgetFielduser_name.php' => '25f000dd33af6d28855ed53ffb62ec0f', + './include/generic/SugarWidgets/SugarWidgetFieldurl.php' => '2da41197d48165e9190b36b441fe249f', + './include/generic/SugarWidgets/SugarWidgetFieldtime.php' => 'd9155212b43391cc39edb4fa76b48352', + './include/generic/SugarWidgets/SugarWidgetFieldtext.php' => '05289dd957f4af46af219fc9667bee1b', + './include/generic/SugarWidgets/SugarWidgetFieldsingleenum.php' => '0cf6ba23c43a1566d815587d7854653f', + './include/generic/SugarWidgets/SugarWidgetFieldrelate.php' => '41d73fbd5776752fb59d4f061513693b', + './include/generic/SugarWidgets/SugarWidgetFieldradioenum.php' => '84507957179e3141d1457ae5fa88271b', + './include/generic/SugarWidgets/SugarWidgetFieldphone.php' => '262983ecb15f82d6f97b7fa7b8b2a1fe', + './include/generic/SugarWidgets/SugarWidgetFieldparent_type.php' => 'cadd3bdca6fdc5581c8d3f12bcd65030', + './include/generic/SugarWidgets/SugarWidgetFieldnum.php' => '6e9acb9aa2dd466d512bad04055c077a', + './include/generic/SugarWidgets/SugarWidgetFieldname.php' => '82f23ab96426931818aaf182ba144bf4', + './include/generic/SugarWidgets/SugarWidgetFieldmultienum.php' => 'bc6c91efab351c068f12e475dd8775b5', + './include/generic/SugarWidgets/SugarWidgetFieldlongtext.php' => '8d5ff0012181531feb562c2efcbc64d9', + './include/generic/SugarWidgets/SugarWidgetFieldint.php' => 'a8c8b274638a9cf039b3d8c266416b9f', + './include/generic/SugarWidgets/SugarWidgetFieldimage.php' => '63b6909b63eafc2bda2d53cb5e6f30d5', + './include/generic/SugarWidgets/SugarWidgetFieldid.php' => '461a534ec0747e686e0ebda2d914845e', + './include/generic/SugarWidgets/SugarWidgetFieldfullname.php' => '3682f5255bf8218b17fc66c30b884999', + './include/generic/SugarWidgets/SugarWidgetFieldfloat.php' => '5d38efd212076d9f096e4225145198e4', + './include/generic/SugarWidgets/SugarWidgetFieldenum.php' => 'b793766549772ded73db9baf19a43451', + './include/generic/SugarWidgets/SugarWidgetFieldemail.php' => '2b239faf616c60f7162fe4fe7259c055', + './include/generic/SugarWidgets/SugarWidgetFielddouble.php' => '8a726ca346e99c9ca1bd6d4972158706', + './include/generic/SugarWidgets/SugarWidgetFielddecimal.php' => '732686fb5739045a130f90f38055cd57', + './include/generic/SugarWidgets/SugarWidgetFielddatetimecombo.php' => 'ed002f3290327c4159579183b42c7d2c', + './include/generic/SugarWidgets/SugarWidgetFielddatetime.php' => 'ef8b68006510a82183ca5f09cee12d59', + './include/generic/SugarWidgets/SugarWidgetFielddatepicker.php' => 'bccc9cba27b46155a0c37fb77531b976', + './include/generic/SugarWidgets/SugarWidgetFielddate.php' => 'fd743d90553bb939b2fd5e8c47064e60', + './include/generic/SugarWidgets/SugarWidgetFieldcurrency.php' => '0d5b18e3408daba97dfb52642ccd759d', + './include/generic/SugarWidgets/SugarWidgetFieldchar.php' => '0df053d7f26f7677a97cda3c03c1e212', + './include/generic/SugarWidgets/SugarWidgetFieldbool.php' => 'cf88ae65be60587132bd357ea5e12c94', + './include/generic/SugarWidgets/SugarWidgetField.php' => 'a495548c3eebdbfbd26d94a3588b4cb2', + './include/generic/SugarWidgets/SugarWidget.php' => '0270ae80c91ede2bd270dd2c364451ed', + './include/generic/Save2.php' => '8fe37a23641d1dac8c6eaa40e03356a9', + './include/generic/LayoutManager.php' => 'f683d0982c048f6ba6c1bd0386dcf746', + './include/generic/DeleteRelationship.php' => 'a09280088f5f6f6fcfb7fdb1477dd8b5', + './include/formbase.php' => 'a3a0d4280a6c00163c3f8f908fc56beb', + './include/fonts/License.html' => '8a22bc6b773aeb68f9748fd1920f84d4', + './include/fonts/Times-Roman.afm' => 'f257a72c31f6a864f4e0994b1771628c', + './include/fonts/Times-Italic.afm' => 'c41212e70e19627889aefef85212a47d', + './include/fonts/Times-BoldItalic.afm' => '49d6b1de28b2f8f6f8a4eaff2485071f', + './include/fonts/Times-Bold.afm' => 'e2244341873416fa5d56635b5bfb797e', + './include/fonts/Helvetica.afm' => '9cceac6630e6963e1b4bfcd89ce91cb4', + './include/fonts/Helvetica-Oblique.afm' => '6261d6f49c6d20fe257ddd8be12c5fa0', + './include/fonts/Helvetica-BoldOblique.afm' => '1a0205dc4b27270f07aae77da1bdff1e', + './include/fonts/Helvetica-Bold.afm' => '50bddd1766f49443b3b3925cb81b971b', + './include/fonts/Courier.afm' => 'cd99e74c7dd0cd1952d5bc878f90c541', + './include/fonts/Courier-Oblique.afm' => '3324f479739ac9ebab740772b55705d2', + './include/fonts/Courier-BoldOblique.afm' => '5c34aeefc1ef69ae2fb317abc1ccc9ca', + './include/fonts/Courier-Bold.afm' => 'cb84ced0cc430a5d54497257a11638f5', + './include/export_utils.php' => 'c2bc58e4366464ee38c82e54b5c8e231', + './include/entryPoint.php' => '7992853edeb130ccff864920956a5910', + './include/dir_inc.php' => '3d81f515f41d3f7d654560093e10fcd2', + './include/database/SqlsrvManager.php' => '4f26319dcb5863696334243bf7b4e579', + './include/database/SqlsrvHelper.php' => '192ad146c32328a5f6a0143d07253fd2', + './include/database/PearDatabase.php' => '04c1aaa57df1bc5516c455b8883d56d2', + './include/database/MysqliManager.php' => '422bf5cf16c77a4b04c4477dd884a145', + './include/database/MysqliHelper.php' => '5c29384d6a98b58e4a70222012ede66b', + './include/database/MysqlManager.php' => '2df7ae91dc3750abf2edf8ab66e85c25', + './include/database/MysqlHelper.php' => 'a6866f89272d781eae540a54437f50d8', + './include/database/MssqlManager.php' => 'a3532faae8ed3b2fb486207a91c05b78', + './include/database/MssqlHelper.php' => '4d98d46ecb0139685571d7c9a98984cb', + './include/database/FreeTDSManager.php' => 'bbeb3f527257a0ebe0fd2f27f4090ca0', + './include/database/FreeTDSHelper.php' => '1f725f014b815db50a02427b8ad07352', + './include/database/DBManagerFactory.php' => '83c89bd465be2c859b15f336d5e22a1d', + './include/database/DBManager.php' => 'cfd4407e7034285edd54e090101cfea8', + './include/database/DBHelper.php' => 'd23ca59ade289a4b826cf55936e92e1d', + './include/controller/Controller.php' => 'f65e2428b4f9b9ed709278aced7099d6', + './include/contextMenus/menuDefs/sugarPerson.php' => '6ba041d95634a9dbdbea99e55a8e51d6', + './include/contextMenus/menuDefs/sugarObject.php' => '298c89b8c3e5386763e71515b4c11d93', + './include/contextMenus/menuDefs/sugarAccount.php' => '2f933fb2dafb7273d5c98f05613ecfa9', + './include/contextMenus/contextMenu.php' => 'fec90b47bb1071a653b972fc4947f2cc', + './include/connectors/utils/ConnectorUtils.php' => '7c28a58adec5ccf4e23cd1beec6a16ea', + './include/connectors/sources/loc/xml.php' => '45ca47d630dfd777456d2b3054dc1778', + './include/connectors/sources/ext/soap/soap.php' => 'a7302d7bd5ebeea6c3d83ae5cd230b16', + './include/connectors/sources/ext/rest/rest.php' => '78a5eab8f0a0ad3b41d92cf132db2b17', + './include/connectors/sources/default/source.php' => '97984ab7a11960de881fb7d04dceda6f', + './include/connectors/sources/SourceFactory.php' => 'cb0d179dd2da3c8bc70a8bc93f86ecd8', + './include/connectors/formatters/ext/soap/tpls/default.tpl' => '7b470afa25be5f2a9cb14cfcc2cbec25', + './include/connectors/formatters/ext/rest/tpls/default.tpl' => 'ae976eb0b1c3a97ff1471746ddc07bda', + './include/connectors/formatters/default/company_detail.js' => '47c3b66024d7cb298c22c01881b78529', + './include/connectors/formatters/default/formatter.php' => 'dd7be2adff839e1c56d13ee8627ece52', + './include/connectors/formatters/FormatterFactory.php' => 'f2838a245924053435869c4ff981235e', + './include/connectors/filters/default/filter.php' => 'c6a34cf14ec98a2a149c447b3c627a1c', + './include/connectors/filters/FilterFactory.php' => 'a74c1562a8f4f6f49e98d0b85efc9b20', + './include/connectors/component.php' => '722227b98fc941d55b0f5dabcb0bff23', + './include/connectors/ConnectorFactory.php' => '44f817c0e5e2db8db9ca5a40f3d4fe45', + './include/VarDefHandler/vardef_meta_arrays.php' => '6144157c776b1d019d0389d1ed0a9868', + './include/VarDefHandler/listvardefoverride.php' => 'd9e443ba78875b7aec6f0cf7b9e17468', + './include/VarDefHandler/VarDefHandler.php' => 'fab80ef153197b304b35cca428000009', + './include/TimeDate.php' => '935896bea5c3d4c78ff212d5170584ca', + './include/TemplateHandler/TemplateHandler.php' => '6854cd6b85466421987803f7962c4b5c', + './include/Sugarpdf/sugarpdf_default.php' => 'a0310a0194f541373e42c96e83b2b144', + './include/Sugarpdf/sugarpdf_config.php' => '5bb0994c91417984853bb9a33c7277e5', + './include/Sugarpdf/sugarpdf/sugarpdf.smarty.php' => '682203646fe9e1e21972ae28cf626723', + './include/Sugarpdf/SugarpdfHelper.php' => '52616eccc49a3a36e74670f3b281a277', + './include/Sugarpdf/SugarpdfFactory.php' => '374161d342248fb7348a1b80478d8c29', + './include/Sugarpdf/Sugarpdf.php' => 'c338aadbb7e308c2c5e1ca85e9d32c2a', + './include/Sugarpdf/FontManager.php' => '4a2de9036d79ab5ebe45ab3eee82695e', + './include/Sugar_Smarty.php' => '547322d4d90cf3c8f9a272bde06ea156', + './include/SugarTinyMCE.php' => 'ad41bfa32103b12916cd596893217566', + './include/SugarTheme/getImage.php' => '2da8f180e461703dafc2e95cc421dd8b', + './include/SugarTheme/cssmin.php' => '05384ba957435def09368425e4480688', + './include/SugarTheme/SugarTheme.php' => 'b7454114e7c736cf807e9dd7e13afbe3', + './include/SugarPHPMailer.php' => 'c4fb090f36f4d295af06ff02049d59eb', + './include/SugarCache/SugarCachesMash.php' => 'd08b32ef33a07c4a1960f326fb5f4b14', + './include/SugarCache/SugarCacheZend.php' => 'e8d3c30797a8e3f3d9717833f7ac2cd4', + './include/SugarCache/SugarCacheWincache.php' => '6bf210ca6bad3f4626c01a15cd598e2c', + './include/SugarCache/SugarCacheRedis.php' => '1d3300c42f473e7a0cc1bb21dcd3ea15', + './include/SugarCache/SugarCacheMemory.php' => 'd84fd2039ca0607fbe03ea23cde088d1', + './include/SugarCache/SugarCacheMemcached.php' => '4f804c06901db015780f373ed669a386', + './include/SugarCache/SugarCacheMemcache.php' => '4795c41709b2dfb3dd64414f7e75d2af', + './include/SugarCache/SugarCacheFile.php' => '6e2628da550c6235d87248825d3eb13e', + './include/SugarCache/SugarCacheAbstract.php' => '134458b0b255e28c6455e77ec0f170ba', + './include/SugarCache/SugarCacheAPC.php' => 'bd0a80c914aa68152e9429a9e3f86777', + './include/SugarCache/SugarCache.php' => 'ea7a05845f592a44da4b9057237000e1', + './include/SugarObjects/templates/sale/vardefs.php' => 'c7e359ed4c4876b961b4171641021ae0', + './include/SugarObjects/templates/sale/metadata/subpanels/default.php' => '8fb6a0b90aab32115fdec077adfee755', + './include/SugarObjects/templates/sale/metadata/searchdefs.php' => '01fab0adf7fb0aec30bb84ab07f551fa', + './include/SugarObjects/templates/sale/metadata/quickcreatedefs.php' => 'd28a9e618293f5aedcfa2d02cd3c2705', + './include/SugarObjects/templates/sale/metadata/popupdefs.php' => 'c1e9b08060c35ec85c272c6494e3ccf6', + './include/SugarObjects/templates/sale/metadata/metafiles.php' => '349e6ae03d64d736e8c362da98d71c5b', + './include/SugarObjects/templates/sale/metadata/listviewdefs.php' => '962f7f6c741c3693bcb6e5ad7b1ef5cd', + './include/SugarObjects/templates/sale/metadata/editviewdefs.php' => '3b7bef9b86fe2e2acf45e9d8d7fec67a', + './include/SugarObjects/templates/sale/metadata/detailviewdefs.php' => '42aa1f0f13dce34821b418f06b3e8e9b', + './include/SugarObjects/templates/sale/metadata/dashletviewdefs.php' => '8480c18ee629a8743d5acf9d793110ec', + './include/SugarObjects/templates/sale/metadata/SearchFields.php' => 'b48d639de511f148dc0f0f8f069987ba', + './include/SugarObjects/templates/sale/language/en_us.lang.php' => 'e17866d97b78d60cab78d64119eaceff', + './include/SugarObjects/templates/sale/language/application/en_us.lang.php' => '88a7f50d64f44799c5b4909ab55a0a80', + './include/SugarObjects/templates/sale/icons/sale_32.gif' => 'f73940c5f0691ffcc4758052272ffc44', + './include/SugarObjects/templates/sale/icons/sale.gif' => 'a89b5a96e5373e8ef621eb3cc8afa2fb', + './include/SugarObjects/templates/sale/icons/chance_32.gif' => '31c7c09bbe878fb78697aca9fb6a49b0', + './include/SugarObjects/templates/sale/icons/chance.gif' => '496625c78161bf4d5e7489d7f3a68d2a', + './include/SugarObjects/templates/sale/icons/Createsale.gif' => 'c1f20d3fdb3859f2f0b1c23b1e154614', + './include/SugarObjects/templates/sale/icons/Createchance.gif' => 'f4fae6d5a4f0135f9e7ea3fbd1a5a80f', + './include/SugarObjects/templates/sale/config.php' => '30a05f45b0d685a9f6486eb1a9b96151', + './include/SugarObjects/templates/sale/Sale.php' => '4811047a40a7167746b14ac103c866d8', + './include/SugarObjects/templates/sale/Chance.php' => 'c8c6b5645b05f82a3e365167d632e493', + './include/SugarObjects/templates/person/vardefs.php' => '2cd0813852af09932d7755631677c6b8', + './include/SugarObjects/templates/person/metadata/subpanels/default.php' => '867623b0a38ac6ac3d34b8fa090117ed', + './include/SugarObjects/templates/person/metadata/searchdefs.php' => 'b2cca9bc8177bb3cfecb3b8cf571ff4b', + './include/SugarObjects/templates/person/metadata/quickcreatedefs.php' => 'a3e2327b2d5dc1b7aaafc9915ffcba40', + './include/SugarObjects/templates/person/metadata/popupdefs.php' => '5d236c65abe1283a2f37ef8896a2928a', + './include/SugarObjects/templates/person/metadata/metafiles.php' => 'b8fdfd4c9f179268320f2043fa142cb3', + './include/SugarObjects/templates/person/metadata/listviewdefs.php' => 'bd2a6592f2f5186007e577065eb7e3aa', + './include/SugarObjects/templates/person/metadata/editviewdefs.php' => '6e716bae04fa96ec21f8827ab226b47e', + './include/SugarObjects/templates/person/metadata/detailviewdefs.php' => '9975beb00d896f3bcd6ea1699ab75b60', + './include/SugarObjects/templates/person/metadata/dashletviewdefs.php' => 'cc28034dbe0d1bda3c6778254168990c', + './include/SugarObjects/templates/person/metadata/SearchFields.php' => '1cdf25fc8f2f44f8b0336b12c7f7f256', + './include/SugarObjects/templates/person/language/en_us.lang.php' => 'ffd666b39971db1d0bbe8e454d0fe43f', + './include/SugarObjects/templates/person/icons/person_32.gif' => '1550c24a793910550200679be1c5c078', + './include/SugarObjects/templates/person/icons/person.gif' => 'ea5e2b2022166291d01ccedaf24b4e33', + './include/SugarObjects/templates/person/icons/Createperson.gif' => '2e20692d501b15729294b80f4f311d77', + './include/SugarObjects/templates/person/config.php' => 'b6eb8ddda2e789be72d8ed423a48890d', + './include/SugarObjects/templates/person/Person.php' => '644282f973fcb83d3555d22a482d7390', + './include/SugarObjects/templates/issue/vardefs.php' => '9891c01794faa4962c37f1e88724c49d', + './include/SugarObjects/templates/issue/metadata/subpanels/default.php' => '55fefed3cdd67df4470e62d806bf69a2', + './include/SugarObjects/templates/issue/metadata/searchdefs.php' => '6ed06477c8f74fa2c347e8dfe54babf6', + './include/SugarObjects/templates/issue/metadata/quickcreatedefs.php' => '9245483009fd5637fc59cd43e3549e20', + './include/SugarObjects/templates/issue/metadata/popupdefs.php' => '604126a5cfcb85b6dba8ecea992188e3', + './include/SugarObjects/templates/issue/metadata/metafiles.php' => 'b08ff06cfacb9c839860955c149cde9b', + './include/SugarObjects/templates/issue/metadata/listviewdefs.php' => '9574102213b07d831532b60476d16345', + './include/SugarObjects/templates/issue/metadata/editviewdefs.php' => '74cd547e922d0e3c7b617f4f3e17b4df', + './include/SugarObjects/templates/issue/metadata/detailviewdefs.php' => '3bf56f585aa0ca6cd641839146a7be3b', + './include/SugarObjects/templates/issue/metadata/dashletviewdefs.php' => 'cc28034dbe0d1bda3c6778254168990c', + './include/SugarObjects/templates/issue/metadata/SearchFields.php' => '414756f5fd12364a365ab10ecd68819b', + './include/SugarObjects/templates/issue/language/en_us.lang.php' => '624b8d8abc8bdb409e2447b8dd3bb51d', + './include/SugarObjects/templates/issue/language/application/en_us.lang.php' => 'd3c5595f7b0afbe04034d8cf26d43cd7', + './include/SugarObjects/templates/issue/icons/issue_32.gif' => 'b2f4acfa921e04b500320c2f6e271478', + './include/SugarObjects/templates/issue/icons/issue.gif' => 'b991bb74ff3c649b1f6592a4f3c6c114', + './include/SugarObjects/templates/issue/icons/Createissue.gif' => '269352232732ae705318612e960b9eba', + './include/SugarObjects/templates/issue/config.php' => '6f9cdfda0abefeab1262260d9030468c', + './include/SugarObjects/templates/issue/Issue.php' => '94069381dc9edadcfa1c231f1f7b4205', + './include/SugarObjects/templates/file/views/view.edit.php' => '5f65187fb35d6ea4b9dcd15a2e1011a4', + './include/SugarObjects/templates/file/vardefs.php' => '0e5a1978b2fbf76e6aff450942d75c07', + './include/SugarObjects/templates/file/metadata/subpanels/default.php' => 'e68b8639a483574b567629cf5bd08807', + './include/SugarObjects/templates/file/metadata/searchdefs.php' => '0ee0f29439e89162c8aef48953f45368', + './include/SugarObjects/templates/file/metadata/quickcreatedefs.php' => 'a20d8b973b3eadf4d5f22766b0f16408', + './include/SugarObjects/templates/file/metadata/metafiles.php' => 'e7d5c1d5e0c06c7984a7db04ee3f6383', + './include/SugarObjects/templates/file/metadata/listviewdefs.php' => '96f0351f161a616abc216f1e60064f5e', + './include/SugarObjects/templates/file/metadata/editviewdefs.php' => '1300d3e0819a32c4e8d8abf344d491fc', + './include/SugarObjects/templates/file/metadata/detailviewdefs.php' => 'cd73435c99737ea80a61ea8e41c902bf', + './include/SugarObjects/templates/file/metadata/dashletviewdefs.php' => '330f959e99840611d6f9cd0772c0892e', + './include/SugarObjects/templates/file/metadata/SearchFields.php' => '1960514f7d8268fc6842fa61b7edf365', + './include/SugarObjects/templates/file/language/en_us.lang.php' => '898b828442b97e1768533da6bd0ec262', + './include/SugarObjects/templates/file/language/application/en_us.lang.php' => '73927a49ad5d7b030819fe9735e0e3ee', + './include/SugarObjects/templates/file/icons/file_32.gif' => '16b6a44601f20a651d1c83dc1a020c12', + './include/SugarObjects/templates/file/icons/file.gif' => 'a577b65a0589e748d18aa1baef4e05c6', + './include/SugarObjects/templates/file/icons/Createfile.gif' => '3ed1d93938f715b1af93c0e99e900af5', + './include/SugarObjects/templates/file/controller.php' => 'd63646be092ad4d77c1ca096c413c43c', + './include/SugarObjects/templates/file/File.php' => 'b8f71060ea100f8d957176efa7d5dd5c', + './include/SugarObjects/templates/company/vardefs.php' => '1b297504eb8a626027d9acbb3ba986b1', + './include/SugarObjects/templates/company/metadata/subpanels/default.php' => '2ab6e9a96e88586d6060f1b8ec003397', + './include/SugarObjects/templates/company/metadata/searchdefs.php' => '7f963db941a6086a9b07c0ead95f3459', + './include/SugarObjects/templates/company/metadata/quickcreatedefs.php' => '19ac11f356b67d89ff17a26017af880a', + './include/SugarObjects/templates/company/metadata/popupdefs.php' => '7179e7d1045762be6ebf2150548a0ad3', + './include/SugarObjects/templates/company/metadata/metafiles.php' => 'b08ff06cfacb9c839860955c149cde9b', + './include/SugarObjects/templates/company/metadata/listviewdefs.php' => '539fc5542521c85335c63f5f455b6a4a', + './include/SugarObjects/templates/company/metadata/editviewdefs.php' => '1fbcdf5012b949eab9c7688cb6340009', + './include/SugarObjects/templates/company/metadata/detailviewdefs.php' => 'fc34b1ab8299a43de9a56f6a3aee928c', + './include/SugarObjects/templates/company/metadata/dashletviewdefs.php' => 'cc28034dbe0d1bda3c6778254168990c', + './include/SugarObjects/templates/company/metadata/SearchFields.php' => 'fc8ac6014765325f5021bdada6175cda', + './include/SugarObjects/templates/company/language/en_us.lang.php' => '660bc6f5262880cf44d6a1d0e20bce1f', + './include/SugarObjects/templates/company/language/application/en_us.lang.php' => '2d87dea43be8c2850cf3abf0ba7ea7c5', + './include/SugarObjects/templates/company/icons/company_32.gif' => 'eb850fc1863a46987cdafca12693c789', + './include/SugarObjects/templates/company/icons/company.gif' => '7890367dfe0e337a2f5f2839b3e6dac7', + './include/SugarObjects/templates/company/icons/Createcompany.gif' => '3978b32e01cbeb974d86b1da0617dae9', + './include/SugarObjects/templates/company/config.php' => '6ae18f6ce9daa6605a8a7b03c48273db', + './include/SugarObjects/templates/company/Company.php' => '193b46d2590072af5ea6b0f694744460', + './include/SugarObjects/templates/basic/vardefs.php' => '706febff3b66254a7244f6bf3b005f12', + './include/SugarObjects/templates/basic/metadata/subpanels/default.php' => '1531d794b6709aeb4a0111d83b786cdb', + './include/SugarObjects/templates/basic/metadata/searchdefs.php' => '77a426e0d55e076a745302a411935d22', + './include/SugarObjects/templates/basic/metadata/quickcreatedefs.php' => 'a55835f923d33db8a0174aad417655a8', + './include/SugarObjects/templates/basic/metadata/popupdefs.php' => 'e498a41b37a1927217dc5f8a12d62de2', + './include/SugarObjects/templates/basic/metadata/metafiles.php' => '73fea3868c8bcddf8e877f902f94fb8f', + './include/SugarObjects/templates/basic/metadata/listviewdefs.php' => '101b945d63217cab64d3942fe6a31973', + './include/SugarObjects/templates/basic/metadata/editviewdefs.php' => '53ebfaff9a10a57b406b778f1b7d889c', + './include/SugarObjects/templates/basic/metadata/detailviewdefs.php' => '3d27bd9aa9f359248caf8c2f44c1ba25', + './include/SugarObjects/templates/basic/metadata/dashletviewdefs.php' => '8480c18ee629a8743d5acf9d793110ec', + './include/SugarObjects/templates/basic/metadata/SearchFields.php' => '6d5cb8f2752706d6e56393c3d3aa870f', + './include/SugarObjects/templates/basic/language/en_us.lang.php' => 'f5baa3b5a84319da06f2c31cf78749a9', + './include/SugarObjects/templates/basic/icons/basic_32.gif' => 'd92dc1c8a1ef6e0351b6948d78bf1436', + './include/SugarObjects/templates/basic/icons/basic.gif' => '75faad9850edd06df55b63abce42d014', + './include/SugarObjects/templates/basic/icons/Createbasic.gif' => 'e25889cd660d838655f5e213fe565f0d', + './include/SugarObjects/templates/basic/Dashlets/Dashlet/m-n-Dashlet.php' => '1891bc6878bb4864ef6135145e5d0908', + './include/SugarObjects/templates/basic/Dashlets/Dashlet/m-n-Dashlet.meta.php' => '75b2139565dc7c4fe4d9d9b8e1973634', + './include/SugarObjects/templates/basic/Basic.php' => 'aae8cc20c1510feac2e68a2d481649eb', + './include/SugarObjects/implements/team_security/vardefs.php' => 'a61bfc389a5f6f58f64a72dca231f50e', + './include/SugarObjects/implements/team_security/language/en_us.lang.php' => 'c00816fcc370c97c6190059119c4c3c0', + './include/SugarObjects/implements/assignable/vardefs.php' => 'f388916ada054d6afa05f954e0a2cd3e', + './include/SugarObjects/implements/assignable/language/en_us.lang.php' => 'e4acab8de35121957fb86900899e0763', + './include/SugarObjects/VardefManager.php' => 'c1f9129f8ab826cda750895e6020ac61', + './include/SugarObjects/SugarSession.php' => '514ac6afae766a48937041187d9c3b49', + './include/SugarObjects/SugarRegistry.php' => '98e36a91582216044880950f43ba725b', + './include/SugarObjects/SugarConfig.php' => 'df914787952d788704ca6a7593f4eb4c', + './include/SugarObjects/LanguageManager.php' => 'f95ebaadc3ed45ceb9fa6b4c41e206bd', + './include/SugarLogger/SugarLogger.php' => '2af3c5f2ad5229e7c55d298e4122b8e3', + './include/SugarLogger/LoggerTemplate.php' => '865497592529cb74a6033a5155f015b0', + './include/SugarLogger/LoggerManager.php' => '62171c14b68db2be07810744dead9519', + './include/SugarFolders/SugarFolders.php' => '4c4eecf343d46449ad4dbb64ac45e52f', + './include/SugarFields/SugarFieldHandler.php' => '5c16ae65725f0cab8b8a498fa7e7dfb5', + './include/SugarFields/Parsers/SearchFormMetaParser.php' => '02267a9149b7e09830109655a8a4b373', + './include/SugarFields/Parsers/Rules/VariableSubstitutionRule.php' => 'da69179d8f94d54dd68c23feafbbc832', + './include/SugarFields/Parsers/Rules/VariableCleanupRule.php' => 'd56cc1194806cb7834ac8da5bd4da03d', + './include/SugarFields/Parsers/Rules/UndefinedVardefRule.php' => 'd303e3e0a83c8f82af8e6277bc78c3a7', + './include/SugarFields/Parsers/Rules/QuotesParseRule.php' => '32459f8e902b11a1424f2f427f9e73bb', + './include/SugarFields/Parsers/Rules/ProductsParseRule.php' => '330054f868b118dfe87182691609a2de', + './include/SugarFields/Parsers/Rules/ParseRules.php' => '1b392485e41dac8da214699f25f740a6', + './include/SugarFields/Parsers/Rules/OpportunitiesParseRule.php' => '6f75e8f0526a85a7e41a3ad6ff9285a4', + './include/SugarFields/Parsers/Rules/NotesParseRule.php' => '7d6c93dd7bd962d66c8c507a2608e40b', + './include/SugarFields/Parsers/Rules/MeetingsParseRule.php' => 'd8a587569f07121db152c3495a4291ee', + './include/SugarFields/Parsers/Rules/LeadsParseRule.php' => 'b763bdd2cda8f7b10be4d6cdb61cab9f', + './include/SugarFields/Parsers/Rules/EmptyRowRule.php' => 'b948020921195b9bdabfcd1e16f823ff', + './include/SugarFields/Parsers/Rules/EmailAddressRule.php' => 'e94c0b9ba67c8df677774114e9bdea4b', + './include/SugarFields/Parsers/Rules/DocumentsParseRule.php' => '64f4ae1336625862068d9e04d3995a2f', + './include/SugarFields/Parsers/Rules/ContractsParseRule.php' => '8b497e91cab35069d0ece860f18a8443', + './include/SugarFields/Parsers/Rules/ContactsParseRule.php' => '13cf473f4fb1429edfed4192ef02b192', + './include/SugarFields/Parsers/Rules/CampaignsParseRule.php' => 'fe8e11b19b0e09f90543014247ea9f50', + './include/SugarFields/Parsers/Rules/CallsParseRule.php' => '82161ac97ae9b06ab3491142eae4ee0f', + './include/SugarFields/Parsers/Rules/BugsParseRule.php' => '903f45dcb27713c8f81d87abc1a0e282', + './include/SugarFields/Parsers/Rules/BaseRule.php' => '453b46f9169f323256157668bb1c5fde', + './include/SugarFields/Parsers/Rules/AddressRule.php' => '2d576b842686df79369ff141554448a0', + './include/SugarFields/Parsers/Rules/ActivitiesParseRule.php' => 'dc3448fde70fb776eabb2fe14e54a364', + './include/SugarFields/Parsers/Rules/AccountsParseRule.php' => 'b61c2fd3ef2f1911e5c80f868d2322f8', + './include/SugarFields/Parsers/QuickCreateMetaParser.php' => '33160aa871736e67ba9f3161770f26a7', + './include/SugarFields/Parsers/MetaParser.php' => 'f4fc34a2e1a360fa03fda3feaf9f7a1d', + './include/SugarFields/Parsers/EditViewMetaParser.php' => '56e8c08febb69176e24e27474efc02a6', + './include/SugarFields/Parsers/DetailViewMetaParser.php' => '067153dd72b6ccead212f5c05989467d', + './include/SugarFields/Fields/Id/SugarFieldId.php' => '4e9671259741f5e9bdad9134536d0b0b', + './include/SugarFields/Fields/Username/SugarFieldUsername.php' => '68b2a346bb6bc9a37fd5997839a3ef22', + './include/SugarFields/Fields/Username/DetailView.tpl' => '265789b155e8f0627ee8f09e7442556a', + './include/SugarFields/Fields/URL/ListView.tpl' => '348cdc6eb954f912b7ad3de52386b044', + './include/SugarFields/Fields/URL/EditView.tpl' => '6c4b5eace8297f1ab1b9a591a996cf53', + './include/SugarFields/Fields/URL/DetailView.tpl' => 'ca276cf6c74d44072082dd4d2bb9df67', + './include/SugarFields/Fields/Text/SugarFieldText.php' => '09062f54c8846717b788223389539921', + './include/SugarFields/Fields/Text/EditView.tpl' => 'c894ddc45353fcbb4bb0ff6ced41dc6a', + './include/SugarFields/Fields/Text/DetailView.tpl' => '569a73fb57f61968c44b8b89d1fa85c8', + './include/SugarFields/Fields/Text/ClassicEditView.tpl' => '64b3798cb9493699ba6753f8d1308800', + './include/SugarFields/Fields/Relate/SugarFieldRelate.php' => '9a4e59ddc32a34efac991a47db3b3330', + './include/SugarFields/Fields/Relate/SearchView.tpl' => '06aa8e553038827a8180f033345d980d', + './include/SugarFields/Fields/Relate/EditView.tpl' => '7104af2a6eb8a8677b8bf8a5129a6efe', + './include/SugarFields/Fields/Relate/DetailView.tpl' => '1d58830f1002d63405955e15402f154f', + './include/SugarFields/Fields/Readonly/SugarFieldReadonly.php' => 'c94a8504b58aa243752d0ea79ba58d35', + './include/SugarFields/Fields/Radioenum/EditView.tpl' => '43624976527f15572ccf9c3e9e913dcf', + './include/SugarFields/Fields/Radioenum/DetailView.tpl' => '40e967a3e3d8d84759ec757e10d87698', + './include/SugarFields/Fields/Phone/SugarFieldPhone.php' => 'e31438e2425b63be6640b3fb4e73d7a5', + './include/SugarFields/Fields/Phone/EditView.tpl' => '9b9ef604b528e14f9e11abbf236de147', + './include/SugarFields/Fields/Password/SugarFieldPassword.php' => 'ce8e8aef9cc8df2b2323402a4b2ff1d6', + './include/SugarFields/Fields/Password/EditView.tpl' => '1edeebd3c8b1ecc3e2c7e85cbe6d082b', + './include/SugarFields/Fields/Parent/SugarFieldParent.php' => '01a9d1328c58c997609e19d4e6a1fad8', + './include/SugarFields/Fields/Parent/SearchView.tpl' => 'bbd6fbd734276c39c8f54ff47d97389f', + './include/SugarFields/Fields/Parent/EditView.tpl' => '38dff65450e0495924448d6ee756aa6b', + './include/SugarFields/Fields/Parent/DetailView.tpl' => '81cf3af6a61d38101e3cfe747dd9a64a', + './include/SugarFields/Fields/Multienum/SugarFieldMultienum.php' => 'a2a08b6a251a8074fece78676e2c6517', + './include/SugarFields/Fields/Multienum/SearchView.tpl' => 'dc5d9652e9a630788ddb7578a850d36c', + './include/SugarFields/Fields/Multienum/ListView.tpl' => '20999318663962eb6e9f9df6c4cc0a93', + './include/SugarFields/Fields/Multienum/EditViewFunction.tpl' => '9f0bd6fbdd370ba799181b420700d690', + './include/SugarFields/Fields/Multienum/EditView.tpl' => 'b76caf30b40ead7e5e77ee385680e623', + './include/SugarFields/Fields/Multienum/DetailView.tpl' => 'b2c0824e4a3585cac4e7dd5b8cbc44fb', + './include/SugarFields/Fields/Link/ListView.tpl' => '3efb0c3d1e5f5f7cc825664416795b6f', + './include/SugarFields/Fields/Link/EditView.tpl' => '13c9dd96fe5d5997ff6626414f51daea', + './include/SugarFields/Fields/Link/DetailView.tpl' => '7cf2bcf75d842bfaf7c2aefe29badd8e', + './include/SugarFields/Fields/Int/RangeSearchForm.tpl' => '7bd5ddf1034ac84f3a76318dc2a08ba7', + './include/SugarFields/Fields/Int/SugarFieldInt.php' => '37b89119cbc9e5654454c94ef9434612', + './include/SugarFields/Fields/Int/SearchForm.tpl' => '49dfd8196ff5a647550a0102ec302b40', + './include/SugarFields/Fields/Int/EditView.tpl' => 'ef85b3701213ec7fbf270b7a652f665b', + './include/SugarFields/Fields/Int/DetailView.tpl' => '2a2e939aa1f46920974d4e55b3e536ed', + './include/SugarFields/Fields/Iframe/EditView.tpl' => 'd932cd74d2aa8f150e05e4fc1842a9ff', + './include/SugarFields/Fields/Iframe/DetailView.tpl' => '166e7c48cf8508bf8475d93e9fa7cc65', + './include/SugarFields/Fields/Html/SugarFieldHtml.php' => '52fbd9c0870c72a93f5ff77fb331b5a5', + './include/SugarFields/Fields/Html/DetailView.tpl' => 'fb7614d8b124259ec226e0419c1de02a', + './include/SugarFields/Fields/Fullname/SugarFieldFullname.php' => '04f64aa66c5bb260769cc0383b82dabd', + './include/SugarFields/Fields/Fullname/DetailView.tpl' => '5013b528be98fb2c5cd89b79a95e7f04', + './include/SugarFields/Fields/Float/SugarFieldFloat.php' => 'cde383c4826dc6789d4564ddf7557f0a', + './include/SugarFields/Fields/Float/EditView.tpl' => '0fb9f47fb2ff78b80b4be921d083c4fa', + './include/SugarFields/Fields/Float/DetailView.tpl' => 'd262f314387c02eea26e73e7b13eeded', + './include/SugarFields/Fields/File/SugarFieldFile.js' => '8235879c29fa930c1b41a9d7a913c4f1', + './include/SugarFields/Fields/File/SearchView.tpl' => '714c86e492dad340a8b6d7fb02402190', + './include/SugarFields/Fields/File/ListView.tpl' => 'e721c525ebe3f10e1d92111f3fa96faf', + './include/SugarFields/Fields/File/SugarFieldFile.php' => '73ba55ea4efb3e5b3fdc67f867e7ca01', + './include/SugarFields/Fields/File/EditView.tpl' => '6809bea5bf1a9d932a44499b807e8a79', + './include/SugarFields/Fields/File/DetailView.tpl' => 'e1a8b7dc324439b6616483c9db5bef54', + './include/SugarFields/Fields/Enum/SugarFieldEnum.php' => 'f20e65f73f58126986b4fdc04a70c3e0', + './include/SugarFields/Fields/Enum/SearchView.tpl' => '0b28499163b68dd7d5830e72420234fd', + './include/SugarFields/Fields/Enum/EditViewFunction.tpl' => '12a4667e9b589c9f765ef85a5caa0a14', + './include/SugarFields/Fields/Enum/EditView.tpl' => 'be6dd8ebec706676b32f71807874426f', + './include/SugarFields/Fields/Enum/DetailViewFunction.tpl' => 'ac68398d2c03f5fd9efe88e63c09115e', + './include/SugarFields/Fields/Enum/DetailView.tpl' => '2202329800d7476db244306c357f8468', + './include/SugarFields/Fields/Download/SugarFieldDownload.php' => '779b5b9abfcae1a71934b838f5eb0799', + './include/SugarFields/Fields/Download/DetailView.tpl' => 'f6d2e5bc05d4918321f840c17e98bbdb', + './include/SugarFields/Fields/Datetimecombo/Datetimecombo.js' => 'e8a30237305aaebef40a69e66f5510df', + './include/SugarFields/Fields/Datetimecombo/RangeSearchForm.tpl' => 'c4dae0f0f5f4e521ce03803e35817204', + './include/SugarFields/Fields/Datetimecombo/SugarFieldDatetimecombo.php' => '19177c0d55dae3f974cb4ad185061208', + './include/SugarFields/Fields/Datetimecombo/SearchView.tpl' => '794430573ea1f10bc910017e977315dd', + './include/SugarFields/Fields/Datetimecombo/EditView.tpl' => 'c07feccf3b23395688857fffd182071f', + './include/SugarFields/Fields/Datetime/SugarFieldDatetime.php' => '795d0c525855ab25231a428879234895', + './include/SugarFields/Fields/Datetime/EditView.tpl' => 'cecc4c2aedea1f00200956b4ce57c382', + './include/SugarFields/Fields/Currency/SugarFieldCurrency.php' => '29694b4b7e7c008b1176898b41603197', + './include/SugarFields/Fields/Currency/ListView.tpl' => 'fa4ab79b0660390d5fbf44f9d69ebea7', + './include/SugarFields/Fields/Currency/EditView.tpl' => 'ec497a7ccc2665af341a4e0b4ba4d00d', + './include/SugarFields/Fields/Currency/DetailView.tpl' => '34e955ee65eb1b10d02b20213d934b61', + './include/SugarFields/Fields/Collection/SugarFieldCollection.js' => '60966b950f10e2f289473c33eb806ddb', + './include/SugarFields/Fields/Collection/view.sugarfieldcollection.php' => 'f58f76131d63b8587d8344e43fe6a713', + './include/SugarFields/Fields/Collection/ViewSugarFieldCollection.php' => '799f44cc04c8f8c693c10c998bf47a83', + './include/SugarFields/Fields/Collection/SugarFieldCollection.php' => '445a08388c087f5c8346430087a76a3c', + './include/SugarFields/Fields/Collection/EditView.tpl' => '8be320b6638a81aeaf0dae3200eeee96', + './include/SugarFields/Fields/Collection/DetailView.tpl' => '5847e6e86b00ce6911f5f0efbb143bd8', + './include/SugarFields/Fields/Collection/CollectionEditViewRow.tpl' => '550c330e047e904e1681d403f0075c45', + './include/SugarFields/Fields/Collection/CollectionEditView.tpl' => '92dbf9dccbead9ce2d506e87572e3a40', + './include/SugarFields/Fields/Collection/CollectionDetailView.tpl' => '89e4fa568874dafc3b7c84bf98ad6b67', + './include/SugarFields/Fields/Bool/SugarFieldBool.php' => 'a218eca4959d94b5701a327d941c3714', + './include/SugarFields/Fields/Bool/SearchView.tpl' => '5ba5e1bec319cc466c2bf8c5c6f36bcd', + './include/SugarFields/Fields/Bool/ListView.tpl' => '2cf9cfe7f0224625a9db87a55c862066', + './include/SugarFields/Fields/Bool/InlineEditView.tpl' => 'fc9ecf7e13414039acd38b619b3e5400', + './include/SugarFields/Fields/Bool/InlineEdit.tpl' => '2c1e27debc2a992ca2f8a41ea01a0600', + './include/SugarFields/Fields/Bool/EditView.tpl' => '20c4753b0534a3bdbc22ae54ba629301', + './include/SugarFields/Fields/Bool/DetailView.tpl' => 'a3b5e1308c6b998830711c3a7581bec1', + './include/SugarFields/Fields/Base/ImportViewFunction.tpl' => '3dcc32cf3cbf29446433bd3a807fa168', + './include/SugarFields/Fields/Base/SugarFieldBase.php' => 'cec1d8e7ac97a0095cdc22cb71ae8bce', + './include/SugarFields/Fields/Base/SearchForm.tpl' => '5a526a4a1d48dcb1c53cd1bc725ee24b', + './include/SugarFields/Fields/Base/ListView.tpl' => '23022cb491510574c46d3a985524d4f2', + './include/SugarFields/Fields/Base/InlineEditView.tpl' => 'cad6ed8451a2f8bfe93a12c7a9e226ca', + './include/SugarFields/Fields/Base/InlineEdit.tpl' => 'd8c88cc70bfa8e746acc23cb9431dcea', + './include/SugarFields/Fields/Base/EditViewFunction.tpl' => '3dcc32cf3cbf29446433bd3a807fa168', + './include/SugarFields/Fields/Base/EditView.tpl' => 'f1c6961334f3242047b999020fabdb09', + './include/SugarFields/Fields/Base/DetailViewFunction.tpl' => '424ee8062ffb12e2aa32f711268229bc', + './include/SugarFields/Fields/Base/DetailView.tpl' => 'fc7c2563d528bbbc328f60fd9e39e089', + './include/SugarFields/Fields/Assigned_user_name/EditViewFunction.tpl' => '69fca202aeeb72fd5617e20d560631c3', + './include/SugarFields/Fields/Assigned_user_name/SugarFieldAssigned_user_name.php' => 'b2ba2feaf8b1db87700965a6314cf656', + './include/SugarFields/Fields/Assigned_user_name/SearchView.tpl' => 'a98eb4befbdcb21fc499f0fa975f8a1a', + './include/SugarFields/Fields/Address/SugarFieldAddress.js' => 'afd9583270e6a2eac3bf72c308f09183', + './include/SugarFields/Fields/Address/en_us.EditView.tpl' => '6a840da6d8a18eb6d11393d73670932b', + './include/SugarFields/Fields/Address/en_us.DetailView.tpl' => '5bf7266e333859717d82eadb479f13b9', + './include/SugarFields/Fields/Address/SugarFieldAddress.php' => '6ae12612bffcfa91e88b72a17622ec36', + './include/SugarFields/Fields/Address/EditView.tpl' => '6a840da6d8a18eb6d11393d73670932b', + './include/SugarFields/Fields/Address/DetailView.tpl' => 'cda7b5ebe9f6fdc86850509718024d8e', + './include/SugarEmailAddress/SugarEmailAddress.js' => 'd7aa1b86fa26ed7d9d10d63d6d540270', + './include/SugarEmailAddress/templates/forWideFormBodyView.tpl' => 'f553c5c7e78e1eac9f28d8193d000d1b', + './include/SugarEmailAddress/templates/forEditView.tpl' => 'a017738db1cb591c8215e7e01c6f1c39', + './include/SugarEmailAddress/templates/forDuplicatesView.tpl' => '09f861c23cd12077f050e3079af3d23f', + './include/SugarEmailAddress/templates/forDetailView.tpl' => 'c482472d715f94594f4c5b0dc1d46557', + './include/SugarEmailAddress/SugarEmailAddress.php' => 'bb09409a336736629f0fdc95ba3bcba1', + './include/SugarDependentDropdown/metadata/dependentDropdown.php' => 'ad07b642238039f6dd8b366019feca3c', + './include/SugarDependentDropdown/javascript/SugarDependentDropdown.js' => 'b5f8625205567f3d436ce7182375c881', + './include/SugarDependentDropdown/SugarDependentDropdown.php' => 'ac4385687c68504d233e39a1c13b89ea', + './include/SugarCharts/swf/barChart.swf' => 'e024c31bfcaa90fa3a54809a8c65861c', + './include/SugarCharts/swf/chart.swf' => 'afda6fe91342c4864d1991d3c1ccbfff', + './include/SugarCharts/swf/groupByChart.swf' => '2eca03fe41128001349bacf997b1fedc', + './include/SugarCharts/swf/horizontalBarChart.swf' => 'f3b95d3dc4f268ed9cf4b388c6c3b4a8', + './include/SugarCharts/swf/horizontalGroupByChart.swf' => '7f611d0a68d18d72ad7cde6e525449d9', + './include/SugarCharts/swf/lineChart.swf' => 'e4b6eef95ff87f5e1b36cdfe74966ddd', + './include/SugarCharts/swf/pieChart.swf' => 'c8a528dc470ac904864ea88549b3adc9', + './include/SugarCharts/swf/stackedGroupByChart.swf' => '0d524ea04b2c56d1c7cdc86194f59ed1', + './include/SugarCharts/SugarChartFactory.php' => 'c12c6dddeeff4a0b91d2bd436c305e57', + './include/SugarCharts/JsChart.php' => 'a47703d7cebaed44448d0c11475411d1', + './include/SugarCharts/Jit/tpls/chart.tpl' => 'db663713468e49441f7fc6c0ccafab54', + './include/SugarCharts/Jit/tpls/DashletGenericChartScript.tpl' => '669af80b8d685e3a7184a54e0c0e3141', + './include/SugarCharts/Jit/js/mySugarCharts.js' => '365b6a9f00fd025442ed582dd7e9c557', + './include/SugarCharts/Jit/js/sugarCharts.js' => 'dc7b0776216db012d32e96d9b23d7745', + './include/SugarCharts/Jit/js/Jit/jit.js' => 'fcff6ed6bcecfc5f8a36a053089c33d3', + './include/SugarCharts/Jit/css/base.css' => '8ce4e603ad49e48925a013c9ad565e52', + './include/SugarCharts/Jit/JitReports.php' => 'a41d2f8c71fb1691c9af14590122fa2e', + './include/SugarCharts/Jit/Jit.php' => '3079c345047407c2d3ab746241927682', + './include/SugarCharts/Jit/FlashCanvas/canvas2png.js' => '71a23466955e17ab3094233fee8db708', + './include/SugarCharts/Jit/FlashCanvas/flashcanvas.js' => '8bc523ae2dce6eb2d191cbb561a218b5', + './include/SugarCharts/Jit/FlashCanvas/save.php' => 'b128689255043db993d1cc2f4bc484bc', + './include/SugarCharts/Jit/FlashCanvas/proxy.php' => '82ccbc7400b0bda3a33316920de41e60', + './include/SugarCharts/Jit/FlashCanvas/flashcanvas.swf' => '528d82bb81799f23d4def3425badf913', + './include/SugarCharts/SugarChart.php' => 'aa23b4fac128341d6112ba185003a08a', + './include/SubPanel/SubPanelTiles.js' => 'ea6a4b3add603885bbe3100d62d36c40', + './include/SubPanel/tpls/singletabmenu.tpl' => '3070f73cc977481a36dbb69ad8f4e23a', + './include/SubPanel/subpanels.txt' => '754316b019dc694b893e830ffe65f49d', + './include/SubPanel/registered_layout_defs.php' => '6784a47eba53d5940d743958bfd1cef5', + './include/SubPanel/SugarTab.php' => 'b401ecf5483d99d56f12d1ff91edf97c', + './include/SubPanel/SubPanelViewer.php' => '2ee30a85709d5abe7bc8e203721d5b68', + './include/SubPanel/SubPanelTilesTabs.php' => '3a7a49c6dbcab329119c74aa96833ae9', + './include/SubPanel/SubPanelTiles.php' => '174bac5837e8db811f8eb691c2dc1395', + './include/SubPanel/SubPanelDynamic.html' => '73e24930846c23f2cedb379ce9053a5e', + './include/SubPanel/SubPanelDefinitions.php' => 'b4e34f38b2c722ad4a143092da5cdc66', + './include/SubPanel/SubPanel.php' => '2eb2ebfb7b6dfd3b067a44d5be750a91', + './include/Smarty/plugins/shared.make_timestamp.php' => '2d98e1b8ae60c93316d90bf152d3f5a5', + './include/Smarty/plugins/shared.escape_special_chars.php' => '1a8d89273862e174b64f683d42feb198', + './include/Smarty/plugins/outputfilter.trimwhitespace.php' => '25a2cdd916bf01bb8caa45a23fdf8d63', + './include/Smarty/plugins/modifier.wordwrap.php' => 'a3478828dc04f5e653d8cf004a8ce374', + './include/Smarty/plugins/modifier.upper.php' => 'dd90f6658466a3f98f935e6556bbcac1', + './include/Smarty/plugins/modifier.truncate.php' => 'b9b8d28ba0af5e060fc7e002b37f9518', + './include/Smarty/plugins/modifier.to_url.php' => '85bfd4db53ca9e701791f0559b7de44b', + './include/Smarty/plugins/modifier.strip_tags.php' => '8f98de4ecc0f3380d36943b0716edae9', + './include/Smarty/plugins/modifier.strip_semicolon.php' => '716963b69fd6281457d284e19c73dd62', + './include/Smarty/plugins/modifier.strip.php' => 'd37cbead10b238172272e54a5cd9c691', + './include/Smarty/plugins/modifier.string_format.php' => '916e60af3846575f2f0b70db2d25ba98', + './include/Smarty/plugins/modifier.spacify.php' => 'caaa7bc654d20b7a34670ffaf4810a16', + './include/Smarty/plugins/modifier.replace.php' => '5bb1e3d534891f79a09a36aee97b16d5', + './include/Smarty/plugins/modifier.regex_replace.php' => '20d7768bb576dbe28790e0d28124b1f9', + './include/Smarty/plugins/modifier.nl2br.php' => '2365291cea2e3cde544dc151bd62c662', + './include/Smarty/plugins/modifier.lower.php' => '014241bdc9356e4db65ff84902e868d2', + './include/Smarty/plugins/modifier.indent.php' => 'ee36b10a3f19acbdd06a6bd9185e62ab', + './include/Smarty/plugins/modifier.in_array.php' => 'f5aabe01841e76d205eec79f091ded5f', + './include/Smarty/plugins/modifier.escape.php' => 'aae08c2908d653176d5cdcdae0a8cd97', + './include/Smarty/plugins/modifier.default_date_value.php' => '6c4f7433ed3982422e83736ac0e1fc50', + './include/Smarty/plugins/modifier.default.php' => '0fe3023b34a89cb5f9168c558fc7cdaa', + './include/Smarty/plugins/modifier.debug_print_var.php' => '681a55a868dbeb1fb6ebcd993be9ed40', + './include/Smarty/plugins/modifier.date_format.php' => '779b980e5296f6e0814b26940c69afb8', + './include/Smarty/plugins/modifier.count_words.php' => '25b752b87368fafa7f66e4811f7f223e', + './include/Smarty/plugins/modifier.count_sentences.php' => 'ce2aa6fd44be95bbca2f9fa405184476', + './include/Smarty/plugins/modifier.count_paragraphs.php' => '094571a25323b4a624339c510c235e23', + './include/Smarty/plugins/modifier.count_characters.php' => '37fa5004b6d5f74dc05833658577e99a', + './include/Smarty/plugins/modifier.cat.php' => '0bdc246da1c7628c41296b51705ef4cf', + './include/Smarty/plugins/modifier.capitalize.php' => 'b6bcbaf3b0c8770898148e483a223c7e', + './include/Smarty/plugins/function.sugarvar_connector.php' => 'c84020dc3c970932cb3f4cc21ce10dfd', + './include/Smarty/plugins/function.sugarvar.php' => '5e7f2cf7aa362630648ce79689c643a9', + './include/Smarty/plugins/function.sugar_variable_constructor.php' => '6561cdb5987f989d18090a4713c9a27a', + './include/Smarty/plugins/function.sugar_translate.php' => 'b52ec4b3da8315a561df668fdfa82a1a', + './include/Smarty/plugins/function.sugar_run_helper.php' => '2118a0bb279e18aae2b0fe9237e6ba6d', + './include/Smarty/plugins/function.sugar_replace_vars.php' => 'a72d58f8842fcd9b39126d6324f1157a', + './include/Smarty/plugins/function.sugar_phone.php' => 'b4780a38d9fdd3a0d44bbc8e5a8c21aa', + './include/Smarty/plugins/function.sugar_number_format.php' => '11a1900821c4ba7b1621f2ee39a69aa2', + './include/Smarty/plugins/function.sugar_link.php' => '2424db7b435a5a5db2fe2fce0e1489cf', + './include/Smarty/plugins/function.sugar_include.php' => '7129e4a4c3b856917d352e62783f67ac', + './include/Smarty/plugins/function.sugar_image.php' => '711ae380835a8819e08757aed10fcaee', + './include/Smarty/plugins/function.sugar_help.php' => '70afb79935fed0839b175dcb90defd77', + './include/Smarty/plugins/function.sugar_getwebpath.php' => '42a9c08d0104dc9e692ace8e5361fdd1', + './include/Smarty/plugins/function.sugar_getjspath.php' => '57012e520ede6460a5246cb49dd6ce16', + './include/Smarty/plugins/function.sugar_getimagepath.php' => 'f95c722408c0860608c3cfdaf41ca57c', + './include/Smarty/plugins/function.sugar_field.php' => 'c91e8279c69999e11a36c96adb838839', + './include/Smarty/plugins/function.sugar_fetch.php' => '6fd07816cbba8003cdb31d3ee067271f', + './include/Smarty/plugins/function.sugar_evalcolumn_old.php' => '85b786307307859d4221cf32466d7893', + './include/Smarty/plugins/function.sugar_evalcolumn.php' => '59740a8d35e31740068ffd7e82067e4c', + './include/Smarty/plugins/function.sugar_currency_format.php' => '328379f1c05a4e8e60d640ce4fc8cb15', + './include/Smarty/plugins/function.sugar_connector_display.php' => '266cbf9b85deea2b1aa7407ca46f069d', + './include/Smarty/plugins/function.sugar_button_slider.php' => '6152ab8014fecf6fa1b6af75c28af497', + './include/Smarty/plugins/function.sugar_button.php' => '04e4e9f30503a9b62ba91c505c2620ca', + './include/Smarty/plugins/function.popup_init.php' => 'bbf08a63f3a1ae2679b324d23cfce520', + './include/Smarty/plugins/function.popup.php' => 'cf231d09647d1b1cf0adf5904b66b6a6', + './include/Smarty/plugins/function.overlib_includes.php' => 'a9ebdebac2bff90663da6090767b3f39', + './include/Smarty/plugins/function.multienum_to_array.php' => '402c543b8c0179e5e8f712dc304bf891', + './include/Smarty/plugins/function.math.php' => '99aa00ff372550f12df400da784ebab4', + './include/Smarty/plugins/function.mailto.php' => '5ba678549af1712ff9e64c244a8806c1', + './include/Smarty/plugins/function.html_table.php' => '2931b5dd6b495a332f4074094f6c1534', + './include/Smarty/plugins/function.html_select_time.php' => '780246c13ff291a61a80e69a12690e4a', + './include/Smarty/plugins/function.html_select_date.php' => 'ec3b1e591143de9dda0bf4c35bb6bf4c', + './include/Smarty/plugins/function.html_radios.php' => 'dde3b081e27db52945838e1f52a24714', + './include/Smarty/plugins/function.html_options.php' => 'a7903c34c86b166373946497fac2b7bb', + './include/Smarty/plugins/function.html_image.php' => '06abba1563143b4b1190ca07d53b0a0d', + './include/Smarty/plugins/function.html_checkboxes.php' => 'b1ca393b03bb49f580bef620db8727cb', + './include/Smarty/plugins/function.fetch.php' => '23aea2dfaba739298fe7ed0fa667efdb', + './include/Smarty/plugins/function.ext_includes.php' => 'e75b10578a7963fbd221d0e823471bc7', + './include/Smarty/plugins/function.eval.php' => '21a9230b569490f28ea9d67b1741ca89', + './include/Smarty/plugins/function.debug.php' => 'f1e71b56fc00f6de299f92571a8f6638', + './include/Smarty/plugins/function.cycle.php' => 'b15976e5809f951353857f490f65661e', + './include/Smarty/plugins/function.counter.php' => '73d05c9943053b38780e3bb86bf74fd2', + './include/Smarty/plugins/function.config_load.php' => '752a15886ca6ee831f2ab650ab09fe4e', + './include/Smarty/plugins/function.assign_debug_info.php' => '47b6d1f6e8411637af71925793a97efc', + './include/Smarty/plugins/compiler.assign.php' => 'e77d210e1f8aceff7f7bd67b1d25b28f', + './include/Smarty/plugins/block.textformat.php' => 'b0bebaca5693c6baf9332d22d6fbd1d1', + './include/Smarty/internals/core.write_file.php' => 'e624cf8490354f89340ba77c4d845519', + './include/Smarty/internals/core.write_compiled_resource.php' => '797244610368f0b276b4ecd743086f6b', + './include/Smarty/internals/core.write_compiled_include.php' => '93584e495a0bfb25f946f20f459889fb', + './include/Smarty/internals/core.write_cache_file.php' => '3347fa035bd907e7ea032ef4b745c0da', + './include/Smarty/internals/core.smarty_include_php.php' => '0f20b03f57483da2ede06ef900586bed', + './include/Smarty/internals/core.run_insert_handler.php' => '0cddac7a6aaf1b4fa18abe44eeb6c807', + './include/Smarty/internals/core.rmdir.php' => '2ecc86dd2fa40ed875c8273db17b4406', + './include/Smarty/internals/core.rm_auto.php' => '38cc535c939220b688d87884935395c1', + './include/Smarty/internals/core.read_cache_file.php' => '335015690743693e69b61d5bd52ae729', + './include/Smarty/internals/core.process_compiled_include.php' => 'da68a35662d0484b19c3637e2b625895', + './include/Smarty/internals/core.process_cached_inserts.php' => '9bfff97b0eb3f1fd2e416c536bac19c9', + './include/Smarty/internals/core.load_resource_plugin.php' => '66b72ff2bdb55f460e439cc07acd367e', + './include/Smarty/internals/core.load_plugins.php' => '4bc662697a0b10387d98685eabbb9faa', + './include/Smarty/internals/core.is_trusted.php' => '5dbc0bf6ad82123f09634397b436e4cb', + './include/Smarty/internals/core.is_secure.php' => '4c329afe681f1aad25b2bcce92dd520f', + './include/Smarty/internals/core.get_php_resource.php' => '0404f718f426d1e4e72ec43452b89ece', + './include/Smarty/internals/core.get_microtime.php' => '44d5bb49946bb2c4204494776324d673', + './include/Smarty/internals/core.get_include_path.php' => '1d5941075543a345c0c217d09d6b9a97', + './include/Smarty/internals/core.display_debug_console.php' => 'e9e81d5f37a8507d324e5bce83c34d04', + './include/Smarty/internals/core.create_dir_structure.php' => 'c8b9a192b7da5dd1a0ffa5a15b230eed', + './include/Smarty/internals/core.assign_smarty_interface.php' => 'c9d0bd78f9fee26105a2df3fbbca93e1', + './include/Smarty/internals/core.assemble_plugin_filepath.php' => 'a28fae766fb2a8ecc45b8c6fc4c35e76', + './include/Smarty/debug.tpl' => '048f29488fb3da08b3fcc5a746489696', + './include/Smarty/Smarty_Compiler.class.php' => 'b9a859a96c0d005cee69253bac461599', + './include/Smarty/Smarty.class.php' => '44dbf7377bba64c38900cc56d6b0b5b7', + './include/Smarty/README' => '1a3fe37eed420a020489d1082ea150c8', + './include/Smarty/LICENSE' => '8c2e1ec1540fb3e0beb68361344cba7e', + './include/Smarty/Config_File.class.php' => '8852379ae39541f5e3355591ee0bfa03', + './include/Smarty/COPYING.lib' => '8c2e1ec1540fb3e0beb68361344cba7e', + './include/SearchForm/tpls/header.tpl' => '66a8fd41e599af7cdaddbf5ec6ddc6e7', + './include/SearchForm/tpls/footer.tpl' => '63029c5d9fb81f706b61e346fd237254', + './include/SearchForm/tpls/SearchFormGenericAdvanced.tpl' => '6c503de6635ffff0d7a3cf913add9a70', + './include/SearchForm/tpls/SearchFormGeneric.tpl' => 'f4cee5cd0a6f267f23d3b493fbc05c8f', + './include/SearchForm/SugarSpot.php' => '59b4acdf92ea5e88bdc62a9eda76aada', + './include/SearchForm/SearchForm2.php' => '566b757e9259eb6b33a7d5be61d293e2', + './include/SearchForm/SearchForm.php' => '18fa71b0f4d20ec60fc9f907009a2dc3', + './include/QuickSearchDefaults.php' => '674dd947d5a73cbb7f671dc0c70326ee', + './include/Popups/tpls/header.tpl' => '100057ca98c7ac829a36cebd232c6bd3', + './include/Popups/tpls/footer.tpl' => 'e973a29e7d29e9ab18a1c41bf6a0318e', + './include/Popups/tpls/PopupGeneric.tpl' => 'bfe6dcbb71e502382816288507264a62', + './include/Popups/Popup_picker.php' => '5778cbee0092c9812b687180ac9c3dcf', + './include/Popups/PopupSmarty.php' => '47845112dc6f4561a1b414b345a9cdf5', + './include/Pear/XML_HTMLSax3/LICENSE' => 'a45bb1bbeed9e26b26c5763df1d3913d', + './include/Pear/XML_HTMLSax3/HTMLSax3/States.php' => '5b528baa84631f85349a7183597d2fb3', + './include/Pear/XML_HTMLSax3/HTMLSax3/Decorators.php' => '34a9a95566c891f013584073fbadaf7e', + './include/Pear/XML_HTMLSax3/HTMLSax3.php' => '11107d97b19feb13feb394cd858603f0', + './include/Pear/HTML_Safe/license.txt' => 'a9001003ee71c8e4ca0337600994e7ac', + './include/Pear/HTML_Safe/Safe.php' => 'fdcbdcb1ba1a71e3ce7432ca04e4b853', + './include/Pear/Crypt_Blowfish/license.txt' => 'a45bb1bbeed9e26b26c5763df1d3913d', + './include/Pear/Crypt_Blowfish/Blowfish/DefaultKey.php' => '8274b556662cc178342ea96940b36514', + './include/Pear/Crypt_Blowfish/Blowfish.php' => 'b391980575340d0fe5bf2df72bc13932', + './include/OutboundEmail/OutboundEmail.php' => 'c502e2caaeaa94b514dd2a14f791745e', + './include/MySugar/tpls/retrieveReportCharts.tpl' => '72c137f9c8df056f8ec6ffaf01aa3bd6', + './include/MySugar/tpls/retrievePage.tpl' => 'aba0b602f74d0f8d420af10fdfd703be', + './include/MySugar/tpls/dashletsSearchResults.tpl' => '1f101a6547e7bd0653cc47fbcb5ac90a', + './include/MySugar/tpls/chartDashletsSearchResults.tpl' => '67fc336767e4e9048e4d59905257b443', + './include/MySugar/tpls/addDashletsDialog.tpl' => '7c87bb1474e1a740c12245c5396efc6f', + './include/MySugar/tpls/MySugar.tpl' => '931e27d4210d26221451f428119e43cd', + './include/MySugar/javascript/MySugar.js' => '78e42672503843e14f0c3195a558d87f', + './include/MySugar/MySugar.php' => 'eeaf9f743996136c20d8b666ecbd8994', + './include/MySugar/DashletsDialog/DashletsDialog.php' => 'e744aa3227983c1359009470bca4efd4', + './include/MassUpdate.php' => '40ff490a2fd6d983c14187bca22cdbea', + './include/MVC/View/views/view.xml.php' => '899ce32b620a040d2f04dd32bf32cd6d', + './include/MVC/View/views/view.vcard.php' => '3b04600e1920cef4e3d6b74e26c0e386', + './include/MVC/View/views/view.sugarpdf.php' => 'fffb5f92357ed83e618ccf726747443e', + './include/MVC/View/views/view.sugarpdf.config.php' => 'f2e716a709d667779fae8f7339a41f8f', + './include/MVC/View/views/view.serialized.php' => '419a311f5b59f154f53c683f56863a5f', + './include/MVC/View/views/view.quickcreate.php' => 'b130d5c1db8f57870ce01a33bdbe6664', + './include/MVC/View/views/view.quick.php' => 'd9fb0ab43dc329674181db536fc738a3', + './include/MVC/View/views/view.popup.php' => 'de27b3d994b115c78c34444e91c1854f', + './include/MVC/View/views/view.noaccess.php' => '97a35342d7a3eed867b1bdbaea229fcd', + './include/MVC/View/views/view.multiedit.php' => '5e113a540d3bbac4d7329b1c6b808377', + './include/MVC/View/views/view.modulelistmenu.php' => 'e903cb33f76f8e66c57ff218698a6a9b', + './include/MVC/View/views/view.list.php' => '3da830a3debfd98e6d0f46f8c463366a', + './include/MVC/View/views/view.json.php' => '860bdf32d8d0c5e223f7d54c41ae017e', + './include/MVC/View/views/view.importvcardsave.php' => '41068e4fead26d11306ed9de7f03a12b', + './include/MVC/View/views/view.importvcard.php' => '63a6f9060dd84fdd9970e34c31857b6f', + './include/MVC/View/views/view.html.php' => 'b0b55af897d4035b5fade1506d6d8db5', + './include/MVC/View/views/view.edit.php' => '0c3e2cf6a1d4da57feac747562bfcb76', + './include/MVC/View/views/view.detail.php' => '8270e3714b50f262b5e6b71418655278', + './include/MVC/View/views/view.config.php' => '3ed505354fa6e7c166ab25cd5244426d', + './include/MVC/View/views/view.classic.php' => 'f42a4229cbdc0234d839e0ea7f2b592d', + './include/MVC/View/views/view.classic.config.php' => 'a24241005a762569f3a5b0e2c906b0cc', + './include/MVC/View/views/view.ajax.php' => 'e5efe32ce8532928396be74f1d2f39a3', + './include/MVC/View/tpls/xsrf.tpl' => '779535fac8004ae61d70a9fb2141e7df', + './include/MVC/View/tpls/modulelistmenu.tpl' => '30e9e17ede95641e61d081bdc55bbf1b', + './include/MVC/View/tpls/Importvcard.tpl' => '76a9b0c70a3b0a143ea483481a11458b', + './include/MVC/View/ViewFactory.php' => 'c7ebee5efbeae00db163c01401ba28e8', + './include/MVC/View/SugarView.php' => '6f087797e1a4bc67abb8c17fcae9aac1', + './include/MVC/SugarModule.php' => '549e85c67ab4e6e4298976410b9fa0e4', + './include/MVC/SugarApplication.php' => 'a3309d3aa416fd21e33df4ab636929ae', + './include/MVC/Controller/file_access_control_map.php' => 'e04c44c836810acfbc21c7ffb10f00d6', + './include/MVC/Controller/entry_point_registry.php' => '63da395b9079b223b4a921ee0d1af7c9', + './include/MVC/Controller/action_view_map.php' => 'f86f9461f69d408db31d4c726c53bc9e', + './include/MVC/Controller/action_file_map.php' => '5a5579b9cee401b91d6d421cf6f95576', + './include/MVC/Controller/SugarController.php' => '4efe413ff1a79f05c2f8fa7782c610dc', + './include/MVC/Controller/ControllerFactory.php' => '0df016a533ab996705d00d709c65c353', + './include/Localization/Localization.php' => '233e770470587ab67c7cf6a3fdffa9b3', + './include/ListView/ListViewDCMenu.tpl' => '2f65467af069a9497f43f09e020b797d', + './include/ListView/ListViewXTPL.php' => '1565e08d5508441d4fc6528e41dda507', + './include/ListView/ListViewSmarty.php' => '072e1dc0db96f0272ca30be6a96fb49e', + './include/ListView/ListViewPagination.tpl' => 'bab0422f5ab27b8c37fd10cf45b5f910', + './include/ListView/ListViewNoMassUpdate.tpl' => 'eed55b49e2b787d71106e4e54d30f45f', + './include/ListView/ListViewGeneric.tpl' => '9ffc51d5bb72ac1eb186dc4d9696b57c', + './include/ListView/ListViewFacade.php' => '09ab474e08eb514a7fe506b6faa3abae', + './include/ListView/ListViewDisplay.php' => 'a814a93190a4442eeb8c78278608a218', + './include/ListView/ListViewData.php' => 'd3842252060a33a735401eb6476e8486', + './include/ListView/ListView.php' => '9f6e57223e08b58929c6b9899a87e700', + './include/JSON.php' => 'e5d193ad3ae6461e297797e204e99e46', + './include/HTTP_WebDAV_Server/license.txt' => 'a45bb1bbeed9e26b26c5763df1d3913d', + './include/HTTP_WebDAV_Server/dav.txt' => 'c5235ed64efa685da638c6dcdb6a9708', + './include/HTTP_WebDAV_Server/Tools/_parse_proppatch.php' => '70971e2e4a07137ef26d6f4777194a9c', + './include/HTTP_WebDAV_Server/Tools/_parse_propfind.php' => 'a714317051491612e3d70d066e18b7b6', + './include/HTTP_WebDAV_Server/Tools/_parse_lockinfo.php' => 'bf062d20864aa65ad832b96961b90b01', + './include/HTTP_WebDAV_Server/Server.php' => '85e6613006abbd02d316572254f9f97f', + './include/HTTP_WebDAV_Server/README' => 'e6f0ca3d7e4fa2b20310995f269c3ef2', + './include/GroupedTabs/GroupedTabStructure.php' => '40657e2a1b291caa5868b843bc683eec', + './include/EditView/header.tpl' => '13b6c6dcd13b71ea8e0f70b4cc544b09', + './include/EditView/footer.tpl' => 'ecd19cb2e11819d8fd4e6002da1e50a9', + './include/EditView/SugarVCR.php' => 'da2c12eea813bacc8d6f004e01fdad09', + './include/EditView/SubpanelQuickCreate.php' => '12637ec7294ec293924c9bd8a4980d8b', + './include/EditView/QuickCreate.tpl' => 'db1d0c687df9587bba18ed50015e7c00', + './include/EditView/QuickCreate.php' => '785ea6d1ee8a781c3be2caa6ad8e6f18', + './include/EditView/PopupQuickCreate.php' => '337f225f03fc21c831155bbaf984125a', + './include/EditView/EditView2.php' => 'dc8f8ab0999c20c65c3ef0c47f27c7d1', + './include/EditView/EditView.tpl' => '2414bcf1a7e7618a1ef5008ee4c9fca8', + './include/EditView/EditView.php' => '0c0e9448689883c371cca32397e79ec8', + './include/DetailView/header.tpl' => '09b011bb23a5b632218aeaf00ca03d0f', + './include/DetailView/footer.tpl' => '3c66d5fab6cadba3277505554b234ae9', + './include/DetailView/DetailView2.php' => '5438db41056ed8f5a6cb6828e2828818', + './include/DetailView/DetailView.tpl' => '87c2b8ef3017ce19626f750f4e49a0c9', + './include/DetailView/DetailView.php' => 'edba64550e8750167aeca183f0917c52', + './include/Dashlets/DashletGenericAutoRefreshDynamic.tpl' => 'cf058a5e3ebf1467326a8b6cac9d8394', + './include/Dashlets/DashletGenericDisplay.tpl' => '0789f0bfd1de579ce83bdf4895665056', + './include/Dashlets/DashletGenericConfigure.tpl' => 'e0b44a273303bed6eaee040a78762d2d', + './include/Dashlets/DashletGenericAutoRefresh.tpl' => '4fb7e5de13f7f786557453913973dad8', + './include/Dashlets/DashletGenericChartConfigure.tpl' => 'acc6b9ec91ce12ef66209851f924473c', + './include/Dashlets/DashletGenericChart.php' => 'c076507694384a248687e95224cf78fe', + './include/Dashlets/DashletGeneric.php' => '740d2e86717fd9769dc16b7554c785be', + './include/Dashlets/DashletCacheBuilder.php' => '2450bc0178c619d93dfa457795a6fa31', + './include/Dashlets/Dashlet.php' => '4e97d5df8cdd4337913e1df1c7dc5977', + './image.php' => '9b23aefc874f7518e0f8c32c8ea53711', + './json_server.php' => '336652fc4e8c10c12889751f7fd64b3a', + './examples/SoapTestPortal2.php' => '1df38f1a9deb711ac020176352775ea8', + './examples/SoapTestPortal.php' => '2d5550a7519f3ef62c445673df39077c', + './examples/SoapTest.php' => 'f026c807b4bdc6c0c4b177f82f5cbcd8', + './examples/ProgressBarTest.php' => 'eb3f978a9d71831cd893e79935867ea1', + './examples/FormValidationTest.php' => 'a9369a5e1d04c7394ab652339abec6da', + './examples/ExampleLeadCapture.php' => '5427510db86ff439c9345bd3673c7173', + './examples/EXAMPLES_README.txt' => 'b55744b5e2684d91f6d3f98db4553673', + './emailmandelivery.php' => 'c48b3d73c8359b341ce50b1963847944', + './download.php' => '3751125d0074b4ecb4ba8f0b3aa3f6d9', + './dictionary.php' => 'e4e8f9cad5a1e40989cfb246d5f8f99b', + './Zend/Version.php' => '7ed9dea03172b0f8fb11f085a17f100b', + './Zend/Validate/Ip.php' => '05326c26a0f419d8dac8c168f6cb7f12', + './Zend/Validate/Interface.php' => 'e4740491b21885d7439b9df6fd669288', + './Zend/Validate/Hostname/Jp.php' => '8edee6d942534ea8037ceb6f23640d5c', + './Zend/Validate/Hostname/Com.php' => '19562d7628ecd73ac147577b96eb8641', + './Zend/Validate/Hostname/Cn.php' => '326faf778c688e6bee5ce0fe006d46a9', + './Zend/Validate/Hostname/Biz.php' => 'ee5319555a6d9089848846b7dece3326', + './Zend/Validate/Hostname.php' => '6e2caae3fccade0947ef2f55fa1db12a', + './Zend/Validate/Abstract.php' => '0e617afaf441ae142ca03eea964e1afc', + './Zend/Uri/Http.php' => 'c7f0cddbf8f25abf27870f055f6a3233', + './Zend/Uri/Exception.php' => 'd887f44a926f35ceb936871537dc5ac8', + './Zend/Uri.php' => 'cde07c0e943c7cda721794d3df422f72', + './Zend/Registry.php' => '56b05bc37aa19203e114fe93782b33b0', + './Zend/Oauth/Token/Request.php' => 'affe7ec2aa5d5213c04faefd241658fe', + './Zend/Oauth/Token/AuthorizedRequest.php' => '89fbdd54439eb00ab07d6cdfee9c230e', + './Zend/Oauth/Token/Access.php' => '3f0660a492b66f94342ab3a0db44869d', + './Zend/Oauth/Token.php' => '66c75d877789a6c9f76fcb56eca8f69f', + './Zend/Oauth/Signature/SignatureAbstract.php' => 'd44f7c92c85ba7915a6774e78f426b1c', + './Zend/Oauth/Signature/Rsa.php' => '1c34a9f3ba22e92181fd20635bd165a0', + './Zend/Oauth/Signature/Plaintext.php' => '172f0dbf4ffed18d6aa136bbe752c4d2', + './Zend/Oauth/Signature/Hmac.php' => '7de78bcbd009391679c290259d4f0b7e', + './Zend/Oauth/Http/Utility.php' => 'b423ef547710255a45cac24c0f2212b6', + './Zend/Oauth/Http/UserAuthorization.php' => '19865a03744565805aedc37c211451b1', + './Zend/Oauth/Http/RequestToken.php' => 'a601ddf2a654043d45c8850970c3f81d', + './Zend/Oauth/Http/AccessToken.php' => '1d1fb8b5fa88827ea8170738cb44ddf0', + './Zend/Oauth/Http.php' => 'b71dc11811eb3b4ce48555c4ee836664', + './Zend/Oauth/Exception.php' => '8aa7149c933281a33beec3e6e29527ac', + './Zend/Oauth/Consumer.php' => 'a7e6bd2b6e40437980f8489790bc6a53', + './Zend/Oauth/Config/ConfigInterface.php' => '6830164ea9812294fc750da1337098f5', + './Zend/Oauth/Config.php' => '80ff096d8cec0c5bb7d1388a480c8803', + './Zend/Oauth/Client.php' => '45f14e23ad50d4d85b1656681d81d487', + './Zend/Oauth.php' => 'a194292fb9c2439c2909d2b0fe17a2bd', + './Zend/Loader.php' => '3a440481f38852f58a39b712ca87d1f9', + './Zend/Http/Response/Stream.php' => '83d96a23bada94448d56b7302916d4ef', + './Zend/Http/Response.php' => '0594b4e9572d27007e49442abe309918', + './Zend/Http/Exception.php' => '98f4737ee4d6b3de93fdf05a3fc7aa4c', + './Zend/Http/Client/Exception.php' => '30da2add08b4555e5fa1dc8c157ca37f', + './Zend/Http/Client/Adapter/Test.php' => 'e06773a4f74eac882c7f22c7f20761e5', + './Zend/Http/Client/Adapter/Stream.php' => '8d522d85b6bff060c9a10f9fd611ec0a', + './Zend/Http/Client/Adapter/Socket.php' => '6d6db9d986cfca0ce18d17c33cc612f6', + './Zend/Http/Client/Adapter/Proxy.php' => '892ba28ced3643b8ed5aca54f3896969', + './Zend/Http/Client/Adapter/Interface.php' => 'a0f8555e41c4679e3e0efc2822235e3a', + './Zend/Http/Client/Adapter/Exception.php' => '89c054ccc9f1db399d3b97051b146d0a', + './Zend/Http/Client/Adapter/Curl.php' => 'a0f409edfe1f0b0dffbf98709c846f19', + './Zend/Http/Client.php' => '0fdc1a5e0e0df69543f9aa98359d0fdc', + './Zend/Gdata/YouTube/VideoQuery.php' => 'd08f02e20e12871425d05490ef7bf634', + './Zend/Gdata/YouTube/VideoFeed.php' => '07eaed57637e2e490c1ff29f18c3af0a', + './Zend/Gdata/YouTube/VideoEntry.php' => '78db67e2d267168f00d82d23454532c3', + './Zend/Gdata/YouTube/UserProfileEntry.php' => '359456a0bed13649bf015ad24660e0a8', + './Zend/Gdata/YouTube/SubscriptionFeed.php' => '6ef548ff24d60cb264c7e38ac6fbaca7', + './Zend/Gdata/YouTube/SubscriptionEntry.php' => 'f4bf339e2ffad6815cabc42ec8981b73', + './Zend/Gdata/YouTube/PlaylistVideoFeed.php' => '3ebd122ccc2d3c6cb2fa97f2522aef0b', + './Zend/Gdata/YouTube/PlaylistVideoEntry.php' => 'd74666010c8a5d60950863bb6c1d9d50', + './Zend/Gdata/YouTube/PlaylistListFeed.php' => '3507e7a2c09dcb5ee8387cbee50da98a', + './Zend/Gdata/YouTube/PlaylistListEntry.php' => 'd8aa220766d77a83e916bfd0192f7364', + './Zend/Gdata/YouTube/MediaEntry.php' => '3478e5d65938b5ec5bdfc4382ebf89f3', + './Zend/Gdata/YouTube/InboxFeed.php' => '20eb4fa2025a9c9a98c5d3fa605f6cf0', + './Zend/Gdata/YouTube/InboxEntry.php' => 'dca5d2c467e84e7fb08dd7e43048e868', + './Zend/Gdata/YouTube/Extension/VideoId.php' => '5fa1f60078f30cff4216d4a9ff814f40', + './Zend/Gdata/YouTube/Extension/Username.php' => '982784449807f558d3eb733fdf805a68', + './Zend/Gdata/YouTube/Extension/Uploaded.php' => '36cdd75b4c5a2e999cca2136d11960ba', + './Zend/Gdata/YouTube/Extension/Token.php' => 'b8f0ea9931e09a2519cc365c257eab90', + './Zend/Gdata/YouTube/Extension/Status.php' => '1d0216cd5c04340148ea8c22a25a28c3', + './Zend/Gdata/YouTube/Extension/Statistics.php' => '50c584bdd099e939c711d1fd38204c2f', + './Zend/Gdata/YouTube/Extension/State.php' => '2f29a2e918dea080bce7b4947a5cf1a7', + './Zend/Gdata/YouTube/Extension/School.php' => '4307b603d94845f53259794be5dfc2ad', + './Zend/Gdata/YouTube/Extension/ReleaseDate.php' => '2f820ec0f859a4a758b15fa6db91032c', + './Zend/Gdata/YouTube/Extension/Relationship.php' => '0aad7884eadc0207c6c37c6d73195deb', + './Zend/Gdata/YouTube/Extension/Recorded.php' => '4fdcc93cbd4897396a7212471a121772', + './Zend/Gdata/YouTube/Extension/Racy.php' => '74ca091807a7e8817da850ddd7823950', + './Zend/Gdata/YouTube/Extension/QueryString.php' => 'ab0e180254036a30661bb2e13e796245', + './Zend/Gdata/YouTube/Extension/Private.php' => 'cae31d4bf0bcaf8a70881dd9cf8327d5', + './Zend/Gdata/YouTube/Extension/Position.php' => '85ddb29ec12e5712cf02e198e16213cf', + './Zend/Gdata/YouTube/Extension/PlaylistTitle.php' => 'c2d90679e77c0db14c3641b4feffd66b', + './Zend/Gdata/YouTube/Extension/PlaylistId.php' => '1d0f3a4a9c7409e0c9e48260d1733e19', + './Zend/Gdata/YouTube/Extension/Occupation.php' => '15d49f27af36ee458375d4e463dbd3e7', + './Zend/Gdata/YouTube/Extension/NoEmbed.php' => '474501835ffcef3db7ce66a3fc990dc4', + './Zend/Gdata/YouTube/Extension/Music.php' => '88fe6680609c5151603b0c440f3c0cf7', + './Zend/Gdata/YouTube/Extension/Movies.php' => '64d0579c0b8024d6ecfcff8715d104fc', + './Zend/Gdata/YouTube/Extension/MediaRating.php' => 'e521e0e474677af81229e53d26660085', + './Zend/Gdata/YouTube/Extension/MediaGroup.php' => '780666a1707fbc6f66131c567513ce0e', + './Zend/Gdata/YouTube/Extension/MediaCredit.php' => 'df56bc66783d7728e91733d21b30f1c2', + './Zend/Gdata/YouTube/Extension/MediaContent.php' => '418f1480bc0e1705c8aea34214346c63', + './Zend/Gdata/YouTube/Extension/Location.php' => '7f31e4011644e3f78462003005bcc128', + './Zend/Gdata/YouTube/Extension/Link.php' => 'e490e2123fa255a08403838cdbb1797f', + './Zend/Gdata/YouTube/Extension/LastName.php' => '38eb3a8a73940421ef5d96e0d9b00344', + './Zend/Gdata/YouTube/Extension/Hometown.php' => '1e45365d9ef59f0685d4951ff2c10008', + './Zend/Gdata/YouTube/Extension/Hobbies.php' => 'c4824a0ecf6c61ee08585e7eb31f7fd5', + './Zend/Gdata/YouTube/Extension/Gender.php' => '09f2ad8e233248a52c88dcc957bf6949', + './Zend/Gdata/YouTube/Extension/FirstName.php' => 'e4ee02e4af42fbdf362fcf1f484f6cef', + './Zend/Gdata/YouTube/Extension/Duration.php' => 'd3cd34eaad5bc28bc95e70f4997e8eed', + './Zend/Gdata/YouTube/Extension/Description.php' => '1efbfbc83319bf470112cebfc4b325da', + './Zend/Gdata/YouTube/Extension/CountHint.php' => '392b457b91e6deac12753af92a0972b1', + './Zend/Gdata/YouTube/Extension/Control.php' => '77805b2e407809fdedba6f9b817f0a57', + './Zend/Gdata/YouTube/Extension/Company.php' => '571ed8acf0f7e498442fefcdfb53607f', + './Zend/Gdata/YouTube/Extension/Books.php' => 'aa8cc7495b93762e1a5141568ca69d9a', + './Zend/Gdata/YouTube/Extension/Age.php' => '823d6b5a30800dfe8ff0e1ce911ad020', + './Zend/Gdata/YouTube/Extension/AboutMe.php' => 'c81b3f7b441c0cb22e57bd32fd37d1ae', + './Zend/Gdata/YouTube/ContactFeed.php' => 'd9df7a110f5f8c7929451f6f7db62eb7', + './Zend/Gdata/YouTube/ContactEntry.php' => 'e65c537e9246bef0bd33502c2b271b36', + './Zend/Gdata/YouTube/CommentFeed.php' => '2a7f5aa0b70e7c1ec9c0585f4101839e', + './Zend/Gdata/YouTube/CommentEntry.php' => '511706a609bfcaa3b9f6365f39decb8c', + './Zend/Gdata/YouTube/ActivityFeed.php' => '3cc4414f4a907b0b4215851041d7cd06', + './Zend/Gdata/YouTube/ActivityEntry.php' => '0b4ecdc019d7f5bc2202e197b8a52ef1', + './Zend/Gdata/YouTube.php' => '55c50f1e97915e71d8d074ec58545193', + './Zend/Gdata/Spreadsheets/WorksheetFeed.php' => 'c236e0a8fb83879d9cfc70c98bd94a79', + './Zend/Gdata/Spreadsheets/WorksheetEntry.php' => '28585b9947db42a3cebafa8305e35ec4', + './Zend/Gdata/Spreadsheets/SpreadsheetFeed.php' => '07edc2e2f0eba835e57d77c82b80adb4', + './Zend/Gdata/Spreadsheets/SpreadsheetEntry.php' => '0db99ce56cc1f60c4912701ea4b6bb44', + './Zend/Gdata/Spreadsheets/ListQuery.php' => '914b1eef2c6d215d95cd9d50c5888ea9', + './Zend/Gdata/Spreadsheets/ListFeed.php' => '7ca20a1f04afddbc182d4a9237720ee9', + './Zend/Gdata/Spreadsheets/ListEntry.php' => '453dd5c3a99a8b85af6983883cdd6331', + './Zend/Gdata/Spreadsheets/Extension/RowCount.php' => '7dd692b4c1078a5c816979898444c551', + './Zend/Gdata/Spreadsheets/Extension/Custom.php' => '2121726d40bef96d5cd6f63fccb9d442', + './Zend/Gdata/Spreadsheets/Extension/ColCount.php' => '5ee3185c11569d23a45e124da3b0187b', + './Zend/Gdata/Spreadsheets/Extension/Cell.php' => '0e1a402993243dbf103b663ae3a65b82', + './Zend/Gdata/Spreadsheets/DocumentQuery.php' => '6ecca6b1509d7c70c96abd5e5c9e84ae', + './Zend/Gdata/Spreadsheets/CellQuery.php' => '2f90c329430c3f7abd6b5e0bc38a489e', + './Zend/Gdata/Spreadsheets/CellFeed.php' => 'e1a2bfe06f4ce23ae9c165b5cd4fbd0f', + './Zend/Gdata/Spreadsheets/CellEntry.php' => '898b3bbeb5f37e933e084ca71e652282', + './Zend/Gdata/Spreadsheets.php' => 'd6987183f1b327ccc11c9613fef7e474', + './Zend/Gdata/Query.php' => 'e2757f1bc039f2aaeed8ad4e7e86722f', + './Zend/Gdata/Photos/UserQuery.php' => '38c69ef30c96b164332f65a331ee0547', + './Zend/Gdata/Photos/UserFeed.php' => '56fdfaed72ad83487b13c9a6724a4c89', + './Zend/Gdata/Photos/UserEntry.php' => '356163021b933a5fa4d5944705be9534', + './Zend/Gdata/Photos/TagEntry.php' => 'db7cc947d50fdecfcf2f61eec00da421', + './Zend/Gdata/Photos/PhotoQuery.php' => '6ad0e3dc10de7c3dca800b77356a77ba', + './Zend/Gdata/Photos/PhotoFeed.php' => 'bf98655deba36706cdd23061f7c9d5ce', + './Zend/Gdata/Photos/PhotoEntry.php' => '3912e922f088f379912993e97f536db7', + './Zend/Gdata/Photos/Extension/Width.php' => '577629fed6de78472df888e378079c7c', + './Zend/Gdata/Photos/Extension/Weight.php' => 'b492aec4b790d2cd4c0eae047c01ec8f', + './Zend/Gdata/Photos/Extension/Version.php' => 'e8913ab213d21e2e4dd24d825aa7e940', + './Zend/Gdata/Photos/Extension/User.php' => 'f165bf08593fee86f7e4717ebaec1b47', + './Zend/Gdata/Photos/Extension/Timestamp.php' => '75eb2c121fa06c129e5d28fbeaa2bec0', + './Zend/Gdata/Photos/Extension/Thumbnail.php' => '43fb1e62312f079d64c7baab2963cea5', + './Zend/Gdata/Photos/Extension/Size.php' => '2630ae3ec766e4474d965736082ebbad', + './Zend/Gdata/Photos/Extension/Rotation.php' => 'a68e0eaf62d7373b40e3134a6b9c5ea4', + './Zend/Gdata/Photos/Extension/QuotaLimit.php' => 'a320dae891db029e4886bdd06371b583', + './Zend/Gdata/Photos/Extension/QuotaCurrent.php' => '71be9182545794213360b44d31164e10', + './Zend/Gdata/Photos/Extension/Position.php' => 'eb5d326804d6934286494155f56a56ec', + './Zend/Gdata/Photos/Extension/PhotoId.php' => '0a1dca01961755747c4f7dfaf18001cf', + './Zend/Gdata/Photos/Extension/NumPhotosRemaining.php' => 'bca831419999d05e562380ab5bf896a0', + './Zend/Gdata/Photos/Extension/NumPhotos.php' => '6409e2ab85a661ec85ddc280323370f2', + './Zend/Gdata/Photos/Extension/Nickname.php' => 'b671bd7ac595645c7df32306dbb0724b', + './Zend/Gdata/Photos/Extension/Name.php' => '65b004def0d96e6df4dc98732d765c72', + './Zend/Gdata/Photos/Extension/MaxPhotosPerAlbum.php' => '54c496b1aebfad69b0b6aa54072ff35f', + './Zend/Gdata/Photos/Extension/Location.php' => 'f796cf33da904ad63ce48bfd314e6899', + './Zend/Gdata/Photos/Extension/Id.php' => '361b94fd39a07c5b185b9fbd7ba41fb1', + './Zend/Gdata/Photos/Extension/Height.php' => 'd602dc7f176bd6a9d868af0d09bc2303', + './Zend/Gdata/Photos/Extension/CommentingEnabled.php' => '49165c783a798d688b41bbbcbe060124', + './Zend/Gdata/Photos/Extension/CommentCount.php' => '543d6e8ec2766eab5feead7b5a717c4f', + './Zend/Gdata/Photos/Extension/Client.php' => '89bf5e2b85b34d1658fc5f44cbd7231e', + './Zend/Gdata/Photos/Extension/Checksum.php' => 'fd7cd4114add2accc8c8739d4ad022b1', + './Zend/Gdata/Photos/Extension/BytesUsed.php' => '9b827f57b6df8b455edbece3f841ccd1', + './Zend/Gdata/Photos/Extension/AlbumId.php' => '165002b61b7b6e2cff7da3e071c77cba', + './Zend/Gdata/Photos/Extension/Access.php' => '4dcc5ef6fa65be6d7c90cb94ff7e8cef', + './Zend/Gdata/Photos/CommentEntry.php' => '3d6e4d837f802a70383d382a8e16c046', + './Zend/Gdata/Photos/AlbumQuery.php' => '46c69253e0c22851915671300cf76bfd', + './Zend/Gdata/Photos/AlbumFeed.php' => '8f923c1bfefdba885bf2a4e549f2ef2c', + './Zend/Gdata/Photos/AlbumEntry.php' => 'f357bde1a27fe69bf9f7d30ca404737e', + './Zend/Gdata/Photos.php' => '9ddecf3bc25e69715e48eda73ec50314', + './Zend/Gdata/MimeFile.php' => '7c590cfb35853728314b660496957cc8', + './Zend/Gdata/MimeBodyString.php' => '8cc543fe62bfee59fd60edfa1755f1de', + './Zend/Gdata/MediaMimeStream.php' => 'c43c413eec9556f1dd103b3279e7f1b0', + './Zend/Gdata/Media/Feed.php' => '5eff2741c0df2fa38192f356cd38a105', + './Zend/Gdata/Media/Extension/MediaTitle.php' => '22d2b650c4ac47eaf7d44d4c79303417', + './Zend/Gdata/Media/Extension/MediaThumbnail.php' => 'c6da2b5cb45fcef98045213bddacc19f', + './Zend/Gdata/Media/Extension/MediaText.php' => 'a532decd15211d332c740b5fb9f2cb86', + './Zend/Gdata/Media/Extension/MediaRestriction.php' => '5ca5d055a993c9d2a8d90798542d9b15', + './Zend/Gdata/Media/Extension/MediaRating.php' => 'c0379615ef7e105805513a106264f5bc', + './Zend/Gdata/Media/Extension/MediaPlayer.php' => 'f8a5d5cba705113cf3ebde25fe1d5501', + './Zend/Gdata/Media/Extension/MediaKeywords.php' => '4af6605e2a9d3097314197c6d7723ff2', + './Zend/Gdata/Media/Extension/MediaHash.php' => '6efe3050750396957b4c134297cec762', + './Zend/Gdata/Media/Extension/MediaGroup.php' => '5df9c900f8c20293ff9b480d07ad09e2', + './Zend/Gdata/Media/Extension/MediaDescription.php' => 'e2687081069be0d2540f4337d40c6361', + './Zend/Gdata/Media/Extension/MediaCredit.php' => '849a2d69e6c0911887faeedaa2a8fdde', + './Zend/Gdata/Media/Extension/MediaCopyright.php' => 'a188c2607b2ba47dd2806c9c8f2705d7', + './Zend/Gdata/Media/Extension/MediaContent.php' => '2d565a102eef2a2015f04a49cd01426e', + './Zend/Gdata/Media/Extension/MediaCategory.php' => '3d304d1f7556b320766a62d05d6c9cce', + './Zend/Gdata/Media/Entry.php' => '3b616e1f80cab56dfa3d70b5c0a5f0cc', + './Zend/Gdata/Media.php' => '01c1520ff214209bd33bbcbead394d64', + './Zend/Gdata/Kind/EventEntry.php' => 'a43630a2d2067d3b485cef550d42dc9f', + './Zend/Gdata/HttpClient.php' => '8fb2007caccb17a77dad778d8af0b60d', + './Zend/Gdata/HttpAdapterStreamingSocket.php' => '7bbd9ba33d8d6df39b51b14a8d3486a1', + './Zend/Gdata/HttpAdapterStreamingProxy.php' => '7affc3e70de3fff146d250317d2d9030', + './Zend/Gdata/Health/Query.php' => '17fabebdad3be441f8dac2b826fca3a4', + './Zend/Gdata/Health/ProfileListFeed.php' => '20ec77b8a95c063f04d5f06e40f4d31c', + './Zend/Gdata/Health/ProfileListEntry.php' => 'a0148f1cc9353b297de31f12b14fb498', + './Zend/Gdata/Health/ProfileFeed.php' => '740a08f3445dac331c2ccf8ad04761be', + './Zend/Gdata/Health/ProfileEntry.php' => '76e93dd6da4feede52a9e2f33b7a3f2c', + './Zend/Gdata/Health/Extension/Ccr.php' => '7820c80f6a5a596dffee19ad86adda4d', + './Zend/Gdata/Health.php' => 'b6ed0d0b12be634f972bab3b99942e74', + './Zend/Gdata/Geo/Feed.php' => 'beb9344c11b85ea47c8d88d5d426add6', + './Zend/Gdata/Geo/Extension/GmlPos.php' => 'a0ff7fdff628fbfc6356ee88d3caaf34', + './Zend/Gdata/Geo/Extension/GmlPoint.php' => '0097670a0c6795935dcd80aaede6192c', + './Zend/Gdata/Geo/Extension/GeoRssWhere.php' => '681591874d4ac36147d432024a036e1b', + './Zend/Gdata/Geo/Entry.php' => 'acaa2f05954dccd840b95a8c4029235b', + './Zend/Gdata/Geo.php' => '8ef08655344ff86003c62f23db98954d', + './Zend/Gdata/Gbase/SnippetQuery.php' => '1feca4717ee466378378931160afde51', + './Zend/Gdata/Gbase/SnippetFeed.php' => 'ffe624be953dea771db41282527cb58e', + './Zend/Gdata/Gbase/SnippetEntry.php' => '40a7196df3511ae3ce963d23bc709c6b', + './Zend/Gdata/Gbase/Query.php' => '80659494e0a9fcb6215b4c4596609d2f', + './Zend/Gdata/Gbase/ItemQuery.php' => 'dd4dc6f47df900fe97254590f7c2d89a', + './Zend/Gdata/Gbase/ItemFeed.php' => '4ec749d978812d02e4aa7ea39326d139', + './Zend/Gdata/Gbase/ItemEntry.php' => '9f2267926147400f176037cfa47250dc', + './Zend/Gdata/Gbase/Feed.php' => 'e56b61fefa051c5596dd107dee255ba5', + './Zend/Gdata/Gbase/Extension/BaseAttribute.php' => 'e621931c3a259452fea4edf13431bfd9', + './Zend/Gdata/Gbase/Entry.php' => '4f0fd497fa906d00230af75f10b22322', + './Zend/Gdata/Gbase.php' => 'b3ee9fb6647e020d710ef1b8fdb7247a', + './Zend/Gdata/Gapps/UserQuery.php' => '7cc7cedbf1261c718ec5e9efd2b8e209', + './Zend/Gdata/Gapps/UserFeed.php' => '910e7651d59bfcc32aaf8539c01aa11c', + './Zend/Gdata/Gapps/UserEntry.php' => 'd4c36359c0de3c0047887cd8e7cc467c', + './Zend/Gdata/Gapps/ServiceException.php' => '44bb02fd9c7ee600b2946d4872c48421', + './Zend/Gdata/Gapps/Query.php' => '5804bf0e612cccb95fd109dfbc8d990b', + './Zend/Gdata/Gapps/OwnerQuery.php' => '2e28da5f124ab4ccdda91cfd69ad65ae', + './Zend/Gdata/Gapps/OwnerFeed.php' => '3f73aa0690ecd2bea62d459a86ae6aee', + './Zend/Gdata/Gapps/OwnerEntry.php' => 'a283e5d08b9640b1e73634b9eac1242f', + './Zend/Gdata/Gapps/NicknameQuery.php' => 'da4a417afde13ce7c511df9faa3c136b', + './Zend/Gdata/Gapps/NicknameFeed.php' => '0ecac922acaff29cea48fdea3dfb29f3', + './Zend/Gdata/Gapps/NicknameEntry.php' => '381398d8b64c684845bd95f696d38216', + './Zend/Gdata/Gapps/MemberQuery.php' => '1655bca8880182513af9eb085de7b05a', + './Zend/Gdata/Gapps/MemberFeed.php' => 'f358e81473a4e695fce3cf6001863140', + './Zend/Gdata/Gapps/MemberEntry.php' => 'e8fd0a7f5a95697e21424df53c2e26f9', + './Zend/Gdata/Gapps/GroupQuery.php' => '86fce715639be938d9eaf926dd20bcfb', + './Zend/Gdata/Gapps/GroupFeed.php' => '2303a0202e5ccaaa9a9531cc5de3eac8', + './Zend/Gdata/Gapps/GroupEntry.php' => '71a9305f473ebd479141b498a3494866', + './Zend/Gdata/Gapps/Extension/Quota.php' => 'd82e3541bbf2d29033963d2c198ab817', + './Zend/Gdata/Gapps/Extension/Property.php' => 'ab9b1a604822fd2f50e7eb230e8227f5', + './Zend/Gdata/Gapps/Extension/Nickname.php' => 'e858a3eafc46e8ba51de5cbe123a5f6d', + './Zend/Gdata/Gapps/Extension/Name.php' => 'f172f52f0db4d0c153205c4e065ea4b2', + './Zend/Gdata/Gapps/Extension/Login.php' => 'ea5ef17c68ab4f008200c5ef1c9ba11c', + './Zend/Gdata/Gapps/Extension/EmailList.php' => '66888e850a10ddfa540b3cb383556337', + './Zend/Gdata/Gapps/Error.php' => 'c7a499123a8aac5ae674582de89409cd', + './Zend/Gdata/Gapps/EmailListRecipientQuery.php' => '4fe617162091b96284cf6b30d4f8d45c', + './Zend/Gdata/Gapps/EmailListRecipientFeed.php' => '054c494d29479aef7fc90ad72a18c148', + './Zend/Gdata/Gapps/EmailListRecipientEntry.php' => '81124d2cbc9bb158df22b9c60ed9abca', + './Zend/Gdata/Gapps/EmailListQuery.php' => '11727b5f93fd88982dccc9bffe990661', + './Zend/Gdata/Gapps/EmailListFeed.php' => '3a00eea9d8c256ccda9ed2de0c5a0f56', + './Zend/Gdata/Gapps/EmailListEntry.php' => '1bb495a41c2e871ff542d2ace03083af', + './Zend/Gdata/Gapps.php' => '344bad2ed2ad479a4f57fda1b7b28670', + './Zend/Gdata/Feed.php' => '84a86a1adb03cf41a52edfb2f1bbd1a9', + './Zend/Gdata/Extension/Who.php' => '68b82339fb38fbd24c46117035604a49', + './Zend/Gdata/Extension/Where.php' => '5e3d0267266d786b86a4eb2c3dc6a7be', + './Zend/Gdata/Extension/When.php' => 'a58d5c1d94f7c340d5c47d1f153c3ca1', + './Zend/Gdata/Extension/Visibility.php' => 'bfcbf78cb8720f7a8eede9897dd4e28d', + './Zend/Gdata/Extension/Transparency.php' => '55a3f7b531fbcd1b8fdf217eb24f4b77', + './Zend/Gdata/Extension/Reminder.php' => 'e17b2f4ee1e0b2c080e24d9c70f0f526', + './Zend/Gdata/Extension/RecurrenceException.php' => '2f229486b249a3ba034dc1922002433e', + './Zend/Gdata/Extension/Recurrence.php' => 'd3a85bd86f5761074d663f3404babce4', + './Zend/Gdata/Extension/Rating.php' => '402217d483bd62c029be175166b0e0f6', + './Zend/Gdata/Extension/OriginalEvent.php' => 'a35914d5d59f8f9286aa816aee6ce058', + './Zend/Gdata/Extension/OpenSearchTotalResults.php' => 'bd1fdeec1ad50db6930597f25ac00976', + './Zend/Gdata/Extension/OpenSearchStartIndex.php' => 'f537eb3df18a5a2cde301b3b1fe550f7', + './Zend/Gdata/Extension/OpenSearchItemsPerPage.php' => 'b2607a72db7ac52eb8384b517d63f132', + './Zend/Gdata/Extension/FeedLink.php' => '9228248336b8904d1d0466fdabeb54ec', + './Zend/Gdata/Extension/ExtendedProperty.php' => '58ceef287b114ab1dd6c8463026cc389', + './Zend/Gdata/Extension/EventStatus.php' => '63dd0b4dc1fd822b792d05c544f41381', + './Zend/Gdata/Extension/EntryLink.php' => '133d38758dc1aa4460f42c5f6429bd98', + './Zend/Gdata/Extension/Comments.php' => '5284e3c442faa4fd195d2f4e90e734ca', + './Zend/Gdata/Extension/AttendeeType.php' => 'b8d7be4de6154f63a908ff36f929d1fb', + './Zend/Gdata/Extension/AttendeeStatus.php' => '38ea8daff33ec27ace3e35bb3399aff9', + './Zend/Gdata/Extension.php' => 'f4983203262813c5b20be865cd651e60', + './Zend/Gdata/Exif/Feed.php' => '8f28a030312f17288dfa452b6535eea1', + './Zend/Gdata/Exif/Extension/Time.php' => '2fc3c0a61ad2774cd262dd2eb18925c0', + './Zend/Gdata/Exif/Extension/Tags.php' => 'fb41e356cf6d13e718df13308c4977a5', + './Zend/Gdata/Exif/Extension/Model.php' => 'e50b5c8c91f132a9688c04979a3a7f2a', + './Zend/Gdata/Exif/Extension/Make.php' => '6a73ecf5a9d9f457a1e2105d6becbe04', + './Zend/Gdata/Exif/Extension/Iso.php' => '27d57264785569ff25f27b56f0626d28', + './Zend/Gdata/Exif/Extension/ImageUniqueId.php' => '2d335e6f555dd161ad56b62cafd227a9', + './Zend/Gdata/Exif/Extension/FocalLength.php' => '37e01682a9ba61f4ed6d4f89482442d5', + './Zend/Gdata/Exif/Extension/Flash.php' => '47d698699c2a3b38367d40e2c921be7e', + './Zend/Gdata/Exif/Extension/FStop.php' => '4048127b24094f8510679c356fb4130b', + './Zend/Gdata/Exif/Extension/Exposure.php' => '17a221583b3d9295310a7105f381b14d', + './Zend/Gdata/Exif/Extension/Distance.php' => '508d9351f48a0c4b89657252970ed753', + './Zend/Gdata/Exif/Entry.php' => 'cf9064fd8345152c90c629a9be667f3c', + './Zend/Gdata/Exif.php' => '2307cff4532c815e782d61daab7ea160', + './Zend/Gdata/Entry.php' => '9ab68a7da9ab47a8c8ebe09377d7ca6e', + './Zend/Gdata/DublinCore/Extension/Title.php' => '4201ad4501a44390d7d20be6e73f55a0', + './Zend/Gdata/DublinCore/Extension/Subject.php' => 'e4e3c9fb6b276ac42a74459ff000b4e6', + './Zend/Gdata/DublinCore/Extension/Rights.php' => '154e444ee89f1a8b61dbb4574f81812f', + './Zend/Gdata/DublinCore/Extension/Publisher.php' => '7b5fbe6b6c8b10a85edd0cd7dbfe7615', + './Zend/Gdata/DublinCore/Extension/Language.php' => '68b69a28430e42a2f1939de30c54fd2d', + './Zend/Gdata/DublinCore/Extension/Identifier.php' => 'da25ea992cd4591161cf7dcb838f6b81', + './Zend/Gdata/DublinCore/Extension/Format.php' => 'f90e804a999bc7ea9de7528f20d7c6b2', + './Zend/Gdata/DublinCore/Extension/Description.php' => '2941724eb29ead9b97aa5d487a8d4a97', + './Zend/Gdata/DublinCore/Extension/Date.php' => 'f6a1f1f6de749607aefe748c0032f52f', + './Zend/Gdata/DublinCore/Extension/Creator.php' => 'd90628cbac0f51ebc078265b77ea2450', + './Zend/Gdata/DublinCore.php' => 'b0bac63dc1a6b8cdedf8eb0a614688c3', + './Zend/Gdata/Docs/Query.php' => 'd78e6e5d4921f901d42ee1470a0037be', + './Zend/Gdata/Docs/DocumentListFeed.php' => '0e1f8bd2edd405a2cc7338398ebc8193', + './Zend/Gdata/Docs/DocumentListEntry.php' => 'eca757a3e4835b698ca58ed561c62528', + './Zend/Gdata/Docs.php' => 'bf405da462f8af4c2b482e1c396df580', + './Zend/Gdata/ClientLogin.php' => '24f07d68ad16d4d76c3ac02b0a172179', + './Zend/Gdata/Calendar/ListFeed.php' => '689104be14f604a351305bd4f259534b', + './Zend/Gdata/Calendar/ListEntry.php' => 'a703e4f6997b1d2220ea7d8ca71bfeac', + './Zend/Gdata/Calendar/Extension/WebContent.php' => 'abc03a658fa837b5da4a16095ddc14be', + './Zend/Gdata/Calendar/Extension/Timezone.php' => 'c32233c244828a0a7700c535f48b42e8', + './Zend/Gdata/Calendar/Extension/SendEventNotifications.php' => '6016ad8af905ebf27c5362dc6aa3c101', + './Zend/Gdata/Calendar/Extension/Selected.php' => 'fb15731ec66ff7140a114a7338c68340', + './Zend/Gdata/Calendar/Extension/QuickAdd.php' => '7238895758792d2ac86e5f665a7ac948', + './Zend/Gdata/Calendar/Extension/Link.php' => '0537bbcc9a494a46e886807825ac4f54', + './Zend/Gdata/Calendar/Extension/Hidden.php' => '3d57e2ec1823f5d8dc40d330670c4b34', + './Zend/Gdata/Calendar/Extension/Color.php' => 'e5ed39bd28bfe0068afafae27053483d', + './Zend/Gdata/Calendar/Extension/AccessLevel.php' => '77d388464e13fa29d6f3458ee43df6c6', + './Zend/Gdata/Calendar/EventQuery.php' => '1b2d94211af1eb3f4d9564a10b26a133', + './Zend/Gdata/Calendar/EventFeed.php' => 'f19c9145cf905a1701dadb117a5dbf75', + './Zend/Gdata/Calendar/EventEntry.php' => '4bfdcba72023f25ca41fef5d91a75073', + './Zend/Gdata/Calendar.php' => '4f403359ac413aea1fc8f6a24a627abc', + './Zend/Gdata/Books/VolumeQuery.php' => 'b976b6765a2e6df2c309db22b5e76160', + './Zend/Gdata/Books/VolumeFeed.php' => 'b8ff187c65a5fe2bf5ce990c18e44da9', + './Zend/Gdata/Books/VolumeEntry.php' => '0f837082c8fa04eaa220a9a951430869', + './Zend/Gdata/Books/Extension/Viewability.php' => 'f70735b6816c819338289cd5bac08364', + './Zend/Gdata/Books/Extension/ThumbnailLink.php' => 'cacfc1c756c927ef1ddeb5d9045534e4', + './Zend/Gdata/Books/Extension/Review.php' => '27afeb43e74846d178909d0300db6735', + './Zend/Gdata/Books/Extension/PreviewLink.php' => 'a3ce28689c7a7918a3e5699dea2545f3', + './Zend/Gdata/Books/Extension/InfoLink.php' => 'f87cad2a8305227311a44158f06c93f7', + './Zend/Gdata/Books/Extension/Embeddability.php' => '8b23184acfcf1d95e3eb35f7ae319c82', + './Zend/Gdata/Books/Extension/BooksLink.php' => '615384af3b31d3b54e3088e0d7ce4fe5', + './Zend/Gdata/Books/Extension/BooksCategory.php' => '1be9d61273496693c7c2b082184f0812', + './Zend/Gdata/Books/Extension/AnnotationLink.php' => '82f10d58503d6efac755aaebbe89e6e2', + './Zend/Gdata/Books/CollectionFeed.php' => '06ba2427be03e2b6ffddecde3abc1f19', + './Zend/Gdata/Books/CollectionEntry.php' => '62d3b17fce4c075fe1fbe88e8b85cab3', + './Zend/Gdata/Books.php' => '19e28ddea7b1e4e528783f72f160d9f3', + './Zend/Gdata/AuthSub.php' => '10bc8d63c7d29afea2a64816ef40be42', + './Zend/Gdata/App/VersionException.php' => 'f79b340a6e76df8235e8936cf1f6dea8', + './Zend/Gdata/App/Util.php' => '4f0103d76da6c1df3b5446d1d4cab1aa', + './Zend/Gdata/App/MediaSource.php' => 'd66435bd23f29c74d16a97ef7bd3c237', + './Zend/Gdata/App/MediaFileSource.php' => '228605cfbe7bd1a56ce499948cffc44f', + './Zend/Gdata/App/MediaEntry.php' => 'e604853b65b83ff22b67aa42333b1470', + './Zend/Gdata/App/LoggingHttpClientAdapterSocket.php' => '80a5cfc9e2d5228d34a83728589c375c', + './Zend/Gdata/App/InvalidArgumentException.php' => '7d25d4e28c5716d5a623f69e3f34f1d5', + './Zend/Gdata/App/IOException.php' => 'a7c6b306054e4393868b4c3abfee4cb3', + './Zend/Gdata/App/HttpException.php' => '6eaf643eed81a95a0185f09597ab598c', + './Zend/Gdata/App/FeedSourceParent.php' => '4b2310f917e8942d5f6ab6322a7980b6', + './Zend/Gdata/App/FeedEntryParent.php' => 'ee305afd397993b2668272e75aa20609', + './Zend/Gdata/App/Feed.php' => 'dd719b4feb53568fdad80ccef14d557d', + './Zend/Gdata/App/Extension/Uri.php' => '493b2a3364cbf5ebe297a548b6f3a0a5', + './Zend/Gdata/App/Extension/Updated.php' => '3f4da2bf87a0c81b7c9f12656e6c1c37', + './Zend/Gdata/App/Extension/Title.php' => '48de3c92ebb8e5fbf923ea43ae0a748f', + './Zend/Gdata/App/Extension/Text.php' => 'c6b9d3a8870ed4540a133455fcd43be6', + './Zend/Gdata/App/Extension/Summary.php' => '1c5fdc5ace6f74e7e8d8d5ade87a695f', + './Zend/Gdata/App/Extension/Subtitle.php' => 'e3e62bb19d1d5ca2a854234a7ff3f8bc', + './Zend/Gdata/App/Extension/Source.php' => 'c0552deee4ae8ec73cfb237d759999ad', + './Zend/Gdata/App/Extension/Rights.php' => 'c623ecc998bbed7e7c52571b37a27c3c', + './Zend/Gdata/App/Extension/Published.php' => 'c2c0fa40b7c7e9c858bf978edd5a0381', + './Zend/Gdata/App/Extension/Person.php' => '4958e01b770f9238e38863b887c0ed77', + './Zend/Gdata/App/Extension/Name.php' => '7d03477dbe90f4484e5477b690a3320f', + './Zend/Gdata/App/Extension/Logo.php' => '3433509934553948b86bda803ee38c99', + './Zend/Gdata/App/Extension/Link.php' => '16a58f5e61a5cc943ec03115c7fc739b', + './Zend/Gdata/App/Extension/Id.php' => 'b5bc2ae8e3e0a762fcb353ea3437ef4e', + './Zend/Gdata/App/Extension/Icon.php' => '231765bce9ed753dce83c97c5cc3944c', + './Zend/Gdata/App/Extension/Generator.php' => '9b1965c558067f31358616766de1aa00', + './Zend/Gdata/App/Extension/Email.php' => '6af7122bfdf49aea8b261a81cae56e05', + './Zend/Gdata/App/Extension/Element.php' => 'e985283b1b696bfb0d326f08fd19d8ad', + './Zend/Gdata/App/Extension/Edited.php' => '330aa08d5ca463aa359af76e5f5b17fa', + './Zend/Gdata/App/Extension/Draft.php' => '99ebe71f8b8b3fd840a181a24c08ae60', + './Zend/Gdata/App/Extension/Control.php' => 'be358f494629721b7c2d3f34d619bdb6', + './Zend/Gdata/App/Extension/Contributor.php' => '52b7be7179f68bd41e8033c7c61de368', + './Zend/Gdata/App/Extension/Content.php' => 'dc5f2ed1b1471d8bf26a4a3a083c2e9e', + './Zend/Gdata/App/Extension/Category.php' => 'e799a0a6548ddfefa0cc14f7c8ff8d1c', + './Zend/Gdata/App/Extension/Author.php' => 'd565809e5cd9f16f4b27c5384d8c5dfb', + './Zend/Gdata/App/Extension.php' => '8e4d504243e904fb21896e5aaa41e986', + './Zend/Gdata/App/Exception.php' => '83d110552e64d66b3e658f53011d1dfe', + './Zend/Gdata/App/Entry.php' => '133cf11a6726a895c2a570b51aeeeab4', + './Zend/Gdata/App/CaptchaRequiredException.php' => '654404b4361bcefcaacb2895199c3ce6', + './Zend/Gdata/App/BaseMediaSource.php' => 'f03d9750e70786156510a6bbf035e50d', + './Zend/Gdata/App/Base.php' => '0812ad5e71d4da23e6dac0b174d72dac', + './Zend/Gdata/App/BadMethodCallException.php' => '7d6e59e67eddf8e29065a07bfafbfbb1', + './Zend/Gdata/App/AuthException.php' => 'b71068b440931bf94ce5c8a1bc1c0963', + './Zend/Gdata/App.php' => '040846a1bbf23b95286b6ce6d92f11e8', + './Zend/Gdata.php' => 'c3979fa5ca85014295e6f78333ade8b4', + './Zend/Exception.php' => '55ee8977abba3e9c8c56937432434c4c', + './Zend/Crypt/Rsa/Key/Public.php' => 'bab2f532d07354d76d66ea559ce8cf91', + './Zend/Crypt/Rsa/Key/Private.php' => 'fa5a88c09c54728381b80ab7f2d1f515', + './Zend/Crypt/Rsa/Key.php' => '74438b6cecba7b323f86817c06bbd5e9', + './Zend/Crypt/Rsa.php' => 'c1b32cc26f5a09dccfae97c4b8a4aab0', + './Zend/Crypt/Math/Exception.php' => 'fa1df64deb5a50dba4b2291087ce73c4', + './Zend/Crypt/Math/BigInteger/Interface.php' => 'ddfb6e640c5e8e70c0145265c6766827', + './Zend/Crypt/Math/BigInteger/Gmp.php' => '961c30bc8a8a1fa5c0639bae35c96c8b', + './Zend/Crypt/Math/BigInteger/Exception.php' => '2abd4617fbef3a5707d674395aa54f17', + './Zend/Crypt/Math/BigInteger/Bcmath.php' => '711aca90da8cb203310549c16a40569a', + './Zend/Crypt/Math/BigInteger.php' => '4e83a33b019afde2b3f465078da98ae1', + './Zend/Crypt/Math.php' => '34803bb199f584d0ddb40c6b10c6926d', + './Zend/Crypt/Hmac/Exception.php' => '0f5e7197d44598e88b0f3c4bc76ce548', + './Zend/Crypt/Hmac.php' => '263965ebc65320101b7b812674d27c35', + './Zend/Crypt/Exception.php' => '1259690d0861934b9aec872583cb77b4', + './Zend/Crypt/DiffieHellman/Exception.php' => '767330f408c58b089aa082d990b73099', + './Zend/Crypt/DiffieHellman.php' => 'ec0a4f522b732f7fcbb9c4ab94d926e1', + './Zend/Crypt.php' => '0e72fd104506094fd2c7682b0b924542', + './install.php' => '53a5f32608389deae7fb6d57b552b39e', + './export.php' => '4d3cf3590901a87b525fd340238e7556', + './data/upload/index.html' => '9cd784063d39b18d308932c28c385853', + './data/Tracker.php' => '29c14ab7333e8d37a7ff77fe42b516bd', + './data/SugarBean.php' => '7fb508b71a67ee4f25b80dc4502e84b5', + './data/Link.php' => '06d9fa82aa3f1f4d2a3ab563174dab60', + './custom/index.html' => 'b0070a296647b6026d1800db14510e3c', + './cron.php' => 'a8ad27b49bafc80799a504760c007bdd', + './campaign_trackerv2.php' => 'e1420743b082e8191b7e231db0810d0e', + './campaign_tracker.php' => '1ae8d86945943738da6a2bc2e8bcdbb9', + './cache/xml/index.html' => '9cd784063d39b18d308932c28c385853', + './cache/upload/index.html' => '9cd784063d39b18d308932c28c385853', + './cache/pdf/index.html' => '9cd784063d39b18d308932c28c385853', + './cache/layout/index.html' => '9cd784063d39b18d308932c28c385853', + './cache/index.html' => '330a1eedb7f47535b37c1159ef805ec1', + './cache/import/index.html' => '9cd784063d39b18d308932c28c385853', + './cache/images/index.html' => '9cd784063d39b18d308932c28c385853', + './cache/feeds/index.html' => '9cd784063d39b18d308932c28c385853', + './cache/csv/index.html' => '9cd784063d39b18d308932c28c385853', + './acceptDecline.php' => '5333056512e0bfcf3249b5ffb96a5189', + './XTemplate/xtpl.php' => '7428c503e8fc3de9ff1e26ff8095b441', + './XTemplate/LICENSE' => '8c2e1ec1540fb3e0beb68361344cba7e', + './WebToLeadCapture.php' => 'e78cc96ab80dad03479a72eb439e60b5', + './TreeData.php' => '93ba2c53f2781017b5b0f2f962c398f4', + './SugarSecurity.php' => '4d8d0d7caf9aa942ff0f7ab61b8bfaae', + './ModuleInstall/PackageManager/tpls/PackageManagerScripts.tpl' => '1a32055544e7142252c7335e3e10d60f', + './ModuleInstall/PackageManager/tpls/PackageManagerLicense.tpl' => '89219bcdad610f475111c9d19c524df7', + './ModuleInstall/PackageManager/tpls/PackageForm.tpl' => '6a286fef17f4ad90cce0aaca456e47d2', + './ModuleInstall/PackageManager/tpls/ModuleLoaderListView.tpl' => '89644c510ea26bc19a338a9039fd14c5', + './ModuleInstall/PackageManager/metadata/listviewdefs.php' => 'e5a304b0e3f59b9655fee84251f859ad', + './ModuleInstall/PackageManager/PackageManagerDownloader.php' => '4b7278a48d4f5924ccab01fa79244e22', + './ModuleInstall/PackageManager/PackageManagerDisplay.php' => '26df5fc37509ae7a4fe28b1f424096c6', + './ModuleInstall/PackageManager/PackageManagerComm.php' => 'd9e4d2d8af57cc28fa6e57cf01eb1e68', + './ModuleInstall/PackageManager/PackageManager.php' => 'a47fe97c2797785e179b781744a3ed92', + './ModuleInstall/PackageManager/PackageController.php' => '5a41f4e7bb19d5585e4b694be0691bed', + './ModuleInstall/PackageManager/ListViewPackages.php' => '9cb9a457724974797f68f6e5bd094842', + './ModuleInstall/ModuleScanner.php' => '533ad4511f2d9d521cb30ac7c10c48f1', + './ModuleInstall/ModuleInstaller.php' => '3445fef26e0ea0d86f0b93e97bf6ec26', + './HandleAjaxCall.php' => '7c97cd2c9be97a8fd845fe4706a65f1c', +); +?> diff --git a/image.php b/image.php new file mode 100644 index 00000000..13de2f4e --- /dev/null +++ b/image.php @@ -0,0 +1,46 @@ + diff --git a/include/Dashlets/Dashlet.php b/include/Dashlets/Dashlet.php new file mode 100644 index 00000000..0032b6d8 --- /dev/null +++ b/include/Dashlets/Dashlet.php @@ -0,0 +1,378 @@ +id = $id; + } + + /** + * Returns the HTML for the configure icon + * + * @return string HTML + */ + public function setConfigureIcon() + { + if($this->isConfigurable) { + $additionalTitle = '
' + . SugarThemeRegistry::current()->getImage('dashlet-header-edit','title="' . translate('LBL_DASHLET_EDIT', 'Home') . '" alt="' . translate('LBL_DASHLET_EDIT', 'Home') . '" border="0" align="absmiddle"').'' + . ''; + } + else { + $additionalTitle = '
'; + } + + return $additionalTitle; + } + + /** + * Returns the HTML for the refresh icon + * + * @return string HTML + */ + public function setRefreshIcon() + { + $additionalTitle = ''; + if($this->isRefreshable) { + $additionalTitle .= '' + . SugarThemeRegistry::current()->getImage('dashlet-header-refresh','border="0" align="absmiddle" title="' . translate('LBL_DASHLET_REFRESH', 'Home') . '" alt="' . translate('LBL_DASHLET_REFRESH', 'Home') . '"') + . ''; + } + + return $additionalTitle; + } + + /** + * Returns the HTML for the delete icon + * + * @return string HTML + */ + public function setDeleteIcon() + { + global $sugar_config; + + if (!empty($sugar_config['lock_homepage']) && $sugar_config['lock_homepage'] == true) { + return '
'; + } + $additionalTitle = '' + . SugarThemeRegistry::current()->getImage('dashlet-header-close','border="0" align="absmiddle" title="' . translate('LBL_DASHLET_DELETE', 'Home') . '" alt="' . translate('LBL_DASHLET_DELETE', 'Home') . '"') + . '
'; + return $additionalTitle; + } + + /** + * @deprecated No longer needed, replaced with Dashlet::getHeader() and Dashlet::getFooter() + * + * @param string $text + * @return string HTML + */ + public function getTitle($text = '') + { + return ''; + } + + /** + * Called when Dashlet is displayed + * + * @param string $text text after the title + * @return string Header html + */ + public function getHeader($text = '') + { + global $sugar_config; + + $title = ''; + $title .= $this->setConfigureIcon(); + $title .= $this->setRefreshIcon(); + $title .= $this->setDeleteIcon(); + + $str = '
id . '" class="hd">
' . get_form_header($this->title, $title, false) . '
'; + + return $str; + } + + /** + * Called when Dashlet is displayed + * + * @return string footer HTML + */ + public function getFooter() + { + $footer = '
'; + + return $footer; + } + + /** + * Called when Dashlet is displayed, override this + * + * @param string $text text after the title + * @return string title HTML + */ + public function display($text = '') + { + return ''; + } + + /** + * Called when Dashlets configuration options are called + */ + public function displayOptions() + { + } + + /** + * Override if you need to do pre-processing before display is called + */ + public function process() + { + } + + /** + * Processes and displays the auto refresh code for the dashlet + * + * @param int $dashletOffset + * @return string HTML code + */ + protected function processAutoRefresh($dashletOffset = 0) + { + global $sugar_config; + + if ( empty($dashletOffset) ) { + $dashletOffset = 0; + $module = $_REQUEST['module']; + if(isset($_REQUEST[$module.'2_'.strtoupper($this->seedBean->object_name).'_offset'])) { + $dashletOffset = $_REQUEST[$module.'2_'.strtoupper($this->seedBean->object_name).'_offset']; + } + } + + if ( !$this->isRefreshable ) { + return ''; + } + if ( !empty($sugar_config['dashlet_auto_refresh_min']) && $sugar_config['dashlet_auto_refresh_min'] == -1 ) { + return ''; + } + $autoRefreshSS = new Sugar_Smarty(); + $autoRefreshSS->assign('dashletOffset', $dashletOffset); + $autoRefreshSS->assign('dashletId', $this->id); + $autoRefreshSS->assign('strippedDashletId', str_replace("-","",$this->id)); //javascript doesn't like "-" in function names + if ( empty($this->autoRefresh) ) { + $this->autoRefresh = 0; + } + elseif ( !empty($sugar_config['dashlet_auto_refresh_min']) ) { + $this->autoRefresh = min($sugar_config['dashlet_auto_refresh_min'],$this->autoRefresh); + } + $autoRefreshSS->assign('dashletRefreshInterval', $this->autoRefresh * 1000); + $tpl = 'include/Dashlets/DashletGenericAutoRefresh.tpl'; + if ( $_REQUEST['action'] == "DynamicAction" ) { + $tpl = 'include/Dashlets/DashletGenericAutoRefreshDynamic.tpl'; + } + + return $autoRefreshSS->fetch($tpl); + } + + /** + * Override this if your dashlet is configurable (this is called when the the configureDashlet form is shown) + * Filters the array for only the parameters it needs to save + * + * @param array $req the array to pull options from + * @return array options array + */ + public function saveOptions($req) + { + } + + /** + * Sets the language strings + * + * @param string $dashletClassname classname of the dashlet + * @param string $dashletDirectory directory path of the dashlet + */ + public function loadLanguage($dashletClassname, $dashletDirectory = 'modules/Home/Dashlets/') + { + global $current_language, $dashletStrings; + + if(!isset($dashletStrings[$dashletClassname])) { + // load current language strings for current language, else default to english + if(is_file($dashletDirectory . $dashletClassname . '/' . $dashletClassname . '.' . $current_language . '.lang.php') + || is_file('custom/' . $dashletDirectory . $dashletClassname . '/' . $dashletClassname . '.' . $current_language . '.lang.php') ) { + if(is_file($dashletDirectory . $dashletClassname . '/' . $dashletClassname . '.' . $current_language . '.lang.php')) { + require($dashletDirectory . $dashletClassname . '/' . $dashletClassname . '.' . $current_language . '.lang.php'); + } + if(is_file('custom/' . $dashletDirectory . $dashletClassname . '/' . $dashletClassname . '.' . $current_language . '.lang.php')) { + require('custom/' . $dashletDirectory . $dashletClassname . '/' . $dashletClassname . '.' . $current_language . '.lang.php'); + } + } + else { + if(is_file($dashletDirectory . $dashletClassname . '/' . $dashletClassname . '.en_us.lang.php')) { + require($dashletDirectory . $dashletClassname . '/' . $dashletClassname . '.en_us.lang.php'); + } + if(is_file('custom/' . $dashletDirectory . $dashletClassname . '/' . $dashletClassname . '.en_us.lang.php')) { + require('custom/' . $dashletDirectory . $dashletClassname . '/' . $dashletClassname . '.en_us.lang.php'); + } + } + } + + $this->dashletStrings = $dashletStrings[$dashletClassname]; + } + + /** + * Generic way to store an options array into UserPreferences + * + * @param array $optionsArray the array to save + */ + public function storeOptions($optionsArray) + { + global $current_user; + + $dashletDefs = $current_user->getPreference('dashlets', 'Home'); // load user's dashlets config + $dashletDefs[$this->id]['options'] = $optionsArray; + $current_user->setPreference('dashlets', $dashletDefs, 0, 'Home'); + } + + /** + * Generic way to retrieve options array from UserPreferences + * + * @return array options array stored in UserPreferences + */ + public function loadOptions() + { + global $current_user; + + $dashletDefs = $current_user->getPreference('dashlets', 'Home'); // load user's dashlets config + if(isset($dashletDefs[$this->id]['options'])) + return $dashletDefs[$this->id]['options']; + else + return array(); + } + + /** + * Override this in the subclass. It is used to determine whether the dashlet can be displayed. + * + * @return bool indicating whether or not the current user has access to display this Dashlet. + */ + public function hasAccess() + { + return true; + } + + /** + * Returns the available auto refresh settings you can set a dashlet to + * + * @return array options available + */ + protected function getAutoRefreshOptions() + { + $options = $GLOBALS['app_list_strings']['dashlet_auto_refresh_options']; + + if ( isset($GLOBALS['sugar_config']['dashlet_auto_refresh_min']) ) { + foreach ( $options as $time => $desc ) { + if ( $time != -1 && $time < $GLOBALS['sugar_config']['dashlet_auto_refresh_min'] ) { + unset($options[$time]); + } + } + } + + return $options; + } + + /** + * Returns true if the dashlet is auto refreshable + * + * @return bool + */ + protected function isAutoRefreshable() + { + return $this->isRefreshable && + ( isset($GLOBALS['sugar_config']['dashlet_auto_refresh_min']) ? + $GLOBALS['sugar_config']['dashlet_auto_refresh_min'] != -1 : true ); + } +} \ No newline at end of file diff --git a/include/Dashlets/DashletCacheBuilder.php b/include/Dashlets/DashletCacheBuilder.php new file mode 100644 index 00000000..592ed5e1 --- /dev/null +++ b/include/Dashlets/DashletCacheBuilder.php @@ -0,0 +1,88 @@ + $file) { + if(substr_count($file, '.meta') == 0) { // ignore meta data files + $class = substr($file, strrpos($file, '/') + 1, -4); + $dashletFiles[$class] = array(); + $dashletFiles[$class]['file'] = $file; + $dashletFiles[$class]['class'] = $class; + if(is_file(preg_replace('/(.*\/.*)(\.php)/Uis', '$1.meta$2', $file))) { // is there an associated meta data file? + $dashletFiles[$class]['meta'] = preg_replace('/(.*\/.*)(\.php)/Uis', '$1.meta$2', $file); + require($dashletFiles[$class]['meta']); + if ( isset($dashletMeta[$class]['module']) ) + $dashletFiles[$class]['module'] = $dashletMeta[$class]['module']; + } + + $filesInDirectory = array(); + getFiles($filesInDirectory, substr($file, 0, strrpos($file, '/')), '/^.*\/Dashlets\/[^\.]*\.icon\.(jpg|jpeg|gif|png)$/i'); + if(!empty($filesInDirectory)) { + $dashletFiles[$class]['icon'] = $filesInDirectory[0]; // take the first icon we see + } + } + } + + write_array_to_file('dashletsFiles', $dashletFiles, $cacheDir . 'dashlets.php'); + } +} +?> \ No newline at end of file diff --git a/include/Dashlets/DashletGeneric.php b/include/Dashlets/DashletGeneric.php new file mode 100644 index 00000000..ab9a509c --- /dev/null +++ b/include/Dashlets/DashletGeneric.php @@ -0,0 +1,506 @@ +isConfigurable = true; + if(isset($options)) { + if(!empty($options['filters'])) $this->filters = $options['filters']; + if(!empty($options['title'])) $this->title = $options['title']; + if(!empty($options['displayRows'])) $this->displayRows = $options['displayRows']; + if(!empty($options['displayColumns'])) $this->displayColumns = $options['displayColumns']; + if(isset($options['myItemsOnly'])) $this->myItemsOnly = $options['myItemsOnly']; + if(isset($options['autoRefresh'])) $this->autoRefresh = $options['autoRefresh']; + } + + $this->layoutManager = new LayoutManager(); + $this->layoutManager->setAttribute('context', 'Report'); + // fake a reporter object here just to pass along the db type used in many widgets. + // this should be taken out when sugarwidgets change + $temp = (object) array('db' => &$GLOBALS['db'], 'report_def_str' => ''); + $this->layoutManager->setAttributePtr('reporter', $temp); + $this->lvs = new ListViewSmarty(); + } + + /** + * Sets up the display options template + * + * @return string HTML that shows options + */ + function processDisplayOptions() { + require_once('include/templates/TemplateGroupChooser.php'); + + $this->configureSS = new Sugar_Smarty(); + // column chooser + $chooser = new TemplateGroupChooser(); + + $chooser->args['id'] = 'edit_tabs'; + $chooser->args['left_size'] = 5; + $chooser->args['right_size'] = 5; + $chooser->args['values_array'][0] = array(); + $chooser->args['values_array'][1] = array(); + + $this->loadCustomMetadata(); + // Bug 39517 - Don't add custom fields automatically to the available fields to display in the listview + //$this->addCustomFields(); + if($this->displayColumns) { + // columns to display + foreach($this->displayColumns as $num => $name) { + // defensive code for array being returned + $translated = translate($this->columns[$name]['label'], $this->seedBean->module_dir); + if(is_array($translated)) $translated = $this->columns[$name]['label']; + $chooser->args['values_array'][0][$name] = trim($translated, ':'); + } + // columns not displayed + foreach(array_diff(array_keys($this->columns), array_values($this->displayColumns)) as $num => $name) { + // defensive code for array being returned + $translated = translate($this->columns[$name]['label'], $this->seedBean->module_dir); + if(is_array($translated)) $translated = $this->columns[$name]['label']; + $chooser->args['values_array'][1][$name] = trim($translated, ':'); + } + } + else { + foreach($this->columns as $name => $val) { + // defensive code for array being returned + $translated = translate($this->columns[$name]['label'], $this->seedBean->module_dir); + if(is_array($translated)) $translated = $this->columns[$name]['label']; + if(!empty($val['default']) && $val['default']) + $chooser->args['values_array'][0][$name] = trim($translated, ':'); + else + $chooser->args['values_array'][1][$name] = trim($translated, ':'); + } + } + + $chooser->args['left_name'] = 'display_tabs'; + $chooser->args['right_name'] = 'hide_tabs'; + $chooser->args['max_left'] = '6'; + + $chooser->args['left_label'] = $GLOBALS['app_strings']['LBL_DISPLAY_COLUMNS']; + $chooser->args['right_label'] = $GLOBALS['app_strings']['LBL_HIDE_COLUMNS']; + $chooser->args['title'] = ''; + $this->configureSS->assign('columnChooser', $chooser->display()); + + $query = false; + $count = 0; + + if(!is_array($this->filters)) { + // use default search params + $this->filters = array(); + foreach($this->searchFields as $name => $params) { + if(!empty($params['default'])) + $this->filters[$name] = $params['default']; + } + } + foreach($this->searchFields as $name=>$params) { + if(!empty($name)) { + $name = strtolower($name); + $currentSearchFields[$name] = array(); + $widgetDef = $this->seedBean->field_defs[$name]; + if($widgetDef['type'] == 'enum') $widgetDef['remove_blank'] = true; // remove the blank option for the dropdown + if($widgetDef['name'] == 'assigned_user_name') $widgetDef['name'] = 'assigned_user_id'; + $widgetDef['input_name0'] = empty($this->filters[$name]) ? '' : $this->filters[$name]; + $currentSearchFields[$name]['label'] = !empty($params['label']) ? translate($params['label'], $this->seedBean->module_dir) : translate($widgetDef['vname'], $this->seedBean->module_dir); + $currentSearchFields[$name]['input'] = $this->layoutManager->widgetDisplayInput($widgetDef, true, (empty($this->filters[$name]) ? '' : $this->filters[$name])); + } + else { // ability to create spacers in input fields + $currentSearchFields['blank' + $count]['label'] = ''; + $currentSearchFields['blank' + $count]['input'] = ''; + $count++; + } + } + $this->currentSearchFields = $currentSearchFields; + + $this->configureSS->assign('strings', array('general' => $GLOBALS['mod_strings']['LBL_DASHLET_CONFIGURE_GENERAL'], + 'filters' => $GLOBALS['mod_strings']['LBL_DASHLET_CONFIGURE_FILTERS'], + 'myItems' => $GLOBALS['mod_strings']['LBL_DASHLET_CONFIGURE_MY_ITEMS_ONLY'], + 'displayRows' => $GLOBALS['mod_strings']['LBL_DASHLET_CONFIGURE_DISPLAY_ROWS'], + 'title' => $GLOBALS['mod_strings']['LBL_DASHLET_CONFIGURE_TITLE'], + 'save' => $GLOBALS['app_strings']['LBL_SAVE_BUTTON_LABEL'], + 'autoRefresh' => $GLOBALS['app_strings']['LBL_DASHLET_CONFIGURE_AUTOREFRESH'], + )); + $this->configureSS->assign('id', $this->id); + $this->configureSS->assign('showMyItemsOnly', $this->showMyItemsOnly); + $this->configureSS->assign('myItemsOnly', $this->myItemsOnly); + $this->configureSS->assign('searchFields', $this->currentSearchFields); + // title + $this->configureSS->assign('dashletTitle', $this->title); + + // display rows + $displayRowOptions = $GLOBALS['sugar_config']['dashlet_display_row_options']; + $this->configureSS->assign('displayRowOptions', $displayRowOptions); + $this->configureSS->assign('displayRowSelect', $this->displayRows); + + if($this->isAutoRefreshable()) { + $this->configureSS->assign('isRefreshable', true); + $this->configureSS->assign('autoRefreshOptions', $this->getAutoRefreshOptions()); + $this->configureSS->assign('autoRefreshSelect', $this->autoRefresh); + } + } + /** + * Displays the options for this Dashlet + * + * @return string HTML that shows options + */ + function displayOptions() { + $this->processDisplayOptions(); + return parent::displayOptions() . $this->configureSS->fetch($this->configureTpl); + } + + function buildWhere() { + global $current_user; + + $returnArray = array(); + + if(!is_array($this->filters)) { + // use defaults + $this->filters = array(); + foreach($this->searchFields as $name => $params) { + if(!empty($params['default'])) + $this->filters[$name] = $params['default']; + } + } + foreach($this->filters as $name=>$params) { + if(!empty($params)) { + if($name == 'assigned_user_id' && $this->myItemsOnly) continue; // don't handle assigned user filter if filtering my items only + $widgetDef = $this->seedBean->field_defs[$name]; + + $widgetClass = $this->layoutManager->getClassFromWidgetDef($widgetDef, true); + $widgetDef['table'] = $this->seedBean->table_name; + $widgetDef['table_alias'] = $this->seedBean->table_name; + if(!empty($widgetDef['source']) && $widgetDef['source'] == 'custom_fields'){ + $widgetDef['table'] = $this->seedBean->table_name."_cstm"; + $widgetDef['table_alias'] = $widgetDef['table']; + } + switch($widgetDef['type']) {// handle different types + case 'date': + case 'datetime': + case 'datetimecombo': + if(is_array($params) && !empty($params)) { + if(!empty($params['date'])) + $widgetDef['input_name0'] = $params['date']; + $filter = 'queryFilter' . $params['type']; + } + else { + $filter = 'queryFilter' . $params; + } + array_push($returnArray, $widgetClass->$filter($widgetDef, true)); + break; + case 'assigned_user_name': + // This type runs through the SugarWidgetFieldname class, and needs a little extra help to make it through + if ( ! isset($widgetDef['column_key']) ) { + $widgetDef['column_key'] = $name; + } + // No break here, we want to run through the default handler + default: + $widgetDef['input_name0'] = $params; + if(is_array($params) && !empty($params)) { // handle array query + array_push($returnArray, $widgetClass->queryFilterone_of($widgetDef, false)); + } + else { + array_push($returnArray, $widgetClass->queryFilterStarts_With($widgetDef, true)); + } + $widgetDef['input_name0'] = $params; + break; + } + } + } + + if($this->myItemsOnly) array_push($returnArray, $this->seedBean->table_name . '.' . "assigned_user_id = '" . $current_user->id . "'"); + + return $returnArray; + } + + protected function loadCustomMetadata() + { + $customMetadate = 'custom/modules/'.$this->seedBean->module_dir.'/metadata/dashletviewdefs.php'; + if ( file_exists ( $customMetadate )){ + require($customMetadate); + $this->searchFields = $dashletData[$this->seedBean->module_dir.'Dashlet']['searchFields']; + foreach($this->searchFields as $key =>$def){ + if($key == 'assigned_user_name'){ + $this->searchFields['assigned_user_id'] = $def; + unset($this->searchFields['assigned_user_name'] ); + break; + } + } + + $this->columns = $dashletData[$this->seedBean->module_dir.'Dashlet']['columns']; + } + } + + /** + * Does all dashlet processing, here's your chance to modify the rows being displayed! + */ + function process($lvsParams = array()) { + $currentSearchFields = array(); + $configureView = true; // configure view or regular view + $query = false; + $whereArray = array(); + $lvsParams['massupdate'] = false; + + $this->loadCustomMetadata(); + $this->addCustomFields(); + // apply filters + if(isset($this->filters) || $this->myItemsOnly) { + $whereArray = $this->buildWhere(); + } + + $this->lvs->export = false; + $this->lvs->multiSelect = false; + // columns + $displayColumns = array(); + if(!empty($this->displayColumns)) { // use user specified columns + foreach($this->displayColumns as $name => $val) { + $displayColumns[strtoupper($val)] = $this->columns[$val]; + $displayColumns[strtoupper($val)]['label'] = trim($displayColumns[strtoupper($val)]['label'], ':');// strip : at the end of headers + } + } + else if (isset($this->columns)){ + // use the default + foreach($this->columns as $name => $val) { + if(!empty($val['default']) && $val['default']) { + $displayColumns[strtoupper($name)] = $val; + $displayColumns[strtoupper($name)]['label'] = trim($displayColumns[strtoupper($name)]['label'], ':'); + } + } + } + $this->lvs->displayColumns = $displayColumns; + + + $this->lvs->lvd->setVariableName($this->seedBean->object_name, array()); + $lvdOrderBy = $this->lvs->lvd->getOrderBy(); // has this list been ordered, if not use default + + $nameRelatedFields = array(); + if(empty($lvdOrderBy['orderBy'])) { + foreach($displayColumns as $colName => $colParams) { + if(!empty($colParams['defaultOrderColumn'])) { + $lvsParams['overrideOrder'] = true; + $lvsParams['orderBy'] = $colName; + $lvsParams['sortOrder'] = $colParams['defaultOrderColumn']['sortOrder']; + } + } + } + // Check for 'last_name' column sorting with related fields (last_name, first_name) + // See ListViewData.php for actual sorting change. + if ($lvdOrderBy['orderBy'] == 'last_name' && !empty($displayColumns['NAME']) && !empty($displayColumns['NAME']['related_fields']) && + in_array('last_name', $displayColumns['NAME']['related_fields']) && + in_array('first_name', $displayColumns['NAME']['related_fields'])) { + $lvsParams['overrideLastNameOrder'] = true; + } + + if(!empty($this->displayTpl)) + { + //MFH BUG #14296 + $where = ''; + if(!empty($whereArray)){ + $where = '(' . implode(') AND (', $whereArray) . ')'; + } + $this->lvs->setup($this->seedBean, $this->displayTpl, $where , $lvsParams, 0, $this->displayRows/*, $filterFields*/); + if(in_array('CREATED_BY', array_keys($displayColumns))) { // handle the created by field + foreach($this->lvs->data['data'] as $row => $data) { + $this->lvs->data['data'][$row]['CREATED_BY'] = get_assigned_user_name($data['CREATED_BY']); + } + } + // assign a baseURL w/ the action set as DisplayDashlet + foreach($this->lvs->data['pageData']['urls'] as $type => $url) { + // awu Replacing action=DisplayDashlet with action=DynamicAction&DynamicAction=DisplayDashlet + if($type == 'orderBy') + $this->lvs->data['pageData']['urls'][$type] = preg_replace('/(action=.*&)/Ui', 'action=DynamicAction&DynamicAction=displayDashlet&', $url); + else + $this->lvs->data['pageData']['urls'][$type] = preg_replace('/(action=.*&)/Ui', 'action=DynamicAction&DynamicAction=displayDashlet&', $url) . '&sugar_body_only=1&id=' . $this->id; + } + + $this->lvs->ss->assign('dashletId', $this->id); + } + } + + /** + * Displays the Dashlet, must call process() prior to calling this + * + * @return string HTML that displays Dashlet + */ + function display() { + return parent::display() . $this->lvs->display(false) . $this->processAutoRefresh(); + } + + /** + * Filter the $_REQUEST and only save only the needed options + * @param array $req the array to pull options from + * + * @return array options array + */ + function saveOptions($req) { + $options = array(); + + $this->loadCustomMetadata(); + foreach($req as $name => $value) { + if(!is_array($value)) $req[$name] = trim($value); + } + $options['filters'] = array(); + foreach($this->searchFields as $name=>$params) { + $widgetDef = $this->seedBean->field_defs[$name]; + if($widgetDef['type'] == 'datetimecombo' || $widgetDef['type'] == 'datetime' || $widgetDef['type'] == 'date') { // special case datetime types + $options['filters'][$widgetDef['name']] = array(); + if(!empty($req['type_' . $widgetDef['name']])) { // save the type of date filter + $options['filters'][$widgetDef['name']]['type'] = $req['type_' . $widgetDef['name']]; + } + if(!empty($req['date_' . $widgetDef['name']])) { // save the date + $options['filters'][$widgetDef['name']]['date'] = $req['date_' . $widgetDef['name']]; + } + } + elseif(!empty($req[$widgetDef['name']])) { + $options['filters'][$widgetDef['name']] = $req[$widgetDef['name']]; + } + } + if(!empty($req['dashletTitle'])) { + $options['title'] = $req['dashletTitle']; + } + + if(!empty($req['myItemsOnly'])) { + $options['myItemsOnly'] = $req['myItemsOnly']; + } + else { + $options['myItemsOnly'] = false; + } + $options['displayRows'] = empty($req['displayRows']) ? '5' : $req['displayRows']; + // displayColumns + if(!empty($req['displayColumnsDef'])) { + $options['displayColumns'] = explode('|', $req['displayColumnsDef']); + } + $options['autoRefresh'] = empty($req['autoRefresh']) ? '0' : $req['autoRefresh']; + return $options; + } + + /** + * Internal function to add custom fields + * + */ + function addCustomFields() { + foreach($this->seedBean->field_defs as $fieldName => $def) { + if(!empty($def['type']) && $def['type'] == 'html') + continue; + if(isset($def['vname'])) { + $translated = translate($def['vname'], $this->seedBean->module_dir); + if(is_array($translated)) $translated = $def['vname']; + if(!empty($def['source']) && $def['source'] == 'custom_fields') { + if(isset($this->columns[$fieldName]['default']) && $this->columns[$fieldName]['default']){ + $this->columns[$fieldName] = array('width' => '10', + 'label' => $translated, + 'default' => 1); + }else{ + $this->columns[$fieldName] = array('width' => '10', + 'label' => $translated); + } + + } + } + } + } +} +?> diff --git a/include/Dashlets/DashletGenericAutoRefresh.tpl b/include/Dashlets/DashletGenericAutoRefresh.tpl new file mode 100644 index 00000000..4c829a5a --- /dev/null +++ b/include/Dashlets/DashletGenericAutoRefresh.tpl @@ -0,0 +1,58 @@ +{* + +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + + + +*} + + + \ No newline at end of file diff --git a/include/Dashlets/DashletGenericAutoRefreshDynamic.tpl b/include/Dashlets/DashletGenericAutoRefreshDynamic.tpl new file mode 100644 index 00000000..7dee1526 --- /dev/null +++ b/include/Dashlets/DashletGenericAutoRefreshDynamic.tpl @@ -0,0 +1,64 @@ +{* + +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + + + +*} + + + \ No newline at end of file diff --git a/include/Dashlets/DashletGenericChart.php b/include/Dashlets/DashletGenericChart.php new file mode 100644 index 00000000..a2672dd9 --- /dev/null +++ b/include/Dashlets/DashletGenericChart.php @@ -0,0 +1,354 @@ + $value ) { + $this->$key = $value; + } + } + + // load searchfields + $classname = get_class($this); + if ( is_file("modules/Charts/Dashlets/$classname/$classname.data.php") ) { + require("modules/Charts/Dashlets/$classname/$classname.data.php"); + $this->_searchFields = $dashletData[$classname]['searchFields']; + } + + // load language files + $this->loadLanguage($classname, 'modules/Charts/Dashlets/'); + + if ( empty($options['title']) ) + $this->title = $this->dashletStrings['LBL_TITLE']; + if ( isset($options['autoRefresh']) ) + $this->autoRefresh = $options['autoRefresh']; + + $this->layoutManager = new LayoutManager(); + $this->layoutManager->setAttribute('context', 'Report'); + // fake a reporter object here just to pass along the db type used in many widgets. + // this should be taken out when sugarwidgets change + $temp = (object) array('db' => &$GLOBALS['db'], 'report_def_str' => ''); + $this->layoutManager->setAttributePtr('reporter', $temp); + } + + /** + * @see Dashlet::setRefreshIcon() + */ + public function setRefreshIcon() + { + $additionalTitle = ''; + if($this->isRefreshable) + $additionalTitle .= '' . translate('LBL_DASHLET_REFRESH', 'Home') . ''; + return $additionalTitle; + } + + /** + * Displays the javascript for the dashlet + * + * @return string javascript to use with this dashlet + */ + public function displayScript() + { + + require_once('include/SugarCharts/SugarChartFactory.php'); + $sugarChart = SugarChartFactory::getInstance(); + return $sugarChart->getDashletScript($this->id); + + } + + /** + * Gets the smarty object for the config window. Designed to allow lazy loading the object + * when it's needed. + */ + protected function getConfigureSmartyInstance() + { + if ( !($this->_configureSS instanceof Sugar_Smarty) ) { + + $this->_configureSS = new Sugar_Smarty(); + } + + return $this->_configureSS; + } + + /** + * Saves the chart config options + * Filter the $_REQUEST and only save only the needed options + * + * @param array $req + * @return array + */ + public function saveOptions( + $req + ) + { + global $timedate; + + $options = array(); + + foreach($req as $name => $value) + if(!is_array($value)) $req[$name] = trim($value); + + foreach($this->_searchFields as $name => $params) { + $widgetDef = $params; + if ( isset($this->getSeedBean()->field_defs[$name]) ) + $widgetDef = $this->getSeedBean()->field_defs[$name]; + if ( $widgetDef['type'] == 'date') // special case date types + $options[$widgetDef['name']] = $timedate->swap_formats($req['type_'.$widgetDef['name']], $timedate->get_date_format(), $timedate->dbDayFormat); + elseif ( $widgetDef['type'] == 'time') // special case time types + $options[$widgetDef['name']] = $timedate->swap_formats($req['type_'.$widgetDef['name']], $timedate->get_time_format(), $timedate->dbTimeFormat); + elseif ( $widgetDef['type'] == 'datepicker') // special case datepicker types + $options[$widgetDef['name']] = $timedate->swap_formats($req[$widgetDef['name']], $timedate->get_date_format(), $timedate->dbDayFormat); + elseif (!empty($req[$widgetDef['name']])) + $options[$widgetDef['name']] = $req[$widgetDef['name']]; + } + + if (!empty($req['dashletTitle'])) + $options['title'] = $req['dashletTitle']; + + $options['autoRefresh'] = empty($req['autoRefresh']) ? '0' : $req['autoRefresh']; + + return $options; + } + + /** + * Handles displaying the chart dashlet configuration popup window + * + * @return string HTML to return to the browser + */ + public function displayOptions() + { + $currentSearchFields = array(); + + if ( is_array($this->_searchFields) ) { + foreach($this->_searchFields as $name=>$params) { + if(!empty($name)) { + $name = strtolower($name); + $currentSearchFields[$name] = array(); + + $widgetDef = $params; + if ( isset($this->getSeedBean()->field_defs[$name]) ) + $widgetDef = $this->getSeedBean()->field_defs[$name]; + + if($widgetDef['type'] == 'enum' || $widgetDef['type'] == 'singleenum') $widgetDef['remove_blank'] = true; // remove the blank option for the dropdown + + if ( empty($widgetDef['input_name0']) ) + $widgetDef['input_name0'] = empty($this->$name) ? '' : $this->$name; + $currentSearchFields[$name]['label'] = translate($widgetDef['vname'], $this->getSeedBean()->module_dir); + if ( $currentSearchFields[$name]['label'] == $widgetDef['vname'] ) + $currentSearchFields[$name]['label'] = translate($widgetDef['vname'], 'Charts'); + $currentSearchFields[$name]['input'] = $this->layoutManager->widgetDisplayInput($widgetDef, true, (empty($this->$name) ? '' : $this->$name)); + } + else { // ability to create spacers in input fields + $currentSearchFields['blank' + $count]['label'] = ''; + $currentSearchFields['blank' + $count]['input'] = ''; + $count++; + } + } + } + $this->currentSearchFields = $currentSearchFields; + $this->getConfigureSmartyInstance()->assign('title',translate('LBL_TITLE','Charts')); + $this->getConfigureSmartyInstance()->assign('save',$GLOBALS['app_strings']['LBL_SAVE_BUTTON_LABEL']); + $this->getConfigureSmartyInstance()->assign('id', $this->id); + $this->getConfigureSmartyInstance()->assign('searchFields', $this->currentSearchFields); + $this->getConfigureSmartyInstance()->assign('dashletTitle', $this->title); + $this->getConfigureSmartyInstance()->assign('dashletType', 'predefined_chart'); + $this->getConfigureSmartyInstance()->assign('module', $_REQUEST['module']); + + if($this->isAutoRefreshable()) { + $this->getConfigureSmartyInstance()->assign('isRefreshable', true); + $this->getConfigureSmartyInstance()->assign('autoRefresh', $GLOBALS['app_strings']['LBL_DASHLET_CONFIGURE_AUTOREFRESH']); + $this->getConfigureSmartyInstance()->assign('autoRefreshOptions', $this->getAutoRefreshOptions()); + $this->getConfigureSmartyInstance()->assign('autoRefreshSelect', $this->autoRefresh); + } + + return parent::displayOptions() . $this->getConfigureSmartyInstance()->fetch($this->_configureTpl); + } + + /** + * Returns the DashletGenericChart::_seedBean object. Designed to allow lazy loading the object + * when it's needed. + * + * @return object + */ + protected function getSeedBean() + { + if ( !($this->_seedBean instanceof SugarBean) ) + $this->_seedBean = SugarModule::get($this->_seedName)->loadBean(); + + return $this->_seedBean; + } + + /** + * Returns the built query read to feed into SugarChart::getData() + * + * @return string SQL query + */ + protected function constructQuery() + { + return ''; + } + + /** + * Returns the array of group by parameters for SugarChart::$group_by + * + * @return string SQL query + */ + protected function constructGroupBy() + { + return array(); + } + + /** + * Displays the Dashlet, must call process() prior to calling this + * + * @return string HTML that displays Dashlet + */ + public function display() + { + return parent::display() . $this->processAutoRefresh(); + } + + /** + * Processes and displays the auto refresh code for the dashlet + * + * @param int $dashletOffset + * @return string HTML code + */ + protected function processAutoRefresh($dashletOffset = 0) + { + global $sugar_config; + + if ( empty($dashletOffset) ) { + $dashletOffset = 0; + $module = $_REQUEST['module']; + if(isset($_REQUEST[$module.'2_'.strtoupper($this->getSeedBean()->object_name).'_offset'])) { + $dashletOffset = $_REQUEST[$module.'2_'.strtoupper($this->getSeedBean()->object_name).'_offset']; + } + } + + if ( !$this->isRefreshable ) { + return ''; + } + if ( !empty($sugar_config['dashlet_auto_refresh_min']) && $sugar_config['dashlet_auto_refresh_min'] == -1 ) { + return ''; + } + $autoRefreshSS = new Sugar_Smarty(); + $autoRefreshSS->assign('dashletOffset', $dashletOffset); + $autoRefreshSS->assign('dashletId', $this->id); + $autoRefreshSS->assign('strippedDashletId', str_replace("-","",$this->id)); //javascript doesn't like "-" in function names + if ( empty($this->autoRefresh) ) { + $this->autoRefresh = 0; + } + elseif ( !empty($sugar_config['dashlet_auto_refresh_min']) ) { + $this->autoRefresh = min($sugar_config['dashlet_auto_refresh_min'],$this->autoRefresh); + } + $autoRefreshSS->assign('dashletRefreshInterval', $this->autoRefresh * 1000); + $autoRefreshSS->assign('url', "predefined_chart"); + $tpl = 'include/Dashlets/DashletGenericAutoRefresh.tpl'; + if ( $_REQUEST['action'] == "DynamicAction" ) { + $tpl = 'include/Dashlets/DashletGenericAutoRefreshDynamic.tpl'; + } + + return $autoRefreshSS->fetch($tpl); + } +} diff --git a/include/Dashlets/DashletGenericChartConfigure.tpl b/include/Dashlets/DashletGenericChartConfigure.tpl new file mode 100644 index 00000000..a3f08857 --- /dev/null +++ b/include/Dashlets/DashletGenericChartConfigure.tpl @@ -0,0 +1,95 @@ +{* + +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + + + +*} + + +
+
+ + + + + + + + +
' . $text . '
+ + + + + {if $isRefreshable} + + + + + {/if} + + {foreach name=searchIteration from=$searchFields key=name item=params} + + + {if ($smarty.foreach.searchIteration.iteration is even) and $smarty.foreach.searchIteration.iteration != $smarty.foreach.searchIteration.last} + + {/if} + {/foreach} + + + + +
+ {$title} + + +
+ {$autoRefresh} + + +
+ {$params.label} + + {$params.input} +
+ +
+ +
\ No newline at end of file diff --git a/include/Dashlets/DashletGenericConfigure.tpl b/include/Dashlets/DashletGenericConfigure.tpl new file mode 100644 index 00000000..a8c672d0 --- /dev/null +++ b/include/Dashlets/DashletGenericConfigure.tpl @@ -0,0 +1,134 @@ +{* + +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + + + +*} + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + {if $isRefreshable} + + + {/if} + + + + + + + + {if $showMyItemsOnly} + + + + + {/if} + + {foreach name=searchIteration from=$searchFields key=name item=params} + + + {if ($smarty.foreach.searchIteration.iteration is even) and $smarty.foreach.searchIteration.iteration != $smarty.foreach.searchIteration.last} + + {/if} + {/foreach} + + + + +
+

{$strings.general}

+
+ {$strings.title} + + +
+ {$strings.displayRows} + + {$strings.autoRefresh} + + +
+ + +
+ {$columnChooser} +
+
+
+

{$strings.filters}

+
+ {$strings.myItems} + + +
+ {$params.label} + + {$params.input} +
+ +
+
+
\ No newline at end of file diff --git a/include/Dashlets/DashletGenericDisplay.tpl b/include/Dashlets/DashletGenericDisplay.tpl new file mode 100644 index 00000000..776182f5 --- /dev/null +++ b/include/Dashlets/DashletGenericDisplay.tpl @@ -0,0 +1,191 @@ +{* + +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + + + +*} + + + + + + + + {foreach from=$displayColumns key=colHeader item=params} + + {/foreach} + {if !empty($quickViewLinks)} + + {/if} + + + {foreach name=rowIteration from=$data key=id item=rowData} + {if $smarty.foreach.rowIteration.iteration is odd} + {assign var='_rowColor' value=$rowColor[0]} + {else} + {assign var='_rowColor' value=$rowColor[1]} + {/if} + + {if $prerow} + + {/if} + {counter start=0 name="colCounter" print=false assign="colCounter"} + {foreach from=$displayColumns key=col item=params} + {strip} + + {/strip} + {counter name="colCounter"} + {/foreach} + {if !empty($quickViewLinks)} + + {/if} + + {foreachelse} + + + + {/foreach} +
+ + + + + +
  + {if $pageData.urls.startPage} + + + + {else} + + + + {/if} + {if $pageData.urls.prevPage} + + + + {else} + + + {/if} + ({if $pageData.offsets.lastOffsetOnPage == 0}0{else}{$pageData.offsets.current+1}{/if} - {$pageData.offsets.lastOffsetOnPage} {$navStrings.of} {if $pageData.offsets.totalCounted}{$pageData.offsets.total}{else}{$pageData.offsets.total}{if $pageData.offsets.lastOffsetOnPage != $pageData.offsets.total}+{/if}{/if}) + {if $pageData.urls.nextPage} + + + + {else} + + + + {/if} + {if $pageData.urls.endPage && $pageData.offsets.total != $pageData.offsets.lastOffsetOnPage} + + + + {elseif !$pageData.offsets.totalCounted || $pageData.offsets.total == $pageData.offsets.lastOffsetOnPage} + + + + {/if} +
+
+
+ {if $params.sortable|default:true} + {sugar_translate label=$params.label module=$pageData.bean.moduleDir}   + {if $params.orderBy|default:$colHeader|lower == $pageData.ordering.orderBy} + {if $pageData.ordering.sortOrder == 'ASC'} + {capture assign="imageName"}arrow_down.{$arrowExt}{/capture} + {$arrowAlt} + {else} + {capture assign="imageName"}arrow_up.{$arrowExt}{/capture} + {$arrowAlt} + {/if} + {else} + {capture assign="imageName"}arrow.{$arrowExt}{/capture} + {$arrowAlt} + {/if} + {else} + {if !isset($params.noHeader) || $params.noHeader == false} + {sugar_translate label=$params.label module=$pageData.bean.moduleDir} + {/if} + {/if} +
+
 
+ + + {if $col == 'NAME' || $params.bold}{/if} + {if $params.link && !$params.customCode} + <{$pageData.tag.$id[$params.ACLTag]|default:$pageData.tag.$id.MAIN} href='index.php?action={$params.action|default:'DetailView'}&module={if $params.dynamic_module}{$rowData[$params.dynamic_module]}{else}{$params.module|default:$pageData.bean.moduleDir}{/if}&record={$rowData[$params.id]|default:$rowData.ID}&offset={$pageData.offsets.current+$smarty.foreach.rowIteration.iteration}&stamp={$pageData.stamp}'> + {/if} + {if $params.customCode} + {sugar_evalcolumn_old var=$params.customCode rowData=$rowData} + {else} + {sugar_field parentFieldArray=$rowData vardef=$params displayType=ListView field=$col} + {/if} + {if empty($rowData.$col) && empty($params.customCode)} {/if} + {if $params.link && !$params.customCode} + + {/if} + {if $col == 'NAME' || $params.bold}{/if} + + {if $pageData.access.edit} + + {/if} + {if $pageData.access.view} + + {/if} +
+ {$APP.LBL_NO_DATA} +
diff --git a/include/DetailView/DetailView.php b/include/DetailView/DetailView.php new file mode 100644 index 00000000..80a81537 --- /dev/null +++ b/include/DetailView/DetailView.php @@ -0,0 +1,451 @@ +local_theme = $theme; + $this->local_app_strings =$app_strings; + } + + function processSugarBean($html_varName, $seed, &$offset, $isfirstview=0) { + global $row_count, $sugar_config; + + global $next_offset; + global $previous_offset; + global $list_view_row_count; + global $current_offset; + if (!empty($sugar_config['disable_vcr']) ) { + $seed->retrieve($_REQUEST['record']); + return $seed; + } + $isfirstview = 0; + + $nav_history_set=false; + $nav_history_array=array(); + $nav_offset=''; + $nav_ids_visited=array(); + $nav_stamp=''; + + //get the session variable DETAIL_NAV_HISTORY, + //the format of the variable stamp,offset, array of IDs visited. + $nav_history=$this->getLocalSessionVariable($html_varName, "DETAIL_NAV_HISTORY"); + if (!empty($nav_history)) { + $nav_history_set=true; + $nav_history_array=explode(":",$nav_history); + $nav_stamp=$nav_history_array[0]; + $nav_offset=$nav_history_array[1]; + eval("\$nav_ids_visited= ".$nav_history_array[2].";"); + } + + //from list offset is there but $bNavHistorySet is false. + //from next,previous,start and end buttons offset and $bNavHistorySet is true. + //from tracker offset is not there but $bNavHistorySet may or may not exist. + if (isset($_REQUEST['offset']) && !empty($_REQUEST['offset'])) { + //get offset values. + $offset = $_REQUEST['offset']; + if($offset < 0){ + $offset = 0; + } + //if the stamp has changed, ignore the offset and navigate to the record. + //use case, search, navigate to detail, copy URL, search again, paste URL. + if (!$this->isRequestFromListView($html_varName)) { + $result = $seed->retrieve($_REQUEST['record']); + return $result; + } + + if ($nav_history_set) { + if (isset($nav_ids_visited[$offset])) { + unset($nav_ids_visited[$offset]); + } + } + + } else { + if ($nav_history_set) { + //try to locate the ID in the nav_history array. + + $key = array_search($_REQUEST['record'], $nav_ids_visited); + if ($key === false) { + //do not show the VCR buttons. + + $result = $seed->retrieve($_REQUEST['record']); + return $result; + } + $offset=$key; + $_REQUEST['offset'] = $offset; + $_GET['offset'] = $offset; + $_POST['offset'] = $offset; + + $_REQUEST['stamp'] = $nav_stamp; + $_GET['stamp'] = $nav_stamp; + $_POST['stamp'] = $nav_stamp; + if (isset($nav_ids_visited[$offset])) { + unset($nav_ids_visited[$offset]); + } + + } else { + if(!empty($seed->id))return $seed; + + $result = $seed->retrieve($_REQUEST['record']); + return $result; + } + } + + //Check if this is the first time we have viewed this record + $var = $this->getLocalSessionVariable($html_varName, "IS_FIRST_VIEW"); + if(!isset($var) || !$var){ + $isFirstView = true; + } + else{ + $isFirstView = false; + } + //indicate that this is not the first time anymore + $this->setLocalSessionVariable($html_varName, "IS_FIRST_VIEW", false); + + // All 3 databases require this because the limit query does a > db_offset comparision. + $db_offset=$offset-1; + + $this->populateQueryWhere($isFirstView, $html_varName); + if(ACLController::requireOwner($seed->module_dir, 'view')) { + global $current_user; + $seed->getOwnerWhere($current_user->id); + if(!empty($this->query_where)) { + $this->query_where .= ' AND '; + } + $this->query_where .= $seed->getOwnerWhere($current_user->id); + } + + $order = $this->getLocalSessionVariable($seed->module_dir.'2_'.$html_varName, "ORDER_BY"); + $orderBy = ''; + if(!empty($order['orderBy'])) + $orderBy = $order['orderBy']; + if(!empty($orderBy) && !empty($order['direction'])) + $orderBy .= ' ' . $order['direction']; + + $this->query_orderby = $seed->process_order_by($orderBy,null); + $current_offset = $_REQUEST['offset'] -1; + $response = $seed->process_detail_query(SugarVCR::retrieve($seed->module_dir), 0, -1, -1, '', $current_offset); + //$response = $seed->get_detail(, $this->query_where, $db_offset); + $object = $response['bean']; + $row_count = $response['row_count']; + $next_offset = $response['next_offset']; + $previous_offset = $response['previous_offset']; + $list_view_row_count = $row_count; + $this->setListViewRowCount($row_count); + + //if the retrieved id is not same as the request ID then hide the VCR buttons. + if (empty($object->id)) { + $this->no_record_found=true; + } + if (empty($_REQUEST['InDetailNav']) and strcmp($_REQUEST['record'],$object->id)!=0) { + $this->offset_key_mismatch=true; + } + if ($this->no_record_found or $this->offset_key_mismatch ) { + if ($nav_history_set) { + $this->return_to_list_only=true; + } + $result = $seed->retrieve($_REQUEST['record']); + return $result; + } + + //update the request with correct value for the record attribute. + //need only when using the VCR buttuoms. This is a workaround need to fix the values + //set in the VCR links. + $_REQUEST['record'] = $object->id; + $_GET['record'] = $object->id; + $_POST['record'] = $object->id; + + //set nav_history. + if (empty($nav_stamp)) { + $nav_stamp=$_GET['stamp']; + } + if (empty($nav_offset)) { + $nav_offset=$offset; + } + //store a maximum of 20 entries in the nav_ids_visited array. + //remove the oldest entry when this limit is reached. + if (count($nav_ids_visited) >= 20) { + reset($nav_ids_visited); + unset($nav_ids_visited[key($nav_ids_visited)]); + } + $nav_ids_visited[$offset]=$object->id; + $nav_history=sprintf("%s:%s:%s",$nav_stamp,$nav_offset,var_export($nav_ids_visited,true)); + $this->setLocalSessionVariable($html_varName, "DETAIL_NAV_HISTORY",$nav_history); + + return $object; + } + + function populateQueryWhere($isfirstview, $html_varName){ + if($isfirstview){ + $this->query_where = $this->getVariableFromSession($_REQUEST['module'], 'QUERY_WHERE'); + + //this is a fail safe, in case the old ListView is still in use + if(empty($this->query_where)){ + $this->query_where = $this->getLocalSessionVariable($html_varName, "QUERY_WHERE"); + } + //SETTING QUERY FOR LATER USE + $this->setSessionVariable("QUERY_DETAIL", "where", $this->query_where); + } + else{ + $this->query_where = $this->getSessionVariable("QUERY_DETAIL", "where"); + } + } + + function processListNavigation( &$xtpl, $html_varName, $current_offset, $display_audit_link = false){ + global $export_module, $sugar_config, $current_user; + //intialize audit_link + $audit_link = ''; + + $row_count = $this->getListViewRowCount(); + + if($display_audit_link && (!isset($sugar_config['disc_client']) || $sugar_config['disc_client'] == false)) + { + //Audit link + $popup_request_data = array( + 'call_back_function' => 'set_return', + 'form_name' => 'EditView', + 'field_to_name_array' => array(), + ); + $json = getJSONobj(); + $encoded_popup_request_data = $json->encode($popup_request_data); + $audit_link = "".$this->local_app_strings['LNK_VIEW_CHANGE_LOG'].""; + } + + $html_text = ""; + $pre_html_text = ""; + $pre_html_text .= "\n"; + $pre_html_text .= "\n"; + $pre_html_text .= "\n"; + + + + if ($this->return_to_list_only == true) { + if($current_offset != 0 && $this->isRequestFromListView($html_varName)) + { + if($current_offset < 0){ + $current_offset = 1; + } + else if($current_offset > $row_count){ + $current_offset = $row_count; + } + + $this->set_base_URL($html_varName); + $list_URL = $this->base_URL.'&action=index&module='.$_REQUEST['module']; + $current_page = floor($current_offset / $this->records_per_page) * $this->records_per_page; + + $list_URL .= '&'.$this->getSessionVariableName($html_varName,"offset").'='.$current_page; + //$list_link = "".$this->local_app_strings['LNK_LIST_RETURN']." "; + $list_link = ""; + + $html_text .= ""; + } + } + else { + if($current_offset != 0 && $this->isRequestFromListView($html_varName)) + { + if($current_offset < 0){ + $current_offset = 1; + } + else if($current_offset > $row_count){ + $current_offset = $row_count; + } + + $next_offset = $current_offset + 1; + $previous_offset = $current_offset - 1; + + $this->set_base_URL($html_varName); + + $start_URL = $this->base_URL."1"."&InDetailNav=1"; + $current_URL = $this->base_URL.$current_offset."&InDetailNav=1"; + $previous_URL = $this->base_URL.$previous_offset."&InDetailNav=1"; + $next_URL = $this->base_URL.$next_offset."&InDetailNav=1"; + $end_URL = $this->base_URL.$row_count."&InDetailNav=1"; + + $current_page = floor($current_offset / $this->records_per_page) * $this->records_per_page; + + if(1 == $current_offset){ + //$start_link = SugarThemeRegistry::current()->getImage("start_off","alt='".$this->local_app_strings['LNK_LIST_START']."' border='0' align='absmiddle'")." ".$this->local_app_strings['LNK_LIST_START']; + //$previous_link = SugarThemeRegistry::current()->getImage("previous_off","alt='".$this->local_app_strings['LNK_LIST_PREVIOUS']."' border='0' align='absmiddle'")." ".$this->local_app_strings['LNK_LIST_PREVIOUS'].""; + $start_link = ""; + $previous_link = ""; + + }else{ + //$start_link = "".SugarThemeRegistry::current()->getImage("start","alt='".$this->local_app_strings['LNK_LIST_START']."' border='0' align='absmiddle'")." ".$this->local_app_strings['LNK_LIST_START'].""; + $start_link = ""; + + if(0 != $current_offset){ + //$previous_link = "".SugarThemeRegistry::current()->getImage("previous","alt='".$this->local_app_strings['LNK_LIST_PREVIOUS']."' border='0' align='absmiddle'")." ".$this->local_app_strings['LNK_LIST_PREVIOUS'].""; + $previous_link = ""; + } + else { + //$previous_link = SugarThemeRegistry::current()->getImage("previous_off","alt='".$this->local_app_strings['LNK_LIST_PREVIOUS']."' border='0' align='absmiddle'")." ".$this->local_app_strings['LNK_LIST_PREVIOUS']; + $previous_link = ""; + + } + } + + + if($row_count <= $current_offset){ + //$end_link = $this->local_app_strings['LNK_LIST_END']." ".SugarThemeRegistry::current()->getImage("end_off","alt='".$this->local_app_strings['LNK_LIST_END']."' border='0' align='absmiddle'"); + //$next_link = $this->local_app_strings['LNK_LIST_NEXT']." ".SugarThemeRegistry::current()->getImage("next_off","alt='".$this->local_app_strings['LNK_LIST_NEXT']."' border='0' align='absmiddle'"); + $end_link = ""; + $next_link = ""; + } + else{ + //$end_link = "".$this->local_app_strings['LNK_LIST_END']." ".SugarThemeRegistry::current()->getImage("end","alt='".$this->local_app_strings['LNK_LIST_END']."' border='0' align='absmiddle'").""; + //$next_link = "".$this->local_app_strings['LNK_LIST_NEXT']." ".SugarThemeRegistry::current()->getImage("next","alt='".$this->local_app_strings['LNK_LIST_NEXT']."' border='0' align='absmiddle'").""; + $end_link = ""; + $next_link = ""; + + } + + $html_text .= ""; + + } + } + $post_html_text = "
 ".$audit_link."".$list_link; + + if ($row_count != 0) { + $resume_URL = $this->base_URL.$current_offset."&InDetailNav=1"; + //$resume_link = "".$this->local_app_strings['LNK_RESUME']." "; + $resume_link = ""; + + $html_text .= "  ".$resume_link; + } + $html_text .= "".$start_link."  ".$previous_link."  (".$current_offset." ".$this->local_app_strings['LBL_LIST_OF']." ".$row_count.")  ".$next_link."  ".$end_link."
\n"; + $post_html_text .= "\n"; + $post_html_text .= "\n"; + $showVCRControl = true; + if(isset($sugar_config['disable_vcr'])) { + $showVCRControl = !$sugar_config['disable_vcr']; + } + if ( $showVCRControl && $html_text != "" ) + $xtpl->assign("PAGINATION",$pre_html_text.$html_text.$post_html_text); + } + + + function set_base_URL($html_varName) { + + if(!isset($this->base_URL)){ + + $this->base_URL = $_SERVER['PHP_SELF']; + if(empty($this->base_URL)){ + $this->base_URL = 'index.php'; + } + + /*fixes an issue with + deletes when doing a search*/ + foreach($_GET as $name=>$value){ + if(!empty($value)){ + if($name != $this->getSessionVariableName($html_varName,"ORDER_BY") && $name != "offset" && substr_count($name, "ORDER_BY")==0 && $name!="isfirstview"){ + if (is_array($value)) { + foreach($value as $valuename=>$valuevalue){ + $this->base_URL .= "&{$name}[]=".$valuevalue; + } + } else { + if(substr_count( $this->base_URL, '?') > 0){ + $this->base_URL .= "&$name=$value"; + }else{ + $this->base_URL .= "?$name=$value"; + } + } + } + } + } + + if($_SERVER['REQUEST_METHOD'] == 'POST'){ + $this->base_URL .= '?'; + if(isset($_REQUEST['action'])) $this->base_URL .= '&action='.$_REQUEST['action']; + if(isset($_REQUEST['record'])) $this->base_URL .= '&record='.$_REQUEST['record']; + if(isset($_REQUEST['module'])) $this->base_URL .= '&module='.$_REQUEST['module']; + } + $this->base_URL .= "&offset="; + } + } + function setListViewRowCount($count) + { + $this->list_row_count = $count; + } + + function getListViewRowCount() + { + return $this->list_row_count; + } + + /* This method will return in all of these cases: When selecting any of the VCR buttons (start,prev,next or last) + * and navigating from list to detail for the first time. + * if false in this case: the user changes the list query (which generates a new stamp) and pastes a URL + * from a previously navigated item. + */ + function isRequestFromListView($html_varName) + { + $varList = $this->getLocalSessionVariable($html_varName, "FROM_LIST_VIEW"); + if(isset($_GET['stamp']) && isset($varList) && $varList == $_GET['stamp']){ + return true; + } + else{ + return false; + } + } + + /** + * Return a variable from the session. uses the new ListView session data. Hence the '2' + * + * @param unknown_type $name - the name of the variable to set in the session + * @param unknown_type $value - the value of the variable to set + */ + function getVariableFromSession($name, $value){ + if(isset($_SESSION[$name."2_".$value])){ + return $_SESSION[$name."2_".$value]; + } + else{ + return ""; + } + } + + } +?> \ No newline at end of file diff --git a/include/DetailView/DetailView.tpl b/include/DetailView/DetailView.tpl new file mode 100644 index 00000000..be65ab0f --- /dev/null +++ b/include/DetailView/DetailView.tpl @@ -0,0 +1,175 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} +{{include file=$headerTpl}} +{sugar_include include=$includes} +
+ {{if $useTabs}} + {* Generate the Tab headers *} + {{counter name="tabCount" start=-1 print=false assign="tabCount"}} + + {{/if}} +
+{{* Loop through all top level panels first *}} +{{counter name="panelCount" print=false start=0 assign="panelCount"}} +{{foreach name=section from=$sectionPanels key=label item=panel}} +{{assign var='panel_id' value=$panelCount}} +
+{counter name="panelFieldCount" start=0 print=false assign="panelFieldCount"} +{{* Print out the panel title if one exists*}} + +{{* Check to see if the panel variable is an array, if not, we'll attempt an include with type param php *}} +{{* See function.sugar_include.php *}} +{{if !is_array($panel)}} + {sugar_include type='php' file='{{$panel}}'} +{{else}} + + {{if !empty($label) && !is_int($label) && $label != 'DEFAULT' && !$useTabs}} +

{sugar_translate label='{{$label}}' module='{{$module}}'}

+ {{/if}} + {{* Print out the table data *}} + + + + + {{foreach name=rowIteration from=$panel key=row item=rowData}} + {counter name="fieldsUsed" start=0 print=false assign="fieldsUsed"} + {counter name="fieldsHidden" start=0 print=false assign="fieldsHidden"} + {capture name="tr" assign="tableRow"} + + {{assign var='columnsInRow' value=$rowData|@count}} + {{assign var='columnsUsed' value=0}} + {{foreach name=colIteration from=$rowData key=col item=colData}} + {{if !empty($colData.field.hideIf)}} + {if !({{$colData.field.hideIf}}) } + {{/if}} + {counter name="fieldsUsed"} + + + {{if !empty($colData.field.hideIf)}} + {else} + + + {/if} + {{/if}} + {{/foreach}} + + {/capture} + {if $fieldsUsed > 0 && $fieldsUsed != $fieldsHidden} + {$tableRow} + {/if} + {{/foreach}} +
+ {{if !empty($colData.field.name)}} + {if !$fields.{{$colData.field.name}}.hidden} + {{/if}} + {{if isset($colData.field.customLabel)}} + {{$colData.field.customLabel}} + {{elseif isset($colData.field.label) && strpos($colData.field.label, '$')}} + {capture name="label" assign="label"}{{$colData.field.label}}{/capture} + {$label|strip_semicolon}: + {{elseif isset($colData.field.label)}} + {capture name="label" assign="label"}{sugar_translate label='{{$colData.field.label}}' module='{{$module}}'}{/capture} + {$label|strip_semicolon}: + {{elseif isset($fields[$colData.field.name])}} + {capture name="label" assign="label"}{sugar_translate label='{{$fields[$colData.field.name].vname}}' module='{{$module}}'}{/capture} + {$label|strip_semicolon}: + {{else}} +   + {{/if}} + {{if isset($colData.field.popupHelp) || isset($fields[$colData.field.name]) && isset($fields[$colData.field.name].popupHelp) }} + {{if isset($colData.field.popupHelp) }} + {capture name="popupText" assign="popupText"}{sugar_translate label="{{$colData.field.popupHelp}}" module='{{$module}}'}{/capture} + {{elseif isset($fields[$colData.field.name].popupHelp)}} + {capture name="popupText" assign="popupText"}{sugar_translate label="{{$fields[$colData.field.name].popupHelp}}" module='{{$module}}'}{/capture} + {{/if}} + {overlib_includes} + {sugar_help text=$popupText WIDTH=400} + {{/if}} + {{if !empty($colData.field.name)}} + {/if} + {{/if}} + + {{if !empty($colData.field.name)}} + {if !$fields.{{$colData.field.name}}.hidden} + {{/if}} + {{if $colData.field.customCode || $colData.field.assign}} + {counter name="panelFieldCount"} + {{sugar_evalcolumn var=$colData.field colData=$colData}} + {{elseif $fields[$colData.field.name] && !empty($colData.field.fields) }} + {{foreach from=$colData.field.fields item=subField}} + {{if $fields[$subField]}} + {counter name="panelFieldCount"} + {{sugar_field parentFieldArray='fields' tabindex=$tabIndex vardef=$fields[$subField] displayType='DetailView'}}  + {{else}} + {counter name="panelFieldCount"} + {{$subField}} + {{/if}} + {{/foreach}} + {{elseif $fields[$colData.field.name]}} + {counter name="panelFieldCount"} + {{sugar_field parentFieldArray='fields' vardef=$fields[$colData.field.name] displayType='DetailView' displayParams=$colData.field.displayParams typeOverride=$colData.field.type}} + {{/if}} + {{if !empty($colData.field.name)}} + {/if} + {{/if}} +   
+{{/if}} +
+{if $panelFieldCount == 0} + + +{/if} +{{/foreach}} +
+{{include file=$footerTpl}} +{{if $useTabs}} + + +{{/if}} \ No newline at end of file diff --git a/include/DetailView/DetailView2.php b/include/DetailView/DetailView2.php new file mode 100644 index 00000000..b2792aba --- /dev/null +++ b/include/DetailView/DetailView2.php @@ -0,0 +1,104 @@ +th = new TemplateHandler(); + $this->th->ss =& $this->ss; + $this->focus = $focus; + $this->tpl = $tpl; + $this->module = $module; + $this->metadataFile = $metadataFile; + if(isset($GLOBALS['sugar_config']['disable_vcr'])) { + $this->showVCRControl = !$GLOBALS['sugar_config']['disable_vcr']; + } + if(!empty($this->metadataFile) && file_exists($this->metadataFile)){ + require_once($this->metadataFile); + }else { + //If file doesn't exist we create a best guess + if(!file_exists("modules/$this->module/metadata/detailviewdefs.php") && + file_exists("modules/$this->module/DetailView.html")) { + global $dictionary; + $htmlFile = "modules/" . $this->module . "/DetailView.html"; + $parser = new DetailViewMetaParser(); + if(!file_exists('modules/'.$this->module.'/metadata')) { + sugar_mkdir('modules/'.$this->module.'/metadata'); + } + $fp = sugar_fopen('modules/'.$this->module.'/metadata/detailviewdefs.php', 'w'); + fwrite($fp, $parser->parse($htmlFile, $dictionary[$focus->object_name]['fields'], $this->module)); + fclose($fp); + } + + //Flag an error... we couldn't create the best guess meta-data file + if(!file_exists("modules/$this->module/metadata/detailviewdefs.php")) { + global $app_strings; + $error = str_replace("[file]", "modules/$this->module/metadata/detailviewdefs.php", $app_strings['ERR_CANNOT_CREATE_METADATA_FILE']); + $GLOBALS['log']->fatal($error); + echo $error; + die(); + } + require_once("modules/$this->module/metadata/detailviewdefs.php"); + } + + $this->defs = $viewdefs[$this->module][$this->view]; + } + +} +?> \ No newline at end of file diff --git a/include/DetailView/footer.tpl b/include/DetailView/footer.tpl new file mode 100644 index 00000000..821df87b --- /dev/null +++ b/include/DetailView/footer.tpl @@ -0,0 +1,38 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} + \ No newline at end of file diff --git a/include/DetailView/header.tpl b/include/DetailView/header.tpl new file mode 100644 index 00000000..c431d90e --- /dev/null +++ b/include/DetailView/header.tpl @@ -0,0 +1,119 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} +{{* Add the preForm code if it is defined (used for vcards) *}} +{{if $preForm}} + {{$preForm}} +{{/if}} + + + + {{/if}} + {{if count($form.buttons) > $num_buttons}} + {{foreach from=$form.buttons key=val item=button}} + {{if is_array($button) && $button.customCode}} + {{if isset($closeFormBeforeCustomButtons)}} + + {{/if}} + {{/if}} + {{/foreach}} + {{/if}} +{{/if}} +{{if !isset($closeFormBeforeCustomButtons)}} + + +{{/if}} +{{if empty($form.hideAudit) || !$form.hideAudit}} + +{{/if}} + +{{* Add $form.links if they are defined *}} +{{if !empty($form) && isset($form.links)}} + + +{{/if}} + +
+
+ + + + + + + + + +{{if isset($form.hidden)}} +{{foreach from=$form.hidden item=field}} +{{$field}} +{{/foreach}} +{{/if}} + +{{if !isset($form.buttons)}} +{{sugar_button module="$module" id="EDIT" view="$view"}} +{{sugar_button module="$module" id="DUPLICATE" view="EditView"}} +{{sugar_button module="$module" id="DELETE" view="$view"}} +{{else}} + {{counter assign="num_buttons" start=0 print=false}} + {{foreach from=$form.buttons key=val item=button}} + {{if !is_array($button) && in_array($button, $built_in_buttons)}} + {{counter print=false}} + {{sugar_button module="$module" id="$button" view="EditView"}} + {{/if}} + {{/foreach}} + {{if isset($closeFormBeforeCustomButtons)}} +
+
+ {{/if}} + {{sugar_button module="$module" id="$button" view="EditView"}} + {{if isset($closeFormBeforeCustomButtons)}} + +{{sugar_button module="$module" id="Audit" view="EditView"}} +{$ADMIN_EDIT} + {{if $panelCount == 0}} + {{* Render tag for VCR control if SHOW_VCR_CONTROL is true *}} + {{if $SHOW_VCR_CONTROL}} + {$PAGINATION} + {{/if}} + {{counter name="panelCount" print=false}} + {{/if}} +  + {{foreach from=$form.links item=link}} + {{$link}}  + {{/foreach}} +
\ No newline at end of file diff --git a/include/EditView/EditView.php b/include/EditView/EditView.php new file mode 100644 index 00000000..050912bf --- /dev/null +++ b/include/EditView/EditView.php @@ -0,0 +1,96 @@ +module = $module; + $this->template = $template; + $this->ss = new Sugar_Smarty(); + } + + /** + * Processes / setups the template + * assigns all things to the template like mod_srings and app_strings + * + */ + function process() { + global $current_language, $app_strings, $sugar_version, $sugar_config, $timedate, $theme;; + $module_strings = return_module_language($current_language, $this->module); + + $this->ss->assign('SUGAR_VERSION', $sugar_version); + $this->ss->assign('JS_CUSTOM_VERSION', $sugar_config['js_custom_version']); + $this->ss->assign('THEME', $theme); + $this->ss->assign('APP', $app_strings); + $this->ss->assign('MOD', $module_strings); + } + + + /** + * Displays the template + * + * @return string HTML of parsed template + */ + function display() { + return $this->ss->fetch($this->template); + } + +} +?> \ No newline at end of file diff --git a/include/EditView/EditView.tpl b/include/EditView/EditView.tpl new file mode 100644 index 00000000..5711beb0 --- /dev/null +++ b/include/EditView/EditView.tpl @@ -0,0 +1,215 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} +{{include file=$headerTpl}} +{sugar_include include=$includes} + + +
+ {{if $useTabs}} + {* Generate the Tab headers *} + {{counter name="tabCount" start=-1 print=false assign="tabCount"}} + + {{/if}} +
+{{* Loop through all top level panels first *}} +{{counter name="panelCount" start=-1 print=false assign="panelCount"}} + +{{foreach name=section from=$sectionPanels key=label item=panel}} +{{counter name="panelCount" print=false}} + +{{* Print out the table data *}} +{{if $label == 'DEFAULT'}} +
+{{else}} +
+{{/if}} + +{counter name="panelFieldCount" start=0 print=false assign="panelFieldCount"} +{{* Check to see if the panel variable is an array, if not, we'll attempt an include with type param php *}} +{{* See function.sugar_include.php *}} +{{if !is_array($panel)}} + {sugar_include type='php' file='{{$panel}}'} +{{else}} + + +{{* Only show header if it is not default or an int value *}} +{{if !empty($label) && !is_int($label) && $label != 'DEFAULT' && !$useTabs && $showSectionPanelsTitles}} + + + +{{/if}} + +{{assign var='rowCount' value=0}} +{{foreach name=rowIteration from=$panel key=row item=rowData}} +{counter name="fieldsUsed" start=0 print=false assign="fieldsUsed"} +{capture name="tr" assign="tableRow"} + + + {{assign var='columnsInRow' value=$rowData|@count}} + {{assign var='columnsUsed' value=0}} + + {{* Loop through each column and display *}} + {{counter name="colCount" start=0 print=false assign="colCount"}} + + {{foreach name=colIteration from=$rowData key=col item=colData}} + + {{counter name="colCount" print=false}} + {{math assign="tabIndex" equation="$panelCount * $maxColumns + $colCount"}} + {{if count($rowData) == $colCount}} + {{assign var="colCount" value=0}} + {{/if}} + + {{if !empty($colData.field.hideIf)}} + {if !({{$colData.field.hideIf}}) } + {{/if}} + + {{if empty($def.templateMeta.labelsOnTop) && empty($colData.field.hideLabel)}} + + {{/if}} + {counter name="fieldsUsed"} + + {/if} + {{/if}} + + {{/foreach}} + +{/capture} +{if $fieldsUsed > 0 } +{$tableRow} +{/if} +{{/foreach}} +
+

{sugar_translate label='{{$label}}' module='{{$module}}'}

+
+ {{if isset($colData.field.customLabel)}} + {{$colData.field.customLabel}} + {{elseif isset($colData.field.label)}} + {capture name="label" assign="label"}{sugar_translate label='{{$colData.field.label}}' module='{{$module}}'}{/capture} + {$label|strip_semicolon}: + {{elseif isset($fields[$colData.field.name])}} + {capture name="label" assign="label"}{sugar_translate label='{{$fields[$colData.field.name].vname}}' module='{{$module}}'}{/capture} + {$label|strip_semicolon}: + {{/if}} + {{* Show the required symbol if field is required, but override not set. Or show if override is set *}} + {{if ($fields[$colData.field.name].required && (!isset($colData.field.displayParams.required) || $colData.field.displayParams.required)) || + (isset($colData.field.displayParams.required) && $colData.field.displayParams.required)}} + {{$APP.LBL_REQUIRED_SYMBOL}} + {{/if}} + {{if isset($colData.field.popupHelp) || isset($fields[$colData.field.name]) && isset($fields[$colData.field.name].popupHelp) }} + {{if isset($colData.field.popupHelp) }} + {capture name="popupText" assign="popupText"}{sugar_translate label="{{$colData.field.popupHelp}}" module='{{$module}}'}{/capture} + {{elseif isset($fields[$colData.field.name].popupHelp)}} + {capture name="popupText" assign="popupText"}{sugar_translate label="{{$fields[$colData.field.name].popupHelp}}" module='{{$module}}'}{/capture} + {{/if}} + {capture name="overlibStuff" assign="overlibStuff"}{overlib_includes}{/capture} + {sugar_help text=$popupText WIDTH=-1} + {{/if}} + + + {{if !empty($def.templateMeta.labelsOnTop)}} + {{if isset($colData.field.label)}} + {{if !empty($colData.field.label)}} + {sugar_translate label='{{$colData.field.label}}' module='{{$module}}'}: + {{/if}} + {{elseif isset($fields[$colData.field.name])}} + {sugar_translate label='{{$fields[$colData.field.name].vname}}' module='{{$module}}'}: + {{/if}} + + {{* Show the required symbol if field is required, but override not set. Or show if override is set *}} + {{if ($fields[$colData.field.name].required && (!isset($colData.field.displayParams.required) || $colData.field.displayParams.required)) || + (isset($colData.field.displayParams.required) && $colData.field.displayParams.required)}} + {{$APP.LBL_REQUIRED_SYMBOL}} + {{/if}} + {{if !isset($colData.field.label) || !empty($colData.field.label)}} +
+ {{/if}} + {{/if}} + + + {{if $fields[$colData.field.name] && !empty($colData.field.fields) }} + {{foreach from=$colData.field.fields item=subField}} + {{if $fields[$subField.name]}} + {counter name="panelFieldCount"} + {{sugar_field parentFieldArray='fields' tabindex=$colData.field.tabindex vardef=$fields[$subField.name] displayType='EditView' displayParams=$subField.displayParams formName=$form_name}}  + {{/if}} + {{/foreach}} + {{elseif !empty($colData.field.customCode)}} + {counter name="panelFieldCount"} + {{sugar_evalcolumn var=$colData.field.customCode colData=$colData tabindex=$colData.field.tabindex}} + {{elseif $fields[$colData.field.name]}} + {counter name="panelFieldCount"} + {{$colData.displayParams}} + {{sugar_field parentFieldArray='fields' tabindex=$colData.field.tabindex vardef=$fields[$colData.field.name] displayType='EditView' displayParams=$colData.field.displayParams typeOverride=$colData.field.type formName=$form_name}} + {{/if}} + {{if !empty($colData.field.hideIf)}} + {else} +
+ +{{/if}} + +
+{if $panelFieldCount == 0} + + +{/if} +{{/foreach}} +
+{{include file=$footerTpl}} +{$overlibStuff} +{{if $useTabs}} + + +{{/if}} + diff --git a/include/EditView/EditView2.php b/include/EditView/EditView2.php new file mode 100644 index 00000000..c438eaf1 --- /dev/null +++ b/include/EditView/EditView2.php @@ -0,0 +1,716 @@ +th = new TemplateHandler(); + $this->th->ss =& $this->ss; + $this->tpl = $tpl; + $this->module = $module; + $this->focus = $focus; + + //this logic checks if the focus has an id and if it does not then it will create a new instance of the focus bean + //but in convert lead we do not want to create a new instance and do not want to populate id. + if($createFocus) + { + $this->createFocus(); + } + if(empty($GLOBALS['sugar_config']['showDetailData'])) { + $this->showDetailData = false; + } + $this->metadataFile = $metadataFile; + + if(isset($GLOBALS['sugar_config']['disable_vcr'])) { + $this->showVCRControl = !$GLOBALS['sugar_config']['disable_vcr']; + } + if(!empty($this->metadataFile) && file_exists($this->metadataFile)){ + include($this->metadataFile); + }else { + //If file doesn't exist we create a best guess + if(!file_exists("modules/$this->module/metadata/editviewdefs.php") && + file_exists("modules/$this->module/EditView.html")) { + require_once('include/SugarFields/Parsers/EditViewMetaParser.php'); + global $dictionary; + $htmlFile = "modules/" . $this->module . "/EditView.html"; + $parser = new EditViewMetaParser(); + if(!file_exists('modules/'.$this->module.'/metadata')) { + sugar_mkdir('modules/'.$this->module.'/metadata'); + } + $fp = sugar_fopen('modules/'.$this->module.'/metadata/editviewdefs.php', 'w'); + fwrite($fp, $parser->parse($htmlFile, $dictionary[$focus->object_name]['fields'], $this->module)); + fclose($fp); + } + + //Flag an error... we couldn't create the best guess meta-data file + if(!file_exists("modules/$this->module/metadata/editviewdefs.php")) { + global $app_strings; + $error = str_replace("[file]", "modules/$this->module/metadata/editviewdefs.php", $app_strings['ERR_CANNOT_CREATE_METADATA_FILE']); + $GLOBALS['log']->fatal($error); + echo $error; + die(); + } + require_once("modules/$this->module/metadata/editviewdefs.php"); + } + + $this->defs = $viewdefs[$this->module][$this->view]; + $this->isDuplicate = isset($_REQUEST['isDuplicate']) && $_REQUEST['isDuplicate'] == 'true' && $this->focus->aclAccess('edit'); + } + + function createFocus() + { + global $beanList, $beanFiles; + + if(empty($beanList[$this->module]))return; + if(!$this->focus ){ + $bean = $beanList[$this->module]; + require_once($beanFiles[$bean]); + $obj = new $bean(); + $this->focus = $obj; + } + + //If there is no idea, assume we are creating a new instance + //and call the fill_in_additional_detail_fields where initialization + //code has been moved to + if(empty($this->focus->id)) { + global $current_user; + $this->focus->fill_in_additional_detail_fields(); + $this->focus->assigned_user_id = $current_user->id; + } + } + + function populateBean() + { + if(!empty($_REQUEST['record']) && $this->populateBean) { + global $beanList; + $bean = $beanList[$this->module]; + $obj = new $bean(); + $this->focus = $obj->retrieve($_REQUEST['record']); + } else { + $GLOBALS['log']->debug("Unable to populate bean, no record parameter found"); + } + } + + /** + * enableFormatting + * This method is used to manually turn on/off the field formatting + * @param $format boolean value to turn on/off field formatting + */ + function enableFormatting( + $format = true + ) + { + $this->formatFields = $format; + } + + + function requiredFirst() + { + $panels = array('required'=>array()); + $reqCol = -1; + $reqRow = 0; + foreach($this->defs['panels'] as $key=>$p){ + + foreach($p as $row=>$rowDef) { + foreach($rowDef as $col => $colDef) { + $field = (is_array($p[$row][$col])) ? $p[$row][$col]['name'] : $p[$row][$col]; + if((!empty($this->focus->field_defs[$field]) + && !empty($this->focus->field_defs[$field]['required'])) + || ( !empty($p[$row][$col]['displayParams']['required']) )) { + $reqCol++; + if($reqCol == $this->defs['templateMeta']['maxColumns']) { + $reqCol = -1; + $reqRow++; + } + $panels['required'][$reqRow][$reqCol] = $p[$row][$col]; + }else{ + $panels[$key][$row][$col] = $p[$row][$col]; + } + + } //foreach + } //foreach + + + } //foreach + $this->defs['panels'] = $panels; + } + + function render() + { + $totalWidth = 0; + foreach($this->defs['templateMeta']['widths'] as $col => $def) { + foreach($def as $k => $value) $totalWidth += $value; + } + // calculate widths + foreach($this->defs['templateMeta']['widths'] as $col => $def) { + foreach($def as $k => $value) + $this->defs['templateMeta']['widths'][$col][$k] = round($value / ($totalWidth / 100), 2); + } + + $this->sectionPanels = array(); + $this->sectionLabels = array(); + if(!empty($this->defs['panels']) && count($this->defs['panels']) > 0) { + $keys = array_keys($this->defs['panels']); + if(is_numeric($keys[0])) { + $defaultPanel = $this->defs['panels']; + unset($this->defs['panels']); //blow away current value + $this->defs['panels'][''] = $defaultPanel; + } + } + if($this->view == 'EditView' && !empty($GLOBALS['sugar_config']['forms']['requireFirst'])){ + $this->requiredFirst(); + } + + $maxColumns = isset($this->defs['templateMeta']['maxColumns']) ? $this->defs['templateMeta']['maxColumns'] : 2; + $panelCount = 0; + static $itemCount = 100; //Start the generated tab indexes at 100 so they don't step on custom ones. + + /* loop all the panels */ + foreach($this->defs['panels'] as $key=>$p) + { + $panel = array(); + + if(!is_array($this->defs['panels'][$key])) { + $this->sectionPanels[strtoupper($key)] = $p; + } else { + + foreach($p as $row=>$rowDef) { + $columnsInRows = count($rowDef); + $columnsUsed = 0; + foreach($rowDef as $col => $colDef) { + $panel[$row][$col] = is_array($p[$row][$col]) ? array('field' => $p[$row][$col]) : array('field' => array('name'=>$p[$row][$col])); + $panel[$row][$col]['field']['tabindex'] = (isset($p[$row][$col]['tabindex']) && is_numeric($p[$row][$col]['tabindex'])) ? $p[$row][$col]['tabindex'] : $itemCount; + + if($columnsInRows < $maxColumns) { + if($col == $columnsInRows - 1) { + $panel[$row][$col]['colspan'] = 2 * $maxColumns - ($columnsUsed + 1); + } else { + $panel[$row][$col]['colspan'] = floor(($maxColumns * 2 - $columnsInRows) / $columnsInRows); + $columnsUsed = $panel[$row][$col]['colspan']; + } + } + + //Set address types to have colspan value of 2 if colspan is not already defined + if(is_array($colDef) && !empty($colDef['hideLabel']) && !isset($panel[$row][$col]['colspan'])) { + $panel[$row][$col]['colspan'] = 2; + } + + $itemCount++; + + } //foreach + } //foreach + + // Panel alignment will be off if the panel doesn't have a row with the max columns + // It will not be aligned to the other panels so we fill out the columns in the last row + $addFiller = true; + foreach($panel as $row) { + if(count($row) == $this->defs['templateMeta']['maxColumns']) { + $addFiller = false; + break; + } + } + + if($addFiller) { + $rowCount = count($panel); + $filler = count($panel[$rowCount-1]); + while($filler < $this->defs['templateMeta']['maxColumns']) { + $panel[$rowCount - 1][$filler++] = array('field'=>array('name'=>'')); + } //while + } + + + $this->sectionPanels[strtoupper($key)] = $panel; + } + + + $panelCount++; + } //foreach + } + + function process( + $checkFormName = false, + $formName = '' + ) + { + global $mod_strings, $sugar_config, $app_strings, $app_list_strings; + + //the retrieve already did this work; + //$this->focus->fill_in_relationship_fields(); + + if(!$this->th->checkTemplate($this->module, $this->view, $checkFormName, $formName)){ + $this->render(); + } + if(isset($_REQUEST['offset'])) { + $this->offset = $_REQUEST['offset'] - 1; + } //if + if($this->showVCRControl) { + $this->th->ss->assign('PAGINATION', SugarVCR::menu($this->module, $this->offset, $this->focus->is_AuditEnabled(), ($this->view == 'EditView'))); + } //if + if(isset($_REQUEST['return_module'])) $this->returnModule = $_REQUEST['return_module']; + if(isset($_REQUEST['return_action'])) $this->returnAction = $_REQUEST['return_action']; + if(isset($_REQUEST['return_id'])) $this->returnId = $_REQUEST['return_id']; + if(isset($_REQUEST['return_relationship'])) $this->returnRelationship = $_REQUEST['return_relationship']; + if(isset($_REQUEST['return_name'])) $this->returnName = $this->getValueFromRequest($_REQUEST, 'return_name' ) ; + + // handle Create $module then Cancel + if (empty($this->returnId)) { + $this->returnAction = 'index'; + } + + $is_owner = $this->focus->isOwner($GLOBALS['current_user']->id); + + $this->fieldDefs = array(); + if($this->focus){ + + global $current_user; + + /*if(empty($this->focus->assigned_user_id) ){ + $this->focus->assigned_user_id = $current_user->id; + }*/ + + if(!empty($this->focus->assigned_user_id)) { + + $this->focus->assigned_user_name = get_assigned_user_name($this->focus->assigned_user_id); + } + foreach($this->focus->toArray() as $name => $value) { + + $valueFormatted = false; + //if($this->focus->field_defs[$name]['type']=='link')continue; + + if (!empty($this->fieldDefs[$name]) && !empty($this->fieldDefs[$name]['value'])) + $this->fieldDefs[$name] = array_merge($this->focus->field_defs[$name] , $this->fieldDefs[$name] ) ; + else + $this->fieldDefs[$name] = $this->focus->field_defs[$name]; + + + foreach(array("formula", "default", "comments", "help") as $toEscape) + { + if (!empty($this->fieldDefs[$name][$toEscape])) { + $this->fieldDefs[$name][$toEscape] = htmlentities($this->fieldDefs[$name][$toEscape], ENT_QUOTES, 'UTF-8'); + } + } + + if(isset($this->fieldDefs[$name]['options']) && isset($app_list_strings[$this->fieldDefs[$name]['options']])) { + $this->fieldDefs[$name]['options'] = $app_list_strings[$this->fieldDefs[$name]['options']]; // fill in enums + } //if + + if(isset($this->fieldDefs[$name]['function'])) { + $function = $this->fieldDefs[$name]['function']; + if(is_array($function) && isset($function['name'])){ + $function = $this->fieldDefs[$name]['function']['name']; + }else{ + $function = $this->fieldDefs[$name]['function']; + } + if(!empty($this->fieldDefs[$name]['function']['returns']) && $this->fieldDefs[$name]['function']['returns'] == 'html'){ + if(!empty($this->fieldDefs[$name]['function']['include'])){ + require_once($this->fieldDefs[$name]['function']['include']); + } + $value = $function($this->focus, $name, $value, $this->view); + $valueFormatted = true; + }else{ + $this->fieldDefs[$name]['options'] = $function($this->focus, $name, $value, $this->view); + } + } + + if(isset($this->fieldDefs[$name]['type']) && $this->fieldDefs[$name]['type'] == 'function' && isset($this->fieldDefs[$name]['function_name'])){ + $value = $this->callFunction($this->fieldDefs[$name]); + $valueFormatted = true; + } + + if(!$valueFormatted) { + // $this->focus->format_field($this->focus->field_defs[$name]); + $value = isset($this->focus->$name) ? $this->focus->$name : ''; + } + + if (empty($this->fieldDefs[$name]['value'])) + { + $this->fieldDefs[$name]['value'] = $value; + } + + + //This code is used for QuickCreates that go to Full Form view + if($this->populateBean && empty($this->focus->id) && (isset($this->fieldDefs[$name]['function']['returns']) ? $this->fieldDefs[$name]['function']['returns'] != 'html' : true) && isset($_REQUEST[$name])) { + $this->fieldDefs[$name]['value'] = $this->getValueFromRequest($_REQUEST, $name); + } //if + + /* + * Populate any relate fields that are linked by a relationship to the calling module. + * Clicking the create button on a subpanel for example will populate three values in the $_REQUEST: + * 1. return_module => the name of the calling module + * 2. return_id => the id of the record in the calling module that the user was viewing and that should be associated with this new record + * 3. return_name => the display value of the return_id record - the value to show in any relate field in this EditView + * Only do if this fieldDef does not already have a value; if it does it will have been explicitly set, and that should overrule this less specific mechanism + */ + if (isset($this->returnModule) && isset($this->returnName) && empty($this->focus->id) && empty($this->fieldDefs['name']['value']) ) + { + if ( ($this->focus->field_defs[$name]['type'] == 'relate') && isset($this->focus->field_defs[$name][ 'module' ]) && $this->focus->field_defs[$name][ 'module' ] == $this->returnModule ) + { + if (isset( $this->fieldDefs[$name]['id_name']) + && !empty($this->returnRelationship) + && isset($this->focus->field_defs[$this->fieldDefs[$name]['id_name']]['relationship']) + && ($this->returnRelationship == $this->focus->field_defs[$this->fieldDefs[$name]['id_name']]['relationship'])) + { + $this->fieldDefs[$name]['value'] = $this->returnName ; + // set the hidden id field for this relate field to the correct value i.e., return_id + $this->fieldDefs[$this->fieldDefs[$name]['id_name']]['value'] = $this->returnId ; + } + } + } + + } //foreach + + } //if + + if(isset($this->focus->additional_meta_fields)) { + $this->fieldDefs = array_merge($this->fieldDefs, $this->focus->additional_meta_fields); + } + + if($this->isDuplicate) { + foreach($this->fieldDefs as $name=>$defs) { + if(!empty($defs['auto_increment'])) { + $this->fieldDefs[$name]['value'] = ''; + } + } + } + } + + /** + * display + * This method makes the Smarty variable assignments and then displays the + * generated view. + * @param $showTitle boolean value indicating whether or not to show a title on the resulting page + * @param $ajaxSave boolean value indicating whether or not the operation is an Ajax save request + * @return HTML display for view as String + */ + function display( + $showTitle = true, + $ajaxSave = false + ) + { + global $mod_strings, $sugar_config, $app_strings, $app_list_strings, $theme, $current_user; + + + if(isset($this->defs['templateMeta']['javascript'])) { + if(is_array($this->defs['templateMeta']['javascript'])) { + $this->th->ss->assign('externalJSFile', 'modules/' . $this->module . '/metadata/editvewdefs.js'); + } else { + $this->th->ss->assign('scriptBlocks', $this->defs['templateMeta']['javascript']); + } + } + + $this->th->ss->assign('id', $this->fieldDefs['id']['value']); + $this->th->ss->assign('offset', $this->offset + 1); + $this->th->ss->assign('APP', $app_strings); + $this->th->ss->assign('MOD', $mod_strings); + $this->th->ss->assign('fields', $this->fieldDefs); + $this->th->ss->assign('sectionPanels', $this->sectionPanels); + $this->th->ss->assign('returnModule', $this->returnModule); + $this->th->ss->assign('returnAction', $this->returnAction); + $this->th->ss->assign('returnId', $this->returnId); + $this->th->ss->assign('isDuplicate', $this->isDuplicate); + $this->th->ss->assign('def', $this->defs); + $this->th->ss->assign('useTabs', isset($this->defs['templateMeta']['useTabs']) ? $this->defs['templateMeta']['useTabs'] : false); + $this->th->ss->assign('maxColumns', isset($this->defs['templateMeta']['maxColumns']) ? $this->defs['templateMeta']['maxColumns'] : 2); + $this->th->ss->assign('module', $this->module); + $this->th->ss->assign('headerTpl', isset($this->defs['templateMeta']['form']['headerTpl']) ? $this->defs['templateMeta']['form']['headerTpl'] : 'include/' . $this->view . '/header.tpl'); + $this->th->ss->assign('footerTpl', isset($this->defs['templateMeta']['form']['footerTpl']) ? $this->defs['templateMeta']['form']['footerTpl'] : 'include/' . $this->view . '/footer.tpl'); + $this->th->ss->assign('current_user', $current_user); + $this->th->ss->assign('bean', $this->focus); + $this->th->ss->assign('isAuditEnabled', $this->focus->is_AuditEnabled()); + $this->th->ss->assign('gridline',$current_user->getPreference('gridline') == 'on' ? '1' : '0'); + + global $js_custom_version; + global $sugar_version; + $this->th->ss->assign('SUGAR_VERSION', $sugar_version); + $this->th->ss->assign('JS_CUSTOM_VERSION', $js_custom_version); + + //this is used for multiple forms on one page + if ( !empty($this->formName) ) { + $form_id = $this->formName; + $form_name = $this->formName; + } + else { + $form_id = $this->view; + $form_name = $this->view; + } + if($ajaxSave && empty($this->formName)){ + $form_id = 'form_'.$this->view .'_'.$this->module; + $form_name = $form_id; + $this->view = $form_name; + //$this->defs['templateMeta']['form']['buttons'] = array(); + //$this->defs['templateMeta']['form']['buttons']['ajax_save'] = array('id' => 'AjaxSave', 'customCode'=>''); + } + + $form_name = $form_name == "QuickCreate" ? "QuickCreate_{$this->module}" : $form_name; + $form_id = $form_id == "QuickCreate" ? "QuickCreate_{$this->module}" : $form_id; + + if(isset($this->defs['templateMeta']['preForm'])) { + $this->th->ss->assign('preForm', $this->defs['templateMeta']['preForm']); + } //if + if(isset($this->defs['templateMeta']['form']['closeFormBeforeCustomButtons'])) { + $this->th->ss->assign('closeFormBeforeCustomButtons', $this->defs['templateMeta']['form']['closeFormBeforeCustomButtons']); + } + if(isset($this->defs['templateMeta']['form']['enctype'])) { + $this->th->ss->assign('enctype', 'enctype="'.$this->defs['templateMeta']['form']['enctype'].'"'); + } + //for SugarFieldImage, we must set form enctype to "multipart/form-data" + foreach($this->fieldDefs as $field){ + if(isset($field['type']) && $field['type'] == 'image'){ + $this->th->ss->assign('enctype', 'enctype="multipart/form-data"'); + break; + } + } + $this->th->ss->assign('showDetailData', $this->showDetailData); + $this->th->ss->assign('showSectionPanelsTitles', $this->showSectionPanelsTitles); + $this->th->ss->assign('form_id', $form_id); + $this->th->ss->assign('form_name', $form_name); + $this->th->ss->assign('set_focus_block', get_set_focus_js()); + + $this->th->ss->assign('form', isset($this->defs['templateMeta']['form']) ? $this->defs['templateMeta']['form'] : null); + $this->th->ss->assign('includes', isset($this->defs['templateMeta']['includes']) ? $this->defs['templateMeta']['includes'] : null); + $this->th->ss->assign('view', $this->view); + + //Calculate time & date formatting (may need to calculate this depending on a setting) + global $timedate; + $this->th->ss->assign('CALENDAR_DATEFORMAT', $timedate->get_cal_date_format()); + $this->th->ss->assign('USER_DATEFORMAT', $timedate->get_user_date_format()); + $time_format = $timedate->get_user_time_format(); + $this->th->ss->assign('TIME_FORMAT', $time_format); + + $date_format = $timedate->get_cal_date_format(); + $time_separator = ":"; + if(preg_match('/\d+([^\d])\d+([^\d]*)/s', $time_format, $match)) { + $time_separator = $match[1]; + } + + // Create Smarty variables for the Calendar picker widget + $t23 = strpos($time_format, '23') !== false ? '%H' : '%I'; + if(!isset($match[2]) || $match[2] == '') { + $this->th->ss->assign('CALENDAR_FORMAT', $date_format . ' ' . $t23 . $time_separator . "%M"); + } else { + $pm = $match[2] == "pm" ? "%P" : "%p"; + $this->th->ss->assign('CALENDAR_FORMAT', $date_format . ' ' . $t23 . $time_separator . "%M" . $pm); + } + + $this->th->ss->assign('TIME_SEPARATOR', $time_separator); + + $seps = get_number_seperators(); + $this->th->ss->assign('NUM_GRP_SEP', $seps[0]); + $this->th->ss->assign('DEC_SEP', $seps[1]); + + if($this->view == 'EditView') { + $height = $current_user->getPreference('text_editor_height'); + $width = $current_user->getPreference('text_editor_width'); + $height = isset($height) ? $height : '300px'; + $width = isset($width) ? $width : '95%'; + $this->th->ss->assign('RICH_TEXT_EDITOR_HEIGHT', $height); + $this->th->ss->assign('RICH_TEXT_EDITOR_WIDTH', $width); + } else { + $this->th->ss->assign('RICH_TEXT_EDITOR_HEIGHT', '100px'); + $this->th->ss->assign('RICH_TEXT_EDITOR_WIDTH', '95%'); + } + + + $this->th->ss->assign('SHOW_VCR_CONTROL', $this->showVCRControl); + + //$str=''; + + $str = $this->showTitle($showTitle); + + //Use the output filter to trim the whitespace + $this->th->ss->load_filter('output', 'trimwhitespace'); + $str .= $this->th->displayTemplate($this->module, $form_name, $this->tpl, $ajaxSave, $this->defs); + return $str; + } + + function insertJavascript( + $javascript + ) + { + $this->ss->assign('javascript', $javascript); + } + + function callFunction( + $vardef + ) + { + $can_execute = true; + $execute_function = array(); + $execute_params = array(); + if(!empty($vardef['function_class'])){ + $execute_function[] = $vardef['function_class']; + $execute_function[] = $vardef['function_name']; + }else{ + $execute_function = $vardef['function_name']; + } + foreach($vardef['function_params'] as $param ){ + if (empty($vardef['function_params_source']) or $vardef['function_params_source']=='parent'){ + if(empty($this->focus->$param)){ + $can_execute = false; + }else{ + $execute_params[] = $this->focus->$param; + } + }else if ($vardef['function_params_source']=='this'){ + if(empty($this->focus->$param)){ + $can_execute = false; + }else{ + $execute_params[] = $this->focus->$param; + } + }else{ + $can_execute = false; + } + + } + $value = ''; + if($can_execute){ + if(!empty($vardef['function_require'])){ + require_once($vardef['function_require']); + } + $value = call_user_func_array($execute_function, $execute_params); + } + return $value; + } + + /** + * getValueFromRequest + * This is a helper method to extract a value from the request + * Array. We do some special processing for fields that start + * with 'date_' by checking to see if they also include time + * and meridiem values + * + * @param request The request Array + * @param name The field name to extract value for + * @return String value for given name + */ + function getValueFromRequest( + $request, + $name + ) + { + //Special processing for date values (combine to one field) + if(preg_match('/^date_(.*)$/s', $name, $matches)) { + $d = $request[$name]; + + if(isset($request['time_' . $matches[1]])) { + $d .= ' ' . $request['time_' . $matches[1]]; + if(isset($request[$matches[1] . '_meridiem'])) { + $d .= $request[$matches[1] . '_meridiem']; + } + } else { + if(isset($request['time_hour_' . $matches[1]]) && + isset($request['time_minute_' . $matches[1]])) { + $d .= ' ' . $request['time_hour_' . $matches[1]] . ':' . $request['time_minute_' . $matches[1]]; + } + if(isset($request['meridiem'])) { + $d .= $request['meridiem']; + } + } + return $d; + } + + return $request[$name]; + } + + /** + * Allow Subviews to overwrite this method to show custom titles. + * Examples: Projects & Project Templates. + * params: $showTitle: boolean for backwards compatibility. + */ + public function showTitle( + $showTitle = false + ) + { + global $mod_strings, $app_strings; + + if (is_null($this->viewObject)) + if (!empty($GLOBALS['current_view'])) + $this->viewObject = $GLOBALS['current_view']; + else + $this->viewObject = new SugarView(); + + if ($showTitle) + return $this->viewObject->getModuleTitle(); + + return ''; + } +} \ No newline at end of file diff --git a/include/EditView/PopupQuickCreate.php b/include/EditView/PopupQuickCreate.php new file mode 100644 index 00000000..38351e8b --- /dev/null +++ b/include/EditView/PopupQuickCreate.php @@ -0,0 +1,54 @@ +defaultProcess = false; + parent::SubpanelQuickCreate($module, $view, true); + $this->ev->defs['templateMeta']['form']['buttons'] = array('POPUPSAVE', 'POPUPCANCEL'); + } + + function process($module){ + $form_name = 'form_QuickCreate_' . $module; + $this->ev->formName = $form_name; + $this->ev->process(true, $form_name); + return $this->ev->display(false, true); + } +} +?> \ No newline at end of file diff --git a/include/EditView/QuickCreate.php b/include/EditView/QuickCreate.php new file mode 100644 index 00000000..fb03c37f --- /dev/null +++ b/include/EditView/QuickCreate.php @@ -0,0 +1,77 @@ +ss->assign('ASSIGNED_USER_ID', $current_user->id); + + $this->ss->assign('REQUEST', array_merge($_GET, $_POST)); + $this->ss->assign('CALENDAR_LANG', "en"); + + $date_format = $timedate->get_cal_date_format(); + $this->ss->assign('USER_DATEFORMAT', '('. $timedate->get_user_date_format().')'); + $this->ss->assign('CALENDAR_DATEFORMAT', $date_format); + + $time_format = $timedate->get_user_time_format(); + $time_separator = ":"; + if(preg_match('/\d+([^\d])\d+([^\d]*)/s', $time_format, $match)) { + $time_separator = $match[1]; + } + $t23 = strpos($time_format, '23') !== false ? '%H' : '%I'; + if(!isset($match[2]) || $match[2] == '') { + $this->ss->assign('CALENDAR_FORMAT', $date_format . ' ' . $t23 . $time_separator . "%M"); + } else { + $pm = $match[2] == "pm" ? "%P" : "%p"; + $this->ss->assign('CALENDAR_FORMAT', $date_format . ' ' . $t23 . $time_separator . "%M" . $pm); + } + + + } +} +?> \ No newline at end of file diff --git a/include/EditView/QuickCreate.tpl b/include/EditView/QuickCreate.tpl new file mode 100644 index 00000000..1acebaa3 --- /dev/null +++ b/include/EditView/QuickCreate.tpl @@ -0,0 +1,38 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} +{{include file="/include/EditView/EditView.tpl"}} diff --git a/include/EditView/SubpanelQuickCreate.php b/include/EditView/SubpanelQuickCreate.php new file mode 100644 index 00000000..9680091a --- /dev/null +++ b/include/EditView/SubpanelQuickCreate.php @@ -0,0 +1,121 @@ +ev = new EditView(); + $this->ev->view = $view; + $this->ev->ss = new Sugar_Smarty(); + //$_REQUEST['return_action'] = 'SubPanelViewer'; + $this->ev->setup($module, null, $source); + + $this->ev->defs['templateMeta']['form']['headerTpl'] = 'include/EditView/header.tpl'; + $this->ev->defs['templateMeta']['form']['footerTpl'] = 'include/EditView/footer.tpl'; + $this->ev->defs['templateMeta']['form']['buttons'] = array('SUBPANELSAVE', 'SUBPANELCANCEL', 'SUBPANELFULLFORM'); + + + + $viewEditSource = 'modules/'.$module.'/views/view.edit.php'; + if (file_exists('custom/'. $viewEditSource)) { + $viewEditSource = 'custom/'. $viewEditSource; + } + + if(file_exists($viewEditSource) && !$proccessOverride) { + include($viewEditSource); + $c = $module . 'ViewEdit'; + + if(class_exists($c)) { + $view = new $c; + if($view->useForSubpanel) { + $this->defaultProcess = false; + + //Check if we shold use the module's QuickCreate.tpl file + if($view->useModuleQuickCreateTemplate && file_exists('modules/'.$module.'/tpls/QuickCreate.tpl')) { + $this->ev->defs['templateMeta']['form']['headerTpl'] = 'modules/'.$module.'/tpls/QuickCreate.tpl'; + } + + $view->ev = & $this->ev; + $view->ss = & $this->ev->ss; + $class = $GLOBALS['beanList'][$module]; + if(!empty($GLOBALS['beanFiles'][$class])){ + require_once($GLOBALS['beanFiles'][$class]); + $bean = new $class(); + $view->bean = $bean; + } + $this->ev->formName = 'form_Subpanel'.$this->ev->view .'_'.$module; + $view->showTitle = false; // Do not show title since this is for subpanel + $view->display(); + } + } + } //if + + if($this->defaultProcess && !$proccessOverride) { + $this->process($module); + } + } + + function process($module){ + $form_name = 'form_Subpanel'.$this->ev->view .'_'.$module; + $this->ev->formName = $form_name; + $this->ev->process(true, $form_name); + echo $this->ev->display(false, true); + } +} +?> \ No newline at end of file diff --git a/include/EditView/SugarVCR.php b/include/EditView/SugarVCR.php new file mode 100644 index 00000000..01309dd7 --- /dev/null +++ b/include/EditView/SugarVCR.php @@ -0,0 +1,187 @@ + 1) ? $ids[$offset-1] : ''; + $menu['CURRENT'] = $ids[$offset]; + $menu['NEXT'] = !empty($ids[$offset+1]) ? $ids[$offset+1] : ''; + } + return $menu; + } + + function menu($module, $offset, $isAuditEnabled, $saveAndContinue = false ){ + $html_text = ""; + if($offset < 0) { + $offset = 0; + } + //this check if require in cases when you visit the edit view before visiting that modules list view. + //you can do this easily either from home or activies or sitemap. + $stored_vcr_query=SugarVCR::retrieve($module); + if(!empty($_REQUEST['record']) and !empty($stored_vcr_query) and isset($_REQUEST['offset']) and (empty($_REQUEST['isDuplicate']) or $_REQUEST['isDuplicate'] == 'false')){ // bug 15893 - only show VCR if called as an element in a set of records + //syncing with display offset; + $offset++; + $action = (!empty($_REQUEST['action']) ? $_REQUEST['action'] : 'EditView'); + //$html_text .= "\n"; + //$html_text .= "\n"; + $html_text .= "\n"; + + $list_URL = 'index.php?action=index&module='.$module; + $current_page = floor($offset / 20) * 20; + $list_URL .= '&offset='.$current_page; + + $menu = SugarVCR::play($module, $offset); + if($saveAndContinue){ + if(!empty($menu['NEXT'])){ + $return_action = 'EditView'; + $return_id = $menu['NEXT']; + $list_URL = 'index.php?action=EditView&module='.$module.'&record='.$return_id.'&offset='.($offset+1); + $list_link = ""; + }else + $list_link = ""; + }else + $list_link = ""; + + $previous_link = ""; + $next_link = ""; + if(!empty($menu['PREV'])) { + //$previous_link = "".SugarThemeRegistry::current()->getImage("previous","alt='".$GLOBALS['app_strings']['LNK_LIST_PREVIOUS']."' border='0' align='absmiddle'").' '.$GLOBALS['app_strings']['LNK_LIST_PREVIOUS'].""; + $href = "index.php?module=$module&action=$action&offset=".($offset-1)."&record=".$menu['PREV']; + $previous_link = ""; + } + else + $previous_link = ""; + + if(!empty($menu['NEXT'])) { + //$next_link = "".$GLOBALS['app_strings']['LNK_LIST_NEXT'].' '.SugarThemeRegistry::current()->getImage("next","alt='".$GLOBALS['app_strings']['LNK_LIST_NEXT']."' border='0' align='absmiddle'").""; + $href = "index.php?module=$module&action=$action&offset=".($offset+1)."&record=".$menu['NEXT']; + $next_link = ""; + } + else + $next_link = ""; + + if(!empty($_SESSION[$module. 'total'])){ + $count = $offset .' '. $GLOBALS['app_strings']['LBL_LIST_OF'] . ' ' . $_SESSION[$module. 'total']; + if(!empty($GLOBALS['sugar_config']['disable_count_query']) + && ( ($_SESSION[$module. 'total']-1) % $GLOBALS['sugar_config']['list_max_entries_per_page'] == 0 ) ) { + $count .= '+'; + } + }else{ + $count = $offset; + } + $html_text .= ""; + + + + $html_text .= "
".$list_link."    ".$previous_link."  (".$count.")  ".$next_link."  
";//"; + } + return $html_text; + } + + function record($module, $offset){ + $GLOBALS['log']->debug('SUGARVCR is recording more records'); + $start = max(0, $offset - VCRSTART); + $index = $start; + $db = DBManagerFactory::getInstance(); + + $result = $db->limitQuery(SugarVCR::retrieve($module),$start,($offset+VCREND),false); + $index++; + + $ids = array(); + while(($row = $db->fetchByAssoc($result)) != null){ + $ids[$index] = $row['id']; + $index++; + } + //now that we have the array of ids, store this in the session + $_SESSION[$module.'QUERY_ARRAY'] = $ids; + return $ids; + } + + function recordIDs($module, $rids, $offset, $totalCount){ + $index = $offset; + $index++; + $ids = array(); + foreach($rids as $id){ + $ids[$index] = $id; + $index++; + } + //now that we have the array of ids, store this in the session + $_SESSION[$module.'QUERY_ARRAY'] = $ids; + $_SESSION[$module.'total'] = $totalCount; + } + + function erase($module){ + unset($_SESSION[$module. 'QUERY_ARRAY']); + } + + } +?> diff --git a/include/EditView/footer.tpl b/include/EditView/footer.tpl new file mode 100644 index 00000000..5be507c0 --- /dev/null +++ b/include/EditView/footer.tpl @@ -0,0 +1,64 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} +{{if empty($form.button_location) || $form.button_location == 'bottom'}} +
+{{if !empty($form) && !empty($form.buttons)}} + {{foreach from=$form.buttons key=val item=button}} + {{sugar_button module="$module" id="$button" view="$view"}} + {{/foreach}} +{{else}} +{{sugar_button module="$module" id="SAVE" view="$view" location="FOOTER"}} +{{sugar_button module="$module" id="CANCEL" view="$view" location="FOOTER"}} +{{/if}} +{{if empty($form.hideAudit) || !$form.hideAudit}} +{{sugar_button module="$module" id="Audit" view="$view"}} +{{/if}} +
+{{/if}} + +{{if $externalJSFile}} +require_once("'".$externalJSFile."'"); +{{/if}} + +{$set_focus_block} + +{{if isset($scriptBlocks)}} + +{{$scriptBlocks}} + +{{/if}} diff --git a/include/EditView/header.tpl b/include/EditView/header.tpl new file mode 100644 index 00000000..8b16fbd2 --- /dev/null +++ b/include/EditView/header.tpl @@ -0,0 +1,91 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} +
+
+ + + + + +
+ +{if isset($smarty.request.isDuplicate) && $smarty.request.isDuplicate eq "true"} + + + +{else} + +{/if} + + + + + + + +{if !empty($smarty.request.return_module) || !empty($smarty.request.relate_to)} + + +{/if} + +{{if isset($form.hidden)}} +{{foreach from=$form.hidden item=field}} +{{$field}} +{{/foreach}} +{{/if}} +{{if empty($form.button_location) || $form.button_location == 'top'}} +{{if !empty($form) && !empty($form.buttons)}} + {{foreach from=$form.buttons key=val item=button}} + {{sugar_button module="$module" id="$button" view="$view"}} + {{/foreach}} +{{else}} +{{sugar_button module="$module" id="SAVE" view="$view" location="HEADER"}} +{{sugar_button module="$module" id="CANCEL" view="$view" location="HEADER"}} +{{/if}} +{{if empty($form.hideAudit) || !$form.hideAudit}} +{{sugar_button module="$module" id="Audit" view="$view"}} +{{/if}} +{{/if}} +{{$ADMIN_EDIT}} +{{if $panelCount == 0}} + {{* Render tag for VCR control if SHOW_VCR_CONTROL is true *}} + {{if $SHOW_VCR_CONTROL}} + {$PAGINATION} + {{/if}} +{{/if}} +
\ No newline at end of file diff --git a/include/GroupedTabs/GroupedTabStructure.php b/include/GroupedTabs/GroupedTabStructure.php new file mode 100644 index 00000000..9ecc18a6 --- /dev/null +++ b/include/GroupedTabs/GroupedTabStructure.php @@ -0,0 +1,149 @@ + $subModules) + { + $tabStructure[$mainTab]['modules'] = array_merge($tabStructure[$mainTab]['modules'], $subModules); + } + } + else + { + $tabStructure =& $GLOBALS['tabStructure']; + } + + $retStruct = array(); + $mlhUsed = array(); + //the invisible list should be merged if activities is set to be hidden + if(in_array('Activities', $modList)){ + $modList = array_merge($modList,$modInvisListActivities); + } + + //Add any iFrame tabs to the 'other' group. + $moduleExtraMenu = array(); + if(!should_hide_iframes()) { + $iFrame = new iFrame(); + $frames = $iFrame->lookup_frames('tab'); + foreach($frames as $key => $values){ + $moduleExtraMenu[$key] = $values; + } + } else if(isset($modList['iFrames'])) { + unset($modList['iFrames']); + } + + $modList = array_merge($modList,$moduleExtraMenu); + + /* Only return modules which exists in the modList */ + foreach($tabStructure as $mainTab => $subModules) + { + //Ensure even empty groups are returned + if($labelAsKey){ + $retStruct[$subModules['label']]['modules'] = array(); + }else{ + $retStruct[$app_strings[$subModules['label']]]['modules']= array(); + } + + foreach($subModules['modules'] as $key => $subModule) + { + /* Perform a case-insensitive in_array check + * and mark whichever module matched as used. + */ + foreach($modList as $module) + { + if(is_string($module) && strcasecmp($subModule, $module) === 0) + { + if($labelAsKey){ + $retStruct[$subModules['label']]['modules'][$module] = $app_list_strings['moduleList'][$module]; + }else{ + $retStruct[$app_strings[$subModules['label']]]['modules'][$module] = $app_list_strings['moduleList'][$module]; + } + $mlhUsed[$module] = true; + break; + } + } + } + //remove the group tabs if it has no sub modules under it + if($labelAsKey){ + if (empty($retStruct[$subModules['label']]['modules'])){ + unset($retStruct[$subModules['label']]); + } + }else{ + if (empty($retStruct[$app_strings[$subModules['label']]]['modules'])){ + unset($retStruct[$app_strings[$subModules['label']]]); + } + } + } + +// _pp($retStruct); + return $retStruct; + } +} + +?> diff --git a/include/HTTP_WebDAV_Server/README b/include/HTTP_WebDAV_Server/README new file mode 100644 index 00000000..9847b261 --- /dev/null +++ b/include/HTTP_WebDAV_Server/README @@ -0,0 +1,10 @@ +This code depends on code introduced into the developement branch for +PHP 4.3, so it will not run with PHP releases before 4.3.0 + +preliminary documentation is available in the dav.txt file, +although it is currently a little outdated ... + +Server/Filesystem.php contains a sample implementation for a simple +file server (including property and lock info storage in a mySQL +database, see db/Fileserver.sql). This sample should give you a good +clue about how to use this class for your own purpose. diff --git a/include/HTTP_WebDAV_Server/Server.php b/include/HTTP_WebDAV_Server/Server.php new file mode 100644 index 00000000..b3d46e7d --- /dev/null +++ b/include/HTTP_WebDAV_Server/Server.php @@ -0,0 +1,1873 @@ + | +// | Christian Stocker | +// +----------------------------------------------------------------------+ +// + +// +require_once "include/HTTP_WebDAV_Server/Tools/_parse_propfind.php"; +require_once "include/HTTP_WebDAV_Server/Tools/_parse_proppatch.php"; +require_once "include/HTTP_WebDAV_Server/Tools/_parse_lockinfo.php"; + + + +/** + * Virtual base class for implementing WebDAV servers + * + * WebDAV server base class, needs to be extended to do useful work + * + * @package HTTP_WebDAV_Server + * @author Hartmut Holzgraefe + * @version 0.99.1dev + */ +class HTTP_WebDAV_Server +{ + // {{{ Member Variables + + /** + * URI path for this request + * + * @var string + */ + var $path; + + /** + * Realm string to be used in authentification popups + * + * @var string + */ + var $http_auth_realm = "PHP WebDAV"; + + /** + * String to be used in "X-Dav-Powered-By" header + * + * @var string + */ + var $dav_powered_by = ""; + + /** + * Remember parsed If: (RFC2518/9.4) header conditions + * + * @var array + */ + var $_if_header_uris = array(); + + /** + * HTTP response status/message + * + * @var string + */ + var $_http_status = "200 OK"; + + /** + * encoding of property values passed in + * + * @var string + */ + var $_prop_encoding = "utf-8"; + + // }}} + + // {{{ Constructor + + /** + * Constructor + * + * @param void + */ + function HTTP_WebDAV_Server() + { + // PHP messages destroy XML output -> switch them off + ini_set("display_errors", 0); + } + + // }}} + + // {{{ ServeRequest() + /** + * Serve WebDAV HTTP request + * + * dispatch WebDAV HTTP request to the apropriate method handler + * + * @param void + * @return void + */ + function ServeRequest() + { + // identify ourselves + if (empty($this->dav_powered_by)) { + header("X-Dav-Powered-By: PHP class: ".get_class($this)); + } else { + header("X-Dav-Powered-By: ".$this->dav_powered_by ); + } + + // check authentication + if (!$this->_check_auth()) { + $this->http_status('401 Unauthorized'); + + // RFC2518 says we must use Digest instead of Basic + // but Microsoft Clients do not support Digest + // and we don't support NTLM and Kerberos + // so we are stuck with Basic here + header('WWW-Authenticate: Basic realm="'.($this->http_auth_realm).'"'); + + return; + } + + // check + if(! $this->_check_if_header_conditions()) { + $this->http_status("412 Precondition failed"); + return; + } + + // set path + $this->path = $this->_urldecode(!empty($_SERVER["PATH_INFO"]) ? $_SERVER["PATH_INFO"] : "/"); + if(ini_get("magic_quotes_gpc")) { + $this->path = stripslashes($this->path); + } + + + // detect requested method names + $method = strtolower($_SERVER["REQUEST_METHOD"]); + $wrapper = "http_".$method; + + // activate HEAD emulation by GET if no HEAD method found + if ($method == "head" && !method_exists($this, "head")) { + $method = "get"; + } + + if (method_exists($this, $wrapper) && ($method == "options" || method_exists($this, $method))) { + $this->$wrapper(); // call method by name + } else { // method not found/implemented + if ($_SERVER["REQUEST_METHOD"] == "LOCK") { + $this->http_status("412 Precondition failed"); + } else { + $this->http_status("405 Method not allowed"); + header("Allow: ".join(", ", $this->_allow())); // tell client what's allowed + } + } + } + + // }}} + + // {{{ abstract WebDAV methods + + // {{{ GET() + /** + * GET implementation + * + * overload this method to retrieve resources from your server + *
+ * + * + * @abstract + * @param array &$params Array of input and output parameters + *
input
    + *
  • path - + *
+ *
output
    + *
  • size - + *
+ * @returns int HTTP-Statuscode + */ + + /* abstract + function GET(&$params) + { + // dummy entry for PHPDoc + } + */ + + // }}} + + // {{{ PUT() + /** + * PUT implementation + * + * PUT implementation + * + * @abstract + * @param array &$params + * @returns int HTTP-Statuscode + */ + + /* abstract + function PUT() + { + // dummy entry for PHPDoc + } + */ + + // }}} + + // {{{ COPY() + + /** + * COPY implementation + * + * COPY implementation + * + * @abstract + * @param array &$params + * @returns int HTTP-Statuscode + */ + + /* abstract + function COPY() + { + // dummy entry for PHPDoc + } + */ + + // }}} + + // {{{ MOVE() + + /** + * MOVE implementation + * + * MOVE implementation + * + * @abstract + * @param array &$params + * @returns int HTTP-Statuscode + */ + + /* abstract + function MOVE() + { + // dummy entry for PHPDoc + } + */ + + // }}} + + // {{{ DELETE() + + /** + * DELETE implementation + * + * DELETE implementation + * + * @abstract + * @param array &$params + * @returns int HTTP-Statuscode + */ + + /* abstract + function DELETE() + { + // dummy entry for PHPDoc + } + */ + // }}} + + // {{{ PROPFIND() + + /** + * PROPFIND implementation + * + * PROPFIND implementation + * + * @abstract + * @param array &$params + * @returns int HTTP-Statuscode + */ + + /* abstract + function PROPFIND() + { + // dummy entry for PHPDoc + } + */ + + // }}} + + // {{{ PROPPATCH() + + /** + * PROPPATCH implementation + * + * PROPPATCH implementation + * + * @abstract + * @param array &$params + * @returns int HTTP-Statuscode + */ + + /* abstract + function PROPPATCH() + { + // dummy entry for PHPDoc + } + */ + // }}} + + // {{{ LOCK() + + /** + * LOCK implementation + * + * LOCK implementation + * + * @abstract + * @param array &$params + * @returns int HTTP-Statuscode + */ + + /* abstract + function LOCK() + { + // dummy entry for PHPDoc + } + */ + // }}} + + // {{{ UNLOCK() + + /** + * UNLOCK implementation + * + * UNLOCK implementation + * + * @abstract + * @param array &$params + * @returns int HTTP-Statuscode + */ + + /* abstract + function UNLOCK() + { + // dummy entry for PHPDoc + } + */ + // }}} + + // }}} + + // {{{ other abstract methods + + // {{{ check_auth() + + /** + * check authentication + * + * overload this method to retrieve and confirm authentication information + * + * @abstract + * @param string type Authentication type, e.g. "basic" or "digest" + * @param string username Transmitted username + * @param string passwort Transmitted password + * @returns bool Authentication status + */ + + /* abstract + function checkAuth($type, $username, $password) + { + // dummy entry for PHPDoc + } + */ + + // }}} + + // {{{ checklock() + + /** + * check lock status for a resource + * + * overload this method to return shared and exclusive locks + * active for this resource + * + * @abstract + * @param string resource Resource path to check + * @returns array An array of lock entries each consisting + * of 'type' ('shared'/'exclusive'), 'token' and 'timeout' + */ + + /* abstract + function checklock($resource) + { + // dummy entry for PHPDoc + } + */ + + // }}} + + // }}} + + // {{{ WebDAV HTTP method wrappers + + // {{{ http_OPTIONS() + + /** + * OPTIONS method handler + * + * The OPTIONS method handler creates a valid OPTIONS reply + * including Dav: and Allowed: heaers + * based on the implemented methods found in the actual instance + * + * @param void + * @return void + */ + function http_OPTIONS() + { + // Microsoft clients default to the Frontpage protocol + // unless we tell them to use WebDAV + header("MS-Author-Via: DAV"); + + // get allowed methods + $allow = $this->_allow(); + + // dav header + $dav = array(1); // assume we are always dav class 1 compliant + if (isset($allow['LOCK'])) { + $dav[] = 2; // dav class 2 requires that locking is supported + } + + // tell clients what we found + $this->http_status("200 OK"); + header("DAV: " .join("," , $dav)); + header("Allow: ".join(", ", $allow)); + } + + // }}} + + + // {{{ http_PROPFIND() + + /** + * PROPFIND method handler + * + * @param void + * @return void + */ + function http_PROPFIND() + { + $options = Array(); + $options["path"] = $this->path; + + // search depth from header (default is "infinity) + if (isset($_SERVER['HTTP_DEPTH'])) { + $options["depth"] = $_SERVER["HTTP_DEPTH"]; + } else { + $options["depth"] = "infinity"; + } + + // analyze request payload + $propinfo = new _parse_propfind("php://input"); + if (!$propinfo->success) { + $this->http_status("400 Error"); + return; + } + $options['props'] = $propinfo->props; + + // call user handler + if (!$this->propfind($options, $files)) { + $this->http_status("404 Not Found"); + return; + } + + // collect namespaces here + $ns_hash = array(); + + // Microsoft Clients need this special namespace for date and time values + $ns_defs = "xmlns:ns0=\"urn:uuid:c2f41010-65b3-11d1-a29f-00aa00c14882/\""; + + // now we loop over all returned file entries + foreach($files["files"] as $filekey => $file) { + + // nothing to do if no properties were returend for a file + if (!isset($file["props"]) || !is_array($file["props"])) { + continue; + } + + // now loop over all returned properties + foreach($file["props"] as $key => $prop) { + // as a convenience feature we do not require that user handlers + // restrict returned properties to the requested ones + // here we strip all unrequested entries out of the response + + switch($options['props']) { + case "all": + // nothing to remove + break; + + case "names": + // only the names of all existing properties were requested + // so we remove all values + unset($files["files"][$filekey]["props"][$key]["val"]); + break; + + default: + $found = false; + + // search property name in requested properties + foreach((array)$options["props"] as $reqprop) { + if ( $reqprop["name"] == $prop["name"] + && $reqprop["xmlns"] == $prop["ns"]) { + $found = true; + break; + } + } + + // unset property and continue with next one if not found/requested + if (!$found) { + $files["files"][$filekey]["props"][$key]=""; + continue(2); + } + break; + } + + // namespace handling + if (empty($prop["ns"])) continue; // no namespace + $ns = $prop["ns"]; + if ($ns == "DAV:") continue; // default namespace + if (isset($ns_hash[$ns])) continue; // already known + + // register namespace + $ns_name = "ns".(count($ns_hash) + 1); + $ns_hash[$ns] = $ns_name; + $ns_defs .= " xmlns:$ns_name=\"$ns\""; + } + + // we also need to add empty entries for properties that were requested + // but for which no values where returned by the user handler + if (is_array($options['props'])) { + foreach($options["props"] as $reqprop) { + if($reqprop['name']=="") continue; // skip empty entries + + $found = false; + + // check if property exists in result + foreach($file["props"] as $prop) { + if ( $reqprop["name"] == $prop["name"] + && $reqprop["xmlns"] == $prop["ns"]) { + $found = true; + break; + } + } + + if (!$found) { + if($reqprop["xmlns"]==="DAV:" && $reqprop["name"]==="lockdiscovery") { + // lockdiscovery is handled by the base class + $files["files"][$filekey]["props"][] + = $this->mkprop("DAV:", + "lockdiscovery" , + $this->lockdiscovery($files["files"][$filekey]['path'])); + } else { + // add empty value for this property + $files["files"][$filekey]["noprops"][] = + $this->mkprop($reqprop["xmlns"], $reqprop["name"], ""); + + // register property namespace if not known yet + if ($reqprop["xmlns"] != "DAV:" && !isset($ns_hash[$reqprop["xmlns"]])) { + $ns_name = "ns".(count($ns_hash) + 1); + $ns_hash[$reqprop["xmlns"]] = $ns_name; + $ns_defs .= " xmlns:$ns_name=\"$reqprop[xmlns]\""; + } + } + } + } + } + } + + // now we generate the reply header ... + $this->http_status("207 Multi-Status"); + header('Content-Type: text/xml; charset="utf-8"'); + + // ... and payload + echo "\n"; + echo "\n"; + + foreach($files["files"] as $file) { + // ignore empty or incomplete entries + if(!is_array($file) || empty($file) || !isset($file["path"])) continue; + $path = $file['path']; + if(!is_string($path) || $path==="") continue; + + echo " \n"; + + $href = (@$_SERVER["HTTPS"] === "on" ? "https:" : "http:"); + $href.= "//".$_SERVER['HTTP_HOST'].$_SERVER['SCRIPT_NAME']; + $href.= $path; + //TODO make sure collection resource pathes end in a trailing slash + + echo " $href\n"; + + // report all found properties and their values (if any) + if (isset($file["props"]) && is_array($file["props"])) { + echo " \n"; + echo " \n"; + + foreach($file["props"] as $key => $prop) { + + if (!is_array($prop)) continue; + if (!isset($prop["name"])) continue; + + if (!isset($prop["val"]) || $prop["val"] === "" || $prop["val"] === false) { + // empty properties (cannot use empty() for check as "0" is a legal value here) + if($prop["ns"]=="DAV:") { + echo " \n"; + } else if(!empty($prop["ns"])) { + echo " <".$ns_hash[$prop["ns"]].":$prop[name]/>\n"; + } else { + echo " <$prop[name] xmlns=\"\"/>"; + } + } else if ($prop["ns"] == "DAV:") { + // some WebDAV properties need special treatment + switch ($prop["name"]) { + case "creationdate": + echo " " + . gmdate("Y-m-d\\TH:i:s\\Z",$prop['val']) + . "\n"; + break; + case "getlastmodified": + echo " " + . TimeDate::httptime($prop['val']) + . "\n"; + break; + case "resourcetype": + echo " \n"; + break; + case "supportedlock": + echo " $prop[val]\n"; + break; + case "lockdiscovery": + echo " \n"; + echo $prop["val"]; + echo " \n"; + break; + default: + echo " " + . $this->_prop_encode(htmlspecialchars($prop['val'])) + . "\n"; + break; + } + } else { + // properties from namespaces != "DAV:" or without any namespace + if ($prop["ns"]) { + echo " <" . $ns_hash[$prop["ns"]] . ":$prop[name]>" + . $this->_prop_encode(htmlspecialchars($prop['val'])) + . "\n"; + } else { + echo " <$prop[name] xmlns=\"\">" + . $this->_prop_encode(htmlspecialchars($prop['val'])) + . "\n"; + } + } + } + + echo " \n"; + echo " HTTP/1.1 200 OK\n"; + echo " \n"; + } + + // now report all properties requested bot not found + if (isset($file["noprops"])) { + echo " \n"; + echo " \n"; + + foreach($file["noprops"] as $key => $prop) { + if ($prop["ns"] == "DAV:") { + echo " \n"; + } else if ($prop["ns"] == "") { + echo " <$prop[name] xmlns=\"\"/>\n"; + } else { + echo " <" . $ns_hash[$prop["ns"]] . ":$prop[name]/>\n"; + } + } + + echo " \n"; + echo " HTTP/1.1 404 Not Found\n"; + echo " \n"; + } + + echo " \n"; + } + + echo "\n"; + } + + + // }}} + + // {{{ http_PROPPATCH() + + /** + * PROPPATCH method handler + * + * @param void + * @return void + */ + function http_PROPPATCH() + { + if($this->_check_lock_status($this->path)) { + $options = Array(); + $options["path"] = $this->path; + + $propinfo = new _parse_proppatch("php://input"); + + if (!$propinfo->success) { + $this->http_status("400 Error"); + return; + } + + $options['props'] = $propinfo->props; + + $responsedescr = $this->proppatch($options); + + $this->http_status("207 Multi-Status"); + header('Content-Type: text/xml; charset="utf-8"'); + + echo "\n"; + + echo "\n"; + echo " \n"; + echo " ".$this->_urlencode($_SERVER["SCRIPT_NAME"].$this->path)."\n"; + + foreach($options["props"] as $prop) { + echo " \n"; + echo " <$prop[name] xmlns=\"$prop[ns]\"/>\n"; + echo " HTTP/1.1 $prop[status]\n"; + echo " \n"; + } + + if ($responsedescr) { + echo " ". + $this->_prop_encode(htmlspecialchars($responsedescr)). + "\n"; + } + + echo " \n"; + echo "\n"; + } else { + $this->http_status("423 Locked"); + } + } + + // }}} + + + // {{{ http_MKCOL() + + /** + * MKCOL method handler + * + * @param void + * @return void + */ + function http_MKCOL() + { + $options = Array(); + $options["path"] = $this->path; + + $stat = $this->mkcol($options); + + $this->http_status($stat); + } + + // }}} + + + // {{{ http_GET() + + /** + * GET method handler + * + * @param void + * @returns void + */ + function http_GET() + { + // TODO check for invalid stream + $options = Array(); + $options["path"] = $this->path; + + $this->_get_ranges($options); + + if (true === ($status = $this->get($options))) { + if (!headers_sent()) { + $status = "200 OK"; + + if (!isset($options['mimetype'])) { + $options['mimetype'] = "application/octet-stream"; + } + header("Content-type: $options[mimetype]"); + + if (isset($options['mtime'])) { + header("Last-modified: ".TimeDate::httpTime()); + } + + if (isset($options['stream'])) { + // GET handler returned a stream + if (!empty($options['ranges']) && (0===fseek($options['stream'], 0, SEEK_SET))) { + // partial request and stream is seekable + + if (count($options['ranges']) === 1) { + $range = $options['ranges'][0]; + + if (isset($range['start'])) { + fseek($options['stream'], $range['start'], SEEK_SET); + if (feof($options['stream'])) { + http_status("416 Requested range not satisfiable"); + exit; + } + + if (isset($range['end'])) { + $size = $range['end']-$range['start']+1; + http_status("206 partial"); + header("Content-length: $size"); + header("Content-range: $range[start]-$range[end]/" + . (isset($options['size']) ? $options['size'] : "*")); + while ($size && !feof($options['stream'])) { + $buffer = fread($options['stream'], 4096); + $size -= strlen($buffer); + echo $buffer; + } + } else { + http_status("206 partial"); + if (isset($options['size'])) { + header("Content-length: ".($options['size'] - $range['start'])); + header("Content-range: $start-$end/" + . (isset($options['size']) ? $options['size'] : "*")); + } + fpassthru($options['stream']); + } + } else { + header("Content-length: ".$range['last']); + fseek($options['stream'], -$range['last'], SEEK_END); + fpassthru($options['stream']); + } + } else { + $this->_multipart_byterange_header(); // init multipart + foreach ($options['ranges'] as $range) { + // TODO what if size unknown? 500? + if (isset($range['start'])) { + $from = $range['start']; + $to = !empty($range['end']) ? $range['end'] : $options['size']-1; + } else { + $from = $options['size'] - $range['last']-1; + $to = $options['size'] -1; + } + $total = isset($options['size']) ? $options['size'] : "*"; + $size = $to - $from + 1; + $this->_multipart_byterange_header($options['mimetype'], $from, $to, $total); + + + fseek($options['stream'], $start, SEEK_SET); + while ($size && !feof($options['stream'])) { + $buffer = fread($options['stream'], 4096); + $size -= strlen($buffer); + echo $buffer; + } + } + $this->_multipart_byterange_header(); // end multipart + } + } else { + // normal request or stream isn't seekable, return full content + if (isset($options['size'])) { + header("Content-length: ".$options['size']); + } + fpassthru($options['stream']); + return; // no more headers + } + } elseif (isset($options['data'])) { + if (is_array($options['data'])) { + // reply to partial request + } else { + header("Content-length: ".strlen($options['data'])); + echo $options['data']; + } + } + } + } + + if (false === $status) { + $this->http_status("404 not found"); + } + + $this->http_status("$status"); + } + + + /** + * parse HTTP Range: header + * + * @param array options array to store result in + * @return void + */ + function _get_ranges(&$options) + { + // process Range: header if present + if (isset($_SERVER['HTTP_RANGE'])) { + + // we only support standard "bytes" range specifications for now + if (preg_match("/bytes[[:space:]]*=[[:space:]]*(.+)/", $_SERVER['HTTP_RANGE'], $matches)) { + $options["ranges"] = array(); + + // ranges are comma separated + foreach (explode(",", $matches[1]) as $range) { + // ranges are either from-to pairs or just end positions + list($start, $end) = explode("-", $range); + $options["ranges"][] = ($start==="") + ? array("last"=>$end) + : array("start"=>$start, "end"=>$end); + } + } + } + } + + /** + * generate separator headers for multipart response + * + * first and last call happen without parameters to generate + * the initial header and closing sequence, all calls inbetween + * require content mimetype, start and end byte position and + * optionaly the total byte length of the requested resource + * + * @param string mimetype + * @param int start byte position + * @param int end byte position + * @param int total resource byte size + */ + function _multipart_byterange_header($mimetype = false, $from = false, $to=false, $total=false) + { + if ($mimetype === false) { + if (!isset($this->multipart_separator)) { + // initial + + // a little naive, this sequence *might* be part of the content + // but it's really not likely and rather expensive to check + $this->multipart_separator = "SEPARATOR_".md5(microtime()); + + // generate HTTP header + header("Content-type: multipart/byteranges; boundary=".$this->multipart_separator); + } else { + // final + + // generate closing multipart sequence + echo "\n--{$this->multipart_separator}--"; + } + } else { + // generate separator and header for next part + echo "\n--{$this->multipart_separator}\n"; + echo "Content-type: $mimetype\n"; + echo "Content-range: $from-$to/". ($total === false ? "*" : $total); + echo "\n\n"; + } + } + + + + // }}} + + // {{{ http_HEAD() + + /** + * HEAD method handler + * + * @param void + * @return void + */ + function http_HEAD() + { + $status = false; + $options = Array(); + $options["path"] = $this->path; + + if (method_exists($this, "HEAD")) { + $status = $this->head($options); + } else if (method_exists($this, "GET")) { + ob_start(); + $status = $this->GET($options); + ob_end_clean(); + } + + if($status===true) $status = "200 OK"; + if($status===false) $status = "404 Not found"; + + $this->http_status($status); + } + + // }}} + + // {{{ http_PUT() + + /** + * PUT method handler + * + * @param void + * @return void + */ + function http_PUT() + { + if ($this->_check_lock_status($this->path)) { + $options = Array(); + $options["path"] = $this->path; + $options["content_length"] = $_SERVER["CONTENT_LENGTH"]; + + // get the Content-type + if (isset($_SERVER["CONTENT_TYPE"])) { + // for now we do not support any sort of multipart requests + if (!strncmp($_SERVER["CONTENT_TYPE"], "multipart/", 10)) { + $this->http_status("501 not implemented"); + echo "The service does not support mulipart PUT requests"; + return; + } + $options["content_type"] = $_SERVER["CONTENT_TYPE"]; + } else { + // default content type if none given + $options["content_type"] = "application/octet-stream"; + } + + /* RFC 2616 2.6 says: "The recipient of the entity MUST NOT + ignore any Content-* (e.g. Content-Range) headers that it + does not understand or implement and MUST return a 501 + (Not Implemented) response in such cases." + */ + foreach ($_SERVER as $key => $val) { + if (strncmp($key, "HTTP_CONTENT", 11)) continue; + switch ($key) { + case 'HTTP_CONTENT_ENCODING': // RFC 2616 14.11 + // TODO support this if ext/zlib filters are available + $this->http_status("501 not implemented"); + echo "The service does not support '$val' content encoding"; + return; + + case 'HTTP_CONTENT_LANGUAGE': // RFC 2616 14.12 + // we assume it is not critical if this one is ignored + // in the actual PUT implementation ... + $options["content_language"] = $value; + break; + + case 'HTTP_CONTENT_LOCATION': // RFC 2616 14.14 + /* The meaning of the Content-Location header in PUT + or POST requests is undefined; servers are free + to ignore it in those cases. */ + break; + + case 'HTTP_CONTENT_RANGE': // RFC 2616 14.16 + // single byte range requests are supported + // the header format is also specified in RFC 2616 14.16 + // TODO we have to ensure that implementations support this or send 501 instead + if (!preg_match('@bytes\s+(\d+)-(\d+)/((\d+)|\*)@', $value, $matches)) { + $this->http_status("400 bad request"); + echo "The service does only support single byte ranges"; + return; + } + + $range = array("start"=>$matches[1], "end"=>$matches[2]); + if (is_numeric($matches[3])) { + $range["total_length"] = $matches[3]; + } + $option["ranges"][] = $range; + + // TODO make sure the implementation supports partial PUT + // this has to be done in advance to avoid data being overwritten + // on implementations that do not support this ... + break; + + case 'HTTP_CONTENT_MD5': // RFC 2616 14.15 + // TODO: maybe we can just pretend here? + $this->http_status("501 not implemented"); + echo "The service does not support content MD5 checksum verification"; + return; + + default: + // any other unknown Content-* headers + $this->http_status("501 not implemented"); + echo "The service does not support '$key'"; + return; + } + } + + $options["stream"] = fopen("php://input", "r"); + + $stat = $this->PUT($options); + + if (is_resource($stat) && get_resource_type($stat) == "stream") { + $stream = $stat; + if (!empty($options["ranges"])) { + // TODO multipart support is missing (see also above) + // TODO error checking + $stat = fseek($stream, $range[0]["start"], SEEK_SET); + fwrite($stream, fread($options["stream"], $range[0]["end"]-$range[0]["start"]+1)); + } else { + while (!feof($options["stream"])) { + fwrite($stream, fread($options["stream"], 4096)); + } + } + fclose($stream); + + $stat = $options["new"] ? "201 Created" : "204 No Content"; + } + + $this->http_status($stat); + } else { + $this->http_status("423 Locked"); + } + } + + // }}} + + + // {{{ http_DELETE() + + /** + * DELETE method handler + * + * @param void + * @return void + */ + function http_DELETE() + { + // check RFC 2518 Section 9.2, last paragraph + if (isset($_SERVER["HTTP_DEPTH"])) { + if ($_SERVER["HTTP_DEPTH"] != "infinity") { + $this->http_status("400 Bad Request"); + return; + } + } + + // check lock status + if ($this->_check_lock_status($this->path)) { + // ok, proceed + $options = Array(); + $options["path"] = $this->path; + + $stat = $this->delete($options); + + $this->http_status($stat); + } else { + // sorry, its locked + $this->http_status("423 Locked"); + } + } + + // }}} + + // {{{ http_COPY() + + /** + * COPY method handler + * + * @param void + * @return void + */ + function http_COPY() + { + // no need to check source lock status here + // destination lock status is always checked by the helper method + $this->_copymove("copy"); + } + + // }}} + + // {{{ http_MOVE() + + /** + * MOVE method handler + * + * @param void + * @return void + */ + function http_MOVE() + { + if ($this->_check_lock_status($this->path)) { + // destination lock status is always checked by the helper method + $this->_copymove("move"); + } else { + $this->http_status("423 Locked"); + } + } + + // }}} + + + // {{{ http_LOCK() + + /** + * LOCK method handler + * + * @param void + * @return void + */ + function http_LOCK() + { + $options = Array(); + $options["path"] = $this->path; + + if (isset($_SERVER['HTTP_DEPTH'])) { + $options["depth"] = $_SERVER["HTTP_DEPTH"]; + } else { + $options["depth"] = "infinity"; + } + + if (isset($_SERVER["HTTP_TIMEOUT"])) { + $options["timeout"] = explode(",", $_SERVER["HTTP_TIMEOUT"]); + } + + if(empty($_SERVER['CONTENT_LENGTH']) && !empty($_SERVER['HTTP_IF'])) { + // check if locking is possible + if(!$this->_check_lock_status($this->path)) { + $this->http_status("423 Locked"); + return; + } + + // refresh lock + $options["update"] = substr($_SERVER['HTTP_IF'], 2, -2); + $stat = $this->lock($options); + } else { + // extract lock request information from request XML payload + $lockinfo = new _parse_lockinfo("php://input"); + if (!$lockinfo->success) { + $this->http_status("400 bad request"); + } + + // check if locking is possible + if(!$this->_check_lock_status($this->path, $lockinfo->lockscope === "shared")) { + $this->http_status("423 Locked"); + return; + } + + // new lock + $options["scope"] = $lockinfo->lockscope; + $options["type"] = $lockinfo->locktype; + $options["owner"] = $lockinfo->owner; + + $options["locktoken"] = $this->_new_locktoken(); + + $stat = $this->lock($options); + } + + if(is_bool($stat)) { + $http_stat = $stat ? "200 OK" : "423 Locked"; + } else { + $http_stat = $stat; + } + + $this->http_status($http_stat); + + if ($http_stat{0} == 2) { // 2xx states are ok + if($options["timeout"]) { + // more than a million is considered an absolute timestamp + // less is more likely a relative value + if($options["timeout"]>1000000) { + $timeout = "Second-".($options['timeout']-time()); + } else { + $timeout = "Second-$options[timeout]"; + } + } else { + $timeout = "Infinite"; + } + + header('Content-Type: text/xml; charset="utf-8"'); + header("Lock-Token: <$options[locktoken]>"); + echo "\n"; + echo "\n"; + echo " \n"; + echo " \n"; + echo " \n"; + echo " \n"; + echo " $options[depth]\n"; + echo " $options[owner]\n"; + echo " $timeout\n"; + echo " $options[locktoken]\n"; + echo " \n"; + echo " \n"; + echo "\n\n"; + } + } + + + // }}} + + // {{{ http_UNLOCK() + + /** + * UNLOCK method handler + * + * @param void + * @return void + */ + function http_UNLOCK() + { + $options = Array(); + $options["path"] = $this->path; + + if (isset($_SERVER['HTTP_DEPTH'])) { + $options["depth"] = $_SERVER["HTTP_DEPTH"]; + } else { + $options["depth"] = "infinity"; + } + + // strip surrounding <> + $options["token"] = substr(trim($_SERVER["HTTP_LOCK_TOKEN"]), 1, -1); + + // call user method + $stat = $this->unlock($options); + + $this->http_status($stat); + } + + // }}} + + // }}} + + // {{{ _copymove() + + function _copymove($what) + { + $options = Array(); + $options["path"] = $this->path; + + if (isset($_SERVER["HTTP_DEPTH"])) { + $options["depth"] = $_SERVER["HTTP_DEPTH"]; + } else { + $options["depth"] = "infinity"; + } + + extract(parse_url($_SERVER["HTTP_DESTINATION"])); + $http_host = $host; + if (isset($port) && $port != 80) + $http_host.= ":$port"; + + list($http_header_host,$http_header_port) = explode(":",$_SERVER["HTTP_HOST"]); + if (isset($http_header_port) && $http_header_port != 80) { + $http_header_host .= ":".$http_header_port; + } + + if ($http_host == $http_header_host && + !strncmp($_SERVER["SCRIPT_NAME"], $path, + strlen($_SERVER["SCRIPT_NAME"]))) { + $options["dest"] = substr($path, strlen($_SERVER["SCRIPT_NAME"])); + if (!$this->_check_lock_status($options["dest"])) { + $this->http_status("423 Locked"); + return; + } + + } else { + $options["dest_url"] = $_SERVER["HTTP_DESTINATION"]; + } + + // see RFC 2518 Sections 9.6, 8.8.4 and 8.9.3 + if (isset($_SERVER["HTTP_OVERWRITE"])) { + $options["overwrite"] = $_SERVER["HTTP_OVERWRITE"] == "T"; + } else { + $options["overwrite"] = true; + } + + $stat = $this->$what($options); + $this->http_status($stat); + } + + // }}} + + // {{{ _allow() + + /** + * check for implemented HTTP methods + * + * @param void + * @return array something + */ + function _allow() + { + // OPTIONS is always there + $allow = array("OPTIONS" =>"OPTIONS"); + + // all other METHODS need both a http_method() wrapper + // and a method() implementation + // the base class supplies wrappers only + foreach(get_class_methods($this) as $method) { + if (!strncmp("http_", $method, 5)) { + $method = strtoupper(substr($method, 5)); + if (method_exists($this, $method)) { + $allow[$method] = $method; + } + } + } + + // we can emulate a missing HEAD implemetation using GET + if (isset($allow["GET"])) + $allow["HEAD"] = "HEAD"; + + // no LOCK without checklok() + if (!method_exists($this, "checklock")) { + unset($allow["LOCK"]); + unset($allow["UNLOCK"]); + } + + return $allow; + } + + // }}} + + /** + * helper for property element creation + * + * @param string XML namespace (optional) + * @param string property name + * @param string property value + * @return array property array + */ + function mkprop() + { + $args = func_get_args(); + if (count($args) == 3) { + return array("ns" => $args[0], + "name" => $args[1], + "val" => $args[2]); + } else { + return array("ns" => "DAV:", + "name" => $args[0], + "val" => $args[1]); + } + } + + // {{{ _check_auth + + /** + * check authentication if check is implemented + * + * @param void + * @return bool true if authentication succeded or not necessary + */ + function _check_auth() + { + if (method_exists($this, "checkAuth")) { + // PEAR style method name + return $this->checkAuth(@$_SERVER["AUTH_TYPE"], + @$_SERVER["PHP_AUTH_USER"], + @$_SERVER["PHP_AUTH_PW"]); + } else if (method_exists($this, "check_auth")) { + // old (pre 1.0) method name + return $this->check_auth(@$_SERVER["AUTH_TYPE"], + @$_SERVER["PHP_AUTH_USER"], + @$_SERVER["PHP_AUTH_PW"]); + } else { + // no method found -> no authentication required + return true; + } + } + + // }}} + + // {{{ UUID stuff + + /** + * generate Unique Universal IDentifier for lock token + * + * @param void + * @return string a new UUID + */ + function _new_uuid() + { + // use uuid extension from PECL if available + if (function_exists("uuid_create")) { + return uuid_create(); + } + + // fallback + $uuid = md5(microtime().getmypid()); // this should be random enough for now + + // set variant and version fields for 'true' random uuid + $uuid{12} = "4"; + $n = 8 + (ord($uuid{16}) & 3); + $hex = "0123456789abcdef"; + $uuid{16} = $hex{$n}; + + // return formated uuid + return substr($uuid, 0, 8)."-" + . substr($uuid, 8, 4)."-" + . substr($uuid, 12, 4)."-" + . substr($uuid, 16, 4)."-" + . substr($uuid, 20); + } + + /** + * create a new opaque lock token as defined in RFC2518 + * + * @param void + * @return string new RFC2518 opaque lock token + */ + function _new_locktoken() + { + return "opaquelocktoken:".$this->_new_uuid(); + } + + // }}} + + // {{{ WebDAV If: header parsing + + /** + * + * + * @param string header string to parse + * @param int current parsing position + * @return array next token (type and value) + */ + function _if_header_lexer($string, &$pos) + { + // skip whitespace + while (ctype_space($string{$pos})) { + ++$pos; + } + + // already at end of string? + if (strlen($string) <= $pos) { + return false; + } + + // get next character + $c = $string{$pos++}; + + // now it depends on what we found + switch ($c) { + case "<": + // URIs are enclosed in <...> + $pos2 = strpos($string, ">", $pos); + $uri = substr($string, $pos, $pos2 - $pos); + $pos = $pos2 + 1; + return array("URI", $uri); + + case "[": + //Etags are enclosed in [...] + if ($string{$pos} == "W") { + $type = "ETAG_WEAK"; + $pos += 2; + } else { + $type = "ETAG_STRONG"; + } + $pos2 = strpos($string, "]", $pos); + $etag = substr($string, $pos + 1, $pos2 - $pos - 2); + $pos = $pos2 + 1; + return array($type, $etag); + + case "N": + // "N" indicates negation + $pos += 2; + return array("NOT", "Not"); + + default: + // anything else is passed verbatim char by char + return array("CHAR", $c); + } + } + + /** + * parse If: header + * + * @param string header string + * @return array URIs and their conditions + */ + function _if_header_parser($str) + { + $pos = 0; + $len = strlen($str); + + $uris = array(); + + // parser loop + while ($pos < $len) { + // get next token + $token = $this->_if_header_lexer($str, $pos); + + // check for URI + if ($token[0] == "URI") { + $uri = $token[1]; // remember URI + $token = $this->_if_header_lexer($str, $pos); // get next token + } else { + $uri = ""; + } + + // sanity check + if ($token[0] != "CHAR" || $token[1] != "(") { + return false; + } + + $list = array(); + $level = 1; + $not = ""; + while ($level) { + $token = $this->_if_header_lexer($str, $pos); + if ($token[0] == "NOT") { + $not = "!"; + continue; + } + switch ($token[0]) { + case "CHAR": + switch ($token[1]) { + case "(": + $level++; + break; + case ")": + $level--; + break; + default: + return false; + } + break; + + case "URI": + $list[] = $not."<$token[1]>"; + break; + + case "ETAG_WEAK": + $list[] = $not."[W/'$token[1]']>"; + break; + + case "ETAG_STRONG": + $list[] = $not."['$token[1]']>"; + break; + + default: + return false; + } + $not = ""; + } + + if (@is_array($uris[$uri])) { + $uris[$uri] = array_merge($uris[$uri],$list); + } else { + $uris[$uri] = $list; + } + } + + return $uris; + } + + /** + * check if conditions from "If:" headers are meat + * + * the "If:" header is an extension to HTTP/1.1 + * defined in RFC 2518 section 9.4 + * + * @param void + * @return void + */ + function _check_if_header_conditions() + { + if (isset($_SERVER["HTTP_IF"])) { + $this->_if_header_uris = + $this->_if_header_parser($_SERVER["HTTP_IF"]); + + foreach($this->_if_header_uris as $uri => $conditions) { + if ($uri == "") { + // default uri is the complete request uri + $uri = (@$_SERVER["HTTPS"] === "on" ? "https:" : "http:"); + $uri.= "//$_SERVER[HTTP_HOST]$_SERVER[SCRIPT_NAME]$_SERVER[PATH_INFO]"; + } + // all must match + $state = true; + foreach($conditions as $condition) { + // lock tokens may be free form (RFC2518 6.3) + // but if opaquelocktokens are used (RFC2518 6.4) + // we have to check the format (litmus tests this) + if (!strncmp($condition, "$/", $condition)) { + return false; + } + } + if (!$this->_check_uri_condition($uri, $condition)) { + $state = false; + break; + } + } + + // any match is ok + if ($state == true) { + return true; + } + } + return false; + } + return true; + } + + /** + * Check a single URI condition parsed from an if-header + * + * Check a single URI condition parsed from an if-header + * + * @abstract + * @param string $uri URI to check + * @param string $condition Condition to check for this URI + * @returns bool Condition check result + */ + function _check_uri_condition($uri, $condition) + { + // not really implemented here, + // implementations must override + return true; + } + + + /** + * + * + * @param string path of resource to check + * @param bool exclusive lock? + */ + function _check_lock_status($path, $exclusive_only = false) + { + // FIXME depth -> ignored for now + if (method_exists($this, "checkLock")) { + // is locked? + $lock = $this->checkLock($path); + + // ... and lock is not owned? + if (is_array($lock) && count($lock)) { + // FIXME doesn't check uri restrictions yet + if (!strstr($_SERVER["HTTP_IF"], $lock["token"])) { + if (!$exclusive_only || ($lock["scope"] !== "shared")) + return false; + } + } + } + return true; + } + + + // }}} + + + /** + * Generate lockdiscovery reply from checklock() result + * + * @param string resource path to check + * @return string lockdiscovery response + */ + function lockdiscovery($path) + { + // no lock support without checklock() method + if (!method_exists($this, "checklock")) { + return ""; + } + + // collect response here + $activelocks = ""; + + // get checklock() reply + $lock = $this->checklock($path); + + // generate block for returned data + if (is_array($lock) && count($lock)) { + // check for 'timeout' or 'expires' + if (!empty($lock["expires"])) { + $timeout = "Second-".($lock["expires"] - time()); + } else if (!empty($lock["timeout"])) { + $timeout = "Second-$lock[timeout]"; + } else { + $timeout = "Infinite"; + } + + // genreate response block + $activelocks.= " + + + + $lock[depth] + $lock[owner] + $timeout + $lock[token] + + "; + } + + // return generated response + return $activelocks; + } + + /** + * set HTTP return status and mirror it in a private header + * + * @param string status code and message + * @return void + */ + function http_status($status) + { + // simplified success case + if($status === true) { + $status = "200 OK"; + } + + // remember status + $this->_http_status = $status; + + // generate HTTP status response + header("HTTP/1.1 $status"); + header("X-WebDAV-Status: $status", true); + } + + /** + * private minimalistic version of PHP urlencode() + * + * only blanks and XML special chars must be encoded here + * full urlencode() encoding confuses some clients ... + * + * @param string URL to encode + * @return string encoded URL + */ + function _urlencode($url) + { + return strtr($url, array(" "=>"%20", + "&"=>"%26", + "<"=>"%3C", + ">"=>"%3E", + )); + } + + /** + * private version of PHP urldecode + * + * not really needed but added for completenes + * + * @param string URL to decode + * @return string decoded URL + */ + function _urldecode($path) + { + return urldecode($path); + } + + /** + * UTF-8 encode property values if not already done so + * + * @param string text to encode + * @return string utf-8 encoded text + */ + function _prop_encode($text) + { + switch (strtolower($this->_prop_encoding)) { + case "utf-8": + return $text; + case "iso-8859-1": + case "iso-8859-15": + case "latin-1": + default: + return utf8_encode($text); + } + } +} + + /* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + */ +?> diff --git a/include/HTTP_WebDAV_Server/Tools/_parse_lockinfo.php b/include/HTTP_WebDAV_Server/Tools/_parse_lockinfo.php new file mode 100644 index 00000000..a04412c2 --- /dev/null +++ b/include/HTTP_WebDAV_Server/Tools/_parse_lockinfo.php @@ -0,0 +1,237 @@ + | +// | Christian Stocker | +// +----------------------------------------------------------------------+ +// + +// + +/** + * helper class for parsing LOCK request bodies + * + * @package HTTP_WebDAV_Server + * @author Hartmut Holzgraefe + * @version 0.99.1dev + */ +class _parse_lockinfo +{ + /** + * success state flag + * + * @var bool + * @access public + */ + var $success = false; + + /** + * lock type, currently only "write" + * + * @var string + * @access public + */ + var $locktype = ""; + + /** + * lock scope, "shared" or "exclusive" + * + * @var string + * @access public + */ + var $lockscope = ""; + + /** + * lock owner information + * + * @var string + * @access public + */ + var $owner = ""; + + /** + * flag that is set during lock owner read + * + * @var bool + * @access private + */ + var $collect_owner = false; + + /** + * constructor + * + * @param string path of stream to read + * @access public + */ + function _parse_lockinfo($path) + { + // we assume success unless problems occur + $this->success = true; + + // remember if any input was parsed + $had_input = false; + + // open stream + $f_in = fopen($path, "r"); + if (!$f_in) { + $this->success = false; + return; + } + + // create namespace aware parser + $xml_parser = xml_parser_create_ns("UTF-8", " "); + + // set tag and data handlers + xml_set_element_handler($xml_parser, + array(&$this, "_startElement"), + array(&$this, "_endElement")); + xml_set_character_data_handler($xml_parser, + array(&$this, "_data")); + + // we want a case sensitive parser + xml_parser_set_option($xml_parser, + XML_OPTION_CASE_FOLDING, false); + + // parse input + while($this->success && !feof($f_in)) { + $line = fgets($f_in); + if (is_string($line)) { + $had_input = true; + $this->success &= xml_parse($xml_parser, $line, false); + } + } + + // finish parsing + if($had_input) { + $this->success &= xml_parse($xml_parser, "", true); + } + + // check if required tags where found + $this->success &= !empty($this->locktype); + $this->success &= !empty($this->lockscope); + + // free parser resource + xml_parser_free($xml_parser); + + // close input stream + fclose($f_in); + } + + + /** + * tag start handler + * + * @param resource parser + * @param string tag name + * @param array tag attributes + * @return void + * @access private + */ + function _startElement($parser, $name, $attrs) + { + // namespace handling + if (strstr($name, " ")) { + list($ns, $tag) = explode(" ", $name); + } else { + $ns = ""; + $tag = $name; + } + + + if ($this->collect_owner) { + // everything within the tag needs to be collected + $ns_short = ""; + $ns_attr = ""; + if ($ns) { + if ($ns == "DAV:") { + $ns_short = "D:"; + } else { + $ns_attr = " xmlns='$ns'"; + } + } + $this->owner .= "<$ns_short$tag$ns_attr>"; + } else if ($ns == "DAV:") { + // parse only the essential tags + switch ($tag) { + case "write": + $this->locktype = $tag; + break; + case "exclusive": + case "shared": + $this->lockscope = $tag; + break; + case "owner": + $this->collect_owner = true; + break; + } + } + } + + /** + * data handler + * + * @param resource parser + * @param string data + * @return void + * @access private + */ + function _data($parser, $data) + { + // only the tag has data content + if ($this->collect_owner) { + $this->owner .= $data; + } + } + + /** + * tag end handler + * + * @param resource parser + * @param string tag name + * @return void + * @access private + */ + function _endElement($parser, $name) + { + // namespace handling + if (strstr($name, " ")) { + list($ns, $tag) = explode(" ", $name); + } else { + $ns = ""; + $tag = $name; + } + + // finished? + if (($ns == "DAV:") && ($tag == "owner")) { + $this->collect_owner = false; + } + + // within we have to collect everything + if ($this->collect_owner) { + $ns_short = ""; + $ns_attr = ""; + if ($ns) { + if ($ns == "DAV:") { + $ns_short = "D:"; + } else { + $ns_attr = " xmlns='$ns'"; + } + } + $this->owner .= ""; + } + } +} + +?> \ No newline at end of file diff --git a/include/HTTP_WebDAV_Server/Tools/_parse_propfind.php b/include/HTTP_WebDAV_Server/Tools/_parse_propfind.php new file mode 100644 index 00000000..2ce57706 --- /dev/null +++ b/include/HTTP_WebDAV_Server/Tools/_parse_propfind.php @@ -0,0 +1,178 @@ + | +// | Christian Stocker | +// +----------------------------------------------------------------------+ +// + +// + +/** + * helper class for parsing PROPFIND request bodies + * + * @package HTTP_WebDAV_Server + * @author Hartmut Holzgraefe + * @version 0.99.1dev + */ +class _parse_propfind +{ + /** + * success state flag + * + * @var bool + * @access public + */ + var $success = false; + + /** + * found properties are collected here + * + * @var array + * @access public + */ + var $props = false; + + /** + * internal tag nesting depth counter + * + * @var int + * @access private + */ + var $depth = 0; + + + /** + * constructor + * + * @access public + */ + function _parse_propfind($path) + { + // success state flag + $this->success = true; + + // property storage array + $this->props = array(); + + // internal tag depth counter + $this->depth = 0; + + // remember if any input was parsed + $had_input = false; + + // open input stream + $f_in = fopen($path, "r"); + if (!$f_in) { + $this->success = false; + return; + } + + // create XML parser + $xml_parser = xml_parser_create_ns("UTF-8", " "); + + // set tag and data handlers + xml_set_element_handler($xml_parser, + array(&$this, "_startElement"), + array(&$this, "_endElement")); + + // we want a case sensitive parser + xml_parser_set_option($xml_parser, + XML_OPTION_CASE_FOLDING, false); + + + // parse input + while($this->success && !feof($f_in)) { + $line = fgets($f_in); + if (is_string($line)) { + $had_input = true; + $this->success &= xml_parse($xml_parser, $line, false); + } + } + + // finish parsing + if($had_input) { + $this->success &= xml_parse($xml_parser, "", true); + } + + // free parser + xml_parser_free($xml_parser); + + // close input stream + fclose($f_in); + + // if no input was parsed it was a request + if(!count($this->props)) $this->props = "all"; // default + } + + + /** + * start tag handler + * + * @access private + * @param resource parser + * @param string tag name + * @param array tag attributes + */ + function _startElement($parser, $name, $attrs) + { + // name space handling + if (strstr($name, " ")) { + list($ns, $tag) = explode(" ", $name); + if ($ns == "") + $this->success = false; + } else { + $ns = ""; + $tag = $name; + } + + // special tags at level 1: and + if ($this->depth == 1) { + if ($tag == "allprop") + $this->props = "all"; + + if ($tag == "propname") + $this->props = "names"; + } + + // requested properties are found at level 2 + if ($this->depth == 2) { + $prop = array("name" => $tag); + if ($ns) + $prop["xmlns"] = $ns; + $this->props[] = $prop; + } + + // increment depth count + $this->depth++; + } + + + /** + * end tag handler + * + * @access private + * @param resource parser + * @param string tag name + */ + function _endElement($parser, $name) + { + // here we only need to decrement the depth count + $this->depth--; + } +} + + +?> \ No newline at end of file diff --git a/include/HTTP_WebDAV_Server/Tools/_parse_proppatch.php b/include/HTTP_WebDAV_Server/Tools/_parse_proppatch.php new file mode 100644 index 00000000..e441083b --- /dev/null +++ b/include/HTTP_WebDAV_Server/Tools/_parse_proppatch.php @@ -0,0 +1,214 @@ + | +// | Christian Stocker | +// +----------------------------------------------------------------------+ +// + +// + +/** + * helper class for parsing PROPPATCH request bodies + * + * @package HTTP_WebDAV_Server + * @author Hartmut Holzgraefe + * @version 0.99.1dev + */ +class _parse_proppatch +{ + /** + * + * + * @var + * @access + */ + var $success; + + /** + * + * + * @var + * @access + */ + var $props; + + /** + * + * + * @var + * @access + */ + var $depth; + + /** + * + * + * @var + * @access + */ + var $mode; + + /** + * + * + * @var + * @access + */ + var $current; + + /** + * constructor + * + * @param string path of input stream + * @access public + */ + function _parse_proppatch($path) + { + $this->success = true; + + $this->depth = 0; + $this->props = array(); + $had_input = false; + + $f_in = fopen($path, "r"); + if (!$f_in) { + $this->success = false; + return; + } + + $xml_parser = xml_parser_create_ns("UTF-8", " "); + + xml_set_element_handler($xml_parser, + array(&$this, "_startElement"), + array(&$this, "_endElement")); + + xml_set_character_data_handler($xml_parser, + array(&$this, "_data")); + + xml_parser_set_option($xml_parser, + XML_OPTION_CASE_FOLDING, false); + + while($this->success && !feof($f_in)) { + $line = fgets($f_in); + if (is_string($line)) { + $had_input = true; + $this->success &= xml_parse($xml_parser, $line, false); + } + } + + if($had_input) { + $this->success &= xml_parse($xml_parser, "", true); + } + + xml_parser_free($xml_parser); + + fclose($f_in); + } + + /** + * tag start handler + * + * @param resource parser + * @param string tag name + * @param array tag attributes + * @return void + * @access private + */ + function _startElement($parser, $name, $attrs) + { + if (strstr($name, " ")) { + list($ns, $tag) = explode(" ", $name); + if ($ns == "") + $this->success = false; + } else { + $ns = ""; + $tag = $name; + } + + if ($this->depth == 1) { + $this->mode = $tag; + } + + if ($this->depth == 3) { + $prop = array("name" => $tag); + $this->current = array("name" => $tag, "ns" => $ns, "status"=> 200); + if ($this->mode == "set") { + $this->current["val"] = ""; // default set val + } + } + + if ($this->depth >= 4) { + $this->current["val"] .= "<$tag"; + foreach ($attr as $key => $val) { + $this->current["val"] .= ' '.$key.'="'.str_replace('"','"', $val).'"'; + } + $this->current["val"] .= ">"; + } + + + + $this->depth++; + } + + /** + * tag end handler + * + * @param resource parser + * @param string tag name + * @return void + * @access private + */ + function _endElement($parser, $name) + { + if (strstr($name, " ")) { + list($ns, $tag) = explode(" ", $name); + if ($ns == "") + $this->success = false; + } else { + $ns = ""; + $tag = $name; + } + + $this->depth--; + + if ($this->depth >= 4) { + $this->current["val"] .= ""; + } + + if ($this->depth == 3) { + if (isset($this->current)) { + $this->props[] = $this->current; + unset($this->current); + } + } + } + + /** + * input data handler + * + * @param resource parser + * @param string data + * @return void + * @access private + */ + function _data($parser, $data) { + if (isset($this->current)) { + $this->current["val"] .= $data; + } + } +} + +?> \ No newline at end of file diff --git a/include/HTTP_WebDAV_Server/dav.txt b/include/HTTP_WebDAV_Server/dav.txt new file mode 100644 index 00000000..9e0b8299 --- /dev/null +++ b/include/HTTP_WebDAV_Server/dav.txt @@ -0,0 +1,229 @@ +The HTTP_WebDAV_Server class provides a framwork for the +implementation of customized WebDAV servers that can provide +filesystem like access to almost any kind of hierachically stored +data. + +The (abstract) server base class tries to encapsulate as much of +the protocol details as possible. It takes care of the needed WebDAV +header and XML payload parsing and generation (and knows about some +of the problems with common clients and tries hard to work around +them). + +WebDAV itself is an extension to the HTTP protocol. The HTTP +specific parts of it are already taken care of by the web server. Any +data needed by the server class is provided by the PHP SAPI interface +of the server used. + +To create a working server from the base class you have to extend and +add methods for the actual access, modification and access control of +your own data. + +You may use the included HTTP_WebDAV_Server_Filesystem class as an +example of how to create a working server. This sample implementation +is used for testing the implementation of this package against the +litmus WebDAV compliance test suite. +(litmus is available on http://www.webdav.org/neon/litmus) + +The methods you can add in your extended class are mostly named after +the WebDAV specific request methods (using upper case names). Methods +you may implement are: + +* GET() get a resource from the server +* HEAD() get resource headers only from the server +* PUT() create or modify a resource on the server +* COPY() copy a resource on the server +* MOVE() move a resource on the server +* DELETE() delete a resource on the server +* MKCOL() create a new collection +* PROPFIND() get property data for a resource +* PROPPATCH() modify property data for a resource +* LOCK() lock a resource +* UNLOCK() unlock a locked resource +* checklock() check whether a resource is locked +* check_auth() check authentication + +You can think of WebDAV resources as files, collections as directories +and properties as filesystem meta data (like size, creation date, ...). + +The base class is able identify which of the methods you have +implemented and will create appropriate answers to OPTIONS requests +that ask for the WebDAV standards compliance level and the allowed +HTTP methods for you. + +For a minimal working test server you need to implement GET(), PUT() +and PROPFIND() only. + +For a minimal (level 1) standards compliant server you also need to +implement MKCOL(), DELETE(), and PROPPATCH(). The COPY(), MOVE() and +HEAD() methods are emulated using GET(), PUT() and DELETE() if not +implemented, but for performance reasons you should better implement +them yourself. + +For a complete (level 2) RFC2518 compliand server you also have to +provide locking support by implementing LOCK(), UNLOCK() and +checklock(). + +Authentication is not really part of the WebDAV specification and +should be handled on the HTTP level. You can do so by means of, for +example, .htaccess files or similar services provided by your web +server. But you can also make use of the authentication features +offered by PHP by implementing the check_auth() method. +Using the check_auth() method you can create a dynamic interface +to any authentication system protecting the data you want to serve. + + + + the following reference information may be outdated and/or + incomplete ... + + +bool PROPINFO($options, &$files) + + options[path] - Resource-Path + options[depth] - Depth of search requested: "0", "1", or "infinity" + options[props] - "all", "names", or an arry of requested properties + each property array element is either a string + (which implies the default "DAV:" namespace) or + an array with the two elements "name" and "xmlns" + for the properties name and XML namespace + + &$files - storage array for property results with the following elements: + + "files" -> array of found properties forresources. elements are: + + "path" -> path of the resource + "props" -> properties array + each property array element is either a string + (which implies the default "DAV:" namespace) or + an array with the two elements "name" and "xmlns" + for the properties name and XML namespace + + you should at least support the following + list of properties from the "DAV:" namespave: + + - resourcetype: "collection" oder "" + - creationdate: unix-timestamp + - getcontentlength: integer + - getlastmodified: unix-timestamp + + You may want to add support for these "DAV:" + properties, too: + + - getcontenttype: mime-type + - displayname: string + + for a compliant server you also have to be + able to return any property from other + namespaces that has been stored using + PROPPATCH + + + return-value: true / false + + + + +string MKCOL($option) + + options[path] - path of the new collection to be created + + return-value: string + HTTP status and status message, possible values are + * 201 Success + * 403 Forbidden + * 405 Method not allowed + * 409 Conflict + * 415 Unsupported media type + * 507 Insufficient Storage + (see also RFC2518 8.3.2) + + + + +string GET(&$options) + + $options['path'] - path to the requested resource + $options['ranges'] - optional array of range specifications for + partial access. range specs are arrays that + consist of either a 'start' and 'end' element + (where 'end' can be empty to indicate a request + up to the actual end of the resource) or a + 'last' element to access the last n bytes of + a resource without knowing its actual size in + advance + + Return-value: true bei Erfolg, false wenn not found + + (TODO: andere stati berücksichtigen) + + Content-Type, Content-Length header müssen von der Methode selbst + erzeugt werden (TODO: outdated) + + + + +string PUT($options) + + options[path] - path to the requested resource + options[content_length] - size of request data in bytes + options[stream] - a PHP stream providing the input data + + return-value: string + HTTP status, possible values are: + * 201 Created -> the resource did not exist before + and has been successfully created + * 204 No Content -> a previously existing resource has + successfully been modified + * 409 Conflict + ... + + + + +string COPY($options) + + options[path] - path to the resource to be copied + options[depth] - "0" or "infinity" (applies only to directories) + options[overwrite] - true / false + options[dest] - path to the destination resource if local + options[dest_url] - non-local destination path + + return-value: string + HTTP status, see RFC2518 8.8.5 + + + + + +string MOVE($options) + + options[path] - path to the resource to be moved + options[overwrite] - true / false + options[dest] - path to the destination resource if local + options[dest_url] - non-local destination path + + return-value: string + HTTP status, see RFC2518 8.9.4 + + + + +string DELETE($options) + + options[path] - path to the resource to be removed + + return-value: string + HTTP status, see RFC2518 8.6.2 + + + + + +bool check_auth($type, $user, $passwd) + + $type: HTTP-Auth type, i.A. "Basic" + $user: HTTP Username + $passwd: HTTP Passwort + + return-value: true bei success, sonst false + (ToDo: array mit Auth-Type und Realm String zulassen bei fehler) \ No newline at end of file diff --git a/include/HTTP_WebDAV_Server/license.txt b/include/HTTP_WebDAV_Server/license.txt new file mode 100644 index 00000000..6c1c1708 --- /dev/null +++ b/include/HTTP_WebDAV_Server/license.txt @@ -0,0 +1,68 @@ +-------------------------------------------------------------------- + The PHP License, version 3.0 +Copyright (c) 1999 - 2006 The PHP Group. All rights reserved. +-------------------------------------------------------------------- + +Redistribution and use in source and binary forms, with or without +modification, is permitted provided that the following conditions +are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + 2. 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. + + 3. The name "PHP" must not be used to endorse or promote products + derived from this software without prior written permission. For + written permission, please contact group@php.net. + + 4. Products derived from this software may not be called "PHP", nor + may "PHP" appear in their name, without prior written permission + from group@php.net. You may indicate that your software works in + conjunction with PHP by saying "Foo for PHP" instead of calling + it "PHP Foo" or "phpfoo" + + 5. The PHP Group may publish revised and/or new versions of the + license from time to time. Each version will be given a + distinguishing version number. + Once covered code has been published under a particular version + of the license, you may always continue to use it under the terms + of that version. You may also choose to use such covered code + under the terms of any subsequent version of the license + published by the PHP Group. No one other than the PHP Group has + the right to modify the terms applicable to covered code created + under this License. + + 6. Redistributions of any form whatsoever must retain the following + acknowledgment: + "This product includes PHP, freely available from + ". + +THIS SOFTWARE IS PROVIDED BY THE PHP DEVELOPMENT TEAM ``AS IS'' AND +ANY EXPRESSED 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 PHP +DEVELOPMENT TEAM OR ITS 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. + +-------------------------------------------------------------------- + +This software consists of voluntary contributions made by many +individuals on behalf of the PHP Group. + +The PHP Group can be contacted via Email at group@php.net. + +For more information on the PHP Group and the PHP project, +please see . + +This product includes the Zend Engine, freely available at +. diff --git a/include/JSON.js b/include/JSON.js new file mode 100644 index 00000000..ccb8d254 --- /dev/null +++ b/include/JSON.js @@ -0,0 +1,44 @@ +/* + Copyright (c) 2005 JSON.org + + 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 Software shall be used for Good, not Evil. + + 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. + + json.js + + The global object JSON contains two methods. + + JSON.stringify(value) takes a JavaScript value and produces a JSON text. + The value must not be cyclical. + + JSON.parse(text) takes a JSON text and produces a JavaScript value. It will + return false if there is an error. + + 2008-10-10: New regular expressions copied in from the new json2.js file on http://json.org (released into the public domain), work better on Safari and IE for more complicated datasets + */ +var JSON=function(){var m={'\b':'\\b','\t':'\\t','\n':'\\n','\f':'\\f','\r':'\\r','"':'\\"','\\':'\\\\'},s={array:function(x){var a=['['],b,f,i,l=x.length,v;for(i=0;ifatal("*** SECURITY: received asynchronous call with invalid ['asychronous_key'] value. Possible CSRF attack."); + return ''; + } + + return $meta['jsonObject']; + } + + return json_decode($string,true); + } + + /** + * @deprecated use JSON::encode() instead + */ + public static function encodeReal($string) + { + return self::encode($string); + } + + /** + * @deprecated use JSON::decode() instead + */ + public static function decodeReal($string) + { + return self::decode($string); + } +} diff --git a/include/ListView/ListView.php b/include/ListView/ListView.php new file mode 100644 index 00000000..102d14f8 --- /dev/null +++ b/include/ListView/ListView.php @@ -0,0 +1,1757 @@ +data_array = $value; +} + +function processListViewMulti($seed, $xTemplateSection, $html_varName) { + + $this->shouldProcess = true; + + echo ""; + $this->processListViewTwo($seed, $xTemplateSection, $html_varName); + + echo "".translate('LBL_CHECKALL')." - ".translate('LBL_CLEARALL').""; + echo '

'; +} + + +function processListView($seed, $xTemplateSection, $html_varName) +{ + global $sugar_config; + + $populateOnly = $this->ignorePopulateOnly ? FALSE : (!empty($sugar_config['save_query']) && $sugar_config['save_query'] == 'populate_only'); + if(isset($seed->module_dir) && $populateOnly) { + if(empty($GLOBALS['displayListView']) && strcmp(strtolower($_REQUEST['action']), 'popup') != 0 && (!empty($_REQUEST['clear_query']) || $_REQUEST['module'] == $seed->module_dir && ((empty($_REQUEST['query']) || $_REQUEST['query'] == 'MSI')&& (empty($_SESSION['last_search_mod']) || $_SESSION['last_search_mod'] != $seed->module_dir)))) { + $_SESSION['last_search_mod'] = $_REQUEST['module'] ; + return; + } + } + if(strcmp(strtolower($_REQUEST['action']), 'popup') != 0){ + $_SESSION['last_search_mod'] = $_REQUEST['module'] ; + } + //following session variable will track the detail view nvigation history. + //needs to the reset after each search. + $this->setLocalSessionVariable($html_varName,"DETAIL_NAV_HISTORY",false); + + require_once('include/MassUpdate.php'); + $mass = new MassUpdate(); + $add_acl_javascript = false; + if(!isset($_REQUEST['action'])) { + $this->shouldProcess=false; + } else { + $this->shouldProcess = is_subclass_of($seed, "SugarBean") + && (($_REQUEST['action'] == 'index') || ('ListView' == substr($_REQUEST['action'],0,8)) /* cn: to include all ListViewXXX.php type views */) + && ($_REQUEST['module'] == $seed->module_dir); + } + + //when processing a multi-select popup. + if($this->process_for_popups && $this->multi_select_popup) $this->shouldProcess =true; + //mass update turned off? + if(!$this->show_mass_update) $this->shouldProcess = false; + if(is_subclass_of($seed, "SugarBean")) { + if($seed->bean_implements('ACL')) { + if(!ACLController::checkAccess($seed->module_dir,'list',true)) { + if($_REQUEST['module'] != 'Home') { + ACLController::displayNoAccess(); + } + return; + } + if(!ACLController::checkAccess($seed->module_dir,'export',true)) { + $sugar_config['disable_export']= true; + } + + } + } + + //force mass update form if requested. + if($this->force_mass_update) { + $this->shouldProcess = true; + } + + if($this->shouldProcess) { + echo $mass->getDisplayMassUpdateForm(true, $this->multi_select_popup); + echo $mass->getMassUpdateFormHeader($this->multi_select_popup); + $mass->setSugarBean($seed); + + //C.L. Fix for 10048, do not process handleMassUpdate for multi select popups + if(!$this->multi_select_popup) { + $mass->handleMassUpdate(); + } + } + + $this->processListViewTwo($seed,$xTemplateSection, $html_varName); + + if($this->shouldProcess && empty($this->process_for_popups)) { + //echo "".translate('LBL_CLEARALL').""; + // cn: preserves current functionality, exception is InboundEmail + if($this->show_mass_update_form) { + echo $mass->getMassUpdateForm(); + } + if(!$this->keep_mass_update_form_open) { + echo $mass->endMassUpdateForm(); + } + } +} + + +function process_dynamic_listview($source_module, $sugarbean,$subpanel_def) +{ + $this->source_module = $source_module; + $this->subpanel_module = $subpanel_def->name; + if(!isset($this->xTemplate)) + $this->createXTemplate(); + + $html_var = $this->subpanel_module . "_CELL"; + + $list_data = $this->processUnionBeans($sugarbean,$subpanel_def, $html_var); + + $list = $list_data['list']; + $parent_data = $list_data['parent_data']; + + if($subpanel_def->isCollection()) { + $thepanel=$subpanel_def->get_header_panel_def(); + } else { + $thepanel=$subpanel_def; + } + + + + $this->process_dynamic_listview_header($thepanel->get_module_name(), $thepanel, $html_var); + $this->process_dynamic_listview_rows($list,$parent_data, 'dyn_list_view', $html_var,$subpanel_def); + + if($this->display_header_and_footer) + { + $this->getAdditionalHeader(); + if(!empty($this->header_title)) + { + echo get_form_header($this->header_title, $this->header_text, false); + } + } + + $this->xTemplate->out('dyn_list_view'); + + if(isset($_SESSION['validation'])) + { + print base64_decode('PGEgaHJlZj0naHR0cDovL3d3dy5zdWdhcmNybS5jb20nPlBPV0VSRUQmbmJzcDtCWSZuYnNwO1NVR0FSQ1JNPC9hPg=='); + } + if(isset($list_data['query'])) { + return ($list_data['query']); + } + } + +/** + * @return void + * @param unknown $data + * @param unknown $xTemplateSection + * @param unknown $html_varName + * @desc INTERNAL FUNCTION handles the rows + */ + function process_dynamic_listview_rows($data,$parent_data, $xtemplateSection, $html_varName, $subpanel_def) + { + global $odd_bg; + global $even_bg; + global $hilite_bg; + global $click_bg; + + $this->xTemplate->assign("BG_HILITE", $hilite_bg); + $this->xTemplate->assign('CHECKALL', "\"\""); + //$this->xTemplate->assign("BG_CLICK", $click_bg); + $oddRow = true; + $count = 0; + reset($data); + + //GETTING OFFSET + $offset = $this->getOffset($html_varName); + //$totaltime = 0; + $processed_ids = array(); + + $fill_additional_fields = array(); + //Either retrieve the is_fill_in_additional_fields property from the lone + //subpanel or visit each subpanel's subpanels to retreive the is_fill_in_addition_fields + //property + $subpanel_list=array(); + if($subpanel_def->isCollection()) { + $subpanel_list=$subpanel_def->sub_subpanels; + } else { + $subpanel_list[]= $subpanel_def; + } + + foreach($subpanel_list as $this_subpanel) + { + if($this_subpanel->is_fill_in_additional_fields()) + { + $fill_additional_fields[] = $this_subpanel->bean_name; + $fill_additional_fields[$this_subpanel->bean_name] = true; + } + } + + if ( empty($data) ) { + $this->xTemplate->assign("ROW_COLOR", 'oddListRow'); + $thepanel=$subpanel_def; + if($subpanel_def->isCollection()) + $thepanel=$subpanel_def->get_header_panel_def(); + $this->xTemplate->assign("COL_COUNT", count($thepanel->get_list_fields())); + $this->xTemplate->parse($xtemplateSection.".nodata"); + } + + while(list($aVal, $aItem) = each($data)) + { + $aItem->check_date_relationships_load(); + // TODO: expensive and needs to be removed and done better elsewhere + + if(!empty($fill_additional_fields[$aItem->object_name]) + || ($aItem->object_name == 'Case' && !empty($fill_additional_fields['aCase'])) + ) + { + $aItem->fill_in_additional_list_fields(); + //$aItem->fill_in_additional_detail_fields(); + } + //rrs bug: 25343 + $aItem->call_custom_logic("process_record"); + + if(isset($parent_data[$aItem->id])) { + + $aItem->parent_name = $parent_data[$aItem->id]['parent_name']; + if(!empty($parent_data[$aItem->id]['parent_name_owner'])) { + $aItem->parent_name_owner = $parent_data[$aItem->id]['parent_name_owner']; + $aItem->parent_name_mod = $parent_data[$aItem->id]['parent_name_mod']; + }} + + $fields = $aItem->get_list_view_data(); + if(isset($processed_ids[$aItem->id])) { + continue; + + } else { + $processed_ids[$aItem->id] = 1; + } + + + //ADD OFFSET TO ARRAY + $fields['OFFSET'] = ($offset + $count + 1); + + if($this->shouldProcess) { + if($aItem->ACLAccess('EditView')) { + $this->xTemplate->assign('PREROW', ""); + } else { + $this->xTemplate->assign('PREROW', ''); + + } + if($aItem->ACLAccess('DetailView')) { + $this->xTemplate->assign('TAG_NAME','a'); + } else { + $this->xTemplate->assign('TAG_NAME','span'); + } + $this->xTemplate->assign('CHECKALL', ""); + } + + if($oddRow) + { + $ROW_COLOR = 'oddListRow'; + $BG_COLOR = $odd_bg; + } + else + { + $ROW_COLOR = 'evenListRow'; + $BG_COLOR = $even_bg; + } + $oddRow = !$oddRow; + + $this->xTemplate->assign("ROW_COLOR", $ROW_COLOR); + $this->xTemplate->assign("BG_COLOR", $BG_COLOR); + $layout_manager = $this->getLayoutManager(); + $layout_manager->setAttribute('context','List'); + $layout_manager->setAttribute('image_path',$this->local_image_path); + $layout_manager->setAttribute('module_name', $subpanel_def->_instance_properties['module']); + if(!empty($this->child_focus)) + $layout_manager->setAttribute('related_module_name',$this->child_focus->module_dir); + + //AG$subpanel_data = $this->list_field_defs; + //$bla = array_pop($subpanel_data); + //select which sub-panel to display here, the decision will be made based on the type of + //the sub-panel and panel in the bean being processed. + if($subpanel_def->isCollection()) { + $thepanel=$subpanel_def->sub_subpanels[$aItem->panel_name]; + } else { + $thepanel=$subpanel_def; + } + //get data source name + $linked_field=$thepanel->get_data_source_name(); + $linked_field_set=$thepanel->get_data_source_name(true); + foreach($thepanel->get_list_fields() as $field_name=>$list_field) + { + //add linked field attribute to the array. + $list_field['linked_field']=$linked_field; + $list_field['linked_field_set']=$linked_field_set; + + $usage = empty($list_field['usage']) ? '' : $list_field['usage']; + if($usage != 'query_only') + { + $list_field['name']=$field_name; + + $module_field = $field_name.'_mod'; + $owner_field = $field_name.'_owner'; + if(!empty($aItem->$module_field)) { + + $list_field['owner_id'] = $aItem->$owner_field; + $list_field['owner_module'] = $aItem->$module_field; + + } else { + $list_field['owner_id'] = false; + $list_field['owner_module'] = false; + } + if(isset($list_field['alias'])) $list_field['name'] = $list_field['alias']; + else $list_field['name']=$field_name; + $list_field['fields'] = $fields; + $list_field['module'] = $aItem->module_dir; + $list_field['start_link_wrapper'] = $this->start_link_wrapper; + $list_field['end_link_wrapper'] = $this->end_link_wrapper; + $list_field['subpanel_id'] = $this->subpanel_id; + $list_field['DetailView'] = $aItem->ACLAccess('DetailView'); + $list_field['ListView'] = $aItem->ACLAccess('ListView'); + $list_field['EditView'] = $aItem->ACLAccess('EditView'); + $list_field['Delete'] = $aItem->ACLAccess('Delete'); + if ( isset($aItem->field_defs[strtolower($list_field['name'])])) { + require_once('include/SugarFields/SugarFieldHandler.php'); + // We need to see if a sugar field exists for this field type first, + // if it doesn't, toss it at the old sugarWidgets. This is for + // backwards compatibilty and will be removed in a future release + $vardef = $aItem->field_defs[strtolower($list_field['name'])]; + if ( isset($vardef['type']) ) { + $fieldType = isset($vardef['custom_type'])?$vardef['custom_type']:$vardef['type']; + $tmpField = SugarFieldHandler::getSugarField($fieldType,true); + } else { + $tmpField = NULL; + } + + if ( $tmpField != NULL ) { + $widget_contents = SugarFieldHandler::displaySmarty($list_field['fields'],$vardef,'ListView',$list_field); + } else { + // No SugarField for this particular type + // Use the old, icky, SugarWidget for now + $widget_contents = $layout_manager->widgetDisplay($list_field); + } + + if ( isset($list_field['widget_class']) && $list_field['widget_class'] == 'SubPanelDetailViewLink' ) { + // We need to call into the old SugarWidgets for the time being, so it can generate a proper link with all the various corner-cases handled + // So we'll populate the field data with the pre-rendered display for the field + $list_field['fields'][$field_name] = $widget_contents; + if('full_name' == $field_name){//bug #32465 + $list_field['fields'][strtoupper($field_name)] = $widget_contents; + } + $widget_contents = $layout_manager->widgetDisplay($list_field); + } else if(isset($list_field['widget_class']) && $list_field['widget_class'] == 'SubPanelEmailLink' ) { + $widget_contents = $layout_manager->widgetDisplay($list_field); + } + } else { + // This handles the edit and remove buttons + $widget_contents = $layout_manager->widgetDisplay($list_field); + } + static $count; + if(!isset($count))$count = 0; else $count++; + $this->xTemplate->assign('CELL_COUNT', $count); + if ( empty($widget_contents) ) $widget_contents = ' '; + $this->xTemplate->assign('CELL', $widget_contents); + $this->xTemplate->parse($xtemplateSection.".row.cell"); + } + } + + $aItem->setupCustomFields($aItem->module_dir); + $aItem->custom_fields->populateAllXTPL($this->xTemplate, 'detail', $html_varName, $fields); + + $count++; + + $this->xTemplate->parse($xtemplateSection.".row"); + } + + $this->xTemplate->parse($xtemplateSection); +} + +/**sets whether or not to display the xtemplate header and footer + * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc. + * All Rights Reserved. + * Contributor(s): ______________________________________. +*/ +function setDisplayHeaderAndFooter($bool) { + $this->display_header_and_footer = $bool; +} + +/**initializes ListView + * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc. + * All Rights Reserved. + * Contributor(s): ______________________________________. +*/ + function ListView() { + + + if(!$this->initialized) { + global $sugar_config; + $this->records_per_page = $sugar_config['list_max_entries_per_page'] + 0; + $this->initialized = true; + global $app_strings, $currentModule; + $this->local_theme = SugarThemeRegistry::current()->__toString(); + $this->local_app_strings =$app_strings; + $this->local_image_path = SugarThemeRegistry::current()->getImagePath(); + $this->local_current_module = $currentModule; + } +} +/**sets how many records should be displayed per page in the list view + * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc. + * All Rights Reserved. + * Contributor(s): ______________________________________. +*/ + function setRecordsPerPage($count) { + $this->records_per_page = $count; +} +/**sets the header title */ + function setHeaderTitle($value) { + $this->header_title = $value; +} +/**sets the header text this is text thats appended to the header table and is usually used for the creation of buttons + * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc. + * All Rights Reserved. + * Contributor(s): ______________________________________. +*/ + function setHeaderText($value) { + $this->header_text = $value; +} +/**sets the path for the XTemplate HTML file to be used this is only needed to be set if you are allowing ListView to create the XTemplate + * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc. + * All Rights Reserved. + * Contributor(s): ______________________________________. +*/ + function setXTemplatePath($value) { + $this->xTemplatePath= $value; +} + +/**this is a helper function for allowing ListView to create a new XTemplate it groups parameters that should be set into a single function + * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc. + * All Rights Reserved. + * Contributor(s): ______________________________________. +*/ + function initNewXTemplate($XTemplatePath, $modString, $imagePath = null) { + $this->setXTemplatePath($XTemplatePath); + if(isset($modString)) + $this->setModStrings($modString); + if(isset($imagePath)) + $this->setImagePath($imagePath); +} + + +function getOrderBy($varName, $defaultOrderBy='', $force_sortorder='') { + $sortBy = $this->getSessionVariable($varName, "ORDER_BY") ; + + if(empty($sortBy)) { + $this->setUserVariable($varName, "ORDER_BY", $defaultOrderBy); + $sortBy = $defaultOrderBy; + } else { + $this->setUserVariable($varName, "ORDER_BY", $sortBy); + } + if($sortBy == 'amount') { + $sortBy = 'amount*1'; + } + if($sortBy == 'amount_usdollar') { + $sortBy = 'amount_usdollar*1'; + } + + $desc = $this->getSessionVariable($varName, $sortBy."S"); + + if(empty($desc)) + $desc = false; + if(isset($_REQUEST[$this->getSessionVariableName($varName, "ORDER_BY")])) + $last = $this->getSessionVariable($varName, "OBL"); + if(!empty($last) && $last == $sortBy) { + $desc = !$desc; + }else { + $this->setSessionVariable($varName, "OBL", $sortBy); + } + $this->setSessionVariable($varName, $sortBy."S", $desc); + if(!empty($sortBy)) { + if(empty($force_sortorder)) { + if(substr_count(strtolower($sortBy), ' desc') == 0 && substr_count(strtolower($sortBy), ' asc') == 0) { + if($desc) { + $this->query_orderby = $sortBy.' desc'; + } else { + $this->query_orderby = $sortBy.' asc'; + } + } + + } else { + $this->query_orderby = $sortBy . ' ' . $force_sortorder; + } + }else { + $this->query_orderby = ""; + } + $this->sortby = $sortBy; + return $this->query_orderby; + +} + + +/**sets the parameters dealing with the db + * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc. + * All Rights Reserved. + * Contributor(s): ______________________________________. +*/ + function setQuery($where, $limit, $orderBy, $varName, $allowOrderByOveride=true) { + $this->query_where = $where; + if($this->getSessionVariable("query", "where") != $where) { + $this->query_where_has_changed = true; + $this->setSessionVariable("query", "where", $where); + } + + $this->query_limit = $limit; + if(!$allowOrderByOveride) { + $this->query_orderby = $orderBy; + return; + } + $this->getOrderBy($varName, $orderBy); + + $this->setLocalSessionVariable($varName, "QUERY_WHERE", $where); + + //SETTING ORDER_BY FOR USE IN DETAILVIEW + $this->setLocalSessionVariable($varName, "ORDER_BY_DETAIL", $this->query_orderby); +} + +function displayArrow() { + +} + +/**sets the theme used only use if it is different from the global + * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc. + * All Rights Reserved. + * Contributor(s): ______________________________________. +*/ + function setTheme($theme) { + $this->local_theme = $theme; + if(isset($this->xTemplate))$this->xTemplate->assign("THEME", $this->local_theme); +} + +/**sets the AppStrings used only use if it is different from the global + * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc. + * All Rights Reserved. + * Contributor(s): ______________________________________. +*/ + function setAppStrings($app_strings) { + unset($this->local_app_strings); + $this->local_app_strings = $app_strings; + if(isset($this->xTemplate))$this->xTemplate->assign("APP", $this->local_app_strings); +} + +/**sets the ModStrings used + * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc. + * All Rights Reserved. + * Contributor(s): ______________________________________. +*/ + function setModStrings($mod_strings) { + unset($this->local_module_strings); + $this->local_mod_strings = $mod_strings; + if(isset($this->xTemplate))$this->xTemplate->assign("MOD", $this->local_mod_strings); +} + +/**sets the ImagePath used + * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc. + * All Rights Reserved. + * Contributor(s): ______________________________________. +*/ + function setImagePath($image_path) { + $this->local_image_path = $image_path; + if(empty($this->local_image_path)) { + $this->local_image_path = SugarThemeRegistry::get($this->local_theme)->getImagePath(); + } + if(isset($this->xTemplate))$this->xTemplate->assign("IMAGE_PATH", $this->local_image_path); +} + +/**sets the currentModule only use if this is different from the global + * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc. + * All Rights Reserved. + * Contributor(s): ______________________________________. +*/ + function setCurrentModule($currentModule) { + unset($this->local_current_module); + $this->local_current_module = $currentModule; + if(isset($this->xTemplate))$this->xTemplate->assign("MODULE_NAME", $this->local_current_module); +} + +/**INTERNAL FUNCTION creates an XTemplate DO NOT CALL THIS THIS IS AN INTERNAL FUNCTION + * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc. + * All Rights Reserved. + * Contributor(s): ______________________________________. +*/ + function createXTemplate() { + if(!isset($this->xTemplate)) { + if(isset($this->xTemplatePath)) { + + $this->xTemplate = new XTemplate($this->xTemplatePath); + $this->xTemplate->assign("APP", $this->local_app_strings); + if(isset($this->local_mod_strings))$this->xTemplate->assign("MOD", $this->local_mod_strings); + $this->xTemplate->assign("THEME", $this->local_theme); + $this->xTemplate->assign("IMAGE_PATH", $this->local_image_path); + $this->xTemplate->assign("MODULE_NAME", $this->local_current_module); + } else { + $GLOBALS['log']->error("NO XTEMPLATEPATH DEFINED CANNOT CREATE XTEMPLATE"); + } + } +} + +/**sets the XTemplate telling ListView to use newXTemplate as its current XTemplate + * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc. + * All Rights Reserved. + * Contributor(s): ______________________________________. +*/ + function setXTemplate($newXTemplate) { + $this->xTemplate = $newXTemplate; +} + +/**returns the XTemplate + * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc. + * All Rights Reserved. + * Contributor(s): ______________________________________. +*/ + function getXTemplate() { + return $this->xTemplate; +} + +/**assigns a name value pair to the XTemplate + * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc. + * All Rights Reserved. + * Contributor(s): ______________________________________. +*/ + function xTemplateAssign($name, $value) { + + if(!isset($this->xTemplate)) { + $this->createXTemplate(); + } + $this->xTemplate->assign($name, $value); + +} + +/**INTERNAL FUNCTION returns the offset first checking the querey then checking the session if the where clause has changed from the last time it returns 0 + * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc. + * All Rights Reserved. + * Contributor(s): ______________________________________. +*/ + function getOffset($localVarName) { + if($this->query_where_has_changed || isset($GLOBALS['record_has_changed'])) { + $this->setSessionVariable($localVarName,"offset", 0); + } + $offset = $this->getSessionVariable($localVarName,"offset"); + if(isset($offset)) { + return $offset; + } + return 0; +} + +/**INTERNAL FUNCTION sets the offset in the session + * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc. + * All Rights Reserved. + * Contributor(s): ______________________________________. +*/ + function setOffset($localVarName, $value) { + $this->setSessionVariable($localVarName, "offset", $value); +} + +/**INTERNAL FUNCTION sets a session variable + * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc. + * All Rights Reserved. + * Contributor(s): ______________________________________. +*/ + function setSessionVariable($localVarName,$varName, $value) { + $_SESSION[$this->local_current_module."_".$localVarName."_".$varName] = $value; +} + +function setUserVariable($localVarName,$varName, $value) { + if($this->is_dynamic || $localVarName == 'CELL')return; + global $current_user; + $current_user->setPreference($this->local_current_module."_".$localVarName."_".$varName, $value); +} + +/**INTERNAL FUNCTION returns a session variable first checking the querey for it then checking the session + * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc. + * All Rights Reserved. + * Contributor(s): ______________________________________. +*/ + function getSessionVariable($localVarName,$varName) { + //Set any variables pass in through request first + if(isset($_REQUEST[$this->getSessionVariableName($localVarName, $varName)])) { + $this->setSessionVariable($localVarName,$varName,$_REQUEST[$this->getSessionVariableName($localVarName, $varName)]); + } + + if(isset($_SESSION[$this->getSessionVariableName($localVarName, $varName)])) { + return $_SESSION[$this->getSessionVariableName($localVarName, $varName)]; + } + return ""; +} + +function getUserVariable($localVarName, $varName) { + global $current_user; + if($this->is_dynamic || $localVarName == 'CELL')return; + if(isset($_REQUEST[$this->getSessionVariableName($localVarName, $varName)])) { + + $this->setUserVariable($localVarName,$varName,$_REQUEST[$this->getSessionVariableName($localVarName, $varName)]); + } + return $current_user->getPreference($this->getSessionVariableName($localVarName, $varName)); +} + + + + + + /** + + * @return void + * @param unknown $localVarName + * @param unknown $varName + * @desc INTERNAL FUNCTION returns the session/query variable name + * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc. + * All Rights Reserved. + * Contributor(s): ______________________________________.. + */ + function getSessionVariableName($localVarName,$varName) { + return $this->local_current_module."_".$localVarName."_".$varName; + } + + /** + + * @return void + * @param unknown $seed + * @param unknown $xTemplateSection + * @param unknown $html_varName + * @desc INTERNAL FUNCTION Handles List Views using seeds that extend SugarBean + $XTemplateSection is the section in the XTemplate file that should be parsed usually main + $html_VarName is the variable name used in the XTemplateFile e.g. TASK + $seed is a seed that extends SugarBean + * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.. + * All Rights Reserved.. + * Contributor(s): ______________________________________.. + */ + function processSugarBean($xtemplateSection, $html_varName, $seed) { + global $list_view_row_count; + + $current_offset = $this->getOffset($html_varName); + $response = array(); + + //ADDING VCR CONTROL + SugarVCR::erase($seed->module_dir); + $params = array(); + //$filter = array('id', 'full_name'); + $filter=array(); + $ret_array = $seed->create_new_list_query($this->query_orderby, $this->query_where, $filter, $params, 0, '', true, $seed, true); + if(!is_array($params)) $params = array(); + if(!isset($params['custom_select'])) $params['custom_select'] = ''; + if(!isset($params['custom_from'])) $params['custom_from'] = ''; + if(!isset($params['custom_where'])) $params['custom_where'] = ''; + if(!isset($params['custom_order_by'])) $params['custom_order_by'] = ''; + $main_query = $ret_array['select'] . $params['custom_select'] . $ret_array['from'] . $params['custom_from'] . $ret_array['where'] . $params['custom_where'] . $ret_array['order_by'] . $params['custom_order_by']; + SugarVCR::store($seed->module_dir, $main_query); + //ADDING VCR CONTROL + + if(empty($this->related_field_name)) { + $response = $seed->get_list($this->query_orderby, $this->query_where, $current_offset, $this->query_limit); + } else { + $related_field_name = $this->related_field_name; + $response = $seed->get_related_list($this->child_focus,$related_field_name, $this->query_orderby, + $this->query_where, $current_offset, $this->query_limit); + } + + $list = $response['list']; + $row_count = $response['row_count']; + $next_offset = $response['next_offset']; + $previous_offset = $response['previous_offset']; + + if(!empty($response['current_offset'])) { + $current_offset = $response['current_offset']; + } + + $list_view_row_count = $row_count; + $this->processListNavigation($xtemplateSection,$html_varName, $current_offset, $next_offset, $previous_offset, $row_count, null, null, empty($seed->column_fields) ? null : count($seed->column_fields)); + + return $list; + } + + function processUnionBeans($sugarbean, $subpanel_def, $html_var = 'CELL') { + + $last_detailview_record = $this->getSessionVariable("detailview", "record"); + if(!empty($last_detailview_record) && $last_detailview_record != $sugarbean->id){ + $GLOBALS['record_has_changed'] = true; + } + $this->setSessionVariable("detailview", "record", $sugarbean->id); + + $current_offset = $this->getOffset($html_var); + $module = isset($_REQUEST['module']) ? $_REQUEST['module'] : ''; + $response = array(); + + $this->sort_order = 'asc'; + if(isset($_REQUEST['sort_order'])) { + $this->sort_order = $_REQUEST['sort_order']; + } else { + if(isset($subpanel_def->_instance_properties['sort_order'])) { + $sort_order = $subpanel_def->_instance_properties['sort_order']; + } + + if(isset($_SESSION['last_sub' .$this->subpanel_module. '_order'])) { + // We swap the order when the request contains an offset (indicating a column sort issued); + // otherwise we do not sort. If we don't make this check, then the subpanel listview will + // swap ordering each time a new record is entered via quick create forms + + if(isset($_REQUEST[$module. '_' . $html_var . '_offset'])) { + $this->sort_order = $_SESSION['last_sub' .$this->subpanel_module. '_order'] == 'asc' ? 'desc' : 'asc'; + } else { + $this->sort_order = $_SESSION['last_sub' .$this->subpanel_module. '_order']; + } + } + elseif(isset($sort_order)) { + $this->sort_order = $sort_order; + } + } + + if (isset($subpanel_def->_instance_properties['sort_by'])) { + $this->query_orderby = $subpanel_def->_instance_properties['sort_by']; + } else { + $this->query_orderby = 'id'; + } + + $this->getOrderBy($html_var,$this->query_orderby, $this->sort_order); + + $_SESSION['last_sub' .$this->subpanel_module. '_order'] = $this->sort_order; + $_SESSION['last_sub' .$this->subpanel_module. '_url'] = $this->getBaseURL($html_var); + + // Bug 8139 - Correct Subpanel sorting on 'name', when subpanel sorting default is 'last_name, first_name' + if (($this->sortby == 'name' || $this->sortby == 'last_name') && + str_replace(' ', '', trim($subpanel_def->_instance_properties['sort_by'])) == 'last_name,first_name') { + $this->sortby = 'last_name '.$this->sort_order.', first_name '; + } + + if(!empty($this->response)){ + $response =& $this->response; + echo 'cached'; + }else{ + $response = SugarBean::get_union_related_list($sugarbean,$this->sortby, $this->sort_order, $this->query_where, $current_offset, -1,-1,$this->query_limit,$subpanel_def); + $this->response =& $response; + } + $list = $response['list']; + $row_count = $response['row_count']; + $next_offset = $response['next_offset']; + $previous_offset = $response['previous_offset']; + if(!empty($response['current_offset']))$current_offset = $response['current_offset']; + global $list_view_row_count; + $list_view_row_count = $row_count; + $this->processListNavigation('dyn_list_view', $html_var, $current_offset, $next_offset, $previous_offset, $row_count, $sugarbean,$subpanel_def); + + return array('list'=>$list, 'parent_data'=>$response['parent_data'], 'query'=>$response['query']); + } + + function getBaseURL($html_varName) { + static $cache = array(); + + if(!empty($cache[$html_varName]))return $cache[$html_varName]; + $blockVariables = array('mass', 'uid', 'massupdate', 'delete', 'merge', 'selectCount','current_query_by_page'); + if(!empty($this->base_URL)) { + return $this->base_URL; + } + + $baseurl = $_SERVER['PHP_SELF']; + if(empty($baseurl)) { + $baseurl = 'index.php'; + } + + /*fixes an issue with deletes when doing a search*/ + foreach(array_merge($_GET, $_POST) as $name=>$value) { + //echo ("$name = $value
"); + if(!empty($value) && $name != 'sort_order' //&& $name != ListView::getSessionVariableName($html_varName,"ORDER_BY") + && $name != ListView::getSessionVariableName($html_varName,"offset") + /*&& substr_count($name, "ORDER_BY")==0*/ && !in_array($name, $blockVariables)) + { + if(is_array($value)) { + foreach($value as $valuename=>$valuevalue) { + if(substr_count($baseurl, '?') > 0) + $baseurl .= "&{$name}[]=".$valuevalue; + else + $baseurl .= "?{$name}[]=".$valuevalue; + } + } else { + $value = urlencode($value); + if(substr_count($baseurl, '?') > 0) { + $baseurl .= "&$name=$value"; + } else { + $baseurl .= "?$name=$value"; + } + } + } + } + + + if($_SERVER['REQUEST_METHOD'] == 'POST') { + // at this point it is possible that the above foreach already executed resulting in double ?'s in the url + if(substr_count($baseurl, '?') == 0) { + $baseurl .= '?'; + } + if(isset($_REQUEST['action'])) $baseurl.= '&action='.$_REQUEST['action']; + if(isset($_REQUEST['record'])) $baseurl .= '&record='.$_REQUEST['record']; + if(isset($_REQUEST['module'])) $baseurl .= '&module='.$_REQUEST['module']; + } + + $baseurl .= "&".ListView::getSessionVariableName($html_varName,"offset")."="; + $cache[$html_varName] = $baseurl; + return $baseurl; + } + /** + * @return void + * @param unknown $data + * @param unknown $xTemplateSection + * @param unknown $html_varName + * @desc INTERNAL FUNCTION process the List Navigation + * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc. + * All Rights Reserved. + * Contributor(s): ______________________________________.. + */ + function processListNavigation($xtemplateSection, $html_varName, $current_offset, $next_offset, $previous_offset, $row_count, $sugarbean=null, $subpanel_def=null, $col_count = 20) { + + global $export_module; + global $sugar_config; + global $current_user; + global $currentModule; + + $start_record = $current_offset + 1; + + if(!is_numeric($col_count)) + $col_count = 20; + + if($row_count == 0) + $start_record = 0; + + $end_record = $start_record + $this->records_per_page; + // back up the the last page. + if($end_record > $row_count+1) { + $end_record = $row_count+1; + } + // Deterime the start location of the last page + if($row_count == 0) + $number_pages = 0; + else + $number_pages = floor(($row_count - 1) / $this->records_per_page); + + $last_offset = $number_pages * $this->records_per_page; + + if(empty($this->query_limit) || $this->query_limit > $this->records_per_page) { + $this->base_URL = $this->getBaseURL($html_varName); + $dynamic_url = ''; + + if($this->is_dynamic) { + $dynamic_url .='&'. $this->getSessionVariableName($html_varName,'ORDER_BY') . '='. $this->getSessionVariable($html_varName,'ORDER_BY').'&sort_order='.$this->sort_order.'&to_pdf=true&action=SubPanelViewer&subpanel=' . $this->subpanel_module; + } + + $current_URL = $this->base_URL.$current_offset.$dynamic_url; + $start_URL = $this->base_URL."0".$dynamic_url; + $previous_URL = $this->base_URL.$previous_offset.$dynamic_url; + $next_URL = $this->base_URL.$next_offset.$dynamic_url; + $end_URL = $this->base_URL.'end'.$dynamic_url; + + if(!empty($this->start_link_wrapper)) { + $current_URL = $this->start_link_wrapper.$current_URL.$this->end_link_wrapper; + $start_URL = $this->start_link_wrapper.$start_URL.$this->end_link_wrapper; + $previous_URL = $this->start_link_wrapper.$previous_URL.$this->end_link_wrapper; + $next_URL = $this->start_link_wrapper.$next_URL.$this->end_link_wrapper; + $end_URL = $this->start_link_wrapper.$end_URL.$this->end_link_wrapper; + } + + $moduleString = "{$currentModule}_{$html_varName}_offset"; + $moduleStringOrder = "{$currentModule}_{$html_varName}_ORDER_BY"; + if($this->shouldProcess && !$this->multi_select_popup) { + // check the checkboxes onload + echo "\n"; + + $massUpdateRun = isset($_REQUEST['massupdate']) && $_REQUEST['massupdate'] == 'true'; + $uids = empty($_REQUEST['uid']) || $massUpdateRun ? '' : $_REQUEST['uid']; + $select_entire_list = isset($_REQUEST['select_entire_list']) && !$massUpdateRun ? $_REQUEST['select_entire_list'] : 0; + + echo "\n" . + "\n". + "\n". + "\n"; + + } + + + $GLOBALS['log']->debug("Offsets: (start, previous, next, last)(0, $previous_offset, $next_offset, $last_offset)"); + + if(0 == $current_offset) { + $start_link = ""; + $previous_link = ""; + } else { + if($this->multi_select_popup) {// nav links for multiselect popup, submit form to save checks. + $start_link = ""; + $previous_link = ""; + } elseif($this->shouldProcess) { + $start_link = ""; + $previous_link = ""; + } else { + $onClick = ''; + if(0 != preg_match('/javascript.*/', $start_URL)){ + $onClick = "\"$start_URL;\""; + }else{ + $onClick ="'location.href=\"$start_URL\";'"; + } + $start_link = ""; + + $onClick = ''; + if(0 != preg_match('/javascript.*/', $previous_URL)){ + $onClick = "\"$previous_URL;\""; + }else{ + $onClick = "'location.href=\"$previous_URL\";'"; + } + $previous_link = ""; + } + } + + if($last_offset <= $current_offset) { + $end_link = ""; + $next_link = ""; + } else { + if($this->multi_select_popup) { // nav links for multiselect popup, submit form to save checks. + $end_link = ""; + if(!empty($sugar_config['disable_count_query'])) { + $end_link = ''; + } + $next_link = ""; + } elseif($this->shouldProcess) { + $end_link = ""; + $next_link = ""; + } else { + $onClick = ''; + if(0 != preg_match('/javascript.*/', $next_URL)){ + $onClick = "\"$next_URL;\""; + }else{ + $onClick ="'location.href=\"$next_URL\";'"; + } + $next_link = ""; + + $onClick = ''; + if(0 != preg_match('/javascript.*/', $end_URL)){ + $onClick = "\"$end_URL;\""; + }else{ + $onClick = "'location.href=\"$end_URL\";'"; + } + $end_link = ""; + + } + } + + $GLOBALS['log']->info("Offset (next, current, prev)($next_offset, $current_offset, $previous_offset)"); + $GLOBALS['log']->info("Start/end records ($start_record, $end_record)"); + + $end_record = $end_record-1; + + echo ""; + + if($this->show_select_menu) { + $select_link = "".$this->local_app_strings['LBL_LINK_SELECT']." ".""; + } else { + $select_link = " "; + } + + // put overlib strings into functions to avoid backslash plague! + /*echo ""; + */ + //$export_link = "".SugarThemeRegistry::current()->getImage("export","alt='".$this->local_app_strings['LBL_EXPORT']."' border='0' align='absmiddle'")." ".$this->local_app_strings['LBL_EXPORT'].""; + $export_link = ''; + + if($this->show_delete_button) { + $delete_link = ''; + } else { + $delete_link = ' '; + } + + $admin = new Administration(); + $admin->retrieveSettings('system'); + + $user_merge = $current_user->getPreference('mailmerge_on'); + if($user_merge == 'on' && isset($admin->settings['system_mailmerge_on']) && $admin->settings['system_mailmerge_on']) { + echo ""; + $merge_link = " | ".$this->local_app_strings['LBL_MAILMERGE'].""; + } else { + $merge_link = " "; + } + + $selected_objects_span = " | {$this->local_app_strings['LBL_LISTVIEW_SELECTED_OBJECTS']}"; + + if($_REQUEST['module'] == 'Home' || $this->local_current_module == 'Import' + || $this->show_export_button == false + || (!empty($sugar_config['disable_export'])) + || (!empty($sugar_config['admin_export_only']) + && !( + is_admin($current_user) + || (ACLController::moduleSupportsACL($_REQUEST['module']) + && ACLAction::getUserAccessLevel($current_user->id,$_REQUEST['module'], 'access') == ACL_ALLOW_ENABLED + && (ACLAction::getUserAccessLevel($current_user->id, $_REQUEST['module'], 'admin') == ACL_ALLOW_ADMIN || + ACLAction::getUserAccessLevel($current_user->id, $_REQUEST['module'], 'admin') == ACL_ALLOW_ADMIN_DEV))))) + { + if ($_REQUEST['module'] != 'InboundEmail' && $_REQUEST['module'] != 'EmailMan' && $_REQUEST['module'] != 'iFrames') { + $selected_objects_span = ''; + } + $export_link = " "; + $merge_link = " "; + } elseif($_REQUEST['module'] != "Accounts" && $_REQUEST['module'] != "Cases" && $_REQUEST['module'] != "Contacts" && $_REQUEST['module'] != "Leads" && $_REQUEST['module'] != "Opportunities") { + $merge_link = " "; + } + + if($this->show_paging == true) { + if(!empty($sugar_config['disable_count_query'])) { + if($row_count > $end_record) { + $row_count .= '+'; + } + } + + $html_text = ''; + $html_text .= "\n"; + $html_text .= "\n"; + //$html_text .= "\n"; + //$html_text .= "
$export_link$merge_link$selected_objects_span
+ + \ No newline at end of file diff --git a/include/ListView/ListViewSmarty.php b/include/ListView/ListViewSmarty.php new file mode 100644 index 00000000..7ce96d03 --- /dev/null +++ b/include/ListView/ListViewSmarty.php @@ -0,0 +1,231 @@ +ss = new Sugar_Smarty(); + } + + /** + * Processes the request. Calls ListViewData process. Also assigns all lang strings, export links, + * This is called from ListViewDisplay + * + * @param file file Template file to use + * @param data array from ListViewData + * @param html_var string the corresponding html var in xtpl per row + * + */ + function process($file, $data, $htmlVar) { + if(!$this->should_process)return; + global $odd_bg, $even_bg, $hilite_bg, $click_bg, $app_strings; + parent::process($file, $data, $htmlVar); + + $this->tpl = $file; + $this->data = $data; + + $totalWidth = 0; + foreach($this->displayColumns as $name => $params) { + $totalWidth += $params['width']; + } + $adjustment = $totalWidth / 100; + + $contextMenuObjectsTypes = array(); + foreach($this->displayColumns as $name => $params) { + $this->displayColumns[$name]['width'] = floor($this->displayColumns[$name]['width'] / $adjustment); + // figure out which contextMenu objectsTypes are required + if(!empty($params['contextMenu']['objectType'])) + $contextMenuObjectsTypes[$params['contextMenu']['objectType']] = true; + } + $this->ss->assign('displayColumns', $this->displayColumns); + $this->ss->assign('APP',$app_strings); + + $this->ss->assign('bgHilite', $hilite_bg); + $this->ss->assign('colCount', count($this->displayColumns) + 10); + $this->ss->assign('htmlVar', strtoupper($htmlVar)); + $this->ss->assign('moduleString', $this->moduleString); + $this->ss->assign('editLinkString', $app_strings['LBL_EDIT_BUTTON']); + $this->ss->assign('viewLinkString', $app_strings['LBL_VIEW_BUTTON']); + $this->ss->assign('allLinkString',$app_strings['LBL_LINK_ALL']); + $this->ss->assign('noneLinkString',$app_strings['LBL_LINK_NONE']); + $this->ss->assign('recordsLinkString',$app_strings['LBL_LINK_RECORDS']); + $this->ss->assign('selectLinkString',$app_strings['LBL_LINK_SELECT']); + if($this->overlib) $this->ss->assign('overlib', true); + + // Bug 24677 - Correct the page total amount on the last page of listviews + $pageTotal = $this->data['pageData']['offsets']['next']-$this->data['pageData']['offsets']['current']; + if ( $this->data['pageData']['offsets']['next'] < 0 ) { + $pageTotal = $this->data['pageData']['offsets']['total'] - $this->data['pageData']['offsets']['current']; + } + if($this->select)$this->ss->assign('selectLink', $this->buildSelectLink('select_link', $this->data['pageData']['offsets']['total'], $pageTotal)); + + if($this->show_action_dropdown) + { + $this->ss->assign('actionsLink', $this->buildActionsLink()); + } + + $this->ss->assign('quickViewLinks', $this->quickViewLinks); + + // handle save checks and stuff + if($this->multiSelect) { + + //if($this->data['pageData']['bean']['moduleDir']== 'KBDocuments') + //{ + // $this->ss->assign('selectedObjectsSpan', $this->buildSelectedObjectsSpan(true, $this->data['pageData']['offsets']['current'])); + //} else { + $this->ss->assign('selectedObjectsSpan', $this->buildSelectedObjectsSpan(true, $this->data['pageData']['offsets']['total'])); + //} + + $this->ss->assign('multiSelectData', $this->getMultiSelectData()); + } + // include button for Adding to Target List if in one of four applicable modules + if ( isset ( $_REQUEST['module']) && in_array ( $_REQUEST['module'] , array ( 'Contacts','Prospects','Leads','Accounts' )) + && ACLController::checkAccess('ProspectLists','edit',true)) { + $this->ss->assign( 'targetLink', $this->buildTargetList() ) ; + } + $this->processArrows($data['pageData']['ordering']); + $this->ss->assign('prerow', $this->multiSelect); + $this->ss->assign('clearAll', $app_strings['LBL_CLEARALL']); + $this->ss->assign('rowColor', array('oddListRow', 'evenListRow')); + $this->ss->assign('bgColor', array($odd_bg, $even_bg)); + $this->ss->assign('contextMenus', $this->contextMenus); + $this->ss->assign('is_admin_for_user', is_admin_for_module($GLOBALS['current_user'],'Users')); + $this->ss->assign('is_admin', is_admin($GLOBALS['current_user'])); + + + if($this->contextMenus && !empty($contextMenuObjectsTypes)) { + $script = ''; + $cm = new contextMenu(); + foreach($contextMenuObjectsTypes as $type => $value) { + $cm->loadFromFile($type); + $script .= $cm->getScript(); + $cm->menuItems = array(); // clear menuItems out + } + $this->ss->assign('contextMenuScript', $script); + } + } + + /** + * Assigns the sort arrows in the tpl + * + * @param ordering array data that contains the ordering info + * + */ + function processArrows($ordering) + { + $pathParts = pathinfo(SugarThemeRegistry::current()->getImageURL('arrow.gif',false)); + + list($width,$height) = getimagesize($pathParts['dirname'].'/'.$pathParts['basename']); + + $this->ss->assign('arrowExt', $pathParts['extension']); + $this->ss->assign('arrowWidth', $width); + $this->ss->assign('arrowHeight', $height); + $this->ss->assign('arrowAlt', translate('LBL_SORT')); + } + + + + /** + * Displays the xtpl, either echo or returning the contents + * + * @param end bool display the ending of the listview data (ie MassUpdate) + * + */ + function display($end = true) { + + if(!$this->should_process) return $GLOBALS['app_strings']['LBL_SEARCH_POPULATE_ONLY']; + global $app_strings; + $this->ss->assign('data', $this->data['data']); + $this->data['pageData']['offsets']['lastOffsetOnPage'] = $this->data['pageData']['offsets']['current'] + count($this->data['data']); + $this->ss->assign('pageData', $this->data['pageData']); + + $navStrings = array('next' => $app_strings['LNK_LIST_NEXT'], + 'previous' => $app_strings['LNK_LIST_PREVIOUS'], + 'end' => $app_strings['LNK_LIST_END'], + 'start' => $app_strings['LNK_LIST_START'], + 'of' => $app_strings['LBL_LIST_OF']); + $this->ss->assign('navStrings', $navStrings); + + $str = parent::display(); + $strend = $this->displayEnd(); + + return $str . $this->ss->fetch($this->tpl) . (($end) ? $strend : ''); + } + function displayEnd() { + $str = ''; + if($this->show_mass_update_form) { + if($this->showMassupdateFields){ + $str .= $this->mass->getMassUpdateForm(true); + } + $str .= $this->mass->endMassUpdateForm(); + } + + return $str; + } +} + +?> diff --git a/include/ListView/ListViewXTPL.php b/include/ListView/ListViewXTPL.php new file mode 100644 index 00000000..9be15138 --- /dev/null +++ b/include/ListView/ListViewXTPL.php @@ -0,0 +1,221 @@ +data = $data; + $html_var = strtoupper($html_var); + $this->xtpl = new XTemplate($file); + $this->xtpl->assign('MOD', $GLOBALS['mod_strings']); + $this->xtpl->assign('APP', $GLOBALS['app_strings']); + $this->xtpl->assign('BG_HILITE', $hilite_bg); + $this->xtpl->assign('ORDER_BY', $data['pageData']['urls']['orderBy']); + + $this->processPagination(); + $this->xtpl->parse($this->nav_block); + + $this->processArrows($data['pageData']['ordering']); + + $oddRow = false; + if($this->xtpl->exists($this->pro_nav_block)) $this->xtpl->parse($this->pro_nav_block); + $this->xtpl->assign('CHECKALL', ""); + foreach($data['data'] as $id=>$row) { + $this->xtpl->assign($html_var, $row); + if(!empty($data['pageData']['tag'][$id])) { + $this->xtpl->assign('TAG', $data['pageData']['tag'][$id]); + } + + $this->xtpl->assign('ROW_COLOR', ($oddRow) ? 'oddListRow' : 'evenListRow'); + $this->xtpl->assign('BG_COLOR', ($oddRow) ? $odd_bg : $even_bg); + $oddRow = !$oddRow; + + if($this->xtpl->exists($this->pro_block)) $this->xtpl->parse($this->pro_block); +// if($this->xtpl->exists($this->os_block)) $this->xtpl->parse($this->os_block); + + + $prerow = " "; + $this->xtpl->assign('PREROW', $prerow); + + $this->xtpl->parse($this->row_block); + } + } + + /** + * Assigns the sort arrows in the tpl + * + * @param ordering array data that contains the ordering info + * + */ + function processArrows($ordering) { + + $pathParts = pathinfo(SugarThemeRegistry::current()->getImageURL('arrow.gif',false)); + + list($width,$height) = getimagesize($pathParts['dirname'].'/'.$pathParts['basename']); + + $this->xtpl->assign('arrow_start', " xtpl->assign('arrow_end', "' width='$width' height='$height' align='absmiddle' alt=".translate('LBL_SORT').">"); + $arrow_order = (strcmp($ordering['sortOrder'], 'ASC'))?'_up': '_down'; + $this->xtpl->assign($ordering['orderBy'].'_arrow', $arrow_order); + } + + /** + * Assigns the pagination links at the top and bottom of the listview + * + */ + function processPagination() { + global $app_strings; +//_pp($this->data['pageData']); + if(empty($this->data['pageData']['urls']['prevPage'])) { + $startLink = SugarThemeRegistry::current()->getImage("start_off", "alt='".$app_strings['LNK_LIST_START']."' border='0' align='absmiddle'")." ".$app_strings['LNK_LIST_START']; + $prevLink = SugarThemeRegistry::current()->getImage("previous_off", "alt='".$app_strings['LNK_LIST_PREVIOUS']."' border='0' align='absmiddle'")." ".$app_strings['LNK_LIST_PREVIOUS']; + } + else { +// if($this->multi_select_popup) {// nav links for multiselect popup, submit form to save checks. +// $start_link = "".SugarThemeRegistry::current()->getImage("start","alt='".$app_strings['LNK_LIST_START']."' border='0' align='absmiddle'")." ".$app_strings['LNK_LIST_START'].""; +// $previous_link = "".SugarThemeRegistry::current()->getImage("previous","alt='".$app_strings['LNK_LIST_PREVIOUS']."' border='0' align='absmiddle'")." ".$app_strings['LNK_LIST_PREVIOUS'].""; +// } +// elseif($this->shouldProcess) { +// // TODO: make popups / listview check saving the same +// $start_link = "".SugarThemeRegistry::current()->getImage("start","alt='".$app_strings['LNK_LIST_START']."' border='0' align='absmiddle'")." ".$app_strings['LNK_LIST_START'].""; +// $previous_link = "".SugarThemeRegistry::current()->getImage("previous","alt='".$app_strings['LNK_LIST_PREVIOUS']."' border='0' align='absmiddle'")." ".$app_strings['LNK_LIST_PREVIOUS'].""; +// } +// else { + $startLink = "data['pageData']['urls']['startPage']}\" >".SugarThemeRegistry::current()->getImage("start","alt='".$app_strings['LNK_LIST_START']."' border='0' align='absmiddle'")." ".$app_strings['LNK_LIST_START'].""; + $prevLink = "data['pageData']['urls']['prevPage']}\" >".SugarThemeRegistry::current()->getImage("previous","alt='".$app_strings['LNK_LIST_PREVIOUS']."' border='0' align='absmiddle'")." ".$app_strings['LNK_LIST_PREVIOUS'].""; +// } + } + + if(!$this->data['pageData']['offsets']['totalCounted']) { + $endLink = $app_strings['LNK_LIST_END']." ".SugarThemeRegistry::current()->getImage("end_off","alt='".$app_strings['LNK_LIST_END']."' border='0' align='absmiddle'"); + } + else { +// if($this->multi_select_popup) { // nav links for multiselect popup, submit form to save checks. +// $end_link = "".$app_strings['LNK_LIST_END']." ".SugarThemeRegistry::current()->getImage("end","alt='".$app_strings['LNK_LIST_END']."' border='0' align='absmiddle'").""; +// $next_link = "".$app_strings['LNK_LIST_NEXT']." ".SugarThemeRegistry::current()->getImage("next","alt='".$app_strings['LNK_LIST_NEXT']."' border='0' align='absmiddle'").""; +// } +// elseif($this->shouldProcess) { +// $end_link = "".$app_strings['LNK_LIST_END']." ".SugarThemeRegistry::current()->getImage("end","alt='".$app_strings['LNK_LIST_END']."' border='0' align='absmiddle'").""; +// $next_link = "".$app_strings['LNK_LIST_NEXT']." ".SugarThemeRegistry::current()->getImage("next","alt='".$app_strings['LNK_LIST_NEXT']."' border='0' align='absmiddle'").""; +// } +// else { + $endLink = "data['pageData']['urls']['endPage']}\" >".$app_strings['LNK_LIST_END']." ".SugarThemeRegistry::current()->getImage("end","alt='".$app_strings['LNK_LIST_END']."' border='0' align='absmiddle'").""; + +// } + } + if(empty($this->data['pageData']['urls']['nextPage'])){ + $nextLink = $app_strings['LNK_LIST_NEXT']." ".SugarThemeRegistry::current()->getImage("next_off","alt='".$app_strings['LNK_LIST_NEXT']."' border='0' align='absmiddle'"); + }else{ + $nextLink = "data['pageData']['urls']['nextPage']}\" >".$app_strings['LNK_LIST_NEXT']." ".SugarThemeRegistry::current()->getImage("next","alt='".$app_strings['LNK_LIST_NEXT']."' border='0' align='absmiddle'").""; + } + + if($this->export) $export_link = $this->buildExportLink(); + else $export_link = ''; + if($this->mailMerge)$merge_link = $this->buildMergeLink(); + else $merge_link = ''; + if($this->multiSelect) $selected_objects_span = $this->buildSelectedObjectsSpan(); + else $selected_objects_span = ''; + + $htmlText = "\n" + . "\n\n"; + + $this->xtpl->assign("PAGINATION", $htmlText); + } + + /** + * Displays the xtpl, either echo or returning the contents + * + * @param echo bool echo or return contents + * + */ + function display($echo = true) { + $str = parent::display(); + $strend = parent::displayEnd(); + $this->xtpl->parse($this->main_block); + if($echo) { + echo $str; + $this->xtpl->out($this->main_block); + echo $strend; + } + else { + return $str . $this->xtpl->text() . $strend; + } + } +} + + +?> \ No newline at end of file diff --git a/include/Localization/Localization.php b/include/Localization/Localization.php new file mode 100644 index 00000000..98f8610d --- /dev/null +++ b/include/Localization/Localization.php @@ -0,0 +1,694 @@ +localeNameFormatDefault = empty($sugar_config['locale_name_format_default']) ? 's f l' : $sugar_config['default_name_format']; + $this->loadCurrencies(); + } + + /** + * returns an array of Sugar Config defaults that are determined by locale settings + * @return array + */ + function getLocaleConfigDefaults() { + $coreDefaults = array( + 'currency' => '', + 'datef' => 'm/d/Y', + 'timef' => 'H:i', + 'default_currency_significant_digits' => 2, + 'default_currency_symbol' => '$', + 'default_export_charset' => $this->default_export_charset, + 'default_locale_name_format' => 's f l', + 'default_number_grouping_seperator' => ',', + 'default_decimal_seperator' => '.', + 'export_delimiter' => ',', + 'default_email_charset' => $this->default_email_charset, + ); + + return $coreDefaults; + } + + /** + * abstraction of precedence + * @param string prefName Name of preference to retrieve based on overrides + * @param object user User in focus, default null (current_user) + * @return string pref Most significant preference + */ + function getPrecedentPreference($prefName, $user=null, $sugarConfigPrefName = '') { + global $current_user; + global $sugar_config; + + $userPref = ''; + $coreDefaults = $this->getLocaleConfigDefaults(); + $pref = isset($coreDefaults[$prefName]) ? $coreDefaults[$prefName] : ''; // defaults, even before config.php + + if($user != null) { + $userPref = $user->getPreference($prefName); + } elseif(!empty($current_user)) { + $userPref = $current_user->getPreference($prefName); + } + // Bug 39171 - If we are asking for default_email_charset, check in emailSettings['defaultOutboundCharset'] as well + if ( $prefName == 'default_email_charset' ) { + if($user != null) { + $emailSettings = $user->getPreference('emailSettings', 'Emails'); + } elseif(!empty($current_user)) { + $emailSettings = $current_user->getPreference('emailSettings', 'Emails'); + } + if ( isset($emailSettings['defaultOutboundCharset']) ) { + $userPref = $emailSettings['defaultOutboundCharset']; + } + } + + // set fallback defaults defined in this class + if(isset($this->$prefName)) { + $pref = $this->$prefName; + } + //rrs: 33086 - give the ability to pass in the preference name as stored in $sugar_config. + if(!empty($sugarConfigPrefName)){ + $prefName = $sugarConfigPrefName; + } + // cn: 9549 empty() call on a value of 0 (0 significant digits) resulted in a false-positive. changing to "isset()" + $pref = (!isset($sugar_config[$prefName]) || (empty($sugar_config[$prefName]) && $sugar_config[$prefName] !== '0')) ? $pref : $sugar_config[$prefName]; + $pref = (empty($userPref) && $userPref !== '0') ? $pref : $userPref; + return $pref; + } + + /////////////////////////////////////////////////////////////////////////// + //// CURRENCY HANDLING + /** + * wrapper for whatever currency system we implement + */ + function loadCurrencies() { + // doing it dirty here + global $db; + global $sugar_config; + + if(empty($db)) { + return array(); + } + + $load = sugar_cache_retrieve('currency_list'); + if ( !is_array($load) ) { + $q = "SELECT id, name, symbol, conversion_rate FROM currencies WHERE status = 'Active' and deleted = 0"; + $r = $db->query($q); + + while($a = $db->fetchByAssoc($r)) { + $load = array(); + $load['name'] = $a['name']; + $load['symbol'] = $a['symbol']; + $load['conversion_rate'] = $a['conversion_rate']; + + $this->currencies[$a['id']] = $load; + } + sugar_cache_put('currency_list',$this->currencies); + } else { + $this->currencies = $load; + } + + // load default from config.php + $this->currencies['-99'] = array( + 'name' => $sugar_config['default_currency_name'], + 'symbol' => $sugar_config['default_currency_symbol'], + 'conversion_rate' => 1 + ); + + } + + /** + * getter for currencies array + * @return array $this->currencies returns array( id => array(name => X, etc + */ + function getCurrencies() { + return $this->currencies; + } + + /** + * retrieves default OOTB currencies for sugar_config and installer. + * @return array ret Array of default currencies keyed by ISO4217 code + */ + function getDefaultCurrencies() { + $ret = array( + 'AUD' => array( 'name' => 'Australian Dollars', + 'iso4217' => 'AUD', + 'symbol' => '$'), + 'BRL' => array( 'name' => 'Brazilian Reais', + 'iso4217' => 'BRL', + 'symbol' => 'R$'), + 'GBP' => array( 'name' => 'British Pounds', + 'iso4217' => 'GBP', + 'symbol' => '£'), + 'CAD' => array( 'name' => 'Canadian Dollars', + 'iso4217' => 'CAD', + 'symbol' => '$'), + 'CNY' => array( 'name' => 'Chinese Yuan', + 'iso4217' => 'CNY', + 'symbol' => 'ï¿¥'), + 'EUR' => array( 'name' => 'Euro', + 'iso4217' => 'EUR', + 'symbol' => '€'), + 'HKD' => array( 'name' => 'Hong Kong Dollars', + 'iso4217' => 'HKD', + 'symbol' => '$'), + 'INR' => array( 'name' => 'Indian Rupees', + 'iso4217' => 'INR', + 'symbol' => '₨'), + 'KRW' => array( 'name' => 'Korean Won', + 'iso4217' => 'KRW', + 'symbol' => '₩'), + 'YEN' => array( 'name' => 'Japanese Yen', + 'iso4217' => 'JPY', + 'symbol' => 'Â¥'), + 'MXM' => array( 'name' => 'Mexican Pesos', + 'iso4217' => 'MXM', + 'symbol' => '$'), + 'SGD' => array( 'name' => 'Singaporean Dollars', + 'iso4217' => 'SGD', + 'symbol' => '$'), + 'CHF' => array( 'name' => 'Swiss Franc', + 'iso4217' => 'CHF', + 'symbol' => 'SFr.'), + 'THB' => array( 'name' => 'Thai Baht', + 'iso4217' => 'THB', + 'symbol' => '฿'), + 'USD' => array( 'name' => 'US Dollars', + 'iso4217' => 'USD', + 'symbol' => '$'), + ); + + return $ret; + } + //// END CURRENCY HANDLING + /////////////////////////////////////////////////////////////////////////// + + + /////////////////////////////////////////////////////////////////////////// + //// CHARSET TRANSLATION + /** + * returns a mod|app_strings array in the target charset + * @param array strings $mod_string, et.al. + * @param string charset Target charset + * @return array Translated string pack + */ + function translateStringPack($strings, $charset) { + // handle recursive + foreach($strings as $k => $v) { + if(is_array($v)) { + $strings[$k] = $this->translateStringPack($v, $charset); + } else { + $strings[$k] = $this->translateCharset($v, 'UTF-8', $charset); + } + } + ksort($strings); + return $strings; + } + + /** + * translates the passed variable for email sending (export) + * @param mixed the var (array or string) to translate + * @return mixed the translated variable + */ + function translateForEmail($var) { + if(is_array($var)) { + foreach($var as $k => $v) { + $var[$k] = $this->translateForEmail($v); + } + return $var; + } elseif(!empty($var)) { + return $this->translateCharset($var, 'UTF-8', $this->getOutboundEmailCharset()); + } + } + + /** + * prepares a bean for export by translating any text fields into the export + * character set + * @param bean object A SugarBean + * @return bean object The bean with translated strings + */ + function prepBeanForExport($bean) { + foreach($bean->field_defs as $k => $field) { + $bean->$k = $this->translateCharset($bean->$k, 'UTF-8', $this->getExportCharset()); + } + + return $bean; + } + + /** + * translates a character set from one encoding to another encoding + * @param string string the string to be translated + * @param string fromCharset the charset the string is currently in + * @param string toCharset the charset to translate into (defaults to UTF-8) + * @return string the translated string + */ + function translateCharset($string, $fromCharset, $toCharset='UTF-8') { + $GLOBALS['log']->debug("Localization: translating [ {$string} ] into {$toCharset}"); + if(function_exists('mb_convert_encoding')) { + return mb_convert_encoding($string, $toCharset, $fromCharset); + } elseif(function_exists('iconv')) { // iconv is flakey + return iconv($fromCharset, $toCharset, $string); + } else { + return $string; + } // end else clause + } + + /** + * translates a character set from one to another, and the into MIME-header friendly format + */ + function translateCharsetMIME($string, $fromCharset, $toCharset='UTF-8', $encoding="Q") { + $previousEncoding = mb_internal_encoding(); + mb_internal_encoding($toCharset); + $result = mb_encode_mimeheader($string, $toCharset, $encoding); + mb_internal_encoding($previousEncoding); + return $result; + } + + function normalizeCharset($charset) { + $charset = strtolower(preg_replace("/[\-\_]*/", "", $charset)); + return $charset; + } + + /** + * returns an array of charsets with keys for available translations; appropriate for get_select_options_with_id() + */ + function getCharsetSelect() { + //jc:12293 - the "labels" or "human-readable" representations of the various charsets + //should be translatable + $translated = array(); + foreach($this->availableCharsets as $key) + { + //$translated[$key] = translate($value); + $translated[$key] = translate($key); + } + + return $translated; + //end:12293 + } + + /** + * returns the charset preferred in descending order: User, Sugar Config, DEFAULT + * @param string charset to override ALL, pass a valid charset here + * @return string charset the chosen character set + */ + function getExportCharset($charset='', $user=null) { + $charset = $this->getPrecedentPreference('default_export_charset', $user); + return $charset; + } + + /** + * returns the charset preferred in descending order: User, Sugar Config, DEFAULT + * @return string charset the chosen character set + */ + function getOutboundEmailCharset($user=null) { + $charset = $this->getPrecedentPreference('default_email_charset', $user); + return $charset; + } + //// END CHARSET TRANSLATION + /////////////////////////////////////////////////////////////////////////// + + /////////////////////////////////////////////////////////////////////////// + //// NUMBER DISPLAY FORMATTING CODE + function getDecimalSeparator($user=null) { + $dec = $this->getPrecedentPreference('default_decimal_separator', $user); + return $dec; + } + + function getNumberGroupingSeparator($user=null) { + $sep = $this->getPrecedentPreference('default_number_grouping_seperator', $user); + return $sep; + } + + function getPrecision($user=null) { + $precision = $this->getPrecedentPreference('default_currency_significant_digits', $user); + return $precision; + } + + function getCurrencySymbol($user=null) { + $dec = $this->getPrecedentPreference('default_currency_symbol', $user); + return $dec; + } + + /** + * returns a number formatted by user preference or system default + * @param string number Number to be formatted and returned + * @param string currencySymbol Currency symbol if override is necessary + * @param bool is_currency Flag to also return the currency symbol + * @return string Formatted number + */ + function getLocaleFormattedNumber($number, $currencySymbol='', $is_currency=true, $user=null) { + $fnum = $number; + $majorDigits = ''; + $minorDigits = ''; + $dec = $this->getDecimalSeparator($user); + $thou = $this->getNumberGroupingSeparator($user); + $precision = $this->getPrecision($user); + $symbol = empty($currencySymbol) ? $this->getCurrencySymbol($user) : $currencySymbol; + + $exNum = explode($dec, $number); + // handle grouping + if(is_array($exNum) && count($exNum) > 0) { + if(strlen($exNum[0]) > 3) { + $offset = strlen($exNum[0]) % 3; + if($offset > 0) { + for($i=0; $i<$offset; $i++) { + $majorDigits .= $exNum[0]{$i}; + } + } + + $tic = 0; + for($i=$offset; $i 0) { // we toss the minor digits otherwise + if(is_array($exNum) && isset($exNum[1])) { + + } + } + + + if($is_currency) { + $fnum = $symbol.$fnum; + } + return $fnum; + } + + /** + * returns Javascript to format numbers and currency for ***DISPLAY*** + */ + function getNumberJs() { + $out = << 0) { + var strlength = majorDigits.length; + + if(strlength > 3) { + var offset = strlength % 3; // find how many to lead off by + + for(j=0; j 0) { + for(i=0; igetPrecedentPreference('default_locale_name_format', $user); + return $returnFormat; + } + + /** + * returns formatted name according to $current_user's locale settings + * + * @param string firstName + * @param string lastName + * @param string salutation + * @param string title + * @param string format If a particular format is desired, then pass this optional parameter as a simple string. + * sfl is "Salutation FirstName LastName", "l, f s" is "LastName[comma][space]FirstName[space]Salutation" + * @param object user object + * @param bool returnEmptyStringIfEmpty true if we should return back an empty string rather than a single space + * when the formatted name would be blank + * @return string formattedName + */ + function getLocaleFormattedName($firstName, $lastName, $salutationKey='', $title='', $format="", $user=null, $returnEmptyStringIfEmpty = false) { + global $current_user; + global $app_list_strings; + + if ( $user == null ) { + $user = $current_user; + } + + $salutation = $salutationKey; + if(!empty($salutationKey) && !empty($app_list_strings['salutation_dom'][$salutationKey])) { + $salutation = (!empty($app_list_strings['salutation_dom'][$salutationKey]) ? $app_list_strings['salutation_dom'][$salutationKey] : $salutationKey); + } + + //check to see if passed in variables are set, if so, then populate array with value, + //if not, then populate array with blank '' + $names = array(); + $names['f'] = (empty($firstName) && $firstName != 0) ? '' : $firstName; + $names['l'] = (empty($lastName) && $lastName != 0) ? '' : $lastName; + $names['s'] = (empty($salutation) && $salutation != 0) ? '' : $salutation; + $names['t'] = (empty($title) && $title != 0) ? '' : $title; + + //Bug: 39936 - if all of the inputs are empty, then don't try to format the name. + $allEmpty = true; + foreach($names as $key => $val){ + if(!empty($val)){ + $allEmpty = false; + break; + } + } + if($allEmpty){ + return $returnEmptyStringIfEmpty ? '' : ' '; + } + //end Bug: 39936 + + if(empty($format)) { + $this->localeNameFormat = $this->getLocaleFormatMacro($user); + } else { + $this->localeNameFormat = $format; + } + + // parse localeNameFormat + $formattedName = ''; + for($i=0; $ilocaleNameFormat); $i++) { + $formattedName .= array_key_exists($this->localeNameFormat{$i}, $names) ? $names[$this->localeNameFormat{$i}] : $this->localeNameFormat{$i}; + } + + $formattedName = trim($formattedName); + if (strlen($formattedName)==0) { + return $returnEmptyStringIfEmpty ? '' : ' '; + } + + if(strpos($formattedName,',',strlen($formattedName)-1)) { // remove trailing commas + $formattedName = substr($formattedName, 0, strlen($formattedName)-1); + } + return trim($formattedName); + } + + /** + * outputs some simple Javascript to show a preview of Name format in "My Account" and "Admin->Localization" + * @param string first First Name, use app_strings default if not specified + * @param string last Last Name, use app_strings default if not specified + * @param string salutation Saluation, use app_strings default if not specified + * @return string some Javascript + */ + function getNameJs($first='', $last='', $salutation='', $title='') { + global $app_strings; + + $salutation = !empty($salutation) ? $salutation : $app_strings['LBL_LOCALE_NAME_EXAMPLE_SALUTATION']; + $first = !empty($first) ? $first : $app_strings['LBL_LOCALE_NAME_EXAMPLE_FIRST']; + $last = !empty($last) ? $last : $app_strings['LBL_LOCALE_NAME_EXAMPLE_LAST']; + $title = !empty($title) ? $title : $app_strings['LBL_LOCALE_NAME_EXAMPLE_TITLE']; + + $ret = " + function setPreview() { + format = document.getElementById('default_locale_name_format').value; + field = document.getElementById('nameTarget'); + + stuff = new Object(); + + stuff['s'] = '{$salutation}'; + stuff['f'] = '{$first}'; + stuff['l'] = '{$last}'; + stuff['t'] = '{$title}'; + + var name = ''; + for(i=0; i \ No newline at end of file diff --git a/include/MVC/Controller/ControllerFactory.php b/include/MVC/Controller/ControllerFactory.php new file mode 100644 index 00000000..aad9f29d --- /dev/null +++ b/include/MVC/Controller/ControllerFactory.php @@ -0,0 +1,82 @@ +setup($module); + return $controller; + } + +} +?> \ No newline at end of file diff --git a/include/MVC/Controller/SugarController.php b/include/MVC/Controller/SugarController.php new file mode 100644 index 00000000..c6ddcdf3 --- /dev/null +++ b/include/MVC/Controller/SugarController.php @@ -0,0 +1,833 @@ +'editview'); + */ + protected $action_remap = array('index'=>'listview'); + /** + * The name of the current module. + */ + public $module = 'Home'; + /** + * The name of the target module. + */ + public $target_module = null; + /** + * The name of the current action. + */ + public $action = 'index'; + /** + * The id of the current record. + */ + public $record = ''; + /** + * The name of the return module. + */ + public $return_module = null; + /** + * The name of the return action. + */ + public $return_action = null; + /** + * The id of the return record. + */ + public $return_id = null; + /** + * If the action was remapped it will be set to do_action and then we will just + * use do_action for the actual action to perform. + */ + protected $do_action = 'index'; + /** + * If a bean is present that set it. + */ + public $bean = null; + /** + * url to redirect to + */ + public $redirect_url = ''; + /** + * any subcontroller can modify this to change the view + */ + public $view = 'classic'; + /** + * this array will hold the mappings between a key and an object for use within the view. + */ + public $view_object_map = array(); + + /** + * This array holds the methods that handleAction() will invoke, in sequence. + */ + protected $tasks = array( + 'pre_action', + 'do_action', + 'post_action' + ); + /** + * List of options to run through within the process() method. + * This list is meant to easily allow additions for new functionality as well as + * the ability to add a controller's own handling. + */ + public $process_tasks = array( + 'blockFileAccess', + 'handleEntryPoint', + 'callLegacyCode', + 'remapAction', + 'handle_action', + 'handleActionMaps', + ); + /** + * Whether or not the action has been handled by $process_tasks + * + * @var bool + */ + protected $_processed = false; + /** + * Map an action directly to a file + */ + /** + * Map an action directly to a file. This will be loaded from action_file_map.php + */ + protected $action_file_map = array(); + /** + * Map an action directly to a view + */ + /** + * Map an action directly to a view. This will be loaded from action_view_map.php + */ + protected $action_view_map = array(); + + /** + * This can be set from the application to tell us whether we have authorization to + * process the action. If this is set we will default to the noaccess view. + */ + public $hasAccess = true; + + /** + * Map case sensitive filenames to action. This is used for linux/unix systems + * where filenames are case sensitive + */ + public static $action_case_file = array( + 'editview'=>'EditView', + 'detailview'=>'DetailView', + 'listview'=>'ListView' + ); + + /** + * Constructor. This ie meant tot load up the module, action, record as well + * as the mapping arrays. + */ + function SugarController(){ + } + + /** + * Called from SugarApplication and is meant to perform the setup operations + * on the controller. + * + */ + public function setup($module = ''){ + if(empty($module) && !empty($_REQUEST['module'])) + $module = $_REQUEST['module']; + //set the module + if(!empty($module)) + $this->setModule($module); + + if(!empty($_REQUEST['target_module']) && $_REQUEST['target_module'] != 'undefined') { + $this->target_module = $_REQUEST['target_module']; + } + //set properties on the controller from the $_REQUEST + $this->loadPropertiesFromRequest(); + //load the mapping files + $this->loadMappings(); + } + /** + * Set the module on the Controller + * + * @param object $module + */ + public function setModule($module){ + $this->module = $module; + } + + /** + * Set properties on the Controller from the $_REQUEST + * + */ + private function loadPropertiesFromRequest(){ + if(!empty($_REQUEST['action'])) + $this->action = $_REQUEST['action']; + if(!empty($_REQUEST['record'])) + $this->record = $_REQUEST['record']; + if(!empty($_REQUEST['view'])) + $this->view = $_REQUEST['view']; + if(!empty($_REQUEST['return_module'])) + $this->return_module = $_REQUEST['return_module']; + if(!empty($_REQUEST['return_action'])) + $this->return_action = $_REQUEST['return_action']; + if(!empty($_REQUEST['return_id'])) + $this->return_id = $_REQUEST['return_id']; + } + + /** + * Load map files for use within the Controller + * + */ + private function loadMappings(){ + $this->loadMapping('action_view_map'); + $this->loadMapping('action_file_map'); + $this->loadMapping('action_remap', true); + } + + /** + * Given a record id load the bean. This bean is accessible from any sub controllers. + */ + public function loadBean() + { + if(!empty($GLOBALS['beanList'][$this->module])){ + $class = $GLOBALS['beanList'][$this->module]; + if(!empty($GLOBALS['beanFiles'][$class])){ + require_once($GLOBALS['beanFiles'][$class]); + $this->bean = new $class(); + if(!empty($this->record)){ + $this->bean->retrieve($this->record); + if($this->bean) + $GLOBALS['FOCUS'] = $this->bean; + } + } + } + } + + /** + * Generic load method to load mapping arrays. + */ + private function loadMapping($var, $merge = false){ + $$var = sugar_cache_retrieve("CONTROLLER_". $var . "_".$this->module); + if(!$$var){ + if($merge && !empty($this->$var)){ + $$var = $this->$var; + }else{ + $$var = array(); + } + if(file_exists('include/MVC/Controller/'. $var . '.php')){ + require('include/MVC/Controller/'. $var . '.php'); + } + if(file_exists('modules/'.$this->module.'/'. $var . '.php')){ + require('modules/'.$this->module.'/'. $var . '.php'); + } + if(file_exists('custom/modules/'.$this->module.'/'. $var . '.php')){ + require('custom/modules/'.$this->module.'/'. $var . '.php'); + } + if(file_exists('custom/include/MVC/Controller/'. $var . '.php')){ + require('custom/include/MVC/Controller/'. $var . '.php'); + } + + sugar_cache_put("CONTROLLER_". $var . "_".$this->module, $$var); + } + $this->$var = $$var; + } + + /** + * This method is called from SugarApplication->execute and it will bootstrap the entire controller process + */ + final public function execute(){ + $this->process(); + if(!empty($this->view)){ + $this->processView(); + }elseif(!empty($this->redirect_url)){ + $this->redirect(); + } + } + + /** + * Display the appropriate view. + */ + private function processView(){ + $view = ViewFactory::loadView($this->view, $this->module, $this->bean, $this->view_object_map, $this->target_module); + $GLOBALS['current_view'] = $view; + if(!empty($this->bean) && !$this->bean->ACLAccess($view->type) && $view->type != 'list'){ + ACLController::displayNoAccess(true); + sugar_cleanup(true); + } + if(isset($this->errors)){ + $view->errors = $this->errors; + } + $view->process(); + } + + /** + * Meant to be overridden by a subclass and allows for specific functionality to be + * injected prior to the process() method being called. + */ + public function preProcess() + {} + + /** + * if we have a function to support the action use it otherwise use the default action + * + * 1) check for file + * 2) check for action + */ + public function process(){ + $GLOBALS['action'] = $this->action; + $GLOBALS['module'] = $this->module; + + //check to ensure we have access to the module. + if($this->hasAccess){ + $this->do_action = $this->action; + + $file = self::getActionFilename($this->do_action); + + $this->loadBean(); + + $processed = false; + foreach($this->process_tasks as $process){ + $this->$process(); + if($this->_processed) + break; + } + + $this->redirect(); + }else{ + $this->no_access(); + } + } + + /** + * This method is called from the process method. I could also be called within an action_* method. + * It allows a developer to override any one of these methods contained within, + * or if the developer so chooses they can override the entire action_* method. + * + * @return true if any one of the pre_, do_, or post_ methods have been defined, + * false otherwise. This is important b/c if none of these methods exists, then we will run the + * action_default() method. + */ + protected function handle_action(){ + $processed = false; + foreach($this->tasks as $task){ + $processed = ($this->$task() || $processed); + } + $this->_processed = $processed; + } + + /** + * Perform an action prior to the specified action. + * This can be overridde in a sub-class + */ + private function pre_action(){ + $function = 'pre_' . $this->action; + if($this->hasFunction($function)){ + $GLOBALS['log']->debug('Performing pre_action'); + $this->$function(); + return true; + } + return false; + } + + /** + * Perform the specified action. + * This can be overridde in a sub-class + */ + private function do_action(){ + $function = 'action_'. strtolower($this->do_action); + if($this->hasFunction($function)){ + $GLOBALS['log']->debug('Performing action: '.$function.' MODULE: '.$this->module); + $this->$function(); + return true; + } + return false; + } + + /** + * Perform an action after to the specified action has occurred. + * This can be overridde in a sub-class + */ + private function post_action(){ + $function = 'post_' . $this->action; + if($this->hasFunction($function)){ + $GLOBALS['log']->debug('Performing post_action'); + $this->$function(); + return true; + } + return false; + } + + /** + * If there is no action found then display an error to the user. + */ + protected function no_action(){ + sugar_die($GLOBALS['app_strings']['LBL_NO_ACTION']); + } + + /** + * The default action handler for instances where we do not have access to process. + */ + protected function no_access(){ + $this->view = 'noaccess'; + } + + /////////////////////////////////////////////// + /////// HELPER FUNCTIONS + /////////////////////////////////////////////// + + /** + * Determine if a given function exists on the objects + * @param function - the function to check + * @return true if the method exists on the object, false otherwise + */ + protected function hasFunction($function){ + return method_exists($this, $function); + } + + + /** + * Set the url to which we will want to redirect + * + * @param string url - the url to which we will want to redirect + */ + protected function set_redirect($url){ + $this->redirect_url = $url; + } + + /** + * Perform redirection based on the redirect_url + * + */ + protected function redirect(){ + + if(!empty($this->redirect_url)) + SugarApplication::redirect($this->redirect_url); + } + + //////////////////////////////////////////////////////// + ////// DEFAULT ACTIONS + /////////////////////////////////////////////////////// + + /* + * Save a bean + */ + + /** + * Do some processing before saving the bean to the database. + */ + public function pre_save(){ + if(!empty($_POST['assigned_user_id']) && $_POST['assigned_user_id'] != $this->bean->assigned_user_id && $_POST['assigned_user_id'] != $GLOBALS['current_user']->id && empty($GLOBALS['sugar_config']['exclude_notifications'][$this->bean->module_dir])){ + $this->bean->notify_on_save = true; + } + $GLOBALS['log']->debug("SugarController:: performing pre_save."); + require_once('include/SugarFields/SugarFieldHandler.php'); + $sfh = new SugarFieldHandler(); + foreach($this->bean->field_defs as $field => $properties) { + $type = !empty($properties['custom_type']) ? $properties['custom_type'] : $properties['type']; + $sf = $sfh->getSugarField(ucfirst($type), true); + if(isset($_POST[$field])) { + if(is_array($_POST[$field]) && !empty($properties['isMultiSelect'])) { + if(empty($_POST[$field][0])) { + unset($_POST[$field][0]); + } + $_POST[$field] = encodeMultienumValue($_POST[$field]); + } + $this->bean->$field = $_POST[$field]; + } else if(!empty($properties['isMultiSelect']) && !isset($_POST[$field]) && isset($_POST[$field . '_multiselect'])) { + $this->bean->$field = ''; + } + if($sf != null){ + $sf->save($this->bean, $_POST, $field, $properties); + } + } + + foreach($this->bean->relationship_fields as $field=>$link){ + if(!empty($_POST[$field])){ + $this->bean->$field = $_POST[$field]; + } + } + if(!$this->bean->ACLAccess('save')){ + ACLController::displayNoAccess(true); + sugar_cleanup(true); + } + $this->bean->unformat_all_fields(); + } + + /** + * Perform the actual save + */ + public function action_save(){ + $this->bean->save(!empty($this->bean->notify_on_save)); + } + + /** + * Specify what happens after the save has occurred. + */ + protected function post_save(){ + $module = (!empty($this->return_module) ? $this->return_module : $this->module); + $action = (!empty($this->return_action) ? $this->return_action : 'DetailView'); + $id = (!empty($this->return_id) ? $this->return_id : $this->bean->id); + + $url = "index.php?module=".$module."&action=".$action."&record=".$id; + $this->set_redirect($url); + } + + /* + * Delete a bean + */ + + /** + * Perform the actual deletion. + */ + protected function action_delete(){ + //do any pre delete processing + //if there is some custom logic for deletion. + if(!empty($_REQUEST['record'])){ + if(!$this->bean->ACLAccess('Delete')){ + ACLController::displayNoAccess(true); + sugar_cleanup(true); + } + $this->bean->mark_deleted($_REQUEST['record']); + }else{ + sugar_die("A record number must be specified to delete"); + } + } + + /** + * Specify what happens after the deletion has occurred. + */ + protected function post_delete(){ + $return_module = isset($_REQUEST['return_module']) ? + $_REQUEST['return_module'] : + $GLOBALS['sugar_config']['default_module']; + $return_action = isset($_REQUEST['return_action']) ? + $_REQUEST['return_action'] : + $GLOBALS['sugar_config']['default_action']; + $return_id = isset($_REQUEST['return_id']) ? + $_REQUEST['return_id'] : + ''; + $url = "index.php?module=".$return_module."&action=".$return_action."&record=".$return_id; + $this->set_redirect($url); + } + /** + * Perform the actual massupdate. + */ + protected function action_massupdate(){ + if(!empty($_REQUEST['massupdate']) && $_REQUEST['massupdate'] == 'true' && (!empty($_REQUEST['uid']) || !empty($_REQUEST['entire']))){ + if(!empty($_REQUEST['Delete']) && $_REQUEST['Delete']=='true' && !$this->bean->ACLAccess('delete') + || (empty($_REQUEST['Delete']) || $_REQUEST['Delete']!='true') && !$this->bean->ACLAccess('save')){ + ACLController::displayNoAccess(true); + sugar_cleanup(true); + } + + set_time_limit(0);//I'm wondering if we will set it never goes timeout here. + // until we have more efficient way of handling MU, we have to disable the limit + $GLOBALS['db']->setQueryLimit(0); + require_once("include/MassUpdate.php"); + require_once('modules/MySettings/StoreQuery.php'); + $seed = loadBean($_REQUEST['module']); + $mass = new MassUpdate(); + $mass->setSugarBean($seed); + if(isset($_REQUEST['entire']) && empty($_POST['mass'])) { + $mass->generateSearchWhere($_REQUEST['module'], $_REQUEST['current_query_by_page']); + } + $mass->handleMassUpdate(); + $storeQuery = new StoreQuery();//restore the current search. to solve bug 24722 for multi tabs massupdate. + $temp_req = array('current_query_by_page' => $_REQUEST['current_query_by_page'], 'return_module' => $_REQUEST['return_module'], 'return_action' => $_REQUEST['return_action']); + if($_REQUEST['return_module'] == 'Emails') { + if(!empty($_REQUEST['type']) && !empty($_REQUEST['ie_assigned_user_id'])) { + $this->req_for_email = array('type' => $_REQUEST['type'], 'ie_assigned_user_id' => $_REQUEST['ie_assigned_user_id']); //specificly for My Achieves + } + } + $_REQUEST = array(); + $_REQUEST = unserialize(base64_decode($temp_req['current_query_by_page'])); + unset($_REQUEST[$seed->module_dir.'2_'.strtoupper($seed->object_name).'_offset']);//after massupdate, the page should redirect to no offset page + $storeQuery->saveFromRequest($_REQUEST['module']); + $_REQUEST = array('return_module' => $temp_req['return_module'], 'return_action' => $temp_req['return_action']);//for post_massupdate, to go back to original page. + }else{ + sugar_die("You must massupdate at least one record"); + } + } + /** + * Specify what happens after the massupdate has occurred. + */ + protected function post_massupdate(){ + $return_module = isset($_REQUEST['return_module']) ? + $_REQUEST['return_module'] : + $GLOBALS['sugar_config']['default_module']; + $return_action = isset($_REQUEST['return_action']) ? + $_REQUEST['return_action'] : + $GLOBALS['sugar_config']['default_action']; + $url = "index.php?module=".$return_module."&action=".$return_action; + if($return_module == 'Emails'){//specificly for My Achieves + if(!empty($this->req_for_email['type']) && !empty($this->req_for_email['ie_assigned_user_id'])) { + $url = $url . "&type=".$this->req_for_email['type']."&assigned_user_id=".$this->req_for_email['ie_assigned_user_id']; + } + } + $this->set_redirect($url); + } + /** + * Perform the listview action + */ + protected function action_listview(){ + $this->view_object_map['bean'] = $this->bean; + $this->view = 'list'; + } + +/* + + //THIS IS HANDLED IN ACTION_REMAP WHERE INDEX IS SET TO LISTVIEW + function action_index(){ + } +*/ + + /** + * Action to handle when using a file as was done in previous versions of Sugar. + */ + protected function action_default(){ + $this->view = 'classic'; + } + + /** + * this method id used within a Dashlet when performing an ajax call + */ + protected function action_callmethoddashlet(){ + if(!empty($_REQUEST['id'])) { + $id = $_REQUEST['id']; + $requestedMethod = $_REQUEST['method']; + $dashletDefs = $GLOBALS['current_user']->getPreference('dashlets', 'Home'); // load user's dashlets config + if(!empty($dashletDefs[$id])) { + require_once($dashletDefs[$id]['fileLocation']); + + $dashlet = new $dashletDefs[$id]['className']($id, (isset($dashletDefs[$id]['options']) ? $dashletDefs[$id]['options'] : array())); + + if(method_exists($dashlet, $requestedMethod) || method_exists($dashlet, '__call')) { + echo $dashlet->$requestedMethod(); + } + else { + echo 'no method'; + } + } + } + } + + /** + * this method is used within a Dashlet when the options configuration is posted + */ + protected function action_configuredashlet(){ + global $current_user, $mod_strings; + + if(!empty($_REQUEST['id'])) { + $id = $_REQUEST['id']; + $dashletDefs = $current_user->getPreference('dashlets', $_REQUEST['module']); // load user's dashlets config + require_once($dashletDefs[$id]['fileLocation']); + + $dashlet = new $dashletDefs[$id]['className']($id, (isset($dashletDefs[$id]['options']) ? $dashletDefs[$id]['options'] : array())); + if(!empty($_REQUEST['configure']) && $_REQUEST['configure']) { // save settings + $dashletDefs[$id]['options'] = $dashlet->saveOptions($_REQUEST); + $current_user->setPreference('dashlets', $dashletDefs, 0, $_REQUEST['module']); + } + else { // display options + $json = getJSONobj(); + return 'result = ' . $json->encode((array('header' => $dashlet->title . ' : ' . $mod_strings['LBL_OPTIONS'], + 'body' => $dashlet->displayOptions()))); + + } + } + else { + return '0'; + } + } + + /** + * getActionFilename + */ + public static function getActionFilename($action) { + if(isset(self::$action_case_file[$action])) { + return self::$action_case_file[$action]; + } + return $action; + } + + /********************************************************************/ + // PROCESS TASKS + /********************************************************************/ + + /** + * Given the module and action, determine whether the super/admin has prevented access + * to this url. In addition if any links specified for this module, load the links into + * GLOBALS + * + * @return true if we want to stop processing, false if processing should continue + */ + private function blockFileAccess(){ + //check if the we have enabled file_access_control and if so then check the mappings on the request; + if(!empty($GLOBALS['sugar_config']['admin_access_control']) && $GLOBALS['sugar_config']['admin_access_control']){ + $this->loadMapping('file_access_control_map'); + //since we have this turned on, check the mapping file + $module = strtolower($this->module); + $action = strtolower($this->do_action); + if(!empty($this->file_access_control_map['modules'][$module]['links'])){ + $GLOBALS['admin_access_control_links'] = $this->file_access_control_map['modules'][$module]['links']; + } + + if(!empty($this->file_access_control_map['modules'][$module]['actions']) && (in_array($action, $this->file_access_control_map['modules'][$module]['actions']) || !empty($this->file_access_control_map['modules'][$module]['actions'][$action]))){ + //check params + if(!empty($this->file_access_control_map['modules'][$module]['actions'][$action]['params'])){ + $block = true; + $params = $this->file_access_control_map['modules'][$module]['actions'][$action]['params']; + foreach($params as $param => $paramVals){ + if(!empty($_REQUEST[$param])){ + if(!in_array($_REQUEST[$param], $paramVals)){ + $block = false; + break; + } + } + } + if($block){ + $this->_processed = true; + $this->no_access(); + } + }else{ + $this->_processed = true; + $this->no_access(); + } + } + }else + $this->_processed = false; + } + + /** + * This code is part of the entry points reworking. We have consolidated all + * entry points to go through index.php. Now in order to bring up an entry point + * it will follow the format: + * 'index.php?entryPoint=download' + * the download entry point is mapped in the following file: entry_point_registry.php + * + */ + private function handleEntryPoint(){ + if(!empty($_REQUEST['entryPoint'])){ + $this->loadMapping('entry_point_registry'); + $entryPoint = $_REQUEST['entryPoint']; + + if(!empty($this->entry_point_registry[$entryPoint])){ + require_once($this->entry_point_registry[$entryPoint]['file']); + $this->_processed = true; + $this->view = ''; + } + } + } + + /** + * Checks to see if the requested entry point requires auth + * + * @param $entrypoint string name of the entrypoint + * @return bool true if auth is required, false if not + */ + public function checkEntryPointRequiresAuth($entryPoint) + { + $this->loadMapping('entry_point_registry'); + + if ( isset($this->entry_point_registry[$entryPoint]['auth']) + && !$this->entry_point_registry[$entryPoint]['auth'] ) + return false; + return true; + } + + /** + * Meant to handle old views e.g. DetailView.php. + * + */ + protected function callLegacyCode() + { + $file = self::getActionFilename($this->do_action); + if ( isset($this->action_view_map[strtolower($this->do_action)]) ) { + $action = $this->action_view_map[strtolower($this->do_action)]; + } + else { + $action = $this->do_action; + } + // index actions actually maps to the view.list.php view + if ( $action == 'index' ) { + $action = 'list'; + } + + if ((file_exists('modules/' . $this->module . '/'. $file . '.php') + && !file_exists('modules/' . $this->module . '/views/view.'. $action . '.php')) + || (file_exists('custom/modules/' . $this->module . '/'. $file . '.php') + && !file_exists('custom/modules/' . $this->module . '/views/view.'. $action . '.php')) + ) { + // A 'classic' module, using the old pre-MVC display files + // We should now discard the bean we just obtained for tracking as the pre-MVC module will instantiate its own + unset($GLOBALS['FOCUS']); + $GLOBALS['log']->debug('Module:' . $this->module . ' using file: '. $file); + $this->action_default(); + $this->_processed = true; + } + } + + /** + * If the action has been remapped to a different action as defined in + * action_file_map.php or action_view_map.php load those maps here. + * + */ + private function handleActionMaps(){ + if(!empty($this->action_file_map[strtolower($this->do_action)])){ + $this->view = ''; + $GLOBALS['log']->debug('Using Action File Map:' . $this->action_file_map[strtolower($this->do_action)]); + require_once($this->action_file_map[strtolower($this->do_action)]); + $this->_processed = true; + }elseif(!empty($this->action_view_map[strtolower($this->do_action)])){ + $GLOBALS['log']->debug('Using Action View Map:' . $this->action_view_map[strtolower($this->do_action)]); + $this->view = $this->action_view_map[strtolower($this->do_action)]; + $this->_processed = true; + }else + $this->no_action(); + } + + /** + * Actually remap the action if required. + * + */ + protected function remapAction(){ + if(!empty($this->action_remap[$this->do_action])){ + $this->action = $this->action_remap[$this->do_action]; + $this->do_action = $this->action; + } + } + +} +?> diff --git a/include/MVC/Controller/action_file_map.php b/include/MVC/Controller/action_file_map.php new file mode 100644 index 00000000..3a634f6d --- /dev/null +++ b/include/MVC/Controller/action_file_map.php @@ -0,0 +1,50 @@ + diff --git a/include/MVC/Controller/action_view_map.php b/include/MVC/Controller/action_view_map.php new file mode 100644 index 00000000..c0830cbf --- /dev/null +++ b/include/MVC/Controller/action_view_map.php @@ -0,0 +1,65 @@ +' => '' +$action_view_map['multieditview']= 'multiedit'; +$action_view_map['detailview']= 'detail'; +$action_view_map['editview']= 'edit'; +$action_view_map['listview']= 'list'; +$action_view_map['popup']= 'popup'; +$action_view_map['vcard']= 'vcard'; +$action_view_map['importvcard']= 'importvcard'; +$action_view_map['importvcardsave']= 'importvcardsave'; +$action_view_map['modulelistmenu']= 'modulelistmenu'; + +// SugarPDF +$action_view_map['sugarpdf']= 'sugarpdf'; +$action_view_map['dc'] = 'dc'; +$action_view_map['dcajax'] = 'dcajax'; +$action_view_map['quick'] = 'quick'; +$action_view_map['quickcreate'] = 'quickcreate'; +$action_view_map['spot'] = 'spot'; +$action_view_map['inlinefield'] = 'inlinefield'; +$action_view_map['inlinefieldsave'] = 'inlinefieldsave'; +$action_view_map['pluginlist'] = 'plugins'; +$action_view_map['downloadplugin'] = 'downloadplugin'; +?> diff --git a/include/MVC/Controller/entry_point_registry.php b/include/MVC/Controller/entry_point_registry.php new file mode 100644 index 00000000..71d32d02 --- /dev/null +++ b/include/MVC/Controller/entry_point_registry.php @@ -0,0 +1,74 @@ + array('file' => 'download.php', 'auth' => true), + 'export' => array('file' => 'export.php', 'auth' => true), + 'export_dataset' => array('file' => 'export_dataset.php', 'auth' => true), + 'Changenewpassword' => array('file' => 'modules/Users/Changenewpassword.php', 'auth' => false), + 'GeneratePassword' => array('file' => 'modules/Users/GeneratePassword.php', 'auth' => false), + 'vCard' => array('file' => 'vCard.php', 'auth' => true), + 'pdf' => array('file' => 'pdf.php', 'auth' => true), + 'minify' => array('file' => 'jssource/minify.php', 'auth' => true), + 'json' => array('file' => 'json.php', 'auth' => true), + 'json_server' => array('file' => 'json_server.php', 'auth' => true), + 'HandleAjaxCall' => array('file' => 'HandleAjaxCall.php', 'auth' => true), + 'TreeData' => array('file' => 'TreeData.php', 'auth' => true), + 'image' => array('file' => 'modules/Campaigns/image.php', 'auth' => false), + 'campaign_trackerv2' => array('file' => 'modules/Campaigns/Tracker.php', 'auth' => false), + 'WebToLeadCapture' => array('file' => 'modules/Campaigns/WebToLeadCapture.php', 'auth' => false), + 'removeme' => array('file' => 'modules/Campaigns/RemoveMe.php', 'auth' => false), + 'acceptDecline' => array('file' => 'modules/Contacts/AcceptDecline.php', 'auth' => false), + 'leadCapture' => array('file' => 'modules/Leads/Capture.php', 'auth' => false), + 'process_queue' => array('file' => 'process_queue.php', 'auth' => true), + 'zipatcher' => array('file' => 'zipatcher.php', 'auth' => true), + 'mm_get_doc' => array('file' => 'modules/MailMerge/get_doc.php', 'auth' => true), + 'getImage' => array('file' => 'include/SugarTheme/getImage.php', 'auth' => false), + 'GenerateQuickComposeFrame' => array('file' => 'modules/Emails/GenerateQuickComposeFrame.php', 'auth' => true), + 'DetailUserRole' => array('file' => 'modules/ACLRoles/DetailUserRole.php', 'auth' => true), + 'getYUIComboFile' => array('file' => 'include/javascript/getYUIComboFile.php', 'auth' => false), + 'UploadFileCheck' => array('file' => 'modules/Configurator/UploadFileCheck.php', 'auth' => true), + 'SAML'=> array('file' => 'modules/Users/authentication/SAMLAuthenticate/index.php', 'auth' => false), +); +?> diff --git a/include/MVC/Controller/file_access_control_map.php b/include/MVC/Controller/file_access_control_map.php new file mode 100644 index 00000000..44667adc --- /dev/null +++ b/include/MVC/Controller/file_access_control_map.php @@ -0,0 +1,71 @@ + array( + 'administration' => array( + 'actions' => array( + 'backups', + 'updater', + ), + 'links' => array( + 'update', + 'backup_management', + 'upgrade_wizard', + 'moduleBuilder', + ), + ), + 'upgradewizard' => array( + 'actions' => array( + 'index', + ), + ), + 'modulebuilder' => array( + 'actions' => array( + 'index' => array('params' => array('type' => array('mb'))), + ), + ), + ) +); +?> \ No newline at end of file diff --git a/include/MVC/SugarApplication.php b/include/MVC/SugarApplication.php new file mode 100644 index 00000000..16741469 --- /dev/null +++ b/include/MVC/SugarApplication.php @@ -0,0 +1,582 @@ +default_module = $sugar_config['default_module']; + $module = $this->default_module; + if(!empty($_REQUEST['module']))$module = $_REQUEST['module']; + insert_charset_header(); + $this->setupPrint(); + $this->controller = ControllerFactory::getController($module); + // if the entry point is defined to not need auth, then don't authenicate + if( empty($_REQUEST['entryPoint']) + || $this->controller->checkEntryPointRequiresAuth($_REQUEST['entryPoint']) ){ + $this->loadUser(); + $this->ACLFilter(); + $this->preProcess(); + $this->controller->preProcess(); + } + + SugarThemeRegistry::buildRegistry(); + $this->loadLanguages(); + $this->checkDatabaseVersion(); + $this->loadDisplaySettings(); + $this->loadLicense(); + $this->loadGlobals(); + $this->setupResourceManagement($module); + $this->checkHTTPReferer(); + $this->controller->execute(); + sugar_cleanup(); + } + + /** + * Load the authenticated user. If there is not an authenticated user then redirect to login screen. + */ + function loadUser(){ + global $authController, $sugar_config; + // Double check the server's unique key is in the session. Make sure this is not an attempt to hijack a session + $user_unique_key = (isset($_SESSION['unique_key'])) ? $_SESSION['unique_key'] : ''; + $server_unique_key = (isset($sugar_config['unique_key'])) ? $sugar_config['unique_key'] : ''; + $allowed_actions = (!empty($this->controller->allowed_actions)) ? $this->controller->allowed_actions : $allowed_actions = array('Authenticate', 'Login',); + + if(($user_unique_key != $server_unique_key) && (!in_array($this->controller->action, $allowed_actions)) && + (!isset($_SESSION['login_error']))) + { + session_destroy(); + $post_login_nav = ''; + + if(!empty($this->controller->module)){ + $post_login_nav .= '&login_module='.$this->controller->module; + } + if(!empty($this->controller->action)){ + if(in_array(strtolower($this->controller->action), array('delete'))) + $post_login_nav .= '&login_action=DetailView'; + elseif(in_array(strtolower($this->controller->action), array('save'))) + $post_login_nav .= '&login_action=EditView'; + elseif(isset($_REQUEST['massupdate'])|| isset($_GET['massupdate']) || isset($_POST['massupdate'])) + $post_login_nav .= '&login_action=index'; + else + $post_login_nav .= '&login_action='.$this->controller->action; + } + if(!empty($this->controller->record)){ + $post_login_nav .= '&login_record='.$this->controller->record; + } + + header('Location: index.php?action=Login&module=Users'.$post_login_nav); + exit (); + } + + $authController = new AuthenticationController((!empty($GLOBALS['sugar_config']['authenticationClass'])? $GLOBALS['sugar_config']['authenticationClass'] : 'SugarAuthenticate')); + $GLOBALS['current_user'] = new User(); + if(isset($_SESSION['authenticated_user_id'])){ + // set in modules/Users/Authenticate.php + if(!$authController->sessionAuthenticate()){ + // if the object we get back is null for some reason, this will break - like user prefs are corrupted + $GLOBALS['log']->fatal('User retrieval for ID: ('.$_SESSION['authenticated_user_id'].') does not exist in database or retrieval failed catastrophically. Calling session_destroy() and sending user to Login page.'); + session_destroy(); + SugarApplication::redirect('index.php?action=Login&module=Users'); + die(); + }//fi + }elseif(!($this->controller->module == 'Users' && in_array($this->controller->action, $allowed_actions))){ + session_destroy(); + SugarApplication::redirect('index.php?action=Login&module=Users'); + die(); + } + $GLOBALS['log']->debug('Current user is: '.$GLOBALS['current_user']->user_name); + + //set cookies + if(isset($_SESSION['authenticated_user_id'])){ + $GLOBALS['log']->debug("setting cookie ck_login_id_20 to ".$_SESSION['authenticated_user_id']); + self::setCookie('ck_login_id_20', $_SESSION['authenticated_user_id'], time() + 86400 * 90); + } + if(isset($_SESSION['authenticated_user_theme'])){ + $GLOBALS['log']->debug("setting cookie ck_login_theme_20 to ".$_SESSION['authenticated_user_theme']); + self::setCookie('ck_login_theme_20', $_SESSION['authenticated_user_theme'], time() + 86400 * 90); + } + if(isset($_SESSION['authenticated_user_theme_color'])){ + $GLOBALS['log']->debug("setting cookie ck_login_theme_color_20 to ".$_SESSION['authenticated_user_theme_color']); + self::setCookie('ck_login_theme_color_20', $_SESSION['authenticated_user_theme_color'], time() + 86400 * 90); + } + if(isset($_SESSION['authenticated_user_theme_font'])){ + $GLOBALS['log']->debug("setting cookie ck_login_theme_font_20 to ".$_SESSION['authenticated_user_theme_font']); + self::setCookie('ck_login_theme_font_20', $_SESSION['authenticated_user_theme_font'], time() + 86400 * 90); + } + if(isset($_SESSION['authenticated_user_language'])){ + $GLOBALS['log']->debug("setting cookie ck_login_language_20 to ".$_SESSION['authenticated_user_language']); + self::setCookie('ck_login_language_20', $_SESSION['authenticated_user_language'], time() + 86400 * 90); + } + //check if user can access + + } + + function ACLFilter(){ + ACLController :: filterModuleList($GLOBALS['moduleList']); + } + + /** + * setupResourceManagement + * This function initialize the ResourceManager and calls the setup method + * on the ResourceManager instance. + * + */ + function setupResourceManagement($module) { + require_once('include/resource/ResourceManager.php'); + $resourceManager = ResourceManager::getInstance(); + $resourceManager->setup($module); + } + + function setupPrint() { + $GLOBALS['request_string'] = ''; + + // merge _GET and _POST, but keep the results local + // this handles the issues where values come in one way or the other + // without affecting the main super globals + $merged = array_merge($_GET, $_POST); + foreach ($merged as $key => $val) + { + if(is_array($val)) + { + foreach ($val as $k => $v) + { + //If an array, then skip the urlencoding. This should be handled with stringify instead. + if(is_array($v)) + continue; + + $GLOBALS['request_string'] .= urlencode($key).'['.$k.']='.urlencode($v).'&'; + } + } + else + { + $GLOBALS['request_string'] .= urlencode($key).'='.urlencode($val).'&'; + } + } + $GLOBALS['request_string'] .= 'print=true'; + } + + function preProcess(){ + $config = new Administration; + $config->retrieveSettings(); + if(!empty($_SESSION['authenticated_user_id'])){ + if(isset($_SESSION['hasExpiredPassword']) && $_SESSION['hasExpiredPassword'] == '1'){ + if( $this->controller->action!= 'Save' && $this->controller->action != 'Logout') { + $this->controller->module = 'Users'; + $this->controller->action = 'ChangePassword'; + $record = $GLOBALS['current_user']->id; + }else{ + $this->handleOfflineClient(); + } + }else{ + $ut = $GLOBALS['current_user']->getPreference('ut'); + if(empty($ut) + && $this->controller->action != 'AdminWizard' + && $this->controller->action != 'EmailUIAjax' + && $this->controller->action != 'Wizard' + && $this->controller->action != 'SaveAdminWizard' + && $this->controller->action != 'SaveUserWizard' + && $this->controller->action != 'SaveTimezone' + && $this->controller->action != 'Logout') { + $this->controller->module = 'Users'; + $this->controller->action = 'SetTimezone'; + $record = $GLOBALS['current_user']->id; + }else{ + if($this->controller->action != 'AdminWizard' + && $this->controller->action != 'EmailUIAjax' + && $this->controller->action != 'Wizard' + && $this->controller->action != 'SaveAdminWizard' + && $this->controller->action != 'SaveUserWizard'){ + $this->handleOfflineClient(); + } + } + } + } + $this->handleAccessControl(); + } + + function handleOfflineClient(){ + if(isset($GLOBALS['sugar_config']['disc_client']) && $GLOBALS['sugar_config']['disc_client']){ + if(isset($_REQUEST['action']) && $_REQUEST['action'] != 'SaveTimezone'){ + if (!file_exists('modules/Sync/file_config.php')){ + if($_REQUEST['action'] != 'InitialSync' && $_REQUEST['action'] != 'Logout' && + ($_REQUEST['action'] != 'Popup' && $_REQUEST['module'] != 'Sync')){ + //echo $_REQUEST['action']; + //die(); + $this->controller->module = 'Sync'; + $this->controller->action = 'InitialSync'; + } + }else{ + require_once ('modules/Sync/file_config.php'); + if(isset($file_sync_info['is_first_sync']) && $file_sync_info['is_first_sync']){ + if($_REQUEST['action'] != 'InitialSync' && $_REQUEST['action'] != 'Logout' && + ( $_REQUEST['action'] != 'Popup' && $_REQUEST['module'] != 'Sync')){ + $this->controller->module = 'Sync'; + $this->controller->action = 'InitialSync'; + } + } + } + } + global $moduleList, $sugar_config, $sync_modules; + require_once('modules/Sync/SyncController.php'); + $GLOBALS['current_user']->is_admin = '0'; //No admins for disc client + } + } + + /** + * Handles everything related to authorization. + */ + function handleAccessControl(){ + if(is_admin($GLOBALS['current_user']) || is_admin_for_any_module($GLOBALS['current_user'])) + return; + if(!empty($_REQUEST['action']) && $_REQUEST['action']=="RetrieveEmail") + return; + if(!is_admin($GLOBALS['current_user']) && !empty($GLOBALS['adminOnlyList'][$this->controller->module]) + && !empty($GLOBALS['adminOnlyList'][$this->controller->module]['all']) + && (empty($GLOBALS['adminOnlyList'][$this->controller->module][$this->controller->action]) || $GLOBALS['adminOnlyList'][$this->controller->module][$this->controller->action] != 'allow')) { + $this->controller->hasAccess = false; + return; + } + + // Bug 20916 - Special case for check ACL access rights for Subpanel QuickCreates + if(isset($_POST['action']) && $_POST['action'] == 'SubpanelCreates') { + $actual_module = $_POST['target_module']; + if(!empty($GLOBALS['modListHeader']) && !in_array($actual_module,$GLOBALS['modListHeader'])) { + $this->controller->hasAccess = false; + } + return; + } + + if(!empty($GLOBALS['current_user']) && empty($GLOBALS['modListHeader'])) + $GLOBALS['modListHeader'] = query_module_access_list($GLOBALS['current_user']); + } + + /** + * Load only bare minimum of language that can be done before user init and MVC stuff + */ + static function preLoadLanguages() + { + if(!empty($_SESSION['authenticated_user_language'])) { + $GLOBALS['current_language'] = $_SESSION['authenticated_user_language']; + } + else { + $GLOBALS['current_language'] = $GLOBALS['sugar_config']['default_language']; + } + $GLOBALS['log']->debug('current_language is: '.$GLOBALS['current_language']); + //set module and application string arrays based upon selected language + $GLOBALS['app_strings'] = return_application_language($GLOBALS['current_language']); + } + + /** + * Load application wide languages as well as module based languages so they are accessible + * from the module. + */ + function loadLanguages(){ + if(!empty($_SESSION['authenticated_user_language'])) { + $GLOBALS['current_language'] = $_SESSION['authenticated_user_language']; + } + else { + $GLOBALS['current_language'] = $GLOBALS['sugar_config']['default_language']; + } + $GLOBALS['log']->debug('current_language is: '.$GLOBALS['current_language']); + //set module and application string arrays based upon selected language + $GLOBALS['app_strings'] = return_application_language($GLOBALS['current_language']); + if(empty($GLOBALS['current_user']->id))$GLOBALS['app_strings']['NTC_WELCOME'] = ''; + if(!empty($GLOBALS['system_config']->settings['system_name']))$GLOBALS['app_strings']['LBL_BROWSER_TITLE'] = $GLOBALS['system_config']->settings['system_name']; + $GLOBALS['app_list_strings'] = return_app_list_strings_language($GLOBALS['current_language']); + $GLOBALS['mod_strings'] = return_module_language($GLOBALS['current_language'], $this->controller->module); + } + /** + * checkDatabaseVersion + * Check the db version sugar_version.php and compare to what the version is stored in the config table. + * Ensure that both are the same. + */ + function checkDatabaseVersion($dieOnFailure = true) + { + $row_count = sugar_cache_retrieve('checkDatabaseVersion_row_count'); + if ( empty($row_count) ) { + global $sugar_db_version; + $version_query = 'SELECT count(*) as the_count FROM config WHERE category=\'info\' AND name=\'sugar_version\''; + + if($GLOBALS['db']->dbType == 'oci8'){ + } + else if ($GLOBALS['db']->dbType == 'mssql'){ + $version_query .= " AND CAST(value AS varchar(8000)) = '$sugar_db_version'"; + } + else { + $version_query .= " AND value = '$sugar_db_version'"; + } + + $result = $GLOBALS['db']->query($version_query); + $row = $GLOBALS['db']->fetchByAssoc($result, -1, true); + $row_count = $row['the_count']; + sugar_cache_put('checkDatabaseVersion_row_count', $row_count); + } + + if($row_count == 0 && empty($GLOBALS['sugar_config']['disc_client'])){ + $sugar_version = $GLOBALS['sugar_version']; + if ( $dieOnFailure ) + sugar_die("Sugar CRM $sugar_version Files May Only Be Used With A Sugar CRM $sugar_db_version Database."); + else + return false; + } + + return true; + } + + /** + * Load the themes/images. + */ + function loadDisplaySettings() + { + global $theme; + + // load the user's default theme + $theme = $GLOBALS['current_user']->getPreference('user_theme'); + + if (is_null($theme)) { + $theme = $GLOBALS['sugar_config']['default_theme']; + if(!empty($_SESSION['authenticated_user_theme'])){ + $theme = $_SESSION['authenticated_user_theme']; + } + else if(!empty($_COOKIE['sugar_user_theme'])){ + $theme = $_COOKIE['sugar_user_theme']; + } + + if(isset($_SESSION['authenticated_user_theme']) && $_SESSION['authenticated_user_theme'] != '') { + $_SESSION['theme_changed'] = false; + } + } + + if(!is_null($theme) && !headers_sent()) + { + setcookie('sugar_user_theme', $theme, time() + 31536000); // expires in a year + } + + SugarThemeRegistry::set($theme); + require_once('include/utils/layout_utils.php'); + $GLOBALS['image_path'] = SugarThemeRegistry::current()->getImagePath().'/'; + if ( defined('TEMPLATE_URL') ) + $GLOBALS['image_path'] = TEMPLATE_URL . '/'. $GLOBALS['image_path']; + + if ( isset($GLOBALS['current_user']) ) { + $GLOBALS['gridline'] = (int) ($GLOBALS['current_user']->getPreference('gridline') == 'on'); + $GLOBALS['current_user']->setPreference('user_theme', $theme, 0, 'global'); + } + } + + function loadLicense(){ + loadLicense(); + global $user_unique_key, $server_unique_key; + $user_unique_key = (isset($_SESSION['unique_key'])) ? $_SESSION['unique_key'] : ''; + $server_unique_key = (isset($sugar_config['unique_key'])) ? $sugar_config['unique_key'] : ''; + } + + function loadGlobals(){ + global $currentModule; + $currentModule = $this->controller->module; + if($this->controller->module == $this->default_module){ + $_REQUEST['module'] = $this->controller->module; + if(empty($_REQUEST['action'])) + $_REQUEST['action'] = $this->default_action; + } + } + /** + * + * Checks a request to ensure the request is coming from a valid source or it is for one of the white listed actions + */ + protected function checkHTTPReferer($dieIfInvalid = true) + { + global $sugar_config; + $whiteListActions = (!empty($sugar_config['http_referer']['actions']))?$sugar_config['http_referer']['actions']:array('index', 'ListView', 'DetailView', 'EditView','oauth'); + // Bug 39691 - Make sure localhost and 127.0.0.1 are always valid HTTP referers + $whiteListReferers = array('127.0.0.1','localhost'); + if(!empty($_SERVER['SERVER_ADDR']))$whiteListReferers[] = $_SERVER['SERVER_ADDR']; + if ( !empty($sugar_config['http_referer']['list']) ) { + $whiteListReferers = array_merge($whiteListReferers,$sugar_config['http_referer']['list']); + } + if(!empty($_SERVER['HTTP_REFERER']) && !empty($_SERVER['SERVER_NAME'])){ + $http_ref = parse_url($_SERVER['HTTP_REFERER']); + if($http_ref['host'] !== $_SERVER['SERVER_NAME'] && !in_array($this->controller->action, $whiteListActions) && + (empty($whiteListReferers) || !in_array($http_ref['host'], $whiteListReferers))){ + if ( $dieIfInvalid ) { + header("Cache-Control: no-cache, must-revalidate"); + $whiteListActions[] = $this->controller->action; + $whiteListString = "'" . implode("', '", $whiteListActions) . "'"; + $ss = new Sugar_Smarty; + $ss->assign('host',$http_ref['host']); + $ss->assign('action',$this->controller->action); + $ss->assign('whiteListString',$whiteListString); + $ss->display('include/MVC/View/tpls/xsrf.tpl'); + sugar_cleanup(true); + } + return false; + } + } + + return true; + } + function startSession() + { + $sessionIdCookie = isset($_COOKIE['PHPSESSID']) ? $_COOKIE['PHPSESSID'] : null; + if(isset($_REQUEST['MSID'])) { + session_id($_REQUEST['MSID']); + session_start(); + if(isset($_SESSION['user_id']) && isset($_SESSION['seamless_login'])){ + unset ($_SESSION['seamless_login']); + }else{ + if(isset($_COOKIE['PHPSESSID'])){ + self::setCookie('PHPSESSID', '', time()-42000, '/'); + } + sugar_cleanup(false); + session_destroy(); + exit('Not a valid entry method'); + } + }else{ + if(can_start_session()){ + session_start(); + } + } + + if ( isset($_REQUEST['login_module']) && isset($_REQUEST['login_action']) + && !($_REQUEST['login_module'] == 'Home' && $_REQUEST['login_action'] == 'index') ) { + if ( !is_null($sessionIdCookie) && empty($_SESSION) ) { + self::setCookie('loginErrorMessage', 'LBL_SESSION_EXPIRED', time()+30, '/'); + } + } + + } + + function endSession(){ + session_destroy(); + } + /** + * Redirect to another URL + * + * @access public + * @param string $url The URL to redirect to + */ + function redirect( + $url + ) + { + /* + * If the headers have been sent, then we cannot send an additional location header + * so we will output a javascript redirect statement. + */ + if (headers_sent()) { + echo "\n"; + } else { + //@ob_end_clean(); // clear output buffer + session_write_close(); + header( 'HTTP/1.1 301 Moved Permanently' ); + header( "Location: ". $url ); + } + exit(); + } + + /** + * Redirect to another URL + * + * @access public + * @param string $url The URL to redirect to + */ + public static function appendErrorMessage($error_message) + { + if (empty($_SESSION['user_error_message']) || !is_array($_SESSION['user_error_message'])){ + $_SESSION['user_error_message'] = array(); + } + $_SESSION['user_error_message'][] = $error_message; + } + + public static function getErrorMessages() + { + if (isset($_SESSION['user_error_message']) && is_array($_SESSION['user_error_message']) ) { + $msgs = $_SESSION['user_error_message']; + unset($_SESSION['user_error_message']); + return $msgs; + }else{ + return array(); + } + } + + /** + * Wrapper for the PHP setcookie() function, to handle cases where headers have + * already been sent + */ + public static function setCookie( + $name, + $value, + $expire = 0, + $path = '/', + $domain = null, + $secure = false, + $httponly = false + ) + { + if ( is_null($domain) ) + if ( isset($_SERVER["HTTP_HOST"]) ) + $domain = $_SERVER["HTTP_HOST"]; + else + $domain = 'localhost'; + + if (!headers_sent()) + setcookie($name,$value,$expire,$path,$domain,$secure,$httponly); + + $_COOKIE[$name] = $value; + } +} diff --git a/include/MVC/SugarModule.php b/include/MVC/SugarModule.php new file mode 100644 index 00000000..9b9a9a35 --- /dev/null +++ b/include/MVC/SugarModule.php @@ -0,0 +1,120 @@ +_moduleName = $moduleName; + } + + /** + * Returns true if the given module implements the indicated template + * + * @param string $template + * @return bool + */ + public function moduleImplements( + $template + ) + { + $focus = self::loadBean(); + + if ( !$focus ) + return false; + + return is_a($focus,$template); + } + + /** + * Returns the bean object of the given module + * + * @return object + */ + public function loadBean($beanList = null, $beanFiles = null, $returnObject = true) + { + // Populate these reference arrays + if ( empty($beanList) ) { + global $beanList; + } + if ( empty($beanFiles) ) { + global $beanFiles; + } + if ( !isset($beanList) || !isset($beanFiles) ) { + require('include/modules.php'); + } + + if ( isset($beanList[$this->_moduleName]) ) { + $bean = $beanList[$this->_moduleName]; + if (isset($beanFiles[$bean])) { + if ( !$returnObject ) { + return true; + } + if ( !sugar_is_file($beanFiles[$bean]) ) { + return false; + } + require_once($beanFiles[$bean]); + $focus = new $bean; + } + else { + return false; + } + } + else { + return false; + } + + return $focus; + } +} diff --git a/include/MVC/View/SugarView.php b/include/MVC/View/SugarView.php new file mode 100644 index 00000000..7f595d85 --- /dev/null +++ b/include/MVC/View/SugarView.php @@ -0,0 +1,1248 @@ + true, 'show_title' => true, 'show_subpanels' => false, 'show_search' => true, 'show_footer' => true, 'show_javascript' => true, 'view_print' => false,); + var $type = null; + var $responseTime; + var $fileResources; + + /** + * Constructor which will peform the setup. + */ + public function SugarView( + $bean = null, + $view_object_map = array() + ) + { + } + + public function init( + $bean = null, + $view_object_map = array() + ) + { + $this->bean = $bean; + $this->view_object_map = $view_object_map; + $this->action = $GLOBALS['action']; + $this->module = $GLOBALS['module']; + $this->_initSmarty(); + } + + protected function _initSmarty() + { + $this->ss = new Sugar_Smarty(); + $this->ss->assign('MOD', $GLOBALS['mod_strings']); + $this->ss->assign('APP', $GLOBALS['app_strings']); + } + + /** + * This method will be called from the controller and is not meant to be overridden. + */ + public function process() + { + LogicHook::initialize(); + $this->_checkModule(); + + //trackView has to be here in order to track for breadcrumbs + $this->_trackView(); + + if ($this->_getOption('show_header')) { + $this->displayHeader(); + } else { + $this->renderJavascript(); + } + + $this->_buildModuleList(); + $this->preDisplay(); + $this->displayErrors(); + $this->display(); + $GLOBALS['logic_hook']->call_custom_logic('', 'after_ui_frame'); + if ($this->_getOption('show_subpanels')) $this->_displaySubPanels(); + if ($this->action === 'Login') { + //this is needed for a faster loading login page ie won't render unless the tables are closed + ob_flush(); + } + if ($this->_getOption('show_footer')) $this->displayFooter(); + $GLOBALS['logic_hook']->call_custom_logic('', 'after_ui_footer'); + //Do not track if there is no module or if module is not a String + $this->_track(); + } + + /** + * This method will display the errors on the page. + */ + public function displayErrors() + { + $errors = ''; + + foreach($this->errors as $error) { + $errors .= '' . $error . '
'; + } + + if ( !$this->suppressDisplayErrors ) { + echo $errors; + } + else { + return $errors; + } + } + + /** + * [OVERRIDE] - This method is meant to overidden in a subclass. The purpose of this method is + * to allow a view to do some preprocessing before the display method is called. This becomes + * useful when you have a view defined at the application level and then within a module + * have a sub-view that extends from this application level view. The application level + * view can do the setup in preDisplay() that is common to itself and any subviews + * and then the subview can just override display(). If it so desires, can also override + * preDisplay(). + */ + public function preDisplay() + { + } + + /** + * [OVERRIDE] - This method is meant to overidden in a subclass. This method + * will handle the actual display logic of the view. + */ + public function display() + { + } + + + /** + * trackView + */ + protected function _trackView() + { + $action = strtolower($this->action); + //Skip save, tracked in SugarBean instead + if($action == 'save') { + return; + } + + + $trackerManager = TrackerManager::getInstance(); + $timeStamp = TimeDate::getInstance()->nowDb(); + if($monitor = $trackerManager->getMonitor('tracker')){ + $monitor->setValue('action', $action); + $monitor->setValue('user_id', $GLOBALS['current_user']->id); + $monitor->setValue('module_name', $this->module); + $monitor->setValue('date_modified', $timeStamp); + $monitor->setValue('visible', (($monitor->action == 'detailview') || ($monitor->action == 'editview') + ) ? 1 : 0); + + if (!empty($this->bean->id)) { + $monitor->setValue('item_id', $this->bean->id); + $monitor->setValue('item_summary', $this->bean->get_summary_text()); + } + + //If visible is true, but there is no bean, do not track (invalid/unauthorized reference) + //Also, do not track save actions where there is no bean id + if($monitor->visible && empty($this->bean->id)) { + $trackerManager->unsetMonitor($monitor); + return; + } + $trackerManager->saveMonitor($monitor, true, true); + } + } + + + /** + * Displays the header on section of the page; basically everything before the content + */ + public function displayHeader() + { + global $theme; + global $max_tabs; + global $app_strings; + global $current_user; + global $sugar_config; + global $app_list_strings; + global $mod_strings; + global $current_language; + + $GLOBALS['app']->headerDisplayed = true; + + $themeObject = SugarThemeRegistry::current(); + $theme = $themeObject->__toString(); + + $ss = new Sugar_Smarty(); + $ss->assign("APP", $app_strings); + $ss->assign("THEME", $theme); + $ss->assign("THEME_IE6COMPAT", $themeObject->ie6compat ? 'true':'false'); + $ss->assign("MODULE_NAME", $this->module); + + // get browser title + $ss->assign("SYSTEM_NAME", $this->getBrowserTitle()); + + // get css + $css = $themeObject->getCSS(); + if ($this->_getOption('view_print')) { + $css .= ''; + } + $ss->assign("SUGAR_CSS",$css); + + // get javascript + ob_start(); + $this->renderJavascript(); + + $ss->assign("SUGAR_JS",ob_get_contents().$themeObject->getJS()); + ob_end_clean(); + + // get favicon + if(isset($GLOBALS['sugar_config']['default_module_favicon'])) + $module_favicon = $GLOBALS['sugar_config']['default_module_favicon']; + else + $module_favicon = false; + + $favicon = ''; + if ( $module_favicon ) + $favicon = $themeObject->getImageURL($this->module.'.gif',false); + if ( !sugar_is_file($favicon) || !$module_favicon ) + $favicon = $themeObject->getImageURL('sugar_icon.ico',false); + $ss->assign('FAVICON_URL',getJSPath($favicon)); + + // build the shortcut menu + $shortcut_menu = array(); + foreach ( $this->getMenu() as $key => $menu_item ) + $shortcut_menu[$key] = array( + "URL" => $menu_item[0], + "LABEL" => $menu_item[1], + "MODULE_NAME" => $menu_item[2], + "IMAGE" => $themeObject + ->getImage($menu_item[2],"alt='".$menu_item[1]."' border='0' align='absmiddle'"), + ); + $ss->assign("SHORTCUT_MENU",$shortcut_menu); + + // handle rtl text direction + if(isset($_REQUEST['RTL']) && $_REQUEST['RTL'] == 'RTL'){ + $_SESSION['RTL'] = true; + } + if(isset($_REQUEST['LTR']) && $_REQUEST['LTR'] == 'LTR'){ + unset($_SESSION['RTL']); + } + if(isset($_SESSION['RTL']) && $_SESSION['RTL']){ + $ss->assign("DIR", 'dir="RTL"'); + } + + // handle resizing of the company logo correctly on the fly + $companyLogoURL = $themeObject->getImageURL('company_logo.png'); + $companyLogoURL_arr = explode('?', $companyLogoURL); + $companyLogoURL = $companyLogoURL_arr[0]; + + $company_logo_attributes = sugar_cache_retrieve('company_logo_attributes'); + if(!empty($company_logo_attributes)) { + $ss->assign("COMPANY_LOGO_MD5", $company_logo_attributes[0]); + $ss->assign("COMPANY_LOGO_WIDTH", $company_logo_attributes[1]); + $ss->assign("COMPANY_LOGO_HEIGHT", $company_logo_attributes[2]); + } + else { + // Always need to md5 the file + $ss->assign("COMPANY_LOGO_MD5", md5_file($companyLogoURL)); + + list($width,$height) = getimagesize($companyLogoURL); + if ( $width > 212 || $height > 40 ) { + $resizePctWidth = ($width - 212)/212; + $resizePctHeight = ($height - 40)/40; + if ( $resizePctWidth > $resizePctHeight ) + $resizeAmount = $width / 212; + else + $resizeAmount = $height / 40; + $ss->assign("COMPANY_LOGO_WIDTH", round($width * (1/$resizeAmount))); + $ss->assign("COMPANY_LOGO_HEIGHT", round($height * (1/$resizeAmount))); + } + else { + $ss->assign("COMPANY_LOGO_WIDTH", $width); + $ss->assign("COMPANY_LOGO_HEIGHT", $height); + } + + // Let's cache the results + sugar_cache_put('company_logo_attributes', + array( + $ss->get_template_vars("COMPANY_LOGO_MD5"), + $ss->get_template_vars("COMPANY_LOGO_WIDTH"), + $ss->get_template_vars("COMPANY_LOGO_HEIGHT") + ) + ); + } + $ss->assign("COMPANY_LOGO_URL",getJSPath($companyLogoURL)."&logo_md5=".$ss->get_template_vars("COMPANY_LOGO_MD5")); + + // get the global links + $gcls = array(); + $global_control_links = array(); + require("include/globalControlLinks.php"); + + foreach($global_control_links as $key => $value) { + if ($key == 'users') { //represents logout link. + $ss->assign("LOGOUT_LINK", $value['linkinfo'][key($value['linkinfo'])]); + $ss->assign("LOGOUT_LABEL", key($value['linkinfo']));//key value for first element. + continue; + } + + foreach ($value as $linkattribute => $attributevalue) { + // get the main link info + if ( $linkattribute == 'linkinfo' ) { + $gcls[$key] = array( + "LABEL" => key($attributevalue), + "URL" => current($attributevalue), + "SUBMENU" => array(), + ); + if(substr($gcls[$key]["URL"], 0, 11) == "javascript:") { + $gcls[$key]["ONCLICK"] = substr($gcls[$key]["URL"],11); + $gcls[$key]["URL"] = "#"; + } + } + // and now the sublinks + if ( $linkattribute == 'submenu' && is_array($attributevalue) ) { + foreach ($attributevalue as $submenulinkkey => $submenulinkinfo) + $gcls[$key]['SUBMENU'][$submenulinkkey] = array( + "LABEL" => key($submenulinkinfo), + "URL" => current($submenulinkinfo), + ); + if(substr($gcls[$key]['SUBMENU'][$submenulinkkey]["URL"], 0, 11) == "javascript:") { + $gcls[$key]['SUBMENU'][$submenulinkkey]["ONCLICK"] = substr($gcls[$key]['SUBMENU'][$submenulinkkey]["URL"],11); + $gcls[$key]['SUBMENU'][$submenulinkkey]["URL"] = "#"; + } + } + } + } + $ss->assign("GCLS",$gcls); + + $ss->assign("SEARCH", isset($_REQUEST['query_string']) ? $_REQUEST['query_string'] : ''); + + if ($this->action == "EditView" || $this->action == "Login") + $ss->assign("ONLOAD", 'onload="set_focus()"'); + + $ss->assign("AUTHENTICATED",isset($_SESSION["authenticated_user_id"])); + + // get other things needed for page style popup + if (isset($_SESSION["authenticated_user_id"])) { + // get the current user name and id + $ss->assign("CURRENT_USER", $current_user->full_name == '' || !showFullName() + ? $current_user->user_name : $current_user->full_name ); + $ss->assign("CURRENT_USER_ID", $current_user->id); + + // get the last viewed records + $tracker = new Tracker(); + $history = $tracker->get_recently_viewed($current_user->id); + foreach ( $history as $key => $row ) { + $history[$key]['item_summary_short'] = getTrackerSubstring($row['item_summary']); + $history[$key]['image'] = SugarThemeRegistry::current() + ->getImage($row['module_name'],'border="0" align="absmiddle" alt="'.$row['item_summary'].'"'); + } + $ss->assign("recentRecords",$history); + } + + $bakModStrings = $mod_strings; + if (isset($_SESSION["authenticated_user_id"]) ) { + // get the module list + $moduleTopMenu = array(); + + $max_tabs = $current_user->getPreference('max_tabs'); + // Attempt to correct if max tabs count is waaay too high. + if ( !isset($max_tabs) || $max_tabs <= 0 || $max_tabs > 10 ) { + $max_tabs = $GLOBALS['sugar_config']['default_max_tabs']; + $current_user->setPreference('max_tabs', $max_tabs, 0, 'global'); + } + + $moduleTab = $this->_getModuleTab(); + $ss->assign('MODULE_TAB',$moduleTab); + + + // See if they are using grouped tabs or not (removed in 6.0, returned in 6.1) + $user_navigation_paradigm = $current_user->getPreference('navigation_paradigm'); + if ( !isset($user_navigation_paradigm) ) { + $user_navigation_paradigm = $GLOBALS['sugar_config']['default_navigation_paradigm']; + } + + + // Get the full module list for later use + foreach ( query_module_access_list($current_user) as $module ) { + // Bug 25948 - Check for the module being in the moduleList + if ( isset($app_list_strings['moduleList'][$module]) ) { + $fullModuleList[$module] = $app_list_strings['moduleList'][$module]; + } + } + + + if(!should_hide_iframes()) { + $iFrame = new iFrame(); + $frames = $iFrame->lookup_frames('tab'); + foreach($frames as $key => $values){ + $fullModuleList[$key] = $values; + } + } + elseif (isset($fullModuleList['iFrames'])) { + unset($fullModuleList['iFrames']); + } + + if ( $user_navigation_paradigm == 'gm' && isset($themeObject->group_tabs) && $themeObject->group_tabs) { + // We are using grouped tabs + require_once('include/GroupedTabs/GroupedTabStructure.php'); + $groupedTabsClass = new GroupedTabStructure(); + $modules = query_module_access_list($current_user); + //handle with submoremodules + $max_tabs = $current_user->getPreference('max_tabs'); + // If the max_tabs isn't set incorrectly, set it within the range, to the default max sub tabs size + if ( !isset($max_tabs) || $max_tabs <= 0 || $max_tabs > 10){ + // We have a default value. Use it + if(isset($GLOBALS['sugar_config']['default_max_tabs'])){ + $max_tabs = $GLOBALS['sugar_config']['default_max_tabs']; + } + else{ + $max_tabs = 8; + } + } + + $subMoreModules = false; + $groupTabs = $groupedTabsClass->get_tab_structure(get_val_array($modules)); + // We need to put this here, so the "All" group is valid for the user's preference. + $groupTabs[$app_strings['LBL_TABGROUP_ALL']]['modules'] = $fullModuleList; + + + // Setup the default group tab. + $allGroup = $app_strings['LBL_TABGROUP_ALL']; + $ss->assign('currentGroupTab',$allGroup); + $currentGroupTab = $allGroup; + $usersGroup = $current_user->getPreference('theme_current_group'); + // Figure out which tab they currently have selected (stored as a user preference) + if ( !empty($usersGroup) && isset($groupTabs[$usersGroup]) ) { + $currentGroupTab = $usersGroup; + } else { + $current_user->setPreference('theme_current_group',$currentGroupTab); + } + + $ss->assign('currentGroupTab',$currentGroupTab); + $usingGroupTabs = true; + + } else { + // Setup the default group tab. + $ss->assign('currentGroupTab',$app_strings['LBL_TABGROUP_ALL']); + + $usingGroupTabs = false; + + $groupTabs[$app_strings['LBL_TABGROUP_ALL']]['modules'] = $fullModuleList; + + } + + + $topTabList = array(); + + // Now time to go through each of the tab sets and fix them up. + foreach ( $groupTabs as $tabIdx => $tabData ) { + $topTabs = $tabData['modules']; + if ( ! is_array($topTabs) ) { + $topTabs = array(); + } + $extraTabs = array(); + + // Split it in to the tabs that go across the top, and the ones that are on the extra menu. + if ( count($topTabs) > $max_tabs ) { + $extraTabs = array_splice($topTabs,$max_tabs); + } + // Make sure the current module is accessable through one of the top tabs + if ( !isset($topTabs[$moduleTab]) ) { + // Nope, we need to add it. + // First, take it out of the extra menu, if it's there + if ( isset($extraTabs[$moduleTab]) ) { + unset($extraTabs[$moduleTab]); + } + if ( count($topTabs) >= $max_tabs - 1 ) { + // We already have the maximum number of tabs, so we need to shuffle the last one + // from the top to the first one of the extras + $lastElem = array_splice($topTabs,$max_tabs-1); + $extraTabs = $lastElem + $extraTabs; + } + if ( !empty($moduleTab) ) { + $topTabs[$moduleTab] = $app_list_strings['moduleList'][$moduleTab]; + } + } + + + /* + // This was removed, but I like the idea, so I left the code in here in case we decide to turn it back on + // If we are using group tabs, add all the "hidden" tabs to the end of the extra menu + if ( $usingGroupTabs ) { + foreach($fullModuleList as $moduleKey => $module ) { + if ( !isset($topTabs[$moduleKey]) && !isset($extraTabs[$moduleKey]) ) { + $extraTabs[$moduleKey] = $module; + } + } + } + */ + + // Get a unique list of the top tabs so we can build the popup menus for them + foreach ( $topTabs as $moduleKey => $module ) { + $topTabList[$moduleKey] = $module; + } + + $groupTabs[$tabIdx]['modules'] = $topTabs; + $groupTabs[$tabIdx]['extra'] = $extraTabs; + } + } + + if ( isset($topTabList) && is_array($topTabList) ) { + // Adding shortcuts array to menu array for displaying shortcuts associated with each module + $shortcutTopMenu = array(); + foreach($topTabList as $module_key => $label) { + global $mod_strings; + $mod_strings = return_module_language($current_language, $module_key); + foreach ( $this->getMenu($module_key) as $key => $menu_item ) { + $shortcutTopMenu[$module_key][$key] = array( + "URL" => $menu_item[0], + "LABEL" => $menu_item[1], + "MODULE_NAME" => $menu_item[2], + "IMAGE" => $themeObject + ->getImage($menu_item[2],"alt='".$menu_item[1]."' border='0' align='absmiddle'"), + ); + } + } + $ss->assign("groupTabs",$groupTabs); + $ss->assign("shortcutTopMenu",$shortcutTopMenu); + $ss->assign('USE_GROUP_TABS',$usingGroupTabs); + + // This is here for backwards compatibility, someday, somewhere, it will be able to be removed + $ss->assign("moduleTopMenu",$groupTabs[$app_strings['LBL_TABGROUP_ALL']]['modules']); + $ss->assign("moduleExtraMenu",$groupTabs[$app_strings['LBL_TABGROUP_ALL']]['extra']); + + } + + global $mod_strings; + $mod_strings = $bakModStrings; + $headerTpl = $themeObject->getTemplate('header.tpl'); + if ( isset($GLOBALS['sugar_config']['developerMode']) && $GLOBALS['sugar_config']['developerMode'] ) + $ss->clear_compiled_tpl($headerTpl); + $ss->display($headerTpl); + + $this->includeClassicFile('modules/Administration/DisplayWarnings.php'); + + $errorMessages = SugarApplication::getErrorMessages(); + if ( !empty($errorMessages)) { + foreach ( $errorMessages as $error_message ) { + echo('

' . $error_message.'

'); + } + } + + } + /** + * If the view is classic then this method will include the file and + * setup any global variables. + * + * @param string $file + */ + public function includeClassicFile( + $file + ) + { + global $sugar_config, $theme, $current_user, $sugar_version, $sugar_flavor, $mod_strings, $app_strings, $app_list_strings, $action, $timezones; + global $gridline, $request_string, $modListHeader, $dashletData, $authController, $locale, $currentModule, $import_bean_map, $image_path, $license; + global $user_unique_key, $server_unique_key, $barChartColors, $modules_exempt_from_availability_check, $dictionary, $current_language, $beanList, $beanFiles, $sugar_build, $sugar_codename; + global $timedate, $login_error; // cn: bug 13855 - timedate not available to classic views. + $currentModule = $this->module; + require_once ($file); + } + + protected function _displayLoginJS() + { + global $sugar_config, $timedate; + + if(isset($this->bean->module_dir)){ + echo ""; + } + if(isset($_REQUEST['action'])){ + echo ""; + } + echo ''; + if (!is_file("include/javascript/sugar_grp1.js")) { + $_REQUEST['root_directory'] = "."; + require_once("jssource/minify_utils.php"); + ConcatenateFiles("."); + } + echo ''; + echo ''; + echo ''; + echo << + if ( typeof(SUGAR) == 'undefined' ) {SUGAR = {}}; + if ( typeof(SUGAR.themes) == 'undefined' ) SUGAR.themes = {}; + +EOQ; + if(isset( $sugar_config['disc_client']) && $sugar_config['disc_client']) + echo ''; + } + + /** + * Get JS validation code for views + */ + public static function getJavascriptValidation() + { + global $timedate; + $cal_date_format = $timedate->get_cal_date_format(); + $timereg = $timedate->get_regular_expression($timedate->get_time_format()); + $datereg = $timedate->get_regular_expression($timedate->get_date_format()); + $date_pos = ''; + foreach ($datereg['positions'] as $type => $pos) { + if (empty($date_pos)) { + $date_pos .= "'$type': $pos"; + } else { + $date_pos .= ",'$type': $pos"; + } + } + + $time_separator = $timedate->timeSeparator(); + $hour_offset = $timedate->getUserUTCOffset() * 60; + + // Add in the number formatting styles here as well, we have been handling this with individual modules. + require_once ('modules/Currencies/Currency.php'); + list ($num_grp_sep, $dec_sep) = get_number_seperators(); + + $the_script = ""; + + return $the_script; + } + + /** + * Called from process(). This method will display the correct javascript. + */ + protected function _displayJavascript() + { + global $locale, $sugar_config, $timedate; + + + if ($this->_getOption('show_javascript')) { + if (!$this->_getOption('show_header')) + echo << + + +EOHTML; + + echo ""; + echo ""; + + if(isset($this->bean->module_dir)){ + echo ""; + } + if(isset($_REQUEST['action'])){ + echo ""; + } + echo ''; + if (!is_file("include/javascript/sugar_grp1.js") || !is_file("include/javascript/sugar_grp1_yui.js")) { + $_REQUEST['root_directory'] = "."; + require_once("jssource/minify_utils.php"); + ConcatenateFiles("."); + } + echo ''; + echo ''; + echo ''; + + if ( isset($sugar_config['quicksearch_querydelay']) ) { + echo ""; + } + // cn: bug 12274 - prepare secret guid for asynchronous calls + if (!isset($_SESSION['asynchronous_key']) || empty($_SESSION['asynchronous_key'])) { + $_SESSION['asynchronous_key'] = create_guid(); + } + $image_server = (defined('TEMPLATE_URL'))?TEMPLATE_URL . '/':''; + echo ''; // cn: bug 12274 - create session-stored key to defend against CSRF + echo ''; + echo self::getJavascriptValidation(); + if (!is_file($GLOBALS['sugar_config']['cache_dir'] . 'jsLanguage/' . $GLOBALS['current_language'] . '.js')) { + require_once ('include/language/jsLanguage.php'); + jsLanguage::createAppStringsCache($GLOBALS['current_language']); + } + echo ''; + if (!is_file($GLOBALS['sugar_config']['cache_dir'] . 'jsLanguage/' . $this->module . '/' . $GLOBALS['current_language'] . '.js')) { + require_once ('include/language/jsLanguage.php'); + jsLanguage::createModuleStringsCache($this->module, $GLOBALS['current_language']); + } + echo ''; + if(isset( $sugar_config['disc_client']) && $sugar_config['disc_client']) + echo ''; + echo ''; + } + + if (isset($_REQUEST['popup']) && !empty($_REQUEST['popup'])) { + // cn: bug 12274 - add security metadata envelope for async calls in popups + echo ''; // cn: bug 12274 - create session-stored key to defend against CSRF + } + } + + /** + * Called from process(). This method will display the footer on the page. + */ + public function displayFooter() + { + if (empty($this->responseTime)) { + $this->_calculateFooterMetrics(); + } + global $sugar_config; + global $app_strings; + + //decide whether or not to show themepicker, default is to show + $showThemePicker = true; + if (isset($sugar_config['showThemePicker'])) { + $showThemePicker = $sugar_config['showThemePicker']; + } + + echo ""; + $jsalerts = new jsAlerts(); + if ( !isset($_SESSION['isMobile']) ) + echo $jsalerts->getScript(); + + $ss = new Sugar_Smarty(); + $ss->assign("AUTHENTICATED",isset($_SESSION["authenticated_user_id"])); + $ss->assign('MOD',return_module_language($GLOBALS['current_language'], 'Users')); + + $bottomLinkList = array(); + if (isset($this->action) && $this->action != "EditView") { + $bottomLinkList['print'] = + array($app_strings['LNK_PRINT'] => 'javascript:void window.open(\'index.php?'.$GLOBALS['request_string'].'\',\'printwin\',\'menubar=1,status=0,resizable=1,scrollbars=1,toolbar=0,location=1\')'); + + } + $bottomLinkList['backtotop'] = array($app_strings['LNK_BACKTOTOP'] => '#top'); + + $bottomLinksStr = ""; + foreach($bottomLinkList as $key => $value) { + foreach($value as $text => $link) { + $href = $link; + if(substr($link, 0, 11) == "javascript:") { + $onclick = " onclick=\"".substr($link,11)."\""; + $href = "#"; + } else { + $onclick = ""; + } + $imageURL = SugarThemeRegistry::current()->getImageURL($key.'.gif'); + $bottomLinksStr .= ""; + } + } + $ss->assign("BOTTOMLINKS",$bottomLinksStr); + if (SugarConfig::getInstance()->get('calculate_response_time', false)) + $ss->assign('STATISTICS',$this->_getStatistics()); + + // Under the License referenced above, you are required to leave in all copyright statements in both + // the code and end-user application. + + + $copyright = '© 2004-2011 SugarCRM Inc. The Program is provided AS IS, without warranty. Licensed under AGPLv3.
This program is free software; you can redistribute it and/or modify it under the terms of the
GNU Affero General Public License version 3 as published by the Free Software Foundation, including the additional permission set forth in the source code header.
'; + + + + + + + + + + + + // The interactive user interfaces in modified source and object code + // versions of this program must display Appropriate Legal Notices, as + // required under Section 5 of the GNU General Public License version + // 3. In accordance with Section 7(b) of the GNU General Public License + // version 3, these Appropriate Legal Notices must retain the display + // of the "Powered by SugarCRM" logo. If the display of the logo is + // not reasonably feasible for technical reasons, the Appropriate + // Legal Notices must display the words "Powered by SugarCRM". + $attribLinkImg = "Powered By SugarCRM\n"; + + + + // Bug 38594 - Add in Trademark wording + $copyright .= 'SugarCRM is a trademark of SugarCRM, Inc. All other company and product names may be trademarks of the respective companies with which they are associated.
'; + + //rrs bug: 20923 - if this image does not exist as per the license, then the proper image will be displaye regardless, so no need + //to display an empty image here. + if(file_exists('include/images/poweredby_sugarcrm.png')){ + $copyright .= $attribLinkImg; + } + // End Required Image + $ss->assign('COPYRIGHT',$copyright); + $ss->display(SugarThemeRegistry::current()->getTemplate('footer.tpl')); + } + + /** + * Called from process(). This method will display subpanels. + */ + protected function _displaySubPanels() + { + if (isset($this->bean) && !empty($this->bean->id) && (file_exists('modules/' . $this->module . '/metadata/subpaneldefs.php') || file_exists('custom/modules/' . $this->module . '/metadata/subpaneldefs.php') || file_exists('custom/modules/' . $this->module . '/Ext/Layoutdefs/layoutdefs.ext.php'))) { + $GLOBALS['focus'] = $this->bean; + require_once ('include/SubPanel/SubPanelTiles.php'); + $subpanel = new SubPanelTiles($this->bean, $this->module); + echo $subpanel->display(); + } + } + + protected function _buildModuleList() + { + if (!empty($GLOBALS['current_user']) && empty($GLOBALS['modListHeader'])) + $GLOBALS['modListHeader'] = query_module_access_list($GLOBALS['current_user']); + } + + /** + * private method used in process() to determine the value of a passed in option + * + * @param string option - the option that we want to know the valye of + * @param bool default - what the default value should be if we do not find the option + * + * @return bool - the value of the option + */ + protected function _getOption( + $option, + $default = false + ) + { + if (!empty($this->options) && isset($this->options['show_all'])) { + return $this->options['show_all']; + } elseif (!empty($this->options) && isset($this->options[$option])) { + return $this->options[$option]; + } else return $default; + } + + /** + * track + * Private function to track information about the view request + */ + private function _track() + { + if (empty($this->responseTime)) { + $this->_calculateFooterMetrics(); + } + if (empty($GLOBALS['current_user']->id)) { + return; + } + + + $trackerManager = TrackerManager::getInstance(); + $trackerManager->save(); + + } + + /** + * Checks to see if the module name passed is valid; dies if it is not + */ + protected function _checkModule() + { + if(!empty($this->module) && !file_exists('modules/'.$this->module)){ + $error = str_replace("[module]", "$this->module", $GLOBALS['app_strings']['ERR_CANNOT_FIND_MODULE']); + $GLOBALS['log']->fatal($error); + echo $error; + die(); + } + } + + public function renderJavascript() + { + if ($this->action !== 'Login') + $this->_displayJavascript(); + else + $this->_displayLoginJS(); + } + + private function _calculateFooterMetrics() + { + $endTime = microtime(true); + $deltaTime = $endTime - $GLOBALS['startTime']; + $this->responseTime = number_format(round($deltaTime, 2), 2); + // Print out the resources used in constructing the page. + $this->fileResources = count(get_included_files()); + } + + private function _getStatistics() + { + $endTime = microtime(true); + $deltaTime = $endTime - $GLOBALS['startTime']; + $response_time_string = $GLOBALS['app_strings']['LBL_SERVER_RESPONSE_TIME'] . " " . number_format(round($deltaTime, 2), 2) . " " . $GLOBALS['app_strings']['LBL_SERVER_RESPONSE_TIME_SECONDS']; + $return = $response_time_string; + $return .= '
'; + if (!empty($GLOBALS['sugar_config']['show_page_resources'])) { + // Print out the resources used in constructing the page. + $included_files = get_included_files(); + + // take all of the included files and make a list that does not allow for duplicates based on case + // I believe the full get_include_files result set appears to have one entry for each file in real + // case, and one entry in all lower case. + $list_of_files_case_insensitive = array(); + foreach($included_files as $key => $name) { + // preserve the first capitalization encountered. + $list_of_files_case_insensitive[mb_strtolower($name) ] = $name; + } + $return .= $GLOBALS['app_strings']['LBL_SERVER_RESPONSE_RESOURCES'] . '(' . DBManager::getQueryCount() . ',' . sizeof($list_of_files_case_insensitive) . ')
'; + // Display performance of the internal and external caches.... + $cacheStats = SugarCache::instance()->getCacheStats(); + $return .= "External cache (hits/total=ratio) local ({$cacheStats['localHits']}/{$cacheStats['requests']}=" . round($cacheStats['localHits']*100/$cacheStats['requests'], 0) . "%)"; + $return .= " external ({$cacheStats['externalHits']}/{$cacheStats['requests']}=" . round($cacheStats['externalHits']*100/$cacheStats['requests'], 0) . "%)
"; + $return .= " misses ({$cacheStats['misses']}/{$cacheStats['requests']}=" . round($cacheStats['misses']*100/$cacheStats['requests'], 0) . "%)
"; + } + + return $return; + } + + /** + * Loads the module shortcuts menu + * + * @param $module string optional, can specify module to retrieve menu for if not the current one + * @return array module menu + */ + public function getMenu( + $module = null + ) + { + global $current_language, $current_user, $mod_strings, $app_strings; + + if ( empty($module) ) + $module = $this->module; + + $final_module_menu = array(); + + if (file_exists('modules/' . $module . '/Menu.php')) { + $GLOBALS['module_menu'] = $module_menu = array(); + require('modules/' . $module . '/Menu.php'); + $final_module_menu = array_merge($final_module_menu,$GLOBALS['module_menu'],$module_menu); + } + if (file_exists('custom/modules/' . $module . '/Ext/Menus/menu.ext.php')) { + $GLOBALS['module_menu'] = $module_menu = array(); + require('custom/modules/' . $module . '/Ext/Menus/menu.ext.php'); + $final_module_menu = array_merge($final_module_menu,$GLOBALS['module_menu'],$module_menu); + } + if (!file_exists('modules/' . $module . '/Menu.php') + && !file_exists('custom/modules/' . $module . '/Ext/Menus/menu.ext.php') + && !empty($GLOBALS['mod_strings']['LNK_NEW_RECORD'])) { + $final_module_menu[] = array("index.php?module=$module&action=EditView&return_module=$module&return_action=DetailView", + $GLOBALS['mod_strings']['LNK_NEW_RECORD'],"{$GLOBALS['app_strings']['LBL_CREATE_BUTTON_LABEL']}$module" ,$module ); + $final_module_menu[] = array("index.php?module=$module&action=index", $GLOBALS['mod_strings']['LNK_LIST'], + $module, $module); + if ( ($this->bean instanceOf SugarBean) && !empty($this->bean->importable) ) + if ( !empty($mod_strings['LNK_IMPORT_'.strtoupper($module)]) ) + $final_module_menu[] = array("index.php?module=Import&action=Step1&import_module=$module&return_module=$module&return_action=index", + $mod_strings['LNK_IMPORT_'.strtoupper($module)], "Import", $module); + else + $final_module_menu[] = array("index.php?module=Import&action=Step1&import_module=$module&return_module=$module&return_action=index", + $app_strings['LBL_IMPORT'], "Import", $module); + } + if (file_exists('custom/application/Ext/Menus/menu.ext.php')) { + $GLOBALS['module_menu'] = $module_menu = array(); + require('custom/application/Ext/Menus/menu.ext.php'); + $final_module_menu = array_merge($final_module_menu,$GLOBALS['module_menu'],$module_menu); + } + $module_menu = $final_module_menu; + + return $module_menu; + } + + /** + * Returns the module name which should be highlighted in the module menu + */ + protected function _getModuleTab() + { + global $app_list_strings, $moduleTabMap; + + // Need to figure out what tab this module belongs to, most modules have their own tabs, but there are exceptions. + if ( !empty($_REQUEST['module_tab']) ) + return $_REQUEST['module_tab']; + elseif ( isset($moduleTabMap[$this->module]) ) + return $moduleTabMap[$this->module]; + // Special cases + elseif ( $this->module == 'MergeRecords' ) + return !empty($_REQUEST['merge_module']) ? $_REQUEST['merge_module'] : $_REQUEST['return_module']; + elseif ( $this->module == 'Users' && $this->action == 'SetTimezone' ) + return 'Home'; + // Default anonymous pages to be under Home + elseif ( !isset($app_list_strings['moduleList'][$this->module]) ) + return 'Home'; + else + return $this->module; + } + + /** + * Return the "breadcrumbs" to display at the top of the page + * + * @param bool $show_help optional, true if we show the help links + * @return HTML string containing breadcrumb title + */ + public function getModuleTitle( + $show_help = true + ) + { + global $sugar_version, $sugar_flavor, $server_unique_key, $current_language, $action; + + $theTitle = "
\n

"; + + $module = preg_replace("/ /","",$this->module); + + $params = $this->_getModuleTitleParams(); + $count = count($params); + $index = 0; + + if(SugarThemeRegistry::current()->directionality == "rtl") { + $params = array_reverse($params); + } + + foreach($params as $parm){ + $index++; + $theTitle .= $parm; + if($index < $count){ + $theTitle .= $this->getBreadCrumbSymbol(); + } + } + $theTitle .= "

\n"; + + if ($show_help) { + $theTitle .= ""; + + $createImageURL = SugarThemeRegistry::current()->getImageURL('create-record.gif'); + $theTitle .= << +{$GLOBALS[ + +{$GLOBALS['app_strings']['LNK_CREATE']} + +EOHTML; + } + + $theTitle .= "
\n"; + return $theTitle; + } + + /** + * Return the metadata file that will be used by this view. + * + * @return string File location of the metadata file. + */ + public function getMetaDataFile() + { + $metadataFile = null; + $foundViewDefs = false; + $viewDef = strtolower($this->type) . 'viewdefs'; + $coreMetaPath = 'modules/'.$this->module.'/metadata/' . $viewDef . '.php'; + if(file_exists('custom/' .$coreMetaPath )){ + $metadataFile = 'custom/' . $coreMetaPath; + $foundViewDefs = true; + }else{ + if(file_exists('custom/modules/'.$this->module.'/metadata/metafiles.php')){ + require_once('custom/modules/'.$this->module.'/metadata/metafiles.php'); + if(!empty($metafiles[$this->module][$viewDef])){ + $metadataFile = $metafiles[$this->module][$viewDef]; + $foundViewDefs = true; + } + }elseif(file_exists('modules/'.$this->module.'/metadata/metafiles.php')){ + require_once('modules/'.$this->module.'/metadata/metafiles.php'); + if(!empty($metafiles[$this->module][$viewDef])){ + $metadataFile = $metafiles[$this->module][$viewDef]; + $foundViewDefs = true; + } + } + } + + if(!$foundViewDefs && file_exists($coreMetaPath)){ + $metadataFile = $coreMetaPath; + } + $GLOBALS['log']->debug("metadatafile=". $metadataFile); + + return $metadataFile; + } + + + /** + * Returns an array composing of the breadcrumbs to use for the module title + * + * @param bool $browserTitle true if the returned string is being used for the browser title, meaning + * there should be no HTML in the string + * @return array + */ + protected function _getModuleTitleParams($browserTitle = false) + { + $params = array($this->_getModuleTitleListParam($browserTitle)); + + if (isset($this->action)){ + switch ($this->action) { + case 'EditView': + if(!empty($this->bean->id)) { + $params[] = "".$this->bean->get_summary_text().""; + $params[] = $GLOBALS['app_strings']['LBL_EDIT_BUTTON_LABEL']; + } + else + $params[] = $GLOBALS['app_strings']['LBL_CREATE_BUTTON_LABEL']; + break; + case 'DetailView': + $beanName = $this->bean->get_summary_text(); + $params[] = $beanName; + break; + } + } + + return $params; + } + + /** + * Returns the portion of the array that will represent the listview in the breadcrumb + * + * @param bool $browserTitle true if the returned string is being used for the browser title, meaning + * there should be no HTML in the string + * @return string + */ + protected function _getModuleTitleListParam( $browserTitle = false ) + { + global $current_user; + global $app_strings; + + if(!empty($GLOBALS['app_list_strings']['moduleList'][$this->module])) + $firstParam = $GLOBALS['app_list_strings']['moduleList'][$this->module]; + else + $firstParam = $this->module; + + $iconPath = $this->getModuleTitleIconPath($this->module); + if($this->action == "ListView" || $this->action == "index") { + if (!empty($iconPath) && !$browserTitle) { + if (SugarThemeRegistry::current()->directionality == "ltr") { + return "" + . "".$this->module."" + . $this->getBreadCrumbSymbol().$app_strings['LBL_SEARCH']; + } else { + return $app_strings['LBL_SEARCH'].$this->getBreadCrumbSymbol() + . "" + . "".$this->module.""; + } + } else { + return $firstParam; + } + } + else { + if (!empty($iconPath) && !$browserTitle) { + return "" + . "".$this->module.""; + } else { + return "{$firstParam}"; + } + } + } + + protected function getModuleTitleIconPath($module) + { + $iconPath = ""; + if(is_file(SugarThemeRegistry::current()->getImageURL('icon_'.$module.'_32.png',false))) { + $iconPath = SugarThemeRegistry::current()->getImageURL('icon_'.$module.'_32.png'); + } + else if (is_file(SugarThemeRegistry::current()->getImageURL('icon_'.ucfirst($module).'_32.png',false))) { + $iconPath = SugarThemeRegistry::current()->getImageURL('icon_'.ucfirst($module).'_32.png'); + } + return $iconPath; + } + + /** + * Returns the string which will be shown in the browser's title; defaults to using the same breadcrumb + * as in the module title + * + * @return string + */ + public function getBrowserTitle() + { + global $app_strings; + + $browserTitle = $app_strings['LBL_BROWSER_TITLE']; + if ( $this->module == 'Users' && ($this->action == 'SetTimezone' || $this->action == 'Login') ) + return $browserTitle; + $params = $this->_getModuleTitleParams(true); + foreach ($params as $value ) + $browserTitle = strip_tags($value) . ' » ' . $browserTitle; + + return $browserTitle; + } + + /** + * Returns the correct breadcrumb symbol according to theme's directionality setting + * + * @return string + */ + public function getBreadCrumbSymbol() + { + if(SugarThemeRegistry::current()->directionality == "ltr") { + return "»"; + } + else { + return "«"; + } + } +} diff --git a/include/MVC/View/ViewFactory.php b/include/MVC/View/ViewFactory.php new file mode 100644 index 00000000..45c64999 --- /dev/null +++ b/include/MVC/View/ViewFactory.php @@ -0,0 +1,248 @@ +_config.php file which holds options used by the view. + */ + function _loadConfig(&$view, $type){ + $view_config_custom = array(); + $view_config_module = array(); + $view_config_root_cstm = array(); + $view_config_root = array(); + $view_config_app = array(); + $config_file_name = 'view.'.$type.'.config.php'; + $view_config = sugar_cache_retrieve("VIEW_CONFIG_FILE_".$view->module."_TYPE_".$type); + if(!$view_config){ + if(file_exists('custom/modules/'.$view->module.'/views/'.$config_file_name)){ + require_once('custom/modules/'.$view->module.'/views/'.$config_file_name); + $view_config_custom = $view_config; + } + if(file_exists('modules/'.$view->module.'/views/'.$config_file_name)){ + require_once('modules/'.$view->module.'/views/'.$config_file_name); + $view_config_module = $view_config; + } + if(file_exists('custom/include/MVC/View/views/'.$config_file_name)){ + require_once('custom/include/MVC/View/views/'.$config_file_name); + $view_config_root_cstm = $view_config; + } + if(file_exists('include/MVC/View/views/'.$config_file_name)){ + require_once('include/MVC/View/views/'.$config_file_name); + $view_config_root = $view_config; + } + if(file_exists('include/MVC/View/views/view.config.php')){ + require_once('include/MVC/View/views/view.config.php'); + $view_config_app = $view_config; + } + $view_config = array('actions' => array(), 'req_params' => array(),); + + //actions + if(!empty($view_config_app) && !empty($view_config_app['actions'])) + $view_config['actions'] = array_merge($view_config['actions'], $view_config_app['actions']); + if(!empty($view_config_root) && !empty($view_config_root['actions'])) + $view_config['actions'] = array_merge($view_config['actions'], $view_config_root['actions']); + if(!empty($view_config_root_cstm) && !empty($view_config_root_cstm['actions'])) + $view_config['actions'] = array_merge($view_config['actions'], $view_config_root_cstm['actions']); + if(!empty($view_config_module) && !empty($view_config_module['actions'])) + $view_config['actions'] = array_merge($view_config['actions'], $view_config_module['actions']); + if(!empty($view_config_custom) && !empty($view_config_custom['actions'])) + $view_config['actions'] = array_merge($view_config['actions'], $view_config_custom['actions']); + + //req_params + if(!empty($view_config_app) && !empty($view_config_app['req_params'])) + $view_config['req_params'] = array_merge($view_config['req_params'], $view_config_app['req_params']); + if(!empty($view_config_root) && !empty($view_config_root['req_params'])) + $view_config['req_params'] = array_merge($view_config['req_params'], $view_config_root['req_params']); + if(!empty($view_config_root_cstm) && !empty($view_config_root_cstm['req_params'])) + $view_config['req_params'] = array_merge($view_config['req_params'], $view_config_root_cstm['req_params']); + if(!empty($view_config_module) && !empty($view_config_module['req_params'])) + $view_config['req_params'] = array_merge($view_config['req_params'], $view_config_module['req_params']); + if(!empty($view_config_custom) && !empty($view_config_custom['req_params'])) + $view_config['req_params'] = array_merge($view_config['req_params'], $view_config_custom['req_params']); + + sugar_cache_put("VIEW_CONFIG_FILE_".$view->module."_TYPE_".$type, $view_config); + } + $action = strtolower($view->action); + $config = null; + if(!empty($view_config['req_params'])){ + //try the params first + foreach($view_config['req_params'] as $key => $value){ + if(!empty($_REQUEST[$key]) && $_REQUEST[$key] == "false") { + $_REQUEST[$key] = false; + } + if(!empty($_REQUEST[$key])){ + + if(!is_array($value['param_value'])){ + if($value['param_value'] == $_REQUEST[$key]){ + $config = $value['config']; + break; + } + }else{ + + foreach($value['param_value'] as $v){ + if($v == $_REQUEST[$key]){ + $config = $value['config']; + break; + } + + } + + } + + + + } + } + } + if($config == null && !empty($view_config['actions']) && !empty($view_config['actions'][$action])){ + $config = $view_config['actions'][$action]; + } + if($config != null) + $view->options = $config; + } + + /** + * This is a private function which just helps the getView function generate the + * proper view object + * + * @return a valid SugarView + */ + function _buildFromFile($file, &$bean, $view_object_map, $type, $module){ + require_once($file); + //try ModuleViewType first then try ViewType if that fails then use SugarView + $class = ucfirst($module).'View'.ucfirst($type); + $customClass = 'Custom' . $class; + + if(class_exists($customClass)){ + return ViewFactory::_buildClass($customClass, $bean, $view_object_map); + } + if(class_exists($class)){ + return ViewFactory::_buildClass($class, $bean, $view_object_map); + } + //Now try the next set of possibilites if it was none of the above + $class = 'View'.ucfirst($type); + $customClass = 'Custom' . $class; + if(class_exists($customClass)){ + return ViewFactory::_buildClass($customClass, $bean, $view_object_map); + } + if(class_exists($class)){ + return ViewFactory::_buildClass($class, $bean, $view_object_map); + } + //Now check if there is a custom SugarView for generic handling + if(file_exists('custom/include/MVC/View/SugarView.php')){ + require_once('custom/include/MVC/View/SugarView.php'); + if(class_exists('CustomSugarView')){ + return new CustomSugarView($bean, $view_object_map); + } + } + //if all else fails return SugarView + return new SugarView($bean, $view_object_map); + + } + + /** + * instantiate the correct view and call init to pass on any obejcts we need to + * from the controller. + * + * @param string class - the name of the class to instantiate + * @param object bean = the bean to pass to the view + * @param array view_object_map - the array which holds obejcts to pass between the + * controller and the view. + * + * @return SugarView + */ + function _buildClass($class, $bean, $view_object_map){ + $view = new $class(); + $view->init($bean, $view_object_map); + if($view instanceof SugarView){ + return $view; + }else + return new SugarView($bean, $view_object_map); + } +} +?> diff --git a/include/MVC/View/tpls/Importvcard.tpl b/include/MVC/View/tpls/Importvcard.tpl new file mode 100644 index 00000000..9be7a316 --- /dev/null +++ b/include/MVC/View/tpls/Importvcard.tpl @@ -0,0 +1,69 @@ +{* + +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + + + +*} + +{$MOD.LBL_IMPORT_VCARDTEXT} + +{literal} + +{/literal} +
+ + + + + +  + + + diff --git a/include/MVC/View/tpls/modulelistmenu.tpl b/include/MVC/View/tpls/modulelistmenu.tpl new file mode 100644 index 00000000..e1508813 --- /dev/null +++ b/include/MVC/View/tpls/modulelistmenu.tpl @@ -0,0 +1,42 @@ +{* + +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + + + +*} +[{foreach from=$LAST_VIEWED item=item name=lastViewed}{ldelim}"text":"{$item.item_summary_short|htmlentities:$smarty.const.ENT_QUOTES:'utf-8'}","url": "{sugar_link module=$item.module_name action='DetailView' record=$item.item_id link_only=1}"{rdelim}{if !$smarty.foreach.lastViewed.last},{/if}{foreachelse}{ldelim} "text": "{$APP.NTC_NO_ITEMS_DISPLAY}"{rdelim}{/foreach}] \ No newline at end of file diff --git a/include/MVC/View/tpls/xsrf.tpl b/include/MVC/View/tpls/xsrf.tpl new file mode 100644 index 00000000..13d8f4aa --- /dev/null +++ b/include/MVC/View/tpls/xsrf.tpl @@ -0,0 +1,61 @@ +{* + +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + + + +*} + +
+

Possible Cross Site Request Forgery (XSRF) Attack Detected

+

If you think this is a mistake please ask your administrator to add the following site to the acceptable referer list

+

{$host}

+

Click here for directions to add this site to the acceptable referer list

+
+ diff --git a/include/MVC/View/views/view.ajax.php b/include/MVC/View/views/view.ajax.php new file mode 100644 index 00000000..82ece12e --- /dev/null +++ b/include/MVC/View/views/view.ajax.php @@ -0,0 +1,57 @@ +options['show_title'] = false; + $this->options['show_header'] = false; + $this->options['show_footer'] = false; + $this->options['show_javascript'] = false; + $this->options['show_subpanels'] = false; + $this->options['show_search'] = false; + + parent::SugarView(); + } +} diff --git a/include/MVC/View/views/view.classic.config.php b/include/MVC/View/views/view.classic.config.php new file mode 100644 index 00000000..d6e1ab02 --- /dev/null +++ b/include/MVC/View/views/view.classic.config.php @@ -0,0 +1,68 @@ + + array( + 'print' => array('param_value' => true, + 'config' => array( + 'show_header' => true, + 'show_footer' => false, + 'view_print' => true, + 'show_title' => false, + 'show_subpanels' => false, + 'show_javascript' => true, + 'show_search' => false,) + ), + 'to_pdf' => array('param_value' => true, + 'config' => array( + 'show_all' => false + ), + ), + 'to_csv' => array('param_value' => true, + 'config' => array( + 'show_all' => false + ), + ), + ), + ); +?> diff --git a/include/MVC/View/views/view.classic.php b/include/MVC/View/views/view.classic.php new file mode 100644 index 00000000..88a444ea --- /dev/null +++ b/include/MVC/View/views/view.classic.php @@ -0,0 +1,71 @@ +type = $this->action; + } + + /** + * @see SugarView::display() + */ + public function display() + { + // Call SugarController::getActionFilename to handle case sensitive file names + $file = SugarController::getActionFilename($this->action); + if(file_exists('custom/modules/' . $this->module . '/'. $file . '.php')){ + $this->includeClassicFile('custom/modules/'. $this->module . '/'. $file . '.php'); + return true; + } + elseif(file_exists('modules/' . $this->module . '/'. $file . '.php')){ + $this->includeClassicFile('modules/'. $this->module . '/'. $file . '.php'); + return true; + } + return false; + } +} diff --git a/include/MVC/View/views/view.config.php b/include/MVC/View/views/view.config.php new file mode 100644 index 00000000..51bc0a9f --- /dev/null +++ b/include/MVC/View/views/view.config.php @@ -0,0 +1,120 @@ + + array( + 'ajaxformsave' => array( + 'show_all' => false + ), + 'popup' => array( + 'show_header' => false, + 'show_subpanels' => false, + 'show_search' => false, + 'show_footer' => false, + 'show_javascript' => true, + ), + 'authenticate' => array( + 'show_header' => false, + 'show_subpanels' => false, + 'show_search' => false, + 'show_footer' => false, + 'show_javascript' => true, + ), + 'subpanelcreates' => array( + 'show_header' => false, + 'show_subpanels' => false, + 'show_search' => false, + 'show_footer' => false, + 'show_javascript' => true, + ), + ), +'req_params' => + array( + 'print' => array('param_value' => true, + 'config' => array( + 'show_header' => true, + 'show_footer' => false, + 'view_print' => true, + 'show_title' => false, + 'show_subpanels' => false, + 'show_javascript' => true, + 'show_search' => false,) + ), + 'action' => array('param_value' => array('Delete','Save'), + 'config' => array( + 'show_all' => false + ), + ), + 'to_pdf' => array('param_value' => true, + 'config' => array( + 'show_all' => false + ), + ), + 'to_csv' => array('param_value' => true, + 'config' => array( + 'show_all' => false + ), + ), + 'sugar_body_only' => array('param_value' => true, + 'config' => array( + 'show_all' => false + ), + ), + 'view' => array('param_value' => 'documentation', + 'config' => array( + 'show_all' => false + ), + ), + 'show_js' => array('param_value' => true, + 'config' => array( + 'show_header' => false, + 'show_footer' => false, + 'view_print' => false, + 'show_title' => false, + 'show_subpanels' => false, + 'show_javascript' => true, + 'show_search' => false,) + ), + ), + ); +?> diff --git a/include/MVC/View/views/view.detail.php b/include/MVC/View/views/view.detail.php new file mode 100644 index 00000000..ee97fee3 --- /dev/null +++ b/include/MVC/View/views/view.detail.php @@ -0,0 +1,71 @@ +options['show_subpanels'] = true; + parent::SugarView(); + } + + function preDisplay(){ + + $metadataFile = $this->getMetaDataFile(); + $this->dv = new DetailView2(); + $this->dv->ss =& $this->ss; + $this->dv->setup($this->module, $this->bean, $metadataFile, 'include/DetailView/DetailView.tpl'); + } + + function display(){ + if(empty($this->bean->id)){ + global $app_strings; + sugar_die($app_strings['ERROR_NO_RECORD']); + } + $this->dv->process(); + echo $this->dv->display(); + } + +} diff --git a/include/MVC/View/views/view.edit.php b/include/MVC/View/views/view.edit.php new file mode 100644 index 00000000..3b219471 --- /dev/null +++ b/include/MVC/View/views/view.edit.php @@ -0,0 +1,68 @@ +getMetaDataFile(); + $this->ev = new EditView(); + $this->ev->ss =& $this->ss; + $this->ev->setup($this->module, $this->bean, $metadataFile, 'include/EditView/EditView.tpl'); + + } + + function display(){ + $this->ev->process(); + echo $this->ev->display($this->showTitle); + } + } +?> diff --git a/include/MVC/View/views/view.html.php b/include/MVC/View/views/view.html.php new file mode 100644 index 00000000..773e03d0 --- /dev/null +++ b/include/MVC/View/views/view.html.php @@ -0,0 +1,49 @@ + diff --git a/include/MVC/View/views/view.importvcard.php b/include/MVC/View/views/view.importvcard.php new file mode 100644 index 00000000..87e521c1 --- /dev/null +++ b/include/MVC/View/views/view.importvcard.php @@ -0,0 +1,79 @@ +ss->assign("ERROR_TEXT", $app_strings['LBL_EMPTY_VCARD']); + $this->ss->assign("HEADER", $app_strings['LBL_IMPORT_VCARD']); + $this->ss->assign("MODULE", $_REQUEST['module']); + $params = array(); + $params[] = "{$mod_strings['LBL_MODULE_NAME']}"; + $params[] = $app_strings['LBL_IMPORT_VCARD_BUTTON_LABEL']; + echo getClassicModuleTitle($mod_strings['LBL_MODULE_NAME'], $params, true); + + + if ( file_exists('custom/include/MVC/View/tpls/Importvcard.tpl') ) + $this->ss->display('custom/include/MVC/View/tpls/Importvcard.tpl'); + else + $this->ss->display('include/MVC/View/tpls/Importvcard.tpl'); + } +} +?> diff --git a/include/MVC/View/views/view.importvcardsave.php b/include/MVC/View/views/view.importvcardsave.php new file mode 100644 index 00000000..b2f12fe5 --- /dev/null +++ b/include/MVC/View/views/view.importvcardsave.php @@ -0,0 +1,70 @@ + 0 ) { + $vcard = new vCard(); + $record = $vcard->importVCard($_FILES['vcard']['tmp_name'],$_REQUEST['module']); + SugarApplication::redirect("index.php?action=DetailView&module={$_REQUEST['module']}&record=$record"); + } + else + SugarApplication::redirect("index.php?action=Importvcard&module={$_REQUEST['module']}"); + } +} +?> diff --git a/include/MVC/View/views/view.json.php b/include/MVC/View/views/view.json.php new file mode 100644 index 00000000..4362dcff --- /dev/null +++ b/include/MVC/View/views/view.json.php @@ -0,0 +1,65 @@ +bean; + $all_fields = array_merge($bean->column_fields,$bean->additional_column_fields); + + $js_fields_arr = array(); + foreach($all_fields as $field) { + if(isset($bean->$field)) { + $bean->$field = from_html($bean->$field); + $bean->$field = preg_replace('/\r\n/','
',$bean->$field); + $bean->$field = preg_replace('/\n/','
',$bean->$field); + $js_fields_arr[$field] = addslashes($bean->$field); + } + } + $out = $json->encode($js_fields_arr, true); + ob_clean(); + print($out); + sugar_cleanup(true); + } +} +?> diff --git a/include/MVC/View/views/view.list.php b/include/MVC/View/views/view.list.php new file mode 100644 index 00000000..6e0b41e1 --- /dev/null +++ b/include/MVC/View/views/view.list.php @@ -0,0 +1,293 @@ +getMetaDataFile(); + + if( !file_exists($metadataFile) ) + sugar_die($GLOBALS['app_strings']['LBL_NO_ACTION'] ); + + require_once($metadataFile); + $this->listViewDefs = $listViewDefs; + + if(!empty($this->bean->object_name) && isset($_REQUEST[$module.'2_'.strtoupper($this->bean->object_name).'_offset'])) {//if you click the pagination button, it will poplate the search criteria here + if(!empty($_REQUEST['current_query_by_page'])) {//The code support multi browser tabs pagination + $blockVariables = array('mass', 'uid', 'massupdate', 'delete', 'merge', 'selectCount', 'request_data', 'current_query_by_page',$module.'2_'.strtoupper($this->bean->object_name).'_ORDER_BY' ); + if(isset($_REQUEST['lvso'])){ + $blockVariables[] = 'lvso'; + } + $current_query_by_page = unserialize(base64_decode($_REQUEST['current_query_by_page'])); + foreach($current_query_by_page as $search_key=>$search_value) { + if($search_key != $module.'2_'.strtoupper($this->bean->object_name).'_offset' && !in_array($search_key, $blockVariables)) { + if (!is_array($search_value)) { + $_REQUEST[$search_key] = $GLOBALS['db']->quoteForEmail($search_value); + } + else { + foreach ($search_value as $key=>&$val) { + $val = $GLOBALS['db']->quoteForEmail($val); + } + $_REQUEST[$search_key] = $search_value; + } + } + } + } + } + if(!empty($_REQUEST['saved_search_select'])) { + if ($_REQUEST['saved_search_select']=='_none' || !empty($_REQUEST['button'])) { + $_SESSION['LastSavedView'][$_REQUEST['module']] = ''; + unset($_REQUEST['saved_search_select']); + unset($_REQUEST['saved_search_select_name']); + + //use the current search module, or the current module to clear out layout changes + if(!empty($_REQUEST['search_module']) || !empty($_REQUEST['module'])){ + $mod = !empty($_REQUEST['search_module']) ? $_REQUEST['search_module'] : $_REQUEST['module']; + global $current_user; + //Reset the current display columns to default. + $current_user->setPreference('ListViewDisplayColumns', array(), 0, $mod); + } + } + else if(empty($_REQUEST['button']) && (empty($_REQUEST['clear_query']) || $_REQUEST['clear_query']!='true')) { + $this->saved_search = loadBean('SavedSearch'); + $this->saved_search->retrieveSavedSearch($_REQUEST['saved_search_select']); + $this->saved_search->populateRequest(); + } + elseif(!empty($_REQUEST['button'])) { // click the search button, after retrieving from saved_search + $_SESSION['LastSavedView'][$_REQUEST['module']] = ''; + unset($_REQUEST['saved_search_select']); + unset($_REQUEST['saved_search_select_name']); + } + } + $this->storeQuery = new StoreQuery(); + if(!isset($_REQUEST['query'])){ + $this->storeQuery->loadQuery($this->module); + $this->storeQuery->populateRequest(); + }else{ + $this->storeQuery->saveFromRequest($this->module); + } + + $this->seed = $this->bean; + + $displayColumns = array(); + if(!empty($_REQUEST['displayColumns'])) { + foreach(explode('|', $_REQUEST['displayColumns']) as $num => $col) { + if(!empty($this->listViewDefs[$module][$col])) + $displayColumns[$col] = $this->listViewDefs[$module][$col]; + } + } + else { + foreach($this->listViewDefs[$module] as $col => $this->params) { + if(!empty($this->params['default']) && $this->params['default']) + $displayColumns[$col] = $this->params; + } + } + $this->params = array('massupdate' => true); + if(!empty($_REQUEST['orderBy'])) { + $this->params['orderBy'] = $_REQUEST['orderBy']; + $this->params['overrideOrder'] = true; + if(!empty($_REQUEST['sortOrder'])) $this->params['sortOrder'] = $_REQUEST['sortOrder']; + } + $this->lv->displayColumns = $displayColumns; + + $this->module = $module; + + $this->prepareSearchForm(); + + if(isset($this->options['show_title']) && $this->options['show_title']) { + $moduleName = isset($this->seed->module_dir) ? $this->seed->module_dir : $GLOBALS['mod_strings']['LBL_MODULE_NAME']; + echo $this->getModuleTitle(true); + } + } + + function listViewProcess(){ + $this->processSearchForm(); + $this->lv->searchColumns = $this->searchForm->searchColumns; + + if(!$this->headers) + return; + if(empty($_REQUEST['search_form_only']) || $_REQUEST['search_form_only'] == false){ + $this->lv->ss->assign("SEARCH",true); + $this->lv->setup($this->seed, 'include/ListView/ListViewGeneric.tpl', $this->where, $this->params); + $savedSearchName = empty($_REQUEST['saved_search_select_name']) ? '' : (' - ' . $_REQUEST['saved_search_select_name']); + echo $this->lv->display(); + } + } + function prepareSearchForm(){ + $this->searchForm = null; + + //search + $view = 'basic_search'; + if(!empty($_REQUEST['search_form_view']) && $_REQUEST['search_form_view'] == 'advanced_search') + $view = $_REQUEST['search_form_view']; + $this->headers = true; + if(!empty($_REQUEST['search_form_only']) && $_REQUEST['search_form_only']) + $this->headers = false; + elseif(!isset($_REQUEST['search_form']) || $_REQUEST['search_form'] != 'false') { + if(isset($_REQUEST['searchFormTab']) && $_REQUEST['searchFormTab'] == 'advanced_search') { + $view = 'advanced_search'; + }else { + $view = 'basic_search'; + } + } + + $this->use_old_search = true; + if ((file_exists('modules/' . $this->module . '/SearchForm.html') + && !file_exists('modules/' . $this->module . '/metadata/searchdefs.php')) + || (file_exists('custom/modules/' . $this->module . '/SearchForm.html') + && !file_exists('custom/modules/' . $this->module . '/metadata/searchdefs.php'))){ + require_once('include/SearchForm/SearchForm.php'); + $this->searchForm = new SearchForm($this->module, $this->seed); + }else{ + $this->use_old_search = false; + require_once('include/SearchForm/SearchForm2.php'); + + if(file_exists('custom/modules/'.$this->module.'/metadata/metafiles.php')){ + require('custom/modules/'.$this->module.'/metadata/metafiles.php'); + }elseif(file_exists('modules/'.$this->module.'/metadata/metafiles.php')){ + require('modules/'.$this->module.'/metadata/metafiles.php'); + } + +/* if(!empty($metafiles[$this->module]['searchdefs'])) + require_once($metafiles[$this->module]['searchdefs']); + elseif(file_exists('modules/'.$this->module.'/metadata/searchdefs.php')) + require_once('modules/'.$this->module.'/metadata/searchdefs.php'); +*/ + + if (file_exists('custom/modules/'.$this->module.'/metadata/searchdefs.php')) + { + require_once('custom/modules/'.$this->module.'/metadata/searchdefs.php'); + } + elseif (!empty($metafiles[$this->module]['searchdefs'])) + { + require_once($metafiles[$this->module]['searchdefs']); + } + elseif (file_exists('modules/'.$this->module.'/metadata/searchdefs.php')) + { + require_once('modules/'.$this->module.'/metadata/searchdefs.php'); + } + + + if(!empty($metafiles[$this->module]['searchfields'])) + require_once($metafiles[$this->module]['searchfields']); + elseif(file_exists('modules/'.$this->module.'/metadata/SearchFields.php')) + require_once('modules/'.$this->module.'/metadata/SearchFields.php'); + + if(file_exists('custom/modules/'.$this->module.'/metadata/SearchFields.php')){ + require_once('custom/modules/'.$this->module.'/metadata/SearchFields.php'); + } + + + $this->searchForm = new SearchForm($this->seed, $this->module, $this->action); + $this->searchForm->setup($searchdefs, $searchFields, 'include/SearchForm/tpls/SearchFormGeneric.tpl', $view, $this->listViewDefs); + $this->searchForm->lv = $this->lv; + } + } + function processSearchForm(){ + if(isset($_REQUEST['query'])) + { + // we have a query + if(!empty($_SERVER['HTTP_REFERER']) && preg_match('/action=EditView/', $_SERVER['HTTP_REFERER'])) { // from EditView cancel + $this->searchForm->populateFromArray($this->storeQuery->query); + } + else { + $this->searchForm->populateFromRequest(); + } + + $where_clauses = $this->searchForm->generateSearchWhere(true, $this->seed->module_dir); + + if (count($where_clauses) > 0 )$this->where = '('. implode(' ) AND ( ', $where_clauses) . ')'; + $GLOBALS['log']->info("List View Where Clause: $this->where"); + } + if($this->use_old_search){ + switch($view) { + case 'basic_search': + $this->searchForm->setup(); + $this->searchForm->displayBasic($this->headers); + break; + case 'advanced_search': + $this->searchForm->setup(); + $this->searchForm->displayAdvanced($this->headers); + break; + case 'saved_views': + echo $this->searchForm->displaySavedViews($this->listViewDefs, $this->lv, $this->headers); + break; + } + }else{ + echo $this->searchForm->display($this->headers); + } + } + function preDisplay(){ + $this->lv = new ListViewSmarty(); + } + function display(){ + if(!$this->bean || !$this->bean->ACLAccess('list')){ + ACLController::displayNoAccess(); + } else { + $this->listViewPrepare(); + $this->listViewProcess(); + } + } +} +?> diff --git a/include/MVC/View/views/view.modulelistmenu.php b/include/MVC/View/views/view.modulelistmenu.php new file mode 100644 index 00000000..6fc77b6d --- /dev/null +++ b/include/MVC/View/views/view.modulelistmenu.php @@ -0,0 +1,66 @@ +options['show_title'] = false; + $this->options['show_header'] = false; + $this->options['show_footer'] = false; + $this->options['show_javascript'] = false; + $this->options['show_subpanels'] = false; + $this->options['show_search'] = false; + parent::SugarView(); + } + + public function display() + { + $tracker = new Tracker(); + $history = $tracker->get_recently_viewed($GLOBALS['current_user']->id,$this->module); + foreach ( $history as $key => $row ) { + $history[$key]['item_summary_short'] = getTrackerSubstring($row['item_summary']); + $history[$key]['image'] = SugarThemeRegistry::current() + ->getImage($row['module_name'],'border="0" align="absmiddle" alt="'.$row['item_summary'].'"'); + } + $this->ss->assign('LAST_VIEWED',$history); + + $this->ss->display('include/MVC/View/tpls/modulelistmenu.tpl'); + } +} +?> diff --git a/include/MVC/View/views/view.multiedit.php b/include/MVC/View/views/view.multiedit.php new file mode 100644 index 00000000..8a5fe16c --- /dev/null +++ b/include/MVC/View/views/view.multiedit.php @@ -0,0 +1,85 @@ +action == 'AjaxFormSave'){ + echo "".$this->bean->id.""; + }else{ + if(!empty($_REQUEST['modules'])){ + $js_array = 'Array('; + + $count = count($_REQUEST['modules']); + $index = 1; + foreach($_REQUEST['modules'] as $module){ + $js_array .= "'form_".$module."'"; + if($index < $count) + $js_array .= ','; + $index++; + } + //$js_array = "Array(".implode(",", $js_array). ")"; + $js_array .= ');'; + echo ""; + if($count > 1) + echo ''; + foreach($_REQUEST['modules'] as $module){ + $bean = $beanList[$module]; + require_once($beanFiles[$bean]); + $GLOBALS['mod_strings'] = return_module_language($GLOBALS['current_language'], $module); + $ev = new EditView($module); + $ev->process(); + echo "
"; + echo $ev->display(true, true); + echo "
"; + } + } + } + } + } +?> diff --git a/include/MVC/View/views/view.noaccess.php b/include/MVC/View/views/view.noaccess.php new file mode 100644 index 00000000..d2dac633 --- /dev/null +++ b/include/MVC/View/views/view.noaccess.php @@ -0,0 +1,49 @@ +Warning: You do not have permission to access this module.

'; + } +} diff --git a/include/MVC/View/views/view.popup.php b/include/MVC/View/views/view.popup.php new file mode 100644 index 00000000..38346165 --- /dev/null +++ b/include/MVC/View/views/view.popup.php @@ -0,0 +1,173 @@ +bean instanceOf SugarBean) && !$this->bean->ACLAccess('list')){ + ACLController::displayNoAccess(); + sugar_cleanup(true); + } + + if(isset($_REQUEST['metadata']) && strpos($_REQUEST['metadata'], "..") !== false) + die("Directory navigation attack denied."); + if(!empty($_REQUEST['metadata']) && $_REQUEST['metadata'] != 'undefined' + && file_exists('modules/' . $this->module . '/metadata/' . $_REQUEST['metadata'] . '.php')) // if custom metadata is requested + require_once('modules/' . $this->module . '/metadata/' . $_REQUEST['metadata'] . '.php'); + elseif(file_exists('custom/modules/' . $this->module . '/metadata/popupdefs.php')) + require_once('custom/modules/' . $this->module . '/metadata/popupdefs.php'); + elseif(file_exists('modules/' . $this->module . '/metadata/popupdefs.php')) + require_once('modules/' . $this->module . '/metadata/popupdefs.php'); + + if(!empty($popupMeta) && !empty($popupMeta['listviewdefs'])){ + if(is_array($popupMeta['listviewdefs'])){ + //if we have an array, then we are not going to include a file, but rather the + //listviewdefs will be defined directly in the popupdefs file + $listViewDefs[$this->module] = $popupMeta['listviewdefs']; + }else{ + //otherwise include the file + require_once($popupMeta['listviewdefs']); + } + }elseif(file_exists('custom/modules/' . $this->module . '/metadata/listviewdefs.php')){ + require_once('custom/modules/' . $this->module . '/metadata/listviewdefs.php'); + }elseif(file_exists('modules/' . $this->module . '/metadata/listviewdefs.php')){ + require_once('modules/' . $this->module . '/metadata/listviewdefs.php'); + } + + //check for searchdefs as well + if(!empty($popupMeta) && !empty($popupMeta['searchdefs'])){ + if(is_array($popupMeta['searchdefs'])){ + //if we have an array, then we are not going to include a file, but rather the + //searchdefs will be defined directly in the popupdefs file + $searchdefs[$this->module]['layout']['advanced_search'] = $popupMeta['searchdefs']; + }else{ + //otherwise include the file + require_once($popupMeta['searchdefs']); + } + }else if(empty($searchdefs) && file_exists('custom/modules/'.$this->module.'/metadata/searchdefs.php')){ + require_once('custom/modules/'.$this->module.'/metadata/searchdefs.php'); + }else if(empty($searchdefs) && file_exists('modules/'.$this->module.'/metadata/searchdefs.php')){ + require_once('modules/'.$this->module.'/metadata/searchdefs.php'); + } + + //if you click the pagination button, it will poplate the search criteria here + if(!empty($this->bean) && isset($_REQUEST[$this->module.'2_'.strtoupper($this->bean->object_name).'_offset'])) { + if(!empty($_REQUEST['current_query_by_page'])) { + $blockVariables = array('mass', 'uid', 'massupdate', 'delete', 'merge', 'selectCount', + 'lvso', 'sortOrder', 'orderBy', 'request_data', 'current_query_by_page'); + $current_query_by_page = unserialize(base64_decode($_REQUEST['current_query_by_page'])); + foreach($current_query_by_page as $search_key=>$search_value) { + if($search_key != $this->module.'2_'.strtoupper($this->bean->object_name).'_offset' + && !in_array($search_key, $blockVariables)) + { + if (!is_array($search_value)) { + $_REQUEST[$search_key] = $GLOBALS['db']->quoteForEmail($search_value); + } + else { + foreach ($search_value as $key=>&$val) { + $val = $GLOBALS['db']->quoteForEmail($val); + } + $_REQUEST[$search_key] = $search_value; + } + } + } + } + } + + if(!empty($listViewDefs) && !empty($searchdefs)){ + require_once('include/Popups/PopupSmarty.php'); + $displayColumns = array(); + $filter_fields = array(); + $popup = new PopupSmarty($this->bean, $this->module); + foreach($listViewDefs[$this->module] as $col => $params) { + $filter_fields[strtolower($col)] = true; + if(!empty($params['related_fields'])) { + foreach($params['related_fields'] as $field) { + //id column is added by query construction function. This addition creates duplicates + //and causes issues in oracle. #10165 + if ($field != 'id') { + $filter_fields[$field] = true; + } + } + } + if(!empty($params['default']) && $params['default']) + $displayColumns[$col] = $params; + } + $popup->displayColumns = $displayColumns; + $popup->filter_fields = $filter_fields; + $popup->mergeDisplayColumns = true; + //check to see if popupdes contains searchdefs + $popup->_popupMeta = $popupMeta; + $popup->listviewdefs = $listViewDefs; + $popup->searchdefs = $searchdefs; + + if(isset($_REQUEST['query'])){ + $popup->searchForm->populateFromRequest(); + } + + $massUpdateData = ''; + if(isset($_REQUEST['mass'])) { + foreach(array_unique($_REQUEST['mass']) as $record) { + $massUpdateData .= "\n"; + } + } + $popup->massUpdateData = $massUpdateData; + + $popup->setup('include/Popups/tpls/PopupGeneric.tpl'); + + insert_popup_header(); + echo $popup->display(); + + }else{ + if(file_exists('modules/' . $this->module . '/Popup_picker.php')){ + require_once('modules/' . $this->module . '/Popup_picker.php'); + }else{ + require_once('include/Popups/Popup_picker.php'); + } + + $popup = new Popup_Picker(); + $popup->_hide_clear_button = true; + echo $popup->process_page(); + } + } +} +?> \ No newline at end of file diff --git a/include/MVC/View/views/view.quick.php b/include/MVC/View/views/view.quick.php new file mode 100644 index 00000000..88f1ddfc --- /dev/null +++ b/include/MVC/View/views/view.quick.php @@ -0,0 +1,68 @@ +options['show_subpanels'] = false; + $this->options['show_title'] = false; + $this->options['show_header'] = false; + $this->options['show_footer'] = false; + $this->options['show_javascript'] = false; + } + + function display(){ + $this->dv->showVCRControl = false; + $this->dv->th->ss->assign('hideHeader', true); + if(empty($this->bean->id)){ + global $app_strings; + sugar_die($app_strings['ERROR_NO_RECORD']); + } + $this->dv->process(); + ob_clean(); + echo json_encode(array('title'=> $this->bean->name, 'url'=>'index.php?module=' . $this->bean->module_dir . '&action=DetailView&record=' . $this->bean->id ,'html'=> $this->dv->display(false))); + } +} diff --git a/include/MVC/View/views/view.quickcreate.php b/include/MVC/View/views/view.quickcreate.php new file mode 100644 index 00000000..ab364e9b --- /dev/null +++ b/include/MVC/View/views/view.quickcreate.php @@ -0,0 +1,168 @@ +bean = loadBean($_REQUEST['source_module']); + if ( $this->bean instanceOf SugarBean + && !in_array($this->bean->object_name,array('EmailMan')) ) { + $this->bean->retrieve($_REQUEST['record']); + if(!empty($this->bean->id))$_REQUEST['parent_id'] = $this->bean->id; + if(!empty($this->bean->module_dir))$_REQUEST['parent_type'] = $this->bean->module_dir; + if(!empty($this->bean->name))$_REQUEST['parent_name'] = $this->bean->name; + if(!empty($this->bean->id))$_REQUEST['return_id'] = $this->bean->id; + if(!empty($this->bean->module_dir))$_REQUEST['return_module'] = $this->bean->module_dir; + + //Now preload any related fields + if(isset($_REQUEST['module'])) { + $target_bean = loadBean($_REQUEST['module']); + foreach($target_bean->field_defs as $fields) { + if($fields['type'] == 'relate' && isset($fields['module']) && $fields['module'] == $_REQUEST['source_module'] && isset($fields['rname'])) { + $rel_name = $fields['rname']; + if(isset($this->bean->$rel_name)) { + $_REQUEST[$fields['name']] = $this->bean->$rel_name; + } + if(!empty($_REQUEST['record']) && !empty($fields['id_name'])) { + $_REQUEST[$fields['id_name']] = $_REQUEST['record']; + } + } + } + } + } + $this->_isDCForm = true; + } + } + + /** + * @see SugarView::display() + */ + public function display() + { + $view = (!empty($_REQUEST['target_view']))?$_REQUEST['target_view']: 'QuickCreate'; + $module = $_REQUEST['module']; + + // locate the best viewdefs to use: 1. custom/module/quickcreatedefs.php 2. module/quickcreatedefs.php 3. custom/module/editviewdefs.php 4. module/editviewdefs.php + $base = 'modules/' . $module . '/metadata/'; + $source = 'custom/' . $base . strtolower($view) . 'defs.php'; + if (!file_exists( $source)) + { + $source = $base . strtolower($view) . 'defs.php'; + if (!file_exists($source)) + { + //if our view does not exist default to EditView + $view = 'EditView'; + $source = 'custom/' . $base . 'editviewdefs.php'; + if (!file_exists($source)) + { + $source = $base . 'editviewdefs.php'; + } + } + } + + $this->ev = new EditView(); + $this->ev->view = $view; + $this->ev->ss = new Sugar_Smarty(); + + $this->ev->ss->assign('isDCForm', $this->_isDCForm); + //$_REQUEST['return_action'] = 'SubPanelViewer'; + $this->ev->setup($module, null, $source); + $this->ev->showSectionPanelsTitles = false; + $this->ev->defs['templateMeta']['form']['headerTpl'] = 'include/EditView/header.tpl'; + $this->ev->defs['templateMeta']['form']['footerTpl'] = 'include/EditView/footer.tpl'; + $this->ev->defs['templateMeta']['form']['buttons'] = array('DCMENUSAVE', 'DCMENUCANCEL', 'DCMENUFULLFORM'); + $this->ev->defs['templateMeta']['form']['button_location'] = 'bottom'; + $this->ev->defs['templateMeta']['form']['hidden'] = ''; + $this->ev->defs['templateMeta']['form']['hidden'] .= ''; + $defaultProcess = true; + if(file_exists('modules/'.$module.'/views/view.edit.php')) { + include('modules/'.$module.'/views/view.edit.php'); + $c = $module . 'ViewEdit'; + + if(class_exists($c)) { + $view = new $c; + if($view->useForSubpanel) { + $defaultProcess = false; + + //Check if we shold use the module's QuickCreate.tpl file + if($view->useModuleQuickCreateTemplate && file_exists('modules/'.$module.'/tpls/QuickCreate.tpl')) { + $this->ev->defs['templateMeta']['form']['headerTpl'] = 'modules/'.$module.'/tpls/QuickCreate.tpl'; + } + + $view->ev = & $this->ev; + $view->ss = & $this->ev->ss; + $class = $GLOBALS['beanList'][$module]; + if(!empty($GLOBALS['beanFiles'][$class])){ + require_once($GLOBALS['beanFiles'][$class]); + $bean = new $class(); + $view->bean = $bean; + } + $view->ev->formName = 'form_DC'.$view->ev->view .'_'.$module; + $view->showTitle = false; // Do not show title since this is for subpanel + $view->display(); + } + } + } //if + + if($defaultProcess) { + $form_name = 'form_DC'.$this->ev->view .'_'.$module; + $this->ev->formName = $form_name; + $this->ev->process(true, $form_name); + echo $this->ev->display(false, true); + } + } +} \ No newline at end of file diff --git a/include/MVC/View/views/view.serialized.php b/include/MVC/View/views/view.serialized.php new file mode 100644 index 00000000..047a35ce --- /dev/null +++ b/include/MVC/View/views/view.serialized.php @@ -0,0 +1,49 @@ +bean->toArray()); + sugar_cleanup(true); + } +} +?> diff --git a/include/MVC/View/views/view.sugarpdf.config.php b/include/MVC/View/views/view.sugarpdf.config.php new file mode 100644 index 00000000..43763311 --- /dev/null +++ b/include/MVC/View/views/view.sugarpdf.config.php @@ -0,0 +1,56 @@ + array( + 'sugarpdf' => array( + 'show_header' => false, + 'show_subpanels' => false, + 'show_search' => false, + 'show_footer' => false, + 'show_javascript' => false, + ), + ), + 'req_params' => array( + 'to_pdf' => array( + 'param_value' => true, + 'config' => array('show_all' => false), + ), + ), +); +?> \ No newline at end of file diff --git a/include/MVC/View/views/view.sugarpdf.php b/include/MVC/View/views/view.sugarpdf.php new file mode 100644 index 00000000..1c3764b7 --- /dev/null +++ b/include/MVC/View/views/view.sugarpdf.php @@ -0,0 +1,86 @@ +sugarpdf = $_REQUEST["sugarpdf"]; + else + header('Location:index.php?module='.$_REQUEST['module'].'&action=DetailView&record='.$_REQUEST['record']); + } + + function preDisplay(){ + $this->sugarpdfBean = SugarpdfFactory::loadSugarpdf($this->sugarpdf, $this->module, $this->bean, $this->view_object_map); + + // ACL control + if(!empty($this->bean) && !$this->bean->ACLAccess($this->sugarpdfBean->aclAction)){ + ACLController::displayNoAccess(true); + sugar_cleanup(true); + } + + if(isset($this->errors)){ + $this->sugarpdfBean->errors = $this->errors; + } + } + + function display(){ + $this->sugarpdfBean->process(); + $this->sugarpdfBean->Output($this->sugarpdfBean->fileName,'I'); + } + +} +?> diff --git a/include/MVC/View/views/view.vcard.php b/include/MVC/View/views/view.vcard.php new file mode 100644 index 00000000..808db257 --- /dev/null +++ b/include/MVC/View/views/view.vcard.php @@ -0,0 +1,62 @@ +loadContact($this->bean->id, $this->module); + $vcard->saveVCard(); + } +} +?> diff --git a/include/MVC/View/views/view.xml.php b/include/MVC/View/views/view.xml.php new file mode 100644 index 00000000..0d8f6328 --- /dev/null +++ b/include/MVC/View/views/view.xml.php @@ -0,0 +1,47 @@ + diff --git a/include/MassUpdate.php b/include/MassUpdate.php new file mode 100644 index 00000000..58de6c39 --- /dev/null +++ b/include/MassUpdate.php @@ -0,0 +1,1277 @@ +sugarbean = $sugar; + } + + /** + * get the massupdate form + * @param bool boolean need to execute the massupdate form or not + * @param multi_select_popup booleanif it is a multi-select value + */ + function getDisplayMassUpdateForm($bool, $multi_select_popup = false) + { + + require_once('include/formbase.php'); + + if(!$multi_select_popup) + $form = '
' . "\n"; + else + $form = '' . "\n"; + + if($bool) + { + $form .= '' . "\n"; + } + else + { + $form .= '' . "\n"; + } + + $form .= getAnyToForm('mu', true); + if(!$multi_select_popup) $form .= "\n"; + + return $form; + } + /** + * returns the mass update's html form header + * @param multi_select_popup boolean if it is a mult-select or not + */ + function getMassUpdateFormHeader($multi_select_popup = false) + { + global $sugar_version; + global $sugar_config; + global $current_user; + + unset($_REQUEST['current_query_by_page']); + $query = base64_encode(serialize(array_merge($_POST, $_GET))); + + $bean = loadBean($_REQUEST['module']); + $order_by_name = $bean->module_dir.'2_'.strtoupper($bean->object_name).'_ORDER_BY' ; + $lvso = isset($_REQUEST['lvso'])?$_REQUEST['lvso']:""; + $request_order_by_name = isset($_REQUEST[$order_by_name])?$_REQUEST[$order_by_name]:""; + $action = isset($_REQUEST['action'])?$_REQUEST['action']:""; + $module = isset($_REQUEST['module'])?$_REQUEST['module']:""; + if($multi_select_popup) + $tempString = ''; + else + $tempString = "
\n" + . "\n" + . "\n" + . "\n" + . "\n" + . "\n" + . "\n" + . "\n" + . "\n" + . "\n" + . "\n"; + + // cn: bug 9103 - MU navigation in emails is broken + if($_REQUEST['module'] == 'Emails') { + $type = ""; + // determine "type" - inbound, archive, etc. + if (isset($_REQUEST['type'])) { + $type = $_REQUEST['type']; + } + // determine owner + $tempString .=<< + +eoq; + } + + return $tempString; + } + + /** + * Executes the massupdate form + * @param displayname Name to display in the popup window + * @param varname name of the variable + */ + function handleMassUpdate(){ + + require_once('include/formbase.php'); + global $current_user, $db, $disable_date_format; + + //We need to disable_date_format so that date values for the beans remain in database format + $disable_date_format = true; + + foreach($_POST as $post=>$value){ + if(is_array($value)){ + if(empty($value)){ + unset($_POST[$post]); + } + }elseif(strlen($value) == 0){ + if( isset($this->sugarbean->field_defs[$post]) && $this->sugarbean->field_defs[$post]['type'] == 'radioenum' && isset($_POST[$post]) ){ + $_POST[$post] = ''; + }else{ + unset($_POST[$post]); + } + } + if(is_string($value) + && isset($this->sugarbean->field_defs[$post]) && + ($this->sugarbean->field_defs[$post]['type'] == 'bool' + || (!empty($this->sugarbean->field_defs[$post]['custom_type']) && $this->sugarbean->field_defs[$post]['custom_type'] == 'bool' + ))){ + + + if(strcmp($value, '2') == 0)$_POST[$post] = 0; + if(!empty($this->sugarbean->field_defs[$post]['dbType']) && strcmp($this->sugarbean->field_defs[$post]['dbType'], 'varchar') == 0 ){ + if(strcmp($value, '1') == 0 )$_POST[$post] = 'on'; + if(strcmp($value, '2') == 0)$_POST[$post] = 'off'; + } + } + if(is_string($value) + && isset($this->sugarbean->field_defs[$post]) && $this->sugarbean->field_defs[$post]['type'] == 'radioenum' && isset($_POST[$post]) && strlen($value) == 0){ + $_POST[$post] = ''; + } + } + + if(!empty($_REQUEST['uid'])) $_POST['mass'] = explode(',', $_REQUEST['uid']); // coming from listview + elseif(isset($_REQUEST['entire']) && empty($_POST['mass'])) { + if(empty($order_by))$order_by = ''; + $ret_array = create_export_query_relate_link_patch($_REQUEST['module'], $this->searchFields, $this->where_clauses); + if(!isset($ret_array['join'])) { + $ret_array['join'] = ''; + } + $query = $this->sugarbean->create_export_query($order_by, $ret_array['where'], $ret_array['join']); + $result = $db->query($query,true); + $new_arr = array(); + while($val = $db->fetchByAssoc($result,-1,false)) + { + array_push($new_arr, $val['id']); + } + $_POST['mass'] = $new_arr; + } + + if(isset($_POST['mass']) && is_array($_POST['mass']) && $_REQUEST['massupdate'] == 'true'){ + $count = 0; + + + foreach($_POST['mass'] as $id){ + if(empty($id)) { + continue; + } + if(isset($_POST['Delete'])){ + $this->sugarbean->retrieve($id); + if($this->sugarbean->ACLAccess('Delete')){ + //Martin Hu Bug #20872 + if($this->sugarbean->object_name == 'EmailMan'){ + $query = "DELETE FROM emailman WHERE id = '" . $this->sugarbean->id . "'"; + $db->query($query); + } else { + + $this->sugarbean->mark_deleted($id); + } + } + } + else { + if($this->sugarbean->object_name == 'Contact' && isset($_POST['Sync'])){ // special for contacts module + if($_POST['Sync'] == 'true') { + $this->sugarbean->retrieve($id); + if($this->sugarbean->ACLAccess('Save')){ + if($this->sugarbean->object_name == 'Contact'){ + + $this->sugarbean->contacts_users_id = $current_user->id; + $this->sugarbean->save(false); + } + } + } + elseif($_POST['Sync'] == 'false') { + $this->sugarbean->retrieve($id); + if($this->sugarbean->ACLAccess('Save')){ + if($this->sugarbean->object_name == 'Contact'){ + if (!isset($this->sugarbean->users)) + { + $this->sugarbean->load_relationship('user_sync'); + } + $this->sugarbean->contacts_users_id = null; + $this->sugarbean->user_sync->delete($this->sugarbean->id, $current_user->id); + } + } + } + } //end if for special Contact handling + + if($count++ != 0) { + //Create a new instance to clear values and handle additional updates to bean's 2,3,4... + $className = get_class($this->sugarbean); + $this->sugarbean = new $className(); + } + + $this->sugarbean->retrieve($id); + + foreach($_POST as $field=>$value){ + if (isset($this->sugarbean->field_defs[$field])) { + if($this->sugarbean->field_defs[$field]['type'] == 'datetime') { + $_POST[$field] = $this->date_to_dateTime($field, $value); + } + if($this->sugarbean->field_defs[$field]['type'] == 'datetimecombo') { + if(!empty($_POST[$field]) && strlen($_POST[$field]) > 10 ){ + $dateValue = $_POST[$field]; + $_POST[$field] = $dateValue; + }else{ + unset($_POST[$field]); + } + } + if ($this->sugarbean->field_defs[$field]['type'] == 'bool') { + $this->checkClearField($field, $value); + } + } + } + + + if($this->sugarbean->ACLAccess('Save')){ + $_POST['record'] = $id; + $_GET['record'] = $id; + $_REQUEST['record'] = $id; + $newbean=$this->sugarbean; + + $old_reports_to_id = null; + if(!empty($_POST['reports_to_id']) && $newbean->reports_to_id != $_POST['reports_to_id']) { + $old_reports_to_id = empty($newbean->reports_to_id) ? 'null' : $newbean->reports_to_id; + } + + $check_notify = FALSE; + + if (isset( $this->sugarbean->assigned_user_id)) { + $old_assigned_user_id = $this->sugarbean->assigned_user_id; + if (!empty($_POST['assigned_user_id']) + && ($old_assigned_user_id != $_POST['assigned_user_id']) + && ($_POST['assigned_user_id'] != $current_user->id)) { + $check_notify = TRUE; + } + } + + //Call include/formbase.php, but do not call retrieve again + populateFromPost('', $newbean, true); + $newbean->save_from_post = false; + + if (!isset($_POST['parent_id'])) { + $newbean->parent_type = null; + } + + $email_address_id = ''; + if (!empty($_POST['optout_primary'])) { + $optout_flag_value = 0; + if ($_POST['optout_primary'] == 'true') { + $optout_flag_value = 1; + } // if + if (isset($this->sugarbean->emailAddress)) { + if (!empty($this->sugarbean->emailAddress->addresses)) { + foreach($this->sugarbean->emailAddress->addresses as $key =>$emailAddressRow) { + if ($emailAddressRow['primary_address'] == '1') { + $email_address_id = $emailAddressRow['email_address_id']; + break; + } // if + } // foreach + } // if + + } // if + } // if + + + $newbean->save($check_notify); + if (!empty($email_address_id)) { + $query = "UPDATE email_addresses SET opt_out = {$optout_flag_value} where id = '{$emailAddressRow['email_address_id']}'"; + $GLOBALS['db']->query($query); + + } // if + + if(!empty($old_reports_to_id) && method_exists($newbean, 'update_team_memberships')) { + $old_id = $old_reports_to_id == 'null' ? '' : $old_reports_to_id; + } + } + } + } + + } + + } + /** + * Displays the massupdate form + */ + function getMassUpdateForm( + $hideDeleteIfNoFieldsAvailable = false + ) + { + global $app_strings; + global $current_user; + + if($this->sugarbean->bean_implements('ACL') && !ACLController::checkAccess($this->sugarbean->module_dir, 'edit', true)){ + return ''; + } + $lang_delete = translate('LBL_DELETE'); + $lang_update = translate('LBL_UPDATE'); + $lang_confirm= translate('NTC_DELETE_CONFIRMATION_MULTIPLE'); + $lang_sync = translate('LBL_SYNC_CONTACT'); + $lang_oc_status = translate('LBL_OC_STATUS'); + $lang_unsync = translate('LBL_UNSYNC'); + $lang_archive = translate('LBL_ARCHIVE'); + $lang_optout_primaryemail = $app_strings['LBL_OPT_OUT_FLAG_PRIMARY']; + + + +// if(!isset($this->sugarbean->field_defs) || count($this->sugarbean->field_defs) == 0) { +// $html = "
"; + if ($subpanel_def != null) { + include_once('include/SubPanel/SubPanelTiles.php'); + $subpanelTiles = new SubPanelTiles($sugarbean); + $html_text .= "\n"; + $html_text .= "\n"; + $this->xTemplate->assign("PAGINATION",$html_text); + } + + //C.L. - Fix for 23461 + if(empty($_REQUEST['action']) || $_REQUEST['action'] != 'Popup') { + $_SESSION['export_where'] = $this->query_where; + } + $this->xTemplate->parse($xtemplateSection.".list_nav_row"); + } + } // end processListNavigation + + function processOrderBy($html_varName) { + + if(!isset($this->base_URL)) { + $this->base_URL = $_SERVER['PHP_SELF']; + + if(isset($_SERVER['QUERY_STRING'])) { + $this->base_URL = preg_replace("/\&".$this->getSessionVariableName($html_varName,"ORDER_BY")."=[0-9a-zA-Z\_\.]*/","",$this->base_URL .'?'.$_SERVER['QUERY_STRING']); + $this->base_URL = preg_replace("/\&".$this->getSessionVariableName($html_varName,"offset")."=[0-9]*/","",$this->base_URL); + } + if($_SERVER['REQUEST_METHOD'] == 'POST') { + $this->base_URL .= '?'; + if(isset($_REQUEST['action'])) $this->base_URL .= '&action='.$_REQUEST['action']; + if(isset($_REQUEST['record'])) $this->base_URL .= '&record='.$_REQUEST['record']; + if(isset($_REQUEST['module'])) $this->base_URL .= '&module='.$_REQUEST['module']; + } + $this->base_URL .= "&".$this->getSessionVariableName($html_varName,"offset")."="; + } + + if($this->is_dynamic) { + $this->base_URL.='&to_pdf=true&action=SubPanelViewer&subpanel=' . $this->source_module; + } + + $sort_URL_base = $this->base_URL. "&".$this->getSessionVariableName($html_varName,"ORDER_BY")."="; + + if($sort_URL_base !== "") + { + $this->xTemplate->assign("ORDER_BY", $sort_URL_base); + return $sort_URL_base; + } else { + return ''; + } + } + + + function getAdditionalHeader() { + + } + + + /** + * @return void + * @param unknown $data + * @param unknown $xTemplateSection + * @param unknown $html_varName + * @desc INTERNAL FUNCTION handles the rows + * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc. + * All Rights Reserved. + * Contributor(s): ______________________________________.. + */ + function processListRows($data, $xtemplateSection, $html_varName) + { + global $odd_bg; + global $even_bg; + global $hilite_bg; + global $app_strings, $sugar_version, $sugar_config; + global $currentModule; + + static $overlib_included; + if(!$overlib_included) { + echo ' + '; + $overlib_included = true; + } + + + $this->xTemplate->assign('BG_HILITE', $hilite_bg); + $this->xTemplate->assign('CHECKALL', "\"\""); + //$this->xTemplate->assign("BG_CLICK", $click_bg); + $oddRow = true; + $count = 0; + reset($data); + + //GETTING OFFSET + $offset = $this->getOffset($html_varName); + $timeStamp = $this->unique_id(); + $_SESSION[$html_varName."_FROM_LIST_VIEW"] = $timeStamp; + + $associated_row_data = array(); + + //mail merge list + $mergeList = array(); + $module = ''; + //todo what is this? It is using an array as a boolean + while(list($aVal, $aItem) = each($data)) + { + if(isset($this->data_array)) { + $fields = $this->data_array; + } else { + $aItem->check_date_relationships_load(); + $fields = $aItem->get_list_view_data(); + } + + if(is_object($aItem)) { // cn: bug 5349 + //add item id to merge list, if the button is clicked + $mergeList[] = $aItem->id; + if(empty($module)) { + $module = $aItem->module_dir; + } + } + //ADD OFFSET TO ARRAY + + $fields['OFFSET'] = ($offset + $count + 1); + + $fields['STAMP'] = $timeStamp; + if($this->shouldProcess) { + + $prerow = ''; + if(!isset($this->data_array)) { + $prerow .= ""; + } + $this->xTemplate->assign('PREROW', $prerow); + + $this->xTemplate->assign('CHECKALL', ""); + } + if(!isset($this->data_array)) { + $tag = $aItem->listviewACLHelper(); + $this->xTemplate->assign('TAG',$tag) ; + } + + if($oddRow) + { + $ROW_COLOR = 'oddListRow'; + $BG_COLOR = $odd_bg; + } + else + { + $ROW_COLOR = 'evenListRow'; + $BG_COLOR = $even_bg; + } + $oddRow = !$oddRow; + + $this->xTemplate->assign('ROW_COLOR', $ROW_COLOR); + $this->xTemplate->assign('BG_COLOR', $BG_COLOR); + + if(isset($this->data_array)) + { + $this->xTemplate->assign('KEY', $aVal); + $this->xTemplate->assign('VALUE', $aItem); + $this->xTemplate->assign('INDEX', $count); + + } + else + { + //AED -- some modules do not have their additionalDetails.php established. Add a check to ensure require_once does not fail + // Bug #2786 + if($this->_additionalDetails && $aItem->ACLAccess('DetailView') && (file_exists('modules/' . $aItem->module_dir . '/metadata/additionalDetails.php') || file_exists('custom/modules/' . $aItem->module_dir . '/metadata/additionalDetails.php'))) { + + $additionalDetailsFile = 'modules/' . $aItem->module_dir . '/metadata/additionalDetails.php'; + if(file_exists('custom/modules/' . $aItem->module_dir . '/metadata/additionalDetails.php')){ + $additionalDetailsFile = 'custom/modules/' . $aItem->module_dir . '/metadata/additionalDetails.php'; + } + + require_once($additionalDetailsFile); + $ad_function = (empty($this->additionalDetailsFunction) ? 'additionalDetails' : $this->additionalDetailsFunction) . $aItem->object_name; + $results = $ad_function($fields); + $results['string'] = str_replace(array("'", "'"), '\'', $results['string']); // no xss! + + if(trim($results['string']) == '') $results['string'] = $app_strings['LBL_NONE']; + $fields[$results['fieldToAddTo']] = $fields[$results['fieldToAddTo']].''; + } + //fixes bug for IE where empty list view rows causes IE to not display bottom border + if(isset($fields['DESCRIPTION']) && empty($fields['DESCRIPTION'])) + $fields['DESCRIPTION'] = " "; + if(isset($fields['LIST_ORDER']) && empty($fields['LIST_ORDER'])) + $fields['LIST_ORDER'] = " "; + + $this->xTemplate->assign($html_varName, $fields); + $aItem->setupCustomFields($aItem->module_dir); + $aItem->custom_fields->populateAllXTPL($this->xTemplate, 'detail', $html_varName, $fields); + } + if(!isset($this->data_array) && $aItem->ACLAccess('DetailView')) { + $count++; + } + if(isset($this->data_array)) { + $count++; + } + if(!isset($this->data_array)) { + $aItem->list_view_parse_additional_sections($this->xTemplate, $xtemplateSection); + + if($this->xTemplate->exists($xtemplateSection.'.row.pro')) { + $this->xTemplate->parse($xtemplateSection.'.row.pro'); + } + } + $this->xTemplate->parse($xtemplateSection . '.row'); + + if(isset($fields['ID'])) { + $associated_row_data[$fields['ID']] = $fields; + // Bug 38908: cleanup data for JS to avoid having   shuffled around + foreach($fields as $key => $value) { + if($value == ' ') { + $associated_row_data[$fields['ID']][$key] = ''; + } + } + } + } + + $_SESSION['MAILMERGE_RECORDS'] = $mergeList; + $_SESSION['MAILMERGE_MODULE_FROM_LISTVIEW'] = $module; + if(empty($_REQUEST['action']) || $_REQUEST['action'] != 'Popup') { + $_SESSION['MAILMERGE_MODULE'] = $module; + } + + if($this->process_for_popups) + { + $json = getJSONobj(); + $is_show_fullname = showFullName() ? 1 : 0; + $associated_javascript_data = ''; + $this->xTemplate->assign('ASSOCIATED_JAVASCRIPT_DATA', $associated_javascript_data); + } + + $this->xTemplate->parse($xtemplateSection); + } + + + function getLayoutManager() + { + require_once('include/generic/LayoutManager.php'); + if($this->layout_manager == null) + { + $this->layout_manager = new LayoutManager(); + } + return $this->layout_manager; + } + + + function process_dynamic_listview_header($source_module, $subpanel_def, $html_var = 'CELL') + { + + + $layout_manager = $this->getLayoutManager(); + $layout_manager->setAttribute('order_by_link',$this->processOrderBy($html_var)); + $layout_manager->setAttribute('context','HeaderCell'); + $layout_manager->setAttribute('image_path',$this->local_image_path); + $layout_manager->setAttribute('html_varName',$html_var); + $layout_manager->setAttribute('module_name', $source_module); + list($orderBy,$desc) = $this->getOrderByInfo($html_var); + + if($orderBy == 'amount*1') + { + $orderBy= 'amount'; + } + + foreach($subpanel_def->get_list_fields() as $column_name=>$widget_args) + { + $usage = empty($widget_args['usage']) ? '' : $widget_args['usage']; + if($usage != 'query_only') + { + $imgArrow = ''; + + if($orderBy == $column_name || (isset($widget_args['sort_by']) && str_replace('.','_',$widget_args['sort_by']) == $orderBy)) + { + $imgArrow = "_down"; + if($this->sort_order == 'desc') { + $imgArrow = "_up"; + } + } + $widget_args['name']=$column_name; + $widget_args['sort'] = $imgArrow; + $widget_args['start_link_wrapper'] = $this->start_link_wrapper; + $widget_args['end_link_wrapper'] = $this->end_link_wrapper; + $widget_args['subpanel_module'] = $this->subpanel_module; + + $widget_contents = $layout_manager->widgetDisplay($widget_args); + $cell_width = empty($widget_args['width']) ? '' : $widget_args['width']; + $this->xTemplate->assign('HEADER_CELL', $widget_contents); + static $count; + if(!isset($count))$count = 0; else $count++; + $this->xTemplate->assign('CELL_COUNT', $count); + $this->xTemplate->assign('CELL_WIDTH', $cell_width); + $this->xTemplate->parse('dyn_list_view.header_cell'); + } + } + + } + + + /** + * @return void + * @param unknown $seed + * @param unknown $xTemplateSection + * @param unknown $html_varName + * @desc PUBLIC FUNCTION Handles List Views using seeds that extend SugarBean + $XTemplateSection is the section in the XTemplate file that should be parsed usually main + $html_VarName is the variable name used in the XTemplateFile e.g. TASK + $seed is a seed there are two types of seeds one is a subclass of SugarBean, the other is a list usually created from a sugar bean using get_list + if no XTemplate is set it will create a new XTemplate + * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.. + * All Rights Reserved.. + * Contributor(s): ______________________________________.. + */ + + function processListViewTwo($seed, $xTemplateSection, $html_varName) { + global $current_user; + if(!isset($this->xTemplate)) { + $this->createXTemplate(); + } + + $isSugarBean = is_subclass_of($seed, "SugarBean"); + $list = null; + + if($isSugarBean) { + $list = $this->processSugarBean($xTemplateSection, $html_varName, $seed); + } else { + $list = $seed; + } + + if (is_object($seed) && isset($seed->object_name) && $seed->object_name == 'WorkFlow') { + $tab=array(); + $access = get_workflow_admin_modules_for_user($current_user); + for ($i = 0; $i < count($list); $i++) { + if(!empty($access[$list[$i]->base_module])){ + $tab[]=$list[$i]; + } + } + $list = $tab; + } + + if($this->is_dynamic) { + $this->processHeaderDynamic($xTemplateSection,$html_varName); + $this->processListRows($list,$xTemplateSection, $html_varName); + } else { + $this->processSortArrows($html_varName); + + if($isSugarBean) { + $seed->parse_additional_headers($this->xTemplate, $xTemplateSection); + } + $this->xTemplateAssign('CHECKALL', ""); + + // Process the order by before processing the pro_nav. The pro_nav requires the order by values to be set + $this->processOrderBy($html_varName); + + + $this->processListRows($list,$xTemplateSection, $html_varName); + } + + if($this->display_header_and_footer) { + $this->getAdditionalHeader(); + if(!empty($this->header_title)) { + echo get_form_header($this->header_title, $this->header_text, false); + } + } + + $this->xTemplate->out($xTemplateSection); + + if(isset($_SESSION['validation'])) { + print base64_decode('PGEgaHJlZj0naHR0cDovL3d3dy5zdWdhcmNybS5jb20nPlBPV0VSRUQmbmJzcDtCWSZuYnNwO1NVR0FSQ1JNPC9hPg=='); + } + } + + function getArrowStart() { + $imgFileParts = pathinfo(SugarThemeRegistry::current()->getImageURL("arrow.gif")); + + return " pngSupport ? "png" : "gif" ); + + if (!isset($upDown) || empty($upDown)) { + $upDown = ""; + } + return " getImageURL("arrow.gif")); + + list($width,$height) = ListView::getArrowImageSize(); + return '.'.$imgFileParts['extension']."' width='$width' height='$height' align='absmiddle' alt=".translate('LBL_SORT').">"; + } + + function getArrowImageSize() { + // just get the non-sort image's size.. the up and down have be the same. + $image = SugarThemeRegistry::current()->getImageURL("arrow.gif",false); + + $cache_key = 'arrow_size.'.$image; + + // Check the cache + $result = sugar_cache_retrieve($cache_key); + if(!empty($result)) + return $result; + + // No cache hit. Calculate the value and return. + $result = getimagesize($image); + sugar_cache_put($cache_key, $result); + return $result; + } + + function getOrderByInfo($html_varName) + { + $orderBy = $this->getSessionVariable($html_varName, "OBL"); + $desc = $this->getSessionVariable($html_varName, $orderBy.'S'); + $orderBy = str_replace('.', '_', $orderBy); + return array($orderBy,$desc); + } + + function processSortArrows($html_varName) + { + + $this->xTemplateAssign("arrow_start", $this->getArrowStart()); + + list($orderBy,$desc) = $this->getOrderByInfo($html_varName); + + $imgArrow = "_down"; + if($desc) { + $imgArrow = "_up"; + } + + if($orderBy == 'amount*1') + { + $this->xTemplateAssign('amount_arrow', $imgArrow); + } + else if($orderBy == 'amount_usdollar*1') + { + $this->xTemplateAssign('amount_usdollar_arrow', $imgArrow); + } + else + { + $this->xTemplateAssign($orderBy.'_arrow', $imgArrow); + } + + $this->xTemplateAssign('arrow_end', $this->getArrowEnd()); + } + + // this is where translation happens for dynamic list views + function loadListFieldDefs(&$subpanel_fields,&$child_focus) + { + $this->list_field_defs = $subpanel_fields; + + for($i=0;$i < count($this->list_field_defs);$i++) + { + $list_field = $this->list_field_defs[$i]; + $field_def = null; + $key = ''; + if(!empty($list_field['vname'])) + { + $key = $list_field['vname']; + } else if(isset($list_field['name']) && isset($child_focus->field_defs[$list_field['name']])) + { + $field_def = $child_focus->field_defs[$list_field['name']]; + $key = $field_def['vname']; + } + if(!empty($key)) + { + $list_field['label'] = translate($key,$child_focus->module_dir); + $this->list_field_defs[$i]['label'] = preg_replace('/:$/','',$list_field['label']); + } + else + { + $this->list_field_defs[$i]['label'] =' '; + } + } + } + + function unique_id() { + return sugar_microtime(); + } + + /**INTERNAL FUNCTION sets a session variable keeping it local to the listview + not the current_module + * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc. + * All Rights Reserved. + * Contributor(s): ______________________________________. + */ + function setLocalSessionVariable($localVarName,$varName, $value) { + $_SESSION[$localVarName."_".$varName] = $value; + } + + /**INTERNAL FUNCTION returns a session variable that is local to the listview, + not the current_module + * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc. + * All Rights Reserved. + * Contributor(s): ______________________________________. + */ + function getLocalSessionVariable($localVarName,$varName) { + if(isset($_SESSION[$localVarName."_".$varName])) { + return $_SESSION[$localVarName."_".$varName]; + } + else{ + return ""; + } + } + + /* Set to true if you want Additional Details to appear in the listview + */ + function setAdditionalDetails($value = true, $function = '') { + if(!empty($function)) $this->additionalDetailsFunction = $function; + $this->_additionalDetails = $value; + } + +} +?> diff --git a/include/ListView/ListViewDCMenu.tpl b/include/ListView/ListViewDCMenu.tpl new file mode 100644 index 00000000..d28de352 --- /dev/null +++ b/include/ListView/ListViewDCMenu.tpl @@ -0,0 +1,189 @@ + {* + +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + + + +*} + + +
"; + + //attempt to get the query to recreate this subpanel + if(!empty($this->response)){ + $response =& $this->response; + }else{ + $response = SugarBean::get_union_related_list($sugarbean,$this->sortby, $this->sort_order, $this->query_where, $current_offset, -1,-1,$this->query_limit,$subpanel_def); + $this->response = $response; + } + //if query is present, then pass it in as parameter + if (isset($response['query']) && !empty($response['query'])){ + $html_text .= $subpanelTiles->get_buttons($subpanel_def, $response['query']); + }else{ + $html_text .= $subpanelTiles->get_buttons($subpanel_def); + } + } + else { + $html_text .= "\n
$select_link $export_link $delete_link $selected_objects_span"; + } + $html_text .= "".$start_link."  ".$previous_link."  (".$start_record." - ".$end_record." ".$this->local_app_strings['LBL_LIST_OF']." ".$row_count.")  ".$next_link."  ".$end_link."
\n"; + $html_text .= "
+ + + + +
+ + + +
+ + + + {if $prerow} + + {/if} + {if $favorites} + + {/if} + {if !empty($quickViewLinks)} + + {/if} + {counter start=0 name="colCounter" print=false assign="colCounter"} + {foreach from=$displayColumns key=colHeader item=params} + + {counter name="colCounter"} + {/foreach} + + + + {counter start=$pageData.offsets.current print=false assign="offset" name="offset"} + {foreach name=rowIteration from=$data key=id item=rowData} + {counter name="offset" print=false} + + {if $smarty.foreach.rowIteration.iteration is odd} + {assign var='_rowColor' value=$rowColor[0]} + {else} + {assign var='_rowColor' value=$rowColor[1]} + {/if} + + {if $prerow} + + {/if} + {if $favorites} + + {/if} + {if !empty($quickViewLinks)} + + {/if} + {counter start=0 name="colCounter" print=false assign="colCounter"} + {foreach from=$displayColumns key=col item=params} + {strip} + + {/strip} + {counter name="colCounter"} + {/foreach} + + {foreachelse} + + + + {/foreach} +
+
+ + {$selectLink} +
+
+   +   +
+ {if false} + {if $params.url_sort} + + {else} + {if $params.orderBy|default:$colHeader|lower == $pageData.ordering.orderBy} + + {else} + + {/if} + {/if} + {sugar_translate label=$params.label module=$pageData.bean.moduleDir} +    + {if $params.orderBy|default:$colHeader|lower == $pageData.ordering.orderBy} + {if $pageData.ordering.sortOrder == 'ASC'} + {capture assign="imageName"}arrow_down.{$arrowExt}{/capture} + {$arrowAlt} + {else} + {capture assign="imageName"}arrow_up.{$arrowExt}{/capture} + {$arrowAlt} + {/if} + {else} + {capture assign="imageName"}arrow.{$arrowExt}{/capture} + {$arrowAlt} + {/if} + {else} + {if !isset($params.noHeader) || $params.noHeader == false} + {sugar_translate label=$params.label module=$pageData.bean.moduleDir} + {/if} + {/if} +
+
+ {if !$is_admin && is_admin_for_user && $rowData.IS_ADMIN==1} + + {else} + + {/if} + {$rowData.star}{if $pageData.access.edit}{/if} + {if $col == 'NAME' || $params.bold}{/if} + {if $params.link && !$params.customCode} + <{$pageData.tag.$id[$params.ACLTag]|default:$pageData.tag.$id.MAIN} href='index.php?action={$params.action|default:'DetailView'}&module={if $params.dynamic_module}{$rowData[$params.dynamic_module]}{else}{$params.module|default:$pageData.bean.moduleDir}{/if}&record={$rowData[$params.id]|default:$rowData.ID}&offset={$pageData.offsets.current+$smarty.foreach.rowIteration.iteration}&stamp={$pageData.stamp}'> + {/if} + {if $params.customCode} + {sugar_evalcolumn_old var=$params.customCode rowData=$rowData} + {else} + {sugar_field parentFieldArray=$rowData vardef=$params displayType=ListView field=$col} + {/if} + {if empty($rowData.$col) && empty($params.customCode)} {/if} + {if $params.link && !$params.customCode} + + {/if} + {if $col == 'NAME' || $params.bold}{/if} +
+ {$APP.LBL_NO_DATA} +
\ No newline at end of file diff --git a/include/ListView/ListViewData.php b/include/ListView/ListViewData.php new file mode 100644 index 00000000..f3452178 --- /dev/null +++ b/include/ListView/ListViewData.php @@ -0,0 +1,577 @@ +limitName = 'list_max_entries_per_page'; + $this->db = &DBManagerFactory::getInstance('listviews'); + } + + /** + * checks the request for the order by and if that is not set then it checks the session for it + * + * @return array containing the keys orderBy => field being ordered off of and sortOrder => the sort order of that field + */ + function getOrderBy($orderBy = '', $direction = '') { + if (!empty($orderBy) || !empty($_REQUEST[$this->var_order_by])) { + if(!empty($_REQUEST[$this->var_order_by])) { + $direction = 'ASC'; + $orderBy = $_REQUEST[$this->var_order_by]; + if(!empty($_REQUEST['lvso']) && (empty($_SESSION['lvd']['last_ob']) || strcmp($orderBy, $_SESSION['lvd']['last_ob']) == 0) ){ + $direction = $_REQUEST['lvso']; + + $trackerManager = TrackerManager::getInstance(); + if($monitor = $trackerManager->getMonitor('tracker')){ + $monitor->setValue('module_name', $GLOBALS['module']); + $monitor->setValue('item_summary', "lvso=".$direction."&".$this->var_order_by."=".$_REQUEST[$this->var_order_by]); + $monitor->setValue('action', 'listview'); + $monitor->setValue('user_id', $GLOBALS['current_user']->id); + $monitor->setValue('date_modified', TimeDate::getInstance()->nowDb()); + $monitor->save(); + } + } + } + $_SESSION[$this->var_order_by] = array('orderBy'=>$orderBy, 'direction'=> $direction); + $_SESSION['lvd']['last_ob'] = $orderBy; + } + else { + if(!empty($_SESSION[$this->var_order_by])) { + $orderBy = $_SESSION[$this->var_order_by]['orderBy']; + $direction = $_SESSION[$this->var_order_by]['direction']; + } + else{ + $orderBy = 'date_entered'; + $direction = 'DESC'; + } + } + return array('orderBy' => $orderBy, 'sortOrder' => $direction); + } + + /** + * gets the reverse of the sort order for use on links to reverse a sort order from what is currently used + * + * @param STRING (ASC or DESC) $current_order + * @return STRING (ASC or DESC) + */ + function getReverseSortOrder($current_order){ + return (strcmp(strtolower($current_order), 'asc') == 0)?'DESC':'ASC'; + } + /** + * gets the limit of how many rows to show per page + * + * @return INT (the limit) + */ + function getLimit() { + return $GLOBALS['sugar_config'][$this->limitName]; + } + + /** + * returns the current offset + * + * @return INT (current offset) + */ + function getOffset() { + return (!empty($_REQUEST[$this->var_offset])) ? $_REQUEST[$this->var_offset] : 0; + } + + /** + * generates the base url without + * any files in the block variables will not be part of the url + * + * + * @return STRING (the base url) + */ + function getBaseURL() { + global $beanList; + if(empty($this->base_url)) { + $blockVariables = array('mass', 'uid', 'massupdate', 'delete', 'merge', 'selectCount',$this->var_order_by, $this->var_offset, 'lvso', 'sortOrder', 'orderBy', 'request_data', 'current_query_by_page'); + $base_url = 'index.php?'; + foreach($beanList as $bean) { + $blockVariables[] = 'Home2_'.strtoupper($bean).'_ORDER_BY'; + } + $blockVariables[] = 'Home2_CASE_ORDER_BY'; + // Added mostly for the unit test runners, which may not have these superglobals defined + $params = array(); + if ( isset($_POST) && is_array($_POST) ) { + $params = array_merge($params,$_POST); + } + if ( isset($_GET) && is_array($_GET) ) { + $params = array_merge($params,$_GET); + } + foreach($params as $name=>$value) { + if(!in_array($name, $blockVariables)){ + if(is_array($value)) { + foreach($value as $v) { + $base_url .= $name.urlencode('[]').'='.urlencode($v) . '&'; + } + } + else { + $base_url .= $name.'='.urlencode($value) . '&'; + } + } + } + $this->base_url = $base_url; + } + return $this->base_url; + } + /** + * based off of a base name it sets base, offset, and order by variable names to retrieve them from requests and sessions + * + * @param unknown_type $baseName + */ + function setVariableName($baseName, $where, $listviewName = null){ + global $timedate; + $module = (!empty($listviewName)) ? $listviewName: $_REQUEST['module']; + $this->var_name = $module .'2_'. strtoupper($baseName); + + $this->var_order_by = $this->var_name .'_ORDER_BY'; + $this->var_offset = $this->var_name . '_offset'; + $timestamp = sugar_microtime(); + $this->stamp = $timestamp; + + $_SESSION[$module .'2_QUERY_QUERY'] = $where; + + $_SESSION[strtoupper($baseName) . "_FROM_LIST_VIEW"] = $timestamp; + $_SESSION[strtoupper($baseName) . "_DETAIL_NAV_HISTORY"] = false; + } + + function getTotalCount($main_query){ + if(!empty($this->count_query)){ + $count_query = $this->count_query; + }else{ + $count_query = SugarBean::create_list_count_query($main_query); + } + $result = $this->db->query($count_query); + if($row = $this->db->fetchByAssoc($result)){ + return $row['c']; + } + return 0; + } + + /** + * takes in a seed and creates the list view query based off of that seed + * if the $limit value is set to -1 then it will use the default limit and offset values + * + * it will return an array with two key values + * 1. 'data'=> this is an array of row data + * 2. 'pageData'=> this is an array containg three values + * a.'ordering'=> array('orderBy'=> the field being ordered by , 'sortOrder'=> 'ASC' or 'DESC') + * b.'urls'=>array('baseURL'=>url used to generate other urls , + * 'orderBy'=> the base url for order by + * //the following may not be set (so check empty to see if they are set) + * 'nextPage'=> the url for the next group of results, + * 'prevPage'=> the url for the prev group of results, + * 'startPage'=> the url for the start of the group, + * 'endPage'=> the url for the last set of results in the group + * c.'offsets'=>array( + * 'current'=>current offset + * 'next'=> next group offset + * 'prev'=> prev group offset + * 'end'=> the offset of the last group + * 'total'=> the total count (only accurate if totalCounted = true otherwise it is either the total count if less than the limit or the total count + 1 ) + * 'totalCounted'=> if a count query was used to get the total count + * + * @param SugarBean $seed + * @param string $where + * @param int:0 $offset + * @param int:-1 $limit + * @param string[]:array() $filter_fields + * @param array:array() $params + * Potential $params are + $params['distinct'] = use distinct key word + $params['include_custom_fields'] = (on by default) + $params['custom_XXXX'] = append custom statements to query + * @param string:'id' $id_field + * @return array('data'=> row data 'pageData' => page data information + */ + function getListViewData($seed, $where, $offset=-1, $limit = -1, $filter_fields=array(),$params=array(),$id_field = 'id') { + global $current_user; + SugarVCR::erase($seed->module_dir); + $this->seed =& $seed; + $totalCounted = empty($GLOBALS['sugar_config']['disable_count_query']); + $_SESSION['MAILMERGE_MODULE_FROM_LISTVIEW'] = $seed->module_dir; + if(empty($_REQUEST['action']) || $_REQUEST['action'] != 'Popup'){ + $_SESSION['MAILMERGE_MODULE'] = $seed->module_dir; + } + + $this->setVariableName($seed->object_name, $where, $this->listviewName); + + $this->seed->id = '[SELECT_ID_LIST]'; + + // if $params tell us to override all ordering + if(!empty($params['overrideOrder']) && !empty($params['orderBy'])) { + $order = $this->getOrderBy(strtolower($params['orderBy']), (empty($params['sortOrder']) ? '' : $params['sortOrder'])); // retreive from $_REQUEST + } + else { + $order = $this->getOrderBy(); // retreive from $_REQUEST + } + + // else use stored preference + $userPreferenceOrder = $current_user->getPreference('listviewOrder', $this->var_name); + + if(empty($order['orderBy']) && !empty($userPreferenceOrder)) { + $order = $userPreferenceOrder; + } + // still empty? try to use settings passed in $param + if(empty($order['orderBy']) && !empty($params['orderBy'])) { + $order['orderBy'] = $params['orderBy']; + $order['sortOrder'] = (empty($params['sortOrder']) ? '' : $params['sortOrder']); + } + + //rrs - bug: 21788. Do not use Order by stmts with fields that are not in the query. + // Bug 22740 - Tweak this check to strip off the table name off the order by parameter. + // Samir Gandhi : Do not remove the report_cache.date_modified condition as the report list view is broken + $orderby = $order['orderBy']; + if (strpos($order['orderBy'],'.') && ($order['orderBy'] != "report_cache.date_modified")) { + $orderby = substr($order['orderBy'],strpos($order['orderBy'],'.')+1); + } + if ($orderby != 'date_entered' && !in_array($orderby, array_keys($filter_fields))) { + $order['orderBy'] = ''; + $order['sortOrder'] = ''; + } + + if (empty($order['orderBy'])) { + $orderBy = ''; + } else { + $orderBy = $order['orderBy'] . ' ' . $order['sortOrder']; + //wdong, Bug 25476, fix the sorting problem of Oracle. + if (isset($params['custom_order_by_override']['ori_code']) && $order['orderBy'] == $params['custom_order_by_override']['ori_code']) + $orderBy = $params['custom_order_by_override']['custom_code'] . ' ' . $order['sortOrder']; + } + + if (empty($params['skipOrderSave'])) { // don't save preferences if told so + $current_user->setPreference('listviewOrder', $order, 0, $this->var_name); // save preference + } + + // If $params tells us to override for the special last_name, first_name sorting + if (!empty($params['overrideLastNameOrder']) && $order['orderBy'] == 'last_name') { + $orderBy = 'last_name '.$order['sortOrder'].', first_name '.$order['sortOrder']; + } + + $ret_array = $seed->create_new_list_query($orderBy, $where, $filter_fields, $params, 0, '', true, $seed, true); + $ret_array['inner_join'] = ''; + if (!empty($this->seed->listview_inner_join)) { + $ret_array['inner_join'] = ' ' . implode(' ', $this->seed->listview_inner_join) . ' '; + } + + if(!is_array($params)) $params = array(); + if(!isset($params['custom_select'])) $params['custom_select'] = ''; + if(!isset($params['custom_from'])) $params['custom_from'] = ''; + if(!isset($params['custom_where'])) $params['custom_where'] = ''; + if(!isset($params['custom_order_by'])) $params['custom_order_by'] = ''; + $main_query = $ret_array['select'] . $params['custom_select'] . $ret_array['from'] . $params['custom_from'] . $ret_array['inner_join']. $ret_array['where'] . $params['custom_where'] . $ret_array['order_by'] . $params['custom_order_by']; + //C.L. - Fix for 23461 + if(empty($_REQUEST['action']) || $_REQUEST['action'] != 'Popup') { + $_SESSION['export_where'] = $ret_array['where']; + } + if($limit < -1) { + $result = $this->db->query($main_query); + } + else { + if($limit == -1) { + $limit = $this->getLimit(); + } + $dyn_offset = $this->getOffset(); + if($dyn_offset > 0 || !is_int($dyn_offset))$offset = $dyn_offset; + + if(strcmp($offset, 'end') == 0){ + $totalCount = $this->getTotalCount($main_query); + $offset = (floor(($totalCount -1) / $limit)) * $limit; + } + if($this->seed->ACLAccess('ListView')) { + $result = $this->db->limitQuery($main_query, $offset, $limit + 1); + } + else { + $result = array(); + } + + } + + $data = array(); + + $temp = clone $seed; + + $rows = array(); + $count = 0; + $idIndex = array(); + $id_list = ''; + while($row = $this->db->fetchByAssoc($result)) { + if($count < $limit) { + if(!empty($id_list)) { + $id_list = '('; + }else{ + $id_list .= ','; + } + $id_list .= '\''.$row[$id_field].'\''; + //handles date formating and such + $idIndex[$row[$id_field]][] = count($rows); + $rows[] = $row; + } + $count++; + } + if (!empty($id_list)) $id_list .= ')'; + + SugarVCR::store($this->seed->module_dir, $main_query); + if($count != 0) { + //NOW HANDLE SECONDARY QUERIES + if(!empty($ret_array['secondary_select'])) { + $secondary_query = $ret_array['secondary_select'] . $ret_array['secondary_from'] . ' WHERE '.$this->seed->table_name.'.id IN ' .$id_list; + $secondary_result = $this->db->query($secondary_query); + while($row = $this->db->fetchByAssoc($secondary_result)) { + foreach($row as $name=>$value) { + //add it to every row with the given id + foreach($idIndex[$row['ref_id']] as $index){ + $rows[$index][$name]=$value; + } + + } + } + } + + // retrieve parent names + if(!empty($filter_fields['parent_name']) && !empty($filter_fields['parent_id']) && !empty($filter_fields['parent_type'])) { + foreach($idIndex as $id => $rowIndex) { + if(!isset($post_retrieve[$rows[$rowIndex[0]]['parent_type']])) { + $post_retrieve[$rows[$rowIndex[0]]['parent_type']] = array(); + } + if(!empty($rows[$rowIndex[0]]['parent_id'])) $post_retrieve[$rows[$rowIndex[0]]['parent_type']][] = array('child_id' => $id , 'parent_id'=> $rows[$rowIndex[0]]['parent_id'], 'parent_type' => $rows[$rowIndex[0]]['parent_type'], 'type' => 'parent'); + } + if(isset($post_retrieve)) { + $parent_fields = $seed->retrieve_parent_fields($post_retrieve); + foreach($parent_fields as $child_id => $parent_data) { + //add it to every row with the given id + foreach($idIndex[$child_id] as $index){ + $rows[$index]['parent_name']= $parent_data['parent_name']; + } + } + } + } + + $pageData = array(); + + reset($rows); + while($row = current($rows)){ + $temp = clone $seed; + $dataIndex = count($data); + + $temp->setupCustomFields($temp->module_dir); + $temp->loadFromRow($row); + if($idIndex[$row[$id_field]][0] == $dataIndex){ + $pageData['tag'][$dataIndex] = $temp->listviewACLHelper(); + }else{ + $pageData['tag'][$dataIndex] = $pageData['tag'][$idIndex[$row[$id_field]][0]]; + } + $data[$dataIndex] = $temp->get_list_view_data($filter_fields); + $pageData['rowAccess'][$dataIndex] = array('view' => $temp->ACLAccess('DetailView'), 'edit' => $temp->ACLAccess('EditView')); + $additionalDetailsAllow = $this->additionalDetails && $temp->ACLAccess('DetailView') && (file_exists('modules/' . $temp->module_dir . '/metadata/additionalDetails.php') || file_exists('custom/modules/' . $temp->module_dir . '/metadata/additionalDetails.php')); + //if($additionalDetailsAllow) $pageData['additionalDetails'] = array(); + $additionalDetailsEdit = $temp->ACLAccess('EditView'); + if($additionalDetailsAllow) { + if($this->additionalDetailsAjax) { + $ar = $this->getAdditionalDetailsAjax($data[$dataIndex]['ID']); + } + else { + $additionalDetailsFile = 'modules/' . $this->seed->module_dir . '/metadata/additionalDetails.php'; + if(file_exists('custom/modules/' . $this->seed->module_dir . '/metadata/additionalDetails.php')){ + $additionalDetailsFile = 'custom/modules/' . $this->seed->module_dir . '/metadata/additionalDetails.php'; + } + require_once($additionalDetailsFile); + $ar = $this->getAdditionalDetails($data[$dataIndex], + (empty($this->additionalDetailsFunction) ? 'additionalDetails' : $this->additionalDetailsFunction) . $this->seed->object_name, + $additionalDetailsEdit); + } + $pageData['additionalDetails'][$dataIndex] = $ar['string']; + $pageData['additionalDetails']['fieldToAddTo'] = $ar['fieldToAddTo']; + } + next($rows); + } + } + $nextOffset = -1; + $prevOffset = -1; + $endOffset = -1; + if($count > $limit) { + $nextOffset = $offset + $limit; + } + + if($offset > 0) { + $prevOffset = $offset - $limit; + if($prevOffset < 0)$prevOffset = 0; + } + $totalCount = $count + $offset; + + if( $count >= $limit && $totalCounted){ + $totalCount = $this->getTotalCount($main_query); + } + SugarVCR::recordIDs($this->seed->module_dir, array_keys($idIndex), $offset, $totalCount); + $endOffset = (floor(($totalCount - 1) / $limit)) * $limit; + $pageData['ordering'] = $order; + $pageData['ordering']['sortOrder'] = $this->getReverseSortOrder($pageData['ordering']['sortOrder']); + $pageData['urls'] = $this->generateURLS($pageData['ordering']['sortOrder'], $offset, $prevOffset, $nextOffset, $endOffset, $totalCounted); + $pageData['offsets'] = array( 'current'=>$offset, 'next'=>$nextOffset, 'prev'=>$prevOffset, 'end'=>$endOffset, 'total'=>$totalCount, 'totalCounted'=>$totalCounted); + $pageData['bean'] = array('objectName' => $seed->object_name, 'moduleDir' => $seed->module_dir); + $pageData['stamp'] = $this->stamp; + $pageData['access'] = array('view' => $this->seed->ACLAccess('DetailView'), 'edit' => $this->seed->ACLAccess('EditView')); + $pageData['idIndex'] = $idIndex; + if(!$this->seed->ACLAccess('ListView')) { + $pageData['error'] = 'ACL restricted access'; + } + + return array('data'=>$data , 'pageData'=>$pageData); + } + + + /** + * generates urls for use by the display layer + * + * @param int $sortOrder + * @param int $offset + * @param int $prevOffset + * @param int $nextOffset + * @param int $endOffset + * @param int $totalCounted + * @return array of urls orderBy and baseURL are always returned the others are only returned according to values passed in. + */ + function generateURLS($sortOrder, $offset, $prevOffset, $nextOffset, $endOffset, $totalCounted) { + $urls = array(); + $urls['baseURL'] = $this->getBaseURL(). 'lvso=' . $sortOrder. '&'; + $urls['orderBy'] = $urls['baseURL'] .$this->var_order_by.'='; + + $dynamicUrl = ''; + if($nextOffset > -1) { + $urls['nextPage'] = $urls['baseURL'] . $this->var_offset . '=' . $nextOffset . $dynamicUrl; + } + if($offset > 0) { + $urls['startPage'] = $urls['baseURL'] . $this->var_offset . '=0' . $dynamicUrl; + } + if($prevOffset > -1) { + $urls['prevPage'] = $urls['baseURL'] . $this->var_offset . '=' . $prevOffset . $dynamicUrl; + } + if($totalCounted) { + $urls['endPage'] = $urls['baseURL'] . $this->var_offset . '=' . $endOffset . $dynamicUrl; + }else{ + $urls['endPage'] = $urls['baseURL'] . $this->var_offset . '=end' . $dynamicUrl; + } + + return $urls; + } + + /** + * generates the additional details span to be retrieved via ajax + * + * @param GUID id id of the record + * @return array string to attach to field + */ + function getAdditionalDetailsAjax($id) + { + global $app_strings; + + $jscalendarImage = SugarThemeRegistry::current()->getImageURL('info_inline.gif'); + + $extra = ""; + + return array('fieldToAddTo' => $this->additionalDetailsFieldToAdd, 'string' => $extra); + } + + /** + * generates the additional details values + * + * @param unknown_type $fields + * @param unknown_type $adFunction + * @param unknown_type $editAccess + * @return array string to attach to field + */ + function getAdditionalDetails($fields, $adFunction, $editAccess) + { + global $app_strings; + + $results = $adFunction($fields); + $results['string'] = str_replace(array("'", "'"), '\'', $results['string']); // no xss! + + if(trim($results['string']) == '') $results['string'] = $app_strings['LBL_NONE']; + $extra = "'), $results['string']) + . "', CAPTION, '
{$app_strings['LBL_ADDITIONAL_DETAILS']}
"; + if($editAccess) $extra .= (!empty($results['editLink']) ? "" : ''); + $extra .= (!empty($results['viewLink']) ? "" : '') + . "', DELAY, 200, STICKY, MOUSEOFF, 1000, WIDTH, " + . (empty($results['width']) ? '300' : $results['width']) + . ", CLOSETEXT, '
', " + . "CLOSETITLE, '{$app_strings['LBL_ADDITIONAL_DETAILS_CLOSE_TITLE']}', CLOSECLICK, FGCLASS, 'olFgClass', " + . "CGCLASS, 'olCgClass', BGCLASS, 'olBgClass', TEXTFONTCLASS, 'olFontClass', CAPTIONFONTCLASS, 'olCapFontClass', CLOSEFONTCLASS, 'olCloseFontClass');\" " + . "onmouseout=\"return nd(1000);\">
"; + + $results = $adFunction($fields); + $results['string'] = str_replace(array("'", "'"), '\'', $results['string']); // no xss! + + if(trim($results['string']) == '') $results['string'] = $app_strings['LBL_NONE']; + $extra = "'), $results['string']) + . "', CAPTION, '
{$app_strings['LBL_ADDITIONAL_DETAILS']}
"; + if($editAccess) $extra .= (!empty($results['editLink']) ? "" : ''); + $extra .= (!empty($results['viewLink']) ? "" : '') + . "', DELAY, 200, STICKY, MOUSEOFF, 1000, WIDTH, " + . (empty($results['width']) ? '300' : $results['width']) + . ", CLOSETEXT, '
', " + . "CLOSETITLE, '{$app_strings['LBL_ADDITIONAL_DETAILS_CLOSE_TITLE']}', CLOSECLICK, FGCLASS, 'olFgClass', " + . "CGCLASS, 'olCgClass', BGCLASS, 'olBgClass', TEXTFONTCLASS, 'olFontClass', CAPTIONFONTCLASS, 'olCapFontClass', CLOSEFONTCLASS, 'olCloseFontClass');\" " + . "onmouseout=\"return nd(1000);\">
"; + + return array('fieldToAddTo' => $results['fieldToAddTo'], 'string' => $extra); + } + +} diff --git a/include/ListView/ListViewDisplay.php b/include/ListView/ListViewDisplay.php new file mode 100644 index 00000000..81102e6b --- /dev/null +++ b/include/ListView/ListViewDisplay.php @@ -0,0 +1,615 @@ +lvd = new ListViewData(); + $this->searchColumns = array () ; + } + function shouldProcess($moduleDir){ + if(!empty($GLOBALS['sugar_config']['save_query']) && $GLOBALS['sugar_config']['save_query'] == 'populate_only'){ + if(empty($GLOBALS['displayListView']) + && (!empty($_REQUEST['clear_query']) + || $_REQUEST['module'] == $moduleDir + && ((empty($_REQUEST['query']) || $_REQUEST['query'] == 'MSI' ) + && (empty($_SESSION['last_search_mod']) || $_SESSION['last_search_mod'] != $moduleDir ) ))){ + $_SESSION['last_search_mod'] = $_REQUEST['module'] ; + $this->should_process = false; + return false; + } + } + $this->should_process = true; + return true; + } + + /** + * Setup the class + * @param seed SugarBean Seed SugarBean to use + * @param file File Template file to use + * @param string $where + * @param offset:0 int offset to start at + * @param int:-1 $limit + * @param string[]:array() $filter_fields + * @param array:array() $params + * Potential $params are + $params['distinct'] = use distinct key word + $params['include_custom_fields'] = (on by default) + $params['massupdate'] = true by default; + $params['handleMassupdate'] = true by default, have massupdate.php handle massupdates? + * @param string:'id' $id_field + */ + function setup($seed, $file, $where, $params = array(), $offset = 0, $limit = -1, $filter_fields = array(), $id_field = 'id') { + $this->should_process = true; + if(isset($seed->module_dir) && !$this->shouldProcess($seed->module_dir)){ + return false; + } + if(isset($params['export'])) { + $this->export = $params['export']; + } + if(!empty($params['multiSelectPopup'])) { + $this->multi_select_popup = $params['multiSelectPopup']; + } + if(!empty($params['massupdate']) && $params['massupdate'] != false) { + $this->show_mass_update_form = true; + $this->mass = new MassUpdate(); + $this->mass->setSugarBean($seed); + if(!empty($params['handleMassupdate']) || !isset($params['handleMassupdate'])) { + $this->mass->handleMassUpdate(); + } + } + $this->seed = $seed; + + $filter_fields = $this->setupFilterFields($filter_fields); + + $data = $this->lvd->getListViewData($seed, $where, $offset, $limit, $filter_fields, $params, $id_field); + + foreach($this->displayColumns as $columnName => $def) + { + $seedName = strtolower($columnName); + if(!empty($this->lvd->seed->field_defs[$seedName])){ + $seedDef = $this->lvd->seed->field_defs[$seedName]; + } + + if(empty($this->displayColumns[$columnName]['type'])){ + if(!empty($seedDef['type'])){ + $this->displayColumns[$columnName]['type'] = (!empty($seedDef['custom_type']))?$seedDef['custom_type']:$seedDef['type']; + }else{ + $this->displayColumns[$columnName]['type'] = ''; + } + }//fi empty(...) + + if(!empty($seedDef['options'])){ + $this->displayColumns[$columnName]['options'] = $seedDef['options']; + } + + //C.L. Fix for 11177 + if($this->displayColumns[$columnName]['type'] == 'html') { + $cField = $this->seed->custom_fields; + if(isset($cField) && isset($cField->bean->$seedName)) { + $seedName2 = strtoupper($columnName); + $htmlDisplay = html_entity_decode($cField->bean->$seedName); + $count = 0; + while($count < count($data['data'])) { + $data['data'][$count][$seedName2] = &$htmlDisplay; + $count++; + } + } + }//fi == 'html' + + //Bug 40511, make sure relate fields have the correct module defined + if ($this->displayColumns[$columnName]['type'] == "relate" && !empty($seedDef['link']) && empty( $this->displayColumns[$columnName]['module'])) + { + $link = $seedDef['link']; + if (!empty($this->lvd->seed->field_defs[$link]) && !empty($this->lvd->seed->field_defs[$seedDef['link']]['module'])) + { + $this->displayColumns[$columnName]['module'] = $this->lvd->seed->field_defs[$seedDef['link']]['module']; + } + } + + if (!empty($seedDef['sort_on'])) { + $this->displayColumns[$columnName]['orderBy'] = $seedDef['sort_on']; + } + + if(isset($seedDef)){ + // Merge the two arrays together, making sure the seedDef doesn't override anything explicitly set in the displayColumns array. + $this->displayColumns[$columnName] = $this->displayColumns[$columnName] + $seedDef; + } + + //C.L. Bug 38388 - ensure that ['id'] is set for related fields + if(!isset($this->displayColumns[$columnName]['id']) && isset($this->displayColumns[$columnName]['id_name'])) { + $this->displayColumns[$columnName]['id'] = strtoupper($this->displayColumns[$columnName]['id_name']); + } + } + + $this->process($file, $data, $seed->object_name); + return true; + } + + function setupFilterFields($filter_fields = array()) + { + // create filter fields based off of display columns + if(empty($filter_fields) || $this->mergeDisplayColumns) { + foreach($this->displayColumns as $columnName => $def) { + + $filter_fields[strtolower($columnName)] = true; + + if(isset($this->seed->field_defs[strtolower($columnName)]['type']) && + strtolower($this->seed->field_defs[strtolower($columnName)]['type']) == 'currency' && + isset($this->seed->field_defs['currency_id'])) { + $filter_fields['currency_id'] = true; + } + + if(!empty($def['related_fields'])) { + foreach($def['related_fields'] as $field) { + //id column is added by query construction function. This addition creates duplicates + //and causes issues in oracle. #10165 + if ($field != 'id') { + $filter_fields[$field] = true; + } + } + } + if (!empty($this->seed->field_defs[strtolower($columnName)]['db_concat_fields'])) { + foreach($this->seed->field_defs[strtolower($columnName)]['db_concat_fields'] as $index=>$field){ + if(!isset($filter_fields[strtolower($field)]) || !$filter_fields[strtolower($field)]) + { + $filter_fields[strtolower($field)] = true; + } + } + } + } + foreach ($this->searchColumns as $columnName => $def ) + { + $filter_fields[strtolower($columnName)] = true; + } + } + + + return $filter_fields; + } + + + /** + * Any additional processing + * @param file File template file to use + * @param data array row data + * @param html_var string html string to be passed back and forth + */ + function process($file, $data, $htmlVar) { + $this->rowCount = count($data['data']); + $this->moduleString = $data['pageData']['bean']['moduleDir'] . '2_' . strtoupper($htmlVar) . '_offset'; + } + + /** + * Display the listview + * @return string ListView contents + */ + public function display() + { + if (!$this->should_process) { + return ''; + } + + $str = ''; + if ($this->multiSelect == true && $this->show_mass_update_form) { + $str = $this->mass->getDisplayMassUpdateForm(true, $this->multi_select_popup).$this->mass->getMassUpdateFormHeader($this->multi_select_popup); + } + + return $str; + } + /** + * Display the select link + * @return string select link html + * @param echo Bool set true if you want it echo'd, set false to have contents returned + */ + function buildSelectLink($id = 'select_link', $total=0, $pageTotal=0) { + global $app_strings; + if ($pageTotal < 0) + $pageTotal = $total; + $script = ""; + $script .= "".""; + + return $script; + } + + /** + * Display the actions link + * + * @param string $id link id attribute, defaults to 'actions_link' + * @return string HTML source + */ + protected function buildActionsLink( + $id = 'actions_link' + ) + { + global $app_strings; + $closeText = ""; + $moreDetailImage = SugarThemeRegistry::current()->getImageURL('MoreDetail.png'); + $menuItems = ''; + + // delete + if ( ACLController::checkAccess($this->seed->module_dir,'delete',true) && $this->delete ) + $menuItems .= $this->buildDeleteLink(); + // compose email + if ( $this->email ) + $menuItems .= $this->buildComposeEmailLink($this->data['pageData']['offsets']['total']); + // mass update + $mass = new MassUpdate(); + $mass->setSugarBean($this->seed); + if ( ACLController::checkAccess($this->seed->module_dir,'edit',true) && $this->showMassupdateFields && $mass->doMassUpdateFieldsExistForFocus() ) + $menuItems .= $this->buildMassUpdateLink(); + // merge + if ( $this->mailMerge ) + $menuItems .= $this->buildMergeLink(); + if ( $this->mergeduplicates ) + $menuItems .= $this->buildMergeDuplicatesLink(); + // add to target list + if ( $this->targetList && ACLController::checkAccess('ProspectLists','edit',true) ) + $menuItems .= $this->buildTargetList(); + // export + if ( ACLController::checkAccess($this->seed->module_dir,'export',true) && $this->export ) + $menuItems .= $this->buildExportLink(); + + foreach ( $this->actionsMenuExtraItems as $item ) + $menuItems .= $item; + + $menuItems = str_replace('"','\"',$menuItems); + $menuItems = str_replace(array("\r","\n"),'',$menuItems); + + if ( empty($menuItems) ) + return ''; + + return << + + + + {$app_strings['LBL_LINK_ACTIONS']}  + +EOHTML; + } + + /** + * Builds the export link + * + * @return string HTML + */ + protected function buildExportLink() + { + global $app_strings; + return "seed->module_dir}', 'index.php?entryPoint=export','{$app_strings['LBL_LISTVIEW_NO_SELECTED']}')\">{$app_strings['LBL_EXPORT']}"; + } + + /** + * Builds the massupdate link + * + * @return string HTML + */ + protected function buildMassUpdateLink() + { + global $app_strings; + + return "{$app_strings['LBL_MASS_UPDATE']}"; + } + + /** + * Builds the compose email link + * + * @return string HTML + */ + protected function buildComposeEmailLink( + $totalCount + ) + { + global $app_strings,$dictionary; + + if (!is_array($this->seed->field_defs)) { + return ''; + } + $foundEmailField = false; + // Search for fields that look like an email address + foreach ($this->seed->field_defs as $field) { + if(isset($field['type'])&&$field['type']=='link' + &&isset($field['relationship'])&&isset($dictionary[$this->seed->object_name]['relationships'][$field['relationship']]) + &&$dictionary[$this->seed->object_name]['relationships'][$field['relationship']]['rhs_module']=='EmailAddresses') { + $foundEmailField = true; + break; + } + } + if (!$foundEmailField) { + return ''; + } + + + $userPref = $GLOBALS['current_user']->getPreference('email_link_type'); + $defaultPref = $GLOBALS['sugar_config']['email_default_client']; + if($userPref != '') + $client = $userPref; + else + $client = $defaultPref; + + if($client == 'sugar') + $script = "seed->module_dir.'\', \''.$totalCount.'\', \''.$app_strings['LBL_LISTVIEW_LESS_THAN_TEN_SELECT'].'\')">' . + $app_strings['LBL_EMAIL_COMPOSE'] . ''; + else + $script = "" . + $app_strings['LBL_EMAIL_COMPOSE'] . ''; + + return $script; + } // fn + /** + * Builds the delete link + * + * @return string HTML + */ + protected function buildDeleteLink() + { + global $app_strings; + + return "{$app_strings['LBL_DELETE_BUTTON_LABEL']}"; + } + /** + * Display the selected object span object + * + * @return string select object span + */ + function buildSelectedObjectsSpan($echo = true, $total=0) { + global $app_strings; + + $selectedObjectSpan = "
{$app_strings['LBL_LISTVIEW_SELECTED_OBJECTS']}
"; + + return $selectedObjectSpan; + } + /** + * Builds the mail merge link + * The link can be disabled by setting module level duplicate_merge property to false + * in the moudle's vardef file. + * + * @return string HTML + */ + protected function buildMergeDuplicatesLink() + { + global $app_strings, $dictionary; + + $return_string=''; + $return_string.= isset($_REQUEST['module']) ? "&return_module={$_REQUEST['module']}" : ""; + $return_string.= isset($_REQUEST['action']) ? "&return_action={$_REQUEST['action']}" : ""; + $return_string.= isset($_REQUEST['record']) ? "&return_id={$_REQUEST['record']}" : ""; + //need delete and edit access. + if (!(ACLController::checkAccess($this->seed->module_dir, 'edit', true)) or !(ACLController::checkAccess($this->seed->module_dir, 'delete', true))) { + return ''; + } + + if (isset($dictionary[$this->seed->object_name]['duplicate_merge']) && $dictionary[$this->seed->object_name]['duplicate_merge']==true ) { + return "seed->module_dir}\",\"$return_string\");} else {alert(\"{$app_strings['LBL_LISTVIEW_TWO_REQUIRED']}\");return false;}'>". + $app_strings['LBL_MERGE_DUPLICATES'].''; + } + + return ''; + } + /** + * Builds the mail merge link + * + * @return string HTML + */ + protected function buildMergeLink(array $modules_array = null) + { + if ( empty($modules_array) ) { + require('modules/MailMerge/modules_array.php'); + } + global $current_user, $app_strings; + + $admin = new Administration(); + $admin->retrieveSettings('system'); + $user_merge = $current_user->getPreference('mailmerge_on'); + $module_dir = (!empty($this->seed->module_dir) ? $this->seed->module_dir : ''); + $str = ''; + + if ($user_merge == 'on' && isset($admin->settings['system_mailmerge_on']) && $admin->settings['system_mailmerge_on'] && !empty($modules_array[$module_dir])) { + $str = "' . + $app_strings['LBL_MAILMERGE'].''; + } + return $str; + } + + /** + * Builds the add to target list link + * + * @return string HTML + */ + protected function buildTargetList() + { + global $app_strings; + $current_query_by_page = base64_encode(serialize(array_merge($_POST, $_GET))); + + $js = <<seed->module_dir}' ); + input.setAttribute ( 'type' , 'hidden' ); + form.appendChild ( input ) ; + var input = document.createElement('input'); + input.setAttribute ( 'name' , 'action' ); + input.setAttribute ( 'value' , 'TargetListUpdate' ); + input.setAttribute ( 'type' , 'hidden' ); + form.appendChild ( input ) ; + } + if ( !form.uids ) { + var input = document.createElement('input'); + input.setAttribute ( 'name' , 'uids' ); + input.setAttribute ( 'type' , 'hidden' ); + form.appendChild ( input ) ; + } + if ( !form.prospect_list ) { + var input = document.createElement('input'); + input.setAttribute ( 'name' , 'prospect_list' ); + input.setAttribute ( 'type' , 'hidden' ); + form.appendChild ( input ) ; + } + if ( !form.return_module ) { + var input = document.createElement('input'); + input.setAttribute ( 'name' , 'return_module' ); + input.setAttribute ( 'type' , 'hidden' ); + form.appendChild ( input ) ; + } + if ( !form.return_action ) { + var input = document.createElement('input'); + input.setAttribute ( 'name' , 'return_action' ); + input.setAttribute ( 'type' , 'hidden' ); + form.appendChild ( input ) ; + } + if ( !form.select_entire_list ) { + var input = document.createElement('input'); + input.setAttribute ( 'name' , 'select_entire_list' ); + input.setAttribute ( 'value', document.MassUpdate.select_entire_list.value); + input.setAttribute ( 'type' , 'hidden' ); + form.appendChild ( input ) ; + } + if ( !form.current_query_by_page ) { + var input = document.createElement('input'); + input.setAttribute ( 'name' , 'current_query_by_page' ); + input.setAttribute ( 'value', '{$current_query_by_page}' ); + input.setAttribute ( 'type' , 'hidden' ); + form.appendChild ( input ) ; + } + open_popup('ProspectLists','600','400','',true,false,{ 'call_back_function':'set_return_and_save_targetlist','form_name':'targetlist_form','field_to_name_array':{'id':'prospect_list'} } ); +EOF; + $js = str_replace(array("\r","\n"),'',$js); + return "{$app_strings['LBL_ADD_TO_PROSPECT_LIST_BUTTON_LABEL']}"; + } + /** + * Display the bottom of the ListView (ie MassUpdate + * @return string contents + */ + public function displayEnd() + { + $str = ''; + if($this->show_mass_update_form) { + $str .= $this->mass->getMassUpdateForm(true); + $str .= $this->mass->endMassUpdateForm(); + } + + return $str; + } + + /** + * Display the multi select data box etc. + * @return string contents + */ + public function getMultiSelectData() + { + $str = "\n"; + + $massUpdateRun = isset($_REQUEST['massupdate']) && $_REQUEST['massupdate'] == 'true'; + $uids = empty($_REQUEST['uid']) || $massUpdateRun ? '' : $_REQUEST['uid']; + $select_entire_list = isset($_REQUEST['select_entire_list']) && !$massUpdateRun ? $_REQUEST['select_entire_list'] : 0; + + $str .= "\n" . + "\n". + "\n"; + + return $str; + } + +} +?> diff --git a/include/ListView/ListViewFacade.php b/include/ListView/ListViewFacade.php new file mode 100644 index 00000000..84904182 --- /dev/null +++ b/include/ListView/ListViewFacade.php @@ -0,0 +1,177 @@ +focus = $focus; + $this->module = $module; + $this->type = $type; + $this->build(); + } + + function build(){ + //we will assume that if the ListView.html file exists we will want to use that one + if(file_exists('modules/'.$this->module.'/ListView.html')){ + $this->type = 1; + $this->lv = new ListView(); + $this->template = 'modules/'.$this->module.'/ListView.html'; + }else{ + $metadataFile = null; + $foundViewDefs = false; + if(file_exists('custom/modules/' . $this->module. '/metadata/listviewdefs.php')){ + $metadataFile = 'custom/modules/' . $this->module . '/metadata/listviewdefs.php'; + $foundViewDefs = true; + }else{ + if(file_exists('custom/modules/'. $this->module.'/metadata/metafiles.php')){ + require_once('custom/modules/'. $this->module.'/metadata/metafiles.php'); + if(!empty($metafiles[ $this->module]['listviewdefs'])){ + $metadataFile = $metafiles[ $this->module]['listviewdefs']; + $foundViewDefs = true; + } + }elseif(file_exists('modules/'. $this->module.'/metadata/metafiles.php')){ + require_once('modules/'. $this->module.'/metadata/metafiles.php'); + if(!empty($metafiles[ $this->module]['listviewdefs'])){ + $metadataFile = $metafiles[ $this->module]['listviewdefs']; + $foundViewDefs = true; + } + } + } + if(!$foundViewDefs && file_exists('modules/'. $this->module.'/metadata/listviewdefs.php')){ + $metadataFile = 'modules/'. $this->module.'/metadata/listviewdefs.php'; + } + require_once($metadataFile); + + + $this->lv = new ListViewSmarty(); + $displayColumns = array(); + if(!empty($_REQUEST['displayColumns'])) { + foreach(explode('|', $_REQUEST['displayColumns']) as $num => $col) { + if(!empty($listViewDefs[$this->module][$col])) + $displayColumns[$col] = $listViewDefs[$this->module][$col]; + } + } + else { + foreach($listViewDefs[$this->module] as $col => $params) { + if(!empty($params['default']) && $params['default']) + $displayColumns[$col] = $params; + } + } + $this->lv->displayColumns = $displayColumns; + $this->type = 2; + $this->template = 'include/ListView/ListViewGeneric.tpl'; + } + } + + function setup($template = '', $where = '', $params = array(), $mod_strings = array(), $offset = 0, $limit = -1, $orderBy = '', $prefix = '', $filter_fields = array(), $id_field = 'id'){ + if(!empty($template)) + $this->template = $template; + + $this->mod_strings = $mod_strings; + + if($this->type == 1){ + $this->lv->initNewXTemplate($this->template,$this->mod_strings); + $this->prefix = $prefix; + $this->lv->setQuery($where, $limit, $orderBy, $prefix); + $this->lv->show_select_menu = false; + $this->lv->show_export_button = false; + $this->lv->show_delete_button = false; + $this->lv->show_mass_update = false; + $this->lv->show_mass_update_form = false; + }else{ + $this->lv->export = false; + $this->lv->delete = false; + $this->lv->select = false; + $this->lv->mailMerge = false; + $this->lv->multiSelect = false; + $this->lv->setup($this->focus, $this->template, $where, $params, $offset, $limit, $filter_fields, $id_field); + + } + } + + function display($title = '', $section = 'main'){ + if($this->type == 1){ + $this->lv->setHeaderTitle($title); + $this->lv->processListView($this->focus, $section, $this->prefix); + }else{ + echo get_form_header($title, '', false); + echo $this->lv->display(); + } + } + + function setTitle($title = ''){ + $this->title = $title; + } + } +?> diff --git a/include/ListView/ListViewGeneric.tpl b/include/ListView/ListViewGeneric.tpl new file mode 100644 index 00000000..17b15803 --- /dev/null +++ b/include/ListView/ListViewGeneric.tpl @@ -0,0 +1,168 @@ +{* + +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + + + +*} + + + +{if $overlib} + + +{/if} +{if $prerow} + {$multiSelectData} +{/if} + +{include file='include/ListView/ListViewPagination.tpl'} + + {if $prerow} + + {/if} + {if !empty($quickViewLinks)} + + {/if} + {counter start=0 name="colCounter" print=false assign="colCounter"} + {foreach from=$displayColumns key=colHeader item=params} + + {counter name="colCounter"} + {/foreach} + + + + {counter start=$pageData.offsets.current print=false assign="offset" name="offset"} + {foreach name=rowIteration from=$data key=id item=rowData} + {counter name="offset" print=false} + + {if $smarty.foreach.rowIteration.iteration is odd} + {assign var='_rowColor' value=$rowColor[0]} + {else} + {assign var='_rowColor' value=$rowColor[1]} + {/if} + + {if $prerow} + + {/if} + {if !empty($quickViewLinks)} + + {/if} + {counter start=0 name="colCounter" print=false assign="colCounter"} + {foreach from=$displayColumns key=col item=params} + {strip} + + {/strip} + {counter name="colCounter"} + {/foreach} + + + {foreachelse} + + + + {/foreach} +{include file='include/ListView/ListViewPagination.tpl'} +
+
+ + {$selectLink} +
+
  +
+ {if $params.sortable|default:true} + {if $params.url_sort} + + {else} + {if $params.orderBy|default:$colHeader|lower == $pageData.ordering.orderBy} + + {else} + + {/if} + {/if} + {sugar_translate label=$params.label module=$pageData.bean.moduleDir} +    + {if $params.orderBy|default:$colHeader|lower == $pageData.ordering.orderBy} + {if $pageData.ordering.sortOrder == 'ASC'} + {capture assign="imageName"}arrow_down.{$arrowExt}{/capture} + {$arrowAlt} + {else} + {capture assign="imageName"}arrow_up.{$arrowExt}{/capture} + {$arrowAlt} + {/if} + {else} + {capture assign="imageName"}arrow.{$arrowExt}{/capture} + {$arrowAlt} + {/if} + {else} + {if !isset($params.noHeader) || $params.noHeader == false} + {sugar_translate label=$params.label module=$pageData.bean.moduleDir} + {/if} + {/if} +
+
 
+ {if !$is_admin && is_admin_for_user && $rowData.IS_ADMIN==1} + + {else} + + {/if} + {if $pageData.rowAccess[$id].edit}{/if} + {if $col == 'NAME' || $params.bold}{/if} + {if $params.link && !$params.customCode} + <{$pageData.tag.$id[$params.ACLTag]|default:$pageData.tag.$id.MAIN} href="#" onMouseOver="javascript:lvg_nav('{if $params.dynamic_module}{$rowData[$params.dynamic_module]}{else}{$params.module|default:$pageData.bean.moduleDir}{/if}', '{$rowData[$params.id]|default:$rowData.ID}', 'd', {$offset}, this)" onFocus="javascript:lvg_nav('{if $params.dynamic_module}{$rowData[$params.dynamic_module]}{else}{$params.module|default:$pageData.bean.moduleDir}{/if}', '{$rowData[$params.id]|default:$rowData.ID}', 'd', {$offset}, this)"> + {/if} + {if $params.customCode} + {sugar_evalcolumn_old var=$params.customCode rowData=$rowData} + {else} + {sugar_field parentFieldArray=$rowData vardef=$params displayType=ListView field=$col} + + {/if} + {if empty($rowData.$col) && empty($params.customCode)} {/if} + {if $params.link && !$params.customCode} + + {/if} + {if $col == 'NAME' || $params.bold}{/if} + {$pageData.additionalDetails.$id}
+ {$APP.LBL_NO_DATA} +
+{if $contextMenus} + +{/if} diff --git a/include/ListView/ListViewNoMassUpdate.tpl b/include/ListView/ListViewNoMassUpdate.tpl new file mode 100644 index 00000000..9cfd0390 --- /dev/null +++ b/include/ListView/ListViewNoMassUpdate.tpl @@ -0,0 +1,133 @@ +{* + +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + + + +*} + +{if $overlib} + + + +{/if} + + + {include file='include/ListView/ListViewPagination.tpl'} + + + {if !empty($quickViewLinks)} + + {/if} + {counter start=0 name="colCounter" print=false assign="colCounter"} + {foreach from=$displayColumns key=colHeader item=params} + + {counter name="colCounter"} + {/foreach} + + + {foreach name=rowIteration from=$data key=id item=rowData} + {if $smarty.foreach.rowIteration.iteration is odd} + {assign var='_rowColor' value=$rowColor[0]} + {else} + {assign var='_rowColor' value=$rowColor[1]} + {/if} + + {if !empty($quickViewLinks)} + + {/if} + {counter start=0 name="colCounter" print=false assign="colCounter"} + {foreach from=$displayColumns key=col item=params} + + {counter name="colCounter"} + {/foreach} + + {foreachelse} + + + + {/foreach} + {include file='include/ListView/ListViewPagination.tpl'} +
  +
+ {if $params.sortable|default:true} + {sugar_translate label=$params.label module=$pageData.bean.moduleDir}   + {if $params.orderBy|default:$colHeader|lower == $pageData.ordering.orderBy} + {if $pageData.ordering.sortOrder == 'ASC'} + {capture assign="imageName"}arrow_down.{$arrowExt}{/capture} + {$arrowAlt} + {else} + {capture assign="imageName"}arrow_up.{$arrowExt}{/capture} + {$arrowAlt} + {/if} + {else} + {capture assign="imageName"}arrow.{$arrowExt}{/capture} + {$arrowAlt} + {/if} + {else} + {sugar_translate label=$params.label module=$pageData.bean.moduleDir} + {/if} +
+
+ {if $pageData.access.edit && $pageData.bean.moduleDir != "Employees"} + + {/if} + + {if $col == 'NAME' || $params.bold}{/if} + {if $params.link && !$params.customCode} + <{$pageData.tag.$id[$params.ACLTag]|default:$pageData.tag.$id.MAIN} href="#" onMouseOver="javascript:lvg_nav('{if $params.dynamic_module}{$rowData[$params.dynamic_module]}{else}{$params.module|default:$pageData.bean.moduleDir}{/if}', '{$rowData[$params.id]|default:$rowData.ID}', 'd', {$smarty.foreach.rowIteration.iteration}, this);" onFocus="javascript:lvg_nav('{if $params.dynamic_module}{$rowData[$params.dynamic_module]}{else}{$params.module|default:$pageData.bean.moduleDir}{/if}', '{$rowData[$params.id]|default:$rowData.ID}', 'd', {$smarty.foreach.rowIteration.iteration}, this);"> + {/if} + {if $params.customCode} + {sugar_evalcolumn_old var=$params.customCode rowData=$rowData} + {else} + {sugar_field parentFieldArray=$rowData vardef=$params displayType=ListView field=$col} + {/if} + {if empty($rowData.$col)} {/if} + {if $params.link && !$params.customCode} + + {/if} + {if $col == 'NAME' || $params.bold}{/if} +
+ {$APP.LBL_NO_DATA} +
+ diff --git a/include/ListView/ListViewPagination.tpl b/include/ListView/ListViewPagination.tpl new file mode 100644 index 00000000..9d183c38 --- /dev/null +++ b/include/ListView/ListViewPagination.tpl @@ -0,0 +1,91 @@ +{* + +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + + +*} +
+ + + + + +
+ {$actionsLink}  +  {$selectedObjectsSpan} + + {if $pageData.urls.startPage} + + {else} + + {/if} + {if $pageData.urls.prevPage} + + {else} + + {/if} + ({if $pageData.offsets.lastOffsetOnPage == 0}0{else}{$pageData.offsets.current+1}{/if} - {$pageData.offsets.lastOffsetOnPage} {$navStrings.of} {if $pageData.offsets.totalCounted}{$pageData.offsets.total}{else}{$pageData.offsets.total}{if $pageData.offsets.lastOffsetOnPage != $pageData.offsets.total}+{/if}{/if}) + {if $pageData.urls.nextPage} + + {else} + + {/if} + {if $pageData.urls.endPage && $pageData.offsets.total != $pageData.offsets.lastOffsetOnPage} + + {elseif !$pageData.offsets.totalCounted || $pageData.offsets.total == $pageData.offsets.lastOffsetOnPage} + + {/if} +
+
\n" + . "\n" + . "
$export_link$merge_link$selected_objects_span".$startLink."  ".$prevLink."  (".($this->data['pageData']['offsets']['current'] + 1) ." - ".($this->data['pageData']['offsets']['current'] + $this->rowCount) + . " ".$app_strings['LBL_LIST_OF']." ".$this->data['pageData']['offsets']['total']; + if(!$this->data['pageData']['offsets']['totalCounted']){ + $htmlText .= '+'; + } + $htmlText .=")  ".$nextLink."  "; + if($this->data['pageData']['offsets']['totalCounted']){ + $htmlText .= $endLink; + } + $htmlText .="
\n
"; +// +// if($this->sugarbean->ACLAccess('Delete', true) ){ +// $html .= ""; +// } +// $html .= "
"; +// return $html; +// } + + + $should_use = false; + $html = ""; + + $html .= << +function toggleMassUpdateForm(){ + document.getElementById('massupdate_form').style.display = 'none'; +} + +EOJS; + if($should_use){ + return $html; + }else{ + if($this->sugarbean->ACLAccess('Delete', true) && !$hideDeleteIfNoFieldsAvailable){ + return "
"; + }else{ + return ''; + } + } + } + + function getFunctionValue($focus, $vardef){ + $function = $vardef['function']; + if(is_array($function) && isset($function['name'])){ + $function = $vardef['function']['name']; + }else{ + $function = $vardef['function']; + } + if(!empty($vardef['function']['returns']) && $vardef['function']['returns'] == 'html'){ + if(!empty($vardef['function']['include'])){ + require_once($vardef['function']['include']); + } + return $function($focus, $vardef['name'], '', 'MassUpdate'); + }else{ + return $function($focus, $vardef['name'], '', 'MassUpdate'); + } + } + + /** + * Returns end of the massupdate form + */ + function endMassUpdateForm(){ + return ''; + } + + /** + * Decides which popup HTML code is needed for mass updating + * @param displayname Name to display in the popup window + * @param field name of the field to update + */ + function handleRelationship($displayname, $field) + { + $ret_val = ''; + if(isset($field['module'])) + { + if ($field['name'] == 'reports_to_name' && ($field['module'] == 'Users' || $field['module'] == 'Employee') ) + return $this->addUserName($displayname, $field['name'], $field['id_name'], $field['module']); + + switch($field['module']) + { + case 'Accounts': + $ret_val = $this->addAccountID($displayname, $field['name'], $field['id_name']); + break; + case 'Contacts': + $ret_val = $this->addGenericModuleID($displayname, $field['name'], $field['id_name'], "Contacts"); + break; + case 'Users': + $ret_val = $this->addGenericModuleID($displayname, $field['name'], $field['id_name'], "Users"); + break; + case 'Employee': + $ret_val = $this->addGenericModuleID($displayname, $field['name'], $field['id_name'], "Employee"); + break; + case 'Releases': + $ret_val = $this->addGenericModuleID($displayname, $field['name'], $field['id_name'], "Releases"); + break; + default: + if(!empty($field['massupdate'])){ + $ret_val = $this->addGenericModuleID($displayname, $field['name'], $field['id_name'], $field['module']); + } + break; + } + } + + return $ret_val; + } + /** + * Add a parent selection popup window + * @param displayname Name to display in the popup window + * @param field_name name of the field + */ + function addParent($displayname, $field){ + global $app_strings, $app_list_strings; + + /////////////////////////////////////// + /// + /// SETUP POPUP + + $popup_request_data = array( + 'call_back_function' => 'set_return', + 'form_name' => 'MassUpdate', + 'field_to_name_array' => array( + 'id' => "parent_id", + 'name' => "parent_name", + ), + ); + + $json = getJSONobj(); + $encoded_popup_request_data = $json->encode($popup_request_data); + + $qsName = array( + 'form' => 'MassUpdate', + 'method' => 'query', + 'modules' => array("Accounts"), + 'group' => 'or', + 'field_list' => array('name', 'id'), + 'populate_list' => array("mass_parent_name", "mass_parent_id"), + 'conditions' => array(array('name'=>'name','op'=>'like_custom','end'=>'%','value'=>'')), + 'limit' => '30','no_match_text' => $app_strings['ERR_SQS_NO_MATCH']); + $qsName = $json->encode($qsName); + + // + /////////////////////////////////////// + + $change_parent_button = ""; + $parent_type = $field['parent_type']; + $parent_types = $app_list_strings[$parent_type]; + $disabled_parent_types = ACLController::disabledModuleList($parent_types,false, 'list'); + foreach($disabled_parent_types as $disabled_parent_type) { + unset($parent_types[$disabled_parent_type]); + } + $types = get_select_options_with_id($parent_types, ''); + //BS Fix Bug 17110 + $pattern = "/\n/"; + $types = preg_replace($pattern, "", $types); + // End Fix + + $json = getJSONobj(); + $disabled_parent_types = $json->encode($disabled_parent_types); + + return <<{$displayname} + + + + + + +
+ + + + + $change_parent_button +
+ + +EOHTML; + } + + /** + * Add a generic input type='text' field + * @param displayname Name to display in the popup window + * @param field_name name of the field + */ + function addInputType($displayname, $varname){ + $html = <<$displayname + + +EOQ; + return $html; + + } + + /** + * Add a generic widget to lookup Users. + * @param displayname Name to display in the popup window + * @param varname name of the variable + * @param id_name name of the id in vardef + * @param mod_type name of the module, either "Contact" or "Releases" currently + */ + function addUserName($displayname, $varname, $id_name='', $mod_type){ + global $app_strings; + + if(empty($id_name)) + $id_name = strtolower($mod_type)."_id"; + + /////////////////////////////////////// + /// + /// SETUP POPUP + $reportsDisplayName = showFullName() ? 'name' : 'user_name'; + $popup_request_data = array( + 'call_back_function' => 'set_return', + 'form_name' => 'MassUpdate', + 'field_to_name_array' => array( + 'id' => "{$id_name}", + "$reportsDisplayName" => "{$varname}", + ), + ); + + $json = getJSONobj(); + $encoded_popup_request_data = $json->encode($popup_request_data); + + $qsName = array( + 'form' => 'MassUpdate', + 'method' => 'get_user_array', + 'modules' => array("{$mod_type}"), + 'group' => 'or', + 'field_list' => array('user_name', 'id'), + 'populate_list' => array("mass_{$varname}", "mass_{$id_name}"), + 'conditions' => array(array('name'=>'name','op'=>'like_custom','end'=>'%','value'=>'')), + 'limit' => '30','no_match_text' => $app_strings['ERR_SQS_NO_MATCH']); + $qsName = $json->encode($qsName); + // + /////////////////////////////////////// + + return <<$displayname + + +   + + + +EOHTML; + } + + + /** + * Add a generic module popup selection popup window HTML code. + * Currently supports Contact and Releases + * @param displayname Name to display in the popup window + * @param varname name of the variable + * @param id_name name of the id in vardef + * @param mod_type name of the module, either "Contact" or "Releases" currently + */ + function addGenericModuleID($displayname, $varname, $id_name='', $mod_type){ + global $app_strings; + + if(empty($id_name)) + $id_name = strtolower($mod_type)."_id"; + + /////////////////////////////////////// + /// + /// SETUP POPUP + + $popup_request_data = array( + 'call_back_function' => 'set_return', + 'form_name' => 'MassUpdate', + 'field_to_name_array' => array( + 'id' => "{$id_name}", + 'name' => "{$varname}", + ), + ); + + $json = getJSONobj(); + $encoded_popup_request_data = $json->encode($popup_request_data); + + $qsName = array( + 'form' => 'MassUpdate', + 'method' => 'query', + 'modules' => array("{$mod_type}"), + 'group' => 'or', + 'field_list' => array('name', 'id'), + 'populate_list' => array("mass_{$varname}", "mass_{$id_name}"), + 'conditions' => array(array('name'=>'name','op'=>'like_custom','end'=>'%','value'=>'')), + 'limit' => '30','no_match_text' => $app_strings['ERR_SQS_NO_MATCH']); + $qsName = $json->encode($qsName); + $img = SugarThemeRegistry::current()->getImageURL("id-ff-select.png"); + // + /////////////////////////////////////// + + return <<$displayname + + + + + + + +EOHTML; + } + /** + * Add Account selection popup window HTML code + * @param displayname Name to display in the popup window + * @param varname name of the variable + * @param id_name name of the id in vardef + */ + function addAccountID($displayname, $varname, $id_name=''){ + global $app_strings; + + $json = getJSONobj(); + + if(empty($id_name)) + $id_name = "account_id"; + + /////////////////////////////////////// + /// + /// SETUP POPUP + + $popup_request_data = array( + 'call_back_function' => 'set_return', + 'form_name' => 'MassUpdate', + 'field_to_name_array' => array( + 'id' => "{$id_name}", + 'name' => "{$varname}", + ), + ); + + $encoded_popup_request_data = $json->encode($popup_request_data); + + // + /////////////////////////////////////// + + $qsParent = array( + 'form' => 'MassUpdate', + 'method' => 'query', + 'modules' => array('Accounts'), + 'group' => 'or', + 'field_list' => array('name', 'id'), + 'populate_list' => array('parent_name', 'parent_id'), + 'conditions' => array(array('name'=>'name','op'=>'like_custom','end'=>'%','value'=>'')), + 'order' => 'name', + 'limit' => '30', + 'no_match_text' => $app_strings['ERR_SQS_NO_MATCH'] + ); + $qsParent['populate_list'] = array('mass_'. $varname, 'mass_' . $id_name); + $img = SugarThemeRegistry::current()->getImageURL("id-ff-select.png"); + $html = '' . $displayname . " \n" + . ' \n"; + $html .= ''; + + return $html; + } + + /** + * Add AssignedUser popup window HTML code + * @param displayname Name to display in the popup window + * @param varname name of the variable + */ + function addAssignedUserID($displayname, $varname){ + global $app_strings; + + $json = getJSONobj(); + + $popup_request_data = array( + 'call_back_function' => 'set_return', + 'form_name' => 'MassUpdate', + 'field_to_name_array' => array( + 'id' => 'assigned_user_id', + 'user_name' => 'assigned_user_name', + ), + ); + $encoded_popup_request_data = $json->encode($popup_request_data); + $qsUser = array( + 'form' => 'MassUpdate', + 'method' => 'get_user_array', // special method + 'field_list' => array('user_name', 'id'), + 'populate_list' => array('assigned_user_name', 'assigned_user_id'), + 'conditions' => array(array('name'=>'user_name','op'=>'like_custom','end'=>'%','value'=>'')), + 'limit' => '30','no_match_text' => $app_strings['ERR_SQS_NO_MATCH']); + + $qsUser['populate_list'] = array('mass_assigned_user_name', 'mass_assigned_user_id'); + $img = SugarThemeRegistry::current()->getImageURL("id-ff-select.png"); + $html = <<$displayname + + + +EOQ; + $html .= ''; + + return $html; + } + /** + * Add Status selection popup window HTML code + * @param displayname Name to display in the popup window + * @param varname name of the variable + * @param options array of options for status + */ + function addStatus($displayname, $varname, $options){ + global $app_strings, $app_list_strings; + + // cn: added "mass_" to the id tag to diffentieate from the status id in StoreQuery + $html = ''.$displayname.''; + if(is_array($options)){ + if(!isset($options['']) && !isset($options['0'])){ + $new_options = array(); + $new_options[''] = ''; + foreach($options as $key=>$value) { + $new_options[$key] = $value; + } + $options = $new_options; + } + $options = get_select_options_with_id_separate_key($options, $options, '', true);; + $html .= ''; + }else{ + $html .= $options; + } + $html .= ''; + return $html; + } + +/** + * Add Status selection popup window HTML code + * @param displayname Name to display in the popup window + * @param varname name of the variable + * @param options array of options for status + */ + function addBool($displayname, $varname){ + global $app_strings, $app_list_strings; + return $this->addStatus($displayname, $varname, $app_list_strings['checkbox_dom']); + } + function addStatusMulti($displayname, $varname, $options){ + global $app_strings, $app_list_strings; + + if(!isset($options['']) && !isset($options['0'])){ + $new_options = array(); + $new_options[''] = ''; + foreach($options as $key=>$value) { + $new_options[$key] = $value; + } + $options = $new_options; + } + $options = get_select_options_with_id_separate_key($options, $options, '', true);; + + // cn: added "mass_" to the id tag to diffentieate from the status id in StoreQuery + $html = ''.$displayname.' + '; + return $html; + } + /** + * Add Date selection popup window HTML code + * @param displayname Name to display in the popup window + * @param varname name of the variable + */ + function addDate($displayname, $varname){ + global $timedate; + $userformat = '('. $timedate->get_user_date_format().')'; + $cal_dateformat = $timedate->get_cal_date_format(); + global $app_strings, $app_list_strings, $theme; + + $javascriptend = << + Calendar.setup ({ + inputField : "${varname}jscal_field", daFormat : "$cal_dateformat", ifFormat : "$cal_dateformat", showsTime : false, button : "${varname}jscal_trigger", singleClick : true, step : 1, weekNumbers:false + }); + +EOQ; + $jscalendarImage = SugarThemeRegistry::current()->getImageURL('jscalendar.gif'); + $html = <<$displayname + + {$app_strings[ $userformat + $javascriptend + +EOQ; + return $html; + + } + + function addRadioenumItem($name, $value, $output) { + $_output = ''; + $_output .= '
+ +EOQ; + array_push($tab_names, $tab); + echo ''; + } // end $tabs foreach + if($showContainer) + { + echo ''; + + + if(!empty($selected_group)) + { + // closing table from tpls/singletabmenu.tpl + echo ''; + } + } + // drag/drop code + $tab_names = '["' . join($tab_names, '","') . '"]'; + global $sugar_config; + + if(empty($sugar_config['lock_subpanels']) || $sugar_config['lock_subpanels'] == false) { + echo << + var SubpanelInit = function() { + SubpanelInitTabNames({$tab_names}); + } + var SubpanelInitTabNames = function(tabNames) { + subpanel_dd = new Array(); + j = 0; + for(i in tabNames) { + subpanel_dd[j] = new ygDDList('whole_subpanel_' + tabNames[i]); + subpanel_dd[j].setHandleElId('subpanel_title_' + tabNames[i]); + subpanel_dd[j].onMouseDown = SUGAR.subpanelUtils.onDrag; + subpanel_dd[j].afterEndDrag = SUGAR.subpanelUtils.onDrop; + j++; + } + + YAHOO.util.DDM.mode = 1; + } + currentModule = '{$this->module}'; + YAHOO.util.Event.addListener(window, 'load', SubpanelInit); + +EOQ; + } + + $ob_contents = ob_get_contents(); + ob_end_clean(); + return $ob_contents; + } + + + function getLayoutManager() + { + require_once('include/generic/LayoutManager.php'); + if ( $this->layout_manager == null) { + $this->layout_manager = new LayoutManager(); + } + return $this->layout_manager; + } + + function get_buttons($thisPanel,$panel_query=null) + { + $subpanel_def = $thisPanel->get_buttons(); + $layout_manager = $this->getLayoutManager(); + $widget_contents = ''; + foreach($subpanel_def as $widget_data) + { + $widget_data['query']=urlencode($panel_query); + $widget_data['action'] = $_REQUEST['action']; + $widget_data['module'] = $thisPanel->get_inst_prop_value('module'); + $widget_data['focus'] = $this->focus; + $widget_data['subpanel_definition'] = $thisPanel; + $widget_contents .= ''; + } + + $widget_contents .= '
' . "\n"; + + if(empty($widget_data['widget_class'])) + { + $widget_contents .= "widget_class not defined for top subpanel buttons"; + } + else + { + $widget_contents .= $layout_manager->widgetDisplay($widget_data); + } + + $widget_contents .= '
'; + return $widget_contents; + } +} +?> diff --git a/include/SubPanel/SubPanelTilesTabs.php b/include/SubPanel/SubPanelTilesTabs.php new file mode 100644 index 00000000..186e2782 --- /dev/null +++ b/include/SubPanel/SubPanelTilesTabs.php @@ -0,0 +1,267 @@ +focus = $focus; + $this->id = $focus->id; + $this->module = $focus->module_dir; + $this->layout_def_key = $layout_def_key; + $this->subpanel_definitions = new SubPanelDefinitions($focus, $layout_def_key, $layout_def_override); + } + + function getSubpanelGroupLayout($selectedGroup) + { + global $current_user; + + $layoutParams = $this->module; + //WDong Bug: 12258 "All" tab in the middle of a record's detail view is not localized. + if($selectedGroup != translate('LBL_TABGROUP_ALL')) + { + $layoutParams .= ':'.$selectedGroup; + } + + // see if user current user has custom subpanel layout + return $current_user->getPreference('subpanelLayout', $layoutParams); + } + + function applyUserCustomLayoutToTabs($tabs, $key='All') + { + //WDong Bug: 12258 "All" tab in the middle of a record's detail view is not localized. + if($key=='All') + { + $key=translate('LBL_TABGROUP_ALL'); + } + $usersCustomLayout = SubPanelTilesTabs::getSubpanelGroupLayout($key); + if(!empty($usersCustomLayout)) + { + /* Return elements of the custom layout + * which occur in $tabs in unchanged order. + * Then append elements of $tabs which are + * not included in the layout. */ + $diff = array_diff($tabs, $usersCustomLayout); + $tabs = array_intersect($usersCustomLayout, $tabs); + foreach($diff as $subpanel) + { + $tabs []= $subpanel; + } + } + + return $tabs; + } + + /* + * Place subpanels into tabs for display on a DetailView + * @param array $tabs Array containing the ids of all subpanels to be placed into tabs + * @param boolean $showTabs Call the view code to display the generated tabs + * @param string $selectedGroup (Optional) Name of any selected tab (defaults to 'All') + */ + function getTabs($tabs, $showTabs = true, $selectedGroup='All') + { + //WDong Bug: 12258 "All" tab in the middle of a record's detail view is not localized. + if($selectedGroup=='All') + $selectedGroup=translate('LBL_TABGROUP_ALL'); + + require_once 'include/SubPanel/SubPanelDefinitions.php' ; + $spd = new SubPanelDefinitions ( $this->focus ) ; + + // Set up a mapping from subpanelID, found in the $tabs list, to the source module name + // As the $GLOBALS['tabStructure'] array holds the Group Tabs by module name we need to efficiently convert between the two + // when constructing the subpanel tabs + // Note that we can't use the very similar GroupedTabStructure class as it lacks this mapping, and logically, it is designed + // for use when constructing the module by module tabs, not the subpanel tabs, as we move away from using module names to represent + // subpanels, and use unique subpanel IDs instead. + + $moduleNames = array () ; + foreach ( $tabs as $subpanelID ) + { + $subpanel = $spd->load_subpanel( $subpanelID ); + if ($subpanel !== false) + $moduleNames [ $subpanelID ] = $subpanel->get_module_name() ; + } + + $groups = array () ; + $found = array () ; + + foreach( $GLOBALS['tabStructure'] as $mainTab => $subModules) + { + foreach( $subModules['modules'] as $key => $subModule ) + { + foreach ( $tabs as $subpanelID ) + if (isset($moduleNames[ $subpanelID ] ) && strcasecmp( $subModule , $moduleNames[ $subpanelID ] ) === 0) + { + $groups [ translate ( $mainTab ) ] [ 'modules' ] [ $key ] = $subpanelID ; + $found [ $subpanelID ] = true ; + break; + } + } + } + + // Put all the remaining subpanels into the 'Other' tab. + + foreach( $tabs as $subpanelID ) + { + if ( ! isset ( $found [ $subpanelID ] ) ) + $groups [ translate ('LBL_TABGROUP_OTHER') ]['modules'] [] = $subpanelID ; + } + + /* Move history to same tab as activities */ + if(in_array('history', $tabs) && in_array('activities', $tabs)) + { + foreach($groups as $mainTab => $group) + { + if(in_array('activities', array_map('strtolower', $group['modules']))) + { + if(!in_array('history', array_map('strtolower', $group['modules']))) + { + /* Move hist from there to here */ + $groups[$mainTab]['modules'] []= 'history'; + } + } + else if(false !== ($i = array_search('history', array_map('strtolower', $group['modules'])))) + { + unset($groups[$mainTab]['modules'][$i]); + if(empty($groups[$mainTab]['modules'])) + { + unset($groups[$mainTab]); + } + } + } + } + + /* Add the 'All' group. + * Note that if a tab group already exists with the name 'All', + * it will be overwritten in this union operation. + */ + if(count($groups) <= 1) + $groups = array(translate('LBL_TABGROUP_ALL') => array('label' => translate('LBL_TABGROUP_ALL'), 'modules' => $tabs)); + else + $groups = array(translate('LBL_TABGROUP_ALL') => array('label' => translate('LBL_TABGROUP_ALL'), 'modules' => $tabs)) + $groups; + /* Note - all $display checking and array_intersects with $tabs + * are now redundant (thanks to GroupedTabStructure), and could + * be removed for performance, but for now can stay to help ensure + * that the tabs get renedered correctly. + */ + + $retTabs = array(); + if($showTabs) + { + require_once('include/SubPanel/SugarTab.php'); + $sugarTab = new SugarTab(); + + $displayTabs = array(); + $otherTabs = array(); + + foreach ($groups as $key=>$tab) + { + $display = false; + foreach($tab['modules'] as $subkey=>$subtab) + { + if(in_array(strtolower($subtab), $tabs)) + { + $display = true; + break; + } + } + + $selected = ''; + + if($selectedGroup == $key) + { + $selected = 'current'; + } + + if($display) + { + $relevantTabs = SubPanelTilesTabs::applyUserCustomLayoutToTabs($tabs, $key); + + $sugarTabs[$key] = array(//'url'=>'index.php?module=' . $_REQUEST['module'] . '&record=' . $_REQUEST['record'] . '&action=' . $_REQUEST['action']. '&subpanel=' . $key.'#tabs', + //'url'=>"javascript:SUGAR.util.retrieveAndFill('index.php?to_pdf=1&module=MySettings&action=LoadTabSubpanels&loadModule={$_REQUEST['module']}&record={$_REQUEST['record']}&subpanel=$key','subpanel_list',null,null,null);", + 'label'=>( !empty($tab['label']) ? $tab['label']: $key ), + 'type'=>$selected); + + $otherTabs[$key] = array('key'=>$key, 'tabs'=>array()); + + $orderedTabs = array_intersect($relevantTabs, array_map('strtolower', $groups[$key]['modules'])); + + foreach($orderedTabs as $subkey => $subtab) + { + $otherTabs[$key]['tabs'][$subkey] = array('key'=>$subtab, 'label'=>translate($this->subpanel_definitions->layout_defs['subpanel_setup'][$subtab]['title_key'])); + } + + if($selectedGroup == $key) + { + $displayTabs = $otherTabs[$key]['tabs']; + $retTabs = $orderedTabs; + } + } + } + + if(empty($displayTabs) && !empty($otherTabs)) + { + //WDong Bug: 12258 "All" tab in the middle of a record's detail view is not localized. + $selectedGroup = translate('LBL_TABGROUP_ALL'); + $displayTabs = $otherTabs[$selectedGroup]['tabs']; + $sugarTabs[$selectedGroup]['type'] = 'current'; + $retTabs = array_intersect($tabs, array_map('strtolower', $groups[$selectedGroup]['modules'])); + } + + if (!empty($sugarTabs) || !empty($otherTabs) ) { + $sugarTab->setup($sugarTabs, $otherTabs, $displayTabs, $selectedGroup); + $sugarTab->display(); + } + } + else + { + $tabs = SubPanelTilesTabs::applyUserCustomLayoutToTabs($tabs, $selectedGroup); + + $retTabs = array_intersect($tabs, array_map('strtolower', $groups[$selectedGroup]['modules'])); + } + + return $retTabs; + } +} +?> diff --git a/include/SubPanel/SubPanelViewer.php b/include/SubPanel/SubPanelViewer.php new file mode 100644 index 00000000..587ab7e8 --- /dev/null +++ b/include/SubPanel/SubPanelViewer.php @@ -0,0 +1,92 @@ +retrieve($record); + +include('include/SubPanel/SubPanel.php'); +$layout_def_key = ''; +if(!empty($_REQUEST['layout_def_key'])){ + $layout_def_key = $_REQUEST['layout_def_key']; +} + +$subpanel_object = new SubPanel($module, $record, $subpanel,null, $layout_def_key); + +$subpanel_object->setTemplateFile('include/SubPanel/SubPanelDynamic.html'); +echo (empty($_REQUEST['inline']))?$subpanel_object->get_buttons():'' ; + +$subpanel_object->display(); + +if(empty($_REQUEST['inline'])) +{ + insert_popup_footer($theme); +} + +?> \ No newline at end of file diff --git a/include/SubPanel/SugarTab.php b/include/SubPanel/SugarTab.php new file mode 100644 index 00000000..9b896eb3 --- /dev/null +++ b/include/SubPanel/SugarTab.php @@ -0,0 +1,91 @@ +type = $type; + $this->ss = new Sugar_Smarty(); + } + + function setup($mainTabs, $otherTabs=array(), $subTabs=array(), $selected_group='All') + { + global $sugar_version, $sugar_config, $current_user; + + $max_tabs = $current_user->getPreference('max_tabs'); + if(!isset($max_tabs) || $max_tabs <= 0) $max_tabs = $GLOBALS['sugar_config']['default_max_tabs']; + + $moreTabs = array_slice($mainTabs,$max_tabs); + /* If the current tab is in the 'More' menu, move it into the visible menu. */ + if(!empty($moreTabs[$selected_group])) + { + $temp = array($selected_group => $mainTabs[$selected_group]); + unset($mainTabs[$selected_group]); + array_splice($mainTabs, $max_tabs-1, 0, $temp); + } + + $this->ss->assign('showLinks', 'false'); + $this->ss->assign('sugartabs', array_slice($mainTabs, 0, $max_tabs)); + $this->ss->assign('moreMenu', array_slice($mainTabs, $max_tabs)); + $this->ss->assign('othertabs', $otherTabs); + $this->ss->assign('startSubPanel', $selected_group); + $this->ss->assign('sugarVersionJsStr', "?s=$sugar_version&c={$sugar_config['js_custom_version']}"); + if(!empty($mainTabs)) + { + $mtak = array_keys($mainTabs); + $this->ss->assign('moreTab', $mainTabs[$mtak[min(count($mtak)-1, $max_tabs-1)]]['label']); + } + } + + function fetch() + { + return $this->ss->fetch('include/SubPanel/tpls/' . $this->type . '.tpl'); + } + + function display() + { + $this->ss->display('include/SubPanel/tpls/' . $this->type . '.tpl'); + } +} + + + +?> diff --git a/include/SubPanel/registered_layout_defs.php b/include/SubPanel/registered_layout_defs.php new file mode 100644 index 00000000..ecdcca3f --- /dev/null +++ b/include/SubPanel/registered_layout_defs.php @@ -0,0 +1,53 @@ + \ No newline at end of file diff --git a/include/SubPanel/subpanels.txt b/include/SubPanel/subpanels.txt new file mode 100644 index 00000000..f066cff5 --- /dev/null +++ b/include/SubPanel/subpanels.txt @@ -0,0 +1,471 @@ +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +SubPanel implementation: + + +Summary: + + DetailView pages now utilize the SubPanelTiles php class to display Subpanels of Related Objects. + Subpanels are generated asynchronously and on demand, and utilize an improved ListView class. + + +------------------------------------------------------------------------------- + +Class Heirarchy: + +DetailView -> SubPanelTiles ->(remotely calls) -> + SubPanelViewer -> SubPanel -> ListView -> (calls template) --> SubPanelDynamic.html + + +------------------------------------------------------------------------------- + +SubPanelTiles: + + The SubPanelTiles class creates the subpanel
s, outputs the javascript to manage loading/displaying panels, and displays tabs. + + - Each Subpanel is outputted as empty + + - When a tab is selected, or a subpanel to be maximized, the showSubPanel javascript function is called. + + - an asynchronous XMLHTTPRequest object is used to remotely fetch snippets of the SubPanel HTML. When the call + returns, the contents of the response from the server will be assigned to the innerHTML of the target
. + + - The XMLHTTPRequest calls the subpanel snippets with your normal Sugar URL with module/action/record + + + - The header/menu/footer panels are not displayed by adding to the query string: "&sugar_body_only=1&inline=1" + + - the "action" is SubPanelViewer, which of course causes Sugar to execute: + modules/$_REQUEST['module']/SubPanelViewer.php + + - SubPanelViewer.php files in every module directory usually just call include/SubPanel/SubPanelViewer.php and return. + + - SubPanelViewer acts as a wrapper around the SubPanel when it is called remotely. + + - The Top "Create" and "Select" buttons are generated inside the hide/display
, but outside of the div that holds + the innerHTML of the Subpanel listview. + + - the presence of, order of, and SugarWidget class of these buttons are controlled in the subpanel definitions. + + - (optional) The tabs are displayed using the SugarWidgetTabs class, which outputs the javascript/html. + + SugarWidgetTabs is generated by javascript, and tab selection is done by dynamically changing CSS attributes of the tabs. + + Someone using this class would pass it a php array of the tab definition. It is converted to javascript data object + definitions and outputted as javascript to the browser. The other input would be the name of the javascript callback function + that should be called when a tab is clicked. + + +------------------------------------------------------------------------------- + + +SubPanel Snippets: + + + SubPanel.php acts as a wrapper around ListView.php: + + - instantiates parent and related bean + + - gets subpanel definitions using a search path (custom, then module-specific, then global) + + - ListView manages sorting, paging and displaying the header and rows + + - SubPanel sets a flag in ListView that it knows to run dynamically + + - passes ListView the javascript link wrappers so that paging and sorting links will work correctly. + + The links will call a javascript function that will return the HTML to the subpanel
, + and not refresh the whole page + + - calls $ListView->loadListFieldDefs($list_fields,$child_focus); so that it can iterate through + the fields and display the appropriate widget and data + +------------------------------------------------------------------------------- + + ListView and SugarWidgets + + + - To generate the header and data cells, dynamic ListViews use SugarWidget singleton display functions. + + - as ListView prepares to display a cell, it looks at its corresponding field definition to + determine which SugarWidget to display. If there is no definition for the widget_class, then it + will default to displaying SugarWidgetField + + snippet: + list_field_defs as $list_field) + { + $list_field['fields'] = $fields; + $list_field['start_link_wrapper'] = $this->start_link_wrapper; + $list_field['end_link_wrapper'] = $this->end_link_wrapper; + + $widget_contents = $layout_manager->widgetDisplay($list_field); + + $this->xTemplate->assign('CELL', $widget_contents); + $this->xTemplate->parse($xtemplateSection.".row.cell"); + } + ?> + - a list_field definition example (from layout_defs.php) + + 'list_fields'=> array( + + array ( + + // use the 'ENCODED_NAME' key to get the data + 'varname'=>'ENCODED_NAME', + + // the key into the vardef.php definition + // also used as the sort order.. split that out + 'name'=>'last_name', + + // use this custom label in the header + 'vname'=>'LBL_LIST_NAME', + + // link this field + 'linked'=>true, + + // use this module because we are linking this field + 'module'=>'Contacts', + + ), + ), + + + - SugarWidgetField will call a different displayXXX() function depending on the context of the container. + + - if in the "HeaderCell" context, it calls $this->displayHeaderCell($args), which returns the HTML + content of the Header Cell + + - if in the "List" context, it calls $this->displayList($args), which returns the HTML content of + a data cell of the ListView. + + - Before ListView displays the widget for a cell, it attaches a pointer to the data for that + SugarBean instance. + + - if the field definition contains a link = true and a module attribute, then it will create a link + to the DetailView of the target SugarBean instance + + + - The edit and remove buttons in the row are also generated like the other cells except it uses + SugarWidgetSubPanelEditButton to display. The buttons are defined in the subpanel definition just like + the fields that are being displayed + + Selecting and deleting relationships: + + - When either a relationship is added via a popup, or the remove button is clicked, an async XMLHTTPRequest is called. + + - The contents of the request is a POST or GET that is constructed and send to the server. The return_url is set + + so that the server returns the Subpanel snippet, which is then added to the innerHTML of the calling subpanel + + +------------------------------------------------------------------------------ +Back end methods: + + + - When being used for Subpanels, ListView uses the get_related_list() method of the SugarBean Class to retrieve related objects. + + + - in $sugarbean->get_related_list(): + + // load relationship + $this->load_relationship($related_field_name); + + // now get the query that fetches related records: + $query_array = $this->$related_field_name->getQuery(true); + + - adding and deleting relationships are done through the include/generic/Save2.php and include/generic/DeleteRelationship.php + + - Link::add() and Link::delete() methods are the core functions that do the database work. + + +------------------------------------------------------------------------------- + +FILES: + +New: + +include/SubPanel/SubPanelDynamic.html + - the xtemplate file that provides the skeleton of the dynamic ListView + output + +include/SubPanel/SubPanel.php + - prepares ListView to output related objects, and within a
+ +include/SubPanel/SubPanelTiles.php + - includes tabs and each subpanel, and manages the show/hide and UI. + +include/SubPanel/SubPanelViewer.php + - wrapper for SubPanel.php when called remotely + +include/generic/DeleteRelationship.php + - generically deletes a relationship based on a parent focus, the linked_field, + and the linked id; + +include/generic/LayoutManager.php + - Factory class to provide singleton access and repository for SugarWidget + - provides global data registry that SugarWidgets can access + +include/generic/Save2.php + - generically adds a relationship using EditView form variables, but is + actually called via XMLHTTPRequest, and only tested with relationship + fields. + +include/generic/SugarWidgets/SugarWidget.php + - base class, defines display(), and holds a reference to the LayoutManager; + +include/generic/SugarWidgets/SugarWidgetField.php + - base class to represent database columns as UI widgets + +include/generic/SugarWidgets/SugarWidgetSubPanelTopButtons.php + - they are the "Create" and "Select" buttons + +include/generic/SugarWidgets/registered_widgets.php + - add new SugarWidget classes here + +include/generic/SugarWidgets/SugarWidgetDynamicTabs.php + - javascript generated tabs + +include/generic/SugarWidgets/SugarWidgetSubPanelEditButton.php + - holds both SugarWidgetSubPanelEditButton and + SugarWidgetSubPanelRemoveButton + - defines 'edit' and 'rem' buttons within the row on the right + +each module: + +modules/$module_name/Save2.php + - redirects to: include/generic/Save2.php + +modules/$module_name/layout_defs.php + - defines subpanels for each bean within this module directory + +modules/$module_name/SubPanelViewer.php + - redirects to: include/generic/SubPanelViewer.php + +modules/$module_name/SaveRelationship.php + - redirects to: include/generic/SaveRelationship.php + +CHANGED: + +modules/$module_name/DetailView.php + - contains SubPanelTiles + +include/ListView/ListView.php + - added: + loadListFieldDefs() + processHeaderDynamic() + getLayoutManager() + is_dynamic + + - changed: + processListRows() + processListViewTwo() + +data/SugarBean.php + - added: + get_related_list() + + + +------------------------------------------------------------------------------- + +TODO: + + + - Within the SugarWidgetField display() function, based on the field data type being displayed, call another SugarWidget + that can output it correctly + + - this includes checkboxes, dropdowns, relationships, dates, etc.. + + - do it throughout the rest of the modules + + - might need to change the how "create" button passes form data. + - make it more configurable so that it can pass custom form data from + focus bean + + - change how tabs are displayed/hidden. + + - right now it uses the linked_fields directly from the sugarbean + + - use the visible_subpanels definition in the layout_def.php, or just use the order in subpanel_defines itself. if you do + you have to add an order_index to each field and sort on that. maybe have a visible/hidden attribute + + - define custom titles in visible_subpanels, else fall back to subpanel string. + + - where do you put union subpanel definitions? change function that returns the definitions to another search path. + + - create special union subpanel type. + + - not just one focus, but an array of them, and some may have be the same class + + - make layout editor work with subpanel listviews + + +------------------------------------------------------------------------------- +PROBLEMS: + +- using firefox, when the "select" button is within the div that gets it's innerHTML + replaced, things break the second time you select a new relationship. it + fails on the window.open that is called with the popup_helper. some internal + mozilla error. + this is why the top buttons are in SubPanelTiles.php and not SubPanel.php + this needs to be resolve or else we will not be able to have popups that + cause refreshes. + + +sample layout_def: +------------------------------------------------------------------------------- + +$layout_defs['account'] = array( + + 'subpanel_setup' => array ( + + // sets up which panels to show, in which order, and with what + // linked_fields + 'show_subpanels' => array ( + array( + + /// which subpanel to show + 'subpanel_key'=>'opportunities', + + /// custom string for the title of this subpanel + 'string_key'=>'LBL_OPPORTUNITIES', + ), + ), + ), + + // defines the default subpanel definition for this SugarBean + 'default_subpanel_define' => array ( + 'class_name'=>array('Opportunity'), + + // define top left buttons + 'top_buttons'=>array( + array ( + 'widget_class'=>'SubPanelTopCreateButton', + ), + array ( + 'widget_class'=>'SubPanelTopSelectButton', + ), + ), + // define list fields + // yea, i know this will only show the Name + 'list_fields'=> array( + array ( + 'name'=>'name', + 'module'=>'Accounts', + 'linked'=>true, + ), + ), + ), + + // defines custom subpanel definitions for this SugarBean + 'subpanel_defines' => array ( + 'opportunities' => array ( + // define top left buttons + 'top_buttons'=>array( + array ( + 'widget_class'=>'SubPanelTopCreateButton', + ), + array ( + 'widget_class'=>'SubPanelTopSelectButton', + ), + ), + 'class_name'=>array('Opportunity'), + // define list fields + // this one displays the same fields as the original + 'list_fields'=> array( + array ( + 'name'=>'name', + 'module'=>'Opportunities', + 'linked'=>true, + ), + array ( + 'varname'=>'account_name', + 'vname'=>'LBL_LIST_ACCOUNT_NAME', + ), + array ( + 'name'=>'date_closed', + ), + array ( + 'widget_class'=>'SubPanelEditButton', + 'name'=>'edit_button', + ), + ), + ), + 'contact' => array ( + 'class_name'=>array('Opportunity'), + 'top_buttons'=>array( + array ( + 'widget_class'=>'SubPanelTopCreateButton', + ), + array ( + 'widget_class'=>'SubPanelTopSelectButton', + ), + ), + + // this one also displays the same fields as the original + 'list_fields'=> array( + array ( + 'varname'=>'ENCODED_NAME', + 'name'=>'last_name', + 'vname'=>'LBL_LIST_NAME', + 'module'=>'Contacts', + 'linked'=>true, + ), + array ( + 'varname'=>'ACCOUNT_NAME', + 'vname'=>'LBL_LIST_ACCOUNT_NAME', + ), + array ( + 'name'=>'email1', + ), + array ( + 'vname'=>'LBL_LIST_PHONE', + 'name'=>'phone_home', + ), + array ( + 'widget_class'=>'SubPanelEditButton', + 'name'=>'edit_button', + ), + array ( + 'widget_class'=>'SubPanelRemoveButton', + 'name'=>'remove_button', + ), + ), + ) + ) +); + diff --git a/include/SubPanel/tpls/singletabmenu.tpl b/include/SubPanel/tpls/singletabmenu.tpl new file mode 100644 index 00000000..1a51c40e --- /dev/null +++ b/include/SubPanel/tpls/singletabmenu.tpl @@ -0,0 +1,142 @@ +{* + +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + + + +*} + + + + + +{if !empty($sugartabs)} +
    +{foreach from=$sugartabs item=tab} +
  • + {$tab.label} +
  • +{/foreach} +{if !empty($moreMenu)} +
  • +
    + more +
    +
  • +{/if} +
+{* Table closed in SubPanelTiles.php, line 295 *} + + + pt zoobJ;1D>4Z$J^1k2%lCV!`_4p5Z-8r849-b1o8sw#G*GI~yrN!Iy z7W!t`lF^r+brfyZuM2iy7DBj&XfJWc-FYEjgHG0+@*%`s2y!OkNs2T}B&eK0F^(fg zcSuI}km-kuK|fcn2F*rJDtlBnrr(_Ii^j%jCp*6(+p^zPBbyTTN+?3Blwwfkw0Bp) zM+xBw+iwq4xQW%&-TGq&#?%MQ$tqiOv^aW(om%$<>(qPvPAx~LYRA`E_j07}8n`FL zh|OwWuyx-wNECbjG)VN7-N&XuA`NhKDkNQJOjv)yZ2hSB+WNyy@bPj4_mv?yR*vBQ zG6bI}NAR&S1fMKNaMW*9c#23Khl19Tl(if8dFpf;x7)DfckAiM@gS4jQ*$%tdEd-< z-XGwE)Q4b|O5C%)_CVK^3}=|h`)8KPj|K1?of>&so=4B1QIF0hA4h}oVW&n4sVI+? zxh;%c61Uh}4^Go>>C3W*ra{89)vbqT-nq;6)dy$WS09>fUwwG$uJ_<Nc$b?Lv|XQ z)ps+s)}!TG{-Hn~aX*iEc^(f3@~HFks4LIo-asBzejZijdE6Jsqu$S>zC4fn19{Z= zdDN8W@v%T2m3|(T<#`+p&LW?pFHOHH zB#ySUTk8sa#ua+p71Hbb>4^Bf70Xu=x#+^X&7r0D8~++{wbV21_6M3F>vO7|u%UKQ z4XjMqa%@9e#+N$6?2L`5WmE?`3Y1(rswJGhSXL~4?@ou@`P~>>!#Vylbs+p>$ zZ>FlCW~%cxQckESb6VfkPFC@G((rSA~S|_D#(E3v@!SkBW;(D9C z4VtMFXuX()8KGphM#R?QIm&)LgjBSz5?6SBUXa)V)Z9{1K@AoEaw=cOFt2#;0+ z&SGPEOzw~RZ2uHjyiRfr_X^XDCGEWfQR=G6fPGF+{zl3{6nA|fkVvHDL00%6D`!CU zybp4d4^nVLpy*$t`xCxS&zI@RA3~g#Rn4JSr0{U)8#3-y7v`%j%vW8Q|EE~#}!k3hVl3mwwccw3#qM4-=xm>E!tP~S8kc8pAtbIU%5y9wP)02=(l+!VLNi2 z1b)ZfsuS1j%60Z&rxl@F0=qpXDD03kBrS&CaO>2kq}B31eq(ei%PG1>1W!QOM6u`8qs#v^k%yD^ISV_ehGJ?orZ8 zF=szVl-kIWGro$5(IVahHF0<)UJ)i)Pn`iu7;h*EQSup8E!hlVZX-f#6#mE0g@Is!y zgi5B*>s^Oe$fFvH8U9xJ8axOWp6P?`V;JzG<2~}cg=^?5ch?P!o+B_^H%;Wy#nNsd z*Ur)a*;UmwoEf{u7IG>1-Ww@2p*Yf@pAH~I*3oK!#@@uFxXDxFA~@>Q!TF^>=vH;C(VQ(8M!XSLRV`MEsR$~hIy@Cs7}`A$UcgW z9IGC(!w0f8Cb;+4%d+q(J}ZUI%S2vgqSKcvyymb+IJ6b=ZbUC_g^#v^XqS5M>V0_i ziKTYY0i_D7BCcaBiF0LCcb2IOCY)n`(8=K@2y-tc3&f;nl%Cb}wCG89cUp~_@eZ_g z5&oTvzYtxoMMJRK4z|#<&BEJQ&k`e|=C${}yrRw!V5#G%@XgoWd;0%e`Kzxit6gyX z&sv_5W6okV=A5O*9P0WJh=88mbja0lndEFml29c3;dvqk5vKuS)r8N!`?%Bb9F>5k zx3@EeKZA3`I;bl5X*Ve~fi(?VQFJv^2~S0FI9*-=S;X|hnBE>2ahtUX+Y0JH+Ywj>^gCPUJ$^h)m-#*f{}1u4zIE{*JpRSdh96#ib>!Q!fJ;>Ym#6|#f^mpA zJ@(G)o=O#8&b{tBLE%(%A!1Ym#w!Caed=A`GG94*oqpcJsVLs2xxCg@NA`(7r^IrI zJx3fA;=UI}6J8{F?AS4AvpdfbXWd{lHJ0A<@TuRvdEkYH4w=PeDvRgHEQ+h1hb)z_v!o|7q%5$;;+De>DmkHuv7<25B)#A37 zKXLJkVjkGLj!-tUP_ES?l~l?u9D!DMB3+sI<7hMn4G*z5-S)HQmac;=QFt5pd18;a ztLG48l^dw+0_zPlpCH}aZ4in+y~qC zf8!7^Uk%_3MCUIH;$pn5{)vw3?)lQsLzt_{lPB?B^fmY2aZB^$b9W^XpHsR}rF4Pp zFIFqCzlel=BMbXODD0b{s?&u+er$)VTG=+EBet}Wl#Pyz;Bh_qF+3G0&~W`g2xTaw zu9rJoT`y-kSD|t!!ru@l$|7JF5JeRFb3sOea;LK9%GI>pFQSJ`S15v=r4l*|l)|7& zl5bdhAE1-uPT?2`Ezn_HF3wZ>rn>TmmgheEzPqk}?mNe&1id3jf=E4+1VO8j1pSfq zNbJMrl9B6gTW?FyJ4MG|{N3*V$$|jwy8h39rnl>-0eA_h0o6sQea}XB2e6*EtL_qOkE^q6aKPvP z=yN-K0kBf-I+!h~^LDUNZTsCmQ3q$IJhRZ%pW&H3$xujLYA9S2(*f^|tNaC3q%27^ z<-2doOVTN=mU*m!&J{2JL$3GTuRy7tyq}70z&fdhw!H0?*AMUNKIENG#o<5RhYFoA zVzf$@C|f7yBGKuy4xaq%1AlYJ-?ytn`hrOXld@Se3H5xU9zcnP@3h_EnNWdkCh6Po zil;A&x!%*Kw5lKToIm9`m`XM8wK&y-cDfcPdwdEVuiWvwn(eu|uo~E$_V>=!C`{8m z_jQAK;FLWw`wY(~jHsLx3EGSQ3n8b(VAzLn_LkyFl$oMWAtKV5Q6=xzjYvO|>!y45 zMk&;!WJrOyw&9SbY>v_tV3zeuo+sl_P7xHkJE?@!|bhSb{qqx)C5V z#gR;=PiVe`T7izSYc&w{+FyYBIK0wWEJs~+Y@RyNR`OBD;Htq|KUda%NAICJJJ30W zGx%Uy%8L8A+*~Prt#+vHTX}vi`@Nl$d+oz~or86?qjaY_DAzUvP^v7PkQlqJIfP3dKp(n(C!7EXQwh~oMmY8SFDWXGoTZ>$C3OOrGYFZPPVVo;y zvyzZnzzEYbqAg>@^!Wp80cYcI<>qFxC7y==hc5>v{t}kGG@h%>UqQG!sNdnMuQkh$ zEw<9amQ!q5I5#Ty0$kjp^1370Mr29sP?ES#O`kD#{rM1aS{OU}kD%b7dS{fUr1j|TC8_>bW3IEg)l+#Qp@Y@c%)CIwF3;qTX6?)$LZe{kM)F^~MBXX;@W z$8j}B%*-R+j_WOfxPe}ANNDD~>t@ND8qV=VeeI*EmtGRH^hABNaPpGY;*DoLAZFo- zdIddE7eZHA6#3kRf928!j%KYw2g0LZF%-+Yph)S;gZYX_*Ypo>v#;sx za51@-p2@Y;P}a57_`AE7=4ei(dgWSjSpTO}X{rSN)2Z}t>{P<_@5=?PU`N~4(#>6O z%wKfZ;qN_ATJyD^ES6Tq70Rl(T&?~shUYGabaHaC-ABt2M28VcQxCUyb2ls5IoK*tZeTI6*In*FBv zMs@^@u4=iChicQccqaug#k&cAjbAGsBkRv+7nv?Dp((hS%8-zfp9)0P{4SLVsZlA! zUvX61RH8d%h{KQJ8k$~yyMlcU00{2uFG~4*Zf|x3@4is=%D2nNdoVHw;ir#4_Wn&C z61z)j80+{QjmB{qD{ldkKRx5}#tC<$XlA6gg;O@vDmQKv`$tsb#dt`vlJYpTvWOKn zqJvYJa^Z*U;{sK^QkQS_WwmAs`nYqUg2#gO(rOv0^)af`Gg4nJBMno~PnQvg*1Zi| z=h8@fp&HPGBqa*Z$yH*Nny3*o_y2vtLgrE?v}?_>ow!Cqp~ROlXAcw; zuZUT%-4r%ia}VJjUJu&U-stPZj}-Eyd}(|nBer&TXG(ht`H>yD^gz)i12lK-&_SP! za0%`(1n(;}z{tCU?gq4YiXC!EN67hZEeum{T(rmiY5JG?+LbYzn`2bD{~rw75DgVS B*+l>V literal 0 HcmV?d00001 diff --git a/include/SugarDateTime.php b/include/SugarDateTime.php new file mode 100644 index 00000000..9b296ba7 --- /dev/null +++ b/include/SugarDateTime.php @@ -0,0 +1,584 @@ + "s", + "min" => "i", + "hour" => "G", + "zhour" => "H", + "day" => "j", + "zday" => "d", + "days_in_month" => "t", + "day_of_week" => "w", + "day_of_year" => "z", + "week" => "W", + "month" => "n", + "zmonth" => "m", + "year" => "Y", + "am_pm" => "A", + "hour_12" => "g", + ); + + protected $var_gets = array( + "24_hour" => "hour", + "day_of_week" => "day_of_week_long", + "day_of_week_short" => "day_of_week_short", + "month_name" => "month_long", + "hour" => "hour_12", + ); + + /** + * @var DateTimeZone + */ + protected static $_gmt; + + /** + * Calendar strings + * @var array + */ + protected $_strings; + + /** + * Copy of DateTime::createFromFormat + * + * Needed to return right type of the object + * + * @param string $format + * @param string $time + * @param DateTimeZone $timezone + * @return SugarDateTime + * @see DateTime::createFromFormat + */ + public static function createFromFormat($format, $time, DateTimeZone $timezone = null) + { + if(empty($time) || empty($format)) { + return false; + } + if(is_callable(array("DateTime", "createFromFormat"))) { + // 5.3, hurray! + if(!empty($timezone)) { + $d = parent::createFromFormat($format, $time, $timezone); + } else { + $d = parent::createFromFormat($format, $time); + } + } else { + // doh, 5.2, will have to simulate + $d = self::_createFromFormat($format, $time, $timezone); + } + if(!$d) { + return false; + } + $sd = new self("@".$d->getTimestamp()); + $sd->setTimezone($d->getTimezone()); + return $sd; + } + + protected static function _createFromFormat($format, $time, DateTimeZone $timezone = null) + { + $res = new self(); + if(!empty($timezone)) { + $res->setTimezone($timezone); + } + if(function_exists("strptime")) { + $str_format = str_replace(array_keys(TimeDate::$format_to_str), array_values(TimeDate::$format_to_str), $format); + // for a reason unknown to modern science, %P doesn't work in strptime + $str_format = str_replace("%P", "%p", $str_format); + // TODO: better way to not risk locale stuff problems? + $data = strptime($time, $str_format); + if(empty($data)) { + $GLOBALS['log']->error("Cannot parse $time for format $format"); + return null; + } + if($data["tm_year"] == 0) { + unset($data["tm_year"]); + } + if($data["tm_mday"] == 0) { + unset($data["tm_mday"]); + } + if(isset($data["tm_year"])) { + $data["tm_year"] += 1900; + } + if(isset($data["tm_mon"])) { + $data["tm_mon"]++; + } + $data += self::$data_init; // fill in missing parts + } else { + // Windows, etc. might not have strptime - we'd have to work harder here + $data = $res->_strptime($time, $format); + } + if(empty($data)) { + $GLOBALS['log']->error("Cannot parse $time for format $format"); + return null; + } + if(isset($data["tm_year"])) { + $res->setDate($data["tm_year"], $data["tm_mon"], $data["tm_mday"]); + } + $res->setTime($data["tm_hour"], $data["tm_min"], $data["tm_sec"]); + return $res; + } + + /** + * Load language strings + * @param string $name string section to return + * @return array + */ + protected function _getStrings($name) + { + if(empty($this->_strings)) { + $this->_strings = return_mod_list_strings_language($GLOBALS['current_language'],"Calendar"); + } + return $this->_strings[$name]; + } + + /** + * Fetch property of the date by name + * @param string $var Property name + */ + public function __get($var) + { + // simple formats + if(isset($this->formats[$var])) { + return $this->format($this->formats[$var]); + } + // conditional, derived and translated ones + switch($var) { + case "ts": + return $this->getTimestamp(); + case "tz_offset": + return $this->getTimezone()->getOffset($this); + case "days_in_year": + return $this->format("L") == '1'?366:365; + break; + case "day_of_week_short": + $str = $this->_getStrings('dom_cal_weekdays'); + return $str[$this->day_of_week]; + case "day_of_week_long": + $str = $this->_getStrings('dom_cal_weekdays_long'); + return $str[$this->day_of_week]; + case "month_short": + $str = $this->_getStrings('dom_cal_month'); + return $str[$this->month]; + case "month_long": + $str = $this->_getStrings('dom_cal_month_long'); + return $str[$this->month]; + } + + return ''; + } + + /** + * Implement some get_ methods that fetch variables + * + * @param string $name + * @param array $args + */ + public function __call($name, $args) + { + // fill in 5.2.x gaps + if($name == "getTimestamp") { + return (int)$this->format('U'); + } + if($name == "setTimestamp") { + $sec = (int)$args[0]; + $sd = new self("@$sec"); + $sd->setTimezone($this->getTimezone()); + return $sd; + } + + // getters + if(substr($name, 0, 4) == "get_") { + $var = substr($name, 4); + + if(isset($this->var_gets[$var])) { + return $this->__get($this->var_gets[$var]); + } + + if(isset($this->formats[$var])) { + return $this->__get($var); + } + } + $GLOBALS['log']->fatal("SugarDateTime: unknowm method $name called"); + sugar_die("SugarDateTime: unknowm method $name called"); + return false; + } + + /** + * Get specific hour of today + * @param int $hour_index + * @return SugarDateTime + */ + public function get_datetime_by_index_today($hour_index) + { + if ( $hour_index < 0 || $hour_index > 23 ) + { + sugar_die("hour is outside of range"); + } + + $newdate = clone $this; + $newdate->setTime($hour_index, 0, 0); + return $newdate; + } + + function get_hour_end_time() + { + $newdate = clone $this; + $newdate->setTime($this->hour, 59, 59); + return $newdate; + } + + function get_day_end_time() + { + $newdate = clone $this; + return $newdate->setTime(23, 59, 59); + } + + function get_day_by_index_this_week($day_index) + { + $newdate = clone $this; + $newdate->setDate($this->year, $this->month, $this->day + + ($day_index - $this->day_of_week))->setTime(0,0); + return $newdate; + } + + function get_day_by_index_this_year($month_index) + { + $newdate = clone $this; + $newdate->setDate($this->year, $month_index+1, 1); + $newdate->setDate($newdate->year, $newdate->month, $newdate->days_in_month); + $newdate->setTime(0, 0); + return $newdate; + } + + function get_day_by_index_this_month($day_index) + { + $newdate = clone $this; + return $newdate->setDate($this->year, $this->month, $day_index+1)->setTime(0, 0); + } + + /** + * Get new date, modified by date expression + * + * @example $yesterday = $today->get("yesterday"); + * + * @param string $expression + * @return SugarDateTime + */ + function get($expression) + { + $newdate = clone $this; + $newdate->modify($expression); + return $newdate; + } + + /** + * Display as DB date + * @return string + */ + function get_mysql_date() + { + return $this->format(TimeDate::DB_DATE_FORMAT); + } + + /** + * Create from ISO 8601 datetime + * @param string $str + * @return SugarDateTime + */ + static public function parse_utc_date_time($str) + { + return new self($str); + } + + /** + * Create a list of time slots for calendar view + * Times must be in user TZ + * @param string $view Which view we are using - day, week, month + * @param SugarDateTime $start_time Start time + * @param SugarDateTime $end_time End time + */ + static function getHashList($view, $start_time, $end_time) + { + $hash_list = array(); + + if ( $view != 'day') + { + $end_time = $end_time->get_day_end_time(); + } + + $end = $end_time->ts; + if($end <= $start_time->ts) { + $end = $start_time->ts+1; + } + + $new_time = clone $start_time; + $new_time->setTime($new_time->hour, 0, 0); + + while ($new_time->ts < $end) { + if ($view == 'day') { + $hash_list[] = $new_time->get_mysql_date() . ":" . $new_time->hour; + $new_time->modify("next hour"); + } else { + $hash_list[] = $new_time->get_mysql_date(); + $new_time->modify("next day"); + } + } + + return $hash_list; + } + + /** + * Get the beginning of the given day + */ + function get_day_begin($day = null, $month = null, $year = null) + { + $newdate = clone $this; + $newdate->setDate( + $year?$year:$this->year, + $month?$month:$this->month, + $day?$day:$this->day); + $newdate->setTime(0, 0); + return $newdate; + } + + /** + * Get the last timestamp of the given day + */ + function get_day_end($day = null, $month = null, $year = null) + { + $newdate = clone $this; + $newdate->setDate( + $year?$year:$this->year, + $month?$month:$this->month, + $day?$day:$this->day); + $newdate->setTime(23, 59, 59); + return $newdate; + } + + function get_year_begin($year) + { + $newdate = clone $this; + $newdate->setDate($this->year, 1, 1); + $newdate->setTime(0,0); + return $newdate; + } + /* + * Print datetime in standard DB format + * + * Set $tz parameter to false if you are sure if the date is in UTC. + * + * @param bool $tz do conversion to UTC + * @return string + */ + function asDb($tz = true) + { + if($tz) { + if(empty(self::$_gmt)) { + self::$_gmt = new DateTimeZone("UTC"); + } + $this->setTimezone(self::$_gmt); + } + return $this->format(TimeDate::DB_DATETIME_FORMAT); + } + + /** + * Get query string for the date + * @return string + */ + function get_date_str() + { + return sprintf("&year=%d&month=%d&day=%d&hour=%d", $this->year, $this->month, $this->day, $this->hour); + } + + function __toString() + { + return $this->format('r'); + } + + protected static $parts_match = array( + 'Y' => 'tm_year', + 'm' => 'tm_mon', + 'n' => 'tm_mon', + 'd' => 'tm_mday', + 'H' => 'tm_hour', + 'h' => 'tm_hour', + 'i' => 'tm_min', + 's' => 'tm_sec', + ); + + protected static $data_init = array( + "tm_hour" => 0, + "tm_min" => 0, + "tm_sec" => 0, + ); + + protected static $strptime_short_mon, $strptime_long_mon; + /** + * DateTime homebrew parser + * + * Since some OSes and PHP versions (please upgrade to 5.3!) do not support built-in parsing functions, + * we have to restort to this ugliness. + * + * @param string $format + * @param string $time + * @return array Parsed parts + */ + protected function _strptime($time, $format) + { + $data = self::$data_init; + if(empty(self::$strptime_short_mon)) { + self::$strptime_short_mon = array_flip($this->_getStrings('dom_cal_month')); + unset(self::$strptime_short_mon[""]); + } + if(empty(self::$strptime_long_mon)) { + self::$strptime_long_mon = array_flip($this->_getStrings('dom_cal_month_long')); + unset(self::$strptime_long_mon[""]); + } + + $regexp = TimeDate::get_regular_expression($format); + if(!preg_match('@'.$regexp['format'].'@', $time, $dateparts)) { + return false; + } + + foreach(self::$parts_match as $part => $datapart) { + if (isset($regexp['positions'][$part]) && isset($dateparts[$regexp['positions'][$part]])) { + $data[$datapart] = (int)$dateparts[$regexp['positions'][$part]]; + } + } + // now process non-numeric ones + if ( isset($regexp['positions']['F']) && !empty($dateparts[$regexp['positions']['F']])) { + // FIXME: locale? + $mon = $dateparts[$regexp['positions']['F']]; + if(isset(self::$sugar_strptime_long_mon[$mon])) { + $data["tm_mon"] = self::$sugar_strptime_long_mon[$mon]; + } else { + return false; + } + } + if ( isset($regexp['positions']['M']) && !empty($dateparts[$regexp['positions']['M']])) { + // FIXME: locale? + $mon = $dateparts[$regexp['positions']['M']]; + if(isset(self::$sugar_strptime_short_mon[$mon])) { + $data["tm_mon"] = self::$sugar_strptime_short_mon[$mon]; + } else { + return false; + } + } + if ( isset($regexp['positions']['a']) && !empty($dateparts[$regexp['positions']['a']])) { + $ampm = $dateparts[$regexp['positions']['a']]; + if($ampm == 'pm') { + if($data["tm_hour"] != 12) $data["tm_hour"] += 12; + } else if($ampm == 'am') { + if($data["tm_hour"] == 12) { + // 12:00am is 00:00 + $data["tm_hour"] = 0; + } + } else { + return false; + } + } + + if ( isset($regexp['positions']['A']) && !empty($dateparts[$regexp['positions']['A']])) { + $ampm = $dateparts[$regexp['positions']['A']]; + if($ampm == 'PM') { + if($data["tm_hour"] != 12) $data["tm_hour"] += 12; + } else if($ampm == 'AM') { + if($data["tm_hour"] == 12) { + // 12:00am is 00:00 + $data["tm_hour"] = 0; + } + } else { + return false; + } + } + + return $data; + } + + // 5.2 compatibility - 5.2 functions don't return $this, let's help them + + /** + * (non-PHPdoc) + * @see DateTime::setDate() + * @return SugarDateTime + */ + public function setDate ($year, $month, $day) + { + parent::setDate($year, $month, $day); + return $this; + } + + /** + * (non-PHPdoc) + * @see DateTime::setTime() + * @return SugarDateTime + */ + public function setTime($hour, $minute, $sec = 0) + { + parent::setTime($hour, $minute, $sec); + return $this; + } + + /** + * (non-PHPdoc) + * @see DateTime::modify() + * @return SugarDateTime + */ + public function modify($modify) + { + if(PHP_VERSION_ID >= 50300 || $modify != 'first day of next month') { + parent::modify($modify); + } else { + /* PHP 5.2 does not understand 'first day of' and defaults need it */ + $this->setDate($this->year, $this->month+1, 1); + } + return $this; + } + + /** + * (non-PHPdoc) + * @see DateTime::setTimezone() + * @return SugarDateTime + */ + public function setTimezone (DateTimeZone $timezone) + { + parent::setTimezone($timezone); + return $this; + } + +} diff --git a/include/SugarDependentDropdown/SugarDependentDropdown.php b/include/SugarDependentDropdown/SugarDependentDropdown.php new file mode 100644 index 00000000..8a742b11 --- /dev/null +++ b/include/SugarDependentDropdown/SugarDependentDropdown.php @@ -0,0 +1,334 @@ + '', + 'id' => '', + 'type' => 'none', // form element, valid "select", "input", "checkbox", "none" + 'label_pos' => 'left', // valid: 'left', 'right', 'top', 'bottom', 'none' (none) + 'hidden' => array(), // metadata to create hidden fields with values you choose + ); + + /* + * Fields that must exist in an element (single dropdown/field) metadata + * array. + */ + var $elementRequired = array( + 'name', + 'id', + //'values', + //'onchange', + //'force_render', + ); + + /** + * Fields that will be merged down into individual elements and handlers + */ + var $alwaysMerge = array( + 'force_render', + ); + + /* + * Valid 'types' for a dependent dropdown + */ + var $validTypes = array( + "select", // select dropdown + "input", // text input field + "checkbox", // checkbox (radio buttons will not be supported) + "none", // blank + "multiple" // custom functionality + ); + + /** + * Sole constructor + * @param string $metadata Path to metadata file to consume + */ + function SugarDependentDropdown($metadata='') { + if(!empty($metadata)) { + $this->init($metadata); + } + } + + /** + * Prepares an instance of SDD for use with a given set + * @param string $metadata Path to metadata file to consume + */ + function init($metadata) { + if(is_string($metadata)) { + if($this->debugMode) { + $this->debugOutput("Got metadata file [ {$metadata} ]"); + } + if(file_exists($metadata)) { + $sugarDependentDropdown = array(); + /* + * The metadata file should be prepped in an associative array. + * The array should be named "$sugarDependentDropdown". + * + * Examine: + * "include/SugarDependentDropdown/metadata/dependentDropdown. + * php" for a commented example. + */ + include($metadata); // provides $sugarDependentDropdown + + foreach($sugarDependentDropdown as $key => $type) { + if(is_array($type)) { + foreach($type as $k => $v) { + if($k == 'elements') { + ksort($v); // order elements + foreach($v as $index => $element) { + $v[$index] = $this->initElement($element, $type['always_merge']); + } + } // end Work with elements block + $type[$k] = $v; + } + + if(!$this->verifyMetadata($type)) { + if($this->debugMode) { + $this->debugOutput("SugarRouting: metadata initialization failed. Please check your metadata source."); + } + } + } + $sugarDependentDropdown[$key] = $type; + } // end foreach of metadata + + /* we made it through all checks so assign this to the output attribute */ + $this->metadata = $sugarDependentDropdown; + } // end file_exists(); + else { + if($this->debugMode) $this->debugOutput("SugarRouting could not find file [ {$metadata} ]"); + } + } // end is_string(); + } // end init() + + + /////////////////////////////////////////////////////////////////////////// + //// PRIVATE UTILS + /** + * Verifies that an element is valid and has all the required info. + */ + function isValidElement($element) { + if(is_array($element)) { + foreach($this->elementRequired as $k => $req) { + if(!array_key_exists($req, $element) && !isset($element['handlers'])) { + if($this->debugMode) { + $this->debugOutput("Element is missing required field: [ $req ]"); + $this->debugOutput($element); + } + return false; + } + } + return true; + } + + if($this->debugMode) { + $this->debugOutput("isValidElement is returning false. Passed the following as an argument:"); + $this->debugOutput($element); + } + return false; + } + + /** + * Initializes an element for processing + * @param array $element Element metadata + * @return array + */ + function initElement($element, $alwaysMerge) { + if($this->isValidElement($element)) { + $mergedElement = sugarArrayMerge($this->defaults, $element); + + foreach($alwaysMerge as $key => $val) { + if(!isset($mergedElement[$key])) + $mergedElement[$key] = $val; + } + + if($this->debugMode) { + foreach($this->elementRequired as $k => $v) { + if(!array_key_exists($v, $mergedElement) && !isset($mergedElement['handlers'])) { + $this->debugOutput("Element is missing required field after initialization: [ $v ]."); + } + } + } + + // iterate through "handlers - mini-elements" + if(isset($mergedElement['handlers'])) { + if(is_array($mergedElement['handlers']) && !empty($mergedElement['handlers'])) { + foreach($mergedElement['handlers'] as $miniKey => $miniElement) { + // apply parent element's properties to mini-element + foreach($mergedElement as $key => $el) { + if($key != 'handlers' && (!isset($miniElement[$key]))) {// || empty($miniElement[$key]) + $miniElement[$key] = $mergedElement[$key]; + } + } + + $miniElement = $this->initElement($miniElement, $alwaysMerge); + $mergedElement['handlers'][$miniKey] = $miniElement; + } + } else { + if($this->debugMode) { + $this->debugOutput("SugarRouting: element contains 'handlers' but is not an array:"); + $this->debugOutput($mergedElement); + } + } + } + + return $mergedElement; + } else { + if($this->debugMode) { + $this->debugOutput("SugarRouting is trying to initialize a non-element:"); + $this->debugOutput($element); + } + } + } + + /** + * Verifies that required metadata is present for all dependencies. Called after all metadata defaults are merged + * and the final array is created. + * @param array $metadata + * @return bool + */ + function verifyMetadata($metadata) { + if(isset($metadata['elements']) && !empty($metadata['elements']) && is_array($metadata['elements'])) { + $elements = $metadata['elements']; + + foreach($elements as $indexName => $element) { + /* confirm each element has a valid type */ + if(!isset($element['type']) && in_array($element['type'], $this->validTypes)) { + if($this->debugMode) { + $this->debugOutput("SugarRouting: valid 'type' not found:"); $this->debugOutput($element); + } + return false; + } + + /************************************************ + * Check based on "type" + */ + switch($element['type']) { + case "select": + if(isset($element['values'])) { + $index = substr($indexName, 7, strlen($indexName)); + + + /* if we have an array to iterate through - this is not the case with lazy-loaded values */ + if(is_array($element['values']) && !empty($element['values'])) { + $index++; // string to int conversion, i know, sucks + $nextElementKey = "element".$index; + $nextElement = $elements[$nextElementKey]; + + foreach($element['values'] as $key => $value) { + if(!array_key_exists($key, $nextElement['handlers'])) { + if($this->debugMode) { + $this->debugOutput("SugarRouting: next-order element is missing a handler for value: [ {$key} ]"); + $this->debugOutput($elements); + $this->debugOutput($nextElement); + } + return false; + } + } + } + } else { + if($this->debugMode) { + $this->debugOutput("SugarRouting: 'select' element found, no 'values' defined."); $this->debugOutput($element); + } + return false; + } + break; // end "select" check + } + + /* + * Handler "handlers" mini-element metadata definition verification + */ + if(isset($element['handlers']) && !empty($element['handlers'])) { + // fake metadata container + $fakeMetadata = array('elements' => null); + $fakeMetadata['elements'] = $element['handlers']; + $result = $this->verifyMetadata($fakeMetadata); + + if(!$result) { + if($this->debugMode) { + $this->debugOutput("SugarRouting: metadata verification for 'handlers' failed: "); $this->debugOutput($fakeMetadata); + } + return false; + } + } + } + + if($this->debugMode) { + $this->debugOutput((count($metadata) > 1) ? "SugarRouting: all checks passed, valid metadata confirmed" : "SugarRouting: 'handlers' checks passed, valid metadata confirmed."); + } + return true; + } else { + if($this->debugMode) { + $this->debugOutput("SugarRouting: Your metadata does not contain a valid 'elements' array:");$this->debugOutput($metadata); + } + } + return false; + } + + /** + * Prints debug messages to the screen + * @param mixed + */ + function debugOutput($v) { + echo "\n
\n";
+		print_r($v);
+		echo "\n
\n"; + } + //// END PRIVATE UTILS + /////////////////////////////////////////////////////////////////////////// +} // end Class def \ No newline at end of file diff --git a/include/SugarDependentDropdown/javascript/SugarDependentDropdown.js b/include/SugarDependentDropdown/javascript/SugarDependentDropdown.js new file mode 100644 index 00000000..77e97c7b --- /dev/null +++ b/include/SugarDependentDropdown/javascript/SugarDependentDropdown.js @@ -0,0 +1,52 @@ +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ +SUGAR.dependentDropdown={currentAction:null,debugMode:false} +SUGAR.dependentDropdown.handleDependentDropdown=function(el){} +SUGAR.dependentDropdown.generateElement=function(focusElement,elementRow,index,elementIndex){if(SUGAR.dependentDropdown.debugMode)SUGAR.dependentDropdown.utils.debugStack('generateElement');var tmp=null;if(focusElement){var sandbox=SUGAR.dependentDropdown.utils.generateElementContainer(focusElement,elementRow,index,elementIndex);if(focusElement.label){focusLabel={tag:'span',cls:'routingLabel',html:" "+focusElement.label+" "} +switch(focusElement.label_pos){case"top":focusLabel.html=focusElement.label+"
";break;case"bottom":focusLabel.html="
"+focusElement.label;break;} +if(focusElement.label_pos=='left'||focusElement.label_pos=='top'){YAHOO.ext.DomHelper.append(sandbox,focusLabel);}} +switch(focusElement.type){case'input':if(typeof(focusElement.values)=='string'){focusElement.values=eval(focusElement.values);} +var preselect=SUGAR.dependentDropdown.utils.getPreselectKey(focusElement.name);if(preselect.match(/::/)) +preselect='';tmp=YAHOO.ext.DomHelper.append(sandbox,{tag:'input',id:focusElement.grouping+"::"+index+":::"+elementIndex+":-:"+focusElement.id,name:focusElement.grouping+"::"+index+"::"+focusElement.name,cls:'input',onchange:focusElement.onchange,value:preselect},true);var newElement=tmp.dom;break;case'select':tmp=YAHOO.ext.DomHelper.append(sandbox,{tag:'select',id:focusElement.grouping+"::"+index+":::"+elementIndex+":-:"+focusElement.id,name:focusElement.grouping+"::"+index+"::"+focusElement.name,cls:'input',onchange:focusElement.onchange},true);var newElement=tmp.dom;if(typeof(focusElement.values)=='string'){focusElement.values=eval(focusElement.values);} +var preselect=SUGAR.dependentDropdown.utils.getPreselectKey(focusElement.name);var i=0;for(var key in focusElement.values){var selected=(preselect==key)?true:false;newElement.options[i]=new Option(focusElement.values[key],key,selected);if(selected){newElement.options[i].selected=true;} +i++;} +break;case'none':break;case'checkbox':alert('implement checkbox pls');break;case'multiple':alert('implement multiple pls');break;default:if(SUGAR.dependentDropdown.dropdowns.debugMode){alert("Improper type defined: [ "+focusElement.type+"]");} +return;break;} +if(focusElement.label){if(focusElement.label_pos=='right'||focusElement.label_pos=='bottom'){YAHOO.ext.DomHelper.append(sandbox,focusLabel);}} +try{newElement.onchange();}catch(e){if(SUGAR.dependentDropdown.dropdowns.debugMode){debugger;}}}else{}} +SUGAR.dependentDropdown.utils={generateElementContainer:function(focusElement,elementRow,index,elementIndex){var oldElement=document.getElementById('elementContainer'+focusElement.grouping+"::"+index+":::"+elementIndex);if(oldElement){SUGAR.dependentDropdown.utils.removeChildren(oldElement);} +var tmp=YAHOO.ext.DomHelper.append(elementRow,{tag:'span',id:'elementContainer'+focusElement.grouping+"::"+index+":::"+elementIndex},true);return tmp.dom;},getPreselectKey:function(elementName){try{if(SUGAR.dependentDropdown.currentAction.action[elementName]){return SUGAR.dependentDropdown.currentAction.action[elementName];}else{return'';}}catch(e){if(SUGAR.dependentDropdown.dropdowns.debugMode){} +return'';}},debugStack:function(func){if(!SUGAR.dependentDropdown._stack){SUGAR.dependentDropdown._stack=new Array();} +SUGAR.dependentDropdown._stack.push(func);},removeChildren:function(el){for(i=el.childNodes.length-1;i>=0;i--){if(el.childNodes[i]){el.removeChild(el.childNodes[i]);}}}} \ No newline at end of file diff --git a/include/SugarDependentDropdown/metadata/dependentDropdown.php b/include/SugarDependentDropdown/metadata/dependentDropdown.php new file mode 100644 index 00000000..98289219 --- /dev/null +++ b/include/SugarDependentDropdown/metadata/dependentDropdown.php @@ -0,0 +1,343 @@ +getActionsDOM(); + +$strings = array(); +foreach($app_strings as $k => $v) { + if(strpos($k, "LBL_ROUTING_") !== false) { + $strings[$k] = $v; + } +} + + +$sugarDependentDropdown = array( + /* + * Turn on heavy logging and report errors + */ + 'debugMode' => false, + + /** + * This is the actions' dependent dropdown metadata for Email 2.0's Rules + * Wizard + */ + 'actions' => array( + /* + * The array values below will be merged into all elements and handlers. + * This is a good way to set a global that is overridable at the + * individual element level. + */ + 'always_merge' => array( + /* + * This flag tells the render engine to display all elements when + * called. If set to 'false', the engine will allow 'onchange' calls to + * render subsequent elements. + */ + 'force_render' => false, + /* + * Used by Email 2.0 - this helps zero in on the DD-type when we + * merge it with a saved Rule. + */ + 'actionType' => 'actions', + /* + * User defined function to call when an element's value is changed + * (select type only) + */ + 'onchange' => '', + ), + /* + * This array will contain as many elements as there are dependencies. It + * will be iterated through. The key is used for ordering; the SDD class + * will ksort() this array + */ + 'elements' => array( + /* + * Initial dropdown. Define the necessaries. + */ + 'element0' => array( + /* + * 'name' will be prepended by the 'grouping' value and a delimiter "::". It then will be prepended by + * a numeric index in increments of 100. If the user inserts actions inbetween retrieved action rows, + * the index will be 1/2 of the delta (i. e., "50" if inserted between index 0 and index 100). + * + * This element will have the following as it's name in the form: + * "actionGroup::0::action0" + * Subsequent elements will have the following: + * "actionGroup::100::action0" + */ + 'name' => 'action0', // name of form element + /* + * The above applies to "id" in addition to: + * "id" will further be appended by ":::" and a numeric index in increments of 1 (0, 1, 2, 3, etc). This is + * to allow us to identify which element is currently being acted upon. + * + * The example below will ultimately have the id "actionGroup::0::action0" in the DOM. + */ + 'id' => 'action0', // id of form element - an internal index will be appended to this value 0, 100, 200, etc. + /* + * 'type' denotes what kind of form element you wish to display. Of course "select" (drop-down) is the + * default. + * Valid values are "select" | "input" (text) | "checkbox" | "none". + */ + 'type' => 'select', + /* + * If using multiple dependent-dropdowns on a single page, you + * must differentiate them via this flag. This value is + * arbitrary, but must be different from other sets of DDs. + */ + 'grouping' => 'actionGroup', + /* + * In the interests of keeping this simple, you can pass an associative array as the argument for values. + * However, you may also pass a string which will be eval()'d in JS. You can write a custom function to + * return a Javascript object as an associative array which will be iterated over and rendered as options + * for a dropdown. The return must be a JS object. + */ + 'values' => $actions, // assoc array of dropdown values, if a STRING, it will be eval'd to lazy load the values + /* + * The 'selected' value must match one of the keys in the above array. If lazy-loading through a JS + * call, there is a chance race-condition that may result in the selected value not being defaulted. In + * this case, preload the values into local memory and retrieve via a non-async JS call. + */ + 'selected' => '', // initially selected value (key value) + /* + * This attribute should map to a JS method/function that is loaded and available. It will be called on + * initialization and can cascade the results to this element's children (this is how Email 2.0 Rules + * Wizard works). If force_render is set to true, this call will still be made. + */ + 'onchange' => 'SUGAR.routing.handleDependentDropdown(this, \'actions\');', // javascript onchange() call + /* + * The text that can accompany this element. Any string value is valid. Simple HTML formatting will be + * honored (, , , etc.). + */ + 'label' => ' ', + /* + * This attribute dictates where the above text will display relative to this element. Valid values are + * "top" | "bottom" | "left" | "right" + */ + 'label_pos' => 'left', + ), + + /* + * Subsequent dropdown/form elements must contain an array keyed to dropdown1's selected value. + * I.e.: + * if 'values' is + * array( + * 'option1' => 'This is option one', + * 'option2' => 'This is option two', + * ); + * dropdown2 must contain an array 'handlers' keyed by "option1" and "option2" + */ + 'element1' => array( + 'name' => 'action1', // name of form element + 'id' => 'action1', // id of form element - an internal index will be appended to this value 0, 100, 200, etc. + 'label' => '', // label to be displayed next/above dropdown + 'label_pos' => 'none', // default 'left' + 'grouping' => 'actionGroup', + /* + * Correspond to the values in the preceding element for dependencies + * - will be merged with parent's values (minus 'handlers' values) + * - keys will override parent values + */ + 'handlers' => array( + /* + * If the selected value is all that you are interested in, + * create blank arrays like below. In this particular case + * the form element "action1" will hold the value + * "mark_read" which will be passed when the form is + * submitted. + */ + 'mark_read' => array(), + 'mark_unread' => array(), + 'mark_flagged' => array(), + /* + * If further processing is required (like more dropdowns + * or input fields), create handlers that have "onchange" + * handlers to further process subsequent elements. + * + * See SUGAR.routing.handleDependentDropdown() found in + * "include/SugarDependentDropdown/javascript/SugarDependentDropdown. + * js" for an example of how to continue cascading the + * dropdowns. + */ + 'move_mail' => array( + //'name' => 'move_email_select', + 'type' => 'select', // create a 2nd order dropdown + 'values' => 'SUGAR.routing.ui.getElementValues("move_mail");', + 'label' => $strings['LBL_ROUTING_TO'], // label to be displayed next/above dropdown + 'label_pos' => 'left', // show "to" before this dropdown the dropdown + //'onchange' => '', // override to prevent double-triggering of setup cascade calls + ), + 'copy_mail' => array( + 'type' => 'select', // create a 2nd order dropdown + 'values' => 'SUGAR.routing.ui.getElementValues("move_mail");', + 'label' => $strings['LBL_ROUTING_TO'], // label to be displayed next/above dropdown + 'label_pos' => 'left', // show "to" before this dropdown the dropdown + ), + + 'forward' => array( + 'type' => 'input', + 'label' => $strings['LBL_ROUTING_TO_ADDRESS'], + 'label_pos' => 'left', + ), + 'reply' => array( + 'type' => 'select', + 'label' => $strings['LBL_ROUTING_WITH_TEMPLATE'], + 'label_pos' => 'left', + 'values' => 'SUGAR.routing.ui.getElementValues("email_templates");', + ), + + 'delete_mail' => array( + 'onchange' => 'SUGAR.routing.handleDependentDropdown(this, \'actions\');', // javascript onchange() call + 'type' => 'none', + ), + + + /* not implemented yet + 'delete_bean' => array( + 'onchange' => 'SUGAR.routing.handleDependentDropdown(this, \'actions\');', // javascript onchange() call + ), + 'delete_file' => array( + 'onchange' => 'SUGAR.routing.handleDependentDropdown(this, \'actions\');', // javascript onchange() call + ),*/ + ), + ), + ), + ), + /** + * This is the criteria dependent dropdown metadata for Email 2.0's Rules + * Wizard + */ + 'criteria' => array( + 'always_merge' => array( + 'force_render' => false, + 'grouping' => 'criteriaGroup', + 'onchange' => 'SUGAR.routing.handleDependentDropdown(this, \'criteria\');', // javascript onchange() call + 'label' => ' ', + 'label_pos' => 'left', + 'actionType' => 'criteria', + ), + 'elements' => array( + 'element0' => array( + 'name' => 'crit0', // name of form element + 'id' => 'crit0id', // id of form element - an internal index will be appended to this value 0, 100, 200, etc. + 'type' => 'select', + 'values' => 'SUGAR.routing.matchDom;', // assoc array of dropdown values, if a STRING, it will be eval'd to lazy load the values + 'selected' => '', // initially selected value (key value) + ), + 'element1' => array( + 'name' => 'crit1', + 'id' => 'crit1id', + 'type' => 'select', + 'values' => 'SUGAR.routing.matchTypeDom;', + 'handlers' => array( + 'from_addr' => array(), + 'to_addr' => array(), + 'cc_addr' => array(), + 'name' => array(), + 'description' => array(), + 'priority_high' => array( + 'type' => 'none', + 'label' => $app_strings['LBL_ROUTING_FLAGGED'], + ), + 'priority_normal' => array( + 'type' => 'none', + 'label' => $app_strings['LBL_ROUTING_FLAGGED'], + ), + 'priority_low' => array( + 'type' => 'none', + 'label' => $app_strings['LBL_ROUTING_FLAGGED'], + ), + ), + ), + 'element2' => array( + 'name' => 'crit2', + 'id' => 'crit2id', + 'type' => 'input', + 'values' => '', + ), + ), + ), + /** + * This is the "simple" (non-cascasding, force-rendered) version of the + * above. It has since been deprecated, but is useful to demonstrate + * how to make relatively static dependent dropdown. + */ + 'criteriaSimple' => array( + 'always_merge' => array( + 'force_render' => true, + 'grouping' => 'criteriaGroup', + 'onchange' => '', // javascript onchange() call + 'label' => ' ', + 'label_pos' => 'left', + ), + 'elements' => array( + 'element0' => array( + 'name' => 'crit0', // name of form element + 'id' => 'crit0id', // id of form element - an internal index will be appended to this value 0, 100, 200, etc. + 'type' => 'select', + 'values' => 'SUGAR.routing.matchDom;', // assoc array of dropdown values, if a STRING, it will be eval'd to lazy load the values + 'selected' => '', // initially selected value (key value) + ), + 'element1' => array( + 'name' => 'crit1', + 'id' => 'crit1id', + 'type' => 'select', + 'values' => 'SUGAR.routing.matchTypeDom;', + ), + 'element2' => array( + 'name' => 'crit2', + 'id' => 'crit2id', + 'type' => 'input', + 'values' => '', + ), + ), + ), +); \ No newline at end of file diff --git a/include/SugarEmailAddress/SugarEmailAddress.js b/include/SugarEmailAddress/SugarEmailAddress.js new file mode 100644 index 00000000..5f69985b --- /dev/null +++ b/include/SugarEmailAddress/SugarEmailAddress.js @@ -0,0 +1,69 @@ +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ +(function(){if(SUGAR.EmailAddressWidget)return;var Dom=YAHOO.util.Dom;SUGAR.EmailAddressWidget=function(module){if(!SUGAR.EmailAddressWidget.count[module])SUGAR.EmailAddressWidget.count[module]=0;this.count=SUGAR.EmailAddressWidget.count[module];SUGAR.EmailAddressWidget.count[module]++;this.module=module;this.id=this.module+this.count;if(document.getElementById(module+'_email_widget_id')) +document.getElementById(module+'_email_widget_id').value=this.id;SUGAR.EmailAddressWidget.instances[this.id]=this;} +SUGAR.EmailAddressWidget.instances={};SUGAR.EmailAddressWidget.count={};SUGAR.EmailAddressWidget.prototype={emailTemplate:'
'+''+''+''+''+''+''+'',numberEmailAddresses:0,replyToFlagObject:new Object(),verifying:false,enterPressed:false,tabPressed:false,emailView:"",emailIsRequired:false,tabIndex:-1,prefillEmailAddresses:function(tableId,o){for(i=0;i1){verifyElementFlag.parentNode.removeChild(verifyElementFlag.parentNode.lastChild);} +var verifiedTextNode=document.createElement('span');verifiedTextNode.innerHTML='';verifyElementFlag.parentNode.appendChild(verifiedTextNode);verifyElementFlag.value="true";this.verifyElementValue=Dom.get(this.id+'emailAddressVerifiedValue'+index);this.verifyElementValue.value=Dom.get(this.id+'emailAddress'+index).value;this.verifying=false;var savePressed=false;if(event){var elm=document.activeElement||event.explicitOriginalTarget;if(typeof elm.type!='undefined'&&/submit|button/.test(elm.type.toLowerCase())){savePressed=true;}} +if(savePressed||this.enterPressed){setTimeout("SUGAR.EmailAddressWidget.instances."+this.id+".forceSubmit()",2100);}else if(this.tabPressed){Dom.get(this.id+'emailAddressPrimaryFlag'+index).focus();}} +var event=this.getEvent(event);var targetEl=this.getEventElement(event);var index=/[a-z]*\d?emailAddress(\d+)/i.exec(targetEl.id)[1];var verifyElementFlag=Dom.get(this.id+'emailAddressVerifiedFlag'+index);this.verifyElementValue=Dom.get(this.id+'emailAddressVerifiedValue'+index);verifyElementFlag.value=(trim(targetEl.value)==''||targetEl.value==this.verifyElementValue.value)?"true":"false" +if(verifyElementFlag.parentNode.childNodes.length>1){verifyElementFlag.parentNode.removeChild(verifyElementFlag.parentNode.lastChild);} +if(/emailAddress\d+$/.test(targetEl.id)&&isValidEmail(targetEl.value)&&!this.verifying&&verifyElementFlag.value=="false"){verifiedTextNode=document.createElement('span');verifyElementFlag.parentNode.appendChild(verifiedTextNode);verifiedTextNode.innerHTML=SUGAR.language.get('app_strings','LBL_VERIFY_EMAIL_ADDRESS');this.verifying=true;var cObj=YAHOO.util.Connect.asyncRequest('GET','index.php?module=Contacts&action=RetrieveEmail&target='+targetEl.id+'&email='+targetEl.value,{success:callbackFunction,failure:callbackFunction,scope:this});}},handleKeyDown:function(event){var e=this.getEvent(event);var eL=this.getEventElement(e);if((kc=e["keyCode"])){this.enterPressed=(kc==13)?true:false;this.tabPressed=(kc==9)?true:false;if(this.enterPressed||this.tabPressed){this.retrieveEmailAddress(e);if(this.enterPressed);this.freezeEvent(e);}}},getEvent:function(event){return(event?event:window.event);},getEventElement:function(e){return(e.srcElement?e.srcElement:(e.target?e.target:e.currentTarget));},freezeEvent:function(e){if(e.preventDefault)e.preventDefault();e.returnValue=false;e.cancelBubble=true;if(e.stopPropagation)e.stopPropagation();return false;},addEmailAddress:function(tableId,address,primaryFlag,replyToFlag,optOutFlag,invalidFlag){if(this.addInProgress) +return;this.addInProgress=true;if(!address) +address="";var insertInto=Dom.get(tableId);var parentObj=insertInto.parentNode;var newContent=document.createElement("input");var nav=new String(navigator.appVersion);var newContentPrimaryFlag;if(SUGAR.isIE){newContentPrimaryFlag=document.createElement("");}else{newContentPrimaryFlag=document.createElement("input");} +var newContentReplyToFlag=document.createElement("input");var newContentOptOutFlag=document.createElement("input");var newContentInvalidFlag=document.createElement("input");var newContentVerifiedFlag=document.createElement("input");var newContentVerifiedValue=document.createElement("input");var removeButton=document.createElement("img");var tbody=document.createElement("tbody");var tr=document.createElement("tr");var td1=document.createElement("td");var td2=document.createElement("td");var td3=document.createElement("td");var td4=document.createElement("td");var td5=document.createElement("td");var td6=document.createElement("td");var td7=document.createElement("td");var td8=document.createElement("td");newContent.setAttribute("type","text");newContent.setAttribute("name",this.id+"emailAddress"+this.numberEmailAddresses);newContent.setAttribute("id",this.id+"emailAddress"+this.numberEmailAddresses);newContent.setAttribute("tabindex",this.tabIndex);newContent.setAttribute("size","30");if(address!=''){newContent.setAttribute("value",address);} +removeButton.setAttribute("id",this.id+"removeButton"+this.numberEmailAddresses);removeButton.setAttribute("class","id-ff-remove");removeButton.setAttribute("name",this.numberEmailAddresses);removeButton.eaw=this;removeButton.setAttribute("src","index.php?entryPoint=getImage&themeName="+SUGAR.themes.theme_name+"&imageName=id-ff-remove.png");removeButton.onclick=function(){this.eaw.removeEmailAddress(this.name);};newContentPrimaryFlag.setAttribute("type","radio");newContentPrimaryFlag.setAttribute("name",this.id+"emailAddressPrimaryFlag");newContentPrimaryFlag.setAttribute("id",this.id+"emailAddressPrimaryFlag"+this.numberEmailAddresses);newContentPrimaryFlag.setAttribute("value",this.id+"emailAddress"+this.numberEmailAddresses);newContentPrimaryFlag.setAttribute("enabled","true");newContentReplyToFlag.setAttribute("type","radio");newContentReplyToFlag.setAttribute("name",this.id+"emailAddressReplyToFlag");newContentReplyToFlag.setAttribute("id",this.id+"emailAddressReplyToFlag"+this.numberEmailAddresses);newContentReplyToFlag.setAttribute("value",this.id+"emailAddress"+this.numberEmailAddresses);newContentReplyToFlag.setAttribute("enabled","true");newContentReplyToFlag.eaw=this;newContentReplyToFlag['onclick']=function(){var form=document.forms[this.eaw.emailView];if(!form){form=document.forms['editContactForm'];} +var nav=new String(navigator.appVersion);if(nav.match(/MSIE/gim)){for(i=0;iindex = self::$count; + self::$count++; + } + + /** + * Legacy email address handling. This is to allow support for SOAP or customizations + * @param string $id + * @param string $module + */ + function handleLegacySave($bean, $prefix = "") { + if(!isset($_REQUEST) || !isset($_REQUEST['useEmailWidget'])) { + if (empty($this->addresses) || !isset($_REQUEST['massupdate'])) { + $this->addresses = array(); + $optOut = (isset($bean->email_opt_out) && $bean->email_opt_out == "1") ? true : false; + $invalid = (isset($bean->invalid_email) && $bean->invalid_email == "1") ? true : false; + + $isPrimary = true; + for($i = 1; $i <= 10; $i++){ + $email = 'email'.$i; + if(isset($bean->$email) && !empty($bean->$email)){ + $opt_out_field = $email.'_opt_out'; + $invalid_field = $email.'_invalid'; + $field_optOut = (isset($bean->$opt_out_field)) ? $bean->$opt_out_field : $optOut; + $field_invalid = (isset($bean->$invalid_field)) ? $bean->$invalid_field : $invalid; + $this->addAddress($bean->$email, $isPrimary, false, $field_invalid, $field_optOut); + $isPrimary = false; + } + } + } + } + $this->populateAddresses($bean->id, $bean->module_dir, array(),''); + if(isset($_REQUEST) && isset($_REQUEST['useEmailWidget'])) { + $this->populateLegacyFields($bean); + } + } + + /** + * Fills standard email1 legacy fields + * @param string id + * @param string module + * @return object + */ + function handleLegacyRetrieve(&$bean) { + $module_dir = $this->getCorrectedModule($bean->module_dir); + $this->addresses = $this->getAddressesByGUID($bean->id, $module_dir); + $this->populateLegacyFields($bean); + + return; + } + + function populateLegacyFields(&$bean){ + $primary_found = false; + $alternate_found = false; + $alternate2_found = false; + foreach($this->addresses as $k=>$address) { + if ($primary_found && $alternate_found) + break; + if ($address['primary_address'] == 1 && !$primary_found) { + $primary_index = $k; + $primary_found = true; + } elseif (!$alternate_found) { + $alternate_index = $k; + $alternate_found = true; + } elseif (!$alternate2_found){ + $alternate2_index = $k; + $alternate2_found = true; + } + } + + if ($primary_found) { + $bean->email1 = $this->addresses[$primary_index]['email_address']; + $bean->email_opt_out = $this->addresses[$primary_index]['opt_out']; + $bean->invalid_email = $this->addresses[$primary_index]['invalid_email']; + if ($alternate_found) { + $bean->email2 = $this->addresses[$alternate_index]['email_address']; + } + } elseif ($alternate_found) { + // Use the first found alternate as email1. + $bean->email1 = $this->addresses[$alternate_index]['email_address']; + $bean->email_opt_out = $this->addresses[$alternate_index]['opt_out']; + $bean->invalid_email = $this->addresses[$alternate_index]['invalid_email']; + if ($alternate2_found) { + $bean->email2 = $this->addresses[$alternate2_index]['email_address']; + } + } + } + + /** + * Saves email addresses for a parent bean + * @param string $id Parent bean ID + * @param string $module Parent bean's module + * @param array $addresses Override of $_REQUEST vars, used to handle non-standard bean saves + * @param string $primary GUID of primary address + * @param string $replyTo GUID of reply-to address + * @param string $invalid GUID of invalid address + */ + function save($id, $module, $new_addrs=array(), $primary='', $replyTo='', $invalid='', $optOut='', $in_workflow=false) { + if(empty($this->addresses) || $in_workflow){ + $this->populateAddresses($id, $module, $new_addrs,$primary); + } + + //find all email addresses.. + $current_links=array(); + // Need to correct this to handle the Employee/User split + $module = $this->getCorrectedModule($module); + $q2="select * from email_addr_bean_rel eabr WHERE eabr.bean_id = '{$id}' AND eabr.bean_module = '{$module}' and eabr.deleted=0"; + $r2 = $this->db->query($q2); + while(($row2=$this->db->fetchByAssoc($r2)) != null ) { + $current_links[$row2['email_address_id']]=$row2; + } + + if (!empty($this->addresses)) { + // insert new relationships and create email address record, if they don't exist + foreach($this->addresses as $address) { + if(!empty($address['email_address'])) { + $guid = create_guid(); + $emailId = $this->AddUpdateEmailAddress($address['email_address'],$address['invalid_email'],$address['opt_out']);// this will save the email address if not found + + //verify linkage and flags. + $upd_eabr=""; + if (isset($current_links[$emailId])) { + if ($address['primary_address'] != $current_links[$emailId]['primary_address'] or $address['reply_to_address'] != $current_links[$emailId]['reply_to_address'] ) { + $upd_eabr="UPDATE email_addr_bean_rel SET primary_address='{$address['primary_address']}', reply_to_address='{$address['reply_to_address']}' WHERE id='{$current_links[$emailId]['id']}'"; + } + + unset($current_links[$emailId]); + } else { + $now = TimeDate::getInstance()->nowDb(); + $upd_eabr = "INSERT INTO email_addr_bean_rel (id, email_address_id,bean_id, bean_module,primary_address,reply_to_address,date_created,date_modified,deleted) VALUES('{$guid}', '{$emailId}', '{$id}', '{$module}', {$address['primary_address']}, {$address['reply_to_address']}, '$now', '$now', 0)"; + } + + if (!empty($upd_eabr)) { + $r2 = $this->db->query($upd_eabr); + } + } + } + } + + //delete link to dropped email address. + if (!empty($current_links)) { + + $delete=""; + foreach ($current_links as $eabr) { + + $delete.=empty($delete) ? "'".$eabr['id'] . "' " : ",'" . $eabr['id'] . "'"; + } + + $eabr_unlink="update email_addr_bean_rel set deleted=1 where id in ({$delete})"; + $this->db->query($eabr_unlink); + } + return; + } + + /** + * returns the number of email addresses found for a specifed bean + * + * @param string $email Address to match + * @param object $bean Bean to query against + * @param string $addresstype Optional, pass a 1 to query against the primary address, 0 for the other addresses + * @return int Count of records found + */ + function getCountEmailAddressByBean( + $email, + $bean, + $addresstype + ) + { + $emailCaps = strtoupper(trim($email)); + if(empty($emailCaps)) + return 0; + + $q = "SELECT * + FROM email_addr_bean_rel eabl JOIN email_addresses ea + ON (ea.id = eabl.email_address_id) + JOIN {$bean->table_name} bean + ON (eabl.bean_id = bean.id) + WHERE ea.email_address_caps = '{$emailCaps}' + and eabl.bean_module = '{$bean->module_dir}' + and eabl.primary_address = '{$addresstype}' + and eabl.deleted=0 "; + + $r = $this->db->query($q); + + // do it this way to make the count accurate in oracle + $i = 0; + while ($this->db->fetchByAssoc($r)) ++$i; + + return $i; + } + + /** + * This function returns a contact or user ID if a matching email is found + * @param $email the email address to match + * @param $table which table to query + */ + function getRelatedId($email, $module) { + $email = trim(strtoupper($email)); + $module = ucfirst($module); + + $q = "SELECT bean_id FROM email_addr_bean_rel eabr + JOIN email_addresses ea ON (eabr.email_address_id = ea.id) + WHERE bean_module = '{$module}' AND ea.email_address_caps = '{$email}' AND eabr.deleted=0"; + + $r = $this->db->query($q, true); + + $retArr = array(); + while($a = $this->db->fetchByAssoc($r)) { + $retArr[] = $a['bean_id']; + } + if(count($retArr) > 0) { + return $retArr; + } else { + return false; + } + } + + /** + * returns a collection of beans matching the email address + * @param string $email Address to match + * @return array + */ + function getBeansByEmailAddress($email) { + global $beanList; + global $beanFiles; + + $ret = array(); + + $email = trim($email); + + if(empty($email)) { + return array(); + } + + $emailCaps = strtoupper($email); + $q = "SELECT * FROM email_addr_bean_rel eabl JOIN email_addresses ea ON (ea.id = eabl.email_address_id) + WHERE ea.email_address_caps = '{$emailCaps}' and eabl.deleted=0 "; + $r = $this->db->query($q); + + while($a = $this->db->fetchByAssoc($r)) { + if(isset($beanList[$a['bean_module']]) && !empty($beanList[$a['bean_module']])) { + $className = $beanList[$a['bean_module']]; + + if(isset($beanFiles[$className]) && !empty($beanFiles[$className])) { + if(!class_exists($className)) { + require_once($beanFiles[$className]); + } + + $bean = new $className(); + $bean->retrieve($a['bean_id']); + + $ret[] = $bean; + } else { + $GLOBALS['log']->fatal("SUGAREMAILADDRESS: could not find valid class file for [ {$className} ]"); + } + } else { + $GLOBALS['log']->fatal("SUGAREMAILADDRESS: could not find valid class [ {$a['bean_module']} ]"); + } + } + + return $ret; + } + + /** + * Saves email addresses for a parent bean + * @param string $id Parent bean ID + * @param string $module Parent bean's module + * @param array $addresses Override of $_REQUEST vars, used to handle non-standard bean saves + * @param string $primary GUID of primary address + * @param string $replyTo GUID of reply-to address + * @param string $invalid GUID of invalid address + */ + function populateAddresses($id, $module, $new_addrs=array(), $primary='', $replyTo='', $invalid='', $optOut='') { + $module = $this->getCorrectedModule($module); + //One last check for the ConvertLead action in which case we need to change $module to 'Leads' + $module = (isset($_REQUEST) && isset($_REQUEST['action']) && $_REQUEST['action'] == 'ConvertLead') ? 'Leads' : $module; + + $post_from_email_address_widget = (isset($_REQUEST) && isset($_REQUEST['emailAddressWidget'])) ? true : false; + $primaryValue = $primary; + $widgetCount = 0; + $hasEmailValue = false; + + if (isset($_REQUEST) && isset($_REQUEST[$module .'_email_widget_id'])) { + + $fromRequest = false; + // determine which array to process + foreach($_REQUEST as $k => $v) { + if(strpos($k, 'emailAddress') !== false) { + $fromRequest = true; + break; + } + } + $widget_id = $_REQUEST[$module .'_email_widget_id']; + + + //Iterate over the widgets for this module, in case there are multiple email widgets for this module + while(isset($_REQUEST[$module . $widget_id . "emailAddress" . $widgetCount])) + { + if (empty($_REQUEST[$module . $widget_id . "emailAddress" . $widgetCount])) { + $widgetCount++; + continue; + } + + $hasEmailValue = true; + + $eId = $module . $widget_id; + if(isset($_REQUEST[$eId . 'emailAddressPrimaryFlag'])) { + $primaryValue = $_REQUEST[$eId . 'emailAddressPrimaryFlag']; + } else if(isset($_REQUEST[$module . 'emailAddressPrimaryFlag'])) { + $primaryValue = $_REQUEST[$module . 'emailAddressPrimaryFlag']; + } + + $optOutValues = array(); + if(isset($_REQUEST[$eId .'emailAddressOptOutFlag'])) { + $optOutValues = $_REQUEST[$eId .'emailAddressOptOutFlag']; + } else if(isset($_REQUEST[$module . 'emailAddressOptOutFlag'])) { + $optOutValues = $_REQUEST[$module . 'emailAddressOptOutFlag']; + } + + $invalidValues = array(); + if(isset($_REQUEST[$eId .'emailAddressInvalidFlag'])) { + $invalidValues = $_REQUEST[$eId .'emailAddressInvalidFlag']; + } else if(isset($_REQUEST[$module . 'emailAddressInvalidFlag'])) { + $invalidValues = $_REQUEST[$module . 'emailAddressInvalidFlag']; + } + + $deleteValues = array(); + if(isset($_REQUEST[$eId .'emailAddressDeleteFlag'])) { + $deleteValues = $_REQUEST[$eId .'emailAddressDeleteFlag']; + } else if(isset($_REQUEST[$module . 'emailAddressDeleteFlag'])) { + $deleteValues = $_REQUEST[$module . 'emailAddressDeleteFlag']; + } + + // prep from form save + $primaryField = $primary; + $replyToField = ''; + $invalidField = ''; + $optOutField = ''; + if($fromRequest && empty($primary) && isset($primaryValue)) { + $primaryField = $primaryValue; + } + + if($fromRequest && empty($replyTo)) { + if(isset($_REQUEST[$eId .'emailAddressReplyToFlag'])) { + $replyToField = $_REQUEST[$eId .'emailAddressReplyToFlag']; + } else if(isset($_REQUEST[$module . 'emailAddressReplyToFlag'])) { + $replyToField = $_REQUEST[$module . 'emailAddressReplyToFlag']; + } + } + if($fromRequest && empty($new_addrs)) { + foreach($_REQUEST as $k => $v) { + if(preg_match('/'.$eId.'emailAddress[0-9]+$/i', $k) && !empty($v)) { + $new_addrs[$k] = $v; + } + } + } + + if($fromRequest && empty($new_addrs)) { + foreach($_REQUEST as $k => $v) { + if(preg_match('/'.$eId.'emailAddressVerifiedValue[0-9]+$/i', $k) && !empty($v)) { + $validateFlag = str_replace("Value", "Flag", $k); + if (isset($_REQUEST[$validateFlag]) && $_REQUEST[$validateFlag] == "true") + $new_addrs[$k] = $v; + } + } + } + + //empty the addresses array if the post happened from email address widget. + if($post_from_email_address_widget) { + $this->addresses=array(); //this gets populated during retrieve of the contact bean. + } else { + $optOutValues = array(); + $invalidValues = array(); + foreach($new_addrs as $k=>$email) { + preg_match('/emailAddress([0-9])+$/', $k, $matches); + $count = $matches[1]; + $result = $this->db->query("SELECT opt_out, invalid_email from email_addresses where email_address_caps = '" . strtoupper($email) . "'"); + if(!empty($result)) { + $row=$this->db->fetchByAssoc($result); + if(!empty($row['opt_out'])) { + $optOutValues[$k] = "emailAddress$count"; + } + if(!empty($row['invalid_email'])) { + $invalidValues[$k] = "emailAddress$count"; + } + } + } + } + // Re-populate the addresses class variable if we have new address(es). + if (!empty($new_addrs)) { + foreach($new_addrs as $k => $reqVar) { + //$key = preg_match("/^$eId/s", $k) ? substr($k, strlen($eId)) : $k; + $reqVar = trim($reqVar); + if(strpos($k, 'emailAddress') !== false) { + if(!empty($reqVar) && !in_array($k, $deleteValues)) { + $primary = ($k == $primaryValue) ? true : false; + $replyTo = ($k == $replyToField) ? true : false; + $invalid = (in_array($k, $invalidValues)) ? true : false; + $optOut = (in_array($k, $optOutValues)) ? true : false; + $this->addAddress(trim($new_addrs[$k]), $primary, $replyTo, $invalid, $optOut); + } + } + } //foreach + } + + $widgetCount++; + }//End of Widget for loop + } + + //If no widgets, set addresses array to empty + if($post_from_email_address_widget && !$hasEmailValue) { + $this->addresses = array(); + } + } + + /** + * Preps internal array structure for email addresses + * @param string $addr Email address + * @param bool $primary Default false + * @param bool $replyTo Default false + */ + function addAddress($addr, $primary=false, $replyTo=false, $invalid=false, $optOut=false) { + $addr = html_entity_decode($addr, ENT_QUOTES); + if(preg_match($this->regex, $addr)) { + $primaryFlag = ($primary) ? '1' : '0'; + $replyToFlag = ($replyTo) ? '1' : '0'; + $invalidFlag = ($invalid) ? '1' : '0'; + $optOutFlag = ($optOut) ? '1' : '0'; + + $addr = trim($addr); + + // If we have such address already, remove it and add new one in. + foreach ($this->addresses as $k=>$address) { + if ($address['email_address'] == $addr) { + unset($this->addresses[$k]); + } elseif ($primary && $address['primary_address'] == '1') { + // We should only have one primary. If we are adding a primary but + // we find an existing primary, reset this one's primary flag. + $address['primary_address'] = '0'; + } + } + + $this->addresses[] = array( + 'email_address' => $addr, + 'primary_address' => $primaryFlag, + 'reply_to_address' => $replyToFlag, + 'invalid_email' => $invalidFlag, + 'opt_out' => $optOutFlag, + ); + } else { + $GLOBALS['log']->fatal("SUGAREMAILADDRESS: address did not validate [ {$addr} ]"); + } + } + + /** + * Updates invalid_email and opt_out flags for each address + */ + function updateFlags() { + if(!empty($this->addresses)) { + foreach($this->addresses as $addressMeta) { + if(isset($addressMeta['email_address']) && !empty($addressMeta['email_address'])) { + $address = $this->_cleanAddress($addressMeta['email_address']); + + $q = "SELECT * FROM email_addresses WHERE email_address = '{$address}'"; + $r = $this->db->query($q); + $a = $this->db->fetchByAssoc($r); + + if(!empty($a)) { + if(isset($a['invalid_email']) && isset($addressMeta['invalid_email']) && isset($addressMeta['opt_out']) && $a['invalid_email'] != $addressMeta['invalid_email'] || $a['opt_out'] != $addressMeta['opt_out']) { + $qUpdate = "UPDATE email_addresses SET invalid_email = {$addressMeta['invalid_email']}, opt_out = {$addressMeta['opt_out']}, date_modified = '".TimeDate::getInstance()->nowDb()."' WHERE id = '{$a['id']}'"; + $rUpdate = $this->db->query($qUpdate); + } + } + } + } + } + } + + public function splitEmailAddress($addr) + { + $email = $this->_cleanAddress($addr); + if(!preg_match($this->regex, $email)) { + $email = ''; // remove bad email addr + } + $name = trim(str_replace(array($email, '<', '>', '"', "'"), '', $addr)); + return array("name" => $name, "email" => strtolower($email)); + } + + /** + * PRIVATE UTIL + * Normalizes an RFC-clean email address, returns a string that is the email address only + * @param string $addr Dirty email address + * @return string clean email address + */ + function _cleanAddress($addr) { + $addr = trim(from_html($addr)); + + if(strpos($addr, "<") !== false && strpos($addr, ">") !== false) { + $address = trim(substr($addr, strrpos($addr, "<") +1, strrpos($addr, ">") - strrpos($addr, "<") -1)); + } else { + $address = trim($addr); + } + + return $address; + } + + /** + * preps a passed email address for email address storage + * @param array $addr Address in focus, must be RFC compliant + * @return string $id email_addresses ID + */ + function getEmailGUID($addr) { + $address = $this->_cleanAddress($addr); + $addressCaps = strtoupper($address); + + $q = "SELECT id FROM email_addresses WHERE email_address_caps = '{$addressCaps}'"; + $r = $this->db->query($q); + $a = $this->db->fetchByAssoc($r); + + if(!empty($a) && !empty($a['id'])) { + return $a['id']; + } else { + $guid = ''; + if(!empty($address)){ + $guid = create_guid(); + $address = $GLOBALS['db']->quote($address); + $addressCaps = $GLOBALS['db']->quote($addressCaps); + $now = TimeDate::getInstance()->nowDb(); + $qa = "INSERT INTO email_addresses (id, email_address, email_address_caps, date_created, date_modified, deleted) + VALUES('{$guid}', '{$address}', '{$addressCaps}', '$now', '$now', 0)"; + $ra = $this->db->query($qa); + } + return $guid; + } + } + + function AddUpdateEmailAddress($addr,$invalid=0,$opt_out=0) { + + $address = $this->_cleanAddress($addr); + $addressCaps = strtoupper($this->db->quoteForEmail($address)); + + $q = "SELECT * FROM email_addresses WHERE email_address_caps = '{$addressCaps}' and deleted=0"; + $r = $this->db->query($q); + $a = $this->db->fetchByAssoc($r); + if(!empty($a) && !empty($a['id'])) { + //verify the opt out and invalid flags. + //bug# 39378- did not allow change of case of an email address + if ($a['invalid_email'] != $invalid or $a['opt_out'] != $opt_out or strcasecmp(trim($a['email_address']), trim($address))==0) { + $upd_q="update email_addresses set email_address='{$address}', invalid_email={$invalid}, opt_out={$opt_out},date_modified = '".gmdate($GLOBALS['timedate']->get_db_date_time_format())."' where id='{$a['id']}'"; + $upd_r= $this->db->query($upd_q); + } + return $a['id']; + } else { + $guid = ''; + if(!empty($address)){ + $guid = create_guid(); + $address = $GLOBALS['db']->quote($address); + $addressCaps = $GLOBALS['db']->quote($addressCaps); + $now = TimeDate::getInstance()->nowDb(); + $qa = "INSERT INTO email_addresses (id, email_address, email_address_caps, date_created, date_modified, deleted, invalid_email, opt_out) + VALUES('{$guid}', '{$address}', '{$addressCaps}', '$now', '$now', 0 , $invalid, $opt_out)"; + $this->db->query($qa); + } + return $guid; + } + } + + /** + * Returns Primary or newest email address + * @param object $focus Object in focus + * @return string email + */ + function getPrimaryAddress($focus,$parent_id=null,$parent_type=null) { + + $parent_type=empty($parent_type) ? $focus->module_dir : $parent_type; + $parent_id=empty($parent_id) ? $focus->id : $parent_id; + + $q = "SELECT ea.email_address FROM email_addresses ea + LEFT JOIN email_addr_bean_rel ear ON ea.id = ear.email_address_id + WHERE ear.bean_module = '{$parent_type}' + AND ear.bean_id = '{$parent_id}' + AND ear.deleted = 0 + ORDER BY ear.primary_address DESC"; + $r = $this->db->limitQuery($q, 0, 1); + $a = $this->db->fetchByAssoc($r); + + if(isset($a['email_address'])) { + return $a['email_address']; + } + return ''; + } + + function getReplyToAddress($focus) { + $q = "SELECT ea.email_address FROM email_addresses ea + LEFT JOIN email_addr_bean_rel ear ON ea.id = ear.email_address_id + WHERE ear.bean_module = '{$focus->module_dir}' + AND ear.bean_id = '{$focus->id}' + AND ear.deleted = 0 + ORDER BY ear.reply_to_address DESC"; + $r = $this->db->query($q); + $a = $this->db->fetchByAssoc($r); + + if(isset($a['email_address'])) { + return $a['email_address']; + } + return ''; + } + + /** + * Returns all email addresses by parent's GUID + * @param string $id Parent's GUID + * @param string $module Parent's module + * @return array + */ + function getAddressesByGUID($id, $module) { + $return = array(); + $module = $this->getCorrectedModule($module); + + $q = "SELECT ea.email_address, ea.email_address_caps, ea.invalid_email, ea.opt_out, ea.date_created, ea.date_modified, + ear.id, ear.email_address_id, ear.bean_id, ear.bean_module, ear.primary_address, ear.reply_to_address, ear.deleted + FROM email_addresses ea LEFT JOIN email_addr_bean_rel ear ON ea.id = ear.email_address_id + WHERE ear.bean_module = '{$module}' + AND ear.bean_id = '{$id}' + AND ear.deleted = 0 + ORDER BY ear.reply_to_address, ear.primary_address DESC"; + $r = $this->db->query($q); + + while($a = $this->db->fetchByAssoc($r)) { + $return[] = $a; + } + + return $return; + } + + /** + * Returns the HTML/JS for the EmailAddress widget + * @param string $parent_id ID of parent bean, generally $focus + * @param string $module $focus' module + * @param bool asMetadata Default false + * @return string HTML/JS for widget + */ + function getEmailAddressWidgetEditView($id, $module, $asMetadata=false, $tpl='',$tabindex='') + { + if ( !($this->smarty instanceOf Sugar_Smarty ) ) + $this->smarty = new Sugar_Smarty(); + + global $app_strings, $dictionary, $beanList; + + $prefill = 'false'; + + $prefillData = 'new Object()'; + $passedModule = $module; + $module = $this->getCorrectedModule($module); + $saveModule = $module; + if(isset($_POST['is_converted']) && $_POST['is_converted']==true){ + $id=$_POST['return_id']; + $module=$_POST['return_module']; + } + $prefillDataArr = array(); + if(!empty($id)) { + $prefillDataArr = $this->getAddressesByGUID($id, $module); + //When coming from convert leads, sometimes module is Contacts while the id is for a lead. + if (empty($prefillDataArr) && $module == "Contacts") + $prefillDataArr = $this->getAddressesByGUID($id, "Leads"); + } else if(isset($_REQUEST['full_form']) && !empty($_REQUEST['emailAddressWidget'])){ + $widget_id = isset($_REQUEST[$module . '_email_widget_id']) ? $_REQUEST[$module . '_email_widget_id'] : '0'; + $count = 0; + $key = $module . $widget_id . 'emailAddress'.$count; + while(isset($_REQUEST[$key])) { + $email = $_REQUEST[$key]; + $prefillDataArr[] = array('email_address'=>$email, + 'primary_address'=>isset($_REQUEST['emailAddressPrimaryFlag']) && $_REQUEST['emailAddressPrimaryFlag'] == $key, + 'invalid_email'=>isset($_REQUEST['emailAddressInvalidFlag']) && in_array($key, $_REQUEST['emailAddressInvalidFlag']), + 'opt_out'=>isset($_REQUEST['emailAddressOptOutFlag']) && in_array($key, $_REQUEST['emailAddressOptOutFlag']), + 'reply_to_address'=>false + ); + $key = $module . $widget_id . 'emailAddress' . ++$count; + } //while + } + + if(!empty($prefillDataArr)) { + $json = new JSON(JSON_LOOSE_TYPE); + $prefillData = $json->encode($prefillDataArr); + $prefill = !empty($prefillDataArr) ? 'true' : 'false'; + } + + $required = false; + $vardefs = $dictionary[$beanList[$passedModule]]['fields']; + if (!empty($vardefs['email1']) && isset($vardefs['email1']['required']) && $vardefs['email1']['required']) + $required = true; + $this->smarty->assign('required', $required); + + $this->smarty->assign('module', $saveModule); + $this->smarty->assign('index', $this->index); + $this->smarty->assign('app_strings', $app_strings); + $this->smarty->assign('prefillEmailAddresses', $prefill); + $this->smarty->assign('prefillData', $prefillData); + $this->smarty->assign('tabindex', $tabindex); + //Set addDefaultAddress flag (do not add if it's from the Email module) + $this->smarty->assign('addDefaultAddress', (isset($_REQUEST['module']) && $_REQUEST['module'] == 'Emails') ? 'false' : 'true'); + $form = $this->view; + + if ($this->view == "QuickCreate") + $form = 'form_'.$this->view .'_'.$module; + $this->smarty->assign('emailView', $form); + + if($module == 'Users') { + $this->smarty->assign('useReplyTo', true); + } else { + $this->smarty->assign('useOptOut', true); + $this->smarty->assign('useInvalid', true); + } + + $template = empty($tpl) ? "include/SugarEmailAddress/templates/forEditView.tpl" : $tpl; + $newEmail = $this->smarty->fetch($template); + + + if($asMetadata) { + // used by Email 2.0 + $ret = array(); + $ret['prefillData'] = $prefillDataArr; + $ret['html'] = $newEmail; + + return $ret; + } + + return $newEmail; + } + + + /** + * Returns the HTML/JS for the EmailAddress widget + * @param object $focus Bean in focus + * @return string HTML/JS for widget + */ + function getEmailAddressWidgetDetailView($focus, $tpl='') + { + if ( !($this->smarty instanceOf Sugar_Smarty ) ) + $this->smarty = new Sugar_Smarty(); + + global $app_strings; + global $current_user; + $assign = array(); + if(empty($focus->id))return ''; + $prefillData = $this->getAddressesByGUID($focus->id, $focus->module_dir); + + foreach($prefillData as $addressItem) { + $key = ($addressItem['primary_address'] == 1) ? 'primary' : ""; + $key = ($addressItem['reply_to_address'] == 1) ? 'reply_to' : $key; + $key = ($addressItem['opt_out'] == 1) ? 'opt_out' : $key; + $key = ($addressItem['invalid_email'] == 1) ? 'invalid' : $key; + $key = ($addressItem['opt_out'] == 1) && ($addressItem['invalid_email'] == 1) ? 'opt_out_invalid' : $key; + + $assign[] = array('key' => $key, 'address' => $current_user->getEmailLink2($addressItem['email_address'], $focus).$addressItem['email_address'].""); + } + + + $this->smarty->assign('app_strings', $app_strings); + $this->smarty->assign('emailAddresses', $assign); + $templateFile = empty($tpl) ? "include/SugarEmailAddress/templates/forDetailView.tpl" : $tpl; + $return = $this->smarty->fetch($templateFile); + return $return; + } + + + /** + * getEmailAddressWidgetDuplicatesView($focus) + * @param object $focus Bean in focus + * @return string HTML that contains hidden input values based off of HTML request + */ + function getEmailAddressWidgetDuplicatesView($focus) + { + if ( !($this->smarty instanceOf Sugar_Smarty ) ) + $this->smarty = new Sugar_Smarty(); + + $count = 0; + $emails = array(); + $primary = null; + $optOut = array(); + $invalid = array(); + $mod = isset($focus) ? $focus->module_dir : ""; + + $widget_id = $_POST[$mod .'_email_widget_id']; + $this->smarty->assign('email_widget_id',$widget_id); + $this->smarty->assign('emailAddressWidget',$_POST['emailAddressWidget']); + + if(isset($_POST[$mod . $widget_id . 'emailAddressPrimaryFlag'])) { + $primary = $_POST[$mod . $widget_id . 'emailAddressPrimaryFlag']; + } + + while(isset($_POST[$mod . $widget_id . "emailAddress" . $count])) { + $emails[] = $_POST[$mod . $widget_id . 'emailAddress' . $count]; + $count++; + } + + if($count == 0) { + return ""; + } + + if(isset($_POST[$mod . $widget_id . 'emailAddressOptOutFlag'])) { + foreach($_POST[$mod . $widget_id . 'emailAddressOptOutFlag'] as $v) { + $optOut[] = $v; + } + } + + if(isset($_POST[$mod . $widget_id . 'emailAddressInvalidFlag'])) { + foreach($_POST[$mod . $widget_id . 'emailAddressInvalidFlag'] as $v) { + $invalid[] = $v; + } + } + + if(isset($_POST[$mod . $widget_id . 'emailAddressReplyToFlag'])) { + foreach($_POST[$mod . $widget_id . 'emailAddressReplyToFlag'] as $v) { + $replyTo[] = $v; + } + } + + if(isset($_POST[$mod . $widget_id . 'emailAddressDeleteFlag'])) { + foreach($_POST[$mod . $widget_id . 'emailAddressDeleteFlag'] as $v) { + $delete[] = $v; + } + } + + while(isset($_POST[$mod . $widget_id . "emailAddressVerifiedValue" . $count])) { + $verified[] = $_POST[$mod . $widget_id . 'emailAddressVerifiedValue' . $count]; + $count++; + } + + $this->smarty->assign('emails', $emails); + $this->smarty->assign('primary', $primary); + $this->smarty->assign('optOut', $optOut); + $this->smarty->assign('invalid', $invalid); + $this->smarty->assign('replyTo', $invalid); + $this->smarty->assign('delete', $invalid); + $this->smarty->assign('verified', $invalid); + $this->smarty->assign('moduleDir', $mod); + + return $this->smarty->fetch("include/SugarEmailAddress/templates/forDuplicatesView.tpl"); + } + + /** + * getFormBaseURL + * + */ + function getFormBaseURL($focus) { + $get = ""; + $count = 0; + $mod = isset($focus) ? $focus->module_dir : ""; + + $widget_id = $_POST[$mod .'_email_widget_id']; + $get .= '&' . $mod . '_email_widget_id='. $widget_id; + $get .= '&emailAddressWidget='.$_POST['emailAddressWidget']; + + while(isset($_REQUEST[$mod . $widget_id . 'emailAddress' . $count])) { + $get .= "&" . $mod . $widget_id . "emailAddress" . $count . "=" . urlencode($_REQUEST[$mod . $widget_id . 'emailAddress' . $count]); + $count++; + } //while + + while(isset($_REQUEST[$mod . $widget_id . 'emailAddressVerifiedValue' . $count])) { + $get .= "&" . $mod . $widget_id . "emailAddressVerifiedValue" . $count . "=" . urlencode($_REQUEST[$mod . $widget_id . 'emailAddressVerifiedValue' . $count]); + $count++; + } //while + + $options = array('emailAddressPrimaryFlag', 'emailAddressOptOutFlag', 'emailAddressInvalidFlag', 'emailAddressDeleteFlag', 'emailAddressReplyToFlag'); + + foreach($options as $option) { + $count = 0; + $optionIdentifier = $mod.$widget_id.$option; + if(isset($_REQUEST[$optionIdentifier])) { + if(is_array($_REQUEST[$optionIdentifier])) { + foreach($_REQUEST[$optionIdentifier] as $optOut) { + $get .= "&" . $optionIdentifier . "[" . $count . "]=" . $optOut; + $count++; + } //foreach + } else { + $get .= "&" . $optionIdentifier . "=" . $_REQUEST[$optionIdentifier]; + } + } //if + } //foreach + return $get; + + } + + function setView($view) { + $this->view = $view; + } + +/** + * This function is here so the Employees/Users division can be handled cleanly in one place + * @param object $focus SugarBean + * @return string The value for the bean_module column in the email_addr_bean_rel table + */ + function getCorrectedModule(&$module) { + return ($module == "Employees")? "Users" : $module; + } +} // end class def + + +/** + * Convenience function for MVC (Mystique) + * @param object $focus SugarBean + * @param string $field unused + * @param string $value unused + * @param string $view DetailView or EditView + * @return string + */ +function getEmailAddressWidget($focus, $field, $value, $view, $tabindex='') { + $sea = new SugarEmailAddress(); + $sea->setView($view); + + if($view == 'EditView' || $view == 'QuickCreate' || $view == 'ConvertLead') { + $module = $focus->module_dir; + if ($view == 'ConvertLead' && $module == "Contacts") $module = "Leads"; + + return $sea->getEmailAddressWidgetEditView($focus->id, $module, false,'',$tabindex); + } + + return $sea->getEmailAddressWidgetDetailView($focus); +} + +?> diff --git a/include/SugarEmailAddress/templates/forDetailView.tpl b/include/SugarEmailAddress/templates/forDetailView.tpl new file mode 100644 index 00000000..bbc6baf0 --- /dev/null +++ b/include/SugarEmailAddress/templates/forDetailView.tpl @@ -0,0 +1,73 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} + +
+{/if} + +{if $showLinks == 'true'} + + + + +
+ + + +{foreach from=$subtabs item=tab} +{if !empty($notFirst) && ($notFirst != 0) && ($notFirst != 1)} + +{else} +{assign var='notFirst' value='2'} +{/if} + +{/foreach} +{if !empty($otherMoreSubMenu[$moreSubMenuName].tabs)} + +{/if} + + + +
| + {$tab.label} + |  >> 
+
+{/if} + +{if !empty($moreMenu)} + +{/if} + +{foreach from=$otherMoreSubMenu item=group} +{if !empty($group.tabs)} + +{/if} +{/foreach} + + diff --git a/include/SugarCache/SugarCache.php b/include/SugarCache/SugarCache.php new file mode 100644 index 00000000..7702a650 --- /dev/null +++ b/include/SugarCache/SugarCache.php @@ -0,0 +1,181 @@ +debug("Found cache backend $cacheClass"); + $cacheInstance = new $cacheClass(); + if ( $cacheInstance->useBackend() + && $cacheInstance->getPriority() < $lastPriority ) { + $GLOBALS['log']->debug("Using cache backend $cacheClass, since ".$cacheInstance->getPriority()." is less than ".$lastPriority); + self::$_cacheInstance = $cacheInstance; + $lastPriority = $cacheInstance->getPriority(); + } + } + } + } + } + } + + /** + * Returns the instance of the SugarCacheAbstract object, cooresponding to the external + * cache being used. + */ + public static function instance() + { + if ( !is_subclass_of(self::$_cacheInstance,'SugarCacheAbstract') ) + self::_init(); + + return self::$_cacheInstance; + } +} + +/** + * Procedural API for external cache + */ + +/** + * Retrieve a key from cache. For the Zend Platform, a maximum age of 5 minutes is assumed. + * + * @param String $key -- The item to retrieve. + * @return The item unserialized + */ +function sugar_cache_retrieve($key) +{ + return SugarCache::instance()->$key; +} + +/** + * Put a value in the cache under a key + * + * @param String $key -- Global namespace cache. Key for the data. + * @param Serializable $value -- The value to store in the cache. + */ +function sugar_cache_put($key, $value) +{ + SugarCache::instance()->$key = $value; +} + +/** + * Clear a key from the cache. This is used to invalidate a single key. + * + * @param String $key -- Key from global namespace + */ +function sugar_cache_clear($key) +{ + unset(SugarCache::instance()->$key); +} + +/** + * Turn off external caching for the rest of this round trip and for all round + * trips for the next cache timeout. This function should be called when global arrays + * are affected (studio, module loader, upgrade wizard, ... ) and it is not ok to + * wait for the cache to expire in order to see the change. + */ +function sugar_cache_reset() +{ + SugarCache::instance()->reset(); +} + +/** + * Internal -- Determine if there is an external cache available for use. + * + * @deprecated + */ +function check_cache() +{ + SugarCache::instance(); +} + +/** + * This function is called once an external cache has been identified to ensure that it is correctly + * working. + * + * @deprecated + * + * @return true for success, false for failure. + */ +function sugar_cache_validate() +{ + $instance = SugarCache::instance(); + + return is_object($instance); +} + +/** + * Internal -- This function actually retrieves information from the caches. + * It is a helper function that provides that actual cache API abstraction. + * + * @param unknown_type $key + * @return unknown + * @deprecated + * @see sugar_cache_retrieve + */ +function external_cache_retrieve_helper($key) +{ + return SugarCache::instance()->$key; +} diff --git a/include/SugarCache/SugarCacheAPC.php b/include/SugarCache/SugarCacheAPC.php new file mode 100644 index 00000000..d2ffb56d --- /dev/null +++ b/include/SugarCache/SugarCacheAPC.php @@ -0,0 +1,104 @@ +expireTimeout); + } + + /** + * @see SugarCacheAbstract::_getExternal() + */ + protected function _getExternal( + $key + ) + { + if ( apc_fetch($key) === false ) { + return null; + } + + return apc_fetch($key); + } + + /** + * @see SugarCacheAbstract::_clearExternal() + */ + protected function _clearExternal( + $key + ) + { + apc_delete($key); + } + + /** + * @see SugarCacheAbstract::_resetExternal() + */ + protected function _resetExternal() + { + apc_clear_cache('user'); + } +} diff --git a/include/SugarCache/SugarCacheAbstract.php b/include/SugarCache/SugarCacheAbstract.php new file mode 100644 index 00000000..a41deab7 --- /dev/null +++ b/include/SugarCache/SugarCacheAbstract.php @@ -0,0 +1,315 @@ +_expireTimeout = $GLOBALS['sugar_config']['cache_expire_timeout']; + if ( isset($GLOBALS['sugar_config']['unique_key']) ) + $this->_keyPrefix = $GLOBALS['sugar_config']['unique_key']; + } + + /** + * Destructor + */ + public function __destruct() + { + } + + /** + * PHP's magic __get() method, used here for getting the current value from the cache. + * + * @param string $key + * @return mixed + */ + public function __get( + $key + ) + { + if ( SugarCache::$isCacheReset ) + return; + + $this->_cacheRequests++; + if ( !$this->useLocalStore || !isset($this->_localStore[$key]) ) { + $this->_localStore[$key] = $this->_getExternal($this->_keyPrefix.$key); + if ( isset($this->_localStore[$key]) ) { + $this->_cacheExternalHits++; + } + else { + $this->_cacheMisses++; + } + } + elseif ( isset($this->_localStore[$key]) ) { + $this->_cacheLocalHits++; + } + + if ( isset($this->_localStore[$key]) ) { + return $this->_localStore[$key]; + } + + return null; + } + + /** + * PHP's magic __set() method, used here for setting a value for a key in the cache. + * + * @param string $key + * @return mixed + */ + public function __set( + $key, + $value + ) + { + if ( is_null($value) ) { + $value = SugarCache::EXTERNAL_CACHE_NULL_VALUE; + } + + if ( $this->useLocalStore ) { + $this->_localStore[$key] = $value; + } + $this->_setExternal($this->_keyPrefix.$key,$value); + } + + /** + * PHP's magic __isset() method, used here for checking for a key in the cache. + * + * @param string $key + * @return mixed + */ + public function __isset( + $key + ) + { + return !is_null($this->__get($key)); + } + + /** + * PHP's magic __unset() method, used here for clearing a key in the cache. + * + * @param string $key + * @return mixed + */ + public function __unset( + $key + ) + { + unset($this->_localStore[$key]); + $this->_clearExternal($this->_keyPrefix.$key); + } + + /** + * Reset the cache for this request + */ + public function reset() + { + $this->_localStore = array(); + SugarCache::$isCacheReset = true; + } + + /** + * Reset the cache fully + */ + public function resetFull() + { + $this->reset(); + $this->_resetExternal(); + } + + /** + * Flush the contents of the cache + */ + public function flush() + { + $this->_localStore = array(); + $this->_resetExternal(); + } + + /** + * Returns the number of cache hits made + * + * @return array assocative array with each key have the value + */ + public function getCacheStats() + { + return array( + 'requests' => $this->_cacheRequests, + 'externalHits' => $this->_cacheExternalHits, + 'localHits' => $this->_cacheLocalHits, + 'misses' => $this->_cacheMisses, + ); + } + + /** + * Returns what backend is used for caching, uses normalized class name for lookup + * + * @return string + */ + public function __toString() + { + return strtolower(str_replace('SugarCache','',get_class($this))); + } + + /** + * Hook for the child implementations of the individual backends to provide thier own logic for + * setting a value from cache + * + * @param string $key + * @param mixed $value + */ + abstract protected function _setExternal( + $key, + $value + ); + + /** + * Hook for the child implementations of the individual backends to provide thier own logic for + * getting a value from cache + * + * @param string $key + * @return mixed $value, returns null if the key is not in the cache + */ + abstract protected function _getExternal( + $key + ); + + /** + * Hook for the child implementations of the individual backends to provide thier own logic for + * clearing a value out of thier cache + * + * @param string $key + */ + abstract protected function _clearExternal( + $key + ); + + /** + * Hook for the child implementations of the individual backends to provide thier own logic for + * clearing thier cache out fully + */ + abstract protected function _resetExternal(); + + /** + * Hook for testing if the backend should be used or not. Typically we'll extend this for backend specific + * checks as well. + * + * @return boolean true if we can use the backend, false if not + */ + public function useBackend() + { + if ( !empty($GLOBALS['sugar_config']['external_cache_disabled']) + && $GLOBALS['sugar_config']['external_cache_disabled'] == true ) { + return false; + } + + if (defined('SUGARCRM_IS_INSTALLING')) { + return false; + } + + if ( isset($GLOBALS['sugar_config']['external_cache_force_backend']) + && ( $GLOBALS['sugar_config']['external_cache_force_backend'] != (string) $this ) ) { + return false; + } + + return true; + } + + /** + * Returns the priority level for this backend + * + * @see self::$_priority + * + * @return int + */ + public function getPriority() + { + return $this->_priority; + } +} diff --git a/include/SugarCache/SugarCacheFile.php b/include/SugarCache/SugarCacheFile.php new file mode 100644 index 00000000..c7716633 --- /dev/null +++ b/include/SugarCache/SugarCacheFile.php @@ -0,0 +1,149 @@ +_cacheFileName = $GLOBALS['sugar_config']['external_cache_filename']; + } + + /** + * @see SugarCacheAbstract::__destruct() + * + * For this backend, we'll write the SugarCacheFile::$localCache array serialized out to a file + */ + public function __destruct() + { + parent::__destruct(); + + if ( $this->_cacheChanged ) + sugar_file_put_contents($GLOBALS['sugar_config']['cache_dir'].'/'.$this->_cacheFileName, + serialize($this->_localStore)); + } + + /** + * @see SugarCacheAbstract::_setExternal() + * + * Does nothing; we write to cache on destroy + */ + protected function _setExternal( + $key, + $value + ) + { + $this->_cacheChanged = true; + } + + /** + * @see SugarCacheAbstract::_getExternal() + */ + protected function _getExternal( + $key + ) + { + // load up the external cache file + if ( sugar_is_file($GLOBALS['sugar_config']['cache_dir'].'/'.$this->_cacheFileName) ) + $this->localCache = unserialize( + file_get_contents($GLOBALS['sugar_config']['cache_dir'].'/'.$this->_cacheFileName)); + + if ( isset($this->_localStore[$key]) ) + return $this->_localStore[$key]; + } + + /** + * @see SugarCacheAbstract::_clearExternal() + * + * Does nothing; we write to cache on destroy + */ + protected function _clearExternal( + $key + ) + { + $this->_cacheChanged = true; + } + + /** + * @see SugarCacheAbstract::_resetExternal() + * + * Does nothing; we write to cache on destroy + */ + protected function _resetExternal() + { + $this->_cacheChanged = true; + } +} diff --git a/include/SugarCache/SugarCacheMemcache.php b/include/SugarCache/SugarCacheMemcache.php new file mode 100644 index 00000000..277bd0a6 --- /dev/null +++ b/include/SugarCache/SugarCacheMemcache.php @@ -0,0 +1,143 @@ +_getMemcacheObject() ) + return true; + + return false; + } + + /** + * @see SugarCacheAbstract::__construct() + */ + public function __construct() + { + parent::__construct(); + } + + /** + * Get the memcache object; initialize if needed + */ + protected function _getMemcacheObject() + { + if ( !($this->_memcache instanceOf Memcache) ) { + $this->_memcache = new Memcache(); + $this->_host = SugarConfig::getInstance()->get('external_cache.memcache.host', $this->_host); + $this->_port = SugarConfig::getInstance()->get('external_cache.memcache.port', $this->_port); + if ( !@$this->_memcache->connect($this->_host,$this->_port) ) { + return false; + } + } + + return $this->_memcache; + } + + /** + * @see SugarCacheAbstract::_setExternal() + */ + protected function _setExternal( + $key, + $value + ) + { + $this->_getMemcacheObject()->set($key, $value, $this->expireTimeout); + } + + /** + * @see SugarCacheAbstract::_getExternal() + */ + protected function _getExternal( + $key + ) + { + $returnValue = $this->_getMemcacheObject()->get($key); + if ( $returnValue === false ) { + return null; + } + + return $returnValue; + } + + /** + * @see SugarCacheAbstract::_clearExternal() + */ + protected function _clearExternal( + $key + ) + { + $this->_getMemcacheObject()->delete($key); + } + + /** + * @see SugarCacheAbstract::_resetExternal() + */ + protected function _resetExternal() + { + $this->_getMemcacheObject()->flush(); + } +} diff --git a/include/SugarCache/SugarCacheMemcached.php b/include/SugarCache/SugarCacheMemcached.php new file mode 100644 index 00000000..ac748442 --- /dev/null +++ b/include/SugarCache/SugarCacheMemcached.php @@ -0,0 +1,143 @@ +_getMemcachedObject() ) + return true; + + return false; + } + + /** + * @see SugarCacheAbstract::__construct() + */ + public function __construct() + { + parent::__construct(); + } + + /** + * Get the memcached object; initialize if needed + */ + protected function _getMemcachedObject() + { + if ( !($this->_memcached instanceOf Memcached) ) { + $this->_memcached = new Memcached(); + $this->_host = SugarConfig::getInstance()->get('external_cache.memcache.host', $this->_host); + $this->_port = SugarConfig::getInstance()->get('external_cache.memcache.port', $this->_port); + if ( !@$this->_memcached->addServer($this->_host,$this->_port) ) { + return false; + } + } + + return $this->_memcached; + } + + /** + * @see SugarCacheAbstract::_setExternal() + */ + protected function _setExternal( + $key, + $value + ) + { + $this->_getMemcachedObject()->set($key, $value, $this->expireTimeout); + } + + /** + * @see SugarCacheAbstract::_getExternal() + */ + protected function _getExternal( + $key + ) + { + $returnValue = $this->_getMemcachedObject()->get($key); + if ( $this->_getMemcachedObject()->getResultCode() == Memcached::RES_NOTFOUND ) { + return null; + } + + return $returnValue; + } + + /** + * @see SugarCacheAbstract::_clearExternal() + */ + protected function _clearExternal( + $key + ) + { + $this->_getMemcachedObject()->delete($key); + } + + /** + * @see SugarCacheAbstract::_resetExternal() + */ + protected function _resetExternal() + { + $this->_getMemcachedObject()->flush(); + } +} diff --git a/include/SugarCache/SugarCacheMemory.php b/include/SugarCache/SugarCacheMemory.php new file mode 100644 index 00000000..a13de319 --- /dev/null +++ b/include/SugarCache/SugarCacheMemory.php @@ -0,0 +1,98 @@ +_getRedisObject() ) + return true; + + return false; + } + + /** + * @see SugarCacheAbstract::__construct() + */ + public function __construct() + { + parent::__construct(); + } + + /** + * Get the memcache object; initialize if needed + */ + protected function _getRedisObject() + { + try { + if ( !($this->_redis instanceOf Redis) ) { + $this->_redis = new Redis(); + $this->_host = SugarConfig::getInstance()->get('external_cache.redis.host', $this->_host); + $this->_port = SugarConfig::getInstance()->get('external_cache.redis.port', $this->_port); + if ( !$this->_redis->connect($this->_host,$this->_port) ) { + return false; + } + } + } + catch (RedisException $e) + { + return false; + } + + return $this->_redis; + } + + /** + * @see SugarCacheAbstract::_setExternal() + */ + protected function _setExternal( + $key, + $value + ) + { + $value = serialize($value); + $key = $this->_fixKeyName($key); + + $this->_getRedisObject()->set($key,$value); + $this->_getRedisObject()->expire($key, $this->expireTimeout); + } + + /** + * @see SugarCacheAbstract::_getExternal() + */ + protected function _getExternal( + $key + ) + { + $key = $this->_fixKeyName($key); + $returnValue = $this->_getRedisObject()->get($key); + // return null if we don't get a cache hit + if ( $returnValue === false ) { + return null; + } + + return is_string($returnValue) ? + unserialize($returnValue) : + $returnValue; + } + + /** + * @see SugarCacheAbstract::_clearExternal() + */ + protected function _clearExternal( + $key + ) + { + $key = $this->_fixKeyName($key); + $this->_getRedisObject()->delete($key); + } + + /** + * @see SugarCacheAbstract::_resetExternal() + */ + protected function _resetExternal() + { + $this->_getRedisObject()->flushAll(); + } + + /** + * Fixed the key naming used so we don't have any spaces + * + * @param string $key + * @return string fixed key name + */ + protected function _fixKeyName($key) + { + return str_replace(' ','_',$key); + } +} diff --git a/include/SugarCache/SugarCacheWincache.php b/include/SugarCache/SugarCacheWincache.php new file mode 100644 index 00000000..c59b63fe --- /dev/null +++ b/include/SugarCache/SugarCacheWincache.php @@ -0,0 +1,104 @@ +expireTimeout); + } + + /** + * @see SugarCacheAbstract::_getExternal() + */ + protected function _getExternal( + $key + ) + { + if ( !wincache_ucache_exists($key) ) { + return null; + } + + return wincache_ucache_get($key); + } + + /** + * @see SugarCacheAbstract::_clearExternal() + */ + protected function _clearExternal( + $key + ) + { + wincache_ucache_delete($key); + } + + /** + * @see SugarCacheAbstract::_resetExternal() + */ + protected function _resetExternal() + { + wincache_ucache_clear(); + } +} diff --git a/include/SugarCache/SugarCacheZend.php b/include/SugarCache/SugarCacheZend.php new file mode 100644 index 00000000..4fe23d09 --- /dev/null +++ b/include/SugarCache/SugarCacheZend.php @@ -0,0 +1,103 @@ +expireTimeout); + } + + /** + * @see SugarCacheAbstract::_getExternal() + */ + protected function _getExternal( + $key + ) + { + $raw_cache_value = zend_shm_cache_fetch($key); + return is_string($raw_cache_value) ? + unserialize($raw_cache_value) : + $raw_cache_value; + } + + /** + * @see SugarCacheAbstract::_clearExternal() + */ + protected function _clearExternal( + $key + ) + { + zend_shm_cache_delete($key); + } + + /** + * @see SugarCacheAbstract::_resetExternal() + */ + protected function _resetExternal() + { + zend_shm_cache_clear(); + } +} diff --git a/include/SugarCache/SugarCachesMash.php b/include/SugarCache/SugarCachesMash.php new file mode 100644 index 00000000..9781785a --- /dev/null +++ b/include/SugarCache/SugarCachesMash.php @@ -0,0 +1,100 @@ +_keyPrefix.'/'.$key, $value, $this->expireTimeout); + } + + /** + * @see SugarCacheAbstract::_getExternal() + */ + protected function _getExternal( + $key + ) + { + return zget('/tmp/'.$this->_keyPrefix.'/'.$key,null); + } + + /** + * @see SugarCacheAbstract::_clearExternal() + */ + protected function _clearExternal( + $key + ) + { + zdelete('/tmp/'.$this->_keyPrefix.'/'.$key); + } + + /** + * @see SugarCacheAbstract::_resetExternal() + */ + protected function _resetExternal() + { + zdelete('/tmp/'.$this->_keyPrefix.'/'); + } +} diff --git a/include/SugarCharts/Jit/FlashCanvas/canvas2png.js b/include/SugarCharts/Jit/FlashCanvas/canvas2png.js new file mode 100644 index 00000000..f4cb2507 --- /dev/null +++ b/include/SugarCharts/Jit/FlashCanvas/canvas2png.js @@ -0,0 +1,9 @@ +/* + * canvas2png.js + * + * Copyright (c) 2010-2011 Shinya Muramatsu + * Released under the MIT License + * http://flashcanvas.net/ + */ +(function(doc){var scripts=doc.getElementsByTagName("script");var script=scripts[scripts.length-1];var url=script.getAttribute("src").replace(/[^\/]+$/,"save.php");window.canvas2png=function(canvas){var tagName=canvas.tagName.toLowerCase();if(tagName!=="canvas"){return;} +if(typeof FlashCanvas!=="undefined"){FlashCanvas.saveImage(canvas);}else{var form=doc.createElement("form");var input=doc.createElement("input");form.setAttribute("action",url);form.setAttribute("method","post");input.setAttribute("type","hidden");input.setAttribute("name","dataurl");input.setAttribute("value",canvas.toDataURL());doc.body.appendChild(form);form.appendChild(input);form.submit();form.removeChild(input);doc.body.removeChild(form);}}})(document); \ No newline at end of file diff --git a/include/SugarCharts/Jit/FlashCanvas/flashcanvas.js b/include/SugarCharts/Jit/FlashCanvas/flashcanvas.js new file mode 100644 index 00000000..2ecd5479 --- /dev/null +++ b/include/SugarCharts/Jit/FlashCanvas/flashcanvas.js @@ -0,0 +1,8 @@ +/* + * FlashCanvas + * + * Copyright (c) 2009 Tim Cameron Ryan + * Copyright (c) 2009-2011 FlashCanvas Project + * Released under the MIT/X License + */ +window.ActiveXObject&&!window.CanvasRenderingContext2D&&function(h,j){function D(a){this.code=a;this.message=T[a]}function U(a){this.width=a}function E(a){this.id=a.C++}function t(a){this.G=a;this.id=a.C++}function u(a,b){this.canvas=a;this.B=b;this.d=a.uniqueID;this.D();this.C=0;this.t="";var c=this;setInterval(function(){n[c.d]===0&&c.e()},30)}function A(){if(j.readyState==="complete"){j.detachEvent(F,A);for(var a=j.getElementsByTagName(r),b=0,c=a.length;b=8?a.src:a.getAttribute("src",4)}function v(a){return(""+a).replace(/&/g,"&").replace(/0)return eval(this.B.CallFunction(''+a.join("�")+""))},I:function(a,b){this.e();this.D();if(a>0)this.B.width=a;if(b>0)this.B.height=b;this.a.push(e.resize,a,b)}};t.prototype={addColorStop:function(a,b){if(isNaN(a)||a<0||a>1)i(1);this.G.a.push(e.addColorStop,this.id,a,b)}};D.prototype=Error();var T={1:"INDEX_SIZE_ERR",9:"NOT_SUPPORTED_ERR",11:"INVALID_STATE_ERR",12:"SYNTAX_ERR",17:"TYPE_MISMATCH_ERR",18:"SECURITY_ERR"},B={initElement:function(a){if(a.getContext)return a;var b=a.uniqueID,c="external"+b;x[b]=false;n[b]=1;Q(a);a.innerHTML='';s[b]=a;var d=a.firstChild;y[b]=a.lastChild;var f=j.body.contains;if(f(a))d.movie=w;else var g=setInterval(function(){if(f(a)){clearInterval(g);d.movie=w}},0);if(j.compatMode==="BackCompat"||!h.XMLHttpRequest)y[b].style.overflow="hidden";var o=new u(a,d);a.getContext=function(l){return l==="2d"?o:k};a.toDataURL=function(l,z){(""+l).replace(/[A-Z]+/g,W)==="image/jpeg"?o.a.push(e.toDataURL,l,typeof z==="number"?z:""):o.a.push(e.toDataURL,l);return o.e()};d.attachEvent(K,G);return a},saveImage:function(a){a.firstChild.saveImage()},setOptions:function(){},trigger:function(a,b){s[a].fireEvent("on"+b)},unlock:function(a,b){n[a]&&--n[a];if(b){var c=s[a],d=c.firstChild,f,g;Q(c);f=c.width;g=c.height;c.style.width=f+"px";c.style.height=g+"px";if(f>0)d.width=f;if(g>0)d.height=g;d.resize(f,g);c.attachEvent(L,H);x[a]=true}}};j.createElement(r);j.createStyleSheet().cssText=r+"{display:inline-block;overflow:hidden;width:300px;height:150px}";j.readyState==="complete"?A():j.attachEvent(F,A);h.attachEvent(J,I);if(w.indexOf(location.protocol+"//"+location.host+"/")===0){var S=new ActiveXObject("Microsoft.XMLHTTP");S.open("GET",w,false);S.send(k)}h[M]=u;h[N]=t;h[O]=E;h[C]=B;h[P]={init:function(){},init_:function(){},initElement:B.initElement};keep=u.measureText}(window,document); \ No newline at end of file diff --git a/include/SugarCharts/Jit/FlashCanvas/flashcanvas.swf b/include/SugarCharts/Jit/FlashCanvas/flashcanvas.swf new file mode 100644 index 0000000000000000000000000000000000000000..66ff213fb9b86811d17f032be3c73df61547e597 GIT binary patch literal 21235 zcmV)3K+C^FS5pbJn*acK+RVKNe3M7gKmN>9^hmO7%f>biJ}yp>fH;q^A>~Me&>Zjq zPH3q%DweQ=Z8?%m$=$tYNJt?KLK4zrAS5BATzYS$cVq`Uz4zXe;}Z1$&OVPM+i>LW z-ur$2uaDhlW_EXWc6N4mW}ip7C6fBCB;{QrNu?xBF4#koq`wY&nk4DaSVQFCS(B^F zm$Wpu#t#N|*oekNqV3?y%EgNpk6OInsAz0K<>-SBI;gU0Oy!s{KGg8Vm$oJXOMI>I zVI#%~29v|_P^_sf(G+bhXFL#$wkHl7F~Z{75XvxZYmYSxmJOlGaC5jN+?t42jvh4{ zj2c1*N20NoKw?~=t*yB!6kv9hOMLOhXlUW$z@o4((j1649$J~L$ZZl$iRSRQ2@TO; zxV*YKyrg`;@(J1YqPAIuD>q~X9oJ`=0d74i6m6+&i$xpSLy#!~R-$p=Cd{I(J=ok7 zZw$xAwYM&8jV?C3$WpmZC>9PRqWx>6XEedDCb?vIs2rAcxsl{(I;V18{#igwm$N&F4^{GjK2nD6JD z)vUxxf!0NVxb#rb(n}->WGNC0w1h`XZfTTsDcvAnL}Mg9MKUQXZ@;dwqvPVkyUtkm zj0)!ZOUqY3qds=|g}}afRPXKmOi!hhmylAaNA=e~>(w87I;B6~o6_Iyy-vOUr3yBUbFE*dAy#7r}zyG?gZD*~O&pP{EZBzF(+Gk(>sGYU! z2KDBiZF0xOJM`y1cwg=4xIx{1!!`POe}7Ot>mQx+i&s8C$t#rZWn0xXn|?v(@+Vyz zmDIYE*FW}@_Vo`bef>o%DYfhu{q=jkv!%XyPw%)XrFTB_sjXw#axjx`-f@@qHAKC= z`&a$-yYH|qUv`81HO6)J^N;G=pTA81;hmJ;@$+}e^I-MiEq7@h%eJ7CQ}nJMKGVCe zebKh+jYri-zSyB}e|U#}{Rhiw`xRHIm#ltMdGpLiwYR~iV~292a_JAsa~n3uD>h$l`})>~?Wtb<9q8;1q#GYVr=R_V zmdn)*m*1pxJhMaZSoy2o^Uf!>>y!8C7ytC0`sEuBX=~p3!nW_~-A~q^w%DMcIx4r*i4(R zDt~$W!Dm;!d+yRH<51}-N5wl_ufcuS7kEOisjntP#GiWjSAnUw969>O@y|qOtiI`^ z@5f(X(EL?!>$l?%dFa}Qn>?S4zpwnsKb?HkJLBs%$KITKU2^=mi^GvCJ3kzMP-We< z@BZcG@n=r(f3S7$?(sqQF$dlL)Vt%KUi9EqLno_SJ{l7WcH?xApdiHffT&DB9HE68q4o@FL#4oO7C5!m%j~+h!+XO|1)*rq+Ze z2+kSN_IOx;L$JAwS`dvcXby*>4dGFOMM$i|QgboR3b!_dx&5SQYa+ZPF=nzhtp$66 zb4n~0wK|yD-VzMQ98FBGY-?R$Gn?j3Z)yz(Vn@UR4Na()Hw(`|a~jPxD;*g~B*L*) zePT4)91gTP%|UQa&N;}c#g6I_T}}=p0#^BgaI{4`GKwMPnuLa?cw2K|sU6(g8k<6K z=ftK&OQ4OLXcJ9O^L9U;F-|GeCS}?5@>DECz(%|D4PnX z8TyOkFcAYS5eL<@M7U)(4x>=Qs({vF3T&}(yy@g{K}%*DtqL}C=IrKUT0>rVNjTJ= z2wT0Wk*4P6oaSht!K&|!Ct}fsVb-&q%Vwc3yCq^gUz`l#jOL3>y#FNX5Cx}4*w&1x zo)fj|^q+V4N$r7#7>>Qrr1sb%)XHs&i>aH|$|`g5kR}G=VP@e9^AuR(<-{8?1&b#| zo1-x$lvq-_pg9^0G-EVv(Ks|)+ZK+A(=?|g9Ei8a#6WB7A9&^RRi8--A zYn)GK2lsMxQ$wOrYYW8UVP^{%#ilpmVKcR1DTQ_62sKCJVHVQP&1xXD&cLKVo7U9Y z)}C-#niU2xxT&=%0o`C~Cc_#7iBRL5K(INiMlfw^sJW?4i-!WuVI>d?JUClspEP^6u#;iC)2dZRZ)^{bi7g1)FgrlC z0NaTU!kEVJ61_3r%uh{}*%MJ~E1oZE!C0~UY|Y`;1(U^<(rq^pYR=yii&2ul9IaridxG{#7w&rjmoZi|q z1bZ6DnV)6ktU2oZ$sk2EBL&GYBZ%j2D9YI`Jty=P9ad5?IaVSXSqKhzkDwluW{ zT0`OaivrE<;kZ8Qh>2s4ojcF5m`@@sp17#nu&cVZ zG%^P;ci!a8KwvNVEcsFGf!2iJ8FyGLs;iWFljj!j)ZsMED!z0lc`d01TLKRpi0xRx zxOAuD^k`rc3^*c_C(RLp;4C*4Y2zdE!2Nf(^_ew1zh%L~Cz_AYEueBX@;A3UYj3yB z7Z&M^h1tDY>$B z-jCW%54)(oyV3Xem3CLNzvpF#=?DcCEU+lEd9$y^3ehm21>rq+!-{2dX5AH)&*~vN z?K~NmSAq2^*k1SjZBxm(!}@%4KXzn11uDqIu|Yj(*}r&xcJ8rxeJxj zPoFjulv;g8?L2JZl#v)JOyxFfza4yWEe8(uj^wv;Mz0?p0Q#gn5gfu`0xD}GzTi!IPx zFvS9Jn1y4JKqy?;0`H&^Ev769g~d%vJcnH|P=Yv}Fg9!BHZ^J0ZtVjofdCy3Wb&SShHv0G(8r9a=hVveMK!**{cD5okSU9DX4WvPvG=18nKf0kh(cAQ< zIG<`U*W}u{u#)+r)NaL%O*xj^HzVBIp5F)NV9h-nUTwM9W6LMRM~xa)FoEN^@;))4 zyH67{(3~-4=G^(y=1iF}fA*B=Qzp%EH#RkdC-MwTYh|YKoKQPLtQG;QZSC>KoKTiW zVISV3+FP5Wp@k~!vRRumZN`*Yn(+TL;hJc|Nwtd@lWov4kOoI4)*KWIbL`Yl38Fsh z&tWQ{HJorFY?u{338z`2wC{~*G?WM@d^Zg; z0q3>`7Bwxv0+|y@ZYJghX=R`7q|!D& z*c@nGnA^{?3U;!?l3kmxy}G?s#3i})VkbPI^2E0A0uME*2@Jw6e01>An&LA9GxcFr z;!ov;rcIeOt9F(RT8DR^D>lQ~tpRb=*d|Ordcv`@2P`V{z;tkAhdmo19iPYt8@5*A zHsP3STPnE3o#y2V3!-yl#HE_3Yd<6?j(tOIfhVuDMceEPtP@BRQKK1>arB_W{pY8> zDPGOHWY`Ws1Ho@x1P1EN z+L=?-V0$8=&8nR{bFvnTwzoFe;t2O+VcYDZ=1!P3#mO;q!VFs`PMJ4lx)#LBZq`K9 zt<8Yl&$9F3BcknzI58S{M}-0*fJ8hb0k5p#JcM^2bLXj*32Fhh$DU%r5w9FaNi z(KJt-oS8tfKumVJ22XZgs9%MAQNc7jF1D`E5a{!{;5-7SQMG`z`V-<69*4MtYYI0v z6l9iJmG7W{FH-lX{r=)%+JSv(2ZDxBbo2rB$WIsv%^bh4 zuWtMa4f_H#c8i{{k7zn(LjR`6pU^O>ZeMTT`nx58jRppR(NmdE;NO#B0KY!$#>^SO z?%$Pbm#h_p>xb7P8_4(H8Lo=tnJ_0OXN#Jmi0rjsEV{VW z5rj9gba6D=;0VD1ONdILMjXenaCEH80dd zv8I-Iv{el)4Yb-D0+jMKoqr|0u|AN1%}{_=nTff4T2OGgLVlp91yL95aRNZWy@kLNnb2%Vu|+H zN$t_5xY>oNGkZfg%%|kS90uYGmog`ub1lrne1?}g8=?&hO#L__O|ftg8^*#MC=L1( zGnj)74hOUlN{_UM8skj?#{wMb@nAF-buMU(#uMgLv&tM9y{X)b%3WxpZH~y7hS@c@ zHzF8Z+7Mo>H%1dIp`)o4VOT5lVPj}PRBKv<@LUtRwKv0E;ybq7GyrMijgIEP;#R@b z)eIjC#?usuL|btHU7T9S);F>04ngt{@DIjyYa!uHp zFPDj#O3pKp^nCS0!)Y`T4mWdUlcy<&+T7H_QF4oEIvSr$t-57b2-;)OXsf#=+|bnC zl3i0ylOWcf37RHmA#LrkHXLatk`_1LLemCTVBu{Xnf9%bF)Rx=O$!s{!hznJR<#3h zbAs=zTL8rqOJne)>@CqyC;+D-2kvO##HeW`fS2mfK8FpOSR@XS!(R#7%vItrA8ZWf zKyuq~#%HF?AuzE<7|IAJu#9+cS=s_i1L(BP(H0Jb8r#|<5w$HGYgc(9)wbsL7H3;@ zv1v_Vo2exQEgcYkskz<6qDuqj9K{3dy$Gt!oPK9K(Ar?uv!}JnK)ew%X^X>CXbs@e z3{OS3%)*gTw4;VcCbQAcL*Hfx() z+!zjU4plov9&d>*4BJfW$}u12a!f?0^Ts#{ey+-1iOQadjW^Q?3At*CE#4kP*g*z) zbu7v7lG=!dT>&oZFip7TO4X<;aoUZPjdI$DB&xDa7h!RM6{k$k1j+VEwKI;KK4s1n z`?T8m!kf<#Zno)uJJ`t=euS%@1CjXngHNbDp;8-<&HgZFmWyuj&26wkSMxoo8H?LE zP75>~K4Idd$y2J2m^!WIkJD$&tUdCmS+nQNopr@sgz{SB)OC-~I<2_=m9v?OREQxsR`(;5#nhI~jh;3Hu`A%@w1pGQ|J($%#kX zW1+AQL0v3=bXD7uau`C~7Z1mpBCfQL$RV1IuRtcuDllK=q)R47m)K@am^^L5bUkFg zA3C~(N|X{uNm0q*l08a(U$S@U2u&(AklITZBkv$&7g6cO{G5ZdiGkZVdy7in=I48y zeL|(*Qt8iB`gbbb&V(IQx=b!TRR(xEGEFMEQZ88!XfWAtkcW&Ia-%%tCV9xs@{qsD zLvE3WcuF3WOI||x5OhA+F=X+OuNmo}lE)Mf_8xK(xDH`4hCqxVEWwbsh#3$0gyHQb zyo21iPO7XL?Xa|JchMnLqjL@&OXSKY<*;$1^Tr-5qrK%Uu0jdjcc*SX_{&l|f|)k)T6#qHE*96@)QFl$!U6Xa!6x~&=yN=LZQ+3xg-BqKz{;1P*-8EWw&Cp#lbyuzK zI#PEXrMqV7uGu=x(Oq+O*F4>IwC*}acO9#{j?-Po>#h@YSDo&v*In~+Yg?h5O!i0)dTyBc*@lkPfEcP-Ri&AO{aceU!SsP1ahT_@?TnC^<}N&Vmgi0sa2{>j1Au+JJO5(nh3fkgg?Nz7Egpkv5ZFdIQppNH-zf4BFrDyaoN- zO8Su7k?ugc6X`CbyOHiex)My7lW+NVgLk*j^`ancLKf#&wG*XL%JX70a-ujA*6?~D?JMQ zF{H=J@dJ$e@GQ8TQHVLHJR2`v>fRaq*E2gRoGx@1>n;Zecb8beFoq&k0ZV0HE5q9{ebih(pN}daGm>5em^97 z0M7>%$EQ4!hZJ3V82BTK<9f!o0De@_Cq1s{>XS%M0e>3l8Kh^Co=18C=|!ZiNJ*qF z#o>e^Ujn#|yMU4O;Mt4xGSVwbnT}}#^qS(hknH;ClzW z+n~LR^ghyuilfZo_!!WqTzWeApA8OYX!_`@$g!5RGN)q>#$8tHxaSGC{WG{0$-XzUYqB#n+vRua*axT=F3w7o?J_h|K z9HzFb(R3ryHJZbX$F*8n9xCQJ3LwWar7R!ILvsw*9K-AmujV*S)>g{aCx9}M%%7nu z45}(XxD9r4xrl5glKGP*oj-0RtGZ+%|L2nQ8+2*cb;zz*1154vyZnmkbkLMfyul8f@l)Md7(oV0owO7|#}Gu_w(ZOHkrFO=;_h^JT_xp@XqT~@2ybSpVe zOwZ13Gr&&r?*gzY%PN^%2R{1`#LUxW*%4^u?BC2P%7>i+?K1_kB)Cdx8Qp!6G@z2g zT4_M`?Bj3sAYh>{6$KjA{zAInf|1=S>Yfn+c*fM`*Y{!Fn#L9pLP->;$4O|xk)(%;M4`>eyVM=kI)c3Ds z*Q-vIER|Y+HYqceS$=*0hNks0Nczn`m|R-OlHc#?a7dI>E=hYydrQ(V$wQLtB}p4j zl0E`PB#k6VMQm-W;B~w&kI%rQ4l8ryNY3#-lB!0LG_jJTu~j5_N3&#ONIGOcl7{S0 zQvLxXRUAmt9)BQd-?7~IAd>bwn4|*_A!*W~Bn>-^`xr-3$#{|uI-I0^CXlrEM3Rao zk@UOCB)O)Lba*vMdmcg3=&2+PpGMNi8j^nhN0Nq4m!uieOl&o^B<+7BNn?&8$vumt z%Go4Mm_t(GT#^o(N75gTCdqRQNrR6iso*%04mh6WJb|Q9btIM7leE`-l5+hd83B?8 z1xfOSNGfe0>CiAq<02%LEg)$`BS{B0v8kL$Qt?8P@|sB+-%{qtm8zwjR!5#REeFav zGP<`^(~o0h5*Z-qQ30E4>|h_#awC(#-fUX@*|ra7(l2EGFp!T0+t# zv{aE6o=nobKasSG{!G%J{zB5y{~_r@`YTDNQU|ub$TH#qEC+b>DaiikRAi^q3Sxsg z4e(!2M|LrtfqW&M334HxvUCoe1DJ0bGtCMV6XZqq_fU;O8S)QKa})$QEB?3Um%CoPpSdFskd2AF~PB zDF|W+qHRWg+zrUq(v8T^qnl8B?#*a^(%*m|dkdh33y`&6j)Jr3RuC_RM2ggOGYD-P zk;N`W7Pt*1OKwNjfw)SMqIUpXMt35=i0(pu{N2bF+=8m1dr)3~uTcLz!0R>uZ@G_n zaokU3jzVbzNe=)RBwa)H2hnU3J%rLyRe2cIH`5~^U5iMGr0eKWP_C!P0N+55qmom$ z%_wseONhsw5IsD}Ev2VW;Z}NDz|R2w8$FBs7J3f(ZDfC*9D~uf;{|ZLk6uK64{ar0 zYe`hN8x%#llez%kMctt1JDo3~(!I2ec*p92uzN@^P(`ok@@3R}gkBNwtAL-U*N{I- zuM5f>B7YN<$LTHPkI~!6pP_dI{aum2hg?;a_XY9+ieID;k#C`o1m$DEPtzv?{#4|j ziTrbse}U2`5tA|emB_ya`48Ngru>NFhv+BdPtnh!;O~GR zrtJd$hsb{s`L811A@UUJJb_4#;bn4}qfCNI3d$V6lU^g+a+&pgipWoudH-J_%TP&F zhK}O0^a|ybIerga*iVy5dYev19lLY};I|M2%1{G4oQlNL@-CeP`a5*C%o;xjU6o58 zlKotuPE|P%k5#hEwHkFkLU1TUFKdKQ7XbbkA)+jOf*_H(m6SR5f|3R;Wn`_)YxH8# z97}~sD@A^}$S)<{tS$l9FX<}44-hPi58{m?zd+=xMb%qG)k|3(tar}u5&2~z-yrH- z2C?^+zQLA!j_er5`p*U6k>HK5miLl=Mz|`5bA>GC|4PPe%K7r%n2Vuhj^UU9?J5Yf zgF40FR)~BZC@Eqgf2AR1juFywSzd2)*kC?>SLPUr%7}bXylDIxFAeNN#K2e@3xjrL02h`lJh)Pt-`(NQ{|-5FryRITX83M7a*rIimtoJLf%|0t{j$+1*FGSV|3P_p;2{|g;{d-=`>-s) z(f*NXaFpN6V0}ehPEC%~SW!R1UtwG$S1+Q*5p|Eq{)*a1WC}B%$QF4;3&3V7FWOU* zKzme-q{!{o-j{Vm+` zY1#jbY}_SJB;#(m`dL{HT+6M82c8o{vPGVk{rl9uAY0gr78a(ut#Zv)S?bs-w=kBJ zjYs5~q)Z)2xkWJvTQUR{QYii|Inpg-prU=VYT?5zT&{gdmiQUj#;C$oYI|gPE7KZ# zg_qSfprHQ=(@jGXM(qHA>Lgg!Z>fV*R zYTkve-j#d1jUGAhp4{z!Uyghr2R;OJKlv*nFHkj(jKB)H?jyO|cwMgjNM_D96@7VF zkc+^mOUzLboO$C7xrc>*6GC@cLhCHW@3&SNZ^`|-6dd19b3{l>_7PjF!jiwN%Kto7 z`9GGc{GT9winJ&G9U~1De~rIKbq8V<)m$J>Sy8n;w^r33KTm2rzP@R$)Yyb|vNhRw z*w(Jbv2`d|1tiM|3LqK{)m5) z|BwC}f3?5PU+0$3H#tG$DJEieFEqx-h-D3Wj;u)~b;xt9}l?+%}%j z4`ky*d7_-G{z9fg#2P4jmZbI`|6!4vDA`qgl04M}t4|^@$wPRi*{I2iWG(zVloal+@n+F@kgluRlwDLYpS{*I zq^1Ea4cM4VcTf##L0j!zWCOFJ{|>VY1+!v=s#+ea!mJdyhlfac;mUBy(7hMB1RSCnZguJ$%k(ag)uM*SPj{=%(>|GS-a ziq1x47yO@jeUHp8_;q5z@3Xr#yH>2(irrN?MO4}M-<9q(A)WExS-`i81?;ogRPEq@ zi&>gS?H#0n!>E6E6laT3RQ@NUc!s1!{YSA$jG`(#VSnZM8J(T5E5wA2$r7#=g#DOc z9)L0QyNU!GItKdeVg0Wef{@0rQiCZ0%mHc3*OV!Sk zalD1pks)nl$Tl*hj||yIh8!b9&XJ)U^Nfu5*+=+IqNP6N&~kkeh5pJ^U+26Mndb1!5Tj-rMvi(Q$f1?c};H-pV? zgb@VwKHWK>mqW5DIy4I&mIcSLcQHa}KCPd$=2=g@{^OH4I=Z@RzZP!Rc%F4P&pMm} zYvS8MKb+V2kbZ3VX|8eMOith$N3a`X?@9WbZZFJ*+)d0J1b2lb)!A$865uZ5Guc0i zo!~CNBl3;xKSaREz>9?XT>(e~Ph=vqt7H%ITiI_vJ=^Y`KJBtD@K`vLEX5>lHneXu ze^XcFMJfl|x>3p6QEbGM;Y%tQWZic%JCkL{(9p(Vpijv| z*)j6a#ukvL64`XK{xn6=?M0|x?*Cqn{2))0>qe$EQ-he%u0eNg7}p;aS-0n)?~zG= z+$^7-E{~ynMyA{!O`7F1ndHNm5PKEv1+69uiX^E%QKxUM(Wx=vPxzzY^&^y#nCeD= z&E9^k?$GVLV9GlN_wKbkq?UISg|zaHpX89OyrVFrmv{6KEU(QYZLTP=VWaoQ02Z>7 z{wBz1YD$j|cfijaDt@twT+qKX16pnc$zz=eQQvdCl;R6Wv-8IW!+)UX38 z5TLGz#T;I#))c8Mi~j|RoJ~TYxq|Fy3$Zj{R>oAlX-3z8Ns~j@1tbneN=xQ)vcnMRU|c@NA=fa zkZZ_)9{I1Kz%O$B`BXQwW~kJ7KGk1Bb%iyBQsX65f2IYVN%bqJuB4_!YFxoW&Ovym z9RjmL2W*L%zO%LJ{)|(p6U~l$(j6C$8qiVCP91S%V}f1W4>%pi8}97i z8bam2Foezhh5**b+wH1$H<`Rc`p(R|Ei}hOu|{^$ceYp^fZI&j<_wSx2Ng_Zm7H-! zYF5d%z{QquL48*W4yxi6yGNGi0ZW0^E3QC%x;QT&3Rx=Mj^Kc46(u@lOyn^;Nt6WO{2k188 zg9xnp3`Lr1f@m9rIXXjpsn=5#rlfhd=2vbj+{YZ@1A@S@5r>d&zIW>4d#7G;?=;k| zxQFpI9NL^C-&Rpzhr|NQyG_K7D@1b+H>qUAzGo^c6*^1d7m}eq65i5J!dtQu-og?# z{Oc0l@}En1%T5x8*_A}NSLYIQT;oz9OoUx*Y)y5!*@@4!p0Fa^wldW?M*;JN z%zQGR-7A%%e8J6Z8Cc3bQ4%%#kk4iEASQ!#PKJD*B4XNR?thfo{|54}QX;F(-d39e zn6y3;oX--pumnf21gPycd5We8iQR@JLY986pcgUye5J^hp`WjqA#`gW^p}okuA=J4NJ6#6 zYzL$JnCk!=y=s>>dIaVCt~_IWinK&S47se&1_mdn?+%qkyDhZehILUPpNu%r#bH6EkXmWlf>lOwl?D>TMe$o@+Rj5!DA9s~$yl1U1HYQk%kz*@eB|BH%!_0RuY zvjbJvo9*$|K0S7Wd3USoXacux@`|a^TmduJtFPDD9bO00A!zSwV7xINhrLFp6MFE}z z+!=Iaa97Z2E}M&#bsqPI_E0VeYt40J67tZ(9@Hy!t3^I=S1>1oyMgBfT^YOpxFhJy z;DteV(9M11u4DUT1pM>Xu~ilX3q(mLmoUO5ohSj1{Ghv1v3Lx!`bgtNzzc$f8N9gf z-0qx<`7~!cpZm+_eg-i#h#?`JkgABGB8G%qLY`uViWw?osE{F{GpA`OZZ;2R)>51q zOIb#aG8|A7phH^)S@)J!QF#IGSdr)P9qni;YTzlA(b3NaWncjVS zMJT7zp1z8}QF{YlN!6V~=B>0_Aqg#XZed^F*$!)SpeYQ{$yhGR99$-_yr9M%xI`=y z%z@?Qo0Qxv#SN>-TOV`*EPy2e%mv7{0;$|)AA^877}FUm0(*C`pmTkDs2JT@UXOVn4Cdd;l2nm zu@$b$#nKBpQSL65BsUNTlet0A;gL$eN~PSx&8qpktl4SREJ4kn+Kx?J#MwayuR*I% zb;E}0E3hKP8goGe-pjkq^@D-(M(&Y9`R;YhGY4BP*d)0)hl{b4KyY`Ngv-)|0zOQz zW-Jpb+__=5SaR8R0x#lbgMvj?v*Lep@@Dtb%pS`-^_F}rNLTUE7%RqJREaoAj6+LL zSV@l>~R z4Tkk?a4YKEnr)D+dzz>_M#MxY<%^xbT6x#Ea(#P4)6@AD(|Vb32K9-)&f)0mOzInc ziPuRhNrM-68T(M~8n@Kp-e%S|u2QP6RH&o4C&@R-S1HCiWpkiYN!G1Xx;!!n)$0@r ztXEL1@TWoCU;_ktMm9Do#x=@B*&y*T&^c81rQGEqZt|r}?Y+smujFpNgTAPvtfG*w z61u&sl$(JRV9VdftZH1VZ0;xvT&*M__gQ^MaygIWY~m|Gj_usJ{M7}I=W=qmTQJ2v z#&dGl5S$|($vqjt^>vDgk^4Ykn=DLrj|6tTg(>bKz&2Z$>P9H-W=P{3dXHw8%QmJ` z+7+o(-+v%MgXi=WZY2wMt`P40e!{JUaQ`EOyFp0{Hw#_fm=TUey(uFci+XcLI2QG9 z8R1yeTP#e=h-wp}+92xMRLXWV>yaMJRp~3KRNeL1#I6@#9$iS* zYxBB-ngYHKx`?n#^(Cz3Pd6>2g#Dt|B6Iy+EY}q#yJ`yM>gyF=ikA?7(6V>BFnxdD zUAtM4y8BnXlpHy#wpqM{E9N(DtK^U!2OUmJc3AnUx1+4byofY!&)2v2dZa{1t<>5> z+VGIAOWeQ?lccW54GQR8ksB5BjvA-9*6ksejx$;7W-Mu4eEM%vA~!4Mjih-iD6Z;i z|EAcx_^!2Z6|=hqvrrMz`&=Lhw%}OBJ4uMIEU+L$PIoCE%6d>FDBbElaFwz}od3md zr&3*!Tb1hD6jnq9Tom(F#;FRHedKnfD{=??vaZOT@X7plDUrJs|2<0NUeNDTYVTL< zZtT}xeC;bqeBN9pl=dl<22J#iWa}&D7njhT4RYy7c7B)XDDQYc2|1G(mvui4U7GqT zxAfK9PhBc22qzpIC6Y`{T$0saaQ_K6zay3s&`8}D z#OWUL$Q2&DhlUTY*`nBmk|0XKJPJIo)D`i1G2bKejOL=m1x3s5qj*n)>f4QOr3fc) zSJ1Jpy~llPAM&6q`7)5*7a_CovrNzvPoJ&@UW@tW+6v|dUBP_*wqc!Y3+D1i2UuNKl3t){&ny4@`=;)Wl8ORs_WNv& zte}pPj*?z>m^}8PCFX}2S1H)xOos$#f$4>`;{Xw^2gi}Z-#`FqIvEJsOwR(rpy^H^ zatdODbzzsmIbuWTf_xQN1a*sw%??!Lpz7|KJWr^^8JvSCY9=Fb(UX+!iPAj@X(|d- zzKOB5i$0Y;B)y$`cUt|}MNo-+6-TN$78QY^2sLv+&B0QFT@MLT~_)|aDEVB@CHPU`Ud`50C63E2*y*M-)&8}m{NDQxycq~ zCbhfI7VEaA)x~#$>1lOY(|Q%9zchM5F~1yAhc@ac=;Z(JBo$#({U&)tU=#1b>qxUJ z>iOomXC8HRgKGv$9fNziDjl^iD%9n3^24I`c0=j4TM^Yl?c(Xn;o@$DaY@v=PVVx# zx@)h)pv?w6RUyrNI-gytSt%LmQVI?+4>ykT9Z5dZs=E~#5(L${(xAY8ehS+cN-?gSY;h8&;M0^0+PQNW z*#_$OUE9^dKKZ@*E0%p~LmThsiW})#w$KkywSKc~ysq#u`UZ}A<4pm+#o*fle22kz z1^6C=?+fq)20s+wM+|-}z)u+bRDhoWoNEtkmg{ejjn5UI+xSB96&PPCzCzgI7{{IW1Ow}DvWbf-@eAVs?RXaQ++;TmFgR1tmf=| z)mLe(QGHd$1*&hfaiQuPV_c;A_A}OUcCqT)-?&8e9bjCl`VKTMQ+1-bSmO~Ee2eNk&UjSy9dA6QdY>oban*N%@r3HDGoDm^^~O`GZ@%%g>hl}VsJ?*l ztm+FI&#AtU@x1D5FkVo7VdF*B7csV~z6C}S>L;U1^)(vZs;|j-N%fs*Y*T#;jULt4 zZ1k$W7UN~r*J`|?`l80Gs;|v>P4%5*ysr9U#v7_HZoH}b62@DquibcC^(`{qQGJVz zcU9jK<2}{4)OcU@oosxd`u=2msQUhFe5CsRVtlOn{>S)4_5IcORP~|v&r~0x<N}T=?W*rQGXA0Za*bb9-zqYGReh_;*rEE)r@3n=a0BoD*O1Mj zY8zFAiYt1`SM-*z$OJyc{K2LOAB#hFtlMPutB828f;u!TCUGOi*s=_^Vw-=n9C=Mi zR==)L;W&;OsQL|sR`eu2vHg?+5#{YsU|KoeL#)rtgnj~iS zro{|fXQlzTdTiBiDRQQAgIW1)v+^SI@{K9)Sd_vMER5<&RX-)m#tO~64-9F{^AW=F z@dyb3FaSIL)x`S zI&<1WLA`p5Dbg8cs}HSKyYAm^wX$2Stp4r&`sWGp-yq*!SRj-MFo{y`!^2bMdHiiYl+|1uOVSBBYSahsP2F`gjMib(bHv|rd5BWkSA3H z--&Na&5Kh0u*bhbsdVw3D+{!~`eTJJP=hM`2EI)2NXy-DU%Roz=AlnKmb2g7y*%)~ zvPFgCAeXF7r4WarACG$@jDP|A#!av-K$~z{Uq?2ls-4O2lh!F_P43G3vAm(ZN07)O zc^Wpf_X>*KhXOwqGImveq7VX_j9l&ffljxF_-BnCY8O(qxA(Fylde$6zH7FI!f1PY zMM$kwa$Ss|dFT3ew^P8d^X~QQ+S#SWu-4-cg%4ZzAb)%e2bw&}hR*5-i4PmN_jpiyhol}`8Z*XC#U4UhD<0>#K2&8+RS&eVBuTLNC{)hPPX>$gBoY5Od(N*md zVKCcZGagA84SR&xYHXYGV1Uz6~s(@#*+I8Q9T#wV!$N%B9zw}g#PQvK7se4ggU ze-oE^{F>wms(YF$w!!UcuUOra?1E=xm+ch!TrpN@n=gV0w-A3b?G=W*o9b++sC{du z_LuVRYGdW0_H9Cr-|toqRJ%PBGJIiaK_A*U1LL@(&#n2Lq}Vju<6<^@%h|Or?|4^+ zlj+||=Ev7tDcQJ{>bq$~V>i`rqw>aW*tV6LFBPfdOQokP@|EJ(B3~>1E^!Ae@I4~m zDE_2*C+v|tIbv_SP%GL87MJ8rjyDwQ0)8&wif6Jgy2)o@bC}i05F>p`Jeg&b0~; z@=WoJ1zzAO@eD=PqdiA@#(4^Xc|o7-Y4I%Z%s|ayXmz;fC{Ls3B+m(+(ST>7?gGzJ z&k|4AGZnP?o}j1A(*Rm%-r;;-4{7*)l0&?W?uu+zlIuNVIQ#^hSZ zhbE4X_Fn%lO?P0svPJIl9A10}BBlaJR_dwrgeodLA;85L(L@U?1w7V-D^SHE z|657Ot@V{#`#0tOeAjYQWo~6&Wj>zn%7V(md3N?Z(2oe;n$Z_en)_Jp^nHFSksUw& ziHpna%6dHQ{Pft@Zvc0Huc-O?Z`a%+Z?W^yQhXI+XheU2&KB=V9wx;uzTh)&$;JL& zS6ovp2{lm2=AO;65rjNY++Snaf^XfBnjsSSrg1UcfAmEWL;ixZe~Y-?Mnnlx$%CmB z&ZG75-Yqt`SMHLHh~hOE{v)Jfm#Rh7_zu!EEPxd$Ur#XVy(-s_&k+U}6O zsTA?K&Kli8CYByxhQLEoF{Hi(9`Y8YyQ}!FRH|#uDsZg+UvlhP)7@z@O|B}rja??% zxD9i>u}8R3`6W}ttUXHnN%57$Thn?u-jj@Mkk_F5Q}|N1uGB-_8#(qbEQU|`9{JxR zruly$rfzC{kGdb}t^0xC;zWL+N7$1IYJnffuGv*og0lff6^&reMT6l8zQs`OTSS07 z5(DfD0YM$c>d{7T{DIIF&d>MwGO2Wtkn=I|qCW>4+_#kEyCcvZ7iTg54(csRTE2kA zJeh`3?Fq7#s#>qUwQ6MVKfB)C{YPjpU&J3jT7cY#+X{u(`)pn-x*Jq3-hEs3*I79TPG!C+Mldg!pRQ&Tn5d=)?c4)jVOpQEImJh8Ild9$afRek5JKQ%pX?lg5| z-+Aj#P0w3tnp)m>-uhGjlX)xuXY=OnH*Zz{Z|7}fzj-U|H*fZS^ENg!Z(GtccAS{8 z68BIMO_qpXOqK9w>_dRlCgC-Tv?jfJ`}EtL1v{^LNoyMV8M-(sI334Jql3-;E-i$6}K zGCcd%`+Vnm=<*p-(dA=urq7EqeXdt_>a)n=^(#1tO)<^RUHk#xY-fA>N59^3N-U|| z137K~O-`To<>XyQB_9nKV4Bruzsc(LT?2lXCrY z%h`>=DF58L#t$^+=Sa_2wFea8)A8#87g8=#9)HgaQ9Fk48*}g1WWst~ia)|lkqn>D zbVK=51^*}PRthgt{PbkI!b_OF$iw+l1r!Tr-Rt5ZXBuhm<@a$#{3i1?{sA`AYF~rD z;Ik-}Z-o8I^b)xc1(pkBl9}ciAIjnPua02OBiQJ2Jkre-{EB}c^c2iNC6BbZ08(%X z|K^RE+qhx(RCsuH_XhFaCLVI}WrAaiotxRsW)+3v({6h(=ca=9z`>5aH(mh+x$_P7 z=|g$^^4Gx}b>_Gw5Bn}kHa92Dx6o26cT-WpY$z^`&u(_u(>bbowo}oPdAPm^M#sT=j1CT z;b2ueiLaiRV9yd9OvqqP|CgAd%Hp7XePv0|vA(l%Fn`DH?I7Ok{a35P{}<$~?dG z$R5?Bi|BL+;?W9^;<0;Ni2L^N{NA&VXJ3y4fi1^?dm?rKWnjdG_}l z=qWVM^*zzg9Cu_Grbo#quZ{z~=#Fb5}N2&xz& zv=8x}o}78E#(z-#cELdAo4^V&Y{jEhc+?7$?O(uTJJo+m77Ga#3c#iiqZ{p+0Cs~A zjR(MVZ$#upo-y8K4VYOq}`yoJ&d6$zAq6Atig;s|^ zJHw&9kyhv*`7I`xt@85`;YM)>p2cFcLQSo z2qOMQPm||FPu!F6w0jnL7JHU>mU>S1p2EkKcLjM*Bk$?tJ%hYwl6NI}&nNF1@?JpR z3(0#CdDoKnV)9->-b-=Rkaq)luO{zC@?JyUYsq^Zc{h>wdh*^%-rLA~J9+OQ@15km zi@bM}_a5@zOWrNyeU!Y9k@s=(K0)3m$@>&}pC<1!6%Gkhhn-FO&Bb z^1e#mcgXuLc@gQnPu>s6`yqKhBJaoK{e--qlJ^_(eoNl($ooBce<1IVGrBRR5WnLM3AXSu4QoeMa@K@6H5Xr}~dFCLr^~E5i0QVFQA;7;HYG`d6}S z3IroI0UJzV0!%=M5u5~L*jtzY_!nXFg&|lb;D9;o2Q&DZt${5dNn-vzp8cT$j~64& z*h1D4{+o8Noc^zy!fxzf_eSsv)$hQr;49=^VF%TB$Z4cQuKy&nUwlIKUuKXmss5`B z@)gzpoI!r(|GEeN2SrqIzqBpsY2dqlPec1QkJOX&jB)WNyQ=q$5y=gF3iY`21^yH~ z6M6kQL8^P1YF{R)?nA2m5RV_>wf-nPgBQtWSGD_P^GGS@v%mgZ^V5*VZ!_V0I-F;} z|IVcLGWBPs!lB5L z`O_m2N8;4s&qc1}+a*D;J{ma{UJHwnzb{nAw=o?<_~XDI__n9Yk6!-84ui`tBr1*kFb9XX}?)Hk+iC!?_*KJvZU%6$lO<>U#R2dDatcjas zXt3}a6miel61!RAy2dm9x}6FgW}$7Dg-)|DU1E3I9d^4NA+lC{Y$_$<#V&r2w$8Xp zLpdXBEYLlkzaH}_SBEe!LEZYqZwP3JF>B)Az?3q+bzBQG4D3t=#g&Ei& z-nzU*noUt3F`X$*eBRlq_4#$kif!r7rdXY(CRKMUyTLchmd5zqH|wx)EO-uH~0L8?Q}WWc)DD_QtoP8DU073u#0|{Tzi%*acm)eM{tJR=XV6B$<_}E-V%I_ zo&FPEsGa@gz-a=p82*2aT}x~mRTTBTnQ`O%NJtt)%dkL2LXZUu7Hp6ZNJU}+tPq<# z%}gchAt8ih2`Rgf;Fg*=!Neqy?K(~@^HCO28VM%GjjY7AU3s|DW=yx%bZV z#Ezq15QSyXy6Tza2J(F{kgM5XtNDZM^N50KgyZKZb= z3~!#A$7f@D9>bFVQot}T$@aB7k8+RP8hngfY0i?ci4Cx^(18{;($>QB}XpMI~4O}Zv0&*Y%k!|=dkzP`tY z<+RSAXq~fv)$*pS50M+cTYOsHQoa%@e-rhA)2593 z9i8R6{Mc-ZmSs?e z(?w6Hs-Zm5RZvBmVCf>LbshrOLDg8+K;>EHK`l$JE4Jji3@Qg>tG3R8%EDOH)>%*` z82boy2~-Bg*1L2DRDouRT8M|fmu+>SL}E^^$G*G?3EiheA;BGJ{ zPT+2Vw?(21UYW#%Hxam1@TwFpf>$K54&FM68hAAldGPWimYL@yaC6}0NMymwk|=>! zB9Q?vL!y9Q0l6lAfCHp=1CAc0U;Lw7T|G_>{5)H69@Pe(K)r!#ljgK~ldbxx)9w5m zRq7d2skb@0$O(UGJJkLa;{A5KXexDq`n;7qYv~1YyK5n*3=Ju30vr&?w;kfY<3Xcx z0;_!S*tfz^w;cBQHXohES1SzBmP;AtjyzxYZv`2x%JY^GJl&_}qP8@L?i}CsO!$4m zx0taQyY^djlKZ-tl12V|ZqRXbAHDv)&7MERo_B<^vg52{-@F+y&$lA`Y!hnuabu|; zA9#jujIIb4m^ZK+0^v>gmf+rfn+u^=m1uBoRJlj#5~^9|;Swmj-|P2=MZmk*RXvM5 zU*j9z0;ab`cGJKvnFazC?y1WLH)l#px6G72Dw(Qt+!)TGDkCL#OSq!TlDyaNxpmnx zTsbV;Kjo1API9-DS!_h+1!UvyPEda;C;t9AxfVPA@J(FHv3=K)wUV=zTgFxT6%{WV zx|hqLd-*G>zPa}58=~s#r~LnJ^D+N`p%J3$8ec|3zw)p2*Lx@f_A-+Wb=L}>e8Y-) z73!nuFqoDObVEjhVd^Lq9tkR_(k#<#NK9Q9B&e7;^l{A=5G=!n+64Uh0VL{ZBrIEB8&y z8dMDJ;C7avd82^({T?&zdoUIY;r!+a4Bj0+*=#+*XfoI(lR=tm9^Y&>yM~(0N1Dy& zn@x)Few5#R^y&@Xg_^|Hz&vmK%k7SKnB)TY>vIY_eA0BJlQ%lUjy}dX>^7Zrr_Sj} z=Pjc%;^?~=Bi*L+8Z{7MT;+Ci0qQ(1OkRM!oj|{hJB{Q;&=-N^Ht20$X`IEDb6hZ) i9(8n$8_D1>|BtGZFL){axcB1AUMlt|#s33=Ra;d7rU|P6 literal 0 HcmV?d00001 diff --git a/include/SugarCharts/Jit/FlashCanvas/proxy.php b/include/SugarCharts/Jit/FlashCanvas/proxy.php new file mode 100644 index 00000000..fe4c0bee --- /dev/null +++ b/include/SugarCharts/Jit/FlashCanvas/proxy.php @@ -0,0 +1,73 @@ + + * @copyright 2010-2011 Shinya Muramatsu + * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @link http://flashcanvas.net/ + * @link http://code.google.com/p/flashcanvas/ + */ + +// Whether we check referrer or not +define('CHECK_REFERRER', true); + +// Check that the request is from FlashCanvas +if (CHECK_REFERRER) { + if (empty($_SERVER['HTTP_REFERER'])) { + exit; + } + if (!preg_match('#/flash\d*canvas\.swf$#', $_SERVER['HTTP_REFERER'])) { + exit; + } +} + +// Check that the request has a valid URL parameter +if (empty($_GET['url'])) { + exit; +} +if (!preg_match('#^https?://#', $_GET['url'])) { + exit; +} + +// Percent-encode special characters in the URL +$search = array( '%', '#', ' '); +$replace = array('%25', '%23', '%20'); +$url = str_replace($search, $replace, $_GET['url']); + +// Disable compression +header('Content-Encoding: none'); + +// Load and output the file +if (extension_loaded('curl')) { + // Use cURL extension + $ch = curl_init($url); + curl_exec($ch); + curl_close($ch); +} else { + // Use the http:// wrapper + readfile($url); +} diff --git a/include/SugarCharts/Jit/FlashCanvas/save.php b/include/SugarCharts/Jit/FlashCanvas/save.php new file mode 100644 index 00000000..31282f9d --- /dev/null +++ b/include/SugarCharts/Jit/FlashCanvas/save.php @@ -0,0 +1,49 @@ + + * @copyright 2010-2011 Shinya Muramatsu + * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @link http://flashcanvas.net/ + * @link http://code.google.com/p/flashcanvas/ + */ + +if ($_SERVER['REQUEST_METHOD'] === 'POST') { + // Force download + header('Content-Type: application/octet-stream'); + header('Content-Disposition: attachment; filename="canvas.png"'); + + if (isset($_POST['dataurl'])) { + // Decode the base64-encoded data + $data = $_POST['dataurl']; + $data = substr($data, strpos($data, ',') + 1); + echo base64_decode($data); + } else { + // Output the raw data + readfile('php://input'); + } +} diff --git a/include/SugarCharts/Jit/Jit.php b/include/SugarCharts/Jit/Jit.php new file mode 100644 index 00000000..8b2bcfe8 --- /dev/null +++ b/include/SugarCharts/Jit/Jit.php @@ -0,0 +1,88 @@ + + + + + '; + } + + function getMySugarChartResources() { + return ' + + '; + } + + + function display($name, $xmlFile, $width='320', $height='480', $resize=false) { + + parent::display($name, $xmlFile, $width, $height, $resize); + + return $this->ss->fetch('include/SugarCharts/Jit/tpls/chart.tpl'); + } + + + function getDashletScript($id,$xmlFile="") { + + parent::getDashletScript($id,$xmlFile); + return $this->ss->fetch('include/SugarCharts/Jit/tpls/DashletGenericChartScript.tpl'); + } + + + + +} + +?> \ No newline at end of file diff --git a/include/SugarCharts/Jit/JitReports.php b/include/SugarCharts/Jit/JitReports.php new file mode 100644 index 00000000..8b06c8ca --- /dev/null +++ b/include/SugarCharts/Jit/JitReports.php @@ -0,0 +1,215 @@ +super_set as $key){ + $temp_dataset[$key] = (isset($dataset[$key])) ? $dataset[$key] : array(); + } + $dataset = $temp_dataset; + } + + foreach ($dataset as $key=>$value){ + if ($first && empty($value)){ + $data .= $this->processDataGroup(4, $key, 'NULL', '', ''); + } + else if (array_key_exists('numerical_value', $dataset)){ + $link = (isset($dataset['link'])) ? '#'.$dataset['link'] : ''; + $data .= $this->processDataGroup($level, $dataset['group_base_text'], $dataset['numerical_value'], $dataset['numerical_value'], $link); + array_push($this->processed_report_keys, $dataset['group_base_text']); + return $data; + } + else{ + $data .= $this->processReportData($value, $level+1); + } + } + + return $data; + } + + function processReportGroup($dataset){ + $super_set = array(); + + foreach($dataset as $groupBy => $groups){ + $prev_super_set = $super_set; + if (count($groups) > count($super_set)){ + $super_set = array_keys($groups); + foreach($prev_super_set as $prev_group){ + if (!in_array($prev_group, $groups)){ + array_push($super_set, $prev_group); + } + } + } + else{ + foreach($groups as $group => $groupData){ + if (!in_array($group, $super_set)){ + array_push($super_set, $group); + } + } + } + } + $super_set = array_unique($super_set); + + return $super_set; + } + + function xmlDataReportSingleValue(){ + $data = ''; + foreach ($this->data_set as $key => $dataset){ + $total = $this->calculateReportGroupTotal($dataset); + $this->checkYAxis($total); + + $data .= $this->tab('', 2); + $data .= $this->tab('' . $key . '', 3); + $data .= $this->tab('', 3); + $data .= $this->tab('',4); + $data .= $this->tab('' . $total . '',5); + $data .= $this->tab('' . $total . '',5); + $data .= $this->tab('',5); + $data .= $this->tab('',5); + $data .= $this->tab('',4); + $data .= $this->tab('', 3); + $data .= $this->tab('', 2); + } + return $data; + } + + function xmlDataReportChart(){ + $data = ''; + // correctly process the first row + $first = true; + foreach ($this->data_set as $key => $dataset){ + + $total = $this->calculateReportGroupTotal($dataset); + $this->checkYAxis($total); + + $data .= $this->tab('', 2); + $data .= $this->tab('' . $key . '', 3); + $data .= $this->tab('' . $total . '', 3); + $data .= $this->tab('', 3); + $data .= $this->tab('', 3); + + if ((isset($dataset[$total]) && $total != $dataset[$total]['numerical_value']) || !array_key_exists($key, $dataset)){ + $data .= $this->processReportData($dataset, 4, $first); + } + + if (!$first){ + $not_processed = array_diff($this->super_set, $this->processed_report_keys); + $processed_diff_count = count($this->super_set) - count($not_processed); + + if ($processed_diff_count != 0){ + foreach ($not_processed as $title){ + $data .= $this->processDataGroup(4, $title, 'NULL', '', ''); + } + } + } + $data .= $this->tab('', 3); + $data .= $this->tab('', 2); + $this->processed_report_keys = array(); + // we're done with the first row! + //$first = false; + } + return $data; + } + + public function processXmlData(){ + $data = ''; + + $this->super_set = $this->processReportGroup($this->data_set); + $single_value = false; + + foreach ($this->data_set as $key => $dataset){ + if ((isset($dataset[$key]) && count($this->data_set[$key]) == 1)){ + $single_value = true; + } + else{ + $single_value = false; + } + } + if ($this->chart_properties['type'] == 'line chart' && $single_value){ + $data .= $this->xmlDataReportSingleValue(); + } + else{ + $data .= $this->xmlDataReportChart(); + } + + return $data; + } + + /** + * wrapper function to return the html code containing the chart in a div + * + * @param string $name name of the div + * string $xmlFile location of the XML file + * string $style optional additional styles for the div + * @return string returns the html code through smarty + */ + function display($name, $xmlFile, $width='320', $height='480', $reportChartDivStyle, $resize=false){ + + + parent::display($name, $xmlFile, $width, $height, $resize=false); + + return $this->ss->fetch('include/SugarCharts/Jit/tpls/chart.tpl'); + } +} + +?> \ No newline at end of file diff --git a/include/SugarCharts/Jit/css/base.css b/include/SugarCharts/Jit/css/base.css new file mode 100644 index 00000000..aa83b954 --- /dev/null +++ b/include/SugarCharts/Jit/css/base.css @@ -0,0 +1,110 @@ +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +/********************************************************************************* + + * Description: Contains a variety of utility functions used to display UI + * components such as form headers and footers. Intended to be modified on a per + * theme basis. + ********************************************************************************/ + +.chartContainer { + float: left; + margin:auto; + width: 100% + } + +.chartContainer .scrollBars { + overflow: auto; + max-height: 600px; + position: relative; +} + +.chartCanvas { + position:relative; + margin:auto; + overflow:hidden; + background-image: url(../../../../index.php?entryPoint=getImage&imageName=chartBg.png); + background-repeat:repeat-x; +} + +.query-color { +width: 16px; +height: 16px; +display: inline-block; +margin-right: 10px; +border: 1px solid #999; +} + +.legend { +padding: 10px 20px; +float: left; +} + +.legend table td { +padding: 0px 20px 5px 0px; +text-align: left; +} +/*TOOLTIPS*/ +.tip { + color: #111; + width: auto; + background-color: white; + border:1px solid #ccc; + -moz-box-shadow:#555 2px 2px 8px; + -webkit-box-shadow:#555 2px 2px 8px; + -o-box-shadow:#555 2px 2px 8px; + box-shadow:#555 2px 2px 8px; + opacity:0.9; + filter:alpha(opacity=90); + font-size:11px; + font-family: Arial, Helvetica, sans-serif; + padding:7px; + -moz-border-radius: 6px; + -webkit-border-radius: 6px; + border-radius: 6px; + +} +.rotatedLabel { +-webkit-transform: rotate(-90deg); +-moz-transform: rotate(-90deg); +filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=3); +} + +.rotatedLabelReverse { +-webkit-transform: rotate(-0deg); +-moz-transform: rotate(90deg); +filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=2); +} \ No newline at end of file diff --git a/include/SugarCharts/Jit/js/Jit/jit.js b/include/SugarCharts/Jit/js/Jit/jit.js new file mode 100644 index 00000000..3d7de07c --- /dev/null +++ b/include/SugarCharts/Jit/js/Jit/jit.js @@ -0,0 +1,496 @@ +/* + Copyright (c) 2010, Nicolas Garcia Belmonte + 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 organization 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 NICOLAS GARCIA BELMONTE ``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 NICOLAS GARCIA BELMONTE 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. + */ +(function(){window.$jit=function(w){w=w||window;for(var k in $jit){if($jit[k].$extend){w[k]=$jit[k];}}};$jit.version='2.0.0b';var $=function(d){return document.getElementById(d);};$.empty=function(){};function pad(number,length){var str=''+number;while(str.length127)&&(c<2048)){utftext+=String.fromCharCode((c>>6)|192);utftext+=String.fromCharCode((c&63)|128);} +else{utftext+=String.fromCharCode((c>>12)|224);utftext+=String.fromCharCode(((c>>6)&63)|128);utftext+=String.fromCharCode((c&63)|128);}} +return utftext;},_utf8_decode:function(utftext){var string="";var i=0;var c=c1=c2=0;while(i191)&&(c<224)){c2=utftext.charCodeAt(i+1);string+=String.fromCharCode(((c&31)<<6)|(c2&63));i+=2;} +else{c2=utftext.charCodeAt(i+1);c3=utftext.charCodeAt(i+2);string+=String.fromCharCode(((c&15)<<12)|((c2&63)<<6)|(c3&63));i+=3;}} +return string;}};Array.prototype.sum=function(){return(!this.length)?0:this.slice(1).sum()+ +((typeof this[0]=='number')?this[0]:0);};function array_match(needle,haystack){var length=haystack.length;var indexValue=new Array();for(var i=0,count=0;i>16,hex>>8&0xff,hex&0xff];}};$.destroy=function(elem){$.clean(elem);if(elem.parentNode) +elem.parentNode.removeChild(elem);if(elem.clearAttributes) +elem.clearAttributes();};$.clean=function(elem){for(var ch=elem.childNodes,i=0,l=ch.length;i-1;};$.addClass=function(obj,klass){if(!$.hasClass(obj,klass)) +obj.className=(obj.className+" "+klass);};$.removeClass=function(obj,klass){obj.className=obj.className.replace(new RegExp('(^|\\s)'+klass+'(?:\\s|$)'),'$1');};$.getPos=function(elem){var offset=getOffsets(elem);var scroll=getScrolls(elem);return{x:offset.x-scroll.x,y:offset.y-scroll.y};function getOffsets(elem){var position={x:0,y:0};while(elem&&!isBody(elem)){position.x+=elem.offsetLeft;position.y+=elem.offsetTop;elem=elem.offsetParent;} +return position;} +function getScrolls(elem){var position={x:0,y:0};while(elem&&!isBody(elem)){position.x+=elem.scrollLeft;position.y+=elem.scrollTop;elem=elem.parentNode;} +return position;} +function isBody(element){return(/^(?:body|html)$/i).test(element.tagName);}};$.event={get:function(e,win){win=win||window;return e||win.event;},getWheel:function(e){return e.wheelDelta?e.wheelDelta/120:-(e.detail||0)/3;},isRightClick:function(e){return(e.which==3||e.button==2);},getPos:function(e,win){win=win||window;e=e||win.event;var doc=win.document;doc=doc.documentElement||doc.body;if(e.touches&&e.touches.length){e=e.touches[0];} +var page={x:e.pageX||(e.clientX+doc.scrollLeft),y:e.pageY||(e.clientY+doc.scrollTop)};return page;},stop:function(e){if(e.stopPropagation)e.stopPropagation();e.cancelBubble=true;if(e.preventDefault)e.preventDefault();else e.returnValue=false;}};$jit.util=$jit.id=$;var Class=function(properties){properties=properties||{};var klass=function(){for(var key in this){if(typeof this[key]!='function') +this[key]=$.unlink(this[key]);} +this.constructor=klass;if(Class.prototyping) +return this;var instance=this.initialize?this.initialize.apply(this,arguments):this;this.$$family='class';return instance;};for(var mutator in Class.Mutators){if(!properties[mutator]) +continue;properties=Class.Mutators[mutator](properties,properties[mutator]);delete properties[mutator];} +$.extend(klass,this);klass.constructor=Class;klass.prototype=properties;return klass;};Class.Mutators={Implements:function(self,klasses){$.each($.splat(klasses),function(klass){Class.prototyping=klass;var instance=(typeof klass=='function')?new klass:klass;for(var prop in instance){if(!(prop in self)){self[prop]=instance[prop];}} +delete Class.prototyping;});return self;}};$.extend(Class,{inherit:function(object,properties){for(var key in properties){var override=properties[key];var previous=object[key];var type=$.type(override);if(previous&&type=='function'){if(override!=previous){Class.override(object,key,override);}}else if(type=='object'){object[key]=$.merge(previous,override);}else{object[key]=override;}} +return object;},override:function(object,name,method){var parent=Class.prototyping;if(parent&&object[name]!=parent[name]) +parent=null;var override=function(){var previous=this.parent;this.parent=parent?parent[name]:object[name];var value=method.apply(this,arguments);this.parent=previous;return value;};object[name]=override;}});Class.prototype.implement=function(){var proto=this.prototype;$.each(Array.prototype.slice.call(arguments||[]),function(properties){Class.inherit(proto,properties);});return this;};$jit.Class=Class;$jit.json={prune:function(tree,maxLevel){this.each(tree,function(elem,i){if(i==maxLevel&&elem.children){delete elem.children;elem.children=[];}});},getParent:function(tree,id){if(tree.id==id) +return false;var ch=tree.children;if(ch&&ch.length>0){for(var i=0;i=(7-4*a)/11){value=b*b-Math.pow((11-6*a-11*p)/4,2);break;}} +return value;},Elastic:function(p,x){return Math.pow(2,10*--p)*Math.cos(20*p*Math.PI*(x[0]||1)/3);}};$.each(transitions,function(val,key){Trans[key]=makeTrans(val);});$.each(['Quad','Cubic','Quart','Quint'],function(elem,i){Trans[elem]=makeTrans(function(p){return Math.pow(p,[i+2]);});});})();var Animation=new Class({initialize:function(options){this.setOptions(options);},setOptions:function(options){var opt={duration:2500,fps:40,transition:Trans.Quart.easeInOut,compute:$.empty,complete:$.empty,link:'ignore'};this.opt=$.merge(opt,options||{});return this;},step:function(){var time=$.time(),opt=this.opt;if(timewin.height)?(pos.y-obj.height-y):pos.y+y)+'px';style.left=((pos.x+obj.width+x>win.width)?(pos.x-obj.width-x):pos.x+x)+'px';},hide:function(triggerCallback){if(!SUGAR.util.isTouchScreen()){this.tip.style.display='none';} +triggerCallback&&this.config.onHide();}});Extras.Classes.NodeStyles=new Class({Implements:[ExtrasInitializer,EventsInterface],initializePost:function(){this.fx=this.viz.fx;this.types=this.viz.fx.nodeTypes;this.nStyles=this.config;this.nodeStylesOnHover=this.nStyles.stylesHover;this.nodeStylesOnClick=this.nStyles.stylesClick;this.hoveredNode=false;this.fx.nodeFxAnimation=new Animation();this.down=false;this.move=false;},onMouseOut:function(e,win){this.down=this.move=false;if(!this.hoveredNode)return;if(this.dom&&this.isLabel(e,win)){this.toggleStylesOnHover(this.hoveredNode,false);} +var rt=e.relatedTarget,canvasWidget=this.canvas.getElement();while(rt&&rt.parentNode){if(canvasWidget==rt.parentNode)return;rt=rt.parentNode;} +this.toggleStylesOnHover(this.hoveredNode,false);this.hoveredNode=false;},onMouseOver:function(e,win){var label;if(this.dom&&(label=this.isLabel(e,win))){var node=this.viz.graph.getNode(label.id);if(node.selected)return;this.hoveredNode=node;this.toggleStylesOnHover(this.hoveredNode,true);}},onMouseDown:function(e,win,event,isRightClick){if(isRightClick)return;var label;if(this.dom&&(label=this.isLabel(e,win))){this.down=this.viz.graph.getNode(label.id);}else if(!this.dom){this.down=event.getNode();} +this.move=false;},onMouseUp:function(e,win,event,isRightClick){if(isRightClick)return;if(!this.move){this.onClick(event.getNode());} +this.down=this.move=false;},getRestoredStyles:function(node,type){var restoredStyles={},nStyles=this['nodeStylesOn'+type];for(var prop in nStyles){restoredStyles[prop]=node.styles['$'+prop];} +return restoredStyles;},toggleStylesOnHover:function(node,set){if(this.nodeStylesOnHover){this.toggleStylesOn('Hover',node,set);}},toggleStylesOnClick:function(node,set){if(this.nodeStylesOnClick){this.toggleStylesOn('Click',node,set);}},toggleStylesOn:function(type,node,set){var viz=this.viz;var nStyles=this.nStyles;if(set){var that=this;if(!node.styles){node.styles=$.merge(node.data,{});} +for(var s in this['nodeStylesOn'+type]){var $s='$'+s;if(!($s in node.styles)){node.styles[$s]=node.getData(s);}} +viz.fx.nodeFx($.extend({'elements':{'id':node.id,'properties':that['nodeStylesOn'+type]},transition:Trans.Quart.easeOut,duration:300,fps:40},this.config));}else{var restoredStyles=this.getRestoredStyles(node,type);viz.fx.nodeFx($.extend({'elements':{'id':node.id,'properties':restoredStyles},transition:Trans.Quart.easeOut,duration:300,fps:40},this.config));}},onClick:function(node){if(!node)return;var nStyles=this.nodeStylesOnClick;if(!nStyles)return;if(node.selected){this.toggleStylesOnClick(node,false);delete node.selected;}else{this.viz.graph.eachNode(function(n){if(n.selected){for(var s in nStyles){n.setData(s,n.styles['$'+s],'end');} +delete n.selected;}});this.toggleStylesOnClick(node,true);node.selected=true;delete node.hovered;this.hoveredNode=false;}},onMouseMove:function(e,win,event){if(this.down)this.move=true;if(this.dom&&this.isLabel(e,win))return;var nStyles=this.nodeStylesOnHover;if(!nStyles)return;if(!this.dom){if(this.hoveredNode){var geom=this.types[this.hoveredNode.getData('type')];var contains=geom&&geom.contains&&geom.contains.call(this.fx,this.hoveredNode,event.getPos());if(contains)return;} +var node=event.getNode();if(!this.hoveredNode&&!node)return;if(node.hovered)return;if(node&&!node.selected){this.fx.nodeFxAnimation.stopTimer();this.viz.graph.eachNode(function(n){if(n.hovered&&!n.selected){for(var s in nStyles){n.setData(s,n.styles['$'+s],'end');} +delete n.hovered;}});node.hovered=true;this.hoveredNode=node;this.toggleStylesOnHover(node,true);}else if(this.hoveredNode&&!this.hoveredNode.selected){this.fx.nodeFxAnimation.stopTimer();this.toggleStylesOnHover(this.hoveredNode,false);delete this.hoveredNode.hovered;this.hoveredNode=false;}}}});Extras.Classes.Navigation=new Class({Implements:[ExtrasInitializer,EventsInterface],initializePost:function(){this.pos=false;this.pressed=false;},onMouseWheel:function(e,win,scroll){if(!this.config.zooming)return;$.event.stop($.event.get(e,win));var val=this.config.zooming/1000,ans=1+scroll*val;this.canvas.scale(ans,ans);},onMouseDown:function(e,win,eventInfo){if(!this.config.panning)return;if(this.config.panning=='avoid nodes'&&eventInfo.getNode())return;this.pressed=true;this.pos=eventInfo.getPos();var canvas=this.canvas,ox=canvas.translateOffsetX,oy=canvas.translateOffsetY,sx=canvas.scaleOffsetX,sy=canvas.scaleOffsetY;this.pos.x*=sx;this.pos.x+=ox;this.pos.y*=sy;this.pos.y+=oy;},onMouseMove:function(e,win,eventInfo){if(!this.config.panning)return;if(!this.pressed)return;if(this.config.panning=='avoid nodes'&&eventInfo.getNode())return;var thispos=this.pos,currentPos=eventInfo.getPos(),canvas=this.canvas,ox=canvas.translateOffsetX,oy=canvas.translateOffsetY,sx=canvas.scaleOffsetX,sy=canvas.scaleOffsetY;currentPos.x*=sx;currentPos.y*=sy;currentPos.x+=ox;currentPos.y+=oy;var x=currentPos.x-thispos.x,y=currentPos.y-thispos.y;this.pos=currentPos;this.canvas.translate(x*1/sx,y*1/sy);},onMouseUp:function(e,win,eventInfo,isRightClick){if(!this.config.panning)return;this.pressed=false;}});var Canvas;(function(){var canvasType=typeof HTMLCanvasElement,supportsCanvas=(canvasType=='object'||canvasType=='function');function $E(tag,props){var elem=document.createElement(tag);for(var p in props){if(typeof props[p]=="object"){$.extend(elem[p],props[p]);}else{elem[p]=props[p];}} +if(tag=="canvas"&&!supportsCanvas&&G_vmlCanvasManager){elem=G_vmlCanvasManager.initElement(elem);} +return elem;} +$jit.Canvas=Canvas=new Class({canvases:[],pos:false,element:false,labelContainer:false,translateOffsetX:0,translateOffsetY:0,scaleOffsetX:1,scaleOffsetY:1,initialize:function(viz,opt){this.viz=viz;this.opt=opt;var id=$.type(opt.injectInto)=='string'?opt.injectInto:opt.injectInto.id,idLabel=id+"-label",wrapper=$(id),width=opt.width||wrapper.offsetWidth,height=opt.height||wrapper.offsetHeight;this.id=id;var canvasOptions={injectInto:id,width:width,height:height};this.element=$E('div',{'id':id+'-canvaswidget','style':{'position':'relative','width':width+'px','height':height+'px'}});this.labelContainer=this.createLabelContainer(opt.Label.type,idLabel,canvasOptions);this.canvases.push(new Canvas.Base({config:$.extend({idSuffix:'-canvas'},canvasOptions),plot:function(base){viz.fx.plot();},resize:function(){viz.refresh();}}));var back=opt.background;if(back){var backCanvas=new Canvas.Background[back.type](viz,$.extend(back,canvasOptions));this.canvases.push(new Canvas.Base(backCanvas));} +var len=this.canvases.length;while(len--){this.element.appendChild(this.canvases[len].canvas);if(len>0){this.canvases[len].plot();}} +this.element.appendChild(this.labelContainer);wrapper.appendChild(this.element);var timer=null,that=this;$.addEvent(window,'scroll',function(){clearTimeout(timer);timer=setTimeout(function(){that.getPos(true);},500);});$.addEvent(window,'click',function(){clearTimeout(timer);timer=setTimeout(function(){that.getPos(true);},500);});sb=document.getElementById('sb'+id);$.addEvent(sb,'scroll',function(){clearTimeout(timer);timer=setTimeout(function(){that.getPos(true);},500);});},getCtx:function(i){return this.canvases[i||0].getCtx();},getConfig:function(){return this.opt;},getElement:function(){return this.element;},getSize:function(i){return this.canvases[i||0].getSize();},resize:function(width,height){this.getPos(true);this.translateOffsetX=this.translateOffsetY=0;this.scaleOffsetX=this.scaleOffsetY=1;for(var i=0,l=this.canvases.length;iet){sum=ch((et+((tt-pi2)-et)*delta));}else{sum=ch((et-pi2+(tt-(et))*delta));}}else if(diff>=pi){if(tt>et){sum=ch((et+((tt-pi2)-et)*delta));}else{sum=ch((et-pi2+(tt-(et-pi2))*delta));}}else{sum=ch((et+(tt-et)*delta));} +var r=(this.rho-elem.rho)*delta+elem.rho;return{'theta':sum,'rho':r};}};var $P=function(a,b){return new Polar(a,b);};Polar.KER=$P(0,0);var Complex=function(x,y){this.x=x;this.y=y;};$jit.Complex=Complex;Complex.prototype={getc:function(){return this;},getp:function(simple){return this.toPolar(simple);},set:function(c){c=c.getc(true);this.x=c.x;this.y=c.y;},setc:function(x,y){this.x=x;this.y=y;},setp:function(theta,rho){this.x=Math.cos(theta)*rho;this.y=Math.sin(theta)*rho;},clone:function(){return new Complex(this.x,this.y);},toPolar:function(simple){var rho=this.norm();var atan=Math.atan2(this.y,this.x);if(atan<0)atan+=Math.PI*2;if(simple)return{'theta':atan,'rho':rho};return new Polar(atan,rho);},norm:function(){return Math.sqrt(this.squaredNorm());},squaredNorm:function(){return this.x*this.x+this.y*this.y;},add:function(pos){return new Complex(this.x+pos.x,this.y+pos.y);},prod:function(pos){return new Complex(this.x*pos.x-this.y*pos.y,this.y*pos.x+this.x*pos.y);},conjugate:function(){return new Complex(this.x,-this.y);},scale:function(factor){return new Complex(this.x*factor,this.y*factor);},equals:function(c){return this.x==c.x&&this.y==c.y;},$add:function(pos){this.x+=pos.x;this.y+=pos.y;return this;},$prod:function(pos){var x=this.x,y=this.y;this.x=x*pos.x-y*pos.y;this.y=y*pos.x+x*pos.y;return this;},$conjugate:function(){this.y=-this.y;return this;},$scale:function(factor){this.x*=factor;this.y*=factor;return this;},$div:function(pos){var x=this.x,y=this.y;var sq=pos.squaredNorm();this.x=x*pos.x+y*pos.y;this.y=y*pos.x-x*pos.y;return this.$scale(1/sq);}};var $C=function(a,b){return new Complex(a,b);};Complex.KER=$C(0,0);$jit.Graph=new Class({initialize:function(opt,Node,Edge,Label){var innerOptions={'complex':false,'Node':{}};this.Node=Node;this.Edge=Edge;this.Label=Label;this.opt=$.merge(innerOptions,opt||{});this.nodes={};this.edges={};var that=this;this.nodeList={};for(var p in Accessors){that.nodeList[p]=(function(p){return function(){var args=Array.prototype.slice.call(arguments);that.eachNode(function(n){n[p].apply(n,args);});};})(p);}},getNode:function(id){if(this.hasNode(id))return this.nodes[id];return false;},getByName:function(name){for(var id in this.nodes){var n=this.nodes[id];if(n.name==name)return n;} +return false;},getAdjacence:function(id,id2){if(id in this.edges){return this.edges[id][id2];} +return false;},addNode:function(obj){if(!this.nodes[obj.id]){var edges=this.edges[obj.id]={};this.nodes[obj.id]=new Graph.Node($.extend({'id':obj.id,'name':obj.name,'data':$.merge(obj.data||{},{}),'adjacencies':edges},this.opt.Node),this.opt.complex,this.Node,this.Edge,this.Label);} +return this.nodes[obj.id];},addAdjacence:function(obj,obj2,data){if(!this.hasNode(obj.id)){this.addNode(obj);} +if(!this.hasNode(obj2.id)){this.addNode(obj2);} +obj=this.nodes[obj.id];obj2=this.nodes[obj2.id];if(!obj.adjacentTo(obj2)){var adjsObj=this.edges[obj.id]=this.edges[obj.id]||{};var adjsObj2=this.edges[obj2.id]=this.edges[obj2.id]||{};adjsObj[obj2.id]=adjsObj2[obj.id]=new Graph.Adjacence(obj,obj2,data,this.Edge,this.Label);return adjsObj[obj2.id];} +return this.edges[obj.id][obj2.id];},removeNode:function(id){if(this.hasNode(id)){delete this.nodes[id];var adjs=this.edges[id];for(var to in adjs){delete this.edges[to][id];} +delete this.edges[id];}},removeAdjacence:function(id1,id2){delete this.edges[id1][id2];delete this.edges[id2][id1];},hasNode:function(id){return id in this.nodes;},empty:function(){this.nodes={};this.edges={};}});var Graph=$jit.Graph;var Accessors;(function(){var getDataInternal=function(prefix,prop,type,force,prefixConfig){var data;type=type||'current';prefix="$"+(prefix?prefix+"-":"");if(type=='current'){data=this.data;}else if(type=='start'){data=this.startData;}else if(type=='end'){data=this.endData;} +var dollar=prefix+prop;if(force){return data[dollar];} +if(!this.Config.overridable) +return prefixConfig[prop]||0;return(dollar in data)?data[dollar]:((dollar in this.data)?this.data[dollar]:(prefixConfig[prop]||0));} +var setDataInternal=function(prefix,prop,value,type){type=type||'current';prefix='$'+(prefix?prefix+'-':'');var data;if(type=='current'){data=this.data;}else if(type=='start'){data=this.startData;}else if(type=='end'){data=this.endData;} +data[prefix+prop]=value;} +var removeDataInternal=function(prefix,properties){prefix='$'+(prefix?prefix+'-':'');var that=this;$.each(properties,function(prop){var pref=prefix+prop;delete that.data[pref];delete that.endData[pref];delete that.startData[pref];});} +Accessors={getData:function(prop,type,force){return getDataInternal.call(this,"",prop,type,force,this.Config);},setData:function(prop,value,type){setDataInternal.call(this,"",prop,value,type);},setDataset:function(types,obj){types=$.splat(types);for(var attr in obj){for(var i=0,val=$.splat(obj[attr]),l=types.length;i=levelBegin&&d<=levelEnd&&filter(node))action(node,d);if(dd)loopLevel(n,levelBegin,levelEnd);});}})(node,levelBegin+d,levelEnd+d);},eachSubgraph:function(node,action,flags){this.eachLevel(node,0,false,action,flags);},eachSubnode:function(node,action,flags){this.eachLevel(node,1,1,action,flags);},anySubnode:function(node,cond,flags){var flag=false;cond=cond||$.lambda(true);var c=$.type(cond)=='string'?function(n){return n[cond];}:cond;this.eachSubnode(node,function(elem){if(c(elem))flag=true;},flags);return flag;},getSubnodes:function(node,level,flags){var ans=[],that=this;level=level||0;var levelStart,levelEnd;if($.type(level)=='array'){levelStart=level[0];levelEnd=level[1];}else{levelStart=level;levelEnd=Number.MAX_VALUE-node._depth;} +this.eachLevel(node,levelStart,levelEnd,function(n){ans.push(n);},flags);return ans;},getParents:function(node){var ans=[];this.eachAdjacency(node,function(adj){var n=adj.nodeTo;if(n._depth-1)){elem.endData[prop]=graphNodeData[prop];}else{elem.data[prop]=graphNodeData[prop];}}}});viz.graph.eachNode(function(elem){if(elem.ignore)return;elem.eachAdjacency(function(adj){if(adj.nodeFrom.ignore||adj.nodeTo.ignore)return;var nodeFrom=graph.getNode(adj.nodeFrom.id);var nodeTo=graph.getNode(adj.nodeTo.id);if(!nodeFrom.adjacentTo(nodeTo)){var adj=viz.graph.getAdjacence(nodeFrom.id,nodeTo.id);fadeEdges=true;adj.setData('alpha',1);adj.setData('alpha',1,'start');adj.setData('alpha',0,'end');}});});var fadeEdges=this.preprocessSum(graph);var modes=!fadeEdges?['node-property:alpha']:['node-property:alpha','edge-property:alpha'];modes[0]=modes[0]+((extraModes&&('node-property'in extraModes))?(':'+$.splat(extraModes['node-property']).join(':')):'');modes[1]=(modes[1]||'edge-property:alpha')+((extraModes&&('edge-property'in extraModes))?(':'+$.splat(extraModes['edge-property']).join(':')):'');if(extraModes&&('label-property'in extraModes)){modes.push('label-property:'+$.splat(extraModes['label-property']).join(':'))} +viz.reposition();viz.graph.eachNode(function(elem){if(elem.id!=root&&elem.pos.getp().equals(Polar.KER)){elem.pos.set(elem.endPos);elem.startPos.set(elem.endPos);}});viz.fx.animate($.merge(options,{modes:['polar'].concat(modes),onComplete:function(){viz.graph.eachNode(function(elem){if(elem.ignore)viz.graph.removeNode(elem.id);});viz.graph.eachNode(function(elem){elem.eachAdjacency(function(adj){if(adj.ignore)viz.graph.removeAdjacence(adj.nodeFrom.id,adj.nodeTo.id);});});options.onComplete();}}));break;default:;}},contract:function(node,opt){var viz=this.viz;if(node.collapsed||!node.anySubnode($.lambda(true)))return;opt=$.merge(this.options,viz.config,opt||{},{'modes':['node-property:alpha:span','linear']});node.collapsed=true;(function subn(n){n.eachSubnode(function(ch){ch.ignore=true;ch.setData('alpha',0,opt.type=='animate'?'end':'current');subn(ch);});})(node);if(opt.type=='animate'){viz.compute('end');if(viz.rotated){viz.rotate(viz.rotated,'none',{'property':'end'});} +(function subn(n){n.eachSubnode(function(ch){ch.setPos(node.getPos('end'),'end');subn(ch);});})(node);viz.fx.animate(opt);}else if(opt.type=='replot'){viz.refresh();}},expand:function(node,opt){if(!('collapsed'in node))return;var viz=this.viz;opt=$.merge(this.options,viz.config,opt||{},{'modes':['node-property:alpha:span','linear']});delete node.collapsed;(function subn(n){n.eachSubnode(function(ch){delete ch.ignore;ch.setData('alpha',1,opt.type=='animate'?'end':'current');subn(ch);});})(node);if(opt.type=='animate'){viz.compute('end');if(viz.rotated){viz.rotate(viz.rotated,'none',{'property':'end'});} +viz.fx.animate(opt);}else if(opt.type=='replot'){viz.refresh();}},preprocessSum:function(graph){var viz=this.viz;graph.eachNode(function(elem){if(!viz.graph.hasNode(elem.id)){viz.graph.addNode(elem);var n=viz.graph.getNode(elem.id);n.setData('alpha',0);n.setData('alpha',0,'start');n.setData('alpha',1,'end');}});var fadeEdges=false;graph.eachNode(function(elem){elem.eachAdjacency(function(adj){var nodeFrom=viz.graph.getNode(adj.nodeFrom.id);var nodeTo=viz.graph.getNode(adj.nodeTo.id);if(!nodeFrom.adjacentTo(nodeTo)){var adj=viz.graph.addAdjacence(nodeFrom,nodeTo,adj.data);if(nodeFrom.startAlpha==nodeFrom.endAlpha&&nodeTo.startAlpha==nodeTo.endAlpha){fadeEdges=true;adj.setData('alpha',0);adj.setData('alpha',0,'start');adj.setData('alpha',1,'end');}}});});return fadeEdges;}};var NodeHelper={'none':{'render':$.empty,'contains':$.lambda(false)},'circle':{'render':function(type,pos,radius,canvas){var ctx=canvas.getCtx();ctx.beginPath();ctx.arc(pos.x,pos.y,radius,0,Math.PI*2,true);ctx.closePath();ctx[type]();},'contains':function(npos,pos,radius){var diffx=npos.x-pos.x,diffy=npos.y-pos.y,diff=diffx*diffx+diffy*diffy;return diff<=radius*radius;}},'ellipse':{'render':function(type,pos,width,height,canvas){var ctx=canvas.getCtx();height/=2;width/=2;ctx.save();ctx.scale(width/height,height/width);ctx.beginPath();ctx.arc(pos.x*(height/width),pos.y*(width/height),height,0,Math.PI*2,true);ctx.closePath();ctx[type]();ctx.restore();},'contains':function(npos,pos,width,height){width/=2;height/=2;var dist=(width+height)/2,diffx=npos.x-pos.x,diffy=npos.y-pos.y,diff=diffx*diffx+diffy*diffy;return diff<=dist*dist;}},'square':{'render':function(type,pos,dim,canvas){canvas.getCtx()[type+"Rect"](pos.x-dim,pos.y-dim,2*dim,2*dim);},'contains':function(npos,pos,dim){return Math.abs(pos.x-npos.x)<=dim&&Math.abs(pos.y-npos.y)<=dim;}},'rectangle':{'render':function(type,pos,width,height,canvas){canvas.getCtx()[type+"Rect"](pos.x-width/2,pos.y-height/2,width,height);},'contains':function(npos,pos,width,height){return Math.abs(pos.x-npos.x)<=width/2&&Math.abs(pos.y-npos.y)<=height/2;}},'triangle':{'render':function(type,pos,dim,canvas){var ctx=canvas.getCtx(),c1x=pos.x,c1y=pos.y-dim,c2x=c1x-dim,c2y=pos.y+dim,c3x=c1x+dim,c3y=c2y;ctx.beginPath();ctx.moveTo(c1x,c1y);ctx.lineTo(c2x,c2y);ctx.lineTo(c3x,c3y);ctx.closePath();ctx[type]();},'contains':function(npos,pos,dim){return NodeHelper.circle.contains(npos,pos,dim);}},'star':{'render':function(type,pos,dim,canvas){var ctx=canvas.getCtx(),pi5=Math.PI/5;ctx.save();ctx.translate(pos.x,pos.y);ctx.beginPath();ctx.moveTo(dim,0);for(var i=0;i<9;i++){ctx.rotate(pi5);if(i%2==0){ctx.lineTo((dim/0.525731)*0.200811,0);}else{ctx.lineTo(dim,0);}} +ctx.closePath();ctx[type]();ctx.restore();},'contains':function(npos,pos,dim){return NodeHelper.circle.contains(npos,pos,dim);}}};var EdgeHelper={'line':{'render':function(from,to,canvas){var ctx=canvas.getCtx();ctx.beginPath();ctx.moveTo(from.x,from.y);ctx.lineTo(to.x,to.y);ctx.stroke();},'contains':function(posFrom,posTo,pos,epsilon){var min=Math.min,max=Math.max,minPosX=min(posFrom.x,posTo.x),maxPosX=max(posFrom.x,posTo.x),minPosY=min(posFrom.y,posTo.y),maxPosY=max(posFrom.y,posTo.y);if(pos.x>=minPosX&&pos.x<=maxPosX&&pos.y>=minPosY&&pos.y<=maxPosY){if(Math.abs(posTo.x-posFrom.x)<=epsilon){return true;} +var dist=(posTo.y-posFrom.y)/(posTo.x-posFrom.x)*(pos.x-posFrom.x)+posFrom.y;return Math.abs(dist-pos.y)<=epsilon;} +return false;}},'arrow':{'render':function(from,to,dim,swap,canvas){var ctx=canvas.getCtx();if(swap){var tmp=from;from=to;to=tmp;} +var vect=new Complex(to.x-from.x,to.y-from.y);vect.$scale(dim/vect.norm());var intermediatePoint=new Complex(to.x-vect.x,to.y-vect.y),normal=new Complex(-vect.y/2,vect.x/2),v1=intermediatePoint.add(normal),v2=intermediatePoint.$add(normal.$scale(-1));ctx.beginPath();ctx.moveTo(from.x,from.y);ctx.lineTo(to.x,to.y);ctx.stroke();ctx.beginPath();ctx.moveTo(v1.x,v1.y);ctx.lineTo(v2.x,v2.y);ctx.lineTo(to.x,to.y);ctx.closePath();ctx.fill();},'contains':function(posFrom,posTo,pos,epsilon){return EdgeHelper.line.contains(posFrom,posTo,pos,epsilon);}},'hyperline':{'render':function(from,to,r,canvas){var ctx=canvas.getCtx();var centerOfCircle=computeArcThroughTwoPoints(from,to);if(centerOfCircle.a>1000||centerOfCircle.b>1000||centerOfCircle.ratio<0){ctx.beginPath();ctx.moveTo(from.x*r,from.y*r);ctx.lineTo(to.x*r,to.y*r);ctx.stroke();}else{var angleBegin=Math.atan2(to.y-centerOfCircle.y,to.x +-centerOfCircle.x);var angleEnd=Math.atan2(from.y-centerOfCircle.y,from.x +-centerOfCircle.x);var sense=sense(angleBegin,angleEnd);ctx.beginPath();ctx.arc(centerOfCircle.x*r,centerOfCircle.y*r,centerOfCircle.ratio*r,angleBegin,angleEnd,sense);ctx.stroke();} +function computeArcThroughTwoPoints(p1,p2){var aDen=(p1.x*p2.y-p1.y*p2.x),bDen=aDen;var sq1=p1.squaredNorm(),sq2=p2.squaredNorm();if(aDen==0) +return{x:0,y:0,ratio:-1};var a=(p1.y*sq2-p2.y*sq1+p1.y-p2.y)/aDen;var b=(p2.x*sq1-p1.x*sq2+p2.x-p1.x)/bDen;var x=-a/2;var y=-b/2;var squaredRatio=(a*a+b*b)/4-1;if(squaredRatio<0) +return{x:0,y:0,ratio:-1};var ratio=Math.sqrt(squaredRatio);var out={x:x,y:y,ratio:ratio>1000?-1:ratio,a:a,b:b};return out;} +function sense(angleBegin,angleEnd){return(angleBeginangleEnd)?false:true):((angleEnd+Math.PI>angleBegin)?true:false);}},'contains':$.lambda(false)}};Graph.Plot={initialize:function(viz,klass){this.viz=viz;this.config=viz.config;this.node=viz.config.Node;this.edge=viz.config.Edge;this.animation=new Animation;this.nodeTypes=new klass.Plot.NodeTypes;this.edgeTypes=new klass.Plot.EdgeTypes;this.labels=viz.labels;},nodeHelper:NodeHelper,edgeHelper:EdgeHelper,Interpolator:{'map':{'border':'color','color':'color','width':'number','height':'number','dim':'number','alpha':'number','lineWidth':'number','angularWidth':'number','span':'number','valueArray':'array-number','dimArray':'array-number'},'canvas':{'globalAlpha':'number','fillStyle':'color','strokeStyle':'color','lineWidth':'number','shadowBlur':'number','shadowColor':'color','shadowOffsetX':'number','shadowOffsetY':'number','miterLimit':'number'},'label':{'size':'number','color':'color'},'compute':function(from,to,delta){return from+(to-from)*delta;},'moebius':function(elem,props,delta,vector){var v=vector.scale(-delta);if(v.norm()<1){var x=v.x,y=v.y;var ans=elem.startPos.getc().moebiusTransformation(v);elem.pos.setc(ans.x,ans.y);v.x=x;v.y=y;}},'linear':function(elem,props,delta){var from=elem.startPos.getc(true);var to=elem.endPos.getc(true);elem.pos.setc(this.compute(from.x,to.x,delta),this.compute(from.y,to.y,delta));},'polar':function(elem,props,delta){var from=elem.startPos.getp(true);var to=elem.endPos.getp();var ans=to.interpolate(from,delta);elem.pos.setp(ans.theta,ans.rho);},'number':function(elem,prop,delta,getter,setter){var from=elem[getter](prop,'start');var to=elem[getter](prop,'end');elem[setter](prop,this.compute(from,to,delta));},'color':function(elem,prop,delta,getter,setter){var from=$.hexToRgb(elem[getter](prop,'start'));var to=$.hexToRgb(elem[getter](prop,'end'));var comp=this.compute;var val=$.rgbToHex([parseInt(comp(from[0],to[0],delta)),parseInt(comp(from[1],to[1],delta)),parseInt(comp(from[2],to[2],delta))]);elem[setter](prop,val);},'array-number':function(elem,prop,delta,getter,setter){var from=elem[getter](prop,'start'),to=elem[getter](prop,'end'),cur=[];for(var i=0,l=from.length;i=0.95){that.labels.plotLabel(canvas,node,opt);}else{that.labels.hideLabel(node,false);}} +ctx.restore();node.visited=!T;});},plotTree:function(node,opt,animating){var that=this,viz=this.viz,canvas=viz.canvas,config=this.config,ctx=canvas.getCtx();var nodeAlpha=node.getData('alpha');node.eachSubnode(function(elem){if(opt.plotSubtree(node,elem)&&elem.exist&&elem.drawn){var adj=node.getAdjacency(elem.id);!animating&&opt.onBeforePlotLine(adj);ctx.globalAlpha=Math.min(nodeAlpha,elem.getData('alpha'));that.plotLine(adj,canvas,animating);!animating&&opt.onAfterPlotLine(adj);that.plotTree(elem,opt,animating);}});if(node.drawn){!animating&&opt.onBeforePlotNode(node);this.plotNode(node,canvas,animating);!animating&&opt.onAfterPlotNode(node);if(!opt.hideLabels&&opt.withLabels&&nodeAlpha>=0.95) +this.labels.plotLabel(canvas,node,opt);else +this.labels.hideLabel(node,false);}else{this.labels.hideLabel(node,true);}},plotNode:function(node,canvas,animating){var f=node.getData('type'),ctxObj=this.node.CanvasStyles;if(f!='none'){var width=node.getData('lineWidth'),color=node.getData('color'),alpha=node.getData('alpha'),ctx=canvas.getCtx();ctx.lineWidth=width;ctx.fillStyle=ctx.strokeStyle=color;ctx.globalAlpha=alpha;for(var s in ctxObj){ctx[s]=node.getCanvasStyle(s);} +this.nodeTypes[f].render.call(this,node,canvas,animating);}},plotLine:function(adj,canvas,animating){var f=adj.getData('type'),ctxObj=this.edge.CanvasStyles;if(f!='none'){var width=adj.getData('lineWidth'),color=adj.getData('color'),ctx=canvas.getCtx();ctx.lineWidth=width;ctx.fillStyle=ctx.strokeStyle=color;for(var s in ctxObj){ctx[s]=adj.getCanvasStyle(s);} +this.edgeTypes[f].render.call(this,adj,canvas,animating);}}};Graph.Label={};Graph.Label.Native=new Class({plotLabel:function(canvas,node,controller){var ctx=canvas.getCtx();var pos=node.pos.getc(true);ctx.font=node.getLabelData('style')+' '+node.getLabelData('size')+'px '+node.getLabelData('family');ctx.textAlign=node.getLabelData('textAlign');ctx.fillStyle=ctx.strokeStyle=node.getLabelData('color');ctx.textBaseline=node.getLabelData('textBaseline');this.renderLabel(canvas,node,controller);},renderLabel:function(canvas,node,controller){var ctx=canvas.getCtx();var pos=node.pos.getc(true);ctx.fillText(node.name,pos.x,pos.y+node.getData("height")/2);},hideLabel:$.empty,hideLabels:$.empty});Graph.Label.DOM=new Class({labelsHidden:false,labelContainer:false,labels:{},getLabelContainer:function(){return this.labelContainer?this.labelContainer:this.labelContainer=document.getElementById(this.viz.config.labelContainer);},getLabel:function(id){return(id in this.labels&&this.labels[id]!=null)?this.labels[id]:this.labels[id]=document.getElementById(id);},hideLabels:function(hide){var container=this.getLabelContainer();if(hide) +container.style.display='none';else +container.style.display='';this.labelsHidden=hide;},clearLabels:function(force){for(var id in this.labels){if(force||!this.viz.graph.hasNode(id)){this.disposeLabel(id);delete this.labels[id];}}},disposeLabel:function(id){var elem=this.getLabel(id);if(elem&&elem.parentNode){elem.parentNode.removeChild(elem);}},hideLabel:function(node,show){node=$.splat(node);var st=show?"":"none",lab,that=this;$.each(node,function(n){var lab=that.getLabel(n.id);if(lab){lab.style.display=st;}});},fitsInCanvas:function(pos,canvas){var size=canvas.getSize();if(pos.x>=size.width||pos.x<0||pos.y>=size.height||pos.y<0)return false;return true;}});Graph.Label.HTML=new Class({Implements:Graph.Label.DOM,plotLabel:function(canvas,node,controller){var id=node.id,tag=this.getLabel(id);if(!tag&&!(tag=document.getElementById(id))){tag=document.createElement('div');var container=this.getLabelContainer();tag.id=id;tag.className='node';tag.style.position='absolute';controller.onCreateLabel(tag,node);container.appendChild(tag);this.labels[node.id]=tag;} +this.placeLabel(tag,node,controller);}});Graph.Label.SVG=new Class({Implements:Graph.Label.DOM,plotLabel:function(canvas,node,controller){var id=node.id,tag=this.getLabel(id);if(!tag&&!(tag=document.getElementById(id))){var ns='http://www.w3.org/2000/svg';tag=document.createElementNS(ns,'svg:text');var tspan=document.createElementNS(ns,'svg:tspan');tag.appendChild(tspan);var container=this.getLabelContainer();tag.setAttribute('id',id);tag.setAttribute('class','node');container.appendChild(tag);controller.onCreateLabel(tag,node);this.labels[node.id]=tag;} +this.placeLabel(tag,node,controller);}});Graph.Geom=new Class({initialize:function(viz){this.viz=viz;this.config=viz.config;this.node=viz.config.Node;this.edge=viz.config.Edge;},translate:function(pos,prop){prop=$.splat(prop);this.viz.graph.eachNode(function(elem){$.each(prop,function(p){elem.getPos(p).$add(pos);});});},setRightLevelToShow:function(node,canvas,callback){var level=this.getRightLevelToShow(node,canvas),fx=this.viz.labels,opt=$.merge({execShow:true,execHide:true,onHide:$.empty,onShow:$.empty},callback||{});node.eachLevel(0,this.config.levelsToShow,function(n){var d=n._depth-node._depth;if(d>level){opt.onHide(n);if(opt.execHide){n.drawn=false;n.exist=false;fx.hideLabel(n,false);}}else{opt.onShow(n);if(opt.execShow){n.exist=true;}}});node.drawn=true;},getRightLevelToShow:function(node,canvas){var config=this.config;var level=config.levelsToShow;var constrained=config.constrained;if(!constrained)return level;while(!this.treeFitsInCanvas(node,canvas,level)&&level>1){level--;} +return level;}});var Loader={construct:function(json){var isGraph=($.type(json)=='array');var ans=new Graph(this.graphOptions,this.config.Node,this.config.Edge,this.config.Label);if(!isGraph) +(function(ans,json){ans.addNode(json);if(json.children){for(var i=0,ch=json.children;ioffsetHeight?offsetWidth:offsetHeight;n.setData('width',dim);n.setData('height',dim);n.setData('dim',dim);}}});},initializeLabel:function(opt){if(!this.label){this.label=document.createElement('div');document.body.appendChild(this.label);} +this.setLabelStyles(opt);},setLabelStyles:function(opt){$.extend(this.label.style,{'visibility':'hidden','position':'absolute','width':'auto','height':'auto'});this.label.className='jit-autoadjust-label';}};Layouts.Tree=(function(){var slice=Array.prototype.slice;function getBoundaries(graph,config,level,orn,prop){var dim=config.Node;var multitree=config.multitree;if(dim.overridable){var w=-1,h=-1;graph.eachNode(function(n){if(n._depth==level&&(!multitree||('$orn'in n.data)&&n.data.$orn==orn)){var dw=n.getData('width',prop);var dh=n.getData('height',prop);w=(w0)?parents[0]:null;path(parents);};for(var i=0,ns=[node.id].concat(nodesInPath);i=b._depth);});for(var i=0;i0&&n.drawn){n.drawn=false;nds[node.id].push(n);}else if((!root||!orns)&&n.drawn){n.drawn=false;nds[node.id].push(n);}});node.drawn=true;} +if(nodes.length>0)viz.fx.plot();for(i in nds){$.each(nds[i],function(n){n.drawn=true;});} +for(i=0;ibaseHeight?size:baseHeight)+this.config.subtreeOffset;},getEdge:function(node,type,s){var $C=function(a,b){return function(){return node.pos.add(new Complex(a,b));};};var dim=this.node;var w=node.getData('width');var h=node.getData('height');if(type=='begin'){if(dim.align=="center"){return this.dispatch(s,$C(0,h/2),$C(-w/2,0),$C(0,-h/2),$C(w/2,0));}else if(dim.align=="left"){return this.dispatch(s,$C(0,h),$C(0,0),$C(0,0),$C(w,0));}else if(dim.align=="right"){return this.dispatch(s,$C(0,0),$C(-w,0),$C(0,-h),$C(0,0));}else throw"align: not implemented";}else if(type=='end'){if(dim.align=="center"){return this.dispatch(s,$C(0,-h/2),$C(w/2,0),$C(0,h/2),$C(-w/2,0));}else if(dim.align=="left"){return this.dispatch(s,$C(0,0),$C(w,0),$C(0,h),$C(0,0));}else if(dim.align=="right"){return this.dispatch(s,$C(0,-h),$C(0,0),$C(0,0),$C(-w,0));}else throw"align: not implemented";}},getScaledTreePosition:function(node,scale){var dim=this.node;var w=node.getData('width');var h=node.getData('height');var s=(this.config.multitree&&('$orn'in node.data)&&node.data.$orn)||this.config.orientation;var $C=function(a,b){return function(){return node.pos.add(new Complex(a,b)).$scale(1-scale);};};if(dim.align=="left"){return this.dispatch(s,$C(0,h),$C(0,0),$C(0,0),$C(w,0));}else if(dim.align=="center"){return this.dispatch(s,$C(0,h/2),$C(-w/2,0),$C(0,-h/2),$C(w/2,0));}else if(dim.align=="right"){return this.dispatch(s,$C(0,0),$C(-w,0),$C(0,-h),$C(0,0));}else throw"align: not implemented";},treeFitsInCanvas:function(node,canvas,level){var csize=canvas.getSize();var s=(this.config.multitree&&('$orn'in node.data)&&node.data.$orn)||this.config.orientation;var size=this.dispatch(s,csize.width,csize.height);var baseSize=this.getTreeBaseSize(node,level,function(level,node){return level===0||!node.anySubnode();});return(baseSize=0){node.drawn=false;var ctx=canvas.getCtx();var diff=viz.geom.getScaledTreePosition(node,scale);ctx.translate(diff.x,diff.y);ctx.scale(scale,scale);} +this.plotTree(node,$.merge(opt,{'withLabels':true,'hideLabels':!!scale,'plotSubtree':function(n,ch){var root=config.multitree&&!('$orn'in node.data);var orns=root&&node.getData('orns');return!root||orns.indexOf(elem.getData('orn'))>-1;}}),animating);if(scale>=0)node.drawn=true;},getAlignedPos:function(pos,width,height){var nconfig=this.node;var square,orn;if(nconfig.align=="center"){square={x:pos.x-width/2,y:pos.y-height/2};}else if(nconfig.align=="left"){orn=this.config.orientation;if(orn=="bottom"||orn=="top"){square={x:pos.x-width/2,y:pos.y};}else{square={x:pos.x,y:pos.y-height/2};}}else if(nconfig.align=="right"){orn=this.config.orientation;if(orn=="bottom"||orn=="top"){square={x:pos.x-width/2,y:pos.y-height};}else{square={x:pos.x-width,y:pos.y-height/2};}}else throw"align: not implemented";return square;},getOrientation:function(adj){var config=this.config;var orn=config.orientation;if(config.multitree){var nodeFrom=adj.nodeFrom;var nodeTo=adj.nodeTo;orn=(('$orn'in nodeFrom.data)&&nodeFrom.data.$orn)||(('$orn'in nodeTo.data)&&nodeTo.data.$orn);} +return orn;}});$jit.ST.Label={};$jit.ST.Label.Native=new Class({Implements:Graph.Label.Native,renderLabel:function(canvas,node,controller){var ctx=canvas.getCtx();var coord=node.pos.getc(true);ctx.fillText(node.name,coord.x,coord.y);}});$jit.ST.Label.DOM=new Class({Implements:Graph.Label.DOM,placeLabel:function(tag,node,controller){var pos=node.pos.getc(true),config=this.viz.config,dim=config.Node,canvas=this.viz.canvas,w=node.getData('width'),h=node.getData('height'),radius=canvas.getSize(),labelPos,orn;var ox=canvas.translateOffsetX,oy=canvas.translateOffsetY,sx=canvas.scaleOffsetX,sy=canvas.scaleOffsetY,posx=pos.x*sx+ox,posy=pos.y*sy+oy;if(dim.align=="center"){labelPos={x:Math.round(posx-w/2+radius.width/2),y:Math.round(posy-h/2+radius.height/2)};}else if(dim.align=="left"){orn=config.orientation;if(orn=="bottom"||orn=="top"){labelPos={x:Math.round(posx-w/2+radius.width/2),y:Math.round(posy+radius.height/2)};}else{labelPos={x:Math.round(posx+radius.width/2),y:Math.round(posy-h/2+radius.height/2)};}}else if(dim.align=="right"){orn=config.orientation;if(orn=="bottom"||orn=="top"){labelPos={x:Math.round(posx-w/2+radius.width/2),y:Math.round(posy-h+radius.height/2)};}else{labelPos={x:Math.round(posx-w+radius.width/2),y:Math.round(posy-h/2+radius.height/2)};}}else throw"align: not implemented";var style=tag.style;style.left=labelPos.x+'px';style.top=labelPos.y+'px';style.display=this.fitsInCanvas(labelPos,canvas)?'':'none';controller.onPlaceLabel(tag,node);}});$jit.ST.Label.SVG=new Class({Implements:[$jit.ST.Label.DOM,Graph.Label.SVG],initialize:function(viz){this.viz=viz;}});$jit.ST.Label.HTML=new Class({Implements:[$jit.ST.Label.DOM,Graph.Label.HTML],initialize:function(viz){this.viz=viz;}});$jit.ST.Plot.NodeTypes=new Class({'none':{'render':$.empty,'contains':$.lambda(false)},'circle':{'render':function(node,canvas){var dim=node.getData('dim'),pos=this.getAlignedPos(node.pos.getc(true),dim,dim),dim2=dim/2;this.nodeHelper.circle.render('fill',{x:pos.x+dim2,y:pos.y+dim2},dim2,canvas);},'contains':function(node,pos){var dim=node.getData('dim'),npos=this.getAlignedPos(node.pos.getc(true),dim,dim),dim2=dim/2;this.nodeHelper.circle.contains({x:npos.x+dim2,y:npos.y+dim2},dim2);}},'square':{'render':function(node,canvas){var dim=node.getData('dim'),dim2=dim/2,pos=this.getAlignedPos(node.pos.getc(true),dim,dim);this.nodeHelper.square.render('fill',{x:pos.x+dim2,y:pos.y+dim2},dim2,canvas);},'contains':function(node,pos){var dim=node.getData('dim'),npos=this.getAlignedPos(node.pos.getc(true),dim,dim),dim2=dim/2;this.nodeHelper.square.contains({x:npos.x+dim2,y:npos.y+dim2},dim2);}},'ellipse':{'render':function(node,canvas){var width=node.getData('width'),height=node.getData('height'),pos=this.getAlignedPos(node.pos.getc(true),width,height);this.nodeHelper.ellipse.render('fill',{x:pos.x+width/2,y:pos.y+height/2},width,height,canvas);},'contains':function(node,pos){var width=node.getData('width'),height=node.getData('height'),npos=this.getAlignedPos(node.pos.getc(true),width,height);this.nodeHelper.ellipse.contains({x:npos.x+width/2,y:npos.y+height/2},width,height,canvas);}},'rectangle':{'render':function(node,canvas){var width=node.getData('width'),height=node.getData('height'),pos=this.getAlignedPos(node.pos.getc(true),width,height);this.nodeHelper.rectangle.render('fill',{x:pos.x+width/2,y:pos.y+height/2},width,height,canvas);},'contains':function(node,pos){var width=node.getData('width'),height=node.getData('height'),npos=this.getAlignedPos(node.pos.getc(true),width,height);this.nodeHelper.rectangle.contains({x:npos.x+width/2,y:npos.y+height/2},width,height,canvas);}}});$jit.ST.Plot.EdgeTypes=new Class({'none':$.empty,'line':{'render':function(adj,canvas){var orn=this.getOrientation(adj),nodeFrom=adj.nodeFrom,nodeTo=adj.nodeTo,rel=nodeFrom._depth1&&direction[0]!=node.id);this.edgeHelper.arrow.render(from,to,dim,inv,canvas);},'contains':function(adj,pos){var orn=this.getOrientation(adj),nodeFrom=adj.nodeFrom,nodeTo=adj.nodeTo,rel=nodeFrom._depthx+dataPointMidPoint){return false;} +for(var i=0,l=dimArray.length;i=x-dataPointMidPoint&&mpos.x<=x+dataPointMidPoint&&mpos.y>=y-dimi[0]-dataPointMidPoint&&mpos.y<=y-dimi[0]+dataPointMidPoint){var valArrayCur=node.getData('valArrayCur');var results=array_match(valArrayCur[i],valArrayCur);var matches=results[0];var indexValues=results[1];if(matches>1){var names=new Array(),values=new Array(),percentages=new Array(),linksArr=new Array();for(var j=0,il=indexValues.length;j0){acum+=valArray[i][0];leftAcum+=dimArray[i][0];}} +aggregateStyle.top=(-font-config.labelOffset)+'px';labelStyle.top=(config.labelOffset+leftAcum)+'px';domElement.style.top=parseInt(domElement.style.top,10)-leftAcum+'px';domElement.style.height=wrapperStyle.height=leftAcum+'px';labels.aggregate.innerHTML=acum;}}});var size=st.canvas.getSize(),margin=config.Margin;st.config.offsetY=-size.height/2+margin.bottom ++(config.showLabels&&(config.labelOffset+config.Label.size));st.config.offsetX=(margin.right-margin.left-config.labelOffset-config.Label.size)/2;this.st=st;this.canvas=this.st.canvas;},renderTitle:function(){var canvas=this.canvas,size=canvas.getSize(),config=this.config,margin=config.Margin,label=config.Label,title=config.Title;ctx=canvas.getCtx();ctx.fillStyle=title.color;ctx.textAlign='left';ctx.textBaseline='top';ctx.font=label.style+' bold '+' '+title.size+'px '+label.family;if(label.type=='Native'){ctx.fillText(title.text,-size.width/2+margin.left,-size.height/2+margin.top);}},renderTicks:function(){var canvas=this.canvas,size=canvas.getSize(),config=this.config,margin=config.Margin,ticks=config.Ticks,title=config.Title,subtitle=config.Subtitle,label=config.Label,maxValue=this.maxValue,maxTickValue=Math.ceil(maxValue*.1)*10;if(maxTickValue==maxValue){var length=maxTickValue.toString().length;maxTickValue=maxTickValue+parseInt(pad(1,length));} +labelValue=0,labelIncrement=maxTickValue/ticks.segments,ctx=canvas.getCtx();ctx.strokeStyle=ticks.color;ctx.font=label.style+' '+label.size+'px '+label.family;ctx.textAlign='center';ctx.textBaseline='middle';idLabel=canvas.id+"-label";labelDim=100;container=document.getElementById(idLabel);var axis=(size.height/2)-(margin.bottom+config.labelOffset+label.size+(subtitle.text?subtitle.size+subtitle.offset:0)),htmlOrigin=size.height-(margin.bottom+config.labelOffset+label.size+(subtitle.text?subtitle.size+subtitle.offset:0)),grid=-size.height+(margin.bottom+config.labelOffset+label.size+margin.top+(title.text?title.size+title.offset:0)+(subtitle.text?subtitle.size+subtitle.offset:0)),segmentLength=grid/ticks.segments;ctx.fillStyle=ticks.color;ctx.fillRect(-(size.width/2)+margin.left+config.labelOffset+label.size-1,-(size.height/2)+margin.top+(title.text?title.size+title.offset:0),1,size.height-margin.top-margin.bottom-label.size-config.labelOffset-(title.text?title.size+title.offset:0)-(subtitle.text?subtitle.size+subtitle.offset:0));while(axis>=grid){ctx.save();ctx.translate(-(size.width/2)+margin.left,Math.round(axis));ctx.rotate(Math.PI/2);ctx.fillStyle=label.color;if(config.showLabels){if(label.type=='Native'){ctx.fillText(labelValue,0,0);}else{labelDiv=document.createElement('div');labelDiv.innerHTML=labelValue;labelDiv.className="rotatedLabel";labelDiv.style.top=(htmlOrigin-(labelDim/2))+"px";labelDiv.style.left=margin.left+"px";labelDiv.style.width=labelDim+"px";labelDiv.style.height=labelDim+"px";labelDiv.style.textAlign="center";labelDiv.style.verticalAlign="middle";labelDiv.style.position="absolute";container.appendChild(labelDiv);}} +ctx.restore();ctx.fillStyle=ticks.color;ctx.fillRect(-(size.width/2)+margin.left+config.labelOffset+label.size,Math.round(axis),size.width-margin.right-margin.left-config.labelOffset-label.size,1);htmlOrigin+=segmentLength;axis+=segmentLength;labelValue+=labelIncrement;}},renderBackground:function(){var canvas=this.canvas,config=this.config,backgroundColor=config.backgroundColor,size=canvas.getSize(),ctx=canvas.getCtx();ctx.fillStyle=backgroundColor;ctx.fillRect(-size.width/2,-size.height/2,size.width,size.height);},loadJSON:function(json){var prefix=$.time(),ch=[],st=this.st,name=$.splat(json.label),color=$.splat(json.color||this.colors),config=this.config,ticks=config.Ticks,renderBackground=config.renderBackground,gradient=!!config.type.split(":")[1],animate=config.animate,title=config.Title,groupTotalValue=0;var valArrayAll=new Array();for(var i=0,values=json.values,l=values.length;i-1)?d:[0,0];}),'end');});this.st.fx.animate({modes:['node-property:dimArray'],duration:1500,onComplete:function(){that.busy=false;}});},restore:function(){if(this.busy)return;this.busy=true;if(this.config.Tips.enable)this.st.tips.hide();this.select(false,false,false);this.normalizeDims();var that=this;this.st.fx.animate({modes:['node-property:height:dimArray'],duration:1500,onComplete:function(){that.busy=false;}});},select:function(id,name,index){if(!this.config.selectOnHover)return;var s=this.selected;if(s.id!=id||s.name!=name||s.index!=index){s.id=id;s.name=name;s.index=index;this.st.graph.eachNode(function(n){n.setData('border',false);});if(id){var n=this.st.graph.getNode(id);n.setData('border',s);var link=index===0?'prev':'next';link=n.getData(link);if(link){n=this.st.graph.getByName(link);if(n){n.setData('border',{name:name,index:1-index});}}} +this.st.plot();}},getLegend:function(){var legend=new Array();var name=new Array();var color=new Array();var n;this.st.graph.getNode(this.st.root).eachAdjacency(function(adj){n=adj.nodeTo;});var colors=n.getData('colorArray'),len=colors.length;$.each(n.getData('stringArray'),function(s,i){color[i]=colors[i%len];name[i]=s;});legend['name']=name;legend['color']=color;return legend;},normalizeDims:function(){var root=this.st.graph.getNode(this.st.root),l=0;root.eachAdjacency(function(){l++;});var maxValue=this.maxValue||1,size=this.st.canvas.getSize(),config=this.config,margin=config.Margin,labelOffset=config.labelOffset+config.Label.size,fixedDim=(size.width-(margin.left+margin.right+labelOffset))/(l-1),animate=config.animate,ticks=config.Ticks,height=size.height-(margin.top+margin.bottom)-(config.showAggregates&&labelOffset) +-(config.showLabels&&labelOffset);var maxTickValue=Math.ceil(maxValue*.1)*10;if(maxTickValue==maxValue){var length=maxTickValue.toString().length;maxTickValue=maxTickValue+parseInt(pad(1,length));} +this.st.graph.eachNode(function(n){var acumLeft=0,acumRight=0,animateValue=[];$.each(n.getData('valueArray'),function(v){acumLeft+=+v[0];acumRight+=+v[1];animateValue.push([0,0]);});var acum=acumRight>acumLeft?acumRight:acumLeft;n.setData('width',fixedDim);if(animate){n.setData('height',acum*height/maxValue,'end');n.setData('dimArray',$.map(n.getData('valueArray'),function(n){return[n[0]*height/maxValue,n[1]*height/maxValue];}),'end');var dimArray=n.getData('dimArray');if(!dimArray){n.setData('dimArray',animateValue);}}else{if(ticks.enable){n.setData('height',acum*height/maxValue);n.setData('dimArray',$.map(n.getData('valueArray'),function(n){return[n[0]*height/maxTickValue,n[1]*height/maxTickValue];}));}else{n.setData('height',acum*height/maxValue);n.setData('dimArray',$.map(n.getData('valueArray'),function(n){return[n[0]*height/maxValue,n[1]*height/maxValue];}));}}});}});$jit.ST.Plot.NodeTypes.implement({'areachart-stacked':{'render':function(node,canvas){var pos=node.pos.getc(true),width=node.getData('width'),height=node.getData('height'),algnPos=this.getAlignedPos(pos,width,height),x=algnPos.x,y=algnPos.y,stringArray=node.getData('stringArray'),dimArray=node.getData('dimArray'),valArray=node.getData('valueArray'),valLeft=$.reduce(valArray,function(x,y){return x+y[0];},0),valRight=$.reduce(valArray,function(x,y){return x+y[1];},0),colorArray=node.getData('colorArray'),colorLength=colorArray.length,config=node.getData('config'),gradient=node.getData('gradient'),showLabels=config.showLabels,aggregates=config.showAggregates,label=config.Label,prev=node.getData('prev');var ctx=canvas.getCtx(),border=node.getData('border');if(colorArray&&dimArray&&stringArray){for(var i=0,l=dimArray.length,acumLeft=0,acumRight=0,valAcum=0;i0||dimArray[i][1]>0)){var h1=acumLeft+dimArray[i][0],h2=acumRight+dimArray[i][1],alpha=Math.atan((h2-h1)/width),delta=55;var linear=ctx.createLinearGradient(x+width/2,y-(h1+h2)/2,x+width/2+delta*Math.sin(alpha),y-(h1+h2)/2+delta*Math.cos(alpha));var color=$.rgbToHex($.map($.hexToRgb(colorArray[i%colorLength].slice(1)),function(v){return(v*0.85)>>0;}));linear.addColorStop(0,colorArray[i%colorLength]);linear.addColorStop(1,color);ctx.fillStyle=linear;} +ctx.beginPath();ctx.moveTo(x,y-acumLeft);ctx.lineTo(x+width,y-acumRight);ctx.lineTo(x+width,y-acumRight-dimArray[i][1]);ctx.lineTo(x,y-acumLeft-dimArray[i][0]);ctx.lineTo(x,y-acumLeft);ctx.fill();ctx.restore();if(border){var strong=border.name==stringArray[i];var perc=strong?0.7:0.8;var color=$.rgbToHex($.map($.hexToRgb(colorArray[i%colorLength].slice(1)),function(v){return(v*perc)>>0;}));ctx.strokeStyle=color;ctx.lineWidth=strong?4:1;ctx.save();ctx.beginPath();if(border.index===0){ctx.moveTo(x,y-acumLeft);ctx.lineTo(x,y-acumLeft-dimArray[i][0]);}else{ctx.moveTo(x+width,y-acumRight);ctx.lineTo(x+width,y-acumRight-dimArray[i][1]);} +ctx.stroke();ctx.restore();} +acumLeft+=(dimArray[i][0]||0);acumRight+=(dimArray[i][1]||0);if(dimArray[i][0]>0) +valAcum+=(valArray[i][0]||0);} +if(prev&&label.type=='Native'){ctx.save();ctx.beginPath();ctx.fillStyle=ctx.strokeStyle=label.color;ctx.font=label.style+' '+label.size+'px '+label.family;ctx.textAlign='center';ctx.textBaseline='middle';if(aggregates(node.name,valLeft,valRight,node)){ctx.fillText(valAcum,x,y-acumLeft-config.labelOffset-label.size/2,width);} +if(showLabels(node.name,valLeft,valRight,node)){ctx.fillText(node.name,x,y+label.size/2+config.labelOffset);} +ctx.restore();}}},'contains':function(node,mpos){var pos=node.pos.getc(true),width=node.getData('width'),height=node.getData('height'),algnPos=this.getAlignedPos(pos,width,height),x=algnPos.x,y=algnPos.y,dimArray=node.getData('dimArray'),rx=mpos.x-x;if(mpos.xx+width||mpos.y>y||mpos.y=intersec){var index=+(rx>width/2);return{'name':node.getData('stringArray')[i],'color':node.getData('colorArray')[i],'value':node.getData('valueArray')[i][index],'index':index};}} +return false;}}});$jit.AreaChart=new Class({st:null,colors:["#416D9C","#70A35E","#EBB056","#C74243","#83548B","#909291","#557EAA"],selected:{},busy:false,initialize:function(opt){this.controller=this.config=$.merge(Options("Canvas","Margin","Label","AreaChart"),{Label:{type:'Native'}},opt);var showLabels=this.config.showLabels,typeLabels=$.type(showLabels),showAggregates=this.config.showAggregates,typeAggregates=$.type(showAggregates);this.config.showLabels=typeLabels=='function'?showLabels:$.lambda(showLabels);this.config.showAggregates=typeAggregates=='function'?showAggregates:$.lambda(showAggregates);this.initializeViz();},initializeViz:function(){var config=this.config,that=this,nodeType=config.type.split(":")[0],nodeLabels={};var st=new $jit.ST({injectInto:config.injectInto,orientation:"bottom",levelDistance:0,siblingOffset:0,subtreeOffset:0,withLabels:config.Label.type!='Native',useCanvas:config.useCanvas,Label:{type:config.Label.type},Node:{overridable:true,type:'areachart-'+nodeType,align:'left',width:1,height:1},Edge:{type:'none'},Tips:{enable:config.Tips.enable,type:'Native',force:true,onShow:function(tip,node,contains){var elem=contains;config.Tips.onShow(tip,elem,node);}},Events:{enable:true,type:'Native',onClick:function(node,eventInfo,evt){if(!config.filterOnClick&&!config.Events.enable)return;var elem=eventInfo.getContains();if(elem)config.filterOnClick&&that.filter(elem.name);config.Events.enable&&config.Events.onClick(elem,eventInfo,evt);},onRightClick:function(node,eventInfo,evt){if(!config.restoreOnRightClick)return;that.restore();},onMouseMove:function(node,eventInfo,evt){if(!config.selectOnHover)return;if(node){var elem=eventInfo.getContains();that.select(node.id,elem.name,elem.index);}else{that.select(false,false,false);}}},onCreateLabel:function(domElement,node){var labelConf=config.Label,valueArray=node.getData('valueArray'),acumLeft=$.reduce(valueArray,function(x,y){return x+y[0];},0),acumRight=$.reduce(valueArray,function(x,y){return x+y[1];},0);if(node.getData('prev')){var nlbs={wrapper:document.createElement('div'),aggregate:document.createElement('div'),label:document.createElement('div')};var wrapper=nlbs.wrapper,label=nlbs.label,aggregate=nlbs.aggregate,wrapperStyle=wrapper.style,labelStyle=label.style,aggregateStyle=aggregate.style;nodeLabels[node.id]=nlbs;wrapper.appendChild(label);wrapper.appendChild(aggregate);if(!config.showLabels(node.name,acumLeft,acumRight,node)){label.style.display='none';} +if(!config.showAggregates(node.name,acumLeft,acumRight,node)){aggregate.style.display='none';} +wrapperStyle.position='relative';wrapperStyle.overflow='visible';wrapperStyle.fontSize=labelConf.size+'px';wrapperStyle.fontFamily=labelConf.family;wrapperStyle.color=labelConf.color;wrapperStyle.textAlign='center';aggregateStyle.position=labelStyle.position='absolute';domElement.style.width=node.getData('width')+'px';domElement.style.height=node.getData('height')+'px';label.innerHTML=node.name;domElement.appendChild(wrapper);}},onPlaceLabel:function(domElement,node){if(!node.getData('prev'))return;var labels=nodeLabels[node.id],wrapperStyle=labels.wrapper.style,labelStyle=labels.label.style,aggregateStyle=labels.aggregate.style,width=node.getData('width'),height=node.getData('height'),dimArray=node.getData('dimArray'),valArray=node.getData('valueArray'),acumLeft=$.reduce(valArray,function(x,y){return x+y[0];},0),acumRight=$.reduce(valArray,function(x,y){return x+y[1];},0),font=parseInt(wrapperStyle.fontSize,10),domStyle=domElement.style;if(dimArray&&valArray){if(config.showLabels(node.name,acumLeft,acumRight,node)){labelStyle.display='';}else{labelStyle.display='none';} +if(config.showAggregates(node.name,acumLeft,acumRight,node)){aggregateStyle.display='';}else{aggregateStyle.display='none';} +wrapperStyle.width=aggregateStyle.width=labelStyle.width=domElement.style.width=width+'px';aggregateStyle.left=labelStyle.left=-width/2+'px';for(var i=0,l=valArray.length,acum=0,leftAcum=0;i0){acum+=valArray[i][0];leftAcum+=dimArray[i][0];}} +aggregateStyle.top=(-font-config.labelOffset)+'px';labelStyle.top=(config.labelOffset+leftAcum)+'px';domElement.style.top=parseInt(domElement.style.top,10)-leftAcum+'px';domElement.style.height=wrapperStyle.height=leftAcum+'px';labels.aggregate.innerHTML=acum;}}});var size=st.canvas.getSize(),margin=config.Margin;st.config.offsetY=-size.height/2+margin.bottom ++(config.showLabels&&(config.labelOffset+config.Label.size));st.config.offsetX=(margin.right-margin.left)/2;this.st=st;this.canvas=this.st.canvas;},loadJSON:function(json){var prefix=$.time(),ch=[],st=this.st,name=$.splat(json.label),color=$.splat(json.color||this.colors),config=this.config,gradient=!!config.type.split(":")[1],animate=config.animate;for(var i=0,values=json.values,l=values.length;i-1)?d:[0,0];}),'end');});this.st.fx.animate({modes:['node-property:dimArray'],duration:1500,onComplete:function(){that.busy=false;}});},restore:function(){if(this.busy)return;this.busy=true;if(this.config.Tips.enable)this.st.tips.hide();this.select(false,false,false);this.normalizeDims();var that=this;this.st.fx.animate({modes:['node-property:height:dimArray'],duration:1500,onComplete:function(){that.busy=false;}});},select:function(id,name,index){if(!this.config.selectOnHover)return;var s=this.selected;if(s.id!=id||s.name!=name||s.index!=index){s.id=id;s.name=name;s.index=index;this.st.graph.eachNode(function(n){n.setData('border',false);});if(id){var n=this.st.graph.getNode(id);n.setData('border',s);var link=index===0?'prev':'next';link=n.getData(link);if(link){n=this.st.graph.getByName(link);if(n){n.setData('border',{name:name,index:1-index});}}} +this.st.plot();}},getLegend:function(){var legend={};var n;this.st.graph.getNode(this.st.root).eachAdjacency(function(adj){n=adj.nodeTo;});var colors=n.getData('colorArray'),len=colors.length;$.each(n.getData('stringArray'),function(s,i){legend[s]=colors[i%len];});return legend;},getMaxValue:function(){var maxValue=0;this.st.graph.eachNode(function(n){var valArray=n.getData('valueArray'),acumLeft=0,acumRight=0;$.each(valArray,function(v){acumLeft+=+v[0];acumRight+=+v[1];});var acum=acumRight>acumLeft?acumRight:acumLeft;maxValue=maxValue>acum?maxValue:acum;});return maxValue;},normalizeDims:function(){var root=this.st.graph.getNode(this.st.root),l=0;root.eachAdjacency(function(){l++;});var maxValue=this.getMaxValue()||1,size=this.st.canvas.getSize(),config=this.config,margin=config.Margin,labelOffset=config.labelOffset+config.Label.size,fixedDim=(size.width-(margin.left+margin.right))/l,animate=config.animate,height=size.height-(margin.top+margin.bottom)-(config.showAggregates&&labelOffset) +-(config.showLabels&&labelOffset);this.st.graph.eachNode(function(n){var acumLeft=0,acumRight=0,animateValue=[];$.each(n.getData('valueArray'),function(v){acumLeft+=+v[0];acumRight+=+v[1];animateValue.push([0,0]);});var acum=acumRight>acumLeft?acumRight:acumLeft;n.setData('width',fixedDim);if(animate){n.setData('height',acum*height/maxValue,'end');n.setData('dimArray',$.map(n.getData('valueArray'),function(n){return[n[0]*height/maxValue,n[1]*height/maxValue];}),'end');var dimArray=n.getData('dimArray');if(!dimArray){n.setData('dimArray',animateValue);}}else{n.setData('height',acum*height/maxValue);n.setData('dimArray',$.map(n.getData('valueArray'),function(n){return[n[0]*height/maxValue,n[1]*height/maxValue];}));}});}});Options.BarChart={$extend:true,animate:true,type:'stacked',labelOffset:3,barsOffset:0,nodeCount:0,hoveredColor:'#9fd4ff',background:false,renderBackground:false,orientation:'horizontal',showAggregates:true,showLabels:true,Ticks:{enable:false,segments:4,color:'#000000'},Tips:{enable:false,onShow:$.empty,onHide:$.empty},Events:{enable:false,onClick:$.empty}};$jit.ST.Plot.NodeTypes.implement({'barchart-stacked':{'render':function(node,canvas){var pos=node.pos.getc(true),width=node.getData('width'),height=node.getData('height'),algnPos=this.getAlignedPos(pos,width,height),x=algnPos.x,y=algnPos.y,dimArray=node.getData('dimArray'),valueArray=node.getData('valueArray'),stringArray=node.getData('stringArray'),linkArray=node.getData('linkArray'),gvl=node.getData('gvl'),colorArray=node.getData('colorArray'),colorLength=colorArray.length,nodeCount=node.getData('nodeCount');var ctx=canvas.getCtx(),canvasSize=canvas.getSize(),opt={},border=node.getData('border'),gradient=node.getData('gradient'),config=node.getData('config'),horz=config.orientation=='horizontal',aggregates=config.showAggregates,showLabels=config.showLabels,label=config.Label,margin=config.Margin;if(colorArray&&dimArray&&stringArray){for(var i=0,l=dimArray.length,acum=0,valAcum=0;i>0;}));linear.addColorStop(0,color);linear.addColorStop(0.3,colorArray[i%colorLength]);linear.addColorStop(0.7,colorArray[i%colorLength]);linear.addColorStop(1,color);ctx.fillStyle=linear;} +if(horz){ctx.fillRect(x+acum,y,dimArray[i],height);}else{ctx.fillRect(x,y-acum-dimArray[i],width,dimArray[i]);} +if(border&&border.name==stringArray[i]){opt.acum=acum;opt.dimValue=dimArray[i];} +acum+=(dimArray[i]||0);valAcum+=(valueArray[i]||0);} +if(border){ctx.save();ctx.lineWidth=2;ctx.strokeStyle=border.color;if(horz){ctx.strokeRect(x+opt.acum+1,y+1,opt.dimValue-2,height-2);}else{ctx.strokeRect(x+1,y-opt.acum-opt.dimValue+1,width-2,opt.dimValue-2);} +ctx.restore();} +if(label.type=='Native'){ctx.save();ctx.fillStyle=ctx.strokeStyle=label.color;ctx.font=label.style+' '+label.size+'px '+label.family;ctx.textBaseline='middle';if(gvl){acumValueLabel=gvl;}else{acumValueLabel=valAcum;} +if(aggregates(node.name,valAcum)){if(!horz){ctx.textAlign='center';ctx.font=label.style+' '+label.size+'px '+label.family;ctx.save();gridHeight=canvasSize.height-(margin.top+margin.bottom+(config.Title.text?config.Title.size+config.Title.offset:0)+ +(config.Subtitle.text?config.Subtitle.size+config.Subtitle.offset:0)+ +(label?label.size+config.labelOffset:0));mtxt=ctx.measureText(acumValueLabel);boxWidth=mtxt.width+10;inset=10;boxHeight=label.size+6;if(boxHeight+acum+config.labelOffset>gridHeight){bottomPadding=acum-config.labelOffset-boxHeight;}else{bottomPadding=acum+config.labelOffset+inset;} +ctx.translate(x+width/2-(mtxt.width/2),y-bottomPadding);cornerRadius=4;boxX=-inset/2;boxY=-boxHeight/2;ctx.rotate(0*Math.PI/180);ctx.fillStyle="rgba(255,255,255,.8)";if(boxHeight+acum+config.labelOffset>gridHeight){$.roundedRect(ctx,boxX,boxY,boxWidth,boxHeight,cornerRadius,"fill");} +ctx.fillStyle=ctx.strokeStyle=label.color;ctx.fillText(acumValueLabel,mtxt.width/2,0);ctx.restore();}} +if(showLabels(node.name,valAcum,node)){if(horz){ctx.font=label.style+' '+label.size+'px '+label.family;inset=10;gridWidth=canvasSize.width-(config.Margin.left+config.Margin.right);mtxt=ctx.measureText(node.name+": "+acumValueLabel);boxWidth=mtxt.width+10;inset=10;if(acum+boxWidth+config.labelOffset+inset>gridWidth){leftPadding=acum-config.labelOffset-boxWidth-inset;}else{leftPadding=acum+config.labelOffset;} +ctx.textAlign='left';ctx.translate(x+inset+leftPadding,y+height/2);boxHeight=label.size+6;boxX=-inset/2;boxY=-boxHeight/2;ctx.fillStyle="rgba(255,255,255,.8)";cornerRadius=4;if(acum+boxWidth+config.labelOffset+inset>gridWidth){$.roundedRect(ctx,boxX,boxY,boxWidth,boxHeight,cornerRadius,"fill");} +ctx.fillStyle=label.color;ctx.rotate(0*Math.PI/180);ctx.fillText(node.name+": "+acumValueLabel,0,0);}else{ctx.textAlign='center';ctx.fillText(node.name,x+width/2,y+label.size/2+config.labelOffset);}} +ctx.restore();}}},'contains':function(node,mpos){var pos=node.pos.getc(true),width=node.getData('width'),height=node.getData('height'),algnPos=this.getAlignedPos(pos,width,height),x=algnPos.x,y=algnPos.y,dimArray=node.getData('dimArray'),config=node.getData('config'),rx=mpos.x-x,horz=config.orientation=='horizontal';if(horz){if(mpos.xx+width||mpos.y>y+height||mpos.yx+width||mpos.y>y||mpos.y=intersec){return{'name':node.getData('stringArray')[i],'color':node.getData('colorArray')[i],'value':node.getData('valueArray')[i],'valuelabel':node.getData('valuelabelArray')[i],'percentage':((node.getData('valueArray')[i]/node.getData('barTotalValue'))*100).toFixed(1),'link':url,'label':node.name};}}} +return false;}},'barchart-grouped':{'render':function(node,canvas){var pos=node.pos.getc(true),width=node.getData('width'),height=node.getData('height'),algnPos=this.getAlignedPos(pos,width,height),x=algnPos.x,y=algnPos.y,dimArray=node.getData('dimArray'),valueArray=node.getData('valueArray'),valuelabelArray=node.getData('valuelabelArray'),linkArray=node.getData('linkArray'),valueLength=valueArray.length,colorArray=node.getData('colorArray'),colorLength=colorArray.length,stringArray=node.getData('stringArray');var ctx=canvas.getCtx(),canvasSize=canvas.getSize(),opt={},border=node.getData('border'),gradient=node.getData('gradient'),config=node.getData('config'),horz=config.orientation=='horizontal',aggregates=config.showAggregates,showLabels=config.showLabels,label=config.Label,shadow=config.shadow,margin=config.Margin,fixedDim=(horz?height:width)/valueLength;maxValue=Math.max.apply(null,dimArray);ctx.fillStyle="rgba(0,0,0,.2)";if(colorArray&&dimArray&&stringArray&&shadow.enable){shadowThickness=shadow.size;for(var i=0,l=valueLength,acum=0,valAcum=0;idimArray[i]){ctx.fillRect((x-shadowThickness)+fixedDim*i,y-dimArray[i]-shadowThickness,fixedDim,dimArray[i]+shadowThickness);}else if(nextBar&&nextBar0&&idimArray[i]){ctx.fillRect((x-((prevBar>0;}));linear.addColorStop(0,color);linear.addColorStop(0.3,colorArray[i%colorLength]);linear.addColorStop(0.7,colorArray[i%colorLength]);linear.addColorStop(1,color);ctx.fillStyle=linear;} +if(horz){ctx.fillRect(x,y+fixedDim*i,dimArray[i],fixedDim);}else{ctx.fillRect(x+fixedDim*i,y-dimArray[i],fixedDim,dimArray[i]);} +if(border&&border.name==stringArray[i]){opt.acum=fixedDim*i;opt.dimValue=dimArray[i];} +acum+=(dimArray[i]||0);valAcum+=(valueArray[i]||0);ctx.fillStyle=ctx.strokeStyle=label.color;ctx.font=label.style+' '+label.size+'px '+label.family;inset=10;if(aggregates(node.name,valAcum)&&label.type=='Native'){if(valuelabelArray[i]){acumValueLabel=valuelabelArray[i];}else{acumValueLabel=valueArray[i];} +if(horz){ctx.font=label.style+' '+label.size+'px '+label.family;ctx.textAlign='left';ctx.textBaseline='top';ctx.fillStyle="rgba(255,255,255,.8)";gridWidth=canvasSize.width-(margin.left+margin.right+config.labeloffset+label.size);mtxt=ctx.measureText(acumValueLabel);boxWidth=mtxt.width+10;if(boxWidth+dimArray[i]+config.labelOffset>gridWidth){leftPadding=dimArray[i]-config.labelOffset-boxWidth-inset;}else{leftPadding=dimArray[i]+config.labelOffset+inset;} +boxHeight=label.size+6;boxX=x+leftPadding;boxY=y+i*fixedDim+(fixedDim/2)-boxHeight/2;cornerRadius=4;if(boxWidth+dimArray[i]+config.labelOffset>gridWidth){$.roundedRect(ctx,boxX,boxY,boxWidth,boxHeight,cornerRadius,"fill");} +ctx.fillStyle=ctx.strokeStyle=label.color;ctx.fillText(acumValueLabel,x+inset/2+leftPadding,y+i*fixedDim+(fixedDim/2)-(label.size/2));}else{ctx.font=label.style+' '+label.size+'px '+label.family;ctx.save();ctx.textAlign='center';gridHeight=canvasSize.height-(margin.top+margin.bottom+(config.Title.text?config.Title.size+config.Title.offset:0)+ +(config.Subtitle.text?config.Subtitle.size+config.Subtitle.offset:0)+ +(label?label.size+config.labelOffset:0));mtxt=ctx.measureText(acumValueLabel);boxWidth=mtxt.width+10;boxHeight=label.size+6;if(boxHeight+dimArray[i]+config.labelOffset>gridHeight){bottomPadding=dimArray[i]-config.labelOffset-boxHeight-inset;}else{bottomPadding=dimArray[i]+config.labelOffset+inset;} +ctx.translate(x+(i*fixedDim)+(fixedDim/2),y-bottomPadding);boxX=-boxWidth/2;boxY=-boxHeight/2;ctx.fillStyle="rgba(255,255,255,.8)";cornerRadius=4;if(boxHeight+dimArray[i]+config.labelOffset>gridHeight){$.roundedRect(ctx,boxX,boxY,boxWidth,boxHeight,cornerRadius,"fill");} +ctx.fillStyle=ctx.strokeStyle=label.color;ctx.fillText(acumValueLabel,0,0);ctx.restore();}}} +if(border){ctx.save();ctx.lineWidth=2;ctx.strokeStyle=border.color;if(horz){ctx.strokeRect(x+1,y+opt.acum+1,opt.dimValue-2,fixedDim-2);}else{ctx.strokeRect(x+opt.acum+1,y-opt.dimValue+1,fixedDim-2,opt.dimValue-2);} +ctx.restore();} +if(label.type=='Native'){ctx.save();ctx.fillStyle=ctx.strokeStyle=label.color;ctx.font=label.style+' '+label.size+'px '+label.family;ctx.textBaseline='middle';if(showLabels(node.name,valAcum,node)){if(horz){ctx.textAlign='center';ctx.translate(x-config.labelOffset-label.size/2,y+height/2);ctx.rotate(Math.PI/2);ctx.fillText(node.name,0,0);}else{ctx.textAlign='center';ctx.fillText(node.name,x+width/2,y+label.size/2+config.labelOffset);}} +ctx.restore();}}},'contains':function(node,mpos){var pos=node.pos.getc(true),width=node.getData('width'),height=node.getData('height'),algnPos=this.getAlignedPos(pos,width,height),x=algnPos.x,y=algnPos.y,dimArray=node.getData('dimArray'),len=dimArray.length,config=node.getData('config'),rx=mpos.x-x,horz=config.orientation=='horizontal',fixedDim=(horz?height:width)/len;if(horz){if(mpos.xx+width||mpos.y>y+height||mpos.yx+width||mpos.y>y||mpos.y=limit&&mpos.y<=limit+fixedDim){return{'name':node.getData('stringArray')[i],'color':node.getData('colorArray')[i],'value':node.getData('valueArray')[i],'valuelabel':node.getData('valuelabelArray')[i],'title':node.getData('titleArray')[i],'percentage':((node.getData('valueArray')[i]/node.getData('barTotalValue'))*100).toFixed(1),'link':url,'label':node.name};}}else{var limit=x+fixedDim*i;if(mpos.x>=limit&&mpos.x<=limit+fixedDim&&mpos.y>=y-dimi){return{'name':node.getData('stringArray')[i],'color':node.getData('colorArray')[i],'value':node.getData('valueArray')[i],'valuelabel':node.getData('valuelabelArray')[i],'title':node.getData('titleArray')[i],'percentage':((node.getData('valueArray')[i]/node.getData('barTotalValue'))*100).toFixed(1),'link':url,'label':node.name};}}} +return false;}},'barchart-basic':{'render':function(node,canvas){var pos=node.pos.getc(true),width=node.getData('width'),height=node.getData('height'),algnPos=this.getAlignedPos(pos,width,height),x=algnPos.x,y=algnPos.y,dimArray=node.getData('dimArray'),valueArray=node.getData('valueArray'),valuelabelArray=node.getData('valuelabelArray'),linkArray=node.getData('linkArray'),valueLength=valueArray.length,colorArray=node.getData('colorMono'),colorLength=colorArray.length,stringArray=node.getData('stringArray');var ctx=canvas.getCtx(),canvasSize=canvas.getSize(),opt={},border=node.getData('border'),gradient=node.getData('gradient'),config=node.getData('config'),horz=config.orientation=='horizontal',aggregates=config.showAggregates,showLabels=config.showLabels,label=config.Label,fixedDim=(horz?height:width)/valueLength,margin=config.Margin;if(colorArray&&dimArray&&stringArray){for(var i=0,l=valueLength,acum=0,valAcum=0;i>0;}));linear.addColorStop(0,color);linear.addColorStop(0.3,colorArray[i%colorLength]);linear.addColorStop(0.7,colorArray[i%colorLength]);linear.addColorStop(1,color);ctx.fillStyle=linear;} +if(horz){ctx.fillRect(x,y+fixedDim*i,dimArray[i],fixedDim);}else{ctx.fillRect(x+fixedDim*i,y-dimArray[i],fixedDim,dimArray[i]);} +if(border&&border.name==stringArray[i]){opt.acum=fixedDim*i;opt.dimValue=dimArray[i];} +acum+=(dimArray[i]||0);valAcum+=(valueArray[i]||0);if(label.type=='Native'){ctx.fillStyle=ctx.strokeStyle=label.color;ctx.font=label.style+' '+label.size+'px '+label.family;if(aggregates(node.name,valAcum)){if(valuelabelArray[i]){acumValueLabel=valuelabelArray[i];}else{acumValueLabel=valueArray[i];} +if(!horz){ctx.textAlign='center';ctx.font=label.style+' '+label.size+'px '+label.family;ctx.save();gridHeight=canvasSize.height-(margin.top+margin.bottom+(config.Title.text?config.Title.size+config.Title.offset:0)+ +(config.Subtitle.text?config.Subtitle.size+config.Subtitle.offset:0)+ +(label?label.size+config.labelOffset:0));mtxt=ctx.measureText(acumValueLabel);boxWidth=mtxt.width+10;inset=10;boxHeight=label.size+6;if(boxHeight+dimArray[i]+config.labelOffset>gridHeight){bottomPadding=dimArray[i]-config.labelOffset-inset;}else{bottomPadding=dimArray[i]+config.labelOffset+inset;} +ctx.translate(x+width/2-(mtxt.width/2),y-bottomPadding);cornerRadius=4;boxX=-inset/2;boxY=-boxHeight/2;ctx.fillStyle="rgba(255,255,255,.6)";if(boxHeight+dimArray[i]+config.labelOffset>gridHeight){$.roundedRect(ctx,boxX,boxY,boxWidth,boxHeight,cornerRadius,"fill");} +ctx.fillStyle=ctx.strokeStyle=label.color;ctx.fillText(acumValueLabel,mtxt.width/2,0);ctx.restore();}}}} +if(border){ctx.save();ctx.lineWidth=2;ctx.strokeStyle=border.color;if(horz){ctx.strokeRect(x+1,y+opt.acum+1,opt.dimValue-2,fixedDim-2);}else{ctx.strokeRect(x+opt.acum+1,y-opt.dimValue+1,fixedDim-2,opt.dimValue-2);} +ctx.restore();} +if(label.type=='Native'){ctx.save();ctx.fillStyle=ctx.strokeStyle=label.color;ctx.font=label.style+' '+label.size+'px '+label.family;ctx.textBaseline='middle';if(showLabels(node.name,valAcum,node)){if(horz){gridWidth=canvasSize.width-(config.Margin.left+config.Margin.right);mtxt=ctx.measureText(node.name+": "+valAcum);boxWidth=mtxt.width+10;inset=10;if(acum+boxWidth+config.labelOffset+inset>gridWidth){leftPadding=acum-config.labelOffset-boxWidth-inset;}else{leftPadding=acum+config.labelOffset;} +ctx.textAlign='left';ctx.translate(x+inset+leftPadding,y+height/2);boxHeight=label.size+6;boxX=-inset/2;boxY=-boxHeight/2;ctx.fillStyle="rgba(255,255,255,.8)";cornerRadius=4;if(acum+boxWidth+config.labelOffset+inset>gridWidth){$.roundedRect(ctx,boxX,boxY,boxWidth,boxHeight,cornerRadius,"fill");} +ctx.fillStyle=label.color;ctx.fillText(node.name+": "+valAcum,0,0);}else{if(stringArray.length>8){ctx.textAlign='left';ctx.translate(x+width/2,y+label.size/2+config.labelOffset);ctx.rotate(45*Math.PI/180);ctx.fillText(node.name,0,0);}else{ctx.textAlign='center';ctx.fillText(node.name,x+width/2,y+label.size/2+config.labelOffset);}}} +ctx.restore();}}},'contains':function(node,mpos){var pos=node.pos.getc(true),width=node.getData('width'),height=node.getData('height'),config=node.getData('config'),algnPos=this.getAlignedPos(pos,width,height),x=algnPos.x,y=algnPos.y,dimArray=node.getData('dimArray'),len=dimArray.length,rx=mpos.x-x,horz=config.orientation=='horizontal',fixedDim=(horz?height:width)/len;if(horz){if(mpos.xx+width||mpos.y>y+height||mpos.yx+width||mpos.y>y||mpos.y=limit&&mpos.y<=limit+fixedDim){return{'name':node.getData('stringArray')[i],'color':node.getData('colorArray')[i],'value':node.getData('valueArray')[i],'valuelabel':node.getData('valuelabelArray')[i],'percentage':((node.getData('valueArray')[i]/node.getData('groupTotalValue'))*100).toFixed(1),'link':url,'label':node.name};}}else{var limit=x+fixedDim*i;if(mpos.x>=limit&&mpos.x<=limit+fixedDim&&mpos.y>=y-dimi){return{'name':node.getData('stringArray')[i],'color':node.getData('colorArray')[i],'value':node.getData('valueArray')[i],'valuelabel':node.getData('valuelabelArray')[i],'percentage':((node.getData('valueArray')[i]/node.getData('groupTotalValue'))*100).toFixed(1),'link':url,'label':node.name};}}} +return false;}}});$jit.BarChart=new Class({st:null,colors:["#004b9c","#9c0079","#9c0033","#28009c","#9c0000","#7d009c","#001a9c","#00809c","#009c80","#009c42","#009c07","#469c00","#799c00","#9c9600","#9c5c00"],selected:{},busy:false,initialize:function(opt){this.controller=this.config=$.merge(Options("Canvas","Margin","Label","BarChart"),{Label:{type:'Native'}},opt);var showLabels=this.config.showLabels,typeLabels=$.type(showLabels),showAggregates=this.config.showAggregates,typeAggregates=$.type(showAggregates);this.config.showLabels=typeLabels=='function'?showLabels:$.lambda(showLabels);this.config.showAggregates=typeAggregates=='function'?showAggregates:$.lambda(showAggregates);Options.Fx.clearCanvas=false;this.initializeViz();},initializeViz:function(){var config=this.config,that=this;var nodeType=config.type.split(":")[0],horz=config.orientation=='horizontal',nodeLabels={};var st=new $jit.ST({injectInto:config.injectInto,orientation:horz?'left':'bottom',background:config.background,renderBackground:config.renderBackground,backgroundColor:config.backgroundColor,colorStop1:config.colorStop1,colorStop2:config.colorStop2,levelDistance:0,nodeCount:config.nodeCount,siblingOffset:config.barsOffset,subtreeOffset:0,withLabels:config.Label.type!='Native',useCanvas:config.useCanvas,Label:{type:config.Label.type},Node:{overridable:true,type:'barchart-'+nodeType,align:'left',width:1,height:1},Edge:{type:'none'},Tips:{enable:config.Tips.enable,type:'Native',force:true,onShow:function(tip,node,contains){var elem=contains;config.Tips.onShow(tip,elem,node);if(elem.link!='undefined'&&elem.link!=''){document.body.style.cursor='pointer';}},onHide:function(call){document.body.style.cursor='default';}},Events:{enable:true,type:'Native',onClick:function(node,eventInfo,evt){if(!config.Events.enable)return;var elem=eventInfo.getContains();config.Events.onClick(elem,eventInfo,evt);},onMouseMove:function(node,eventInfo,evt){if(!config.hoveredColor)return;if(node){var elem=eventInfo.getContains();that.select(node.id,elem.name,elem.index);}else{that.select(false,false,false);}}},onCreateLabel:function(domElement,node){var labelConf=config.Label,valueArray=node.getData('valueArray'),acum=$.reduce(valueArray,function(x,y){return x+y;},0),grouped=config.type.split(':')[0]=='grouped',horz=config.orientation=='horizontal';var nlbs={wrapper:document.createElement('div'),aggregate:document.createElement('div'),label:document.createElement('div')};var wrapper=nlbs.wrapper,label=nlbs.label,aggregate=nlbs.aggregate,wrapperStyle=wrapper.style,labelStyle=label.style,aggregateStyle=aggregate.style;nodeLabels[node.id]=nlbs;wrapper.appendChild(label);wrapper.appendChild(aggregate);if(!config.showLabels(node.name,acum,node)){labelStyle.display='none';} +if(!config.showAggregates(node.name,acum,node)){aggregateStyle.display='none';} +wrapperStyle.position='relative';wrapperStyle.overflow='visible';wrapperStyle.fontSize=labelConf.size+'px';wrapperStyle.fontFamily=labelConf.family;wrapperStyle.color=labelConf.color;wrapperStyle.textAlign='center';aggregateStyle.position=labelStyle.position='absolute';domElement.style.width=node.getData('width')+'px';domElement.style.height=node.getData('height')+'px';aggregateStyle.left="0px";labelStyle.left=config.labelOffset+'px';labelStyle.whiteSpace="nowrap";label.innerHTML=node.name;domElement.appendChild(wrapper);},onPlaceLabel:function(domElement,node){if(!nodeLabels[node.id])return;var labels=nodeLabels[node.id],wrapperStyle=labels.wrapper.style,labelStyle=labels.label.style,aggregateStyle=labels.aggregate.style,grouped=config.type.split(':')[0]=='grouped',horz=config.orientation=='horizontal',dimArray=node.getData('dimArray'),valArray=node.getData('valueArray'),nodeCount=node.getData('nodeCount'),valueLength=valArray.length;valuelabelArray=node.getData('valuelabelArray'),stringArray=node.getData('stringArray'),width=(grouped&&horz)?Math.max.apply(null,dimArray):node.getData('width'),height=(grouped&&!horz)?Math.max.apply(null,dimArray):node.getData('height'),font=parseInt(wrapperStyle.fontSize,10),domStyle=domElement.style,fixedDim=(horz?height:width)/valueLength;if(dimArray&&valArray){wrapperStyle.width=aggregateStyle.width=labelStyle.width=domElement.style.width=width+'px';aggregateStyle.width=width-config.labelOffset+"px";for(var i=0,l=valArray.length,acum=0;i0){acum+=valArray[i];}} +if(config.showLabels(node.name,acum,node)){labelStyle.display='';}else{labelStyle.display='none';} +if(config.showAggregates(node.name,acum,node)){aggregateStyle.display='';}else{aggregateStyle.display='none';} +if(config.orientation=='horizontal'){aggregateStyle.textAlign='right';labelStyle.textAlign='left';labelStyle.textIndex=aggregateStyle.textIndent=config.labelOffset+'px';aggregateStyle.top=labelStyle.top=(height-font)/2+'px';domElement.style.height=wrapperStyle.height=height+'px';}else{aggregateStyle.top=(-font-config.labelOffset)+'px';labelStyle.top=(config.labelOffset+height)+'px';domElement.style.top=parseInt(domElement.style.top,10)-height+'px';domElement.style.height=wrapperStyle.height=height+'px';if(stringArray.length>8){labels.label.className="rotatedLabelReverse";labelStyle.textAlign="left";labelStyle.top=config.labelOffset+height+width/2+"px";}} +if(horz){labels.label.innerHTML=labels.label.innerHTML+": "+acum;labels.aggregate.innerHTML="";}else{if(grouped){maxValue=Math.max.apply(null,dimArray);for(var i=0,l=valArray.length,acum=0,valAcum=0;i40)?40:fixedDim;whiteSpace=size.width-(marginWidth+(fixedDim*l));if(!grouped&&!horz){st.config.siblingOffset=whiteSpace/(l+1);} +if(horz){st.config.offsetX=size.width/2-margin.left-(grouped&&config.Label?config.labelOffset+config.Label.size:0);if(config.Ticks.enable){st.config.offsetY=((margin.bottom+config.Label.size+config.labelOffset+(subtitle.text?subtitle.size+subtitle.offset:0))-(margin.top+(title.text?title.size+title.offset:0)))/2;}else{st.config.offsetY=(margin.bottom-margin.top-(title.text?title.size+title.offset:0)-(subtitle.text?subtitle.size+subtitle.offset:0))/2;}}else{st.config.offsetY=-size.height/2+margin.bottom ++(config.showLabels&&(config.labelOffset+config.Label.size))+(subtitle.text?subtitle.size+subtitle.offset:0);if(config.Ticks.enable){st.config.offsetX=((margin.right-config.Label.size-config.labelOffset)-margin.left)/2;}else{st.config.offsetX=(margin.right-margin.left)/2;}} +this.st=st;this.canvas=this.st.canvas;},renderTitle:function(){var canvas=this.canvas,size=canvas.getSize(),config=this.config,margin=config.Margin,label=config.Label,title=config.Title;ctx=canvas.getCtx();ctx.fillStyle=title.color;ctx.textAlign='left';ctx.font=label.style+' bold '+' '+title.size+'px '+label.family;if(label.type=='Native'){ctx.fillText(title.text,-size.width/2+margin.left,-size.height/2+margin.top);}},renderSubtitle:function(){var canvas=this.canvas,size=canvas.getSize(),config=this.config,margin=config.Margin,label=config.Label,subtitle=config.Subtitle;ctx=canvas.getCtx();ctx.fillStyle=title.color;ctx.textAlign='left';ctx.font=label.style+' '+subtitle.size+'px '+label.family;if(label.type=='Native'){ctx.fillText(subtitle.text,-size.width/2+margin.left,size.height/2-margin.bottom-subtitle.size);}},renderScrollNote:function(){var canvas=this.canvas,size=canvas.getSize(),config=this.config,margin=config.Margin,label=config.Label,note=config.ScrollNote;ctx=canvas.getCtx();ctx.fillStyle=title.color;title=config.Title;ctx.textAlign='center';ctx.font=label.style+' bold '+' '+note.size+'px '+label.family;if(label.type=='Native'){ctx.fillText(note.text,0,-size.height/2+margin.top+title.size);}},renderTicks:function(){var canvas=this.canvas,size=canvas.getSize(),config=this.config,margin=config.Margin,ticks=config.Ticks,title=config.Title,subtitle=config.Subtitle,label=config.Label,shadow=config.shadow;horz=config.orientation=='horizontal',maxValue=this.getMaxValue(),maxTickValue=Math.ceil(maxValue*.1)*10;if(maxTickValue==maxValue){var length=maxTickValue.toString().length;maxTickValue=maxTickValue+parseInt(pad(1,length));} +grouped=config.type.split(':')[0]=='grouped',labelValue=0,labelIncrement=maxTickValue/ticks.segments,ctx=canvas.getCtx();ctx.strokeStyle=ticks.color;ctx.font=label.style+' '+label.size+'px '+label.family;ctx.textAlign='center';ctx.textBaseline='middle';idLabel=canvas.id+"-label";labelDim=100;container=document.getElementById(idLabel);if(horz){var axis=-(size.width/2)+margin.left+(grouped&&config.Label?config.labelOffset+label.size:0),grid=size.width-(margin.left+margin.right+(grouped&&config.Label?config.labelOffset+label.size:0)),segmentLength=grid/ticks.segments;ctx.fillStyle=ticks.color;ctx.fillRect(axis,(size.height/2)-margin.bottom-config.labelOffset-label.size-(subtitle.text?subtitle.size+subtitle.offset:0)+(shadow.enable?shadow.size:0),size.width-margin.left-margin.right-(grouped&&config.Label?config.labelOffset+label.size:0),1);while(axis<=grid){ctx.fillStyle=ticks.color;lineHeight=size.height-margin.bottom-margin.top-config.labelOffset-label.size-(title.text?title.size+title.offset:0)-(subtitle.text?subtitle.size+subtitle.offset:0);ctx.fillRect(Math.round(axis),-(size.height/2)+margin.top+(title.text?title.size+title.offset:0)-(shadow.enable?shadow.size:0),1,lineHeight+(shadow.enable?shadow.size*2:0));ctx.fillStyle=label.color;if(label.type=='Native'&&config.showLabels){ctx.fillText(labelValue,Math.round(axis),-(size.height/2)+margin.top+(title.text?title.size+title.offset:0)+config.labelOffset+lineHeight+label.size);} +axis+=segmentLength;labelValue+=labelIncrement;}}else{var axis=(size.height/2)-(margin.bottom+config.labelOffset+label.size+(subtitle.text?subtitle.size+subtitle.offset:0)),htmlOrigin=size.height-(margin.bottom+config.labelOffset+label.size+(subtitle.text?subtitle.size+subtitle.offset:0)),grid=-size.height+(margin.bottom+config.labelOffset+label.size+margin.top+(title.text?title.size+title.offset:0)+(subtitle.text?subtitle.size+subtitle.offset:0)),segmentLength=grid/ticks.segments;ctx.fillStyle=ticks.color;ctx.fillRect(-(size.width/2)+margin.left+config.labelOffset+label.size-1,-(size.height/2)+margin.top+(title.text?title.size+title.offset:0),1,size.height-margin.top-margin.bottom-label.size-config.labelOffset-(title.text?title.size+title.offset:0)-(subtitle.text?subtitle.size+subtitle.offset:0));while(axis>=grid){ctx.save();ctx.translate(-(size.width/2)+margin.left,Math.round(axis));ctx.rotate(0*Math.PI/180);ctx.fillStyle=label.color;if(config.showLabels){if(label.type=='Native'){ctx.fillText(labelValue,0,0);}else{labelDiv=document.createElement('div');labelDiv.innerHTML=labelValue;labelDiv.className="rotatedLabel";labelDiv.style.top=(htmlOrigin-(labelDim/2))+"px";labelDiv.style.left=margin.left+"px";labelDiv.style.width=labelDim+"px";labelDiv.style.height=labelDim+"px";labelDiv.style.textAlign="center";labelDiv.style.verticalAlign="middle";labelDiv.style.position="absolute";container.appendChild(labelDiv);}} +ctx.restore();ctx.fillStyle=ticks.color;ctx.fillRect(-(size.width/2)+margin.left+config.labelOffset+label.size,Math.round(axis),size.width-margin.right-margin.left-config.labelOffset-label.size,1);htmlOrigin+=segmentLength;axis+=segmentLength;labelValue+=labelIncrement;}}},renderBackground:function(){var canvas=this.canvas,config=this.config,backgroundColor=config.backgroundColor,size=canvas.getSize(),ctx=canvas.getCtx();ctx.fillStyle=backgroundColor;ctx.fillRect(-size.width/2,-size.height/2,size.width,size.height);},loadJSON:function(json){if(this.busy)return;this.busy=true;var prefix=$.time(),ch=[],st=this.st,name=$.splat(json.label),color=$.splat(json.color||this.colors),config=this.config,gradient=!!config.type.split(":")[1],renderBackground=config.renderBackground,animate=config.animate,ticks=config.Ticks,title=config.Title,note=config.ScrollNote,subtitle=config.Subtitle,horz=config.orientation=='horizontal',that=this,colorLength=color.length,nameLength=name.length;groupTotalValue=0;for(var i=0,values=json.values,l=values.length;iacum?maxValue:acum;});return maxValue;},setBarType:function(type){this.config.type=type;this.st.config.Node.type='barchart-'+type.split(':')[0];},normalizeDims:function(){var root=this.st.graph.getNode(this.st.root),l=0;root.eachAdjacency(function(){l++;});var maxValue=this.getMaxValue()||1,size=this.st.canvas.getSize(),config=this.config,margin=config.Margin,ticks=config.Ticks,title=config.Title,subtitle=config.Subtitle,grouped=config.type.split(':')[0]=='grouped',marginWidth=margin.left+margin.right+(config.Label&&grouped?config.Label.size+config.labelOffset:0),marginHeight=(title.text?title.size+title.offset:0)+(subtitle.text?subtitle.size+subtitle.offset:0)+margin.top+margin.bottom,horz=config.orientation=='horizontal',fixedDim=(size[horz?'height':'width']-(horz?marginHeight:marginWidth)-(ticks.enable?config.Label.size+config.labelOffset:0)-(l-1)*config.barsOffset)/l,animate=config.animate,height=size[horz?'width':'height']-(horz?marginWidth:marginHeight) +-((config.showLabels&&!horz)?(config.Label.size+config.labelOffset):0),dim1=horz?'height':'width',dim2=horz?'width':'height',basic=config.type.split(':')[0]=='basic';var maxTickValue=Math.ceil(maxValue*.1)*10;if(maxTickValue==maxValue){var length=maxTickValue.toString().length;maxTickValue=maxTickValue+parseInt(pad(1,length));} +fixedDim=fixedDim>40?40:fixedDim;this.st.graph.eachNode(function(n){var acum=0,animateValue=[];$.each(n.getData('valueArray'),function(v){acum+=+v;animateValue.push(0);});if(grouped){fixedDim=animateValue.length*40;} +n.setData(dim1,fixedDim);if(animate){n.setData(dim2,acum*height/maxValue,'end');n.setData('dimArray',$.map(n.getData('valueArray'),function(n){return n*height/maxValue;}),'end');var dimArray=n.getData('dimArray');if(!dimArray){n.setData('dimArray',animateValue);}}else{if(ticks.enable){n.setData(dim2,acum*height/maxTickValue);n.setData('dimArray',$.map(n.getData('valueArray'),function(n){return n*height/maxTickValue;}));}else{n.setData(dim2,acum*height/maxValue);n.setData('dimArray',$.map(n.getData('valueArray'),function(n){return n*height/maxValue;}));}}});}});Options.FunnelChart={$extend:true,animate:true,type:'stacked',labelOffset:3,barsOffset:0,hoveredColor:'#9fd4ff',orientation:'vertical',showAggregates:true,showLabels:true,Tips:{enable:false,onShow:$.empty,onHide:$.empty},Events:{enable:false,onClick:$.empty}};$jit.ST.Plot.NodeTypes.implement({'funnelchart-basic':{'render':function(node,canvas){var pos=node.pos.getc(true),width=node.getData('width'),height=node.getData('height'),algnPos=this.getAlignedPos(pos,width,height),x=algnPos.x,y=algnPos.y,dimArray=node.getData('dimArray'),valueArray=node.getData('valueArray'),valuelabelArray=node.getData('valuelabelArray'),linkArray=node.getData('linkArray'),colorArray=node.getData('colorArray'),colorLength=colorArray.length,stringArray=node.getData('stringArray');var ctx=canvas.getCtx(),opt={},border=node.getData('border'),gradient=node.getData('gradient'),config=node.getData('config'),horz=config.orientation=='horizontal',aggregates=config.showAggregates,showLabels=config.showLabels,label=config.Label,size=canvas.getSize(),labelOffset=config.labelOffset+10;minWidth=width*.25;ratio=.65;if(colorArray&&dimArray&&stringArray){for(var i=0,l=dimArray.length,acum=0,valAcum=0;i0)?dimArray[i-1]:100;var labelOffsetHeight=(previousElementHeight0)?((dimArray[i]>label.size)?(dimArray[i]/2)-(label.size/2):label.size):0;var topWidth=minWidth+((acum+dimArray[i])*ratio);var bottomWidth=minWidth+((acum)*ratio);var bottomWidthLabel=minWidth+((acum+labelOffsetHeight)*ratio);var labelOffsetRight=(previousElementHeight0)?((i%2!=0&&dimArray[i]0)?((i%2!=0&&dimArray[i]0)?dimArray[i-1]:100;var labelOffsetHeight=(previousElementHeight0)?((dimArray[i]>label.size)?(dimArray[i]/2)-(label.size/2):label.size):0;var labelOffsetRight=(previousElementHeight0)?((i%2!=0&&dimArray[i]0)?((i%2!=0&&dimArray[i]>0;});linear.addColorStop(0,'rgba('+color+',1)');linear.addColorStop(0.5,'rgba('+colorRgb+',1)');linear.addColorStop(1,'rgba('+color+',1)');ctx.fillStyle=linear;} +ctx.beginPath();ctx.moveTo(-topWidth/2,y-acum-dimArray[i]);ctx.lineTo(topWidth/2,y-acum-dimArray[i]);ctx.lineTo(bottomWidth/2,y-acum);ctx.lineTo(-bottomWidth/2,y-acum);ctx.closePath();ctx.fill();if(border&&border.name==stringArray[i]){opt.acum=acum;opt.dimValue=dimArray[i];} +if(border){ctx.save();ctx.lineWidth=2;ctx.strokeStyle=border.color;ctx.restore();} +if(label.type=='Native'){ctx.save();ctx.fillStyle=ctx.strokeStyle=label.color;ctx.font=label.style+' '+label.size+'px '+label.family;ctx.textBaseline='middle';acumValueLabel=valAcum;if(showLabels(node.name,valAcum,node)){ctx.textAlign='left';ctx.fillText(stringArray[i],(bottomWidthLabel/2)+labelOffset+labelOffsetRight,y-acum-labelOffsetHeight-label.size/2);ctx.textAlign='right';ctx.fillText(valuelabelArray[i],(-bottomWidthLabel/2)-labelOffset-labelOffsetLeft,y-acum-labelOffsetHeight-label.size/2);} +ctx.restore();} +acum+=(dimArray[i]||0);valAcum+=(valueArray[i]||0);}}},'contains':function(node,mpos){var pos=node.pos.getc(true),width=node.getData('width'),height=node.getData('height'),algnPos=this.getAlignedPos(pos,width,height),x=algnPos.x,y=algnPos.y,dimArray=node.getData('dimArray'),config=node.getData('config'),st=node.getData('st'),rx=mpos.x-x,horz=config.orientation=='horizontal',minWidth=width*.25;ratio=.65,canvas=node.getData('canvas'),size=canvas.getSize(),offsetY=st.config.offsetY;if(mpos.y>y||mpos.yboundRight){return false;} +for(var i=0,l=dimArray.length,acum=(horz?x:y);i=intersec){return{'name':node.getData('stringArray')[i],'color':node.getData('colorArray')[i],'value':node.getData('valueArray')[i],'percentage':node.getData('percentageArray')[i],'valuelabel':node.getData('valuelabelArray')[i],'link':url,'label':node.name};}} +return false;}}});$jit.FunnelChart=new Class({st:null,colors:["#004b9c","#9c0079","#9c0033","#28009c","#9c0000","#7d009c","#001a9c","#00809c","#009c80","#009c42","#009c07","#469c00","#799c00","#9c9600","#9c5c00"],selected:{},busy:false,initialize:function(opt){this.controller=this.config=$.merge(Options("Canvas","Margin","Label","BarChart"),{Label:{type:'Native'}},opt);var showLabels=this.config.showLabels,typeLabels=$.type(showLabels),showAggregates=this.config.showAggregates,typeAggregates=$.type(showAggregates);this.config.showLabels=typeLabels=='function'?showLabels:$.lambda(showLabels);this.config.showAggregates=typeAggregates=='function'?showAggregates:$.lambda(showAggregates);Options.Fx.clearCanvas=false;this.initializeViz();},initializeViz:function(){var config=this.config,that=this;var nodeType=config.type.split(":")[0],horz=config.orientation=='horizontal',nodeLabels={};var st=new $jit.ST({injectInto:config.injectInto,orientation:horz?'left':'bottom',levelDistance:0,background:config.background,renderBackground:config.renderBackground,backgroundColor:config.backgroundColor,colorStop1:config.colorStop1,colorStop2:config.colorStop2,siblingOffset:config.segmentOffset,subtreeOffset:0,withLabels:config.Label.type!='Native',useCanvas:config.useCanvas,Label:{type:config.Label.type},Node:{overridable:true,type:'funnelchart-'+nodeType,align:'left',width:1,height:1},Edge:{type:'none'},Tips:{enable:config.Tips.enable,type:'Native',force:true,onShow:function(tip,node,contains){var elem=contains;config.Tips.onShow(tip,elem,node);if(elem.link!='undefined'&&elem.link!=''){document.body.style.cursor='pointer';}},onHide:function(call){document.body.style.cursor='default';}},Events:{enable:true,type:'Native',onClick:function(node,eventInfo,evt){if(!config.Events.enable)return;var elem=eventInfo.getContains();config.Events.onClick(elem,eventInfo,evt);},onMouseMove:function(node,eventInfo,evt){if(!config.hoveredColor)return;if(node){var elem=eventInfo.getContains();that.select(node.id,elem.name,elem.index);}else{that.select(false,false,false);}}},onCreateLabel:function(domElement,node){var labelConf=config.Label,valueArray=node.getData('valueArray'),idArray=node.getData('idArray'),valuelabelArray=node.getData('valuelabelArray'),stringArray=node.getData('stringArray');size=st.canvas.getSize() +prefix=$.time();for(var i=0,l=valueArray.length;iacum?maxValue:acum;});return maxValue;},setBarType:function(type){this.config.type=type;this.st.config.Node.type='funnelchart-'+type.split(':')[0];},normalizeDims:function(){var root=this.st.graph.getNode(this.st.root),l=0;root.eachAdjacency(function(){l++;});var maxValue=this.getMaxValue()||1,size=this.st.canvas.getSize(),config=this.config,margin=config.Margin,title=config.Title,subtitle=config.Subtitle,marginWidth=margin.left+margin.right,marginHeight=(title.text?title.size+title.offset:0)+(subtitle.text?subtitle.size+subtitle.offset:0)+margin.top+margin.bottom,horz=config.orientation=='horizontal',animate=config.animate,height=size[horz?'width':'height']-(horz?marginWidth:marginHeight) +-(config.showLabels&&(config.Label.size+config.labelOffset)),dim1=horz?'height':'width',dim2=horz?'width':'height';minWidth=size.width/8;this.st.graph.eachNode(function(n){var acum=0,animateValue=[];$.each(n.getData('valueArray'),function(v){acum+=+v;animateValue.push(0);});n.setData(dim1,minWidth);if(animate){n.setData(dim2,acum*height/maxValue,'end');n.setData('dimArray',$.map(n.getData('valueArray'),function(n){return n*height/maxValue;}),'end');var dimArray=n.getData('dimArray');if(!dimArray){n.setData('dimArray',animateValue);}}else{n.setData(dim2,acum*height/maxValue);n.setData('dimArray',$.map(n.getData('valueArray'),function(n){return n*height/maxValue;}));}});}});Options.PieChart={$extend:true,animate:true,offset:25,sliceOffset:0,labelOffset:3,type:'stacked',labelType:'name',hoveredColor:'#9fd4ff',Events:{enable:false,onClick:$.empty},Tips:{enable:false,onShow:$.empty,onHide:$.empty},showLabels:true,resizeLabels:false,updateHeights:false};Layouts.Radial=new Class({compute:function(property){var prop=$.splat(property||['current','start','end']);NodeDim.compute(this.graph,prop,this.config);this.graph.computeLevels(this.root,0,"ignore");var lengthFunc=this.createLevelDistanceFunc();this.computeAngularWidths(prop);this.computePositions(prop,lengthFunc);},computePositions:function(property,getLength){var propArray=property;var graph=this.graph;var root=graph.getNode(this.root);var parent=this.parent;var config=this.config;for(var i=0,l=propArray.length;imaxDim[pi]?dim:maxDim[pi]):dim;} +subnodes.push(sib);},"ignore");if(parent&&parent.id==elem.id&&subnodes.length>0&&subnodes[0].dist){subnodes.sort(function(a,b){return(a.dist>=b.dist)-(a.dist<=b.dist);});} +for(var k=0,ls=subnodes.length;kpi/2&&p.theta<3*pi/2);var thetap=cond?p.theta+pi:p.theta;if(cond){x-=Math.abs(Math.cos(p.theta)*measure.width);y+=Math.sin(p.theta)*measure.width;}else if(node.id==this.viz.root){x-=measure.width/2;}} +ctx.save();ctx.translate(x,y);ctx.rotate(thetap);ctx.fillText(node.name,0,0);ctx.restore();}});Sunburst.Label.SVG=new Class({Implements:Graph.Label.SVG,initialize:function(viz){this.viz=viz;},placeLabel:function(tag,node,controller){var pos=node.pos.getc(true),viz=this.viz,canvas=this.viz.canvas;var radius=canvas.getSize();var labelPos={x:Math.round(pos.x+radius.width/2),y:Math.round(pos.y+radius.height/2)};tag.setAttribute('x',labelPos.x);tag.setAttribute('y',labelPos.y);var bb=tag.getBBox();if(bb){var x=tag.getAttribute('x');var y=tag.getAttribute('y');var p=node.pos.getp(true);var pi=Math.PI;var cond=(p.theta>pi/2&&p.theta<3*pi/2);if(cond){tag.setAttribute('x',x-bb.width);tag.setAttribute('y',y-bb.height);}else if(node.id==viz.root){tag.setAttribute('x',x-bb.width/2);} +var thetap=cond?p.theta+pi:p.theta;if(node._depth) +tag.setAttribute('transform','rotate('+thetap*360/(2*pi)+' '+x ++' '+y+')');} +controller.onPlaceLabel(tag,node);}});Sunburst.Label.HTML=new Class({Implements:Graph.Label.HTML,initialize:function(viz){this.viz=viz;},placeLabel:function(tag,node,controller){var pos=node.pos.clone(),canvas=this.viz.canvas,height=node.getData('height'),ldist=((height||node._depth==0)?height:this.viz.config.levelDistance)/2,radius=canvas.getSize();pos.rho+=ldist;pos=pos.getc(true);var labelPos={x:Math.round(pos.x+radius.width/2),y:Math.round(pos.y+radius.height/2)};var style=tag.style;style.left=labelPos.x+'px';style.top=labelPos.y+'px';style.display=this.fitsInCanvas(labelPos,canvas)?'':'none';controller.onPlaceLabel(tag,node);}});Sunburst.Plot.NodeTypes=new Class({'none':{'render':$.empty,'contains':$.lambda(false),'anglecontains':function(node,pos){var span=node.getData('span')/2,theta=node.pos.theta;var begin=theta-span,end=theta+span;if(begin<0) +begin+=Math.PI*2;var atan=Math.atan2(pos.y,pos.x);if(atan<0) +atan+=Math.PI*2;if(begin>end){return(atan>begin&&atan<=Math.PI*2)||atanbegin&&atanend){return(atan>begin&&atan<=Math.PI*2)||atanbegin&&atan=ld*d)&&(rho<=(ld*d+ldist));} +return false;}},'gradient-multipie':{'render':function(node,canvas){var ctx=canvas.getCtx();var height=node.getData('height');var ldist=height?height:this.config.levelDistance;var radialGradient=ctx.createRadialGradient(0,0,node.getPos().rho,0,0,node.getPos().rho+ldist);var colorArray=$.hexToRgb(node.getData('color')),ans=[];$.each(colorArray,function(i){ans.push(parseInt(i*0.5,10));});var endColor=$.rgbToHex(ans);radialGradient.addColorStop(0,endColor);radialGradient.addColorStop(1,node.getData('color'));ctx.fillStyle=radialGradient;this.nodeTypes['multipie'].render.call(this,node,canvas);},'contains':function(node,pos){return this.nodeTypes['multipie'].contains.call(this,node,pos);}},'gradient-pie':{'render':function(node,canvas){var ctx=canvas.getCtx();var radialGradient=ctx.createRadialGradient(0,0,0,0,0,node.getPos().rho);var colorArray=$.hexToRgb(node.getData('color')),ans=[];$.each(colorArray,function(i){ans.push(parseInt(i*0.5,10));});var endColor=$.rgbToHex(ans);radialGradient.addColorStop(1,endColor);radialGradient.addColorStop(0,node.getData('color'));ctx.fillStyle=radialGradient;this.nodeTypes['pie'].render.call(this,node,canvas);},'contains':function(node,pos){return this.nodeTypes['pie'].contains.call(this,node,pos);}}});Sunburst.Plot.EdgeTypes=new Class({'none':$.empty,'line':{'render':function(adj,canvas){var from=adj.nodeFrom.pos.getc(true),to=adj.nodeTo.pos.getc(true);this.edgeHelper.line.render(from,to,canvas);},'contains':function(adj,pos){var from=adj.nodeFrom.pos.getc(true),to=adj.nodeTo.pos.getc(true);return this.edgeHelper.line.contains(from,to,pos,this.edge.epsilon);}},'arrow':{'render':function(adj,canvas){var from=adj.nodeFrom.pos.getc(true),to=adj.nodeTo.pos.getc(true),dim=adj.getData('dim'),direction=adj.data.$direction,inv=(direction&&direction.length>1&&direction[0]!=adj.nodeFrom.id);this.edgeHelper.arrow.render(from,to,dim,inv,canvas);},'contains':function(adj,pos){var from=adj.nodeFrom.pos.getc(true),to=adj.nodeTo.pos.getc(true);return this.edgeHelper.arrow.contains(from,to,pos,this.edge.epsilon);}},'hyperline':{'render':function(adj,canvas){var from=adj.nodeFrom.pos.getc(),to=adj.nodeTo.pos.getc(),dim=Math.max(from.norm(),to.norm());this.edgeHelper.hyperline.render(from.$scale(1/dim),to.$scale(1/dim),dim,canvas);},'contains':$.lambda(false)}});})($jit.Sunburst);$jit.Sunburst.Plot.NodeTypes.implement({'piechart-stacked':{'render':function(node,canvas){var pos=node.pos.getp(true),dimArray=node.getData('dimArray'),valueArray=node.getData('valueArray'),colorArray=node.getData('colorArray'),colorLength=colorArray.length,stringArray=node.getData('stringArray'),span=node.getData('span')/2,theta=node.pos.theta,begin=theta-span,end=theta+span,polar=new Polar;var ctx=canvas.getCtx(),opt={},gradient=node.getData('gradient'),border=node.getData('border'),config=node.getData('config'),showLabels=config.showLabels,resizeLabels=config.resizeLabels,label=config.Label;var xpos=config.sliceOffset*Math.cos((begin+end)/2);var ypos=config.sliceOffset*Math.sin((begin+end)/2);if(colorArray&&dimArray&&stringArray){for(var i=0,l=dimArray.length,acum=0,valAcum=0;i>0;}),endColor=$.rgbToHex(ans);radialGradient.addColorStop(0,colori);radialGradient.addColorStop(0.5,colori);radialGradient.addColorStop(1,endColor);ctx.fillStyle=radialGradient;} +polar.rho=acum+config.sliceOffset;polar.theta=begin;var p1coord=polar.getc(true);polar.theta=end;var p2coord=polar.getc(true);polar.rho+=dimi;var p3coord=polar.getc(true);polar.theta=begin;var p4coord=polar.getc(true);ctx.beginPath();ctx.arc(xpos,ypos,acum+.01,begin,end,false);ctx.arc(xpos,ypos,acum+dimi+.01,end,begin,true);ctx.fill();if(border&&border.name==stringArray[i]){opt.acum=acum;opt.dimValue=dimArray[i];opt.begin=begin;opt.end=end;} +acum+=(dimi||0);valAcum+=(valueArray[i]||0);} +if(border){ctx.save();ctx.globalCompositeOperation="source-over";ctx.lineWidth=2;ctx.strokeStyle=border.color;var s=begin>0;fontSize=fontSize<+resizeLabels?+resizeLabels:fontSize;ctx.font=label.style+' '+fontSize+'px '+label.family;ctx.textBaseline='middle';ctx.textAlign='center';polar.rho=acum+config.labelOffset+config.sliceOffset;polar.theta=node.pos.theta;var cart=polar.getc(true);ctx.fillText(node.name,cart.x,cart.y);ctx.restore();}}},'contains':function(node,pos){if(this.nodeTypes['none'].anglecontains.call(this,node,pos)){var rho=Math.sqrt(pos.x*pos.x+pos.y*pos.y);var ld=this.config.levelDistance,d=node._depth;var config=node.getData('config');if(rho<=ld*d+config.sliceOffset){var dimArray=node.getData('dimArray');for(var i=0,l=dimArray.length,acum=config.sliceOffset;i=acum&&rho<=acum+dimi){return{name:node.getData('stringArray')[i],color:node.getData('colorArray')[i],value:node.getData('valueArray')[i],label:node.name};} +acum+=dimi;}} +return false;} +return false;}},'piechart-basic':{'render':function(node,canvas){var pos=node.pos.getp(true),dimArray=node.getData('dimArray'),valueArray=node.getData('valueArray'),colorArray=node.getData('colorMono'),colorLength=colorArray.length,stringArray=node.getData('stringArray'),percentage=node.getData('percentage'),span=node.getData('span')/2,theta=node.pos.theta,begin=theta-span,end=theta+span,polar=new Polar;var ctx=canvas.getCtx(),opt={},gradient=node.getData('gradient'),border=node.getData('border'),config=node.getData('config'),showLabels=config.showLabels,resizeLabels=config.resizeLabels,label=config.Label;var xpos=config.sliceOffset*Math.cos((begin+end)/2);var ypos=config.sliceOffset*Math.sin((begin+end)/2);if(colorArray&&dimArray&&stringArray){for(var i=0,l=dimArray.length,acum=0,valAcum=0;i>0;}),endColor2=$.map(colorRgb,function(i){return(i*0.7)>>0;});radialGradient.addColorStop(0,'rgba('+colorRgb+',1)');radialGradient.addColorStop(.7,'rgba('+colorRgb+',1)');radialGradient.addColorStop(.98,'rgba('+endColor+',1)');radialGradient.addColorStop(1,'rgba('+endColor2+',1)');ctx.fillStyle=radialGradient;}} +ctx.beginPath();ctx.arc(xpos,ypos,acum+.01,begin,end,false);ctx.arc(xpos,ypos,acum+dimi+.01,end,begin,true);ctx.fill();if(border&&border.name==stringArray[i]){opt.acum=acum;opt.dimValue=dimArray[i];opt.begin=begin;opt.end=end;opt.sliceValue=valueArray[i];} +acum+=(dimi||0);valAcum+=(valueArray[i]||0);} +if(border){ctx.save();ctx.globalCompositeOperation="source-over";ctx.lineWidth=2;ctx.strokeStyle=border.color;var s=begin>0;fontSize=fontSize<+resizeLabels?+resizeLabels:fontSize;ctx.font=label.style+' '+fontSize+'px '+label.family;ctx.textBaseline='middle';ctx.textAlign='center';pi=Math.PI;angle=theta*360/(2*pi);polar.rho=acum+config.labelOffset+config.sliceOffset;polar.theta=node.pos.theta;var cart=polar.getc(true);if(((angle>=225&&angle<=315)||(angle<=135&&angle>=45))&&percentage<=5){}else{if(config.labelType=='name'){ctx.fillText(node.name,cart.x,cart.y);}else{ctx.fillText(node.data.valuelabel,cart.x,cart.y);}} +ctx.restore();}}},'contains':function(node,pos){if(this.nodeTypes['none'].anglecontains.call(this,node,pos)){var rho=Math.sqrt(pos.x*pos.x+pos.y*pos.y);var ld=this.config.levelDistance,d=node._depth;var config=node.getData('config');if(rho<=ld*d+config.sliceOffset){var dimArray=node.getData('dimArray');for(var i=0,l=dimArray.length,acum=config.sliceOffset;i=acum&&rho<=acum+dimi){var url=Url.decode(node.getData('linkArray')[i]);return{name:node.getData('stringArray')[i],link:url,color:node.getData('colorArray')[i],value:node.getData('valueArray')[i],percentage:node.getData('percentage'),valuelabel:node.getData('valuelabelsArray')[i],label:node.name};} +acum+=dimi;}} +return false;} +return false;}}});$jit.PieChart=new Class({sb:null,colors:["#416D9C","#70A35E","#EBB056","#C74243","#83548B","#909291","#557EAA"],selected:{},busy:false,initialize:function(opt){this.controller=this.config=$.merge(Options("Canvas","PieChart","Label"),{Label:{type:'Native'}},opt);this.initializeViz();},initializeViz:function(){var config=this.config,that=this;var nodeType=config.type.split(":")[0];var sb=new $jit.Sunburst({injectInto:config.injectInto,useCanvas:config.useCanvas,withLabels:config.Label.type!='Native',background:config.background,renderBackground:config.renderBackground,backgroundColor:config.backgroundColor,colorStop1:config.colorStop1,colorStop2:config.colorStop2,Label:{type:config.Label.type},Node:{overridable:true,type:'piechart-'+nodeType,width:1,height:1},Edge:{type:'none'},Tips:{enable:config.Tips.enable,type:'Native',force:true,onShow:function(tip,node,contains){var elem=contains;config.Tips.onShow(tip,elem,node);if(elem.link!='undefined'&&elem.link!=''){document.body.style.cursor='pointer';}},onHide:function(){document.body.style.cursor='default';}},Events:{enable:true,type:'Native',onClick:function(node,eventInfo,evt){if(!config.Events.enable)return;var elem=eventInfo.getContains();config.Events.onClick(elem,eventInfo,evt);},onMouseMove:function(node,eventInfo,evt){if(!config.hoveredColor)return;if(node){var elem=eventInfo.getContains();that.select(node.id,elem.name,elem.index);}else{that.select(false,false,false);}}},onCreateLabel:function(domElement,node){var labelConf=config.Label;if(config.showLabels){var style=domElement.style;style.fontSize=labelConf.size+'px';style.fontFamily=labelConf.family;style.color=labelConf.color;style.textAlign='center';if(config.labelType=='name'){domElement.innerHTML=node.name;}else{domElement.innerHTML=(node.data.valuelabel!=undefined)?node.data.valuelabel:"";} +domElement.style.width='400px';}},onPlaceLabel:function(domElement,node){if(!config.showLabels)return;var pos=node.pos.getp(true),dimArray=node.getData('dimArray'),span=node.getData('span')/2,theta=node.pos.theta,begin=theta-span,end=theta+span,polar=new Polar;var showLabels=config.showLabels,resizeLabels=config.resizeLabels,label=config.Label;if(dimArray){for(var i=0,l=dimArray.length,acum=0;i>0;fontSize=fontSize<+resizeLabels?+resizeLabels:fontSize;domElement.style.fontSize=fontSize+'px';polar.rho=acum+config.labelOffset+config.sliceOffset;polar.theta=(begin+end)/2;var pos=polar.getc(true);var radius=that.canvas.getSize();var labelPos={x:Math.round(pos.x+radius.width/2),y:Math.round(pos.y+radius.height/2)};domElement.style.left=(labelPos.x-200)+'px';domElement.style.top=labelPos.y+'px';}}});var size=sb.canvas.getSize(),min=Math.min;sb.config.levelDistance=min(size.width,size.height)/2 +-config.offset-config.sliceOffset;this.sb=sb;this.canvas=this.sb.canvas;this.canvas.getCtx().globalCompositeOperation='lighter';},renderBackground:function(){var canvas=this.canvas,config=this.config,backgroundColor=config.backgroundColor,size=canvas.getSize(),ctx=canvas.getCtx();ctx.globalCompositeOperation="destination-over";ctx.fillStyle=backgroundColor;ctx.fillRect(-size.width/2,-size.height/2,size.width,size.height);},loadJSON:function(json){var prefix=$.time(),ch=[],sb=this.sb,name=$.splat(json.label),nameLength=name.length,color=$.splat(json.color||this.colors),colorLength=color.length,config=this.config,renderBackground=config.renderBackground,gradient=!!config.type.split(":")[1],animate=config.animate,mono=nameLength==1;totalValue=0;for(var i=0,values=json.values,l=values.length;iacum?maxValue:acum;});return maxValue;},normalizeDims:function(){var root=this.sb.graph.getNode(this.sb.root),l=0;root.eachAdjacency(function(){l++;});var maxValue=this.getMaxValue()||1,config=this.config,animate=config.animate,rho=this.sb.config.levelDistance;this.sb.graph.eachNode(function(n){var acum=0,animateValue=[];$.each(n.getData('valueArray'),function(v){acum+=+v;animateValue.push(1);});var stat=(animateValue.length==1)&&!config.updateHeights;if(animate){n.setData('dimArray',$.map(n.getData('valueArray'),function(n){return stat?rho:(n*rho/maxValue);}),'end');var dimArray=n.getData('dimArray');if(!dimArray){n.setData('dimArray',animateValue);}}else{n.setData('dimArray',$.map(n.getData('valueArray'),function(n){return stat?rho:(n*rho/maxValue);}));} +n.setData('normalizedDim',acum/maxValue);});}});Options.GaugeChart={$extend:true,animate:true,offset:25,sliceOffset:0,labelOffset:3,type:'stacked',labelType:'name',hoveredColor:'#9fd4ff',Events:{enable:false,onClick:$.empty},Tips:{enable:false,onShow:$.empty,onHide:$.empty},showLabels:true,resizeLabels:false,updateHeights:false};$jit.Sunburst.Plot.NodeTypes.implement({'gaugechart-basic':{'render':function(node,canvas){var pos=node.pos.getp(true),dimArray=node.getData('dimArray'),valueArray=node.getData('valueArray'),valuelabelsArray=node.getData('valuelabelsArray'),gaugeTarget=node.getData('gaugeTarget'),nodeIteration=node.getData('nodeIteration'),nodeLength=node.getData('nodeLength'),colorArray=node.getData('colorMono'),colorLength=colorArray.length,stringArray=node.getData('stringArray'),span=node.getData('span')/2,theta=node.pos.theta,begin=((theta-span)/2)+Math.PI,end=((theta+span)/2)+Math.PI,polar=new Polar;var ctx=canvas.getCtx(),opt={},gradient=node.getData('gradient'),border=node.getData('border'),config=node.getData('config'),showLabels=config.showLabels,resizeLabels=config.resizeLabels,label=config.Label;var xpos=Math.cos((begin+end)/2);var ypos=Math.sin((begin+end)/2);if(colorArray&&dimArray&&stringArray&&gaugeTarget!=0){for(var i=0,l=dimArray.length,acum=0,valAcum=0;i>0;}),endColor=$.rgbToHex(ans);radialGradient.addColorStop(0,'rgba('+colorRgb+',1)');radialGradient.addColorStop(0.1,'rgba('+colorRgb+',1)');radialGradient.addColorStop(0.85,'rgba('+colorRgb+',1)');radialGradient.addColorStop(1,'rgba('+ans+',1)');ctx.fillStyle=radialGradient;} +polar.rho=acum;polar.theta=begin;var p1coord=polar.getc(true);polar.theta=end;var p2coord=polar.getc(true);polar.rho+=dimi;var p3coord=polar.getc(true);polar.theta=begin;var p4coord=polar.getc(true);ctx.beginPath();ctx.arc(xpos,(ypos+dimi/2),(acum+dimi+.01)*.8,begin,end,false);ctx.arc(xpos,(ypos+dimi/2),(acum+dimi+.01),end,begin,true);ctx.fill();acum+=(dimi||0);valAcum+=(valueArray[i]||0);} +if(showLabels&&label.type=='Native'){ctx.save();ctx.fillStyle=ctx.strokeStyle=label.color;ctx.font=label.style+' '+label.size+'px '+label.family;ctx.textBaseline='bottom';ctx.textAlign='center';polar.rho=acum*.65;polar.theta=begin;var cart=polar.getc(true);if(nodeIteration==1){textY=cart.y-(label.size/2)+acum/2;}else{textY=cart.y+acum/2;} +if(config.labelType=='name'){ctx.fillText(node.name,cart.x,textY);}else{ctx.fillText(valuelabelsArray[0],cart.x,textY);} +if(nodeIteration==nodeLength){polar.theta=end;var cart=polar.getc(true);if(config.labelType=='name'){ctx.fillText(node.name,cart.x,cart.x,cart.y-(label.size/2)+acum/2);}else{ctx.fillText(valuelabelsArray[1],cart.x,cart.y-(label.size/2)+acum/2);}} +ctx.restore();}}},'contains':function(node,pos){if(this.nodeTypes['none'].anglecontainsgauge.call(this,node,pos)){var config=node.getData('config');var ld=this.config.levelDistance,d=node._depth;var yOffset=pos.y-(ld/2);var xOffset=pos.x;var rho=Math.sqrt(xOffset*xOffset+yOffset*yOffset);if(rho<=parseInt(ld*d)){var dimArray=node.getData('dimArray');for(var i=0,l=dimArray.length,acum=config.sliceOffset;i=ld*.8&&rho<=acum+dimi){var url=Url.decode(node.getData('linkArray')[i]);return{name:node.getData('stringArray')[i],link:url,color:node.getData('colorArray')[i],value:node.getData('valueArray')[i],valuelabel:node.getData('valuelabelsArray')[0]+" - "+node.getData('valuelabelsArray')[1],label:node.name};} +acum+=dimi;}} +return false;} +return false;}}});$jit.GaugeChart=new Class({sb:null,colors:["#416D9C","#70A35E","#EBB056","#C74243","#83548B","#909291","#557EAA"],selected:{},busy:false,initialize:function(opt){this.controller=this.config=$.merge(Options("Canvas","GaugeChart","Label"),{Label:{type:'Native'}},opt);this.initializeViz();},initializeViz:function(){var config=this.config,that=this;var nodeType=config.type.split(":")[0];var sb=new $jit.Sunburst({injectInto:config.injectInto,useCanvas:config.useCanvas,withLabels:config.Label.type!='Native',background:config.background,renderBackground:config.renderBackground,backgroundColor:config.backgroundColor,colorStop1:config.colorStop1,colorStop2:config.colorStop2,Label:{type:config.Label.type},Node:{overridable:true,type:'gaugechart-'+nodeType,width:1,height:1},Edge:{type:'none'},Tips:{enable:config.Tips.enable,type:'Native',force:true,onShow:function(tip,node,contains){var elem=contains;config.Tips.onShow(tip,elem,node);if(elem.link!='undefined'&&elem.link!=''){document.body.style.cursor='pointer';}},onHide:function(){document.body.style.cursor='default';}},Events:{enable:true,type:'Native',onClick:function(node,eventInfo,evt){if(!config.Events.enable)return;var elem=eventInfo.getContains();config.Events.onClick(elem,eventInfo,evt);}},onCreateLabel:function(domElement,node){var labelConf=config.Label;if(config.showLabels){var style=domElement.style;style.fontSize=labelConf.size+'px';style.fontFamily=labelConf.family;style.color=labelConf.color;style.textAlign='center';valuelabelsArray=node.getData('valuelabelsArray'),nodeIteration=node.getData('nodeIteration'),nodeLength=node.getData('nodeLength'),canvas=sb.canvas,prefix=$.time();if(config.labelType=='name'){domElement.innerHTML=node.name;}else{domElement.innerHTML=(valuelabelsArray[0]!=undefined)?valuelabelsArray[0]:"";} +domElement.style.width='400px';if(nodeIteration==nodeLength&&nodeLength!=0){idLabel=canvas.id+"-label";container=document.getElementById(idLabel);finalLabel=document.createElement('div');finalLabelStyle=finalLabel.style;finalLabel.id=prefix+"finalLabel";finalLabelStyle.position="absolute";finalLabelStyle.width="400px";finalLabelStyle.left="0px";container.appendChild(finalLabel);if(config.labelType=='name'){finalLabel.innerHTML=node.name;}else{finalLabel.innerHTML=(valuelabelsArray[1]!=undefined)?valuelabelsArray[1]:"";}}}},onPlaceLabel:function(domElement,node){if(!config.showLabels)return;var pos=node.pos.getp(true),dimArray=node.getData('dimArray'),nodeIteration=node.getData('nodeIteration'),nodeLength=node.getData('nodeLength'),span=node.getData('span')/2,theta=node.pos.theta,begin=((theta-span)/2)+Math.PI,end=((theta+span)/2)+Math.PI,polar=new Polar;var showLabels=config.showLabels,resizeLabels=config.resizeLabels,label=config.Label,radiusOffset=sb.config.levelDistance;if(dimArray){for(var i=0,l=dimArray.length,acum=0;i>0;fontSize=fontSize<+resizeLabels?+resizeLabels:fontSize;domElement.style.fontSize=fontSize+'px';polar.rho=acum*.65;polar.theta=begin;var pos=polar.getc(true);var radius=that.canvas.getSize();var labelPos={x:Math.round(pos.x+radius.width/2),y:Math.round(pos.y+(radius.height/2)+radiusOffset/2)};domElement.style.left=(labelPos.x-200)+'px';domElement.style.top=labelPos.y+'px';if(nodeIteration==1){domElement.style.top=labelPos.y-label.size+'px';} +if(nodeIteration==nodeLength&&nodeLength!=0){polar.theta=end;var final=polar.getc(true);var finalPos={x:Math.round(final.x+radius.width/2),y:Math.round(final.y+(radius.height/2)+radiusOffset/2)};finalLabel.style.left=(finalPos.x-200)+"px";finalLabel.style.top=finalPos.y-label.size+"px";}}}});this.sb=sb;this.canvas=this.sb.canvas;var size=sb.canvas.getSize(),min=Math.min;sb.config.levelDistance=min(size.width,size.height)/2 +-config.offset-config.sliceOffset;},renderBackground:function(){var canvas=this.sb.canvas,config=this.config,style=config.gaugeStyle,ctx=canvas.getCtx(),size=canvas.getSize(),radius=this.sb.config.levelDistance,startAngle=(Math.PI/180)*1,endAngle=(Math.PI/180)*179;ctx.fillStyle=style.borderColor;ctx.beginPath();ctx.arc(0,radius/2,radius+4,startAngle,endAngle,true);ctx.fill();var radialGradient=ctx.createRadialGradient(0,radius/2,0,0,radius/2,radius);radialGradient.addColorStop(0,'#ffffff');radialGradient.addColorStop(0.3,style.backgroundColor);radialGradient.addColorStop(0.6,style.backgroundColor);radialGradient.addColorStop(1,'#FFFFFF');ctx.fillStyle=radialGradient;startAngle=(Math.PI/180)*0;endAngle=(Math.PI/180)*180;ctx.beginPath();ctx.arc(0,radius/2,radius,startAngle,endAngle,true);ctx.fill();},renderNeedle:function(gaugePosition,target){var canvas=this.sb.canvas,config=this.config,style=config.gaugeStyle,ctx=canvas.getCtx(),size=canvas.getSize(),radius=this.sb.config.levelDistance;gaugeCenter=(radius/2);startAngle=0;endAngle=(Math.PI/180)*180;ctx.fillStyle=style.needleColor;var segments=180/target;needleAngle=gaugePosition*segments;ctx.translate(0,gaugeCenter);ctx.save();ctx.rotate(needleAngle*Math.PI/180);ctx.beginPath();ctx.moveTo(0,0);ctx.lineTo(0,-4);ctx.lineTo(-radius*.9,-1);ctx.lineTo(-radius*.9,1);ctx.lineTo(0,4);ctx.lineTo(0,0);ctx.closePath();ctx.fill();ctx.restore();ctx.lineWidth=1;ctx.strokeStyle='#aa0000';ctx.save();ctx.rotate(needleAngle*Math.PI/180);ctx.beginPath();ctx.moveTo(0,0);ctx.lineTo(0,-4);ctx.lineTo(-radius*.8,-1);ctx.lineTo(-radius*.8,1);ctx.lineTo(0,4);ctx.lineTo(0,0);ctx.closePath();ctx.stroke();ctx.restore();ctx.fillStyle="#000000";ctx.lineWidth=style.borderSize;ctx.strokeStyle=style.borderColor;var radialGradient=ctx.createRadialGradient(0,style.borderSize,0,0,style.borderSize,radius*.2);radialGradient.addColorStop(0,'#666666');radialGradient.addColorStop(0.8,'#444444');radialGradient.addColorStop(1,'rgba(0,0,0,0)');ctx.fillStyle=radialGradient;ctx.translate(0,5);ctx.save();ctx.beginPath();ctx.arc(0,0,radius*.2,startAngle,endAngle,true);ctx.fill();ctx.restore();},renderTicks:function(values){var canvas=this.sb.canvas,config=this.config,style=config.gaugeStyle,ctx=canvas.getCtx(),size=canvas.getSize(),radius=this.sb.config.levelDistance,gaugeCenter=(radius/2);ctx.strokeStyle=style.borderColor;ctx.lineWidth=5;ctx.lineCap="round";for(var i=0,total=0,l=values.length;iacum?maxValue:acum;});return maxValue;},normalizeDims:function(){var root=this.sb.graph.getNode(this.sb.root),l=0;root.eachAdjacency(function(){l++;});var maxValue=this.getMaxValue()||1,config=this.config,animate=config.animate,rho=this.sb.config.levelDistance;this.sb.graph.eachNode(function(n){var acum=0,animateValue=[];$.each(n.getData('valueArray'),function(v){acum+=+v;animateValue.push(1);});var stat=(animateValue.length==1)&&!config.updateHeights;if(animate){n.setData('dimArray',$.map(n.getData('valueArray'),function(n){return stat?rho:(n*rho/maxValue);}),'end');var dimArray=n.getData('dimArray');if(!dimArray){n.setData('dimArray',animateValue);}}else{n.setData('dimArray',$.map(n.getData('valueArray'),function(n){return stat?rho:(n*rho/maxValue);}));} +n.setData('normalizedDim',acum/maxValue);});}});Layouts.TM={};Layouts.TM.SliceAndDice=new Class({compute:function(prop){var root=this.graph.getNode(this.clickedNode&&this.clickedNode.id||this.root);this.controller.onBeforeCompute(root);var size=this.canvas.getSize(),config=this.config,width=size.width,height=size.height;this.graph.computeLevels(this.root,0,"ignore");root.getPos(prop).setc(-width/2,-height/2);root.setData('width',width,prop);root.setData('height',height+config.titleHeight,prop);this.computePositions(root,root,this.layout.orientation,prop);this.controller.onAfterCompute(root);},computePositions:function(par,ch,orn,prop){var totalArea=0;par.eachSubnode(function(n){totalArea+=n.getData('area',prop);});var config=this.config,offst=config.offset,width=par.getData('width',prop),height=par.getData('height',prop)-config.titleHeight,fact=par==ch?1:(ch.getData('area',prop)/totalArea);var otherSize,size,dim,pos,pos2,posth,pos2th;var horizontal=(orn=="h");if(horizontal){orn='v';otherSize=height;size=width*fact;dim='height';pos='y';pos2='x';posth=config.titleHeight;pos2th=0;}else{orn='h';otherSize=height*fact;size=width;dim='width';pos='x';pos2='y';posth=0;pos2th=config.titleHeight;} +var cpos=ch.getPos(prop);ch.setData('width',size,prop);ch.setData('height',otherSize,prop);var offsetSize=0,tm=this;ch.eachSubnode(function(n){var p=n.getPos(prop);p[pos]=offsetSize+cpos[pos]+posth;p[pos2]=cpos[pos2]+pos2th;tm.computePositions(ch,n,orn,prop);offsetSize+=n.getData(dim,prop);});}});Layouts.TM.Area={compute:function(prop){prop=prop||"current";var root=this.graph.getNode(this.clickedNode&&this.clickedNode.id||this.root);this.controller.onBeforeCompute(root);var config=this.config,size=this.canvas.getSize(),width=size.width,height=size.height,offst=config.offset,offwdth=width-offst,offhght=height-offst;this.graph.computeLevels(this.root,0,"ignore");root.getPos(prop).setc(-width/2,-height/2);root.setData('width',width,prop);root.setData('height',height,prop);var coord={'top':-height/2+config.titleHeight,'left':-width/2,'width':offwdth,'height':offhght-config.titleHeight};this.computePositions(root,coord,prop);this.controller.onAfterCompute(root);},computeDim:function(tail,initElem,w,coord,comp,prop){if(tail.length+initElem.length==1){var l=(tail.length==1)?tail:initElem;this.layoutLast(l,w,coord,prop);return;} +if(tail.length>=2&&initElem.length==0){initElem=[tail.shift()];} +if(tail.length==0){if(initElem.length>0)this.layoutRow(initElem,w,coord,prop);return;} +var c=tail[0];if(comp(initElem,w)>=comp([c].concat(initElem),w)){this.computeDim(tail.slice(1),initElem.concat([c]),w,coord,comp,prop);}else{var newCoords=this.layoutRow(initElem,w,coord,prop);this.computeDim(tail,[],newCoords.dim,newCoords,comp,prop);}},worstAspectRatio:function(ch,w){if(!ch||ch.length==0)return Number.MAX_VALUE;var areaSum=0,maxArea=0,minArea=Number.MAX_VALUE;for(var i=0,l=ch.length;iarea?maxArea:area;} +var sqw=w*w,sqAreaSum=areaSum*areaSum;return Math.max(sqw*maxArea/sqAreaSum,sqAreaSum/(sqw*minArea));},avgAspectRatio:function(ch,w){if(!ch||ch.length==0)return Number.MAX_VALUE;var arSum=0;for(var i=0,l=ch.length;ih?w/h:h/w;} +return arSum/l;},layoutLast:function(ch,w,coord,prop){var child=ch[0];child.getPos(prop).setc(coord.left,coord.top);child.setData('width',coord.width,prop);child.setData('height',coord.height,prop);}};Layouts.TM.Squarified=new Class({Implements:Layouts.TM.Area,computePositions:function(node,coord,prop){var config=this.config;if(coord.width>=coord.height) +this.layout.orientation='h';else +this.layout.orientation='v';var ch=node.getSubnodes([1,1],"ignore");if(ch.length>0){this.processChildrenLayout(node,ch,coord,prop);for(var i=0,l=ch.length;i0){this.processChildrenLayout(node,ch,coord,prop);for(var i=0,l=ch.length;itreeDepth)treeDepth=d;});var startNode=this.graph.getNode(this.clickedNode&&this.clickedNode.id||root.id);var maxDepth=Math.min(treeDepth,levelsToShow-1);var initialDepth=startNode._depth;if(this.layout.horizontal()){this.computeSubtree(startNode,-width/2,-height/2,width/(maxDepth+1),height,initialDepth,maxDepth,posType);}else{this.computeSubtree(startNode,-width/2,-height/2,width,height/(maxDepth+1),initialDepth,maxDepth,posType);}},computeSubtree:function(root,x,y,width,height,initialDepth,maxDepth,posType){root.getPos(posType).setc(x,y);root.setData('width',width,posType);root.setData('height',height,posType);var nodeLength,prevNodeLength=0,totalDim=0;var children=Graph.Util.getSubnodes(root,[1,1]);if(!children.length) +return;$.each(children,function(e){totalDim+=e.getData('dim');});for(var i=0,l=children.length;i>0;}));lg.addColorStop(0,color);lg.addColorStop(1,colorGrad);ctx.fillStyle=lg;} +if(border){ctx.strokeStyle=border;ctx.lineWidth=3;} +ctx.fillRect(posx,posy,Math.max(0,width-offset),Math.max(0,height-offset));border&&ctx.strokeRect(pos.x,pos.y,width,height);},'contains':function(node,pos){if(this.viz.clickedNode&&!$jit.Graph.Util.isDescendantOf(node,this.viz.clickedNode.id))return false;var npos=node.pos.getc(true),width=node.getData('width'),height=node.getData('height');return this.nodeHelper.rectangle.contains({x:npos.x+width/2,y:npos.y+height/2},pos,width,height);}}});$jit.Icicle.Plot.EdgeTypes=new Class({'none':$.empty});Layouts.ForceDirected=new Class({getOptions:function(random){var s=this.canvas.getSize();var w=s.width,h=s.height;var count=0;this.graph.eachNode(function(n){count++;});var k2=w*h/count,k=Math.sqrt(k2);var l=this.config.levelDistance;return{width:w,height:h,tstart:w*0.1,nodef:function(x){return k2/(x||1);},edgef:function(x){return k*(x-l);}};},compute:function(property,incremental){var prop=$.splat(property||['current','start','end']);var opt=this.getOptions();NodeDim.compute(this.graph,prop,this.config);this.graph.computeLevels(this.root,0,"ignore");this.graph.eachNode(function(n){$.each(prop,function(p){var pos=n.getPos(p);if(pos.equals(Complex.KER)){pos.x=opt.width/5*(Math.random()-0.5);pos.y=opt.height/5*(Math.random()-0.5);} +n.disp={};$.each(prop,function(p){n.disp[p]=$C(0,0);});});});this.computePositions(prop,opt,incremental);},computePositions:function(property,opt,incremental){var times=this.config.iterations,i=0,that=this;if(incremental){(function iter(){for(var total=incremental.iter,j=0;j=times){incremental.onComplete();return;}} +incremental.onStep(Math.round(i/(times-1)*100));setTimeout(iter,1);})();}else{for(;i1&&direction[0]!=adj.nodeFrom.id);this.edgeHelper.arrow.render(from,to,dim,inv,canvas);},'contains':function(adj,pos){var from=adj.nodeFrom.pos.getc(true),to=adj.nodeTo.pos.getc(true);return this.edgeHelper.arrow.contains(from,to,pos,this.edge.epsilon);}}});})($jit.ForceDirected);$jit.TM={};var TM=$jit.TM;$jit.TM.$extend=true;TM.Base={layout:{orientation:"h",vertical:function(){return this.orientation=="v";},horizontal:function(){return this.orientation=="h";},change:function(){this.orientation=this.vertical()?"h":"v";}},initialize:function(controller){var config={orientation:"h",titleHeight:13,offset:2,levelsToShow:0,constrained:false,animate:false,Node:{type:'rectangle',overridable:true,width:3,height:3,color:'#444'},Label:{textAlign:'center',textBaseline:'top'},Edge:{type:'none'},duration:700,fps:45};this.controller=this.config=$.merge(Options("Canvas","Node","Edge","Fx","Controller","Tips","NodeStyles","Events","Navigation","Label"),config,controller);this.layout.orientation=this.config.orientation;var canvasConfig=this.config;if(canvasConfig.useCanvas){this.canvas=canvasConfig.useCanvas;this.config.labelContainer=this.canvas.id+'-label';}else{if(canvasConfig.background){canvasConfig.background=$.merge({type:'Circles'},canvasConfig.background);} +this.canvas=new Canvas(this,canvasConfig);this.config.labelContainer=(typeof canvasConfig.injectInto=='string'?canvasConfig.injectInto:canvasConfig.injectInto.id)+'-label';} +this.graphOptions={'complex':true,'Node':{'selected':false,'exist':true,'drawn':true}};this.graph=new Graph(this.graphOptions,this.config.Node,this.config.Edge);this.labels=new TM.Label[canvasConfig.Label.type](this);this.fx=new TM.Plot(this);this.op=new TM.Op(this);this.group=new TM.Group(this);this.geom=new TM.Geom(this);this.clickedNode=null;this.busy=false;this.initializeExtras();},refresh:function(){if(this.busy)return;this.busy=true;var that=this;if(this.config.animate){this.compute('end');this.config.levelsToShow>0&&this.geom.setRightLevelToShow(this.graph.getNode(this.clickedNode&&this.clickedNode.id||this.root));this.fx.animate($.merge(this.config,{modes:['linear','node-property:width:height'],onComplete:function(){that.busy=false;}}));}else{var labelType=this.config.Label.type;if(labelType!='Native'){var that=this;this.graph.eachNode(function(n){that.labels.hideLabel(n,false);});} +this.busy=false;this.compute();this.config.levelsToShow>0&&this.geom.setRightLevelToShow(this.graph.getNode(this.clickedNode&&this.clickedNode.id||this.root));this.plot();}},plot:function(){this.fx.plot();},leaf:function(n){return n.getSubnodes([1,1],"ignore").length==0;},enter:function(n){if(this.busy)return;this.busy=true;var that=this,config=this.config,graph=this.graph,clickedNode=n,previousClickedNode=this.clickedNode;var callback={onComplete:function(){if(config.levelsToShow>0){that.geom.setRightLevelToShow(n);} +if(config.levelsToShow>0||config.request)that.compute();if(config.animate){graph.nodeList.setData('alpha',0,'end');n.eachSubgraph(function(n){n.setData('alpha',1,'end');},"ignore");that.fx.animate({duration:500,modes:['node-property:alpha'],onComplete:function(){that.clickedNode=clickedNode;that.compute('end');that.clickedNode=previousClickedNode;that.fx.animate({modes:['linear','node-property:width:height'],duration:1000,onComplete:function(){that.busy=false;that.clickedNode=clickedNode;}});}});}else{that.busy=false;that.clickedNode=n;that.refresh();}}};if(config.request){this.requestNodes(clickedNode,callback);}else{callback.onComplete();}},out:function(){if(this.busy)return;this.busy=true;this.events.hoveredNode=false;var that=this,config=this.config,graph=this.graph,parents=graph.getNode(this.clickedNode&&this.clickedNode.id||this.root).getParents(),parent=parents[0],clickedNode=parent,previousClickedNode=this.clickedNode;if(!parent){this.busy=false;return;} +callback={onComplete:function(){that.clickedNode=parent;if(config.request){that.requestNodes(parent,{onComplete:function(){that.compute();that.plot();that.busy=false;}});}else{that.compute();that.plot();that.busy=false;}}};if(config.levelsToShow>0) +this.geom.setRightLevelToShow(parent);if(config.animate){this.clickedNode=clickedNode;this.compute('end');this.clickedNode=previousClickedNode;this.fx.animate({modes:['linear','node-property:width:height'],duration:1000,onComplete:function(){that.clickedNode=clickedNode;graph.eachNode(function(n){n.setDataset(['current','end'],{'alpha':[0,1]});},"ignore");previousClickedNode.eachSubgraph(function(node){node.setData('alpha',1);},"ignore");that.fx.animate({duration:500,modes:['node-property:alpha'],onComplete:function(){callback.onComplete();}});}});}else{callback.onComplete();}},requestNodes:function(node,onComplete){var handler=$.merge(this.controller,onComplete),lev=this.config.levelsToShow;if(handler.request){var leaves=[],d=node._depth;node.eachLevel(0,lev,function(n){var nodeLevel=lev-(n._depth-d);if(n.drawn&&!n.anySubnode()&&nodeLevel>0){leaves.push(n);n._level=nodeLevel;}});this.group.requestNodes(leaves,handler);}else{handler.onComplete();}}};TM.Op=new Class({Implements:Graph.Op,initialize:function(viz){this.viz=viz;}});TM.Geom=new Class({Implements:Graph.Geom,getRightLevelToShow:function(){return this.viz.config.levelsToShow;},setRightLevelToShow:function(node){var level=this.getRightLevelToShow(),fx=this.viz.labels;node.eachLevel(0,level+1,function(n){var d=n._depth-node._depth;if(d>level){n.drawn=false;n.exist=false;n.ignore=true;fx.hideLabel(n,false);}else{n.drawn=true;n.exist=true;delete n.ignore;}});node.drawn=true;delete node.ignore;}});TM.Group=new Class({initialize:function(viz){this.viz=viz;this.canvas=viz.canvas;this.config=viz.config;},requestNodes:function(nodes,controller){var counter=0,len=nodes.length,nodeSelected={};var complete=function(){controller.onComplete();};var viz=this.viz;if(len==0) +complete();for(var i=0;i>0;}));lg.addColorStop(0,color);lg.addColorStop(1,colorGrad);ctx.fillStyle=lg;} +ctx.fillRect(posx,posy,width-offst,height-offst);if(border){ctx.save();ctx.strokeStyle=border;ctx.strokeRect(posx,posy,width-offst,height-offst);ctx.restore();}}else if(titleHeight>0){ctx.fillRect(pos.x+offst/2,pos.y+offst/2,width-offst,titleHeight-offst);if(border){ctx.save();ctx.strokeStyle=border;ctx.strokeRect(pos.x+offst/2,pos.y+offst/2,width-offst,height-offst);ctx.restore();}}},'contains':function(node,pos){if(this.viz.clickedNode&&!node.isDescendantOf(this.viz.clickedNode.id)||node.ignore)return false;var npos=node.pos.getc(true),width=node.getData('width'),leaf=this.viz.leaf(node),height=leaf?node.getData('height'):this.config.titleHeight;return this.nodeHelper.rectangle.contains({x:npos.x+width/2,y:npos.y+height/2},pos,width,height);}}});TM.Plot.EdgeTypes=new Class({'none':$.empty});TM.SliceAndDice=new Class({Implements:[Loader,Extras,TM.Base,Layouts.TM.SliceAndDice]});TM.Squarified=new Class({Implements:[Loader,Extras,TM.Base,Layouts.TM.Squarified]});TM.Strip=new Class({Implements:[Loader,Extras,TM.Base,Layouts.TM.Strip]});$jit.RGraph=new Class({Implements:[Loader,Extras,Layouts.Radial],initialize:function(controller){var $RGraph=$jit.RGraph;var config={interpolation:'linear',levelDistance:100};this.controller=this.config=$.merge(Options("Canvas","Node","Edge","Fx","Controller","Tips","NodeStyles","Events","Navigation","Label"),config,controller);var canvasConfig=this.config;if(canvasConfig.useCanvas){this.canvas=canvasConfig.useCanvas;this.config.labelContainer=this.canvas.id+'-label';}else{if(canvasConfig.background){canvasConfig.background=$.merge({type:'Circles'},canvasConfig.background);} +this.canvas=new Canvas(this,canvasConfig);this.config.labelContainer=(typeof canvasConfig.injectInto=='string'?canvasConfig.injectInto:canvasConfig.injectInto.id)+'-label';} +this.graphOptions={'complex':false,'Node':{'selected':false,'exist':true,'drawn':true}};this.graph=new Graph(this.graphOptions,this.config.Node,this.config.Edge);this.labels=new $RGraph.Label[canvasConfig.Label.type](this);this.fx=new $RGraph.Plot(this,$RGraph);this.op=new $RGraph.Op(this);this.json=null;this.root=null;this.busy=false;this.parent=false;this.initializeExtras();},createLevelDistanceFunc:function(){var ld=this.config.levelDistance;return function(elem){return(elem._depth+1)*ld;};},refresh:function(){this.compute();this.plot();},reposition:function(){this.compute('end');},plot:function(){this.fx.plot();},getNodeAndParentAngle:function(id){var theta=false;var n=this.graph.getNode(id);var ps=n.getParents();var p=(ps.length>0)?ps[0]:false;if(p){var posParent=p.pos.getc(),posChild=n.pos.getc();var newPos=posParent.add(posChild.scale(-1));theta=Math.atan2(newPos.y,newPos.x);if(theta<0) +theta+=2*Math.PI;} +return{parent:p,theta:theta};},tagChildren:function(par,id){if(par.angleSpan){var adjs=[];par.eachAdjacency(function(elem){adjs.push(elem.nodeTo);},"ignore");var len=adjs.length;for(var i=0;i1&&direction[0]!=adj.nodeFrom.id);this.edgeHelper.arrow.render(from,to,dim,inv,canvas);},'contains':function(adj,pos){var from=adj.nodeFrom.pos.getc(true),to=adj.nodeTo.pos.getc(true);return this.edgeHelper.arrow.contains(from,to,pos,this.edge.epsilon);}}});})($jit.RGraph);Complex.prototype.moebiusTransformation=function(c){var num=this.add(c);var den=c.$conjugate().$prod(this);den.x++;return num.$div(den);};Graph.Util.moebiusTransformation=function(graph,pos,prop,startPos,flags){this.eachNode(graph,function(elem){for(var i=0;i=2){return genDistFunc(i-0.01);}} +return genDistFunc(0.75);},getRadius:function(){var rad=this.config.radius;if(rad!=="auto"){return rad;} +var s=this.canvas.getSize();return Math.min(s.width,s.height)/2;},refresh:function(reposition){if(reposition){this.reposition();this.graph.eachNode(function(node){node.startPos.rho=node.pos.rho=node.endPos.rho;node.startPos.theta=node.pos.theta=node.endPos.theta;});}else{this.compute();} +this.plot();},reposition:function(){this.compute('end');var vector=this.graph.getNode(this.root).pos.getc().scale(-1);Graph.Util.moebiusTransformation(this.graph,[vector],['end'],'end',"ignore");this.graph.eachNode(function(node){if(node.ignore){node.endPos.rho=node.pos.rho;node.endPos.theta=node.pos.theta;}});},plot:function(){this.fx.plot();},onClick:function(id,opt){var pos=this.graph.getNode(id).pos.getc(true);this.move(pos,opt);},move:function(pos,opt){var versor=$C(pos.x,pos.y);if(this.busy===false&&versor.norm()<1){this.busy=true;var root=this.graph.getClosestNodeToPos(versor),that=this;this.graph.computeLevels(root.id,0);this.controller.onBeforeCompute(root);opt=$.merge({onComplete:$.empty},opt||{});this.fx.animate($.merge({modes:['moebius'],hideLabels:true},opt,{onComplete:function(){that.busy=false;opt.onComplete();}}),versor);}}});$jit.Hypertree.$extend=true;(function(Hypertree){Hypertree.Op=new Class({Implements:Graph.Op});Hypertree.Plot=new Class({Implements:Graph.Plot});Hypertree.Label={};Hypertree.Label.Native=new Class({Implements:Graph.Label.Native,initialize:function(viz){this.viz=viz;},renderLabel:function(canvas,node,controller){var ctx=canvas.getCtx();var coord=node.pos.getc(true);var s=this.viz.getRadius();ctx.fillText(node.name,coord.x*s,coord.y*s);}});Hypertree.Label.SVG=new Class({Implements:Graph.Label.SVG,initialize:function(viz){this.viz=viz;},placeLabel:function(tag,node,controller){var pos=node.pos.getc(true),canvas=this.viz.canvas,ox=canvas.translateOffsetX,oy=canvas.translateOffsetY,sx=canvas.scaleOffsetX,sy=canvas.scaleOffsetY,radius=canvas.getSize(),r=this.viz.getRadius();var labelPos={x:Math.round((pos.x*sx)*r+ox+radius.width/2),y:Math.round((pos.y*sy)*r+oy+radius.height/2)};tag.setAttribute('x',labelPos.x);tag.setAttribute('y',labelPos.y);controller.onPlaceLabel(tag,node);}});Hypertree.Label.HTML=new Class({Implements:Graph.Label.HTML,initialize:function(viz){this.viz=viz;},placeLabel:function(tag,node,controller){var pos=node.pos.getc(true),canvas=this.viz.canvas,ox=canvas.translateOffsetX,oy=canvas.translateOffsetY,sx=canvas.scaleOffsetX,sy=canvas.scaleOffsetY,radius=canvas.getSize(),r=this.viz.getRadius();var labelPos={x:Math.round((pos.x*sx)*r+ox+radius.width/2),y:Math.round((pos.y*sy)*r+oy+radius.height/2)};var style=tag.style;style.left=labelPos.x+'px';style.top=labelPos.y+'px';style.display=this.fitsInCanvas(labelPos,canvas)?'':'none';controller.onPlaceLabel(tag,node);}});Hypertree.Plot.NodeTypes=new Class({'none':{'render':$.empty,'contains':$.lambda(false)},'circle':{'render':function(node,canvas){var nconfig=this.node,dim=node.getData('dim'),p=node.pos.getc();dim=nconfig.transform?dim*(1-p.squaredNorm()):dim;p.$scale(node.scale);if(dim>0.2){this.nodeHelper.circle.render('fill',p,dim,canvas);}},'contains':function(node,pos){var dim=node.getData('dim'),npos=node.pos.getc().$scale(node.scale);return this.nodeHelper.circle.contains(npos,pos,dim);}},'ellipse':{'render':function(node,canvas){var pos=node.pos.getc().$scale(node.scale),width=node.getData('width'),height=node.getData('height');this.nodeHelper.ellipse.render('fill',pos,width,height,canvas);},'contains':function(node,pos){var width=node.getData('width'),height=node.getData('height'),npos=node.pos.getc().$scale(node.scale);return this.nodeHelper.circle.contains(npos,pos,width,height);}},'square':{'render':function(node,canvas){var nconfig=this.node,dim=node.getData('dim'),p=node.pos.getc();dim=nconfig.transform?dim*(1-p.squaredNorm()):dim;p.$scale(node.scale);if(dim>0.2){this.nodeHelper.square.render('fill',p,dim,canvas);}},'contains':function(node,pos){var dim=node.getData('dim'),npos=node.pos.getc().$scale(node.scale);return this.nodeHelper.square.contains(npos,pos,dim);}},'rectangle':{'render':function(node,canvas){var nconfig=this.node,width=node.getData('width'),height=node.getData('height'),pos=node.pos.getc();width=nconfig.transform?width*(1-pos.squaredNorm()):width;height=nconfig.transform?height*(1-pos.squaredNorm()):height;pos.$scale(node.scale);if(width>0.2&&height>0.2){this.nodeHelper.rectangle.render('fill',pos,width,height,canvas);}},'contains':function(node,pos){var width=node.getData('width'),height=node.getData('height'),npos=node.pos.getc().$scale(node.scale);return this.nodeHelper.square.contains(npos,pos,width,height);}},'triangle':{'render':function(node,canvas){var nconfig=this.node,dim=node.getData('dim'),p=node.pos.getc();dim=nconfig.transform?dim*(1-p.squaredNorm()):dim;p.$scale(node.scale);if(dim>0.2){this.nodeHelper.triangle.render('fill',p,dim,canvas);}},'contains':function(node,pos){var dim=node.getData('dim'),npos=node.pos.getc().$scale(node.scale);return this.nodeHelper.triangle.contains(npos,pos,dim);}},'star':{'render':function(node,canvas){var nconfig=this.node,dim=node.getData('dim'),p=node.pos.getc();dim=nconfig.transform?dim*(1-p.squaredNorm()):dim;p.$scale(node.scale);if(dim>0.2){this.nodeHelper.star.render('fill',p,dim,canvas);}},'contains':function(node,pos){var dim=node.getData('dim'),npos=node.pos.getc().$scale(node.scale);return this.nodeHelper.star.contains(npos,pos,dim);}}});Hypertree.Plot.EdgeTypes=new Class({'none':$.empty,'line':{'render':function(adj,canvas){var from=adj.nodeFrom.pos.getc(true),to=adj.nodeTo.pos.getc(true),r=adj.nodeFrom.scale;this.edgeHelper.line.render({x:from.x*r,y:from.y*r},{x:to.x*r,y:to.y*r},canvas);},'contains':function(adj,pos){var from=adj.nodeFrom.pos.getc(true),to=adj.nodeTo.pos.getc(true),r=adj.nodeFrom.scale;this.edgeHelper.line.contains({x:from.x*r,y:from.y*r},{x:to.x*r,y:to.y*r},pos,this.edge.epsilon);}},'arrow':{'render':function(adj,canvas){var from=adj.nodeFrom.pos.getc(true),to=adj.nodeTo.pos.getc(true),r=adj.nodeFrom.scale,dim=adj.getData('dim'),direction=adj.data.$direction,inv=(direction&&direction.length>1&&direction[0]!=adj.nodeFrom.id);this.edgeHelper.arrow.render({x:from.x*r,y:from.y*r},{x:to.x*r,y:to.y*r},dim,inv,canvas);},'contains':function(adj,pos){var from=adj.nodeFrom.pos.getc(true),to=adj.nodeTo.pos.getc(true),r=adj.nodeFrom.scale;this.edgeHelper.arrow.contains({x:from.x*r,y:from.y*r},{x:to.x*r,y:to.y*r},pos,this.edge.epsilon);}},'hyperline':{'render':function(adj,canvas){var from=adj.nodeFrom.pos.getc(),to=adj.nodeTo.pos.getc(),dim=this.viz.getRadius();this.edgeHelper.hyperline.render(from,to,dim,canvas);},'contains':$.lambda(false)}});})($jit.Hypertree);})(); \ No newline at end of file diff --git a/include/SugarCharts/Jit/js/mySugarCharts.js b/include/SugarCharts/Jit/js/mySugarCharts.js new file mode 100644 index 00000000..d8ac9cbf --- /dev/null +++ b/include/SugarCharts/Jit/js/mySugarCharts.js @@ -0,0 +1,39 @@ +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ +SUGAR.mySugar.sugarCharts=function(){var activeTab=activePage,charts=new Object(),windowWidth=0,firstLoad=(SUGAR.isIE)?true:false;return{loadSugarCharts:function(activeTab){var chartFound=false;for(id in charts[activeTab]){if(id!='undefined'){chartFound=true;loadSugarChart(charts[activeTab][id]['chartId'],charts[activeTab][id]['jsonFilename'],charts[activeTab][id]['css'],charts[activeTab][id]['chartConfig']);}} +charts=new Object();},addToChartsArrayJson:function(json,activeTab){for(id in json){if(json[id]['supported']=="true"){SUGAR.mySugar.sugarCharts.addToChartsArray(json[id]['chartId'],json[id]['filename'],json[id]['css'],json[id]['chartConfig'],activeTab);}}},addToChartsArray:function(chartId,jsonFilename,css,chartConfig,activeTab){if(charts[activeTab]==null){charts[activeTab]=new Object();} +charts[activeTab][chartId]=new Object();charts[activeTab][chartId]['chartId']=chartId;charts[activeTab][chartId]['jsonFilename']=jsonFilename;charts[activeTab][chartId]['css']=css;charts[activeTab][chartId]['chartConfig']=chartConfig;},refreshPage:function(){var newWidth=document.body.offsetWidth;if(newWidth!=windowWidth&&!firstLoad){if(SUGAR.isIE){SUGAR.mySugar.loading.show();document.getElementById('loading_c').style.display='inline';setTimeout(function(){location.reload();},500);}else{SUGAR.mySugar.retrievePage(activePage);} +SUGAR.mySugar.sugarCharts.loadSugarCharts(activePage);} +firstLoad=false;windowWidth=newWidth;},refreshGraphs:function(){setTimeout("SUGAR.mySugar.sugarCharts.refreshPage()",1000);}}}();YAHOO.util.Event.addListener(window,'resize',SUGAR.mySugar.sugarCharts.refreshGraphs); \ No newline at end of file diff --git a/include/SugarCharts/Jit/js/sugarCharts.js b/include/SugarCharts/Jit/js/sugarCharts.js new file mode 100644 index 00000000..13ce7393 --- /dev/null +++ b/include/SugarCharts/Jit/js/sugarCharts.js @@ -0,0 +1,76 @@ +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ +function loadSugarChart(chartId,jsonFilename,css,chartConfig){var labelType,useGradients,nativeTextSupport,animate;(function(){var ua=navigator.userAgent,typeOfCanvas=typeof HTMLCanvasElement,nativeCanvasSupport=(typeOfCanvas=='object'||typeOfCanvas=='function'),textSupport=nativeCanvasSupport&&(typeof document.createElement('canvas').getContext('2d').fillText=='function');labelType='Native';nativeTextSupport=labelType=='Native';useGradients=nativeCanvasSupport;animate=false;})();switch(chartConfig["chartType"]){case"barChart":var handleFailure=function(o){alert('fail');if(o.responseText!==undefined){alert('failed');}} +var handleSuccess=function(o){if(o.responseText!==undefined&&o.responseText!="No Data"){var json=eval('('+o.responseText+')');var properties=$jit.util.splat(json.properties)[0];var marginBottom=(chartConfig["orientation"]=='vertical'&&json.values.length>8)?20*4:20;var barChart=new $jit.BarChart({injectInto:chartId,animate:false,nodeCount:json.values.length,renderBackground:chartConfig['imageExportType']=="jpg"?true:false,backgroundColor:'rgb(255,255,255)',colorStop1:'rgba(255,255,255,.8)',colorStop2:'rgba(255,255,255,0)',shadow:{enable:true,size:2},orientation:chartConfig["orientation"],hoveredColor:false,Title:{text:properties['title'],size:16,color:'#444444',offset:20},Subtitle:{text:properties['subtitle'],size:11,color:css["color"],offset:20},Ticks:{enable:true,color:css["gridLineColor"]},barsOffset:(chartConfig["orientation"]=="vertical")?30:20,Margin:{top:20,left:30,right:20,bottom:marginBottom},ScrollNote:{text:(chartConfig["scroll"]&&SUGAR.util.isTouchScreen())?"Use two fingers to scroll":"",size:12},Events:{enable:true,onClick:function(node){if(!node||SUGAR.util.isTouchScreen())return;if(node.link=='undefined'||node.link=='')return;window.location.href=node.link;}},labelOffset:5,type:useGradients?chartConfig["barType"]+':gradient':chartConfig["barType"],showAggregates:true,showLabels:true,Label:{type:labelType,size:12,family:css["font-family"],color:css["color"],colorAlt:"#ffffff"},Tips:{enable:true,onShow:function(tip,elem){if(elem.link!='undefined'&&elem.link!=''){drillDown=(SUGAR.util.isTouchScreen())?"
Click to drilldown":"
Click to drilldown";}else{drillDown="";} +if(elem.valuelabel!='undefined'&&elem.valuelabel!=undefined&&elem.valuelabel!=''){value="elem.valuelabel";}else{value="elem.value";} +eval("tip.innerHTML = '' + elem."+chartConfig["tip"]+" + ': ' + "+value+" + ' - ' + elem.percentage + '%' + drillDown");}}});barChart.loadJSON(json);var list=$jit.id('legend'+chartId);var legend=barChart.getLegend(),cols=(typeof SUGAR=='undefined'||typeof SUGAR.mySugar=='undefined')?8:4,rows=Math.ceil(legend["name"].length/cols),table="";var j=0;for(i=0;i";for(td=0;td';if(legend["name"][j]!=undefined){table+='
 
'+legend["name"][j];} +table+='';j++;} +table+="";} +table+="
";list.innerHTML=table;$jit.util.saveImageTest(chartId,jsonFilename,chartConfig["imageExportType"]);}} +var callback={success:handleSuccess,failure:handleFailure,argument:{foo:'foo',bar:''}};var request=YAHOO.util.Connect.asyncRequest('GET',jsonFilename+"?r="+new Date().getTime(),callback);break;case"lineChart":var handleFailure=function(o){alert('fail');if(o.responseText!==undefined){alert('failed');}} +var handleSuccess=function(o){if(o.responseText!==undefined&&o.responseText!="No Data"){var json=eval('('+o.responseText+')');var properties=$jit.util.splat(json.properties)[0];var lineChart=new $jit.LineChart({injectInto:chartId,animate:false,renderBackground:chartConfig['imageExportType']=="jpg"?true:false,backgroundColor:'rgb(255,255,255)',colorStop1:'rgba(255,255,255,.8)',colorStop2:'rgba(255,255,255,0)',selectOnHover:false,Title:{text:properties['title'],size:16,color:'#444444',offset:20},Subtitle:{text:properties['subtitle'],size:11,color:css["color"],offset:20},Ticks:{enable:true,color:css["gridLineColor"]},Margin:{top:20,left:40,right:40,bottom:20},Events:{enable:true,onClick:function(node){if(!node||SUGAR.util.isTouchScreen())return;if(node.link=='undefined'||node.link=='')return;window.location.href=node.link;}},labelOffset:5,type:useGradients?chartConfig["lineType"]+':gradient':chartConfig["lineType"],showAggregates:true,showLabels:true,Label:{type:labelType,size:12,family:css["font-family"],color:css["color"],colorAlt:"#ffffff"},Tips:{enable:true,onShow:function(tip,elem){if(elem.link!='undefined'&&elem.link!=''){drillDown=(SUGAR.util.isTouchScreen())?"
Click to drilldown":"
Click to drilldown";}else{drillDown="";} +if(elem.valuelabel!='undefined'&&elem.valuelabel!=undefined&&elem.valuelabel!=''){var value="elem.valuelabel";}else{var value="elem.value";} +if(elem.collision){eval("var name = elem."+chartConfig["tip"]+";");var content='';for(var i=0;i';} +content+='
'+name[i]+': '+elem.value[i]+' - '+elem.percentage[i]+'%'+'
';tip.innerHTML=content;}else{eval("tip.innerHTML = '' + elem."+chartConfig["tip"]+" + ': ' + "+value+" + ' - ' + elem.percentage + '%' + drillDown");}}}});lineChart.loadJSON(json);var list=$jit.id('legend'+chartId);var legend=lineChart.getLegend(),cols=(typeof SUGAR=='undefined'||typeof SUGAR.mySugar=='undefined')?8:4,rows=Math.ceil(legend["name"].length/cols),table="";var j=0;for(i=0;i";for(td=0;td';if(legend["name"][j]!=undefined){table+='
 
'+legend["name"][j];} +table+='';j++;} +table+="";} +table+="
";list.innerHTML=table;$jit.util.saveImageTest(chartId,jsonFilename,chartConfig["imageExportType"]);}} +var callback={success:handleSuccess,failure:handleFailure,argument:{foo:'foo',bar:''}};var request=YAHOO.util.Connect.asyncRequest('GET',jsonFilename+"?r="+new Date().getTime(),callback);break;case"pieChart":var handleFailure=function(o){alert('fail');if(o.responseText!==undefined){alert('failed');}} +var handleSuccess=function(o){if(o.responseText!==undefined){var json=eval('('+o.responseText+')');var properties=$jit.util.splat(json.properties)[0];var pieChart=new $jit.PieChart({injectInto:chartId,animate:false,renderBackground:chartConfig['imageExportType']=="jpg"?true:false,backgroundColor:'rgb(255,255,255)',colorStop1:'rgba(255,255,255,.8)',colorStop2:'rgba(255,255,255,0)',labelType:properties['labels'],hoveredColor:false,offset:50,sliceOffset:0,labelOffset:30,type:useGradients?chartConfig["pieType"]+':gradient':chartConfig["pieType"],showLabels:true,Events:{enable:true,onClick:function(node){if(!node||SUGAR.util.isTouchScreen())return;if(node.link=='undefined'||node.link=='')return;window.location.href=node.link;}},Label:{type:labelType,size:12,family:css["font-family"],color:css["color"]},Tips:{enable:true,onShow:function(tip,elem){if(elem.link!='undefined'&&elem.link!=''){drillDown=(SUGAR.util.isTouchScreen())?"
Click to drilldown":"
Click to drilldown";}else{drillDown="";} +if(elem.valuelabel!='undefined'&&elem.valuelabel!=undefined&&elem.valuelabel!=''){value="elem.valuelabel";}else{value="elem.value";} +eval("tip.innerHTML = '' + elem.label + ': ' + "+value+" + ' - ' + elem.percentage + '%' + drillDown");}}});pieChart.loadJSON(json);var list=$jit.id('legend'+chartId);var legend=pieChart.getLegend(),cols=(typeof SUGAR=='undefined'||typeof SUGAR.mySugar=='undefined')?8:4,rows=Math.ceil(legend["name"].length/cols);table="";var j=0;for(i=0;i";for(td=0;td';if(legend["name"][j]!=undefined){table+='
 
'+legend["name"][j];} +table+='';j++;} +table+="";} +table+="
";list.innerHTML=table;$jit.util.saveImageTest(chartId,jsonFilename,chartConfig["imageExportType"]);}} +var callback={success:handleSuccess,failure:handleFailure,argument:{foo:'foo',bar:''}};var request=YAHOO.util.Connect.asyncRequest('GET',jsonFilename+"?r="+new Date().getTime(),callback);break;case"funnelChart":var handleFailure=function(o){alert('fail');if(o.responseText!==undefined){alert('failed');}} +var handleSuccess=function(o){if(o.responseText!==undefined&&o.responseText!="No Data"){var json=eval('('+o.responseText+')');var properties=$jit.util.splat(json.properties)[0];var funnelChart=new $jit.FunnelChart({injectInto:chartId,animate:false,renderBackground:chartConfig['imageExportType']=="jpg"?true:false,backgroundColor:'rgb(255,255,255)',colorStop1:'rgba(255,255,255,.8)',colorStop2:'rgba(255,255,255,0)',orientation:"vertical",hoveredColor:false,Title:{text:properties['title'],size:16,color:'#444444',offset:20},Subtitle:{text:properties['subtitle'],size:11,color:css["color"],offset:20},segmentOffset:20,Margin:{top:20,left:20,right:20,bottom:20},Events:{enable:true,onClick:function(node){if(!node||SUGAR.util.isTouchScreen())return;if(node.link=='undefined'||node.link=='')return;window.location.href=node.link;}},labelOffset:10,type:useGradients?chartConfig["funnelType"]+':gradient':chartConfig["funnelType"],showAggregates:true,showLabels:true,Label:{type:labelType,size:12,family:css["font-family"],color:css["color"],colorAlt:"#ffffff"},Tips:{enable:true,onShow:function(tip,elem){if(elem.link!='undefined'&&elem.link!=''){drillDown=(SUGAR.util.isTouchScreen())?"
Click to drilldown":"
Click to drilldown";}else{drillDown="";} +if(elem.valuelabel!='undefined'&&elem.valuelabel!=undefined&&elem.valuelabel!=''){value="elem.valuelabel";}else{value="elem.value";} +eval("tip.innerHTML = '' + elem."+chartConfig["tip"]+" + ': ' + "+value+" + ' - ' + elem.percentage + '%' + drillDown");}}});funnelChart.loadJSON(json);var list=$jit.id('legend'+chartId);var legend=funnelChart.getLegend(),cols=(typeof SUGAR=='undefined'||typeof SUGAR.mySugar=='undefined')?8:4,rows=Math.ceil(legend["name"].length/cols);table="";var j=0;for(i=0;i";for(td=0;td';if(legend["name"][j]!=undefined){table+='
 
'+legend["name"][j];} +table+='';j++;} +table+="";} +table+="
";list.innerHTML=table;$jit.util.saveImageTest(chartId,jsonFilename,chartConfig["imageExportType"]);}} +var callback={success:handleSuccess,failure:handleFailure,argument:{foo:'foo',bar:''}};var request=YAHOO.util.Connect.asyncRequest('GET',jsonFilename+"?r="+new Date().getTime(),callback);break;case"gaugeChart":var handleFailure=function(o){alert('fail');if(o.responseText!==undefined){alert('failed');}} +var handleSuccess=function(o){if(o.responseText!==undefined){var json=eval('('+o.responseText+')');var properties=$jit.util.splat(json.properties)[0];var gaugeChart=new $jit.GaugeChart({injectInto:chartId,animate:false,renderBackground:chartConfig['imageExportType']=="jpg"?true:false,backgroundColor:'rgb(255,255,255)',colorStop1:'rgba(255,255,255,.8)',colorStop2:'rgba(255,255,255,0)',labelType:properties['labels'],hoveredColor:false,Title:{text:properties['title'],size:16,color:'#444444',offset:20},Subtitle:{text:properties['subtitle'],size:11,color:css["color"],offset:5},offset:20,gaugeStyle:{backgroundColor:'#aaaaaa',borderColor:'#999999',needleColor:'rgba(255,0,0,.8)',borderSize:4,positionFontSize:24,positionOffset:2},type:useGradients?chartConfig["gaugeType"]+':gradient':chartConfig["gaugeType"],showLabels:true,Events:{enable:true,onClick:function(node){if(!node||SUGAR.util.isTouchScreen())return;if(node.link=='undefined'||node.link=='')return;window.location.href=node.link;}},Label:{type:labelType,size:12,family:css["font-family"],color:css["color"]},Tips:{enable:true,onShow:function(tip,elem){if(elem.link!='undefined'&&elem.link!=''){drillDown=(SUGAR.util.isTouchScreen())?"
Click to drilldown":"
Click to drilldown";}else{drillDown="";} +if(elem.valuelabel!='undefined'&&elem.valuelabel!=undefined&&elem.valuelabel!=''){value="elem.valuelabel";}else{value="elem.value";} +eval("tip.innerHTML = '' + elem.label + ': ' + "+value+" + drillDown");}}});gaugeChart.loadJSON(json);var list=$jit.id('legend'+chartId);var legend=gaugeChart.getLegend(),cols=(typeof SUGAR=='undefined'||typeof SUGAR.mySugar=='undefined')?8:4,rows=Math.ceil(legend["name"].length/cols);table="";var j=1;for(i=0;i";for(td=0;td';if(legend["name"][j]!=undefined){table+='
 
'+legend["name"][j];} +table+='';j++;} +table+="";} +table+="
";list.innerHTML=table;$jit.util.saveImageTest(chartId,jsonFilename,chartConfig["imageExportType"]);}} +var callback={success:handleSuccess,failure:handleFailure,argument:{foo:'foo',bar:''}};var request=YAHOO.util.Connect.asyncRequest('GET',jsonFilename+"?r="+new Date().getTime(),callback);break;}} \ No newline at end of file diff --git a/include/SugarCharts/Jit/tpls/DashletGenericChartScript.tpl b/include/SugarCharts/Jit/tpls/DashletGenericChartScript.tpl new file mode 100644 index 00000000..9e040ab5 --- /dev/null +++ b/include/SugarCharts/Jit/tpls/DashletGenericChartScript.tpl @@ -0,0 +1,51 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} + + \ No newline at end of file diff --git a/include/SugarCharts/Jit/tpls/chart.tpl b/include/SugarCharts/Jit/tpls/chart.tpl new file mode 100644 index 00000000..507dccd5 --- /dev/null +++ b/include/SugarCharts/Jit/tpls/chart.tpl @@ -0,0 +1,76 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} + +{if !$error} + + +
+
+
+
+
+
+
+{else} + +{$error} +{/if} \ No newline at end of file diff --git a/include/SugarCharts/JsChart.php b/include/SugarCharts/JsChart.php new file mode 100644 index 00000000..618aefa4 --- /dev/null +++ b/include/SugarCharts/JsChart.php @@ -0,0 +1,675 @@ +chartId = $name; + $this->height = $height; + $this->width = $width; + $this->xmlFile = $xmlFile; + $this->chartType = $this->chart_properties['type']; + + + $style = array(); + $chartConfig = array(); + $xmlStr = $this->processXML($this->xmlFile); + $json = $this->buildJson($xmlStr); + $this->saveJsonFile($json); + $this->ss->assign("chartId", $this->chartId); + $this->ss->assign("filename", $this->jsonFilename); + + + $dimensions = $this->getChartDimensions($xmlStr); + $this->ss->assign("width", $dimensions['width']); + $this->ss->assign("height", $dimensions['height']); + $config = $this->getConfigProperties(); + $style['gridLineColor'] = str_replace("0x","#",$config->gridLines); + $style['font-family'] = $config->labelFontFamily; + $style['color'] = str_replace("0x","#",$config->labelFontColor); + $this->ss->assign("css", $style); + foreach($this->getChartConfigParams($xmlStr) as $key => $value) { + $chartConfig[$key] = $value; + } + $chartConfig['imageExportType'] = $this->image_export_type; + $this->ss->assign("config", $chartConfig); + if($json == "No Data") { + $this->ss->assign("error", "No Data"); + } + + if(!$this->isSupported($this->chartType)) { + $this->ss->assign("error", "Unsupported Chart Type"); + } + + + $file = ""; + + return $this->ss->fetch($file); + } + + + function getDashletScript($id,$xmlFile="") { + + global $sugar_config, $current_user, $current_language; + $this->id = $id; + $this->chartId = $id; + $this->xmlFile = (!$xmlFile) ? $sugar_config['tmp_dir']. $current_user->id . '_' . $this->id . '.xml' : $xmlFile; + + + $style = array(); + $chartConfig = array(); + $this->ss->assign("chartId", $this->chartId); + $this->ss->assign("filename", str_replace(".xml",".js",$this->xmlFile)); + $config = $this->getConfigProperties(); + $style['gridLineColor'] = str_replace("0x","#",$config->gridLines); + $style['font-family'] = $config->labelFontFamily; + $style['color'] = str_replace("0x","#",$config->labelFontColor); + $this->ss->assign("css", $style); + $xmlStr = $this->processXML($this->xmlFile); + foreach($this->getChartConfigParams($xmlStr) as $key => $value) { + $chartConfig[$key] = $value; + } + + $chartConfig['imageExportType'] = $this->image_export_type; + $this->ss->assign("config", $chartConfig); + + $file = ""; + return $this->ss->fetch($file); + } + + function chartArray($chartsArray) { + + $customChartsArray = array(); + $style = array(); + $chartConfig = array(); + foreach($chartsArray as $id => $data) { + $customChartsArray[$id] = array(); + $customChartsArray[$id]['chartId'] = $id; + $customChartsArray[$id]['filename'] = str_replace(".xml",".js",$data['xmlFile']); + $customChartsArray[$id]['width'] = $data['width']; + $customChartsArray[$id]['height'] = $data['height']; + + $config = $this->getConfigProperties(); + $style['gridLineColor'] = str_replace("0x","#",$config->gridLines); + $style['font-family'] = (string)$config->labelFontFamily; + $style['color'] = str_replace("0x","#",$config->labelFontColor); + $customChartsArray[$id]['css'] = $style; + $xmlStr = $this->processXML($data['xmlFile']); + $xml = new SimpleXMLElement($xmlStr); + $params = $this->getChartConfigParams($xmlStr); + $customChartsArray[$id]['supported'] = ($this->isSupported($xml->properties->type)) ? "true" : "false"; + foreach($params as $key => $value) { + $chartConfig[$key] = $value; + } + $chartConfig['imageExportType'] = $this->image_export_type; + $customChartsArray[$id]['chartConfig'] = $chartConfig; + } + + return $customChartsArray; + } + + function getChartConfigParams($xmlStr) { + + $xml = new SimpleXMLElement($xmlStr); + + $chartType = $xml->properties->type; + if($chartType == "pie chart") { + return array ("pieType" => "basic","tip" => "name","chartType" => "pieChart"); + } elseif($chartType == "line chart") { + return array ("lineType" => "basic","tip" => "name","chartType" => "lineChart"); + } elseif($chartType == "funnel chart 3D") { + return array ("funnelType" => "basic","tip" => "name","chartType" => "funnelChart"); + } elseif($chartType == "gauge chart") { + return array ("gaugeType" => "basic","tip" => "name","chartType" => "gaugeChart"); + } elseif($chartType == "stacked group by chart") { + return array ("orientation" => "vertical","barType" => "stacked","tip" => "name","chartType" => "barChart"); + } elseif($chartType == "group by chart") { + return array("orientation" => "vertical", "barType" => "grouped", "tip" => "title","chartType" => "barChart"); + } elseif($chartType == "bar chart") { + return array("orientation" => "vertical", "barType" => "basic", "tip" => "label","chartType" => "barChart"); + } elseif ($chartType == "horizontal group by chart") { + return array("orientation" => "horizontal", "barType" => "stacked", "tip" => "name","chartType" => "barChart"); + } elseif ($chartType == "horizontal bar chart" || "horizontal") { + return array("orientation" => "horizontal","barType" => "basic","tip" => "label","chartType" => "barChart"); + } else { + return array("orientation" => "vertical","barType" => "stacked","tip" => "name","chartType" => "barChart"); + } + } + function getChartDimensions($xmlStr) { + if($this->getNumNodes($xmlStr) > 9 && $this->chartType != "pie chart") { + if($this->chartType == "horizontal group by chart" || $this->chartType == "horizontal bar chart") { + $diff = $this->getNumNodes($xmlStr) - 9; + $height = ($diff * (.20 * $this->height)) + $this->height; + return array("width"=>$this->width, "height"=>($height)); + } else { + return array("width"=>($this->width * 2), "height"=>$this->height); + } + } else { + return array("width"=>"100%", "height"=>$this->height); + } + } + + function checkData($xmlstr) { + $xml = new SimpleXMLElement($xmlstr); + if(sizeof($xml->data->group) > 0) { + return true; + } else { + return false; + } + } + + function getNumNodes($xmlstr) { + $xml = new SimpleXMLElement($xmlstr); + return sizeof($xml->data->group); + } + + function buildProperties($xmlstr) { + $content = $this->tab("'properties': [\n",1); + $properties = array(); + $xml = new SimpleXMLElement($xmlstr); + foreach($xml->properties->children() as $property) { + $properties[] = $this->tab("'".$property->getName()."':"."'".$property."'",2); + } + $content .= $this->tab("{\n",1); + $content .= join(",\n",$properties)."\n"; + $content .= $this->tab("}\n",1); + $content .= $this->tab("],\n",1); + return $content; + } + + function buildLabelsBarChartStacked($xmlstr) { + $content = $this->tab("'label': [\n",1); + $labels = array(); + $xml = new SimpleXMLElement($xmlstr); + foreach($xml->data->group[0]->subgroups->group as $group) { + $labels[] = $this->tab("'".$group->title."'",2); + } + $content .= join(",\n",$labels)."\n"; + $content .= $this->tab("],\n",1); + return $content; + } + + function buildLabelsBarChart($xmlstr) { + $content = $this->tab("'label': [\n",1); + $labels = array(); + $xml = new SimpleXMLElement($xmlstr); + foreach($xml->data->group as $group) { + $labels[] = $this->tab("'".$group->title."'",2); + } + $labelStr = join(",\n",$labels)."\n"; + $content .= $labelStr; + $content .= $this->tab("],\n",1); + return $content; + } + + function buildDataBarChartStacked($xmlstr) { + $content = $this->tab("'values': [\n",1); + $data = array(); + $xml = new SimpleXMLElement($xmlstr); + foreach($xml->data->group as $group) { + $groupcontent = $this->tab("{\n",1); + $groupcontent .= $this->tab("'label': '{$group->title}',\n",2); + $groupcontent .= $this->tab("'gvalue': '{$group->value}',\n",2); + $groupcontent .= $this->tab("'gvaluelabel': '{$group->label}',\n",2); + $subgroupValues = array(); + $subgroupValueLabels = array(); + $subgroupLinks = array(); + foreach($group->subgroups->group as $subgroups) { + $subgroupValues[] = $this->tab(($subgroups->value == "NULL") ? 0 : $subgroups->value,3); + $subgroupValueLabels[] = $this->tab("'".$subgroups->label."'",3); + $subgroupLinks[] = $this->tab("'".$subgroups->link."'",3); + } + $subgroupValuesStr = join(",\n",$subgroupValues)."\n"; + $subgroupValueLabelsStr = join(",\n",$subgroupValueLabels)."\n"; + $subgroupLinksStr = join(",\n",$subgroupLinks)."\n"; + + $groupcontent .= $this->tab("'values': [\n".$subgroupValuesStr,2); + $groupcontent .= $this->tab("],\n",2); + $groupcontent .= $this->tab("'valuelabels': [\n".$subgroupValueLabelsStr,2); + $groupcontent .= $this->tab("],\n",2); + $groupcontent .= $this->tab("'links': [\n".$subgroupLinksStr,2); + $groupcontent .= $this->tab("]\n",2); + $groupcontent .= $this->tab("}",1); + $data[] = $groupcontent; + } + $content .= join(",\n",$data)."\n"; + $content .= $this->tab("]",1); + return $content; + } + + function buildDataBarChartGrouped($xmlstr) { + $content = $this->tab("'values': [\n",1); + $data = array(); + $xml = new SimpleXMLElement($xmlstr); + foreach($xml->data->group as $group) { + $groupcontent = $this->tab("{\n",1); + $groupcontent .= $this->tab("'label': '{$group->title}',\n",2); + $groupcontent .= $this->tab("'gvalue': '{$group->value}',\n",2); + $groupcontent .= $this->tab("'gvaluelabel': '{$group->label}',\n",2); + $subgroupValues = array(); + $subgroupValueLabels = array(); + $subgroupLinks = array(); + $subgroupTitles = array(); + foreach($group->subgroups->group as $subgroups) { + $subgroupValues[] = $this->tab(($subgroups->value == "NULL") ? 0 : $subgroups->value,3); + $subgroupValueLabels[] = $this->tab("'".$subgroups->label."'",3); + $subgroupLinks[] = $this->tab("'".$subgroups->link."'",3); + $subgroupTitles[] = $this->tab("'".$subgroups->title."'",3); + } + $subgroupValuesStr = join(",\n",$subgroupValues)."\n"; + $subgroupValueLabelsStr = join(",\n",$subgroupValueLabels)."\n"; + $subgroupLinksStr = join(",\n",$subgroupLinks)."\n"; + $subgroupTitlesStr = join(",\n",$subgroupTitles)."\n"; + + $groupcontent .= $this->tab("'values': [\n".$subgroupValuesStr,2); + $groupcontent .= $this->tab("],\n",2); + $groupcontent .= $this->tab("'valuelabels': [\n".$subgroupValueLabelsStr,2); + $groupcontent .= $this->tab("],\n",2); + $groupcontent .= $this->tab("'links': [\n".$subgroupLinksStr,2); + $groupcontent .= $this->tab("],\n",2); + $groupcontent .= $this->tab("'titles': [\n".$subgroupTitlesStr,2); + $groupcontent .= $this->tab("]\n",2); + $groupcontent .= $this->tab("}",1); + $data[] = $groupcontent; + } + $content .= join(",\n",$data)."\n"; + $content .= $this->tab("]",1); + return $content; + } + + function buildDataBarChart($xmlstr) { + $content = $this->tab("'values': [\n",1); + $data = array(); + $xml = new SimpleXMLElement($xmlstr); + $groupcontent = ""; + $groupcontentArr = array(); + + foreach($xml->data->group as $group) { + $groupcontent = $this->tab("{\n",1); + $groupcontent .= $this->tab("'label': [\n",2); + $groupcontent .= $this->tab("'{$group->title}'\n",3); + $groupcontent .= $this->tab("],\n",2); + $groupcontent .= $this->tab("'values': [\n",2); + $groupcontent .= $this->tab(($group->value == "NULL") ? 0 : $group->value."\n",3); + $groupcontent .= $this->tab("],\n",2); + if($group->label) { + $groupcontent .= $this->tab("'valuelabels': [\n",2); + $groupcontent .= $this->tab("'{$group->label}'\n",3); + $groupcontent .= $this->tab("],\n",2); + } + $groupcontent .= $this->tab("'links': [\n",2); + $groupcontent .= $this->tab("'{$group->link}'\n",3); + $groupcontent .= $this->tab("]\n",2); + $groupcontent .= $this->tab("}",1); + $groupcontentArr[] = $groupcontent; + } + $content .= join(",\n",$groupcontentArr)."\n"; + $content .= $this->tab("]",1); + return $content; + } + + function buildLabelsPieChart($xmlstr) { + $content = $this->tab("'label': [\n",1); + $labels = array(); + $xml = new SimpleXMLElement($xmlstr); + foreach($xml->data->group as $group) { + $labels[] = $this->tab("'".$group->title."'",2); + } + $labelStr = join(",\n",$labels)."\n"; + $content .= $labelStr; + $content .= $this->tab("],\n",1); + return $content; + } + + + function buildDataPieChart($xmlstr) { + $content = $this->tab("'values': [\n",1); + $data = array(); + $xml = new SimpleXMLElement($xmlstr); + $groupcontent = ""; + $groupcontentArr = array(); + + foreach($xml->data->group as $group) { + $groupcontent = $this->tab("{\n",1); + $groupcontent .= $this->tab("'label': [\n",2); + $groupcontent .= $this->tab("'{$group->title}'\n",3); + $groupcontent .= $this->tab("],\n",2); + $groupcontent .= $this->tab("'values': [\n",2); + $groupcontent .= $this->tab("{$group->value}\n",3); + $groupcontent .= $this->tab("],\n",2); + $groupcontent .= $this->tab("'valuelabels': [\n",2); + $groupcontent .= $this->tab("'{$group->label}'\n",3); + $groupcontent .= $this->tab("],\n",2); + $groupcontent .= $this->tab("'links': [\n",2); + $groupcontent .= $this->tab("'{$group->link}'\n",3); + $groupcontent .= $this->tab("]\n",2); + $groupcontent .= $this->tab("}",1); + $groupcontentArr[] = $groupcontent; + } + + + $content .= join(",\n",$groupcontentArr)."\n"; + $content .= $this->tab("\n]",1); + return $content; + } + + function buildLabelsGaugeChart($xmlstr) { + $content = $this->tab("'label': [\n",1); + $labels = array(); + $xml = new SimpleXMLElement($xmlstr); + foreach($xml->data->group as $group) { + $labels[] = $this->tab("'".$group->title."'",2); + } + $labelStr = join(",\n",$labels)."\n"; + $content .= $labelStr; + $content .= $this->tab("],\n",1); + return $content; + } + + function buildDataGaugeChart($xmlstr) { + $content = $this->tab("'values': [\n",1); + $data = array(); + $xml = new SimpleXMLElement($xmlstr); + foreach($xml->data->group as $group) { + $groupcontent = $this->tab("{\n",1); + $groupcontent .= $this->tab("'label': '{$group->title}',\n",2); + $groupcontent .= $this->tab("'gvalue': '{$group->value}',\n",2); + $finalComma = ($group->title != "GaugePosition") ? "," : ""; + $groupcontent .= $this->tab("'gvaluelabel': '{$group->label}'{$finalComma}\n",2); + $subgroupTitles = array(); + $subgroupValues = array(); + $subgroupValueLabels = array(); + $subgroupLinks = array(); + + if(is_object($group->subgroups->group)) { + foreach($group->subgroups->group as $subgroups) { + $subgroupTitles[] = $this->tab("'".$subgroups->title."'",3); + //$subgroupValues[] = $this->tab($subgroups->value,3); + $subgroupValues[] = $subgroups->value; + $subgroupValueLabels[] = $this->tab("'".$subgroups->label."'",3); + $subgroupLinks[] = $this->tab("'".$subgroups->link."'",3); + } + $subgroupTitlesStr = join(",\n",$subgroupTitles)."\n"; + $subgroupValuesStr = join(",\n",$subgroupValues)."\n"; + $subgroupValueLabelsStr = join(",\n",$subgroupValueLabels)."\n"; + $subgroupLinksStr = join(",\n",$subgroupLinks)."\n"; + + //$groupcontent .= $this->tab("'labels': [\n".$subgroupTitlesStr,2); + //$groupcontent .= $this->tab("],\n",2); + $val = ((int)$subgroupValues[1] == (int)$subgroupValues[0]) ? $this->tab($subgroupValues[1],3)."\n" : $this->tab($subgroupValues[1] - $subgroupValues[0],3)."\n"; + + $groupcontent .= $this->tab("'values': [\n".$val,2); + $groupcontent .= $this->tab("],\n",2); + $groupcontent .= $this->tab("'valuelabels': [\n".$subgroupValueLabelsStr,2); + $groupcontent .= $this->tab("]\n",2); + //$groupcontent .= $this->tab("'links': [\n".$subgroupLinksStr,2); + //$groupcontent .= $this->tab("]\n",2); + + } + + $groupcontent .= $this->tab("}",1); + $data[] = $groupcontent; + + } + + $content .= join(",\n",$data)."\n"; + + + $content .= $this->tab("]",1); + return $content; + } + + + function getConfigProperties() { + $path = SugarThemeRegistry::current()->getImageURL('sugarColors.xml',false); + + if(!file_exists($path)) { + $GLOBALS['log']->debug("Cannot open file ($path)"); + } + $xmlstr = file_get_contents($path); + $xml = new SimpleXMLElement($xmlstr); + return $xml->charts; + } + + function buildChartColors() { + + $content = $this->tab("'color': [\n",1); + $colorArr = array(); + $xml = $this->getConfigProperties(); + $colors = ($this->chartType == "gauge chart") ? $xml->gaugeChartElementColors->color : $xml->chartElementColors->color; + foreach($colors as $color) { + $colorArr[] = $this->tab("'".str_replace("0x","#",$color)."'",2); + } + $content .= join(",\n",$colorArr)."\n"; + $content .= $this->tab("],\n",1); + + return $content; + + } + + function buildJson($xmlstr){ + if($this->checkData($xmlstr)) { + $content = "{\n"; + if ($this->chartType == "pie chart" || $this->chartType == "funnel chart 3D") { + $content .= $this->buildProperties($xmlstr); + $content .= $this->buildLabelsPieChart($xmlstr); + $content .= $this->buildChartColors(); + $content .= $this->buildDataPieChart($xmlstr); + } + elseif ($this->chartType == "gauge chart") { + $content .= $this->buildProperties($xmlstr); + $content .= $this->buildLabelsGaugeChart($xmlstr); + $content .= $this->buildChartColors(); + $content .= $this->buildDataGaugeChart($xmlstr); + } + elseif ($this->chartType == "horizontal bar chart" || $this->chartType == "bar chart") { + $content .= $this->buildProperties($xmlstr); + $content .= $this->buildLabelsBarChart($xmlstr); + $content .= $this->buildChartColors(); + $content .= $this->buildDataBarChart($xmlstr); + } + elseif ($this->chartType == "group by chart") { + $content .= $this->buildProperties($xmlstr); + $content .= $this->buildLabelsBarChartStacked($xmlstr); + $content .= $this->buildChartColors(); + $content .= $this->buildDataBarChartGrouped($xmlstr); + } else { + $content .= $this->buildProperties($xmlstr); + $content .= $this->buildLabelsBarChartStacked($xmlstr); + $content .= $this->buildChartColors(); + $content .= $this->buildDataBarChartStacked($xmlstr); + } + $content .= "\n}"; + return $content; + } else { + return "No Data"; + } + } + + function buildHTMLLegend($xmlFile) { + $xmlstr = $this->processXML($xmlFile); + $xml = new SimpleXMLElement($xmlstr); + $this->chartType = $xml->properties->type; + $html = ""; + + if ($this->chartType == "group by chart" || $this->chartType == "horizontal group by chart") { + $groups = $xml->data->group[0]->subgroups->group; + $items = (sizeof($xml->data->group[0]->subgroups->group) <= 5) ? 5 : sizeof($xml->data->group[0]->subgroups->group); + } else { + $groups = $xml->data->group; + $items = (sizeof($xml->data->group) <= 5) ? 5 : sizeof($xml->data->group); + } + + $rows = ceil($items/5); + $fullItems = $rows * 5; + $remainder = ($items < $fullItems) ? $fullItems - $items : 0; + $i = 0; + $x = 0; + + + $colorArr = array(); + $xmlColors = $this->getConfigProperties(); + $colors = ($this->chartType == "gauge chart") ? $xmlColors->gaugeChartElementColors->color : $xmlColors->chartElementColors->color; + + foreach($colors as $color) { + $colorArr[] = str_replace("0x","#",$color); + } + + + foreach($groups as $group) { + if($i == 5) {$i = 0;} + $html .= ($i == 0) ? "" : ""; + $html .= ""; + $html .= ""; + $html .= ($x+1 == $items) ? "" : ""; + $html .= ($i == 4) ? "" : ""; + $x++; + $i++; + } + + + $html .= "
"; + $html .= "
     
"; + $html .= "
"; + $html .= $group->title; + $html .= "
"; + return $html; + } + + function saveJsonFile($jsonContents) { + + $this->jsonFilename = str_replace(".xml",".js",$this->xmlFile); + //$jsonContents = mb_convert_encoding($jsonContents, 'UTF-16LE', 'UTF-8'); + + // open file + if (!$fh = sugar_fopen($this->jsonFilename, 'w')) { + $GLOBALS['log']->debug("Cannot open file ($this->jsonFilename)"); + return; + } + + // write the contents to the file + if (fwrite($fh,$jsonContents) === FALSE) { + $GLOBALS['log']->debug("Cannot write to file ($this->jsonFilename)"); + return false; + } + + $GLOBALS['log']->debug("Success, wrote ($jsonContents) to file ($this->jsonFilename)"); + + fclose($fh); + return true; + } + + function get_image_cache_file_name ($xmlFile,$ext = ".png") { + $filename = str_replace("/xml/","/images/",str_replace(".xml",$ext,$xmlFile)); + + return $filename; + } + + + function getXMLChartProperties($xmlStr) { + $props = array(); + $xml = new SimpleXMLElement($xmlstr); + foreach($xml->properties->children() as $properties) { + $props[$properties->getName()] = $properties; + } + return $props; + } + + function processXML($xmlFile) { + + if(!file_exists($xmlFile)) { + $GLOBALS['log']->debug("Cannot open file ($xmlFile)"); + } + + $pattern = array(); + $replacement = array(); + $content = file_get_contents($xmlFile); + $content = mb_convert_encoding($content, 'UTF-8','UTF-16LE' ); + $pattern[] = '/\([a-zA-Z0-9#?&%.;\[\]\/=+_-\s]+)\<\/link\>/e'; + $replacement[] = "''.urlencode(\"$1\").''"; +// $pattern[] = '/NULL/e'; +// $replacement[] = ""; + return preg_replace($pattern,$replacement, $content); + } + + +} + +?> \ No newline at end of file diff --git a/include/SugarCharts/SugarChart.php b/include/SugarCharts/SugarChart.php new file mode 100644 index 00000000..18c05199 --- /dev/null +++ b/include/SugarCharts/SugarChart.php @@ -0,0 +1,841 @@ +db = &DBManagerFactory::getInstance(); + $this->ss = new Sugar_Smarty(); + + $this->chart_yAxis['yMin'] = 0; + $this->chart_yAxis['yMax'] = 0; + + + if ($GLOBALS['current_user']->getPreference('currency')){ + + $currency = new Currency(); + $currency->retrieve($GLOBALS['current_user']->getPreference('currency')); + $this->div = $currency->conversion_rate; + $this->currency_symbol = $currency->symbol; + } + else{ + $this->currency_symbol = $GLOBALS['sugar_config']['default_currency_symbol']; + $this->div = 1; + $this->is_currency = false; + } + $this->image_export_type = (extension_loaded('gd') && function_exists('gd_info')) ? "png" : "jpg"; + } + + function getData($query){ + $result = $this->db->query($query); + + $row = $this->db->fetchByAssoc($result); + + while ($row != null){ + $this->data_set[] = $row; + $row = $this->db->fetchByAssoc($result); + } + } + + function constructBaseURL(){ + $numParams = 0; + $url = 'index.php?'; + + foreach ($this->base_url as $param => $value){ + if ($numParams == 0){ + $url .= $param . '=' . $value; + } + else{ + $url .= '&' .$param . '=' .$value; + } + $numParams++; + } + + return $url; + } + + function constructURL(){ + $url = $this->constructBaseURL(); + foreach ($this->url_params as $param => $value){ + if ($param == 'assigned_user_id') $param = 'assigned_user_id[]'; + if (is_array($value)){ + foreach($value as $multiple){ + $url .= '&' . $param . '=' . urlencode($multiple); + } + } + else{ + $url .= '&' . $param . '=' . urlencode($value); + } + } + return $url; + } + + function setData($dataSet){ + $this->data_set = $dataSet; + } + + function setProperties($title, $subtitle, $type, $legend='on', $labels='value', $print='on'){ + $this->chart_properties['title'] = $title; + $this->chart_properties['subtitle'] = $subtitle; + $this->chart_properties['type'] = $type; + $this->chart_properties['legend'] = $legend; + $this->chart_properties['labels'] = $labels; + } + + function setDisplayProperty($property, $value){ + $this->chart_properties[$property] = $value; + } + + function setColors($colors = array()){ + $this->colors_list = $colors; + } + + /** + * returns the header for the constructed xml file for sugarcharts + * + * @param nothing + * @return string $header XML header + */ + function xmlHeader(){ + $header = "\n"; + $header .= "\n"; + + return $header; + } + + /** + * returns the footer for the constructed xml file for sugarcharts + * + * @param nothing + * @return string $footer XML footer + */ + function xmlFooter(){ + $footer = ""; + + return $footer; + } + + /** + * returns the properties tag for the constructed xml file for sugarcharts + * + * @param nothing + * @return string $properties XML properties tag + */ + function xmlProperties(){ + // open the properties tag + $properties = $this->tab("",1); + + // grab the property and value from the chart_properties variable + foreach ($this->chart_properties as $key => $value){ + $properties .= $this->tab("<$key>$value",2); + } + + if (!empty($this->colors_list)){ + // open the colors tag + $properties .= $this->tab("",2); + foreach ($this->colors_list as $color){ + $properties .= $this->tab("$color",3); + } + + // close the colors tag + $properties .= $this->tab("",2); + } + + // close the properties tag + $properties .= $this->tab("",1); + + return $properties; + } + + /** + * returns the y-axis values for the chart + * + * @param nothing + * @return string $yAxis XML yAxis tag + */ + function xmlYAxis(){ + $this->chart_yAxis['yStep'] = '100'; + $this->chart_yAxis['yLog'] = '1'; + $this->chart_yAxis['yMax'] = $this->is_currency ? $this->convertCurrency($this->chart_yAxis['yMax']) : $this->chart_yAxis['yMax']; + $max = $this->chart_yAxis['yMax']; + $exp = ($max == 0) ? 1 : floor(log10($max)); + $baseval = $max / pow(10, $exp); + + // steps will be 10^n, 2*10^n, 5*10^n (where n >= 0) + if ($baseval > 0 && $baseval <= 1){ + $step = 2 * pow(10, $exp-1); + } + else if ($baseval > 1 && $baseval <= 3){ + $step = 5 * pow(10, $exp-1); + } + else if ($baseval > 3 && $baseval <= 6){ + $step = 10 * pow(10, $exp-1); + } + else if ($baseval > 6 && $baseval <= 10){ + $step = 20 * pow(10, $exp-1); + } + + // edge cases for values less than 10 + if ($max == 0 || $step < 1){ + $step = 1; + } + + $this->chart_yAxis['yStep'] = $step; + + // to compensate, the yMax should be at least one step above the max value + $this->chart_yAxis['yMax'] += $this->chart_yAxis['yStep']; + + $yAxis = $this->tab("" ,1); + + foreach ($this->chart_yAxis as $key => $value){ + $yAxis .= $this->tab("<$key>$value", 2); + } + + $yAxis .= $this->tab("" ,1); + + return $yAxis; + } + + /** + * returns the total amount value for the group by field + * + * @param group by field + * @return int $total total value + */ + function calculateTotal($group_by){ + $total = 0; + + for($i =0; $i < count($this->data_set); $i++){ + if ($this->data_set[$i][$this->group_by[0]] == $group_by){ + $total += $this->data_set[$i]['total']; + } + } + return $total; + } + + /** + * returns text with tabs appended before it + * + * @param string $str input string + * int $depth number of times to tab + * @return string with tabs appended before it + */ + function tab($str, $depth){ + return str_repeat("\t", $depth) . $str . "\n"; + } + + /** + * returns xml data format + * + * @param none + * @return string with xml data format + */ + function processData(){ + $data = array(); + + $group_by = $this->group_by[0]; + if (isset($this->group_by[1])){ + $drill_down = $this->group_by[1]; + } + + $prev_group_by = ''; + + for($i =0; $i < count($this->data_set); $i++){ + if ($this->data_set[$i][$group_by] != $prev_group_by){ + $prev_group_by = $this->data_set[$i][$group_by]; + $data[$this->data_set[$i][$group_by]] = array(); + } + + $data[$this->data_set[$i][$group_by]][] = $this->data_set[$i]; + + // push new item onto legend items list + if (isset($drill_down)){ + if (!in_array($this->data_set[$i][$drill_down], $this->super_set)){ + $this->super_set[] = $this->data_set[$i][$drill_down]; + } + } + } + + return $data; + } + + function processDataGroup($tablevel, $title, $value, $label, $link){ + $link = $this->forceHideDataGroupLink ? '' : $link; + $data = $this->tab('',$tablevel); + $data .= $this->tab('' . $title . '',$tablevel+1); + $data .= $this->tab('' . $value . '',$tablevel+1); + $data .= $this->tab('',$tablevel+1); + $data .= $this->tab('' . $link . '',$tablevel+1); + $data .= $this->tab('',$tablevel); + return $data; + } + + function calculateGroupByTotal($dataset){ + $total = 0; + + foreach ($dataset as $key => $value){ + $total += $value; + } + + return $total; + } + + function calculateSingleBarMax($dataset){ + $max = 0; + foreach ($dataset as $value){ + if ($value > $max){ + $max = $value; + } + } + + return $max; + } + + /** + * returns correct yAxis min/max + * + * @param value to check + * @return yAxis min and max + */ + function checkYAxis($value){ + if ($value < $this->chart_yAxis['yMin']){ + $this->chart_yAxis['yMin'] = $value; + } + else if ($value > $this->chart_yAxis['yMax']){ + $this->chart_yAxis['yMax'] = $value; + } + } + + + function convertCurrency($to_convert){ + global $locale; + $decimals = '2'; + $decimals = $locale->getPrecision(); + $amount = ($this->div == 1) ? $to_convert : round($to_convert * $this->div,$decimals); + + return $amount; + } + + function formatNumber($number, $decimals= null, $decimal_point= null, $thousands_sep= null){ + global $locale; + if(is_null($decimals)) { + $decimals = $locale->getPrecision(); + } + $seps = get_number_seperators(); + $thousands_sep = $seps[0]; + $decimal_point = $seps[1]; + return number_format($number, $decimals, $decimal_point, $thousands_sep); + } + + function getTotal(){ + $new_data = $this->processData(); + $total = 0; + foreach ($new_data as $groupByKey => $value){ + $total += $this->calculateTotal($groupByKey); + } + + return $total; + } + + function xmlDataForGroupByChart(){ + $data = ''; + foreach ($this->data_set as $key => $value){ + $amount = $this->is_currency ? $this->convertCurrency($this->calculateGroupByTotal($value)) : $this->calculateGroupByTotal($value); + $label = $this->is_currency ? ($this->currency_symbol . $this->formatNumber($amount)) : $amount; + + $data .= $this->tab('',2); + $data .= $this->tab('' . $key . '',3); + $data .= $this->tab('' . $amount . '',3); + $data .= $this->tab('',3); + $data .= $this->tab('',3); + $data .= $this->tab('',3); + + foreach ($value as $k => $v){ + $amount = $this->is_currency ? $this->convertCurrency($v) : $v; + $label = $this->is_currency ? ($this->currency_symbol . $this->formatNumber($amount)) : $amount; + + $data .= $this->tab('',4); + $data .= $this->tab('' . $k . '',5); + $data .= $this->tab('' . $amount . '',5); + $data .= $this->tab('',5); + $data .= $this->tab('',5); + $data .= $this->tab('',4); + $this->checkYAxis($v); + } + $data .= $this->tab('',3); + $data .= $this->tab('',2); + } + + return $data; + } + + function xmlDataForGaugeChart(){ + $data = ''; + $gaugePosition = $this->data_set[0]['num']; + $this->chart_yAxis['yMax'] = $this->chart_properties['gaugeTarget']; + $this->chart_yAxis['yStep'] = 1; + $data .= $this->processDataGroup(2, 'GaugePosition', $gaugePosition, $gaugePosition, ''); + $data .= $this->processGauge($gaugePosition, $this->chart_properties['gaugeTarget']); + + return $data; + } + + function xmlDataBarChart(){ + $data = ''; + $max = $this->calculateSingleBarMax($this->data_set); + $this->checkYAxis($max); + + if (isset($this->group_by[0])){ + $group_by = $this->group_by[0]; + if (isset($this->group_by[1])){ + $drill_down = $this->group_by[1]; + } + } + + foreach ($this->data_set as $key => $value){ + if ($this->is_currency){ + $value = $this->convertCurrency($value); + $label = $this->currency_symbol; + $label .= $this->formatNumber($value); + $label .= $this->thousands_symbol; + } + else{ + $label = $value; + } + + $data .= $this->tab('', 2); + $data .= $this->tab('' . $key . '', 3); + $data .= $this->tab('' . $value . '', 3); + $data .= $this->tab('', 3); + if (isset($drill_down) && $drill_down){ + if ($this->group_by[0] == 'm'){ + $additional_param = '&date_closed_advanced=' . urlencode($key); + } + else{ + $additional_param = "&" . $this->group_by[0] . "=" . urlencode($key); + } + $url = $this->constructURL() . $additional_param; + + $data .= $this->tab('' . $url . '', 3); + } + $data .= $this->tab('', 3); + $data .= $this->tab('', 3); + $data .= $this->tab('', 2); + } + return $data; + } + + function xmlDataGenericChart(){ + $data = ''; + $group_by = $this->group_by[0]; + if (isset($this->group_by[1])){ + $drill_down = $this->group_by[1]; + } + $new_data = $this->processData(); + + foreach ($new_data as $groupByKey => $value){ + $total = $this->calculateTotal($groupByKey); + $this->checkYAxis($total); + + if ($this->group_by[0] == 'm'){ + $additional_param = '&date_closed_advanced=' . urlencode($groupByKey); + } + else{ + $paramValue = (isset($value[0]['key']) && $value[0]['key'] != '') ? $value[0]['key'] : $groupByKey; + $paramValue = (isset($value[0][$this->group_by[0]."_dom_option"]) && $value[0][$this->group_by[0]."_dom_option"] != '') ? $value[0][$this->group_by[0]."_dom_option"] : $paramValue; + $additional_param = "&" . $this->group_by[0] . "=" . urlencode($paramValue); + } + + $url = $this->constructURL() . $additional_param; + + $amount = $this->is_currency ? $this->convertCurrency($total) : $total; + $label = $this->is_currency ? ($this->currency_symbol . $this->formatNumber($amount) . 'K') : $amount; + + $data .= $this->tab('',2); + $data .= $this->tab('' . $groupByKey . '',3); + $data .= $this->tab('' . $amount . '',3); + $data .= $this->tab('',3); + $data .= $this->tab('' . $url . '',3); + + $data .= $this->tab('',3); + $processed = array(); + + if (isset($drill_down) && $drill_down != ''){ + for($i =0; $i < count($new_data[$groupByKey]); $i++){ + if ($new_data[$groupByKey][$i][$group_by] == $groupByKey){ + if ($drill_down == 'user_name'){ + $drill_down_param = '&assigned_user_id[]=' . urlencode($new_data[$groupByKey][$i]['assigned_user_id']); + } + else if ($drill_down == 'm'){ + $drill_down_param = '&date_closed_advanced=' . urlencode($new_data[$groupByKey][$i][$drill_down]); + } + else{ + $paramValue = (isset($new_data[$groupByKey][$i][$drill_down."_dom_option"]) && $new_data[$groupByKey][$i][$drill_down."_dom_option"] != '') ? $new_data[$groupByKey][$i][$drill_down."_dom_option"] : $new_data[$groupByKey][$i][$drill_down]; + $drill_down_param = '&' . $drill_down . '=' . urlencode($paramValue); + } + + if($this->is_currency) { + $sub_amount = $this->formatNumber($this->convertCurrency($new_data[$groupByKey][$i]['total'])); + $sub_amount_formatted = $this->currency_symbol . $sub_amount . 'K'; + //bug: 38877 - do not format the amount for the value as it breaks the chart + $sub_amount = $this->convertCurrency($new_data[$groupByKey][$i]['total']); + } else { + $sub_amount = $new_data[$groupByKey][$i]['total']; + $sub_amount_formatted = $sub_amount; + } + + $data .= $this->processDataGroup(4, $new_data[$groupByKey][$i][$drill_down], + $sub_amount, + $sub_amount_formatted, + $url . $drill_down_param ); + array_push($processed, $new_data[$groupByKey][$i][$drill_down]); + } + } + $not_processed = array_diff($this->super_set, $processed); + foreach ($not_processed as $title){ + $data .= $this->processDataGroup(4, $title, 'NULL', '', $url); + } + } + + $data .= $this->tab('',3); + $data .= $this->tab('',2); + } + return $data; + } + + /** + * returns a name for the XML File + * + * @param string $file_id - unique id to make part of the file name + */ + public static function getXMLFileName( + $file_id + ) + { + global $sugar_config, $current_user; + + $filename = $sugar_config['tmp_dir']. $current_user->id . '_' . $file_id . '.xml'; + + if ( !is_dir(dirname($filename)) ) + create_cache_directory(str_ireplace($GLOBALS['sugar_config']['cache_dir'],"",$filename)); + + return $filename; + } + + public function processXmlData(){ + $data = ''; + + if ($this->chart_properties['type'] == 'group by chart'){ + $data .= $this->xmlDataForGroupByChart(); + } + else if ($this->chart_properties['type'] == 'bar chart' || $this->chart_properties['type'] == 'horizontal bar chart'){ + $data .= $this->xmlDataBarChart(); + } + else{ + $data .= $this->xmlDataGenericChart(); + } + + return $data; + } + + function xmlData(){ + $data = $this->tab('',1); + $data .= $this->processXmlData(); + $data .= $this->tab('',1); + + return $data; + } + + /** + * function to generate XML and return it + * + * @param none + * @return string $xmlContents with xml information + */ + function generateXML($xmlDataName = false){ + $xmlContents = $this->xmlHeader(); + $xmlContents .= $this->xmlProperties(); + $xmlContents .= $this->xmlData(); + $xmlContents .= $this->xmlYAxis(); + $xmlContents .= $this->xmlFooter(); + + return $xmlContents; + } + + /** + * function to save XML contents into a file + * + * @param string $xmlFilename location of the xml file + * string $xmlContents contents of the xml file + * @return string boolean denoting whether save has failed + */ + function saveXMLFile($xmlFilename,$xmlContents) { + global $app_strings; + global $locale; + + $xmlContents = chr(255).chr(254).mb_convert_encoding($xmlContents, 'UTF-16LE', 'UTF-8'); + + // open file + if (!$fh = sugar_fopen($xmlFilename, 'w')) { + $GLOBALS['log']->debug("Cannot open file ($xmlFilename)"); + return; + } + + // write the contents to the file + if (fwrite($fh,$xmlContents) === FALSE) { + $GLOBALS['log']->debug("Cannot write to file ($xmlFilename)"); + return false; + } + + $GLOBALS['log']->debug("Success, wrote ($xmlContents) to file ($xmlFilename)"); + + fclose($fh); + return true; + } + + /** + * generates xml file for Flash charts to use for internationalized instances + * + * @param string $xmlFile location of the XML file to write to + * @return none + */ + function generateChartStrings($xmlFile){ + global $current_language, $app_list_strings; + + $chartStringsXML = "\n"; + $chartStringsXML .= "\n"; + $chartStringsXML .= $this->tab("",1); + + if (empty($app_list_strings)) { + //set module and application string arrays based upon selected language + $app_list_strings = return_app_list_strings_language($current_language); + } + + // retrieve the strings defined at include/language/en_us.lang.php + foreach ($app_list_strings['chart_strings'] as $tag => $chart_string){ + $chartStringsXML .= $this->tab("<$tag>$chart_string",2); + } + + $chartStringsXML .= $this->tab("",1); + $chartStringsXML .= "\n"; + + $this->saveXMLFile($xmlFile, $chartStringsXML); + } + + /** + * wrapper function to return the html code containing the chart in a div + * + * @param string $name name of the div + * string $xmlFile location of the XML file + * string $style optional additional styles for the div + * @return string returns the html code through smarty + */ + function display($name, $xmlFile, $width='320', $height='480', $resize=false){ + + + // generate strings for chart if it does not exist + global $current_language, $theme, $sugar_config,$app_strings; + + $this->app_strings = $app_strings; + $this->chartStringsXML = $GLOBALS['sugar_config']['tmp_dir'].'chart_strings.' . $current_language .'.lang.xml'; + if (!file_exists($this->chartStringsXML)){ + $this->generateChartStrings($this->chartStringsXML); + } + + $templateFile = ""; + return $templateFile; + } + + function getDashletScript($id,$xmlFile="") { + + $xmlFile = (!$xmlFile) ? $sugar_config['tmp_dir']. $current_user->id . '_' . $this->id . '.xml' : $xmlFile; + $chartStringsXML = $GLOBALS['sugar_config']['tmp_dir'].'chart_strings.' . $current_language .'.lang.xml'; + + $this->ss->assign('chartName', $id); + $this->ss->assign('chartXMLFile', $xmlFile); + $this->ss->assign('chartStyleCSS', SugarThemeRegistry::current()->getCSSURL('chart.css')); + $this->ss->assign('chartColorsXML', SugarThemeRegistry::current()->getImageURL('sugarColors.xml')); + $this->ss->assign('chartLangFile', $GLOBALS['sugar_config']['tmp_dir'].'chart_strings.' . $GLOBALS['current_language'] .'.lang.xml'); + + $templateFile = ""; + return $templateFile; + } + + + /** + This function is used for localize all the characters in the Chart. And it can also sort all the dom_values by the sequence defined in the dom, but this may produce a lot of extra empty data in the xml file, when the chart is sorted by two key cols. + If the data quantity is large, it maybe a little slow. + * @param array $data_set The data get from database + string $keycolname1 We will sort by this key first + bool $translate1 Whether to trabslate the first column + string $keycolname1 We will sort by this key secondly, and it can be null, then it will only sort by the first column. + bool $translate1 Whether to trabslate the second column + bool $ifsort2 Whether to sort by the second column or just translate the second column. + * @return The sorted and translated data. + */ + function sortData($data_set, $keycolname1=null, $translate1=false, $keycolname2=null, $translate2=false, $ifsort2=false) { + //You can set whether the columns need to be translated or sorted. It the column needn't to be translated, the sorting must be done in SQL, this function will not do the sorting. + global $app_list_strings; + $sortby1[] = array(); + foreach ($data_set as $row) { + $sortby1[] = $row[$keycolname1]; + } + $sortby1 = array_unique($sortby1); + //The data is from the database, the sorting should be done in the sql. So I will not do the sort here. + if($translate1) { + $temp_sortby1 = array(); + foreach(array_keys($app_list_strings[$keycolname1.'_dom']) as $sortby1_value) { + if(in_array($sortby1_value, $sortby1)) { + $temp_sortby1[] = $sortby1_value; + } + } + $sortby1 = $temp_sortby1; + } + + //if(isset($sortby1[0]) && $sortby1[0]=='') unset($sortby1[0]);//the beginning of lead_source_dom is blank. + if(isset($sortby1[0]) && $sortby1[0]==array()) unset($sortby1[0]);//the beginning of month after search is blank. + + if($ifsort2==false) $sortby2=array(0); + + if($keycolname2!=null) { + $sortby2 = array(); + foreach ($data_set as $row) { + $sortby2[] = $row[$keycolname2]; + } + //The data is from the database, the sorting should be done in the sql. So I will not do the sort here. + $sortby2 = array_unique($sortby2); + if($translate2) { + $temp_sortby2 = array(); + foreach(array_keys($app_list_strings[$keycolname2.'_dom']) as $sortby2_value) { + if(in_array($sortby2_value, $sortby2)) { + $temp_sortby2[] = $sortby2_value; + } + } + $sortby2 = $temp_sortby2; + } + } + + $data=array(); + + foreach($sortby1 as $sort1) { + foreach($sortby2 as $sort2) { + if($ifsort2) $a=0; + foreach($data_set as $key => $value){ + if($value[$keycolname1] == $sort1 && (!$ifsort2 || $value[$keycolname2]== $sort2)) { + if($translate1) { + $value[$keycolname1.'_dom_option'] = $value[$keycolname1]; + $value[$keycolname1] = $app_list_strings[$keycolname1.'_dom'][$value[$keycolname1]]; + } + if($translate2) { + $value[$keycolname2.'_dom_option'] = $value[$keycolname2]; + $value[$keycolname2] = $app_list_strings[$keycolname2.'_dom'][$value[$keycolname2]]; + } + array_push($data, $value); + unset($data_set[$key]); + $a=1; + } + } + if($ifsort2 && $a==0) {//Add 0 for sorting by the second column, if the first row doesn't have a certain col, it will fill the column with 0. + $val=array(); + $val['total'] = 0; + $val['count'] = 0; + if($translate1) { + $val[$keycolname1] = $app_list_strings[$keycolname1.'_dom'][$sort1]; + $val[$keycolname1.'_dom_option'] = $sort1; + } + else { + $val[$keycolname1] = $sort1; + } + if($translate2) { + $val[$keycolname2] = $app_list_strings[$keycolname2.'_dom'][$sort2]; + $val[$keycolname2.'_dom_option'] = $sort2; + } + elseif($keycolname2!=null) { + $val[$keycolname2] = $sort2; + } + array_push($data, $val); + } + } + } + return $data; + } + + function getChartResources() { + + $resources = ""; + return $resources; + } + + function getMySugarChartResources() { + + $mySugarRources = ""; + return $mySugarResources; + } + + /** + * wrapper function to return chart array after any additional processing + * + * @param array $chartsArray array of chart config items that need processing + * @return array $chartArray after it has been process + */ + function chartArray($chartsArray) { + + return $chartsArray; + } + +} // end class def diff --git a/include/SugarCharts/SugarChartFactory.php b/include/SugarCharts/SugarChartFactory.php new file mode 100644 index 00000000..196ab1b0 --- /dev/null +++ b/include/SugarCharts/SugarChartFactory.php @@ -0,0 +1,93 @@ +debug("using default engine include/SugarCharts/".$defaultEngine."/".$defaultEngine.$module.".php"); + require_once("include/SugarCharts/".$defaultEngine."/".$defaultEngine.$module.".php"); + } + + $className = $chartEngine.$module; + return new $className(); + + } + +} + +?> diff --git a/include/SugarCharts/swf/barChart.swf b/include/SugarCharts/swf/barChart.swf new file mode 100644 index 0000000000000000000000000000000000000000..916cd957463548173c34984565972d6d3c277986 GIT binary patch literal 11828 zcmV-4F3ZtFS5pUXng9TJob7!HbR5TVXwU5I?kpCI8w3x40!dLk#7m?k>i`Lml(?Wo zE+~MyXxZQrSOQBfu+Z*80OZJ~Y{{Z7NVX%yv}K2q6@J;@IxJc8k;GJN*%lSW{xAOj zMR`B|PqF=8;#i55_v3s!KJcrmyJxy*W^qMw{9Xb+&Q5n%RbSQBRnOdfn55+t~ji z+Rxu4X){)nXk7xdzx>K4fAghfOLMmzdV`4^ESW<{=1@yHSd>F|c3`l?v)K&MVRjQ+ z!i)`2i{~G$d+D)9Hu!51e|73zOPXK&OkqUi5Ro~AWe#I=da%)YhufMqB5Tv%EzXB_GONWifo1080*D6up-a) z*S+-gP(Vc*4;vfC)<8{e{m83RB9980M@(<63MUU?~x{IqJy|#4dr~ zO4j@Ov9sx)v8T4i+21hW52_aYt!1U`2x}W@P3N)$!`oNpfZEC(ZJS4SK;~Bh10*1$ z_E0Unoy@T+gzhbkmsonVl<&#jo?*qlLOz#cWBEe=jfM0Gkz=L7Y?0-MuO2RC3VRCa zp$tavO7|V_9qMDfgBfgoR?3W*I{9nwShl}3NHI6kTkklVGNBQhrz~b0VWZ0pnPH}c zLKuQy%MQ0;Y@`{V(NBi4a)*eBO@J{(fKWwhD$Jr4kecjrQ{y7Fl2TWBQWGLIL8(z} z<*u$MI~!R9uNN55yyq_bX!4G8qkrJEk2-D=td!5^4rY-z)4=gn)TBM|c5;f}1qJ-I*e`d4DEXO5ezTI@!>~-r@etILi)aOFM_N zLsz9sX~ueiH;w=k6bIA&`LUk9bS}fv!`YsZOr}4ee|ksKh0Jh?jb-`=GDU{9hN06o zm4N1t2ws7<@1U5FFUIo4gncm)Urf{&W9u={=CPeqapuNWY;T&1L7D7$)Q0fN77T?T z6yqUc1%vmc=(9?S4cnoB*obXW*l3PZIO>L7;Hp%D5^Xz7;gBy8eyb@|Gl`{Q=I2<+ z02IrxYf~7{pLO(%HPa7E?W_Bg$r@PGRFui;V1m`Ww+>ToXP$&;bCRcbQu+#pb?502 zxr&Fd9iW`6PMPdtHdW;S=yX=`lo(Hm$rKw>0P)Lg*0R@?DZC*HKk6@hoTm@?3vXzJ z56x2ec-g|oS9OVjS49J_iXBN8dT0QEbX*K^)ljYK-N5Lhg^AW=9>zhR5R*6!)Ubg! z+rRy0&BveGTFw3qJ965TVp5TjeHk1#j+A^qq}TEx4R0q`!z|VhLy*LPkd8y6xl%Tl z9nQFNQWbAZ6K{q`yn&o);&P^jonx#sbnS=O7o8l`NvD<-(!&Fped!~aTv61i4(qh$ z&GWXP=-2A>`gHj^Jpk$TRHro7X(Px2DQ4zcx1GGZRgrCoIvGmH(rQ>oHEfOhYZ#*% z)>HN{pSD1-0koTkSwBP@hJlmxh7(bbD$^*Z&IUepPR9;gj4h&?;gk$)=TvOxRHG|s zSS~Y=8Sd{rQW}Pyfaqcg=JD<(DC$z6aK-@A)(Hg&{tiPSS{eI)I9DEniCD^1V8Wu4 z3rTyN=yv7DS?_JxV)h6~W)abaiJU0N=E8(GjHHq<=i_fD%$zxzJq5eaxb!}al$&a% zQfm9p6$M2OA%ohxEQAkI6-=t2?gg%&lo&>SlqMBp)FmhP7w==8kC5A$Gyg>^s9 zUMV^3=E*k;?tW{b-9O(#I^Dkj#MnZMTH)kKa)V2&CX!Z*M5paKnA)8mE~P<87C?4^ zj9^Xd=%VA_eDYRcnCYWzKiEp6KWv!DCd1iRU%ag0B@k4oTP}vVq=WvE5Nnb`Y!%FJ zOGt=q_6e~%MTh~P1WB+r5+uPEv*-y4ffCO^bB0}vdg-$uFmsvPGPy30>-2JPEYCp7 zAMY9tW^7CYt+SBNmssB*sIR1kN-eZ+w16labfAzQ9VxQGbg^gjNRkJN&Kn^g%$8tm z^cS+ZT-Qh`n;$Mp5?5gys<5DFqcI`JkuvAd)1)WY`9dl0(@MFiVTV`29^K0oo6AA5 znKwG}E!Tb$Oibl1r?6OJ4kRU#YzoeA$UO8O=OilqR1>K-&TvTedV|!3c@d~e0e3hI zA!w4qYBUEwneS;fquGNR*scXN$~+LN`5>NO1*0r#p)SbLYPy>Q9yC_11Ki~juA>oK z4?#1 zrOeO>A4`EH%H%Rb5Sbzi9YASt9fV1UEo2On2|kx1 zF=Yn=YA~oALUIljV9L7{{@6&Sfa)z?QV6NF^f6 zlJjh}<`iMH%olGt$2%{{WhDKyCKW|!MM^6sJXdm*RTOo8idw(T$8M`iBmTpY#l zvKerdf?UAGBE7Fsi?Fs_5!Pv#Y7y4VS_BujYd$RsnCpceIgd`bFr}Kx^FZ9-j_mm% zZd@qhriB)Dvz8+t&s$R1ai3;0k-CWRw$3N3Z8P^7r+D!!b>~o*%)f;$bt|fRFIDz? zS9cTHi(McPPELZ5^USkS(UlXoqD2(_W~4U#znwNEFRUqaA}$L*Ww>!>%KNl54B0~H zY!wU>r6gO6n=3K&nF4^h#-BSZ*2_UCWQW_IU5qf{tf-9La9W_k<< z36DpWkz9@(7lV7UnOwhbwW|nARSawH9b`V zjZ@XZ9qn^M8=A^W8ILYY6X*@4L5m(gI5Co8N1$foY=VukK~_NZJd-Z4BbkBhaI%o@ z&qA(yK*mr)4;GsZf#f(yc0T?9QA!_5kF%ldFq>QjKjSRK66;x1us~S!m;ou!>Ffpr z6e=sqbu6}>bSPB7?lD*;uH0DRprm+{f@Nq)Ar(tcGF2>7OR7+@^rRRiRZ@~=#4B;B zBW@X$Nl3FPEu^KHBF&<-3N0-r(jvGFVnryAN=L=yN}kn?Y1RyBcKNhu2qVJVcT6_Q zfeKBso*C5a?5}W@#WJEbq~m(=p=cC6FiZl73l z>k})mPv(NGbO5vW02G{;*6dn$w-eiTyeqQW) zC3y0Z?kt#s#vt235SPe+DlVYDL$t<)Mt1BzN%Kko)E6q+sn2$1!TKHWNT;$ zdcMD0@z?E(H(qs6!{z%G)R<^$YBdWRb1TUOJWEf$4Km7ZroAiP(!#T)JE$5aI%lxe zmkY(dT>5#!Vknp1I!pSBndnEDy%P9%Rcc0%^X=7I+6COtvL;y`3%G18w8!!e=53U9 z5(J*>X)R*gwjZ`{gTG30x;*V;*LA_{df`0Sb)Czu#&3~b*Zs$_>v~U?b7a|dx&a&$?mfbK%mR9;T6M|Lx-0~zlGYB?-hl;e9Mqv_np zV44}2|K4GiFlg#PnLoy+>X^OJ-ehkEUf*I__C+|U$FXU)!X#(K(aXKfsv!>8?HD=@ zRy~cRUCw-KTXh!qhVSBfNK^!HmbEXA;F_(1<&B7mJdSXI)jI3`RgG7hLA@TC=rpYC)J0irY)*F=tmKb31BP?w4 zsaG0+Txm-WXes5cMcW&+!0X=?A{DJ4n}!P<7o* zT}@~&Ho+RNCS-dFnAk->p`CmoD;6he2}f7MD5uvWI_*VX+C=I!k+Q51!7Qdw*oqS2 zNJ2tgE#f)Ua-_t2Fp6AAph*e4gi>+o7MVdy<$7xyBvtY-l+x67!5U#)4T5kJNDL_kypmyK{Fgz&2rU<`JghL`cDZ-WrKPJLq z5&j~B=Ko9P@1d~MLm}*;XB?17KqnH&0}e()Lqa*$3q#PU_Ix?Kj=89~jknhVBi?nF(+6?Hv z)0~GlW6W+`-iNmdku;PY7E!{DI?R{&X*a(3lbkLF7Ivcs7oM$tY~e4(ZGqVu*t zU8Ft!w0l4c^pNM2mb2BhZD#>P?35DU2=oC&dZb8MjDe+-AEPWB|L>3>%?k+0!xS3M zmWt%SRXnD&Y<@6b!j%B>KD{z4STU~cTK>m^~j^xr4 zWt`*CY}9^y1GBOlV+JVUMRzuLVB3ptNceUQYP6n_bYFIOpc^$S?51532>9N4S0Q~y zw|6ZCVW`YNTN?ivgsVIaNsr|-V$OPx%-YAb6Pj=U_c55!7kj;Q}p#s(#3^- zaX;xHk)hU}aitk`W@yk-whsgweWr4IrjU2EV4+PP!Ig`20rTbLXjsr1j#w;mmU2)= zf%u|fLc9;-tB-$N#1(2>3>yWi!}Nyj=v^L@yCStU(Ls3b!?&HJhf@LER0`6XZ2ss` zXMGmy$vcWZ1jE-7|0#%%+?;n>*2-}~r+wF@en=)iz|%gH)4ym-A1Q*wE>cVK`hpBV zr3W&`GSQG$L^5{AQIK9FtdzDz>5Yv#Fp%MmaWvge4U50~M7{96+bMk^ON>!;-Z;7P z>r1$T)=xnWxwB9J;V`jtJWJ!cfc1fj^o`~~DsiDau|GQuk2DCSo>FE+tWff4X#Z|D z!8tXneF>qlC{cI#Gc5z|SRI#>5J6%^3A z<_{Eb+nX3=yxC=Fp9nfjjPCaoVzH6t0Y0no<$bXq4BiGM`%#&=eOSm)-}8x!Zv&Hx zz=R^_0D~A4GQ!`0m}~e z0EAieiwt+$@Yo2Dh*Inn#%i0j4lvv9)NZS}H zaC0-bj1S~CA2=p=X1&jG3nhM;P~lm!iI3cWvi^wdTVpa^>l2ZzP+e>M)1UJ`8Y}B zot=@Zw)rtGo*Cm}f7LHRuY!llr885x)SvIWX2!V8g8@Bwd6^yrVpsTyU70E~%B~dR zter-@*qmdx@#UBG3MXw;ruHA1T55vX+g&cKqHf$l%S!EHS*gQaR^rJ!p_i92dzXv0 zTi^A)d#XVZo>$rJ{38^#MBC|kb+@mmJmD&O?x7Y*Ld82hZ3v~_8(ivZ-pNw$Em!Kj zWlK%{b!|%SbEhu2gUw#+efEA0;!?hDlS+2Yp7%bxs|+s4h95DfOp2tUa$PrDxh$l8 zV73wnD9CGk0TtcE3wzx{DyrcsV)}jm#wV0+)O7%$hx!A3(Q)1w=Zk@LFy(|rhs7(C z3DJw)BJp}YOVu$xNq18eR`-0S1Kz+TenJ7fAtm(m8c#p@u!Jd~-^)5X8i&qAk8&lrX$Zfr*ERKzK$1hf=%_ zT3>CS#w1X=Z2-WvI{V!zzT42gB_*tv_lRM@HLODjP2{|ak8d{Sn^#Qxy{VveA>ZCD zi<;ANoAa}Z@Z=kfdsAFPk62;1lwAQ(P|(A;>f%XJn>*@jEz8^7(WZbzQk6Z~nT{s! z2RGhAHqcsT+KV+Z2yW7i|-X*S^5~*!lmbEvJAfhsmcSKu`#Cu#I(4` z@@veqNlH6DqUfD?Y&r39gJ<|~{yi%ASF@{mn4sd0Xnco_Y!cZ6;PAC{|bNiL(t0*<+HR4o7bm;9?L~}}6gcww# zf|O6-x?%Bsx>l8~DQA0uVduMfgUmp0pFLv59sLueL`5(tJa6UAw~CdeM?kVSl!^b2 z-(VM1pl;;oMacniVp26%pemqU-e|{m0ZY7^>rq^R(W|V07Y|?ScHYishdFs?x+COpX)Ty{Pd7L-Q1v)1vv#SKd9@#r9)J*);%*9UF z5j*9^Z9d^`_X*_yHD&Zp_(yMrGkQH4OwedTISuV}yI`sJrKXnnw>SQRZ*NqwuSj|6 z{T`AC8v*tAw7w^%nbEe@skID9f_J{mlpF91Q zhnny~dft_qYE$+W&$P?gjh>$7k9T6Qmn&;flS9Ma9o(>Y&qEI0Eym@CQD_8JH?S1| z;U0l_&pRdff(pvni}F25vG?*XxVJ^UO>x(gonzFZKsN41I^5TFya%pDZIZ}S;?dF7s=2O&%=2p}IrRN(y6`(wCjn60hvcM0LDe(u< zM}4M*%6_wfOwJC%<%{5Xmja(>^W4mxP=W->`8d+<}QhMV+sn^s{L= zjMu4H6&PFV#8UnK5Nj1S_PXA^)7nOt$J~%>eLXH(@iR^nS2_nC@LZpe^v6>EGq*U% zA1NSCJ-I7bHj>vfb%wrO`X&=F3OiJ5q0?IEF)gIF`G3PWf3==`8>{6oimxWZAIP^x zLT?{4J`&b?>a*%7{haJ4?5KTm^N1WUhW+2WIWYO0K5w~)v6Gh#;-0c>f|cQ?A#Cz6 zW$=`!{O9RI?}{er>v}qs@XQ#`bSn~wT+mi55wtoLwE9;;z9Rfe9w~RpJaylX_>zfy zU1L05`k2bFq3ov0*}JK7PTf=~yUFj77e$sIdfCqsf32`$b1s`$RCy}JtGd%v`yD^F znxW7h$eGK|OQ-vQ6N-uO1^c;XuZ@s!Y=j!o?N`~)^BO#>h}o+h@-upPgSHoJVl!dx zv%hFXl>Gqf<_Iko2Wu4kI|3n@Js?4`K31p|qjjz@$}AMBb5@KzcHd@*@d`SO~= zvkU`6wZC5E4X>i?KP!`pXgnm?E_1G=*n%YN?{%iYD z_~UuYGLWgQ5!Cy}*=MN^7xBqvLK`PxWt*|?Z?vBS+6VBc-!;?z*?~`iU#7UPXzIsT zsjUx2UVH7$_P==Twbx`MsDyt^87UDjL@V`(Zd#^NB5sT>*CVXxD@p|9I}lbwpVUh6 zC;DbB9=R?k()LAKc#j6JU{pVHllEdOxMK<~jG^`FJVp0^wEALlzL-Dt#jNqgT%gB5 z0a|uq{IkCJuhBWtXX*J8J^9|(KNHQvLtodn?0!R}y{tjLtU@`GXI<&Q3F9E!}8gtp3jH%y{eG4sn^q zGI^QBQhvPO*$BMgtr^Q$b7Xf@hxa4Rv-bHg5}Wa&jOqr!{r(naT=(^lonT+9vDo9x zVkfU-75uKDo5UwB&aubh&`I|j&~fLR7lPQ^mmkLOgh21yPZ;7$A%1g^IH8rFRVcm# zruT3vPDV?FBvjOuauI5NTUb1?u+hTa4V65(7H?A#q-QPwWgKSmY;)jOQ)g)R_7T>^ zYK$q6;GA-Q*Jz1hjyFOhEj&l4kV#$Y&FxxdvXiYWG#fdS&fJWvH!gLFNQ)mPisLG{ zgeoDIyr+bgd-f_XFW*et1^jgZ{I)>#&qfw=o@!>VO#fpC3oTYZ0pncv2r4Dl?11=E_9psRP`j>EzuSm5{aMNcN=HLM-^az>Q~YK#t2r(wR(>f} z3=f`-@)+B0t|V|g{D9v?75WEur@^%$?t9=z=qJQAO+CzWSC`f72S%!^u+j-7p@qX$ zkuqGZR!aCbkbDF^8Fnocho5g#-^_=9t*8q>6k#oMXjw?hYVPut3a^CfWiD<^+#}`1 zjrnk6guBWESL=hTZC>S69Y89vDdH-`$~bR~L|2)%;D`-ehB@Iz2=ie~+J!~W2t5<@ zwCPFroZ0n?iVV0lVg9=ae<8V6Nrqs;3AWI)-Nu{ima`F7_4<2XSyN*$(1-D2r0=}` z-gEza{V%`1x_as9KWTYZ%qQo``DD4APv{n=FeJdpZakq4Tz+jyE4zu^!HjO! zAOGIY#ZR6N(e;R*hW{t{J&85(A3XUbbMp^xyfOTjqJpbr1y{-nQigFzI5&31El;P4 zujJm)zKuN_S%we^fOvJ_<RWr^WS?uJMXa3SYLYgAD;cq&u;r_U8gAGYFWhdMG@Hsr0-H-Cb0)S%+)}r=~;H) zz4wl@N3QxVk~+cZtdVpskeAQkb1h93;`+nY?5=M=`SO{@PUB%b;fU9U(n5glq~Xni zn8r(kTGBdpm{lBR7rw+9wWjf!!^V$qoUHiXnaBAZI9P!7vH z?}en9g{u(am}kDfQWZxEkaAu$grcY_T**4w$tKh~Lj+s>!>YUv*59EJC*Uc?Tt`+846L7sTx z35&+2!N8*DtclEBe@RF97q{4t)!%KccIJdp8(?PA^H;5 z^@{?#4DbK_T<0whf8}3IEY))agPYKek6St>~N45r^A|%SJ~=@X(L^7#^w+sNddcA`hAJ2A&o21|G}3 zi;IWC{G-3-vH&;)SP_|i3-Cx#>15HgQq4O2!fMFULU)lDm z_nbxh3wof_xQ1OM9rFL)lvP%FkcwTX!GZa9SQz!04hS{EyzPla~M~ z*{_4yk~~ZSJJr$ho#PVFh~@T&D*g%P~1*kg9#4d6m=!#ga##ujo<3nuPp_9lp55-=$5c4PiO4x&808=qOA^p?;SV9w6e( z%s$2Qb4Em%PK-7h^3w_o`X<0c8!yF8Eh|MEZo|UoK^wHu&J&&_?e1XikCLECL68FO zM+L&L@lokl5%Aiy<5BO0knq2{EHuDR= zb<{3iF;fx27AF{K=GSvqDP1bZM|lL%rCf%R&9EJMwfZz;$4=9X4Abm)PcQxKTOSI& zc>SlVPv7>!0ii+dkQ&r>X>p)Q-tJ(dxq?D-bufB|L~obY77Fm4G$+<`&2|Uchwa}w z;cB&2T&wMHm02#l`+#50tOe|I%-ne4cbM_NJ*Vus0vvCOp0XJqc<5|^!W8MMc*WyT z&Cq>zvl2z4_U9lzPOddt#jGn&Mv}(}3Oe%aK{;8gC;U0@=wpz%vJDIyPauMd{(}+B0{rX7CGJ5`1HzZ<@`4X!CZ_nUba&F%-AlPLUB0`Q z{wL~g7jhY{BLJk*-cEuUa5j|FsVbI|(&C|~eTT|HmTQG;@t6KQ4PdzhP$tM-ic_rv zY`q|-8qRRLhD16?Y$lM{%!5f_?b%k{Z-OCaMEq*)UZVYC$#tHhMc93gs!mBo&z zYCmu(;BMlr*xp3C#53^!1D;&1X#AbTK5HW5%ANlgK#8U(D(B>DWr(ioL|FKVib>QO6!- z{~6pJ&*MlTcgOTEIvUP_QQ(#x{(i;l{ZXv<@0@p?EhfL{LOty4G_K~bxp~ApaJ?lE zHqa{$8O@z`%{*yS$GM)UZ#|fL`DHdwPt-RH&tKVAJbvDzY#yGdSJ4x7DGZh6;V)eJ zKQw9JO4dqrAUqBlL$SOIiiEB>{P>;qI?d15^fRXVn*Qz`_BFi|E+%b(np{hDWnD}4 z|9;m}gW^=Gm98b1^nW>(X3F5doJ#+}P9%(K3op9UxPZ~gF0)6L9C{5HZ%9p`ku9)e(Y=bYTt3g zW+!iFReraQaJxuvjFjYZD%2fK+y$fwZ5oY%jvwtRYej!kd?R}TW>>jf=iJq;EZzwQ zOz};JzrwHWPLcNK(~B&Pia7%nODYnA^HYJKir=N8Sx8h0@$V}V4i@V%4R-PgTtidq z?_Tij?EnDK4>m95^SOiB5j@pgwkyA4L0pWG8HXRbw^Up#;)Ifj|mFZeVgBy6xKi9S=we!;SR|qL8Od+rotrR}=|zKjhuq_kUm1 z+{_<{;ij)1HulTv$OoRSIq;8LG!dHg~qo156C i#vP{nMOg?;Z(Ov;{b}lf0?K^=+nb`)xc?tB_}6Yn?=WNl literal 0 HcmV?d00001 diff --git a/include/SugarCharts/swf/chart.swf b/include/SugarCharts/swf/chart.swf new file mode 100644 index 0000000000000000000000000000000000000000..e3ec231c1a1cad14acdf871f905a0908fdcaf315 GIT binary patch literal 11243 zcmV^jbkFR;9xThTz=+(+t*8ilaqM#J?79mg zc;M_z@9xO#%rY~}vM2(I3JJk`BVM1u6Yn!dje_LMffA2IV$2s4H8JKlN@6}uqEYv& zdaJ6ts=J3pp67eMpXZ^s-?QF&tLm+zt7^6&@7^u&e~<^w_w@JoS9#ZH2yLH-@=?M_ zwr4v~Lj*q(sdm(sNTt%KE7gNCMz#ypq|=dJghD9V5lPo%(G-;FZp~!V@nk#NH3~%| ziD-8sk~Nwm$#w%NC^#8;)<+WEMh3Ne`vS<1*uSe3q?X$dK087w@AD&7Q9U{e*O%Pp zLCvU7MXEjxPs)ww2>bZhG4T)55GgV%MrBq!DVv6Rm$ZB%| zrfcPW3i9F?KUkreR&c*X@G)w&749;upa_vVq5CR$8S`3W6}jJD zGrdsHysEFARS$stc|gLJztc~unU_{LpsCbaleLbs{@!F&iFIZwy1yFZ0_A-LNDY`+ z)z?TWUH~jpRR%!$`x}X(K;^EbC=!b;izkiRv=LdGK`P3hjJ)w=S9i9BHdVbdvSB`M z!I>r_O&C#LM{ie$k;E+*1zL#|W32ZQ*J!jY62o;Jd=@|q)Bw~m=*6H1T8keMA-$4v zAZUtuy-88MmE@U65J!;Bv6|h}D#QR46oHQKBjOQ-wLOdvG}lr4uu`pw>cA;$st(qy zcS#}-iQ-@_z#!eC%tY>fLfmxXuETeX0%>_zXmpcp%V%-Hihnig|)f)EvT2 zk%Gc7A}RZ=_~n+0{~M-aIy2vFGPG8LLO~Uzb`>&7tRd%7cR>M@M1bu=);p--z7k6V zZBdGz*Gx;4mM>Ptd6`P6BPOp<@Mm#buLfI{N>t_bos2u#Bid8Yd1lviMp1V%p3SVu zZpflcwl`t4bQlJEo!`=evhi%f0BT3JGqK#jFLN_pkz^>Eh-5PJCV-mdglR%0vH&!9 z8sVyxnIS36hx=>Fl`z_kWNcv!_tUAiHU`#4qHBp^21b*=Yu3jz@m9<|Kb64a06Ye0 zuB#P9XQG~XGM4J$GBe3bCYnwq619;u0WdL1{zlU2RL`P#A|Y^eXS1nf4I!ZJE`o1! zp%WRDNyK9Y=xttdvqc$66>V$05jP0*5+DYB@ivf9L+8 z9w2Npg!h@W6k0$Rd8A+H}DG@VxLm-ck3n=0ls-xOil#lDTjGhGQhc9sgI!4eoQ7qH{ExRMQ)y#mM;v#QBv+9buCwV(c78`Z5yPzb8BWFUXg7(U z;Yg=}vZ-aM9wR+Jk}+_WQ(Z2;Vjc(kY*gOEJ5X=Y%C~xU*WtqyDZ@rzQ zU^+>`WT0TkYy|2IVWP=pd%JiXqiQoO3=+IGF@YwAuxq0RmhMiHoI<5RP$8n-=`+3}Xe4ie6R8(*!6#)hmi@DLO-DWMlZ?plm?mQRZ)z_S)`cFfp`3o0Xo(le$5 z(L!J^*f29rrmxY$$Gfs~A_?63CQblyXd&*F(sM#9l524X#(YWYTWAa#Ghq@A zJsI4Zs44=)H{w7K6%n^4-1ah&L<{N1(XJtO3_>F(E8{gX7DF&MQOK}D_vqe=MwqHp z*g+l7PINyWVrbzy7{b*xO42|NkO8PghXG3-8E5JFFyb4HESUnp7ecy&e5etRQ%-jy z^C@f*8H)}tHGknPE$Wq|Oj@mD-ZBQwHZUqSV!hGAlW5L>U-i%9VlK5O|i` zqz5tSp_cR@H|b%n(nU_`qTFc@w@D9S(jzSCA-U7GOP4#P%iW|a;5pJJUCN|KS<5?)y%kkBTTw-BX}jem&Q??+OHZ;%1ewHSOCl&soMe+Ic1jcziCu%`-W4J5Mar8B zo!XyF%=OVF+L=PvfxARM(x+gKsbRUN#9hra(xYN%nn)@DiD}q?>DF?AKp$&roDsG+ z=4l{776A(K2K%7GCqKGr?9A`rQ<~pju zRC_fL8L82faR&46yoy|vlTs>8$5@mqK}JAORzOrUdo9CiNP6&A8zv5FK#UItXbMQp z2WSC<)Czm%unw18V!xh<+yxxoSZK>_6U`GaFXDqtV%{9YTp*Y?uflEU0)o=eW!HF^ z@q~>YYsTzBfk}!E^JT=A8eUSRCD}SCsCpWq7sGQ24Qlm3q4cFzQNRjg1+r+EPgJ<9 zx>2M-L)G*KCo<@U46{sINL*(dA!R3Xlh2OKL;6{!DNaSrTFe#S;+6o$FL%QiAbo|E z-Lvi4#pIP1`5ZeL|5*vfuX5y+lJIl&u4066&pt`fGTqUrk;$MMPapXdKz#oT#UZu= zG%nRwu)?x0LetTWYSQbi-o>eh^QkH{Dq)TKnSR=#oeRw8v2Ty&*FDGQBtLvk;^}!6 z>>J^ukLm?A=fm@YW^;MmkKe$wHEnc?htov*g>Cd}8vqdkY)06m-H25|m1)%2C$iRg z#Ny4iJQg86YMS6NCCDc}JvPr-!wlI!(J=EbRy{UX%59Lck64H3x1px1*mtpyzGgDK zLAL{Mj4kVTglP=8{Ir3l@X1stZFD7iLv86)XDDN&@njs&;1P@B!o2iMGnP1W7gu!_ zgf0?B9X&{D&uc*<(M$qB(F7dQOyen~vzZQI?R6;*&m??4(&|hhm+GEsCQfjvj`8pS zV!NtbmJ_{b@MNVllj=@K4YIn23cAw9dcGdl27hX&&S;i1V1|l1Cp{;sY93aw}-aQ+<{Ohrj(GnaDtqNhP^Db{vv4E{-&$gXZ@StlNkF#iQ$%hlgV=UlV1;1Y(rF%r6SQOP|?(4 zVVnof9fZoArT2>cyRZ%k=vL|7i)=-r=g5AN6^|}u-L1B2kcNh5_biQBAX=bm@I|z6 zF*O(B090<%GwjPYhJOg|)0?hhTT$wX`-0ScSGjyL=5@i$*FWvG(r52npuMSsc;}KK zUC1KVpL7%8dOP$1{x$>Oo zo(IlimC#0TX&EwAVskFmHxeBoB&Kt*L&*}t^sK~miK{Vv63-@Ap0vF(`GodeEtz*I z8SQX5fb`93u|_{O`$;1MQK2KIRYa19nG6y)0$})GUztoe;Z0!@cELHa^d>UY6c~GR zG4|RRHH&c=l1tFiB}rV8OZ6o-)feYtBqb@wjko>{f?zzPD)^x*8i;IW*=n*g^)j0v}RTn%;xv3%Yy zkQ%4g()JxRL4|-}N1{R3M90f~gOI*sAQKw<%II!Dd4G(h1as|x=eNMzZ-cqqzLTka z58J0SN6+jqB$)}*UC8!e7Xl>Ea4ZSP<8Pusm@|`IWBPhXz8oEuX=hF*kHthYGD2p; zv+hP~)@^nk+*+vfe%V3~Og3?WE>-<5V?923^z(Kw2f2z97B-KxT5O**=X$DNZo$@c z_WCb(jdpG_z|Hd_g@w|I8chS%+V}zp*u!RaLX#ytKsrV46&1Y>#zCrMg+(ysxqdRp z^Ewvu3Sga2@@)}pL&I3rOMB2pX|h09AiqPGaOPMGNg~f2;Mvs-mV5N8Rj)NSWZo1y zKH5Y*u!yr8`gI1%{73)J>#=?36=j3Yw1PCPaubyK8!0+0p~D>AD4`oUx=BJear9Xd z`Yeuame9={-6Ek|IC{B+ULJPj(QvNSo&Z()Olhspn!DrN7fK8W_QiViYuFkV0N28% zKM=jH!t|m}nxB51-Z0W`#*Q%WC$1-v{RY+n+(3Yr7;qy25bFT?2r!!g-z7kT0XGp~ z4+C}+;MWYenE-_z3fw|~1q`^A02>)_8v&kS!0iP17wKrKyws)tVe_9{g|CAud`F$R z>O$-N_h2bu9aCW(gNi-wDyDt|6?eL;_>1S*RovyS;=XU7;%;{p#y3!LkGqO7OvSy& zpyEDv6~9-gioM66;(m7(w|)Z^54fvX#Z)|KZ<^L;2B)rv+;tTkkFJN^b-jp=L)Rnj zy1J#c#IXudqMRF};g$TU+|XO=*CI4W=#84x^K?wOIR# z0bUkKws#XH=AKf%RkXABY_?^vvln(Qu4zxCS|bT_C!w${bj=2|CY?%U>0Zp1u1J*Z zvjc$dMs;reY)kYuc4x`XKh9%eOcmnp*O(EFcSaI5(P(!%673Z>nKmY^U1Q|@0?SHd zLv19@x5_5X_cS?-#FZuuBbG3liAn68GSRJN@J@*o(GX8I<7{_lh<3U$jr%LIq1i}a z*7XM4uttiKDzmn{HH&FmXs{gi05jUkc(#LX(;bK_)y*~-lf7^BtN6lXHr?Bt>dByl z(Uzq+o@O@HB_mp48?cOX+fMAVbvR}uvXNC#M+sKeL3dE&HyMrH1dg%1Cin@LQWFNq zgfNwcO2RiDE@!GzjU=}?T|$S!mQ zZwv5SV;4y)1B?qeImEEE<^rt=wwuzO&nTPxURSXn<=5aWQ-_PVB0xL z_uWdnOy&L7ohjV9VNZ0lgH)FW0+Ta$M!K`S|sGdApB3ayMh&^=(w&~Uh#|darq0a6^Hcr|R>Pe+zE7OrK_x;}4c$ah*pgkRF zZKb>M=__pdrj6OT{af1NEo>c^w~V`=aG*v^s5Fl>fW}4f4X`KQoQANC+H}{p6;yEh z?qR!$@f$t$fI8wa*u_ti=3B<&IOr_`L6jxoh;AHSU}SLt8L_ETr=q5~5u%$Ca9m+; z_12zU3kfN*_ZGGv*ugFnNC;!E$y6GLyoUL>tOyb<2ne=oW^8t@7~!<-a)3l5z zpdc>}%ElI5SVdvsttJ_dbV7%jS=VhC8;#g9dj5gdigb6TqbAvo*-3lGArh$IF%bbC z5D_$e^8gwNqKo22B8G%vBs=y(ItAOowRR&L#uB73jZAg{d^Ltnho9+*rj1C}SlHQ> z?X?c=Y(Tx{(IuQY!iyqV+zvbFc?8;RVWQMCuqe+Czh#Up$dTC1oJ+C;2D*u1wh5JP z6y7}Dsl2gbDvQ%3QDS@;KqLigPUAYQIL#?sA3x_s%r{5lkT=YcB?r1l%LOlz@W8wz zIBcfyK8wBcvv%y2vyd{MLEiDekaxuiHYspB<@61XH$kAtm_xXPIA}`<12sGnYRvwKLRy1xi zqp@K|WAhMXgdSCra4arGg&0NIXc-t*M`F;91l}PT>y@Jo63-1Q`eL_t*n%}ii8+m= zW%ewI%rXO@s2!x4M&-C{NO3u8i_1}4T#nMX4221j@CNBI_p;1mk76H1*CxppG45jv z!^?seBW@^oo<$|;I}{Clg@`1;k_-#iysdLhNj#HHaMMO|f($R!?L{~Zx z+zBHP^UyF=iwoN7#RfiRm4tIvL~AGm3m75N3`1zbBV+t^o09dLIhV`X< z+m7TS*iT%horKsHNs1W4J{OsYa_s~eF%&j+3y5LxAx=OHhr2EW#0YC6CbhA`Cz40P z#sL8_N}DJnMr-*pA|!F-A^imZp+g^4{ru3OLju zn5hku5wo=4`Xt0DcEqXn;+w6XCP1g_X9&<7{Y(LxtIrdlO1(;es`VNHs@3NUNiMLy zj8O7I)^cb$E|PZ%Q)HbRvfhEj$`<=XXbJg?p%K=8#if8))-2!KLa`0af^66)Cf4X? zL6aNuEH`Ac8?wa>xm-rB09(%XiO@>sFbbW+pjD8C)nSoe#I1DUc_E_j10qwQW8w9j!p?d|i&q8k$ z(0&Vjv4GYr^d*fsY~Mtx3MO3|&c(5racs%Sv6XRLmXqUh#<4Bz<|uB%6|PjC{*|s& zp7vF)RG#kkuv|i~_i9%vPxqRz zTV3MmUh7Kb>0akb<>_AUO6BR^5O%AqJlz{zsXX02S1M2UyRKB8?oDC0*1*%E7Z><>}rUc57}t-P>HLJl)$}sXX2PaHaBe?+6P$;P>=B0(7SZ;aGT=cI3zr zv8%mX8u#5pI(ZRsuZG8OBH}(cYbA7id)>P8`=vx5(AwJCL?sVu&pr2?hu!BwtM$(5%GkEhnXVcNxNZB*|Yn7t*56)L_Dp%{r1};;s^Fro{>1P zGoG~uN|^kdUBM6Sc0aGJSRrw|psl!HLhRG-U$H_&?8h}i^52Wn=oc5$0srpZZ&lrl zZ55C|!pMVm&o6bc&^P3K{Jkaiaux?jSP zP_ErC$Ombd)!NV@5l2Fx)_+A%#Q9wK{E)^W38w+BO~R3(i#9iZE*&VnZjDBM0S*6` zEijOI9e_9JF}J{EMd!!dexmo0&8%c(lOV5T$cUeZA$t4@%Q?oDPNWXQI8_mcaN@X# zhM+ge&6fJF>A0Mt-eNl`M#4H0zxR(~5@sA~G}=$1RG>i5F2JkvrO z3G93a+d0>=Gr+I0l$hUjRgItTu>&HG<3q3oL>egG>1FZQ+(5Yro_~;S6d5)T#ISWB z1~Um5TK`d^Wu*bOYq}uy{xM2zm8AZ3EK<0Je&A9saBlvrdO+g;S(|Kl9cdh>ehhZ0 zACfg6z?0P%(U=e2jrq&}rZFGpGUg+9V?O@hH0C2$W5g-}m7d_ea1QxIbaYPIJaW~_ z0hMhUSlQNNR<_kund)ichob7gq`QsDJtB4d?t?nFa~iHK{52(~`8d)YQN0k@kJ8+Z z%C+^FxITbba70xdln--KKFUe?z*%IZ*oF8AXK=jY#=#$3FDIRg^sn5c&+R1a z>PB|iZ82<`tU;Go4z#%67Ktai(?%$p3Xzrk5PUcbWym*Uat<3tKVMkU?%&lg?)d_S zi(j(A;}_y6NIdMnMeXB<{l}}+vag`nzh+@0$B}#MR3r-tE$#>O`on!*6hKNd`J*U{ z>0#YI)#6|YnI|=^6L+`TFBi8i>t%^1y|zSEIZ@j|e~k1f>@<=OsVLwD=r;^f0s0Gr zd;opPAU{9_3WYR)rZGqdsDVKNfYvf72+$4&(2ie z=Qo#~a`Rpx@OlQ|T_x~(2jHC|@TvpwDgv)>0N%sM;`I-}yI0`V2H@R=PA_Fj3hJ7hZsPZI1G{9b(%0r5V3G#}U8S2IvrM=rlrY@q|I+S0M_NC~^Sv z5|kCe7-)sC!EvROhp>eu#LQASlwK@Nzm`@I$x_ATLJ9uS#JndVPxwMP5ityw9<0E% z5+&Ak<{teE@KTvVyX~NL8YV!Zg&qtHQAR?D(-#V#2k82F(596e^m+x?xtpKf3s$&L z9Wh$XdBT&&XqAV{^>U0>?J=4vIVy`IjH_Z8SKY#RuRV-A>^eN?SnM*7o?>J zKpYCt30?{f185e5h6A*aK_dYAE`urndY?ff0Xj{k&?tZwGiWqG=Q1b+P$z><0BAFV z#sG9JgH8nKP6mwy=qUz`14#2xXgolx7&L))A`F@c(DMwMMDxy|$pF2}ppyXlZw8$V zkk3z{DFBr-XevOH7&MKh$Dru|ZDP<2fUaiHOn|<}pjiMt!JtzB`j|nd0yIIR&}@L3 z8FU&zTNrdYK-V$o41nh96q-Z5%b+s>`T>LH0`v)k<^lBm0EH?6`X_^`06INLp=y9O zFsKHgHyBh4P+1;@<^!~qK??x7o0Z0D781b#$1)pn8CU`4n0VPz8gQ05mlp zH;6kJMES_U`wLU;@`DAu)!SU${`D%D^hOe1P*-f`M~zij*cIc)bZ z+aJh5e=kVs59XjBVDyJ_(DyL<&vMW&WAuk}&|4XOe-3&rqraGgJ|=ja{<~B5-<`Sg zA2?3^cggzi%9Z~Br9YA@|HqsDqjLI><|==k(jUu}e@1^YSNSvgQ@P5Y(Z8Q7|BU{0 zuKY9l4|0{ier*21e;O6ZL3h*Z1%f6B)8JodG`%0@Nbhk*e?ABOI!1pX2R+T``*P5m z;R5jsA)qulA_=|d+9_$ql|ekN1O+|Lh?GB&o_wz7fS=lX-@vg?LxHmt!U}`*9Zc{i zu7Uwf3N$M@oY25z59Xjx@qfccaS|)!z3d~W6tJ7<1+wSS3b2wjn7zjo?43na#De`^ zE7%utXLkFfMIGv}9LbpLJ2|RzVm z#(8O7eI{2WidER$6JWLT8LM^%cwXQ19H(*5Qsc&%pwdX~dM-z`?L6L;ek{A;$J7m@ zJdOz;y$oh8+&Q~W)$oMQe!U966;I=ny=ll4A!v5to$OHIw!8i0PL;b9n$ZI}GP;e? zf0TnBWAy*bL0`b=KhM?vmE&~eA=#0Ks3Q-v*!NnFjcV;~7JKMljG~#m4?{9pPRMYZ!Wp9P2k%i>zt?@V_~iKqkreeQLI~5S=de z1y(3<)ITAaQHw6G`ld@w;(mCzv(%Qlm|!ES@~-tFw0#d6jItf^3`!;8C~-q-z2P{- zyJiC%JGTGC6gk=7%P1ZEC=xr9M1EMxJgV$|2so8on9LgKMQL)3Mm)_-pXBf@%5%HVzlgROc4bGA51BcDwJVkutTDjPb5hF*d;w`ikIQwm z7*Z*r3ynv&iXq4`4))QffI-mauQ`h1qdQAfj3mVn%uaJtTxweEBF3&)Y()FeSVUHH zHz4nyL#T8+ekGgTipt)>z^2584V9OFcd%T!n{obJUuSy?- zpFY%u^0y!~x*D6LV55r44sAio`}z)38rS zJ<-tl6Wjh$^X3)>k}E1p7(e-R)aw`5P8qs&^-tD4JE-IN?+w{m{h%?W;e)d9$7^by z|J4iIF8<`RO^3tVo_qW@t>&DISKso`rod^&oI=mO_n!LWvX-USmTq5NyHff2rG4=q ze>HpW$j0Ko{IIn3<@GI(-uTe;>1TUxT7L7}SFJvB$s6}Rd)FK1K2-j*w|?}&l9IJ~ z7c`YWd&JkVA`$Oim3R7z>?@VGO}Kh?-={x)qffc!H}R_Q(!~e1ObZp>aO)N0cdvdU z@T==z>HFmHV|%qln;zKw@5#eI9QNk2Wj{b|?~i@!gHv`NQfF@2f7;1czVu4^rax`* zKNWd#^|kAsoz}7N&LNlYfB285OsZab#KKm^cov6OQwEq5Aw@yaB?jq}bt2H&xAPUrLIJ^X5SYVUHat_&j!G4b0(umBzO9IECziKT;F zEv4xdxmrhP9o zw9OwVMCuMdHkneZ5g_vcStuiefXtVXIv|5G(ho>oMyi1H%SaC(RROt!ASt+w*rhVg z|KIGa@{&)JTRjlHT#P0`jMTO90bJ@8mwd5uzi_`%RsJAM8jJ@4{+e_=l7P^?IdCfe zTZVf69k{js(FsK#&m4@Zl|zRP^?PVcoruuft`OYZG;a*~twAF_rgHAIu1Z|H$N{<` zxX$hK52q2o3`hKeYE9O$s8Lv5N|JzUKXW-MbHa_gr)L!`|Z0 z*WH1hzVU@6O5~S+zrFe{t@igz?oxhRa{B?#y(e$G!8i9DmWvTQ7sGiRsm0F<)c)0z zYrfjEA1OiVgX7aal54NvkzhK0j)Jl(q-BL;C_nbfa9$G1_<2_%MJvZ>)c(<_fBh(Q zA@SgENoQ?&5D&oJo!B3!#f2Ec308SO$E@2|srRFD(-NKnES;eb~zfPr9yd)4}fVnm(bG zn-u5x(b$zkr=_oC6P|r&C&r$DR(^T=S0CQwfdSOv!-qYC(X3gsW|GI4Dbqgr;^p@i zb(OrMeA=<|#fhWU_wM^+c*l31TsU!Dam)LAFFpU=_m+JA*4AOQxBTs{lzpX zdck}v4<%FTW@g$>d%g6IUkyL+_J#MZKH@2TZRFck7ILCyoa^Qyma z7jSMrS;_#T{@++ny6`=iYx@;=1m(D`(7FSWn@g`*>+D@j?yQKn#f`MfZyh@>Nn{s# znD>0Z%^v*5L+Q83SkCxPnLIN2#re1Zn+R9ODt4NpeadMbVQ)eXx}?`X6|Ta^q1w2WQ2|X#x^#8WJ~_w5nzvu zWH7(1JeEe%n2|=zj4T<##tD$fK#U<91p;9WAr4_7kQkDXpGiUz3|^AW=Y&0P^G<$e zvq{(uIWOdd4T)Y=b@#n}KckNW+3eZXIl6PZyQ;goySlonx^MR=3;Y{nHDip;*4bu# zVq)SryOS}dv0ZOI_{U$~t22mV-~ayi^;))W-MY2-Sg?NeZ~pVsx1IOnw#P20dANI^ z>e9%Top0>z`q1d;Jzw6pr>lD1fe*2Yk8bIWwElic-HN9kTJq^jV|N=hUugYM?;Fp& z`uY#9fAfpR!R<>w)_2{Bo=;zK#;(EV?|=LQH@)=e!WGv%wP2q4v)PefHgrBbRQTTc zAK$Te1)GRe0!2E|^xjZNgCEuk;g<3U(W$fk)L;*5iB&)_zzi+4F`r3g3FBRnbKuut zU9apto_d`J(&K{nl6T(F^e_0R?=^dcxI2nDnR zs^D!b%gPbDt2kO@so`R-Gjn5_6}t1eY?h7W@;$rqsUgaa75g&-#0HLzvc#wt5AT`l$r$$9;j8Yf6QsW{uPN`u? zjkdRk+40aUcwMYP^PX67PvYhi!ymHRhxbp6`X|VWxmW874Dw}4h!A$2+I^E;bKV3tqe0s3RM$$cf=>o%A z1KrKzacKUK;1y{5R*DIDVhm4A&=V8##DqODrZWcGJhE{-%Iw&(_4VTspvjDeO$aY& z#83c25gsB|(0E^pK8sOo&Qq=lJ@En#A|~1VK4Dfp5Esr zUULv1n1c9dN#dgm+r_{ur-2t@ds6vM8UP?2XG2^Vs#UQW7=1XuzbTP}anLQqwC53o3B>h`^4HX`%mo130;awMMid~aoku^@^2wM!iO}xjV%Ik&;vt|#DI{F1H;*3 zCYu>d+j3GBZ_FXyG?#b-IaAN&jLA+g))u(z7WTAN04R9O^PnlEn3+c15M(XEP)#=Sj#q`ZCTgcCAw#4E9gsl>WYB`NTcwOz zr73#LX+>A7@aZv1^spAQ5rQ$+rX6NI5Upu2r&ZQ9g%bO2_}mLW>={goX*MpW*%+T@ zCnDn@s>`W0HbNL!)oKhBP7t^_n;t;vxpBPCmQ^g9?n@8$bnPh)LT5sBp_m(D9rZx@ zM#%7}1|_L5@V6UCYGUjToNWi7d?}TIjSE(p90g=|et$bo9bNk}h0Goh?@9v8SQEhD z@W3WSPYW7tY9ZG)n0~V~1q+^|!R>x(Njp_fQXr7z9bqx+bP9y0QM*PoF@zd+G=d!J15K$_`|s2x>{Po%`)lnI=Is(D zRp5FW zmS8(b15GcV%N1F7Kd6kP`bjS99?l~Q2kk>j3l_;bW1a%ixddcsKyr-wWktvx)`bE7K4>FaCV_UOvyFQqso=23LaINZ03B31>L04MEvLG2~iQ76GSnMVutg5 zGS5?QKpO)Yche~~-3$=8V)y6QIn2TaYEL|;>W+Gm6*Os$RbsncRxJ(dIvCc_trxOW zg8|5c)~7 ziUE{{(oV2^*;_q^Nj!9CGu_v3&E@T4vgyG-FtPXK)2ZusSeI3 z_Fl}sP|Rlr`&jdy{08nOC=8_ro4T{9LSg+9q6TZRWCLqnjVT)t&;f&r7bIs3#>$%nCxTF#>?l&DH67q)>+ynxl)Dbu1tn220XAww!2U?4>DNSI_>7a_&k?=(K7AN9L#+wr2D{aB7BF^o= z=e&f2Ix8nEG=Zf%FcOW9P75)!!EA(7%4B|GhOKs5k}#TPig!B4Tae&_m3|f`6y5KP zq=QU&F5)PQDQZcQTEE%DflDXBk4ooR6lM3kNpKZHmT|dC@5@yZR+J)Pr2|tXVfmCK z*tqR8X;HvDQ&=-I=!8{C)mEJW;%a-aPZLoL&NZisc-E4Tq6CvnUrz<>a-rRdsy|cZ?Tf%rKwI-_ zkTzrYf+6D40;JL{)e1$&DOhusrG_|^lakY*tvXCGA^Mr6oNQg_Zd~MkM6=`cr2A<& zFl1YyaVPjv8k%a{bTdOQ{|r%dnkK0%ZKjCP853#G!l#Bs=A-!`;X139 zuCppxNHrBw&480fI*@%jQ4wk}*Fby?Yt!yNAJQvt{lwu1Do>p2Eun7Z!EX-V{p|Ta zd|+^`D5F-EQNtXoEVWd|PO!II%(W0x$GR|YtiV$})z5u$z^4LryS0@gOP~ff-2LLX z$bXj1zfR^~MfuO7{I{ihWfjo7TF=^oAHZU&KiR*IeVo+4Ty`}T~9WaVHzy*!C zCjmwdl$v0B2!S$Q%YW9DkWeVzfXF1SCPJ&F3q?}XMJjj40Z2EPJH_Kl;{I&9vp=0K z^4HCsos>W(ki*h(RS66p)jYI}pZyMLtSp@J=#qItegi2m;zoDw9|H3OYBtLDvk}(M z@@O5VQ+c*0-Ip0mPDDr3T!=T=cwAhPh&A$$TNa|Nzr-*OLHUzR4iwbu43tq zq%sxDnG~U<7$q56G=?i*QA3L*AkCz-fFn&8X$Ga0Inp8`ErhFLMu^IYS&9-jAB+x6 zGbTwhOQ(ec7!h2*;ZU6%sL&+KnMTddet?T^h8Ct(3=cjKrq%yN0a|#kOot_eB!w|ZqI50OQI@V{^QrVe7^Q!VR}wdp#1cevV#A@?AjgU%k_$Lx zFW0Kb6~yics9sIU`f5bj9T9X##N82P?uc@CMARJ-aYujzf#!vm3i)EnmrD5(k}m-= zI%qY+s1i;StH13&F{alihHsxt2iZ|tczUIUeM_4TvZJ)%^hyi*mIlaitalj1C`lo6 zeLdeL5J~bbpg>uYcLN2YN!}G9W>i8jmW=Wq5#cz6p<|*TEUk{EC8jFo>gy0e1*U)s z5RoCnG%7fe<&wyXB-R3+m66}NeCwT$Bs!+qO z5N_Tu=dG{zDR!kOR&yXY%l*UY|J*YB%q=?|xZF3X#)OmOi&#*b9wm!;k*;!UWt7=K zTbbO{!n3i%uNv@dpgx^1Y`IeDrwJpmRC?1C>8DSYe~6h2fR7g@Cj~jfT;xbw%sqHZ z5~Z<#%a%fW%x`7xMp-67badt6=v}w&r!DK?FGlXXPkPvOnLoR(m;t*kv)NVq3$p97 z|2lSE?kaMcEW4}}%PyOOWtUCCvdgAm*=19(?6Rp@cA0}^S5A{iPEanDSv=?os8hmc%woY?`$& z$r({xKUrr~5(jLy44qn|hDOpRYrZv&YNL+FaXlm~0yxW>XNPf@Ep*2@9rgF&X29_Z zgsC!S(Hsg1=XQvBRp%3hW}YWwf->g(4xw3iV{}(cz!@X!Tg@QRVsS{kpriiK9NQfc zVCBoTSf0iESac5y>U`>z1|V13;#QbzNl_~tmKvn)(K5@Zk-~yL3>c9p<-LmOF3C z>Ih|J7y*KrO`)I>ri?>z33aiE=TP%8C*Ff$Fad6vkCQ2seQgBJI@B+xc6WVT!k?QPvI&VmY1yEV5iPU`Q31zK?xar;f6+=Nnen ziTo#QA}Fs4EB{LCtqR_tLYM2@)Ngih8qb+;;pIg07-4-xvG#^jHIMRs3iGMM&@JBp zw71t!zeS|9-*kRXC&d_Y1@ zR@iER1TBz&6J((exi&}$L6A!Vr*B|v?0)n6Y+(3iQbbZESG_I>~d2L8wNtKyFsCg-?7YqIfwS+bpaFu5O4+ z4Hc-|5ioypBUG;C6dn-eajGGC5Pt`U2gHh30pG<|8El^ptOUJL)s@{ie!Fn&-8W)C zjoj2p`#;3b&Rj8-#d5gYl-%HQ`%6J?3!>5hm5H4r*Jp;TEiyy7k#xSjcV~K#JK&*2 z=t67j4J+b4qk_X}tnAz)IBS=wy$gpn2I0f5##P(5DSK9gH6t|GmA1~Jv{k-qA z<+`Nb9lg*9u?Znk#bThdmLwVjJ5oJ8xG{)YzH=zm4S^2S->~~FR5jIO&U^L}i_J{H zUkX@9Zlr+wlX#RYmg}0%IMhhpF?MNPj?K%Pii7q>TKQ&=D#tRRTz$4zkga`D&f@It zQhb!sz@)F0GN~-CqTnt#B9n2w8P#T}c`?%svW-4mx-p&4S&FbwsQ2LFMJkUnh_@;+ zzH=D|0BK zsT8C|`CMXhlwTS(SC<6@QXebDO4^`0!OypBT{h+c0_G;aR z%R*yh(5W$6N4;ZXjK1C(4nWvM-wl|BxMw8D!Y?q~1jb`SkVTkc$1&EihY(#b30k|u zy%91cAuvrVzZqas6z!P~awF*p+V)b0oBqMP0D8EGA|}2rl^d%mGVT{y?iX3%7g^~S zS>=jEVsRG)cX?Ec)Eb$}<8*bqWg<$Tbp$#~IB9A`g=FLMeRr5r@5+)QXS>UBd}=#K zq|R1R=8DKUYGl12LX#nQ&P#gZ8j>zz6^J>G&}=J&sS;PHCa0`pLWt_&`zAk z8y%lC^ljq~fqI@e-)#$*`DLQM5y>-MiR?PDSFPMF^gBLj=i3 z5TtC#NpUVQ-qHrN^6d|#-Dn1(8B{8v{aSpF>#czf`PifzeCyW|?zbelRKo<3=;Se% zA@{$RS#%qLndI6oh)0hO{#sy5gu9gUuMF{Am-9WoRb<^l&`NHnpB=Ix4PysY9nIVc z%6bR2AcUX&legukXz0h>J}Xa~jxqB^0` zDtGb3RFw-&S=+_oscQS%5YoA_fxM{pa6GfM-MX55@`oG+y*0H9y2eo(Jpm^&_Ed_t&~qDK`|~DT zM$hfk@=0jmc2}K%>K*=6U;cJdy`vP>J4#Ybe9@7VpZ8D~+{~t~b*H)00dXN;RJ0EEwo#vG#aDmr;#w?l?DNb}4EMDm&zUosb~!;2#{} ztRCeti$%)cBrPpi@KQ9Ehzkb0RwQ!f@{uYAH7&x)GYP zb8Fq6O^k72<@6=}7GymOtR9`~gl^Y_PjLN7ZgGZn5 zHtT&7$+UD8r(2e(7dYbsoGAr7%c0d7G%f74MfeX51V2Mo@g1D;9fEZ6AF<3iQY`WjNAJXgBgE%5uHnV`dr0uN!;i$n1QoSJ=iBU5 zBH4a}__jK4Rff)zC|LDrbT}(GP|@X>tg~XL82``F$H&9IyrMRuZ8g$&#lsD1#*|Z& zbCf&vV!pb}5k*GSEe%ejFd$JPBGft4fXoem-tO%7)f3Y7!EH`5`w0g$X`<^qC7Yng zhO56p!fT;=Zs4ZAJrO@Wp>~|bFqY%hYMUt69_F|qXsh7EOl7;-3QVoV9Df~b7ql}L zu5s>AXRKncc3Z7?S{90j-=uAGnXvsIEidUE5PaBMZub&5QucAdVaLJrIYQItwaJ7> zuOGE}U!9g$C51k;UrxCI5e?Qf5sxt^(ePN;r)ZAmC;p#r`%qKF7Ol^9{ajQ^n>Cuf}Y~EP|RN?j{e^ zs3&H`6SI##xuz|i?^-W-GNO4Z`bnQVGJ6`CXX*^@=1D}9S&^0aCt)nH|L zMR&8BMVj`{#crLp>M z>gC?4Od`nUJucq!l;$-br;kD^Q=qgVS32FJ8S>$Ji~n%FWwPNq1I_SO^ER);;1;iD zs3zP>&-W(Bo0UD&lkMKNqbDZ#)^*m*Dgxl(Q$5dk4kd$qzGNVRzHK-@j?zKUvc#r^A_tc%n+d z`;#27UT(ZJ@0tRLQV&l7M4vI;Jp~Yrk9#HqQb*JW%)jH=dO;6abk8!iP#B++70U-cktnl#&fr6-m{cod0f0MqTR@_jyN$nxT6>oD|qSQW@HY~4w*qQ= z6B57S#_&h5An8Y!R=6m%U3^y)o6_oy$u%>%NhK^7@Ded+u9k3;kVsX`l2X#>;H5(3 zgS1AjoM*4DW&OR^Y5C`^Wj#oZZm1KF8dYM|%@@SP)t4isR$Ju?G?D)hxyC1jbgph$ z1=5-B_|c&=I)wh}SgBTa<$(@}QlLC?H*p4j%n^@za7Rkw(q~=R*s+8spG3Q25kD-- z`DoHQQ-gQoBOUZfOVHglT!mEn`(qriY)ZhRB>+cC0D6k{1$2z8pT3FF)~b~?3Zpbq zc58gxeO&lH9~FwJ@O^&5LL}!SPkT&E@)B}fd;!Zl!-4^3$OvX|T+u-3ZntTlkoi^X$+xgt7L#~tA{>)^Uo`aeUhS5kqoZX`A@;&pSAX(11=4Xk&7UAmQG-(q8PB7dcl=Cq5~5v@lhe+rbM8QkE3@n8 z%x4?i(`($CUMoenUuJ%u*Wj~?!m`cE-in&;-j7vmGR#i%3r0xUtg&pG&|=4f1xPcb zZhkT8jE=*6>TW^b%yl21V<|wsks?SA_l2eD)x{PH7#OOD;!C{YRg^Z)o}ghREM+W2 zW5%NtLK8jlN5KanT%trIDHNR%mh4lase`^ug$ftUzu~3?^I40&W=wmw!K#&9i+awk zC?r!3Um`7cBXfJf=egZay}iF{>4iUDwxogFPmT0 zWLL49nf6;ie)7pD@%Yi)L%-eM^v#vCe|B@jlSkNbb0G}b`FO%>MI!+H)4%o}{^`yi zvDNP}*u%_VW0$ise#hNa;&V9bcz_h2$g_DzVyTi6znA?g}a7)Ozy*2u1fmKa-#w|I%HCntak##>2rDjs-Q zcQU(u*A=U0mD)Inf1Yzs`*4wAiMybUPQ65^kWM`6F6}a=v#}-?m?}G+&U22cH~qDX zNP{0)jbqNALNy~hdl!X|rdn^O5ke4|}R^G{2!!t+bvnHqI|i;W+u?hv2eUqxRe zJ1$9dom}9!@FANj6t@Gqas&eKu57Ns^vG2flMBvQE`~@AW(HKII8?2EAI(_s7us?i z^(4@<dFO;borthgIy5hSL%_c1dJ~(_L#T^(G=G{84cFv zSAGRz1P?V2^BB`?h!HrRt-|j;4E&P4TjL58_r7u8Ok7+F*vVWsLmCZUV9a$P)-|pq zG;+9d(wHmMy0mlIjoF9L)nQfvIsEvnng%}Tt3+M+nJY_~m6w5e84c|os_+8BE@tCK z#I1#H+=vG^LbwZEa8(|-s)mJD)d3`iO%YWg7DRbt#M?`>1xKv4zSQI4ItcT@OZtXE z&k#N1^fc*7w`!U-idGG{l|lYH3x6TGN=b%b+zK|*v&F=FQk&QiD}Uv>dzY9R0~H!4 zgO^{q?!Mn#v+JviD&}7EX5&+0sySUwHBEA=p%EX11Q^hD2OQ&-qb!gpjS>Yf`#Bnh zgcA^BmIqG1yBlXedW7x`p5RyQRz`pF=x6oSKi#z}_#IKV zGi2Qs%DSPHJsO1sC~N1DmxsSS*yQ-c-LBs0j9*UHPp3U%Z&ff9F<09vQnRQ)5;KiM zrY|w}4_)nn>>ZWrH}t2J=K{>L!qExV0WkL8akdzqi`Xb*_dLhyYM_++?z<1z?IbmB33=!+nq`ls0K2M><24{rGu zW_5t)vsC7@L|)*C&t){rh#Pwsvs=IU=<`SG+O)%X3L8=`(gJ{PrQv0`n8v9=QudKUtxAu!&hswTt^x^YspA!{XAqiM6D*`+Zl@X|*iQy&E+9E&PGbQdy ziHps>3P;(ijBPle(RI`?$X=~@=(Vwr9*s3OzVeHkv66KFw;HhTKc2*f5{%P(0Od^v2WR1pq2?Mo3W|-RuGS2) z#P4hXsjB6AdtumIZOv}hoJW(I&?8{N(fICDn!C7;BJL>QJ6cuArvNFJ9Y83Iy2wSW zjg8f#S|cd%E70)Xs|xzYQamXN^e;z!&?O}+MW11}L)+_qa8(wZttdgB=Cty}?woF( z6A|c9ww7)pL{&9x>qjfttuK7|{O8zg(7SEct>>(JrjjUmR|v5n@P?h}AmXl2C=4AB zsW;sE>-xryQOHkw**~!5TYx@+4vd9MK~P7r4!Dl?l16&SWvkNo)f`BllNs7>t~D02~2cMoXai=zP|G( z2k3&g&49W3lS^)H2t4zimc1_>fXrb~vGZ8_8+mp1j6%@&X*;fCq|Xo4B1~m%zid!_6L#K*FjUK^7-7zR?)PgZ-$2~ZX+%m z9vZ^4hjJr$M2xQj{cat3h&Wf=cg#%^!@f0@hl2d;*@lt;I0RS$nSKrMh#z&5GzV2v z4!@upG8~~G4wf<)EbqoU=dqE*8@ArNbuQkKtuAD3+NJC)DV5@7yBnW*{HELA@yvIR z2oAc)kAp~v69+-B5eL1~d?(i&eNsw3c-p$gtK*{iGZ!0Av7%v4f#d5SXEQ`6CB};12Q4 zU_Px@L5D)&Ak_TCf(31T2WvZ8TbT|KGWE7lK!aMtj{!B{^Us}7g$*?SyvFDn&}Hm} z-#^#A>~^;Dh&(lg(QStKkIuNUb090(ul<>#JlO?1)v_b3vs=(g<`#}B{xp{rCqlZs zT#-2pKHGm_nVHJY5zPgkSS$&d8ni*5W} zTAhv|EGIU*|J^ntg~{x6-ad$@8Cf&4M-zTb3kfTY(bnSMGhv#8rJom#BW^umW$sC z@mnc=tMC`ZZ?$cqpvbGC)pW%P5r#5xSxs@cm3C)T2gK8RNH=1x44yXfeie;)Ds2-&)T>%!a7v@RzlW4}S|{@&fLo z6JZ^?p9`U#8{gIZNKmEhgk+dDzj6~(mOGbmA4re8%rahPl*)XNpkm}rUcen0QRzzf z2pxFrq?R8X;EPh$(C0-dYp?~Vj_cGEB4IIx_bYuiX;(%oPt-9NG8G4xvG{N)4(-+9hcHZ?v${s6nB* z$RB-^MBgZFvU5ng!#S~rYqqUuPquvHfUVV*bFFrht;}-aodSM2x)iWaF#XIGFEj1` zxXuo>1vuWGHEuFK@X)FSVhTg)bdO@z`dPX-YJUgfV{Eb3BxYTCOq)CqRpcX2QI(Um zdMv5+j$TZ8L|uvNW36*di4^B)tJz}eYUNDUxAOQ^ev_^^W70ke);^V0Ifr$!Q&ue{ zKy2UnyrE73c6>m$9l#4Xdn%JfkT2#AF&Yef!C$6uVXaIy{FcCo?ODcgmb8aiNUY58 zsYJ5{8i*WwgC8!wX3#4y%X8AUkR~9J7r*~nUYVPq@ni@A!^^J}3k`84t}3Z~#c5?k zjzI}vf0XG=k2kd2k<}v7Ns9tdGZjGXQ~-5T0nC~Tpxzh2KH&^1`b*891^Bm=bL@lW z`h?Ti<^>PPWK8iF>F$K5yXSIMx^#EX{U6lbHsm~9rvON$y{!bDRx+Ju+gY8eVks$& zuKXOI=W>ww4&oZU)Su=6m@fg8>2ZtVcxweq&(HCO^V`L8e%m6aN1WfbTG&jQzBDgM z(>Ji_Wk|iTtM%ZIt2RcD#>~Ghm%fpN%y6rmFfT)OhbGK&K4D(0dVnhUT$$i=G@wMv@imnnvd!%1X!+=H0D5<@!TEIbcipi3qOfT*5Q~{2GvcbS*?Q1UH{NV9S4d zs;z;?*iJCHX!&ixx$>s0xRo}3tTi+_mr8%U+k(*_V|y8257U(OusG>qu9dH#8pC(H zh?OthUhtAeO+bXvQc!FXU9P7D=owU2Rl=(Ez@>n_>Aq}zJ!uk8!vEN%kcqd3C2x@D zP3CPNT%%O);8j<=#T~pGX`M~k!yfbj<)Z-C+Ni$HM6MxnPP|ld;wou8W9q82A>jnm zw)P&)|U=rB0!{3{{ z-uGa=|LT0}Y&QB<*{S;1*%4gWV$<`7x8h2TFRZUm915C#-jy@Vn>x<+Lw)1@$>*PE zGxS4!J%8+?=EC)-J-}w*hk6nHQ0Kx>nIHVrx!-n316#7j(0%YQXbgqY4k!}3;(+zH z*XJ}dPt)s6^)&tbZT2+19S$bPN;o-|s!KYSYW{r3Qmx`rs*;W+JL~^-DNRFDtD+=F5KMy+MM~fkNxn0;)-wls!3=S+oe{qO|Jbl!82*2PE1U+dT=>Z zy94Tg2kN*P1hKjUXEQxXt9wQ}{g~VMTHp1W$;NJE2;fL;Ow|9~9DUrLj_&X|%`$ej7c8Q;^{o-Z=XQwD?q_UAzbks5@YzW6k zNWh7$bY?=F@>miuVgcGPWl0CTZk>T8+m(iVvxn63N${ig!Tl}`){UzWQsK#{QYECS z6d~1<;7>(}jqBV4uI5rhTeGUsgCsZ#4}X+wl^l;To41ht_%ik7&SmPlvh2;z9Q(rU z?|A0qZXu33q&T`XBJyZu^>F!0hB-vQ6P|lP#T!r*X+A& zd+VK2!f<1KaTv;!X=}JJ;))_+ZiliPy8qv298TtUMb<&u6>Q`W6`^-MRk`Ee*9O?X zV8cy_1_VvGd8i3=vcAFf3vgHKf(^~9hc-wLz!iXdg5BHlABXfSo?T-*ekUT>1y@oQ zE#-4b7rl~ob?ty^;#DN8l&h;I$`2Fl*eZ~&)^=k%eJGzR=8F4=(rjaAXS%o}pBvhm zP4yKVJV3THBj>S#d0P$v2_P`==S$*0WiIB$$lPc-paSv%GD(6 N>%-Kz{~r}C1s4u{A-@0s literal 0 HcmV?d00001 diff --git a/include/SugarCharts/swf/horizontalBarChart.swf b/include/SugarCharts/swf/horizontalBarChart.swf new file mode 100644 index 0000000000000000000000000000000000000000..3f22a42a138f6f8f87958ff18c7f76daf055248c GIT binary patch literal 11926 zcmV;HE@{z2S5pVZm;eBHob7#md>qAe#<8S-{4v{U{29FH( z$Vdj_O;|IQM$*_LjWRQ`EJA`4Ob{d(0~c+`63!6f4I~5-LM|cMGuaIZW;wFE+1(?% zmmJyM+$9$-%l`7Qo3GWq_o}M9s=G%YKDf&tEC1ZnRrTJhuUGHAdR1L@oP~bK*t`kG z7MN_8IW;xaZm(yI8LZPd&H9*8^TfzQcBU`HrXcn#JoZh&;~7@du;xT`^u8}|{q94< z8`)H>29ixc`(Pwuzz^$yaC=pPNSSOPmmfQjA7SnGCWr~K&hY(6yzb;@2lpADC*se% zLlS4KCb8$ceS1IoZ)5jd_BSglkNx9oA_Gfi5Rw_xQU(@f(48F^Eb&}6Ky;Yh^eOnk zI-Gpwp|v}1IP;Rf7V+~(t~l6qSMRYAkwrvi5tdohQ5F$5i=J#>2J+Yf@lmMB16vu^ z+Cx3?HZjTO zvHY=2ffY;XLg_}98XY<;L!GQIQ-nBtcCxW-Uum#AQ_S9yftXw=eIx(rWJBY7hWj$d zS#~&E+A*9Rx++~tGj<3vKAg_6;$XTjKi1Qm&ShA7INLLl$@H<(V7AEe!&eWNGKJlR z^iYN!8c7#2!zDJB=^Mxt*`x*S6J~9bmCQCGO#Inq2gQVZF_teT?2C!`VxqnnTaPiB z9osP(XKrl8w#LaAl*x`qZ3wqCV<-fn7!N_YE!${9%mh6vQwfR<+o6Eih;32WXo^!f z>V{q5s#GN<+IE=2Azvc=R#T|v6qbsaPq2~!D3)Q@rZApA>*yJ4q92ypTlaC3)w9OQ zD3jH}1gmLJ9j4sEJPFaJBv0?8^otqRou@xkp00UuPL=u)%2cXU8Y{IHgn^VZv#s0?-ru}Zyo!dX zl%a$yUd8#miq%xbrP2M~8pf!GHIzF@>t+bnO5Mo}!(f4$vQEn7S}vETVmDi$hN)s3 zAq;Hi)N99NgDYrQE;EoB?mKk2Gz>if(Zv#IiS9-y=^~(T)&SDh2?YrLZiYfEW$a(z zXW|GjpOmS zH7Qw%#-;aZq})_9l~S93wkRla2r=w3>TD4s0&&hcMlTf6zR;q^E;Ppq2N8J8n4$Y+ z2Rc2k@xvV0;KI5ewO2}xx;gUA1$V!7q1`{%LOR`l0f?~+Eoz06BgqXetr|&M%@dur z^FV4>ez=qd8Cd|?1u_COXaD@8FMR6Vz%Wz&Y#*zs9Q}v-@oX}jed&u^>z@Zfg#xhw zbV&#OBOz8Vh1fFCZ}Ulrt@jDBIz@;9p9D#;*D6VZHL&Oj34s#NKx3J0M!WQB$SapQ zmdSO2Sf`f*V|fNb{%F^5Fk@pHSe=D@zQlS5!F(k%R9d0EqXk6apaX^c=tz+bri(qJ zhm$-|blwR0K(+*9qpy(7<+?^n+5B)(lDG=v(1gv792)9%$C09P=xNfE+kByv_i3fv z)Ud;=FyGn34V$-tVKZlRh%Vh3v(h+l>+W?7(&n_gVksXelp+FY?=%+vcPs;P@~KNp_&ikxm7UAq88eM9Id9i zQQ$#i)jGgkF5x;FvGZWWLhtNmyo%VsSF#K1^p6?XxKM^8(pD-b`(3H6Gw$5QH)KIM)+6?EKw$x8G^_Z&HxdV2G;>lLhM4uFo}TPT(dHqn4!)TKZnLISe=tmzzu3_0{*rWgfsMJF_-Pj6b>Cr z=SDLkus7e!`twk&9t`5den@Ap0{0ZS>|>;y*#+8wVxDWIyw5OyZ{qANlyMuM{>Iu| zdKHuu=W}W)tbC|dslBc=okNyf4#c=Lt!6xXo>>hSUwjbr5`*+6LmYkoJ?vW|q_6#Vf*+`xFdL41uXP*udnZhS6CYNc~1 zVWvsUUBgH=YdsWU_Ck9Rq!N+E$vL)KQ;IN}=Zd$4<6V^GGLn9lCKW^I;*?fQc(!nq zWfXNuidw(T$8N3D;K#95DzHyb3@@GrS1HJHE*9y1g<6D_<%)2rhN%`|#f(L8al7Wy zqJX(d*pYMSgw-i^raTA4HSWls8{*mvMO=5GMP0Au$j9@B6n5OhY&uex5#GkRWVLDf zKI0TO&ro*`wPo%tbh%qm)qAP3-xXkr<9x9T1j58A5ON+pD-B(#xD_j+=$}Sv>i^B0 zQ}V)^!Y1Of@Z*LXXQsSQOT&;Ygw9sMFi}dfwYb?51C-btQA{~Ui->-l17iGw3Tcw1 zdSQr_7h2RRCr4!-T2J%P`PjMoBsBD^T3|aH3`gRp-h3`!xJ)(7x|2Ig`OcmjSm$Ua z$$HYI(Lx$0Vo7!b+965Smo6OLg=qAaDe!l|DCGec43NGgSc#boU>qg{%3~w{*;IxV zk$VR+r4;ZiGGnG#x+*gQW#Xv>h#+@_vMdeGrMwNEh-eR?i;|_V|ok+ z0FOs=klcwJ7lXUAnOq-BkCyU1Xe$YKW)Y0y-clL|)nI7|!lm(Cre`pdDe>1`Jw22_ z_N8V~MH?a`TZ#m!%2xhSFdmA3rcYl3|CTX2;n$8)Jj4fTnjQ zU0{bZ1KHtZA>EgSTz7-~poAVQHX8z|aDe9U_ya^KeJFjL4P}Sfsg=BAiU;zYAY?+! zTE#-phZ~teow$*i*ozz45_Ifap(yfI0$+_NE<+|z7h7g>`>6%cf+b>xA|%wUGHS`f zXCDfwGtoN@W;J>uqTYzGH=@!TQQ?iK@q7f(l@KP;bZ23|nUn24))aZyt zt5(d>Alk%r5X+3B&$*q~%?VdJHm4Y`-5eptEK8!GA%ZW7>6w z!n4aQ9GDv*S7N=RRyZ0$JZoDcUu+7eco$G0lH%P!foO_%MTA*35VTWq-XkI$qcC(# zoLTM~V<#%ATIT8N2tkErfC^C|BbIGd^Fmh0LdH{^$0(3UaSo(FWs37BAco2zCRD_j ziWsLht#U_Ig)*utle|$?#sg7bWtrD>A#B1$iz#UFV6VSq@mGV*p z`>2(LjoFoCInUCQZ@rAN7to5hx3utF*d0_2crKtmU8K6L1JW0({_ueGrWw+kr=t&( z)+NBl7p0~JS!!RbrO63ovOE@W*(J~(OFEdhQCcO4NfSF5y_+`uL;EK9OVCvAvp#lh z4QAIBb70q2mtBqjhwR$=|Bqc)d9s`(%eIzd+143Ywsi)UZJmK-TW4U|)|pwhRb$ze zvt-%U|4WuVb(dqURNk zG?*!+Sp)4K+MDksi=EYhjCTUH9G1<`-ALZdXgW7Cm}Um%zh{_L8l*Z<=8v(-I`o08 zvR4DIudyt9Eh_amHqAOva#kFDXX~vR;(%RTVT0nYx8~7E+Ue+9+p4p;k8LNnL!u&p zTGrkW4dZY!?8~|vAH+Q+lhp`QYt1Je3JDv#gZt|hbwn_z|460*GnOzff`)Bd24 z6^j$KO2<~iD5uvWI_>#h+C=IMk+Q51!7QLq*oqS2NTr0jTEugxB}j?)U=+EKK$8-7 zA*JGi5Hf?7%I(%RNJ{W9l+x5~!5YSa20^$9qzGB3mf6MMz$_GRQLCa07{rVwm`NSwkmviJHVOJuZXt+P+@YUv-YVe@Ds&xjnnmSyIgL~1JHdFNd5oBS z#Ig34Zkoq=KSjCfu*`%s-l4q{L56%t1CB{x%T5HtM+hD*P=v3N@chS)m%$1L6)9k@ ziM!6D(skB)alWE;;U%Ggdd^EU# zCUys;+k?y686<14fC=E&z^VEDVUBgf}5z`ArNsknX_83fy@?(^X8-xo#}~{&Zg-F8fi_^o*o?A<&KbnhlQ* ziPhDi^zoe%eJDHZyz_cfA6zq9EM@!0H8Rxnm^V<`No&99NR>EmLa3H? zo8!VjAKOtVKrfB&IG&}(EMO@h``*zU3@a|`#`k51;gN<>)lWC35ggS=OxxFHk&-EST!%>W5l#D~;`vG657)NM~sn(XV%7OlBdQP+!JBqE=W5B5tg%S zBraFkqRb9QaYr~sMEE{+XMs&d>QK?L1Z{yIRqJr|Y6nm*sgqBo74iR{+ z;*LtExfDzXhPOqvi{U^T3ZKi;t(H~1)Qw2W<`6IQc?~v-8m!@krlhs0xZ8chaBHYY5;am3Rh`ZcINz56%!Vc{2~%2`CipJ%2*Qoq&=qumxq`*Z z?@VJSrm>Sgo|tE>otmdjPeH{TF`^c4o7Kc#gs_Q5%4Vt=MQqU`;!rK8yv_av$O!o< z0hD^{Iq^l_<)YoM;Cnu{rd$W}CVIY&WZgU_N`O8&`)$~JgUl(E6`F|>?GfF8?apy1 ziSJdEA&z||A2)Hv`~6Bl>7w-gR13&=%hXJD8(8T|B`F2i^vB!e}J#tN%9sy$4`ibpLl^Gs;>A5-84mred`wO-DzHN;ok}Wlw;7>@M)0j#__pj2fu2;*8ij8k zkwwjExy|{w>DGjAr8|(~c45Q{yQS<3fWi;qa0S4VqBeKb*IJghxucB%iKOT~*|{d9 zA2=KU94-ee^_Y`V$?WT0A;+!N8)#AdM$4jw&Ud(r;yn3ach}@%X8)dx_D+2#{I1D* zMG3#lzKMUBqn74+dj5X5uK{?%yQr{-EX!Ao>*rGE>*vy%*NfR#P+ye+Zbk<@t}N|$ zwjxD{#rKHsh-W)*5^a6NxTz}Eg?Rx_Y5D- zzc&m1)n+_AOi*#fh&12I=?_^3Y4PF7VW%?mHC(S#pJvT|<3N4gx>dKtiJf75KTjWP zWCD3bZA8~tAloLR*_lLXsXmHzjpBShmT8iNs9TzJq$nU!A|f>CX;92-0KH4^_VrV0 z`#SyVe9huip_*?=SnP$MT`-R_l{*$GF!fF!{%&wbze`wnc)0HeI_8M+dcB;%1Z^7i zsmia$+y>^h$ABhHAP!X0AhAn}CgZtTkcIdoego#HrueprL6(y`?TD8WydR|&!NtbT zy_}bPN_JbyH?wKfwJb2tQKI1^zg=-|R9RXo$o3)S%oIho4~Y#=ifpfNWVv(>)Ht7-T^h>_?NW~sWdFfq?B*KOkH|T>J@WmYU#boKDPui#S?rp*rDA0E# zXMHwGxmv89%g(Jgzs#QQDh78~ak}oBgDNiBqpB+AB`W$=v6@h#=dsjeo3in1x-DpK z^wbo8ycL~YuB>D>cqSRpuw%guJ2r=LFeaGhI5JI8bpu-g5XJ@K_*=#JK?QXzy<5B! z**c~E@A22a?m`&rR{K4iv2IbyAy`U{x|N>qB?(In(N?*ryU4_3*_rKxI>1(=`|Bwv{O_1UF=OdxTTTc$YVi>KWNBt{D`1 zTC#kRU{F=NjT;DJqSGF?2S)n)|3`a2{3T>}D{Y`xM+Z=;k#SxwpHRw2xmp9Ro`$ks zl|Ycdst^x+z;VNp3VwiY8(;T>jKId31Uorr{rpJ_K``@~u7-$bB<|1aW(I`Z~@Mn9H6AQci3C zVTa?FB!Mn>cSr1p$_?&&18KzkG-BmxoDQU6`)SzaY1|h`BkZRUE>GkBKpIg$jc6Gf z?nFzmU#|NXj=v6}!UoxegLG=w$AzwI=6=tIoz-u0JgU2ZnjJ{*ZkGS3P;C;&R!u6q zAtG)_J2IEZd3~vMfw2iE*7cd35rgCr$Gu4Fjv<%Iqn<5SIG{YX*C(7)xwNV!<@ob} zKgPkGoe>HuO}wh8`Uz)E9@_o|xj#jj0!Ot_L<^Z(NbP}7V%%F(|Cp>$*=h^_C*MN| zeSgIG*Ra+_XVn4oN0KG5QTED(bjiDh{i$vaT#dkwTki47v;zU+p0I3!mEliA*yLf# z;0aOG$LS;M3Nptl5H3~e5!|2YR)oPCnv%pS%dE!vjQk36rs5asNV!YqsXIrpj!(16 zT53AAwI7#TeR8D3g59#HBQe-5ZZ&m9pyZ+S~)|=>B}0~m%x=LS#Wv$ z#aI~RTJn@b-`6<%g80{)MFY!E!t5t$G;FqFW!leQUa{o$M2dIJ4pZe){P1d;_Vhr` zu~|iV^%-ETGSm31{Zx~8s!{7qHEIOg-fBP1>-405ey2tS&F_L70PEOvn77-Xvm(me z{L)!Mf1b|^9YEb>5r}WnbWlg5W$SQP**xL-42@Z9KK|XTA zeAzSXu*|1ZN%vDkW$y%U)o0bo5~; zbB1^7iyk|a$DZfHxXf-@Wn1}NcFeMKtOZ^g*$AsX!`P8C2HUi06RTflb08ZTTj*djgARW+T7%ISN%V#C>}EWae=)?Ki_Bwm z^s#V=D2ZO`WqeHYT=)So{PZnI6PLco zi(Bwnmx?1nqfGt9*{`l5A)Dt;wIO^UGqea#X`qz(zca1Cw`_CxMwFO%Aht`=NidoC z97cX*qt;c$Qc@Or=xLjOILIPuh*}qc3akJu)&Lf%0BW;cZn!8-LJjcH5~UHGbc*qR zRRhn9G~_0s8x(-0GXY$zmAI))_P$SFRQ6~I%!98mUfF?`XxxXhOv~1xV@l_UKfYEh z;a1Vf=ARLa$C|y+IPg^lfT7yiZNUo-vK+#sc z&e--72J7hP05$!}>(!6EG4YABiMHlffAn4^^lY=#vrSS>qn=&jV8aZPJ^0{*TvwyQ zHyD`2q1IO*^_D{&cYVKhNBnHUejh+{f)`1GOQhnymf?x(hSbjnAcG(rFG?yE8%`TG;D@|lX^f%_LjejNA>DEiqrL^OqW zy`ZQjSLLGxKXHJ?`Ipwt@dW(HhIim0kMK+%7l)N|2NQqaFTRVo9l=jNZ2G)1#q~}zT@9v4vlfa8t1&2#Eq<9(l54TJxQENRT1(u+6>+vy z^82;;-3}pohUpohXOx~cJ-K(yaGkmp+ZxGuc?$kdTmwY>H7tA3I&U(61K|h3>iM{? z)^*Ou-N8I}qJ;xM`It(?m+|`QiOpgNT!byfZe|rXv(?WV4EI#kG+cAD@uM40RebyG zqwY;1%YX$wjO^ONzB6*!&F>s~p0f=ST2~3l=b5p){}l2VvLbW%;~ZN7AeXS?jNSh{ zYrw0KV4OfM-*5fMyj#|O>%ULk@|Bxnt*^6|N9ARAt#W8wBFEYqp| zYv%Rywom=~um867u1i?s)9miMPH;LaB%S4Qh~aZ34KZ;YR4Y6A%};&(Y(uAU+8t{1 z`A}QorfK7f8tqcI(V!3kjfMqSB@1w=tjJP$u9m21+M}ds4Z>X`aaYU2W9(WP+af61 z9|T5RhZh9e^>i=}n}q)pZNNT3Up`B=%=h=h*gNQ4Lm8x0tF2-u|19(3JBR*~^(i8~k@MLaB~dck zxkwWi-fNXatq`XpktlTh$!~rBo1gya-#l~sx0bqUX#?BO?mlz^O7hrak4eP@>PRRi zVAy$EI>Ntvm;K1RJFJV}xas7Q#cu#Aj^)b`73>s31-9-mW8XiwwKi2h?*meEZInEC znK%X7MrY3^wkQ1a1Al*lG~h14T>se>?`;Y_`+@c&e|7?huY%~!tm~HrwiR!`e4_JR zr@#CQ6H7Jq%rkiFBP8SOK zvE8C=Mdyr;IP6AjHaaqbXJEjb2z~^Y#nlTayWVdi6PfbDmW$@?N;{~qRNa77!@BJp1_{djRuukI| zcG(Fb@GC2BZhrPN@45S?XTN<$aM0Eu4kD2&O&j8%TkS`pcUUbWH=SJPaM0UW=hy!0 zzVC5HfPP)~$N!}E>n9=dN{|C`j8Ok>U}89|!w-k+*&$LQ=F4)d0FVV7#_ozl!oUo5 zs~$Tc#B>CTi$Se{0n7$AK{_2yMyDdtFx32fOH1d#UG?2y>zNQCQ}2j`45&5ySWp8l za9hCgc{^!~A2V`{tYmfUA!lyQ=t>^^|01gYEkH$f>0nkKZN$A9Ldv?H0ledd8&0a| zGc?hs-W0~wIg_FnZ4|yxxru2Bv|wKjC6e;pL*Yf?XS<(^JcHI?7=+o2Q@`w}KhIK1 z+2QXuyx#X?y?^Ia4O@U5&Ms8lurp|`u-U1H4!Y%X)+z$;Kbtk}nmN*@j>G%f&Q`(* zJNb=!QeXeNI3J7~@Z_IFihu>8F>JI6BpmT)=OfY!g=gO0Ry=yqLyqSt7?p8U63UU6 z@WRS!7%EF5#^rymS-kG-A%WLWJjxnWkDNOk#JO)c7ZAre$x(I?tz;N32dAG}XhKwW zwmS^HcNytd9^vsh4xf7GBB3XYpNm5p77jb z;t@@0SNw7pj|5emW@d^{P-4Ol9T5|j3Y>hn6BdYxiwoZp;(YlYz zV;3alq-2rKpnQ`v=DUdTBZ&IEc~2evnlhXC1>8Dn7q6J9C_0N1j5P7-e3jCrazvCz5M9c}AssyfW48&**Ra{d1E3{*YbB%l9eq-gOI4_^C-8NZvP&46G^b%2xXhwm52QFRl*NMG z0cuy;w9frUiiImUlQuO*qrbsTjSrIR!)GvA8WnRIDweb`#E>9H;5W1C2o(Ww{Ic1& z$c8VBRtktJv8_a6u^!W46OW+@8hCG_ug`qf5tj0KyfTo^!4oac59|}iv}KON58XO* z!FLHxcZZ)T?~t>UF1%ES#hw44;6g&9@!Q=VL(qOj8P+vKIZL!qQZsVGM5*G_z1$$%z?+=)Gzw#=S^sZgc ze)W4*uO54G5K7#D${RBN5SBQ}Ui?92-&aJjF=_b*NQDCbm0E&x_9By3d#a1)?tM(zcXH1hJ<#Pe&$$oxP7Rq%lRBQuifmbJDn6{~>W}N^#5A zc5HD*Lo94Gvv)$RCRRc*CF$u4pjur9d2LL6M~LAl0oKTB44gG_%6(m1`!b@f)9ZhqopXkg8ZUz)cqwj_p9WDwhHww< zJ>Vzhb9>2y6{D3RI;z7>Xy$OWv=Sc{=q+8&tkRhg{DKzi>Y!}%2(@0!aq61nya1st zVGcdA#w|YIbV{`h)Z>lJ#ly)#5MG6bS3!6ed0^@^n7XEAPL)aZTS7unh2p#cD!aE(pyLzoX>n&4W>nqjp*U4}7VuWW(hec2{ju?>^!l;pU&0ar{(xEkCnWWP4( z`10Jfa(S+n{Y3{umC8qR7FFHlkPOPT!%no`nR7>oJEn1yr_b&2IGTGkP+xt^QA+M_ zwhXVDI~Q4u#oP+T#OxxF-4PA9-M$or&D~vmY)sYR>)Sfxp;woB4Nt9zvBk z^)OC_ri60r===F=&)xd_cfWS^Z_>wvGT$ea`CeH=%JND`IQdfl-?mS^8VzG}WXc^y&3w_tIm&ZQ0`lsJcu6#vU+n&pXc-}1z`qs;x&?casxnt|zke78><;LSrXQU7=MIm};(EYWqUH2&FfsG&IaN-L*LP{^ z_DcRQ5MFhY^U;9VJSqIg zo^6ej;)YMxO%oM|LYREkQHgIc-SDm;Ydo$Uw-z%*3RnUOtrXJ?GPN0X-Mdvr#dQ7Vq$O8)%Zn zVjV*5-Px}WjQ{)U!0+nn0E*~2t`2xn=CC@TqP~@@1MLaihqoZBJ(@QH?s@jn z_Metch>QtltFwARkr@@RaDGT|XX*Qn+n3|)~bU)<` cZEIw>{Q@m?_4p6vhK+5FQPQFR2l1T=hLq=Bb^rhX literal 0 HcmV?d00001 diff --git a/include/SugarCharts/swf/horizontalGroupByChart.swf b/include/SugarCharts/swf/horizontalGroupByChart.swf new file mode 100644 index 0000000000000000000000000000000000000000..3aafeeccdf48d141fe2a154da742d3c095cecc94 GIT binary patch literal 12451 zcmV;UFkH_=S5pU~p#T7Qob7!JbR0*OXmwA|Opj*twPZQ=$Z>4TcI@~QJ8_&KTe3|& za$=8+WD>F@>x`w5G|ot)%#17x5@Nt1jsb6$uwG1@tOLObEZ>Ci5@2!IO&|{0@Le{% zT{vM`-h+h)Ifu_%zIylGs_L%l?iooYyvI9d<>Q{Ns(Ww!Zryw9R&~`O7Wx5WbB;1L z&t%)psi~<>do5$kVBN+&Y=9XJ9~wJlX9q%T3S!T|WA_w19%BtHmmH3c|K*dLzI|$R zJ)4R(K(YyFZ;M0>_+ecT?yO4?DU%K53ln<_W31EO05Kuf9ex)QZ#weP;oZigMEtSW zN#cw(BzAs#VAltJKk?2>zqz9J;J?2lGO%O@A(=rVWnfVTy}6;`GS6ilM2Fc;kH8Ps z;mBjBR&TxT^mG1N#LpeL;)dki{RhWH77>|6SZ2{gSw!3{`f>wV$m4Q|k3voE-Ndja zA9>GiW&_z0#No4>P2>j3!@b#3?hRRp$(J+N^Pg@uGP!efAbW`AMsww@ zqq&h+XUZAI_Cdz`GkI1T&I}YL`ua2ZEX$1M`o^-^0ahN)l~`f)>d|txxTBaE$+CT8 znPPUd%qFq}L)j8LVL{`BS;vW5W*ZSE{%o_0VnV(c%NG;&#YB8DQD2O$$C%8HZ9NfZ zZfwow))O%(lO2!R5MJDdp%8>(JOt&oY$J)733}G16BHY^Ljkc7+oG_Mj8i!3hF##g zbS)*?c9_B;Un2b0Q>fuMmWr7lVr2tREW>V0V?2L0(KD8$AC}(Lbic`(S?h@?lhwfl zE4i}?Q{KQl3DIPVr*~8OMGWiC(;;#R4`Dk%IhUL?*=6iRodclLS;A9dJS8SmY)Apb zC)l)QZ>msuLll18U-&prAMzL8&k;Mqixm&lLM;0I<%)Jcvs` zwd%J6qmLIS7o`d?4*E%$-VwVDerws#k2}BkECP=U2LmJ+Wwu6WqfFZcAe5lMy{l!8)&ql`cuBfSgnq_`4a3w1}~{!_UzXU_2>dfh9{$o*V__aB;E+)xf@kxl(RFh-xK)?JDox2-G*G=yBkiV|X$pkWydNCKn<-*AEjtjJPLb~gyK>ofxa1>d&@JA+zOpIHOO|ehT8G(HBaVJ z;oNhd+SL3M3~v-8Eg*rr=pPOJW;yi#6|}-!8v57zhCT&S#lrZQUk)@WasWCtNC@0s zM?#>5MGs2|_!~CR_GEXUrT6!cbv}DAo9`LT@|V361qNdCmY&fHj0kC9#}x~OGV31( zgOCh6$#?zZMMUACLs;;VQ-jj@{*;W7)fmo{`kZJYw>MV?t{y1n^7)>za;`91l0;vP zacCyy#`cZ$yCXmm>-03Ya&t&{L3wjS|-#b zvXLzUj0`oj1ze7;Npk+9KtiEf%cJU)sCpjNknZ4&jTybsAT9le(uAm(%Sa-dHlYUt zpUn3(lPAKAY@u!E)pWB!;8x!sUgs!_T4<&&afkn%EjIXg1OheY6L6!JZdlO+VDF|s!c_Q@+f zIBDGX=X3qH>?jo7Z1UOBq4F@>U(9B1*;B{?*6s|12lItO5vrHNym|(ae5qW_jSjJn z{lzU=W{Op@#MLyA`sj*ift9rOx zC};8|GI%MCYNy8PT9{j`ps%s#OL>@*7xx{^xF)A?9#g ze%3QyBA)*oE{Z~O41$;ey~&0U@)HEvq9x)KqE^1dag^gQv*!{>YcEdc=24o!x}cXT z-a-Ow3jTN@u4B9@A-=&Cjw<5(UVJV{X{B>0VWug}UBgJVX`L2fcG7NxR3fr4HOp4J zFijYXW{YT3N;m5I^YOt43 zqAsX{s}${GUIcnysTN^Xr6OFSVX8$~Ic*VK+#b!@qf%MjJ1cGns%ylAW+o_NV69E7 zQ}9_Ju1l-a+)9X-R_*Wr7FwU4QGqs`H{I&x4Zyr?Mg_W@pf=8i@D=G9P~0@5e6Iv3 zn&^EGq{7ihVQTKt%hJA;ieBpYV8ejS0IpbIvL{q_38Pc_!UWe*t}366wyLP7yhF$o zR*$fJO}7pBd@mw8(iBrc?=za7X=;e~hOLa^SehGqHM7nt#Mvx93lvum&N8orV{sCq zQ5CU%_U$pF0yUgB-Rk8Hz-)91q)ecjX#zbLnMt2Lhko4%L%}vTac=G}A zuizb1+FR%b!53oIN*01XT+a;Z#P!U?UR=)>q95N1MUk%(_-aIP$uWT@fn}z)9G?d* zSSDsDK|<3?qmgDJ?Cl|Sx_g(wtX5A%)Eg1@M$~#EYP=D3-iWw2BIb=qw4x6JUh3tG zEngbsOGLheS{*rPH43u~qD@@(u*@jBm^*phoN%pU42$vF%MoJCvLp)HL->+N%@A43 zEjqK@qJg>11X;^1JhR-wfw=*4E!I0~g`*+Fvo^Q#wWV;HcL4<=Y2FPKh^Bd0M3~h8 zK|3AiJtD#}3PZ=lndSO7$(h;6JbfJ@sL(V}Au43VvaNbv$QoJ5c$)JV1rlk_ffT4s zbN&RxP$k5KiWpN7%2bAnNNZ^O_!nO}J<=1uY(oR*z`Mmy&qg zr3fOEg%21ZK2|NVVTQwqWnmM2%yh|w(zr0&;9BL4!jnTT94kbVgJyRU#*V^&9>)Zf; z37S!U)W@#v!R)$x7VO&Yva9ibkzL#W-?8gTPnI)e+4f2-+dd7;wok*d?bEPq`!p=u zK0V8}Yb?8BhAi9u2eRz(yB%w_jT4=k_u0lUq?5qi7yc1~TuxxJrdh)tPGx@RM3^OqQoujPQAk~2~ ze}bK8V)n)MN_!RX`X!cSuSTUF$EH~WO3sR-Q*W)+Kpe20D{N5w&DI)XU2(P42&yu7#d_yz7nD8%Yk8i^vS9b)nQENpVsi=(jCG1_XKFt?K8 zPBEKbyF9a{~foL-OUwC8$h6RFcg%CbTPGmk=HD@ueTwG!%T5znC(A|>8~ zQRG4bO-a}bC>58OkQua8Znt(oQi6w}l%{SAHZTr^E42bCLe{Be_V70_3&mU1s_6j+ zai+W>7F%gpFr-S%JjmW_Qb#%D`8KBwg8r0S2%;5t=qH@FT6lvBy@oi=qH?>O#wqiS zU%b#fM$A6qSbIx1&EveEqFi-YWT2<`A%Y6ngL!^0wMitrmnI3&WyMc5MI2Sqq6!k=W&{9j}K9tt}> z6v7_*m;(|C=tKf}hXWD{00|>VE&wE=v%(GsBT-?{iB&&zQhJI16ka!N-j{oQa3Vry8cqi0Ox-WX4KFdjh6K zg$c^VaZ`d3W9Z7I?56^oh{CPwjhf2PP=Zn#j)y#c*(`Ccslp3J}iuFz7`^o?cu zA<&EZ8Xe4XaX52mn?xVUjXLkV-qZ)zjF-x}!AXq_H9aryAyG3ob7}!X6(zVnR~{~m zi;hq`1u0E~Cy-Q^ICdRXklqMOSsV{q6n7WH#qze?PDQJ-;%6_p$svh5u*e}PSEEaE zm7a0~R3_GQZ^?~0E7oI$iEOcFaBp^$yF4LB;4Wt+oRx9ezofbElpQkM^)L5#xr^eo zPLB__8n4^EOIb-4URLgCQ`}^_XVg0}_j*d9MU>>;!bFLIg~+2MBXMg{k3*Z%8xxqz zHW-hUov_>XrYrkk(IY9q+|iuBi=9rA8q-u=8{U#=ED78ZnVL6*` z;&M$e%It7-J;YE%gm0pEmIGy^4i&9P&=&Yn6+adfDR=zwBwI~N5c#k}{sK;3-Mvw} zxm63-ZC3XF)eCaqQM#@j_G5CF!`^h2gXuaI5)l z;ne{cYbs$Fii~h;s7Mnvl1Q!9HgFH^;$E&+Sr07{)7qIP{?>WK;ia3=eYKal;>FAL zOk*mhF_k{5m}kTtpQBBw8H*e+PDgm_tVIv2Xq^qtrY`T+^vmhFQF6`|yo#b7fJb~Q zr~ti*hTld6PkSN4E0653D2r-}X=m_WxZy2Uqy zZKCH@BxC0=QAqS$+E*dRyp1{KwnDR^+9L{&Zc6-hz&43BfRu#bDMa;Ed<-`-&V#RV zl6week8DWG+Cx=G-^~<3?4cHf@RPsyxBN5>{UNU-*4L(om|AkT!RAwZM^g73W4o=A zDb$oIrmPa}4aQZhMCHm&cq(`G)T}G_rGQ-~dgV@ruvnXuv=ZQszAarn!Ii#@33whK zXLhH;ooW({wJxrG)-rEGr$ada$4_S~wxtU$8@9s*feLL)yYABMB${5`TNS)^x_q1@ z7`9heXa603jMU5rOaONG%(1)ujkps%qMo>GEX$Y6wKLD{6r639LDC*%bZepYLve%Lx4jXD%tqQzf zM^AdUYDi|cu}Uz!Oo54QL?BX?KwH{frsJ&yO|cmTBiiaVTC)+T%JtH2dY!bAZV)PF zzA#pjj&@1699$BFjz5PirU<^ zueB_1bK9)}iDZL%vNN3-jvqK2035Cae4!??En4@#(bXk~+#M!7 z`DT#S3z(g8(e~@#yKFzvtXPNr_5lBGPA$!i^vw498h|JCQ(*@+G3ZYp3QnJSo7^~? z*1l0V4}$u#0&p8HgF#$$4`<&9ZDoWZuv2^n=woo;xtL|AD)2LIsoTRDUlTyfeusH3 zNIJ|X#!!fxX%ocf&7R@K`FmLKw>DwtVSU(21R9{69sXY>fo+irR>-1xR0GjU-jVL}`&e%5|mZeEm6+l!T~Tk~&fp zkSGxmTJ$t1W)GnE=-s|{N={?AK}jb3X1?Qs*YFC3OjwZNx-Cq2om9^ruG?G%_Q@%= z;~a)@K9+OZrk-ysTHuACy=?DeD%;IhV45A~_|ss!QJ1jrd~%;CV~q!lmicm4UqMF$ zV!@d&w)2d}w1`T4C`|wR;tmapzEz>&L{yqS2wq+jcYB&!F-0zX+&ECdB~rnQ#h7=j zY|(AqyZBtGRZH}F3ffs~;LMd~sO}6zOb|J#s5Dx98UKE2YHDb@jJyA^j4=;)QwJ}YrttHyvF7*`5-VLu#%7v7f?o02_?dxx~*jFS)S_J9%;UXcft^4_hmsx=-8z{*ae;rA z=&$%LQ5Cx{?WMN|NrVk8uH=I%`eMd?F=hJTpLUeKVY4ta-_a zS;;01`IuNuKkS{ld(wxz(|zceHwSmjn`beO-Yl5zEy#31%@x>+fbdp<_|`wxzzHfS zpN2RJ%+d8EXLgdDIYMqOW>ur!M$fxwa(EQ< z&)r;79;;Tyx4+V5JmxRsvFXd`R705+Y2v<8J<;v3BJG9XhB2>5IGu|7@~EGdgW{SU zsi&nX7YW8mz1u2*ASSM1;@?frS^y=sUDm9wyRmvxn_EE0afa|MJ z)~gZ-5?B=)sPAxw3yqe0S;ZCud+(k0@k*{c=_({9{fkuP(h`|_W=aNZn6Ao2vXIta zR&8^c?!i~w0mr6KaXlTX$IhMLeE#PseIm;09oWPv$A9HcvG)FaI^+Fu`mEqxT#z9y zOcEjDULFyZKFL(Vk#aPNe0Me3@mH_3?0C0dcD#Ff*%1gr>~NwwJM6%LOzrlccVI#E z3|%Qh}c?#7f|�Cm2Nm1`Eg}7&F?*qNnY0kLBr)Jk4_s@>{ z{Xx`A6~P}k9|m|}c13!iN|9tf!JrJ8};<{?=Fy9+_cL9| zp3+=xzUoX1^T-TfI3xW{+Ntx0x|}l#NQ27{z7qD|R^)_-1BuvvB6bxbj|38_^%JSB zLgc-HL}Gp-u_{FF3nWtKCsJ31$f-agaX*oG6(aWs5{deWM5_>aAdpCnpGb{DMDA@P zD_jy&rUI^6f7Q=9@M?q#8#I#|ro&M`EX=kxzVh@DXX_kU?dmq-HV4wX9rmLN)ucH0 z^MtaUGUA4`3jv6ncQvaiFgD@Dx{k+>31#qc$DvQVY(g%TPk8ohqvG()FdlV|HPxz? zl6uAi{ul>$wpA*qw8m9O)lWFv`JnBeksDl<<>;suifAEI3#mQu$uRA*`(xBUCM#62 z+G3%Ie}w>jf57<9u+~M7tMcSik|nTFc2NslnRJ-gu>V^x2d+opCoK2!2)^0Hw4bzW zf|cP+wL#k}e8(KYEV_nP6lfLu z(`mW0_X*FAQLN*~*@;GKI<>W*ko$xW@{N}>>A41{=VVv-j@N8(dQO7SDiL2%S9nT(fIHLd&pFw2VA|)B zPT}N+gs0r{LNZbK2U6x+nRoGQfp^tnaPXJp3FUdqGSI4pMo@2G=i3OC&&7!owHkw4 zif3A1`m;X=wCRxl?>!?C?I^8E8Z@BGK-pMPG7d={N!otUqT z1he;CG@(bViq0{#h{d#bLW#JTK4VY_U!m`|G>ag`K_T(z4n3n(+3~lBd*GsC$GwB<)?|B1u@Ck1r9bd=pcQgJs5qy zM87~@w}H10Er8gwkvWX+_L+xw`*eQcFrHw9A5@-=ptM*P0$hgIj$s_-9Qk2{uG3fm z2MSm>u}xZkn5M`S36VpKcjLOabv9(kd6fp+?bdfwfoW59DMzRZGkZU!YZPek{4E%omw~LN!D}RotPLav{T9iyosZ$2gFavP6tp zQy#Kw(`b#kS5)CRPV>voTv$G)6B<-4LGhbN>cR%Ui3D#XiL3YHp+4M2cbkcl=%rr5 z{YN|(el#9GcNEgZ?RN5pI(#;z<4Dk`P=Ef3YO||8$o#oWZ3rL8G%dnYS}0}ipG+(8 z6aP7UE1E`jqe{|AFq!zYR(`On)>Xw)QZDe&(>6?UkonXQjV=NeSOHj|0nAqc)Mn!! z#c`md@R#t=LZuO$bc*qRp=;uu1u8NJZBq-hXgYw4v=S#PWbgZoR%MUHfqC%d`K!9n zD2@AYmT1{JbWG_d@y9oc{SS3?OU#D_e+=3HcU3z$&)9!u11A#FtDLR?Jq#;8}@bG{oTf`@iPhgO#saaUMLAJl!_Z~$67>+ zyN)aFHpX0?UC(v)gz5y|lOXB5@ss(iHWkM3o0ek_c0FcUwl>UDU$H9Rwi#C0;<*TmoV zhy#K0nNoRo;h=lfPbtf_(D5c!5z$4S2k>)En~rKobG_3>cc3cLY%#@z)fkk=7QeMJ z#kE*mTsZ37Au28$jX3+;`9-4qf~^oe!}N^MGfGdJp4`!9xQ^bM&8=j-d<^~{y#|Q* zYgqB>8{TC82Ex-t)SC!gt?S%Gu$6f(e+>tK@-dZ&FX8po6WhcPxDZ>4-OOrkW~-hu z817MQXu0NQKDulf3!_qmt5EddsI2eRv8_N}o?Z+`vAQ=Dy((3)CEKF5q5gU6A_ zkQJH3A7|N809gtH#RLXF)kVVuGP!#xyKs@Yyz#4}Z@S}uf8u)&E3BLGt*!o!subP1C`c$j5$Z!pRyiq_|?>RzIa#+ujP`=GC92Pxq^n5xbw1|9r@xT zPoHV&HtunU*<3!%mb+=%n4$)|*ljQja&kB3ZI9I0)nJ2IrC}c|x3a?-Gn7 zgMZ*bY@?lh!ao{uziC_?SAdi|6_D@nPLNlzZg#X4 zhaQqj2~?3#O2DvlF7FEe>PGv)Id@tYy?oP=g$rH=R2;{bA}ZJ@gbHlkWyZdHc2i@z zdCps;)>5} zBHM)bdw;0=#(SRprHQ4Qdh9X0XnobacirAP_4u(A!t&G%txp)ih?8W=5a#w+Tvk;EIe-kVJ> z?UAppVBN+w?9#(R*w@zF-1hi~-+1h%$G?7BaL}e84kD2&%^KpM+w2FUcUp_bZaT8Y z;h-y7_vin4_jfoWK)Z%3gmzsBh3Rg@bHmlwvQBu`Mew}0AvA& zvAZLYFfc>Y%7+dMF&%;8Vo+;f0JDKjkWQDA(eX$$3^hNucyag8-OasV=a~>8Q}2v~ z45&5ySWp8la2JEs^D5F7KVsw*S;3mvDQ8~IkpJlav#9zn2P(2lhja2^NAAfGQr7hf z;0=7-Xi`O=p@}~APGGLenH0TfpYZic^%_{YVYm`XB<;Hd%!|Trv^g7j3@yPh2(xFW ze$~}{j-{2d!{2Xtz2AlP{*zNRY#wqrJ70CfPBSuBW~3gv=qm3Ss|dW3cE+?DW=Wem zZY^?ZEsU@uUwCKw>8Hi1sN8s`&Adnvus}41jShi?BmT@>M0%$9*sD59w_JG2@froA zGLA|@Ir1E^!kKy)DhngV#;<7Bt~+x`;DuoCV=byT&K(Zov|F49h;t|9D7yhIWEd_t zRG(I8LR5CPI}E)yOX?R;;yHW{pL*vZp${3q5C=Um@)Z0}CJb$uo0u>+35n%fD@`8= zgoTlv=usyfQNBIHc7iIX;xIGQd~y;KTNEN7B?Ex3YTPCrTe_f|58u>#(4%r%n|8PrM?T!0A|*8~BLFzD$_B z0q}h_6B40Kl|kaJH_;i1RFC6T!)_$RG3J8U$++({s`ZQuSqGwe1}Evm4OEYcm6Z))0n=QDnk;ea>K8lGpI@_c}x611{MKEB!{eavemyIp6kQd)kr zNgzs1a>$QTlXTUTnIwm)2epS+%v2Pe#R*1|d@5h3bg3K>l@Uaja&buWyADP(v`CjU zV~)Li!NOxlzkRB_>I*+wB<$18(mw5wmhd8YZgEk;yz27da;Q!X>aY*$ti8!1s`Hq+ zg=}4`lYZT3ynO{L=Ug(l5um zU`K%3l{T$&wWMO<3eKeMmC@*LaeL)Sa(nm;CQGAYR-s}^3quSEVuV=Qk5Cg37fExm zYbZ;YwF06}>@Ja5tj{#q(TC6k4ZPUW*Jr-VqRWK>Ug%8c?ur)Y#|De@UbBbbhwj?@ zLvMQ4x=XP0z?cK*!qlWSc$738Dj_`d6>h$* ztAan>&9^SDQjmHdp$4@ejg<=0R0V&!g1ESqui%|S4(lddYZ4rVClpDxN}otDm$#7p z_&jf`KF@2Z$>09?W1oR}-t#vL3ARm2u&t_>X}gTQLdKTh`D)d1wwXC>DJ6+mYz`rc zCL{z>7;-zu*qt#{MQ>Lxs@{8M+gt-jzPWJ!oQ`%B*r;Sy-noa!f z*st$+5v+D&1ue20?a#f;jF%sgPJ|t@GFMA`bp*}bHIQ)R95bI{^RBIX(RKVaG~Huut(PM{(y=13ok-R@816S zXTMYT;=yN!p~NkyydmSaV~JDj+3(j5d`1)-la{T6R4DK_)DoPv=bN+|U&HECTsgcC z-6F4n2)dt0u2wsuK-5KD)|L{9Aa?c_=%NU)vv(7QG^R*X>V9NxP8yeMKO}CQ^E3Fm zjx7$$iG__e_Ijw*(G^fkNxFIgRIAG%uZ^ki-7p*_z*<>@fwLw~d7x*!%rM96p=r)P zN2rkL?i^BbyB18@ql<8=S)H62;BIntnMpHO2nCisV*}p*hHYCG~QQ(~g zdZ&8f9~!GozT^~AmYggRbay|8Xq&2SIbh*5eMB2kBKQ!9FwjLD|OOj}a zYBReUv}mF{2F(0KT%GUXH8aO?af^ligT2Y%6VqDClixvCpWNBB3zSrpf5qBBhHxM4 zJK*;NaeK*w6{A%mI@-uhXyb5=v<=!<)tS*0^0_$4jWH9^_t5NflS<1{7Zya1t= zGKU^n;})N9I;C0y>hXH!;^E{V2(L!Nt0BA#JupogOjB}+Q)N>9mXJ_Xp*U}V+MWva z=SVGFdO6{_5at7zCb*WeURbYBmto8|E8CxVUv`LA?7-wEB{{C{!xd8!t_Cj?vR@l? zd};1lxir_vzS_l5rSj37LshpCl0mt4*@^bM^6m(6$24y1^tnAgh~{1c)K}kbl$P6^ zEyJtk&PEnsF*iXmF}nz4cR<7Kv^N64E;jL<(~;YL{)0tE!`YwQ`_=7tnEURwf z2XHDhC6r^=z%O3<^lg8B?4_%Jn>i?y`EIGqcgY%3mRCW-k>>{gd*{^at~&l{^&X{8 z8(o2EHu2@%H{bRI!=;C_-+y}Ix<@Cz|58AnecyQUySa|!j_>|;$C6KrJbPrGX_+Uj z&2&J*xw^}{SY0glPcLgbuY{Q0qPDwpd(u?wDoEU;?#^pxPv5n1>Nm>Lkg%kdvuC&8 z*TuTD^+)?H(EP7am;Bx}t0lk5^Y_D&bAXST|61;g-3q_G+H#-h&z0=ipVqv7Ste1t$0D$;&(y^^bz~~gwe9Z9`@|i=eyWp z|H1@tA3M6S%EH8?Z((B6QRDuJ_MgJaL5;rf2=r4K%K=D78(O^0XU`Tju|u)Cl)lHWi5yQe(XitGDcfi~0cVM^xNX{ua2 zqwmesEuFw?+@$9v*fb36P|c5xKRIr`_Q`ebw*pfnv99A8*UcwAavj^ZZ%?NG7QBUPjdJVaRNXxUdvpz`e8&ml zrjHd1+aN`Bq=ITip${k&sTce~y{|}l->$;_ZaE<@~ literal 0 HcmV?d00001 diff --git a/include/SugarCharts/swf/lineChart.swf b/include/SugarCharts/swf/lineChart.swf new file mode 100644 index 0000000000000000000000000000000000000000..46076d2f2e6666f4c7368ca11f42c19fe0b36b1f GIT binary patch literal 11780 zcmV+fF8k3#S5pV?!vFwyob7!HcwEJiaJ`u~Gfx_gZd%6%1IYum;Y7MS-j1mrxT@d`{_T3T;ajhk-uBrg8vG9?z=#LHm_?n9x#)Kogr4=q(l>3?|vhBYi1dSYF%z7B@L zzgEwaty|E;;?Tx46yL)2x3`SYq9Zja& zdfTBZmX5^sr<>wk-LX`9O{_oNO=;`5cJJT09{<|57yxq=tUwIG`}%4z-At>xpp08xdV>4xsTO`XZ(j z1ueGcEWyuVpyjX+0?23x9uA0yF))mlF#)p>SHNLmOBK>)1WoFeQ)-X_i#QBLn#w=! zf#}I{tvDh|;-3-@OF1mF*onVE1le43y9Yizg5s+|65BD9g3wDq!LgR>tP{?w=7>f1a8op;0@-1lO^Ck7{8*eK?(pqj%91s%s=K88iG8NLL;o5kc; zI$^^<%zl2uzd!NY`(B^FulFm5zjNo#Cx?G?G`etL_7`uFlVL~|R3sZ@oQGjCZ2kRL zui9|4Ig8F8`Ejf;JQTfta>sSAmp;+*`hx#_{?5veet7!KSk>+ycfP#-3lBap@92To z=e^#$xBR~86KDSDpC^9jgDVG+0>{ymtHR&QTEN&`}GqRGp zYRWXFn7Sqe(2+>5?uoZwA^^$|AllR49ku2VT5QV1ViSZ3UC+O$iaX|?Ldjla#8Z0; zANM`ACwShQTmN$TAQma|=V1N4k#V#2RV3VEj+#UuadM?*! z@_{%F-X@eDHF)hs$u@}bY;ngmGUYIj_hGq~WTTYhSn*ixA8km08lNVNZjL-N$uE)u zVg_AbzLAF7`B3!^7L1D1`f@6^b<`33Hpsn$CVT8ISTEOi#qVmj^h9jZW6p}zhf#>T zak1Tq|LK*S8NsoQ>dP4?Q=m;8NiDbn6_BA?&oUEP38g9C=~!?7mUx<`YnK$ndSbnZ z5{dQ-s5QxWPtO+A31AcfQSE6b;?^aS7E({FuL~81-N{(=lFft#o1z%+>`5e&NNSwQ zXzqm6!0uE!8Sm?Y<-3#h(3VUj(vXh#6Vdns%TxW)zS{PlXeza0W>+#X&`$);tcT?b zDW{&W95AH0VfNl=&p?a`sl`9&k0nW)g}R(*OnAKCDjC}L_a+8XF=*Qt??B31)6p)} zXZg8pKeQc?x!p19LXbag2Qn7OcV6d8#!~UiVp7>A-ifDGQSR$hPrL(rojD*Q8x!r& znLrk_Qq(!Bm1RO2^%x^Ww+#nhMCw1w2{T|A%f}vJS?~*NNre&HN@<9JTLPkZr3uyW zNUfIY4XSCCDEwUn`6xq{I5Nqq38@E5nJZMmgt6tcn(HMM*W`plLZGh`100 zcS>m3nnTWxSlL41gs_7;vm~lCOtm{O!rYdL9IJ|;`fp4!CSxuaG9~;@vGbG&7gha^ z6<8w*oEjE-68}sKH#-_*Gj~N=ZN!m};i;mS>6|np!hN_L+@+j03Vx7yTSz_Ij5^dQ zqu|;Isbl0Sem>n!!pvMG%yMAbNjQB>5-i+tte08XKRe>`9Go2boQP>QkH`EG;am>q zorDo&$D2R4DU_4k1spD9gUF)R&hbSptR9HjU~z;x?BF<-_9e`Rr6*6(8RO|UQTmzK zNo+s8Mc$DuHWe&m5q7L{?sa&y<-?*yi`X3^Ua7R$(?+K`yJqv(pc|&B+H9F1+cKp> zZ&-#}`lXms_IIJBmntp2BK%29H?LK?Ii=>*$Umhta)Qe1;bRt@*TeIAcwP_B>*0Al zJgY z`c0qd{oKF2(9!i+-<`c*_dol+zuY(BqVUAMpVbD1=e|OD?#tCi!}%Ci(niBzuvBd{ zG|m3PPiC+B&5fUbq57V$HedF_jO|~m`twf~d_7Th@9eqk zm8m~E=gO~48ur&*bfyygie*XY%$;-k!|CF+AP1g?r);{OWk^FkHQT z`1U;?|C6WdMc=KrA3i)d?YfrEi!SHm|J?J^s~Q_!4v6bcrx z>IS8uxwU~qciqxI@8W@AclwT<5C42a@00Z}blofqsaA!YqHL0>7}l7D2%E%Fio~3% zFl+4Q$F%pv{Fsv6{HTVC=KC|u50N^S`7xED^5(~w1?SC=y!nwgKl0{B-u%d$A9?d5 zZ+_&>kN3p*<$9394B)5yq4n;*Mde(>eD?%(p@mcfBpfis`o zuyf)(lnFbY-951Dxh4E3>d861z@e zpQdb-%aL2Bzq>ZdL}8DrkpC-oN7ygW-?q zu`~aF>-O(Y-g#BagBQ$cJf~*En84)WmoDEywx?zy&eD>LAsnP|%xbmXH(?0n0?HyM=x_ieTj<4ey z&yRlV&)41h#R-LVO*hY7{-e$(+Ik*7O%^;y6+Bzn7YS_M-1lS;(d-$%J6mx~%uo!i3 zAI{f91)j6*+JN9dd!i?iTnsJYRp~@i>xIxX5DP44}!I?-w^i>1Zm>eg1yV5P>PySSQ!DvVv1Gu0V~W`ZgnHdW{>A~|Q7SYB@wb+r9k z4)n)hH@0j)9Dse$4WjF!N!T6hiuZ++(T+IQx(+od&S)jFp%=w}OM(;d2Mgu=-spbl zjrYN!3B>o77+sv`MWc;-34RPXiRfB@FA8(bCtAyO8faDTDnJ9qJ>x(q0NtZdX!@jw zqOd^rU|#*9Dr#<+#M9B>Ti?+JzjNeHByv}gBFWTx1huV9t;eiO)a}V#mxt@p6pEuR zjqB3t56u!oG_@tsgwvoG^f}kiv}eIa(Q88*qacsW8_StXi*fB?R0FK6gUMolxjbD0U|V-3bNmgrX|4RPmui zJs9etR6Y3BgO^u84>4CSlZLC=-&UXK2d6`JRZs;X~$U;SAFd}4(BSjG*fgA}%gnS~RHy2`&9kIZU7-XIn zTcfJbHmXAAq+kgiF80N`=e%ZuEwa!GY-qvkXeESp=rmp^H`?p#+_na0(paY~ar+bWv zk;4%*{Q#`)807)ws>B|5#fqu&sufjPs+}jR)f@=Udfz35yCIu+fO)Z9#Te39+!%5tyQ>2NKEB_R!R_4mD9wWbIwDQq(o{Dlj zEix)dt#PU&Z@RGlW`uKNp_HA5{FvGZZl=^J5D%GwGQVdn7>Gi}q)8I?8fuPfUstq z(Qwj?#Vu7hb}Qj<3Bi=<6L}5Aj3q5{UG<2CLNk`C6rV~tqeW^KnJFGuir1N<+FK5o zX^J>zp4n1$XtHGzd!cxaR+NNL7X){M&m)#z8igTKX$zTgp(O>)ctB~8o(wIskeL*a zluJ!&Sqm$O&LmUMaRHx|34B&dHeJ`x&9y4EG@#=2msG_JaFa+64Y)=qU#vv@+aP(B6p!e$f@)A`|rf;pOw zLn;NHy>N$zJIXA+i=Ej^W%(l(5nNW#EWgNn3gHtr=zNwmo$0nDO_bbJZV@d~r1cS` z*6U8yJSh4pAeIi@Q>2u4OU_QIs9t&+w#y5`3|O7e7WY2bM1zNm*>A zjC6-Ubs`@wU_OWfDBdmO9vT0DjC*DLkc{gxevgd%Wc)Ee_WuAfd&p<@ke7Ps5fj9p zr4t$CMia!F1;j@n@hl*Irzos5L3}2N*9kHs3%M4EpFl`Tyf4oO7}^nd90vO0sO+br zJ;Gr$(BDChvhIQ2-F?w`PYU{ziS}43wT3>nVc87iLUK5;wo?jkuHn-GnbjNblS$H* z*XP`WYdZiPvCil~PkJMHAt{MJp~9Y7{)~$Gv?-e6{nvKFbwpa(gU5Ss_Ki5#Cl6Ld z#r`ceH=Saapv?!@j%d;T6xX{CO`ya+uGe%<_R9JO*k_E{ee~Nm(92|7pHCqEv`_>1 ziJK{CWbU;OB*`N!9L>C&nxY-puy~SNwpbQ#*rwzrY9bx&Nm&lP^+-O)*dLpMmC0oE zfB==>o!Kig(us|UeX-=~Xex$fl24Gb*?ox}#n|+)S#HhBE!vd%9SLfgb61-7ty5y- zS$d0w$H?aIaody`pP`T&xN^Ie7-&JXB=!;6{UT{|w4;MISB2i=Oe5{conlqm=J4XL zO81T8TVAy#lH0XRj#dd~iG$-)57Bfw+TP6==BGEzePJhs)^@QFFqSEZV|T`*J>-a{ zU4Pq#@c|U5*8XTaVc;-|_YU-`XnSIyFKs&(Ah)RbQ$FVKqW%*ap5+Xt-Fa~uKx|K| zeR-;j`-ij`#=whub6obY>M|`5Jl;2O~?A> zE|21b6bU91JM(~GgQG26y4eu5fuYWBKvd-_$)#*=ZU#V(YCZ z5hX;Pq~!?~F}8392uIbH4oUvHMe`L zk6y`*AD-64dLVWLQ_!~@oFBZNa`-0W~N+TV>U zu6K{tuDc8jV0*-#qPccoJu94XFUAdWJ)l)X+kid@JO;G?EmHmLEv3}Ml7oiP$AXJ?EBlZiRFlR7xrp$HX}T_Wj6GDpe^W4a13M^TPtP$_2`a zlic{SbV0>rnLEjjGDRj%wkK9edNmdE(0P)~wCaefT{eixj@TqKMw+6lvy8v1&N}H% z$j&Fo!YAz{_#|Y!CSo@=x;6@Xwn}79b!Jjt9XLkqG}kDuT|tKG7O>js?mTc11rDOX z(P(gq_Mr-g#t!7wAJ)YnuR&oyH6o~@`Ud@TX^GQ9kXjV1*7GzUrSF;bt;^v%2PM@1C z-8s8vww?AjtVT;$-8^-a2EzqR$7GN-3mEcP7z=0&bviSc6DLtmvt$()IJ4RUGfU)@ zuxjAjsbyiLIkQB8xkwzks$!E7qb{Ikj%?=M!nSUDi<38Vr(@jz7BSpoEY8`#Uj5#(5Un2Ipbs)%K6h8XJvG?3Z*_;0jm-dFUe1?q2(*}u zsiA1A*`6AQdMSXmxJ=1%Gj)vdeVotRUyxN+>`b(lNj^${LAAZ$CTm$X%L#&Up<`KI z2NF>h#NATuL<%4hXA;5$XC9JyA)+@syM5t^oxf(knij3ugrL~Zo$Q9-BLw$?T{havjHJb zj^*}j*`l2!Q{r@%J^LaK-#^OmkeX<9z(FBC?})h6v^G~O1dJ)OyRzunIf0{6wHzB5 zMRE7&dfc+nvB%H??M6lW=tQ6G$mtjz_+r|h8YMqwSw3U4t5d8k*)0X?zAxxG(NWmC ztWL}n4k38mnG1X-C<$SWZSsv9-IgKh6&tnIyGe+!rzMksWtTSAlhC%E<6nTBIcHDVid6#15iP#N;th=H0aWktT;Jp#kR^W%~IJY6|j!# zlha@-qIzllM!U}^;1f#e zccZGygrF+lm)4x+xK0-zbs?WAvgQL3$Lo<^Yel3*tysKKsg4bajLTg659Hqu^4V=W z6gHYVXFCp|%{8wg?;HEm{((B*DNN3m_Czan#`FMc}~ z)s@Co!lJs|rr65a)Sh%Dhl9K%eh`<$tHp|w3*;K(TIxQx$Hm^=yJ;vfz@M%n0B4n` z;Rd<8oYg3MZM1?rBQD+d2>IwNRnMdPaE0LZze#`9honLAVKbWzit9|w8Vhwu8h8rw zusp{qbXyY!Td{`Ioi95UX0=6%v!<4rsXW%Nw~cOL6dZIo>2I)aW^4r6aGSMW;)vbg zh#hpq>@B^Koakk?qZ|Omd$jp}2dQ%!v$>+YS$tD+yhw5Ha2vN7*4Gm5q5_wL(&um~ zI{W-<>|OM2=K3&x!$>BnLCMpPD4tSPP2?BT3&im(%{bH|080q)Cf!;zSl`FAoAn^W zs`x)(+#}*#_|0;XzKLJR2yx3o1Q!Xp)`5?<*!)nUg+-z3vb@fd;f=z^7xFr#7mAXb zRh`aF7UoE z({#w3rb}h_(;UnV_?T_MiztDUSk~A4JPUzS%sQCPUzc&=3@f- zNhS0cw?~}G4$Vq3Fl*r++O#zH)Pv2V0p7u*L3lxD?G$ z!m#OXGkENTmDt%T4*L3eSb9~U#sOYZ5;$F%qafkvHu zZ%5E9UTwZJa(Dp*R>BzXJal%x-q4AEqFPnGjuV`tG-p4Uo5%K%Ay1@-977^tI|dPu zuSMJ~b}g*gcEL#I0wUI@PjK21hXeVZYFa374-^5|6SlDuXG_onuh|l?fb)I!*oPd& zZFOVcYpD|=;ghWRsDvOGi)?##X5!+EL_|$<57?jvGN6#4`yAx?W!nSJYe48sN|^R! zjivVGX*s3L$Vj<7BV}$z%KaHBOEOYsW~9s>2Uc%J%B2}8vocaX=1f5r46mf{QyhMp zL$TrifMl46Jt##+#6BbQ9&$iFAUCN?J{k&K@gx%iktf*mm@A7&nP#?2z*I|9!Nf2j zg$EiMjB0$C2mAhV=;v2G2S-4g#n(e?b>DpswAZe0l$W;6SC_WUlh;%GrvTreHXo|} ztCt^lpVV$JYB7HSY=bL6`#mB*^2j4}U0mXx-yf*`*1Spoc}4XjN8p(8L!1B>(kDer z79h~Syxe*7OIu!qg;(qF9nfK@1A^8?R?btC{2J3Xd1}zS5K7+b;XFvbA2@e?d!mm@ zLA`wwL(B7(&bvEIvtm7Ob$F~BJTUa}vp*vGDOe*haVj);Dr=Srh*%)as6wAs16L!{ zhRy=^fVS6&IZt<7%(HK8uQRwpUhWwO$-wXvRTPhrf%E=g0h2VxTO9 zr$>I%2*>S*dc{b(2^ZvHFGBN3a)>UyyDk1Z5oqWeP$iCrJ6?2<2j^2UacX!QUEYBq z9rCrG6Hn}osRRAn_|SHuZ*5;XmRy&l)7|d3CG0nq^+Z$YO^9xL?E=S?;$UBF-!^jq z%28>%(Ja~*@0G9}%>!vTRBk`m4&eKhHpfGnBAvToZW|u+f%3)d;xt`4fL#Smu{V3N5xWKwRw#pl421;g=GL!sWYgpAzMa`fGcL3p~T)6c|4Me_iKb!hUAnp zT1B;(e9B~7#JgUzz${Crvh?ca460_JUfKp0Zb5ZdR@{ON+ycg(;esp6fGew>VKyB> ziij0KJH+&$U`D7p2QLI-rFq0s#3x`}j5XGkbPoL-hB!1hELcgkRhYH$EqJ9q@jH=z zF}uu`jnR;`U&&#EF$2TJ&=1AWZF{a{vj%8M(E9b==e9lnUl+Xjjk=O4N4{F~Ik`G6 zQLE!(wL0>k_hAN&=|;zJ6(~y;$^wP52l)QbrEmgMjAHMpcki;sn>7*8R;+src^@G2 zwG>(9d><;JY-?RJr-zm*ZlNTxK#}Oc6Cc?=1Dg*w48l)KwbEn1z2)-um6Lu7ULaTT z-S|I956F|?&wpCwS@=@zAALWNZ97x7?F`j6QZh~tV#bMm=QKib>glc*9WO5&^PfTx zA%u9Q>&fF#qCa!}p#4>cWBy45P~u>Z`8wD!x}+AC!G3^`9)}6^f%4mLza6{lXLYw$ zTsHrEKOMR3D?1D7UWMuR?vgZ~rD$BHzPEvz4V-Ni0Uqvj4m@=)dM>D_A9?fHf2+Ix zG^qL<9K2qB4E=qooU_$!wiKSjGr#7xNh;HV^Iz(dx zHKfU%3%j6j7tB2_#IJP1dAqbKNvxK48zlyno8g({F{i`MSyf*a7;iBa=&;9BOYUBhU3=M7|>;`ypV&l=J z@|s|(ekF8HyyU4*U)qQzbiyVm4Gp|hc_1G4#h-bCsy}9Y7{ziGKp_|_`JGTWO#0q( z9NgL7tT69u>+D21-fk{8<|4$ajI|DH;#3GPCSsWu@7o*Vq=|hhvH|(6YXLA8AT{D# zXo8_ClzQ{h-YgX&u;#OCAaqk3PN?_5;bL&Mhp&v4jS`kQ%AF@0T-KXpXJHNFDU&*9 zyk(9QV2{FTzJHl?*np+8EQf2KzT@oUFbQ>cOLVJ*=+@gZmF&uq?!)S>Oa~D+`TYUx zc+9=@+TT^xwCophcP55wU^5(S8$?3xyYD`ohp-0U{`R+p0MihtIJ43B#>K`x6(7=1 zeQoEpQ%`vfQEA3rOQ>MfGAaseqo?3!$IdQ`R90O5s+9G0O4irfKiV0F^}auB`S~E< z8N3=X7d|}mifZrUS2yhWe}h=~987M4<~Nc!zO~Y8A8fk#<}bbOA*x1>9zBZib8ors zimH*v4~7X|)U;mJ)Felhu^fv(kA;1$5ca!C*q0)!qse4q-#W=!**63IrnIq?4fOY; zz|o7PmaT$9tXX~dK@Z6gOD-+tr}DGcRKKm5Pi%-(=LDc304WmsMJOZLs8ggls2X$l z`Rp;>5%bYtDa65ot@}94%Z+;iAJV7y@4R+_DM6c{>7RbQ=_iBgGW7*t`<=aC@5jUlP6KL) zaR07R%jg0+u2u-x%;#zyd9g3A4n->YG(@khrNi1p`2jYc)CKjbDH)^IU;`cKE( zXCH)lN7Vagz!zlG|I_$0bS4(1`n5ZrR`118r<#hr`Q{tluq-SN`}C(dra$|osLso~ z*@_ltESG{KgG3=Gia%nz#x*-iv(#%Qi5X}$JpGHF_8re)t1a4(`4tC;XzEQpCogEbfs?dH$kk7+q z*eTWJKWy0Lvb0cpllTqTr$b+di5Z>_i}m|lZ-}~H9aY`ColHRNr|o0}iub9-cBOb$ zW}ssTtA)+#f433Gakc}U_gK@5q~^+;p_)FZ`K8$ed@1aoxC=GjGw_gE7ZGNb9tl|< z77y*jv9s7GePYsf^VvLW3N$PWEb5vRNgz8IoLl0xbO)=3+6Mr9y?IX-QMWv-Zp3i{s(WOvg>on1cjv>q<;^@b0vcY{T1%!o3Nr~Ct zmbi$KNnKpz5p1C6`5@J!8oM&4SKGX4)kVBNWPk(;Fk(MgAVzgC<2AY^AcnsQF?t2J z^VKj8-Oq*4EUe*jaW{yq?ywS=rfl_w$E2&Y7cyUs#UXOQc>o1u!>H9cK;7J|yQ z|2W@#^&zBy=VwZ%fKZMBqHF?rLe&*52!eF8l5=YAKo z7hIQySQ9vZAHo1J@W|1C#H9LTu@10#8%lsYX4`E^JZk@p)5p*}tyZqOj#uBC`&2pV zIu*58+wUeZpUJbRZUe~iAp-OM6DB3|+LfMkbi3_>mUr?V7U8hBZh$7M??Ee)#s#b1}{UhEcvklIk>_+s&qNci26(AK19ftRu-|n zV__D={yGIbxt! z>{L6JEvLp+p5v_?0W#G=TumnR(;NU(6@YD#yujvuYeai5oBNGcxeL`QcY#_YX_eb* zVuLb(d390-u($5Jn0r}U8$ z3-_WPk;?6y;;C3(WB0f9N1dD(>JMP|LjB@z?1lPUIG-Hb*6egD&*^lk`0Jfcl{R-% znQ}T=Md#g3qg9Z1H@(O1CfYyW3A_XDZ&aH)2Va{!_2AHd+?AgD%~xurR`GtNRqRyz zg0&d7S*Rl;BaIoj0&157YA^%pnBl`|HA<_Qr;T_1^j-X8>=gTemuLnIT?WOO4j(b+ zn|>NKlbZ(|9WE&09CA$BJQ}mQgdCqZbE#v}W3n#G>Z&&K#8Rz0w)MF?eCMyuZKE1#imBuPNK?=n(c)3)A;a9IC<{P z;7Q@MQ2+}}KntcY;(+&<7h)*B+P=tWC$)GK{A^!j%#Ld#q$H!DQad4KxdL&B4(@#X+v;3WyPA%6 zD0elW#SO$*Z7?WGyWF%?K8AJ&G3_>R3BHZ|U;W*A|@pB}(E zRo)^o83{#^F*jk|)$RZNgu?;dP(&VqPE@1(E0d^tVZ;Mh70^+#F4*^GiT|q4m2Upc zl1}({;^v6tDyqlJ`)g5A>*`xEozA6BuV22fzg{^DE}jq4_rAt?c)Pema{#r}gabPup&@T~QTaN%>!{^Q!cA-6M?v literal 0 HcmV?d00001 diff --git a/include/SugarCharts/swf/pieChart.swf b/include/SugarCharts/swf/pieChart.swf new file mode 100644 index 0000000000000000000000000000000000000000..0a4fe7a75a01e4dd72f5afb740b614f65cd11119 GIT binary patch literal 12168 zcmV;3FL%&GS5pV^u>b&gob7!JbX-T3V7>0w-LKW%`pa_cw&TAOC;rFz%C=<3mYmov zM{*Jy2ufROOKrE*o$i)D`C&qW?Esz(VKf^Ekc5zh%!FSEzZu41hhIV#ILp}?hBq=t{C33;;Ol491!}mV|qc-}Sk#e}7~m#ipap01|-2w}-<3!B{thr=yKA#)1&s9^44wsVHOP zr}j*YWKOc4sdfe#i@y_@kEs9vdp8i52>Q``j*P>Xc2j2KXzow;m*r6;oEgg!Wy9?72&mD)8?E}rV=StwyPk}jt) zm#F}=fG_-+azBlflNv~2Aed@>e}FxRXeK6vFy^{?358QrCbJ?T)?X*0B@m6e5CJ7x zCkp&D;4_w*N-!&K3zVpMA{DEbUgI3oYno$v&2vo8<{z-XrGEA|&JMk4cIeHsLvNiO zdfP>bIsCNGqGQ3cW6m1irY9HxYTIA~T&I4Ub^Km+>i>UQv~DS}E=o#Ji`Fezwibw~ zg7y2Ml9&@JjdMb!X>R!fjniDeAS7mo-Z(q-rrDvl%nrTvVpZiuD`!ip=vg(nO+{22 ziEx{Edt)aW(?Ox7b{t6U%ukfl*$Gfw)6pw~jG1UKFNU|X?_=$xCs7OD&Qg=(hh?Y_ zRpssY>|-agBjvGyOeuSJ24ZsM^zHQ1N9s~4@9adj+yfCef?8yb`bIrEIGhIc4B&%> zOlE|Y$Fe1sp8z$QDef+&$20B$f!B?NSQj6S3}-Y7bYo1=6JvT}LY|ngCnn;FvGf?y zcwN}hdZ5*u)Y#Tem~vQ#6^~dDUbcvbf)I*Q2rx~{pusaqT_ujOAuH$;8x{kBk&IzD z;)EUGrc?qGEh~iKpeGT2n=#aKo|lRRo@JX19*!pY0JF*fbkh*VNvjlQUc01_IS%#! zn~E@5F&-UB_VOPy+1JX`FXyu@kq(i|Da0!d1zRqdw&<|{yNXRU+JHK}<&+Yol&DOx zAO#Tb^Ohh+>=^Zyz|cw%oM8!K6-y9X-Y>dSGj=CaGYF=mC72(EupedM?d(q0APftw zH`Eky?0eLa4l%9~9O**AGlbv;dZ?|j1*lnr&l>;6h##CAKVa0XA#B5tGz~Z|HERT$ z_07msD`H?(0V7~VQ!!F6#MXt#R)T=Y<)Rpzkx68vNOIHQO?JqSdM{D$n+^3|yEz)L zIYPuhc7gRkILz)?`o`b<;ytGg_Py_Yk2NQbMZWnjFTMQ}jqhlf`dqyCU%q-e@cqAg z`iYMB_pC9aFP2w-`q}P9U%LF&C2JpnB&Scrl|GSBC9cu0Pb4Z!tw?gyaQcKR#iviyO`Z3N3*mN%T4jLjz64^m zYDf2xY%a&ABO)aTawk%72@F%Xg|I3FVg@OFOJZ+Z{Gcrr)XAdQ$>JypAX%KZ35cM? z1STfLl!KN800@wQse(^G7D><&hcTeSyM?x&e@QbYEH56rtg zt$S&@*jYb1??ii0^b%-f1wsZFHcJE;8W?uh61D+#9?@+)R1>K#5@}BLRs%)2E&?!% zh&o~+XfC3@?Ehq*XCOHhVmQ9}FI&&fx3W#WnhSxdH)OhVht9`?8~BFw%^bUBX+>A_u8)K0lfN zJI|H%;~M@iz+^akPoU@ZUT-RA#tWnlP;aF8aLMCP5pXQ8*74Ie~JxYKDIxfg}UuaL--D*IJ^eKM+8XDNlvgO@W%?7A~#0Z%8F=M37SQasSM0UEnJx|%X}(;){03Oa*z*Up&B7;B^{q&u`4_X|I4sC{ zu2YvLb%C8wTjYw&UT0jZZ$XADUK-b$7-dhHwbMWn#Xv`j4-(us8s(6mM96tsA~&`Z z@+HRAHrijE2r_?wTWgnKn!s8xfVG^5!_PGQQ6X+)#5agfK7>K z+RJm-FnSj`99@(Go5@;iT?(m4WJzzGTw6+}=(2k8mJ{9ze8wpAmA&<@B(D-CJ=JD) zN~;+>FQZ&8$EY?L3s^G^sBl(;$#>dcwRdAJpTuIV@GoiS-#zH1RT~+^b=N5ckjay3BxVMz9t$$1Dx;dtI{T$P~VUFq1 zLT}gH)0<^;UL5*$vqQgrcIY?E4t?wF(6?Rej=^?k09RL^RsGUUa|u2YtEO4*yv~+N^PEs=nG-6lb3%o5a@$-{fhKOh*j?bpi$!mq9eT^`&|7DR-Z4A$ zc^5mw>Qpo}ll!;xa51&fUQBhiZ?^~EvKe&w=gs@24j<0v^2Lqntbd?)M>*d&cpK}R z%=EIsba}Fv=IfHZ>^43>?gfonJhqdg;ajFi?|@Ox11?NiM|#<4F_Qs|!-#-+Y@(md ztdPY;`QM5_)vi<6}>N>WEI0J~}ne{S5o z#U7G|PPu0H_Mkqg`7R1@~Iq*ubGT^-8neO3dPKk z>`CJNetIwDOJyfc1WK7XB8I$$PUWQRc< zCwf7uvcRa_z+y}o0X|jkJVwo^6$BJ_-Jx&ko%JcJ~1Z7k?B~Ws$Ym63L zq-5_1s>}ap3}$w^A|mdHkUJvbj%aX4G`b^V?ue*6BHqb&Ti~ThzF6|5S-ynjOVC-g zGFybwhv-1(RD_v<2;Tl~k0S3Y;Y6c8MQq&Y-W;R36O2w!}L^z6J zXqXr?ox?wU+?Z}*uC@*%RImnA5DOVLEwhOV*&quUOOcFWAf6%##6TiN@(GB+N{De4 zF{&cQkf)6i+?3_74g9DAu#C%DqL-Me3LY30jb`AcehwRV(4q=j%pa|Zqn)3}N_jER z(J0PXa1CqZr-(uZ;2E9TOjH~<8jy>YF-h7qI0yfZPoqLi;#sXWCN5>RV)g-K_A^Yx zNWme}ZMaU_o)U@b+Nci{uFmaaHGySBh3qm{wJ!+h2@@guvFidh=Lv4AqRNNiWq!Ns%0gwLjXgH5jM0vL6InCMGy~wMK z!>Es}`6+Ctrz4Kw(01b`DQsliv^efbT_CzI2%$;ML2L=5CIG6~X3hKviRm2L+oOnQ zNaVudHZqLaKQkK8R-c`A6Ivj8oG02_a;$J89wmue3zNNeSB;xZF_(r*4p4(anG#T@ zMX5f%nX#N8J0%*xk|dV=YUWN} zijunlWb+%ahjI z?~WsBS*MGW7hpY!(^}>(&jw#=xXp2y5AeFAmwwDss14e25X^a9jhqSP*Gn(yp1=0S z1KxVB6(#FywZ+849l?oK-fKs_04@^CD?`W@i1$^`Y`t>^OihPTa)Z7Qq}F?*8S}(# zG8^=`Ftg_Coj^|qoxjv)2nV#ys7(>9*G9(uudAHxNJ7{$;9)cAiFQ}h^iM5h*40ja z&Q=DJ+o_%jv#zx^(?J;*U3gwM;9(?Xc)eQ+b;W$c0QLAT6p~k7d2RcDedU!`;&H#? z180^wg{ew*>p+a?ZgbJ4*zG>ujp}hNKD)7*dce-x0UXjsacz9}3<@X{sBbN_vl3)B z@VNarUPI@*`4@Ad9e?~s?f6IS_($#dx@t$I5PwvY)M7iW8MUDocTryYBNLSJf5 z^sHyr1I06Kjfeg0y@r#K>B(r1VALu0^bdIIza~WsEKsnpmT*Oi&e(5M<|(v~y5E&Kj(Oqz zNC(RI{PdJI-re%s^DA(fcdxSK3Ukt~@>w_$4^ z)MmQg^h4_Qnos&0YNWrh8hu4OQ~}v*y-7>EgHDCLxwkTwP?C$gnVTs?5(J)iVn^M) z`JcCMhQByk2akJ%bI4yf({%{vkRzPN>o1%`zjNVS-vldX;d-KD%Q_Y$wk+tV&pDB{g6~@xc;2G|jU{O8-n;l$% z-_NF6nKf*USXYB6Ujt)xhOY(2I4_QvLDP)!v$~^Z6E^uyx%z6hnXTAScF>sA%I8BZ zx~a8;_Cz8gz*qdOu}Fw_8pFyC@ByctO*L_tX0sjF^C98rfLP-Xkn%UIV=^WrV{!vx zm%|$qaK!}OF?JatW_+OY{3XtQe~>ku z1kInI8I2*eguPkBqwH;-uuglPn>Lbq0!f)>5MkzHD8y$C+!9Ghs9hqSpcZpV)NBzh zfe6|wVK2c{Znkp?&{ApRtP7Ij6oyg;^jTgrBcL&Zme2#ZuxwZ$^!@Y}HZAcMfjJKd zh<&mn$f9cu6S`B01&*`#23)HHXoPJR^rxLdAg!29KW@Jz;EkJI0b14X(j<*2)9j53 zO)+BoGsbIg>U)DRYNrSd4`v`PClSE!xZh4!iVAG2G!-o-`Z-H_6MhQabj5#Zr55e|s(Jt7Kpxs)Br z;HiT!i?5M(d=y6%OBqoblo2IHqeWPZ7Uyt}z%m<53mLn^wW21M8(h1g6kQODCS<52 zXiN64RGfskRZ+(QpXsh)6;p9~DZxM-bwSZw+px;1xUDe4I9@>h(N+=|fSXKCC8dS- z!yz1}ouLY=G}SJwEawrFqgF(YT46D2Ex{IuLB_{ZRDct_mNbHeaRd{SQ4)Tx*)*n{ z6ce^qgJzjJ!-Q6vL*A&Po;x>tDbKwTr)0z7&0ZxlpHf$(;}k@ak=i?KouZ}^`;fdZ z{?;u(Yg6^GV`dVPn{f*<-xi9^Rgq@YFugNsm>Hwj)gJ%D(;ipW)gEnZP=7=dY(wZ@2u#R*huVOx>05b3di&|~*2Tf-4YwqOig=r`RFOAkVu z;A%%FFA`WOVVQWhq7Op;`XGS%pjHloPbybsGUtiP?BI-;9jwLddI-;)p5&CP@dDU* z+myx|%jj2m2aZ!`dd+>QLKIf+OYP61ekVo$-m3ywzTAmJ8vBSE# zeQ_CIe16rWxMu73Ve22r7xrc+G9^fk&Cnc)=;p{j2D~+>*YpTgtBY^0;a4E8EQ?P|Oc!N+rBd#M%DhnbR9O z--yc~)5FKGM5pW{|CDe@gb(ED{Qm%7iM5>o#P84{#g#;Z*fDwJNTz5z3#8d$Hq1s? zh8Z_!mlV|jyU7cF@`s4xkSDpRqtszPQE)6lQ8&8mlxqygbqy7w@A4RhF=b& z-5cdxqk4U@Zs@Je$0Csdal-4};vu`@pcmMR;hi(ifu^W!^3tY?$d z?NB3bW0BXc0GAZ#f&7UQch99L=|V({{dyeV5^%@(X1b$1;pQiE5TX45(D6vVId@pbb`<5TrnyKVz3y++tA&Jj^`bB z*(pIE;=es;jtXZ!;o9e3Y;zoV+*2Ou!mZC^rL#8Q_Ho_eG$!A$+o>irPua^;M2UE> zaPXuDA9}*s&TjR4uX+5$Lg|`c zC;z#2gLDbiy+~2Jq8!*he9qmL!kbUrMlg~e-X)qu+#SU|)G{SrG8zQv;wCYYo^L@u z^%m0w?g#xQUxt%}!hk8dR-lYh4BrG3VrD|CGgn+u*-l_zZNU;v#k) zPZ6=5JQm;PiJ18*F@d>6T6QLRZfs!=x|xzNF^Q$-InSn!vDN}>A;rpbg;T4Um2_&d z$a!7tyk1J>v~kulYl)Mp9RE{}xh5N)$RDuui0|RZ-T9 z$aQMum7)-a39>YCY-J|(V@r>i;H%*2*zGb*Be|zb1>!9;B}(% z8(HT}Fx-4ui#MtzI74e=<3(x8Zoo~`er>_YzUJQh_f+tkzoQD$(a%UyF6!3IFOkHH z>iCjfoQr#hB%nFL_3NBiT9Fff8}K>@hVdMVb`x@+`MNmVi_gFXKEyg$VU;oT|#EE1&<>a| zLUcMLZ0#LT&bF+BIP~m{GZAwglkPKdCX`1Q7}X~_HI`^kQaLEH4@Z>LfTpGVa)c_K zn^v+V{gTi!Zmp2>3Rau=ho&#SPB&XOUwoa;x2nrkFkBxsu8h>Wj=^*3gGWJqijSQk zE+4qJ){lm6$WX&B@!anm*)^l6h8M9)FlVG2ls9pJlyg-A11YM5Cb3&l9fP3-mh1qI zI)le_x1n(707qZH`@zv zm+G6X=2WcE+O}`D4m_T$DW~vWoC!0FJ}8yj=V+~Z9<5%_QU&Svt!K%no=1J^S(-^b zOFk%7<*<4^bJgovuFxxe>sj`xXU?ad<(bs8?1NIfJ#}AuU&&T|?W>SjUKzsQ*WSOE zIKKAk;z7Cc%FLvjSoc34Ow`PAVXs-0Ib|r`&2^I}oHRle@jjP7N7HFaWk{tLE7@2l%W^pzLYG2tCsKZSs1Yq z>(@``YP8zhJTbd;{q!zxL!7JDj+F=+RS3RA6z{xW@i662YSK7YLpmPumySQJCLOLU z9`S7evRQt(os;gZOQPOw{i#=?9;wu6AJLYYJR>@d%g4p7GAmMXzv3s!b zSt(aYA9c_6?9#p)pYOrd%0Giy`;?T*Kli(Cr8@q9vL4eQdT24>y}jynD}P?;x|J%l zO-}nJ=em{pim{c7@xESBv&U1yiMM8^?{}%W$~=^kiy3@?$A-ja;fX-Cd_Jfx75bI~ zo==F21^%5b7O2{kL~)=7#V3*Ckt09fegyuiQ+#U9%lOosm+^zx@*e``KV7AjC~FrrB^JY+w6rrT+18RsG-m%9-4Ka)=QNYZ&$&+93lygus0xd^%Qf{wDcs(62} z;z;FfCJz*7qG$az^8Ir*UjKzxyFObfbcFpLFH(DPr&Q$f!?i()R+te%g8zElefiGr07uM0^&xB_m*7{yESf z{|7aQ0`+;kh(U??0^XIQpmm0y{Og}@fBD#DA6FvhhZjHe@7o{x$t|B#P~VCUF$z=% zROs7iQz%fE;Nd_#+_*qJ%Gl+AtcZMA$5|OE=@IiHXY`1+$dI1*>hO>5e$V!M+CSDS zBY}q_4i6#pSNs=3pGk>0cz#w)@L%8?7S>;rX-G+*7ppx)zg=JDpvYz=5`td@Vf!&I zJ#_KlI0Szwf{^{+SYJfC1fO5(;oSVN&P|B< zh#sRI746cGigxKoMZ5H)qFwq?(JuYG7nWxamgHu9{ugBL-wI|^=*!}88->0i(!N^Z zm>CbXR5_4V?daOq+%)0&b!_5y;`-Ewv_^7RM4jy=*UlKlzRbTd&Xz$$6DzQ$Cm1{W zgu!5VXU!eodSbyxUwd2dGq--A>51bn>}S(a{(*vKX0W%1!v-MWhk7pXZws>)8=D#U zab;uq4}TRoc5By?7nlFznimCbtHf;~-0A2Rc(y_8g>W0g54bn;kFjt6>S^cu?Trk- z-`>jX^W&Ip_@9FKVe~dY2yA-dJTqQ8t$X({#@*9+X_mtOl*Q=dX(4D=C`<{@Vmock zxL$mie@*=hY#u?%bKJJ`jX;vVLh?g$s?&}A&QF?WCioXqMihq%f3F>J7p!l8YgIC_IpI;$P+tu@;>jTE-Ji`gSQnhG>(lz&E7@ke#xe z|Aa9>{`d6Fwy5X^1lE8Ccsp}o=__q<=d5P5e`x0t#Sfzsnv#F3 zo}zE25=fhuR+nD zi9tj%wDTj~jy7;~T^l^k9$+zY+LBsAxUwDO-#&t8`lR@X_&|DMG$Y={2d7vrT`KR( zAJ5qOt&}P6Sj|*%SfF#*T#@_uR>)=B&^b^SC+zNK-okmAn`HdgE@Y|mq|3Yh@=oyP- z&q&Iyb|pL)I}}*JU|^HuBd`+abbf+8eD2&y_GdSKi<3G{bS{;27Rw&SpG&ZZ&7&T+ zh&}kVk9_%=jy~fNr>D)Mo_48|rgbai*;0pRPzWEM@d7N91z4&YG|MF_w`aJbSm}qm zLgFr$h3By=W$Xg+Eklb_T*Z#eJNA{2+|>;Yc!cd^&56l>Zav3JA&*)EVV&3#a~&q>+MA2|XY6s(6+4Jvz!gKDiAeL=-xl zK?jOZzLK|D@7m#0% zg1&|X{R3RkHv_BF#bW-%Zoyj7Hj@Qg+EB_S3k483?z;{@Ldd}4GMqMiYk8&TX4ea;AyW&5cxP#V&H}YCkV)c= zbMLJI8WFfyZD4)IO>E<7F(4!w?p*Z3U*7ZZ9WQ+62_Zon{Uiu=vNU~Ag6_4Rj67s6 zE8OwmI$MG^vA!?;{k|WNAV9mW`{Ga4cIE3Bn?Vi8E`sfQITO8M9bfTpXG5pa-g!lK z6#z2%C~+j(Bokc5+2kT3}6+YTDGij^j!M@*n$Cw zkf{%ag9g+ZeoUwVY2;;K8C`|L$xj&07?;3Y@^N$mC(DVM^v|zGIlBd@$R-`jmIujU zmZpOzNx?e4vO_1OVWnz5L(_cfS9EE(XHx6pd}`F$s<0Ed6jVeBr|=}t!YU}jbPhky zt;G=Nvae77vb+5ymQuHqO!4_Zg?aQV1qnAk^s$8FO@R|X3MF2 zt`dCK_?g(BWVkr-znCz_Vg3?;`Abk-(PgHbleA!nqi?c3F^SL_bjuE^pvnSDAVm|H zs5mVg789BVJ~?qFG!PTx>jk(nLca;|+bDjU#BZ}$S8%T9Uc|dwD=wEW5;==06L*HO z+9DB12^q_sNs^cz;j;msF?`1HnZRcwKAZ5_j?ZR%w&1h1M3uH>@KK)Z@`FORRD^zOhD#m?Cu$Ew6+`W5j!%wHn@x zNwL~xgILL!$0v0YBPDA?RL_8Xt~HhCLg=T-YAaoVtmNG*MWoL!-`<+}E?{KPkGS(} zpgd!k=LZlfj@v7^@{&l#P*Kyd(st%5?PGXro-ay6a@32`kaUKr0PZ>jU8wz3v4Aqr znM5$0r0IU6(xkFSR7Ma@O6m|NfLj<&;lkb0jCuIAOBO$T_WO^QulVXumI(XwYH6Qt zQKxIyIH+J=b$f6L>RJuzvf6#}(-9UsjC*PyLyUW-507P5Sg85TQxH*54RHj~bG z)`*2BmqVex)=dl3n$pJJ=(`+E>&)U35M>QRSs&i*GrCICm4<3lGh~GT;!H9U`48X) zZ~Pt~yU5h21gcQ6xA}zRr+h(`wdaPU(5M)Si?vjV#RdZgJNq=ZC)N7f4E8ht0O;4` zl=J!Afoy@_kt6v^cj<_Gaxy332fwLqn@M6w#7obZxK8S%Jyn-CONk$T9T{G@qBn|S zMg|=_P&Cx#I&7HtkFbD?(2!)IQdm(1FlqxjFbydUo~sRll6=K3-{mQ4V-@_Eb2o>} zf_3961!?jSYE}!N45Y%oaTULFbqj}F z2NB8p0*CJu`&rYtIg7jJYvKZ#Md-dp5e!qX zNdy}x*o@DX-fiNbR;x|=YMXQ$fwtF0sKX|-8VSvt38qE+8UdGf<@+6co@RA!?G(MN zTlBK|*vq=rUS{9bINjK4aLBW7fVrXUT&|lOy_Yy@mojdW7wI`&rk4DCfceSK;7sHP z8{V`+c>M*i3-s?a69GOm`QI{NLE!sLm5->94_^*O9S-sxBfjRe5CZC9E#(5Vt(_5M K@Bam{#YheK&7(^I literal 0 HcmV?d00001 diff --git a/include/SugarCharts/swf/stackedGroupByChart.swf b/include/SugarCharts/swf/stackedGroupByChart.swf new file mode 100644 index 0000000000000000000000000000000000000000..956ad41c4fad537b0b65f23641ad84931285f122 GIT binary patch literal 12211 zcmV;kFHF!wS5pTap#T7Qob7!HbX-T3Xua;&-A`)mvMetx$FbvmOYCeA*^=$VEhl!% zNX`ZcN?U44?X=WNcgwQEgct~klYl1+)?mougy0|Y$pTIwWM*)N2@r>Tn1Pu;ne*YF z0RQ|MmKpN@pKxGU^zTyjUcIHYn1o@@jC}n1)vbGPZMSaSx>c|0pa}n?5RHe0m=_Y; zLz9z}ZPvL$2t#xj_g)OYb+>)yo(JkqUld%tw?_Z}GD zC?+fFAUXtew@0G}{D^i4x7Ab;uaFqX<;V8sM?{--K0v~vBXU1-Z+L2OllWWWeexQ` zTZp>q#q)vp^Dlq$w_jYiAa~unUl%e3Q>74ADb!O6CZ*7o9T+TeG8+IK5!Zn}z8m5GbyC%*8h!iY>Es#1uk6dEXnsFOl>wl5<~5)->#H>e~}eteU7 z(_fON#T8Ub9}hkIvjx4Mz4BaD5=*5MQ|Z)EIu@m~E7LCvvJs#aq6gE!f;`jL@ZwWL z0R?Hg!B{)C0!nhzy{}BjG%8gZ74F)qwA0|CRMi4FE=(i3wUABcs3mW$xBz~uM9*vc zPo>`!Pi~Bh?+TC)Di-{$6s7ElXdPLc&SeLNH!sNnwsD^~v!u9ZW zI45clyQg%pB+{d$e0TQdj41XN^0}NC%NP2tE~H0@ohS`viy}XK*>EXS*ilFiWe~hA z-FsutP_O72%wYA4Qs!W(gI{~bvVEmNf?Q2+JqN`^2r4l#VG7HL7@bZi6cJh|j3M|n ztw<|EqX~S*J{iHny_=X=gjj(D5UNZ~L`19-Vw0UtY+S}xQS4GrY_*K7rq~$Pa%X2u zoQlqc*X0IO@98!7C2u)B`X_e%=>4Wzl=Au9-Ym*y8YI4ksV_#jaqB<6!yZV1$Q#ny?qaG;f&n>vLX}?`y%1DmO^z$FjpeJ2wgene3n2DVY7<04mM8pzFj_;uOvjvu&;{mvoLs$=x z&!xvg;(RetV9bN{bSRZsjQUg*u4vpqY*<5xwq|T9}>^nDd>Yvy(pxI2Qs_T`!czrEK|c7mFY!@Z=^CE z#WGz4Jy5Bc8I%oCHWCh%WGgqkuDlIdIztPYGA`o6jJPl(Hl|Z64OAL?85#1yD0Bjfr4eZh6ft#Lx`FnlCDLLFWso{1G54V#Q6QHW+Qf+L7Fo>#M z8K|5fa9J)hgxYiKM3bYdL@qOs8Sd-ZR~m-K1aPqgra)IS|KzA3$J8|gfIgl-8_knuXB1G060ES10wjp^&=F!P5aP5HM zH%CLTlsW3$-lvgrVnZnkgj3uQwy@5WFp{#{If<*-BTn{<-7qT|{o$PPY%-F4iW&9>wgzUlKIs2ukdw!3M32p(GkBMXwdWkG-{9%xTS`az&sH zJx?>`#70;;qp1m)C+=i};~ijd%$gkKm#va&A%|ELBTEJZ8Fyss+Y(!uVELm!mBzK2 zK{XnvmO*u?Ru*hb=zRu_?7u5d0981GB$H{8LuTMp_@1EzPFm1@+IB`&Hwyx`6o2P^FD_ik(hcb4X7#fu4Y7-66Qt*bMI!XC^J5FtENsd;AzCdxy^r zy;F86uW*+#LnGWJ0(+y>?WsCyJ}J+nLTT>8Dd0SclT`D&sNhYcz|d#KnYc=DRRX-uQI0y{f-Zb6OuBMs zbHYTEn7WH1+2U%nsIU@N3&awWMafy#+F2>0SUg+0vzcy5l9e0%EKO<#-8reLII{J$ zjF~Jaq!lS@k5->du5@v0H)z%}UyV>v}n%nF)#PSR0%kK0Cs5Q~Er&9N~FWHh6#tZA{H5Lz~W+@6`DX zpgey@8M=V5E}RYHi&8V-c=3$VeFtFCMDK^76%K!1GXDXj$f*OK??q)phU8Sx`;4V#8XM-;u(V!W zkz!-7a@I+OSIO-O$$ ziXdCrWfFUe1eUQrkFc%eakrXq7SkA9mM8EVN`tk3aPRmCC@Lt~K`}1I#GokPG$NBO zh<%xX>~OM>?#n`|J3#MIL^ozz41w<2OHK&<0j3l`ls+hivcuxYQusM2!lHV$h)EHM z$QCmo1{z&lWq_q;#@P51o5{FC%kU0ERN>-|83~GtH)~XeD=Ms0xuZflRmc@psZ+V5 zDk!RoqD&)Rg{vWP)2K>9oJDbAS6oQOnG{#)imQ-uQCul8qm)LKZTqtIX?9_pIYpdR zJ}wqUKxFflBTcHKLY1r*235QGJ6wn{jaVHS-(Gsin9=-uMQGzznU(Ai8d68D=mZ4GPWF9 z>C(qxVXhWo(4^1@NtJFCA=ITC#Ue^Q9K#WyiVKOGKB|(G=j4_n^FWW4NF^5`qG7dB zPd)>2cUX5!Dbd#fF)twE1yp+hm0m!N7ZCRXD!c&DAW*&VQmbAp^-`x^qUt3~(*yEw zoAq+gwA&!e6`lqwOqqOq2K7lY?j<8B6tk4PLRHrpgud38~Rkf`Y9Ki#lticRj z-if$X4q1gp77r$CM6x62kdd-WGY3KRo`;?JIne^gjYK#rHDrbIc%TIPyd&hDNS$?{Yn zWhPx-`kRj|0OnT5Ena>Uj6J&Nn9e>-tq z?MZTmBD<=b$gY}3WLHfiva6;M*;Uhs?5gQSc9lzH*UnI6SN)D6d*n`g&R8Rw!P3J$ zl_FB0$(f1Ezu|rPQYk+q;{7;xYQ*Puo-56<-#3c7(qN{P7EQDna96&U=FOr3bi5s? zXIwEi$J-`j>D`K{8l;wU^9Zz9VvDz@9OBF@vfcQj+8p>wRn;17q{*z87 zh*z!6zs`QEhc_tDyFxtGZ*@r;bLMTGoN0#0*+(2pZ@NwMIJZ-bhYmAj`v#!C{eA+L zH4V8!A)8iJFg`gf$O1+D8imh4R=f;VBq&P(b0r_#B~blP4_8t>Farz^%5X@A-zURi z89pMzrVKwK!x0&NRzUTCTliZjVz*EjTj*&UB^uC(gz^y^B^-bfL6mF&O4Kb1J8YDQ zjS_aFEDgx6gAzp)l#=j%7@`h;&HC?RbT|vfeleY6XWi&XA37-qM~C(er?a`D7%Aj? zGsPlpJaFa==)Q9~53fbYcHE)>Z{sp*C_5}c(v3RID;%`&F)sQt{przMX;*eQQ$!GL zMa37|5>T|?cBhN<8365oa0R-_bBaMIMyW_{R=KT9embCeIbF;0_PR?iz|tc{N_PyV zKlw3A*LDgI$@Dna5Iu~)`VtMi%RLoXKV4V|dZVIi+ctu>YdG69+9yFPMDhy=-tj=SxF_A$hr2TK0zd}a6a}=8{jOuGJtHSS=hEWReoUs-Ru(05lYvROS)7__YM+;y}szI60*cY_S|{3!BXH!#_3~_ zY&wSv61ek-n@Da9ciw4dH06f2NIP4*XS`T}E1C{#Z5NO8Ezd~42zfb>v8~qO%s|=& zxH(hE+X1qc*;tllGMdcL&ZTTG=r#I~Wgjk5qzkBPI1Lg;_i_#DAy84ctThU3_zjEd zUFcGqFV$u%*Q)9uJa^&SR_jP)+mVrBA6wm6bYkNfJ4dcIR{)5Yb1Yf()fp*F{wc^W>g;z~Aj`3KbbUmof3>E*_H%uc=l*;yy{|~g zZKIZ=+O^*(At$0|yhv@wGZyIUXk}@7A0@aSlp?7qtyOV|z*Zd?$Z$LLr~9a7@pqRj zGQM}&1uJCxXc)5Jm|girEL^7R6I%-fXr}S42eVY=1uP(Bxpy=Nota01@!i>Bc%-2( zcb76Fa`7|gBtZ?fd%GBCp~$+v$Z)kWrDHe0+8`&=3hHRAgKGFA5)8;)2f2J2QK)w1 zZUxG~h$Pk2H4OdfflP64eoq0n0ZR42HLpUuWYAv9bUy8ni<&eHkcN;O9^`&FcpFrm zf^x(2&_afqoQF={o~I0sac!Ie3KCmL2!D^%QzuRq(j$Xl-GuiWy{2a}Cur`cLyWFw z*EXQgW_LIYVGG?nFoVPm5D^i3S>Wa(hDL!!jGz+;b?sI|Z%vYx`EbXGib+aJ%jP!= zN&?Xi*$B_4p2V3tZgGX_cpUS?&WtMgaiZErOTg+NU`-IPHV9Z31g!S}F|+u|Dtkv7 zWNf2~Wmrhx*q4kGY7?Q(mHwPYSs+!pyq^nWnmsHDIM17o>r2h~GIpL$vOogo>%eB2 z2}6b8xiIC2B~qTuY8dlfp?P))t#VIeS^r)eYpQw@0rh0eqMlgBTU;C12X?XVpqV2V zxg#-dnQ-;mvpl_c@n&=i>=jNqy^SYanG&u{30I+oM_!LKx@Jd0ME4t8W8BGGK!VRs zajuu}UYe!;t@*r@a#>1hhUHvDSr1j6{&gwzKavzJL-dpvBSP+k2(cl5#)Tw!D--At zaK5kgl9@ziQmRDuGx<5EzXT!R<7D0B4RI^j#YuXpQOHc9Kge2z(to?K^KFJ_!?jap z9-Tk`@hIntQ0|I3u1Uj6GC?5dP9{{WU*L zML*$nZ~5x6s(0Izkj z-q!O5+CCbS2(lridR>)zNmk2lx>m-W%eCDgSc2CQ2s3|vGKj{vD8HP<4_;c%V;BX<*n z=#&h0r<~Opt|h37&8WH2UbO(hj6zXTN)vac6*^Su5&Z|Rxo2#m&N%gK& z&_a=K;m4;?Plue6u=IAN*u0IIQ74z30a%dHZnMG{qgS`(t1Z)8-BxozB-yc^2V_F!Y&nuU(!N*UX5K`aE8cCL20U|9_Fbsmlb) zie8D1iAtZ#WfD4L;B*GA>MjK?--0DE>)Z#Y|EY%h;pH*wxiGT)0qTbLdd zy4cOraOT*;@rNOH5r?t#!?E{Hh&lU>^n8yTHB4*EUq@5cezMfHBcW9s7RUCypIE1{1Mbo}Rg2 zZ|VHcXSB(=C~I^m(@nO!V-eSS!3CI3m?~`^1TJbkY=F;_j0&>0lryBl(F1Jbmdu#j z?uAAlrO|1v91-j}nC#RYyLhVK?27a`y52%C0 z9c1Y)X^1|5^s4ZW_+|?Su#RoFixUMV)0oo%RSs>>1F1*l-H=w~L3rUdBWO~!prf&6 z#>PnS?g+@sO>c2tZgS=2rr^AI>+M3#d%wl>=44zuu})KU<8p_prs^tfRp&`y92
 
+ {foreach from=$emailAddresses item=address} + + + + {foreachelse} + + + + {/foreach} +
+ {if $address.key === 'opt_out' || $address.key === 'invalid' || $address.key === 'opt_out_invalid'} + + {elseif $address.key === 'primary'} + + {elseif $address.key === 'reply_to' && $item.key != 0} + + {/if} + + {$address.address} + + {if $address.key === 'primary'} +  ({$app_strings.LBL_EMAIL_PRIMARY})‎ + {elseif $address.key === 'reply_to'} +  ({$app_strings.LBL_EMAIL_REPLY_TO})‎ + {elseif $address.key === 'opt_out'} +  ({$app_strings.LBL_EMAIL_OPT_OUT})‎ + {elseif $address.key === 'invalid'} +  ({$app_strings.LBL_EMAIL_INVALID})‎ + {elseif $address.key === 'opt_out_invalid'} +  ({$app_strings.LBL_EMAIL_OPT_OUT_AND_INVALID})‎ + {/if} +
+ {$app_strings.LBL_NONE} +
diff --git a/include/SugarEmailAddress/templates/forDuplicatesView.tpl b/include/SugarEmailAddress/templates/forDuplicatesView.tpl new file mode 100644 index 00000000..2403b9b1 --- /dev/null +++ b/include/SugarEmailAddress/templates/forDuplicatesView.tpl @@ -0,0 +1,63 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} + + +{counter assign="count" start=-1 print=false} +{foreach from=$emails item=email} + +{/foreach} +{counter assign="count" start=-1 print=false} +{foreach from=$verified item=email} + +{/foreach} +{if isset($primary)} + +{/if} +{foreach from=$optOut item=email} + +{/foreach} +{foreach from=$invalid item=email} + +{/foreach} +{foreach from=$replyTo item=email} + +{/foreach} +{foreach from=$delete item=email} + +{/foreach} + diff --git a/include/SugarEmailAddress/templates/forEditView.tpl b/include/SugarEmailAddress/templates/forEditView.tpl new file mode 100644 index 00000000..5e6e13c3 --- /dev/null +++ b/include/SugarEmailAddress/templates/forEditView.tpl @@ -0,0 +1,123 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} +{php} +global $emailInstances; +if (empty($emailInstances)) + $emailInstances = array(); +if (!isset($emailInstances[$this->_tpl_vars['module']])) + $emailInstances[$this->_tpl_vars['module']] = 0; +$this->_tpl_vars['index'] = $emailInstances[$this->_tpl_vars['module']]; +$emailInstances['module']++; +{/php} + + + + + + + +
+ + + + + + + {if $useReplyTo == true} + + {/if} + {if $useOptOut == true} + + {/if} + {if $useInvalid == true} + + {/if} + +
+ + + + + + +   + + {$app_strings.LBL_EMAIL_PRIMARY} + + {$app_strings.LBL_EMAIL_REPLY_TO} + + {$app_strings.LBL_EMAIL_OPT_OUT} + + {$app_strings.LBL_EMAIL_INVALID} +
+
+ + diff --git a/include/SugarEmailAddress/templates/forWideFormBodyView.tpl b/include/SugarEmailAddress/templates/forWideFormBodyView.tpl new file mode 100644 index 00000000..ea78aeb6 --- /dev/null +++ b/include/SugarEmailAddress/templates/forWideFormBodyView.tpl @@ -0,0 +1,105 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} + + {$app_strings.LBL_EMAIL_ADDRESSES}: + + + + + + + + + + +
+ + + + + + + {if $useReplyTo == true} + + {/if} + {if $useOptOut == true} + + {/if} + {if $useInvalid == true} + + {/if} + +
+ + + + + +   + + {$app_strings.LBL_EMAIL_PRIMARY} + + {$app_strings.LBL_EMAIL_REPLY_TO} + + {$app_strings.LBL_EMAIL_OPT_OUT} + + {$app_strings.LBL_EMAIL_INVALID} +
+
+ + + + + \ No newline at end of file diff --git a/include/SugarFields/Fields/Address/DetailView.tpl b/include/SugarFields/Fields/Address/DetailView.tpl new file mode 100644 index 00000000..7b93cf46 --- /dev/null +++ b/include/SugarFields/Fields/Address/DetailView.tpl @@ -0,0 +1,58 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} + + + + + +
+ + + + +{$fields.{{$displayParams.key}}_address_street.value|escape:'htmlentitydecode'|escape:'html'|url2html|nl2br}
+{$fields.{{$displayParams.key}}_address_city.value|escape:'htmlentitydecode'|escape:'html'|url2html|nl2br} {$fields.{{$displayParams.key}}_address_state.value|escape:'htmlentitydecode'|strip_tags|url2html|nl2br}  {$fields.{{$displayParams.key}}_address_postalcode.value|escape:'htmlentitydecode'|strip_tags|url2html|nl2br}
+{$fields.{{$displayParams.key}}_address_country.value|escape:'htmlentitydecode'|escape:'html'|url2html|nl2br} +
+{{* +This is custom code that you may set to show on the second column of the address +table. An example would be the "Copy" button present from the Accounts detailview. +See modules/Accounts/views/view.detail.php to see the value being set +*}} +{$custom_code_{{$displayParams.key}}} +
\ No newline at end of file diff --git a/include/SugarFields/Fields/Address/EditView.tpl b/include/SugarFields/Fields/Address/EditView.tpl new file mode 100644 index 00000000..9f1d2469 --- /dev/null +++ b/include/SugarFields/Fields/Address/EditView.tpl @@ -0,0 +1,138 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} + +{{assign var="key" value=$displayParams.key|upper}} +{{assign var="street" value=$displayParams.key|cat:'_address_street'}} +{{assign var="city" value=$displayParams.key|cat:'_address_city'}} +{{assign var="state" value=$displayParams.key|cat:'_address_state'}} +{{assign var="country" value=$displayParams.key|cat:'_address_country'}} +{{assign var="postalcode" value=$displayParams.key|cat:'_address_postalcode'}} +
+{sugar_translate label='LBL_{{$key}}_ADDRESS' module='{{$module}}'} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +{{if $displayParams.copy}} + + + + +{{else}} + + + +{{/if}} +
+{sugar_translate label='LBL_STREET' module='{{$module}}'}: +{if $fields.{{$street}}.required || {{if $street|lower|in_array:$displayParams.required}}true{{else}}false{{/if}}} +{$APP.LBL_REQUIRED_SYMBOL} +{/if} + +{{if $displayParams.maxlength}} + +{{else}} + +{{/if}} +
+{sugar_translate label='LBL_CITY' module='{{$module}}'}: +{if $fields.{{$city}}.required || {{if $city|lower|in_array:$displayParams.required}}true{{else}}false{{/if}}} +{$APP.LBL_REQUIRED_SYMBOL} +{/if} + + +
+{sugar_translate label='LBL_STATE' module='{{$module}}'}: +{if $fields.{{$state}}.required || {{if $state|lower|in_array:$displayParams.required}}true{{else}}false{{/if}}} +{$APP.LBL_REQUIRED_SYMBOL} +{/if} + + +
+ +{sugar_translate label='LBL_POSTAL_CODE' module='{{$module}}'}: +{if $fields.{{$postalcode}}.required || {{if $postalcode|lower|in_array:$displayParams.required}}true{{else}}false{{/if}}} +{$APP.LBL_REQUIRED_SYMBOL} +{/if} + + +
+ +{sugar_translate label='LBL_COUNTRY' module='{{$module}}'}: +{if $fields.{{$country}}.required || {{if $country|lower|in_array:$displayParams.required}}true{{else}}false{{/if}}} +{$APP.LBL_REQUIRED_SYMBOL} +{/if} + + +
+{sugar_translate label='LBL_COPY_ADDRESS_FROM_LEFT' module=''}: + + +
 
+
+ \ No newline at end of file diff --git a/include/SugarFields/Fields/Address/SugarFieldAddress.js b/include/SugarFields/Fields/Address/SugarFieldAddress.js new file mode 100644 index 00000000..af830cec --- /dev/null +++ b/include/SugarFields/Fields/Address/SugarFieldAddress.js @@ -0,0 +1,41 @@ +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ +var elems=new Array("address_street","address_city","address_state","address_postalcode","address_country");var tHasText=false;var originalBgColor='#FFFFFF';var Dom=YAHOO.util.Dom;function TestCheckboxReady(id){YAHOO.util.Event.onAvailable(id,this.handleOnAvailable,this);} +TestCheckboxReady.prototype.handleOnAvailable=function(me){for(x in elems){f=fromKey+"_"+elems[x];t=toKey+"_"+elems[x];e1=document.getElementById(t);e2=document.getElementById(f);if(e1!=null&&typeof e1!="undefined"&&e2!=null&&typeof e2!="undefined"){if(!tHasText&&trim(e1.value)!=""){tHasText=true;} +if(e1.value!=e2.value){document.getElementById(this.id).checked=false;break;} +originalBgColor=e1.style.backgroundColor;}} +if(!tHasText){document.getElementById(this.id).checked=false;}else{syncFields(fromKey,toKey);}} +function writeToSyncField(e){fromEl=YAHOO.util.Event.getTarget(e,true);if(typeof fromEl!="undefined"){toEl=document.getElementById(fromEl.id.replace(fromKey,toKey));toEl.value=fromEl.value;}} +function syncFields(fromKey,toKey){for(x in elems){f=fromKey+"_"+elems[x];e2=document.getElementById(f);t=toKey+"_"+elems[x];e1=document.getElementById(t);if(e1!=null&&typeof e1!="undefined"&&e2!=null&&typeof e2!="undefined"){if(!document.getElementById(toKey+'_checkbox').checked){Dom.setStyle(e1,'backgroundColor',originalBgColor);e1.removeAttribute('readOnly');YAHOO.util.Event.removeListener(e2,'keyup');}else{e1.value=e2.value;Dom.setStyle(e1,'backgroundColor','#DCDCDC');e1.setAttribute('readOnly',true);YAHOO.util.Event.addListener(e2,'keyup',writeToSyncField);}}}} \ No newline at end of file diff --git a/include/SugarFields/Fields/Address/SugarFieldAddress.php b/include/SugarFields/Fields/Address/SugarFieldAddress.php new file mode 100644 index 00000000..0b561059 --- /dev/null +++ b/include/SugarFields/Fields/Address/SugarFieldAddress.php @@ -0,0 +1,105 @@ + 'primary_address_street', + * 'type' => 'address', + * 'displayParams'=>array('key'=>'primary'), + * ), + * + * Where name is set to the field for ACL verification, type is set to 'address' + * to override the default field type and the displayParams array includes the key + * for the address field. Assumptions are made that the vardefs.php contains address + * elements with the corresponding names. There is the optional displayParam index + * 'copy' that accepts as value the key of the other address fields. In our + * example we may enable copying from the primary address fields with: + * + * array ( + * 'name' => 'altaddress_street', + * 'type' => 'address', + * 'displayParams'=>array('key'=>'alt', 'copy'=>'primary'), + * ), + * + */ +require_once('include/SugarFields/Fields/Base/SugarFieldBase.php'); +class SugarFieldAddress extends SugarFieldBase { + + function getDetailViewSmarty($parentFieldArray, $vardef, $displayParams, $tabindex) { + $this->setup($parentFieldArray, $vardef, $displayParams, $tabindex); + global $app_strings; + if(!isset($displayParams['key'])) { + $GLOBALS['log']->debug($app_strings['ERR_ADDRESS_KEY_NOT_SPECIFIED']); + $this->ss->trigger_error($app_strings['ERR_ADDRESS_KEY_NOT_SPECIFIED']); + return; + } + + //Allow for overrides. You can specify a Smarty template file location in the language file. + if(isset($app_strings['SMARTY_ADDRESS_DETAILVIEW'])) { + $tplCode = $app_strings['SMARTY_ADDRESS_DETAILVIEW']; + return $this->fetch($tplCode); + } + + return $this->fetch($this->findTemplate('DetailView')); + } + + function getEditViewSmarty($parentFieldArray, $vardef, $displayParams, $tabindex) { + $this->setup($parentFieldArray, $vardef, $displayParams, $tabindex); + global $app_strings; + if(!isset($displayParams['key'])) { + $GLOBALS['log']->debug($app_strings['ERR_ADDRESS_KEY_NOT_SPECIFIED']); + $this->ss->trigger_error($app_strings['ERR_ADDRESS_KEY_NOT_SPECIFIED']); + return; + } + + //Allow for overrides. You can specify a Smarty template file location in the language file. + if(isset($app_strings['SMARTY_ADDRESS_EDITVIEW'])) { + $tplCode = $app_strings['SMARTY_ADDRESS_EDITVIEW']; + return $this->fetch($tplCode); + } + + return $this->fetch($this->findTemplate('EditView')); + } + +} +?> diff --git a/include/SugarFields/Fields/Address/en_us.DetailView.tpl b/include/SugarFields/Fields/Address/en_us.DetailView.tpl new file mode 100644 index 00000000..a1b5fdac --- /dev/null +++ b/include/SugarFields/Fields/Address/en_us.DetailView.tpl @@ -0,0 +1,63 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} + + + +{{if !empty($displayParams.enableConnectors)}} + +{{/if}} + + +
+ + + + +{$fields.{{$displayParams.key}}_address_street.value|escape:'htmlentitydecode'|escape:'html'|url2html|nl2br}
+{$fields.{{$displayParams.key}}_address_city.value|escape:'htmlentitydecode'|escape:'html'|url2html|nl2br} {$fields.{{$displayParams.key}}_address_state.value|escape:'htmlentitydecode'|strip_tags|url2html|nl2br}  {$fields.{{$displayParams.key}}_address_postalcode.value|escape:'htmlentitydecode'|strip_tags|url2html|nl2br}
+{$fields.{{$displayParams.key}}_address_country.value|escape:'htmlentitydecode'|escape:'html'|url2html|nl2br} +
+{{sugarvar_connector view='DetailView'}} + +{{* +This is custom code that you may set to show on the second column of the address +table. An example would be the "Copy" button present from the Accounts detailview. +See modules/Accounts/views/view.detail.php to see the value being set +*}} +{$custom_code_{{$displayParams.key}}} +
\ No newline at end of file diff --git a/include/SugarFields/Fields/Address/en_us.EditView.tpl b/include/SugarFields/Fields/Address/en_us.EditView.tpl new file mode 100644 index 00000000..9f1d2469 --- /dev/null +++ b/include/SugarFields/Fields/Address/en_us.EditView.tpl @@ -0,0 +1,138 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} + +{{assign var="key" value=$displayParams.key|upper}} +{{assign var="street" value=$displayParams.key|cat:'_address_street'}} +{{assign var="city" value=$displayParams.key|cat:'_address_city'}} +{{assign var="state" value=$displayParams.key|cat:'_address_state'}} +{{assign var="country" value=$displayParams.key|cat:'_address_country'}} +{{assign var="postalcode" value=$displayParams.key|cat:'_address_postalcode'}} +
+{sugar_translate label='LBL_{{$key}}_ADDRESS' module='{{$module}}'} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +{{if $displayParams.copy}} + + + + +{{else}} + + + +{{/if}} +
+{sugar_translate label='LBL_STREET' module='{{$module}}'}: +{if $fields.{{$street}}.required || {{if $street|lower|in_array:$displayParams.required}}true{{else}}false{{/if}}} +{$APP.LBL_REQUIRED_SYMBOL} +{/if} + +{{if $displayParams.maxlength}} + +{{else}} + +{{/if}} +
+{sugar_translate label='LBL_CITY' module='{{$module}}'}: +{if $fields.{{$city}}.required || {{if $city|lower|in_array:$displayParams.required}}true{{else}}false{{/if}}} +{$APP.LBL_REQUIRED_SYMBOL} +{/if} + + +
+{sugar_translate label='LBL_STATE' module='{{$module}}'}: +{if $fields.{{$state}}.required || {{if $state|lower|in_array:$displayParams.required}}true{{else}}false{{/if}}} +{$APP.LBL_REQUIRED_SYMBOL} +{/if} + + +
+ +{sugar_translate label='LBL_POSTAL_CODE' module='{{$module}}'}: +{if $fields.{{$postalcode}}.required || {{if $postalcode|lower|in_array:$displayParams.required}}true{{else}}false{{/if}}} +{$APP.LBL_REQUIRED_SYMBOL} +{/if} + + +
+ +{sugar_translate label='LBL_COUNTRY' module='{{$module}}'}: +{if $fields.{{$country}}.required || {{if $country|lower|in_array:$displayParams.required}}true{{else}}false{{/if}}} +{$APP.LBL_REQUIRED_SYMBOL} +{/if} + + +
+{sugar_translate label='LBL_COPY_ADDRESS_FROM_LEFT' module=''}: + + +
 
+
+ \ No newline at end of file diff --git a/include/SugarFields/Fields/Assigned_user_name/EditViewFunction.tpl b/include/SugarFields/Fields/Assigned_user_name/EditViewFunction.tpl new file mode 100644 index 00000000..909fc108 --- /dev/null +++ b/include/SugarFields/Fields/Assigned_user_name/EditViewFunction.tpl @@ -0,0 +1,38 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} +{{include file="/include/SugarFields/Fields/Multienum/EditViewFunction.tpl"}} diff --git a/include/SugarFields/Fields/Assigned_user_name/SearchView.tpl b/include/SugarFields/Fields/Assigned_user_name/SearchView.tpl new file mode 100644 index 00000000..1b80a3bc --- /dev/null +++ b/include/SugarFields/Fields/Assigned_user_name/SearchView.tpl @@ -0,0 +1,40 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} +{{capture name=display_size assign=size}}{{$displayParams.size|default:6}}{{/capture}} +{php}$this->_tpl_vars['user_options'] = get_user_array(false);{/php} +{html_options name='{{$vardef.name}}[]' options=$user_options size="{{$size}}" style="width: 150px" {{if $size > 1}}multiple="1"{{/if}} selected={{sugarvar key='value' string=true}}} diff --git a/include/SugarFields/Fields/Assigned_user_name/SugarFieldAssigned_user_name.php b/include/SugarFields/Fields/Assigned_user_name/SugarFieldAssigned_user_name.php new file mode 100644 index 00000000..353d2afc --- /dev/null +++ b/include/SugarFields/Fields/Assigned_user_name/SugarFieldAssigned_user_name.php @@ -0,0 +1,51 @@ +setup($parentFieldArray, $vardef, $displayParams, $tabindex); + return $this->fetch($this->findTemplate('EditViewFunction')); + }else{ + $this->setup($parentFieldArray, $vardef, $displayParams, $tabindex); + return $this->fetch($this->findTemplate('SearchView')); + } + } +} diff --git a/include/SugarFields/Fields/Base/DetailView.tpl b/include/SugarFields/Fields/Base/DetailView.tpl new file mode 100644 index 00000000..776d5ebb --- /dev/null +++ b/include/SugarFields/Fields/Base/DetailView.tpl @@ -0,0 +1,48 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} +{if strlen({{sugarvar key='value' string=true}}) <= 0} +{assign var="value" value={{sugarvar key='default_value' string=true}} } +{else} +{assign var="value" value={{sugarvar key='value' string=true}} } +{/if} +{{sugarvar key='value'}} +{{if !empty($displayParams.enableConnectors)}} +{if !empty($value)} +{{sugarvar_connector view='DetailView'}} +{/if} +{{/if}} \ No newline at end of file diff --git a/include/SugarFields/Fields/Base/DetailViewFunction.tpl b/include/SugarFields/Fields/Base/DetailViewFunction.tpl new file mode 100644 index 00000000..a57857c9 --- /dev/null +++ b/include/SugarFields/Fields/Base/DetailViewFunction.tpl @@ -0,0 +1,41 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} +{{sugarvar key='value'}} +{{if !empty($displayParams.enableConnectors)}} +{{sugarvar_connector view='DetailView'}} +{{/if}} \ No newline at end of file diff --git a/include/SugarFields/Fields/Base/EditView.tpl b/include/SugarFields/Fields/Base/EditView.tpl new file mode 100644 index 00000000..98e9e1e7 --- /dev/null +++ b/include/SugarFields/Fields/Base/EditView.tpl @@ -0,0 +1,46 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} +{if strlen({{sugarvar key='value' string=true}}) <= 0} +{assign var="value" value={{sugarvar key='default_value' string=true}} } +{else} +{assign var="value" value={{sugarvar key='value' string=true}} } +{/if} + \ No newline at end of file diff --git a/include/SugarFields/Fields/Base/EditViewFunction.tpl b/include/SugarFields/Fields/Base/EditViewFunction.tpl new file mode 100644 index 00000000..8b0c8413 --- /dev/null +++ b/include/SugarFields/Fields/Base/EditViewFunction.tpl @@ -0,0 +1,38 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} +{{sugarvar key='value'}} diff --git a/include/SugarFields/Fields/Base/ImportViewFunction.tpl b/include/SugarFields/Fields/Base/ImportViewFunction.tpl new file mode 100644 index 00000000..8b0c8413 --- /dev/null +++ b/include/SugarFields/Fields/Base/ImportViewFunction.tpl @@ -0,0 +1,38 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} +{{sugarvar key='value'}} diff --git a/include/SugarFields/Fields/Base/InlineEdit.tpl b/include/SugarFields/Fields/Base/InlineEdit.tpl new file mode 100644 index 00000000..40b7e82a --- /dev/null +++ b/include/SugarFields/Fields/Base/InlineEdit.tpl @@ -0,0 +1,39 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} +{{assign var=fieldName value=$vardef.name}} + \ No newline at end of file diff --git a/include/SugarFields/Fields/Base/InlineEditView.tpl b/include/SugarFields/Fields/Base/InlineEditView.tpl new file mode 100644 index 00000000..6e8819f0 --- /dev/null +++ b/include/SugarFields/Fields/Base/InlineEditView.tpl @@ -0,0 +1,39 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} +{{assign var=fieldName value=$vardef.name}} +{{$parentFieldArray->$fieldName}} \ No newline at end of file diff --git a/include/SugarFields/Fields/Base/ListView.tpl b/include/SugarFields/Fields/Base/ListView.tpl new file mode 100644 index 00000000..65827dea --- /dev/null +++ b/include/SugarFields/Fields/Base/ListView.tpl @@ -0,0 +1,39 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} + +{sugar_fetch object=$parentFieldArray key=$col} diff --git a/include/SugarFields/Fields/Base/SearchForm.tpl b/include/SugarFields/Fields/Base/SearchForm.tpl new file mode 100644 index 00000000..a6d10f94 --- /dev/null +++ b/include/SugarFields/Fields/Base/SearchForm.tpl @@ -0,0 +1,38 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} + diff --git a/include/SugarFields/Fields/Base/SugarFieldBase.php b/include/SugarFields/Fields/Base/SugarFieldBase.php new file mode 100644 index 00000000..67ae5829 --- /dev/null +++ b/include/SugarFields/Fields/Base/SugarFieldBase.php @@ -0,0 +1,393 @@ +type = $type; + $this->ss = new Sugar_Smarty(); + } + function fetch($path){ + $additional = ''; + if(!$this->hasButton && !empty($this->button)){ + $additional .= 'button . '>'; + } + if(!empty($this->buttons)){ + foreach($this->buttons as $v){ + $additional .= ' '; + } + + } + if(!empty($this->image)){ + $additional .= ' image . '>'; + } + return $this->ss->fetch($path) . $additional; + } + + function findTemplate($view){ + static $tplCache = array(); + + if ( isset($tplCache[$this->type][$view]) ) { + return $tplCache[$this->type][$view]; + } + + $lastClass = get_class($this); + $classList = array($this->type,str_replace('SugarField','',$lastClass)); + while ( $lastClass = get_parent_class($lastClass) ) { + $classList[] = str_replace('SugarField','',$lastClass); + } + + $tplName = ''; + foreach ( $classList as $className ) { + global $current_language; + if(isset($current_language)) { + $tplName = 'include/SugarFields/Fields/'. $className .'/'. $current_language . '.' . $view .'.tpl'; + if ( file_exists('custom/'.$tplName) ) { + $tplName = 'custom/'.$tplName; + break; + } + if ( file_exists($tplName) ) { + break; + } + } + $tplName = 'include/SugarFields/Fields/'. $className .'/'. $view .'.tpl'; + if ( file_exists('custom/'.$tplName) ) { + $tplName = 'custom/'.$tplName; + break; + } + if ( file_exists($tplName) ) { + break; + } + } + + $tplCache[$this->type][$view] = $tplName; + + return $tplName; + } + + public function formatField($rawField, $vardef){ + // The base field doesn't do any formatting, so override it in subclasses for more specific actions + return $rawField; + } + + + public function unformatField($formattedField, $vardef){ + // The base field doesn't do any formatting, so override it in subclasses for more specific actions + return $formattedField; + } + + function getSmartyView($parentFieldArray, $vardef, $displayParams, $tabindex = -1, $view){ + $this->setup($parentFieldArray, $vardef, $displayParams, $tabindex); + + + return $this->fetch($this->findTemplate($view)); + } + + function getListViewSmarty($parentFieldArray, $vardef, $displayParams, $col) { + // FIXME: Rework the listview to use two-pass rendering like the DetailView + + $tabindex = 1; + $isArray = is_array($parentFieldArray); + $fieldName = $vardef['name']; + + if ( $isArray ) { + $fieldNameUpper = strtoupper($fieldName); + if ( isset($parentFieldArray[$fieldNameUpper])) { + $parentFieldArray[$fieldName] = $this->formatField($parentFieldArray[$fieldNameUpper],$vardef); + } else { + $parentFieldArray[$fieldName] = ''; + } + } else { + if ( isset($parentFieldArray->$fieldName) ) { + $parentFieldArray->$fieldName = $this->formatField($parentFieldArray->$fieldName,$vardef); + } else { + $parentFieldArray->$fieldName = ''; + } + } + $this->setup($parentFieldArray, $vardef, $displayParams, $tabindex, false); + + $this->ss->left_delimiter = '{'; + $this->ss->right_delimiter = '}'; + $this->ss->assign('col',$vardef['name']); + + return $this->fetch($this->findTemplate('ListView')); + } + + /** + * Returns a smarty template for the DetailViews + * + * @param parentFieldArray string name of the variable in the parent template for the bean's data + * @param vardef vardef field defintion + * @param displayParam parameters for display + * available paramters are: + * * labelSpan - column span for the label + * * fieldSpan - column span for the field + */ + function getDetailViewSmarty($parentFieldArray, $vardef, $displayParams, $tabindex) { + return $this->getSmartyView($parentFieldArray, $vardef, $displayParams, $tabindex, 'DetailView'); + } + + // 99% of all fields will just format like a listview, but just in case, it's here to override + function getChangeLogSmarty($parentFieldArray, $vardef, $displayParams, $tabindex) { + return $this->formatField($parentFieldArray[$vardef['name']],$vardef); + } + + + function getEditViewSmarty($parentFieldArray, $vardef, $displayParams, $tabindex) { + if(!empty($vardef['function']['returns']) && $vardef['function']['returns'] == 'html'){ + $type = $this->type; + $this->type = 'Base'; + $result= $this->getDetailViewSmarty($parentFieldArray, $vardef, $displayParams, $tabindex); + $this->type = $type; + return $result; + } + return $this->getSmartyView($parentFieldArray, $vardef, $displayParams, $tabindex, 'EditView'); + } + + function getImportViewSmarty($parentFieldArray, $vardef, $displayParams, $tabindex) + { + return $this->getEditViewSmarty($parentFieldArray, $vardef, $displayParams, $tabindex); + } + + + + function getSearchViewSmarty($parentFieldArray, $vardef, $displayParams, $tabindex) { + if(!empty($vardef['auto_increment']))$vardef['len']=255; + return $this->getSmartyView($parentFieldArray, $vardef, $displayParams, $tabindex, 'EditView'); + } + + function getPopupViewSmarty($parentFieldArray, $vardef, $displayParams, $tabindex){ + if (is_array($displayParams) && !isset($displayParams['formName'])) + $displayParams['formName'] = 'popup_query_form'; + else if (empty($displayParams)) + $displayParams = array('formName' => 'popup_query_form'); + return $this->getSearchViewSmarty($parentFieldArray, $vardef, $displayParams, $tabindex); + } + + public function getEmailTemplateValue($inputField, $vardef, $context = null){ + // This does not return a smarty section, instead it returns a direct value + return $this->formatField($inputField,$vardef); + } + + function displayFromFunc( $displayType, $parentFieldArray, $vardef, $displayParams, $tabindex = 0 ) { + + if ( ! is_array($vardef['function']) ) { + $funcName = $vardef['function']; + $includeFile = ''; + $onListView = false; + $returnsHtml = false; + } else { + $funcName = $vardef['function']['name']; + $includeFile = ''; + if ( isset($vardef['function']['include']) ) { + $includeFile = $vardef['function']['include']; + } + if ( isset($vardef['function']['onListView']) && $vardef['function']['onListView'] == true ) { + $onListView = true; + } else { + $onListView = false; + } + if ( isset($vardef['function']['returns']) && $vardef['function']['returns'] == 'html' ) { + $returnsHtml = true; + } else { + $returnsHtml = false; + } + } + + if ( $displayType == 'ListView' + || $displayType == 'popupView' + || $displayType == 'searchView' + || $displayType == 'wirelessEditView' + || $displayType == 'wirelessDetailView' + || $displayType == 'wirelessListView' + ) { + // Traditionally, before 6.0, additional functions were never called, so this code doesn't get called unless the vardef forces it + if ( $onListView ) { + if ( !empty($includeFile) ) { + require_once($includeFile); + } + + return $funcName($parentFieldArray, $vardef['name'], $parentFieldArray[$vardef['name']], $displayType); + } else { + $displayTypeFunc = 'get'.$displayType.'Smarty'; + return $this->$displayTypeFunc($parentFieldArray, $vardef, $displayParams, $tabindex); + } + } else { + if ( !empty($displayParams['idName']) ) { + $fieldName = $displayParams['idName']; + } else { + $fieldName = $vardef['name']; + } + if ( $returnsHtml ) { + $this->setup($parentFieldArray, $vardef, $displayParams, $tabindex); + $tpl = $this->findTemplate($displayType.'Function'); + if ( $tpl == '' ) { + // Can't find a function template, just use the base + $tpl = $this->findTemplate('DetailViewFunction'); + } + return "" . $this->fetch($tpl) . ''; + } else { + return '{sugar_run_helper include="'.$includeFile.'" func="'.$funcName.'" bean=$bean field="'.$fieldName.'" value=$fields.'.$fieldName.'.value displayType="'.$displayType.'"}'; + } + } + } + + function getEditView() { + } + + function getSearchInput() { + } + + function getQueryLike() { + } + + function getQueryIn() { + } + + /** + * Setup function to assign values to the smarty template, should be called before every display function + */ + function setup($parentFieldArray, $vardef, $displayParams, $tabindex, $twopass=true) { + $this->button = ''; + $this->buttons = ''; + $this->image = ''; + if ($twopass){ + $this->ss->left_delimiter = '{{'; + $this->ss->right_delimiter = '}}'; + } + $this->ss->assign('parentFieldArray', $parentFieldArray); + $this->ss->assign('vardef', $vardef); + $this->ss->assign('tabindex', $tabindex); + + //for adding attributes to the field + + if(!empty($displayParams['field'])){ + $plusField = ''; + foreach($displayParams['field'] as $key=>$value){ + $plusField .= ' ' . $key . '="' . $value . '"';//bug 27381 + } + $displayParams['field'] = $plusField; + } + //for adding attributes to the button + if(!empty($displayParams['button'])){ + $plusField = ''; + foreach($displayParams['button'] as $key=>$value){ + $plusField .= ' ' . $key . '="' . $value . '"'; + } + $displayParams['button'] = $plusField; + $this->button = $displayParams['button']; + } + if(!empty($displayParams['buttons'])){ + $plusField = ''; + foreach($displayParams['buttons'] as $keys=>$values){ + foreach($values as $key=>$value){ + $plusField[$keys] .= ' ' . $key . '="' . $value . '"'; + } + } + $displayParams['buttons'] = $plusField; + $this->buttons = $displayParams['buttons']; + } + if(!empty($displayParams['image'])){ + $plusField = ''; + foreach($displayParams['image'] as $key=>$value){ + $plusField .= ' ' . $key . '="' . $value . '"'; + } + $displayParams['image'] = $plusField; + $this->image = $displayParams['image']; + } + $this->ss->assign('displayParams', $displayParams); + + + } + + /** + * This should be called when the bean is saved. The bean itself will be passed by reference + * @param SugarBean bean - the bean performing the save + * @param array params - an array of paramester relevant to the save, most likely will be $_REQUEST + */ + public function save($bean, $params, $field, $properties, $prefix = ''){ + if ( isset($params[$prefix.$field]) ) { + if(isset($properties['len']) && isset($properties['type']) && 'varchar' == $properties['type']){ + $bean->$field = trim($this->unformatField($params[$prefix.$field],$properties)); + } + else { + $bean->$field = $this->unformatField($params[$prefix.$field],$properties); + } + } + } + + /** + * Handles import field sanitizing for an field type + * + * @param $value string value to be sanitized + * @param $vardefs array + * @param $focus SugarBean object + * @param $settings ImportFieldSanitize object + * @return string sanitized value or boolean false if there's a problem with the value + */ + public function importSanitize( + $value, + $vardef, + $focus, + ImportFieldSanitize $settings + ) + { + if( isset($vardef['len']) ) { + // check for field length + $value = sugar_substr($value, $vardef['len']); + } + + return $value; + } + + /** + * isRangeSearchView + * This method helps determine whether or not to display the range search view code for the sugar field + * @param array $vardef entry representing the sugar field's definition + * @return boolean true if range search view should be displayed, false otherwise + */ + protected function isRangeSearchView($vardef) + { + return !empty($vardef['enable_range_search']) && !empty($_REQUEST['action']) && $_REQUEST['action']!='Popup'; + } +} diff --git a/include/SugarFields/Fields/Bool/DetailView.tpl b/include/SugarFields/Fields/Bool/DetailView.tpl new file mode 100644 index 00000000..5bd8a96d --- /dev/null +++ b/include/SugarFields/Fields/Bool/DetailView.tpl @@ -0,0 +1,46 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} +{if strval({{sugarvar key='value' stringFormat='false'}}) == "1" || strval({{sugarvar key='value' stringFormat='false'}}) == "yes" || strval({{sugarvar key='value' stringFormat='false'}}) == "on"} +{assign var="checked" value="CHECKED"} +{else} +{assign var="checked" value=""} +{/if} + +{{if !empty($displayParams.enableConnectors)}} +{{sugarvar_connector view='DetailView'}} +{{/if}} \ No newline at end of file diff --git a/include/SugarFields/Fields/Bool/EditView.tpl b/include/SugarFields/Fields/Bool/EditView.tpl new file mode 100644 index 00000000..8c91fa85 --- /dev/null +++ b/include/SugarFields/Fields/Bool/EditView.tpl @@ -0,0 +1,46 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} +{if strval({{sugarvar key='value' stringFormat='false'}}) == "1" || strval({{sugarvar key='value' stringFormat='false'}}) == "yes" || strval({{sugarvar key='value' stringFormat='false'}}) == "on"} +{assign var="checked" value="CHECKED"} +{else} +{assign var="checked" value=""} +{/if} + + diff --git a/include/SugarFields/Fields/Bool/InlineEdit.tpl b/include/SugarFields/Fields/Bool/InlineEdit.tpl new file mode 100644 index 00000000..d69773bc --- /dev/null +++ b/include/SugarFields/Fields/Bool/InlineEdit.tpl @@ -0,0 +1,45 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} +{{assign var=fieldName value=$vardef.name}} +{{if strval($parentFieldArray->$fieldName) == "1"}} +{{assign var="checked" value="CHECKED"}} +{{else}} +{{assign var="checked" value=""}} +{{/if}} + + \ No newline at end of file diff --git a/include/SugarFields/Fields/Bool/InlineEditView.tpl b/include/SugarFields/Fields/Bool/InlineEditView.tpl new file mode 100644 index 00000000..eacd7217 --- /dev/null +++ b/include/SugarFields/Fields/Bool/InlineEditView.tpl @@ -0,0 +1,44 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} +{{assign var=fieldName value=$vardef.name}} +{{if strval($parentFieldArray->$fieldName) == "1"}} +{{assign var="checked" value="CHECKED"}} +{{else}} +{{assign var="checked" value=""}} +{{/if}} + \ No newline at end of file diff --git a/include/SugarFields/Fields/Bool/ListView.tpl b/include/SugarFields/Fields/Bool/ListView.tpl new file mode 100644 index 00000000..2b2766c0 --- /dev/null +++ b/include/SugarFields/Fields/Bool/ListView.tpl @@ -0,0 +1,44 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} + + {if strval($parentFieldArray.$col) == "1" || strval($parentFieldArray.$col) == "yes" || strval($parentFieldArray.$col) == "on"} +{assign var="checked" value="CHECKED"} +{else} +{assign var="checked" value=""} +{/if} + diff --git a/include/SugarFields/Fields/Bool/SearchView.tpl b/include/SugarFields/Fields/Bool/SearchView.tpl new file mode 100644 index 00000000..c7f40836 --- /dev/null +++ b/include/SugarFields/Fields/Bool/SearchView.tpl @@ -0,0 +1,55 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} +{assign var="yes" value=""} +{assign var="no" value=""} +{assign var="default" value=""} + +{if strval({{sugarvar key='value' stringFormat='false'}}) == "1"} + {assign var="yes" value="SELECTED"} +{elseif strval({{sugarvar key='value' stringFormat='false'}}) == "0"} + {assign var="no" value="SELECTED"} +{else} + {assign var="default" value="SELECTED"} +{/if} + + + diff --git a/include/SugarFields/Fields/Bool/SugarFieldBool.php b/include/SugarFields/Fields/Bool/SugarFieldBool.php new file mode 100644 index 00000000..943de103 --- /dev/null +++ b/include/SugarFields/Fields/Bool/SugarFieldBool.php @@ -0,0 +1,113 @@ +setup($parentFieldArray, $vardef, $displayParams, $tabindex); + //If there was a type override to specifically render it as a boolean, show the EditView checkbox + if( preg_match("/(favorites|current_user|open)_only.*/", $vardef['name'])) + { + return $this->fetch($this->findTemplate('EditView')); + } else { + return $this->fetch($this->findTemplate('SearchView')); + } + } + + /** + * @see SugarFieldBase::importSanitize() + */ + public function importSanitize( + $value, + $vardef, + $focus, + ImportFieldSanitize $settings + ) + { + $bool_values = array(0=>'0',1=>'no',2=>'off',3=>'n',4=>'yes',5=>'y',6=>'on',7=>'1'); + $bool_search = array_search($value,$bool_values); + if ( $bool_search === false ) { + return false; + } + else { + //Convert all the values to a real bool. + $value = (int) ( $bool_search > 3 ); + } + if ( isset($vardef['dbType']) && $vardef['dbType'] == 'varchar' ) + $value = ( $value ? 'on' : 'off' ); + + return $value; + } + + public function getEmailTemplateValue($inputField, $vardef, $context = null){ + global $app_list_strings; + // This does not return a smarty section, instead it returns a direct value + if ( $inputField == 'bool_true' || $inputField === true ) { // Note: true must be absolute true + return $app_list_strings['checkbox_dom']['1']; + } else if ( $inputField == 'bool_false' || $inputField === false){ // Note: false must be absolute false + return $app_list_strings['checkbox_dom']['2']; + } else { // otherwise we return blank display + return ''; + } + } + + public function unformatField($formattedField, $vardef){ + if ( empty($formattedField) ) { + $unformattedField = false; + return $unformattedField; + } + if ( $formattedField == '0' || $formattedField == 'off' || $formattedField == 'false' || $formattedField == 'no' ) { + $unformattedField = false; + } else { + $unformattedField = true; + } + + return $unformattedField; + } + +} + +?> diff --git a/include/SugarFields/Fields/Collection/CollectionDetailView.tpl b/include/SugarFields/Fields/Collection/CollectionDetailView.tpl new file mode 100644 index 00000000..7d900be6 --- /dev/null +++ b/include/SugarFields/Fields/Collection/CollectionDetailView.tpl @@ -0,0 +1,61 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} +{if !$displayParams.nolink} + +{/if} +{$values.primary.name} +{if !$displayParams.nolink} + + +{if !empty($values.secondaries)} + Hide/Show + + + +{/if} +{/if} \ No newline at end of file diff --git a/include/SugarFields/Fields/Collection/CollectionEditView.tpl b/include/SugarFields/Fields/Collection/CollectionEditView.tpl new file mode 100644 index 00000000..762439a4 --- /dev/null +++ b/include/SugarFields/Fields/Collection/CollectionEditView.tpl @@ -0,0 +1,98 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} + + + + + + + + + +{if !empty($vardef.required)} + +{/if} + + {include file=$cacheRowFile} + + + + + + + + +
+ + + {if !empty($displayParams.allowNewValue) } + + {/if} + + +
+ + + + +
+ Add +
+{if !empty($values.secondaries)} + {foreach item=secondary_field from=$values.secondaries key=key} + + {/foreach} +{/if} + +{literal} + +{/literal} +{$quickSearchCode} \ No newline at end of file diff --git a/include/SugarFields/Fields/Collection/CollectionEditViewRow.tpl b/include/SugarFields/Fields/Collection/CollectionEditViewRow.tpl new file mode 100644 index 00000000..ed2bbd67 --- /dev/null +++ b/include/SugarFields/Fields/Collection/CollectionEditViewRow.tpl @@ -0,0 +1,81 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} + + + + {if empty($displayParams.hideNameLabel)} + {ldelim}sugar_translate label='LBL_COLLECTION_NAME'{rdelim}: + {/if} + + {foreach item=extra_field from=$displayParams.collection_field_list key=key_extra} + + {$extra_field.label} + + + {/foreach} + + + + + + + + {ldelim}sugar_translate label='LBL_COLLECTION_PRIMARY'{rdelim} + + + +   Hide/Show + + + + + + + + + {if $showSelectButton} + + {/if} + + {foreach item=extra_field from=$displayParams.collection_field_list key=key_extra} + + {$extra_field.field} + + {/foreach} \ No newline at end of file diff --git a/include/SugarFields/Fields/Collection/DetailView.tpl b/include/SugarFields/Fields/Collection/DetailView.tpl new file mode 100644 index 00000000..79e42197 --- /dev/null +++ b/include/SugarFields/Fields/Collection/DetailView.tpl @@ -0,0 +1,61 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} + + +
+ \ No newline at end of file diff --git a/include/SugarFields/Fields/Collection/EditView.tpl b/include/SugarFields/Fields/Collection/EditView.tpl new file mode 100644 index 00000000..76e1ba5d --- /dev/null +++ b/include/SugarFields/Fields/Collection/EditView.tpl @@ -0,0 +1,67 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} + + + +
+ \ No newline at end of file diff --git a/include/SugarFields/Fields/Collection/SugarFieldCollection.js b/include/SugarFields/Fields/Collection/SugarFieldCollection.js new file mode 100644 index 00000000..4d20760e --- /dev/null +++ b/include/SugarFields/Fields/Collection/SugarFieldCollection.js @@ -0,0 +1,80 @@ +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ +if(typeof(SUGAR.collection)=="undefined"){SUGAR.collection=function(form_name,field_name,module,popupData){this.more_status=false;this.form=form_name;this.field=field_name;this.field_element_name=this.form+'_'+this.field;this.module=module;this.fields_count=0;this.extra_fields_count=0;this.first=true;this.primary_field="";this.cloneField=new Array();this.sqs_clone="";this.secondaries_values=new Array();this.update_fields=new Object();this.show_more_image=true;};SUGAR.collection.prototype={remove:function(num){var radio_els=this.get_radios();var div_el;if(radio_els.length==1){div_el=document.getElementById(this.field_element_name+'_input_div_'+num);var input_els=div_el.getElementsByTagName('input');input_els[0].value='';input_els[1].value='';if(this.primary_field){div_el=document.getElementById(this.field_element_name+'_radio_div_'+num);radio_els=div_el.getElementsByTagName('input');radio_els[0].checked=false;}}else{div_el=document.getElementById(this.field_element_name+'_input_div_'+num);if(!div_el) +div_el=document.getElementById(this.field_element_name+'_radio_div_'+num);var tr_to_remove=document.getElementById('lineFields_'+this.field_element_name+'_'+num);div_el.parentNode.parentNode.parentNode.removeChild(tr_to_remove);var div_id='lineFields_'+this.field_element_name+'_'+num;if(typeof sqs_objects[div_id.replace("_field_","_")]!='undefined'){delete(sqs_objects[div_id.replace("_field_","_")]);} +var checked=false;for(var k=0;kencode($displayParams); + $vardefJSON = $json->encode($vardef); + $this->ss->assign('displayParamsJSON', '{literal}'.$displayParamsJSON.'{/literal}'); + $this->ss->assign('vardefJSON', '{literal}'.$vardefJSON.'{/literal}'); + $this->setup($parentFieldArray, $vardef, $displayParams, $tabindex); + if(empty($this->tpl_path)){ + $this->tpl_path = $this->findTemplate('DetailView'); + } + return $this->fetch($this->tpl_path); + } + + function getEditViewSmarty($parentFieldArray, $vardef, $displayParams, $tabindex, $searchView = false) { + if($searchView){ + $form_name = 'search_form'; + }else{ + $form_name = 'EditView'; + } + $json = getJSONobj(); + $displayParamsJSON = $json->encode($displayParams); + $vardefJSON = $json->encode($vardef); + $this->ss->assign('required', !empty($vardef['required'])); + $this->ss->assign('displayParamsJSON', '{literal}'.$displayParamsJSON.'{/literal}'); + $this->ss->assign('vardefJSON', '{literal}'.$vardefJSON.'{/literal}'); + $this->setup($parentFieldArray, $vardef, $displayParams, $tabindex); + if(!$searchView) { + if(empty($this->tpl_path)){ + $this->tpl_path = $this->findTemplate('EditView'); + } + return $this->fetch($this->tpl_path); + } + } + + function getSearchViewSmarty($parentFieldArray, $vardef, $displayParams, $tabindex) { + $this->getEditViewSmarty($parentFieldArray, $vardef, $displayParams, $tabindex, true); + } + /** + * This should be called when the bean is saved. The bean itself will be passed by reference + * @param SugarBean bean - the bean performing the save + * @param array params - an array of paramester relevant to the save, most likely will be $_REQUEST + */ + public function save(&$bean, $params, $field, $properties, $prefix = ''){ + if(isset($_POST["primary_" . $field . "_collection"])){ + $save = false; + $value_name = $field . "_values"; + $link_field = array(); + // populate $link_field from POST + foreach($_POST as $name=>$value){ + if(strpos($name, $field . "_collection_") !== false){ + $num = substr($name, -1); + if(is_numeric($num)){ + settype($num, 'int'); + if(strpos($name, $field . "_collection_extra_") !== false){ + $extra_field = substr($name, $field . "_collection_extra_" . $num); + $link_field[$num]['extra_field'][$extra_field]=$value; + }else if ($name == $field . "_collection_" . $num){ + $link_field[$num]['name']=$value; + }else if ($name == "id_" . $field . "_collection_" . $num){ + $link_field[$num]['id']=$value; + } + } + } + } + // Set Primary + if(isset($_POST["primary_" . $field . "_collection"])){ + $primary = $_POST["primary_" . $field . "_collection"]; + settype($primary, 'int'); + $link_field[$primary]['primary']=true; + } + // Create or update record and take care of the extra_field + require('include/modules.php'); + require_once('data/Link.php'); + $class = load_link_class($bean->field_defs[$field]); + + $link_obj = new $class($bean->field_defs[$field]['relationship'], $bean, $bean->field_defs[$field]); + $module = $link_obj->getRelatedModuleName(); + $beanName = $beanList[$module]; + require_once($beanFiles[$beanName]); + foreach($link_field as $k=>$v){ + $save = false; + $update_fields = array(); + $obj = new $beanName(); + if(!isset($link_field[$k]['name']) || empty($link_field[$k]['name'])){ + // There is no name so it is an empty record -> ignore it! + unset($link_field[$k]); + break; + } + if(!isset($link_field[$k]['id']) || empty($link_field[$k]['id']) || (isset($_POST[$field . "_new_on_update"]) && $_POST[$field . "_new_on_update"] === 'true')){ + // Create a new record + if(isset($_POST[$field . "_allow_new"]) && ($_POST[$field . "_allow_new"] === 'false' || $_POST[$field . "_allow_new"] === false)){ + // Not allow to create a new record so remove from $link_field + unset($link_field[$k]); + break; + } + if(!isset($link_field[$k]['id']) || empty($link_field[$k]['id'])){ + // There is no ID so it is a new record + $save = true; + $obj->name=$link_field[$k]['name']; + }else{ + // We duplicate an existing record because new_on_update is set + $obj->retrieve($link_field[$k]['id']); + $obj->id=''; + $obj->name = $obj->name . '_DUP'; + } + }else{ + // id exist so retrieve the data + $obj->retrieve($link_field[$k]['id']); + } + // Update the extra field for the new or the existing record + if(isset($v['extra_field']) && is_array($v['extra_field'])){ + // Retrieve the changed fields + if(isset($_POST["update_fields_{$field}_collection"]) && !empty($_POST["update_fields_{$field}_collection"])){ + $JSON = getJSONobj(); + $update_fields = $JSON->decode(html_entity_decode($_POST["update_fields_{$field}_collection"])); + } + // Update the changed fields + foreach($update_fields as $kk=>$vv){ + if(!isset($_POST[$field . "_allow_update"]) || ($_POST[$field . "_allow_update"] !== 'false' && $_POST[$field . "_allow_update"] !== false)){ + //allow to update the extra_field in the record + if(isset($v['extra_field'][$kk]) && $vv == true){ + $extra_field_name = str_replace("_".$field."_collection_extra_".$k,"",$kk); + if($obj->$extra_field_name != $v['extra_field'][$kk]){ + $save = true; + $obj->$extra_field_name=$v['extra_field'][$kk]; + } + } + } + } + } + // Save the new or updated record + if($save){ + if(!$obj->ACLAccess('save')){ + ACLController::displayNoAccess(true); + sugar_cleanup(true); + } + $obj->save(); + $link_field[$k]['id']=$obj->id; + } + } + // Save new relationship or delete deleted relationship + if(!empty($link_field)){ + if($bean->load_relationship($field)){ + $oldvalues = $bean->$field->get(true); + $role_field = $bean->$field->_get_link_table_role_field($bean->$field->_relationship_name); + foreach($link_field as $new_v){ + if(!empty($new_v['id'])){ + if(!empty($role_field)){ + if(isset($new_v['primary']) && $new_v['primary']){ + $bean->$field->add($new_v['id'], array($role_field=>'primary')); + }else{ + $bean->$field->add($new_v['id'], array($role_field=>'NULL')); + } + }else{ + $bean->$field->add($new_v['id'], array()); + } + } + } + foreach($oldvalues as $old_v){ + $match = false; + foreach($link_field as $new_v){ + if($new_v['id'] == $old_v['id']){ + $match = true; + } + } + if(!$match){ + $bean->$field->delete($bean->id, $old_v['id']); + } + } + } + } + } + } + +} +?> \ No newline at end of file diff --git a/include/SugarFields/Fields/Collection/ViewSugarFieldCollection.php b/include/SugarFields/Fields/Collection/ViewSugarFieldCollection.php new file mode 100644 index 00000000..c4bd8074 --- /dev/null +++ b/include/SugarFields/Fields/Collection/ViewSugarFieldCollection.php @@ -0,0 +1,543 @@ +json = getJSONobj(); + if($fill_data){ + $this->displayParams = $this->json->decode(html_entity_decode($_REQUEST['displayParams'])); + $this->vardef = $this->json->decode(html_entity_decode($_REQUEST['vardef'])); + $this->module_dir = $_REQUEST['module_dir']; + $this->action_type = $_REQUEST['action_type']; + $this->name = $this->vardef['name']; + $this->value_name = $this->name . '_values'; + $this->numFields = 1; + $this->ss = new Sugar_Smarty(); + $this->edit_tpl_path = $this->findTemplate('CollectionEditView'); + $this->detail_tpl_path = $this->findTemplate('CollectionDetailView'); + $this->extra_var = array(); + $this->field_to_name_array = array(); + } + } + /* + * Retrieve the related module and load the bean and the relationship + * call retrieve values() + */ + function setup(){ + if(!class_exists('Relationship')){ + + } + $rel = new Relationship(); + if(!empty($this->vardef['relationship'])){ + $rel->retrieve_by_name($this->vardef['relationship']); + } + if($rel->relationship_type == 'many-to-many'){ + if($rel->lhs_module == $this->module_dir){ + $this->related_module = $rel->rhs_module; + $module_dir = $rel->lhs_module; + }else if($rel->rhs_module == $this->module_dir){ + $this->related_module = $rel->lhs_module; + $module_dir = $rel->rhs_module; + }else{ + die("this field has no relationships mapped with this module"); + } + if($module_dir != $this->module_dir){ + die('These modules do not match : '. $this->module_dir . ' and ' . $module_dir); + } + if(isset($GLOBALS['beanList'][$this->module_dir])){ + $class = $GLOBALS['beanList'][$this->module_dir]; + if(file_exists($GLOBALS['beanFiles'][$class])){ + $this->bean = loadBean($this->module_dir); + $this->bean->retrieve($_REQUEST['bean_id']); + if($this->bean->load_relationship($this->vardef['name'])){ + $this->retrieve_values(); + }else{ + die('failed to load the relationship'); + } + }else{ + die('class file do not exist'); + } + }else{ + die($this->module_dir . ' is not in the beanList.'); + } + } + else{ + die("the relationship is not a many-to-many"); + } + } + /* + * Retrieve the values from the DB using the get method of the link class + * Organize and save the value into the bean + */ + function retrieve_values(){ + if(empty($this->bean->{$this->value_name}) && isset($this->bean->{$this->name})){ + $values = array(); + $values = $this->bean->{$this->name}->get(true); + $role_field = $this->bean->{$this->name}->_get_link_table_role_field($this->bean->{$this->name}->_relationship_name); + foreach($values as $v){ + $role = ''; + foreach($v as $kk=>$vv){ + if($kk == $role_field){ + $role=$vv; + } + } + if($role == 'primary'){ + $primary_id = $v['id']; + }else{ + $secondary_ids[] = array('id'=>$v['id'], 'role'=>$role); + } + } + $this->bean->{$this->value_name} = array('role_field'=>$role_field); + if(isset($primary_id) || isset($secondary_ids)){ + if(!isset($primary_id)){ + $primary_id = $secondary_ids[0]['id']; + unset($secondary_ids[0]); + } + if(isset($GLOBALS['beanList'][ $this->related_module])){ + $class = $GLOBALS['beanList'][$this->related_module]; + if(file_exists($GLOBALS['beanFiles'][$class])){ + $mod = loadBean($this->module_dir); + $mod->relDepth = $this->bean->relDepth + 1; + $mod->retrieve($primary_id); + if (isset($mod->name)) { + $this->bean->{$this->value_name}=array_merge($this->bean->{$this->value_name}, array('primary'=>array('id'=>$primary_id, 'name'=>$mod->name))); + } + $secondaries = array(); + if(isset($secondary_ids)){ + foreach($secondary_ids as $v){ + if($mod->retrieve($v['id'])){ + if (isset($mod->name)){ + $secondaries['secondaries'][]=array('id'=>$v['id'], 'name'=>$mod->name); + } + } + } + } + $this->bean->{$this->value_name}=array_merge($this->bean->{$this->value_name}, $secondaries); + if(isset($field['additionalFields'])){ + foreach($field['additionalFields'] as $field=>$to){ + if(isset($mod->$field)){ + $this->bean->$to = $mod->$field; + } + } + } + } + } + } + } + } + /* + * redirect to the good process method. + */ + function process(){ + if($this->action_type == 'editview'){ + $this->process_editview(); + }else if($this->action_type == 'detailview'){ + $this->process_detailview(); + } + } + function process_detailview(){ + + } + /* + * Build the DisplayParams array + */ + function process_editview(){ + if(isset($this->bean->{$this->value_name}['secondaries'])){ + $this->numFields=count($this->bean->{$this->value_name}['secondaries'])+1; + } + if(!isset($this->displayParams['readOnly'])) { + $this->displayParams['readOnly'] = ''; + } else { + $this->displayParams['readOnly'] = $this->displayParams['readOnly'] == false ? '' : 'READONLY'; + } + // If there is extra field to show. + if(isset($this->displayParams['collection_field_list'])){ + + require_once('include/SugarFields/SugarFieldHandler.php'); + $sfh = new SugarFieldHandler(); + vardefmanager::loadVardef($this->related_module, $GLOBALS['beanList'][$this->related_module]); + foreach($this->displayParams['collection_field_list'] as $k=>$v){ + $javascript=''; + $collection_field_vardef = $GLOBALS['dictionary'][$GLOBALS['beanList'][$this->related_module]]['fields'][$v['name']]; + + // For each extra field the params which are not displayParams will be consider as params to override the vardefs values. + foreach($v as $k_override=>$v_override){ + if($k_override != 'displayParams'){ + $collection_field_vardef[$k_override] = $v_override; + } + } + + // If relate field : enable quick search by creating the sqs_object array. + if($collection_field_vardef['type'] == 'relate'){ + require_once('include/TemplateHandler/TemplateHandler.php'); + $tph = new TemplateHandler(); + $javascript = $tph->createQuickSearchCode(array($collection_field_vardef['name']=>$collection_field_vardef), array($v), $this->form_name); + $javascript = str_replace('" + $javascriptPHP = $this->json->decode($javascript); + foreach($javascriptPHP['populate_list'] as $kk=>$vv){ + $javascriptPHP['populate_list'][$kk] .= "_" . $this->vardef['name'] . "_collection_extra_0"; + } + foreach($javascriptPHP['required_list'] as $kk=>$vv){ + $javascriptPHP['required_list'][$kk] .= "_" . $this->vardef['name'] . "_collection_extra_0"; + } + foreach($javascriptPHP['field_list'] as $kk=>$vv){ + if($vv == 'id'){ + $javascriptPHP['populate_list'][$kk]; + } + } + $javascript = $this->json->encode($javascriptPHP); + $javascript = "'; + } + + $collection_field_vardef['name'] .= "_" . $this->vardef['name'] . "_collection_extra_0"; + if(isset($collection_field_vardef['id_name'])){ + $collection_field_vardef['id_name'] .= "_" . $this->vardef['name'] . "_collection_extra_0"; + } + if(isset($this->displayParams['allow_update']) && ($this->displayParams['allow_update'] === false || $this->displayParams['allow_update'] === 'false')){ + $this->displayParams['allow_update']='false'; + $v['displayParams']['field']['disabled']=''; + }else{ + $this->displayParams['allow_update']='true'; + if(!isset($v['displayParams'])){ + $v['displayParams']=array(); + } + } + $viewtype='EditView'; + $name = $collection_field_vardef['name']; + // Rearranging the array with name as key instaead of number. This is required for displaySmarty() to assign the good variable. + $this->displayParams['collection_field_list'][$name]['vardefName'] = $this->displayParams['collection_field_list'][$k]['name']; + $this->displayParams['collection_field_list'][$name]['name'] = $name; + if($collection_field_vardef['type'] == 'relate'){ + $this->displayParams['collection_field_list'][$name]['id_name'] = $collection_field_vardef['id_name']; + $this->displayParams['collection_field_list'][$name]['module'] = $collection_field_vardef['module']; + } + $this->displayParams['collection_field_list'][$name]['label'] = "{sugar_translate label='{$collection_field_vardef['vname']}' module='{$this->related_module}'}";//translate($collection_field_vardef['vname'], $this->related_module); + $this->displayParams['collection_field_list'][$name]['field'] = $sfh->displaySmarty('displayParams.collection_field_list', $collection_field_vardef, $viewtype, $v['displayParams'], 1); + $this->displayParams['collection_field_list'][$name]['field'] .= '{literal}'.$javascript; + // Handle update_field array ONCHANGE + $this->displayParams['collection_field_list'][$name]['field'] .= << + var oldonchange = ''; + if(typeof(document.getElementById('{$collection_field_vardef['name']}').attributes.onchange) != 'undefined') + { + oldonchange=document.getElementById('{$collection_field_vardef['name']}').attributes.onchange.value; + } +FRA; + $this->displayParams['collection_field_list'][$name]['field'] .= "eval(\"document.getElementById('{$collection_field_vardef['name']}').onchange = function onchange(event){collection['{$this->vardef['name']}'].update_fields.{$collection_field_vardef['name']}=true;"; + if($collection_field_vardef['type'] == 'relate'){ + // If relate add the ID field to the array + $this->displayParams['collection_field_list'][$name]['field'] .= "collection['{$this->vardef['name']}'].update_fields.{$collection_field_vardef['id_name']}=true;"; + } + $this->displayParams['collection_field_list'][$name]['field'] .= "document.getElementById('update_fields_{$this->vardef['name']}_collection').value = JSON.stringifyNoSecurity(collection['{$this->vardef['name']}'].update_fields);\" + oldonchange + \"};\");{/literal}"; + //we need to get rid of the old value; + unset($this->displayParams['collection_field_list'][$k]); + } + } + if(!isset($this->displayParams['class'])) $this->displayParams['class']=''; + if(isset($this->displayParams['allow_new']) && ($this->displayParams['allow_new'] === false || $this->displayParams['allow_new'] === 'false')){ + $this->displayParams['allow_new']='false'; + $this->displayParams['class']=str_replace('sqsNoAutofill','',$this->displayParams['class']); + }else{ + $this->displayParams['allow_new']='true'; + $this->displayParams['class'].=' sqsNoAutofill'; + } + if(isset($this->displayParams['new_on_update']) && ($this->displayParams['new_on_update'] !== false || $this->displayParams['new_on_update'] !== 'false' || $this->displayParams['new_on_update'] !== 'FALSE' || $this->displayParams['new_on_update'] !== '0')){ + $this->displayParams['new_on_update']='true'; + }else{ + $this->displayParams['new_on_update']='false'; + } + } + + /* + * Init the template with the variables + */ + function init_tpl(){ + foreach($this->extra_var as $k=>$v){ + $this->ss->assign($k,$v); + } + if($this->action_type == 'editview'){ + $this->ss->assign('quickSearchCode',$this->createQuickSearchCode()); + $this->createPopupCode();// this code populate $this->displayParams with popupdata. + $this->tpl_path = $this->edit_tpl_path; + }else if($this->action_type == 'detailview'){ + $this->tpl_path = $this->detail_tpl_path; + } + + $this->ss->assign('displayParams',$this->displayParams); + $this->ss->assign('vardef',$this->vardef); + $this->ss->assign('module',$this->related_module); + $this->ss->assign('values',$this->bean->{$this->value_name}); + $this->ss->assign('showSelectButton',$this->showSelectButton); + $this->ss->assign('hideShowHideButton',$this->hideShowHideButton); + $this->ss->assign('APP',$GLOBALS['app_strings']); + } + /* + * Display the collection field after retrieving the cached row. + */ + function display(){ + $cacheRowFile = $GLOBALS['sugar_config']['cache_dir'] . 'modules/'. $this->module_dir . '/collections/'. $this->name . '.tpl'; + if(!$this->checkTemplate($cacheRowFile)){ + $dir = dirname($cacheRowFile); + if(!file_exists($dir)) { + + mkdir_recursive($dir, null, true); + } + $cacheRow = $this->ss->fetch($this->findTemplate('CollectionEditViewRow')); + file_put_contents($cacheRowFile, $cacheRow); + } + $this->ss->assign('cacheRowFile', $cacheRowFile); + return $this->ss->fetch($this->tpl_path); + } + /* + * Check if the template is cached + * return a bool + */ + function checkTemplate($cacheRowFile){ + if(!empty($GLOBALS['sugar_config']['developerMode']) || !empty($_SESSION['developerMode'])){ + return false; + } + return file_exists($cacheRowFile); + } + + + /* + * Create the quickSearch code for the collection field. + * return the javascript code which define sqs_objects. + */ + function createQuickSearchCode($returnAsJavascript = true){ + $sqs_objects = array(); + require_once('include/QuickSearchDefaults.php'); + $qsd = new QuickSearchDefaults(); + $qsd->setFormName($this->form_name); + for($i=0; $i<$this->numFields; $i++){ + $name1 = "{$this->form_name}_{$this->name}_collection_{$i}"; + if(!$this->skipModuleQuickSearch && preg_match('/(Campaigns|Teams|Users|Contacts|Accounts)/si', $this->related_module, $matches)) { + if($matches[0] == 'Users'){ + $sqs_objects[$name1] = $qsd->getQSUser(); + } else if($matches[0] == 'Campaigns') { + $sqs_objects[$name1] = $qsd->getQSCampaigns(); + + } else if($matches[0] == 'Users'){ + $sqs_objects[$name1] = $qsd->getQSUser(); + + } else if($matches[0] == 'Accounts') { + $nameKey = "{$this->name}_collection_{$i}"; + $idKey = "id_{$this->name}_collection_{$i}"; + + //There are billingKey, shippingKey and additionalFields entries you can define in editviewdefs.php + //entry to allow quick search to autocomplete fields with a suffix value of the + //billing/shippingKey value (i.e. 'billingKey' => 'primary' in Contacts will populate + //primary_XXX fields with the Account's billing address values). + //addtionalFields are key/value pair of fields to fill from Accounts(key) to Contacts(value) + $billingKey = isset($this->displayParams['billingKey']) ? $this->displayParams['billingKey'] : null; + $shippingKey = isset($this->displayParams['shippingKey']) ? $this->displayParams['shippingKey'] : null; + $additionalFields = isset($this->displayParams['additionalFields']) ? $this->displayParams['additionalFields'] : null; + $sqs_objects[$name1] = $qsd->getQSAccount($nameKey, $idKey, $billingKey, $shippingKey, $additionalFields); + } else if($matches[0] == 'Contacts'){ + $sqs_objects[$name1] = $qsd->getQSContact($name1, "id_".$name1); + } + $temp_array = array('field_list'=>array(),'populate_list'=>array()); + foreach($sqs_objects[$name1]['field_list'] as $k=>$v){ + if(!in_array($v, array('name','id'))){ + $sqs_objects[$name1]['primary_field_list'][]=$v; + $sqs_objects[$name1]['primary_populate_list'][]=$sqs_objects[$name1]['populate_list'][$k]; + }else{ + $temp_array['field_list'][]=$v; + $temp_array['populate_list'][]=$sqs_objects[$name1]['populate_list'][$k]; + } + } + $sqs_objects[$name1]['field_list'] = $temp_array['field_list']; + $sqs_objects[$name1]['populate_list'] = $temp_array['populate_list']; + if(isset($this->displayParams['collection_field_list'])){ + foreach($this->displayParams['collection_field_list'] as $v){ + $sqs_objects[$name1]['populate_list'][]= $v['vardefName']."_".$this->name."_collection_extra_".$i; + $sqs_objects[$name1]['field_list'][] = $v['vardefName']; + } + } + }else { + $sqs_objects[$name1] = $qsd->getQSParent($this->related_module); + $sqs_objects[$name1]['populate_list'] = array("{$this->vardef['name']}_collection_{$i}", "id_{$this->vardef['name']}_collection_{$i}"); + $sqs_objects[$name1]['field_list'] = array('name', 'id'); + if(isset($this->displayParams['collection_field_list'])){ + foreach($this->displayParams['collection_field_list'] as $v){ + $sqs_objects[$name1]['populate_list'][] = $v['vardefName']."_".$this->name."_collection_extra_".$i; + $sqs_objects[$name1]['field_list'][] = $v['vardefName']; + } + } + if(isset($this->displayParams['field_to_name_array'])){ + foreach($this->displayParams['field_to_name_array'] as $k=>$v){ + /* + * "primary_populate_list" and "primary_field_list" are used when the field is selected as a primary. + * At this time the JS function changePrimary() will copy "primary_populate_list" and "primary_field_list" + * into "populate_list" and "field_list" and remove the values from all the others which are secondaries. + * "primary_populate_list" and "primary_field_list" contain the fields which has to be populated outside of + * the collection field. For example the "Address Information" are populated with the "billing address" of the + * selected account in a contact editview. + */ + $sqs_objects[$name1]['primary_populate_list'][] = $v; + $sqs_objects[$name1]['primary_field_list'][] = $k; + } + }else if(isset($field['field_list']) && isset($field['populate_list'])){ + $sqs_objects[$name1]['primary_populate_list'] = array_merge($sqs_objects[$name1]['populate_list'], $field['field_list']); + $sqs_objects[$name1]['primary_field_list'] = array_merge($sqs_objects[$name1]['field_list'], $field['populate_list']); + }else{ + $sqs_objects[$name1]['primary_populate_list'] = array(); + $sqs_objects[$name1]['primary_field_list'] = array(); + } + } + } + + $id = "{$this->form_name}_{$this->name}_collection_0"; + + if(!empty($sqs_objects) && count($sqs_objects) > 0) { + foreach($sqs_objects[$id]['field_list'] as $k=>$v){ + $this->field_to_name_array[$v] = $sqs_objects[$id]['populate_list'][$k]; + } + if($returnAsJavascript){ + $quicksearch_js = ''; + }else{ + return $sqs_objects; + } + } + return ''; + } + /* + * Always call createQuickSearchCode() before createPopupCode() to define field_to_name_array + */ + function createPopupCode(){ + // TODO the 'select' button is not fully working. We should use the sqs_objects in open_popup instead of the parameter. + if(isset($this->field_to_name_array) && !empty($this->field_to_name_array)){ + $call_back_function = 'set_return'; + + if(isset($this->displayParams['formName'])) { + $form = $this->displayParams['formName']; + } else if($this->action_type == 'editview'){ + $form = 'EditView'; + } else if($this->action_type == 'quickcreate'){ + $form = "QuickCreate_{$this->module_dir}"; + } + + if(isset($this->displayParams['call_back_function'])) { + $call_back_function = $this->displayParams['call_back_function']; + } + + $popup_request_data= array( + 'call_back_function' => $call_back_function, + 'form_name' => $form, + 'field_to_name_array' => $this->field_to_name_array, + ); + + //Make sure to replace {{ and }} with spacing in between because Smarty template parsing will treat {{ or }} specially + $this->displayParams['popupData'] = '{literal}'. str_replace(array('{{', '}}'), array('{ {', '} }'), $this->json->encode($popup_request_data)) . '{/literal}'; + } + } + + + + function findTemplate($view){ + static $tplCache = array(); + + if ( isset($tplCache[$this->type][$view]) ) { + return $tplCache[$this->type][$view]; + } + + $lastClass = get_class($this); + $classList = array($this->type,str_replace('ViewSugarField','',$lastClass)); + while ( $lastClass = get_parent_class($lastClass) ) { + $classList[] = str_replace('ViewSugarField','',$lastClass); + } + + $tplName = ''; + foreach ( $classList as $className ) { + global $current_language; + if(isset($current_language)) { + $tplName = 'include/SugarFields/Fields/'. $className .'/'. $current_language . '.' . $view .'.tpl'; + if ( file_exists('custom/'.$tplName) ) { + $tplName = 'custom/'.$tplName; + break; + } + if ( file_exists($tplName) ) { + break; + } + } + $tplName = 'include/SugarFields/Fields/'. $className .'/'. $view .'.tpl'; + if ( file_exists('custom/'.$tplName) ) { + $tplName = 'custom/'.$tplName; + break; + } + if ( file_exists($tplName) ) { + break; + } + } + + $tplCache[$this->type][$view] = $tplName; + + return $tplName; + } +} + +?> \ No newline at end of file diff --git a/include/SugarFields/Fields/Collection/view.sugarfieldcollection.php b/include/SugarFields/Fields/Collection/view.sugarfieldcollection.php new file mode 100644 index 00000000..bdfcbd67 --- /dev/null +++ b/include/SugarFields/Fields/Collection/view.sugarfieldcollection.php @@ -0,0 +1,43 @@ +setup(); +$view->process(); +$view->init_tpl(); +echo $view->display(); +?> \ No newline at end of file diff --git a/include/SugarFields/Fields/Currency/DetailView.tpl b/include/SugarFields/Fields/Currency/DetailView.tpl new file mode 100644 index 00000000..87564af8 --- /dev/null +++ b/include/SugarFields/Fields/Currency/DetailView.tpl @@ -0,0 +1,43 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} + +{sugar_number_format var={{sugarvar key='value' stringFormat='false'}} } + +{{if !empty($displayParams.enableConnectors)}} +{{sugarvar_connector view='DetailView'}} +{{/if}} \ No newline at end of file diff --git a/include/SugarFields/Fields/Currency/EditView.tpl b/include/SugarFields/Fields/Currency/EditView.tpl new file mode 100644 index 00000000..424e6031 --- /dev/null +++ b/include/SugarFields/Fields/Currency/EditView.tpl @@ -0,0 +1,44 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} +{if strlen({{sugarvar key='value' string=true}}) <= 0} +{assign var="value" value={{sugarvar key='default_value' string=true}} } +{else} +{assign var="value" value={{sugarvar key='value' string=true}} } +{/if} + diff --git a/include/SugarFields/Fields/Currency/ListView.tpl b/include/SugarFields/Fields/Currency/ListView.tpl new file mode 100644 index 00000000..b86508ee --- /dev/null +++ b/include/SugarFields/Fields/Currency/ListView.tpl @@ -0,0 +1,43 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} +{sugar_fetch object=$parentFieldArray key=$col assign='amount'} +{if stripos(strtoupper($col), '_USD') || empty($currency_id)} +{sugar_currency_format var=$amount} +{else} +{sugar_currency_format var=$amount currency_id=$currency_id} +{/if} diff --git a/include/SugarFields/Fields/Currency/SugarFieldCurrency.php b/include/SugarFields/Fields/Currency/SugarFieldCurrency.php new file mode 100644 index 00000000..acb2fbe9 --- /dev/null +++ b/include/SugarFields/Fields/Currency/SugarFieldCurrency.php @@ -0,0 +1,76 @@ +setup($parentFieldArray, $vardef, $displayParams, $tabindex, false); + + $this->ss->left_delimiter = '{'; + $this->ss->right_delimiter = '}'; + $this->ss->assign('col',strtoupper($vardef['name'])); + if(is_object($parentFieldArray) ){ + if(!empty($parentFieldArray->currency_id)) { + $this->ss->assign('currency_id',$parentFieldArray->currency_id); + } + } else if (!empty($parentFieldArray['CURRENCY_ID'])) { + $this->ss->assign('currency_id',$parentFieldArray['CURRENCY_ID']); + } else if (!empty($parentFieldArray['currency_id'])) { + $this->ss->assign('currency_id',$parentFieldArray['currency_id']); + } + return $this->fetch($this->findTemplate('ListView')); + } + + /** + * @see SugarFieldBase::importSanitize() + */ + public function importSanitize( + $value, + $vardef, + $focus, + ImportFieldSanitize $settings + ) + { + $value = str_replace($settings->currency_symbol,"",$value); + + return $settings->float($value,$vardef,$focus); + } +} \ No newline at end of file diff --git a/include/SugarFields/Fields/Datetime/EditView.tpl b/include/SugarFields/Fields/Datetime/EditView.tpl new file mode 100644 index 00000000..601d601b --- /dev/null +++ b/include/SugarFields/Fields/Datetime/EditView.tpl @@ -0,0 +1,66 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} +{{capture name=idname assign=idname}}{{sugarvar key='name'}}{{/capture}} +{{if !empty($displayParams.idName)}} + {{assign var=idname value=$displayParams.idName}} +{{/if}} + +{assign var=date_value value={{sugarvar key='value' string=true}} } + +{{if !$displayParams.hiddeCalendar}} +{$APP.LBL_ENTER_DATE} +{{/if}} +{{if $displayParams.showFormats}} + ({$USER_DATEFORMAT}) +{{/if}} + +{{if !$displayParams.hiddeCalendar}} + +{{/if}} \ No newline at end of file diff --git a/include/SugarFields/Fields/Datetime/SugarFieldDatetime.php b/include/SugarFields/Fields/Datetime/SugarFieldDatetime.php new file mode 100644 index 00000000..6f969785 --- /dev/null +++ b/include/SugarFields/Fields/Datetime/SugarFieldDatetime.php @@ -0,0 +1,181 @@ +setup($parentFieldArray, $vardef, $displayParams, $tabindex); + //jchi , bug #24557 , 10/31/2008 + if(isset($vardef['name']) && ($vardef['name'] == 'date_entered' || $vardef['name'] == 'date_modified')){ + return $this->fetch($this->findTemplate('DetailView')); + } + //end + return $this->fetch($this->findTemplate('EditView')); + } + + function getImportViewSmarty($parentFieldArray, $vardef, $displayParams, $tabindex) + { + $displayParams['showMinutesDropdown'] = false; + $displayParams['showHoursDropdown'] = false; + $displayParams['showNoneCheckbox'] = false; + $displayParams['showFormats'] = true; + $displayParams['hiddeCalendar'] = false; + + $this->setup($parentFieldArray, $vardef, $displayParams, $tabindex); + return $this->fetch($this->findTemplate('EditView')); + } + + + function getSearchViewSmarty($parentFieldArray, $vardef, $displayParams, $tabindex) { + if($this->isRangeSearchView($vardef)) { + $this->setup($parentFieldArray, $vardef, $displayParams, $tabindex); + $id = isset($displayParams['idName']) ? $displayParams['idName'] : $vardef['name']; + $this->ss->assign('original_id', "{$id}"); + $this->ss->assign('id_range', "range_{$id}"); + $this->ss->assign('id_range_start', "start_range_{$id}"); + $this->ss->assign('id_range_end', "end_range_{$id}"); + $this->ss->assign('id_range_choice', "{$id}_range_choice"); + if(file_exists('custom/include/SugarFields/Fields/Datetimecombo/RangeSearchForm.tpl')) + { + return $this->fetch('custom/include/SugarFields/Fields/Datetimecombo/RangeSearchForm.tpl'); + } + return $this->fetch('include/SugarFields/Fields/Datetimecombo/RangeSearchForm.tpl'); + } + return $this->getSmartyView($parentFieldArray, $vardef, $displayParams, $tabindex, 'EditView'); + } + + public function getEmailTemplateValue($inputField, $vardef, $context = null){ + global $timedate; + // This does not return a smarty section, instead it returns a direct value + if(isset($context['notify_user'])) { + $user = $context['notify_user']; + } else { + $user = $GLOBALS['current_user']; + } + if($vardef['type'] == 'date') { + // convert without TZ + return $timedate->to_display($inputField, $timedate->get_db_date_format(), $timedate->get_date_format($user)); + } else { + return $timedate->to_display_date_time($inputField, true, true, $user); + } + } + + public function save($bean, $inputData, $field, $def, $prefix = '') { + global $timedate; + if ( !isset($inputData[$prefix.$field]) ) { + return; + } + + $offset = strlen(trim($inputData[$prefix.$field])) < 11 ? false : true; + $bean->$field = $timedate->to_db_date($inputData[$prefix.$field], $offset); + } + + /** + * @see SugarFieldBase::importSanitize() + */ + public function importSanitize( + $value, + $vardef, + $focus, + ImportFieldSanitize $settings + ) + { + global $timedate; + + $format = $timedate->merge_date_time($settings->dateformat, $settings->timeformat); + + if ( !$timedate->check_matching_format($value, $format) ) { + $parts = $timedate->split_date_time($value); + if(empty($parts[0])) { + $datepart = $timedate->getNow()->format($settings->dateformat); + } + else { + $datepart = $parts[0]; + } + if(empty($parts[1])) { + $timepart = $timedate->fromTimestamp(0)->format($settings->timeformat); + } else { + $timepart = $parts[1]; + // see if we can get by stripping the seconds + if(strpos($settings->timeformat, 's') === false) { + $sep = $timedate->timeSeparatorFormat($settings->timeformat); + // We are assuming here seconds are the last component, which + // is kind of reasonable - no sane time format puts seconds first + $timeparts = explode($sep, $timepart); + if(!empty($timeparts[2])) { + $timepart = join($sep, array($timeparts[0], $timeparts[1])); + } + } + } + + $value = $timedate->merge_date_time($datepart, $timepart); + if ( !$timedate->check_matching_format($value, $format) ) { + return false; + } + } + + try { + $date = SugarDateTime::createFromFormat($format, $value, new DateTimeZone($settings->timezone)); + } catch(Exception $e) { + return false; + } + return $date->asDb(); + } +} diff --git a/include/SugarFields/Fields/Datetimecombo/Datetimecombo.js b/include/SugarFields/Fields/Datetimecombo/Datetimecombo.js new file mode 100644 index 00000000..65888e21 --- /dev/null +++ b/include/SugarFields/Fields/Datetimecombo/Datetimecombo.js @@ -0,0 +1,51 @@ +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ +function Datetimecombo(datetime,field,timeformat,tabindex,showCheckbox,checked,allowEmptyHM){this.datetime=datetime;this.allowEmptyHM=allowEmptyHM;if(typeof this.datetime=="undefined"||datetime==''||trim(datetime).length<10){this.datetime='';var d=new Date();var month=d.getMonth();var date=d.getDate();var year=d.getYear();var hours=d.getHours();var minutes=d.getMinutes();} +this.fieldname=field;if(datetime!='') +{parts=datetime.split(' ');this.hrs=parseInt(parts[1].substring(0,2),10);this.mins=parseInt(parts[1].substring(3,5),10);} +if(this.mins>0&&this.mins<15){this.mins=15;}else if(this.mins>15&&this.mins<30){this.mins=30;}else if(this.mins>30&&this.mins<45){this.mins=45;}else if(this.mins>45){this.hrs+=1;this.mins=0;} +this.timeformat=timeformat;this.tabindex=tabindex==null||isNaN(tabindex)?1:tabindex;this.timeseparator=this.timeformat.substring(2,3);this.has12Hours=/^11/.test(this.timeformat);this.hasMeridiem=/am|pm/i.test(this.timeformat);if(this.hasMeridiem){this.pm=/pm/.test(this.timeformat);} +this.meridiem=this.hasMeridiem?trim(this.datetime.substring(16)):'';this.datetime=this.datetime.substr(0,10);this.showCheckbox=showCheckbox;this.checked=parseInt(checked);document.getElementById(this.fieldname+'_date').value=this.datetime;} +Datetimecombo.prototype.jsscript=function(callback){text='\nfunction update_'+this.fieldname+'(calendar) {';text+='\nd = document.getElementById("'+this.fieldname+'_date").value;';text+='\nh = document.getElementById("'+this.fieldname+'_hours").value;';text+='\nm = document.getElementById("'+this.fieldname+'_minutes").value;';text+='\nnewdate = d + " " + h + "'+this.timeseparator+'" + m;';if(this.hasMeridiem){text+='\nif(typeof document.getElementById("'+this.fieldname+'_meridiem") != "undefined") {';text+='\n newdate += document.getElementById("'+this.fieldname+'_meridiem").value;';text+='\n}';} +text+='\nif(trim(newdate) =="'+this.timeseparator+'") newdate="";';text+='\ndocument.getElementById("'+this.fieldname+'").value = newdate;';text+='\n'+callback;text+='\n}';return text;} +Datetimecombo.prototype.html=function(callback){var text=' ';text+=this.timeseparator;text+='\n ';if(this.hasMeridiem){text+='\n ';text+='\n';} +if(this.showCheckbox){text+='\n';} +return text;};Datetimecombo.prototype.update=function(){id=this.fieldname+'_date';d=window.document.getElementById(id).value;id=this.fieldname+'_hours';h=window.document.getElementById(id).value;id=this.fieldname+'_minutes';m=window.document.getElementById(id).value;newdate=d+' '+h+this.timeseparator+m;if(this.hasMeridiem){ampm=document.getElementById(this.fieldname+"_meridiem").value;newdate+=ampm;} +if(trim(newdate)==""+this.timeseparator+""){newdate='';} +document.getElementById(this.fieldname).value=newdate;SUGAR.util.callOnChangeListers(this.fieldname);if(this.showCheckbox){flag=this.fieldname+'_flag';date=this.fieldname+'_date';hours=this.fieldname+'_hours';mins=this.fieldname+'_minutes';if(document.getElementById(flag).checked){document.getElementById(flag).value=1;document.getElementById(this.fieldname).value='';document.getElementById(date).disabled=true;document.getElementById(hours).disabled=true;document.getElementById(mins).disabled=true;}else{document.getElementById(flag).value=0;document.getElementById(date).disabled=false;document.getElementById(hours).disabled=false;document.getElementById(mins).disabled=false;}}}; \ No newline at end of file diff --git a/include/SugarFields/Fields/Datetimecombo/EditView.tpl b/include/SugarFields/Fields/Datetimecombo/EditView.tpl new file mode 100644 index 00000000..e94e6bf3 --- /dev/null +++ b/include/SugarFields/Fields/Datetimecombo/EditView.tpl @@ -0,0 +1,118 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} +{{capture name=idname assign=idname}}{{sugarvar key='name'}}{{/capture}} +{{if !empty($displayParams.idName)}} + {{assign var=idname value=$displayParams.idName}} +{{/if}} + +{{assign var=flag_field value=$vardef.name|cat:_flag}} + + + + + +{{if $displayParams.showFormats}} + + + + +{{/if}} +
+ +{$APP.LBL_ENTER_DATE}  +{{if empty($displayParams.splitDateTime)}} + +{{else}} +
+{{/if}} +
+{{if $displayParams.showNoneCheckbox}} + +{{/if}} +
+{$USER_DATEFORMAT} + +{$TIME_FORMAT} +
+ + + \ No newline at end of file diff --git a/include/SugarFields/Fields/Datetimecombo/RangeSearchForm.tpl b/include/SugarFields/Fields/Datetimecombo/RangeSearchForm.tpl new file mode 100644 index 00000000..476a227f --- /dev/null +++ b/include/SugarFields/Fields/Datetimecombo/RangeSearchForm.tpl @@ -0,0 +1,167 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} +{{if empty($displayParams.idName)}} +{assign var="id" value={{sugarvar key='name' string=true}} } +{{else}} +{assign var="id" value={{$displayParams.idName}} } +{{/if}} + +{if isset($smarty.request.{{$id_range_choice}})} +{assign var="starting_choice" value=$smarty.request.{{$id_range_choice}}} +{else} +{assign var="starting_choice" value="="} +{/if} + +
+ +
+ +
+ +{{if !$displayParams.hiddeCalendar}} +{$APP.LBL_ENTER_DATE} +{{/if}} +{{if $displayParams.showFormats}} + ({$USER_DATEFORMAT}) +{{/if}} +{{if !$displayParams.hiddeCalendar}} + +{{/if}} +
+ +
+{assign var=date_value value={{sugarvar key='value' string=true}} } + +{{if !$displayParams.hiddeCalendar}} +{$APP.LBL_ENTER_DATE} +{{/if}} +{{if $displayParams.showFormats}} + ({$USER_DATEFORMAT}) +{{/if}} +{{if !$displayParams.hiddeCalendar}} + +{{/if}} +{$APP.LBL_AND} +{assign var=date_value value={{sugarvar key='value' string=true}} } + +{{if !$displayParams.hiddeCalendar}} +{$APP.LBL_ENTER_DATE} +{{/if}} +{{if $displayParams.showFormats}} + ({$USER_DATEFORMAT}) +{{/if}} +{{if !$displayParams.hiddeCalendar}} + +{{/if}} +
+ + + \ No newline at end of file diff --git a/include/SugarFields/Fields/Datetimecombo/SearchView.tpl b/include/SugarFields/Fields/Datetimecombo/SearchView.tpl new file mode 100644 index 00000000..b15552a3 --- /dev/null +++ b/include/SugarFields/Fields/Datetimecombo/SearchView.tpl @@ -0,0 +1,111 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} + + + + + +{{if $displayParams.showFormats}} + + + + +{{/if}} +
+ +{$APP.LBL_ENTER_DATE}  +{{if empty($displayParams.splitDateTime)}} + +{{else}} +
+{{/if}} +
+{{if $displayParams.showNoneCheckbox}} + +{{/if}} +
+{$USER_DATEFORMAT} + +{$TIME_FORMAT} +
+ + + + + diff --git a/include/SugarFields/Fields/Datetimecombo/SugarFieldDatetimecombo.php b/include/SugarFields/Fields/Datetimecombo/SugarFieldDatetimecombo.php new file mode 100644 index 00000000..559552a8 --- /dev/null +++ b/include/SugarFields/Fields/Datetimecombo/SugarFieldDatetimecombo.php @@ -0,0 +1,150 @@ +get_cal_date_format(); + + $displayParams['timeFormat'] = $timedate->get_user_time_format(); + $this->setup($parentFieldArray, $vardef, $displayParams, $tabindex); + return $this->fetch($this->findTemplate('EditView')); + } + + function getImportViewSmarty($parentFieldArray, $vardef, $displayParams, $tabindex) + { + $displayParams['showFormats'] = true; + return $this->getEditViewSmarty($parentFieldArray, $vardef, $displayParams, $tabindex); + } + + function getSearchViewSmarty($parentFieldArray, $vardef, $displayParams, $tabindex) { + + if($this->isRangeSearchView($vardef)) { + $displayParams['showMinutesDropdown'] = false; + $displayParams['showHoursDropdown'] = false; + $displayParams['showNoneCheckbox'] = false; + $displayParams['showFormats'] = false; + global $timedate, $current_language; + $displayParams['dateFormat'] = $timedate->get_cal_date_format(); + $displayParams['timeFormat'] = $timedate->get_user_time_format(); + + $this->setup($parentFieldArray, $vardef, $displayParams, $tabindex); + $id = isset($displayParams['idName']) ? $displayParams['idName'] : $vardef['name']; + $this->ss->assign('original_id', "{$id}"); + $this->ss->assign('id_range', "range_{$id}"); + $this->ss->assign('id_range_start', "start_range_{$id}"); + $this->ss->assign('id_range_end', "end_range_{$id}"); + $this->ss->assign('id_range_choice', "{$id}_range_choice"); + if(file_exists('custom/include/SugarFields/Fields/Datetimecombo/RangeSearchForm.tpl')) + { + return $this->fetch('custom/include/SugarFields/Fields/Datetimecombo/RangeSearchForm.tpl'); + } + return $this->fetch('include/SugarFields/Fields/Datetimecombo/RangeSearchForm.tpl'); + } + + // Create Smarty variables for the Calendar picker widget + if(!isset($displayParams['showMinutesDropdown'])) { + $displayParams['showMinutesDropdown'] = false; + } + + if(!isset($displayParams['showHoursDropdown'])) { + $displayParams['showHoursDropdown'] = false; + } + + if(!isset($displayParams['showNoneCheckbox'])) { + $displayParams['showNoneCheckbox'] = false; + } + + if(!isset($displayParams['showFormats'])) { + $displayParams['showFormats'] = false; + } + + global $timedate; + $displayParams['dateFormat'] = $timedate->get_cal_date_format(); + + $displayParams['timeFormat'] = $timedate->get_user_time_format(); + $this->setup($parentFieldArray, $vardef, $displayParams, $tabindex); + return $this->fetch($this->findTemplate('SearchView')); + } + + + public function getEmailTemplateValue($inputField, $vardef, $context = null, $tabindex = 0){ + // This does not return a smarty section, instead it returns a direct value + if(isset($context['notify_user'])) { + $user = $context['notify_user']; + } else { + $user = $GLOBALS['current_user']; + } + return TimeDate::getInstance()->to_display_date_time($inputField, true, true, $user); + } + + public function save(&$bean, &$inputData, &$field, &$def, $prefix = '') { + global $timedate; + if ( !isset($inputData[$prefix.$field]) ) { + //$bean->$field = ''; + return; + } + + if(strpos($inputData[$prefix.$field], ' ') > 0) { + $bean->$field = $timedate->to_db($inputData[$prefix.$field]); + } else { + $GLOBALS['log']->error('Field ' . $prefix.$field . ' expecting datetime format, but got value: ' . $inputData[$prefix.$field]); + //Default to assume date format value + $bean->$field = $timedate->to_db_date($inputData[$prefix.$field]); + } + } +} +?> \ No newline at end of file diff --git a/include/SugarFields/Fields/Download/DetailView.tpl b/include/SugarFields/Fields/Download/DetailView.tpl new file mode 100644 index 00000000..dca9373e --- /dev/null +++ b/include/SugarFields/Fields/Download/DetailView.tpl @@ -0,0 +1,46 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} + +{$fields.filename.value} + +{{if !empty($displayParams.enableConnectors)}} +{if !empty($fields.filename.value)} +{{sugarvar_connector view='DetailView'}} +{/if} +{{/if}} + diff --git a/include/SugarFields/Fields/Download/SugarFieldDownload.php b/include/SugarFields/Fields/Download/SugarFieldDownload.php new file mode 100644 index 00000000..4ffa538e --- /dev/null +++ b/include/SugarFields/Fields/Download/SugarFieldDownload.php @@ -0,0 +1,48 @@ +setup($parentFieldArray, $vardef, $displayParams, $tabindex); + return $this->fetch($this->findTemplate('DetailView.tpl')); + } +} +?> \ No newline at end of file diff --git a/include/SugarFields/Fields/Enum/DetailView.tpl b/include/SugarFields/Fields/Enum/DetailView.tpl new file mode 100644 index 00000000..a0679161 --- /dev/null +++ b/include/SugarFields/Fields/Enum/DetailView.tpl @@ -0,0 +1,49 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} +{* This is here so currency fields, who don't really have dropdown +lists can work. *} +{if is_string({{sugarvar key='options' string=true}})} + +{ {{sugarvar key='options' string=true}} } +{else} + +{ {{sugarvar key='options' string=true}}[{{sugarvar key='value' string=true}}]} +{/if} +{{if !empty($displayParams.enableConnectors)}} +{{sugarvar_connector view='DetailView'}} +{{/if}} \ No newline at end of file diff --git a/include/SugarFields/Fields/Enum/DetailViewFunction.tpl b/include/SugarFields/Fields/Enum/DetailViewFunction.tpl new file mode 100644 index 00000000..8dcb5ebf --- /dev/null +++ b/include/SugarFields/Fields/Enum/DetailViewFunction.tpl @@ -0,0 +1,41 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} +{{sugarvar key='value'}} +{{if !empty($displayParams.enableConnectors)}} +{{sugarvar_connector view='DetailView'}} +{{/if}} \ No newline at end of file diff --git a/include/SugarFields/Fields/Enum/EditView.tpl b/include/SugarFields/Fields/Enum/EditView.tpl new file mode 100644 index 00000000..012fedda --- /dev/null +++ b/include/SugarFields/Fields/Enum/EditView.tpl @@ -0,0 +1,49 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} + + diff --git a/include/SugarFields/Fields/Enum/EditViewFunction.tpl b/include/SugarFields/Fields/Enum/EditViewFunction.tpl new file mode 100644 index 00000000..ebe9a8ea --- /dev/null +++ b/include/SugarFields/Fields/Enum/EditViewFunction.tpl @@ -0,0 +1,42 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} + \ No newline at end of file diff --git a/include/SugarFields/Fields/Enum/SearchView.tpl b/include/SugarFields/Fields/Enum/SearchView.tpl new file mode 100644 index 00000000..783359f1 --- /dev/null +++ b/include/SugarFields/Fields/Enum/SearchView.tpl @@ -0,0 +1,39 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} +{{capture name=display_size assign=size}}{{$displayParams.size|default:6}}{{/capture}} +{html_options name='{{$vardef.name}}[]' options={{sugarvar key='options' string=true}} size="{{$size}}" style="width: 150px" {{if $size > 1}}multiple="1"{{/if}} selected={{sugarvar key='value' string=true}}} diff --git a/include/SugarFields/Fields/Enum/SugarFieldEnum.php b/include/SugarFields/Fields/Enum/SugarFieldEnum.php new file mode 100644 index 00000000..dbdde32a --- /dev/null +++ b/include/SugarFields/Fields/Enum/SugarFieldEnum.php @@ -0,0 +1,147 @@ +setup($parentFieldArray, $vardef, $displayParams, $tabindex); + return "" . $this->fetch($this->findTemplate('DetailViewFunction')) . ""; + } else { + return parent::getDetailViewSmarty($parentFieldArray, $vardef, $displayParams, $tabindex); + } + } + + function getEditViewSmarty($parentFieldArray, $vardef, $displayParams, $tabindex) { + + if(empty($displayParams['size'])) { + $displayParams['size'] = 6; + } + + if(isset($vardef['function']) && !empty($vardef['function']['returns']) && $vardef['function']['returns']== 'html'){ + $this->setup($parentFieldArray, $vardef, $displayParams, $tabindex); + return $this->fetch($this->findTemplate('EditViewFunction')); + }else{ + return parent::getEditViewSmarty($parentFieldArray, $vardef, $displayParams, $tabindex); + } + } + + + + function getSearchViewSmarty($parentFieldArray, $vardef, $displayParams, $tabindex) { + + if(empty($displayParams['size'])) { + $displayParams['size'] = 6; + } + + if(!empty($vardef['function']['returns']) && $vardef['function']['returns']== 'html'){ + $this->setup($parentFieldArray, $vardef, $displayParams, $tabindex); + return $this->fetch($this->findTemplate('EditViewFunction')); + }else{ + $this->setup($parentFieldArray, $vardef, $displayParams, $tabindex); + return $this->fetch($this->findTemplate('SearchView')); + } + } + + + function displayFromFunc( $displayType, $parentFieldArray, $vardef, $displayParams, $tabindex ) { + if ( isset($vardef['function']['returns']) && $vardef['function']['returns'] == 'html' ) { + return parent::displayFromFunc($displayType, $parentFieldArray, $vardef, $displayParams, $tabindex); + } + + $displayTypeFunc = 'get'.$displayType.'Smarty'; + return $this->$displayTypeFunc($parentFieldArray, $vardef, $displayParams, $tabindex); + } + + /** + * @see SugarFieldBase::importSanitize() + */ + public function importSanitize( + $value, + $vardef, + $focus, + ImportFieldSanitize $settings + ) + { + global $app_list_strings; + + // Bug 27467 - Trim the value given + $value = trim($value); + + if ( isset($app_list_strings[$vardef['options']]) + && !isset($app_list_strings[$vardef['options']][$value]) ) { + // Bug 23485/23198 - Check to see if the value passed matches the display value + if ( in_array($value,$app_list_strings[$vardef['options']]) ) + $value = array_search($value,$app_list_strings[$vardef['options']]); + // Bug 33328 - Check for a matching key in a different case + elseif ( in_array(strtolower($value), array_keys(array_change_key_case($app_list_strings[$vardef['options']]))) ) { + foreach ( $app_list_strings[$vardef['options']] as $optionkey => $optionvalue ) + if ( strtolower($value) == strtolower($optionkey) ) + $value = $optionkey; + } + // Bug 33328 - Check for a matching value in a different case + elseif ( in_array(strtolower($value), array_map('strtolower', $app_list_strings[$vardef['options']])) ) { + foreach ( $app_list_strings[$vardef['options']] as $optionkey => $optionvalue ) + if ( strtolower($value) == strtolower($optionvalue) ) + $value = $optionkey; + } + else + return false; + } + + return $value; + } + + public function formatField($rawField, $vardef){ + global $app_list_strings; + + if(!empty($vardef['options'])){ + $option_array_name = $vardef['options']; + + if(!empty($app_list_strings[$option_array_name][$rawField])){ + return $app_list_strings[$option_array_name][$rawField]; + }else { + return $rawField; + } + } else { + return $rawField; + } + } +} +?> \ No newline at end of file diff --git a/include/SugarFields/Fields/File/DetailView.tpl b/include/SugarFields/Fields/File/DetailView.tpl new file mode 100644 index 00000000..59e15e4e --- /dev/null +++ b/include/SugarFields/Fields/File/DetailView.tpl @@ -0,0 +1,51 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} + +{{sugarvar key='value'}} + +{{if isset($vardef) && isset($vardef.allowEapm) && $vardef.allowEapm}} +{if isset($fields.{{$vardef.docType}}) && !empty($fields.{{$vardef.docType}}.value) && $fields.{{$vardef.docType}}.value != 'SugarCRM' && !empty($fields.{{$vardef.docUrl}}.value) } +{capture name=imageNameCapture assign=imageName} +{$fields.{{$vardef.docType}}.value}_image_inline.png +{/capture} + +{/if} +{{/if}} +{{if !empty($displayParams.enableConnectors)}} +{{sugarvar_connector view='DetailView'}} +{{/if}} diff --git a/include/SugarFields/Fields/File/EditView.tpl b/include/SugarFields/Fields/File/EditView.tpl new file mode 100644 index 00000000..17218505 --- /dev/null +++ b/include/SugarFields/Fields/File/EditView.tpl @@ -0,0 +1,221 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} +{{if isset($vardef.allowEapm) && $vardef.allowEapm}} + +{{/if}} + +{{capture name=idName assign=idName}}{{sugarvar key='name'}}{{/capture}} +{{if !empty($displayParams.idName)}} + {{assign var=idName value=$displayParams.idName}} +{{/if}} + +{{if !isset($vardef.noRemove) || !$vardef.noRemove}} +{if !empty({{sugarvar key='value' stringFormat=true}}) } + {assign var=showRemove value=true} +{else} + {assign var=showRemove value=false} +{/if} +{{else}} + {assign var=showRemove value=false} +{{/if}} + +{{if isset($vardef.noChange) && $vardef.noChange }} +{if !empty({{sugarvar key='value' stringFormat=true}}) } + {assign var=showRemove value=true} + {assign var=noChange value=true} +{else} + {assign var=noChange value=false} +{/if} +{{else}} + {assign var=noChange value=false} +{{/if}} + + + +{{if isset($vardef.allowEapm) && $vardef.allowEapm}} + + + +{{/if}} + + {{sugarvar key='value'}} + +{{if isset($vardef.allowEapm) && $vardef.allowEapm}} +{if isset($fields.{{$vardef.docType}}) && !empty($fields.{{$vardef.docType}}.value) && $fields.{{$vardef.docType}}.value != 'Sugar' && !empty($fields.{{$vardef.docUrl}}.value) } +{capture name=imageNameCapture assign=imageName} +{$fields.{{$vardef.docType}}.value}_image_inline.png +{/capture} + +{/if} +{{/if}} +{if !$noChange} + +{/if} + +{if !$noChange} + + + + + +{{if isset($vardef.allowEapm) && $vardef.allowEapm}} + \ No newline at end of file diff --git a/include/SugarFields/Fields/File/ListView.tpl b/include/SugarFields/Fields/File/ListView.tpl new file mode 100644 index 00000000..daa15eac --- /dev/null +++ b/include/SugarFields/Fields/File/ListView.tpl @@ -0,0 +1,45 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} +{sugar_fetch object=$parentFieldArray key=$col} +{if isset($vardef.allowEapm) && $vardef.allowEapm && isset($parentFieldArray.DOC_TYPE) } +{capture name=imageNameCapture assign=imageName} +{sugar_fetch object=$parentFieldArray key=DOC_TYPE}_image_inline.png +{/capture} + +{/if} + \ No newline at end of file diff --git a/include/SugarFields/Fields/File/SearchView.tpl b/include/SugarFields/Fields/File/SearchView.tpl new file mode 100644 index 00000000..4ca8e409 --- /dev/null +++ b/include/SugarFields/Fields/File/SearchView.tpl @@ -0,0 +1,39 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} + + diff --git a/include/SugarFields/Fields/File/SugarFieldFile.js b/include/SugarFields/Fields/File/SugarFieldFile.js new file mode 100644 index 00000000..55d23f3c --- /dev/null +++ b/include/SugarFields/Fields/File/SugarFieldFile.js @@ -0,0 +1,45 @@ +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ +if(typeof(SUGAR.field)=='undefined'){SUGAR.field=new Object();} +if(typeof(SUGAR.field.file)=='undefined'){SUGAR.field.file={deleteAttachment:function(elemBaseName,docTypeName,elem){ajaxStatus.showStatus(SUGAR.language.get("Notes","LBL_REMOVING_ATTACHMENT"));elem.form.deleteAttachment.value=1;elem.form.action.value="EditView";SUGAR.dashlets.postForm(elem.form,SUGAR.field.file.deleteAttachmentCallbackGen(elemBaseName,docTypeName));elem.form.deleteAttachment.value=0;elem.form.action.value="";},deleteAttachmentCallbackGen:function(elemBaseName,docTypeName){return function(text){if(text=='true'){document.getElementById(elemBaseName+'_new').style.display='';ajaxStatus.hideStatus();document.getElementById(elemBaseName+'_old').innerHTML='';document.getElementById(docTypeName).disabled=false;document.getElementById(elemBaseName).value='';}else{document.getElementById(elemBaseName+'_new').style.display='none';ajaxStatus.flashStatus(SUGAR.language.get('Notes','ERR_REMOVING_ATTACHMENT'),2000);}}},checkEapiLogin:function(res){var failedLogins=JSON.parse(res.responseText);if(failedLogins.length==0){return;} +for(var idx in failedLogins){if(confirm(failedLogins[idx].label)){window.open(failedLogins[idx].checkURL,'EAPM_CHECK_'+idx);}else{document.getElementById(res.argument.docTypeName).value='Sugar';document.getElementById(res.argument.docTypeName).onchange();}}},setupEapiShowHide:function(elemBaseName,docTypeName,formName){var externalSearchToggle=function(){var moreElem=document.getElementById(elemBaseName+"_more");var hideMore=(moreElem.style.display=='none');if(hideMore){moreElem.style.display='';document.getElementById(elemBaseName+'_less').style.display='none';document.getElementById(elemBaseName+'_remoteNameSpan').style.display='none';document.getElementById(elemBaseName+'_file').disabled=false;}else{moreElem.style.display='none';document.getElementById(elemBaseName+'_less').style.display='';document.getElementById(elemBaseName+'_remoteNameSpan').style.display='';document.getElementById(elemBaseName+'_file').disabled=true;}} +var showHideFunc=function(){var docShowHideElem=document.getElementById(elemBaseName+"_externalApiSelector");var dropdownValue=document.getElementById(docTypeName).value;if(typeof(SUGAR.eapm)!='undefined'&&typeof(SUGAR.eapm[dropdownValue])!='undefined'&&typeof(SUGAR.eapm[dropdownValue].docSearch)!='undefined'&&SUGAR.eapm[dropdownValue].docSearch){docShowHideElem.style.display='';YAHOO.util.Connect.asyncRequest('GET','index.php?module=EAPM&action=CheckLogins&to_pdf=1&api='+dropdownValue,{success:SUGAR.field.file.checkEapiLogin,argument:{'elemBaseName':elemBaseName,'docTypeName':docTypeName}});YAHOO.util.Connect.asyncRequest('GET','index.php?module=EAPM&action=flushFileCache&to_pdf=1&api='+dropdownValue,{});}else{docShowHideElem.style.display='none';document.getElementById(elemBaseName+'_file').disabled=false;} +sqs_objects[formName+"_"+elemBaseName+"_remoteName"].api=dropdownValue;var secLevelBoxElem=document.getElementById(elemBaseName+'_securityLevelBox');var secLevelElem=document.getElementById(elemBaseName+'_securityLevel');secLevelElem.options.length=0;if(SUGAR.eapm[dropdownValue]&&SUGAR.eapm[dropdownValue].sharingOptions){var opts=SUGAR.eapm[dropdownValue].sharingOptions;var i=0;for(idx in opts){secLevelElem.options[i]=new Option(SUGAR.language.get('app_strings',opts[idx]),idx,false,false);i++;} +secLevelBoxElem.style.display='';}else{secLevelBoxElem.style.display='none';}} +document.getElementById(docTypeName).onchange=showHideFunc;document.getElementById(elemBaseName+'_externalApiLabel').onclick=externalSearchToggle;showHideFunc();},openPopup:function(elemBaseName){window.open('index.php?module=Documents&action=extdoc&isPopup=1&elemBaseName='+elemBaseName+'&apiName='+document.getElementById('doc_type').value,'sugarPopup','width=600,height=400,menubar=no,toolbar=no,status=no,resizeable=yes,scrollbars=yes');},clearRemote:function(elemBaseName){document.getElementById('doc_id').value='';document.getElementById(elemBaseName).value='';document.getElementById(elemBaseName+'_remoteName').value='';document.getElementById('doc_url').value='';},populateFromPopup:function(elemBaseName,docId,docName,docUrl,docDirectUrl){document.getElementById('doc_id').value=docId;document.getElementById(elemBaseName).value=docId;document.getElementById(elemBaseName+'_remoteName').value=docName;document.getElementById('doc_url').value=docUrl;},getFileExtension:function(fileName){var lastindex=fileName.lastIndexOf(".");if(lastindex==-1) +return false;else +return fileName.substr(++lastindex);},isFileExtensionValid:function(fileName){var docType=document.getElementById('doc_type').value;var fileExtension=this.getFileExtension(fileName);if(typeof(SUGAR.eapm[docType])=='undefined'||!fileExtension||!SUGAR.eapm[docType].restrictUploadsByExtension){return true;} +var whiteSuffixlist=SUGAR.eapm[docType]['restrictUploadsByExtension'];if(whiteSuffixlist.constructor==Array){var results=false;for(var i=0;ifillInOptions($vardef,$displayParams); + return parent::getDetailViewSmarty($parentFieldArray, $vardef, $displayParams, $tabindex); + } + + function getEditViewSmarty($parentFieldArray, $vardef, $displayParams, $tabindex) { + $this->fillInOptions($vardef,$displayParams); + return parent::getEditViewSmarty($parentFieldArray, $vardef, $displayParams, $tabindex); + } + + public function save(&$bean, $params, $field, $vardef, $prefix = ''){ + $fakeDisplayParams = array(); + $this->fillInOptions($vardef,$fakeDisplayParams); + + require_once('include/upload_file.php'); + $upload_file = new UploadFile($prefix . $field . '_file'); + + //remove file + if (isset($_REQUEST['remove_file_' . $field]) && $params['remove_file_' . $field] == 1) + { + $upload_file->unlink_file($bean->$field); + $bean->$field=""; + } + + $move=false; + if (isset($_FILES[$prefix . $field . '_file']) && $upload_file->confirm_upload()) + { + $bean->$field = $upload_file->get_stored_file_name(); + $bean->file_mime_type = $upload_file->mime_type; + $bean->file_ext = $upload_file->file_ext; + $move=true; + } + + if (isset($params['isDuplicate']) && $params['isDuplicate'] == true && $params['isDuplicate'] != 'false' ) { + // It's a duplicate + $old_id = $params['relate_id']; + } + + if (empty($bean->id)) { + $bean->id = create_guid(); + $bean->new_with_id = true; + } + + if ($move) { + $upload_file->final_move($bean->id); + $upload_file->upload_doc($bean, $bean->id, $params[$prefix . $vardef['docType']], $bean->$field, $upload_file->mime_type); + } else if ( ! empty($old_id) ) { + // It's a duplicate, I think + + if ( empty($params[$prefix . $vardef['docUrl'] ]) ) { + $upload_file->duplicate_file($old_id, $bean->id, $bean->$field); + } else { + $docType = $vardef['docType']; + $bean->$docType = $params[$prefix . $field . '_old_doctype']; + } + } else if ( !empty($params[$prefix . $field . '_remoteName']) ) { + // We ain't moving, we might need to do some remote linking + $displayParams = array(); + $this->fillInOptions($vardef,$displayParams); + + if ( isset($params[$prefix . $vardef['docId']]) + && ! empty($params[$prefix . $vardef['docId']]) + && isset($params[$prefix . $vardef['docType']]) + && ! empty($params[$prefix . $vardef['docType']]) + ) { + $bean->$field = $params[$prefix . $field . '_remoteName']; + + require_once('include/utils/file_utils.php'); + $extension = get_file_extension($bean->$field); + if(!empty($extension)) + { + $bean->file_ext = $extension; + $bean->file_mime_type = get_mime_content_type_from_filename($bean->$field); + } + } + } + + if ( empty($bean->$field) ) { + $GLOBALS['log']->fatal("The $field is empty, clearing out the lot"); + // Looks like we are emptying this out + $clearFields = array('docId', 'docType', 'docUrl', 'docDirectUrl'); + foreach ( $clearFields as $clearMe ) { + if ( ! isset($vardef[$clearMe]) ) { + continue; + } + $clearField = $vardef[$clearMe]; + $bean->$clearField = ''; + } + } + } +} diff --git a/include/SugarFields/Fields/Float/DetailView.tpl b/include/SugarFields/Fields/Float/DetailView.tpl new file mode 100644 index 00000000..a161078f --- /dev/null +++ b/include/SugarFields/Fields/Float/DetailView.tpl @@ -0,0 +1,43 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} + +{sugar_number_format var={{sugarvar key='value' stringFormat='false'}} {{if !empty($vardef.precision)}}precision={{$vardef.precision}}{{/if}} } + +{{if !empty($displayParams.enableConnectors)}} +{{sugarvar_connector view='DetailView'}} +{{/if}} \ No newline at end of file diff --git a/include/SugarFields/Fields/Float/EditView.tpl b/include/SugarFields/Fields/Float/EditView.tpl new file mode 100644 index 00000000..7ec53205 --- /dev/null +++ b/include/SugarFields/Fields/Float/EditView.tpl @@ -0,0 +1,49 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} +{if strlen({{sugarvar key='value' string=true}}) <= 0} +{assign var="value" value={{sugarvar key='default_value' string=true}} } +{else} +{assign var="value" value={{sugarvar key='value' string=true}} } +{/if} + diff --git a/include/SugarFields/Fields/Float/SugarFieldFloat.php b/include/SugarFields/Fields/Float/SugarFieldFloat.php new file mode 100644 index 00000000..469082b0 --- /dev/null +++ b/include/SugarFields/Fields/Float/SugarFieldFloat.php @@ -0,0 +1,85 @@ +num_grp_sep,"",$value); + $dec_sep = $settings->dec_sep; + if ( $dec_sep != '.' ) { + $value = str_replace($dec_sep,".",$value); + } + if ( !is_numeric($value) ) { + return false; + } + + return $value; + } +} diff --git a/include/SugarFields/Fields/Fullname/DetailView.tpl b/include/SugarFields/Fields/Fullname/DetailView.tpl new file mode 100644 index 00000000..1a259c9c --- /dev/null +++ b/include/SugarFields/Fields/Fullname/DetailView.tpl @@ -0,0 +1,58 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} +{if strlen({{sugarvar key='value' string=true}}) <= 0} +{assign var="value" value={{sugarvar key='default_value' string=true}} } +{else} +{assign var="value" value={{sugarvar key='value' string=true}} } +{/if} +
+{{sugarvar key='value'}} +   + + + + + + + +
+{{if !empty($displayParams.enableConnectors)}} +{if !empty($value)} +{{sugarvar_connector view='DetailView'}} +{/if} +{{/if}} \ No newline at end of file diff --git a/include/SugarFields/Fields/Fullname/SugarFieldFullname.php b/include/SugarFields/Fields/Fullname/SugarFieldFullname.php new file mode 100644 index 00000000..fcf476f2 --- /dev/null +++ b/include/SugarFields/Fields/Fullname/SugarFieldFullname.php @@ -0,0 +1,76 @@ +setup($parentFieldArray, $vardef, $displayParams, $tabindex); + return $this->fetch($this->findTemplate('DetailView')); + } + + /** + * @see SugarFieldBase::importSanitize() + */ + public function importSanitize( + $value, + $vardef, + $focus, + ImportFieldSanitize $settings + ) + { + if ( property_exists($focus,'first_name') && property_exists($focus,'last_name') ) { + $name_arr = preg_split('/\s+/',$value); + + if ( count($name_arr) == 1) { + $focus->last_name = $value; + } + else { + // figure out what comes first, the last name or first name + if ( strpos($settings->default_locale_name_format,'l') > strpos($settings->default_locale_name_format,'f') ) { + $focus->first_name = array_shift($name_arr); + $focus->last_name = join(' ',$name_arr); + } + else { + $focus->last_name = array_shift($name_arr); + $focus->first_name = join(' ',$name_arr); + } + } + } + } +} \ No newline at end of file diff --git a/include/SugarFields/Fields/Html/DetailView.tpl b/include/SugarFields/Fields/Html/DetailView.tpl new file mode 100644 index 00000000..467d2435 --- /dev/null +++ b/include/SugarFields/Fields/Html/DetailView.tpl @@ -0,0 +1,41 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} +{{$vardef.value}} +{{if !empty($displayParams.enableConnectors)}} +{{sugarvar_connector view='DetailView'}} +{{/if}} \ No newline at end of file diff --git a/include/SugarFields/Fields/Html/SugarFieldHtml.php b/include/SugarFields/Fields/Html/SugarFieldHtml.php new file mode 100644 index 00000000..2be725b6 --- /dev/null +++ b/include/SugarFields/Fields/Html/SugarFieldHtml.php @@ -0,0 +1,73 @@ +getVardefValue($vardef); + + $this->setup($parentFieldArray, $vardef, $displayParams, $tabindex); + return $this->fetch($this->findTemplate('DetailView')); + } + + function getEditViewSmarty($parentFieldArray, $vardef, $displayParams, $tabindex){ + $vardef['value'] = $this->getVardefValue($vardef); + + $this->setup($parentFieldArray, $vardef, $displayParams, $tabindex); + return $this->fetch($this->findTemplate('DetailView')); + } + + function getSearchViewSmarty($parentFieldArray, $vardef, $displayParams, $tabindex) { + $vardef['value'] = $this->getVardefValue($vardef); + + $this->setup($parentFieldArray, $vardef, $displayParams, $tabindex); + return $this->fetch($this->findTemplate('DetailView')); + } + + function getVardefValue($vardef){ + if(empty($vardef['value'])){ + if(!empty($vardef['default'])) + return from_html($vardef['default']); + elseif(!empty($vardef['default_value'])) + return from_html($vardef['default_value']); + } else { + return from_html($vardef['value']); + } + } +} +?> \ No newline at end of file diff --git a/include/SugarFields/Fields/Id/SugarFieldId.php b/include/SugarFields/Fields/Id/SugarFieldId.php new file mode 100644 index 00000000..0cb851f3 --- /dev/null +++ b/include/SugarFields/Fields/Id/SugarFieldId.php @@ -0,0 +1,58 @@ + 36 ) { + return false; + } + + return $value; + } +} +?> \ No newline at end of file diff --git a/include/SugarFields/Fields/Iframe/DetailView.tpl b/include/SugarFields/Fields/Iframe/DetailView.tpl new file mode 100644 index 00000000..b130220e --- /dev/null +++ b/include/SugarFields/Fields/Iframe/DetailView.tpl @@ -0,0 +1,49 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} +{capture name=getLink assign=link}{{sugarvar key='value'}}{/capture} +{{if $vardef.gen}} +{sugar_replace_vars subject='{{$vardef.default|replace:'{':'['|replace:'}':']'}}' assign='link'} +{{/if}} +{if !empty($link) && $link != "http://"} +{capture name=getStart assign=linkStart}{$link|substr:0:7}{/capture} + + +{/if} +{{if !empty($displayParams.enableConnectors)}} +{{sugarvar_connector view='DetailView'}} +{{/if}} \ No newline at end of file diff --git a/include/SugarFields/Fields/Iframe/EditView.tpl b/include/SugarFields/Fields/Iframe/EditView.tpl new file mode 100644 index 00000000..ee26db7e --- /dev/null +++ b/include/SugarFields/Fields/Iframe/EditView.tpl @@ -0,0 +1,49 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} +{{if !$vardef.gen}} + {if !empty({{sugarvar key='value' string=true}})} + + {else} + + {/if} +{{/if}} \ No newline at end of file diff --git a/include/SugarFields/Fields/Int/DetailView.tpl b/include/SugarFields/Fields/Int/DetailView.tpl new file mode 100644 index 00000000..73a8ea7f --- /dev/null +++ b/include/SugarFields/Fields/Int/DetailView.tpl @@ -0,0 +1,48 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} + +{{if $vardef.disable_num_format}} +{assign var="value" value={{sugarvar key='value' string=true}} } +{$value} +{{else}} +{sugar_number_format precision=0 var={{sugarvar key='value' stringFormat='false'}}} +{{/if}} + +{{if !empty($displayParams.enableConnectors)}} +{{sugarvar_connector view='DetailView'}} +{{/if}} diff --git a/include/SugarFields/Fields/Int/EditView.tpl b/include/SugarFields/Fields/Int/EditView.tpl new file mode 100644 index 00000000..f924ea71 --- /dev/null +++ b/include/SugarFields/Fields/Int/EditView.tpl @@ -0,0 +1,44 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} +{if strlen({{sugarvar key='value' string=true}}) <= 0} +{assign var="value" value={{sugarvar key='default_value' string=true}} } +{else} +{assign var="value" value={{sugarvar key='value' string=true}} } +{/if} + diff --git a/include/SugarFields/Fields/Int/RangeSearchForm.tpl b/include/SugarFields/Fields/Int/RangeSearchForm.tpl new file mode 100644 index 00000000..f98ff25e --- /dev/null +++ b/include/SugarFields/Fields/Int/RangeSearchForm.tpl @@ -0,0 +1,107 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} +{if strlen({{sugarvar key='value' string=true}}) <= 0} +{assign var="value" value={{sugarvar key='default_value' string=true}} } +{else} +{assign var="value" value={{sugarvar key='value' string=true}} } +{/if} + +{{if empty($displayParams.idName)}} +{assign var="id" value={{sugarvar key='name' string=true}} } +{{else}} +{assign var="id" value={{$displayParams.idName}} } +{{/if}} + +{if isset($smarty.request.{{$id_range_choice}})} +{assign var="starting_choice" value=$smarty.request.{{$id_range_choice}}} +{else} +{assign var="starting_choice" value="="} +{/if} + + + + + +
+ +
+
+ +{$APP.LBL_AND} + +
+
\ No newline at end of file diff --git a/include/SugarFields/Fields/Int/SearchForm.tpl b/include/SugarFields/Fields/Int/SearchForm.tpl new file mode 100644 index 00000000..26c358c1 --- /dev/null +++ b/include/SugarFields/Fields/Int/SearchForm.tpl @@ -0,0 +1,46 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} +{if strlen({{sugarvar key='value' string=true}}) <= 0} +{assign var="value" value={{sugarvar key='default_value' string=true}} } +{else} +{assign var="value" value={{sugarvar key='value' string=true}} } +{/if} + \ No newline at end of file diff --git a/include/SugarFields/Fields/Int/SugarFieldInt.php b/include/SugarFields/Fields/Int/SugarFieldInt.php new file mode 100644 index 00000000..2f47d2da --- /dev/null +++ b/include/SugarFields/Fields/Int/SugarFieldInt.php @@ -0,0 +1,103 @@ +unformatField($field['value'],$field); + } + + function getSearchViewSmarty($parentFieldArray, $vardef, $displayParams, $tabindex) { + // Use the basic field type for searches, no need to format/unformat everything... for now + $this->setup($parentFieldArray, $vardef, $displayParams, $tabindex); + if($this->isRangeSearchView($vardef)) { + $id = isset($displayParams['idName']) ? $displayParams['idName'] : $vardef['name']; + $this->ss->assign('original_id', "{$id}"); + $this->ss->assign('id_range', "range_{$id}"); + $this->ss->assign('id_range_start', "start_range_{$id}"); + $this->ss->assign('id_range_end', "end_range_{$id}"); + $this->ss->assign('id_range_choice', "{$id}_range_choice"); + if(file_exists('custom/include/SugarFields/Fields/Int/RangeSearchForm.tpl')) + { + return $this->fetch('custom/include/SugarFields/Fields/Int/RangeSearchForm.tpl'); + } + return $this->fetch('include/SugarFields/Fields/Int/RangeSearchForm.tpl'); + } + + return $this->fetch($this->findTemplate('SearchForm')); + } + + /** + * @see SugarFieldBase::importSanitize() + */ + public function importSanitize( + $value, + $vardef, + $focus, + ImportFieldSanitize $settings + ) + { + $value = str_replace($settings->num_grp_sep,"",$value); + if (!is_numeric($value) || strstr($value,".")) { + return false; + } + + return $value; + } +} \ No newline at end of file diff --git a/include/SugarFields/Fields/Link/DetailView.tpl b/include/SugarFields/Fields/Link/DetailView.tpl new file mode 100644 index 00000000..fffc5690 --- /dev/null +++ b/include/SugarFields/Fields/Link/DetailView.tpl @@ -0,0 +1,50 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} +{capture name=getLink assign=link}{{sugarvar key='value'}}{/capture} +{{if $vardef.gen}} +{sugar_replace_vars subject='{{$vardef.default|replace:'{':'['|replace:'}':']'}}' assign='link'} +{{/if}} +{if !empty($link)} +{capture name=getStart assign=linkStart}{$link|substr:0:7}{/capture} + +{{if !empty($displayParams.title)}}{sugar_translate label='{{$displayParams.title}}' module=$module}{{else}}{$link}{{/if}} + +{{if !empty($displayParams.enableConnectors)}} +{{sugarvar_connector view='DetailView'}} +{{/if}} +{/if} diff --git a/include/SugarFields/Fields/Link/EditView.tpl b/include/SugarFields/Fields/Link/EditView.tpl new file mode 100644 index 00000000..30620079 --- /dev/null +++ b/include/SugarFields/Fields/Link/EditView.tpl @@ -0,0 +1,47 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} +{{if !$vardef.gen}} + {if !empty({{sugarvar key='value' string=true}})} + + {else} + + {/if} +{{/if}} \ No newline at end of file diff --git a/include/SugarFields/Fields/Link/ListView.tpl b/include/SugarFields/Fields/Link/ListView.tpl new file mode 100644 index 00000000..86813eb4 --- /dev/null +++ b/include/SugarFields/Fields/Link/ListView.tpl @@ -0,0 +1,39 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} +{capture name=getLink assign=link}{sugar_fetch object=$parentFieldArray key=$col}{/capture} +{$link} diff --git a/include/SugarFields/Fields/Multienum/DetailView.tpl b/include/SugarFields/Fields/Multienum/DetailView.tpl new file mode 100644 index 00000000..762c996f --- /dev/null +++ b/include/SugarFields/Fields/Multienum/DetailView.tpl @@ -0,0 +1,47 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} +{if !empty({{sugarvar key='value' string=true}}) && ({{sugarvar key='value' string=true}} != '^^')} + +{multienum_to_array string={{sugarvar key='value' string=true}} assign="vals"} +{foreach from=$vals item=item} +
  • { {{sugarvar key='options' string=true}}.$item }
  • +{/foreach} +{{if !empty($displayParams.enableConnectors)}} +{{sugarvar_connector view='DetailView'}} +{{/if}} +{/if} \ No newline at end of file diff --git a/include/SugarFields/Fields/Multienum/EditView.tpl b/include/SugarFields/Fields/Multienum/EditView.tpl new file mode 100644 index 00000000..b594bc0a --- /dev/null +++ b/include/SugarFields/Fields/Multienum/EditView.tpl @@ -0,0 +1,45 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} + +{multienum_to_array string={{sugarvar key='value' string=true}} default={{sugarvar key='default' string=true}} assign="values"} + diff --git a/include/SugarFields/Fields/Multienum/EditViewFunction.tpl b/include/SugarFields/Fields/Multienum/EditViewFunction.tpl new file mode 100644 index 00000000..b1aab632 --- /dev/null +++ b/include/SugarFields/Fields/Multienum/EditViewFunction.tpl @@ -0,0 +1,41 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} + + \ No newline at end of file diff --git a/include/SugarFields/Fields/Multienum/ListView.tpl b/include/SugarFields/Fields/Multienum/ListView.tpl new file mode 100644 index 00000000..d8de905e --- /dev/null +++ b/include/SugarFields/Fields/Multienum/ListView.tpl @@ -0,0 +1,45 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} +{if !empty($parentFieldArray.$col)} +{multienum_to_array string=$parentFieldArray.$col assign="vals"} +{foreach from=$vals item=item name=multiEnum} +{$vardef.options_list.$item}{if !$smarty.foreach.multiEnum.last}, +{/if} +{/foreach} +{/if} +  diff --git a/include/SugarFields/Fields/Multienum/SearchView.tpl b/include/SugarFields/Fields/Multienum/SearchView.tpl new file mode 100644 index 00000000..2938b01f --- /dev/null +++ b/include/SugarFields/Fields/Multienum/SearchView.tpl @@ -0,0 +1,38 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} +{html_options name='{{$vardef.name}}[]' options={{sugarvar key='options' string=true}} size="{{$displayParams.size|default:6}}" style="width: 150px" multiple=1 selected={{sugarvar key='value' string=true}}} \ No newline at end of file diff --git a/include/SugarFields/Fields/Multienum/SugarFieldMultienum.php b/include/SugarFields/Fields/Multienum/SugarFieldMultienum.php new file mode 100644 index 00000000..175bebc1 --- /dev/null +++ b/include/SugarFields/Fields/Multienum/SugarFieldMultienum.php @@ -0,0 +1,117 @@ +setup($parentFieldArray, $vardef, $displayParams, $tabindex); + return $this->fetch($this->findTemplate('EditViewFunction')); + }else{ + $this->setup($parentFieldArray, $vardef, $displayParams, $tabindex); + return $this->fetch($this->findTemplate('SearchView')); + } + } + + function displayFromFunc( $displayType, $parentFieldArray, $vardef, $displayParams, $tabindex ) { + if ( isset($vardef['function']['returns']) && $vardef['function']['returns'] == 'html' ) { + return parent::displayFromFunc($displayType, $parentFieldArray, $vardef, $displayParams, $tabindex); + } + + $displayTypeFunc = 'get'.$displayType.'Smarty'; + return $this->$displayTypeFunc($parentFieldArray, $vardef, $displayParams, $tabindex); + } + + public function save(&$bean, $params, $field, $properties, $prefix = ''){ + if ( isset($params[$prefix.$field]) ) { + if($params[$prefix.$field][0] === '' && !empty($params[$prefix.$field][1]) ) { + unset($params[$prefix.$field][0]); + } + + $bean->$field = encodeMultienumValue($params[$prefix.$field]); + } + else if (isset($params[$prefix.$field.'_multiselect']) && $params[$prefix.$field.'_multiselect']==true) { + // if the value in db is not empty and + // if the data is not set in params (means the user has deselected everything) and + // if the coorespoding multiselect flag is true + // then set field to '' + if (!empty($bean->$field)) { + $bean->$field = ''; + } + } + } + + /** + * @see SugarFieldBase::importSanitize() + */ + public function importSanitize( + $value, + $vardef, + $focus, + ImportFieldSanitize $settings + ) + { + if(!empty($value) && is_array($value)) { + $enum_list = $value; + } + else { + // If someone was using the old style multienum import technique + $value = str_replace("^","",$value); + + // We will need to break it apart to put test it. + $enum_list = explode(",",$value); + } + // parse to see if all the values given are valid + foreach ( $enum_list as $key => $enum_value ) { + $enum_list[$key] = $enum_value = trim($enum_value); + if ( parent::importSanitize($enum_value,$vardef,$focus,$settings) === false ) { + return false; + } + } + $value = encodeMultienumValue($enum_list); + + return $value; + } +} \ No newline at end of file diff --git a/include/SugarFields/Fields/Parent/DetailView.tpl b/include/SugarFields/Fields/Parent/DetailView.tpl new file mode 100644 index 00000000..78e7b3ac --- /dev/null +++ b/include/SugarFields/Fields/Parent/DetailView.tpl @@ -0,0 +1,47 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} +{{if !$nolink}} + + +{{/if}}{{sugarvar key='value'}}{{if !$nolink}} +{{/if}} +{{if !empty($displayParams.enableConnectors)}} +{if !empty({{sugarvar key='value'}})} +{{sugarvar_connector view='DetailView'}} +{/if} +{{/if}} \ No newline at end of file diff --git a/include/SugarFields/Fields/Parent/EditView.tpl b/include/SugarFields/Fields/Parent/EditView.tpl new file mode 100644 index 00000000..d4fedcc6 --- /dev/null +++ b/include/SugarFields/Fields/Parent/EditView.tpl @@ -0,0 +1,97 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} + + +{{if $displayParams.split}} +
    +{{/if}} +{if empty({{sugarvar key='options' string=true}}[$fields.parent_type.value])} + {assign var="keepParent" value = 0} +{else} + {assign var="keepParent" value = 1} +{/if} + + +{{if empty($displayParams.selectOnly)}} + +{{/if}} + + +{literal} +{{$displayParams.disabled_parent_types}} +{/literal} +{literal} +{{$quickSearchCode}} +{/literal} \ No newline at end of file diff --git a/include/SugarFields/Fields/Parent/SearchView.tpl b/include/SugarFields/Fields/Parent/SearchView.tpl new file mode 100644 index 00000000..59d2d0e5 --- /dev/null +++ b/include/SugarFields/Fields/Parent/SearchView.tpl @@ -0,0 +1,76 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} + +{{if $displayParams.split}} +
    +{{/if}} +{if empty({{sugarvar key='options' string=true}}[$fields.parent_type.value])} + {assign var="keepParent" value = 0} +{else} + {assign var="keepParent value = 1} +{/if} + + + +{{if empty($displayParams.selectOnly)}} + +{{/if}} + + +{literal} +{{$displayParams.disabled_parent_types}} +{/literal} \ No newline at end of file diff --git a/include/SugarFields/Fields/Parent/SugarFieldParent.php b/include/SugarFields/Fields/Parent/SugarFieldParent.php new file mode 100644 index 00000000..40cf320a --- /dev/null +++ b/include/SugarFields/Fields/Parent/SugarFieldParent.php @@ -0,0 +1,169 @@ +ss->assign('nolink', true); + }else{ + $this->ss->assign('nolink', false); + } + $this->setup($parentFieldArray, $vardef, $displayParams, $tabindex); + return $this->fetch($this->findTemplate('DetailView')); + } + + function getEditViewSmarty($parentFieldArray, $vardef, $displayParams, $tabindex) { + $form_name = 'EditView'; + if(isset($displayParams['formName'])) { + $form_name = $displayParams['formName']; + } + + $popup_request_data = array( + 'call_back_function' => 'set_return', + 'form_name' => $form_name, + 'field_to_name_array' => array( + 'id' => $vardef['id_name'], + 'name' => $vardef['name'], + ), + ); + + + global $app_list_strings; + $parent_types = $app_list_strings['record_type_display']; + + $disabled_parent_types = ACLController::disabledModuleList($parent_types,false, 'list'); + foreach($disabled_parent_types as $disabled_parent_type){ + if($disabled_parent_type != $focus->parent_type){ + unset($parent_types[$disabled_parent_type]); + } + } + asort($parent_types); + $json = getJSONobj(); + $displayParams['popupData'] = '{literal}'.$json->encode($popup_request_data).'{/literal}'; + $displayParams['disabled_parent_types'] = ''; + $this->ss->assign('quickSearchCode', $this->createQuickSearchCode($form_name, $vardef)); + $this->setup($parentFieldArray, $vardef, $displayParams, $tabindex); + return $this->fetch($this->findTemplate('EditView')); + } + + function getSearchViewSmarty($parentFieldArray, $vardef, $displayParams, $tabindex) { + $form_name = 'search_form'; + + if(isset($displayParams['formName'])) { + $form_name = $displayParams['formName']; + } + + $this->ss->assign('form_name', $form_name); + + $popup_request_data = array( + 'call_back_function' => 'set_return', + 'form_name' => $form_name, + 'field_to_name_array' => array( + 'id' => $vardef['id_name'], + 'name' => $vardef['name'], + ), + ); + + + global $app_list_strings; + $parent_types = $app_list_strings['record_type_display']; + $disabled_parent_types = ACLController::disabledModuleList($parent_types,false, 'list'); + foreach($disabled_parent_types as $disabled_parent_type){ + if($disabled_parent_type != $focus->parent_type){ + unset($parent_types[$disabled_parent_type]); + } + } + + $json = getJSONobj(); + $displayParams['popupData'] = '{literal}'.$json->encode($popup_request_data).'{/literal}'; + $displayParams['disabled_parent_types'] = ''; + $this->setup($parentFieldArray, $vardef, $displayParams, $tabindex); + return $this->fetch($this->findTemplate('SearchView')); + } + + /** + * @see SugarFieldBase::importSanitize() + */ + public function importSanitize( + $value, + $vardef, + $focus, + ImportFieldSanitize $settings + ) + { + global $beanList; + + if ( isset($vardef['type_name']) ) { + $moduleName = $vardef['type_name']; + if ( isset($focus->$moduleName) && isset($beanList[$focus->$moduleName]) ) { + $vardef['module'] = $focus->$moduleName; + $vardef['rname'] = 'name'; + $relatedBean = loadBean($focus->$moduleName); + $vardef['table'] = $relatedBean->table_name; + return parent::importSanitize($value,$vardef,$focus,$settings); + } + } + + return false; + } + + function createQuickSearchCode($formName = 'EditView', $vardef){ + + require_once('include/QuickSearchDefaults.php'); + $json = getJSONobj(); + + $dynamicParentTypePlaceHolder = "**@**"; //Placeholder for dynamic parent so smarty tags are not escaped in json encoding. + $dynamicParentType = '{/literal}{if !empty($fields.parent_type.value)}{$fields.parent_type.value}{else}Accounts{/if}{literal}'; + + //Get the parent sqs definition + $qsd = new QuickSearchDefaults(); + $qsd->setFormName($formName); + $sqsFieldArray = $qsd->getQSParent($dynamicParentTypePlaceHolder); + $qsFieldName = $formName . "_" . $vardef['name']; + + //Build the javascript + $quicksearch_js = ''; + } +} +?> \ No newline at end of file diff --git a/include/SugarFields/Fields/Password/EditView.tpl b/include/SugarFields/Fields/Password/EditView.tpl new file mode 100644 index 00000000..23277b2e --- /dev/null +++ b/include/SugarFields/Fields/Password/EditView.tpl @@ -0,0 +1,40 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} + diff --git a/include/SugarFields/Fields/Password/SugarFieldPassword.php b/include/SugarFields/Fields/Password/SugarFieldPassword.php new file mode 100644 index 00000000..79a5f9cf --- /dev/null +++ b/include/SugarFields/Fields/Password/SugarFieldPassword.php @@ -0,0 +1,56 @@ + \ No newline at end of file diff --git a/include/SugarFields/Fields/Phone/EditView.tpl b/include/SugarFields/Fields/Phone/EditView.tpl new file mode 100644 index 00000000..86269204 --- /dev/null +++ b/include/SugarFields/Fields/Phone/EditView.tpl @@ -0,0 +1,50 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} +{{capture name=idname assign=idname}}{{sugarvar key='name'}}{{/capture}} +{{if !empty($displayParams.idName)}} + {{assign var=idname value=$displayParams.idName}} +{{/if}} + +{if strlen({{sugarvar key='value' string=true}}) <= 0} +{assign var="value" value={{sugarvar key='default_value' string=true}} } +{else} +{assign var="value" value={{sugarvar key='value' string=true}} } +{/if} + + + diff --git a/include/SugarFields/Fields/Phone/SugarFieldPhone.php b/include/SugarFields/Fields/Phone/SugarFieldPhone.php new file mode 100644 index 00000000..b6eb81c7 --- /dev/null +++ b/include/SugarFields/Fields/Phone/SugarFieldPhone.php @@ -0,0 +1,56 @@ +$field = $params[$prefix.$field]; + } + } + +} +?> \ No newline at end of file diff --git a/include/SugarFields/Fields/Radioenum/DetailView.tpl b/include/SugarFields/Fields/Radioenum/DetailView.tpl new file mode 100644 index 00000000..5d2718c8 --- /dev/null +++ b/include/SugarFields/Fields/Radioenum/DetailView.tpl @@ -0,0 +1,45 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} + +{ {{sugarvar key='options' string=true}}[{{sugarvar key='value' string=true}}]} + +{{if !empty($displayParams.enableConnectors)}} +{if !empty({{sugarvar key='options' string=true}}[{{sugarvar key='value' string=true}}])} +{{sugarvar_connector view='DetailView'}} +{/if} +{{/if}} \ No newline at end of file diff --git a/include/SugarFields/Fields/Radioenum/EditView.tpl b/include/SugarFields/Fields/Radioenum/EditView.tpl new file mode 100644 index 00000000..f296dd09 --- /dev/null +++ b/include/SugarFields/Fields/Radioenum/EditView.tpl @@ -0,0 +1,52 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} +{if empty({{sugarvar key='value' string=true}})} +{assign var="value" value={{sugarvar key='default_value' string=true}} } +{else} +{assign var="value" value={{sugarvar key='value' string=true}} } +{/if} +{capture name=idname assign=idname}{{sugarvar key='name'}}{/capture} +{{if !empty($displayParams.idName)}} + {assign var=idname value=$displayParams.idName} +{{/if}} + +{if isset({{sugarvar key='value' string=true}}) && {{sugarvar key='value' string=true}} != ''} + {html_radios id="$idname" name="$idname" title="{{$vardef.help}}" options={{sugarvar key='options' string=true}} selected={{sugarvar key='value' string=true}} separator="{{$vardef.separator}}"} +{else} + {html_radios id="$idname" name="$idname" title="{{$vardef.help}}" options={{sugarvar key='options' string=true}} selected={{sugarvar key='default' string=true}} separator="{{$vardef.separator}}"} +{/if} \ No newline at end of file diff --git a/include/SugarFields/Fields/Readonly/SugarFieldReadonly.php b/include/SugarFields/Fields/Readonly/SugarFieldReadonly.php new file mode 100644 index 00000000..da59b3ee --- /dev/null +++ b/include/SugarFields/Fields/Readonly/SugarFieldReadonly.php @@ -0,0 +1,45 @@ +getDetailViewSmarty($parentFieldArray, $vardef, $displayParams, $tabindex); + } + +} +?> \ No newline at end of file diff --git a/include/SugarFields/Fields/Relate/DetailView.tpl b/include/SugarFields/Fields/Relate/DetailView.tpl new file mode 100644 index 00000000..82998db2 --- /dev/null +++ b/include/SugarFields/Fields/Relate/DetailView.tpl @@ -0,0 +1,49 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} +{{if !$nolink && !empty($vardef.id_name)}} +{if !empty({{sugarvar memberName='vardef.id_name' key='value' string='true'}})}{/if} +{{/if}} +{{sugarvar key='value'}} +{{if !$nolink && !empty($vardef.id_name)}} +{if !empty({{sugarvar memberName='vardef.id_name' key='value' string='true'}})}{/if} +{{/if}} +{{if !empty($displayParams.enableConnectors) && !empty($vardef.id_name)}} +{if !empty({{sugarvar memberName='vardef.id_name' key='value' string='true'}})} +{{sugarvar_connector view='DetailView'}} +{/if} +{{/if}} diff --git a/include/SugarFields/Fields/Relate/EditView.tpl b/include/SugarFields/Fields/Relate/EditView.tpl new file mode 100644 index 00000000..446d7727 --- /dev/null +++ b/include/SugarFields/Fields/Relate/EditView.tpl @@ -0,0 +1,76 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} +{{capture name=idname assign=idname}}{{sugarvar key='name'}}{{/capture}} +{{if !empty($displayParams.idName)}} + {{assign var=idname value=$displayParams.idName}} +{{/if}} + + +{{if empty($displayParams.hideButtons) }} + +{{if empty($displayParams.selectOnly) }} +{{/if}} + +{{/if}} +{{if !empty($displayParams.allowNewValue) }} + +{{/if}} + \ No newline at end of file diff --git a/include/SugarFields/Fields/Relate/SearchView.tpl b/include/SugarFields/Fields/Relate/SearchView.tpl new file mode 100644 index 00000000..02589c26 --- /dev/null +++ b/include/SugarFields/Fields/Relate/SearchView.tpl @@ -0,0 +1,50 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} + + +{{if empty($displayParams.hideButtons) }} + +{{if empty($displayParams.clearOnly) }} +{{/if}} +{{if empty($displayParams.selectOnly) }} +{{/if}} + +{{/if}} +{{if !empty($displayParams.allowNewValue) }} + +{{/if}} diff --git a/include/SugarFields/Fields/Relate/SugarFieldRelate.php b/include/SugarFields/Fields/Relate/SugarFieldRelate.php new file mode 100644 index 00000000..4a505e25 --- /dev/null +++ b/include/SugarFields/Fields/Relate/SugarFieldRelate.php @@ -0,0 +1,368 @@ +ss->assign('nolink', true); + }else{ + $this->ss->assign('nolink', false); + } + $this->setup($parentFieldArray, $vardef, $displayParams, $tabindex); + return $this->fetch($this->findTemplate('DetailView')); + } + + function getEditViewSmarty($parentFieldArray, $vardef, $displayParams, $tabindex) { + if(!empty($vardef['function']['returns']) && $vardef['function']['returns'] == 'html'){ + return parent::getEditViewSmarty($parentFieldArray, $vardef, $displayParams, $tabindex); + } + + $call_back_function = 'set_return'; + if(isset($displayParams['call_back_function'])) { + $call_back_function = $displayParams['call_back_function']; + } + $form_name = 'EditView'; + if(isset($displayParams['formName'])) { + $form_name = $displayParams['formName']; + } + + //Special Case for accounts; use the displayParams array and retrieve + //the key and copy indexes. 'key' is the suffix of the field we are searching + //the Account's address with. 'copy' is the suffix we are copying the addresses + //form fields into. + if(isset($vardef['module']) && preg_match('/Accounts/si',$vardef['module']) + && isset($displayParams['key']) && isset($displayParams['copy'])) { + + if(isset($displayParams['key']) && is_array($displayParams['key'])) { + $database_key = $displayParams['key']; + } else { + $database_key[] = $displayParams['key']; + } + + if(isset($displayParams['copy']) && is_array($displayParams['copy'])) { + $form = $displayParams['copy']; + } else { + $form[] = $displayParams['copy']; + } + + if(count($database_key) != count($form)) { + global $app_list_strings; + $this->ss->trigger_error($app_list_strings['ERR_SMARTY_UNEQUAL_RELATED_FIELD_PARAMETERS']); + } //if + + $copy_phone = isset($displayParams['copyPhone']) ? $displayParams['copyPhone'] : true; + + $field_to_name = array(); + $field_to_name['id'] = $vardef['id_name']; + $field_to_name['name'] = $vardef['name']; + $address_fields = array('_address_street', '_address_city', '_address_state', '_address_postalcode', '_address_country'); + $count = 0; + foreach($form as $f) { + foreach($address_fields as $afield) { + $field_to_name[$database_key[$count] . $afield] = $f . $afield; + } + $count++; + } + + $popup_request_data = array( + 'call_back_function' => $call_back_function, + 'form_name' => $form_name, + 'field_to_name_array' => $field_to_name, + ); + + if($copy_phone) { + $popup_request_data['field_to_name_array']['phone_office'] = 'phone_work'; + } + } elseif(isset($displayParams['field_to_name_array'])) { + $popup_request_data = array( + 'call_back_function' => $call_back_function, + 'form_name' => $form_name, + 'field_to_name_array' => $displayParams['field_to_name_array'], + ); + } else { + $popup_request_data = array( + 'call_back_function' => $call_back_function, + 'form_name' => $form_name, + 'field_to_name_array' => array( + 'id' => (empty($displayParams['idName']) ? $vardef['id_name'] : ($displayParams['idName'] . '_' . $vardef['id_name'])) , + ((empty($vardef['rname'])) ? 'name' : $vardef['rname']) => (empty($displayParams['idName']) ? $vardef['name'] : $displayParams['idName']), + ), + ); + } + $json = getJSONobj(); + $displayParams['popupData'] = '{literal}'.$json->encode($popup_request_data). '{/literal}'; + if(!isset($displayParams['readOnly'])) { + $displayParams['readOnly'] = ''; + } else { + $displayParams['readOnly'] = $displayParams['readOnly'] == false ? '' : 'READONLY'; + } + $this->setup($parentFieldArray, $vardef, $displayParams, $tabindex); + return $this->fetch($this->findTemplate('EditView')); + } + + function getPopupViewSmarty($parentFieldArray, $vardef, $displayParams, $tabindex){ + $displayParams['clearOnly'] = true; + return $this->getSearchViewSmarty($parentFieldArray, $vardef, $displayParams, $tabindex); + } + + function getSearchViewSmarty($parentFieldArray, $vardef, $displayParams, $tabindex) { + $call_back_function = 'set_return'; + if(isset($displayParams['call_back_function'])) { + $call_back_function = $displayParams['call_back_function']; + } + $form_name = 'search_form'; + if(isset($displayParams['formName'])) { + $form_name = $displayParams['formName']; + } + if(!empty($vardef['rname']) && $vardef['rname'] == 'user_name'){ + $displayParams['useIdSearch'] = true; + } + + //Special Case for accounts; use the displayParams array and retrieve + //the key and copy indexes. 'key' is the suffix of the field we are searching + //the Account's address with. 'copy' is the suffix we are copying the addresses + //form fields into. + if(isset($vardef['module']) && preg_match('/Accounts/si',$vardef['module']) + && isset($displayParams['key']) && isset($displayParams['copy'])) { + + if(isset($displayParams['key']) && is_array($displayParams['key'])) { + $database_key = $displayParams['key']; + } else { + $database_key[] = $displayParams['key']; + } + + if(isset($displayParams['copy']) && is_array($displayParams['copy'])) { + $form = $displayParams['copy']; + } else { + $form[] = $displayParams['copy']; + } + + if(count($database_key) != count($form)) { + global $app_list_strings; + $this->ss->trigger_error($app_list_strings['ERR_SMARTY_UNEQUAL_RELATED_FIELD_PARAMETERS']); + } //if + + $copy_phone = isset($displayParams['copyPhone']) ? $displayParams['copyPhone'] : true; + + $field_to_name = array(); + $field_to_name['id'] = $vardef['id_name']; + $field_to_name['name'] = $vardef['name']; + $address_fields = array('_address_street', '_address_city', '_address_state', '_address_postalcode', '_address_country'); + $count = 0; + foreach($form as $f) { + foreach($address_fields as $afield) { + $field_to_name[$database_key[$count] . $afield] = $f . $afield; + } + $count++; + } + + $popup_request_data = array( + 'call_back_function' => $call_back_function, + 'form_name' => $form_name, + 'field_to_name_array' => $field_to_name, + ); + + if($copy_phone) { + $popup_request_data['field_to_name_array']['phone_office'] = 'phone_work'; + } + } elseif(isset($displayParams['field_to_name_array'])) { + $popup_request_data = array( + 'call_back_function' => $call_back_function, + 'form_name' => $form_name, + 'field_to_name_array' => $displayParams['field_to_name_array'], + ); + } else { + $popup_request_data = array( + 'call_back_function' => $call_back_function, + 'form_name' => $form_name, + 'field_to_name_array' => array( + 'id' => $vardef['id_name'], + ((empty($vardef['rname'])) ? 'name' : $vardef['rname']) => $vardef['name'], + ), + ); + } + $json = getJSONobj(); + $displayParams['popupData'] = '{literal}'.$json->encode($popup_request_data). '{/literal}'; + if(!isset($displayParams['readOnly'])) { + $displayParams['readOnly'] = ''; + } else { + $displayParams['readOnly'] = $displayParams['readOnly'] == false ? '' : 'READONLY'; + } + $this->setup($parentFieldArray, $vardef, $displayParams, $tabindex); + return $this->fetch($this->findTemplate('SearchView')); + } + + function formatField($rawField, $vardef) { + if ('contact_name' == $vardef['name']){ + $default_locale_name_format = $GLOBALS['current_user']->getPreference('default_locale_name_format'); + $default_locale_name_format = trim(preg_replace('/s/i', '', $default_locale_name_format)); + $new_field = ''; + $names = array(); + $temp = explode(' ', $rawField); + if ( !isset($temp[1]) ) { + $names['f'] = ''; + $names['l'] = $temp[0]; + } + elseif ( !empty($temp) ) { + $names['f'] = $temp[0]; + $names['l'] = $temp[1]; + } + for($i=0;$iretrieve_by_string_fields( + array($userFocus->db->concat('users',array('first_name','last_name')) => $value )); + if ( !empty($userFocus->id) ) { + $value = $userFocus->user_name; + } + } + + // Bug 32869 - Assumed related field name is 'name' if it is not specified + if ( !isset($vardef['rname']) ) + $vardef['rname'] = 'name'; + + // Bug 27046 - Validate field against type as it is in the related field + $rvardef = $newbean->getFieldDefinition($vardef['rname']); + if ( isset($rvardef['type']) + && method_exists($this,$rvardef['type']) ) { + $fieldtype = $rvardef['type']; + $returnValue = $settings->$fieldtype($value,$rvardef); + if ( !$returnValue ) + return false; + else + $value = $returnValue; + } + + if ( isset($vardef['id_name']) ) { + $idField = $vardef['id_name']; + + // Bug 24075 - clear out id field value if it is invalid + if ( isset($focus->$idField) ) { + $checkfocus = loadBean($vardef['module']); + if ( $checkfocus && is_null($checkfocus->retrieve($focus->$idField)) ) + $focus->$idField = ''; + } + + // be sure that the id isn't already set for this row + if ( empty($focus->$idField) + && $idField != $vardef['name'] + && !empty($vardef['rname']) + && !empty($vardef['table'])) { + // Bug 27562 - Check db_concat_fields first to see if the field name is a concat + $relatedFieldDef = $newbean->getFieldDefinition($vardef['rname']); + if ( isset($relatedFieldDef['db_concat_fields']) + && is_array($relatedFieldDef['db_concat_fields']) ) + $fieldname = $focus->db->concat($vardef['table'],$relatedFieldDef['db_concat_fields']); + else + $fieldname = $vardef['rname']; + // lookup first record that matches in linked table + $query = "SELECT id + FROM {$vardef['table']} + WHERE {$fieldname} = '" . $focus->db->quote($value) . "' + AND deleted != 1"; + + $result = $focus->db->limitQuery($query,0,1,true, "Want only a single row"); + if(!empty($result)){ + if ( $relaterow = $focus->db->fetchByAssoc($result) ) + $focus->$idField = $relaterow['id']; + elseif ( !$settings->addRelatedBean + || ( $newbean->bean_implements('ACL') && !$newbean->ACLAccess('save') ) + || ( in_array($newbean->module_dir,array('Teams','Users')) ) + ) + return false; + else { + // add this as a new record in that bean, then relate + if ( isset($relatedFieldDef['db_concat_fields']) + && is_array($relatedFieldDef['db_concat_fields']) ) { + $relatedFieldParts = explode(' ',$value); + foreach ($relatedFieldDef['db_concat_fields'] as $relatedField) + $newbean->$relatedField = array_shift($relatedFieldParts); + } + else + $newbean->$vardef['rname'] = $value; + if ( !isset($focus->assigned_user_id) || $focus->assigned_user_id == '' ) + $newbean->assigned_user_id = $GLOBALS['current_user']->id; + else + $newbean->assigned_user_id = $focus->assigned_user_id; + if ( !isset($focus->modified_user_id) || $focus->modified_user_id == '' ) + $newbean->modified_user_id = $GLOBALS['current_user']->id; + else + $newbean->modified_user_id = $focus->modified_user_id; + + // populate fields from the parent bean to the child bean + $focus->populateRelatedBean($newbean); + + $newbean->save(false); + $focus->$idField = $newbean->id; + $settings->createdBeans[] = ImportFile::writeRowToLastImport( + $focus->module_dir,$newbean->object_name,$newbean->id); + } + } + } + } + + return $value; + } +} diff --git a/include/SugarFields/Fields/Text/ClassicEditView.tpl b/include/SugarFields/Fields/Text/ClassicEditView.tpl new file mode 100644 index 00000000..92fac760 --- /dev/null +++ b/include/SugarFields/Fields/Text/ClassicEditView.tpl @@ -0,0 +1,45 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} + +{if !empty($displayParams.maxlength)} + +{else} + +{/if} + + diff --git a/include/SugarFields/Fields/Text/DetailView.tpl b/include/SugarFields/Fields/Text/DetailView.tpl new file mode 100644 index 00000000..50b7ec00 --- /dev/null +++ b/include/SugarFields/Fields/Text/DetailView.tpl @@ -0,0 +1,49 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} + +{{if empty($displayParams.textonly)}} +{{sugarvar key='value' htmlentitydecode='true'}} +{{else}} +{{sugarvar key='value'}} +{{/if}} + +{{if !empty($displayParams.enableConnectors)}} +{if !empty({{sugarvar key='value'}})} +{{sugarvar_connector view='DetailView'}} +{/if} +{{/if}} \ No newline at end of file diff --git a/include/SugarFields/Fields/Text/EditView.tpl b/include/SugarFields/Fields/Text/EditView.tpl new file mode 100644 index 00000000..df93f8b1 --- /dev/null +++ b/include/SugarFields/Fields/Text/EditView.tpl @@ -0,0 +1,57 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} +{if empty({{sugarvar key='value' string=true}})} +{assign var="value" value={{sugarvar key='default_value' string=true}} } +{else} +{assign var="value" value={{sugarvar key='value' string=true}} } +{/if} + + +{{capture name=idname assign=idname}}{{sugarvar key='name'}}{{/capture}} +{{if !empty($displayParams.idName)}} + {{assign var=idname value=$displayParams.idName}} +{{/if}} + + + + + + diff --git a/include/SugarFields/Fields/Text/SugarFieldText.php b/include/SugarFields/Fields/Text/SugarFieldText.php new file mode 100644 index 00000000..4a6043fc --- /dev/null +++ b/include/SugarFields/Fields/Text/SugarFieldText.php @@ -0,0 +1,77 @@ +ss->assign('prefix', $prefix); + $this->ss->assign('field_id', $field_id); + $this->ss->assign('value', $value); + $this->ss->assign('tabindex', $tabindex); + + $displayParams = array(); + $displayParams['textonly'] = $rich_text ? false : true; + $displayParams['maxlength'] = $maxlength; + $displayParams['rows'] = $rows; + $displayParams['cols'] = $cols; + + + $this->ss->assign('displayParams', $displayParams); + if(isset($GLOBALS['current_user'])) { + $height = $GLOBALS['current_user']->getPreference('text_editor_height'); + $width = $GLOBALS['current_user']->getPreference('text_editor_width'); + $height = isset($height) ? $height : '300px'; + $width = isset($width) ? $width : '95%'; + $this->ss->assign('RICH_TEXT_EDITOR_HEIGHT', $height); + $this->ss->assign('RICH_TEXT_EDITOR_WIDTH', $width); + } else { + $this->ss->assign('RICH_TEXT_EDITOR_HEIGHT', '100px'); + $this->ss->assign('RICH_TEXT_EDITOR_WIDTH', '95%'); + } + + return $this->ss->fetch($this->findTemplate('ClassicEditView')); + } +} +?> diff --git a/include/SugarFields/Fields/URL/DetailView.tpl b/include/SugarFields/Fields/URL/DetailView.tpl new file mode 100644 index 00000000..e5ff7e29 --- /dev/null +++ b/include/SugarFields/Fields/URL/DetailView.tpl @@ -0,0 +1,52 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} +{capture name=getLink assign=link}{{sugarvar key='value'}}{/capture} +{{if $vardef.gen}} +{sugar_replace_vars subject='{{$vardef.default|replace:'{':'['|replace:'}':']'}}' assign='link'} +{{/if}} +{if !empty($link)} +{capture name=getStart assign=linkStart}{$link|substr:0:7}{/capture} + + +{{if !empty($displayParams.title)}}{sugar_translate label='{{$displayParams.title}}' module=$module}{{else}}{$link}{{/if}} + + +{{if !empty($displayParams.enableConnectors)}} +{{sugarvar_connector view='DetailView'}} +{{/if}} +{/if} diff --git a/include/SugarFields/Fields/URL/EditView.tpl b/include/SugarFields/Fields/URL/EditView.tpl new file mode 100644 index 00000000..c083432d --- /dev/null +++ b/include/SugarFields/Fields/URL/EditView.tpl @@ -0,0 +1,56 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} +{if empty({{sugarvar key='value' string=true}})} +{assign var="value" value={{sugarvar key='default_value' string=true}} } +{else} +{assign var="value" value={{sugarvar key='value' string=true}} } +{/if} +{{capture name=idname assign=idname}}{{sugarvar key='name'}}{{/capture}} +{{if !empty($displayParams.idName)}} + {{assign var=idname value=$displayParams.idName}} +{{/if}} +{{if !$vardef.gen}} + {if !empty({{sugarvar key='value' string=true}})} + + {else} + + {/if} +{{/if}} \ No newline at end of file diff --git a/include/SugarFields/Fields/URL/ListView.tpl b/include/SugarFields/Fields/URL/ListView.tpl new file mode 100644 index 00000000..4ef6ec66 --- /dev/null +++ b/include/SugarFields/Fields/URL/ListView.tpl @@ -0,0 +1,45 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} +{capture name=getLink assign=link}{{sugarvar key='value'}}{/capture} +{{if $vardef.gen}} +{sugar_replace_vars subject='{{$vardef.default|replace:'{':'['|replace:'}':']'}}' assign='link'} +{{/if}} +{if !empty($link)} +{capture name=getStart assign=linkStart}{$link|substr:0:7}{/capture} +{{if !empty($displayParams.title)}}{sugar_translate label='{{$displayParams.title}}' module=$module}{{else}}{$link}{{/if}} +{/if} diff --git a/include/SugarFields/Fields/Username/DetailView.tpl b/include/SugarFields/Fields/Username/DetailView.tpl new file mode 100644 index 00000000..95810b4b --- /dev/null +++ b/include/SugarFields/Fields/Username/DetailView.tpl @@ -0,0 +1,43 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} + +{$fields[{{sugarvar key='salutation' stringFormat=true}}].value} {$fields[{{sugarvar key='first_name' stringFormat=true}}].value} {$fields[{{sugarvar key='last_name' stringFormat=true}}].value} + +{{if !empty($displayParams.enableConnectors)}} +{{sugarvar_connector view='DetailView'}} +{{/if}} \ No newline at end of file diff --git a/include/SugarFields/Fields/Username/SugarFieldUsername.php b/include/SugarFields/Fields/Username/SugarFieldUsername.php new file mode 100644 index 00000000..f9113d79 --- /dev/null +++ b/include/SugarFields/Fields/Username/SugarFieldUsername.php @@ -0,0 +1,46 @@ +setup($parentFieldArray, $vardef, $displayParams, $tabindex); + + return $this->fetch($this->findTemplate('DetailView')); + } +} +?> diff --git a/include/SugarFields/Parsers/DetailViewMetaParser.php b/include/SugarFields/Parsers/DetailViewMetaParser.php new file mode 100644 index 00000000..df6f376c --- /dev/null +++ b/include/SugarFields/Parsers/DetailViewMetaParser.php @@ -0,0 +1,192 @@ +mView = 'DetailView'; +} + + +/** + * parse + * + * @param $filePath The file path of the HTML file to parse + * @param $vardefs The module's vardefs + * @param $moduleDir The module's directory + * @param $merge boolean value indicating whether or not to merge the parsed contents + * @param $masterCopy The file path of the mater copy of the metadata file to merge against + * @return String format of metadata contents + **/ +function parse($filePath, $vardefs = array(), $moduleDir = '', $merge=false, $masterCopy=null) { + +// Grab file contents +$contents = file_get_contents($filePath); + +// Remove \n,\r characters to allow for better text parsing +$contents = $this->trimHTML($contents); +$contents = $this->stripFlavorTags($contents); + + +// Notes DetailView.html file is messed up +if($moduleDir == 'Notes') { + $contents = str_replace('{PAGINATION}', '{PAGINATION}', $contents); + $contents = str_replace(' blocks. + * The method also converts values enclosed within "{...}" blocks that may need to be converted + * to Smarty syntax. + * + * @param $contents The HTML String contents to parse + * + * @return $javascript The formatted script blocks or null if none found + */ +function getJavascript($contents, $addLiterals = true) { + +$javascript = null; + +//Check if there are Javascript blocks of code to process +preg_match_all("'(]*?>)(.*?)(]*?>)'si", $contents, $matches, PREG_PATTERN_ORDER); +if(empty($matches)) { + return $javascript; +} + +foreach($matches[0] as $scriptBlock) { + $javascript .= "\n" . $scriptBlock; +} //foreach + +$javascript = substr($javascript, 1); + +//Remove stuff first +//1) Calendar.setup {..} blocks +$javascript = preg_replace('/Calendar.setup[\s]*[\(][^\)]*?[\)][\s]*;/si', '', $javascript); + +//Find all blocks that may need to be replaced with Smarty syntax +preg_match_all("'([\{])([a-zA-Z0-9_]*?)([\}])'si", $javascript, $matches, PREG_PATTERN_ORDER); +if(!empty($matches)) { + $replace = array(); + + foreach($matches[0] as $xTemplateCode) { + if(!isset($replace[$xTemplateCode])) { + $replace[$xTemplateCode] = str_replace("{", "{\$", $xTemplateCode); + } //if + } //foreach + + $javascript = str_replace(array_keys($replace), array_values($replace), $javascript); +} //if + +if(!$addLiterals) { + return $javascript; +} + +return $this->parseDelimiters($javascript); + +} + +function parseDelimiters($javascript) { + $newJavascript = ''; + $scriptLength = strlen($javascript); + $count = 0; + $inSmartyVariable = false; + + while($count < $scriptLength) { + + if($inSmartyVariable) { + $start = $count; + $numOfChars = 1; + while(isset($javascript[$count]) && $javascript[$count] != '}') { + $count++; + $numOfChars++; + } + + $newJavascript .= substr($javascript, $start, $numOfChars); + $inSmartyVariable = false; + + } else { + + $char = $javascript[$count]; + $nextChar = ($count + 1 >= $scriptLength) ? '' : $javascript[$count + 1]; + + if($char == "{" && $nextChar == "$") { + $inSmartyVariable = true; + $newJavascript .= $javascript[$count]; + } else if($char == "{") { + $newJavascript .= " {ldelim} "; + } else if($char == "}") { + $newJavascript .= " {rdelim} "; + } else { + $newJavascript .= $javascript[$count]; + } + } + $count++; + } //while + + return $newJavascript; +} + +/** + * findAssignedVariableName + * This method provides additional support in attempting to parse the module's corresponding + * PHP file for either the EditView or DetailView. In the event that the subclasses cannot + * find a matching vardefs.php entry in the HTML file, this method can be called to parse the + * PHP file to see if the assignment was made using the bean's variable. If so, we return + * this variable name. + * + * @param $name The tag name found in the HTML file for which we want to search + * @param $filePath The full file path for the HTML file + * @return The variable name found in PHP file, original $name variable if not found + */ +function findAssignedVariableName($name, $filePath) { + + if($this->mPHPFile == "INVALID") { + return $name; + } + + if(!isset($this->mPHPFile)) { + if(preg_match('/(.*?)(DetailView).html$/', $filePath, $matches)) { + $dir = $matches[1]; + } else if(preg_match('/(.*?)(EditView).html$/', $filePath, $matches)) { + $dir = $matches[1]; + } + + if(!isset($dir) || !is_dir($dir)) { + $this->mPHPFile = "INVALID"; + return $name; + } + + $filesInDir = $this->dirList($dir); + $phpFile = $matches[2].'.*?[\.]php'; + foreach($filesInDir as $file) { + if(preg_match("/$phpFile/", $file)) { + $this->mPHPFile = $matches[1] . $file; + break; + } + } + + if(!isset($this->mPHPFile) || !file_exists($this->mPHPFile)) { + $this->mPHPFile = "INVALID"; + return $name; + } + } + + $phpContents = file_get_contents($this->mPHPFile); + $uname = strtoupper($name); + if(preg_match("/xtpl->assign[\(][\"\']".$uname."[\"\'][\s]*?,[\s]*?[\$]focus->(.*?)[\)]/si", $phpContents, $matches)) { + return $matches[1]; + } + return $name; +} + + +/** + * dirList + * Utility method to list all the files in a given directory. + * + * @param $directory The directory to scan + * @return $results The files in the directory that were found + */ +function dirList ($directory) { + + // create an array to hold directory list + $results = array(); + + // create a handler for the directory + $handler = opendir($directory); + + // keep going until all files in directory have been read + while ($file = readdir($handler)) { + // if $file isn't this directory or its parent, + // add it to the results array + if ($file != '.' && $file != '..') + $results[] = $file; + } + + // tidy up: close the handler + closedir($handler); + return $results; +} + + +/** + * isCustomField + * This method checks the mixed variable $elementNames to see if it is a custom field. A custom + * field is simply defined as a field that ends with "_c". If $elementNames is an Array + * any matching custom field value will result in a true evaluation + * @param $elementNames Array or String value of form element name(s). + * @return String name of custom field; null if none found + */ +function getCustomField($elementNames) { + + if(!isset($elementNames) || (!is_string($elementNames) && !is_array($elementNames))) { + return null; + } + + if(is_string($elementNames)) { + if(preg_match('/(.+_c)(_basic)?(\[\])?$/', $elementNames, $matches)) { + return count($matches) == 1 ? $matches[0] : $matches[1]; + } + return null; + } + + foreach($elementNames as $name) { + if(preg_match('/(.+_c)(_basic)?(\[\])?$/', $name, $matches)) { + return count($matches) == 1 ? $matches[0] : $matches[1]; + } + } + + return null; +} + +function applyPreRules($moduleDir, $panels) { + if(file_exists("include/SugarFields/Parsers/Rules/".$moduleDir."ParseRule.php")) { + require_once("include/SugarFields/Parsers/Rules/".$moduleDir."ParseRule.php"); + $class = $moduleDir."ParseRule"; + $parseRule = new $class(); + $panels = $parseRule->preParse($panels, $this->mView); + } + return $panels; +} + +function applyRules($moduleDir, $panels) { + return $this->applyPostRules($moduleDir, $panels); +} + +function applyPostRules($moduleDir, $panels) { + //Run module specific rules + if(file_exists("include/SugarFields/Parsers/Rules/".$moduleDir."ParseRule.php")) { + require_once("include/SugarFields/Parsers/Rules/".$moduleDir."ParseRule.php"); + $class = $moduleDir."ParseRule"; + $parseRule = new $class(); + $panels = $parseRule->parsePanels($panels, $this->mView); + } + + //Now run defined rules + require_once("include/SugarFields/Parsers/Rules/ParseRules.php"); + $rules = ParseRules::getRules(); + + foreach($rules as $rule) { + if(!file_exists($rule['file'])) { + $GLOBALS['log']->error("Cannot run rule for " . $rule['file']); + continue; + } //if + require_once($rule['file']); + $runRule = new $rule['class']; + $panels = $runRule->parsePanels($panels, $this->mView); + + } //foreach + + return $panels; +} + +function createFileContents($moduleDir, $panels, $templateMeta=array(), $htmlFilePath) { + +$header = "mView'] = array( + 'templateMeta' => array('maxColumns' => '2', + 'widths' => array( + array('label' => '10', 'field' => '30'), + array('label' => '10', 'field' => '30') + ), + ),"; +} else { +$header .= "\$viewdefs['$moduleDir']['$this->mView'] = array( + 'templateMeta' =>" . var_export($templateMeta, true) . ","; +} + +//Replace all the @sq (single quote tags that may have been inserted) +$header = preg_replace('/\@sq/', "'", $header); + +/* +$contents = file_get_contents($htmlFilePath); + +$javascript = $this->getJavascript($contents, true); + +if(!empty($javascript)) { + $javascript = str_replace("'", "\\'", $javascript); + $header .= "\n 'javascript' => '" . $javascript . "',\n"; +} //if +*/ +$header .= "\n 'panels' =>"; + +$footer = " +\n +); +?>"; + + $metadata = ''; + $body = var_export($panels, true); + $metadata = $header . $body . $footer; + $metadata = preg_replace('/(\d+)[\s]=>[\s]?/',"",$metadata); + return $metadata; + +} + + +/** + * mergePanels + * This function merges the $panels Array against the $masterCopy's meta data definition + * @param $panels meta data Array to merge + * @param $moduleDir Directory name of the module + * @param $masterCopy file path to the meta data master copy + * @return Array of merged $panel definition + */ +function mergePanels($panels, $vardefs, $moduleDir, $masterCopy) { + require($masterCopy); + $masterpanels = $viewdefs[$moduleDir][$this->mView]['panels']; + $hasMultiplePanels = $this->hasMultiplePanels($masterpanels); + + if(!$hasMultiplePanels) { + $keys = array_keys($viewdefs[$moduleDir][$this->mView]['panels']); + if(!empty($keys) && count($keys) == 1) { + if(strtolower($keys[0]) == 'default') { + $masterpanels = array('default'=>$viewdefs[$moduleDir][$this->mView]['panels'][$keys[0]]); + } else { + $firstPanel = array_values($viewdefs[$moduleDir][$this->mView]['panels']); + $masterpanels = array('default'=> $firstPanel[0]); + } + } else { + $masterpanels = array('default'=>$viewdefs[$moduleDir][$this->mView]['panels']); + } + } + foreach($masterpanels as $name=>$masterpanel) { + if(isset($panels[$name])) { + // Get all the names in the panel + $existingElements = array(); + $existingLocation = array(); + + foreach($panels[$name] as $rowKey=>$row) { + foreach($row as $colKey=>$column) { + if(is_array($column) && !empty($column['name'])) { + $existingElements[$column['name']] = $column['name']; + $existingLocation[$column['name']] = array("panel"=>$name, "row"=>$rowKey, "col"=>$colKey); + } else if(!is_array($column) && !empty($column)) { + $existingElements[$column] = $column; + $existingLocation[$column] = array("panel"=>$name, "row"=>$rowKey, "col"=>$colKey); + } + } //foreach + } //foreach + + // Now check against the $masterCopy + foreach($masterpanel as $rowKey=>$row) { + + $addRow = array(); + + foreach($row as $colKey=>$column) { + if(is_array($column) && isset($column['name'])) { + $id = $column['name']; + } else if(!is_array($column) && !empty($column)) { + $id = $column; + } else { + continue; + } + if(empty($existingElements[$id])) { + //Only add if + // 1) if it is a required field (as defined in metadata) + // 2) or if it has a customLabel and customCode (a very deep customization) + if((is_array($column) && !empty($column['displayParams']['required'])) || + (is_array($column) && !empty($column['customCode']) && !empty($column['customLabel']))) { + $addRow[] = $column; + } + } else { + //Use definition from master copy instead + $panels[$existingLocation[$id]['panel']][$existingLocation[$id]['row']][$existingLocation[$id]['col']] = $column; + } + } //foreach + + // Add it to the $panels + if(!empty($addRow)) { + $panels[$name][] = $addRow; + } + } //foreach + + } else { + $panels[$name] = $masterpanel; + } + } //foreach + + // We're not done yet... go through the $panels Array now and try to remove duplicate + // or empty panels + foreach($panels as $name=>$panel) { + if(count($panel) == 0 || !isset($masterpanels[$name])) { + unset($panels[$name]); + } + } //foreach + + return $panels; +} + +/** + * mergeTemplateMeta + * This function merges the $templateMeta Array against the $masterCopy's meta data definition + * @param $templateMeta meta data Array to merge + * @param $moduleDir Directory name of the module + * @param $masterCopy file path to the meta data master copy + * @return Array of merged $templateMeta definition + */ +function mergeTemplateMeta($templateMeta, $moduleDir, $masterCopy) { + require($masterCopy); + $masterTemplateMeta = $viewdefs[$moduleDir][$this->mView]['templateMeta']; + + if(isset($masterTemplateMeta['javascript'])) { + //Insert the getJSPath code back into src value + $masterTemplateMeta['javascript'] = preg_replace('/src\s*=\s*[\'\"].*?(modules\/|include\/)([^\.]*?\.js)([^\'\"]*?)[\'\"]/i', 'src="@sq . getJSPath(@sq${1}${2}@sq) . @sq"', $masterTemplateMeta['javascript']); + } + + return $masterTemplateMeta; +} + +function hasRequiredSpanLabel($html) { + if(empty($html)) { + return false; + } + + return preg_match('/\<(div|span) class=(\")?required(\")?\s?>\*<\/(div|span)>/si', $html); +} + +function hasMultiplePanels($panels) { + + if(!isset($panels) || empty($panels) || !is_array($panels)) { + return false; + } + + if(is_array($panels) && (count($panels) == 0 || count($panels) == 1)) { + return false; + } + + foreach($panels as $panel) { + if(!empty($panel) && !is_array($panel)) { + return false; + } else { + foreach($panel as $row) { + if(!empty($row) && !is_array($row)) { + return false; + } //if + } //foreach + } //if-else + } //foreach + + return true; +} + +function getRelateFieldName($mixed='') { + if(!is_array($mixed)) { + return ''; + } else if(count($mixed) == 2){ + $id = ''; + $name = ''; + foreach($mixed as $el) { + if(preg_match('/_id$/', $el)) { + $id = $el; + } else if(preg_match('/_name$/', $el)) { + $name = $el; + } + } + return (!empty($id) && !empty($name)) ? $name : ''; + } + return ''; +} + +function getCustomPanels() { + return $this->mCustomPanels; +} + +/** + * fixTablesWithMissingTr + * This is a very crude function to fix instances where files declared a table as + * instead of . Without this helper function, the + * parsing could messed up. + * + */ +function fixTablesWithMissingTr($tableContents) { + if(preg_match('/(]*?[\/]?>\s*?]*?[\/]?>\s*? tag immediately followed by a tag + */ +function fixRowsWithMissingTr($tableContents) { + if(preg_match('/(<\/tr[^>]*?[\/]?>\s*?]*?[\/]?>\s*? tags + */ +function fixDuplicateTrTags($tableContents) { + if(preg_match('/(]*?[\/]?>\s*?]*?[\/]?>\s*? diff --git a/include/SugarFields/Parsers/QuickCreateMetaParser.php b/include/SugarFields/Parsers/QuickCreateMetaParser.php new file mode 100644 index 00000000..da223dd2 --- /dev/null +++ b/include/SugarFields/Parsers/QuickCreateMetaParser.php @@ -0,0 +1,266 @@ +mView = 'QuickCreate'; +} + +/** + * parse + * + * @param $filePath The file path of the HTML file to parse + * @param $vardefs The module's vardefs + * @param $moduleDir The module's directory + * @param $merge boolean value indicating whether or not to merge the parsed contents + * @param $masterCopy The file path of the mater copy of the metadata file to merge against + * @return String format of metadata contents + **/ +function parse($filePath, $vardefs = array(), $moduleDir = '', $merge=false, $masterCopy=null) { + + global $app_strings; + $contents = file_get_contents($filePath); + + // The contents are not well formed so we add this section to make it easier to parse + $contents = $this->trimHTML($contents) . ''; + $moduleName = ''; + + $forms = $this->getElementsByType("form", $contents); + $tables = $this->getElementsByType("table", $forms[0] . ""); + $mainrow = $this->getElementsByType("tr", $tables[1]); + $rows = substr($mainrow[0], strpos($mainrow[0], "")); + $tablerows = $this->getElementsByType("tr", $rows); + + foreach($tablerows as $trow) { + + $emptyCount = 0; + $tablecolumns = $this->getElementsByType("td", $trow); + $col = array(); + $slot = 0; + + foreach($tablecolumns as $tcols) { + + $sugarAttrLabel = $this->getTagAttribute("sugar", $tcols, "'^slot[^b]+$'"); + $sugarAttrValue = $this->getTagAttribute("sugar", $tcols, "'slot[0-9]+b$'"); + + // If there wasn't any slot numbering/lettering then just default to expect label->vallue pairs + $sugarAttrLabel = count($sugarAttrLabel) != 0 ? $sugarAttrLabel : ($slot % 2 == 0) ? true : false; + $sugarAttrValue = count($sugarAttrValue) != 0 ? $sugarAttrValue : ($slot % 2 == 1) ? true : false; + + $slot++; + + if($sugarAttrValue) { + + $spanValue = strtolower($this->getElementValue("span", $tcols)); + if(empty($spanValue)) { + $spanValue = strtolower($this->getElementValue("slot", $tcols)); + } + if(empty($spanValue)) { + $spanValue = strtolower($this->getElementValue("td", $tcols)); + } + + //Get all the editable form elements' names + $formElementNames = $this->getFormElementsNames($spanValue); + $customField = $this->getCustomField($formElementNames); + + $name = ''; + $readOnly = false; + $fields = null; + $customCode = null; + + if(!empty($customField)) { + // If it's a custom field we just set the name + $name = $customField; + + } else if(empty($formElementNames) && preg_match_all('/[\{]([^\}]*?)[\}]/s', $spanValue, $matches, PREG_SET_ORDER)) { + // We are here if the $spanValue did not contain a form element for editing. + // We will assume that it is read only (since there were no edit form elements) + + + // If there is more than one matching {} value then try to find the right one to key off + // based on vardefs.php file. Also, use the entire spanValue as customCode + if(count($matches) > 1) { + $name = $matches[0][1]; + $customCode = $spanValue; + foreach($matches as $pair) { + if(preg_match("/^(mod[\.]|app[\.]).*?/s", $pair[1])) { + $customCode = str_replace($pair[1], '$'.strtoupper($pair[1]), $customCode); + } else if(!empty($vardefs[$pair[1]])) { + $name = $pair[1]; + $customCode = str_replace($pair[1], '$fields.'.$pair[1].'.value', $customCode); + } + } //foreach + } else { + //If it is only a label, skip + if(preg_match("/^(mod[\.]|app[\.]).*?/s", $matches[0][1])) { + continue; + } else if(preg_match("/^[\$].*?/s", $matches[0][1])) { + $name = '{' . strtoupper($matches[0][1]) . '}'; + } else { + $name = $matches[0][1]; + } + } + + $readOnly = true; + } else if(is_array($formElementNames)) { + + if(count($formElementNames) == 1) { + if(!empty($vardefs[$formElementNames[0]])) { + $name = $formElementNames[0]; + } + } else { + $fields = array(); + foreach($formElementNames as $elementName) { + // What we are doing here is saying that we will add all your fields assuming + // there are none that are of type relate or link. However, if we find such a type + // we'll take the first one found and assume that is the field you want (the SugarFields + // library will handle rendering the popup and select and clear buttons for you). + if(isset($vardefs[$elementName])) { + $type = $vardefs[$elementName]['type']; + if($type != 'relate' && $type != 'link') { + $fields[] = $elementName; + $name = $elementName; + } else { + unset($fields); + $name = $elementName; + break; + } + } + } + } //if-else + } + + // Build the entry + if(preg_match("/' + +'
    ' + +'
    ' + +' ' + +' ' + +' ' + +' ' + +' ' + +' ' + +' ' + +' ' + +' ' + +' ' + +' ' + +' ' + +' ' + +' ' + +' ' + +' ' + +' ' + +' ' + +' ' + +' ' + +' ' + +' ' + +' ' + +' ' + +' ' + +'
    ' + +' {app_strings.LBL_EMAIL_ATTACHMENTS}' + +'
    ' + +'  ' + +'
    ' + +' ' + +'
    ' + +'
    ' + +'  ' + +'
    ' + +'  ' + +'
    ' + +' {app_strings.LBL_EMAIL_ATTACHMENTS2}' + +'
    ' + +'  ' + +'
    ' + +' ' + +'
    ' + //
    ' + +'
    ' + +'  ' + +'
    ' + +'  ' + +'
    ' + +' ' + +'
    ' + +'  ' + +'
    ' + +'
    ' + +'
    ' + +'
    ' + +'
    ' + +' ' + +'
    ' + +'
    ' + +' ' + +' ' + +' ' + +' ' + +' ' + +' ' + +' ' + +'
    ' + +' {app_strings.LBL_EMAIL_TEMPLATES}:' + +'
    ' + +' ' + +'
    ' + +'
    ' + +' ' + +' ' + +' ' + +' ' + +' ' + +' ' + +' ' + +'
    ' + +' {app_strings.LBL_EMAIL_SIGNATURES}:' + +'
    ' + +' ' + +'
    ' + +' ' + +' ' + +' ' + +' ' + +'
    ' + +'  ' + +' {mod_strings.LBL_SEND_IN_PLAIN_TEXT}' + +'
    ' + +'
    ' + +'
    ' + +'
    ' + +'
    '; +// End of File modules/Emails/javascript/composeEmailTemplate.js + +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +SUGAR.email2.templates['displayOneEmail'] = +'
    ' + +'
    ' + +'
    ' + +' ' + +' ' + +' ' + +' ' + +' ' + +' ' + +' ' + +' ' + +' ' + +'
    ' + +' ' + +' ' + +' ' + +' ' + +' ' + +' ' + +' ' + +' ' + +' ' + +' ' + +' ' + +' ' + +' ' + +' ' + +' ' + +' ' + +' ' + +' {meta.cc}' + +' {email.attachments}' + +'
    ' + +' {app_strings.LBL_EMAIL_FROM}:' + +' ' + +' {email.from_addr}' + +'
    ' + +' {app_strings.LBL_EMAIL_SUBJECT}:' + +' ' + +' {email.name}' + +'
    ' + +' {app_strings.LBL_EMAIL_DATE_SENT_BY_SENDER}:' + +' ' + +' {email.date_start} {email.time_start}' + +'
    ' + +' {app_strings.LBL_EMAIL_TO}:' + +' ' + +' {email.toaddrs}' + +'
    ' + +'
    ' + +//' {email.description}' + +'
    ' +;// End of File modules/Emails/javascript/displayOneEmailTemplate.js + +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +SUGAR.email2.templates['viewPrintable'] = '' + +'' + +'' + +'
    ' + +'' + +' ' + +' ' + +' ' + +' ' + +' ' + +' ' + +'
    ' + +' ' + +' ' + +' ' + +' ' + +' ' + +' ' + +' ' + +' ' + +' ' + +' ' + +' ' + +' ' + +' ' + +' ' + +' ' + +' ' + +' ' + +' {email.cc}' + +' {email.attachments}' + +'
    ' + +' {app_strings.LBL_EMAIL_FROM}:' + +' ' + +' {email.from_name} <{email.from_addr}>' + +'
    ' + +' {app_strings.LBL_EMAIL_SUBJECT}:' + +' ' + +' {email.name}' + +'
    ' + +' {app_strings.LBL_EMAIL_DATE_SENT_BY_SENDER}:' + +' ' + +' {email.date_start} {email.time_start}' + +'
    ' + +' {app_strings.LBL_EMAIL_TO}:' + +' ' + +' {email.toaddrs}' + +'
    ' + +'
    ' + +' ' + +' ' + +' ' + +' ' + +'
    ' + +'
    ' + + '{email.description}' + +'
    ' + +'
    ' + +'
    ' + +'
    ' + +''; +// End of File modules/Emails/javascript/viewPrintable.js + +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ +function enableQS(noReload){YAHOO.util.Event.onDOMReady(function(){if(typeof sqs_objects=='undefined'){return;} +var Dom=YAHOO.util.Dom;var qsFields=Dom.getElementsByClassName('sqsEnabled');for(qsField in qsFields){if(typeof qsFields[qsField]=='function'||typeof qsFields[qsField].id=='undefined'){continue;} +form_id=qsFields[qsField].form.getAttribute('id');if(typeof form_id=='object'&&qsFields[qsField].form.getAttribute('real_id')){form_id=qsFields[qsField].form.getAttribute('real_id');} +qs_index_id=form_id+'_'+qsFields[qsField].name;if(typeof sqs_objects[qs_index_id]=='undefined'){qs_index_id=qsFields[qsField].name;if(typeof sqs_objects[qs_index_id]=='undefined'){continue;}} +if(QSProcessedFieldsArray[qs_index_id]){continue;} +var qs_obj=sqs_objects[qs_index_id];var loaded=false;if(!document.forms[qs_obj.form]){continue;} +if(!document.forms[qs_obj.form].elements[qsFields[qsField].id].readOnly&&qs_obj['disable']!=true){combo_id=qs_obj.form+'_'+qsFields[qsField].id;if(Dom.get(combo_id+"_results")){loaded=true} +if(!loaded){QSProcessedFieldsArray[qs_index_id]=true;qsFields[qsField].form_id=form_id;var sqs=sqs_objects[qs_index_id];var resultDiv=document.createElement('div');resultDiv.id=combo_id+"_results";Dom.insertAfter(resultDiv,qsFields[qsField]);var fields=qs_obj.field_list.slice();fields[fields.length]="module";var ds=new YAHOO.util.DataSource("index.php?",{responseType:YAHOO.util.XHRDataSource.TYPE_JSON,responseSchema:{resultsList:'fields',total:'totalCount',fields:fields,metaNode:"fields",metaFields:{total:'totalCount',fields:"fields"}},connMethodPost:true});var forceSelect=!((qsFields[qsField].form&&typeof(qsFields[qsField].form)=='object'&&qsFields[qsField].form.name=='search_form')||qsFields[qsField].className.match('sqsNoAutofill')!=null);var search=new YAHOO.widget.AutoComplete(qsFields[qsField],resultDiv,ds,{typeAhead:forceSelect,forceSelection:forceSelect,fields:fields,sqs:sqs,animSpeed:0.25,qs_obj:qs_obj,inputElement:qsFields[qsField],generateRequest:function(sQuery){var out=SUGAR.util.paramsToUrl({to_pdf:'true',module:'Home',action:'quicksearchQuery',data:encodeURIComponent(YAHOO.lang.JSON.stringify(this.sqs)),query:sQuery});return out;},setFields:function(data,filter){this.updateFields(data,filter);},updateFields:function(data,filter){for(var i in this.fields){for(var key in this.qs_obj.field_list){if(this.fields[i]==this.qs_obj.field_list[key]&&document.forms[this.qs_obj.form].elements[this.qs_obj.populate_list[key]]&&this.qs_obj.populate_list[key].match(filter)){var displayValue=data[i].replace(/&/gi,'&').replace(/</gi,'<').replace(/>/gi,'>').replace(/'/gi,'\'').replace(/"/gi,'"');document.forms[this.qs_obj.form].elements[this.qs_obj.populate_list[key]].value=displayValue;}}}},clearFields:function(){for(var key in this.qs_obj.field_list){if(document.forms[this.qs_obj.form].elements[this.qs_obj.populate_list[key]]){document.forms[this.qs_obj.form].elements[this.qs_obj.populate_list[key]].value="";}} +this.oldValue="";}});if(/^(billing_|shipping_)?account_name$/.exec(qsFields[qsField].name)) +{search.clearFields=function(){};search.setFields=function(data,filter) +{var label_str='';var label_data_str='';var current_label_data_str='';var label_data_hash=new Array();for(var i in this.fields){for(var key in this.qs_obj.field_list){if(this.fields[i]==this.qs_obj.field_list[key]&&document.forms[this.qs_obj.form].elements[this.qs_obj.populate_list[key]]&&document.getElementById(this.qs_obj.populate_list[key]+'_label')&&this.qs_obj.populate_list[key].match(filter)){var displayValue=data[i].replace(/&/gi,'&').replace(/</gi,'<').replace(/>/gi,'>').replace(/'/gi,'\'').replace(/"/gi,'"');var data_label=document.getElementById(this.qs_obj.populate_list[key]+'_label').innerHTML.replace(/\n/gi,'');label_and_data=data_label+' '+displayValue;if(document.forms[this.qs_obj.form].elements[this.qs_obj.populate_list[key]]&&!label_data_hash[data_label]) +{label_str+=data_label+' \n';label_data_str+=label_and_data+'\n';label_data_hash[data_label]=true;current_label_data_str+=data_label+' '+document.forms[this.qs_obj.form].elements[this.qs_obj.populate_list[key]].value+'\n';}}}} +if(label_str!=current_label_data_str&¤t_label_data_str!=label_data_str){module_key=(typeof document.forms[form_id].elements['module']!='undefined')?document.forms[form_id].elements['module'].value:'app_strings';warning_label=SUGAR.language.translate(module_key,'NTC_OVERWRITE_ADDRESS_PHONE_CONFIRM')+'\n\n'+label_data_str;if(!confirm(warning_label)) +{this.updateFields(data,/account_id/);}else{if(Dom.get('shipping_checkbox')) +{if(this.inputElement.id=='shipping_account_name') +{filter=Dom.get('shipping_checkbox').checked?/(account_id|office_phone)/:filter;}else if(this.inputElement.id=='billing_account_name'){filter=Dom.get('shipping_checkbox').checked?filter:/(account_id|office_phone|billing)/;}}else if(Dom.get('alt_checkbox')){filter=Dom.get('alt_checkbox').checked?filter:/^(?!alt)/;} +this.updateFields(data,filter);}}else{this.updateFields(data,filter);}};} +if(typeof(SUGAR.config.quicksearch_querydelay)!='undefined'){search.queryDelay=SUGAR.config.quicksearch_querydelay;} +search.itemSelectEvent.subscribe(function(e,args){var data=args[2];var fields=this.fields;this.setFields(data,/\S/);if(typeof(this.qs_obj['post_onblur_function'])!='undefined'){collection_extended=new Array();for(var i in fields){for(var key in this.qs_obj.field_list){if(fields[i]==this.qs_obj.field_list[key]){collection_extended[this.qs_obj.field_list[key]]=data[i];}}} +eval(this.qs_obj['post_onblur_function']+'(collection_extended, this.qs_obj.id)');}});search.textboxFocusEvent.subscribe(function(){this.oldValue=this.getInputEl().value;});search.selectionEnforceEvent.subscribe(function(e,args){if(this.oldValue!=args[1]){this.clearFields();}else{this.getInputEl().value=this.oldValue;}});search.dataReturnEvent.subscribe(function(e,args){if(this.getInputEl().value.length==0&&args[2].length>0){var data=[];for(var key in this.qs_obj.field_list){data[data.length]=args[2][0][this.qs_obj.field_list[key]];} +this.getInputEl().value=data[this.key];this.itemSelectEvent.fire(this,"",data);}});search.typeAheadEvent.subscribe(function(e,args){this.getInputEl().value=this.getInputEl().value.replace(/&/gi,'&').replace(/</gi,'<').replace(/>/gi,'>').replace(/'/gi,'\'').replace(/"/gi,'"');});if(typeof QSFieldsArray[combo_id]=='undefined'&&qsFields[qsField].id){QSFieldsArray[combo_id]=search;}}}}});} +function registerSingleSmartInputListener(input){if((c=input.className)&&(c.indexOf("sqsEnabled")!=-1)){enableQS(true);}} +if(typeof QSFieldsArray=='undefined'){QSFieldsArray=new Array();QSProcessedFieldsArray=new Array();}// End of File include/javascript/quicksearch.js + diff --git a/include/javascript/sugar_grp_overlib.js b/include/javascript/sugar_grp_overlib.js new file mode 100644 index 00000000..d5259a89 --- /dev/null +++ b/include/javascript/sugar_grp_overlib.js @@ -0,0 +1,384 @@ +/* + Artistic License 2.0 + + Copyright (c) 2000-2006, The Perl Foundation. + + Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. + Preamble + + This license establishes the terms under which a given free software Package may be copied, modified, distributed, and/or redistributed. The intent is that the Copyright Holder maintains some artistic control over the development of that Package while still keeping the Package available as open source and free software. + + You are always permitted to make arrangements wholly outside of this license directly with the Copyright Holder of a given Package. If the terms of this license do not permit the full use that you propose to make of the Package, you should contact the Copyright Holder and seek a different licensing arrangement. + Definitions + + "Copyright Holder" means the individual(s) or organization(s) named in the copyright notice for the entire Package. + + "Contributor" means any party that has contributed code or other material to the Package, in accordance with the Copyright Holder's procedures. + + "You" and "your" means any person who would like to copy, distribute, or modify the Package. + + "Package" means the collection of files distributed by the Copyright Holder, and derivatives of that collection and/or of those files. A given Package may consist of either the Standard Version, or a Modified Version. + + "Distribute" means providing a copy of the Package or making it accessible to anyone else, or in the case of a company or organization, to others outside of your company or organization. + + "Distributor Fee" means any fee that you charge for Distributing this Package or providing support for this Package to another party. It does not mean licensing fees. + + "Standard Version" refers to the Package if it has not been modified, or has been modified only in ways explicitly requested by the Copyright Holder. + + "Modified Version" means the Package, if it has been changed, and such changes were not explicitly requested by the Copyright Holder. + + "Original License" means this Artistic License as Distributed with the Standard Version of the Package, in its current version or as it may be modified by The Perl Foundation in the future. + + "Source" form means the source code, documentation source, and configuration files for the Package. + + "Compiled" form means the compiled bytecode, object code, binary, or any other form resulting from mechanical transformation or translation of the Source form. + Permission for Use and Modification Without Distribution + + (1) You are permitted to use the Standard Version and create and use Modified Versions for any purpose without restriction, provided that you do not Distribute the Modified Version. + Permissions for Redistribution of the Standard Version + + (2) You may Distribute verbatim copies of the Source form of the Standard Version of this Package in any medium without restriction, either gratis or for a Distributor Fee, provided that you duplicate all of the original copyright notices and associated disclaimers. At your discretion, such verbatim copies may or may not include a Compiled form of the Package. + + (3) You may apply any bug fixes, portability changes, and other modifications made available from the Copyright Holder. The resulting Package will still be considered the Standard Version, and as such will be subject to the Original License. + Distribution of Modified Versions of the Package as Source + + (4) You may Distribute your Modified Version as Source (either gratis or for a Distributor Fee, and with or without a Compiled form of the Modified Version) provided that you clearly document how it differs from the Standard Version, including, but not limited to, documenting any non-standard features, executables, or modules, and provided that you do at least ONE of the following: + + (a) make the Modified Version available to the Copyright Holder of the Standard Version, under the Original License, so that the Copyright Holder may include your modifications in the Standard Version. + (b) ensure that installation of your Modified Version does not prevent the user installing or running the Standard Version. In addition, the Modified Version must bear a name that is different from the name of the Standard Version. + (c) allow anyone who receives a copy of the Modified Version to make the Source form of the Modified Version available to others under + (i) the Original License or + (ii) a license that permits the licensee to freely copy, modify and redistribute the Modified Version using the same licensing terms that apply to the copy that the licensee received, and requires that the Source form of the Modified Version, and of any works derived from it, be made freely available in that license fees are prohibited but Distributor Fees are allowed. + Distribution of Compiled Forms of the Standard Version or Modified Versions without the Source + + (5) You may Distribute Compiled forms of the Standard Version without the Source, provided that you include complete instructions on how to get the Source of the Standard Version. Such instructions must be valid at the time of your distribution. If these instructions, at any time while you are carrying out such distribution, become invalid, you must provide new instructions on demand or cease further distribution. If you provide valid instructions or cease distribution within thirty days after you become aware that the instructions are invalid, then you do not forfeit any of your rights under this license. + + (6) You may Distribute a Modified Version in Compiled form without the Source, provided that you comply with Section 4 with respect to the Source of the Modified Version. + Aggregating or Linking the Package + + (7) You may aggregate the Package (either the Standard Version or Modified Version) with other packages and Distribute the resulting aggregation provided that you do not charge a licensing fee for the Package. Distributor Fees are permitted, and licensing fees for other components in the aggregation are permitted. The terms of this license apply to the use and Distribution of the Standard or Modified Versions as included in the aggregation. + + (8) You are permitted to link Modified and Standard Versions with other works, to embed the Package in a larger work of your own, or to build stand-alone binary or bytecode versions of applications that include the Package, and Distribute the result without restriction, provided the result does not expose a direct interface to the Package. + Items That are Not Considered Part of a Modified Version + + (9) Works (including, but not limited to, modules and scripts) that merely extend or make use of the Package, do not, by themselves, cause the Package to be a Modified Version. In addition, such works are not considered parts of the Package itself, and are not subject to the terms of this license. + General Provisions + + (10) Any use, modification, and distribution of the Standard or Modified Versions is governed by this Artistic License. By using, modifying or distributing the Package, you accept this license. Do not use, modify, or distribute the Package, if you do not accept this license. + + (11) If your Modified Version has been derived from a Modified Version made by someone other than you, you are nevertheless required to ensure that your Modified Version complies with the requirements of this license. + + (12) This license does not grant you the right to use any trademark, service mark, tradename, or logo of the Copyright Holder. + + (13) This license includes the non-exclusive, worldwide, free-of-charge patent license to make, have made, use, offer to sell, sell, import and otherwise transfer the Package with respect to any patent claims licensable by the Copyright Holder that are necessarily infringed by the Package. If you institute patent litigation (including a cross-claim or counterclaim) against any party alleging that the Package constitutes direct or contributory patent infringement, then this Artistic License to you shall terminate on the date that such litigation is filed. + + (14) Disclaimer of Warranty: THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY YOUR LOCAL LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR CONTRIBUTOR WILL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +var OLloaded=0,pmCnt=1,pMtr=new Array(),OLcmdLine=new Array(),OLrunTime=new Array(),OLv,OLudf,OLpct=new Array("83%","67%","83%","100%","117%","150%","200%","267%"),OLrefXY,OLbubblePI=0,OLcrossframePI=0,OLdebugPI=0,OLdraggablePI=0,OLexclusivePI=0,OLfilterPI=0,OLfunctionPI=0,OLhidePI=0,OLiframePI=0,OLovertwoPI=0,OLscrollPI=0,OLshadowPI=0,OLprintPI=0;if(typeof OLgateOK=='undefined')var OLgateOK=1;var OLp1or2c='inarray,caparray,caption,closetext,right,left,center,autostatuscap,padx,pady,' ++'below,above,vcenter,donothing',OLp1or2co='nofollow,background,offsetx,offsety,fgcolor,' ++'bgcolor,cgcolor,textcolor,capcolor,width,wrap,wrapmax,height,border,base,status,autostatus,' ++'snapx,snapy,fixx,fixy,relx,rely,midx,midy,ref,refc,refp,refx,refy,fgbackground,bgbackground,' ++'cgbackground,fullhtml,capicon,textfont,captionfont,textsize,captionsize,timeout,delay,hauto,' ++'vauto,nojustx,nojusty,fgclass,bgclass,cgclass,capbelow,textpadding,textfontclass,' ++'captionpadding,captionfontclass,sticky,noclose,mouseoff,offdelay,closecolor,closefont,' ++'closesize,closeclick,closetitle,closefontclass,decode',OLp1or2o='text,cap,close,hpos,vpos,' ++'padxl,padxr,padyt,padyb',OLp1co='label',OLp1or2=OLp1or2co+','+OLp1or2o,OLp1=OLp1co+','+'frame';OLregCmds(OLp1or2c+','+OLp1or2co+','+OLp1co);function OLud(v){return eval('typeof ol_'+v+'=="undefined"')?1:0;} +if(OLud('fgcolor'))var ol_fgcolor="#ccccff";if(OLud('bgcolor'))var ol_bgcolor="#333399";if(OLud('cgcolor'))var ol_cgcolor="#333399";if(OLud('textcolor'))var ol_textcolor="#000000";if(OLud('capcolor'))var ol_capcolor="#ffffff";if(OLud('closecolor'))var ol_closecolor="#eeeeff";if(OLud('textfont'))var ol_textfont="Verdana,Arial,Helvetica";if(OLud('captionfont'))var ol_captionfont="Verdana,Arial,Helvetica";if(OLud('closefont'))var ol_closefont="Verdana,Arial,Helvetica";if(OLud('textsize'))var ol_textsize=1;if(OLud('captionsize'))var ol_captionsize=1;if(OLud('closesize'))var ol_closesize=1;if(OLud('fgclass'))var ol_fgclass="";if(OLud('bgclass'))var ol_bgclass="";if(OLud('cgclass'))var ol_cgclass="";if(OLud('textpadding'))var ol_textpadding=2;if(OLud('textfontclass'))var ol_textfontclass="";if(OLud('captionpadding'))var ol_captionpadding=2;if(OLud('captionfontclass'))var ol_captionfontclass="";if(OLud('closefontclass'))var ol_closefontclass="";if(OLud('close'))var ol_close="Close";if(OLud('closeclick'))var ol_closeclick=0;if(OLud('closetitle'))var ol_closetitle="Click to Close";if(OLud('text'))var ol_text="Default Text";if(OLud('cap'))var ol_cap="";if(OLud('capbelow'))var ol_capbelow=0;if(OLud('background'))var ol_background="";if(OLud('width'))var ol_width=200;if(OLud('wrap'))var ol_wrap=0;if(OLud('wrapmax'))var ol_wrapmax=0;if(OLud('height'))var ol_height=-1;if(OLud('border'))var ol_border=1;if(OLud('base'))var ol_base=0;if(OLud('offsetx'))var ol_offsetx=10;if(OLud('offsety'))var ol_offsety=10;if(OLud('sticky'))var ol_sticky=0;if(OLud('nofollow'))var ol_nofollow=0;if(OLud('noclose'))var ol_noclose=0;if(OLud('mouseoff'))var ol_mouseoff=0;if(OLud('offdelay'))var ol_offdelay=300;if(OLud('hpos'))var ol_hpos=RIGHT;if(OLud('vpos'))var ol_vpos=BELOW;if(OLud('status'))var ol_status="";if(OLud('autostatus'))var ol_autostatus=0;if(OLud('snapx'))var ol_snapx=0;if(OLud('snapy'))var ol_snapy=0;if(OLud('fixx'))var ol_fixx=-1;if(OLud('fixy'))var ol_fixy=-1;if(OLud('relx'))var ol_relx=null;if(OLud('rely'))var ol_rely=null;if(OLud('midx'))var ol_midx=null;if(OLud('midy'))var ol_midy=null;if(OLud('ref'))var ol_ref="";if(OLud('refc'))var ol_refc='UL';if(OLud('refp'))var ol_refp='UL';if(OLud('refx'))var ol_refx=0;if(OLud('refy'))var ol_refy=0;if(OLud('fgbackground'))var ol_fgbackground="";if(OLud('bgbackground'))var ol_bgbackground="";if(OLud('cgbackground'))var ol_cgbackground="";if(OLud('padxl'))var ol_padxl=1;if(OLud('padxr'))var ol_padxr=1;if(OLud('padyt'))var ol_padyt=1;if(OLud('padyb'))var ol_padyb=1;if(OLud('fullhtml'))var ol_fullhtml=0;if(OLud('capicon'))var ol_capicon="";if(OLud('frame'))var ol_frame=self;if(OLud('timeout'))var ol_timeout=0;if(OLud('delay'))var ol_delay=0;if(OLud('hauto'))var ol_hauto=0;if(OLud('vauto'))var ol_vauto=0;if(OLud('nojustx'))var ol_nojustx=0;if(OLud('nojusty'))var ol_nojusty=0;if(OLud('label'))var ol_label="";if(OLud('decode'))var ol_decode=0;if(OLud('texts'))var ol_texts=new Array("Text 0","Text 1");if(OLud('caps'))var ol_caps=new Array("Caption 0","Caption 1");var o3_text="",o3_cap="",o3_sticky=0,o3_nofollow=0,o3_background="",o3_noclose=0,o3_mouseoff=0,o3_offdelay=300,o3_hpos=RIGHT,o3_offsetx=10,o3_offsety=10,o3_fgcolor="",o3_bgcolor="",o3_cgcolor="",o3_textcolor="",o3_capcolor="",o3_closecolor="",o3_width=200,o3_wrap=0,o3_wrapmax=0,o3_height=-1,o3_border=1,o3_base=0,o3_status="",o3_autostatus=0,o3_snapx=0,o3_snapy=0,o3_fixx=-1,o3_fixy=-1,o3_relx=null,o3_rely=null,o3_midx=null,o3_midy=null,o3_ref="",o3_refc='UL',o3_refp='UL',o3_refx=0,o3_refy=0,o3_fgbackground="",o3_bgbackground="",o3_cgbackground="",o3_padxl=0,o3_padxr=0,o3_padyt=0,o3_padyb=0,o3_fullhtml=0,o3_vpos=BELOW,o3_capicon="",o3_textfont="Verdana,Arial,Helvetica",o3_captionfont="",o3_closefont="",o3_textsize=1,o3_captionsize=1,o3_closesize=1,o3_frame=self,o3_timeout=0,o3_delay=0,o3_hauto=0,o3_vauto=0,o3_nojustx=0,o3_nojusty=0,o3_close="",o3_closeclick=0,o3_closetitle="",o3_fgclass="",o3_bgclass="",o3_cgclass="",o3_textpadding=2,o3_textfontclass="",o3_captionpadding=2,o3_captionfontclass="",o3_closefontclass="",o3_capbelow=0,o3_label="",o3_decode=0,CSSOFF=DONOTHING,CSSCLASS=DONOTHING,OLdelayid=0,OLtimerid=0,OLshowid=0,OLndt=0,over=null,OLfnRef="",OLhover=0,OLx=0,OLy=0,OLshowingsticky=0,OLallowmove=0,OLcC=null,OLua=navigator.userAgent.toLowerCase(),OLns4=(navigator.appName=='Netscape'&&parseInt(navigator.appVersion)==4),OLns6=(document.getElementById)?1:0,OLie4=(document.all)?1:0,OLgek=(OLv=OLua.match(/gecko\/(\d{8})/i))?parseInt(OLv[1]):0,OLmac=(OLua.indexOf('mac')>=0)?1:0,OLsaf=(OLua.indexOf('safari')>=0)?1:0,OLkon=(OLua.indexOf('konqueror')>=0)?1:0,OLkht=(OLsaf||OLkon)?1:0,OLopr=(OLua.indexOf('opera')>=0)?1:0,OLop7=(OLopr&&document.createTextNode)?1:0;if(OLopr){OLns4=OLns6=0;if(!OLop7)OLie4=0;} +var OLieM=((OLie4&&OLmac)&&!(OLkht||OLopr))?1:0,OLie5=0,OLie55=0;if(OLie4&&!OLop7){if((OLv=OLua.match(/msie (\d\.\d+)\.*/i))&&(OLv=parseFloat(OLv[1]))>=5.0){OLie5=1;OLns6=0;if(OLv>=5.5)OLie55=1;}if(OLns6)OLie4=0;} +if(OLns4)window.onresize=function(){location.reload();} +var OLchkMh=1,OLdw;if(OLns4||OLie4||OLns6)OLmh();else{overlib=nd=cClick=OLpageDefaults=no_overlib;} +function overlib(){if(!(OLloaded&&OLgateOK))return;if((OLexclusivePI)&&OLisExclusive(arguments))return true;if(OLchkMh)OLmh();if(OLndt&&!OLtimerid)OLndt=0;if(over)cClick();OLload(OLp1or2);OLload(OLp1);OLfnRef="";OLhover=0;OLsetRunTimeVar();OLparseTokens('o3_',arguments);if(!(over=OLmkLyr()))return false;if(o3_decode)OLdecode();if(OLprintPI)OLchkPrint();if(OLbubblePI)OLchkForBubbleEffect();if(OLdebugPI)OLsetDebugCanShow();if(OLshadowPI)OLinitShadow();if(OLiframePI)OLinitIfs();if(OLfilterPI)OLinitFilterLyr();if(OLexclusivePI&&o3_exclusive&&o3_exclusivestatus!="")o3_status=o3_exclusivestatus;else if(o3_autostatus==2&&o3_cap!="")o3_status=o3_cap;else if(o3_autostatus==1&&o3_text!="")o3_status=o3_text;if(!o3_delay){return OLmain();}else{OLdelayid=setTimeout("OLmain()",o3_delay);if(o3_status!=""){self.status=o3_status;return true;} +else if(!(OLop7&&event&&event.type=='mouseover'))return false;}} +function nd(time){if(OLloaded&&OLgateOK){if(!((OLexclusivePI)&&OLisExclusive())){if(time&&over&&!o3_delay){if(OLtimerid>0)clearTimeout(OLtimerid);OLtimerid=(OLhover&&o3_frame==self&&!OLcursorOff())?0:setTimeout("cClick()",(o3_timeout=OLndt=time));}else{if(!OLshowingsticky){OLallowmove=0;if(over)OLhideObject(over);}}}} +return false;} +function cClick(){if(OLloaded&&OLgateOK){OLhover=0;if(over){if(OLovertwoPI&&over==over2)cClick2();OLhideObject(over);OLshowingsticky=0;}} +return false;} +function OLpageDefaults(){OLparseTokens('ol_',arguments);} +function no_overlib(){return false;} +function OLmain(){o3_delay=0;if(o3_frame==self){if(o3_noclose)OLoptMOUSEOFF(0);else if(o3_mouseoff)OLoptMOUSEOFF(1);} +if(o3_sticky)OLshowingsticky=1;OLdoLyr();OLallowmove=0;if(o3_timeout>0){if(OLtimerid>0)clearTimeout(OLtimerid);OLtimerid=setTimeout("cClick()",o3_timeout);} +if(o3_ref){OLrefXY=OLgetRefXY(o3_ref);if(OLrefXY[0]==null){o3_ref="";o3_midx=0;o3_midy=0;}} +OLdisp(o3_status);if(OLdraggablePI)OLcheckDrag();if(o3_status!="")return true;else if(!(OLop7&&event&&event.type=='mouseover'))return false;} +function OLload(c){var i,m=c.split(',');for(i=0;i
    ');d=fd.all[id];}else{d=fd.createElement('div');if(d){d.id=id;fd.body.appendChild(d);}}if(!d)return null;if(OLns4)d.zIndex=z;else{var o=d.style;o.position='absolute';o.visibility='hidden';o.zIndex=z;}} +return d;} +function OLdoLyr(){if(o3_background==''&&!o3_fullhtml){if(o3_fgbackground!='')o3_fgbackground=' background="'+o3_fgbackground+'"';if(o3_bgbackground!='')o3_bgbackground=' background="'+o3_bgbackground+'"';if(o3_cgbackground!='')o3_cgbackground=' background="'+o3_cgbackground+'"';if(o3_fgcolor!='')o3_fgcolor=' bgcolor="'+o3_fgcolor+'"';if(o3_bgcolor!='')o3_bgcolor=' bgcolor="'+o3_bgcolor+'"';if(o3_cgcolor!='')o3_cgcolor=' bgcolor="'+o3_cgcolor+'"';if(o3_height>0)o3_height=' height="'+o3_height+'"';else o3_height='';} +if(!OLns4)OLrepositionTo(over,(OLns6?20:0),0);var lyrHtml=OLdoLGF();if(o3_sticky&&OLtimerid>0){clearTimeout(OLtimerid);OLtimerid=0;} +if(o3_wrap&&!o3_fullhtml){OLlayerWrite(lyrHtml);o3_width=(OLns4?over.clip.width:over.offsetWidth);if(OLns4&&o3_wrapmax<1)o3_wrapmax=o3_frame.innerWidth-40;o3_wrap=0;if(o3_wrapmax>0&&o3_width>o3_wrapmax)o3_width=o3_wrapmax;lyrHtml=OLdoLGF();} +OLlayerWrite(lyrHtml);o3_width=(OLns4?over.clip.width:over.offsetWidth);if(OLbubblePI)OLgenerateBubble(lyrHtml);} +function OLcontentSimple(txt){var t=OLbgLGF()+OLfgLGF(txt)+OLbaseLGF();OLsetBackground('');return t;} +function OLcontentCaption(txt,title,close){var closing=(OLprintPI?OLprintCapLGF():''),closeevent='onmouseover',caption,t,cC='javascript:return '+OLfnRef+(OLovertwoPI&&over==over2?'cClick2();':'cClick();');if(o3_closeclick)closeevent=(o3_closetitle?'title="'+o3_closetitle+'" ':'')+'onclick';if(o3_capicon!='')o3_capicon=' ';if(close){closing+='':'>'+OLlgfUtil(0,'','span',o3_closecolor,o3_closefont,o3_closesize))+close ++(o3_closefontclass?'':OLlgfUtil(1,'','span'))+'';} +caption='':'>')+(o3_captionfontclass?'
    ':'' ++OLlgfUtil(0,'','',o3_capcolor,o3_captionfont,o3_captionsize))+o3_capicon+title ++OLlgfUtil(1,'','')+(o3_captionfontclass?'':'')+closing+'
    ';t=OLbgLGF()+(o3_capbelow?OLfgLGF(txt)+caption:caption+OLfgLGF(txt))+OLbaseLGF();OLsetBackground('');return t;} +function OLcontentBackground(txt,image,hasfullhtml){var t;if(hasfullhtml){t=txt;}else{t='' ++OLlgfUtil(0,o3_textfontclass,'div',o3_textcolor,o3_textfont,o3_textsize)+txt+ +OLlgfUtil(1,'','div')+'';} +OLsetBackground(image);return t;} +function OLbgLGF(){return'';} +function OLfgLGF(t){return'' ++OLlgfUtil(0,o3_textfontclass,'div',o3_textcolor,o3_textfont,o3_textsize)+t ++(OLprintPI?OLprintFgLGF():'')+OLlgfUtil(1,'','div')+'';} +function OLlgfUtil(end,tfc,ele,col,fac,siz){if(end)return('');else return(tfc?'
    ':('<'+(OLns4?'font color="'+col+'" face="'+OLquoteMultiNameFonts(fac)+'" size="'+siz:ele ++' style="color:'+col+';font-family:'+OLquoteMultiNameFonts(fac)+';font-size:'+siz+';' ++(ele=='span'?'text-decoration:underline;':''))+'">'));} +function OLquoteMultiNameFonts(f){var i,v,pM=f.split(',');for(i=0;i0&&!o3_wrap)?('
    '):'')+'';} +function OLwd(a){return(o3_wrap?'':' width="'+(!a?'100%':(a==1?o3_width:(o3_width-o3_padxl-o3_padxr)))+'"');} +function OLsetBackground(i){if(i==''){if(OLns4)over.background.src=null;else{if(OLns6)over.style.width='';over.style.backgroundImage='none';}}else{if(OLns4)over.background.src=i;else{if(OLns6)over.style.width=o3_width+'px';over.style.backgroundImage='url('+i+')';}}} +function OLdisp(s){if(!OLallowmove){if(OLshadowPI)OLdispShadow();if(OLiframePI)OLdispIfs();OLplaceLayer();if(OLndt)OLshowObject(over);else OLshowid=setTimeout("OLshowObject(over)",1);OLallowmove=(o3_sticky||o3_nofollow)?0:1;}OLndt=0;if(s!="")self.status=s;} +function OLplaceLayer(){var snp,X,Y,pgLeft,pgTop,pWd=o3_width,pHt,iWd=100,iHt=100,SB=0,LM=0,CX=0,TM=0,BM=0,CY=0,o=OLfd(),nsb=(OLgek>=20010505&&!o3_frame.scrollbars.visible)?1:0;if(!OLkht&&o&&o.clientWidth)iWd=o.clientWidth;else if(o3_frame.innerWidth){SB=Math.ceil(1.4*(o3_frame.outerWidth-o3_frame.innerWidth));if(SB>20)SB=20;iWd=o3_frame.innerWidth;} +pgLeft=(OLie4)?o.scrollLeft:o3_frame.pageXOffset;if(OLie55&&OLfilterPI&&o3_filter&&o3_filtershadow)SB=CX=5;else +if((OLshadowPI)&&bkdrop&&o3_shadow&&o3_shadowx){SB+=((o3_shadowx>0)?o3_shadowx:0);LM=((o3_shadowx<0)?Math.abs(o3_shadowx):0);CX=Math.abs(o3_shadowx);} +if(o3_ref!=""||o3_fixx>-1||o3_relx!=null||o3_midx!=null){if(o3_ref!=""){X=OLrefXY[0];if(OLie55&&OLfilterPI&&o3_filter&&o3_filtershadow){if(o3_refp=='UR'||o3_refp=='LR')X-=5;} +else if((OLshadowPI)&&bkdrop&&o3_shadow&&o3_shadowx){if(o3_shadowx<0&&(o3_refp=='UL'||o3_refp=='LL'))X-=o3_shadowx;else +if(o3_shadowx>0&&(o3_refp=='UR'||o3_refp=='LR'))X-=o3_shadowx;}}else{if(o3_midx!=null){X=parseInt(pgLeft+((iWd-pWd-SB-LM)/2)+o3_midx);}else{if(o3_relx!=null){if(o3_relx>=0)X=pgLeft+o3_relx+LM;else X=pgLeft+o3_relx+iWd-pWd-SB;}else{X=o3_fixx+LM;}}}}else{if(o3_hauto){if(o3_hpos==LEFT&&OLx-pgLeftiWd/2&&OLx+pWd+o3_offsetx>pgLeft+iWd-SB)o3_hpos=LEFT;} +X=(o3_hpos==CENTER)?parseInt(OLx-((pWd+CX)/2)+o3_offsetx):(o3_hpos==LEFT)?OLx-o3_offsetx-pWd:OLx+o3_offsetx;if(o3_snapx>1){snp=X%o3_snapx;if(o3_hpos==LEFT){X=X-(o3_snapx+snp);}else{X=X+(o3_snapx-snp);}}} +if(!o3_nojustx&&X+pWd>pgLeft+iWd-SB) +X=iWd+pgLeft-pWd-SB;if(!o3_nojustx&&X-LM0)?o3_shadowy:0;CY=Math.abs(o3_shadowy);} +if(o3_ref!=""||o3_fixy>-1||o3_rely!=null||o3_midy!=null){if(o3_ref!=""){Y=OLrefXY[1];if(OLie55&&OLfilterPI&&o3_filter&&o3_filtershadow){if(o3_refp=='LL'||o3_refp=='LR')Y-=5;}else if((OLshadowPI)&&bkdrop&&o3_shadow&&o3_shadowy){if(o3_shadowy<0&&(o3_refp=='UL'||o3_refp=='UR'))Y-=o3_shadowy;else +if(o3_shadowy>0&&(o3_refp=='LL'||o3_refp=='LR'))Y-=o3_shadowy;}}else{if(o3_midy!=null){Y=parseInt(pgTop+((iHt-pHt-CY)/2)+o3_midy);}else{if(o3_rely!=null){if(o3_rely>=0)Y=pgTop+o3_rely+TM;else Y=pgTop+o3_rely+iHt-pHt-BM;}else{Y=o3_fixy+TM;}}}}else{if(o3_vauto){if(o3_vpos==ABOVE&&OLy-pgTopiHt/2&&OLy+pHt+o3_offsety+((OLns4||OLkht)?17:0)>pgTop+iHt-BM) +o3_vpos=ABOVE;}Y=(o3_vpos==VCENTER)?parseInt(OLy-((pHt+CY)/2)+o3_offsety):(o3_vpos==ABOVE)?OLy-(pHt+o3_offsety+BM):OLy+o3_offsety+TM;if(o3_snapy>1){snp=Y%o3_snapy;if(pHt>0&&o3_vpos==ABOVE){Y=Y-(o3_snapy+snp);}else{Y=Y+(o3_snapy-snp);}}} +if(!o3_nojusty&&Y+pHt+BM>pgTop+iHt)Y=pgTop+iHt-pHt-BM;if(!o3_nojusty&&Y-TM1){ob=o[0];rXY[0]+=o[0].x+o[1].pageX;rXY[1]+=o[0].y+o[1].pageY;}else{if((o.toString().indexOf('Image')!=-1)||(o.toString().indexOf('Anchor')!=-1)){rXY[0]+=o.x;rXY[1]+=o.y;}else{rXY[0]+=o.pageX;rXY[1]+=o.pageY;}}}else{rXY[0]+=OLpageLoc(o,'Left');rXY[1]+=OLpageLoc(o,'Top');} +of=OLgetRefOffsets(ob);rXY[0]+=of[0];rXY[1]+=of[1];return rXY;} +function OLgetRef(l){var r=OLgetRefById(l);return(r)?r:OLgetRefByName(l);} +function OLgetRefById(l,d){var r="",j;l=(l||'overDiv');d=(d||o3_frame.document);if(OLie4&&d.all){return d.all[l];}else if(d.getElementById){return d.getElementById(l);}else if(d.layers&&d.layers.length>0){if(d.layers[l])return d.layers[l];for(j=0;j0){for(j=0;j0)return r;else if(r)return[r,d.layers[j]];}} +return null;} +function OLgetRefOffsets(o){var c=o3_refc.toUpperCase(),p=o3_refp.toUpperCase(),W=0,H=0,pW=0,pH=0,of=[0,0];pW=(OLbubblePI&&o3_bubble)?o3_width:OLns4?over.clip.width:over.offsetWidth;pH=(OLbubblePI&&o3_bubble)?OLbubbleHt:OLns4?over.clip.height:over.offsetHeight;if((!OLop7)&&o.toString().indexOf('Image')!=-1){W=o.width;H=o.height;}else if((!OLop7)&&o.toString().indexOf('Anchor')!=-1){c=o3_refc='UL';}else{W=(OLns4)?o.clip.width:o.offsetWidth;H=(OLns4)?o.clip.height:o.offsetHeight;} +if((OLns4||(OLns6&&OLgek))&&o.border){W+=2*parseInt(o.border);H+=2*parseInt(o.border);} +if(c=='UL'){of=(p=='UR')?[-pW,0]:(p=='LL')?[0,-pH]:(p=='LR')?[-pW,-pH]:[0,0];}else if(c=='UR'){of=(p=='UR')?[W-pW,0]:(p=='LL')?[W,-pH]:(p=='LR')?[W-pW,-pH]:[W,0];}else if(c=='LL'){of=(p=='UR')?[-pW,H]:(p=='LL')?[0,H-pH]:(p=='LR')?[-pW,H-pH]:[0,H];}else if(c=='LR'){of=(p=='UR')?[W-pW,H]:(p=='LL')?[W,H-pH]:(p=='LR')?[W-pW,H-pH]:[W,H];} +return of;} +function OLpageLoc(o,t){var l=0;while(o.offsetParent&&o.offsetParent.tagName.toLowerCase()!='html'){l+=o['offset'+t];o=o.offsetParent;}l+=o['offset'+t];return l;} +function OLmouseMove(e){var e=(e||event);OLcC=(OLovertwoPI&&over2&&over==over2?cClick2:cClick);OLx=(e.pageX||e.clientX+OLfd().scrollLeft);OLy=(e.pageY||e.clientY+OLfd().scrollTop);if((OLallowmove&&over)&&(o3_frame==self||over==OLgetRefById())){OLplaceLayer();if(OLhidePI)OLhideUtil(0,1,1,0,0,0);} +if(OLhover&&over&&o3_frame==self&&OLcursorOff())if(o3_offdelay<1)OLcC();else +{if(OLtimerid>0)clearTimeout(OLtimerid);OLtimerid=setTimeout("OLcC()",o3_offdelay);}} +function OLmh(){var fN,f,j,k,s,mh=OLmouseMove,w=(OLns4&&window.onmousemove),re=/function[ ]*(\w*)\(/;OLdw=document;if(document.onmousemove||w){if(w)OLdw=window;f=OLdw.onmousemove.toString();fN=f.match(re);if(!fN||fN[1]=='anonymous'||fN[1]=='OLmouseMove'){OLchkMh=0;return;} +if(fN[1])s=fN[1]+'(e)';else{j=f.indexOf('{');k=f.lastIndexOf('}')+1;s=f.substring(j,k);} +s+=';OLmouseMove(e);';mh=new Function('e',s);} +OLdw.onmousemove=mh;if(OLns4)OLdw.captureEvents(Event.MOUSEMOVE);} +function OLparseTokens(pf,ar){var i,v,md=-1,par=(pf!='ol_'),p=OLpar,q=OLparQuo,t=OLtoggle;OLudf=(par&&!ar.length?1:0);for(i=0;i=0)?1:0');} +function OLhasDims(s){return/[%\-a-z]+$/.test(s);} +function OLfontSize(){var i;if(OLhasDims(o3_textsize)){if(OLns4)o3_textsize="2";}else +if(!OLns4){i=parseInt(o3_textsize);o3_textsize=(i>0&&i<8)?OLpct[i]:OLpct[0];} +if(OLhasDims(o3_captionsize)){if(OLns4)o3_captionsize="2";}else +if(!OLns4){i=parseInt(o3_captionsize);o3_captionsize=(i>0&&i<8)?OLpct[i]:OLpct[0];} +if(OLhasDims(o3_closesize)){if(OLns4)o3_closesize="2";}else +if(!OLns4){i=parseInt(o3_closesize);o3_closesize=(i>0&&i<8)?OLpct[i]:OLpct[0];} +if(OLprintPI)OLprintDims();} +function OLdecode(){var re=/%[0-9A-Fa-f]{2,}/,t=o3_text,c=o3_cap,u=unescape,d=!OLns4&&(!OLgek||OLgek>=20020826)&&typeof decodeURIComponent?decodeURIComponent:u;if(typeof(window.TypeError)=='function'){if(re.test(t)){eval(new Array('try{','o3_text=d(t);','}catch(e){','o3_text=u(t);','}').join('\n'))};if(c&&re.test(c)){eval(new Array('try{','o3_cap=d(c);','}catch(e){','o3_cap=u(c);','}').join('\n'))}}else{if(re.test(t))o3_text=u(t);if(c&&re.test(c))o3_cap=u(c);}} +function OLlayerWrite(t){t+="\n";if(OLns4){over.document.write(t);over.document.close();}else if(typeof over.innerHTML!='undefined'){if(OLieM)over.innerHTML='';over.innerHTML=t;}else{range=o3_frame.document.createRange();range.setStartAfter(over);domfrag=range.createContextualFragment(t);while(over.hasChildNodes()){over.removeChild(over.lastChild);} +over.appendChild(domfrag);} +if(OLprintPI)over.print=o3_print?t:null;} +function OLshowObject(o){OLshowid=0;o=(OLns4)?o:o.style;if(((OLfilterPI)&&!OLchkFilter(o))||!OLfilterPI)o.visibility="visible";if(OLshadowPI)OLshowShadow();if(OLiframePI)OLshowIfs();if(OLhidePI)OLhideUtil(1,1,0);} +function OLhideObject(o){if(OLshowid>0){clearTimeout(OLshowid);OLshowid=0;} +if(OLtimerid>0)clearTimeout(OLtimerid);if(OLdelayid>0)clearTimeout(OLdelayid);OLtimerid=0;OLdelayid=0;self.status="";o3_label=ol_label;if(o3_frame!=self)o=OLgetRefById();if(o){if(o.onmouseover)o.onmouseover=null;if(OLscrollPI&&o==over)OLclearScroll();if(OLdraggablePI)OLclearDrag();if(OLfilterPI)OLcleanupFilter(o);if(OLshadowPI)OLhideShadow();var os=(OLns4)?o:o.style;os.visibility="hidden";if(OLhidePI&&o==over)OLhideUtil(0,0,1);if(OLiframePI)OLhideIfs(o);}} +function OLrepositionTo(o,xL,yL){o=(OLns4)?o:o.style;if(o.setAttribute){o.setAttribute('left',OLns4?xL:xL+'px');o.setAttribute('top',OLns4?yL:yL+'px');}else{o.left=(OLns4?xL:xL+'px');o.top=(OLns4?yL:yL+'px');}} +function OLoptMOUSEOFF(c){if(!c)o3_close="";over.onmouseover=function(){OLhover=1;if(OLtimerid>0){clearTimeout(OLtimerid);OLtimerid=0;}}} +function OLcursorOff(){var o=(OLns4?over:over.style),pHt=OLns4?over.clip.height:over.offsetHeight,left=parseInt(o.left),top=parseInt(o.top),right=left+o3_width,bottom=top+((OLbubblePI&&o3_bubble)?OLbubbleHt:pHt);if(OLxright||OLybottom)return true;return false;} +function OLsetRunTimeVar(){if(OLrunTime.length)for(var k=0;k-1){i=j;break;}}} +return i;} +function OLregCmds(c){if(typeof c!='string')return;var pM=c.split(',');pMtr=pMtr.concat(pM);for(var i=0;i 0){ + //add error messages for display + for(i in ret.errorArray) + overlay(app_strings.LBL_EMAIL_ERROR_DESC, ret.errorArray[i], 'alert'); + }else if (typeof(ret.errorArray)=='object' && ret.errorArray!=null && ret.errorArray!='' ) { + //if error element is returning an object, and the object value is not empty or null, then display error message + for(i in ret.errorArray) + overlay(app_strings.LBL_EMAIL_ERROR_DESC, ret.errorArray[i], 'alert'); + } + + //YUI bug with IE6 - Wont restore visibility property for nested select elements. + if(SUGAR.isIE) { + var overlayPanel = YAHOO.SUGAR.MessageBox.panel; + if(overlayPanel) { + overlayPanel.subscribe('hide',function() { YAHOO.util.Dom.setStyle('addressFrom' + idx,'visibility','');}); + } + } + }, + + + handleDeleteSignature : function(o) { + hideOverlay(); + var ret = JSON.parse(o.responseText); + SUGAR.email2.composeLayout.signatures = ret.signatures; + var field = document.getElementById('signature_id'); + SUGAR.email2.util.emptySelectOptions(field); + + for(var i in ret.signatures) { // iterate through assoc array + var opt = new Option(ret.signatures[i], i); + field.options.add(opt); + } + setSigEditButtonVisibility(); + }, + + /** + */ + handleDeleteReturn : function(o) { + // force refresh ListView + hideOverlay(); + if(document.getElementById('focusEmailMbox')) { + YAHOO.namespace('frameFolders').selectednode = SUGAR.email2.folders.getNodeFromMboxPath(document.getElementById('focusEmailMbox').innerHTML); + } + + // need to display success message before calling next async call? + document.getElementById(this.target).innerHTML = o.responseText; + }, + + /** + */ + handleFailure : function(o) { + // Failure handler + overlay('Exception occurred...', o.statusText, 'alert'); + if(document.getElementById('saveButton')) { + document.getElementById('saveButton').disabled = false; + } + }, + + handleReplyForward : function(o) { + var a = JSON.parse(o.responseText); + globalA = a; + var idx = SUGAR.email2.composeLayout.currentInstanceId; + + document.getElementById('email_id' + idx).value = a.uid; + document.getElementById('emailSubject' + idx).value = a.name; + document.getElementById('addressTO' + idx).value = a.from; + document.getElementById('uid' + idx).value = a.uid; + if(a.cc) { + document.getElementById('addressCC' + idx).value = a.cc; + SE.composeLayout.showHiddenAddress('cc', idx); + } + + if(a.type) { + document.getElementById('type' + idx).value = a.type; + } + + // apply attachment values + SUGAR.email2.composeLayout.loadAttachments(a.attachments); + + setTimeout("callbackReplyForward.finish(globalA);", 500); + }, + + handleReplyForwardForDraft : function(o) { + var a = JSON.parse(o.responseText); + globalA = a; + var idx = SUGAR.email2.composeLayout.currentInstanceId; + + document.getElementById('email_id' + idx).value = a.uid; + document.getElementById('emailSubject' + idx).value = a.name; + document.getElementById('addressTO' + idx).value = a.to; + + if(a.cc) { + document.getElementById('addressCC' + idx).value = a.cc; + SUGAR.email2.composeLayout.showHiddenAddress('cc',idx); + } + + if(a.bcc) { + document.getElementById('addressBCC' + idx).value = a.bcc; + SUGAR.email2.composeLayout.showHiddenAddress('bcc',idx); + } + + + if(a.type) { + document.getElementById('type' + idx).value = a.type; + } + + + // apply attachment values + SUGAR.email2.composeLayout.loadAttachments(a.attachments); + + setTimeout("callbackReplyForward.finish(globalA);", 500); + }, + + /** + */ + handleSuccess : function(o) { + document.getElementById(this.target).innerHTML = o.responseText; + hideOverlay(); + }, + + /** + */ + ieDeleteSuccess : function(o) { + hideOverlay(); + + var ret = JSON.parse(o.responseText); + + SUGAR.email2.accounts.refreshInboundAccountTable(); + alert(app_strings.LBL_EMAIL_IE_DELETE_SUCCESSFUL); + SUGAR.email2.accounts.rebuildFolderList(); + + }, + + /** + */ + ieSaveSuccess : function(o) { + document.getElementById('saveButton').disabled = false; + var a = JSON.parse(o.responseText); + if (a) { + if(a.error) { + overlay(app_strings.LBL_EMAIL_ERROR_DESC, app_strings.LBL_EMAIL_ERROR_CHECK_IE_SETTINGS, 'alert'); + SUGAR.email2.accounts.ieAccountError(SUGAR.email2.accounts.errorStyle); + } else { + resp = JSON.parse(o.responseText); + SUGAR.email2.accounts.refreshInboundAccountTable(); + SUGAR.email2.accounts.refreshOuboundAccountTable(); + SUGAR.email2.folders.startEmailCheckOneAccount(resp.id, true); + SUGAR.email2.accounts.inboundAccountEditDialog.hide(); + } + } else { + hideOverlay(); + overlay(app_strings.LBL_EMAIL_ERROR_DESC, app_strings.LBL_EMAIL_ERROR_SAVE_ACCOUNT, 'alert'); + } + + }, + + /** + */ + loadAttachments : function(o) { + var result = JSON.parse(o.responseText); + + SUGAR.email2.composeLayout.loadAttachments(result); + }, + + /** + */ + loadSignature : function(o) { + var ret = JSON.parse(o.responseText); + SUGAR.email2.signatures[ret.id] = ret.signature_html; + SUGAR.email2.composeLayout.setSignature(SUGAR.email2.signatures.targetInstance); + }, + + /** + * Follow up to mark email read|unread|flagged + */ + markEmailCleanup : function(o) { + var ret = JSON.parse(o.responseText); + if (!ret['status']) { + hideOverlay(); + overlay(app_strings.LBL_EMAIL_ERROR_DESC, ret['message'], 'alert'); + } else { + SUGAR.email2.contextMenus.markEmailCleanup(); + } // else + }, + + /** + */ + rebuildShowFolders : function(o) { + var t = JSON.parse(o.responseText); + var show = document.getElementById('ieAccountListShow'); + + SUGAR.email2.util.emptySelectOptions(show); + + for(i=0; i" + + // remove button + "" + + // file icon + "" + + // hidden id field + "" + + // file name + ((ret.nameForDisplay != null) ? ret.nameForDisplay + " " : ret.name + " ") + + "
    " + + "
    "; + overall.innerHTML += out; + if(SUGAR.email2.util.isIe()) { + document.getElementById('addedFiles' + idx).innerHTML = document.getElementById('addedFiles' + idx).innerHTML; + } + + // hide popup + SUGAR.email2.addFileDialog.hide(); + // focus attachments + SUGAR.email2.composeLayout.showAttachmentPanel(idx); + } +}; + + +/////////////////////////////////////////////////////////////////////////// +//// PER MODULE CALLBACK OBJECTS +AjaxObject.accounts = { + saveOutboundCleanup : function(o) { + SUGAR.email2.accounts.refreshOuboundAccountTable(); + SUGAR.email2.accounts.outboundDialog.hide(); + var id = o.responseText; + SUGAR.email2.accounts.newAddedOutboundId = id; + }, + saveDefaultOutboundCleanup: function(o){ + + }, + callbackEditOutbound : { + success : function(o) + { + var ret = JSON.parse(o.responseText); + // show overlay + SUGAR.email2.accounts.showAddSmtp(); + + // fill values + document.getElementById("mail_id").value = ret.id; + document.getElementById("type").value = ret.type; + document.getElementById("mail_sendtype").value = ret.mail_sendtype; + document.getElementById("mail_name").value = ret.name; + document.getElementById("mail_smtpserver").value = ret.mail_smtpserver; + document.getElementById("outboundEmailForm").mail_smtptype.value = ret.mail_smtptype; + document.getElementById("mail_smtpport").value = ret.mail_smtpport; + document.getElementById("mail_smtpuser").value = ret.mail_smtpuser; + //document.getElementById("mail_smtppass").value = ret.mail_smtppass; + document.getElementById("mail_smtpauth_req").checked = (ret.mail_smtpauth_req == 1) ? true : false; + SUGAR.email2.accounts.smtp_authenticate_field_display(); + document.getElementById("mail_smtpssl").options[ret.mail_smtpssl].selected = true; + + if(ret.type == 'system-override') { + SUGAR.email2.accounts.toggleOutboundAccountDisabledFields(true); + SUGAR.email2.accounts.changeEmailScreenDisplay(ret.mail_smtptype,true); + } + else { + SUGAR.email2.accounts.toggleOutboundAccountDisabledFields(false); + SUGAR.email2.accounts.changeEmailScreenDisplay(ret.mail_smtptype,false); + } + + + }, + failure : AjaxObject.handleFailure, + timeout : AjaxObject.timeout, + scope : AjaxObject + }, + callbackDeleteOutbound : { + success : function(o) { + var ret = JSON.parse(o.responseText); + if(ret.is_error) + { + if(confirm(ret.error_message)) + { + overlay(app_strings.LBL_EMAIL_IE_DELETE, app_strings.LBL_EMAIL_ONE_MOMENT); + AjaxObject.startRequest(AjaxObject.accounts.callbackDeleteOutbound, urlStandard + "&emailUIAction=deleteOutbound&confirm=true&outbound_email=" + ret.outbound_email); + } + else + hideOverlay(); + } + else + { + hideOverlay(); + SUGAR.email2.accounts.refreshOuboundAccountTable(); + } + }, + + failure : AjaxObject.handleFailure, + timeout : AjaxObject.timeout, + scope : AjaxObject + }, + + callbackCheckMailProgress : { + success : function(o) { + if (typeof(SUGAR.email2.accounts.totalMsgCount) == "undefined") { + SUGAR.email2.accounts.totalMsgCount = -1; + } + + //Check for server timeout / errors + var ret = JSON.parse(o.responseText); + var done = false; + + if (typeof(o.responseText) == 'undefined' || o.responseText == "" || ret == false) { + hideOverlay(); + overlay(app_strings.LBL_EMAIL_ERROR_DESC, app_strings.LBL_EMAIL_ERROR_TIMEOUT, 'alert'); + SUGAR.email2.accounts.totalMsgCount = -1; + //SUGAR.email2.folders.rebuildFolders(); + done = true; + } + + var currIeId = ret['ieid']; + + + var serverCount = ret.count; + + if (ret['status'] == 'done') { + for(i=0; i < SUGAR.email2.accounts.ieIds.length; i++) { + if (i == SUGAR.email2.accounts.ieIds.length - 1) { + //We are all done + done = true; + break; + } else if (SUGAR.email2.accounts.ieIds[i] == currIeId) { + //Go to next account + currIeId = SUGAR.email2.accounts.ieIds[i+1]; + ret.count = 0; + SUGAR.email2.accounts.totalMsgCount = -1; + break; + } + } + } + else if (ret.mbox && ret.totalcount && ret.count) { + SUGAR.email2.accounts.totalMsgCount = ret.totalcount; + if (ret.count >= ret.totalcount) { + serverCount = 0; + } + } else if (SUGAR.email2.accounts.totalMsgCount < 0 && ret.totalcount) { + SUGAR.email2.accounts.totalMsgCount = ret.totalcount; + } else { + hideOverlay(); + overlay(app_strings.LBL_EMAIL_ERROR_DESC, app_strings.LBL_EMAIL_ERROR_TIMEOUT, 'alert'); + SUGAR.email2.accounts.totalMsgCount = -1; + done = true; + } + + if (done) { + SUGAR.email2.accounts.totalMsgCount = -1; + hideOverlay(); + SUGAR.email2.folders.rebuildFolders(); + SE.listView.refreshGrid(); + } else if (SUGAR.email2.accounts.totalMsgCount < 0) { + YAHOO.SUGAR.MessageBox.updateProgress(0, mod_strings.LBL_CHECKING_ACCOUNT + ' '+ (i + 2) + ' '+ mod_strings.LBL_OF + ' ' + SUGAR.email2.accounts.ieIds.length); + AjaxObject.startRequest(AjaxObject.accounts.callbackCheckMailProgress, urlStandard + + '&emailUIAction=checkEmailProgress&ieId=' + currIeId + "¤tCount=0&synch=" + ret.synch); + } else { + YAHOO.SUGAR.MessageBox.updateProgress((ret.count / SUGAR.email2.accounts.totalMsgCount) * 100, + app_strings.LBL_EMAIL_DOWNLOAD_STATUS.replace(/\[\[count\]\]/, ret.count).replace(/\[\[total\]\]/, SUGAR.email2.accounts.totalMsgCount)); + AjaxObject.startRequest(AjaxObject.accounts.callbackCheckMailProgress, urlStandard + + '&emailUIAction=checkEmailProgress&ieId=' + currIeId + "¤tCount=" + serverCount + + '&mbox=' + ret.mbox + '&synch=' + ret.synch + '&totalcount=' + SUGAR.email2.accounts.totalMsgCount); + } + }, + failure : AjaxObject.handleFailure, + timeout : AjaxObject.timeout, + scope : AjaxObject + } +}; + +/////////////////////////////////////////////////////////////////////////////// +//// COMPOSE LAYOUT +AjaxObject.composeLayout = { + /** + * Populates the record id + */ + saveDraftCleanup : function(o) { + hideOverlay(); + var ret = JSON.parse(o.responseText); + if(ret) + SUGAR.email2.composeLayout.forceCloseCompose(ret.composeLayoutId); + else if (o.responseText) + overlay(mod_strings.LBL_ERROR_SAVING_DRAFT, o.responseText, 'alert'); + } +}; + +AjaxObject.composeLayout.callback = { + saveDraft : { + success : AjaxObject.composeLayout.saveDraftCleanup, + failure : AjaxObject.handleFailure, + timeout : AjaxObject.timeout, + scope : AjaxObject + } +}; + +AjaxObject.detailView = { + /** + * Pops-up a printable view of an email + */ + displayPrintable : function(o) { + var ret = JSON.parse(o.responseText); + var displayTemplate = new YAHOO.SUGAR.Template(SUGAR.email2.templates['viewPrintable']); + // 2 below must be in global context + meta = ret.meta; + meta['panelId'] = SUGAR.email2.util.getPanelId(); + email = ret.meta.email; + if (typeof(email.cc) == 'undefined') { + email.cc = ""; + } + + var out = displayTemplate.exec({ + 'app_strings' : app_strings, + 'theme' : theme, + 'idx' : 'Preview', + 'meta' : meta, + 'email' : meta.email + }); + + // open popup window + var popup = window.open('modules/Emails/templates/_blank.html', 'printwin' , + 'scrollbars=yes,menubar=no,height=600,width=800,resizable=yes,toolbar=no,location=no,status=no'); + + popup.document.write(out); + popup.document.close(); + }, + + /** + * Takes formatted response and creates a modal pop-over containing a title and content + */ + displayView : function(o) { + var SED = SUGAR.email2.detailView; + var ret = JSON.parse(o.responseText); + + if(!SED.viewDialog) { + SED.viewDialog = new YAHOO.widget.Dialog("viewDialog", { + modal:true, + visible:true, + fixedcenter:true, + constraintoviewport: true, + shadow : true + }); + SED.viewDialog.renderEvent.subscribe(function() { + var content = this.body.firstChild; + var viewH = YAHOO.util.Dom.getViewportHeight(); + if (content) { + this.body.style.overflow = "auto"; + this.body.style.width = "800px"; + this.body.style.height = (viewH - 75 > content.clientHeight ? (content.clientHeight) : (viewH - 75)) + "px"; + } + }, SED.viewDialog); + } // end lazy load + SED.viewDialog.setHeader(ret.title); + SED.viewDialog.setBody(ret.html); + SED.viewDialog.render(); + SED.viewDialog.show(); + }, + + /** + * Generates a modal popup to populate with the contents of bean's full EditView + */ + showQuickCreateForm : function(o) { + var SED = SUGAR.email2.detailView; + var ret = JSON.parse(o.responseText); + + if(!SED.quickCreateDialog) { + SED.quickCreateDialog = new YAHOO.widget.Dialog("quickCreate", { + modal:true, + visible:true, + fixedcenter:true, + constraintoviewport: true, + shadow : true + }); + + SED.quickCreateDialog.renderEvent.subscribe(function() { + var viewH = YAHOO.util.Dom.getViewportHeight(); + var contH = 0; + for (var i in this.body.childNodes) { + if (this.body.childNodes[i].clientHeight) { + contH += this.body.childNodes[i].clientHeight; + } else if (this.body.childNodes[i].offsetHeight) { + contH += this.body.childNodes[i].offsetHeight; + } // if + } + this.body.style.width = "800px"; + this.body.style.height = (viewH - 75 > contH ? (contH + 10) : (viewH - 75)) + "px"; + this.body.style.overflow = "auto"; + }, SED.quickCreateDialog); + + SED.quickCreateDialog.hideEvent.subscribe(function(){ + var qsFields = YAHOO.util.Dom.getElementsByClassName('.sqsEnabled', null, this.body); + /*for(var qsField in qsFields){ + if (typeof QSFieldsArray[qsFields[qsField].id] != 'undefined') + Ext.getCmp('combobox_'+qsFields[qsField].id).destroy(); + }*/ + }); + SED.quickCreateDialog.setHeader(app_strings.LBL_EMAIL_QUICK_CREATE); + } // end lazy load + if (ret.html) { + ret.html = ret.html.replace('', ""); + } + SED.quickCreateDialog.setBody(ret.html ? ret.html : " "); + SED.quickCreateDialog.render(); + SUGAR.util.evalScript(ret.html + ''); + + SED.quickCreateDialog.ieId = ret.ieId; + SED.quickCreateDialog.uid = ret.uid; + SED.quickCreateDialog.mbox = ret.mbox; + SED.quickCreateDialog.qcmodule = ret.module; + + SED.quickCreateDialog.show(); + + var editForm = document.getElementById('form_EmailQCView_' + ret.module); + if (editForm) { + editForm.module.value = 'Emails'; + var count = SUGAR.EmailAddressWidget.count[ret.module] ? SUGAR.EmailAddressWidget.count[ret.module] : 0; + var tableId = YAHOO.util.Dom.getElementsByClassName('emailaddresses', 'table', editForm)[0].id; + var instId = ret.module + count; + SED.quickCreateEmailsToAdd = ret.emailAddress; + SED.quickCreateEmailCallback = function(instId, tableId) { + var eaw = SUGAR.EmailAddressWidget.instances[instId]; + if (typeof(eaw) == "undefined") + window.setTimeout("SUGAR.email2.detailView.quickCreateEmailCallback('" + + instId + "','" + tableId + "');", 100); + eaw.prefillEmailAddresses(tableId, SUGAR.email2.detailView.quickCreateEmailsToAdd); + } + window.setTimeout("SUGAR.email2.detailView.quickCreateEmailCallback('" + + instId + "','" + tableId + "');", 100); + } + }, + + saveQuickCreateForm : function(o) { + hideOverlay(); + SUGAR.email2.detailView.quickCreateDialog.hide(); + validate['EditView'] = [ ]; + }, + + saveQuickCreateFormAndReply : function(o) { + hideOverlay(); + var ret = JSON.parse(o.responseText); + SUGAR.email2.detailView.quickCreateDialog.hide(); + var qcd = SUGAR.email2.detailView.quickCreateDialog; + var type = (qcd.qcmodule == 'Cases') ? 'replyCase' : 'reply'; + if (ret) { + var emailID = ret.id; + SUGAR.email2.composeLayout.c0_replyForwardEmail(null, ret.id, 'sugar::Emails', type); + } else { + SUGAR.email2.composeLayout.c0_replyForwardEmail(qcd.ieId, qcd.uid, qcd.mbox, type); + } + //Cean the validate cache to prevent errors on the next call + validate['EditView'] = [ ]; + }, + + saveQuickCreateFormAndAddToAddressBook : function(o) { + hideOverlay(); + SUGAR.email2.detailView.quickCreateDialog.hide(); + SUGAR.email2.complexLayout.findPanel('contactsTab').show(); + validate['EditView'] = [ ]; + }, + + handleAssignmentDialogAssignAction : function() { + + + var assign_user_id = window.document.forms['Distribute'].elements['assigned_user_id'].value; + + var dist = 'direct'; + var users = false; + var rules = false; + var get = ""; + var found_teams = false; + var warning_message = mod_strings.LBL_WARN_NO_USERS; + if(!found_teams && assign_user_id == '' ) + { + alert(warning_message); + return; + } + + var emailUids = SUGAR.email2.listView.getUidsFromSelection(); + var uids = ""; + for(i=0; i'; + } + overlay(SUGAR.language.get('Emails','LBL_IMPORT_STATUS_TITLE'), statusString, 'alert'); + } + SE.listView.refreshGrid(); + +}, +failure : AjaxObject.handleFailure, +timeout : AjaxObject.timeout, +scope : AjaxObject + +}; +var callbackComposeCache = { + success : AjaxObject.composeCache, + failure : AjaxObject.handleFailure, + timeout : AjaxObject.timeout, + scope : AjaxObject +}; +var callbackDelete = { + success : AjaxObject.handleDeleteReturn, + failure : AjaxObject.handleFailure, + timeout : AjaxObject.timeout, + scope : AjaxObject +}; +var callbackEmailDetailMultiple = { + success : function(o) { + hideOverlay(); + var retMulti = JSON.parse(o.responseText); + var ret = new Object(); + + for(var i=0; i 0) { + for (i = 0 ; i < tabArray.length ; i++) { + var tabObject = tabArray[i]; + if (tabObject.get("id") == ("composeTab" + idx)) { + var tabLabel = a.name; + if (tabLabel != null && tabLabel.length > 25) { + tabLabel = tabLabel.substring(0, 25) + "..."; + } // if + tabObject.get("labelEl").firstChild.data = tabLabel; + break; + } + } + } + + //SUGAR.email2.innerLayout.regions.center.getPanel('composeLayout' + idx).setTitle(a.name); + if (a.parent_name != null && a.parent_name != "") { + document.getElementById('data_parent_name' + idx).value = a.parent_name; + } + if (a.parent_type != null && a.parent_type != "") { + document.getElementById('data_parent_type' + idx).value = a.parent_type; + } + if (a.parent_id != null && a.parent_id != "") { + document.getElementById('data_parent_id' + idx).value = a.parent_id; + } + if (a.fromAccounts.status) { + var addressFrom = document.getElementById('addressFrom' + idx); + SUGAR.email2.util.emptySelectOptions(addressFrom); + var fromAccountOpts = a.fromAccounts.data; + for(i=0; i"; + } + } + function attachIcon(cell, record, column, value) { + if(value == "1") { + cell.innerHTML = ""; + } + } + + var colModel = + [ + { + label: "", + width: 10, + sortable: false, + fixed: true, + resizeable: true, + formatter: attachIcon, + key: 'hasAttach' + }, + { + label: "!", + width: widths[0], + sortable: true, + fixed: true, + resizeable: true, + formatter: flaggedIcon, + key: 'flagged' + }, + { + label: "", + width: widths[1], + sortable: true, + fixed: true, + resizeable: true, + formatter: repliedIcon, + key: 'status' + }, + { + label: app_strings.LBL_EMAIL_FROM, + width: widths[2], + sortable: true, + resizeable: true, + key: 'from' + }, + { + label: app_strings.LBL_EMAIL_SUBJECT, + width: widths[3], + sortable: true, + resizeable: true, + key: 'subject' + }, + { + label: mod_strings.LBL_LIST_DATE, + width: widths[4], + sortable: true, + resizeable: true, + key: 'date' + }, + { + label: app_strings.LBL_EMAIL_TO, + width: widths[5], + sortable: false, + resizeable: true, + key: 'to_addrs' + }, + { + label: 'uid', + hidden: true, + key: 'uid' + }, + { + label: 'mbox', + hidden: true, + key: 'mbox' + }, + { + label: 'ieId', + hidden: true, + key: 'ieId' + }, + { + label: 'site_url', + hidden: true, + key: 'site_url' + }, + { label: 'seen', + hidden: true, + key: 'seen' + }, + { label: 'type', + hidden: true, + key: 'type' + } + ]; + + var dataModel = new YAHOO.util.DataSource(urlBase + "?", { + responseType: YAHOO.util.DataSource.TYPE_JSON, + responseSchema: { + resultsList: 'Email', + fields: ['flagged', 'status', 'from', 'subject', 'date','to_addrs', 'uid', 'mbox', 'ieId', 'site_url', 'seen', 'type', 'AssignedTo','hasAttach'], + metaFields: {total: 'TotalCount', unread:"UnreadCount", fromCache: "FromCache"} + } + }); + var params = { + to_pdf : "true", + module : "Emails", + action : "EmailUIAjax", + emailUIAction : "getMessageList", + mbox : "INBOX", + ieId : "", + forceRefresh : "false" + }; + if(lazyLoadFolder != null) { + params['mbox'] = lazyLoadFolder.folder; + params['ieId'] = lazyLoadFolder.ieId; + //Check if the folder is a Sugar Folder + var test = new String(lazyLoadFolder.folder); + if(test.match(/SUGAR\./)) { + params['emailUIAction'] = 'getMessageListSugarFolders'; + params['mbox'] = test.substr(6); + } + } + //dataModel.initPaging(urlBase, SUGAR.email2.userPrefs.emailSettings.showNumInList); + + // create the Grid + var grid = SUGAR.email2.grid = new YAHOO.SUGAR.SelectionGrid('emailGrid', colModel, dataModel, { + MSG_EMPTY: SUGAR.language.get("Emails", "LBL_EMPTY_FOLDER"), + dynamicData: true, + paginator: new YAHOO.widget.Paginator({ + rowsPerPage:parseInt(SUGAR.email2.userPrefs.emailSettings.showNumInList), + containers : ["dt-pag-nav"], + template: "", + firstPageLinkLabel: "", + previousPageLinkLabel: "", + nextPageLinkLabel: "", + lastPageLinkLabel: "" + }), + initialRequest:SUGAR.util.paramsToUrl(params), + width: "800px", + height: "400px" + }); + + initRowDD(); + + //Override Paging request construction + grid.set("generateRequest", function(oState, oSelf) { + oState = oState || {pagination:null, sortedBy:null}; + var sort = (oState.sortedBy) ? oState.sortedBy.key : oSelf.getColumnSet().keys[1].getKey(); + var dir = (oState.sortedBy && oState.sortedBy.dir === YAHOO.widget.DataTable.CLASS_DESC) ? "desc" : "asc"; + var startIndex = (oState.pagination) ? oState.pagination.recordOffset : 0; + var results = (oState.pagination) ? oState.pagination.rowsPerPage : null; + // Build the request + var ret = + SUGAR.util.paramsToUrl(oSelf.params) + + "&sort=" + sort + + "&dir=" + dir + + "&start=" + startIndex + + ((results !== null) ? "&limit=" + results : ""); + return ret; + }); + + + grid.handleDataReturnPayload = function(oRequest, oResponse, oPayload) { + oPayload = oPayload || { }; + + oPayload.totalRecords = oResponse.meta.total; + oPayload.unreadRecords = oResponse.meta.unread; + + var tabObject = SE.innerLayout.get("tabs")[0]; + var mboxTitle = ""; + if (this.params.mbox != null) { + mboxTitle = this.params.mbox; + } + var tabtext = mboxTitle + " (" + oResponse.meta.total + " " + app_strings.LBL_EMAIL_MESSAGES + " )"; + tabObject.get("labelEl").firstChild.data = tabtext; + + if (SE.tree) { + var node = SE.tree.getNodeByProperty('id', this.params.ieId) || SE.tree.getNodeByProperty('origText', this.params.mbox); + if (node) { + node.data.unseen = oResponse.meta.unread; + SE.accounts.renderTree(); + } + } + return oPayload; + } + + var resize = grid.resizeGrid = function () { + SUGAR.email2.grid.set("width", SUGAR.email2.grid.get("element").parentNode.clientWidth + "px"); + SUGAR.email2.grid.set("height", (SUGAR.email2.grid.get("element").parentNode.clientHeight - 47) + "px"); + } + grid.convertDDRows = function() { + var rowEl = this.getFirstTrEl(); + while (rowEl != null) { + new this.DDRow(this, this.getRecord(rowEl), rowEl); + rowEl = this.getNextTrEl(rowEl); + } + } + + + grid.on("columnResizeEvent", function(o) { + //Find the index of the column + var colSet = SUGAR.email2.grid.getColumnSet().flat; + for (var i=0; i < colSet.length; i++) { + if (o.column == colSet[i]) { + //Store it in the cookie + Ck.setSub("EmailGridWidths", i + "", o.width, {expires: SUGAR.email2.nextYear}); + } + } + //this.resizeGrid(); + }, null, grid); + + grid.on("postRenderEvent", function() {this.convertDDRows()}, null, grid); + grid.on("rowClickEvent", SUGAR.email2.listView.handleClick); + grid.on("rowDblclickEvent", SUGAR.email2.listView.getEmail); + grid.render(); + SUGAR.email2.listViewLayout.on("render", resize); + resize(); + + //Setup the default load parameters + SUGAR.email2.grid.params = params; + + grid.on('postRenderEvent', SUGAR.email2.listView.setEmailListStyles); + dataModel.subscribe("requestEvent", grid.disable, grid, true); + dataModel.subscribe("responseParseEvent", grid.undisable, grid, true); + } + }; + e2Grid.init(); +}; + + +function initRowDD() { + var sg = SUGAR.email2.grid, + Dom = YAHOO.util.Dom; + sg.DDRow = function(oDataTable, oRecord, elTr) { + if(oDataTable && oRecord && elTr) { + this.ddtable = oDataTable; + this.table = oDataTable.getTableEl(); + this.row = oRecord; + this.rowEl = elTr; + this.newIndex = null; + this.init(elTr); + this.initFrame(); // Needed for DDProxy + this.invalidHandleTypes = {}; + } + }; + + YAHOO.extend(sg.DDRow, YAHOO.util.DDProxy, { + _resizeProxy: function() { + this.constructor.superclass._resizeProxy.apply(this, arguments); + var dragEl = this.getDragEl(), + el = this.getEl(); + var xy = Dom.getXY(el); + + Dom.setStyle(dragEl, 'height', this.rowEl.offsetHeight + "px"); + Dom.setStyle(dragEl, 'width', (parseInt(Dom.getStyle(dragEl, 'width'),10) + 4) + 'px'); + Dom.setXY(dragEl, [xy[0] - 100, xy[1] - 20] ); + Dom.setStyle(dragEl, 'display', ""); + }, + + startDrag: function(x, y) { + //Check if we should be dragging a set of rows rather than just the one. + var selectedRows = this.ddtable.getSelectedRows(); + var iSelected = false; + for (var i in selectedRows) { + if (this.rowEl.id == selectedRows[i]) { + iSelected = true; + break + } + } + if (iSelected) { + this.rows = []; + for (var i in selectedRows) { + this.rows[i] = this.ddtable.getRecord(selectedRows[i]); + } + } else { + this.rows = [this.row]; + this.ddtable.unselectAllRows(); + this.ddtable.selectRow(this.row); + } + + //Initialize the dragable proxy + var dragEl = this.getDragEl(); + var clickEl = this.getEl(); + Dom.setStyle(clickEl, "opacity", "0.25"); + dragEl.innerHTML = "" + clickEl.innerHTML + "
    "; + Dom.addClass(dragEl, "yui-dt-liner"); + Dom.setStyle(dragEl, "opacity", "0.5"); + Dom.setStyle(dragEl, "height", (clickEl.clientHeight - 2) + "px"); + Dom.setStyle(dragEl, "backgroundColor", Dom.getStyle(clickEl, "backgroundColor")); + Dom.setStyle(dragEl, "border", "2px solid gray"); + }, + + clickValidator: function(e) { + if (this.row.getData()[0] == " ") + return false; + var target = YAHOO.util.Event.getTarget(e); + return ( this.isValidHandleChild(target) && + (this.id == this.handleElId || this.DDM.handleWasClicked(target, this.id)) ); + }, + /** + * This funciton checks that the target of the drag is a table row in this + * DDGroup and simply moves the sourceEL to that location as a preview. + */ + onDragOver: function(ev, id) { + var node = SUGAR.email2.tree.getNodeByElement(Dom.get(id)); + if (node && node != this.targetNode) { + this.targetNode = node; + SUGAR.email2.folders.unhighliteAll(); + node.highlight(); + } + }, + + onDragOut: function(e, id) { + if (this.targetNode) { + SUGAR.email2.folders.unhighliteAll(); + this.targetNode = false; + } + }, + endDrag: function() { + Dom.setStyle(this.getEl(), "opacity", ""); + Dom.setStyle(this.getDragEl(), "display", "none"); + if (this.targetNode) { + SUGAR.email2.folders.handleDrop(this.rows, this.targetNode); + } + SUGAR.email2.folders.unhighliteAll(); + this.rows = null; + } + }); +} + +function AddressSearchGridInit() { + function moduleIcon(elCell, oRecord, oColumn, oData) { + elCell.innerHTML = ""; + }; + function selectionCheckBox(elCell, oRecord, oColumn, oData) { + elCell.innerHTML = ''; + }; + var checkHeader = '{FirstPageLink} {PreviousPageLink} {PageLinks} {NextPageLink} {LastPageLink}
    ", + firstPageLinkLabel: "", + previousPageLinkLabel: "", + nextPageLinkLabel: "", + lastPageLinkLabel: "" + }), + initialRequest:SUGAR.util.paramsToUrl(dataModel.params), + width: "560px", + height: "250px" + }); + //Override Paging request construction + grid.set("generateRequest", function(oState, oSelf) { + oState = oState || {pagination:null, sortedBy:null}; + var sort = (oState.sortedBy) ? oState.sortedBy.key : oSelf.getColumnSet().keys[0].getKey(); + var dir = (oState.sortedBy && oState.sortedBy.dir === YAHOO.widget.DataTable.CLASS_DESC) ? "desc" : "asc"; + var startIndex = (oState.pagination) ? oState.pagination.recordOffset : 0; + var results = (oState.pagination) ? oState.pagination.rowsPerPage : null; + // Build the request + var ret = + SUGAR.util.paramsToUrl(oSelf.getDataSource().params) + + "&sort=" + sort + "&dir=" + dir + "&start=" + startIndex + + ((results !== null) ? "&limit=" + results : ""); + return ret; + }); + + grid.handleDataReturnPayload = function(oRequest, oResponse, oPayload) { + oPayload = oPayload || { }; + oPayload.totalRecords = oResponse.meta.total; + return oPayload; + } + + grid.clickToggleSelect= function(args) { + var isIE = (args.event.target == null); + var targetElement = isIE ? args.event.srcElement : args.event.target; + if(targetElement.type == null || targetElement.type != 'checkbox') { + SUGAR.email2.addressBook.grid.toggleSelect(args.target.id); + } + } + + grid.reSelectRowsOnRender = function (){ + var rows = SUGAR.email2.addressBook.grid.getRecordSet().getRecords(); + for (var i = 0; i < rows.length; i++) + { + var emailAddress = rows[i].getData("email"); + var alreadyAdded = SUGAR.email2.addressBook.doesEmailAdddressExistInResultTable(emailAddress); + if(alreadyAdded) + { + rows[i].setData("selected", true); + SUGAR.email2.addressBook.grid.selectRow(rows[i]); + } + else + { + rows[i].setData("selected", false); + SUGAR.email2.addressBook.grid.unselectRow(rows[i]); + } + } + } + grid.subscribe("rowMouseoverEvent", grid.onEventHighlightRow); + grid.subscribe("rowMouseoutEvent", grid.onEventUnhighlightRow); + grid.subscribe("rowClickEvent", grid.clickToggleSelect); + grid.subscribe("postRenderEvent", grid.reSelectRowsOnRender); + + grid.render(); + dataModel.subscribe("requestEvent", grid.disable, grid, true); + dataModel.subscribe("responseParseEvent", grid.undisable, grid, true); + + grid.toggleSelectCheckbox = function(id,checked){ + var row = SUGAR.email2.addressBook.grid.getRecord(id); + row.setData("checked",checked); + }; + grid.toggleSelect = function(id, checked) { + var row = SUGAR.email2.addressBook.grid.getRecord(id); + checked = row.getData("selected"); + if (!checked) + { + SUGAR.email2.addressBook.grid.selectRow(row); + SE.addressBook.insertContactRowToResultTable(id,null) + } else + { + SUGAR.email2.addressBook.grid.unselectRow(row); + SE.addressBook.removeRowFromGridResults(id,row.getData("email")); + } + row.setData("selected", !checked); + }; + + grid.toggleSelectAll = function(checked) { + rows = SUGAR.email2.addressBook.grid.getRecordSet().getRecords(); + for (var i = 0; i < rows.length; i++) { + if (typeof(rows[i]) != "undefined") + rows[i].setData("checked", checked); + } + var checkBoxes = SUGAR.email2.addressBook.grid.get("element").getElementsByTagName('input'); + for (var i = 0; i < checkBoxes.length; i++) { + checkBoxes[i].checked = checked; + } + }; + + //Initialize the grid result table. + AddressSearchResultsGridInit(); +} + + + +/** +* Initalize the results table for the address book selection. +* +*/ +function AddressSearchResultsGridInit() +{ + + /* Full name sort funciton to compare by last name if available */ + var fullNameSort = function(a, b, desc) { + // Deal with empty values + if(!YAHOO.lang.isValue(a)) + return (!YAHOO.lang.isValue(b)) ? 0 : 1; + else if(!YAHOO.lang.isValue(b)) + return -1; + + var aNames = a.getData("name").split(' '); + var bNames = b.getData("name").split(' '); + + var aSortField = (aNames.length == 2) ? aNames[1] : a.getData("name"); + var bSortField = (bNames.length == 2) ? bNames[1] : b.getData("name"); + + return YAHOO.util.Sort.compare(aSortField,bSortField, desc); + + }; + + var typeDdOptions = [app_strings.LBL_EMAIL_ADDRESS_BOOK_ADD_TO.replace(/:$/,'') , + app_strings.LBL_EMAIL_ADDRESS_BOOK_ADD_CC.replace(/:$/,''), + app_strings.LBL_EMAIL_ADDRESS_BOOK_ADD_BCC.replace(/:$/,'')]; + + var ColumnDefs = [{key:'type',label:app_strings.LBL_EMAIL_ADDRESS_BOOK_ADRRESS_TYPE, width: 60, sortable: true, editor: new YAHOO.widget.RadioCellEditor({radioOptions:typeDdOptions,disableBtns:true})}, + {key:'name',label:app_strings.LBL_EMAIL_ACCOUNTS_NAME,width: 280,sortable: true, sortOptions:{sortFunction:fullNameSort}}]; + + var myDataSource = new YAHOO.util.DataSource([]); + myDataSource.responseType = YAHOO.util.DataSource.TYPE_JSARRAY; + myDataSource.responseSchema = { + fields: ["name","type","email_address","display_email_address","bean_id","idx"] + }; + + var gridResults = SUGAR.email2.addressBook.gridResults = new YAHOO.widget.ScrollingDataTable("addrSearchResultGrid", ColumnDefs, myDataSource, { + width: "350px",height: "250px", MSG_EMPTY: " "}); + + var highlightEditableCell = function(oArgs) { + var elCell = oArgs.target; + if(YAHOO.util.Dom.hasClass(elCell, "yui-dt-editable")) { + this.highlightCell(elCell); + } + }; + + gridResults.subscribe("cellMouseoverEvent", highlightEditableCell); + gridResults.subscribe("cellMouseoutEvent", gridResults.onEventUnhighlightCell); + gridResults.subscribe("cellClickEvent", gridResults.onEventShowCellEditor); + gridResults.subscribe("rowMouseoverEvent", gridResults.onEventHighlightRow); + gridResults.subscribe("rowMouseoutEvent", gridResults.onEventUnhighlightRow); + + //Setup the context menus + var onContextMenuClick = function(p_sType, p_aArgs, p_myDataTable) { + var task = p_aArgs[1]; + if(task) + { + var elRow = this.contextEventTarget; + elRow = p_myDataTable.getTrEl(elRow); + + if(elRow) + { + switch(task.index) + { + case 0: + var oRecord = p_myDataTable.getRecord(elRow); + p_myDataTable.deleteRow(elRow); + SUGAR.email2.addressBook.grid.reSelectRowsOnRender(); + } + } + } + }; + var contextMenu = new YAHOO.widget.ContextMenu("contextmenu", + {trigger:gridResults.getTbodyEl()}); + contextMenu.addItem(app_strings.LBL_EMAIL_DELETE); + contextMenu.render("addrSearchResultGrid"); + contextMenu.clickEvent.subscribe(onContextMenuClick, gridResults); +} +// End of File modules/Emails/javascript/grid.js + +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + (function() { + var sw = YAHOO.SUGAR, + Event = YAHOO.util.Event, + Connect = YAHOO.util.Connect, + Dom = YAHOO.util.Dom + SE = SUGAR.email2; + +/////////////////////////////////////////////////////////////////////////////// +//// ADDRESS BOOK +SE.addressBook = { + _contactCache : new Array(), // cache of contacts + _dd : new Array(), // filtered list, same format as _contactCache + _ddLists : new Array(), // list of Lists + _dd_mlUsed : new Array(), // contacts in mailing list edit view column1 + _dd_mlAvailable : new Array(), // contacts in mailing list edit view column2 + clickBubble : true, // hack to get around onclick event bubbling + relatedBeanId : '', + relatedBeanType : '', + idx : 0, + + itemSpacing : 'white-space:nowrap; padding:2px;', + reGUID : SE.reGUID, + + + + /** + * YUI bug fix 2527707. Causes nested datatable's in to cause 404 errors whens earching. + */ + initFixForDatatableSort: function () { + //Workaround for YUI bug 2527707: http://yuilibrary.com/projects/yui2/ticket/913efafad48ce433199f3e72e4847b18, should be removed when YUI 2.8+ is used + YAHOO.widget.DataTable.prototype.getColumn = function(column) { + var oColumn = this._oColumnSet.getColumn(column); + + if(!oColumn) { + // Validate TD element + var elCell = column.nodeName.toLowerCase() != "th" ? this.getTdEl(column) : false; + if(elCell) { + oColumn = this._oColumnSet.getColumn(elCell.cellIndex); + } + // Validate TH element + else { + elCell = this.getThEl(column); + if(elCell) { + // Find by TH el ID + var allColumns = this._oColumnSet.flat; + for(var i=0, len=allColumns.length; i 0) { + SE.composeLayout.handleDrop( + (type == 'contacts') ? SE.contactView : SE.emailListsView, + null, rows, 'addressTO' + idx ); + } else { + alert(app_strings.LBL_EMAIL_MENU_MAKE_SELECTION); + } + }, + + editContact : function() { + SE.contextMenus.contactsContextMenu.hide(); + var element = SE.contactView.getSelectedNodes()[0]; + var elementId = ""; + if (element.className.indexOf('address-contact') > -1) { + elementId = element.id; + } else if (element.className.indexOf('address-exp-contact') > -1) { + elementId = element.id.substring(2); + } + }, + + + /** + * Filters contact entries based on user input + */ + filter : function(inputEl) { + var ret = new Object(); + var re = new RegExp(inputEl.value, "gi"); + + for(var i in this._contactCache) { + if(this._contactCache[i].name.match(re)) { + ret[i] = this._contactCache[i]; + } + } + + this.buildContactList(ret); + }, + + fullForm : function(id, module) { + document.location = "index.php?return_module=Emails&return_action=index&module=" + module + "&action=EditView&record=" + id; + }, + + /** + * returns a formatted email address from the addressBook cache + */ + getFormattedAddress : function(id) { + var o = this._contactCache[id]; + var primaryEmail = ''; + + for(var i=0; i]+)>)/ig, "").replace(/'/gi,'\''); + var ret = finalName + " <" + finalEmail.replace(/'/gi,'\'') + ">"; + + return ret; + }, + + /** + * Sets up async call to query for matching contacts, users, etc. + */ + searchContacts : function() { + var fn = document.getElementById('input_searchField').value; + var pe = document.getElementById('input_searchPerson').value; + + var rb = document.getElementById('hasRelatedBean').checked; + if (rb) { + var idx = this.idx; + var relatedBeanId = document.getElementById('data_parent_id' + idx).value; + var relatedBeanType = document.getElementById('data_parent_type' + idx).value; + this.addressBookDataModel.params['related_bean_id'] = relatedBeanId; + this.addressBookDataModel.params['related_bean_type'] = relatedBeanType; + } else { + this.addressBookDataModel.params['related_bean_id'] = ''; + } + + this.addressBookDataModel.params['search_field'] = fn; + this.addressBookDataModel.params['person'] = pe; + this.addressBookDataModel.params['emailUIAction'] = 'getAddressSearchResults'; + this.grid._oDataSource = this.addressBookDataModel; + this.grid.getDataSource().sendRequest(SUGAR.util.paramsToUrl(this.addressBookDataModel.params), this.grid.onDataReturnInitializeTable, this.grid); + }, + + /** + * Clear Search Crieteria For Addressbook + */ + clearAddressBookSearch : function() { + document.getElementById('input_searchField').value = ""; + document.getElementById('input_searchPerson').selectedIndex = 0; + }, + + /** + * Opens modal select window to add contacts to addressbook + */ + selectContactsDialogue : function(destId) { + if(!this.contactsDialogue) { + var dlg = this.contactsDialogue = new YAHOO.widget.Dialog("contactsDialogue", { + modal:true, + visible:false, + draggable: false, + constraintoviewport: true, + width : 980, + buttons : [{text: app_strings.LBL_EMAIL_ADDRESS_BOOK_ADD, isDefault: true, handler: this.populateEmailAddressFieldsFromResultTable}, + {text: app_strings.LBL_EMAIL_ADDRESS_BOOK_CLEAR, isDefault: true, handler: this.clearAllEmailAddressFieldsFromResultTable} ] + }); + dlg.setHeader(app_strings.LBL_EMAIL_ADDRESS_BOOK_SELECT_TITLE); + + var body = SUGAR.util.getAndRemove("contactsDialogueHTML"); + dlg.setBody(body.innerHTML); + dlg.renderEvent.subscribe(function() { + var iev = YAHOO.util.Dom.get("contactsDialogueBody"); + if (iev && !SUGAR.isIE) { + this.body.style.width = "950px"; + } + }, dlg); + + + dlg.beforeRenderEvent.subscribe(function() { + var dd = new YAHOO.util.DDProxy(dlg.element); + dd.setHandleElId(dlg.header); + dd.on('endDragEvent', function() { + dlg.show(); + }); + }, dlg, true); + dlg.render(); + + var tp = new YAHOO.widget.TabView("contactsSearchTabs"); + + var tabContent = SUGAR.util.getAndRemove("searchForm"); + tp.addTab(new YAHOO.widget.Tab({ + label: app_strings.LBL_EMAIL_ADDRESS_BOOK_TITLE, + scroll : true, + content : tabContent.innerHTML, + id : "addressSearchTab", + active : true + })); + + var addListenerFields = ['input_searchPerson','input_searchField' ] + YAHOO.util.Event.addListener(addListenerFields,"keydown", function(e){ + if (e.keyCode == 13) { + YAHOO.util.Event.stopEvent(e); + SUGAR.email2.addressBook.searchContacts(); + } + }); + + this.contactsDialogue.render(); + dlg.center(); + } + //Quick Compose does not have an innerLayout component and will always be referenced with ix 0. + if (typeof(SUGAR.email2.innerLayout) == 'undefined') + var idx = 0; + else + { + var activePanel = SUGAR.email2.innerLayout.get("activeTab").get("id"); + var idx = activePanel.substring(10); + } + SE.addressBook.idx = idx; + + var relatedBeanId; + if ((hasRelatedBeanId = document.getElementById('data_parent_id' + idx).value) != '') { + document.getElementById('relatedBeanColumn').style.display = ''; + var relatedBeanName = document.getElementById('data_parent_name' + idx).value; + var relatedBeanType = document.getElementById('data_parent_type' + idx).value; + relatedBeanId = document.getElementById('data_parent_id' + idx).value; + document.getElementById('relatedBeanInfo').innerHTML = ' ' + relatedBeanType + ' ' + relatedBeanName + ''; + SE.addressBook.relatedBeanType = relatedBeanType; + } else { + document.getElementById('relatedBeanColumn').style.display = 'none'; + document.getElementById('hasRelatedBean').checked = false; + } + + if (!SE.addressBook.grid) + { + if (hasRelatedBeanId) { + document.getElementById('hasRelatedBean').checked = true; + } + AddressSearchGridInit(); + SE.addressBook.relatedBeanId = relatedBeanId; + } + else + { + if (typeof(relatedBeanId) != 'undefined' && relatedBeanId != SE.addressBook.relatedBeanId) + { + SE.addressBook.relatedBeanId = relatedBeanId; + document.getElementById('hasRelatedBean').checked = true; + } + if (document.getElementById('hasRelatedBean').checked == true) + { + SE.addressBook.addressBookDataModel.params['related_bean_id'] = relatedBeanId; + SE.addressBook.addressBookDataModel.params['related_bean_type'] = relatedBeanType; + } else { + SE.addressBook.addressBookDataModel.params['related_bean_id'] = ''; + SE.addressBook.addressBookDataModel.params['related_bean_type'] = ''; + } + SE.addressBook.addressBookDataModel.params['search_field'] = document.getElementById('input_searchField').value;; + SE.addressBook.addressBookDataModel.params['person'] = document.getElementById('input_searchPerson').value; + SE.addressBook.grid.getDataSource().sendRequest(SUGAR.util.paramsToUrl(SE.addressBook.addressBookDataModel.params), SE.addressBook.grid.onDataReturnInitializeTable, SE.addressBook.grid); + } + + //Remove any lingering rows in the result set table if the module was closed. + SE.addressBook.gridResults.deleteRows(0, SUGAR.email2.addressBook.gridResults.getRecordSet().getLength()); + //Repopulate + SE.addressBook.populateResulstTableEmailAddresses(); + + this.contactsDialogue.show(); + }, + /** + * Clear all email addresses from result table. + * + */ + clearAllEmailAddressFieldsFromResultTable: function () { + SUGAR.email2.addressBook.gridResults.deleteRows(0, SUGAR.email2.addressBook.gridResults.getRecordSet().getLength()); + //Unhighlight any rows currently selected if the emails were cleared. + SUGAR.email2.addressBook.grid.toggleSelectAll(false); + SUGAR.email2.addressBook.grid.reSelectRowsOnRender(); + }, + /** + * Take all email address listed in the compose tab To|Cc|Bcc fields and re-populates the + * results table. This function is called when the address book is displayed. + */ + populateResulstTableEmailAddresses: function () { + + var idx = SE.addressBook.idx; + var emailFields = ['to','cc','bcc']; + + for(var k=0;k'; + if(t_name == '') + t_name = displayEmail = t_emailAddr; + + var addressType = SE.addressBook.translateAddresType(emailFields[k],true); + SUGAR.email2.addressBook.gridResults.addRow({'type':addressType,'name':t_name,'email_address': t_emailAddr, + 'display_email_address': displayEmail,'bean_id': -1,'idx' : SE.addressBook.idx}); + } + } + }, + + /** + * Checks all entries in the result table against a particular email address, returning true + * if the email address is found, false otherwise. + */ + doesEmailAdddressExistInResultTable: function(emailAddress) + { + if(trim(emailAddress) == '') + return false; + + var emailAddressFound = false; + var contacts = SE.addressBook.gridResults.getRecordSet().getRecords(); + for (var i=0; i < contacts.length; i++) + { + var data = SE.addressBook.gridResults.getRecord(contacts[i]).getData(); + //If we are adding to cc or bcc fields, make them visible. + if(data.email_address == emailAddress) + { + emailAddressFound = true; + break; + } + } + + return emailAddressFound; + }, + /** + * Takes all email addresses that the users wishes to add from the address book and populates the To + * fields on the compose tab. + */ + populateEmailAddressFieldsFromResultTable: function() + { + //Clear the fields first, all email addresses are stored in the address book + var idx = SE.addressBook.idx; + var emailFields = ['to','cc','bcc']; + for(var k=0;k'; + if(addressType == null) + addressType = app_strings.LBL_EMAIL_ADDRESS_BOOK_ADD_TO.replace(/:$/,''); //Default to To when using the plus icon. + SUGAR.email2.addressBook.gridResults.addRow({'type':addressType,'name':name,'email_address': data.email,'display_email_address': ea,'bean_id': data.bean_id,'idx' : SE.addressBook.idx}); + }, + /** + * Remove a row from the gridsResult table. + */ + removeRowFromGridResults : function(rowId,emailAddress) + { + var contacts = SE.addressBook.gridResults.getRecordSet().getRecords(); + for (var i=0; i < contacts.length; i++) + { + var rec = SE.addressBook.gridResults.getRecord(contacts[i]); + var data = rec.getData(); + if(data.email_address == emailAddress) + { + SUGAR.email2.addressBook.gridResults.deleteRow(rec.getId()); + break; + } + } + + SUGAR.email2.addressBook.toggleSearchRowIcon(rowId,true); + }, + /** + * Translates between the addressType To|Cc|Bcc labels/keys. + */ + translateAddresType: function(addressType,fromKey) + { + var displayTo = app_strings.LBL_EMAIL_ADDRESS_BOOK_ADD_TO.replace(/:$/,''); + var displayCc = app_strings.LBL_EMAIL_ADDRESS_BOOK_ADD_CC.replace(/:$/,''); + var displayBcc = app_strings.LBL_EMAIL_ADDRESS_BOOK_ADD_BCC.replace(/:$/,''); + var mappingObject = {}; + + if(fromKey) + mappingObject = {'to':displayTo, 'cc':displayCc, 'bcc':displayBcc}; + else + { + mappingObject[displayTo] = 'to'; //Cant use object literal with variable variable. + mappingObject[displayCc] = 'cc'; + mappingObject[displayBcc] = 'bcc'; + } + + return typeof(mappingObject[addressType]) != 'undefined' ? mappingObject[addressType] : ''; + + }, + /** + * + */ + toggleSearchRowIcon : function(rowId,show) + { + if(show) + { + var idToShow = rowId + '_add_img'; + var idToHide = rowId + '_rm_img'; + } + else + { + var idToShow = rowId + '_rm_img'; + var idToHide = rowId + '_add_img'; + } + + + Dom.addClass(idToHide, "yui-hidden"); + Dom.removeClass(idToShow, "yui-hidden"); + }, + /** + * Determine if an entry has already been added to the grid results table to prevent duplicates. + */ + doesGridResultsEntryExist: function(emailAddrs) + { + + var contactExists = false; + var contacts = SE.addressBook.gridResults.getRecordSet().getRecords(); + for (var i=0; i < contacts.length; i++) + { + var data = SE.addressBook.gridResults.getRecord(contacts[i]).getData(); + if(data.email_address == emailAddrs) + { + contactExists = true; + break; + } + } + return contactExists; + }, + + /** + * adds an email address to a string, but first checks if it exists + * @param string concat The string we are appending email addresses to + * @param string addr Email address to add + * @return string + */ + smartAddEmailAddressToComposeField : function(concat, addr) { + var re = new RegExp(addr); + + if(!concat.match(re)) { + if(concat != "") { + concat += "; " + addr; + } else { + concat = addr; + } + } + + return concat; + } +}; +//// END ADDRESS BOOK +/////////////////////////////////////////////////////////////////////////////// + + + +/////////////////////////////////////////////////////////////////////////////// +//// AUTOCOMPLETE +/** + * Auto-complete object + */ +SE.autoComplete = { + config : { + delimChar : [";", ","], + useShadow : false, + useIFrame : false, + typeAhead : true, + prehighlightClassName : "yui-ac-prehighlight", + queryDelay : 0 + }, + instances : new Array(), + + /** + * Parses an addressBook entry looking for primary address. If not found, it will return the last found address. + * @param object Contact from AddressBook + * @return string + */ + getPrimaryAddress : function(contact) { + var address = app_strings.LBL_EMAIL_ADDRESS_BOOK_NOT_FOUND; + + for(var eIndex in contact.email) { + address = contact.email[eIndex].email_address; + if(contact.email[eIndex].primary_address == 1) { + return contact.email[eIndex].email_address; + } + } + return address; + }, + + + /** + * initializes autocomplete widgets for a given compose view + * @param int idx + */ + init : function(idx) { + var ds = new YAHOO.widget.DS_JSArray(this.returnDataSource(SE.addressBook._contactCache), { + "queryMatchContains" : false, + "queryMatchSubset" : true + }); + + this.instances[idx] = { + to : null, + cc : null, + bcc : null + }; + + + // instantiate the autoComplete widgets + this.instances[idx]['to'] = new YAHOO.widget.AutoComplete('addressTO'+idx, "addressToAC"+idx, ds, this.config); + this.instances[idx]['cc'] = new YAHOO.widget.AutoComplete('addressCC'+idx, "addressCcAC"+idx, ds, this.config); + this.instances[idx]['bcc'] = new YAHOO.widget.AutoComplete('addressBCC'+idx, "addressBccAC"+idx, ds, this.config); + + // enable hiding of interfering textareas + this.instances[idx]['to'].containerExpandEvent.subscribe(SE.autoComplete.toggleTextareaHide); + this.instances[idx]['cc'].containerExpandEvent.subscribe(SE.autoComplete.toggleTextareaHide); + this.instances[idx]['bcc'].containerExpandEvent.subscribe(SE.autoComplete.toggleTextareaHide); + + // enable reshowing of hidden textareas + this.instances[idx]['to'].containerCollapseEvent.subscribe(SE.autoComplete.toggleTextareaShow); + this.instances[idx]['cc'].containerCollapseEvent.subscribe(SE.autoComplete.toggleTextareaShow); + this.instances[idx]['bcc'].containerCollapseEvent.subscribe(SE.autoComplete.toggleTextareaShow); + + // enable refreshes of contact lists + this.instances[idx]['to'].textboxFocusEvent.subscribe(SE.autoComplete.refreshDataSource); + this.instances[idx]['cc'].textboxFocusEvent.subscribe(SE.autoComplete.refreshDataSource); + this.instances[idx]['bcc'].textboxFocusEvent.subscribe(SE.autoComplete.refreshDataSource); + }, + + refreshDataSource : function(sType, aArgs) { + var textBoxId = aArgs[0].getInputEl().id; // "addressTo0" + var idx; + var refresh = SE.autoComplete.returnDataSource(SE.addressBook._contactCache); + + if(textBoxId.indexOf("addressTO") > -1 || textBoxId.indexOf("addressCC") > -1) { + idx = textBoxId.substr(9); + } else { + idx = textBoxId.substr(10); + } + + SE.autoComplete.instances[idx]['to'].dataSource.data = refresh; + SE.autoComplete.instances[idx]['cc'].dataSource.data = refresh; + SE.autoComplete.instances[idx]['bcc'].dataSource.data = refresh; + }, + + /** + * Parses AddressBook entries to return an appropriate DataSource array for YUI.autoComplete + */ + returnDataSource : function(contacts) { + var ret = new Array(); + for(var id in contacts) { + if (contacts[id].name) { + var primary = this.getPrimaryAddress(contacts[id]); + + ret[ret.length] = contacts[id].name.replace(/<[\/]*b>/gi, '') + " <" + primary + ">"; + //ret[ret.length] = contacts[id].name + " <" + primary + ">"; + + for(var emailIndex in contacts[id].email) { + ret[ret.length] = contacts[id].email[emailIndex].email_address; + } + } + } + + return ret; + }, + + /** + * Hides address textareas to prevent autocomplete dropdown from being obscured + */ + toggleTextareaHide : function(sType, aArgs) { + var textBoxId = aArgs[0]._oTextbox.id; // "addressTo0" + var type = ""; + var idx = -1; + + if(textBoxId.indexOf("addressTO") > -1) { + type = "to"; + } else if(textBoxId.indexOf("addressCC") > -1) { + type = "cc"; + } + idx = textBoxId.substr(9); + + // follow through if not BCC + if(type != "") { + var cc = document.getElementById("addressCC" + idx); + var bcc = document.getElementById("addressBCC" + idx); + + switch(type) { + case "to": + cc.style.visibility = 'hidden'; + case "cc": + bcc.style.visibility = 'hidden'; + break; + } + } + }, + + /** + * Redisplays the textareas after an address is commited + */ + toggleTextareaShow : function(sType, aArgs) { + var textBoxId = aArgs[0]._oTextbox.id; // "addressTo0" + var type = ""; + var idx = -1; + + if(textBoxId.indexOf("addressTO") > -1) { + type = "to"; + } else if(textBoxId.indexOf("addressCC") > -1) { + type = "cc"; + } + idx = textBoxId.substr(9); + + // follow through if not BCC + if(type != "") { + document.getElementById("addressCC" + idx).style.visibility = 'visible'; + document.getElementById("addressBCC" + idx).style.visibility = 'visible'; + } + } +}; + +//// END AUTOCOMPLETE +/////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +//// COMPOSE & SEND +/** + * expands the options sidebar + */ +SE.composeLayout = { + currentInstanceId : 0, + ccHidden : true, + bccHidden : true, + outboundAccountErrors : null, + loadedTinyInstances : {}, //Tracks which tinyMCE editors have initalized with html content. + + showAddressDetails : function(e) { + var linkElement = document.getElementById("More"+e.id); + var spanElement = document.getElementById("Detail"+e.id); + var emailAddressList = e.value; + if(e.value.length > 96) + { + var resultArray = SE.composeLayout._getEmailArrayFromString(emailAddressList); + var displayArray = []; + for (var i=0; i<' + t_emailAddr + '>'); + else + displayArray.push(t_name + '
    <' + t_emailAddr + '>'); + } + + var result = displayArray.join('
    '); + // Display + linkElement.style.display = "inline"; + linkElement.style.height="10px"; + linkElement.style.overflow="visible"; + spanElement.innerHTML = result; + } + else + linkElement.style.display = "none"; + + }, + + /** + * Given a string of email address, return an array containing the name portion (if available) + * and email portion. + */ + _getEmailArrayFromString : function (emailAddressList){ + + var reg = /@.*?;/g; + while ((results = reg.exec(emailAddressList)) != null) + { + orignial = results[0]; + parsedResult = results[0].replace(';', ':::::'); + emailAddressList = emailAddressList.replace (orignial, parsedResult); + } + + reg = /@.*?,/g; + while ((results = reg.exec(emailAddressList)) != null) + { + orignial = results[0]; + parsedResult = results[0].replace(',', ':::::'); + emailAddressList = emailAddressList.replace (orignial, parsedResult); + } + //Administrator ;1@somwhe.com;2@somwherecomplex.com,3@somwherecomplex.com;4@somwherecomplex.com,5@somwherecomplex.com, + var emailArr = emailAddressList.split(":::::"); + var resultsArray = []; + var newArr = []; + for (var i=0; i'); + + if(trim(emailArr[i]) != '') + { + if(rposition != -1 && lposition != -1) + { + var t_name = emailArr[i].substr(0, rposition-1); + var t_emailAddr = emailArr[i].substr(rposition+1, (lposition-1 - rposition) ); + resultsArray.push({'name':t_name, 'email_address': t_emailAddr}); + } + else + { + resultsArray.push({'name':'', 'email_address': emailArr[i]}); + } + } + } + return resultsArray; + }, + /////////////////////////////////////////////////////////////////////////// + //// COMPOSE FLOW + /** + * Prepare bucket DIV and yui-ext tab panels + */ + _0_yui : function() { + var idx = this.currentInstanceId; + + var composeTab = new YAHOO.SUGAR.ClosableTab({ + label: mod_strings.LNK_NEW_SEND_EMAIL, + scroll : true, + content : "
    ", + id : "composeTab" + idx, + closeMsg: app_strings.LBL_EMAIL_CONFIRM_CLOSE, + active : true + }, SE.innerLayout); + SE.innerLayout.addTab(composeTab); + + // get template engine with template + if (!SE.composeLayout.composeTemplate) { + SE.composeLayout.composeTemplate = new YAHOO.SUGAR.Template(SE.templates['compose']); + } + + // create Tab inner layout + var composePanel = this.getComposeLayout(); + composePanel.getUnitByPosition("right").collapse(); + composePanel.autoSize(); + + }, + /** + * Generate the quick compose layout + * @method getQuickComposeLayout + * @param {Pannel} parentPanel Parent pannel + * @param {Object} o Options + * @return {} none + **/ + getQuickComposeLayout : function (parentPanel,o) { + var idx = SE.composeLayout.currentInstanceId; + + //Before rendering the parent pannel we need to initalize the grid layout + parentPanel.beforeRenderEvent.subscribe(function() { + + YAHOO.util.Event.onAvailable('htmleditordiv' + idx, function() { + SE.composeLayout._createComposeLayout(idx); + SE.composeLayout[idx].set('height', 350); + SE.composeLayout[idx].render(); + }); + }); + + //Wait until the Compose Layout has rendered, then add the + //options tab and perform the tiny initialization. + parentPanel.renderEvent.subscribe(function() { + + YAHOO.util.Event.onAvailable('htmleditordiv' + idx, function() { + SE.composeLayout._initComposeOptionTabs(idx); + SE.composeLayout[idx].getUnitByPosition("right").collapse(); + //Initialize tinyMCE + if (!SUGAR.util.isTouchScreen()) + SE.composeLayout._1_tiny(); + //Init templates and address book + SE.composeLayout._2_final(); + + SE.composeLayout.quickCreateComposePackage(o); + + }); + }); + + //Check if we have the div override for the shortcut bar + if(typeof o.menu_id != 'undefined') { + parentPanel.render(o.menu_id); + } else { + parentPanel.render(document.body); + } + + return SE.composeLayout[idx]; + }, + /** + * Fill in all fields into the quick compose layout. + * @method quickCreateComposePackage + * @param {Object} o Options + * @return {} none + **/ + quickCreateComposePackage: function(o) + { + //If we have a compose package fill in defaults. + if (typeof(o.composePackage) != 'undefined') + { + composePackage = o.composePackage; //Set the compose data object + //Hijack this method called by composePackage as it's not need for quick creates. + SE.composeLayout.c0_composeNewEmail = function(){}; + SE.composeLayout.composePackage(); //Fill in defaults. + } + }, + getComposeLayout : function() { + var idx = SE.composeLayout.currentInstanceId; + + this._createComposeLayout(idx); + SE.composeLayout[idx].render(); + this._initComposeOptionTabs(idx); + + return SE.composeLayout[idx]; + }, + + /** + * Create the layout manager for the compose window. + */ + _createComposeLayout : function(idx) + { + SE.composeLayout[idx] = new YAHOO.widget.Layout('htmleditordiv' + idx, { + parent: SE.complexLayout, + border:true, + hideOnLayout: true, + height: 400, + units: [{ + position: "center", + animate: false, + scroll: false, + split:true, + body: + SE.composeLayout.composeTemplate.exec({ + 'app_strings':app_strings, + 'mod_strings':mod_strings, + 'theme': theme, + 'linkbeans_options' : linkBeans, + 'idx' : SE.composeLayout.currentInstanceId + }) + },{ + position: "right", + scroll:true, + collapse: true, + collapsed: true, + resize: true, + border:true, + animate: false, + width:'230', + body: "
    ", + titlebar: true, + split: true, + header: app_strings.LBL_EMAIL_OPTIONS + }] + }); + }, + + /** + * Create compose tab which will populate the 'right' container in the compose window. + */ + _initComposeOptionTabs : function(idx) + { + var cTabs = new YAHOO.widget.TabView("composeRightTabs" + idx); + var tab = new YAHOO.widget.Tab({ + label: app_strings.LBL_EMAIL_ATTACHMENT, + scroll : true, + content : SUGAR.util.getAndRemove("divAttachments" + idx).innerHTML, + id : "divAttachments" + idx, + active : true + }); + + tab.layout = SE.composeLayout[idx]; + + tab.on("activeChange", function(o){ + if (o.newValue) { + this.layout.getUnitByPosition("right").set("header", app_strings.LBL_EMAIL_ATTACHMENT); + } + }); + + cTabs.addTab(tab); + + tab = new YAHOO.widget.Tab({ + label: app_strings.LBL_EMAIL_OPTIONS, + scroll : true, + content : SUGAR.util.getAndRemove("divOptions" + idx).innerHTML, + id : "divOptions" + idx, + active : false + }); + + tab.layout = SE.composeLayout[idx]; + tab.on("activeChange", function(o){ + if (o.newValue) { + this.layout.getUnitByPosition("right").set("header", app_strings.LBL_EMAIL_OPTIONS); + } + }); + cTabs.addTab(tab); + + SE.composeLayout[idx].autoSize = function() { + var pEl = this.get("element").parentNode.parentNode.parentNode; + this.set("height", pEl.clientHeight-30); + this.render(); + } + + SE.composeLayout[idx].rightTabs = cTabs; + }, + isParentTypeValid : function(idx) { + var parentTypeValue = document.getElementById('data_parent_type' + idx).value; + var parentNameValue = document.getElementById('data_parent_name' + idx).value; + if (trim(parentTypeValue) == ""){ + alert(mod_strings.LBL_ERROR_SELECT_MODULE); + return false; + } // if + return true; + }, + + isParentTypeAndNameValid : function(idx) { + var parentTypeValue = document.getElementById('data_parent_type' + idx).value; + var parentNameValue = document.getElementById('data_parent_name' + idx).value; + var parentIdValue = document.getElementById('data_parent_id' + idx).value; + if ((trim(parentTypeValue) != "" && trim(parentNameValue) == "") || + (trim(parentTypeValue) != "" && trim(parentNameValue) != "" && parentIdValue == "")){ + alert(mod_strings.LBL_ERROR_SELECT_MODULE_SELECT); + return false; + } // if + return true; + }, + + callopenpopupForEmail2 : function(idx,options) { + + var formName = 'emailCompose' + idx; + + if(typeof(options) != 'undefined' && typeof(options.form_name) != 'undefined') + formName = options.form_name; + + var parentTypeValue = document.getElementById('data_parent_type' + idx).value; + var parentNameValue = document.getElementById('data_parent_name' + idx).value; + if (!SE.composeLayout.isParentTypeValid(idx)) { + return; + } // if + open_popup(document.getElementById('data_parent_type' + idx).value,600,400,'&tree=ProductsProd',true,false, + { + call_back_function:"SE.composeLayout.popupAddEmail", + form_name:formName, + field_to_name_array:{ + id:'data_parent_id' + idx, + name:'data_parent_name' + idx, + email1:'email1'} + }); + }, + + popupAddEmail : function(o) + { + var nameKey = "data_parent_name" + SE.composeLayout.currentInstanceId; + var data = o.name_to_value_array; + if (typeof (data[nameKey]) != "undefined" && data[nameKey] != "" + && typeof (data["email1"]) != "undefined" && data["email1"] != "" && data["email1"] != "undefined") + { + var target = Dom.get("addressTO" + SE.composeLayout.currentInstanceId); + target.value = SE.addressBook.smartAddEmailAddressToComposeField(target.value, data[nameKey] + "<" + data.email1 + ">"); + } + set_return(o); + }, + /** + * Prepare TinyMCE + */ + _1_tiny : function() { + var idx = SE.composeLayout.currentInstanceId; + var elId = SE.tinyInstances.currentHtmleditor = 'htmleditor' + idx; + SE.tinyInstances[elId] = { }; + SE.tinyInstances[elId].ready = false; + var t = tinyMCE.getInstanceById(elId); + + if(typeof(t) == 'undefined') { + tinyMCE.execCommand('mceAddControl', false, elId); + YAHOO.util.Event.onAvailable(elId + "_parent", function() { + SE.composeLayout.resizeEditor(idx); + setTimeout("SUGAR.email2.composeLayout.setSignature('" + idx + "')", 1000); + }, this); + } + }, + + resizeEditor : function(idx) + { + var cof = Dom.get('composeOverFrame' + idx); + var head = Dom.get('composeHeaderTable' + idx); + var targetHeight = cof.clientHeight - head.clientHeight; + var instance = tinyMCE.get(SE.tinyInstances.currentHtmleditor); + + var parentEl = Dom.get(instance.editorId + '_parent'); + var toolbar = Dom.getElementsByClassName("mceFirst", "tr", parentEl)[0]; + var contentEl = instance.contentAreaContainer; + var iFrame = contentEl.firstChild; + var tinMceToolbarOffset = 18; + iFrame.style.height = (targetHeight - toolbar.offsetHeight - tinMceToolbarOffset) + "px"; + }, + + /** + * Initializes d&d, auto-complete, email templates + */ + _2_final : function() { + var idx = SE.composeLayout.currentInstanceId; + + if(this.emailTemplates) { + this.setComposeOptions(idx); + } else { + //populate email template cache + AjaxObject.target = ''; + AjaxObject.startRequest(callbackComposeCache, urlStandard + "&emailUIAction=fillComposeCache"); + } + + // handle drop targets for addressBook + var to = new YAHOO.util.DDTarget('addressTO' +idx, 'addressBookDD', {notifyDrop:this.handleDrop}); + var cc = new YAHOO.util.DDTarget('addressCC' +idx, 'addressBookDD', {notifyDrop:this.handleDrop}); + var bcc = new YAHOO.util.DDTarget('addressBCC'+idx, 'addressBookDD', {notifyDrop:this.handleDrop}); + to.notifyDrop = cc.notifyDrop = bcc.notifyDrop = this.handleDrop; + + // auto-complete setup + SE.autoComplete.init(idx); + + // set focus on to: + document.getElementById("addressTO" + idx).focus(); + }, + + /** + * hide tinyMCE tool bar if send email as plaintext is checked + */ + renderTinyMCEToolBar : function (idx, hide) { + if (hide) { + document.getElementById('htmleditor' + idx + '_toolbar1').style.display = 'none'; + } else { + document.getElementById('htmleditor' + idx + '_toolbar1').style.display = ''; + } + }, + + c1_composeEmail : function(isReplyForward, retry) { + if (!retry) { + this._0_yui(); + } + if (typeof(tinyMCE) == 'undefined' || typeof(tinyMCE.settings) == 'undefined'){ + setTimeout("SE.composeLayout.c1_composeEmail(" + isReplyForward + ", true);", 500); + } else { + this._1_tiny(); + this._2_final(); + + if(isReplyForward) { + this.replyForwardEmailStage2(); + } + } + }, + + /** + * takes draft info and prepopulates + */ + c0_composeDraft : function() { + this.getNewInstanceId(); + inCompose = true; + document.getElementById('_blank').innerHTML = ''; + var idx = SE.composeLayout.currentInstanceId; + SE.composeLayout.draftObject = new Object(); + SE.composeLayout.draftObject.id = idx; + SE.composeLayout.draftObject.isDraft = true; + SE.composeLayout.currentInstanceId = idx; + SE.tinyInstances.currentHtmleditor = 'htmleditor' + SE.composeLayout.currentInstanceId; + SE.tinyInstances[SE.tinyInstances.currentHtmleditor] = new Object(); + SE.tinyInstances[SE.tinyInstances.currentHtmleditor].ready = false; + + SE.composeLayout._0_yui(); + SE.composeLayout._1_tiny(); + + // final touches + SE.composeLayout._2_final(); + + /* Draft-specific final processing. Need a delay to allow Tiny to render before calling setText() */ + setTimeout("AjaxObject.handleReplyForwardForDraft(SE.o);", 1000); + }, + + /** + * Strip & Prep editor hidden fields + */ + c0_composeNewEmail : function() { + this.getNewInstanceId(); + this.c1_composeEmail(false); + }, + + /** + * Sends async request to get the compose view. + * Requests come from "reply" or "forwards" + */ + c0_replyForwardEmail : function(ieId, uid, mbox, type) { + SE.composeLayout.replyForwardObj = new Object(); + SE.composeLayout.replyForwardObj.ieId = ieId; + SE.composeLayout.replyForwardObj.uid = uid; + SE.composeLayout.replyForwardObj.mbox = mbox; + SE.composeLayout.replyForwardObj.type = type; + + if(mbox == 'sugar::Emails') { + SE.composeLayout.replyForwardObj.sugarEmail = true; + } + + SE.composeLayout.getNewInstanceId(); + SE.composeLayout.c1_composeEmail(true); + }, + //// END COMPOSE FLOW + /////////////////////////////////////////////////////////////////////////// + + /** + * Called when a contact, email, or mailinglist is dropped + * into one of the compose fields. + */ + handleDrop : function (source, event, data, target) { + var nodes; + if (!target) { + target = event.getTarget(); + if (data.single) { + data.nodes = [data.nodes]; + } + nodes = data.nodes; + } else { + target = document.getElementById(target); + nodes = data; + } + + if (target.id.indexOf('address') > -1) { + // dropped onto email to/cc/bcc field + for(var i in nodes) { + var node = nodes[i].getData(); + var email = ""; + if (node[1].indexOf('contact') > -1) { + email = SE.addressBook.getFormattedAddress(node[0]); + } else if (node[1].indexOf('address-email') > -1){ + email = node[3].replace(/ /gi, ''); + email = email.replace('<', '<').replace('>', '>'); + var tr = source.getTrEl(nodes[i]); + while (tr && !Dom.hasClass(tr, "address-contact")) { + tr = source.getPreviousTrEl(tr); + } + var CID = source.getRecord(tr).getData()[0]; + var o = SE.addressBook._contactCache[CID]; + var name = new String(o.name); + var finalName = name.replace(/(<([^>]+)>)/ig, ""); + email = finalName + email; + } + target.value = SE.addressBook.smartAddEmailAddressToComposeField(target.value, email); + } + } + }, + + + /*///////////////////////////////////////////////////////////////////////////// + /// EMAIL TEMPLATE CODE + */ + applyEmailTemplate : function (idx, id) { + + //bug #20680 + var box_title = mod_strings.LBL_EMAILTEMPLATE_MESSAGE_SHOW_TITLE; + var box_msg = mod_strings.LBL_EMAILTEMPLATE_MESSAGE_SHOW_MSG; + var box_none_msg = mod_strings.LBL_EMAILTEMPLATE_MESSAGE_CLEAR_MSG; + //Bug #6224 + var to_addr = document.getElementById('addressTO'+idx); + if (to_addr.value.search(/[^;,]{6,}[;,][^;,]{6,}/) != -1) { + box_title = mod_strings.LBL_EMAILTEMPLATE_MESSAGE_WARNING_TITLE; + box_msg = mod_strings.LBL_EMAILTEMPLATE_MESSAGE_MULTIPLE_RECIPIENTS + '

    ' + box_msg; + } + + // id is selected index of email template drop-down + if(id == '' || id == "0") { + YAHOO.SUGAR.MessageBox.show({ + title:box_title, + msg: box_none_msg, + type: 'confirm', + fn: function(btn){ + if(btn=='no'){return;}; + SUGAR.email2.composeLayout.processNoneResult(idx, id);}, + modal:true, + scope:this + }); + return; + } + + YAHOO.SUGAR.MessageBox.show({ + title:box_title, + msg: box_msg, + type: 'confirm', + fn: function(btn){ + if(btn=='no'){return;}; + SUGAR.email2.composeLayout.processResult(idx, id);}, + modal:true, + scope:this + }); + }, + + processNoneResult : function(idx, id) { + var tiny = SE.util.getTiny('htmleditor' + idx); + var tinyHTML = tiny.getContent(); + var openTag = '
    '; + var htmllow = tinyHTML.toLowerCase(); + var start = htmllow.indexOf(openTag); + if (start > -1) { + tinyHTML = tinyHTML.substr(start); + tiny.setContent(tinyHTML); + } else { + tiny.setContent(''); + } + }, + + processResult : function(idx , id){ + call_json_method('EmailTemplates','retrieve','record='+id,'email_template_object', this.appendEmailTemplateJSON); + + // get attachments if any + AjaxObject.target = ''; + AjaxObject.startRequest(callbackLoadAttachments, urlStandard + "&emailUIAction=getTemplateAttachments&parent_id=" + id); + }, + + appendEmailTemplateJSON : function() { + var idx = SE.composeLayout.currentInstanceId; // post increment + + // query based on template, contact_id0,related_to + //jchi 09/10/2008 refix #7743 + if(json_objects['email_template_object']['fields']['subject'] != '' ) { // cn: bug 7743, don't stomp populated Subject Line + document.getElementById('emailSubject' + idx).value = decodeURI(encodeURI(json_objects['email_template_object']['fields']['subject'])); + } + + var text = decodeURI(encodeURI(json_objects['email_template_object']['fields']['body_html'])).replace(/
    /ig, '\n').replace(/
    /gi, "\n").replace(/&/gi,'&').replace(/</gi,'<').replace(/>/gi,'>').replace(/'/gi,'\'').replace(/"/gi,'"'); + + // cn: bug 14361 - text-only templates don't fill compose screen + if(text == '') { + text = decodeURI(encodeURI(json_objects['email_template_object']['fields']['body'])).replace(/
    /ig, '\n').replace(/
    /gi, "\n").replace(/&/gi,'&').replace(/</gi,'<').replace(/>/gi,'>').replace(/'/gi,'\'').replace(/"/gi,'"').replace(/\r\n/gi,"
    "); + } + + var tiny = SE.util.getTiny('htmleditor' + idx); + var tinyHTML = tiny.getContent(); + var openTag = '
    '; + var closeTag = '
    '; + var htmllow = tinyHTML.toLowerCase(); + var start = htmllow.indexOf(openTag); + if (start > -1) { + var htmlPart2 = tinyHTML.substr(start); + tinyHTML = text + htmlPart2; + tiny.setContent(tinyHTML); + } else { + tiny.setContent(text); + } + }, + + /** + * Writes out the signature in the email editor + */ + setSignature : function(idx) { + if (!tinyMCE) + return false; + var hide = document.getElementById('setEditor' + idx).checked; + SE.composeLayout.renderTinyMCEToolBar(idx,hide); + //wait for signatures to load before trying to set them + if (!SE.composeLayout.signatures) { + setTimeout("SE.composeLayout.setSignature(" + idx + ");", 1000); + return; + } + + if(idx) { + var sel = document.getElementById('signatures' + idx); + } else { + var sel = document.getElementById('signature_id'); + idx = SE.tinyInstances.currentHtmleditor; + } + + //Ensure that the tinyMCE html has been rendered. + if(typeof(SE.composeLayout.loadedTinyInstances[idx]) != 'undefined' && SE.composeLayout.loadedTinyInstances[idx] == false) { + setTimeout("SE.composeLayout.setSignature(" + idx + ");",1000); + return; + } + + var signature = ''; + + try { + signature = sel.options[sel.selectedIndex].value; + } catch(e) { + + } + + var openTag = '
    '; + var closeTag = '
    '; + var t = SE.util.getTiny('htmleditor' + idx); + //IE 6 Hack + if(typeof(t) != 'undefined') + { + t.contentDocument = t.contentWindow.document; + var html = t.getContent(); + } + else + var html = ''; + + var htmllow = html.toLowerCase(); + var start = htmllow.indexOf(openTag); + var end = htmllow.indexOf(closeTag) + closeTag.length; + + // selected "none" - remove signature from email + if(signature == '') { + if (start > -1) { + var htmlPart1 = html.substr(0, start); + var htmlPart2 = html.substr(end, html.length); + + html = htmlPart1 + htmlPart2; + t.setContent(html); + } + SE.signatures.lastAttemptedLoad = ''; + return false; + } + + if(!SE.signatures.lastAttemptedLoad) // lazy load place holder + SE.signatures.lastAttemptedLoad = ''; + + SE.signatures.lastAttemptedLoad = signature; + + if(typeof(SE.signatures[signature]) == 'undefined') { + //lazy load + SE.signatures.lastAttemptedLoad = ''; // reset this flag for recursion + SE.signatures.targetInstance = (idx) ? idx : ""; + AjaxObject.target = ''; + AjaxObject.startRequest(callbackLoadSignature, urlStandard + "&emailUIAction=getSignature&id="+signature); + } else { + var newSignature = this.prepareSignature(SE.signatures[signature]); + + // clear out old signature + if(SE.signatures.lastAttemptedLoad && start > -1) { + var htmlPart1 = html.substr(0, start); + var htmlPart2 = html.substr(end, html.length); + + html = htmlPart1 + htmlPart2; + } + + // [pre|ap]pend + start = html.indexOf('

    '); + if(SE.userPrefs.signatures.signature_prepend == 'true' && start > -1) { + var htmlPart1 = html.substr(0, start); + var htmlPart2 = html.substr(start, html.length); + var newHtml = htmlPart1 + openTag + newSignature + closeTag + htmlPart2; + } else if(SUGAR.email2.userPrefs.signatures.signature_prepend == 'true') { + var newHtml = '
    ' + openTag + newSignature + closeTag + html; + } else { + var newHtml = html + openTag + newSignature + closeTag; + } + //tinyMCE.setContent(newHtml); + t.setContent(newHtml); + } + }, + + prepareSignature : function(str) { + var signature = new String(str); + + signature = signature.replace(/</gi, '<'); + signature = signature.replace(/>/gi, '>'); + + return signature; + }, + + + showAttachmentPanel : function(idx) { + var east = SE.composeLayout[idx].getUnitByPosition("right"); + var tabs = SE.composeLayout[idx].rightTabs; + east.expand(); + tabs.set("activeTab", tabs.getTab(0)); + }, + + /** + * expands sidebar and displays options panel + */ + showOptionsPanel : function(idx) { + var east = SE.composeLayout[idx].getUnitByPosition("right"); + var tabs = SE.composeLayout[idx].rightTabs; + east.expand(); + tabs.set("activeTab", tabs.getTab(1)); + }, + + /** + * Selects the Contacts tab + */ + showContactsPanel : function() { + SE.complexLayout.regions.west.showPanel("contactsTab"); + }, + + /** + * Generates fields for Select Document + */ + addDocumentField : function(idx) { + var basket = document.getElementById('addedDocuments' + idx); + if(basket) { + var index = (basket.childNodes.length / 7) - 1; + if(index < 0) + index = 0; + } else { + index = 0; + } + + var test = document.getElementById('documentId' + idx + index); + + while(test != null) { + index++; + test = document.getElementById('documentId' + idx + index); + } + + var documentCup = document.createElement("div"); + documentCup.id = 'documentCup' + idx + index; + documentCup.innerHTML = "" + + // document id field + "" + + // document name field + "" + + // select button + "" + + // remove button + "" + + "
    "; + + basket.appendChild(documentCup); + //basket.innerHTML += out; + return index; + }, + + /** + * Makes async call to save a draft of the email + * @param int Instance index + */ + saveDraft : function(tinyInstance) { + this.sendEmail(tinyInstance, true); + }, + + selectDocument : function(target) { + URL="index.php?module=Emails&action=PopupDocuments&to_pdf=true&target=" + target; + windowName = 'selectDocument'; + windowFeatures = 'width=800' + ',height=600' + ',resizable=1,scrollbars=1'; + + win = window.open(URL, windowName, windowFeatures); + if(window.focus) { + // put the focus on the popup if the browser supports the focus() method + win.focus(); + } + }, + + /** + * Modal popup for file attachment dialogue + */ + addFileField : function() { + if(!SE.addFileDialog){ // lazy initialize the dialog and only create it once + SE.addFileDialog = new YAHOO.widget.Dialog("addFileDialog", { + modal:true, + visible:false, + fixedcenter:true, + constraintoviewport: true, + scroll: true, + keylisteners : new YAHOO.util.KeyListener(document, { keys:27 }, { + fn:function(){SE.addFileDialog.hide();} + }) + }); + SE.addFileDialog.setHeader(app_strings.LBL_EMAIL_ATTACHMENTS); + SE.addFileDialog.render(); + // SE.addFileDialog.addKeyListener(27, , SE.addFileDialog); + } + Dom.removeClass("addFileDialog", "yui-hidden"); + + SE.addFileDialog.show(); + }, + + /** + * Async upload of file to temp dir + */ + uploadAttachment : function() { + if(document.getElementById('email_attachment').value != "") { + var formObject = document.getElementById('uploadAttachment'); + YAHOO.util.Connect.setForm(formObject, true, true); + AjaxObject.target = ''; + AjaxObject.startRequest(callbackUploadAttachment, null); + } else { + alert(app_strings.LBL_EMAIL_ERROR_NO_FILE); + } + }, + + /** + * Adds a SugarDocument to an outbound email. Action occurs in a popup window displaying a ListView from the Documents module + * @param string target in focus compose layout + */ + setDocument : function(idx, target, documentId, documentName, docRevId) { + // fields are named/id'd [fieldName][instanceId][index] + var addedDocs = document.getElementById("addedDocuments" + idx); + var docId = document.getElementById('documentId' + idx + target); + var docName = document.getElementById('documentName' + idx + target); + var docRevisionId = document.getElementById('document' + idx + target); + docId.value = documentId; + docName.value = documentName; + docRevisionId.value = docRevId; + }, + + /** + * Removes the bucket div containing the document input fields + */ + deleteDocumentField : function(documentCup) { + var f0 = document.getElementById(documentCup); + f0.parentNode.removeChild(f0); + }, + + /** + * Removes a Template Attachment field + * @param int + * @param int + */ + deleteTemplateAttachmentField : function(idx, index) { + // create not-in-array values for removal filtering + var r = document.getElementById("templateAttachmentsRemove" + idx).value; + + if(r != "") { + r += "::"; + } + + r += document.getElementById('templateAttachmentId' + idx + index).value; + document.getElementById("templateAttachmentsRemove" + idx).value = r; + + var target = 'templateAttachmentCup' + idx + index; + d = document.getElementById(target); + d.parentNode.removeChild(d); + }, + + /** + * Async removal of uploaded temp file + * @param string index Should be a concatenation of idx and index + * @param string + */ + deleteUploadAttachment : function(index, file) { + var d = document.getElementById('email_attachment_bucket' + index); + d.parentNode.removeChild(d); + + // make async call to delete cached file + AjaxObject.target = ''; + AjaxObject.startRequest(null, urlStandard + "&emailUIAction=removeUploadedAttachment&file="+file); + }, + + /** + * Attaches files coming from Email Templates + */ + addTemplateAttachmentField : function(idx) { + // expose title + document.getElementById('templateAttachmentsTitle' + idx).style.display = 'block'; + + var basket = document.getElementById('addedTemplateAttachments' + idx); + + if(basket) { + var index = basket.childNodes.length; + if(index < 0) + index = 0; + } else { + index = 0; + } + + var out = "
    " + + // remove button + "" + + // file icon + "" + + // templateAttachment field + "" + + // docId field + "" + + // file name + " " + + "

    " + + "
    "; + basket.innerHTML = basket.innerHTML + out; + + return index; + }, + + /** + * Sends one email via async call + * @param int idx Editor instance ID + * @param bool isDraft + */ + sendEmail : function(idx, isDraft) { + + //If the outbound account has an error message associate with it, alert the user and refuse to continue. + var obAccountID = document.getElementById('addressFrom' + idx).value; + + if( typeof(SUGAR.email2.composeLayout.outboundAccountErrors[obAccountID]) != 'undefined' ) + { + overlay(app_strings.LBL_EMAIL_ERROR_DESC, SUGAR.email2.composeLayout.outboundAccountErrors[obAccountID], 'alert'); + return false; + } + + + var form = document.getElementById('emailCompose' + idx); + var composeOptionsFormName = "composeOptionsForm" + idx; + var t = SE.util.getTiny(SE.tinyInstances.currentHtmleditor); + var html = t.getContent(); + var subj = document.getElementById('emailSubject' + idx).value; + var to = trim(document.getElementById('addressTO' + idx).value); + var cc = trim(document.getElementById('addressCC' + idx).value); + var bcc = trim(document.getElementById('addressBCC' + idx).value); + var email_id = document.getElementById('email_id' + idx).value; + var composeType = document.getElementById('composeType').value; + var parent_type = document.getElementById("parent_type").value; + var parent_id = document.getElementById("parent_id").value; + + var el_uid = document.getElementById("uid"); + var uid = (el_uid == null) ? '' : el_uid.value; + + var el_ieId = document.getElementById("ieId"); + var ieId = (el_ieId == null) ? '' : el_ieId.value; + + var el_mbox = document.getElementById("mbox"); + var mbox = (el_mbox == null) ? '' : el_mbox.value; + + if (!isValidEmail(to) || !isValidEmail(cc) || !isValidEmail(bcc)) { + alert(app_strings.LBL_EMAIL_COMPOSE_INVALID_ADDRESS); + return false; + } + + if (!SE.composeLayout.isParentTypeAndNameValid(idx)) { + return; + } // if + var parentTypeValue = document.getElementById('data_parent_type' + idx).value; + var parentIdValue = document.getElementById('data_parent_id' + idx).value; + parent_id = parentIdValue; + parent_type = parentTypeValue; + + var in_draft = (document.getElementById('type' + idx).value == 'draft') ? true : false; + // baseline viability check + + if(to == "" && cc == '' && bcc == '' && !isDraft) { + alert(app_strings.LBL_EMAIL_COMPOSE_ERR_NO_RECIPIENTS); + return false; + } else if(subj == '' && !isDraft) { + if(!confirm(app_strings.LBL_EMAIL_COMPOSE_NO_SUBJECT)) { + return false; + } else { + subj = app_strings.LBL_EMAIL_COMPOSE_NO_SUBJECT_LITERAL; + } + } else if(html == '' && !isDraft) { + if(!confirm(app_strings.LBL_EMAIL_COMPOSE_NO_BODY)) { + return false; + } + } + + SE.util.clearHiddenFieldValues('emailCompose' + idx); + document.getElementById('data_parent_id' + idx).value = parentIdValue; + var title = (isDraft) ? app_strings.LBL_EMAIL_SAVE_DRAFT : app_strings.LBL_EMAIL_SENDING_EMAIL; + overlay(title, app_strings.LBL_EMAIL_ONE_MOMENT); + html = html.replace(/</ig, "sugarLessThan"); + html = html.replace(/>/ig, "sugarGreaterThan"); + + form.sendDescription.value = html; + form.sendSubject.value = subj; + form.sendTo.value = to; + form.sendCc.value = cc; + form.sendBcc.value = bcc; + form.email_id.value = email_id; + form.composeType.value = composeType; + form.composeLayoutId.value = 'composeLayout' + idx; + form.setEditor.value = (document.getElementById('setEditor' + idx).checked == false) ? 1 : 0; + form.saveToSugar.value = 1; + form.fromAccount.value = document.getElementById('addressFrom' + idx).value; + form.parent_type.value = parent_type; + form.parent_id.value = parent_id; + form.uid.value = uid; + form.ieId.value = ieId; + form.mbox.value = mbox; + + // email attachments + var addedFiles = document.getElementById('addedFiles' + idx); + if(addedFiles) { + for(i=0; i 0) { + document.getElementById("emailSubject" + SE.composeLayout.currentInstanceId).value = composePackage.subject; + } + + //If no parent fields are set in the composePackage, ensure they are cleared. + var parentFields = ['parent_type','parent_name','parent_id']; + for(var i=0;i 0) { + document.getElementById("email_id" + SE.composeLayout.currentInstanceId).value = composePackage.email_id; + } // if + if (composePackage.body != null && composePackage.body.length > 0) { + var tiny = SE.util.getTiny('htmleditor' + SE.composeLayout.currentInstanceId); + SE.composeLayout.loadedTinyInstances[SE.composeLayout.currentInstanceId] = false; + setTimeout("SE.composeLayout.setContentOnThisTiny();", 3000); + } // if + if (composePackage.attachments != null) { + SE.composeLayout.loadAttachments(composePackage.attachments); + } // if + + if (composePackage.fromAccounts != null && composePackage.fromAccounts.status) { + var addressFrom = document.getElementById('addressFrom' + SE.composeLayout.currentInstanceId); + SE.util.emptySelectOptions(addressFrom); + var fromAccountOpts = composePackage.fromAccounts.data; + for(i=0; i/ig, '\n').replace(/
    /gi, "\n").replace(/&/gi,'&').replace(/</gi,'<').replace(/>/gi,'>').replace(/'/gi,'\'').replace(/"/gi,'"'); + } // if + //Flag determines if we should clear the tiny contents or just append + if (typeof(composePackage.clearBody) != 'undefined' && composePackage.clearBody) + SE.composeLayout.tinyHTML = ''; + else + SE.composeLayout.tinyHTML = tinyHTML + composePackage.body; + + tiny.setContent(SE.composeLayout.tinyHTML); + //Indicate that the contents has been loaded successfully. + SE.composeLayout.loadedTinyInstances[SE.composeLayout.currentInstanceId] = true; + }, + /** + * Confirms closure of a compose screen if "x" is clicked + */ + confirmClose : function(panel) { + if(confirm(app_strings.LBL_EMAIL_CONFIRM_CLOSE)) { + SE.composeLayout.closeCompose(panel.id); + return true; + } else { + return false; + } + }, + + /** + * forces close of a compose screen + */ + forceCloseCompose : function(id) { + SE.composeLayout.closeCompose(id); + + // handle flow back to originating view + if(composePackage) { + // check if it's a module we need to return to + if(composePackage.return_module && composePackage.return_action && composePackage.return_id) { + if(confirm(app_strings.LBL_EMAIL_RETURN_TO_VIEW)) { + var url = "index.php?module=" + composePackage.return_module + "&action=" + composePackage.return_action + "&record=" + composePackage.return_id; + window.location = url; + } + } + } + }, + + /** + * closes the editor that just sent email + * @param string id ID of composeLayout tab + */ + closeCompose : function(id) { + // destroy tinyMCE instance + var idx = id.substr(13, id.length); + var instanceId = "htmleditor" + idx; + tinyMCE.execCommand('mceRemoveControl', false, instanceId); + + // nullify DOM and namespace values. + inCompose = false; + SE.composeLayout[idx] = null; + SE.tinyInstances[instanceId] = null; + var tabsArray = SE.innerLayout.get("tabs"); + for (i = 0 ; i < tabsArray.length ; i++) { + if (tabsArray[i].get("id") == ('composeTab' + idx)) { + tabsArray[i].close(); + break; + } + } + //SE.innerLayout.getTab(idx).close(); + }, + + /** + * Enable the quick search for the compose relate field or search tab + */ + enableQuickSearchRelate: function(idx,overides){ + + if(typeof overides != 'undefined') + { + var newModuleID = overides['moduleSelectField']; //data_parent_type_search + var newModule = document.getElementById(newModuleID).value; + var formName = overides['formName']; + var fieldName = overides['fieldName']; + var fieldId = overides['fieldId']; + var fullName = formName + "_" + fieldName; + var postBlurFunction = null; + } + else + { + var newModule = document.getElementById('data_parent_type'+idx).value; + var formName = 'emailCompose'+idx; + var fieldName = 'data_parent_name'+idx; + var fieldId = 'data_parent_id'+idx; + var fullName = formName + "_" + fieldName; + var postBlurFunction = "SE.composeLayout.qsAddAddress"; + } + + if(typeof sqs_objects == 'undefined') + window['sqs_objects'] = new Array; + + window['sqs_objects'][fullName] = { + form:formName, + method:"query", + modules:[newModule], + group:"or", + field_list:["name","id", "email1"],populate_list:[fieldName,fieldId],required_list:[fieldId], + conditions:[{name:"name",op:"like_custom",end:"%",value:""}], + post_onblur_function: postBlurFunction, + order:"name","limit":"30","no_match_text":"No Match"}; + + + if(typeof QSProcessedFieldsArray != 'undefined') + QSProcessedFieldsArray[fullName] = false; + if (typeof(QSFieldsArray) != 'undefined' && typeof(QSFieldsArray[fullName]) != 'undefined') { + QSFieldsArray[fullName].destroy(); + delete QSFieldsArray[fullName]; + } + if (Dom.get(fullName + "_results")) { + Dom.get(fullName + "_results").parentNode.removeChild(Dom.get(fullName + "_results")); + } + + enableQS(false); + }, + + qsAddAddress : function(o) { + if (o.name != "" && o.email1 != "") + { + var target = Dom.get("addressTO" + SE.composeLayout.currentInstanceId); + target.value = SE.addressBook.smartAddEmailAddressToComposeField(target.value, o.name + "<" + o.email1 + ">"); + } + }, + /** + * Returns a new instance ID, 0-index + */ + getNewInstanceId : function() { + this.currentInstanceId = this.currentInstanceId + 1; + return this.currentInstanceId; + }, + + /** + * Takes an array of objects that contain the filename and GUID of a Note (attachment or Sugar Document) and applies the values to the compose screen. Valid use-cases are applying an EmailTemplate or resuming a Draft Email. + */ + loadAttachments : function(result) { + var idx = SE.composeLayout.currentInstanceId; + + if(typeof(result) == 'object') { + //jchi #20680. Clean the former template attachments; + var basket = document.getElementById('addedTemplateAttachments' + idx); + if(basket.innerHTML != ''){ + confirm(mod_strings.LBL_CHECK_ATTACHMENTS, mod_strings.LBL_HAS_ATTACHMENTS, function(btn){ + if (btn != 'yes'){ + basket.innerHTML = ''; + } + }); + } + for(i in result) { + if(typeof result[i] == 'object') { + var index = SE.composeLayout.addTemplateAttachmentField(idx); + var bean = result[i]; + document.getElementById('templateAttachmentId' + idx + index).value = bean['id']; + document.getElementById('templateAttachmentName' + idx + index).innerHTML += bean['filename']; + } + } + } + }, + + /** + * fills drop-down values for email templates and signatures + */ + setComposeOptions : function(idx) { + // send from accounts + var addressFrom = document.getElementById('addressFrom' + idx); + + if (addressFrom.options.length <= 0) { + SE.util.emptySelectOptions(addressFrom); + var fromAccountOpts = SE.composeLayout.fromAccounts; + for (id = 0 ; id < fromAccountOpts.length ; id++) { + var key = fromAccountOpts[id].value; + var display = fromAccountOpts[id].text; + var is_default = false; + if(key == SUGAR.default_inbound_accnt_id) + is_default = true; + var opt = new Option(display, key); + addressFrom.options.add(opt); + addressFrom.options[id].selected = is_default; //Safari bug new Option(x,y,true) does not work. + } + } + + // email templates + var et = document.getElementById('email_template' + idx); + SE.util.emptySelectOptions(et); + + for(var key in this.emailTemplates) { // iterate through assoc array + var display = this.emailTemplates[key]; + var opt = new Option(display, key); + et.options.add(opt); + } + + // signatures + var sigs = document.getElementById('signatures' + idx); + SE.util.emptySelectOptions(sigs); + + for(var key in this.signatures) { // iterate through assoc array + var display = this.signatures[key]; + var opt = new Option(display, key); + + if(key == SE.userPrefs.signatures.signature_default) { + opt.selected = true; + } + + sigs.options.add(opt); + } + + // html/plain email? + var htmlEmail = document.getElementById('setEditor' + idx); + if(SE.userPrefs.emailSettings.sendPlainText == 1) { + htmlEmail.checked = true; + } else { + htmlEmail.checked = false; + } + + SE.tinyInstances[SE.tinyInstances.currentHtmleditor].ready = true; + }, + + /** + * After compose screen is rendered, async call to get email body from Sugar + */ + replyForwardEmailStage2 : function() { + SE.util.clearHiddenFieldValues('emailUIForm'); + overlay(app_strings.LBL_EMAIL_RETRIEVING_MESSAGE, app_strings.LBL_EMAIL_ONE_MOMENT); + + var ieId = SE.composeLayout.replyForwardObj.ieId; + var uid = SE.composeLayout.replyForwardObj.uid; + var mbox = SE.composeLayout.replyForwardObj.mbox; + var type = SE.composeLayout.replyForwardObj.type; + var idx = SE.composeLayout.currentInstanceId; + + var sugarEmail = (SE.composeLayout.replyForwardObj.sugarEmail) ? '&sugarEmail=true' : ""; + + document.getElementById('emailSubject' + idx).value = type; + document.getElementById('emailUIAction').value = 'composeEmail'; + document.getElementById('composeType').value = type; + document.getElementById('ieId').value = ieId; + document.getElementById('uid').value = uid; + document.getElementById('mbox').value = mbox; + document.getElementById('setEditor' + idx).checked = SE.userPrefs.emailSettings.sendPlainText == 1 ? true : false; + var formObject = document.getElementById('emailUIForm'); + YAHOO.util.Connect.setForm(formObject); + + var sendType = type; + AjaxObject.startRequest(callbackReplyForward, urlStandard + "&composeType=" + type + sugarEmail); + }, + + /** + * Show the hidden cc or bcc fields + */ + showHiddenAddress: function(addrType,idx){ + + Dom.removeClass(addrType+"_tr"+idx, "yui-hidden"); + Dom.addClass(addrType+"_span"+idx, "yui-hidden"); + Dom.addClass("bcc_cc_sep"+idx, "yui-hidden"); + this[addrType+'Hidden'+idx] = false; + + //After bcc or cc is added, move options below last addr field + Dom.insertAfter("add_addr_options_tr"+idx, 'bcc_tr'+idx); + + //If both cc and bcc hidden, remove the empty row containing text. + if( ( typeof(this['ccHidden'+idx]) != 'undefined' && typeof(this['bccHidden'+idx]) != 'undefined') + && ( this['ccHidden'+idx] == false && this['bccHidden'+idx] == false) ) + Dom.addClass("add_addr_options_tr"+idx, "yui-hidden"); + + SE.composeLayout.resizeEditor(idx); + }, + /** + * Hide the cc and bcc fields if they were shown. + */ + hideHiddenAddresses: function(idx){ + + var addrTypes = ['cc','bcc']; + for(var i = 0;i
    '; +// End of File modules/Emails/javascript/composeEmailTemplate.js + +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +/** + Complex layout init + */ +function complexLayoutInit() { + var se = SUGAR.email2; + var Dom = YAHOO.util.Dom; + se.e2Layout = { + getInnerLayout : function(rows) { + se.listViewLayout = new YAHOO.widget.Layout('listViewDiv', { + parent: se.complexLayout, + border:true, + hideOnLayout: true, + height: 400, + units: [{ + position: "center", + scroll:false, // grid should autoScroll itself + split:true, + body: "
    " + },{ + position: "bottom", + scroll:true, + collapse: false, + resize: true, + useShim:true, + height:'250', + body: "
    " + },{ + position: "right", + scroll:true, + collapse: false, + resize: true, + useShim:true, + width:'250', + body: "
    ", + titlebar: false //,header: "right" + }] + }); + se.complexLayout.on("render", function(){ + var height = SUGAR.email2.innerLayout.get("element").clientHeight - 30; + SUGAR.email2.innerLayout.get("activeTab").get("contentEl").parentNode.style.height = height + "px"; + SUGAR.email2.listViewLayout.set("height", height); + SUGAR.email2.listViewLayout.render(); + }); + se.listViewLayout.render(); + //CSS hack for now + se.listViewLayout.get("element").parentNode.parentNode.style.padding = "0px" + var rp = se.listViewLayout.resizePreview = function() { + var pre = Dom.get("displayEmailFramePreview"); + if (pre) { + var parent = Dom.getAncestorByClassName(pre, "yui-layout-bd"); + pre.style.height = (parent.clientHeight - pre.offsetTop) + "px"; + } + }; + se.listViewLayout.getUnitByPosition("bottom").on("heightChange", se.autoSetLayout); + se.listViewLayout.getUnitByPosition("right").on("endResize", se.autoSetLayout); + se.e2Layout.setPreviewPanel(rows); + se.previewLayout = se.listViewLayout; + return se.listViewLayout; + }, + + getInnerLayout2Rows : function() { + return this.getInnerLayout(true); + }, + getInnerLayout2Columns : function() { + return this.getInnerLayout(false); + }, + + init : function(){ + // initialize state manager, we will use cookies +// Ext.state.Manager.setProvider(new Ext.state.CookieProvider()); + var viewHeight = document.documentElement ? document.documentElement.clientHeight : self.innerHeight; + se.complexLayout = new YAHOO.widget.Layout("container", { + border:true, + hideOnLayout: true, + height: Dom.getViewportHeight() - (document.getElementById('header').clientHeight ) - 65, + width: Dom.getViewportWidth() - 40, + units: [{ + position: "center", + scroll:false, + body: "
    " + }, + { + position: "left", + scroll: true, + body: "
    ", + collapse: true, + width: 210, + minWidth: 100, + resize:true, + useShim:true, + titlebar: true, + header: " " + }, + { + header: Dom.get('footerLinks').innerHTML, + position: 'bottom', + id: 'mbfooter', + height: 22, + border: false + }] + }); + se.complexLayout.render(); + var tp = se.innerLayout = new YAHOO.widget.TabView("emailtabs"); + tp.addTab(new YAHOO.widget.Tab({ + label: "Inbox", + scroll : true, + content : "
    ", + id : "center", + active : true + })); + var centerEl = se.complexLayout.getUnitByPosition('center').get('wrap'); + tp.appendTo(centerEl); + //CSS hack for now + tp.get("element").style.borderRight = "1px solid #666" + + var listV = this.getInnerLayout2Rows(); + listV.set("height", tp.get("element").clientHeight - 25); + listV.render(); + + se.leftTabs = new YAHOO.widget.TabView("lefttabs"); + var folderTab = new YAHOO.widget.Tab({ + label: app_strings.LBL_EMAIL_FOLDERS_SHORT, + scroll : true, + content : "
    ", + id : "tree", + active : true + }); + folderTab.on("activeChange", function(o){ + if (o.newValue) { + se.complexLayout.getUnitByPosition("left").set("header", app_strings.LBL_EMAIL_FOLDERS); + } + }); + se.leftTabs.addTab(folderTab); + + var tabContent = SUGAR.util.getAndRemove("searchTab"); + var searchTab = new YAHOO.widget.Tab({ + label: app_strings.LBL_EMAIL_SEARCH_SHORT, + scroll : true, + content : tabContent.innerHTML, + id : tabContent.id + }); + searchTab.on("activeChange", function(o){ + if (o.newValue) + { + se.complexLayout.getUnitByPosition("left").set("header", app_strings.LBL_EMAIL_SEARCH); + //Setup the calendars if needed + Calendar.setup ({inputField : "searchDateFrom", ifFormat : calFormat, showsTime : false, button : "searchDateFrom_trigger", singleClick : true, step : 1, weekNumbers:false}); + Calendar.setup ({inputField : "searchDateTo", ifFormat : calFormat, showsTime : false, button : "searchDateTo_trigger", singleClick : true, step : 1, weekNumbers:false}); + + //Initalize sqs object for assigned user name + se.e2Layout.initSQSObject('advancedSearchForm','assigned_user_name'); + + //Attach event handler for when the relate module option is selected for the correct sqs object + var parentSearchArgs = {'formName':'advancedSearchForm','fieldName':'data_parent_name_search', + 'moduleSelectField':'data_parent_type_search','fieldId':'data_parent_id_search'}; + YAHOO.util.Event.addListener('data_parent_type_search', 'change',function(){ + SUGAR.email2.composeLayout.enableQuickSearchRelate(null,parentSearchArgs) }); + + //If enter key is pressed, perform search + var addKeyPressFields = ['searchSubject','searchFrom','searchTo','data_parent_name_search','searchDateTo','searchDateFrom','attachmentsSearch','assigned_user_name']; + for(var i=0; i < addKeyPressFields.length;i++) + { + YAHOO.util.Event.addListener(window.document.forms['advancedSearchForm'].elements[addKeyPressFields[i]],"keydown", function(e){ + if (e.keyCode == 13) { + YAHOO.util.Event.stopEvent(e); + SUGAR.email2.search.searchAdvanced(); + } + }); + } + //Initiate quick search for the search tab. Do this only when the tab is selected rather than onDomLoad for perf. gains. + enableQS(true); + //Clear parent values if selecting another parent type. + YAHOO.util.Event.addListener('data_parent_type_search','change', + function(){ + document.getElementById('data_parent_id_search').value =''; + document.getElementById('data_parent_name_search').value =''; + }); + + } + }); + se.leftTabs.addTab(searchTab); + + var resizeTabBody = function() { + var height = SUGAR.email2.leftTabs.get("element").clientHeight - 30; + SUGAR.email2.leftTabs.get("activeTab").get("contentEl").parentNode.style.height = height + "px"; + } + resizeTabBody(); + se.complexLayout.on("render", resizeTabBody); + se.leftTabs.on("activeTabChange", resizeTabBody); + //hack to allow left pane scroll bar to fully show + var lefttabsDiv = document.getElementById('lefttabs'); + var lefttabsDivParent = Dom.getAncestorBy(lefttabsDiv); + var lefttabsDivGParent = Dom.getAncestorBy(lefttabsDivParent); + lefttabsDivParent.style.width = lefttabsDivGParent.offsetWidth - 10 + "px"; + + }, + initSQSObject: function(formName,fieldName) + { + var fullFieldName = formName + '_' + fieldName; //SQS Convention + var resultName = fullFieldName + '_' + 'results'; + + if (QSFieldsArray[fullFieldName] != null) + { + QSFieldsArray[fullFieldName].destroy(); + delete QSFieldsArray[fullFieldName]; + } + if (QSProcessedFieldsArray[fullFieldName]) + QSProcessedFieldsArray[fullFieldName] = false; + + if( Dom.get(resultName) ) + { + var obj = document.getElementById(resultName); + obj.parentNode.removeChild(obj); + } + }, + setPreviewPanel: function(rows) { + if (rows) { + SUGAR.email2.listViewLayout.getUnitByPosition("right").set("width", 0); + SUGAR.email2.listViewLayout.getUnitByPosition("bottom").set("height", 250); + Dom.get("listRight").innerHTML = ""; + Dom.get("listBottom").innerHTML = "
    "; + } else { + SUGAR.email2.listViewLayout.getUnitByPosition("bottom").set("height", 0); + SUGAR.email2.listViewLayout.getUnitByPosition("right").set("width", 250); + Dom.get("listBottom").innerHTML = ""; + Dom.get("listRight").innerHTML = "
    "; + } + } + }; + se.e2Layout.init(); +} + +var myBufferedListenerObject = new Object(); +myBufferedListenerObject.refit = function() { + if(SUGAR.email2.grid) { + SUGAR.email2.grid.autoSize(); + } +} +// End of File modules/Emails/javascript/complexLayout.js + diff --git a/include/javascript/sugar_grp_yui2.js b/include/javascript/sugar_grp_yui2.js new file mode 100644 index 00000000..966a9eb2 --- /dev/null +++ b/include/javascript/sugar_grp_yui2.js @@ -0,0 +1,31 @@ +/* +Copyright (c) 2009, Yahoo! Inc. All rights reserved. +Code licensed under the BSD License: +http://developer.yahoo.net/yui/license.txt +version: 2.8.0r4 +*/ +if(!YAHOO.util.DragDropMgr){YAHOO.util.DragDropMgr=function(){var A=YAHOO.util.Event,B=YAHOO.util.Dom;return{useShim:false,_shimActive:false,_shimState:false,_debugShim:false,_createShim:function(){var C=document.createElement("div");C.id="yui-ddm-shim";if(document.body.firstChild){document.body.insertBefore(C,document.body.firstChild);}else{document.body.appendChild(C);}C.style.display="none";C.style.backgroundColor="red";C.style.position="absolute";C.style.zIndex="99999";B.setStyle(C,"opacity","0");this._shim=C;A.on(C,"mouseup",this.handleMouseUp,this,true);A.on(C,"mousemove",this.handleMouseMove,this,true);A.on(window,"scroll",this._sizeShim,this,true);},_sizeShim:function(){if(this._shimActive){var C=this._shim;C.style.height=B.getDocumentHeight()+"px";C.style.width=B.getDocumentWidth()+"px";C.style.top="0";C.style.left="0";}},_activateShim:function(){if(this.useShim){if(!this._shim){this._createShim();}this._shimActive=true;var C=this._shim,D="0";if(this._debugShim){D=".5";}B.setStyle(C,"opacity",D);this._sizeShim();C.style.display="block";}},_deactivateShim:function(){this._shim.style.display="none";this._shimActive=false;},_shim:null,ids:{},handleIds:{},dragCurrent:null,dragOvers:{},deltaX:0,deltaY:0,preventDefault:true,stopPropagation:true,initialized:false,locked:false,interactionInfo:null,init:function(){this.initialized=true;},POINT:0,INTERSECT:1,STRICT_INTERSECT:2,mode:0,_execOnAll:function(E,D){for(var F in this.ids){for(var C in this.ids[F]){var G=this.ids[F][C];if(!this.isTypeOfDD(G)){continue;}G[E].apply(G,D);}}},_onLoad:function(){this.init();A.on(document,"mouseup",this.handleMouseUp,this,true);A.on(document,"mousemove",this.handleMouseMove,this,true);A.on(window,"unload",this._onUnload,this,true);A.on(window,"resize",this._onResize,this,true);},_onResize:function(C){this._execOnAll("resetConstraints",[]);},lock:function(){this.locked=true;},unlock:function(){this.locked=false;},isLocked:function(){return this.locked;},locationCache:{},useCache:true,clickPixelThresh:3,clickTimeThresh:1000,dragThreshMet:false,clickTimeout:null,startX:0,startY:0,fromTimeout:false,regDragDrop:function(D,C){if(!this.initialized){this.init();}if(!this.ids[C]){this.ids[C]={};}this.ids[C][D.id]=D;},removeDDFromGroup:function(E,C){if(!this.ids[C]){this.ids[C]={};}var D=this.ids[C];if(D&&D[E.id]){delete D[E.id];}},_remove:function(E){for(var D in E.groups){if(D){var C=this.ids[D];if(C&&C[E.id]){delete C[E.id];}}}delete this.handleIds[E.id];},regHandle:function(D,C){if(!this.handleIds[D]){this.handleIds[D]={};}this.handleIds[D][C]=C;},isDragDrop:function(C){return(this.getDDById(C))?true:false;},getRelated:function(H,D){var G=[];for(var F in H.groups){for(var E in this.ids[F]){var C=this.ids[F][E];if(!this.isTypeOfDD(C)){continue;}if(!D||C.isTarget){G[G.length]=C;}}}return G;},isLegalTarget:function(G,F){var D=this.getRelated(G,true);for(var E=0,C=D.length;Ethis.clickPixelThresh||D>this.clickPixelThresh){this.startDrag(this.startX,this.startY);}}if(this.dragThreshMet){if(C&&C.events.b4Drag){C.b4Drag(F);C.fireEvent("b4DragEvent",{e:F});}if(C&&C.events.drag){C.onDrag(F);C.fireEvent("dragEvent",{e:F});}if(C){this.fireEvents(F,false);}}this.stopEvent(F);}},fireEvents:function(V,L){var a=this.dragCurrent;if(!a||a.isLocked()||a.dragOnly){return;}var N=YAHOO.util.Event.getPageX(V),M=YAHOO.util.Event.getPageY(V),P=new YAHOO.util.Point(N,M),K=a.getTargetCoord(P.x,P.y),F=a.getDragEl(),E=["out","over","drop","enter"],U=new YAHOO.util.Region(K.y,K.x+F.offsetWidth,K.y+F.offsetHeight,K.x),I=[],D={},Q=[],c={outEvts:[],overEvts:[],dropEvts:[],enterEvts:[]};for(var S in this.dragOvers){var d=this.dragOvers[S];if(!this.isTypeOfDD(d)){continue; +}if(!this.isOverTarget(P,d,this.mode,U)){c.outEvts.push(d);}I[S]=true;delete this.dragOvers[S];}for(var R in a.groups){if("string"!=typeof R){continue;}for(S in this.ids[R]){var G=this.ids[R][S];if(!this.isTypeOfDD(G)){continue;}if(G.isTarget&&!G.isLocked()&&G!=a){if(this.isOverTarget(P,G,this.mode,U)){D[R]=true;if(L){c.dropEvts.push(G);}else{if(!I[G.id]){c.enterEvts.push(G);}else{c.overEvts.push(G);}this.dragOvers[G.id]=G;}}}}}this.interactionInfo={out:c.outEvts,enter:c.enterEvts,over:c.overEvts,drop:c.dropEvts,point:P,draggedRegion:U,sourceRegion:this.locationCache[a.id],validDrop:L};for(var C in D){Q.push(C);}if(L&&!c.dropEvts.length){this.interactionInfo.validDrop=false;if(a.events.invalidDrop){a.onInvalidDrop(V);a.fireEvent("invalidDropEvent",{e:V});}}for(S=0;S2000){}else{setTimeout(C._addListeners,10);if(document&&document.body){C._timeoutCount+=1;}}}},handleWasClicked:function(C,E){if(this.isHandle(E,C.id)){return true;}else{var D=C.parentNode;while(D){if(this.isHandle(E,D.id)){return true;}else{D=D.parentNode;}}}return false;}};}();YAHOO.util.DDM=YAHOO.util.DragDropMgr;YAHOO.util.DDM._addListeners();}(function(){var A=YAHOO.util.Event;var B=YAHOO.util.Dom;YAHOO.util.DragDrop=function(E,C,D){if(E){this.init(E,C,D);}};YAHOO.util.DragDrop.prototype={events:null,on:function(){this.subscribe.apply(this,arguments);},id:null,config:null,dragElId:null,handleElId:null,invalidHandleTypes:null,invalidHandleIds:null,invalidHandleClasses:null,startPageX:0,startPageY:0,groups:null,locked:false,lock:function(){this.locked=true;},unlock:function(){this.locked=false;},isTarget:true,padding:null,dragOnly:false,useShim:false,_domRef:null,__ygDragDrop:true,constrainX:false,constrainY:false,minX:0,maxX:0,minY:0,maxY:0,deltaX:0,deltaY:0,maintainOffset:false,xTicks:null,yTicks:null,primaryButtonOnly:true,available:false,hasOuterHandles:false,cursorIsOver:false,overlap:null,b4StartDrag:function(C,D){},startDrag:function(C,D){},b4Drag:function(C){},onDrag:function(C){},onDragEnter:function(C,D){},b4DragOver:function(C){},onDragOver:function(C,D){},b4DragOut:function(C){},onDragOut:function(C,D){},b4DragDrop:function(C){},onDragDrop:function(C,D){},onInvalidDrop:function(C){},b4EndDrag:function(C){},endDrag:function(C){},b4MouseDown:function(C){},onMouseDown:function(C){},onMouseUp:function(C){},onAvailable:function(){},getEl:function(){if(!this._domRef){this._domRef=B.get(this.id); +}return this._domRef;},getDragEl:function(){return B.get(this.dragElId);},init:function(F,C,D){this.initTarget(F,C,D);A.on(this._domRef||this.id,"mousedown",this.handleMouseDown,this,true);for(var E in this.events){this.createEvent(E+"Event");}},initTarget:function(E,C,D){this.config=D||{};this.events={};this.DDM=YAHOO.util.DDM;this.groups={};if(typeof E!=="string"){this._domRef=E;E=B.generateId(E);}this.id=E;this.addToGroup((C)?C:"default");this.handleElId=E;A.onAvailable(E,this.handleOnAvailable,this,true);this.setDragElId(E);this.invalidHandleTypes={A:"A"};this.invalidHandleIds={};this.invalidHandleClasses=[];this.applyConfig();},applyConfig:function(){this.events={mouseDown:true,b4MouseDown:true,mouseUp:true,b4StartDrag:true,startDrag:true,b4EndDrag:true,endDrag:true,drag:true,b4Drag:true,invalidDrop:true,b4DragOut:true,dragOut:true,dragEnter:true,b4DragOver:true,dragOver:true,b4DragDrop:true,dragDrop:true};if(this.config.events){for(var C in this.config.events){if(this.config.events[C]===false){this.events[C]=false;}}}this.padding=this.config.padding||[0,0,0,0];this.isTarget=(this.config.isTarget!==false);this.maintainOffset=(this.config.maintainOffset);this.primaryButtonOnly=(this.config.primaryButtonOnly!==false);this.dragOnly=((this.config.dragOnly===true)?true:false);this.useShim=((this.config.useShim===true)?true:false);},handleOnAvailable:function(){this.available=true;this.resetConstraints();this.onAvailable();},setPadding:function(E,C,F,D){if(!C&&0!==C){this.padding=[E,E,E,E];}else{if(!F&&0!==F){this.padding=[E,C,E,C];}else{this.padding=[E,C,F,D];}}},setInitPosition:function(F,E){var G=this.getEl();if(!this.DDM.verifyEl(G)){if(G&&G.style&&(G.style.display=="none")){}else{}return;}var D=F||0;var C=E||0;var H=B.getXY(G);this.initPageX=H[0]-D;this.initPageY=H[1]-C;this.lastPageX=H[0];this.lastPageY=H[1];this.setStartPosition(H);},setStartPosition:function(D){var C=D||B.getXY(this.getEl());this.deltaSetXY=null;this.startPageX=C[0];this.startPageY=C[1];},addToGroup:function(C){this.groups[C]=true;this.DDM.regDragDrop(this,C);},removeFromGroup:function(C){if(this.groups[C]){delete this.groups[C];}this.DDM.removeDDFromGroup(this,C);},setDragElId:function(C){this.dragElId=C;},setHandleElId:function(C){if(typeof C!=="string"){C=B.generateId(C);}this.handleElId=C;this.DDM.regHandle(this.id,C);},setOuterHandleElId:function(C){if(typeof C!=="string"){C=B.generateId(C);}A.on(C,"mousedown",this.handleMouseDown,this,true);this.setHandleElId(C);this.hasOuterHandles=true;},unreg:function(){A.removeListener(this.id,"mousedown",this.handleMouseDown);this._domRef=null;this.DDM._remove(this);},isLocked:function(){return(this.DDM.isLocked()||this.locked);},handleMouseDown:function(J,I){var D=J.which||J.button;if(this.primaryButtonOnly&&D>1){return;}if(this.isLocked()){return;}var C=this.b4MouseDown(J),F=true;if(this.events.b4MouseDown){F=this.fireEvent("b4MouseDownEvent",J);}var E=this.onMouseDown(J),H=true;if(this.events.mouseDown){H=this.fireEvent("mouseDownEvent",J);}if((C===false)||(E===false)||(F===false)||(H===false)){return;}this.DDM.refreshCache(this.groups);var G=new YAHOO.util.Point(A.getPageX(J),A.getPageY(J));if(!this.hasOuterHandles&&!this.DDM.isOverTarget(G,this)){}else{if(this.clickValidator(J)){this.setStartPosition();this.DDM.handleMouseDown(J,this);this.DDM.stopEvent(J);}else{}}},clickValidator:function(D){var C=YAHOO.util.Event.getTarget(D);return(this.isValidHandleChild(C)&&(this.id==this.handleElId||this.DDM.handleWasClicked(C,this.id)));},getTargetCoord:function(E,D){var C=E-this.deltaX;var F=D-this.deltaY;if(this.constrainX){if(Cthis.maxX){C=this.maxX;}}if(this.constrainY){if(Fthis.maxY){F=this.maxY;}}C=this.getTick(C,this.xTicks);F=this.getTick(F,this.yTicks);return{x:C,y:F};},addInvalidHandleType:function(C){var D=C.toUpperCase();this.invalidHandleTypes[D]=D;},addInvalidHandleId:function(C){if(typeof C!=="string"){C=B.generateId(C);}this.invalidHandleIds[C]=C;},addInvalidHandleClass:function(C){this.invalidHandleClasses.push(C);},removeInvalidHandleType:function(C){var D=C.toUpperCase();delete this.invalidHandleTypes[D];},removeInvalidHandleId:function(C){if(typeof C!=="string"){C=B.generateId(C);}delete this.invalidHandleIds[C];},removeInvalidHandleClass:function(D){for(var E=0,C=this.invalidHandleClasses.length;E=this.minX;D=D-C){if(!E[D]){this.xTicks[this.xTicks.length]=D;E[D]=true;}}for(D=this.initPageX;D<=this.maxX;D=D+C){if(!E[D]){this.xTicks[this.xTicks.length]=D;E[D]=true;}}this.xTicks.sort(this.DDM.numericSort);},setYTicks:function(F,C){this.yTicks=[];this.yTickSize=C;var E={};for(var D=this.initPageY;D>=this.minY;D=D-C){if(!E[D]){this.yTicks[this.yTicks.length]=D;E[D]=true;}}for(D=this.initPageY;D<=this.maxY;D=D+C){if(!E[D]){this.yTicks[this.yTicks.length]=D;E[D]=true;}}this.yTicks.sort(this.DDM.numericSort);},setXConstraint:function(E,D,C){this.leftConstraint=parseInt(E,10);this.rightConstraint=parseInt(D,10);this.minX=this.initPageX-this.leftConstraint;this.maxX=this.initPageX+this.rightConstraint;if(C){this.setXTicks(this.initPageX,C);}this.constrainX=true;},clearConstraints:function(){this.constrainX=false;this.constrainY=false;this.clearTicks();},clearTicks:function(){this.xTicks=null;this.yTicks=null;this.xTickSize=0;this.yTickSize=0;},setYConstraint:function(C,E,D){this.topConstraint=parseInt(C,10);this.bottomConstraint=parseInt(E,10);this.minY=this.initPageY-this.topConstraint;this.maxY=this.initPageY+this.bottomConstraint;if(D){this.setYTicks(this.initPageY,D); +}this.constrainY=true;},resetConstraints:function(){if(this.initPageX||this.initPageX===0){var D=(this.maintainOffset)?this.lastPageX-this.initPageX:0;var C=(this.maintainOffset)?this.lastPageY-this.initPageY:0;this.setInitPosition(D,C);}else{this.setInitPosition();}if(this.constrainX){this.setXConstraint(this.leftConstraint,this.rightConstraint,this.xTickSize);}if(this.constrainY){this.setYConstraint(this.topConstraint,this.bottomConstraint,this.yTickSize);}},getTick:function(I,F){if(!F){return I;}else{if(F[0]>=I){return F[0];}else{for(var D=0,C=F.length;D=I){var H=I-F[D];var G=F[E]-I;return(G>H)?F[D]:F[E];}}return F[F.length-1];}}},toString:function(){return("DragDrop "+this.id);}};YAHOO.augment(YAHOO.util.DragDrop,YAHOO.util.EventProvider);})();YAHOO.util.DD=function(C,A,B){if(C){this.init(C,A,B);}};YAHOO.extend(YAHOO.util.DD,YAHOO.util.DragDrop,{scroll:true,autoOffset:function(C,B){var A=C-this.startPageX;var D=B-this.startPageY;this.setDelta(A,D);},setDelta:function(B,A){this.deltaX=B;this.deltaY=A;},setDragElPos:function(C,B){var A=this.getDragEl();this.alignElWithMouse(A,C,B);},alignElWithMouse:function(C,G,F){var E=this.getTargetCoord(G,F);if(!this.deltaSetXY){var H=[E.x,E.y];YAHOO.util.Dom.setXY(C,H);var D=parseInt(YAHOO.util.Dom.getStyle(C,"left"),10);var B=parseInt(YAHOO.util.Dom.getStyle(C,"top"),10);this.deltaSetXY=[D-E.x,B-E.y];}else{YAHOO.util.Dom.setStyle(C,"left",(E.x+this.deltaSetXY[0])+"px");YAHOO.util.Dom.setStyle(C,"top",(E.y+this.deltaSetXY[1])+"px");}this.cachePosition(E.x,E.y);var A=this;setTimeout(function(){A.autoScroll.call(A,E.x,E.y,C.offsetHeight,C.offsetWidth);},0);},cachePosition:function(B,A){if(B){this.lastPageX=B;this.lastPageY=A;}else{var C=YAHOO.util.Dom.getXY(this.getEl());this.lastPageX=C[0];this.lastPageY=C[1];}},autoScroll:function(J,I,E,K){if(this.scroll){var L=this.DDM.getClientHeight();var B=this.DDM.getClientWidth();var N=this.DDM.getScrollTop();var D=this.DDM.getScrollLeft();var H=E+I;var M=K+J;var G=(L+N-I-this.deltaY);var F=(B+D-J-this.deltaX);var C=40;var A=(document.all)?80:30;if(H>L&&G0&&I-NB&&F0&&J-D0){G=F-1;do{D=E.subscribers[G];if(D&&D.obj==I&&D.fn==H){return true;}}while(G--);}return false;};YAHOO.lang.augmentProto(A,YAHOO.util.EventProvider);}());(function(){YAHOO.widget.Module=function(R,Q){if(R){this.init(R,Q);}else{}};var F=YAHOO.util.Dom,D=YAHOO.util.Config,N=YAHOO.util.Event,M=YAHOO.util.CustomEvent,G=YAHOO.widget.Module,I=YAHOO.env.ua,H,P,O,E,A={"BEFORE_INIT":"beforeInit","INIT":"init","APPEND":"append","BEFORE_RENDER":"beforeRender","RENDER":"render","CHANGE_HEADER":"changeHeader","CHANGE_BODY":"changeBody","CHANGE_FOOTER":"changeFooter","CHANGE_CONTENT":"changeContent","DESTROY":"destroy","BEFORE_SHOW":"beforeShow","SHOW":"show","BEFORE_HIDE":"beforeHide","HIDE":"hide"},J={"VISIBLE":{key:"visible",value:true,validator:YAHOO.lang.isBoolean},"EFFECT":{key:"effect",suppressEvent:true,supercedes:["visible"]},"MONITOR_RESIZE":{key:"monitorresize",value:true},"APPEND_TO_DOCUMENT_BODY":{key:"appendtodocumentbody",value:false}};G.IMG_ROOT=null;G.IMG_ROOT_SSL=null;G.CSS_MODULE="yui-module";G.CSS_HEADER="hd";G.CSS_BODY="bd";G.CSS_FOOTER="ft";G.RESIZE_MONITOR_SECURE_URL="javascript:false;";G.RESIZE_MONITOR_BUFFER=1;G.textResizeEvent=new M("textResize");G.forceDocumentRedraw=function(){var Q=document.documentElement;if(Q){Q.className+=" ";Q.className=YAHOO.lang.trim(Q.className);}};function L(){if(!H){H=document.createElement("div");H.innerHTML=('
    '+'
    ');P=H.firstChild;O=P.nextSibling;E=O.nextSibling;}return H;}function K(){if(!P){L();}return(P.cloneNode(false));}function B(){if(!O){L();}return(O.cloneNode(false));}function C(){if(!E){L();}return(E.cloneNode(false));}G.prototype={constructor:G,element:null,header:null,body:null,footer:null,id:null,imageRoot:G.IMG_ROOT,initEvents:function(){var Q=M.LIST; +this.beforeInitEvent=this.createEvent(A.BEFORE_INIT);this.beforeInitEvent.signature=Q;this.initEvent=this.createEvent(A.INIT);this.initEvent.signature=Q;this.appendEvent=this.createEvent(A.APPEND);this.appendEvent.signature=Q;this.beforeRenderEvent=this.createEvent(A.BEFORE_RENDER);this.beforeRenderEvent.signature=Q;this.renderEvent=this.createEvent(A.RENDER);this.renderEvent.signature=Q;this.changeHeaderEvent=this.createEvent(A.CHANGE_HEADER);this.changeHeaderEvent.signature=Q;this.changeBodyEvent=this.createEvent(A.CHANGE_BODY);this.changeBodyEvent.signature=Q;this.changeFooterEvent=this.createEvent(A.CHANGE_FOOTER);this.changeFooterEvent.signature=Q;this.changeContentEvent=this.createEvent(A.CHANGE_CONTENT);this.changeContentEvent.signature=Q;this.destroyEvent=this.createEvent(A.DESTROY);this.destroyEvent.signature=Q;this.beforeShowEvent=this.createEvent(A.BEFORE_SHOW);this.beforeShowEvent.signature=Q;this.showEvent=this.createEvent(A.SHOW);this.showEvent.signature=Q;this.beforeHideEvent=this.createEvent(A.BEFORE_HIDE);this.beforeHideEvent.signature=Q;this.hideEvent=this.createEvent(A.HIDE);this.hideEvent.signature=Q;},platform:function(){var Q=navigator.userAgent.toLowerCase();if(Q.indexOf("windows")!=-1||Q.indexOf("win32")!=-1){return"windows";}else{if(Q.indexOf("macintosh")!=-1){return"mac";}else{return false;}}}(),browser:function(){var Q=navigator.userAgent.toLowerCase();if(Q.indexOf("opera")!=-1){return"opera";}else{if(Q.indexOf("msie 7")!=-1){return"ie7";}else{if(Q.indexOf("msie")!=-1){return"ie";}else{if(Q.indexOf("safari")!=-1){return"safari";}else{if(Q.indexOf("gecko")!=-1){return"gecko";}else{return false;}}}}}}(),isSecure:function(){if(window.location.href.toLowerCase().indexOf("https")===0){return true;}else{return false;}}(),initDefaultConfig:function(){this.cfg.addProperty(J.VISIBLE.key,{handler:this.configVisible,value:J.VISIBLE.value,validator:J.VISIBLE.validator});this.cfg.addProperty(J.EFFECT.key,{suppressEvent:J.EFFECT.suppressEvent,supercedes:J.EFFECT.supercedes});this.cfg.addProperty(J.MONITOR_RESIZE.key,{handler:this.configMonitorResize,value:J.MONITOR_RESIZE.value});this.cfg.addProperty(J.APPEND_TO_DOCUMENT_BODY.key,{value:J.APPEND_TO_DOCUMENT_BODY.value});},init:function(V,U){var S,W;this.initEvents();this.beforeInitEvent.fire(G);this.cfg=new D(this);if(this.isSecure){this.imageRoot=G.IMG_ROOT_SSL;}if(typeof V=="string"){S=V;V=document.getElementById(V);if(!V){V=(L()).cloneNode(false);V.id=S;}}this.id=F.generateId(V);this.element=V;W=this.element.firstChild;if(W){var R=false,Q=false,T=false;do{if(1==W.nodeType){if(!R&&F.hasClass(W,G.CSS_HEADER)){this.header=W;R=true;}else{if(!Q&&F.hasClass(W,G.CSS_BODY)){this.body=W;Q=true;}else{if(!T&&F.hasClass(W,G.CSS_FOOTER)){this.footer=W;T=true;}}}}}while((W=W.nextSibling));}this.initDefaultConfig();F.addClass(this.element,G.CSS_MODULE);if(U){this.cfg.applyConfig(U,true);}if(!D.alreadySubscribed(this.renderEvent,this.cfg.fireQueue,this.cfg)){this.renderEvent.subscribe(this.cfg.fireQueue,this.cfg,true);}this.initEvent.fire(G);},initResizeMonitor:function(){var R=(I.gecko&&this.platform=="windows");if(R){var Q=this;setTimeout(function(){Q._initResizeMonitor();},0);}else{this._initResizeMonitor();}},_initResizeMonitor:function(){var Q,S,U;function W(){G.textResizeEvent.fire();}if(!I.opera){S=F.get("_yuiResizeMonitor");var V=this._supportsCWResize();if(!S){S=document.createElement("iframe");if(this.isSecure&&G.RESIZE_MONITOR_SECURE_URL&&I.ie){S.src=G.RESIZE_MONITOR_SECURE_URL;}if(!V){U=[" + + + + + + + +
    + + +
    +
    + + + + + + + + + + + + + +
    + + +
    +
    +
    + +
    +
    + +
    + +
    + +
    +
    +
    + + diff --git a/include/javascript/tiny_mce/plugins/advimage/css/advimage.css b/include/javascript/tiny_mce/plugins/advimage/css/advimage.css new file mode 100644 index 00000000..228530f9 --- /dev/null +++ b/include/javascript/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:428px; 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/include/javascript/tiny_mce/plugins/advimage/editor_plugin.js b/include/javascript/tiny_mce/plugins/advimage/editor_plugin.js new file mode 100644 index 00000000..3af50573 --- /dev/null +++ b/include/javascript/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/include/javascript/tiny_mce/plugins/advimage/editor_plugin_src.js b/include/javascript/tiny_mce/plugins/advimage/editor_plugin_src.js new file mode 100644 index 00000000..43269dd1 --- /dev/null +++ b/include/javascript/tiny_mce/plugins/advimage/editor_plugin_src.js @@ -0,0 +1,47 @@ +/** + + * + * @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/include/javascript/tiny_mce/plugins/advimage/image.htm b/include/javascript/tiny_mce/plugins/advimage/image.htm new file mode 100644 index 00000000..3cd7647c --- /dev/null +++ b/include/javascript/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/include/javascript/tiny_mce/plugins/advimage/img/sample.gif b/include/javascript/tiny_mce/plugins/advimage/img/sample.gif new file mode 100644 index 0000000000000000000000000000000000000000..53bf6890b507741c10910c9e2217ad8247b98e8d GIT binary patch literal 1624 zcmV-e2B-N)Nk%w1VJ!eH0OkMy|NsB}{r&v>{Q3F$`1ttq^YifV@ayaA>FMd_=H}w! z;^5%m-rnBb-QC>W+}qpR+S=OL+1c3G*w@$B*4Eb4)YQ|{)zHw=&d$%x&CScp%gV~i z$;rvc$jHXV#>B+L!^6YE!otD9!N9=4zrVk|y}i7=yt})*y1Kf#xw*Hux3;#nwY9ah zw6wFcv$C?Xv9YnRu&}SMudc4Ht*x!BtgNf6tE#H1si~={sjjD|r>3T+rKP2$q@<&x zqobp!qN1Xqp`oFnrJ$goprE6lpP!zdp`MSWoSd7Ro12@UnwpxLnw^=MnV6WE zmzS58mX?*3mz9;3mX?*2l$4W`lai8@l9G~eg|M^H&l zLpBo?51@vfgB2q_TVh*dNP<;cR$Wg!vYsMHR!qvvOis>GNH`+ zJ3B|tqgANiBSy@x>Q#;x7+DuU7&rwlf#S04)VZvA$XoUy8Y&f7)SqP<}Lw@L# zA(@Cohl`6CZyedUu^BlmK|DG5$Kl2f8z@uCc)^k-3m7$G!njf7$;XhOW>^`rV#UFh zEN#eG;bP?tCs>{+)q)ceg9$aDAaTZ{MGK5rU8ty$qz8){MT#gHGX{#XEJHLonBXFa zj+#9GE&^pq!`qG`K5iiC!gq}sRY|1yD8?j++_^oR0g+)NNtZN`)08!0q=}AA4HhIo zFaa9NYu8%97=oos5f?O`lwre~4VfoIei+FyK|urxj@C(-q(sS(!$5uL3j&jg7&XY% zlr17;3GGL;2K8>CB87G97;W(2VZ((D+3Hz;L;bylfhf(kFNV8at)h;hdM z85WX(#*Hq@@BYePt3t_l{ zCL3|YVWydA0Fz{rTl65n00)c^)^-jJn1c zRVXtA6mkUMEDLU|v7{JK&_IJ2ciiCy7BOT1fdUBh8b=yrbYaCAchCU_7?H`b1`}4q zLB|_mI2!;7W4QCq6F1O+MW||6AwmKafUrReUA&QotxQZI8D$G)AuSVV@X<&A9v;~H zKnWjo&;bljq=29aCeV-t5GBYkL=Q}q(S~FLd2t39MyRmC%_GFHkPc7CfIt8P*emqV z0YK2j9A+kmW^!tn(ZmG+L=6DZR99W}8p9?Utr=#t@rE2=zxf3QQ(JBJ&<{Z2>8EUP zeX1B)2w_3gXV)D-0Tt+=#@cV-0f!PU#MglZ3m6b}0e08zK^x;9(u?Tga{%?&nNTXhcEuM_#J>yL>p*a zuZJ2pliCGSp!Ye8>YFq@)ZOW-uT~OrjFQK!)UyVGFt7ni'); + }, + + 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.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 = '0'; + 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/include/javascript/tiny_mce/plugins/advimage/langs/en_dlg.js b/include/javascript/tiny_mce/plugins/advimage/langs/en_dlg.js new file mode 100644 index 00000000..ef81f78b --- /dev/null +++ b/include/javascript/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/include/javascript/tiny_mce/plugins/advlink/css/advlink.css b/include/javascript/tiny_mce/plugins/advlink/css/advlink.css new file mode 100644 index 00000000..66c65493 --- /dev/null +++ b/include/javascript/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/include/javascript/tiny_mce/plugins/advlink/editor_plugin.js b/include/javascript/tiny_mce/plugins/advlink/editor_plugin.js new file mode 100644 index 00000000..4899f7b8 --- /dev/null +++ b/include/javascript/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/include/javascript/tiny_mce/plugins/advlink/editor_plugin_src.js b/include/javascript/tiny_mce/plugins/advlink/editor_plugin_src.js new file mode 100644 index 00000000..7c8b55f4 --- /dev/null +++ b/include/javascript/tiny_mce/plugins/advlink/editor_plugin_src.js @@ -0,0 +1,58 @@ +/** + + * + * @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/include/javascript/tiny_mce/plugins/advlink/js/advlink.js b/include/javascript/tiny_mce/plugins/advlink/js/advlink.js new file mode 100644 index 00000000..c8d19835 --- /dev/null +++ b/include/javascript/tiny_mce/plugins/advlink/js/advlink.js @@ -0,0 +1,527 @@ +/* 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/include/javascript/tiny_mce/plugins/advlink/langs/en_dlg.js b/include/javascript/tiny_mce/plugins/advlink/langs/en_dlg.js new file mode 100644 index 00000000..8ef9c792 --- /dev/null +++ b/include/javascript/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/include/javascript/tiny_mce/plugins/advlink/link.htm b/include/javascript/tiny_mce/plugins/advlink/link.htm new file mode 100644 index 00000000..bb8e6543 --- /dev/null +++ b/include/javascript/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/include/javascript/tiny_mce/plugins/autosave/editor_plugin.js b/include/javascript/tiny_mce/plugins/autosave/editor_plugin.js new file mode 100644 index 00000000..01a994ee --- /dev/null +++ b/include/javascript/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/include/javascript/tiny_mce/plugins/autosave/editor_plugin_src.js b/include/javascript/tiny_mce/plugins/autosave/editor_plugin_src.js new file mode 100644 index 00000000..959cc4e1 --- /dev/null +++ b/include/javascript/tiny_mce/plugins/autosave/editor_plugin_src.js @@ -0,0 +1,51 @@ +/** + + * + * @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/include/javascript/tiny_mce/plugins/bbcode/editor_plugin.js b/include/javascript/tiny_mce/plugins/bbcode/editor_plugin.js new file mode 100644 index 00000000..88f7ea65 --- /dev/null +++ b/include/javascript/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,"[quote]");rep(/<\/blockquote>/gi,"[/quote]");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/include/javascript/tiny_mce/plugins/bbcode/editor_plugin_src.js b/include/javascript/tiny_mce/plugins/bbcode/editor_plugin_src.js new file mode 100644 index 00000000..28f2eebd --- /dev/null +++ b/include/javascript/tiny_mce/plugins/bbcode/editor_plugin_src.js @@ -0,0 +1,117 @@ +/** + + * + * @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,"[quote]"); + rep(/<\/blockquote>/gi,"[/quote]"); + 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/include/javascript/tiny_mce/plugins/compat2x/editor_plugin.js b/include/javascript/tiny_mce/plugins/compat2x/editor_plugin.js new file mode 100644 index 00000000..02a1da8b --- /dev/null +++ b/include/javascript/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/include/javascript/tiny_mce/plugins/emotions/img/smiley-cool.gif b/include/javascript/tiny_mce/plugins/emotions/img/smiley-cool.gif new file mode 100644 index 0000000000000000000000000000000000000000..ba90cc36fb0415d0273d1cd206bff63fd9c91fde GIT binary patch literal 354 zcmV-o0iFIwNk%w1VG;lm0Mr!#3ke00dJfFY%i+lrhK7V(RutUQJhPY;?(XfrsZKgL z7WLQ^zPO&zzav{)SL^9nBOw~z(=orMEH5uC-P_gr`uhCnASMa|$-iRw?m_(dUwU8) zq>Kx}s1_F$4FCWDA^8LW0018VEC2ui01^Na000Hw;3tYzX_jM3Qpv$_M?zI9i5=0S zX-{-uv=l3%&P0s%m9Ox_a(m_c|u z01g3U0`Wll5)poVdma=N8y<3f0Sf~hXmTC}2oxMW4FdxUj+z4<0}lrX2nP=qkDRIt z9Ge*(qzMrj3jrIOjvI{`5eWzt3`G_T8yChG8w(a19SkK12@M(+799Zr9n=~PzBCmA z5)BU-)YKUd4H5!D9|!^o9kWIe9SH(WDHRk92}DZ?3})2$P@$55g90f0N)ZA8JID5J Aw*UYD literal 0 HcmV?d00001 diff --git a/include/javascript/tiny_mce/plugins/emotions/img/smiley-cry.gif b/include/javascript/tiny_mce/plugins/emotions/img/smiley-cry.gif new file mode 100644 index 0000000000000000000000000000000000000000..74d897a4f6d22e814e2b054e98b8a75fb464b4be GIT binary patch literal 329 zcmV-P0k-}}Nk%w1VG;lm0Mr-&E)xPSit@9T3%;vR+|V+?t0A(pllJjXrMl7n=_A_a za^B+Su$LjvyC3@TIQZNZa##w=!k(SO^P#bO*w(eU#;{U83XFCU_V)J5wrb+;g2vkN z#>U24qVoOvY5)KLA^8LW0018VEC2ui01^Na000HX;3tY$X_jM3QUfCh%s^o(nF++< zc?Th6v=oL>*by8K!mhvwelUXuuW&&U9iGO3hM@>Njw{l^#0q9mWpcefdI;O$;efnY zkd~@r-o$*74FCWI1%d((4+jDz0va0>69^fI6%`W{8w!gU1pyL>prH>E0R<%k6Aq%H z4ij+^9TEwM5P}eh2@)L<~6+>@EpxfA0YrcPNsSu literal 0 HcmV?d00001 diff --git a/include/javascript/tiny_mce/plugins/emotions/img/smiley-embarassed.gif b/include/javascript/tiny_mce/plugins/emotions/img/smiley-embarassed.gif new file mode 100644 index 0000000000000000000000000000000000000000..963a96b8a7593b1d8bcbab073abe5ee4e539dbf6 GIT binary patch literal 331 zcmV-R0kr-{Nk%w1VG;lm0MrryDh>j~yq&6%75dW~z^P39(NxsGDE{UkxtkIEq(S-a zRKlwv+S=Lr?>hbYY~sQ?c3T&ZcN_Nh_EU3s(>Io6B&>WW`@bsw**)Ocy1bht z{*G6|uwwqUQ2+n{A^8LW0018VEC2ui01^Na000HZ;3tYwX_jM3YQ!c88=*-m*&&bO zILd=`w3KAC;8hxpif*w9ek6oqV-Z0L77fROK$BSR@5BAv-%C>6y>>#+D4e#&nz^qMDItlpp zTG728+|V&?R13PIEBW(C`uh6d*t-1sZ^XQv;oDD}iYLOV7uVO;{`xl4#4tJ{0;h@! z>)kfFn;iS@Hvj+tA^8LW0018VEC2ui01^Na000Hm;3tYuX_jM3Mo7199TGt*Nf;R= zNmOPKwA8_2Q6MTDP6eT`I1VESVj-zGIG(JdB3U44kcdI@;AAq{Gv^^O%%ltj2GdB) z>vIL;d*~=0a|w1Bf^!cF9R~+vb94;_0}TxWlnMrlj2MuVoSYAreF`3(0|pHS8VLgr zi3bP_qZ;q#>Sw62=mns-On=0wransPVevT^YK{Dy(0YY zH)vE6x0?;Wqb>gZas1^OT0si>`ugD5y87}*#H$s=yq(wA*8cf7{`y+(+9J7|9QfT7 z`ROHiU=Y&6FaQ7mA^8LW0018VEC2ui01^Na000Hi;3tYvX_jM3N`@u~nju9hSuh^r zIEcp-wA7(NL0~2d#RP+(G!CPPA>o*KJjv_CkucCA5=K?AfF#RG2V*8BU@jL304|4P z2;PGRF@bj$et;Jf2pR_mVsIA<85|n}kQ*Bq42Ovqj*yy>6P0=h3X&9Z01yyk~2N4w%7#RW^55W%`0vQ+-6(y_*2pqz~90*;x9}yM}%$UI(7t#$D mK_3Se1{4HKM+6iG7EmeH6$V631{L5n)#CyC0qx-*Apkoyg?w!Q literal 0 HcmV?d00001 diff --git a/include/javascript/tiny_mce/plugins/emotions/img/smiley-innocent.gif b/include/javascript/tiny_mce/plugins/emotions/img/smiley-innocent.gif new file mode 100644 index 0000000000000000000000000000000000000000..334d49e0e60f2997c9ba24071764f95d9e08a5cc GIT binary patch literal 336 zcmV-W0k8f?Nk%w1VG;lm0MrryI4TI-%dP0m5~*+Y`T~ z7Rth){q{I_X%*S48uRZ|(b3V&wIKTX`u+WJzo<^$#wuY;3W|Cf{O29IkTAcaE&lpe z+P*^H)-tknA^-pYA^8LW0018VEC2ui01^Na000He;3tYwX_n)75QgVvNQ`6#5gcMm zEEG~blgXokptKAJgCU?%JT?yos!R6cPtcQWh2siHlNI2L}ifQhgX02^InZ2?-ktkqVRyZJY^Trk|lv zovp437?1~d46O)?2(1i+2NDYk8<+_Kil!K!3njA^!I#dL8x<729}*B65mC=m5gHH@ iDi9P3f*VjB3KS4HDb_qqRul{0DIT=Nk%w1VG;lm0Mrx!QauaC#>Vb6G=_5=^YB^9wrc376Sb5I-qJGf@9vZ# z5WlKU(!eVB+7tfnDXp0zyB`?BZ5IChalob*`uh6d*t+@dKGHcU+L|83yq*5~IoH?L zy`?Gp<{bX|SpWb4A^8LW0018VEC2ui01^Na000Hg;3tYyX_jM3R?Bl7&r(q;SsVx< zNd$5fv{ZsKA$SlL3&KN~a1tZRf*~1Ltkx9~2uL3&z-yb0WJDRY082|tP literal 0 HcmV?d00001 diff --git a/include/javascript/tiny_mce/plugins/emotions/img/smiley-laughing.gif b/include/javascript/tiny_mce/plugins/emotions/img/smiley-laughing.gif new file mode 100644 index 0000000000000000000000000000000000000000..1606c119e75678c4031f384e0d50849906e8f533 GIT binary patch literal 344 zcmV-e0jK^)Nk%w1VG;lm0MruzQauf>s;1-69HWK?p_PpF=Pd8~Ygtcnp*fHAL z**;z>w3iC}`fmL6IkKB1N;3zEa}&zKpsu1;_V)HocR5-{J~BcYvE`YXhBnc@CfU=! za(Ec zG>66zv=rqr;2j)}gKqE$ekcSD?}0=WLB?AWp85)qALd+P=4)6X4oXy{bw2>K^d$ z@6ERvva+(4ib~41YUkTEn1&#?rzrOHT>1I=Y*h`+%*@WtPUPg|!@EEI_d5LgZ>^Og z-qyCjsu$J9F8}}lA^8LW0018VEC2ui01^Na000HT;3tYxX_jM37RWXX8&XUv=@{Oj zX@_Sxw3H&!kzgQ?2LvPOL=>Y5VxieY9+_+eqFEql6OKWXd3Ze8Ggf2Zln@U|mI9d9 zGm^(wVUTA5cYs-V1`2#+a})^z6chrF5`~8k5e6@pmkW`GeGw<069yTQaGnH)s0suV zR|pCd0ZtRCsjM9VB^L+~7X%f*zyuc%2p3=#ycf#L%McYo9|{Z&5D^#_78qL%3{WW( X7Xb)FP6z?UH6ODVz!ev-DIowmgll^P literal 0 HcmV?d00001 diff --git a/include/javascript/tiny_mce/plugins/emotions/img/smiley-smile.gif b/include/javascript/tiny_mce/plugins/emotions/img/smiley-smile.gif new file mode 100644 index 0000000000000000000000000000000000000000..e6a9e60d5ddd1243fbbf2197b4dc6cd9c1b58b93 GIT binary patch literal 345 zcmV-f0jB;(Nk%w1VG;lm0MrlwCJF+^#>SR<4C>Dj%C>6W(lWoQPVevT^YB^Fy&h6M z4YZgH{O~qtR1(Ci8T;lQ`uh6d*t-7xar*K{#Jrulo-Wtd*44u?{`oh#n;gQXGXDEo z_}UVAU=FH^0ssI2A^8LW0018VEC2ui01^Na000Hn;3tYuX_jM3Mn>j&nGr!MNh}v4 zNyxPjwA7*EKx`%q#$Vl9SM>N9ReH-cn1&^4jYXf0KotqjT;UWC94U(4-NtX4#i!%9}pHA2?&dg3>XLr r8Wuqx2Nnhn1xrT-4h9xbDb^GQ8V(K`1{C5o)#U;I0p5-K5CQ-@9%ySnDDC*4*{OcpiwransPVevTQacIr@mkQp zCf(06s)_=>r7UYx48o@u`uh6d*t-7rH~ji<`P&oj;5Wp)o!8ga`SV6TA_BIW5#ZWV z{`*+__>9}pJ}3JDSl85wB_3Jn)Q o9|so(4+|I^92g4^1{Y8%(iR3pP6ig=HPPY$`~mLZA3^{CJDB=?L;wH) literal 0 HcmV?d00001 diff --git a/include/javascript/tiny_mce/plugins/emotions/img/smiley-tongue-out.gif b/include/javascript/tiny_mce/plugins/emotions/img/smiley-tongue-out.gif new file mode 100644 index 0000000000000000000000000000000000000000..2075dc16058f1f17912167675ce5cfb9986fc71d GIT binary patch literal 328 zcmV-O0k{4~Nk%w1VG;lm0Mrx!CJF+^#>SU@3-{U*rx+Q^wrc$ABfqLn@9*x?z8(4X zSW-O=@){bmmI~g|GQXoP);cvj3|f1M8e@{G*!tYaiCEujj1NGxRN#6#tiCETo+{x{Hkzt z5k-kPvcD=V2nbmjCgL6k{uF&2nP-t0s;w<385Nx2oxDb z9T5Pp7qJl?3Kkh9oe2sCr5F$p7zPSlsUH*@54w*83=9Or4;w)r2pcU95(FL|1Th;< aDaRQH4;Tal7#Y$v#?=Au0pHUfApkpvZg^t= literal 0 HcmV?d00001 diff --git a/include/javascript/tiny_mce/plugins/emotions/img/smiley-undecided.gif b/include/javascript/tiny_mce/plugins/emotions/img/smiley-undecided.gif new file mode 100644 index 0000000000000000000000000000000000000000..bef7e257303f8243c89787e7a7f9955dd1f112e2 GIT binary patch literal 337 zcmV-X0j~Z>Nk%w1VG;lm0MroxDi#99#>R?y8~4}{%C>6#>?OadPVevTr-=vi@LATn z4rERY-qJF+n+?CCE&B3D{{3Shh?>WT0o%`b%*Voqm`dL;(4F35y zc485^n;g!+Bme*aA^8LW0018VEC2ui01^Na000Hf;3tYvX_jM3N=AnuogqakNi<9X zK?&0kwA8^tNn{?C$|IAYI1ZzT!2>}iuMddFK#NEkRl!7%6brJAnUs;)XcnA}TNBSP zxQ9;SvEfwYeSaGd2^|LqU~(QF1qBxr3Ii7x84ZVt8wCTKoSYAqc?p`G2onnpk`IOl z1`HLGj}riN2p1K12N4z&8IBDc6tEWs859;JtRB6>lf+xO9}yT19toMv8wnl`7(pKg j7zPv!OGgY81{hE&(iR3pP6ig;HPPS!_yOwPA0Yrc)=Yf3 literal 0 HcmV?d00001 diff --git a/include/javascript/tiny_mce/plugins/emotions/img/smiley-wink.gif b/include/javascript/tiny_mce/plugins/emotions/img/smiley-wink.gif new file mode 100644 index 0000000000000000000000000000000000000000..9faf1aff8f4b28e02f4f414975fe1859c43b6b54 GIT binary patch literal 351 zcmV-l0igazNk%w1VG;lm0MrryC=CL}#>Sn03F^-g-qAA3wransPV?|t@9*x%vmQ`7 z4E*pcw3rOOq%3t@4*K#({N^40{c-yG`rz2Q!KfI-yq*61HrBop*VoqW<}&{JS@_x# zwwfH#!YTdnIsgCwA^8LW0018VEC2ui01^Na000Ht;3tYwX_jM3P6j6koH0o%Sun&A zMF+tYv=pL2IcOdp&qH&dG!P?+ArV0)J)O=Yk}%LD6Go&#@MJn3he8=)%%lWOM*#pN zEDD9iq9J$@90v~;83`GC4i0+{2OJ0pVtacF5E}yn8<`pmkCBv_pqZEtoPY-l0}P>= z3WE6cr`19U7DgF9{F}at6R35*Q5~ x2OgBy9tRx_7(pKh7zPvsOGgA01{hE&-4zBzP6id}HMp@0Krnzkbss_i06S`>cdh^c literal 0 HcmV?d00001 diff --git a/include/javascript/tiny_mce/plugins/emotions/img/smiley-yell.gif b/include/javascript/tiny_mce/plugins/emotions/img/smiley-yell.gif new file mode 100644 index 0000000000000000000000000000000000000000..648e6e879123fe49beebbc1f3635141864a79a9c GIT binary patch literal 336 zcmV-W0k8f?Nk%w1VG;lm0MrryG8O{K#>IbS7WCB_mWF$+hzY-{PWkp(?(Xf;zbH~P z3jOdj?W+^YwrakfE8fyG&5jTBz!3WS`fgM_;MltQ+c}4GO8)(E`S3`@yq&d~5!ct& z)v79NObo)O7XSbNA^8LW0018VEC2ui01^Na000He;3tYwX_jM3QifI(nn6h_*=Wyk zUB{y}v=qYOIUF#R3dZPhAVv~H;(|a2yN_5FH&J0|$eJ3kw4gj1Y?v5d#>LMV12^6BYy$1)ZKA zga!|m2?POz0R)f>4+aPl8KD{gz`+G_9vLMFQU?RU!8uyH9}*i52|cC+7S0YEK_3Vk i1|APfM-Ltb8&4_H83sg61{vHn(cc000qNZzApkp + + + {#example_dlg.title} + + + + + +
    +

    Here is a example dialog.

    +

    Selected text:

    +

    Custom arg:

    + +
    +
    + +
    + +
    + +
    +
    +
    + + + diff --git a/include/javascript/tiny_mce/plugins/example/editor_plugin.js b/include/javascript/tiny_mce/plugins/example/editor_plugin.js new file mode 100644 index 00000000..cb7010d1 --- /dev/null +++ b/include/javascript/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/include/javascript/tiny_mce/plugins/example/editor_plugin_src.js b/include/javascript/tiny_mce/plugins/example/editor_plugin_src.js new file mode 100644 index 00000000..beb36049 --- /dev/null +++ b/include/javascript/tiny_mce/plugins/example/editor_plugin_src.js @@ -0,0 +1,81 @@ +/** + + * + * @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/include/javascript/tiny_mce/plugins/example/img/example.gif b/include/javascript/tiny_mce/plugins/example/img/example.gif new file mode 100644 index 0000000000000000000000000000000000000000..1ab5da4461113d2af579898528246fdbe52ecd00 GIT binary patch literal 87 zcmZ?wbhEHb6k!lyn83&Y1dNP~ia%L^OhyJB5FaGNz@*pGzw+SQ`#f{}FJ-?!v#V)e mtsGNfpJeCKSAiOz**>0`XR2{OVa>-G_df0vaY/i);if(attr&&attr[1]){bdattr=attr[1].match(/\s*(\w+\s*=\s*".*?"|\w+\s*=\s*'.*?'|\w+\s*=\s*\w+|\w+)\s*/g);if(bdattr){for(i=0,len=bdattr.length;i',sp);t.head=c.substring(0,sp+1);ep=c.indexOf('\n';t.head+=ed.getParam('fullpage_default_doctype','');t.head+='\n\n\n'+ed.getParam('fullpage_default_title','Untitled document')+'\n';if(v=ed.getParam('fullpage_default_encoding'))t.head+='\n';if(v=ed.getParam('fullpage_default_font_family'))st+='font-family: '+v+';';if(v=ed.getParam('fullpage_default_font_size'))st+='font-size: '+v+';';if(v=ed.getParam('fullpage_default_text_color'))st+='color: '+v+';';t.head+='\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/include/javascript/tiny_mce/plugins/fullpage/editor_plugin_src.js b/include/javascript/tiny_mce/plugins/fullpage/editor_plugin_src.js new file mode 100644 index 00000000..264d22c9 --- /dev/null +++ b/include/javascript/tiny_mce/plugins/fullpage/editor_plugin_src.js @@ -0,0 +1,142 @@ +/** + + * + * @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); + + if (bdattr) { + 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, v, st = ''; + + // 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('\n'; + + t.head += ed.getParam('fullpage_default_doctype', ''); + t.head += '\n\n\n' + ed.getParam('fullpage_default_title', 'Untitled document') + '\n'; + + if (v = ed.getParam('fullpage_default_encoding')) + t.head += '\n'; + + if (v = ed.getParam('fullpage_default_font_family')) + st += 'font-family: ' + v + ';'; + + if (v = ed.getParam('fullpage_default_font_size')) + st += 'font-size: ' + v + ';'; + + if (v = ed.getParam('fullpage_default_text_color')) + st += 'color: ' + v + ';'; + + t.head += '\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); + } + }); + + // Register plugin + tinymce.PluginManager.add('fullpage', tinymce.plugins.FullPagePlugin); +})(); \ No newline at end of file diff --git a/include/javascript/tiny_mce/plugins/fullpage/fullpage.htm b/include/javascript/tiny_mce/plugins/fullpage/fullpage.htm new file mode 100644 index 00000000..eabc8237 --- /dev/null +++ b/include/javascript/tiny_mce/plugins/fullpage/fullpage.htm @@ -0,0 +1,577 @@ + + + + {#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/include/javascript/tiny_mce/plugins/fullpage/js/fullpage.js b/include/javascript/tiny_mce/plugins/fullpage/js/fullpage.js new file mode 100644 index 00000000..6c994e9c --- /dev/null +++ b/include/javascript/tiny_mce/plugins/fullpage/js/fullpage.js @@ -0,0 +1,461 @@ +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/include/javascript/tiny_mce/plugins/iespell/editor_plugin.js b/include/javascript/tiny_mce/plugins/iespell/editor_plugin.js new file mode 100644 index 00000000..06dae75d --- /dev/null +++ b/include/javascript/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/include/javascript/tiny_mce/plugins/iespell/editor_plugin_src.js b/include/javascript/tiny_mce/plugins/iespell/editor_plugin_src.js new file mode 100644 index 00000000..3e36302d --- /dev/null +++ b/include/javascript/tiny_mce/plugins/iespell/editor_plugin_src.js @@ -0,0 +1,51 @@ +/** + + * + * @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/include/javascript/tiny_mce/plugins/inlinepopups/editor_plugin.js b/include/javascript/tiny_mce/plugins/inlinepopups/editor_plugin.js new file mode 100644 index 00000000..5560b6b1 --- /dev/null +++ b/include/javascript/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;t.windows={};},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);}}});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')=='modal'){DOM.add(DOM.doc.body,'div',{id:'mceModalBlocker','class':(t.editor.settings.inlinepopups_skin||'clearlooks2')+'_modalBlocker',style:{zIndex:t.zIndex-1}});DOM.show('mceModalBlocker');}else DOM.setStyle('mceModalBlocker','z-index',t.zIndex-1);if(tinymce.isIE6||/Firefox\/2\./.test(navigator.userAgent)||(tinymce.isIE&&!DOM.boxModel))DOM.setStyles('mceModalBlocker',{position:'absolute',width:vp.w-2,height:vp.h-2});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;if(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(w,ti){var e;w=this._findId(w);if(e=DOM.get(w+'_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});},_findId:function(w){var t=this;if(typeof(w)=='string')return w;each(t.windows,function(wo){var ifr=DOM.get(wo.id+'_ifr');if(ifr&&w==ifr.contentWindow){w=wo.id;return false;}});return w;},_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/include/javascript/tiny_mce/plugins/inlinepopups/editor_plugin_src.js b/include/javascript/tiny_mce/plugins/inlinepopups/editor_plugin_src.js new file mode 100644 index 00000000..5bf612c2 --- /dev/null +++ b/include/javascript/tiny_mce/plugins/inlinepopups/editor_plugin_src.js @@ -0,0 +1,632 @@ +/** + + * + * @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; + t.windows = {}; + }, + + 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 + 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') == 'modal') { + DOM.add(DOM.doc.body, 'div', { + id : 'mceModalBlocker', + 'class' : (t.editor.settings.inlinepopups_skin || 'clearlooks2') + '_modalBlocker', + style : {zIndex : t.zIndex - 1} + }); + + DOM.show('mceModalBlocker'); // Reduces flicker in IE + } else + DOM.setStyle('mceModalBlocker', 'z-index', t.zIndex - 1); + + if (tinymce.isIE6 || /Firefox\/2\./.test(navigator.userAgent) || (tinymce.isIE && !DOM.boxModel)) + DOM.setStyles('mceModalBlocker', {position : 'absolute', width : vp.w - 2, height : vp.h - 2}); + + 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; + + if (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(w, ti) { + var e; + + w = this._findId(w); + + if (e = DOM.get(w + '_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 + + _findId : function(w) { + var t = this; + + if (typeof(w) == 'string') + return w; + + each(t.windows, function(wo) { + var ifr = DOM.get(wo.id + '_ifr'); + + if (ifr && w == ifr.contentWindow) { + w = wo.id; + return false; + } + }); + + return w; + }, + + _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/include/javascript/tiny_mce/plugins/inlinepopups/skins/clearlooks2/img/alert.gif b/include/javascript/tiny_mce/plugins/inlinepopups/skins/clearlooks2/img/alert.gif new file mode 100644 index 0000000000000000000000000000000000000000..94abd08763fffdaa0dd5c5afb470a97294f2b94d GIT binary patch literal 818 zcmV-21I_$LNk%w1VITk?0OkMyy?1uhZf>Is3*B5?sT&&Hqoc$;Jkrt6&k+&QHa5gV zL)l77I5;@fLqpYMWV+*+oUyj*ia`4%)P|vrSClaB!?EE7K$--(_XZ zOH0lO2-#9n!;Fik78a-!6wR}-yS%#378ch%J=j4(x@2V5*3{b0&C|=t(mFcQDJi8A z60bTsucxKY8XD3{O5bW~+gDfHP*AZbD54S)*gHGL#>A(co5`c08yg$Yzr7_TCCA9d zs-U0MFfhzxW4%d9s-K?K($LSkxy-Sz(7?Xdn3%wSe#oDmxL#e?qN1My0^C(q&nzt3 zjEvWFbJcly)5*uu)6w93eACp@*{!X#QBc56PRYv1%goBm&CA4*kj9vnyFxN00960|JK*lA^8LV00000EC2ui z03ZM$000O7fPaF6goTEOh>41ejE#5-A-Y zDMkRMg$FSdD>XGe76Lo4g8*}CUeivLI}B6rYIE)9Vh306CXDUKb=Dfx`}wT=u<6# zD$n)U&_b6YEgl901IUC4zyf`27&(S$$E;fb{Wx)wm4^u-0H zv*CdXLINn%=tH`+>C>qDxJcmTfS@*Z45S!AI|Ya#EOHOnP2`2|1;88Ju#tey5e=^) w9O1*fx%21Hn;(HtX3!cMK%gku&b_<$??7lEkM$&p`Sa-0r)T3DnWI1eJD_KQDgXcg literal 0 HcmV?d00001 diff --git a/include/javascript/tiny_mce/plugins/inlinepopups/skins/clearlooks2/img/button.gif b/include/javascript/tiny_mce/plugins/inlinepopups/skins/clearlooks2/img/button.gif new file mode 100644 index 0000000000000000000000000000000000000000..e671094cb0eb210b756117f992cf5ca2caa698fd GIT binary patch literal 280 zcmZ?wbhEHb3}BFB*v!Ci>hy`^ZOqepYsb$*CnUiMCojPaU!rn5M;0h0LDv*_&)DBrWN@OfznH1FT4{BUps!wTd|YdJ0002^_xJYp^u)%)d3$)z&B_1&{{R30 z000000000000000A^8LW000^QEC2ui0CWH_000I5phk>jX`ZJhqHH^=Zk(=iEn-2g z?|i>wBOI?nEEih2q)UH?AHyg7~@-@+VH6!(;c_ zxnl@0-@$+5z5y6S@uA0c2rFuI7V_gjj3zt(raakjrMZ$WvB8W9atTdoP;NHMsS_E` zo&bQ*s1XAOQ5i;$x=5;&g^B@Cqe`7hmFm-~ShGUCs0c-^w)`cdp#12=eOP%eQY|sD1+r)(d#BVZMbAD~4*IvE#>(BS&T|xw7TPlrL+3 zoO$zRs18Dl9!)zw58wX%{rd5@fPehOCg6KeHK5@Cf($n3po0lM*gyda7AK*C5k5#^gBwbip@gwr zxFA#zlxU)fn3pyG@#n&{$-F`k&?i#Os}T#YskFu{;S5}9I=NKOD% zl13IcK>xnz`3B3WgWQ!)wLkXuHnZ0c5HvW}0r6=_Zpm`ce)8x0(|!A=bwNAx@Vw%7Dp(bgC44=paU%GsGm?BAnBx(R%)rGkzT6lrjlmL z>8F%>3M!~kDPZcUsHUnas#2}$>Z=O03hS(=%1Z03TZN@7Sh{A#Yp+%P3hY!W2w?27 z$R?|-vc)dz?6bx;3+=SXN=q&OwHg>}*IdYMD_6JPx&>~yY8|WCxyGKWSi0&O#%{ZU z8SB}+^3J(S<94K>q#ugahfi?d(AAt1bTp(;R8!O__ z4hjuog&|&Ow1y6L_~6nY!bY^QK&A*J1XR};BaJ(@)KE`%6)&h8Wq?g93 z?c|kAwoPS{a3?9ZmalP{H`@ZtDW{vp&e>*|d8!$>oy!S+xSFqx+4!8sJ}PKTu0Ct)uD=RDxVCHlB}`m%1))6x2zDYdq=`Kv|wmLm3t8~B<$_Jb3xuB^__&G?WTylN4utE$1m z!1=ILv9hrCi66PSxc~e2>z6G0pe^@^5&5A-&VntacS+opK(T{V_m()r#KOD0y0na8 z%goB5UmeoU$gX`!&(O}**3|y@@xQ>n(9zHMmpZewvaqqQx45?Js#L_q!_309tE{Tf zhBEo9Vadb0m3v>7ePP{-Blnp<{MWPlxL*0GU8$dvuduJ(k1^BK(#Ocgm{14%#gX`? zRrPxW_?tJVsi*s^Ih9Zd`n!Ms{rtGOx2&zJ_Iw2Oc>wp7H`dqHA^8LV00000EC2ui z03ZM$000O7fPaF6gntbM4p9Oi0#ObH4TX}Ee_sv)5lUSnX(L@q5dschl$1*XVQCp1 zeyy$<2VnwB5T%0+1Q8<=Os>AJM0j(~$f5C*s#Z5#}WQsM?UH3Y?cED>eUzkt6a5bO}dMvwr^Xb5l#@FPJS zeS!wHvEmgRmp@>-3c_NDJ)uzN1ZkynBnOke0ssw~U_pYYQEhN&DagSGI<2(wiP}L< z2e47_&4?6KK!XdoP`Bdkv!miI0SHd)Rj>ff-abVV5}Gn#$6lukSl~7CfghoAf$`$8 z5@&CbciebnJ`7g|k8#ol6q!Rhs*3^IC>>Kxp>@zA1EAR&LqLOw8f*9N5TStp1}s%3 zVM*boLJ~NtT^KPTcxVj-0|X>-(j+l5M`Wq2O|PlKt>1?^svPY_j#uua~0?Tgn$1%K*EI2i?jm zAoXC1c4Wxs^ZEJtUB4qT{UQ1HY%Uh+pQ*t&D_y59>e1Hjx9TtBow%m&!&jTd_f1dxIfK5J>hhd07SSo@U1ANej1zBgs@J)fS$HxTwj{ShgdWQ_Y8V1_h@vv!qzRzyB@+ z)6#Z?iW=a9&+kg`Kr%f7CfA71iK;1=LJ}Gy$VX4NJcj@#Eg2?3moI4LKhG1RIoI;k zR(9^*MkqfeXOWI?@z07&C`6+;+5U$r@?g~7SE`^9EI4NyQM);aP&a^Qu#OXmrWw+; zlBPWv*b`t#;?w$Wfug|f{7_}xnb%jXB(rC~MUS#+NW!T2av4Ypxp0F2N_qva>Vv^VISDi|>EX(%41 z@Cm688>Uf+QlLkXaIO#&z;q&UJDY-1!mg;(MFDCGS{6p8a!wVF{_rmktj70is)Xxc~qF literal 0 HcmV?d00001 diff --git a/include/javascript/tiny_mce/plugins/inlinepopups/skins/clearlooks2/img/horizontal.gif b/include/javascript/tiny_mce/plugins/inlinepopups/skins/clearlooks2/img/horizontal.gif new file mode 100644 index 0000000000000000000000000000000000000000..c2a2ad454db194e428a7b9da40f62d5376a17428 GIT binary patch literal 769 zcmb7?=`WiB0LI^D)(HC`v6*aD4AW#LGRb0Oi$tH~CP=nb%N%8n zy02ceuewTUUDeW|RaMp*TlLV6R$o=rQOY{@AME+?`}QQiCwU%4Jq)?`{5B8=ECT1T z+wH!7{zji$)-UA>D9({)xO1SJGLHK54Mat(}s4_unMiKjB85EHng*~!Ddt+?(c5uHG4ZI zsc>jP#5Y6w6Wj5!Y=0^oK*&D+R;Yh@ze z7vfi;qFW{owiOfGqcB@XkwUZ0j?Km4{qjE- z6c!Z|O1!?5l~+^}tE#*^aCo0?lZ$rLKBwT;dI+nLO(UEMvb-ad9elEWPw8Xg(t zx$y<#6T+{PQ@$ecjAT|iC%dxnP5yoH$I`OLFU5*drPiz>bidcu^@a^2v}rP3-`?4^ z?Cl>M-Z(n8ot*x$0~Z|;ku35!-qAHSQN*GM3tW8AN#VWJNrHQD+6qXfO_zB^6eFVU zOjzupAb0*`W8} zQVeE5Djt<a0+Owme6r2OGio7DoTWqkhGKj0`0*1-*<$#uL5YH*kC8Z>wpCvYO~asp;G r-~A;>$wp)vkltB=c_?k6Zw*FUgrbAm;sB08O9+}m=}H3OFd*zN8L+JA literal 0 HcmV?d00001 diff --git a/include/javascript/tiny_mce/plugins/inlinepopups/skins/clearlooks2/img/vertical.gif b/include/javascript/tiny_mce/plugins/inlinepopups/skins/clearlooks2/img/vertical.gif new file mode 100644 index 0000000000000000000000000000000000000000..43a735f22c81d6d7d99c1ba9f034f38bfdd1a92b GIT binary patch literal 92 zcmZ?wbhEHb&D4o4FLHO9PR)B literal 0 HcmV?d00001 diff --git a/include/javascript/tiny_mce/plugins/inlinepopups/skins/clearlooks2/window.css b/include/javascript/tiny_mce/plugins/inlinepopups/skins/clearlooks2/window.css new file mode 100644 index 00000000..5e6fd7d3 --- /dev/null +++ b/include/javascript/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:fixed; 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; -ms-filter:'alpha(opacity=50)'; filter:alpha(opacity=50)} +.clearlooks2_modalBlocker {position:fixed; left:0; top:0; width:100%; height:100%; background:#FFF; opacity:0.6; -ms-filter:'alpha(opacity=60)'; 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/include/javascript/tiny_mce/plugins/inlinepopups/template.htm b/include/javascript/tiny_mce/plugins/inlinepopups/template.htm new file mode 100644 index 00000000..c98fe41a --- /dev/null +++ b/include/javascript/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/include/javascript/tiny_mce/plugins/insertdatetime/editor_plugin.js b/include/javascript/tiny_mce/plugins/insertdatetime/editor_plugin.js new file mode 100644 index 00000000..34d4ceca --- /dev/null +++ b/include/javascript/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/include/javascript/tiny_mce/plugins/layer/editor_plugin_src.js b/include/javascript/tiny_mce/plugins/layer/editor_plugin_src.js new file mode 100644 index 00000000..89390a2b --- /dev/null +++ b/include/javascript/tiny_mce/plugins/layer/editor_plugin_src.js @@ -0,0 +1,209 @@ +/** + + * + * @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/include/javascript/tiny_mce/plugins/media/css/content.css b/include/javascript/tiny_mce/plugins/media/css/content.css new file mode 100644 index 00000000..7739381d --- /dev/null +++ b/include/javascript/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/include/javascript/tiny_mce/plugins/media/css/media.css b/include/javascript/tiny_mce/plugins/media/css/media.css new file mode 100644 index 00000000..7b2253ba --- /dev/null +++ b/include/javascript/tiny_mce/plugins/media/css/media.css @@ -0,0 +1,16 @@ +#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: 380px; 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/include/javascript/tiny_mce/plugins/media/editor_plugin.js b/include/javascript/tiny_mce/plugins/media/editor_plugin.js new file mode 100644 index 00000000..b226b00d --- /dev/null +++ b/include/javascript/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.onPreInit.add(function(){ed.serializer.addRules('param[name|value|_mce_value]');});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'};ed.selection.onSetContent.add(function(){t._spansToImgs(ed.getBody());});ed.selection.onBeforeSetContent.add(t._objectsToSpans,t);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(t._objectsToSpans,t);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(/_mce_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};},_objectsToSpans:function(ed,o){var t=this,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(/]*)>/gi,'');h=h.replace(/<\/(object)([^>]*)>/gi,'');h=h.replace(/<\/embed>/gi,'');h=h.replace(/]*)>/gi,function(a,b){return''});h=h.replace(/\/ class=\"mceItemParam\"><\/span>/gi,'class="mceItemParam">');o.content=h;},_buildObj:function(o,n){var ob,ed=this.editor,dom=ed.dom,p=this._parse(n.title),stc;stc=ed.getParam('media_strict',true)&&o.type=='application/x-shockwave-flash';p.width=o.width=dom.getAttrib(n,'width')||100;p.height=o.height=dom.getAttrib(n,'height')||100;if(p.src)p.src=ed.convertURL(p.src,'src',n);if(stc){ob=dom.create('span',{mce_name:'object',type:'application/x-shockwave-flash',data:p.src,width:o.width,height:o.height});}else{ob=dom.create('span',{mce_name:'object',classid:"clsid:"+o.classid,codebase:o.codebase,width:o.width,height:o.height});}each(p,function(v,k){if(!/^(width|height|codebase|classid|_cx|_cy)$/.test(k)){if(o.type=='application/x-mplayer2'&&k=='src')k='url';if(v)dom.add(ob,'span',{mce_name:'param',name:k,'_mce_value':v});}});if(!stc)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='',args;args=['id','name','width','height','bgcolor','align','flashvars','src','wmode','allowfullscreen','quality'];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(args,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,'_mce_value');});if(pa.movie){pa.src=pa.movie;delete pa.movie;}n=dom.select('.mceItemEmbed',n)[0];if(n){each(args,function(na){var v=dom.getAttrib(n,na);if(v&&!pa[na])pa[na]=v;});}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/include/javascript/tiny_mce/plugins/media/editor_plugin_src.js b/include/javascript/tiny_mce/plugins/media/editor_plugin_src.js new file mode 100644 index 00000000..9f4abda2 --- /dev/null +++ b/include/javascript/tiny_mce/plugins/media/editor_plugin_src.js @@ -0,0 +1,400 @@ +/** + + * + * @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); + }; + + ed.onPreInit.add(function() { + // Force in _value parameter this extra parameter is required for older Opera versions + ed.serializer.addRules('param[name|value|_mce_value]'); + }); + + // 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' + }; + + ed.selection.onSetContent.add(function() { + t._spansToImgs(ed.getBody()); + }); + + ed.selection.onBeforeSetContent.add(t._objectsToSpans, t); + + 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(t._objectsToSpans, t); + + 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(/_mce_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 + _objectsToSpans : function(ed, o) { + var t = this, 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(/]*)>/gi, ''); + h = h.replace(/<\/(object)([^>]*)>/gi, ''); + h = h.replace(/<\/embed>/gi, ''); + h = h.replace(/]*)>/gi, function(a, b) {return ''}); + h = h.replace(/\/ class=\"mceItemParam\"><\/span>/gi, 'class="mceItemParam">'); + + o.content = h; + }, + + _buildObj : function(o, n) { + var ob, ed = this.editor, dom = ed.dom, p = this._parse(n.title), stc; + + stc = ed.getParam('media_strict', true) && o.type == 'application/x-shockwave-flash'; + + p.width = o.width = dom.getAttrib(n, 'width') || 100; + p.height = o.height = dom.getAttrib(n, 'height') || 100; + + if (p.src) + p.src = ed.convertURL(p.src, 'src', n); + + if (stc) { + ob = dom.create('span', { + mce_name : 'object', + type : 'application/x-shockwave-flash', + data : p.src, + width : o.width, + height : o.height + }); + } else { + ob = dom.create('span', { + mce_name : 'object', + classid : "clsid:" + o.classid, + codebase : o.codebase, + width : o.width, + height : o.height + }); + } + + each (p, function(v, k) { + if (!/^(width|height|codebase|classid|_cx|_cy)$/.test(k)) { + // Use url instead of src in IE for Windows media + if (o.type == 'application/x-mplayer2' && k == 'src') + k = 'url'; + + if (v) + dom.add(ob, 'span', {mce_name : 'param', name : k, '_mce_value' : v}); + } + }); + + if (!stc) + 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 = '', args; + + args = ['id', 'name', 'width', 'height', 'bgcolor', 'align', 'flashvars', 'src', 'wmode', 'allowfullscreen', 'quality']; + + // 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(args, 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, '_mce_value'); + }); + + // Use src not movie + if (pa.movie) { + pa.src = pa.movie; + delete pa.movie; + } + + // Merge with embed args + n = dom.select('.mceItemEmbed', n)[0]; + if (n) { + each(args, function(na) { + var v = dom.getAttrib(n, na); + + if (v && !pa[na]) + pa[na] = v; + }); + } + + 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/include/javascript/tiny_mce/plugins/media/img/flash.gif b/include/javascript/tiny_mce/plugins/media/img/flash.gif new file mode 100644 index 0000000000000000000000000000000000000000..cb192e6ceda8d19ad8e7d08dd1cfde0aa72ead2a GIT binary patch literal 241 zcmVOzlLa+Za}7>m0&NpCfJ0FQc3~F7DE)S%o1)Qi1n@vxX46qnD4hRS-NE*Pw!4UvE=#^N( literal 0 HcmV?d00001 diff --git a/include/javascript/tiny_mce/plugins/media/img/flv_player.swf b/include/javascript/tiny_mce/plugins/media/img/flv_player.swf new file mode 100644 index 0000000000000000000000000000000000000000..042c2ab969e98a6fdbe08848c4a73bd2c41de906 GIT binary patch literal 11668 zcmV;FEo;(4S5pYUVE_PloV|PrTvNvr@V+F3a36As0Rb-#MGjBSfQpD35b>z>Admpj zkkAkitwp@*Rqv`rs-o69lDZ&@y{HKo3{JcK8Rt^ z72Hab0Fi(9n@~bYkV2y_)Fy`HtF#7{J|rojb4e1a7ekY%Jpqu!GtXQ6#>m0qvY zqk05XkPr<=DTomvJ9PBuQB+V+fX0s>j}|Rjgg*T6Llosb@Z|f-K0(8m{He?6zo^!s zgW%o|yBiCa{N=g3_eV+xKc?-B?2)mXBGanczVGz$;(Jq8W!}yB$#d7jwz;Cki@c`f zWnSDHobzK#aT@9u=8^8x_Ib_e#Xl4Y`Zer+8u>-bA6`uVXi-Ep^6uWh%d8KaJS&g= z)KA}qY1=qz((;kczfDdZmcI1pls2gC!tgBV;pBqfKiK7u7MDbR)&C>$gyc05A7uO} zTU6zl(L392O7^D-J^u?tL2G}Nl|dGb6UZS!lq5p+9>gp}0$|zy zkSG#qbPAfg3zp?lIyJ5j#n!UMW{%nE-W&j!ZI})Q-KC5ph&MP(<)Js zTB%fN`{MEmC|{-4pi+ZEZQoGP^zA& zLSxF+rRqEl+hmTqSfx>GRVc3zjiF2!xFY<5N}=@HB8fb_IYAXlu?mZ7o| zrNW>xk}{1xtqwkmRR+Z{LK(lMQ+^9H0Gff% zJX2#B5lWP0dWAs^!o=T2Duogl*TKM!LUG8TsxY9=AQJ=bIZ~7vbc1o5C@Ly0DylPi zB6X=;AxGtErAn8jC@Te$;}vQ{nof_KL}N>PDKwfqMgBNcpw_5zCX}d9MX?4f1q5BH zQjIf;K8tpwpGg@hdc9%-(x|kBAc=g9I)9w8e;9k(1AMm0;^LIo2w|sWvCp)nqQ>Q7OIBoG-c3dwN`BaqJ6M4 zOw%ihS>0nCrK&(trZKR9V0>jIgTY<~VtawF!NoeAp$Mx6j|!@8ZhRE#47wDpaxk_w zZ9bB#483$(tty`=BA>qE(!oTHNMSH2@{4Fs^2!PdRC?S%DtRNC0b9$_Vc`%-0KWsl z4tpyM3N%(xt|-mdt4j=V07SGG+5vUw2tQ$nS`eWC^bEjRP@go6ZIn-bkt%;2?kwgU zO4Mu->COPIH>?q}HbxaOMi1RbgUQ$i;+&MUN@8Pb=p;x%p_xEbqg59ZRT$-mKTO69 z!yNNKBTkW_Sd)Vd6GVm$l)xKwg@qbbTA4-zomHu{D2EgTnM#5}(?In_K|MQ0b&T%O zv0GG-P9IbR152e3=^iR;{1rz?#t z)>Wug`QQd3^L53YQGQveL060kl%kTdQtS=buB4W!HHLm#TBTH%Vl9C#4A_6@i(xPp z0H1>?=P*pb)mTQ;z)w9I8i3J zGPPErptgE+fycR@b$bnIc#*`@ZkZw?a&b6jjeW{^Wky@if#fot%>Nv=VB$=K+nQI}A85~NO@ z;yQJrXo!Rj&atr$y{rUU0DqzfQ5x9-^=WZ&iLR8b!m3t6j%Nl|TsjW-XP^RpW0y9R zhP+-d-V8_q17$oKlV7ICVlALkB!tps zE=VF0Ble%j&I#b{0T@Z_2zhaKCjMnF^;{`HJ&_4XA`*&3d`O3Er%bk5gd~pmH+)It znbiW+kwX*{M7GXJ?zGGS*{0%58U#Gx`7~4m%Z`L)7pW(%aUnJJTn)6*ft2iR7Iw3Z znpPZN@N|_gb3zg~qbxEpv+g2+$k8dl1mz*ez4H_aGEHSIXqm)a$}99Dg(4FOJVoT` zF71o?!4380A$b2cghV3(70zUH=6T58JY;@}r<@RyTD0u*Pmm=98RR|u-!^aAaUUze z8>@VclI3idkLdT(+Lr%Ko{SN}U&;q{HG$&s0FdcqSlJvH{+vyVLnPq?r*F@f zI(GNCT^@`l*P=*lge0iA*jh0`|H2;4^c3_8_W1AAc8TG87F^PSQ{+oVDu`nU;@iG8 z;vq}KLoA|{0}~NhXPUk|O<%OPAYVbc=K!GXi+oKrPI6A?=_HQVB5DyGY*<7n&muwz zb_bqCbdZ{0Y*|FGr9}i=TSTyJiwL%~i2wf{3jYe@=PgD%vZ``2+975(sa(J|3?zK`XS zCPH@M=z<8-?L@qnB$6O^CS9QKQF0gO01Oe$hwvg0F;ZM7;PSCftU5c9FPeN}92aNX zJ)&6AELQYC!iqIZVxz4R>u6(Q%}049n>O|k;1Y;#&B3~48`DlBDA67UcD5!;=cNR~ z5z5oqnHR9%RmAkAw8&i4s#egK;)3&KB;EQFr{9-OUIo1A6c~MXkx0^m^tGpyrtWc4 z5*?grbm+;BQz-F5X2{S`cS$@!iI!UM?vTwXBb|=$7L*zfFd>oFNN7!>)a)~f&L*o# zBu$o*Dpy)1BQ2!#BLIGAnzzNWWgo3FGz<}5Q=3N&Ld)DuR!&)>O6ir2rwgqaGZer$ zPe}GAC4I;C4(UcYG&kSQC*iq$#*dZPR6H|7GI$(EUZqD<)EmqGE z5{9GCc>STP37J;w3t2plEqN#;ZX$qVfse+8N}5XAA?!kung=sUpcxnFfSnvE9|X#A zru!@qgVd-snJs3wr&1dnN0c69OC2_K6w$omI*~OLPg_;d%~Ulrf^z5x8e;N&&^yATxs&TCd(CJ-oKnKR{%vS@4$o+Gkt zxBzVWE=cmaskM=^fMpWID(ZCtJSv+o5Q#sz&X1M_un~|ep=t6M+DfjeoEor#mgiZP z=V$XGsdByxKDJ;t7KwCuW6@0p$F@L-ZHznszqW=~0ey{u*BCkBAx8SrP)!$wW27|5 zHXo#g|1AuYm1L`0VPA?1JoNwH z!O&Q!<|o|V)H|xB{FO2q7z+qVHPmGUurNdj#8o=5l`+x)YkblXKxu} zY1pIn!8U9Xe8ph7G54UWcVpXwuyBQ>l{AyLir$j2H2_niPKMa%IEhA@Ip2e~ql%Cq z3>gTiwx+y>&JL`{1@#X+v2#PHt*JY7mQkGTYr7jPw_4z%rH#E%@WWx~3eH4``?H(? z>9TFkid>wHRwdx)Sg$mT(h^a1FwUH?#3Z4{*;2qOio%A82Acs;1;+W-c$n|4BQynB zW>)?-axt3wM7%6Zvz4a2Bogx+S4|7cGXV%KC2S>9mm7|-Hx!`eydmpUtH}s_so&(B zE2T|s)dAU=h3FEJagx|=hb$_H-SCbWfR779LVWVThoM4#LvFN2y^QAgPT1ez5^!~; zl!+lCA#cKE9)FFQ25~^m1z`(hgN+S}EK?!}zRw1Rz{V`uf&e!;C)O>n;hM$S#sWTS z87K1jZpJeJWW2|7;S(sAvnYeNHM9RLe4ZRvd)NEI@U5|8|ugIm>8*) z%Xx#>#dM|vvCDS@yAV4XKnIFN?mQ9t7p-u2uTI5g!rSAg=0sTaM4%LmVC+_ECIlO^vs4JDBLZ&EVS!{J z#9?oX!&jhCh`|D!%Px{EmMoFHOFEUx69E0k3%VG9WIO3(m4I$`E``xZ`m&5&SP_Z@ z@=P1`%gOZNJ@Xi40aI;j2bT{6FDuwJObgVE`FKMaJ1Z~Novbho|C&T!TR86#cN9cOdLp7vK^BoISnGxtn8HG0&H;#R4W6qxVVEbs z{H+x}c$g1 zpG_0Fp2+tVpg*KBj6CTEJK)phF7v2Ea!<3fS#%hwmFNUApVN~*M#px}TbN-#q9@OR)B3i*0Q?^Cwv)$r*hsAeC%Bl|``w0>2 zQXo(LOr7Nbv;hWhpW1=MeR(JR7~~L+BwBn9`y831_Ay0{0Bc7Nv0osPNOsDpoQS($ zMI0MjC=#%zNQkfdjKF;^H!kgQMQL*5J}6i8g`5UcUePW&jiS7w-SU~-p)!!K2WAHc zPZ5MsAxU6TEu3ioCT^e`kM0=LS8Fq{L3M8t!#5uhW7~Sz@>ejP z3IDH*!`tGFCrshO&}pF=7Ce_)iO1YlxRqRPL=j7o3a|kQAvy}l>Ob~)mQ>;SB|Eor z#91Xi@+81QB$E=l<4t7)PM+7M$)E(1J#-&NBsPa;2Q_O{LYN2Ar4C2p4EGvsO~7sB zh(u(uLLm9Vj0jN^TeI7&M#QUGArfX%YBo)Yk0xNbvLjsC3F(@X4+%qdbjm7_d__c1 zoJ}XP=E2FAJ(o~#)e-bfJCErSUp9k#7yx8jeHd!3lYq2=Mv17SJz*Uk%lnkG1 zvRq(>+w8J{RRtM*afr_=%Cu~Yzjk1Ch``(8uZ}>4;b?`(B+Y}SR{7#Rlt8h6EChRp$6lOftRMFA0$ZuGMvhL!{1Vd4Tsq%M#rM4oAw z9iKIpnk}!>m3x~eZYD)?2uzqsw;en&QKMxDB@J{XKdgB=4P;k@hsT$`6F!RKK!+a3 zr8A#t_WTVyH>G9Y(IYTsW&3TEnRl3&TsPkM+-Hp4=01_{%|?*5)NC7AjFsO!Vw5^J z*E3u6wIEAFM1zzbo(rV=o+2aXPR3A2asW%-_rH|){mt;c-v;mdU!8X&Su^_vJgdKI z5c5E2Cf3Z~H?YV2hw+TK`BUC2ZHyUqo8D*`_V{ShTtv??#=jETnJ*X_MI$|1bXVa5AVDKCif@+*5fHKbb^HrG6?P;jBm9rosSX{-zLOxtv=$mH}G z6p@{UQ{4<9cW?!q!XkIYV zbYN4jadEs{(<1A%-dJmvr;8?@E}HRV#O86vFI#1!m4Cx!KYsddA@y`t>U>C3_U_6* zV06h6lqBwa#8tKtFDF{&>^4`>`2PQuSa3CC!S&y;VBrRhg|Etjj~NR-|BMBCp3b&j z`m@bM@L~K+L)v1=By*W3lE_S3=Qv(qZz|vx{cwSkacP3qTp=OxYIXwt#owX#MXWRC z2I4ic$rOZMx>B<}(HAv2;J%CTl_K!FUhE3bZXyiCuooUAyWx{D_V81SDhLd|?4rFG zijE;@0+GuR>dBh~6`@vD2xS3weSJN0ciGl}>_16wwb}LCM(qXmq6`P_q6`VWD5KtP z9y}eqwYSFCDg{O)>u5$QQ<`O({-1kWbW=~p;X14q7^+7)lR35F$=-NUu zvPRh$+wM{~G~fbyuR10#SEy`oDW84jwe{as4Q$Vh8#nX!vp!!s{l4|b6A)paKYtztc{PL;U2Hrgo-;L}^M>h-(x}{F(}Fl2JvbY2XKe)G zzv1*mBbH=O3;Gl)F$s6?v02LTIevi;rUCD$H9)igjw5AA@{mFI?%e~3xeHOC*PCnS z_s~YpI0VFf0LTmQ-@(LNpkqX8|S(sH6w)^49?S?t6rsux-nX{OQ7xcTjO4 zib5%<6m3C=kQYII>$u&1hb&+- zy1(7NxC#mm*bQeMWeGoN2<(Q+LxtZqxE??i7nlpRZmm$f7jv`LUR9NlgTd!i1uVlP zZcber^Vab9D?*uj@om0tK)DIt2If*N;7$Al!;P&<=!hO{2fV~WO!BjaKp2 zS>ORQX&ovbE<9HP_3;{L$MrHM+5l|a&jOa9&C9uzha0&-E50NBF25k$Cv!cE2_BHS z9zo?BfoIweXpr=AeHHKwv~EMM-}GW`<=W4v;(AKRy4j)l9NaZ;1Y`-z6&sn0xj?pJ zIBw<$Zia~GVHOqz{w7_n0g5?HCtQOv*%goIoeF=mCQI`sf00#FQ{Yapg`Km&7TiZr9a#b62OAn z&e=44;$C9CRG>}9k9ZA2olqp|3@~-k8Y9% z&ST3*L|@&W8^77v86`V(0e}Ex=K(IK;!=LD-;2g%*Bwo5?>1#lxiY!q&yq*8qlKfc z%c@hhj@jt(;rH_|uW>|f2cu8WY$Fi-=VtJqOs@cRQHE$%)}mo^$vUZbq033u@3rRq zULfat0}#$zvVeI^XLJxcV$@knZbuj=$%9)syjFe@Ch(GcSt2FE^S+qcp@yt>)=}+ zp7Rd1*f!OzHYLRWk%PPAzKkx)xrM&N)@G;oJ~=0&(pWs=gcaHA; z^6=hWPd2UUC+}7lTOZrh)HBxq*b~>f!^*r~5Q?`AU0+$>`HzW-Yeq)aO_4SH{pisn z?|V-w67uRUPJdADbpD?A=#PEp9l0&oayDb@`FoY0Uw)oEG|*XGQh%MXuT;JE_L-kV zpI@H$qD{}+L$}->ziZ^=aUb3Zzkj0y^;?`PQH2+l5Hxu`cp5Yt5)bWqGaf=jwKh$-(Q&1N?>7CyW-dc2S zYEg^qP49l)|EhNRIfwI$4nB^lcHVk^od2mJ=Zd6(J8%5`s3QG9-k{s@D_w8D5pW{s z_nV`$$It4$w&9J0Q3rdT3i5We8!~xQ&f1-6ZioIpUGw&By~ErCQy+SKmp|~0>lFz; zes2%Dcjxib+-^1do<0BY>7a-ckE2$fP?t#USFe`-@#mzZDObYI-6+}kJl20+-nOCZ zUMvj^jb14~n-mgXJ>VNhcbEU(>e7SH-b-)$x6j<$N1m)ZfA6&oXTqlMSIquB zE99D;zJB=P%UjQmt$(^}Y^C7NUbi{ab+qG#f3LQD*HK%tQR-vwQUzA?jKOD9j8+pr z_vbA4gU>@8yM^S9ThqEB&2EQB@{~C~i^pj{9dueUHCGipYvZ=zug(2tSep?a);)Ya z-`~5>fx5!C2j(t+^Ycqnf`dydW1FgDPZd?3?^sY*?KX3N>aLN?ChlGJ{e$uuc{>i- zPfMA5Sozm%mx{fkcZ~jc$%FF#ADxewuy^#`6eYH-(&wm0m!KPE&X`1ahru5lNNy4-v#Y4z7m>$4r6*{y5{>$+}`&)$ogkp6{L zb+u1tC}TD~%-(QjU(bLAeU)pj71XWKcqRJGU9vA%<}=ss#|a66*-5L1JuUxoUP95Z z;XUj-9y}n~|M$KNlahvYN#8Y6es)Z#SIN1P(@uAI|5lG*oZ@SaJ-h;@GJM&PJ9nNu zi~h5+e$nfZ%Qr4n_$hOLb?Z?@1DMc%n(qEF@fz6fqV(Pw8_r~hFZH}z`KZh1eYTu^@!PMP zpCT7u{}^f}9gJqu-lmx}IRulqCouYb;$GX~NHaq$WPkwmK^MT9!i?55c;J?lL0*6K z4QMryujzI{$jKq5F--kksSxZ$3G` zt;2~!o6hdKT6g}^xL@lQ$e&znH+;%`;xUom#wDfh&{6Lp10kLLEiw4a}; zIDuAP)Vv)ChJEZIV}o1o=@sDa)R-{;C&PD%3r9w7c-q;^@xr)`%QQgIBU$tI$DsPM~TZtCLia_!cmJ!8M!6F&aStJ$fNQ6HaQG3CS6elc5S##RpqA0r{AvF=pozs2fVM3+IQo9{D96nf>VEXn9-D_xI)gr)#o&!{AM4$5x!LikG@>R3)vx<(x9wr`O?v zx;z`iKeD|p0{m(CIbk`T0D)PFb{oHGI@ASBp z?bn88XucBp)SS8ZN9)RucIyr_x^|#O(#dEf9baN3k(`lq;?@whfRS`2>oa(3w>^U( z8G;NAfP}~s=W@QdScEgR_r8=Nr|fA##%od8G)@eO)q(D5L8z0=5%Cf$d}}2OA|W8X zF^F#iFD=7YsMd=y|B;Sddgd~;u@mCK&?{E!#eo>gnS*i~IQ1m2Esd%G!-QZMSDbiq z%<>2sFFR#h^gzAC82hU|g?s{WV}mbgTK#ceruOOfj6{MDrJ) zV!6^5v~;pVdw6z%X6R-7R7di^MB2Q%&x%H9~#H-8QIUz(Ln45_OAge~rzKY(Z zN$kU;1MVY}0BlLWpOS+YO}Wd789{x0eG|TgoBS|sCOf3TYY$LYg8hB>#s`+_y5EFy z)CP?zNLLVKC{hI#Xv*>By!Zl9Y?VO+bb3{Bkh&x?G7?nZ1~7U8t+<1>X7Cr9P*hA@ zOftB+zizKzKBewZKps5XY6i;Ke4&Bn>%d3@Tm6gZ+=B0g9S(D!OZdT|wxoI+8 z=+X?B&#f8#aj$Jdr=_iXbU1Iv$@eCYi}L&8uYq0s*DpNME6Ba7pw8jFmRg36;}QujUXdwq|5!y7UViX(-j1q2 zCO&6&PS`Pg&$~x%?|G3J=mtUyJTxi2e)?M*&Rl%_>yu~Glc(L^R99CwFDLx=ql49_ zeSLkMV=51<-k$vM;5GI4x;NhV!}+hp7n4G6B~HHC?~~U5@tu31aCUEf*~E$8&FUR; z?a9oyI&W`U-FtGb{9H+o=@2;oY<>5#r{j!=ZqHro>i7MXyK}^XNA^D~_mPOMM+t}3 ze|_=3Wb&TU`%SO6(2ZQZqf&|yfMthy(G*fa6>Yl^Hx8=GtqqH9}^n3 z?n|l4A|t<=x|*Yb?<6<<7TA&>f9U>1dpj5?ep3Zerh8l2F(?MB_nTf-LE=C)bwEc0 zd=pU2pqcEdMpN>MhiCy_w@5%qF4s?{o$NOgP4-e7%Us?WKuxEPeDVi{|B8v^R zB>cGn?UUW+E~#=aaYWFkwhoKc;CAT!w6v!!;h98w>O^~*NS!XbLWOrSlF@Laq(1%H zwQI=TMN<`1aa?+*WrOkuCFk2^oD7pW8IFQy3V04~Lb8bZ?L&=BI^DTJ=v^#E8S4m$fXGF-bTg^FJ?Eia`h^T literal 0 HcmV?d00001 diff --git a/include/javascript/tiny_mce/plugins/media/img/quicktime.gif b/include/javascript/tiny_mce/plugins/media/img/quicktime.gif new file mode 100644 index 0000000000000000000000000000000000000000..3b0499145b16138249f653a1a3f2c80230fb292c GIT binary patch literal 303 zcmV+~0nq+ONk%w1VGsZi0K^{vH>m7Qv+~s9^fsC5ZpZP=*zu3F=Jxpf8k_5u%JNv6 z=md-84VLU4w)kSE=yI&-yw>b=v+SqE?+kq47pC+YrR?bJ^yu>Zyvpn;hTp*6^mM!O zu+8$^=JX7bb<~J01ZTA{q@86#&8&6~H`Ss{{?p%K!-p%L6P2TpFYz90?pD06UU# BbnE~C literal 0 HcmV?d00001 diff --git a/include/javascript/tiny_mce/plugins/media/img/realmedia.gif b/include/javascript/tiny_mce/plugins/media/img/realmedia.gif new file mode 100644 index 0000000000000000000000000000000000000000..fdfe0b9ac05869ae845fdd828eaad97cc0c69dbc GIT binary patch literal 439 zcmV;o0Z9HwNk%w1VI=?(0K^{vQcz8xz}f&njBB06v9GQ`Jv%NdDHCI&z`wqZw$(Lw zuFTBL!Pe#<92tv>h)9OE1Xh}vnVEHSaeb-GByg#tqM_B*)YRkdSdqTuipLaF8n=^^LJP4|1^gGRdo_Rl+a*grZQ1hw@Zo1ikN$oB{QbRq&z?QIckdq1aE3;Fq_(WV>Kc7gjQtQh+9OrtFhn-)LUqD<|MOIl_!(Ed#pPRE;S)g;ew3>pd zn`Wa(lc2DGa)peFw3f88dp-|`@*)AXj;@(8hwDr|7Sxsp;&YxjN*Y{PBB!TIU|!b7Zgv0OaG5)&Kwi literal 0 HcmV?d00001 diff --git a/include/javascript/tiny_mce/plugins/media/img/trans.gif b/include/javascript/tiny_mce/plugins/media/img/trans.gif new file mode 100644 index 0000000000000000000000000000000000000000..388486517fa8da13ebd150e8f65d5096c3e10c3a GIT binary patch literal 43 ncmZ?wbhEHbWMp7un7{x9ia%KxMSyG_5FaGNz{KRj$Y2csb)f_x literal 0 HcmV?d00001 diff --git a/include/javascript/tiny_mce/plugins/media/img/windowsmedia.gif b/include/javascript/tiny_mce/plugins/media/img/windowsmedia.gif new file mode 100644 index 0000000000000000000000000000000000000000..ab50f2d887a0843b116ef598e5a005e5601d18d0 GIT binary patch literal 415 zcmV;Q0bu?|Nk%w1VGjTg0M$PL`E^qkEu+z?1&N?x_*pRg{rx~kg!#|I<>uyug^O^t z0hZGrt*x!>$1C!zn`W5@`ts6_uMW)2%<0NUEKIo?SIPPE=}U0}7Z(?JcX!y=*;bF< zCWz-=h7+2ao9)(dOHM;+X=xs9)%!~xc&ICMZdRYdUQ2$^@9y(6X3NCIz{cM7f^Z=Q z1_tQ95kgl8b%R%OiYTIo7LSdE^@}A^8LW002J#EC2ui01p5U000KOz@O0K01zUifeIyT9%!RzMDgehG|mwLz+Eh; z7Z~iE zrX?OfJ^>XeDJK)xJuWOB3_l1N0Ra>g4Gk^=ED0V6LI?>4;Q|6OB{LplLMRLg8U5-E J?0y6R06W6!pgRBn literal 0 HcmV?d00001 diff --git a/include/javascript/tiny_mce/plugins/media/js/embed.js b/include/javascript/tiny_mce/plugins/media/js/embed.js new file mode 100644 index 00000000..6fe25de0 --- /dev/null +++ b/include/javascript/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)) { + tinyMCEPopup.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; + + // Avoid annoying warning about insecure items + if (!tinymce.isIE || document.location.protocol != 'https:') { + 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/include/javascript/tiny_mce/plugins/nonbreaking/editor_plugin.js b/include/javascript/tiny_mce/plugins/nonbreaking/editor_plugin.js new file mode 100644 index 00000000..4fce503c --- /dev/null +++ b/include/javascript/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/include/javascript/tiny_mce/plugins/nonbreaking/editor_plugin_src.js b/include/javascript/tiny_mce/plugins/nonbreaking/editor_plugin_src.js new file mode 100644 index 00000000..720971d9 --- /dev/null +++ b/include/javascript/tiny_mce/plugins/nonbreaking/editor_plugin_src.js @@ -0,0 +1,50 @@ +/** + + * + * @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/include/javascript/tiny_mce/plugins/noneditable/editor_plugin.js b/include/javascript/tiny_mce/plugins/noneditable/editor_plugin.js new file mode 100644 index 00000000..8a1b8f07 --- /dev/null +++ b/include/javascript/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/include/javascript/tiny_mce/plugins/noneditable/editor_plugin_src.js b/include/javascript/tiny_mce/plugins/noneditable/editor_plugin_src.js new file mode 100644 index 00000000..9176f47b --- /dev/null +++ b/include/javascript/tiny_mce/plugins/noneditable/editor_plugin_src.js @@ -0,0 +1,87 @@ +/** + + * + * @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/include/javascript/tiny_mce/plugins/pagebreak/css/content.css b/include/javascript/tiny_mce/plugins/pagebreak/css/content.css new file mode 100644 index 00000000..c949d58c --- /dev/null +++ b/include/javascript/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/include/javascript/tiny_mce/plugins/pagebreak/editor_plugin.js b/include/javascript/tiny_mce/plugins/pagebreak/editor_plugin.js new file mode 100644 index 00000000..177ea95b --- /dev/null +++ b/include/javascript/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/include/javascript/tiny_mce/plugins/pagebreak/editor_plugin_src.js b/include/javascript/tiny_mce/plugins/pagebreak/editor_plugin_src.js new file mode 100644 index 00000000..3d97a5d7 --- /dev/null +++ b/include/javascript/tiny_mce/plugins/pagebreak/editor_plugin_src.js @@ -0,0 +1,74 @@ +/** + + * + * @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/include/javascript/tiny_mce/plugins/pagebreak/img/pagebreak.gif b/include/javascript/tiny_mce/plugins/pagebreak/img/pagebreak.gif new file mode 100644 index 0000000000000000000000000000000000000000..acdf4085f3068c4c0a1d6855f4b80dae8bac3068 GIT binary patch literal 325 zcmV-L0lNN2Nk%w1VPpUd0J9GO`>v<{=;ru;boX6P{`2zsmyZ3>&HK5t_;hIbi-G;z z+4`cI{KdfcXj}GCLjV8&A^8LW000jFEC2ui0Av6R000E?@X1N5y*TU5yZ>M)j$|1M z4Ouvb$pHu>IW8BZq|n;U0s@T!VM5~w1_+1X!EiVl!&PITYdjT!ffYfpt{jAfv%qvh zA63WUHSlr7LkeyaV4(pM0f50(II?RD4RtMg4-E+tFhdAy5{3c=0}3Bg9Y8`B2To20 zR%SO62L%9}0H+dzoKB$+2TOwzUrwi{XiBM^4V#>63q3!LsU3u93zH8CdwqY%62;1g z0g8ze$k93lWExp`CUe|K4qOWk17ZeJ0|5pDP6+}};{>bI@lOWj=kf}r2sHp7w9-Ie XK%9UG6W(*AX-vY05F<*&5CH%?Gwy&_ literal 0 HcmV?d00001 diff --git a/include/javascript/tiny_mce/plugins/pagebreak/img/trans.gif b/include/javascript/tiny_mce/plugins/pagebreak/img/trans.gif new file mode 100644 index 0000000000000000000000000000000000000000..388486517fa8da13ebd150e8f65d5096c3e10c3a GIT binary patch literal 43 ncmZ?wbhEHbWMp7un7{x9ia%KxMSyG_5FaGNz{KRj$Y2csb)f_x literal 0 HcmV?d00001 diff --git a/include/javascript/tiny_mce/plugins/paste/blank.htm b/include/javascript/tiny_mce/plugins/paste/blank.htm new file mode 100644 index 00000000..f841206c --- /dev/null +++ b/include/javascript/tiny_mce/plugins/paste/blank.htm @@ -0,0 +1,22 @@ + + +blank_page + + + + + + + + + diff --git a/include/javascript/tiny_mce/plugins/paste/css/blank.css b/include/javascript/tiny_mce/plugins/paste/css/blank.css new file mode 100644 index 00000000..f1ab1133 --- /dev/null +++ b/include/javascript/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/include/javascript/tiny_mce/plugins/paste/css/pasteword.css b/include/javascript/tiny_mce/plugins/paste/css/pasteword.css new file mode 100644 index 00000000..77685fd2 --- /dev/null +++ b/include/javascript/tiny_mce/plugins/paste/css/pasteword.css @@ -0,0 +1,3 @@ +.sourceIframe { + border: 1px solid #808080; +} diff --git a/include/javascript/tiny_mce/plugins/paste/editor_plugin.js b/include/javascript/tiny_mce/plugins/paste/editor_plugin.js new file mode 100644 index 00000000..eeeebd5b --- /dev/null +++ b/include/javascript/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(!tinymce.isIE&&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){content=this.editor.dom.encode(content);if(content&&content.length>0){if(!this.editor.selection.isCollapsed())this.editor.execCommand("Delete");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,...,\x93|\x94|\u201c|\u201d,",\x60|\x91|\x92|\u2018|\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('
    ]+>/g,"");if(this.editor.getParam("paste_remove_spans",true))content=content.replace(/<\/?span[^>]*>/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) { + content = this.editor.dom.encode(content); + + if (content && content.length > 0) { + // Delete any highlighted text before pasting + if (!this.editor.selection.isCollapsed()) + this.editor.execCommand("Delete"); + + 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,...,\x93|\x94|\u201c|\u201d,",\x60|\x91|\x92|\u2018|\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('
    ]+>/g, ""); // Header elements + + if (this.editor.getParam("paste_remove_spans", true)) + content = content.replace(/<\/?span[^>]*>/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/include/javascript/tiny_mce/plugins/paste/pasteword.htm b/include/javascript/tiny_mce/plugins/paste/pasteword.htm new file mode 100644 index 00000000..f96d4784 --- /dev/null +++ b/include/javascript/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/include/javascript/tiny_mce/plugins/preview/editor_plugin.js b/include/javascript/tiny_mce/plugins/preview/editor_plugin.js new file mode 100644 index 00000000..deb4bce9 --- /dev/null +++ b/include/javascript/tiny_mce/plugins/preview/editor_plugin.js @@ -0,0 +1 @@ +(function(){tinymce.create('tinymce.plugins.Preview',{init:function(ed,url){var t=this,css=tinymce.explode(ed.settings.content_css);t.editor=ed;tinymce.each(css,function(u,k){css[k]=ed.documentBaseURI.toAbsolute(u);});ed.addCommand('mcePreview',function(){ed.windowManager.open({file:ed.getParam("plugin_preview_pageurl",url+"/preview.html"),width:parseInt(ed.getParam("plugin_preview_width","550")),height:parseInt(ed.getParam("plugin_preview_height","600")),resizable:"yes",scrollbars:"yes",popup_css:css.join(','),inline:ed.getParam("plugin_preview_inline",1)},{base:ed.documentBaseURI.getURI()});});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};}});tinymce.PluginManager.add('preview',tinymce.plugins.Preview);})(); \ No newline at end of file diff --git a/include/javascript/tiny_mce/plugins/preview/editor_plugin_src.js b/include/javascript/tiny_mce/plugins/preview/editor_plugin_src.js new file mode 100644 index 00000000..5ad98c24 --- /dev/null +++ b/include/javascript/tiny_mce/plugins/preview/editor_plugin_src.js @@ -0,0 +1,50 @@ +/** + + * + * @author Moxiecode + * @copyright Copyright © 2004-2008, Moxiecode Systems AB, All rights reserved. + */ + +(function() { + tinymce.create('tinymce.plugins.Preview', { + init : function(ed, url) { + var t = this, css = tinymce.explode(ed.settings.content_css); + + t.editor = ed; + + // Force absolute CSS urls + tinymce.each(css, function(u, k) { + css[k] = ed.documentBaseURI.toAbsolute(u); + }); + + ed.addCommand('mcePreview', function() { + ed.windowManager.open({ + file : ed.getParam("plugin_preview_pageurl", url + "/preview.html"), + width : parseInt(ed.getParam("plugin_preview_width", "550")), + height : parseInt(ed.getParam("plugin_preview_height", "600")), + resizable : "yes", + scrollbars : "yes", + popup_css : css.join(','), + inline : ed.getParam("plugin_preview_inline", 1) + }, { + base : ed.documentBaseURI.getURI() + }); + }); + + 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 + }; + } + }); + + // Register plugin + tinymce.PluginManager.add('preview', tinymce.plugins.Preview); +})(); \ No newline at end of file diff --git a/include/javascript/tiny_mce/plugins/preview/example.html b/include/javascript/tiny_mce/plugins/preview/example.html new file mode 100644 index 00000000..48202224 --- /dev/null +++ b/include/javascript/tiny_mce/plugins/preview/example.html @@ -0,0 +1,28 @@ + + + + + +Example of a custom preview page + + + +Editor contents:
    +
    + +
    + + + diff --git a/include/javascript/tiny_mce/plugins/preview/jscripts/embed.js b/include/javascript/tiny_mce/plugins/preview/jscripts/embed.js new file mode 100644 index 00000000..6fe25de0 --- /dev/null +++ b/include/javascript/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 += ' + + + + +{#preview.preview_desc} + + + + + diff --git a/include/javascript/tiny_mce/plugins/print/editor_plugin.js b/include/javascript/tiny_mce/plugins/print/editor_plugin.js new file mode 100644 index 00000000..7d09a87c --- /dev/null +++ b/include/javascript/tiny_mce/plugins/print/editor_plugin.js @@ -0,0 +1 @@ +(function(){tinymce.create('tinymce.plugins.Print',{init:function(ed,url){ed.addCommand('mcePrint',function(){ed.getWin().print();});ed.addButton('print',{title:'print.print_desc',cmd:'mcePrint'});},getInfo:function(){return{longname:'Print',author:'Moxiecode Systems AB',authorurl:'http://tinymce.moxiecode.com',infourl:'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/print',version:tinymce.majorVersion+"."+tinymce.minorVersion};}});tinymce.PluginManager.add('print',tinymce.plugins.Print);})(); \ No newline at end of file diff --git a/include/javascript/tiny_mce/plugins/print/editor_plugin_src.js b/include/javascript/tiny_mce/plugins/print/editor_plugin_src.js new file mode 100644 index 00000000..84b70fc6 --- /dev/null +++ b/include/javascript/tiny_mce/plugins/print/editor_plugin_src.js @@ -0,0 +1,31 @@ +/** + + * + * @author Moxiecode + * @copyright Copyright © 2004-2008, Moxiecode Systems AB, All rights reserved. + */ + +(function() { + tinymce.create('tinymce.plugins.Print', { + init : function(ed, url) { + ed.addCommand('mcePrint', function() { + ed.getWin().print(); + }); + + ed.addButton('print', {title : 'print.print_desc', cmd : 'mcePrint'}); + }, + + getInfo : function() { + return { + longname : 'Print', + author : 'Moxiecode Systems AB', + authorurl : 'http://tinymce.moxiecode.com', + infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/print', + version : tinymce.majorVersion + "." + tinymce.minorVersion + }; + } + }); + + // Register plugin + tinymce.PluginManager.add('print', tinymce.plugins.Print); +})(); diff --git a/include/javascript/tiny_mce/plugins/safari/blank.htm b/include/javascript/tiny_mce/plugins/safari/blank.htm new file mode 100644 index 00000000..266808ce --- /dev/null +++ b/include/javascript/tiny_mce/plugins/safari/blank.htm @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/include/javascript/tiny_mce/plugins/safari/editor_plugin.js b/include/javascript/tiny_mce/plugins/safari/editor_plugin.js new file mode 100644 index 00000000..4daac19f --- /dev/null +++ b/include/javascript/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;function isEmpty(d,e,f){var w,n;w=d.createTreeWalker(e,NodeFilter.SHOW_ALL,null,false);while(n=w.nextNode()){if(f){if(!f(n))return false;}if(n.nodeType==3&&n.nodeValue&&/[^\s\u00a0]+/.test(n.nodeValue))return false;if(n.nodeType==1&&/^(HR|IMG|TABLE)$/.test(n.nodeName))return false;}return true;};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.addCommand('CreateLink',function(u,v){var n=ed.selection.getNode(),dom=ed.dom,a;if(n&&(/^(left|right)$/i.test(dom.getStyle(n,'float',1))||/^(left|right)$/i.test(dom.getAttrib(n,'align')))){a=dom.create('a',{href:v},n.cloneNode());n.parentNode.replaceChild(a,n);ed.selection.select(a);}else ed.getDoc().execCommand("CreateLink",false,v);});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,r,n,s;if(e.keyCode==46||e.keyCode==8){b=ed.getBody();h=b.innerHTML;s=ed.selection;if(b.childNodes.length==1&&!/<(img|hr)/.test(h)&&tinymce.trim(h.replace(/<[^>]+>/g,'')).length==0){ed.setContent('


    ',{format:'raw'});n=b.firstChild;r=s.getRng();r.setStart(n,0);r.setEnd(n,0);s.setRng(r);}}});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,ed.dom.processHTML(v)+'XX');ed.selection.select(ed.dom.get('_mce_tmp'));ed.getDoc().execCommand("Delete",false,' ');});ed.onKeyPress.add(function(ed,e){var se,li,lic,r1,r2,n,sel,doc,be,af,pa;if(e.keyCode==13){sel=ed.selection;se=sel.getNode();if(e.shiftKey||ed.settings.force_br_newlines&&se.nodeName!='LI'){t._insertBR(ed);Event.cancel(e);}if(li=dom.getParent(se,'LI')){lic=dom.getParent(li,'OL,UL');doc=ed.getDoc();pa=dom.create('p');dom.add(pa,'br',{mce_bogus:"1"});if(isEmpty(doc,li)){if(n=dom.getParent(lic.parentNode,'LI,OL,UL'))return;n=dom.getParent(lic,'p,h1,h2,h3,h4,h5,h6,div')||lic;r1=doc.createRange();r1.setStartBefore(n);r1.setEndBefore(li);r2=doc.createRange();r2.setStartAfter(li);r2.setEndAfter(n);be=r1.cloneContents();af=r2.cloneContents();if(!isEmpty(doc,af))dom.insertAfter(af,n);dom.insertAfter(pa,n);if(!isEmpty(doc,be))dom.insertAfter(be,n);dom.remove(n);n=pa.firstChild;r1=doc.createRange();r1.setStartBefore(n);r1.setEndBefore(n);sel.setRng(r1);return Event.cancel(e);}}}});ed.onExecCommand.add(function(ed,cmd){var sel,dom,bl,bm;if(cmd=='InsertUnorderedList'||cmd=='InsertOrderedList'){sel=ed.selection;dom=ed.dom;if(bl=dom.getParent(sel.getNode(),function(n){return/^(H[1-6]|P|ADDRESS|PRE)$/.test(n.nodeName);})){bm=sel.getBookmark();dom.remove(bl,1);sel.moveToBookmark(bm);}}});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/include/javascript/tiny_mce/plugins/safari/editor_plugin_src.js b/include/javascript/tiny_mce/plugins/safari/editor_plugin_src.js new file mode 100644 index 00000000..b82febda --- /dev/null +++ b/include/javascript/tiny_mce/plugins/safari/editor_plugin_src.js @@ -0,0 +1,514 @@ +/** + + * + * @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; + + function isEmpty(d, e, f) { + var w, n; + + w = d.createTreeWalker(e, NodeFilter.SHOW_ALL, null, false); + while (n = w.nextNode()) { + // Filter func + if (f) { + if (!f(n)) + return false; + } + + // Non whitespace text node + if (n.nodeType == 3 && n.nodeValue && /[^\s\u00a0]+/.test(n.nodeValue)) + return false; + + // Is non text element byt still content + if (n.nodeType == 1 && /^(HR|IMG|TABLE)$/.test(n.nodeName)) + return false; + } + + return true; + }; + + 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 CreateLink command will not work correctly on images that is aligned + ed.addCommand('CreateLink', function(u, v) { + var n = ed.selection.getNode(), dom = ed.dom, a; + + if (n && (/^(left|right)$/i.test(dom.getStyle(n, 'float', 1)) || /^(left|right)$/i.test(dom.getAttrib(n, 'align')))) { + a = dom.create('a', {href : v}, n.cloneNode()); + n.parentNode.replaceChild(a, n); + ed.selection.select(a); + } else + ed.getDoc().execCommand("CreateLink", false, v); + }); + + 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, r, n, s; + + // If backspace or delete key + if (e.keyCode == 46 || e.keyCode == 8) { + b = ed.getBody(); + h = b.innerHTML; + s = ed.selection; + + // 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) { + // Inject paragrah and bogus br + ed.setContent('


    ', {format : 'raw'}); + + // Move caret before bogus br + n = b.firstChild; + r = s.getRng(); + r.setStart(n, 0); + r.setEnd(n, 0); + s.setRng(r); + } + } + }); + + // 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, ed.dom.processHTML(v) + 'XX'); + ed.selection.select(ed.dom.get('_mce_tmp')); + ed.getDoc().execCommand("Delete", false, ' '); + }); + + ed.onKeyPress.add(function(ed, e) { + var se, li, lic, r1, r2, n, sel, doc, be, af, pa; + + if (e.keyCode == 13) { + sel = ed.selection; + se = sel.getNode(); + + // Workaround for missing shift+enter support, http://bugs.webkit.org/show_bug.cgi?id=16973 + if (e.shiftKey || ed.settings.force_br_newlines && se.nodeName != 'LI') { + t._insertBR(ed); + Event.cancel(e); + } + + // Workaround for DIV elements produced by Safari + if (li = dom.getParent(se, 'LI')) { + lic = dom.getParent(li, 'OL,UL'); + doc = ed.getDoc(); + + pa = dom.create('p'); + dom.add(pa, 'br', {mce_bogus : "1"}); + + if (isEmpty(doc, li)) { + // If list in list then use browser default behavior + if (n = dom.getParent(lic.parentNode, 'LI,OL,UL')) + return; + + n = dom.getParent(lic, 'p,h1,h2,h3,h4,h5,h6,div') || lic; + + // Create range from the start of block element to the list item + r1 = doc.createRange(); + r1.setStartBefore(n); + r1.setEndBefore(li); + + // Create range after the list to the end of block element + r2 = doc.createRange(); + r2.setStartAfter(li); + r2.setEndAfter(n); + + be = r1.cloneContents(); + af = r2.cloneContents(); + + if (!isEmpty(doc, af)) + dom.insertAfter(af, n); + + dom.insertAfter(pa, n); + + if (!isEmpty(doc, be)) + dom.insertAfter(be, n); + + dom.remove(n); + + n = pa.firstChild; + r1 = doc.createRange(); + r1.setStartBefore(n); + r1.setEndBefore(n); + sel.setRng(r1); + + return Event.cancel(e); + } + } + } + }); + + // Safari doesn't place lists outside block elements + ed.onExecCommand.add(function(ed, cmd) { + var sel, dom, bl, bm; + + if (cmd == 'InsertUnorderedList' || cmd == 'InsertOrderedList') { + sel = ed.selection; + dom = ed.dom; + + if (bl = dom.getParent(sel.getNode(), function(n) {return /^(H[1-6]|P|ADDRESS|PRE)$/.test(n.nodeName);})) { + bm = sel.getBookmark(); + dom.remove(bl, 1); + sel.moveToBookmark(bm); + } + } + }); + + // 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.onInit.add(function() { + t._fixWebKitSpans(); + + 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/include/javascript/tiny_mce/plugins/save/editor_plugin.js b/include/javascript/tiny_mce/plugins/save/editor_plugin.js new file mode 100644 index 00000000..8a13e7d3 --- /dev/null +++ b/include/javascript/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;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.");},_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/include/javascript/tiny_mce/plugins/save/editor_plugin_src.js b/include/javascript/tiny_mce/plugins/save/editor_plugin_src.js new file mode 100644 index 00000000..236c3545 --- /dev/null +++ b/include/javascript/tiny_mce/plugins/save/editor_plugin_src.js @@ -0,0 +1,98 @@ +/** + + * + * @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; + + 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."); + }, + + _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/include/javascript/tiny_mce/plugins/searchreplace/css/searchreplace.css b/include/javascript/tiny_mce/plugins/searchreplace/css/searchreplace.css new file mode 100644 index 00000000..3e2eaf34 --- /dev/null +++ b/include/javascript/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/include/javascript/tiny_mce/plugins/searchreplace/editor_plugin.js b/include/javascript/tiny_mce/plugins/searchreplace/editor_plugin.js new file mode 100644 index 00000000..7fd913b2 --- /dev/null +++ b/include/javascript/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/include/javascript/tiny_mce/plugins/searchreplace/editor_plugin_src.js b/include/javascript/tiny_mce/plugins/searchreplace/editor_plugin_src.js new file mode 100644 index 00000000..30e2610b --- /dev/null +++ b/include/javascript/tiny_mce/plugins/searchreplace/editor_plugin_src.js @@ -0,0 +1,54 @@ +/** + + * + * @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/include/javascript/tiny_mce/plugins/searchreplace/js/searchreplace.js b/include/javascript/tiny_mce/plugins/searchreplace/js/searchreplace.js new file mode 100644 index 00000000..e555a3fc --- /dev/null +++ b/include/javascript/tiny_mce/plugins/searchreplace/js/searchreplace.js @@ -0,0 +1,126 @@ +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; + + if (s == '') + return; + + 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': + // Move caret to beginning of text + ed.execCommand('SelectAll'); + ed.selection.collapse(true); + + 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) + tinyMCEPopup.alert(ed.getLang('searchreplace_dlg.allreplaced')); + else + tinyMCEPopup.alert(ed.getLang('searchreplace_dlg.notfound')); + + return; + + case 'current': + if (!ed.selection.isCollapsed()) + 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 + tinyMCEPopup.alert(ed.getLang('searchreplace_dlg.notfound')); + + tinyMCEPopup.storeSelection(); + } else { + if (!w.find(s, ca, b, false, false, false, false)) + tinyMCEPopup.alert(ed.getLang('searchreplace_dlg.notfound')); + else + fix(); + } + } +}; + +tinyMCEPopup.onInit.add(SearchReplaceDialog.init, SearchReplaceDialog); diff --git a/include/javascript/tiny_mce/plugins/searchreplace/langs/en_dlg.js b/include/javascript/tiny_mce/plugins/searchreplace/langs/en_dlg.js new file mode 100644 index 00000000..3dd3453d --- /dev/null +++ b/include/javascript/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/include/javascript/tiny_mce/plugins/searchreplace/searchreplace.htm b/include/javascript/tiny_mce/plugins/searchreplace/searchreplace.htm new file mode 100644 index 00000000..90e80d07 --- /dev/null +++ b/include/javascript/tiny_mce/plugins/searchreplace/searchreplace.htm @@ -0,0 +1,105 @@ + + + + {#searchreplace_dlg.replace_title} + + + + + + + + +
    + + +
    +
    + + + + + + + + + + + +
    + + + + + + + + +
    +
    + + + + + +
    +
    +
    + +
    + + + + + + + + + + + + + + + +
    + + + + + + + + +
    +
    + + + + + +
    +
    +
    + +
    + +
    +
    + + + +
    + +
    + +
    +
    +
    + + diff --git a/include/javascript/tiny_mce/plugins/spellchecker/css/content.css b/include/javascript/tiny_mce/plugins/spellchecker/css/content.css new file mode 100644 index 00000000..656ce1ee --- /dev/null +++ b/include/javascript/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/include/javascript/tiny_mce/plugins/spellchecker/editor_plugin.js b/include/javascript/tiny_mce/plugins/spellchecker/editor_plugin.js new file mode 100644 index 00000000..9cb67996 --- /dev/null +++ b/include/javascript/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/include/javascript/tiny_mce/plugins/spellchecker/editor_plugin_src.js b/include/javascript/tiny_mce/plugins/spellchecker/editor_plugin_src.js new file mode 100644 index 00000000..65a21a2e --- /dev/null +++ b/include/javascript/tiny_mce/plugins/spellchecker/editor_plugin_src.js @@ -0,0 +1,338 @@ +/** + + * + * @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/include/javascript/tiny_mce/plugins/spellchecker/img/wline.gif b/include/javascript/tiny_mce/plugins/spellchecker/img/wline.gif new file mode 100644 index 0000000000000000000000000000000000000000..7d0a4dbca03cc13177a359a5f175dda819fdf464 GIT binary patch literal 46 ycmZ?wbhEHbWMN=tXkcXcqowu#|9{1wEQ|~cj0`#qKmd|qU}ANVOOs?}um%7FLkRf* literal 0 HcmV?d00001 diff --git a/include/javascript/tiny_mce/plugins/style/css/props.css b/include/javascript/tiny_mce/plugins/style/css/props.css new file mode 100644 index 00000000..5550b093 --- /dev/null +++ b/include/javascript/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/include/javascript/tiny_mce/plugins/style/editor_plugin.js b/include/javascript/tiny_mce/plugins/style/editor_plugin.js new file mode 100644 index 00000000..6ebaa91c --- /dev/null +++ b/include/javascript/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/include/javascript/tiny_mce/plugins/style/editor_plugin_src.js b/include/javascript/tiny_mce/plugins/style/editor_plugin_src.js new file mode 100644 index 00000000..7a8ecf0d --- /dev/null +++ b/include/javascript/tiny_mce/plugins/style/editor_plugin_src.js @@ -0,0 +1,52 @@ +/** + + * + * @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/include/javascript/tiny_mce/plugins/style/js/props.js b/include/javascript/tiny_mce/plugins/style/js/props.js new file mode 100644 index 00000000..4fdfceb8 --- /dev/null +++ b/include/javascript/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/include/javascript/tiny_mce/plugins/style/langs/en_dlg.js b/include/javascript/tiny_mce/plugins/style/langs/en_dlg.js new file mode 100644 index 00000000..d9d77627 --- /dev/null +++ b/include/javascript/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/include/javascript/tiny_mce/plugins/style/props.htm b/include/javascript/tiny_mce/plugins/style/props.htm new file mode 100644 index 00000000..54538e35 --- /dev/null +++ b/include/javascript/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/include/javascript/tiny_mce/plugins/table/cell.htm b/include/javascript/tiny_mce/plugins/table/cell.htm new file mode 100644 index 00000000..c9317316 --- /dev/null +++ b/include/javascript/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/include/javascript/tiny_mce/plugins/table/css/cell.css b/include/javascript/tiny_mce/plugins/table/css/cell.css new file mode 100644 index 00000000..a47cc1a1 --- /dev/null +++ b/include/javascript/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/include/javascript/tiny_mce/plugins/table/css/row.css b/include/javascript/tiny_mce/plugins/table/css/row.css new file mode 100644 index 00000000..0e397db3 --- /dev/null +++ b/include/javascript/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/include/javascript/tiny_mce/plugins/table/css/table.css b/include/javascript/tiny_mce/plugins/table/css/table.css new file mode 100644 index 00000000..8f107831 --- /dev/null +++ b/include/javascript/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/include/javascript/tiny_mce/plugins/table/editor_plugin.js b/include/javascript/tiny_mce/plugins/table/editor_plugin.js new file mode 100644 index 00000000..97a9d256 --- /dev/null +++ b/include/javascript/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]});});if(ed.getParam('inline_styles')){ed.onPreProcess.add(function(ed,o){var dom=ed.dom;each(dom.select('table',o.node),function(n){var v;if(v=dom.getAttrib(n,'width')){dom.setStyle(n,'width',v);dom.setAttrib(n,'width');}if(v=dom.getAttrib(n,'height')){dom.setStyle(n,'height',v);dom.setAttrib(n,'height');}});});}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')){if(!tinymce.isGecko&&!tinymce.isOpera){tinyMCE.execInstanceCommand(ed.editorId,"mceTableMoveToNextRow",true);return tinymce.dom.Event.cancel(e);}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"mceTableMoveToNextRow":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"mceTableMoveToNextRow":var nextCell=getNextCell(tableElm,tdElm);if(!nextCell){inst.execCommand("mceTableInsertRowAfter",tdElm);nextCell=getNextCell(tableElm,tdElm);}inst.selection.select(nextCell);inst.selection.collapse(true);return true;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&&tableElm.nodeName=='TBODY'){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(inst.dom.getParent(tableElm,"table"));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(inst.dom.getParent(tableElm,"table"));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)&&tableElm.nodeName=='TBODY'){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/include/javascript/tiny_mce/plugins/table/editor_plugin_src.js b/include/javascript/tiny_mce/plugins/table/editor_plugin_src.js new file mode 100644 index 00000000..985af1a8 --- /dev/null +++ b/include/javascript/tiny_mce/plugins/table/editor_plugin_src.js @@ -0,0 +1,1136 @@ +/** + + * + * @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]}); + }); + + if (ed.getParam('inline_styles')) { + // Force move of attribs to styles in strict mode + ed.onPreProcess.add(function(ed, o) { + var dom = ed.dom; + + each(dom.select('table', o.node), function(n) { + var v; + + if (v = dom.getAttrib(n, 'width')) { + dom.setStyle(n, 'width', v); + dom.setAttrib(n, 'width'); + } + + if (v = dom.getAttrib(n, 'height')) { + dom.setStyle(n, 'height', v); + dom.setAttrib(n, 'height'); + } + }); + }); + } + + 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')) { + if (!tinymce.isGecko && !tinymce.isOpera) { + tinyMCE.execInstanceCommand(ed.editorId, "mceTableMoveToNextRow", true); + return tinymce.dom.Event.cancel(e); + } + + 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 "mceTableMoveToNextRow": + 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(inst.dom.getParent(tableElm, "table")); + 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(inst.dom.getParent(tableElm, "table")); + 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) && tableElm.nodeName == 'TBODY') { + 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/include/javascript/tiny_mce/plugins/table/js/cell.js b/include/javascript/tiny_mce/plugins/table/js/cell.js new file mode 100644 index 00000000..07320ac2 --- /dev/null +++ b/include/javascript/tiny_mce/plugins/table/js/cell.js @@ -0,0 +1,269 @@ +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'); + + function doUpdate(s) { + if (s) { + updateCell(tdElm); + + ed.addVisual(); + ed.nodeChanged(); + inst.execCommand('mceEndUndoLevel'); + tinyMCEPopup.close(); + } + }; + + if (ed.getParam("accessibility_warnings", 1)) { + if (celltype == "th" && scope == "") + tinyMCEPopup.confirm(ed.getLang('table_dlg.missing_scope', '', true), doUpdate); + else + doUpdate(1); + + 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) { + tinyMCEPopup.alert(inst.getLang('table_dlg.col_limit').replace(/\{\$cols\}/g, colLimit)); + return false; + } else if (rowLimit && rows > rowLimit) { + tinyMCEPopup.alert(inst.getLang('table_dlg.row_limit').replace(/\{\$rows\}/g, rowLimit)); + return false; + } else if (cellLimit && cols * rows > cellLimit) { + tinyMCEPopup.alert(inst.getLang('table_dlg.cell_limit').replace(/\{\$cells\}/g, 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 && inst.settings.inline_styles) { + 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 && inst.settings.inline_styles) { + dom.setStyle(elm, 'height', height); + dom.setAttrib(elm, 'height', ''); + } else { + dom.setAttrib(elm, 'height', height, true); + dom.setStyle(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/include/javascript/tiny_mce/plugins/table/langs/en_dlg.js b/include/javascript/tiny_mce/plugins/table/langs/en_dlg.js new file mode 100644 index 00000000..a33c987c --- /dev/null +++ b/include/javascript/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/include/javascript/tiny_mce/plugins/table/merge_cells.htm b/include/javascript/tiny_mce/plugins/table/merge_cells.htm new file mode 100644 index 00000000..f2dcbec5 --- /dev/null +++ b/include/javascript/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/include/javascript/tiny_mce/plugins/table/row.htm b/include/javascript/tiny_mce/plugins/table/row.htm new file mode 100644 index 00000000..4a709d36 --- /dev/null +++ b/include/javascript/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/include/javascript/tiny_mce/plugins/table/table.htm b/include/javascript/tiny_mce/plugins/table/table.htm new file mode 100644 index 00000000..74982fa1 --- /dev/null +++ b/include/javascript/tiny_mce/plugins/table/table.htm @@ -0,0 +1,193 @@ + + + + {#table_dlg.title} + + + + + + + + + + +
    + + +
    +
    +
    + {#table_dlg.general_props} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +
    +
    + +
    +
    + {#table_dlg.advanced_props} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    + + + + + +
     
    +
    + +
    + +
    + +
    + + + + + +
     
    +
    + + + + + +
     
    +
    +
    +
    +
    + +
    +
    + +
    + +
    + +
    +
    +
    + + diff --git a/include/javascript/tiny_mce/plugins/template/blank.htm b/include/javascript/tiny_mce/plugins/template/blank.htm new file mode 100644 index 00000000..538a3b12 --- /dev/null +++ b/include/javascript/tiny_mce/plugins/template/blank.htm @@ -0,0 +1,12 @@ + + + blank_page + + + + + + + diff --git a/include/javascript/tiny_mce/plugins/template/css/template.css b/include/javascript/tiny_mce/plugins/template/css/template.css new file mode 100644 index 00000000..0a03f2e5 --- /dev/null +++ b/include/javascript/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/include/javascript/tiny_mce/plugins/template/editor_plugin.js b/include/javascript/tiny_mce/plugins/template/editor_plugin.js new file mode 100644 index 00000000..0f7fb015 --- /dev/null +++ b/include/javascript/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/include/javascript/tiny_mce/plugins/template/js/template.js b/include/javascript/tiny_mce/plugins/template/js/template.js new file mode 100644 index 00000000..7eab2ebb --- /dev/null +++ b/include/javascript/tiny_mce/plugins/template/js/template.js @@ -0,0 +1,106 @@ +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, ti) { + var d = window.frames['templatesrc'].document, x, tsrc = this.tsrc; + + if (!u) + return; + + d.body.innerHTML = this.templateHTML = this.getFileContents(u); + + for (x=0; x + + {#template_dlg.title} + + + + + + +
    +
    +
    {#template_dlg.desc}
    +
    + +
    +
    +
    +
    + {#template_dlg.preview} + +
    +
    + +
    +
    + +
    + +
    + +
    + +
    +
    +
    + + diff --git a/include/javascript/tiny_mce/plugins/visualchars/editor_plugin.js b/include/javascript/tiny_mce/plugins/visualchars/editor_plugin.js new file mode 100644 index 00000000..e1e4238a --- /dev/null +++ b/include/javascript/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/include/javascript/tiny_mce/plugins/xhtmlxtras/acronym.htm b/include/javascript/tiny_mce/plugins/xhtmlxtras/acronym.htm new file mode 100644 index 00000000..3cbe57e8 --- /dev/null +++ b/include/javascript/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/include/javascript/tiny_mce/plugins/xhtmlxtras/attributes.htm b/include/javascript/tiny_mce/plugins/xhtmlxtras/attributes.htm new file mode 100644 index 00000000..1d882007 --- /dev/null +++ b/include/javascript/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/include/javascript/tiny_mce/plugins/xhtmlxtras/cite.htm b/include/javascript/tiny_mce/plugins/xhtmlxtras/cite.htm new file mode 100644 index 00000000..aa24db6d --- /dev/null +++ b/include/javascript/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/include/javascript/tiny_mce/plugins/xhtmlxtras/css/attributes.css b/include/javascript/tiny_mce/plugins/xhtmlxtras/css/attributes.css new file mode 100644 index 00000000..85b1b376 --- /dev/null +++ b/include/javascript/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/include/javascript/tiny_mce/plugins/xhtmlxtras/css/popup.css b/include/javascript/tiny_mce/plugins/xhtmlxtras/css/popup.css new file mode 100644 index 00000000..034b9852 --- /dev/null +++ b/include/javascript/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/include/javascript/tiny_mce/plugins/xhtmlxtras/del.htm b/include/javascript/tiny_mce/plugins/xhtmlxtras/del.htm new file mode 100644 index 00000000..f67e84ff --- /dev/null +++ b/include/javascript/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/include/javascript/tiny_mce/plugins/xhtmlxtras/editor_plugin.js b/include/javascript/tiny_mce/plugins/xhtmlxtras/editor_plugin.js new file mode 100644 index 00000000..00c178e5 --- /dev/null +++ b/include/javascript/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');cm.setActive('cite',0);cm.setActive('acronym',0);cm.setActive('abbr',0);cm.setActive('del',0);cm.setActive('ins',0);if(n){do{cm.setDisabled(n.nodeName.toLowerCase(),0);cm.setActive(n.nodeName.toLowerCase(),1);}while(n=n.parentNode);}});},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/include/javascript/tiny_mce/plugins/xhtmlxtras/editor_plugin_src.js b/include/javascript/tiny_mce/plugins/xhtmlxtras/editor_plugin_src.js new file mode 100644 index 00000000..75a26ff1 --- /dev/null +++ b/include/javascript/tiny_mce/plugins/xhtmlxtras/editor_plugin_src.js @@ -0,0 +1,136 @@ +/** + + * + * @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'); + cm.setActive('cite', 0); + cm.setActive('acronym', 0); + cm.setActive('abbr', 0); + cm.setActive('del', 0); + cm.setActive('ins', 0); + + // Activate all + if (n) { + do { + cm.setDisabled(n.nodeName.toLowerCase(), 0); + cm.setActive(n.nodeName.toLowerCase(), 1); + } while (n = n.parentNode); + } + }); + }, + + 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/include/javascript/tiny_mce/plugins/xhtmlxtras/ins.htm b/include/javascript/tiny_mce/plugins/xhtmlxtras/ins.htm new file mode 100644 index 00000000..2411e820 --- /dev/null +++ b/include/javascript/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/include/javascript/tiny_mce/plugins/xhtmlxtras/js/abbr.js b/include/javascript/tiny_mce/plugins/xhtmlxtras/js/abbr.js new file mode 100644 index 00000000..9630a365 --- /dev/null +++ b/include/javascript/tiny_mce/plugins/xhtmlxtras/js/abbr.js @@ -0,0 +1,25 @@ + /** + + * + * @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/include/javascript/tiny_mce/plugins/xhtmlxtras/js/acronym.js b/include/javascript/tiny_mce/plugins/xhtmlxtras/js/acronym.js new file mode 100644 index 00000000..d4ffbe1b --- /dev/null +++ b/include/javascript/tiny_mce/plugins/xhtmlxtras/js/acronym.js @@ -0,0 +1,25 @@ + /** + + * + * @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/include/javascript/tiny_mce/plugins/xhtmlxtras/js/attributes.js b/include/javascript/tiny_mce/plugins/xhtmlxtras/js/attributes.js new file mode 100644 index 00000000..9971b6a3 --- /dev/null +++ b/include/javascript/tiny_mce/plugins/xhtmlxtras/js/attributes.js @@ -0,0 +1,123 @@ + /** + + * + * @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/include/javascript/tiny_mce/plugins/xhtmlxtras/js/cite.js b/include/javascript/tiny_mce/plugins/xhtmlxtras/js/cite.js new file mode 100644 index 00000000..f764d9b6 --- /dev/null +++ b/include/javascript/tiny_mce/plugins/xhtmlxtras/js/cite.js @@ -0,0 +1,25 @@ + /** + + * + * @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/include/javascript/tiny_mce/plugins/xhtmlxtras/js/del.js b/include/javascript/tiny_mce/plugins/xhtmlxtras/js/del.js new file mode 100644 index 00000000..e607a009 --- /dev/null +++ b/include/javascript/tiny_mce/plugins/xhtmlxtras/js/del.js @@ -0,0 +1,60 @@ + /** + + * + * @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) { + insertInlineElement('del'); + 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(); + + insertInlineElement(element_name); + var elementArray = tinymce.grep(SXE.inst.dom.select(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; +} + +function insertInlineElement(en) { + var ed = tinyMCEPopup.editor, dom = ed.dom; + + ed.getDoc().execCommand('FontName', false, 'mceinline'); + tinymce.each(dom.select(tinymce.isWebKit ? 'span' : 'font'), function(n) { + if (n.style.fontFamily == 'mceinline' || n.face == 'mceinline') + dom.replace(dom.create(en, {_mce_new : 1}), n, 1); + }); +} diff --git a/include/javascript/tiny_mce/plugins/xhtmlxtras/js/ins.js b/include/javascript/tiny_mce/plugins/xhtmlxtras/js/ins.js new file mode 100644 index 00000000..d518739f --- /dev/null +++ b/include/javascript/tiny_mce/plugins/xhtmlxtras/js/ins.js @@ -0,0 +1,59 @@ + /** + + * + * @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) { + insertInlineElement('INS'); + 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/include/javascript/tiny_mce/themes/advanced/anchor.htm b/include/javascript/tiny_mce/themes/advanced/anchor.htm new file mode 100644 index 00000000..054cde57 --- /dev/null +++ b/include/javascript/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/include/javascript/tiny_mce/themes/advanced/charmap.htm b/include/javascript/tiny_mce/themes/advanced/charmap.htm new file mode 100644 index 00000000..8ca01133 --- /dev/null +++ b/include/javascript/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/include/javascript/tiny_mce/themes/advanced/color_picker.htm b/include/javascript/tiny_mce/themes/advanced/color_picker.htm new file mode 100644 index 00000000..4cab7689 --- /dev/null +++ b/include/javascript/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/include/javascript/tiny_mce/themes/advanced/editor_template.js b/include/javascript/tiny_mce/themes/advanced/editor_template.js new file mode 100644 index 00000000..f233b72c --- /dev/null +++ b/include/javascript/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',{sizes:[8,10,12,14,18,24,36],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,o;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_more_colors:1,theme_advanced_row_height:23,theme_advanced_resize_horizontal:1,theme_advanced_resizing_use_cookie:1,theme_advanced_font_sizes:"1,2,3,4,5,6,7",readonly:ed.settings.readonly},ed.settings);if(!s.font_size_style_values)s.font_size_style_values="8pt,10pt,12pt,14pt,18pt,24pt,36pt";if(tinymce.is(s.theme_advanced_font_sizes,'string')){s.font_size_style_values=tinymce.explode(s.font_size_style_values);s.font_size_classes=tinymce.explode(s.font_size_classes||'');o={};ed.settings.theme_advanced_font_sizes=s.theme_advanced_font_sizes;each(ed.getParam('theme_advanced_font_sizes','','hash'),function(v,k){var cl;if(k==v&&v>=1&&v<=7){k=v+' ('+t.sizes[v-1]+'pt)';if(ed.settings.convert_fonts_to_spans){cl=s.font_size_classes[v-1];v=s.font_size_style_values[v-1]||(t.sizes[v-1]+'pt');}}if(/\s*\./.test(v))cl=v.replace(/\./g,'');o[k]=cl?{'class':cl}:{fontSize:v};});s.theme_advanced_font_sizes=o;}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(s.editor_css?ed.documentBaseURI.toAbsolute(s.editor_css):url+"/skins/"+ed.settings.skin+"/ui.css");if(s.skin_variant)DOM.loadCSS(url+"/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(e){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){if(!c.NativeListBox){Event.add(n.id+'_text','focus',t._importClasses,t);Event.add(n.id+'_text','mousedown',t._importClasses,t);Event.add(n.id+'_open','focus',t._importClasses,t);Event.add(n.id+'_open','mousedown',t._importClasses,t);}else Event.add(n.id,'focus',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 t=this,ed=t.editor,c,i=0,cl=[];c=ed.controlManager.createListBox('fontsizeselect',{title:'advanced.font_size',onselect:function(v){if(v.fontSize)ed.execCommand('FontSize',false,v.fontSize);else{each(t.settings.theme_advanced_font_sizes,function(v,k){if(v['class'])cl.push(v['class']);});ed.editorCommands._applyInlineStyle('span',{'class':v['class']},{check_classes:cl});}}});if(c){each(t.settings.theme_advanced_font_sizes,function(v,k){var fz=v.fontSize;if(fz>=1&&fz<=7)fz=t.sizes[parseInt(fz)-1]+'pt';c.add(k,v,{'style':'font-size:'+fz,'class':'mceFontSize'+(i++)+(' '+(v['class']||''))});});}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;if(s.theme_advanced_default_foreground_color)o.default_color=s.theme_advanced_default_foreground_color;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;if(s.theme_advanced_default_background_color)o.default_color=s.theme_advanced_default_background_color;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(s.readonly){n=DOM.add(tb,'tr');n=ic=DOM.add(n,'td',{'class':'mceIframeContainer'});return ic;}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(v.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']||da).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"), tabindex : "-1"},''));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();', tabindex : "-1"},''));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,cl,fz,fn;if(s.readonly)return;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(ed.settings.convert_fonts_to_spans){ed.dom.getParent(n,function(n){if(n.nodeName==='SPAN'){if(!cl&&n.className)cl=n.className;if(!fz&&n.style.fontSize)fz=n.style.fontSize;if(!fn&&n.style.fontFamily)fn=n.style.fontFamily.replace(/[\"\']+/g,'').replace(/^([^,]+).*/,'$1').toLowerCase();}return false;});if(c=cm.get('fontselect')){c.select(function(v){return v.replace(/^([^,]+).*/,'$1').toLowerCase()==fn;});}if(c=cm.get('fontsizeselect')){c.select(function(v){if(v.fontSize&&v.fontSize===fz)return true;if(v['class']&&v['class']===cl)return true;});}}else{if(c=cm.get('fontselect'))c.select(ed.queryCommandValue('FontName'));if(c=cm.get('fontsizeselect')){v=ed.queryCommandValue('FontSize');c.select(function(iv){return iv.fontSize==v;});}}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||n.nodeName==='BR'||(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/include/javascript/tiny_mce/themes/advanced/editor_template_src.js b/include/javascript/tiny_mce/themes/advanced/editor_template_src.js new file mode 100644 index 00000000..304cabb2 --- /dev/null +++ b/include/javascript/tiny_mce/themes/advanced/editor_template_src.js @@ -0,0 +1,1153 @@ +/** + + * + * @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', { + sizes : [8, 10, 12, 14, 18, 24, 36], + + // 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, o; + + 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_more_colors : 1, + theme_advanced_row_height : 23, + theme_advanced_resize_horizontal : 1, + theme_advanced_resizing_use_cookie : 1, + theme_advanced_font_sizes : "1,2,3,4,5,6,7", + readonly : ed.settings.readonly + }, ed.settings); + + // Setup default font_size_style_values + if (!s.font_size_style_values) + s.font_size_style_values = "8pt,10pt,12pt,14pt,18pt,24pt,36pt"; + + if (tinymce.is(s.theme_advanced_font_sizes, 'string')) { + s.font_size_style_values = tinymce.explode(s.font_size_style_values); + s.font_size_classes = tinymce.explode(s.font_size_classes || ''); + + // Parse string value + o = {}; + ed.settings.theme_advanced_font_sizes = s.theme_advanced_font_sizes; + each(ed.getParam('theme_advanced_font_sizes', '', 'hash'), function(v, k) { + var cl; + + if (k == v && v >= 1 && v <= 7) { + k = v + ' (' + t.sizes[v - 1] + 'pt)'; + + if (ed.settings.convert_fonts_to_spans) { + cl = s.font_size_classes[v - 1]; + v = s.font_size_style_values[v - 1] || (t.sizes[v - 1] + 'pt'); + } + } + + if (/\s*\./.test(v)) + cl = v.replace(/\./g, ''); + + o[k] = cl ? {'class' : cl} : {fontSize : v}; + }); + + s.theme_advanced_font_sizes = o; + } + + 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(s.editor_css ? ed.documentBaseURI.toAbsolute(s.editor_css) : url + "/skins/" + ed.settings.skin + "/ui.css"); + + if (s.skin_variant) + DOM.loadCSS(url + "/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(e) { + 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) { + if (!c.NativeListBox) { + Event.add(n.id + '_text', 'focus', t._importClasses, t); + Event.add(n.id + '_text', 'mousedown', t._importClasses, t); + Event.add(n.id + '_open', 'focus', t._importClasses, t); + Event.add(n.id + '_open', 'mousedown', t._importClasses, t); + } else + Event.add(n.id, 'focus', 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 t = this, ed = t.editor, c, i = 0, cl = []; + + c = ed.controlManager.createListBox('fontsizeselect', {title : 'advanced.font_size', onselect : function(v) { + if (v.fontSize) + ed.execCommand('FontSize', false, v.fontSize); + else { + each(t.settings.theme_advanced_font_sizes, function(v, k) { + if (v['class']) + cl.push(v['class']); + }); + + ed.editorCommands._applyInlineStyle('span', {'class' : v['class']}, {check_classes : cl}); + } + }}); + + if (c) { + each(t.settings.theme_advanced_font_sizes, function(v, k) { + var fz = v.fontSize; + + if (fz >= 1 && fz <= 7) + fz = t.sizes[parseInt(fz) - 1] + 'pt'; + + c.add(k, v, {'style' : 'font-size:' + fz, 'class' : 'mceFontSize' + (i++) + (' ' + (v['class'] || ''))}); + }); + } + + 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; + + if (s.theme_advanced_default_foreground_color) + o.default_color = s.theme_advanced_default_foreground_color; + + 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; + + if (s.theme_advanced_default_background_color) + o.default_color = s.theme_advanced_default_background_color; + + 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; + + if (s.readonly) { + n = DOM.add(tb, 'tr'); + n = ic = DOM.add(n, 'td', {'class' : 'mceIframeContainer'}); + return ic; + } + + // 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 (v.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'] || da).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"), tabindex : "-1"}, '')); + + // 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();', tabindex : "-1"}, '')); + 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, cl, fz, fn; + + if (s.readonly) + return; + + 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 (ed.settings.convert_fonts_to_spans) { + ed.dom.getParent(n, function(n) { + if (n.nodeName === 'SPAN') { + if (!cl && n.className) + cl = n.className; + + if (!fz && n.style.fontSize) + fz = n.style.fontSize; + + if (!fn && n.style.fontFamily) + fn = n.style.fontFamily.replace(/[\"\']+/g, '').replace(/^([^,]+).*/, '$1').toLowerCase(); + } + + return false; + }); + + if (c = cm.get('fontselect')) { + c.select(function(v) { + return v.replace(/^([^,]+).*/, '$1').toLowerCase() == fn; + }); + } + + if (c = cm.get('fontsizeselect')) { + c.select(function(v) { + if (v.fontSize && v.fontSize === fz) + return true; + + if (v['class'] && v['class'] === cl) + return true; + }); + } + } else { + if (c = cm.get('fontselect')) + c.select(ed.queryCommandValue('FontName')); + + if (c = cm.get('fontsizeselect')) { + v = ed.queryCommandValue('FontSize'); + c.select(function(iv) { + return iv.fontSize == v; + }); + } + } + + 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 || n.nodeName === 'BR' || (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/include/javascript/tiny_mce/themes/advanced/image.htm b/include/javascript/tiny_mce/themes/advanced/image.htm new file mode 100644 index 00000000..bd92b004 --- /dev/null +++ b/include/javascript/tiny_mce/themes/advanced/image.htm @@ -0,0 +1,86 @@ + + + + {#advanced_dlg.image_title} + + + + + + + +
    + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + +
     
    + x +
    +
    +
    + +
    +
    + +
    + +
    + +
    +
    +
    + + diff --git a/include/javascript/tiny_mce/themes/advanced/img/colorpicker.jpg b/include/javascript/tiny_mce/themes/advanced/img/colorpicker.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b4c542d107b25f68a9d4f9d7a109d0565d1f1437 GIT binary patch literal 3189 zcmbW0dsLEX8o)utyLkf>vO+8cOg9wF%x1j+p@RkpsHC1z^8%LRB~9&2XDqEGG)XNW za}>Dv$PIyhNYo}DFE8{K%%;saJRZN^Z|nBZpzy$8e9+2Iz;a<8Kk+#d^3T1~%eX+Yocd57U@)iBS;Lz~Rksn75)5aOo z?47y!`{oCW4<9{#^7PrO*Kd~J{`T(uhu>GYz#z*%v4Hp|*ne=j0$dhWR+d&aD_mfU z{lIJKY6bDeS-VBjZPE+fQ9+fq&?sTsg&TH0!Hk!%jG`%fj}7?y8(*!UeJ1mKAkW+N+qrtJ``cfL69@8V&h4pSlYZct zdbj(JoO9O?Qsypg_fMOg z#rMbU1sg3&fUGhub|uS1yIT&?FK_29gtOKhHhq6|)$&^OfnnC|ikp{TaNez5@_lf< zVtK=Xq%zSvAMNgxI$d``m?>^#DeXGE<=1t-8%N)&Uj?N0rRmZL=i-Ck?cDEJW9D3T zQNPlr2-xo8nJClmdhOM!G zSxEgwFp>mhr9k%KF1;r^Lf?*3q*Hw)AAX54&QN>v!`Sj4coX05(}r$KJj?NGNXrKD z8NeX+XC1e{BJniG?|2&dIw0`UbHjy&?fwkwr)jCV>jFx1PkkVvaTKR0CyLX7_nCecUzMp7ZL}O4zG~}I+CyvTeU-TI-o>tMCfOfLfd}6{ zn-VTf)-(a;Sp7?!H+8zxp-X96c*~5f=$(V9wU)QI1jM{4!5`D}1JYcRmW=fTf+e4QuYi-${T5Wl!DOA;{Oo23HgADWZ0p6&DQlQq?3y&OLbGnI?ce`qz*7HE3Q&J0yE1{KY(ay2sM|HXSio`Q) zzXlFjW+UfD{LLS0Y3NDMZ+bLSxya70{JN19=17g3?)?e9FZ5ZnrErV zvc9TlZ?yq&c7k1;y1CMvfr`2*p>dU3G~uVHuoh;U3XOlsL-Hc><_FsSENHw4o(p$j zw)bdIf$wKuY_M5uY7jo7*N8)xlDq44D&RA{O83Md zUZRt!OQyD3-d!M)y58T8o^7r1;Q)?=Jbggc))teO1jnW^(b!S@M~%0?c1D#A#m!42 z6EgV^RRPY~f@L299EO4F{YM6aRn%jA0bj&VhnX{+pd%E8D?>;{UE_=;kb=g2yfqfAsCc65n7)rm9R;0fugG!a?6I`}*+F&TF6jg!YbNSM&6n z!>=Ksh-cuFCLM#PT%OLR31*# zS!FN80v&b?Q9xLl3|=v$!KrSTHPk$lOz&cBC(uMCnl~&v&7{(2O78wex~cmSOpaE& z@n0x|jdJ&(EI@;CjEQDIz&KHWb$avInqg_#umE)7H0pr@iwQbrk>en z79En`gx%hnTVYhT!J&F=6h@YKI{B>qZeoJ13eb^8$|MD$Fd|@Xz9!KyjAO3$S7A&6 zYeXZFhR=5gk`glrvDnM5U17rT-%tL9$Xkv}o|0U3PlQp{eM3$Ocx?e|u{ujx6p2chSy@+SHkN##WBa9ifCVH+`fLyi`WHu2S0Ro<$2jyxdslxi%sXK_EHhD>M5VFx3b4`Flh zIc+g;!#Pf^N9TwRp)FB8seslma>NhVnFKcGYRfSYt`m)MKVN zJFFM37S4z!if;L>jai*Z;Dx9uyz#v$-IYW1Q)7knZia`sJ-gGm3ULV6Au?R(5Si3A z5F(+LINUNU&E#}=!BCsu%B>|82L8R~_$}at>B^3wP{a$xih^b*veU}^%SvA!+$lzK zBsz66-IK>Ysg7aaQ~#J+Ae@Vb#6Xz!tXUW*GLZDfkf66tq!{&32#Rm+|vJii{`y-7cV5enl_GL(c= z{?V^}q$&*ST0{H+~kYM|3uYAs#ozCy(?T>GWX{31NhEwAXaj z$-4<~)zvKkig3>%>7H#88haoT&KLQ(p^}5wZDdLx6KuYt)#=5@obg1ET z!{g_qB0WaNtYWyPG+?L#;E<_|jLW|K#~bMh0c5F+bE?jc+QiEu*c*>0hl)mt&v;q9 zPKAu!+3dJ`Y)zlylp^0O;m9NO(KQNpN*rDyx3ok0O5&`hV>Gm_4_)o#6CnbVu%_YL zkA_EL0QME}wev(ESKLmxMjDBc)Yb-aJM+rU(|mZh4tM?0}d<^7HhJa22mwL*EptRLFpXUAn5J_@V literal 0 HcmV?d00001 diff --git a/include/javascript/tiny_mce/themes/advanced/img/icons.gif b/include/javascript/tiny_mce/themes/advanced/img/icons.gif new file mode 100644 index 0000000000000000000000000000000000000000..ccac36f54d983cc33a0a6e45134e3dabf1820367 GIT binary patch literal 11505 zcmWk!i9gei8~^N{89t8O#~h)Hkq~0;v&@+*O@yQj(Hv!LjvSe*keGW!CgiL}a>pDM zr5dTP?vYC8e*K>R;CVgI`+45)_w(30+8G}VT8Ehd-vQuY@K9sN2mk;ZpU>_zaIG-j zUDEfb_WrLZa&*Gwn`aAW44i{sefULA%qwoZFAxay+%7+uTmAm|W_~%FTff66W2&}$ z-iQA3$7VYZ&*{2^qE@oFuZvOb{ z(H(oDfAX{LskP3M9gu4f&*VpW6yL8XR8e)u*x1-FoqgZl7ySA$;(IJ~M$DdpM zJJK2b_`&Y9f~x!DFP=F&4<%Z;2U9mUH`BAPbGV+mJKMki_>1qcUK|a#3cD3@p}FA3MnU~_QC60FQvd0r z1n1bn_WoG{sjPEwZrjq>BCM&UYx0qf&h+9>GcyYg6nd{#@9zmO{x9qg>BDWD@<{0w*XWj^#Vu6=<=5{&$D{J^jXhDaqW}FDfBy16^Fzyk-@pG} zYTg=p`ZuTZkD#pV?%ltFu#lf?ICHntua?^-JjT_0h5~ad*kjK<$Td5If$v|pxhwpe z4S$cGZSQQW5o`;N_>2f0%y1!J9b4kRe97Z)^I1JTLy!MD-HPYm4rX_BvARZ|zWH0z z_gu|yRpKwSe~kC^a!h7hX8j_c&E-u$oNB0iL+rV|_3EWpSdPAXjN!eM7yka+cl|7G zPBK_*?Oj^Ge*Jp+h|8?+Wb*i&k3ZQJBr2Qpub)+az##x20QUZa0PufI0B8Xq5K?qt zGY4sC$=v~C?CSfOpt@6qLwn7G9NGO5%VX`eqxm@NY(>Xgb>l_a7ZzC6g(t1W@WB%m zyS~6Ct{KO^TORLdoT(zvFiK9Htl3%z)5jD(>D2sHr5dN}PF~Fq>wG#Qp1&iz>D+XL z!L_xeTb4S)=cSkHom-#f>@G9>3i(QV-cR{*aWOt_5E^(9A`o%eZe6*bC7yVAc|Y~$ zF?d|wpT$c7yZ0q_GQMbccZBr{Bk(%CH_n}Ehu|!vL<;iW5BE8sBY)+?KVDwRWjs>a zywsQvOG9PuOs3ADcE`3S^9$SViz(gQOl0F^Rt9OU`Q{3^!H~RXcDaIeM!|4;cD)$O z&}o&Lw1kv7?ZP(>`31Al3BVPW*Cx&XIW+7Ih0S&=+fRo_JL_QI#N;SXleefsQr_V~ z=~HJ$=XFF3WjRn(=$gC&!2xF}lm}F=T5HG#*+7LjD9=bi=Sc;thSxp95oQ%b$JqH0`<8QUBK8dSpi>pG@Uot;E`0i!*q5${Ce)|~j81Un* zJ<|?#Zr!IEvy%i5F%5iLuz$_i!A83pj21?hpE0OT=adS7T$FUE1EWH)ed&E`-?s>2 z+g)jR%guYD{ip39=f-%AI8FL{HoQHk2CnP?z_WF*1WR?1u0@=XUU{8Llu*~nvsOxb zZ$xHd@qCu0()#KkK^Zv3*kAtiJ-Bm$2)kte53ZA9M2ri*!&z-eLvetG%<)psUARKW{~}4j+}bfdWVMJ0~GYP^L;XbYpzBBU;mjPRNAv zz925yg}%3Kzp%|v-T~IxBCg4G=3G?ORH%c|GiX)-U4GpBy2J$pw$> zd@7v#KWVNFHVP^>Pgr^D_B-!)G+Dc(#US9V?1#kd12`~ahO?3|XWr<_o-P}itJ4SI z*U!1^AaZnLeu$cRbiBOaKHWPlG-tRHIX`HqoJ+_XU%|t*K+KO1+t&C=#V;3iqjW!9 z8`GNcYrjyL0*a?z)IGpOjAs@ETN&07=3uHyE0(V|#R!$sE5szfwMwWm!A>Z(pizQt zn8SD_-Hjenj)|rbmvJ(dxI&o0=57+_BaNHo^&C^9B4>HSN5M3!-QDi4l;3AMT-6c? zpdXZ*V?-p(KYL+3q9FVCRTTX+9TcR88=u{!5si&Fs$(u)_VWT-TKd#-i33|$es082 zXSe4LtpnCFyFj}>?Mgx}DB8D;GZJ!qyzeZ5pthnVg0?|xXuI{LL~D?sv^jF%2KD%Y zDnytS=-qd2N5+SG-5p=9^JA*VULN8c9+@xQoOn{8X<#Y0vi;yoGBZaW?XKEKthDdb z0@Z%I5Lf%Xs$LZD@owfP*95#|CXXnTeayve!h9u_Vl3+QRuxTx%LD-0(Wqqn@Y63# z7Sq-Y#UnZ%BKjv`h+72N3pQfCI4jV-9=gK?FSP@(+;8llDwf7TbnVVc&>_K>wu#pI z8W38%-mZit@i~ zYm|KesSA(0Df(G)HQo0=rD2<9=2UpH4jdfXQ;vhka|v?Fiz9L} zWYgk<#qr;23K~Ay*x*u$3_7*b`NUWz@<#LhGQtXj`LxISfjVCfCbWx6{-Z5}Oc_ zUpE-!ermq+NYH}60vwRW9PROcZrEWf%*geLmkQ9Y^r~`P)A9@c_L%1BY%Il8l|AHt zZR~)H(0`{_SY_WjBe0Ag9M?QRG)R|n>6!#~nT(EB!kzw9{ zTK4X6S~_TGIhPI_Ow%8jI3YApbGHxJ8y20z7H2H&t=A>4r=y2c1!s?R` zU+q^>SQFR|aBVBbyTrN3pw9X`ko|wDeve)(cEifJhHH;ul59XW6Nxmq9n^g!JZdi_ zFJz5SeE*wy!}SN&XZwqt8AoIX!}ymBEGtcc5S#CP*sN%)R)52c(5n&94USFI`+$2{ zMyf?`JW=>#O92kwbM!8^d!CjO^%LCh!;t_X_YL4%S*F~fn|c}zht8n+RvctQv{j`6 zU>KmPVq3yL%&;zCtDRf$5}Gg7e(b>O`c&I7XX zo4J3)b~&w`y6hZUmN@C(SE!pb-nlfP1F9V(%Btyk=jEPJw{vw_eFcxtj9)XV^j>dJJqGf(nW^|1XQgw+a*G^Fqlqz|E&H(Z zppmb*F1s9Z4^w!NwWUY9Pa0otJ+hkEJ?0S7Igk?_A4-ONrynw7E!FJlQz4;m zl&sNetQA1!AOLOma46WZsbSy%2%nHKa$U7(TE0y+BV5q{ha0V17G-?r8?VEVFz73)I`~KuZidU2DB9Q3~#LUa}jjDw#1a7UUrJ!`yF8VMj|9V0w9elOQt&*NdPn+TeF3n)i=u(kKCysJ{)Vz+&|eLw zZra=S6H^k&N7sn4P)qw_0+>Y=ff|W7Xc>nC!XxJ;T8@gh8PSxO*yzHH{Fs8hN|E*+B##UA^RU2g~WKpd6$^KnM)E9RI40KyC80< z(li*oZm+WE^@UejU^yCswv65rtDqegEZ1(7tRDYzPI=p2dVnMSdzA2GL|lo9YOy*u z^$nH6MBo@eBlX;MH$a6iCzY}PSeUs;X5470xv$pVZm*E7bAiDdxewAoC03+Yr~9yW zglafZ3P)#c?9z!ji|rKF;6=oDgKUCZdxKfsdceNzv@JG8L}SRBS_kcFo~AO-YTBIzSeXbv#a6<46Lr)1K6Bu-MI<18ih zRChp0JAzk(?gkgeqNC!CC60bqKYtZGOy0MXgG||m7><##|MGuWQpER=@cIwD&U4N5 zQCEHoMv4cQYDX&9f|Yzdbt+n@`jAoM(Q&xMq4P%>;pvF;vCd^cz>h+Jm9s{KG(Irs zrxfkj093XtRfxdpC75k*VZCvz=kO^R2z=QA(nrc`)U*B%sZ*Io`)~c|v3T%pmfK}x z@$aSXNxt-4d-#J6x)K-r+g{|4HtqKpz{eMI!x${)!$mnB0)mhMot8UW(25dQW@5cm zceMN{KV_U0z33?g^OBlRk4cc|<7%c{$rNzmI)ox>))m=kNYTcT@UJQ68wMi@V4xVeN4m3Lf_j{Y&-Jaqrpow4S0TD3hNo&{PCaRN`5r|Ixcrf>1 zQR#$F?pLAk?>~xaGAnk7AFTH+Uo@_|y9=}ok!jzkT3K`*d|U`-UK1Br_^;3ot4810 zq0mHtOJmAV;-Wq4`TsVnV^0BcHr9SK&rdFjRaPz*B(q#E1IEehn>ZF6!+0`iL@l^x z85Ff+BT9!0fNB?BVqS#KVy6HTk(Ig>vP*AS4e4p4 z#$YXO)+gpi#YIfR5QSCk#_G?k{UR`?&{?d5gN?^AO~rmq1=)31%A3mjnkxDl%?UEB zrKTE_<~qOThQwx;Nov(kvE=gRn?IY`@;7do-01YXaXaxwPx+0$z8eEiZ?yk}?Ezc% z@L_lTS|TKb$I4sU`S2)Gi+n0Vn+o+|Tsy`4UJ@gm+)N%K$!i*1oKB8-e(WMi6Ht0 zTgVg?b_T`Xvqf%5np1(@*?=NhAEhUz_^e$~7)2%um9W8=yP@Jij@F<=J6p$<4Lp1b z%CZsqrXBh>z)k@lYJ9DulL3x!J4Wy#^ITCce5V%`ZkGfqlEK;s;ssp5pM#Qn20-u- zMY7OUrWm#Wv+W_y%@$p!LKn)BjcKhX6fmMc(XNc!l6Z)0`|YzlaBU5mV2Teu25U>U8r>v$P!k-%J7&$Vg8%`Y8EkK!K1H8CqzH@WAzI5g=t$@Dh=L zBmu(&OdSCk!bUN1=E3AX*0nxX4(RwxOpytPZSAyrBOUz)&o#;BzN@Eq#E*00v%S!x8rUGyN3L=v(h za^R6dLQ{YYNeIz?YhtKHXA+d9LMBciig74eD%gpGjgqnD;7~b1*fa?|rq)zkbq2J^d3+MLK)A{JK2y+3J5mza6pZ(B>5oZq(kdKoe{`6y`XCbB> zRMaHOlneGdgVqGtyc%RbW5U5@VBKur`vJ(uTre0n?y^Gs8aX2xH~m&|=1Vg88$0tM z;4Yd9*pj)ne9TS`1Wi5*g`nht+01OQFQ=#H)u2>K^hGu#5JUrq_BH$m<;bBGK!jZg zh_0B!w9H}oocFh2$@jrx4o+X-EL2Q|L{APXW0CsYd3~IadcY7OdT39}&@5R5&L4v7 zJw&+OKTtuS^MZxIM`p?T-|-MASqx1;DROQ@Ek$b?UMB;(HrR(v$ZWt3Wh6vd1rOaUSU z@tB&$lcr<4%%HaWkhaf_F5#ar&j8&9U@&9JHV=LM80g0}lyNu8iUUvLw9cslyC)Jhv*_4a)y^PU12JUI)Twx5& zf+E-!&g1X!Ube_1GU6>8*2_n_;+HV(2ygPBTx0=ab`aMBG1~_t5!Oip!VpqVWQ00o zt0d9_ARI_M0eJtp!F{m${tWMefPDYjr%T9LfK3+jYkiI;brl_h#SkI)+Rd3fbn^k> zRx)_)z4G<<%Hmv9M%fGK@0Tz+S$;?7Xzp|{TfboTjoDvV8iyW!DwLOTN*En3S%queI72)*$F)i3MEdhbSpt^n*TQ|u=n zSR;r^6EWF*VC(SHZ+DQVc_PS#-am&-+5Y#P7-B>Vu=uYSS{Vz+0guht53stX#1&K0 ziXkX`3_smgSB0Kk+0T5X76?Yne8UvXR0WCXo14abmOD4I+VSO^=8JFe!S9BjzQcps z6_2CQ$KZP`d2lx&7d^BpdrgcZ3I$>ARLD(Ef1oHFk5j&80X@eBL;x|w<2#yZ1v(@Y zD++b~8FU{HeuM}LPXTurkSckRJG?idE+Dy5^e7Sjk}s0XgPi38&lsRAe%_ln?@yhN z0bqC%s7uCXPXCi#NNf!x<1aMlEY?B5UvI&|3y-{o|6PDu{uR=L(#fLgJk9kK(QIbP zcl?qG7Go&xy8+-uhOz^28)N9qq(X+H1ayz^@Im5c9<=vpZiSC_~=j2qdj;Q%h^EQSvT>oVN!oT`&z)P356 z#Z?o(VO#yskqWyhq#=ILu$ZiB`c6(emB#2g(onJRv0rs3R1R~l!A%NtF$U-0-g`^S z^^|?Z5s{z+bC>UA3`7(M#R{0(Z1d$CgVkGuth0UC|DHa2w~$fm-i79i4b~@pH{n?Q zRFsZ;CwP&owz{^SEvePuGF}jz{9|L~XylaS5qS&LvBg77*Q#fdgQ!u^ot*)qK~ZB4 z0LwzBrT&(6U#UWP`S5Y5661G55+IJ0qm?G42^HyH#}Crt*{a&+vh38<19suKJ&-Z- ztSw?U3)m&DQCdxxFkA#GbU|kGh(hdgyM1#dtIb@2vi$&aKn>VXQO{4tjqkjcEa9LS zw>CRk$CiqjYytVyPK}9kjg|5skH>O)H;F2;R3_O|v3SyGNnS)TAx(tD&@T^fF-BBo zWGwEt$9$j&PR|DZT?`j5O%sf z_WDsk3p-8X;4(9=LB^l}g7pb1p-baKp0bpJ89oN`-gGV!qoEPGZizhnD-7;h=_V}U zD#5-Yb4oBsw8FW=k5>8zNKg8#6uQ3-?ijGEYH2K z4P48n>g-bEecw~ytX#bo2G@WMW9qhi_3CsITyABn8~)T;3h&74SdM@H(I~^r_k&84 zdWK-FpcB{h;ay8n_D3a|+wH0ucKSbnOhm-C)^$7Ca#BTfMz5*}F^z4SMf`@xi716e z1Qomatpl0zI;kg3>W17T`)NH2i0scu*(kFRM$l@^l&epEwMUKAPHc)iW28*a$t^_k z_ubVQg(#v9BWtf{a^dcJt}WbQioEyJ&PE=@YT z7&j@>_f}KPT$5>?x#LSk;Mo3}Z8h*?@5?Lz`mRIM(YH)vMPy6C>iC6kC%s<%*;Z&S zNPOR}doStF1y}nOg_nZMX;i0umZ`#PRMcaGBEyG4qB)d#+#AnE(*#}nFxf#E6fZD< zaBzTjkb_)9cj|u1plAczTA0qW(pwyK6S*W+SCb0MC-WrkEEa=0ye6fPYValbz9=cZ zIbteA7|*nk4B{b`&RL4atV6Nq@EsXzPRRaukJKw>mda8bF#p*J=Wd zw#@RUq{)B|9EDe7trMMG>0kmzTQpU=^Y<%sD>&R|IHyBhVG3 zYpMM}OX#l&34R{kM`}kaa-b(1Puc0kTLH~*TiA_&`dvAC6Dd-8wvGiSchgS56j%}Z zR)h6AT@tqfbEiVIBpHzSH%$&s?q%Za5V%@_hEl-5?vzNA;{iXwoysT7#g$RH+8LnbZ`n$B2<3bLHTj&XBg_OpbcmdTZhd|I)wP(9RD(=IpD!ZV&|Cb2x~QOTj(bl-RAWwJj(0 zk{I_zxoy;wkwMNqPat-d?e&M4^~QX^#fwy!3TYmusSU(?GLFO#75#N0XGqOKh|sJI zpan-obAa-bizF#eZMrmOP{;~|sfCV#j+;3~deWoFh8J`7 zjtgBu04vQxJ43&%UhRZugo%;q(iObJM~2HJL&5)yMeGfl$vOVWS$V=nUumMU%?viR zf*{a4;JV^I8+@N-Cug-nwe!0U`b=qPUzgGgUsE}yTI{W_|Ri`V1agbLEY}8hOca;;XMXvMjHk;QD7|@w%sX zoCR`qr~rrXwsYSK_YMJq*s_8g!6OVm079yyS8fGRDHI6iee#12T)_qER5C=2D!zMR zxg(N23!o7@Tf&vTN^X#~4Oh0w8Hj1a22x+*fEP0+Fkz3Vo0s@!kH-OtT@N6am&3rL@;-F=_a zOB^#!!Wcs@6!eC!K2!<)q+Sz}1%i4w0`^2M>ERLb{tDLv|DkwsSLR$Xy1xba=YD3! zMQGVbb{;%|PKam}^6iw=gPmg0q)5unFqV)a%lQl4`C41)B0+SSaJ=*q0Mr@WM;v~J zMp1G^x37Ar-!0P?eTBQMZ=R7V->42q6JbIvenZXIfsrAIBL1NHmi6v!sBJ)MhPqAB z7s-HTiOV@uBO*NanuG#lIQz!1*1=&5?6BqD;WGZPO~A07)Ppis>dS)6tNm#ZzDYyJ z!DniX9;^o*9J(JVQwiv!`OrnkI=bP&o-DxE@+R7$&&RCy_*PnDj)@H!s>eZUaWVqA zCh~<+PG!B}J#?k)3@Lu~t;uwyMTi)F$L;wHB%i90X1a%>y9bYoB|&yg^rvvuL?}BP z8T6yGfFCfBM@Tz`GrJ`}rb9H_Nzg-AV~FIe46^!u2Rvny9%Yg#&KnSRh6{AmX?k3! znlb%JsgUiq`gAbd0aquPbf?VNGT&j)-QRL~f0}bmU2XzY9S|@1fViS4ban6DQ1+#n za-l6Dr|RG186-@j54F>DVgm1U)4}N`3-gMJeWh)lfroam_4(=ucN}fwG`chw&c;rb z)j5KC(7P1miA3aftVN_1{l`4bXg};okA=zny`Dt#I#~mANlwakM+&+#MYfZMM_cb9 z9KHp)z(pxgQ|o;&F$@Bl$r%elpEohMAA-KiMb*#$b50O$)|k6wKo$>0Wua!wFtSVBj-KBg3#{-90^!*ma0BgBHTH_XDKyT;O*iM2-u{ zZSRmP6{7APkO!&GAXIf7y3@yuZi5N;9ZShF%OJ4PIb)Yv#>!-2TE=t?RY@P9PS#~x z{-o2iH5NP%KgLcz$vwQ8lyjNg{^G`Xp2NdOkq?j7JN@n0S&hc{IAseNi^Js}d#rfz zaE}pqZ@8~h11S2wUpC*Z>Ejpl>D`*pStr?DligWx+uq7-ueQ#|`+wzh`2bML zWKZ$_-yP0=LzA^!=V=9w^{>f)%pUlS(&m<@kQ%M86%dl3w!r|(B~=QSIckIXSKEyG zsivl>JSH5?qzf_#a3}}S%=F1QiPqyF^3r?G{_*zghn?XfeM%0Oj*p$!r1@5O>zU*1d|lQyVkBgThFKSy^Q;KIE8vu^BlGWchJX6kLjZMo1N zIsOu*&-(5>8+iV#CEUL={n_B5XWb`f`1MPhtvNC?`c6t)Y!*WWB13qX&O zA*u+dE&(xnh8m6=8D-hZhRB-?}my%l6l4njN+KB|${znl2Kzn_0e4FlFnoirMTbV!$zM`Y<94fM1 zT3WdqNTI(-O7laA%gXw~%$JJup0sQ~VxnoJdX~07kakEsB)w4dFE8}@Js}b`NH)X3 zftJCm52(R@>d=G=S)6%2akIrq=uIm5k9W+2l|Z)UHjUmD0LUa{{D@8Kfj34?ShR9F zN{;!aU4UM|!$u-qOwlW;<>k!~OaCm?UMGNo@cnZp3t(T-6%7uMeI-cABIQ%ySIw4S ztZA*v;8WvtLomO}Dq}00=E7`JGDfI`!!cQD7twGNjz=3Q>kq*2sNQ{}dH0(i(<*cS z#sP-)Jk2?a%5Dy+TZ9;~QsY`7Ymc%qY=l2yRiNfy$Axqs_BZnJ*Ni-=LOD5FNV`c; zd9}TFtNry2&TIdS*EG`Wq59V?;G6E9Z}PUO^4nB|AI^t)r0;Z|#gkG?&$Hxj!J|T`;fu7W}~(~Y%X z5J*}3sPkmy@YheFb<7vZF6$p`F&f%t+CB8>7NV%bYr*E>F{C3sz0=eAP}a9c3-H*N zhG|r5Y8srCtFB!a=XO=n`cVey72;y>nXFgvi+ZQ7JF54*RW?UojSs$<1U0_$O7n5{ z@txUt@?EtJ1b7izr?WCnd{-CvZdIW?-#thToi1$`p+yVIr&8rAS7h9%3g&2avL;*6 zxnlb5^0Rkc$rjt{R5hgd&~}-+FY8Z^xk)7!#ZEOP6VRTEo(_n;4Ol0%|Ge`HviGaC zIN*ZzhZH9K;TlY{&nv9?ZLW|%^Umq1$Jr`Os;OwcWH=1tW7Vonvm*_s9LY|qbZRE1 z3NNlt@MsMW7-eg)Bh!(!r>NB$6J?x_%kg^!FR!S~|8!hIzDePItX{yplAfqFR#-}F zeUg?=w89)MJ^SwFr?=A>igDP-7oWzTqqVkS{1N1aa@5||=gQDF{9%Ya@A)_jdGRdV z=uhUp(wbcp9>1nNBA%oD)(L(N*`DE7?2nld0D93{8si~m2h%ez^!Pp20PC%AmodNA z0YKxmpB*{;B>C{7)M2LPy@ksYS1Kb#x<80E?i?MBz*nLDagn-i44 zy)!ZUMq|F|Z*p#LW}Qk?8G~b(RF~~k!K*r~_%?OEGUmy}GdNW2!Kzpjqw=NZgBjbv zb5^XmQF+8Rb^BASNyCEE1+-<=C2xmww#T<@?s@4}y?SS`InF-4l)NF`y(QO%b!ps? zZo|sBtkH-ctySXOb>loNzPju7q*=##N5vgYiSx;i^R0^WYm4*07Z)%SckE?c;ODsG zf;f^`e2_}~3ElW$i}(=N_>;%uL!;uuQsTq&<4;w^N3_MCz84=k6MyDq{Mpa(QCGj# z7rs}2n=bn+KGx#=IoI=X$Ir({oj+&~L|aH4rx~IavBYYX#2Vei zT8qRw*Tj0)Z-r5bMOAm|^Anq@5}Pv^Pu@$OLj9xyfa(7Lzyl0e literal 0 HcmV?d00001 diff --git a/include/javascript/tiny_mce/themes/advanced/js/about.js b/include/javascript/tiny_mce/themes/advanced/js/about.js new file mode 100644 index 00000000..7fc8ba2a --- /dev/null +++ b/include/javascript/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/include/javascript/tiny_mce/themes/advanced/js/anchor.js b/include/javascript/tiny_mce/themes/advanced/js/anchor.js new file mode 100644 index 00000000..76f4f7dd --- /dev/null +++ b/include/javascript/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/include/javascript/tiny_mce/themes/advanced/js/charmap.js b/include/javascript/tiny_mce/themes/advanced/js/charmap.js new file mode 100644 index 00000000..d9fd8d32 --- /dev/null +++ b/include/javascript/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/include/javascript/tiny_mce/themes/advanced/js/color_picker.js b/include/javascript/tiny_mce/themes/advanced/js/color_picker.js new file mode 100644 index 00000000..c1a65db2 --- /dev/null +++ b/include/javascript/tiny_mce/themes/advanced/js/color_picker.js @@ -0,0 +1,253 @@ +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/include/javascript/tiny_mce/themes/advanced/js/link.js b/include/javascript/tiny_mce/themes/advanced/js/link.js new file mode 100644 index 00000000..c8cb642a --- /dev/null +++ b/include/javascript/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/include/javascript/tiny_mce/themes/advanced/js/source_editor.js b/include/javascript/tiny_mce/themes/advanced/js/source_editor.js new file mode 100644 index 00000000..a6235a38 --- /dev/null +++ b/include/javascript/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/include/javascript/tiny_mce/themes/advanced/langs/en.js b/include/javascript/tiny_mce/themes/advanced/langs/en.js new file mode 100644 index 00000000..52989e39 --- /dev/null +++ b/include/javascript/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/include/javascript/tiny_mce/themes/advanced/langs/en_dlg.js b/include/javascript/tiny_mce/themes/advanced/langs/en_dlg.js new file mode 100644 index 00000000..80e49419 --- /dev/null +++ b/include/javascript/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/include/javascript/tiny_mce/themes/advanced/link.htm b/include/javascript/tiny_mce/themes/advanced/link.htm new file mode 100644 index 00000000..b647eed4 --- /dev/null +++ b/include/javascript/tiny_mce/themes/advanced/link.htm @@ -0,0 +1,64 @@ + + + + {#advanced_dlg.link_title} + + + + + + + + +
    + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + +
    + + + + +
     
    +
    +
    + +
    +
    + +
    + +
    + +
    +
    +
    + + diff --git a/include/javascript/tiny_mce/themes/advanced/skins/default/content.css b/include/javascript/tiny_mce/themes/advanced/skins/default/content.css new file mode 100644 index 00000000..cb7604e7 --- /dev/null +++ b/include/javascript/tiny_mce/themes/advanced/skins/default/content.css @@ -0,0 +1,32 @@ +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(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} +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} + +/* 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/include/javascript/tiny_mce/themes/advanced/skins/default/dialog.css b/include/javascript/tiny_mce/themes/advanced/skins/default/dialog.css new file mode 100644 index 00000000..8b21c026 --- /dev/null +++ b/include/javascript/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; opacity:0.3; -ms-filter:'alpha(opacity=30)'; filter: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/include/javascript/tiny_mce/themes/advanced/skins/default/img/buttons.png b/include/javascript/tiny_mce/themes/advanced/skins/default/img/buttons.png new file mode 100644 index 0000000000000000000000000000000000000000..7dd58418ba7cfe58ae7efdf174e0b223fe3aa6a0 GIT binary patch literal 3274 zcmV;*3^ntKP)vhvWz=ElHVTU+(h$oTm7rnFw= z#lG_L@z>Yab%+@B(Z}@j@}#p|h#d-Ha21r3lI-j0?ajsc`T6PS=IZI^?Ca|2$-?Z+ z#H%L@czAgD`1gZ@gX+q{=f}bK_x5aTZ1(o``1trpNJ!-4;q&tH-P_pe%f#ZsyXeTl z;^5vYDk=vD2k`Ll^6~KO%foAHYuvlE`uh6h#J%Up!SnO-^YZcM$G_phy57FF>B_@2 zG&J}3_vhy1;NIKl=jBRDN&x`@?dHyV<$1d3kwydU{JsOZD~j?##m9zqnmp zU4)q(-rU*i>gdkR%iP-6>Bzt4<>Tby;C6O)g+u7Fi^Yd9*S@7=d<>TRzqB->R^6~NS=;q{L zU|{$5_HJ%&j-5pI_VnZ97cymWMQsi>#$@a~zJm+b24>*?s`Kw_>-YEd@9ysC=jQ6jz~|-U_V)Jf?d;9X z&BMdN$uR=*^77r?-S6-3%uUYo000UBNklbM`ydMEin*+}whKg169D1bTAel#7r%w?GyUy@b*pMzXSyzY?h@ z3-N}8g51;~G~P<{m+Z|*(~X5P1-aeb(_^{eT^B}ch?tY zrBh#z)8LR*SPxv0!r@BdYYB7ULp;eMaut}B_J#FVuVkeMSfGbo7?foJiWR%d&AM{+ zs^x08)P*FXmS8r^_C58*7PqCixUdj?MS6NHS?Eksi!D8XyhZr=Ul1r3RCu*V{soi3 zzJ^?Tvstfq>vehyT!DW8#RRvmM-f(7XmRUwdY!u(w$X#+dUw5Iw6NIiz9Kb&!jyfs zz7wIdNc;t;*LCX96)%>lcXukOE>3f|baq;ZjG(Zu)>R>@_lO)o=&L%#B#GkczAA~% zJ;h4u>#M7(4qz2p-+=>`?3BIRtq%iL?xv=uYQ!E$>I_#&Nz$GyO&+B4c*3Gp3X9(3 zL1Jlz)e3vPUgz-w9vz_+(dP}js|kB#^j=K3^ni>w0`h8!(x#?9g}qC!cX=BCuM6&( zm{HZxpeuFbq|$0R$Ae@IeR~u%VLT0CqICm0PlIHiXU^_(xm;m9ufe020DG5mHvqWk zv8uF52_Ex?yhN-=D+`4b_He8EJfV;`4BcMHBKDz>m?ehj(7M1T6bhHhxbb3vhLBf} z9#$(b1<%2aSe0yhH{@9U)I&%AWYc zIPAg;vm2`V`mnv%C6P*i?he;)tN|CS4xL=c0F1H~_U7zAY%|$rv%=n-z1^6le`)u{ z*YKg5npCT%<`6pW+f3fp-AGO5i6%8Q_rbns?(Gjhd^-bx>l`XX=5}O=IaG*bwv76? zaniYw5uB5aA5)Fa?>_}jyz}mUk-uY3yhAwr!JRvQ6WP1>uUjLl_ha3iJ0Bo^bT(3x z7shViUd;fvZ=bv{NjcZYe!3W2THIdm#iiKApH8kjsg28H7e9%Wmv?oQ%M>AeU0sQy zqVhx+;KMzQTOkP=!J(@tMeLJ{CogYM8|!1Sn9o;6(`6+}%AqHLvdS15u$HTVqTf<( zC4o%FO%i@{>j<}Qaa>DK_yY38EQ4X%z$FDGltFX@PM5-W%5-&YXdpW@-~q5_&i|GNqZ~+av^y0n>~v!INtH&lx1Wh1SQibqf3B52jwA zjZ&#LRET@3d*jjGHV8YzLKN8($JME3AND@PQnp20B^V;tx-WWXLCoUijgQ|`DeQwm z?d(xt7Vcj1(W6HcLO41@sR%D$YD7#&F*8)1j5xA<^r5I$or2lC!v2BD6us^MW};dk ziCK1hrNueasZ-KKjplzy<`6Ur$k43g%Tq-DD4EoL?NHc%6pco|9108#4LzPk&qNS~ z@IymU5|pGwz$FNxA&0ar0v@vs%@FZFwc6#ch60lPrPZA8zFQV%Ba!Q$2jCz?AD{>m zABo%u27~f$#FXoiNTioa2Ms=s%z!aWFqu9F$&75jxYE{k<3?K~{tMssI3ADuf;JP4 z^6_{t&ItyUDPPCq@sE<}z@RA-p9y05jX*pem=#tQMf;`syXaAiOwI5-e>6Td^_UkR zVfopVjqHO&pbPeEGRaR(Ju{`8e?{Fe8htkP5OfcsHZZu(FW;SCB7e1)VzJe`-~MS^ z`S$K=EQakbUxL@k{7TNYvN8{^lNazhajyS(k}%djNZ!ZSjt{oC501Tn!wJH>z+uAs z*P#3G`Ja68Ud1PYo)nG&HZjU$oynf$VXWmLfl4;LhW7;=BP>X*f$Q?+>3y zm6jmg29B0i2HM2L?pADHyD$O!GO&h3IxI^|O#`aZI25KttkOis1efk`Zb7u4IESjV z4GwmPfid_p&J9l1GOSaja&pS)3G6@e;EDw5## zNmZJ(A5x{!DLc>`uo9qQq30%Q$+e$2XEbV!Mk8BEAO(yeX`~ckG*oGzF(xS|s?tzX z%ciO{SeVhsiAp?Owtw%KkyL4{1iE9DT0xu2LTswiQqfSQv4X&28CfHD>^<3DrR5Qn zM&rb#1uB*H2Qg`m?Z6qRrzi3 zK~m{Taw4qO??+<1JSSX0g+08D{Wid_tT+UljgqS;38RfbrBcNa-eyay(q#K%1L#KK z>dR(KRcXA#u|<{Ue^Zs_ci2wJRgc#17&s=|3t(>xARK=DOyDXl5HN18(zIB$Rh1U7 z$wd$E2n1yNBLnDG`R#UxEdU3Uh2ZUW9_OT2X%4&H?%$$HbJ%S}4J)jEB<5wG8q|kKzxu41Cw-5|H{*E`4`XOxxoD9Y}F^Z SLTQbO*E^TJI;F+RU=09Vu@yA{ literal 0 HcmV?d00001 diff --git a/include/javascript/tiny_mce/themes/advanced/skins/default/img/menu_check.gif b/include/javascript/tiny_mce/themes/advanced/skins/default/img/menu_check.gif new file mode 100644 index 0000000000000000000000000000000000000000..adfdddccd7cac62a17d68873fa53c248bff8351a GIT binary patch literal 70 zcmZ?wbhEHb6k!lyXkcUjg8%>jEB<5wG8q|kKzxu41Cwk||H{*E`4`XG(j;}D)%x|1 U%)82UlRJ8EoZ9xTT7&iJhvXcHF*h)T1OnEW1i^?zgDfop1p?usL*#PMGT;HQkSO{q6FlJyb$PWkPf|h*eTST}7h8z$}MF(XD(aQ)ZLZ zM?v0rT<1C4XHn<6PbNA{XL@>1^)apdD_@tcYDrW#m`k#MmslI7p^P;Az74wGs`!SI zLs$GEZHsafXsu1i-WleMzAL(yw$-LK{0hv;6hrx8kx!!4$``dAyBnY9Jz&DqJo2$A z!(L$H=KqBeY~CF_viHPz^tTglc?D97CqEBjzUwH}7GI zapg8YZM~>2Wk%E$d&r@9ly9b4Q zJpM7T@}r63I(OExUlG%Xcjz3MU+9U^r!SkpjNThDtaP)7>j6L5z%o5|^hlVOyI*uY zt^UU6NTuY?(Lb4ZIU2Zb5Vz}Pb7KF%ivf&j^CL>$cDz?rMNTQQ|NqDVD7mhghUp%h zhIA{gi{S8y9YhIIbSv$`B!JiPi!0#4#Jge0)p&YVPHchWcyAn zQhvb8ggXGXs9;k`u9Uq*YB>O+Q3Rq=2hlLFcG{Q3ORH_}JnY8C+r%@}6|%ySP%bWG zV~mA;?P`Q2L_Ss})nrJ{$TmeA9Tt*4=}X5x%RioM@_?ZsKSEST-f+GBv~Ya)xX3O{ z8!d=YthI-13OI;RN~`>|6u5L{z20oBp%9MIj)n$!Aw{Wpq&Rtr4~*_74Gjo@3el>B zz(Rk;;>2lp73<2;d=r*8z%WkdsG=vRuG_fvxO#uN^El|+5Qoz^X!2MfxJ3m}vyi?> zMLLDi8+${Z6YbUg?8GNR>-+SwHKdFyr%HqWcs|X_l*-DAC^bG&KCqWg7-_`UlwQ`EdOp_LJkr`L$mHHs75uP?fSgVfsDjuE#ft2b8HDt0yFt!+;C zEgL=)G9ZFt4wa+N3Xg7FGc0~`&EEt6_%7tyzmnb9B_h1~7~GD4V-Bhx7~QKRkF>&aT>(-!Us@aJxAY@8E?HW$G8g zSz@7Jcp>iCp;lU1ieF6n7!oAa-1E!rS0 zF1lBFVS%G#ZO}b@*+bIk+7@Q|iG60vIDVpV%4tW8rKyzwRo_<25;8*Ky@n z-sX>W*b;M){5lB_Edc@m1`VHy0@dg$PTR9uE$O2&a?KAe?xRlCj&Z$iZYw>o1FUl`^eGF(ALoK@apvR@ALES^78HR@$B&M>-P5Y_4V=e^zifZ@AC5Q z@$v2U_Ve}i^85Sw`1tnr_VoSz{QUg;`uh3!`1kSe-|p?^>+0k0?&$36oE*q;kn@I-k&}bV{vSuh^^>3n?4| z;IMd1E}PHjw0g~MyWjA*d`_>=7l@jE&+q&HfPsR8goTEOh>41ejE#(BTJr4xw7TUm@OOFuz`c;&!9t#9!C>oFt6t5zwd>cgW6Pc$+rZ!o zxO3~?&AYen-@tNG7S|k~SJ3z>`o$Ddm(@N@>THSZ1l^mRxq}B^ypwDdw0~ zere{JXr`&=nrnnf=9^WrDd(JY)@f%NZo;W2ly~;&=bwOLndhE*25RV`h$b4qpoG4u z=%bKEiYB9tjw$J-m}V*mrIp61>8GHE8V0AGPATfCs76X^sZplt>Z^dR%IcG_)@rMq zvd((zuDp7gE33T*D{LLV&T8zj$R?}ovdlK?EUU#nEA6z@R%`9G*b0Edw%m5>?YH2D zEAF`DmTT_0=%%ax?z-%@>+ZYox~sqgCd6y+z4+#<@4o!@>u8O)@dg`oiyn5@f zOZ$w(NTg$xb9CJ6RgW7L9%1w;9GT zXhuesF~cnPJD=ab@q68~Jm-C%bKmdxIp;agd2Y%BGXpO6bL;>Ba2XluThcXz&bq9O zbcta`lj(}h&(Q7#0C1f7j~RgckHP@JZtkt8_uzq-Z=mlBFJC_iBRxF{zW`qk?|cu3v(}90mV#!^Y9bbb>P7@!1+ql<}?sp zNXiRm0PHg*1sRId0f{s2$@+lT9iV#r;p@8q2kUJL=^^8kT+`?l(PvbDThGW1C0HK@a+)b7UEvtILOv9*;y zFFj^-R#rg8<&;alw*0TqJQ1ZBWuDc85dbJo7o^|zfEqH!T{||Wk_zQ^x`zA73|??` zU8ik~SNUlJ06H*ok|w9ncrN-5bF>ewoG@h5b=#i1CRC(pcuPkd*Jt9Z0>%3 z4_jQ^z+e`PdvxtxhHN8fp1+*BY^nbqN2*hZgw@V9sTd{47y~BK>aUT*`=w&zAK2nu zk(+4-lx7Z)B0hbg$H)~1kr7z8;P+3}&wqQMRC*yr_rulROH-iR8cL4LsEN7>e1EFR z5T1Um-0=zHk;xTaNMP3*5dikve7k3)SsA0f;?U#4;I0_7sh5Cg~Dz=&cb_wCsWUA6tclC0LG zEr*^Oi)`?2C~q*k=PK#ge95<5F8^%JcQfsgZp~+?Wt~M*`5EP)e6`UyAtRI0nv$&P zb6#h?h~9O-16%o)v(B64OxR8hV-0@i{AN51=HyBgjO$PKlolxvW)b!j2^Ox)z5h*Q z`i)4x^>tOn?cA+Ao;+V0hzwNbm0Gm}n?0B7M;BkclxfSQinqPdsI2&`rgy{mhHazeL8gZm%X+Rq>0_W7 z+m>`$&Ozks6@lHWYga|TDc^@Fx;s3p%+AS%R2f!TR2gh{sMPM16@Kfu+h#|O;nwLl zzT$Ajz%y;^bm5lOqSbO4dzp}_#%)5aeC4xJ(a&xA!9Smu;d6^RA4eD6_bpoq?btdI zi%_6iQ+-a#2nL)G=0;8_W(4P$uzK%Je_wTRg?_}Ig`Oi^Td&k5%OwXLpAMT;|1x{; z-94VS-hB@1QtLi_K7C&K>Z&*t7*I6k8zBce6p9aV#cD`}CtO8k*{ zNf!hynujG$?#A`+L9%f?|JR#$};|n*|p=XA#_IMXs6-*m=p7n&ih&xDrlVTD( zET5w(Um)7IJkWtL4kY+HqQj;Lg$0cTzjn$Ib$AuLH$DmZX+-(c)grqaFDBpvdaD*2 zlUf{~vaUZvRY#iZna6nk*t)3jL?PX_X8wC~X>cXcW%sP+k!HZBbK zshD#!coM1i0;PYVpRK=A;HhY?R(H+#ri^B#{8RNM)mG(Jtv-1VyOCK)A;jok6EQV; znOc?S|8}A%I|oT?g=-w^;b(Id1|0oDKac%7Oehnokmr}XovnR8+3Z&4UmaeVa-p}E z_Rj=gN@WlICH~9vg2JTAWb%TZgUoreeM1@3un&LI+i!+S_1-9z+knMisd(RhpX>f| z!R;cU{Ff3wN*cF26yrXmzxUUzlr+tNdg44cJzfr1yC*czdY`{(Ryd!j3;z2!Aj#%I>NYR5LGHnQV#nCY{a$K6A*-9H$fZFAVL zZzM!)BjoMz2HX=6?wQ5r;v7~IW zk7JFQkN-|T;}j#6AtAU4j}w%F#^-FEW91>)3c8Pn$dZ6Dk6Yhe!0VEC|(AK@NEtZ0$y*z#dV=$;Tb zH(R8pvD|SG=1c4)5>P_RkpWkzW5aEW!B_A#?dI)HhuS+ji+amRvs(5vSH%?0@r19vTPRmOhPUK45F1n?urnaUPK*dtZ^v2!BFBhGqmC%N3&k89- zl4iH($0l7bRZ7KmZHv?)`hNAD?;H%dq4@alA$g}e7#S?S`vt{gj(H^! zB@KEV*AuKJ%E%ca85tlGW9|Xv$&G6W`n<{Hsbi`G0QIS_$QBuNTjGhKr6~Y}T>^mU zH~=^X=^6_FLDvBQ=L`V1a{=J2?+2&edjP-)Jh*Rtm+k|CAYv?U2)S3+gNn<9$7R6d zGkfAQ;RVgB#qF4^y4m8kwd}f?mf@`h3}F>}^f03SQ`_37Hgs|OT5;P-_YA&s64x<- zZ6E&)pWFR4i|?M<>72lJPygwi|2u>vOrVLQ%lnh7hqLQPOIyc_o5XnxVHrn8Voy-p z*ZAwRXP6t}N@YFlm^TnWt~D zGk`egUHCh^a@4o@w|8N86m>MZvOk78nA;%DVu(}d!#T{+_%eQdm$rtdqIW3hKPQ-7 z%J9nJ0AjCyiSBqXh};`q-XB8Xr`8T9(FYT#-Ld7JQRJU_%)!zY0rQuJ+9nMk@I%Pm z$u;`P_g1iU-Yp4LshY z{pXGcCyc-;Q*hE0oH7F^&A{o0;H)!k)(xC<2j@J%`KRF0ODgIexb~ikP6O96spw4V zS|*6e1vfs@Ha^idiovbYV@%n}MmdOUIQiW`#x6U{V|)6?$Gq4y1zO(T6B>yV|) z`6vfbPw}q3+Oli9k0Kx~j)O))3{gIfkmt2Ggmp^zqNV~Ix}Bb6FmL*P46|cnJO3_L zK&ntl)wtFUh1IpIh1yO3Mmga3zrqe$dFs>$Wuw|d zAM*qgBkJ|a=24a7v)G0p*oi|#t)_k1G&Vq1R(4zSWbIvtjNsvp?9_+OW&bznC8?G~ z`>U@@q`iG4a5!8tCy4>p=0ZC2;3}z>xq{r&oS&GOhzO98l_k1$5eLQN&_un`)%ltE z`FSZP!p*fuz5^9i)x(3)e6Y0czbwU;e*UHrrV$z!eogIazrf*Sz<((I!ZZm1ri)T3 z60EWBrBdi5!J4ufj>}A4OGb)crwEk`Amb%iL*u24;`I&rbqtww4AraVJP=t7QTq6d z>y*poqR#v}l}3C9sS;8tyHA^D@ng}bOTj=Qit{wwVBjggj((N^&w7zu!Bi?rGPq2| z;jQR{IEK-F|2T$T3&z)Lw>pD!b|5~N->%=H_h>P5^17g)AOiqM%gD$WcYkW-LL|8e zC%PnkpLb3A9znj&i70S?X1$=8=wb>)U*-%45;-_HyaB)w0)epZEJUxhFc|oY-7IeD zcGmW1Yz@w-namFDJ57gaaYb?Qs=P21A}4fiLg-DeYs_K^`(YJfdUCnlAER#tFZ>_a$BB99{ContEgmwxirsvI>X=!^5T?R>zTY!*gEY z?#v$*h);#T6+16v`qF3ak z={=Z8t;w7w2ERn97HO>ooYkViN0~zj2fl98uF^MPEaIB(7uwbusz zWn#>5-vr}sCLIhP3tOy2GJi?@Ekj;?HXR7PDwS57OQ+6%3yY{Vs~aAj!!{CNux4D) z;$m1K?QU;_l@1DjUp7eKd2<_z>h}||gWnBq`-y)^Y$GoZ{q^j;aM~PO_$kr28z0HD z?jroHxg!VbPET|0%S4OBf;$;ERm-}aGUHYw`=-Z2)OU&=f6MXq6z*GhQ9mz8YMN1X zA$2PZXynHJ^IR>G($dlUycyvgZo;wb+T7fWhm?nCmxHOjL%Q%Bu zOK(rFjt}Yh`CdOXlont=9hb%w*X=AV%+9PQDM<3K;1+&PYj?QOwElp;mJmC5Q-Cu; z_j9olaxZtLLYY(*z>8E>q2uLahjEinHmgPzzFu(iu#W2aZ97xl03at>J=w%BI-jLfSG(1)qZm4EQ@^MeoM-{P7PPn*+hB6S1 z$6~RD-3$-s+N*89cF6q2kVv<3}ah#beYOWC@IP(&*Fr{z^Yi3P$4r(ZGr z)LJF7oQl!zI{TMQ(fsKo!tIoeOG1zRGaRJrhbmuC^H&Rg9vB#CEfRTR*&u7{OoEkR zisJ4~`?qx@K&Ov{mR2rkWD{lJJP~%dl_vXhPp>GK^6)dI=NKe!Y;5r9KQ2;wbv^6o zx~UXDXe31|FqG;sSD^m@>ETfDG?r~%54#7pMLIsno7!iB*^92MAdyRSUZKnXfTWvC zmN5l+Zdc5_;G)~x+w*ht^L0KBh!$vPeSIgLKQl*};uL*IDC3GQE7XVlnZ)^r^K*2f z)wjw-LL43K?QLT2Z0OJ&eL~W=LL>KN#t+`8kAv^FLW{O$SADOL$LgBUAr8DuI?13F zZ~WG2$@6E|bSa@(lZRFnPAdXpX&kx^yzwD8gVUM{gcm-y*j~Sp=vj}I=&@NHi=o#M zz{qI+6h3S+Y(gjcGf4Z<-c$`;k6}0mXrlzg?Cnx|AG$`R^}5z)Wi1%XK^yq3j@M1O zxw)sJ&x?s2dc$q$M+xY{hKhXJvDP!VSq^+7 zK&?R^^LjkaF&C#6}U3!=r%%BB}_0cs!R4XTDW0&iQR%Q6@v0$p`QJ2%{H zgKg&rYinyWmanw^A6i?jSCcxWg6dT6^XeP1(R-DC3dvVF-5`_qzXBjm0c$D&qniSn R!Sp}^Mt9BhYjvGt{|88cricIl literal 0 HcmV?d00001 diff --git a/include/javascript/tiny_mce/themes/advanced/skins/o2k7/img/button_bg_black.png b/include/javascript/tiny_mce/themes/advanced/skins/o2k7/img/button_bg_black.png new file mode 100644 index 0000000000000000000000000000000000000000..8996c7493e8a58c9c40845cbe8abdc3e6730716d GIT binary patch literal 3736 zcmV;J4rlR+P)KLZ*U+IBfRsybQWXdwQbLP>6pAqfylh#{fb6;Z(vMMVS~$e@S=j*ftg6;Uhf59&ghTmgWD0l;*T zI709Y^p6lP1rIRMx#05C~cW=H_Aw*bJ-5DT&Z2n+x)QHX^p z00esgV8|mQcmRZ%02D^@S3L16t`O%c004NIvOKvYIYoh62rY33S640`D9%Y2D-rV&neh&#Q1i z007~1e$oCcFS8neI|hJl{-P!B1ZZ9hpmq0)X0i`JwE&>$+E?>%_LC6RbVIkUx0b+_+BaR3cnT7Zv!AJxW zizFb)h!jyGOOZ85F;a?DAXP{m@;!0_IfqH8(HlgRxt7s3}k3K`kFu>>-2Q$QMFfPW!La{h336o>X zu_CMttHv6zR;&ZNiS=X8v3CR#fknUxHUxJ0uoBa_M6WNWeqIg~6QE69c9o#eyhGvpiOA@W-aonk<7r1(?fC{oI5N*U!4 zfg=2N-7=cNnjjOr{yriy6mMFgG#l znCF=fnQv8CDz++o6_Lscl}eQ+l^ZHARH>?_s@|##Rr6KLRFA1%Q+=*RRWnoLsR`7U zt5vFIcfW3@?wFpwUVxrVZ>QdQz32KIeJ}k~{cZZE^+ya? z2D1z#2HOnI7(B%_ac?{wFUQ;QQA1tBKtrWrm0_3Rgps+?Jfqb{jYbcQX~taRB;#$y zZN{S}1|}gUOHJxc?wV3fxuz+mJ4`!F$IZ;mqRrNsHJd##*D~ju=bP7?-?v~|cv>vB zsJ6IeNwVZxrdjT`yl#bBIa#GxRa#xMMy;K#CDyyGyQdMSxlWT#tDe?p!?5wT$+oGt z8L;Kp2HUQ-ZMJ=3XJQv;x5ci*?vuTfeY$;({XGW_huIFR9a(?@3)XSs8O^N5RyOM=TTmp(3=8^+zpz2r)C z^>JO{deZfso3oq3?Wo(Y?l$ge?uXo;%ru`Vo>?<<(8I_>;8Eq#KMS9gFl*neeosSB zfoHYnBQIkwkyowPu(zdms`p{<7e4kra-ZWq<2*OsGTvEV%s0Td$hXT+!*8Bnh2KMe zBmZRodjHV?r+_5^X9J0WL4jKW`}lf%A-|44I@@LTvf1rHjG(ze6+w@Jt%Bvjts!X0 z?2xS?_ve_-kiKB_KiJlZ$9G`c^=E@oNG)mWWaNo-3TIW8)$Hg0Ub-~8?KhvJ>$ z3*&nim@mj(aCxE5!t{lw7O5^0EIO7zOo&c6l<+|iDySBWCGrz@C5{St!X3hAA}`T4 z(TLbXTq+(;@<=L8dXnssyft|w#WSTW<++3>sgS%(4NTpeI-VAqb|7ssJvzNHgOZVu zaYCvgO_R1~>SyL=cFU|~g|hy|Zi}}s9+d~lYqOB71z9Z$wnC=pR9Yz4DhIM>Wmjgu z&56o6maCpC&F##y%G;1PobR9i?GnNg;gYtchD%p19a!eQtZF&3JaKv33gZ<8D~47E ztUS1iwkmDaPpj=$m#%)jCVEY4fnLGNg2A-`YwHVD3gv};>)hAvT~AmqS>Lr``i7kw zJ{5_It`yrBmlc25DBO7E8;5VoznR>Ww5hAaxn$2~(q`%A-YuS64wkBy=9dm`4cXeX z4c}I@?e+FW+b@^RDBHV(wnMq2zdX3SWv9u`%{xC-q*U}&`cyXV(%rRT*Z6MH?i+i& z_B8C(+grT%{XWUQ+f@NoP1R=AW&26{v-dx)iK^-Nmiuj8txj!m?Z*Ss1N{dh4z}01 z)YTo*JycSU)+_5r4#yw9{+;i4Ee$peRgIj+;v;ZGdF1K$3E%e~4LaI(jC-u%2h$&R z9cLXcYC@Xwnns&bn)_Q~Te?roKGD|d-g^8;+aC{{G(1^(O7m37Y1-+6)01cN&y1aw zoqc{T`P^XJqPBbIW6s}d4{z_f5Om?vMgNQEJG?v2T=KYd^0M3I6IZxbny)%vZR&LD zJpPl@Psh8QyPB@KTx+@RdcC!KX7}kEo;S|j^u2lU7XQ}Oo;f|;z4Ll+_r>@1-xl3| zawq-H%e&ckC+@AhPrP6BKT#_XdT7&;F71j}Joy zkC~6lh7E@6o;W@^IpRNZ{ptLtL(gQ-CY~4mqW;US7Zxvm_|@yz&e53Bp_lTPlfP|z zrTyx_>lv@x#=^!PzR7qqF<$gm`|ZJZ+;<)Cqu&ot2z=00004XF*Lt006O$eEU(80000WV@Og>004R=004l4008;_004mL004C` z008P>0026e000+nl3&F}000BCNkl)#*re`t|z!@uXQTe7P#;w#Wn=3>BNw{8@$8{@lQTY-PZN7P@?K?Gj zwyh>rjW7nIn1{^QG`8%on(qc8CV(xigUr`7w(PH(?}{LZ1z=n2AoDeiE&HqHGlS6# z<{k|0!N^@1vHK(QHH|I%tL8I<@eCF*F<4lQb18Ga?Qf;>3u`&*#FuMQ)tDj@gnL?+ zxAm_gB0;6{hE)7Um$l7e>&Ne1W6JjfLOsnUkHcDX{8g_)L`17zrR&;ZV(Y}$snNA{ zh3$QHu0!IiJXwRq?iF9_s_e%Eu&s5F`I^R-{Z;c5&)|OMsK;PGCI(wt2br&FY}sEm zpBW5iF!x~Y!Q6ut_Urebmhr)lp99~6uV1}lr)GVVYyceilo$(Yz}V4n zP`(d_C!HvOqs3NgayGsi@d6C|wnfB2sVXyr<6toNU~muS7GbAF2yPMB7SWl(e&QJH zTzt^Zpl3HDGWZw==T!UMK)8pl`DTW@K7`0`L2pUzihK1EnL zMfjcHMI@KOgLH~u2BR754+FqR2IF2=GJ|d4;MbYKePZzLx8wl)_h4WFR;tSRy$mGR z93ZCWc_TZAw{Yw49Y)Ger7An9-zuB_R#?|izg0$=tF6+SS{PMV2RLmN{Qf|6v_=os zQEE*rtg5SHItn;a)eZ$PAJZ6MTW8fi0h}OKh#E7P8O%MHTLiZVZV|)E;3HKzgzDQ5 zOHtxXNA+a}TiN79wLs43?6K-Quq{H=6GY(F9&DoeGJ}Wq6pKLZ*U+IBfRsybQWXdwQbLP>6pAqfylh#{fb6;Z(vMMVS~$e@S=j*ftg6;Uhf59&ghTmgWD0l;*T zI709Y^p6lP1rIRMx#05C~cW=H_Aw*bJ-5DT&Z2n+x)QHX^p z00esgV8|mQcmRZ%02D^@S3L16t`O%c004NIvOKvYIYoh62rY33S640`D9%Y2D-rV&neh&#Q1i z007~1e$oCcFS8neI|hJl{-P!B1ZZ9hpmq0)X0i`JwE&>$+E?>%_LC6RbVIkUx0b+_+BaR3cnT7Zv!AJxW zizFb)h!jyGOOZ85F;a?DAXP{m@;!0_IfqH8(HlgRxt7s3}k3K`kFu>>-2Q$QMFfPW!La{h336o>X zu_CMttHv6zR;&ZNiS=X8v3CR#fknUxHUxJ0uoBa_M6WNWeqIg~6QE69c9o#eyhGvpiOA@W-aonk<7r1(?fC{oI5N*U!4 zfg=2N-7=cNnjjOr{yriy6mMFgG#l znCF=fnQv8CDz++o6_Lscl}eQ+l^ZHARH>?_s@|##Rr6KLRFA1%Q+=*RRWnoLsR`7U zt5vFIcfW3@?wFpwUVxrVZ>QdQz32KIeJ}k~{cZZE^+ya? z2D1z#2HOnI7(B%_ac?{wFUQ;QQA1tBKtrWrm0_3Rgps+?Jfqb{jYbcQX~taRB;#$y zZN{S}1|}gUOHJxc?wV3fxuz+mJ4`!F$IZ;mqRrNsHJd##*D~ju=bP7?-?v~|cv>vB zsJ6IeNwVZxrdjT`yl#bBIa#GxRa#xMMy;K#CDyyGyQdMSxlWT#tDe?p!?5wT$+oGt z8L;Kp2HUQ-ZMJ=3XJQv;x5ci*?vuTfeY$;({XGW_huIFR9a(?@3)XSs8O^N5RyOM=TTmp(3=8^+zpz2r)C z^>JO{deZfso3oq3?Wo(Y?l$ge?uXo;%ru`Vo>?<<(8I_>;8Eq#KMS9gFl*neeosSB zfoHYnBQIkwkyowPu(zdms`p{<7e4kra-ZWq<2*OsGTvEV%s0Td$hXT+!*8Bnh2KMe zBmZRodjHV?r+_5^X9J0WL4jKW`}lf%A-|44I@@LTvf1rHjG(ze6+w@Jt%Bvjts!X0 z?2xS?_ve_-kiKB_KiJlZ$9G`c^=E@oNG)mWWaNo-3TIW8)$Hg0Ub-~8?KhvJ>$ z3*&nim@mj(aCxE5!t{lw7O5^0EIO7zOo&c6l<+|iDySBWCGrz@C5{St!X3hAA}`T4 z(TLbXTq+(;@<=L8dXnssyft|w#WSTW<++3>sgS%(4NTpeI-VAqb|7ssJvzNHgOZVu zaYCvgO_R1~>SyL=cFU|~g|hy|Zi}}s9+d~lYqOB71z9Z$wnC=pR9Yz4DhIM>Wmjgu z&56o6maCpC&F##y%G;1PobR9i?GnNg;gYtchD%p19a!eQtZF&3JaKv33gZ<8D~47E ztUS1iwkmDaPpj=$m#%)jCVEY4fnLGNg2A-`YwHVD3gv};>)hAvT~AmqS>Lr``i7kw zJ{5_It`yrBmlc25DBO7E8;5VoznR>Ww5hAaxn$2~(q`%A-YuS64wkBy=9dm`4cXeX z4c}I@?e+FW+b@^RDBHV(wnMq2zdX3SWv9u`%{xC-q*U}&`cyXV(%rRT*Z6MH?i+i& z_B8C(+grT%{XWUQ+f@NoP1R=AW&26{v-dx)iK^-Nmiuj8txj!m?Z*Ss1N{dh4z}01 z)YTo*JycSU)+_5r4#yw9{+;i4Ee$peRgIj+;v;ZGdF1K$3E%e~4LaI(jC-u%2h$&R z9cLXcYC@Xwnns&bn)_Q~Te?roKGD|d-g^8;+aC{{G(1^(O7m37Y1-+6)01cN&y1aw zoqc{T`P^XJqPBbIW6s}d4{z_f5Om?vMgNQEJG?v2T=KYd^0M3I6IZxbny)%vZR&LD zJpPl@Psh8QyPB@KTx+@RdcC!KX7}kEo;S|j^u2lU7XQ}Oo;f|;z4Ll+_r>@1-xl3| zawq-H%e&ckC+@AhPrP6BKT#_XdT7&;F71j}Joy zkC~6lh7E@6o;W@^IpRNZ{ptLtL(gQ-CY~4mqW;US7Zxvm_|@yz&e53Bp_lTPlfP|z zrTyx_>lv@x#=^!PzR7qqF<$gm`|ZJZ+;<)Cqu&ot2z=00004XF*Lt006O$eEU(80000WV@Og>004R=004l4008;_004mL004C` z008P>0026e000+nl3&F}000UJNklsV|cYlY&q4zsSqY(=s&=iZ>cW|Jxv$MmG9zDvBot+(KW~|_7TD<6H{cAkN3K|aG zcrux+oO=g@0Ya4~{cSpH8q)S^C!RJ4&uZ})*9T~k*=eimkK)R(5Tt1);2fRB?TM})FJ3}Q5GXUb8Lk){FF_3Wx z=iJIUQx^{h5)s+dB4+IF?&d(;*xttO?zotV+(ty0F%iZKw08@d%-%zcDVt0A1Sf#Z z!$i550O_}rB?3rfgC(+rO4veFh#~^8Hy-20_BQs$V=WfUeQHPBy1+Q2J>DBT_nOd; zg%BBtmQXJ}Okfa+99U7I2a5MoP!1ME*2}cE*xTO+2~p?`YNwur5G5ud?C!LPP@KOm{BB z#+D0KgT?0I#e@*i(sz&zP75$15rJ3S|2QI{O)t_@pSjQy1b~?`xvW2-u@wmfCWc_c z)13c;fEO-bc3xDzZd;8l6W9w42 zW<`}u<0ZaeC@-Kijls+P(6(Jz6qgLJDBi=ii9)_II9f8%T4>=@up99}kB^U{(Z*SusdxZ;9thpIi5|i%i*z7$Q42&#_|A+Sh|kzjQ25$CH1E&}eROqug=T&4vm5K@rO%+N(%@`EF2u{BU z2Qnvsn%2zW93s5e7jCOIXrWnutK12sf9DVsIqQl!K zhoN|xb6z?(C(OXNeio?91RU=H0IvOZk=t(m;#^_H#4j{gps5xS*M76PNc)#Z#YNxG ziV!N#^i_O(Q*TlwRk0u{wdK&9Q_#P8{fY~KbKOP@%m6t7Q#fr z6(&y=#~QAtQ!vp0V0x&ttt5csqa28v*RKG_N5#EX2FeV0Jl4nlM=tICkBWPb$GWXo z+@j2iWlp6fpqDxQv_v1P%!ka5<0Jz&aqHWHjHo#FZ)M=#a_bw+j+mn}px!qeOTe}Q zY!hrb(x+I|44{$-^&C&VxQs>Iq8|c?*8SU-N@Z4=h=ATktzooG$I%jf zM^9NqP`kBL{y`K^Q5aM2ED-e}OpJ=ndH@$KuK0e+hz~1_tWL#>s0WxKT0l$@h4C8d{u@yJ}>WAE3Fd(@KviX7h9|z;NfuiI1EEH+t=KPgTM3Aw^tS8%B9EP z^FIQ3GY}A4!0e!2MEv!BH|*f^eOPO4vn>O8GOk!rNj0Vl^C`K{oB$@Vy3__9;QQZu zsT%p6nI|0@Px#?8vwI>zRXr6&qMS=T9077Cn~IJ)5MpqpvI zv*Y?!y^a9vbgF8avwNRNI6?R_xcWD=lsNK`)oC{XE_1H47NP>Y@&~8_J8U8J9{vFU zaP8Kjt$p*SAL^5fKL#$m)&YR~8wE(E1t_M@-d$N4PclpTv(-N;ISMKwaxkx7!L@h) z?Ofv@=u{EZUkCL!fwc{Yb$ys~>ThPh>-m8-eczl@e;u@L&NuaSNK0aRs52VW1Ma=! zW`6IzQ`|$`4H1F0bD)atgv*kf_TDsm_bxeM`GEfvi4`EMXxeA*;pX*U0iV6+){Bk+ z%x6ReTe}PSOr2szl;!Ry`!)GE+Z)6|z#gj^AWExl?*DF~j;SAfiH08s_s-@COXCse zt1K&4O)3x&A>UQ0%;Mqbl!n9UBEXfN+*(&e#D=3fmi?ZrZcfuxmO$jOUxm5?aMX7! zfjl>t#TnF+1%XC-2r6=Uu4xg9gQtKvc9uisyY6kqWefa}R)j}lGU^Bi!vc^> z9-S($V$V6bv=SaqzQ4o2%)s%DcQ3_4T)pHJ_8n&Rr~9ROG-5#LxX)wLf6NO|fq`uOj7mdgJI0H2v4wf~~Kng9R* M07*qoM6N<$f@g#ZbN~PV literal 0 HcmV?d00001 diff --git a/include/javascript/tiny_mce/themes/advanced/skins/o2k7/ui.css b/include/javascript/tiny_mce/themes/advanced/skins/o2k7/ui.css new file mode 100644 index 00000000..0f8d5c24 --- /dev/null +++ b/include/javascript/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; -ms-filter:'alpha(opacity=30)'; 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; background:url(img/button_bg.png) -44px 0} +.o2k7Skin .mceSplitButton span.mceOpen {display:none} +.o2k7Skin table.mceSplitButtonEnabled:hover a.mceAction, .o2k7Skin .mceSplitButtonHover a.mceAction, .o2k7Skin .mceSplitButtonSelected {background:url(img/button_bg.png) 0 -22px} +.o2k7Skin table.mceSplitButtonEnabled:hover a.mceOpen, .o2k7Skin .mceSplitButtonHover a.mceOpen, .o2k7Skin .mceSplitButtonSelected a.mceOpen {background-position:-44px -44px} +.o2k7Skin .mceSplitButtonDisabled .mceAction {opacity:0.3; -ms-filter:'alpha(opacity=30)'; 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; -ms-filter:'alpha(opacity=30)'; 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/include/javascript/tiny_mce/themes/advanced/skins/o2k7/ui_black.css b/include/javascript/tiny_mce/themes/advanced/skins/o2k7/ui_black.css new file mode 100644 index 00000000..81dbfe41 --- /dev/null +++ b/include/javascript/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 a.mceOpen, .o2k7SkinBlack .mceListBox a.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, .o2k7SkinBlack .mceListBoxHover .mceText, .o2k7SkinBlack .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, .o2k7SkinBlack .mceSplitButtonHover a.mceAction, .o2k7SkinBlack .mceSplitButtonSelected {background-image:url(img/button_bg_black.png)} +.o2k7SkinBlack .mceMenu .mceMenuItemEnabled a:hover, .o2k7SkinBlack .mceMenu .mceMenuItemActive {background-color:#FFE7A1} \ No newline at end of file diff --git a/include/javascript/tiny_mce/themes/advanced/skins/o2k7/ui_silver.css b/include/javascript/tiny_mce/themes/advanced/skins/o2k7/ui_silver.css new file mode 100644 index 00000000..e8ae844f --- /dev/null +++ b/include/javascript/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 a.mceOpen, .o2k7SkinSilver .mceListBox a.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/include/javascript/tiny_mce/themes/advanced/source_editor.htm b/include/javascript/tiny_mce/themes/advanced/source_editor.htm new file mode 100644 index 00000000..5f047dcb --- /dev/null +++ b/include/javascript/tiny_mce/themes/advanced/source_editor.htm @@ -0,0 +1,32 @@ + + + + {#advanced_dlg.code_title} + + + + + +
    +
    {#advanced_dlg.code_title}
    + +
    + +
    + +
    + + + +
    +
    + +
    + +
    + +
    +
    +
    + + diff --git a/include/javascript/tiny_mce/themes/simple/editor_template.js b/include/javascript/tiny_mce/themes/simple/editor_template.js new file mode 100644 index 00000000..d19fb53f --- /dev/null +++ b/include/javascript/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.documentBaseURI.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/include/javascript/tiny_mce/themes/simple/editor_template_src.js b/include/javascript/tiny_mce/themes/simple/editor_template_src.js new file mode 100644 index 00000000..fac4d895 --- /dev/null +++ b/include/javascript/tiny_mce/themes/simple/editor_template_src.js @@ -0,0 +1,85 @@ +/** + + * + * 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.documentBaseURI.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/include/javascript/tiny_mce/themes/simple/img/icons.gif b/include/javascript/tiny_mce/themes/simple/img/icons.gif new file mode 100644 index 0000000000000000000000000000000000000000..16af141ff0eea376a889b1e8d28e9c1cacaaab16 GIT binary patch literal 1440 zcmV;R1z-9{Nk%w1VaNa!0QUd@Ib*`7v&H}b0P*i`B{WZ*I4YI8{iDPCZ*XyWj;?N! z&ooP8CcKTM%}ImAk&d@bUef&=iA% zhPA3sm56OYcjMRI^s}jof~E0n!SIozxs`y)bZpaM%~elOt(xIz_1F@`xREtxwxO@X zElsNLx;f_MIwnTOux@bk@5r<-;@s){f~fMSskU>S&vlpdmZGk)n^Ks084*pfMo5}`Y)@uBrt7q^ z_xb)XxI@^-XhLVQWPPfUtMQSg&Xb6UQhU2=S3pa1!Lhs1Kwz1)!P59aI6r5pthLM4 zE-ud4`aC>8zybolqcQ$sRq*)W>+kl^)!br%x2LJkVv+Dui1Oh7|6z>ag023Luhg%= z;=sbh)RP30t>V}2$H?fg=;-%zOTU8v0MO8l85I$+z}bYP#G9DS_#hs}n3hj*tissz zAwYQh{QX~VkH5&*9YTcu{{H^`{_yYcW|;u|{Qilm^upTyi?sd!nVG)6{{LrW`s5%! zQETJeu@Y0sB3Qy+jGVB@-BWO)C1U{h_4v@?@UEu*S8lPiucH6>|4vxO2|0#LaF@v0 z@ZaCy@c8hkxVXaB{z|fT@U~;Hv$d$T$J*xpqPpE8TH+G^0=vlI+KzIEuZN}B@UYO} z&dtoGp5{=vw)ErQRcDJbQgSxGf8JYL_`X^{uFH_9uqY`f`}_Of)zF}&w4mVd!0r05 zoM3>k!2kdMA^8LW00930EC2ui0LTCo000R80RIUbNU)&6g9sBUT*$DY!-o(fN}Ncs zqQ#3CGiuz(v7^V2AVW@EluM+^lPFV4B&kwhfCK?JZW}S8Lq-x8D(>2KU{_0tBn}8A zagb%p1Q&P-6u`78(}*2LRH3FT;{^Z%ooYoWl!#X%K7Tem@Rf*AgGMWAZK^N;uLKrJ zgqs_6Dufyfw<06~AZA3KR{>nO09GJYj!yq2Mo2^;St0-;UpPxp*8_}f6+Z>JE!?&a z+dPb*b~hYDra%-%J`C}|)xna%9$;-yz|zc`Z6DmMS)p07fiENwe4t=jwVQEwY|=zo zxL=@s=&E6Qp)TGXT_1)l*emUVx)m?~6;Hl)c5^2e&KlH&3v877L9rfP;Fp}T4iu?af8AOXd@5C0(U&fK3z8Av u{UxbK~bzVrJ#-t*jZ&pr2fKKGn^&V9~vZo*x2BQEx{>;M38nHcL^F{BiObs@}* z`J{#WLxwovXYBAC060$l$4o$8!D#?sw|K0lclYii-vHm|k9_^aO!V}`{GR!GKKAwi zfM8^yH4JKv6VxCt?&+GwM`W1#S_weJtaOti_){-Si=W`V9WVZ2Ucj=G&%l61xW6Qx zIXOAvt$?KrXCnI?8&>>da`dP8#6ikZ*e9=Xj!Y3TOdSEKH%uWB{D5|7vhEi^+mI=uFz2#0P{IPZ3_WyP0q)8IE|RbRP5}{x z2f1NP!2Jwy0j82vKX1B3cwNuxb$DV7!1VZ0{n)%cIrDj8dcu&mZD20F_l+P$K~x|}=gXx@k6>Qpl6&#z^PNTmmnMl1(^x`y}el%5+)I}ziC z{+nV%ZRP-}B2yQ-P25`SrTJGZPx>e8=e;E=m0n2DO}o-_X%ci_#>h~ZH8IzKuTM0Y z!ct|+A3S80mwAc^uuzL3L4$(Us`#(&g1vdn3IGLcQB-!%*n8~-# z(8-gNhLb*47jZHb`6|X|FQyM5-M#AB)G}nmuJ*sd7Ge=tWvnn(eD^+kp_{h<=L73y zDXYOJx6iEduBxoEdgLhS*nG;fS}6Yj<-3-0Pq*enlU1E%T=^-L7kO$U(SjzXr8OTj zr_MeSdPII)w;u45Zy{6EJbT=3atLR%p1sbz7sSaGD-him50g5Rf12$y>`c(4Pd?@RJM(g;u(Uk1qVh}SVkL(S(PjvmQsHF% zs@Bj(*?Oho#P6&so65qwo7TeCu!>vdah0%gU#QmSa0glfs{`T=!b0z}Wyv?^mDXM{ zj)!Ny2g`_iaaF~>h`iQ)`P<0+%Rp&(4ow7}q)}P%K}}EjwzA!KD`JMH7TZdW|3N{3 z`H3~DvTR~_;v)a{mE|kKUsUe2D0(=0Rc2*p*;g4?SymZswyD1=8NeMVk=#0c zwL3k?%w8Sn54MXzP`_X1ZoC#iX`OsDGL^ zd}qk>_HnP{ip0v(-lx5vF0)=1zieu@VMfTaGHdyA<;$%*x9;?f43B&qnaRDDuc0`r zw3fe?KbwzfcDWaPPo}B7>4%3&J@(!g2SQV;&zpN{4yE=s_a1yVtSPLyGy|`Jm+_Ug zn5Uap70tj9Uw4`Ynkt&ld|jPmMb$PvZF=Pja}$C!_tYW?>22w+e!hA~(_rI@o9C_) zxhE3-yx|%DP1~D`d7}jctyevJSvYx^{TT1qobpQ3si7;~j|;8yr;K1iu$Jf1#Q3BH z)2Jc2Y)!d*;ogP*Htg*HlK+FH&`DBZ{`dSYd^xI)ph|d5h(i|-s}x@;a!`Igj_B9> zW4St^#ZjE8;DxCUx6reQgf*^Rlz%9nYF9J+wYfB?lI*%Iq`9y8tawFpMg97s(xQX& z@b!-7{^lVIgm01a8;suTi=aCg3QhoJ5to=?%n6Y?k@t^L4nkjwwUdtIx9evFG=5F}<%s89tU)Ll=IH%;BxHopOTFHL# z_Gc#)v#$kBp!J?(^pEtj^cVACiWX{hvbV2EYgWoVQAb|?sq#~+SI*O6c-p?u-o)GV zoSK|;t*VdrFANn=j9V^T=2!_6%8~DX;1}{?v}^B8nP7$7Ntv5j+IQm3Z)E(_;gv2I ze0yp4RM4el_K+@-F4zV63Dt@CIXy>dQS)76X|vF@t<=_QArd{xr8286F_IPUTkmk) zS;)UxB$yW{_EbsZW}9MkTIzd$-AZw@^d{H_?5}6wP_@UKdU}sfQnS2hCfk75_xIJu z9c0;?bib@a?@7%{v(>{q>^$2?5(d?>s*0|T;D^5tqTXLG*e(X~C%aBAr8Sktn%c>V z*#B*-exg>d?jM3;UlBNdHP)83TKz|2ll0SRiz>Wbc5QguA2Nw474wy#Qqu4@WO@V~OT7HyJw!rH-DRl6vaGdX8doDVop`xn0#eK|k z(i8W0QMTwlcUEQg-)wFlu6bkw7sj>$Pue#?$!Cv9q2SR?dM%&Y)qk{llnsoI+|q)6 zhVDU+psIw)g+|xe1D^?ka9HcU%GNaMek+-#Iq(Z*!(?MN?K$m1F`;}XYt<%H;tsMX zPao8nKlR7=F;6nn*e-H6&9?lW7Maw5TBXcf-8ACvJO7JbxE&U z7DqmTA&YX|L1m~Wj&x$k!Wr^T@5#LUKGDAfpco~J-X z-67;Q5jyY~iHn*_hwYBNEzB%@6)ty(c0qk?3R`FHAzeeeQ!UTuq`R|_Gutuf4#j1w-pKDw~i7P2D< z&P*4nX)Lr6Lw(6TWD-VjA^e#nZFC4eA0$brX|-r|-qXhG%5n!qvy8Kub*@T zl@KS;Mr77E(PQ*fQVNgW@s!+@p;)fi&7vEcYHG_`&uBPmnckTD*ySQ2`bYXut&pI6 z_`&q%?C3 zL<7Jf$dEVyc%c9Q8!iBFGY0^KeAAqJ3;}={xO)d`z`%eYh#JiuMDNsfW1=$<(dmeo zjP95WM1J$1l2&YH-E;|jIjipXkD;|WEa?w!-}cqFV)$|~e5s^$xdgu0`J3=-Vxw&w z*E+V2nAz@{CUpMB{~E`2PHpwf{u@M-#+S$=3%e74_NG_%k!y$Zf6230(!vG>jXT0@ zQWkKBD|iY9x4*ta!{QHDwhjtf(8ch@lGepy_(H?L@-N2uQ~0)tjbD=+0}K1zvkVjX zeiX51?%&Yje((Ihp1JK2%>KyY?kI*hvwAR%B~LEx&0zP(76>cb^ko8V2~SK&K zhZgtxQ9FG|29P*_-Wgih9Yhf(m-i-?h~t>;(FObndTSO-M6Qvr|LB;_gMJiY5WPLI z%qL(;yWI9`%6K1(3Q7(n;XqFi2emX?T!M z21(7}!4Q3a5TtI4U6L8WDoG=3?&A|zCaLN{(cA-zZgEJoBj3+qz1VjeXFz>+S_q3%Ha5;mvltEk0 z0I@mXY5{${dec;X@b$bxp z9RrC|)SYo~Z-z#k2KN_0G6p0sfm9+m{{oy329Ym8bR>w5rp-swkufx642VghGpsLV zfa_J@<_~aZ7~Go&NhpxA1I~ni(;>9q!Qf0NZ9WD(+@ue@p!NmO2Lh@6FQ{;5TB{2k z@raIiLhE`Aj>gePV!^R^N`noh!Is)&M{TsD!Ck=LIkdTQ5Lr3ckUh|l1I||*p_&en zje`w21K)GDrW!Y=8jp~TjF;a|x}gsMOhAB@xiv%meO2x_!p66W8|!3F z3K<7F$K0Opu&RXCgY0kj(}Md=k40Ax3**GROT%0zW&NB3QY@Ac&kyGl^e-&ALU@lcY9Q}1h&TWo z+k?8hnE8OA{@y=VwBtoF@ihygu@)0b$2x5Lov1td z-k(2Ze}N=k@O+&25t3H|iTZ-W?aUDy#Sicgc12CnBuq5L+a-$MlL@I3Y8rf~(>P;3 z6|)Hzvs3&!*8B$J{E8Z)sCX_~-HCM8E*6rI;^47^s=UobI%jJMp zUEHb>8saG^lr1R4=HWje>a6xd&1c<7%aN7wAskl%AhM|DwH^LGE<~=j0xyL1Sf`8F zffz3*Ycx-kPN=ks(AiKa(byk%<5z5p{T<`)uilX3XZL^m(C70?&g>>B^n3^&aS>j9 z(=a=hH}sEs46p9_z0MHG2c9n8K7X{?dLX>Or_5^-R}=tu3__0%m^4q(9!oU$T2(;h zNEfnimp*HOZcw1o*@LAD3YkNR4wn4n!2NCwOMU}OG@k+IaKgNZV*bJaAt7uzSt@b9 zI%mY~Pg3{HjIBCfO5aNUj=q~RUy9^Of6ie-JM#Qs73~!#+PX12@5|%LBP$yl8|!N} z(<+WeX4cottl1cv*%Xu$t)~l`4PMZ6FIm&W3$-3l_^?6o_l`b`;8X`NC zCSjT;Go-{Vy}Ran$)Ua?Ci?hcquG{?heOssk(AxT=;)W4uiuZYVX$@4afkW;MwkRe zg#{4hP)@|byaFde!CYEWl9lzz>a&*5*_D^tDmPctYVAn%wGT@|gM)()rq-0of86@S zpW$YCMNq)NG9$`LhM%M70yp9Oe27W3YD3n< zV?=oxR(68L_JS3@&Ti7CH)#u-q^YxN7b22`Or8ynbtoJ~GYNN6M}36p0QHtFr;sN(-`SjCLE z^;=~`c}nHAqS=&+**WhTU?amp#_E%kugb=cbTvjcRPdpJo_T*OLJ~E+ z!ioz{$NIZL-zNH7DRMHiRe7{kW|Putvu{sV*4mj)KM`Q#@$FtzjJr`TWl&lobv$g0 zKk0a>J=E{+oZtaA(2AEuGZ)*O-YVuT>7N}ZloloSuk}6lP(mKk+94U@XrwtnRBxAs zm^c~xa2y+x-0}0iUT9JlG=jv-)(>n)f262E!2209 VmjT$ODWe$zObpERYjs_s{s;8{A&me4 literal 0 HcmV?d00001 diff --git a/include/javascript/tiny_mce/themes/simple/skins/o2k7/ui.css b/include/javascript/tiny_mce/themes/simple/skins/o2k7/ui.css new file mode 100644 index 00000000..021d650f --- /dev/null +++ b/include/javascript/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; -ms-filter:'alpha(opacity=30)'; 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/include/javascript/tiny_mce/tiny_mce.js b/include/javascript/tiny_mce/tiny_mce.js new file mode 100644 index 00000000..d230fc9c --- /dev/null +++ b/include/javascript/tiny_mce/tiny_mce.js @@ -0,0 +1 @@ +var tinymce={majorVersion:'3',minorVersion:'2.1.1',releaseDate:'2008-11-27',_init:function(){var t=this,d=document,w=window,na=navigator,ua=na.userAgent,i,nl,n,base,p,v;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;t.isAir=/adobeair/i.test(ua);if(w.tinyMCEPreInit){t.suffix=tinyMCEPreInit.suffix;t.baseURL=tinyMCEPreInit.base;t.query=tinyMCEPreInit.query;return;}t.suffix='';nl=d.getElementsByTagName('base');for(i=0;i=items.length){for(i=0,l=base.length;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,l=base.length-(bp-1);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);function ready(){if(!o.async||x.readyState==4||c++>10000){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;}else w.setTimeout(ready,10);};if(!o.async)return ready();t=w.setTimeout(ready,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_]+)$/,props:{"for":"htmlFor","class":"className",className:"className",checked:"checked",disabled:"disabled",maxlength:"maxLength",readonly:"readOnly",selected:"selected",value:"value",id:"id",name:"name",type:"type"},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,sr;e=t.get(e);p=t.getPos(e);sr=t.getSize(e);return{x:p.x,y:p.y,w:sr.w,h:sr.h};},getSize:function(e){var t=this,w,h;e=t.get(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{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.toUpperCase()==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(e&&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,xp;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.selectorRe)t.selectorRe=/^([\w\\*]+)?(?:#([\w\\]+))?(?:\.([\w\\\.]+))?(?:\[\@([\w\\]+)([\^\$\*!]?=)([\w\\]+)\])?(?:\:([\w\\]+))?/i;;if(tinymce.isAir){each(tinymce.explode(pa),function(v){if(!(xp=t.cache[v])){xp='';each(v.split(' '),function(v){v=t.selectorRe.exec(v);xp+=v[1]?'//'+v[1]:'//*';if(v[2])xp+="[@id='"+v[2]+"']";if(v[3]){each(v[3].split('.'),function(n){xp+="[@class = '"+n+"' or contains(concat(' ', @class, ' '), ' "+n+" ')]";});}});t.cache[v]=xp;}xp=t.doc.evaluate(xp,s,null,4,null);while(n=xp.iterateNext())o.push(n);});return o;}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;t.setAttribs(e,a);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(!e||!n)return;if(t.settings.strict)n=n.toLowerCase();return this.run(e,function(e){var s=t.settings;switch(n){case"style":if(!is(v,'string')){each(v,function(v,n){t.setStyle(e,n,v);});return;}if(s.keep_values){if(v&&!t._isRes(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;case"shape":e.setAttribute('mce_style',v);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|shape)$/.test(n)){v=e.getAttribute("mce_"+n);if(v)return v;}if(isIE&&t.props[n]){v=e[t.props[n]];v=v&&v.nodeValue?v.nodeValue:v;}if(!v)v=e.getAttribute(n,2);if(n==='style'){v=v||e.style.cssText;if(v){v=t.serializeStyle(t.parseStyle(v));if(t.settings.keep_values&&!t._isRes(v))e.setAttribute('mce_style',v);}}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===20)v='';break;case'width':case'height':case'vspace':case'checked':case'disabled':case'readonly':if(v===0)v='';break;case'hspace':if(v===-1)v='';break;case'maxlength':case'tabindex':if(v===32768||v===2147483647||v==='32768')v='';break;case'compact':case'noshade':case'nowrap':if(v===65535)return n;return dv;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!==undefined&&v!==null&&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];};st=st.replace(/&(#?[a-z0-9]+);/g,'&$1_MCE_SEMI_');each(st.split(';'),function(v){var sv,ur=[];if(v){v=v.replace(/_MCE_SEMI_/g,';');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('+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){if(tinymce.isGecko&&k.indexOf('-moz-')===0)return;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||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(/\s+(disabled|checked|readonly|selected)\s*=\s*[\"\']?(false|0)[\"\']?/gi,'');}h=h.replace(/]+)\/>|/gi,'');if(s.keep_values){if(/)/g,'\n');s=s.replace(/^[\r\n]*|[\r\n]*$/g,'');s=s.replace(/^\s*(\/\/\s*|\]\]>|-->|\]\]-->)\s*$/g,'');return s;};h=h.replace(/]+|)>([\s\S]*?)<\/script>/g,function(v,a,b){b=trim(b);if(!a)a=' type="text/javascript"';if(b)b='';return''+b+'';});h=h.replace(/]+|)>([\s\S]*?)<\/style>/g,function(v,a,b){b=trim(b);return''+b+'';});}h=h.replace(//g,'');h=h.replace(/<([\w:]+) [^>]*(src|href|style|shape|coords)[^>]*>/gi,function(a,n){function handle(m,b,c){var u=c;if(a.indexOf('mce_'+b)!=-1)return m;if(b=='style'){if(t._isRes(c))return m;if(s.hex_colors){u=u.replace(/rgb\([^\)]+\)/g,function(v){return t.toHex(v);});}if(s.url_converter){u=u.replace(/url\([\'\"]?([^\)\'\"]+)\)/g,function(x,c){return'url('+t.encode(s.url_converter.call(s.url_converter_scope||t,t.decode(c),b,n))+')';});}}else if(b!='coords'&&b!='shape'){if(s.url_converter)u=t.encode(s.url_converter.call(s.url_converter_scope||t,t.decode(c),b,n));}return' '+b+'="'+c+'" mce_'+b+'="'+u+'"';};a=a.replace(/ (src|href|style|coords|shape)=[\"]([^\"]+)[\"]/gi,handle);a=a.replace(/ (src|href|style|coords|shape)=[\']([^\']+)[\']/gi,handle);return a.replace(/ (src|href|style|coords|shape)=([^\s\"\'>]+)/gi,handle);});}return h;},getOuterHTML:function(e){var d;e=this.get(e);if(!e)return null;if(isIE)return e.outerHTML;d=(e.ownerDocument||this.doc).createElement("body");d.appendChild(e.cloneNode(true));return d.innerHTML;},setOuterHTML:function(e,h,d){var t=this;return this.run(e,function(e){var n,tp;e=t.get(e);d=d||e.ownerDocument||t.doc;if(isIE&&e.nodeType==1)e.outerHTML=h;else{tp=d.createElement("body");tp.innerHTML=h;n=tp.lastChild;while(n){t.insertAfter(n.cloneNode(true),e);n=n.previousSibling;}t.remove(e);}});},decode:function(s){var e,n,v;if(/&[^;]+;/.test(s)){e=this.doc.createElement("div");e.innerHTML=s;n=e.firstChild;v='';if(n){do{v+=n.nodeValue;}while(n.nextSibling);}return v||s;}return s;},encode:function(s){return s?(''+s).replace(/[<>&\"]/g,function(c,b){switch(c){case'&':return'&';case'"':return'"';case'<':return'<';case'>':return'>';}return c;}):s;},insertAfter:function(n,r){var t=this;r=t.get(r);return this.run(n,function(n){var p,ns;p=r.parentNode;ns=r.nextSibling;if(ns)p.insertBefore(n,ns);else p.appendChild(n);return n;});},isBlock:function(n){if(n.nodeType&&n.nodeType!==1)return false;n=n.nodeName||n;return/^(H[1-6]|HR|P|DIV|ADDRESS|PRE|FORM|TABLE|LI|OL|UL|TD|CAPTION|BLOCKQUOTE|CENTER|DL|DT|DD|DIR|FIELDSET|NOSCRIPT|NOFRAMES|MENU|ISINDEX|SAMP)$/.test(n);},replace:function(n,o,k){if(is(o,'array'))n=n.cloneNode(true);return this.run(o,function(o){if(k){each(o.childNodes,function(c){n.appendChild(c.cloneNode(true));});}return o.parentNode.replaceChild(n,o);});},toHex:function(s){var c=/^\s*rgb\s*?\(\s*?([0-9]+)\s*?,\s*?([0-9]+)\s*?,\s*?([0-9]+)\s*?\)\s*$/i.exec(s);function hex(s){s=parseInt(s).toString(16);return s.length>1?s:'0'+s;};if(c){s='#'+hex(c[1])+hex(c[2])+hex(c[3]);return s;}return s;},getClasses:function(){var t=this,cl=[],i,lo={},f=t.settings.class_filter,ov;if(t.classes)return t.classes;function addClasses(s){each(s.imports,function(r){addClasses(r);});each(s.cssRules||s.rules,function(r){switch(r.type||1){case 1:if(r.selectorText){each(r.selectorText.split(','),function(v){v=v.replace(/^\s*|\s*$|^\s\./g,"");if(/\.mce/.test(v)||!/\.[\w\-]+$/.test(v))return;ov=v;v=v.replace(/.*\.([a-z0-9_\-]+).*/i,'$1');if(f&&!(v=f(v,ov)))return;if(!lo[v]){cl.push({'class':v});lo[v]=1;}});}break;case 3:addClasses(r.styleSheet);break;}});};try{each(t.doc.styleSheets,addClasses);}catch(ex){}if(cl.length>0)t.classes=cl;return cl;},run:function(e,f,s){var t=this,o;if(t.doc&&typeof(e)==='string')e=t.get(e);if(!e)return false;s=s||this;if(!e.nodeType&&(e.length||e.length===0)){o=[];each(e,function(e,i){if(e){if(typeof(e)=='string')e=t.doc.getElementById(e);o.push(f.call(s,e,i));}});return o;}return f.call(s,e);},getAttribs:function(n){var o;n=this.get(n);if(!n)return[];if(isIE){o=[];if(n.nodeName=='OBJECT')return n.attributes;n.cloneNode(false).outerHTML.replace(/([a-z0-9\:\-_]+)=/gi,function(a,b){o.push({specified:1,nodeName:b});});return o;}return n.attributes;},destroy:function(s){var t=this;t.win=t.doc=t.root=null;if(!s)tinymce.removeUnload(t.destroy);},_isRes:function(c){return/^(top|left|bottom|right|width|height)/i.test(c)||/;\s*(top|left|bottom|right|width|height)/i.test(c);}});tinymce.DOM=new tinymce.dom.DOMUtils(document,{process_html:0});})();(function(){var each=tinymce.each,DOM=tinymce.DOM,isIE=tinymce.isIE,isWebKit=tinymce.isWebKit,Event;tinymce.create('static tinymce.dom.Event',{inits:[],events:[],add:function(o,n,f,s){var cb,t=this,el=t.events,r;if(o&&o instanceof Array){r=[];each(o,function(o){o=DOM.get(o);r.push(t.add(o,n,f,s));});return r;}o=DOM.get(o);if(!o)return;cb=function(e){e=e||window.event;if(e&&!e.target&&isIE)e.target=e.srcElement;if(!s)return f(e);return f.call(s,e);};if(n=='unload'){tinymce.unloads.unshift({func:cb});return cb;}if(n=='init'){if(t.domLoaded)cb();else t.inits.push(cb);return cb;}el.push({obj:o,name:n,func:f,cfunc:cb,scope:s});t._add(o,n,cb);return f;},remove:function(o,n,f){var t=this,a=t.events,s=false,r;if(o&&o instanceof Array){r=[];each(o,function(o){o=DOM.get(o);r.push(t.remove(o,n,f));});return r;}o=DOM.get(o);each(a,function(e,i){if(e.obj==o&&e.name==n&&(!f||(e.func==f||e.cfunc==f))){a.splice(i,1);t._remove(o,n,e.cfunc);s=true;return false;}});return s;},clear:function(o){var t=this,a=t.events,i,e;if(o){o=DOM.get(o);for(i=a.length-1;i>=0;i--){e=a[i];if(e.obj===o){t._remove(e.obj,e.name,e.cfunc);e.obj=e.cfunc=null;a.splice(i,1);}}}},cancel:function(e){if(!e)return false;this.stop(e);return this.prevent(e);},stop:function(e){if(e.stopPropagation)e.stopPropagation();else e.cancelBubble=true;return false;},prevent:function(e){if(e.preventDefault)e.preventDefault();else e.returnValue=false;return false;},_unload:function(){var t=Event;each(t.events,function(e,i){t._remove(e.obj,e.name,e.cfunc);e.obj=e.cfunc=null;});t.events=[];t=null;},_add:function(o,n,f){if(o.attachEvent)o.attachEvent('on'+n,f);else if(o.addEventListener)o.addEventListener(n,f,false);else o['on'+n]=f;},_remove:function(o,n,f){if(o){try{if(o.detachEvent)o.detachEvent('on'+n,f);else if(o.removeEventListener)o.removeEventListener(n,f,false);else o['on'+n]=null;}catch(ex){}}},_pageInit:function(){var e=Event;if(e.domLoaded)return;e._remove(window,'DOMContentLoaded',e._pageInit);e.domLoaded=true;each(e.inits,function(c){c();});e.inits=[];},_wait:function(){var t;if(window.tinyMCE_GZ&&tinyMCE_GZ.loaded){Event.domLoaded=1;return;}var skipInitPhase = (typeof (skipTinyMCEInitPhase) != 'undefined') ? true : false;if(isIE&&document.location.protocol!='https:'&& !skipInitPhase){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+='';if(tinymce.relaxedDomain){if(isIE||(tinymce.isOpera&&parseFloat(opera.version())>=9.5))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{if(!s.readonly)d.designMode='On';}catch(ex){}}if(isIE){b=t.getBody();DOM.hide(b);if(!s.readonly)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,element_format:s.element_format,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;if(!s.readonly)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(/^(]*>( | |\s|\u00a0|)<\/p>[\r\n]*|
    [\r\n]*)$/,'');});}if(isGecko&&!s.readonly){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,ce=t.settings.content_editable;if(!sf){if(!ce&&(!isIE||t.selection.getNode().ownerDocument!=t.getDoc()))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||'en',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||'en')+'.'+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;if(e){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(!e||!t.initialized)return;o=o||{};o.save=true;if(!o.no_events){t.undoManager.typing=0;t.undoManager.add();}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(),'
    ');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;if(!o.no_events)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.getBody(),'mousedown',function(e){if(e.ctrlKey){e.fakeType='contextmenu';eventHandler(e);}});}else Event.add(t.getBody(),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&&!s.readonly){if(t._isHidden()){try{if(!s.content_editable)d.designMode='On';}catch(ex){}}try{d.execCommand("styleWithCSS",0,false);}catch(ex){if(!t._isHidden())try{d.execCommand("useCSS",0,true);}catch(ex){}}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){var c=e.keyCode;if((c>=33&&c<=36)||(c>=37&&c<=40)||c==13||c==45||c==46||c==8||(tinymce.isMac&&(c==91||c==93))||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(tinymce.isMac&&o.ctrl!=e.metaKey)return;else if(!tinymce.isMac&&o.ctrl!=e.ctrlKey)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 process(no){var n,sp,nl,x;if(!s.inline_styles)return;nl=t.dom.select('font',no);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);}};t.onPreProcess.add(function(ed,o){if(o.get)process(o.node);});t.onSetContent.add(function(ed,o){if(o.initial)process(o.node);});},_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;function isBlock(n){return/^(H[1-6]|HR|P|DIV|ADDRESS|PRE|FORM|TABLE|OL|UL|TD|CAPTION|BLOCKQUOTE|CENTER|DL|DT|DD|DIR|FIELDSET|NOSCRIPT|NOFRAMES|MENU|ISINDEX|SAMP)$/.test(n.nodeName);};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{if(ed.settings.convert_fonts_to_spans)t._applyInlineStyle('span',{style:{fontFamily:v}});else ed.getDoc().execCommand('FontName',false,v);}},FontSize:function(u,v){var ed=this.editor,s=ed.settings,fc,fs;if(s.convert_fonts_to_spans&&v>=1&&v<=7){fs=tinymce.explode(s.font_size_style_values);fc=tinymce.explode(s.font_size_classes);if(fc)v=fc[v-1]||v;else v=fs[v-1]||v;}if(v>=1&&v<=7)ed.getDoc().execCommand('FontSize',false,v);else this._applyInlineStyle('span',{style:{fontSize: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(p=ed.dom.getParent(ed.selection.getNode(),'SPAN'))v=p.style.fontSize;if(!v&&(isOpera||isWebKit)){if(p=ed.dom.getParent(ed.selection.getNode(),'FONT'))v=p.size;return v;}return v||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(p=ed.dom.getParent(ed.selection.getNode(),'SPAN'))v=p.style.fontFamily.replace(/, /g,',').replace(/[\'\"]/g,'').toLowerCase();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(bl||n.parentNode,'textAlign','');dom.setStyle(n,'float','');this.mceRepaint();return;}if(v=='center'){if(bl&&/^(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(bl||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())&&!ed.settings.force_span_wrappers)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(ed.settings.force_span_wrappers&&p.nodeName!='SPAN')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);},ForeColor:function(ui,v){var ed=this.editor;if(ed.settings.convert_fonts_to_spans){this._applyInlineStyle('span',{style:{color:v}});return;}else ed.getDoc().execCommand('ForeColor',false,v);},HiliteColor:function(ui,val){var t=this,ed=t.editor,d=ed.getDoc();if(ed.settings.convert_fonts_to_spans){this._applyInlineStyle('span',{style:{backgroundColor:val}});return;}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,s=ed.selection,dom=ed.dom,bl,nb,b;function isBlock(n){return/^(P|DIV|H[1-6]|ADDRESS|BLOCKQUOTE|PRE)$/.test(n.nodeName);};bl=dom.getParent(s.getNode(),function(n){return isBlock(n);});if(bl){if((isIE&&isBlock(bl.parentNode))||bl.nodeName=='DIV'){nb=ed.dom.create(val);each(dom.getAttribs(bl),function(v){dom.setAttrib(nb,v.nodeName,dom.getAttrib(bl,v.nodeName));});b=s.getBookmark();dom.replace(nb,bl,1);s.moveToBookmark(b);ed.nodeChanged();return;}}val=ed.settings.forced_root_block?(val||'

    '):val;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;}return this.queryStateInsertUnorderedList()||this.queryStateInsertOrderedList()||(!ed.settings.inline_styles&&!!ed.dom.getParent(ed.selection.getNode(),'BLOCKQUOTE'));},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(),isBlock);eb=dom.getParent(s.getEnd(),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(),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);},_applyInlineStyle:function(na,at,op){var t=this,ed=t.editor,dom=ed.dom,bm,lo={},kh;na=na.toUpperCase();if(op&&op.check_classes&&at['class'])op.check_classes.push(at['class']);function replaceFonts(){var bm;each(dom.select(tinymce.isWebKit&&!tinymce.isAir?'span':'font'),function(n){if(n.style.fontFamily=='mceinline'||n.face=='mceinline'){if(!bm)bm=ed.selection.getBookmark();at._mce_new='1';dom.replace(dom.create(na,at),n,1);}});each(dom.select(na),function(n){if(n.getAttribute('_mce_new')){function removeStyle(n){if(n.nodeType==1){each(at.style,function(v,k){dom.setStyle(n,k,'');});if(at['class']&&n.className&&op){each(op.check_classes,function(c){if(dom.hasClass(n,c))dom.removeClass(n,c);});}}};each(dom.select(na,n),removeStyle);if(n.parentNode&&n.parentNode.nodeType==1&&n.parentNode.childNodes.length==1)removeStyle(n.parentNode);dom.getParent(n.parentNode,function(pn){if(pn.nodeType==1){if(at.style){each(at.style,function(v,k){var sv;if(!lo[k]&&(sv=dom.getStyle(pn,k))){if(sv===v)dom.setStyle(n,k,'');lo[k]=1;}});}if(at['class']&&pn.className&&op){each(op.check_classes,function(c){if(dom.hasClass(pn,c))dom.removeClass(n,c);});}}return false;});n.removeAttribute('_mce_new');}});each(dom.select(na).reverse(),function(n){var c=0;each(dom.getAttribs(n),function(an){if(an.nodeName.substring(0,1)!='_'&&dom.getAttrib(n,an.nodeName)!=''){c++;}});if(c==0)dom.remove(n,1);});ed.selection.moveToBookmark(bm);return!!bm;};ed.focus();ed.getDoc().execCommand('FontName',false,'mceinline');replaceFonts();if(kh=t._applyInlineStyle.keyhandler){ed.onKeyUp.remove(kh);ed.onKeyPress.remove(kh);ed.onKeyDown.remove(kh);ed.onSetContent.remove(t._applyInlineStyle.chandler);}if(ed.selection.isCollapsed()){t._pendingStyles=tinymce.extend(t._pendingStyles||{},at.style);t._applyInlineStyle.chandler=ed.onSetContent.add(function(){delete t._pendingStyles;});t._applyInlineStyle.keyhandler=kh=function(e){if(t._pendingStyles){at.style=t._pendingStyles;delete t._pendingStyles;}if(replaceFonts()){ed.onKeyDown.remove(t._applyInlineStyle.keyhandler);ed.onKeyPress.remove(t._applyInlineStyle.keyhandler);}if(e.type=='keyup')ed.onKeyUp.remove(t._applyInlineStyle.keyhandler);};ed.onKeyDown.add(kh);ed.onKeyPress.add(kh);ed.onKeyUp.add(kh);}else t._pendingStyles=0;},_getSelectedBlocks:function(st,en){var ed=this.editor,dom=ed.dom,s=ed.selection,sb,eb,n,bl=[];sb=dom.getParent(st||s.getStart(),isBlock);eb=dom.getParent(en||s.getEnd(),isBlock);if(sb)bl.push(sb);if(sb&&eb&&sb!=eb){n=sb;while((n=n.nextSibling)&&n!=eb){if(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==0||t.index==t.data.length)?t.index-1:t.index];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,n,eid;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){if(r.startContainer.nodeType==1&&(n=r.startContainer.childNodes[r.startOffset])&&n.nodeType==1){eid=n.getAttribute("id");n.setAttribute("id","__mce");}else{if(ed.dom.getParent(r.startContainer,function(e){return e===b;})){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=b.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){}}}else if(!isIE&&(n=ed.dom.get('__mce'))){if(eid)n.setAttribute('id',eid);else n.removeAttribute('id');r=d.createRange();r.setStartBefore(n);r.setEndBefore(n);se.setRng(r);}},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,car;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='
    ';function appendStyles(e,en){var nl=[],nn,n,i;e.innerHTML='';if(se.keep_styles){n=en;do{if(/^(SPAN|STRONG|B|EM|I|FONT|STRIKE|U)$/.test(n.nodeName)){nn=n.cloneNode(false);dom.setAttrib(nn,'id','');nl.push(nn);}}while(n=n.parentNode);}if(nl.length>0){for(i=nl.length-1,nn=e;i>=0;i--)nn=nn.appendChild(nl[i]);nl[0].innerHTML=isOpera?' ':'
    ';return nl[0];}else e.innerHTML=isOpera?' ':'
    ';};if(isEmpty(aft))car=appendStyles(aft,en);if(isOpera&&parseFloat(opera.version())<9.5){r.insertNode(bef);r.insertNode(aft);}else{r.insertNode(aft);r.insertNode(bef);}aft.normalize();bef.normalize();function first(n){return d.createTreeWalker(n,NodeFilter.SHOW_TEXT,null,false).nextNode()||n;};r=d.createRange();r.selectNodeContents(isGecko?first(car||aft):car||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); + }, + + confirm : function(t, cb, s) { + this.editor.windowManager.confirm(t, cb, s, window); + }, + + alert : function(tx, cb, s) { + this.editor.windowManager.alert(tx, cb, s, window); + }, + + close : function() { + var t = this; + + // To avoid domain relaxing issue in Opera + function close() { + t.editor.windowManager.close(window); + 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, nv; + + // Translate page + if (t.features.translate_i18n !== false) { + 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',''); + + if ((nv = t.editor.translate(h)) && nv != h) + document.body.innerHTML = nv; + + if ((nv = t.editor.translate(ti)) && nv != ti) + document.title = ti = nv; + } + + 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(window, ti); + 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 || (tinymce.isOpera && parseFloat(opera.version()) >= 9.5)) + 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 { + if (!s.readonly) + 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); + + if (!s.readonly) + 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, + element_format : s.element_format, + 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; + + if (!s.readonly) + 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(/^(]*>( | |\s|\u00a0|)<\/p>[\r\n]*|
    [\r\n]*)$/, ''); + }); + } + + if (isGecko && !s.readonly) { + 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, ce = t.settings.content_editable; + + if (!sf) { + // Is not content editable or the selection is outside the area in IE + // the IE statement is needed to avoid bluring if element selections inside layers since + // the layer is like it's own document in IE + if (!ce && (!isIE || t.selection.getNode().ownerDocument != t.getDoc())) + 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 || 'en', 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 || 'en') + '.' + 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; + + // Command 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; + + if (e) { + 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 (!e || !t.initialized) + return; + + o = o || {}; + o.save = true; + + // Add undo level will trigger onchange event + if (!o.no_events) { + t.undoManager.typing = 0; + t.undoManager.add(); + } + + 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(), '
    '); + 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; + + if (!o.no_events) + 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.getBody(), 'mousedown', function(e) { + if (e.ctrlKey) { + e.fakeType = 'contextmenu'; + eventHandler(e); + } + }); + } else + Event.add(t.getBody(), 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 && !s.readonly) { + 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()) + try {d.execCommand("useCSS", 0, true);} catch (ex) {} + } + + 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) { + var c = e.keyCode; + + if ((c >= 33 && c <= 36) || (c >= 37 && c <= 40) || c == 13 || c == 45 || c == 46 || c == 8 || (tinymce.isMac && (c == 91 || c == 93)) || 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 (tinymce.isMac && o.ctrl != e.metaKey) + return; + else if (!tinymce.isMac && o.ctrl != e.ctrlKey) + 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 process(no) { + var n, sp, nl, x; + + // Keep unit tests happy + if (!s.inline_styles) + return; + + nl = t.dom.select('font', no); + 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); + } + }; + + // Run on cleanup + t.onPreProcess.add(function(ed, o) { + if (o.get) + process(o.node); + }); + + t.onSetContent.add(function(ed, o) { + if (o.initial) + process(o.node); + }); + }, + + _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; + + function isBlock(n) { + return /^(H[1-6]|HR|P|DIV|ADDRESS|PRE|FORM|TABLE|OL|UL|TD|CAPTION|BLOCKQUOTE|CENTER|DL|DT|DD|DIR|FIELDSET|NOSCRIPT|NOFRAMES|MENU|ISINDEX|SAMP)$/.test(n.nodeName); + }; + + 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 { + if (ed.settings.convert_fonts_to_spans) + t._applyInlineStyle('span', {style : {fontFamily : v}}); + else + ed.getDoc().execCommand('FontName', false, v); + } + }, + + FontSize : function(u, v) { + var ed = this.editor, s = ed.settings, fc, fs; + + // Use style options instead + if (s.convert_fonts_to_spans && v >= 1 && v <= 7) { + fs = tinymce.explode(s.font_size_style_values); + fc = tinymce.explode(s.font_size_classes); + + if (fc) + v = fc[v - 1] || v; + else + v = fs[v - 1] || v; + } + + if (v >= 1 && v <= 7) + ed.getDoc().execCommand('FontSize', false, v); + else + this._applyInlineStyle('span', {style : {fontSize : 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 (p = ed.dom.getParent(ed.selection.getNode(), 'SPAN')) + v = p.style.fontSize; + + if (!v && (isOpera || isWebKit)) { + if (p = ed.dom.getParent(ed.selection.getNode(), 'FONT')) + v = p.size; + + return v; + } + + return v || 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 (p = ed.dom.getParent(ed.selection.getNode(), 'SPAN')) + v = p.style.fontFamily.replace(/, /g, ',').replace(/[\'\"]/g, '').toLowerCase(); + + 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(bl || n.parentNode, 'textAlign', ''); + + dom.setStyle(n, 'float', ''); + this.mceRepaint(); + return; + } + + if (v == 'center') { + // Do not change table elements + if (bl && /^(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(bl || 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()) && !ed.settings.force_span_wrappers) + 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; + + if (ed.settings.force_span_wrappers && p.nodeName != 'SPAN') + 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); + }, + + ForeColor : function(ui, v) { + var ed = this.editor; + + if (ed.settings.convert_fonts_to_spans) { + this._applyInlineStyle('span', {style : {color : v}}); + return; + } else + ed.getDoc().execCommand('ForeColor', false, v); + }, + + HiliteColor : function(ui, val) { + var t = this, ed = t.editor, d = ed.getDoc(); + + if (ed.settings.convert_fonts_to_spans) { + this._applyInlineStyle('span', {style : {backgroundColor : val}}); + return; + } + + 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, s = ed.selection, dom = ed.dom, bl, nb, b; + + function isBlock(n) { + return /^(P|DIV|H[1-6]|ADDRESS|BLOCKQUOTE|PRE)$/.test(n.nodeName); + }; + + bl = dom.getParent(s.getNode(), function(n) { + return isBlock(n); + }); + + // IE has an issue where it removes the parent div if you change format on the paragrah in

    Content

    + // FF and Opera doesn't change parent DIV elements if you switch format + if (bl) { + if ((isIE && isBlock(bl.parentNode)) || bl.nodeName == 'DIV') { + // Rename block element + nb = ed.dom.create(val); + + each(dom.getAttribs(bl), function(v) { + dom.setAttrib(nb, v.nodeName, dom.getAttrib(bl, v.nodeName)); + }); + + b = s.getBookmark(); + dom.replace(nb, bl, 1); + s.moveToBookmark(b); + ed.nodeChanged(); + return; + } + } + + val = ed.settings.forced_root_block ? (val || '

    ') : val; + + 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; + } + + return this.queryStateInsertUnorderedList() || this.queryStateInsertOrderedList() || (!ed.settings.inline_styles && !!ed.dom.getParent(ed.selection.getNode(), 'BLOCKQUOTE')); + }, + + 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(), isBlock); + eb = dom.getParent(s.getEnd(), 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(), 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); + }, + + _applyInlineStyle : function(na, at, op) { + var t = this, ed = t.editor, dom = ed.dom, bm, lo = {}, kh; + + na = na.toUpperCase(); + + if (op && op.check_classes && at['class']) + op.check_classes.push(at['class']); + + function replaceFonts() { + var bm; + + each(dom.select(tinymce.isWebKit && !tinymce.isAir ? 'span' : 'font'), function(n) { + if (n.style.fontFamily == 'mceinline' || n.face == 'mceinline') { + if (!bm) + bm = ed.selection.getBookmark(); + + at._mce_new = '1'; + dom.replace(dom.create(na, at), n, 1); + } + }); + + // Remove redundant elements + each(dom.select(na), function(n) { + if (n.getAttribute('_mce_new')) { + function removeStyle(n) { + if (n.nodeType == 1) { + each(at.style, function(v, k) { + dom.setStyle(n, k, ''); + }); + + // Remove spans with the same class or marked classes + if (at['class'] && n.className && op) { + each(op.check_classes, function(c) { + if (dom.hasClass(n, c)) + dom.removeClass(n, c); + }); + } + } + }; + + // Remove specified style information from child elements + each(dom.select(na, n), removeStyle); + + // Remove the specified style information on parent if current node is only child (IE) + if (n.parentNode && n.parentNode.nodeType == 1 && n.parentNode.childNodes.length == 1) + removeStyle(n.parentNode); + + // Remove the child elements style info if a parent already has it + dom.getParent(n.parentNode, function(pn) { + if (pn.nodeType == 1) { + if (at.style) { + each(at.style, function(v, k) { + var sv; + + if (!lo[k] && (sv = dom.getStyle(pn, k))) { + if (sv === v) + dom.setStyle(n, k, ''); + + lo[k] = 1; + } + }); + } + + // Remove spans with the same class or marked classes + if (at['class'] && pn.className && op) { + each(op.check_classes, function(c) { + if (dom.hasClass(pn, c)) + dom.removeClass(n, c); + }); + } + } + + return false; + }); + + n.removeAttribute('_mce_new'); + } + }); + + // Remove empty span elements + each(dom.select(na).reverse(), function(n) { + var c = 0; + + // Check if there is any attributes + each(dom.getAttribs(n), function(an) { + if (an.nodeName.substring(0, 1) != '_' && dom.getAttrib(n, an.nodeName) != '') { + //console.log(dom.getOuterHTML(n), dom.getAttrib(n, an.nodeName)); + c++; + } + }); + + // No attributes then remove the element and keep the children + if (c == 0) + dom.remove(n, 1); + }); + + ed.selection.moveToBookmark(bm); + + return !!bm; + }; + + // Create inline elements + ed.focus(); + ed.getDoc().execCommand('FontName', false, 'mceinline'); + replaceFonts(); + + if (kh = t._applyInlineStyle.keyhandler) { + ed.onKeyUp.remove(kh); + ed.onKeyPress.remove(kh); + ed.onKeyDown.remove(kh); + ed.onSetContent.remove(t._applyInlineStyle.chandler); + } + + if (ed.selection.isCollapsed()) { + // Start collecting styles + t._pendingStyles = tinymce.extend(t._pendingStyles || {}, at.style); + + t._applyInlineStyle.chandler = ed.onSetContent.add(function() { + delete t._pendingStyles; + }); + + t._applyInlineStyle.keyhandler = kh = function(e) { + // Use pending styles + if (t._pendingStyles) { + at.style = t._pendingStyles; + delete t._pendingStyles; + } + + if (replaceFonts()) { + ed.onKeyDown.remove(t._applyInlineStyle.keyhandler); + ed.onKeyPress.remove(t._applyInlineStyle.keyhandler); + } + + if (e.type == 'keyup') + ed.onKeyUp.remove(t._applyInlineStyle.keyhandler); + }; + + ed.onKeyDown.add(kh); + ed.onKeyPress.add(kh); + ed.onKeyUp.add(kh); + } else + t._pendingStyles = 0; + }, + +/* + _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(), isBlock); + eb = dom.getParent(en || s.getEnd(), isBlock); + + if (sb) + bl.push(sb); + + if (sb && eb && sb != eb) { + n = sb; + + while ((n = n.nextSibling) && n != eb) { + if (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 == 0 || t.index == t.data.length) ? t.index - 1 : t.index]; + 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.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, n, eid; + + // 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) { + // If selection is element then mark it + if (r.startContainer.nodeType == 1 && (n = r.startContainer.childNodes[r.startOffset]) && n.nodeType == 1) { + // Save the id of the selected element + eid = n.getAttribute("id"); + n.setAttribute("id", "__mce"); + } else { + // If element is inside body, might not be the case in contentEdiable mode + if (ed.dom.getParent(r.startContainer, function(e) {return e === b;})) { + 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 = b.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 + } + } + } else if (!isIE && (n = ed.dom.get('__mce'))) { + // Restore the id of the selected element + if (eid) + n.setAttribute('id', eid); + else + n.removeAttribute('id'); + + // Move caret before selected element + r = d.createRange(); + r.setStartBefore(n); + r.setEndBefore(n); + se.setRng(r); + } + }, + + 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, car; + + 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 = '
    '; + + function appendStyles(e, en) { + var nl = [], nn, n, i; + + e.innerHTML = ''; + + // Make clones of style elements + if (se.keep_styles) { + n = en; + do { + // We only want style specific elements + if (/^(SPAN|STRONG|B|EM|I|FONT|STRIKE|U)$/.test(n.nodeName)) { + nn = n.cloneNode(false); + dom.setAttrib(nn, 'id', ''); // Remove ID since it needs to be unique + nl.push(nn); + } + } while (n = n.parentNode); + } + + // Append style elements to aft + if (nl.length > 0) { + for (i = nl.length - 1, nn = e; i >= 0; i--) + nn = nn.appendChild(nl[i]); + + // Padd most inner style element + nl[0].innerHTML = isOpera ? ' ' : '
    '; // Extra space for Opera so that the caret can move there + return nl[0]; // Move caret to most inner element + } else + e.innerHTML = isOpera ? ' ' : '
    '; // Extra space for Opera so that the caret can move there + }; + + // Fill empty afterblook with current style + if (isEmpty(aft)) + car = appendStyles(aft, en); + + // Opera needs this one backwards for older versions + if (isOpera && parseFloat(opera.version()) < 9.5) { + r.insertNode(bef); + r.insertNode(aft); + } else { + r.insertNode(aft); + r.insertNode(bef); + } + + // Normalize + aft.normalize(); + bef.normalize(); + + function first(n) { + return d.createTreeWalker(n, NodeFilter.SHOW_TEXT, null, false).nextNode() || n; + }; + + // Move cursor and scroll into view + r = d.createRange(); + r.selectNodeContents(isGecko ? first(car || aft) : car || 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 + 25); // Needs to be hardcoded to roughly one line of text if a huge text block is broken into two blocks + //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) { + var pr; + + 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))) { + pr = e.previousSibling; + + Event.remove(b, 'DOMNodeInserted', handler); + + // Is there whitespace at the end of the node before then we might need the pesky BR + // to place the caret at a correct location see bug: #2013943 + if (pr && pr.nodeType == 3 && /\s+$/.test(pr.nodeValue)) + return; + + // 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() { + bm = ed.selection.getBookmark(1); + }); + + 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, cc) { + s = s || {}; + s.menu_button = 1; + + return this.createButton(id, s, cc); + }, + + 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, bm; + + 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(); + }); + + // Fix for bug #1897785, #1898007 + if (tinymce.isIE) { + c.onShowMenu.add(function() { + bm = ed.selection.getBookmark(1); + }); + + c.onHideMenu.add(function() { + if (bm) { + ed.selection.moveToBookmark(bm); + bm = 0; + } + }); + } + + 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; + } + } + + // 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, w) { + w = w || window; + + cb.call(s || this, w.confirm(this._decode(this.editor.getLang(t, t)))); + }, + + alert : function(tx, cb, s, w) { + var t = this; + + w = w || window; + w.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/include/javascript/tiny_mce/utils/editable_selects.js b/include/javascript/tiny_mce/utils/editable_selects.js new file mode 100644 index 00000000..15a2a09d --- /dev/null +++ b/include/javascript/tiny_mce/utils/editable_selects.js @@ -0,0 +1,69 @@ +/** + + * + * 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; i0)?F:0;}if(C in D&&!("style" in D&&C in D.style)){D[C]=F;}else{B.Dom.setStyle(D,C,F+E);}},getAttribute:function(C){var E=this.getEl();var G=B.Dom.getStyle(E,C);if(G!=="auto"&&!this.patterns.offsetUnit.test(G)){return parseFloat(G);}var D=this.patterns.offsetAttribute.exec(C)||[];var H=!!(D[3]);var F=!!(D[2]);if("style" in E){if(F||(B.Dom.getStyle(E,"position")=="absolute"&&H)){G=E["offset"+D[0].charAt(0).toUpperCase()+D[0].substr(1)];}else{G=0;}}else{if(C in E){G=E[C];}}return G;},getDefaultUnit:function(C){if(this.patterns.defaultUnit.test(C)){return"px";}return"";},setRuntimeAttribute:function(D){var I;var E;var F=this.attributes;this.runtimeAttributes[D]={};var H=function(J){return(typeof J!=="undefined");};if(!H(F[D]["to"])&&!H(F[D]["by"])){return false;}I=(H(F[D]["from"]))?F[D]["from"]:this.getAttribute(D);if(H(F[D]["to"])){E=F[D]["to"];}else{if(H(F[D]["by"])){if(I.constructor==Array){E=[];for(var G=0,C=I.length;G0&&isFinite(K)){if(G.currentFrame+K>=J){K=J-(I+1);}G.currentFrame+=K;}};this._queue=B;this._getIndex=E;};YAHOO.util.Bezier=new function(){this.getPosition=function(E,D){var F=E.length;var C=[];for(var B=0;B0&&!(L[0] instanceof Array)){L=[L];}else{var K=[];for(M=0,O=L.length;M0){this.runtimeAttributes[P]=this.runtimeAttributes[P].concat(L);}this.runtimeAttributes[P][this.runtimeAttributes[P].length]=I;}else{F.setRuntimeAttribute.call(this,P);}};var B=function(G,I){var H=E.Dom.getXY(this.getEl());G=[G[0]-H[0]+I[0],G[1]-H[1]+I[1]];return G;};var D=function(G){return(typeof G!=="undefined");};E.Motion=A;})();(function(){var D=function(F,E,G,H){if(F){D.superclass.constructor.call(this,F,E,G,H);}};D.NAME="Scroll";var B=YAHOO.util;YAHOO.extend(D,B.ColorAnim);var C=D.superclass;var A=D.prototype;A.doMethod=function(E,H,F){var G=null;if(E=="scroll"){G=[this.method(this.currentFrame,H[0],F[0]-H[0],this.totalFrames),this.method(this.currentFrame,H[1],F[1]-H[1],this.totalFrames)];}else{G=C.doMethod.call(this,E,H,F);}return G;};A.getAttribute=function(E){var G=null;var F=this.getEl();if(E=="scroll"){G=[F.scrollLeft,F.scrollTop];}else{G=C.getAttribute.call(this,E);}return G;};A.setAttribute=function(E,H,G){var F=this.getEl();if(E=="scroll"){F.scrollLeft=H[0];F.scrollTop=H[1];}else{C.setAttribute.call(this,E,H,G);}};B.Scroll=D;})();YAHOO.register("animation",YAHOO.util.Anim,{version:"2.8.0r4",build:"2449"}); \ No newline at end of file diff --git a/include/javascript/yui/build/animation/animation.js b/include/javascript/yui/build/animation/animation.js new file mode 100644 index 00000000..5737b68b --- /dev/null +++ b/include/javascript/yui/build/animation/animation.js @@ -0,0 +1,1392 @@ +/* +Copyright (c) 2009, Yahoo! Inc. All rights reserved. +Code licensed under the BSD License: +http://developer.yahoo.net/yui/license.txt +version: 2.8.0r4 +*/ +(function() { + +var Y = YAHOO.util; + +/* +Copyright (c) 2006, Yahoo! Inc. All rights reserved. +Code licensed under the BSD License: +http://developer.yahoo.net/yui/license.txt +*/ + +/** + * The animation module provides allows effects to be added to HTMLElements. + * @module animation + * @requires yahoo, event, dom + */ + +/** + * + * Base animation class that provides the interface for building animated effects. + *

    Usage: var myAnim = new YAHOO.util.Anim(el, { width: { from: 10, to: 100 } }, 1, YAHOO.util.Easing.easeOut);

    + * @class Anim + * @namespace YAHOO.util + * @requires YAHOO.util.AnimMgr + * @requires YAHOO.util.Easing + * @requires YAHOO.util.Dom + * @requires YAHOO.util.Event + * @requires YAHOO.util.CustomEvent + * @constructor + * @param {String | HTMLElement} el Reference to the element that will be animated + * @param {Object} attributes The attribute(s) to be animated. + * Each attribute is an object with at minimum a "to" or "by" member defined. + * Additional optional members are "from" (defaults to current value), "units" (defaults to "px"). + * All attribute names use camelCase. + * @param {Number} duration (optional, defaults to 1 second) Length of animation (frames or seconds), defaults to time-based + * @param {Function} method (optional, defaults to YAHOO.util.Easing.easeNone) Computes the values that are applied to the attributes per frame (generally a YAHOO.util.Easing method) + */ + +var Anim = function(el, attributes, duration, method) { + if (!el) { + } + this.init(el, attributes, duration, method); +}; + +Anim.NAME = 'Anim'; + +Anim.prototype = { + /** + * Provides a readable name for the Anim instance. + * @method toString + * @return {String} + */ + toString: function() { + var el = this.getEl() || {}; + var id = el.id || el.tagName; + return (this.constructor.NAME + ': ' + id); + }, + + patterns: { // cached for performance + noNegatives: /width|height|opacity|padding/i, // keep at zero or above + offsetAttribute: /^((width|height)|(top|left))$/, // use offsetValue as default + defaultUnit: /width|height|top$|bottom$|left$|right$/i, // use 'px' by default + offsetUnit: /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i // IE may return these, so convert these to offset + }, + + /** + * Returns the value computed by the animation's "method". + * @method doMethod + * @param {String} attr The name of the attribute. + * @param {Number} start The value this attribute should start from for this animation. + * @param {Number} end The value this attribute should end at for this animation. + * @return {Number} The Value to be applied to the attribute. + */ + doMethod: function(attr, start, end) { + return this.method(this.currentFrame, start, end - start, this.totalFrames); + }, + + /** + * Applies a value to an attribute. + * @method setAttribute + * @param {String} attr The name of the attribute. + * @param {Number} val The value to be applied to the attribute. + * @param {String} unit The unit ('px', '%', etc.) of the value. + */ + setAttribute: function(attr, val, unit) { + var el = this.getEl(); + if ( this.patterns.noNegatives.test(attr) ) { + val = (val > 0) ? val : 0; + } + + if (attr in el && !('style' in el && attr in el.style)) { + el[attr] = val; + } else { + Y.Dom.setStyle(el, attr, val + unit); + } + }, + + /** + * Returns current value of the attribute. + * @method getAttribute + * @param {String} attr The name of the attribute. + * @return {Number} val The current value of the attribute. + */ + getAttribute: function(attr) { + var el = this.getEl(); + var val = Y.Dom.getStyle(el, attr); + + if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) { + return parseFloat(val); + } + + var a = this.patterns.offsetAttribute.exec(attr) || []; + var pos = !!( a[3] ); // top or left + var box = !!( a[2] ); // width or height + + if ('style' in el) { + // use offsets for width/height and abs pos top/left + if ( box || (Y.Dom.getStyle(el, 'position') == 'absolute' && pos) ) { + val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)]; + } else { // default to zero for other 'auto' + val = 0; + } + } else if (attr in el) { + val = el[attr]; + } + + return val; + }, + + /** + * Returns the unit to use when none is supplied. + * @method getDefaultUnit + * @param {attr} attr The name of the attribute. + * @return {String} The default unit to be used. + */ + getDefaultUnit: function(attr) { + if ( this.patterns.defaultUnit.test(attr) ) { + return 'px'; + } + + return ''; + }, + + /** + * Sets the actual values to be used during the animation. Should only be needed for subclass use. + * @method setRuntimeAttribute + * @param {Object} attr The attribute object + * @private + */ + setRuntimeAttribute: function(attr) { + var start; + var end; + var attributes = this.attributes; + + this.runtimeAttributes[attr] = {}; + + var isset = function(prop) { + return (typeof prop !== 'undefined'); + }; + + if ( !isset(attributes[attr]['to']) && !isset(attributes[attr]['by']) ) { + return false; // note return; nothing to animate to + } + + start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr); + + // To beats by, per SMIL 2.1 spec + if ( isset(attributes[attr]['to']) ) { + end = attributes[attr]['to']; + } else if ( isset(attributes[attr]['by']) ) { + if (start.constructor == Array) { + end = []; + for (var i = 0, len = start.length; i < len; ++i) { + end[i] = start[i] + attributes[attr]['by'][i] * 1; // times 1 to cast "by" + } + } else { + end = start + attributes[attr]['by'] * 1; + } + } + + this.runtimeAttributes[attr].start = start; + this.runtimeAttributes[attr].end = end; + + // set units if needed + this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? + attributes[attr]['unit'] : this.getDefaultUnit(attr); + return true; + }, + + /** + * Constructor for Anim instance. + * @method init + * @param {String | HTMLElement} el Reference to the element that will be animated + * @param {Object} attributes The attribute(s) to be animated. + * Each attribute is an object with at minimum a "to" or "by" member defined. + * Additional optional members are "from" (defaults to current value), "units" (defaults to "px"). + * All attribute names use camelCase. + * @param {Number} duration (optional, defaults to 1 second) Length of animation (frames or seconds), defaults to time-based + * @param {Function} method (optional, defaults to YAHOO.util.Easing.easeNone) Computes the values that are applied to the attributes per frame (generally a YAHOO.util.Easing method) + */ + init: function(el, attributes, duration, method) { + /** + * Whether or not the animation is running. + * @property isAnimated + * @private + * @type Boolean + */ + var isAnimated = false; + + /** + * A Date object that is created when the animation begins. + * @property startTime + * @private + * @type Date + */ + var startTime = null; + + /** + * The number of frames this animation was able to execute. + * @property actualFrames + * @private + * @type Int + */ + var actualFrames = 0; + + /** + * The element to be animated. + * @property el + * @private + * @type HTMLElement + */ + el = Y.Dom.get(el); + + /** + * The collection of attributes to be animated. + * Each attribute must have at least a "to" or "by" defined in order to animate. + * If "to" is supplied, the animation will end with the attribute at that value. + * If "by" is supplied, the animation will end at that value plus its starting value. + * If both are supplied, "to" is used, and "by" is ignored. + * Optional additional member include "from" (the value the attribute should start animating from, defaults to current value), and "unit" (the units to apply to the values). + * @property attributes + * @type Object + */ + this.attributes = attributes || {}; + + /** + * The length of the animation. Defaults to "1" (second). + * @property duration + * @type Number + */ + this.duration = !YAHOO.lang.isUndefined(duration) ? duration : 1; + + /** + * The method that will provide values to the attribute(s) during the animation. + * Defaults to "YAHOO.util.Easing.easeNone". + * @property method + * @type Function + */ + this.method = method || Y.Easing.easeNone; + + /** + * Whether or not the duration should be treated as seconds. + * Defaults to true. + * @property useSeconds + * @type Boolean + */ + this.useSeconds = true; // default to seconds + + /** + * The location of the current animation on the timeline. + * In time-based animations, this is used by AnimMgr to ensure the animation finishes on time. + * @property currentFrame + * @type Int + */ + this.currentFrame = 0; + + /** + * The total number of frames to be executed. + * In time-based animations, this is used by AnimMgr to ensure the animation finishes on time. + * @property totalFrames + * @type Int + */ + this.totalFrames = Y.AnimMgr.fps; + + /** + * Changes the animated element + * @method setEl + */ + this.setEl = function(element) { + el = Y.Dom.get(element); + }; + + /** + * Returns a reference to the animated element. + * @method getEl + * @return {HTMLElement} + */ + this.getEl = function() { return el; }; + + /** + * Checks whether the element is currently animated. + * @method isAnimated + * @return {Boolean} current value of isAnimated. + */ + this.isAnimated = function() { + return isAnimated; + }; + + /** + * Returns the animation start time. + * @method getStartTime + * @return {Date} current value of startTime. + */ + this.getStartTime = function() { + return startTime; + }; + + this.runtimeAttributes = {}; + + + + /** + * Starts the animation by registering it with the animation manager. + * @method animate + */ + this.animate = function() { + if ( this.isAnimated() ) { + return false; + } + + this.currentFrame = 0; + + this.totalFrames = ( this.useSeconds ) ? Math.ceil(Y.AnimMgr.fps * this.duration) : this.duration; + + if (this.duration === 0 && this.useSeconds) { // jump to last frame if zero second duration + this.totalFrames = 1; + } + Y.AnimMgr.registerElement(this); + return true; + }; + + /** + * Stops the animation. Normally called by AnimMgr when animation completes. + * @method stop + * @param {Boolean} finish (optional) If true, animation will jump to final frame. + */ + this.stop = function(finish) { + if (!this.isAnimated()) { // nothing to stop + return false; + } + + if (finish) { + this.currentFrame = this.totalFrames; + this._onTween.fire(); + } + Y.AnimMgr.stop(this); + }; + + var onStart = function() { + this.onStart.fire(); + + this.runtimeAttributes = {}; + for (var attr in this.attributes) { + this.setRuntimeAttribute(attr); + } + + isAnimated = true; + actualFrames = 0; + startTime = new Date(); + }; + + /** + * Feeds the starting and ending values for each animated attribute to doMethod once per frame, then applies the resulting value to the attribute(s). + * @private + */ + + var onTween = function() { + var data = { + duration: new Date() - this.getStartTime(), + currentFrame: this.currentFrame + }; + + data.toString = function() { + return ( + 'duration: ' + data.duration + + ', currentFrame: ' + data.currentFrame + ); + }; + + this.onTween.fire(data); + + var runtimeAttributes = this.runtimeAttributes; + + for (var attr in runtimeAttributes) { + this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit); + } + + actualFrames += 1; + }; + + var onComplete = function() { + var actual_duration = (new Date() - startTime) / 1000 ; + + var data = { + duration: actual_duration, + frames: actualFrames, + fps: actualFrames / actual_duration + }; + + data.toString = function() { + return ( + 'duration: ' + data.duration + + ', frames: ' + data.frames + + ', fps: ' + data.fps + ); + }; + + isAnimated = false; + actualFrames = 0; + this.onComplete.fire(data); + }; + + /** + * Custom event that fires after onStart, useful in subclassing + * @private + */ + this._onStart = new Y.CustomEvent('_start', this, true); + + /** + * Custom event that fires when animation begins + * Listen via subscribe method (e.g. myAnim.onStart.subscribe(someFunction) + * @event onStart + */ + this.onStart = new Y.CustomEvent('start', this); + + /** + * Custom event that fires between each frame + * Listen via subscribe method (e.g. myAnim.onTween.subscribe(someFunction) + * @event onTween + */ + this.onTween = new Y.CustomEvent('tween', this); + + /** + * Custom event that fires after onTween + * @private + */ + this._onTween = new Y.CustomEvent('_tween', this, true); + + /** + * Custom event that fires when animation ends + * Listen via subscribe method (e.g. myAnim.onComplete.subscribe(someFunction) + * @event onComplete + */ + this.onComplete = new Y.CustomEvent('complete', this); + /** + * Custom event that fires after onComplete + * @private + */ + this._onComplete = new Y.CustomEvent('_complete', this, true); + + this._onStart.subscribe(onStart); + this._onTween.subscribe(onTween); + this._onComplete.subscribe(onComplete); + } +}; + + Y.Anim = Anim; +})(); +/** + * Handles animation queueing and threading. + * Used by Anim and subclasses. + * @class AnimMgr + * @namespace YAHOO.util + */ +YAHOO.util.AnimMgr = new function() { + /** + * Reference to the animation Interval. + * @property thread + * @private + * @type Int + */ + var thread = null; + + /** + * The current queue of registered animation objects. + * @property queue + * @private + * @type Array + */ + var queue = []; + + /** + * The number of active animations. + * @property tweenCount + * @private + * @type Int + */ + var tweenCount = 0; + + /** + * Base frame rate (frames per second). + * Arbitrarily high for better x-browser calibration (slower browsers drop more frames). + * @property fps + * @type Int + * + */ + this.fps = 1000; + + /** + * Interval delay in milliseconds, defaults to fastest possible. + * @property delay + * @type Int + * + */ + this.delay = 1; + + /** + * Adds an animation instance to the animation queue. + * All animation instances must be registered in order to animate. + * @method registerElement + * @param {object} tween The Anim instance to be be registered + */ + this.registerElement = function(tween) { + queue[queue.length] = tween; + tweenCount += 1; + tween._onStart.fire(); + this.start(); + }; + + /** + * removes an animation instance from the animation queue. + * All animation instances must be registered in order to animate. + * @method unRegister + * @param {object} tween The Anim instance to be be registered + * @param {Int} index The index of the Anim instance + * @private + */ + this.unRegister = function(tween, index) { + index = index || getIndex(tween); + if (!tween.isAnimated() || index === -1) { + return false; + } + + tween._onComplete.fire(); + queue.splice(index, 1); + + tweenCount -= 1; + if (tweenCount <= 0) { + this.stop(); + } + + return true; + }; + + /** + * Starts the animation thread. + * Only one thread can run at a time. + * @method start + */ + this.start = function() { + if (thread === null) { + thread = setInterval(this.run, this.delay); + } + }; + + /** + * Stops the animation thread or a specific animation instance. + * @method stop + * @param {object} tween A specific Anim instance to stop (optional) + * If no instance given, Manager stops thread and all animations. + */ + this.stop = function(tween) { + if (!tween) { + clearInterval(thread); + + for (var i = 0, len = queue.length; i < len; ++i) { + this.unRegister(queue[0], 0); + } + + queue = []; + thread = null; + tweenCount = 0; + } + else { + this.unRegister(tween); + } + }; + + /** + * Called per Interval to handle each animation frame. + * @method run + */ + this.run = function() { + for (var i = 0, len = queue.length; i < len; ++i) { + var tween = queue[i]; + if ( !tween || !tween.isAnimated() ) { continue; } + + if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null) + { + tween.currentFrame += 1; + + if (tween.useSeconds) { + correctFrame(tween); + } + tween._onTween.fire(); + } + else { YAHOO.util.AnimMgr.stop(tween, i); } + } + }; + + var getIndex = function(anim) { + for (var i = 0, len = queue.length; i < len; ++i) { + if (queue[i] === anim) { + return i; // note return; + } + } + return -1; + }; + + /** + * On the fly frame correction to keep animation on time. + * @method correctFrame + * @private + * @param {Object} tween The Anim instance being corrected. + */ + var correctFrame = function(tween) { + var frames = tween.totalFrames; + var frame = tween.currentFrame; + var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames); + var elapsed = (new Date() - tween.getStartTime()); + var tweak = 0; + + if (elapsed < tween.duration * 1000) { // check if falling behind + tweak = Math.round((elapsed / expected - 1) * tween.currentFrame); + } else { // went over duration, so jump to end + tweak = frames - (frame + 1); + } + if (tweak > 0 && isFinite(tweak)) { // adjust if needed + if (tween.currentFrame + tweak >= frames) {// dont go past last frame + tweak = frames - (frame + 1); + } + + tween.currentFrame += tweak; + } + }; + this._queue = queue; + this._getIndex = getIndex; +}; +/** + * Used to calculate Bezier splines for any number of control points. + * @class Bezier + * @namespace YAHOO.util + * + */ +YAHOO.util.Bezier = new function() { + /** + * Get the current position of the animated element based on t. + * Each point is an array of "x" and "y" values (0 = x, 1 = y) + * At least 2 points are required (start and end). + * First point is start. Last point is end. + * Additional control points are optional. + * @method getPosition + * @param {Array} points An array containing Bezier points + * @param {Number} t A number between 0 and 1 which is the basis for determining current position + * @return {Array} An array containing int x and y member data + */ + this.getPosition = function(points, t) { + var n = points.length; + var tmp = []; + + for (var i = 0; i < n; ++i){ + tmp[i] = [points[i][0], points[i][1]]; // save input + } + + for (var j = 1; j < n; ++j) { + for (i = 0; i < n - j; ++i) { + tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0]; + tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1]; + } + } + + return [ tmp[0][0], tmp[0][1] ]; + + }; +}; +(function() { +/** + * Anim subclass for color transitions. + *

    Usage: var myAnim = new Y.ColorAnim(el, { backgroundColor: { from: '#FF0000', to: '#FFFFFF' } }, 1, Y.Easing.easeOut); Color values can be specified with either 112233, #112233, + * [255,255,255], or rgb(255,255,255)

    + * @class ColorAnim + * @namespace YAHOO.util + * @requires YAHOO.util.Anim + * @requires YAHOO.util.AnimMgr + * @requires YAHOO.util.Easing + * @requires YAHOO.util.Bezier + * @requires YAHOO.util.Dom + * @requires YAHOO.util.Event + * @constructor + * @extends YAHOO.util.Anim + * @param {HTMLElement | String} el Reference to the element that will be animated + * @param {Object} attributes The attribute(s) to be animated. + * Each attribute is an object with at minimum a "to" or "by" member defined. + * Additional optional members are "from" (defaults to current value), "units" (defaults to "px"). + * All attribute names use camelCase. + * @param {Number} duration (optional, defaults to 1 second) Length of animation (frames or seconds), defaults to time-based + * @param {Function} method (optional, defaults to YAHOO.util.Easing.easeNone) Computes the values that are applied to the attributes per frame (generally a YAHOO.util.Easing method) + */ + var ColorAnim = function(el, attributes, duration, method) { + ColorAnim.superclass.constructor.call(this, el, attributes, duration, method); + }; + + ColorAnim.NAME = 'ColorAnim'; + + ColorAnim.DEFAULT_BGCOLOR = '#fff'; + // shorthand + var Y = YAHOO.util; + YAHOO.extend(ColorAnim, Y.Anim); + + var superclass = ColorAnim.superclass; + var proto = ColorAnim.prototype; + + proto.patterns.color = /color$/i; + proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i; + proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i; + proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i; + proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/; // need rgba for safari + + /** + * Attempts to parse the given string and return a 3-tuple. + * @method parseColor + * @param {String} s The string to parse. + * @return {Array} The 3-tuple of rgb values. + */ + proto.parseColor = function(s) { + if (s.length == 3) { return s; } + + var c = this.patterns.hex.exec(s); + if (c && c.length == 4) { + return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ]; + } + + c = this.patterns.rgb.exec(s); + if (c && c.length == 4) { + return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ]; + } + + c = this.patterns.hex3.exec(s); + if (c && c.length == 4) { + return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ]; + } + + return null; + }; + + proto.getAttribute = function(attr) { + var el = this.getEl(); + if (this.patterns.color.test(attr) ) { + var val = YAHOO.util.Dom.getStyle(el, attr); + + var that = this; + if (this.patterns.transparent.test(val)) { // bgcolor default + var parent = YAHOO.util.Dom.getAncestorBy(el, function(node) { + return !that.patterns.transparent.test(val); + }); + + if (parent) { + val = Y.Dom.getStyle(parent, attr); + } else { + val = ColorAnim.DEFAULT_BGCOLOR; + } + } + } else { + val = superclass.getAttribute.call(this, attr); + } + + return val; + }; + + proto.doMethod = function(attr, start, end) { + var val; + + if ( this.patterns.color.test(attr) ) { + val = []; + for (var i = 0, len = start.length; i < len; ++i) { + val[i] = superclass.doMethod.call(this, attr, start[i], end[i]); + } + + val = 'rgb('+Math.floor(val[0])+','+Math.floor(val[1])+','+Math.floor(val[2])+')'; + } + else { + val = superclass.doMethod.call(this, attr, start, end); + } + + return val; + }; + + proto.setRuntimeAttribute = function(attr) { + superclass.setRuntimeAttribute.call(this, attr); + + if ( this.patterns.color.test(attr) ) { + var attributes = this.attributes; + var start = this.parseColor(this.runtimeAttributes[attr].start); + var end = this.parseColor(this.runtimeAttributes[attr].end); + // fix colors if going "by" + if ( typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined' ) { + end = this.parseColor(attributes[attr].by); + + for (var i = 0, len = start.length; i < len; ++i) { + end[i] = start[i] + end[i]; + } + } + + this.runtimeAttributes[attr].start = start; + this.runtimeAttributes[attr].end = end; + } + }; + + Y.ColorAnim = ColorAnim; +})(); +/*! +TERMS OF USE - EASING EQUATIONS +Open source under the BSD License. +Copyright 2001 Robert Penner 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 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. +*/ + +/** + * Singleton that determines how an animation proceeds from start to end. + * @class Easing + * @namespace YAHOO.util +*/ + +YAHOO.util.Easing = { + + /** + * Uniform speed between points. + * @method easeNone + * @param {Number} t Time value used to compute current value + * @param {Number} b Starting value + * @param {Number} c Delta between start and end values + * @param {Number} d Total length of animation + * @return {Number} The computed value for the current animation frame + */ + easeNone: function (t, b, c, d) { + return c*t/d + b; + }, + + /** + * Begins slowly and accelerates towards end. + * @method easeIn + * @param {Number} t Time value used to compute current value + * @param {Number} b Starting value + * @param {Number} c Delta between start and end values + * @param {Number} d Total length of animation + * @return {Number} The computed value for the current animation frame + */ + easeIn: function (t, b, c, d) { + return c*(t/=d)*t + b; + }, + + /** + * Begins quickly and decelerates towards end. + * @method easeOut + * @param {Number} t Time value used to compute current value + * @param {Number} b Starting value + * @param {Number} c Delta between start and end values + * @param {Number} d Total length of animation + * @return {Number} The computed value for the current animation frame + */ + easeOut: function (t, b, c, d) { + return -c *(t/=d)*(t-2) + b; + }, + + /** + * Begins slowly and decelerates towards end. + * @method easeBoth + * @param {Number} t Time value used to compute current value + * @param {Number} b Starting value + * @param {Number} c Delta between start and end values + * @param {Number} d Total length of animation + * @return {Number} The computed value for the current animation frame + */ + easeBoth: function (t, b, c, d) { + if ((t/=d/2) < 1) { + return c/2*t*t + b; + } + + return -c/2 * ((--t)*(t-2) - 1) + b; + }, + + /** + * Begins slowly and accelerates towards end. + * @method easeInStrong + * @param {Number} t Time value used to compute current value + * @param {Number} b Starting value + * @param {Number} c Delta between start and end values + * @param {Number} d Total length of animation + * @return {Number} The computed value for the current animation frame + */ + easeInStrong: function (t, b, c, d) { + return c*(t/=d)*t*t*t + b; + }, + + /** + * Begins quickly and decelerates towards end. + * @method easeOutStrong + * @param {Number} t Time value used to compute current value + * @param {Number} b Starting value + * @param {Number} c Delta between start and end values + * @param {Number} d Total length of animation + * @return {Number} The computed value for the current animation frame + */ + easeOutStrong: function (t, b, c, d) { + return -c * ((t=t/d-1)*t*t*t - 1) + b; + }, + + /** + * Begins slowly and decelerates towards end. + * @method easeBothStrong + * @param {Number} t Time value used to compute current value + * @param {Number} b Starting value + * @param {Number} c Delta between start and end values + * @param {Number} d Total length of animation + * @return {Number} The computed value for the current animation frame + */ + easeBothStrong: function (t, b, c, d) { + if ((t/=d/2) < 1) { + return c/2*t*t*t*t + b; + } + + return -c/2 * ((t-=2)*t*t*t - 2) + b; + }, + + /** + * Snap in elastic effect. + * @method elasticIn + * @param {Number} t Time value used to compute current value + * @param {Number} b Starting value + * @param {Number} c Delta between start and end values + * @param {Number} d Total length of animation + * @param {Number} a Amplitude (optional) + * @param {Number} p Period (optional) + * @return {Number} The computed value for the current animation frame + */ + + elasticIn: function (t, b, c, d, a, p) { + if (t == 0) { + return b; + } + if ( (t /= d) == 1 ) { + return b+c; + } + if (!p) { + p=d*.3; + } + + if (!a || a < Math.abs(c)) { + a = c; + var s = p/4; + } + else { + var s = p/(2*Math.PI) * Math.asin (c/a); + } + + return -(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b; + }, + + /** + * Snap out elastic effect. + * @method elasticOut + * @param {Number} t Time value used to compute current value + * @param {Number} b Starting value + * @param {Number} c Delta between start and end values + * @param {Number} d Total length of animation + * @param {Number} a Amplitude (optional) + * @param {Number} p Period (optional) + * @return {Number} The computed value for the current animation frame + */ + elasticOut: function (t, b, c, d, a, p) { + if (t == 0) { + return b; + } + if ( (t /= d) == 1 ) { + return b+c; + } + if (!p) { + p=d*.3; + } + + if (!a || a < Math.abs(c)) { + a = c; + var s = p / 4; + } + else { + var s = p/(2*Math.PI) * Math.asin (c/a); + } + + return a*Math.pow(2,-10*t) * Math.sin( (t*d-s)*(2*Math.PI)/p ) + c + b; + }, + + /** + * Snap both elastic effect. + * @method elasticBoth + * @param {Number} t Time value used to compute current value + * @param {Number} b Starting value + * @param {Number} c Delta between start and end values + * @param {Number} d Total length of animation + * @param {Number} a Amplitude (optional) + * @param {Number} p Period (optional) + * @return {Number} The computed value for the current animation frame + */ + elasticBoth: function (t, b, c, d, a, p) { + if (t == 0) { + return b; + } + + if ( (t /= d/2) == 2 ) { + return b+c; + } + + if (!p) { + p = d*(.3*1.5); + } + + if ( !a || a < Math.abs(c) ) { + a = c; + var s = p/4; + } + else { + var s = p/(2*Math.PI) * Math.asin (c/a); + } + + if (t < 1) { + return -.5*(a*Math.pow(2,10*(t-=1)) * + Math.sin( (t*d-s)*(2*Math.PI)/p )) + b; + } + return a*Math.pow(2,-10*(t-=1)) * + Math.sin( (t*d-s)*(2*Math.PI)/p )*.5 + c + b; + }, + + + /** + * Backtracks slightly, then reverses direction and moves to end. + * @method backIn + * @param {Number} t Time value used to compute current value + * @param {Number} b Starting value + * @param {Number} c Delta between start and end values + * @param {Number} d Total length of animation + * @param {Number} s Overshoot (optional) + * @return {Number} The computed value for the current animation frame + */ + backIn: function (t, b, c, d, s) { + if (typeof s == 'undefined') { + s = 1.70158; + } + return c*(t/=d)*t*((s+1)*t - s) + b; + }, + + /** + * Overshoots end, then reverses and comes back to end. + * @method backOut + * @param {Number} t Time value used to compute current value + * @param {Number} b Starting value + * @param {Number} c Delta between start and end values + * @param {Number} d Total length of animation + * @param {Number} s Overshoot (optional) + * @return {Number} The computed value for the current animation frame + */ + backOut: function (t, b, c, d, s) { + if (typeof s == 'undefined') { + s = 1.70158; + } + return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b; + }, + + /** + * Backtracks slightly, then reverses direction, overshoots end, + * then reverses and comes back to end. + * @method backBoth + * @param {Number} t Time value used to compute current value + * @param {Number} b Starting value + * @param {Number} c Delta between start and end values + * @param {Number} d Total length of animation + * @param {Number} s Overshoot (optional) + * @return {Number} The computed value for the current animation frame + */ + backBoth: function (t, b, c, d, s) { + if (typeof s == 'undefined') { + s = 1.70158; + } + + if ((t /= d/2 ) < 1) { + return c/2*(t*t*(((s*=(1.525))+1)*t - s)) + b; + } + return c/2*((t-=2)*t*(((s*=(1.525))+1)*t + s) + 2) + b; + }, + + /** + * Bounce off of start. + * @method bounceIn + * @param {Number} t Time value used to compute current value + * @param {Number} b Starting value + * @param {Number} c Delta between start and end values + * @param {Number} d Total length of animation + * @return {Number} The computed value for the current animation frame + */ + bounceIn: function (t, b, c, d) { + return c - YAHOO.util.Easing.bounceOut(d-t, 0, c, d) + b; + }, + + /** + * Bounces off end. + * @method bounceOut + * @param {Number} t Time value used to compute current value + * @param {Number} b Starting value + * @param {Number} c Delta between start and end values + * @param {Number} d Total length of animation + * @return {Number} The computed value for the current animation frame + */ + bounceOut: function (t, b, c, d) { + if ((t/=d) < (1/2.75)) { + return c*(7.5625*t*t) + b; + } else if (t < (2/2.75)) { + return c*(7.5625*(t-=(1.5/2.75))*t + .75) + b; + } else if (t < (2.5/2.75)) { + return c*(7.5625*(t-=(2.25/2.75))*t + .9375) + b; + } + return c*(7.5625*(t-=(2.625/2.75))*t + .984375) + b; + }, + + /** + * Bounces off start and end. + * @method bounceBoth + * @param {Number} t Time value used to compute current value + * @param {Number} b Starting value + * @param {Number} c Delta between start and end values + * @param {Number} d Total length of animation + * @return {Number} The computed value for the current animation frame + */ + bounceBoth: function (t, b, c, d) { + if (t < d/2) { + return YAHOO.util.Easing.bounceIn(t*2, 0, c, d) * .5 + b; + } + return YAHOO.util.Easing.bounceOut(t*2-d, 0, c, d) * .5 + c*.5 + b; + } +}; + +(function() { +/** + * Anim subclass for moving elements along a path defined by the "points" + * member of "attributes". All "points" are arrays with x, y coordinates. + *

    Usage: var myAnim = new YAHOO.util.Motion(el, { points: { to: [800, 800] } }, 1, YAHOO.util.Easing.easeOut);

    + * @class Motion + * @namespace YAHOO.util + * @requires YAHOO.util.Anim + * @requires YAHOO.util.AnimMgr + * @requires YAHOO.util.Easing + * @requires YAHOO.util.Bezier + * @requires YAHOO.util.Dom + * @requires YAHOO.util.Event + * @requires YAHOO.util.CustomEvent + * @constructor + * @extends YAHOO.util.ColorAnim + * @param {String | HTMLElement} el Reference to the element that will be animated + * @param {Object} attributes The attribute(s) to be animated. + * Each attribute is an object with at minimum a "to" or "by" member defined. + * Additional optional members are "from" (defaults to current value), "units" (defaults to "px"). + * All attribute names use camelCase. + * @param {Number} duration (optional, defaults to 1 second) Length of animation (frames or seconds), defaults to time-based + * @param {Function} method (optional, defaults to YAHOO.util.Easing.easeNone) Computes the values that are applied to the attributes per frame (generally a YAHOO.util.Easing method) + */ + var Motion = function(el, attributes, duration, method) { + if (el) { // dont break existing subclasses not using YAHOO.extend + Motion.superclass.constructor.call(this, el, attributes, duration, method); + } + }; + + + Motion.NAME = 'Motion'; + + // shorthand + var Y = YAHOO.util; + YAHOO.extend(Motion, Y.ColorAnim); + + var superclass = Motion.superclass; + var proto = Motion.prototype; + + proto.patterns.points = /^points$/i; + + proto.setAttribute = function(attr, val, unit) { + if ( this.patterns.points.test(attr) ) { + unit = unit || 'px'; + superclass.setAttribute.call(this, 'left', val[0], unit); + superclass.setAttribute.call(this, 'top', val[1], unit); + } else { + superclass.setAttribute.call(this, attr, val, unit); + } + }; + + proto.getAttribute = function(attr) { + if ( this.patterns.points.test(attr) ) { + var val = [ + superclass.getAttribute.call(this, 'left'), + superclass.getAttribute.call(this, 'top') + ]; + } else { + val = superclass.getAttribute.call(this, attr); + } + + return val; + }; + + proto.doMethod = function(attr, start, end) { + var val = null; + + if ( this.patterns.points.test(attr) ) { + var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100; + val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t); + } else { + val = superclass.doMethod.call(this, attr, start, end); + } + return val; + }; + + proto.setRuntimeAttribute = function(attr) { + if ( this.patterns.points.test(attr) ) { + var el = this.getEl(); + var attributes = this.attributes; + var start; + var control = attributes['points']['control'] || []; + var end; + var i, len; + + if (control.length > 0 && !(control[0] instanceof Array) ) { // could be single point or array of points + control = [control]; + } else { // break reference to attributes.points.control + var tmp = []; + for (i = 0, len = control.length; i< len; ++i) { + tmp[i] = control[i]; + } + control = tmp; + } + + if (Y.Dom.getStyle(el, 'position') == 'static') { // default to relative + Y.Dom.setStyle(el, 'position', 'relative'); + } + + if ( isset(attributes['points']['from']) ) { + Y.Dom.setXY(el, attributes['points']['from']); // set position to from point + } + else { Y.Dom.setXY( el, Y.Dom.getXY(el) ); } // set it to current position + + start = this.getAttribute('points'); // get actual top & left + + // TO beats BY, per SMIL 2.1 spec + if ( isset(attributes['points']['to']) ) { + end = translateValues.call(this, attributes['points']['to'], start); + + var pageXY = Y.Dom.getXY(this.getEl()); + for (i = 0, len = control.length; i < len; ++i) { + control[i] = translateValues.call(this, control[i], start); + } + + + } else if ( isset(attributes['points']['by']) ) { + end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ]; + + for (i = 0, len = control.length; i < len; ++i) { + control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ]; + } + } + + this.runtimeAttributes[attr] = [start]; + + if (control.length > 0) { + this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control); + } + + this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end; + } + else { + superclass.setRuntimeAttribute.call(this, attr); + } + }; + + var translateValues = function(val, start) { + var pageXY = Y.Dom.getXY(this.getEl()); + val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ]; + + return val; + }; + + var isset = function(prop) { + return (typeof prop !== 'undefined'); + }; + + Y.Motion = Motion; +})(); +(function() { +/** + * Anim subclass for scrolling elements to a position defined by the "scroll" + * member of "attributes". All "scroll" members are arrays with x, y scroll positions. + *

    Usage: var myAnim = new YAHOO.util.Scroll(el, { scroll: { to: [0, 800] } }, 1, YAHOO.util.Easing.easeOut);

    + * @class Scroll + * @namespace YAHOO.util + * @requires YAHOO.util.Anim + * @requires YAHOO.util.AnimMgr + * @requires YAHOO.util.Easing + * @requires YAHOO.util.Bezier + * @requires YAHOO.util.Dom + * @requires YAHOO.util.Event + * @requires YAHOO.util.CustomEvent + * @extends YAHOO.util.ColorAnim + * @constructor + * @param {String or HTMLElement} el Reference to the element that will be animated + * @param {Object} attributes The attribute(s) to be animated. + * Each attribute is an object with at minimum a "to" or "by" member defined. + * Additional optional members are "from" (defaults to current value), "units" (defaults to "px"). + * All attribute names use camelCase. + * @param {Number} duration (optional, defaults to 1 second) Length of animation (frames or seconds), defaults to time-based + * @param {Function} method (optional, defaults to YAHOO.util.Easing.easeNone) Computes the values that are applied to the attributes per frame (generally a YAHOO.util.Easing method) + */ + var Scroll = function(el, attributes, duration, method) { + if (el) { // dont break existing subclasses not using YAHOO.extend + Scroll.superclass.constructor.call(this, el, attributes, duration, method); + } + }; + + Scroll.NAME = 'Scroll'; + + // shorthand + var Y = YAHOO.util; + YAHOO.extend(Scroll, Y.ColorAnim); + + var superclass = Scroll.superclass; + var proto = Scroll.prototype; + + proto.doMethod = function(attr, start, end) { + var val = null; + + if (attr == 'scroll') { + val = [ + this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames), + this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames) + ]; + + } else { + val = superclass.doMethod.call(this, attr, start, end); + } + return val; + }; + + proto.getAttribute = function(attr) { + var val = null; + var el = this.getEl(); + + if (attr == 'scroll') { + val = [ el.scrollLeft, el.scrollTop ]; + } else { + val = superclass.getAttribute.call(this, attr); + } + + return val; + }; + + proto.setAttribute = function(attr, val, unit) { + var el = this.getEl(); + + if (attr == 'scroll') { + el.scrollLeft = val[0]; + el.scrollTop = val[1]; + } else { + superclass.setAttribute.call(this, attr, val, unit); + } + }; + + Y.Scroll = Scroll; +})(); +YAHOO.register("animation", YAHOO.util.Anim, {version: "2.8.0r4", build: "2449"}); diff --git a/include/javascript/yui/build/assets/skins/sam/ajax-loader.gif b/include/javascript/yui/build/assets/skins/sam/ajax-loader.gif new file mode 100644 index 0000000000000000000000000000000000000000..fe2cd23b3a3c017ae6acfd291135a998e2f8ee74 GIT binary patch literal 3208 zcmc(iX;4#H9>pJdFE7h`I{03&1A#Fh5ut4eDm1GK0RjYM5fB7KV#MGsi$D+vOBRqd zgf*ZfkQkyZBB-FP%_0qIW8nsBs{?emDDG|9WA}8815QoVR1F`dYN~qf$6L4Vt>5{d zbE+;kz|X}skqIz?cL4D54JR>7R zC=>$!T9zM?jlL0^I9{Q?tL@pK(cHe}-_1BFI}+1&2$&hkX+mb=uEfke`x6EB$@`M_ z1D3x+6zbfmRr5E@KMFuI#v=jAiQ3uG89q;9-Ry^&w1yMBlo4lEk+iEfP1~`Z92~Ch z)f})CRri0#HYFIlTMw~0MospF06WXy{W&YWHZ0k11QlAYagA`g5O>qXR=-HrvaSDB z_Zb0=l#$8xjDe^-X;5K?KVNEb2=?++uqjb-O>uH}3V{f=X`7C@YYi%YeTnA8$>uJL zdiJ@qX{;*$)Z!y4F&_ST_WAfw@%dWHWd;8me2W=>IK+3S8&sdijfuDK^L*g-myocg zROu67HjY0iw0C{snY#0R-qG!)?{-XEVE62>ig9TY@TJe3GXKdwJI@}|HamJe#?Oh? z>{oe56Alk5BlvXgg+R&0z85Eh49$Wmvo|XwF?%x^Ps^2qs0qZ3Lus@P^`@A3w%??Y zNrp~Cj`ZJGgco)yaDR-t*2poe`}@ODuqlfmf)3H3yyd&tGHN+(Pbqh2HaizA_Q?03 z6vb*{Wx}dVt(w~oQM1}L?Z-Q0t>x+_$09~DhU4QV>^p8+p>pT`ODnb?l<*T8U_yyX3gn$N3RHXr@+ zyvwBNh$Uem{8w}MwvKc7Gmcy*LA+#TjXHezj51<%sd86PQTE_%4<;Tv<}?{hyF5u{ zkD1y^OsUMEo~3O81nHZ-l2Kp%@HSdEL_C0LBdJI}v^9ywA{T7!B#!)OL4eaycbp&+ z5pvi?(F_W;coQ4kkztVq?e-uwu_(tvT3d^&DOEaAn;~2A)k(wQc0=2_Rt>AyyzwIK zl3z!1spEi>EiV?!bl1O*=~m&5gDzJxOTJN*QbfnDZYaizCp;dV0H%S);r_=zJOw%~ zGhVp7or&@2D4oTwYRN9|WXI!Vp(fU6FKR6n{fm|?=zw|mx6?JVqdQG~BaNGDnRi>l zWr@lNZ{z!Ii}9(;2iDn~t7+Roes3*ru#$tcIN5SvM~=}x@s)B~;nm!UyFj4ns-+KC zc_r464Q9=e8C%yH1+YRNJti+sN5Yn_SwqNX=fla45fUzOXNGxJ4hxjCY{HwGakNE^ z5Gm!7Qctx3)g5m>fwpRouQ_^-Tg&QI9=LFct)n*JU4h~IB~JK=lpSzIw>N9I92(3V z#mN!!gq)F;6@X-7>-2OMuem(+EcT-5*}CKeJ*)igt9`$D-p8gNTswGg?T*nef(P0b zcK@gG+v#UVZEStDg7}(BoUR)T4X1dKm2Q?_{Y{jjD5!4YXH+j@Ig72hZ7T)Vu~st0 zhrrH1_xTCGs)WHrj1dNfmTf!0G9QpSc>9IMZI4_uy=Z;JSQ=ro!vUDYT@jMzLrhFC zPld89_W0NY*EiruQ}aPeN!s@MW-X%DH0Th1i)M9Wrw>?N84RMRn?==Gv)*2$LZFtj z2yh8YM(r*`qrn!`bl7N@Jo-$m`V4N zd#7=6y}+ZI8A2#Xi~iZ;pv~t?ycaJ#{&({Q5Z*pl09Ju4W^-*NO|A0{+hV9Zh26ql z2MH72VLb8&2TY#uH1oxixNyRH@Bou{d;Ek=(P*RR{C}jf8 z4tl&k6u5>WN>#{O0GSx;^S%8J`bnXRdTvecd2(%ukpLhBjxD#vB!4;(wPc{rdch`m z{%<-+=B&UpQHKv~*;s5BYG-s}%Kff&XttelV?p1`IN!0#pDoFGj*%g&ANf!k5>lK4 ze&JKqZ9m<);$PS3Lh-J1r<^%yWkWVJZTbE|+9d_wT+Ca}vEj*!aj>+En31zyUZw=A z6ucU+B3a~I(&7eY7Vsb#Cgyo@^m@{<6*;bXq*E{{O%!KAMB<=xdV`M>-8~aTkY1dq z?+nWqtVG8F%5|iZw;3Bpv1e2bB;w=q)j57RxDTznFZ z3W@4K+O`crTxg*teEmo8b4BzyV0nd0j;L5srpzr-v7(E31Q2w!D0I{4^VvCVEDBK% z66eVw*qhwhwuinQ1=3A&0r@@%}|u!GftRru!rq=CeZOe*qn zn9DxM$)PhKM5mLc$Kh}X3U@IGpfHE8)geTm0W$~$2jiD{5_Niam1Aa-u?l5?(>BA6sZK>V=uqv=_H!;GRk>u*v_2IuH5uz@LJl! zo%n|YVa^Cd1g)$p7CBL?>dp$T>v@mAeRdBQ ze9w4I`#JtYzxS8wKA@n*nM@x$;j>^6p8iiJAfw-kO+FQYF`K+*DbdiS6yEK@3ss4I zb-S367!k?l1nf57%jYeZZRb@fFtH1zC_7P6K-5qzuxPfqlC^Y+Rkn zbFQFvs!+j^0Aulpi7jGEH4eJxe|oc;i#k&X*FNJ#({)(kiy|YGeTF=NOz@lp5 z{Q(*&J)M-|;LMD6f(rxO6Qt&82r*>2FC{xfrINcwkzh@0(^1z}{o3ZEbV%La)Tyd- zkE-Q3P(e`K>r7{mFAmn{+FinI28ktR!TXo>U>7bD#rtjy^Or>rfNofB{O3`2qkBz$ zf=qb{lOZ=#c);7PjT`KNS=CL!uR!jNgJZfMm*M&5n2(0!J$?isJIy7)ef}TtY5fE2 C|Ftdv literal 0 HcmV?d00001 diff --git a/include/javascript/yui/build/assets/skins/sam/asc.gif b/include/javascript/yui/build/assets/skins/sam/asc.gif new file mode 100644 index 0000000000000000000000000000000000000000..a1fe7385d5ac940629233f0dc4bbd61f20959c3b GIT binary patch literal 177 zcmZ?wbhEHbU}|FG@8_44nAqLjosyCg9vmZ){{V zVZwy=_I7V?@1UTd{Jgy0-d;-!i@3Nr8*A&jy1Ge|CjI~ap8*F@{K>+|z#z_`1Cj^X z$-t`jKsD}w@w|)+IvTGc!Y=lCF}Yu=Q8eH=%k0e0mLc1=fuZY=!y%64o~d4Qx%?Cv FtO0P~GlKvC literal 0 HcmV?d00001 diff --git a/include/javascript/yui/build/assets/skins/sam/autocomplete.css b/include/javascript/yui/build/assets/skins/sam/autocomplete.css new file mode 100644 index 00000000..07fc0302 --- /dev/null +++ b/include/javascript/yui/build/assets/skins/sam/autocomplete.css @@ -0,0 +1,7 @@ +/* +Copyright (c) 2009, Yahoo! Inc. All rights reserved. +Code licensed under the BSD License: +http://developer.yahoo.net/yui/license.txt +version: 2.8.0r4 +*/ +.yui-skin-sam .yui-ac{position:relative;font-family:arial;font-size:100%;}.yui-skin-sam .yui-ac-input{position:absolute;width:100%;}.yui-skin-sam .yui-ac-container{position:absolute;top:1.6em;width:100%;}.yui-skin-sam .yui-ac-content{position:absolute;width:100%;border:1px solid #808080;background:#fff;overflow:hidden;z-index:9050;}.yui-skin-sam .yui-ac-shadow{position:absolute;margin:.3em;width:100%;background:#000;-moz-opacity:.10;opacity:.10;filter:alpha(opacity=10);z-index:9049;}.yui-skin-sam .yui-ac iframe{opacity:0;filter:alpha(opacity=0);padding-right:.3em;padding-bottom:.3em;}.yui-skin-sam .yui-ac-content ul{margin:0;padding:0;width:100%;}.yui-skin-sam .yui-ac-content li{margin:0;padding:2px 5px;cursor:default;white-space:nowrap;list-style:none;zoom:1;}.yui-skin-sam .yui-ac-content li.yui-ac-prehighlight{background:#B3D4FF;}.yui-skin-sam .yui-ac-content li.yui-ac-highlight{background:#426FD9;color:#FFF;} diff --git a/include/javascript/yui/build/assets/skins/sam/back-h.png b/include/javascript/yui/build/assets/skins/sam/back-h.png new file mode 100644 index 0000000000000000000000000000000000000000..5f69f4e2564357c83eddcecd5f104e14ecf09d49 GIT binary patch literal 334 zcmeAS@N?(olHy`uVBq!ia0vp^8bBP#!2~4rHx?TMDaPU;cPEB*=VV?2IV|apzK#qG z8~eHcB(ehe3dtTpz6=aiY77hwEes65fIoOOtf|Nms9M{<~TG{NqzV`0JLv$@3}2r!1e&d7^!S-DO!ayYtzu zlYbXZdwJtvz~-c)`W2~GWd>K)%(x?;HM38a$5dPGdwUdyvi-fkSZmx?=65Sx>H+$T N!PC{xWt~$(695Wxh_(O# literal 0 HcmV?d00001 diff --git a/include/javascript/yui/build/assets/skins/sam/back-v.png b/include/javascript/yui/build/assets/skins/sam/back-v.png new file mode 100644 index 0000000000000000000000000000000000000000..658574a9d560febf6f58a6a005e602ae734f97da GIT binary patch literal 338 zcmeAS@N?(olHy`uVBq!ia0vp^fk3Rm!2~2Z4>V?gr~;43Vg?4j!ywFfJby(BP>``W z$lZxy-8q?;Kn_c~qpu?a!^VE@KZ&eBzCyA`kS_y6l^O#>Lkk1LFQ8Dv3kHT#0|tgy z2@DKYGZ+}e3+C(!v;j)&_H=O!$#8xetNtMognoD1W&+apvb;IkbSm6HPD+>;$YzUet;PS1vwR5kn@U@xAZc*X`bN{qf6~>%I#YFG@c*bNAWmV~4vw71T)EP4+yI zm~wtolli{h{KvO{m;tHh|I%4jCy1_T3f;gJc5v07ee4g7Yue6#khD9T{)1zz`*b-fq}tl1_Oh5!JJ)zHb9Bj zo-U3d8P0E~+HyA*iX83NS6;e=XVR0zjVBT|NT_&L{`FGpKAL2Fa>10KxKFts1mAI{ zTl(++c+cBw&>1Hg`q?f)-lTL;*t$N(e z5?hd3GOgj$2NlMp2LqYB{x-9SR9ACql#~mV9Q=7MjH&2tFH1^vHs=YGaG?o#I;s{w z@^7uZwW|JFk^J=j)5pJVtzYr_iPcWOb;5U<>=m}`da)?fz4zkhFyGbPdQqiUBy97q c5+S&cLBv9~EU0~*E702vp00i_>zopr03oxJMgRZ+ literal 0 HcmV?d00001 diff --git a/include/javascript/yui/build/assets/skins/sam/bar-v.png b/include/javascript/yui/build/assets/skins/sam/bar-v.png new file mode 100644 index 0000000000000000000000000000000000000000..2efd664d9abdddff7e06ec512e0198f5fcaf1a56 GIT binary patch literal 387 zcmeAS@N?(olHy`uVBq!ia0vp^0YI$5!2~3qF}(@{Qk(@Ik;M!Qe1}1p@p%4<6rdnu zage(c!@6@aFM%AEbVpxD28NCO+{4xi!)|R=d;J&iHZ8yvVO_gGSA|3s-364JloT@b e|NoWUGS9D3dxyvWMZl0`VDNPHb6Mw<&;$VKhMGhG literal 0 HcmV?d00001 diff --git a/include/javascript/yui/build/assets/skins/sam/bg-h.gif b/include/javascript/yui/build/assets/skins/sam/bg-h.gif new file mode 100644 index 0000000000000000000000000000000000000000..996288916e82bf2972bb4b8097f1b4a0869955d2 GIT binary patch literal 212 zcmV;_04x7TNk%w1VbK5_0HOu};o;%Q$;qdur-_M)x3{;~*Vq65{{R30A^8LW000I6 zEC2ui0MP&(000A-Xu90~Fv>}*y*TU5yZ>M)j$~<`XsWJk>%MR-&vb3yc&_h!@BhG{ za7Zi~kI1BQ$!t1BgQ#>$ty-_xtai)odcWYXI4gJ*&gisy&2GEj@VIs;jK6uCK7M Ova__cwzs%A2>?48g>Yp6 literal 0 HcmV?d00001 diff --git a/include/javascript/yui/build/assets/skins/sam/bg-v.gif b/include/javascript/yui/build/assets/skins/sam/bg-v.gif new file mode 100644 index 0000000000000000000000000000000000000000..8e287cd52222c75c8f921cfdd4b4ae02b783c0e4 GIT binary patch literal 481 zcmV<70UrKGNk%w1VI%+9?F_4V!T?c3Yi)6>)G>FKw(x2LD4*Voto|Nj60 z00000000000000000000A^8LW000R9EC2ui03-n5000F4Fv&@)y*TU5yZ>M)1%db# z2qKu>ks2)LB5`naUe$Rb%^?jF5?t^_yflh-^g;Ix9iB^kPjarXfkzSKvm137eG4lFF3Kmd=>a zn$n!qo;kDDqu96FtKO~LyW+j%zvjW{!|KKC$L`7S%ks_i&-T&y)B4r?*Pu#pof4P| zTr7Xv0HRt$kfFg^2){)Pr?BA>i=iIons~6H#(^J>3vz_$apcC5C`(}s7}B9hkS|51 zeAV(|&5SW!&diq6W>1_uyZvN2bfM3n002t}0{{R350Hx300004XF*Lt007q5 z)K6G40000PbVXQnQ*UN;cVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBUzfKW_SMepzL z*?5)vnXr^-@mq~v#Is<_TJv!tH9IQe$@Xx30Dl4m?CIp{=H9&7-_qpj z@$&Na_V>}=-P_s8t;X5r<>9oxu=V))t;fI5&dBfV=di}q&Ctl)z^}#1!s6l2^YQNR z_4fPy{pIZK+vn}2t)%$)_toO#;n%^Nt);HK#<#b(?d|Q^-PrN-^x)*+!OF_W$Hdm! z)7aL|?e6dH@9^Q?*SNj5^z`$uytMfH`|DE_v7Q^$@+uYl) zwyn<6!SC?!+19@4>g)FN@VIM;P5=N05J^NqRCwC#*lSzbSQiFhNFotI4oL6_;vuC{b=qK$I+Xz#Vv+gl@7g<|P-q!D?T7b6AA7YNE^pUbd+%Us zvHiGMY?dFDpVm+7|H0xQ7NY(A7RQyM(T<>!bm{vn3=x8=(rL;Q{SFI3)s8?qX$u8u zH@N?3nH4ckx}#Azn*N_G4oMxo<@6I6%H5fJK~aq=_stfD8jQ*iH3XfEFQlfX+!}Qx ze4~YjL@+!_3T(FWE&nOEIN%yOC)PU~H4MJ1yg;_~-0+z22Q16&6NVKzRfjwP1ed_zA3i zg*8U*O1&IMRBp?=xVZQmEHTY-U$r_!L!g-&bz+X`4t(d)WtnwhDFsip&8{Fwn?C$Y-BAJXOA#XK`_RhKI zdKm{RiY;3Snxy>@I2z;yA7(lgGa&E3x|;RV@bB*M9w! z+hA1ns)v#B*^{x*P0SkNT`$lbbO1 zME0ERVyeQj0n}Jv{oq}t;(WYbiBc-f4zs z%YX#}iTOaK;&}X+uf*nSwGJ!E(%mmvP#Eld++;eN$nw9l&R$elfpTnqJ`jt=_)zHh zEEWjIGmI!o&9${JSS8e?pJ6B}4r^%JRure>NuS5FsBIQf4$MD%o3GdOr9Z`r)$Fow z_7)3VDR7fVlvd3Kp3iKn%Jc0jXMc6DrhK_F|4%-@l8@I9{bf-Uea+=ztJ|c9(jI1G zjt{S#Wi`}ip(Oz5kGJ*uO1}QgL#nr|KKb+-)^Zv0xdlz4EyieCK9N;l&1@?$nkRkI zSpY%x{7TzHPCj@rJzbDxabu|&{B_W>aAuQjDtG_l{MF3NbN(t6a;hq(proTr9lj3V zFq0r5Yr-dqvS?jj9=41o8G*_@Oz2l1W@es%^_*o@Cx4b`zeP~{jbE9ZeqdyJV#4Q> zcK=@cLS3bf(PX@q&t4#FW;+xLIh6BCDV)h*M_W5O-6I^ zL?8rB&V;tNuN?bn1f}hMwYen95?IsymMq;u*q~)LN$27Z%ZlT}hgTuT?)!Qs9B$j` zgJRKfeJYExuV7lxqE&?1e{`%aFGmI}i`gU@j)%|Al&f{!0waQoXeKxtSzcSc=lJLY zYXVg^ZH!*rXx>|0jYJ~1;VRVWv$_`xBA>}7|7fET?R99Lt{%b>#H8%gO_B=Uv2 zEZr;OVLH8+?g$J?!XH~++cT_UbLr`l3|9xAPn1NT3|sX&7z{>cA%k_9O)_L-@4W|< zR;$G@Dz;|L6tAUISrR2!1W~qb$W})LQ?s{UYyQtI+$4M+`FW=0_tP{y=53kUUc{s# zj)J%$iGRI26*pvgbU}c}Bv|dpn337yda&vH^B^dlvL7Yi z@mSG(V{GAdZNNf>0fr$@qv3(QOWMNm!`ZQ3CJP5+#k*3l*t}Kjy}A=0vY@brM-Tu) zpX+wmyQJ-?{;c0BBEdO{9*y-|@c|18>k#HI2%TyNO^>vt!|h)Na{HGz1Fvj_hb{D5 zJ%*wsV*087z%uTCq5yIDOd+dU>g5^AA;fan9>~#P zUFIDp*E^prm1K-f+YNrkz>AFelrhp8wtB(G0M676;-~cnG0H;6K!E*vgTNlL6VXu? z+HC^fZvPTp7aBxoqy?Xu1lqCx9<&{!C2rKcXsJrvG#yNhy03)|QoT{41~uw_oBM|R k{QsPv*4L~bm;VVc0HT!-jb!e$TmS$707*qoM6N<$g7zKgCjbBd literal 0 HcmV?d00001 diff --git a/include/javascript/yui/build/assets/skins/sam/button.css b/include/javascript/yui/build/assets/skins/sam/button.css new file mode 100644 index 00000000..9d63c610 --- /dev/null +++ b/include/javascript/yui/build/assets/skins/sam/button.css @@ -0,0 +1,7 @@ +/* +Copyright (c) 2009, Yahoo! Inc. All rights reserved. +Code licensed under the BSD License: +http://developer.yahoo.net/yui/license.txt +version: 2.8.0r4 +*/ +.yui-button{display:-moz-inline-box;display:inline-block;vertical-align:text-bottom;}.yui-button .first-child{display:block;*display:inline-block;}.yui-button button,.yui-button a{display:block;*display:inline-block;border:none;margin:0;}.yui-button button{background-color:transparent;*overflow:visible;cursor:pointer;}.yui-button a{text-decoration:none;}.yui-skin-sam .yui-button{border-width:1px 0;border-style:solid;border-color:#808080;background:url(sprite.png) repeat-x 0 0;margin:auto .25em;}.yui-skin-sam .yui-button .first-child{border-width:0 1px;border-style:solid;border-color:#808080;margin:0 -1px;_margin:0;}.yui-skin-sam .yui-button button,.yui-skin-sam .yui-button a,.yui-skin-sam .yui-button a:visited{padding:0 10px;font-size:93%;line-height:2;*line-height:1.7;min-height:2em;*min-height:auto;color:#000;}.yui-skin-sam .yui-button a{*line-height:1.875;*padding-bottom:1px;}.yui-skin-sam .yui-split-button button,.yui-skin-sam .yui-menu-button button{padding-right:20px;background-position:right center;background-repeat:no-repeat;}.yui-skin-sam .yui-menu-button button{background-image:url(menu-button-arrow.png);}.yui-skin-sam .yui-split-button button{background-image:url(split-button-arrow.png);}.yui-skin-sam .yui-button-focus{border-color:#7D98B8;background-position:0 -1300px;}.yui-skin-sam .yui-button-focus .first-child{border-color:#7D98B8;}.yui-skin-sam .yui-split-button-focus button{background-image:url(split-button-arrow-focus.png);}.yui-skin-sam .yui-button-hover{border-color:#7D98B8;background-position:0 -1300px;}.yui-skin-sam .yui-button-hover .first-child{border-color:#7D98B8;}.yui-skin-sam .yui-split-button-hover button{background-image:url(split-button-arrow-hover.png);}.yui-skin-sam .yui-button-active{border-color:#7D98B8;background-position:0 -1700px;}.yui-skin-sam .yui-button-active .first-child{border-color:#7D98B8;}.yui-skin-sam .yui-split-button-activeoption{border-color:#808080;background-position:0 0;}.yui-skin-sam .yui-split-button-activeoption .first-child{border-color:#808080;}.yui-skin-sam .yui-split-button-activeoption button{background-image:url(split-button-arrow-active.png);}.yui-skin-sam .yui-radio-button-checked,.yui-skin-sam .yui-checkbox-button-checked{border-color:#304369;background-position:0 -1400px;}.yui-skin-sam .yui-radio-button-checked .first-child,.yui-skin-sam .yui-checkbox-button-checked .first-child{border-color:#304369;}.yui-skin-sam .yui-radio-button-checked button,.yui-skin-sam .yui-checkbox-button-checked button{color:#fff;}.yui-skin-sam .yui-button-disabled{border-color:#ccc;background-position:0 -1500px;}.yui-skin-sam .yui-button-disabled .first-child{border-color:#ccc;}.yui-skin-sam .yui-button-disabled button,.yui-skin-sam .yui-button-disabled a,.yui-skin-sam .yui-button-disabled a:visited{color:#A6A6A6;cursor:default;}.yui-skin-sam .yui-menu-button-disabled button{background-image:url(menu-button-arrow-disabled.png);}.yui-skin-sam .yui-split-button-disabled button{background-image:url(split-button-arrow-disabled.png);} diff --git a/include/javascript/yui/build/assets/skins/sam/calendar.css b/include/javascript/yui/build/assets/skins/sam/calendar.css new file mode 100644 index 00000000..b01c7e61 --- /dev/null +++ b/include/javascript/yui/build/assets/skins/sam/calendar.css @@ -0,0 +1,8 @@ +/* +Copyright (c) 2009, Yahoo! Inc. All rights reserved. +Code licensed under the BSD License: +http://developer.yahoo.net/yui/license.txt +version: 2.8.0r4 +*/ +.yui-calcontainer{position:relative;float:left;_overflow:hidden;}.yui-calcontainer iframe{position:absolute;border:none;margin:0;padding:0;z-index:0;width:100%;height:100%;left:0;top:0;}.yui-calcontainer iframe.fixedsize{width:50em;height:50em;top:-1px;left:-1px;}.yui-calcontainer.multi .groupcal{z-index:1;float:left;position:relative;}.yui-calcontainer .title{position:relative;z-index:1;}.yui-calcontainer .close-icon{position:absolute;z-index:1;text-indent:-10000em;overflow:hidden;}.yui-calendar{position:relative;}.yui-calendar .calnavleft{position:absolute;z-index:1;text-indent:-10000em;overflow:hidden;}.yui-calendar .calnavright{position:absolute;z-index:1;text-indent:-10000em;overflow:hidden;}.yui-calendar .calheader{position:relative;width:100%;text-align:center;}.yui-calcontainer .yui-cal-nav-mask{position:absolute;z-index:2;margin:0;padding:0;width:100%;height:100%;_width:0;_height:0;left:0;top:0;display:none;}.yui-calcontainer .yui-cal-nav{position:absolute;z-index:3;top:0;display:none;}.yui-calcontainer .yui-cal-nav .yui-cal-nav-btn{display:-moz-inline-box;display:inline-block;}.yui-calcontainer .yui-cal-nav .yui-cal-nav-btn button{display:block;*display:inline-block;*overflow:visible;border:none;background-color:transparent;cursor:pointer;}.yui-calendar .calbody a:hover{background:inherit;}p#clear{clear:left;padding-top:10px;}.yui-skin-sam .yui-calcontainer{background-color:#f2f2f2;border:1px solid #808080;padding:10px;}.yui-skin-sam .yui-calcontainer.multi{padding:0 5px 0 5px;}.yui-skin-sam .yui-calcontainer.multi .groupcal{background-color:transparent;border:none;padding:10px 5px 10px 5px;margin:0;}.yui-skin-sam .yui-calcontainer .title{background:url(sprite.png) repeat-x 0 0;border-bottom:1px solid #ccc;font:100% sans-serif;color:#000;font-weight:bold;height:auto;padding:.4em;margin:0 -10px 10px -10px;top:0;left:0;text-align:left;}.yui-skin-sam .yui-calcontainer.multi .title{margin:0 -5px 0 -5px;}.yui-skin-sam .yui-calcontainer.withtitle{padding-top:0;}.yui-skin-sam .yui-calcontainer .calclose{background:url(sprite.png) no-repeat 0 -300px;width:25px;height:15px;top:.4em;right:.4em;cursor:pointer;}.yui-skin-sam .yui-calendar{border-spacing:0;border-collapse:collapse;font:100% sans-serif;text-align:center;margin:0;}.yui-skin-sam .yui-calendar .calhead{background:transparent;border:none;vertical-align:middle;padding:0;}.yui-skin-sam .yui-calendar .calheader{background:transparent;font-weight:bold;padding:0 0 .6em 0;text-align:center;}.yui-skin-sam .yui-calendar .calheader img{border:none;}.yui-skin-sam .yui-calendar .calnavleft{background:url(sprite.png) no-repeat 0 -450px;width:25px;height:15px;top:0;bottom:0;left:-10px;margin-left:.4em;cursor:pointer;}.yui-skin-sam .yui-calendar .calnavright{background:url(sprite.png) no-repeat 0 -500px;width:25px;height:15px;top:0;bottom:0;right:-10px;margin-right:.4em;cursor:pointer;}.yui-skin-sam .yui-calendar .calweekdayrow{height:2em;}.yui-skin-sam .yui-calendar .calweekdayrow th{padding:0;border:none;}.yui-skin-sam .yui-calendar .calweekdaycell{color:#000;font-weight:bold;text-align:center;width:2em;}.yui-skin-sam .yui-calendar .calfoot{background-color:#f2f2f2;}.yui-skin-sam .yui-calendar .calrowhead,.yui-skin-sam .yui-calendar .calrowfoot{color:#a6a6a6;font-size:85%;font-style:normal;font-weight:normal;border:none;}.yui-skin-sam .yui-calendar .calrowhead{text-align:right;padding:0 2px 0 0;}.yui-skin-sam .yui-calendar .calrowfoot{text-align:left;padding:0 0 0 2px;}.yui-skin-sam .yui-calendar td.calcell{border:1px solid #ccc;background:#fff;padding:1px;height:1.6em;line-height:1.6em;text-align:center;white-space:nowrap;}.yui-skin-sam .yui-calendar td.calcell a{color:#06c;display:block;height:100%;text-decoration:none;}.yui-skin-sam .yui-calendar td.calcell.today{background-color:#000;}.yui-skin-sam .yui-calendar td.calcell.today a{background-color:#fff;}.yui-skin-sam .yui-calendar td.calcell.oom{background-color:#ccc;color:#a6a6a6;cursor:default;}.yui-skin-sam .yui-calendar td.calcell.selected{background-color:#fff;color:#000;}.yui-skin-sam .yui-calendar td.calcell.selected a{background-color:#b3d4ff;color:#000;}.yui-skin-sam .yui-calendar td.calcell.calcellhover{background-color:#426fd9;color:#fff;cursor:pointer;}.yui-skin-sam .yui-calendar td.calcell.calcellhover a{background-color:#426fd9;color:#fff;}.yui-skin-sam .yui-calendar td.calcell.previous{color:#e0e0e0;}.yui-skin-sam .yui-calendar td.calcell.restricted{text-decoration:line-through;}.yui-skin-sam .yui-calendar td.calcell.highlight1{background-color:#cf9;}.yui-skin-sam .yui-calendar td.calcell.highlight2{background-color:#9cf;}.yui-skin-sam .yui-calendar td.calcell.highlight3{background-color:#fcc;}.yui-skin-sam .yui-calendar td.calcell.highlight4{background-color:#cf9;}.yui-skin-sam .yui-calendar a.calnav{border:1px solid #f2f2f2;padding:0 4px;text-decoration:none;color:#000;zoom:1;}.yui-skin-sam .yui-calendar a.calnav:hover{background:url(sprite.png) repeat-x 0 0;border-color:#A0A0A0;cursor:pointer;}.yui-skin-sam .yui-calcontainer .yui-cal-nav-mask{background-color:#000;opacity:.25;filter:alpha(opacity=25);}.yui-skin-sam .yui-calcontainer .yui-cal-nav{font-family:arial,helvetica,clean,sans-serif;font-size:93%;border:1px solid #808080;left:50%;margin-left:-7em;width:14em;padding:0;top:2.5em;background-color:#f2f2f2;}.yui-skin-sam .yui-calcontainer.withtitle .yui-cal-nav{top:4.5em;}.yui-skin-sam .yui-calcontainer.multi .yui-cal-nav{width:16em;margin-left:-8em;}.yui-skin-sam .yui-calcontainer .yui-cal-nav-y,.yui-skin-sam .yui-calcontainer .yui-cal-nav-m,.yui-skin-sam .yui-calcontainer .yui-cal-nav-b{padding:5px 10px 5px 10px;}.yui-skin-sam .yui-calcontainer .yui-cal-nav-b{text-align:center;}.yui-skin-sam .yui-calcontainer .yui-cal-nav-e{margin-top:5px;padding:5px;background-color:#EDF5FF;border-top:1px solid black;display:none;}.yui-skin-sam .yui-calcontainer .yui-cal-nav label{display:block;font-weight:bold;} +.yui-skin-sam .yui-calcontainer .yui-cal-nav-mc{width:100%;_width:auto;}.yui-skin-sam .yui-calcontainer .yui-cal-nav-y input.yui-invalid{background-color:#FFEE69;border:1px solid #000;}.yui-skin-sam .yui-calcontainer .yui-cal-nav-yc{width:4em;}.yui-skin-sam .yui-calcontainer .yui-cal-nav .yui-cal-nav-btn{border:1px solid #808080;background:url(sprite.png) repeat-x 0 0;background-color:#ccc;margin:auto .15em;}.yui-skin-sam .yui-calcontainer .yui-cal-nav .yui-cal-nav-btn button{padding:0 8px;font-size:93%;line-height:2;*line-height:1.7;min-height:2em;*min-height:auto;color:#000;}.yui-skin-sam .yui-calcontainer .yui-cal-nav .yui-cal-nav-btn.yui-default{border:1px solid #304369;background-color:#426fd9;background:url(sprite.png) repeat-x 0 -1400px;}.yui-skin-sam .yui-calcontainer .yui-cal-nav .yui-cal-nav-btn.yui-default button{color:#fff;} diff --git a/include/javascript/yui/build/assets/skins/sam/carousel.css b/include/javascript/yui/build/assets/skins/sam/carousel.css new file mode 100644 index 00000000..dc1f9789 --- /dev/null +++ b/include/javascript/yui/build/assets/skins/sam/carousel.css @@ -0,0 +1,7 @@ +/* +Copyright (c) 2009, Yahoo! Inc. All rights reserved. +Code licensed under the BSD License: +http://developer.yahoo.net/yui/license.txt +version: 2.8.0r4 +*/ +.yui-carousel{visibility:hidden;overflow:hidden;position:relative;text-align:left;zoom:1;}.yui-carousel.yui-carousel-visible{visibility:visible;}.yui-carousel-content{overflow:hidden;position:relative;text-align:center;}.yui-carousel-element li{border:1px solid #ccc;list-style:none;margin:1px;overflow:hidden;padding:0;position:absolute;text-align:center;}.yui-carousel-vertical .yui-carousel-element li{display:block;float:none;}.yui-log .carousel{background:#f2e886;}.yui-carousel-nav{zoom:1;}.yui-carousel-nav:after{content:".";display:block;height:0;clear:both;visibility:hidden;}.yui-carousel-button-focus{outline:1px dotted #000;}.yui-carousel-min-width{min-width:115px;}.yui-carousel-element{overflow:hidden;position:relative;margin:0 auto;padding:0;text-align:left;*margin:0;}.yui-carousel-horizontal .yui-carousel-element{width:320000px;}.yui-carousel-vertical .yui-carousel-element{height:320000px;}.yui-skin-sam .yui-carousel-nav select{position:static;}.yui-carousel .yui-carousel-item-selected{border:1px dashed #000;margin:1px;}.yui-skin-sam .yui-carousel,.yui-skin-sam .yui-carousel-vertical{border:1px solid #808080;}.yui-skin-sam .yui-carousel-nav{background:url(sprite.png) repeat-x 0 0;padding:3px;text-align:right;}.yui-skin-sam .yui-carousel-button{background:url(sprite.png) no-repeat 0 -600px;float:right;height:19px;margin:5px;overflow:hidden;width:40px;}.yui-skin-sam .yui-carousel-vertical .yui-carousel-button{background-position:0 -800px;}.yui-skin-sam .yui-carousel-button-disabled{background-position:0 -2000px;}.yui-skin-sam .yui-carousel-vertical .yui-carousel-button-disabled{background-position:0 -2100px;}.yui-skin-sam .yui-carousel-button input,.yui-skin-sam .yui-carousel-button button{background-color:transparent;border:0;cursor:pointer;display:block;height:44px;margin:-2px 0 0 -2px;padding:0 0 0 50px;}.yui-skin-sam span.yui-carousel-first-button{background-position:0 -550px;margin-left:-100px;margin-right:50px;*margin:5px 5px 5px -90px;}.yui-skin-sam .yui-carousel-vertical span.yui-carousel-first-button{background-position:0 -750px;}.yui-skin-sam span.yui-carousel-first-button-disabled{background-position:0 -1950px;}.yui-skin-sam .yui-carousel-vertical span.yui-carousel-first-button-disabled{background-position:0 -2050px;}.yui-skin-sam .yui-carousel-nav ul{float:right;height:19px;margin:0;margin-left:-220px;margin-right:100px;*margin-left:-160px;*margin-right:0;padding:0;}.yui-skin-sam .yui-carousel-min-width .yui-carousel-nav ul{*margin-left:-170px;}.yui-skin-sam .yui-carousel-nav select{position:relative;*right:50px;top:4px;}.yui-skin-sam .yui-carousel-vertical .yui-carousel-nav select{position:static;}.yui-skin-sam .yui-carousel-vertical .yui-carousel-nav ul,.yui-skin-sam .yui-carousel-vertical .yui-carousel-nav select{float:none;margin:0;*zoom:1;}.yui-skin-sam .yui-carousel-nav ul li{background:url(sprite.png) no-repeat 0 -650px;cursor:pointer;float:left;height:9px;list-style:none;margin:10px 0 0 5px;overflow:hidden;padding:0;width:9px;}.yui-skin-sam .yui-carousel-nav ul:after{content:".";display:block;height:0;clear:both;visibility:hidden;}.yui-skin-sam .yui-carousel-nav ul li a{display:block;width:100%;height:100%;text-indent:-10000px;text-align:left;overflow:hidden;}.yui-skin-sam .yui-carousel-nav ul li.yui-carousel-nav-page-focus{outline:1px dotted #000;}.yui-skin-sam .yui-carousel-nav ul li.yui-carousel-nav-page-selected{background-position:0 -700px;}.yui-skin-sam .yui-carousel-item-loading{background:url(ajax-loader.gif) no-repeat 50% 50%;position:absolute;text-indent:-150px;} diff --git a/include/javascript/yui/build/assets/skins/sam/check0.gif b/include/javascript/yui/build/assets/skins/sam/check0.gif new file mode 100644 index 0000000000000000000000000000000000000000..193028b99361c6527f17a9056037f3d8729fada7 GIT binary patch literal 608 zcmZ?wbhEHb6krfzc;>|L^y$-=FJFHD{{8v$=l}lwYiw-%_U+rNSFb*Q{ycHwL|t9o z4nyho27-Mo48_U+qq=FHi!VMBd=eR6X0+O=zU@7{g=`t?<-R$aV!QBO~=si|q# zu3gWbJ!@`mzI^%e$A3uKV-Me@C^y%BTZ(p%u#nr1TIw0qR;)H>HZ-Y})b4zPm zdq-zicTcmUtRf$uChJr_107k%CMHe`N0x;P`5omrrJC4T89CNEtasp8#oolg$!xcC z*G^_mh9((lImRPL*@bMRWts#ebZswOyr3>2&}6S{Yk&KWy@0BkeG`wFo;Jga7tBID z3Or5XCSs!Nxxa8b*r|v&i3p1^@tiSGSg@dh)kuRwD&VlggmwY>tRDsr6B@;pN)`kN kI5!@bwak+c_`=}P#wi$N7O_%^c>;TH(y2L>8UhT~0GYwkU;qFB literal 0 HcmV?d00001 diff --git a/include/javascript/yui/build/assets/skins/sam/check1.gif b/include/javascript/yui/build/assets/skins/sam/check1.gif new file mode 100644 index 0000000000000000000000000000000000000000..7d9ceba3847ffb41864626de755147cf2e0ccc41 GIT binary patch literal 622 zcmZ?wbhEHb6krfzcoxU7ckkYV2M?Y-d-m9|V>@>2*tTt3LPEl(O`BR;T8=%(xpqq#l;5>99Xq#)&2YTYiepbIy&0g+AOW@ zckS9Guc-F@`}d~imPLyeZQs6~fsu`YfvK{pX2F65U0q$Rt*sL$O-@Ws1A@}h((LT) z?(XjO>(?(?vSiJgH4`UJK6B=bk&)5y`M-)|l9Y<;$0E z*|Mdlr)S-|b(NKs3l=PFZf@Sadv|qB-H{_lmMvRWUS2+J+H@9n9wt`q{DLAwL&J0D z&M`1B06hgHX$=&AvM@3*#4+fAECR&|1N-TQIAB<`wzYS3c6IkOiz~=+aJchM|1mCdzDLXw4hE#vxNR(VN@CJ{DPhF!b7VuM)OM4A+ZRauU+7{|s2 zcnd2w$tde{Md^hbMtE?UD9bddsdKr+>S#rp``L#2t2OayvU`dd#ftf`8raM6HSzlj zc(5=uIVZF*Fl5;XgfOzUFmkr3NH`Qau*iwBl%AN_(0#mLZsnU73LZ^-il>A0j5i(a fVsVr<>G*MA!L!EM+AbM4F05F7ettU>BZD;n{1fhr literal 0 HcmV?d00001 diff --git a/include/javascript/yui/build/assets/skins/sam/check2.gif b/include/javascript/yui/build/assets/skins/sam/check2.gif new file mode 100644 index 0000000000000000000000000000000000000000..181317599bfd45f03a7a69784b232509171d98e9 GIT binary patch literal 609 zcmZ?wbhEHb6krfzc;?HnW5@{Q2|Z;^P1R|37;4=+mc9 z2M!#ludjdl^y!^DcW&Oi`QX8Wd-v|GTD9u_{rlg(eY<=2?(*f!7cE+}Zr!@3rlz#C zw93lLty{Ntbad?6wX3|me9f9QU0q#_jEvpg-8D5erKP3o*RL-ssmjjIK6B=bk&#hr zYwM9CN4|dj+Sb-)XlVHT`}dxnp5w=lFIlo=!GZ+|z~IZE19BTEP8ittHTX6)x3spkcXW1j_cTk$%W!aLa!=*3 zc9)lEa$s@xW?Hz=(p!newn>g(hVaPYrXndu(oIuG-2?s&?!;%&%Yb2pGtyHpw{(Nw4Sq&gU}|FG@8_44nAqLjosyCg9vmZ){{V zVZwy=_I7V?@1UTd{Jgy0-d;-!i@3Nr8*A&jy1Ge|CjI~ap8*F@{K>+|z#z_`1Cj^X z$-t_&AfWe&MeGaLh@5Q0kS;d8>Ju6P(#(BMdM*5_og0L@6jvQ6(g^H!doZ(#VTvMy FH2`14Gspk{ literal 0 HcmV?d00001 diff --git a/include/javascript/yui/build/assets/skins/sam/dt-arrow-dn.png b/include/javascript/yui/build/assets/skins/sam/dt-arrow-dn.png new file mode 100644 index 0000000000000000000000000000000000000000..85fda0bbca21cefc6b8cf1726bc83e43bff993c4 GIT binary patch literal 116 zcmeAS@N?(olHy`uVBq!ia0vp@K+M9#3?wzWV%32ZXMj(L>;M1%fy~Ir2;r~IJAo|5 zk|4ie28U-i(tsREPZ!6Kid)Guq>ddput17Y#X`7&C779+nL(zFDdZjVkv^az22WQ% Jmvv4FO#tWt9i9LH literal 0 HcmV?d00001 diff --git a/include/javascript/yui/build/assets/skins/sam/dt-arrow-up.png b/include/javascript/yui/build/assets/skins/sam/dt-arrow-up.png new file mode 100644 index 0000000000000000000000000000000000000000..1c674316aed41943dae79b01583956db63c8be08 GIT binary patch literal 116 zcmeAS@N?(olHy`uVBq!ia0vp@K+M9#3?wzWV%32ZXMj(L>;M1%fy}VT__niwAVJ2G zAirP+hi5m^fE-Cr7srr_TgeGo2?+@gd>DjQ2|6TYNiZ`ri2h~@(drDS1}b9kboFyt I=akR{0KC>mi#>Q#WroDds`uzFx3^1VhlZBCift5iABmh#&!0aEf z>&{2rQ#+d!lrGr5WpF;$+r>U-p%#pf7j6C(;=#aR4FLK*IpF{R literal 0 HcmV?d00001 diff --git a/include/javascript/yui/build/assets/skins/sam/editor-sprite-active.gif b/include/javascript/yui/build/assets/skins/sam/editor-sprite-active.gif new file mode 100644 index 0000000000000000000000000000000000000000..3e9d4200b3e6b124354f12d6c5f90513587315d1 GIT binary patch literal 5614 zcmWlacRbXO1I9o1xjo!{lubD$*{)PZ%E{hmB%^eSjHD|nE1g~Dp{$g<5<)o*8pfR! zLZ>29I-@cghx!`H{rWxsKCkEXdj5IdkF~9pp^@JPz#q9J2HuV@E>Cw=KWalD5brf5 z7wc(%{`^^vGTB!-Q^43kwVXjh56;{r((;NP8t1yuEj})vselgDp zJdb?taWtcvjSfDm=L^V}ZaKLe+_P)9)^>Fo%@uYsXOf}WU+182uy=&5+)M5H!WD-ChUT{vHz`j|Ar-IaI6Ki=Ci-5_eN1`t zGqh`>W~8@LxVW^o{`Ze4xRy(OI#qR0ZT}u!^=kFkuV44|^-VW(Btz1iyzMM)obKr> z>@hSMnO{|4D;zrHm3QOF{rmP4zL>DnXU2Ik4*81aZ0)6&J^|4uvxY=&&B9M@S3dQW ziUtc7dFj7_X7>i-p#Fn&xWUm|4n#*PAbQtP4XXWN4UG`BF5d}9aGRG0^~ zpr!1S43WLO09;BRC&b4t#FN_%}!gCj3UT>=B=4=;^zgX%MjIHDJvZzd?tgq9xj6grWkcJ-Pm!MfLLe zLB-PMcU$GY14L+B-Bd(V_WFAfe6a+CrdtErg- zJ60cq6b0_jPrO9DvQy)e`N=NHS*(n`bM+-dRv|u(=E#jZDelV+9VN?ncp-JgW~V52 zwIVT{rMFy#iB_M(Mw>~mXBU^-bBK=;wyjfDo5?#^YSF?}mRd7wq62j@gZG{qXc5HU zVDBjeF{zt&@luq|SH3a3{425RvT91&_0wC9&PM*qmz8chsA5hT-f15F zrSL(!X;BTwDiiEub(^}Z-R{h)d&0I&fsbtYeAV3}_$8GRD|%|OJ~+h*h`vXEM9QO8dd zYmcYsgDMk9EnNq{G&8{Pb|>275wcZ*`2F&2Ai4O>P`Q}+<5oRx zrPpuMxO3{uh6!dA$rBGk=l*5JDBs_#A7T&8ueX}y@n1tomGnc^+RK`ACK zLffq81Sa`D!bq!B@3l;{`s1Nv*M+7=k&=Y6F+bzvd|`RbLXY;w2Hwl0yKtmbNFX^9+ewfx;t2zs)75Y%Ib|Y(r)JqTX&`@w z%}7=<5c>FQS2}Pq)z64{m*tnb+|YtmHot9pU(gxEHU#q)PVnLF4y=SM0hTI{pnxwV zsN%fK#6Rs1yY}VO6u$x3qEG}|OT8a_iE+05g2z`_)lscjNhbD8G^x8a*2!F>ob6beCvJIleF zH3wh{PTx0X>`mG-?1DAVP|?b?F<%wGUBYg5*s|e-phNX0_gTC@TRNC(j*g~WF;^PL zARucn&XYxOAIIj=V5+@L7RS zldn|5rI%qum$#hk_xd(kb`WaLPcH}E%~bUsZ<1qX#}@XMsqs6Kot`D*wds7)6COlc zokSyrtrAkl?A*_e15eCtwA`Wq&o4ieAI9F%2`_l*J@F&|u;DhH3sEfkW_n?ZcDbo1 z+wN$wWxm0*s`l0k_J_eld4u7A-A{Rh&@pB)Zsm(!X%R#(Tr8P(*iJ#*>OX%|Uu!JA z!esJkcl7(ko9D-SboRK2;U0)YDdnJeqg(8hgx*E=U?|?Tock&cHK~F%Q#bmVAmuK_ zkzF@2vu$L-NkOgb4R^L5(TsMv)Y&Q(cDd4GaUt*G`(yAraq3)7P@Yd?@+NHM@9%6Yxyv$W{ zL_n}T8t;;n^hj5AceT|GzDxF)R7G0AoR{0|@U^U6)%&h#I8H{7yqE~6;QS2^OvDWj zJ*y8$_+H^7;p6>E+#kS^Ialc$oIcDwkYDypr^YP?Kln+r8pGdo>XcWEk8m}-q3vST z=@)6ZjGI!jn?6^29)0=oM>HP$QeDxAW|8 z({W^V@TAnyhTf${o5w#L=I6%#MlbO&y0d_ALl(>;ppG~=%|!16ET-Sp6SM3O%pc1L zkb~>y%25gA(AR%lhrw4-dZ{+&Sdw%_1V50fXJ7T33R4l~TG zCQ1>CD_!B;%-n*KhNp6qZDDm_6v^!q=K8X<2_R*c=DQ{_!?j4)|Gh z$)g16j9v0#70|O28@VGv^YppaKuXHy=nOB|RfDdus0rn?SlP`aY9r1lW%Ig#1PpsM zfkvGKr9>}T){=b~jH-1$amp#i*s^Ilxo>O(5}haa8suA={#qQP1rF=zp6E&#clGlo zQ8#^Un!oYxPd02#rA@Q>ToHN!Z3Va5)I8ncqZFF&W?%U3YtH?^LCKIO?W=Ew`|BAd z6sD@q^O2`VG;1|N{gjWMBj4G)yC%F!HmuXcP0|Z()S-f9ZV|=BT+x% zXXboOg!qK#*HviUOI5r7uwwA4;|uj7yL|%uV%c?-uS4~n2K@zIKG(-2Jx-aOIOT&Q zDb_K?UfdU>8?Gh4`@>OY7$(PD^o#pP>C?eakH(rUUW++#Km1OE|MC6d*WNYOuH-Lq z&&8e1+WU8=<=(W8u6JU=&Qz&#>PU0Cy{xa^uBJ>&S3Sz&xz0GUrVYkQg2rFGXMJ#E zNK0~@49HX(ZjDj>uJHho8!zL3=hpSzlf74PHfcZ*5-4$POOTfA#w*eYLTFXw@`2e&#{y8h!(cGw^KMVz z`~vY!6W(HJ2dq&T{%%v-i+}|iWsvQ=iTJLGr`g z$FzvG#zZJ*%#_r+P0Q-LmUV-YPs%ORQ+i*VFRlJbl==Dfz|LHL^6D#P`7XvKZ~(o| zzO?rBQkQ^mh|CmIne*>1weWylB77GQb%@JMr!Ym#TS&8Kr0gJH$xHrV!*9iE@Gj5SA!KPCO(a5-5Z=GR#69X1tuRPEN8@Pa=pg zPRkf;Okz7F+1)eQEi&mgFV4F%PS+53Q;2=a!fR1d{5?~&m=}WzQ`%vGA#WF8!5_J2hmVjC#P*Y&5v-bEnBvqD&^zCwaB1H9)7 z|L=0PbwxIamOUn55m#8Zg~`VvQ*0{Z21Upz8ZMD45d)A0$P!wR^f4}4)hkymI9Fwb zbmB?w35@gLcG(}7Rp$*^$SBrIr3YTTBC{T(4>Mx%xv=UB_)2PYSYX(<$gB51XN!jO z7Q1lu^t`?XS3CKgp8DB}bbJ%}YT1%6I4_}Xl!7q>eWpno!O$@y*hU5{BnsvqWgmDK zFUv#i9L`6p0AXV~xJoAzB*N%HSqV`;Ku+4Uk%Jy0DOw(XF zjuc{^W^YTqTBzZkGn40py_PTUp5}GU^vX4F`D>j^*Kl>9w@o3c4h(vlFUu=VHi9uU z3J#I4BkI5l8VOH~AT2>bHY2e~1FGtddmx{8bcEz~Ht*2EL)VRpZepWc=1Vfkzk=E zXt-nnAzI#f+8S;my!nO^&oqLjFCe7=iC1g{syKJlt8}^oAtx+QTP__-jI;DiGOE0J zT%+{E%#D<&!reQ!*IK!ek9p zu#KzeqN=j!sy|zySQ_dGrK*Pw(%E2-0P8@98*}Zzc@Po-g-q&K~ z0s92-LQz$%0{YEtO`CU(8ui`~4t0hO=CSXId1zNMW|Ii}35QChB7Zj0n}xOhDwdJBYN@b2o-kp6<2OSrowba)Vix*>@ep&|Ft;TNE~iZs-5A%K!Z_(3RR zI!37)E`PEP4Fek7_8n)y8N6fB#SiXv_}i634*3XeMO%3xI4g4Q7t@KG1rJa;Fd1^X zB3FS=M^c_YlxO07=|oF1kh&ExAGMShMm950xfG;BjIEdjvlVLcp~tyG{6YIiCwb0? z=N?;_KeA;ac0-S|Iv<@r|JY(OD3Dw4IQPincD?^-{h{>7zFG~D&;4U!8n7IHfBX}S z$`c3sC&|_R6#T=;>IYe)J9kt=^9wRE0?^_Cbcu=IKOu8c2p)Sa{cF1Ed1PW2T3#8h;VPZB>pG*PA z3D#$Q-*17oGQc7TALI{Hrm#jPC}CV6j2UDjCTETQAx%$!C6-Vw9jUxX(xu~%?||1c zJdu)3**-1fiyR+yXt_Fh^?A$Ozk|3Q2PpC2-&&B3E$ECE>>39M1!!af3gV;41R5Qf z-41OaAmKthWWsNz0Mbf)IVHXlBcquI+t$ceBJ;N@@g+rkHxYlk_P+>pl+k9e)~Yyx zmt?jXgtqNpL*kfH`;^*2NsLWNdpsM!vDjycgq@m#`nNf}eZ1f3*h6f&@yCfKZ1trop_}aB&Hw!~#wUP{v$j*pA)z z4iDVB152V}6a+F6RE&fGNTQ+%E+{4s?#;pla3M)521(n)q+-sLKpMiEGh#I6E*p>K z!0u9D-n2J*O#>)1^xnS%x)K--7IDiFXp9AJ1Tah?2_}5YWDz$wLYqFmb=m~{CJ$=R z(Y88J0OgJA-+{xY&}_;-3pg$T`;P^NeIG*bVD!I3VHZg=*6*wx0WgOcc?0~9MvAH`;JfA9xZDO0c8ahywf2S^%-iCJ`B^Rh~qv==q;<0+CI6 z0wBWx#0LQJyzhc8^8<1>_yq!2X_-eNP+>wO_>zNNWun7v{++XCF$5OV!U#EVs%Yz} z9dH^8j=BX!Lqt4#44(rlVx7o7;%*2vVh5VmE<*MIf10VD@T8115_s7MT8>? zfpNh&2!ks@U_WC+2!Lo$hisT1TNYrC$s=Mi5WlQd%$r2yAS88L2=VY*HmafqdI%sV RDPx!cToE9&k%xf2{{!Lm*)sqD literal 0 HcmV?d00001 diff --git a/include/javascript/yui/build/assets/skins/sam/editor-sprite.gif b/include/javascript/yui/build/assets/skins/sam/editor-sprite.gif new file mode 100644 index 0000000000000000000000000000000000000000..02042fa1474cd62d7de63588ae536f5495d45be2 GIT binary patch literal 5690 zcmWlc`9D;R!-mf}b7mjrAf%KTkv*d#OKL2MR7O!K8KEpaHR35eVysz;lYJBhC87)o zNg7L8q9!etQe%sx3@ubL@Atiby8eOd^SSQb4tAzy-tvGic2Np^|NaAp;hCA4+S=M- zUAeFK4*dD^XDMRGFF)tw$9*iT2m8w%ty0T!pRs@DFe)ST&@i`OGY$5)F!R^V2D+-9 zZg@L7IKIBEcWPj{KW+DxeB5?3i?Ok>0|yQ^#2W?%p8E2{I7SB+wq81kGr`bJMPCfpVHFOvZPbSo3}h`zLhV!H8<216B~Q^(&dF$yL)XdlGlD+3a#6quf#9v`2K7J<2Qvh%M`N>2e@9|g%tNv1X> z%@3NV#z!Y6u+7cQ_4n?v+1|6$AJ!%tB)**M|2z`V@~mp8w_N<~(OBQ&^2*Pit9f~O z4Gj&<`xCd1>5AXJ%BZTNniHYH1VFz2p zIoa9ws%!=yrAl7s?)TU;FGOb_SAOd&)2`Hh(DdLv&vsy7Kq{5a&CSt&!5{!g0e#?q z`+p|@f)tPvRqX}*);NNK?$L4-Mx-KV7pv9AodM0tRF^uOoUH z{qpr2#ONOcdkP#I?u4mZq$9@Bz&t>9GiE+BKf6U8TrrS8PRhCoA9iNe@?jFTkD@-QkQdL zu=1AHCe`<`YhTRO1hfj{$ZGqW8|TNnGWB+Arz?*a{am zlBD{6nxog<#-w!JbTmHmyV{^y{@un6m)&_vQq2H=+;}y z@qQcx%h0?LO}4x(c}n9P3s5~bJ-Q$NBhJQSLrUJ8v)X0lV=4Oe(_^Vo^fBk7B`&KD z6Ri#6Q?wo~$B~F=mV_#MRD)g0+$xq(jikc<4O#}irK8N7E&-F-ZiSm!I!enn-Eu|3 zZ&a=4*E6_Q3ta~kb&qSZdUjfMWRR2@Zvv(Y!ai1}=?1@Za0?}xTMtqzMY?YZp zBox@RaWPjI4!Wp{i?wzo;gu79ZJp3I7dui*(pOqu$RTbqU8QYvgHl?qea1?vj%uyF zeqKb^7BS6Ix z(jZRMJDqy*$)xu6GoJaMj+A5s>e`gw`hBRf`iXhaZSv?Xz3LWqxJpoiRH8Kyy>fPE z9?Fr`O(1pXTRjh4YQ>*9U~!xIngq*eT_VNbu7B6Fr%f-bC0mFaW)h# zx~QrxZKwG=s2#%s;t&nq(zqRY%c%{-q4$a%4!Wmp#aLK(E91G!re&!Ks%2=eZmQ~_ zF)Cx`&Lr%o#fUI?RSyZ;q2T`xxo4Bbs7cfG_|ESHmoJ6H-DZTgwtw1g-%5aB)3eF9 z3$8gcDXR(2vY#(CGMcO|OfdIt50Bi^ifH+c?s^3|qmNZSaDv;2n|!?;b`Gk-ahgX? z1$S$13w!ZgpGagldIVf%S@urftX}#3QdHXU+B0-sX!25Z;-WlxiH@;Y#gbrFMd}f> zvn2O)8$sMd5ss20iQB^D()Iue!#N1J6KRw8_h+gop$Y#`IxvB$Oc=MjQDYiI^=t$W zu4kl0gb6Ww%JCCx*rqbt-sGe1LQH7VJ*>Ys<($yQT>7zg2Bwjyx>7;;mFKGEmYSYg1rKrMo$=@^)6 z3NMk);xsidVINRyg-sw>Ao)sRi4!gLgK^d;rf4s@Or_dR%eiitt}X`7^x#W=gfC?B zPYtcIBj)M|xY!+ekj>stRJB!X(l!=B&(kacGy9cxH*yj@TlD@(qTSVoX?!mg$vbR%Gl3vzM_FDtyBcvJ=j8dBp|X|N{3Cwl-X|T8q_jG<^mpV|p zbkRXAw^%1DDPP;2$EN0skM zNAd(9nu>)O*C-DxJUUZIA;=?$QjB z`*rJ0g{BFL?CoM9={gqFPLC>JDy&lQg;_0vted^ca!E|Ut^RBZMlRQ|d7BZagr3G!0)QP9+Cy+eJl z^F{E(qHq_`96o*wRpqYe#w&+t0gw~knc zU^?z%GG#P6vPA8G+`Utt|BN-vy3ti~9IHRH(T~6Ic(O^UCMwn7WDN8EP^eXc{&6{F z*_)Gtc6LYvP99`5RJZo!p6&ee?k{t3 zUpZMWmNPi=Az@qd$&tn@rpFDz6{PBMgI)fY*0JhVRLjWb1rWzxWbe@_V#S!wCX^>1^e!x z_aUBZuZ^{zsPM^MnJ=@jH1)Cy;`qo7mYZXcjuMW(bQ>|JNB(1JUGJluPo*S{Oxw>J#^s?PuSFVg`8Wi zTsX6NSM%8GXG=GatSs!&Tz*ygEV;5ebUwC-yb-7Vvzw%$RHkGRY@zzzMK!N-W440w zY;V6Zd+fh|KL|(2Q2JbV?p%~%{#6@8<<2uZ77Cw7oWw`J7(c^YD7v|Q-pJ|ijC6zi zi>?-^-Z1`akhQ{bf>f#w%M+vXq|4L09~pPeQ9UkYC`rAnEQNL4SSfRjkt-T>R6x?D>fP>uVKZl5mUp3u`4W)u>{YEfcq#}o)It4jWb^z zZ@)TTMuOkFgtuFw8YGbqm?pSrCpZlfKIJA%<;F=xgj4~cN=VXUB$lxfPq-z%$xRIO zS8ZS^acbl$QR2E%#0mwT(}1G_FewAUNWc{iVG9S&ti6b*Q?0~Q)eO=wLNY`VD=C+_ z!h-H_x2)rnh%qvAT+&?@gb`D#QQ|NH=ei(+EJy;trR=B*l(ddXDYZvTQJ_-j_A%E$ zNldD+LoC>sVW#mELb$~H zR+!LeG4h8AEr_W~LSlR#A`*cpb8FCGTHZxs5_+(MY0Qg-t_eUxgm6m;zug!ZcvxAo z1eOXlN(3Y&E+plq|L#iP@G;$Wm$DmjMc(YnWpTpsM#wxYst*8OO9*ELlv85aP61wz zq39;WY4b94D>5{HQGJ#&7%G`Q_D=uZIE#@(9i`UkcpmzzG5xRo0jf^KyeZ0>Cn}-D z#U*MDpOnRqw7cp5b#-=~B8sWV{MiWJ6reqw9xi6-)$A<$GEPiM304>un8KLkK zRzw-Nnj8fNxSEl>T9oq;&ZYnF^8s<^!jT}e+-M;7!mpeaK4>e9H#W_~*5r6h=U`)U z41et-Brt-_2UQ{T@9HYLv8X;K-pT~yS=ib*j;CKq8vE~S?VuNuyn zb>L6#hSzZOGzR$-2cvB5GnfacnV5|fLUQVG5@McVX2DpNHTAdS2|Tu zXr1pQQIR3hioRE@H|&X8at~I#QMCN22gB^KLi>M(dcz>ygS11{Ym+-)dx@sn+9n?NfT_i_#Co>&EV-Pyp|Ja%rW? zb({Qh#V7bQDFUUCS$Bsg$ft8=i`jU7#aZ4X)@Pzkw^qm z5#x#jVSP4i$Go*(gg>zXx$J?p2PzMXDr@%K0yPji1IF=j`eL#!2dgV4r?6pT2~eX^ zm56`|EJD|In2PRumG~?cH0cW zUJR1OcMh}hERn1ka$71Y|A7)N2mm_{HiZTBvv4#NyNQ8B(qvTl*c}2OJs(VFVLVZ6 zgD%1l;n#~Wr85`}GUO@1R+u9U4#pkD?BRgQ=>GuQ&P9Y$zQxd8>^3p9uCjc`5${7v zb&-kZ4<-89Rr=w){S3H-3Y1tWCJ||X%^#{d0(YQ5g@9@yBzkfE9Q1%95m+LI+X2}c z7F^F(3DW|SPl9_n1XUs2j@ElQ>RI9%Y8efIj&|xoET~Bit8DNJBF{;nS_U9S8$vA_ zubKc2{Ko$r?c7d~FFpu}{SP_35eN^upL(_Ka8AP@aG&VymvXh?SgM0MjVxl`7t!vK zuH3i#+_cl;0bir;pd(Ta$OIS56mc}jMoWP$oQRt47zK9UHBX}(e><|aTM zuzs+bFX!0=_C17-PhiA=PtJveJ8IUqf1heKdc@Q zeMp+emMtso64I-dmD&Wqq2sU-mNz1u|w~9K|>q6X(l^3C?(5)~zN!nXnEQg(74@A9Wwj zTLhD90B4EFSqxG@k~5>}Wdv&`74#FWuv7%+jbc^- z%5HIeOv@vi8Tb$y=8QKkL=4C>@F#?bjRaS5kZ2=7f*E+MnCdFQg&=s+73hoz^KlWE zjY32^CYuEuK;E1|WbOVz%vr=eUjVnixHBj;igaOvsX7cW^b6IIIS_OKkBxa1xo^Oc zL**7g0istJBUncaaAk&)3vg)+#NJ@&j2K8nsX8chTQmeSvC!yX!N|}uJL<;B&?pmt z3ZS#5x!16zbxQ-=BmHa6goY>S2K9gb`pje_A2 zyttS_PBZjErjiA>Nr-9!(i9i7`YZy8pdtp~V@$rofxVcRysbbnpeIFTybw4f3>o2E z9^$}5+((pRM(Lsw6O|GDReBB(CE`&s9WX(*wOJl9L48PaB#C&8>fo~Bov2KqPd7VLZet6gcnf2 zToyJFQKuxtZ*K5KkpkYCWWj+eX$nL(^d%K}C=^3+I(?`97aHUd8bb}3#CnrUIdHQw cR{5z6xrwa2TLKn}Th16kCL#yxH3(qwf7i6=Gynhq literal 0 HcmV?d00001 diff --git a/include/javascript/yui/build/assets/skins/sam/editor.css b/include/javascript/yui/build/assets/skins/sam/editor.css new file mode 100644 index 00000000..00451d8c --- /dev/null +++ b/include/javascript/yui/build/assets/skins/sam/editor.css @@ -0,0 +1,10 @@ +/* +Copyright (c) 2009, Yahoo! Inc. All rights reserved. +Code licensed under the BSD License: +http://developer.yahoo.net/yui/license.txt +version: 2.8.0r4 +*/ +.yui-busy{cursor:wait!important;}.yui-toolbar-container fieldset,.yui-editor-container fieldset{padding:0;margin:0;border:0;}.yui-toolbar-container legend{display:none;}.yui-skin-sam .yui-toolbar-container .yui-button button,.yui-skin-sam .yui-toolbar-container .yui-button a,.yui-skin-sam .yui-toolbar-container .yui-button a:visited{font-size:0;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-select button,.yui-skin-sam .yui-toolbar-container .yui-toolbar-select a,.yui-skin-sam .yui-toolbar-container .yui-toolbar-select a:visited,.yui-skin-sam .yui-toolbar-container .yui-toolbar-spinbutton button,.yui-skin-sam .yui-toolbar-container .yui-toolbar-spinbutton a,.yui-skin-sam .yui-toolbar-container .yui-toolbar-spinbutton a:visited{font-size:12px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-spinbutton a.up,.yui-skin-sam .yui-toolbar-container .yui-toolbar-spinbutton a.down{font-size:0;line-height:0;padding:0;}.yui-toolbar-container .yui-toolbar-subcont{padding:.25em 0;zoom:1;}.yui-toolbar-container-collapsed .yui-toolbar-subcont{display:none;}.yui-toolbar-container .yui-toolbar-subcont:after{display:block;clear:both;visibility:hidden;content:'.';height:0;}.yui-toolbar-container span.yui-toolbar-draghandle{cursor:move;border-left:1px solid #999;border-right:1px solid #999;overflow:hidden;text-indent:77777px;width:2px;height:20px;display:block;clear:none;float:left;margin:0 0 0 .2em;}.yui-toolbar-container .yui-toolbar-titlebar.draggable{cursor:move;}.yui-toolbar-container .yui-toolbar-titlebar{position:relative;}.yui-toolbar-container .yui-toolbar-titlebar h2{font-weight:bold;letter-spacing:0;border:none;color:#000;margin:0;padding:.2em;}.yui-toolbar-container .yui-toolbar-titlebar h2 a{text-decoration:none;color:#000;cursor:default;}.yui-toolbar-container.yui-toolbar-grouped span.yui-toolbar-draghandle{height:40px;}.yui-toolbar-container .yui-toolbar-group{float:left;margin-right:.5em;zoom:1;}.yui-toolbar-container .yui-toolbar-group:after{display:block;clear:both;visibility:hidden;content:'.';height:0;}.yui-toolbar-container .yui-toolbar-group h3{font-size:75%;padding:0 0 0 .25em;margin:0;}.yui-toolbar-container span.yui-toolbar-separator{width:2px;padding:0;height:18px;margin:.2em 0 .2em .1em;display:none;float:left;}.yui-toolbar-container.yui-toolbar-grouped span.yui-toolbar-separator{height:45px;*height:50px;}.yui-toolbar-container.yui-toolbar-grouped .yui-toolbar-group span.yui-toolbar-separator{height:18px;display:block;}.yui-toolbar-container ul li{margin:0;padding:0;list-style-type:none;}.yui-toolbar-container .yui-toolbar-nogrouplabels h3{display:none;}.yui-toolbar-container .yui-push-button,.yui-toolbar-container .yui-color-button,.yui-toolbar-container .yui-menu-button{position:relative;cursor:pointer;}.yui-toolbar-container .yui-button .first-child,.yui-toolbar-container .yui-button .first-child a{height:100%;width:100%;overflow:hidden;font-size:0;}.yui-toolbar-container .yui-button-disabled{cursor:default;}.yui-toolbar-container .yui-button-disabled .yui-toolbar-icon{opacity:.5;filter:alpha(opacity=50);}.yui-toolbar-container .yui-button-disabled .up,.yui-toolbar-container .yui-button-disabled .down{opacity:.5;filter:alpha(opacity=50);}.yui-toolbar-container .yui-button a{overflow:hidden;}.yui-toolbar-container .yui-toolbar-select .first-child a{cursor:pointer;}.yui-toolbar-fontname-arial{font-family:Arial;}.yui-toolbar-fontname-arial-black{font-family:Arial Black;}.yui-toolbar-fontname-comic-sans-ms{font-family:Comic Sans MS;}.yui-toolbar-fontname-courier-new{font-family:Courier New;}.yui-toolbar-fontname-times-new-roman{font-family:Times New Roman;}.yui-toolbar-fontname-verdana{font-family:Verdana;}.yui-toolbar-fontname-impact{font-family:Impact;}.yui-toolbar-fontname-lucida-console{font-family:Lucida Console;}.yui-toolbar-fontname-tahoma{font-family:Tahoma;}.yui-toolbar-fontname-trebuchet-ms{font-family:Trebuchet MS;}.yui-toolbar-container .yui-toolbar-spinbutton{position:relative;}.yui-toolbar-container .yui-toolbar-spinbutton .first-child a{z-index:0;opacity:1;}.yui-toolbar-container .yui-toolbar-spinbutton a.up,.yui-toolbar-container .yui-toolbar-spinbutton a.down{position:absolute;display:block;right:0;cursor:pointer;z-index:1;padding:0;margin:0;}.yui-toolbar-container .yui-overlay{position:absolute;}.yui-toolbar-container .yui-overlay ul li{margin:0;list-style-type:none;}.yui-toolbar-container{z-index:1;}.yui-editor-container .yui-editor-editable-container{position:relative;z-index:0;width:100%;}.yui-editor-container .yui-editor-masked{background-color:#CCC;height:100%;width:100%;position:absolute;top:0;left:0;opacity:.5;filter:alpha(opacity=50);}.yui-editor-container iframe{border:0;padding:0;margin:0;zoom:1;display:block;}.yui-editor-container .yui-editor-editable{padding:0;margin:0;}.yui-editor-container .dompath{font-size:85%;}.yui-editor-panel .hd{text-align:left;position:relative;}.yui-editor-panel .hd h3{font-weight:bold;padding:.25em 0 .25em .25em;margin:0;}.yui-editor-panel .bd{width:100%;zoom:1;position:relative;}.yui-editor-panel .bd div.yui-editor-body-cont{padding:.25em .1em;zoom:1;}.yui-editor-panel .bd .gecko form{overflow:auto;}.yui-editor-panel .bd div.yui-editor-body-cont:after{display:block;clear:both;visibility:hidden;content:'.';height:0;}.yui-editor-panel .ft{text-align:right;width:99%;float:left;clear:both;}.yui-editor-panel .ft span.tip{display:block;position:relative;padding:.5em .5em .5em 23px;text-align:left;zoom:1;}.yui-editor-panel label{clear:both;float:left;padding:0;width:100%;text-align:left;zoom:1;}.yui-editor-panel .gecko label{overflow:auto;}.yui-editor-panel label strong{float:left;width:6em;}.yui-editor-panel .removeLink{width:80%;text-align:right;}.yui-editor-panel label input{margin-left:.25em;float:left;}.yui-editor-panel .yui-toolbar-group{margin-bottom:.75em;}.yui-editor-panel .height-width{float:left;}.yui-editor-panel .height-width span{font-style:italic;display:block;float:left;overflow:visible;}.yui-editor-panel .height-width span.info{font-size:70%;margin-top:3px;float:none;} +.yui-editor-panel .yui-toolbar-bordersize,.yui-editor-panel .yui-toolbar-bordertype{font-size:75%;}.yui-editor-panel .yui-toolbar-container span.yui-toolbar-separator{border:none;}.yui-editor-panel .yui-toolbar-bordersize span a span,.yui-editor-panel .yui-toolbar-bordertype span a span{display:block;height:8px;left:4px;position:absolute;top:3px;_top:-5px;width:24px;text-indent:52px;font-size:0;}.yui-editor-panel .yui-toolbar-bordertype span a span.yui-toolbar-bordertype-solid{border-bottom:1px solid black;}.yui-editor-panel .yui-toolbar-bordertype span a span.yui-toolbar-bordertype-dotted{border-bottom:1px dotted black;}.yui-editor-panel .yui-toolbar-bordertype span a span.yui-toolbar-bordertype-dashed{border-bottom:1px dashed black;}.yui-editor-panel .yui-toolbar-bordersize span a span.yui-toolbar-bordersize-0{*top:0;text-indent:0;font-size:75%;}.yui-editor-panel .yui-toolbar-bordersize span a span.yui-toolbar-bordersize-1{border-bottom:1px solid black;}.yui-editor-panel .yui-toolbar-bordersize span a span.yui-toolbar-bordersize-2{border-bottom:2px solid black;}.yui-editor-panel .yui-toolbar-bordersize span a span.yui-toolbar-bordersize-3{top:2px;*top:-5px;border-bottom:3px solid black;}.yui-editor-panel .yui-toolbar-bordersize span a span.yui-toolbar-bordersize-4{top:1px;*top:-5px;border-bottom:4px solid black;}.yui-editor-panel .yui-toolbar-bordersize span a span.yui-toolbar-bordersize-5{top:1px;*top:-5px;border-bottom:5px solid black;}.yui-toolbar-container .yui-toolbar-bordersize-menu,.yui-toolbar-container .yui-toolbar-bordertype-menu{width:95px!important;}.yui-toolbar-bordersize-menu .yuimenuitemlabel,.yui-toolbar-bordertype-menu .yuimenuitemlabel,.yui-toolbar-bordersize-menu .yuimenuitemlabel,.yui-toolbar-bordertype-menu .yuimenuitemlabel:hover{margin:0 3px 7px 17px;}.yui-toolbar-bordersize-menu .yuimenuitemlabel .checkedindicator,.yui-toolbar-bordertype-menu .yuimenuitemlabel .checkedindicator{position:absolute;left:-12px;*top:14px;*left:0;}.yui-toolbar-bordersize-menu li.yui-toolbar-bordersize-1 a{border-bottom:1px solid black;height:14px;}.yui-toolbar-bordersize-menu li.yui-toolbar-bordersize-2 a{border-bottom:2px solid black;height:14px;}.yui-toolbar-bordersize-menu li.yui-toolbar-bordersize-3 a{border-bottom:3px solid black;height:14px;}.yui-toolbar-bordersize-menu li.yui-toolbar-bordersize-4 a{border-bottom:4px solid black;height:14px;}.yui-toolbar-bordersize-menu li.yui-toolbar-bordersize-5 a{border-bottom:5px solid black;height:14px;}.yui-toolbar-bordertype-menu li.yui-toolbar-bordertype-solid a{border-bottom:1px solid black;height:14px;}.yui-toolbar-bordertype-menu li.yui-toolbar-bordertype-dashed a{border-bottom:1px dashed black;height:14px;}.yui-toolbar-bordertype-menu li.yui-toolbar-bordertype-dotted a{border-bottom:1px dotted black;height:14px;}h2.yui-editor-skipheader,h3.yui-editor-skipheader{height:0;margin:0;padding:0;border:none;width:0;overflow:hidden;position:absolute;}.yui-toolbar-colors{width:133px;zoom:1;display:none;z-index:100;overflow:hidden;}.yui-toolbar-colors:after{display:block;clear:both;visibility:hidden;content:'.';height:0;}.yui-toolbar-colors a{height:9px;width:9px;float:left;display:block;overflow:hidden;text-indent:999px;margin:0;cursor:pointer;border:1px solid #F6F7EE;}.yui-toolbar-colors a:hover{border:1px solid black;}.yui-color-button-menu{overflow:visible;background-color:transparent;}.yui-toolbar-colors span{position:relative;display:block;padding:3px;overflow:hidden;float:left;width:100%;zoom:1;}.yui-toolbar-colors span:after{display:block;clear:both;visibility:hidden;content:'.';height:0;}.yui-toolbar-colors span em{height:35px;width:30px;float:left;display:block;overflow:hidden;text-indent:999px;margin:.75px;border:1px solid black;}.yui-toolbar-colors span strong{font-weight:normal;padding-left:3px;display:block;font-size:85%;float:left;width:65%;}.yui-toolbar-group-undoredo h3,.yui-toolbar-group-insertitem h3,.yui-toolbar-group-indentlist h3{width:68px;}.yui-toolbar-group-indentlist2 h3{width:122px;}.yui-toolbar-group-alignment h3{width:130px;}.yui-skin-sam .yui-editor-container{border:1px solid #808080;}.yui-skin-sam .yui-toolbar-container{zoom:1;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-titlebar{background:url(sprite.png) repeat-x 0 -200px;position:relative;}.yui-skin-sam .yui-editor-container .draggable .yui-toolbar-titlebar{cursor:move;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-titlebar h2{color:#000;font-weight:bold;margin:0;padding:.3em 1em;font-size:100%;text-align:left;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-group h3{color:#808080;font-size:75%;margin:1em 0 0;padding-bottom:0;padding-left:.25em;text-align:left;}.yui-toolbar-container span.yui-toolbar-separator{border:none;text-indent:33px;overflow:hidden;margin:0 .25em;}.yui-skin-sam .yui-toolbar-container{background-color:#F2F2F2;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-subcont{padding:0 1em .35em;border-bottom:1px solid #808080;}.yui-skin-sam .yui-toolbar-container-collapsed .yui-toolbar-titlebar{border-bottom:1px solid #808080;}.yui-skin-sam .yui-editor-container .visible .yui-menu-shadow,.yui-skin-sam .yui-editor-panel .visible .yui-menu-shadow{display:none;}.yui-skin-sam .yui-editor-container ul{list-style-type:none;margin:0;padding:0;}.yui-skin-sam .yui-editor-container ul li{list-style-type:none;margin:0;padding:0;}.yui-skin-sam .yui-toolbar-group ul li.yui-toolbar-groupitem{float:left;}.yui-skin-sam .yui-editor-container .dompath{background-color:#F2F2F2;border-top:1px solid #808080;color:#999;text-align:left;padding:.25em;}.yui-skin-sam .yui-toolbar-container .collapse{background:url(sprite.png) no-repeat 0 -400px;}.yui-skin-sam .yui-toolbar-container .collapsed{background:url(sprite.png) no-repeat 0 -350px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-titlebar span.collapse{cursor:pointer;position:absolute;top:4px;right:2px;display:block;overflow:hidden;height:15px;width:15px;text-indent:9999px;} +.yui-skin-sam .yui-toolbar-container .yui-push-button,.yui-skin-sam .yui-toolbar-container .yui-color-button,.yui-skin-sam .yui-toolbar-container .yui-menu-button{background:url(sprite.png) repeat-x 0 0;position:relative;display:block;height:22px;width:30px;_font-size:0;margin:0;border-color:#808080;color:#f2f2f2;border-style:solid;border-width:1px 0;zoom:1;}.yui-skin-sam .yui-toolbar-container .yui-push-button a,.yui-skin-sam .yui-toolbar-container .yui-color-button a,.yui-skin-sam .yui-toolbar-container .yui-menu-button a{padding-left:35px;height:20px;text-decoration:none;font-size:0;line-height:2;display:block;color:#000;overflow:hidden;white-space:nowrap;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-spinbutton a,.yui-skin-sam .yui-toolbar-container .yui-toolbar-select a{font-size:12px;}.yui-skin-sam .yui-toolbar-container .yui-push-button .first-child,.yui-skin-sam .yui-toolbar-container .yui-color-button .first-child,.yui-skin-sam .yui-toolbar-container .yui-menu-button .first-child{border-color:#808080;border-style:solid;border-width:0 1px;margin:0 -1px;display:block;position:relative;}.yui-skin-sam .yui-toolbar-container .yui-push-button-disabled .first-child,.yui-skin-sam .yui-toolbar-container .yui-color-button-disabled .first-child,.yui-skin-sam .yui-toolbar-container .yui-menu-button-disabled .first-child{border-color:#ccc;}.yui-skin-sam .yui-toolbar-container .yui-push-button-disabled a,.yui-skin-sam .yui-toolbar-container .yui-color-button-disabled a,.yui-skin-sam .yui-toolbar-container .yui-menu-button-disabled a{color:#A6A6A6;cursor:default;}.yui-skin-sam .yui-toolbar-container .yui-push-button-disabled,.yui-skin-sam .yui-toolbar-container .yui-color-button-disabled,.yui-skin-sam .yui-toolbar-container .yui-menu-button-disabled{border-color:#ccc;}.yui-skin-sam .yui-toolbar-container .yui-button .first-child{*left:0;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-fontname{width:135px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-heading{width:92px;}.yui-skin-sam .yui-toolbar-container .yui-button-hover{background:url(sprite.png) repeat-x 0 -1300px;border-color:#808080;}.yui-skin-sam .yui-toolbar-container .yui-button-selected{background:url(sprite.png) repeat-x 0 -1700px;border-color:#808080;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-nogrouplabels h3{display:none;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-nogrouplabels .yui-toolbar-group{margin-top:.75em;}.yui-skin-sam .yui-toolbar-container .yui-push-button span.yui-toolbar-icon,.yui-skin-sam .yui-toolbar-container .yui-color-button span.yui-toolbar-icon,.yui-skin-sam .yui-toolbar-container .yui-menu-button span.yui-toolbar-icon{display:block;position:absolute;top:2px;height:18px;width:18px;overflow:hidden;background:url(editor-sprite.gif) no-repeat 30px 30px;}.yui-skin-sam .yui-toolbar-container .yui-button-selected span.yui-toolbar-icon,.yui-skin-sam .yui-toolbar-container .yui-button-hover span.yui-toolbar-icon{background-image:url(editor-sprite-active.gif);}.yui-skin-sam .yui-toolbar-container .visible .yuimenuitemlabel{cursor:pointer;color:#000;*position:relative;}.yui-skin-sam .yui-toolbar-container .yui-button-menu{background-color:#fff;}.yui-skin-sam .yui-toolbar-container .yui-button-menu .yui-menu-body-scrolled{position:relative;}.yui-skin-sam div.yuimenu li.selected{background-color:#B3D4FF;}.yui-skin-sam div.yuimenu li.selected a.selected{color:#000;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-bold span.yui-toolbar-icon{background-position:0 0;left:5px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-strikethrough span.yui-toolbar-icon{background-position:0 -108px;left:5px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-italic span.yui-toolbar-icon{background-position:0 -36px;left:5px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-undo span.yui-toolbar-icon{background-position:0 -1326px;left:5px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-redo span.yui-toolbar-icon{background-position:0 -1355px;left:5px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-underline span.yui-toolbar-icon{background-position:0 -72px;left:5px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-subscript span.yui-toolbar-icon{background-position:0 -180px;left:5px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-superscript span.yui-toolbar-icon{background-position:0 -144px;left:5px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-forecolor span.yui-toolbar-icon{background-position:0 -216px;left:5px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-backcolor span.yui-toolbar-icon{background-position:0 -288px;left:5px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-justifyleft span.yui-toolbar-icon{background-position:0 -324px;left:5px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-justifycenter span.yui-toolbar-icon{background-position:0 -360px;left:5px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-justifyright span.yui-toolbar-icon{background-position:0 -396px;left:5px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-justifyfull span.yui-toolbar-icon{background-position:0 -432px;left:5px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-indent span.yui-toolbar-icon{background-position:0 -720px;left:5px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-outdent span.yui-toolbar-icon{background-position:0 -684px;left:5px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-createlink span.yui-toolbar-icon{background-position:0 -792px;left:5px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-insertimage span.yui-toolbar-icon{background-position:1px -756px;left:5px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-left span.yui-toolbar-icon{background-position:0 -972px;left:5px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-right span.yui-toolbar-icon{background-position:0 -936px;left:5px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-inline span.yui-toolbar-icon{background-position:0 -900px;left:5px;} +.yui-skin-sam .yui-toolbar-container .yui-toolbar-block span.yui-toolbar-icon{background-position:0 -864px;left:5px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-bordercolor span.yui-toolbar-icon{background-position:0 -252px;left:5px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-removeformat span.yui-toolbar-icon{background-position:0 -1080px;left:5px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-hiddenelements span.yui-toolbar-icon{background-position:0 -1044px;left:5px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-insertunorderedlist span.yui-toolbar-icon{background-position:0 -468px;left:5px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-insertorderedlist span.yui-toolbar-icon{background-position:0 -504px;left:5px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-spinbutton,.yui-skin-sam .yui-toolbar-container .yui-toolbar-spinbutton .first-child{width:35px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-spinbutton .first-child a{padding-left:2px;text-align:left;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-spinbutton span.yui-toolbar-icon{display:none;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-spinbutton a.up,.yui-skin-sam .yui-toolbar-container .yui-toolbar-spinbutton a.down{right:2px;background:url(editor-sprite.gif) no-repeat 0 -1222px;overflow:hidden;height:6px;width:7px;min-height:0;padding:0;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-spinbutton a.up{top:2px;background-position:0 -1222px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-spinbutton a.down{bottom:2px;background-position:0 -1187px;}.yui-skin-sam .yui-toolbar-container select{height:22px;border:1px solid #808080;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-select .first-child a{padding-left:5px;text-align:left;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-select span.yui-toolbar-icon{background:url(editor-sprite.gif) no-repeat 0 -1144px;overflow:hidden;right:-2px;top:0;height:20px;}.yui-skin-sam .yui-editor-panel .yui-color-button-menu .bd{background-color:transparent;border:none;width:135px;}.yui-skin-sam .yui-color-button-menu .yui-toolbar-colors{border:1px solid #808080;}.yui-skin-sam .yui-editor-panel{padding:0;margin:0;border:none;background-color:transparent;overflow:visible;position:absolute;}.yui-skin-sam .yui-editor-panel .hd{margin:10px 0 0;padding:0;border:none;}.yui-skin-sam .yui-editor-panel .hd h3{color:#000;border:1px solid #808080;background:url(sprite.png) repeat-x 0 -200px;width:99%;position:relative;margin:0;padding:3px 0 0 0;font-size:93%;text-indent:5px;height:20px;}.yui-skin-sam .yui-editor-panel .bd{background-color:#F2F2F2;border-left:1px solid #808080;border-right:1px solid #808080;width:99%;margin:0;padding:0;overflow:visible;}.yui-skin-sam .yui-editor-panel ul{list-style-type:none;margin:0;padding:0;}.yui-skin-sam .yui-editor-panel ul li{margin:0;padding:0;}.yui-skin-sam .yui-editor-panel .yui-toolbar-container .yui-toolbar-subcont{padding:0;border:none;margin-top:.35em;}.yui-skin-sam .yui-editor-panel .yui-toolbar-bordersize,.yui-skin-sam .yui-editor-panel .yui-toolbar-bordertype{width:50px;}.yui-skin-sam .yui-editor-panel label{display:block;float:none;padding:4px 0;margin-bottom:7px;}.yui-skin-sam .yui-editor-panel label strong{font-weight:normal;font-size:93%;text-align:right;padding-top:2px;}.yui-skin-sam .yui-editor-panel label input{width:75%;}.yui-skin-sam .yui-editor-panel .createlink_target,.yui-skin-sam .yui-editor-panel .insertimage_target{width:auto;margin-right:5px;}.yui-skin-sam .yui-editor-panel .removeLink{width:98%;}.yui-skin-sam .yui-editor-panel label input.warning{background-color:#FFEE69;}.yui-skin-sam .yui-editor-panel .yui-toolbar-group h3{color:#000;float:left;font-weight:normal;font-size:93%;margin:5px 0 0 0;padding:0 3px 0 0;text-align:right;}.yui-skin-sam .yui-editor-panel .height-width h3{margin:3px 0 0 10px;}.yui-skin-sam .yui-editor-panel .height-width{margin:3px 0 0 35px;*margin-left:14px;width:42%;*width:44%;}.yui-skin-sam .yui-editor-panel .yui-toolbar-group-border{width:190px;}.yui-skin-sam .yui-editor-panel .no-button .yui-toolbar-group-border{width:210px;}.yui-skin-sam .yui-editor-panel .yui-toolbar-group-padding{width:203px;_width:198px;}.yui-skin-sam .yui-editor-panel .no-button .yui-toolbar-group-padding{width:172px;}.yui-skin-sam .yui-editor-panel .yui-toolbar-group-padding h3{margin-left:25px;*margin-left:12px;}.yui-skin-sam .yui-editor-panel .yui-toolbar-group-textflow{width:182px;}.yui-skin-sam .yui-editor-panel .hd{background:none;}.yui-skin-sam .yui-editor-panel .ft{background-color:#F2F2F2;border:1px solid #808080;border-top:none;padding:0;margin:0 0 2px 0;}.yui-skin-sam .yui-editor-panel .hd span.close{background:url(sprite.png) no-repeat 0 -300px;cursor:pointer;display:block;height:16px;overflow:hidden;position:absolute;right:5px;text-indent:500px;top:2px;width:26px;}.yui-skin-sam .yui-editor-panel .ft span.tip{background-color:#EDF5FF;border-top:1px solid #808080;font-size:85%;}.yui-skin-sam .yui-editor-panel .ft span.tip strong{display:block;float:left;margin:0 2px 8px 0;}.yui-skin-sam .yui-editor-panel .ft span.tip span.icon{background:url(editor-sprite.gif) no-repeat 0 -1260px;display:block;height:20px;left:2px;position:absolute;top:8px;width:20px;}.yui-skin-sam .yui-editor-panel .ft span.tip span.icon-info{background-position:2px -1260px;}.yui-skin-sam .yui-editor-panel .ft span.tip span.icon-warn{background-position:2px -1296px;}.yui-skin-sam .yui-editor-panel .hd span.knob{position:absolute;height:10px;width:28px;top:-10px;left:25px;text-indent:9999px;overflow:hidden;background:url(editor-knob.gif) no-repeat 0 0;}.yui-skin-sam .yui-editor-panel .yui-toolbar-container{float:left;width:100%;background-image:none;border:none;}.yui-skin-sam .yui-editor-panel .yui-toolbar-container .bd{background-color:#fff;}.yui-editor-blankimage{background-image:url(blankimage.png);}.yui-skin-sam .yui-editor-container .yui-resize-handle-br{height:11px;width:11px;background-position:-20px -60px;background-color:transparent;} diff --git a/include/javascript/yui/build/assets/skins/sam/header_background.png b/include/javascript/yui/build/assets/skins/sam/header_background.png new file mode 100644 index 0000000000000000000000000000000000000000..3ef7909d3ed04956a06c5d9017076ea30e0ced27 GIT binary patch literal 158 zcmeAS@N?(olHy`uVBq!ia0vp^j6kf+!2~3434ebKq$EpRBT9nv(@M${i&7aJQ}UBi z6+Ckj(^G>|6H_V+Po~-c6*+jiIEGZ*s_F9NI$*%V9Q*UX`TlF!Ldi}q7dA02yr`^X zu-PrN{%75tzwegsKk4J*;_R|w)xBe%IT`Nt9oJ`MW0-m*yz~E_s%D^B44$rjF6*2U FngH9xIDh~E literal 0 HcmV?d00001 diff --git a/include/javascript/yui/build/assets/skins/sam/hue_bg.png b/include/javascript/yui/build/assets/skins/sam/hue_bg.png new file mode 100644 index 0000000000000000000000000000000000000000..d9bcdeb5c49910d5c32c9ebbb134200bf138b7b4 GIT binary patch literal 1120 zcmWkuZA?>V6h6*nD|EKy_G>T#efd;-TcIEZRG=3KG$^eF2Q{FAMV4*KY}f{qh`QSV zerz}DmTbC_Y|fEr#w0P0=t#CW_qsTZ+oCcxM!nmzgkYx0y)F9Qv+IxZJb6w|&dGC5 zaz;Z<^@~z7QUPF5prJObvq_J$hJ`xXo5wcl^n8zhtsmg}%|C)|K3%8x)wT6C_ipWb zw=>oa{%CJkw=1x%v!^@U-5DL&ajAP1z;mggH7#{nz-rJ$faL=7qA45La$rShQh@N! zu%sTCvXE1t{K=eCf%*<$g}~m_lTbYf%#DuhOcn)}oyL+UY!^T)N0SIlg&q}p70^Bg z#v`A*ftBD@6%H#L*N*0!pas#aR&fdVH33r!@M?%V4H}RB^=Q5i+Cy}fVbYD}B4EjH z?P{0x>Acg883%Oa|AzJ?B#N%FVmw`fKNY;g=C3&BXB;Z@Kam~dpydSE;!)KoPs+}MGZ#35TL&dgu1t8ZJCOzunMR5)=3wB`6<04>Wd>fEGNt=fUO7S z2UdorB;0d<%}W2%DB8|}rj&7Bd@G600GiIAl}DfA(T~fGjEtPSpMM-+!RdW!t0gq&tGw>1(Ck!bL+QCwfHM zFSfg6C%J1(_sXrL%2?h=Gs#tB`jY5~^n-B4=5yiEV7#4=o|0Az*Nu@}Ih_Oz$pHOG zC`&0{EO(L#V`PcEmKepS-spt1Gd{>irzEF%o|nyJB4uhF{YR*@P1evnVor$^%6<|| znF`WIVUCMc(=ZuIiR8<#kjLU}uWTnbQf7F06KORJtfO9XHgzgQe;2kI(+lL6NRM$K zObK})t}2X5(vY~u9{XN8DGugG$E0mSB^Mi(>V!GlYlD8E#--~|}G|8JkdYdiH90fD-v+HZu-d;bSJ8}W_+ literal 0 HcmV?d00001 diff --git a/include/javascript/yui/build/assets/skins/sam/imagecropper.css b/include/javascript/yui/build/assets/skins/sam/imagecropper.css new file mode 100644 index 00000000..0e8d36f6 --- /dev/null +++ b/include/javascript/yui/build/assets/skins/sam/imagecropper.css @@ -0,0 +1,7 @@ +/* +Copyright (c) 2009, Yahoo! Inc. All rights reserved. +Code licensed under the BSD License: +http://developer.yahoo.net/yui/license.txt +version: 2.8.0r4 +*/ +.yui-crop{position:relative;}.yui-crop .yui-crop-mask{position:absolute;top:0;left:0;height:100%;width:100%;}.yui-crop .yui-resize{position:absolute;top:10px;left:10px;border:0;}.yui-crop .yui-crop-resize-mask{position:absolute;top:0;left:0;height:100%;width:100%;background-position:-10px -10px;overflow:hidden;}.yui-skin-sam .yui-crop .yui-crop-mask{background-color:#000;opacity:.5;filter:alpha(opacity=50);}.yui-skin-sam .yui-crop .yui-resize{border:1px dashed #fff;} diff --git a/include/javascript/yui/build/assets/skins/sam/layout.css b/include/javascript/yui/build/assets/skins/sam/layout.css new file mode 100644 index 00000000..aa5545f1 --- /dev/null +++ b/include/javascript/yui/build/assets/skins/sam/layout.css @@ -0,0 +1,7 @@ +/* +Copyright (c) 2009, Yahoo! Inc. All rights reserved. +Code licensed under the BSD License: +http://developer.yahoo.net/yui/license.txt +version: 2.8.0r4 +*/ +.yui-layout-loading{visibility:hidden;}body.yui-layout{overflow:hidden;position:relative;padding:0;margin:0;}.yui-layout-doc{position:relative;overflow:hidden;padding:0;margin:0;}.yui-layout-unit{height:50px;width:50px;padding:0;margin:0;float:none;z-index:0;}.yui-layout-unit-top{position:absolute;top:0;left:0;width:100%;}.yui-layout-unit-left{position:absolute;top:0;left:0;}.yui-layout-unit-right{position:absolute;top:0;right:0;}.yui-layout-unit-bottom{position:absolute;bottom:0;left:0;width:100%;}.yui-layout-unit-center{position:absolute;top:0;left:0;width:100%;}.yui-layout div.yui-layout-hd{position:absolute;top:0;left:0;zoom:1;width:100%;}.yui-layout div.yui-layout-bd{position:absolute;top:0;left:0;zoom:1;width:100%;}.yui-layout .yui-layout-noscroll div.yui-layout-bd{overflow:hidden;}.yui-layout .yui-layout-scroll div.yui-layout-bd{overflow:auto;}.yui-layout div.yui-layout-ft{position:absolute;bottom:0;left:0;width:100%;zoom:1;}.yui-layout .yui-layout-unit div.yui-layout-hd h2{text-align:left;}.yui-layout .yui-layout-unit div.yui-layout-hd .collapse{cursor:pointer;height:13px;position:absolute;right:2px;top:2px;width:17px;font-size:0;}.yui-layout .yui-layout-unit div.yui-layout-hd .close{cursor:pointer;height:13px;position:absolute;right:2px;top:2px;width:17px;font-size:0;}.yui-layout .yui-layout-unit div.yui-layout-hd .collapse-close{right:25px;}.yui-layout .yui-layout-clip{position:absolute;height:20px;background-color:#c0c0c0;display:none;}.yui-layout .yui-layout-clip .collapse{cursor:pointer;height:13px;position:absolute;right:2px;top:2px;width:17px;font-size:0;}.yui-layout .yui-layout-wrap{height:100%;width:100%;position:absolute;left:0;}.yui-skin-sam .yui-layout .yui-resize-proxy{border:none;font-size:0;margin:0;padding:0;}.yui-skin-sam .yui-layout .yui-resize-resizing .yui-resize-handle{display:none;zoom:1;}.yui-skin-sam .yui-layout .yui-resize-proxy div{position:absolute;border:1px solid #808080;background-color:#EDF5FF;}.yui-skin-sam .yui-layout .yui-resize .yui-resize-handle-active{zoom:1;}.yui-skin-sam .yui-layout .yui-resize-proxy .yui-layout-handle-l{width:5px;height:100%;top:0;left:0;zoom:1;}.yui-skin-sam .yui-layout .yui-resize-proxy .yui-layout-handle-r{width:5px;top:0;right:0;height:100%;position:absolute;zoom:1;}.yui-skin-sam .yui-layout .yui-resize-proxy .yui-layout-handle-b{width:100%;bottom:0;left:0;height:5px;}.yui-skin-sam .yui-layout .yui-resize-proxy .yui-layout-handle-t{width:100%;top:0;left:0;height:5px;}.yui-skin-sam .yui-layout .yui-layout-unit-left div.yui-layout-hd .collapse{background:transparent url(layout_sprite.png) no-repeat -20px -160px;border:1px solid #808080;}.yui-skin-sam .yui-layout .yui-layout-clip-left .collapse{background:transparent url(layout_sprite.png) no-repeat -20px -140px;border:1px solid #808080;}.yui-skin-sam .yui-layout .yui-layout-unit-right div.yui-layout-hd .collapse{background:transparent url(layout_sprite.png) no-repeat -20px -200px;border:1px solid #808080;}.yui-skin-sam .yui-layout .yui-layout-clip-right .collapse{background:transparent url(layout_sprite.png) no-repeat -20px -120px;border:1px solid #808080;}.yui-skin-sam .yui-layout .yui-layout-unit-top div.yui-layout-hd .collapse{background:transparent url(layout_sprite.png) no-repeat -20px -220px;border:1px solid #808080;}.yui-skin-sam .yui-layout .yui-layout-clip-top .collapse{background:transparent url(layout_sprite.png) no-repeat -20px -240px;border:1px solid #808080;}.yui-skin-sam .yui-layout .yui-layout-unit-bottom div.yui-layout-hd .collapse{background:transparent url(layout_sprite.png) no-repeat -20px -260px;border:1px solid #808080;}.yui-skin-sam .yui-layout .yui-layout-clip-bottom .collapse{background:transparent url(layout_sprite.png) no-repeat -20px -180px;border:1px solid #808080;}.yui-skin-sam .yui-layout .yui-layout-unit div.yui-layout-hd .close{background:transparent url(layout_sprite.png) no-repeat -20px -100px;border:1px solid #808080;}.yui-skin-sam .yui-layout .yui-layout-hd{background:url(sprite.png) repeat-x 0 -1400px;border:1px solid #808080;}.yui-skin-sam .yui-layout{background-color:#EDF5FF;}.yui-skin-sam .yui-layout .yui-layout-unit div.yui-layout-hd h2{font-weight:bold;color:#fff;padding:3px;margin:0;}.yui-skin-sam .yui-layout .yui-layout-unit div.yui-layout-bd{border:1px solid #808080;border-bottom:none;border-top:none;*border-bottom-width:0;*border-top-width:0;background-color:#f2f2f2;text-align:left;}.yui-skin-sam .yui-layout .yui-layout-unit div.yui-layout-bd-noft{border-bottom:1px solid #808080;}.yui-skin-sam .yui-layout .yui-layout-unit div.yui-layout-bd-nohd{border-top:1px solid #808080;}.yui-skin-sam .yui-layout .yui-layout-clip{position:absolute;height:20px;background-color:#EDF5FF;display:none;border:1px solid #808080;}.yui-skin-sam .yui-layout div.yui-layout-ft{border:1px solid #808080;border-top:none;*border-top-width:0;background-color:#f2f2f2;}.yui-skin-sam .yui-layout-unit .yui-resize-handle{background-color:transparent;zoom:1;}.yui-skin-sam .yui-layout-unit .yui-resize-handle-r{right:0;top:0;background-image:none;zoom:1;}.yui-skin-sam .yui-layout-unit .yui-resize-handle-l{left:0;top:0;background-image:none;zoom:1;}.yui-skin-sam .yui-layout-unit .yui-resize-handle-b{right:0;bottom:0;background-image:none;}.yui-skin-sam .yui-layout-unit .yui-resize-handle-t{right:0;top:0;background-image:none;}.yui-skin-sam .yui-layout-unit .yui-resize-handle-r .yui-layout-resize-knob,.yui-skin-sam .yui-layout-unit .yui-resize-handle-l .yui-layout-resize-knob{position:absolute;height:16px;width:6px;top:45%;left:0;display:block;background:transparent url(layout_sprite.png) no-repeat 0 -5px;}.yui-skin-sam .yui-layout-unit .yui-resize-handle-t .yui-layout-resize-knob,.yui-skin-sam .yui-layout-unit .yui-resize-handle-b .yui-layout-resize-knob{position:absolute;height:6px;width:16px;left:45%;background:transparent url(layout_sprite.png) no-repeat -20px 0;zoom:1;} diff --git a/include/javascript/yui/build/assets/skins/sam/layout_sprite.png b/include/javascript/yui/build/assets/skins/sam/layout_sprite.png new file mode 100644 index 0000000000000000000000000000000000000000..d6fce3c7a5bec2e266531e2b921f6a3bc3572bcb GIT binary patch literal 1409 zcmV-{1%CR8P)Foc7fVkN9ZLH|iPzfUuN*G~E00Ia|@iPD+ScV@e5BCj%&595~Az9JYb1HE%fJ|lvg&G4W z6xqeu5wao}vOGw#oOoq zdC>F%1Q0?EEY*Rd3zq4SGax3LA2VLCrA$0(SkZGRe)Txn3^>fhp`Mk2G^wZ|DoEi^P%kHvUUm}of|3c`UUt&-f|52O4U_0*PV)UriM_~rMM%_(97pUF zgq4T@9=!koXf2}^3PBhQEBt~NN?sh$J8ydbXFQt)$8tiP<$_ov{Q4FXyL>Z8Y{z2V zkaSb@Mp@4L)cu~!F2?_5njt5??aV6VWbNsf=#lQ+PR7RWs~T&qO?1)0;8OP9mr&?_ zEd!{i70@B06_L@4$jDGFl7UgQB&=k~SS7Maj>slCBAcYPu^a+2hmVBJ&?9G-+}TBz zXWWq~l#nFk3zof330q|P#FdpMx?{=@e9y*0nRuG?)9dbIA?=7Zn<-7Ogy z%rLzw;Z+H4qs~_O26Js?Gu0GVXL}YV+@i`mTQ6efT|4_N8}^c}3;8Lx-qSp(>c5yP zv+!2uj`O5iUE1Gh?d8?|Hp~2qjUgL*#Kz|yu(3mIobhzo0%%W3w;50B)}I;aHsc}P zSeq@=3AQYoV9T-zwk(^Ikvv-Un*@E(FC%n|1lUfINU{yq26f#+*Q{GQ%4Xe0YxQpu zv2_#y8&Nz-w%~RHx=DSu0s3URv(}ru4{F`oY^bw)ANJd!RX0b`Dd=_+pdGVqaS#TA zaC#8o%*J|#2HI+&(EtA%Z`Y=G+9q~V=ogzs#Fs&WPiD*-y?Scqb$UUo8r5tsP!;V9 z+So;%!C1xB@h9l0TBW5A>O>nFRjUhLtI#SPHmr5mvtO=H#t?b%!g$d!L~pK&n|i}L z!&%^r^XATaJ(Q)5hg3QzAHz@KF_|6%p4ElhboHes%dnJo?C(gon^x1UVMu9>l+$EM zyYYBITTA&JYj=J;UeH!t2igzSu&1+}ENH*(>w~#T?}~D>R>)!8tQB$?H*0yv+zy3X zp5FpK#BWTE@nL>rYK#x`TfkSiVcaHeL%A7)bE^@*P25(v!8sWU;bx5QQEo#=#9l_Y z9jWsb&xxPHEyHgiDKT#F_ig65r+y1bS-53z`*yvmBxe`^)OW4foqs1^G=pWW+-Vx8O~1UE+HGF@F06NmG=W!zJbw P00000NkvXXu0mjf;Dg73 literal 0 HcmV?d00001 diff --git a/include/javascript/yui/build/assets/skins/sam/loading.gif b/include/javascript/yui/build/assets/skins/sam/loading.gif new file mode 100644 index 0000000000000000000000000000000000000000..0bbf3bc0c0e5e635553e8d1bf9ceddefbc402396 GIT binary patch literal 2673 zcmchY_gj;P7RTSb83YJ1>=8y5ONL=ZcEgk+C?FydumNNz8c=c6`n&|fmMu_HHG%^w zNLVjHyfy)hAgHK_Kxkz+0Ktm5M|X*?y?g!o_3yv`{_^F^wY9YuFJ3GxEUd1s-nnz<)vH(c?%i8n zUVirM+2rIT007UQKY#e};oRKZty{MqJa}MhYina;bNBAu-+udTYHDhBcJ|n@WA*j* z-+lL;iHS*OX6D|#dm|zu!o$ON?b=mbT)bh!26uP&kdP1u2Zx!N8486$B9X?&$DclZ zdgI28>FMdk#l`#g@Bj4EPc=0)2M!!4EG!%z9?s6rzI5r**|TSdhK8)HtXf)HHgDc+ zZEek9Fk)k4xm@nHZQC3j9o^jACMG6~jg9m3^EYnX2*Yq^XJ>6~?X_#y4jnqQbLUQp zM6z$+zMp^o*}}p?p-?n8H=jOzx~Zv&N~Km+RkgLX9X@>c=FOXxm6dsUd1NvZ zX=yul?BMZua=F~p)O7py?EwJ+w{PD*dGh2hzx?v((WCP6au$mb!vmnqSpF6-9Ona(JQT#e>!KODwxYzG5#S|?M#v6eD#mgO^`=~9EL;yL&>*dd5*+XG=_`^3=CG25PbLa+LJ%N(PW_s z=_-TaM{SB!w(n7k+dMDN2G6VPqUA$u7F4m@ABAZ1D`*UMfe}E6csJU}J1Trmp#~7hZ5QSGpNvd1Uz$!Rf3q28pgSj9o zx?zwoWa8GYK@TOz^)mp#V2_VR5WfJ0W9BSSbn+cKb z7B9l9)K#s!?PSt;g%c8u;y7rd?hkP%>vq5BY=N>c=98V=+T&RSPgSu|E(FAK>B?vNN1 zPszwcbxJ?Oh|1pGd!9?gxzSWOR8o=x5!rGh+6r3hBL-14aTaAQxvJ|Y-S_m4niV2S zK@?}-9Dkhg<+w{Ny!vjyp-QmjyGmIW1DFB{k>P2=8cm~9M^_P#8?JFDumGEPaqJvf zZ{f;B#CG;H7q8a_hQ$pR6%%6So8vKM+W+cNPE_TI46^dn9q@qBr@1bUgxcPGB*b-i z3Hx_0(Esy5KKx^Y0yfgB6~}t>@!ctk>J|!vgVRhE2CPQ;AOKY2y%5nM@YF^ZMS~q}%L-n>Lpor#4w48UHYViOt={{43LMRvkIp+rkbs*s; z14}4q0y6`s8DL?uo-~*R@5tnFsC1DR#BGxT8fA20u_o?`0iDNI6lf;^$@AkR1dPTz z>XF1ZAqNjU95c@Vn59Wo;Z6b(YG+L$xy3(?j2I*vQ>PmzMEdh`yw3=)E}JYMDG|*x mDkGVJ;D)fXhxDI?kcM(ish)C#5QQ<|d}62BjvZR2H60wE-$(3-AeXt*@{D|Np;u@pDC#5QQ<|d}62BjvZR2H60wE-$(3-AeX1=9cj|6h7@{#_u8sU*lR z_&>wb?FL>zp1h}vV@SoVq=W_rH;IG.bd>ul:after{content:".";display:block;clear:both;visibility:hidden;height:0;line-height:0;}.yuimenubaritem{float:left;}.yuimenubaritemlabel,.yuimenuitemlabel{display:block;}.yuimenuitemlabel .helptext{font-style:normal;display:block;margin:-1em 0 0 10em;}.yui-menu-shadow{position:absolute;visibility:hidden;z-index:-1;}.yui-menu-shadow-visible{top:2px;right:-3px;left:-3px;bottom:-3px;visibility:visible;}.hide-scrollbars *{overflow:hidden;}.hide-scrollbars select{display:none;}.yuimenu.show-scrollbars,.yuimenubar.show-scrollbars{overflow:visible;}.yuimenu.hide-scrollbars .yui-menu-shadow,.yuimenubar.hide-scrollbars .yui-menu-shadow{overflow:hidden;}.yuimenu.show-scrollbars .yui-menu-shadow,.yuimenubar.show-scrollbars .yui-menu-shadow{overflow:auto;}.yui-overlay.yui-force-redraw{margin-bottom:1px;}.yui-skin-sam .yuimenubar{font-size:93%;line-height:2;*line-height:1.9;border:solid 1px #808080;background:url(sprite.png) repeat-x 0 0;}.yui-skin-sam .yuimenubarnav .yuimenubaritem{border-right:solid 1px #ccc;}.yui-skin-sam .yuimenubaritemlabel{padding:0 10px;color:#000;text-decoration:none;cursor:default;border-style:solid;border-color:#808080;border-width:1px 0;*position:relative;margin:-1px 0;}.yui-skin-sam .yuimenubaritemlabel:visited{color:#000;}.yui-skin-sam .yuimenubarnav .yuimenubaritemlabel{padding-right:20px;*display:inline-block;}.yui-skin-sam .yuimenubarnav .yuimenubaritemlabel-hassubmenu{background:url(menubaritem_submenuindicator.png) right center no-repeat;}.yui-skin-sam .yuimenubaritem-selected{background:url(sprite.png) repeat-x 0 -1700px;}.yui-skin-sam .yuimenubaritemlabel-selected{border-color:#7D98B8;}.yui-skin-sam .yuimenubarnav .yuimenubaritemlabel-selected{border-left-width:1px;margin-left:-1px;*left:-1px;}.yui-skin-sam .yuimenubaritemlabel-disabled,.yui-skin-sam .yuimenubaritemlabel-disabled:visited{cursor:default;color:#A6A6A6;}.yui-skin-sam .yuimenubarnav .yuimenubaritemlabel-hassubmenu-disabled{background-image:url(menubaritem_submenuindicator_disabled.png);}.yui-skin-sam .yuimenu{font-size:93%;line-height:1.5;*line-height:1.45;}.yui-skin-sam .yuimenubar .yuimenu,.yui-skin-sam .yuimenu .yuimenu{font-size:100%;}.yui-skin-sam .yuimenu .bd{*zoom:1;_zoom:normal;border:solid 1px #808080;background-color:#fff;}.yui-skin-sam .yuimenu .yuimenu .bd{*zoom:normal;}.yui-skin-sam .yuimenu ul{padding:3px 0;border-width:1px 0 0 0;border-color:#ccc;border-style:solid;}.yui-skin-sam .yuimenu ul.first-of-type{border-width:0;}.yui-skin-sam .yuimenu h6{font-weight:bold;border-style:solid;border-color:#ccc;border-width:1px 0 0 0;color:#a4a4a4;padding:3px 10px 0 10px;}.yui-skin-sam .yuimenu ul.hastitle,.yui-skin-sam .yuimenu h6.first-of-type{border-width:0;}.yui-skin-sam .yuimenu .yui-menu-body-scrolled{border-color:#ccc #808080;overflow:hidden;}.yui-skin-sam .yuimenu .topscrollbar,.yui-skin-sam .yuimenu .bottomscrollbar{height:16px;border:solid 1px #808080;background:#fff url(sprite.png) no-repeat 0 0;}.yui-skin-sam .yuimenu .topscrollbar{border-bottom-width:0;background-position:center -950px;}.yui-skin-sam .yuimenu .topscrollbar_disabled{background-position:center -975px;}.yui-skin-sam .yuimenu .bottomscrollbar{border-top-width:0;background-position:center -850px;}.yui-skin-sam .yuimenu .bottomscrollbar_disabled{background-position:center -875px;}.yui-skin-sam .yuimenuitem{_border-bottom:solid 1px #fff;}.yui-skin-sam .yuimenuitemlabel{padding:0 20px;color:#000;text-decoration:none;cursor:default;}.yui-skin-sam .yuimenuitemlabel:visited{color:#000;}.yui-skin-sam .yuimenuitemlabel .helptext{margin-top:-1.5em;*margin-top:-1.45em;}.yui-skin-sam .yuimenuitem-hassubmenu{background-image:url(menuitem_submenuindicator.png);background-position:right center;background-repeat:no-repeat;}.yui-skin-sam .yuimenuitem-checked{background-image:url(menuitem_checkbox.png);background-position:left center;background-repeat:no-repeat;}.yui-skin-sam .yui-menu-shadow-visible{background-color:#000;opacity:.12;filter:alpha(opacity=12);}.yui-skin-sam .yuimenuitem-selected{background-color:#B3D4FF;}.yui-skin-sam .yuimenuitemlabel-disabled,.yui-skin-sam .yuimenuitemlabel-disabled:visited{cursor:default;color:#A6A6A6;}.yui-skin-sam .yuimenuitem-hassubmenu-disabled{background-image:url(menuitem_submenuindicator_disabled.png);}.yui-skin-sam .yuimenuitem-checked-disabled{background-image:url(menuitem_checkbox_disabled.png);} diff --git a/include/javascript/yui/build/assets/skins/sam/menubaritem_submenuindicator.png b/include/javascript/yui/build/assets/skins/sam/menubaritem_submenuindicator.png new file mode 100644 index 0000000000000000000000000000000000000000..030941c9cffc064276813d7eaab03d8c667ed700 GIT binary patch literal 3618 zcmV+-4&CvIP)KLZ*U+IBfRsybQWXdwQbLP>6pAqfylh#{fb6;Z(vMMVS~$e@S=j*ftg6;Uhf59&ghTmgWD0l;*T zI709Y^p6lP1rIRMx#05C~cW=H_Aw*bJ-5DT&Z2n+x)QHX^p z00esgV8|mQcmRZ%02D^@S3L16t`O%c004NIvOKvYIYoh62rY33S640`D9%Y2D-rV&neh&#Q1i z007~1e$oCcFS8neI|hJl{-P!B1ZZ9hpmq0)X0i`JwE&>$+E?>%_LC6RbVIkUx0b+_+BaR3cnT7Zv!AJxW zizFb)h!jyGOOZ85F;a?DAXP{m@;!0_IfqH8(HlgRxt7s3}k3K`kFu>>-2Q$QMFfPW!La{h336o>X zu_CMttHv6zR;&ZNiS=X8v3CR#fknUxHUxJ0uoBa_M6WNWeqIg~6QE69c9o#eyhGvpiOA@W-aonk<7r1(?fC{oI5N*U!4 zfg=2N-7=cNnjjOr{yriy6mMFgG#l znCF=fnQv8CDz++o6_Lscl}eQ+l^ZHARH>?_s@|##Rr6KLRFA1%Q+=*RRWnoLsR`7U zt5vFIcfW3@?wFpwUVxrVZ>QdQz32KIeJ}k~{cZZE^+ya? z2D1z#2HOnI7(B%_ac?{wFUQ;QQA1tBKtrWrm0_3Rgps+?Jfqb{jYbcQX~taRB;#$y zZN{S}1|}gUOHJxc?wV3fxuz+mJ4`!F$IZ;mqRrNsHJd##*D~ju=bP7?-?v~|cv>vB zsJ6IeNwVZxrdjT`yl#bBIa#GxRa#xMMy;K#CDyyGyQdMSxlWT#tDe?p!?5wT$+oGt z8L;Kp2HUQ-ZMJ=3XJQv;x5ci*?vuTfeY$;({XGW_huIFR9a(?@3)XSs8O^N5RyOM=TTmp(3=8^+zpz2r)C z^>JO{deZfso3oq3?Wo(Y?l$ge?uXo;%ru`Vo>?<<(8I_>;8Eq#KMS9gFl*neeosSB zfoHYnBQIkwkyowPu(zdms`p{<7e4kra-ZWq<2*OsGTvEV%s0Td$hXT+!*8Bnh2KMe zBmZRodjHV?r+_5^X9J0WL4jKW`}lf%A-|44I@@LTvf1rHjG(ze6+w@Jt%Bvjts!X0 z?2xS?_ve_-kiKB_KiJlZ$9G`c^=E@oNG)mWWaNo-3TIW8)$Hg0Ub-~8?KhvJ>$ z3*&nim@mj(aCxE5!t{lw7O5^0EIO7zOo&c6l<+|iDySBWCGrz@C5{St!X3hAA}`T4 z(TLbXTq+(;@<=L8dXnssyft|w#WSTW<++3>sgS%(4NTpeI-VAqb|7ssJvzNHgOZVu zaYCvgO_R1~>SyL=cFU|~g|hy|Zi}}s9+d~lYqOB71z9Z$wnC=pR9Yz4DhIM>Wmjgu z&56o6maCpC&F##y%G;1PobR9i?GnNg;gYtchD%p19a!eQtZF&3JaKv33gZ<8D~47E ztUS1iwkmDaPpj=$m#%)jCVEY4fnLGNg2A-`YwHVD3gv};>)hAvT~AmqS>Lr``i7kw zJ{5_It`yrBmlc25DBO7E8;5VoznR>Ww5hAaxn$2~(q`%A-YuS64wkBy=9dm`4cXeX z4c}I@?e+FW+b@^RDBHV(wnMq2zdX3SWv9u`%{xC-q*U}&`cyXV(%rRT*Z6MH?i+i& z_B8C(+grT%{XWUQ+f@NoP1R=AW&26{v-dx)iK^-Nmiuj8txj!m?Z*Ss1N{dh4z}01 z)YTo*JycSU)+_5r4#yw9{+;i4Ee$peRgIj+;v;ZGdF1K$3E%e~4LaI(jC-u%2h$&R z9cLXcYC@Xwnns&bn)_Q~Te?roKGD|d-g^8;+aC{{G(1^(O7m37Y1-+6)01cN&y1aw zoqc{T`P^XJqPBbIW6s}d4{z_f5Om?vMgNQEJG?v2T=KYd^0M3I6IZxbny)%vZR&LD zJpPl@Psh8QyPB@KTx+@RdcC!KX7}kEo;S|j^u2lU7XQ}Oo;f|;z4Ll+_r>@1-xl3| zawq-H%e&ckC+@AhPrP6BKT#_XdT7&;F71j}Joy zkC~6lh7E@6o;W@^IpRNZ{ptLtL(gQ-CY~4mqW;US7Zxvm_|@yz&e53Bp_lTPlfP|z zrTyx_>lv@x#=^!PzR7qqF<$gm`|ZJZ+;<)Cqu&ot2z=00004XF*Lt006O$eEU(80000WV@Og>004R=004l4008;_004mL004C` z008P>0026e000+nl3&F}00093P)t-s00030|NjC40s{jB1Ox;H1qB8M1_uWR2nYxX z2?+`c3JVJh3=9kn4Gj(s4i66x5D*X%5fKs+5)%^>6ciK{6%`g178e&67#J8C85tTH z8XFrM92^`S9UUGX9v>ecARr(iAt53nA|oRsBqSsyB_$>%CMPE+C@3f?DJd!{Dl021 zEG#T7EiEoCE-x=HFfcGNF)=bSGBYzXG&D3dH8nOiHa9mnI5;>tIXOByIy*Z%JUl!- zJv}}?K0iM{KtMo2K|w-7LPJACL_|bIMMXwNMn^|SNJvOYNl8jdN=r*iOiWBoO-)Wt zPESuyP*6}&QBhJ-Qd3h?R8&+|RaI72R##V7SXfwDSy@_IT3cINTwGjTU0q&YUSD5d zU|?WjVPRroVq;@tWMpJzWo2e&W@l$-XlQ6@X=!R|YHMq2Y;0_8ZEbFDZf|dIaBy&O zadC2Ta&vQYbaZreb#-=jc6WDoczAeud3kzzdV70&e0+R;eSLm@et&;|fPjF3fq{a8 zf`fyDgoK2Jg@uNOhKGlTh=_=ZiHVAeii?YjjEszpjg5|uj*pLzkdTm(k&%*;l9Q8@ zl$4Z}m6ev3mY0{8n3$NEnVFiJnwy)OoSdAUot>VZo}ZteprD|kp`oIpqNAguq@<*! zrKP5(rl+T;sHmu^si~@}s;jH3tgNi9t*x%EuCK4Ju&}VPv9YqUva_?Zw6wIfwY9dk zwzs#pxVX5vxw*Q!y1To(yu7@dCU z$jHda$;ryf%FD~k%*@Qq&CSlv&d<-!(9qD)(b3Y<($mw^)YR0~)z#M4*4Nk9*x1lt)=I7_<=;-L_>FMg~ z>g((4?Ck9A?d|UF?(gsK@bK{Q@$vHV^7Hfa^z`)g_4W4l_V@Sq`1ttw`T6?#`uqF) z{QUg={r&#_{{R2~`6RjA00002bW%=J{{ZE;FiHRb03%66K~#9!Vqky(Mi^jVMCCIw oFfyX>85y7$4gdfE0RR6300puDFk literal 0 HcmV?d00001 diff --git a/include/javascript/yui/build/assets/skins/sam/menubaritem_submenuindicator_disabled.png b/include/javascript/yui/build/assets/skins/sam/menubaritem_submenuindicator_disabled.png new file mode 100644 index 0000000000000000000000000000000000000000..6c1612230550ef09678a38a2e3374585055a07eb GIT binary patch literal 3618 zcmV+-4&CvIP)KLZ*U+IBfRsybQWXdwQbLP>6pAqfylh#{fb6;Z(vMMVS~$e@S=j*ftg6;Uhf59&ghTmgWD0l;*T zI709Y^p6lP1rIRMx#05C~cW=H_Aw*bJ-5DT&Z2n+x)QHX^p z00esgV8|mQcmRZ%02D^@S3L16t`O%c004NIvOKvYIYoh62rY33S640`D9%Y2D-rV&neh&#Q1i z007~1e$oCcFS8neI|hJl{-P!B1ZZ9hpmq0)X0i`JwE&>$+E?>%_LC6RbVIkUx0b+_+BaR3cnT7Zv!AJxW zizFb)h!jyGOOZ85F;a?DAXP{m@;!0_IfqH8(HlgRxt7s3}k3K`kFu>>-2Q$QMFfPW!La{h336o>X zu_CMttHv6zR;&ZNiS=X8v3CR#fknUxHUxJ0uoBa_M6WNWeqIg~6QE69c9o#eyhGvpiOA@W-aonk<7r1(?fC{oI5N*U!4 zfg=2N-7=cNnjjOr{yriy6mMFgG#l znCF=fnQv8CDz++o6_Lscl}eQ+l^ZHARH>?_s@|##Rr6KLRFA1%Q+=*RRWnoLsR`7U zt5vFIcfW3@?wFpwUVxrVZ>QdQz32KIeJ}k~{cZZE^+ya? z2D1z#2HOnI7(B%_ac?{wFUQ;QQA1tBKtrWrm0_3Rgps+?Jfqb{jYbcQX~taRB;#$y zZN{S}1|}gUOHJxc?wV3fxuz+mJ4`!F$IZ;mqRrNsHJd##*D~ju=bP7?-?v~|cv>vB zsJ6IeNwVZxrdjT`yl#bBIa#GxRa#xMMy;K#CDyyGyQdMSxlWT#tDe?p!?5wT$+oGt z8L;Kp2HUQ-ZMJ=3XJQv;x5ci*?vuTfeY$;({XGW_huIFR9a(?@3)XSs8O^N5RyOM=TTmp(3=8^+zpz2r)C z^>JO{deZfso3oq3?Wo(Y?l$ge?uXo;%ru`Vo>?<<(8I_>;8Eq#KMS9gFl*neeosSB zfoHYnBQIkwkyowPu(zdms`p{<7e4kra-ZWq<2*OsGTvEV%s0Td$hXT+!*8Bnh2KMe zBmZRodjHV?r+_5^X9J0WL4jKW`}lf%A-|44I@@LTvf1rHjG(ze6+w@Jt%Bvjts!X0 z?2xS?_ve_-kiKB_KiJlZ$9G`c^=E@oNG)mWWaNo-3TIW8)$Hg0Ub-~8?KhvJ>$ z3*&nim@mj(aCxE5!t{lw7O5^0EIO7zOo&c6l<+|iDySBWCGrz@C5{St!X3hAA}`T4 z(TLbXTq+(;@<=L8dXnssyft|w#WSTW<++3>sgS%(4NTpeI-VAqb|7ssJvzNHgOZVu zaYCvgO_R1~>SyL=cFU|~g|hy|Zi}}s9+d~lYqOB71z9Z$wnC=pR9Yz4DhIM>Wmjgu z&56o6maCpC&F##y%G;1PobR9i?GnNg;gYtchD%p19a!eQtZF&3JaKv33gZ<8D~47E ztUS1iwkmDaPpj=$m#%)jCVEY4fnLGNg2A-`YwHVD3gv};>)hAvT~AmqS>Lr``i7kw zJ{5_It`yrBmlc25DBO7E8;5VoznR>Ww5hAaxn$2~(q`%A-YuS64wkBy=9dm`4cXeX z4c}I@?e+FW+b@^RDBHV(wnMq2zdX3SWv9u`%{xC-q*U}&`cyXV(%rRT*Z6MH?i+i& z_B8C(+grT%{XWUQ+f@NoP1R=AW&26{v-dx)iK^-Nmiuj8txj!m?Z*Ss1N{dh4z}01 z)YTo*JycSU)+_5r4#yw9{+;i4Ee$peRgIj+;v;ZGdF1K$3E%e~4LaI(jC-u%2h$&R z9cLXcYC@Xwnns&bn)_Q~Te?roKGD|d-g^8;+aC{{G(1^(O7m37Y1-+6)01cN&y1aw zoqc{T`P^XJqPBbIW6s}d4{z_f5Om?vMgNQEJG?v2T=KYd^0M3I6IZxbny)%vZR&LD zJpPl@Psh8QyPB@KTx+@RdcC!KX7}kEo;S|j^u2lU7XQ}Oo;f|;z4Ll+_r>@1-xl3| zawq-H%e&ckC+@AhPrP6BKT#_XdT7&;F71j}Joy zkC~6lh7E@6o;W@^IpRNZ{ptLtL(gQ-CY~4mqW;US7Zxvm_|@yz&e53Bp_lTPlfP|z zrTyx_>lv@x#=^!PzR7qqF<$gm`|ZJZ+;<)Cqu&ot2z=00004XF*Lt006O$eEU(80000WV@Og>004R=004l4008;_004mL004C` z008P>0026e000+nl3&F}00093P)t-se}8}f|NjC40s{jB1Ox;H1qB8M1_uWR2nYxX z2?+`c3JVJh3=9kn4Gj(s4i66x5D*X%5fKs+5)%^>6ciK{6%`g178e&67#J8C85tTH z8XFrM92^`S9UUGX9v>ecARr(iAt53nA|oRsBqSsyB_$>%CMPE+C@3f?DJd!{Dl021 zEG#T7EiEoCE-x=HFfcGNF)=bSGBYzXG&D3dH8nOiHa9mnI5;>tIXOByIy*Z%JUl!- zJv}}?K0iM{KtMo2K|w-7LPJACL_|bIMMXwNMn^|SNJvOYNl8jdN=r*iOiWBoO-)Wt zPESuyP*6}&QBhJ-Qd3h?R8&+|RaI72R##V7SXfwDSy@_IT3cINTwGjTU0q&YUSD5d zU|?WjVPRroVq;@tWMpJzWo2e&W@l$-XlQ6@X=!R|YHMq2Y;0_8ZEbFDZf|dIaBy&O zadC2Ta&vQYbaZreb#-=jc6WDoczAeud3kzzdV70&e0+R;eSLm@et&;|fPjF3fq{a8 zf`fyDgoK2Jg@uNOhKGlTh=_=ZiHVAeii?YjjEszpjg5|uj*pLzkdTm(k&%*;l9Q8@ zl$4Z}m6ev3mY0{8n3$NEnVFiJnwy)OoSdAUot>VZo}ZteprD|kp`oIpqNAguq@<*! zrKP5(rl+T;sHmu^si~@}s;jH3tgNi9t*x%EuCK4Ju&}VPv9YqUva_?Zw6wIfwY9dk zwzs#pxVX5vxw*Q!y1To(yu7@dCU z$jHda$;ryf%FD~k%*@Qq&CSlv&d<-!(9qD)(b3Y<($mw^)YR0~)z#M4*4Nk9*x1lt)=I7_<=;-L_>FMg~ z>g((4?Ck9A?d|UF?(gsK@bK{Q@$vHV^7Hfa^z`)g_4W4l_V@Sq`1ttw`T6?#`uqF) z{QUg={r&#_{{R2~9(fUf00002bW%=J{{ZE;FiHRb03%66K~#9!Vqky(Mi^jVMCCIw oFfyX>85y7$4gdfE0RR6300puDFKLZ*U+IBfRsybQWXdwQbLP>6pAqfylh#{fb6;Z(vMMVS~$e@S=j*ftg6;Uhf59&ghTmgWD0l;*T zI709Y^p6lP1rIRMx#05C~cW=H_Aw*bJ-5DT&Z2n+x)QHX^p z00esgV8|mQcmRZ%02D^@S3L16t`O%c004NIvOKvYIYoh62rY33S640`D9%Y2D-rV&neh&#Q1i z007~1e$oCcFS8neI|hJl{-P!B1ZZ9hpmq0)X0i`JwE&>$+E?>%_LC6RbVIkUx0b+_+BaR3cnT7Zv!AJxW zizFb)h!jyGOOZ85F;a?DAXP{m@;!0_IfqH8(HlgRxt7s3}k3K`kFu>>-2Q$QMFfPW!La{h336o>X zu_CMttHv6zR;&ZNiS=X8v3CR#fknUxHUxJ0uoBa_M6WNWeqIg~6QE69c9o#eyhGvpiOA@W-aonk<7r1(?fC{oI5N*U!4 zfg=2N-7=cNnjjOr{yriy6mMFgG#l znCF=fnQv8CDz++o6_Lscl}eQ+l^ZHARH>?_s@|##Rr6KLRFA1%Q+=*RRWnoLsR`7U zt5vFIcfW3@?wFpwUVxrVZ>QdQz32KIeJ}k~{cZZE^+ya? z2D1z#2HOnI7(B%_ac?{wFUQ;QQA1tBKtrWrm0_3Rgps+?Jfqb{jYbcQX~taRB;#$y zZN{S}1|}gUOHJxc?wV3fxuz+mJ4`!F$IZ;mqRrNsHJd##*D~ju=bP7?-?v~|cv>vB zsJ6IeNwVZxrdjT`yl#bBIa#GxRa#xMMy;K#CDyyGyQdMSxlWT#tDe?p!?5wT$+oGt z8L;Kp2HUQ-ZMJ=3XJQv;x5ci*?vuTfeY$;({XGW_huIFR9a(?@3)XSs8O^N5RyOM=TTmp(3=8^+zpz2r)C z^>JO{deZfso3oq3?Wo(Y?l$ge?uXo;%ru`Vo>?<<(8I_>;8Eq#KMS9gFl*neeosSB zfoHYnBQIkwkyowPu(zdms`p{<7e4kra-ZWq<2*OsGTvEV%s0Td$hXT+!*8Bnh2KMe zBmZRodjHV?r+_5^X9J0WL4jKW`}lf%A-|44I@@LTvf1rHjG(ze6+w@Jt%Bvjts!X0 z?2xS?_ve_-kiKB_KiJlZ$9G`c^=E@oNG)mWWaNo-3TIW8)$Hg0Ub-~8?KhvJ>$ z3*&nim@mj(aCxE5!t{lw7O5^0EIO7zOo&c6l<+|iDySBWCGrz@C5{St!X3hAA}`T4 z(TLbXTq+(;@<=L8dXnssyft|w#WSTW<++3>sgS%(4NTpeI-VAqb|7ssJvzNHgOZVu zaYCvgO_R1~>SyL=cFU|~g|hy|Zi}}s9+d~lYqOB71z9Z$wnC=pR9Yz4DhIM>Wmjgu z&56o6maCpC&F##y%G;1PobR9i?GnNg;gYtchD%p19a!eQtZF&3JaKv33gZ<8D~47E ztUS1iwkmDaPpj=$m#%)jCVEY4fnLGNg2A-`YwHVD3gv};>)hAvT~AmqS>Lr``i7kw zJ{5_It`yrBmlc25DBO7E8;5VoznR>Ww5hAaxn$2~(q`%A-YuS64wkBy=9dm`4cXeX z4c}I@?e+FW+b@^RDBHV(wnMq2zdX3SWv9u`%{xC-q*U}&`cyXV(%rRT*Z6MH?i+i& z_B8C(+grT%{XWUQ+f@NoP1R=AW&26{v-dx)iK^-Nmiuj8txj!m?Z*Ss1N{dh4z}01 z)YTo*JycSU)+_5r4#yw9{+;i4Ee$peRgIj+;v;ZGdF1K$3E%e~4LaI(jC-u%2h$&R z9cLXcYC@Xwnns&bn)_Q~Te?roKGD|d-g^8;+aC{{G(1^(O7m37Y1-+6)01cN&y1aw zoqc{T`P^XJqPBbIW6s}d4{z_f5Om?vMgNQEJG?v2T=KYd^0M3I6IZxbny)%vZR&LD zJpPl@Psh8QyPB@KTx+@RdcC!KX7}kEo;S|j^u2lU7XQ}Oo;f|;z4Ll+_r>@1-xl3| zawq-H%e&ckC+@AhPrP6BKT#_XdT7&;F71j}Joy zkC~6lh7E@6o;W@^IpRNZ{ptLtL(gQ-CY~4mqW;US7Zxvm_|@yz&e53Bp_lTPlfP|z zrTyx_>lv@x#=^!PzR7qqF<$gm`|ZJZ+;<)Cqu&ot2z=00004XF*Lt006O$eEU(80000WV@Og>004R=004l4008;_004mL004C` z008P>0026e000+nl3&F}00093P)t-s00030|NjC40s{jB1Ox;H1qB8M1_uWR2nYxX z2?+`c3JVJh3=9kn4Gj(s4i66x5D*X%5fKs+5)%^>6ciK{6%`g178e&67#J8C85tTH z8XFrM92^`S9UUGX9v>ecARr(iAt53nA|oRsBqSsyB_$>%CMPE+C@3f?DJd!{Dl021 zEG#T7EiEoCE-x=HFfcGNF)=bSGBYzXG&D3dH8nOiHa9mnI5;>tIXOByIy*Z%JUl!- zJv}}?K0iM{KtMo2K|w-7LPJACL_|bIMMXwNMn^|SNJvOYNl8jdN=r*iOiWBoO-)Wt zPESuyP*6}&QBhJ-Qd3h?R8&+|RaI72R##V7SXfwDSy@_IT3cINTwGjTU0q&YUSD5d zU|?WjVPRroVq;@tWMpJzWo2e&W@l$-XlQ6@X=!R|YHMq2Y;0_8ZEbFDZf|dIaBy&O zadC2Ta&vQYbaZreb#-=jc6WDoczAeud3kzzdV70&e0+R;eSLm@et&;|fPjF3fq{a8 zf`fyDgoK2Jg@uNOhKGlTh=_=ZiHVAeii?YjjEszpjg5|uj*pLzkdTm(k&%*;l9Q8@ zl$4Z}m6ev3mY0{8n3$NEnVFiJnwy)OoSdAUot>VZo}ZteprD|kp`oIpqNAguq@<*! zrKP5(rl+T;sHmu^si~@}s;jH3tgNi9t*x%EuCK4Ju&}VPv9YqUva_?Zw6wIfwY9dk zwzs#pxVX5vxw*Q!y1To(yu7@dCU z$jHda$;ryf%FD~k%*@Qq&CSlv&d<-!(9qD)(b3Y<($mw^)YR0~)z#M4*4Nk9*x1lt)=I7_<=;-L_>FMg~ z>g((4?Ck9A?d|UF?(gsK@bK{Q@$vHV^7Hfa^z`)g_4W4l_V@Sq`1ttw`T6?#`uqF) z{QUg={r&#_{{R2~`6RjA00002bW%=J{{ZE;FiHRb04hmDK~#9!T+A^Jz#tFKLZ*U+IBfRsybQWXdwQbLP>6pAqfylh#{fb6;Z(vMMVS~$e@S=j*ftg6;Uhf59&ghTmgWD0l;*T zI709Y^p6lP1rIRMx#05C~cW=H_Aw*bJ-5DT&Z2n+x)QHX^p z00esgV8|mQcmRZ%02D^@S3L16t`O%c004NIvOKvYIYoh62rY33S640`D9%Y2D-rV&neh&#Q1i z007~1e$oCcFS8neI|hJl{-P!B1ZZ9hpmq0)X0i`JwE&>$+E?>%_LC6RbVIkUx0b+_+BaR3cnT7Zv!AJxW zizFb)h!jyGOOZ85F;a?DAXP{m@;!0_IfqH8(HlgRxt7s3}k3K`kFu>>-2Q$QMFfPW!La{h336o>X zu_CMttHv6zR;&ZNiS=X8v3CR#fknUxHUxJ0uoBa_M6WNWeqIg~6QE69c9o#eyhGvpiOA@W-aonk<7r1(?fC{oI5N*U!4 zfg=2N-7=cNnjjOr{yriy6mMFgG#l znCF=fnQv8CDz++o6_Lscl}eQ+l^ZHARH>?_s@|##Rr6KLRFA1%Q+=*RRWnoLsR`7U zt5vFIcfW3@?wFpwUVxrVZ>QdQz32KIeJ}k~{cZZE^+ya? z2D1z#2HOnI7(B%_ac?{wFUQ;QQA1tBKtrWrm0_3Rgps+?Jfqb{jYbcQX~taRB;#$y zZN{S}1|}gUOHJxc?wV3fxuz+mJ4`!F$IZ;mqRrNsHJd##*D~ju=bP7?-?v~|cv>vB zsJ6IeNwVZxrdjT`yl#bBIa#GxRa#xMMy;K#CDyyGyQdMSxlWT#tDe?p!?5wT$+oGt z8L;Kp2HUQ-ZMJ=3XJQv;x5ci*?vuTfeY$;({XGW_huIFR9a(?@3)XSs8O^N5RyOM=TTmp(3=8^+zpz2r)C z^>JO{deZfso3oq3?Wo(Y?l$ge?uXo;%ru`Vo>?<<(8I_>;8Eq#KMS9gFl*neeosSB zfoHYnBQIkwkyowPu(zdms`p{<7e4kra-ZWq<2*OsGTvEV%s0Td$hXT+!*8Bnh2KMe zBmZRodjHV?r+_5^X9J0WL4jKW`}lf%A-|44I@@LTvf1rHjG(ze6+w@Jt%Bvjts!X0 z?2xS?_ve_-kiKB_KiJlZ$9G`c^=E@oNG)mWWaNo-3TIW8)$Hg0Ub-~8?KhvJ>$ z3*&nim@mj(aCxE5!t{lw7O5^0EIO7zOo&c6l<+|iDySBWCGrz@C5{St!X3hAA}`T4 z(TLbXTq+(;@<=L8dXnssyft|w#WSTW<++3>sgS%(4NTpeI-VAqb|7ssJvzNHgOZVu zaYCvgO_R1~>SyL=cFU|~g|hy|Zi}}s9+d~lYqOB71z9Z$wnC=pR9Yz4DhIM>Wmjgu z&56o6maCpC&F##y%G;1PobR9i?GnNg;gYtchD%p19a!eQtZF&3JaKv33gZ<8D~47E ztUS1iwkmDaPpj=$m#%)jCVEY4fnLGNg2A-`YwHVD3gv};>)hAvT~AmqS>Lr``i7kw zJ{5_It`yrBmlc25DBO7E8;5VoznR>Ww5hAaxn$2~(q`%A-YuS64wkBy=9dm`4cXeX z4c}I@?e+FW+b@^RDBHV(wnMq2zdX3SWv9u`%{xC-q*U}&`cyXV(%rRT*Z6MH?i+i& z_B8C(+grT%{XWUQ+f@NoP1R=AW&26{v-dx)iK^-Nmiuj8txj!m?Z*Ss1N{dh4z}01 z)YTo*JycSU)+_5r4#yw9{+;i4Ee$peRgIj+;v;ZGdF1K$3E%e~4LaI(jC-u%2h$&R z9cLXcYC@Xwnns&bn)_Q~Te?roKGD|d-g^8;+aC{{G(1^(O7m37Y1-+6)01cN&y1aw zoqc{T`P^XJqPBbIW6s}d4{z_f5Om?vMgNQEJG?v2T=KYd^0M3I6IZxbny)%vZR&LD zJpPl@Psh8QyPB@KTx+@RdcC!KX7}kEo;S|j^u2lU7XQ}Oo;f|;z4Ll+_r>@1-xl3| zawq-H%e&ckC+@AhPrP6BKT#_XdT7&;F71j}Joy zkC~6lh7E@6o;W@^IpRNZ{ptLtL(gQ-CY~4mqW;US7Zxvm_|@yz&e53Bp_lTPlfP|z zrTyx_>lv@x#=^!PzR7qqF<$gm`|ZJZ+;<)Cqu&ot2z=00004XF*Lt006O$eEU(80000WV@Og>004R=004l4008;_004mL004C` z008P>0026e000+nl3&F}00093P)t-se}8}f|NjC40s{jB1Ox;H1qB8M1_uWR2nYxX z2?+`c3JVJh3=9kn4Gj(s4i66x5D*X%5fKs+5)%^>6ciK{6%`g178e&67#J8C85tTH z8XFrM92^`S9UUGX9v>ecARr(iAt53nA|oRsBqSsyB_$>%CMPE+C@3f?DJd!{Dl021 zEG#T7EiEoCE-x=HFfcGNF)=bSGBYzXG&D3dH8nOiHa9mnI5;>tIXOByIy*Z%JUl!- zJv}}?K0iM{KtMo2K|w-7LPJACL_|bIMMXwNMn^|SNJvOYNl8jdN=r*iOiWBoO-)Wt zPESuyP*6}&QBhJ-Qd3h?R8&+|RaI72R##V7SXfwDSy@_IT3cINTwGjTU0q&YUSD5d zU|?WjVPRroVq;@tWMpJzWo2e&W@l$-XlQ6@X=!R|YHMq2Y;0_8ZEbFDZf|dIaBy&O zadC2Ta&vQYbaZreb#-=jc6WDoczAeud3kzzdV70&e0+R;eSLm@et&;|fPjF3fq{a8 zf`fyDgoK2Jg@uNOhKGlTh=_=ZiHVAeii?YjjEszpjg5|uj*pLzkdTm(k&%*;l9Q8@ zl$4Z}m6ev3mY0{8n3$NEnVFiJnwy)OoSdAUot>VZo}ZteprD|kp`oIpqNAguq@<*! zrKP5(rl+T;sHmu^si~@}s;jH3tgNi9t*x%EuCK4Ju&}VPv9YqUva_?Zw6wIfwY9dk zwzs#pxVX5vxw*Q!y1To(yu7@dCU z$jHda$;ryf%FD~k%*@Qq&CSlv&d<-!(9qD)(b3Y<($mw^)YR0~)z#M4*4Nk9*x1lt)=I7_<=;-L_>FMg~ z>g((4?Ck9A?d|UF?(gsK@bK{Q@$vHV^7Hfa^z`)g_4W4l_V@Sq`1ttw`T6?#`uqF) z{QUg={r&#_{{R2~9(fUf00002bW%=J{{ZE;FiHRb04hmDK~#9!T+A^Jz#tFKLZ*U+IBfRsybQWXdwQbLP>6pAqfylh#{fb6;Z(vMMVS~$e@S=j*ftg6;Uhf59&ghTmgWD0l;*T zI709Y^p6lP1rIRMx#05C~cW=H_Aw*bJ-5DT&Z2n+x)QHX^p z00esgV8|mQcmRZ%02D^@S3L16t`O%c004NIvOKvYIYoh62rY33S640`D9%Y2D-rV&neh&#Q1i z007~1e$oCcFS8neI|hJl{-P!B1ZZ9hpmq0)X0i`JwE&>$+E?>%_LC6RbVIkUx0b+_+BaR3cnT7Zv!AJxW zizFb)h!jyGOOZ85F;a?DAXP{m@;!0_IfqH8(HlgRxt7s3}k3K`kFu>>-2Q$QMFfPW!La{h336o>X zu_CMttHv6zR;&ZNiS=X8v3CR#fknUxHUxJ0uoBa_M6WNWeqIg~6QE69c9o#eyhGvpiOA@W-aonk<7r1(?fC{oI5N*U!4 zfg=2N-7=cNnjjOr{yriy6mMFgG#l znCF=fnQv8CDz++o6_Lscl}eQ+l^ZHARH>?_s@|##Rr6KLRFA1%Q+=*RRWnoLsR`7U zt5vFIcfW3@?wFpwUVxrVZ>QdQz32KIeJ}k~{cZZE^+ya? z2D1z#2HOnI7(B%_ac?{wFUQ;QQA1tBKtrWrm0_3Rgps+?Jfqb{jYbcQX~taRB;#$y zZN{S}1|}gUOHJxc?wV3fxuz+mJ4`!F$IZ;mqRrNsHJd##*D~ju=bP7?-?v~|cv>vB zsJ6IeNwVZxrdjT`yl#bBIa#GxRa#xMMy;K#CDyyGyQdMSxlWT#tDe?p!?5wT$+oGt z8L;Kp2HUQ-ZMJ=3XJQv;x5ci*?vuTfeY$;({XGW_huIFR9a(?@3)XSs8O^N5RyOM=TTmp(3=8^+zpz2r)C z^>JO{deZfso3oq3?Wo(Y?l$ge?uXo;%ru`Vo>?<<(8I_>;8Eq#KMS9gFl*neeosSB zfoHYnBQIkwkyowPu(zdms`p{<7e4kra-ZWq<2*OsGTvEV%s0Td$hXT+!*8Bnh2KMe zBmZRodjHV?r+_5^X9J0WL4jKW`}lf%A-|44I@@LTvf1rHjG(ze6+w@Jt%Bvjts!X0 z?2xS?_ve_-kiKB_KiJlZ$9G`c^=E@oNG)mWWaNo-3TIW8)$Hg0Ub-~8?KhvJ>$ z3*&nim@mj(aCxE5!t{lw7O5^0EIO7zOo&c6l<+|iDySBWCGrz@C5{St!X3hAA}`T4 z(TLbXTq+(;@<=L8dXnssyft|w#WSTW<++3>sgS%(4NTpeI-VAqb|7ssJvzNHgOZVu zaYCvgO_R1~>SyL=cFU|~g|hy|Zi}}s9+d~lYqOB71z9Z$wnC=pR9Yz4DhIM>Wmjgu z&56o6maCpC&F##y%G;1PobR9i?GnNg;gYtchD%p19a!eQtZF&3JaKv33gZ<8D~47E ztUS1iwkmDaPpj=$m#%)jCVEY4fnLGNg2A-`YwHVD3gv};>)hAvT~AmqS>Lr``i7kw zJ{5_It`yrBmlc25DBO7E8;5VoznR>Ww5hAaxn$2~(q`%A-YuS64wkBy=9dm`4cXeX z4c}I@?e+FW+b@^RDBHV(wnMq2zdX3SWv9u`%{xC-q*U}&`cyXV(%rRT*Z6MH?i+i& z_B8C(+grT%{XWUQ+f@NoP1R=AW&26{v-dx)iK^-Nmiuj8txj!m?Z*Ss1N{dh4z}01 z)YTo*JycSU)+_5r4#yw9{+;i4Ee$peRgIj+;v;ZGdF1K$3E%e~4LaI(jC-u%2h$&R z9cLXcYC@Xwnns&bn)_Q~Te?roKGD|d-g^8;+aC{{G(1^(O7m37Y1-+6)01cN&y1aw zoqc{T`P^XJqPBbIW6s}d4{z_f5Om?vMgNQEJG?v2T=KYd^0M3I6IZxbny)%vZR&LD zJpPl@Psh8QyPB@KTx+@RdcC!KX7}kEo;S|j^u2lU7XQ}Oo;f|;z4Ll+_r>@1-xl3| zawq-H%e&ckC+@AhPrP6BKT#_XdT7&;F71j}Joy zkC~6lh7E@6o;W@^IpRNZ{ptLtL(gQ-CY~4mqW;US7Zxvm_|@yz&e53Bp_lTPlfP|z zrTyx_>lv@x#=^!PzR7qqF<$gm`|ZJZ+;<)Cqu&ot2z=00004XF*Lt006O$eEU(80000WV@Og>004R=004l4008;_004mL004C` z008P>0026e000+nl3&F}00093P)t-s00030|NjC40s{jB1Ox;H1qB8M1_uWR2nYxX z2?+`c3JVJh3=9kn4Gj(s4i66x5D*X%5fKs+5)%^>6ciK{6%`g178e&67#J8C85tTH z8XFrM92^`S9UUGX9v>ecARr(iAt53nA|oRsBqSsyB_$>%CMPE+C@3f?DJd!{Dl021 zEG#T7EiEoCE-x=HFfcGNF)=bSGBYzXG&D3dH8nOiHa9mnI5;>tIXOByIy*Z%JUl!- zJv}}?K0iM{KtMo2K|w-7LPJACL_|bIMMXwNMn^|SNJvOYNl8jdN=r*iOiWBoO-)Wt zPESuyP*6}&QBhJ-Qd3h?R8&+|RaI72R##V7SXfwDSy@_IT3cINTwGjTU0q&YUSD5d zU|?WjVPRroVq;@tWMpJzWo2e&W@l$-XlQ6@X=!R|YHMq2Y;0_8ZEbFDZf|dIaBy&O zadC2Ta&vQYbaZreb#-=jc6WDoczAeud3kzzdV70&e0+R;eSLm@et&;|fPjF3fq{a8 zf`fyDgoK2Jg@uNOhKGlTh=_=ZiHVAeii?YjjEszpjg5|uj*pLzkdTm(k&%*;l9Q8@ zl$4Z}m6ev3mY0{8n3$NEnVFiJnwy)OoSdAUot>VZo}ZteprD|kp`oIpqNAguq@<*! zrKP5(rl+T;sHmu^si~@}s;jH3tgNi9t*x%EuCK4Ju&}VPv9YqUva_?Zw6wIfwY9dk zwzs#pxVX5vxw*Q!y1To(yu7@dCU z$jHda$;ryf%FD~k%*@Qq&CSlv&d<-!(9qD)(b3Y<($mw^)YR0~)z#M4*4Nk9*x1lt)=I7_<=;-L_>FMg~ z>g((4?Ck9A?d|UF?(gsK@bK{Q@$vHV^7Hfa^z`)g_4W4l_V@Sq`1ttw`T6?#`uqF) z{QUg={r&#_{{R2~`6RjA00002bW%=J{{ZE;FiHRb03u05K~#9!VqjoI00ssI6b=Il nhXI!ivK}PU00000|NjF33?~3ZGNlzM00000NkvXXu0mjf(Ym^p literal 0 HcmV?d00001 diff --git a/include/javascript/yui/build/assets/skins/sam/menuitem_submenuindicator_disabled.png b/include/javascript/yui/build/assets/skins/sam/menuitem_submenuindicator_disabled.png new file mode 100644 index 0000000000000000000000000000000000000000..427d60a38af14ac7b530a266dc2e969555d287c7 GIT binary patch literal 3617 zcmV++4&L#JP)KLZ*U+IBfRsybQWXdwQbLP>6pAqfylh#{fb6;Z(vMMVS~$e@S=j*ftg6;Uhf59&ghTmgWD0l;*T zI709Y^p6lP1rIRMx#05C~cW=H_Aw*bJ-5DT&Z2n+x)QHX^p z00esgV8|mQcmRZ%02D^@S3L16t`O%c004NIvOKvYIYoh62rY33S640`D9%Y2D-rV&neh&#Q1i z007~1e$oCcFS8neI|hJl{-P!B1ZZ9hpmq0)X0i`JwE&>$+E?>%_LC6RbVIkUx0b+_+BaR3cnT7Zv!AJxW zizFb)h!jyGOOZ85F;a?DAXP{m@;!0_IfqH8(HlgRxt7s3}k3K`kFu>>-2Q$QMFfPW!La{h336o>X zu_CMttHv6zR;&ZNiS=X8v3CR#fknUxHUxJ0uoBa_M6WNWeqIg~6QE69c9o#eyhGvpiOA@W-aonk<7r1(?fC{oI5N*U!4 zfg=2N-7=cNnjjOr{yriy6mMFgG#l znCF=fnQv8CDz++o6_Lscl}eQ+l^ZHARH>?_s@|##Rr6KLRFA1%Q+=*RRWnoLsR`7U zt5vFIcfW3@?wFpwUVxrVZ>QdQz32KIeJ}k~{cZZE^+ya? z2D1z#2HOnI7(B%_ac?{wFUQ;QQA1tBKtrWrm0_3Rgps+?Jfqb{jYbcQX~taRB;#$y zZN{S}1|}gUOHJxc?wV3fxuz+mJ4`!F$IZ;mqRrNsHJd##*D~ju=bP7?-?v~|cv>vB zsJ6IeNwVZxrdjT`yl#bBIa#GxRa#xMMy;K#CDyyGyQdMSxlWT#tDe?p!?5wT$+oGt z8L;Kp2HUQ-ZMJ=3XJQv;x5ci*?vuTfeY$;({XGW_huIFR9a(?@3)XSs8O^N5RyOM=TTmp(3=8^+zpz2r)C z^>JO{deZfso3oq3?Wo(Y?l$ge?uXo;%ru`Vo>?<<(8I_>;8Eq#KMS9gFl*neeosSB zfoHYnBQIkwkyowPu(zdms`p{<7e4kra-ZWq<2*OsGTvEV%s0Td$hXT+!*8Bnh2KMe zBmZRodjHV?r+_5^X9J0WL4jKW`}lf%A-|44I@@LTvf1rHjG(ze6+w@Jt%Bvjts!X0 z?2xS?_ve_-kiKB_KiJlZ$9G`c^=E@oNG)mWWaNo-3TIW8)$Hg0Ub-~8?KhvJ>$ z3*&nim@mj(aCxE5!t{lw7O5^0EIO7zOo&c6l<+|iDySBWCGrz@C5{St!X3hAA}`T4 z(TLbXTq+(;@<=L8dXnssyft|w#WSTW<++3>sgS%(4NTpeI-VAqb|7ssJvzNHgOZVu zaYCvgO_R1~>SyL=cFU|~g|hy|Zi}}s9+d~lYqOB71z9Z$wnC=pR9Yz4DhIM>Wmjgu z&56o6maCpC&F##y%G;1PobR9i?GnNg;gYtchD%p19a!eQtZF&3JaKv33gZ<8D~47E ztUS1iwkmDaPpj=$m#%)jCVEY4fnLGNg2A-`YwHVD3gv};>)hAvT~AmqS>Lr``i7kw zJ{5_It`yrBmlc25DBO7E8;5VoznR>Ww5hAaxn$2~(q`%A-YuS64wkBy=9dm`4cXeX z4c}I@?e+FW+b@^RDBHV(wnMq2zdX3SWv9u`%{xC-q*U}&`cyXV(%rRT*Z6MH?i+i& z_B8C(+grT%{XWUQ+f@NoP1R=AW&26{v-dx)iK^-Nmiuj8txj!m?Z*Ss1N{dh4z}01 z)YTo*JycSU)+_5r4#yw9{+;i4Ee$peRgIj+;v;ZGdF1K$3E%e~4LaI(jC-u%2h$&R z9cLXcYC@Xwnns&bn)_Q~Te?roKGD|d-g^8;+aC{{G(1^(O7m37Y1-+6)01cN&y1aw zoqc{T`P^XJqPBbIW6s}d4{z_f5Om?vMgNQEJG?v2T=KYd^0M3I6IZxbny)%vZR&LD zJpPl@Psh8QyPB@KTx+@RdcC!KX7}kEo;S|j^u2lU7XQ}Oo;f|;z4Ll+_r>@1-xl3| zawq-H%e&ckC+@AhPrP6BKT#_XdT7&;F71j}Joy zkC~6lh7E@6o;W@^IpRNZ{ptLtL(gQ-CY~4mqW;US7Zxvm_|@yz&e53Bp_lTPlfP|z zrTyx_>lv@x#=^!PzR7qqF<$gm`|ZJZ+;<)Cqu&ot2z=00004XF*Lt006O$eEU(80000WV@Og>004R=004l4008;_004mL004C` z008P>0026e000+nl3&F}00093P)t-se}8}f|NjC40s{jB1Ox;H1qB8M1_uWR2nYxX z2?+`c3JVJh3=9kn4Gj(s4i66x5D*X%5fKs+5)%^>6ciK{6%`g178e&67#J8C85tTH z8XFrM92^`S9UUGX9v>ecARr(iAt53nA|oRsBqSsyB_$>%CMPE+C@3f?DJd!{Dl021 zEG#T7EiEoCE-x=HFfcGNF)=bSGBYzXG&D3dH8nOiHa9mnI5;>tIXOByIy*Z%JUl!- zJv}}?K0iM{KtMo2K|w-7LPJACL_|bIMMXwNMn^|SNJvOYNl8jdN=r*iOiWBoO-)Wt zPESuyP*6}&QBhJ-Qd3h?R8&+|RaI72R##V7SXfwDSy@_IT3cINTwGjTU0q&YUSD5d zU|?WjVPRroVq;@tWMpJzWo2e&W@l$-XlQ6@X=!R|YHMq2Y;0_8ZEbFDZf|dIaBy&O zadC2Ta&vQYbaZreb#-=jc6WDoczAeud3kzzdV70&e0+R;eSLm@et&;|fPjF3fq{a8 zf`fyDgoK2Jg@uNOhKGlTh=_=ZiHVAeii?YjjEszpjg5|uj*pLzkdTm(k&%*;l9Q8@ zl$4Z}m6ev3mY0{8n3$NEnVFiJnwy)OoSdAUot>VZo}ZteprD|kp`oIpqNAguq@<*! zrKP5(rl+T;sHmu^si~@}s;jH3tgNi9t*x%EuCK4Ju&}VPv9YqUva_?Zw6wIfwY9dk zwzs#pxVX5vxw*Q!y1To(yu7@dCU z$jHda$;ryf%FD~k%*@Qq&CSlv&d<-!(9qD)(b3Y<($mw^)YR0~)z#M4*4Nk9*x1lt)=I7_<=;-L_>FMg~ z>g((4?Ck9A?d|UF?(gsK@bK{Q@$vHV^7Hfa^z`)g_4W4l_V@Sq`1ttw`T6?#`uqF) z{QUg={r&#_{{R2~9(fUf00002bW%=J{{ZE;FiHRb03u05K~#9!VqjoI00ssI6b=Il nhXI!ivK}PU00000|NjF33?~3ZGNlzM00000NkvXXu0mjfMZ3C* literal 0 HcmV?d00001 diff --git a/include/javascript/yui/build/assets/skins/sam/paginator.css b/include/javascript/yui/build/assets/skins/sam/paginator.css new file mode 100644 index 00000000..31f0d336 --- /dev/null +++ b/include/javascript/yui/build/assets/skins/sam/paginator.css @@ -0,0 +1,7 @@ +/* +Copyright (c) 2009, Yahoo! Inc. All rights reserved. +Code licensed under the BSD License: +http://developer.yahoo.net/yui/license.txt +version: 2.8.0r4 +*/ +.yui-skin-sam .yui-pg-container{display:block;margin:6px 0;white-space:nowrap;}.yui-skin-sam .yui-pg-first,.yui-skin-sam .yui-pg-previous,.yui-skin-sam .yui-pg-next,.yui-skin-sam .yui-pg-last,.yui-skin-sam .yui-pg-current,.yui-skin-sam .yui-pg-pages,.yui-skin-sam .yui-pg-page{display:inline-block;font-family:arial,helvetica,clean,sans-serif;padding:3px 6px;zoom:1;}.yui-skin-sam .yui-pg-pages{padding:0;}.yui-skin-sam .yui-pg-current{padding:3px 0;}.yui-skin-sam a.yui-pg-first:link,.yui-skin-sam a.yui-pg-first:visited,.yui-skin-sam a.yui-pg-first:active,.yui-skin-sam a.yui-pg-first:hover,.yui-skin-sam a.yui-pg-previous:link,.yui-skin-sam a.yui-pg-previous:visited,.yui-skin-sam a.yui-pg-previous:active,.yui-skin-sam a.yui-pg-previous:hover,.yui-skin-sam a.yui-pg-next:link,.yui-skin-sam a.yui-pg-next:visited,.yui-skin-sam a.yui-pg-next:active,.yui-skin-sam a.yui-pg-next:hover,.yui-skin-sam a.yui-pg-last:link,.yui-skin-sam a.yui-pg-last:visited,.yui-skin-sam a.yui-pg-last:active,.yui-skin-sam a.yui-pg-last:hover,.yui-skin-sam a.yui-pg-page:link,.yui-skin-sam a.yui-pg-page:visited,.yui-skin-sam a.yui-pg-page:active,.yui-skin-sam a.yui-pg-page:hover{color:#06c;text-decoration:underline;outline:0;}.yui-skin-sam span.yui-pg-first,.yui-skin-sam span.yui-pg-previous,.yui-skin-sam span.yui-pg-next,.yui-skin-sam span.yui-pg-last{color:#a6a6a6;}.yui-skin-sam .yui-pg-page{background-color:#fff;border:1px solid #CBCBCB;padding:2px 6px;text-decoration:none;}.yui-skin-sam .yui-pg-current-page{background-color:transparent;border:none;font-weight:bold;padding:3px 6px;}.yui-skin-sam .yui-pg-page{margin-left:1px;margin-right:1px;}.yui-skin-sam .yui-pg-first,.yui-skin-sam .yui-pg-previous{padding-left:0;}.yui-skin-sam .yui-pg-next,.yui-skin-sam .yui-pg-last{padding-right:0;}.yui-skin-sam .yui-pg-current,.yui-skin-sam .yui-pg-rpp-options{margin-left:1em;margin-right:1em;} diff --git a/include/javascript/yui/build/assets/skins/sam/picker_mask.png b/include/javascript/yui/build/assets/skins/sam/picker_mask.png new file mode 100644 index 0000000000000000000000000000000000000000..f8d91932b376af76ccfac030c12eb9fec7ee4c63 GIT binary patch literal 12174 zcmV;9FLBU`P)_6|b&%Dfjpyv}j54LBIXFZqhE-_t{2r7|?ya1%Cs>h{sswI&ir4|Fh z$jAgxe*E!Arq9Rc<1hC3+xpMn|Ni&&sREphKX2dqw+!rCg4fvHA{v>|sAOH9VUq1Wx=i{&V_yqRn;}h7QkI%<-7fW_4(VkZ}j!+ z*W3A4Q2+7AAN1S*{zm`&=RfJ^|M;1H`st@nDf0RFlp-IAiA&;HZ{w3b`^>wEDMb|H zcWo7$YKZ}V2ee&$PJPY#JEPa?S+a1^5~E@1g&W3xW#A&D$3t?w{=G7DSsA*r_4-%Y z`s|z_E&o@}NSYWQ_Q@Xg&3d|Ou zW&0J1V(Gn21@Ok$tl7ApUjkd|>Gf{~b_Mkc=*rd-*uVe&`%Pc}`s=SZK(DV?u$Q+4 zw*GP77{rl7z$bi8N=|4%dgnzQK{K@X9=v7^ctch^o|!a57b!8M)R5bd+^DZB*f)2h zXi(pP{pA7dU4m@DUcq}~?BDNws-MON*}ARvB9}^yYkUl^^T(x&iy;x&pXVP)oMH zG4>x1DYCNm`n+yi_f;$KX~32?&=bL&3KR!`?Ad)hXq&kbL*FF~DPi6Lgmfs6L(D+0 zND0vbo2}RNnI*FeDS>21aabAxyE61@^}W7lp{p^l|7WGkjF52;svSZcA8su7jAYiZ3LweO3*sn5! zSD>!n=?3mEUmKmhK6d%BxhCszn^Za-*h3D(8SY6kiNgaaXQX90(eY3K$c_zH0Bie! zBHJ2UyB-p(7Bef5YbLIag?2iM6)3&}lecGR>8-$C0bN;o1$K2uG_Y5@@20Q6ep|mt z*;#x0tH7=ryq?1awzczFEUg2jL1spUI~;shFFVJMWT3#Y2!p-uSjIu7V%f`fjs-Ap z^O>)I7X@&(g2WB97X@e*&x;21dj4(4t<5d)+aC4x2CzHGU+%zOzu(5F>;Cn4UV*tj zZ$V@8yjpp$fL&R8ZO0o+m)B>04HkLJJo2A^{CRu7ZvXb}emug@Fk>GfXvJPL@_-^q z01_^oksZ=)$m(QUUX;~R(;!CYEsBZDLoIZEb1~!wBOR^fg#bCy%lortW+6TF_FY@w z&6w46@B~bZ!ZnoFU!@$z>E}`k{^oUMnFB{O&3px81f^O z51QS()3a{J?CEH!+pUC&YHNa5>Eykw2XY`qJYY8f?~*Z#9Wbu!EB)#UYzgYy^IbES z3h4T`vT|kq^`Z574Oq_r_AIDJ0c{44L7>OU1PLbsz#Hu@vK`wj512a*;t0UHoeBa? zk6L-sMY|p{s1$`s7O*7~*BX(c{b~v9`g)Thw{{({Us@kq|5b2nV9S~lBm$l;MJBR- zSsN}46ctdtgi9+$xa(0`+j0;b5@@3(htB#Thl4>@u&CE;xE$KTV_CN$*;#_wksf7p zH>9;!8MRBwYyjM)2y#PKP>c6P+kZ7HSsw`0kDr;x8GBY&%c%cEP&e$K0;+W$c6Ga3 z-f4l|(a#9Tgjm>eL6n{@$mNioz>^;m>!~orEy~tWx3~ zOIPqpfCGkR(H?r%tE(Zjv@CMcj9p#<%|dfa05{ue+I>B?x*{YBs9Lr@sIdpzjet7C z(j3YXHqYbA7G>{gy$rQE(#f8iq4wzn3QC-$G_@y1j3806bjQvT*z2!Z!CPeq$}$Qt zKiFGHksaJG`+EfLE_ox5tq+;W^uV3*u}1^OjK^IhVL9wdjz0DhDyAkTJeq`!B#Pcg zhP)_7_7G+P^?uQ&deV!Q8k_%Iz3u(DO+Od8Pl9$mZo9rWlUfCjjYrK(<6~b$ZT0S1 zS3O;Ux%tu+)a&a-3?R6yAif2U*Sn8h->)oR%UIXfo6X1d@8#Re{rTQ*_p!In<@$MS zi0rd9cH9YgPHQJ6i50k+-%kgas7Aw(CeRhp9mnRTLOFML>EN7Z(g?zUW!g!Hg9HcE;V1EAh^ef|OhyG~Aswq6=s?q4)8Rd863y;SWj zSY7I8OIMc~2-fXFMwH5^wNOOZdAr8m>OGbX*q5qptG2GXdan<;-u3UQn|Fkfk?i04PcV*!JYNDjCSSa=A`)xBsyFVf!o zcEj3Z$<&e+vLHr0ak9iY3#aPde)nR zA-C1eupV=%_1K$crutm{Xra05zTK<7Zd!fooV!f@ zjN&Brbhe|X^)|DOW?&^TSXpb-J8|rPncYZ6g>MN)cr9$&910<@S`i zkQl{aQy;-2thth!_d8NT%MNOLaRo zCuFG|O0cz;&U9i--BvN-HZ`yK2WHwUjV^zvpBugv*x@U8x z({-K67HqPx8;i~;!e{od_khhIU{6k}7aYNF7KD;K_3|HlOG;X68|WyQts~R_Ey{93p$q#vLD)BBQJf!DrZ2nhQiG*TS=m|!i=sNPks~sAWNwo((+QeE z#&&JLOxr|mJq#Wvwe^U!h^q1|mxGNOYb!WJG9t^^ z7DMZKI!Lj#PN|b)?X9WqMFoppm0nG~SG!I#I0zVZ`DqtCYId&sD^t_0?Sst)+mcAN zUvx@c>}O&7-Gj-m-xe7Z%Keh9Wq_!IMZnTSjO}I%4>EJ4jWgw@5p#Q)LYiP`6fiQd z^$Ve27n-UX6~u~jBf+k#TtGMMS9dA;lIYZHi)4l30jO7QF&T(%QhouWT^ zynfVSX2S`ZnZPko&ykt#z}4MKa~F_k(OQ~~0%y}dDP!_F!}v#hlq(gM^>trIkoxdHpiniE-2)#zvMuOXYZ z@JTauPGdhoUrzx&2nsFzYz-P9uOq1X=#HU5Icmr1+m7`=TI)3+i)$@z)KfDUFrb|e zMgs?s-Dk1u&Z5gh$7`mpZ50a_t)I09Z_Y2;>j48bSd6fih|8uJJL^RwJv?I9MOj1S zdLU4vQqm5rNLt8_pn<5I7Sa+!IUbUAt>rFsNh$%|eUVd;2@Sq8wo0jAKq5vm`3kt3 z=3N~Rsk>_m9Wl3@TSRJXnS>Dm>Ye59TAeks*WX>pFw%@&JCaPu7;eaM#?H163Yxqm ziO1X{Y;1uY1)XquF~r!S{e#6HD+K5cU}@)0U+V%VRlwA-9$@K^y(J@8pB$}LpzaKz z#@63&zauQRhE`R26msV$Z^{OZT{Yqz~|MKp5@rfxL0c0%O-=ufe>>^uw{kcP3JqOoTg z+bjHcEIkgV+Xd`yFtrAF15DLXpaVjTJA-wc7@{Rz2CcE1z_Vdg<2a#%A@fTHRary$ zx^qPy{_{TkOX+1&?B6kR^}s#nLpfB<^+cJ+!)2=@cHV%N&a^i{jchr@!b(pU4J^^d zO17|ADFAxZ`eGm^1_e)qtT@Ery0EFfmaLv(=|+cN8%Rh$tyRdxLGaieqrB*@ zL#S!P*wWof-%8)Qb4e_g_L$k4z#SDq0S(+`G&PH>PTX|r+7{K~Ti3eID{{XsPtw=} z0bxo@dr1_)!UUvA#=f(B>9TP$k}MsN5fF`Yl1{Sda#ZD%T;wD_* zrR(uRL+ilL+JnOY9wm9-+$udbbEn?0(LOj>$r_hai=7gPtL*qQi|ZPXQR$29gp zkeHn=VZ^I8vx(Xr3C^*P2@HVj>StOa=0bwJ{*liQX>WaLOu?0&v$0Jsj zZGj8Z3^mjKv_3!Zt()Tzw)7pqx@$jMW2a1WYelRebzTA;ZOaH?FNSYztt>#^x{9&}1iB)CrBSv~c-4}XJO4VNu`kuHu8xMR`H+r@WMy3&f@(oD zV-IQUBfyT>ItFjOyTqV&0>y3{a4&QaiC7u|8A%bSB@^2+!6JcGyO0!VK!4kJZHk>1 znNk-3?ybKKaCMsmp|tx{qUMoqf7#pY9YA&lk%ZZwrPU|5J9327sG0NZzDc%Dr%025 zqCIwz@d$Rqv$k9j0=G{sMPM7F99180rOMfIOX{5lSZj~hBGDq+p)@>{DBd>D(nB2@ zz1GjEM9YEo=n!M0*-1Ij*Dw%_*w@JncJ0>&i~KC^eP`rF2U)|W{@J)VA!A!|1Qar* z*jjIw0i|Z_ef0$;GbCeMEUibRZ?mK78J{kaZ6ym=Hg~jl6AQ>=HEZjAwYpG94|(1j zW6N|q-Bz=DfN-cDdxU)xSwru&TsGqlj#fXTK+$96&LKfghSJ8J%i;Ld466Ic7^EwK zuHB7AWfjo^qGj`m7f~6w&sVL%jGPcDOR5_pYDq3q8i?$oc2L&4#06v<775i>3x}i}tq++VK{F93+C@%G zValBBMTkrmmI0*)W{`~}Bamck?hjo=AIT2H;zr=Ov-i5ctc-b|dO^D>y);olB4TMB zC|XiP28;VR$Cqm(8I)rp>kC5c^snH_B6o0E;XOGDq4mJAaYlw*nfA;o{!0X+V9n+`Q=20nuSDlk0 zdgAwJ=+@w{od%FmxoH4qYj6Ry<_6@487vZ>V-HCY_L4Ek;gHVAHhozyMcV2<0vW}W z{7{x50y!yd{Q&F2azst1q4hSTulr-+Tp`h%A*?MwAJ_+zEJ?ObOB4spn(@)R)X>2& zf=kQ!usm=ppk%N<3>mc_`qq7y4os*fgh3{fE%yV-ALNecQ9724spY3iR-n%;mLmd6 zE873Ja6=*qeEPg1Cyb7X=BtLlGg9Z#Gl5!Z*j^VXfzjv;q(@hx2?D~5Jdw7U_P2|X zXdzX>N67uq%&cTd!^|?#(m5pyv#$2jQbRr?MwiJL*{)@0>KMC94OKA3K#t72B8eGQ zho%5VV9w47VpMu*-A$wNL!A%GiU-iw7fW|M05Jh}mf1p5fbI&HM3Gac!nzy#;7ldzS7-AeZ2l+khNtzzZzBJg{dp zb~=mbyw7Y0_M9bK!fawT={_?Rk|qSC2C5A~wb;**BF6L!W`$oc0wS#Y$YvKE zd17j5OQIOlnsscaN0*DLL$AtD>*~b_1WCz@B5FbwppQe4OMr?AbDH21$qb#P1Oo$h z`Jrt*5Px-YLqh0lp~&%y-E2wy05*1A5Qnk%VHvfhCyH zC=hpY#SvhGb9KOVK)%&Y^RnGaB(p=7)*V4_v-Gn7YcXoCFRC_(RZ!S6b8Cfqwbxbv zIj6A?%91d9Xt1|+Of}XTw3;!B44<0% znWwtB|2&P4+P1NSp^2?K9QLkzeJ!ClT9SHNtqA8<27~p{mMh}O4{Na_#LV9CBRDWv z0#Jih47q~#9>@&J3tPNlQHDPawRfPgO~%%`y0s}74Z!7ym6a4BPiw1+ygEt-x+0)F zb#IHD5sR_Ifd)sVNL0&_vGT}Xc+?%csAYn*+Q^s#o56yZ9IR5MSuC&vo8!1&Bi#ab zqlFVvgjB+%|65pFi}1B2Pjo6A6*5T>N(ltKX>(B|m0NHnM|lj~Jr~#sRwic^FJ1-T`NnK`Sm1G_Iw#v}#|WQK-WlSrb8+AYnEC!}nrHzOofG;mq1M+5E# zF0gem)7`OLLSQ3s1BPWaokAx|WSl1)5O_Z6ba(|#QZlH~GNb{nI{^wDZ8k5vpDICX zWG18F@zH)Vr5-va5qopI{6+-mtjzF^x9ma0=x8jY25H&De=xXL-ukp$GA4EJ?nEl- zQ?{Ut(U?OkHjw~DK_d!wv%y_+E+_VTv|H%tHi!TN=lLhqd)(n^$wIw5XbX}6n z`wVcC!1m9<6ftn4w>5(+5MMNCf!6LiiE4Whw^Y6wQ<}v(+fAE42iREv2fEtS=E3Z# z5uh!P+mj_oiZsVqH6tECPhe|8cAs!~*a#jwEAVkGN;B?DgH?WY8pQ;Rv=0J-zk#a?d`U!O06|i&_pC0~% zs`H#tCai{-F-YNecP#Zgvjn-m4!WXHOEei+>hHL2yn0o89qjDD)2se_dhnP@n|qag zq7K&uG4;zpyE+``=ZwZifMAQ|GqM9DW;}m7&*Dql$%OnMBsqMELWGhrj(%q3(o|;F zm3fVvSr`q@)mGl(=b*|dsgt6oOp6bR~u`cPXan(Y?Gyewo|O!dC`^>(LOeEI&2wo%g8#w=7X*X=dws6C9Z=RM)P&R>XeWcW*}*S9|dBO z#E4vw6hn)0PQ$k*rB~U=N_Ki%gBgJqonHde7}bdbG3X-bM%8BGh!5%`glVkCChN}~g3BW$M}kFK2>ONsVtFvIPh8-j|! zP`X_o->~@7R1I1~_EP)g01;!(lkT_dq{zVuDO3BhOrBuw4xoebW0}oV0S%e1I!G@ zS(<=GAhvWhk}V>&+|*Y)b=L0-?9AW-BY4bAxj;rqE3At~Ky}WW0=SHa2iUo(K{h79 zoT?DC0FAa;NfwZ-@hm`!>^_u$QRi@h3rq?mNydOZGE=G{H&Tn{xCKvROl{R@LvI^( zB**_YItF)xh#kMXDH{M%hCO)$0MF=nR&EvuhTU2bMl1Q!wJQMKqreW=pfU8fHKC=;%8?Wy zW7a2QbPj5(!NIjz>u$oivp7#D1d0NoTZEjF9$;1MK(IMCCG zx#4mA491Rzkwx{-qhlU*CEw$JHpIZDM;^H+`-KBjpLq;>6vPe?U29I&lkB=&7dC0T zkL-zu_B9&G9&wIzIR`R>lTzb(!J|=U9R-`&X&KV;#bWceXp7Ay_biXxa!>Y)!Gw|^ zRzPXZRpL4+;23w5y4e9ilxJLLJ(vJZZMK~=hmp~M@T|Zw#n?zU2c03D=h^@)oM4jt zsnM*VVdlh?mfl95dUI}PN`okEK2kL0v3MjOvN9u+K?D|Fd;ZM@K@!6VE-4WpdRjVS z`e9&)&ImiJgbn!Hp)7H-n8gVs%>dH{es0F7IG{|}g8|!fpqD#of!gVkQq&1hX3_GZ z_3_C-5c<`Ii&6%I$Pr){sa-I;}6YGm*O`nF^QD6H`R=aiQ0s=u4 zTza2}Kqg;X`>lWu)lt7?a43FWI*YMWGq5^yjaX|lW+X^@MFS{LxLd9dEvFY2K>Mgp?OA;_w>u?86cFL0 zl^u|i`zRqxP>`3><7&bkb1pweD>LXk79h=KJ3K9)2o~)&cO%)=1g}F zezt&oXXmE4tL+eryM}%D`&caP0o?<5GC3n&x1^uY*oC}O)4&Ny&lDB0x4RvToOh&) zr$x!r&{le0YierKcvjGr`MhwQN2@c|(vL0gU66c2WH&Pd(};GS(b>6m9(kOx2U$5v z@|0jSjm6$YCkMz`nb*JIW&u`KPe-hr@wz*AM^1+0bSRGYKYlwV;Do^T4dXIFHa6J1 z)5oZS&(qlha)lDCehAo6iE0Y?R>0YuTY#ACrKQ=>*;xRyl>~C^y1g2X{k0@ro$W{? zwvM-s$pDz_i65J#OcG%Bz!;8vLC%YD?so%r2z*0VV~N1-I_u_z2H-X|cn0LCMglSM zk_53Mlgw>~!{KUf$8{>kWIt>;QEu|Y(%7QI@3#!A20N#nd+-LJ&->U1fju>|lm~u` zMVtiAa2v1VIPJr2mhANV{@gxO%YTY*rpumms_z`G6*Nz z@vOfDix06fV0>$B$utX(vNk(w-AuBv%gzxK2aX60xFRL6_ufZ}bZ!6>Cu>P8z_~%E zH<=FdoV||Vfm~{K063R%M}Vz=BS&@=XYTJbm>oS$PO`<-#+Jr*?hJ)Bt`PObM)kSZ8H|g?k<=*@;I^`DUND+wP){p6|2G-|G5*}WiV*^B=KId- z;G@Tf8k-jmEBQtPM31$T_1&(cVlBrp3fd&t$w|wntNq&V-IN5&It_E4@Imd|Kl?!< zfuUTc3zAHObCRvo`Z^&~rld%Ai4Mrxfz*f=J2kV1&iOMk#tIN2lVtAiQla>BXSp(9++bG|?7bP^y}FKW_JBeC3hEjw3ZfkQ=ooGj?Ibj8S#saVB*- z(a3wWYzYE&Mi#gdr2U=EcHfQNhXCmfHXuAzgA3lI-REUKqmoum9Ai$?F!CHEmD0~z zqF9XWl^>uxWn#1olpsOM+>$6(x}0oQrzmhdPl^o4kuac)((nmM5;-1}WlGssZT7om z&`$%t(;*_@Mk^abP-k3?V4{ACM!F=WN2VN=j44B&BSj(rM^iD32B1+VaO%L_i|*Y4 zY*t?&sLqff4*OA7!ZgPku1D6@utwCJ{WyPAO_H%kf$k=8h&W*C==PQYs~c!Wj2#U! zFn*)-F|TRRDm+6Dq3p;2+49V@!K-(?{xPPPoF1to z$x0H=yC}mJp~L3**vIz?8MOj$Qro8;i>#|LTTB(5kG`YF^a7^fmu>C|j@F))CsXdp z2*c0Hi~~%Z-PZrVI2D6HRvrQW5r+0;$An*<4jfMfb~Hxr6qu(0VIU{6XB%fdUt+7GKM$ZQ7d z+*G-q^3AhAkG6UGeKe43wk=Z~@{qi^8g4~a7kh3;^x0=fpYx@Ed05BU<|1?Y@y9GNH9cw6|*ydMtC~bu#Ur zW^%V9`U#e%tuqzfu>F?#-9|w@YT*rZk~0~*#cRn2ktxkSAW3Ed%?xnei<~%b>YUvy zQB0iuZb_Yd#{V~D+^D7_lR5mbj7|2~MWfx0!AN^YIy$^?2|Zp0fzVvE@~A_$*cnVA zMw#g)ypCq2vdiFXhx6E0)LqSNUxhI zVW-W=i}3ha-8{;~vjY#ZReptXbC!%U_7TS<<#h*49XcddFz8&+VQpzLHIvtFG}ukc ztmOZTJf~!aiH*rPc@pR;9nD7=JCGdVDq<116>`I1b5xT@tC-Dp5?2cO>`Zi$Oc?Cc z(=Nq~W}cBGvz~W!9>~};tnKM?az?r*E|O;jW_03+7UVQwICongNlHz~C-}PvCLZYw zR_qcowKa`$hP?y!^;8FkQe+UQgE~86O1M%&)(VWI%!rlfG4Y`wbreh^=ZP%0M8brg z;dU5oO-Jt}hg^{e*c8v~l#?WMUt?_~z?@+B^hF06nQ2~sj#!{Wam0bn8hwA4g(GPp zre)|l%aSOn8U*|Kj6IRW895IgvD0rHxqx+pbT_1PaWqhU>-R^eY8dPASqqQe_aWKy zbYM@gdG;KmUU;{SlVCmuzzWeg767aWXd_QWP{P+&9)h)*5Dlk z!wjP}|BcZa_lfvoG{C0G|7UodwcV@AJHfqqjue^oy9ceoY@nI}^Q?wH6;v~TLW`Kr zXy79tKO?#FmJgG$lhVOuZE*2ZjE(?$gwY2R3`cIyVJA+KNNfEK$gcDqZHkf0VMdOe zm>Iv^1hyK8I~oYO9l-Us@yB|M4gsFj<5}h%0zYagcd)ZD(q&^V&IE^>F~$_5al^!k4%1 zJn&9?;+~W-ewCt^;T`NeM?jwi+M(lXmEnk#nsGM*Cu2AujAFmD9g=3^cRpazg{)2P zn8^slCiA+?NR(!+NuZ1{S-MkuZF%6gv9{}!d*XLgzfH?4N!?6zAmK9F0seNx-8fs1 zXDviP*JZL(3;|+<;j`Pb3|s~}q7~H5vaL6j*f~=voG(jG12zp0Lhxjb*#NQD5r-zc z8>nBrJig*G4d%vKNVex5w1@9RM?K}U<_D?ky?<0-r@?(R`7p`ot`?H2s#>^rZ4^=FlN|z7;uANn-1>IN}N2Cr3Zk`BP^T*Bp+h=GXQ?n zq4@~xH~`i&0DT(!&VYJ`-9wFiKyS}TnG}0}0I747b%*zVRH^Xn>CK)NJe~mTrv#t_ zcabwXLIlFM0P-}L$AMa&#=dX$_}d`x3eTZ?RLY=?o8@$7*!k>srvp9PW)jSU?U;_9 z^Qe?K+IdESZGby%u+M1qd$#NeEItDAvw?m9$ftmLQX9{>7*l{gdPf)rHlFHin8at8 zf231nfja`;X`qjQ{TPtT2$-J+=#L;%GCuZM%zFe-GoTq|EqXG0J-rjFA!)YD@D%G+(%jVtWGl1QAU{d2%u&<<*Zbo86f4@e+txxnf@rS&tmU0L4FkI zvtVzu0H1hQIRnIJ0C_feJe#F6_kc5iO=q3M`0__VKFhGvjLYYO_Y5XJ1jJ{7c^Yep zHW&J!52nA`qtNH$?S3o4*oSLk&tTSPNrW?X?<5;9naK^$U}fVxx$Ap|$u2f@bg3gWkxHK%Fp4+8RMf$}i0&g=*$e&(C#qxaD0ZvpHl zv+I6`Mm!BUmxWOUFGBaUp^pXA9e5eL-vl3cNcl?@AS6vgTG5D@?CMq zTi=Sx2mN33JO2+a9~-FUJu&myl|RHap8Fr(82g7GfB2M~pO3%P.bd>ul:after{content:".";display:block;clear:both;visibility:hidden;height:0;line-height:0;}.yuimenubaritem{float:left;}.yuimenubaritemlabel,.yuimenuitemlabel{display:block;}.yuimenuitemlabel .helptext{font-style:normal;display:block;margin:-1em 0 0 10em;}.yui-menu-shadow{position:absolute;visibility:hidden;z-index:-1;}.yui-menu-shadow-visible{top:2px;right:-3px;left:-3px;bottom:-3px;visibility:visible;}.hide-scrollbars *{overflow:hidden;}.hide-scrollbars select{display:none;}.yuimenu.show-scrollbars,.yuimenubar.show-scrollbars{overflow:visible;}.yuimenu.hide-scrollbars .yui-menu-shadow,.yuimenubar.hide-scrollbars .yui-menu-shadow{overflow:hidden;}.yuimenu.show-scrollbars .yui-menu-shadow,.yuimenubar.show-scrollbars .yui-menu-shadow{overflow:auto;}.yui-overlay.yui-force-redraw{margin-bottom:1px;}.yui-skin-sam .yuimenubar{font-size:93%;line-height:2;*line-height:1.9;border:solid 1px #808080;background:url(sprite.png) repeat-x 0 0;}.yui-skin-sam .yuimenubarnav .yuimenubaritem{border-right:solid 1px #ccc;}.yui-skin-sam .yuimenubaritemlabel{padding:0 10px;color:#000;text-decoration:none;cursor:default;border-style:solid;border-color:#808080;border-width:1px 0;*position:relative;margin:-1px 0;}.yui-skin-sam .yuimenubaritemlabel:visited{color:#000;}.yui-skin-sam .yuimenubarnav .yuimenubaritemlabel{padding-right:20px;*display:inline-block;}.yui-skin-sam .yuimenubarnav .yuimenubaritemlabel-hassubmenu{background:url(menubaritem_submenuindicator.png) right center no-repeat;}.yui-skin-sam .yuimenubaritem-selected{background:url(sprite.png) repeat-x 0 -1700px;}.yui-skin-sam .yuimenubaritemlabel-selected{border-color:#7D98B8;}.yui-skin-sam .yuimenubarnav .yuimenubaritemlabel-selected{border-left-width:1px;margin-left:-1px;*left:-1px;}.yui-skin-sam .yuimenubaritemlabel-disabled,.yui-skin-sam .yuimenubaritemlabel-disabled:visited{cursor:default;color:#A6A6A6;}.yui-skin-sam .yuimenubarnav .yuimenubaritemlabel-hassubmenu-disabled{background-image:url(menubaritem_submenuindicator_disabled.png);}.yui-skin-sam .yuimenu{font-size:93%;line-height:1.5;*line-height:1.45;}.yui-skin-sam .yuimenubar .yuimenu,.yui-skin-sam .yuimenu .yuimenu{font-size:100%;}.yui-skin-sam .yuimenu .bd{*zoom:1;_zoom:normal;border:solid 1px #808080;background-color:#fff;}.yui-skin-sam .yuimenu .yuimenu .bd{*zoom:normal;}.yui-skin-sam .yuimenu ul{padding:3px 0;border-width:1px 0 0 0;border-color:#ccc;border-style:solid;}.yui-skin-sam .yuimenu ul.first-of-type{border-width:0;}.yui-skin-sam .yuimenu h6{font-weight:bold;border-style:solid;border-color:#ccc;border-width:1px 0 0 0;color:#a4a4a4;padding:3px 10px 0 10px;}.yui-skin-sam .yuimenu ul.hastitle,.yui-skin-sam .yuimenu h6.first-of-type{border-width:0;}.yui-skin-sam .yuimenu .yui-menu-body-scrolled{border-color:#ccc #808080;overflow:hidden;}.yui-skin-sam .yuimenu .topscrollbar,.yui-skin-sam .yuimenu .bottomscrollbar{height:16px;border:solid 1px #808080;background:#fff url(sprite.png) no-repeat 0 0;}.yui-skin-sam .yuimenu .topscrollbar{border-bottom-width:0;background-position:center -950px;}.yui-skin-sam .yuimenu .topscrollbar_disabled{background-position:center -975px;}.yui-skin-sam .yuimenu .bottomscrollbar{border-top-width:0;background-position:center -850px;}.yui-skin-sam .yuimenu .bottomscrollbar_disabled{background-position:center -875px;}.yui-skin-sam .yuimenuitem{_border-bottom:solid 1px #fff;}.yui-skin-sam .yuimenuitemlabel{padding:0 20px;color:#000;text-decoration:none;cursor:default;}.yui-skin-sam .yuimenuitemlabel:visited{color:#000;}.yui-skin-sam .yuimenuitemlabel .helptext{margin-top:-1.5em;*margin-top:-1.45em;}.yui-skin-sam .yuimenuitem-hassubmenu{background-image:url(menuitem_submenuindicator.png);background-position:right center;background-repeat:no-repeat;}.yui-skin-sam .yuimenuitem-checked{background-image:url(menuitem_checkbox.png);background-position:left center;background-repeat:no-repeat;}.yui-skin-sam .yui-menu-shadow-visible{background-color:#000;opacity:.12;filter:alpha(opacity=12);}.yui-skin-sam .yuimenuitem-selected{background-color:#B3D4FF;}.yui-skin-sam .yuimenuitemlabel-disabled,.yui-skin-sam .yuimenuitemlabel-disabled:visited{cursor:default;color:#A6A6A6;}.yui-skin-sam .yuimenuitem-hassubmenu-disabled{background-image:url(menuitem_submenuindicator_disabled.png);}.yui-skin-sam .yuimenuitem-checked-disabled{background-image:url(menuitem_checkbox_disabled.png);} +.yui-skin-sam .yui-pg-container{display:block;margin:6px 0;white-space:nowrap;}.yui-skin-sam .yui-pg-first,.yui-skin-sam .yui-pg-previous,.yui-skin-sam .yui-pg-next,.yui-skin-sam .yui-pg-last,.yui-skin-sam .yui-pg-current,.yui-skin-sam .yui-pg-pages,.yui-skin-sam .yui-pg-page{display:inline-block;font-family:arial,helvetica,clean,sans-serif;padding:3px 6px;zoom:1;}.yui-skin-sam .yui-pg-pages{padding:0;}.yui-skin-sam .yui-pg-current{padding:3px 0;}.yui-skin-sam a.yui-pg-first:link,.yui-skin-sam a.yui-pg-first:visited,.yui-skin-sam a.yui-pg-first:active,.yui-skin-sam a.yui-pg-first:hover,.yui-skin-sam a.yui-pg-previous:link,.yui-skin-sam a.yui-pg-previous:visited,.yui-skin-sam a.yui-pg-previous:active,.yui-skin-sam a.yui-pg-previous:hover,.yui-skin-sam a.yui-pg-next:link,.yui-skin-sam a.yui-pg-next:visited,.yui-skin-sam a.yui-pg-next:active,.yui-skin-sam a.yui-pg-next:hover,.yui-skin-sam a.yui-pg-last:link,.yui-skin-sam a.yui-pg-last:visited,.yui-skin-sam a.yui-pg-last:active,.yui-skin-sam a.yui-pg-last:hover,.yui-skin-sam a.yui-pg-page:link,.yui-skin-sam a.yui-pg-page:visited,.yui-skin-sam a.yui-pg-page:active,.yui-skin-sam a.yui-pg-page:hover{color:#06c;text-decoration:underline;outline:0;}.yui-skin-sam span.yui-pg-first,.yui-skin-sam span.yui-pg-previous,.yui-skin-sam span.yui-pg-next,.yui-skin-sam span.yui-pg-last{color:#a6a6a6;}.yui-skin-sam .yui-pg-page{background-color:#fff;border:1px solid #CBCBCB;padding:2px 6px;text-decoration:none;}.yui-skin-sam .yui-pg-current-page{background-color:transparent;border:none;font-weight:bold;padding:3px 6px;}.yui-skin-sam .yui-pg-page{margin-left:1px;margin-right:1px;}.yui-skin-sam .yui-pg-first,.yui-skin-sam .yui-pg-previous{padding-left:0;}.yui-skin-sam .yui-pg-next,.yui-skin-sam .yui-pg-last{padding-right:0;}.yui-skin-sam .yui-pg-current,.yui-skin-sam .yui-pg-rpp-options{margin-left:1em;margin-right:1em;} +.yui-skin-sam .yui-pv{background-color:#4a4a4a;font:arial;position:relative;width:99%;z-index:1000;margin-bottom:1em;overflow:hidden;}.yui-skin-sam .yui-pv .hd{background:url(header_background.png) repeat-x;min-height:30px;overflow:hidden;zoom:1;padding:2px 0;}.yui-skin-sam .yui-pv .hd h4{padding:8px 10px;margin:0;font:bold 14px arial;color:#fff;}.yui-skin-sam .yui-pv .hd a{background:#3f6bc3;font:bold 11px arial;color:#fff;padding:4px;margin:3px 10px 0 0;border:1px solid #3f567d;cursor:pointer;display:block;float:right;}.yui-skin-sam .yui-pv .hd span{display:none;}.yui-skin-sam .yui-pv .hd span.yui-pv-busy{height:18px;width:18px;background:url(wait.gif) no-repeat;overflow:hidden;display:block;float:right;margin:4px 10px 0 0;}.yui-skin-sam .yui-pv .hd:after,.yui-pv .bd:after,.yui-skin-sam .yui-pv-chartlegend dl:after{content:'.';visibility:hidden;clear:left;height:0;display:block;}.yui-skin-sam .yui-pv .bd{position:relative;zoom:1;overflow-x:auto;overflow-y:hidden;}.yui-skin-sam .yui-pv .yui-pv-table{padding:0 10px;margin:5px 0 10px 0;}.yui-skin-sam .yui-pv .yui-pv-table .yui-dt-bd td{color:#eeee5c;font:12px arial;}.yui-skin-sam .yui-pv .yui-pv-table tr.yui-dt-odd{background:#929292;}.yui-skin-sam .yui-pv .yui-pv-table tr.yui-dt-even{background:#58637a;}.yui-skin-sam .yui-pv .yui-pv-table tr.yui-dt-even td.yui-dt-asc,.yui-skin-sam .yui-pv .yui-pv-table tr.yui-dt-even td.yui-dt-desc{background:#384970;}.yui-skin-sam .yui-pv .yui-pv-table tr.yui-dt-odd td.yui-dt-asc,.yui-skin-sam .yui-pv .yui-pv-table tr.yui-dt-odd td.yui-dt-desc{background:#6F6E6E;}.yui-skin-sam .yui-pv .yui-pv-table .yui-dt-hd th{background-image:none;background:#2E2D2D;}.yui-skin-sam .yui-pv th.yui-dt-asc .yui-dt-liner{background:transparent url(asc.gif) no-repeat scroll right center;}.yui-skin-sam .yui-pv th.yui-dt-desc .yui-dt-liner{background:transparent url(desc.gif) no-repeat scroll right center;}.yui-skin-sam .yui-pv .yui-pv-table .yui-dt-hd th a{color:#fff;font:bold 12px arial;}.yui-skin-sam .yui-pv .yui-pv-table .yui-dt-hd th.yui-dt-asc,.yui-skin-sam .yui-pv .yui-pv-table .yui-dt-hd th.yui-dt-desc{background:#333;}.yui-skin-sam .yui-pv-chartcontainer{padding:0 10px;}.yui-skin-sam .yui-pv-chart{height:250px;clear:right;margin:5px 0 0 0;color:#fff;}.yui-skin-sam .yui-pv-chartlegend div{float:right;margin:0 0 0 10px;_width:250px;}.yui-skin-sam .yui-pv-chartlegend dl{border:1px solid #999;padding:.2em 0 .2em .5em;zoom:1;margin:5px 0;}.yui-skin-sam .yui-pv-chartlegend dt{float:left;display:block;height:.7em;width:.7em;padding:0;}.yui-skin-sam .yui-pv-chartlegend dd{float:left;display:block;color:#fff;margin:0 1em 0 .5em;padding:0;font:11px arial;}.yui-skin-sam .yui-pv-minimized{height:35px;}.yui-skin-sam .yui-pv-minimized .bd{top:-3000px;}.yui-skin-sam .yui-pv-minimized .hd a.yui-pv-refresh{display:none;} +.yui-pb-bar,.yui-pb-mask{width:100%;height:100%;}.yui-pb{position:relative;top:0;left:0;width:200px;height:20px;padding:0;border:none;margin:0;text-align:left;}.yui-pb-mask{position:absolute;top:0;left:0;z-index:2;}.yui-pb-mask div{width:50%;height:50%;background-repeat:no-repeat;padding:0;position:absolute;}.yui-pb-tl{background-position:top left;}.yui-pb-tr{background-position:top right;left:50%;}.yui-pb-bl{background-position:bottom left;top:50%;}.yui-pb-br{background-position:bottom right;left:50%;top:50%;}.yui-pb-bar{margin:0;position:absolute;left:0;top:0;z-index:1;}.yui-pb-ltr .yui-pb-bar{_position:static;}.yui-pb-rtl .yui-pb-bar{background-position:right;}.yui-pb-btt .yui-pb-bar{background-position:left bottom;}.yui-pb-bar{background-color:blue;}.yui-pb{border:thin solid #808080;}.yui-skin-sam .yui-pb{background-color:transparent;border:solid #808080;border-width:1px 0;}.yui-skin-sam .yui-pb-rtl,.yui-skin-sam .yui-pb-ltr{background-image:url(back-h.png);background-repeat:repeat-x;}.yui-skin-sam .yui-pb-ttb,.yui-skin-sam .yui-pb-btt{background-image:url(back-v.png);background-repeat:repeat-y;}.yui-skin-sam .yui-pb-bar{background-color:transparent;}.yui-skin-sam .yui-pb-ltr .yui-pb-bar,.yui-skin-sam .yui-pb-rtl .yui-pb-bar{background-image:url(bar-h.png);background-repeat:repeat-x;}.yui-skin-sam .yui-pb-ttb .yui-pb-bar,.yui-skin-sam .yui-pb-btt .yui-pb-bar{background-image:url(bar-v.png);background-repeat:repeat-y;}.yui-skin-sam .yui-pb-mask{border:solid #808080;border-width:0 1px;margin:0 -1px;}.yui-skin-sam .yui-pb-caption{color:#000;text-align:center;margin:0 auto;}.yui-skin-sam .yui-pb-range{color:#a6a6a6;} +.yui-resize{position:relative;zoom:1;z-index:0;}.yui-resize-wrap{zoom:1;}.yui-draggable{cursor:move;}.yui-resize .yui-resize-handle{position:absolute;z-index:1;font-size:0;margin:0;padding:0;zoom:1;height:1px;width:1px;}.yui-resize .yui-resize-handle-br{height:5px;width:5px;bottom:0;right:0;cursor:se-resize;z-index:2;zoom:1;}.yui-resize .yui-resize-handle-bl{height:5px;width:5px;bottom:0;left:0;cursor:sw-resize;z-index:2;zoom:1;}.yui-resize .yui-resize-handle-tl{height:5px;width:5px;top:0;left:0;cursor:nw-resize;z-index:2;zoom:1;}.yui-resize .yui-resize-handle-tr{height:5px;width:5px;top:0;right:0;cursor:ne-resize;z-index:2;zoom:1;}.yui-resize .yui-resize-handle-r{width:5px;height:100%;top:0;right:0;cursor:e-resize;zoom:1;}.yui-resize .yui-resize-handle-l{height:100%;width:5px;top:0;left:0;cursor:w-resize;zoom:1;}.yui-resize .yui-resize-handle-b{width:100%;height:5px;bottom:0;right:0;cursor:s-resize;zoom:1;}.yui-resize .yui-resize-handle-t{width:100%;height:5px;top:0;right:0;cursor:n-resize;zoom:1;}.yui-resize-proxy{position:absolute;border:1px dashed #000;visibility:hidden;z-index:1000;}.yui-resize-hover .yui-resize-handle,.yui-resize-hidden .yui-resize-handle{opacity:0;filter:alpha(opacity=0);}.yui-resize-ghost{opacity:.5;filter:alpha(opacity=50);}.yui-resize-knob .yui-resize-handle{height:6px;width:6px;}.yui-resize-knob .yui-resize-handle-tr{right:-3px;top:-3px;}.yui-resize-knob .yui-resize-handle-tl{left:-3px;top:-3px;}.yui-resize-knob .yui-resize-handle-bl{left:-3px;bottom:-3px;}.yui-resize-knob .yui-resize-handle-br{right:-3px;bottom:-3px;}.yui-resize-knob .yui-resize-handle-t{left:45%;top:-3px;}.yui-resize-knob .yui-resize-handle-r{right:-3px;top:45%;}.yui-resize-knob .yui-resize-handle-l{left:-3px;top:45%;}.yui-resize-knob .yui-resize-handle-b{left:45%;bottom:-3px;}.yui-resize-status{position:absolute;top:-999px;left:-999px;padding:2px;font-size:80%;display:none;zoom:1;z-index:9999;}.yui-resize-status strong,.yui-resize-status em{font-weight:normal;font-style:normal;padding:1px;zoom:1;}.yui-skin-sam .yui-resize .yui-resize-handle{background-color:#F2F2F2;zoom:1;}.yui-skin-sam .yui-resize .yui-resize-handle-active{background-color:#7D98B8;zoom:1;}.yui-skin-sam .yui-resize .yui-resize-handle-l,.yui-skin-sam .yui-resize .yui-resize-handle-r,.yui-skin-sam .yui-resize .yui-resize-handle-l-active,.yui-skin-sam .yui-resize .yui-resize-handle-r-active{height:100%;zoom:1;}.yui-skin-sam .yui-resize-knob .yui-resize-handle{border:1px solid #808080;}.yui-skin-sam .yui-resize-hover .yui-resize-handle-active{opacity:1;filter:alpha(opacity=100);}.yui-skin-sam .yui-resize-proxy{border:1px dashed #426FD9;}.yui-skin-sam .yui-resize-status{border:1px solid #A6982B;border-top:1px solid #D4C237;background-color:#FFEE69;color:#000;}.yui-skin-sam .yui-resize-status strong,.yui-skin-sam .yui-resize-status em{float:left;display:block;clear:both;padding:1px;text-align:center;}.yui-skin-sam .yui-resize .yui-resize-handle-inner-r,.yui-skin-sam .yui-resize .yui-resize-handle-inner-l{background:transparent url(layout_sprite.png) no-repeat 0 -5px;height:16px;width:5px;position:absolute;top:45%;}.yui-skin-sam .yui-resize .yui-resize-handle-inner-t,.yui-skin-sam .yui-resize .yui-resize-handle-inner-b{background:transparent url(layout_sprite.png) no-repeat -20px 0;height:5px;width:16px;position:absolute;left:50%;}.yui-skin-sam .yui-resize .yui-resize-handle-br{background-image:url(layout_sprite.png);background-repeat:no-repeat;background-position:-22px -62px;}.yui-skin-sam .yui-resize .yui-resize-handle-tr{background-image:url(layout_sprite.png);background-repeat:no-repeat;background-position:-22px -42px;}.yui-skin-sam .yui-resize .yui-resize-handle-tl{background-image:url(layout_sprite.png);background-repeat:no-repeat;background-position:-22px -82px;}.yui-skin-sam .yui-resize .yui-resize-handle-bl{background-image:url(layout_sprite.png);background-repeat:no-repeat;background-position:-22px -23px;}.yui-skin-sam .yui-resize-knob .yui-resize-handle-t,.yui-skin-sam .yui-resize-knob .yui-resize-handle-r,.yui-skin-sam .yui-resize-knob .yui-resize-handle-b,.yui-skin-sam .yui-resize-knob .yui-resize-handle-l,.yui-skin-sam .yui-resize-knob .yui-resize-handle-tl,.yui-skin-sam .yui-resize-knob .yui-resize-handle-tr,.yui-skin-sam .yui-resize-knob .yui-resize-handle-bl,.yui-skin-sam .yui-resize-knob .yui-resize-handle-br,.yui-skin-sam .yui-resize-knob .yui-resize-handle-inner-t,.yui-skin-sam .yui-resize-knob .yui-resize-handle-inner-r,.yui-skin-sam .yui-resize-knob .yui-resize-handle-inner-b,.yui-skin-sam .yui-resize-knob .yui-resize-handle-inner-l,.yui-skin-sam .yui-resize-knob .yui-resize-handle-inner-tl,.yui-skin-sam .yui-resize-knob .yui-resize-handle-inner-tr,.yui-skin-sam .yui-resize-knob .yui-resize-handle-inner-bl,.yui-skin-sam .yui-resize-knob .yui-resize-handle-inner-br{background-image:none;}.yui-skin-sam .yui-resize-knob .yui-resize-handle-l,.yui-skin-sam .yui-resize-knob .yui-resize-handle-r,.yui-skin-sam .yui-resize-knob .yui-resize-handle-l-active,.yui-skin-sam .yui-resize-knob .yui-resize-handle-r-active{height:6px;width:6px;}.yui-skin-sam .yui-resize-textarea .yui-resize-handle-r{right:-8px;}.yui-skin-sam .yui-resize-textarea .yui-resize-handle-b{bottom:-8px;}.yui-skin-sam .yui-resize-textarea .yui-resize-handle-br{right:-8px;bottom:-8px;} +.yui-busy{cursor:wait!important;}.yui-toolbar-container fieldset,.yui-editor-container fieldset{padding:0;margin:0;border:0;}.yui-toolbar-container legend{display:none;}.yui-skin-sam .yui-toolbar-container .yui-button button,.yui-skin-sam .yui-toolbar-container .yui-button a,.yui-skin-sam .yui-toolbar-container .yui-button a:visited{font-size:0;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-select button,.yui-skin-sam .yui-toolbar-container .yui-toolbar-select a,.yui-skin-sam .yui-toolbar-container .yui-toolbar-select a:visited,.yui-skin-sam .yui-toolbar-container .yui-toolbar-spinbutton button,.yui-skin-sam .yui-toolbar-container .yui-toolbar-spinbutton a,.yui-skin-sam .yui-toolbar-container .yui-toolbar-spinbutton a:visited{font-size:12px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-spinbutton a.up,.yui-skin-sam .yui-toolbar-container .yui-toolbar-spinbutton a.down{font-size:0;line-height:0;padding:0;}.yui-toolbar-container .yui-toolbar-subcont{padding:.25em 0;zoom:1;}.yui-toolbar-container-collapsed .yui-toolbar-subcont{display:none;}.yui-toolbar-container .yui-toolbar-subcont:after{display:block;clear:both;visibility:hidden;content:'.';height:0;}.yui-toolbar-container span.yui-toolbar-draghandle{cursor:move;border-left:1px solid #999;border-right:1px solid #999;overflow:hidden;text-indent:77777px;width:2px;height:20px;display:block;clear:none;float:left;margin:0 0 0 .2em;}.yui-toolbar-container .yui-toolbar-titlebar.draggable{cursor:move;}.yui-toolbar-container .yui-toolbar-titlebar{position:relative;}.yui-toolbar-container .yui-toolbar-titlebar h2{font-weight:bold;letter-spacing:0;border:none;color:#000;margin:0;padding:.2em;}.yui-toolbar-container .yui-toolbar-titlebar h2 a{text-decoration:none;color:#000;cursor:default;}.yui-toolbar-container.yui-toolbar-grouped span.yui-toolbar-draghandle{height:40px;}.yui-toolbar-container .yui-toolbar-group{float:left;margin-right:.5em;zoom:1;}.yui-toolbar-container .yui-toolbar-group:after{display:block;clear:both;visibility:hidden;content:'.';height:0;}.yui-toolbar-container .yui-toolbar-group h3{font-size:75%;padding:0 0 0 .25em;margin:0;}.yui-toolbar-container span.yui-toolbar-separator{width:2px;padding:0;height:18px;margin:.2em 0 .2em .1em;display:none;float:left;}.yui-toolbar-container.yui-toolbar-grouped span.yui-toolbar-separator{height:45px;*height:50px;}.yui-toolbar-container.yui-toolbar-grouped .yui-toolbar-group span.yui-toolbar-separator{height:18px;display:block;}.yui-toolbar-container ul li{margin:0;padding:0;list-style-type:none;}.yui-toolbar-container .yui-toolbar-nogrouplabels h3{display:none;}.yui-toolbar-container .yui-push-button,.yui-toolbar-container .yui-color-button,.yui-toolbar-container .yui-menu-button{position:relative;cursor:pointer;}.yui-toolbar-container .yui-button .first-child,.yui-toolbar-container .yui-button .first-child a{height:100%;width:100%;overflow:hidden;font-size:0;}.yui-toolbar-container .yui-button-disabled{cursor:default;}.yui-toolbar-container .yui-button-disabled .yui-toolbar-icon{opacity:.5;filter:alpha(opacity=50);}.yui-toolbar-container .yui-button-disabled .up,.yui-toolbar-container .yui-button-disabled .down{opacity:.5;filter:alpha(opacity=50);}.yui-toolbar-container .yui-button a{overflow:hidden;}.yui-toolbar-container .yui-toolbar-select .first-child a{cursor:pointer;}.yui-toolbar-fontname-arial{font-family:Arial;}.yui-toolbar-fontname-arial-black{font-family:Arial Black;}.yui-toolbar-fontname-comic-sans-ms{font-family:Comic Sans MS;}.yui-toolbar-fontname-courier-new{font-family:Courier New;}.yui-toolbar-fontname-times-new-roman{font-family:Times New Roman;}.yui-toolbar-fontname-verdana{font-family:Verdana;}.yui-toolbar-fontname-impact{font-family:Impact;}.yui-toolbar-fontname-lucida-console{font-family:Lucida Console;}.yui-toolbar-fontname-tahoma{font-family:Tahoma;}.yui-toolbar-fontname-trebuchet-ms{font-family:Trebuchet MS;}.yui-toolbar-container .yui-toolbar-spinbutton{position:relative;}.yui-toolbar-container .yui-toolbar-spinbutton .first-child a{z-index:0;opacity:1;}.yui-toolbar-container .yui-toolbar-spinbutton a.up,.yui-toolbar-container .yui-toolbar-spinbutton a.down{position:absolute;display:block;right:0;cursor:pointer;z-index:1;padding:0;margin:0;}.yui-toolbar-container .yui-overlay{position:absolute;}.yui-toolbar-container .yui-overlay ul li{margin:0;list-style-type:none;}.yui-toolbar-container{z-index:1;}.yui-editor-container .yui-editor-editable-container{position:relative;z-index:0;width:100%;}.yui-editor-container .yui-editor-masked{background-color:#CCC;height:100%;width:100%;position:absolute;top:0;left:0;opacity:.5;filter:alpha(opacity=50);}.yui-editor-container iframe{border:0;padding:0;margin:0;zoom:1;display:block;}.yui-editor-container .yui-editor-editable{padding:0;margin:0;}.yui-editor-container .dompath{font-size:85%;}.yui-editor-panel .hd{text-align:left;position:relative;}.yui-editor-panel .hd h3{font-weight:bold;padding:.25em 0 .25em .25em;margin:0;}.yui-editor-panel .bd{width:100%;zoom:1;position:relative;}.yui-editor-panel .bd div.yui-editor-body-cont{padding:.25em .1em;zoom:1;}.yui-editor-panel .bd .gecko form{overflow:auto;}.yui-editor-panel .bd div.yui-editor-body-cont:after{display:block;clear:both;visibility:hidden;content:'.';height:0;}.yui-editor-panel .ft{text-align:right;width:99%;float:left;clear:both;}.yui-editor-panel .ft span.tip{display:block;position:relative;padding:.5em .5em .5em 23px;text-align:left;zoom:1;}.yui-editor-panel label{clear:both;float:left;padding:0;width:100%;text-align:left;zoom:1;}.yui-editor-panel .gecko label{overflow:auto;}.yui-editor-panel label strong{float:left;width:6em;}.yui-editor-panel .removeLink{width:80%;text-align:right;}.yui-editor-panel label input{margin-left:.25em;float:left;}.yui-editor-panel .yui-toolbar-group{margin-bottom:.75em;}.yui-editor-panel .height-width{float:left;}.yui-editor-panel .height-width span{font-style:italic;display:block;float:left;overflow:visible;}.yui-editor-panel .height-width span.info{font-size:70%;margin-top:3px;float:none;} +.yui-editor-panel .yui-toolbar-bordersize,.yui-editor-panel .yui-toolbar-bordertype{font-size:75%;}.yui-editor-panel .yui-toolbar-container span.yui-toolbar-separator{border:none;}.yui-editor-panel .yui-toolbar-bordersize span a span,.yui-editor-panel .yui-toolbar-bordertype span a span{display:block;height:8px;left:4px;position:absolute;top:3px;_top:-5px;width:24px;text-indent:52px;font-size:0;}.yui-editor-panel .yui-toolbar-bordertype span a span.yui-toolbar-bordertype-solid{border-bottom:1px solid black;}.yui-editor-panel .yui-toolbar-bordertype span a span.yui-toolbar-bordertype-dotted{border-bottom:1px dotted black;}.yui-editor-panel .yui-toolbar-bordertype span a span.yui-toolbar-bordertype-dashed{border-bottom:1px dashed black;}.yui-editor-panel .yui-toolbar-bordersize span a span.yui-toolbar-bordersize-0{*top:0;text-indent:0;font-size:75%;}.yui-editor-panel .yui-toolbar-bordersize span a span.yui-toolbar-bordersize-1{border-bottom:1px solid black;}.yui-editor-panel .yui-toolbar-bordersize span a span.yui-toolbar-bordersize-2{border-bottom:2px solid black;}.yui-editor-panel .yui-toolbar-bordersize span a span.yui-toolbar-bordersize-3{top:2px;*top:-5px;border-bottom:3px solid black;}.yui-editor-panel .yui-toolbar-bordersize span a span.yui-toolbar-bordersize-4{top:1px;*top:-5px;border-bottom:4px solid black;}.yui-editor-panel .yui-toolbar-bordersize span a span.yui-toolbar-bordersize-5{top:1px;*top:-5px;border-bottom:5px solid black;}.yui-toolbar-container .yui-toolbar-bordersize-menu,.yui-toolbar-container .yui-toolbar-bordertype-menu{width:95px!important;}.yui-toolbar-bordersize-menu .yuimenuitemlabel,.yui-toolbar-bordertype-menu .yuimenuitemlabel,.yui-toolbar-bordersize-menu .yuimenuitemlabel,.yui-toolbar-bordertype-menu .yuimenuitemlabel:hover{margin:0 3px 7px 17px;}.yui-toolbar-bordersize-menu .yuimenuitemlabel .checkedindicator,.yui-toolbar-bordertype-menu .yuimenuitemlabel .checkedindicator{position:absolute;left:-12px;*top:14px;*left:0;}.yui-toolbar-bordersize-menu li.yui-toolbar-bordersize-1 a{border-bottom:1px solid black;height:14px;}.yui-toolbar-bordersize-menu li.yui-toolbar-bordersize-2 a{border-bottom:2px solid black;height:14px;}.yui-toolbar-bordersize-menu li.yui-toolbar-bordersize-3 a{border-bottom:3px solid black;height:14px;}.yui-toolbar-bordersize-menu li.yui-toolbar-bordersize-4 a{border-bottom:4px solid black;height:14px;}.yui-toolbar-bordersize-menu li.yui-toolbar-bordersize-5 a{border-bottom:5px solid black;height:14px;}.yui-toolbar-bordertype-menu li.yui-toolbar-bordertype-solid a{border-bottom:1px solid black;height:14px;}.yui-toolbar-bordertype-menu li.yui-toolbar-bordertype-dashed a{border-bottom:1px dashed black;height:14px;}.yui-toolbar-bordertype-menu li.yui-toolbar-bordertype-dotted a{border-bottom:1px dotted black;height:14px;}h2.yui-editor-skipheader,h3.yui-editor-skipheader{height:0;margin:0;padding:0;border:none;width:0;overflow:hidden;position:absolute;}.yui-toolbar-colors{width:133px;zoom:1;display:none;z-index:100;overflow:hidden;}.yui-toolbar-colors:after{display:block;clear:both;visibility:hidden;content:'.';height:0;}.yui-toolbar-colors a{height:9px;width:9px;float:left;display:block;overflow:hidden;text-indent:999px;margin:0;cursor:pointer;border:1px solid #F6F7EE;}.yui-toolbar-colors a:hover{border:1px solid black;}.yui-color-button-menu{overflow:visible;background-color:transparent;}.yui-toolbar-colors span{position:relative;display:block;padding:3px;overflow:hidden;float:left;width:100%;zoom:1;}.yui-toolbar-colors span:after{display:block;clear:both;visibility:hidden;content:'.';height:0;}.yui-toolbar-colors span em{height:35px;width:30px;float:left;display:block;overflow:hidden;text-indent:999px;margin:.75px;border:1px solid black;}.yui-toolbar-colors span strong{font-weight:normal;padding-left:3px;display:block;font-size:85%;float:left;width:65%;}.yui-toolbar-group-undoredo h3,.yui-toolbar-group-insertitem h3,.yui-toolbar-group-indentlist h3{width:68px;}.yui-toolbar-group-indentlist2 h3{width:122px;}.yui-toolbar-group-alignment h3{width:130px;}.yui-skin-sam .yui-editor-container{border:1px solid #808080;}.yui-skin-sam .yui-toolbar-container{zoom:1;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-titlebar{background:url(sprite.png) repeat-x 0 -200px;position:relative;}.yui-skin-sam .yui-editor-container .draggable .yui-toolbar-titlebar{cursor:move;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-titlebar h2{color:#000;font-weight:bold;margin:0;padding:.3em 1em;font-size:100%;text-align:left;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-group h3{color:#808080;font-size:75%;margin:1em 0 0;padding-bottom:0;padding-left:.25em;text-align:left;}.yui-toolbar-container span.yui-toolbar-separator{border:none;text-indent:33px;overflow:hidden;margin:0 .25em;}.yui-skin-sam .yui-toolbar-container{background-color:#F2F2F2;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-subcont{padding:0 1em .35em;border-bottom:1px solid #808080;}.yui-skin-sam .yui-toolbar-container-collapsed .yui-toolbar-titlebar{border-bottom:1px solid #808080;}.yui-skin-sam .yui-editor-container .visible .yui-menu-shadow,.yui-skin-sam .yui-editor-panel .visible .yui-menu-shadow{display:none;}.yui-skin-sam .yui-editor-container ul{list-style-type:none;margin:0;padding:0;}.yui-skin-sam .yui-editor-container ul li{list-style-type:none;margin:0;padding:0;}.yui-skin-sam .yui-toolbar-group ul li.yui-toolbar-groupitem{float:left;}.yui-skin-sam .yui-editor-container .dompath{background-color:#F2F2F2;border-top:1px solid #808080;color:#999;text-align:left;padding:.25em;}.yui-skin-sam .yui-toolbar-container .collapse{background:url(sprite.png) no-repeat 0 -400px;}.yui-skin-sam .yui-toolbar-container .collapsed{background:url(sprite.png) no-repeat 0 -350px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-titlebar span.collapse{cursor:pointer;position:absolute;top:4px;right:2px;display:block;overflow:hidden;height:15px;width:15px;text-indent:9999px;} +.yui-skin-sam .yui-toolbar-container .yui-push-button,.yui-skin-sam .yui-toolbar-container .yui-color-button,.yui-skin-sam .yui-toolbar-container .yui-menu-button{background:url(sprite.png) repeat-x 0 0;position:relative;display:block;height:22px;width:30px;_font-size:0;margin:0;border-color:#808080;color:#f2f2f2;border-style:solid;border-width:1px 0;zoom:1;}.yui-skin-sam .yui-toolbar-container .yui-push-button a,.yui-skin-sam .yui-toolbar-container .yui-color-button a,.yui-skin-sam .yui-toolbar-container .yui-menu-button a{padding-left:35px;height:20px;text-decoration:none;font-size:0;line-height:2;display:block;color:#000;overflow:hidden;white-space:nowrap;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-spinbutton a,.yui-skin-sam .yui-toolbar-container .yui-toolbar-select a{font-size:12px;}.yui-skin-sam .yui-toolbar-container .yui-push-button .first-child,.yui-skin-sam .yui-toolbar-container .yui-color-button .first-child,.yui-skin-sam .yui-toolbar-container .yui-menu-button .first-child{border-color:#808080;border-style:solid;border-width:0 1px;margin:0 -1px;display:block;position:relative;}.yui-skin-sam .yui-toolbar-container .yui-push-button-disabled .first-child,.yui-skin-sam .yui-toolbar-container .yui-color-button-disabled .first-child,.yui-skin-sam .yui-toolbar-container .yui-menu-button-disabled .first-child{border-color:#ccc;}.yui-skin-sam .yui-toolbar-container .yui-push-button-disabled a,.yui-skin-sam .yui-toolbar-container .yui-color-button-disabled a,.yui-skin-sam .yui-toolbar-container .yui-menu-button-disabled a{color:#A6A6A6;cursor:default;}.yui-skin-sam .yui-toolbar-container .yui-push-button-disabled,.yui-skin-sam .yui-toolbar-container .yui-color-button-disabled,.yui-skin-sam .yui-toolbar-container .yui-menu-button-disabled{border-color:#ccc;}.yui-skin-sam .yui-toolbar-container .yui-button .first-child{*left:0;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-fontname{width:135px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-heading{width:92px;}.yui-skin-sam .yui-toolbar-container .yui-button-hover{background:url(sprite.png) repeat-x 0 -1300px;border-color:#808080;}.yui-skin-sam .yui-toolbar-container .yui-button-selected{background:url(sprite.png) repeat-x 0 -1700px;border-color:#808080;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-nogrouplabels h3{display:none;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-nogrouplabels .yui-toolbar-group{margin-top:.75em;}.yui-skin-sam .yui-toolbar-container .yui-push-button span.yui-toolbar-icon,.yui-skin-sam .yui-toolbar-container .yui-color-button span.yui-toolbar-icon,.yui-skin-sam .yui-toolbar-container .yui-menu-button span.yui-toolbar-icon{display:block;position:absolute;top:2px;height:18px;width:18px;overflow:hidden;background:url(editor-sprite.gif) no-repeat 30px 30px;}.yui-skin-sam .yui-toolbar-container .yui-button-selected span.yui-toolbar-icon,.yui-skin-sam .yui-toolbar-container .yui-button-hover span.yui-toolbar-icon{background-image:url(editor-sprite-active.gif);}.yui-skin-sam .yui-toolbar-container .visible .yuimenuitemlabel{cursor:pointer;color:#000;*position:relative;}.yui-skin-sam .yui-toolbar-container .yui-button-menu{background-color:#fff;}.yui-skin-sam .yui-toolbar-container .yui-button-menu .yui-menu-body-scrolled{position:relative;}.yui-skin-sam div.yuimenu li.selected{background-color:#B3D4FF;}.yui-skin-sam div.yuimenu li.selected a.selected{color:#000;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-bold span.yui-toolbar-icon{background-position:0 0;left:5px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-strikethrough span.yui-toolbar-icon{background-position:0 -108px;left:5px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-italic span.yui-toolbar-icon{background-position:0 -36px;left:5px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-undo span.yui-toolbar-icon{background-position:0 -1326px;left:5px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-redo span.yui-toolbar-icon{background-position:0 -1355px;left:5px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-underline span.yui-toolbar-icon{background-position:0 -72px;left:5px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-subscript span.yui-toolbar-icon{background-position:0 -180px;left:5px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-superscript span.yui-toolbar-icon{background-position:0 -144px;left:5px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-forecolor span.yui-toolbar-icon{background-position:0 -216px;left:5px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-backcolor span.yui-toolbar-icon{background-position:0 -288px;left:5px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-justifyleft span.yui-toolbar-icon{background-position:0 -324px;left:5px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-justifycenter span.yui-toolbar-icon{background-position:0 -360px;left:5px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-justifyright span.yui-toolbar-icon{background-position:0 -396px;left:5px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-justifyfull span.yui-toolbar-icon{background-position:0 -432px;left:5px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-indent span.yui-toolbar-icon{background-position:0 -720px;left:5px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-outdent span.yui-toolbar-icon{background-position:0 -684px;left:5px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-createlink span.yui-toolbar-icon{background-position:0 -792px;left:5px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-insertimage span.yui-toolbar-icon{background-position:1px -756px;left:5px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-left span.yui-toolbar-icon{background-position:0 -972px;left:5px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-right span.yui-toolbar-icon{background-position:0 -936px;left:5px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-inline span.yui-toolbar-icon{background-position:0 -900px;left:5px;} +.yui-skin-sam .yui-toolbar-container .yui-toolbar-block span.yui-toolbar-icon{background-position:0 -864px;left:5px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-bordercolor span.yui-toolbar-icon{background-position:0 -252px;left:5px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-removeformat span.yui-toolbar-icon{background-position:0 -1080px;left:5px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-hiddenelements span.yui-toolbar-icon{background-position:0 -1044px;left:5px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-insertunorderedlist span.yui-toolbar-icon{background-position:0 -468px;left:5px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-insertorderedlist span.yui-toolbar-icon{background-position:0 -504px;left:5px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-spinbutton,.yui-skin-sam .yui-toolbar-container .yui-toolbar-spinbutton .first-child{width:35px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-spinbutton .first-child a{padding-left:2px;text-align:left;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-spinbutton span.yui-toolbar-icon{display:none;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-spinbutton a.up,.yui-skin-sam .yui-toolbar-container .yui-toolbar-spinbutton a.down{right:2px;background:url(editor-sprite.gif) no-repeat 0 -1222px;overflow:hidden;height:6px;width:7px;min-height:0;padding:0;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-spinbutton a.up{top:2px;background-position:0 -1222px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-spinbutton a.down{bottom:2px;background-position:0 -1187px;}.yui-skin-sam .yui-toolbar-container select{height:22px;border:1px solid #808080;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-select .first-child a{padding-left:5px;text-align:left;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-select span.yui-toolbar-icon{background:url(editor-sprite.gif) no-repeat 0 -1144px;overflow:hidden;right:-2px;top:0;height:20px;}.yui-skin-sam .yui-editor-panel .yui-color-button-menu .bd{background-color:transparent;border:none;width:135px;}.yui-skin-sam .yui-color-button-menu .yui-toolbar-colors{border:1px solid #808080;}.yui-skin-sam .yui-editor-panel{padding:0;margin:0;border:none;background-color:transparent;overflow:visible;position:absolute;}.yui-skin-sam .yui-editor-panel .hd{margin:10px 0 0;padding:0;border:none;}.yui-skin-sam .yui-editor-panel .hd h3{color:#000;border:1px solid #808080;background:url(sprite.png) repeat-x 0 -200px;width:99%;position:relative;margin:0;padding:3px 0 0 0;font-size:93%;text-indent:5px;height:20px;}.yui-skin-sam .yui-editor-panel .bd{background-color:#F2F2F2;border-left:1px solid #808080;border-right:1px solid #808080;width:99%;margin:0;padding:0;overflow:visible;}.yui-skin-sam .yui-editor-panel ul{list-style-type:none;margin:0;padding:0;}.yui-skin-sam .yui-editor-panel ul li{margin:0;padding:0;}.yui-skin-sam .yui-editor-panel .yui-toolbar-container .yui-toolbar-subcont{padding:0;border:none;margin-top:.35em;}.yui-skin-sam .yui-editor-panel .yui-toolbar-bordersize,.yui-skin-sam .yui-editor-panel .yui-toolbar-bordertype{width:50px;}.yui-skin-sam .yui-editor-panel label{display:block;float:none;padding:4px 0;margin-bottom:7px;}.yui-skin-sam .yui-editor-panel label strong{font-weight:normal;font-size:93%;text-align:right;padding-top:2px;}.yui-skin-sam .yui-editor-panel label input{width:75%;}.yui-skin-sam .yui-editor-panel .createlink_target,.yui-skin-sam .yui-editor-panel .insertimage_target{width:auto;margin-right:5px;}.yui-skin-sam .yui-editor-panel .removeLink{width:98%;}.yui-skin-sam .yui-editor-panel label input.warning{background-color:#FFEE69;}.yui-skin-sam .yui-editor-panel .yui-toolbar-group h3{color:#000;float:left;font-weight:normal;font-size:93%;margin:5px 0 0 0;padding:0 3px 0 0;text-align:right;}.yui-skin-sam .yui-editor-panel .height-width h3{margin:3px 0 0 10px;}.yui-skin-sam .yui-editor-panel .height-width{margin:3px 0 0 35px;*margin-left:14px;width:42%;*width:44%;}.yui-skin-sam .yui-editor-panel .yui-toolbar-group-border{width:190px;}.yui-skin-sam .yui-editor-panel .no-button .yui-toolbar-group-border{width:210px;}.yui-skin-sam .yui-editor-panel .yui-toolbar-group-padding{width:203px;_width:198px;}.yui-skin-sam .yui-editor-panel .no-button .yui-toolbar-group-padding{width:172px;}.yui-skin-sam .yui-editor-panel .yui-toolbar-group-padding h3{margin-left:25px;*margin-left:12px;}.yui-skin-sam .yui-editor-panel .yui-toolbar-group-textflow{width:182px;}.yui-skin-sam .yui-editor-panel .hd{background:none;}.yui-skin-sam .yui-editor-panel .ft{background-color:#F2F2F2;border:1px solid #808080;border-top:none;padding:0;margin:0 0 2px 0;}.yui-skin-sam .yui-editor-panel .hd span.close{background:url(sprite.png) no-repeat 0 -300px;cursor:pointer;display:block;height:16px;overflow:hidden;position:absolute;right:5px;text-indent:500px;top:2px;width:26px;}.yui-skin-sam .yui-editor-panel .ft span.tip{background-color:#EDF5FF;border-top:1px solid #808080;font-size:85%;}.yui-skin-sam .yui-editor-panel .ft span.tip strong{display:block;float:left;margin:0 2px 8px 0;}.yui-skin-sam .yui-editor-panel .ft span.tip span.icon{background:url(editor-sprite.gif) no-repeat 0 -1260px;display:block;height:20px;left:2px;position:absolute;top:8px;width:20px;}.yui-skin-sam .yui-editor-panel .ft span.tip span.icon-info{background-position:2px -1260px;}.yui-skin-sam .yui-editor-panel .ft span.tip span.icon-warn{background-position:2px -1296px;}.yui-skin-sam .yui-editor-panel .hd span.knob{position:absolute;height:10px;width:28px;top:-10px;left:25px;text-indent:9999px;overflow:hidden;background:url(editor-knob.gif) no-repeat 0 0;}.yui-skin-sam .yui-editor-panel .yui-toolbar-container{float:left;width:100%;background-image:none;border:none;}.yui-skin-sam .yui-editor-panel .yui-toolbar-container .bd{background-color:#fff;}.yui-editor-blankimage{background-image:url(blankimage.png);}.yui-skin-sam .yui-editor-container .yui-resize-handle-br{height:11px;width:11px;background-position:-20px -60px;background-color:transparent;} +.yui-h-slider,.yui-v-slider,.yui-region-slider{position:relative;}.yui-h-slider .yui-slider-thumb,.yui-v-slider .yui-slider-thumb,.yui-region-slider .yui-slider-thumb{position:absolute;cursor:default;}.yui-skin-sam .yui-h-slider{background:url(bg-h.gif) no-repeat 5px 0;height:28px;width:228px;}.yui-skin-sam .yui-h-slider .yui-slider-thumb{top:4px;}.yui-skin-sam .yui-v-slider{background:url(bg-v.gif) no-repeat 12px 0;height:228px;width:48px;}.yui-skin-sam .yui-region-slider{height:228px;width:228px;} +.yui-navset .yui-nav li,.yui-navset .yui-navset-top .yui-nav li,.yui-navset .yui-navset-bottom .yui-nav li{margin:0 .5em 0 0;}.yui-navset-left .yui-nav li,.yui-navset-right .yui-nav li{margin:0 0 .5em;}.yui-navset .yui-content .yui-hidden{border:0;height:0;width:0;padding:0;position:absolute;left:-999999px;overflow:hidden;visibility:hidden;}.yui-navset .yui-navset-left .yui-nav,.yui-navset .yui-navset-right .yui-nav,.yui-navset-left .yui-nav,.yui-navset-right .yui-nav{width:6em;}.yui-navset-top .yui-nav,.yui-navset-bottom .yui-nav{width:auto;}.yui-navset .yui-navset-left,.yui-navset-left{padding:0 0 0 6em;}.yui-navset-right{padding:0 6em 0 0;}.yui-navset-top,.yui-navset-bottom{padding:auto;}.yui-nav,.yui-nav li{margin:0;padding:0;list-style:none;}.yui-navset li em{font-style:normal;}.yui-navset{position:relative;zoom:1;}.yui-navset .yui-content,.yui-navset .yui-content div{zoom:1;}.yui-navset .yui-content:after{content:'';display:block;clear:both;}.yui-navset .yui-nav li,.yui-navset .yui-navset-top .yui-nav li,.yui-navset .yui-navset-bottom .yui-nav li{display:inline-block;display:-moz-inline-stack;*display:inline;vertical-align:bottom;cursor:pointer;zoom:1;}.yui-navset-left .yui-nav li,.yui-navset-right .yui-nav li{display:block;}.yui-navset .yui-nav a{position:relative;}.yui-navset .yui-nav li a,.yui-navset-top .yui-nav li a,.yui-navset-bottom .yui-nav li a{display:block;display:inline-block;vertical-align:bottom;zoom:1;}.yui-navset-left .yui-nav li a,.yui-navset-right .yui-nav li a{display:block;}.yui-navset-bottom .yui-nav li a{vertical-align:text-top;}.yui-navset .yui-nav li a em,.yui-navset-top .yui-nav li a em,.yui-navset-bottom .yui-nav li a em{display:block;}.yui-navset .yui-navset-left .yui-nav,.yui-navset .yui-navset-right .yui-nav,.yui-navset-left .yui-nav,.yui-navset-right .yui-nav{position:absolute;z-index:1;}.yui-navset-top .yui-nav,.yui-navset-bottom .yui-nav{position:static;}.yui-navset .yui-navset-left .yui-nav,.yui-navset-left .yui-nav{left:0;right:auto;}.yui-navset .yui-navset-right .yui-nav,.yui-navset-right .yui-nav{right:0;left:auto;}.yui-skin-sam .yui-navset .yui-nav,.yui-skin-sam .yui-navset .yui-navset-top .yui-nav{border:solid #2647a0;border-width:0 0 5px;zoom:1;}.yui-skin-sam .yui-navset .yui-nav li,.yui-skin-sam .yui-navset .yui-navset-top .yui-nav li{margin:0 .16em 0 0;padding:1px 0 0;zoom:1;}.yui-skin-sam .yui-navset .yui-nav .selected,.yui-skin-sam .yui-navset .yui-navset-top .yui-nav .selected{margin:0 .16em -1px 0;}.yui-skin-sam .yui-navset .yui-nav a,.yui-skin-sam .yui-navset .yui-navset-top .yui-nav a{background:#d8d8d8 url(sprite.png) repeat-x;border:solid #a3a3a3;border-width:0 1px;color:#000;position:relative;text-decoration:none;}.yui-skin-sam .yui-navset .yui-nav a em,.yui-skin-sam .yui-navset .yui-navset-top .yui-nav a em{border:solid #a3a3a3;border-width:1px 0 0;cursor:hand;padding:.25em .75em;left:0;right:0;bottom:0;top:-1px;position:relative;}.yui-skin-sam .yui-navset .yui-nav .selected a,.yui-skin-sam .yui-navset .yui-nav .selected a:focus,.yui-skin-sam .yui-navset .yui-nav .selected a:hover{background:#2647a0 url(sprite.png) repeat-x left -1400px;color:#fff;}.yui-skin-sam .yui-navset .yui-nav a:hover,.yui-skin-sam .yui-navset .yui-nav a:focus{background:#bfdaff url(sprite.png) repeat-x left -1300px;outline:0;}.yui-skin-sam .yui-navset .yui-nav .selected a em{padding:.35em .75em;}.yui-skin-sam .yui-navset .yui-nav .selected a,.yui-skin-sam .yui-navset .yui-nav .selected a em{border-color:#243356;}.yui-skin-sam .yui-navset .yui-content{background:#edf5ff;}.yui-skin-sam .yui-navset .yui-content,.yui-skin-sam .yui-navset .yui-navset-top .yui-content{border:1px solid #808080;border-top-color:#243356;padding:.25em .5em;}.yui-skin-sam .yui-navset-left .yui-nav,.yui-skin-sam .yui-navset .yui-navset-left .yui-nav,.yui-skin-sam .yui-navset .yui-navset-right .yui-nav,.yui-skin-sam .yui-navset-right .yui-nav{border-width:0 5px 0 0;Xposition:absolute;top:0;bottom:0;}.yui-skin-sam .yui-navset .yui-navset-right .yui-nav,.yui-skin-sam .yui-navset-right .yui-nav{border-width:0 0 0 5px;}.yui-skin-sam .yui-navset-left .yui-nav li,.yui-skin-sam .yui-navset .yui-navset-left .yui-nav li,.yui-skin-sam .yui-navset-right .yui-nav li{margin:0 0 .16em;padding:0 0 0 1px;}.yui-skin-sam .yui-navset-right .yui-nav li{padding:0 1px 0 0;}.yui-skin-sam .yui-navset-left .yui-nav .selected,.yui-skin-sam .yui-navset .yui-navset-left .yui-nav .selected{margin:0 -1px .16em 0;}.yui-skin-sam .yui-navset-right .yui-nav .selected{margin:0 0 .16em -1px;}.yui-skin-sam .yui-navset-left .yui-nav a,.yui-skin-sam .yui-navset-right .yui-nav a{border-width:1px 0;}.yui-skin-sam .yui-navset-left .yui-nav a em,.yui-skin-sam .yui-navset .yui-navset-left .yui-nav a em,.yui-skin-sam .yui-navset-right .yui-nav a em{border-width:0 0 0 1px;padding:.2em .75em;top:auto;left:-1px;}.yui-skin-sam .yui-navset-right .yui-nav a em{border-width:0 1px 0 0;left:auto;right:-1px;}.yui-skin-sam .yui-navset-left .yui-nav a,.yui-skin-sam .yui-navset-left .yui-nav .selected a,.yui-skin-sam .yui-navset-left .yui-nav a:hover,.yui-skin-sam .yui-navset-right .yui-nav a,.yui-skin-sam .yui-navset-right .yui-nav .selected a,.yui-skin-sam .yui-navset-right .yui-nav a:hover,.yui-skin-sam .yui-navset-bottom .yui-nav a,.yui-skin-sam .yui-navset-bottom .yui-nav .selected a,.yui-skin-sam .yui-navset-bottom .yui-nav a:hover{background-image:none;}.yui-skin-sam .yui-navset-left .yui-content{border:1px solid #808080;border-left-color:#243356;}.yui-skin-sam .yui-navset-bottom .yui-nav,.yui-skin-sam .yui-navset .yui-navset-bottom .yui-nav{border-width:5px 0 0;}.yui-skin-sam .yui-navset .yui-navset-bottom .yui-nav .selected,.yui-skin-sam .yui-navset-bottom .yui-nav .selected{margin:-1px .16em 0 0;}.yui-skin-sam .yui-navset .yui-navset-bottom .yui-nav li,.yui-skin-sam .yui-navset-bottom .yui-nav li{padding:0 0 1px 0;vertical-align:top;}.yui-skin-sam .yui-navset .yui-navset-bottom .yui-nav a em,.yui-skin-sam .yui-navset-bottom .yui-nav a em{border-width:0 0 1px;top:auto;bottom:-1px;} +.yui-skin-sam .yui-navset-bottom .yui-content,.yui-skin-sam .yui-navset .yui-navset-bottom .yui-content{border:1px solid #808080;border-bottom-color:#243356;} +table.ygtvtable{margin-bottom:0;border:none;border-collapse:collapse;}td.ygtvcell{border:none;padding:0;}a.ygtvspacer{text-decoration:none;outline-style:none;display:block;}.ygtvtn{width:18px;height:22px;background:url(treeview-sprite.gif) 0 -5600px no-repeat;cursor:pointer;}.ygtvtm{width:18px;height:22px;cursor:pointer;background:url(treeview-sprite.gif) 0 -4000px no-repeat;}.ygtvtmh,.ygtvtmhh{width:18px;height:22px;cursor:pointer;background:url(treeview-sprite.gif) 0 -4800px no-repeat;}.ygtvtp{width:18px;height:22px;cursor:pointer;background:url(treeview-sprite.gif) 0 -6400px no-repeat;}.ygtvtph,.ygtvtphh{width:18px;height:22px;cursor:pointer;background:url(treeview-sprite.gif) 0 -7200px no-repeat;}.ygtvln{width:18px;height:22px;background:url(treeview-sprite.gif) 0 -1600px no-repeat;cursor:pointer;}.ygtvlm{width:18px;height:22px;cursor:pointer;background:url(treeview-sprite.gif) 0 0 no-repeat;}.ygtvlmh,.ygtvlmhh{width:18px;height:22px;cursor:pointer;background:url(treeview-sprite.gif) 0 -800px no-repeat;}.ygtvlp{width:18px;height:22px;cursor:pointer;background:url(treeview-sprite.gif) 0 -2400px no-repeat;}.ygtvlph,.ygtvlphh{width:18px;height:22px;cursor:pointer;background:url(treeview-sprite.gif) 0 -3200px no-repeat;cursor:pointer;}.ygtvloading{width:18px;height:22px;background:url(treeview-loading.gif) 0 0 no-repeat;}.ygtvdepthcell{width:18px;height:22px;background:url(treeview-sprite.gif) 0 -8000px no-repeat;}.ygtvblankdepthcell{width:18px;height:22px;}* html .ygtvchildren{height:2%;}.ygtvlabel,.ygtvlabel:link,.ygtvlabel:visited,.ygtvlabel:hover{margin-left:2px;text-decoration:none;background-color:white;cursor:pointer;}.ygtvcontent{cursor:default;}.ygtvspacer{height:22px;width:18px;}.ygtvfocus{background-color:#c0e0e0;border:none;}.ygtvfocus .ygtvlabel,.ygtvfocus .ygtvlabel:link,.ygtvfocus .ygtvlabel:visited,.ygtvfocus .ygtvlabel:hover{background-color:#c0e0e0;}.ygtvfocus a{outline-style:none;}.ygtvok{width:18px;height:22px;background:url(treeview-sprite.gif) 0 -8800px no-repeat;}.ygtvok:hover{background:url(treeview-sprite.gif) 0 -8844px no-repeat;}.ygtvcancel{width:18px;height:22px;background:url(treeview-sprite.gif) 0 -8822px no-repeat;}.ygtvcancel:hover{background:url(treeview-sprite.gif) 0 -8866px no-repeat;}.ygtv-label-editor{background-color:#f2f2f2;border:1px solid silver;position:absolute;display:none;overflow:hidden;margin:auto;z-index:9000;}.ygtv-edit-TextNode{width:190px;}.ygtv-edit-TextNode .ygtvcancel,.ygtv-edit-TextNode .ygtvok{border:none;}.ygtv-edit-TextNode .ygtv-button-container{float:right;}.ygtv-edit-TextNode .ygtv-input input{width:140px;}.ygtv-edit-DateNode .ygtvcancel{border:none;}.ygtv-edit-DateNode .ygtvok{display:none;}.ygtv-edit-DateNode .ygtv-button-container{text-align:right;margin:auto;}.ygtv-highlight .ygtv-highlight1,.ygtv-highlight .ygtv-highlight1 .ygtvlabel{background-color:blue;color:white;}.ygtv-highlight .ygtv-highlight2,.ygtv-highlight .ygtv-highlight2 .ygtvlabel{background-color:silver;}.ygtv-highlight .ygtv-highlight0 .ygtvfocus .ygtvlabel,.ygtv-highlight .ygtv-highlight1 .ygtvfocus .ygtvlabel,.ygtv-highlight .ygtv-highlight2 .ygtvfocus .ygtvlabel{background-color:#c0e0e0;}.ygtv-highlight .ygtvcontent{padding-right:1em;}.ygtv-checkbox .ygtv-highlight0 .ygtvcontent{padding-left:1em;background:url(check0.gif) no-repeat;}.ygtv-checkbox .ygtv-highlight0 .ygtvfocus.ygtvcontent,.ygtv-checkbox .ygtv-highlight1 .ygtvfocus.ygtvcontent,.ygtv-checkbox .ygtv-highlight2 .ygtvfocus.ygtvcontent{background-color:#c0e0e0;}.ygtv-checkbox .ygtv-highlight1 .ygtvcontent{padding-left:1em;background:url(check1.gif) no-repeat;}.ygtv-checkbox .ygtv-highlight2 .ygtvcontent{padding-left:1em;background:url(check2.gif) no-repeat;} + diff --git a/include/javascript/yui/build/assets/skins/sam/slider.css b/include/javascript/yui/build/assets/skins/sam/slider.css new file mode 100644 index 00000000..9450e3be --- /dev/null +++ b/include/javascript/yui/build/assets/skins/sam/slider.css @@ -0,0 +1,7 @@ +/* +Copyright (c) 2009, Yahoo! Inc. All rights reserved. +Code licensed under the BSD License: +http://developer.yahoo.net/yui/license.txt +version: 2.8.0r4 +*/ +.yui-h-slider,.yui-v-slider,.yui-region-slider{position:relative;}.yui-h-slider .yui-slider-thumb,.yui-v-slider .yui-slider-thumb,.yui-region-slider .yui-slider-thumb{position:absolute;cursor:default;}.yui-skin-sam .yui-h-slider{background:url(bg-h.gif) no-repeat 5px 0;height:28px;width:228px;}.yui-skin-sam .yui-h-slider .yui-slider-thumb{top:4px;}.yui-skin-sam .yui-v-slider{background:url(bg-v.gif) no-repeat 12px 0;height:228px;width:48px;}.yui-skin-sam .yui-region-slider{height:228px;width:228px;} diff --git a/include/javascript/yui/build/assets/skins/sam/split-button-arrow-active.png b/include/javascript/yui/build/assets/skins/sam/split-button-arrow-active.png new file mode 100644 index 0000000000000000000000000000000000000000..fa58c5030e76082c84e38342cf6722c723ad2fd2 GIT binary patch literal 280 zcmV+z0q6dSP)N~-|K;%i-0c73 z@c-iO|KRQa-|hd~QeFE1003M`L_t(|+U&?l5`sVg1i`WZK}Epr|6dhmytLs92=mel z9uoULP6;mwyM%qhIpHzkHQ|(SNO(*5TD8?y@wq9xG<+26t_AN^`$=39HtEMPCOjwP e%l`;(0R{kdKn;SADLBOd00006$Gh9E#3p9{H-P6S}q~camLV^=3&tj%#_Xa_x2_Xl57U&w-9pX85Q9;Im dv4Me^VIeE)+1pK9I)PdkJYD@<);T3K0RYcxInw|D literal 0 HcmV?d00001 diff --git a/include/javascript/yui/build/assets/skins/sam/split-button-arrow-focus.png b/include/javascript/yui/build/assets/skins/sam/split-button-arrow-focus.png new file mode 100644 index 0000000000000000000000000000000000000000..167d71eb721ba9b85c6601f9077d5c39faa4ebd2 GIT binary patch literal 185 zcmeAS@N?(olHy`uVBq!ia0vp^0zhoU!3-pmJXhxdDVB6cUq=RpYd5a=M;HP5k|nMY zCBgY=CFO}lsSJ)O`AMk?p1FzXsX?iUDV2pMQ*D5XI0Jk_Tx)0S05bpo|DSu#^)isf zToU9L{Qp10^;5h+0~ypkT^vIyZY3ooII;39W@>hC5M-JVa^Poyu7TYlo?{mkWE>b9 b7?>Frva+7N-L$0>sD;7P)z4*}Q$iB}D9ShR literal 0 HcmV?d00001 diff --git a/include/javascript/yui/build/assets/skins/sam/split-button-arrow-hover.png b/include/javascript/yui/build/assets/skins/sam/split-button-arrow-hover.png new file mode 100644 index 0000000000000000000000000000000000000000..167d71eb721ba9b85c6601f9077d5c39faa4ebd2 GIT binary patch literal 185 zcmeAS@N?(olHy`uVBq!ia0vp^0zhoU!3-pmJXhxdDVB6cUq=RpYd5a=M;HP5k|nMY zCBgY=CFO}lsSJ)O`AMk?p1FzXsX?iUDV2pMQ*D5XI0Jk_Tx)0S05bpo|DSu#^)isf zToU9L{Qp10^;5h+0~ypkT^vIyZY3ooII;39W@>hC5M-JVa^Poyu7TYlo?{mkWE>b9 b7?>Frva+7N-L$0>sD;7P)z4*}Q$iB}D9ShR literal 0 HcmV?d00001 diff --git a/include/javascript/yui/build/assets/skins/sam/split-button-arrow.png b/include/javascript/yui/build/assets/skins/sam/split-button-arrow.png new file mode 100644 index 0000000000000000000000000000000000000000..b33a93ff2dc2039bd24e4ea3b75ecf4bb3295f84 GIT binary patch literal 185 zcmeAS@N?(olHy`uVBq!ia0vp^0zhoU!3-pmJXhxdDVB6cUq=RpYd5a=M;HP5k|nMY zCBgY=CFO}lsSJ)O`AMk?p1FzXsX?iUDV2pMQ*D5XI0Jk_TpJo1fXx5@|JyBHuocK+ zE(!7r{{Nrh`YB$Zfeh-NE{-7;w~`VPoLG4lGc~(62r^9wIqgTe~DWM4f1sXSq literal 0 HcmV?d00001 diff --git a/include/javascript/yui/build/assets/skins/sam/sprite.png b/include/javascript/yui/build/assets/skins/sam/sprite.png new file mode 100644 index 0000000000000000000000000000000000000000..73634d6a22c4377060f49217b63f31b59fe22d51 GIT binary patch literal 3745 zcmd^C`B&0g_x=DPilSwrm^nqWnUq#eWm--*^_u07bqmX(Ow1J2va6=14V2nkPNmhY z>pbKX8aQGaYNeQ>fCJzZNCKiJFLv*Dec%7#eSXEiNvKM52X-1&Ks5Iy%nf@%RFP{l#ybSs9bX znx39!vqywNp;#-n3j!vm-TRDQt5)(2~rzV*2|SO56Nspdahr;-Zd(t^W+rlQGslR&tF(rp5JW>HfmW$*F;XK?Y-}yXP~PH%X`W*Y(S$r)L@{ zjk7{I|6FrR>(CIh;$1b5Hz{3Mz<9sg;aNH-5*-Nb{o31i0M}>f-(2&)zWrl|NG#ra zy0NgNbYC#dIlJ#$lc_OtJno%dgL$k5BoeQ{`qAG_A88ZZm-{BkTPN%HPSkCrS8SPA zQHhLkVaRw*@`G^hMGD1Q^X1_Xi zUWE&unOh&s6s4t^9W0!!NNs+kRa-}&?G2tI5Ei| zejK}{Mo&?kr#D=CT5Y)D+G2eC$+(Xbmo<5KwT;H9JRVQt6kiB|S(BD767-I5-vVVZ|jgA2T5P$4tIU|r9SQK>hzc#TLptZ8*+Ul!`b)`vCQ}P z0hEqYj2dd4I|$89%=kg3dSS=@!j73?$C|KXE!eRn>{tXwxF54ik7$E%T!y8j{|k)1 z|0-1@|HP&M%vr!x0X=~otH+L=#Rh1h+QDc80G$g#S5T;3Wa?uw)rmq)B~!I2)HVv$ zheC~~tkU=w?uOJa`|KOdlFD+4X+PI3BC!G6P_+QDhD?2h9n-)F^)NycjL;1ep@V8y zK=WZ}GYU&vm87H^7YMS6A#6ll6-;i$B>x}S>D=qd$wp5Ca+RKF28J6>O#9~?uCEbR zV!E6O(35W+bJVuow=(JdT9@WsK35qz*;(nCk6+uZQ|S<+Q;)6}hn$$J%lY$8&!Zl@ z7(Tmt<+R~vd;oV$`-DfhRyU>B`O*bq^MFK`f zM(ltBp!K{K%Q6z6g@0X_fX3fhdzw!CmKLGbeF3%ABbcSd4pb%PK)Q>ZN{m}iq*MU^ zxM?i~QzQK`7hUfbcN2hX2X0+juvm9nzPUMehR{OVa~68Q+1dHYo9+Y+O|)|Dc}zQM z%?(Bh3L3O0aDZ|nb4_$W&HKjTa_oHlO*1owj#<-i1-5@QzU0XFXM$kx3Cwg~^QP+9 zsOF!yv`D<#r^S9*`r=^+t*e)PKRMlg8alGe(0N-*3xH`jFbF4CDaePf-Lq$+ z_JWWJIAyF4s2>SbA<4EwIu+}0fd}D+BZ4k?f;_pHW%lXAcRWpjqXqXN?Y(dPcturr z8NGFTUYUPOY=32Sj;IN7?DQ+tKi)d|L}Z03^qwkv_FhMxWFvnDIn&tKSOpYwko}qb zxly;Wv{c{|$?2@E@u0sxwj=v&(D_$direR70z3VZANNd)Mx9HNDE8s|BH}l!AZrzd zQUalNCI^9DPg8GXDc;zn0{j8P(m;pYA%|$-PLFdbqP(Y2UU?AkI=Cj&yaJeTo5){2 zR}3k2c`yZ7sE~6te`R8pu+cC|F98?2En&wL%eLaM4+wu87Vo8qZ}}TsS`5BHT4nf= z0I(h=RP0)Bs!&=2l$ZO01e>p~WMKBWwdQk&*kDOd6)j3&?E7wsexnPlXU(O# zuljo1$*Bf4%F4=Zs(G77cyISv`6j5_hOg1kXw|5*Q_2cB!KH^O)fs88-5!20+s+A@ zt{=%a$}-0wlF2Srgt%-)iaGVVqRQvzwCDM7=d@ah>um|??C3nHmk}~l3Q6~;yOg(Tj}AGmP=BBZ6WFh3T>G>E_~0 zV=q;isVW)_KE+Y|5G3X?ue7353?5Jrb^K0XiJBt6gpfE1@hUtOKwlmL<#>et)jQMs zP9@s1sBK_iAkh1R_KwibXvVJJ`nAKzZNyYH-7 zhi$cO?>yczO?*90W))nk{q3pyW{0gCBL)WtA78*;DwF!O-=PU&ilrH~1OnlMf_K_@ zglJW`k*`nnNv?f(?QnKt!5LL{eekGbsROFm4>=Y1>vh^3t|_UmsHlj}RV&8f^y*%9 zeHoZIJ*7mCQu~?DuOj30)8c>lZSJ?4yU}K5is{N9i-OgZTs)lHW`>_HP0aa}n%6Yk zV6-vELYl1nb1J`y_TjCf)Bb@kbu>^|?YQ~eSEtlWr-L6L)BBdFN}-~~G|TOyFNRHu zii+S1UXuoR-?YKhD?gW4o%G??1oq*?i@(#X&(~#USBn-1ZB>ia1_jX(FY3A7@_uze zq%Q1mkV_LPTJS>Sp|wcxd-Z<5;Xk~~eP9N4qO@_{I&G6J(jvu2Hh#;nHCmD>tRw}o zDU{ymFf`QE6xcH3v|B*CS6+VY+K4!AXqTeok*2z8rG)wNbXu&Bnrfj9yimX_JXWiG z&19R>QY{kL|IM>pAHTC+hN6)Vc;Rkpv-< z^ob-bB1w@*QX`UJM3Nqnq(dZuh$IA&w3bLxCX%4UC79}psI0)>Vr)X+i2aoEI6>}f z8^&VE1|{8&lI}rWHb$+BLlCd(5wAjsS3$(9P$Frys+uj-aX-Q_PQfuw$#EI_|21-* z5TBMFPQ(JPC&`gyA}9;2nEFqdMPkPuV#mOk5qYfyp&ut?@Dno(k}@Bb;(yn( zzhaY<@5iXhwGuOnwIR+>4o308=v)P}oP$xe0GbIw^A*sKuVr*lSl2nKn23$2%Wxt_ zwFx6;%MbAaTB4Z5%z!Wz5KM0b^9_QzfMB|+F>}n%$G&w-RGl`sHbqp235x$P&5;k)YU@q zX~|W0i~~FFP(c5lWc2I#uITH5^p)tlV8!RdP9>4uKJAn2xd_I#4K1pNO?5X7eS$$g zh- z3`S&i*Iv?T3X*;?B0=v2-|IE^hO&gQTJLW{5jDf@y-#Ph^7@Q^F70D{FSTsU*EW4i=9hj%JltBYw_d$-48>? zj67G@+QG#0!q)P?`BuOGf9?&FMG;WsvPY65^mUaonrGoX-b8F za^G3nBtU5zoGYm>j(H>Y1+6GqIoRSXPk7}IEELd7aSKMHpI@$Yce!a3;6(Pgqj8z0 zFYS5p_vVr3*$;S`>A$)NBjbd!Bwi14|EVS+`9BbFad1CWY>!R+4|+`f{{R30 literal 0 HcmV?d00001 diff --git a/include/javascript/yui/build/assets/skins/sam/sprite.psd b/include/javascript/yui/build/assets/skins/sam/sprite.psd new file mode 100644 index 0000000000000000000000000000000000000000..fff2c3471308fed4c93ef4961ea1cd729b41bdca GIT binary patch literal 118162 zcmeHw2|yG_)^PRAa0+;!CWb_jV8ja;4!IPfAjk@dK}|H9F9`x7%3(M}-9+PVqMs)J zy2>uQ@yNy_my%?KjYd|Jc;wQ2L|F}Kj|doG02Kxph8dg{HZ@|`(%9%2yxr$ESZ2{>JlC6e=~WyQWT!y^^rC^Uq}bv&t`GlBilw4hZh zqGOiFr8_Q;i%&?N?o{)iFPt0`Vy8Pj;~nW9xgt1jX~OI^sd4kxJTX6J&GHz(Sf`*s z>uIa}S0$}Tic61nT$PlVoaVo3x>Iy)%HlYGa1*qflOqk1zI?jV4C3LqFmkSAa7t>N zqnE34N{qYbR7bC=t{y&9eLUPJJ4U7?JBG$Bc2xQ~dbqp$IC^;aD?R?r!ZVL&Rx-^bbyri%yRVfjbb&<2wcZmCE@_D3yo5m(LV;AAfiEX(YNdWJk_4 zjmVVPge9xHq~Yc7=?=`1rXdO0ISr_a*y!|VgHn-(?UW8JPfF_il$69kzB=bFO-WBl zTbi=MF?gP*V`OwpLNb9Rg%W}bDNS=DOqMX6)+pguCwy;}5gXH97b`MS6KR#l#<;~L z#wEoir>8-ED0S;2HpYKRN@`McdSLX56^RKk(WJ`VRwl;^6}dtz$uzf)pnXksdnWC~ z>j+Z2cUN(0_wo-;NlZzFx{eFQ)b5m26BqYWKrbUI#bPS&rJXPs8 zb?OukSEV!=Nw{v)nVpc9o|3w{t2}#q@Ur;WqpSP^LLnc=v=yld>2aUR8 z#e&z20BJ*jw(aAu6dFR;h-tBoY0)dYiKip{y~L9iP9(mss})*sWMubMD)tRYNxI@l zqxgp>r=>?H$Haw)1ZHF;#QKL!_4HGQczb(!P4x>2Q7UJ62D{Ht`b-U(8al&oW+>lT zL`F*E^>ta&6P9%Jr#jL}e7XuI!TLX$ngFeiHmN`mr!F{&C{e$KQE_Q0i5a8`213sd ze{M?h6rxJKJ4apAb5yB!=cpYq7bGX72YLv(bwYQJ^#l}aWn4%?d|VpD@t!)_!`laL zU%34ydrbA1?BU}DH{g7|CVP9j!>t52;C($Od-zSA?CGwY?5XsH+i$YB2i%?>fP-{= z+~J0>J_Pm#f4DupJUs$t`hl?eLOuB?J@}^w#qdv0zNC$aBczF7er!RzrC&|kbWQ9CQE}kGm zh>j1KcEwyG>o4&xP3eb-Up-&o*)L4&F&dWZ08N!#TTl=S}_=VB_HP(q&?oQ5-NTut~a1>@tc2Mg=xWmx*0Qaloj+ zCh0P<%P0;Q71$(QCUzOc0iyz&q|3xEqc~txV3Ty2*ku$4j0$X$E)%14aclNtcOTMsdKXz$WQ3vCAk97!|lj>9X!v>=~B~D?Bq{DJNMA zDz74IK_46f-bsm$E8|kh5{~Iku(Hv~F)ld<)*&XxPj^}{KXi&OUHmyV5g+3%!~*Rc66HJ<~9RX*u}ZIh0G6eoEs57Z@wd09qBgf2`5MCLQS#`FODvt zgn(&ousm%=Tx$C22uN%SL~xBwkA)SL)A-bN$N_9@LQHy~wbiucajOGi4W=uf7_2x; zPIsLf9Um7;*ZR56jhvm5ny@AX7AGabI-hB7Bs@eDqIVxZJ%Ox*b&VmbH&ar@I9Air z(jobHNp{Op7V}}Jxe0#ORy`&O>*11Sq^3r%?npG6fIt#N6p7N4M(@QUi2%`wu%-&u zLJ$W@w?~R#{aJckXkv7HJ4Fy4m>3ryml_C5a6~61&`qRpnwv;Atd=yiCM1i*#LU`@ z+-*Jn8tS2&LJ^LOY=ad^qVry=ig_{7i6F}NPc?KZP+g~D6s)~A?vW;uma%v~KhCa*hH?LegybbDFNmXQccb*&$hmVv z=8~|%u=xFn=%hHY`;v^D#*8C|4(L6OpIt|Et7+ocNLVh8n8Zy=)k7&r5aBZ-A}&2W z4!%4(zAD7{oxgR2F|xa1ykivVG>%)f589Ap`$#Uq3Y5-INQsZ89RKxlTTdAzyiSgu zl6ViWyK}|reC^GMU6zrS9v4fHQE@TpzedTwy#kVolC&p)=y>k#3Nqa>viE}a@$~90 zw71Vx9kiq^-2LWeAbX(uyUzuna|!iGz!asgPUQ)Lp$F~b)4c@v>7ws32>@1v!>|ay zVt>`Wa97dpsbIf`uDOH$1`pnu)n z^NJO*_iq=iuW*uXdci!$d*KI5=V3S!OmDSVF z$Mn@JB)>R?IGyvP<1`tw`QNsZwA+7k^^`|fTE$<4ok{H}6)B}+{H}zGbL5>V6$yon z)5yGjpf%ME+#tFEGz86tCj*!8rh7;}M*ZyQlRko8MTo|_NkLni`Ki&#X)B^rL5;AQ z`Y1+FpV9ENMe|WAiblyO4XuE8DvASl3|cLuQA0yQ>KIcOLa_{=hBt+W!V~tu?Be?f z^@UwA`E(Sv?eJ(y^(b9fUQb~w`hdC;&A5tn=hJa}#pP~63o z;D|(|q6Cx9 z4IoA*A2aF)=wWbMP#`=+lD0*BYD&fm9h5mJwqUE)xa5o^h+{Kr9!VY45r6~OHaa6c zB@A|5Oa=W;EFjQ)=)Z)()_h=sAwJtZ6);^TBM z=Fy4i^P}T+aCR|q5HD_3dU)FG`H>NeVLMWiprwe`32e1AC3Ve=#DsW}Q-k@!gIXi)&-Zw0Ll1U)(?ZAIj~P*O(-wg`13dxi2T(I>FE@khS) z{ySy%Tt`QVpCQhnF)LDm%gkH|>=_GN?}Ga^a3^M_uON6r_3*{ZiCadR-0)N&5Zn(E zcRcT&OvCW*$B8>ODH#M@Mrd9Un-ojjr@;NcD>I1T%Ok+OVP!&GCb-Xo+c_~KDFNK1 zhaH|27Y&V3L3rkz9v8C|-0tAENu3`R4DM+lRW|Vw_hN}V9V8IKqTrMjt7)A$y2MO? zy^H;P9cRa7k~zgGb74>A=+s!)@i=KkbTW)+e3?lsG_1=$tQ5^Zdi0cp>&Z##miMoJ ziq;u3^7{^4N6Zdf${y&KVKkHfr31J4Erbrg4t4<-J8;hLAT;0RcZ|tM zUC9Sgke3;V!Pr4#UaHh#eWqgidqF{W^4Aa*(5W6vv9M8X7Og3W*f}1 z&E7Nn)a)y>3ua|zjppX&BhAN~`DKeDmszj3{)hF))?Zm)wyqyEXpqw& zzd=t8N*MI&pnnYd*Pw3)l?-aO8D=xlCfMdVn+%&j+q`e{r44ISZ)+r`?gv)f^J$ga@t=3uMA;|9+d{QTfGgR=+c4gO*9^&wV6 z9vc!oBznl&Av=Z~8B#PvGt_>la_EyolZL)IbpO!rhN^~H40~+YtYNXkUK_S|*vVnn z?B({4+6UXm*#F6XpZ!<%Wy8&fj~^aBeA)0fhJQ4?V0i6_VI#aoJUwF7h#e!2jVK-| zANknG@R5llw~Wjk`Qylz2OfD~#shH=YCU>Y?in!yN(~VjMO*zFUbR5^}toZ*=0 z_z%ZZjHM#^~VJ@eSc#|}TH8vo$<@bPQL9~ghx#nvUr#M zxQ=vhFd)j)2 zdam>Q%v0?($t%w5ZLgoa?Y$$tH+rA&)=u@AnmYC4sg*v?J}>(0^eOTk?mO4_P2X?* z%=~8ht@AtT*X%#lKixmqzb0Tx!193o0jg=^r^QX%H|^SVr|HqtcTX=4bPRkk@SVWo zps_*GL3@HqAAj`m*vH>{ykf?L8Ovtm%(ywzeP-&+PiNi=_78p~_{$J^NLa|`kb+sm zW-XYteb&#RPNDIk2SRJZyuh%Zom~|ENO(;6hvBuq^ZDH?zdJR@X3o4h z+vk){*LvpMLheXEnc{_4~j5zU(>g=Qcd|CL^7730?E<9~6Ix`NN5q$G*J&<&sxsys~>Ovv%>?6YCyb_u9I$SHoWYV7>MF zo;o{F0eRl51?~a_v56J)Y zKd%3I|LEAGJC2Pww&io{&tLl-f3fBZ&6g{_yna0X__Y%+oVavy;mPx-o;p?V)ts-s z{W|pPli$qv=8JEqe|z*h|L=~R_C0<0%+xc7zW4tA)Bp4SzfTLM799G)=ZDYE`kl=` zH|^Z#g+YbK{~Pk(ug`~{KXc)U3+H}Z@Z(QK&lMH_6#J8kO=Q&2mYmHILVPU%RljOr5I6b#K;>s(-)1tKo!ZuIA^)q{h}; zo0~>8ebDUN{7uUDph32FwnOaf zh77l}vl~txcEkB7Lk&p)e~E@#LUH7B#tF%WGV-Aez5+7>3_isK0hMO(sRDmMF!_^1 z;S^@(7M51lgJ7ae*ONgqx#&3rF$zX5Q^?FL%q`92HlE-)RIV61Oldabsc3trm)3ij z58t}`;LJyzM?@W8?CF*I$8*6J>H~!fO5^JC zUOV~UjBE9wZyqxM1PTf!mg ze>J1hQ=Nh;pVWNuhx(|eG(mr@DZiz)c%|(XwEB2g*V2%95)pG5VyD?h-id)4Of7v!|ZQ#U` z+Uh6qSRJK8?0X5}h=S2PmQZw3++p~Z|tyL%bq zB7}hsfl<1F=1F@a9Mk+}QdK8vi|UPTDzVug2)C($5s-iSZ^E0vB) z;oJ~tr0*~tw7ny1Pv7Mox#;Gn@E|{P27V5}n}Hb;NjaF&9pzvila@oqh-omcvW~PN z3Hk@U9_0gllfHEDI|R?zBt<7Dghz!&5pRN@ksLxM3X9<$LIS`If5L<%p$N?gohO|~ zLZM(T(Czf17z?873OQGJV^K;@*~d?q1*<{ zi7{csSp#ktq#zmr$14Qy@;nLcl0?#Qd6A@@49f#B2r2xj$OHad$b7mXw?#zs>bO)# zB}peSBbm@f}5Du9~5K8)hLmsrm`Z(m#D~ITp#ogf0 zM_=V2gE6qbOVLvv3dp~2TB!bV^kp8s(|V`nF(kerVS1v}T&LCv)Klo&^Se8F^iJEI zmd%j(hJ@*zQa%LXn{hQ_d<@+dZwO_^$1t9%+lyfd-%6x~8&(G-T<UK9oLsZy!Ifx!+Ab-_5+F^`VBEtp)SAHe7>h5C`gV zSYQDvbZMBL-FKb>0;Mem#XN^EBQ5B`$(z6g-*eu)@14fyOU##^=LBCSL-OXs+<6ME zP}*YD2IYp<2C63x-b8oA;j2(LKSK-TfHOpyblD)D^hJ8DKtTy8Dk0Zas>dovGH^Fj zcLf+Lpj((hFbon$ncipDp^8t~aQ5~bk^_o<5pw7AY6S+i0bOlaOW#_6TL9*O@+SI5 zKyd}QG2kk|PfOpe@YVt>#^+PxOULKZGbM)lV#u)+s7oOMP*#>b4eI+_iRtMt!4W*-}a9W^|aJ3OWbr5O*uJF$~tU~&3X*fP6pGr^p z819FG4<$fFGw|USaHR9i`|zQ9eriFmuNu^h44|&pVYv5?f_@EQXgTkfav1Ot*022T zosYk*8tI)M0~_MERU4=kMv!a5$Rds}%`kdvpRehxbed?4BR6s1SzG8XHpzo1h{W=ON`ENzJ$vjgQfxC?+mx?)u!u$1t9%+lxVJrSFX!hCmIII<|#NZ0n?r-)Zaa z;4hI_k_+iSNDd?)-aQE19pUc8MN%3B7fGAEtzpSKxyaIYD=5vKq%Fp^p`{?)A{Qyq zuy(gipX4B;JqW1@{^ENRVtPW#)OR%^mdNxralpg@69?{X4p`CNkMxM-%ZK#3~&Vfma!%5W%j25ybPOBDFHf5*kZVTX0HIn7uh2A zJbRY?p8bwJ#eU9y#^$j(?7IVY8CD7sim!)e_7>EGhOL8|sHJsL%~r7$Y&q1(HCocE zP|`~Sa2Zq*gsYCLF*;racb(+jjG2QP4l|mA&4N!0wmg{hx&~`rPdeDrfdlaM>u_sC zTr)NYTpD1+m`zx5JuNBidXo^VYY0fYOFDqtCFHkDOuGfkG`oN-@)U8MD5vFVZ!HG# zKwoHtHOI?=W)0jGl6M=%No@kId$;U3#?7$An8cI1(eduX>*71*N2$<9qp^5>W$Kit zP-ZFZQg>ILbRVD3%~%@sh1VymjYLdu0keq!-@=DV*h;Xw2i@}?*d{q$rzCdYNeLQds%tvp=U!o%to0lp;*M#>~c%!6C$6*g4ObVk`X3kwF3r)EtvkRU-g( zZSrNvNmVQGqfX$5THuFT;76UnkJ?-Ev#@bmoxl&Zz>hkCA9Vsh)B->1YUE3h)8$%$ zAL{E&_{EyL!w!rU`(SL@Rg5k0>)9o^B>VLe%k+SVvP> zXG{tRU4&+F339&-wk=oao4^DwrB$CBt%LaMApSatzYgNVo4^FGFOC$?mzXa-&k3F@ z(l9-{Aq6NgqyVLd6o3;vS9*>m^=*aH7Gvn(;7QE5ICz5t-dCY+euhmtIN%IHT{fsp zkls3)9z4-HNDtn49i*}j(pyK<15QDDz$+;oQa9LhRhM8J482xMb#+x$3s`!UV>2G) zsuYz3QGqQgz`LqhQ^i%vz<{a(QnjLRWu;10UIrkpl4DI}rB=lQOtYpK^644^q~RyAu>Dy~9SUeXNtiXd0clr+QleF+DC+Hz1i0})82DM6|V z3^bRN=q-`7bcVR$2UT;Mww`Hg{sl_GG}m)Yid*%X#^y3?hMVh~nr?9oSi>|@@&MGd za-b0B8WGT^Xl-oNv}!SG0Jxz7%j;WtZ*3#f)L4Pd0ft{4x7r$U6Yq=L8WoymP1AWO zj;5v247?i&fE%?b9L4E^HtSQ8beCodl*Pv1ME?2V7$g$y;*BjRb{368fMh3+A1yB0sMlw zD!CeCwYK~hECWvb(TLhtOi?wE)hU33!djfb|hq*N|zRZm!NQN6N7+KH?nm zl;=LY&&|!n@kj->#I7NcZf>XXY0iyt83%~hJfHJ~BT1v8v~G;!S{0TBc!qFpvb49; z0O2wP5YGOdfPg4~a2-Vu&rRbIZEnaOU`G)qF$f|cDw1=vgcxqFE-qt88fycd<6LPP zE{uJq3g{RY65!%O=x||1*;f!sM>)Ejujj^}?s2rHc ztewKyGgC7AP&j_k7NM&pK+UDH=4N$uQ9&uT`lXC(ZdBJ-6%|~=Rz=Ottpun%1wvD# z<{A|MlmlQ@RIgUIv{YA?e+0nQqUvh3y0ZKf#IeK$MU`rG`Kf=GLLtlwE~?cRKcXL2 zto9=Mx8T~%yIRW$Z1%(MqKmt!ms$Bor%vtufeO;@t9>FMAVMnPs-P1|{8UmYOqpF3 zCd@9d=hz?EGwe4oW%k7YT!xl&Cd*$l*ct5O^a^5w*y(Hl>j#$)>j{@T>&i}IUD(G4 z;4-uv(r{z~mQ4MLld$~sADM`)WpA+6P;=!2a7iibAGcU;e(G7A^z0~eDM;rfn9RMi z%P`vWLFP|^^q+xNaE`qId0vE;aTQufDNMSSQT~&*BetWv{Wh!=9igO?`nQD1WFkuy zP?lmS*+5+#6!z$9g+aKi494j;Y}Qm(TU*vdMqo45ja%@&MMhwYhB6J--Y9D*BS6K? zTNvL^!8aL)t<U0HwQ25#YQFr`)SS%X{3 zYQf!di@PDKxZI=yjH;4gYHt!uaXAcLKmvC|ezU2eLR-RIP*-9`RjGxqK8)K+nBpHR zF)D2>VH(t}CFp!5mX#M5YcIE6z~>S1GHso7Z|lf@z0~nmM<(k+Lu!!cRcC8ClXYQt zyz8)L>&!2cbzx_Ib@0k$U1*GzmGQQM#>colTR{@5b1mzKN$CEyE*uQD8|32c{`$+h zkfd)%tqX}oV_#br5(^ZQb)kMKGWnP|VB&y@1HUc~bZ1>?597#Sz1D@qs;w5R3#(v4 zr4+37el6C8#J=!qyLBO%EG=M9vtO~t+5fPgvY)UY4A|AVSyK-apEpI)qi2}V*I zDmpEE4eEq1=|D^m8B`K|7F#CkLKYNUChJ0dR+4(G2|HV2_OWGT_cnGW>q2T7*~R`( z*RHa&`QUHNy08LFb1HhaE<7i(E~J)DdaVmsV5xV4SQlnueD=hNW5>>7oC#KbJjfkW z93}{`F5Cy+$5dyIaffAR@jhx@Na4eWb8~l68^U99eCF_BE*EX%K}L0k%f$y!CIt`6 zE}qHd4lw&DC_kKg<_vcL?<2nESe2_fbKn5CPqs5t1(}N=x0A^PV?vb4fuD9K-iCk@ zbU>4dwowzq%)T)#BWwT@!=o>0qnMYDQWL|YQCzfQK~$L6QDS0vG%7lJ0hfWp7_Xy1 z9s$EHfYsa<&I=s{6T@}OmW5pagSiZVGeFxOwT}1JdNIykU}6X`#$PRH18@WcC*T^b zmm=(|EzXu;DHyh_)yr%P#%o3ZguS%RC4e9MSI%K$#gjbNf7 zZ^f2DgDfF$1|QXqz+nn!0#ZA}qb-9NOCTHU439o-ZE0!!G!&_Gt=}FDc80~;0;aH- z+8Gv@6@B?-etsdCj1?AXztrZVLa;OZQeKF0AxOb?FfIgdAiXd*cQXLRg@wSgLhgOE zfm#}Zi`f8CfN{K&S{lAD+rFWYS{iN#Uuqz>oq1X6pq7T4MV#p1UPch;_R6Ij3rz4f z26Gdc;EmMMFyF^#(Nn>JJ`*RiO~i!&g)bd2ctz?plrk54S-Ni0z-?5k->m~D1h*BAc(b3@rbrSWCyUb z2$L8D5gfCW3$%n7fj&y5Gf87z@LJA?rlDl)(ut+vq(#9>C80yfIM@+O!+Zy4rE+h< zUZv8(?jUKf*7=hhoF^$KIosJCq?U&3CUJJmr1U-%j{epO%qGD}v&-3K zaK*E6Yz!OCzQFz-uBX{3_6atE4I6;V&~iw_i57RiWlO^r$?|Hl(49<0U!yj0cRCp@ z<+OhHPayMGU^1E56_!(r!b+fmw2zy#t?;czY(sbdt)KGleRM4i#SH|A)hgLQ;L3nq z-Ba5I3zmj?OPA(ROT(h2+q0KaTYs}{Z=A|a-$pGBzg?P(Yc?(YmRcIF-Es=!P3iDy z29}0->3eel+O#x}S{hcRbKA`!=%&@tU|0y2h99inyJ-`y;5ISQTgiA>v2^JOP z;x@_FMivoE!)>dx!FT%>f?2c@1}`9i+a%vo^zB-1jVx1{2d0MGR%_SFc7mzl8fMWn zfTPpF^=%$J(k;Q*aOI*!+Q?QVwnX4*GBz~AbmP~hY#V55c{3N2v7sUL!1JoJ@tn!n zushy$7|?a**RRjmkl!k?|F%o);FZbP&=?~<<4p&Rk6|)4?5=fp;G|m_-Y>?6#3a+S zm0?F6n_MOim^fhKK!0#Rzp!|cD<0|RzRY3$^2UZ_GefeXnQUgr zmvkWJhGp+E_x-k&;dOCOzTehXhS%?}tqiNftMzYX2s;}( zsd_dxENnM6Y*bK#A9W*dH>j@Tw>E6w%CJ^`g=}TmVQhFQ{8IZ?hN5LpnP7A{fX0T^ z`nNKq{OG~huuy7jDDb0B;0J7FNOo2$Y2V6_8XI1zl^7ddYTwGRf7t=XhVOQ4Wmt+! zJ8xxJ3R@YL>TG2wVx(Ic3K9ExE5lP<4mwGU4G*7$ZQ4$PS{k2(-NsIWd0|cs&{>lM zrWHA`KG>lI2Y3U!mZr8_PYdSD7tk%DQA;_1c!5M5~*hqHwyVlqU?JvAR z5I5Msuq3<$HZX)|`v!*kObiFO)pciLr~(s1)$N!VHd>Hw2>!3tx3@eqXnD}|#I8t9 zx+1455);Eq?Hd^OZ_AU)m&wG?WMU|l2dNuO484hop##R-y}f;Wwqxu7W^_Er`6zq| z0!$32gSXG22p`T@wjEC=%4I7G`}+F(2T>zJA32Wj_2vB0OdezoMR5K&069?5SN2MT zKNrAEr=Z-|KO%w)z|)DZIX>inC?X($n=T7-I0TuCAQ!|q90I#K2M+wSL3kztN>G5t z0nMZ)h7NsWQ%2Z9Obj!%VN9lAVi?9fuUHT!niz&X|Gd=15WpTy48uB^7y>LcF(ja9 zV#w&27y=|QF?55%W_Dv@_`G0Z$mp6FG94y{j9_B;%pist^h{rx7`~~U#w>i3nix(q zn>%5`xN!@?R&3#1?F8*Ov=B@TC&(9KypS7>Mu1fzc!P=I!qKDc0C;oZLNGC0$T=W$ zYGMd3#vG!6i6QT#CWa2O5#|f2iQx$FrIukM7;CA6ni$%NIMKmbBM2mw?AvvNiQ(}b z+*W4CacW{%v~y?Pp`4tZTeFIYiDA*!ysvXE;Y&F=S?i04NyW~*lQ}t+xRT3ZvNn>f z@pDddIkG%3uFPT9=YT=Qj+{I|6r3vnMAmW@X13;Pb7T+$;GN4Lz}C};AOIlRa?l)r z*NZTTKoC3f;d25kEh=+%W@TkU60)2fr@5UpjVxwP7O^ngn71P0Py;>J7UzWKsYh&h|Ij5+FVa{@H4zoO~4=oH=YF$tUu`rB`{NPZi zw@UytN(KMelB3w^I`1;)vyLZ9hndl$t+EhaBEQ4sN+~ zdspLVx?e(zv-+)YKoOZw7WqnMk;xvB19ch5U$8LTs8DRA7KWcIye2C?r+XRB9Q*15 zyP4F&aF1dEE_G1sp%#V@On4Q(`Rw4!3@i*c+662C$U(7@S{Ponyn@EYsjaQaowLH2;+b7EmQbNFQN^_oC1GFKS9fCSD#KH>8{ z4{*a|4$MZdD4aQ5`+zJ6EDVP+GDm=Ihk|R*MtBTmz{1c~CetdK83bNnUntr+NZ+Eh zL|^HB46*GnBur2A7!u!*Fu#gC`trDJ*3hHIdkKf=2Kv2^r$V@1QtO#2Q(kb`0D{)r zofcI%5U$TGXFGZZ{!mdny7?D*+DLkjp4v_Ces?zybD*8rEZM^~R8j^)Menrs6r!UX z#6=D#<~Pu>mF99E?S|WXb2lsmOvD~XaKsjf_3`eWH^~WJwbZkQKfjBdNr#Tt3Wrkh zkXnHFfNK8at{NIp*Go4VpW-e)jhpnuF5az&8cM5S<4=5rOgPhuB zP%+4PT?R6yBSmsf7oXL@m6y-C7OHmFE{#}yW^gbYl$tTkmQb zO-!SSX*7`zop*6Gu`!J%oj4%v=?D6U$$c}mW$c)tFMR)vCD#q=gvqz;eelbKnBV=j zewkdSho1jNewj!M+s9)G%yYq?@67PXxzXwAqB}G)Z8^AY;KWKY6Gr|#OsnNP4J_UN zurOhb=YVOoyx}}Et(G^ISLDEvU;k=(8)Qu{8#r#nx*vKX(`tDlSK^Na!(~j==JIbt z;u#;qc&ctMM*kko!yjwY-$(PGSQhOxXd&1D$EG1FWI;gUE~8^SR@jPWxQ#>X(8s@sdvzjGO;V}^T^D$`s> zZyYlDn>b+NfQbWr%Yp9ZGE9cX-Sb%dvLJ8MTt@diGGTwa95Bsg7+&|LxeQ}@b$`rd zm`*V;yxzr-;h@xo<}&n42(ic@H?jG+8+I9{Qw;Rig~`Xn z0TTyI9Ox?!=%33lEpzM4WAV#^yiIc%ow;Lzf9o7DN4nqlQs_?ir4f0nKaal3foOH5 zluO-rBM$}SFP8Ss-ulbYmwEI~4{R(r+3sefqDvkdwzE(kKSp!)3O;7 z-;gl9Q_6=Rd^4^_jE~V#_rzrgWyZ%ao~ql6(LZw;WVbYHp(c2`cnUA$3 zZ%Cc=9)_f)5Yp$<6;l`Ay{FMz2r*q<2@$cq#Wu{Jq}GwXn6~&fEDcjA69-HjFmd31 z;egotN#9~0*;i#WWVACROi%O}65o(8zkxj3H@y+}J`~mC18a&u7bUg^|vcyd|*?zB!roy<5%E# zqNMKL9FMQzWL4o+`cK*{hXd=%dp>FNZ2L)@8sQ{KP5Vik#Spz%Jl?LhMt+%`v{@r$ zeO-1j{9^k_n-v0~*M#>~c%vlPH5&>-3S&(1yM{HGA!?3Es?vYbCgn#DCvBdUp0p|O zqfX!loU}>#(SFiqjeH4mx?C&pLw%hIzu11#X8*DS&c@u=anfc9F6n&IW(k~NS)y~& zrihWAv?)aF=aV)+;*wD|Ical!Hpy^39NLtPO1O7r71`Nvwq|lk+q+CjGI3#W)lrv- zlZK=T)bR;ml+CBwRaEX2W3Z^fnVVJm&)ft_lQg~V&)h79=2c1`4Y&Aa)1V<|ZkA{? zCFIOaLGa+r&EoK4ICB%8?PqQZQg`LL(BAr2;0$I;cV}*v!7mPRx1ZX^J1)Hb08IBTJ?=>~YUaZSuENLa3EBI%%J@P&L80G@|@ z84L)lfk5YhEZD=dxrI2%DOncH)m7)uS5-r4r1gCJZb)4N>``mzNt^X%tyNW(m1;OM zQQfMo(pDlhoU~abS7WT!mc!AS;0a`_%gcWOK%-Uzv(%gl7147x!Nn9o1mGC&q~~m^ zWaUL_dd_A!_|o$c%bD+`4tmb!FCtEKaNi>cbo(XihzaLxz7_z-n+Ci_&)GcU>KZc5 z)6Lb{0c|Paq<`xnarFCN* z*TS)40iGe8n=I|^G(fma0fe)^CmGOgEFp%Q ztBcDRlE&JA=QvlIh6`h#NeY@TTX!DmcuDMZNUsY59 zCukNmH@6a?@)QV7k(z5%08kEqRZ+cK-O^HBS^g0KSBt8v)#}RfQxL}z7Zg>h)#a!D zO%K{ExTscN{D>T>syS?pBse zJ@cg|hl`43CI>=Zg2~)Fy9}c}A7uU%NdFmV1?S)Z*CLokz6|*n!?Bdt*fPp}(ssml zbhqDzm7*h*bW;BoNE4Y%CVZ`cvJ^wf2I}gdut%5an6xhJfuD({W71$&P&^{ebW9pd ziRzsD)p_&%ZcYyC=6o@TWjZEJdInrqcORSz*Z#FG?U>0hPX@f}px-0sA72?jUF%Qn z6n5!(bbNSiE3btVwXNjiv4B0ze#IVV{{!cof5Lt+U{}x7OMP{ zQW$$hm1h@ysDd1Fsu8K{tWIsj^52rSwE|QX6+LTP&q=hcRO6x6r){m}wXLIDSG1jBDmD`r23Iq6i8yIUnm{w307m=yRP~Qzx9elD zVzFm!D@dB8>2ki4F?t%B6GYg_wQ;0$I;ciPqp(6(0es%`Dc z4A8cc1_=M9`n9d3Qvz+Pzz!X4YyYxDDqkjTt4Z4`l?SOCw5=zIwlx#uvnNg*J9ZZ1 zOwfArAa_i0m>@vgx(~dMsm>hZ4$IEseN@{@;lqb>b9Yjm>M=P!bNDcqi?;C~qdLRo z;sYp?f`?@n&*X9kn0*wKAI?2x(m4p6xseMuX|ymXYRT#rU^(TW98VO~dx%Jpbebo2r) z1BWqQM}a&7hFt(H;ug*e9R-!^x@F74E`S0t1Kx?o$>*_Va6$<+jr~ns0+VU+U1}y{l zC^v$MhP)M91`V==ycv8{I|7F(oC!$vu18x2F_u6!=v|LKZEb03{WKIwTI09x24z>V zwty)trh3-`v!XA*%+D_b6%sOELEh!Y*$%LoG9e%U%= zg64H&FgKA2-bgjC`9402o(c~1nW)Ssn%De^i&BCQ-~)kyO6Po{dG%SeG%&CL7jS`$ zauOgm2Coec3|tfwqYY%7*QqcLMvJ&W*@nFv0HK@&TGNS5`TF!^2p=9jRiRN|EqF|+x(4k};?1<(y-@#d_ z+*`0$sdTVANHwqdlN_8UDJMDG*&U>s*L9OPJ7!XPABsnTHV=JAG_PNtu2!8tk#`U@ zuLY;Is^aqnU*;VGm1IMPwvq5a~&U3{I0CEAa$}2d3zM|qpe(nYUzRNpt;=+ae z+-!(ri4W%GU$~H)okcaT2lrmMuy+I1w|=eNi?Re)8t-boNHwpA)AIJFQ7^NL8?v+0 z4pTu&>od)39Zd1@ml~#+$RtxOdlROa$V5{m=#z*(mP|BVh3UVG18^DI5K>tFN@kPU zBsP&<&Mt#1o{eK;*l6|z_V;i-%|@|Lun}z709=NaLmE!hK>n6BuPyDGS2aw3@>9{* zsE+VX7yd{&t>66<$ov(MexheBryABupn|lIo3yR)twwA^cmJ)Q^6q`46Z}M{%`d1T zT70sg>dJs!-Ba5I3!2xwrAza!;Wlhmv~+v+Qfm8Tw(X5mx#`=;2yF4~(p+4#Y3a9R z1X#P}6vms<;nR$RemQ+_E=8?|}rYfD=ZVo{=t&XlDgNpeFtM_i&ge$mBO!QVV z9#$;f{>G+F6{omOvbB*#DlEs_R%e6n_ALanXeA6@KmxZ(zNP5fwcHw6rZTS*Guu{c z*UENc+_r{UG!5YBbZ~u}2aj~iN-SHsXpuIuRf#PTcy zR}9nByV}pVCv(-+)nvk&M|D<4chXhYf^q1sU7A{nLZ6qcF3&7NS7v4`1zu?Gh1GOQFN6t8?0zdahL zeG;#HC5v5&#akKuDkdczh%wWkl9-gQ`bSlh@>QyEmAdaYI8nkQdhF_uB3gbD^SFSRdq?O%3)^7Y-0rLLv8wDVHeQdsI*slI2Y3U!mZr8_P?INgLtMxB%1^JRR zID=KLjbwrAwZ=whf8h;+xWNL~lJF8(;0n+71+My3t^?fax>LETK;^2s9hGaN1?h(1 z|5|-}%QJ(P2Tf1xiqxbla=Ic>xn62t;M%_}Pbyy~m8(hRDwPMR8&s~|MCIy$@pf-- zAD`_QJAhh|2RR>wFF}CHbvk(a9E$Mad}Z75bTZjyMPXlGfBzt=RP~YL2wz{$AI;=J z=1>IZj{}ec1$||&MEG+7%ybIMef=XMxBxtz_?qKG{)Zw00=Vh2AcsScxd?JWjKd+& zGdghKrwzh05m15xG!AGcRk=F!jgF15gQ#3HwP8%ApmGi4o>wdg6IHHZ&p$6!xdPau z$~CN$$`xR#%9Vhk%9YVkxdJ3nxw=7NGrLi_J};kE4UbQhyp5C-bq!i4zdyE3#rO=1o%=-*$Bp3>YyrDI}s;3IBNuf zq>_ERZcw=%-@$EVb{wZF*P@*}^A6?Y?A)4FL{zRtTl2ooxr8s}YPIEc3JWw|0Fza(*f_XDGrH=(Gtg$)HMg`QT6@0mh94sc{MA<|zOe4Sd+_Q9bJ$T3a+*aM|&$*5g#; zy3x+X){c6a9d{Zz(rzP_BfCD+xb}&h-L8E0VLVp&BkLc3gf)rhVVMP4XmN)97S<}B zV2{G}DV^_ok9}tVuG`_WuEv$$a*(WbCCgxV?IT%bdAG0IDT#4$#B#R^Ykb8OzG9iL zQQe?88+^NO<7m2HLW>&LR$&!!#}<}kQPtG}yA0$nXk0fc6dS3=^>c;SWX0!X05+RB z_SFS;GpWXPk75BXbx`b~8rKIVyb9lZcJO5e8rO|>0Sf?fP;8_c*Q<7%mpKG=7;bx& z3@YZ)!vh=~V2cF@#x|M^ho==@V;vk$zsfnt9#DKvG_Es;PX=GF2?Qf^g~1C*;2h)= zKHu{IH%#WhYy=JK%;DMxWI>>D9mdEU0k$0qu00#!F_Zy~tE)_=RWvgQy!xv5>py+# z^%|;jQVVmHyaK9LfXEsRbi4+1Q!r1-12^ds5#HTJH^na%>;nx|Z{@vBeJh!xFBbSiTGNb|PcQHhedG(#ze2@`_q!iIT9B0|9NQ28! zJ?sHy%+1H@Ep0>n?+qI6joP?3sDKg6fOduu4QFV(?KYf{Mz3wUFYE87jMmha1@3?2eUV-(P*8&8Bv(*FK-T3*2Cru7u0RY%uzVfCFi0F_ zdY@f~Dn8-v$i5vM2NeAx_GGBcQkf+!)*y;HRbU zR(NXx7UT1&@ulN)xgGkt#=($dDO70_zJ?lsb}i7+25*k$Pu_(7UqBpMi7z~_!LtqG z5c*1Vo~#bU`*+RJc#IZkBwTHTT1Th>xWYf{U^7#Fw=^6dlTXF?+`Ef`fe$4>MKkc> z7I38V&HM17dVXp_u&)}_jJl(v6Ry``cz{2?4K3&WQVs(?!b~;NCmb+LvhEkTx=+f{ z3M0rhVPp}z>% literal 0 HcmV?d00001 diff --git a/include/javascript/yui/build/assets/skins/sam/tabview.css b/include/javascript/yui/build/assets/skins/sam/tabview.css new file mode 100644 index 00000000..eb795746 --- /dev/null +++ b/include/javascript/yui/build/assets/skins/sam/tabview.css @@ -0,0 +1,8 @@ +/* +Copyright (c) 2009, Yahoo! Inc. All rights reserved. +Code licensed under the BSD License: +http://developer.yahoo.net/yui/license.txt +version: 2.8.0r4 +*/ +.yui-navset .yui-nav li,.yui-navset .yui-navset-top .yui-nav li,.yui-navset .yui-navset-bottom .yui-nav li{margin:0 .5em 0 0;}.yui-navset-left .yui-nav li,.yui-navset-right .yui-nav li{margin:0 0 .5em;}.yui-navset .yui-content .yui-hidden{border:0;height:0;width:0;padding:0;position:absolute;left:-999999px;overflow:hidden;visibility:hidden;}.yui-navset .yui-navset-left .yui-nav,.yui-navset .yui-navset-right .yui-nav,.yui-navset-left .yui-nav,.yui-navset-right .yui-nav{width:6em;}.yui-navset-top .yui-nav,.yui-navset-bottom .yui-nav{width:auto;}.yui-navset .yui-navset-left,.yui-navset-left{padding:0 0 0 6em;}.yui-navset-right{padding:0 6em 0 0;}.yui-navset-top,.yui-navset-bottom{padding:auto;}.yui-nav,.yui-nav li{margin:0;padding:0;list-style:none;}.yui-navset li em{font-style:normal;}.yui-navset{position:relative;zoom:1;}.yui-navset .yui-content,.yui-navset .yui-content div{zoom:1;}.yui-navset .yui-content:after{content:'';display:block;clear:both;}.yui-navset .yui-nav li,.yui-navset .yui-navset-top .yui-nav li,.yui-navset .yui-navset-bottom .yui-nav li{display:inline-block;display:-moz-inline-stack;*display:inline;vertical-align:bottom;cursor:pointer;zoom:1;}.yui-navset-left .yui-nav li,.yui-navset-right .yui-nav li{display:block;}.yui-navset .yui-nav a{position:relative;}.yui-navset .yui-nav li a,.yui-navset-top .yui-nav li a,.yui-navset-bottom .yui-nav li a{display:block;display:inline-block;vertical-align:bottom;zoom:1;}.yui-navset-left .yui-nav li a,.yui-navset-right .yui-nav li a{display:block;}.yui-navset-bottom .yui-nav li a{vertical-align:text-top;}.yui-navset .yui-nav li a em,.yui-navset-top .yui-nav li a em,.yui-navset-bottom .yui-nav li a em{display:block;}.yui-navset .yui-navset-left .yui-nav,.yui-navset .yui-navset-right .yui-nav,.yui-navset-left .yui-nav,.yui-navset-right .yui-nav{position:absolute;z-index:1;}.yui-navset-top .yui-nav,.yui-navset-bottom .yui-nav{position:static;}.yui-navset .yui-navset-left .yui-nav,.yui-navset-left .yui-nav{left:0;right:auto;}.yui-navset .yui-navset-right .yui-nav,.yui-navset-right .yui-nav{right:0;left:auto;}.yui-skin-sam .yui-navset .yui-nav,.yui-skin-sam .yui-navset .yui-navset-top .yui-nav{border:solid #2647a0;border-width:0 0 5px;zoom:1;}.yui-skin-sam .yui-navset .yui-nav li,.yui-skin-sam .yui-navset .yui-navset-top .yui-nav li{margin:0 .16em 0 0;padding:1px 0 0;zoom:1;}.yui-skin-sam .yui-navset .yui-nav .selected,.yui-skin-sam .yui-navset .yui-navset-top .yui-nav .selected{margin:0 .16em -1px 0;}.yui-skin-sam .yui-navset .yui-nav a,.yui-skin-sam .yui-navset .yui-navset-top .yui-nav a{background:#d8d8d8 url(sprite.png) repeat-x;border:solid #a3a3a3;border-width:0 1px;color:#000;position:relative;text-decoration:none;}.yui-skin-sam .yui-navset .yui-nav a em,.yui-skin-sam .yui-navset .yui-navset-top .yui-nav a em{border:solid #a3a3a3;border-width:1px 0 0;cursor:hand;padding:.25em .75em;left:0;right:0;bottom:0;top:-1px;position:relative;}.yui-skin-sam .yui-navset .yui-nav .selected a,.yui-skin-sam .yui-navset .yui-nav .selected a:focus,.yui-skin-sam .yui-navset .yui-nav .selected a:hover{background:#2647a0 url(sprite.png) repeat-x left -1400px;color:#fff;}.yui-skin-sam .yui-navset .yui-nav a:hover,.yui-skin-sam .yui-navset .yui-nav a:focus{background:#bfdaff url(sprite.png) repeat-x left -1300px;outline:0;}.yui-skin-sam .yui-navset .yui-nav .selected a em{padding:.35em .75em;}.yui-skin-sam .yui-navset .yui-nav .selected a,.yui-skin-sam .yui-navset .yui-nav .selected a em{border-color:#243356;}.yui-skin-sam .yui-navset .yui-content{background:#edf5ff;}.yui-skin-sam .yui-navset .yui-content,.yui-skin-sam .yui-navset .yui-navset-top .yui-content{border:1px solid #808080;border-top-color:#243356;padding:.25em .5em;}.yui-skin-sam .yui-navset-left .yui-nav,.yui-skin-sam .yui-navset .yui-navset-left .yui-nav,.yui-skin-sam .yui-navset .yui-navset-right .yui-nav,.yui-skin-sam .yui-navset-right .yui-nav{border-width:0 5px 0 0;Xposition:absolute;top:0;bottom:0;}.yui-skin-sam .yui-navset .yui-navset-right .yui-nav,.yui-skin-sam .yui-navset-right .yui-nav{border-width:0 0 0 5px;}.yui-skin-sam .yui-navset-left .yui-nav li,.yui-skin-sam .yui-navset .yui-navset-left .yui-nav li,.yui-skin-sam .yui-navset-right .yui-nav li{margin:0 0 .16em;padding:0 0 0 1px;}.yui-skin-sam .yui-navset-right .yui-nav li{padding:0 1px 0 0;}.yui-skin-sam .yui-navset-left .yui-nav .selected,.yui-skin-sam .yui-navset .yui-navset-left .yui-nav .selected{margin:0 -1px .16em 0;}.yui-skin-sam .yui-navset-right .yui-nav .selected{margin:0 0 .16em -1px;}.yui-skin-sam .yui-navset-left .yui-nav a,.yui-skin-sam .yui-navset-right .yui-nav a{border-width:1px 0;}.yui-skin-sam .yui-navset-left .yui-nav a em,.yui-skin-sam .yui-navset .yui-navset-left .yui-nav a em,.yui-skin-sam .yui-navset-right .yui-nav a em{border-width:0 0 0 1px;padding:.2em .75em;top:auto;left:-1px;}.yui-skin-sam .yui-navset-right .yui-nav a em{border-width:0 1px 0 0;left:auto;right:-1px;}.yui-skin-sam .yui-navset-left .yui-nav a,.yui-skin-sam .yui-navset-left .yui-nav .selected a,.yui-skin-sam .yui-navset-left .yui-nav a:hover,.yui-skin-sam .yui-navset-right .yui-nav a,.yui-skin-sam .yui-navset-right .yui-nav .selected a,.yui-skin-sam .yui-navset-right .yui-nav a:hover,.yui-skin-sam .yui-navset-bottom .yui-nav a,.yui-skin-sam .yui-navset-bottom .yui-nav .selected a,.yui-skin-sam .yui-navset-bottom .yui-nav a:hover{background-image:none;}.yui-skin-sam .yui-navset-left .yui-content{border:1px solid #808080;border-left-color:#243356;}.yui-skin-sam .yui-navset-bottom .yui-nav,.yui-skin-sam .yui-navset .yui-navset-bottom .yui-nav{border-width:5px 0 0;}.yui-skin-sam .yui-navset .yui-navset-bottom .yui-nav .selected,.yui-skin-sam .yui-navset-bottom .yui-nav .selected{margin:-1px .16em 0 0;}.yui-skin-sam .yui-navset .yui-navset-bottom .yui-nav li,.yui-skin-sam .yui-navset-bottom .yui-nav li{padding:0 0 1px 0;vertical-align:top;}.yui-skin-sam .yui-navset .yui-navset-bottom .yui-nav a em,.yui-skin-sam .yui-navset-bottom .yui-nav a em{border-width:0 0 1px;top:auto;bottom:-1px;} +.yui-skin-sam .yui-navset-bottom .yui-content,.yui-skin-sam .yui-navset .yui-navset-bottom .yui-content{border:1px solid #808080;border-bottom-color:#243356;} diff --git a/include/javascript/yui/build/assets/skins/sam/treeview-loading.gif b/include/javascript/yui/build/assets/skins/sam/treeview-loading.gif new file mode 100644 index 0000000000000000000000000000000000000000..0bbf3bc0c0e5e635553e8d1bf9ceddefbc402396 GIT binary patch literal 2673 zcmchY_gj;P7RTSb83YJ1>=8y5ONL=ZcEgk+C?FydumNNz8c=c6`n&|fmMu_HHG%^w zNLVjHyfy)hAgHK_Kxkz+0Ktm5M|X*?y?g!o_3yv`{_^F^wY9YuFJ3GxEUd1s-nnz<)vH(c?%i8n zUVirM+2rIT007UQKY#e};oRKZty{MqJa}MhYina;bNBAu-+udTYHDhBcJ|n@WA*j* z-+lL;iHS*OX6D|#dm|zu!o$ON?b=mbT)bh!26uP&kdP1u2Zx!N8486$B9X?&$DclZ zdgI28>FMdk#l`#g@Bj4EPc=0)2M!!4EG!%z9?s6rzI5r**|TSdhK8)HtXf)HHgDc+ zZEek9Fk)k4xm@nHZQC3j9o^jACMG6~jg9m3^EYnX2*Yq^XJ>6~?X_#y4jnqQbLUQp zM6z$+zMp^o*}}p?p-?n8H=jOzx~Zv&N~Km+RkgLX9X@>c=FOXxm6dsUd1NvZ zX=yul?BMZua=F~p)O7py?EwJ+w{PD*dGh2hzx?v((WCP6au$mb!vmnqSpF6-9Ona(JQT#e>!KODwxYzG5#S|?M#v6eD#mgO^`=~9EL;yL&>*dd5*+XG=_`^3=CG25PbLa+LJ%N(PW_s z=_-TaM{SB!w(n7k+dMDN2G6VPqUA$u7F4m@ABAZ1D`*UMfe}E6csJU}J1Trmp#~7hZ5QSGpNvd1Uz$!Rf3q28pgSj9o zx?zwoWa8GYK@TOz^)mp#V2_VR5WfJ0W9BSSbn+cKb z7B9l9)K#s!?PSt;g%c8u;y7rd?hkP%>vq5BY=N>c=98V=+T&RSPgSu|E(FAK>B?vNN1 zPszwcbxJ?Oh|1pGd!9?gxzSWOR8o=x5!rGh+6r3hBL-14aTaAQxvJ|Y-S_m4niV2S zK@?}-9Dkhg<+w{Ny!vjyp-QmjyGmIW1DFB{k>P2=8cm~9M^_P#8?JFDumGEPaqJvf zZ{f;B#CG;H7q8a_hQ$pR6%%6So8vKM+W+cNPE_TI46^dn9q@qBr@1bUgxcPGB*b-i z3Hx_0(Esy5KKx^Y0yfgB6~}t>@!ctk>J|!vgVRhE2CPQ;AOKY2y%5nM@YF^ZMS~q}%L-n>Lpor#4w48UHYViOt={{43LMRvkIp+rkbs*s; z14}4q0y6`s8DL?uo-~*R@5tnFsC1DR#BGxT8fA20u_o?`0iDNI6lf;^$@AkR1dPTz z>XF1ZAqNjU95c@Vn59Wo;Z6b(YG+L$xy3(?j2I*vQ>PmzMEdh`yw3=)E}JYMDG|*x mDkGVJ;D)fXhxDI?kcM(ish)HppA z|KIKZ;^O4y=I80^>g(+6?eFj4?f>KM|K#xh=JEgV@$vHV^!4@i_V)Mp`T6?#`uqF) z|Ns900000000000A^8LW0012TEC2ui01^PWA^-*cU?+}bX_CaLu56dKMJ&&8S!{T& z;{|zVyNyP}^JR`lOa_A)YI>srb4tZrE>Kb7GQE1e*-pV?37F63OQkSyi7OQ}8g7Hw z?~lsk9xgl_4}pS%eGZ0)h<|+zjE#07FJR?dF`%c< zpFK+qpg^>!QKD@|3_Z#;sfeKxh(@I_HLBAN1EOlxI-%=?t63$8l@MX*~B&;C>oFt6t5zwd>cgW6PdRySDAyxO3~?&AYen-@t4~RHm#vzLM@W_}AL{iC_m#oNQiEOs%=9_TFDd(JY z)@kRRc;>0+o_zM{=bwNED(Iku7Ha6Bh$gD&qKr1`=%bKED(R$@R%+>`&!l*YrkioL z7*kDs3aU|HQ6-fbQX%!}R%S%y6+QGThAZy4+ZYo z#w+i<^ww+dz4+#<@4o!@>+ipGYHCUVo2WTMi!tT^V-7&P=mQQ&ED>=AJ62&akY8M3 z1sFb9aKVve^Z`K`bB$bpdj;50B?NllapfQ|2T}-_U4|J2nU9!xCM9VaT!VVD2waNL zq!2xd(V`$7iqfDk{fX0_K;4PdoKU@q)h%Gng4Qc=t%BDlfNg@ z(6$?Dr>&FRue@zH-Q?kIp5Ey34RqXq&mDN(ezR9Niie|e_uzRmzPICjL;knmloKww z;g=(xx#Ed$+PNwIi&x&b=#P^gx#^QzjymS6Yu-BNn|mHR=${W=d(pQaoqN)|FWr07 zzds#()Wc6*eAUNaoqX2IZ{2*?&wm|#*wc?)ec9KaJ-hAOY4<<2WzT>GblU+Hm_WD1rd2GO@c^>vVaA9P;`;WtA0m5_cXv|kGGw?h53kbf`qUkm}Lx*Cqo zhNZ*d>2#R78~QMZKipvudkDlL3eku}Jfael$VArh(1}BYA`+#zL@GAXbx*`%6ty@- zE>_WtSA_oE3=ud+2A0u*SrlU$1-M26o-uT7gkT&cI7bTB(SmoxU>-HNM-KMUgMS2J zAVoMx5*E^gheTl_Rk%nNHqwQUgkdCQI7u3AQH_^mV6WW)+ICLMP-(hq$71EIaRq*R<_iYFNI}HWjRw?*3_0a#br))xzll; zRHZ+)W>8JpQ(qPpm`4?6Qi-`#V>T6;LoH`iSvpmhRu!gKm1$OKx>cKY6{la-X;^tW zR-dL+sAnZ=S&h0@q_$P5Z)Iv+ojO;jrd6tUrD|TSx>v0BRjYsHYGA!OSg;mWtcN9Q zV$EvB#)8qYCS5FBCF@qo!qu{J#VlPlYgfpk)U!b4EHs}w+Paojw9+JPYE8RZ)QZ!! zaGYjrRr^}dqSdx)h3x`s``F$_7Poi>u3m-9SK|8BxPV2jV3kW)<{H+yh=s0V{-w)U z-+tD*p{4F*wOd*4Ue>#r1@C6X+ga@1*1WkT?`hTBTK4kxx9AOSe1|*V;@0=L_f2ko zm%HEQ_V>B}jc$OaJK*ZV_rTXhaCQs4T?Tj8!QX{&cqKeu3YS;G=f!Y(ExcY1x7Wk( zO|Xa;tYP_(CjI?wsTb;k3ZLmX!&_u0vRhH{{#JZLHx+RBH=I&UL)GqiUu~Lh3#l!L)zGqzO}ObjO!pzO}t?Zui^U{|0x! z#XWFx7u?(jM|Z;2y>NE(`{DkEIKU+?aEcS$;s(b!!ZogNjx*fj4v)CVCqD9um;B-< z&v?o=zVeQ@{NpbVImu^ka+;&u<|@ZI%XRK@p2OVdGOxMNZ$AF?oELrPNAG#kf4=mf z6aDE%hdR=wu5_w1-Re${y4I(@^{RLM>R-<~*T?R4vV-01VlTVe&%XAwv;FOEkNdkD zK6jAUJ?3`@dfuD9cdYk4?0-jl;M+cUxEEgT@uqv??Y?-tH(u|L=X>P+K6$`bUhtPE zeC7?mdBo3K@tA`CEx&rqw_fwF=X~rvUvJRYUi7yoeeO-ad(`({ z^}lC*@LfNA*cV^+$EW?hZNGfnH(&S9=Y8~jKYid=U-;K2e)f&OedKpv`T2H!_@O_3 z>6f4S=eK_PvA=%px1am(_kR4ruj*^pAK&+9{`?Qm|NhSRfA;^Ed;$1<1Gs6opeBO_XoC)jgW5xCC}e8x!-Fd1gDFUZr9dz+;4^8GFbeZ94C5jT zg9K(^BNXEUJQ4s^fH7XsBO6mBA2Syr10^K07I1JfOQJGT5&$dn056jzXt*U&kO*Ib z2#bI-jNkw|von@p14!sH~{iM*(bkLZh$2#k{`i=jx2qiBq!h>WMGjHyVAi^z<(2#vWYjk_p}y-1C} zh>gLhjl<}SpU92Z=#8r=j;%o+kTk2Sh?Rbpun2hnbjPuxx?0AoVh>vfi zkD*kL(dduU2$0nXj@DR^1bL7GnT-j#jSJb0{3u%wNm~sWjuFX+73qijn2#EnksR5N z7a52jIfx-yh$DH3C7Fl_d6Ko5k{jufEeVk?DUmAqj1y^)HOZ1436nV~lQC(LJ&BPn zxsyIAlt8JIL3xx$nUp+9lpy(&P05u0BI%S-36&%%l~qZVCTW#fiIpgMlU_NK-}seU z*_B{9j%8VnXL*iknT~6@j$^r!V#$?o*_Q4|m+)vgK*&Nu=uLXIO~%7&B^gp8r4;R? zDuh{>utEV7KoqEAD)U5`6W}Ula8F;6PiE07W)VG157#(#PAQe(WiIhvpo4cu$zuB9>S(L(AoWXgV#EG0w z>6^*foXa_!&uN^_IhD*Aoytj_(21SWX`Rz~mDQ=8*Xf{Y=Sh}tNt1RdkM&89_i6r*^BI=;`H%e>kpDT5ahaa(xt{VVm-M-xW~rcP$)IZK zplk`DZi%4$DWP>~p?8U)_Nk%x$)Wm5p$iJ44Jx7!N}>^Jq7zD>2dbiT>7oAVq5uk` z0vezSNuvyDqYf#fHL9aG%A+}oq8AFJ87ib3N~9fXq#w$n35ujI%A_&sq%-QH6e*=P ziK9~rr8|nHJ*uTYs-zXlrB~{uAu6ULN~R@hrYDM~DcYVZ%BC#}rd3L%IH{&VN~c3= zr$vgVM_Ng!22OwZgMC?l-E^mJx}Any0V2r?HBtt!k*V%BZ*MsJRNM zr5dKYDyqLqs=;ciwW_GY>Z`>{smW@o%ZjPZs;SS)sRrt*(Tb|os;bj!tJeyv+bXNw zN~_swtlx^OuMx|y6YH#_vvvDC`4CkwL(YqJWAvkWV<0IRbh>$4*Zv?WWk>e{PC z+pZ1Sr=|9%{_vBRF0_}&2nHL!OSV?)wP*{sZL0-VJGOEQwrX3od&{?O`?Yi1w}RUF7eEFUAToD=26qs;P;!Q(3ju2A1A%Y` zt*a$76NiQ{C3Yw#bO;GPfQLMzhlfiN0PwrO8@#_;0sx?dH~;`7P`phT1jsuA${R6C z5HZaw0svq!Q}DYOFuffB02!k(zk3DR3jmz^1-}cr;R^x3dk5)j2NrO?=nDYv8zm1A zzJdUAyfG8LhyVaJ;{f4%yNnRNx;qKlyS>6&z$H<@2AsUcy8+>=0}ZnS4a~p*U?abK z1mVjBz>C4yo4v{F1qJNE$veKm`?+M`zIG72rE9_ktTOaFzrPy@_B+4HYY4xazX0$D U{p-H~9KZ}Pzz8h7+YkZ(JNT^25dZ)H literal 0 HcmV?d00001 diff --git a/include/javascript/yui/build/assets/skins/sam/treeview.css b/include/javascript/yui/build/assets/skins/sam/treeview.css new file mode 100644 index 00000000..3843d4bd --- /dev/null +++ b/include/javascript/yui/build/assets/skins/sam/treeview.css @@ -0,0 +1,7 @@ +/* +Copyright (c) 2009, Yahoo! Inc. All rights reserved. +Code licensed under the BSD License: +http://developer.yahoo.net/yui/license.txt +version: 2.8.0r4 +*/ +table.ygtvtable{margin-bottom:0;border:none;border-collapse:collapse;}td.ygtvcell{border:none;padding:0;}a.ygtvspacer{text-decoration:none;outline-style:none;display:block;}.ygtvtn{width:18px;height:22px;background:url(treeview-sprite.gif) 0 -5600px no-repeat;cursor:pointer;}.ygtvtm{width:18px;height:22px;cursor:pointer;background:url(treeview-sprite.gif) 0 -4000px no-repeat;}.ygtvtmh,.ygtvtmhh{width:18px;height:22px;cursor:pointer;background:url(treeview-sprite.gif) 0 -4800px no-repeat;}.ygtvtp{width:18px;height:22px;cursor:pointer;background:url(treeview-sprite.gif) 0 -6400px no-repeat;}.ygtvtph,.ygtvtphh{width:18px;height:22px;cursor:pointer;background:url(treeview-sprite.gif) 0 -7200px no-repeat;}.ygtvln{width:18px;height:22px;background:url(treeview-sprite.gif) 0 -1600px no-repeat;cursor:pointer;}.ygtvlm{width:18px;height:22px;cursor:pointer;background:url(treeview-sprite.gif) 0 0 no-repeat;}.ygtvlmh,.ygtvlmhh{width:18px;height:22px;cursor:pointer;background:url(treeview-sprite.gif) 0 -800px no-repeat;}.ygtvlp{width:18px;height:22px;cursor:pointer;background:url(treeview-sprite.gif) 0 -2400px no-repeat;}.ygtvlph,.ygtvlphh{width:18px;height:22px;cursor:pointer;background:url(treeview-sprite.gif) 0 -3200px no-repeat;cursor:pointer;}.ygtvloading{width:18px;height:22px;background:url(treeview-loading.gif) 0 0 no-repeat;}.ygtvdepthcell{width:18px;height:22px;background:url(treeview-sprite.gif) 0 -8000px no-repeat;}.ygtvblankdepthcell{width:18px;height:22px;}* html .ygtvchildren{height:2%;}.ygtvlabel,.ygtvlabel:link,.ygtvlabel:visited,.ygtvlabel:hover{margin-left:2px;text-decoration:none;background-color:white;cursor:pointer;}.ygtvcontent{cursor:default;}.ygtvspacer{height:22px;width:18px;}.ygtvfocus{background-color:#c0e0e0;border:none;}.ygtvfocus .ygtvlabel,.ygtvfocus .ygtvlabel:link,.ygtvfocus .ygtvlabel:visited,.ygtvfocus .ygtvlabel:hover{background-color:#c0e0e0;}.ygtvfocus a{outline-style:none;}.ygtvok{width:18px;height:22px;background:url(treeview-sprite.gif) 0 -8800px no-repeat;}.ygtvok:hover{background:url(treeview-sprite.gif) 0 -8844px no-repeat;}.ygtvcancel{width:18px;height:22px;background:url(treeview-sprite.gif) 0 -8822px no-repeat;}.ygtvcancel:hover{background:url(treeview-sprite.gif) 0 -8866px no-repeat;}.ygtv-label-editor{background-color:#f2f2f2;border:1px solid silver;position:absolute;display:none;overflow:hidden;margin:auto;z-index:9000;}.ygtv-edit-TextNode{width:190px;}.ygtv-edit-TextNode .ygtvcancel,.ygtv-edit-TextNode .ygtvok{border:none;}.ygtv-edit-TextNode .ygtv-button-container{float:right;}.ygtv-edit-TextNode .ygtv-input input{width:140px;}.ygtv-edit-DateNode .ygtvcancel{border:none;}.ygtv-edit-DateNode .ygtvok{display:none;}.ygtv-edit-DateNode .ygtv-button-container{text-align:right;margin:auto;}.ygtv-highlight .ygtv-highlight1,.ygtv-highlight .ygtv-highlight1 .ygtvlabel{background-color:blue;color:white;}.ygtv-highlight .ygtv-highlight2,.ygtv-highlight .ygtv-highlight2 .ygtvlabel{background-color:silver;}.ygtv-highlight .ygtv-highlight0 .ygtvfocus .ygtvlabel,.ygtv-highlight .ygtv-highlight1 .ygtvfocus .ygtvlabel,.ygtv-highlight .ygtv-highlight2 .ygtvfocus .ygtvlabel{background-color:#c0e0e0;}.ygtv-highlight .ygtvcontent{padding-right:1em;}.ygtv-checkbox .ygtv-highlight0 .ygtvcontent{padding-left:1em;background:url(check0.gif) no-repeat;}.ygtv-checkbox .ygtv-highlight0 .ygtvfocus.ygtvcontent,.ygtv-checkbox .ygtv-highlight1 .ygtvfocus.ygtvcontent,.ygtv-checkbox .ygtv-highlight2 .ygtvfocus.ygtvcontent{background-color:#c0e0e0;}.ygtv-checkbox .ygtv-highlight1 .ygtvcontent{padding-left:1em;background:url(check1.gif) no-repeat;}.ygtv-checkbox .ygtv-highlight2 .ygtvcontent{padding-left:1em;background:url(check2.gif) no-repeat;} diff --git a/include/javascript/yui/build/assets/skins/sam/wait.gif b/include/javascript/yui/build/assets/skins/sam/wait.gif new file mode 100644 index 0000000000000000000000000000000000000000..471c1a4f93f2cabf0b3a85c3ff8e0a8aadefc548 GIT binary patch literal 1100 zcmZwFZA@EL90u^)S14;kcS~P51JcqXyBK7YjR|$m*3qt)1nqFnf*+(nyIT_zZIrbc zP70+hE$ePOAcE2K4FU;V;KM+=xUiQtnG(k(Qx;;(oQVNl47kM11c$9(j7iV=cuw*= z&;L26aeaM*8AVX!4nUmF3luezO5JukyN8Fbj*JY)E9#Hd|0*@ZIv{eO*Nb# z12yCIrOhLLJlbn33DTB}t(F_b2bV4~y*j=}%v9m90(t13QX1^b_==P$D+H{5*5Mu? z8gKY>BXXf^7@!+sCzFj+>XgJsqfc(1Ya(r=#J=3 zlZtj9{~(p*xA$9X2mMtN6e0bM#^36uHAhJ9Q&;+@HQ_ThCJ=yPPcaaStzMs1DHP_0 zvw_E92pgO+s83$0SnZp{u*pvQ$A3#Rftg(VD(=52XCTzUftd4T-22$PQrgIR*gHx4 z{43C_yk?5j?(i$Mual4dFf?{<9Wn}qfaB%>iNwkdu&q!m&h2IcZ$2Th!C8}<*_&Pr zyKl`OZw8N)3D^4?RK}UoD=o00gbKYHy=yv32mZ9Dl8aIS8x^Z$2?NwcBLzFmZOtoW zzN62&u*QDIz{Fy}^YAXY&Txmg7ATSAhAr8K5fZbFZ*SFa$_qE2L|VVFHOI{wKE8B_ zGXV2p-56OO`rc4Z7g3zbj)2_3YjK$((`OUqD%*mgvS`YELYsVW1or1)YW%;)D$oE>#r zQ3z|D(W$Eg`c?NY^+fD&+nctrc25@u47U__J8-QW7NqK!$T9C@*SpuaHyFRRpIGae rj_Lao#za}+eaj_<`F9!mRdtBiaY8;H-1;A--){B[A].style.display="none";}};YAHOO.widget.AutoComplete.prototype.getSubsetMatches=function(E){var D,C,A;for(var B=E.length;B>=this.minQueryLength;B--){A=this.generateRequest(E.substr(0,B));this.dataRequestEvent.fire(this,D,A);C=this.dataSource.getCachedResponse(A);if(C){return this.filterResults.apply(this.dataSource,[E,C,C,{scope:this}]);}}return null;};YAHOO.widget.AutoComplete.prototype.preparseRawResponse=function(C,B,A){var D=((this.responseStripAfter!=="")&&(B.indexOf))?B.indexOf(this.responseStripAfter):-1;if(D!=-1){B=B.substring(0,D);}return B;};YAHOO.widget.AutoComplete.prototype.filterResults=function(K,M,Q,L){if(L&&L.argument&&L.argument.query){K=L.argument.query;}if(K&&K!==""){Q=YAHOO.widget.AutoComplete._cloneObject(Q);var I=L.scope,P=this,C=Q.results,N=[],B=I.maxResultsDisplayed,J=(P.queryMatchCase||I.queryMatchCase),A=(P.queryMatchContains||I.queryMatchContains);for(var D=0,H=C.length;D-1))){N.push(F);}}if(H>B&&N.length===B){break;}}Q.results=N;}else{}return Q;};YAHOO.widget.AutoComplete.prototype.handleResponse=function(C,A,B){if((this instanceof YAHOO.widget.AutoComplete)&&this._sName){this._populateList(C,A,B);}};YAHOO.widget.AutoComplete.prototype.doBeforeLoadData=function(C,A,B){return true;};YAHOO.widget.AutoComplete.prototype.formatResult=function(B,D,A){var C=(A)?A:"";return C;};YAHOO.widget.AutoComplete.prototype.doBeforeExpandContainer=function(D,A,C,B){return true;};YAHOO.widget.AutoComplete.prototype.destroy=function(){var B=this.toString();var A=this._elTextbox;var D=this._elContainer;this.textboxFocusEvent.unsubscribeAll();this.textboxKeyEvent.unsubscribeAll();this.dataRequestEvent.unsubscribeAll();this.dataReturnEvent.unsubscribeAll();this.dataErrorEvent.unsubscribeAll();this.containerPopulateEvent.unsubscribeAll();this.containerExpandEvent.unsubscribeAll();this.typeAheadEvent.unsubscribeAll();this.itemMouseOverEvent.unsubscribeAll();this.itemMouseOutEvent.unsubscribeAll();this.itemArrowToEvent.unsubscribeAll();this.itemArrowFromEvent.unsubscribeAll();this.itemSelectEvent.unsubscribeAll();this.unmatchedItemSelectEvent.unsubscribeAll();this.selectionEnforceEvent.unsubscribeAll();this.containerCollapseEvent.unsubscribeAll();this.textboxBlurEvent.unsubscribeAll();this.textboxChangeEvent.unsubscribeAll();YAHOO.util.Event.purgeElement(A,true);YAHOO.util.Event.purgeElement(D,true);D.innerHTML="";for(var C in this){if(YAHOO.lang.hasOwnProperty(this,C)){this[C]=null;}}};YAHOO.widget.AutoComplete.prototype.textboxFocusEvent=null;YAHOO.widget.AutoComplete.prototype.textboxKeyEvent=null;YAHOO.widget.AutoComplete.prototype.dataRequestEvent=null;YAHOO.widget.AutoComplete.prototype.dataReturnEvent=null;YAHOO.widget.AutoComplete.prototype.dataErrorEvent=null;YAHOO.widget.AutoComplete.prototype.containerPopulateEvent=null;YAHOO.widget.AutoComplete.prototype.containerExpandEvent=null;YAHOO.widget.AutoComplete.prototype.typeAheadEvent=null;YAHOO.widget.AutoComplete.prototype.itemMouseOverEvent=null;YAHOO.widget.AutoComplete.prototype.itemMouseOutEvent=null; +YAHOO.widget.AutoComplete.prototype.itemArrowToEvent=null;YAHOO.widget.AutoComplete.prototype.itemArrowFromEvent=null;YAHOO.widget.AutoComplete.prototype.itemSelectEvent=null;YAHOO.widget.AutoComplete.prototype.unmatchedItemSelectEvent=null;YAHOO.widget.AutoComplete.prototype.selectionEnforceEvent=null;YAHOO.widget.AutoComplete.prototype.containerCollapseEvent=null;YAHOO.widget.AutoComplete.prototype.textboxBlurEvent=null;YAHOO.widget.AutoComplete.prototype.textboxChangeEvent=null;YAHOO.widget.AutoComplete._nIndex=0;YAHOO.widget.AutoComplete.prototype._sName=null;YAHOO.widget.AutoComplete.prototype._elTextbox=null;YAHOO.widget.AutoComplete.prototype._elContainer=null;YAHOO.widget.AutoComplete.prototype._elContent=null;YAHOO.widget.AutoComplete.prototype._elHeader=null;YAHOO.widget.AutoComplete.prototype._elBody=null;YAHOO.widget.AutoComplete.prototype._elFooter=null;YAHOO.widget.AutoComplete.prototype._elShadow=null;YAHOO.widget.AutoComplete.prototype._elIFrame=null;YAHOO.widget.AutoComplete.prototype._bFocused=false;YAHOO.widget.AutoComplete.prototype._oAnim=null;YAHOO.widget.AutoComplete.prototype._bContainerOpen=false;YAHOO.widget.AutoComplete.prototype._bOverContainer=false;YAHOO.widget.AutoComplete.prototype._elList=null;YAHOO.widget.AutoComplete.prototype._nDisplayedItems=0;YAHOO.widget.AutoComplete.prototype._sCurQuery=null;YAHOO.widget.AutoComplete.prototype._sPastSelections="";YAHOO.widget.AutoComplete.prototype._sInitInputValue=null;YAHOO.widget.AutoComplete.prototype._elCurListItem=null;YAHOO.widget.AutoComplete.prototype._elCurPrehighlightItem=null;YAHOO.widget.AutoComplete.prototype._bItemSelected=false;YAHOO.widget.AutoComplete.prototype._nKeyCode=null;YAHOO.widget.AutoComplete.prototype._nDelayID=-1;YAHOO.widget.AutoComplete.prototype._nTypeAheadDelayID=-1;YAHOO.widget.AutoComplete.prototype._iFrameSrc="javascript:false;";YAHOO.widget.AutoComplete.prototype._queryInterval=null;YAHOO.widget.AutoComplete.prototype._sLastTextboxValue=null;YAHOO.widget.AutoComplete.prototype._initProps=function(){var B=this.minQueryLength;if(!YAHOO.lang.isNumber(B)){this.minQueryLength=1;}var E=this.maxResultsDisplayed;if(!YAHOO.lang.isNumber(E)||(E<1)){this.maxResultsDisplayed=10;}var F=this.queryDelay;if(!YAHOO.lang.isNumber(F)||(F<0)){this.queryDelay=0.2;}var C=this.typeAheadDelay;if(!YAHOO.lang.isNumber(C)||(C<0)){this.typeAheadDelay=0.2;}var A=this.delimChar;if(YAHOO.lang.isString(A)&&(A.length>0)){this.delimChar=[A];}else{if(!YAHOO.lang.isArray(A)){this.delimChar=null;}}var D=this.animSpeed;if((this.animHoriz||this.animVert)&&YAHOO.util.Anim){if(!YAHOO.lang.isNumber(D)||(D<0)){this.animSpeed=0.3;}if(!this._oAnim){this._oAnim=new YAHOO.util.Anim(this._elContent,{},this.animSpeed);}else{this._oAnim.duration=this.animSpeed;}}if(this.forceSelection&&A){}};YAHOO.widget.AutoComplete.prototype._initContainerHelperEls=function(){if(this.useShadow&&!this._elShadow){var A=document.createElement("div");A.className="yui-ac-shadow";A.style.width=0;A.style.height=0;this._elShadow=this._elContainer.appendChild(A);}if(this.useIFrame&&!this._elIFrame){var B=document.createElement("iframe");B.src=this._iFrameSrc;B.frameBorder=0;B.scrolling="no";B.style.position="absolute";B.style.width=0;B.style.height=0;B.style.padding=0;B.tabIndex=-1;B.role="presentation";B.title="Presentational iframe shim";this._elIFrame=this._elContainer.appendChild(B);}};YAHOO.widget.AutoComplete.prototype._initContainerEl=function(){YAHOO.util.Dom.addClass(this._elContainer,"yui-ac-container");if(!this._elContent){var C=document.createElement("div");C.className="yui-ac-content";C.style.display="none";this._elContent=this._elContainer.appendChild(C);var B=document.createElement("div");B.className="yui-ac-hd";B.style.display="none";this._elHeader=this._elContent.appendChild(B);var D=document.createElement("div");D.className="yui-ac-bd";this._elBody=this._elContent.appendChild(D);var A=document.createElement("div");A.className="yui-ac-ft";A.style.display="none";this._elFooter=this._elContent.appendChild(A);}else{}};YAHOO.widget.AutoComplete.prototype._initListEl=function(){var C=this.maxResultsDisplayed,A=this._elList||document.createElement("ul"),B;while(A.childNodes.length=18&&A<=20)||(A==27)||(A>=33&&A<=35)||(A>=36&&A<=40)||(A>=44&&A<=45)||(A==229)){return true;}return false;};YAHOO.widget.AutoComplete.prototype._sendQuery=function(D){if(this.minQueryLength<0){this._toggleContainer(false);return;}if(this.delimChar){var A=this._extractQuery(D);D=A.query;this._sPastSelections=A.previous;}if((D&&(D.length0)){if(this._nDelayID!=-1){clearTimeout(this._nDelayID);}this._toggleContainer(false);return;}D=encodeURIComponent(D);this._nDelayID=-1;if(this.dataSource.queryMatchSubset||this.queryMatchSubset){var C=this.getSubsetMatches(D);if(C){this.handleResponse(D,C,{query:D});return; +}}if(this.dataSource.responseStripAfter){this.dataSource.doBeforeParseData=this.preparseRawResponse;}if(this.applyLocalFilter){this.dataSource.doBeforeCallback=this.filterResults;}var B=this.generateRequest(D);this.dataRequestEvent.fire(this,D,B);this.dataSource.sendRequest(B,{success:this.handleResponse,failure:this.handleResponse,scope:this,argument:{query:D}});};YAHOO.widget.AutoComplete.prototype._populateListItem=function(B,A,C){B.innerHTML=this.formatResult(A,C,B._sResultMatch);};YAHOO.widget.AutoComplete.prototype._populateList=function(K,F,C){if(this._nTypeAheadDelayID!=-1){clearTimeout(this._nTypeAheadDelayID);}K=(C&&C.query)?C.query:K;var H=this.doBeforeLoadData(K,F,C);if(H&&!F.error){this.dataReturnEvent.fire(this,K,F.results);if(this._bFocused){var M=decodeURIComponent(K);this._sCurQuery=M;this._bItemSelected=false;var R=F.results,A=Math.min(R.length,this.maxResultsDisplayed),J=(this.dataSource.responseSchema.fields)?(this.dataSource.responseSchema.fields[0].key||this.dataSource.responseSchema.fields[0]):0;if(A>0){if(!this._elList||(this._elList.childNodes.length=0;Q--){var P=I[Q],E=R[Q];if(this.resultTypeList){var B=[];B[0]=(YAHOO.lang.isString(E))?E:E[J]||E[this.key];var L=this.dataSource.responseSchema.fields;if(YAHOO.lang.isArray(L)&&(L.length>1)){for(var N=1,S=L.length;N=A;O--){G=I[O];G.style.display="none";}}this._nDisplayedItems=A;this.containerPopulateEvent.fire(this,K,R);if(this.autoHighlight){var D=this._elList.firstChild;this._toggleHighlight(D,"to");this.itemArrowToEvent.fire(this,D);this._typeAhead(D,K);}else{this._toggleHighlight(this._elCurListItem,"from");}H=this._doBeforeExpandContainer(this._elTextbox,this._elContainer,K,R);this._toggleContainer(H);}else{this._toggleContainer(false);}return;}}else{this.dataErrorEvent.fire(this,K,F);}};YAHOO.widget.AutoComplete.prototype._doBeforeExpandContainer=function(D,A,C,B){if(this.autoSnapContainer){this.snapContainer();}return this.doBeforeExpandContainer(D,A,C,B);};YAHOO.widget.AutoComplete.prototype._clearSelection=function(){var A=(this.delimChar)?this._extractQuery(this._elTextbox.value):{previous:"",query:this._elTextbox.value};this._elTextbox.value=A.previous;this.selectionEnforceEvent.fire(this,A.query);};YAHOO.widget.AutoComplete.prototype._textMatchesOption=function(){var A=null;for(var B=0;B=0;B--){G=H.lastIndexOf(C[B]);if(G>F){F=G;}}if(C[B]==" "){for(var A=C.length-1;A>=0;A--){if(H[F-1]==C[A]){F--;break;}}}if(F>-1){E=F+1;while(H.charAt(E)==" "){E+=1;}D=H.substring(0,E);H=H.substr(E);}else{D="";}return{previous:D,query:H};};YAHOO.widget.AutoComplete.prototype._toggleContainerHelpers=function(D){var E=this._elContent.offsetWidth+"px";var B=this._elContent.offsetHeight+"px";if(this.useIFrame&&this._elIFrame){var C=this._elIFrame;if(D){C.style.width=E;C.style.height=B;C.style.padding="";}else{C.style.width=0;C.style.height=0;C.style.padding=0;}}if(this.useShadow&&this._elShadow){var A=this._elShadow;if(D){A.style.width=E;A.style.height=B;}else{A.style.width=0;A.style.height=0;}}};YAHOO.widget.AutoComplete.prototype._toggleContainer=function(I){var D=this._elContainer;if(this.alwaysShowContainer&&this._bContainerOpen){return;}if(!I){this._toggleHighlight(this._elCurListItem,"from");this._nDisplayedItems=0;this._sCurQuery=null;if(this._elContent.style.display=="none"){return;}}var A=this._oAnim;if(A&&A.getEl()&&(this.animHoriz||this.animVert)){if(A.isAnimated()){A.stop(true);}var G=this._elContent.cloneNode(true);D.appendChild(G);G.style.top="-9000px";G.style.width="";G.style.height="";G.style.display="";var F=G.offsetWidth;var C=G.offsetHeight;var B=(this.animHoriz)?0:F;var E=(this.animVert)?0:C;A.attributes=(I)?{width:{to:F},height:{to:C}}:{width:{to:B},height:{to:E}};if(I&&!this._bContainerOpen){this._elContent.style.width=B+"px";this._elContent.style.height=E+"px";}else{this._elContent.style.width=F+"px";this._elContent.style.height=C+"px";}D.removeChild(G);G=null;var H=this;var J=function(){A.onComplete.unsubscribeAll();if(I){H._toggleContainerHelpers(true);H._bContainerOpen=I;H.containerExpandEvent.fire(H);}else{H._elContent.style.display="none";H._bContainerOpen=I;H.containerCollapseEvent.fire(H);}};this._toggleContainerHelpers(false);this._elContent.style.display="";A.onComplete.subscribe(J);A.animate();}else{if(I){this._elContent.style.display="";this._toggleContainerHelpers(true);this._bContainerOpen=I;this.containerExpandEvent.fire(this);}else{this._toggleContainerHelpers(false);this._elContent.style.display="none";this._bContainerOpen=I;this.containerCollapseEvent.fire(this);}}};YAHOO.widget.AutoComplete.prototype._toggleHighlight=function(A,C){if(A){var B=this.highlightClassName; +if(this._elCurListItem){YAHOO.util.Dom.removeClass(this._elCurListItem,B);this._elCurListItem=null;}if((C=="to")&&B){YAHOO.util.Dom.addClass(A,B);this._elCurListItem=A;}}};YAHOO.widget.AutoComplete.prototype._togglePrehighlight=function(B,C){var A=this.prehighlightClassName;if(this._elCurPrehighlightItem){YAHOO.util.Dom.removeClass(this._elCurPrehighlightItem,A);}if(B==this._elCurListItem){return;}if((C=="mouseover")&&A){YAHOO.util.Dom.addClass(B,A);this._elCurPrehighlightItem=B;}else{YAHOO.util.Dom.removeClass(B,A);}};YAHOO.widget.AutoComplete.prototype._updateValue=function(C){if(!this.suppressInputUpdate){var F=this._elTextbox;var E=(this.delimChar)?(this.delimChar[0]||this.delimChar):null;var B=C._sResultMatch;var D="";if(E){D=this._sPastSelections;D+=B+E;if(E!=" "){D+=" ";}}else{D=B;}F.value=D;if(F.type=="textarea"){F.scrollTop=F.scrollHeight;}var A=F.value.length;this._selectText(F,A,A);this._elCurListItem=C;}};YAHOO.widget.AutoComplete.prototype._selectItem=function(A){this._bItemSelected=true;this._updateValue(A);this._sPastSelections=this._elTextbox.value;this._clearInterval();this.itemSelectEvent.fire(this,A,A._oResultData);this._toggleContainer(false);};YAHOO.widget.AutoComplete.prototype._jumpSelection=function(){if(this._elCurListItem){this._selectItem(this._elCurListItem);}else{this._toggleContainer(false);}};YAHOO.widget.AutoComplete.prototype._moveSelection=function(G){if(this._bContainerOpen){var H=this._elCurListItem,D=-1;if(H){D=H._nItemIndex;}var E=(G==40)?(D+1):(D-1);if(E<-2||E>=this._nDisplayedItems){return;}if(H){this._toggleHighlight(H,"from");this.itemArrowFromEvent.fire(this,H);}if(E==-1){if(this.delimChar){this._elTextbox.value=this._sPastSelections+this._sCurQuery;}else{this._elTextbox.value=this._sCurQuery;}return;}if(E==-2){this._toggleContainer(false);return;}var F=this._elList.childNodes[E],B=this._elContent,C=YAHOO.util.Dom.getStyle(B,"overflow"),I=YAHOO.util.Dom.getStyle(B,"overflowY"),A=((C=="auto")||(C=="scroll")||(I=="auto")||(I=="scroll"));if(A&&(E>-1)&&(E(B.scrollTop+B.offsetHeight)){B.scrollTop=(F.offsetTop+F.offsetHeight)-B.offsetHeight;}else{if((F.offsetTop+F.offsetHeight)(B.scrollTop+B.offsetHeight)){this._elContent.scrollTop=(F.offsetTop+F.offsetHeight)-B.offsetHeight;}}}}this._toggleHighlight(F,"to");this.itemArrowToEvent.fire(this,F);if(this.typeAhead){this._updateValue(F);}}};YAHOO.widget.AutoComplete.prototype._onContainerMouseover=function(A,C){var D=YAHOO.util.Event.getTarget(A);var B=D.nodeName.toLowerCase();while(D&&(B!="table")){switch(B){case"body":return;case"li":if(C.prehighlightClassName){C._togglePrehighlight(D,"mouseover");}else{C._toggleHighlight(D,"to");}C.itemMouseOverEvent.fire(C,D);break;case"div":if(YAHOO.util.Dom.hasClass(D,"yui-ac-container")){C._bOverContainer=true;return;}break;default:break;}D=D.parentNode;if(D){B=D.nodeName.toLowerCase();}}};YAHOO.widget.AutoComplete.prototype._onContainerMouseout=function(A,C){var D=YAHOO.util.Event.getTarget(A);var B=D.nodeName.toLowerCase();while(D&&(B!="table")){switch(B){case"body":return;case"li":if(C.prehighlightClassName){C._togglePrehighlight(D,"mouseout");}else{C._toggleHighlight(D,"from");}C.itemMouseOutEvent.fire(C,D);break;case"ul":C._toggleHighlight(C._elCurListItem,"to");break;case"div":if(YAHOO.util.Dom.hasClass(D,"yui-ac-container")){C._bOverContainer=false;return;}break;default:break;}D=D.parentNode;if(D){B=D.nodeName.toLowerCase();}}};YAHOO.widget.AutoComplete.prototype._onContainerClick=function(A,C){var D=YAHOO.util.Event.getTarget(A);var B=D.nodeName.toLowerCase();while(D&&(B!="table")){switch(B){case"body":return;case"li":C._toggleHighlight(D,"to");C._selectItem(D);return;default:break;}D=D.parentNode;if(D){B=D.nodeName.toLowerCase();}}};YAHOO.widget.AutoComplete.prototype._onContainerScroll=function(A,B){B._focus();};YAHOO.widget.AutoComplete.prototype._onContainerResize=function(A,B){B._toggleContainerHelpers(B._bContainerOpen);};YAHOO.widget.AutoComplete.prototype._onTextboxKeyDown=function(A,B){var C=A.keyCode;if(B._nTypeAheadDelayID!=-1){clearTimeout(B._nTypeAheadDelayID);}switch(C){case 9:if(!YAHOO.env.ua.opera&&(navigator.userAgent.toLowerCase().indexOf("mac")==-1)||(YAHOO.env.ua.webkit>420)){if(B._elCurListItem){if(B.delimChar&&(B._nKeyCode!=C)){if(B._bContainerOpen){YAHOO.util.Event.stopEvent(A);}}B._selectItem(B._elCurListItem);}else{B._toggleContainer(false);}}break;case 13:if(!YAHOO.env.ua.opera&&(navigator.userAgent.toLowerCase().indexOf("mac")==-1)||(YAHOO.env.ua.webkit>420)){if(B._elCurListItem){if(B._nKeyCode!=C){if(B._bContainerOpen){YAHOO.util.Event.stopEvent(A);}}B._selectItem(B._elCurListItem);}else{B._toggleContainer(false);}}break;case 27:B._toggleContainer(false);return;case 39:B._jumpSelection();break;case 38:if(B._bContainerOpen){YAHOO.util.Event.stopEvent(A);B._moveSelection(C);}break;case 40:if(B._bContainerOpen){YAHOO.util.Event.stopEvent(A);B._moveSelection(C);}break;default:B._bItemSelected=false;B._toggleHighlight(B._elCurListItem,"from");B.textboxKeyEvent.fire(B,C);break;}if(C===18){B._enableIntervalDetection();}B._nKeyCode=C;};YAHOO.widget.AutoComplete.prototype._onTextboxKeyPress=function(A,B){var C=A.keyCode;if(YAHOO.env.ua.opera||(navigator.userAgent.toLowerCase().indexOf("mac")!=-1)&&(YAHOO.env.ua.webkit<420)){switch(C){case 9:if(B._bContainerOpen){if(B.delimChar){YAHOO.util.Event.stopEvent(A);}if(B._elCurListItem){B._selectItem(B._elCurListItem);}else{B._toggleContainer(false);}}break;case 13:if(B._bContainerOpen){YAHOO.util.Event.stopEvent(A);if(B._elCurListItem){B._selectItem(B._elCurListItem);}else{B._toggleContainer(false);}}break;default:break;}}else{if(C==229){B._enableIntervalDetection();}}};YAHOO.widget.AutoComplete.prototype._onTextboxKeyUp=function(A,C){var B=this.value;C._initProps();var D=A.keyCode;if(C._isIgnoreKey(D)){return; +}if(C._nDelayID!=-1){clearTimeout(C._nDelayID);}C._nDelayID=setTimeout(function(){C._sendQuery(B);},(C.queryDelay*1000));};YAHOO.widget.AutoComplete.prototype._onTextboxFocus=function(A,B){if(!B._bFocused){B._elTextbox.setAttribute("autocomplete","off");B._bFocused=true;B._sInitInputValue=B._elTextbox.value;B.textboxFocusEvent.fire(B);}};YAHOO.widget.AutoComplete.prototype._onTextboxBlur=function(A,C){if(!C._bOverContainer||(C._nKeyCode==9)){if(!C._bItemSelected){var B=C._textMatchesOption();if(!C._bContainerOpen||(C._bContainerOpen&&(B===null))){if(C.forceSelection){C._clearSelection();}else{C.unmatchedItemSelectEvent.fire(C,C._sCurQuery);}}else{if(C.forceSelection){C._selectItem(B);}}}C._clearInterval();C._bFocused=false;if(C._sInitInputValue!==C._elTextbox.value){C.textboxChangeEvent.fire(C);}C.textboxBlurEvent.fire(C);C._toggleContainer(false);}else{C._focus();}};YAHOO.widget.AutoComplete.prototype._onWindowUnload=function(A,B){if(B&&B._elTextbox&&B.allowBrowserAutocomplete){B._elTextbox.setAttribute("autocomplete","on");}};YAHOO.widget.AutoComplete.prototype.doBeforeSendQuery=function(A){return this.generateRequest(A);};YAHOO.widget.AutoComplete.prototype.getListItems=function(){var C=[],B=this._elList.childNodes;for(var A=B.length-1;A>=0;A--){C[A]=B[A];}return C;};YAHOO.widget.AutoComplete._cloneObject=function(D){if(!YAHOO.lang.isValue(D)){return D;}var F={};if(YAHOO.lang.isFunction(D)){F=D;}else{if(YAHOO.lang.isArray(D)){var E=[];for(var C=0,B=D.length;C + *
  • Navigate with up/down arrow keys and/or mouse to pick a selection
  • + *
  • The drop down container can "roll down" or "fly out" via configurable + * animation
  • + *
  • UI look-and-feel customizable through CSS, including container + * attributes, borders, position, fonts, etc
  • + * + * + * @class AutoComplete + * @constructor + * @param elInput {HTMLElement} DOM element reference of an input field. + * @param elInput {String} String ID of an input field. + * @param elContainer {HTMLElement} DOM element reference of an existing DIV. + * @param elContainer {String} String ID of an existing DIV. + * @param oDataSource {YAHOO.widget.DataSource} DataSource instance. + * @param oConfigs {Object} (optional) Object literal of configuration params. + */ +YAHOO.widget.AutoComplete = function(elInput,elContainer,oDataSource,oConfigs) { + if(elInput && elContainer && oDataSource) { + // Validate DataSource + if(oDataSource && YAHOO.lang.isFunction(oDataSource.sendRequest)) { + this.dataSource = oDataSource; + } + else { + return; + } + + // YAHOO.widget.DataSource schema backwards compatibility + // Converted deprecated schema into supported schema + // First assume key data is held in position 0 of results array + this.key = 0; + var schema = oDataSource.responseSchema; + // An old school schema has been defined in the deprecated DataSource constructor + if(oDataSource._aDeprecatedSchema) { + var aDeprecatedSchema = oDataSource._aDeprecatedSchema; + if(YAHOO.lang.isArray(aDeprecatedSchema)) { + + if((oDataSource.responseType === YAHOO.util.DataSourceBase.TYPE_JSON) || + (oDataSource.responseType === YAHOO.util.DataSourceBase.TYPE_UNKNOWN)) { // Used to default to unknown + // Store the resultsList + schema.resultsList = aDeprecatedSchema[0]; + // Store the key + this.key = aDeprecatedSchema[1]; + // Only resultsList and key are defined, so grab all the data + schema.fields = (aDeprecatedSchema.length < 3) ? null : aDeprecatedSchema.slice(1); + } + else if(oDataSource.responseType === YAHOO.util.DataSourceBase.TYPE_XML) { + schema.resultNode = aDeprecatedSchema[0]; + this.key = aDeprecatedSchema[1]; + schema.fields = aDeprecatedSchema.slice(1); + } + else if(oDataSource.responseType === YAHOO.util.DataSourceBase.TYPE_TEXT) { + schema.recordDelim = aDeprecatedSchema[0]; + schema.fieldDelim = aDeprecatedSchema[1]; + } + oDataSource.responseSchema = schema; + } + } + + // Validate input element + if(YAHOO.util.Dom.inDocument(elInput)) { + if(YAHOO.lang.isString(elInput)) { + this._sName = "instance" + YAHOO.widget.AutoComplete._nIndex + " " + elInput; + this._elTextbox = document.getElementById(elInput); + } + else { + this._sName = (elInput.id) ? + "instance" + YAHOO.widget.AutoComplete._nIndex + " " + elInput.id: + "instance" + YAHOO.widget.AutoComplete._nIndex; + this._elTextbox = elInput; + } + YAHOO.util.Dom.addClass(this._elTextbox, "yui-ac-input"); + } + else { + return; + } + + // Validate container element + if(YAHOO.util.Dom.inDocument(elContainer)) { + if(YAHOO.lang.isString(elContainer)) { + this._elContainer = document.getElementById(elContainer); + } + else { + this._elContainer = elContainer; + } + if(this._elContainer.style.display == "none") { + } + + // For skinning + var elParent = this._elContainer.parentNode; + var elTag = elParent.tagName.toLowerCase(); + if(elTag == "div") { + YAHOO.util.Dom.addClass(elParent, "yui-ac"); + } + else { + } + } + else { + return; + } + + // Default applyLocalFilter setting is to enable for local sources + if(this.dataSource.dataType === YAHOO.util.DataSourceBase.TYPE_LOCAL) { + this.applyLocalFilter = true; + } + + // Set any config params passed in to override defaults + if(oConfigs && (oConfigs.constructor == Object)) { + for(var sConfig in oConfigs) { + if(sConfig) { + this[sConfig] = oConfigs[sConfig]; + } + } + } + + // Initialization sequence + this._initContainerEl(); + this._initProps(); + this._initListEl(); + this._initContainerHelperEls(); + + // Set up events + var oSelf = this; + var elTextbox = this._elTextbox; + + // Dom events + YAHOO.util.Event.addListener(elTextbox,"keyup",oSelf._onTextboxKeyUp,oSelf); + YAHOO.util.Event.addListener(elTextbox,"keydown",oSelf._onTextboxKeyDown,oSelf); + YAHOO.util.Event.addListener(elTextbox,"focus",oSelf._onTextboxFocus,oSelf); + YAHOO.util.Event.addListener(elTextbox,"blur",oSelf._onTextboxBlur,oSelf); + YAHOO.util.Event.addListener(elContainer,"mouseover",oSelf._onContainerMouseover,oSelf); + YAHOO.util.Event.addListener(elContainer,"mouseout",oSelf._onContainerMouseout,oSelf); + YAHOO.util.Event.addListener(elContainer,"click",oSelf._onContainerClick,oSelf); + YAHOO.util.Event.addListener(elContainer,"scroll",oSelf._onContainerScroll,oSelf); + YAHOO.util.Event.addListener(elContainer,"resize",oSelf._onContainerResize,oSelf); + YAHOO.util.Event.addListener(elTextbox,"keypress",oSelf._onTextboxKeyPress,oSelf); + YAHOO.util.Event.addListener(window,"unload",oSelf._onWindowUnload,oSelf); + + // Custom events + this.textboxFocusEvent = new YAHOO.util.CustomEvent("textboxFocus", this); + this.textboxKeyEvent = new YAHOO.util.CustomEvent("textboxKey", this); + this.dataRequestEvent = new YAHOO.util.CustomEvent("dataRequest", this); + this.dataReturnEvent = new YAHOO.util.CustomEvent("dataReturn", this); + this.dataErrorEvent = new YAHOO.util.CustomEvent("dataError", this); + this.containerPopulateEvent = new YAHOO.util.CustomEvent("containerPopulate", this); + this.containerExpandEvent = new YAHOO.util.CustomEvent("containerExpand", this); + this.typeAheadEvent = new YAHOO.util.CustomEvent("typeAhead", this); + this.itemMouseOverEvent = new YAHOO.util.CustomEvent("itemMouseOver", this); + this.itemMouseOutEvent = new YAHOO.util.CustomEvent("itemMouseOut", this); + this.itemArrowToEvent = new YAHOO.util.CustomEvent("itemArrowTo", this); + this.itemArrowFromEvent = new YAHOO.util.CustomEvent("itemArrowFrom", this); + this.itemSelectEvent = new YAHOO.util.CustomEvent("itemSelect", this); + this.unmatchedItemSelectEvent = new YAHOO.util.CustomEvent("unmatchedItemSelect", this); + this.selectionEnforceEvent = new YAHOO.util.CustomEvent("selectionEnforce", this); + this.containerCollapseEvent = new YAHOO.util.CustomEvent("containerCollapse", this); + this.textboxBlurEvent = new YAHOO.util.CustomEvent("textboxBlur", this); + this.textboxChangeEvent = new YAHOO.util.CustomEvent("textboxChange", this); + + // Finish up + elTextbox.setAttribute("autocomplete","off"); + YAHOO.widget.AutoComplete._nIndex++; + } + // Required arguments were not found + else { + } +}; + +///////////////////////////////////////////////////////////////////////////// +// +// Public member variables +// +///////////////////////////////////////////////////////////////////////////// + +/** + * The DataSource object that encapsulates the data used for auto completion. + * This object should be an inherited object from YAHOO.widget.DataSource. + * + * @property dataSource + * @type YAHOO.widget.DataSource + */ +YAHOO.widget.AutoComplete.prototype.dataSource = null; + +/** + * By default, results from local DataSources will pass through the filterResults + * method to apply a client-side matching algorithm. + * + * @property applyLocalFilter + * @type Boolean + * @default true for local arrays and json, otherwise false + */ +YAHOO.widget.AutoComplete.prototype.applyLocalFilter = null; + +/** + * When applyLocalFilter is true, the local filtering algorthim can have case sensitivity + * enabled. + * + * @property queryMatchCase + * @type Boolean + * @default false + */ +YAHOO.widget.AutoComplete.prototype.queryMatchCase = false; + +/** + * When applyLocalFilter is true, results can be locally filtered to return + * matching strings that "contain" the query string rather than simply "start with" + * the query string. + * + * @property queryMatchContains + * @type Boolean + * @default false + */ +YAHOO.widget.AutoComplete.prototype.queryMatchContains = false; + +/** + * Enables query subset matching. When the DataSource's cache is enabled and queryMatchSubset is + * true, substrings of queries will return matching cached results. For + * instance, if the first query is for "abc" susequent queries that start with + * "abc", like "abcd", will be queried against the cache, and not the live data + * source. Recommended only for DataSources that return comprehensive results + * for queries with very few characters. + * + * @property queryMatchSubset + * @type Boolean + * @default false + * + */ +YAHOO.widget.AutoComplete.prototype.queryMatchSubset = false; + +/** + * Number of characters that must be entered before querying for results. A negative value + * effectively turns off the widget. A value of 0 allows queries of null or empty string + * values. + * + * @property minQueryLength + * @type Number + * @default 1 + */ +YAHOO.widget.AutoComplete.prototype.minQueryLength = 1; + +/** + * Maximum number of results to display in results container. + * + * @property maxResultsDisplayed + * @type Number + * @default 10 + */ +YAHOO.widget.AutoComplete.prototype.maxResultsDisplayed = 10; + +/** + * Number of seconds to delay before submitting a query request. If a query + * request is received before a previous one has completed its delay, the + * previous request is cancelled and the new request is set to the delay. If + * typeAhead is also enabled, this value must always be less than the typeAheadDelay + * in order to avoid certain race conditions. + * + * @property queryDelay + * @type Number + * @default 0.2 + */ +YAHOO.widget.AutoComplete.prototype.queryDelay = 0.2; + +/** + * If typeAhead is true, number of seconds to delay before updating input with + * typeAhead value. In order to prevent certain race conditions, this value must + * always be greater than the queryDelay. + * + * @property typeAheadDelay + * @type Number + * @default 0.5 + */ +YAHOO.widget.AutoComplete.prototype.typeAheadDelay = 0.5; + +/** + * When IME usage is detected or interval detection is explicitly enabled, + * AutoComplete will detect the input value at the given interval and send a + * query if the value has changed. + * + * @property queryInterval + * @type Number + * @default 500 + */ +YAHOO.widget.AutoComplete.prototype.queryInterval = 500; + +/** + * Class name of a highlighted item within results container. + * + * @property highlightClassName + * @type String + * @default "yui-ac-highlight" + */ +YAHOO.widget.AutoComplete.prototype.highlightClassName = "yui-ac-highlight"; + +/** + * Class name of a pre-highlighted item within results container. + * + * @property prehighlightClassName + * @type String + */ +YAHOO.widget.AutoComplete.prototype.prehighlightClassName = null; + +/** + * Query delimiter. A single character separator for multiple delimited + * selections. Multiple delimiter characteres may be defined as an array of + * strings. A null value or empty string indicates that query results cannot + * be delimited. This feature is not recommended if you need forceSelection to + * be true. + * + * @property delimChar + * @type String | String[] + */ +YAHOO.widget.AutoComplete.prototype.delimChar = null; + +/** + * Whether or not the first item in results container should be automatically highlighted + * on expand. + * + * @property autoHighlight + * @type Boolean + * @default true + */ +YAHOO.widget.AutoComplete.prototype.autoHighlight = true; + +/** + * If autohighlight is enabled, whether or not the input field should be automatically updated + * with the first query result as the user types, auto-selecting the substring portion + * of the first result that the user has not yet typed. + * + * @property typeAhead + * @type Boolean + * @default false + */ +YAHOO.widget.AutoComplete.prototype.typeAhead = false; + +/** + * Whether or not to animate the expansion/collapse of the results container in the + * horizontal direction. + * + * @property animHoriz + * @type Boolean + * @default false + */ +YAHOO.widget.AutoComplete.prototype.animHoriz = false; + +/** + * Whether or not to animate the expansion/collapse of the results container in the + * vertical direction. + * + * @property animVert + * @type Boolean + * @default true + */ +YAHOO.widget.AutoComplete.prototype.animVert = true; + +/** + * Speed of container expand/collapse animation, in seconds.. + * + * @property animSpeed + * @type Number + * @default 0.3 + */ +YAHOO.widget.AutoComplete.prototype.animSpeed = 0.3; + +/** + * Whether or not to force the user's selection to match one of the query + * results. Enabling this feature essentially transforms the input field into a + * <select> field. This feature is not recommended with delimiter character(s) + * defined. + * + * @property forceSelection + * @type Boolean + * @default false + */ +YAHOO.widget.AutoComplete.prototype.forceSelection = false; + +/** + * Whether or not to allow browsers to cache user-typed input in the input + * field. Disabling this feature will prevent the widget from setting the + * autocomplete="off" on the input field. When autocomplete="off" + * and users click the back button after form submission, user-typed input can + * be prefilled by the browser from its cache. This caching of user input may + * not be desired for sensitive data, such as credit card numbers, in which + * case, implementers should consider setting allowBrowserAutocomplete to false. + * + * @property allowBrowserAutocomplete + * @type Boolean + * @default true + */ +YAHOO.widget.AutoComplete.prototype.allowBrowserAutocomplete = true; + +/** + * Enabling this feature prevents the toggling of the container to a collapsed state. + * Setting to true does not automatically trigger the opening of the container. + * Implementers are advised to pre-load the container with an explicit "sendQuery()" call. + * + * @property alwaysShowContainer + * @type Boolean + * @default false + */ +YAHOO.widget.AutoComplete.prototype.alwaysShowContainer = false; + +/** + * Whether or not to use an iFrame to layer over Windows form elements in + * IE. Set to true only when the results container will be on top of a + * <select> field in IE and thus exposed to the IE z-index bug (i.e., + * 5.5 < IE < 7). + * + * @property useIFrame + * @type Boolean + * @default false + */ +YAHOO.widget.AutoComplete.prototype.useIFrame = false; + +/** + * Whether or not the results container should have a shadow. + * + * @property useShadow + * @type Boolean + * @default false + */ +YAHOO.widget.AutoComplete.prototype.useShadow = false; + +/** + * Whether or not the input field should be updated with selections. + * + * @property suppressInputUpdate + * @type Boolean + * @default false + */ +YAHOO.widget.AutoComplete.prototype.suppressInputUpdate = false; + +/** + * For backward compatibility to pre-2.6.0 formatResults() signatures, setting + * resultsTypeList to true will take each object literal result returned by + * DataSource and flatten into an array. + * + * @property resultTypeList + * @type Boolean + * @default true + */ +YAHOO.widget.AutoComplete.prototype.resultTypeList = true; + +/** + * For XHR DataSources, AutoComplete will automatically insert a "?" between the server URI and + * the "query" param/value pair. To prevent this behavior, implementers should + * set this value to false. To more fully customize the query syntax, implementers + * should override the generateRequest() method. + * + * @property queryQuestionMark + * @type Boolean + * @default true + */ +YAHOO.widget.AutoComplete.prototype.queryQuestionMark = true; + +/** + * If true, before each time the container expands, the container element will be + * positioned to snap to the bottom-left corner of the input element. If + * autoSnapContainer is set to false, this positioning will not be done. + * + * @property autoSnapContainer + * @type Boolean + * @default true + */ +YAHOO.widget.AutoComplete.prototype.autoSnapContainer = true; + +///////////////////////////////////////////////////////////////////////////// +// +// Public methods +// +///////////////////////////////////////////////////////////////////////////// + + /** + * Public accessor to the unique name of the AutoComplete instance. + * + * @method toString + * @return {String} Unique name of the AutoComplete instance. + */ +YAHOO.widget.AutoComplete.prototype.toString = function() { + return "AutoComplete " + this._sName; +}; + + /** + * Returns DOM reference to input element. + * + * @method getInputEl + * @return {HTMLELement} DOM reference to input element. + */ +YAHOO.widget.AutoComplete.prototype.getInputEl = function() { + return this._elTextbox; +}; + + /** + * Returns DOM reference to container element. + * + * @method getContainerEl + * @return {HTMLELement} DOM reference to container element. + */ +YAHOO.widget.AutoComplete.prototype.getContainerEl = function() { + return this._elContainer; +}; + + /** + * Returns true if widget instance is currently active. + * + * @method isFocused + * @return {Boolean} Returns true if widget instance is currently active. + */ +YAHOO.widget.AutoComplete.prototype.isFocused = function() { + return this._bFocused; +}; + + /** + * Returns true if container is in an expanded state, false otherwise. + * + * @method isContainerOpen + * @return {Boolean} Returns true if container is in an expanded state, false otherwise. + */ +YAHOO.widget.AutoComplete.prototype.isContainerOpen = function() { + return this._bContainerOpen; +}; + +/** + * Public accessor to the <ul> element that displays query results within the results container. + * + * @method getListEl + * @return {HTMLElement[]} Reference to <ul> element within the results container. + */ +YAHOO.widget.AutoComplete.prototype.getListEl = function() { + return this._elList; +}; + +/** + * Public accessor to the matching string associated with a given <li> result. + * + * @method getListItemMatch + * @param elListItem {HTMLElement} Reference to <LI> element. + * @return {String} Matching string. + */ +YAHOO.widget.AutoComplete.prototype.getListItemMatch = function(elListItem) { + if(elListItem._sResultMatch) { + return elListItem._sResultMatch; + } + else { + return null; + } +}; + +/** + * Public accessor to the result data associated with a given <li> result. + * + * @method getListItemData + * @param elListItem {HTMLElement} Reference to <LI> element. + * @return {Object} Result data. + */ +YAHOO.widget.AutoComplete.prototype.getListItemData = function(elListItem) { + if(elListItem._oResultData) { + return elListItem._oResultData; + } + else { + return null; + } +}; + +/** + * Public accessor to the index of the associated with a given <li> result. + * + * @method getListItemIndex + * @param elListItem {HTMLElement} Reference to <LI> element. + * @return {Number} Index. + */ +YAHOO.widget.AutoComplete.prototype.getListItemIndex = function(elListItem) { + if(YAHOO.lang.isNumber(elListItem._nItemIndex)) { + return elListItem._nItemIndex; + } + else { + return null; + } +}; + +/** + * Sets HTML markup for the results container header. This markup will be + * inserted within a <div> tag with a class of "yui-ac-hd". + * + * @method setHeader + * @param sHeader {String} HTML markup for results container header. + */ +YAHOO.widget.AutoComplete.prototype.setHeader = function(sHeader) { + if(this._elHeader) { + var elHeader = this._elHeader; + if(sHeader) { + elHeader.innerHTML = sHeader; + elHeader.style.display = ""; + } + else { + elHeader.innerHTML = ""; + elHeader.style.display = "none"; + } + } +}; + +/** + * Sets HTML markup for the results container footer. This markup will be + * inserted within a <div> tag with a class of "yui-ac-ft". + * + * @method setFooter + * @param sFooter {String} HTML markup for results container footer. + */ +YAHOO.widget.AutoComplete.prototype.setFooter = function(sFooter) { + if(this._elFooter) { + var elFooter = this._elFooter; + if(sFooter) { + elFooter.innerHTML = sFooter; + elFooter.style.display = ""; + } + else { + elFooter.innerHTML = ""; + elFooter.style.display = "none"; + } + } +}; + +/** + * Sets HTML markup for the results container body. This markup will be + * inserted within a <div> tag with a class of "yui-ac-bd". + * + * @method setBody + * @param sBody {String} HTML markup for results container body. + */ +YAHOO.widget.AutoComplete.prototype.setBody = function(sBody) { + if(this._elBody) { + var elBody = this._elBody; + YAHOO.util.Event.purgeElement(elBody, true); + if(sBody) { + elBody.innerHTML = sBody; + elBody.style.display = ""; + } + else { + elBody.innerHTML = ""; + elBody.style.display = "none"; + } + this._elList = null; + } +}; + +/** +* A function that converts an AutoComplete query into a request value which is then +* passed to the DataSource's sendRequest method in order to retrieve data for +* the query. By default, returns a String with the syntax: "query={query}" +* Implementers can customize this method for custom request syntaxes. +* +* @method generateRequest +* @param sQuery {String} Query string +* @return {MIXED} Request +*/ +YAHOO.widget.AutoComplete.prototype.generateRequest = function(sQuery) { + var dataType = this.dataSource.dataType; + + // Transform query string in to a request for remote data + // By default, local data doesn't need a transformation, just passes along the query as is. + if(dataType === YAHOO.util.DataSourceBase.TYPE_XHR) { + // By default, XHR GET requests look like "{scriptURI}?{scriptQueryParam}={sQuery}&{scriptQueryAppend}" + if(!this.dataSource.connMethodPost) { + sQuery = (this.queryQuestionMark ? "?" : "") + (this.dataSource.scriptQueryParam || "query") + "=" + sQuery + + (this.dataSource.scriptQueryAppend ? ("&" + this.dataSource.scriptQueryAppend) : ""); + } + // By default, XHR POST bodies are sent to the {scriptURI} like "{scriptQueryParam}={sQuery}&{scriptQueryAppend}" + else { + sQuery = (this.dataSource.scriptQueryParam || "query") + "=" + sQuery + + (this.dataSource.scriptQueryAppend ? ("&" + this.dataSource.scriptQueryAppend) : ""); + } + } + // By default, remote script node requests look like "{scriptURI}&{scriptCallbackParam}={callbackString}&{scriptQueryParam}={sQuery}&{scriptQueryAppend}" + else if(dataType === YAHOO.util.DataSourceBase.TYPE_SCRIPTNODE) { + sQuery = "&" + (this.dataSource.scriptQueryParam || "query") + "=" + sQuery + + (this.dataSource.scriptQueryAppend ? ("&" + this.dataSource.scriptQueryAppend) : ""); + } + + return sQuery; +}; + +/** + * Makes query request to the DataSource. + * + * @method sendQuery + * @param sQuery {String} Query string. + */ +YAHOO.widget.AutoComplete.prototype.sendQuery = function(sQuery) { + // Activate focus for a new interaction + this._bFocused = true; + + // Adjust programatically sent queries to look like they were input by user + // when delimiters are enabled + var newQuery = (this.delimChar) ? this._elTextbox.value + sQuery : sQuery; + this._sendQuery(newQuery); +}; + +/** + * Snaps container to bottom-left corner of input element + * + * @method snapContainer + */ +YAHOO.widget.AutoComplete.prototype.snapContainer = function() { + var oTextbox = this._elTextbox, + pos = YAHOO.util.Dom.getXY(oTextbox); + pos[1] += YAHOO.util.Dom.get(oTextbox).offsetHeight + 2; + YAHOO.util.Dom.setXY(this._elContainer,pos); +}; + +/** + * Expands container. + * + * @method expandContainer + */ +YAHOO.widget.AutoComplete.prototype.expandContainer = function() { + this._toggleContainer(true); +}; + +/** + * Collapses container. + * + * @method collapseContainer + */ +YAHOO.widget.AutoComplete.prototype.collapseContainer = function() { + this._toggleContainer(false); +}; + +/** + * Clears entire list of suggestions. + * + * @method clearList + */ +YAHOO.widget.AutoComplete.prototype.clearList = function() { + var allItems = this._elList.childNodes, + i=allItems.length-1; + for(; i>-1; i--) { + allItems[i].style.display = "none"; + } +}; + +/** + * Handles subset matching for when queryMatchSubset is enabled. + * + * @method getSubsetMatches + * @param sQuery {String} Query string. + * @return {Object} oParsedResponse or null. + */ +YAHOO.widget.AutoComplete.prototype.getSubsetMatches = function(sQuery) { + var subQuery, oCachedResponse, subRequest; + // Loop through substrings of each cached element's query property... + for(var i = sQuery.length; i >= this.minQueryLength ; i--) { + subRequest = this.generateRequest(sQuery.substr(0,i)); + this.dataRequestEvent.fire(this, subQuery, subRequest); + + // If a substring of the query is found in the cache + oCachedResponse = this.dataSource.getCachedResponse(subRequest); + if(oCachedResponse) { + return this.filterResults.apply(this.dataSource, [sQuery, oCachedResponse, oCachedResponse, {scope:this}]); + } + } + return null; +}; + +/** + * Executed by DataSource (within DataSource scope via doBeforeParseData()) to + * handle responseStripAfter cleanup. + * + * @method preparseRawResponse + * @param sQuery {String} Query string. + * @return {Object} oParsedResponse or null. + */ +YAHOO.widget.AutoComplete.prototype.preparseRawResponse = function(oRequest, oFullResponse, oCallback) { + var nEnd = ((this.responseStripAfter !== "") && (oFullResponse.indexOf)) ? + oFullResponse.indexOf(this.responseStripAfter) : -1; + if(nEnd != -1) { + oFullResponse = oFullResponse.substring(0,nEnd); + } + return oFullResponse; +}; + +/** + * Executed by DataSource (within DataSource scope via doBeforeCallback()) to + * filter results through a simple client-side matching algorithm. + * + * @method filterResults + * @param sQuery {String} Original request. + * @param oFullResponse {Object} Full response object. + * @param oParsedResponse {Object} Parsed response object. + * @param oCallback {Object} Callback object. + * @return {Object} Filtered response object. + */ + +YAHOO.widget.AutoComplete.prototype.filterResults = function(sQuery, oFullResponse, oParsedResponse, oCallback) { + // If AC has passed a query string value back to itself, grab it + if(oCallback && oCallback.argument && oCallback.argument.query) { + sQuery = oCallback.argument.query; + } + + // Only if a query string is available to match against + if(sQuery && sQuery !== "") { + // First make a copy of the oParseResponse + oParsedResponse = YAHOO.widget.AutoComplete._cloneObject(oParsedResponse); + + var oAC = oCallback.scope, + oDS = this, + allResults = oParsedResponse.results, // the array of results + filteredResults = [], // container for filtered results, + nMax = oAC.maxResultsDisplayed, // max to find + bMatchCase = (oDS.queryMatchCase || oAC.queryMatchCase), // backward compat + bMatchContains = (oDS.queryMatchContains || oAC.queryMatchContains); // backward compat + + // Loop through each result object... + for(var i=0, len=allResults.length; i -1))) { + // Stash the match + filteredResults.push(oResult); + } + } + + // Filter no more if maxResultsDisplayed is reached + if(len>nMax && filteredResults.length===nMax) { + break; + } + } + oParsedResponse.results = filteredResults; + } + else { + } + + return oParsedResponse; +}; + +/** + * Handles response for display. This is the callback function method passed to + * YAHOO.util.DataSourceBase#sendRequest so results from the DataSource are + * returned to the AutoComplete instance. + * + * @method handleResponse + * @param sQuery {String} Original request. + * @param oResponse {Object} Response object. + * @param oPayload {MIXED} (optional) Additional argument(s) + */ +YAHOO.widget.AutoComplete.prototype.handleResponse = function(sQuery, oResponse, oPayload) { + if((this instanceof YAHOO.widget.AutoComplete) && this._sName) { + this._populateList(sQuery, oResponse, oPayload); + } +}; + +/** + * Overridable method called before container is loaded with result data. + * + * @method doBeforeLoadData + * @param sQuery {String} Original request. + * @param oResponse {Object} Response object. + * @param oPayload {MIXED} (optional) Additional argument(s) + * @return {Boolean} Return true to continue loading data, false to cancel. + */ +YAHOO.widget.AutoComplete.prototype.doBeforeLoadData = function(sQuery, oResponse, oPayload) { + return true; +}; + +/** + * Overridable method that returns HTML markup for one result to be populated + * as innerHTML of an <LI> element. + * + * @method formatResult + * @param oResultData {Object} Result data object. + * @param sQuery {String} The corresponding query string. + * @param sResultMatch {HTMLElement} The current query string. + * @return {String} HTML markup of formatted result data. + */ +YAHOO.widget.AutoComplete.prototype.formatResult = function(oResultData, sQuery, sResultMatch) { + var sMarkup = (sResultMatch) ? sResultMatch : ""; + return sMarkup; +}; + +/** + * Overridable method called before container expands allows implementers to access data + * and DOM elements. + * + * @method doBeforeExpandContainer + * @param elTextbox {HTMLElement} The text input box. + * @param elContainer {HTMLElement} The container element. + * @param sQuery {String} The query string. + * @param aResults {Object[]} An array of query results. + * @return {Boolean} Return true to continue expanding container, false to cancel the expand. + */ +YAHOO.widget.AutoComplete.prototype.doBeforeExpandContainer = function(elTextbox, elContainer, sQuery, aResults) { + return true; +}; + + +/** + * Nulls out the entire AutoComplete instance and related objects, removes attached + * event listeners, and clears out DOM elements inside the container. After + * calling this method, the instance reference should be expliclitly nulled by + * implementer, as in myAutoComplete = null. Use with caution! + * + * @method destroy + */ +YAHOO.widget.AutoComplete.prototype.destroy = function() { + var instanceName = this.toString(); + var elInput = this._elTextbox; + var elContainer = this._elContainer; + + // Unhook custom events + this.textboxFocusEvent.unsubscribeAll(); + this.textboxKeyEvent.unsubscribeAll(); + this.dataRequestEvent.unsubscribeAll(); + this.dataReturnEvent.unsubscribeAll(); + this.dataErrorEvent.unsubscribeAll(); + this.containerPopulateEvent.unsubscribeAll(); + this.containerExpandEvent.unsubscribeAll(); + this.typeAheadEvent.unsubscribeAll(); + this.itemMouseOverEvent.unsubscribeAll(); + this.itemMouseOutEvent.unsubscribeAll(); + this.itemArrowToEvent.unsubscribeAll(); + this.itemArrowFromEvent.unsubscribeAll(); + this.itemSelectEvent.unsubscribeAll(); + this.unmatchedItemSelectEvent.unsubscribeAll(); + this.selectionEnforceEvent.unsubscribeAll(); + this.containerCollapseEvent.unsubscribeAll(); + this.textboxBlurEvent.unsubscribeAll(); + this.textboxChangeEvent.unsubscribeAll(); + + // Unhook DOM events + YAHOO.util.Event.purgeElement(elInput, true); + YAHOO.util.Event.purgeElement(elContainer, true); + + // Remove DOM elements + elContainer.innerHTML = ""; + + // Null out objects + for(var key in this) { + if(YAHOO.lang.hasOwnProperty(this, key)) { + this[key] = null; + } + } + +}; + +///////////////////////////////////////////////////////////////////////////// +// +// Public events +// +///////////////////////////////////////////////////////////////////////////// + +/** + * Fired when the input field receives focus. + * + * @event textboxFocusEvent + * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance. + */ +YAHOO.widget.AutoComplete.prototype.textboxFocusEvent = null; + +/** + * Fired when the input field receives key input. + * + * @event textboxKeyEvent + * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance. + * @param nKeycode {Number} The keycode number. + */ +YAHOO.widget.AutoComplete.prototype.textboxKeyEvent = null; + +/** + * Fired when the AutoComplete instance makes a request to the DataSource. + * + * @event dataRequestEvent + * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance. + * @param sQuery {String} The query string. + * @param oRequest {Object} The request. + */ +YAHOO.widget.AutoComplete.prototype.dataRequestEvent = null; + +/** + * Fired when the AutoComplete instance receives query results from the data + * source. + * + * @event dataReturnEvent + * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance. + * @param sQuery {String} The query string. + * @param aResults {Object[]} Results array. + */ +YAHOO.widget.AutoComplete.prototype.dataReturnEvent = null; + +/** + * Fired when the AutoComplete instance does not receive query results from the + * DataSource due to an error. + * + * @event dataErrorEvent + * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance. + * @param sQuery {String} The query string. + * @param oResponse {Object} The response object, if available. + */ +YAHOO.widget.AutoComplete.prototype.dataErrorEvent = null; + +/** + * Fired when the results container is populated. + * + * @event containerPopulateEvent + * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance. + */ +YAHOO.widget.AutoComplete.prototype.containerPopulateEvent = null; + +/** + * Fired when the results container is expanded. + * + * @event containerExpandEvent + * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance. + */ +YAHOO.widget.AutoComplete.prototype.containerExpandEvent = null; + +/** + * Fired when the input field has been prefilled by the type-ahead + * feature. + * + * @event typeAheadEvent + * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance. + * @param sQuery {String} The query string. + * @param sPrefill {String} The prefill string. + */ +YAHOO.widget.AutoComplete.prototype.typeAheadEvent = null; + +/** + * Fired when result item has been moused over. + * + * @event itemMouseOverEvent + * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance. + * @param elItem {HTMLElement} The <li> element item moused to. + */ +YAHOO.widget.AutoComplete.prototype.itemMouseOverEvent = null; + +/** + * Fired when result item has been moused out. + * + * @event itemMouseOutEvent + * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance. + * @param elItem {HTMLElement} The <li> element item moused from. + */ +YAHOO.widget.AutoComplete.prototype.itemMouseOutEvent = null; + +/** + * Fired when result item has been arrowed to. + * + * @event itemArrowToEvent + * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance. + * @param elItem {HTMLElement} The <li> element item arrowed to. + */ +YAHOO.widget.AutoComplete.prototype.itemArrowToEvent = null; + +/** + * Fired when result item has been arrowed away from. + * + * @event itemArrowFromEvent + * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance. + * @param elItem {HTMLElement} The <li> element item arrowed from. + */ +YAHOO.widget.AutoComplete.prototype.itemArrowFromEvent = null; + +/** + * Fired when an item is selected via mouse click, ENTER key, or TAB key. + * + * @event itemSelectEvent + * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance. + * @param elItem {HTMLElement} The selected <li> element item. + * @param oData {Object} The data returned for the item, either as an object, + * or mapped from the schema into an array. + */ +YAHOO.widget.AutoComplete.prototype.itemSelectEvent = null; + +/** + * Fired when a user selection does not match any of the displayed result items. + * + * @event unmatchedItemSelectEvent + * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance. + * @param sSelection {String} The selected string. + */ +YAHOO.widget.AutoComplete.prototype.unmatchedItemSelectEvent = null; + +/** + * Fired if forceSelection is enabled and the user's input has been cleared + * because it did not match one of the returned query results. + * + * @event selectionEnforceEvent + * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance. + * @param sClearedValue {String} The cleared value (including delimiters if applicable). + */ +YAHOO.widget.AutoComplete.prototype.selectionEnforceEvent = null; + +/** + * Fired when the results container is collapsed. + * + * @event containerCollapseEvent + * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance. + */ +YAHOO.widget.AutoComplete.prototype.containerCollapseEvent = null; + +/** + * Fired when the input field loses focus. + * + * @event textboxBlurEvent + * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance. + */ +YAHOO.widget.AutoComplete.prototype.textboxBlurEvent = null; + +/** + * Fired when the input field value has changed when it loses focus. + * + * @event textboxChangeEvent + * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance. + */ +YAHOO.widget.AutoComplete.prototype.textboxChangeEvent = null; + +///////////////////////////////////////////////////////////////////////////// +// +// Private member variables +// +///////////////////////////////////////////////////////////////////////////// + +/** + * Internal class variable to index multiple AutoComplete instances. + * + * @property _nIndex + * @type Number + * @default 0 + * @private + */ +YAHOO.widget.AutoComplete._nIndex = 0; + +/** + * Name of AutoComplete instance. + * + * @property _sName + * @type String + * @private + */ +YAHOO.widget.AutoComplete.prototype._sName = null; + +/** + * Text input field DOM element. + * + * @property _elTextbox + * @type HTMLElement + * @private + */ +YAHOO.widget.AutoComplete.prototype._elTextbox = null; + +/** + * Container DOM element. + * + * @property _elContainer + * @type HTMLElement + * @private + */ +YAHOO.widget.AutoComplete.prototype._elContainer = null; + +/** + * Reference to content element within container element. + * + * @property _elContent + * @type HTMLElement + * @private + */ +YAHOO.widget.AutoComplete.prototype._elContent = null; + +/** + * Reference to header element within content element. + * + * @property _elHeader + * @type HTMLElement + * @private + */ +YAHOO.widget.AutoComplete.prototype._elHeader = null; + +/** + * Reference to body element within content element. + * + * @property _elBody + * @type HTMLElement + * @private + */ +YAHOO.widget.AutoComplete.prototype._elBody = null; + +/** + * Reference to footer element within content element. + * + * @property _elFooter + * @type HTMLElement + * @private + */ +YAHOO.widget.AutoComplete.prototype._elFooter = null; + +/** + * Reference to shadow element within container element. + * + * @property _elShadow + * @type HTMLElement + * @private + */ +YAHOO.widget.AutoComplete.prototype._elShadow = null; + +/** + * Reference to iframe element within container element. + * + * @property _elIFrame + * @type HTMLElement + * @private + */ +YAHOO.widget.AutoComplete.prototype._elIFrame = null; + +/** + * Whether or not the widget instance is currently active. If query results come back + * but the user has already moved on, do not proceed with auto complete behavior. + * + * @property _bFocused + * @type Boolean + * @private + */ +YAHOO.widget.AutoComplete.prototype._bFocused = false; + +/** + * Animation instance for container expand/collapse. + * + * @property _oAnim + * @type Boolean + * @private + */ +YAHOO.widget.AutoComplete.prototype._oAnim = null; + +/** + * Whether or not the results container is currently open. + * + * @property _bContainerOpen + * @type Boolean + * @private + */ +YAHOO.widget.AutoComplete.prototype._bContainerOpen = false; + +/** + * Whether or not the mouse is currently over the results + * container. This is necessary in order to prevent clicks on container items + * from being text input field blur events. + * + * @property _bOverContainer + * @type Boolean + * @private + */ +YAHOO.widget.AutoComplete.prototype._bOverContainer = false; + +/** + * Internal reference to <ul> elements that contains query results within the + * results container. + * + * @property _elList + * @type HTMLElement + * @private + */ +YAHOO.widget.AutoComplete.prototype._elList = null; + +/* + * Array of <li> elements references that contain query results within the + * results container. + * + * @property _aListItemEls + * @type HTMLElement[] + * @private + */ +//YAHOO.widget.AutoComplete.prototype._aListItemEls = null; + +/** + * Number of <li> elements currently displayed in results container. + * + * @property _nDisplayedItems + * @type Number + * @private + */ +YAHOO.widget.AutoComplete.prototype._nDisplayedItems = 0; + +/* + * Internal count of <li> elements displayed and hidden in results container. + * + * @property _maxResultsDisplayed + * @type Number + * @private + */ +//YAHOO.widget.AutoComplete.prototype._maxResultsDisplayed = 0; + +/** + * Current query string + * + * @property _sCurQuery + * @type String + * @private + */ +YAHOO.widget.AutoComplete.prototype._sCurQuery = null; + +/** + * Selections from previous queries (for saving delimited queries). + * + * @property _sPastSelections + * @type String + * @default "" + * @private + */ +YAHOO.widget.AutoComplete.prototype._sPastSelections = ""; + +/** + * Stores initial input value used to determine if textboxChangeEvent should be fired. + * + * @property _sInitInputValue + * @type String + * @private + */ +YAHOO.widget.AutoComplete.prototype._sInitInputValue = null; + +/** + * Pointer to the currently highlighted <li> element in the container. + * + * @property _elCurListItem + * @type HTMLElement + * @private + */ +YAHOO.widget.AutoComplete.prototype._elCurListItem = null; + +/** + * Pointer to the currently pre-highlighted <li> element in the container. + * + * @property _elCurPrehighlightItem + * @type HTMLElement + * @private + */ +YAHOO.widget.AutoComplete.prototype._elCurPrehighlightItem = null; + +/** + * Whether or not an item has been selected since the container was populated + * with results. Reset to false by _populateList, and set to true when item is + * selected. + * + * @property _bItemSelected + * @type Boolean + * @private + */ +YAHOO.widget.AutoComplete.prototype._bItemSelected = false; + +/** + * Key code of the last key pressed in textbox. + * + * @property _nKeyCode + * @type Number + * @private + */ +YAHOO.widget.AutoComplete.prototype._nKeyCode = null; + +/** + * Delay timeout ID. + * + * @property _nDelayID + * @type Number + * @private + */ +YAHOO.widget.AutoComplete.prototype._nDelayID = -1; + +/** + * TypeAhead delay timeout ID. + * + * @property _nTypeAheadDelayID + * @type Number + * @private + */ +YAHOO.widget.AutoComplete.prototype._nTypeAheadDelayID = -1; + +/** + * Src to iFrame used when useIFrame = true. Supports implementations over SSL + * as well. + * + * @property _iFrameSrc + * @type String + * @private + */ +YAHOO.widget.AutoComplete.prototype._iFrameSrc = "javascript:false;"; + +/** + * For users typing via certain IMEs, queries must be triggered by intervals, + * since key events yet supported across all browsers for all IMEs. + * + * @property _queryInterval + * @type Object + * @private + */ +YAHOO.widget.AutoComplete.prototype._queryInterval = null; + +/** + * Internal tracker to last known textbox value, used to determine whether or not + * to trigger a query via interval for certain IME users. + * + * @event _sLastTextboxValue + * @type String + * @private + */ +YAHOO.widget.AutoComplete.prototype._sLastTextboxValue = null; + +///////////////////////////////////////////////////////////////////////////// +// +// Private methods +// +///////////////////////////////////////////////////////////////////////////// + +/** + * Updates and validates latest public config properties. + * + * @method __initProps + * @private + */ +YAHOO.widget.AutoComplete.prototype._initProps = function() { + // Correct any invalid values + var minQueryLength = this.minQueryLength; + if(!YAHOO.lang.isNumber(minQueryLength)) { + this.minQueryLength = 1; + } + var maxResultsDisplayed = this.maxResultsDisplayed; + if(!YAHOO.lang.isNumber(maxResultsDisplayed) || (maxResultsDisplayed < 1)) { + this.maxResultsDisplayed = 10; + } + var queryDelay = this.queryDelay; + if(!YAHOO.lang.isNumber(queryDelay) || (queryDelay < 0)) { + this.queryDelay = 0.2; + } + var typeAheadDelay = this.typeAheadDelay; + if(!YAHOO.lang.isNumber(typeAheadDelay) || (typeAheadDelay < 0)) { + this.typeAheadDelay = 0.2; + } + var delimChar = this.delimChar; + if(YAHOO.lang.isString(delimChar) && (delimChar.length > 0)) { + this.delimChar = [delimChar]; + } + else if(!YAHOO.lang.isArray(delimChar)) { + this.delimChar = null; + } + var animSpeed = this.animSpeed; + if((this.animHoriz || this.animVert) && YAHOO.util.Anim) { + if(!YAHOO.lang.isNumber(animSpeed) || (animSpeed < 0)) { + this.animSpeed = 0.3; + } + if(!this._oAnim ) { + this._oAnim = new YAHOO.util.Anim(this._elContent, {}, this.animSpeed); + } + else { + this._oAnim.duration = this.animSpeed; + } + } + if(this.forceSelection && delimChar) { + } +}; + +/** + * Initializes the results container helpers if they are enabled and do + * not exist + * + * @method _initContainerHelperEls + * @private + */ +YAHOO.widget.AutoComplete.prototype._initContainerHelperEls = function() { + if(this.useShadow && !this._elShadow) { + var elShadow = document.createElement("div"); + elShadow.className = "yui-ac-shadow"; + elShadow.style.width = 0; + elShadow.style.height = 0; + this._elShadow = this._elContainer.appendChild(elShadow); + } + if(this.useIFrame && !this._elIFrame) { + var elIFrame = document.createElement("iframe"); + elIFrame.src = this._iFrameSrc; + elIFrame.frameBorder = 0; + elIFrame.scrolling = "no"; + elIFrame.style.position = "absolute"; + elIFrame.style.width = 0; + elIFrame.style.height = 0; + elIFrame.style.padding = 0; + elIFrame.tabIndex = -1; + elIFrame.role = "presentation"; + elIFrame.title = "Presentational iframe shim"; + this._elIFrame = this._elContainer.appendChild(elIFrame); + } +}; + +/** + * Initializes the results container once at object creation + * + * @method _initContainerEl + * @private + */ +YAHOO.widget.AutoComplete.prototype._initContainerEl = function() { + YAHOO.util.Dom.addClass(this._elContainer, "yui-ac-container"); + + if(!this._elContent) { + // The elContent div is assigned DOM listeners and + // helps size the iframe and shadow properly + var elContent = document.createElement("div"); + elContent.className = "yui-ac-content"; + elContent.style.display = "none"; + + this._elContent = this._elContainer.appendChild(elContent); + + var elHeader = document.createElement("div"); + elHeader.className = "yui-ac-hd"; + elHeader.style.display = "none"; + this._elHeader = this._elContent.appendChild(elHeader); + + var elBody = document.createElement("div"); + elBody.className = "yui-ac-bd"; + this._elBody = this._elContent.appendChild(elBody); + + var elFooter = document.createElement("div"); + elFooter.className = "yui-ac-ft"; + elFooter.style.display = "none"; + this._elFooter = this._elContent.appendChild(elFooter); + } + else { + } +}; + +/** + * Clears out contents of container body and creates up to + * YAHOO.widget.AutoComplete#maxResultsDisplayed <li> elements in an + * <ul> element. + * + * @method _initListEl + * @private + */ +YAHOO.widget.AutoComplete.prototype._initListEl = function() { + var nListLength = this.maxResultsDisplayed, + elList = this._elList || document.createElement("ul"), + elListItem; + + while(elList.childNodes.length < nListLength) { + elListItem = document.createElement("li"); + elListItem.style.display = "none"; + elListItem._nItemIndex = elList.childNodes.length; + elList.appendChild(elListItem); + } + if(!this._elList) { + var elBody = this._elBody; + YAHOO.util.Event.purgeElement(elBody, true); + elBody.innerHTML = ""; + this._elList = elBody.appendChild(elList); + } + + this._elBody.style.display = ""; +}; + +/** + * Focuses input field. + * + * @method _focus + * @private + */ +YAHOO.widget.AutoComplete.prototype._focus = function() { + // http://developer.mozilla.org/en/docs/index.php?title=Key-navigable_custom_DHTML_widgets + var oSelf = this; + setTimeout(function() { + try { + oSelf._elTextbox.focus(); + } + catch(e) { + } + },0); +}; + +/** + * Enables interval detection for IME support. + * + * @method _enableIntervalDetection + * @private + */ +YAHOO.widget.AutoComplete.prototype._enableIntervalDetection = function() { + var oSelf = this; + if(!oSelf._queryInterval && oSelf.queryInterval) { + oSelf._queryInterval = setInterval(function() { oSelf._onInterval(); }, oSelf.queryInterval); + } +}; + +/** + * Enables interval detection for a less performant but brute force mechanism to + * detect input values at an interval set by queryInterval and send queries if + * input value has changed. Needed to support right-click+paste or shift+insert + * edge cases. Please note that intervals are cleared at the end of each interaction, + * so enableIntervalDetection must be called for each new interaction. The + * recommended approach is to call it in response to textboxFocusEvent. + * + * @method enableIntervalDetection + */ +YAHOO.widget.AutoComplete.prototype.enableIntervalDetection = + YAHOO.widget.AutoComplete.prototype._enableIntervalDetection; + +/** + * Enables query triggers based on text input detection by intervals (rather + * than by key events). + * + * @method _onInterval + * @private + */ +YAHOO.widget.AutoComplete.prototype._onInterval = function() { + var currValue = this._elTextbox.value; + var lastValue = this._sLastTextboxValue; + if(currValue != lastValue) { + this._sLastTextboxValue = currValue; + this._sendQuery(currValue); + } +}; + +/** + * Cancels text input detection by intervals. + * + * @method _clearInterval + * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance. + * @private + */ +YAHOO.widget.AutoComplete.prototype._clearInterval = function() { + if(this._queryInterval) { + clearInterval(this._queryInterval); + this._queryInterval = null; + } +}; + +/** + * Whether or not key is functional or should be ignored. Note that the right + * arrow key is NOT an ignored key since it triggers queries for certain intl + * charsets. + * + * @method _isIgnoreKey + * @param nKeycode {Number} Code of key pressed. + * @return {Boolean} True if key should be ignored, false otherwise. + * @private + */ +YAHOO.widget.AutoComplete.prototype._isIgnoreKey = function(nKeyCode) { + if((nKeyCode == 9) || (nKeyCode == 13) || // tab, enter + (nKeyCode == 16) || (nKeyCode == 17) || // shift, ctl + (nKeyCode >= 18 && nKeyCode <= 20) || // alt, pause/break,caps lock + (nKeyCode == 27) || // esc + (nKeyCode >= 33 && nKeyCode <= 35) || // page up,page down,end + /*(nKeyCode >= 36 && nKeyCode <= 38) || // home,left,up + (nKeyCode == 40) || // down*/ + (nKeyCode >= 36 && nKeyCode <= 40) || // home,left,up, right, down + (nKeyCode >= 44 && nKeyCode <= 45) || // print screen,insert + (nKeyCode == 229) // Bug 2041973: Korean XP fires 2 keyup events, the key and 229 + ) { + return true; + } + return false; +}; + +/** + * Makes query request to the DataSource. + * + * @method _sendQuery + * @param sQuery {String} Query string. + * @private + */ +YAHOO.widget.AutoComplete.prototype._sendQuery = function(sQuery) { + // Widget has been effectively turned off + if(this.minQueryLength < 0) { + this._toggleContainer(false); + return; + } + // Delimiter has been enabled + if(this.delimChar) { + var extraction = this._extractQuery(sQuery); + // Here is the query itself + sQuery = extraction.query; + // ...and save the rest of the string for later + this._sPastSelections = extraction.previous; + } + + // Don't search queries that are too short + if((sQuery && (sQuery.length < this.minQueryLength)) || (!sQuery && this.minQueryLength > 0)) { + if(this._nDelayID != -1) { + clearTimeout(this._nDelayID); + } + this._toggleContainer(false); + return; + } + + sQuery = encodeURIComponent(sQuery); + this._nDelayID = -1; // Reset timeout ID because request is being made + + // Subset matching + if(this.dataSource.queryMatchSubset || this.queryMatchSubset) { // backward compat + var oResponse = this.getSubsetMatches(sQuery); + if(oResponse) { + this.handleResponse(sQuery, oResponse, {query: sQuery}); + return; + } + } + + if(this.dataSource.responseStripAfter) { + this.dataSource.doBeforeParseData = this.preparseRawResponse; + } + if(this.applyLocalFilter) { + this.dataSource.doBeforeCallback = this.filterResults; + } + + var sRequest = this.generateRequest(sQuery); + this.dataRequestEvent.fire(this, sQuery, sRequest); + + this.dataSource.sendRequest(sRequest, { + success : this.handleResponse, + failure : this.handleResponse, + scope : this, + argument: { + query: sQuery + } + }); +}; + +/** + * Populates the given <li> element with return value from formatResult(). + * + * @method _populateListItem + * @param elListItem {HTMLElement} The LI element. + * @param oResult {Object} The result object. + * @param sCurQuery {String} The query string. + * @private + */ +YAHOO.widget.AutoComplete.prototype._populateListItem = function(elListItem, oResult, sQuery) { + elListItem.innerHTML = this.formatResult(oResult, sQuery, elListItem._sResultMatch); +}; + +/** + * Populates the array of <li> elements in the container with query + * results. + * + * @method _populateList + * @param sQuery {String} Original request. + * @param oResponse {Object} Response object. + * @param oPayload {MIXED} (optional) Additional argument(s) + * @private + */ +YAHOO.widget.AutoComplete.prototype._populateList = function(sQuery, oResponse, oPayload) { + // Clear previous timeout + if(this._nTypeAheadDelayID != -1) { + clearTimeout(this._nTypeAheadDelayID); + } + + sQuery = (oPayload && oPayload.query) ? oPayload.query : sQuery; + + // Pass data through abstract method for any transformations + var ok = this.doBeforeLoadData(sQuery, oResponse, oPayload); + + // Data is ok + if(ok && !oResponse.error) { + this.dataReturnEvent.fire(this, sQuery, oResponse.results); + + // Continue only if instance is still active (i.e., user hasn't already moved on) + if(this._bFocused) { + // Store state for this interaction + var sCurQuery = decodeURIComponent(sQuery); + this._sCurQuery = sCurQuery; + this._bItemSelected = false; + + var allResults = oResponse.results, + nItemsToShow = Math.min(allResults.length,this.maxResultsDisplayed), + sMatchKey = (this.dataSource.responseSchema.fields) ? + (this.dataSource.responseSchema.fields[0].key || this.dataSource.responseSchema.fields[0]) : 0; + + if(nItemsToShow > 0) { + // Make sure container and helpers are ready to go + if(!this._elList || (this._elList.childNodes.length < nItemsToShow)) { + this._initListEl(); + } + this._initContainerHelperEls(); + + var allListItemEls = this._elList.childNodes; + // Fill items with data from the bottom up + for(var i = nItemsToShow-1; i >= 0; i--) { + var elListItem = allListItemEls[i], + oResult = allResults[i]; + + // Backward compatibility + if(this.resultTypeList) { + // Results need to be converted back to an array + var aResult = []; + // Match key is first + aResult[0] = (YAHOO.lang.isString(oResult)) ? oResult : oResult[sMatchKey] || oResult[this.key]; + // Add additional data to the result array + var fields = this.dataSource.responseSchema.fields; + if(YAHOO.lang.isArray(fields) && (fields.length > 1)) { + for(var k=1, len=fields.length; k= nItemsToShow; j--) { + extraListItem = allListItemEls[j]; + extraListItem.style.display = "none"; + } + } + + this._nDisplayedItems = nItemsToShow; + + this.containerPopulateEvent.fire(this, sQuery, allResults); + + // Highlight the first item + if(this.autoHighlight) { + var elFirstListItem = this._elList.firstChild; + this._toggleHighlight(elFirstListItem,"to"); + this.itemArrowToEvent.fire(this, elFirstListItem); + this._typeAhead(elFirstListItem,sQuery); + } + // Unhighlight any previous time + else { + this._toggleHighlight(this._elCurListItem,"from"); + } + + // Pre-expansion stuff + ok = this._doBeforeExpandContainer(this._elTextbox, this._elContainer, sQuery, allResults); + + // Expand the container + this._toggleContainer(ok); + } + else { + this._toggleContainer(false); + } + + return; + } + } + // Error + else { + this.dataErrorEvent.fire(this, sQuery, oResponse); + } + +}; + +/** + * Called before container expands, by default snaps container to the + * bottom-left corner of the input element, then calls public overrideable method. + * + * @method _doBeforeExpandContainer + * @param elTextbox {HTMLElement} The text input box. + * @param elContainer {HTMLElement} The container element. + * @param sQuery {String} The query string. + * @param aResults {Object[]} An array of query results. + * @return {Boolean} Return true to continue expanding container, false to cancel the expand. + * @private + */ +YAHOO.widget.AutoComplete.prototype._doBeforeExpandContainer = function(elTextbox, elContainer, sQuery, aResults) { + if(this.autoSnapContainer) { + this.snapContainer(); + } + + return this.doBeforeExpandContainer(elTextbox, elContainer, sQuery, aResults); +}; + +/** + * When forceSelection is true and the user attempts + * leave the text input box without selecting an item from the query results, + * the user selection is cleared. + * + * @method _clearSelection + * @private + */ +YAHOO.widget.AutoComplete.prototype._clearSelection = function() { + var extraction = (this.delimChar) ? this._extractQuery(this._elTextbox.value) : + {previous:"",query:this._elTextbox.value}; + this._elTextbox.value = extraction.previous; + this.selectionEnforceEvent.fire(this, extraction.query); +}; + +/** + * Whether or not user-typed value in the text input box matches any of the + * query results. + * + * @method _textMatchesOption + * @return {HTMLElement} Matching list item element if user-input text matches + * a result, null otherwise. + * @private + */ +YAHOO.widget.AutoComplete.prototype._textMatchesOption = function() { + var elMatch = null; + + for(var i=0; i= 0; i--) { + nNewIndex = sQuery.lastIndexOf(aDelimChar[i]); + if(nNewIndex > nDelimIndex) { + nDelimIndex = nNewIndex; + } + } + // If we think the last delimiter is a space (" "), make sure it is NOT + // a false positive by also checking the char directly before it + if(aDelimChar[i] == " ") { + for (var j = aDelimChar.length-1; j >= 0; j--) { + if(sQuery[nDelimIndex - 1] == aDelimChar[j]) { + nDelimIndex--; + break; + } + } + } + // A delimiter has been found in the query so extract the latest query from past selections + if(nDelimIndex > -1) { + nQueryStart = nDelimIndex + 1; + // Trim any white space from the beginning... + while(sQuery.charAt(nQueryStart) == " ") { + nQueryStart += 1; + } + // ...and save the rest of the string for later + sPrevious = sQuery.substring(0,nQueryStart); + // Here is the query itself + sQuery = sQuery.substr(nQueryStart); + } + // No delimiter found in the query, so there are no selections from past queries + else { + sPrevious = ""; + } + + return { + previous: sPrevious, + query: sQuery + }; +}; + +/** + * Syncs results container with its helpers. + * + * @method _toggleContainerHelpers + * @param bShow {Boolean} True if container is expanded, false if collapsed + * @private + */ +YAHOO.widget.AutoComplete.prototype._toggleContainerHelpers = function(bShow) { + var width = this._elContent.offsetWidth + "px"; + var height = this._elContent.offsetHeight + "px"; + + if(this.useIFrame && this._elIFrame) { + var elIFrame = this._elIFrame; + if(bShow) { + elIFrame.style.width = width; + elIFrame.style.height = height; + elIFrame.style.padding = ""; + } + else { + elIFrame.style.width = 0; + elIFrame.style.height = 0; + elIFrame.style.padding = 0; + } + } + if(this.useShadow && this._elShadow) { + var elShadow = this._elShadow; + if(bShow) { + elShadow.style.width = width; + elShadow.style.height = height; + } + else { + elShadow.style.width = 0; + elShadow.style.height = 0; + } + } +}; + +/** + * Animates expansion or collapse of the container. + * + * @method _toggleContainer + * @param bShow {Boolean} True if container should be expanded, false if container should be collapsed + * @private + */ +YAHOO.widget.AutoComplete.prototype._toggleContainer = function(bShow) { + + var elContainer = this._elContainer; + + // If implementer has container always open and it's already open, don't mess with it + // Container is initialized with display "none" so it may need to be shown first time through + if(this.alwaysShowContainer && this._bContainerOpen) { + return; + } + + // Reset states + if(!bShow) { + this._toggleHighlight(this._elCurListItem,"from"); + this._nDisplayedItems = 0; + this._sCurQuery = null; + + // Container is already closed, so don't bother with changing the UI + if(this._elContent.style.display == "none") { + return; + } + } + + // If animation is enabled... + var oAnim = this._oAnim; + if(oAnim && oAnim.getEl() && (this.animHoriz || this.animVert)) { + if(oAnim.isAnimated()) { + oAnim.stop(true); + } + + // Clone container to grab current size offscreen + var oClone = this._elContent.cloneNode(true); + elContainer.appendChild(oClone); + oClone.style.top = "-9000px"; + oClone.style.width = ""; + oClone.style.height = ""; + oClone.style.display = ""; + + // Current size of the container is the EXPANDED size + var wExp = oClone.offsetWidth; + var hExp = oClone.offsetHeight; + + // Calculate COLLAPSED sizes based on horiz and vert anim + var wColl = (this.animHoriz) ? 0 : wExp; + var hColl = (this.animVert) ? 0 : hExp; + + // Set animation sizes + oAnim.attributes = (bShow) ? + {width: { to: wExp }, height: { to: hExp }} : + {width: { to: wColl}, height: { to: hColl }}; + + // If opening anew, set to a collapsed size... + if(bShow && !this._bContainerOpen) { + this._elContent.style.width = wColl+"px"; + this._elContent.style.height = hColl+"px"; + } + // Else, set it to its last known size. + else { + this._elContent.style.width = wExp+"px"; + this._elContent.style.height = hExp+"px"; + } + + elContainer.removeChild(oClone); + oClone = null; + + var oSelf = this; + var onAnimComplete = function() { + // Finish the collapse + oAnim.onComplete.unsubscribeAll(); + + if(bShow) { + oSelf._toggleContainerHelpers(true); + oSelf._bContainerOpen = bShow; + oSelf.containerExpandEvent.fire(oSelf); + } + else { + oSelf._elContent.style.display = "none"; + oSelf._bContainerOpen = bShow; + oSelf.containerCollapseEvent.fire(oSelf); + } + }; + + // Display container and animate it + this._toggleContainerHelpers(false); // Bug 1424486: Be early to hide, late to show; + this._elContent.style.display = ""; + oAnim.onComplete.subscribe(onAnimComplete); + oAnim.animate(); + } + // Else don't animate, just show or hide + else { + if(bShow) { + this._elContent.style.display = ""; + this._toggleContainerHelpers(true); + this._bContainerOpen = bShow; + this.containerExpandEvent.fire(this); + } + else { + this._toggleContainerHelpers(false); + this._elContent.style.display = "none"; + this._bContainerOpen = bShow; + this.containerCollapseEvent.fire(this); + } + } + +}; + +/** + * Toggles the highlight on or off for an item in the container, and also cleans + * up highlighting of any previous item. + * + * @method _toggleHighlight + * @param elNewListItem {HTMLElement} The <li> element item to receive highlight behavior. + * @param sType {String} Type "mouseover" will toggle highlight on, and "mouseout" will toggle highlight off. + * @private + */ +YAHOO.widget.AutoComplete.prototype._toggleHighlight = function(elNewListItem, sType) { + if(elNewListItem) { + var sHighlight = this.highlightClassName; + if(this._elCurListItem) { + // Remove highlight from old item + YAHOO.util.Dom.removeClass(this._elCurListItem, sHighlight); + this._elCurListItem = null; + } + + if((sType == "to") && sHighlight) { + // Apply highlight to new item + YAHOO.util.Dom.addClass(elNewListItem, sHighlight); + this._elCurListItem = elNewListItem; + } + } +}; + +/** + * Toggles the pre-highlight on or off for an item in the container, and also cleans + * up pre-highlighting of any previous item. + * + * @method _togglePrehighlight + * @param elNewListItem {HTMLElement} The <li> element item to receive highlight behavior. + * @param sType {String} Type "mouseover" will toggle highlight on, and "mouseout" will toggle highlight off. + * @private + */ +YAHOO.widget.AutoComplete.prototype._togglePrehighlight = function(elNewListItem, sType) { + var sPrehighlight = this.prehighlightClassName; + + if(this._elCurPrehighlightItem) { + YAHOO.util.Dom.removeClass(this._elCurPrehighlightItem, sPrehighlight); + } + if(elNewListItem == this._elCurListItem) { + return; + } + + if((sType == "mouseover") && sPrehighlight) { + // Apply prehighlight to new item + YAHOO.util.Dom.addClass(elNewListItem, sPrehighlight); + this._elCurPrehighlightItem = elNewListItem; + } + else { + // Remove prehighlight from old item + YAHOO.util.Dom.removeClass(elNewListItem, sPrehighlight); + } +}; + +/** + * Updates the text input box value with selected query result. If a delimiter + * has been defined, then the value gets appended with the delimiter. + * + * @method _updateValue + * @param elListItem {HTMLElement} The <li> element item with which to update the value. + * @private + */ +YAHOO.widget.AutoComplete.prototype._updateValue = function(elListItem) { + if(!this.suppressInputUpdate) { + var elTextbox = this._elTextbox; + var sDelimChar = (this.delimChar) ? (this.delimChar[0] || this.delimChar) : null; + var sResultMatch = elListItem._sResultMatch; + + // Calculate the new value + var sNewValue = ""; + if(sDelimChar) { + // Preserve selections from past queries + sNewValue = this._sPastSelections; + // Add new selection plus delimiter + sNewValue += sResultMatch + sDelimChar; + if(sDelimChar != " ") { + sNewValue += " "; + } + } + else { + sNewValue = sResultMatch; + } + + // Update input field + elTextbox.value = sNewValue; + + // Scroll to bottom of textarea if necessary + if(elTextbox.type == "textarea") { + elTextbox.scrollTop = elTextbox.scrollHeight; + } + + // Move cursor to end + var end = elTextbox.value.length; + this._selectText(elTextbox,end,end); + + this._elCurListItem = elListItem; + } +}; + +/** + * Selects a result item from the container + * + * @method _selectItem + * @param elListItem {HTMLElement} The selected <li> element item. + * @private + */ +YAHOO.widget.AutoComplete.prototype._selectItem = function(elListItem) { + this._bItemSelected = true; + this._updateValue(elListItem); + this._sPastSelections = this._elTextbox.value; + this._clearInterval(); + this.itemSelectEvent.fire(this, elListItem, elListItem._oResultData); + this._toggleContainer(false); +}; + +/** + * If an item is highlighted in the container, the right arrow key jumps to the + * end of the textbox and selects the highlighted item, otherwise the container + * is closed. + * + * @method _jumpSelection + * @private + */ +YAHOO.widget.AutoComplete.prototype._jumpSelection = function() { + if(this._elCurListItem) { + this._selectItem(this._elCurListItem); + } + else { + this._toggleContainer(false); + } +}; + +/** + * Triggered by up and down arrow keys, changes the current highlighted + * <li> element item. Scrolls container if necessary. + * + * @method _moveSelection + * @param nKeyCode {Number} Code of key pressed. + * @private + */ +YAHOO.widget.AutoComplete.prototype._moveSelection = function(nKeyCode) { + if(this._bContainerOpen) { + // Determine current item's id number + var elCurListItem = this._elCurListItem, + nCurItemIndex = -1; + + if(elCurListItem) { + nCurItemIndex = elCurListItem._nItemIndex; + } + + var nNewItemIndex = (nKeyCode == 40) ? + (nCurItemIndex + 1) : (nCurItemIndex - 1); + + // Out of bounds + if(nNewItemIndex < -2 || nNewItemIndex >= this._nDisplayedItems) { + return; + } + + if(elCurListItem) { + // Unhighlight current item + this._toggleHighlight(elCurListItem, "from"); + this.itemArrowFromEvent.fire(this, elCurListItem); + } + if(nNewItemIndex == -1) { + // Go back to query (remove type-ahead string) + if(this.delimChar) { + this._elTextbox.value = this._sPastSelections + this._sCurQuery; + } + else { + this._elTextbox.value = this._sCurQuery; + } + return; + } + if(nNewItemIndex == -2) { + // Close container + this._toggleContainer(false); + return; + } + + var elNewListItem = this._elList.childNodes[nNewItemIndex], + + // Scroll the container if necessary + elContent = this._elContent, + sOF = YAHOO.util.Dom.getStyle(elContent,"overflow"), + sOFY = YAHOO.util.Dom.getStyle(elContent,"overflowY"), + scrollOn = ((sOF == "auto") || (sOF == "scroll") || (sOFY == "auto") || (sOFY == "scroll")); + if(scrollOn && (nNewItemIndex > -1) && + (nNewItemIndex < this._nDisplayedItems)) { + // User is keying down + if(nKeyCode == 40) { + // Bottom of selected item is below scroll area... + if((elNewListItem.offsetTop+elNewListItem.offsetHeight) > (elContent.scrollTop + elContent.offsetHeight)) { + // Set bottom of scroll area to bottom of selected item + elContent.scrollTop = (elNewListItem.offsetTop+elNewListItem.offsetHeight) - elContent.offsetHeight; + } + // Bottom of selected item is above scroll area... + else if((elNewListItem.offsetTop+elNewListItem.offsetHeight) < elContent.scrollTop) { + // Set top of selected item to top of scroll area + elContent.scrollTop = elNewListItem.offsetTop; + + } + } + // User is keying up + else { + // Top of selected item is above scroll area + if(elNewListItem.offsetTop < elContent.scrollTop) { + // Set top of scroll area to top of selected item + this._elContent.scrollTop = elNewListItem.offsetTop; + } + // Top of selected item is below scroll area + else if(elNewListItem.offsetTop > (elContent.scrollTop + elContent.offsetHeight)) { + // Set bottom of selected item to bottom of scroll area + this._elContent.scrollTop = (elNewListItem.offsetTop+elNewListItem.offsetHeight) - elContent.offsetHeight; + } + } + } + + this._toggleHighlight(elNewListItem, "to"); + this.itemArrowToEvent.fire(this, elNewListItem); + if(this.typeAhead) { + this._updateValue(elNewListItem); + } + } +}; + +///////////////////////////////////////////////////////////////////////////// +// +// Private event handlers +// +///////////////////////////////////////////////////////////////////////////// + +/** + * Handles container mouseover events. + * + * @method _onContainerMouseover + * @param v {HTMLEvent} The mouseover event. + * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance. + * @private + */ +YAHOO.widget.AutoComplete.prototype._onContainerMouseover = function(v,oSelf) { + var elTarget = YAHOO.util.Event.getTarget(v); + var elTag = elTarget.nodeName.toLowerCase(); + while(elTarget && (elTag != "table")) { + switch(elTag) { + case "body": + return; + case "li": + if(oSelf.prehighlightClassName) { + oSelf._togglePrehighlight(elTarget,"mouseover"); + } + else { + oSelf._toggleHighlight(elTarget,"to"); + } + + oSelf.itemMouseOverEvent.fire(oSelf, elTarget); + break; + case "div": + if(YAHOO.util.Dom.hasClass(elTarget,"yui-ac-container")) { + oSelf._bOverContainer = true; + return; + } + break; + default: + break; + } + + elTarget = elTarget.parentNode; + if(elTarget) { + elTag = elTarget.nodeName.toLowerCase(); + } + } +}; + +/** + * Handles container mouseout events. + * + * @method _onContainerMouseout + * @param v {HTMLEvent} The mouseout event. + * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance. + * @private + */ +YAHOO.widget.AutoComplete.prototype._onContainerMouseout = function(v,oSelf) { + var elTarget = YAHOO.util.Event.getTarget(v); + var elTag = elTarget.nodeName.toLowerCase(); + while(elTarget && (elTag != "table")) { + switch(elTag) { + case "body": + return; + case "li": + if(oSelf.prehighlightClassName) { + oSelf._togglePrehighlight(elTarget,"mouseout"); + } + else { + oSelf._toggleHighlight(elTarget,"from"); + } + + oSelf.itemMouseOutEvent.fire(oSelf, elTarget); + break; + case "ul": + oSelf._toggleHighlight(oSelf._elCurListItem,"to"); + break; + case "div": + if(YAHOO.util.Dom.hasClass(elTarget,"yui-ac-container")) { + oSelf._bOverContainer = false; + return; + } + break; + default: + break; + } + + elTarget = elTarget.parentNode; + if(elTarget) { + elTag = elTarget.nodeName.toLowerCase(); + } + } +}; + +/** + * Handles container click events. + * + * @method _onContainerClick + * @param v {HTMLEvent} The click event. + * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance. + * @private + */ +YAHOO.widget.AutoComplete.prototype._onContainerClick = function(v,oSelf) { + var elTarget = YAHOO.util.Event.getTarget(v); + var elTag = elTarget.nodeName.toLowerCase(); + while(elTarget && (elTag != "table")) { + switch(elTag) { + case "body": + return; + case "li": + // In case item has not been moused over + oSelf._toggleHighlight(elTarget,"to"); + oSelf._selectItem(elTarget); + return; + default: + break; + } + + elTarget = elTarget.parentNode; + if(elTarget) { + elTag = elTarget.nodeName.toLowerCase(); + } + } +}; + + +/** + * Handles container scroll events. + * + * @method _onContainerScroll + * @param v {HTMLEvent} The scroll event. + * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance. + * @private + */ +YAHOO.widget.AutoComplete.prototype._onContainerScroll = function(v,oSelf) { + oSelf._focus(); +}; + +/** + * Handles container resize events. + * + * @method _onContainerResize + * @param v {HTMLEvent} The resize event. + * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance. + * @private + */ +YAHOO.widget.AutoComplete.prototype._onContainerResize = function(v,oSelf) { + oSelf._toggleContainerHelpers(oSelf._bContainerOpen); +}; + + +/** + * Handles textbox keydown events of functional keys, mainly for UI behavior. + * + * @method _onTextboxKeyDown + * @param v {HTMLEvent} The keydown event. + * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance. + * @private + */ +YAHOO.widget.AutoComplete.prototype._onTextboxKeyDown = function(v,oSelf) { + var nKeyCode = v.keyCode; + + // Clear timeout + if(oSelf._nTypeAheadDelayID != -1) { + clearTimeout(oSelf._nTypeAheadDelayID); + } + + switch (nKeyCode) { + case 9: // tab + if(!YAHOO.env.ua.opera && (navigator.userAgent.toLowerCase().indexOf("mac") == -1) || (YAHOO.env.ua.webkit>420)) { + // select an item or clear out + if(oSelf._elCurListItem) { + if(oSelf.delimChar && (oSelf._nKeyCode != nKeyCode)) { + if(oSelf._bContainerOpen) { + YAHOO.util.Event.stopEvent(v); + } + } + oSelf._selectItem(oSelf._elCurListItem); + } + else { + oSelf._toggleContainer(false); + } + } + break; + case 13: // enter + if(!YAHOO.env.ua.opera && (navigator.userAgent.toLowerCase().indexOf("mac") == -1) || (YAHOO.env.ua.webkit>420)) { + if(oSelf._elCurListItem) { + if(oSelf._nKeyCode != nKeyCode) { + if(oSelf._bContainerOpen) { + YAHOO.util.Event.stopEvent(v); + } + } + oSelf._selectItem(oSelf._elCurListItem); + } + else { + oSelf._toggleContainer(false); + } + } + break; + case 27: // esc + oSelf._toggleContainer(false); + return; + case 39: // right + oSelf._jumpSelection(); + break; + case 38: // up + if(oSelf._bContainerOpen) { + YAHOO.util.Event.stopEvent(v); + oSelf._moveSelection(nKeyCode); + } + break; + case 40: // down + if(oSelf._bContainerOpen) { + YAHOO.util.Event.stopEvent(v); + oSelf._moveSelection(nKeyCode); + } + break; + default: + oSelf._bItemSelected = false; + oSelf._toggleHighlight(oSelf._elCurListItem, "from"); + + oSelf.textboxKeyEvent.fire(oSelf, nKeyCode); + break; + } + + if(nKeyCode === 18){ + oSelf._enableIntervalDetection(); + } + oSelf._nKeyCode = nKeyCode; +}; + +/** + * Handles textbox keypress events. + * @method _onTextboxKeyPress + * @param v {HTMLEvent} The keypress event. + * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance. + * @private + */ +YAHOO.widget.AutoComplete.prototype._onTextboxKeyPress = function(v,oSelf) { + var nKeyCode = v.keyCode; + + // Expose only to non SF3 (bug 1978549) Mac browsers (bug 790337) and Opera browsers (bug 583531), + // where stopEvent is ineffective on keydown events + if(YAHOO.env.ua.opera || (navigator.userAgent.toLowerCase().indexOf("mac") != -1) && (YAHOO.env.ua.webkit < 420)) { + switch (nKeyCode) { + case 9: // tab + // select an item or clear out + if(oSelf._bContainerOpen) { + if(oSelf.delimChar) { + YAHOO.util.Event.stopEvent(v); + } + if(oSelf._elCurListItem) { + oSelf._selectItem(oSelf._elCurListItem); + } + else { + oSelf._toggleContainer(false); + } + } + break; + case 13: // enter + if(oSelf._bContainerOpen) { + YAHOO.util.Event.stopEvent(v); + if(oSelf._elCurListItem) { + oSelf._selectItem(oSelf._elCurListItem); + } + else { + oSelf._toggleContainer(false); + } + } + break; + default: + break; + } + } + + //TODO: (?) limit only to non-IE, non-Mac-FF for Korean IME support (bug 811948) + // Korean IME detected + else if(nKeyCode == 229) { + oSelf._enableIntervalDetection(); + } +}; + +/** + * Handles textbox keyup events to trigger queries. + * + * @method _onTextboxKeyUp + * @param v {HTMLEvent} The keyup event. + * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance. + * @private + */ +YAHOO.widget.AutoComplete.prototype._onTextboxKeyUp = function(v,oSelf) { + var sText = this.value; //string in textbox + + // Check to see if any of the public properties have been updated + oSelf._initProps(); + + // Filter out chars that don't trigger queries + var nKeyCode = v.keyCode; + if(oSelf._isIgnoreKey(nKeyCode)) { + return; + } + + // Clear previous timeout + if(oSelf._nDelayID != -1) { + clearTimeout(oSelf._nDelayID); + } + + // Set new timeout + oSelf._nDelayID = setTimeout(function(){ + oSelf._sendQuery(sText); + },(oSelf.queryDelay * 1000)); +}; + +/** + * Handles text input box receiving focus. + * + * @method _onTextboxFocus + * @param v {HTMLEvent} The focus event. + * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance. + * @private + */ +YAHOO.widget.AutoComplete.prototype._onTextboxFocus = function (v,oSelf) { + // Start of a new interaction + if(!oSelf._bFocused) { + oSelf._elTextbox.setAttribute("autocomplete","off"); + oSelf._bFocused = true; + oSelf._sInitInputValue = oSelf._elTextbox.value; + oSelf.textboxFocusEvent.fire(oSelf); + } +}; + +/** + * Handles text input box losing focus. + * + * @method _onTextboxBlur + * @param v {HTMLEvent} The focus event. + * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance. + * @private + */ +YAHOO.widget.AutoComplete.prototype._onTextboxBlur = function (v,oSelf) { + // Is a true blur + if(!oSelf._bOverContainer || (oSelf._nKeyCode == 9)) { + // Current query needs to be validated as a selection + if(!oSelf._bItemSelected) { + var elMatchListItem = oSelf._textMatchesOption(); + // Container is closed or current query doesn't match any result + if(!oSelf._bContainerOpen || (oSelf._bContainerOpen && (elMatchListItem === null))) { + // Force selection is enabled so clear the current query + if(oSelf.forceSelection) { + oSelf._clearSelection(); + } + // Treat current query as a valid selection + else { + oSelf.unmatchedItemSelectEvent.fire(oSelf, oSelf._sCurQuery); + } + } + // Container is open and current query matches a result + else { + // Force a selection when textbox is blurred with a match + if(oSelf.forceSelection) { + oSelf._selectItem(elMatchListItem); + } + } + } + + oSelf._clearInterval(); + oSelf._bFocused = false; + if(oSelf._sInitInputValue !== oSelf._elTextbox.value) { + oSelf.textboxChangeEvent.fire(oSelf); + } + oSelf.textboxBlurEvent.fire(oSelf); + + oSelf._toggleContainer(false); + } + // Not a true blur if it was a selection via mouse click + else { + oSelf._focus(); + } +}; + +/** + * Handles window unload event. + * + * @method _onWindowUnload + * @param v {HTMLEvent} The unload event. + * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance. + * @private + */ +YAHOO.widget.AutoComplete.prototype._onWindowUnload = function(v,oSelf) { + if(oSelf && oSelf._elTextbox && oSelf.allowBrowserAutocomplete) { + oSelf._elTextbox.setAttribute("autocomplete","on"); + } +}; + +///////////////////////////////////////////////////////////////////////////// +// +// Deprecated for Backwards Compatibility +// +///////////////////////////////////////////////////////////////////////////// +/** + * @method doBeforeSendQuery + * @deprecated Use generateRequest. + */ +YAHOO.widget.AutoComplete.prototype.doBeforeSendQuery = function(sQuery) { + return this.generateRequest(sQuery); +}; + +/** + * @method getListItems + * @deprecated Use getListEl().childNodes. + */ +YAHOO.widget.AutoComplete.prototype.getListItems = function() { + var allListItemEls = [], + els = this._elList.childNodes; + for(var i=els.length-1; i>=0; i--) { + allListItemEls[i] = els[i]; + } + return allListItemEls; +}; + +///////////////////////////////////////////////////////////////////////// +// +// Private static methods +// +///////////////////////////////////////////////////////////////////////// + +/** + * Clones object literal or array of object literals. + * + * @method AutoComplete._cloneObject + * @param o {Object} Object. + * @private + * @static + */ +YAHOO.widget.AutoComplete._cloneObject = function(o) { + if(!YAHOO.lang.isValue(o)) { + return o; + } + + var copy = {}; + + if(YAHOO.lang.isFunction(o)) { + copy = o; + } + else if(YAHOO.lang.isArray(o)) { + var array = []; + for(var i=0,len=o.length;iC#5QQ<|d}62BjvZR2H60wE-$(3-AeXt*@{D|Np;u@pDC#5QQ<|d}62BjvZR2H60wE-$(3-AeX1=9cj|6h7@{#_u8sU*lR z_&>wb?FL>zp1h}vV@SoVq=W_rH;IGN~-|K;%i-0c73 z@c-iO|KRQa-|hd~QeFE1003M`L_t(|+U&?l5`sVg1i`WZK}Epr|6dhmytLs92=mel z9uoULP6;mwyM%qhIpHzkHQ|(SNO(*5TD8?y@wq9xG<+26t_AN^`$=39HtEMPCOjwP e%l`;(0R{kdKn;SADLBOd00006$Gh9E#3p9{H-P6S}q~camLV^=3&tj%#_Xa_x2_Xl57U&w-9pX85Q9;Im dv4Me^VIeE)+1pK9I)PdkJYD@<);T3K0RYcxInw|D literal 0 HcmV?d00001 diff --git a/include/javascript/yui/build/button/assets/skins/sam/split-button-arrow-focus.png b/include/javascript/yui/build/button/assets/skins/sam/split-button-arrow-focus.png new file mode 100644 index 0000000000000000000000000000000000000000..167d71eb721ba9b85c6601f9077d5c39faa4ebd2 GIT binary patch literal 185 zcmeAS@N?(olHy`uVBq!ia0vp^0zhoU!3-pmJXhxdDVB6cUq=RpYd5a=M;HP5k|nMY zCBgY=CFO}lsSJ)O`AMk?p1FzXsX?iUDV2pMQ*D5XI0Jk_Tx)0S05bpo|DSu#^)isf zToU9L{Qp10^;5h+0~ypkT^vIyZY3ooII;39W@>hC5M-JVa^Poyu7TYlo?{mkWE>b9 b7?>Frva+7N-L$0>sD;7P)z4*}Q$iB}D9ShR literal 0 HcmV?d00001 diff --git a/include/javascript/yui/build/button/assets/skins/sam/split-button-arrow-hover.png b/include/javascript/yui/build/button/assets/skins/sam/split-button-arrow-hover.png new file mode 100644 index 0000000000000000000000000000000000000000..167d71eb721ba9b85c6601f9077d5c39faa4ebd2 GIT binary patch literal 185 zcmeAS@N?(olHy`uVBq!ia0vp^0zhoU!3-pmJXhxdDVB6cUq=RpYd5a=M;HP5k|nMY zCBgY=CFO}lsSJ)O`AMk?p1FzXsX?iUDV2pMQ*D5XI0Jk_Tx)0S05bpo|DSu#^)isf zToU9L{Qp10^;5h+0~ypkT^vIyZY3ooII;39W@>hC5M-JVa^Poyu7TYlo?{mkWE>b9 b7?>Frva+7N-L$0>sD;7P)z4*}Q$iB}D9ShR literal 0 HcmV?d00001 diff --git a/include/javascript/yui/build/button/assets/skins/sam/split-button-arrow.png b/include/javascript/yui/build/button/assets/skins/sam/split-button-arrow.png new file mode 100644 index 0000000000000000000000000000000000000000..b33a93ff2dc2039bd24e4ea3b75ecf4bb3295f84 GIT binary patch literal 185 zcmeAS@N?(olHy`uVBq!ia0vp^0zhoU!3-pmJXhxdDVB6cUq=RpYd5a=M;HP5k|nMY zCBgY=CFO}lsSJ)O`AMk?p1FzXsX?iUDV2pMQ*D5XI0Jk_TpJo1fXx5@|JyBHuocK+ zE(!7r{{Nrh`YB$Zfeh-NE{-7;w~`VPoLG4lGc~(62r^9wIqgTe~DWM4f1sXSq literal 0 HcmV?d00001 diff --git a/include/javascript/yui/build/button/button-min.js b/include/javascript/yui/build/button/button-min.js new file mode 100644 index 00000000..6a81b63e --- /dev/null +++ b/include/javascript/yui/build/button/button-min.js @@ -0,0 +1,11 @@ +/* +Copyright (c) 2009, Yahoo! Inc. All rights reserved. +Code licensed under the BSD License: +http://developer.yahoo.net/yui/license.txt +version: 2.8.0r4 +*/ +(function(){var G=YAHOO.util.Dom,M=YAHOO.util.Event,I=YAHOO.lang,L=YAHOO.env.ua,B=YAHOO.widget.Overlay,J=YAHOO.widget.Menu,D={},K=null,E=null,C=null;function F(O,N,R,P){var S,Q;if(I.isString(O)&&I.isString(N)){if(L.ie){Q='0){V.label=Q;}}}function A(P){var O=P.attributes,N=O.srcelement,R=N.nodeName.toUpperCase(),Q=this;if(R==this.NODE_NAME){P.element=N;P.id=N.id;G.getElementsBy(function(S){switch(S.nodeName.toUpperCase()){case"BUTTON":case"A":case"INPUT":H.call(Q,S,O);break;}},"*",N);}else{switch(R){case"BUTTON":case"A":case"INPUT":H.call(this,N,O);break;}}}YAHOO.widget.Button=function(R,O){if(!B&&YAHOO.widget.Overlay){B=YAHOO.widget.Overlay;}if(!J&&YAHOO.widget.Menu){J=YAHOO.widget.Menu;}var Q=YAHOO.widget.Button.superclass.constructor,P,N;if(arguments.length==1&&!I.isString(R)&&!R.nodeName){if(!R.id){R.id=G.generateId();}Q.call(this,(this.createButtonElement(R.type)),R);}else{P={element:null,attributes:(O||{})};if(I.isString(R)){N=G.get(R);if(N){if(!P.attributes.id){P.attributes.id=R;}P.attributes.srcelement=N;A.call(this,P);if(!P.element){P.element=this.createButtonElement(P.attributes.type);}Q.call(this,P.element,P.attributes);}}else{if(R.nodeName){if(!P.attributes.id){if(R.id){P.attributes.id=R.id;}else{P.attributes.id=G.generateId();}}P.attributes.srcelement=R;A.call(this,P);if(!P.element){P.element=this.createButtonElement(P.attributes.type);}Q.call(this,P.element,P.attributes);}}}};YAHOO.extend(YAHOO.widget.Button,YAHOO.util.Element,{_button:null,_menu:null,_hiddenFields:null,_onclickAttributeValue:null,_activationKeyPressed:false,_activationButtonPressed:false,_hasKeyEventHandlers:false,_hasMouseEventHandlers:false,_nOptionRegionX:0,CLASS_NAME_PREFIX:"yui-",NODE_NAME:"SPAN",CHECK_ACTIVATION_KEYS:[32],ACTIVATION_KEYS:[13,32],OPTION_AREA_WIDTH:20,CSS_CLASS_NAME:"button",_setType:function(N){if(N=="split"){this.on("option",this._onOption);}},_setLabel:function(O){this._button.innerHTML=O;var P,N=L.gecko;if(N&&N<1.9&&G.inDocument(this.get("element"))){P=(this.CLASS_NAME_PREFIX+this.CSS_CLASS_NAME);this.removeClass(P);I.later(0,this,this.addClass,P);}},_setTabIndex:function(N){this._button.tabIndex=N;},_setTitle:function(N){if(this.get("type")!="link"){this._button.title=N;}},_setDisabled:function(N){if(this.get("type")!="link"){if(N){if(this._menu){this._menu.hide();}if(this.hasFocus()){this.blur();}this._button.setAttribute("disabled","disabled");this.addStateCSSClasses("disabled");this.removeStateCSSClasses("hover");this.removeStateCSSClasses("active");this.removeStateCSSClasses("focus");}else{this._button.removeAttribute("disabled");this.removeStateCSSClasses("disabled");}}},_setHref:function(N){if(this.get("type")=="link"){this._button.href=N;}},_setTarget:function(N){if(this.get("type")=="link"){this._button.setAttribute("target",N);}},_setChecked:function(N){var O=this.get("type");if(O=="checkbox"||O=="radio"){if(N){this.addStateCSSClasses("checked");}else{this.removeStateCSSClasses("checked");}}},_setMenu:function(U){var P=this.get("lazyloadmenu"),R=this.get("element"),N,W=false,X,O,Q;function V(){X.render(R.parentNode);this.removeListener("appendTo",V);}function T(){X.cfg.queueProperty("container",R.parentNode);this.removeListener("appendTo",T);}function S(){var Y;if(X){G.addClass(X.element,this.get("menuclassname"));G.addClass(X.element,this.CLASS_NAME_PREFIX+this.get("type")+"-button-menu");X.showEvent.subscribe(this._onMenuShow,null,this);X.hideEvent.subscribe(this._onMenuHide,null,this);X.renderEvent.subscribe(this._onMenuRender,null,this);if(J&&X instanceof J){if(P){Y=this.get("container");if(Y){X.cfg.queueProperty("container",Y);}else{this.on("appendTo",T);}}X.cfg.queueProperty("clicktohide",false);X.keyDownEvent.subscribe(this._onMenuKeyDown,this,true);X.subscribe("click",this._onMenuClick,this,true);this.on("selectedMenuItemChange",this._onSelectedMenuItemChange);Q=X.srcElement;if(Q&&Q.nodeName.toUpperCase()=="SELECT"){Q.style.display="none";Q.parentNode.removeChild(Q);}}else{if(B&&X instanceof B){if(!K){K=new YAHOO.widget.OverlayManager();}K.register(X);}}this._menu=X;if(!W&&!P){if(G.inDocument(R)){X.render(R.parentNode);}else{this.on("appendTo",V);}}}}if(B){if(J){N=J.prototype.CSS_CLASS_NAME;}if(U&&J&&(U instanceof J)){X=U;W=true;S.call(this);}else{if(B&&U&&(U instanceof B)){X=U;W=true;X.cfg.queueProperty("visible",false);S.call(this);}else{if(J&&I.isArray(U)){X=new J(G.generateId(),{lazyload:P,itemdata:U});this._menu=X;this.on("appendTo",S);}else{if(I.isString(U)){O=G.get(U);if(O){if(J&&G.hasClass(O,N)||O.nodeName.toUpperCase()=="SELECT"){X=new J(U,{lazyload:P});S.call(this);}else{if(B){X=new B(U,{visible:false});S.call(this);}}}}else{if(U&&U.nodeName){if(J&&G.hasClass(U,N)||U.nodeName.toUpperCase()=="SELECT"){X=new J(U,{lazyload:P});S.call(this);}else{if(B){if(!U.id){G.generateId(U);}X=new B(U,{visible:false});S.call(this);}}}}}}}}},_setOnClick:function(N){if(this._onclickAttributeValue&&(this._onclickAttributeValue!=N)){this.removeListener("click",this._onclickAttributeValue.fn); +this._onclickAttributeValue=null;}if(!this._onclickAttributeValue&&I.isObject(N)&&I.isFunction(N.fn)){this.on("click",N.fn,N.obj,N.scope);this._onclickAttributeValue=N;}},_isActivationKey:function(N){var S=this.get("type"),O=(S=="checkbox"||S=="radio")?this.CHECK_ACTIVATION_KEYS:this.ACTIVATION_KEYS,Q=O.length,R=false,P;if(Q>0){P=Q-1;do{if(N==O[P]){R=true;break;}}while(P--);}return R;},_isSplitButtonOptionKey:function(P){var O=(M.getCharCode(P)==40);var N=function(Q){M.preventDefault(Q);this.removeListener("keypress",N);};if(O){if(L.opera){this.on("keypress",N);}M.preventDefault(P);}return O;},_addListenersToForm:function(){var T=this.getForm(),S=YAHOO.widget.Button.onFormKeyPress,R,N,Q,P,O;if(T){M.on(T,"reset",this._onFormReset,null,this);M.on(T,"submit",this._onFormSubmit,null,this);N=this.get("srcelement");if(this.get("type")=="submit"||(N&&N.type=="submit")){Q=M.getListeners(T,"keypress");R=false;if(Q){P=Q.length;if(P>0){O=P-1;do{if(Q[O].fn==S){R=true;break;}}while(O--);}}if(!R){M.on(T,"keypress",S);}}}},_showMenu:function(R){if(YAHOO.widget.MenuManager){YAHOO.widget.MenuManager.hideVisible();}if(K){K.hideAll();}var N=this._menu,Q=this.get("menualignment"),P=this.get("focusmenu"),O;if(this._renderedMenu){N.cfg.setProperty("context",[this.get("element"),Q[0],Q[1]]);N.cfg.setProperty("preventcontextoverlap",true);N.cfg.setProperty("constraintoviewport",true);}else{N.cfg.queueProperty("context",[this.get("element"),Q[0],Q[1]]);N.cfg.queueProperty("preventcontextoverlap",true);N.cfg.queueProperty("constraintoviewport",true);}this.focus();if(J&&N&&(N instanceof J)){O=N.focus;N.focus=function(){};if(this._renderedMenu){N.cfg.setProperty("minscrollheight",this.get("menuminscrollheight"));N.cfg.setProperty("maxheight",this.get("menumaxheight"));}else{N.cfg.queueProperty("minscrollheight",this.get("menuminscrollheight"));N.cfg.queueProperty("maxheight",this.get("menumaxheight"));}N.show();N.focus=O;N.align();if(R.type=="mousedown"){M.stopPropagation(R);}if(P){N.focus();}}else{if(B&&N&&(N instanceof B)){if(!this._renderedMenu){N.render(this.get("element").parentNode);}N.show();N.align();}}},_hideMenu:function(){var N=this._menu;if(N){N.hide();}},_onMouseOver:function(O){var Q=this.get("type"),N,P;if(Q==="split"){N=this.get("element");P=(G.getX(N)+(N.offsetWidth-this.OPTION_AREA_WIDTH));this._nOptionRegionX=P;}if(!this._hasMouseEventHandlers){if(Q==="split"){this.on("mousemove",this._onMouseMove);}this.on("mouseout",this._onMouseOut);this._hasMouseEventHandlers=true;}this.addStateCSSClasses("hover");if(Q==="split"&&(M.getPageX(O)>P)){this.addStateCSSClasses("hoveroption");}if(this._activationButtonPressed){this.addStateCSSClasses("active");}if(this._bOptionPressed){this.addStateCSSClasses("activeoption");}if(this._activationButtonPressed||this._bOptionPressed){M.removeListener(document,"mouseup",this._onDocumentMouseUp);}},_onMouseMove:function(N){var O=this._nOptionRegionX;if(O){if(M.getPageX(N)>O){this.addStateCSSClasses("hoveroption");}else{this.removeStateCSSClasses("hoveroption");}}},_onMouseOut:function(N){var O=this.get("type");this.removeStateCSSClasses("hover");if(O!="menu"){this.removeStateCSSClasses("active");}if(this._activationButtonPressed||this._bOptionPressed){M.on(document,"mouseup",this._onDocumentMouseUp,null,this);}if(O==="split"&&(M.getPageX(N)>this._nOptionRegionX)){this.removeStateCSSClasses("hoveroption");}},_onDocumentMouseUp:function(P){this._activationButtonPressed=false;this._bOptionPressed=false;var Q=this.get("type"),N,O;if(Q=="menu"||Q=="split"){N=M.getTarget(P);O=this._menu.element;if(N!=O&&!G.isAncestor(O,N)){this.removeStateCSSClasses((Q=="menu"?"active":"activeoption"));this._hideMenu();}}M.removeListener(document,"mouseup",this._onDocumentMouseUp);},_onMouseDown:function(P){var Q,O=true;function N(){this._hideMenu();this.removeListener("mouseup",N);}if((P.which||P.button)==1){if(!this.hasFocus()){this.focus();}Q=this.get("type");if(Q=="split"){if(M.getPageX(P)>this._nOptionRegionX){this.fireEvent("option",P);O=false;}else{this.addStateCSSClasses("active");this._activationButtonPressed=true;}}else{if(Q=="menu"){if(this.isActive()){this._hideMenu();this._activationButtonPressed=false;}else{this._showMenu(P);this._activationButtonPressed=true;}}else{this.addStateCSSClasses("active");this._activationButtonPressed=true;}}if(Q=="split"||Q=="menu"){this._hideMenuTimer=I.later(250,this,this.on,["mouseup",N]);}}return O;},_onMouseUp:function(P){var Q=this.get("type"),N=this._hideMenuTimer,O=true;if(N){N.cancel();}if(Q=="checkbox"||Q=="radio"){this.set("checked",!(this.get("checked")));}this._activationButtonPressed=false;if(Q!="menu"){this.removeStateCSSClasses("active");}if(Q=="split"&&M.getPageX(P)>this._nOptionRegionX){O=false;}return O;},_onFocus:function(O){var N;this.addStateCSSClasses("focus");if(this._activationKeyPressed){this.addStateCSSClasses("active");}C=this;if(!this._hasKeyEventHandlers){N=this._button;M.on(N,"blur",this._onBlur,null,this);M.on(N,"keydown",this._onKeyDown,null,this);M.on(N,"keyup",this._onKeyUp,null,this);this._hasKeyEventHandlers=true;}this.fireEvent("focus",O);},_onBlur:function(N){this.removeStateCSSClasses("focus");if(this.get("type")!="menu"){this.removeStateCSSClasses("active");}if(this._activationKeyPressed){M.on(document,"keyup",this._onDocumentKeyUp,null,this);}C=null;this.fireEvent("blur",N);},_onDocumentKeyUp:function(N){if(this._isActivationKey(M.getCharCode(N))){this._activationKeyPressed=false;M.removeListener(document,"keyup",this._onDocumentKeyUp);}},_onKeyDown:function(O){var N=this._menu;if(this.get("type")=="split"&&this._isSplitButtonOptionKey(O)){this.fireEvent("option",O);}else{if(this._isActivationKey(M.getCharCode(O))){if(this.get("type")=="menu"){this._showMenu(O);}else{this._activationKeyPressed=true;this.addStateCSSClasses("active");}}}if(N&&N.cfg.getProperty("visible")&&M.getCharCode(O)==27){N.hide();this.focus();}},_onKeyUp:function(N){var O;if(this._isActivationKey(M.getCharCode(N))){O=this.get("type");if(O=="checkbox"||O=="radio"){this.set("checked",!(this.get("checked"))); +}this._activationKeyPressed=false;if(this.get("type")!="menu"){this.removeStateCSSClasses("active");}}},_onClick:function(P){var R=this.get("type"),Q,N,O;switch(R){case"submit":if(P.returnValue!==false){this.submitForm();}break;case"reset":Q=this.getForm();if(Q){Q.reset();}break;case"split":if(this._nOptionRegionX>0&&(M.getPageX(P)>this._nOptionRegionX)){O=false;}else{this._hideMenu();N=this.get("srcelement");if(N&&N.type=="submit"&&P.returnValue!==false){this.submitForm();}}break;}return O;},_onDblClick:function(O){var N=true;if(this.get("type")=="split"&&M.getPageX(O)>this._nOptionRegionX){N=false;}return N;},_onAppendTo:function(N){I.later(0,this,this._addListenersToForm);},_onFormReset:function(O){var P=this.get("type"),N=this._menu;if(P=="checkbox"||P=="radio"){this.resetValue("checked");}if(J&&N&&(N instanceof J)){this.resetValue("selectedMenuItem");}},_onFormSubmit:function(N){this.createHiddenFields();},_onDocumentMouseDown:function(Q){var N=M.getTarget(Q),P=this.get("element"),O=this._menu.element;if(N!=P&&!G.isAncestor(P,N)&&N!=O&&!G.isAncestor(O,N)){this._hideMenu();if(L.ie&&N.focus){N.setActive();}M.removeListener(document,"mousedown",this._onDocumentMouseDown);}},_onOption:function(N){if(this.hasClass(this.CLASS_NAME_PREFIX+"split-button-activeoption")){this._hideMenu();this._bOptionPressed=false;}else{this._showMenu(N);this._bOptionPressed=true;}},_onMenuShow:function(N){M.on(document,"mousedown",this._onDocumentMouseDown,null,this);var O=(this.get("type")=="split")?"activeoption":"active";this.addStateCSSClasses(O);},_onMenuHide:function(N){var O=(this.get("type")=="split")?"activeoption":"active";this.removeStateCSSClasses(O);if(this.get("type")=="split"){this._bOptionPressed=false;}},_onMenuKeyDown:function(P,O){var N=O[0];if(M.getCharCode(N)==27){this.focus();if(this.get("type")=="split"){this._bOptionPressed=false;}}},_onMenuRender:function(P){var S=this.get("element"),O=S.parentNode,N=this._menu,R=N.element,Q=N.srcElement,T;if(O!=R.parentNode){O.appendChild(R);}this._renderedMenu=true;if(Q&&Q.nodeName.toLowerCase()==="select"&&Q.value){T=N.getItem(Q.selectedIndex);this.set("selectedMenuItem",T,true);this._onSelectedMenuItemChange({newValue:T});}},_onMenuClick:function(O,N){var Q=N[1],P;if(Q){this.set("selectedMenuItem",Q);P=this.get("srcelement");if(P&&P.type=="submit"){this.submitForm();}this._hideMenu();}},_onSelectedMenuItemChange:function(O){var P=O.prevValue,Q=O.newValue,N=this.CLASS_NAME_PREFIX;if(P){G.removeClass(P.element,(N+"button-selectedmenuitem"));}if(Q){G.addClass(Q.element,(N+"button-selectedmenuitem"));}},_onLabelClick:function(N){this.focus();var O=this.get("type");if(O=="radio"||O=="checkbox"){this.set("checked",(!this.get("checked")));}},createButtonElement:function(N){var P=this.NODE_NAME,O=document.createElement(P);O.innerHTML="<"+P+' class="first-child">'+(N=="link"?"":'')+"";return O;},addStateCSSClasses:function(O){var P=this.get("type"),N=this.CLASS_NAME_PREFIX;if(I.isString(O)){if(O!="activeoption"&&O!="hoveroption"){this.addClass(N+this.CSS_CLASS_NAME+("-"+O));}this.addClass(N+P+("-button-"+O));}},removeStateCSSClasses:function(O){var P=this.get("type"),N=this.CLASS_NAME_PREFIX;if(I.isString(O)){this.removeClass(N+this.CSS_CLASS_NAME+("-"+O));this.removeClass(N+P+("-button-"+O));}},createHiddenFields:function(){this.removeHiddenFields();var V=this.getForm(),Z,O,S,X,Y,T,U,N,R,W,P,Q=false;if(V&&!this.get("disabled")){O=this.get("type");S=(O=="checkbox"||O=="radio");if((S&&this.get("checked"))||(E==this)){Z=F((S?O:"hidden"),this.get("name"),this.get("value"),this.get("checked"));if(Z){if(S){Z.style.display="none";}V.appendChild(Z);}}X=this._menu;if(J&&X&&(X instanceof J)){Y=this.get("selectedMenuItem");P=X.srcElement;Q=(P&&P.nodeName.toUpperCase()=="SELECT");if(Y){U=(Y.value===null||Y.value==="")?Y.cfg.getProperty("text"):Y.value;T=this.get("name");if(Q){W=P.name;}else{if(T){W=(T+"_options");}}if(U&&W){N=F("hidden",W,U);V.appendChild(N);}}else{if(Q){N=V.appendChild(P);}}}if(Z&&N){this._hiddenFields=[Z,N];}else{if(!Z&&N){this._hiddenFields=N;}else{if(Z&&!N){this._hiddenFields=Z;}}}R=this._hiddenFields;}return R;},removeHiddenFields:function(){var Q=this._hiddenFields,O,P;function N(R){if(G.inDocument(R)){R.parentNode.removeChild(R);}}if(Q){if(I.isArray(Q)){O=Q.length;if(O>0){P=O-1;do{N(Q[P]);}while(P--);}}else{N(Q);}this._hiddenFields=null;}},submitForm:function(){var Q=this.getForm(),P=this.get("srcelement"),O=false,N;if(Q){if(this.get("type")=="submit"||(P&&P.type=="submit")){E=this;}if(L.ie){O=Q.fireEvent("onsubmit");}else{N=document.createEvent("HTMLEvents");N.initEvent("submit",true,true);O=Q.dispatchEvent(N);}if((L.ie||L.webkit)&&O){Q.submit();}}return O;},init:function(P,d){var V=d.type=="link"?"a":"button",a=d.srcelement,S=P.getElementsByTagName(V)[0],U;if(!S){U=P.getElementsByTagName("input")[0];if(U){S=document.createElement("button");S.setAttribute("type","button");U.parentNode.replaceChild(S,U);}}this._button=S;YAHOO.widget.Button.superclass.init.call(this,P,d);var T=this.get("id"),Z=T+"-button";S.id=Z;var X,Q;var e=function(f){return(f.htmlFor===T);};var c=function(){Q.setAttribute((L.ie?"htmlFor":"for"),Z);};if(a&&this.get("type")!="link"){X=G.getElementsBy(e,"label");if(I.isArray(X)&&X.length>0){Q=X[0];}}D[T]=this;var b=this.CLASS_NAME_PREFIX;this.addClass(b+this.CSS_CLASS_NAME);this.addClass(b+this.get("type")+"-button");M.on(this._button,"focus",this._onFocus,null,this);this.on("mouseover",this._onMouseOver);this.on("mousedown",this._onMouseDown);this.on("mouseup",this._onMouseUp);this.on("click",this._onClick);var R=this.get("onclick");this.set("onclick",null);this.set("onclick",R);this.on("dblclick",this._onDblClick);var O;if(Q){if(this.get("replaceLabel")){this.set("label",Q.innerHTML);O=Q.parentNode;O.removeChild(Q);}else{this.on("appendTo",c);M.on(Q,"click",this._onLabelClick,null,this);this._label=Q;}}this.on("appendTo",this._onAppendTo);var N=this.get("container"),Y=this.get("element"),W=G.inDocument(Y); +if(N){if(a&&a!=Y){O=a.parentNode;if(O){O.removeChild(a);}}if(I.isString(N)){M.onContentReady(N,this.appendTo,N,this);}else{this.on("init",function(){I.later(0,this,this.appendTo,N);});}}else{if(!W&&a&&a!=Y){O=a.parentNode;if(O){this.fireEvent("beforeAppendTo",{type:"beforeAppendTo",target:O});O.replaceChild(Y,a);this.fireEvent("appendTo",{type:"appendTo",target:O});}}else{if(this.get("type")!="link"&&W&&a&&a==Y){this._addListenersToForm();}}}this.fireEvent("init",{type:"init",target:this});},initAttributes:function(O){var N=O||{};YAHOO.widget.Button.superclass.initAttributes.call(this,N);this.setAttributeConfig("type",{value:(N.type||"push"),validator:I.isString,writeOnce:true,method:this._setType});this.setAttributeConfig("label",{value:N.label,validator:I.isString,method:this._setLabel});this.setAttributeConfig("value",{value:N.value});this.setAttributeConfig("name",{value:N.name,validator:I.isString});this.setAttributeConfig("tabindex",{value:N.tabindex,validator:I.isNumber,method:this._setTabIndex});this.configureAttribute("title",{value:N.title,validator:I.isString,method:this._setTitle});this.setAttributeConfig("disabled",{value:(N.disabled||false),validator:I.isBoolean,method:this._setDisabled});this.setAttributeConfig("href",{value:N.href,validator:I.isString,method:this._setHref});this.setAttributeConfig("target",{value:N.target,validator:I.isString,method:this._setTarget});this.setAttributeConfig("checked",{value:(N.checked||false),validator:I.isBoolean,method:this._setChecked});this.setAttributeConfig("container",{value:N.container,writeOnce:true});this.setAttributeConfig("srcelement",{value:N.srcelement,writeOnce:true});this.setAttributeConfig("menu",{value:null,method:this._setMenu,writeOnce:true});this.setAttributeConfig("lazyloadmenu",{value:(N.lazyloadmenu===false?false:true),validator:I.isBoolean,writeOnce:true});this.setAttributeConfig("menuclassname",{value:(N.menuclassname||(this.CLASS_NAME_PREFIX+"button-menu")),validator:I.isString,method:this._setMenuClassName,writeOnce:true});this.setAttributeConfig("menuminscrollheight",{value:(N.menuminscrollheight||90),validator:I.isNumber});this.setAttributeConfig("menumaxheight",{value:(N.menumaxheight||0),validator:I.isNumber});this.setAttributeConfig("menualignment",{value:(N.menualignment||["tl","bl"]),validator:I.isArray});this.setAttributeConfig("selectedMenuItem",{value:null});this.setAttributeConfig("onclick",{value:N.onclick,method:this._setOnClick});this.setAttributeConfig("focusmenu",{value:(N.focusmenu===false?false:true),validator:I.isBoolean});this.setAttributeConfig("replaceLabel",{value:false,validator:I.isBoolean,writeOnce:true});},focus:function(){if(!this.get("disabled")){this._button.focus();}},blur:function(){if(!this.get("disabled")){this._button.blur();}},hasFocus:function(){return(C==this);},isActive:function(){return this.hasClass(this.CLASS_NAME_PREFIX+this.CSS_CLASS_NAME+"-active");},getMenu:function(){return this._menu;},getForm:function(){var N=this._button,O;if(N){O=N.form;}return O;},getHiddenFields:function(){return this._hiddenFields;},destroy:function(){var P=this.get("element"),N=this._menu,T=this._label,O,S;if(N){if(K&&K.find(N)){K.remove(N);}N.destroy();}M.purgeElement(P);M.purgeElement(this._button);M.removeListener(document,"mouseup",this._onDocumentMouseUp);M.removeListener(document,"keyup",this._onDocumentKeyUp);M.removeListener(document,"mousedown",this._onDocumentMouseDown);if(T){M.removeListener(T,"click",this._onLabelClick);O=T.parentNode;O.removeChild(T);}var Q=this.getForm();if(Q){M.removeListener(Q,"reset",this._onFormReset);M.removeListener(Q,"submit",this._onFormSubmit);}this.unsubscribeAll();O=P.parentNode;if(O){O.removeChild(P);}delete D[this.get("id")];var R=(this.CLASS_NAME_PREFIX+this.CSS_CLASS_NAME);S=G.getElementsByClassName(R,this.NODE_NAME,Q);if(I.isArray(S)&&S.length===0){M.removeListener(Q,"keypress",YAHOO.widget.Button.onFormKeyPress);}},fireEvent:function(O,N){var P=arguments[0];if(this.DOM_EVENTS[P]&&this.get("disabled")){return false;}return YAHOO.widget.Button.superclass.fireEvent.apply(this,arguments);},toString:function(){return("Button "+this.get("id"));}});YAHOO.widget.Button.onFormKeyPress=function(R){var P=M.getTarget(R),S=M.getCharCode(R),Q=P.nodeName&&P.nodeName.toUpperCase(),N=P.type,T=false,V,X,O,W;function U(a){var Z,Y;switch(a.nodeName.toUpperCase()){case"INPUT":case"BUTTON":if(a.type=="submit"&&!a.disabled){if(!T&&!O){O=a;}}break;default:Z=a.id;if(Z){V=D[Z];if(V){T=true;if(!V.get("disabled")){Y=V.get("srcelement");if(!X&&(V.get("type")=="submit"||(Y&&Y.type=="submit"))){X=V;}}}}break;}}if(S==13&&((Q=="INPUT"&&(N=="text"||N=="password"||N=="checkbox"||N=="radio"||N=="file"))||Q=="SELECT")){G.getElementsBy(U,"*",this);if(O){O.focus();}else{if(!O&&X){M.preventDefault(R);if(L.ie){X.get("element").fireEvent("onclick");}else{W=document.createEvent("HTMLEvents");W.initEvent("click",true,true);if(L.gecko<1.9){X.fireEvent("click",W);}else{X.get("element").dispatchEvent(W);}}}}}};YAHOO.widget.Button.addHiddenFieldsToForm=function(N){var R=YAHOO.widget.Button.prototype,T=G.getElementsByClassName((R.CLASS_NAME_PREFIX+R.CSS_CLASS_NAME),"*",N),Q=T.length,S,O,P;if(Q>0){for(P=0;P0){F=H-1;do{this._buttons[F].set("disabled",G);}while(F--);}},_onKeyDown:function(K){var G=B.getTarget(K),I=B.getCharCode(K),H=G.parentNode.parentNode.id,J=E[H],F=-1;if(I==37||I==38){F=(J.index===0)?(this._buttons.length-1):(J.index-1);}else{if(I==39||I==40){F=(J.index===(this._buttons.length-1))?0:(J.index+1);}}if(F>-1){this.check(F);this.getButton(F).focus();}},_onAppendTo:function(H){var I=this._buttons,G=I.length,F;for(F=0;F0){this.addButtons(J);}function F(L){return(L.type=="radio");}J=C.getElementsBy(F,"input",this.get("element"));if(J.length>0){this.addButtons(J);}this.on("keydown",this._onKeyDown);this.on("appendTo",this._onAppendTo);var G=this.get("container");if(G){if(D.isString(G)){B.onContentReady(G,function(){this.appendTo(G);},null,this);}else{this.appendTo(G);}}},initAttributes:function(G){var F=G||{};YAHOO.widget.ButtonGroup.superclass.initAttributes.call(this,F);this.setAttributeConfig("name",{value:F.name,validator:D.isString});this.setAttributeConfig("disabled",{value:(F.disabled||false),validator:D.isBoolean,method:this._setDisabled});this.setAttributeConfig("value",{value:F.value});this.setAttributeConfig("container",{value:F.container,writeOnce:true});this.setAttributeConfig("checkedButton",{value:null});},addButton:function(J){var L,K,G,F,H,I;if(J instanceof A&&J.get("type")=="radio"){L=J;}else{if(!D.isString(J)&&!J.nodeName){J.type="radio";L=new A(J);}else{L=new A(J,{type:"radio"});}}if(L){F=this._buttons.length;H=L.get("name");I=this.get("name");L.index=F;this._buttons[F]=L;E[L.get("id")]=L;if(H!=I){L.set("name",I);}if(this.get("disabled")){L.set("disabled",true);}if(L.get("checked")){this.set("checkedButton",L);}K=L.get("element");G=this.get("element");if(K.parentNode!=G){G.appendChild(K);}L.on("checkedChange",this._onButtonCheckedChange,L,this);}return L;},addButtons:function(G){var H,I,J,F;if(D.isArray(G)){H=G.length;J=[];if(H>0){for(F=0;F0){F=this._buttons.length-1;do{this._buttons[F].index=F;}while(F--);}}},getButton:function(F){return this._buttons[F];},getButtons:function(){return this._buttons;},getCount:function(){return this._buttons.length;},focus:function(H){var I,G,F;if(D.isNumber(H)){I=this._buttons[H];if(I){I.focus();}}else{G=this.getCount();for(F=0;F0){G=this._buttons.length-1;do{this._buttons[G].destroy();}while(G--);}B.purgeElement(H);F.removeChild(H);},toString:function(){return("ButtonGroup "+this.get("id"));}});})();YAHOO.register("button",YAHOO.widget.Button,{version:"2.8.0r4",build:"2449"}); \ No newline at end of file diff --git a/include/javascript/yui/build/button/button.js b/include/javascript/yui/build/button/button.js new file mode 100644 index 00000000..b57c819e --- /dev/null +++ b/include/javascript/yui/build/button/button.js @@ -0,0 +1,4633 @@ +/* +Copyright (c) 2009, Yahoo! Inc. All rights reserved. +Code licensed under the BSD License: +http://developer.yahoo.net/yui/license.txt +version: 2.8.0r4 +*/ +/** +* @module button +* @description

    The Button Control enables the creation of rich, graphical +* buttons that function like traditional HTML form buttons. Unlike +* traditional HTML form buttons, buttons created with the Button Control can have +* a label that is different from its value. With the inclusion of the optional +* Menu Control, the Button Control can also be +* used to create menu buttons and split buttons, controls that are not +* available natively in HTML. The Button Control can also be thought of as a +* way to create more visually engaging implementations of the browser's +* default radio-button and check-box controls.

    +*

    The Button Control supports the following types:

    +*
    +*
    push
    +*
    Basic push button that can execute a user-specified command when +* pressed.
    +*
    link
    +*
    Navigates to a specified url when pressed.
    +*
    submit
    +*
    Submits the parent form when pressed.
    +*
    reset
    +*
    Resets the parent form when pressed.
    +*
    checkbox
    +*
    Maintains a "checked" state that can be toggled on and off.
    +*
    radio
    +*
    Maintains a "checked" state that can be toggled on and off. Use with +* the ButtonGroup class to create a set of controls that are mutually +* exclusive; checking one button in the set will uncheck all others in +* the group.
    +*
    menu
    +*
    When pressed will show/hide a menu.
    +*
    split
    +*
    Can execute a user-specified command or display a menu when pressed.
    +*
    +* @title Button +* @namespace YAHOO.widget +* @requires yahoo, dom, element, event +* @optional container, menu +*/ + + +(function () { + + + /** + * The Button class creates a rich, graphical button. + * @param {String} p_oElement String specifying the id attribute of the + * <input>, <button>, + * <a>, or <span> element to + * be used to create the button. + * @param {HTMLInputElement| + * HTMLButtonElement|HTMLElement} p_oElement Object reference for the + * <input>, <button>, + * <a>, or <span> element to be + * used to create the button. + * @param {Object} p_oElement Object literal specifying a set of + * configuration attributes used to create the button. + * @param {Object} p_oAttributes Optional. Object literal specifying a set + * of configuration attributes used to create the button. + * @namespace YAHOO.widget + * @class Button + * @constructor + * @extends YAHOO.util.Element + */ + + + + // Shorthard for utilities + + var Dom = YAHOO.util.Dom, + Event = YAHOO.util.Event, + Lang = YAHOO.lang, + UA = YAHOO.env.ua, + Overlay = YAHOO.widget.Overlay, + Menu = YAHOO.widget.Menu, + + + // Private member variables + + m_oButtons = {}, // Collection of all Button instances + m_oOverlayManager = null, // YAHOO.widget.OverlayManager instance + m_oSubmitTrigger = null, // The button that submitted the form + m_oFocusedButton = null; // The button that has focus + + + + // Private methods + + + + /** + * @method createInputElement + * @description Creates an <input> element of the + * specified type. + * @private + * @param {String} p_sType String specifying the type of + * <input> element to create. + * @param {String} p_sName String specifying the name of + * <input> element to create. + * @param {String} p_sValue String specifying the value of + * <input> element to create. + * @param {String} p_bChecked Boolean specifying if the + * <input> element is to be checked. + * @return {HTMLInputElement} + */ + function createInputElement(p_sType, p_sName, p_sValue, p_bChecked) { + + var oInput, + sInput; + + if (Lang.isString(p_sType) && Lang.isString(p_sName)) { + + if (UA.ie) { + + /* + For IE it is necessary to create the element with the + "type," "name," "value," and "checked" properties set all + at once. + */ + + sInput = "<input> or <a>) that + * map to Button configuration attributes and sets them into a collection + * that is passed to the Button constructor. + * @private + * @param {HTMLInputElement|HTMLAnchorElement} p_oElement Object reference to the HTML + * element (either <input> or <span> + * ) used to create the button. + * @param {Object} p_oAttributes Object reference for the collection of + * configuration attributes used to create the button. + */ + function setAttributesFromSrcElement(p_oElement, p_oAttributes) { + + var sSrcElementNodeName = p_oElement.nodeName.toUpperCase(), + sClass = (this.CLASS_NAME_PREFIX + this.CSS_CLASS_NAME), + me = this, + oAttribute, + oRootNode, + sText; + + + /** + * @method setAttributeFromDOMAttribute + * @description Gets the value of the specified DOM attribute and sets it + * into the collection of configuration attributes used to configure + * the button. + * @private + * @param {String} p_sAttribute String representing the name of the + * attribute to retrieve from the DOM element. + */ + function setAttributeFromDOMAttribute(p_sAttribute) { + + if (!(p_sAttribute in p_oAttributes)) { + + /* + Need to use "getAttributeNode" instead of "getAttribute" + because using "getAttribute," IE will return the innerText + of a <button> for the value attribute + rather than the value of the "value" attribute. + */ + + oAttribute = p_oElement.getAttributeNode(p_sAttribute); + + + if (oAttribute && ("value" in oAttribute)) { + + + p_oAttributes[p_sAttribute] = oAttribute.value; + + } + + } + + } + + + /** + * @method setFormElementProperties + * @description Gets the value of the attributes from the form element + * and sets them into the collection of configuration attributes used to + * configure the button. + * @private + */ + function setFormElementProperties() { + + setAttributeFromDOMAttribute("type"); + + if (p_oAttributes.type == "button") { + + p_oAttributes.type = "push"; + + } + + if (!("disabled" in p_oAttributes)) { + + p_oAttributes.disabled = p_oElement.disabled; + + } + + setAttributeFromDOMAttribute("name"); + setAttributeFromDOMAttribute("value"); + setAttributeFromDOMAttribute("title"); + + } + + + switch (sSrcElementNodeName) { + + case "A": + + p_oAttributes.type = "link"; + + setAttributeFromDOMAttribute("href"); + setAttributeFromDOMAttribute("target"); + + break; + + case "INPUT": + + setFormElementProperties(); + + if (!("checked" in p_oAttributes)) { + + p_oAttributes.checked = p_oElement.checked; + + } + + break; + + case "BUTTON": + + setFormElementProperties(); + + oRootNode = p_oElement.parentNode.parentNode; + + if (Dom.hasClass(oRootNode, sClass + "-checked")) { + + p_oAttributes.checked = true; + + } + + if (Dom.hasClass(oRootNode, sClass + "-disabled")) { + + p_oAttributes.disabled = true; + + } + + p_oElement.removeAttribute("value"); + + p_oElement.setAttribute("type", "button"); + + break; + + } + + p_oElement.removeAttribute("id"); + p_oElement.removeAttribute("name"); + + if (!("tabindex" in p_oAttributes)) { + + p_oAttributes.tabindex = p_oElement.tabIndex; + + } + + if (!("label" in p_oAttributes)) { + + // Set the "label" property + + sText = sSrcElementNodeName == "INPUT" ? + p_oElement.value : p_oElement.innerHTML; + + + if (sText && sText.length > 0) { + + p_oAttributes.label = sText; + + } + + } + + } + + + /** + * @method initConfig + * @description Initializes the set of configuration attributes that are + * used to instantiate the button. + * @private + * @param {Object} Object representing the button's set of + * configuration attributes. + */ + function initConfig(p_oConfig) { + + var oAttributes = p_oConfig.attributes, + oSrcElement = oAttributes.srcelement, + sSrcElementNodeName = oSrcElement.nodeName.toUpperCase(), + me = this; + + + if (sSrcElementNodeName == this.NODE_NAME) { + + p_oConfig.element = oSrcElement; + p_oConfig.id = oSrcElement.id; + + Dom.getElementsBy(function (p_oElement) { + + switch (p_oElement.nodeName.toUpperCase()) { + + case "BUTTON": + case "A": + case "INPUT": + + setAttributesFromSrcElement.call(me, p_oElement, + oAttributes); + + break; + + } + + }, "*", oSrcElement); + + } + else { + + switch (sSrcElementNodeName) { + + case "BUTTON": + case "A": + case "INPUT": + + setAttributesFromSrcElement.call(this, oSrcElement, + oAttributes); + + break; + + } + + } + + } + + + + // Constructor + + YAHOO.widget.Button = function (p_oElement, p_oAttributes) { + + if (!Overlay && YAHOO.widget.Overlay) { + + Overlay = YAHOO.widget.Overlay; + + } + + + if (!Menu && YAHOO.widget.Menu) { + + Menu = YAHOO.widget.Menu; + + } + + + var fnSuperClass = YAHOO.widget.Button.superclass.constructor, + oConfig, + oElement; + + + if (arguments.length == 1 && !Lang.isString(p_oElement) && !p_oElement.nodeName) { + + if (!p_oElement.id) { + + p_oElement.id = Dom.generateId(); + + + } + + + fnSuperClass.call(this, (this.createButtonElement(p_oElement.type)), p_oElement); + + } + else { + + oConfig = { element: null, attributes: (p_oAttributes || {}) }; + + + if (Lang.isString(p_oElement)) { + + oElement = Dom.get(p_oElement); + + if (oElement) { + + if (!oConfig.attributes.id) { + + oConfig.attributes.id = p_oElement; + + } + + + + oConfig.attributes.srcelement = oElement; + + initConfig.call(this, oConfig); + + + if (!oConfig.element) { + + + oConfig.element = this.createButtonElement(oConfig.attributes.type); + + } + + fnSuperClass.call(this, oConfig.element, oConfig.attributes); + + } + + } + else if (p_oElement.nodeName) { + + if (!oConfig.attributes.id) { + + if (p_oElement.id) { + + oConfig.attributes.id = p_oElement.id; + + } + else { + + oConfig.attributes.id = Dom.generateId(); + + + } + + } + + + + oConfig.attributes.srcelement = p_oElement; + + initConfig.call(this, oConfig); + + + if (!oConfig.element) { + + + oConfig.element = this.createButtonElement(oConfig.attributes.type); + + } + + fnSuperClass.call(this, oConfig.element, oConfig.attributes); + + } + + } + + }; + + + + YAHOO.extend(YAHOO.widget.Button, YAHOO.util.Element, { + + + // Protected properties + + + /** + * @property _button + * @description Object reference to the button's internal + * <a> or <button> element. + * @default null + * @protected + * @type HTMLAnchorElement|HTMLButtonElement + */ + _button: null, + + + /** + * @property _menu + * @description Object reference to the button's menu. + * @default null + * @protected + * @type {YAHOO.widget.Overlay| + * YAHOO.widget.Menu} + */ + _menu: null, + + + /** + * @property _hiddenFields + * @description Object reference to the <input> + * element, or array of HTML form elements used to represent the button + * when its parent form is submitted. + * @default null + * @protected + * @type HTMLInputElement|Array + */ + _hiddenFields: null, + + + /** + * @property _onclickAttributeValue + * @description Object reference to the button's current value for the + * "onclick" configuration attribute. + * @default null + * @protected + * @type Object + */ + _onclickAttributeValue: null, + + + /** + * @property _activationKeyPressed + * @description Boolean indicating if the key(s) that toggle the button's + * "active" state have been pressed. + * @default false + * @protected + * @type Boolean + */ + _activationKeyPressed: false, + + + /** + * @property _activationButtonPressed + * @description Boolean indicating if the mouse button that toggles + * the button's "active" state has been pressed. + * @default false + * @protected + * @type Boolean + */ + _activationButtonPressed: false, + + + /** + * @property _hasKeyEventHandlers + * @description Boolean indicating if the button's "blur", "keydown" and + * "keyup" event handlers are assigned + * @default false + * @protected + * @type Boolean + */ + _hasKeyEventHandlers: false, + + + /** + * @property _hasMouseEventHandlers + * @description Boolean indicating if the button's "mouseout," + * "mousedown," and "mouseup" event handlers are assigned + * @default false + * @protected + * @type Boolean + */ + _hasMouseEventHandlers: false, + + + /** + * @property _nOptionRegionX + * @description Number representing the X coordinate of the leftmost edge of the Button's + * option region. Applies only to Buttons of type "split". + * @default 0 + * @protected + * @type Number + */ + _nOptionRegionX: 0, + + + + // Constants + + /** + * @property CLASS_NAME_PREFIX + * @description Prefix used for all class names applied to a Button. + * @default "yui-" + * @final + * @type String + */ + CLASS_NAME_PREFIX: "yui-", + + + /** + * @property NODE_NAME + * @description The name of the node to be used for the button's + * root element. + * @default "SPAN" + * @final + * @type String + */ + NODE_NAME: "SPAN", + + + /** + * @property CHECK_ACTIVATION_KEYS + * @description Array of numbers representing keys that (when pressed) + * toggle the button's "checked" attribute. + * @default [32] + * @final + * @type Array + */ + CHECK_ACTIVATION_KEYS: [32], + + + /** + * @property ACTIVATION_KEYS + * @description Array of numbers representing keys that (when presed) + * toggle the button's "active" state. + * @default [13, 32] + * @final + * @type Array + */ + ACTIVATION_KEYS: [13, 32], + + + /** + * @property OPTION_AREA_WIDTH + * @description Width (in pixels) of the area of a split button that + * when pressed will display a menu. + * @default 20 + * @final + * @type Number + */ + OPTION_AREA_WIDTH: 20, + + + /** + * @property CSS_CLASS_NAME + * @description String representing the CSS class(es) to be applied to + * the button's root element. + * @default "button" + * @final + * @type String + */ + CSS_CLASS_NAME: "button", + + + + // Protected attribute setter methods + + + /** + * @method _setType + * @description Sets the value of the button's "type" attribute. + * @protected + * @param {String} p_sType String indicating the value for the button's + * "type" attribute. + */ + _setType: function (p_sType) { + + if (p_sType == "split") { + + this.on("option", this._onOption); + + } + + }, + + + /** + * @method _setLabel + * @description Sets the value of the button's "label" attribute. + * @protected + * @param {String} p_sLabel String indicating the value for the button's + * "label" attribute. + */ + _setLabel: function (p_sLabel) { + + this._button.innerHTML = p_sLabel; + + + /* + Remove and add the default class name from the root element + for Gecko to ensure that the button shrinkwraps to the label. + Without this the button will not be rendered at the correct + width when the label changes. The most likely cause for this + bug is button's use of the Gecko-specific CSS display type of + "-moz-inline-box" to simulate "inline-block" supported by IE, + Safari and Opera. + */ + + var sClass, + nGeckoVersion = UA.gecko; + + + if (nGeckoVersion && nGeckoVersion < 1.9 && Dom.inDocument(this.get("element"))) { + + sClass = (this.CLASS_NAME_PREFIX + this.CSS_CLASS_NAME); + + this.removeClass(sClass); + + Lang.later(0, this, this.addClass, sClass); + + } + + }, + + + /** + * @method _setTabIndex + * @description Sets the value of the button's "tabindex" attribute. + * @protected + * @param {Number} p_nTabIndex Number indicating the value for the + * button's "tabindex" attribute. + */ + _setTabIndex: function (p_nTabIndex) { + + this._button.tabIndex = p_nTabIndex; + + }, + + + /** + * @method _setTitle + * @description Sets the value of the button's "title" attribute. + * @protected + * @param {String} p_nTabIndex Number indicating the value for + * the button's "title" attribute. + */ + _setTitle: function (p_sTitle) { + + if (this.get("type") != "link") { + + this._button.title = p_sTitle; + + } + + }, + + + /** + * @method _setDisabled + * @description Sets the value of the button's "disabled" attribute. + * @protected + * @param {Boolean} p_bDisabled Boolean indicating the value for + * the button's "disabled" attribute. + */ + _setDisabled: function (p_bDisabled) { + + if (this.get("type") != "link") { + + if (p_bDisabled) { + + if (this._menu) { + + this._menu.hide(); + + } + + if (this.hasFocus()) { + + this.blur(); + + } + + this._button.setAttribute("disabled", "disabled"); + + this.addStateCSSClasses("disabled"); + + this.removeStateCSSClasses("hover"); + this.removeStateCSSClasses("active"); + this.removeStateCSSClasses("focus"); + + } + else { + + this._button.removeAttribute("disabled"); + + this.removeStateCSSClasses("disabled"); + + } + + } + + }, + + + /** + * @method _setHref + * @description Sets the value of the button's "href" attribute. + * @protected + * @param {String} p_sHref String indicating the value for the button's + * "href" attribute. + */ + _setHref: function (p_sHref) { + + if (this.get("type") == "link") { + + this._button.href = p_sHref; + + } + + }, + + + /** + * @method _setTarget + * @description Sets the value of the button's "target" attribute. + * @protected + * @param {String} p_sTarget String indicating the value for the button's + * "target" attribute. + */ + _setTarget: function (p_sTarget) { + + if (this.get("type") == "link") { + + this._button.setAttribute("target", p_sTarget); + + } + + }, + + + /** + * @method _setChecked + * @description Sets the value of the button's "target" attribute. + * @protected + * @param {Boolean} p_bChecked Boolean indicating the value for + * the button's "checked" attribute. + */ + _setChecked: function (p_bChecked) { + + var sType = this.get("type"); + + if (sType == "checkbox" || sType == "radio") { + + if (p_bChecked) { + this.addStateCSSClasses("checked"); + } + else { + this.removeStateCSSClasses("checked"); + } + + } + + }, + + + /** + * @method _setMenu + * @description Sets the value of the button's "menu" attribute. + * @protected + * @param {Object} p_oMenu Object indicating the value for the button's + * "menu" attribute. + */ + _setMenu: function (p_oMenu) { + + var bLazyLoad = this.get("lazyloadmenu"), + oButtonElement = this.get("element"), + sMenuCSSClassName, + + /* + Boolean indicating if the value of p_oMenu is an instance + of YAHOO.widget.Menu or YAHOO.widget.Overlay. + */ + + bInstance = false, + oMenu, + oMenuElement, + oSrcElement; + + + function onAppendTo() { + + oMenu.render(oButtonElement.parentNode); + + this.removeListener("appendTo", onAppendTo); + + } + + + function setMenuContainer() { + + oMenu.cfg.queueProperty("container", oButtonElement.parentNode); + + this.removeListener("appendTo", setMenuContainer); + + } + + + function initMenu() { + + var oContainer; + + if (oMenu) { + + Dom.addClass(oMenu.element, this.get("menuclassname")); + Dom.addClass(oMenu.element, this.CLASS_NAME_PREFIX + this.get("type") + "-button-menu"); + + oMenu.showEvent.subscribe(this._onMenuShow, null, this); + oMenu.hideEvent.subscribe(this._onMenuHide, null, this); + oMenu.renderEvent.subscribe(this._onMenuRender, null, this); + + + if (Menu && oMenu instanceof Menu) { + + if (bLazyLoad) { + + oContainer = this.get("container"); + + if (oContainer) { + + oMenu.cfg.queueProperty("container", oContainer); + + } + else { + + this.on("appendTo", setMenuContainer); + + } + + } + + oMenu.cfg.queueProperty("clicktohide", false); + + oMenu.keyDownEvent.subscribe(this._onMenuKeyDown, this, true); + oMenu.subscribe("click", this._onMenuClick, this, true); + + this.on("selectedMenuItemChange", this._onSelectedMenuItemChange); + + oSrcElement = oMenu.srcElement; + + if (oSrcElement && oSrcElement.nodeName.toUpperCase() == "SELECT") { + + oSrcElement.style.display = "none"; + oSrcElement.parentNode.removeChild(oSrcElement); + + } + + } + else if (Overlay && oMenu instanceof Overlay) { + + if (!m_oOverlayManager) { + + m_oOverlayManager = new YAHOO.widget.OverlayManager(); + + } + + m_oOverlayManager.register(oMenu); + + } + + + this._menu = oMenu; + + + if (!bInstance && !bLazyLoad) { + + if (Dom.inDocument(oButtonElement)) { + + oMenu.render(oButtonElement.parentNode); + + } + else { + + this.on("appendTo", onAppendTo); + + } + + } + + } + + } + + + if (Overlay) { + + if (Menu) { + + sMenuCSSClassName = Menu.prototype.CSS_CLASS_NAME; + + } + + if (p_oMenu && Menu && (p_oMenu instanceof Menu)) { + + oMenu = p_oMenu; + bInstance = true; + + initMenu.call(this); + + } + else if (Overlay && p_oMenu && (p_oMenu instanceof Overlay)) { + + oMenu = p_oMenu; + bInstance = true; + + oMenu.cfg.queueProperty("visible", false); + + initMenu.call(this); + + } + else if (Menu && Lang.isArray(p_oMenu)) { + + oMenu = new Menu(Dom.generateId(), { lazyload: bLazyLoad, itemdata: p_oMenu }); + + this._menu = oMenu; + + this.on("appendTo", initMenu); + + } + else if (Lang.isString(p_oMenu)) { + + oMenuElement = Dom.get(p_oMenu); + + if (oMenuElement) { + + if (Menu && Dom.hasClass(oMenuElement, sMenuCSSClassName) || + oMenuElement.nodeName.toUpperCase() == "SELECT") { + + oMenu = new Menu(p_oMenu, { lazyload: bLazyLoad }); + + initMenu.call(this); + + } + else if (Overlay) { + + oMenu = new Overlay(p_oMenu, { visible: false }); + + initMenu.call(this); + + } + + } + + } + else if (p_oMenu && p_oMenu.nodeName) { + + if (Menu && Dom.hasClass(p_oMenu, sMenuCSSClassName) || + p_oMenu.nodeName.toUpperCase() == "SELECT") { + + oMenu = new Menu(p_oMenu, { lazyload: bLazyLoad }); + + initMenu.call(this); + + } + else if (Overlay) { + + if (!p_oMenu.id) { + + Dom.generateId(p_oMenu); + + } + + oMenu = new Overlay(p_oMenu, { visible: false }); + + initMenu.call(this); + + } + + } + + } + + }, + + + /** + * @method _setOnClick + * @description Sets the value of the button's "onclick" attribute. + * @protected + * @param {Object} p_oObject Object indicating the value for the button's + * "onclick" attribute. + */ + _setOnClick: function (p_oObject) { + + /* + Remove any existing listeners if a "click" event handler + has already been specified. + */ + + if (this._onclickAttributeValue && + (this._onclickAttributeValue != p_oObject)) { + + this.removeListener("click", this._onclickAttributeValue.fn); + + this._onclickAttributeValue = null; + + } + + + if (!this._onclickAttributeValue && + Lang.isObject(p_oObject) && + Lang.isFunction(p_oObject.fn)) { + + this.on("click", p_oObject.fn, p_oObject.obj, p_oObject.scope); + + this._onclickAttributeValue = p_oObject; + + } + + }, + + + + // Protected methods + + + + /** + * @method _isActivationKey + * @description Determines if the specified keycode is one that toggles + * the button's "active" state. + * @protected + * @param {Number} p_nKeyCode Number representing the keycode to + * be evaluated. + * @return {Boolean} + */ + _isActivationKey: function (p_nKeyCode) { + + var sType = this.get("type"), + aKeyCodes = (sType == "checkbox" || sType == "radio") ? + this.CHECK_ACTIVATION_KEYS : this.ACTIVATION_KEYS, + + nKeyCodes = aKeyCodes.length, + bReturnVal = false, + i; + + + if (nKeyCodes > 0) { + + i = nKeyCodes - 1; + + do { + + if (p_nKeyCode == aKeyCodes[i]) { + + bReturnVal = true; + break; + + } + + } + while (i--); + + } + + return bReturnVal; + + }, + + + /** + * @method _isSplitButtonOptionKey + * @description Determines if the specified keycode is one that toggles + * the display of the split button's menu. + * @protected + * @param {Event} p_oEvent Object representing the DOM event object + * passed back by the event utility (YAHOO.util.Event). + * @return {Boolean} + */ + _isSplitButtonOptionKey: function (p_oEvent) { + + var bShowMenu = (Event.getCharCode(p_oEvent) == 40); + + + var onKeyPress = function (p_oEvent) { + + Event.preventDefault(p_oEvent); + + this.removeListener("keypress", onKeyPress); + + }; + + + // Prevent the browser from scrolling the window + if (bShowMenu) { + + if (UA.opera) { + + this.on("keypress", onKeyPress); + + } + + Event.preventDefault(p_oEvent); + } + + return bShowMenu; + + }, + + + /** + * @method _addListenersToForm + * @description Adds event handlers to the button's form. + * @protected + */ + _addListenersToForm: function () { + + var oForm = this.getForm(), + onFormKeyPress = YAHOO.widget.Button.onFormKeyPress, + bHasKeyPressListener, + oSrcElement, + aListeners, + nListeners, + i; + + + if (oForm) { + + Event.on(oForm, "reset", this._onFormReset, null, this); + Event.on(oForm, "submit", this._onFormSubmit, null, this); + + oSrcElement = this.get("srcelement"); + + + if (this.get("type") == "submit" || + (oSrcElement && oSrcElement.type == "submit")) + { + + aListeners = Event.getListeners(oForm, "keypress"); + bHasKeyPressListener = false; + + if (aListeners) { + + nListeners = aListeners.length; + + if (nListeners > 0) { + + i = nListeners - 1; + + do { + + if (aListeners[i].fn == onFormKeyPress) { + + bHasKeyPressListener = true; + break; + + } + + } + while (i--); + + } + + } + + + if (!bHasKeyPressListener) { + + Event.on(oForm, "keypress", onFormKeyPress); + + } + + } + + } + + }, + + + + /** + * @method _showMenu + * @description Shows the button's menu. + * @protected + * @param {Event} p_oEvent Object representing the DOM event object + * passed back by the event utility (YAHOO.util.Event) that triggered + * the display of the menu. + */ + _showMenu: function (p_oEvent) { + + if (YAHOO.widget.MenuManager) { + YAHOO.widget.MenuManager.hideVisible(); + } + + + if (m_oOverlayManager) { + m_oOverlayManager.hideAll(); + } + + + var oMenu = this._menu, + aMenuAlignment = this.get("menualignment"), + bFocusMenu = this.get("focusmenu"), + fnFocusMethod; + + + if (this._renderedMenu) { + + oMenu.cfg.setProperty("context", + [this.get("element"), aMenuAlignment[0], aMenuAlignment[1]]); + + oMenu.cfg.setProperty("preventcontextoverlap", true); + oMenu.cfg.setProperty("constraintoviewport", true); + + } + else { + + oMenu.cfg.queueProperty("context", + [this.get("element"), aMenuAlignment[0], aMenuAlignment[1]]); + + oMenu.cfg.queueProperty("preventcontextoverlap", true); + oMenu.cfg.queueProperty("constraintoviewport", true); + + } + + + /* + Refocus the Button before showing its Menu in case the call to + YAHOO.widget.MenuManager.hideVisible() resulted in another element in the + DOM being focused after another Menu was hidden. + */ + + this.focus(); + + + if (Menu && oMenu && (oMenu instanceof Menu)) { + + // Since Menus automatically focus themselves when made visible, temporarily + // replace the Menu focus method so that the value of the Button's "focusmenu" + // attribute determines if the Menu should be focus when made visible. + + fnFocusMethod = oMenu.focus; + + oMenu.focus = function () {}; + + if (this._renderedMenu) { + + oMenu.cfg.setProperty("minscrollheight", this.get("menuminscrollheight")); + oMenu.cfg.setProperty("maxheight", this.get("menumaxheight")); + + } + else { + + oMenu.cfg.queueProperty("minscrollheight", this.get("menuminscrollheight")); + oMenu.cfg.queueProperty("maxheight", this.get("menumaxheight")); + + } + + + oMenu.show(); + + oMenu.focus = fnFocusMethod; + + oMenu.align(); + + + /* + Stop the propagation of the event so that the MenuManager + doesn't blur the menu after it gets focus. + */ + + if (p_oEvent.type == "mousedown") { + Event.stopPropagation(p_oEvent); + } + + + if (bFocusMenu) { + oMenu.focus(); + } + + } + else if (Overlay && oMenu && (oMenu instanceof Overlay)) { + + if (!this._renderedMenu) { + oMenu.render(this.get("element").parentNode); + } + + oMenu.show(); + oMenu.align(); + + } + + }, + + + /** + * @method _hideMenu + * @description Hides the button's menu. + * @protected + */ + _hideMenu: function () { + + var oMenu = this._menu; + + if (oMenu) { + + oMenu.hide(); + + } + + }, + + + + + // Protected event handlers + + + /** + * @method _onMouseOver + * @description "mouseover" event handler for the button. + * @protected + * @param {Event} p_oEvent Object representing the DOM event object + * passed back by the event utility (YAHOO.util.Event). + */ + _onMouseOver: function (p_oEvent) { + + var sType = this.get("type"), + oElement, + nOptionRegionX; + + + if (sType === "split") { + + oElement = this.get("element"); + nOptionRegionX = + (Dom.getX(oElement) + (oElement.offsetWidth - this.OPTION_AREA_WIDTH)); + + this._nOptionRegionX = nOptionRegionX; + + } + + + if (!this._hasMouseEventHandlers) { + + if (sType === "split") { + + this.on("mousemove", this._onMouseMove); + + } + + this.on("mouseout", this._onMouseOut); + + this._hasMouseEventHandlers = true; + + } + + + this.addStateCSSClasses("hover"); + + + if (sType === "split" && (Event.getPageX(p_oEvent) > nOptionRegionX)) { + + this.addStateCSSClasses("hoveroption"); + + } + + + if (this._activationButtonPressed) { + + this.addStateCSSClasses("active"); + + } + + + if (this._bOptionPressed) { + + this.addStateCSSClasses("activeoption"); + + } + + + if (this._activationButtonPressed || this._bOptionPressed) { + + Event.removeListener(document, "mouseup", this._onDocumentMouseUp); + + } + + }, + + + /** + * @method _onMouseMove + * @description "mousemove" event handler for the button. + * @protected + * @param {Event} p_oEvent Object representing the DOM event object + * passed back by the event utility (YAHOO.util.Event). + */ + _onMouseMove: function (p_oEvent) { + + var nOptionRegionX = this._nOptionRegionX; + + if (nOptionRegionX) { + + if (Event.getPageX(p_oEvent) > nOptionRegionX) { + + this.addStateCSSClasses("hoveroption"); + + } + else { + + this.removeStateCSSClasses("hoveroption"); + + } + + } + + }, + + /** + * @method _onMouseOut + * @description "mouseout" event handler for the button. + * @protected + * @param {Event} p_oEvent Object representing the DOM event object + * passed back by the event utility (YAHOO.util.Event). + */ + _onMouseOut: function (p_oEvent) { + + var sType = this.get("type"); + + this.removeStateCSSClasses("hover"); + + + if (sType != "menu") { + + this.removeStateCSSClasses("active"); + + } + + + if (this._activationButtonPressed || this._bOptionPressed) { + + Event.on(document, "mouseup", this._onDocumentMouseUp, null, this); + + } + + + if (sType === "split" && (Event.getPageX(p_oEvent) > this._nOptionRegionX)) { + + this.removeStateCSSClasses("hoveroption"); + + } + + }, + + + /** + * @method _onDocumentMouseUp + * @description "mouseup" event handler for the button. + * @protected + * @param {Event} p_oEvent Object representing the DOM event object + * passed back by the event utility (YAHOO.util.Event). + */ + _onDocumentMouseUp: function (p_oEvent) { + + this._activationButtonPressed = false; + this._bOptionPressed = false; + + var sType = this.get("type"), + oTarget, + oMenuElement; + + if (sType == "menu" || sType == "split") { + + oTarget = Event.getTarget(p_oEvent); + oMenuElement = this._menu.element; + + if (oTarget != oMenuElement && + !Dom.isAncestor(oMenuElement, oTarget)) { + + this.removeStateCSSClasses((sType == "menu" ? + "active" : "activeoption")); + + this._hideMenu(); + + } + + } + + Event.removeListener(document, "mouseup", this._onDocumentMouseUp); + + }, + + + /** + * @method _onMouseDown + * @description "mousedown" event handler for the button. + * @protected + * @param {Event} p_oEvent Object representing the DOM event object + * passed back by the event utility (YAHOO.util.Event). + */ + _onMouseDown: function (p_oEvent) { + + var sType, + bReturnVal = true; + + + function onMouseUp() { + + this._hideMenu(); + this.removeListener("mouseup", onMouseUp); + + } + + + if ((p_oEvent.which || p_oEvent.button) == 1) { + + + if (!this.hasFocus()) { + + this.focus(); + + } + + + sType = this.get("type"); + + + if (sType == "split") { + + if (Event.getPageX(p_oEvent) > this._nOptionRegionX) { + + this.fireEvent("option", p_oEvent); + bReturnVal = false; + + } + else { + + this.addStateCSSClasses("active"); + + this._activationButtonPressed = true; + + } + + } + else if (sType == "menu") { + + if (this.isActive()) { + + this._hideMenu(); + + this._activationButtonPressed = false; + + } + else { + + this._showMenu(p_oEvent); + + this._activationButtonPressed = true; + + } + + } + else { + + this.addStateCSSClasses("active"); + + this._activationButtonPressed = true; + + } + + + + if (sType == "split" || sType == "menu") { + + this._hideMenuTimer = Lang.later(250, this, this.on, ["mouseup", onMouseUp]); + + } + + } + + return bReturnVal; + + }, + + + /** + * @method _onMouseUp + * @description "mouseup" event handler for the button. + * @protected + * @param {Event} p_oEvent Object representing the DOM event object + * passed back by the event utility (YAHOO.util.Event). + */ + _onMouseUp: function (p_oEvent) { + + var sType = this.get("type"), + oHideMenuTimer = this._hideMenuTimer, + bReturnVal = true; + + + if (oHideMenuTimer) { + + oHideMenuTimer.cancel(); + + } + + + if (sType == "checkbox" || sType == "radio") { + + this.set("checked", !(this.get("checked"))); + + } + + + this._activationButtonPressed = false; + + + if (sType != "menu") { + + this.removeStateCSSClasses("active"); + + } + + + if (sType == "split" && Event.getPageX(p_oEvent) > this._nOptionRegionX) { + + bReturnVal = false; + + } + + return bReturnVal; + + }, + + + /** + * @method _onFocus + * @description "focus" event handler for the button. + * @protected + * @param {Event} p_oEvent Object representing the DOM event object + * passed back by the event utility (YAHOO.util.Event). + */ + _onFocus: function (p_oEvent) { + + var oElement; + + this.addStateCSSClasses("focus"); + + if (this._activationKeyPressed) { + + this.addStateCSSClasses("active"); + + } + + m_oFocusedButton = this; + + + if (!this._hasKeyEventHandlers) { + + oElement = this._button; + + Event.on(oElement, "blur", this._onBlur, null, this); + Event.on(oElement, "keydown", this._onKeyDown, null, this); + Event.on(oElement, "keyup", this._onKeyUp, null, this); + + this._hasKeyEventHandlers = true; + + } + + + this.fireEvent("focus", p_oEvent); + + }, + + + /** + * @method _onBlur + * @description "blur" event handler for the button. + * @protected + * @param {Event} p_oEvent Object representing the DOM event object + * passed back by the event utility (YAHOO.util.Event). + */ + _onBlur: function (p_oEvent) { + + this.removeStateCSSClasses("focus"); + + if (this.get("type") != "menu") { + + this.removeStateCSSClasses("active"); + + } + + if (this._activationKeyPressed) { + + Event.on(document, "keyup", this._onDocumentKeyUp, null, this); + + } + + + m_oFocusedButton = null; + + this.fireEvent("blur", p_oEvent); + + }, + + + /** + * @method _onDocumentKeyUp + * @description "keyup" event handler for the document. + * @protected + * @param {Event} p_oEvent Object representing the DOM event object + * passed back by the event utility (YAHOO.util.Event). + */ + _onDocumentKeyUp: function (p_oEvent) { + + if (this._isActivationKey(Event.getCharCode(p_oEvent))) { + + this._activationKeyPressed = false; + + Event.removeListener(document, "keyup", this._onDocumentKeyUp); + + } + + }, + + + /** + * @method _onKeyDown + * @description "keydown" event handler for the button. + * @protected + * @param {Event} p_oEvent Object representing the DOM event object + * passed back by the event utility (YAHOO.util.Event). + */ + _onKeyDown: function (p_oEvent) { + + var oMenu = this._menu; + + + if (this.get("type") == "split" && + this._isSplitButtonOptionKey(p_oEvent)) { + + this.fireEvent("option", p_oEvent); + + } + else if (this._isActivationKey(Event.getCharCode(p_oEvent))) { + + if (this.get("type") == "menu") { + + this._showMenu(p_oEvent); + + } + else { + + this._activationKeyPressed = true; + + this.addStateCSSClasses("active"); + + } + + } + + + if (oMenu && oMenu.cfg.getProperty("visible") && + Event.getCharCode(p_oEvent) == 27) { + + oMenu.hide(); + this.focus(); + + } + + }, + + + /** + * @method _onKeyUp + * @description "keyup" event handler for the button. + * @protected + * @param {Event} p_oEvent Object representing the DOM event object + * passed back by the event utility (YAHOO.util.Event). + */ + _onKeyUp: function (p_oEvent) { + + var sType; + + if (this._isActivationKey(Event.getCharCode(p_oEvent))) { + + sType = this.get("type"); + + if (sType == "checkbox" || sType == "radio") { + + this.set("checked", !(this.get("checked"))); + + } + + this._activationKeyPressed = false; + + if (this.get("type") != "menu") { + + this.removeStateCSSClasses("active"); + + } + + } + + }, + + + /** + * @method _onClick + * @description "click" event handler for the button. + * @protected + * @param {Event} p_oEvent Object representing the DOM event object + * passed back by the event utility (YAHOO.util.Event). + */ + _onClick: function (p_oEvent) { + + var sType = this.get("type"), + oForm, + oSrcElement, + bReturnVal; + + + switch (sType) { + + case "submit": + + if (p_oEvent.returnValue !== false) { + + this.submitForm(); + + } + + break; + + case "reset": + + oForm = this.getForm(); + + if (oForm) { + + oForm.reset(); + + } + + break; + + + case "split": + + if (this._nOptionRegionX > 0 && + (Event.getPageX(p_oEvent) > this._nOptionRegionX)) { + + bReturnVal = false; + + } + else { + + this._hideMenu(); + + oSrcElement = this.get("srcelement"); + + if (oSrcElement && oSrcElement.type == "submit" && + p_oEvent.returnValue !== false) { + + this.submitForm(); + + } + + } + + break; + + } + + return bReturnVal; + + }, + + + /** + * @method _onDblClick + * @description "dblclick" event handler for the button. + * @protected + * @param {Event} p_oEvent Object representing the DOM event object + * passed back by the event utility (YAHOO.util.Event). + */ + _onDblClick: function (p_oEvent) { + + var bReturnVal = true; + + if (this.get("type") == "split" && Event.getPageX(p_oEvent) > this._nOptionRegionX) { + + bReturnVal = false; + + } + + return bReturnVal; + + }, + + + /** + * @method _onAppendTo + * @description "appendTo" event handler for the button. + * @protected + * @param {Event} p_oEvent Object representing the DOM event object + * passed back by the event utility (YAHOO.util.Event). + */ + _onAppendTo: function (p_oEvent) { + + /* + It is necessary to call "_addListenersToForm" using + "setTimeout" to make sure that the button's "form" property + returns a node reference. Sometimes, if you try to get the + reference immediately after appending the field, it is null. + */ + + Lang.later(0, this, this._addListenersToForm); + + }, + + + /** + * @method _onFormReset + * @description "reset" event handler for the button's form. + * @protected + * @param {Event} p_oEvent Object representing the DOM event + * object passed back by the event utility (YAHOO.util.Event). + */ + _onFormReset: function (p_oEvent) { + + var sType = this.get("type"), + oMenu = this._menu; + + if (sType == "checkbox" || sType == "radio") { + + this.resetValue("checked"); + + } + + + if (Menu && oMenu && (oMenu instanceof Menu)) { + + this.resetValue("selectedMenuItem"); + + } + + }, + + + /** + * @method _onFormSubmit + * @description "submit" event handler for the button's form. + * @protected + * @param {Event} p_oEvent Object representing the DOM event + * object passed back by the event utility (YAHOO.util.Event). + */ + _onFormSubmit: function (p_oEvent) { + + this.createHiddenFields(); + + }, + + + /** + * @method _onDocumentMouseDown + * @description "mousedown" event handler for the document. + * @protected + * @param {Event} p_oEvent Object representing the DOM event object + * passed back by the event utility (YAHOO.util.Event). + */ + _onDocumentMouseDown: function (p_oEvent) { + + var oTarget = Event.getTarget(p_oEvent), + oButtonElement = this.get("element"), + oMenuElement = this._menu.element; + + + if (oTarget != oButtonElement && + !Dom.isAncestor(oButtonElement, oTarget) && + oTarget != oMenuElement && + !Dom.isAncestor(oMenuElement, oTarget)) { + + this._hideMenu(); + + // In IE when the user mouses down on a focusable element + // that element will be focused and become the "activeElement". + // (http://msdn.microsoft.com/en-us/library/ms533065(VS.85).aspx) + // However, there is a bug in IE where if there is a + // positioned element with a focused descendant that is + // hidden in response to the mousedown event, the target of + // the mousedown event will appear to have focus, but will + // not be set as the activeElement. This will result + // in the element not firing key events, even though it + // appears to have focus. The following call to "setActive" + // fixes this bug. + + if (UA.ie && oTarget.focus) { + oTarget.setActive(); + } + + Event.removeListener(document, "mousedown", + this._onDocumentMouseDown); + + } + + }, + + + /** + * @method _onOption + * @description "option" event handler for the button. + * @protected + * @param {Event} p_oEvent Object representing the DOM event object + * passed back by the event utility (YAHOO.util.Event). + */ + _onOption: function (p_oEvent) { + + if (this.hasClass(this.CLASS_NAME_PREFIX + "split-button-activeoption")) { + + this._hideMenu(); + + this._bOptionPressed = false; + + } + else { + + this._showMenu(p_oEvent); + + this._bOptionPressed = true; + + } + + }, + + + /** + * @method _onMenuShow + * @description "show" event handler for the button's menu. + * @private + * @param {String} p_sType String representing the name of the event + * that was fired. + */ + _onMenuShow: function (p_sType) { + + Event.on(document, "mousedown", this._onDocumentMouseDown, + null, this); + + var sState = (this.get("type") == "split") ? "activeoption" : "active"; + + this.addStateCSSClasses(sState); + + }, + + + /** + * @method _onMenuHide + * @description "hide" event handler for the button's menu. + * @private + * @param {String} p_sType String representing the name of the event + * that was fired. + */ + _onMenuHide: function (p_sType) { + + var sState = (this.get("type") == "split") ? "activeoption" : "active"; + + this.removeStateCSSClasses(sState); + + + if (this.get("type") == "split") { + + this._bOptionPressed = false; + + } + + }, + + + /** + * @method _onMenuKeyDown + * @description "keydown" event handler for the button's menu. + * @private + * @param {String} p_sType String representing the name of the event + * that was fired. + * @param {Array} p_aArgs Array of arguments sent when the event + * was fired. + */ + _onMenuKeyDown: function (p_sType, p_aArgs) { + + var oEvent = p_aArgs[0]; + + if (Event.getCharCode(oEvent) == 27) { + + this.focus(); + + if (this.get("type") == "split") { + + this._bOptionPressed = false; + + } + + } + + }, + + + /** + * @method _onMenuRender + * @description "render" event handler for the button's menu. + * @private + * @param {String} p_sType String representing the name of the + * event thatwas fired. + */ + _onMenuRender: function (p_sType) { + + var oButtonElement = this.get("element"), + oButtonParent = oButtonElement.parentNode, + oMenu = this._menu, + oMenuElement = oMenu.element, + oSrcElement = oMenu.srcElement, + oItem; + + + if (oButtonParent != oMenuElement.parentNode) { + + oButtonParent.appendChild(oMenuElement); + + } + + this._renderedMenu = true; + + // If the user has designated an
    ",K=document.createElement("div");document.body.appendChild(K);K.innerHTML=J;}function B(L,I,J,M,K){H[parseInt(L.tId)]={"o":L,"c":M};if(K){M.method=I;M.data=K;}L.conn.send(J,M,L.tId);}function E(I){D(I);G._transport=document.getElementById("YUIConnectionSwf");}function C(){G.xdrReadyEvent.fire();}function A(J,I){if(J){G.startEvent.fire(J,I.argument);if(J.startEvent){J.startEvent.fire(J,I.argument);}}}function F(J){var K=H[J.tId].o,I=H[J.tId].c;if(J.statusText==="xdr:start"){A(K,I);return;}J.responseText=decodeURI(J.responseText);K.r=J;if(I.argument){K.r.argument=I.argument;}this.handleTransactionResponse(K,I,J.statusText==="xdr:abort"?true:false);delete H[J.tId];}G.xdr=B;G.swf=D;G.transport=E;G.xdrReadyEvent=new YAHOO.util.CustomEvent("xdrReady");G.xdrReady=C;G.handleXdrResponse=F;})();(function(){var D=YAHOO.util.Connect,F=YAHOO.util.Event;D._isFormSubmit=false;D._isFileUpload=false;D._formNode=null;D._sFormData=null;D._submitElementValue=null;D.uploadEvent=new YAHOO.util.CustomEvent("upload"),D._hasSubmitListener=function(){if(F){F.addListener(document,"click",function(J){var I=F.getTarget(J),H=I.nodeName.toLowerCase();if((H==="input"||H==="button")&&(I.type&&I.type.toLowerCase()=="submit")){D._submitElementValue=encodeURIComponent(I.name)+"="+encodeURIComponent(I.value);}});return true;}return false;}();function G(T,O,J){var S,I,R,P,W,Q=false,M=[],V=0,L,N,K,U,H;this.resetFormState();if(typeof T=="string"){S=(document.getElementById(T)||document.forms[T]);}else{if(typeof T=="object"){S=T;}else{return;}}if(O){this.createFrame(J?J:null);this._isFormSubmit=true;this._isFileUpload=true;this._formNode=S;return;}for(L=0,N=S.elements.length;L-1){H=I.options[I.selectedIndex];M[V++]=R+encodeURIComponent((H.attributes.value&&H.attributes.value.specified)?H.value:H.text);}break;case"select-multiple":if(I.selectedIndex>-1){for(K=I.selectedIndex,U=I.options.length;K');if(typeof H=="boolean"){J.src="javascript:false";}}else{J=document.createElement("iframe");J.id=I;J.name=I;}J.style.position="absolute";J.style.top="-1000px";J.style.left="-1000px";document.body.appendChild(J);}function E(H){var K=[],I=H.split("&"),J,L;for(J=0;J0){for(P=0;P= 200 && httpStatus < 300) || httpStatus === 1223 || xdrS){ + responseObject = o.xdr ? o.r : this.createResponseObject(o, args); + if(callback && callback.success){ + if(!callback.scope){ + callback.success(responseObject); + } + else{ + // If a scope property is defined, the callback will be fired from + // the context of the object. + callback.success.apply(callback.scope, [responseObject]); + } + } + + // Fire global custom event -- successEvent + this.successEvent.fire(responseObject); + + if(o.successEvent){ + // Fire transaction custom event -- successEvent + o.successEvent.fire(responseObject); + } + } + else{ + switch(httpStatus){ + // The following cases are wininet.dll error codes that may be encountered. + case 12002: // Server timeout + case 12029: // 12029 to 12031 correspond to dropped connections. + case 12030: + case 12031: + case 12152: // Connection closed by server. + case 13030: // See above comments for variable status. + // XDR transactions will not resolve to this case, since the + // response object is already built in the xdr response. + responseObject = this.createExceptionObject(o.tId, args, (isAbort?isAbort:false)); + if(callback && callback.failure){ + if(!callback.scope){ + callback.failure(responseObject); + } + else{ + callback.failure.apply(callback.scope, [responseObject]); + } + } + + break; + default: + responseObject = (o.xdr) ? o.response : this.createResponseObject(o, args); + if(callback && callback.failure){ + if(!callback.scope){ + callback.failure(responseObject); + } + else{ + callback.failure.apply(callback.scope, [responseObject]); + } + } + } + + // Fire global custom event -- failureEvent + this.failureEvent.fire(responseObject); + + if(o.failureEvent){ + // Fire transaction custom event -- failureEvent + o.failureEvent.fire(responseObject); + } + + } + + this.releaseObject(o); + responseObject = null; + }, + + /** + * @description This method evaluates the server response, creates and returns the results via + * its properties. Success and failure cases will differ in the response + * object's property values. + * @method createResponseObject + * @private + * @static + * @param {object} o The connection object + * @param {callbackArg} callbackArg The user-defined argument or arguments to be passed to the callback + * @return {object} + */ + createResponseObject:function(o, callbackArg) + { + var obj = {}, headerObj = {}, + i, headerStr, header, delimitPos; + + try + { + headerStr = o.conn.getAllResponseHeaders(); + header = headerStr.split('\n'); + for(i=0; i' + + '' + + '' + + '
    ', + c = document.createElement('div'); + + document.body.appendChild(c); + c.innerHTML = o; + } + + /** + * @description This method calls the public method on the + * Flash transport to start the XDR transaction. It is analogous + * to Connection Manager's asyncRequest method. + * @method xdr + * @private + * @static + * @param {object} The transaction object. + * @param {string} HTTP request method. + * @param {string} URI for the transaction. + * @param {object} The transaction's callback object. + * @param {object} The JSON object used as HTTP POST data. + * @return {void} + */ + function _xdr(o, m, u, c, d) { + _fn[parseInt(o.tId)] = { 'o':o, 'c':c }; + if (d) { + c.method = m; + c.data = d; + } + + o.conn.send(u, c, o.tId); + } + + /** + * @description This method instantiates the Flash transport and + * establishes a static reference to it, used for all XDR requests. + * @method transport + * @public + * @static + * @param {string} URI to connection.swf. + * @return {void} + */ + function _init(uri) { + _swf(uri); + YCM._transport = document.getElementById('YUIConnectionSwf'); + } + + function _xdrReady() { + YCM.xdrReadyEvent.fire(); + } + + /** + * @description This method fires the global and transaction start + * events. + * @method _xdrStart + * @private + * @static + * @param {object} The transaction object. + * @param {string} The transaction's callback object. + * @return {void} + */ + function _xdrStart(o, cb) { + if (o) { + // Fire global custom event -- startEvent + YCM.startEvent.fire(o, cb.argument); + + if(o.startEvent){ + // Fire transaction custom event -- startEvent + o.startEvent.fire(o, cb.argument); + } + } + } + + /** + * @description This method is the initial response handler + * for XDR transactions. The Flash transport calls this + * function and sends the response payload. + * @method handleXdrResponse + * @private + * @static + * @param {object} The response object sent from the Flash transport. + * @return {void} + */ + function _handleXdrResponse(r) { + var o = _fn[r.tId].o, + cb = _fn[r.tId].c; + + if (r.statusText === 'xdr:start') { + _xdrStart(o, cb); + return; + } + + r.responseText = decodeURI(r.responseText); + o.r = r; + if (cb.argument) { + o.r.argument = cb.argument; + } + + this.handleTransactionResponse(o, cb, r.statusText === 'xdr:abort' ? true : false); + delete _fn[r.tId]; + } + + // Bind the functions to Connection Manager as static fields. + YCM.xdr = _xdr; + YCM.swf = _swf; + YCM.transport = _init; + YCM.xdrReadyEvent = new YAHOO.util.CustomEvent('xdrReady'); + YCM.xdrReady = _xdrReady; + YCM.handleXdrResponse = _handleXdrResponse; +})(); + +/** + * @for Connect + */ +(function(){ + var YCM = YAHOO.util.Connect, + YE = YAHOO.util.Event; + /** + * @description Property modified by setForm() to determine if the data + * should be submitted as an HTML form. + * @property _isFormSubmit + * @private + * @static + * @type boolean + */ + YCM._isFormSubmit = false; + + /** + * @description Property modified by setForm() to determine if a file(s) + * upload is expected. + * @property _isFileUpload + * @private + * @static + * @type boolean + */ + YCM._isFileUpload = false; + + /** + * @description Property modified by setForm() to set a reference to the HTML + * form node if the desired action is file upload. + * @property _formNode + * @private + * @static + * @type object + */ + YCM._formNode = null; + + /** + * @description Property modified by setForm() to set the HTML form data + * for each transaction. + * @property _sFormData + * @private + * @static + * @type string + */ + YCM._sFormData = null; + + /** + * @description Tracks the name-value pair of the "clicked" submit button if multiple submit + * buttons are present in an HTML form; and, if YAHOO.util.Event is available. + * @property _submitElementValue + * @private + * @static + * @type string + */ + YCM._submitElementValue = null; + + /** + * @description Custom event that fires when handleTransactionResponse() determines a + * response in the HTTP 4xx/5xx range. + * @property failureEvent + * @private + * @static + * @type CustomEvent + */ + YCM.uploadEvent = new YAHOO.util.CustomEvent('upload'), + + /** + * @description Determines whether YAHOO.util.Event is available and returns true or false. + * If true, an event listener is bound at the document level to trap click events that + * resolve to a target type of "Submit". This listener will enable setForm() to determine + * the clicked "Submit" value in a multi-Submit button, HTML form. + * @property _hasSubmitListener + * @private + * @static + */ + YCM._hasSubmitListener = function() { + if(YE){ + YE.addListener( + document, + 'click', + function(e){ + var obj = YE.getTarget(e), + name = obj.nodeName.toLowerCase(); + + if((name === 'input' || name === 'button') && (obj.type && obj.type.toLowerCase() == 'submit')){ + YCM._submitElementValue = encodeURIComponent(obj.name) + "=" + encodeURIComponent(obj.value); + } + }); + return true; + } + return false; + }(); + + /** + * @description This method assembles the form label and value pairs and + * constructs an encoded string. + * asyncRequest() will automatically initialize the transaction with a + * a HTTP header Content-Type of application/x-www-form-urlencoded. + * @method setForm + * @public + * @static + * @param {string || object} form id or name attribute, or form object. + * @param {boolean} optional enable file upload. + * @param {boolean} optional enable file upload over SSL in IE only. + * @return {string} string of the HTML form field name and value pairs.. + */ + function _setForm(formId, isUpload, secureUri) + { + var oForm, oElement, oName, oValue, oDisabled, + hasSubmit = false, + data = [], item = 0, + i,len,j,jlen,opt; + + this.resetFormState(); + + if(typeof formId == 'string'){ + // Determine if the argument is a form id or a form name. + // Note form name usage is deprecated by supported + // here for legacy reasons. + oForm = (document.getElementById(formId) || document.forms[formId]); + } + else if(typeof formId == 'object'){ + // Treat argument as an HTML form object. + oForm = formId; + } + else{ + return; + } + + // If the isUpload argument is true, setForm will call createFrame to initialize + // an iframe as the form target. + // + // The argument secureURI is also required by IE in SSL environments + // where the secureURI string is a fully qualified HTTP path, used to set the source + // of the iframe, to a stub resource in the same domain. + if(isUpload){ + + // Create iframe in preparation for file upload. + this.createFrame(secureUri?secureUri:null); + + // Set form reference and file upload properties to true. + this._isFormSubmit = true; + this._isFileUpload = true; + this._formNode = oForm; + + return; + } + + // Iterate over the form elements collection to construct the + // label-value pairs. + for (i=0,len=oForm.elements.length; i -1) { + opt = oElement.options[oElement.selectedIndex]; + data[item++] = oName + encodeURIComponent( + (opt.attributes.value && opt.attributes.value.specified) ? opt.value : opt.text); + } + break; + case 'select-multiple': + if (oElement.selectedIndex > -1) { + for(j=oElement.selectedIndex, jlen=oElement.options.length; j'); + + // IE will throw a security exception in an SSL environment if the + // iframe source is undefined. + if(typeof secureUri == 'boolean'){ + io.src = 'javascript:false'; + } + } + else{ + io = document.createElement('iframe'); + io.id = frameId; + io.name = frameId; + } + + io.style.position = 'absolute'; + io.style.top = '-1000px'; + io.style.left = '-1000px'; + + document.body.appendChild(io); + } + + /** + * @description Parses the POST data and creates hidden form elements + * for each key-value, and appends them to the HTML form object. + * @method appendPostData + * @private + * @static + * @param {string} postData The HTTP POST data + * @return {array} formElements Collection of hidden fields. + */ + function _appendPostData(postData){ + var formElements = [], + postMessage = postData.split('&'), + i, delimitPos; + + for(i=0; i < postMessage.length; i++){ + delimitPos = postMessage[i].indexOf('='); + if(delimitPos != -1){ + formElements[i] = document.createElement('input'); + formElements[i].type = 'hidden'; + formElements[i].name = decodeURIComponent(postMessage[i].substring(0,delimitPos)); + formElements[i].value = decodeURIComponent(postMessage[i].substring(delimitPos+1)); + this._formNode.appendChild(formElements[i]); + } + } + + return formElements; + } + + /** + * @description Uploads HTML form, inclusive of files/attachments, using the + * iframe created in createFrame to facilitate the transaction. + * @method uploadFile + * @private + * @static + * @param {int} id The transaction id. + * @param {object} callback User-defined callback object. + * @param {string} uri Fully qualified path of resource. + * @param {string} postData POST data to be submitted in addition to HTML form. + * @return {void} + */ + function _uploadFile(o, callback, uri, postData){ + // Each iframe has an id prefix of "yuiIO" followed + // by the unique transaction id. + var frameId = 'yuiIO' + o.tId, + uploadEncoding = 'multipart/form-data', + io = document.getElementById(frameId), + ie8 = (document.documentMode && document.documentMode === 8) ? true : false, + oConn = this, + args = (callback && callback.argument)?callback.argument:null, + oElements,i,prop,obj, rawFormAttributes, uploadCallback; + + // Track original HTML form attribute values. + rawFormAttributes = { + action:this._formNode.getAttribute('action'), + method:this._formNode.getAttribute('method'), + target:this._formNode.getAttribute('target') + }; + + // Initialize the HTML form properties in case they are + // not defined in the HTML form. + this._formNode.setAttribute('action', uri); + this._formNode.setAttribute('method', 'POST'); + this._formNode.setAttribute('target', frameId); + + if(YAHOO.env.ua.ie && !ie8){ + // IE does not respect property enctype for HTML forms. + // Instead it uses the property - "encoding". + this._formNode.setAttribute('encoding', uploadEncoding); + } + else{ + this._formNode.setAttribute('enctype', uploadEncoding); + } + + if(postData){ + oElements = this.appendPostData(postData); + } + + // Start file upload. + this._formNode.submit(); + + // Fire global custom event -- startEvent + this.startEvent.fire(o, args); + + if(o.startEvent){ + // Fire transaction custom event -- startEvent + o.startEvent.fire(o, args); + } + + // Start polling if a callback is present and the timeout + // property has been defined. + if(callback && callback.timeout){ + this._timeOut[o.tId] = window.setTimeout(function(){ oConn.abort(o, callback, true); }, callback.timeout); + } + + // Remove HTML elements created by appendPostData + if(oElements && oElements.length > 0){ + for(i=0; i < oElements.length; i++){ + this._formNode.removeChild(oElements[i]); + } + } + + // Restore HTML form attributes to their original + // values prior to file upload. + for(prop in rawFormAttributes){ + if(YAHOO.lang.hasOwnProperty(rawFormAttributes, prop)){ + if(rawFormAttributes[prop]){ + this._formNode.setAttribute(prop, rawFormAttributes[prop]); + } + else{ + this._formNode.removeAttribute(prop); + } + } + } + + // Reset HTML form state properties. + this.resetFormState(); + + // Create the upload callback handler that fires when the iframe + // receives the load event. Subsequently, the event handler is detached + // and the iframe removed from the document. + uploadCallback = function() { + if(callback && callback.timeout){ + window.clearTimeout(oConn._timeOut[o.tId]); + delete oConn._timeOut[o.tId]; + } + + // Fire global custom event -- completeEvent + oConn.completeEvent.fire(o, args); + + if(o.completeEvent){ + // Fire transaction custom event -- completeEvent + o.completeEvent.fire(o, args); + } + + obj = { + tId : o.tId, + argument : callback.argument + }; + + try + { + // responseText and responseXML will be populated with the same data from the iframe. + // Since the HTTP headers cannot be read from the iframe + obj.responseText = io.contentWindow.document.body?io.contentWindow.document.body.innerHTML:io.contentWindow.document.documentElement.textContent; + obj.responseXML = io.contentWindow.document.XMLDocument?io.contentWindow.document.XMLDocument:io.contentWindow.document; + } + catch(e){} + + if(callback && callback.upload){ + if(!callback.scope){ + callback.upload(obj); + } + else{ + callback.upload.apply(callback.scope, [obj]); + } + } + + // Fire global custom event -- uploadEvent + oConn.uploadEvent.fire(obj); + + if(o.uploadEvent){ + // Fire transaction custom event -- uploadEvent + o.uploadEvent.fire(obj); + } + + YE.removeListener(io, "load", uploadCallback); + + setTimeout( + function(){ + document.body.removeChild(io); + oConn.releaseObject(o); + }, 100); + }; + + // Bind the onload handler to the iframe to detect the file upload response. + YE.addListener(io, "load", uploadCallback); + } + + YCM.setForm = _setForm; + YCM.resetFormState = _resetFormState; + YCM.createFrame = _createFrame; + YCM.appendPostData = _appendPostData; + YCM.uploadFile = _uploadFile; +})(); + +YAHOO.register("connection", YAHOO.util.Connect, {version: "2.8.0r4", build: "2449"}); diff --git a/include/javascript/yui/build/connection/connection.swf b/include/javascript/yui/build/connection/connection.swf new file mode 100644 index 0000000000000000000000000000000000000000..c33a7fe2748316e549cc345836942ce4d4331df1 GIT binary patch literal 2423 zcmV--35fPXS5pbe4*&po+KpG;QybS6zh`%)yDJG00?Sx@L}10(L`VWBw!s*K`G_H4 zIeavZi_ET8E2LPg$nJ`dX=Xx`rb#>POxj5^)0w8tQ#;e?TOaz^KcFuL&$ONCOQ%nL z<94R+^xR$90vgxVz}<7t$M2kb&beo$T_XL1kmg?#(g9?;^#UQ}!?r&GA!AmdIJz`F z8{gfmnD!{{ZuOTOXKOT_-r3nn?OaV&t&Q~1$jC@KGn^hC9z=~nd(U*V-9gj7*gx(9 zOdGatmA9O7)r|AKmao>FTmAiY)PnvTbgO1nT*!i+HY&!ZVLEntC^dvY1%0$wwKg?p zT-(~Jly!~6rFRGIQdNJvqiq|5#foN^#?lQ%ZsU}liZMP}sOF9MY{l4(UyV;T>|Je7 zg)0{tfsUUzrpB#PdUZ3sWmO9`9b+mYlxuv_ghOoA@|Ch(GOY2M`Pi)PcrF@TuA^Iq z=2TB>JmYbBMKd>Q+J-ScbI+AM-@7qt4xXpB5g!^!#)mVR5ibnR9ZR3dcAbL-94FJ^ ze~M#dO8EXSe)BLOVuk(qFN*(;5cl)<{FT=)V#WU&z;mwe)ynHNr(9XrtEOq_9E<$1 z-Dx5ORY=j&HjNF;dEf@UDj#V}{{Mr0_$dzhk)9HGV zsco1A#jR+{G@Ot}8QZ)ed^7wJn#;~uR@HJhftB*6;gLa4mE+kymz{o*k1eabjd{Zw z7R#owP_`YzG%Pzj=K@Wa?JdpGv1rMc0ceH7bL*FSvy9E^cEj7NFVnXj&2su*s#Vi< z!?s_lSJcXtnq_pqNDuF(<SrdxY?wr0Al5NAzQH@7N=W6*joTF%r}sZ_OsVJ&J~ zw4Mc84@=_R=JSqT(#%4|uoCZ1-pyuR*QqJbb;=VxC|FB|y;U`BBgozI9>aO&bL%AT z%@x9Dv(s{>^g>J zYL(WRIx%PBv#9At5Z&-V@|ym*^Baz{%MYRz_9PvZ#F|wW^t^z#)Jqe!jQ4Ap9-qVS zkc5+OOIcl7Sa5{_q?SCnf75VE)k64GY>DBkz4Zaw7@m{MSJODKuBG#}a>Xf|?Wc-9 z>J>e4nmO$~y@`Q=I~rEhdgZi|dtwcJZyTOs=l=ldIyp*4&)jtBes*~!+&J8#do~HD zt41BK&Y%Y@p0#BM`x+dHXA6whGrg9`$Wz(H`wKHGGu@{go}DdWERxH5W-8BR*JqZN zvP;b?bBi-e>(5}?ye2xWYtuAEg&5O;GwOrI#r5Q@Bj&6-r;DG)d_o zg%qV}N;6cxO5t@1*Qhd1mD|b$P-Tw7T?!M*JW!Zd-hxhiW+^0TaD)cOC@j(T6$+~q zzNIXH@(w8XKv_hcH3~TjDg{kh2c-at3W^3)FsQFceH+wQ3VSb7fruc865W?&8Ndho zxcc3d;wpe7w|peyQ&C#?xrP+sGO2A}7QrXU?cC0#&Upw@6y*V_V?TuSg?-ue0>O~t zClJP$cQa|>OBhI?6^I{S{UT`t5^M+3d=7{Z1rj=sVGTeB*Si2jiSZ~qfi!gik-LFV z1Z;tz1o-*~kQMPs=1pXYpadrVHN-AF$*^;eBCDhnL3)m`nA(%FZUo|_%3eP zmBZr2~+oM4ypff# z`1teV;+(Bd4B{;#%`fJN!V@7u_y_FK>HEgCwDNMk~xC6g-HVr zHo<_yO#y30Cb3d5$?iOAnGj1Y9Qskygj8xmYQ}(y5W!YuvyVC^e5DTL-F=e?g9Ie} zf+@&^ilP!2NA~;^#2zK{9BiJwb)fo+X|*Mr5!k|k>MstdO`N`W7{LUy?4e4F!)ga- zy^T@IqM!ucMwDfaGD4QwiW)g64ivA}VO|&5>NAc9hMadi&KnWDE9^miQwK)zLj+bN z4DT8OuX(_0NALi0$#+@qAo(!)?Nwo4{4-m3O%sB4jj3vndj2pQ7np|D0l!}fe1O(E zx4utwgaBN|1YG9D0)j~fE99;p6mJy!XRpI2x`f!pL&ScRTxX@cv?}h4*y@kf$RWCr z(8cD{?SY7okSkA%Bij*dHD*4|juQ4hca05#zO7vQVYVHZjWGlzjNu1>LDcZpp#vUB zjR#WWfz)^)+dPmR^t{78=lQA7=U&6-cd!J%kKkZqALM`U_w`^DHAcJ=vFalxqp;cVFIR zKZkxCCe7UFA{u>FH~I?LFCo`;knIBYD{k@Lz!mm2$8QmEY`*p+gUVrpsA5LFolz$; p>SRW}lTkzX_keV}pHdKYxJg$Ve_5RTHk>-~yKDkw{{aPr(-^X}v;hDB literal 0 HcmV?d00001 diff --git a/include/javascript/yui/build/connection/connection_core-debug.js b/include/javascript/yui/build/connection/connection_core-debug.js new file mode 100644 index 00000000..3c0c61c5 --- /dev/null +++ b/include/javascript/yui/build/connection/connection_core-debug.js @@ -0,0 +1,980 @@ +/* +Copyright (c) 2009, Yahoo! Inc. All rights reserved. +Code licensed under the BSD License: +http://developer.yahoo.net/yui/license.txt +version: 2.8.0r4 +*/ +/** + * The Connection Manager provides a simplified interface to the XMLHttpRequest + * object. It handles cross-browser instantiantion of XMLHttpRequest, negotiates the + * interactive states and server response, returning the results to a pre-defined + * callback you create. + * + * @namespace YAHOO.util + * @module connection + * @requires yahoo + * @requires event + */ + +/** + * The Connection Manager singleton provides methods for creating and managing + * asynchronous transactions. + * + * @class Connect + */ + +YAHOO.util.Connect = +{ + /** + * @description Array of MSFT ActiveX ids for XMLHttpRequest. + * @property _msxml_progid + * @private + * @static + * @type array + */ + _msxml_progid:[ + 'Microsoft.XMLHTTP', + 'MSXML2.XMLHTTP.3.0', + 'MSXML2.XMLHTTP' + ], + + /** + * @description Object literal of HTTP header(s) + * @property _http_header + * @private + * @static + * @type object + */ + _http_headers:{}, + + /** + * @description Determines if HTTP headers are set. + * @property _has_http_headers + * @private + * @static + * @type boolean + */ + _has_http_headers:false, + + /** + * @description Determines if a default header of + * Content-Type of 'application/x-www-form-urlencoded' + * will be added to any client HTTP headers sent for POST + * transactions. + * @property _use_default_post_header + * @private + * @static + * @type boolean + */ + _use_default_post_header:true, + + /** + * @description The default header used for POST transactions. + * @property _default_post_header + * @private + * @static + * @type boolean + */ + _default_post_header:'application/x-www-form-urlencoded; charset=UTF-8', + + /** + * @description The default header used for transactions involving the + * use of HTML forms. + * @property _default_form_header + * @private + * @static + * @type boolean + */ + _default_form_header:'application/x-www-form-urlencoded', + + /** + * @description Determines if a default header of + * 'X-Requested-With: XMLHttpRequest' + * will be added to each transaction. + * @property _use_default_xhr_header + * @private + * @static + * @type boolean + */ + _use_default_xhr_header:true, + + /** + * @description The default header value for the label + * "X-Requested-With". This is sent with each + * transaction, by default, to identify the + * request as being made by YUI Connection Manager. + * @property _default_xhr_header + * @private + * @static + * @type boolean + */ + _default_xhr_header:'XMLHttpRequest', + + /** + * @description Determines if custom, default headers + * are set for each transaction. + * @property _has_default_header + * @private + * @static + * @type boolean + */ + _has_default_headers:true, + + /** + * @description Determines if custom, default headers + * are set for each transaction. + * @property _has_default_header + * @private + * @static + * @type boolean + */ + _default_headers:{}, + + /** + * @description Collection of polling references to the polling mechanism in handleReadyState. + * @property _poll + * @private + * @static + * @type object + */ + _poll:{}, + + /** + * @description Queue of timeout values for each transaction callback with a defined timeout value. + * @property _timeOut + * @private + * @static + * @type object + */ + _timeOut:{}, + + /** + * @description The polling frequency, in milliseconds, for HandleReadyState. + * when attempting to determine a transaction's XHR readyState. + * The default is 50 milliseconds. + * @property _polling_interval + * @private + * @static + * @type int + */ + _polling_interval:50, + + /** + * @description A transaction counter that increments the transaction id for each transaction. + * @property _transaction_id + * @private + * @static + * @type int + */ + _transaction_id:0, + + /** + * @description Custom event that fires at the start of a transaction + * @property startEvent + * @private + * @static + * @type CustomEvent + */ + startEvent: new YAHOO.util.CustomEvent('start'), + + /** + * @description Custom event that fires when a transaction response has completed. + * @property completeEvent + * @private + * @static + * @type CustomEvent + */ + completeEvent: new YAHOO.util.CustomEvent('complete'), + + /** + * @description Custom event that fires when handleTransactionResponse() determines a + * response in the HTTP 2xx range. + * @property successEvent + * @private + * @static + * @type CustomEvent + */ + successEvent: new YAHOO.util.CustomEvent('success'), + + /** + * @description Custom event that fires when handleTransactionResponse() determines a + * response in the HTTP 4xx/5xx range. + * @property failureEvent + * @private + * @static + * @type CustomEvent + */ + failureEvent: new YAHOO.util.CustomEvent('failure'), + + /** + * @description Custom event that fires when a transaction is successfully aborted. + * @property abortEvent + * @private + * @static + * @type CustomEvent + */ + abortEvent: new YAHOO.util.CustomEvent('abort'), + + /** + * @description A reference table that maps callback custom events members to its specific + * event name. + * @property _customEvents + * @private + * @static + * @type object + */ + _customEvents: + { + onStart:['startEvent', 'start'], + onComplete:['completeEvent', 'complete'], + onSuccess:['successEvent', 'success'], + onFailure:['failureEvent', 'failure'], + onUpload:['uploadEvent', 'upload'], + onAbort:['abortEvent', 'abort'] + }, + + /** + * @description Member to add an ActiveX id to the existing xml_progid array. + * In the event(unlikely) a new ActiveX id is introduced, it can be added + * without internal code modifications. + * @method setProgId + * @public + * @static + * @param {string} id The ActiveX id to be added to initialize the XHR object. + * @return void + */ + setProgId:function(id) + { + this._msxml_progid.unshift(id); + YAHOO.log('ActiveX Program Id ' + id + ' added to _msxml_progid.', 'info', 'Connection'); + }, + + /** + * @description Member to override the default POST header. + * @method setDefaultPostHeader + * @public + * @static + * @param {boolean} b Set and use default header - true or false . + * @return void + */ + setDefaultPostHeader:function(b) + { + if(typeof b == 'string'){ + this._default_post_header = b; + YAHOO.log('Default POST header set to ' + b, 'info', 'Connection'); + } + else if(typeof b == 'boolean'){ + this._use_default_post_header = b; + } + }, + + /** + * @description Member to override the default transaction header.. + * @method setDefaultXhrHeader + * @public + * @static + * @param {boolean} b Set and use default header - true or false . + * @return void + */ + setDefaultXhrHeader:function(b) + { + if(typeof b == 'string'){ + this._default_xhr_header = b; + YAHOO.log('Default XHR header set to ' + b, 'info', 'Connection'); + } + else{ + this._use_default_xhr_header = b; + } + }, + + /** + * @description Member to modify the default polling interval. + * @method setPollingInterval + * @public + * @static + * @param {int} i The polling interval in milliseconds. + * @return void + */ + setPollingInterval:function(i) + { + if(typeof i == 'number' && isFinite(i)){ + this._polling_interval = i; + YAHOO.log('Default polling interval set to ' + i +'ms', 'info', 'Connection'); + } + }, + + /** + * @description Instantiates a XMLHttpRequest object and returns an object with two properties: + * the XMLHttpRequest instance and the transaction id. + * @method createXhrObject + * @private + * @static + * @param {int} transactionId Property containing the transaction id for this transaction. + * @return object + */ + createXhrObject:function(transactionId) + { + var obj,http,i; + try + { + // Instantiates XMLHttpRequest in non-IE browsers and assigns to http. + http = new XMLHttpRequest(); + // Object literal with http and tId properties + obj = { conn:http, tId:transactionId, xhr: true }; + YAHOO.log('XHR object created for transaction ' + transactionId, 'info', 'Connection'); + } + catch(e) + { + for(i=0; i= 200 && httpStatus < 300) || httpStatus === 1223 || xdrS){ + responseObject = o.xdr ? o.r : this.createResponseObject(o, args); + if(callback && callback.success){ + if(!callback.scope){ + callback.success(responseObject); + YAHOO.log('Success callback. HTTP code is ' + httpStatus, 'info', 'Connection'); + } + else{ + // If a scope property is defined, the callback will be fired from + // the context of the object. + callback.success.apply(callback.scope, [responseObject]); + YAHOO.log('Success callback with scope. HTTP code is ' + httpStatus, 'info', 'Connection'); + } + } + + // Fire global custom event -- successEvent + this.successEvent.fire(responseObject); + + if(o.successEvent){ + // Fire transaction custom event -- successEvent + o.successEvent.fire(responseObject); + } + } + else{ + switch(httpStatus){ + // The following cases are wininet.dll error codes that may be encountered. + case 12002: // Server timeout + case 12029: // 12029 to 12031 correspond to dropped connections. + case 12030: + case 12031: + case 12152: // Connection closed by server. + case 13030: // See above comments for variable status. + // XDR transactions will not resolve to this case, since the + // response object is already built in the xdr response. + responseObject = this.createExceptionObject(o.tId, args, (isAbort?isAbort:false)); + if(callback && callback.failure){ + if(!callback.scope){ + callback.failure(responseObject); + YAHOO.log('Failure callback. Exception detected. Status code is ' + httpStatus, 'warn', 'Connection'); + } + else{ + callback.failure.apply(callback.scope, [responseObject]); + YAHOO.log('Failure callback with scope. Exception detected. Status code is ' + httpStatus, 'warn', 'Connection'); + } + } + + break; + default: + responseObject = (o.xdr) ? o.response : this.createResponseObject(o, args); + if(callback && callback.failure){ + if(!callback.scope){ + callback.failure(responseObject); + YAHOO.log('Failure callback. HTTP status code is ' + httpStatus, 'warn', 'Connection'); + } + else{ + callback.failure.apply(callback.scope, [responseObject]); + YAHOO.log('Failure callback with scope. HTTP status code is ' + httpStatus, 'warn', 'Connection'); + } + } + } + + // Fire global custom event -- failureEvent + this.failureEvent.fire(responseObject); + + if(o.failureEvent){ + // Fire transaction custom event -- failureEvent + o.failureEvent.fire(responseObject); + } + + } + + this.releaseObject(o); + responseObject = null; + }, + + /** + * @description This method evaluates the server response, creates and returns the results via + * its properties. Success and failure cases will differ in the response + * object's property values. + * @method createResponseObject + * @private + * @static + * @param {object} o The connection object + * @param {callbackArg} callbackArg The user-defined argument or arguments to be passed to the callback + * @return {object} + */ + createResponseObject:function(o, callbackArg) + { + var obj = {}, headerObj = {}, + i, headerStr, header, delimitPos; + + try + { + headerStr = o.conn.getAllResponseHeaders(); + header = headerStr.split('\n'); + for(i=0; i=200&&E<300)||E===1223||C){A=B.xdr?B.r:this.createResponseObject(B,G);if(I&&I.success){if(!I.scope){I.success(A);}else{I.success.apply(I.scope,[A]);}}this.successEvent.fire(A);if(B.successEvent){B.successEvent.fire(A);}}else{switch(E){case 12002:case 12029:case 12030:case 12031:case 12152:case 13030:A=this.createExceptionObject(B.tId,G,(D?D:false));if(I&&I.failure){if(!I.scope){I.failure(A);}else{I.failure.apply(I.scope,[A]);}}break;default:A=(B.xdr)?B.response:this.createResponseObject(B,G);if(I&&I.failure){if(!I.scope){I.failure(A);}else{I.failure.apply(I.scope,[A]);}}}this.failureEvent.fire(A);if(B.failureEvent){B.failureEvent.fire(A);}}this.releaseObject(B);A=null;},createResponseObject:function(A,G){var D={},I={},E,C,F,B;try{C=A.conn.getAllResponseHeaders();F=C.split("\n");for(E=0;E= 200 && httpStatus < 300) || httpStatus === 1223 || xdrS){ + responseObject = o.xdr ? o.r : this.createResponseObject(o, args); + if(callback && callback.success){ + if(!callback.scope){ + callback.success(responseObject); + } + else{ + // If a scope property is defined, the callback will be fired from + // the context of the object. + callback.success.apply(callback.scope, [responseObject]); + } + } + + // Fire global custom event -- successEvent + this.successEvent.fire(responseObject); + + if(o.successEvent){ + // Fire transaction custom event -- successEvent + o.successEvent.fire(responseObject); + } + } + else{ + switch(httpStatus){ + // The following cases are wininet.dll error codes that may be encountered. + case 12002: // Server timeout + case 12029: // 12029 to 12031 correspond to dropped connections. + case 12030: + case 12031: + case 12152: // Connection closed by server. + case 13030: // See above comments for variable status. + // XDR transactions will not resolve to this case, since the + // response object is already built in the xdr response. + responseObject = this.createExceptionObject(o.tId, args, (isAbort?isAbort:false)); + if(callback && callback.failure){ + if(!callback.scope){ + callback.failure(responseObject); + } + else{ + callback.failure.apply(callback.scope, [responseObject]); + } + } + + break; + default: + responseObject = (o.xdr) ? o.response : this.createResponseObject(o, args); + if(callback && callback.failure){ + if(!callback.scope){ + callback.failure(responseObject); + } + else{ + callback.failure.apply(callback.scope, [responseObject]); + } + } + } + + // Fire global custom event -- failureEvent + this.failureEvent.fire(responseObject); + + if(o.failureEvent){ + // Fire transaction custom event -- failureEvent + o.failureEvent.fire(responseObject); + } + + } + + this.releaseObject(o); + responseObject = null; + }, + + /** + * @description This method evaluates the server response, creates and returns the results via + * its properties. Success and failure cases will differ in the response + * object's property values. + * @method createResponseObject + * @private + * @static + * @param {object} o The connection object + * @param {callbackArg} callbackArg The user-defined argument or arguments to be passed to the callback + * @return {object} + */ + createResponseObject:function(o, callbackArg) + { + var obj = {}, headerObj = {}, + i, headerStr, header, delimitPos; + + try + { + headerStr = o.conn.getAllResponseHeaders(); + header = headerStr.split('\n'); + for(i=0; iI}<~*C}@N9;| z|NsA=EwFpJ-~8Duhv%zpo=tOjvC8JfTC11aEne+4d$G;p=@iFjvmIXTGJmnj^5t&x zr&AqYZnu2C(C+0{%NHwcUM#bHwa@(3Zu94hZJ#f+eLBtY*<_~|n=N1MF@Ler`q^B& z=Zo#W-Ku@Q+~(ON$ETAWU+pt{x!3&pJiF%$?4B>Pd9lIz8}k zv#+Op7)HTp2w)2V#h)yU3=F;uIv`0dcnCdYow$ryRwm)l6DB4Gk+g(dC56_L>4~z^wOeRtW784ndaCP%f(TF<}v9Z6kOWey$LV&><04x5_ Al>h($ literal 0 HcmV?d00001 diff --git a/include/javascript/yui/build/container/assets/blck16_1.gif b/include/javascript/yui/build/container/assets/blck16_1.gif new file mode 100644 index 0000000000000000000000000000000000000000..56689611db271fcafe42e652c6496b703f38d9e3 GIT binary patch literal 591 zcmZ?wbhEHb6krfwcox9$rM&!ief{ri*M2G}{3$H|$;0!--TkMg=1&okpCKVXxwt;N zxcth@c*Vv2Q&{-tkt5$~YJLa`{ycj0>&%&7XV3nrrS+MI=d+K`XHn5_?d?BJO@AsW z{Zv)`YG(E_BlD|}&_^rl?}CEgy1RcG8h!;T5EXr^r~ge|{U;yaPbsON?(SbLEx!~N zewCB^p{Ms#Qu3>h&(GwzuioCjFJJy*Wc1VC{%e2#Pd2unyu9D6tbX$I|8#Tv8W#4` z*!ZWP-%n1?Zxt0Ei;A9yhW*sn|0yl~B{cM_i_2#lo8P&)@4~{r#K!(ijJwXn^eM>g z=bk;^jExxv8BqMm!pOi7z@P(i7bs2`*w-`!G&Q%hw)(O7cKNdSwFUV3dV3pk+G$z# zwM?AM$uQsA)PL55N#5K{&1U{ctY~3a#+}>aQ#-+$7*~BS71qnO#&}r^Q57t%-%1S=z?9MTNskuE|eA zUvtWbrb&uSd}>SPv=lTvVCIq34bX6?IN{XT%~f}2LB`yc8I$0kO%o As{jB1 literal 0 HcmV?d00001 diff --git a/include/javascript/yui/build/container/assets/close12_1.gif b/include/javascript/yui/build/container/assets/close12_1.gif new file mode 100644 index 0000000000000000000000000000000000000000..e2f67d72efc158da4e069822cbe338915761e396 GIT binary patch literal 85 zcmZ?wbhEHbz lf$Gy9znh?Y?^x%Bps9Cfw!UsJn!aoAS>7kV)`>G%0|4uCA&me4 literal 0 HcmV?d00001 diff --git a/include/javascript/yui/build/container/assets/container-core.css b/include/javascript/yui/build/container/assets/container-core.css new file mode 100644 index 00000000..49032155 --- /dev/null +++ b/include/javascript/yui/build/container/assets/container-core.css @@ -0,0 +1,176 @@ +/* +Copyright (c) 2009, Yahoo! Inc. All rights reserved. +Code licensed under the BSD License: +http://developer.yahoo.net/yui/license.txt +version: 2.8.0r4 +*/ +.yui-overlay, +.yui-panel-container { + visibility: hidden; + position: absolute; + z-index: 2; +} + +.yui-panel { + position:relative; +} + +.yui-panel-container form { + margin: 0; +} + +.mask { + z-index: 1; + display: none; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; +} + +.mask.block-scrollbars { + /* + Application of "overflow:auto" prevents Mac scrollbars from bleeding + through the modality mask in Gecko. The block-scollbars class is only + added for Gecko on MacOS + */ + overflow: auto; +} + +/* + PLEASE NOTE: + + 1) ".masked select" is used to prevent elements when dragging a + Panel in IE 6. This is necessary to prevent some redraw problems with + the elements don't inherit their parent + element's opacity in IE 6. + +*/ + +.masked select, +.drag select, +.hide-select select { + _visibility: hidden; +} + +.yui-panel-container select { + _visibility: inherit; +} + +/* + +There are two known issues with YAHOO.widget.Overlay (and its subclasses) that +manifest in Gecko-based browsers on Mac OS X: + + 1) Elements with scrollbars will poke through Overlay instances floating + above them. + + 2) An Overlay's scrollbars and the scrollbars of its child nodes remain + visible when the Overlay is hidden. + +To fix these bugs: + + 1) The "overflow" property of an Overlay instance's root element and child + nodes is toggled between "hidden" and "auto" (through the application + and removal of the "hide-scrollbars" and "show-scrollbars" CSS classes) + as its "visibility" configuration property is toggled between + "false" and "true." + + 2) The "display" property of elements that are child nodes of the + Overlay instance's root element is set to "none" when it is hidden. + +PLEASE NOTE: + + 1) The "hide-scrollbars" and "show-scrollbars" CSS classes classes are + applied only for Gecko on Mac OS X and are added/removed to/from the + Overlay's root HTML element (DIV) via the "hideMacGeckoScrollbars" and + "showMacGeckoScrollbars" methods of YAHOO.widget.Overlay. + + 2) There may be instances where the CSS for a web page or application + contains style rules whose specificity override the rules implemented by + the Container CSS files to fix this bug. In such cases, is necessary to + leverage the provided "hide-scrollbars" and "show-scrollbars" classes to + write custom style rules to guard against this bug. + +** For more information on this issue, see: + + https://bugzilla.mozilla.org/show_bug.cgi?id=187435 + + YUILibrary bug #1723530 + +*/ + +.hide-scrollbars, +.hide-scrollbars * { + + overflow: hidden; + +} + +.hide-scrollbars select { + + display: none; + +} + +.show-scrollbars { + + overflow: auto; + +} + +.yui-panel-container.show-scrollbars { + + overflow: visible; + +} + +.yui-panel-container.show-scrollbars .underlay { + + overflow: auto; + +} + +.yui-panel-container.focused { + +} + + +/* Panel underlay styles */ + +.yui-panel-container .underlay { + + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + +} + +.yui-panel-container.matte { + + padding: 3px; + background-color: #fff; + +} + +.yui-panel-container.shadow .underlay { + + top: 3px; + bottom: -3px; + right: -3px; + left: 3px; + background-color: #000; + opacity: .12; + filter: alpha(opacity=12); /* For IE */ + +} + +/* + Workaround for Safari 2.x - the yui-force-redraw class is applied, and then removed when + the Panel's content changes, to force Safari 2.x to redraw the underlay. + We attempt to choose a CSS property which has no visual impact when added, + removed, but still causes Safari to redraw +*/ +.yui-panel-container.shadow .underlay.yui-force-redraw { + padding-bottom: 1px; +} + +.yui-effect-fade .underlay { + display:none; +} + +.yui-panel { + visibility:hidden; + border-collapse:separate; + position:relative; + left:0; + top:0; + font:1em Arial; + background-color:#FFF; + border:1px solid #000; + z-index:1; + overflow:hidden; +} + +.yui-panel .hd { + background-color:#3d77cb; + color:#FFF; + font-size:100%; + line-height:100%; + border:1px solid #FFF; + border-bottom:1px solid #000; + font-weight:bold; + padding:4px; + white-space:nowrap; +} + +.yui-panel .bd { + overflow:hidden; + padding:4px; +} + +.yui-panel .bd p { + margin:0 0 1em; +} + +.yui-panel .container-close { + position:absolute; + top:5px; + right:4px; + z-index:6; + height:12px; + width:12px; + margin:0px; + padding:0px; + background:url(close12_1.gif) no-repeat; + cursor:pointer; + visibility:inherit; + text-indent:-10000em; + overflow:hidden; + text-decoration:none; +} + +.yui-panel .ft { + padding:4px; + overflow:hidden; +} + +.yui-simple-dialog .bd .yui-icon { + background-repeat:no-repeat; + width:16px; + height:16px; + margin-right:10px; + float:left; +} + +.yui-simple-dialog .bd span.blckicon { + background: url("blck16_1.gif") no-repeat; +} + +.yui-simple-dialog .bd span.alrticon { + background: url("alrt16_1.gif") no-repeat; +} + +.yui-simple-dialog .bd span.hlpicon { + background: url("hlp16_1.gif") no-repeat; +} + +.yui-simple-dialog .bd span.infoicon { + background: url("info16_1.gif") no-repeat; +} + +.yui-simple-dialog .bd span.warnicon { + background: url("warn16_1.gif") no-repeat; +} + +.yui-simple-dialog .bd span.tipicon { + background: url("tip16_1.gif") no-repeat; +} + +.yui-dialog .ft, +.yui-simple-dialog .ft { + padding-bottom:5px; + padding-right:5px; + text-align:right; +} + +.yui-dialog form, +.yui-simple-dialog form { + margin:0; +} + +.button-group button { + font:100 76% verdana; + text-decoration:none; + background-color: #E4E4E4; + color: #333; + cursor: hand; + vertical-align: middle; + border: 2px solid #797979; + border-top-color:#FFF; + border-left-color:#FFF; + margin:2px; + padding:2px; +} + +.button-group button.default { + font-weight:bold; +} + +.button-group button:hover, +.button-group button.hover { + border:2px solid #90A029; + background-color:#EBF09E; + border-top-color:#FFF; + border-left-color:#FFF; +} + +.button-group button:active { + border:2px solid #E4E4E4; + background-color:#BBB; + border-top-color:#333; + border-left-color:#333; +} + +.yui-override-padding { + padding:0 !important; +} diff --git a/include/javascript/yui/build/container/assets/hlp16_1.gif b/include/javascript/yui/build/container/assets/hlp16_1.gif new file mode 100644 index 0000000000000000000000000000000000000000..4645c8fdfa693126bd5fe969737dc1ccac1e62e1 GIT binary patch literal 928 zcmZ?wbhEHb6krfw_-?>(y^ZbFe)X>pdVXIIcs^hJNiYA4HF8fnd0uW*csg0|*(}jl z`_x|_)OfyJ`tcvW#7eMYJ$(NgzUhYtNHbdmqF11(tG+wNe ze>Pv@+j-kFHC!JrMKFwl(GZ|x2q^w!VPs%1V9){C3Ca@;9JLII94(3qS`Uipv+%@l zJbu8yCTA2-aZun`HzT7AOT>bMhd6me#LFrcC_U-sP!kYHkZ^G7YSj;u&^QoqpnHNC zZ;t}w0;My&@@fnRB0st^3#zvLlHqv7#J$v;RfvPpREvjIBSs+hlwxDp>V#Uch7Y1| R8o5%}?uytg>gK>;4FF6EfMoyx literal 0 HcmV?d00001 diff --git a/include/javascript/yui/build/container/assets/info16_1.gif b/include/javascript/yui/build/container/assets/info16_1.gif new file mode 100644 index 0000000000000000000000000000000000000000..22f697a9917f3bae423726ef6c541e618e7a0221 GIT binary patch literal 601 zcmZ?wbhEHb6krfwc*ekR^2`$>r}fqW+ji}_yJYokZHxH}m!7X}I}?_)$H;t^iq<51 z=Q+}%ZYnzMy4K6|tXJyWt`_1CmRGK`4ch7!yH!cOTSh)#$8w3X<^)ZX8Jjj7)YD4R zv0UsNwN+Im+c|Qxyi$XTZl|efbxhsqsOlp&_LH02_MbZYysT(KOUEHeshsMn1>ULK zcJ8{NpjI!y<89(Jm7mMa#AU9wZo~BX*R*u%c{v=rOEb1M1WP>7`>p}+xYXGoF!2kdN literal 0 HcmV?d00001 diff --git a/include/javascript/yui/build/container/assets/skins/sam/container-skin.css b/include/javascript/yui/build/container/assets/skins/sam/container-skin.css new file mode 100644 index 00000000..6966c95d --- /dev/null +++ b/include/javascript/yui/build/container/assets/skins/sam/container-skin.css @@ -0,0 +1,242 @@ +/* +Copyright (c) 2009, Yahoo! Inc. All rights reserved. +Code licensed under the BSD License: +http://developer.yahoo.net/yui/license.txt +version: 2.8.0r4 +*/ +/* Panel modality mask styles */ +.yui-skin-sam .mask { + background-color: #000; + opacity: .25; + filter: alpha(opacity=25); /* Set opacity in IE */ +} + +/* Panel styles */ +.yui-skin-sam .yui-panel-container { + padding:0 1px; + /* Padding added for IE to allow 0,0 alignment with shadow */ + *padding:2px; +} + +.yui-skin-sam .yui-panel { + position: relative; + left:0; + top:0; + border-style: solid; + border-width: 1px 0; + border-color: #808080; + z-index: 1; + + /* Rollback rounded corner support for IE6/7 */ + *border-width:1px; + *zoom:1; + _zoom:normal; +} + +.yui-skin-sam .yui-panel .hd, +.yui-skin-sam .yui-panel .bd, +.yui-skin-sam .yui-panel .ft { + border-style: solid; + border-width: 0 1px; + border-color: #808080; + margin: 0 -1px; + + /* Rollback rounded corner support for IE6/7 */ + *margin:0; + *border:0; +} + +.yui-skin-sam .yui-panel .hd { + border-bottom: solid 1px #ccc; +} + +.yui-skin-sam .yui-panel .bd, +.yui-skin-sam .yui-panel .ft { + background-color: #F2F2F2; +} + +.yui-skin-sam .yui-panel .hd { + padding: 0 10px; + font-size: 93%; /* 12px */ + line-height: 2; /* ~24px */ + *line-height: 1.9; /* For IE */ + font-weight: bold; + color: #000; + background: url(../../../../assets/skins/sam/sprite.png) repeat-x 0 -200px; +} + +.yui-skin-sam .yui-panel .bd { + padding: 10px; +} + +.yui-skin-sam .yui-panel .ft { + border-top: solid 1px #808080; + padding: 5px 10px; + font-size: 77%; +} + +.yui-skin-sam .yui-panel-container.focused .yui-panel .hd { + +} + +.yui-skin-sam .container-close { + position: absolute; + top: 5px; + right: 6px; + width: 25px; + height: 15px; + background: url(../../../../assets/skins/sam/sprite.png) no-repeat 0 -300px; + cursor:pointer; +} + +/* Panel underlay styles */ +.yui-skin-sam .yui-panel-container .underlay { + right: -1px; + left: -1px; +} + +.yui-skin-sam .yui-panel-container.matte { + padding: 9px 10px; + background-color: #fff; +} + +.yui-skin-sam .yui-panel-container.shadow { + /* IE 7 Quirks Mode and IE 6 Standards Mode and Quirks mode */ + _padding: 2px 4px 0 2px; +} + +.yui-skin-sam .yui-panel-container.shadow .underlay { + position: absolute; + top: 2px; + left: -3px; + right: -3px; + bottom: -3px; + + /* IE7 Strict (provides 3px shadow (when combined with 2px padding applied to container) */ + *top: 4px; + *left: -1px; + *right: -1px; + *bottom: -1px; + + /* IE 7 Quirks Mode and IE 6 Standards Mode and Quirks mode */ + _top: 0; + _left: 0; + _right: 0; + _bottom: 0; + _margin-top: 3px; + _margin-left: -1px; + + background-color: #000; + opacity: .12; + filter: alpha(opacity=12); /* Set opacity in IE */ +} + + +/* Dialog styles */ +.yui-skin-sam .yui-dialog .ft { + border-top: none; + padding: 0 10px 10px 10px; + font-size: 100%; +} + +.yui-skin-sam .yui-dialog .ft .button-group { + display: block; + text-align: right; +} + +/* Dialog default button style */ +.yui-skin-sam .yui-dialog .ft button.default { + font-weight:bold; +} + +/* Dialog default YUI Button style */ +.yui-skin-sam .yui-dialog .ft span.default { + border-color: #304369; + background-position: 0 -1400px; +} + +.yui-skin-sam .yui-dialog .ft span.default .first-child { + border-color: #304369; +} + +.yui-skin-sam .yui-dialog .ft span.default button { + color: #fff; +} + +/* Dialog YUI Button disabled state */ +.yui-skin-sam .yui-dialog .ft span.yui-button-disabled { + background-position:0pt -1500px; + border-color:#ccc; +} + +.yui-skin-sam .yui-dialog .ft span.yui-button-disabled .first-child { + border-color:#ccc; +} + +.yui-skin-sam .yui-dialog .ft span.yui-button-disabled button { + color:#a6a6a6; +} + +/* SimpleDialog icon styles */ +.yui-skin-sam .yui-simple-dialog .bd .yui-icon { + background: url(../../../../assets/skins/sam/sprite.png) no-repeat 0 0; + width: 16px; + height: 16px; + margin-right: 10px; + float: left; +} + +.yui-skin-sam .yui-simple-dialog .bd span.blckicon { + background-position: 0 -1100px; +} + +.yui-skin-sam .yui-simple-dialog .bd span.alrticon { + background-position: 0 -1050px; +} + +.yui-skin-sam .yui-simple-dialog .bd span.hlpicon { + background-position: 0 -1150px; +} + +.yui-skin-sam .yui-simple-dialog .bd span.infoicon { + background-position: 0 -1200px; +} + +.yui-skin-sam .yui-simple-dialog .bd span.warnicon { + background-position: 0 -1900px; +} + +.yui-skin-sam .yui-simple-dialog .bd span.tipicon { + background-position: 0 -1250px; +} + +/* Tooltip styles */ +.yui-skin-sam .yui-tt .bd { + position: relative; + top: 0; + left: 0; + z-index: 1; + color: #000; + padding: 2px 5px; + border-color: #D4C237 #A6982B #A6982B #A6982B; + border-width: 1px; + border-style: solid; + background-color: #FFEE69; +} + +.yui-skin-sam .yui-tt.show-scrollbars .bd { + overflow: auto; +} + +.yui-skin-sam .yui-tt-shadow { + top: 2px; + right: -3px; + left: -3px; + bottom: -3px; + background-color: #000; +} + +.yui-skin-sam .yui-tt-shadow-visible { + opacity: .12; + filter: alpha(opacity=12); /* For IE */ +} \ No newline at end of file diff --git a/include/javascript/yui/build/container/assets/skins/sam/container.css b/include/javascript/yui/build/container/assets/skins/sam/container.css new file mode 100644 index 00000000..45f1e0b0 --- /dev/null +++ b/include/javascript/yui/build/container/assets/skins/sam/container.css @@ -0,0 +1,7 @@ +/* +Copyright (c) 2009, Yahoo! Inc. All rights reserved. +Code licensed under the BSD License: +http://developer.yahoo.net/yui/license.txt +version: 2.8.0r4 +*/ +.yui-overlay,.yui-panel-container{visibility:hidden;position:absolute;z-index:2;}.yui-panel{position:relative;}.yui-panel-container form{margin:0;}.mask{z-index:1;display:none;position:absolute;top:0;left:0;right:0;bottom:0;}.mask.block-scrollbars{overflow:auto;}.masked select,.drag select,.hide-select select{_visibility:hidden;}.yui-panel-container select{_visibility:inherit;}.hide-scrollbars,.hide-scrollbars *{overflow:hidden;}.hide-scrollbars select{display:none;}.show-scrollbars{overflow:auto;}.yui-panel-container.show-scrollbars,.yui-tt.show-scrollbars{overflow:visible;}.yui-panel-container.show-scrollbars .underlay,.yui-tt.show-scrollbars .yui-tt-shadow{overflow:auto;}.yui-panel-container.shadow .underlay.yui-force-redraw{padding-bottom:1px;}.yui-effect-fade .underlay,.yui-effect-fade .yui-tt-shadow{display:none;}.yui-tt-shadow{position:absolute;}.yui-override-padding{padding:0!important;}.yui-panel-container .container-close{overflow:hidden;text-indent:-10000em;text-decoration:none;}.yui-overlay.yui-force-redraw,.yui-panel-container.yui-force-redraw{margin-bottom:1px;}.yui-skin-sam .mask{background-color:#000;opacity:.25;filter:alpha(opacity=25);}.yui-skin-sam .yui-panel-container{padding:0 1px;*padding:2px;}.yui-skin-sam .yui-panel{position:relative;left:0;top:0;border-style:solid;border-width:1px 0;border-color:#808080;z-index:1;*border-width:1px;*zoom:1;_zoom:normal;}.yui-skin-sam .yui-panel .hd,.yui-skin-sam .yui-panel .bd,.yui-skin-sam .yui-panel .ft{border-style:solid;border-width:0 1px;border-color:#808080;margin:0 -1px;*margin:0;*border:0;}.yui-skin-sam .yui-panel .hd{border-bottom:solid 1px #ccc;}.yui-skin-sam .yui-panel .bd,.yui-skin-sam .yui-panel .ft{background-color:#F2F2F2;}.yui-skin-sam .yui-panel .hd{padding:0 10px;font-size:93%;line-height:2;*line-height:1.9;font-weight:bold;color:#000;background:url(../../../../assets/skins/sam/sprite.png) repeat-x 0 -200px;}.yui-skin-sam .yui-panel .bd{padding:10px;}.yui-skin-sam .yui-panel .ft{border-top:solid 1px #808080;padding:5px 10px;font-size:77%;}.yui-skin-sam .container-close{position:absolute;top:5px;right:6px;width:25px;height:15px;background:url(../../../../assets/skins/sam/sprite.png) no-repeat 0 -300px;cursor:pointer;}.yui-skin-sam .yui-panel-container .underlay{right:-1px;left:-1px;}.yui-skin-sam .yui-panel-container.matte{padding:9px 10px;background-color:#fff;}.yui-skin-sam .yui-panel-container.shadow{_padding:2px 4px 0 2px;}.yui-skin-sam .yui-panel-container.shadow .underlay{position:absolute;top:2px;left:-3px;right:-3px;bottom:-3px;*top:4px;*left:-1px;*right:-1px;*bottom:-1px;_top:0;_left:0;_right:0;_bottom:0;_margin-top:3px;_margin-left:-1px;background-color:#000;opacity:.12;filter:alpha(opacity=12);}.yui-skin-sam .yui-dialog .ft{border-top:none;padding:0 10px 10px 10px;font-size:100%;}.yui-skin-sam .yui-dialog .ft .button-group{display:block;text-align:right;}.yui-skin-sam .yui-dialog .ft button.default{font-weight:bold;}.yui-skin-sam .yui-dialog .ft span.default{border-color:#304369;background-position:0 -1400px;}.yui-skin-sam .yui-dialog .ft span.default .first-child{border-color:#304369;}.yui-skin-sam .yui-dialog .ft span.default button{color:#fff;}.yui-skin-sam .yui-dialog .ft span.yui-button-disabled{background-position:0 -1500px;border-color:#ccc;}.yui-skin-sam .yui-dialog .ft span.yui-button-disabled .first-child{border-color:#ccc;}.yui-skin-sam .yui-dialog .ft span.yui-button-disabled button{color:#a6a6a6;}.yui-skin-sam .yui-simple-dialog .bd .yui-icon{background:url(../../../../assets/skins/sam/sprite.png) no-repeat 0 0;width:16px;height:16px;margin-right:10px;float:left;}.yui-skin-sam .yui-simple-dialog .bd span.blckicon{background-position:0 -1100px;}.yui-skin-sam .yui-simple-dialog .bd span.alrticon{background-position:0 -1050px;}.yui-skin-sam .yui-simple-dialog .bd span.hlpicon{background-position:0 -1150px;}.yui-skin-sam .yui-simple-dialog .bd span.infoicon{background-position:0 -1200px;}.yui-skin-sam .yui-simple-dialog .bd span.warnicon{background-position:0 -1900px;}.yui-skin-sam .yui-simple-dialog .bd span.tipicon{background-position:0 -1250px;}.yui-skin-sam .yui-tt .bd{position:relative;top:0;left:0;z-index:1;color:#000;padding:2px 5px;border-color:#D4C237 #A6982B #A6982B #A6982B;border-width:1px;border-style:solid;background-color:#FFEE69;}.yui-skin-sam .yui-tt.show-scrollbars .bd{overflow:auto;}.yui-skin-sam .yui-tt-shadow{top:2px;right:-3px;left:-3px;bottom:-3px;background-color:#000;}.yui-skin-sam .yui-tt-shadow-visible{opacity:.12;filter:alpha(opacity=12);} diff --git a/include/javascript/yui/build/container/assets/tip16_1.gif b/include/javascript/yui/build/container/assets/tip16_1.gif new file mode 100644 index 0000000000000000000000000000000000000000..8f0be2b8d1fc2151459ddf48c8676f296489a32e GIT binary patch literal 552 zcmZ?wbhEHb6krfwcoxdAqKt250pG88J6`NoJHNgC#7vPV=gNM)KlSdk6-h;E3R*j89zJi_ws8jg}jVf1H%U_x=y1GH>{3efE$9ulq^}jNY_s7%7Yg^Q> zZ&AOxukg+`jfa=Ee7NLzbDQSVEiw;Q@LgK3a&HmayE9fFE_$AvDtPZi>Gka<>-s%k z9n`(GMepbgxjmD_e!N<=V~Wp)c9DO7zkGWX`t@GmmMQi>->ki{LVRtP{*x0vzu)HE z*rxgVklvf)rq8x3zBy*}WTVvm#T@rfmVUgN{`~e~hJgl(KUo+V7(y9zKn?-L2?Kj; zLugZTOKTgOrGd7zMO(9!ryG-*zam#3o3IlTuYjqwl1`hJJ(HKFjJS^5O<_s*)niv=?xL6ph0rg?UhX4Qo literal 0 HcmV?d00001 diff --git a/include/javascript/yui/build/container/assets/warn16_1.gif b/include/javascript/yui/build/container/assets/warn16_1.gif new file mode 100644 index 0000000000000000000000000000000000000000..d679df5aae924ed5a4b16a921c3c4578cd6ea970 GIT binary patch literal 580 zcmZ?wbhEHb6krfwc*el+xK`w8Ci9Cj{%bZ0KW-lQw59R=42!=X9>1HQ`TNnaZ`+e^ zxiCGg7yWvC!5vSgkFyM)RZCt{XMB>%`sdC4t0s)k%aq@3nExPx>EmqU4>OHk)k?l; zmwHep@UBKJ>`yaTpH~^(FBLo^!f?M>@KLq! zyFQK2XP13hAOB*u@2iQ4XT=zlAmgF^t_P!+l2!krs_OSVY}-KO z3Gm&T$hkGa!JyeyIZAdbXW(hOppYg{Dbv$z99yjz{Nj?#h4@c%Sjh2c$H!|Ji8%`> xGW^tE_3^J0v%kfc?(0rR4(Mwo&Dn84<+vz2ch7_c1uBQyRW;c{tVB2%tO4c8+`#|< literal 0 HcmV?d00001 diff --git a/include/javascript/yui/build/container/container-min.js b/include/javascript/yui/build/container/container-min.js new file mode 100644 index 00000000..d36255e2 --- /dev/null +++ b/include/javascript/yui/build/container/container-min.js @@ -0,0 +1,19 @@ +/* +Copyright (c) 2009, Yahoo! Inc. All rights reserved. +Code licensed under the BSD License: +http://developer.yahoo.net/yui/license.txt +version: 2.8.0r4 +*/ +(function(){YAHOO.util.Config=function(D){if(D){this.init(D);}};var B=YAHOO.lang,C=YAHOO.util.CustomEvent,A=YAHOO.util.Config;A.CONFIG_CHANGED_EVENT="configChanged";A.BOOLEAN_TYPE="boolean";A.prototype={owner:null,queueInProgress:false,config:null,initialConfig:null,eventQueue:null,configChangedEvent:null,init:function(D){this.owner=D;this.configChangedEvent=this.createEvent(A.CONFIG_CHANGED_EVENT);this.configChangedEvent.signature=C.LIST;this.queueInProgress=false;this.config={};this.initialConfig={};this.eventQueue=[];},checkBoolean:function(D){return(typeof D==A.BOOLEAN_TYPE);},checkNumber:function(D){return(!isNaN(D));},fireEvent:function(D,F){var E=this.config[D];if(E&&E.event){E.event.fire(F);}},addProperty:function(E,D){E=E.toLowerCase();this.config[E]=D;D.event=this.createEvent(E,{scope:this.owner});D.event.signature=C.LIST;D.key=E;if(D.handler){D.event.subscribe(D.handler,this.owner);}this.setProperty(E,D.value,true);if(!D.suppressEvent){this.queueProperty(E,D.value);}},getConfig:function(){var D={},F=this.config,G,E;for(G in F){if(B.hasOwnProperty(F,G)){E=F[G];if(E&&E.event){D[G]=E.value;}}}return D;},getProperty:function(D){var E=this.config[D.toLowerCase()];if(E&&E.event){return E.value;}else{return undefined;}},resetProperty:function(D){D=D.toLowerCase();var E=this.config[D];if(E&&E.event){if(this.initialConfig[D]&&!B.isUndefined(this.initialConfig[D])){this.setProperty(D,this.initialConfig[D]);return true;}}else{return false;}},setProperty:function(E,G,D){var F;E=E.toLowerCase();if(this.queueInProgress&&!D){this.queueProperty(E,G);return true;}else{F=this.config[E];if(F&&F.event){if(F.validator&&!F.validator(G)){return false;}else{F.value=G;if(!D){this.fireEvent(E,G);this.configChangedEvent.fire([E,G]);}return true;}}else{return false;}}},queueProperty:function(S,P){S=S.toLowerCase();var R=this.config[S],K=false,J,G,H,I,O,Q,F,M,N,D,L,T,E;if(R&&R.event){if(!B.isUndefined(P)&&R.validator&&!R.validator(P)){return false;}else{if(!B.isUndefined(P)){R.value=P;}else{P=R.value;}K=false;J=this.eventQueue.length;for(L=0;L0){G=F-1;do{D=E.subscribers[G];if(D&&D.obj==I&&D.fn==H){return true;}}while(G--);}return false;};YAHOO.lang.augmentProto(A,YAHOO.util.EventProvider);}());(function(){YAHOO.widget.Module=function(R,Q){if(R){this.init(R,Q);}else{}};var F=YAHOO.util.Dom,D=YAHOO.util.Config,N=YAHOO.util.Event,M=YAHOO.util.CustomEvent,G=YAHOO.widget.Module,I=YAHOO.env.ua,H,P,O,E,A={"BEFORE_INIT":"beforeInit","INIT":"init","APPEND":"append","BEFORE_RENDER":"beforeRender","RENDER":"render","CHANGE_HEADER":"changeHeader","CHANGE_BODY":"changeBody","CHANGE_FOOTER":"changeFooter","CHANGE_CONTENT":"changeContent","DESTROY":"destroy","BEFORE_SHOW":"beforeShow","SHOW":"show","BEFORE_HIDE":"beforeHide","HIDE":"hide"},J={"VISIBLE":{key:"visible",value:true,validator:YAHOO.lang.isBoolean},"EFFECT":{key:"effect",suppressEvent:true,supercedes:["visible"]},"MONITOR_RESIZE":{key:"monitorresize",value:true},"APPEND_TO_DOCUMENT_BODY":{key:"appendtodocumentbody",value:false}};G.IMG_ROOT=null;G.IMG_ROOT_SSL=null;G.CSS_MODULE="yui-module";G.CSS_HEADER="hd";G.CSS_BODY="bd";G.CSS_FOOTER="ft";G.RESIZE_MONITOR_SECURE_URL="javascript:false;";G.RESIZE_MONITOR_BUFFER=1;G.textResizeEvent=new M("textResize");G.forceDocumentRedraw=function(){var Q=document.documentElement;if(Q){Q.className+=" ";Q.className=YAHOO.lang.trim(Q.className);}};function L(){if(!H){H=document.createElement("div");H.innerHTML=('
    '+'
    ');P=H.firstChild;O=P.nextSibling;E=O.nextSibling;}return H;}function K(){if(!P){L();}return(P.cloneNode(false));}function B(){if(!O){L();}return(O.cloneNode(false));}function C(){if(!E){L();}return(E.cloneNode(false));}G.prototype={constructor:G,element:null,header:null,body:null,footer:null,id:null,imageRoot:G.IMG_ROOT,initEvents:function(){var Q=M.LIST; +this.beforeInitEvent=this.createEvent(A.BEFORE_INIT);this.beforeInitEvent.signature=Q;this.initEvent=this.createEvent(A.INIT);this.initEvent.signature=Q;this.appendEvent=this.createEvent(A.APPEND);this.appendEvent.signature=Q;this.beforeRenderEvent=this.createEvent(A.BEFORE_RENDER);this.beforeRenderEvent.signature=Q;this.renderEvent=this.createEvent(A.RENDER);this.renderEvent.signature=Q;this.changeHeaderEvent=this.createEvent(A.CHANGE_HEADER);this.changeHeaderEvent.signature=Q;this.changeBodyEvent=this.createEvent(A.CHANGE_BODY);this.changeBodyEvent.signature=Q;this.changeFooterEvent=this.createEvent(A.CHANGE_FOOTER);this.changeFooterEvent.signature=Q;this.changeContentEvent=this.createEvent(A.CHANGE_CONTENT);this.changeContentEvent.signature=Q;this.destroyEvent=this.createEvent(A.DESTROY);this.destroyEvent.signature=Q;this.beforeShowEvent=this.createEvent(A.BEFORE_SHOW);this.beforeShowEvent.signature=Q;this.showEvent=this.createEvent(A.SHOW);this.showEvent.signature=Q;this.beforeHideEvent=this.createEvent(A.BEFORE_HIDE);this.beforeHideEvent.signature=Q;this.hideEvent=this.createEvent(A.HIDE);this.hideEvent.signature=Q;},platform:function(){var Q=navigator.userAgent.toLowerCase();if(Q.indexOf("windows")!=-1||Q.indexOf("win32")!=-1){return"windows";}else{if(Q.indexOf("macintosh")!=-1){return"mac";}else{return false;}}}(),browser:function(){var Q=navigator.userAgent.toLowerCase();if(Q.indexOf("opera")!=-1){return"opera";}else{if(Q.indexOf("msie 7")!=-1){return"ie7";}else{if(Q.indexOf("msie")!=-1){return"ie";}else{if(Q.indexOf("safari")!=-1){return"safari";}else{if(Q.indexOf("gecko")!=-1){return"gecko";}else{return false;}}}}}}(),isSecure:function(){if(window.location.href.toLowerCase().indexOf("https")===0){return true;}else{return false;}}(),initDefaultConfig:function(){this.cfg.addProperty(J.VISIBLE.key,{handler:this.configVisible,value:J.VISIBLE.value,validator:J.VISIBLE.validator});this.cfg.addProperty(J.EFFECT.key,{suppressEvent:J.EFFECT.suppressEvent,supercedes:J.EFFECT.supercedes});this.cfg.addProperty(J.MONITOR_RESIZE.key,{handler:this.configMonitorResize,value:J.MONITOR_RESIZE.value});this.cfg.addProperty(J.APPEND_TO_DOCUMENT_BODY.key,{value:J.APPEND_TO_DOCUMENT_BODY.value});},init:function(V,U){var S,W;this.initEvents();this.beforeInitEvent.fire(G);this.cfg=new D(this);if(this.isSecure){this.imageRoot=G.IMG_ROOT_SSL;}if(typeof V=="string"){S=V;V=document.getElementById(V);if(!V){V=(L()).cloneNode(false);V.id=S;}}this.id=F.generateId(V);this.element=V;W=this.element.firstChild;if(W){var R=false,Q=false,T=false;do{if(1==W.nodeType){if(!R&&F.hasClass(W,G.CSS_HEADER)){this.header=W;R=true;}else{if(!Q&&F.hasClass(W,G.CSS_BODY)){this.body=W;Q=true;}else{if(!T&&F.hasClass(W,G.CSS_FOOTER)){this.footer=W;T=true;}}}}}while((W=W.nextSibling));}this.initDefaultConfig();F.addClass(this.element,G.CSS_MODULE);if(U){this.cfg.applyConfig(U,true);}if(!D.alreadySubscribed(this.renderEvent,this.cfg.fireQueue,this.cfg)){this.renderEvent.subscribe(this.cfg.fireQueue,this.cfg,true);}this.initEvent.fire(G);},initResizeMonitor:function(){var R=(I.gecko&&this.platform=="windows");if(R){var Q=this;setTimeout(function(){Q._initResizeMonitor();},0);}else{this._initResizeMonitor();}},_initResizeMonitor:function(){var Q,S,U;function W(){G.textResizeEvent.fire();}if(!I.opera){S=F.get("_yuiResizeMonitor");var V=this._supportsCWResize();if(!S){S=document.createElement("iframe");if(this.isSecure&&G.RESIZE_MONITOR_SECURE_URL&&I.ie){S.src=G.RESIZE_MONITOR_SECURE_URL;}if(!V){U=[" + + + + +
    +
    +
    +

    YUI Library Home

    +
    + + +
    + + + +
    +
    +
    +

    The Yahoo! User Interface Library (YUI)

    +
    +
    +
    +
    +
    + +

    Welcome to the Yahoo! User Interface Library (YUI)

    + +

    Thanks for downloading the YUI Library of JavaScript and CSS components. The files you've downloaded contain all of the source code for YUI (in the /build directory) as well as functional examples for each component. They also contain documentation in the form of API docs. PDF cheatsheets for most components are available as an external download.

    + +

    Getting Started:

    +
      +
    1. Check out the examples of YUI in action. We recommend starting with the Event Utility and Dom Collection examples; Event and Dom provide an important foundation for JavaScript developers using YUI. Once you've reviewed those two foundational pieces, go on to explore utilities like Drag and Drop and Animation or UI controls like Button, Calendar and TabView. If you're interested in YUI's CSS components, read through the examples for Reset, Base, Fonts, and Grids in that order.
    2. +
    3. Remember that there are full user's guides for each component on the YUI website (external link). If you have any questions about a component as you play with the examples, check out the component's user's guide or the searchable API documentation.
    4. +
    5. Remember that you can download cheat sheets (external) for most YUI components. These one- or two-page printable PDFs make for a good starting point as you explore the various aspects of YUI.
    6. +
    7. Start building. You can include YUI scripts and CSS from this distribution (in the /build directory) or directly from Yahoo! servers. The YUI Loader Utility is a client-side loading package that can dynamically pull in YUI scripts as needed, whether from your servers or from ours.
    8. +
    9. Become a member of the YUI community. YUI developers and implementers share thoughts and solutions and provide a helping hand in our forums (external link; requires a Yahoo! ID). YUI developers also contribute to the YUIBlog, where you'll find in-depth articles, videos and other great content about YUI and the world of frontend engineering.
    10. +
    +

    YUI Functional Examples Included with This Download:

    + +

    Along with the source code for YUI, your download includes 298 functional examples and tutorials that demonstrate each component in action. Use the list below or the menu at left to review these YUI demos — they're the best way to get oriented to what YUI can do and to grab sample code that can help you get started. Remember that these examples and more, in addition to user's guides for each YUI component, can also be found on the YUI website (external link). (Note: Almost all examples in this distribution will work if you are browsing them from your filesystem, but some examples included here do need to be deployed on a PHP-enabled http server to function properly; if you don't have access to such a setup, just check out those examples on our website to see how they work.)

    + +
    + + + +
    +

    More from the YUI Project:

    + +

    The YUI Project also includes the YUI Compressor, a safe and powerful server-side JavaScript/CSS minifier. We use YUI Compressor to pack the YUI Library's -min files, and you can use it on your own files as well. Check out the YUI Compressor page on the YUI website.

    +
    + +
    +
    + + + +
    + +
    +

    Copyright © 2008 Yahoo! Inc. All rights reserved.

    +

    Privacy Policy - + Terms of Service - + Copyright Policy - + Job Openings

    +
    +
    + + + diff --git a/include/javascript/yui/ygDDList.js b/include/javascript/yui/ygDDList.js new file mode 100644 index 00000000..f321e943 --- /dev/null +++ b/include/javascript/yui/ygDDList.js @@ -0,0 +1,154 @@ + +/* Copyright (c) 2006 Yahoo! Inc. All rights reserved. */ + +/** + * @class a YAHOO.util.DDProxy implementation. During the drag over event, the + * dragged element is inserted before the dragged-over element. + * + * @extends YAHOO.util.DDProxy + * @constructor + * @param {String} id the id of the linked element + * @param {String} sGroup the group of related DragDrop objects + */ +function ygDDList(id, sGroup) { + + if (id) { + this.init(id, sGroup); + this.initFrame(); + //this.logger = new ygLogger("ygDDList"); + } + + var s = this.getDragEl().style; + s.borderColor = "transparent"; + s.backgroundColor = "#f6f5e5"; + s.opacity = 0.76; + s.filter = "alpha(opacity=76)"; +} + +ygDDList.prototype = new YAHOO.util.DDProxy(); + +ygDDList.prototype.borderDiv = null; +ygDDList.prototype.originalDisplayProperties = Array(); + +ygDDList.prototype.startDrag = function(x, y) { + //this.logger.debug(this.id + " startDrag"); + + var dragEl = this.getDragEl(); + var clickEl = this.getEl(); + + dragEl.innerHTML = clickEl.innerHTML; + dragElObjects = dragEl.getElementsByTagName('object'); + + + dragEl.className = clickEl.className; + dragEl.style.color = clickEl.style.color; + dragEl.style.border = "1px solid #aaa"; + + // save the style of the object + clickElRegion = YAHOO.util.Dom.getRegion(clickEl); + + this.borderDiv = document.createElement('div'); // create a div to display border + this.borderDiv.style.height = (clickElRegion.bottom - clickElRegion.top) + 'px'; + this.borderDiv.style.border = '2px dashed #cccccc'; + + for(i in clickEl.childNodes) { // hide contents of the target elements contents + if(typeof clickEl.childNodes[i].style != 'undefined') { + this.originalDisplayProperties[i] = clickEl.childNodes[i].style.display; + clickEl.childNodes[i].style.display = 'none'; + } + + } + clickEl.appendChild(this.borderDiv); +}; + +ygDDList.prototype.endDrag = function(e) { + // disable moving the linked element + var clickEl = this.getEl(); + + clickEl.removeChild(this.borderDiv); // remove border div + + for(i in clickEl.childNodes) { // show target elements contents + if(typeof clickEl.childNodes[i].style != 'undefined') { + clickEl.childNodes[i].style.display = this.originalDisplayProperties[i]; + } + } + + if(this.clickHeight) + clickEl.style.height = this.clickHeight; + else + clickEl.style.height = ''; + + if(this.clickBorder) + clickEl.style.border = this.clickBorder; + else + clickEl.style.border = ''; + + dragEl = this.getDragEl(); + dragEl.innerHTML = ''; + + this.afterEndDrag(e); +}; + +ygDDList.prototype.afterEndDrag = function(e) { + +} + +ygDDList.prototype.onDrag = function(e, id) { + +}; + +ygDDList.prototype.onDragOver = function(e, id) { + // this.logger.debug(this.id.toString() + " onDragOver " + id); + var el; + + if ("string" == typeof id) { + el = YAHOO.util.DDM.getElement(id); + } else { + el = YAHOO.util.DDM.getBestMatch(id).getEl(); + } + + dragEl = this.getDragEl(); + elRegion = YAHOO.util.Dom.getRegion(el); + +// this.logger.debug('id: ' + el.id); +// this.logger.debug('size: ' + (elRegion.bottom - elRegion.top)); +// this.logger.debug('getPosY: ' + YAHOO.util.DDM.getPosY(el)); + var mid = YAHOO.util.DDM.getPosY(el) + (Math.floor((elRegion.bottom - elRegion.top) / 2)); +// this.logger.debug('mid: ' + mid); + +// this.logger.debug(YAHOO.util.DDM.getPosY(dragEl) + " < " + mid); +// this.logger.debug("Y: " + YAHOO.util.Event.getPageY(e)); + + if (YAHOO.util.DDM.getPosY(dragEl) < mid ) { // insert on top triggering item + var el2 = this.getEl(); + var p = el.parentNode; + p.insertBefore(el2, el); + } + if (YAHOO.util.DDM.getPosY(dragEl) >= mid ) { // insert below triggered item + var el2 = this.getEl(); + var p = el.parentNode; + p.insertBefore(el2, el.nextSibling); + } +}; + +ygDDList.prototype.onDragEnter = function(e, id) { + // this.logger.debug(this.id.toString() + " onDragEnter " + id); + // this.getDragEl().style.border = "1px solid #449629"; +}; + +ygDDList.prototype.onDragOut = function(e, id) { + // I need to know when we are over nothing + // this.getDragEl().style.border = "1px solid #964428"; +} + +///////////////////////////////////////////////////////////////////////////// + +function ygDDListBoundary(id, sGroup) { + if (id) { + this.init(id, sGroup); + //this.logger = new ygLogger("ygDDListBoundary"); + this.isBoundary = true; + } +} + +ygDDListBoundary.prototype = new YAHOO.util.DDTarget(); diff --git a/include/javascript/yui3/README b/include/javascript/yui3/README new file mode 100644 index 00000000..2084cdc3 --- /dev/null +++ b/include/javascript/yui3/README @@ -0,0 +1,50 @@ +YUI 3.x Library Source + +* Documentation: http://developer.yahoo.com/yui/3/ +* License: http://developer.yahoo.com/yui/license.html +* Latest Stable Release: http://yuilibrary.com/downloads/ +* Discuss: http://yuilibrary.com/forum/ +* Contributor Info: http://developer.yahoo.com/yui/community/contribute.html + +Welcome to YUI. + +The YUI Library is a set of utilities and controls, written in JavaScript, +for building richly interactive web applications using techniques such +as DOM scripting, DHTML and AJAX. YUI is available under a BSD license +and is free for all uses. + +This is the source tree for YUI's 3.x codeline which is has been released +as a technical preview and is not considered ready for production use. +The production codeline for YUI is YUI 2.x; http://developer.yahoo.com/yui/ +is the main YUI website. + +The source tree for YUI includes the following directories: + +* api: Generated API docs for the entire library in HTML format. These + documents are build using YUI Doc from the contents of the src + directory. +* build: Generated/built YUI files. The built files are generated from + the contents of the src directory. Files are provided in full, + commented form (suitable for debugging) and in minified form + (suitable for deployment and use). +* sandbox: The sandbox directory contains works-in-progress, including + unreleased future components, as well as experimental and/or + demonstration code created by library authors. +* src: This directory contains the source code (JavaScript, CSS, image + assets, ActionScript files) for the library. src also contains (or + will contain) all module-specific documentation, tests and examples. + All modifications to the library and its documentation should take + place in this directory. + + The src directory also contains build.xml files, which can be + used to build individual modules using the YUI component build + tool. The YUI component build tool is part of the YUI "builder" + project, also available on GitHub: + + http://github.com/yui/builder + + The README in the componentbuild directory of the builder project + covers installation and use of the build tool. + +Code found in the development head is always a work in progress and +should be treated as experimental. diff --git a/include/javascript/yui3/assets/bg_hd.gif b/include/javascript/yui3/assets/bg_hd.gif new file mode 100644 index 0000000000000000000000000000000000000000..c10acba460e4e67dcfdb5f979bdd5f5477279e7c GIT binary patch literal 96 zcmZ?wbhEHbWMq(J*v!E2@a@-|&p++H@Z{v}mj|ytd;Rs-^G`o6K770F?87%-e=%SH g#h)x-F&z*IGJ}DI*I=qkwyDA#N0wg-LW~U707hdXa{vGU literal 0 HcmV?d00001 diff --git a/include/javascript/yui3/assets/bullet-box6x6.gif b/include/javascript/yui3/assets/bullet-box6x6.gif new file mode 100644 index 0000000000000000000000000000000000000000..22608e487507380c5adaddc06bffe7df9be39bd3 GIT binary patch literal 51 zcmZ?wbhEHbWMg1sXkcLY|NsAi0|yj;vM_*v4u}BBFfeiT$S+7Zy)(*X83Thg0BxBK Af&c&j literal 0 HcmV?d00001 diff --git a/include/javascript/yui3/assets/bullet4x4.png b/include/javascript/yui3/assets/bullet4x4.png new file mode 100644 index 0000000000000000000000000000000000000000..2c85f24be5f23538cea2a7c1ecde930ba6bb0d91 GIT binary patch literal 126 zcmeAS@N?(olHy`uVBq!ia0vp^EFjFm3?%32=lK9B$r9IylHmNblJdl&R0hYC{G?O` z&)mfH)S%SFl*+=BsWw1GYymzYuKklH1DSrCRDS>|K2I0NkcwML2?tmh7}*#YL>L$| SJdKipG7O%selF{r5}E-1LLPSj literal 0 HcmV?d00001 diff --git a/include/javascript/yui3/assets/cheatsheet-shadow.jpg b/include/javascript/yui3/assets/cheatsheet-shadow.jpg new file mode 100644 index 0000000000000000000000000000000000000000..6ce11d8d4fa76727dd99ce9828d73cfc908ba507 GIT binary patch literal 11796 zcmdUVWmp_dn{ML{!6jJm;2sDt6O!N-+#$FH53Yd#!5sp@C4^wX-QC@t!QGvio%enB ze7k$?{y1mru6jT&cY&0}%a(rBT^8e=qYXk7n zfgGR)34snk#798FM}Tz!G;ldl5dKbo0r)E+Aj0KDMMKBH#DZ6-eg+>ZBqT&+Bow&t z@KPUmIe?6hLhyn|9Fi1$luHah*=@^)gC@lysqW2XQNOcGK!3`QnqmY1yj z0)nrEgkQgVFCi%rLALPYG!U>X=UyF*~Qh(-NQ5RYfx~=x6rV-_=Loy z7z3{QN)S!iVER{A*6o{=$WT==K+Id}NdtJg5ZX%4kN8gmk=L z(23s0W|y~P(DSLB5*s^>W0ElNuQQ(g1?_KS|98Lw{#VHU1?)d?Edba^2=K{6!Uw>> z!?sk9b?!1xCOA{t2~Vb$$buL|s(>giv5{8cK{E^OyMeTBHbU^ZoJ8!c~2r zfQJpqgjuKMl_vZq`-eh76zLnKb9RM3z=<*f7yYE@Yn)$WxNmNeDsE;ySJQpb;jG_E zIP@O8E;U~Y1DZ*nF8w-MjL!_J-8R?;XRD@KXf0z$MPGgBwXi}E9Qo5rgSUg&xAMWK z3FvOvoDnR9=r)q)^SY02Q1S`n-f7(6>(W)_^{J@5_dmiOJoo3NM-n}Y>oBGsGv};k zY>F=V8(AwH7?Drv$-}tcs?;OfX8OAg;-r%NTi=zNZjf-)gG|FKE-%bQ_GEc=1Py9C z#9);-w9zTSFYm!!-}u+P1!%}`VSuJw^UKSpN-4_#Qd6w!uU$>j=XbhqnE;wI)EU+^P-#|Xoi!k8s3b<0L%-cvl*mH>St#!R@3W(spm%@t038V(U9hw!I?09J9WU7|0*n(nq z4*YS7bRS4wh@SjlTlq>B1`KpAOdfmM|Hm?l{!emx_>3MQm{=gkFW;(meRxMU*c8)| z?Sa&kk*8t*D1a9N-o+?}0ju18X9M{GU4xdq`krzg^mG5QT5?tn9>$>-k8Hi*^nr*4dV!r4m)eG>tLhzc* z*lg@Za6KA2YFlyUAyKk%fOR<8x}qrBFt)u=3~b(c@b}GTq6h&Xr1RM zj;k*oe%@Jv%5aYEG7@e<5e$xRhp54LI<6lg@HBDY#f!SfJ!r4s2n^is*LL zF`67 zdU)aFgx7bp?@Uf9I5khTxN^Q}=4_yZPB5MBE=-7(hvbmbGzR0YsJ`OXxxiXnTa?NK z-&k@nJiKlWK#V|M~0t_S*?-%+fcsJIwx0osVJ1lX4R#HCnyF zb6vW_2-S^o?$i*W>l2+37n7fb_vKs`o5p?}d6mo2x9_VQgzqAc#waOW&ROwp)n};P z5@7&(aB|}SLE!a|;XINaBo8v?MPVRXS$B5aN>GrL+BJx=%0Q>6%Co!Q0o}6qJwuwT z)TWoI>a^XXa6W^BH8oX?>D{;T{p9F4kiqYe+4|zFPiJvD#r+qZp zMvC&B&E3Nj{5C0=ygv8Bs>^zFKVtK%{%??}7>d~*^hL6)m)z#$!j5ldNF)Pe{3}kO zj<}_aI!f%Rdi91z6UFqZ@=Yk^t#IM~>x2(_9pkKAsjIdV6f44Nl*B81!OXFT)`s|x zj4|vMaseVt+NCii=|#&S3v1ZNhROCqSEFKVtF7yFQ+~UIq)=2Ca810m!qpmg&XRN@ zTg`m*>N~H3(@u&o)@Be4=#3U@(D;*R!DbEp^kd>&Sb={1x7D`!^ku(*i#NMtI@1Or z$?MESj}b2@ajVJcfm}DP9Ma z*dM%*s%zxfn^MO%G~vYv=b7KN9VIX9kJv|pi<<^>)@jVfB3+~0KuesCJ)YA)N=({o zDimxTb7TlR1^4K67l-I6Bi2>P4*DP$C2UxRc*B&MH5AA{K%Z!i*kTlMC(zACgw{Nr zwY+3khoEQBlL}fm{gNBOiHL&`1|TxSfDOz4_QX1Jq-<@Mvnf2Cdapp{z59d9S^Eco z93y}`cgojgx-)z4th)Hmtrc;}oG811wo@K4eXUZgyC|iz(t?Jc)zkVz{@l>GFZqJI zQWun_HBfHSmU2bZ*Q{!ya&2+Ahs=ah4TROi+e@uzQ&~S<#^vIN*X#T-Y5b`<>dd)m z=kVfsfo2{u6Ab7WPic}Wl`QQul&JeKfWVd%9UCL*n-vCJ5_o`hx@YaoD=#=X zv`O5Hw@t0^)5TGEVp@5qJ5x(s)|Duq8vM!+X0`{tJV2J=!)(#Xt{i7^o{+4oU)9k# z`?2o6+AfjCw=0pnZW%&26}@$~cj}M+ZCTM_)?$%`p)Sz*p`W6J{=(DEh&sb!3vH zMA#Kxt?gVKhh!0bXEOHj;^;`{bnipYFjM75K#X*U_~!m^rIbG{ibiXnlHHUx4AwqO zCoUR#@?U=%59!tEPW&3M@th2$g5BMciz>E_Qjn1S^<(Ga%FmDu++Xh%7<7DlVwI;~ zG_BNs`iMlsz$Ln7o~yvzd3`Q0ToCTUO9q(BRhhQGkl7#*67e|b7bfPvu&TL`L<=uV zLN66ys$RynoMV5dXy%4-m!>=9KC$% z_8Bek-~(4zq_LH2ukFv@_UQV#P4sS(H2ZZs1ttdy^|Sg6NvpDFY;wr%9%h*;K{9P9 zHD4@c$Y?D@GkO}1NKPbM1qB5&gr*pp5{XraYy=d{bnig=zj(`D|ywyO0GKXH1ri{T+#^&fbZjG~QXRU0)ZUpf^Gm)lEEm%1E)tM_#D zCKr=fDF-P`*Qg`JPxR2jTb5$G%xdHWZNkS&n10V})_xbFmg%Q*&J>ThzEXJAd+%Fr zd!5cXaech%y2{J{Ht%fJudYn=Oe)ks;L8!Aa%F=43e6p6uQ9oN3T=R{2c*otCrvN! zaQX?YU%^G#(fJo$UaVe@KHCYRnCrecQyValyelJ22^FADOHDi)c~G@=eBD!k)a6Fs z0-0{$vmLE1vC+Bhxn!sio5`=sI*&OR8!8}pDf}U2-Hik^2NA}pJtHY_u*wz5Q$k!3NGu}U=_R~P{m8U1Jj>DdB((dc#vw1gwSBq_IWNl#jxE>!ew_i_Ua z@MG9?D|vX*m8gZ^$e+=K9_6Pjn1wvNCBBnk2-4g6*na=ay8U9TGrtg&cKzVJ@xR^+WGU-pz3zG}K zK}xDt1IKQ``A6xb@w`;3lo|sfKcgOWG9jV!x*pF5=d>xaM;UC)1=ncH3RG$nDtwT0 zEA#VQfLaR4|BX;D@x)%u@#G`Qu^Yjv+GO&FFz2=HIy{46*%mCK>tCmIIMkom~@= zD>0nF4L8Vtm#uaZayFg+yA!u0AN{Q{vexyt*$8Y8{UVGWWmma#n&bOQoKjn22-3Pw zyX1U*a1=i$=irXU<3@Qlng3bZmySOBhwem* zxM6}stp|DEXyR&AM&dLKu(!#)#F+%28gan@vf?Lb=hLin{ zrFtL)AFc-+?-RD3;k{Ew&GigzwqJPOWzXI-n`-JcE5sG^)rC4Fo4T$xuRCA*kDhq` zzRFw7HHB=QVB3LJ9?|%!qaE6Z7@N=5EtI5Klo?p9_z^iHpS5HdYV~m6?A*nNF*Bvd zx31nN73TPmb~St*m$50ZlG|Xabuz1`NG!cp87>bi0PrUZsIST#eToG7Biw})V*}3Q zXJc$v1EZP(d-$R@>N^W}%S>L+xtpj?9P0=~Qi~BF9z^!K;-NivT|2wLcF8%=sGg!m zDIc%);dt)In@&J3>A;Q75mVoP1)BS{b52^WKN7IN4VB5|T8njl5zV;Z<^1O(RXu1k z!iyrbWs&d;ssEbUn_|o*U2Go1@3-Q0&w(H3+rS20YKR6-dWXe+25 z#gmy`%J+9I4HY-@Dab&v7gfl8>}5_k-WC0xgiLnq2Huqd+`2ri@W`N_eOAe0OR{F> z7z=dfEK|!cXJz4*c)!>%Jo-4gfnv)t zG9N)ph+cmFxagoO=HA1KM|x{ZJ6RTy+z_-M`P!AcUQ*k4XW(sbUEtBM3k*0-+@-mE z4u4^I!Dpq0JsHdsh6*h<95(X2Fu+3bo9}X!9V5?>)DX=nt`BQ{ifHVi2USS$=UFq$ zYBn?Er_l<7uS$tGxF-9OKGC3@ydND4^1B>{Diu!?plQL`AFf#hl;)xYe2tVl1=dAY z#r91PqMp~$qLr^%JW8)z)EJKL(le1t-As^L5gTr+ynf`F6yL^o4$~ETk>KI4e4F=2 z2uEV_a**;>usX^#yFsJl>50tO^Jz4&;!hKQp&`Pqk> zaiqwRVxhlzJ8EI&!dF>|va^r8|5}K=G|w_SCskPB1dp}JOLOpycz4i_A?fJ^+#dDh z@%wZyxmNI5ccBf4L}nu~)5$&RZaV5Pa40LIAaJr)w!gpDsa`qR{-?W_%A0R_xt!jJ>~7>9<0yt=jwdefxpN_K7Kzaac;3Z9v12xN3 z)g8rzHs(?%)zipRgN^GMZpE7|n z-~58$^0@u&0XfHC`XLwe_1}Z|xRhwu2p9d(P6ev0s~$Z4qzC6Xcj)tPv)5|ROWt+! zN~+b5=}D@w>>?MSZPDAk=_j`4BHYKK+O22&-h0mON$-G)%C}=wCyG~=uQw^GW=j`_ zBWk5F`943qCi7RGeUNI5aDN9b#!-aler=?^Lb-YBh)CV5zBa3yve@&Wwh@fY_`pj_ ziclqe%xmeb;AVl^1@ElG$+}bzw2)1Z1J5O`Jm@1jrKic%^q>;yzNaa7S2A`||9LUb zu8IYkV;{)sxIpvHi1h?j=j~Bf)Yj4Q+UvhX$)}$sZ zL~eDLEttmo9#Vu16}<45j{&_0JfHDRsqC0sE3@j}KIqo9R=pV}uB@3CT_%w*Y9nVJ z?g*F%bxzGd_9@QVl?W~U{oSFX@yL+qJF5e|=8~h*LXqd;KA`7?=_(5!1SFn^c9LUJ zvIYi-xUJ3R^?Gd-No!z9Uels|g~PDYa#2dT`{;ugXpan`bh5K@JQ| z*0`>Co>)!q(uZGAtDDRnf~TVMiM0OG(^%#Hi?JE_-;B+hPTkgZ+S#TmUhp;J$P_YS zuajfko5wyPjCAlLosO|}>w1U_H*3Ht3(Sx!FFaPsMBSU1%=Xr$*1uOrNN8e_AJpnN0;nE`q)| zlj)L&J}4|VNTPm->tQj0tMHtNI85pmA`%-4Xq73 zktMb>oJ|3&87XUxUu^hwwlcrb)>%2=M2C_U4g|<73%;Xvo~@OgRp1>Nk>>9S@3Ivb zD*YIG)u%o8rP_b!Zs8T~YtyK!%o*m#wmlC*J?ji&xC~sytG~aEHA+q%s}J;WulqP= zJnaYcuHD(?hI-2sHMdJBCEY{VF^~0PUa#%k&2(j8*2T@(xK1|d5E#gDR--#Opo(AI zf?2>iQD8**nBM1mD;x<~G$JLwl53b%y)7H+{{^LIj$zRML+=`$&`>(?-54 z{xOI`MlRyN^HWJD-^9wsk1D_Vmim3FO~9)J@Y(qjI&E~v&+^mep3GuDYl&R`u z**zTbyi1GxJx_z=T%B+m1d7hO8fruCov1^ZBR!fhyHB>MW6R50i*IIU#UBq+HU{nn zgz#VD%;uWJi5&#MfUnFtw2!IZdS)2hQwM_>e!+mG^uB|GSZz`e%2{?gwEv}+gSLj! zGo2&=JI?WyU90S2B%=>&xA*EDIsZ&4$7AbSM(j`bmIW+(POK7!Wmb~`!sTKuOx(3$ zYERTdMMqT$2)StEXjOk+*LZINmcYErhd2Gy8eW@_Qs3&Woi+my!S~b;jAR2;o{Mf` zLKltKzeWQ@oyr+XoXNrzl}EpExYmx{EsdRydre2Lz<@qZ7!YUZ_DDDZ1J+;a8o9v@ zJXt>Z4sEjKl_TjP4-~Wn*R^M^J5={+>Wf^Ias}epyu;ad80SeI$2#xQVw}bieGhz* zcJUHl`8Rn7zc~-$K{Q1(sCf>Zy``?QJyU@>3egL3Tg($yV}(g~qbK5GrR-C=zo4Q?1TH*W;(jMP##dObzqO=|K%=z*x`z1ai*{5}HZ&Sk06KUx`DM=R3ps`yz= zc;Rgrd9t)UH#u%L(e7fl&vz_(3uekMx==(Iph`1Q$JYMVRYhs+F!%JxUiCi{9b4L5 z-x=CHJOYq$Yg%`P+hqJg&oWs=M!$_}970bImJhq+dgk}rKHmfGFN`%iqppj?&b6#X z2$t^SpmFTW!dXoB+Q4?JWNeO#7N}@M-=ZyaL83jn5bB3e{r=hd%RS&gJVW13SH!}H z*AKKJqJoK+%*t?4o{@H0TGQL6AvpW0Vrki6MN0Hbc9>k@+r=nf^%oUVvtn#~-P9z1 z!e(~07Ugef<}bc~sY{Y?QKfn5{c3Ecu;YR3eCpVP>pJXfcS5qB-e4vl%QDs@)Smm)Txd);QdEo6d znzDA|OSKu?lkGgisEGJR7q-n!9)Onsy~%i1esxz^;`d9|G^NRit~#YlzSi>n?r(IX z(Cf!}+MSF?N6l&uG^LB9g~^WBT?#~l3{b`I=y703#H&(@REE+#rz1|16GH1qw$yR9MtElMeJkhk!`VFDW|~$ zteP&_Rt-&Y?S4j(&}yM|Z=#Rpq2D<%>$Dv_cgPQhX(yWa=?A=pX3-c>&Vk)L7%*!1 z$;W|p2uWhn7NVOU4oXVp6 z;2{u$V}nS;Fw>EKdt^hB*UPcnpz8E9zPUvAKOQv3Vyhq5rv$B8PhAxQ6igt);%vW4G2mdMLwF}6XFiJjU_Q`=AAr&8Af3Yo#<7|O`D6xt zb;DeAYtM`9bikB;;b{^W)zKh*rK`ERtw1E9pNvPh`DL|C5zdJ*`+^@4?XueU9@>W$ zlFz>kawe{Oys)4qipUwzE3(4G-Cp~nQqOQh7t3#trN6Ai=B^=_(r)4L`OhnddSRnk z!0Sw3c3;CzjbjP9#WkAS><1#WZM{im zjm^@}R-^X^4u#5SPf72;LlX~mzMjbmX3)h_hF6cwpwYnNOhN7^{;gBJm&HB*#f$|0 z-4!BuH zp3rt@J>x9XRi3psuXRJ6HjX!uY}ynSUh;I}xhyUtxm95~2rzexHkvW zB-59|0r8lsOtZ!XjE7}YNY-d6>(9t_eV}_wZ)r(3Sv9hss`g@ zOEgaHzZ~bk4-mOCkCQxa3%=Y6?Mypr6JA_Nm-%^ZNH;Bf!56PH@iL(I~0jHK|nfvftQAreNnL zQ~ryoKW3S&*Yz+429TgfM8bpOHN)2dwfJurTEF$C?tghqaSf(@hH-wo9%3N;YdhM= zOZbM5rpxu^%xn)?AM$ZCL<}62;2zdCVnhPvWGBN8X_<4*+*plpybr5>s$Y)_3a;LG zD-2*+-N6IOPnuawA+z2*1d?5%s8sM_ZkV!R&0SB0N#^qKWjrK_F{ z^?4<~EDkM`0he1bNSDPwLlpHnJ};|~l^z|lQ}7Tkh{g`qtVfTi5zf(+Ff$yP$T}q0 z4~_V1f3q_X&A)GDGEZH4CP$e@G~!M_8NX80ZYHoi6<;66QDD=1J?KFK;wAh#Di2`n z=|%XGoSNkN6m{w#Ntb&#qSR&r*gEs&2O2(vmh3yTSj_}F-e+PuKo_DRH51hjvEZ?`zD z+zkD-X2Lt^XdCU1vBM|cQA&J)Zzd7jpV*C&V3o7eKzrXq9||x>d0N!IaU3?qBkQoO z+<99|rW%OdEjBCS<#|&e1!1%2@t!x~siZs#*2}rxZ%S2E@p;>mcvMVsVYQ7OM>lJe z{u|X-3I-6~%|_p1J<0pYUI}}P7wl^`d?Ilcje9C^#a3)W_T4mYs{BVA(ySXb`NzGk zYy{2oVadXd^!v-lKH9`jW^)hi<*9{RYO^0ORO^Mwk$pdgUE11-je{qeGEQ_rB&}1N zkv~>AhSQSrRg9jq7#BD&YMI&|vmpI!4Bx=i8@=Xw*3S6HWD7%sIHvTNFWeg`0xDGC z9>?)POAq5w?pKjdu!^o(MUb%KD~9L(qmIKKp!|n7%UU7`Io7<8*6Vb5#9&c&=LBqp z6&^Fl9OA+)%kLGhRjY!~i zP=H6+Tzju$>;6>BnVw#k@G?0}+I*1SVHPc~>_1T3e=ECG=x31cGxj>xc<6MZ*{i|Mw!|+?vG`Rw@_5`4lMO0aTPmLuj3Ov;B8?FZs4tdgdzJ z7IS-I!-M_PAt%nZ0H4`K)t2%|dw`P&rx-wK3eC+; zAKYJ`gPG{@9ZRx#;hUR2+B!~U_^Y#q5vYWrci0LD+TdYX+pwEFNLN&Bxw((OiT|BO z`EmWr2>jcEeme7$GIzgCXn|a}$GRBfnw}n%Uc~P^(e_L#U=i~cwy|DPWc@Lp@9UsjtoY3Ju`c|R>Kc6l1IkegoquX?#%kf(GshtY|T3p7~r1+D#1NDG3B`h_Yg`K;)NdNx%MEs zN7Q;d2Sd&Z54}+!K8h}Z3TIT+n}^a`>t`&kLL&}HJLQjX!!h{#pdB0mFT}0vx)>gs zpLlKCdc?}Xz^i@B>E(gZ?_RBiUm4*-;+x=SsSeeG0c$LO_h#Pu__8(3@8Sjw#a)E~ zVeoBstKHzchfElNW)B0p)xo#cMKIu=*n)N`+i(9$GIGz?Orp`Jg?kepNAM4MF{ zt^Nw`c`B0a`3Y3XX`peG`u7i ziVq*wIxs76mkcGYed2v$foo5;@PKBk?7hwZDFpvh8QzTF|7Xqo_y-iLmtTm8mhZu3 zS>C?`FW?G>(6qsEpDiP`8(O$Lttwexr6b8c@UnE<=h($ literal 0 HcmV?d00001 diff --git a/include/javascript/yui3/assets/cheatsheet-thumbnail.png b/include/javascript/yui3/assets/cheatsheet-thumbnail.png new file mode 100644 index 0000000000000000000000000000000000000000..4d10465a0d5436bfb5ca654d762893ef1f0fda36 GIT binary patch literal 36189 zcmXtG8ITDk-Tq#FdJrKCHSUP8LN`%7QIf_&CqsvWgTs=Qkx&EvHUdBSsK~(Yqb8mxI5;qztc0kB*N>xi z?*xi@|K0ntKNWS=)fJ~0D_9T_3MAAsqPJ9h%(}m^M?UM-5#4>Z@zYny_D4{4M#3E*ep zy0qvx8ckn&YF~S#cEHW#xrm&yxnPh<4AO0d&)BkV6l?;IIR zM`9&B&Rd|L*9?TaVs|^rdL7I@M1|cn?s{+Ych&$`I-v*_0S~*2IWo4l?f)V#e6);e zPkyK+s0~vba5}lKU{$VC)nS>QrM6mAZzEmE+TriKMTet)nw4J7=J&&SRiml<5XF=H z>6Z<)h{(ncU+pi4x3#egYxnKi%@3iZNo}p)?_UHyjJjT;1yPldRVjXxFQF2xsuzjk(>2zIjSsbZE5+N{b%#3(UEk zFhuy5Q*z7cdQ5gNMx{7gI)5lZi)XIe?@oDe&9_O=rus4VLy5BUgy3VD#_(3%CyIgf z97L3pW`6=#Kkl|99==d-ufBV zwOklN;qEe&Um@!1>X?{U$sC{-w|&~cr-48*M zwZQ9&r?YM9i}AUXR&WSwn2u{q<*;&nvbKY7V z%pT5#k3!>*xn3c{&zr(Ksnid)lQqvvHJ9zXxx3=j54h>jAL>kn(oej0LwHNEHaMoUKn#yMF{0@?HHyY-RHluEZqmG+@@ZB>~Kb(E=+n0Y$ zv=X`?U}YaYKNH7seVBPGbPdhju?u|FG?(0&4|wL84C!tQ$UlXLBh8Jt!G8QP*TKEW zzxAbp)_$p0*VK{e_soMdoWMoPQo6e-vNNjvzwSSDd z`?@N26x?nTa9<-VUp4tt^*veBH2geq;eQf>3^-qoS@ zuRSJ0FGI=~7wJ9y&K_pWuU&_lh)NUkN`=R zr=s`J^+@EacHH#^PVjWzD`Ha!40gU6bqrpOLMDVBS<^X;L~-f4GC)T6!-3m9)B(sr z>49hdRDm04whd%u8qpC{0bhOE$1|WMcfBP-eRMd&-wu5Wq5EwCnWuT7+-pmPUn;2n z79W#e9pC)K{X*}eFV-|v`8z#lH@jt}LeEfFRMnhbHeahMS%yJXGu41wp0iM$o$%Zs zUV519%f zGmJt?bs-($lBHJ%U3h~e&mDDe%TnGo$Hh`%6^QAJ50u#prlS|?2GqW!TN?_{9YrO)0+ z2IHbqASn2it$bdp%7s3(WCg%|$y$I_Q9GE9WCgGYwGd8Rt|Hyda6A!VX}4@khKD?~ zxzr0+pM67kJuwpOf20chLH*|n|Mh;NQ(5HrLDgt3a9-w}_WfGGqbF(vAwqE1dq1(P zpkU>rn;ONVu{nGkrzT&jCVi=;Y2UUjbjhA!h{>K8=>UkYzNK`q(zImj};y=Ac zC5>d+i04)F0^3?Gn~U>;=SpqNYBp`z2n&d=dETTSjQlej58BgrH2#{#aEp7Ee3Lek zJiNG*#dfnShpmGYtaKNsDJvnu-tTp@h}KX3&Y^YdTyw<52HXp!dQA`WDOoQsrHqbm z*Ir&5&3?&mKFNi(?myKxH642~e<75$k4I5$R?@SA)>Q>`#jXypX(eW1QSekS=tpAV z#+FmGFp1aIbkl&F3}_aKY0TS>*vLz163yu)X6xSWl0P-g6O&S%n362C4RFLThGe&{ ze_i_IiJExrm+d6hSIYl1D_;hmmfX+D zLwm*05lJa^lU2lNX(Z6yldWlG0xRMc+)6ib#R}s>%isPmD*M;GD(vekZyHo|K}1mT z*PRPyu)FCI(sX}VJ0uG2_b5^DH8ic5xxwMa_~UI7SD#MI$HZw*thu!DV>!eJx`Xp_ z<8D4B-0$*~u0-?(6DEl|x!6P+ejH-qdBi8oo-m3qi4k=CX7UFC1pLTb+SIgqIoBz0cNt1(0B_gr2FE~z!F*GDgpZZ)mUG=(kP#*r3oU=3em!R6;c8jn2#ljzN0 zL`n2b?9+eU6^E~B&z+FxKbB=_{?$W}O?o@e6B%BuPoPjA4rXqyjsh?1#lM~sCehcY zRT!;ddr^>-L9?%53b+h^ZHbF@#Z{kbW!lD;j!}Q5>4Wj3aMdT$w#`&BNk~F#tc@4H1f7=OVs3@+b!3O+dDK~X9til|;i6zu{d;{{ zS+j6>rnurH9MO}t_w`}mr7b9?Q4wBS$Qia$E0^npvL|ENJX;Po~zem#!{KZ?FY zDR<+nJwg?faea*ilH4K4eE|y~+dz3Y!>O0V4_y4w&A@ zw5zCq0}_^ysHf3wyhB#lZ_d?ubo=R`r5|>#PHj@~`m+g2MPvMp1g&fhO*pjhX9mPj z&QE?@Btr@~+hREqjvVBNhkLC`%E~FGwK6@NPL%Vfb4X~g8yQ9diuO}x(+YV3zf%+1 zDds*?c*#WBk`K*sF^7E3CzJ=?aTq-Nwy&Q|Ft8hm_x9%CicF(ouRr!P-rz<_4Q{*i zZjutEr|lgdi$Wp84P+G+6ZPA6>M}?0u#huI$eAdjRH`&cNcN=D2whqzt}R2W zy@T`@S*dceX&$=oeYfpxiYcf%ynC;_4OE0r_Ri5uDpv#eJ4`Fnm&?m%hDzl@ttICww0Q6z!_H(Z@|4);kBEa z3`EttV?K_wfefYqREjYR!2I{lEJLa!K|U4whf z^VJ6H8+|bgX|c!6y=Hhh5C2d+|D4?~>V`{6!FlZ$xqhWHDYhiTET&-R@IE@hQL#gw zYCskhlr2c3qc|T5SWCp4)7FMl(ZteCMB6vvo|~Wi4bG=mXCrnNjFh6Y?#4}3LkrT; zCYHy*U@jNqgO2q-kmVdE?e7;QOeBw3$`-51Bz<*&{rKb>9{d8#Oh}O$njl57Ruz7f z)V>`3>I+)KuiB3OrzgJ(NkodaSCU%_-odq}StAn?EVqZetinB~>MFdv+2$Tgy zAw&ZX?UQ<(gB|V3)_Lro`D?@J-*nZL@-o^8M$eGRFmj(4OrjyfiZNDU z%&I7mHkU#%geWqAQA^9^z~JAXyU5O~*$-yPiY+!;*nJkX=H{u#Bd34<%Iu>Wbsl0tG)HTvCScKSc+eYR`GM_&E zV;d>dxaiT{-5GxB!EwR#AWs=VjyXifdn-~!T4LJvqkXcsVge2~_5pts1LT~EMX#G* z(uM+LbAxK&5lC^R_Cpk1T3FlL{UKzEb>zC-b>u)KnK{IIIm3AgilFxXiim=(!b*fE zndsNiCC||@xO~K##F{*A&Y6j&06kd9wYYDkyjyr4xa*1#dg6}X<&*21#Dio@&_?0c&p_FsOS=9@TcAD$lqLq3FIY=A01(afD_~_O6Tn~-f3!S zYmrcrn>`$8=De<6B8i&-!74=t;sZN&BKG2+HDh}5;V+}js?A=`Qt##S+MAMgJVd92 zo!(&ffV0!?w{zFT={JPw2heb_?Y1tlO!L68kLqyDa&V%U_tPVGrX33WXfDqK5nvE>YkK?dg$8l2CT!c*LRlsaEZ#kraq*zq_h98$Z^Zx_fTf z+15d)3bL6yeCpwOjf+}o1IF3oOu@B6%II;rJ~|4Dk|1_$zb1+<&u`oi@bUF6ozK#! zumE1Y+pPbyKPv~DStfV9;0yDF@GZqa9Od@x{AZMTx}R^+{JPG*5^1A20Tbpr8Q@NLN>%DQhf0LJSiV%X#O@2BP@iSVro;=NkPq zU{PgF(=pVwu=EI*5a>@GNymEwFA92_Dpy%utyVKzs`<{ovc~n_zwS2LYnUi15^4k; z@Cg_lp~Wvps(t)y4>i_@64rj$}CB z;$#v)7A z4{eX6f4b>H)Q|J#UucYV(9J%qNEx9_E%L{K%ctL1P}*&_ET}be=}wg=eyh#0?0H4P z(Q$?_Br#9fK-v|v_DGfNdpiwt8RdVjn*@Zqh^v1-dMo0df$^7d{z3%%C7USsVpDox&a@W;wy zAWwyKW0!fByMB;K`n|nyj956fwE`*rW7Ds|T&P~H!9CmJI`Old8K~N-^tMyejrwiy zN@nWrfR!QTaV(|@8vh|Qc6P>j?E~~ACTZ!~gS)PKdAL|TB8e6!f_~posC-IYU$QI7 zvtY&_;FHT{(l*U?MdKXWOR@xW#}0YuKK|<4x>ItlFKK`7JYl{t@;R3r&lbkHTiF`> z=kwV&3@Gx(+uh@&3Y1#Zq(BmLb6P45;A_2DxuPRj8C&vwn0LpGXCRJnc(Aeq=+c|< z_T-vJARbzxRNLAbT{`%$nUeBVtJ&?G_CDmaS?Wy)6a=k48r*o%v0Viun}%yolQi%u+DCi7YK;%%@W>KmAtm8Y$I{mx$^$ zh2vdk-VYWPe*5#3CTWN<%|e|$LY6U$m1B?|O89q*B+Ul=#RvALJ22UBe!tRDND8-i zTu2mTlM*x7jT`4cC#PoBN&ik`#DWzHo=X+Ml^h0=rBk!(>alfOsbgax6KZ~>_ceNK z8s&EpxGLYEvoq%OiB3u7SMb!GyYF?}E-sQ-7=Cw$iCF7+$JJ*wo78Pd@&X%|iB0tC z!)a?I70rmyx{%!#5IS}=EiR_df(M)?p)*ArUA6zPr{ztXst@*9PKjpJh!S zZ9}3{EUI(sD-Nr})x)2yXZsT*yn~AbFN*7AnC?;=Ni^f9eNB0zQdjxY;QOk<@8r+V zjm_^g>B&y>YaAmlnUtLlVzu|lNeVSs)mT9!uy&N7?LKc{H48nC7{UEqw4N5`9egs) zo_|@V(9`JoMPW)qz`zX8_~DX00^1S~30^S~O=`0=GaMYbrJX*xiMFPZI*}jd_S*?* z-nlHzpWOQoe_zwfO$`8DN^+ig$zv|R7C5tK^N$p{T1EA5R@PMhd=py8wer0-PscRmZe2j_?V?Il1%Fimj`v_gkdB(l-NhPtv?_DG@0eUD9xR^w5%sC89< zl)E_P%GWP~^A8JA!WVR|vZY)&dlxqy)dnpR>7#-ZRf(*u`1pKjQ!OoQ5?|Me1EWm2 zV=Q!$t~q1%2Nx?H{%+ z3Xpvi+9EE}$|y7m-MqG%&Vq{+^f#?ZZ*8|-b}4{C_tgP4{+K1=2qe+`4U8L)f%KHS zRVM~6Zqwdo%Om~esy5!B^#c6d^cTwdB&vTwFvn-U_0;-Ks-!&z7o^qD^H4VSDC4l~8dP#5`!g|4!^L1EqcT z3}M9r0#`aeoGL5m#snq~4cs7!^th=1?4!9|DI;VIHoFIq;jHzz<1A><;T50&izoYN zL|8U&%UnJj24(u>bQKUn^W54>gPMZzCaK*Y2?73VP|&V-bIu3>HIP*8%wUX3h5y#^ z6zNG}zMBHz;Gm$xPdaJAtQB54(yZGNlT?2HObjNvF9rVAvKvgav#E7bZd9>8^Yf+8 zcQJSNRj(w=)Wz69qL|cmild+|oMC@W{5A>q^1ux~p|O45A?HYjZ^IVfrIV0liD-c& zM4;}-p0V#CLZU@Fg?jAC`bKnfgwj)xQOjhrc;RmOwI}4Z8-=9ND`R~kU@TyCBm{(v zj?dx!{ixwR)|qjepCBxRDLr&Hp_Nc&x!M0 zsqn05^^Eqsa3P6hY-#wo%I8dRMv$qVfte`N%ai57AXBJj(BTxU!Pw)EBlI_8vqrr_ zYw+soz3}EEk`z<5^Znm9*wk&g)f$=90=Mz>P*QA)miU%^JDL2ih0F@sg0WO_xUrtK zb-!g=G)x0_$Ow`jbv_&X)M5VRyCyXEUq_N_?C&17ZrH|qy+dAF-j9;=j1>4t94N<< zOp_>=IPuWl#4I;cPH1X~hP~?ft*?djVv+S(obFWb@dfHl@CC6!Ezw$F=;Rq?Z~s(U zOXHw{Y(M8S*)`d$3#o1zE<==M!J@8FW>&$w3<+EYvDP?RJFluv5pd993lggRbQofD zPAD!epP_LOoKi)l|ERmK_fK_c%*f^(*r)1emq_^9`j;;BNJ9!dG=@wUH=hS#{qbKH zLYV7ne|LFyzGyPutb|TkC!Jik{gkR2e;DR^78f5iY!9&@yTZar-aoc--XSZt!J82W zxqJdCTKHRJgk{*&9oqG_woXD~y|~7%ir%u0m^!(o%=Sr&t#j5@f};_li>FFw_o=CN zMzb6zc_0!6TDNRSX|f(>p;PCA<_|s@xjB~B^XzFmJ5CfRiWo_TMhq0OG|{wml}=~D z5nmFnctV+@kr4hm;E2G~Kca>NRobS+NRl=1*{Yb?d?A{59=y8QY~?;T&y?RCH`Qkx zlL}4klT?5jujTb@anC&y)0Eb>?v-2^wm4ze@1uOrC=NE$?M=3EIkaOPALI1?hr2F= z6y(z`SCmqsSLM9@*E`%ZcFLaHA4RcBNd*TOJpX3e$nF|##<Y-dc zN^?%n;Fmy_R?m9rCp2tn<6;JsHr3^9f3b)K(3ge4 zJLZyAFG|Dt_n4s?#pI%(3_jn?M{56X*Qpk^spw-;+0PO22r6%hnw`o;iquR_yTvQn z*?)C3F4Z0~eps1dAuLwPrOh3w^IZ%0ZJgl8EnlU!9_01yvP3ya-^lFC152aBheqEd zxw64U0!J>s+N|Jp)f4la1eaP74~P9U#tt?I22`My8SbMkp4!SXx+lL`^Zlw;D^iwV zW$pGYX7^dQn#$)%7D$Dt;bQb3R#?X-rtBf54HOdLCY(I}SOts5PF^YRh&jMRT%mLY zGHlmB1Fa)XJ49M^w%XS2Sb$@DKHptNNHti90GRRH7!?L-aak9ztA{Eq`xX`;Na}I) zoKtsvV~&<+`yxE5okV}YhB318&yxN6hJu!?gWtbiUU0*EH5cw_v%-<9_I1)h{v8bR zz0)Tw?;H(DwYRoXsdsJT2(se;jMQVo(nlKt{wZCsP!)8eSM-g3WN(T&EY^KPb`8hDgSeYcN`@MFm`XXx%zKJ&H-Q($u(zx7M~m zmC{-rTFDGV_bGc*{g;2Nxg+>d{fQP)8jjSK^--0~gFK|q@*%z3t|h8jnyat9&C%+h z|9b%l{@k^n)^c`=6bGWp-WVanE@r=boJ}eBuAlJ9tjwO^y`-stl$6Z!juvoGci;p6QNI z7qW?jD~Y42UdwhGz9}#v1xg+FX!u_AE|mt1Y@GGHR&VbyJdgW^*Z%^k^P!@1+N121 zR>h=3zCG?#ZB1Z)ux(c@up|MLx;)G^;lEjty$}zi17H@AKp~}?EJwnADbyWz6zzzi zB(cc%25AcMj#LIlhC3xfuQBF6DDb@Z2k$gk2$3VC_vDIne`MtuuqMHDn4r)YB1{@N z+UWeGQMV7i+xQK7vEA!<-z<}_8#Fx>k3_Z1fjJe~y8$@}=qRR&;&i`(_#=kWtJ$z` zPpFh>0PyCd13u?&Z-5_hwn_5cl(Ea2kP<~;vYmFdngatzp*q^?>kI+EmhVSq*NNa~ z2{Y%8%fA$HDC-F`vW&kRh&2;Y!|92%%S+XQG)1GuB1XdN>m- zT9U`;hq$iw8a6MuF$rLekrMebb;~yKGLT_?D-+P!;H~;zdbteq%H=j8ghL<049!_iOaetH@aTD}%)S@bR9ldb zR;3J8YeY8gQ0flP4y9rubMayIFt(}D%#!B`lhPV})cwu|C~5%p3{J=$ohpUsow%o( zb48WgKn}3b!vyvfc%|~+li*SPaYZU)TpKrqO@LXLPhT z?&-~78Hu)5KDwQp7twE)p(DHFE@yl1^9|9oh=~&j3Fm7`DRPZ{4iG-1vnP(;4OOSQ z;7MLmyR~c4&7~SoboYEU3;4bGkAy_g$h0goa>}iAmXa1PquUVvTXCqxrz3tZTw=6= z%QFh%kqc%^VqT}KZgL9r<71d+Pvd5uG*w5zCgniUyR!2koSXcJ+k9rR0oiH$CF`X* zY2B(!nWP|xCg{kP(qH=`4G~R3F*cqSi;Th#D*!8k@Axbno$IAiqY2>hY;(k**Q>VI z47I!B&3BME9Y`9_%<>febjgMHeNz8=kRfiR;&RHvHC(#SF)kx7`2Stze z?LhT?xuU4A`Jhn>CcR4?CcTF`6Oz*M=&4~fc0zQ__;}azBi;O3l6UekeyrK+)GsHF z-fK|mje{9boEh{3XIB(;huG^Rr~IYsfAxfUan=V%E!1-S?m{IQLcW|amkvO-#Ki2^ zHDJcKlPoFI`&P=3IVr-3hf$BUf$lLBi24KKuKkqn1N*ENnE;lQ-e5!&uj5&5cmVfm3=@{mqALqs zLni!h+nTGXPd`_DbTT9#XiOx;QdHmDKQ{5O%#o(@|DN+X@Zu*-hO_zIGGT4!<9whj zCukMF)Erl2Whe1HDtM77?NF^6&=^Bd<6_BXRL_4^Y%2-ExVjph2?^^p{{1aW9;_B; zYg5wD^g1~VR1W0oo~;OFSz`{{HmIaHzab8kGCpE z%#Bj1(>{4p9HK}7MI38T4asAh*Ke{{>U_d?(dWY#>G6dz1hEb2Y$GTO-p{N+Tv5u) z&jF37?$2+9Dm}>*df*-#H#b_j0j6hL^mk)}7CK*y7Ev%`i-p-^446?gG4cnwq6$wn z1zmSAfv2G%J*=-SHrP!tauD-SF|?x|QRr zLa3jRG(G3xNmQ@rrvan^pVs@j?uAFZve6=lu&saNH4 zeE{V4m)pxZeaH7a{PHZRmZtH6p~v0O3zuZ#&x=22enm35C%sQSie7uhigQyPp65rT zs`<<~OHR{P*MEYSyl*#Og`1&(Q(nx;|3SRS05HlB5fj7j$=$WYwHU-1u*-Wg_Egk# z^dHu=4+q{&r+?4Qws3HWU0tPG^?Jq%I14>B%OKLTGxoXYMT=YZTr%Ni5DL*pecb8$c%6$$7p?4hf_7P^^II?&?R ze_RN~`PEn_R!(>Z4H#^6fX)^HdBN{2O30_J0FZK^S55*MrC*XqctlY1-m)vIgUN0N ziD@VDlM0}FA=o&R56+4E}~tp}{G_BqyGo+6-rT;%JmLpBX&D1%=K} zUZVmgfet-_SYt?LWo7l{WDm}l{lAXkA|eZaM1Pg!o}KY-n^uJeVVOcXLXZlOD_>7&g$9hxArIp02q3Dd)?+ zY^@&otk}b)7!|&L>oeex!&mGAPVA-tMsXwi(Zw_x0hRG zCcKEum*FKlMD06{Lgl9?`$GqW=~FjO@Q7SV7BNEx@HDa zT}Yo=t&C%!u#e2{e@4KZT z$;k_8V}OPUg+iADU!VV+_mfw$vc2cr+a1vJz$dSROeTW+CQK0+`(9 z=4NGOr5odTEh`4B^|bNi6A7joi;*%UvcFBn{q}?V1ClEgT6M3?b%lkMd~ni9voC@f z2^4DpWyAgJcSv2V7e$I*)GEtbc=jM0nDMPlp++Mz48(ZTpOH28!JVyh+wZvyw;gd? zYx$cpmmq$TYK_SZ3%$?7+Z}E`S)^nCSeHa&h|>G??R&?7P~Q{5(ZmSqV|rGAv3-7; zTf3+tF&w;ipr* z{BFaRnZQGy&Y9Zi-vkP5^9(;rOTDsFD#x_KrCKC7$qscOL2QRSq5Hv9PG#N*aurPW zDe_*T*$J%2UP9fq&V3H;QD7A=1%z0#Zfnf$S{rn=-5*(pM;d{TEv)nH+jXin7gy@a zmy-qY7aJHH#?~e`6ue?ZTLk0E4fwc7cn%Sca?v4!QRzmeKzS>c2pN%QDDUHgx>`Iy z`KBa(nRVD_LCoHVsSVK=qLU~RFoE5ZZ~*SfT1|i+F%?3yrDYm^$OrUnwO-%!8s=oh zob&@6>s9G8<&q6`El-v-|0a?Y_}&<2Foygau*em5rf9xuU} zgqcwFUVb4jQ>qfOQUrt@_wzwynvUl3=r1R!n%_&mCGdQnU77qV2fsFlZ4$&S$F-axt03Bx`e!)3J{Z}x7jpObSJ zSrMJB)iL>RzLUhmzrUes6-sYrWO_>^j~W6j7DyIy!v<>{L!EDKt_&+W;M&j{+^xHc zJv~8sLbR`}p5%u}(C73zJDAG8exRYEigTcmMNjDMDR4CZ7CeRaL+he%$7xkMCt&BH z{kK9+7Gm$x`rqT;xSN1B!rO~4;jgQNwXk~A>ZS`MZDL~U89NP@)HLmp|7crzxy!!= zI+7g8B8_~@nL#VX7Z^spgh7Oeilw&W*UKG3kRn~Ae4!_O}M3d-+UNRHyRs$_D|k<4b;Ot3LPq|rdMF`;OK1gI2A}Z{a|wrRJPE1&5mEZ z+z{D~zL8!g+aqMG1=o zA|lwT+zx@G1L!jf6W&#+=sXc&M2Q>lX)>hlce^`ejxknmatZ)sebJ!ZDbCQBv23=y zl8t?%nH_*qe%vDf&K0X){FyL9JHjQ1hzN51ME{?^7J#ek*56+8Xp}l%$PCLs>yg4( zy${3qn~yi1Atf4YgVRSJ%|9-*Gy(QH0JRd2|1br(956|Ub}dO(KZb*W>5j#%mA2Ua z3PG;t{O*2Vn*0f3VR zS$y%#@3!W705@IE3p|o)zE;`U@_9}E8*zba0^y;1^?{6bm#84H8Vjg2CED#43oMIZ zxR067?4CqsF3C`O__Y9UJezmCYmj+JtGKiH4L=%Il*Vu_Q?bF$LP5Oq!?kuTYm7#5 z)^+N3T)CdDqMhf})PRS^#Om8sLX@%N;<={vbsAJ!LI3A$iO{1Z766h#`1-F><$*fc zg6s#sf6_@XJjIBZmd1mRuTD;u+0L*<-C>2sFazxrNjk@mg6|Ur%v*KL z(Q@^R#?D{D!*qq|wKO%aoB*KLwe9NozS*ww62Z}tZr?CTDv8w0T;( zD4><&$1Db@{T(q?kU$2`2vl6P!zH9A{XdWnr zY{T2n7wEC$V}_{`W?270`9T)R*NBA$r7vZc2_|bSG1KqJU@a_bhBtbJ`3Z=0v2CIS zDAULq!(Q-zYJGP6B&65l619xJ~!j1=Gvuz!NAS6`+$_aKW2IRnvK7V z94K+nmWqYxeURy}ohH{R zU0}zP6`3ca=MUl(D+Jeo>nRw6j6T9(RoDi1u zSS4dYdrm$Oll}+NlUSFF4P=aZ#!x!i-QqdYqqv`Y+*mz3SBn^<%0`SCa;utu23El7 zDQ@Zi|opONB(L8XgSZ4&E7D?Iu=s~%@$`SP+EB`yMJ zH=vjOnm^+w-cy+etds#7bq$Kn?i@nV2I;kI7+< zW9R$vn9x!s=*o(8{i6B&0`Ij?tXl2Yd}btZQI|ynJF?v`AW4&eFL6LO3L)C;BmTTG z-G}i6nqF;x2as6c}BY+W+Yh~p};32D^V0+>8%C~RW&d0-=fFm+gyoVm&kT*`c zvLZ%ruOQg1N5G+U>|86xfoqU9pt4pL4RGadI9&tP{GzkVZ=wA|mz; zms&JRMI_;;wir%|7!C*#iB?9%z&SYf%^cie(8}Wb7-#-tL+{*F-TjrZLp2M1jkLM^MmDQETx{S%{>UYoR#rt4X+VH9K zZzX9&>4TW&3G}3$Yw`Kz_73*H>eazi%DBq(dmfYs-MBD)eZU4@unJC9BESqQy`t## z3lXW(qalhfXmSV4o@fz0s~c-|tS(vP-;4Q=7nX*n?B}8+mgAhZ_V5C(3aFj8&P*6f zO3KnkbQ+IM2Ic!GP0#Nf4s-P>uwHiRX_ed0@ROmBcW3QQ&1c<@-@YlH4RgE>8#Xny z8ggqBlaS};%^jUx@}$FCd$LykRAj95sd+BnDz9Fp;YL?X;r;DX*OJ_$s<2{eS0F{7 zzo9KL{zsr^c-h+$hgy<=I=l1kU|694Cj9mRijVaa49+y#5oj+zP*ffzmxMnA=**d?sm>z0fV6y0?v5i)H_7^uTwVo8WOR(0b}r{W`KDk$DVb_RL-`EYhuUvAG}#@XNHa6|)ja7ILZOZ6ZYU z9xPaDWuR@_70r)Tvno&U`7}I~#7f1#vfRhB`3KH72V_g2fJE3oFz{X>8Dn<>@#lSL zDX_iaGZRq^%}BMR@t>*!IoiGr>|+l=QVi0olHkAV5+roV8CH z#l%OKo`NZwMuDQsxwyE*%Jepmn^tL-K7?s9tWObObyd-hQwVIBu%AcF`pqstNYxk_j1Jkr5ir0MkGIAhR8m`gtHMrX!;>`_ z{S6#_^vUaPTq5*1UmAjITF)FUQg9+p&dqH9ku+;2iV+zPiF^biGcoG(h{KC54H>(x zYhvSQ_ssV^B4O=t>!8IR3xn`|6$^#-Ls8dV6d&2B|z`0+%DDHTMhtBU7K zShxJda~EUVukKt&iK2?jd<ce(bK13RwQs>E}$hF9n ztXTT2!7B+}ZYXm7y(Rbj8+~O6t~L^wc(}lyl?xl4#1&txjb|Y1#YY3Njq`N6k3X_z zW2!JW%3xYe@uZ_h3AO6s27iNvy69CBM?&SE+YvK6ULQD zq6c+KnK~hjK+uq$_k2(^p)xqwcuMr7_T0Z5VB+wM$kMnBcs&qcXNmP_-_Wgev(Qpa ze8b5I>uJF0+^{Y6^?cyjahlHw^{FEkRa+e-ex`KVw&52W2K2W8mYrzACf1?&*WsLIKb|b zRhbEYIsfuy@5#XTe_P^y1P?a zKw7#)+9h3)Sh|t!hX44U^M2sVo;`cG=bpJ{=2sWjOV7^w);4(oQps~P85z8!ueFU$ zA&Y;?Q(>5v28>Yw(ucdQm040{;bST0BpRpi9UZsJx2Zzc=$BEH8d+LXPgO_fsN z9p6|n=|ke(vŜ{V<$y4`m??YTV!CIB&vYvEFxleyiRCETJq0BxWgNjew!C==g#8HKUt3*rUIN(A$i@SM9!Gx+t^_~ax4TF3=x zzELTPs~2GnMe>J2-vJ6V>a*~=r~CN6+jyy`H=}g8zkw?8r@8(wccu7}*)Pd5Z5MwI zyRPv8d>mrqHZ!NaRi~zOa$)q40Ojug`3rAfGg)n1Sel1&>qj^h4rZt|A1ToJx`?R$ zbn=J^-JL!n5ggtlrsy2i3fRx*78dqcy4+Aae*dz4(#icju&BH}Ur#1~>yr|C?VXmM zCXxm_m_XRuikNi}d9qx|j+!aznxGTwoxKZ^#{2n`i#@_my|jFhPGV#rSqZ zSM<;=HQ*z9tYgOSdjsXAr$r!(qPL@gk<=JGyS&`9To)7~0|USCitv*|Xt_umF@O*+ z3R){4y#6^`lZ=Flkvx`;ncJr!)LyR|QeWtF)2~%)4@-7-`127R5HN&hW}yDL24Ai> zvqgivh|@kbo6Q=1S{!t5zoE%U*?4?}CmFtP(f1y+!RMh1K`KR>=YPbo=_my?&ArS+ ztnz#hsu37L@5|scc;9B;H1(fy_@!BojH+L?8IZ=JPG05uR@rA6Y8Fvd!eHjywD7fF z{Z5xuWu_Q=A#wpPoWZ);?m$tb;NU#cl+8={j+^!G-5B!*L0MuUvLQbXyivo$X5bAEFQjRKmFMmgqKxGJ>RTKtyFzup zP~bUT;jut&lOhwI31fFG6Z*QVUSBdZIK);MnVDLqMN@TsD4N{c=fIC;6u5lw9XSyF z-WW{;&UnRW;j_M1oK*Mc<2cYnWhR;SDF!?xA`h$$R#0Z*9qQu zx|aB*s-oiOuOH8dIC9Kvydy0;2m1Puo9uz!2!YVc5jYm;SA8iL;h zTrF8G=bdYqBM6pw!^1POyi9H6yQ}ak6VtK#6f640X~)^G*WdnG1wX5^;GrYSLh$Sy z9nI#jB#=lJAD8_N1MlD1ZMm>=aJ=E-5@Szan^@@u!&Yt3F2zX>oV1F0!o&FwJNYhW z+bVyir@gPIw5~S!yTn)tk;GQ})&{*F`iUGHzI5?=2$9ZLw74;*BgrON|F)&vf8E_E z%LT5Ujg^?O=85LBWE9g{X^B1*-S9uN+6I<>wiqxMrgc8%S0}%B-BmN6g1{6`Ov0^d z+}J^FogBtQd6f~zqH82j3mQKV&G;U1#@VaAqOUgULjN8b|IS!INUBlwqT1E_fYf&U zrFaq~sDKke_L0)z&QKyPHGI|jNQSiOwO;nh`M6)0OKS{k>($Fa=ZxH33lo!1#!Nv> z`-Xm$mP_x58o~QHLVFgYB=2$($(R8Bq%J7QLuh5|6IHi|Zf2$fxbiHPH^SUOtg@I` zFIV!jrKi*x7#I>PGTj(P!RrAtb*5?G!qoJ*<+95r%N!N;YL%#4MgWh20HeWiDL_%= znxLMweUP#PjjY)r-NPZcg7#NqJ8|i!g-Pc&16KG&6hV70;|*sN;3GCyHX$u%|`B`25V z0Xtk>ZSD6pM#W`pWN>TQTWC*L7aUbu@(KlOSDxan94B!x z!hL3JgK6Es&)dNrNhghX*pm4mB_o5J?)!aD)>FPejz)G%j>4psSUQ&e_OVO1T8~km zMq&x#?GaGggJi~R3X9IIEidE8fJL8OwxAXCQG?FwKl{zi&9h@08JW2jX0E}ebwCr3 z`2wutqr2!Q>n?gZLVE-GyfCJ>q-WYi^UaQ7*G!P#s-!QxWy+GnlH1JIN ziF(B=%QCB(`8iWB>xds?aaKQdnAS^xaK3J8 z8vC=!5GxgY9QmA(h)`Qc$HdPs$CWDA!p$zlr5t*PRW!Mloq&3g1=kgP2N+CJvY356UW3=$F37-xLSd$6?N+q_# zA=^ln$V)3R9Q06$JdNy0F6+iDrurc2DBzG&*Pzdn;pBQN>uiNKSSM?RIs-z8Uc+9; z#9*#rUm3hzGERs+cNZ_922(m_eAilu0TfnjGMH1^t|MZ)fm^f2nzEP=HgU%6* zc>JHs{;uVH@u|`kOR^}na!i>?E+@F2C(Knu6T^Ayv)6JtyW4%H({)s0RA5+%8wc%( zn{(j39(+6xl;EKpY|^*%18(r0n+}wVgId;RxBR8Wi}kF^4en3MM|tm!$AbUBy+f4t z<~LCT&!`?m5}lCYJlguY45{)-@(f(|;kqRwLqq7VVK7k1yz+u-I&N5ksDU=fKi~YP zLY2(}byV>Rjq;J3BiZOw_kdN7PxRNr*YA(~m&#jR}X4#-8+* zGhQ`x-@OLqZ$%~qBvB1B<{j0pJ^?f9@zW>yFfAkB+`9|D%8!-u3JS+nqPK)d!M)^f zU5?aXdy5}HB0_`a%E!mUKq*2LmQ;-HyX*1e*qTQ!fTaMdja0qPzl;anmj=^yz^x+? zQ@xA)Of1juFM;F3nSz$ud>wH8hVMk2-s>F@xc>=J}}@-yo1M3`Re}=fzj3up;L&p|9y=ZCTb$ zbX4_P%gGDrcx9IK%!~|kC*uS)rFWqf<-i~6;o*UU9H~71l^5ih#7Y7iwG{{o(@}XI zDh?Et=!134X+H@(rWsjM)eg*oIy8C-1I z9ThEH!1sa-275_%Y65S`3Gt8;PWFa$BSl=`8p44b9mG`&T9G_r9OQ zDB|WN7>u>714LJ32u2UBK)pT;*b>V7;LtGJ=V3>?f}T~H$gzHH6mS{XzE7Nw`sMKp z@!u!FK&?Ce1^pnO5##d^cSXg@uE+I#;H_h1zbRN-oB)Wb(}rZqtCp+#9R0^x$mH_( zx9q#C>$d}gQgv+6=c8;tdY*t8sRg*Y-RYW!j*b{sSjWlV%DdV8fMji2lsJ?is9@%D zQ3I9p_IEK)jKpCl;9EEJT0sG_KdJ=9GT`VI@sm$pS-}OdCh0I57&i!sabsB1FcxKZ z*bq4IpuGJC?m4&P-KP|Vp0chBHcyuY_)2VJ<+;VWw0}&vlN;s#I{cZR*%WM?b;TPi zdUwC{sBK!d=GM7*Pwm{?4`#B%&DX%{2X9fEL^||$6;mwn`A%%LJ06)v+MgF(=`Joy zdGDt^qeDX_=b99FNY{3VjEbjttTPEg`5&Pa*tVbc9OOOcYhrR;J~E;0RN;8b^PkO( z{NX~p(nWGEaHE@IcJ3R~Ip4GrDVw9fU6j>vkrUMg6?ihm9e1zHBa7li1{53n7dw3; zOHn&rhqI^<7r5vwF$(P(+Jn~48#m;0bN6Kj7(&ae{cu%MhT@cri78I>*ezs}HuA&+gID&LI0BD9q`0uxaOKG0Mq#!@l?1Je8)Wm# z_4OD>nA7%#VlSGxx`+C7Dgqa&&^uX3TF1)~jvJ`@s1mrmOoEf)DH$}lynxfa*V4~1 zV*Um%s|F#4x9Dr{Cc8v#P4?mN;lBR>*0;`MEOrMk|# z0g%CC|J@t54bn&2YzivaOIK#UN!8~cL;}$n zIPefzR;rwZkVgX-TzGswfG7u@?HDXAhpTF6esWKlCdzOJQ)4h?c}Ng+YQ-)3Cj+0j zo1Nmj%b@JwL*EIRRf_XF2U=2OWJ8}xihXqjDHU@95^)oh9Kk47{D?kfg6D`GTE-+~ zTCQ&il^a%ie7Z~_i`LY`T;G&4jClrr=lMfTxl}X7AUc*#cI41Vahh@U@n487d>oHN zG>!i7C-g6r*(XzgM~{5(HV{N}0Yh2@zy!;@a^z`8x!4enMr)o!s@+;ZDZ<0ude z1RB>xo)*|2(&Wu-z{RWfPB8nIx6SWHtKHx4qQaLP^jo;37a zW5DVaXS2<8vrK8}+vBVKXvv0MiHijicPjxL*;3)Oa8YtgC%08TKAC2Og-^GhwsRYn zL{W0y{+WZtqi>Jyi^345;k+52$15tL(nZUU$5zFt;lnlioC4fGeMKMt%S1vG3CxN8 zuthQw_iN5#M<1a2zind_6$^LmQKhA9_{mtu4Nh6h2dyl*VzJI`Gygdn6KikHrxEH= zLcr~8md#LQnXJt%OTGQD+31paoT(FaO&-KFY1{T<<2|Q5WYgyldf|E^F-B{ZVFj;j zk!G3xyh-g~R@S>K<5g(;S^>}Af++a!JGW>)yl81z+-Uu%f3>{@kkQi1y$x5R`*0w? zqRtdd>WGh9EY)GA8N!HSEo#oHuCFXTPNsVJj`E=O8q-1=*CO+5c}QV;+0ck+&1_Dg z8G*7Cd${Vf71x^m)vx*SkoO?n&RCD{b#%1fS=Z~Dqgjr7q%^`!rdOWI8mVtMI)kcr z?Y@3>x}KM&eEWGe`Kq z4e7Zu$38dfxv?9V+j?*`*{iUuA4hf}B2dfneLpGl{7gOF>afwXw2rv@L)c``CHQW5 z;{`iifRh(7IBJk8B~bVaT<=LI4Wc^PMQc{c38XDY5*cnTA18lhXQgJws}TJGt%+ik z<1U1>1*IGGklnDt-lu82yPOIPvC#RK%+ms23u152jzOG%JRHu9eEO~f=cZZJ&ooLu_hel#bvfeuTwzyH? z&85nmJ)Be33kxll88PUBvgDRdTH^sh&Rj$M<&qzgtO_U}c2zaBk$`u}^mB-21TR5R zuS|Q0P7a*(f0OC5^->c=*0+88zE(DFye-&P?W>f&Wq6CZ^l&ph6F8$`mo?j+fBjl( z!aW^foy7o-vptEd(bLsFm^d16;vvhoS6BF+{-l?Ys8oZSOB6v$Py!Tnh2AFlhr3-P zI`YWX8NN@-5hr6IH~k<4U0@TKMUmhJA3sH|mpHut%J&RSl57H-JQFRNVx~GdSuVqalURaYcD+#Yo{m z?GUs=T*Ei@AEiZ7D9p^AbFyC#1A2?Sf#xgcP;lp%6u z@B+gsWtKLcRvA_);3fjXKaXtN5^-B&92J~-JimbK)(=}c2Kv-*c%Wqq1NE$cpl*$Q z8MMMVmE5Et2b`z0Nw zFA|s*Jg7)LTtAqb{3`X_LQ9H|G@cHfHdZ&)+_AsQ>mDQ093yZd^;MI6^7ZTVh(1&E zFey%jUWv9w-4)NaG{ar*e;0iTZ|x>2#-Sa@oXphyHC4Bd@*|$N}N#j9tL#(Tsk@Yv{FO0g?6Lne)%* zgUXg_mM0))-a9rA+kb5UG<(-=Yz=+_6u28D@YU?tIJkMZB-y%SMGsa}J^3`RrhK_cKaE$0xim(z}7f{%-v?uqSa)2?Q$GG$TN6 z8eug^J$^GjVao?F=Ba*^O^!S|VkMWeJ|MW<@Ljqyqn*siuHUO`R?6|t!d?uBZrq@M zmLvnKf9tafQS-%K99Th&*&k~;8r)~MPX^3$hLqFqb<1V(EQ2ete~`XhaavQHl- z={VLQ<)POSmXao~2Os~{1OH>lrxo0vLP9CgLW|-9JZ#kl!b&V}{wpjWs>t8*zXjq{ z=p@gdG(r**sxrg!&&`N~AW4F^$7iRDt$xx5ep1c5oUWhqcbv#z--lij`YpNE9un?u z)-SxBTNzX|J&R&!r?B+AB@i?SH--#=UE%Q5VY=sFu30uGGAYF3TLvZ8@y}t_^mLev z*sIDi=Y{4Fc85QSypdk-X^dsiG(r@58XEz*;G31^0-i zFAk10C=w(2qOhSEWG#*y_cAmsj`pl^8lpN6un9wwm@88M>DyIOA_h!TFuXlLfOFXe zu2MUvHiD;)jSN6I+cSJgg^P>NZ?6x8))xDoD`i`!M z3z-VZ2vm6^aC2J_Z;yU=)7d9c*L!;ueCfSg=E%*(HC)ge?yx$u zK=cUf7yI$8(1Y3->rTKfIOBK z8E}r)PM?3%Qvj)i#4bAfp?7>i)S%L5bO+>GRu1Qh_=>6^t(){Y2nkE7UFSX?8_g#& zUOf)RX0&^xdQ^s$`upg`hnt35WfB729dT*T&!0aH$SxN4j-=4UnZ!aTBL(*3`h}=| zM?eL?+Vcy16J4vTk1g$)8aoQ|{eLY0Ed3v*<76FS%oM`J3luGUe1AwNNyP~K2{449 zMYv~8iZtD$n*(9e^tZjDS4e5qAG8*7YDFc}!^M+`ct?x=H4!TsZ}zM-fc` zLRyZ^zY8%Nq+-N-?h4=o5Xf0-LGu9*xZjvC^s=-2R-HkDbsw4N1J@w*>&s6y3BjYRrLeRgS9O3%}+9_qHmfhG!bSyNM&Bw+q6Wa92I&Twgk z@(HcVszdN(PY{T22sVbY(wW)W9&R=Om1Y}oQlgF?6qrjYikuUa<+;#1k19BC&+j?FVEP%mGdeMWvts@GoMVqSWnu1Brs2Cb%_^M8 z0Uri&_UQY-huoze&RFSziX9IMRv4hlf!`8D^OFlWWn8y^G~8=m_FWNqyp_7~hDBDlrk5 zT6z%na;m7OYQhyFtE<1NvTNz+8WyS#CCf0#lz}k&*G48DzS%E`*a2b4vyE7J$BW2`d6@obXwrbbC z87_8%j=q5bK>(h`#Ki&hw@|gJ$Ofa$!Rx|fy!%L4^!ivyh9NlxrXeq3?v$^cg&jFitwo@7r`Z0A>dLtEnUkfjig2w>GrHK?Fe%)@RzxyOlotBH9f)YWP@ zE)G`-LaFd+Q*7_ZT&Haq%hASpvY{6-KXY`}$g5!HZ1PD)K)z_w+~2-`?baqsiW`fXm&(c$Z6_Qen?EEn?@w_;k${}F z6iB9X^Jmv@=2&^}2pn`4ZHul5VyeXimOZQ1?OuFPN%Z)n_j8J+M|q|pcQ@QY+by=* z%APUeS)0j%xe^+?M#bcx=V$5}H~BhO4uazjhxq?hQ%~~7W{=GVV!z*uJOny{>5iVP zMgPUylD7-C;mx;^_lszHdjxvLNl#hagSE9y%4TSZ6P}}JL}@fj$eYu#{=;HJovX)F zXPKJ>?$;UP2?EpC5=HB7J-i(6uh72c-@h$d!{06;3^h$G@4RJlaD-P+3ml)h?#+5` zo9!R*kVI*sNv2H@B=$L_q;7z1!)5)qfCuAN553tAW|KwR!LzW?Re(SVQgkX%6Nvx0 zV=tJhSGgkvC`jt{TS}pOp3+4r$3}FiqLfqbw5=_4$sddGBApuVfRzX12$66qiC2f1 z)@|w9x-C%#^IiM*1wA+c-SUuP91LdUd+zdLDis`M^~9AG9I3(FkBa6CjH|!ZV^#{N z(-tK04n@oT8AGSLYyOS6cp|4-gRiXlFDU3wu<=iafgUt;GS5p6L`$rKJ}|H~X}k>Z zsFH!c5*F$RxYCGxvDKVG63N-ELYG~m!p7caOb18dY$Sa-H;Nj?YL+QR%B!U>J$0AS z$P!wm0Men-(r4<7vDnjbTn#S-g|DUABP8`d0e z=7|fXDz%}5(WX`i>7pRvrA_r8c27bfvft~;<>8hAtv?@Tk>eK5`u$)&1J7I599veiglPC*!ypjXjZ!>nH;O(QaMbm^Io@ca3V+yBHL5f9zypn zDU*hEke>A_nC4jlP9ZD6Ws-08b)NMw9^G*Seo`Cn1ey+L(ks;ZHSM&X@+~9C+ht2- zzI37pdUyyemu)KT#}6-xxq~6$VIr!%96|4&7;9tcT{EPuq#f>xv}v~6*S~_#%-c1h$akGQS8kfzSkZ!DoRWdGe*)^Rw{GlV6vgQ#Qs*kYuWUgw`hVjdW5J39x zugy&Qg^U{9>8ALEiKR549#Qs9FJ3zOYMj*7Ye=N}@#rzQ!)REag9TQ~Xv$PE6#AO~ zSI+(Z3BBjzeZzC^ohOyM?sN9|u)p;{TokW6bjnL~5d6_OaXQjSb% zM#cin*RiulZM^kwMf$jZ-|szEq0k`4KWhG`FG1?8-tKO-NDhZx|D6 z4I6pL-huNS@92m8+h6{zdJDr?hl*T0#E{GhWr9gwn!h(Veg^!x<$A^Nr;Y(j)7(3| zS;b0N?S}{~#yD(K9n?6wB)J)Qy+gL24!jNX6z$+B45v<$NgB7G{5nni)AE>?wdoXr94rRz&^>u^MxDAQ zuI`z+;-3`T6$D5na3n(%(EyUtXNv6mV+-awO*|Gy6ZK3;1Wh02k^qf-&jc;20=P`X z0MHRiIG9n4QoYA1$!p5ly%!KXs9tr=CWEL}oA+D{RBRDDaX2%AGC<(zvF#=Z(ipt{ zmM&*;wc0?bfQ89;{4msjqBuVv?1ny#dveX^@AzMm!L8r$WKcIZPN|i=I`CmVm^k(* zBlo;DUc9(>xYma|j4XAU&HLOL)KFcVnR$Yz%~O7@_P0)XFYoi(0wEK4-1YbWO^!TS z>ok=s+U%7wd;CqDq)kH_yE@H-i3l>}$d_Z}l1Gx%Ji7MN{u67Wrb2*;DAaM)`88@A zS|F29w@zb+uw>d3B*alB&LSObvR{2uog(&FZi{HrdVV&HVE{L_<=pSo%4zpoy4+Uu z@Otui{n2RcX5RhDv#fkTXZ9l;yCqxoH(^HC7@{{T*k3e1VgiqWMW{=Od@9+uJkj(X5WMh-fMF%A?bn|nW|A^c8j(nN$htZCoFt+_H)GxKta z7aZtbv#dA~E5Nti+M!{UHii(rFXpVr2 zk9W7k*eI{L8?44f9ABe9E44|8_>eQdw6Q@{24?f3u}pIMASI3uK--4RUJQR7wZxYtn0)qB z(1#5E%|Q*@o{tnHdI%>Tk!hRC?nC*!p`AN5GZ0C(ti`R;9oplU2jlLOwH+XZyP+9=r zX*sb5hQjxpG7xeG!f3V1shQ?Ls&o#6laN&lozfD|1j$e8Ed5%lVr<=i7;Yf zVsN7SK~xrS!BGl%j39+9uz{DMRin|`WN5)dVq7(2%30`B-lVNAp#h1~$lX(pkm_Cj zkxF67P*|Kq8hF3LH=aM7#PMy&p1;+JS&5SxUe^|KhgWKoEQ9=IS}3Dbq599tcPKf+ zWhi~F?*~TRmoUh6Mplfoe^=ibG)8&bjN|rDU6@;_qo=?`YH%Q;e-)DS94Iybjl7i? z_!L$@?CAK0Q$PkJQ0j*bmotL~1_>NEu>6H}C@{w+M(FhqN7W+GV%JTbZQy z4J&+CUO&#^Z~a}+C2@!2LP#hvytysXrX=A|A?Dy!Bi5>SE3g(uAVHW4#gn2wG z_!F=SFCGrH7(KQ4+1k^qJ4@zlW(_#}8D+Z=NvKp>H16bRu)mA1&dxs{5A7Yb8BB|4 z5uhmjMxjm}Q)Wp8s;tskyE?0JRx+||5m@-s!bH#vB@u*ve*FSougg*GdF1=tuC|9N zl21Z!Nr1co^Si=;MB4fAR!jbNgM{0HsdH--1ml}7L)2eFRdvZ?vzfj^mZDisy;g?P z7aD)vktAQu3XxfTtdy-%2;UA_Kn@A9xT}{(>0lzYz@^t5e zG?nJ=b2g|Lbvg{#={UO1@P^If{^^N84Zgnij(c}Oyfv0bPaerBBm|2OxI#h=Z$Rcr z1zouu?=Kuh-OTcY`pZNHzb`K<#G!gdYr@>N`U~F|t$4U0T&$ZHS{o+oI#0Yfsa0x7 zQeF#Qt7az{(WYW5AATyoiET5R>GW>G?l!uJBS9ZZfgSjWt0^!H+~R1FshkzCa0hKm zq<~;~tcLiP#>8oe316jUCv6%^wb{k4%n^pDccv;YVSjx#PJB9pD`Xsc9kM}O9TL)0 zdZ5>8c|`6b2RbG``y6%z=Vi4{(c<#Zw^EYTc;0EQfO)^iT3zTU=*+56T&_Qx*^nGZ#C|UYS zn(&WI%kM^Sqs9K4;%zp&@;$Xu!NGx29cRcf6&ueQkh&u&;CI?cb8m<%8wh+A+C!vC z6z#-e42OiRxlOtwvXjn;@_G{FP0C`;JV{6~e%b2CBw@q;{`$j)${m2&+fz^eGc``@ z7q&GX_*R2Sp)G9^#EVX?$Yf&DzR)?=c9!C~Dc4l?*xBp+C|Z|;qWm{}?~b=8{L%7+ zdl!2LTU`#2{tyyTFAs7=0Hr#8M`FxvisUX_$1CT(n&*CT)3L z$Ug3g_>kw1duFp9F?M$8&F?xx#Y`Vg-o{9640MT9C5qlZJbRJ}{m%tv>_Xjl{x&&o zYGaCMpw(y8;&x1aFvH00k>kAdX(sfE#z~?KvJCybpBuY0C-vGTOgjxsg>P=ra*e$k z8{8{~mQYoQ`mi+97nhZvag6(%NtnvE#4(oo)VfrUPjR|fIJqc`7V5W&38Tq)@jCZp zSu31v>iVvf`+AF^bfirS=e6{=R``@Nl_h$2+rFnc?*wJuCu{4~wC69V=K2w%_n}et z(&xuF0!+WgU}ZhiN~gsq^UhdK?u)TK{-oZq!~E*X%Jv(FMgDM!xZ<}w zMI^FuY`z2ajbn4|aS7=VvONaWXXc-%Ij;F#sJ*eCt$U#pKINO)8*o~;^VpyHs1wDL zzPaoqAc6I^BYUrX_dr-(t4`aFvM7;NrgxgOE;`PRkn zM>h|br67IY63&pS`iz-X_E{9|(Z$rU{~KpJ1bu#VvMe(}wC%F$S@U(K&wH)(&m5iE zZ3==V)UtUzole#KGe$V3zKh|`X{JtCM?bd8Q+{9zc5|QKSe1FW^}6CC-0Zuqo4d!S zsP5hsLR=4i?yAetpZNRV3ZAvct)&vb<(svOu~S`{s)^^~%<1{|-JMlkV{;^vwt^v8 zk1m;m`n6nwS?=$Sd~Gq6NmbG~gp@1hf9u^!VkOFF6!+tC=%6!DCuX=uWrT;*{8`-{^j{cKNm;%ZKl#t z1kJOJ`s43Me-D)?w+*}~m)uxTCdFnZcgZ)VBHD27Z;!hk%eorrjx)6l0<<1H+GEMJ zb|^^SatF5R)V!H*hE{5>tWXej>R6fHU>-jHH9P62#M4b$sf(np@oE1i*}mp+A|$#I zE%{ZEUrB9xc5$w70uGwgd?QsDGw{y!ofb8{xUe^u9N_NsXfab$6K*+u-ejS=w_8@< z5M03!5y>UL@ZRxHg_?#gii^BVfuUq#DIF8D#?R2Znv&c|(vKbgW!#M{5%f8H zg4yxV>Go#Oy#8%PYQ5EZ216xGN!!41_2W|8z~2*YJ+fVbC=pOuKzx4x;yahnXVItF zlX?meSyMCrmu#t}9i0kAhM+4E=-@SSEBg4+@OF;h$sk9M#(*|LsV7)FZdnC&&K^xoE!Qh}8@Ut%jEw(!SsFVUQ)~1hL>^CQyBV$XNBG@;BU4lesM~pFWa&o}-)c{Kh82JEM`$rcyZhUR6sT#? zdxU$i*n2az>~Ey*c)A#D$p!mu#B906X~t&msUe#$v4R#>K0n9^sia+pKc3|S86;?H z@o+*GkrcrMyW7rxjD9cq+(=FK3(yGw!B0yT$bw$ArL}&(9N*p`kFTR5;Jd>eRY4oE z`sNkw-TI)Y6r88j%5r92d+Yaan}fyH-ie8X>9uigSz8djZKB68U9+@&lKL9+C3Zt= z-2usOIdU4pqLSUOHC3irgf%%L(e^qm`+R_so?}TIwoJ5e49YZ`ZmsJYV{8@`OQIhb zkOG!u^Od@3Q!$m41%l}%Rbiq!3;H-(8EtY76@7IP5p4}#&2&oF(_ZXa1$;!^KUqw^ zpyc>>oDcDviKznFA75j}#T+d!0#4S<+%!puznX5Cd&iAbEXC_GJ|G0*HlFCvY_NJ= zY*jmq^8vj*|MdbI+x4LNsr1!0uj5iN!`??C@;iUz!`s5?OZ#^3HB@Y>cYXD&mX?;v z1er#GM^D$x%lKZ_|^Gs_iB6hsmR0Oc;LWYueXc0qqw7^BNelP znVDHIFuVbgB<#b7l**~))8f)&K$X{=&Pyz-!8#`2(f;!oF@El*&RTptBgV4tP9UJ$zig zwR3P-5#R%A^X;&)N+OQJis$5mCdS79m6V|1Jx_HL42KK@^Uj;MZ$G8UyWIX^i|VKR zr`(k*Ea4XRu8)C4=VWG@*z7zPm#0o1HPs{RzT4o~rXpT0NjKV@zkXqzMR>Qw$Iq`~ z9{O>*OM!Kh{Gq>_&)1HDCyZwo=PH$&lkT}qyTAB3otFFc2VqZlb`LKD2vMHO zs@GB^pKEa7rOCfF=S^+-tAKt=CL>2-RJJd`RKK@D8bZkwXoRSDUI2o4ier)rgLfP$ zO-;aVuyW47G(XL`g}iVa+HBO~wu4t@WqI{4Sj}Ont^fK3QOm`?BbCp{{GNa5cn8#` zvOmA;5~smLwW?`{Q3$t1io z2G^7(-LH!mG3A~e^KznR|7AOu!XoIXPx`&ifKr6r)s|b@ z$T4X!dTP1nT!ppb>sP)nQ}U%sR^1(a7tT499`BIFzH?$mp+sgrPp(`drOE%GQZ+S1 zzeXWeXo7l{m_)Q9TDiww(V?GhBNINd132xKA2Jhr^HjVwV-iHc>D=Y(O^ z$)g*=%q>Z*Ae{%qyx8%Poi*+LVHpWu*s*b0@uM6ZqmIC+HWQbZA`lq|h|78dsai6r z{WMMfI5kF|62jS{+8NQwG}plz}@MHsI9YYb;4ZE8H>``tpP z*s$^qm!@$Aiy1L{uY{yq?{{|ta2Rjer~a>)Ub2a=d1q(1uun~(=`ta*P^PmQu4k7F z^A081_Ye}e*m(2S4t657Ymo#=UbIgB)I~h&#(Jga)=QMPaA|`ZKbV=_8E;m7LiNz8 zWvvW4L*I|qaPj-*o2wRSRvuSXPHXFX#h8GWK#^;0DKHDr2qpm}w7rpN)wguF2yOQ~ zP@Y?qN_k~IS^3MEJpEH#&)GvwK!15Tvu55q5IFmiEq5jNuxnK5@$ylOF!XbmGMvZq zaA|9=)m7N%E&_BX6U^QG{hJ{A#S8H36^$&JZoqgq0$gDIrq~-NSW~*O(L|jdmJ2{) z=y@=2=IZJ?zEw!Q9P*G^ml2G!YraNtqC_Yp<YexibLiCZ1uY8x>?_5Q7I@%AlLE}yYp}72_YYrqTys75sanNiHAML=E z+|MKwwa9GkYgJV;$9kt+hFs{U9x+8Fg{OwNdslq|Nf1?*RALGWNfqaV{LaL_>l z+~ZZj;PE_046Bt9lbp`6TkDbnXGJ-A{=v{Ji$DZg^H<@-FUy(z<#ZxhCREvw!DTddf6aB5VEBx z`4Eezm(oWa0qppoXC{nww<=_h0Q@ zoLzAGK7#0BpV&`5J#;nuL5oksag8FmD{wf?*T0wKYK2W{n9Uj_h|8A!GObq6HzE_L|CcI8omeN&Ppb#-!0 zTED|964C5XU_)9~R(8Fkv}9)PH3N?)dpVZZeMH90bMoVktLrV_6GWq6)K|`1<7#;E{Q92-Ul1E?N@J|USIBh2@p#@X_JH{eXhc_L zE)sXGBrA2cgd79Wp7eTfCE@G8ebWn5Lvfg2DzKk)lw(MaeABIp-Gp>j zYK{qeet|t6a#!&_;o{8XTD`X{|HE(pwaW+gHypWZHA}ZI=Bg#+aX=$S^Ai-^Sk%s7 zB%l#iVLdZx2BHRbSo~H-j!)#MYVPA@G|1#X%|Xc;sQzTaA7i{}0(X)fKrz=S>{f!R zn%lv}Wxt>ohT!1W#+GWCFV6_1ZN#RGnd741R>F66lL-E#6D695cJ-*(rrHxoifi(+ zl(5N>8D^X6r~pwZt4IK}t|nieJ=|s+goIj<{fOcUq9n?DM7Bs4O1O<=8vgAG`3uiduE@-swm_fj-gqjutJ;;PXtanGU$-~&0uc)!R%zC-%#^l zg?un&84Xv+$LVbS>3mb~^wKp2RCY1B$&s)mB zv-#W{;?UFRKrWoHo*y|yAEEl*_NYP@1hegkue{H;>{w~_;Ihn>9xxA%>F?c?8Hv@XKH z!3koucq9{bj11^ge+>~tS?flHhP(E>yDpqYY5LYRwx0P0(%fkjA3OC*HIwJVi+Jnb z9p+zmTx%$W3^bDH7yT~{ZqRO80x#LqQeOyjKH;wk>?qqn`reC%Eg<3=>$6b2e}JVh zH@mn9AN?!fRbN|McHakzVceQV?I1oWm?J!7v5IY9Nxc3SrUzO0lJ<0JWp`lH=Y@w4 z9vm3FIW7((_CZg`flo=a;NTz#;;tb!clQq9MWN#HI1{I*S$y;eMN!Dr>pYyjN1@om z%-M51xbq2;tg!fKp6yPL?Df@E?%le(=^yCh>GCowE316?!G}CudCCue_(L8(d>jOf(&;qmj29gG z_51G!gQ9YsOvYxjL4W@sOG{69?eb+D$Kl@HJEYSYYPBlU(`R_H^aR7Sa4eHo&YtDt zk3M2_bd;wnPx-??`bT{D!3S(^Y;^qcDz!$Fks;4@nn)y>pPS>8Pd=esE>kELaUF+T zE{7yZ{JlT;gU`(y<)>NVB%Qz|+M=?%uqPD2ilrd0Nc|tyT*y<+aYOly}JHJfH9H{rx{g zj*Ff*LR9t?3TSaH_#E&OZo^+P84J7^{=SJ^k#x3z6x-bveIGv8n$!^xDf2;ho<`n1`uK~1W^ng)F{l( zcZU@Jjrima3xUS3C_&DWq8CjORlDp35f*=IP0ob<1B#n;S^7j3i0ax3_3oHh=l&e@Z<5+tm%!A1m_4 zIjvz02BNA%z#}{|nw>@OEIx4?oh7_~n2+7m<^YEokKq%9 zPwwB4jrX+pQr;&op<_h$l3L(|)Gs2s@yX|r#jfNHFHtERCU-Z2?}1P3ZU&;ijy_>w zQd{gwYKi|kO6;T5kpN+d9gFM~zPQ9*No}%M zcMe;w{(e#YI!tc5ygtEK3*GWN_StLf65A(qnBczj4wE}9y${SIk=RRW7mtA9gTiF> ziQP?7w>#Tqx~n1Gh<$<=15s(+O&zh>C3TqGQI#ah%{{Rd|61L2Y@ggtXdS+Rr~w!@ zDt%X>#ICgV_xF!Ek=QQ=x=GTgHsA|QpS)p7t+Q9>4yz*vsU^X64vRcSb)jw~h5agv zzX+k_gxD`0jv{tcbq(v=he>URy^=qAEeH|YzhJC$fKNn+y{@|Gjfd3_KhV=n4LLCy zUtDxEBD<+0VSPI)y$>U|8#yO7k~-=i4-oZ=grBA`p`$nFKVioqb(GL2#D4J*C3e)KaS*wkF6+bm*}*ls z`LV-Zk#08_y`ivSd6>a?LhKh8-2y4y49O_Lqkijd;q`s4KG?5{go7(k2^$Te`$9A-T)TNj+6R#kb_pByiX5~=y&q9u_enwP->LHXFR$N^!=?VmVy#Ajig5c&i@ zx)HpaQF+v72b~Y-9t}K9g@{V?gY@W=DB}qZ!#?*M2dfudjl(0>2TInX2-@wq69e%C z&x7Mg{( zJaZG%Q-e|yQz{EjrrH1%MFseTxUO2YYVY2?2M!#VK7IPOZQItZTeooG!g=%NO`SUR z*s)`4)~wmMapV5|`*-Zvv0}xF)vH$@IdWw3About...

    dp.SyntaxHighlighter

    Version: {V}

    http://www.dreamprojections.com/SyntaxHighlighter

    ©2004-2005 Alex Gorbatchev. All right reserved.
    ',ExpandCode:'+ expand code',ViewPlain:'view plain',Print:'print',CopyToClipboard:'copy to clipboard',About:'?',CopiedToClipboard:'The code is in your clipboard now.'};dp.SyntaxHighlighter=dp.sh;dp.sh.Utils.Expand=function(sender) +{var table=sender;var span=sender;while(span!=null&&span.tagName!='SPAN') +span=span.parentNode;while(table!=null&&table.tagName!='TABLE') +table=table.parentNode;span.parentNode.removeChild(span);table.tBodies[0].className='show';table.parentNode.style.height='100%';} +dp.sh.Utils.ViewSource=function(sender) +{var code=sender.parentNode.originalCode;var wnd=window.open('','_blank','width=750, height=400, location=0, resizable=1, menubar=0, scrollbars=1');code=code.replace(/'+code+'');wnd.document.close();} +dp.sh.Utils.ToClipboard=function(sender) +{var code=sender.parentNode.originalCode;if(window.clipboardData) +{window.clipboardData.setData('text',code);alert(dp.sh.Strings.CopiedToClipboard);}} +dp.sh.Utils.PrintSource=function(sender) +{var td=sender.parentNode;var code=td.processedCode;var iframe=document.createElement('IFRAME');var doc=null;var wnd=iframe.style.cssText='position:absolute; width:0px; height:0px; left:-5px; top:-5px;';td.appendChild(iframe);doc=iframe.contentWindow.document;code=code.replace(/'+code+'');doc.close();iframe.contentWindow.focus();iframe.contentWindow.print();td.removeChild(iframe);} +dp.sh.Utils.About=function() +{var wnd=window.open('','_blank','dialog,width=320,height=150,scrollbars=0');var doc=wnd.document;var styles=document.getElementsByTagName('style');var links=document.getElementsByTagName('link');doc.write(dp.sh.Strings.AboutDialog.replace('{V}',dp.sh.Version));for(var i=0;i'+styles[i].innerHTML+'');for(var i=0;i');doc.close();wnd.focus();} +dp.sh.Match=function(value,index,css) +{this.value=value;this.index=index;this.length=value.length;this.css=css;} +dp.sh.Highlighter=function() +{this.addGutter=true;this.addControls=true;this.collapse=false;this.tabsToSpaces=true;} +dp.sh.Highlighter.SortCallback=function(m1,m2) +{if(m1.indexm2.index) +return 1;else +{if(m1.lengthm2.length) +return 1;} +return 0;} +dp.sh.Highlighter.prototype.GetMatches=function(regex,css) +{var index=0;var match=null;while((match=regex.exec(this.code))!=null) +{this.matches[this.matches.length]=new dp.sh.Match(match[0],match.index,css);}} +dp.sh.Highlighter.prototype.AddBit=function(str,css) +{var span=document.createElement('span');str=str.replace(/&/g,'&');str=str.replace(/ /g,' ');str=str.replace(/');if(css!=null) +{var regex=new RegExp('
    ','gi');if(regex.test(str)) +{var lines=str.split(' 
    ');str='';for(var i=0;ic.index)&&(match.index<=c.index+c.length)) +return true;} +return false;} +dp.sh.Highlighter.prototype.ProcessRegexList=function() +{for(var i=0;i/gi,'\n');var lines=html.split('\n');var row=null;var cell=null;var tBody=null;var html='';var pipe=' | ';function UtilHref(util,text) +{return''+text+'';} +tBody=document.createElement('TBODY');this.table.appendChild(tBody);if(this.addGutter==true) +{row=tBody.insertRow(-1);cell=row.insertCell(-1);cell.className='tools-corner';} +if(this.addControls==true) +{var tHead=document.createElement('THEAD');this.table.appendChild(tHead);row=tHead.insertRow(-1);if(this.addGutter==true) +{cell=row.insertCell(-1);cell.className='tools-corner';} +cell=row.insertCell(-1);cell.originalCode=this.originalCode;cell.processedCode=this.code;cell.className='tools';if(this.collapse==true) +{tBody.className='hide';cell.innerHTML+=''+UtilHref('Expand',dp.sh.Strings.ExpandCode)+''+pipe+'';} +cell.innerHTML+=UtilHref('ViewSource',dp.sh.Strings.ViewPlain)+pipe+UtilHref('PrintSource',dp.sh.Strings.Print);if(window.clipboardData) +cell.innerHTML+=pipe+UtilHref('ToClipboard',dp.sh.Strings.CopyToClipboard);cell.innerHTML+=pipe+UtilHref('About',dp.sh.Strings.About);} +for(var i=0,lineIndex=this.firstLine;i0;i++) +{if(Trim(lines[i]).length==0) +continue;var matches=regex.exec(lines[i]);if(matches!=null&&matches.length>0) +min=Math.min(matches[0].length,min);} +if(min>0) +for(var i=0;i','gm'),'cdata');this.GetMatches(new RegExp('','gm'),'comments');regex=new RegExp('([\\w-\.]+)\\s*=\\s*(".*?"|\'.*?\'|\\w+)*','gm');while((match=regex.exec(this.code))!=null) +{push(this.matches,new dp.sh.Match(match[1],match.index,'attribute'));if(match[2]!=undefined) +{push(this.matches,new dp.sh.Match(match[2],match.index+match[0].indexOf(match[2]),'attribute-value'));}} +this.GetMatches(new RegExp('','gm'),'tag');regex=new RegExp('2DMT7{-^frOVv~QkPP&Ewq->nsP|D1x-16aL6T+fS1y->At;?rCzDB|UT?Kn!l4k)^P(uaoX&VWPDLVS z3^V9-9LI%%!9*fqvszIE(P_0zD&=vzEoQSQ2rh>sl}cr^+0oI_$ml469m^7AOPfd(=_d{J75s9+iVaBkbZwW7K_qR%xHAj zZA^+0cp;Nc8x49<6f&7K%Vrbt1j8^{Hj8K=L<8$}Xgn5AC6gKeKwua}V6zDW0ky+n zPoiu?Rem84SSyDdxl|Me9*rCY$wnJQ@)2dcAg=HN`NnMuR|* zD2N=->(D$dS0plOHDk$SLWdv_09wr!r`?{fnB8U%1p_?KN&d%Fyp;aus(YhvenKL9 zEqOgl(J`p%+jYPBy@S-_&Etzpk|12+#`W#@(A zhTf0QpWXgq#MHZ=n9i*1S=FSyQZ&77VCc`5O}C1cxkIuU-T0K!2kk|dPt*-6I)~0* zlB4$nhWdWPi^}cyCsppkmsLccPjtVtW8L+i`<&LMi^Y*uYp2V*&V6w(iB9iyet-Ji zE^gtL*CQ=opLw|!>3FcY`%3@H8CC0#Ty`w{r0UeSCC481Kat;Ruc|?1ibbS9pwe&aT#R+%DO!J$i(uMa1rzv{|hT2OWx6~*_%5`JYm*@H#8hc!=^BT9m z+%&J7E#ACn?_jQQp?`4SYGp~Ms(0dE;PK_cq|z;$f2jHTPb(&=Mx1xf)WWVGo*X$> z*l@N>?i$%zR=R4|rAGz6xmzUTqzg_;#`$Eox|(stz^sBx^0xAdCkjR}PF8-fVWfY? z#2S~h^p|R&Tn)6wYt_;jHNEOO?9t)N6)U8{56g}{Rdu}G+fh+CC3FX^oA8yYynezC z+3NZgJ9al*D`EHc1PT{3@-?QnZqD&cuDSQBz+7{08!`Ee%vn@c&|TRww})9IX)1XB z>b&Gvnd;oK35u~c7pf?C7VjDBl2q-PvbcZT9;piP-Q0a-@m%tS+}ZfYi)XEp6Oyq) gN%dXecuDQ}@=FVLc0apP+!WuqblxeMyjZg0UuMopT>t<8 literal 0 HcmV?d00001 diff --git a/include/javascript/yui3/assets/gradient-ex-box.png b/include/javascript/yui3/assets/gradient-ex-box.png new file mode 100644 index 0000000000000000000000000000000000000000..5d8bc6fb668eac4b46d78793b22ce510eb58b7ea GIT binary patch literal 482 zcmV<80UiE{P)Gu5V_Wa-O z_w4ul;PCk6^ZD=k{@U#J*6Q`x>-FRD_}%XJ*z5M*?)TsC_u1?A(&zHz@%ho`^4sk8 z+Uxew=JMk4_|N6>}e z_4{5}>QMjy0LMv0K~#9!?8-+{LO}opz-JaQD`v!;KtVCz|6p997felkvDcje%Jkzd z$|~~sgmRB^i?W0~ZXl0q$YUFM+(90@C|k(mIm#u<4ay_R8Oj67GV-{Oa)EM%a)@$` zvW`3+qYP2axQ#saQGwV)Swscm9m+GR8Rt-ec!IKr@`)M|SCGdAR3Lt!M#NwAAEy*M zC|~Gr#RHUg)QEV5Qc(+e9HU0W5vm#IQGxh_W;C9ne4`nSo5>U#)$v} Y0P}GsZl5aLjsO4v07*qoM6N<$f*>a!(*OVf literal 0 HcmV?d00001 diff --git a/include/javascript/yui3/assets/gradient-mod.png b/include/javascript/yui3/assets/gradient-mod.png new file mode 100644 index 0000000000000000000000000000000000000000..94379ba2c7c1edd79b6504f31f1c87c27d36b25c GIT binary patch literal 207 zcmeAS@N?(olHy`uVBq!ia0vp^8bIvC!3-pY{8N&Flw^r(L`iUdT1k0gQ7VIDN`6wR zf@f}GdTLN=VoGJ<$y6JlB9#E25Z50+e*F3K=jYF#zkdDt^5x6#-@m_o`}Y0&_pe{S z{{8#+-@kwV|NsB8J|G9E-qF*=F{I+wn^QXl85DR}3_sWZ{qD_vW|`gMh%m*^0_q|r zWggmm9@<_fCv-h#y^_0Z<>*6Q`-@%iQR`r7RFGu5I?)Tm8_U!lk@B04O>-Ev*^3Ub+ z>-PNF>-OUD_|N6>}e z_4}p^sc--Q0L4i}K~#9!?8-+{LO}opz-JaQD`v!;KtVCz|6p997felkvDcje%Jky{ z$~N+Nk8*}`fwG7^t|5<0$YUFM+(aICP_~fAJCtLTCzLMAKFSHo3i5c3a*lF^a*A?@ zvW`6VP==^xTty!Hs6gzXJfi|}7v%-jjB}_!JVMz+`9zI~%gEybDiA+VBjPXmk5h`5 zC|~Gr#YdEP)QEV4Qc(+e9HU0W5vm#IQGxh_W;EWSe4`nS8_44;su|x<&3J$&0t^7D Wgd85W+a_E90000$B3^%H-?q_4wrR z^_|4hyw~CS{Qc|h@Y3n+eXqiy$kg%k^`ynt-0AL-xybGD_3-!k=kM|0?D50gzTmL&EVYV=uT=~K3GI5j z3kC*D#uiE6v^u#s@XAC6U|!->?yjAF&+q&He=Zev2UKua6bp2CfQ^oTf`fAl8HZ*E z0Cta?n=X+YC3ABOWf(4^b`^OG6EOt`3?V(Uw6(UkxU(S)F*~3(mQ|RUstXG-u(G+! z%so821rrN9k^l$6LpCK93k4cH&EdB^8V3b2($k-!E@M_0qIIe}tgZ(d6cjqOI{p6t z00ROvkWa&c3MDE9BQZzQu>&D8P;e&BmcV}oBr=G$K+qf#*fOXpz$1eJeiu`wq>!P9 zIgZora1aH+oe&TeP|d6NDg=f9XCZh9o#oGf(W6L{=39ESUj`mA5GJrR%po!z6hdg# zDs(6=l}Qck(~%(rM~~JlB^ar1tJfYy!^&Ms0qH)149un5A!z2D3Wk0ZfY5MftDaf8 zdhKU)X@WeKP=G<%-$ZpZ&IcO< z1|R50sJCE&2K)CGG;=<%1Asy@inh66D!HGBj9Bc%bhn^4WjWA+@CK8~}N#>xV&LE*kH`M{x*`b|1aB(Qy zhXsn5V0$N`=bi)>_>ch#`y3QQ8P*X)4>BkH2H=j46&RwACbsvU1S81TLsquU1i@5f zL{-3dr~xP3fRbT30+H>}Am@-0NZE41e+;vVzIRT(S8362{foY0y%41}15*ezf z7SyR3Rw1+~4PVs&P{9w^Wk=6;u=uywnyt}#9*H9?%4nnP9ZA6fr`Tl0FvV<#&uPng zIAD*@u1CYPKFG=cAPOZ#IAK~?z>{GQI*Qw@vkBUYt`F>ufagBGz6eU6#4b_{rVPNk zDYN%t3FN*bvWEc*5Y~5}75R1R&4&NU%I1|nKD_V5?Mg@ug=Ac~fHU=WiZ8VKLR_Q` z`snb|uYJV`LBZJJVGObfw><01(Vh#jkdIPKpMCiCyq~umZyF$vO;6|49CH|XOv z+`HMbE1fvXUpKD1+^=u%{PR8pe>q3Qv(5S2uLLbNvynG{HS`syens_AD^DEJ(JCE! zf(N1REiQa38z1({_oMUeOMS!3+2#zkAJ6%(e&)Jgd!nZ|)j7?27bI8j9EdIgc<)`e zvqJ7d2*Alf41$J(QujWcv+VOZbl;7^mI7(dFX_ua49Vn-{${h}KjmAV^Di_#I z7w)T>lC0t#XKBGuVlaT#bO1Iz$hRSKGnn4I8Zi}lKt?*zouX3@;UM|SbjEU>G_+(b z6@!5~acO8D0D(k504h!9N}iph=O=&pr8<3pqUDjmL@!`YbYXyY25jRH-nhFAeDtIL z{;Cxc8HG+N9u%4im8MW4uz{ZXi%mS}X-~N{f|;TxR}#Re^s)&;u^B+92ryEQc)9@y zfS{z)I%zQ%slrBTF#u4FY3~NwN)!~-rq9GbpyJSA18#-D1&aDRAM7)w$86aG>N)@nKvAH1Eny_l>OOX65j6&& z>k2l|0P+w3v2XoAHD#u&dHS`Ufb|Lh+`0h}uxSK!Ex=-pIwH-0ldEp@>f=H~TMz&+ zW`^5r9Xp#)TIv)WI~XhmC?EmUt^fwAU9A^eo6*;96g(6_Ee9mPrnb8EO^oIL;ew8| z)qZyMpN}JeXm=oi<6<>Pbd;eio4eMbgrKf4kN^fCP*)CQSG&_f>InD>MC$!@n?s>M zT{SS>W|e@p4OovRNktZZs#FLp4Od;GYTwK@Dt*e;FG4Hn+#80sxY1242xLk*1>3;2 zL4+-Y!7I5@pl!Y0|Jk>0aUB&0f-7ubj?g6h+`s?b@bvl2Nbh2Jr~W= zX3(^H_LB1xZCy!wTsYy%p+w36nj0*}2Vai@qFulUcys{DnrN9Lx)lNcOp@nQ?sOvu`V>0X}!>ebsE>&c2@7+1nG8jDL%qpsz!_b zn;!odQ9hWjoyI(;AVHfsJ(%{A{W(sec-hAw0FjS)?d(v0yGu!4-*RUi%{}Vi+Qm^g z^GZ}AV1o+U`WUu@b$q>pZ(sn3n!$)iuyKy}RymuQ4Yg0bsXhZh0t8aG4oegyo@-ky z5?3)!TdX6K+cxJ$47H=)gJkB2ywW89jmd#L91NiL$71%ka$*zz^OEVA;7vAwoPBUF zx~0*wbs;ooDW20kKGm%^AD5H`C%6OI-Ljj}TAD|`X4D+~x*xEt1a2K*x(UuWh0TXp zoYCG7{~*M`5$t&-f^@^v-8=_6{HSXd^hxeF%b)E^Y2;kt{~hP_%Sro}ujKk=#un7G+a zOG1H5D8W}-0)l=7h<>`qcm=?HgY;M4@qY#&ev5V|tRWZw>gNwEQyRVZUa#_h$L3ZV zfG62gfFf8Ii^l_|A#0yUYp~!Spn$#fSNBjTX;K>b5D*nH3tjOH+Sejq_gpI#$b>EtFrK$!$YT!> zp($wsAaRHbT@evx(F;46hOo7QY&eJGFo&3!iF3#mv|)#)=1;HS8&dKXi)agth!qF$ z5-u``ICU(p@Cp#o5~uMWnplgqs1*;=E75QYyu?5MhWI7AGm5h~jKnyMWKj;16i)u+ z3g3r_iD-+^*oaz@4|$o)1=o1bCj_e2y z-B^w1APs^5Tq{)qJAf>1z#Q$!j^gnYsi=y3v3$j1BiVQu+n5ZBSc`<(izL~SF8Pu$Ns`>b zJ~`2gG^CO<8IwA>lP<{}F7hJu2x7uw46n$OM!AzSi4G=tl5~&?tMD^1u#z)5l~h@k zR(X{^nGPOdlf>|ptss?H8J1!>l}af?j+X)d!g4GIIhJfGmSs5&z!EG7MGUI&l&mlT zU)h#=nUrry4Ku-&PFaw68I^mvmr;qA#-Im%F$pP?30|3(h1r&eiI|D$34Ag`*x{6R zd6#(EnV$KXpc$H?X$(LK0J(t$6VQ}(nT?z&ny&epp-GyGc?U7FB#7WNtO=XCxtr+# zmzEhzR)msxkO!z4XhFmsW6-r+Mymgp%!YO000NW zAP?;Mp(u)?7Fs-g@&+IP0Sj6O8@iq}TBA04qd1DAcJ!QB5SZ=k^sk%C>#2Tj%&;kzNPy_G*NksxMdaK16 zt;X5{1mFNP;BMIJ0635Xr7Er7YOFbc0@#YJ0#IKq(5>J4t066dh z&swkcdawAJulicAFQ5W7AQ_fn8A&Cu@md2Uz^(h5unL>7IdA{~8?X>-8RhB#@@fJL zd$AbHuQ<@I?n(fm`T^xSuqr?TEl{#8U;-$cvMOr=FVM0s`?4?#vnxvi{`#-gS{c_0 zX(3xD0syjgQW-U%0w!y+D_gWF8?!HKv?<#HDu4qwi?ibjX`;HbG|($i83RL`wOYHi zT)VY28?n|Z0g_6nqKX3l)yM$V2$LkRwrtzBZu_=w`;R2x1{MITuqvw`C97oH03Of- zGk~^edz5kuw`*&Z_|UU<8>@=@sf8-48PEZM8@Z7yxPlwGJ@Be`TLlX6w=>YWp8L6= z8@i%9x}?hhe`^4fTBu`7s6)^I4-mQ?5W5|q0km7YwtKs{o4dLDxgC%Ishhe(AOaoW zxw1RFyc@f^o4m;zyP+EZpsKn;5CAh!ywqF0)_c9!o4v7%01bc*0)PP2ivZ#~zT{iJ z=6k;ATfWun0od>ZDG zoWKgazzD3q9dH8w!Jq)!E4~a|!4_=6<{P^Y(7n|$!RC9xARNLO%u7}90Of1IR+z#n zd=v*wF`JjP#4#pBz=WMIMwfWlyg$g=#!4{!rz@WmM*$iAG+%ACr;T*(D20C)VwH_*xoP|enS z&DfmH+PuvQu*#qu01qGlWN-qT+{M$p%G{jJ>YUEr48~Q%heG8$ZX9gozgJ< z(?IRgGR@G|Y}06b1p$x()x6L?9n?+@)I&|wMNQG)oB&>&0sg$yJ^j>N9n>gI(+ZFQ zIQ;|v32@9jebQZ>);~SdVBO82Tm~7S)hD3VbRE-dE!8#6&jFACgKW}FEdncj0fK!2 z0x;Nyeb|Vd*oR%%g00ds-OXct0ZOd^Ck@ytE!YCU*owW`oK4t_z0xAU*49kSnM~Q1 zJ=mJv*{W^WnLXH`9ol&9){^bd4L#R^joBBF01PbxyxrTr{oBAD+#ZkshMfS99odx4 z)VEF8xxL%L{oK&q+r!P=jcwebodRW`0JdG+&K=#}?b{1Y+^N0NQSAXWeF10f0ldB3 znVkT?UDrUp-mWbI3V_@TZP~=_+3xMz@cq;4-P*am-!xqY>Yd*g0Nniz)Bmm6EX~{h zQjOl#jMDgx+O5sft9{{!tUXk<8pozgDwD?PUIKh1C?m=sao#g#GA2PU^{;>a>pOjt=YpHNNIi ze(OZO=5k^ImHw;3KJ1@L={#Q8o&E!BF65yuKPe(#n(fYmYiUs)2?$a*tmA`iA-?(v)^Nrv1aIpHMj|IHn_<7&B5f%K8&-|=A z{BcjKk{_x+|M9n923UXfdRzH=yZw{ezN>4f*gyE*pZm$*zLr1!mY@8/g,'>');win=window.open('',"codeview","status=0,scrollbars=1,width=600,height=400,menubar=0,toolbar=0,directories=0");win.document.body.innerHTML='
    '+code+'
    ';if(print){Y.later(1000,win,function(){win.focus();win.print();win.focus();});}},handleClick=function(e){if(e.target.get('tagName').toLowerCase()=='a'){var type=e.target.get('innerHTML').replace(/ /g,'');switch(type){case'print':openWindow(e.target.get('parentNode.parentNode'),true);break;case'viewplain':openWindow(e.target.get('parentNode.parentNode'));break;case'togglelinenumbers':e.target.get('parentNode.parentNode').toggleClass('yui-syntax-highlight-linenumbers');break;case'copy':break;}} +e.halt();};items.each(function(i){var header=Y.Node.create('');header.on('click',handleClick);i.insertBefore(header,i.get('firstChild'));i.on('mouseenter',function(){header.removeClass('hidden');});i.on('mouseleave',function(){header.addClass('hidden');});});});} \ No newline at end of file diff --git a/include/javascript/yui3/assets/title_h_bg.gif b/include/javascript/yui3/assets/title_h_bg.gif new file mode 100644 index 0000000000000000000000000000000000000000..1378700ce6fe158f8824f9142d77a81896030d85 GIT binary patch literal 91 zcmZ?wbhEHbe8#j0_A+3_2hlNS=X7hoxoZ>9_og=WMyv qz4_jr-~4TlJf=PCT=wde9-F|HPd?Yb^*;Y~?)yJ}7ZwIq25SJJ&?G7V literal 0 HcmV?d00001 diff --git a/include/javascript/yui3/assets/yui-candy.jpg b/include/javascript/yui3/assets/yui-candy.jpg new file mode 100644 index 0000000000000000000000000000000000000000..6c61b9522df7f1501a4d35af9b00f14e0f5c0cd0 GIT binary patch literal 11389 zcmY+qbyO727e2gncL~xVEU*Yjhrp7%^wK4g(%lHs-LSNjbV|b#(p?fFyL3uQBLe#R z`M&S(ch39FIWy0>&)k`N=Z~2`=KlTucN0JgRe~r1(9i(@>wgXK_XI$u;BDpT4?qK8 z0ssKjf2K14v7EK5r47Kk@1F(jFA5L=z(D^G|9T883=9k`EKCdxOe}1y|A38)jq?xK zxVU)u`1p9Zg#QEae<1z8K*PYq#Ky)Z#Kk2fCnh8&r~FT$B>SIE_Wur~|KIR`eg1#s zZy$gR7vKkI!9XJepp&6tkfHq@0@VBq5E}#SU;lsbUsyP}{}RMQ17M*2hySDeO9lOZ zDk%UB1LMC$@UU>vG5*Q_*~zf50pu(cI0AC4l(^bpDhv0}uYzf8uc%XtJ;HPv`?p}0 zG|%wZg$Cpm$o~1GV`5@r;Ql*~|5ir>kfF0+2*{CRYFn^kxrYi;oTnBy_J957<3S0= z4okaad-WFyAp937IvEBTKn8GSskXvsKgVc}GU#n^K^O?)>6D?}Pd*$ifcr)CWW?V~ zN-0C;5EM4P-Cw$cd+;LTvUoc83il;Q4PLuwo%+xA)(K@kuGSwI+$ArU{xG>}`cnJf zL?Pa*w3x@er=6Qa2?p0`)rtf0yV>RP+*wh+ZZprHg$@4}CEtUEE?xWuXfMDJ4qCQV5jy!S5Jn4V`IZ+Z@5vz{HAp@Z+GUSQRhc^vK zQwK!nxVqSkpr|L56BIjFQ&z+Lv^-Wwoc~z9cGmbz^@FS2`EaK$8<|6shneo8lUSlR zPcS`^Fli$nu?NE&GjLLJ- zy?HN}RXQU7!+H8#k7&u+@PS11&4eR{$F8g!cW>I=@26i53ro+svH+RvGZ^vMdjmWwh=Y>`~0&pm1nFFLuuDmT;U&vfCc<6LI=4IdB zc5bij@OjS$Mdy9b!(;EQzsX@cyxn#0FW{wZk3LcE#cE}eHls80L(co)^jfn3I}S$5 z+d~BHTUa%4qf~1WkvgiMHa&vKCvEXdQ%3jtNZg!^Rz4NEOpIwC7TLH`s)fK`qU7bq z>1x(0b3*r9j>;>K!0yRSNsnx9<;H`Bz&^s5`qrvc`RP$jv(L+*B+?yl$)vBsM(fr!NkJ!A~#Fztg75*61^8yo3i}c zt8&t&BNnDTwK0$vm%1UZK7gR9LlSlTbcXJ>45^SCeJ3gWUe&9~w-;`O{qWvW!DR2q z`*MG;Of8dgaGJlos7g*YMamu-ijo_RLhzBkBTKRQEgds*?Gn=#GeWi;AFEoIEW)WL zAf*>`c>9u*w4e7`WbyR~+@<{$Sw(&WNU+l+W4o_R)>{#JdyM`@^)hkkr_c2n(-8bFeqIFLwPB z`h=h`LKaAb$5FqiXilmu&2T>^y5sFAnT|K%cvDZDD~i8HyW(22?;KHQJe4A#A;8YV zw$Si#WNAUyR+iGmi1z#26F2*DE0E13;TFkL2;XHuJvKZf>MJj@;t?at;}N4RIPiA&vmwn zcuI)86Q{Mq<2*+`#cZ}UlJSJlC5$k>z0@Xj)$e>Tz*S=Nl7HvoZnt~hu(8Aqlm)n8uSoV|d+^FAnQ0M86QlUaAfiv|)Ll7G=Zz0&l2f+O zoZxa0OJtur9BcBSH(nR%JgrR0v>r6Zg$Ne|VWCgCQE8dDOp7|NIWJtpP44r2Jj9PL zTgyaGcJ&cK5SzGjZ1X>pUq%{ECGHsBYGFhQ&9&hP(S=2up{o>anHf_LXf{83NvH<% zT|pmnNevVtD%@Gvdb_cUQ*;(8dY&CE>oKSXNeuBBq4Vry5pz%Jq7A{v3{`>X`3`lq z@5o|}!K+DVhPnsiZ6zkZ)Hg3KNa&$g%$*__viI)=BMa7-X6&=D=#!Sj)=F7l znMC57_z%>dN#w*M%mFQDW=Z=q5mPTWZ zjdqNidU1FeMgDPP+RS|??*2~E({z3~#E2%%IxdLxKCubYa0cq{B2`z3YhPWbXMi6n zw^3KSa>w2`#Lrn70^DxOzg~(xCoVC`s(Jrf%00N%YB?}TD$1JM`G-(ccS{tbDhpho zbGRnE3^Pou>^(KPl=06(*9-`@cEBqdOkvge{Bv>2Pl8reG4vO~j7H~>&X={4SgFhG za-;hi?TuueNz@`;AQ#Fi4Fw${im{aM;0)5A`yA}0VZa7bqNVj3k^T^ACF{Ymd<~A6 z43g56U1~SB#jc8wyIQAYy^4()Jh@rYu&H$)e~M(#I3&kb($Hh^oTc&TEiz%T@&X8 zj#HrcK+f_hbH?P=Vm>E)wYNHR(ul{mctv6kTTw=C6~ZxVebbXWTCWGhnEIg|#O{7W zMXmW8o{n{2<2~dJuy=|d;Bix^c)7jH`O3DtchbphQ}DNm&I|60qp!51 zrfG2!q@}>22oSL|{(745(JDIClH$HBMfBjKVA|*U;w=W{w&yc={)qu`xbpFFo3NBm zLmYMw5N&!pMf=*JPs(CpfO6kIl;*W%F>i9bHok}s90m+|9Tyj{_tFsV}hc6cm^u;x|#iX{- zj>vpFnN8kC6i9Z?-v|Eh)%FoED5}w1Nd8?^@RQrzpt*cIe0cJWFn#al7A#%xEfi-a z6Ml6}>p~12LT{B8zScg>D#y3g%fn0d?GOg%)q_9zq;|e2hRFW~grq-$j`L@fg}v~- zT+hF|umMB{byWrO(AvJr_i^B%vHhSMD@y_A>pVtZ(c95e(*4M$I-$4#=3-PzNeY^Y1%5@4-!Z{Mpn)7kjF5}d*=)RrF|vz`Ce{Y?hO^jL%BsrU zRlf!_$v)iaq-G03tX9>xdsxUtJx(44xgg3!63;qXLLe1m!e`H?hXS2^0#)5&(X|(q z%gL)2vNK{oS?Hsw$NTJch&GVBrMpW>QD{tyOy+v8t+KI?nwchiW79{Ov}c+}bOo54 zBP>`xN9VtXK=pTuw5f`@6}^MPZ2}!p2d9&$Z0wh$2bKKN>iN}JMqaL>{O|+j6cv_B zD^u|xu=83|tt83e%@u<_0ju{U34FXo9F6!{f_f@QE~{kxJ%_r~3INE#hwwQoUuPR$ zzkO(PLGrI+cM!&=JH7x_ngTv2AF`F=^QW5i9_Wo_)5OjX&Tq6H-BixT<$ONtvdR9U z;Y_nS@_Tq<^R!y+@Y``$vZrnvJ49UW%GUDyKq>j7l+DD#I&l44NF z(G({&>?jA6u8pYL(cWlaT>2V-?H=)o!8l+fH@v{`zCK4uf6N1KPs@PjP1v8b76I2E zj$@;`sLNexyFwA)fseYsY@gRx5k@m`BguXRhC3ofeH=^G;%xz+S@P+n@Z)G>sXtWY zh8}ozarN=in#Kz5UH@6)qhstGiFXaw%YENkrk4GR-dPsZWNJLO3I0)b2K(i#M&{}N z417b>5hMGNHRMaB)xl;DMKE>rpT;Bhu~xIrMdf~_4tU(;^9uEirg%xN_DJs6GO5-S zM%L9FsdE#wuuRl!gTrECT}Pxy#@E-R-V4O*Hf+@XOD)ushicz&0>y@eBCPrv9lqdP zYN~k$DYP276Uu{nz4R+~Fiqv?HJ>ed1RabrMo}eEgJphW?&+JdOAfR27F`o($jK zKBXZVvQ>K}xGF%IFCu$i`eLx0?@TcC#437+_Il{E{=30Mu21J?(mC+^`173GU|3kw zBT~Cp@<{7Rz7CS})LO#Wp=vBh*)XE0UEkE;J`9)m7CVdL~z6vknW=AVr1fwZA<9Pl?x z9kH4{R8pL%$fRWv(+E-NL}xb-tt0)i$1^O9Xz)U({D3g?Cg<$P3w9u3g=K8 zmG5q19e*=WR^*40b5_MWKR)%%E7wa6KTfhP{#4!YR2&8JwVBxr4wj4(&yLpD=a8PvPNoomAogv#C(p`o99^o= z@O&!W!9~Z@x9wUhed~=FtSU=*-7&?BZb`MW@xQ*s!<_yCEVY(cl&u&r2qW!IY@mC? zkRaBZROeZ~*zg?g$#;=^bitTEG`p)vu%veIOf%;q`ExTT!cq_!8I@r~%Ia%%c_}zf z9IVp1Z|S|_mVPZ2?l$}5(J-Thr|k8p*^w|K^WyR@h)cFse&)Yna{u*-`Z5BVy+BeT zq5ngYl+hgzngNCYA?zeASc>oSx&kv}C$s}bL%)=Rj%?gczLKXZIN80Xm%!`u=CVnR2lZrJ zIQF6Yt50+Z1G zcjlHPoCi?vyoop`75$o!4EEDw+Pc16Wvn4ofI5G(2G^FJ%GEn&!<#hhj=unIJndZh zQL2ruP9K1hgf$+e<;81SCZ^o%-+@O=QbVVi-4$F3L;1mv?VxW{9xUEDXg_$P-bZCU_i)=8__Q-@ zl#f#-HVdnjsT82)6B~mWWii}l3|{HpM1bvVIc&sd5JIyl*|-KwI>y^Ufzy2YQ@h45~B5xuWJfb&{? zA=M06X`)W&bnFYaO=GZkdxT_A>nvYU7X5pvtQ;NJ2G6=kP7C4hMfLq!Wl7vUz>#ic z>LcMWwjkNIzAvVAU0bURCVfg$7~6ge2HYga zzf*kCZW+-&6dxt>Q17oC>dhx%#S8b)FA}@sIbFuG*pGgiP% zt$o}hedJ|wQfs{8_eG(tucecTFZd5_EQ@w2Z{%?Ni}iMlDG&mv=v`UK+On*1^%ONO z5Zg}Sm2$ICj^31?lTS=Oi{&GdrPw4qDLcUXlTDVDpi!osgJ#_W1!@PinK^abjO9D; z%67gLp-ofoJ#dL7uhdFGf8R_gdw_pMyj`&AZPsQ2nx6Gp>k)B5pSPgJbC7u=EL(JZ z6iUip+h`A1RqRSz;wmIvybb|s-oNIScl@-b+9x4TvZybxRCXOnOVq13{4AXQ;54au z|G7MGnW~ShT1EV6MLZO!W$+eXqHceFa}`QnMJbVOagElU7Z-fZJ_JDPQ=S(moE7w} zhP%Cly>ch;E>oq&q$#4fDd0K3x2;hP7z$;6nr|H~?{8nEpAXUUBMfH_KLn7-}D#7SGb<%U+(Cq*xl-0zJcL$jbH z5ue24-oAP=RbtXqqGV|`U%pSI^D@KYMJ(c3uvX&!+OEjX8S2~pZ(U7RC8*r4qlA#6NNLlk5`@nHtI{Tj z^d@Up9^vEl7a;iMdgiBBsO`kQKi3_nyl>Q!y~ngil2&F3G>;mVlbPW$@Z2kzPGm_s zH}GlbL=&0e9HW36GJ>hn$@(f5-nkEn9a{24Hq+iHj7?O~9MU#cUX612w6b7v zyksHP!>*E?r?d+kWyCQ(#E%?UYj9;)3-MW2C#?BWIcw;rsgTM>*BEuFHpL!lZ$JBJ zhtC#PA(q^v?8?Cz&~=+60Z{L#Ci@Fu`#t-6`DyJ*hwX+*#`Z7ZFMufvWe(c=z>~Vx zR0#6*Yi*|1seSo&Fg#m%!kbP{f`Q=Y;wMZ=mjwuGwEV|h(y>8R>|6-D(=uC|f|`_% z!X0R#9&OMy_d8o=Pn@gWmSR<3Nn%MUJKWdNQ1K|0D?iIQ+hI$tW47&$DO@1t>xuhZ zyOm&NLMh%$;mHFrV?N+8%X8mbU3BkxYB5F@3WTa&`A@GeVW%U=DprfJx9vn@v-}fj zQ;|+W;BTZ`Do_AYx1=6eA0GBmSk+K9(=KssM>g)7`MN>msEmIS?SNe<3^tdL(V~R} z>&SAGxOCcbBUp5|+>!3|Jhk7d*`|7gy+&WnzBy7DbZg(RWl=XX50~CY7EI(4UKZFx zVE|;tToDHtj>(`t>DEDKG5k6b)o)MG9BHZRlB|0Fjlw=`pDn<0`_XEmV>ANZ2j`

    o4*iCTX#cpkB*1T=RwTZA*)0#g41(`Q z_@$nytyvl_f9_$&u6v|>F3as*F%E<(w=5q#_`W++B1=jEt$(p|p}JC#e*Ma}$yABSsk3}$c-GN3<`Q(l2b22D<9?SN08S?>%kAzM9S-PF6D*LN0;+Vq2A==WH_+%iv_>$tifAUTQ1@1Xl0ux zfqtK{HQp}gMQxWhofcQlz~ti{p3k}n(wW%f!JdPC>Zbc4Ma#3U?Oz)Mo(E0$Q?O8w zYv@_j%4Bnf*XK!k^4R(e#_WtvStVm(5a(?K3D`?QHtK7!9X&OFznJ=`bu})_I$EhfOI(X}Q1&#) zHblyM30H&%NS^39I?$zg;G<=566jq$9OzP8fKep_McdpK~6aJ)a zySFe%W69e^wZUQ0cGeasUoZSJb0^k*%!ysBEtLpQh0UECmKZ!OGyRE7_lO(a)u_Q> zWjRK)JI?V+>Zq52X6qa_{l&BU&~%v~RO1i79UWX-h(%HvW7dPPJ)&QegJ(!x%=eh8 zny}K>4!kRdLwQ~v!Rm|qx!&hqq$}S`HCmvxk&kDbzmf~v z{^6X9A3W#TVuxUUcFyf}Z;?;;-jadcrxc>932=u{J>lTE_&K7a>b7u$H`i030(7O;x9KPd@ zftyk0m?!0nO)&&=eM9Bl<6>2Um+z}7gyy^U8$RK7is_>JN>2lqaB>Ajl$kq^O=8N1 ztTt3RR#mcHH^kA*-=OZK-fQN?u8JEyYC-Brq99w+j}K+Qhmi@h=ePL~ zA}C$pqiXivAal%hv_%hQk84;|q0&I)Fdu^2FHN^h>w%|AG$uBJFhWe_=-}w>W2Ws( zPG%X(-Q$;L5+CM{NxSwJRMJ`4k+qGt^NVTeLA|4?78+zo8I}`4t}gBwqmz(5(k#!d{=7zg3sGKy(5sH zpeD1G5ZyFXMCAxHE@cZyRi(v%6yD8@lW?G(y(Y6HvPuA@lV6U~T8Fz~ zJ)ezEO5g{ELQ4Z9uw52V9jmL6sj|sj6B*ZdRcL~290Dby8|-3{#RrTkP$XyCktRTy z6oSp0;c^>4;&EYrW(QM~2`QFzHkm&zac;S}DdU7XxJvOGffha5M^OYO8)-#d2wQ z_Y$tur+*#MMiPU?+Lcz~Ae>OFSCqb;k*^w~tr}8vhlP&Iq}gs5*@Rn33j9N7&liLs z?bH^!{ScgM$1&f_Q~@S+WG;_BERRUB^5`9_PDayMC>GZ3Q4ZK1L3nj$yFw?$88yPn zZB}FVO+Yimn0hh=N17e!p94p`AR8Z=APt2FFnMNEt7A#ji%Z;{aRwmpb50W=!;xdf_}x_Nd&XB_90N_7Z5#G$toj{CLHd?yAc zb{a8RVa-2ct=*@!k0@P5Q9`c5sfXWB)yBljujE10wGTEwu44<#Bhd@c6}IF@508b3#csp!KXKVY120 zWrt{`2{bJQm!Wa^Xh+9m1xFSU;o;a*G5nrX#p)`C&N87MywXi+NSeWuQ`Odas8^^!i+7czV`O~0sry>$UBqM+2W<^iOqg(D-haQiwJ-T09ZZ8bOjpKjpi8ay46|GC z;PSgoda_RAkEJ@1@?s&3o=D_b83mUl6koOApWk8>LxmQHUlj1oOyeO=m%A5zEu~6~ zQ_`YgcvukD2whS|q;`YxfOj-1(*hBd{HSGw5I7qYud*F(aoV2SgxxKyOq< zrO1C@s(Bozo4OiF+P9;MTXr*3>ArOg95c5dwTkgvxWQ3tsB_Ry+$Xeu8#$<=J z_zP)Y9cPVJ6=zE#3>U?iD|=OoOWkTjYq2Aco}7pW>X;pJ><0D7!Yf~AzQA;^ycfpL zpgDTJ)Qd4!{-&u#CuJXt>K#MECSH=tW@mkQap~RZgTom{J4B1#AUDY3ILdL!_{3jS(FwqiQjuKKReV) zA73hVb^kf9Zo9L#R{X-~&Fn_85Dy4PT~90Z;g4Lgd|6QCF9W^;VsGHTqJ^Fg)zXfJ z{AJSv%&+BZo5Hy&lYF-n#kdPD%Mjc_$E{-A0n>^FR57kXr+l$pqR>4(xBbTD513A% z}@EzTWux(dSq__^1WWkhn(Fjl8ihb&~2UHZwae>!+X}U2JdM!pYPXeNePS z6SmqZaE`V@9(;Qh)Y(%msc`;2ZF)>im64A|f!FPZ46}E~H#?9}q-nj!Dl%jNSfZMQ z(0qIE_tA2tj_Sn?+3{`Ap`hDYc%2W*n*iorz^API zWUB^Vu__%VZTGuXZFi_~mwsy{9H?-YUT1}otC2g;F3B-)e9U9qrTd}T3@rqLRZJkn z;$#P&S)Y-B)T1=ckRg)x8^v-;DY5{}TOT{H*7sntu0;QvhRdh-UhK!nMM-5!o^|_L z{8IbY^o>fEG-W!^kgY1P;C!XM@ei<2gu0G}&*~fOVa<#pBKn|raj?Kux4!^f2?{j-$z@F#gZ%Nw zp{dDzTz$g{K9h^@6Ton$WGr4fnt#7n#((1MLv*~c%{(~S&up1On~`7q9!I;($lA~| z;?2|dzEv8Prq|h*H-o9KS-c`#*nNFJvP;n8;|B@>wq!_A# zY6Ae$2o>FhMa~8?jHzuiJUKY$&|+=Rx42KO8kk^b`3tHOcX`*(46nktDx)C5h?x#( zkNJAKd*`%~hguH4Nkey2@cg&x!cU(acF1)RwzI*9Zf_294OJdM5j=KJYluTKYt{mo z`L)3v$x?Y_0nFfkte8Nm^vjQiGo~8IKi2R+rv85!m_{WWqaIPXy7G800000 literal 0 HcmV?d00001 diff --git a/include/javascript/yui3/assets/yui.css b/include/javascript/yui3/assets/yui.css new file mode 100644 index 00000000..8cbdcc99 --- /dev/null +++ b/include/javascript/yui3/assets/yui.css @@ -0,0 +1,719 @@ +/* +Copyright (c) 2007, Yahoo! Inc. All rights reserved. +Code licensed under the BSD License: +http://developer.yahoo.net/yui/license.txt +version: 2.4.0 +*/ +html{color:#000;background:#FFF;}body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,code,form,fieldset,legend,input,textarea,p,blockquote,th,td{margin:0;padding:0;}table{border-collapse:collapse;border-spacing:0;}fieldset,img{border:0;}address,caption,cite,code,dfn,em,strong,th,var{font-style:normal;font-weight:normal;}li{list-style:none;}caption,th{text-align:left;}h1,h2,h3,h4,h5,h6{font-size:100%;font-weight:normal;}q:before,q:after{content:'';}abbr,acronym {border:0;font-variant:normal;}sup {vertical-align:text-top;}sub {vertical-align:text-bottom;}input,textarea,select{font-family:inherit;font-size:inherit;font-weight:inherit;}legend{color:#000;} + +body {font:13px/1.231 arial,helvetica,clean,sans-serif;*font-size:small;*font:x-small;}table {font-size:inherit;font:100%;}pre,code,kbd,samp,tt{font-family:monospace;*font-size:108%;line-height:100%;} + + +/** + * Nudge down to get to 13px equivalent for these form elements + */ +select, +input, +button, +textarea { + font:99% arial,helvetica,clean,sans-serif; +} + +body{text-align:center;}#ft{clear:both;}#doc,#doc2,#doc3,#doc4,.yui-t1,.yui-t2,.yui-t3,.yui-t4,.yui-t5,.yui-t6,.yui-t7{margin:auto;text-align:left;width:57.69em;*width:56.301em;min-width:750px;}#doc2{width:73.074em;*width:71.313em;}#doc3{margin:auto 10px;width:auto;}#doc4{width:74.923em;*width:73.117em;}.yui-b{position:relative;}.yui-b{_position:static;}#yui-main .yui-b{position:static;}#yui-main{width:100%;}.yui-t1 #yui-main,.yui-t2 #yui-main,.yui-t3 #yui-main{float:right;margin-left:-25em;}.yui-t4 #yui-main,.yui-t5 #yui-main,.yui-t6 #yui-main{float:left;margin-right:-25em;}.yui-t1 .yui-b{float:left;width:12.3207em;*width:12.0106em;}.yui-t1 #yui-main .yui-b{margin-left:13.3207em;*margin-left:13.0106em;}.yui-t2 .yui-b{float:left;width:13.8456em;*width:13.512em;}.yui-t2 #yui-main .yui-b{margin-left:14.8456em;*margin-left:14.512em;}.yui-t3 .yui-b{float:left;width:23.0759em;*width:22.52em;}.yui-t3 #yui-main .yui-b{margin-left:24.0759em;*margin-left:23.52em;}.yui-t4 .yui-b{float:right;width:13.8456em;*width:13.512em;}.yui-t4 #yui-main .yui-b{margin-right:14.8456em;*margin-right:14.512em;}.yui-t5 .yui-b{float:right;width:18.4608em;*width:18.016em;}.yui-t5 #yui-main .yui-b{margin-right:19.4608em;*margin-right:19.016em;}.yui-t6 .yui-b{float:right;width:23.0759em;*width:22.52em;}.yui-t6 #yui-main .yui-b{margin-right:24.0759em;*margin-right:23.52em;}.yui-t7 #yui-main .yui-b{display:block;margin:0 0 1em 0;}#yui-main .yui-b{float:none;width:auto;}.yui-g .yui-gb .yui-u,.yui-gb .yui-g,.yui-gb .yui-gb,.yui-gb .yui-gc,.yui-gb .yui-gd,.yui-gb .yui-ge,.yui-gb .yui-gf,.yui-gb .yui-u,.yui-gc .yui-u,.yui-gc .yui-g,.yui-gd .yui-u{float:left;margin-left:2%;width:32%;}.yui-gb .yui-gb .yui-u,.yui-gb .yui-gc .yui-u{*margin-left:1.8%;_margin-left:4%;}.yui-g .yui-gb .yui-u{_margin-left:.8%;}.yui-gb .yui-u{float:right;}.yui-gb div.first{margin-left:0;float:left;}.yui-g .yui-gb div.first,.yui-gb .yui-gb div.first{*margin-right:0;*width:32%;_width:31.7%;}.yui-gb .yui-gc div.first,.yui-gb .yui-gd div.first{*margin-right:0;}.yui-gb .yui-gd .yui-u{*width:66%;_width:61.2%;}.yui-gb .yui-gd div.first{*width:31%;_width:29.5%;}.yui-g .yui-gc .yui-u,.yui-gb .yui-gc .yui-u{width:32%;_float:right;margin-right:0;_margin-left:0;}.yui-gb .yui-gc div.first{width:66%;*float:left;*margin-left:0;}.yui-gb .yui-ge .yui-u,.yui-gb .yui-gf .yui-u{margin:0;}.yui-g .yui-u,.yui-g .yui-g,.yui-g .yui-gb,.yui-g .yui-gc,.yui-g .yui-gd,.yui-g .yui-ge,.yui-g .yui-gf,.yui-gc .yui-u,.yui-gd .yui-g,.yui-g .yui-gc .yui-u,.yui-ge .yui-u,.yui-ge .yui-g,.yui-gf .yui-g,.yui-gf .yui-u{float:right;}.yui-g .yui-gc div.first,.yui-g .yui-ge div.first,.yui-g div.first,.yui-gc div.first,.yui-gc div.first div.first,.yui-gd div.first,.yui-ge div.first,.yui-gf div.first{float:left;}.yui-g .yui-g .yui-u,.yui-gb .yui-g .yui-u,.yui-gc .yui-g .yui-u,.yui-gd .yui-g .yui-u,.yui-ge .yui-g .yui-u,.yui-gf .yui-g .yui-u{width:49%;*width:48.1%;*margin-left:0;}.yui-g .yui-g div.first{*margin:0;}.yui-gb .yui-g div.first{*margin-right:4%;_margin-right:1.3%;}.yui-gb .yui-gb .yui-u{_margin-left:.7%;}.yui-gb .yui-g div.first,.yui-gb .yui-gb div.first{*margin-left:0;}.yui-gc .yui-g .yui-u,.yui-gd .yui-g .yui-u{*width:48.1%;*margin-left:0;}.yui-g .yui-u,.yui-g .yui-g,.yui-g .yui-gb,.yui-g .yui-gc,.yui-g .yui-gd,.yui-g .yui-ge,.yui-g .yui-gf{width:49.1%;}.yui-g .yui-gb div.first,.yui-gb div.first,.yui-gc div.first,.yui-gd div.first{margin-left:0;}.yui-g .yui-gc div.first,.yui-gc div.first,.yui-gd .yui-g,.yui-gd .yui-u{width:66%;}.yui-gd div.first,.yui-gb .yui-gd div.first{width:32%;}.yui-g .yui-gd div.first{_width:29.9%;}.yui-ge .yui-u,.yui-ge .yui-g,.yui-gf div.first{width:24%;}.yui-gb .yui-ge div.yui-u,.yui-gb .yui-gf div.yui-u{float:right;}.yui-gb .yui-ge div.first,.yui-gb .yui-gf div.first {float:left;}.yui-ge div.first,.yui-gf .yui-g,.yui-gf .yui-u{width:74.2%;}.yui-gb .yui-ge .yui-u,.yui-gb .yui-gf div.first{*width:24%;_width:20%;}.yui-gb .yui-ge div.first,.yui-gb .yui-gf .yui-u{*width:73.5%;_width:65.5%;}#bd:after,.yui-g:after,.yui-gb:after,.yui-gc:after,.yui-gd:after,.yui-ge:after,.yui-gf:after{content:".";display:block;height:0;clear:both;visibility:hidden;}#bd,.yui-g,.yui-gb,.yui-gc,.yui-gd,.yui-ge,.yui-gf{zoom:1;}.yui-gb .yui-u{float:left;} + +#doc4 { + clear:left; +} +#headerContainer { + min-width:65em; +} + +blockquote,ul,ol,dl { + margin:1em; +} +ol,ul,dl { + margin-left:2em; +} +ol li { + list-style: decimal outside; + margin-bottom:1em; +} +ul li { + list-style: disc outside; +} + +/*begin YDN/YUI styles*/ + + +/*a, a code {color:#0000de;} */ +a:visited, a:visited code {color:#639;} +a:active, a:active code {color: #f00;} + +h1 a { color:#E76300; } +h1 a:visited {color:#E76300} + +#logo_pane { display: none; } + +#ygma { margin:.5em auto 1em auto; } + +/*#bd ul li {margin-bottom:1em;}*/ +#bd ul li ul {margin-top:0;margin-bottom:0;} +#bd ol {} +#bd ol li p { margin-left:0} +#bd ol li ol {list-style:lower-alpha} +#bd ol li ol li {margin-bottom:1em} +#bd ol li ol li ol{list-style:lower-roman} +#bd ol li ol li ol li {margin-bottom:1em} + +#bd p.errormessage {background:url(http://l.yimg.com/a/i/us/search/gr/alertbubble.gif) 0 0 no-repeat; padding-left:30px; margin:2em 2em 2em 1em; font-weight:bold;} + + +h2.classname { border-top:none; margin-top:0; margin-bottom:.2em; font-size: 130%; color:#000;} +h3.breadcrumb { border-top:none; margin-top:0; margin-bottom:.2em; font-size: 80%; color:#000;} +h3.methods { border-top:none; margin-top:0; margin-bottom:.2em; font-size: 100%; color:#000;} + +.screenshot {border:thin solid #999999; margin:8px;} + + +#ft { margin-top:4em } +#ft p { padding-bottom:2em; margin:0; text-align:center; font-size:80%; line-height:1.4em} +#ft p.first { padding:1em 0 0 0; margin:0; } + +#pagetitle {background:#fff url(../assets/gradient-mod.png) repeat-x;border-color:#D9D9D9;margin-bottom:10px;clear:both;} +#pagetitle h1 {padding:4px;margin:0; color:#333; font-size:123.1%; font-weight:bold; position:relative;} +#pagetitle h1 em {color:#FF9933; font-size:60%; font-weight:bold; font-style:normal; position:relative;} + + + +#ygunav {background:#eee; border-bottom:2px solid #ccc; padding:0 10px;font-size:78%;text-align:right;margin-bottom:6px;height:2.5em;line-height:2.5em;} +html>body #ygunav {overflow:hidden;} +#ygunav strong {font-family:verdana;} +#ygunav p {display:inline;margin:0;padding:0;} +#ygunav p em {float:left;text-align:left;font-style:normal; padding-top:.7em} +* html #ygunav p em {margin-top:1px;} +#ygunav p em i {visibility:hidden;} +#ygunav a {color:#000;} +#ygunav form {display:inline;margin:0 0 0 1em;} +#ygsp {width:8em;font-size:110%;padding:0;vertical-align:middle;} +#ygunav .ygbt {background:#dcdcdc;font:110% verdana;position:relative;top:1px;} +* html #ygunav .ygbt {top:4px;} +* html>body #ygunav .ygbt {line-height:0;top:-4px;} +#ygunav label {color:#666;font-family:tahoma;top:1px;} + +#bd ol.getstarted { margin:0; padding:0; } +#bd ol.getstarted li { font-weight:bold; color:#668AA8; margin-bottom:1em; padding-left:20px; list-style-type:none;} +#bd ol.getstarted li p { color:#000; font-weight:normal; margin:0 0 0 20px; padding:0 } + +code {font-family:"Courier New", monospace; font-size: 100%;color:inherit;} +p code {color:#000;} +a code {color:inherit;} + +/*div.apisummary {height:auto; margin:10px 0; width:auto; zoom:1;} +div.apisummary table {font-size:inherit;font:100%; border-collapse:separate; border:1px solid #666666; border-left:none;} +#doc3 div.apisummary table td, #doc3 div.apisummary table th {padding:.35em; vertical-align:top;} +div.apisummary table th { background:#B6CDE1; color:#fff; vertical-align:top; font-weight:bold;} +div.apisummary table td { border-top:1px solid #666666;} +div.apisummary table td, div.apisummary table th { border-left:1px solid #666666;} +div.apisummary table tr { background-color:#ddd;} +div.apisummary table tr.odd { background-color:#fff; } +div.apisummary table tfoot tr { background-color:#fff; } +*/ +dl#menuwidgets dt {font-weight:bold;} +dl#menuwidgets {margin:0 0 0 1.5em;} +img.example {clear:right;margin-bottom:10px;margin-left:10px;border:0;float:right;border:1px solid #999;} + +/*YUI theater box on main page top right corner*/ +#yui-theater {width:316px; overflow:hidden;} +#yui-theater h3 {margin:0; padding:0; color:#E76300; font-size:100%; font-weight:bold; font-stretch:expanded;} +#yui-theater h2 {margin:0 0 10px 0; padding:0; border:none; color:#000; font-size:122%; font-weight:bold;} +#yui-theater p {margin:7px 0 0 0;} +#yui-theater div {float:right; font-size:85%;} + +/*rss reader styles*/ +p.loading-content {background-image:url(http://l.yimg.com/a/i/ydn/yuiweb/img/busy_arrow.gif); background-position:top left; background-repeat:no-repeat; height:20px;padding:4px 0 0 25px; margin:0;} +img.icon-rss {display:inline;border:none !important;position:relative;top:2px;left:1px;} + +#index-secondary {width:316px;float:right;margin-left:10px;} + + +/*styles for right gutter on component pages*/ +#componentvideo img {margin:.5em 0 .2em 0; border:1px solid #999;} +.example-container h4 {margin:0.2em 0 .1em 0; color:#668AA8; font-size:92%;} +#examples p, #componentvideo p {font-size:85%; margin:0 0 .2em 0;} +#examples li.selected {font-weight:bold;} + +/*styles for example pages*/ +/*.example .promo {background-color:#89d;border-color:#666666; padding:1em;}*/ +/*.example .promo h1, .example .promo h2, .example .promo h3 {color:#FFCC66;}*/ +/*.example .promo h1 {font-size:159%; padding-top:0; margin-top:0;}*/ +.exampleIntro, .exampleIntro p, .exampleIntro a, .exampleIntro a code {color:#fff;} +.example .promo p {margin-top:.7em;} +.firstContent {margin-top:0; padding-top:0;} +#logger {margin-top:1em;} +.example-container {background-color:#F1F6F7;} + +.example-container .bd {padding:1em; position:relative; z-index:1; zoom:1;} +.example-container .bd .bd {padding:0; position:static;} /* Reset to defaults to ensure styles are only applied to the top-level .bd of .example-container */ +.example-container>.bd:after {content:'.';visibility:hidden;clear:left;height:0;display:block;} +.example-container .exampleHd {background: url(example-hd-bg.gif) 0 0 repeat-x #4E4D4C; } +.example-container h3 {margin:.2em 0 .4em 0;} +.example .example-container h1, .example .example-container h2, .example .example-container h3, .example .example-container h4, .example .example-container h5, .example .example-container h6 {color:#E76300; font-weight:bold;} +.example-container a {color:#000;} +.example-container a:visited, .example-container a:visited code {color:#000;} +.example-container a:active, .example-container a:active code {color: #000;} + +#loggerGloss {margin-top:.5em; font-size:85%;} +#loggerDiv {font-size:77%;text-align:left;margin-top:.5em; visibility:hidden; height:280px; } /*gets turned on by script when loaded */ +#loggerDiv.yui-log {padding:.4em;width:96%;background-color:#FBE7D9;border:1px solid #666;font-family:monospace;z-index:9000;} +#loggerDiv.yui-log p {margin:1px;padding:.1em;} +#loggerDiv.yui-log .yui-log-hd {margin:0; padding:0; background-color:#CECCCC;} +#loggerDiv.yui-log .yui-log-hd h4 {display:none;} +#loggerDiv.yui-log .yui-log-bd {width:100%;height:20em;background-color:#FFF;border:1px solid #ECECEC;overflow-y:auto;overflow-x:hidden;} +#loggerDiv.yui-log .yui-log-bd pre {border-top:1px solid #ECECEC;} +#loggerDiv.yui-log .yui-log-bd code p {margin:1px 0;} +#loggerDiv.yui-log .yui-log-ft .yui-log-categoryfilters {margin-top:.5em;clear:right;} +#loggerDiv.yui-log .yui-log-ft .yui-log-sourcefilters {margin-top:.5em;border:none; clear:both;} +#loggerDiv.yui-log .yui-log-btns {margin-top:.2em;padding:.2em;background: url(bg_hd.gif) 0 0 repeat-x #CECCCC; text-align:right; float:none; position:static;} +#loggerDiv.yui-log .yui-log-filtergrp {margin-right:.3em; float:left; display:block} +#loggerDiv.yui-log .yui-log-ft {margin-top:.3em;margin-bottom:.3em; font-family:verdana; zoom:1;} +/*bug in Safari when this is applied to .yui-log-ft:*/ +#loggerDiv.yui-log:after {content:'.';visibility:hidden;clear:both;height:0;display:block;} +.example-container.newWindow {text-align:center;} +p.newWindowButton {text-align:right; margin-top:0; padding:.5em;} +.bd p.newWindowButton {text-align:center;} /*when new window is required and button appears in middle of example body*/ +p.loggerButton {text-align:center;} +#loggerLink a, #newWindowLink a {font-size:115%; font-weight:bold; color:#000099;} +#newWindowLink a {font-size:107%;} +#loggerModule {padding-bottom:.2em;} + + +/*theater page styles*/ +.theater h1 {border-bottom:1px dashed #CCC; margin-bottom:1em;padding-bottom:.2em;} +.theater img {border:1px solid #666;} +.theater img.last {border:1px solid #666;} +.theater p.details {font-size:77%; color:#666; margin:.2em 0 0 0; padding:0;} +.theater p.description, + #doc3 .theater ul li {font-size:85%; margin:0; padding:0; color:#333;} + +#readmePanel .hd { font-weight:bold; font-size:129%; color:#fff; background:#89d; } +#readmePanel .bd {text-align:left; overflow:auto;} +#readmePanel .ft {text-align:right; background-color:#E7E7E7; font-size:85%;} +/* Browser specific (not valid) styles to make preformatted text wrap */ +#readmePanel .bd pre { + white-space: pre-wrap; /* css-3 */ + white-space: -moz-pre-wrap; /* Mozilla, since 1999 */ + white-space: -pre-wrap; /* Opera 4-6 */ + white-space: -o-pre-wrap; /* Opera 7 */ + word-wrap: break-word; /* Internet Explorer 5.5+ */ + font-size: 100%; + color:#000033;} + +/*ed eliot's server-side delicious badge css*/ +#delicious-badge .bookmark { background: url(http://images.del.icio.us/static/img/delicious.small.gif) no-repeat left center; padding-left: 15px; font-weight: bold; } +#delicious-badge p, #delicious-badge div {text-align: center; margin:0;} +#delicious-badge a { color: #00f; text-decoration: none; } +#delicious-badge div { background: #eee; } +#delicious-badge div span { font-weight: bold; color: #000; } +#delicious-badge ul, #delicious-badge li { display: inline; list-style: none; padding: 0; margin: 0;background:none; } +#delicious-badge li { margin-left: 5px; } +#delicious-badge li span { position: absolute; left: -999px; width: 999px; } +#delicious-badge .saved-by { color: #999; } +#delicious-badge .saved-by span { background: #00f; padding: 3px; color: #fff; } +#delicious-badge .be-first { font-size: 85%; color: #999; } +#delicious-badge .tag-size-1 { font-size: 100%; } +#delicious-badge .tag-size-2 { font-size: 107%; } +#delicious-badge .tag-size-3 { font-size: 114%; } +#delicious-badge .tag-size-4 { font-size: 122%; } +#delicious-badge .tag-size-5 { font-size: 129%; } + +/*faq page:*/ +.yui-ge .yui-g {width:98%;} +.yui-ge .yui-g .yui-u {width:48.1%;} +#questions {margin:1em 0 2em 0; padding:0.5em; border:1px solid #838383; background-color:#E6E6E6;} +#questions ul {margin:0; list-style:none;} +#yui-main #questions li {padding-bottom:.2em; font-size:85%; margin:0;} +#questions li a {display:block; padding:.6em; text-decoration:none;} +#questions li a:hover {background-color:#F6F6F6;} + +/*for notes on file includes*/ +.configurator-notice {margin:0;} +#configuratorBadge {display:block; float:right; margin:0 0 10px 10px;} +.include-notice {clear:left; border:1px solid #6F7EA1; background:#eee; padding:.7em;} +.include-notice p.firstP {margin-top:0;} +.include-notice p.lastP {margin-bottom:0;} +.include-notice strong {color:#990000;} +.configurator-notice p {font-size:93%;} + +/*for site search suggest via autocomplete*/ +#ygunav {overflow:visible !important;} +/*#sitesearch {float:right; width:37em; position:relative; text-align:right; z-index:1000;} */ +/*#searchinput {width:15em; font-size:11px; font-weight:bold; position:relative; top:2px;}*/ + +/* v3 modules */ + +/* colors + orange = #FF8800; + green = #89B31F; + teal = #2288BB; + light gray stroke = #D9D9D9; + normal gray text = #666666; + + h1 {font-size:212%;color:#89b31f !important;} + h2 {font-size:153.9%;color:#89b31f !important;} + a {color:#2288bb;text-decoration:none;} + + /yui/assets/bullet4x4.png + /yui/assets/gradient-promo.png + +/* examples swatch + + * C0FFF6 - light blue + * 8DD5E7 - blue + * 00B8BF - teal + * CDCDCD - gray + * CFB192 - tan + * 71241A - brown + * EDFF9F - lime + * FFA928 - yellow/gold + * D00050 - red + * FFA882 - peach + * 53DBA6 - bright purple + * 004C6D - dark blue + +*/ + + +#bar-note { + background:#F2FBFF url(../assets/gradient-promo.png) repeat-x 0 0;padding:3px;margin:0 20px 10px 20px;font-size:85%;clear:both;} +#bar-note strong {font-weight:bold;} +#bar-note a {color:#004C6D;text-decoration:none;font-weight:bold;} +#bar-note a:hover {text-decoration:underline;} +#bar-note p {margin:0;text-align:center;} +span.desc {text-transform:uppercase;font-size:77%;font-family:verdana;display:block;} + +#main {color:#333;} +#main a {color:#2288BB;text-decoration:none;} +#main a:hover {text-decoration:underline;} +#main h1, #main h2, #main h3, #main h4, #main h5, #main h6 {margin:0;} +#main h2 {font-size:212%;color:#89B31F;font-weight:normal;margin:0 0 12px 0;padding:0;} +#main h3 {font-size:153.9%;color:#FF8800;font-weight:normal;margin:0 0 12px 0;padding:0;} +#main h4 {font-size:123.1%;font-weight:normal;color:#FF8800;;margin-bottom:10px;} +#main h5 {font-size:93%;font-weight:normal;text-transform:uppercase;color:#666;border-bottom:1px solid #D9D9D9;margin-bottom:12px;} +#main h5 code {text-transform:none;} +#main h6 {font-size:93%;font-weight:normal;color:#FF8800;margin-bottom:10px;font-weight:bold;} +#main p, +#main form {margin-bottom:1em;} +#main div.clear {clear:both;} +#main strong {font-weight:bold;} +#main em {font-style:italic;} + +#promo, .example .promo {background:#f2fbff url(../assets/gradient-promo.png) repeat-x 0 0;border:1px solid #D9D9D9;padding:13px;margin-bottom:13px;} +#promo p, .promo p {margin-bottom:1em;} +/*#promo ul, .promo ul {margin:0 0 1em 0;padding:0;} +#promo ul ul, .promo ul ul {margin:0;padding:0;}*/ +#promo .yui-u ul {margin:0 0 1em 0;padding:0;} +#promo .yui-u ul ul {margin:0 0 0 0;padding:0;} +/*#promo ul li, .promo ul li {list-style: none;margin:0;padding:0 0 0 15px;background:url(../assets/bullet4x4.png) no-repeat 3px 6px;}*/ +#promo .yui-u ul li, .promo .yui-u ul li {list-style: none;margin:0;padding:0 0 0 15px;background:url(../assets/bullet4x4.png) no-repeat 3px 6px;} + +#main .yui-g {width:100%;} +#promo #quicklinks {} +#promo #jumps {} +#promo h4, .promo h4 {font-size:100%;font-weight:normal;text-transform:uppercase;color:#666;border-bottom:1px solid #D9D9D9;margin-bottom:10px;margin-right:10px;} +#promo code {color:inherit;font-weight:bold;} +#promo .yui-gb {float: left; width: 100%; margin-bottom: 16px;} + +#utilityboxes {} +#utilityboxes .mod {border:1px solid #D9D9D9;} +#utilityboxes .mod .hd, +#utilityboxes .mod .bd {border:1px solid #fff;} +#utilityboxes .mod .hd {background-color:#999;padding:4px 6px 2px 6px;} +#utilityboxes .mod .hd h4 {color:#FFF;border:none;margin:0;font-size:100%;font-weight:bold;} +#utilityboxes .mod .bd {border-top:none;padding:6px;padding-bottom:0;} +#utilityboxes ul {margin:0;padding:0;margin-bottom:1em;} +#utilityboxes ul li {list-style: none;margin:0;padding:0 0 0 15px;background:url(../assets/bullet4x4.png) no-repeat 3px 6px;} +#utilityboxes table td {background:none;padding:0;} +#utilityboxes table {margin:0;} + + +/* for frontpage*/ + +.index-main #download {margin-bottom:2em;} +.index-main #download img {float:left; padding:0 0.5em 0.5em 0;} +.index-main {margin-right:331px;} +.inlay a {display:block;float:right;margin:-10px 0 13px 10px;} + +/* sidebars */ + +.sidebar .mod {margin-bottom:1em;} +.sidebar .mod .bd li, +.sidebar .mod .bd p {font-size:85%;color:#666;} +.sidebar .mod p {margin:1em 0;} +.sidebar .mod li p {margin:0 0 1em 0;} +.sidebar .mod .bd li p {font-size:100%;} +.sidebar .mod h5 {font-size:85%;font-weight:normal;text-transform:uppercase;color:#666;border-bottom:1px solid #D9D9D9;margin-bottom:6px;} +/* lists */ +.sidebar .mod ul {margin:0;padding:0;} +.sidebar .mod li {list-style:none;margin:0;padding:0 0 0 12px;background:url(../assets/bullet-box6x6.gif) no-repeat 0 4px;} +.sidebar .mod a {color:#2288BB;text-decoration:none;} +.sidebar .mod a:hover {text-decoration:underline;} +.sidebar .mod h4 {margin:0;padding:0;line-height:1;} +.sidebar .mod .hd {padding:5px 6px 5px 6px;} +.sidebar .mod .bd {padding:10px;} +.sidebar .mod .ft {padding:0 10px 10px 10px;} + +a#pdf-all {padding-left:16px;background:url(../assets/download-arrow.png) no-repeat 0 0px;} + +.box3 {border:1px solid #D9D9D9;background-color:#F5F5F5;} + .box3 .hd {background-color:#999;} + .box3 h4 {color:#FFF;} + .box3 .bd img {display:block;} + /*inner stroke*/ + .box3 .hd {border:1px solid #fff;border-bottom-width:0;} + .box3 .bd {border:1px solid #fff;border-bottom-width:0;} + .box3 .ft {border:1px solid #fff;border-top-width:0;} + /* for cheatsheet download tracking*/ + .box3 a#pdf-all {padding-left:16px;background:url(../assets/download-arrow.png) no-repeat 0 0px;} + + .box4 {border:1px solid #D9D9D9;background:url(../assets/gradient-mod.png) repeat-x 0 0;} + .box4 h4 {color:#89B31F;} + + + #bd .toc3 {border:1px solid #D9D9D9;background-color:#F5F5F5;} + #bd .toc3 ul {padding:0;margin:0;border:1px solid #FFF;border-top:none;} + + #bd .toc3 li {font-size:85%;list-style:none;list-style:none;margin:0;background:transparent url(../assets/bullet-box6x6.gif) no-repeat 6px 7px;} + #bd .toc3 li.sect {font-size:85%;font-weight:normal;text-transform:uppercase;color:#666; + border-bottom:1px solid #D9D9D9;margin:6px 6px 6px 6px;padding:4px 5px 4px 0;background:none;} + #bd .toc3 li a {color:#2288BB;text-decoration:none;display:block;padding:2px 5px 2px 16px;} + #bd .toc3 li a:hover {text-decoration:underline;} + #bd .toc3 li.selected {background-color:#999;} + #bd .toc3 li.selected a {color:#FFF;} + #bd .toc3 li.selected a:hover {color:#FFF;} + + + /* */ + .example h2 em {font-size:78.5714%;color:#666;font-style:normal;} + .ex-box {border:1px solid #D9D9D9;} + .ex-box .bd {background:#F2FBFF url(../assets/gradient-promo.png) repeat-x 0 0;padding:10px;border:1px solid #FFF;} + .ex-box .ft {background:#F2FBFF url(../assets/gradient-example-ft.png) repeat-x 0 0;border-top:1px solid #D9D9D9;} + + /*left navigation TOC */ + /*#toc {background-color:#ecf5fa; padding:0; border:1px solid #89d } + #toc ul {margin:0; padding:0;} + #toc ul li {list-style:none; padding:0; margin:0; font-size:85%; } + #toc ul li.selected { font-weight:bold; color:#fff; background:#f82; padding:0; } + #toc ul li.selected a { color:#fff; } + #toc ul li a { display:block; padding:2px 2px 2px 10px; text-decoration:none; } + #toc ul li a:hover { color:#fff; background:#e60; } + #toc ul li em { display:none; } + #toc ul li.sect { font-weight:bold; color:#fff; background:#89d; padding:2px 0; text-indent:2px; margin-top:2px;} + #toc ul li.first {margin-top:0;}*/ + + + .apisummary table, + table {width:100%;margin-bottom:1em;} + + .apisummary table tr, + table tr {vertical-align:top;} + + .apisummary table caption, + table caption {display:none;} + + .apisummary table th, + table th {background-color:#6c8ea1;color:#FFF;text-transform:uppercase;font-weight:bold;} + + .apisummary table td, + table td {background-color:#e5edf1;} + .apisummary table tr.odd, + table tr.odd td {background-color:#F5F8F9;} + + .apisummary table th, + .apisummary table td, + table th, table td {padding:5px;border:2px solid #fff;} + + .apisummary table tr {background-color:#f5f8f9;} + dl {margin:0;} + dl dt { + /*giving UL's LIs generated numbers*/ + font-weight:bold;} + dl dd {margin:1em 0 1.5em 1em;} + .dp-highlighter table tr, .dp-highlighter table td {border:0;padding:0;background-color:#FFF;} + table tr {background-color:#fff;} + table td dl {margin:1em 0;} + +.dp-highlighter .line1, .dp-highlighter .line2 {padding-left: 10px;white-space:nowrap;} + +table.auto {width:auto;} +#main .examplesTable h4 {margin:0;color:#FFF;} +#main .promo a {color:#333;} +#main .promo .newWindowButton a {text-decoration:underline;color:#2288BB;} + + +/*for new header treatment*/ + +/*header area*/ +#topMaxCont{width:100%;background:#fff;height:1.7em;} +#topContainer{margin-left:auto;margin-right:auto;/*width:74.8em;*/} +#topIntCont{width:74.8em;float:left;height:1.7em;} +#headerMaxCont{width:100%;height:4.1em;background:url('http://l.yimg.com/a/i/ydn/header-top-bkg.jpg') repeat-x #0066a0;margin-bottom:1em;} +#headerContainer{margin-left:auto;margin-right:auto;height:4.15em;} +#headerMainSandbag {position:absolute;width:100%;height:4.1em;top:0;left:50%;margin-left:-62.1em;} +#headerMainSandbag {background: transparent url('http://l.yimg.com/a/i/ydn/header-top.jpg') no-repeat 50% top;z-index:0;} +#headerSubSandbag {position:absolute;width:123.5em;height:1.9em;top:5.77em;left:50%;margin-left:-62.1em;} +#headerSubSandbag {background: transparent url('http://l.yimg.com/a/i/ydn/header-sub.jpg') no-repeat 50% top;z-index:0;} +.ydnLogo{position:relative;/*left:-2.3em;*/} +#subHMaxCont{width:100%;height:1.9em;background:url('http://l.yimg.com/a/i/ydn/header-sub-bkg.jpg') repeat-x;} +#subHContainer{margin-left:auto;margin-right:auto;width:74.8em;} +#subHIntCont{float:left;position:relative;left:-.76em;bottom:1.6em;width:74.8em;z-index:201;} +#topDropMaxCont{width:100%;height:1.9em;background:url('http://l.yimg.com/a/i/ydn/header-shadow-bkg.gif') repeat-x;margin-bottom:1.8em;} +#topDropContainer{margin-left:auto;margin-right:auto;width:74.8em;} +#topDropIntCont{text-align:left;} +#breadcrumbs{font-size:92%;height:1.2em;width:74.8em;float:left;text-decoration:none;margin-left:0;padding:0;position:relative;top:-1em;} +#breadcrumbs a{text-decoration:none;color:#2288bb;} +#breadcrumbs a:hover{height:2em;float:left;text-decoration:underline;} +#bcSep{float:left;width:1.5em;height:1.5em;background:url('http://l.yimg.com/a/i/ydn/bcsep.gif')no-repeat;position:relative;bottom:3px;margin-right:.5em;} +#bcItem{float:left;margin:0 .5em 0 0} +#breadcrumbs a.bcOn{color:#888;} +#topAreaL{float:left;color:#9f9f9f;font-size:85%;padding:6px 0 0 0;width:500px;} +#topAreaL ul li{float:left;margin-left:8px;padding-left:8px;border-left:1px solid #dfdfdf;} +#topAreaL ul li.first{float:left;margin-left:0; border-left:0;} +#topAreaL strong{margin-left:60px;font-weight:bold;} +#topAreaR{float:right;color:#9f9f9f;font-size:85%;padding:6px 0 0 0;display:block;} +#topAreaR ul li{float:left; margin-left:8px; padding-left:8px; border-left:1px solid #dfdfdf;} +#topAreaR ul li.first{margin-left:0; border-left:0;} +#topAreaR strong{margin-left:0px;font-weight:bold;margin-right:40px;} + +#ydnNav{float:left;padding:.4em 0;} +#ydnNav .yuimenubaritemlabel {float:left;color:#fff;font-weight:bold;text-transform:uppercase;text-decoration:none;} +#ydnNav .yuimenubaritemlabel-hassubmenu-selected {background:url('http://l.yimg.com/a/i/ydn/top-nav-arrow-off.gif') no-repeat .13em .8em ;z-index:181;} +#ydnNav .yuimenubaritemlabel em{position:relative;color:#fff;font-weight:bold;font-style:normal;} +#ydnNav li a:hover {color:#fff;} +#ydnNav ul li.yuimenubaritem{padding:0 .5em;background:url('http://l.yimg.com/a/i/ydn/top-navsep.gif') no-repeat;} +#ydnNav ul li.first-of-type{background:0;padding-left:0;margin:0;} +#ydnNav li .yuimenu a {color:#28b;text-decoration:none; font-size:120%; padding-bottom:.3em;z-index:182;} +#ydnNav ul li.first-of-type{background:none;} +#ydnNav .yuimenubaritemlabel-selected{background:url('http://l.yimg.com/a/i/ydn/nav-hover-bg.gif') repeat-x;z-index:180;} +#ydnNav li .yuimenu a:hover {color:#28b;text-decoration:underline;} +.lowerc{text-transform:lowercase;} +.dropArrow{margin-left:.3em;margin-bottom:.13em;display:inline;} +.innerSubMenuArea{background-color:#f5f5f5;background:url('http://l.yimg.com/a/i/ydn/nav-submenu-drop-bg.gif') repeat-x top #f5f5f5;padding:.8em .8em;font-size:85%;text-align:left;border-top:0;z-index:183;border-top:1px solid #fff;} +.yuimenu .bd ul{float:left;min-width:8em;max-width:16em;margin-right:2em;} + +.submenuindicator{display:none;} +.subMenuH{color:#6BAE00;text-transform:uppercase;font-size:114%;font-weight:bold; padding-bottom:.3em;} +.yuimenu .x1,.yuimenu .x1a,.yuimenu .x2,.yuimenu .x2a {display:block;background:url('http://l.yimg.com/a/i/ydn/glow.png') no-repeat;_background:transparent;width:100%;height:100%;position:absolute;} +.yuimenu .x1{background-position:0 0;z-index:-2;top:-10px;left:-10px;bottom:0;padding:0 10px 10px 0;} +.yuimenu .x1 .x1a {height:10px;width:10px;background-position:100% 0;right:-10px;top:0;} +.yuimenu .x2 {background-position:100% 100%;z-index:-1;bottom:-10px;right:-10px;padding:10px 0 0 10px;} +.yuimenu .x2 .x2a {height:10px;width:10px;background-position:0 100%;left:-10px;bottom:0;} +#innerMenuL{float:left;min-width:8em;max-width:16em;margin-right:2em;} +#menuColContainer{float:left;} + +#headeraL{float:left;color:#9f9f9f;font-size:85%;padding:.23em 0;} +#headeraL ul li{float:left; border-left:1px solid #dfdfdf;} +#headeraL ul li.first{float:left;margin-left:0; border-left:0;} +#headeraL strong{margin-left:4.6em;font-weight:bold;} + +#headeraR{float:right;color:#86cdf5;padding-right:10px;} +#headeraR ul li{float:left; margin-left:8px; padding-left:.7em; border-left:1px solid #86cdf5;font-size:85%;font-weight:bold;} +#headeraR ul li.first{border-left:0;} +#searchArea{z-index:190;position:relative;margin-top:1.2em;width:29em;text-align:right;} +ul.srchOptns li{margin-top:.3em;} + + + + /*new footer*/ + + /* begin footer area */ + #footermainCont{width:100%;} + #footerMaxCont {width:100%;clear:both;background-color:#eaeaea;border-top:1px solid #fff;} + #footerInternal{float:left;text-align:left;} + #footerBotMainCont{width:100%;} + #footerBotMaxCont {width:100%;clear:both;background-color:#fff;border-top:1px solid #fff;} + #footerBotContainer{margin-left:170px;margin-right:auto;background:#fff;} + #footerBotInternal{float:left;text-align:left;} + #ydnfoot{border-top:0;} + #ydnfoot{background:#f2f2f2;text-align:left;} + #ydnfoot a{text-decoration:none;color:#2288bb;} + #ydnfoot a:hover{text-decoration:underline;color:#19577D;} + #ydnfoot_top{background:#eaeaea;color:#acacac;} + #ydnfoot_top p, #ydnfoot_top strong {} + #ydnfoot_top h3 {font-weight:bold;text-transform:uppercase;font-size:120%;color:#fff;} + #ydnfoot h2 {font-weight:bold;text-transform:uppercase;font-size:120%;color:#000;} + #ydnfoot_mid{background:#f5f5f5;} + #ydnfttopL{float:left;width:157px;} + #ydnfttopR{float:left;width:137px; margin-left:0;} + #ydnfttop2L{float:left;width:100px;} + #ydnfttop2R{float:left;width:100px; margin-left:0;} + #ydnfttop2LL{float:left;width:100px;} + #centr1, #centr2, #centr3, #centr4, #centr5, #centr6 {font-size:85%;float:left; width:108px;} + #ydnfoot strong{font-weight:bold;} + #ydnfoot ul{padding:0;list-style-type:disc;list-style-position: inside;} + #ydnfoot li{color:#2288bb;list-style-type:disc;} + #ydnfoot_top dt{margin-top:.3em;} + #ydnfoot_mid dt{margin-top:1em;} + #devcentL, #devcentR {padding:1em 1em 0 0;} + #devcentL{float:left;} + #devcentR{float:left;} + #ydnfoot_bot{float:left;color:#666;font-size:86%;width:989px;padding:1em;border-top:1px solid #fff;} + #ydnfoot_bot a:hover, #ydnfoot_top a:hover{text-decoration:underline;color:#000;} + #ydnfoot .ftbtmL{float:left;} + #ydnfoot .ftbtmR{float:right;} + #fthrline{float:left;width:100%;} + #ydnfoot .midlsect{border-right:1px solid red;} + #boxtop1{float:left;width:311px;border-right:1px solid #fff;padding:13px;height:7em;} + #boxtop2{float:left;width:311px;border-right:1px solid #fff;padding:13px;} + #boxtop3{float:left;width:311px;padding:13px;} + #boxmid1{float:left;border-right:1px solid #fff;padding:13px;width:655px;} + #boxmid2{float:left;border-right:1px solid #fff;padding:13px;width:655px;} + #boxmid3{float:left;padding:1em 0 1em .3em;} + + + #footer3 {clear:both;background:url('http://l.yimg.com/a/i/us/ydn/tiy.gif') no-repeat top right;margin:20px 10px 10px 0;height:20px;} + #footer3legal {padding-left:190px;padding-right:136px;padding-top:5px;} + #footer3legal p {color:#BBB;font-size:93%;} + #footer3legal a {color:#28b;text-decoration:none;} + #footer3legal a:hover {text-decoration:underline;} + + /* end footer area*/ + + + +/* IE6 hack for 3 column layout */ +#infra.yui-u { + *width:31%; +} + + +/* updates for pr2 */ + +#main ul.topiclist p.topic {margin:0 0 1em 0;font-weight:bold;} +#main ul.topiclist p {margin:0 0 1em 0;} +#main dl dt code {font-weight:bold;color:#333;} +div.wideimage {margin-bottom:1em;} +#downloadbtn { + border:1px solid #fff;border-bottom:none; +} +#downloadbtn a { + margin:10px; + border:1px solid #89B31F; + background-color:#fff; + display:block; + font-size:93%; + color:#004C6D; + line-height:2em; + padding:0 10px; + text-decoration:none; + text-align:center; +} +#downloadbtn a:hover { + text-decoration:underline; +} + +/* New syntax Highlighter Core */ +.yui-syntax-highlight { + background-color: #F5F5F5; + border: 1px solid #D9D9D9; + padding: .75em; + overflow-x: auto; + position: relative; + margin-bottom: 15px; + _width: 97%; + _margin-bottom: 1.5em; +} + +.yui-syntax-highlight .numbers { + display: none; +} + +.yui-syntax-highlight-linenumbers .numbers { + display: block; +} + +.yui-syntax-highlight-linenumbers .nonumbers { + display: none; +} + +.yui-syntax-highlight ol { + margin-top: 0; + margin-left: 2em; +} + +.yui-syntax-highlight ol li { + margin-bottom: 0; +} + +.yui-syntax-highlight textarea { + display: none; +} + +.yui-syntax-highlight .syn-header { + position: absolute; + right: 5px; + top: 0; + background-color: #F5F5F5; +} +.yui-syntax-highlight .hidden { + visibility: hidden; + position: absolute; + top: 0; + left: 0; + height: 0px; + width: 0px; + background-color: red; +} + +/* HTML Colors */ +.yui-syntax-highlight .html4strict {font-family:monospace;} +.yui-syntax-highlight .html4strict .imp {font-weight: bold; color: red;} +.yui-syntax-highlight .html4strict .kw2 {color: #000000; font-weight: bold;} +.yui-syntax-highlight .html4strict .kw3 {color: #000066;} +.yui-syntax-highlight .html4strict .es0 {color: #000099; font-weight: bold;} +.yui-syntax-highlight .html4strict .br0 {color: #66cc66;} +.yui-syntax-highlight .html4strict .sy0 {color: #66cc66;} +.yui-syntax-highlight .html4strict .st0 {color: #ff0000;} +.yui-syntax-highlight .html4strict .nu0 {color: #cc66cc;} +.yui-syntax-highlight .html4strict .sc-1 {color: #808080; font-style: italic;} +.yui-syntax-highlight .html4strict .sc0 {color: #00bbdd;} +.yui-syntax-highlight .html4strict .sc1 {color: #ddbb00;} +.yui-syntax-highlight .html4strict .sc2 {color: #009900;} +.yui-syntax-highlight .html4strict span.xtra { display:block; } + +/* Javascript Colors */ +.yui-syntax-highlight .javascript {font-family:monospace;} +.yui-syntax-highlight .javascript .imp {font-weight: bold; color: red;} +.yui-syntax-highlight .javascript .kw1 {color: #000066; font-weight: bold;} +.yui-syntax-highlight .javascript .kw2 {color: #003366; font-weight: bold;} +.yui-syntax-highlight .javascript .kw3 {color: #000066;} +.yui-syntax-highlight .javascript .co1 {color: #006600; font-style: italic;} +.yui-syntax-highlight .javascript .co2 {color: #009966; font-style: italic;} +.yui-syntax-highlight .javascript .coMULTI {color: #006600; font-style: italic;} +.yui-syntax-highlight .javascript .es0 {color: #000099; font-weight: bold;} +.yui-syntax-highlight .javascript .br0 {color: #009900;} +.yui-syntax-highlight .javascript .sy0 {color: #339933;} +.yui-syntax-highlight .javascript .st0 {color: #3366CC;} +.yui-syntax-highlight .javascript .nu0 {color: #CC0000;} +.yui-syntax-highlight .javascript .me1 {color: #660066;} +.yui-syntax-highlight .javascript span.xtra { display:block; } + +/* CSS Colors */ +.yui-syntax-highlight .css {font-family:monospace;} +.yui-syntax-highlight .css .imp {font-weight: bold; color: red;} +.yui-syntax-highlight .css .kw1 {color: #000000; font-weight: bold;} +.yui-syntax-highlight .css .kw2 {color: #993333;} +.yui-syntax-highlight .css .co1 {color: #a1a100;} +.yui-syntax-highlight .css .co2 {color: #ff0000; font-style: italic;} +.yui-syntax-highlight .css .coMULTI {color: #808080; font-style: italic;} +.yui-syntax-highlight .css .es0 {color: #000099; font-weight: bold;} +.yui-syntax-highlight .css .br0 {color: #00AA00;} +.yui-syntax-highlight .css .sy0 {color: #00AA00;} +.yui-syntax-highlight .css .st0 {color: #ff0000;} +.yui-syntax-highlight .css .nu0 {color: #cc66cc;} +.yui-syntax-highlight .css .re0 {color: #cc00cc;} +.yui-syntax-highlight .css .re1 {color: #6666ff;} +.yui-syntax-highlight .css .re2 {color: #3333ff;} +.yui-syntax-highlight .css .re3 {color: #933;} +.yui-syntax-highlight .css span.xtra { display:block; } + + diff --git a/include/javascript/yui3/assets/yui.gif b/include/javascript/yui3/assets/yui.gif new file mode 100644 index 0000000000000000000000000000000000000000..3f956dfbdcf0ec96d4d05a5a5ad6239824b1ebbb GIT binary patch literal 2425 zcmb`?i93{u1Hkcj#*BGqTw|OgGzPQeSd1)@-WfBFa@Hi*GLrjPMUt52otz;@GTo=;+vO>1`^#E)t1YEY{fAm;|6o zBog5Nm(D*Z1OQL~aBuo^7NE=30|o zO>Yj|>3GCA)HA!;mFgbw028^#7A%iT;*#{06}XvM**P#TFG?B7xtgh{bs~wSUF68a z?Tanu-@09^iNfKO^ObSP`wBm2>tAZ;ozc|F=gImoc}R?O?USediRu_sQxab9`Ewyf zEA^!)wKC`z9v+<$+%=`FjK}k^zeT6F4y>(ju(3R4CsKD3y3l2EQkH>HKu3MRk{~{K z2PON8eY6;_)r?WFis3eLt28(c>le=rwbeRNHrHdU>GVFs+-oR#)~R>?rg2Q?Mq)Dm z4Zdvqka}dfG~Gzz@!U+^j5}Z6ZmF9g_JV+^p$1RePpkw0i$zAG;u<4QU}5iQ?T)CE zn*ljN4069wUuU0};bYhF6APbJuno4W-Us1u$}=(*(4=$}p7wgTy6t_%Nilnyk~a&|!1pbUD1aPM&jP zXqFw5J6`4?mV?{fAXR9Ypt;F{PDYz${HU1ZezgIcCe4PWbxTG!auFr|ra5~R(-QU_=CHHDT?f(u zUiWUrO}{HkmC@p&#lZNt;J*kg)VnB;_`s3DofUG_vRk5SyTJt3jRaLu1PX zd=>U2-?&NZv_cxJbs;NvKMp}h+3LM+bq$Wb6Sz5S`%$S43UA&W z+@Izr1NU)YPG67RI+vTUgoWRVf-;rAuqYIMg2lB}X(oa^QrXEIFA+E_d7^Rhu0J5nHK$Hcw03+50R=04bzDZ}<@oR@u$@Ir&t2G!ArxpN~ztLKOTOrYdI?xa}?x2JG>^JEKM zahY*_7f7?OzYAAy22CeuK5d_?iDF{06T>rzMi$p3bcE>Be;NW-;M;PA;A-&IOXb2x zQ6u5uC^M~2(r{-M+Tfs?-kS_Pyg(;ga-T*~e*>DHbWpq|2kAc^f6Lk#?EIqvxp-Tl znWERShF;0U^XkO*md^9@u^`=*hTNGB+JfeBId>n@IKJsPv+xq)9Fb?A;e=W-O#j7SWFaGRCLJy? zFKv65?K#*YZviJ;?*)D|-L}9De5^nm_xcVq(q&@#m+`j46N9pI_l8e- zBhLb{?2?PAKUc6Miy(gTrDTT3wFQZ22!h2y^ygU96eb5yH!%t-q#Z1x?0 zR$FMuYB?ouiICRrYff%O8g!QO63fkKxYL7333A*SOXPRsXa$Y=hI5 z*+*oCiYw>ha;TD%yRyFg)ff0eCr^={ioToXHRZF{b?Fo}HR09z!f0rF00`-ZeDDY5 zJQkmw>M{SFyPg63CR+_%JD)BU10iA~pLyvLl*yZCO0nQsg0?h6u1XfMUmP>a((n}! za6mo-3ht=Sr^h#1HQ@ zWV%P~RogGeYU#>+xn4BPrCS{$FyYk-m>IoP4*N0*ADZ4j-?FDQM9EUV{{r~51PQY(u~2?{?wq>%N-)pBg4b^|)Xu zSbp%Q+J$K9_@h^6p$Lr&8}MgKTe0|sl?FXL3jsMyHpn|xZ=Z),Q=Z,R,T;if(W){a=Z-a;U=(a<=0);Q=0;}for(var V in X){if(X[V].to){R=X[V];T=(V in S&&"set"in S[V])?S[V].set:B.Anim.DEFAULT_SETTER;if(!U){T(this,V,R.from,R.to,a,Z,Y,R.unit);}else{T(this,V,R.from,R.to,Q,Z,Y,R.unit);}}}this._actualFrames+=1;this._set(L,a);this.fire(I);if(U){this._lastFrame();}},_lastFrame:function(){var Q=this.get("iterations"),R=this.get(H);R+=1;if(Q==="infinite"||R=d),lastFrame=d,attribute,setter;if(reversed){t=d-t;done=(t<=0);lastFrame=0;} +for(var i in attr){if(attr[i].to){attribute=attr[i];setter=(i in customAttr&&'set'in customAttr[i])?customAttr[i].set:Y.Anim.DEFAULT_SETTER;if(!done){setter(this,i,attribute.from,attribute.to,t,d,easing,attribute.unit);}else{setter(this,i,attribute.from,attribute.to,lastFrame,d,easing,attribute.unit);}}} +this._actualFrames+=1;this._set(ELAPSED_TIME,t);this.fire(TWEEN);if(done){this._lastFrame();}},_lastFrame:function(){var iter=this.get('iterations'),iterCount=this.get(ITERATION_COUNT);iterCount+=1;if(iter==='infinite'||iterCount=Z),Q=Z,R,T;if(W){a=Z-a;U=(a<=0);Q=0;}for(var V in X){if(X[V].to){R=X[V];T=(V in S&&"set"in S[V])?S[V].set:B.Anim.DEFAULT_SETTER;if(!U){T(this,V,R.from,R.to,a,Z,Y,R.unit);}else{T(this,V,R.from,R.to,Q,Z,Y,R.unit);}}}this._actualFrames+=1;this._set(L,a);this.fire(I);if(U){this._lastFrame();}},_lastFrame:function(){var Q=this.get("iterations"),R=this.get(H);R+=1;if(Q==="infinite"||R=d),lastFrame=d,attribute,setter;if(reversed){t=d-t;done=(t<=0);lastFrame=0;} +for(var i in attr){if(attr[i].to){attribute=attr[i];setter=(i in customAttr&&'set'in customAttr[i])?customAttr[i].set:Y.Anim.DEFAULT_SETTER;if(!done){setter(this,i,attribute.from,attribute.to,t,d,easing,attribute.unit);}else{setter(this,i,attribute.from,attribute.to,lastFrame,d,easing,attribute.unit);}}} +this._actualFrames+=1;this._set(ELAPSED_TIME,t);this.fire(TWEEN);if(done){this._lastFrame();}},_lastFrame:function(){var iter=this.get('iterations'),iterCount=this.get(ITERATION_COUNT);iterCount+=1;if(iter==='infinite'||iterCount{( zJaZG%Q-e|yQz{EjrrH1%83g!*xITRJ_}{;OfByXW{rmT?U%%de`0(P@tEbPN{rvg! z+qdsuzJ7i4=IzH%pKjc^b?5H=|NsB1Ei5Ys>UH#VaSW-r_2lqr!2=2$4hP$nn(TkQ zzvk)pQqg*IirRgpPkKuOvRy+9%axi8*|K$`vd>r=8dtryIcNE1@BeRH1`K(}xW#!V S|9%fNjKR~@&t;ucLK6Uym}f@- literal 0 HcmV?d00001 diff --git a/include/javascript/yui3/build/assets/skins/sam/console-filters.css b/include/javascript/yui3/build/assets/skins/sam/console-filters.css new file mode 100644 index 00000000..cb9fb419 --- /dev/null +++ b/include/javascript/yui3/build/assets/skins/sam/console-filters.css @@ -0,0 +1,8 @@ +/* +Copyright (c) 2009, Yahoo! Inc. All rights reserved. +Code licensed under the BSD License: +http://developer.yahoo.net/yui/license.txt +version: 3.0.0 +build: 1549 +*/ +.yui-skin-sam .yui-console-ft .yui-console-filters-categories,.yui-skin-sam .yui-console-ft .yui-console-filters-sources{text-align:left;padding:5px 0;border:1px inset;margin:0 2px;}.yui-skin-sam .yui-console-ft .yui-console-filters-categories{background:#fff;border-bottom:2px ridge;}.yui-skin-sam .yui-console-ft .yui-console-filters-sources{background:#fff;margin-bottom:2px;border-top:0 none;border-bottom-right-radius:10px;border-bottom-left-radius:10px;-moz-border-radius-bottomright:10px;-moz-border-radius-bottomleft:10px;-webkit-border-bottom-right-radius:10px;-webkit-border-bottom-left-radius:10px;}.yui-skin-sam .yui-console-filter-label{white-space:nowrap;margin-left:1ex;} diff --git a/include/javascript/yui3/build/assets/skins/sam/console.css b/include/javascript/yui3/build/assets/skins/sam/console.css new file mode 100644 index 00000000..5688517e --- /dev/null +++ b/include/javascript/yui3/build/assets/skins/sam/console.css @@ -0,0 +1,8 @@ +/* +Copyright (c) 2009, Yahoo! Inc. All rights reserved. +Code licensed under the BSD License: +http://developer.yahoo.net/yui/license.txt +version: 3.0.0 +build: 1549 +*/ +.yui-skin-sam .yui-separate-console{position:absolute;right:1em;top:1em;z-index:999;}.yui-skin-sam .yui-inline-console{display:-moz-inline-stack;display:inline-block;*display:inline;zoom:1;vertical-align:top;}.yui-skin-sam .yui-inline-console .yui-console-content{position:relative;}.yui-skin-sam .yui-console-content{background:#777;_background:#D8D8DA url(bg.png) repeat-x 0 0;font:normal 13px/1.3 Arial,sans-serif;text-align:left;border:1px solid #777;border-radius:10px;-moz-border-radius:10px;-webkit-border-radius:10px;}.yui-skin-sam .yui-console-hd,.yui-skin-sam .yui-console-bd,.yui-skin-sam .yui-console-ft{position:relative;}.yui-skin-sam .yui-console-hd,.yui-skin-sam .yui-console-ft .yui-console-controls{text-align:right;}.yui-skin-sam .yui-console-hd{background:#D8D8DA url(bg.png) repeat-x 0 0;padding:1ex;border:1px solid transparent;_border:0 none;border-top-right-radius:10px;border-top-left-radius:10px;-moz-border-radius-topright:10px;-moz-border-radius-topleft:10px;-webkit-border-top-right-radius:10px;-webkit-border-top-left-radius:10px;}.yui-skin-sam .yui-console-bd{background:#fff;border-top:1px solid #777;border-bottom:1px solid #777;color:#000;font-size:11px;overflow:auto;overflow-x:auto;overflow-y:scroll;_width:100%;}.yui-skin-sam .yui-console-ft{background:#D8D8DA url(bg.png) repeat-x 0 0;border:1px solid transparent;_border:0 none;border-bottom-right-radius:10px;border-bottom-left-radius:10px;-moz-border-radius-bottomright:10px;-moz-border-radius-bottomleft:10px;-webkit-border-bottom-right-radius:10px;-webkit-border-bottom-left-radius:10px;}.yui-skin-sam .yui-console-controls{padding:4px 1ex;zoom:1;}.yui-skin-sam .yui-console-title{color:#000;display:inline;float:left;font-weight:bold;font-size:13px;height:24px;line-height:24px;margin:0;padding-left:1ex;}.yui-skin-sam .yui-console-pause-label{float:left;}.yui-skin-sam .yui-console-button{line-height:1.3;}.yui-skin-sam .yui-console-collapsed .yui-console-bd,.yui-skin-sam .yui-console-collapsed .yui-console-ft{display:none;}.yui-skin-sam .yui-console-content.yui-console-collapsed{-webkit-border-radius:0;}.yui-skin-sam .yui-console-collapsed .yui-console-hd{border-radius:10px;-moz-border-radius:10px;-webkit-border-radius:0;}.yui-skin-sam .yui-console-entry{border-bottom:1px solid #aaa;min-height:32px;_height:32px;}.yui-skin-sam .yui-console-entry-meta{margin:0;overflow:hidden;}.yui-skin-sam .yui-console-entry-content{margin:0;padding:0 1ex;white-space:pre-wrap;word-wrap:break-word;}.yui-skin-sam .yui-console-entry-meta .yui-console-entry-src{color:#000;font-style:italic;font-weight:bold;float:right;margin:2px 5px 0 0;}.yui-skin-sam .yui-console-entry-meta .yui-console-entry-time{color:#777;padding-left:1ex;}.yui-skin-sam .yui-console-entry-warn .yui-console-entry-meta .yui-console-entry-time{color:#555;}.yui-skin-sam .yui-console-entry-info .yui-console-entry-meta .yui-console-entry-cat,.yui-skin-sam .yui-console-entry-warn .yui-console-entry-meta .yui-console-entry-cat,.yui-skin-sam .yui-console-entry-error .yui-console-entry-meta .yui-console-entry-cat{display:none;}.yui-skin-sam .yui-console-entry-warn{background:#aee url(warn_error.png) no-repeat -15px 15px;}.yui-skin-sam .yui-console-entry-error{background:#ffa url(warn_error.png) no-repeat 5px -24px;color:#900;}.yui-skin-sam .yui-console-entry-warn .yui-console-entry-content,.yui-skin-sam .yui-console-entry-error .yui-console-entry-content{padding-left:24px;}.yui-skin-sam .yui-console-entry-cat{text-transform:uppercase;padding:1px 4px;background-color:#ccc;}.yui-skin-sam .yui-console-entry-info .yui-console-entry-cat{background-color:#ac2;}.yui-skin-sam .yui-console-entry-warn .yui-console-entry-cat{background-color:#e81;}.yui-skin-sam .yui-console-entry-error .yui-console-entry-cat{background-color:#b00;color:#fff;}.yui-skin-sam .yui-console-hidden{display:none;} diff --git a/include/javascript/yui3/build/assets/skins/sam/horizontal-menu-submenu-indicator.png b/include/javascript/yui3/build/assets/skins/sam/horizontal-menu-submenu-indicator.png new file mode 100644 index 0000000000000000000000000000000000000000..2ef3454cac8bb059622b01ea1676c5e4fd010180 GIT binary patch literal 879 zcmV-#1CacQP)6ciK{6%`g178e&67#J8C85tTH8XFrM92^`S9UUGX9v>ecARr(iAt53nA|oRs zBqSsyB_$>%CMPE+C@3f?DJd!{Dl021EG#T7EiEoCE-x=HFfcGNF)=bSGBYzXG&D3d zH8nOiHa9mnI5;>tIXOByIy*Z%JUl!-Jv}}?K0iM{KtMo2K|w-7LPJACL_|bIMMXwN zMn^|SNJvOYNl8jdN=r*iOiWBoO-)WtPESuyP*6}&QBhJ-Qd3h?R8&+|RaI72R##V7 zSXfwDSy@_IT3cINTwGjTU0q&YUSD5dU|?WjVPRroVq;@tWMpJzWo2e&W@l$-XlQ6@ zX=!R|YHMq2Y;0_8ZEbFDZf|dIaBy&OadC2Ta&vQYbaZreb#-=jc6WDoczAeud3kzz zdV70&e0+R;eSLm@et&;|fPjF3fq{a8f`fyDgoK2Jg@uNOhKGlTh=_=ZiHVAeii?Yj zjEszpjg5|uj*pLzkdTm(k&%*;l9Q8@l$4Z}m6ev3mY0{8n3$NEnVFiJnwy)OoSdAU zot>VZo}ZteprD|kp`oIpqNAguq@<*!rKP5(rl+T;sHmu^si~@}s;jH3tgNi9t*x%E zuCK4Ju&}VPv9YqUva_?Zw6wIfwY9dkwzs#pxVX5vxw*Q!y1To(yu7@dCU$jHda$;ryf%FD~k%*@Qq&CSlv&d<-!(9qD) z(b3Y<($mw^)YR0~)z#M4*4Nk9*x1lt)=I7_<=;-L_>FMg~>g((4?Ck9A?d|UF?(gsK@bK{Q@$vHV^7Hfa z^z`)g_4W4l_V@Sq`1ttw`T6?#`uqF){QUg={r&#_{{R2~`6RjA00002bW%=J{{ZE; zFiHRb031m~K~xCWV_<*)Mi^jVMCAho7*Y5j0Y+p#BLD@m05JvHrdj|1002ovPDHLk FV1l|tohkqT literal 0 HcmV?d00001 diff --git a/include/javascript/yui3/build/assets/skins/sam/horizontal-menu-submenu-toggle.png b/include/javascript/yui3/build/assets/skins/sam/horizontal-menu-submenu-toggle.png new file mode 100644 index 0000000000000000000000000000000000000000..e776af4ba371f0fef46080b405d5c57a400da78c GIT binary patch literal 206 zcmV;<05SiGP)~V$KU_w@&D)Y|Iz0E)#v}q;{VU%|HR$@ literal 0 HcmV?d00001 diff --git a/include/javascript/yui3/build/assets/skins/sam/node-menunav.css b/include/javascript/yui3/build/assets/skins/sam/node-menunav.css new file mode 100644 index 00000000..7761e3e7 --- /dev/null +++ b/include/javascript/yui3/build/assets/skins/sam/node-menunav.css @@ -0,0 +1,8 @@ +/* +Copyright (c) 2009, Yahoo! Inc. All rights reserved. +Code licensed under the BSD License: +http://developer.yahoo.net/yui/license.txt +version: 3.0.0 +build: 1549 +*/ +.yui-menu .yui-menu{position:absolute;z-index:1;}.yui-menu .yui-shim{position:absolute;top:0;left:0;z-index:-1;opacity:0;filter:alpha(opacity=0);border:none;margin:0;padding:0;height:100%;width:100%;}.yui-menu-hidden{top:-10000px;left:-10000px;visibility:hidden;}.yui-menu li{list-style-type:none;}.yui-menu ul,.yui-menu li{margin:0;padding:0;}.yui-menu-label,.yui-menuitem-content{text-align:left;white-space:nowrap;display:block;}.yui-menu-horizontal li{float:left;width:auto;}.yui-menu-horizontal li li{float:none;}.yui-menu-horizontal ul{*zoom:1;}.yui-menu-horizontal ul ul{*zoom:normal;}.yui-menu-horizontal>.yui-menu-content>ul:after{content:"";display:block;clear:both;line-height:0;font-size:0;visibility:hidden;}.yui-menu-content{*zoom:1;}.yui-menu-hidden .yui-menu-content{*zoom:normal;}.yui-menuitem-content,.yui-menu-label{_zoom:1;}.yui-menu-hiden .yui-menuitem-content,.yui-menu-hiden .yui-menu-label{_zoom:normal;}.yui-skin-sam .yui-menu-content,.yui-skin-sam .yui-menu .yui-menu .yui-menu-content{font-size:93%;line-height:1.5;*line-height:1.45;border:solid 1px #808080;background:#fff;padding:3px 0;}.yui-skin-sam .yui-menu .yui-menu .yui-menu-content{font-size:100%;}.yui-skin-sam .yui-menu-horizontal .yui-menu-content{line-height:2;*line-height:1.9;background:url(sprite.png) repeat-x 0 0;padding:0;}.yui-skin-sam .yui-menu ul,.yui-skin-sam .yui-menu ul ul{margin-top:3px;padding-top:3px;border-top:solid 1px #ccc;}.yui-skin-sam .yui-menu ul.first-of-type{border:0;margin:0;padding:0;}.yui-skin-sam .yui-menu-horizontal ul{padding:0;margin:0;border:0;}.yui-skin-sam .yui-menu li,.yui-skin-sam .yui-menu .yui-menu li{_border-bottom:solid 1px #fff;}.yui-skin-sam .yui-menu-horizontal li{_border-bottom:0;}.yui-skin-sam .yui-menubuttonnav li{border-right:solid 1px #ccc;}.yui-skin-sam .yui-splitbuttonnav li{border-right:solid 1px #808080;}.yui-skin-sam .yui-menubuttonnav li li,.yui-skin-sam .yui-splitbuttonnav li li{border-right:0;}.yui-skin-sam .yui-menu-label,.yui-skin-sam .yui-menu .yui-menu .yui-menu-label,.yui-skin-sam .yui-menuitem-content,.yui-skin-sam .yui-menu .yui-menu .yui-menuitem-content{padding:0 20px;color:#000;text-decoration:none;cursor:default;float:none;border:0;margin:0;}.yui-skin-sam .yui-menu-horizontal .yui-menu-label,.yui-skin-sam .yui-menu-horizontal .yui-menuitem-content{padding:0 10px;border-style:solid;border-color:#808080;border-width:1px 0;margin:-1px 0;float:left;width:auto;}.yui-skin-sam .yui-menu-label,.yui-skin-sam .yui-menu .yui-menu .yui-menu-label{background:url(vertical-menu-submenu-indicator.png) right center no-repeat;}.yui-skin-sam .yui-menu-horizontal .yui-menu-label{background:url(sprite.png) repeat-x 0 0;}.yui-skin-sam .yui-menubuttonnav .yui-menu-label,.yui-skin-sam .yui-splitbuttonnav .yui-menu-label{background-image:none;}.yui-skin-sam .yui-menubuttonnav .yui-menu-label{padding-right:0;}.yui-skin-sam .yui-menubuttonnav .yui-menu-label em{font-style:normal;padding-right:20px;display:block;background:url(horizontal-menu-submenu-indicator.png) right center no-repeat;}.yui-skin-sam .yui-splitbuttonnav .yui-menu-label{padding:0;}.yui-skin-sam .yui-splitbuttonnav .yui-menu-label a{float:left;width:auto;color:#000;text-decoration:none;cursor:default;padding:0 5px 0 10px;}.yui-skin-sam .yui-splitbuttonnav .yui-menu-label .yui-menu-toggle{padding:0;border-left:solid 1px #ccc;width:15px;overflow:hidden;text-indent:-1000px;background:url(horizontal-menu-submenu-indicator.png) 3px center no-repeat;}.yui-skin-sam .yui-menu-label-active,.yui-skin-sam .yui-menu-label-menuvisible,.yui-skin-sam .yui-menu .yui-menu .yui-menu-label-active,.yui-skin-sam .yui-menu .yui-menu .yui-menu-label-menuvisible{background-color:#B3D4FF;}.yui-skin-sam .yui-menuitem-active .yui-menuitem-content,.yui-skin-sam .yui-menu .yui-menu .yui-menuitem-active .yui-menuitem-content{background-image:none;background-color:#B3D4FF;border-left-width:0;margin-left:0;}.yui-skin-sam .yui-menu-horizontal .yui-menu-label-active,.yui-skin-sam .yui-menu-horizontal .yui-menuitem-active .yui-menuitem-content,.yui-skin-sam .yui-menu-horizontal .yui-menu-label-menuvisible{border-color:#7D98B8;background:url(sprite.png) repeat-x 0 -1700px;}.yui-skin-sam .yui-menubuttonnav .yui-menu-label-active,.yui-skin-sam .yui-menubuttonnav .yui-menuitem-active .yui-menuitem-content,.yui-skin-sam .yui-menubuttonnav .yui-menu-label-menuvisible,.yui-skin-sam .yui-splitbuttonnav .yui-menu-label-active,.yui-skin-sam .yui-splitbuttonnav .yui-menuitem-active .yui-menuitem-content,.yui-skin-sam .yui-splitbuttonnav .yui-menu-label-menuvisible{border-left-width:1px;margin-left:-1px;}.yui-skin-sam .yui-splitbuttonnav .yui-menu-label-menuvisible{border-color:#808080;background:transparent;}.yui-skin-sam .yui-splitbuttonnav .yui-menu-label-menuvisible .yui-menu-toggle{border-color:#7D98B8;background:url(horizontal-menu-submenu-toggle.png) left center no-repeat;} diff --git a/include/javascript/yui3/build/assets/skins/sam/overlay.css b/include/javascript/yui3/build/assets/skins/sam/overlay.css new file mode 100644 index 00000000..80ef091a --- /dev/null +++ b/include/javascript/yui3/build/assets/skins/sam/overlay.css @@ -0,0 +1,9 @@ +/* +Copyright (c) 2009, Yahoo! Inc. All rights reserved. +Code licensed under the BSD License: +http://developer.yahoo.net/yui/license.txt +version: 3.0.0 +build: 1549 +//Commented out until YUI 3 overlay classes no longer conflicts with the YUI 2 overlay css + +.yui-overlay{position:absolute;}.yui-overlay-hidden{visibility:hidden;}*/ diff --git a/include/javascript/yui3/build/assets/skins/sam/rail-classic-x.png b/include/javascript/yui3/build/assets/skins/sam/rail-classic-x.png new file mode 100644 index 0000000000000000000000000000000000000000..553c8236827b8b2c5b149af95e80212f366fc7ee GIT binary patch literal 92 zcmeAS@N?(olHy`uVBq!ia0vp^j6lr7!3-oT*p_ktDb4_&5ZBJm&h6W`U%!4m`PGdt oKtVoF7sn8e>&XcT2~19I3=EPCY!Oky-ar`!Pgg&ebxsLQ0JeV?@&Et; literal 0 HcmV?d00001 diff --git a/include/javascript/yui3/build/assets/skins/sam/rail-classic-y.png b/include/javascript/yui3/build/assets/skins/sam/rail-classic-y.png new file mode 100644 index 0000000000000000000000000000000000000000..dae35afbfc3fb8a043847d331468dfaf01184a27 GIT binary patch literal 90 zcmeAS@N?(olHy`uVBq!ia0vp^%s|Y@0U~wmp0oie&H$ef*X`T4FJHd=`t|GgbmtWT k1$jJO978y+CnuyN0eRdEEdJNKvw.yui-menu-content>ul:after{content:"";display:block;clear:both;line-height:0;font-size:0;visibility:hidden;}.yui-menu-content{*zoom:1;}.yui-menu-hidden .yui-menu-content{*zoom:normal;}.yui-menuitem-content,.yui-menu-label{_zoom:1;}.yui-menu-hiden .yui-menuitem-content,.yui-menu-hiden .yui-menu-label{_zoom:normal;}.yui-skin-sam .yui-menu-content,.yui-skin-sam .yui-menu .yui-menu .yui-menu-content{font-size:93%;line-height:1.5;*line-height:1.45;border:solid 1px #808080;background:#fff;padding:3px 0;}.yui-skin-sam .yui-menu .yui-menu .yui-menu-content{font-size:100%;}.yui-skin-sam .yui-menu-horizontal .yui-menu-content{line-height:2;*line-height:1.9;background:url(sprite.png) repeat-x 0 0;padding:0;}.yui-skin-sam .yui-menu ul,.yui-skin-sam .yui-menu ul ul{margin-top:3px;padding-top:3px;border-top:solid 1px #ccc;}.yui-skin-sam .yui-menu ul.first-of-type{border:0;margin:0;padding:0;}.yui-skin-sam .yui-menu-horizontal ul{padding:0;margin:0;border:0;}.yui-skin-sam .yui-menu li,.yui-skin-sam .yui-menu .yui-menu li{_border-bottom:solid 1px #fff;}.yui-skin-sam .yui-menu-horizontal li{_border-bottom:0;}.yui-skin-sam .yui-menubuttonnav li{border-right:solid 1px #ccc;}.yui-skin-sam .yui-splitbuttonnav li{border-right:solid 1px #808080;}.yui-skin-sam .yui-menubuttonnav li li,.yui-skin-sam .yui-splitbuttonnav li li{border-right:0;}.yui-skin-sam .yui-menu-label,.yui-skin-sam .yui-menu .yui-menu .yui-menu-label,.yui-skin-sam .yui-menuitem-content,.yui-skin-sam .yui-menu .yui-menu .yui-menuitem-content{padding:0 20px;color:#000;text-decoration:none;cursor:default;float:none;border:0;margin:0;}.yui-skin-sam .yui-menu-horizontal .yui-menu-label,.yui-skin-sam .yui-menu-horizontal .yui-menuitem-content{padding:0 10px;border-style:solid;border-color:#808080;border-width:1px 0;margin:-1px 0;float:left;width:auto;}.yui-skin-sam .yui-menu-label,.yui-skin-sam .yui-menu .yui-menu .yui-menu-label{background:url(vertical-menu-submenu-indicator.png) right center no-repeat;}.yui-skin-sam .yui-menu-horizontal .yui-menu-label{background:url(sprite.png) repeat-x 0 0;}.yui-skin-sam .yui-menubuttonnav .yui-menu-label,.yui-skin-sam .yui-splitbuttonnav .yui-menu-label{background-image:none;}.yui-skin-sam .yui-menubuttonnav .yui-menu-label{padding-right:0;}.yui-skin-sam .yui-menubuttonnav .yui-menu-label em{font-style:normal;padding-right:20px;display:block;background:url(horizontal-menu-submenu-indicator.png) right center no-repeat;}.yui-skin-sam .yui-splitbuttonnav .yui-menu-label{padding:0;}.yui-skin-sam .yui-splitbuttonnav .yui-menu-label a{float:left;width:auto;color:#000;text-decoration:none;cursor:default;padding:0 5px 0 10px;}.yui-skin-sam .yui-splitbuttonnav .yui-menu-label .yui-menu-toggle{padding:0;border-left:solid 1px #ccc;width:15px;overflow:hidden;text-indent:-1000px;background:url(horizontal-menu-submenu-indicator.png) 3px center no-repeat;}.yui-skin-sam .yui-menu-label-active,.yui-skin-sam .yui-menu-label-menuvisible,.yui-skin-sam .yui-menu .yui-menu .yui-menu-label-active,.yui-skin-sam .yui-menu .yui-menu .yui-menu-label-menuvisible{background-color:#B3D4FF;}.yui-skin-sam .yui-menuitem-active .yui-menuitem-content,.yui-skin-sam .yui-menu .yui-menu .yui-menuitem-active .yui-menuitem-content{background-image:none;background-color:#B3D4FF;border-left-width:0;margin-left:0;}.yui-skin-sam .yui-menu-horizontal .yui-menu-label-active,.yui-skin-sam .yui-menu-horizontal .yui-menuitem-active .yui-menuitem-content,.yui-skin-sam .yui-menu-horizontal .yui-menu-label-menuvisible{border-color:#7D98B8;background:url(sprite.png) repeat-x 0 -1700px;}.yui-skin-sam .yui-menubuttonnav .yui-menu-label-active,.yui-skin-sam .yui-menubuttonnav .yui-menuitem-active .yui-menuitem-content,.yui-skin-sam .yui-menubuttonnav .yui-menu-label-menuvisible,.yui-skin-sam .yui-splitbuttonnav .yui-menu-label-active,.yui-skin-sam .yui-splitbuttonnav .yui-menuitem-active .yui-menuitem-content,.yui-skin-sam .yui-splitbuttonnav .yui-menu-label-menuvisible{border-left-width:1px;margin-left:-1px;}.yui-skin-sam .yui-splitbuttonnav .yui-menu-label-menuvisible{border-color:#808080;background:transparent;}.yui-skin-sam .yui-splitbuttonnav .yui-menu-label-menuvisible .yui-menu-toggle{border-color:#7D98B8;background:url(horizontal-menu-submenu-toggle.png) left center no-repeat;} +.yui-overlay{position:absolute;}.yui-overlay-hidden{visibility:hidden;} +.yui-slider{display:-moz-inline-stack;display:inline-block;*display:inline;zoom:1;vertical-align:middle;}.yui-slider-content{position:relative;}.yui-slider-rail{position:relative;}.yui-slider-thumb{position:absolute;}.yui-slider-thumb-image{display:block;}.yui-slider-image-error .yui-slider-thumb{height:10px;width:10px;background:#000;color:#000;overflow:hidden;}.yui-slider-image-error .yui-slider-thumb-image{display:none;}.yui-skin-sam .yui-slider-rail-x{background:url("rail-classic-x.png") repeat-x 0 7px;min-height:19px;*height:19px;}.yui-skin-sam .yui-slider-rail-y{background:url("rail-classic-y.png") repeat-y 7px 0;min-width:19px;*width:19px;} +.yui-widget-stacked .yui-widget-shim{opacity:0;filter:alpha(opacity=0);position:absolute;border:none;top:0;left:0;padding:0;margin:0;z-index:-1;width:100%;height:100%;_width:0;_height:0;} +.yui-widget-hidden{display:none;} diff --git a/include/javascript/yui3/build/assets/skins/sam/slider.css b/include/javascript/yui3/build/assets/skins/sam/slider.css new file mode 100644 index 00000000..1b2c4a72 --- /dev/null +++ b/include/javascript/yui3/build/assets/skins/sam/slider.css @@ -0,0 +1,8 @@ +/* +Copyright (c) 2009, Yahoo! Inc. All rights reserved. +Code licensed under the BSD License: +http://developer.yahoo.net/yui/license.txt +version: 3.0.0 +build: 1549 +*/ +.yui-slider{display:-moz-inline-stack;display:inline-block;*display:inline;zoom:1;vertical-align:middle;}.yui-slider-content{position:relative;}.yui-slider-rail{position:relative;}.yui-slider-thumb{position:absolute;}.yui-slider-thumb-image{display:block;}.yui-slider-image-error .yui-slider-thumb{height:10px;width:10px;background:#000;color:#000;overflow:hidden;}.yui-slider-image-error .yui-slider-thumb-image{display:none;}.yui-skin-sam .yui-slider-rail-x{background:url("rail-classic-x.png") repeat-x 0 7px;min-height:19px;*height:19px;}.yui-skin-sam .yui-slider-rail-y{background:url("rail-classic-y.png") repeat-y 7px 0;min-width:19px;*width:19px;} diff --git a/include/javascript/yui3/build/assets/skins/sam/sprite.png b/include/javascript/yui3/build/assets/skins/sam/sprite.png new file mode 100644 index 0000000000000000000000000000000000000000..afd65e05aaabc820fc2e6bba0740818773fcd599 GIT binary patch literal 3123 zcmYk8dpy(oAIHCQkKB(`L$fBLgHFmdwpy8rlp;APT_~3%jD%5a64_7ZI7gvht{voB zq}Rs{e+ z-3^62FY9IipggQ1FFWB*a!LR|9`HPK;e=Ew6|)+qskFuJ!wbzOg3pDl>|;V3o3~i# z`tXaj0DoRRu4F)JL)Jb=jRW`t43mpchf5=Me6i8o#fm`-snmC%q*)6 zJgNd(gTc%WKBv*>DY!0|;4d??v#YMIuOl^Bbq+b@J!^V;tP02V`Tid*LMGi6m@o8J z>n?7vsmweV&J*x_@zJ^43P|62cAM>?RX)HYWfgYv33mp7&V*j_k zr;FY`!nnAYsOL0axw(G#J+K(}+dVMze>t6NSZK5pfBZ-#M00ZvkjE)oTU%XST@s08 zV`F1|eO)9H&9hjuvvVt4?&|95vG8w9o|HJNT<)x=rgOULRl#DJn7_; zlr%4$=S#)n^-okOi_M-{mM$(X&2pu4OeU2^Utizg@%UtxY(TuYv^2++eql-nW~4*2 z(%va4l_M32#FPaojU(j?1e}!>#9cB5gMmV!e7;~+C>$gX&$HN-)iqo$Pgdgf_4clA zLjQo{tpWRh-sW+sP$+_jj4p9Fqogs*^EKAq?^!Ii{f*B@gNRd8)RmPLfvi?ndq4Jl zXlb*(+P$>IVa~I-TrP*RLMD&PRO{b2&do95p(J?N7?004J5y@mQ9+LZ^F}U-TU)=M zcU>JgQ(Ie0pI^zz$@xxn3JwltQo4AgATm~o#bRw>Fsrl-Nkq(0BW`nLX3PmfUzQdW zeJQS(;EScpS^F78^ak0Jt*Z9D$ZOYg#G$I^Ibcb`?Z0$G=NrJcNi1P~MLj@({5d zsvVS_mCSev5ra_93fY+CowAqzmGCIUr}cf>e9l{bb)!QU)&jq8fjS0h+5;0MF?t|k zbCk1M_6B?e$ku#x(@Le|8to%Q(l58xQ_+H0!}**|`k&HC9Ma~xYkcjMN1DoLr;U4% z;=~lC40=+>!JDbOH|0w`4`;T3ITXQYd8qR@d(Pl;Am;nsYeB<$^sqtj)S}aD`h(YH ziOmAy@5j~}acOD$L<+QV`#q`!5iF6ZsUYjV)tMRM2MJLni-|<$0sG?RP~LXNy6_jR zPI*9Dnn&X{h+7b-0Ikt!ZxE@`d2oBCIDU$oyZJlOc<}p%2<|9ftrA{zSZI*65Iv~Y zBq4GS0NUE7N!#)OrDK=utc_iLSPsAdW!B|^0s6*?STL`RsMh5CGC~dlJ>`>_#zsSI z)t9+vQE8Ld-yxx_&@}zN$-G!I9i#L(6z+>?-*RTk-iJj-Ujs(TQvWy2YDFEomvHAA z_o1;p6*rcBM(LchwrAhkS+Q#;qSw;RK9(PN7Iy}Bkh<7nuCtsW(`dQzE~)`}w6Mny za6sPu{FOcca!6U@QSU*a9>9VPXbr5Ba!z^U^*x5?pr=;2T$(M=n-9!9190{BKCB_Ubo6m%pJlk` zo+jnYkRu{iP1!fQ;tUP>M6$Pm!BiiDEWG^o5C2byEeCDwbNwG6E-oDgETXx~HA6F( zf$?8|lLq%??27pXOdfQx?m#N5*p4Me~` zXe0%J($efe#bduFjmvI6<^otj7iI;2M{ehcGUl+-_NK!iRt0d~N&$7x5QsIQm7|tY z0iJ16&JGU%iTow8d+)H$72O1MI|xY-Ol#kMQuV~ykqQ)g#r1x2m5;}E;?x^`7{v&i zs=dz6yJ?3MoI^jfK~2>Qy=;ESm<66;-e@tqa?MPzk0J~@d765($9CHJ>yMoqc0@sZ z)Q4=fN=6ZT{L~!q71(+3?QFuJjcpq==w{#;DgU)JWSQNpKBq$>-4c+aV=C@H`7X?i zx^;_$&8)1bU*}XEnAjO8sHm)~BWs~!q_3~u`t@{1fG?(FDz`hME+f&=@BGxup1l-WW?H>uxOYN=74bD6rp2ZP|wr6^JdS3;J)tAmOBxjhsDD*gT~ou=?|imcHPq&zs-};~KOpC*M?~AFgpC7LD!BTfmbOeJQg9%D zYMLbDb;Eu~tDTi?4b!?y{DS$(Xwp{umiD4{)~AQvwcE%1XL*Blfe$V;_1)QEH;z4Y zdcR1n7>=B&>kW9A@YbB@bidRvPJf?9%U1CYgM{F-_nsdAuu6IUy6ne@*z2LJXq5@_ z)kC|L+NL=g6S2M_jFs}T5_=bdGP(2sw-eOsc5=x`}1k$`0ZoRES{4#givEdzuB zc)c3in3=*ImpF+v4ggcV0aKV46UZ z=xxgwFL{ZHHka&C+#Pe<`X3hxERD5Gs0*9#9PY$eq0q^U&A+g?2SlHrp;gR;g9w_4 z`(RYT|Jjy@G}b<<`!yuEbnjH%i)Y~A98iF;Bt$>F|458i@D9HY0qM*^?5Af{?+;K* z{bvh8|nVnE*~rBj@x@! zof9&_7rsV}YBXM9tX-~Pu&$Heqjpz t#6&}WQC_v4-qAr9E!idrg%(C}T>`R7sV<66EZOD*xSjAoRvo+c=s&g>bp!wa literal 0 HcmV?d00001 diff --git a/include/javascript/yui3/build/assets/skins/sam/thumb-classic-x.png b/include/javascript/yui3/build/assets/skins/sam/thumb-classic-x.png new file mode 100644 index 0000000000000000000000000000000000000000..8d284d4ddca18c53339354d5571b44ff266d422e GIT binary patch literal 374 zcmeAS@N?(olHy`uVBq!ia0vp^{6H+s!3-oTWR}kWQj#UE5hcO-X(i=}MX3yqDfvmM z3ZA)%>8U}fi7AzZCsS>JiV^~RLR`1+*nR%OrIV-596oaF=dWL9&s|u&bor&rS8m?A z{rts?Yu9f)dh~e5u06+3oLakX!{#m9zJLF*b^ETb-@g6$@#Db3LvP-`{qW)ApFe+| zJbC*0^XC^YU#;7)>EFM9_a8j`_3PLF|NrMiA5{d}rBD*&7YyX$0}L@S(r~$oQM``RuFKxDCV-ZBe_PvQzqsA?jEn8TDxV>%s%DjFR|IN{>M%3=syeHCD(~v zSrx^+)O!`%!K;_ItoX+^|KjQ5-`qk8m)%0S<@t+5FX)$io04Y4mt1wZpzOO+_6B>V zwQQH_PVftezs#DPvE{|AxwH5z*NS`&Z(wBDBrU=293u7t=oSV~S3j3^P6&~?4vmZTv{O{ktmoH!a z{rB(vhY!Dh|Nipz>(8G*|AT>k_ZoJfT?!>Ze!&nCoFqd`jPzTe+IUYF$B>F!G3P9q z8WaSaFKRSNFM8B<`_BJqT&zs%|M)U(O4(S!5?y4opEa{^<%BeDg9{NeIhfa6ciK{6%`g178e&67#J8C85tTH8XFrM92^`S9UUGX9v>ecARr(iAt53nA|oRs zBqSsyB_$>%CMPE+C@3f?DJd!{Dl021EG#T7EiEoCE-x=HFfcGNF)=bSGBYzXG&D3d zH8nOiHa9mnI5;>tIXOByIy*Z%JUl!-Jv}}?K0iM{KtMo2K|w-7LPJACL_|bIMMXwN zMn^|SNJvOYNl8jdN=r*iOiWBoO-)WtPESuyP*6}&QBhJ-Qd3h?R8&+|RaI72R##V7 zSXfwDSy@_IT3cINTwGjTU0q&YUSD5dU|?WjVPRroVq;@tWMpJzWo2e&W@l$-XlQ6@ zX=!R|YHMq2Y;0_8ZEbFDZf|dIaBy&OadC2Ta&vQYbaZreb#-=jc6WDoczAeud3kzz zdV70&e0+R;eSLm@et&;|fPjF3fq{a8f`fyDgoK2Jg@uNOhKGlTh=_=ZiHVAeii?Yj zjEszpjg5|uj*pLzkdTm(k&%*;l9Q8@l$4Z}m6ev3mY0{8n3$NEnVFiJnwy)OoSdAU zot>VZo}ZteprD|kp`oIpqNAguq@<*!rKP5(rl+T;sHmu^si~@}s;jH3tgNi9t*x%E zuCK4Ju&}VPv9YqUva_?Zw6wIfwY9dkwzs#pxVX5vxw*Q!y1To(yu7@dCU$jHda$;ryf%FD~k%*@Qq&CSlv&d<-!(9qD) z(b3Y<($mw^)YR0~)z#M4*4Nk9*x1lt)=I7_<=;-L_>FMg~>g((4?Ck9A?d|UF?(gsK@bK{Q@$vHV^7Hfa z^z`)g_4W4l_V@Sq`1ttw`T6?#`uqF){QUg={r&#_{{R2~`6RjA00002bW%=J{{ZE; zFiHRb03At0K~xA^V`N}tfCEM_LU0f~FayRzmqFHpWEubi8~_iDFE~{I0000DSr z1<%~X^wgl##FWaylc_d9MF#?WLR_z0x$^3j+16hJ(a~a$ADg(l zxoT@mu2`{RxvFYzZthZf`DxRp9XondM^Vw5fuXjxcH1_sPoF+bVPMc^WPG%J`@Xoi zojZ4SGcbgPghWS0tuZ#9!@w|OhVt#DOBXOOl$Mrm_w$>{z~JpIvU;`p!-o%TZ1|EH z7_6;j%*=Re85oWq*Go)HeEat8@87?Zlg0J)cr_#>E?qL5$IH9f);1$OeSw&mp@E*g zJ-@Ip%Z+*S7V`1^|No!wQ)fQVFAgO^e!)O4C4k{j^+p#421ZX$7srr_TW_w!<~JFL zusztu@yU?&r-om^hA3AVtwqv@%>Mu1A9Zq5s<`c)x965+R(*W3#5O;wq}?s8KTEpQ znnkeW4u5;~;g^QS##gsX-3v3zFuHs^Vzt4(FyjLYlDjysl_lNeGurv_jJ9A}2j|83 zoSmKJRq5vrJ^0LFu=ZatyNUMX7c9#&)uUbW=0wbiwExlcgO}-D-x=m(v&)-Ko@1)c z2(`28xLIWzY2mgyb9Up^>DOg7Ki?>>GXA?-{#l~jv-;l0XP@8q7cx3%c&1y4|22cj z(uGFHgr==<-1)?this._q[I]:null;},promote:function(K){var J={callback:K},I;if(this.isRunning()){I=this.after(B,function(){this.fire(D,J);I.detach();},this);}else{this.fire(D,J);}return this;},_defPromoteFn:function(K){var I=this.indexOf(K.callback),J=(I>-1)?this._q.splice(I,1)[0]:null;K.promoted=J;if(J){this._q.unshift(J);}},remove:function(K){var J={callback:K},I;if(this.isRunning()){I=this.after(B,function(){this.fire(H,J);I.detach();},this);}else{this.fire(H,J);}return this;},_defRemoveFn:function(J){var I=this.indexOf(J.callback);J.removed=(I>-1)?this._q.splice(I,1)[0]:null;},size:function(){if(!this.isRunning()){this.next();}return this._q.length;}});},"3.0.0",{requires:["event-custom"]}); \ No newline at end of file diff --git a/include/javascript/yui3/build/async-queue/async-queue.js b/include/javascript/yui3/build/async-queue/async-queue.js new file mode 100644 index 00000000..32de6a7a --- /dev/null +++ b/include/javascript/yui3/build/async-queue/async-queue.js @@ -0,0 +1,19 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add('async-queue',function(Y){Y.AsyncQueue=function(){this._init();this.add.apply(this,arguments);};var Queue=Y.AsyncQueue,EXECUTE='execute',SHIFT='shift',PROMOTE='promote',REMOVE='remove',isObject=Y.Lang.isObject,isFunction=Y.Lang.isFunction;Queue.defaults=Y.mix({autoContinue:true,iterations:1,timeout:10,until:function(){this.iterations|=0;return this.iterations<=0;}},Y.config.queueDefaults||{});Y.extend(Queue,Y.EventTarget,{_running:false,_init:function(){Y.EventTarget.call(this,{emitFacade:true});this._q=[];this.defaults={};this._initEvents();},_initEvents:function(){this.publish('execute',{defaultFn:this._defExecFn,emitFacade:true});this.publish('shift',{defaultFn:this._defShiftFn,emitFacade:true});this.publish('add',{defaultFn:this._defAddFn,emitFacade:true});this.publish('promote',{defaultFn:this._defPromoteFn,emitFacade:true});this.publish('remove',{defaultFn:this._defRemoveFn,emitFacade:true});},next:function(){var callback;while(this._q.length){callback=this._q[0]=this._prepare(this._q[0]);if(callback&&callback.until()){this.fire(SHIFT,{callback:callback});callback=null;}else{break;}} +return callback||null;},_defShiftFn:function(e){if(this.indexOf(e.callback)===0){this._q.shift();}},_prepare:function(callback){if(isFunction(callback)&&callback._prepared){return callback;} +var config=Y.merge(Queue.defaults,{context:this,args:[],_prepared:true},this.defaults,(isFunction(callback)?{fn:callback}:callback)),wrapper=Y.bind(function(){if(!wrapper._running){wrapper.iterations--;} +if(isFunction(wrapper.fn)){wrapper.fn.apply(wrapper.context||Y,Y.Array(wrapper.args));}},this);return Y.mix(wrapper,config);},run:function(){var callback,cont=true;for(callback=this.next();cont&&callback&&!this.isRunning();callback=this.next()) +{cont=(callback.timeout<0)?this._execute(callback):this._schedule(callback);} +if(!callback){this.fire('complete');} +return this;},_execute:function(callback){this._running=callback._running=true;callback.iterations--;this.fire(EXECUTE,{callback:callback});var cont=this._running&&callback.autoContinue;this._running=callback._running=false;return cont;},_schedule:function(callback){this._running=Y.later(callback.timeout,this,function(){if(this._execute(callback)){this.run();}});return false;},isRunning:function(){return!!this._running;},_defExecFn:function(e){e.callback();},add:function(){this.fire('add',{callbacks:Y.Array(arguments,0,true)});return this;},_defAddFn:function(e){var _q=this._q,added=[];Y.Array.each(e.callbacks,function(c){if(isObject(c)){_q.push(c);added.push(c);}});e.added=added;},pause:function(){if(isObject(this._running)){this._running.cancel();} +this._running=false;return this;},stop:function(){this._q=[];return this.pause();},indexOf:function(callback){var i=0,len=this._q.length,c;for(;i-1)?this._q[i]:null;},promote:function(callback){var payload={callback:callback},e;if(this.isRunning()){e=this.after(SHIFT,function(){this.fire(PROMOTE,payload);e.detach();},this);}else{this.fire(PROMOTE,payload);} +return this;},_defPromoteFn:function(e){var i=this.indexOf(e.callback),promoted=(i>-1)?this._q.splice(i,1)[0]:null;e.promoted=promoted;if(promoted){this._q.unshift(promoted);}},remove:function(callback){var payload={callback:callback},e;if(this.isRunning()){e=this.after(SHIFT,function(){this.fire(REMOVE,payload);e.detach();},this);}else{this.fire(REMOVE,payload);} +return this;},_defRemoveFn:function(e){var i=this.indexOf(e.callback);e.removed=(i>-1)?this._q.splice(i,1)[0]:null;},size:function(){if(!this.isRunning()){this.next();} +return this._q.length;}});},'3.0.0',{requires:['event-custom']}); \ No newline at end of file diff --git a/include/javascript/yui3/build/attribute/attribute-base-min.js b/include/javascript/yui3/build/attribute/attribute-base-min.js new file mode 100644 index 00000000..cc4f4e19 --- /dev/null +++ b/include/javascript/yui3/build/attribute/attribute-base-min.js @@ -0,0 +1,8 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add("attribute-base",function(C){C.State=function(){this.data={};};C.State.prototype={add:function(O,Y,e){var c=this.data;c[Y]=c[Y]||{};c[Y][O]=e;},addAll:function(O,c){var Y;for(Y in c){if(c.hasOwnProperty(Y)){this.add(O,Y,c[Y]);}}},remove:function(O,Y){var c=this.data;if(c[Y]&&(O in c[Y])){delete c[Y][O];}},removeAll:function(O,c){var Y=this.data;C.each(c||Y,function(e,d){if(C.Lang.isString(d)){this.remove(O,d);}else{this.remove(O,e);}},this);},get:function(O,Y){var c=this.data;return(c[Y]&&O in c[Y])?c[Y][O]:undefined;},getAll:function(O){var c=this.data,Y;C.each(c,function(e,d){if(O in c[d]){Y=Y||{};Y[d]=e[O];}},this);return Y;}};var K=C.Object,F=C.Lang,L=C.EventTarget,W=".",U="Change",N="getter",M="setter",P="readOnly",X="writeOnce",b="validator",H="value",Q="valueFn",E="broadcast",S="lazyAdd",J="_bypassProxy",a="added",B="initializing",I="initValue",V="published",T="defaultValue",A="lazy",R="isLazyAdd",G,Z={};Z[P]=1;Z[X]=1;Z[N]=1;Z[E]=1;function D(){var c=this,O=this.constructor.ATTRS,Y=C.Base;c._ATTR_E_FACADE={};L.call(c,{emitFacade:true});c._conf=c._state=new C.State();c._stateProxy=c._stateProxy||null;c._requireAddAttr=c._requireAddAttr||false;if(O&&!(Y&&c instanceof Y)){c.addAttrs(this._protectAttrs(O));}}D.INVALID_VALUE={};G=D.INVALID_VALUE;D._ATTR_CFG=[M,N,b,H,Q,X,P,S,E,J];D.prototype={addAttr:function(Y,O,d){var e=this,g=e._state,f,c;d=(S in O)?O[S]:d;if(d&&!e.attrAdded(Y)){g.add(Y,A,O||{});g.add(Y,a,true);}else{if(!e.attrAdded(Y)||g.get(Y,R)){O=O||{};c=(H in O);if(c){f=O.value;delete O.value;}O.added=true;O.initializing=true;g.addAll(Y,O);if(c){e.set(Y,f);}g.remove(Y,B);}}return e;},attrAdded:function(O){return!!this._state.get(O,a);},modifyAttr:function(Y,O){var c=this,e,d;if(c.attrAdded(Y)){if(c._isLazyAttr(Y)){c._addLazyAttr(Y);}d=c._state;for(e in O){if(Z[e]&&O.hasOwnProperty(e)){d.add(Y,e,O[e]);if(e===E){d.remove(Y,V);}}}}},removeAttr:function(O){this._state.removeAll(O);},get:function(O){return this._getAttr(O);},_isLazyAttr:function(O){return this._state.get(O,A);},_addLazyAttr:function(Y){var c=this._state,O=c.get(Y,A);c.add(Y,R,true);c.remove(Y,A);this.addAttr(Y,O);},set:function(O,c,Y){return this._setAttr(O,c,Y);},reset:function(O){var c=this,Y;if(O){if(c._isLazyAttr(O)){c._addLazyAttr(O);}c.set(O,c._state.get(O,I));}else{Y=c._state.data.added;C.each(Y,function(d,e){c.reset(e);},c);}return c;},_set:function(O,c,Y){return this._setAttr(O,c,Y,true);},_getAttr:function(c){var d=this,h=c,e=d._state,f,O,g,Y;if(c.indexOf(W)!==-1){f=c.split(W);c=f.shift();}if(d._tCfgs&&d._tCfgs[c]){Y={};Y[c]=d._tCfgs[c];delete d._tCfgs[c];d._addAttrs(Y,d._tVals);}if(d._isLazyAttr(c)){d._addLazyAttr(c);}g=d._getStateVal(c);O=e.get(c,N);g=(O)?O.call(d,g,h):g;g=(f)?K.getValue(g,f):g;return g;},_setAttr:function(c,f,O,d){var i=true,Y=this._state,g=this._stateProxy,j=Y.data,h,k,l,e;if(c.indexOf(W)!==-1){k=c;l=c.split(W);c=l.shift();}if(this._isLazyAttr(c)){this._addLazyAttr(c);}h=(!j.value||!(c in j.value));if(g&&c in g&&!this._state.get(c,J)){h=false;}if(this._requireAddAttr&&!this.attrAdded(c)){}else{if(!h&&!d){if(Y.get(c,X)){i=false;}if(Y.get(c,P)){i=false;}}if(i){if(!h){e=this.get(c);}if(l){f=K.setValue(C.clone(e),l,f);if(f===undefined){i=false;}}if(i){if(Y.get(c,B)){this._setAttrVal(c,k,e,f);}else{this._fireAttrChange(c,k,e,f,O);}}}}return this;},_fireAttrChange:function(g,f,d,c,O){var i=this,e=g+U,Y=i._state,h;if(!Y.get(g,V)){i.publish(e,{queuable:false,defaultFn:i._defAttrChangeFn,silent:true,broadcast:Y.get(g,E)});Y.add(g,V,true);}h=(O)?C.merge(O):i._ATTR_E_FACADE;h.type=e;h.attrName=g;h.subAttrName=f;h.prevVal=d;h.newVal=c;i.fire(h);},_defAttrChangeFn:function(O){if(!this._setAttrVal(O.attrName,O.subAttrName,O.prevVal,O.newVal)){O.stopImmediatePropagation();}else{O.newVal=this._getStateVal(O.attrName);}},_getStateVal:function(O){var Y=this._stateProxy;return Y&&(O in Y)&&!this._state.get(O,J)?Y[O]:this._state.get(O,H);},_setStateVal:function(O,c){var Y=this._stateProxy;if(Y&&(O in Y)&&!this._state.get(O,J)){Y[O]=c;}else{this._state.add(O,H,c);}},_setAttrVal:function(l,k,h,f){var n=this,i=true,c=n._state,d=c.get(l,b),g=c.get(l,M),j=c.get(l,B),m=this._getStateVal(l),Y=k||l,e,O;if(d){O=d.call(n,f,Y);if(!O&&j){f=c.get(l,T);O=true;}}if(!d||O){if(g){e=g.call(n,f,Y);if(e===G){i=false;}else{if(e!==undefined){f=e;}}}if(i){if(!k&&(f===m)&&!F.isObject(f)){i=false;}else{if(c.get(l,I)===undefined){c.add(l,I,f);}n._setStateVal(l,f);}}}else{i=false;}return i;},setAttrs:function(O,Y){return this._setAttrs(O,Y);},_setAttrs:function(Y,c){for(var O in Y){if(Y.hasOwnProperty(O)){this.set(O,Y[O]);}}return this;},getAttrs:function(O){return this._getAttrs(O);},_getAttrs:function(d){var f=this,h={},e,Y,O,g,c=(d===true);d=(d&&!c)?d:K.keys(f._state.data.added);for(e=0,Y=d.length;e=0;--O){X=W[O];for(T in X){if(X.hasOwnProperty(T)){S=B.mix({},X[T],true,R);L=S.value;V=S.cloneDefaultValue;if(L){if((V===undefined&&(C===L.constructor||J.isArray(L)))||V===K||V===true){S.value=B.clone(L);}else{if(V===Q){S.value=B.merge(L);}}}Y=null;if(T.indexOf(I)!==-1){Y=T.split(I);T=Y.shift();}if(Y&&U[T]&&U[T].value){H.setValue(U[T].value,Y,L);}else{if(!Y){if(!U[T]){U[T]=S;}else{B.mix(U[T],S,true,R);}}}}}}}return U;},_initHierarchy:function(U){var R=this._lazyAddAttrs,V,W,X,S,O,T=this._getClasses(),L=this._getAttrCfgs();for(X=T.length-1;X>=0;X--){V=T[X];W=V.prototype;if(V._yuibuild&&V._yuibuild.exts&&!V._yuibuild.dynamic){for(S=0,O=V._yuibuild.exts.length;S=0;--i){attrs=allAttrs[i];for(attr in attrs){if(attrs.hasOwnProperty(attr)){cfg=Y.mix({},attrs[attr],true,cfgProps);val=cfg.value;clone=cfg.cloneDefaultValue;if(val){if((clone===undefined&&(OBJECT_CONSTRUCTOR===val.constructor||L.isArray(val)))||clone===DEEP||clone===true){cfg.value=Y.clone(val);}else if(clone===SHALLOW){cfg.value=Y.merge(val);}} +path=null;if(attr.indexOf(DOT)!==-1){path=attr.split(DOT);attr=path.shift();} +if(path&&aggAttrs[attr]&&aggAttrs[attr].value){O.setValue(aggAttrs[attr].value,path,val);}else if(!path){if(!aggAttrs[attr]){aggAttrs[attr]=cfg;}else{Y.mix(aggAttrs[attr],cfg,true,cfgProps);}}}}}} +return aggAttrs;},_initHierarchy:function(userVals){var lazy=this._lazyAddAttrs,constr,constrProto,ci,ei,el,classes=this._getClasses(),attrCfgs=this._getAttrCfgs();for(ci=classes.length-1;ci>=0;ci--){constr=classes[ci];constrProto=constr.prototype;if(constr._yuibuild&&constr._yuibuild.exts&&!constr._yuibuild.dynamic){for(ei=0,el=constr._yuibuild.exts.length;ei=0;--O){X=W[O];for(T in X){if(X.hasOwnProperty(T)){S=B.mix({},X[T],true,R);L=S.value;V=S.cloneDefaultValue;if(L){if((V===undefined&&(C===L.constructor||J.isArray(L)))||V===K||V===true){S.value=B.clone(L);}else{if(V===Q){S.value=B.merge(L);}}}Y=null;if(T.indexOf(I)!==-1){Y=T.split(I);T=Y.shift();}if(Y&&U[T]&&U[T].value){H.setValue(U[T].value,Y,L);}else{if(!Y){if(!U[T]){U[T]=S;}else{B.mix(U[T],S,true,R);}}}}}}}return U;},_initHierarchy:function(U){var R=this._lazyAddAttrs,V,W,X,S,O,T=this._getClasses(),L=this._getAttrCfgs();for(X=T.length-1;X>=0;X--){V=T[X];W=V.prototype;if(V._yuibuild&&V._yuibuild.exts&&!V._yuibuild.dynamic){for(S=0,O=V._yuibuild.exts.length;S=0;--i){attrs=allAttrs[i];for(attr in attrs){if(attrs.hasOwnProperty(attr)){cfg=Y.mix({},attrs[attr],true,cfgProps);val=cfg.value;clone=cfg.cloneDefaultValue;if(val){if((clone===undefined&&(OBJECT_CONSTRUCTOR===val.constructor||L.isArray(val)))||clone===DEEP||clone===true){cfg.value=Y.clone(val);}else if(clone===SHALLOW){cfg.value=Y.merge(val);}} +path=null;if(attr.indexOf(DOT)!==-1){path=attr.split(DOT);attr=path.shift();} +if(path&&aggAttrs[attr]&&aggAttrs[attr].value){O.setValue(aggAttrs[attr].value,path,val);}else if(!path){if(!aggAttrs[attr]){aggAttrs[attr]=cfg;}else{Y.mix(aggAttrs[attr],cfg,true,cfgProps);}}}}}} +return aggAttrs;},_initHierarchy:function(userVals){var lazy=this._lazyAddAttrs,constr,constrProto,ci,ei,el,classes=this._getClasses(),attrCfgs=this._getAttrCfgs();for(ci=classes.length-1;ci>=0;ci--){constr=classes[ci];constrProto=constr.prototype;if(constr._yuibuild&&constr._yuibuild.exts&&!constr._yuibuild.dynamic){for(ei=0,el=constr._yuibuild.exts.length;ei0){if(D){while(D.length>E){D.shift();}}}else{this._entries=[];}return E;}},size:{readOnly:true,getter:function(){return this._entries.length;}},uniqueKeys:{value:false,validator:function(D){return(A.isBoolean(D));}},entries:{readOnly:true,getter:function(){return this._entries;}}}});C.extend(B,C.Plugin.Base,{_entries:null,initializer:function(D){this.publish("add",{defaultFn:this._defAddFn});this.publish("flush",{defaultFn:this._defFlushFn});this._entries=[];},destructor:function(){this._entries=null;},_defAddFn:function(G){var E=this._entries,D=this.get("max"),F=G.entry;if(this.get("uniqueKeys")&&(this.retrieve(G.entry.request))){E.shift();}while(E.length>=D){E.shift();}E[E.length]=F;},_defFlushFn:function(D){this._entries=[];},_isMatch:function(E,D){return(E===D.request);},add:function(E,D,F){if(this.get("entries")&&(this.get("max")>0)&&(A.isValue(E)||A.isNull(E)||A.isUndefined(E))){this.fire("add",{entry:{request:E,response:D,payload:F}});}else{}},flush:function(){this.fire("flush");},retrieve:function(H){var D=this._entries,G=D.length,F=null,E=G-1;if((this.get("max")>0)&&(G>0)){this.fire("request",{request:H});for(;E>=0;E--){F=D[E];if(this._isMatch(H,F)){this.fire("retrieve",{entry:F});if(E0){if(entries){while(entries.length>value){entries.shift();}}} +else{this._entries=[];} +return value;}},size:{readOnly:true,getter:function(){return this._entries.length;}},uniqueKeys:{value:false,validator:function(value){return(LANG.isBoolean(value));}},entries:{readOnly:true,getter:function(){return this._entries;}}}});Y.extend(Cache,Y.Plugin.Base,{_entries:null,initializer:function(config){this.publish("add",{defaultFn:this._defAddFn});this.publish("flush",{defaultFn:this._defFlushFn});this._entries=[];},destructor:function(){this._entries=null;},_defAddFn:function(e){var entries=this._entries,max=this.get("max"),entry=e.entry;if(this.get("uniqueKeys")&&(this.retrieve(e.entry.request))){entries.shift();} +while(entries.length>=max){entries.shift();} +entries[entries.length]=entry;},_defFlushFn:function(e){this._entries=[];},_isMatch:function(request,entry){return(request===entry.request);},add:function(request,response,payload){if(this.get("entries")&&(this.get("max")>0)&&(LANG.isValue(request)||LANG.isNull(request)||LANG.isUndefined(request))){this.fire("add",{entry:{request:request,response:response,payload:payload}});} +else{}},flush:function(){this.fire("flush");},retrieve:function(request){var entries=this._entries,length=entries.length,entry=null,i=length-1;if((this.get("max")>0)&&(length>0)){this.fire("request",{request:request});for(;i>=0;i--){entry=entries[i];if(this._isMatch(request,entry)){this.fire("retrieve",{entry:entry});if(i=0;F=F-1){if(A[F]===G){break;}}return F;};B.unique=function(F,H){var A=F.slice(),G=0,J=-1,I=null;while(G=0;i=i-1){if(a[i]===val){break;}} +return i;};A.unique=function(a,sort){var b=a.slice(),i=0,n=-1,item=null;while(i2)?D.Array(L,2,true):null;return D.mix(V,U,(W),W);},augmentProto:function(V,U){var L=arguments,W=(L.length>2)?D.Array(L,2,true):null;return D.mix(V,U,(W),W,1);},extend:D.extend,merge:D.merge},true);G.augment=G.augmentProto;G.hasOwnProperty=function(U,L){return(U.hasOwnProperty(L));};D.augmentProto=G.augmentProto;D.mix(D,{register:function(L,X,W){var c=D.Env.modules;if(!c[L]){c[L]={versions:[],builds:[]};}var U=c[L],a=W.version,Z=W.build,Y=D.Env.listeners;U.name=L;U.version=a;U.build=Z;U.versions.push(a);U.builds.push(Z);U.mainClass=X;for(var V=0;V=this.left&&L.right<=this.right&&L.top>=this.top&&L.bottom<=this.bottom);};YAHOO.util.Region.prototype.getArea=function(){return((this.bottom-this.top)*(this.right-this.left));};YAHOO.util.Region.prototype.intersect=function(X){var V=Math.max(this.top,X.top);var W=Math.min(this.right,X.right);var L=Math.min(this.bottom,X.bottom);var U=Math.max(this.left,X.left);if(L>=V&&W>=U){return new YAHOO.util.Region(V,W,L,U);}else{return null;}};YAHOO.util.Region.prototype.union=function(X){var V=Math.min(this.top,X.top);var W=Math.max(this.right,X.right);var L=Math.max(this.bottom,X.bottom);var U=Math.min(this.left,X.left);return new YAHOO.util.Region(V,W,L,U);};YAHOO.util.Region.prototype.toString=function(){return("Region {"+"top: "+this.top+", right: "+this.right+", bottom: "+this.bottom+", left: "+this.left+"}");};YAHOO.util.Region.getRegion=function(L){return YUI.DOM.region(L);};YAHOO.util.Point=function(L,U){if(YAHOO.lang.isArray(L)){U=L[1];L=L[0];}this.x=this.right=this.left=this[0]=L;this.y=this.top=this.bottom=this[1]=U;};YAHOO.util.Point.prototype=new YAHOO.util.Region();},"3.0.0",{requires:["dom","event"]});YUI._setup();YUI.use("dom","event","compat"); \ No newline at end of file diff --git a/include/javascript/yui3/build/compat/compat.js b/include/javascript/yui3/build/compat/compat.js new file mode 100644 index 00000000..d02b48fc --- /dev/null +++ b/include/javascript/yui3/build/compat/compat.js @@ -0,0 +1,45 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add('compat',function(Y){var COMPAT_ARG='~yui|2|compat~';if(window.YAHOO!=YUI){var o=(window.YAHOO)?YUI.merge(window.YAHOO):null;window.YAHOO=YUI;if(o){Y.mix(Y,o);}} +Y.namespace("util","widget","example");Y.env=(Y.env)?Y.mix(Y.env,Y.Env):Y.Env;Y.lang=(Y.lang)?Y.mix(Y.lang,Y.Lang):Y.Lang;Y.env.ua=Y.UA;Y.mix(Y.env,{modules:[],listeners:[],getVersion:function(name){return this.Env.modules[name]||null;}});var L=Y.lang;Y.mix(L,{augmentObject:function(r,s){var a=arguments,wl=(a.length>2)?Y.Array(a,2,true):null;return Y.mix(r,s,(wl),wl);},augmentProto:function(r,s){var a=arguments,wl=(a.length>2)?Y.Array(a,2,true):null;return Y.mix(r,s,(wl),wl,1);},extend:Y.extend,merge:Y.merge},true);L.augment=L.augmentProto;L.hasOwnProperty=function(o,k){return(o.hasOwnProperty(k));};Y.augmentProto=L.augmentProto;Y.mix(Y,{register:function(name,mainClass,data){var mods=Y.Env.modules;if(!mods[name]){mods[name]={versions:[],builds:[]};} +var m=mods[name],v=data.version,b=data.build,ls=Y.Env.listeners;m.name=name;m.version=v;m.build=b;m.versions.push(v);m.builds.push(b);m.mainClass=mainClass;for(var i=0;i=this.left&®ion.right<=this.right&®ion.top>=this.top&®ion.bottom<=this.bottom);};YAHOO.util.Region.prototype.getArea=function(){return((this.bottom-this.top)*(this.right-this.left));};YAHOO.util.Region.prototype.intersect=function(region){var t=Math.max(this.top,region.top);var r=Math.min(this.right,region.right);var b=Math.min(this.bottom,region.bottom);var l=Math.max(this.left,region.left);if(b>=t&&r>=l){return new YAHOO.util.Region(t,r,b,l);}else{return null;}};YAHOO.util.Region.prototype.union=function(region){var t=Math.min(this.top,region.top);var r=Math.max(this.right,region.right);var b=Math.max(this.bottom,region.bottom);var l=Math.min(this.left,region.left);return new YAHOO.util.Region(t,r,b,l);};YAHOO.util.Region.prototype.toString=function(){return("Region {"+"top: "+this.top+", right: "+this.right+", bottom: "+this.bottom+", left: "+this.left+"}");};YAHOO.util.Region.getRegion=function(el){return YUI.DOM.region(el);};YAHOO.util.Point=function(x,y){if(YAHOO.lang.isArray(x)){y=x[1];x=x[0];} +this.x=this.right=this.left=this[0]=x;this.y=this.top=this.bottom=this[1]=y;};YAHOO.util.Point.prototype=new YAHOO.util.Region();},'3.0.0',{requires:['dom','event']});YUI._setup();YUI.use('dom','event','compat'); \ No newline at end of file diff --git a/include/javascript/yui3/build/console/assets/console-core.css b/include/javascript/yui3/build/console/assets/console-core.css new file mode 100644 index 00000000..dbc8374a --- /dev/null +++ b/include/javascript/yui3/build/console/assets/console-core.css @@ -0,0 +1,7 @@ +/* +Copyright (c) 2009, Yahoo! Inc. All rights reserved. +Code licensed under the BSD License: +http://developer.yahoo.net/yui/license.txt +version: 3.0.0 +build: 1549 +*/ diff --git a/include/javascript/yui3/build/console/assets/console-filters-core.css b/include/javascript/yui3/build/console/assets/console-filters-core.css new file mode 100644 index 00000000..dbc8374a --- /dev/null +++ b/include/javascript/yui3/build/console/assets/console-filters-core.css @@ -0,0 +1,7 @@ +/* +Copyright (c) 2009, Yahoo! Inc. All rights reserved. +Code licensed under the BSD License: +http://developer.yahoo.net/yui/license.txt +version: 3.0.0 +build: 1549 +*/ diff --git a/include/javascript/yui3/build/console/assets/skins/sam/bg.png b/include/javascript/yui3/build/console/assets/skins/sam/bg.png new file mode 100644 index 0000000000000000000000000000000000000000..652fce6ccd8ca02d82780e686e12581161753579 GIT binary patch literal 219 zcmeAS@N?(olHy`uVBq!ia0vp^%s?E#0U}?&vA+VOBuiW)N`mv#O3D+9QW+dm@{>{( zJaZG%Q-e|yQz{EjrrH1%83g!*xITRJ_}{;OfByXW{rmT?U%%de`0(P@tEbPN{rvg! z+qdsuzJ7i4=IzH%pKjc^b?5H=|NsB1Ei5Ys>UH#VaSW-r_2lqr!2=2$4hP$nn(TkQ zzvk)pQqg*IirRgpPkKuOvRy+9%axi8*|K$`vd>r=8dtryIcNE1@BeRH1`K(}xW#!V S|9%fNjKR~@&t;ucLK6Uym}f@- literal 0 HcmV?d00001 diff --git a/include/javascript/yui3/build/console/assets/skins/sam/console-filters-skin.css b/include/javascript/yui3/build/console/assets/skins/sam/console-filters-skin.css new file mode 100644 index 00000000..dc870f3a --- /dev/null +++ b/include/javascript/yui3/build/console/assets/skins/sam/console-filters-skin.css @@ -0,0 +1,34 @@ +/* +Copyright (c) 2009, Yahoo! Inc. All rights reserved. +Code licensed under the BSD License: +http://developer.yahoo.net/yui/license.txt +version: 3.0.0 +build: 1549 +*/ +.yui-skin-sam .yui-console-ft .yui-console-filters-categories, +.yui-skin-sam .yui-console-ft .yui-console-filters-sources { + text-align: left; + padding: 5px 0; + border: 1px inset; + margin: 0 2px; +} +.yui-skin-sam .yui-console-ft .yui-console-filters-categories { + background: #fff; + border-bottom: 2px ridge; +} +.yui-skin-sam .yui-console-ft .yui-console-filters-sources { + background: #fff; + margin-bottom: 2px; + + border-top: 0 none; + border-bottom-right-radius: 10px; + border-bottom-left-radius: 10px; + -moz-border-radius-bottomright: 10px; + -moz-border-radius-bottomleft: 10px; + -webkit-border-bottom-right-radius: 10px; + -webkit-border-bottom-left-radius: 10px; +} +.yui-skin-sam .yui-console-filter-label { + white-space: nowrap; + margin-left: 1ex; +} diff --git a/include/javascript/yui3/build/console/assets/skins/sam/console-filters.css b/include/javascript/yui3/build/console/assets/skins/sam/console-filters.css new file mode 100644 index 00000000..cb9fb419 --- /dev/null +++ b/include/javascript/yui3/build/console/assets/skins/sam/console-filters.css @@ -0,0 +1,8 @@ +/* +Copyright (c) 2009, Yahoo! Inc. All rights reserved. +Code licensed under the BSD License: +http://developer.yahoo.net/yui/license.txt +version: 3.0.0 +build: 1549 +*/ +.yui-skin-sam .yui-console-ft .yui-console-filters-categories,.yui-skin-sam .yui-console-ft .yui-console-filters-sources{text-align:left;padding:5px 0;border:1px inset;margin:0 2px;}.yui-skin-sam .yui-console-ft .yui-console-filters-categories{background:#fff;border-bottom:2px ridge;}.yui-skin-sam .yui-console-ft .yui-console-filters-sources{background:#fff;margin-bottom:2px;border-top:0 none;border-bottom-right-radius:10px;border-bottom-left-radius:10px;-moz-border-radius-bottomright:10px;-moz-border-radius-bottomleft:10px;-webkit-border-bottom-right-radius:10px;-webkit-border-bottom-left-radius:10px;}.yui-skin-sam .yui-console-filter-label{white-space:nowrap;margin-left:1ex;} diff --git a/include/javascript/yui3/build/console/assets/skins/sam/console-skin.css b/include/javascript/yui3/build/console/assets/skins/sam/console-skin.css new file mode 100644 index 00000000..829cd572 --- /dev/null +++ b/include/javascript/yui3/build/console/assets/skins/sam/console-skin.css @@ -0,0 +1,192 @@ +/* +Copyright (c) 2009, Yahoo! Inc. All rights reserved. +Code licensed under the BSD License: +http://developer.yahoo.net/yui/license.txt +version: 3.0.0 +build: 1549 +*/ +.yui-skin-sam .yui-separate-console { + position:absolute; + right:1em; + top:1em; + z-index:999; +} + +.yui-skin-sam .yui-inline-console { + /* xbrowser inline-block styles */ + display: -moz-inline-stack; /* FF2 */ + display: inline-block; + *display: inline; /* IE 7- (with zoom) */ + zoom: 1; + vertical-align: top; +} +.yui-skin-sam .yui-inline-console .yui-console-content { + position: relative; +} + +.yui-skin-sam .yui-console-content { + background: #777; + _background: #D8D8DA url(bg.png) repeat-x 0 0; + font: normal 13px/1.3 Arial, sans-serif; + text-align: left; + + border: 1px solid #777; + border-radius: 10px; + -moz-border-radius: 10px; + -webkit-border-radius: 10px; +} + +.yui-skin-sam .yui-console-hd, +.yui-skin-sam .yui-console-bd, +.yui-skin-sam .yui-console-ft { + position: relative; +} + +.yui-skin-sam .yui-console-hd, +.yui-skin-sam .yui-console-ft .yui-console-controls { + text-align: right; +} + +.yui-skin-sam .yui-console-hd { + background: #D8D8DA url(bg.png) repeat-x 0 0; + padding: 1ex; + + border: 1px solid transparent; + _border: 0 none; + border-top-right-radius: 10px; + border-top-left-radius: 10px; + -moz-border-radius-topright: 10px; + -moz-border-radius-topleft: 10px; + -webkit-border-top-right-radius: 10px; + -webkit-border-top-left-radius: 10px; +} + +.yui-skin-sam .yui-console-bd { + background: #fff; + border-top: 1px solid #777; + border-bottom: 1px solid #777; + color: #000; + font-size: 11px; + overflow: auto; + overflow-x: auto; + overflow-y: scroll; + _width: 100%; +} + +.yui-skin-sam .yui-console-ft { + background: #D8D8DA url(bg.png) repeat-x 0 0; + + border: 1px solid transparent; + _border: 0 none; + border-bottom-right-radius: 10px; + border-bottom-left-radius: 10px; + -moz-border-radius-bottomright: 10px; + -moz-border-radius-bottomleft: 10px; + -webkit-border-bottom-right-radius: 10px; + -webkit-border-bottom-left-radius: 10px; +} + +.yui-skin-sam .yui-console-controls { + padding: 4px 1ex; + zoom: 1; +} + +.yui-skin-sam .yui-console-title { + color: #000; + display: inline; + float: left; + font-weight: bold; + font-size: 13px; + height: 24px; + line-height: 24px; + margin: 0; + padding-left: 1ex; +} + +.yui-skin-sam .yui-console-pause-label { + float: left; +} +.yui-skin-sam .yui-console-button { + line-height: 1.3; +} + +.yui-skin-sam .yui-console-collapsed .yui-console-bd, +.yui-skin-sam .yui-console-collapsed .yui-console-ft { + display: none; +} +.yui-skin-sam .yui-console-content.yui-console-collapsed { + -webkit-border-radius: 0; +} +.yui-skin-sam .yui-console-collapsed .yui-console-hd { + border-radius: 10px; + -moz-border-radius: 10px; + -webkit-border-radius: 0; +} + +/* Log entries */ +.yui-skin-sam .yui-console-entry { + border-bottom: 1px solid #aaa; + min-height: 32px; + _height: 32px; +} + +.yui-skin-sam .yui-console-entry-meta { + margin: 0; + overflow: hidden; +} + +.yui-skin-sam .yui-console-entry-content { + margin: 0; + padding: 0 1ex; + white-space: pre-wrap; + word-wrap: break-word; +} + +.yui-skin-sam .yui-console-entry-meta .yui-console-entry-src { + color: #000; + font-style: italic; + font-weight: bold; + float: right; + margin: 2px 5px 0 0; +} +.yui-skin-sam .yui-console-entry-meta .yui-console-entry-time { + color: #777; + padding-left: 1ex; +} +.yui-skin-sam .yui-console-entry-warn .yui-console-entry-meta .yui-console-entry-time { + color: #555; +} + +.yui-skin-sam .yui-console-entry-info .yui-console-entry-meta .yui-console-entry-cat, +.yui-skin-sam .yui-console-entry-warn .yui-console-entry-meta .yui-console-entry-cat, +.yui-skin-sam .yui-console-entry-error .yui-console-entry-meta .yui-console-entry-cat { + display: none; +} +.yui-skin-sam .yui-console-entry-warn { + background: #aee url(warn_error.png) no-repeat -15px 15px; +} +.yui-skin-sam .yui-console-entry-error { + background: #ffa url(warn_error.png) no-repeat 5px -24px; + color: #900; +} +.yui-skin-sam .yui-console-entry-warn .yui-console-entry-content, +.yui-skin-sam .yui-console-entry-error .yui-console-entry-content { + padding-left: 24px; +} +.yui-skin-sam .yui-console-entry-cat { + text-transform: uppercase; + padding: 1px 4px; + background-color: #ccc; +} +.yui-skin-sam .yui-console-entry-info .yui-console-entry-cat { + background-color: #ac2; +} +.yui-skin-sam .yui-console-entry-warn .yui-console-entry-cat { + background-color: #e81; +} +.yui-skin-sam .yui-console-entry-error .yui-console-entry-cat { + background-color: #b00; + color: #fff; +} + +.yui-skin-sam .yui-console-hidden { display: none; } diff --git a/include/javascript/yui3/build/console/assets/skins/sam/console.css b/include/javascript/yui3/build/console/assets/skins/sam/console.css new file mode 100644 index 00000000..5688517e --- /dev/null +++ b/include/javascript/yui3/build/console/assets/skins/sam/console.css @@ -0,0 +1,8 @@ +/* +Copyright (c) 2009, Yahoo! Inc. All rights reserved. +Code licensed under the BSD License: +http://developer.yahoo.net/yui/license.txt +version: 3.0.0 +build: 1549 +*/ +.yui-skin-sam .yui-separate-console{position:absolute;right:1em;top:1em;z-index:999;}.yui-skin-sam .yui-inline-console{display:-moz-inline-stack;display:inline-block;*display:inline;zoom:1;vertical-align:top;}.yui-skin-sam .yui-inline-console .yui-console-content{position:relative;}.yui-skin-sam .yui-console-content{background:#777;_background:#D8D8DA url(bg.png) repeat-x 0 0;font:normal 13px/1.3 Arial,sans-serif;text-align:left;border:1px solid #777;border-radius:10px;-moz-border-radius:10px;-webkit-border-radius:10px;}.yui-skin-sam .yui-console-hd,.yui-skin-sam .yui-console-bd,.yui-skin-sam .yui-console-ft{position:relative;}.yui-skin-sam .yui-console-hd,.yui-skin-sam .yui-console-ft .yui-console-controls{text-align:right;}.yui-skin-sam .yui-console-hd{background:#D8D8DA url(bg.png) repeat-x 0 0;padding:1ex;border:1px solid transparent;_border:0 none;border-top-right-radius:10px;border-top-left-radius:10px;-moz-border-radius-topright:10px;-moz-border-radius-topleft:10px;-webkit-border-top-right-radius:10px;-webkit-border-top-left-radius:10px;}.yui-skin-sam .yui-console-bd{background:#fff;border-top:1px solid #777;border-bottom:1px solid #777;color:#000;font-size:11px;overflow:auto;overflow-x:auto;overflow-y:scroll;_width:100%;}.yui-skin-sam .yui-console-ft{background:#D8D8DA url(bg.png) repeat-x 0 0;border:1px solid transparent;_border:0 none;border-bottom-right-radius:10px;border-bottom-left-radius:10px;-moz-border-radius-bottomright:10px;-moz-border-radius-bottomleft:10px;-webkit-border-bottom-right-radius:10px;-webkit-border-bottom-left-radius:10px;}.yui-skin-sam .yui-console-controls{padding:4px 1ex;zoom:1;}.yui-skin-sam .yui-console-title{color:#000;display:inline;float:left;font-weight:bold;font-size:13px;height:24px;line-height:24px;margin:0;padding-left:1ex;}.yui-skin-sam .yui-console-pause-label{float:left;}.yui-skin-sam .yui-console-button{line-height:1.3;}.yui-skin-sam .yui-console-collapsed .yui-console-bd,.yui-skin-sam .yui-console-collapsed .yui-console-ft{display:none;}.yui-skin-sam .yui-console-content.yui-console-collapsed{-webkit-border-radius:0;}.yui-skin-sam .yui-console-collapsed .yui-console-hd{border-radius:10px;-moz-border-radius:10px;-webkit-border-radius:0;}.yui-skin-sam .yui-console-entry{border-bottom:1px solid #aaa;min-height:32px;_height:32px;}.yui-skin-sam .yui-console-entry-meta{margin:0;overflow:hidden;}.yui-skin-sam .yui-console-entry-content{margin:0;padding:0 1ex;white-space:pre-wrap;word-wrap:break-word;}.yui-skin-sam .yui-console-entry-meta .yui-console-entry-src{color:#000;font-style:italic;font-weight:bold;float:right;margin:2px 5px 0 0;}.yui-skin-sam .yui-console-entry-meta .yui-console-entry-time{color:#777;padding-left:1ex;}.yui-skin-sam .yui-console-entry-warn .yui-console-entry-meta .yui-console-entry-time{color:#555;}.yui-skin-sam .yui-console-entry-info .yui-console-entry-meta .yui-console-entry-cat,.yui-skin-sam .yui-console-entry-warn .yui-console-entry-meta .yui-console-entry-cat,.yui-skin-sam .yui-console-entry-error .yui-console-entry-meta .yui-console-entry-cat{display:none;}.yui-skin-sam .yui-console-entry-warn{background:#aee url(warn_error.png) no-repeat -15px 15px;}.yui-skin-sam .yui-console-entry-error{background:#ffa url(warn_error.png) no-repeat 5px -24px;color:#900;}.yui-skin-sam .yui-console-entry-warn .yui-console-entry-content,.yui-skin-sam .yui-console-entry-error .yui-console-entry-content{padding-left:24px;}.yui-skin-sam .yui-console-entry-cat{text-transform:uppercase;padding:1px 4px;background-color:#ccc;}.yui-skin-sam .yui-console-entry-info .yui-console-entry-cat{background-color:#ac2;}.yui-skin-sam .yui-console-entry-warn .yui-console-entry-cat{background-color:#e81;}.yui-skin-sam .yui-console-entry-error .yui-console-entry-cat{background-color:#b00;color:#fff;}.yui-skin-sam .yui-console-hidden{display:none;} diff --git a/include/javascript/yui3/build/console/assets/skins/sam/warn_error.png b/include/javascript/yui3/build/console/assets/skins/sam/warn_error.png new file mode 100644 index 0000000000000000000000000000000000000000..db4e55483e346c03b793a2bd0be72847505c9ef0 GIT binary patch literal 703 zcmeAS@N?(olHy`uVBq!ia0vp^%0O(w!3-qLuM~O!DajJoh?3y^w370~qErUQl>DSr z1<%~X^wgl##FWaylc_d9MF#?WLR_z0x$^3j+16hJ(a~a$ADg(l zxoT@mu2`{RxvFYzZthZf`DxRp9XondM^Vw5fuXjxcH1_sPoF+bVPMc^WPG%J`@Xoi zojZ4SGcbgPghWS0tuZ#9!@w|OhVt#DOBXOOl$Mrm_w$>{z~JpIvU;`p!-o%TZ1|EH z7_6;j%*=Re85oWq*Go)HeEat8@87?Zlg0J)cr_#>E?qL5$IH9f);1$OeSw&mp@E*g zJ-@Ip%Z+*S7V`1^|No!wQ)fQVFAgO^e!)O4C4k{j^+p#421ZX$7srr_TW_w!<~JFL zusztu@yU?&r-om^hA3AVtwqv@%>Mu1A9Zq5s<`c)x965+R(*W3#5O;wq}?s8KTEpQ znnkeW4u5;~;g^QS##gsX-3v3zFuHs^Vzt4(FyjLYlDjysl_lNeGurv_jJ9A}2j|83 zoSmKJRq5vrJ^0LFu=ZatyNUMX7c9#&)uUbW=0wbiwExlcgO}-D-x=m(v&)-Ko@1)c z2(`28xLIWzY2mgyb9Up^>DOg7Ki?>>GXA?-{#l~jv-;l0XP@8q7cx3%c&1y4|22cj z(uGFHgr==<DSr z1<%~X^wgl##FWaylc_d9MF#?WLR_z0x$^3j+16hJ(a~a$ADg(l zxoT@mu2`{RxvFYzZthZf`DxRp9XondM^Vw5fuXjxcH1_sPoF+bVPMc^WPG%J`@Xoi zojZ4SGcbgPghWS0tuZ#9!@w|OhVt#DOBXOOl$Mrm_w$>{z~JpIvU;`p!-o%TZ1|EH z7_6;j%*=Re85oWq*Go)HeEat8@87?Zlg0J)cr_#>E?qL5$IH9f);1$OeSw&mp@E*g zJ-@Ip%Z+*S7V`1^|No!wQ)fQVFAgO^e!)O4C4k{j^+p#421ZX$7srr_TW_w!<~JFL zusztu@yU?&r-om^hA3AVtwqv@%>Mu1A9Zq5s<`c)x965+R(*W3#5O;wq}?s8KTEpQ znnkeW4u5;~;g^QS##gsX-3v3zFuHs^Vzt4(FyjLYlDjysl_lNeGurv_jJ9A}2j|83 zoSmKJRq5vrJ^0LFu=ZatyNUMX7c9#&)uUbW=0wbiwExlcgO}-D-x=m(v&)-Ko@1)c z2(`28xLIWzY2mgyb9Up^>DOg7Ki?>>GXA?-{#l~jv-;l0XP@8q7cx3%c&1y4|22cj z(uGFHgr==<',SOURCES_TEMPLATE:'

    ',FILTER_TEMPLATE:' ",CHROME_CLASSES:{categories:Q(G,B,"categories"),sources:Q(G,B,"sources"),category:Q(G,L,F),source:Q(G,L,D),filter:Q(G,L),filter_label:Q(G,L,"label")},ATTRS:{defaultVisibility:{value:true,validator:C.Lang.isBoolean},category:{value:{},validator:function(V,U){return this._validateCategory(U,V);}},source:{value:{},validator:function(V,U){return this._validateSource(U,V);}},cacheLimit:{value:Number.POSITIVE_INFINITY,setter:function(U){if(C.Lang.isNumber(U)){this._cacheLimit=U;return U;}else{return C.Attribute.INVALID_VALUE;}}}}});C.extend(K,C.Plugin.Base,{_entries:null,_cacheLimit:Number.POSITIVE_INFINITY,_categories:null,_sources:null,initializer:function(){this._entries=[];this.get(P).on("entry",this._onEntry,this);this.doAfter("renderUI",this.renderUI);this.doAfter("syncUI",this.syncUI);this.doAfter("bindUI",this.bindUI);this.doAfter("clearConsole",this._afterClearConsole);if(this.get(P).get("rendered")){this.renderUI();this.syncUI();this.bindUI();}this.after("cacheLimitChange",this._afterCacheLimitChange);},destructor:function(){this._entries=[];if(this._categories){this._categories.get(H).removeChild(this._categories);}if(this._sources){this._sources.get(H).removeChild(this._sources);}},renderUI:function(){var V=this.get(P).get("contentBox").query(I),U;if(V){U=C.substitute(K.CATEGORIES_TEMPLATE,K.CHROME_CLASSES);this._categories=V.appendChild(C.Node.create(U));U=C.substitute(K.SOURCES_TEMPLATE,K.CHROME_CLASSES);this._sources=V.appendChild(C.Node.create(U));}},bindUI:function(){this._categories.on("click",C.bind(this._onCategoryCheckboxClick,this));this._sources.on("click",C.bind(this._onSourceCheckboxClick,this));this.after("categoryChange",this._afterCategoryChange);this.after("sourceChange",this._afterSourceChange);},syncUI:function(){C.each(this.get(F),function(V,U){this._uiSetCheckbox(F,U,V);},this);C.each(this.get(D),function(V,U){this._uiSetCheckbox(D,U,V);},this);this.refreshConsole();},_onEntry:function(X){this._entries.push(X.message);var U=E+X.message.category,Z=M+X.message.source,V=this.get(U),a=this.get(Z),W=this._entries.length-this._cacheLimit,Y;if(W>0){this._entries.splice(0,W);}if(V===undefined){Y=this.get(O);this.set(U,Y);V=Y;}if(a===undefined){Y=this.get(O);this.set(Z,Y);a=Y;}if(!V||!a){X.preventDefault();}},_afterClearConsole:function(){this._entries=[];},_afterCategoryChange:function(W){var U=W.subAttrName.replace(/category\./,T),V=W.prevVal,X=W.newVal;if(!U||V[U]!==undefined){this.refreshConsole();this._filterBuffer();}if(U&&!W.fromUI){this._uiSetCheckbox(F,U,X[U]);}},_afterSourceChange:function(V){var X=V.subAttrName.replace(/source\./,T),U=V.prevVal,W=V.newVal;if(!X||U[X]!==undefined){this.refreshConsole();this._filterBuffer();}if(X&&!V.fromUI){this._uiSetCheckbox(D,X,W[X]);}},_filterBuffer:function(){var V=this.get(F),X=this.get(D),U=this.get(P).buffer,Y=null,W;for(W=U.length-1;W>=0;--W){if(!V[U[W].category]||!X[U[W].source]){Y=Y||W;}else{if(Y){U.splice(W,(Y-W));Y=null;}}}if(Y){U.splice(0,Y+1);}},_afterCacheLimitChange:function(U){if(isFinite(U.newVal)){var V=this._entries.length-U.newVal;if(V>0){this._entries.splice(0,V);}}},refreshConsole:function(){var Y=this._entries,c=this.get(P),Z=c.get("contentBox").query(S),V=c.get("consoleLimit"),b=this.get(F),U=this.get(D),W=[],X,a;if(Z){c._cancelPrintLoop();for(X=Y.length-1;X>=0&&V>=0;--X){a=Y[X];if(b[a.category]&&U[a.source]){W.unshift(a);--V;}}Z.set("innerHTML",T);c.buffer=W;c.printBuffer();}},_uiSetCheckbox:function(V,Y,X){if(V&&Y){var U=V===F?this._categories:this._sources,a=A+Q(G,L,Y),Z=U.query(a),W;if(!Z){W=this.get(P);this._createCheckbox(U,Y);Z=U.query(a);W._uiSetHeight(W.get("height"));}Z.set(R,X);}},_onCategoryCheckboxClick:function(W){var V=W.target,U;if(V.hasClass(K.CHROME_CLASSES.filter)){U=V.get("value");if(U&&U in this.get(F)){this.set(E+U,V.get(R),{fromUI:true});}}},_onSourceCheckboxClick:function(V){var U=V.target,W;if(U.hasClass(K.CHROME_CLASSES.filter)){W=U.get("value");if(W&&W in this.get(D)){this.set(M+W,U.get(R),{fromUI:true});}}},hideCategory:function(V,U){if(J(U)){C.Array.each(arguments,arguments.callee,this);}else{this.set(E+V,false);}},showCategory:function(V,U){if(J(U)){C.Array.each(arguments,arguments.callee,this);}else{this.set(E+V,true);}},hideSource:function(V,U){if(J(U)){C.Array.each(arguments,arguments.callee,this);}else{this.set(M+V,false);}},showSource:function(V,U){if(J(U)){C.Array.each(arguments,arguments.callee,this);}else{this.set(M+V,true);}},_createCheckbox:function(U,V){var X=C.merge(K.CHROME_CLASSES,{filter_name:V,filter_class:Q(G,L,V)}),W=C.Node.create(C.substitute(K.FILTER_TEMPLATE,X));U.appendChild(W);},_validateCategory:function(U,V){return C.Lang.isObject(V,true)&&U.split(/\./).length<3;},_validateSource:function(V,U){return C.Lang.isObject(U,true)&&V.split(/\./).length<3;}});C.namespace("Plugin").ConsoleFilters=K;},"3.0.0",{requires:["console","plugin"]}); \ No newline at end of file diff --git a/include/javascript/yui3/build/console/console-filters.js b/include/javascript/yui3/build/console/console-filters.js new file mode 100644 index 00000000..9ac8001d --- /dev/null +++ b/include/javascript/yui3/build/console/console-filters.js @@ -0,0 +1,19 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add('console-filters',function(Y){var getCN=Y.ClassNameManager.getClassName,CONSOLE='console',FILTERS='filters',FILTER='filter',CATEGORY='category',SOURCE='source',CATEGORY_DOT='category.',SOURCE_DOT='source.',HOST='host',PARENT_NODE='parentNode',CHECKED='checked',DEF_VISIBILITY='defaultVisibility',DOT='.',EMPTY='',C_BODY=DOT+Y.Console.CHROME_CLASSES.console_bd_class,C_FOOT=DOT+Y.Console.CHROME_CLASSES.console_ft_class,SEL_CHECK='input[type=checkbox].',isString=Y.Lang.isString;function ConsoleFilters(){ConsoleFilters.superclass.constructor.apply(this,arguments);} +Y.mix(ConsoleFilters,{NAME:'consoleFilters',NS:FILTER,CATEGORIES_TEMPLATE:'
    ',SOURCES_TEMPLATE:'
    ',FILTER_TEMPLATE:' ',CHROME_CLASSES:{categories:getCN(CONSOLE,FILTERS,'categories'),sources:getCN(CONSOLE,FILTERS,'sources'),category:getCN(CONSOLE,FILTER,CATEGORY),source:getCN(CONSOLE,FILTER,SOURCE),filter:getCN(CONSOLE,FILTER),filter_label:getCN(CONSOLE,FILTER,'label')},ATTRS:{defaultVisibility:{value:true,validator:Y.Lang.isBoolean},category:{value:{},validator:function(v,k){return this._validateCategory(k,v);}},source:{value:{},validator:function(v,k){return this._validateSource(k,v);}},cacheLimit:{value:Number.POSITIVE_INFINITY,setter:function(v){if(Y.Lang.isNumber(v)){this._cacheLimit=v;return v;}else{return Y.Attribute.INVALID_VALUE;}}}}});Y.extend(ConsoleFilters,Y.Plugin.Base,{_entries:null,_cacheLimit:Number.POSITIVE_INFINITY,_categories:null,_sources:null,initializer:function(){this._entries=[];this.get(HOST).on("entry",this._onEntry,this);this.doAfter("renderUI",this.renderUI);this.doAfter("syncUI",this.syncUI);this.doAfter("bindUI",this.bindUI);this.doAfter("clearConsole",this._afterClearConsole);if(this.get(HOST).get('rendered')){this.renderUI();this.syncUI();this.bindUI();} +this.after("cacheLimitChange",this._afterCacheLimitChange);},destructor:function(){this._entries=[];if(this._categories){this._categories.get(PARENT_NODE).removeChild(this._categories);} +if(this._sources){this._sources.get(PARENT_NODE).removeChild(this._sources);}},renderUI:function(){var foot=this.get(HOST).get('contentBox').query(C_FOOT),html;if(foot){html=Y.substitute(ConsoleFilters.CATEGORIES_TEMPLATE,ConsoleFilters.CHROME_CLASSES);this._categories=foot.appendChild(Y.Node.create(html));html=Y.substitute(ConsoleFilters.SOURCES_TEMPLATE,ConsoleFilters.CHROME_CLASSES);this._sources=foot.appendChild(Y.Node.create(html));}},bindUI:function(){this._categories.on('click',Y.bind(this._onCategoryCheckboxClick,this));this._sources.on('click',Y.bind(this._onSourceCheckboxClick,this));this.after('categoryChange',this._afterCategoryChange);this.after('sourceChange',this._afterSourceChange);},syncUI:function(){Y.each(this.get(CATEGORY),function(v,k){this._uiSetCheckbox(CATEGORY,k,v);},this);Y.each(this.get(SOURCE),function(v,k){this._uiSetCheckbox(SOURCE,k,v);},this);this.refreshConsole();},_onEntry:function(e){this._entries.push(e.message);var cat=CATEGORY_DOT+e.message.category,src=SOURCE_DOT+e.message.source,cat_filter=this.get(cat),src_filter=this.get(src),overLimit=this._entries.length-this._cacheLimit,visible;if(overLimit>0){this._entries.splice(0,overLimit);} +if(cat_filter===undefined){visible=this.get(DEF_VISIBILITY);this.set(cat,visible);cat_filter=visible;} +if(src_filter===undefined){visible=this.get(DEF_VISIBILITY);this.set(src,visible);src_filter=visible;} +if(!cat_filter||!src_filter){e.preventDefault();}},_afterClearConsole:function(){this._entries=[];},_afterCategoryChange:function(e){var cat=e.subAttrName.replace(/category\./,EMPTY),before=e.prevVal,after=e.newVal;if(!cat||before[cat]!==undefined){this.refreshConsole();this._filterBuffer();} +if(cat&&!e.fromUI){this._uiSetCheckbox(CATEGORY,cat,after[cat]);}},_afterSourceChange:function(e){var src=e.subAttrName.replace(/source\./,EMPTY),before=e.prevVal,after=e.newVal;if(!src||before[src]!==undefined){this.refreshConsole();this._filterBuffer();} +if(src&&!e.fromUI){this._uiSetCheckbox(SOURCE,src,after[src]);}},_filterBuffer:function(){var cats=this.get(CATEGORY),srcs=this.get(SOURCE),buffer=this.get(HOST).buffer,start=null,i;for(i=buffer.length-1;i>=0;--i){if(!cats[buffer[i].category]||!srcs[buffer[i].source]){start=start||i;}else if(start){buffer.splice(i,(start-i));start=null;}} +if(start){buffer.splice(0,start+1);}},_afterCacheLimitChange:function(e){if(isFinite(e.newVal)){var delta=this._entries.length-e.newVal;if(delta>0){this._entries.splice(0,delta);}}},refreshConsole:function(){var entries=this._entries,host=this.get(HOST),body=host.get('contentBox').query(C_BODY),remaining=host.get('consoleLimit'),cats=this.get(CATEGORY),srcs=this.get(SOURCE),buffer=[],i,e;if(body){host._cancelPrintLoop();for(i=entries.length-1;i>=0&&remaining>=0;--i){e=entries[i];if(cats[e.category]&&srcs[e.source]){buffer.unshift(e);--remaining;}} +body.set('innerHTML',EMPTY);host.buffer=buffer;host.printBuffer();}},_uiSetCheckbox:function(type,item,checked){if(type&&item){var container=type===CATEGORY?this._categories:this._sources,sel=SEL_CHECK+getCN(CONSOLE,FILTER,item),checkbox=container.query(sel),host;if(!checkbox){host=this.get(HOST);this._createCheckbox(container,item);checkbox=container.query(sel);host._uiSetHeight(host.get('height'));} +checkbox.set(CHECKED,checked);}},_onCategoryCheckboxClick:function(e){var t=e.target,cat;if(t.hasClass(ConsoleFilters.CHROME_CLASSES.filter)){cat=t.get('value');if(cat&&cat in this.get(CATEGORY)){this.set(CATEGORY_DOT+cat,t.get(CHECKED),{fromUI:true});}}},_onSourceCheckboxClick:function(e){var t=e.target,src;if(t.hasClass(ConsoleFilters.CHROME_CLASSES.filter)){src=t.get('value');if(src&&src in this.get(SOURCE)){this.set(SOURCE_DOT+src,t.get(CHECKED),{fromUI:true});}}},hideCategory:function(cat,multiple){if(isString(multiple)){Y.Array.each(arguments,arguments.callee,this);}else{this.set(CATEGORY_DOT+cat,false);}},showCategory:function(cat,multiple){if(isString(multiple)){Y.Array.each(arguments,arguments.callee,this);}else{this.set(CATEGORY_DOT+cat,true);}},hideSource:function(src,multiple){if(isString(multiple)){Y.Array.each(arguments,arguments.callee,this);}else{this.set(SOURCE_DOT+src,false);}},showSource:function(src,multiple){if(isString(multiple)){Y.Array.each(arguments,arguments.callee,this);}else{this.set(SOURCE_DOT+src,true);}},_createCheckbox:function(container,name){var info=Y.merge(ConsoleFilters.CHROME_CLASSES,{filter_name:name,filter_class:getCN(CONSOLE,FILTER,name)}),node=Y.Node.create(Y.substitute(ConsoleFilters.FILTER_TEMPLATE,info));container.appendChild(node);},_validateCategory:function(cat,v){return Y.Lang.isObject(v,true)&&cat.split(/\./).length<3;},_validateSource:function(src,v){return Y.Lang.isObject(v,true)&&src.split(/\./).length<3;}});Y.namespace('Plugin').ConsoleFilters=ConsoleFilters;},'3.0.0',{requires:['console','plugin']}); \ No newline at end of file diff --git a/include/javascript/yui3/build/console/console-min.js b/include/javascript/yui3/build/console/console-min.js new file mode 100644 index 00000000..41e67d58 --- /dev/null +++ b/include/javascript/yui3/build/console/console-min.js @@ -0,0 +1,8 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add("console",function(D){function V(){V.superclass.constructor.apply(this,arguments);}var G=D.ClassNameManager.getClassName,B="checked",s="clear",r="click",T="collapsed",AE="console",d="contentBox",h="disabled",o="entry",l="error",j="height",P="info",y="innerHTML",M="lastTime",F="pause",f="paused",x="reset",v="startTime",p="title",i="warn",Z=".",X=G(AE,"button"),b=G(AE,"checkbox"),AD=G(AE,s),w=G(AE,"collapse"),S=G(AE,T),E=G(AE,"controls"),e=G(AE,"hd"),c=G(AE,"bd"),C=G(AE,"ft"),k=G(AE,p),z=G(AE,o),t=G(AE,o,"cat"),a=G(AE,o,"content"),U=G(AE,o,"meta"),g=G(AE,o,"src"),A=G(AE,o,"time"),Q=G(AE,F),W=G(AE,F,"label"),n=/^(\S+)\s/,AA=/&/g,u=/>/g,J=/'+'

    '+''+"{sourceAndDetail}"+""+''+"{category}"+''+" {totalTime}ms (+{elapsedTime}) {localTime}"+""+"

    "+'
    {message}
    '+"",I=D.Lang,K=D.Node.create,AC=I.isNumber,N=I.isString,q=D.merge,AB=D.substitute;D.mix(V,{NAME:AE,LOG_LEVEL_INFO:P,LOG_LEVEL_WARN:i,LOG_LEVEL_ERROR:l,ENTRY_CLASSES:{entry_class:z,entry_meta_class:U,entry_cat_class:t,entry_src_class:g,entry_time_class:A,entry_content_class:a},CHROME_CLASSES:{console_hd_class:e,console_bd_class:c,console_ft_class:C,console_controls_class:E,console_checkbox_class:b,console_pause_class:Q,console_pause_label_class:W,console_button_class:X,console_clear_class:AD,console_collapse_class:w,console_title_class:k},HEADER_TEMPLATE:'
    '+'

    {str_title}

    '+'"+"
    ",BODY_TEMPLATE:'
    ',FOOTER_TEMPLATE:'
    '+'
    '+'"+'"+"
    "+"
    ",ENTRY_TEMPLATE:O,ATTRS:{logEvent:{value:"yui:log",writeOnce:true,validator:N},logSource:{value:D,writeOnce:true,validator:function(L){return L&&D.Lang.isFunction(L.on);}},strings:{value:{title:"Log Console",pause:"Pause",clear:"Clear",collapse:"Collapse",expand:"Expand"}},paused:{value:false,validator:I.isBoolean},defaultCategory:{value:P,validator:N},defaultSource:{value:"global",validator:N},entryTemplate:{value:O,validator:N},logLevel:{value:D.config.logLevel||P,setter:function(L){return this._setLogLevel(L);}},printTimeout:{value:100,validator:AC},printLimit:{value:50,validator:AC},consoleLimit:{value:300,validator:AC},newestOnTop:{value:true},scrollIntoView:{value:true},startTime:{value:new Date()},lastTime:{value:new Date(),readOnly:true},collapsed:{value:false},height:{value:"300px"},width:{value:"300px"},useBrowserConsole:{lazyAdd:false,value:false,getter:function(){var L=this.get("logSource");return L instanceof YUI?L.config.useBrowserConsole:null;},setter:function(L){var Y=this.get("logSource");if(Y instanceof YUI){L=!!L;Y.config.useBrowserConsole=!!L;return L;}else{return D.Attribute.INVALID_VALUE;}}},style:{value:"separate",writeOnce:true,validator:function(L){return this._validateStyle(L);}}}});D.extend(V,D.Widget,{_evtCat:null,_head:null,_body:null,_foot:null,_printLoop:null,buffer:null,log:function(){D.log.apply(D,arguments);return this;},clearConsole:function(){this._body.set(y,"");this._cancelPrintLoop();this.buffer=[];return this;},reset:function(){this.fire(x);return this;},collapse:function(){this.set(T,true);return this;},expand:function(){this.set(T,false);return this;},printBuffer:function(Y){var AK=this.buffer,AF=D.config.debug,L=[],AH=this.get("consoleLimit"),AJ=this.get("newestOnTop"),AG=AJ?this._body.get("firstChild"):null,AI;if(AK.length>AH){AK.splice(0,AK.length-AH);}Y=Math.min(AK.length,(Y||AK.length));D.config.debug=false;if(!this.get(f)&&this.get("rendered")){for(AI=0;AI0){if(this.get("newestOnTop")){AH=AF;Y=L.size();}else{AH=0;}this._body.setStyle("display","none");for(;AH/g,RE_LT=/'+'

    '+''+'{sourceAndDetail}'+''+''+'{category}'+''+' {totalTime}ms (+{elapsedTime}) {localTime}'+''+'

    '+'
    {message}
    '+'',L=Y.Lang,create=Y.Node.create,isNumber=L.isNumber,isString=L.isString,merge=Y.merge,substitute=Y.substitute;Y.mix(Console,{NAME:CONSOLE,LOG_LEVEL_INFO:INFO,LOG_LEVEL_WARN:WARN,LOG_LEVEL_ERROR:ERROR,ENTRY_CLASSES:{entry_class:C_ENTRY,entry_meta_class:C_ENTRY_META,entry_cat_class:C_ENTRY_CAT,entry_src_class:C_ENTRY_SRC,entry_time_class:C_ENTRY_TIME,entry_content_class:C_ENTRY_CONTENT},CHROME_CLASSES:{console_hd_class:C_CONSOLE_HD,console_bd_class:C_CONSOLE_BD,console_ft_class:C_CONSOLE_FT,console_controls_class:C_CONSOLE_CONTROLS,console_checkbox_class:C_CHECKBOX,console_pause_class:C_PAUSE,console_pause_label_class:C_PAUSE_LABEL,console_button_class:C_BUTTON,console_clear_class:C_CLEAR,console_collapse_class:C_COLLAPSE,console_title_class:C_CONSOLE_TITLE},HEADER_TEMPLATE:'
    '+'

    {str_title}

    '+''+'
    ',BODY_TEMPLATE:'
    ',FOOTER_TEMPLATE:'
    '+'
    '+''+''+'
    '+'
    ',ENTRY_TEMPLATE:ENTRY_TEMPLATE_STR,ATTRS:{logEvent:{value:'yui:log',writeOnce:true,validator:isString},logSource:{value:Y,writeOnce:true,validator:function(v){return v&&Y.Lang.isFunction(v.on);}},strings:{value:{title:"Log Console",pause:"Pause",clear:"Clear",collapse:"Collapse",expand:"Expand"}},paused:{value:false,validator:L.isBoolean},defaultCategory:{value:INFO,validator:isString},defaultSource:{value:'global',validator:isString},entryTemplate:{value:ENTRY_TEMPLATE_STR,validator:isString},logLevel:{value:Y.config.logLevel||INFO,setter:function(v){return this._setLogLevel(v);}},printTimeout:{value:100,validator:isNumber},printLimit:{value:50,validator:isNumber},consoleLimit:{value:300,validator:isNumber},newestOnTop:{value:true},scrollIntoView:{value:true},startTime:{value:new Date()},lastTime:{value:new Date(),readOnly:true},collapsed:{value:false},height:{value:"300px"},width:{value:"300px"},useBrowserConsole:{lazyAdd:false,value:false,getter:function(){var logSource=this.get('logSource');return logSource instanceof YUI?logSource.config.useBrowserConsole:null;},setter:function(v){var logSource=this.get('logSource');if(logSource instanceof YUI){v=!!v;logSource.config.useBrowserConsole=!!v;return v;}else{return Y.Attribute.INVALID_VALUE;}}},style:{value:'separate',writeOnce:true,validator:function(v){return this._validateStyle(v);}}}});Y.extend(Console,Y.Widget,{_evtCat:null,_head:null,_body:null,_foot:null,_printLoop:null,buffer:null,log:function(){Y.log.apply(Y,arguments);return this;},clearConsole:function(){this._body.set(INNER_HTML,'');this._cancelPrintLoop();this.buffer=[];return this;},reset:function(){this.fire(RESET);return this;},collapse:function(){this.set(COLLAPSED,true);return this;},expand:function(){this.set(COLLAPSED,false);return this;},printBuffer:function(limit){var messages=this.buffer,debug=Y.config.debug,entries=[],consoleLimit=this.get('consoleLimit'),newestOnTop=this.get('newestOnTop'),anchor=newestOnTop?this._body.get('firstChild'):null,i;if(messages.length>consoleLimit){messages.splice(0,messages.length-consoleLimit);} +limit=Math.min(messages.length,(limit||messages.length));Y.config.debug=false;if(!this.get(PAUSED)&&this.get('rendered')){for(i=0;i0){if(this.get('newestOnTop')){i=limit;l=entries.size();}else{i=0;} +this._body.setStyle('display','none');for(;i0){var L=(Y===false?function(Z){return Z;}:B),U=W.split(/;\s/g),V=G,O=G,R=G;for(var Q=0,S=U.length;Q0){var decodeValue=(shouldDecode===false?function(s){return s;}:decode),cookieParts=text.split(/;\s/g),cookieName=NULL,cookieValue=NULL,cookieNameValue=NULL;for(var i=0,len=cookieParts.length;i-1;F--){O={};N=K[F];I=(A.isObject(N)&&!A.isFunction(N))?2:(A.isArray(N))?1:(A.isString(N))?0:-1;if(I>0){for(E=H.length-1;E>-1;E--){J=H[E];M=(!A.isUndefined(J.key))?J.key:J;L=(!A.isUndefined(N[M]))?N[M]:N[E];O[M]=C.DataSchema.Base.parse(L,J);}}else{if(I===0){O=N;}else{O=null;}}G[F]=O;}D.results=G;return D;}};C.DataSchema.Array=C.mix(B,C.DataSchema.Base);},"3.0.0",{requires:["dataschema-base"]}); \ No newline at end of file diff --git a/include/javascript/yui3/build/dataschema/dataschema-array.js b/include/javascript/yui3/build/dataschema/dataschema-array.js new file mode 100644 index 00000000..0a6cdb7a --- /dev/null +++ b/include/javascript/yui3/build/dataschema/dataschema-array.js @@ -0,0 +1,15 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add('dataschema-array',function(Y){var LANG=Y.Lang,SchemaArray={apply:function(schema,data){var data_in=data,data_out={results:[],meta:{}};if(LANG.isArray(data_in)){if(LANG.isArray(schema.resultFields)){data_out=SchemaArray._parseResults(schema.resultFields,data_in,data_out);} +else{data_out.results=data_in;}} +else{data_out.error=new Error("Array schema parse failure");} +return data_out;},_parseResults:function(fields,array_in,data_out){var results=[],result,item,type,field,key,value,i,j;for(i=array_in.length-1;i>-1;i--){result={};item=array_in[i];type=(LANG.isObject(item)&&!LANG.isFunction(item))?2:(LANG.isArray(item))?1:(LANG.isString(item))?0:-1;if(type>0){for(j=fields.length-1;j>-1;j--){field=fields[j];key=(!LANG.isUndefined(field.key))?field.key:field;value=(!LANG.isUndefined(item[key]))?item[key]:item[j];result[key]=Y.DataSchema.Base.parse(value,field);}} +else if(type===0){result=item;} +else{result=null;} +results[i]=result;} +data_out.results=results;return data_out;}};Y.DataSchema.Array=Y.mix(SchemaArray,Y.DataSchema.Base);},'3.0.0',{requires:['dataschema-base']}); \ No newline at end of file diff --git a/include/javascript/yui3/build/dataschema/dataschema-base-min.js b/include/javascript/yui3/build/dataschema/dataschema-base-min.js new file mode 100644 index 00000000..4bd964e3 --- /dev/null +++ b/include/javascript/yui3/build/dataschema/dataschema-base-min.js @@ -0,0 +1,8 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add("dataschema-base",function(B){var A=B.Lang,C={apply:function(D,E){return E;},parse:function(D,E){if(E.parser){var F=(A.isFunction(E.parser))?E.parser:B.Parsers[E.parser+""];if(F){D=F.call(this,D);}else{}}return D;}};B.namespace("DataSchema").Base=C;B.namespace("Parsers");},"3.0.0",{requires:["base"]}); \ No newline at end of file diff --git a/include/javascript/yui3/build/dataschema/dataschema-base.js b/include/javascript/yui3/build/dataschema/dataschema-base.js new file mode 100644 index 00000000..86e43cbc --- /dev/null +++ b/include/javascript/yui3/build/dataschema/dataschema-base.js @@ -0,0 +1,10 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add('dataschema-base',function(Y){var LANG=Y.Lang,SchemaBase={apply:function(schema,data){return data;},parse:function(value,field){if(field.parser){var parser=(LANG.isFunction(field.parser))?field.parser:Y.Parsers[field.parser+''];if(parser){value=parser.call(this,value);} +else{}} +return value;}};Y.namespace("DataSchema").Base=SchemaBase;Y.namespace("Parsers");},'3.0.0',{requires:['base']}); \ No newline at end of file diff --git a/include/javascript/yui3/build/dataschema/dataschema-json-min.js b/include/javascript/yui3/build/dataschema/dataschema-json-min.js new file mode 100644 index 00000000..633687aa --- /dev/null +++ b/include/javascript/yui3/build/dataschema/dataschema-json-min.js @@ -0,0 +1,8 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add("dataschema-json",function(C){var A=C.Lang,B={getPath:function(D){var G=null,F=[],E=0;if(D){D=D.replace(/\[(['"])(.*?)\1\]/g,function(I,H,J){F[E]=J;return".@"+(E++);}).replace(/\[(\d+)\]/g,function(I,H){F[E]=parseInt(H,10)|0;return".@"+(E++);}).replace(/^\./,"");if(!/[^\w\.\$@]/.test(D)){G=D.split(".");for(E=G.length-1;E>=0;--E){if(G[E].charAt(0)==="@"){G[E]=F[parseInt(G[E].substr(1),10)];}}}else{}}return G;},getLocationValue:function(G,F){var E=0,D=G.length;for(;E=0;--H){I={};R=P[H];if(R){for(F=J.length-1;F>=0;--F){I[J[F].key]=C.DataSchema.Base.parse((A.isUndefined(R[J[F].path])?R[F]:R[J[F].path]),J[F]);}for(F=N.length-1;F>=0;--F){I[N[F].key]=C.DataSchema.Base.parse((B.getLocationValue(N[F].path,R)),N[F]);}for(F=L.length-1;F>=0;--F){Q=L[F].key;I[Q]=L[F].parser(I[Q]);if(A.isUndefined(I[Q])){I[Q]=null;}}G[H]=I;}}E.results=G;return E;},_parseMeta:function(G,D,F){if(A.isObject(G)){var E,H;for(E in G){if(G.hasOwnProperty(E)){H=B.getPath(G[E]);if(H&&D){F.meta[E]=B.getLocationValue(H,D);}}}}else{F.error=new Error("JSON meta data retrieval failure");}return F;}};C.DataSchema.JSON=C.mix(B,C.DataSchema.Base);},"3.0.0",{requires:["json","dataschema-base"]}); \ No newline at end of file diff --git a/include/javascript/yui3/build/dataschema/dataschema-json.js b/include/javascript/yui3/build/dataschema/dataschema-json.js new file mode 100644 index 00000000..6b49e3ef --- /dev/null +++ b/include/javascript/yui3/build/dataschema/dataschema-json.js @@ -0,0 +1,30 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add('dataschema-json',function(Y){var LANG=Y.Lang,SchemaJSON={getPath:function(locator){var path=null,keys=[],i=0;if(locator){locator=locator.replace(/\[(['"])(.*?)\1\]/g,function(x,$1,$2){keys[i]=$2;return'.@'+(i++);}).replace(/\[(\d+)\]/g,function(x,$1){keys[i]=parseInt($1,10)|0;return'.@'+(i++);}).replace(/^\./,'');if(!/[^\w\.\$@]/.test(locator)){path=locator.split('.');for(i=path.length-1;i>=0;--i){if(path[i].charAt(0)==='@'){path[i]=keys[parseInt(path[i].substr(1),10)];}}} +else{}} +return path;},getLocationValue:function(path,data){var i=0,len=path.length;for(;i=0;--i){record={};result=array_in[i];if(result){for(j=simplePaths.length-1;j>=0;--j){record[simplePaths[j].key]=Y.DataSchema.Base.parse((LANG.isUndefined(result[simplePaths[j].path])?result[j]:result[simplePaths[j].path]),simplePaths[j]);} +for(j=complexPaths.length-1;j>=0;--j){record[complexPaths[j].key]=Y.DataSchema.Base.parse((SchemaJSON.getLocationValue(complexPaths[j].path,result)),complexPaths[j]);} +for(j=fieldParsers.length-1;j>=0;--j){key=fieldParsers[j].key;record[key]=fieldParsers[j].parser(record[key]);if(LANG.isUndefined(record[key])){record[key]=null;}} +results[i]=record;}} +data_out.results=results;return data_out;},_parseMeta:function(metaFields,json_in,data_out){if(LANG.isObject(metaFields)){var key,path;for(key in metaFields){if(metaFields.hasOwnProperty(key)){path=SchemaJSON.getPath(metaFields[key]);if(path&&json_in){data_out.meta[key]=SchemaJSON.getLocationValue(path,json_in);}}}} +else{data_out.error=new Error("JSON meta data retrieval failure");} +return data_out;}};Y.DataSchema.JSON=Y.mix(SchemaJSON,Y.DataSchema.Base);},'3.0.0',{requires:['json','dataschema-base']}); \ No newline at end of file diff --git a/include/javascript/yui3/build/dataschema/dataschema-min.js b/include/javascript/yui3/build/dataschema/dataschema-min.js new file mode 100644 index 00000000..69846c00 --- /dev/null +++ b/include/javascript/yui3/build/dataschema/dataschema-min.js @@ -0,0 +1,8 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add("dataschema-base",function(B){var A=B.Lang,C={apply:function(D,E){return E;},parse:function(D,E){if(E.parser){var F=(A.isFunction(E.parser))?E.parser:B.Parsers[E.parser+""];if(F){D=F.call(this,D);}else{}}return D;}};B.namespace("DataSchema").Base=C;B.namespace("Parsers");},"3.0.0",{requires:["base"]});YUI.add("dataschema-json",function(C){var A=C.Lang,B={getPath:function(D){var G=null,F=[],E=0;if(D){D=D.replace(/\[(['"])(.*?)\1\]/g,function(I,H,J){F[E]=J;return".@"+(E++);}).replace(/\[(\d+)\]/g,function(I,H){F[E]=parseInt(H,10)|0;return".@"+(E++);}).replace(/^\./,"");if(!/[^\w\.\$@]/.test(D)){G=D.split(".");for(E=G.length-1;E>=0;--E){if(G[E].charAt(0)==="@"){G[E]=F[parseInt(G[E].substr(1),10)];}}}else{}}return G;},getLocationValue:function(G,F){var E=0,D=G.length;for(;E=0;--H){I={};R=P[H];if(R){for(F=J.length-1;F>=0;--F){I[J[F].key]=C.DataSchema.Base.parse((A.isUndefined(R[J[F].path])?R[F]:R[J[F].path]),J[F]);}for(F=N.length-1;F>=0;--F){I[N[F].key]=C.DataSchema.Base.parse((B.getLocationValue(N[F].path,R)),N[F]);}for(F=L.length-1;F>=0;--F){Q=L[F].key;I[Q]=L[F].parser(I[Q]);if(A.isUndefined(I[Q])){I[Q]=null;}}G[H]=I;}}E.results=G;return E;},_parseMeta:function(G,D,F){if(A.isObject(G)){var E,H;for(E in G){if(G.hasOwnProperty(E)){H=B.getPath(G[E]);if(H&&D){F.meta[E]=B.getLocationValue(H,D);}}}}else{F.error=new Error("JSON meta data retrieval failure");}return F;}};C.DataSchema.JSON=C.mix(B,C.DataSchema.Base);},"3.0.0",{requires:["json","dataschema-base"]});YUI.add("dataschema-xml",function(C){var B=C.Lang,A={apply:function(F,G){var D=G,E={results:[],meta:{}};if(D&&D.nodeType&&(D.nodeType===9||D.nodeType===1||D.nodeType===11)&&F){E=A._parseResults(F,D,E);E=A._parseMeta(F.metaFields,D,E);}else{E.error=new Error("XML schema parse failure");}return E;},_getLocationValue:function(K,H){var F=K.locator||K.key||K,E=H.ownerDocument||H,D,G,I=null;try{if(!B.isUndefined(E.evaluate)){D=E.evaluate(F,H,E.createNSResolver(!H.ownerDocument?H.documentElement:H.ownerDocument.documentElement),0,null);while(G=D.iterateNext()){I=G.textContent;}}else{E.setProperty("SelectionLanguage","XPath");D=H.selectNodes(F)[0];I=D.value||D.text||null;}return C.DataSchema.Base.parse(I,K);}catch(J){}},_parseMeta:function(H,G,F){if(B.isObject(H)){var E,D=G.ownerDocument||G;for(E in H){if(H.hasOwnProperty(E)){F.meta[E]=A._getLocationValue(H[E],D);}}}return F;},_parseResults:function(F,K,G){if(F.resultListLocator&&B.isArray(F.resultFields)){var E=K.getElementsByTagName(F.resultListLocator),L=F.resultFields,J=[],D,M,N,I,H;if(E.length){for(I=E.length-1;I>=0;I--){N={};D=E[I];for(H=L.length-1;H>=0;H--){M=L[H];N[M.key||M]=A._getLocationValue(M,D);}J[I]=N;}G.results=J;}else{G.error=new Error("XML schema result nodes retrieval failure");}}return G;}};C.DataSchema.XML=C.mix(A,C.DataSchema.Base);},"3.0.0",{requires:["dataschema-base"]});YUI.add("dataschema-array",function(C){var A=C.Lang,B={apply:function(F,G){var D=G,E={results:[],meta:{}};if(A.isArray(D)){if(A.isArray(F.resultFields)){E=B._parseResults(F.resultFields,D,E);}else{E.results=D;}}else{E.error=new Error("Array schema parse failure");}return E;},_parseResults:function(H,K,D){var G=[],O,N,I,J,M,L,F,E;for(F=K.length-1;F>-1;F--){O={};N=K[F];I=(A.isObject(N)&&!A.isFunction(N))?2:(A.isArray(N))?1:(A.isString(N))?0:-1;if(I>0){for(E=H.length-1;E>-1;E--){J=H[E];M=(!A.isUndefined(J.key))?J.key:J;L=(!A.isUndefined(N[M]))?N[M]:N[E];O[M]=C.DataSchema.Base.parse(L,J);}}else{if(I===0){O=N;}else{O=null;}}G[F]=O;}D.results=G;return D;}};C.DataSchema.Array=C.mix(B,C.DataSchema.Base);},"3.0.0",{requires:["dataschema-base"]});YUI.add("dataschema-text",function(C){var B=C.Lang,A={apply:function(F,G){var D=G,E={results:[],meta:{}};if(B.isString(D)&&B.isString(F.resultDelimiter)){E=A._parseResults(F,D,E);}else{E.error=new Error("Text schema parse failure");}return E;},_parseResults:function(D,K,E){var I=D.resultDelimiter,H=[],L,P,S,R,J,N,Q,O,G,F,M=K.length-I.length;if(K.substr(M)==I){K=K.substr(0,M);}L=K.split(D.resultDelimiter);for(G=L.length-1;G>-1;G--){S={};R=L[G];if(B.isString(D.fieldDelimiter)){P=R.split(D.fieldDelimiter);if(B.isArray(D.resultFields)){J=D.resultFields;for(F=J.length-1;F>-1;F--){N=J[F];Q=(!B.isUndefined(N.key))?N.key:N;O=(!B.isUndefined(P[Q]))?P[Q]:P[F];S[Q]=C.DataSchema.Base.parse(O,N);}}}else{S=R;}H[G]=S;}E.results=H;return E;}};C.DataSchema.Text=C.mix(A,C.DataSchema.Base);},"3.0.0",{requires:["dataschema-base"]});YUI.add("dataschema",function(A){},"3.0.0",{use:["dataschema-base","dataschema-json","dataschema-xml","dataschema-array","dataschema-text"]}); \ No newline at end of file diff --git a/include/javascript/yui3/build/dataschema/dataschema-text-min.js b/include/javascript/yui3/build/dataschema/dataschema-text-min.js new file mode 100644 index 00000000..996f31a4 --- /dev/null +++ b/include/javascript/yui3/build/dataschema/dataschema-text-min.js @@ -0,0 +1,8 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add("dataschema-text",function(C){var B=C.Lang,A={apply:function(F,G){var D=G,E={results:[],meta:{}};if(B.isString(D)&&B.isString(F.resultDelimiter)){E=A._parseResults(F,D,E);}else{E.error=new Error("Text schema parse failure");}return E;},_parseResults:function(D,K,E){var I=D.resultDelimiter,H=[],L,P,S,R,J,N,Q,O,G,F,M=K.length-I.length;if(K.substr(M)==I){K=K.substr(0,M);}L=K.split(D.resultDelimiter);for(G=L.length-1;G>-1;G--){S={};R=L[G];if(B.isString(D.fieldDelimiter)){P=R.split(D.fieldDelimiter);if(B.isArray(D.resultFields)){J=D.resultFields;for(F=J.length-1;F>-1;F--){N=J[F];Q=(!B.isUndefined(N.key))?N.key:N;O=(!B.isUndefined(P[Q]))?P[Q]:P[F];S[Q]=C.DataSchema.Base.parse(O,N);}}}else{S=R;}H[G]=S;}E.results=H;return E;}};C.DataSchema.Text=C.mix(A,C.DataSchema.Base);},"3.0.0",{requires:["dataschema-base"]}); \ No newline at end of file diff --git a/include/javascript/yui3/build/dataschema/dataschema-text.js b/include/javascript/yui3/build/dataschema/dataschema-text.js new file mode 100644 index 00000000..5f5f988e --- /dev/null +++ b/include/javascript/yui3/build/dataschema/dataschema-text.js @@ -0,0 +1,14 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add('dataschema-text',function(Y){var LANG=Y.Lang,SchemaText={apply:function(schema,data){var data_in=data,data_out={results:[],meta:{}};if(LANG.isString(data_in)&&LANG.isString(schema.resultDelimiter)){data_out=SchemaText._parseResults(schema,data_in,data_out);} +else{data_out.error=new Error("Text schema parse failure");} +return data_out;},_parseResults:function(schema,text_in,data_out){var resultDelim=schema.resultDelimiter,results=[],results_in,fields_in,result,item,fields,field,key,value,i,j,tmpLength=text_in.length-resultDelim.length;if(text_in.substr(tmpLength)==resultDelim){text_in=text_in.substr(0,tmpLength);} +results_in=text_in.split(schema.resultDelimiter);for(i=results_in.length-1;i>-1;i--){result={};item=results_in[i];if(LANG.isString(schema.fieldDelimiter)){fields_in=item.split(schema.fieldDelimiter);if(LANG.isArray(schema.resultFields)){fields=schema.resultFields;for(j=fields.length-1;j>-1;j--){field=fields[j];key=(!LANG.isUndefined(field.key))?field.key:field;value=(!LANG.isUndefined(fields_in[key]))?fields_in[key]:fields_in[j];result[key]=Y.DataSchema.Base.parse(value,field);}}} +else{result=item;} +results[i]=result;} +data_out.results=results;return data_out;}};Y.DataSchema.Text=Y.mix(SchemaText,Y.DataSchema.Base);},'3.0.0',{requires:['dataschema-base']}); \ No newline at end of file diff --git a/include/javascript/yui3/build/dataschema/dataschema-xml-min.js b/include/javascript/yui3/build/dataschema/dataschema-xml-min.js new file mode 100644 index 00000000..148774d7 --- /dev/null +++ b/include/javascript/yui3/build/dataschema/dataschema-xml-min.js @@ -0,0 +1,8 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add("dataschema-xml",function(C){var B=C.Lang,A={apply:function(F,G){var D=G,E={results:[],meta:{}};if(D&&D.nodeType&&(D.nodeType===9||D.nodeType===1||D.nodeType===11)&&F){E=A._parseResults(F,D,E);E=A._parseMeta(F.metaFields,D,E);}else{E.error=new Error("XML schema parse failure");}return E;},_getLocationValue:function(K,H){var F=K.locator||K.key||K,E=H.ownerDocument||H,D,G,I=null;try{if(!B.isUndefined(E.evaluate)){D=E.evaluate(F,H,E.createNSResolver(!H.ownerDocument?H.documentElement:H.ownerDocument.documentElement),0,null);while(G=D.iterateNext()){I=G.textContent;}}else{E.setProperty("SelectionLanguage","XPath");D=H.selectNodes(F)[0];I=D.value||D.text||null;}return C.DataSchema.Base.parse(I,K);}catch(J){}},_parseMeta:function(H,G,F){if(B.isObject(H)){var E,D=G.ownerDocument||G;for(E in H){if(H.hasOwnProperty(E)){F.meta[E]=A._getLocationValue(H[E],D);}}}return F;},_parseResults:function(F,K,G){if(F.resultListLocator&&B.isArray(F.resultFields)){var E=K.getElementsByTagName(F.resultListLocator),L=F.resultFields,J=[],D,M,N,I,H;if(E.length){for(I=E.length-1;I>=0;I--){N={};D=E[I];for(H=L.length-1;H>=0;H--){M=L[H];N[M.key||M]=A._getLocationValue(M,D);}J[I]=N;}G.results=J;}else{G.error=new Error("XML schema result nodes retrieval failure");}}return G;}};C.DataSchema.XML=C.mix(A,C.DataSchema.Base);},"3.0.0",{requires:["dataschema-base"]}); \ No newline at end of file diff --git a/include/javascript/yui3/build/dataschema/dataschema-xml.js b/include/javascript/yui3/build/dataschema/dataschema-xml.js new file mode 100644 index 00000000..1e934e67 --- /dev/null +++ b/include/javascript/yui3/build/dataschema/dataschema-xml.js @@ -0,0 +1,18 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add('dataschema-xml',function(Y){var LANG=Y.Lang,SchemaXML={apply:function(schema,data){var xmldoc=data,data_out={results:[],meta:{}};if(xmldoc&&xmldoc.nodeType&&(xmldoc.nodeType===9||xmldoc.nodeType===1||xmldoc.nodeType===11)&&schema){data_out=SchemaXML._parseResults(schema,xmldoc,data_out);data_out=SchemaXML._parseMeta(schema.metaFields,xmldoc,data_out);} +else{data_out.error=new Error("XML schema parse failure");} +return data_out;},_getLocationValue:function(field,context){var locator=field.locator||field.key||field,xmldoc=context.ownerDocument||context,result,res,value=null;try{if(!LANG.isUndefined(xmldoc.evaluate)){result=xmldoc.evaluate(locator,context,xmldoc.createNSResolver(!context.ownerDocument?context.documentElement:context.ownerDocument.documentElement),0,null);while(res=result.iterateNext()){value=res.textContent;}} +else{xmldoc.setProperty("SelectionLanguage","XPath");result=context.selectNodes(locator)[0];value=result.value||result.text||null;} +return Y.DataSchema.Base.parse(value,field);} +catch(e){}},_parseMeta:function(metaFields,xmldoc_in,data_out){if(LANG.isObject(metaFields)){var key,xmldoc=xmldoc_in.ownerDocument||xmldoc_in;for(key in metaFields){if(metaFields.hasOwnProperty(key)){data_out.meta[key]=SchemaXML._getLocationValue(metaFields[key],xmldoc);}}} +return data_out;},_parseResults:function(schema,xmldoc_in,data_out){if(schema.resultListLocator&&LANG.isArray(schema.resultFields)){var nodeList=xmldoc_in.getElementsByTagName(schema.resultListLocator),fields=schema.resultFields,results=[],node,field,result,i,j;if(nodeList.length){for(i=nodeList.length-1;i>=0;i--){result={};node=nodeList[i];for(j=fields.length-1;j>=0;j--){field=fields[j];result[field.key||field]=SchemaXML._getLocationValue(field,node);} +results[i]=result;} +data_out.results=results;} +else{data_out.error=new Error("XML schema result nodes retrieval failure");}} +return data_out;}};Y.DataSchema.XML=Y.mix(SchemaXML,Y.DataSchema.Base);},'3.0.0',{requires:['dataschema-base']}); \ No newline at end of file diff --git a/include/javascript/yui3/build/dataschema/dataschema.js b/include/javascript/yui3/build/dataschema/dataschema.js new file mode 100644 index 00000000..01b2ed18 --- /dev/null +++ b/include/javascript/yui3/build/dataschema/dataschema.js @@ -0,0 +1,55 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add('dataschema-base',function(Y){var LANG=Y.Lang,SchemaBase={apply:function(schema,data){return data;},parse:function(value,field){if(field.parser){var parser=(LANG.isFunction(field.parser))?field.parser:Y.Parsers[field.parser+''];if(parser){value=parser.call(this,value);} +else{}} +return value;}};Y.namespace("DataSchema").Base=SchemaBase;Y.namespace("Parsers");},'3.0.0',{requires:['base']});YUI.add('dataschema-json',function(Y){var LANG=Y.Lang,SchemaJSON={getPath:function(locator){var path=null,keys=[],i=0;if(locator){locator=locator.replace(/\[(['"])(.*?)\1\]/g,function(x,$1,$2){keys[i]=$2;return'.@'+(i++);}).replace(/\[(\d+)\]/g,function(x,$1){keys[i]=parseInt($1,10)|0;return'.@'+(i++);}).replace(/^\./,'');if(!/[^\w\.\$@]/.test(locator)){path=locator.split('.');for(i=path.length-1;i>=0;--i){if(path[i].charAt(0)==='@'){path[i]=keys[parseInt(path[i].substr(1),10)];}}} +else{}} +return path;},getLocationValue:function(path,data){var i=0,len=path.length;for(;i=0;--i){record={};result=array_in[i];if(result){for(j=simplePaths.length-1;j>=0;--j){record[simplePaths[j].key]=Y.DataSchema.Base.parse((LANG.isUndefined(result[simplePaths[j].path])?result[j]:result[simplePaths[j].path]),simplePaths[j]);} +for(j=complexPaths.length-1;j>=0;--j){record[complexPaths[j].key]=Y.DataSchema.Base.parse((SchemaJSON.getLocationValue(complexPaths[j].path,result)),complexPaths[j]);} +for(j=fieldParsers.length-1;j>=0;--j){key=fieldParsers[j].key;record[key]=fieldParsers[j].parser(record[key]);if(LANG.isUndefined(record[key])){record[key]=null;}} +results[i]=record;}} +data_out.results=results;return data_out;},_parseMeta:function(metaFields,json_in,data_out){if(LANG.isObject(metaFields)){var key,path;for(key in metaFields){if(metaFields.hasOwnProperty(key)){path=SchemaJSON.getPath(metaFields[key]);if(path&&json_in){data_out.meta[key]=SchemaJSON.getLocationValue(path,json_in);}}}} +else{data_out.error=new Error("JSON meta data retrieval failure");} +return data_out;}};Y.DataSchema.JSON=Y.mix(SchemaJSON,Y.DataSchema.Base);},'3.0.0',{requires:['json','dataschema-base']});YUI.add('dataschema-xml',function(Y){var LANG=Y.Lang,SchemaXML={apply:function(schema,data){var xmldoc=data,data_out={results:[],meta:{}};if(xmldoc&&xmldoc.nodeType&&(xmldoc.nodeType===9||xmldoc.nodeType===1||xmldoc.nodeType===11)&&schema){data_out=SchemaXML._parseResults(schema,xmldoc,data_out);data_out=SchemaXML._parseMeta(schema.metaFields,xmldoc,data_out);} +else{data_out.error=new Error("XML schema parse failure");} +return data_out;},_getLocationValue:function(field,context){var locator=field.locator||field.key||field,xmldoc=context.ownerDocument||context,result,res,value=null;try{if(!LANG.isUndefined(xmldoc.evaluate)){result=xmldoc.evaluate(locator,context,xmldoc.createNSResolver(!context.ownerDocument?context.documentElement:context.ownerDocument.documentElement),0,null);while(res=result.iterateNext()){value=res.textContent;}} +else{xmldoc.setProperty("SelectionLanguage","XPath");result=context.selectNodes(locator)[0];value=result.value||result.text||null;} +return Y.DataSchema.Base.parse(value,field);} +catch(e){}},_parseMeta:function(metaFields,xmldoc_in,data_out){if(LANG.isObject(metaFields)){var key,xmldoc=xmldoc_in.ownerDocument||xmldoc_in;for(key in metaFields){if(metaFields.hasOwnProperty(key)){data_out.meta[key]=SchemaXML._getLocationValue(metaFields[key],xmldoc);}}} +return data_out;},_parseResults:function(schema,xmldoc_in,data_out){if(schema.resultListLocator&&LANG.isArray(schema.resultFields)){var nodeList=xmldoc_in.getElementsByTagName(schema.resultListLocator),fields=schema.resultFields,results=[],node,field,result,i,j;if(nodeList.length){for(i=nodeList.length-1;i>=0;i--){result={};node=nodeList[i];for(j=fields.length-1;j>=0;j--){field=fields[j];result[field.key||field]=SchemaXML._getLocationValue(field,node);} +results[i]=result;} +data_out.results=results;} +else{data_out.error=new Error("XML schema result nodes retrieval failure");}} +return data_out;}};Y.DataSchema.XML=Y.mix(SchemaXML,Y.DataSchema.Base);},'3.0.0',{requires:['dataschema-base']});YUI.add('dataschema-array',function(Y){var LANG=Y.Lang,SchemaArray={apply:function(schema,data){var data_in=data,data_out={results:[],meta:{}};if(LANG.isArray(data_in)){if(LANG.isArray(schema.resultFields)){data_out=SchemaArray._parseResults(schema.resultFields,data_in,data_out);} +else{data_out.results=data_in;}} +else{data_out.error=new Error("Array schema parse failure");} +return data_out;},_parseResults:function(fields,array_in,data_out){var results=[],result,item,type,field,key,value,i,j;for(i=array_in.length-1;i>-1;i--){result={};item=array_in[i];type=(LANG.isObject(item)&&!LANG.isFunction(item))?2:(LANG.isArray(item))?1:(LANG.isString(item))?0:-1;if(type>0){for(j=fields.length-1;j>-1;j--){field=fields[j];key=(!LANG.isUndefined(field.key))?field.key:field;value=(!LANG.isUndefined(item[key]))?item[key]:item[j];result[key]=Y.DataSchema.Base.parse(value,field);}} +else if(type===0){result=item;} +else{result=null;} +results[i]=result;} +data_out.results=results;return data_out;}};Y.DataSchema.Array=Y.mix(SchemaArray,Y.DataSchema.Base);},'3.0.0',{requires:['dataschema-base']});YUI.add('dataschema-text',function(Y){var LANG=Y.Lang,SchemaText={apply:function(schema,data){var data_in=data,data_out={results:[],meta:{}};if(LANG.isString(data_in)&&LANG.isString(schema.resultDelimiter)){data_out=SchemaText._parseResults(schema,data_in,data_out);} +else{data_out.error=new Error("Text schema parse failure");} +return data_out;},_parseResults:function(schema,text_in,data_out){var resultDelim=schema.resultDelimiter,results=[],results_in,fields_in,result,item,fields,field,key,value,i,j,tmpLength=text_in.length-resultDelim.length;if(text_in.substr(tmpLength)==resultDelim){text_in=text_in.substr(0,tmpLength);} +results_in=text_in.split(schema.resultDelimiter);for(i=results_in.length-1;i>-1;i--){result={};item=results_in[i];if(LANG.isString(schema.fieldDelimiter)){fields_in=item.split(schema.fieldDelimiter);if(LANG.isArray(schema.resultFields)){fields=schema.resultFields;for(j=fields.length-1;j>-1;j--){field=fields[j];key=(!LANG.isUndefined(field.key))?field.key:field;value=(!LANG.isUndefined(fields_in[key]))?fields_in[key]:fields_in[j];result[key]=Y.DataSchema.Base.parse(value,field);}}} +else{result=item;} +results[i]=result;} +data_out.results=results;return data_out;}};Y.DataSchema.Text=Y.mix(SchemaText,Y.DataSchema.Base);},'3.0.0',{requires:['dataschema-base']});YUI.add('dataschema',function(Y){},'3.0.0',{use:['dataschema-base','dataschema-json','dataschema-xml','dataschema-array','dataschema-text']}); \ No newline at end of file diff --git a/include/javascript/yui3/build/datasource/datasource-arrayschema-min.js b/include/javascript/yui3/build/datasource/datasource-arrayschema-min.js new file mode 100644 index 00000000..98d767bf --- /dev/null +++ b/include/javascript/yui3/build/datasource/datasource-arrayschema-min.js @@ -0,0 +1,8 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add("datasource-arrayschema",function(B){var A=function(){A.superclass.constructor.apply(this,arguments);};B.mix(A,{NS:"schema",NAME:"dataSourceArraySchema",ATTRS:{schema:{}}});B.extend(A,B.Plugin.Base,{initializer:function(C){this.doBefore("_defDataFn",this._beforeDefDataFn);},_beforeDefDataFn:function(E){var D=(B.DataSource.IO&&(this.get("host")instanceof B.DataSource.IO)&&B.Lang.isString(E.data.responseText))?E.data.responseText:E.data,C=B.DataSchema.Array.apply(this.get("schema"),D);if(!C){C={meta:{},results:D};}this.get("host").fire("response",B.mix({response:C},E));return new B.Do.Halt("DataSourceArraySchema plugin halted _defDataFn");}});B.namespace("Plugin").DataSourceArraySchema=A;},"3.0.0",{requires:["plugin","datasource-local","dataschema-array"]}); \ No newline at end of file diff --git a/include/javascript/yui3/build/datasource/datasource-arrayschema.js b/include/javascript/yui3/build/datasource/datasource-arrayschema.js new file mode 100644 index 00000000..b26d5ed2 --- /dev/null +++ b/include/javascript/yui3/build/datasource/datasource-arrayschema.js @@ -0,0 +1,9 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add('datasource-arrayschema',function(Y){var DataSourceArraySchema=function(){DataSourceArraySchema.superclass.constructor.apply(this,arguments);};Y.mix(DataSourceArraySchema,{NS:"schema",NAME:"dataSourceArraySchema",ATTRS:{schema:{}}});Y.extend(DataSourceArraySchema,Y.Plugin.Base,{initializer:function(config){this.doBefore("_defDataFn",this._beforeDefDataFn);},_beforeDefDataFn:function(e){var data=(Y.DataSource.IO&&(this.get("host")instanceof Y.DataSource.IO)&&Y.Lang.isString(e.data.responseText))?e.data.responseText:e.data,response=Y.DataSchema.Array.apply(this.get("schema"),data);if(!response){response={meta:{},results:data};} +this.get("host").fire("response",Y.mix({response:response},e));return new Y.Do.Halt("DataSourceArraySchema plugin halted _defDataFn");}});Y.namespace('Plugin').DataSourceArraySchema=DataSourceArraySchema;},'3.0.0',{requires:['plugin','datasource-local','dataschema-array']}); \ No newline at end of file diff --git a/include/javascript/yui3/build/datasource/datasource-cache-min.js b/include/javascript/yui3/build/datasource/datasource-cache-min.js new file mode 100644 index 00000000..9ed44f1f --- /dev/null +++ b/include/javascript/yui3/build/datasource/datasource-cache-min.js @@ -0,0 +1,8 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add("datasource-cache",function(B){var A=function(){A.superclass.constructor.apply(this,arguments);};B.mix(A,{NS:"cache",NAME:"dataSourceCache",ATTRS:{}});B.extend(A,B.Cache,{initializer:function(C){this.doBefore("_defRequestFn",this._beforeDefRequestFn);this.doBefore("_defResponseFn",this._beforeDefResponseFn);},_beforeDefRequestFn:function(D){var C=(this.retrieve(D.request))||null;if(C&&C.response){this.get("host").fire("response",B.mix({response:C.response},D));return new B.Do.Halt("DataSourceCache plugin halted _defRequestFn");}},_beforeDefResponseFn:function(C){if(C.response&&!C.response.cached){C.response.cached=true;this.add(C.request,C.response,(C.callback&&C.callback.argument));}}});B.namespace("Plugin").DataSourceCache=A;},"3.0.0",{requires:["datasource-local","cache"]}); \ No newline at end of file diff --git a/include/javascript/yui3/build/datasource/datasource-cache.js b/include/javascript/yui3/build/datasource/datasource-cache.js new file mode 100644 index 00000000..b9c25f73 --- /dev/null +++ b/include/javascript/yui3/build/datasource/datasource-cache.js @@ -0,0 +1,8 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add('datasource-cache',function(Y){var DataSourceCache=function(){DataSourceCache.superclass.constructor.apply(this,arguments);};Y.mix(DataSourceCache,{NS:"cache",NAME:"dataSourceCache",ATTRS:{}});Y.extend(DataSourceCache,Y.Cache,{initializer:function(config){this.doBefore("_defRequestFn",this._beforeDefRequestFn);this.doBefore("_defResponseFn",this._beforeDefResponseFn);},_beforeDefRequestFn:function(e){var entry=(this.retrieve(e.request))||null;if(entry&&entry.response){this.get("host").fire("response",Y.mix({response:entry.response},e));return new Y.Do.Halt("DataSourceCache plugin halted _defRequestFn");}},_beforeDefResponseFn:function(e){if(e.response&&!e.response.cached){e.response.cached=true;this.add(e.request,e.response,(e.callback&&e.callback.argument));}}});Y.namespace('Plugin').DataSourceCache=DataSourceCache;},'3.0.0',{requires:['datasource-local','cache']}); \ No newline at end of file diff --git a/include/javascript/yui3/build/datasource/datasource-function-min.js b/include/javascript/yui3/build/datasource/datasource-function-min.js new file mode 100644 index 00000000..8146e353 --- /dev/null +++ b/include/javascript/yui3/build/datasource/datasource-function-min.js @@ -0,0 +1,8 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add("datasource-function",function(B){var A=B.Lang,C=function(){C.superclass.constructor.apply(this,arguments);};B.mix(C,{NAME:"dataSourceFunction",ATTRS:{source:{validator:A.isFunction}}});B.extend(C,B.DataSource.Local,{_defRequestFn:function(G){var F=this.get("source"),D;if(F){try{D=F(G.request,this,G);this.fire("data",B.mix({data:D},G));}catch(E){G.error=E;this.fire("error",G);}}else{G.error=new Error("Function data failure");this.fire("error",G);}return G.tId;}});B.DataSource.Function=C;},"3.0.0",{requires:["datasource-local"]}); \ No newline at end of file diff --git a/include/javascript/yui3/build/datasource/datasource-function.js b/include/javascript/yui3/build/datasource/datasource-function.js new file mode 100644 index 00000000..d3b10188 --- /dev/null +++ b/include/javascript/yui3/build/datasource/datasource-function.js @@ -0,0 +1,11 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add('datasource-function',function(Y){var LANG=Y.Lang,DSFn=function(){DSFn.superclass.constructor.apply(this,arguments);};Y.mix(DSFn,{NAME:"dataSourceFunction",ATTRS:{source:{validator:LANG.isFunction}}});Y.extend(DSFn,Y.DataSource.Local,{_defRequestFn:function(e){var fn=this.get("source"),response;if(fn){try{response=fn(e.request,this,e);this.fire("data",Y.mix({data:response},e));} +catch(error){e.error=error;this.fire("error",e);}} +else{e.error=new Error("Function data failure");this.fire("error",e);} +return e.tId;}});Y.DataSource.Function=DSFn;},'3.0.0',{requires:['datasource-local']}); \ No newline at end of file diff --git a/include/javascript/yui3/build/datasource/datasource-get-min.js b/include/javascript/yui3/build/datasource/datasource-get-min.js new file mode 100644 index 00000000..4dceb912 --- /dev/null +++ b/include/javascript/yui3/build/datasource/datasource-get-min.js @@ -0,0 +1,8 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add("datasource-get",function(B){var A=function(){A.superclass.constructor.apply(this,arguments);};B.mix(A,{NAME:"dataSourceGet",ATTRS:{get:{value:B.Get,cloneDefaultValue:false},asyncMode:{value:"allowAll"},scriptCallbackParam:{value:"callback"},generateRequestCallback:{value:function(C,D){return"&"+C.get("scriptCallbackParam")+"=YUI.Env.DataSource.callbacks["+D+"]";}}},callbacks:[],_tId:0});B.extend(A,B.DataSource.Local,{_defRequestFn:function(F){var E=this.get("source"),D=this.get("get"),G=A._tId++,C=this;YUI.Env.DataSource.callbacks[G]=B.rbind(function(H){if((C.get("asyncMode")!=="ignoreStaleResponses")||(G===A.callbacks.length-1)){C.fire("data",B.mix({data:H},F));}else{}delete A.callbacks[G];},this,G);E+=F.request+this.get("generateRequestCallback")(this,G);D.script(E,{autopurge:true,onFailure:B.bind(function(H){H.error=new Error("Script node data failure");this.fire("error",H);},this,F)});return F.tId;}});B.DataSource.Get=A;YUI.namespace("Env.DataSource.callbacks");},"3.0.0",{requires:["datasource-local","get"]}); \ No newline at end of file diff --git a/include/javascript/yui3/build/datasource/datasource-get.js b/include/javascript/yui3/build/datasource/datasource-get.js new file mode 100644 index 00000000..66010900 --- /dev/null +++ b/include/javascript/yui3/build/datasource/datasource-get.js @@ -0,0 +1,10 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add('datasource-get',function(Y){var DSGet=function(){DSGet.superclass.constructor.apply(this,arguments);};Y.mix(DSGet,{NAME:"dataSourceGet",ATTRS:{get:{value:Y.Get,cloneDefaultValue:false},asyncMode:{value:"allowAll"},scriptCallbackParam:{value:"callback"},generateRequestCallback:{value:function(self,id){return"&"+self.get("scriptCallbackParam")+"=YUI.Env.DataSource.callbacks["+id+"]";}}},callbacks:[],_tId:0});Y.extend(DSGet,Y.DataSource.Local,{_defRequestFn:function(e){var uri=this.get("source"),get=this.get("get"),id=DSGet._tId++,self=this;YUI.Env.DataSource.callbacks[id]=Y.rbind(function(response){if((self.get("asyncMode")!=="ignoreStaleResponses")||(id===DSGet.callbacks.length-1)){self.fire("data",Y.mix({data:response},e));} +else{} +delete DSGet.callbacks[id];},this,id);uri+=e.request+this.get("generateRequestCallback")(this,id);get.script(uri,{autopurge:true,onFailure:Y.bind(function(e){e.error=new Error("Script node data failure");this.fire("error",e);},this,e)});return e.tId;}});Y.DataSource.Get=DSGet;YUI.namespace("Env.DataSource.callbacks");},'3.0.0',{requires:['datasource-local','get']}); \ No newline at end of file diff --git a/include/javascript/yui3/build/datasource/datasource-io-min.js b/include/javascript/yui3/build/datasource/datasource-io-min.js new file mode 100644 index 00000000..da5145f6 --- /dev/null +++ b/include/javascript/yui3/build/datasource/datasource-io-min.js @@ -0,0 +1,8 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add("datasource-io",function(B){var A=function(){A.superclass.constructor.apply(this,arguments);};B.mix(A,{NAME:"dataSourceIO",ATTRS:{io:{value:B.io,cloneDefaultValue:false}}});B.extend(A,B.DataSource.Local,{initializer:function(C){this._queue={interval:null,conn:null,requests:[]};},_queue:null,_defRequestFn:function(F){var E=this.get("source"),G=this.get("io"),D=F.request,C=B.mix(F.cfg,{on:{success:function(J,H,I){this.fire("data",B.mix({data:H},I));},failure:function(J,H,I){I.error=new Error("IO data failure");this.fire("error",B.mix({data:H},I));this.fire("data",B.mix({data:H},I));}},context:this,arguments:F});if(B.Lang.isString(D)){if(C.method&&(C.method.toUpperCase()==="POST")){C.data=C.data?C.data+D:D;}else{E+=D;}}G(E,C);return F.tId;}});B.DataSource.IO=A;},"3.0.0",{requires:["datasource-local","io"]}); \ No newline at end of file diff --git a/include/javascript/yui3/build/datasource/datasource-io.js b/include/javascript/yui3/build/datasource/datasource-io.js new file mode 100644 index 00000000..4719a506 --- /dev/null +++ b/include/javascript/yui3/build/datasource/datasource-io.js @@ -0,0 +1,10 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add('datasource-io',function(Y){var DSIO=function(){DSIO.superclass.constructor.apply(this,arguments);};Y.mix(DSIO,{NAME:"dataSourceIO",ATTRS:{io:{value:Y.io,cloneDefaultValue:false}}});Y.extend(DSIO,Y.DataSource.Local,{initializer:function(config){this._queue={interval:null,conn:null,requests:[]};},_queue:null,_defRequestFn:function(e){var uri=this.get("source"),io=this.get("io"),request=e.request,cfg=Y.mix(e.cfg,{on:{success:function(id,response,e){this.fire("data",Y.mix({data:response},e));},failure:function(id,response,e){e.error=new Error("IO data failure");this.fire("error",Y.mix({data:response},e));this.fire("data",Y.mix({data:response},e));}},context:this,arguments:e});if(Y.Lang.isString(request)){if(cfg.method&&(cfg.method.toUpperCase()==="POST")){cfg.data=cfg.data?cfg.data+request:request;} +else{uri+=request;}} +io(uri,cfg);return e.tId;}});Y.DataSource.IO=DSIO;},'3.0.0',{requires:['datasource-local','io']}); \ No newline at end of file diff --git a/include/javascript/yui3/build/datasource/datasource-jsonschema-min.js b/include/javascript/yui3/build/datasource/datasource-jsonschema-min.js new file mode 100644 index 00000000..98cfdf8d --- /dev/null +++ b/include/javascript/yui3/build/datasource/datasource-jsonschema-min.js @@ -0,0 +1,8 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add("datasource-jsonschema",function(B){var A=function(){A.superclass.constructor.apply(this,arguments);};B.mix(A,{NS:"schema",NAME:"dataSourceJSONSchema",ATTRS:{schema:{}}});B.extend(A,B.Plugin.Base,{initializer:function(C){this.doBefore("_defDataFn",this._beforeDefDataFn);},_beforeDefDataFn:function(E){var D=(B.DataSource.IO&&(this.get("host")instanceof B.DataSource.IO)&&B.Lang.isString(E.data.responseText))?E.data.responseText:E.data,C=B.DataSchema.JSON.apply(this.get("schema"),D);if(!C){C={meta:{},results:D};}this.get("host").fire("response",B.mix({response:C},E));return new B.Do.Halt("DataSourceJSONSchema plugin halted _defDataFn");}});B.namespace("Plugin").DataSourceJSONSchema=A;},"3.0.0",{requires:["plugin","datasource-local","dataschema-json"]}); \ No newline at end of file diff --git a/include/javascript/yui3/build/datasource/datasource-jsonschema.js b/include/javascript/yui3/build/datasource/datasource-jsonschema.js new file mode 100644 index 00000000..086d1b24 --- /dev/null +++ b/include/javascript/yui3/build/datasource/datasource-jsonschema.js @@ -0,0 +1,9 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add('datasource-jsonschema',function(Y){var DataSourceJSONSchema=function(){DataSourceJSONSchema.superclass.constructor.apply(this,arguments);};Y.mix(DataSourceJSONSchema,{NS:"schema",NAME:"dataSourceJSONSchema",ATTRS:{schema:{}}});Y.extend(DataSourceJSONSchema,Y.Plugin.Base,{initializer:function(config){this.doBefore("_defDataFn",this._beforeDefDataFn);},_beforeDefDataFn:function(e){var data=(Y.DataSource.IO&&(this.get("host")instanceof Y.DataSource.IO)&&Y.Lang.isString(e.data.responseText))?e.data.responseText:e.data,response=Y.DataSchema.JSON.apply(this.get("schema"),data);if(!response){response={meta:{},results:data};} +this.get("host").fire("response",Y.mix({response:response},e));return new Y.Do.Halt("DataSourceJSONSchema plugin halted _defDataFn");}});Y.namespace('Plugin').DataSourceJSONSchema=DataSourceJSONSchema;},'3.0.0',{requires:['plugin','datasource-local','dataschema-json']}); \ No newline at end of file diff --git a/include/javascript/yui3/build/datasource/datasource-local-min.js b/include/javascript/yui3/build/datasource/datasource-local-min.js new file mode 100644 index 00000000..e467f986 --- /dev/null +++ b/include/javascript/yui3/build/datasource/datasource-local-min.js @@ -0,0 +1,8 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add("datasource-local",function(C){var B=C.Lang,A=function(){A.superclass.constructor.apply(this,arguments);};C.mix(A,{NAME:"dataSourceLocal",ATTRS:{source:{value:null}},_tId:0,issueCallback:function(E){if(E.callback){var D=(E.error&&E.callback.failure)||E.callback.success;if(D){D(E);}}}});C.extend(A,C.Base,{initializer:function(D){this._initEvents();},_initEvents:function(){this.publish("request",{defaultFn:C.bind("_defRequestFn",this),queuable:true});this.publish("data",{defaultFn:C.bind("_defDataFn",this),queuable:true});this.publish("response",{defaultFn:C.bind("_defResponseFn",this),queuable:true});},_defRequestFn:function(E){var D=this.get("source");if(B.isUndefined(D)){E.error=new Error("Local source undefined");}if(E.error){this.fire("error",E);}this.fire("data",C.mix({data:D},E));},_defDataFn:function(G){var E=G.data,F=G.meta,D={results:(B.isArray(E))?E:[E],meta:(F)?F:{}};this.fire("response",C.mix({response:D},G));},_defResponseFn:function(D){A.issueCallback(D);},sendRequest:function(E,G,D){var F=A._tId++;this.fire("request",{tId:F,request:E,callback:G,cfg:D||{}});return F;}});C.namespace("DataSource").Local=A;},"3.0.0",{requires:["base"]}); \ No newline at end of file diff --git a/include/javascript/yui3/build/datasource/datasource-local.js b/include/javascript/yui3/build/datasource/datasource-local.js new file mode 100644 index 00000000..0d8cd8b8 --- /dev/null +++ b/include/javascript/yui3/build/datasource/datasource-local.js @@ -0,0 +1,10 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add('datasource-local',function(Y){var LANG=Y.Lang,DSLocal=function(){DSLocal.superclass.constructor.apply(this,arguments);};Y.mix(DSLocal,{NAME:"dataSourceLocal",ATTRS:{source:{value:null}},_tId:0,issueCallback:function(e){if(e.callback){var callbackFunc=(e.error&&e.callback.failure)||e.callback.success;if(callbackFunc){callbackFunc(e);}}}});Y.extend(DSLocal,Y.Base,{initializer:function(config){this._initEvents();},_initEvents:function(){this.publish("request",{defaultFn:Y.bind("_defRequestFn",this),queuable:true});this.publish("data",{defaultFn:Y.bind("_defDataFn",this),queuable:true});this.publish("response",{defaultFn:Y.bind("_defResponseFn",this),queuable:true});},_defRequestFn:function(e){var data=this.get("source");if(LANG.isUndefined(data)){e.error=new Error("Local source undefined");} +if(e.error){this.fire("error",e);} +this.fire("data",Y.mix({data:data},e));},_defDataFn:function(e){var data=e.data,meta=e.meta,response={results:(LANG.isArray(data))?data:[data],meta:(meta)?meta:{}};this.fire("response",Y.mix({response:response},e));},_defResponseFn:function(e){DSLocal.issueCallback(e);},sendRequest:function(request,callback,cfg){var tId=DSLocal._tId++;this.fire("request",{tId:tId,request:request,callback:callback,cfg:cfg||{}});return tId;}});Y.namespace("DataSource").Local=DSLocal;},'3.0.0',{requires:['base']}); \ No newline at end of file diff --git a/include/javascript/yui3/build/datasource/datasource-min.js b/include/javascript/yui3/build/datasource/datasource-min.js new file mode 100644 index 00000000..2f3e76fe --- /dev/null +++ b/include/javascript/yui3/build/datasource/datasource-min.js @@ -0,0 +1,8 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add("datasource-local",function(C){var B=C.Lang,A=function(){A.superclass.constructor.apply(this,arguments);};C.mix(A,{NAME:"dataSourceLocal",ATTRS:{source:{value:null}},_tId:0,issueCallback:function(E){if(E.callback){var D=(E.error&&E.callback.failure)||E.callback.success;if(D){D(E);}}}});C.extend(A,C.Base,{initializer:function(D){this._initEvents();},_initEvents:function(){this.publish("request",{defaultFn:C.bind("_defRequestFn",this),queuable:true});this.publish("data",{defaultFn:C.bind("_defDataFn",this),queuable:true});this.publish("response",{defaultFn:C.bind("_defResponseFn",this),queuable:true});},_defRequestFn:function(E){var D=this.get("source");if(B.isUndefined(D)){E.error=new Error("Local source undefined");}if(E.error){this.fire("error",E);}this.fire("data",C.mix({data:D},E));},_defDataFn:function(G){var E=G.data,F=G.meta,D={results:(B.isArray(E))?E:[E],meta:(F)?F:{}};this.fire("response",C.mix({response:D},G));},_defResponseFn:function(D){A.issueCallback(D);},sendRequest:function(E,G,D){var F=A._tId++;this.fire("request",{tId:F,request:E,callback:G,cfg:D||{}});return F;}});C.namespace("DataSource").Local=A;},"3.0.0",{requires:["base"]});YUI.add("datasource-io",function(B){var A=function(){A.superclass.constructor.apply(this,arguments);};B.mix(A,{NAME:"dataSourceIO",ATTRS:{io:{value:B.io,cloneDefaultValue:false}}});B.extend(A,B.DataSource.Local,{initializer:function(C){this._queue={interval:null,conn:null,requests:[]};},_queue:null,_defRequestFn:function(F){var E=this.get("source"),G=this.get("io"),D=F.request,C=B.mix(F.cfg,{on:{success:function(J,H,I){this.fire("data",B.mix({data:H},I));},failure:function(J,H,I){I.error=new Error("IO data failure");this.fire("error",B.mix({data:H},I));this.fire("data",B.mix({data:H},I));}},context:this,arguments:F});if(B.Lang.isString(D)){if(C.method&&(C.method.toUpperCase()==="POST")){C.data=C.data?C.data+D:D;}else{E+=D;}}G(E,C);return F.tId;}});B.DataSource.IO=A;},"3.0.0",{requires:["datasource-local","io"]});YUI.add("datasource-get",function(B){var A=function(){A.superclass.constructor.apply(this,arguments);};B.mix(A,{NAME:"dataSourceGet",ATTRS:{get:{value:B.Get,cloneDefaultValue:false},asyncMode:{value:"allowAll"},scriptCallbackParam:{value:"callback"},generateRequestCallback:{value:function(C,D){return"&"+C.get("scriptCallbackParam")+"=YUI.Env.DataSource.callbacks["+D+"]";}}},callbacks:[],_tId:0});B.extend(A,B.DataSource.Local,{_defRequestFn:function(F){var E=this.get("source"),D=this.get("get"),G=A._tId++,C=this;YUI.Env.DataSource.callbacks[G]=B.rbind(function(H){if((C.get("asyncMode")!=="ignoreStaleResponses")||(G===A.callbacks.length-1)){C.fire("data",B.mix({data:H},F));}else{}delete A.callbacks[G];},this,G);E+=F.request+this.get("generateRequestCallback")(this,G);D.script(E,{autopurge:true,onFailure:B.bind(function(H){H.error=new Error("Script node data failure");this.fire("error",H);},this,F)});return F.tId;}});B.DataSource.Get=A;YUI.namespace("Env.DataSource.callbacks");},"3.0.0",{requires:["datasource-local","get"]});YUI.add("datasource-function",function(B){var A=B.Lang,C=function(){C.superclass.constructor.apply(this,arguments);};B.mix(C,{NAME:"dataSourceFunction",ATTRS:{source:{validator:A.isFunction}}});B.extend(C,B.DataSource.Local,{_defRequestFn:function(G){var F=this.get("source"),D;if(F){try{D=F(G.request,this,G);this.fire("data",B.mix({data:D},G));}catch(E){G.error=E;this.fire("error",G);}}else{G.error=new Error("Function data failure");this.fire("error",G);}return G.tId;}});B.DataSource.Function=C;},"3.0.0",{requires:["datasource-local"]});YUI.add("datasource-cache",function(B){var A=function(){A.superclass.constructor.apply(this,arguments);};B.mix(A,{NS:"cache",NAME:"dataSourceCache",ATTRS:{}});B.extend(A,B.Cache,{initializer:function(C){this.doBefore("_defRequestFn",this._beforeDefRequestFn);this.doBefore("_defResponseFn",this._beforeDefResponseFn);},_beforeDefRequestFn:function(D){var C=(this.retrieve(D.request))||null;if(C&&C.response){this.get("host").fire("response",B.mix({response:C.response},D));return new B.Do.Halt("DataSourceCache plugin halted _defRequestFn");}},_beforeDefResponseFn:function(C){if(C.response&&!C.response.cached){C.response.cached=true;this.add(C.request,C.response,(C.callback&&C.callback.argument));}}});B.namespace("Plugin").DataSourceCache=A;},"3.0.0",{requires:["datasource-local","cache"]});YUI.add("datasource-jsonschema",function(B){var A=function(){A.superclass.constructor.apply(this,arguments);};B.mix(A,{NS:"schema",NAME:"dataSourceJSONSchema",ATTRS:{schema:{}}});B.extend(A,B.Plugin.Base,{initializer:function(C){this.doBefore("_defDataFn",this._beforeDefDataFn);},_beforeDefDataFn:function(E){var D=(B.DataSource.IO&&(this.get("host")instanceof B.DataSource.IO)&&B.Lang.isString(E.data.responseText))?E.data.responseText:E.data,C=B.DataSchema.JSON.apply(this.get("schema"),D);if(!C){C={meta:{},results:D};}this.get("host").fire("response",B.mix({response:C},E));return new B.Do.Halt("DataSourceJSONSchema plugin halted _defDataFn");}});B.namespace("Plugin").DataSourceJSONSchema=A;},"3.0.0",{requires:["plugin","datasource-local","dataschema-json"]});YUI.add("datasource-xmlschema",function(B){var A=function(){A.superclass.constructor.apply(this,arguments);};B.mix(A,{NS:"schema",NAME:"dataSourceXMLSchema",ATTRS:{schema:{}}});B.extend(A,B.Plugin.Base,{initializer:function(C){this.doBefore("_defDataFn",this._beforeDefDataFn);},_beforeDefDataFn:function(E){var D=(B.DataSource.IO&&(this.get("host")instanceof B.DataSource.IO)&&E.data.responseXML&&(E.data.responseXML.nodeType===9))?E.data.responseXML:E.data,C=B.DataSchema.XML.apply(this.get("schema"),D);if(!C){C={meta:{},results:D};}this.get("host").fire("response",B.mix({response:C},E));return new B.Do.Halt("DataSourceXMLSchema plugin halted _defDataFn");}});B.namespace("Plugin").DataSourceXMLSchema=A;},"3.0.0",{requires:["plugin","datasource-local","dataschema-xml"]});YUI.add("datasource-arrayschema",function(B){var A=function(){A.superclass.constructor.apply(this,arguments);};B.mix(A,{NS:"schema",NAME:"dataSourceArraySchema",ATTRS:{schema:{}}});B.extend(A,B.Plugin.Base,{initializer:function(C){this.doBefore("_defDataFn",this._beforeDefDataFn);},_beforeDefDataFn:function(E){var D=(B.DataSource.IO&&(this.get("host")instanceof B.DataSource.IO)&&B.Lang.isString(E.data.responseText))?E.data.responseText:E.data,C=B.DataSchema.Array.apply(this.get("schema"),D);if(!C){C={meta:{},results:D};}this.get("host").fire("response",B.mix({response:C},E));return new B.Do.Halt("DataSourceArraySchema plugin halted _defDataFn");}});B.namespace("Plugin").DataSourceArraySchema=A;},"3.0.0",{requires:["plugin","datasource-local","dataschema-array"]});YUI.add("datasource-textschema",function(B){var A=function(){A.superclass.constructor.apply(this,arguments);};B.mix(A,{NS:"schema",NAME:"dataSourceTextSchema",ATTRS:{schema:{}}});B.extend(A,B.Plugin.Base,{initializer:function(C){this.doBefore("_defDataFn",this._beforeDefDataFn);},_beforeDefDataFn:function(E){var D=(B.DataSource.IO&&(this.get("host")instanceof B.DataSource.IO)&&B.Lang.isString(E.data.responseText))?E.data.responseText:E.data,C=B.DataSchema.Text.apply(this.get("schema"),D);if(!C){C={meta:{},results:D};}this.get("host").fire("response",B.mix({response:C},E));return new B.Do.Halt("DataSourceTextSchema plugin halted _defDataFn");}});B.namespace("Plugin").DataSourceTextSchema=A;},"3.0.0",{requires:["plugin","datasource-local","dataschema-text"]});YUI.add("datasource-polling",function(C){var A=C.Lang,B=function(){this._intervals={};};B.prototype={_intervals:null,setInterval:function(F,E,G){var D=C.later(F,this,this.sendRequest,[E,G],true);this._intervals[D.id]=D;return D.id;},clearInterval:function(E,D){E=D||E;if(this._intervals[E]){this._intervals[E].cancel();delete this._intervals[E];}},clearAllIntervals:function(){C.each(this._intervals,this.clearInterval,this);}};C.augment(C.DataSource.Local,B);},"3.0.0",{requires:["datasource-local"]});YUI.add("datasource",function(A){},"3.0.0",{use:["datasource-local","datasource-io","datasource-get","datasource-function","datasource-cache","datasource-jsonschema","datasource-xmlschema","datasource-arrayschema","datasource-textschema","datasource-polling"]}); \ No newline at end of file diff --git a/include/javascript/yui3/build/datasource/datasource-polling-min.js b/include/javascript/yui3/build/datasource/datasource-polling-min.js new file mode 100644 index 00000000..803ecc46 --- /dev/null +++ b/include/javascript/yui3/build/datasource/datasource-polling-min.js @@ -0,0 +1,8 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add("datasource-polling",function(C){var A=C.Lang,B=function(){this._intervals={};};B.prototype={_intervals:null,setInterval:function(F,E,G){var D=C.later(F,this,this.sendRequest,[E,G],true);this._intervals[D.id]=D;return D.id;},clearInterval:function(E,D){E=D||E;if(this._intervals[E]){this._intervals[E].cancel();delete this._intervals[E];}},clearAllIntervals:function(){C.each(this._intervals,this.clearInterval,this);}};C.augment(C.DataSource.Local,B);},"3.0.0",{requires:["datasource-local"]}); \ No newline at end of file diff --git a/include/javascript/yui3/build/datasource/datasource-polling.js b/include/javascript/yui3/build/datasource/datasource-polling.js new file mode 100644 index 00000000..5f677ff5 --- /dev/null +++ b/include/javascript/yui3/build/datasource/datasource-polling.js @@ -0,0 +1,8 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add('datasource-polling',function(Y){var LANG=Y.Lang,Pollable=function(){this._intervals={};};Pollable.prototype={_intervals:null,setInterval:function(msec,request,callback){var x=Y.later(msec,this,this.sendRequest,[request,callback],true);this._intervals[x.id]=x;return x.id;},clearInterval:function(id,key){id=key||id;if(this._intervals[id]){this._intervals[id].cancel();delete this._intervals[id];}},clearAllIntervals:function(){Y.each(this._intervals,this.clearInterval,this);}};Y.augment(Y.DataSource.Local,Pollable);},'3.0.0',{requires:['datasource-local']}); \ No newline at end of file diff --git a/include/javascript/yui3/build/datasource/datasource-textschema-min.js b/include/javascript/yui3/build/datasource/datasource-textschema-min.js new file mode 100644 index 00000000..fce68694 --- /dev/null +++ b/include/javascript/yui3/build/datasource/datasource-textschema-min.js @@ -0,0 +1,8 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add("datasource-textschema",function(B){var A=function(){A.superclass.constructor.apply(this,arguments);};B.mix(A,{NS:"schema",NAME:"dataSourceTextSchema",ATTRS:{schema:{}}});B.extend(A,B.Plugin.Base,{initializer:function(C){this.doBefore("_defDataFn",this._beforeDefDataFn);},_beforeDefDataFn:function(E){var D=(B.DataSource.IO&&(this.get("host")instanceof B.DataSource.IO)&&B.Lang.isString(E.data.responseText))?E.data.responseText:E.data,C=B.DataSchema.Text.apply(this.get("schema"),D);if(!C){C={meta:{},results:D};}this.get("host").fire("response",B.mix({response:C},E));return new B.Do.Halt("DataSourceTextSchema plugin halted _defDataFn");}});B.namespace("Plugin").DataSourceTextSchema=A;},"3.0.0",{requires:["plugin","datasource-local","dataschema-text"]}); \ No newline at end of file diff --git a/include/javascript/yui3/build/datasource/datasource-textschema.js b/include/javascript/yui3/build/datasource/datasource-textschema.js new file mode 100644 index 00000000..cf4ab692 --- /dev/null +++ b/include/javascript/yui3/build/datasource/datasource-textschema.js @@ -0,0 +1,9 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add('datasource-textschema',function(Y){var DataSourceTextSchema=function(){DataSourceTextSchema.superclass.constructor.apply(this,arguments);};Y.mix(DataSourceTextSchema,{NS:"schema",NAME:"dataSourceTextSchema",ATTRS:{schema:{}}});Y.extend(DataSourceTextSchema,Y.Plugin.Base,{initializer:function(config){this.doBefore("_defDataFn",this._beforeDefDataFn);},_beforeDefDataFn:function(e){var data=(Y.DataSource.IO&&(this.get("host")instanceof Y.DataSource.IO)&&Y.Lang.isString(e.data.responseText))?e.data.responseText:e.data,response=Y.DataSchema.Text.apply(this.get("schema"),data);if(!response){response={meta:{},results:data};} +this.get("host").fire("response",Y.mix({response:response},e));return new Y.Do.Halt("DataSourceTextSchema plugin halted _defDataFn");}});Y.namespace('Plugin').DataSourceTextSchema=DataSourceTextSchema;},'3.0.0',{requires:['plugin','datasource-local','dataschema-text']}); \ No newline at end of file diff --git a/include/javascript/yui3/build/datasource/datasource-xmlschema-min.js b/include/javascript/yui3/build/datasource/datasource-xmlschema-min.js new file mode 100644 index 00000000..06d0bf87 --- /dev/null +++ b/include/javascript/yui3/build/datasource/datasource-xmlschema-min.js @@ -0,0 +1,8 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add("datasource-xmlschema",function(B){var A=function(){A.superclass.constructor.apply(this,arguments);};B.mix(A,{NS:"schema",NAME:"dataSourceXMLSchema",ATTRS:{schema:{}}});B.extend(A,B.Plugin.Base,{initializer:function(C){this.doBefore("_defDataFn",this._beforeDefDataFn);},_beforeDefDataFn:function(E){var D=(B.DataSource.IO&&(this.get("host")instanceof B.DataSource.IO)&&E.data.responseXML&&(E.data.responseXML.nodeType===9))?E.data.responseXML:E.data,C=B.DataSchema.XML.apply(this.get("schema"),D);if(!C){C={meta:{},results:D};}this.get("host").fire("response",B.mix({response:C},E));return new B.Do.Halt("DataSourceXMLSchema plugin halted _defDataFn");}});B.namespace("Plugin").DataSourceXMLSchema=A;},"3.0.0",{requires:["plugin","datasource-local","dataschema-xml"]}); \ No newline at end of file diff --git a/include/javascript/yui3/build/datasource/datasource-xmlschema.js b/include/javascript/yui3/build/datasource/datasource-xmlschema.js new file mode 100644 index 00000000..fcfee48a --- /dev/null +++ b/include/javascript/yui3/build/datasource/datasource-xmlschema.js @@ -0,0 +1,9 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add('datasource-xmlschema',function(Y){var DataSourceXMLSchema=function(){DataSourceXMLSchema.superclass.constructor.apply(this,arguments);};Y.mix(DataSourceXMLSchema,{NS:"schema",NAME:"dataSourceXMLSchema",ATTRS:{schema:{}}});Y.extend(DataSourceXMLSchema,Y.Plugin.Base,{initializer:function(config){this.doBefore("_defDataFn",this._beforeDefDataFn);},_beforeDefDataFn:function(e){var data=(Y.DataSource.IO&&(this.get("host")instanceof Y.DataSource.IO)&&e.data.responseXML&&(e.data.responseXML.nodeType===9))?e.data.responseXML:e.data,response=Y.DataSchema.XML.apply(this.get("schema"),data);if(!response){response={meta:{},results:data};} +this.get("host").fire("response",Y.mix({response:response},e));return new Y.Do.Halt("DataSourceXMLSchema plugin halted _defDataFn");}});Y.namespace('Plugin').DataSourceXMLSchema=DataSourceXMLSchema;},'3.0.0',{requires:['plugin','datasource-local','dataschema-xml']}); \ No newline at end of file diff --git a/include/javascript/yui3/build/datasource/datasource.js b/include/javascript/yui3/build/datasource/datasource.js new file mode 100644 index 00000000..b998d664 --- /dev/null +++ b/include/javascript/yui3/build/datasource/datasource.js @@ -0,0 +1,21 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add('datasource-local',function(Y){var LANG=Y.Lang,DSLocal=function(){DSLocal.superclass.constructor.apply(this,arguments);};Y.mix(DSLocal,{NAME:"dataSourceLocal",ATTRS:{source:{value:null}},_tId:0,issueCallback:function(e){if(e.callback){var callbackFunc=(e.error&&e.callback.failure)||e.callback.success;if(callbackFunc){callbackFunc(e);}}}});Y.extend(DSLocal,Y.Base,{initializer:function(config){this._initEvents();},_initEvents:function(){this.publish("request",{defaultFn:Y.bind("_defRequestFn",this),queuable:true});this.publish("data",{defaultFn:Y.bind("_defDataFn",this),queuable:true});this.publish("response",{defaultFn:Y.bind("_defResponseFn",this),queuable:true});},_defRequestFn:function(e){var data=this.get("source");if(LANG.isUndefined(data)){e.error=new Error("Local source undefined");} +if(e.error){this.fire("error",e);} +this.fire("data",Y.mix({data:data},e));},_defDataFn:function(e){var data=e.data,meta=e.meta,response={results:(LANG.isArray(data))?data:[data],meta:(meta)?meta:{}};this.fire("response",Y.mix({response:response},e));},_defResponseFn:function(e){DSLocal.issueCallback(e);},sendRequest:function(request,callback,cfg){var tId=DSLocal._tId++;this.fire("request",{tId:tId,request:request,callback:callback,cfg:cfg||{}});return tId;}});Y.namespace("DataSource").Local=DSLocal;},'3.0.0',{requires:['base']});YUI.add('datasource-io',function(Y){var DSIO=function(){DSIO.superclass.constructor.apply(this,arguments);};Y.mix(DSIO,{NAME:"dataSourceIO",ATTRS:{io:{value:Y.io,cloneDefaultValue:false}}});Y.extend(DSIO,Y.DataSource.Local,{initializer:function(config){this._queue={interval:null,conn:null,requests:[]};},_queue:null,_defRequestFn:function(e){var uri=this.get("source"),io=this.get("io"),request=e.request,cfg=Y.mix(e.cfg,{on:{success:function(id,response,e){this.fire("data",Y.mix({data:response},e));},failure:function(id,response,e){e.error=new Error("IO data failure");this.fire("error",Y.mix({data:response},e));this.fire("data",Y.mix({data:response},e));}},context:this,arguments:e});if(Y.Lang.isString(request)){if(cfg.method&&(cfg.method.toUpperCase()==="POST")){cfg.data=cfg.data?cfg.data+request:request;} +else{uri+=request;}} +io(uri,cfg);return e.tId;}});Y.DataSource.IO=DSIO;},'3.0.0',{requires:['datasource-local','io']});YUI.add('datasource-get',function(Y){var DSGet=function(){DSGet.superclass.constructor.apply(this,arguments);};Y.mix(DSGet,{NAME:"dataSourceGet",ATTRS:{get:{value:Y.Get,cloneDefaultValue:false},asyncMode:{value:"allowAll"},scriptCallbackParam:{value:"callback"},generateRequestCallback:{value:function(self,id){return"&"+self.get("scriptCallbackParam")+"=YUI.Env.DataSource.callbacks["+id+"]";}}},callbacks:[],_tId:0});Y.extend(DSGet,Y.DataSource.Local,{_defRequestFn:function(e){var uri=this.get("source"),get=this.get("get"),id=DSGet._tId++,self=this;YUI.Env.DataSource.callbacks[id]=Y.rbind(function(response){if((self.get("asyncMode")!=="ignoreStaleResponses")||(id===DSGet.callbacks.length-1)){self.fire("data",Y.mix({data:response},e));} +else{} +delete DSGet.callbacks[id];},this,id);uri+=e.request+this.get("generateRequestCallback")(this,id);get.script(uri,{autopurge:true,onFailure:Y.bind(function(e){e.error=new Error("Script node data failure");this.fire("error",e);},this,e)});return e.tId;}});Y.DataSource.Get=DSGet;YUI.namespace("Env.DataSource.callbacks");},'3.0.0',{requires:['datasource-local','get']});YUI.add('datasource-function',function(Y){var LANG=Y.Lang,DSFn=function(){DSFn.superclass.constructor.apply(this,arguments);};Y.mix(DSFn,{NAME:"dataSourceFunction",ATTRS:{source:{validator:LANG.isFunction}}});Y.extend(DSFn,Y.DataSource.Local,{_defRequestFn:function(e){var fn=this.get("source"),response;if(fn){try{response=fn(e.request,this,e);this.fire("data",Y.mix({data:response},e));} +catch(error){e.error=error;this.fire("error",e);}} +else{e.error=new Error("Function data failure");this.fire("error",e);} +return e.tId;}});Y.DataSource.Function=DSFn;},'3.0.0',{requires:['datasource-local']});YUI.add('datasource-cache',function(Y){var DataSourceCache=function(){DataSourceCache.superclass.constructor.apply(this,arguments);};Y.mix(DataSourceCache,{NS:"cache",NAME:"dataSourceCache",ATTRS:{}});Y.extend(DataSourceCache,Y.Cache,{initializer:function(config){this.doBefore("_defRequestFn",this._beforeDefRequestFn);this.doBefore("_defResponseFn",this._beforeDefResponseFn);},_beforeDefRequestFn:function(e){var entry=(this.retrieve(e.request))||null;if(entry&&entry.response){this.get("host").fire("response",Y.mix({response:entry.response},e));return new Y.Do.Halt("DataSourceCache plugin halted _defRequestFn");}},_beforeDefResponseFn:function(e){if(e.response&&!e.response.cached){e.response.cached=true;this.add(e.request,e.response,(e.callback&&e.callback.argument));}}});Y.namespace('Plugin').DataSourceCache=DataSourceCache;},'3.0.0',{requires:['datasource-local','cache']});YUI.add('datasource-jsonschema',function(Y){var DataSourceJSONSchema=function(){DataSourceJSONSchema.superclass.constructor.apply(this,arguments);};Y.mix(DataSourceJSONSchema,{NS:"schema",NAME:"dataSourceJSONSchema",ATTRS:{schema:{}}});Y.extend(DataSourceJSONSchema,Y.Plugin.Base,{initializer:function(config){this.doBefore("_defDataFn",this._beforeDefDataFn);},_beforeDefDataFn:function(e){var data=(Y.DataSource.IO&&(this.get("host")instanceof Y.DataSource.IO)&&Y.Lang.isString(e.data.responseText))?e.data.responseText:e.data,response=Y.DataSchema.JSON.apply(this.get("schema"),data);if(!response){response={meta:{},results:data};} +this.get("host").fire("response",Y.mix({response:response},e));return new Y.Do.Halt("DataSourceJSONSchema plugin halted _defDataFn");}});Y.namespace('Plugin').DataSourceJSONSchema=DataSourceJSONSchema;},'3.0.0',{requires:['plugin','datasource-local','dataschema-json']});YUI.add('datasource-xmlschema',function(Y){var DataSourceXMLSchema=function(){DataSourceXMLSchema.superclass.constructor.apply(this,arguments);};Y.mix(DataSourceXMLSchema,{NS:"schema",NAME:"dataSourceXMLSchema",ATTRS:{schema:{}}});Y.extend(DataSourceXMLSchema,Y.Plugin.Base,{initializer:function(config){this.doBefore("_defDataFn",this._beforeDefDataFn);},_beforeDefDataFn:function(e){var data=(Y.DataSource.IO&&(this.get("host")instanceof Y.DataSource.IO)&&e.data.responseXML&&(e.data.responseXML.nodeType===9))?e.data.responseXML:e.data,response=Y.DataSchema.XML.apply(this.get("schema"),data);if(!response){response={meta:{},results:data};} +this.get("host").fire("response",Y.mix({response:response},e));return new Y.Do.Halt("DataSourceXMLSchema plugin halted _defDataFn");}});Y.namespace('Plugin').DataSourceXMLSchema=DataSourceXMLSchema;},'3.0.0',{requires:['plugin','datasource-local','dataschema-xml']});YUI.add('datasource-arrayschema',function(Y){var DataSourceArraySchema=function(){DataSourceArraySchema.superclass.constructor.apply(this,arguments);};Y.mix(DataSourceArraySchema,{NS:"schema",NAME:"dataSourceArraySchema",ATTRS:{schema:{}}});Y.extend(DataSourceArraySchema,Y.Plugin.Base,{initializer:function(config){this.doBefore("_defDataFn",this._beforeDefDataFn);},_beforeDefDataFn:function(e){var data=(Y.DataSource.IO&&(this.get("host")instanceof Y.DataSource.IO)&&Y.Lang.isString(e.data.responseText))?e.data.responseText:e.data,response=Y.DataSchema.Array.apply(this.get("schema"),data);if(!response){response={meta:{},results:data};} +this.get("host").fire("response",Y.mix({response:response},e));return new Y.Do.Halt("DataSourceArraySchema plugin halted _defDataFn");}});Y.namespace('Plugin').DataSourceArraySchema=DataSourceArraySchema;},'3.0.0',{requires:['plugin','datasource-local','dataschema-array']});YUI.add('datasource-textschema',function(Y){var DataSourceTextSchema=function(){DataSourceTextSchema.superclass.constructor.apply(this,arguments);};Y.mix(DataSourceTextSchema,{NS:"schema",NAME:"dataSourceTextSchema",ATTRS:{schema:{}}});Y.extend(DataSourceTextSchema,Y.Plugin.Base,{initializer:function(config){this.doBefore("_defDataFn",this._beforeDefDataFn);},_beforeDefDataFn:function(e){var data=(Y.DataSource.IO&&(this.get("host")instanceof Y.DataSource.IO)&&Y.Lang.isString(e.data.responseText))?e.data.responseText:e.data,response=Y.DataSchema.Text.apply(this.get("schema"),data);if(!response){response={meta:{},results:data};} +this.get("host").fire("response",Y.mix({response:response},e));return new Y.Do.Halt("DataSourceTextSchema plugin halted _defDataFn");}});Y.namespace('Plugin').DataSourceTextSchema=DataSourceTextSchema;},'3.0.0',{requires:['plugin','datasource-local','dataschema-text']});YUI.add('datasource-polling',function(Y){var LANG=Y.Lang,Pollable=function(){this._intervals={};};Pollable.prototype={_intervals:null,setInterval:function(msec,request,callback){var x=Y.later(msec,this,this.sendRequest,[request,callback],true);this._intervals[x.id]=x;return x.id;},clearInterval:function(id,key){id=key||id;if(this._intervals[id]){this._intervals[id].cancel();delete this._intervals[id];}},clearAllIntervals:function(){Y.each(this._intervals,this.clearInterval,this);}};Y.augment(Y.DataSource.Local,Pollable);},'3.0.0',{requires:['datasource-local']});YUI.add('datasource',function(Y){},'3.0.0',{use:['datasource-local','datasource-io','datasource-get','datasource-function','datasource-cache','datasource-jsonschema','datasource-xmlschema','datasource-arrayschema','datasource-textschema','datasource-polling']}); \ No newline at end of file diff --git a/include/javascript/yui3/build/datatype/datatype-date-format-min.js b/include/javascript/yui3/build/datatype/datatype-date-format-min.js new file mode 100644 index 00000000..9812b506 --- /dev/null +++ b/include/javascript/yui3/build/datatype/datatype-date-format-min.js @@ -0,0 +1,8 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add("datatype-date-format",function(D){var A=function(E,G,F){if(typeof F==="undefined"){F=10;}G=G.toString();for(;parseInt(E,10)1;F/=10){E=G+E;}return E.toString();};D.config.dateFormat=D.config.dateFormat||"%Y-%m-%d";D.config.locale=D.config.locale||"en";var C={formats:{a:function(F,E){return E.a[F.getDay()];},A:function(F,E){return E.A[F.getDay()];},b:function(F,E){return E.b[F.getMonth()];},B:function(F,E){return E.B[F.getMonth()];},C:function(E){return A(parseInt(E.getFullYear()/100,10),0);},d:["getDate","0"],e:["getDate"," "],g:function(E){return A(parseInt(C.formats.G(E)%100,10),0);},G:function(G){var H=G.getFullYear();var F=parseInt(C.formats.V(G),10);var E=parseInt(C.formats.W(G),10);if(E>F){H++;}else{if(E===0&&F>=52){H--;}}return H;},H:["getHours","0"],I:function(F){var E=F.getHours()%12;return A(E===0?12:E,0);},j:function(I){var H=new Date(""+I.getFullYear()+"/1/1 GMT");var F=new Date(""+I.getFullYear()+"/"+(I.getMonth()+1)+"/"+I.getDate()+" GMT");var E=F-H;var G=parseInt(E/60000/60/24,10)+1;return A(G,0,100);},k:["getHours"," "],l:function(F){var E=F.getHours()%12;return A(E===0?12:E," ");},m:function(E){return A(E.getMonth()+1,0);},M:["getMinutes","0"],p:function(F,E){return E.p[F.getHours()>=12?1:0];},P:function(F,E){return E.P[F.getHours()>=12?1:0];},s:function(F,E){return parseInt(F.getTime()/1000,10);},S:["getSeconds","0"],u:function(E){var F=E.getDay();return F===0?7:F;},U:function(H){var E=parseInt(C.formats.j(H),10);var G=6-H.getDay();var F=parseInt((E+G)/7,10);return A(F,0);},V:function(H){var G=parseInt(C.formats.W(H),10);var E=(new Date(""+H.getFullYear()+"/1/1")).getDay();var F=G+(E>4||E<=1?0:1);if(F===53&&(new Date(""+H.getFullYear()+"/12/31")).getDay()<4){F=1;}else{if(F===0){F=C.formats.V(new Date(""+(H.getFullYear()-1)+"/12/31"));}}return A(F,0);},w:"getDay",W:function(H){var E=parseInt(C.formats.j(H),10);var G=7-C.formats.u(H);var F=parseInt((E+G)/7,10);return A(F,0,10);},y:function(E){return A(E.getFullYear()%100,0);},Y:"getFullYear",z:function(G){var F=G.getTimezoneOffset();var E=A(parseInt(Math.abs(F/60),10),0);var I=A(Math.abs(F%60),0);return(F>0?"-":"+")+E+I;},Z:function(E){var F=E.toString().replace(/^.*:\d\d( GMT[+-]\d+)? \(?([A-Za-z ]+)\)?\d*$/,"$2").replace(/[a-z ]/g,"");if(F.length>4){F=C.formats.z(E);}return F;},"%":function(E){return"%";}},aggregates:{c:"locale",D:"%m/%d/%y",F:"%Y-%m-%d",h:"%b",n:"\n",r:"locale",R:"%H:%M",t:"\t",T:"%H:%M:%S",x:"locale",X:"locale"},format:function(N,H){H=H||{};if(!D.Lang.isDate(N)){return D.Lang.isValue(N)?N:"";}var M=H.format||D.config.dateFormat,F=H.locale||D.config.locale,L=D.DataType.Date.Locale;F=F.replace(/_/g,"-");if(!L[F]){var G=F.replace(/-[a-zA-Z]+$/,"");if(G in L){F=G;}else{if(D.config.locale in L){F=D.config.locale;}else{F="en";}}}var J=L[F];var I=function(P,O){var Q=C.aggregates[O];return(Q==="locale"?J[O]:Q);};var E=function(P,O){var Q=C.formats[O];switch(D.Lang.type(Q)){case"string":return N[Q]();case"function":return Q.call(N,N,J);case"array":if(D.Lang.type(Q[0])==="string"){return A(N[Q[0]](),Q[1]);}default:return O;}};while(M.match(/%[cDFhnrRtTxX]/)){M=M.replace(/%([cDFhnrRtTxX])/g,I);}var K=M.replace(/%([aAbBCdegGHIjklmMpPsSuUVwWyYzZ%])/g,E);I=E=undefined;return K;}};D.mix(D.namespace("DataType.Date"),C);var B={a:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],A:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],b:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],B:["January","February","March","April","May","June","July","August","September","October","November","December"],c:"%a %d %b %Y %T %Z",p:["AM","PM"],P:["am","pm"],r:"%I:%M:%S %p",x:"%d/%m/%y",X:"%T"};D.namespace("DataType.Date.Locale");D.DataType.Date.Locale["en"]=B;D.DataType.Date.Locale["en-US"]=D.merge(B,{c:"%a %d %b %Y %I:%M:%S %p %Z",x:"%m/%d/%Y",X:"%I:%M:%S %p"});D.DataType.Date.Locale["en-GB"]=D.merge(B,{r:"%l:%M:%S %P %Z"});D.DataType.Date.Locale["en-AU"]=D.merge(B);},"3.0.0"); \ No newline at end of file diff --git a/include/javascript/yui3/build/datatype/datatype-date-format.js b/include/javascript/yui3/build/datatype/datatype-date-format.js new file mode 100644 index 00000000..83eeddc9 --- /dev/null +++ b/include/javascript/yui3/build/datatype/datatype-date-format.js @@ -0,0 +1,22 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add('datatype-date-format',function(Y){var xPad=function(x,pad,r) +{if(typeof r==="undefined") +{r=10;} +pad=pad.toString();for(;parseInt(x,10)1;r/=10){x=pad+x;} +return x.toString();};Y.config.dateFormat=Y.config.dateFormat||"%Y-%m-%d";Y.config.locale=Y.config.locale||"en";var Dt={formats:{a:function(d,l){return l.a[d.getDay()];},A:function(d,l){return l.A[d.getDay()];},b:function(d,l){return l.b[d.getMonth()];},B:function(d,l){return l.B[d.getMonth()];},C:function(d){return xPad(parseInt(d.getFullYear()/100,10),0);},d:["getDate","0"],e:["getDate"," "],g:function(d){return xPad(parseInt(Dt.formats.G(d)%100,10),0);},G:function(d){var y=d.getFullYear();var V=parseInt(Dt.formats.V(d),10);var W=parseInt(Dt.formats.W(d),10);if(W>V){y++;}else if(W===0&&V>=52){y--;} +return y;},H:["getHours","0"],I:function(d){var I=d.getHours()%12;return xPad(I===0?12:I,0);},j:function(d){var gmd_1=new Date(""+d.getFullYear()+"/1/1 GMT");var gmdate=new Date(""+d.getFullYear()+"/"+(d.getMonth()+1)+"/"+d.getDate()+" GMT");var ms=gmdate-gmd_1;var doy=parseInt(ms/60000/60/24,10)+1;return xPad(doy,0,100);},k:["getHours"," "],l:function(d){var I=d.getHours()%12;return xPad(I===0?12:I," ");},m:function(d){return xPad(d.getMonth()+1,0);},M:["getMinutes","0"],p:function(d,l){return l.p[d.getHours()>=12?1:0];},P:function(d,l){return l.P[d.getHours()>=12?1:0];},s:function(d,l){return parseInt(d.getTime()/1000,10);},S:["getSeconds","0"],u:function(d){var dow=d.getDay();return dow===0?7:dow;},U:function(d){var doy=parseInt(Dt.formats.j(d),10);var rdow=6-d.getDay();var woy=parseInt((doy+rdow)/7,10);return xPad(woy,0);},V:function(d){var woy=parseInt(Dt.formats.W(d),10);var dow1_1=(new Date(""+d.getFullYear()+"/1/1")).getDay();var idow=woy+(dow1_1>4||dow1_1<=1?0:1);if(idow===53&&(new Date(""+d.getFullYear()+"/12/31")).getDay()<4) +{idow=1;} +else if(idow===0) +{idow=Dt.formats.V(new Date(""+(d.getFullYear()-1)+"/12/31"));} +return xPad(idow,0);},w:"getDay",W:function(d){var doy=parseInt(Dt.formats.j(d),10);var rdow=7-Dt.formats.u(d);var woy=parseInt((doy+rdow)/7,10);return xPad(woy,0,10);},y:function(d){return xPad(d.getFullYear()%100,0);},Y:"getFullYear",z:function(d){var o=d.getTimezoneOffset();var H=xPad(parseInt(Math.abs(o/60),10),0);var M=xPad(Math.abs(o%60),0);return(o>0?"-":"+")+H+M;},Z:function(d){var tz=d.toString().replace(/^.*:\d\d( GMT[+-]\d+)? \(?([A-Za-z ]+)\)?\d*$/,"$2").replace(/[a-z ]/g,"");if(tz.length>4){tz=Dt.formats.z(d);} +return tz;},"%":function(d){return"%";}},aggregates:{c:"locale",D:"%m/%d/%y",F:"%Y-%m-%d",h:"%b",n:"\n",r:"locale",R:"%H:%M",t:"\t",T:"%H:%M:%S",x:"locale",X:"locale"},format:function(oDate,oConfig){oConfig=oConfig||{};if(!Y.Lang.isDate(oDate)){return Y.Lang.isValue(oDate)?oDate:"";} +var format=oConfig.format||Y.config.dateFormat,sLocale=oConfig.locale||Y.config.locale,LOCALE=Y.DataType.Date.Locale;sLocale=sLocale.replace(/_/g,"-");if(!LOCALE[sLocale]){var tmpLocale=sLocale.replace(/-[a-zA-Z]+$/,"");if(tmpLocale in LOCALE){sLocale=tmpLocale;}else if(Y.config.locale in LOCALE){sLocale=Y.config.locale;}else{sLocale="en";}} +var aLocale=LOCALE[sLocale];var replace_aggs=function(m0,m1){var f=Dt.aggregates[m1];return(f==="locale"?aLocale[m1]:f);};var replace_formats=function(m0,m1){var f=Dt.formats[m1];switch(Y.Lang.type(f)){case"string":return oDate[f]();case"function":return f.call(oDate,oDate,aLocale);case"array":if(Y.Lang.type(f[0])==="string"){return xPad(oDate[f[0]](),f[1]);} +default:return m1;}};while(format.match(/%[cDFhnrRtTxX]/)){format=format.replace(/%([cDFhnrRtTxX])/g,replace_aggs);} +var str=format.replace(/%([aAbBCdegGHIjklmMpPsSuUVwWyYzZ%])/g,replace_formats);replace_aggs=replace_formats=undefined;return str;}};Y.mix(Y.namespace("DataType.Date"),Dt);var YDateEn={a:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],A:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],b:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],B:["January","February","March","April","May","June","July","August","September","October","November","December"],c:"%a %d %b %Y %T %Z",p:["AM","PM"],P:["am","pm"],r:"%I:%M:%S %p",x:"%d/%m/%y",X:"%T"};Y.namespace("DataType.Date.Locale");Y.DataType.Date.Locale["en"]=YDateEn;Y.DataType.Date.Locale["en-US"]=Y.merge(YDateEn,{c:"%a %d %b %Y %I:%M:%S %p %Z",x:"%m/%d/%Y",X:"%I:%M:%S %p"});Y.DataType.Date.Locale["en-GB"]=Y.merge(YDateEn,{r:"%l:%M:%S %P %Z"});Y.DataType.Date.Locale["en-AU"]=Y.merge(YDateEn);},'3.0.0'); \ No newline at end of file diff --git a/include/javascript/yui3/build/datatype/datatype-date-min.js b/include/javascript/yui3/build/datatype/datatype-date-min.js new file mode 100644 index 00000000..1d2ae634 --- /dev/null +++ b/include/javascript/yui3/build/datatype/datatype-date-min.js @@ -0,0 +1,8 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add("datatype-date-parse",function(B){var A=B.Lang;B.mix(B.namespace("DataType.Date"),{parse:function(D){var C=null;if(!(A.isDate(D))){C=new Date(D);}else{return C;}if(A.isDate(C)&&(C!="Invalid Date")&&!isNaN(C)){return C;}else{return null;}}});B.namespace("Parsers").date=B.DataType.Date.parse;},"3.0.0");YUI.add("datatype-date-format",function(D){var A=function(E,G,F){if(typeof F==="undefined"){F=10;}G=G.toString();for(;parseInt(E,10)1;F/=10){E=G+E;}return E.toString();};D.config.dateFormat=D.config.dateFormat||"%Y-%m-%d";D.config.locale=D.config.locale||"en";var C={formats:{a:function(F,E){return E.a[F.getDay()];},A:function(F,E){return E.A[F.getDay()];},b:function(F,E){return E.b[F.getMonth()];},B:function(F,E){return E.B[F.getMonth()];},C:function(E){return A(parseInt(E.getFullYear()/100,10),0);},d:["getDate","0"],e:["getDate"," "],g:function(E){return A(parseInt(C.formats.G(E)%100,10),0);},G:function(G){var H=G.getFullYear();var F=parseInt(C.formats.V(G),10);var E=parseInt(C.formats.W(G),10);if(E>F){H++;}else{if(E===0&&F>=52){H--;}}return H;},H:["getHours","0"],I:function(F){var E=F.getHours()%12;return A(E===0?12:E,0);},j:function(I){var H=new Date(""+I.getFullYear()+"/1/1 GMT");var F=new Date(""+I.getFullYear()+"/"+(I.getMonth()+1)+"/"+I.getDate()+" GMT");var E=F-H;var G=parseInt(E/60000/60/24,10)+1;return A(G,0,100);},k:["getHours"," "],l:function(F){var E=F.getHours()%12;return A(E===0?12:E," ");},m:function(E){return A(E.getMonth()+1,0);},M:["getMinutes","0"],p:function(F,E){return E.p[F.getHours()>=12?1:0];},P:function(F,E){return E.P[F.getHours()>=12?1:0];},s:function(F,E){return parseInt(F.getTime()/1000,10);},S:["getSeconds","0"],u:function(E){var F=E.getDay();return F===0?7:F;},U:function(H){var E=parseInt(C.formats.j(H),10);var G=6-H.getDay();var F=parseInt((E+G)/7,10);return A(F,0);},V:function(H){var G=parseInt(C.formats.W(H),10);var E=(new Date(""+H.getFullYear()+"/1/1")).getDay();var F=G+(E>4||E<=1?0:1);if(F===53&&(new Date(""+H.getFullYear()+"/12/31")).getDay()<4){F=1;}else{if(F===0){F=C.formats.V(new Date(""+(H.getFullYear()-1)+"/12/31"));}}return A(F,0);},w:"getDay",W:function(H){var E=parseInt(C.formats.j(H),10);var G=7-C.formats.u(H);var F=parseInt((E+G)/7,10);return A(F,0,10);},y:function(E){return A(E.getFullYear()%100,0);},Y:"getFullYear",z:function(G){var F=G.getTimezoneOffset();var E=A(parseInt(Math.abs(F/60),10),0);var I=A(Math.abs(F%60),0);return(F>0?"-":"+")+E+I;},Z:function(E){var F=E.toString().replace(/^.*:\d\d( GMT[+-]\d+)? \(?([A-Za-z ]+)\)?\d*$/,"$2").replace(/[a-z ]/g,"");if(F.length>4){F=C.formats.z(E);}return F;},"%":function(E){return"%";}},aggregates:{c:"locale",D:"%m/%d/%y",F:"%Y-%m-%d",h:"%b",n:"\n",r:"locale",R:"%H:%M",t:"\t",T:"%H:%M:%S",x:"locale",X:"locale"},format:function(N,H){H=H||{};if(!D.Lang.isDate(N)){return D.Lang.isValue(N)?N:"";}var M=H.format||D.config.dateFormat,F=H.locale||D.config.locale,L=D.DataType.Date.Locale;F=F.replace(/_/g,"-");if(!L[F]){var G=F.replace(/-[a-zA-Z]+$/,"");if(G in L){F=G;}else{if(D.config.locale in L){F=D.config.locale;}else{F="en";}}}var J=L[F];var I=function(P,O){var Q=C.aggregates[O];return(Q==="locale"?J[O]:Q);};var E=function(P,O){var Q=C.formats[O];switch(D.Lang.type(Q)){case"string":return N[Q]();case"function":return Q.call(N,N,J);case"array":if(D.Lang.type(Q[0])==="string"){return A(N[Q[0]](),Q[1]);}default:return O;}};while(M.match(/%[cDFhnrRtTxX]/)){M=M.replace(/%([cDFhnrRtTxX])/g,I);}var K=M.replace(/%([aAbBCdegGHIjklmMpPsSuUVwWyYzZ%])/g,E);I=E=undefined;return K;}};D.mix(D.namespace("DataType.Date"),C);var B={a:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],A:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],b:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],B:["January","February","March","April","May","June","July","August","September","October","November","December"],c:"%a %d %b %Y %T %Z",p:["AM","PM"],P:["am","pm"],r:"%I:%M:%S %p",x:"%d/%m/%y",X:"%T"};D.namespace("DataType.Date.Locale");D.DataType.Date.Locale["en"]=B;D.DataType.Date.Locale["en-US"]=D.merge(B,{c:"%a %d %b %Y %I:%M:%S %p %Z",x:"%m/%d/%Y",X:"%I:%M:%S %p"});D.DataType.Date.Locale["en-GB"]=D.merge(B,{r:"%l:%M:%S %P %Z"});D.DataType.Date.Locale["en-AU"]=D.merge(B);},"3.0.0");YUI.add("datatype-date",function(A){},"3.0.0",{use:["datatype-date-parse","datatype-date-format"]}); \ No newline at end of file diff --git a/include/javascript/yui3/build/datatype/datatype-date-parse-min.js b/include/javascript/yui3/build/datatype/datatype-date-parse-min.js new file mode 100644 index 00000000..e3c9c307 --- /dev/null +++ b/include/javascript/yui3/build/datatype/datatype-date-parse-min.js @@ -0,0 +1,8 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add("datatype-date-parse",function(B){var A=B.Lang;B.mix(B.namespace("DataType.Date"),{parse:function(D){var C=null;if(!(A.isDate(D))){C=new Date(D);}else{return C;}if(A.isDate(C)&&(C!="Invalid Date")&&!isNaN(C)){return C;}else{return null;}}});B.namespace("Parsers").date=B.DataType.Date.parse;},"3.0.0"); \ No newline at end of file diff --git a/include/javascript/yui3/build/datatype/datatype-date-parse.js b/include/javascript/yui3/build/datatype/datatype-date-parse.js new file mode 100644 index 00000000..0cb5c212 --- /dev/null +++ b/include/javascript/yui3/build/datatype/datatype-date-parse.js @@ -0,0 +1,11 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add('datatype-date-parse',function(Y){var LANG=Y.Lang;Y.mix(Y.namespace("DataType.Date"),{parse:function(data){var date=null;if(!(LANG.isDate(data))){date=new Date(data);} +else{return date;} +if(LANG.isDate(date)&&(date!="Invalid Date")&&!isNaN(date)){return date;} +else{return null;}}});Y.namespace("Parsers").date=Y.DataType.Date.parse;},'3.0.0'); \ No newline at end of file diff --git a/include/javascript/yui3/build/datatype/datatype-date.js b/include/javascript/yui3/build/datatype/datatype-date.js new file mode 100644 index 00000000..8e9fe7af --- /dev/null +++ b/include/javascript/yui3/build/datatype/datatype-date.js @@ -0,0 +1,25 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add('datatype-date-parse',function(Y){var LANG=Y.Lang;Y.mix(Y.namespace("DataType.Date"),{parse:function(data){var date=null;if(!(LANG.isDate(data))){date=new Date(data);} +else{return date;} +if(LANG.isDate(date)&&(date!="Invalid Date")&&!isNaN(date)){return date;} +else{return null;}}});Y.namespace("Parsers").date=Y.DataType.Date.parse;},'3.0.0');YUI.add('datatype-date-format',function(Y){var xPad=function(x,pad,r) +{if(typeof r==="undefined") +{r=10;} +pad=pad.toString();for(;parseInt(x,10)1;r/=10){x=pad+x;} +return x.toString();};Y.config.dateFormat=Y.config.dateFormat||"%Y-%m-%d";Y.config.locale=Y.config.locale||"en";var Dt={formats:{a:function(d,l){return l.a[d.getDay()];},A:function(d,l){return l.A[d.getDay()];},b:function(d,l){return l.b[d.getMonth()];},B:function(d,l){return l.B[d.getMonth()];},C:function(d){return xPad(parseInt(d.getFullYear()/100,10),0);},d:["getDate","0"],e:["getDate"," "],g:function(d){return xPad(parseInt(Dt.formats.G(d)%100,10),0);},G:function(d){var y=d.getFullYear();var V=parseInt(Dt.formats.V(d),10);var W=parseInt(Dt.formats.W(d),10);if(W>V){y++;}else if(W===0&&V>=52){y--;} +return y;},H:["getHours","0"],I:function(d){var I=d.getHours()%12;return xPad(I===0?12:I,0);},j:function(d){var gmd_1=new Date(""+d.getFullYear()+"/1/1 GMT");var gmdate=new Date(""+d.getFullYear()+"/"+(d.getMonth()+1)+"/"+d.getDate()+" GMT");var ms=gmdate-gmd_1;var doy=parseInt(ms/60000/60/24,10)+1;return xPad(doy,0,100);},k:["getHours"," "],l:function(d){var I=d.getHours()%12;return xPad(I===0?12:I," ");},m:function(d){return xPad(d.getMonth()+1,0);},M:["getMinutes","0"],p:function(d,l){return l.p[d.getHours()>=12?1:0];},P:function(d,l){return l.P[d.getHours()>=12?1:0];},s:function(d,l){return parseInt(d.getTime()/1000,10);},S:["getSeconds","0"],u:function(d){var dow=d.getDay();return dow===0?7:dow;},U:function(d){var doy=parseInt(Dt.formats.j(d),10);var rdow=6-d.getDay();var woy=parseInt((doy+rdow)/7,10);return xPad(woy,0);},V:function(d){var woy=parseInt(Dt.formats.W(d),10);var dow1_1=(new Date(""+d.getFullYear()+"/1/1")).getDay();var idow=woy+(dow1_1>4||dow1_1<=1?0:1);if(idow===53&&(new Date(""+d.getFullYear()+"/12/31")).getDay()<4) +{idow=1;} +else if(idow===0) +{idow=Dt.formats.V(new Date(""+(d.getFullYear()-1)+"/12/31"));} +return xPad(idow,0);},w:"getDay",W:function(d){var doy=parseInt(Dt.formats.j(d),10);var rdow=7-Dt.formats.u(d);var woy=parseInt((doy+rdow)/7,10);return xPad(woy,0,10);},y:function(d){return xPad(d.getFullYear()%100,0);},Y:"getFullYear",z:function(d){var o=d.getTimezoneOffset();var H=xPad(parseInt(Math.abs(o/60),10),0);var M=xPad(Math.abs(o%60),0);return(o>0?"-":"+")+H+M;},Z:function(d){var tz=d.toString().replace(/^.*:\d\d( GMT[+-]\d+)? \(?([A-Za-z ]+)\)?\d*$/,"$2").replace(/[a-z ]/g,"");if(tz.length>4){tz=Dt.formats.z(d);} +return tz;},"%":function(d){return"%";}},aggregates:{c:"locale",D:"%m/%d/%y",F:"%Y-%m-%d",h:"%b",n:"\n",r:"locale",R:"%H:%M",t:"\t",T:"%H:%M:%S",x:"locale",X:"locale"},format:function(oDate,oConfig){oConfig=oConfig||{};if(!Y.Lang.isDate(oDate)){return Y.Lang.isValue(oDate)?oDate:"";} +var format=oConfig.format||Y.config.dateFormat,sLocale=oConfig.locale||Y.config.locale,LOCALE=Y.DataType.Date.Locale;sLocale=sLocale.replace(/_/g,"-");if(!LOCALE[sLocale]){var tmpLocale=sLocale.replace(/-[a-zA-Z]+$/,"");if(tmpLocale in LOCALE){sLocale=tmpLocale;}else if(Y.config.locale in LOCALE){sLocale=Y.config.locale;}else{sLocale="en";}} +var aLocale=LOCALE[sLocale];var replace_aggs=function(m0,m1){var f=Dt.aggregates[m1];return(f==="locale"?aLocale[m1]:f);};var replace_formats=function(m0,m1){var f=Dt.formats[m1];switch(Y.Lang.type(f)){case"string":return oDate[f]();case"function":return f.call(oDate,oDate,aLocale);case"array":if(Y.Lang.type(f[0])==="string"){return xPad(oDate[f[0]](),f[1]);} +default:return m1;}};while(format.match(/%[cDFhnrRtTxX]/)){format=format.replace(/%([cDFhnrRtTxX])/g,replace_aggs);} +var str=format.replace(/%([aAbBCdegGHIjklmMpPsSuUVwWyYzZ%])/g,replace_formats);replace_aggs=replace_formats=undefined;return str;}};Y.mix(Y.namespace("DataType.Date"),Dt);var YDateEn={a:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],A:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],b:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],B:["January","February","March","April","May","June","July","August","September","October","November","December"],c:"%a %d %b %Y %T %Z",p:["AM","PM"],P:["am","pm"],r:"%I:%M:%S %p",x:"%d/%m/%y",X:"%T"};Y.namespace("DataType.Date.Locale");Y.DataType.Date.Locale["en"]=YDateEn;Y.DataType.Date.Locale["en-US"]=Y.merge(YDateEn,{c:"%a %d %b %Y %I:%M:%S %p %Z",x:"%m/%d/%Y",X:"%I:%M:%S %p"});Y.DataType.Date.Locale["en-GB"]=Y.merge(YDateEn,{r:"%l:%M:%S %P %Z"});Y.DataType.Date.Locale["en-AU"]=Y.merge(YDateEn);},'3.0.0');YUI.add('datatype-date',function(Y){},'3.0.0',{use:['datatype-date-parse','datatype-date-format']}); \ No newline at end of file diff --git a/include/javascript/yui3/build/datatype/datatype-min.js b/include/javascript/yui3/build/datatype/datatype-min.js new file mode 100644 index 00000000..78209572 --- /dev/null +++ b/include/javascript/yui3/build/datatype/datatype-min.js @@ -0,0 +1,8 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add("datatype-number-parse",function(B){var A=B.Lang;B.mix(B.namespace("DataType.Number"),{parse:function(D){var C=(D===null)?D:+D;if(A.isNumber(C)){return C;}else{return null;}}});B.namespace("Parsers").number=B.DataType.Number.parse;},"3.0.0");YUI.add("datatype-number-format",function(B){var A=B.Lang;B.mix(B.namespace("DataType.Number"),{format:function(I,E){if(A.isNumber(I)){E=E||{};var D=(I<0),F=I+"",M=E.decimalPlaces,C=E.decimalSeparator||".",L=E.thousandsSeparator,K,G,J,H;if(A.isNumber(M)&&(M>=0)&&(M<=20)){F=I.toFixed(M);}if(C!=="."){F=F.replace(".",C);}if(L){K=F.lastIndexOf(C);K=(K>-1)?K:F.length;G=F.substring(K);for(J=0,H=K;H>0;H--){if((J%3===0)&&(H!==K)&&(!D||(H>1))){G=L+G;}G=F.charAt(H-1)+G;J++;}F=G;}F=(E.prefix)?E.prefix+F:F;F=(E.suffix)?F+E.suffix:F;return F;}else{return(A.isValue(I)&&I.toString)?I.toString():"";}}});},"3.0.0");YUI.add("datatype-number",function(A){},"3.0.0",{use:["datatype-number-parse","datatype-number-format"]});YUI.add("datatype-date-parse",function(B){var A=B.Lang;B.mix(B.namespace("DataType.Date"),{parse:function(D){var C=null;if(!(A.isDate(D))){C=new Date(D);}else{return C;}if(A.isDate(C)&&(C!="Invalid Date")&&!isNaN(C)){return C;}else{return null;}}});B.namespace("Parsers").date=B.DataType.Date.parse;},"3.0.0");YUI.add("datatype-date-format",function(D){var A=function(E,G,F){if(typeof F==="undefined"){F=10;}G=G.toString();for(;parseInt(E,10)1;F/=10){E=G+E;}return E.toString();};D.config.dateFormat=D.config.dateFormat||"%Y-%m-%d";D.config.locale=D.config.locale||"en";var C={formats:{a:function(F,E){return E.a[F.getDay()];},A:function(F,E){return E.A[F.getDay()];},b:function(F,E){return E.b[F.getMonth()];},B:function(F,E){return E.B[F.getMonth()];},C:function(E){return A(parseInt(E.getFullYear()/100,10),0);},d:["getDate","0"],e:["getDate"," "],g:function(E){return A(parseInt(C.formats.G(E)%100,10),0);},G:function(G){var H=G.getFullYear();var F=parseInt(C.formats.V(G),10);var E=parseInt(C.formats.W(G),10);if(E>F){H++;}else{if(E===0&&F>=52){H--;}}return H;},H:["getHours","0"],I:function(F){var E=F.getHours()%12;return A(E===0?12:E,0);},j:function(I){var H=new Date(""+I.getFullYear()+"/1/1 GMT");var F=new Date(""+I.getFullYear()+"/"+(I.getMonth()+1)+"/"+I.getDate()+" GMT");var E=F-H;var G=parseInt(E/60000/60/24,10)+1;return A(G,0,100);},k:["getHours"," "],l:function(F){var E=F.getHours()%12;return A(E===0?12:E," ");},m:function(E){return A(E.getMonth()+1,0);},M:["getMinutes","0"],p:function(F,E){return E.p[F.getHours()>=12?1:0];},P:function(F,E){return E.P[F.getHours()>=12?1:0];},s:function(F,E){return parseInt(F.getTime()/1000,10);},S:["getSeconds","0"],u:function(E){var F=E.getDay();return F===0?7:F;},U:function(H){var E=parseInt(C.formats.j(H),10);var G=6-H.getDay();var F=parseInt((E+G)/7,10);return A(F,0);},V:function(H){var G=parseInt(C.formats.W(H),10);var E=(new Date(""+H.getFullYear()+"/1/1")).getDay();var F=G+(E>4||E<=1?0:1);if(F===53&&(new Date(""+H.getFullYear()+"/12/31")).getDay()<4){F=1;}else{if(F===0){F=C.formats.V(new Date(""+(H.getFullYear()-1)+"/12/31"));}}return A(F,0);},w:"getDay",W:function(H){var E=parseInt(C.formats.j(H),10);var G=7-C.formats.u(H);var F=parseInt((E+G)/7,10);return A(F,0,10);},y:function(E){return A(E.getFullYear()%100,0);},Y:"getFullYear",z:function(G){var F=G.getTimezoneOffset();var E=A(parseInt(Math.abs(F/60),10),0);var I=A(Math.abs(F%60),0);return(F>0?"-":"+")+E+I;},Z:function(E){var F=E.toString().replace(/^.*:\d\d( GMT[+-]\d+)? \(?([A-Za-z ]+)\)?\d*$/,"$2").replace(/[a-z ]/g,"");if(F.length>4){F=C.formats.z(E);}return F;},"%":function(E){return"%";}},aggregates:{c:"locale",D:"%m/%d/%y",F:"%Y-%m-%d",h:"%b",n:"\n",r:"locale",R:"%H:%M",t:"\t",T:"%H:%M:%S",x:"locale",X:"locale"},format:function(N,H){H=H||{};if(!D.Lang.isDate(N)){return D.Lang.isValue(N)?N:"";}var M=H.format||D.config.dateFormat,F=H.locale||D.config.locale,L=D.DataType.Date.Locale;F=F.replace(/_/g,"-");if(!L[F]){var G=F.replace(/-[a-zA-Z]+$/,"");if(G in L){F=G;}else{if(D.config.locale in L){F=D.config.locale;}else{F="en";}}}var J=L[F];var I=function(P,O){var Q=C.aggregates[O];return(Q==="locale"?J[O]:Q);};var E=function(P,O){var Q=C.formats[O];switch(D.Lang.type(Q)){case"string":return N[Q]();case"function":return Q.call(N,N,J);case"array":if(D.Lang.type(Q[0])==="string"){return A(N[Q[0]](),Q[1]);}default:return O;}};while(M.match(/%[cDFhnrRtTxX]/)){M=M.replace(/%([cDFhnrRtTxX])/g,I);}var K=M.replace(/%([aAbBCdegGHIjklmMpPsSuUVwWyYzZ%])/g,E);I=E=undefined;return K;}};D.mix(D.namespace("DataType.Date"),C);var B={a:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],A:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],b:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],B:["January","February","March","April","May","June","July","August","September","October","November","December"],c:"%a %d %b %Y %T %Z",p:["AM","PM"],P:["am","pm"],r:"%I:%M:%S %p",x:"%d/%m/%y",X:"%T"};D.namespace("DataType.Date.Locale");D.DataType.Date.Locale["en"]=B;D.DataType.Date.Locale["en-US"]=D.merge(B,{c:"%a %d %b %Y %I:%M:%S %p %Z",x:"%m/%d/%Y",X:"%I:%M:%S %p"});D.DataType.Date.Locale["en-GB"]=D.merge(B,{r:"%l:%M:%S %P %Z"});D.DataType.Date.Locale["en-AU"]=D.merge(B);},"3.0.0");YUI.add("datatype-date",function(A){},"3.0.0",{use:["datatype-date-parse","datatype-date-format"]});YUI.add("datatype-xml-parse",function(B){var A=B.Lang;B.mix(B.namespace("DataType.XML"),{parse:function(E){var D=null;if(A.isString(E)){try{if(!A.isUndefined(DOMParser)){D=new DOMParser().parseFromString(E,"text/xml");}}catch(F){try{if(!A.isUndefined(ActiveXObject)){D=new ActiveXObject("Microsoft.XMLDOM");D.async=false;D.loadXML(E);}}catch(C){}}}if((A.isNull(D))||(A.isNull(D.documentElement))||(D.documentElement.nodeName==="parsererror")){}return D;}});B.namespace("Parsers").xml=B.DataType.XML.parse;},"3.0.0");YUI.add("datatype-xml-format",function(B){var A=B.Lang;B.mix(B.namespace("DataType.XML"),{format:function(C){try{if(!A.isUndefined(XMLSerializer)){return(new XMLSerializer()).serializeToString(C);}}catch(D){if(C&&C.xml){return C.xml;}else{return(A.isValue(C)&&C.toString)?C.toString():"";}}}});},"3.0.0");YUI.add("datatype-xml",function(A){},"3.0.0",{use:["datatype-xml-parse","datatype-xml-format"]});YUI.add("datatype",function(A){},"3.0.0",{use:["datatype-number","datatype-date","datatype-xml"]}); \ No newline at end of file diff --git a/include/javascript/yui3/build/datatype/datatype-number-format-min.js b/include/javascript/yui3/build/datatype/datatype-number-format-min.js new file mode 100644 index 00000000..a70c31ea --- /dev/null +++ b/include/javascript/yui3/build/datatype/datatype-number-format-min.js @@ -0,0 +1,8 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add("datatype-number-format",function(B){var A=B.Lang;B.mix(B.namespace("DataType.Number"),{format:function(I,E){if(A.isNumber(I)){E=E||{};var D=(I<0),F=I+"",M=E.decimalPlaces,C=E.decimalSeparator||".",L=E.thousandsSeparator,K,G,J,H;if(A.isNumber(M)&&(M>=0)&&(M<=20)){F=I.toFixed(M);}if(C!=="."){F=F.replace(".",C);}if(L){K=F.lastIndexOf(C);K=(K>-1)?K:F.length;G=F.substring(K);for(J=0,H=K;H>0;H--){if((J%3===0)&&(H!==K)&&(!D||(H>1))){G=L+G;}G=F.charAt(H-1)+G;J++;}F=G;}F=(E.prefix)?E.prefix+F:F;F=(E.suffix)?F+E.suffix:F;return F;}else{return(A.isValue(I)&&I.toString)?I.toString():"";}}});},"3.0.0"); \ No newline at end of file diff --git a/include/javascript/yui3/build/datatype/datatype-number-format.js b/include/javascript/yui3/build/datatype/datatype-number-format.js new file mode 100644 index 00000000..fe1e254c --- /dev/null +++ b/include/javascript/yui3/build/datatype/datatype-number-format.js @@ -0,0 +1,14 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add('datatype-number-format',function(Y){var LANG=Y.Lang;Y.mix(Y.namespace("DataType.Number"),{format:function(data,config){if(LANG.isNumber(data)){config=config||{};var isNeg=(data<0),output=data+"",decPlaces=config.decimalPlaces,decSep=config.decimalSeparator||".",thouSep=config.thousandsSeparator,decIndex,newOutput,count,i;if(LANG.isNumber(decPlaces)&&(decPlaces>=0)&&(decPlaces<=20)){output=data.toFixed(decPlaces);} +if(decSep!=="."){output=output.replace(".",decSep);} +if(thouSep){decIndex=output.lastIndexOf(decSep);decIndex=(decIndex>-1)?decIndex:output.length;newOutput=output.substring(decIndex);for(count=0,i=decIndex;i>0;i--){if((count%3===0)&&(i!==decIndex)&&(!isNeg||(i>1))){newOutput=thouSep+newOutput;} +newOutput=output.charAt(i-1)+newOutput;count++;} +output=newOutput;} +output=(config.prefix)?config.prefix+output:output;output=(config.suffix)?output+config.suffix:output;return output;} +else{return(LANG.isValue(data)&&data.toString)?data.toString():"";}}});},'3.0.0'); \ No newline at end of file diff --git a/include/javascript/yui3/build/datatype/datatype-number-min.js b/include/javascript/yui3/build/datatype/datatype-number-min.js new file mode 100644 index 00000000..0703c8bc --- /dev/null +++ b/include/javascript/yui3/build/datatype/datatype-number-min.js @@ -0,0 +1,8 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add("datatype-number-parse",function(B){var A=B.Lang;B.mix(B.namespace("DataType.Number"),{parse:function(D){var C=(D===null)?D:+D;if(A.isNumber(C)){return C;}else{return null;}}});B.namespace("Parsers").number=B.DataType.Number.parse;},"3.0.0");YUI.add("datatype-number-format",function(B){var A=B.Lang;B.mix(B.namespace("DataType.Number"),{format:function(I,E){if(A.isNumber(I)){E=E||{};var D=(I<0),F=I+"",M=E.decimalPlaces,C=E.decimalSeparator||".",L=E.thousandsSeparator,K,G,J,H;if(A.isNumber(M)&&(M>=0)&&(M<=20)){F=I.toFixed(M);}if(C!=="."){F=F.replace(".",C);}if(L){K=F.lastIndexOf(C);K=(K>-1)?K:F.length;G=F.substring(K);for(J=0,H=K;H>0;H--){if((J%3===0)&&(H!==K)&&(!D||(H>1))){G=L+G;}G=F.charAt(H-1)+G;J++;}F=G;}F=(E.prefix)?E.prefix+F:F;F=(E.suffix)?F+E.suffix:F;return F;}else{return(A.isValue(I)&&I.toString)?I.toString():"";}}});},"3.0.0");YUI.add("datatype-number",function(A){},"3.0.0",{use:["datatype-number-parse","datatype-number-format"]}); \ No newline at end of file diff --git a/include/javascript/yui3/build/datatype/datatype-number-parse-min.js b/include/javascript/yui3/build/datatype/datatype-number-parse-min.js new file mode 100644 index 00000000..9a700d45 --- /dev/null +++ b/include/javascript/yui3/build/datatype/datatype-number-parse-min.js @@ -0,0 +1,8 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add("datatype-number-parse",function(B){var A=B.Lang;B.mix(B.namespace("DataType.Number"),{parse:function(D){var C=(D===null)?D:+D;if(A.isNumber(C)){return C;}else{return null;}}});B.namespace("Parsers").number=B.DataType.Number.parse;},"3.0.0"); \ No newline at end of file diff --git a/include/javascript/yui3/build/datatype/datatype-number-parse.js b/include/javascript/yui3/build/datatype/datatype-number-parse.js new file mode 100644 index 00000000..139e4eb4 --- /dev/null +++ b/include/javascript/yui3/build/datatype/datatype-number-parse.js @@ -0,0 +1,9 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add('datatype-number-parse',function(Y){var LANG=Y.Lang;Y.mix(Y.namespace("DataType.Number"),{parse:function(data){var number=(data===null)?data:+data;if(LANG.isNumber(number)){return number;} +else{return null;}}});Y.namespace("Parsers").number=Y.DataType.Number.parse;},'3.0.0'); \ No newline at end of file diff --git a/include/javascript/yui3/build/datatype/datatype-number.js b/include/javascript/yui3/build/datatype/datatype-number.js new file mode 100644 index 00000000..094790fb --- /dev/null +++ b/include/javascript/yui3/build/datatype/datatype-number.js @@ -0,0 +1,15 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add('datatype-number-parse',function(Y){var LANG=Y.Lang;Y.mix(Y.namespace("DataType.Number"),{parse:function(data){var number=(data===null)?data:+data;if(LANG.isNumber(number)){return number;} +else{return null;}}});Y.namespace("Parsers").number=Y.DataType.Number.parse;},'3.0.0');YUI.add('datatype-number-format',function(Y){var LANG=Y.Lang;Y.mix(Y.namespace("DataType.Number"),{format:function(data,config){if(LANG.isNumber(data)){config=config||{};var isNeg=(data<0),output=data+"",decPlaces=config.decimalPlaces,decSep=config.decimalSeparator||".",thouSep=config.thousandsSeparator,decIndex,newOutput,count,i;if(LANG.isNumber(decPlaces)&&(decPlaces>=0)&&(decPlaces<=20)){output=data.toFixed(decPlaces);} +if(decSep!=="."){output=output.replace(".",decSep);} +if(thouSep){decIndex=output.lastIndexOf(decSep);decIndex=(decIndex>-1)?decIndex:output.length;newOutput=output.substring(decIndex);for(count=0,i=decIndex;i>0;i--){if((count%3===0)&&(i!==decIndex)&&(!isNeg||(i>1))){newOutput=thouSep+newOutput;} +newOutput=output.charAt(i-1)+newOutput;count++;} +output=newOutput;} +output=(config.prefix)?config.prefix+output:output;output=(config.suffix)?output+config.suffix:output;return output;} +else{return(LANG.isValue(data)&&data.toString)?data.toString():"";}}});},'3.0.0');YUI.add('datatype-number',function(Y){},'3.0.0',{use:['datatype-number-parse','datatype-number-format']}); \ No newline at end of file diff --git a/include/javascript/yui3/build/datatype/datatype-xml-format-min.js b/include/javascript/yui3/build/datatype/datatype-xml-format-min.js new file mode 100644 index 00000000..bb17701a --- /dev/null +++ b/include/javascript/yui3/build/datatype/datatype-xml-format-min.js @@ -0,0 +1,8 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add("datatype-xml-format",function(B){var A=B.Lang;B.mix(B.namespace("DataType.XML"),{format:function(C){try{if(!A.isUndefined(XMLSerializer)){return(new XMLSerializer()).serializeToString(C);}}catch(D){if(C&&C.xml){return C.xml;}else{return(A.isValue(C)&&C.toString)?C.toString():"";}}}});},"3.0.0"); \ No newline at end of file diff --git a/include/javascript/yui3/build/datatype/datatype-xml-format.js b/include/javascript/yui3/build/datatype/datatype-xml-format.js new file mode 100644 index 00000000..aa351603 --- /dev/null +++ b/include/javascript/yui3/build/datatype/datatype-xml-format.js @@ -0,0 +1,10 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add('datatype-xml-format',function(Y){var LANG=Y.Lang;Y.mix(Y.namespace("DataType.XML"),{format:function(data){try{if(!LANG.isUndefined(XMLSerializer)){return(new XMLSerializer()).serializeToString(data);}} +catch(e){if(data&&data.xml){return data.xml;} +else{return(LANG.isValue(data)&&data.toString)?data.toString():"";}}}});},'3.0.0'); \ No newline at end of file diff --git a/include/javascript/yui3/build/datatype/datatype-xml-min.js b/include/javascript/yui3/build/datatype/datatype-xml-min.js new file mode 100644 index 00000000..9b270649 --- /dev/null +++ b/include/javascript/yui3/build/datatype/datatype-xml-min.js @@ -0,0 +1,8 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add("datatype-xml-parse",function(B){var A=B.Lang;B.mix(B.namespace("DataType.XML"),{parse:function(E){var D=null;if(A.isString(E)){try{if(!A.isUndefined(DOMParser)){D=new DOMParser().parseFromString(E,"text/xml");}}catch(F){try{if(!A.isUndefined(ActiveXObject)){D=new ActiveXObject("Microsoft.XMLDOM");D.async=false;D.loadXML(E);}}catch(C){}}}if((A.isNull(D))||(A.isNull(D.documentElement))||(D.documentElement.nodeName==="parsererror")){}return D;}});B.namespace("Parsers").xml=B.DataType.XML.parse;},"3.0.0");YUI.add("datatype-xml-format",function(B){var A=B.Lang;B.mix(B.namespace("DataType.XML"),{format:function(C){try{if(!A.isUndefined(XMLSerializer)){return(new XMLSerializer()).serializeToString(C);}}catch(D){if(C&&C.xml){return C.xml;}else{return(A.isValue(C)&&C.toString)?C.toString():"";}}}});},"3.0.0");YUI.add("datatype-xml",function(A){},"3.0.0",{use:["datatype-xml-parse","datatype-xml-format"]}); \ No newline at end of file diff --git a/include/javascript/yui3/build/datatype/datatype-xml-parse-min.js b/include/javascript/yui3/build/datatype/datatype-xml-parse-min.js new file mode 100644 index 00000000..1dc26231 --- /dev/null +++ b/include/javascript/yui3/build/datatype/datatype-xml-parse-min.js @@ -0,0 +1,8 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add("datatype-xml-parse",function(B){var A=B.Lang;B.mix(B.namespace("DataType.XML"),{parse:function(E){var D=null;if(A.isString(E)){try{if(!A.isUndefined(DOMParser)){D=new DOMParser().parseFromString(E,"text/xml");}}catch(F){try{if(!A.isUndefined(ActiveXObject)){D=new ActiveXObject("Microsoft.XMLDOM");D.async=false;D.loadXML(E);}}catch(C){}}}if((A.isNull(D))||(A.isNull(D.documentElement))||(D.documentElement.nodeName==="parsererror")){}return D;}});B.namespace("Parsers").xml=B.DataType.XML.parse;},"3.0.0"); \ No newline at end of file diff --git a/include/javascript/yui3/build/datatype/datatype-xml-parse.js b/include/javascript/yui3/build/datatype/datatype-xml-parse.js new file mode 100644 index 00000000..ebde1ccc --- /dev/null +++ b/include/javascript/yui3/build/datatype/datatype-xml-parse.js @@ -0,0 +1,12 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add('datatype-xml-parse',function(Y){var LANG=Y.Lang;Y.mix(Y.namespace("DataType.XML"),{parse:function(data){var xmlDoc=null;if(LANG.isString(data)){try{if(!LANG.isUndefined(DOMParser)){xmlDoc=new DOMParser().parseFromString(data,"text/xml");}} +catch(e){try{if(!LANG.isUndefined(ActiveXObject)){xmlDoc=new ActiveXObject("Microsoft.XMLDOM");xmlDoc.async=false;xmlDoc.loadXML(data);}} +catch(ee){}}} +if((LANG.isNull(xmlDoc))||(LANG.isNull(xmlDoc.documentElement))||(xmlDoc.documentElement.nodeName==="parsererror")){} +return xmlDoc;}});Y.namespace("Parsers").xml=Y.DataType.XML.parse;},'3.0.0'); \ No newline at end of file diff --git a/include/javascript/yui3/build/datatype/datatype-xml.js b/include/javascript/yui3/build/datatype/datatype-xml.js new file mode 100644 index 00000000..9bfd881d --- /dev/null +++ b/include/javascript/yui3/build/datatype/datatype-xml.js @@ -0,0 +1,14 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add('datatype-xml-parse',function(Y){var LANG=Y.Lang;Y.mix(Y.namespace("DataType.XML"),{parse:function(data){var xmlDoc=null;if(LANG.isString(data)){try{if(!LANG.isUndefined(DOMParser)){xmlDoc=new DOMParser().parseFromString(data,"text/xml");}} +catch(e){try{if(!LANG.isUndefined(ActiveXObject)){xmlDoc=new ActiveXObject("Microsoft.XMLDOM");xmlDoc.async=false;xmlDoc.loadXML(data);}} +catch(ee){}}} +if((LANG.isNull(xmlDoc))||(LANG.isNull(xmlDoc.documentElement))||(xmlDoc.documentElement.nodeName==="parsererror")){} +return xmlDoc;}});Y.namespace("Parsers").xml=Y.DataType.XML.parse;},'3.0.0');YUI.add('datatype-xml-format',function(Y){var LANG=Y.Lang;Y.mix(Y.namespace("DataType.XML"),{format:function(data){try{if(!LANG.isUndefined(XMLSerializer)){return(new XMLSerializer()).serializeToString(data);}} +catch(e){if(data&&data.xml){return data.xml;} +else{return(LANG.isValue(data)&&data.toString)?data.toString():"";}}}});},'3.0.0');YUI.add('datatype-xml',function(Y){},'3.0.0',{use:['datatype-xml-parse','datatype-xml-format']}); \ No newline at end of file diff --git a/include/javascript/yui3/build/datatype/datatype.js b/include/javascript/yui3/build/datatype/datatype.js new file mode 100644 index 00000000..b12d4868 --- /dev/null +++ b/include/javascript/yui3/build/datatype/datatype.js @@ -0,0 +1,38 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add('datatype-number-parse',function(Y){var LANG=Y.Lang;Y.mix(Y.namespace("DataType.Number"),{parse:function(data){var number=(data===null)?data:+data;if(LANG.isNumber(number)){return number;} +else{return null;}}});Y.namespace("Parsers").number=Y.DataType.Number.parse;},'3.0.0');YUI.add('datatype-number-format',function(Y){var LANG=Y.Lang;Y.mix(Y.namespace("DataType.Number"),{format:function(data,config){if(LANG.isNumber(data)){config=config||{};var isNeg=(data<0),output=data+"",decPlaces=config.decimalPlaces,decSep=config.decimalSeparator||".",thouSep=config.thousandsSeparator,decIndex,newOutput,count,i;if(LANG.isNumber(decPlaces)&&(decPlaces>=0)&&(decPlaces<=20)){output=data.toFixed(decPlaces);} +if(decSep!=="."){output=output.replace(".",decSep);} +if(thouSep){decIndex=output.lastIndexOf(decSep);decIndex=(decIndex>-1)?decIndex:output.length;newOutput=output.substring(decIndex);for(count=0,i=decIndex;i>0;i--){if((count%3===0)&&(i!==decIndex)&&(!isNeg||(i>1))){newOutput=thouSep+newOutput;} +newOutput=output.charAt(i-1)+newOutput;count++;} +output=newOutput;} +output=(config.prefix)?config.prefix+output:output;output=(config.suffix)?output+config.suffix:output;return output;} +else{return(LANG.isValue(data)&&data.toString)?data.toString():"";}}});},'3.0.0');YUI.add('datatype-number',function(Y){},'3.0.0',{use:['datatype-number-parse','datatype-number-format']});YUI.add('datatype-date-parse',function(Y){var LANG=Y.Lang;Y.mix(Y.namespace("DataType.Date"),{parse:function(data){var date=null;if(!(LANG.isDate(data))){date=new Date(data);} +else{return date;} +if(LANG.isDate(date)&&(date!="Invalid Date")&&!isNaN(date)){return date;} +else{return null;}}});Y.namespace("Parsers").date=Y.DataType.Date.parse;},'3.0.0');YUI.add('datatype-date-format',function(Y){var xPad=function(x,pad,r) +{if(typeof r==="undefined") +{r=10;} +pad=pad.toString();for(;parseInt(x,10)1;r/=10){x=pad+x;} +return x.toString();};Y.config.dateFormat=Y.config.dateFormat||"%Y-%m-%d";Y.config.locale=Y.config.locale||"en";var Dt={formats:{a:function(d,l){return l.a[d.getDay()];},A:function(d,l){return l.A[d.getDay()];},b:function(d,l){return l.b[d.getMonth()];},B:function(d,l){return l.B[d.getMonth()];},C:function(d){return xPad(parseInt(d.getFullYear()/100,10),0);},d:["getDate","0"],e:["getDate"," "],g:function(d){return xPad(parseInt(Dt.formats.G(d)%100,10),0);},G:function(d){var y=d.getFullYear();var V=parseInt(Dt.formats.V(d),10);var W=parseInt(Dt.formats.W(d),10);if(W>V){y++;}else if(W===0&&V>=52){y--;} +return y;},H:["getHours","0"],I:function(d){var I=d.getHours()%12;return xPad(I===0?12:I,0);},j:function(d){var gmd_1=new Date(""+d.getFullYear()+"/1/1 GMT");var gmdate=new Date(""+d.getFullYear()+"/"+(d.getMonth()+1)+"/"+d.getDate()+" GMT");var ms=gmdate-gmd_1;var doy=parseInt(ms/60000/60/24,10)+1;return xPad(doy,0,100);},k:["getHours"," "],l:function(d){var I=d.getHours()%12;return xPad(I===0?12:I," ");},m:function(d){return xPad(d.getMonth()+1,0);},M:["getMinutes","0"],p:function(d,l){return l.p[d.getHours()>=12?1:0];},P:function(d,l){return l.P[d.getHours()>=12?1:0];},s:function(d,l){return parseInt(d.getTime()/1000,10);},S:["getSeconds","0"],u:function(d){var dow=d.getDay();return dow===0?7:dow;},U:function(d){var doy=parseInt(Dt.formats.j(d),10);var rdow=6-d.getDay();var woy=parseInt((doy+rdow)/7,10);return xPad(woy,0);},V:function(d){var woy=parseInt(Dt.formats.W(d),10);var dow1_1=(new Date(""+d.getFullYear()+"/1/1")).getDay();var idow=woy+(dow1_1>4||dow1_1<=1?0:1);if(idow===53&&(new Date(""+d.getFullYear()+"/12/31")).getDay()<4) +{idow=1;} +else if(idow===0) +{idow=Dt.formats.V(new Date(""+(d.getFullYear()-1)+"/12/31"));} +return xPad(idow,0);},w:"getDay",W:function(d){var doy=parseInt(Dt.formats.j(d),10);var rdow=7-Dt.formats.u(d);var woy=parseInt((doy+rdow)/7,10);return xPad(woy,0,10);},y:function(d){return xPad(d.getFullYear()%100,0);},Y:"getFullYear",z:function(d){var o=d.getTimezoneOffset();var H=xPad(parseInt(Math.abs(o/60),10),0);var M=xPad(Math.abs(o%60),0);return(o>0?"-":"+")+H+M;},Z:function(d){var tz=d.toString().replace(/^.*:\d\d( GMT[+-]\d+)? \(?([A-Za-z ]+)\)?\d*$/,"$2").replace(/[a-z ]/g,"");if(tz.length>4){tz=Dt.formats.z(d);} +return tz;},"%":function(d){return"%";}},aggregates:{c:"locale",D:"%m/%d/%y",F:"%Y-%m-%d",h:"%b",n:"\n",r:"locale",R:"%H:%M",t:"\t",T:"%H:%M:%S",x:"locale",X:"locale"},format:function(oDate,oConfig){oConfig=oConfig||{};if(!Y.Lang.isDate(oDate)){return Y.Lang.isValue(oDate)?oDate:"";} +var format=oConfig.format||Y.config.dateFormat,sLocale=oConfig.locale||Y.config.locale,LOCALE=Y.DataType.Date.Locale;sLocale=sLocale.replace(/_/g,"-");if(!LOCALE[sLocale]){var tmpLocale=sLocale.replace(/-[a-zA-Z]+$/,"");if(tmpLocale in LOCALE){sLocale=tmpLocale;}else if(Y.config.locale in LOCALE){sLocale=Y.config.locale;}else{sLocale="en";}} +var aLocale=LOCALE[sLocale];var replace_aggs=function(m0,m1){var f=Dt.aggregates[m1];return(f==="locale"?aLocale[m1]:f);};var replace_formats=function(m0,m1){var f=Dt.formats[m1];switch(Y.Lang.type(f)){case"string":return oDate[f]();case"function":return f.call(oDate,oDate,aLocale);case"array":if(Y.Lang.type(f[0])==="string"){return xPad(oDate[f[0]](),f[1]);} +default:return m1;}};while(format.match(/%[cDFhnrRtTxX]/)){format=format.replace(/%([cDFhnrRtTxX])/g,replace_aggs);} +var str=format.replace(/%([aAbBCdegGHIjklmMpPsSuUVwWyYzZ%])/g,replace_formats);replace_aggs=replace_formats=undefined;return str;}};Y.mix(Y.namespace("DataType.Date"),Dt);var YDateEn={a:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],A:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],b:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],B:["January","February","March","April","May","June","July","August","September","October","November","December"],c:"%a %d %b %Y %T %Z",p:["AM","PM"],P:["am","pm"],r:"%I:%M:%S %p",x:"%d/%m/%y",X:"%T"};Y.namespace("DataType.Date.Locale");Y.DataType.Date.Locale["en"]=YDateEn;Y.DataType.Date.Locale["en-US"]=Y.merge(YDateEn,{c:"%a %d %b %Y %I:%M:%S %p %Z",x:"%m/%d/%Y",X:"%I:%M:%S %p"});Y.DataType.Date.Locale["en-GB"]=Y.merge(YDateEn,{r:"%l:%M:%S %P %Z"});Y.DataType.Date.Locale["en-AU"]=Y.merge(YDateEn);},'3.0.0');YUI.add('datatype-date',function(Y){},'3.0.0',{use:['datatype-date-parse','datatype-date-format']});YUI.add('datatype-xml-parse',function(Y){var LANG=Y.Lang;Y.mix(Y.namespace("DataType.XML"),{parse:function(data){var xmlDoc=null;if(LANG.isString(data)){try{if(!LANG.isUndefined(DOMParser)){xmlDoc=new DOMParser().parseFromString(data,"text/xml");}} +catch(e){try{if(!LANG.isUndefined(ActiveXObject)){xmlDoc=new ActiveXObject("Microsoft.XMLDOM");xmlDoc.async=false;xmlDoc.loadXML(data);}} +catch(ee){}}} +if((LANG.isNull(xmlDoc))||(LANG.isNull(xmlDoc.documentElement))||(xmlDoc.documentElement.nodeName==="parsererror")){} +return xmlDoc;}});Y.namespace("Parsers").xml=Y.DataType.XML.parse;},'3.0.0');YUI.add('datatype-xml-format',function(Y){var LANG=Y.Lang;Y.mix(Y.namespace("DataType.XML"),{format:function(data){try{if(!LANG.isUndefined(XMLSerializer)){return(new XMLSerializer()).serializeToString(data);}} +catch(e){if(data&&data.xml){return data.xml;} +else{return(LANG.isValue(data)&&data.toString)?data.toString():"";}}}});},'3.0.0');YUI.add('datatype-xml',function(Y){},'3.0.0',{use:['datatype-xml-parse','datatype-xml-format']});YUI.add('datatype',function(Y){},'3.0.0',{use:['datatype-number','datatype-date','datatype-xml']}); \ No newline at end of file diff --git a/include/javascript/yui3/build/dd/dd-constrain-min.js b/include/javascript/yui3/build/dd/dd-constrain-min.js new file mode 100644 index 00000000..7cedda68 --- /dev/null +++ b/include/javascript/yui3/build/dd/dd-constrain-min.js @@ -0,0 +1,8 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add("dd-constrain",function(B){var K="dragNode",M="offsetHeight",F="offsetWidth",Q="host",P="constrain2region",H="constrain2node",G="tickXArray",O="tickYArray",N=B.DD.DDM,E="top",J="right",L="bottom",D="left",I=null;var A=function(C){A.superclass.constructor.apply(this,arguments);};A.NAME="DragConstrained";A.NS="con";A.ATTRS={host:{},stickX:{value:false},stickY:{value:false},tickX:{value:false},tickY:{value:false},tickXArray:{value:false},tickYArray:{value:false},constrain2region:{value:false,getter:function(C){if(B.Lang.isObject(C)){var R={};B.mix(R,C);return R;}else{return false;}},setter:function(C){if(B.Lang.isObject(C)){if(B.Lang.isNumber(C[E])&&B.Lang.isNumber(C[J])&&B.Lang.isNumber(C[D])&&B.Lang.isNumber(C[L])){var R={};B.mix(R,C);return R;}else{return false;}}else{if(C!==false){return false;}}return C;}},gutter:{value:"0",setter:function(C){return B.DD.DDM.cssSizestoObject(C);}},constrain2node:{value:false,setter:function(R){if(!this.get(P)){var C=B.Node.get(R);if(C){return C;}}else{if(this.get(P)!==false){}}return false;}},constrain2view:{value:false}};I={initializer:function(){this.get(Q).on("drag:start",B.bind(this._handleStart,this));this.get(Q).after("drag:align",B.bind(this.align,this));},_handleStart:function(){this._regionCache=null;},_regionCache:null,_cacheRegion:function(){this._regionCache=this.get(H).get("region");},getRegion:function(V){var T={},U=null,C=null,S=this.get("gutter"),R=this.get(Q);if(this.get(H)){if(!this._regionCache){B.on("resize",B.bind(this._cacheRegion,this),window);this._cacheRegion();}T=B.clone(this._regionCache);}else{if(this.get(P)){T=this.get(P);}else{if(this.get("constrain2view")){T=R.get(K).get("viewportRegion");}else{return false;}}}B.each(S,function(W,X){if((X==J)||(X==L)){T[X]-=W;}else{T[X]+=W;}});if(V){U=R.get(K).get(M);C=R.get(K).get(F);T[J]=T[J]-C;T[L]=T[L]-U;}return T;},_checkRegion:function(C){var S=C,U=this.getRegion(),T=this.get(Q),V=T.get(K).get(M),R=T.get(K).get(F);if(S[1]>(U[L]-V)){C[1]=(U[L]-V);}if(U[E]>S[1]){C[1]=U[E];}if(S[0]>(U[J]-R)){C[0]=(U[J]-R);}if(U[D]>S[0]){C[0]=U[D];}return C;},inRegion:function(S){S=S||this.get(Q).get(K).getXY();var R=this._checkRegion([S[0],S[1]]),C=false;if((S[0]===R[0])&&(S[1]===R[1])){C=true;}return C;},align:function(){var S=this.get(Q),C=S.actXY,R=this.getRegion(true);if(this.get("stickX")){C[1]=(S.startXY[1]-S.deltaXY[1]);}if(this.get("stickY")){C[0]=(S.startXY[0]-S.deltaXY[0]);}if(R){C=this._checkRegion(C);}C=this._checkTicks(C,R);S.actXY=C;},_checkTicks:function(W,U){var T=this.get(Q),V=(T.startXY[0]-T.deltaXY[0]),S=(T.startXY[1]-T.deltaXY[1]),C=this.get("tickX"),R=this.get("tickY");if(C&&!this.get(G)){W[0]=N._calcTicks(W[0],V,C,U[D],U[J]);}if(R&&!this.get(O)){W[1]=N._calcTicks(W[1],S,R,U[E],U[L]);}if(this.get(G)){W[0]=N._calcTickArray(W[0],this.get(G),U[D],U[J]);}if(this.get(O)){W[1]=N._calcTickArray(W[1],this.get(O),U[E],U[L]);}return W;}};B.namespace("Plugin");B.extend(A,B.Base,I);B.Plugin.DDConstrained=A;B.mix(N,{_calcTicks:function(X,W,T,V,U){var R=((X-W)/T),S=Math.floor(R),C=Math.ceil(R);if((S!==0)||(C!==0)){if((R>=S)&&(R<=C)){X=(W+(T*S));if(V&&U){if(XU){X=(W+(T*(S-1)));}}}}return X;},_calcTickArray:function(Y,Z,X,U){var R=0,V=Z.length,T=0,S,C,W;if(!Z||(Z.length===0)){return Y;}else{if(Z[0]>=Y){return Z[0];}else{for(R=0;R=Y){S=Y-Z[R];C=Z[T]-Y;W=(C>S)?Z[R]:Z[T];if(X&&U){if(W>U){if(Z[R]){W=Z[R];}else{W=Z[V-1];}}}return W;}}return Z[Z.length-1];}}}});},"3.0.0",{requires:["dd-drag"],skinnable:false}); \ No newline at end of file diff --git a/include/javascript/yui3/build/dd/dd-constrain.js b/include/javascript/yui3/build/dd/dd-constrain.js new file mode 100644 index 00000000..fea8d72a --- /dev/null +++ b/include/javascript/yui3/build/dd/dd-constrain.js @@ -0,0 +1,29 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add('dd-constrain',function(Y){var DRAG_NODE='dragNode',OFFSET_HEIGHT='offsetHeight',OFFSET_WIDTH='offsetWidth',HOST='host',CON_2_REGION='constrain2region',CON_2_NODE='constrain2node',TICK_X_ARRAY='tickXArray',TICK_Y_ARRAY='tickYArray',DDM=Y.DD.DDM,TOP='top',RIGHT='right',BOTTOM='bottom',LEFT='left',proto=null;var C=function(config){C.superclass.constructor.apply(this,arguments);};C.NAME='DragConstrained';C.NS='con';C.ATTRS={host:{},stickX:{value:false},stickY:{value:false},tickX:{value:false},tickY:{value:false},tickXArray:{value:false},tickYArray:{value:false},constrain2region:{value:false,getter:function(r){if(Y.Lang.isObject(r)){var o={};Y.mix(o,r);return o;}else{return false;}},setter:function(r){if(Y.Lang.isObject(r)){if(Y.Lang.isNumber(r[TOP])&&Y.Lang.isNumber(r[RIGHT])&&Y.Lang.isNumber(r[LEFT])&&Y.Lang.isNumber(r[BOTTOM])){var o={};Y.mix(o,r);return o;}else{return false;}}else if(r!==false){return false;} +return r;}},gutter:{value:'0',setter:function(gutter){return Y.DD.DDM.cssSizestoObject(gutter);}},constrain2node:{value:false,setter:function(n){if(!this.get(CON_2_REGION)){var node=Y.Node.get(n);if(node){return node;}}else if(this.get(CON_2_REGION)!==false){} +return false;}},constrain2view:{value:false}};proto={initializer:function(){this.get(HOST).on('drag:start',Y.bind(this._handleStart,this));this.get(HOST).after('drag:align',Y.bind(this.align,this));},_handleStart:function(){this._regionCache=null;},_regionCache:null,_cacheRegion:function(){this._regionCache=this.get(CON_2_NODE).get('region');},getRegion:function(inc){var r={},oh=null,ow=null,g=this.get('gutter'),host=this.get(HOST);if(this.get(CON_2_NODE)){if(!this._regionCache){Y.on('resize',Y.bind(this._cacheRegion,this),window);this._cacheRegion();} +r=Y.clone(this._regionCache);}else if(this.get(CON_2_REGION)){r=this.get(CON_2_REGION);}else if(this.get('constrain2view')){r=host.get(DRAG_NODE).get('viewportRegion');}else{return false;} +Y.each(g,function(i,n){if((n==RIGHT)||(n==BOTTOM)){r[n]-=i;}else{r[n]+=i;}});if(inc){oh=host.get(DRAG_NODE).get(OFFSET_HEIGHT);ow=host.get(DRAG_NODE).get(OFFSET_WIDTH);r[RIGHT]=r[RIGHT]-ow;r[BOTTOM]=r[BOTTOM]-oh;} +return r;},_checkRegion:function(_xy){var oxy=_xy,r=this.getRegion(),host=this.get(HOST),oh=host.get(DRAG_NODE).get(OFFSET_HEIGHT),ow=host.get(DRAG_NODE).get(OFFSET_WIDTH);if(oxy[1]>(r[BOTTOM]-oh)){_xy[1]=(r[BOTTOM]-oh);} +if(r[TOP]>oxy[1]){_xy[1]=r[TOP];} +if(oxy[0]>(r[RIGHT]-ow)){_xy[0]=(r[RIGHT]-ow);} +if(r[LEFT]>oxy[0]){_xy[0]=r[LEFT];} +return _xy;},inRegion:function(xy){xy=xy||this.get(HOST).get(DRAG_NODE).getXY();var _xy=this._checkRegion([xy[0],xy[1]]),inside=false;if((xy[0]===_xy[0])&&(xy[1]===_xy[1])){inside=true;} +return inside;},align:function(){var host=this.get(HOST),_xy=host.actXY,r=this.getRegion(true);if(this.get('stickX')){_xy[1]=(host.startXY[1]-host.deltaXY[1]);} +if(this.get('stickY')){_xy[0]=(host.startXY[0]-host.deltaXY[0]);} +if(r){_xy=this._checkRegion(_xy);} +_xy=this._checkTicks(_xy,r);host.actXY=_xy;},_checkTicks:function(xy,r){var host=this.get(HOST),lx=(host.startXY[0]-host.deltaXY[0]),ly=(host.startXY[1]-host.deltaXY[1]),xt=this.get('tickX'),yt=this.get('tickY');if(xt&&!this.get(TICK_X_ARRAY)){xy[0]=DDM._calcTicks(xy[0],lx,xt,r[LEFT],r[RIGHT]);} +if(yt&&!this.get(TICK_Y_ARRAY)){xy[1]=DDM._calcTicks(xy[1],ly,yt,r[TOP],r[BOTTOM]);} +if(this.get(TICK_X_ARRAY)){xy[0]=DDM._calcTickArray(xy[0],this.get(TICK_X_ARRAY),r[LEFT],r[RIGHT]);} +if(this.get(TICK_Y_ARRAY)){xy[1]=DDM._calcTickArray(xy[1],this.get(TICK_Y_ARRAY),r[TOP],r[BOTTOM]);} +return xy;}};Y.namespace('Plugin');Y.extend(C,Y.Base,proto);Y.Plugin.DDConstrained=C;Y.mix(DDM,{_calcTicks:function(pos,start,tick,off1,off2){var ix=((pos-start)/tick),min=Math.floor(ix),max=Math.ceil(ix);if((min!==0)||(max!==0)){if((ix>=min)&&(ix<=max)){pos=(start+(tick*min));if(off1&&off2){if(posoff2){pos=(start+(tick*(min-1)));}}}} +return pos;},_calcTickArray:function(pos,ticks,off1,off2){var i=0,len=ticks.length,next=0,diff1,diff2,ret;if(!ticks||(ticks.length===0)){return pos;}else if(ticks[0]>=pos){return ticks[0];}else{for(i=0;i=pos){diff1=pos-ticks[i];diff2=ticks[next]-pos;ret=(diff2>diff1)?ticks[i]:ticks[next];if(off1&&off2){if(ret>off2){if(ticks[i]){ret=ticks[i];}else{ret=ticks[len-1];}}} +return ret;}} +return ticks[ticks.length-1];}}});},'3.0.0',{requires:['dd-drag'],skinnable:false}); \ No newline at end of file diff --git a/include/javascript/yui3/build/dd/dd-ddm-base-min.js b/include/javascript/yui3/build/dd/dd-ddm-base-min.js new file mode 100644 index 00000000..ce96cd13 --- /dev/null +++ b/include/javascript/yui3/build/dd/dd-ddm-base-min.js @@ -0,0 +1,8 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add("dd-ddm-base",function(B){var A=function(){A.superclass.constructor.apply(this,arguments);};A.NAME="ddm";A.ATTRS={dragCursor:{value:"move"},clickPixelThresh:{value:3},clickTimeThresh:{value:1000},dragMode:{value:"point",setter:function(C){this._setDragMode(C);return C;}}};B.extend(A,B.Base,{_active:null,_setDragMode:function(C){if(C===null){C=B.DD.DDM.get("dragMode");}switch(C){case 1:case"intersect":return 1;case 2:case"strict":return 2;case 0:case"point":return 0;}return 0;},CSS_PREFIX:"yui-dd",_activateTargets:function(){},_drags:[],activeDrag:false,_regDrag:function(C){if(this.getDrag(C.get("node"))){return false;}if(!this._active){this._setupListeners();}this._drags.push(C);return true;},_unregDrag:function(D){var C=[];B.each(this._drags,function(F,E){if(F!==D){C[C.length]=F;}});this._drags=C;},_setupListeners:function(){this._active=true;var C=B.get(document);C.on("mousemove",B.bind(this._move,this));C.on("mouseup",B.bind(this._end,this));},_start:function(){this.fire("ddm:start");this._startDrag();},_startDrag:function(){},_endDrag:function(){},_dropMove:function(){},_end:function(){if(this.activeDrag){this._endDrag();this.fire("ddm:end");this.activeDrag.end.call(this.activeDrag);this.activeDrag=null;}},stopDrag:function(){if(this.activeDrag){this._end();}return this;},_move:function(C){if(this.activeDrag){this.activeDrag._move.call(this.activeDrag,C);this._dropMove();}},cssSizestoObject:function(D){var C=D.split(" ");switch(C.length){case 1:C[1]=C[2]=C[3]=C[0];break;case 2:C[2]=C[0];C[3]=C[1];break;case 3:C[3]=C[1];break;}return{top:parseInt(C[0],10),right:parseInt(C[1],10),bottom:parseInt(C[2],10),left:parseInt(C[3],10)};},getDrag:function(D){var C=false,E=B.get(D);if(E instanceof B.Node){B.each(this._drags,function(G,F){if(E.compareTo(G.get("node"))){C=G;}});}return C;}});B.namespace("DD");B.DD.DDM=new A();},"3.0.0",{requires:["node","base"],skinnable:false}); \ No newline at end of file diff --git a/include/javascript/yui3/build/dd/dd-ddm-base.js b/include/javascript/yui3/build/dd/dd-ddm-base.js new file mode 100644 index 00000000..1d9af0ce --- /dev/null +++ b/include/javascript/yui3/build/dd/dd-ddm-base.js @@ -0,0 +1,15 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add('dd-ddm-base',function(Y){var DDMBase=function(){DDMBase.superclass.constructor.apply(this,arguments);};DDMBase.NAME='ddm';DDMBase.ATTRS={dragCursor:{value:'move'},clickPixelThresh:{value:3},clickTimeThresh:{value:1000},dragMode:{value:'point',setter:function(mode){this._setDragMode(mode);return mode;}}};Y.extend(DDMBase,Y.Base,{_active:null,_setDragMode:function(mode){if(mode===null){mode=Y.DD.DDM.get('dragMode');} +switch(mode){case 1:case'intersect':return 1;case 2:case'strict':return 2;case 0:case'point':return 0;} +return 0;},CSS_PREFIX:'yui-dd',_activateTargets:function(){},_drags:[],activeDrag:false,_regDrag:function(d){if(this.getDrag(d.get('node'))){return false;} +if(!this._active){this._setupListeners();} +this._drags.push(d);return true;},_unregDrag:function(d){var tmp=[];Y.each(this._drags,function(n,i){if(n!==d){tmp[tmp.length]=n;}});this._drags=tmp;},_setupListeners:function(){this._active=true;var doc=Y.get(document);doc.on('mousemove',Y.bind(this._move,this));doc.on('mouseup',Y.bind(this._end,this));},_start:function(){this.fire('ddm:start');this._startDrag();},_startDrag:function(){},_endDrag:function(){},_dropMove:function(){},_end:function(){if(this.activeDrag){this._endDrag();this.fire('ddm:end');this.activeDrag.end.call(this.activeDrag);this.activeDrag=null;}},stopDrag:function(){if(this.activeDrag){this._end();} +return this;},_move:function(ev){if(this.activeDrag){this.activeDrag._move.call(this.activeDrag,ev);this._dropMove();}},cssSizestoObject:function(gutter){var x=gutter.split(' ');switch(x.length){case 1:x[1]=x[2]=x[3]=x[0];break;case 2:x[2]=x[0];x[3]=x[1];break;case 3:x[3]=x[1];break;} +return{top:parseInt(x[0],10),right:parseInt(x[1],10),bottom:parseInt(x[2],10),left:parseInt(x[3],10)};},getDrag:function(node){var drag=false,n=Y.get(node);if(n instanceof Y.Node){Y.each(this._drags,function(v,k){if(n.compareTo(v.get('node'))){drag=v;}});} +return drag;}});Y.namespace('DD');Y.DD.DDM=new DDMBase();},'3.0.0',{requires:['node','base'],skinnable:false}); \ No newline at end of file diff --git a/include/javascript/yui3/build/dd/dd-ddm-drop-min.js b/include/javascript/yui3/build/dd/dd-ddm-drop-min.js new file mode 100644 index 00000000..0d4df2a1 --- /dev/null +++ b/include/javascript/yui3/build/dd/dd-ddm-drop-min.js @@ -0,0 +1,8 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add("dd-ddm-drop",function(A){A.mix(A.DD.DDM,{_noShim:false,_activeShims:[],_hasActiveShim:function(){if(this._noShim){return true;}return this._activeShims.length;},_addActiveShim:function(B){this._activeShims[this._activeShims.length]=B;},_removeActiveShim:function(C){var B=[];A.each(this._activeShims,function(E,D){if(E._yuid!==C._yuid){B[B.length]=E;}});this._activeShims=B;},syncActiveShims:function(B){A.later(0,this,function(C){var D=((C)?this.targets:this._lookup());A.each(D,function(F,E){F.sizeShim.call(F);},this);},B);},mode:0,POINT:0,INTERSECT:1,STRICT:2,useHash:true,activeDrop:null,validDrops:[],otherDrops:{},targets:[],_addValid:function(B){this.validDrops[this.validDrops.length]=B;return this;},_removeValid:function(B){var C=[];A.each(this.validDrops,function(E,D){if(E!==B){C[C.length]=E;}});this.validDrops=C;return this;},isOverTarget:function(C){if(this.activeDrag&&C){var F=this.activeDrag.mouseXY,E,B=this.activeDrag.get("dragMode"),D;if(F&&this.activeDrag){D=this.activeDrag.region;if(B==this.STRICT){return this.activeDrag.get("dragNode").inRegion(C.region,true,D);}else{if(C&&C.shim){if((B==this.INTERSECT)&&this._noShim){E=((D)?D:this.activeDrag.get("node"));return C.get("node").intersect(E).inRegion;}else{return C.shim.intersect({top:F[1],bottom:F[1],left:F[0],right:F[0]},C.region).inRegion;}}else{return false;}}}else{return false;}}else{return false;}},clearCache:function(){this.validDrops=[];this.otherDrops={};this._activeShims=[];},_activateTargets:function(){this.clearCache();A.each(this.targets,function(C,B){C._activateShim.apply(C,[]);},this);this._handleTargetOver();},getBestMatch:function(F,D){var C=null,E=0,B;A.each(F,function(I,H){var G=this.activeDrag.get("dragNode").intersect(I.get("node"));I.region.area=G.area;if(G.inRegion){if(G.area>E){E=G.area;C=I;}}},this);if(D){B=[];A.each(F,function(H,G){if(H!==C){B[B.length]=H;}},this);return[C,B];}else{return C;}},_deactivateTargets:function(){var B=[],C,E=this.activeDrag,D=this.activeDrop;if(E&&D&&this.otherDrops[D]){if(!E.get("dragMode")){B=this.otherDrops;delete B[D];}else{C=this.getBestMatch(this.otherDrops,true);D=C[0];B=C[1];}E.get("node").removeClass(this.CSS_PREFIX+"-drag-over");if(D){D.fire("drop:hit",{drag:E,drop:D,others:B});E.fire("drag:drophit",{drag:E,drop:D,others:B});}}else{if(E){E.get("node").removeClass(this.CSS_PREFIX+"-drag-over");E.fire("drag:dropmiss",{pageX:E.lastXY[0],pageY:E.lastXY[1]});}else{}}this.activeDrop=null;A.each(this.targets,function(G,F){G._deactivateShim.apply(G,[]);},this);},_dropMove:function(){if(this._hasActiveShim()){this._handleTargetOver();}else{A.each(this.otherDrops,function(C,B){C._handleOut.apply(C,[]);});}},_lookup:function(){if(!this.useHash||this._noShim){return this.validDrops;}var B=[];A.each(this.validDrops,function(D,C){if(D.shim&&D.shim.inViewportRegion(false,D.region)){B[B.length]=D;}});return B;},_handleTargetOver:function(){var B=this._lookup();A.each(B,function(D,C){D._handleTargetOver.call(D);},this);},_regTarget:function(B){this.targets[this.targets.length]=B;},_unregTarget:function(C){var B=[],D;A.each(this.targets,function(F,E){if(F!=C){B[B.length]=F;}},this);this.targets=B;D=[];A.each(this.validDrops,function(F,E){if(F!==C){D[D.length]=F;}});this.validDrops=D;},getDrop:function(C){var B=false,D=A.Node.get(C);if(D instanceof A.Node){A.each(this.targets,function(F,E){if(D.compareTo(F.get("node"))){B=F;}});}return B;}},true);},"3.0.0",{requires:["dd-ddm"],skinnable:false}); \ No newline at end of file diff --git a/include/javascript/yui3/build/dd/dd-ddm-drop.js b/include/javascript/yui3/build/dd/dd-ddm-drop.js new file mode 100644 index 00000000..a9c38682 --- /dev/null +++ b/include/javascript/yui3/build/dd/dd-ddm-drop.js @@ -0,0 +1,13 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add('dd-ddm-drop',function(Y){Y.mix(Y.DD.DDM,{_noShim:false,_activeShims:[],_hasActiveShim:function(){if(this._noShim){return true;} +return this._activeShims.length;},_addActiveShim:function(d){this._activeShims[this._activeShims.length]=d;},_removeActiveShim:function(d){var s=[];Y.each(this._activeShims,function(v,k){if(v._yuid!==d._yuid){s[s.length]=v;}});this._activeShims=s;},syncActiveShims:function(force){Y.later(0,this,function(force){var drops=((force)?this.targets:this._lookup());Y.each(drops,function(v,k){v.sizeShim.call(v);},this);},force);},mode:0,POINT:0,INTERSECT:1,STRICT:2,useHash:true,activeDrop:null,validDrops:[],otherDrops:{},targets:[],_addValid:function(drop){this.validDrops[this.validDrops.length]=drop;return this;},_removeValid:function(drop){var drops=[];Y.each(this.validDrops,function(v,k){if(v!==drop){drops[drops.length]=v;}});this.validDrops=drops;return this;},isOverTarget:function(drop){if(this.activeDrag&&drop){var xy=this.activeDrag.mouseXY,r,dMode=this.activeDrag.get('dragMode'),aRegion;if(xy&&this.activeDrag){aRegion=this.activeDrag.region;if(dMode==this.STRICT){return this.activeDrag.get('dragNode').inRegion(drop.region,true,aRegion);}else{if(drop&&drop.shim){if((dMode==this.INTERSECT)&&this._noShim){r=((aRegion)?aRegion:this.activeDrag.get('node'));return drop.get('node').intersect(r).inRegion;}else{return drop.shim.intersect({top:xy[1],bottom:xy[1],left:xy[0],right:xy[0]},drop.region).inRegion;}}else{return false;}}}else{return false;}}else{return false;}},clearCache:function(){this.validDrops=[];this.otherDrops={};this._activeShims=[];},_activateTargets:function(){this.clearCache();Y.each(this.targets,function(v,k){v._activateShim.apply(v,[]);},this);this._handleTargetOver();},getBestMatch:function(drops,all){var biggest=null,area=0,out;Y.each(drops,function(v,k){var inter=this.activeDrag.get('dragNode').intersect(v.get('node'));v.region.area=inter.area;if(inter.inRegion){if(inter.area>area){area=inter.area;biggest=v;}}},this);if(all){out=[];Y.each(drops,function(v,k){if(v!==biggest){out[out.length]=v;}},this);return[biggest,out];}else{return biggest;}},_deactivateTargets:function(){var other=[],tmp,activeDrag=this.activeDrag,activeDrop=this.activeDrop;if(activeDrag&&activeDrop&&this.otherDrops[activeDrop]){if(!activeDrag.get('dragMode')){other=this.otherDrops;delete other[activeDrop];}else{tmp=this.getBestMatch(this.otherDrops,true);activeDrop=tmp[0];other=tmp[1];} +activeDrag.get('node').removeClass(this.CSS_PREFIX+'-drag-over');if(activeDrop){activeDrop.fire('drop:hit',{drag:activeDrag,drop:activeDrop,others:other});activeDrag.fire('drag:drophit',{drag:activeDrag,drop:activeDrop,others:other});}}else if(activeDrag){activeDrag.get('node').removeClass(this.CSS_PREFIX+'-drag-over');activeDrag.fire('drag:dropmiss',{pageX:activeDrag.lastXY[0],pageY:activeDrag.lastXY[1]});}else{} +this.activeDrop=null;Y.each(this.targets,function(v,k){v._deactivateShim.apply(v,[]);},this);},_dropMove:function(){if(this._hasActiveShim()){this._handleTargetOver();}else{Y.each(this.otherDrops,function(v,k){v._handleOut.apply(v,[]);});}},_lookup:function(){if(!this.useHash||this._noShim){return this.validDrops;} +var drops=[];Y.each(this.validDrops,function(v,k){if(v.shim&&v.shim.inViewportRegion(false,v.region)){drops[drops.length]=v;}});return drops;},_handleTargetOver:function(){var drops=this._lookup();Y.each(drops,function(v,k){v._handleTargetOver.call(v);},this);},_regTarget:function(t){this.targets[this.targets.length]=t;},_unregTarget:function(drop){var targets=[],vdrops;Y.each(this.targets,function(v,k){if(v!=drop){targets[targets.length]=v;}},this);this.targets=targets;vdrops=[];Y.each(this.validDrops,function(v,k){if(v!==drop){vdrops[vdrops.length]=v;}});this.validDrops=vdrops;},getDrop:function(node){var drop=false,n=Y.Node.get(node);if(n instanceof Y.Node){Y.each(this.targets,function(v,k){if(n.compareTo(v.get('node'))){drop=v;}});} +return drop;}},true);},'3.0.0',{requires:['dd-ddm'],skinnable:false}); \ No newline at end of file diff --git a/include/javascript/yui3/build/dd/dd-ddm-min.js b/include/javascript/yui3/build/dd/dd-ddm-min.js new file mode 100644 index 00000000..17a42169 --- /dev/null +++ b/include/javascript/yui3/build/dd/dd-ddm-min.js @@ -0,0 +1,8 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add("dd-ddm",function(A){A.mix(A.DD.DDM,{_pg:null,_debugShim:false,_activateTargets:function(){},_deactivateTargets:function(){},_startDrag:function(){if(this.activeDrag.get("useShim")){this._pg_activate();this._activateTargets();}},_endDrag:function(){this._pg_deactivate();this._deactivateTargets();},_pg_deactivate:function(){this._pg.setStyle("display","none");},_pg_activate:function(){var B=this.activeDrag.get("activeHandle"),C="auto";if(B){C=B.getStyle("cursor");}if(C=="auto"){C=this.get("dragCursor");}this._pg_size();this._pg.setStyles({top:0,left:0,display:"block",opacity:((this._debugShim)?".5":"0"),cursor:C});},_pg_size:function(){if(this.activeDrag){var B=A.get("body"),D=B.get("docHeight"),C=B.get("docWidth");this._pg.setStyles({height:D+"px",width:C+"px"});}},_createPG:function(){var D=A.Node.create("
    "),B=A.get("body");D.setStyles({top:"0",left:"0",position:"absolute",zIndex:"9999",overflow:"hidden",backgroundColor:"red",display:"none",height:"5px",width:"5px"});D.set("id",A.stamp(D));D.addClass("yui-dd-shim");if(B.get("firstChild")){B.insertBefore(D,B.get("firstChild"));}else{B.appendChild(D);}this._pg=D;this._pg.on("mouseup",A.bind(this._end,this));this._pg.on("mousemove",A.bind(this._move,this));var C=A.get(window);A.on("window:resize",A.bind(this._pg_size,this));C.on("scroll",A.bind(this._pg_size,this));}},true);A.on("domready",A.bind(A.DD.DDM._createPG,A.DD.DDM));},"3.0.0",{requires:["dd-ddm-base","event-resize"],skinnable:false}); \ No newline at end of file diff --git a/include/javascript/yui3/build/dd/dd-ddm.js b/include/javascript/yui3/build/dd/dd-ddm.js new file mode 100644 index 00000000..9298d295 --- /dev/null +++ b/include/javascript/yui3/build/dd/dd-ddm.js @@ -0,0 +1,11 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add('dd-ddm',function(Y){Y.mix(Y.DD.DDM,{_pg:null,_debugShim:false,_activateTargets:function(){},_deactivateTargets:function(){},_startDrag:function(){if(this.activeDrag.get('useShim')){this._pg_activate();this._activateTargets();}},_endDrag:function(){this._pg_deactivate();this._deactivateTargets();},_pg_deactivate:function(){this._pg.setStyle('display','none');},_pg_activate:function(){var ah=this.activeDrag.get('activeHandle'),cur='auto';if(ah){cur=ah.getStyle('cursor');} +if(cur=='auto'){cur=this.get('dragCursor');} +this._pg_size();this._pg.setStyles({top:0,left:0,display:'block',opacity:((this._debugShim)?'.5':'0'),cursor:cur});},_pg_size:function(){if(this.activeDrag){var b=Y.get('body'),h=b.get('docHeight'),w=b.get('docWidth');this._pg.setStyles({height:h+'px',width:w+'px'});}},_createPG:function(){var pg=Y.Node.create('
    '),bd=Y.get('body');pg.setStyles({top:'0',left:'0',position:'absolute',zIndex:'9999',overflow:'hidden',backgroundColor:'red',display:'none',height:'5px',width:'5px'});pg.set('id',Y.stamp(pg));pg.addClass('yui-dd-shim');if(bd.get('firstChild')){bd.insertBefore(pg,bd.get('firstChild'));}else{bd.appendChild(pg);} +this._pg=pg;this._pg.on('mouseup',Y.bind(this._end,this));this._pg.on('mousemove',Y.bind(this._move,this));var win=Y.get(window);Y.on('window:resize',Y.bind(this._pg_size,this));win.on('scroll',Y.bind(this._pg_size,this));}},true);Y.on('domready',Y.bind(Y.DD.DDM._createPG,Y.DD.DDM));},'3.0.0',{requires:['dd-ddm-base','event-resize'],skinnable:false}); \ No newline at end of file diff --git a/include/javascript/yui3/build/dd/dd-drag-min.js b/include/javascript/yui3/build/dd/dd-drag-min.js new file mode 100644 index 00000000..1abbc05e --- /dev/null +++ b/include/javascript/yui3/build/dd/dd-drag-min.js @@ -0,0 +1,8 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add("dd-drag",function(D){var E=D.DD.DDM,U="node",G="dragging",N="dragNode",C="offsetHeight",K="offsetWidth",S="mouseup",P="mousedown",M="dragstart",H="drag:mouseDown",B="drag:afterMouseDown",F="drag:removeHandle",L="drag:addHandle",R="drag:removeInvalid",T="drag:addInvalid",J="drag:start",I="drag:end",O="drag:drag",Q="drag:align",A=function(W){this._lazyAddAttrs=false;A.superclass.constructor.apply(this,arguments);var V=E._regDrag(this);if(!V){D.error("Failed to register node, already in use: "+W.node);}};A.NAME="drag";A.ATTRS={node:{setter:function(V){var W=D.get(V);if(!W){D.error("DD.Drag: Invalid Node Given: "+V);}else{W=W.item(0);}return W;}},dragNode:{setter:function(V){var W=D.Node.get(V);if(!W){D.error("DD.Drag: Invalid dragNode Given: "+V);}return W;}},offsetNode:{value:true},clickPixelThresh:{value:E.get("clickPixelThresh")},clickTimeThresh:{value:E.get("clickTimeThresh")},lock:{value:false,setter:function(V){if(V){this.get(U).addClass(E.CSS_PREFIX+"-locked");}else{this.get(U).removeClass(E.CSS_PREFIX+"-locked");}return V;}},data:{value:false},move:{value:true},useShim:{value:true},activeHandle:{value:false},primaryButtonOnly:{value:true},dragging:{value:false},parent:{value:false},target:{value:false,setter:function(V){this._handleTarget(V);return V;}},dragMode:{value:null,setter:function(V){return E._setDragMode(V);}},groups:{value:["default"],getter:function(){if(!this._groups){this._groups={};}var V=[];D.each(this._groups,function(X,W){V[V.length]=W;});return V;},setter:function(V){this._groups={};D.each(V,function(X,W){this._groups[X]=true;},this);return V;}},handles:{value:null,setter:function(V){if(V){this._handles={};D.each(V,function(X,W){this._handles[X]=true;},this);}else{this._handles=null;}return V;}},bubbles:{writeOnce:true,value:D.DD.DDM}};D.extend(A,D.Base,{addToGroup:function(V){this._groups[V]=true;E._activateTargets();return this;},removeFromGroup:function(V){delete this._groups[V];E._activateTargets();return this;},target:null,_handleTarget:function(V){if(D.DD.Drop){if(V===false){if(this.target){E._unregTarget(this.target);this.target=null;}return false;}else{if(!D.Lang.isObject(V)){V={};}V.bubbles=("bubbles"in V)?V.bubbles:this.get("bubbles");V.node=this.get(U);V.groups=V.groups||this.get("groups");this.target=new D.DD.Drop(V);}}else{return false;}},_groups:null,_createEvents:function(){this.publish(H,{defaultFn:this._defMouseDownFn,queuable:false,emitFacade:true,bubbles:true,prefix:"drag"});this.publish(Q,{defaultFn:this._defAlignFn,queuable:false,emitFacade:true,bubbles:true,prefix:"drag"});this.publish(O,{defaultFn:this._defDragFn,queuable:false,emitFacade:true,bubbles:true,prefix:"drag"});this.publish(I,{preventedFn:this._prevEndFn,queuable:false,emitFacade:true,bubbles:true,prefix:"drag"});var V=[B,F,L,R,T,J,"drag:drophit","drag:dropmiss","drag:over","drag:enter","drag:exit"];D.each(V,function(X,W){this.publish(X,{type:X,emitFacade:true,bubbles:true,preventable:false,queuable:false,prefix:"drag"});},this);if(this.get("bubbles")){this.addTarget(this.get("bubbles"));}},_ev_md:null,_startTime:null,_endTime:null,_handles:null,_invalids:null,_invalidsDefault:{"textarea":true,"input":true,"a":true,"button":true,"select":true},_dragThreshMet:null,_fromTimeout:null,_clickTimeout:null,deltaXY:null,startXY:null,nodeXY:null,lastXY:null,actXY:null,realXY:null,mouseXY:null,region:null,_handleMouseUp:function(V){this._fixIEMouseUp();if(E.activeDrag){E._end();}},_fixDragStart:function(V){V.preventDefault();},_ieSelectFix:function(){return false;},_ieSelectBack:null,_fixIEMouseDown:function(){if(D.UA.ie){this._ieSelectBack=D.config.doc.body.onselectstart;D.config.doc.body.onselectstart=this._ieSelectFix;}},_fixIEMouseUp:function(){if(D.UA.ie){D.config.doc.body.onselectstart=this._ieSelectBack;}},_handleMouseDownEvent:function(V){this.fire(H,{ev:V});},_defMouseDownFn:function(W){var V=W.ev;this._dragThreshMet=false;this._ev_md=V;if(this.get("primaryButtonOnly")&&V.button>1){return false;}if(this.validClick(V)){this._fixIEMouseDown();V.halt();this._setStartPosition([V.pageX,V.pageY]);E.activeDrag=this;this._clickTimeout=D.later(this.get("clickTimeThresh"),this,this._timeoutCheck);}this.fire(B,{ev:V});},validClick:function(Z){var Y=false,b=false,V=Z.target,X=null,W=null,a=false;if(this._handles){D.each(this._handles,function(c,d){if(D.Lang.isString(d)){if(V.test(d+", "+d+" *")&&!X){X=d;Y=true;}}});}else{b=this.get(U);if(b.contains(V)||b.compareTo(V)){Y=true;}}if(Y){if(this._invalids){D.each(this._invalids,function(c,d){if(D.Lang.isString(d)){if(V.test(d+", "+d+" *")){Y=false;}}});}}if(Y){if(X){W=Z.currentTarget.queryAll(X);a=false;W.each(function(d,c){if((d.contains(V)||d.compareTo(V))&&!a){a=true;this.set("activeHandle",d);}},this);}else{this.set("activeHandle",this.get(U));}}return Y;},_setStartPosition:function(V){this.startXY=V;this.nodeXY=this.lastXY=this.realXY=this.get(U).getXY();if(this.get("offsetNode")){this.deltaXY=[(this.startXY[0]-this.nodeXY[0]),(this.startXY[1]-this.nodeXY[1])];}else{this.deltaXY=[0,0];}},_timeoutCheck:function(){if(!this.get("lock")&&!this._dragThreshMet){this._fromTimeout=this._dragThreshMet=true;this.start();this._alignNode([this._ev_md.pageX,this._ev_md.pageY],true);}},removeHandle:function(V){if(this._handles[V]){delete this._handles[V];this.fire(F,{handle:V});}return this;},addHandle:function(V){if(!this._handles){this._handles={};}if(D.Lang.isString(V)){this._handles[V]=true;this.fire(L,{handle:V});}return this;},removeInvalid:function(V){if(this._invalids[V]){this._invalids[V]=null;delete this._invalids[V];this.fire(R,{handle:V});}return this;},addInvalid:function(V){if(D.Lang.isString(V)){this._invalids[V]=true;this.fire(T,{handle:V});}return this;},initializer:function(){this.get(U).dd=this;if(!this.get(U).get("id")){var V=D.stamp(this.get(U));this.get(U).set("id",V);}this.actXY=[];this._invalids=D.clone(this._invalidsDefault,true);this._createEvents();if(!this.get(N)){this.set(N,this.get(U));}this.on("initializedChange",D.bind(this._prep,this));this.set("groups",this.get("groups"));},_prep:function(){this._dragThreshMet=false;var V=this.get(U);V.addClass(E.CSS_PREFIX+"-draggable");V.on(P,D.bind(this._handleMouseDownEvent,this));V.on(S,D.bind(this._handleMouseUp,this));V.on(M,D.bind(this._fixDragStart,this));},_unprep:function(){var V=this.get(U);V.removeClass(E.CSS_PREFIX+"-draggable");V.detachAll();},start:function(){if(!this.get("lock")&&!this.get(G)){var W=this.get(U),V=W.get(K),X=W.get(C);this._startTime=(new Date()).getTime();E._start();W.addClass(E.CSS_PREFIX+"-dragging");this.fire(J,{pageX:this.nodeXY[0],pageY:this.nodeXY[1],startTime:this._startTime});var Y=this.nodeXY;this.region={"0":Y[0],"1":Y[1],area:0,top:Y[1],right:Y[0]+V,bottom:Y[1]+X,left:Y[0]};this.set(G,true);}return this;},end:function(){this._endTime=(new Date()).getTime();if(this._clickTimeout){this._clickTimeout.cancel();}this._dragThreshMet=false;this._fromTimeout=false;if(!this.get("lock")&&this.get(G)){this.fire(I,{pageX:this.lastXY[0],pageY:this.lastXY[1],startTime:this._startTime,endTime:this._endTime});}this.get(U).removeClass(E.CSS_PREFIX+"-dragging");this.set(G,false);this.deltaXY=[0,0];return this;},_prevEndFn:function(V){this.get(N).setXY(this.nodeXY);},_align:function(V){this.fire(Q,{pageX:V[0],pageY:V[1]});},_defAlignFn:function(V){this.actXY=[V.pageX-this.deltaXY[0],V.pageY-this.deltaXY[1]];},_alignNode:function(V){this._align(V);this._moveNode();},_moveNode:function(V){var W=[],X=[],Z=this.nodeXY,Y=this.actXY;W[0]=(Y[0]-this.lastXY[0]);W[1]=(Y[1]-this.lastXY[1]);X[0]=(Y[0]-this.nodeXY[0]);X[1]=(Y[1]-this.nodeXY[1]);this.region={"0":Y[0],"1":Y[1],area:0,top:Y[1],right:Y[0]+this.get(N).get(K),bottom:Y[1]+this.get(N).get(C),left:Y[0]};this.fire(O,{pageX:Y[0],pageY:Y[1],scroll:V,info:{start:Z,xy:Y,delta:W,offset:X}});this.lastXY=Y;},_defDragFn:function(V){if(this.get("move")){if(V.scroll){V.scroll.node.set("scrollTop",V.scroll.top);V.scroll.node.set("scrollLeft",V.scroll.left);}this.get(N).setXY([V.pageX,V.pageY]);this.realXY=[V.pageX,V.pageY];}},_move:function(X){if(this.get("lock")){return false;}else{this.mouseXY=[X.pageX,X.pageY];if(!this._dragThreshMet){var W=Math.abs(this.startXY[0]-X.pageX),V=Math.abs(this.startXY[1]-X.pageY);if(W>this.get("clickPixelThresh")||V>this.get("clickPixelThresh")){this._dragThreshMet=true;this.start();this._alignNode([X.pageX,X.pageY]);}}else{if(this._clickTimeout){this._clickTimeout.cancel();}this._alignNode([X.pageX,X.pageY]);}}},stopDrag:function(){if(this.get(G)){E._end();}return this;},destructor:function(){this._unprep();this.detachAll();if(this.target){this.target.destroy();}E._unregDrag(this);}});D.namespace("DD");D.DD.Drag=A;},"3.0.0",{requires:["dd-ddm-base"],skinnable:false}); \ No newline at end of file diff --git a/include/javascript/yui3/build/dd/dd-drag.js b/include/javascript/yui3/build/dd/dd-drag.js new file mode 100644 index 00000000..ca352131 --- /dev/null +++ b/include/javascript/yui3/build/dd/dd-drag.js @@ -0,0 +1,35 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add('dd-drag',function(Y){var DDM=Y.DD.DDM,NODE='node',DRAGGING='dragging',DRAG_NODE='dragNode',OFFSET_HEIGHT='offsetHeight',OFFSET_WIDTH='offsetWidth',MOUSE_UP='mouseup',MOUSE_DOWN='mousedown',DRAG_START='dragstart',EV_MOUSE_DOWN='drag:mouseDown',EV_AFTER_MOUSE_DOWN='drag:afterMouseDown',EV_REMOVE_HANDLE='drag:removeHandle',EV_ADD_HANDLE='drag:addHandle',EV_REMOVE_INVALID='drag:removeInvalid',EV_ADD_INVALID='drag:addInvalid',EV_START='drag:start',EV_END='drag:end',EV_DRAG='drag:drag',EV_ALIGN='drag:align',Drag=function(o){this._lazyAddAttrs=false;Drag.superclass.constructor.apply(this,arguments);var valid=DDM._regDrag(this);if(!valid){Y.error('Failed to register node, already in use: '+o.node);}};Drag.NAME='drag';Drag.ATTRS={node:{setter:function(node){var n=Y.get(node);if(!n){Y.error('DD.Drag: Invalid Node Given: '+node);}else{n=n.item(0);} +return n;}},dragNode:{setter:function(node){var n=Y.Node.get(node);if(!n){Y.error('DD.Drag: Invalid dragNode Given: '+node);} +return n;}},offsetNode:{value:true},clickPixelThresh:{value:DDM.get('clickPixelThresh')},clickTimeThresh:{value:DDM.get('clickTimeThresh')},lock:{value:false,setter:function(lock){if(lock){this.get(NODE).addClass(DDM.CSS_PREFIX+'-locked');}else{this.get(NODE).removeClass(DDM.CSS_PREFIX+'-locked');} +return lock;}},data:{value:false},move:{value:true},useShim:{value:true},activeHandle:{value:false},primaryButtonOnly:{value:true},dragging:{value:false},parent:{value:false},target:{value:false,setter:function(config){this._handleTarget(config);return config;}},dragMode:{value:null,setter:function(mode){return DDM._setDragMode(mode);}},groups:{value:['default'],getter:function(){if(!this._groups){this._groups={};} +var ret=[];Y.each(this._groups,function(v,k){ret[ret.length]=k;});return ret;},setter:function(g){this._groups={};Y.each(g,function(v,k){this._groups[v]=true;},this);return g;}},handles:{value:null,setter:function(g){if(g){this._handles={};Y.each(g,function(v,k){this._handles[v]=true;},this);}else{this._handles=null;} +return g;}},bubbles:{writeOnce:true,value:Y.DD.DDM}};Y.extend(Drag,Y.Base,{addToGroup:function(g){this._groups[g]=true;DDM._activateTargets();return this;},removeFromGroup:function(g){delete this._groups[g];DDM._activateTargets();return this;},target:null,_handleTarget:function(config){if(Y.DD.Drop){if(config===false){if(this.target){DDM._unregTarget(this.target);this.target=null;} +return false;}else{if(!Y.Lang.isObject(config)){config={};} +config.bubbles=('bubbles'in config)?config.bubbles:this.get('bubbles');config.node=this.get(NODE);config.groups=config.groups||this.get('groups');this.target=new Y.DD.Drop(config);}}else{return false;}},_groups:null,_createEvents:function(){this.publish(EV_MOUSE_DOWN,{defaultFn:this._defMouseDownFn,queuable:false,emitFacade:true,bubbles:true,prefix:'drag'});this.publish(EV_ALIGN,{defaultFn:this._defAlignFn,queuable:false,emitFacade:true,bubbles:true,prefix:'drag'});this.publish(EV_DRAG,{defaultFn:this._defDragFn,queuable:false,emitFacade:true,bubbles:true,prefix:'drag'});this.publish(EV_END,{preventedFn:this._prevEndFn,queuable:false,emitFacade:true,bubbles:true,prefix:'drag'});var ev=[EV_AFTER_MOUSE_DOWN,EV_REMOVE_HANDLE,EV_ADD_HANDLE,EV_REMOVE_INVALID,EV_ADD_INVALID,EV_START,'drag:drophit','drag:dropmiss','drag:over','drag:enter','drag:exit'];Y.each(ev,function(v,k){this.publish(v,{type:v,emitFacade:true,bubbles:true,preventable:false,queuable:false,prefix:'drag'});},this);if(this.get('bubbles')){this.addTarget(this.get('bubbles'));}},_ev_md:null,_startTime:null,_endTime:null,_handles:null,_invalids:null,_invalidsDefault:{'textarea':true,'input':true,'a':true,'button':true,'select':true},_dragThreshMet:null,_fromTimeout:null,_clickTimeout:null,deltaXY:null,startXY:null,nodeXY:null,lastXY:null,actXY:null,realXY:null,mouseXY:null,region:null,_handleMouseUp:function(ev){this._fixIEMouseUp();if(DDM.activeDrag){DDM._end();}},_fixDragStart:function(e){e.preventDefault();},_ieSelectFix:function(){return false;},_ieSelectBack:null,_fixIEMouseDown:function(){if(Y.UA.ie){this._ieSelectBack=Y.config.doc.body.onselectstart;Y.config.doc.body.onselectstart=this._ieSelectFix;}},_fixIEMouseUp:function(){if(Y.UA.ie){Y.config.doc.body.onselectstart=this._ieSelectBack;}},_handleMouseDownEvent:function(ev){this.fire(EV_MOUSE_DOWN,{ev:ev});},_defMouseDownFn:function(e){var ev=e.ev;this._dragThreshMet=false;this._ev_md=ev;if(this.get('primaryButtonOnly')&&ev.button>1){return false;} +if(this.validClick(ev)){this._fixIEMouseDown();ev.halt();this._setStartPosition([ev.pageX,ev.pageY]);DDM.activeDrag=this;this._clickTimeout=Y.later(this.get('clickTimeThresh'),this,this._timeoutCheck);} +this.fire(EV_AFTER_MOUSE_DOWN,{ev:ev});},validClick:function(ev){var r=false,n=false,tar=ev.target,hTest=null,els=null,set=false;if(this._handles){Y.each(this._handles,function(i,n){if(Y.Lang.isString(n)){if(tar.test(n+', '+n+' *')&&!hTest){hTest=n;r=true;}}});}else{n=this.get(NODE) +if(n.contains(tar)||n.compareTo(tar)){r=true;}} +if(r){if(this._invalids){Y.each(this._invalids,function(i,n){if(Y.Lang.isString(n)){if(tar.test(n+', '+n+' *')){r=false;}}});}} +if(r){if(hTest){els=ev.currentTarget.queryAll(hTest);set=false;els.each(function(n,i){if((n.contains(tar)||n.compareTo(tar))&&!set){set=true;this.set('activeHandle',n);}},this);}else{this.set('activeHandle',this.get(NODE));}} +return r;},_setStartPosition:function(xy){this.startXY=xy;this.nodeXY=this.lastXY=this.realXY=this.get(NODE).getXY();if(this.get('offsetNode')){this.deltaXY=[(this.startXY[0]-this.nodeXY[0]),(this.startXY[1]-this.nodeXY[1])];}else{this.deltaXY=[0,0];}},_timeoutCheck:function(){if(!this.get('lock')&&!this._dragThreshMet){this._fromTimeout=this._dragThreshMet=true;this.start();this._alignNode([this._ev_md.pageX,this._ev_md.pageY],true);}},removeHandle:function(str){if(this._handles[str]){delete this._handles[str];this.fire(EV_REMOVE_HANDLE,{handle:str});} +return this;},addHandle:function(str){if(!this._handles){this._handles={};} +if(Y.Lang.isString(str)){this._handles[str]=true;this.fire(EV_ADD_HANDLE,{handle:str});} +return this;},removeInvalid:function(str){if(this._invalids[str]){this._invalids[str]=null;delete this._invalids[str];this.fire(EV_REMOVE_INVALID,{handle:str});} +return this;},addInvalid:function(str){if(Y.Lang.isString(str)){this._invalids[str]=true;this.fire(EV_ADD_INVALID,{handle:str});} +return this;},initializer:function(){this.get(NODE).dd=this;if(!this.get(NODE).get('id')){var id=Y.stamp(this.get(NODE));this.get(NODE).set('id',id);} +this.actXY=[];this._invalids=Y.clone(this._invalidsDefault,true);this._createEvents();if(!this.get(DRAG_NODE)){this.set(DRAG_NODE,this.get(NODE));} +this.on('initializedChange',Y.bind(this._prep,this));this.set('groups',this.get('groups'));},_prep:function(){this._dragThreshMet=false;var node=this.get(NODE);node.addClass(DDM.CSS_PREFIX+'-draggable');node.on(MOUSE_DOWN,Y.bind(this._handleMouseDownEvent,this));node.on(MOUSE_UP,Y.bind(this._handleMouseUp,this));node.on(DRAG_START,Y.bind(this._fixDragStart,this));},_unprep:function(){var node=this.get(NODE);node.removeClass(DDM.CSS_PREFIX+'-draggable');node.detachAll();},start:function(){if(!this.get('lock')&&!this.get(DRAGGING)){var node=this.get(NODE),ow=node.get(OFFSET_WIDTH),oh=node.get(OFFSET_HEIGHT);this._startTime=(new Date()).getTime();DDM._start();node.addClass(DDM.CSS_PREFIX+'-dragging');this.fire(EV_START,{pageX:this.nodeXY[0],pageY:this.nodeXY[1],startTime:this._startTime});var xy=this.nodeXY;this.region={'0':xy[0],'1':xy[1],area:0,top:xy[1],right:xy[0]+ow,bottom:xy[1]+oh,left:xy[0]};this.set(DRAGGING,true);} +return this;},end:function(){this._endTime=(new Date()).getTime();if(this._clickTimeout){this._clickTimeout.cancel();} +this._dragThreshMet=false;this._fromTimeout=false;if(!this.get('lock')&&this.get(DRAGGING)){this.fire(EV_END,{pageX:this.lastXY[0],pageY:this.lastXY[1],startTime:this._startTime,endTime:this._endTime});} +this.get(NODE).removeClass(DDM.CSS_PREFIX+'-dragging');this.set(DRAGGING,false);this.deltaXY=[0,0];return this;},_prevEndFn:function(e){this.get(DRAG_NODE).setXY(this.nodeXY);},_align:function(xy){this.fire(EV_ALIGN,{pageX:xy[0],pageY:xy[1]});},_defAlignFn:function(e){this.actXY=[e.pageX-this.deltaXY[0],e.pageY-this.deltaXY[1]];},_alignNode:function(eXY){this._align(eXY);this._moveNode();},_moveNode:function(scroll){var diffXY=[],diffXY2=[],startXY=this.nodeXY,xy=this.actXY;diffXY[0]=(xy[0]-this.lastXY[0]);diffXY[1]=(xy[1]-this.lastXY[1]);diffXY2[0]=(xy[0]-this.nodeXY[0]);diffXY2[1]=(xy[1]-this.nodeXY[1]);this.region={'0':xy[0],'1':xy[1],area:0,top:xy[1],right:xy[0]+this.get(DRAG_NODE).get(OFFSET_WIDTH),bottom:xy[1]+this.get(DRAG_NODE).get(OFFSET_HEIGHT),left:xy[0]};this.fire(EV_DRAG,{pageX:xy[0],pageY:xy[1],scroll:scroll,info:{start:startXY,xy:xy,delta:diffXY,offset:diffXY2}});this.lastXY=xy;},_defDragFn:function(e){if(this.get('move')){if(e.scroll){e.scroll.node.set('scrollTop',e.scroll.top);e.scroll.node.set('scrollLeft',e.scroll.left);} +this.get(DRAG_NODE).setXY([e.pageX,e.pageY]);this.realXY=[e.pageX,e.pageY];}},_move:function(ev){if(this.get('lock')){return false;}else{this.mouseXY=[ev.pageX,ev.pageY];if(!this._dragThreshMet){var diffX=Math.abs(this.startXY[0]-ev.pageX),diffY=Math.abs(this.startXY[1]-ev.pageY);if(diffX>this.get('clickPixelThresh')||diffY>this.get('clickPixelThresh')){this._dragThreshMet=true;this.start();this._alignNode([ev.pageX,ev.pageY]);}}else{if(this._clickTimeout){this._clickTimeout.cancel();} +this._alignNode([ev.pageX,ev.pageY]);}}},stopDrag:function(){if(this.get(DRAGGING)){DDM._end();} +return this;},destructor:function(){this._unprep();this.detachAll();if(this.target){this.target.destroy();} +DDM._unregDrag(this);}});Y.namespace('DD');Y.DD.Drag=Drag;},'3.0.0',{requires:['dd-ddm-base'],skinnable:false}); \ No newline at end of file diff --git a/include/javascript/yui3/build/dd/dd-drop-min.js b/include/javascript/yui3/build/dd/dd-drop-min.js new file mode 100644 index 00000000..5f2aa126 --- /dev/null +++ b/include/javascript/yui3/build/dd/dd-drop-min.js @@ -0,0 +1,8 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add("dd-drop",function(A){var B="node",G=A.DD.DDM,F="offsetHeight",C="offsetWidth",I="drop:over",H="drop:enter",D="drop:exit",E=function(){this._lazyAddAttrs=false;E.superclass.constructor.apply(this,arguments);A.on("domready",A.bind(function(){A.later(100,this,this._createShim);},this));G._regTarget(this);};E.NAME="drop";E.ATTRS={node:{setter:function(J){var K=A.Node.get(J);if(!K){A.error("DD.Drop: Invalid Node Given: "+J);}return K;}},groups:{value:["default"],setter:function(J){this._groups={};A.each(J,function(L,K){this._groups[L]=true;},this);return J;}},padding:{value:"0",setter:function(J){return G.cssSizestoObject(J);}},lock:{value:false,setter:function(J){if(J){this.get(B).addClass(G.CSS_PREFIX+"-drop-locked");}else{this.get(B).removeClass(G.CSS_PREFIX+"-drop-locked");}return J;}},bubbles:{writeOnce:true,value:A.DD.DDM}};A.extend(E,A.Base,{_createEvents:function(){var J=[I,H,D,"drop:hit"];A.each(J,function(L,K){this.publish(L,{type:L,emitFacade:true,preventable:false,bubbles:true,queuable:false,prefix:"drop"});},this);if(this.get("bubbles")){this.addTarget(this.get("bubbles"));}},_valid:null,_groups:null,shim:null,region:null,overTarget:null,inGroup:function(J){this._valid=false;var K=false;A.each(J,function(M,L){if(this._groups[M]){K=true;this._valid=true;}},this);return K;},initializer:function(){A.later(100,this,this._createEvents);var J=this.get(B),K;if(!J.get("id")){K=A.stamp(J);J.set("id",K);}J.addClass(G.CSS_PREFIX+"-drop");this.set("groups",this.get("groups"));},destructor:function(){G._unregTarget(this);if(this.shim){this.shim.detachAll();this.shim.get("parentNode").removeChild(this.shim);this.shim=null;}this.get(B).removeClass(G.CSS_PREFIX+"-drop");this.detachAll();},_deactivateShim:function(){if(!this.shim){return false;}this.get(B).removeClass(G.CSS_PREFIX+"-drop-active-valid");this.get(B).removeClass(G.CSS_PREFIX+"-drop-active-invalid");this.get(B).removeClass(G.CSS_PREFIX+"-drop-over");this.shim.setStyles({top:"-999px",left:"-999px",zIndex:"1"});this.overTarget=false;},_activateShim:function(){if(!G.activeDrag){return false;}if(this.get(B)===G.activeDrag.get(B)){return false;}if(this.get("lock")){return false;}var J=this.get(B);if(this.inGroup(G.activeDrag.get("groups"))){J.removeClass(G.CSS_PREFIX+"-drop-active-invalid");J.addClass(G.CSS_PREFIX+"-drop-active-valid");G._addValid(this);this.overTarget=false;this.sizeShim();}else{G._removeValid(this);J.removeClass(G.CSS_PREFIX+"-drop-active-valid");J.addClass(G.CSS_PREFIX+"-drop-active-invalid");}},sizeShim:function(){if(!G.activeDrag){return false;}if(this.get(B)===G.activeDrag.get(B)){return false;}if(this.get("lock")){return false;}if(!this.shim){A.later(100,this,this.sizeShim);return false;}var O=this.get(B),M=O.get(F),K=O.get(C),Q=O.getXY(),P=this.get("padding"),J,N,L;K=K+P.left+P.right;M=M+P.top+P.bottom;Q[0]=Q[0]-P.left;Q[1]=Q[1]-P.top;if(G.activeDrag.get("dragMode")===G.INTERSECT){J=G.activeDrag;N=J.get(B).get(F);L=J.get(B).get(C);M=(M+N);K=(K+L);Q[0]=Q[0]-(L-J.deltaXY[0]);Q[1]=Q[1]-(N-J.deltaXY[1]);}this.shim.setStyles({height:M+"px",width:K+"px",top:Q[1]+"px",left:Q[0]+"px"});this.region={"0":Q[0],"1":Q[1],area:0,top:Q[1],right:Q[0]+K,bottom:Q[1]+M,left:Q[0]};},_createShim:function(){if(!G._pg){A.later(10,this,this._createShim);return;}if(this.shim){return;}var J=A.Node.create('
    ');J.setStyles({height:this.get(B).get(F)+"px",width:this.get(B).get(C)+"px",backgroundColor:"yellow",opacity:".5",zIndex:"1",overflow:"hidden",top:"-900px",left:"-900px",position:"absolute"});G._pg.appendChild(J);this.shim=J;J.on("mouseover",A.bind(this._handleOverEvent,this));J.on("mouseout",A.bind(this._handleOutEvent,this));},_handleTargetOver:function(){if(G.isOverTarget(this)){this.get(B).addClass(G.CSS_PREFIX+"-drop-over");G.activeDrop=this;G.otherDrops[this]=this;if(this.overTarget){G.activeDrag.fire("drag:over",{drop:this,drag:G.activeDrag});this.fire(I,{drop:this,drag:G.activeDrag});}else{this.overTarget=true;this.fire(H,{drop:this,drag:G.activeDrag});G.activeDrag.fire("drag:enter",{drop:this,drag:G.activeDrag});G.activeDrag.get(B).addClass(G.CSS_PREFIX+"-drag-over");}}else{this._handleOut();}},_handleOverEvent:function(){this.shim.setStyle("zIndex","999");G._addActiveShim(this);},_handleOutEvent:function(){this.shim.setStyle("zIndex","1");G._removeActiveShim(this);},_handleOut:function(J){if(!G.isOverTarget(this)||J){if(this.overTarget){this.overTarget=false;if(!J){G._removeActiveShim(this);}if(G.activeDrag){this.get(B).removeClass(G.CSS_PREFIX+"-drop-over");G.activeDrag.get(B).removeClass(G.CSS_PREFIX+"-drag-over");this.fire(D);G.activeDrag.fire("drag:exit",{drop:this});delete G.otherDrops[this];}}}}});A.DD.Drop=E;},"3.0.0",{requires:["dd-ddm-drop","dd-drag"],skinnable:false}); \ No newline at end of file diff --git a/include/javascript/yui3/build/dd/dd-drop-plugin-min.js b/include/javascript/yui3/build/dd/dd-drop-plugin-min.js new file mode 100644 index 00000000..b8b8bdd4 --- /dev/null +++ b/include/javascript/yui3/build/dd/dd-drop-plugin-min.js @@ -0,0 +1,8 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add("dd-drop-plugin",function(A){var B=function(C){C.node=C.host;B.superclass.constructor.apply(this,arguments);};B.NAME="dd-drop-plugin";B.NS="drop";A.extend(B,A.DD.Drop);A.namespace("Plugin");A.Plugin.Drop=B;},"3.0.0",{requires:["dd-drop"],skinnable:false}); \ No newline at end of file diff --git a/include/javascript/yui3/build/dd/dd-drop-plugin.js b/include/javascript/yui3/build/dd/dd-drop-plugin.js new file mode 100644 index 00000000..6f9d5fde --- /dev/null +++ b/include/javascript/yui3/build/dd/dd-drop-plugin.js @@ -0,0 +1,8 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add('dd-drop-plugin',function(Y){var Drop=function(config){config.node=config.host;Drop.superclass.constructor.apply(this,arguments);};Drop.NAME="dd-drop-plugin";Drop.NS="drop";Y.extend(Drop,Y.DD.Drop);Y.namespace('Plugin');Y.Plugin.Drop=Drop;},'3.0.0',{requires:['dd-drop'],skinnable:false}); \ No newline at end of file diff --git a/include/javascript/yui3/build/dd/dd-drop.js b/include/javascript/yui3/build/dd/dd-drop.js new file mode 100644 index 00000000..d16c7216 --- /dev/null +++ b/include/javascript/yui3/build/dd/dd-drop.js @@ -0,0 +1,24 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add('dd-drop',function(Y){var NODE='node',DDM=Y.DD.DDM,OFFSET_HEIGHT='offsetHeight',OFFSET_WIDTH='offsetWidth',EV_DROP_OVER='drop:over',EV_DROP_ENTER='drop:enter',EV_DROP_EXIT='drop:exit',Drop=function(){this._lazyAddAttrs=false;Drop.superclass.constructor.apply(this,arguments);Y.on('domready',Y.bind(function(){Y.later(100,this,this._createShim);},this));DDM._regTarget(this);};Drop.NAME='drop';Drop.ATTRS={node:{setter:function(node){var n=Y.Node.get(node);if(!n){Y.error('DD.Drop: Invalid Node Given: '+node);} +return n;}},groups:{value:['default'],setter:function(g){this._groups={};Y.each(g,function(v,k){this._groups[v]=true;},this);return g;}},padding:{value:'0',setter:function(p){return DDM.cssSizestoObject(p);}},lock:{value:false,setter:function(lock){if(lock){this.get(NODE).addClass(DDM.CSS_PREFIX+'-drop-locked');}else{this.get(NODE).removeClass(DDM.CSS_PREFIX+'-drop-locked');} +return lock;}},bubbles:{writeOnce:true,value:Y.DD.DDM}};Y.extend(Drop,Y.Base,{_createEvents:function(){var ev=[EV_DROP_OVER,EV_DROP_ENTER,EV_DROP_EXIT,'drop:hit'];Y.each(ev,function(v,k){this.publish(v,{type:v,emitFacade:true,preventable:false,bubbles:true,queuable:false,prefix:'drop'});},this);if(this.get('bubbles')){this.addTarget(this.get('bubbles'));}},_valid:null,_groups:null,shim:null,region:null,overTarget:null,inGroup:function(groups){this._valid=false;var ret=false;Y.each(groups,function(v,k){if(this._groups[v]){ret=true;this._valid=true;}},this);return ret;},initializer:function(){Y.later(100,this,this._createEvents);var node=this.get(NODE),id;if(!node.get('id')){id=Y.stamp(node);node.set('id',id);} +node.addClass(DDM.CSS_PREFIX+'-drop');this.set('groups',this.get('groups'));},destructor:function(){DDM._unregTarget(this);if(this.shim){this.shim.detachAll();this.shim.get('parentNode').removeChild(this.shim);this.shim=null;} +this.get(NODE).removeClass(DDM.CSS_PREFIX+'-drop');this.detachAll();},_deactivateShim:function(){if(!this.shim){return false;} +this.get(NODE).removeClass(DDM.CSS_PREFIX+'-drop-active-valid');this.get(NODE).removeClass(DDM.CSS_PREFIX+'-drop-active-invalid');this.get(NODE).removeClass(DDM.CSS_PREFIX+'-drop-over');this.shim.setStyles({top:'-999px',left:'-999px',zIndex:'1'});this.overTarget=false;},_activateShim:function(){if(!DDM.activeDrag){return false;} +if(this.get(NODE)===DDM.activeDrag.get(NODE)){return false;} +if(this.get('lock')){return false;} +var node=this.get(NODE);if(this.inGroup(DDM.activeDrag.get('groups'))){node.removeClass(DDM.CSS_PREFIX+'-drop-active-invalid');node.addClass(DDM.CSS_PREFIX+'-drop-active-valid');DDM._addValid(this);this.overTarget=false;this.sizeShim();}else{DDM._removeValid(this);node.removeClass(DDM.CSS_PREFIX+'-drop-active-valid');node.addClass(DDM.CSS_PREFIX+'-drop-active-invalid');}},sizeShim:function(){if(!DDM.activeDrag){return false;} +if(this.get(NODE)===DDM.activeDrag.get(NODE)){return false;} +if(this.get('lock')){return false;} +if(!this.shim){Y.later(100,this,this.sizeShim);return false;} +var node=this.get(NODE),nh=node.get(OFFSET_HEIGHT),nw=node.get(OFFSET_WIDTH),xy=node.getXY(),p=this.get('padding'),dd,dH,dW;nw=nw+p.left+p.right;nh=nh+p.top+p.bottom;xy[0]=xy[0]-p.left;xy[1]=xy[1]-p.top;if(DDM.activeDrag.get('dragMode')===DDM.INTERSECT){dd=DDM.activeDrag;dH=dd.get(NODE).get(OFFSET_HEIGHT);dW=dd.get(NODE).get(OFFSET_WIDTH);nh=(nh+dH);nw=(nw+dW);xy[0]=xy[0]-(dW-dd.deltaXY[0]);xy[1]=xy[1]-(dH-dd.deltaXY[1]);} +this.shim.setStyles({height:nh+'px',width:nw+'px',top:xy[1]+'px',left:xy[0]+'px'});this.region={'0':xy[0],'1':xy[1],area:0,top:xy[1],right:xy[0]+nw,bottom:xy[1]+nh,left:xy[0]};},_createShim:function(){if(!DDM._pg){Y.later(10,this,this._createShim);return;} +if(this.shim){return;} +var s=Y.Node.create('
    ');s.setStyles({height:this.get(NODE).get(OFFSET_HEIGHT)+'px',width:this.get(NODE).get(OFFSET_WIDTH)+'px',backgroundColor:'yellow',opacity:'.5',zIndex:'1',overflow:'hidden',top:'-900px',left:'-900px',position:'absolute'});DDM._pg.appendChild(s);this.shim=s;s.on('mouseover',Y.bind(this._handleOverEvent,this));s.on('mouseout',Y.bind(this._handleOutEvent,this));},_handleTargetOver:function(){if(DDM.isOverTarget(this)){this.get(NODE).addClass(DDM.CSS_PREFIX+'-drop-over');DDM.activeDrop=this;DDM.otherDrops[this]=this;if(this.overTarget){DDM.activeDrag.fire('drag:over',{drop:this,drag:DDM.activeDrag});this.fire(EV_DROP_OVER,{drop:this,drag:DDM.activeDrag});}else{this.overTarget=true;this.fire(EV_DROP_ENTER,{drop:this,drag:DDM.activeDrag});DDM.activeDrag.fire('drag:enter',{drop:this,drag:DDM.activeDrag});DDM.activeDrag.get(NODE).addClass(DDM.CSS_PREFIX+'-drag-over');}}else{this._handleOut();}},_handleOverEvent:function(){this.shim.setStyle('zIndex','999');DDM._addActiveShim(this);},_handleOutEvent:function(){this.shim.setStyle('zIndex','1');DDM._removeActiveShim(this);},_handleOut:function(force){if(!DDM.isOverTarget(this)||force){if(this.overTarget){this.overTarget=false;if(!force){DDM._removeActiveShim(this);} +if(DDM.activeDrag){this.get(NODE).removeClass(DDM.CSS_PREFIX+'-drop-over');DDM.activeDrag.get(NODE).removeClass(DDM.CSS_PREFIX+'-drag-over');this.fire(EV_DROP_EXIT);DDM.activeDrag.fire('drag:exit',{drop:this});delete DDM.otherDrops[this];}}}}});Y.DD.Drop=Drop;},'3.0.0',{requires:['dd-ddm-drop','dd-drag'],skinnable:false}); \ No newline at end of file diff --git a/include/javascript/yui3/build/dd/dd-min.js b/include/javascript/yui3/build/dd/dd-min.js new file mode 100644 index 00000000..ebf6f5b6 --- /dev/null +++ b/include/javascript/yui3/build/dd/dd-min.js @@ -0,0 +1,8 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add("dd-ddm-base",function(B){var A=function(){A.superclass.constructor.apply(this,arguments);};A.NAME="ddm";A.ATTRS={dragCursor:{value:"move"},clickPixelThresh:{value:3},clickTimeThresh:{value:1000},dragMode:{value:"point",setter:function(C){this._setDragMode(C);return C;}}};B.extend(A,B.Base,{_active:null,_setDragMode:function(C){if(C===null){C=B.DD.DDM.get("dragMode");}switch(C){case 1:case"intersect":return 1;case 2:case"strict":return 2;case 0:case"point":return 0;}return 0;},CSS_PREFIX:"yui-dd",_activateTargets:function(){},_drags:[],activeDrag:false,_regDrag:function(C){if(this.getDrag(C.get("node"))){return false;}if(!this._active){this._setupListeners();}this._drags.push(C);return true;},_unregDrag:function(D){var C=[];B.each(this._drags,function(F,E){if(F!==D){C[C.length]=F;}});this._drags=C;},_setupListeners:function(){this._active=true;var C=B.get(document);C.on("mousemove",B.bind(this._move,this));C.on("mouseup",B.bind(this._end,this));},_start:function(){this.fire("ddm:start");this._startDrag();},_startDrag:function(){},_endDrag:function(){},_dropMove:function(){},_end:function(){if(this.activeDrag){this._endDrag();this.fire("ddm:end");this.activeDrag.end.call(this.activeDrag);this.activeDrag=null;}},stopDrag:function(){if(this.activeDrag){this._end();}return this;},_move:function(C){if(this.activeDrag){this.activeDrag._move.call(this.activeDrag,C);this._dropMove();}},cssSizestoObject:function(D){var C=D.split(" ");switch(C.length){case 1:C[1]=C[2]=C[3]=C[0];break;case 2:C[2]=C[0];C[3]=C[1];break;case 3:C[3]=C[1];break;}return{top:parseInt(C[0],10),right:parseInt(C[1],10),bottom:parseInt(C[2],10),left:parseInt(C[3],10)};},getDrag:function(D){var C=false,E=B.get(D);if(E instanceof B.Node){B.each(this._drags,function(G,F){if(E.compareTo(G.get("node"))){C=G;}});}return C;}});B.namespace("DD");B.DD.DDM=new A();},"3.0.0",{requires:["node","base"],skinnable:false});YUI.add("dd-ddm",function(A){A.mix(A.DD.DDM,{_pg:null,_debugShim:false,_activateTargets:function(){},_deactivateTargets:function(){},_startDrag:function(){if(this.activeDrag.get("useShim")){this._pg_activate();this._activateTargets();}},_endDrag:function(){this._pg_deactivate();this._deactivateTargets();},_pg_deactivate:function(){this._pg.setStyle("display","none");},_pg_activate:function(){var B=this.activeDrag.get("activeHandle"),C="auto";if(B){C=B.getStyle("cursor");}if(C=="auto"){C=this.get("dragCursor");}this._pg_size();this._pg.setStyles({top:0,left:0,display:"block",opacity:((this._debugShim)?".5":"0"),cursor:C});},_pg_size:function(){if(this.activeDrag){var B=A.get("body"),D=B.get("docHeight"),C=B.get("docWidth");this._pg.setStyles({height:D+"px",width:C+"px"});}},_createPG:function(){var D=A.Node.create("
    "),B=A.get("body");D.setStyles({top:"0",left:"0",position:"absolute",zIndex:"9999",overflow:"hidden",backgroundColor:"red",display:"none",height:"5px",width:"5px"});D.set("id",A.stamp(D));D.addClass("yui-dd-shim");if(B.get("firstChild")){B.insertBefore(D,B.get("firstChild"));}else{B.appendChild(D);}this._pg=D;this._pg.on("mouseup",A.bind(this._end,this));this._pg.on("mousemove",A.bind(this._move,this));var C=A.get(window);A.on("window:resize",A.bind(this._pg_size,this));C.on("scroll",A.bind(this._pg_size,this));}},true);A.on("domready",A.bind(A.DD.DDM._createPG,A.DD.DDM));},"3.0.0",{requires:["dd-ddm-base","event-resize"],skinnable:false});YUI.add("dd-ddm-drop",function(A){A.mix(A.DD.DDM,{_noShim:false,_activeShims:[],_hasActiveShim:function(){if(this._noShim){return true;}return this._activeShims.length;},_addActiveShim:function(B){this._activeShims[this._activeShims.length]=B;},_removeActiveShim:function(C){var B=[];A.each(this._activeShims,function(E,D){if(E._yuid!==C._yuid){B[B.length]=E;}});this._activeShims=B;},syncActiveShims:function(B){A.later(0,this,function(C){var D=((C)?this.targets:this._lookup());A.each(D,function(F,E){F.sizeShim.call(F);},this);},B);},mode:0,POINT:0,INTERSECT:1,STRICT:2,useHash:true,activeDrop:null,validDrops:[],otherDrops:{},targets:[],_addValid:function(B){this.validDrops[this.validDrops.length]=B;return this;},_removeValid:function(B){var C=[];A.each(this.validDrops,function(E,D){if(E!==B){C[C.length]=E;}});this.validDrops=C;return this;},isOverTarget:function(C){if(this.activeDrag&&C){var F=this.activeDrag.mouseXY,E,B=this.activeDrag.get("dragMode"),D;if(F&&this.activeDrag){D=this.activeDrag.region;if(B==this.STRICT){return this.activeDrag.get("dragNode").inRegion(C.region,true,D);}else{if(C&&C.shim){if((B==this.INTERSECT)&&this._noShim){E=((D)?D:this.activeDrag.get("node"));return C.get("node").intersect(E).inRegion;}else{return C.shim.intersect({top:F[1],bottom:F[1],left:F[0],right:F[0]},C.region).inRegion;}}else{return false;}}}else{return false;}}else{return false;}},clearCache:function(){this.validDrops=[];this.otherDrops={};this._activeShims=[];},_activateTargets:function(){this.clearCache();A.each(this.targets,function(C,B){C._activateShim.apply(C,[]);},this);this._handleTargetOver();},getBestMatch:function(F,D){var C=null,E=0,B;A.each(F,function(I,H){var G=this.activeDrag.get("dragNode").intersect(I.get("node"));I.region.area=G.area;if(G.inRegion){if(G.area>E){E=G.area;C=I;}}},this);if(D){B=[];A.each(F,function(H,G){if(H!==C){B[B.length]=H;}},this);return[C,B];}else{return C;}},_deactivateTargets:function(){var B=[],C,E=this.activeDrag,D=this.activeDrop;if(E&&D&&this.otherDrops[D]){if(!E.get("dragMode")){B=this.otherDrops;delete B[D];}else{C=this.getBestMatch(this.otherDrops,true);D=C[0];B=C[1];}E.get("node").removeClass(this.CSS_PREFIX+"-drag-over");if(D){D.fire("drop:hit",{drag:E,drop:D,others:B});E.fire("drag:drophit",{drag:E,drop:D,others:B});}}else{if(E){E.get("node").removeClass(this.CSS_PREFIX+"-drag-over");E.fire("drag:dropmiss",{pageX:E.lastXY[0],pageY:E.lastXY[1]});}else{}}this.activeDrop=null;A.each(this.targets,function(G,F){G._deactivateShim.apply(G,[]);},this);},_dropMove:function(){if(this._hasActiveShim()){this._handleTargetOver();}else{A.each(this.otherDrops,function(C,B){C._handleOut.apply(C,[]);});}},_lookup:function(){if(!this.useHash||this._noShim){return this.validDrops;}var B=[];A.each(this.validDrops,function(D,C){if(D.shim&&D.shim.inViewportRegion(false,D.region)){B[B.length]=D;}});return B;},_handleTargetOver:function(){var B=this._lookup();A.each(B,function(D,C){D._handleTargetOver.call(D);},this);},_regTarget:function(B){this.targets[this.targets.length]=B;},_unregTarget:function(C){var B=[],D;A.each(this.targets,function(F,E){if(F!=C){B[B.length]=F;}},this);this.targets=B;D=[];A.each(this.validDrops,function(F,E){if(F!==C){D[D.length]=F;}});this.validDrops=D;},getDrop:function(C){var B=false,D=A.Node.get(C);if(D instanceof A.Node){A.each(this.targets,function(F,E){if(D.compareTo(F.get("node"))){B=F;}});}return B;}},true);},"3.0.0",{requires:["dd-ddm"],skinnable:false});YUI.add("dd-drag",function(D){var E=D.DD.DDM,U="node",G="dragging",N="dragNode",C="offsetHeight",K="offsetWidth",S="mouseup",P="mousedown",M="dragstart",H="drag:mouseDown",B="drag:afterMouseDown",F="drag:removeHandle",L="drag:addHandle",R="drag:removeInvalid",T="drag:addInvalid",J="drag:start",I="drag:end",O="drag:drag",Q="drag:align",A=function(W){this._lazyAddAttrs=false;A.superclass.constructor.apply(this,arguments);var V=E._regDrag(this);if(!V){D.error("Failed to register node, already in use: "+W.node);}};A.NAME="drag";A.ATTRS={node:{setter:function(V){var W=D.get(V);if(!W){D.error("DD.Drag: Invalid Node Given: "+V);}else{W=W.item(0);}return W;}},dragNode:{setter:function(V){var W=D.Node.get(V);if(!W){D.error("DD.Drag: Invalid dragNode Given: "+V);}return W;}},offsetNode:{value:true},clickPixelThresh:{value:E.get("clickPixelThresh")},clickTimeThresh:{value:E.get("clickTimeThresh")},lock:{value:false,setter:function(V){if(V){this.get(U).addClass(E.CSS_PREFIX+"-locked");}else{this.get(U).removeClass(E.CSS_PREFIX+"-locked");}return V;}},data:{value:false},move:{value:true},useShim:{value:true},activeHandle:{value:false},primaryButtonOnly:{value:true},dragging:{value:false},parent:{value:false},target:{value:false,setter:function(V){this._handleTarget(V);return V;}},dragMode:{value:null,setter:function(V){return E._setDragMode(V);}},groups:{value:["default"],getter:function(){if(!this._groups){this._groups={};}var V=[];D.each(this._groups,function(X,W){V[V.length]=W;});return V;},setter:function(V){this._groups={};D.each(V,function(X,W){this._groups[X]=true;},this);return V;}},handles:{value:null,setter:function(V){if(V){this._handles={};D.each(V,function(X,W){this._handles[X]=true;},this);}else{this._handles=null;}return V;}},bubbles:{writeOnce:true,value:D.DD.DDM}};D.extend(A,D.Base,{addToGroup:function(V){this._groups[V]=true;E._activateTargets();return this;},removeFromGroup:function(V){delete this._groups[V];E._activateTargets();return this;},target:null,_handleTarget:function(V){if(D.DD.Drop){if(V===false){if(this.target){E._unregTarget(this.target);this.target=null;}return false;}else{if(!D.Lang.isObject(V)){V={};}V.bubbles=("bubbles"in V)?V.bubbles:this.get("bubbles");V.node=this.get(U);V.groups=V.groups||this.get("groups");this.target=new D.DD.Drop(V);}}else{return false;}},_groups:null,_createEvents:function(){this.publish(H,{defaultFn:this._defMouseDownFn,queuable:false,emitFacade:true,bubbles:true,prefix:"drag"});this.publish(Q,{defaultFn:this._defAlignFn,queuable:false,emitFacade:true,bubbles:true,prefix:"drag"});this.publish(O,{defaultFn:this._defDragFn,queuable:false,emitFacade:true,bubbles:true,prefix:"drag"});this.publish(I,{preventedFn:this._prevEndFn,queuable:false,emitFacade:true,bubbles:true,prefix:"drag"});var V=[B,F,L,R,T,J,"drag:drophit","drag:dropmiss","drag:over","drag:enter","drag:exit"];D.each(V,function(X,W){this.publish(X,{type:X,emitFacade:true,bubbles:true,preventable:false,queuable:false,prefix:"drag"});},this);if(this.get("bubbles")){this.addTarget(this.get("bubbles"));}},_ev_md:null,_startTime:null,_endTime:null,_handles:null,_invalids:null,_invalidsDefault:{"textarea":true,"input":true,"a":true,"button":true,"select":true},_dragThreshMet:null,_fromTimeout:null,_clickTimeout:null,deltaXY:null,startXY:null,nodeXY:null,lastXY:null,actXY:null,realXY:null,mouseXY:null,region:null,_handleMouseUp:function(V){this._fixIEMouseUp();if(E.activeDrag){E._end();}},_fixDragStart:function(V){V.preventDefault();},_ieSelectFix:function(){return false;},_ieSelectBack:null,_fixIEMouseDown:function(){if(D.UA.ie){this._ieSelectBack=D.config.doc.body.onselectstart;D.config.doc.body.onselectstart=this._ieSelectFix;}},_fixIEMouseUp:function(){if(D.UA.ie){D.config.doc.body.onselectstart=this._ieSelectBack;}},_handleMouseDownEvent:function(V){this.fire(H,{ev:V});},_defMouseDownFn:function(W){var V=W.ev;this._dragThreshMet=false;this._ev_md=V;if(this.get("primaryButtonOnly")&&V.button>1){return false;}if(this.validClick(V)){this._fixIEMouseDown();V.halt();this._setStartPosition([V.pageX,V.pageY]);E.activeDrag=this;this._clickTimeout=D.later(this.get("clickTimeThresh"),this,this._timeoutCheck);}this.fire(B,{ev:V});},validClick:function(Z){var Y=false,b=false,V=Z.target,X=null,W=null,a=false;if(this._handles){D.each(this._handles,function(c,d){if(D.Lang.isString(d)){if(V.test(d+", "+d+" *")&&!X){X=d;Y=true;}}});}else{b=this.get(U);if(b.contains(V)||b.compareTo(V)){Y=true;}}if(Y){if(this._invalids){D.each(this._invalids,function(c,d){if(D.Lang.isString(d)){if(V.test(d+", "+d+" *")){Y=false;}}});}}if(Y){if(X){W=Z.currentTarget.queryAll(X);a=false;W.each(function(d,c){if((d.contains(V)||d.compareTo(V))&&!a){a=true;this.set("activeHandle",d);}},this);}else{this.set("activeHandle",this.get(U));}}return Y;},_setStartPosition:function(V){this.startXY=V;this.nodeXY=this.lastXY=this.realXY=this.get(U).getXY();if(this.get("offsetNode")){this.deltaXY=[(this.startXY[0]-this.nodeXY[0]),(this.startXY[1]-this.nodeXY[1])];}else{this.deltaXY=[0,0];}},_timeoutCheck:function(){if(!this.get("lock")&&!this._dragThreshMet){this._fromTimeout=this._dragThreshMet=true;this.start();this._alignNode([this._ev_md.pageX,this._ev_md.pageY],true);}},removeHandle:function(V){if(this._handles[V]){delete this._handles[V];this.fire(F,{handle:V});}return this;},addHandle:function(V){if(!this._handles){this._handles={};}if(D.Lang.isString(V)){this._handles[V]=true;this.fire(L,{handle:V});}return this;},removeInvalid:function(V){if(this._invalids[V]){this._invalids[V]=null;delete this._invalids[V];this.fire(R,{handle:V});}return this;},addInvalid:function(V){if(D.Lang.isString(V)){this._invalids[V]=true;this.fire(T,{handle:V});}return this;},initializer:function(){this.get(U).dd=this;if(!this.get(U).get("id")){var V=D.stamp(this.get(U));this.get(U).set("id",V);}this.actXY=[];this._invalids=D.clone(this._invalidsDefault,true);this._createEvents();if(!this.get(N)){this.set(N,this.get(U));}this.on("initializedChange",D.bind(this._prep,this));this.set("groups",this.get("groups"));},_prep:function(){this._dragThreshMet=false;var V=this.get(U);V.addClass(E.CSS_PREFIX+"-draggable");V.on(P,D.bind(this._handleMouseDownEvent,this));V.on(S,D.bind(this._handleMouseUp,this));V.on(M,D.bind(this._fixDragStart,this));},_unprep:function(){var V=this.get(U);V.removeClass(E.CSS_PREFIX+"-draggable");V.detachAll();},start:function(){if(!this.get("lock")&&!this.get(G)){var W=this.get(U),V=W.get(K),X=W.get(C);this._startTime=(new Date()).getTime();E._start();W.addClass(E.CSS_PREFIX+"-dragging");this.fire(J,{pageX:this.nodeXY[0],pageY:this.nodeXY[1],startTime:this._startTime});var Y=this.nodeXY;this.region={"0":Y[0],"1":Y[1],area:0,top:Y[1],right:Y[0]+V,bottom:Y[1]+X,left:Y[0]};this.set(G,true);}return this;},end:function(){this._endTime=(new Date()).getTime();if(this._clickTimeout){this._clickTimeout.cancel();}this._dragThreshMet=false;this._fromTimeout=false;if(!this.get("lock")&&this.get(G)){this.fire(I,{pageX:this.lastXY[0],pageY:this.lastXY[1],startTime:this._startTime,endTime:this._endTime});}this.get(U).removeClass(E.CSS_PREFIX+"-dragging");this.set(G,false);this.deltaXY=[0,0];return this;},_prevEndFn:function(V){this.get(N).setXY(this.nodeXY);},_align:function(V){this.fire(Q,{pageX:V[0],pageY:V[1]});},_defAlignFn:function(V){this.actXY=[V.pageX-this.deltaXY[0],V.pageY-this.deltaXY[1]];},_alignNode:function(V){this._align(V);this._moveNode();},_moveNode:function(V){var W=[],X=[],Z=this.nodeXY,Y=this.actXY;W[0]=(Y[0]-this.lastXY[0]);W[1]=(Y[1]-this.lastXY[1]);X[0]=(Y[0]-this.nodeXY[0]);X[1]=(Y[1]-this.nodeXY[1]);this.region={"0":Y[0],"1":Y[1],area:0,top:Y[1],right:Y[0]+this.get(N).get(K),bottom:Y[1]+this.get(N).get(C),left:Y[0]};this.fire(O,{pageX:Y[0],pageY:Y[1],scroll:V,info:{start:Z,xy:Y,delta:W,offset:X}});this.lastXY=Y;},_defDragFn:function(V){if(this.get("move")){if(V.scroll){V.scroll.node.set("scrollTop",V.scroll.top);V.scroll.node.set("scrollLeft",V.scroll.left);}this.get(N).setXY([V.pageX,V.pageY]);this.realXY=[V.pageX,V.pageY];}},_move:function(X){if(this.get("lock")){return false;}else{this.mouseXY=[X.pageX,X.pageY];if(!this._dragThreshMet){var W=Math.abs(this.startXY[0]-X.pageX),V=Math.abs(this.startXY[1]-X.pageY);if(W>this.get("clickPixelThresh")||V>this.get("clickPixelThresh")){this._dragThreshMet=true;this.start();this._alignNode([X.pageX,X.pageY]);}}else{if(this._clickTimeout){this._clickTimeout.cancel();}this._alignNode([X.pageX,X.pageY]);}}},stopDrag:function(){if(this.get(G)){E._end();}return this;},destructor:function(){this._unprep();this.detachAll();if(this.target){this.target.destroy();}E._unregDrag(this);}});D.namespace("DD");D.DD.Drag=A;},"3.0.0",{requires:["dd-ddm-base"],skinnable:false});YUI.add("dd-proxy",function(H){var F=H.DD.DDM,B="node",C="dragNode",A="host",D=true;var G=function(I){G.superclass.constructor.apply(this,arguments);};G.NAME="DDProxy";G.NS="proxy";G.ATTRS={host:{},moveOnEnd:{value:D},hideOnEnd:{value:D},resizeFrame:{value:D},positionProxy:{value:D},borderStyle:{value:"1px solid #808080"}};var E={_hands:null,_init:function(){if(!F._proxy){H.on("domready",H.bind(this._init,this));return;}if(!this._hands){this._hands=[];}var K,L,J,M=this.get(A),I=M.get(C);if(I.compareTo(M.get(B))){if(F._proxy){M.set(C,F._proxy);}}H.each(this._hands,function(N){N.detach();});L=F.on("ddm:start",H.bind(function(){if(F.activeDrag===M){F._setFrame(M);}},this));J=F.on("ddm:end",H.bind(function(){if(M.get("dragging")){if(this.get("moveOnEnd")){M.get(B).setXY(M.lastXY);}if(this.get("hideOnEnd")){M.get(C).setStyle("display","none");}}},this));this._hands=[L,J];},initializer:function(){this._init();},destructor:function(){var I=this.get(A);H.each(this._hands,function(J){J.detach();});I.set(C,I.get(B));}};H.namespace("Plugin");H.extend(G,H.Base,E);H.Plugin.DDProxy=G;H.mix(F,{_createFrame:function(){if(!F._proxy){F._proxy=D;var J=H.Node.create("
    "),I=H.Node.get("body");J.setStyles({position:"absolute",display:"none",zIndex:"999",top:"-999px",left:"-999px"});I.insertBefore(J,I.get("firstChild"));J.set("id",H.stamp(J));J.addClass(F.CSS_PREFIX+"-proxy");F._proxy=J;}},_setFrame:function(J){var M=J.get(B),L=J.get(C),I,K="auto";if(J.proxy.get("resizeFrame")){F._proxy.setStyles({height:M.get("offsetHeight")+"px",width:M.get("offsetWidth")+"px"});}I=F.activeDrag.get("activeHandle");if(I){K=I.getStyle("cursor");}if(K=="auto"){K=F.get("dragCursor");}L.setStyles({visibility:"hidden",display:"block",cursor:K,border:J.proxy.get("borderStyle")});if(J.proxy.get("positionProxy")){L.setXY(J.nodeXY);}L.setStyle("visibility","visible");}});H.on("domready",H.bind(F._createFrame,F));},"3.0.0",{requires:["dd-ddm","dd-drag"],skinnable:false});YUI.add("dd-constrain",function(B){var K="dragNode",M="offsetHeight",F="offsetWidth",Q="host",P="constrain2region",H="constrain2node",G="tickXArray",O="tickYArray",N=B.DD.DDM,E="top",J="right",L="bottom",D="left",I=null;var A=function(C){A.superclass.constructor.apply(this,arguments);};A.NAME="DragConstrained";A.NS="con";A.ATTRS={host:{},stickX:{value:false},stickY:{value:false},tickX:{value:false},tickY:{value:false},tickXArray:{value:false},tickYArray:{value:false},constrain2region:{value:false,getter:function(C){if(B.Lang.isObject(C)){var R={};B.mix(R,C);return R;}else{return false;}},setter:function(C){if(B.Lang.isObject(C)){if(B.Lang.isNumber(C[E])&&B.Lang.isNumber(C[J])&&B.Lang.isNumber(C[D])&&B.Lang.isNumber(C[L])){var R={};B.mix(R,C);return R;}else{return false;}}else{if(C!==false){return false;}}return C;}},gutter:{value:"0",setter:function(C){return B.DD.DDM.cssSizestoObject(C);}},constrain2node:{value:false,setter:function(R){if(!this.get(P)){var C=B.Node.get(R);if(C){return C;}}else{if(this.get(P)!==false){}}return false;}},constrain2view:{value:false}};I={initializer:function(){this.get(Q).on("drag:start",B.bind(this._handleStart,this));this.get(Q).after("drag:align",B.bind(this.align,this));},_handleStart:function(){this._regionCache=null;},_regionCache:null,_cacheRegion:function(){this._regionCache=this.get(H).get("region");},getRegion:function(V){var T={},U=null,C=null,S=this.get("gutter"),R=this.get(Q);if(this.get(H)){if(!this._regionCache){B.on("resize",B.bind(this._cacheRegion,this),window);this._cacheRegion();}T=B.clone(this._regionCache);}else{if(this.get(P)){T=this.get(P);}else{if(this.get("constrain2view")){T=R.get(K).get("viewportRegion");}else{return false;}}}B.each(S,function(W,X){if((X==J)||(X==L)){T[X]-=W;}else{T[X]+=W;}});if(V){U=R.get(K).get(M);C=R.get(K).get(F);T[J]=T[J]-C;T[L]=T[L]-U;}return T;},_checkRegion:function(C){var S=C,U=this.getRegion(),T=this.get(Q),V=T.get(K).get(M),R=T.get(K).get(F);if(S[1]>(U[L]-V)){C[1]=(U[L]-V);}if(U[E]>S[1]){C[1]=U[E];}if(S[0]>(U[J]-R)){C[0]=(U[J]-R);}if(U[D]>S[0]){C[0]=U[D];}return C;},inRegion:function(S){S=S||this.get(Q).get(K).getXY();var R=this._checkRegion([S[0],S[1]]),C=false;if((S[0]===R[0])&&(S[1]===R[1])){C=true;}return C;},align:function(){var S=this.get(Q),C=S.actXY,R=this.getRegion(true);if(this.get("stickX")){C[1]=(S.startXY[1]-S.deltaXY[1]);}if(this.get("stickY")){C[0]=(S.startXY[0]-S.deltaXY[0]);}if(R){C=this._checkRegion(C);}C=this._checkTicks(C,R);S.actXY=C;},_checkTicks:function(W,U){var T=this.get(Q),V=(T.startXY[0]-T.deltaXY[0]),S=(T.startXY[1]-T.deltaXY[1]),C=this.get("tickX"),R=this.get("tickY");if(C&&!this.get(G)){W[0]=N._calcTicks(W[0],V,C,U[D],U[J]);}if(R&&!this.get(O)){W[1]=N._calcTicks(W[1],S,R,U[E],U[L]);}if(this.get(G)){W[0]=N._calcTickArray(W[0],this.get(G),U[D],U[J]);}if(this.get(O)){W[1]=N._calcTickArray(W[1],this.get(O),U[E],U[L]);}return W;}};B.namespace("Plugin");B.extend(A,B.Base,I);B.Plugin.DDConstrained=A;B.mix(N,{_calcTicks:function(X,W,T,V,U){var R=((X-W)/T),S=Math.floor(R),C=Math.ceil(R);if((S!==0)||(C!==0)){if((R>=S)&&(R<=C)){X=(W+(T*S));if(V&&U){if(XU){X=(W+(T*(S-1)));}}}}return X;},_calcTickArray:function(Y,Z,X,U){var R=0,V=Z.length,T=0,S,C,W;if(!Z||(Z.length===0)){return Y;}else{if(Z[0]>=Y){return Z[0];}else{for(R=0;R=Y){S=Y-Z[R];C=Z[T]-Y;W=(C>S)?Z[R]:Z[T];if(X&&U){if(W>U){if(Z[R]){W=Z[R];}else{W=Z[V-1];}}}return W;}}return Z[Z.length-1];}}}});},"3.0.0",{requires:["dd-drag"],skinnable:false});YUI.add("dd-scroll",function(C){var H=function(){H.superclass.constructor.apply(this,arguments);},L="host",A="buffer",J="parentScroll",G="windowScroll",I="scrollTop",F="scrollLeft",E="offsetWidth",K="offsetHeight";H.ATTRS={parentScroll:{value:false,setter:function(M){if(M){return M;}return false;}},buffer:{value:30},scrollDelay:{value:235},host:{value:null},windowScroll:{value:false},vertical:{value:true},horizontal:{value:true}};C.extend(H,C.Base,{_scrolling:null,_vpRegionCache:null,_dimCache:null,_scrollTimer:null,_getVPRegion:function(){var M={};var N=this.get(J),R=this.get(A),Q=this.get(G),U=((Q)?[]:N.getXY()),S=((Q)?"winWidth":E),P=((Q)?"winHeight":K),T=((Q)?N.get(I):U[1]),O=((Q)?N.get(F):U[0]);M={top:T+R,right:(N.get(S)+O)-R,bottom:(N.get(P)+T)-R,left:O+R};this._vpRegionCache=M;return M;},initializer:function(){var M=this.get(L);M.after("drag:start",C.bind(this.start,this));M.after("drag:end",C.bind(this.end,this));M.on("drag:align",C.bind(this.align,this));C.get(window).on("scroll",C.bind(function(){this._vpRegionCache=null;},this));},_checkWinScroll:function(Y){var X=this._getVPRegion(),M=this.get(L),O=this.get(G),S=M.lastXY,N=false,e=this.get(A),R=this.get(J),g=R.get(I),U=R.get(F),V=this._dimCache.w,a=this._dimCache.h,T=S[1]+a,W=S[1],d=S[0]+V,Q=S[0],f=W,P=Q,Z=g,c=U;if(this.get("horizontal")){if(Q<=X.left){N=true;P=S[0]-((O)?e:0);c=U-e;}if(d>=X.right){N=true;P=S[0]+((O)?e:0);c=U+e;}}if(this.get("vertical")){if(T>=X.bottom){N=true;f=S[1]+((O)?e:0);Z=g+e;}if(W<=X.top){N=true;f=S[1]-((O)?e:0);Z=g-e;}}if(Z<0){Z=0;f=S[1];}if(c<0){c=0;P=S[0];}if(f<0){f=S[1];}if(P<0){P=S[0];}if(Y){M.actXY=[P,f];M._moveNode({node:R,top:Z,left:c});if(!Z&&!c){this._cancelScroll();}}else{if(N){this._initScroll();}else{this._cancelScroll();}}},_initScroll:function(){this._cancelScroll();this._scrollTimer=C.Lang.later(this.get("scrollDelay"),this,this._checkWinScroll,[true],true);},_cancelScroll:function(){this._scrolling=false;if(this._scrollTimer){this._scrollTimer.cancel();delete this._scrollTimer;}},align:function(M){if(this._scrolling){this._cancelScroll();M.preventDefault();}if(!this._scrolling){this._checkWinScroll();}},_setDimCache:function(){var M=this.get(L).get("dragNode");this._dimCache={h:M.get(K),w:M.get(E)};},start:function(){this._setDimCache();},end:function(M){this._dimCache=null;this._cancelScroll();},toString:function(){return H.NAME+" #"+this.get("node").get("id");}});C.namespace("Plugin");var B=function(){B.superclass.constructor.apply(this,arguments);};B.ATTRS=C.merge(H.ATTRS,{windowScroll:{value:true,setter:function(M){if(M){this.set(J,C.get(window));}return M;}}});C.extend(B,H,{initializer:function(){this.set("windowScroll",this.get("windowScroll"));}});B.NAME=B.NS="winscroll";C.Plugin.DDWinScroll=B;var D=function(){D.superclass.constructor.apply(this,arguments);};D.ATTRS=C.merge(H.ATTRS,{node:{value:false,setter:function(M){var N=C.get(M);if(!N){if(M!==false){C.error("DDNodeScroll: Invalid Node Given: "+M);}}else{N=N.item(0);this.set(J,N);}return N;}}});C.extend(D,H,{initializer:function(){this.set("node",this.get("node"));}});D.NAME=D.NS="nodescroll";C.Plugin.DDNodeScroll=D;C.DD.Scroll=H;},"3.0.0",{skinnable:false,requires:["dd-drag"],optional:["dd-proxy"]});YUI.add("dd-plugin",function(B){var A=function(C){C.node=((B.Widget&&C.host instanceof B.Widget)?C.host.get("boundingBox"):C.host);A.superclass.constructor.apply(this,arguments);};A.NAME="dd-plugin";A.NS="dd";B.extend(A,B.DD.Drag);B.namespace("Plugin");B.Plugin.Drag=A;},"3.0.0",{skinnable:false,requires:["dd-drag"],optional:["dd-constrain","dd-proxy"]});YUI.add("dd-drop",function(A){var B="node",G=A.DD.DDM,F="offsetHeight",C="offsetWidth",I="drop:over",H="drop:enter",D="drop:exit",E=function(){this._lazyAddAttrs=false;E.superclass.constructor.apply(this,arguments);A.on("domready",A.bind(function(){A.later(100,this,this._createShim);},this));G._regTarget(this);};E.NAME="drop";E.ATTRS={node:{setter:function(J){var K=A.Node.get(J);if(!K){A.error("DD.Drop: Invalid Node Given: "+J);}return K;}},groups:{value:["default"],setter:function(J){this._groups={};A.each(J,function(L,K){this._groups[L]=true;},this);return J;}},padding:{value:"0",setter:function(J){return G.cssSizestoObject(J);}},lock:{value:false,setter:function(J){if(J){this.get(B).addClass(G.CSS_PREFIX+"-drop-locked");}else{this.get(B).removeClass(G.CSS_PREFIX+"-drop-locked");}return J;}},bubbles:{writeOnce:true,value:A.DD.DDM}};A.extend(E,A.Base,{_createEvents:function(){var J=[I,H,D,"drop:hit"];A.each(J,function(L,K){this.publish(L,{type:L,emitFacade:true,preventable:false,bubbles:true,queuable:false,prefix:"drop"});},this);if(this.get("bubbles")){this.addTarget(this.get("bubbles"));}},_valid:null,_groups:null,shim:null,region:null,overTarget:null,inGroup:function(J){this._valid=false;var K=false;A.each(J,function(M,L){if(this._groups[M]){K=true;this._valid=true;}},this);return K;},initializer:function(){A.later(100,this,this._createEvents);var J=this.get(B),K;if(!J.get("id")){K=A.stamp(J);J.set("id",K);}J.addClass(G.CSS_PREFIX+"-drop");this.set("groups",this.get("groups"));},destructor:function(){G._unregTarget(this);if(this.shim){this.shim.detachAll();this.shim.get("parentNode").removeChild(this.shim);this.shim=null;}this.get(B).removeClass(G.CSS_PREFIX+"-drop");this.detachAll();},_deactivateShim:function(){if(!this.shim){return false;}this.get(B).removeClass(G.CSS_PREFIX+"-drop-active-valid");this.get(B).removeClass(G.CSS_PREFIX+"-drop-active-invalid");this.get(B).removeClass(G.CSS_PREFIX+"-drop-over");this.shim.setStyles({top:"-999px",left:"-999px",zIndex:"1"});this.overTarget=false;},_activateShim:function(){if(!G.activeDrag){return false;}if(this.get(B)===G.activeDrag.get(B)){return false;}if(this.get("lock")){return false;}var J=this.get(B);if(this.inGroup(G.activeDrag.get("groups"))){J.removeClass(G.CSS_PREFIX+"-drop-active-invalid");J.addClass(G.CSS_PREFIX+"-drop-active-valid");G._addValid(this);this.overTarget=false;this.sizeShim();}else{G._removeValid(this);J.removeClass(G.CSS_PREFIX+"-drop-active-valid");J.addClass(G.CSS_PREFIX+"-drop-active-invalid");}},sizeShim:function(){if(!G.activeDrag){return false;}if(this.get(B)===G.activeDrag.get(B)){return false;}if(this.get("lock")){return false;}if(!this.shim){A.later(100,this,this.sizeShim);return false;}var O=this.get(B),M=O.get(F),K=O.get(C),Q=O.getXY(),P=this.get("padding"),J,N,L;K=K+P.left+P.right;M=M+P.top+P.bottom;Q[0]=Q[0]-P.left;Q[1]=Q[1]-P.top;if(G.activeDrag.get("dragMode")===G.INTERSECT){J=G.activeDrag;N=J.get(B).get(F);L=J.get(B).get(C);M=(M+N);K=(K+L);Q[0]=Q[0]-(L-J.deltaXY[0]);Q[1]=Q[1]-(N-J.deltaXY[1]);}this.shim.setStyles({height:M+"px",width:K+"px",top:Q[1]+"px",left:Q[0]+"px"});this.region={"0":Q[0],"1":Q[1],area:0,top:Q[1],right:Q[0]+K,bottom:Q[1]+M,left:Q[0]};},_createShim:function(){if(!G._pg){A.later(10,this,this._createShim);return;}if(this.shim){return;}var J=A.Node.create('
    ');J.setStyles({height:this.get(B).get(F)+"px",width:this.get(B).get(C)+"px",backgroundColor:"yellow",opacity:".5",zIndex:"1",overflow:"hidden",top:"-900px",left:"-900px",position:"absolute"});G._pg.appendChild(J);this.shim=J;J.on("mouseover",A.bind(this._handleOverEvent,this));J.on("mouseout",A.bind(this._handleOutEvent,this));},_handleTargetOver:function(){if(G.isOverTarget(this)){this.get(B).addClass(G.CSS_PREFIX+"-drop-over");G.activeDrop=this;G.otherDrops[this]=this;if(this.overTarget){G.activeDrag.fire("drag:over",{drop:this,drag:G.activeDrag});this.fire(I,{drop:this,drag:G.activeDrag});}else{this.overTarget=true;this.fire(H,{drop:this,drag:G.activeDrag});G.activeDrag.fire("drag:enter",{drop:this,drag:G.activeDrag});G.activeDrag.get(B).addClass(G.CSS_PREFIX+"-drag-over");}}else{this._handleOut();}},_handleOverEvent:function(){this.shim.setStyle("zIndex","999");G._addActiveShim(this);},_handleOutEvent:function(){this.shim.setStyle("zIndex","1");G._removeActiveShim(this);},_handleOut:function(J){if(!G.isOverTarget(this)||J){if(this.overTarget){this.overTarget=false;if(!J){G._removeActiveShim(this);}if(G.activeDrag){this.get(B).removeClass(G.CSS_PREFIX+"-drop-over");G.activeDrag.get(B).removeClass(G.CSS_PREFIX+"-drag-over");this.fire(D);G.activeDrag.fire("drag:exit",{drop:this});delete G.otherDrops[this];}}}}});A.DD.Drop=E;},"3.0.0",{requires:["dd-ddm-drop","dd-drag"],skinnable:false});YUI.add("dd-drop-plugin",function(A){var B=function(C){C.node=C.host;B.superclass.constructor.apply(this,arguments);};B.NAME="dd-drop-plugin";B.NS="drop";A.extend(B,A.DD.Drop);A.namespace("Plugin");A.Plugin.Drop=B;},"3.0.0",{requires:["dd-drop"],skinnable:false});YUI.add("dd",function(A){},"3.0.0",{use:["dd-ddm-base","dd-ddm","dd-ddm-drop","dd-drag","dd-proxy","dd-constrain","dd-plugin","dd-drop","dd-drop-plugin","dd-scroll"],skinnable:false}); \ No newline at end of file diff --git a/include/javascript/yui3/build/dd/dd-plugin-min.js b/include/javascript/yui3/build/dd/dd-plugin-min.js new file mode 100644 index 00000000..aedd1893 --- /dev/null +++ b/include/javascript/yui3/build/dd/dd-plugin-min.js @@ -0,0 +1,8 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add("dd-plugin",function(B){var A=function(C){C.node=((B.Widget&&C.host instanceof B.Widget)?C.host.get("boundingBox"):C.host);A.superclass.constructor.apply(this,arguments);};A.NAME="dd-plugin";A.NS="dd";B.extend(A,B.DD.Drag);B.namespace("Plugin");B.Plugin.Drag=A;},"3.0.0",{skinnable:false,requires:["dd-drag"],optional:["dd-constrain","dd-proxy"]}); \ No newline at end of file diff --git a/include/javascript/yui3/build/dd/dd-plugin.js b/include/javascript/yui3/build/dd/dd-plugin.js new file mode 100644 index 00000000..4d396f4b --- /dev/null +++ b/include/javascript/yui3/build/dd/dd-plugin.js @@ -0,0 +1,8 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add('dd-plugin',function(Y){var Drag=function(config){config.node=((Y.Widget&&config.host instanceof Y.Widget)?config.host.get('boundingBox'):config.host);Drag.superclass.constructor.apply(this,arguments);};Drag.NAME="dd-plugin";Drag.NS="dd";Y.extend(Drag,Y.DD.Drag);Y.namespace('Plugin');Y.Plugin.Drag=Drag;},'3.0.0',{skinnable:false,requires:['dd-drag'],optional:['dd-constrain','dd-proxy']}); \ No newline at end of file diff --git a/include/javascript/yui3/build/dd/dd-proxy-min.js b/include/javascript/yui3/build/dd/dd-proxy-min.js new file mode 100644 index 00000000..406c788d --- /dev/null +++ b/include/javascript/yui3/build/dd/dd-proxy-min.js @@ -0,0 +1,8 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add("dd-proxy",function(H){var F=H.DD.DDM,B="node",C="dragNode",A="host",D=true;var G=function(I){G.superclass.constructor.apply(this,arguments);};G.NAME="DDProxy";G.NS="proxy";G.ATTRS={host:{},moveOnEnd:{value:D},hideOnEnd:{value:D},resizeFrame:{value:D},positionProxy:{value:D},borderStyle:{value:"1px solid #808080"}};var E={_hands:null,_init:function(){if(!F._proxy){H.on("domready",H.bind(this._init,this));return;}if(!this._hands){this._hands=[];}var K,L,J,M=this.get(A),I=M.get(C);if(I.compareTo(M.get(B))){if(F._proxy){M.set(C,F._proxy);}}H.each(this._hands,function(N){N.detach();});L=F.on("ddm:start",H.bind(function(){if(F.activeDrag===M){F._setFrame(M);}},this));J=F.on("ddm:end",H.bind(function(){if(M.get("dragging")){if(this.get("moveOnEnd")){M.get(B).setXY(M.lastXY);}if(this.get("hideOnEnd")){M.get(C).setStyle("display","none");}}},this));this._hands=[L,J];},initializer:function(){this._init();},destructor:function(){var I=this.get(A);H.each(this._hands,function(J){J.detach();});I.set(C,I.get(B));}};H.namespace("Plugin");H.extend(G,H.Base,E);H.Plugin.DDProxy=G;H.mix(F,{_createFrame:function(){if(!F._proxy){F._proxy=D;var J=H.Node.create("
    "),I=H.Node.get("body");J.setStyles({position:"absolute",display:"none",zIndex:"999",top:"-999px",left:"-999px"});I.insertBefore(J,I.get("firstChild"));J.set("id",H.stamp(J));J.addClass(F.CSS_PREFIX+"-proxy");F._proxy=J;}},_setFrame:function(J){var M=J.get(B),L=J.get(C),I,K="auto";if(J.proxy.get("resizeFrame")){F._proxy.setStyles({height:M.get("offsetHeight")+"px",width:M.get("offsetWidth")+"px"});}I=F.activeDrag.get("activeHandle");if(I){K=I.getStyle("cursor");}if(K=="auto"){K=F.get("dragCursor");}L.setStyles({visibility:"hidden",display:"block",cursor:K,border:J.proxy.get("borderStyle")});if(J.proxy.get("positionProxy")){L.setXY(J.nodeXY);}L.setStyle("visibility","visible");}});H.on("domready",H.bind(F._createFrame,F));},"3.0.0",{requires:["dd-ddm","dd-drag"],skinnable:false}); \ No newline at end of file diff --git a/include/javascript/yui3/build/dd/dd-proxy.js b/include/javascript/yui3/build/dd/dd-proxy.js new file mode 100644 index 00000000..02258ec5 --- /dev/null +++ b/include/javascript/yui3/build/dd/dd-proxy.js @@ -0,0 +1,16 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add('dd-proxy',function(Y){var DDM=Y.DD.DDM,NODE='node',DRAG_NODE='dragNode',HOST='host',TRUE=true;var P=function(config){P.superclass.constructor.apply(this,arguments);};P.NAME='DDProxy';P.NS='proxy';P.ATTRS={host:{},moveOnEnd:{value:TRUE},hideOnEnd:{value:TRUE},resizeFrame:{value:TRUE},positionProxy:{value:TRUE},borderStyle:{value:'1px solid #808080'}};var proto={_hands:null,_init:function(){if(!DDM._proxy){Y.on('domready',Y.bind(this._init,this));return;} +if(!this._hands){this._hands=[];} +var i,h,h1,host=this.get(HOST),dnode=host.get(DRAG_NODE);if(dnode.compareTo(host.get(NODE))){if(DDM._proxy){host.set(DRAG_NODE,DDM._proxy);}} +Y.each(this._hands,function(v){v.detach();});h=DDM.on('ddm:start',Y.bind(function(){if(DDM.activeDrag===host){DDM._setFrame(host);}},this));h1=DDM.on('ddm:end',Y.bind(function(){if(host.get('dragging')){if(this.get('moveOnEnd')){host.get(NODE).setXY(host.lastXY);} +if(this.get('hideOnEnd')){host.get(DRAG_NODE).setStyle('display','none');}}},this));this._hands=[h,h1];},initializer:function(){this._init();},destructor:function(){var host=this.get(HOST);Y.each(this._hands,function(v){v.detach();});host.set(DRAG_NODE,host.get(NODE));}};Y.namespace('Plugin');Y.extend(P,Y.Base,proto);Y.Plugin.DDProxy=P;Y.mix(DDM,{_createFrame:function(){if(!DDM._proxy){DDM._proxy=TRUE;var p=Y.Node.create('
    '),b=Y.Node.get('body');p.setStyles({position:'absolute',display:'none',zIndex:'999',top:'-999px',left:'-999px'});b.insertBefore(p,b.get('firstChild'));p.set('id',Y.stamp(p));p.addClass(DDM.CSS_PREFIX+'-proxy');DDM._proxy=p;}},_setFrame:function(drag){var n=drag.get(NODE),d=drag.get(DRAG_NODE),ah,cur='auto';if(drag.proxy.get('resizeFrame')){DDM._proxy.setStyles({height:n.get('offsetHeight')+'px',width:n.get('offsetWidth')+'px'});} +ah=DDM.activeDrag.get('activeHandle');if(ah){cur=ah.getStyle('cursor');} +if(cur=='auto'){cur=DDM.get('dragCursor');} +d.setStyles({visibility:'hidden',display:'block',cursor:cur,border:drag.proxy.get('borderStyle')});if(drag.proxy.get('positionProxy')){d.setXY(drag.nodeXY);} +d.setStyle('visibility','visible');}});Y.on('domready',Y.bind(DDM._createFrame,DDM));},'3.0.0',{requires:['dd-ddm','dd-drag'],skinnable:false}); \ No newline at end of file diff --git a/include/javascript/yui3/build/dd/dd-scroll-min.js b/include/javascript/yui3/build/dd/dd-scroll-min.js new file mode 100644 index 00000000..a5c4bde8 --- /dev/null +++ b/include/javascript/yui3/build/dd/dd-scroll-min.js @@ -0,0 +1,8 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add("dd-scroll",function(C){var H=function(){H.superclass.constructor.apply(this,arguments);},L="host",A="buffer",J="parentScroll",G="windowScroll",I="scrollTop",F="scrollLeft",E="offsetWidth",K="offsetHeight";H.ATTRS={parentScroll:{value:false,setter:function(M){if(M){return M;}return false;}},buffer:{value:30},scrollDelay:{value:235},host:{value:null},windowScroll:{value:false},vertical:{value:true},horizontal:{value:true}};C.extend(H,C.Base,{_scrolling:null,_vpRegionCache:null,_dimCache:null,_scrollTimer:null,_getVPRegion:function(){var M={};var N=this.get(J),R=this.get(A),Q=this.get(G),U=((Q)?[]:N.getXY()),S=((Q)?"winWidth":E),P=((Q)?"winHeight":K),T=((Q)?N.get(I):U[1]),O=((Q)?N.get(F):U[0]);M={top:T+R,right:(N.get(S)+O)-R,bottom:(N.get(P)+T)-R,left:O+R};this._vpRegionCache=M;return M;},initializer:function(){var M=this.get(L);M.after("drag:start",C.bind(this.start,this));M.after("drag:end",C.bind(this.end,this));M.on("drag:align",C.bind(this.align,this));C.get(window).on("scroll",C.bind(function(){this._vpRegionCache=null;},this));},_checkWinScroll:function(Y){var X=this._getVPRegion(),M=this.get(L),O=this.get(G),S=M.lastXY,N=false,e=this.get(A),R=this.get(J),g=R.get(I),U=R.get(F),V=this._dimCache.w,a=this._dimCache.h,T=S[1]+a,W=S[1],d=S[0]+V,Q=S[0],f=W,P=Q,Z=g,c=U;if(this.get("horizontal")){if(Q<=X.left){N=true;P=S[0]-((O)?e:0);c=U-e;}if(d>=X.right){N=true;P=S[0]+((O)?e:0);c=U+e;}}if(this.get("vertical")){if(T>=X.bottom){N=true;f=S[1]+((O)?e:0);Z=g+e;}if(W<=X.top){N=true;f=S[1]-((O)?e:0);Z=g-e;}}if(Z<0){Z=0;f=S[1];}if(c<0){c=0;P=S[0];}if(f<0){f=S[1];}if(P<0){P=S[0];}if(Y){M.actXY=[P,f];M._moveNode({node:R,top:Z,left:c});if(!Z&&!c){this._cancelScroll();}}else{if(N){this._initScroll();}else{this._cancelScroll();}}},_initScroll:function(){this._cancelScroll();this._scrollTimer=C.Lang.later(this.get("scrollDelay"),this,this._checkWinScroll,[true],true);},_cancelScroll:function(){this._scrolling=false;if(this._scrollTimer){this._scrollTimer.cancel();delete this._scrollTimer;}},align:function(M){if(this._scrolling){this._cancelScroll();M.preventDefault();}if(!this._scrolling){this._checkWinScroll();}},_setDimCache:function(){var M=this.get(L).get("dragNode");this._dimCache={h:M.get(K),w:M.get(E)};},start:function(){this._setDimCache();},end:function(M){this._dimCache=null;this._cancelScroll();},toString:function(){return H.NAME+" #"+this.get("node").get("id");}});C.namespace("Plugin");var B=function(){B.superclass.constructor.apply(this,arguments);};B.ATTRS=C.merge(H.ATTRS,{windowScroll:{value:true,setter:function(M){if(M){this.set(J,C.get(window));}return M;}}});C.extend(B,H,{initializer:function(){this.set("windowScroll",this.get("windowScroll"));}});B.NAME=B.NS="winscroll";C.Plugin.DDWinScroll=B;var D=function(){D.superclass.constructor.apply(this,arguments);};D.ATTRS=C.merge(H.ATTRS,{node:{value:false,setter:function(M){var N=C.get(M);if(!N){if(M!==false){C.error("DDNodeScroll: Invalid Node Given: "+M);}}else{N=N.item(0);this.set(J,N);}return N;}}});C.extend(D,H,{initializer:function(){this.set("node",this.get("node"));}});D.NAME=D.NS="nodescroll";C.Plugin.DDNodeScroll=D;C.DD.Scroll=H;},"3.0.0",{skinnable:false,requires:["dd-drag"],optional:["dd-proxy"]}); \ No newline at end of file diff --git a/include/javascript/yui3/build/dd/dd-scroll.js b/include/javascript/yui3/build/dd/dd-scroll.js new file mode 100644 index 00000000..f90052e6 --- /dev/null +++ b/include/javascript/yui3/build/dd/dd-scroll.js @@ -0,0 +1,20 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add('dd-scroll',function(Y){var S=function(){S.superclass.constructor.apply(this,arguments);},HOST='host',BUFFER='buffer',PARENT_SCROLL='parentScroll',WINDOW_SCROLL='windowScroll',SCROLL_TOP='scrollTop',SCROLL_LEFT='scrollLeft',OFFSET_WIDTH='offsetWidth',OFFSET_HEIGHT='offsetHeight';S.ATTRS={parentScroll:{value:false,setter:function(node){if(node){return node;} +return false;}},buffer:{value:30},scrollDelay:{value:235},host:{value:null},windowScroll:{value:false},vertical:{value:true},horizontal:{value:true}};Y.extend(S,Y.Base,{_scrolling:null,_vpRegionCache:null,_dimCache:null,_scrollTimer:null,_getVPRegion:function(){var r={};var n=this.get(PARENT_SCROLL),b=this.get(BUFFER),ws=this.get(WINDOW_SCROLL),xy=((ws)?[]:n.getXY()),w=((ws)?'winWidth':OFFSET_WIDTH),h=((ws)?'winHeight':OFFSET_HEIGHT),t=((ws)?n.get(SCROLL_TOP):xy[1]),l=((ws)?n.get(SCROLL_LEFT):xy[0]);r={top:t+b,right:(n.get(w)+l)-b,bottom:(n.get(h)+t)-b,left:l+b};this._vpRegionCache=r;return r;},initializer:function(){var h=this.get(HOST);h.after('drag:start',Y.bind(this.start,this));h.after('drag:end',Y.bind(this.end,this));h.on('drag:align',Y.bind(this.align,this));Y.get(window).on('scroll',Y.bind(function(){this._vpRegionCache=null;},this));},_checkWinScroll:function(move){var r=this._getVPRegion(),ho=this.get(HOST),ws=this.get(WINDOW_SCROLL),xy=ho.lastXY,scroll=false,b=this.get(BUFFER),win=this.get(PARENT_SCROLL),sTop=win.get(SCROLL_TOP),sLeft=win.get(SCROLL_LEFT),w=this._dimCache.w,h=this._dimCache.h,bottom=xy[1]+h,top=xy[1],right=xy[0]+w,left=xy[0],nt=top,nl=left,st=sTop,sl=sLeft;if(this.get('horizontal')){if(left<=r.left){scroll=true;nl=xy[0]-((ws)?b:0);sl=sLeft-b;} +if(right>=r.right){scroll=true;nl=xy[0]+((ws)?b:0);sl=sLeft+b;}} +if(this.get('vertical')){if(bottom>=r.bottom){scroll=true;nt=xy[1]+((ws)?b:0);st=sTop+b;} +if(top<=r.top){scroll=true;nt=xy[1]-((ws)?b:0);st=sTop-b;}} +if(st<0){st=0;nt=xy[1];} +if(sl<0){sl=0;nl=xy[0];} +if(nt<0){nt=xy[1];} +if(nl<0){nl=xy[0];} +if(move){ho.actXY=[nl,nt];ho._moveNode({node:win,top:st,left:sl});if(!st&&!sl){this._cancelScroll();}}else{if(scroll){this._initScroll();}else{this._cancelScroll();}}},_initScroll:function(){this._cancelScroll();this._scrollTimer=Y.Lang.later(this.get('scrollDelay'),this,this._checkWinScroll,[true],true);},_cancelScroll:function(){this._scrolling=false;if(this._scrollTimer){this._scrollTimer.cancel();delete this._scrollTimer;}},align:function(e){if(this._scrolling){this._cancelScroll();e.preventDefault();} +if(!this._scrolling){this._checkWinScroll();}},_setDimCache:function(){var node=this.get(HOST).get('dragNode');this._dimCache={h:node.get(OFFSET_HEIGHT),w:node.get(OFFSET_WIDTH)};},start:function(){this._setDimCache();},end:function(xy){this._dimCache=null;this._cancelScroll();},toString:function(){return S.NAME+' #'+this.get('node').get('id');}});Y.namespace('Plugin');var WS=function(){WS.superclass.constructor.apply(this,arguments);};WS.ATTRS=Y.merge(S.ATTRS,{windowScroll:{value:true,setter:function(scroll){if(scroll){this.set(PARENT_SCROLL,Y.get(window));} +return scroll;}}});Y.extend(WS,S,{initializer:function(){this.set('windowScroll',this.get('windowScroll'));}});WS.NAME=WS.NS='winscroll';Y.Plugin.DDWinScroll=WS;var NS=function(){NS.superclass.constructor.apply(this,arguments);};NS.ATTRS=Y.merge(S.ATTRS,{node:{value:false,setter:function(node){var n=Y.get(node);if(!n){if(node!==false){Y.error('DDNodeScroll: Invalid Node Given: '+node);}}else{n=n.item(0);this.set(PARENT_SCROLL,n);} +return n;}}});Y.extend(NS,S,{initializer:function(){this.set('node',this.get('node'));}});NS.NAME=NS.NS='nodescroll';Y.Plugin.DDNodeScroll=NS;Y.DD.Scroll=S;},'3.0.0',{skinnable:false,requires:['dd-drag'],optional:['dd-proxy']}); \ No newline at end of file diff --git a/include/javascript/yui3/build/dd/dd.js b/include/javascript/yui3/build/dd/dd.js new file mode 100644 index 00000000..c6ce2dcf --- /dev/null +++ b/include/javascript/yui3/build/dd/dd.js @@ -0,0 +1,107 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add('dd-ddm-base',function(Y){var DDMBase=function(){DDMBase.superclass.constructor.apply(this,arguments);};DDMBase.NAME='ddm';DDMBase.ATTRS={dragCursor:{value:'move'},clickPixelThresh:{value:3},clickTimeThresh:{value:1000},dragMode:{value:'point',setter:function(mode){this._setDragMode(mode);return mode;}}};Y.extend(DDMBase,Y.Base,{_active:null,_setDragMode:function(mode){if(mode===null){mode=Y.DD.DDM.get('dragMode');} +switch(mode){case 1:case'intersect':return 1;case 2:case'strict':return 2;case 0:case'point':return 0;} +return 0;},CSS_PREFIX:'yui-dd',_activateTargets:function(){},_drags:[],activeDrag:false,_regDrag:function(d){if(this.getDrag(d.get('node'))){return false;} +if(!this._active){this._setupListeners();} +this._drags.push(d);return true;},_unregDrag:function(d){var tmp=[];Y.each(this._drags,function(n,i){if(n!==d){tmp[tmp.length]=n;}});this._drags=tmp;},_setupListeners:function(){this._active=true;var doc=Y.get(document);doc.on('mousemove',Y.bind(this._move,this));doc.on('mouseup',Y.bind(this._end,this));},_start:function(){this.fire('ddm:start');this._startDrag();},_startDrag:function(){},_endDrag:function(){},_dropMove:function(){},_end:function(){if(this.activeDrag){this._endDrag();this.fire('ddm:end');this.activeDrag.end.call(this.activeDrag);this.activeDrag=null;}},stopDrag:function(){if(this.activeDrag){this._end();} +return this;},_move:function(ev){if(this.activeDrag){this.activeDrag._move.call(this.activeDrag,ev);this._dropMove();}},cssSizestoObject:function(gutter){var x=gutter.split(' ');switch(x.length){case 1:x[1]=x[2]=x[3]=x[0];break;case 2:x[2]=x[0];x[3]=x[1];break;case 3:x[3]=x[1];break;} +return{top:parseInt(x[0],10),right:parseInt(x[1],10),bottom:parseInt(x[2],10),left:parseInt(x[3],10)};},getDrag:function(node){var drag=false,n=Y.get(node);if(n instanceof Y.Node){Y.each(this._drags,function(v,k){if(n.compareTo(v.get('node'))){drag=v;}});} +return drag;}});Y.namespace('DD');Y.DD.DDM=new DDMBase();},'3.0.0',{requires:['node','base'],skinnable:false});YUI.add('dd-ddm',function(Y){Y.mix(Y.DD.DDM,{_pg:null,_debugShim:false,_activateTargets:function(){},_deactivateTargets:function(){},_startDrag:function(){if(this.activeDrag.get('useShim')){this._pg_activate();this._activateTargets();}},_endDrag:function(){this._pg_deactivate();this._deactivateTargets();},_pg_deactivate:function(){this._pg.setStyle('display','none');},_pg_activate:function(){var ah=this.activeDrag.get('activeHandle'),cur='auto';if(ah){cur=ah.getStyle('cursor');} +if(cur=='auto'){cur=this.get('dragCursor');} +this._pg_size();this._pg.setStyles({top:0,left:0,display:'block',opacity:((this._debugShim)?'.5':'0'),cursor:cur});},_pg_size:function(){if(this.activeDrag){var b=Y.get('body'),h=b.get('docHeight'),w=b.get('docWidth');this._pg.setStyles({height:h+'px',width:w+'px'});}},_createPG:function(){var pg=Y.Node.create('
    '),bd=Y.get('body');pg.setStyles({top:'0',left:'0',position:'absolute',zIndex:'9999',overflow:'hidden',backgroundColor:'red',display:'none',height:'5px',width:'5px'});pg.set('id',Y.stamp(pg));pg.addClass('yui-dd-shim');if(bd.get('firstChild')){bd.insertBefore(pg,bd.get('firstChild'));}else{bd.appendChild(pg);} +this._pg=pg;this._pg.on('mouseup',Y.bind(this._end,this));this._pg.on('mousemove',Y.bind(this._move,this));var win=Y.get(window);Y.on('window:resize',Y.bind(this._pg_size,this));win.on('scroll',Y.bind(this._pg_size,this));}},true);Y.on('domready',Y.bind(Y.DD.DDM._createPG,Y.DD.DDM));},'3.0.0',{requires:['dd-ddm-base','event-resize'],skinnable:false});YUI.add('dd-ddm-drop',function(Y){Y.mix(Y.DD.DDM,{_noShim:false,_activeShims:[],_hasActiveShim:function(){if(this._noShim){return true;} +return this._activeShims.length;},_addActiveShim:function(d){this._activeShims[this._activeShims.length]=d;},_removeActiveShim:function(d){var s=[];Y.each(this._activeShims,function(v,k){if(v._yuid!==d._yuid){s[s.length]=v;}});this._activeShims=s;},syncActiveShims:function(force){Y.later(0,this,function(force){var drops=((force)?this.targets:this._lookup());Y.each(drops,function(v,k){v.sizeShim.call(v);},this);},force);},mode:0,POINT:0,INTERSECT:1,STRICT:2,useHash:true,activeDrop:null,validDrops:[],otherDrops:{},targets:[],_addValid:function(drop){this.validDrops[this.validDrops.length]=drop;return this;},_removeValid:function(drop){var drops=[];Y.each(this.validDrops,function(v,k){if(v!==drop){drops[drops.length]=v;}});this.validDrops=drops;return this;},isOverTarget:function(drop){if(this.activeDrag&&drop){var xy=this.activeDrag.mouseXY,r,dMode=this.activeDrag.get('dragMode'),aRegion;if(xy&&this.activeDrag){aRegion=this.activeDrag.region;if(dMode==this.STRICT){return this.activeDrag.get('dragNode').inRegion(drop.region,true,aRegion);}else{if(drop&&drop.shim){if((dMode==this.INTERSECT)&&this._noShim){r=((aRegion)?aRegion:this.activeDrag.get('node'));return drop.get('node').intersect(r).inRegion;}else{return drop.shim.intersect({top:xy[1],bottom:xy[1],left:xy[0],right:xy[0]},drop.region).inRegion;}}else{return false;}}}else{return false;}}else{return false;}},clearCache:function(){this.validDrops=[];this.otherDrops={};this._activeShims=[];},_activateTargets:function(){this.clearCache();Y.each(this.targets,function(v,k){v._activateShim.apply(v,[]);},this);this._handleTargetOver();},getBestMatch:function(drops,all){var biggest=null,area=0,out;Y.each(drops,function(v,k){var inter=this.activeDrag.get('dragNode').intersect(v.get('node'));v.region.area=inter.area;if(inter.inRegion){if(inter.area>area){area=inter.area;biggest=v;}}},this);if(all){out=[];Y.each(drops,function(v,k){if(v!==biggest){out[out.length]=v;}},this);return[biggest,out];}else{return biggest;}},_deactivateTargets:function(){var other=[],tmp,activeDrag=this.activeDrag,activeDrop=this.activeDrop;if(activeDrag&&activeDrop&&this.otherDrops[activeDrop]){if(!activeDrag.get('dragMode')){other=this.otherDrops;delete other[activeDrop];}else{tmp=this.getBestMatch(this.otherDrops,true);activeDrop=tmp[0];other=tmp[1];} +activeDrag.get('node').removeClass(this.CSS_PREFIX+'-drag-over');if(activeDrop){activeDrop.fire('drop:hit',{drag:activeDrag,drop:activeDrop,others:other});activeDrag.fire('drag:drophit',{drag:activeDrag,drop:activeDrop,others:other});}}else if(activeDrag){activeDrag.get('node').removeClass(this.CSS_PREFIX+'-drag-over');activeDrag.fire('drag:dropmiss',{pageX:activeDrag.lastXY[0],pageY:activeDrag.lastXY[1]});}else{} +this.activeDrop=null;Y.each(this.targets,function(v,k){v._deactivateShim.apply(v,[]);},this);},_dropMove:function(){if(this._hasActiveShim()){this._handleTargetOver();}else{Y.each(this.otherDrops,function(v,k){v._handleOut.apply(v,[]);});}},_lookup:function(){if(!this.useHash||this._noShim){return this.validDrops;} +var drops=[];Y.each(this.validDrops,function(v,k){if(v.shim&&v.shim.inViewportRegion(false,v.region)){drops[drops.length]=v;}});return drops;},_handleTargetOver:function(){var drops=this._lookup();Y.each(drops,function(v,k){v._handleTargetOver.call(v);},this);},_regTarget:function(t){this.targets[this.targets.length]=t;},_unregTarget:function(drop){var targets=[],vdrops;Y.each(this.targets,function(v,k){if(v!=drop){targets[targets.length]=v;}},this);this.targets=targets;vdrops=[];Y.each(this.validDrops,function(v,k){if(v!==drop){vdrops[vdrops.length]=v;}});this.validDrops=vdrops;},getDrop:function(node){var drop=false,n=Y.Node.get(node);if(n instanceof Y.Node){Y.each(this.targets,function(v,k){if(n.compareTo(v.get('node'))){drop=v;}});} +return drop;}},true);},'3.0.0',{requires:['dd-ddm'],skinnable:false});YUI.add('dd-drag',function(Y){var DDM=Y.DD.DDM,NODE='node',DRAGGING='dragging',DRAG_NODE='dragNode',OFFSET_HEIGHT='offsetHeight',OFFSET_WIDTH='offsetWidth',MOUSE_UP='mouseup',MOUSE_DOWN='mousedown',DRAG_START='dragstart',EV_MOUSE_DOWN='drag:mouseDown',EV_AFTER_MOUSE_DOWN='drag:afterMouseDown',EV_REMOVE_HANDLE='drag:removeHandle',EV_ADD_HANDLE='drag:addHandle',EV_REMOVE_INVALID='drag:removeInvalid',EV_ADD_INVALID='drag:addInvalid',EV_START='drag:start',EV_END='drag:end',EV_DRAG='drag:drag',EV_ALIGN='drag:align',Drag=function(o){this._lazyAddAttrs=false;Drag.superclass.constructor.apply(this,arguments);var valid=DDM._regDrag(this);if(!valid){Y.error('Failed to register node, already in use: '+o.node);}};Drag.NAME='drag';Drag.ATTRS={node:{setter:function(node){var n=Y.get(node);if(!n){Y.error('DD.Drag: Invalid Node Given: '+node);}else{n=n.item(0);} +return n;}},dragNode:{setter:function(node){var n=Y.Node.get(node);if(!n){Y.error('DD.Drag: Invalid dragNode Given: '+node);} +return n;}},offsetNode:{value:true},clickPixelThresh:{value:DDM.get('clickPixelThresh')},clickTimeThresh:{value:DDM.get('clickTimeThresh')},lock:{value:false,setter:function(lock){if(lock){this.get(NODE).addClass(DDM.CSS_PREFIX+'-locked');}else{this.get(NODE).removeClass(DDM.CSS_PREFIX+'-locked');} +return lock;}},data:{value:false},move:{value:true},useShim:{value:true},activeHandle:{value:false},primaryButtonOnly:{value:true},dragging:{value:false},parent:{value:false},target:{value:false,setter:function(config){this._handleTarget(config);return config;}},dragMode:{value:null,setter:function(mode){return DDM._setDragMode(mode);}},groups:{value:['default'],getter:function(){if(!this._groups){this._groups={};} +var ret=[];Y.each(this._groups,function(v,k){ret[ret.length]=k;});return ret;},setter:function(g){this._groups={};Y.each(g,function(v,k){this._groups[v]=true;},this);return g;}},handles:{value:null,setter:function(g){if(g){this._handles={};Y.each(g,function(v,k){this._handles[v]=true;},this);}else{this._handles=null;} +return g;}},bubbles:{writeOnce:true,value:Y.DD.DDM}};Y.extend(Drag,Y.Base,{addToGroup:function(g){this._groups[g]=true;DDM._activateTargets();return this;},removeFromGroup:function(g){delete this._groups[g];DDM._activateTargets();return this;},target:null,_handleTarget:function(config){if(Y.DD.Drop){if(config===false){if(this.target){DDM._unregTarget(this.target);this.target=null;} +return false;}else{if(!Y.Lang.isObject(config)){config={};} +config.bubbles=('bubbles'in config)?config.bubbles:this.get('bubbles');config.node=this.get(NODE);config.groups=config.groups||this.get('groups');this.target=new Y.DD.Drop(config);}}else{return false;}},_groups:null,_createEvents:function(){this.publish(EV_MOUSE_DOWN,{defaultFn:this._defMouseDownFn,queuable:false,emitFacade:true,bubbles:true,prefix:'drag'});this.publish(EV_ALIGN,{defaultFn:this._defAlignFn,queuable:false,emitFacade:true,bubbles:true,prefix:'drag'});this.publish(EV_DRAG,{defaultFn:this._defDragFn,queuable:false,emitFacade:true,bubbles:true,prefix:'drag'});this.publish(EV_END,{preventedFn:this._prevEndFn,queuable:false,emitFacade:true,bubbles:true,prefix:'drag'});var ev=[EV_AFTER_MOUSE_DOWN,EV_REMOVE_HANDLE,EV_ADD_HANDLE,EV_REMOVE_INVALID,EV_ADD_INVALID,EV_START,'drag:drophit','drag:dropmiss','drag:over','drag:enter','drag:exit'];Y.each(ev,function(v,k){this.publish(v,{type:v,emitFacade:true,bubbles:true,preventable:false,queuable:false,prefix:'drag'});},this);if(this.get('bubbles')){this.addTarget(this.get('bubbles'));}},_ev_md:null,_startTime:null,_endTime:null,_handles:null,_invalids:null,_invalidsDefault:{'textarea':true,'input':true,'a':true,'button':true,'select':true},_dragThreshMet:null,_fromTimeout:null,_clickTimeout:null,deltaXY:null,startXY:null,nodeXY:null,lastXY:null,actXY:null,realXY:null,mouseXY:null,region:null,_handleMouseUp:function(ev){this._fixIEMouseUp();if(DDM.activeDrag){DDM._end();}},_fixDragStart:function(e){e.preventDefault();},_ieSelectFix:function(){return false;},_ieSelectBack:null,_fixIEMouseDown:function(){if(Y.UA.ie){this._ieSelectBack=Y.config.doc.body.onselectstart;Y.config.doc.body.onselectstart=this._ieSelectFix;}},_fixIEMouseUp:function(){if(Y.UA.ie){Y.config.doc.body.onselectstart=this._ieSelectBack;}},_handleMouseDownEvent:function(ev){this.fire(EV_MOUSE_DOWN,{ev:ev});},_defMouseDownFn:function(e){var ev=e.ev;this._dragThreshMet=false;this._ev_md=ev;if(this.get('primaryButtonOnly')&&ev.button>1){return false;} +if(this.validClick(ev)){this._fixIEMouseDown();ev.halt();this._setStartPosition([ev.pageX,ev.pageY]);DDM.activeDrag=this;this._clickTimeout=Y.later(this.get('clickTimeThresh'),this,this._timeoutCheck);} +this.fire(EV_AFTER_MOUSE_DOWN,{ev:ev});},validClick:function(ev){var r=false,n=false,tar=ev.target,hTest=null,els=null,set=false;if(this._handles){Y.each(this._handles,function(i,n){if(Y.Lang.isString(n)){if(tar.test(n+', '+n+' *')&&!hTest){hTest=n;r=true;}}});}else{n=this.get(NODE) +if(n.contains(tar)||n.compareTo(tar)){r=true;}} +if(r){if(this._invalids){Y.each(this._invalids,function(i,n){if(Y.Lang.isString(n)){if(tar.test(n+', '+n+' *')){r=false;}}});}} +if(r){if(hTest){els=ev.currentTarget.queryAll(hTest);set=false;els.each(function(n,i){if((n.contains(tar)||n.compareTo(tar))&&!set){set=true;this.set('activeHandle',n);}},this);}else{this.set('activeHandle',this.get(NODE));}} +return r;},_setStartPosition:function(xy){this.startXY=xy;this.nodeXY=this.lastXY=this.realXY=this.get(NODE).getXY();if(this.get('offsetNode')){this.deltaXY=[(this.startXY[0]-this.nodeXY[0]),(this.startXY[1]-this.nodeXY[1])];}else{this.deltaXY=[0,0];}},_timeoutCheck:function(){if(!this.get('lock')&&!this._dragThreshMet){this._fromTimeout=this._dragThreshMet=true;this.start();this._alignNode([this._ev_md.pageX,this._ev_md.pageY],true);}},removeHandle:function(str){if(this._handles[str]){delete this._handles[str];this.fire(EV_REMOVE_HANDLE,{handle:str});} +return this;},addHandle:function(str){if(!this._handles){this._handles={};} +if(Y.Lang.isString(str)){this._handles[str]=true;this.fire(EV_ADD_HANDLE,{handle:str});} +return this;},removeInvalid:function(str){if(this._invalids[str]){this._invalids[str]=null;delete this._invalids[str];this.fire(EV_REMOVE_INVALID,{handle:str});} +return this;},addInvalid:function(str){if(Y.Lang.isString(str)){this._invalids[str]=true;this.fire(EV_ADD_INVALID,{handle:str});} +return this;},initializer:function(){this.get(NODE).dd=this;if(!this.get(NODE).get('id')){var id=Y.stamp(this.get(NODE));this.get(NODE).set('id',id);} +this.actXY=[];this._invalids=Y.clone(this._invalidsDefault,true);this._createEvents();if(!this.get(DRAG_NODE)){this.set(DRAG_NODE,this.get(NODE));} +this.on('initializedChange',Y.bind(this._prep,this));this.set('groups',this.get('groups'));},_prep:function(){this._dragThreshMet=false;var node=this.get(NODE);node.addClass(DDM.CSS_PREFIX+'-draggable');node.on(MOUSE_DOWN,Y.bind(this._handleMouseDownEvent,this));node.on(MOUSE_UP,Y.bind(this._handleMouseUp,this));node.on(DRAG_START,Y.bind(this._fixDragStart,this));},_unprep:function(){var node=this.get(NODE);node.removeClass(DDM.CSS_PREFIX+'-draggable');node.detachAll();},start:function(){if(!this.get('lock')&&!this.get(DRAGGING)){var node=this.get(NODE),ow=node.get(OFFSET_WIDTH),oh=node.get(OFFSET_HEIGHT);this._startTime=(new Date()).getTime();DDM._start();node.addClass(DDM.CSS_PREFIX+'-dragging');this.fire(EV_START,{pageX:this.nodeXY[0],pageY:this.nodeXY[1],startTime:this._startTime});var xy=this.nodeXY;this.region={'0':xy[0],'1':xy[1],area:0,top:xy[1],right:xy[0]+ow,bottom:xy[1]+oh,left:xy[0]};this.set(DRAGGING,true);} +return this;},end:function(){this._endTime=(new Date()).getTime();if(this._clickTimeout){this._clickTimeout.cancel();} +this._dragThreshMet=false;this._fromTimeout=false;if(!this.get('lock')&&this.get(DRAGGING)){this.fire(EV_END,{pageX:this.lastXY[0],pageY:this.lastXY[1],startTime:this._startTime,endTime:this._endTime});} +this.get(NODE).removeClass(DDM.CSS_PREFIX+'-dragging');this.set(DRAGGING,false);this.deltaXY=[0,0];return this;},_prevEndFn:function(e){this.get(DRAG_NODE).setXY(this.nodeXY);},_align:function(xy){this.fire(EV_ALIGN,{pageX:xy[0],pageY:xy[1]});},_defAlignFn:function(e){this.actXY=[e.pageX-this.deltaXY[0],e.pageY-this.deltaXY[1]];},_alignNode:function(eXY){this._align(eXY);this._moveNode();},_moveNode:function(scroll){var diffXY=[],diffXY2=[],startXY=this.nodeXY,xy=this.actXY;diffXY[0]=(xy[0]-this.lastXY[0]);diffXY[1]=(xy[1]-this.lastXY[1]);diffXY2[0]=(xy[0]-this.nodeXY[0]);diffXY2[1]=(xy[1]-this.nodeXY[1]);this.region={'0':xy[0],'1':xy[1],area:0,top:xy[1],right:xy[0]+this.get(DRAG_NODE).get(OFFSET_WIDTH),bottom:xy[1]+this.get(DRAG_NODE).get(OFFSET_HEIGHT),left:xy[0]};this.fire(EV_DRAG,{pageX:xy[0],pageY:xy[1],scroll:scroll,info:{start:startXY,xy:xy,delta:diffXY,offset:diffXY2}});this.lastXY=xy;},_defDragFn:function(e){if(this.get('move')){if(e.scroll){e.scroll.node.set('scrollTop',e.scroll.top);e.scroll.node.set('scrollLeft',e.scroll.left);} +this.get(DRAG_NODE).setXY([e.pageX,e.pageY]);this.realXY=[e.pageX,e.pageY];}},_move:function(ev){if(this.get('lock')){return false;}else{this.mouseXY=[ev.pageX,ev.pageY];if(!this._dragThreshMet){var diffX=Math.abs(this.startXY[0]-ev.pageX),diffY=Math.abs(this.startXY[1]-ev.pageY);if(diffX>this.get('clickPixelThresh')||diffY>this.get('clickPixelThresh')){this._dragThreshMet=true;this.start();this._alignNode([ev.pageX,ev.pageY]);}}else{if(this._clickTimeout){this._clickTimeout.cancel();} +this._alignNode([ev.pageX,ev.pageY]);}}},stopDrag:function(){if(this.get(DRAGGING)){DDM._end();} +return this;},destructor:function(){this._unprep();this.detachAll();if(this.target){this.target.destroy();} +DDM._unregDrag(this);}});Y.namespace('DD');Y.DD.Drag=Drag;},'3.0.0',{requires:['dd-ddm-base'],skinnable:false});YUI.add('dd-proxy',function(Y){var DDM=Y.DD.DDM,NODE='node',DRAG_NODE='dragNode',HOST='host',TRUE=true;var P=function(config){P.superclass.constructor.apply(this,arguments);};P.NAME='DDProxy';P.NS='proxy';P.ATTRS={host:{},moveOnEnd:{value:TRUE},hideOnEnd:{value:TRUE},resizeFrame:{value:TRUE},positionProxy:{value:TRUE},borderStyle:{value:'1px solid #808080'}};var proto={_hands:null,_init:function(){if(!DDM._proxy){Y.on('domready',Y.bind(this._init,this));return;} +if(!this._hands){this._hands=[];} +var i,h,h1,host=this.get(HOST),dnode=host.get(DRAG_NODE);if(dnode.compareTo(host.get(NODE))){if(DDM._proxy){host.set(DRAG_NODE,DDM._proxy);}} +Y.each(this._hands,function(v){v.detach();});h=DDM.on('ddm:start',Y.bind(function(){if(DDM.activeDrag===host){DDM._setFrame(host);}},this));h1=DDM.on('ddm:end',Y.bind(function(){if(host.get('dragging')){if(this.get('moveOnEnd')){host.get(NODE).setXY(host.lastXY);} +if(this.get('hideOnEnd')){host.get(DRAG_NODE).setStyle('display','none');}}},this));this._hands=[h,h1];},initializer:function(){this._init();},destructor:function(){var host=this.get(HOST);Y.each(this._hands,function(v){v.detach();});host.set(DRAG_NODE,host.get(NODE));}};Y.namespace('Plugin');Y.extend(P,Y.Base,proto);Y.Plugin.DDProxy=P;Y.mix(DDM,{_createFrame:function(){if(!DDM._proxy){DDM._proxy=TRUE;var p=Y.Node.create('
    '),b=Y.Node.get('body');p.setStyles({position:'absolute',display:'none',zIndex:'999',top:'-999px',left:'-999px'});b.insertBefore(p,b.get('firstChild'));p.set('id',Y.stamp(p));p.addClass(DDM.CSS_PREFIX+'-proxy');DDM._proxy=p;}},_setFrame:function(drag){var n=drag.get(NODE),d=drag.get(DRAG_NODE),ah,cur='auto';if(drag.proxy.get('resizeFrame')){DDM._proxy.setStyles({height:n.get('offsetHeight')+'px',width:n.get('offsetWidth')+'px'});} +ah=DDM.activeDrag.get('activeHandle');if(ah){cur=ah.getStyle('cursor');} +if(cur=='auto'){cur=DDM.get('dragCursor');} +d.setStyles({visibility:'hidden',display:'block',cursor:cur,border:drag.proxy.get('borderStyle')});if(drag.proxy.get('positionProxy')){d.setXY(drag.nodeXY);} +d.setStyle('visibility','visible');}});Y.on('domready',Y.bind(DDM._createFrame,DDM));},'3.0.0',{requires:['dd-ddm','dd-drag'],skinnable:false});YUI.add('dd-constrain',function(Y){var DRAG_NODE='dragNode',OFFSET_HEIGHT='offsetHeight',OFFSET_WIDTH='offsetWidth',HOST='host',CON_2_REGION='constrain2region',CON_2_NODE='constrain2node',TICK_X_ARRAY='tickXArray',TICK_Y_ARRAY='tickYArray',DDM=Y.DD.DDM,TOP='top',RIGHT='right',BOTTOM='bottom',LEFT='left',proto=null;var C=function(config){C.superclass.constructor.apply(this,arguments);};C.NAME='DragConstrained';C.NS='con';C.ATTRS={host:{},stickX:{value:false},stickY:{value:false},tickX:{value:false},tickY:{value:false},tickXArray:{value:false},tickYArray:{value:false},constrain2region:{value:false,getter:function(r){if(Y.Lang.isObject(r)){var o={};Y.mix(o,r);return o;}else{return false;}},setter:function(r){if(Y.Lang.isObject(r)){if(Y.Lang.isNumber(r[TOP])&&Y.Lang.isNumber(r[RIGHT])&&Y.Lang.isNumber(r[LEFT])&&Y.Lang.isNumber(r[BOTTOM])){var o={};Y.mix(o,r);return o;}else{return false;}}else if(r!==false){return false;} +return r;}},gutter:{value:'0',setter:function(gutter){return Y.DD.DDM.cssSizestoObject(gutter);}},constrain2node:{value:false,setter:function(n){if(!this.get(CON_2_REGION)){var node=Y.Node.get(n);if(node){return node;}}else if(this.get(CON_2_REGION)!==false){} +return false;}},constrain2view:{value:false}};proto={initializer:function(){this.get(HOST).on('drag:start',Y.bind(this._handleStart,this));this.get(HOST).after('drag:align',Y.bind(this.align,this));},_handleStart:function(){this._regionCache=null;},_regionCache:null,_cacheRegion:function(){this._regionCache=this.get(CON_2_NODE).get('region');},getRegion:function(inc){var r={},oh=null,ow=null,g=this.get('gutter'),host=this.get(HOST);if(this.get(CON_2_NODE)){if(!this._regionCache){Y.on('resize',Y.bind(this._cacheRegion,this),window);this._cacheRegion();} +r=Y.clone(this._regionCache);}else if(this.get(CON_2_REGION)){r=this.get(CON_2_REGION);}else if(this.get('constrain2view')){r=host.get(DRAG_NODE).get('viewportRegion');}else{return false;} +Y.each(g,function(i,n){if((n==RIGHT)||(n==BOTTOM)){r[n]-=i;}else{r[n]+=i;}});if(inc){oh=host.get(DRAG_NODE).get(OFFSET_HEIGHT);ow=host.get(DRAG_NODE).get(OFFSET_WIDTH);r[RIGHT]=r[RIGHT]-ow;r[BOTTOM]=r[BOTTOM]-oh;} +return r;},_checkRegion:function(_xy){var oxy=_xy,r=this.getRegion(),host=this.get(HOST),oh=host.get(DRAG_NODE).get(OFFSET_HEIGHT),ow=host.get(DRAG_NODE).get(OFFSET_WIDTH);if(oxy[1]>(r[BOTTOM]-oh)){_xy[1]=(r[BOTTOM]-oh);} +if(r[TOP]>oxy[1]){_xy[1]=r[TOP];} +if(oxy[0]>(r[RIGHT]-ow)){_xy[0]=(r[RIGHT]-ow);} +if(r[LEFT]>oxy[0]){_xy[0]=r[LEFT];} +return _xy;},inRegion:function(xy){xy=xy||this.get(HOST).get(DRAG_NODE).getXY();var _xy=this._checkRegion([xy[0],xy[1]]),inside=false;if((xy[0]===_xy[0])&&(xy[1]===_xy[1])){inside=true;} +return inside;},align:function(){var host=this.get(HOST),_xy=host.actXY,r=this.getRegion(true);if(this.get('stickX')){_xy[1]=(host.startXY[1]-host.deltaXY[1]);} +if(this.get('stickY')){_xy[0]=(host.startXY[0]-host.deltaXY[0]);} +if(r){_xy=this._checkRegion(_xy);} +_xy=this._checkTicks(_xy,r);host.actXY=_xy;},_checkTicks:function(xy,r){var host=this.get(HOST),lx=(host.startXY[0]-host.deltaXY[0]),ly=(host.startXY[1]-host.deltaXY[1]),xt=this.get('tickX'),yt=this.get('tickY');if(xt&&!this.get(TICK_X_ARRAY)){xy[0]=DDM._calcTicks(xy[0],lx,xt,r[LEFT],r[RIGHT]);} +if(yt&&!this.get(TICK_Y_ARRAY)){xy[1]=DDM._calcTicks(xy[1],ly,yt,r[TOP],r[BOTTOM]);} +if(this.get(TICK_X_ARRAY)){xy[0]=DDM._calcTickArray(xy[0],this.get(TICK_X_ARRAY),r[LEFT],r[RIGHT]);} +if(this.get(TICK_Y_ARRAY)){xy[1]=DDM._calcTickArray(xy[1],this.get(TICK_Y_ARRAY),r[TOP],r[BOTTOM]);} +return xy;}};Y.namespace('Plugin');Y.extend(C,Y.Base,proto);Y.Plugin.DDConstrained=C;Y.mix(DDM,{_calcTicks:function(pos,start,tick,off1,off2){var ix=((pos-start)/tick),min=Math.floor(ix),max=Math.ceil(ix);if((min!==0)||(max!==0)){if((ix>=min)&&(ix<=max)){pos=(start+(tick*min));if(off1&&off2){if(posoff2){pos=(start+(tick*(min-1)));}}}} +return pos;},_calcTickArray:function(pos,ticks,off1,off2){var i=0,len=ticks.length,next=0,diff1,diff2,ret;if(!ticks||(ticks.length===0)){return pos;}else if(ticks[0]>=pos){return ticks[0];}else{for(i=0;i=pos){diff1=pos-ticks[i];diff2=ticks[next]-pos;ret=(diff2>diff1)?ticks[i]:ticks[next];if(off1&&off2){if(ret>off2){if(ticks[i]){ret=ticks[i];}else{ret=ticks[len-1];}}} +return ret;}} +return ticks[ticks.length-1];}}});},'3.0.0',{requires:['dd-drag'],skinnable:false});YUI.add('dd-scroll',function(Y){var S=function(){S.superclass.constructor.apply(this,arguments);},HOST='host',BUFFER='buffer',PARENT_SCROLL='parentScroll',WINDOW_SCROLL='windowScroll',SCROLL_TOP='scrollTop',SCROLL_LEFT='scrollLeft',OFFSET_WIDTH='offsetWidth',OFFSET_HEIGHT='offsetHeight';S.ATTRS={parentScroll:{value:false,setter:function(node){if(node){return node;} +return false;}},buffer:{value:30},scrollDelay:{value:235},host:{value:null},windowScroll:{value:false},vertical:{value:true},horizontal:{value:true}};Y.extend(S,Y.Base,{_scrolling:null,_vpRegionCache:null,_dimCache:null,_scrollTimer:null,_getVPRegion:function(){var r={};var n=this.get(PARENT_SCROLL),b=this.get(BUFFER),ws=this.get(WINDOW_SCROLL),xy=((ws)?[]:n.getXY()),w=((ws)?'winWidth':OFFSET_WIDTH),h=((ws)?'winHeight':OFFSET_HEIGHT),t=((ws)?n.get(SCROLL_TOP):xy[1]),l=((ws)?n.get(SCROLL_LEFT):xy[0]);r={top:t+b,right:(n.get(w)+l)-b,bottom:(n.get(h)+t)-b,left:l+b};this._vpRegionCache=r;return r;},initializer:function(){var h=this.get(HOST);h.after('drag:start',Y.bind(this.start,this));h.after('drag:end',Y.bind(this.end,this));h.on('drag:align',Y.bind(this.align,this));Y.get(window).on('scroll',Y.bind(function(){this._vpRegionCache=null;},this));},_checkWinScroll:function(move){var r=this._getVPRegion(),ho=this.get(HOST),ws=this.get(WINDOW_SCROLL),xy=ho.lastXY,scroll=false,b=this.get(BUFFER),win=this.get(PARENT_SCROLL),sTop=win.get(SCROLL_TOP),sLeft=win.get(SCROLL_LEFT),w=this._dimCache.w,h=this._dimCache.h,bottom=xy[1]+h,top=xy[1],right=xy[0]+w,left=xy[0],nt=top,nl=left,st=sTop,sl=sLeft;if(this.get('horizontal')){if(left<=r.left){scroll=true;nl=xy[0]-((ws)?b:0);sl=sLeft-b;} +if(right>=r.right){scroll=true;nl=xy[0]+((ws)?b:0);sl=sLeft+b;}} +if(this.get('vertical')){if(bottom>=r.bottom){scroll=true;nt=xy[1]+((ws)?b:0);st=sTop+b;} +if(top<=r.top){scroll=true;nt=xy[1]-((ws)?b:0);st=sTop-b;}} +if(st<0){st=0;nt=xy[1];} +if(sl<0){sl=0;nl=xy[0];} +if(nt<0){nt=xy[1];} +if(nl<0){nl=xy[0];} +if(move){ho.actXY=[nl,nt];ho._moveNode({node:win,top:st,left:sl});if(!st&&!sl){this._cancelScroll();}}else{if(scroll){this._initScroll();}else{this._cancelScroll();}}},_initScroll:function(){this._cancelScroll();this._scrollTimer=Y.Lang.later(this.get('scrollDelay'),this,this._checkWinScroll,[true],true);},_cancelScroll:function(){this._scrolling=false;if(this._scrollTimer){this._scrollTimer.cancel();delete this._scrollTimer;}},align:function(e){if(this._scrolling){this._cancelScroll();e.preventDefault();} +if(!this._scrolling){this._checkWinScroll();}},_setDimCache:function(){var node=this.get(HOST).get('dragNode');this._dimCache={h:node.get(OFFSET_HEIGHT),w:node.get(OFFSET_WIDTH)};},start:function(){this._setDimCache();},end:function(xy){this._dimCache=null;this._cancelScroll();},toString:function(){return S.NAME+' #'+this.get('node').get('id');}});Y.namespace('Plugin');var WS=function(){WS.superclass.constructor.apply(this,arguments);};WS.ATTRS=Y.merge(S.ATTRS,{windowScroll:{value:true,setter:function(scroll){if(scroll){this.set(PARENT_SCROLL,Y.get(window));} +return scroll;}}});Y.extend(WS,S,{initializer:function(){this.set('windowScroll',this.get('windowScroll'));}});WS.NAME=WS.NS='winscroll';Y.Plugin.DDWinScroll=WS;var NS=function(){NS.superclass.constructor.apply(this,arguments);};NS.ATTRS=Y.merge(S.ATTRS,{node:{value:false,setter:function(node){var n=Y.get(node);if(!n){if(node!==false){Y.error('DDNodeScroll: Invalid Node Given: '+node);}}else{n=n.item(0);this.set(PARENT_SCROLL,n);} +return n;}}});Y.extend(NS,S,{initializer:function(){this.set('node',this.get('node'));}});NS.NAME=NS.NS='nodescroll';Y.Plugin.DDNodeScroll=NS;Y.DD.Scroll=S;},'3.0.0',{skinnable:false,requires:['dd-drag'],optional:['dd-proxy']});YUI.add('dd-plugin',function(Y){var Drag=function(config){config.node=((Y.Widget&&config.host instanceof Y.Widget)?config.host.get('boundingBox'):config.host);Drag.superclass.constructor.apply(this,arguments);};Drag.NAME="dd-plugin";Drag.NS="dd";Y.extend(Drag,Y.DD.Drag);Y.namespace('Plugin');Y.Plugin.Drag=Drag;},'3.0.0',{skinnable:false,requires:['dd-drag'],optional:['dd-constrain','dd-proxy']});YUI.add('dd-drop',function(Y){var NODE='node',DDM=Y.DD.DDM,OFFSET_HEIGHT='offsetHeight',OFFSET_WIDTH='offsetWidth',EV_DROP_OVER='drop:over',EV_DROP_ENTER='drop:enter',EV_DROP_EXIT='drop:exit',Drop=function(){this._lazyAddAttrs=false;Drop.superclass.constructor.apply(this,arguments);Y.on('domready',Y.bind(function(){Y.later(100,this,this._createShim);},this));DDM._regTarget(this);};Drop.NAME='drop';Drop.ATTRS={node:{setter:function(node){var n=Y.Node.get(node);if(!n){Y.error('DD.Drop: Invalid Node Given: '+node);} +return n;}},groups:{value:['default'],setter:function(g){this._groups={};Y.each(g,function(v,k){this._groups[v]=true;},this);return g;}},padding:{value:'0',setter:function(p){return DDM.cssSizestoObject(p);}},lock:{value:false,setter:function(lock){if(lock){this.get(NODE).addClass(DDM.CSS_PREFIX+'-drop-locked');}else{this.get(NODE).removeClass(DDM.CSS_PREFIX+'-drop-locked');} +return lock;}},bubbles:{writeOnce:true,value:Y.DD.DDM}};Y.extend(Drop,Y.Base,{_createEvents:function(){var ev=[EV_DROP_OVER,EV_DROP_ENTER,EV_DROP_EXIT,'drop:hit'];Y.each(ev,function(v,k){this.publish(v,{type:v,emitFacade:true,preventable:false,bubbles:true,queuable:false,prefix:'drop'});},this);if(this.get('bubbles')){this.addTarget(this.get('bubbles'));}},_valid:null,_groups:null,shim:null,region:null,overTarget:null,inGroup:function(groups){this._valid=false;var ret=false;Y.each(groups,function(v,k){if(this._groups[v]){ret=true;this._valid=true;}},this);return ret;},initializer:function(){Y.later(100,this,this._createEvents);var node=this.get(NODE),id;if(!node.get('id')){id=Y.stamp(node);node.set('id',id);} +node.addClass(DDM.CSS_PREFIX+'-drop');this.set('groups',this.get('groups'));},destructor:function(){DDM._unregTarget(this);if(this.shim){this.shim.detachAll();this.shim.get('parentNode').removeChild(this.shim);this.shim=null;} +this.get(NODE).removeClass(DDM.CSS_PREFIX+'-drop');this.detachAll();},_deactivateShim:function(){if(!this.shim){return false;} +this.get(NODE).removeClass(DDM.CSS_PREFIX+'-drop-active-valid');this.get(NODE).removeClass(DDM.CSS_PREFIX+'-drop-active-invalid');this.get(NODE).removeClass(DDM.CSS_PREFIX+'-drop-over');this.shim.setStyles({top:'-999px',left:'-999px',zIndex:'1'});this.overTarget=false;},_activateShim:function(){if(!DDM.activeDrag){return false;} +if(this.get(NODE)===DDM.activeDrag.get(NODE)){return false;} +if(this.get('lock')){return false;} +var node=this.get(NODE);if(this.inGroup(DDM.activeDrag.get('groups'))){node.removeClass(DDM.CSS_PREFIX+'-drop-active-invalid');node.addClass(DDM.CSS_PREFIX+'-drop-active-valid');DDM._addValid(this);this.overTarget=false;this.sizeShim();}else{DDM._removeValid(this);node.removeClass(DDM.CSS_PREFIX+'-drop-active-valid');node.addClass(DDM.CSS_PREFIX+'-drop-active-invalid');}},sizeShim:function(){if(!DDM.activeDrag){return false;} +if(this.get(NODE)===DDM.activeDrag.get(NODE)){return false;} +if(this.get('lock')){return false;} +if(!this.shim){Y.later(100,this,this.sizeShim);return false;} +var node=this.get(NODE),nh=node.get(OFFSET_HEIGHT),nw=node.get(OFFSET_WIDTH),xy=node.getXY(),p=this.get('padding'),dd,dH,dW;nw=nw+p.left+p.right;nh=nh+p.top+p.bottom;xy[0]=xy[0]-p.left;xy[1]=xy[1]-p.top;if(DDM.activeDrag.get('dragMode')===DDM.INTERSECT){dd=DDM.activeDrag;dH=dd.get(NODE).get(OFFSET_HEIGHT);dW=dd.get(NODE).get(OFFSET_WIDTH);nh=(nh+dH);nw=(nw+dW);xy[0]=xy[0]-(dW-dd.deltaXY[0]);xy[1]=xy[1]-(dH-dd.deltaXY[1]);} +this.shim.setStyles({height:nh+'px',width:nw+'px',top:xy[1]+'px',left:xy[0]+'px'});this.region={'0':xy[0],'1':xy[1],area:0,top:xy[1],right:xy[0]+nw,bottom:xy[1]+nh,left:xy[0]};},_createShim:function(){if(!DDM._pg){Y.later(10,this,this._createShim);return;} +if(this.shim){return;} +var s=Y.Node.create('
    ');s.setStyles({height:this.get(NODE).get(OFFSET_HEIGHT)+'px',width:this.get(NODE).get(OFFSET_WIDTH)+'px',backgroundColor:'yellow',opacity:'.5',zIndex:'1',overflow:'hidden',top:'-900px',left:'-900px',position:'absolute'});DDM._pg.appendChild(s);this.shim=s;s.on('mouseover',Y.bind(this._handleOverEvent,this));s.on('mouseout',Y.bind(this._handleOutEvent,this));},_handleTargetOver:function(){if(DDM.isOverTarget(this)){this.get(NODE).addClass(DDM.CSS_PREFIX+'-drop-over');DDM.activeDrop=this;DDM.otherDrops[this]=this;if(this.overTarget){DDM.activeDrag.fire('drag:over',{drop:this,drag:DDM.activeDrag});this.fire(EV_DROP_OVER,{drop:this,drag:DDM.activeDrag});}else{this.overTarget=true;this.fire(EV_DROP_ENTER,{drop:this,drag:DDM.activeDrag});DDM.activeDrag.fire('drag:enter',{drop:this,drag:DDM.activeDrag});DDM.activeDrag.get(NODE).addClass(DDM.CSS_PREFIX+'-drag-over');}}else{this._handleOut();}},_handleOverEvent:function(){this.shim.setStyle('zIndex','999');DDM._addActiveShim(this);},_handleOutEvent:function(){this.shim.setStyle('zIndex','1');DDM._removeActiveShim(this);},_handleOut:function(force){if(!DDM.isOverTarget(this)||force){if(this.overTarget){this.overTarget=false;if(!force){DDM._removeActiveShim(this);} +if(DDM.activeDrag){this.get(NODE).removeClass(DDM.CSS_PREFIX+'-drop-over');DDM.activeDrag.get(NODE).removeClass(DDM.CSS_PREFIX+'-drag-over');this.fire(EV_DROP_EXIT);DDM.activeDrag.fire('drag:exit',{drop:this});delete DDM.otherDrops[this];}}}}});Y.DD.Drop=Drop;},'3.0.0',{requires:['dd-ddm-drop','dd-drag'],skinnable:false});YUI.add('dd-drop-plugin',function(Y){var Drop=function(config){config.node=config.host;Drop.superclass.constructor.apply(this,arguments);};Drop.NAME="dd-drop-plugin";Drop.NS="drop";Y.extend(Drop,Y.DD.Drop);Y.namespace('Plugin');Y.Plugin.Drop=Drop;},'3.0.0',{requires:['dd-drop'],skinnable:false});YUI.add('dd',function(Y){},'3.0.0',{use:['dd-ddm-base','dd-ddm','dd-ddm-drop','dd-drag','dd-proxy','dd-constrain','dd-plugin','dd-drop','dd-drop-plugin','dd-scroll'],skinnable:false}); \ No newline at end of file diff --git a/include/javascript/yui3/build/dom/dom-base-min.js b/include/javascript/yui3/build/dom/dom-base-min.js new file mode 100644 index 00000000..38ca661f --- /dev/null +++ b/include/javascript/yui3/build/dom/dom-base-min.js @@ -0,0 +1,8 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add("dom-base",function(D){(function(H){var R="nodeType",F="ownerDocument",E="defaultView",J="parentWindow",M="tagName",O="parentNode",Q="firstChild",L="previousSibling",P="nextSibling",K="contains",G="compareDocumentPosition",N=document.documentElement,I=/<([a-z]+)/i;H.DOM={byId:function(T,S){S=S||H.config.doc;return S.getElementById(T);},children:function(U,S){var T=[];if(U){S=S||"*";T=H.Selector.query("> "+S,U);}return T;},firstByTag:function(S,T){var U;T=T||H.config.doc;if(S&&T.getElementsByTagName){U=T.getElementsByTagName(S)[0];}return U||null;},getText:(N.textContent!==undefined)?function(T){var S="";if(T){S=T.textContent;}return S||"";}:function(T){var S="";if(T){S=T.innerText;}return S||"";},setText:(N.textContent!==undefined)?function(S,T){if(S){S.textContent=T;}}:function(S,T){if(S){S.innerText=T;}},previous:function(S,U,T){return H.DOM.elementByAxis(S,L,U,T);},next:function(S,U,T){return H.DOM.elementByAxis(S,P,U,T);},ancestor:function(S,U,T){return H.DOM.elementByAxis(S,O,U,T);},elementByAxis:function(S,V,U,T){while(S&&(S=S[V])){if((T||S[M])&&(!U||U(S))){return S;}}return null;},contains:function(T,U){var S=false;if(!U||!T||!U[R]||!T[R]){S=false;}else{if(T[K]){if(H.UA.opera||U[R]===1){S=T[K](U);}else{S=H.DOM._bruteContains(T,U);}}else{if(T[G]){if(T===U||!!(T[G](U)&16)){S=true;}}}}return S;},inDoc:function(S,T){T=T||S[F];var U=S.id;if(!U){U=S.id=H.guid();}return!!(T.getElementById(U));},create:function(X,Z){if(typeof X==="string"){X=H.Lang.trim(X);}if(!Z&&H.DOM._cloneCache[X]){return H.DOM._cloneCache[X].cloneNode(true);}Z=Z||H.config.doc;var T=I.exec(X),W=H.DOM._create,Y=H.DOM.creators,V=null,S,U;if(T&&Y[T[1]]){if(typeof Y[T[1]]==="function"){W=Y[T[1]];}else{S=Y[T[1]];}}U=W(X,Z,S).childNodes;if(U.length===1){V=U[0].parentNode.removeChild(U[0]);}else{V=H.DOM._nl2frag(U,Z);}if(V){H.DOM._cloneCache[X]=V.cloneNode(true);}return V;},_nl2frag:function(T,W){var U=null,V,S;if(T&&(T.push||T.item)&&T[0]){W=W||T[0].ownerDocument;U=W.createDocumentFragment();if(T.item){T=H.Array(T,0,true);}for(V=0,S=T.length;V)+\s*1&&Y&&!V.test(Z)){Y[O].removeChild(Y);}return b;},script:function(Y,Z){var a=Z.createElement("div");a.innerHTML="-"+Y;a.removeChild(a[Q]);return a;}},true);W.mix(W.DOM.VALUE_GETTERS,{button:function(Y){return(Y.attributes&&Y.attributes.value)?Y.attributes.value.value:"";}});W.mix(W.DOM.VALUE_SETTERS,{button:function(Z,a){var Y=Z.attributes.value;if(!Y){Y=Z[F].createAttribute("value");Z.setAttributeNode(Y);}Y.value=a;}});}if(W.UA.gecko||W.UA.ie){W.mix(X,{option:function(Y,Z){return S("",Z);},tr:function(Y,Z){return S(""+Y+"",Z);},td:function(Y,Z){return S(""+Y+"",Z);},tbody:function(Y,Z){return S(U+Y+T,Z);}});W.mix(X,{legend:"fieldset",th:X.td,thead:X.tbody,tfoot:X.tbody,caption:X.tbody,colgroup:X.tbody,col:X.tbody,optgroup:X.option});}W.mix(W.DOM.VALUE_GETTERS,{option:function(Z){var Y=Z.attributes;return(Y.value&&Y.value.specified)?Z.value:Z.text;},select:function(Z){var a=Z.value,Y=Z.options;if(Y&&a===""){if(Z.multiple){}else{a=W.DOM.getValue(Y[Z.selectedIndex],"value");}}return a;}});})(H);})(D);var B,A,C;D.mix(D.DOM,{hasClass:function(G,F){var E=D.DOM._getRegExp("(?:^|\\s+)"+F+"(?:\\s+|$)");return E.test(G.className);},addClass:function(F,E){if(!D.DOM.hasClass(F,E)){F.className=D.Lang.trim([F.className,E].join(" "));}},removeClass:function(F,E){if(E&&A(F,E)){F.className=D.Lang.trim(F.className.replace(D.DOM._getRegExp("(?:^|\\s+)"+E+"(?:\\s+|$)")," "));if(A(F,E)){C(F,E);}}},replaceClass:function(F,E,G){B(F,G);C(F,E);},toggleClass:function(F,E){if(A(F,E)){C(F,E);}else{B(F,E);}}});A=D.DOM.hasClass;C=D.DOM.removeClass;B=D.DOM.addClass;},"3.0.0",{requires:["oop"]}); \ No newline at end of file diff --git a/include/javascript/yui3/build/dom/dom-base.js b/include/javascript/yui3/build/dom/dom-base.js new file mode 100644 index 00000000..3b7fc0e1 --- /dev/null +++ b/include/javascript/yui3/build/dom/dom-base.js @@ -0,0 +1,40 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add('dom-base',function(Y){(function(Y){var NODE_TYPE='nodeType',OWNER_DOCUMENT='ownerDocument',DEFAULT_VIEW='defaultView',PARENT_WINDOW='parentWindow',TAG_NAME='tagName',PARENT_NODE='parentNode',FIRST_CHILD='firstChild',PREVIOUS_SIBLING='previousSibling',NEXT_SIBLING='nextSibling',CONTAINS='contains',COMPARE_DOCUMENT_POSITION='compareDocumentPosition',documentElement=document.documentElement,re_tag=/<([a-z]+)/i;Y.DOM={byId:function(id,doc){doc=doc||Y.config.doc;return doc.getElementById(id);},children:function(node,tag){var ret=[];if(node){tag=tag||'*';ret=Y.Selector.query('> '+tag,node);} +return ret;},firstByTag:function(tag,root){var ret;root=root||Y.config.doc;if(tag&&root.getElementsByTagName){ret=root.getElementsByTagName(tag)[0];} +return ret||null;},getText:(documentElement.textContent!==undefined)?function(element){var ret='';if(element){ret=element.textContent;} +return ret||'';}:function(element){var ret='';if(element){ret=element.innerText;} +return ret||'';},setText:(documentElement.textContent!==undefined)?function(element,content){if(element){element.textContent=content;}}:function(element,content){if(element){element.innerText=content;}},previous:function(element,fn,all){return Y.DOM.elementByAxis(element,PREVIOUS_SIBLING,fn,all);},next:function(element,fn,all){return Y.DOM.elementByAxis(element,NEXT_SIBLING,fn,all);},ancestor:function(element,fn,all){return Y.DOM.elementByAxis(element,PARENT_NODE,fn,all);},elementByAxis:function(element,axis,fn,all){while(element&&(element=element[axis])){if((all||element[TAG_NAME])&&(!fn||fn(element))){return element;}} +return null;},contains:function(element,needle){var ret=false;if(!needle||!element||!needle[NODE_TYPE]||!element[NODE_TYPE]){ret=false;}else if(element[CONTAINS]){if(Y.UA.opera||needle[NODE_TYPE]===1){ret=element[CONTAINS](needle);}else{ret=Y.DOM._bruteContains(element,needle);}}else if(element[COMPARE_DOCUMENT_POSITION]){if(element===needle||!!(element[COMPARE_DOCUMENT_POSITION](needle)&16)){ret=true;}} +return ret;},inDoc:function(element,doc){doc=doc||element[OWNER_DOCUMENT];var id=element.id;if(!id){id=element.id=Y.guid();} +return!!(doc.getElementById(id));},create:function(html,doc){if(typeof html==='string'){html=Y.Lang.trim(html);} +if(!doc&&Y.DOM._cloneCache[html]){return Y.DOM._cloneCache[html].cloneNode(true);} +doc=doc||Y.config.doc;var m=re_tag.exec(html),create=Y.DOM._create,custom=Y.DOM.creators,ret=null,tag,nodes;if(m&&custom[m[1]]){if(typeof custom[m[1]]==='function'){create=custom[m[1]];}else{tag=custom[m[1]];}} +nodes=create(html,doc,tag).childNodes;if(nodes.length===1){ret=nodes[0].parentNode.removeChild(nodes[0]);}else{ret=Y.DOM._nl2frag(nodes,doc);} +if(ret){Y.DOM._cloneCache[html]=ret.cloneNode(true);} +return ret;},_nl2frag:function(nodes,doc){var ret=null,i,len;if(nodes&&(nodes.push||nodes.item)&&nodes[0]){doc=doc||nodes[0].ownerDocument;ret=doc.createDocumentFragment();if(nodes.item){nodes=Y.Array(nodes,0,true);} +for(i=0,len=nodes.length;i)+\s*1&&tb&&!re_tbody.test(html)){tb[PARENT_NODE].removeChild(tb);} +return frag;},script:function(html,doc){var frag=doc.createElement('div');frag.innerHTML='-'+html;frag.removeChild(frag[FIRST_CHILD]);return frag;}},true);Y.mix(Y.DOM.VALUE_GETTERS,{button:function(node){return(node.attributes&&node.attributes.value)?node.attributes.value.value:'';}});Y.mix(Y.DOM.VALUE_SETTERS,{button:function(node,val){var attr=node.attributes.value;if(!attr){attr=node[OWNER_DOCUMENT].createAttribute('value');node.setAttributeNode(attr);} +attr.value=val;}});} +if(Y.UA.gecko||Y.UA.ie){Y.mix(creators,{option:function(html,doc){return create('',doc);},tr:function(html,doc){return create(''+html+'',doc);},td:function(html,doc){return create(''+html+'',doc);},tbody:function(html,doc){return create(TABLE_OPEN+html+TABLE_CLOSE,doc);}});Y.mix(creators,{legend:'fieldset',th:creators.td,thead:creators.tbody,tfoot:creators.tbody,caption:creators.tbody,colgroup:creators.tbody,col:creators.tbody,optgroup:creators.option});} +Y.mix(Y.DOM.VALUE_GETTERS,{option:function(node){var attrs=node.attributes;return(attrs.value&&attrs.value.specified)?node.value:node.text;},select:function(node){var val=node.value,options=node.options;if(options&&val===''){if(node.multiple){}else{val=Y.DOM.getValue(options[node.selectedIndex],'value');}} +return val;}});})(Y);})(Y);var addClass,hasClass,removeClass;Y.mix(Y.DOM,{hasClass:function(node,className){var re=Y.DOM._getRegExp('(?:^|\\s+)'+className+'(?:\\s+|$)');return re.test(node.className);},addClass:function(node,className){if(!Y.DOM.hasClass(node,className)){node.className=Y.Lang.trim([node.className,className].join(' '));}},removeClass:function(node,className){if(className&&hasClass(node,className)){node.className=Y.Lang.trim(node.className.replace(Y.DOM._getRegExp('(?:^|\\s+)'+ +className+'(?:\\s+|$)'),' '));if(hasClass(node,className)){removeClass(node,className);}}},replaceClass:function(node,oldC,newC){addClass(node,newC);removeClass(node,oldC);},toggleClass:function(node,className){if(hasClass(node,className)){removeClass(node,className);}else{addClass(node,className);}}});hasClass=Y.DOM.hasClass;removeClass=Y.DOM.removeClass;addClass=Y.DOM.addClass;},'3.0.0',{requires:['oop']}); \ No newline at end of file diff --git a/include/javascript/yui3/build/dom/dom-min.js b/include/javascript/yui3/build/dom/dom-min.js new file mode 100644 index 00000000..cbca3319 --- /dev/null +++ b/include/javascript/yui3/build/dom/dom-min.js @@ -0,0 +1,8 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add("dom-base",function(D){(function(H){var R="nodeType",F="ownerDocument",E="defaultView",J="parentWindow",M="tagName",O="parentNode",Q="firstChild",L="previousSibling",P="nextSibling",K="contains",G="compareDocumentPosition",N=document.documentElement,I=/<([a-z]+)/i;H.DOM={byId:function(T,S){S=S||H.config.doc;return S.getElementById(T);},children:function(U,S){var T=[];if(U){S=S||"*";T=H.Selector.query("> "+S,U);}return T;},firstByTag:function(S,T){var U;T=T||H.config.doc;if(S&&T.getElementsByTagName){U=T.getElementsByTagName(S)[0];}return U||null;},getText:(N.textContent!==undefined)?function(T){var S="";if(T){S=T.textContent;}return S||"";}:function(T){var S="";if(T){S=T.innerText;}return S||"";},setText:(N.textContent!==undefined)?function(S,T){if(S){S.textContent=T;}}:function(S,T){if(S){S.innerText=T;}},previous:function(S,U,T){return H.DOM.elementByAxis(S,L,U,T);},next:function(S,U,T){return H.DOM.elementByAxis(S,P,U,T);},ancestor:function(S,U,T){return H.DOM.elementByAxis(S,O,U,T);},elementByAxis:function(S,V,U,T){while(S&&(S=S[V])){if((T||S[M])&&(!U||U(S))){return S;}}return null;},contains:function(T,U){var S=false;if(!U||!T||!U[R]||!T[R]){S=false;}else{if(T[K]){if(H.UA.opera||U[R]===1){S=T[K](U);}else{S=H.DOM._bruteContains(T,U);}}else{if(T[G]){if(T===U||!!(T[G](U)&16)){S=true;}}}}return S;},inDoc:function(S,T){T=T||S[F];var U=S.id;if(!U){U=S.id=H.guid();}return!!(T.getElementById(U));},create:function(X,Z){if(typeof X==="string"){X=H.Lang.trim(X);}if(!Z&&H.DOM._cloneCache[X]){return H.DOM._cloneCache[X].cloneNode(true);}Z=Z||H.config.doc;var T=I.exec(X),W=H.DOM._create,Y=H.DOM.creators,V=null,S,U;if(T&&Y[T[1]]){if(typeof Y[T[1]]==="function"){W=Y[T[1]];}else{S=Y[T[1]];}}U=W(X,Z,S).childNodes;if(U.length===1){V=U[0].parentNode.removeChild(U[0]);}else{V=H.DOM._nl2frag(U,Z);}if(V){H.DOM._cloneCache[X]=V.cloneNode(true);}return V;},_nl2frag:function(T,W){var U=null,V,S;if(T&&(T.push||T.item)&&T[0]){W=W||T[0].ownerDocument;U=W.createDocumentFragment();if(T.item){T=H.Array(T,0,true);}for(V=0,S=T.length;V)+\s*1&&Y&&!V.test(Z)){Y[O].removeChild(Y);}return b;},script:function(Y,Z){var a=Z.createElement("div");a.innerHTML="-"+Y;a.removeChild(a[Q]);return a;}},true);W.mix(W.DOM.VALUE_GETTERS,{button:function(Y){return(Y.attributes&&Y.attributes.value)?Y.attributes.value.value:"";}});W.mix(W.DOM.VALUE_SETTERS,{button:function(Z,a){var Y=Z.attributes.value;if(!Y){Y=Z[F].createAttribute("value");Z.setAttributeNode(Y);}Y.value=a;}});}if(W.UA.gecko||W.UA.ie){W.mix(X,{option:function(Y,Z){return S("",Z);},tr:function(Y,Z){return S(""+Y+"",Z);},td:function(Y,Z){return S(""+Y+"",Z);},tbody:function(Y,Z){return S(U+Y+T,Z);}});W.mix(X,{legend:"fieldset",th:X.td,thead:X.tbody,tfoot:X.tbody,caption:X.tbody,colgroup:X.tbody,col:X.tbody,optgroup:X.option});}W.mix(W.DOM.VALUE_GETTERS,{option:function(Z){var Y=Z.attributes;return(Y.value&&Y.value.specified)?Z.value:Z.text;},select:function(Z){var a=Z.value,Y=Z.options;if(Y&&a===""){if(Z.multiple){}else{a=W.DOM.getValue(Y[Z.selectedIndex],"value");}}return a;}});})(H);})(D);var B,A,C;D.mix(D.DOM,{hasClass:function(G,F){var E=D.DOM._getRegExp("(?:^|\\s+)"+F+"(?:\\s+|$)");return E.test(G.className);},addClass:function(F,E){if(!D.DOM.hasClass(F,E)){F.className=D.Lang.trim([F.className,E].join(" "));}},removeClass:function(F,E){if(E&&A(F,E)){F.className=D.Lang.trim(F.className.replace(D.DOM._getRegExp("(?:^|\\s+)"+E+"(?:\\s+|$)")," "));if(A(F,E)){C(F,E);}}},replaceClass:function(F,E,G){B(F,G);C(F,E);},toggleClass:function(F,E){if(A(F,E)){C(F,E);}else{B(F,E);}}});A=D.DOM.hasClass;C=D.DOM.removeClass;B=D.DOM.addClass;},"3.0.0",{requires:["oop"]});YUI.add("dom-style",function(A){(function(E){var C="documentElement",B="defaultView",D="ownerDocument",L="style",N="float",F="cssFloat",G="styleFloat",J="transparent",H="getComputedStyle",M=E.config.doc,I=undefined,K=/color$/i;E.mix(E.DOM,{CUSTOM_STYLES:{},setStyle:function(R,O,S,Q){Q=Q||R.style;var P=E.DOM.CUSTOM_STYLES;if(Q){if(S===null){S="";}if(O in P){if(P[O].set){P[O].set(R,S,Q);return;}else{if(typeof P[O]==="string"){O=P[O];}}}Q[O]=S;}},getStyle:function(R,O){var Q=R[L],P=E.DOM.CUSTOM_STYLES,S="";if(Q){if(O in P){if(P[O].get){return P[O].get(R,O,Q);}else{if(typeof P[O]==="string"){O=P[O];}}}S=Q[O];if(S===""){S=E.DOM[H](R,O);}}return S;},setStyles:function(P,Q){var O=P.style;E.each(Q,function(R,S){E.DOM.setStyle(P,S,R,O);},E.DOM);},getComputedStyle:function(P,O){var R="",Q=P[D];if(P[L]){R=Q[B][H](P,null)[O];}return R;}});if(M[C][L][F]!==I){E.DOM.CUSTOM_STYLES[N]=F;}else{if(M[C][L][G]!==I){E.DOM.CUSTOM_STYLES[N]=G;}}if(E.UA.opera){E.DOM[H]=function(Q,P){var O=Q[D][B],R=O[H](Q,"")[P];if(K.test(P)){R=E.Color.toRGB(R);}return R;};}if(E.UA.webkit){E.DOM[H]=function(Q,P){var O=Q[D][B],R=O[H](Q,"")[P];if(R==="rgba(0, 0, 0, 0)"){R=J;}return R;};}})(A);(function(D){var B=parseInt,C=RegExp;D.Color={KEYWORDS:{black:"000",silver:"c0c0c0",gray:"808080",white:"fff",maroon:"800000",red:"f00",purple:"800080",fuchsia:"f0f",green:"008000",lime:"0f0",olive:"808000",yellow:"ff0",navy:"000080",blue:"00f",teal:"008080",aqua:"0ff"},re_RGB:/^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i,re_hex:/^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i,re_hex3:/([0-9A-F])/gi,toRGB:function(E){if(!D.Color.re_RGB.test(E)){E=D.Color.toHex(E);}if(D.Color.re_hex.exec(E)){E="rgb("+[B(C.$1,16),B(C.$2,16),B(C.$3,16)].join(", ")+")";}return E;},toHex:function(F){F=D.Color.KEYWORDS[F]||F;if(D.Color.re_RGB.exec(F)){F=[Number(C.$1).toString(16),Number(C.$2).toString(16),Number(C.$3).toString(16)];for(var E=0;E-1)){a=c;}else{if(D.DOM.IE.COMPUTED[b]){a=D.DOM.IE.COMPUTED[b](Y,b);}else{if(P.test(c)){a=N.getPixel(Y,b)+K;}else{a=c;}}}}}return a;},sizeOffsets:{width:["Left","Right"],height:["Top","Bottom"],top:["Top"],bottom:["Bottom"]},getOffset:function(b,g){var d=E(b)[g],Y=g.charAt(0).toUpperCase()+g.substr(1),f="offset"+Y,a="pixel"+Y,e=N.sizeOffsets[g],c="";if(d===M||d.indexOf("%")>-1){c=b["offset"+Y];if(e[0]){c-=N.getPixel(b,"padding"+e[0]);c-=N.getBorderWidth(b,"border"+e[0]+"Width",1);}if(e[1]){c-=N.getPixel(b,"padding"+e[1]);c-=N.getBorderWidth(b,"border"+e[1]+"Width",1);}}else{if(!b.style[a]&&!b.style[g]){b.style[g]=d;}c=b.style[a];}return c+K;},borderMap:{thin:"2px",medium:"4px",thick:"6px"},getBorderWidth:function(a,c,Y){var b=Y?"":K,d=a.currentStyle[c];if(d.indexOf(K)<0){if(N.borderMap[d]){d=N.borderMap[d];}else{}}return(Y)?parseFloat(d):d;},getPixel:function(b,Y){var d=null,a=E(b),e=a.right,c=a[Y];b.style.right=c;d=b.style.pixelRight;b.style.right=e;return d;},getMargin:function(b,Y){var c,a=E(b);if(a[Y]==M){c=0;}else{c=N.getPixel(b,Y);}return c+K;},getVisibility:function(a,Y){var b;while((b=a.currentStyle)&&b[Y]=="inherit"){a=a.parentNode;}return(b)?b[Y]:S;},getColor:function(a,Y){var b=E(a)[Y];if(!b||b===R){D.DOM.elementByAxis(a,"parentNode",null,function(c){b=E(c)[Y];if(b&&b!==R){a=c;return true;}});}return D.Color.toRGB(b);},getBorderColor:function(a,Y){var b=E(a),c=b[Y]||b.color;return D.Color.toRGB(D.Color.toHex(c));}},F={};try{if(X.style[T]===Z&&X[B]){D.DOM.CUSTOM_STYLES[T]={get:function(a){var c=100;try{c=a[B]["DXImageTransform.Microsoft.Alpha"][T];}catch(b){try{c=a[B]("alpha")[T];}catch(Y){}}return c/100;},set:function(a,d,Y){var c,b;if(d===""){b=E(a);c=(T in b)?b[T]:1;d=c;}if(typeof Y[L]=="string"){Y[L]="alpha("+T+"="+d*100+")";if(!a.currentStyle||!a.currentStyle[W]){Y.zoom=1;}}}};}}catch(U){}try{document.createElement("div").style.height="-1px";}catch(U){D.DOM.CUSTOM_STYLES.height={set:function(b,c,a){var Y=parseFloat(c);if(isNaN(Y)||Y>=0){a.height=c;}else{}}};D.DOM.CUSTOM_STYLES.width={set:function(b,c,a){var Y=parseFloat(c);if(isNaN(Y)||Y>=0){a.width=c;}else{}}};}F[I]=F[O]=N.getOffset;F.color=F.backgroundColor=N.getColor;F[G]=F[J]=F[Q]=F[V]=F[H]=N.getBorderWidth;F.marginTop=F.marginRight=F.marginBottom=F.marginLeft=N.getMargin;F.visibility=N.getVisibility;F.borderColor=F.borderTopColor=F.borderRightColor=F.borderBottomColor=F.borderLeftColor=N.getBorderColor;if(!D.config.win[C]){D.DOM[C]=N.get;}D.namespace("DOM.IE");D.DOM.IE.COMPUTED=F;D.DOM.IE.ComputedStyle=N;})(A);},"3.0.0",{requires:["dom-base"]});YUI.add("dom-screen",function(A){(function(F){var D="documentElement",O="compatMode",M="position",C="fixed",K="relative",G="left",H="top",I="BackCompat",N="medium",E="borderLeftWidth",B="borderTopWidth",P="getBoundingClientRect",J="getComputedStyle",L=/^t(?:able|d|h)$/i;F.mix(F.DOM,{winHeight:function(R){var Q=F.DOM._getWinSize(R).height;return Q;},winWidth:function(R){var Q=F.DOM._getWinSize(R).width;return Q;},docHeight:function(R){var Q=F.DOM._getDocSize(R).height;return Math.max(Q,F.DOM._getWinSize(R).height);},docWidth:function(R){var Q=F.DOM._getDocSize(R).width;return Math.max(Q,F.DOM._getWinSize(R).width);},docScrollX:function(Q){var R=F.DOM._getDoc(Q);return Math.max(R[D].scrollLeft,R.body.scrollLeft);},docScrollY:function(Q){var R=F.DOM._getDoc(Q);return Math.max(R[D].scrollTop,R.body.scrollTop);},getXY:function(){if(document[D][P]){return function(T){var a=null,U,R,V,Y,X,Q,S,W,Z;if(T){if(F.DOM.inDoc(T)){U=F.DOM.docScrollX(T);R=F.DOM.docScrollY(T);V=T[P]();Z=F.DOM._getDoc(T);a=[V.left,V.top];if(F.UA.ie){Y=2;X=2;W=Z[O];Q=F.DOM[J](Z[D],E);S=F.DOM[J](Z[D],B);if(F.UA.ie===6){if(W!==I){Y=0;X=0;}}if((W==I)){if(Q!==N){Y=parseInt(Q,10);}if(S!==N){X=parseInt(S,10);}}a[0]-=Y;a[1]-=X;}if((R||U)){a[0]+=U;a[1]+=R;}}else{a=F.DOM._getOffset(T);}}return a;};}else{return function(R){var T=null,Q,V,S,U;if(R){if(F.DOM.inDoc(R)){T=[R.offsetLeft,R.offsetTop];Q=R;V=((F.UA.gecko||F.UA.webkit>519)?true:false);while((Q=Q.offsetParent)){T[0]+=Q.offsetLeft;T[1]+=Q.offsetTop;if(V){T=F.DOM._calcBorders(Q,T);}}if(F.DOM.getStyle(R,M)!=C){Q=R;while((Q=Q.parentNode)){S=Q.scrollTop;U=Q.scrollLeft;if(F.UA.gecko&&(F.DOM.getStyle(Q,"overflow")!=="visible")){T=F.DOM._calcBorders(Q,T);}if(S||U){T[0]-=U;T[1]-=S;}}T[0]+=F.DOM.docScrollX(R);T[1]+=F.DOM.docScrollY(R);}else{T[0]+=F.DOM.docScrollX(R);T[1]+=F.DOM.docScrollY(R);}}else{T=F.DOM._getOffset(R);}}return T;};}}(),_getOffset:function(Q){var S,R=null;if(Q){S=F.DOM.getStyle(Q,M);R=[parseInt(F.DOM[J](Q,G),10),parseInt(F.DOM[J](Q,H),10)];if(isNaN(R[0])){R[0]=parseInt(F.DOM.getStyle(Q,G),10);if(isNaN(R[0])){R[0]=(S===K)?0:Q.offsetLeft||0;}}if(isNaN(R[1])){R[1]=parseInt(F.DOM.getStyle(Q,H),10);if(isNaN(R[1])){R[1]=(S===K)?0:Q.offsetTop||0;}}}return R;},getX:function(Q){return F.DOM.getXY(Q)[0];},getY:function(Q){return F.DOM.getXY(Q)[1];},setXY:function(R,U,X){var S=F.DOM.setStyle,W,V,Q,T;if(R&&U){W=F.DOM.getStyle(R,M);V=F.DOM._getOffset(R);if(W=="static"){W=K;S(R,M,W);}T=F.DOM.getXY(R);if(U[0]!==null){S(R,G,U[0]-T[0]+V[0]+"px");}if(U[1]!==null){S(R,H,U[1]-T[1]+V[1]+"px");}if(!X){Q=F.DOM.getXY(R);if(Q[0]!==U[0]||Q[1]!==U[1]){F.DOM.setXY(R,U,true);}}}else{}},setX:function(R,Q){return F.DOM.setXY(R,[Q,null]);},setY:function(Q,R){return F.DOM.setXY(Q,[null,R]);},_calcBorders:function(S,T){var R=parseInt(F.DOM[J](S,B),10)||0,Q=parseInt(F.DOM[J](S,E),10)||0;if(F.UA.gecko){if(L.test(S.tagName)){R=0;Q=0;}}T[0]+=Q;T[1]+=R;return T;},_getWinSize:function(T){var V=F.DOM._getDoc(),U=V.defaultView||V.parentWindow,W=V[O],S=U.innerHeight,R=U.innerWidth,Q=V[D];if(W&&!F.UA.opera){if(W!="CSS1Compat"){Q=V.body;}S=Q.clientHeight;R=Q.clientWidth;}return{height:S,width:R};},_getDocSize:function(R){var S=F.DOM._getDoc(),Q=S[D];if(S[O]!="CSS1Compat"){Q=S.body;}return{height:Q.scrollHeight,width:Q.scrollWidth};}});})(A);(function(G){var D="top",C="right",H="bottom",B="left",F=function(L,K){var N=Math.max(L[D],K[D]),O=Math.min(L[C],K[C]),I=Math.min(L[H],K[H]),J=Math.max(L[B],K[B]),M={};M[D]=N;M[C]=O;M[H]=I;M[B]=J;return M;},E=G.DOM;G.mix(E,{region:function(J){var K=E.getXY(J),I=false;if(J&&K){I=E._getRegion(K[1],K[0]+J.offsetWidth,K[1]+J.offsetHeight,K[0]);}return I;},intersect:function(K,I,M){var J=M||E.region(K),L={},O=I,N;if(O.tagName){L=E.region(O);}else{if(G.Lang.isObject(I)){L=I;}else{return false;}}N=F(L,J);return{top:N[D],right:N[C],bottom:N[H],left:N[B],area:((N[H]-N[D])*(N[C]-N[B])),yoff:((N[H]-N[D])),xoff:(N[C]-N[B]),inRegion:E.inRegion(K,I,false,M)};},inRegion:function(L,I,J,N){var M={},K=N||E.region(L),P=I,O;if(P.tagName){M=E.region(P);}else{if(G.Lang.isObject(I)){M=I;}else{return false;}}if(J){return(K[B]>=M[B]&&K[C]<=M[C]&&K[D]>=M[D]&&K[H]<=M[H]);}else{O=F(M,K);if(O[H]>=O[D]&&O[C]>=O[B]){return true;}else{return false;}}},inViewportRegion:function(J,I,K){return E.inRegion(J,E.viewportRegion(J),I,K);},_getRegion:function(K,L,I,J){var M={};M[D]=M[1]=K;M[B]=M[0]=J;M[H]=I;M[C]=L;M.width=M[C]-M[B];M.height=M[H]-M[D];return M;},viewportRegion:function(J){J=J||G.config.doc.documentElement;var I=false,L,K;if(J){L=E.docScrollX(J);K=E.docScrollY(J);I=E._getRegion(K,E.winWidth(J)+L,K+E.winHeight(J),L);}return I;}});})(A);},"3.0.0",{requires:["dom-base","dom-style"]});YUI.add("selector-native",function(A){(function(G){G.namespace("Selector");var E="compareDocumentPosition",F="ownerDocument",D="yui-tmp-",C=0;var B={_foundCache:[],useNative:true,_compare:("sourceIndex"in document.documentElement)?function(K,J){var I=K.sourceIndex,H=J.sourceIndex;if(I===H){return 0;}else{if(I>H){return 1;}}return-1;}:(document.documentElement[E]?function(I,H){if(I[E](H)&4){return-1;}else{return 1;}}:function(L,K){var J,H,I;if(L&&K){J=L[F].createRange();J.setStart(L,0);H=K[F].createRange();H.setStart(K,0);I=J.compareBoundaryPoints(1,H);}return I;}),_sort:function(H){if(H){H=G.Array(H,0,true);if(H.sort){H.sort(B._compare);}}return H;},_deDupe:function(H){var I=[],J,K;for(J=0;(K=H[J++]);){if(!K._found){I[I.length]=K;K._found=true;}}for(J=0;(K=I[J++]);){K._found=null;K.removeAttribute("_found");}return I;},query:function(I,P,Q,H){P=P||G.config.doc;var M=[],J=(G.Selector.useNative&&document.querySelector&&!H),L=[[I,P]],N,R,K,O=(J)?G.Selector._nativeQuery:G.Selector._bruteQuery;if(I&&O){if(!H&&(!J||P.tagName)){L=B._splitQueries(I,P);}for(K=0;(N=L[K++]);){R=O(N[0],N[1],Q);if(!Q){R=G.Array(R,0,true);}if(R){M=M.concat(R);}}if(L.length>1){M=B._sort(B._deDupe(M));}}return(Q)?(M[0]||null):M;},_splitQueries:function(J,M){var I=J.split(","),K=[],N="",L,H;if(M){if(M.tagName){M.id=M.id||G.guid();N="#"+M.id+" ";}for(L=0,H=I.length;L":{axis:"parentNode",direct:true},"+":{axis:"previousSibling",direct:true}},_parsers:[{name:E,re:/^\[([a-z]+\w*)+([~\|\^\$\*!=]=?)?['"]?([^\]]*?)['"]?\]/i,fn:function(K,L){var J=K[2]||"",I=G.Selector.operators,M;if((K[1]==="id"&&J==="=")||(K[1]==="className"&&document.getElementsByClassName&&(J==="~="||J==="="))){L.prefilter=K[1];L[K[1]]=K[3];}if(J in I){M=I[J];if(typeof M==="string"){M=G.Selector._getRegExp(M.replace("{val}",K[3]));}K[2]=M;}if(!L.last||L.prefilter!==K[1]){return K.slice(1);}}},{name:D,re:/^((?:-?[_a-z]+[\w-]*)|\*)/i,fn:function(J,K){var I=J[1].toUpperCase();K.tagName=I;if(I!=="*"&&(!K.last||K.prefilter)){return[D,"=",I];}if(!K.prefilter){K.prefilter="tagName";}}},{name:A,re:/^\s*([>+~]|\s)\s*/,fn:function(I,J){}},{name:F,re:/^:([\-\w]+)(?:\(['"]?(.+)['"]?\))*/i,fn:function(I,J){var K=C[F][I[1]];if(K){return[I[2],K];}else{return false;}}}],_getToken:function(I){return{tagName:null,id:null,className:null,attributes:{},combinator:null,tests:[]};},_tokenize:function(K){K=K||"";K=C._replaceShorthand(G.Lang.trim(K));var J=C._getToken(),P=K,O=[],Q=false,M,N,L,I;outer:do{Q=false;for(L=0;(I=C._parsers[L++]);){if((M=I.re.exec(K))){if(I!==A){J.selector=K;}K=K.replace(M[0],"");if(!K.length){J.last=true;}if(C._attrFilters[M[1]]){M[1]=C._attrFilters[M[1]];}N=I.fn(M,J);if(N===false){Q=false;break outer;}else{if(N){J.tests.push(N);}}if(!K.length||I.name===A){O.push(J);J=C._getToken(J);if(I.name===A){J.combinator=G.Selector.combinators[M[1]];}}Q=true;}}}while(Q&&K.length);if(!Q||K.length){O=[];}return O;},_replaceShorthand:function(J){var K=C.shorthand,L=J.match(C._re.attr),O=J.match(C._re.pseudos),N,M,I;if(O){J=J.replace(C._re.pseudos,"!!REPLACED_PSEUDO!!");}if(L){J=J.replace(C._re.attr,"!!REPLACED_ATTRIBUTE!!");}for(N in K){if(K.hasOwnProperty(N)){J=J.replace(C._getRegExp(N,"gi"),K[N]);}}if(L){for(M=0,I=L.length;M519)?true:false);while((Q=Q.offsetParent)){T[0]+=Q.offsetLeft;T[1]+=Q.offsetTop;if(V){T=F.DOM._calcBorders(Q,T);}}if(F.DOM.getStyle(R,M)!=C){Q=R;while((Q=Q.parentNode)){S=Q.scrollTop;U=Q.scrollLeft;if(F.UA.gecko&&(F.DOM.getStyle(Q,"overflow")!=="visible")){T=F.DOM._calcBorders(Q,T);}if(S||U){T[0]-=U;T[1]-=S;}}T[0]+=F.DOM.docScrollX(R);T[1]+=F.DOM.docScrollY(R);}else{T[0]+=F.DOM.docScrollX(R);T[1]+=F.DOM.docScrollY(R);}}else{T=F.DOM._getOffset(R);}}return T;};}}(),_getOffset:function(Q){var S,R=null;if(Q){S=F.DOM.getStyle(Q,M);R=[parseInt(F.DOM[J](Q,G),10),parseInt(F.DOM[J](Q,H),10)];if(isNaN(R[0])){R[0]=parseInt(F.DOM.getStyle(Q,G),10);if(isNaN(R[0])){R[0]=(S===K)?0:Q.offsetLeft||0;}}if(isNaN(R[1])){R[1]=parseInt(F.DOM.getStyle(Q,H),10);if(isNaN(R[1])){R[1]=(S===K)?0:Q.offsetTop||0;}}}return R;},getX:function(Q){return F.DOM.getXY(Q)[0];},getY:function(Q){return F.DOM.getXY(Q)[1];},setXY:function(R,U,X){var S=F.DOM.setStyle,W,V,Q,T;if(R&&U){W=F.DOM.getStyle(R,M);V=F.DOM._getOffset(R);if(W=="static"){W=K;S(R,M,W);}T=F.DOM.getXY(R);if(U[0]!==null){S(R,G,U[0]-T[0]+V[0]+"px");}if(U[1]!==null){S(R,H,U[1]-T[1]+V[1]+"px");}if(!X){Q=F.DOM.getXY(R);if(Q[0]!==U[0]||Q[1]!==U[1]){F.DOM.setXY(R,U,true);}}}else{}},setX:function(R,Q){return F.DOM.setXY(R,[Q,null]);},setY:function(Q,R){return F.DOM.setXY(Q,[null,R]);},_calcBorders:function(S,T){var R=parseInt(F.DOM[J](S,B),10)||0,Q=parseInt(F.DOM[J](S,E),10)||0;if(F.UA.gecko){if(L.test(S.tagName)){R=0;Q=0;}}T[0]+=Q;T[1]+=R;return T;},_getWinSize:function(T){var V=F.DOM._getDoc(),U=V.defaultView||V.parentWindow,W=V[O],S=U.innerHeight,R=U.innerWidth,Q=V[D];if(W&&!F.UA.opera){if(W!="CSS1Compat"){Q=V.body;}S=Q.clientHeight;R=Q.clientWidth;}return{height:S,width:R};},_getDocSize:function(R){var S=F.DOM._getDoc(),Q=S[D];if(S[O]!="CSS1Compat"){Q=S.body;}return{height:Q.scrollHeight,width:Q.scrollWidth};}});})(A);(function(G){var D="top",C="right",H="bottom",B="left",F=function(L,K){var N=Math.max(L[D],K[D]),O=Math.min(L[C],K[C]),I=Math.min(L[H],K[H]),J=Math.max(L[B],K[B]),M={};M[D]=N;M[C]=O;M[H]=I;M[B]=J;return M;},E=G.DOM;G.mix(E,{region:function(J){var K=E.getXY(J),I=false;if(J&&K){I=E._getRegion(K[1],K[0]+J.offsetWidth,K[1]+J.offsetHeight,K[0]);}return I;},intersect:function(K,I,M){var J=M||E.region(K),L={},O=I,N;if(O.tagName){L=E.region(O);}else{if(G.Lang.isObject(I)){L=I;}else{return false;}}N=F(L,J);return{top:N[D],right:N[C],bottom:N[H],left:N[B],area:((N[H]-N[D])*(N[C]-N[B])),yoff:((N[H]-N[D])),xoff:(N[C]-N[B]),inRegion:E.inRegion(K,I,false,M)};},inRegion:function(L,I,J,N){var M={},K=N||E.region(L),P=I,O;if(P.tagName){M=E.region(P);}else{if(G.Lang.isObject(I)){M=I;}else{return false;}}if(J){return(K[B]>=M[B]&&K[C]<=M[C]&&K[D]>=M[D]&&K[H]<=M[H]);}else{O=F(M,K);if(O[H]>=O[D]&&O[C]>=O[B]){return true;}else{return false;}}},inViewportRegion:function(J,I,K){return E.inRegion(J,E.viewportRegion(J),I,K);},_getRegion:function(K,L,I,J){var M={};M[D]=M[1]=K;M[B]=M[0]=J;M[H]=I;M[C]=L;M.width=M[C]-M[B];M.height=M[H]-M[D];return M;},viewportRegion:function(J){J=J||G.config.doc.documentElement;var I=false,L,K;if(J){L=E.docScrollX(J);K=E.docScrollY(J);I=E._getRegion(K,E.winWidth(J)+L,K+E.winHeight(J),L);}return I;}});})(A);},"3.0.0",{requires:["dom-base","dom-style"]}); \ No newline at end of file diff --git a/include/javascript/yui3/build/dom/dom-screen.js b/include/javascript/yui3/build/dom/dom-screen.js new file mode 100644 index 00000000..137e2520 --- /dev/null +++ b/include/javascript/yui3/build/dom/dom-screen.js @@ -0,0 +1,30 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add('dom-screen',function(Y){(function(Y){var DOCUMENT_ELEMENT='documentElement',COMPAT_MODE='compatMode',POSITION='position',FIXED='fixed',RELATIVE='relative',LEFT='left',TOP='top',_BACK_COMPAT='BackCompat',MEDIUM='medium',BORDER_LEFT_WIDTH='borderLeftWidth',BORDER_TOP_WIDTH='borderTopWidth',GET_BOUNDING_CLIENT_RECT='getBoundingClientRect',GET_COMPUTED_STYLE='getComputedStyle',RE_TABLE=/^t(?:able|d|h)$/i;Y.mix(Y.DOM,{winHeight:function(node){var h=Y.DOM._getWinSize(node).height;return h;},winWidth:function(node){var w=Y.DOM._getWinSize(node).width;return w;},docHeight:function(node){var h=Y.DOM._getDocSize(node).height;return Math.max(h,Y.DOM._getWinSize(node).height);},docWidth:function(node){var w=Y.DOM._getDocSize(node).width;return Math.max(w,Y.DOM._getWinSize(node).width);},docScrollX:function(node){var doc=Y.DOM._getDoc(node);return Math.max(doc[DOCUMENT_ELEMENT].scrollLeft,doc.body.scrollLeft);},docScrollY:function(node){var doc=Y.DOM._getDoc(node);return Math.max(doc[DOCUMENT_ELEMENT].scrollTop,doc.body.scrollTop);},getXY:function(){if(document[DOCUMENT_ELEMENT][GET_BOUNDING_CLIENT_RECT]){return function(node){var xy=null,scrollLeft,scrollTop,box,off1,off2,bLeft,bTop,mode,doc;if(node){if(Y.DOM.inDoc(node)){scrollLeft=Y.DOM.docScrollX(node);scrollTop=Y.DOM.docScrollY(node);box=node[GET_BOUNDING_CLIENT_RECT]();doc=Y.DOM._getDoc(node);xy=[box.left,box.top];if(Y.UA.ie){off1=2;off2=2;mode=doc[COMPAT_MODE];bLeft=Y.DOM[GET_COMPUTED_STYLE](doc[DOCUMENT_ELEMENT],BORDER_LEFT_WIDTH);bTop=Y.DOM[GET_COMPUTED_STYLE](doc[DOCUMENT_ELEMENT],BORDER_TOP_WIDTH);if(Y.UA.ie===6){if(mode!==_BACK_COMPAT){off1=0;off2=0;}} +if((mode==_BACK_COMPAT)){if(bLeft!==MEDIUM){off1=parseInt(bLeft,10);} +if(bTop!==MEDIUM){off2=parseInt(bTop,10);}} +xy[0]-=off1;xy[1]-=off2;} +if((scrollTop||scrollLeft)){xy[0]+=scrollLeft;xy[1]+=scrollTop;}}else{xy=Y.DOM._getOffset(node);}} +return xy;};}else{return function(node){var xy=null,parentNode,bCheck,scrollTop,scrollLeft;if(node){if(Y.DOM.inDoc(node)){xy=[node.offsetLeft,node.offsetTop];parentNode=node;bCheck=((Y.UA.gecko||Y.UA.webkit>519)?true:false);while((parentNode=parentNode.offsetParent)){xy[0]+=parentNode.offsetLeft;xy[1]+=parentNode.offsetTop;if(bCheck){xy=Y.DOM._calcBorders(parentNode,xy);}} +if(Y.DOM.getStyle(node,POSITION)!=FIXED){parentNode=node;while((parentNode=parentNode.parentNode)){scrollTop=parentNode.scrollTop;scrollLeft=parentNode.scrollLeft;if(Y.UA.gecko&&(Y.DOM.getStyle(parentNode,'overflow')!=='visible')){xy=Y.DOM._calcBorders(parentNode,xy);} +if(scrollTop||scrollLeft){xy[0]-=scrollLeft;xy[1]-=scrollTop;}} +xy[0]+=Y.DOM.docScrollX(node);xy[1]+=Y.DOM.docScrollY(node);}else{xy[0]+=Y.DOM.docScrollX(node);xy[1]+=Y.DOM.docScrollY(node);}}else{xy=Y.DOM._getOffset(node);}} +return xy;};}}(),_getOffset:function(node){var pos,xy=null;if(node){pos=Y.DOM.getStyle(node,POSITION);xy=[parseInt(Y.DOM[GET_COMPUTED_STYLE](node,LEFT),10),parseInt(Y.DOM[GET_COMPUTED_STYLE](node,TOP),10)];if(isNaN(xy[0])){xy[0]=parseInt(Y.DOM.getStyle(node,LEFT),10);if(isNaN(xy[0])){xy[0]=(pos===RELATIVE)?0:node.offsetLeft||0;}} +if(isNaN(xy[1])){xy[1]=parseInt(Y.DOM.getStyle(node,TOP),10);if(isNaN(xy[1])){xy[1]=(pos===RELATIVE)?0:node.offsetTop||0;}}} +return xy;},getX:function(node){return Y.DOM.getXY(node)[0];},getY:function(node){return Y.DOM.getXY(node)[1];},setXY:function(node,xy,noRetry){var setStyle=Y.DOM.setStyle,pos,delta,newXY,currentXY;if(node&&xy){pos=Y.DOM.getStyle(node,POSITION);delta=Y.DOM._getOffset(node);if(pos=='static'){pos=RELATIVE;setStyle(node,POSITION,pos);} +currentXY=Y.DOM.getXY(node);if(xy[0]!==null){setStyle(node,LEFT,xy[0]-currentXY[0]+delta[0]+'px');} +if(xy[1]!==null){setStyle(node,TOP,xy[1]-currentXY[1]+delta[1]+'px');} +if(!noRetry){newXY=Y.DOM.getXY(node);if(newXY[0]!==xy[0]||newXY[1]!==xy[1]){Y.DOM.setXY(node,xy,true);}}}else{}},setX:function(node,x){return Y.DOM.setXY(node,[x,null]);},setY:function(node,y){return Y.DOM.setXY(node,[null,y]);},_calcBorders:function(node,xy2){var t=parseInt(Y.DOM[GET_COMPUTED_STYLE](node,BORDER_TOP_WIDTH),10)||0,l=parseInt(Y.DOM[GET_COMPUTED_STYLE](node,BORDER_LEFT_WIDTH),10)||0;if(Y.UA.gecko){if(RE_TABLE.test(node.tagName)){t=0;l=0;}} +xy2[0]+=l;xy2[1]+=t;return xy2;},_getWinSize:function(node){var doc=Y.DOM._getDoc(),win=doc.defaultView||doc.parentWindow,mode=doc[COMPAT_MODE],h=win.innerHeight,w=win.innerWidth,root=doc[DOCUMENT_ELEMENT];if(mode&&!Y.UA.opera){if(mode!='CSS1Compat'){root=doc.body;} +h=root.clientHeight;w=root.clientWidth;} +return{height:h,width:w};},_getDocSize:function(node){var doc=Y.DOM._getDoc(),root=doc[DOCUMENT_ELEMENT];if(doc[COMPAT_MODE]!='CSS1Compat'){root=doc.body;} +return{height:root.scrollHeight,width:root.scrollWidth};}});})(Y);(function(Y){var TOP='top',RIGHT='right',BOTTOM='bottom',LEFT='left',getOffsets=function(r1,r2){var t=Math.max(r1[TOP],r2[TOP]),r=Math.min(r1[RIGHT],r2[RIGHT]),b=Math.min(r1[BOTTOM],r2[BOTTOM]),l=Math.max(r1[LEFT],r2[LEFT]),ret={};ret[TOP]=t;ret[RIGHT]=r;ret[BOTTOM]=b;ret[LEFT]=l;return ret;},DOM=Y.DOM;Y.mix(DOM,{region:function(node){var xy=DOM.getXY(node),ret=false;if(node&&xy){ret=DOM._getRegion(xy[1],xy[0]+node.offsetWidth,xy[1]+node.offsetHeight,xy[0]);} +return ret;},intersect:function(node,node2,altRegion){var r=altRegion||DOM.region(node),region={},n=node2,off;if(n.tagName){region=DOM.region(n);}else if(Y.Lang.isObject(node2)){region=node2;}else{return false;} +off=getOffsets(region,r);return{top:off[TOP],right:off[RIGHT],bottom:off[BOTTOM],left:off[LEFT],area:((off[BOTTOM]-off[TOP])*(off[RIGHT]-off[LEFT])),yoff:((off[BOTTOM]-off[TOP])),xoff:(off[RIGHT]-off[LEFT]),inRegion:DOM.inRegion(node,node2,false,altRegion)};},inRegion:function(node,node2,all,altRegion){var region={},r=altRegion||DOM.region(node),n=node2,off;if(n.tagName){region=DOM.region(n);}else if(Y.Lang.isObject(node2)){region=node2;}else{return false;} +if(all){return(r[LEFT]>=region[LEFT]&&r[RIGHT]<=region[RIGHT]&&r[TOP]>=region[TOP]&&r[BOTTOM]<=region[BOTTOM]);}else{off=getOffsets(region,r);if(off[BOTTOM]>=off[TOP]&&off[RIGHT]>=off[LEFT]){return true;}else{return false;}}},inViewportRegion:function(node,all,altRegion){return DOM.inRegion(node,DOM.viewportRegion(node),all,altRegion);},_getRegion:function(t,r,b,l){var region={};region[TOP]=region[1]=t;region[LEFT]=region[0]=l;region[BOTTOM]=b;region[RIGHT]=r;region.width=region[RIGHT]-region[LEFT];region.height=region[BOTTOM]-region[TOP];return region;},viewportRegion:function(node){node=node||Y.config.doc.documentElement;var ret=false,scrollX,scrollY;if(node){scrollX=DOM.docScrollX(node);scrollY=DOM.docScrollY(node);ret=DOM._getRegion(scrollY,DOM.winWidth(node)+scrollX,scrollY+DOM.winHeight(node),scrollX);} +return ret;}});})(Y);},'3.0.0',{requires:['dom-base','dom-style']}); \ No newline at end of file diff --git a/include/javascript/yui3/build/dom/dom-style-min.js b/include/javascript/yui3/build/dom/dom-style-min.js new file mode 100644 index 00000000..9ae4370f --- /dev/null +++ b/include/javascript/yui3/build/dom/dom-style-min.js @@ -0,0 +1,8 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add("dom-style",function(A){(function(E){var C="documentElement",B="defaultView",D="ownerDocument",L="style",N="float",F="cssFloat",G="styleFloat",J="transparent",H="getComputedStyle",M=E.config.doc,I=undefined,K=/color$/i;E.mix(E.DOM,{CUSTOM_STYLES:{},setStyle:function(R,O,S,Q){Q=Q||R.style;var P=E.DOM.CUSTOM_STYLES;if(Q){if(S===null){S="";}if(O in P){if(P[O].set){P[O].set(R,S,Q);return;}else{if(typeof P[O]==="string"){O=P[O];}}}Q[O]=S;}},getStyle:function(R,O){var Q=R[L],P=E.DOM.CUSTOM_STYLES,S="";if(Q){if(O in P){if(P[O].get){return P[O].get(R,O,Q);}else{if(typeof P[O]==="string"){O=P[O];}}}S=Q[O];if(S===""){S=E.DOM[H](R,O);}}return S;},setStyles:function(P,Q){var O=P.style;E.each(Q,function(R,S){E.DOM.setStyle(P,S,R,O);},E.DOM);},getComputedStyle:function(P,O){var R="",Q=P[D];if(P[L]){R=Q[B][H](P,null)[O];}return R;}});if(M[C][L][F]!==I){E.DOM.CUSTOM_STYLES[N]=F;}else{if(M[C][L][G]!==I){E.DOM.CUSTOM_STYLES[N]=G;}}if(E.UA.opera){E.DOM[H]=function(Q,P){var O=Q[D][B],R=O[H](Q,"")[P];if(K.test(P)){R=E.Color.toRGB(R);}return R;};}if(E.UA.webkit){E.DOM[H]=function(Q,P){var O=Q[D][B],R=O[H](Q,"")[P];if(R==="rgba(0, 0, 0, 0)"){R=J;}return R;};}})(A);(function(D){var B=parseInt,C=RegExp;D.Color={KEYWORDS:{black:"000",silver:"c0c0c0",gray:"808080",white:"fff",maroon:"800000",red:"f00",purple:"800080",fuchsia:"f0f",green:"008000",lime:"0f0",olive:"808000",yellow:"ff0",navy:"000080",blue:"00f",teal:"008080",aqua:"0ff"},re_RGB:/^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i,re_hex:/^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i,re_hex3:/([0-9A-F])/gi,toRGB:function(E){if(!D.Color.re_RGB.test(E)){E=D.Color.toHex(E);}if(D.Color.re_hex.exec(E)){E="rgb("+[B(C.$1,16),B(C.$2,16),B(C.$3,16)].join(", ")+")";}return E;},toHex:function(F){F=D.Color.KEYWORDS[F]||F;if(D.Color.re_RGB.exec(F)){F=[Number(C.$1).toString(16),Number(C.$2).toString(16),Number(C.$3).toString(16)];for(var E=0;E-1)){a=c;}else{if(D.DOM.IE.COMPUTED[b]){a=D.DOM.IE.COMPUTED[b](Y,b);}else{if(P.test(c)){a=N.getPixel(Y,b)+K;}else{a=c;}}}}}return a;},sizeOffsets:{width:["Left","Right"],height:["Top","Bottom"],top:["Top"],bottom:["Bottom"]},getOffset:function(b,g){var d=E(b)[g],Y=g.charAt(0).toUpperCase()+g.substr(1),f="offset"+Y,a="pixel"+Y,e=N.sizeOffsets[g],c="";if(d===M||d.indexOf("%")>-1){c=b["offset"+Y];if(e[0]){c-=N.getPixel(b,"padding"+e[0]);c-=N.getBorderWidth(b,"border"+e[0]+"Width",1);}if(e[1]){c-=N.getPixel(b,"padding"+e[1]);c-=N.getBorderWidth(b,"border"+e[1]+"Width",1);}}else{if(!b.style[a]&&!b.style[g]){b.style[g]=d;}c=b.style[a];}return c+K;},borderMap:{thin:"2px",medium:"4px",thick:"6px"},getBorderWidth:function(a,c,Y){var b=Y?"":K,d=a.currentStyle[c];if(d.indexOf(K)<0){if(N.borderMap[d]){d=N.borderMap[d];}else{}}return(Y)?parseFloat(d):d;},getPixel:function(b,Y){var d=null,a=E(b),e=a.right,c=a[Y];b.style.right=c;d=b.style.pixelRight;b.style.right=e;return d;},getMargin:function(b,Y){var c,a=E(b);if(a[Y]==M){c=0;}else{c=N.getPixel(b,Y);}return c+K;},getVisibility:function(a,Y){var b;while((b=a.currentStyle)&&b[Y]=="inherit"){a=a.parentNode;}return(b)?b[Y]:S;},getColor:function(a,Y){var b=E(a)[Y];if(!b||b===R){D.DOM.elementByAxis(a,"parentNode",null,function(c){b=E(c)[Y];if(b&&b!==R){a=c;return true;}});}return D.Color.toRGB(b);},getBorderColor:function(a,Y){var b=E(a),c=b[Y]||b.color;return D.Color.toRGB(D.Color.toHex(c));}},F={};try{if(X.style[T]===Z&&X[B]){D.DOM.CUSTOM_STYLES[T]={get:function(a){var c=100;try{c=a[B]["DXImageTransform.Microsoft.Alpha"][T];}catch(b){try{c=a[B]("alpha")[T];}catch(Y){}}return c/100;},set:function(a,d,Y){var c,b;if(d===""){b=E(a);c=(T in b)?b[T]:1;d=c;}if(typeof Y[L]=="string"){Y[L]="alpha("+T+"="+d*100+")";if(!a.currentStyle||!a.currentStyle[W]){Y.zoom=1;}}}};}}catch(U){}try{document.createElement("div").style.height="-1px";}catch(U){D.DOM.CUSTOM_STYLES.height={set:function(b,c,a){var Y=parseFloat(c);if(isNaN(Y)||Y>=0){a.height=c;}else{}}};D.DOM.CUSTOM_STYLES.width={set:function(b,c,a){var Y=parseFloat(c);if(isNaN(Y)||Y>=0){a.width=c;}else{}}};}F[I]=F[O]=N.getOffset;F.color=F.backgroundColor=N.getColor;F[G]=F[J]=F[Q]=F[V]=F[H]=N.getBorderWidth;F.marginTop=F.marginRight=F.marginBottom=F.marginLeft=N.getMargin;F.visibility=N.getVisibility;F.borderColor=F.borderTopColor=F.borderRightColor=F.borderBottomColor=F.borderLeftColor=N.getBorderColor;if(!D.config.win[C]){D.DOM[C]=N.get;}D.namespace("DOM.IE");D.DOM.IE.COMPUTED=F;D.DOM.IE.ComputedStyle=N;})(A);},"3.0.0",{requires:["dom-base"]}); \ No newline at end of file diff --git a/include/javascript/yui3/build/dom/dom-style.js b/include/javascript/yui3/build/dom/dom-style.js new file mode 100644 index 00000000..88246cb7 --- /dev/null +++ b/include/javascript/yui3/build/dom/dom-style.js @@ -0,0 +1,36 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add('dom-style',function(Y){(function(Y){var DOCUMENT_ELEMENT='documentElement',DEFAULT_VIEW='defaultView',OWNER_DOCUMENT='ownerDocument',STYLE='style',FLOAT='float',CSS_FLOAT='cssFloat',STYLE_FLOAT='styleFloat',TRANSPARENT='transparent',GET_COMPUTED_STYLE='getComputedStyle',DOCUMENT=Y.config.doc,UNDEFINED=undefined,re_color=/color$/i;Y.mix(Y.DOM,{CUSTOM_STYLES:{},setStyle:function(node,att,val,style){style=style||node.style;var CUSTOM_STYLES=Y.DOM.CUSTOM_STYLES;if(style){if(val===null){val='';} +if(att in CUSTOM_STYLES){if(CUSTOM_STYLES[att].set){CUSTOM_STYLES[att].set(node,val,style);return;}else if(typeof CUSTOM_STYLES[att]==='string'){att=CUSTOM_STYLES[att];}} +style[att]=val;}},getStyle:function(node,att){var style=node[STYLE],CUSTOM_STYLES=Y.DOM.CUSTOM_STYLES,val='';if(style){if(att in CUSTOM_STYLES){if(CUSTOM_STYLES[att].get){return CUSTOM_STYLES[att].get(node,att,style);}else if(typeof CUSTOM_STYLES[att]==='string'){att=CUSTOM_STYLES[att];}} +val=style[att];if(val===''){val=Y.DOM[GET_COMPUTED_STYLE](node,att);}} +return val;},setStyles:function(node,hash){var style=node.style;Y.each(hash,function(v,n){Y.DOM.setStyle(node,n,v,style);},Y.DOM);},getComputedStyle:function(node,att){var val='',doc=node[OWNER_DOCUMENT];if(node[STYLE]){val=doc[DEFAULT_VIEW][GET_COMPUTED_STYLE](node,null)[att];} +return val;}});if(DOCUMENT[DOCUMENT_ELEMENT][STYLE][CSS_FLOAT]!==UNDEFINED){Y.DOM.CUSTOM_STYLES[FLOAT]=CSS_FLOAT;}else if(DOCUMENT[DOCUMENT_ELEMENT][STYLE][STYLE_FLOAT]!==UNDEFINED){Y.DOM.CUSTOM_STYLES[FLOAT]=STYLE_FLOAT;} +if(Y.UA.opera){Y.DOM[GET_COMPUTED_STYLE]=function(node,att){var view=node[OWNER_DOCUMENT][DEFAULT_VIEW],val=view[GET_COMPUTED_STYLE](node,'')[att];if(re_color.test(att)){val=Y.Color.toRGB(val);} +return val;};} +if(Y.UA.webkit){Y.DOM[GET_COMPUTED_STYLE]=function(node,att){var view=node[OWNER_DOCUMENT][DEFAULT_VIEW],val=view[GET_COMPUTED_STYLE](node,'')[att];if(val==='rgba(0, 0, 0, 0)'){val=TRANSPARENT;} +return val;};}})(Y);(function(Y){var PARSE_INT=parseInt,RE=RegExp;Y.Color={KEYWORDS:{black:'000',silver:'c0c0c0',gray:'808080',white:'fff',maroon:'800000',red:'f00',purple:'800080',fuchsia:'f0f',green:'008000',lime:'0f0',olive:'808000',yellow:'ff0',navy:'000080',blue:'00f',teal:'008080',aqua:'0ff'},re_RGB:/^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i,re_hex:/^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i,re_hex3:/([0-9A-F])/gi,toRGB:function(val){if(!Y.Color.re_RGB.test(val)){val=Y.Color.toHex(val);} +if(Y.Color.re_hex.exec(val)){val='rgb('+[PARSE_INT(RE.$1,16),PARSE_INT(RE.$2,16),PARSE_INT(RE.$3,16)].join(', ')+')';} +return val;},toHex:function(val){val=Y.Color.KEYWORDS[val]||val;if(Y.Color.re_RGB.exec(val)){val=[Number(RE.$1).toString(16),Number(RE.$2).toString(16),Number(RE.$3).toString(16)];for(var i=0;i-1)){value=current;}else if(Y.DOM.IE.COMPUTED[property]){value=Y.DOM.IE.COMPUTED[property](el,property);}else if(re_unit.test(current)){value=ComputedStyle.getPixel(el,property)+PX;}else{value=current;}} +return value;},sizeOffsets:{width:['Left','Right'],height:['Top','Bottom'],top:['Top'],bottom:['Bottom']},getOffset:function(el,prop){var current=_getStyleObj(el)[prop],capped=prop.charAt(0).toUpperCase()+prop.substr(1),offset='offset'+capped,pixel='pixel'+capped,sizeOffsets=ComputedStyle.sizeOffsets[prop],value='';if(current===AUTO||current.indexOf('%')>-1){value=el['offset'+capped];if(sizeOffsets[0]){value-=ComputedStyle.getPixel(el,'padding'+sizeOffsets[0]);value-=ComputedStyle.getBorderWidth(el,'border'+sizeOffsets[0]+'Width',1);} +if(sizeOffsets[1]){value-=ComputedStyle.getPixel(el,'padding'+sizeOffsets[1]);value-=ComputedStyle.getBorderWidth(el,'border'+sizeOffsets[1]+'Width',1);}}else{if(!el.style[pixel]&&!el.style[prop]){el.style[prop]=current;} +value=el.style[pixel];} +return value+PX;},borderMap:{thin:'2px',medium:'4px',thick:'6px'},getBorderWidth:function(el,property,omitUnit){var unit=omitUnit?'':PX,current=el.currentStyle[property];if(current.indexOf(PX)<0){if(ComputedStyle.borderMap[current]){current=ComputedStyle.borderMap[current];}else{}} +return(omitUnit)?parseFloat(current):current;},getPixel:function(node,att){var val=null,style=_getStyleObj(node),styleRight=style.right,current=style[att];node.style.right=current;val=node.style.pixelRight;node.style.right=styleRight;return val;},getMargin:function(node,att){var val,style=_getStyleObj(node);if(style[att]==AUTO){val=0;}else{val=ComputedStyle.getPixel(node,att);} +return val+PX;},getVisibility:function(node,att){var current;while((current=node.currentStyle)&¤t[att]=='inherit'){node=node.parentNode;} +return(current)?current[att]:VISIBLE;},getColor:function(node,att){var current=_getStyleObj(node)[att];if(!current||current===TRANSPARENT){Y.DOM.elementByAxis(node,'parentNode',null,function(parent){current=_getStyleObj(parent)[att];if(current&¤t!==TRANSPARENT){node=parent;return true;}});} +return Y.Color.toRGB(current);},getBorderColor:function(node,att){var current=_getStyleObj(node),val=current[att]||current.color;return Y.Color.toRGB(Y.Color.toHex(val));}},IEComputed={};try{if(documentElement.style[OPACITY]===UNDEFINED&&documentElement[FILTERS]){Y.DOM.CUSTOM_STYLES[OPACITY]={get:function(node){var val=100;try{val=node[FILTERS]['DXImageTransform.Microsoft.Alpha'][OPACITY];}catch(e){try{val=node[FILTERS]('alpha')[OPACITY];}catch(err){}} +return val/100;},set:function(node,val,style){var current,styleObj;if(val===''){styleObj=_getStyleObj(node);current=(OPACITY in styleObj)?styleObj[OPACITY]:1;val=current;} +if(typeof style[FILTER]=='string'){style[FILTER]='alpha('+OPACITY+'='+val*100+')';if(!node.currentStyle||!node.currentStyle[HAS_LAYOUT]){style.zoom=1;}}}};}}catch(e){} +try{document.createElement('div').style.height='-1px';}catch(e){Y.DOM.CUSTOM_STYLES.height={set:function(node,val,style){var floatVal=parseFloat(val);if(isNaN(floatVal)||floatVal>=0){style.height=val;}else{}}};Y.DOM.CUSTOM_STYLES.width={set:function(node,val,style){var floatVal=parseFloat(val);if(isNaN(floatVal)||floatVal>=0){style.width=val;}else{}}};} +IEComputed[WIDTH]=IEComputed[HEIGHT]=ComputedStyle.getOffset;IEComputed.color=IEComputed.backgroundColor=ComputedStyle.getColor;IEComputed[BORDER_WIDTH]=IEComputed[BORDER_TOP_WIDTH]=IEComputed[BORDER_RIGHT_WIDTH]=IEComputed[BORDER_BOTTOM_WIDTH]=IEComputed[BORDER_LEFT_WIDTH]=ComputedStyle.getBorderWidth;IEComputed.marginTop=IEComputed.marginRight=IEComputed.marginBottom=IEComputed.marginLeft=ComputedStyle.getMargin;IEComputed.visibility=ComputedStyle.getVisibility;IEComputed.borderColor=IEComputed.borderTopColor=IEComputed.borderRightColor=IEComputed.borderBottomColor=IEComputed.borderLeftColor=ComputedStyle.getBorderColor;if(!Y.config.win[GET_COMPUTED_STYLE]){Y.DOM[GET_COMPUTED_STYLE]=ComputedStyle.get;} +Y.namespace('DOM.IE');Y.DOM.IE.COMPUTED=IEComputed;Y.DOM.IE.ComputedStyle=ComputedStyle;})(Y);},'3.0.0',{requires:['dom-base']}); \ No newline at end of file diff --git a/include/javascript/yui3/build/dom/dom.js b/include/javascript/yui3/build/dom/dom.js new file mode 100644 index 00000000..974c6d28 --- /dev/null +++ b/include/javascript/yui3/build/dom/dom.js @@ -0,0 +1,130 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add('dom-base',function(Y){(function(Y){var NODE_TYPE='nodeType',OWNER_DOCUMENT='ownerDocument',DEFAULT_VIEW='defaultView',PARENT_WINDOW='parentWindow',TAG_NAME='tagName',PARENT_NODE='parentNode',FIRST_CHILD='firstChild',PREVIOUS_SIBLING='previousSibling',NEXT_SIBLING='nextSibling',CONTAINS='contains',COMPARE_DOCUMENT_POSITION='compareDocumentPosition',documentElement=document.documentElement,re_tag=/<([a-z]+)/i;Y.DOM={byId:function(id,doc){doc=doc||Y.config.doc;return doc.getElementById(id);},children:function(node,tag){var ret=[];if(node){tag=tag||'*';ret=Y.Selector.query('> '+tag,node);} +return ret;},firstByTag:function(tag,root){var ret;root=root||Y.config.doc;if(tag&&root.getElementsByTagName){ret=root.getElementsByTagName(tag)[0];} +return ret||null;},getText:(documentElement.textContent!==undefined)?function(element){var ret='';if(element){ret=element.textContent;} +return ret||'';}:function(element){var ret='';if(element){ret=element.innerText;} +return ret||'';},setText:(documentElement.textContent!==undefined)?function(element,content){if(element){element.textContent=content;}}:function(element,content){if(element){element.innerText=content;}},previous:function(element,fn,all){return Y.DOM.elementByAxis(element,PREVIOUS_SIBLING,fn,all);},next:function(element,fn,all){return Y.DOM.elementByAxis(element,NEXT_SIBLING,fn,all);},ancestor:function(element,fn,all){return Y.DOM.elementByAxis(element,PARENT_NODE,fn,all);},elementByAxis:function(element,axis,fn,all){while(element&&(element=element[axis])){if((all||element[TAG_NAME])&&(!fn||fn(element))){return element;}} +return null;},contains:function(element,needle){var ret=false;if(!needle||!element||!needle[NODE_TYPE]||!element[NODE_TYPE]){ret=false;}else if(element[CONTAINS]){if(Y.UA.opera||needle[NODE_TYPE]===1){ret=element[CONTAINS](needle);}else{ret=Y.DOM._bruteContains(element,needle);}}else if(element[COMPARE_DOCUMENT_POSITION]){if(element===needle||!!(element[COMPARE_DOCUMENT_POSITION](needle)&16)){ret=true;}} +return ret;},inDoc:function(element,doc){doc=doc||element[OWNER_DOCUMENT];var id=element.id;if(!id){id=element.id=Y.guid();} +return!!(doc.getElementById(id));},create:function(html,doc){if(typeof html==='string'){html=Y.Lang.trim(html);} +if(!doc&&Y.DOM._cloneCache[html]){return Y.DOM._cloneCache[html].cloneNode(true);} +doc=doc||Y.config.doc;var m=re_tag.exec(html),create=Y.DOM._create,custom=Y.DOM.creators,ret=null,tag,nodes;if(m&&custom[m[1]]){if(typeof custom[m[1]]==='function'){create=custom[m[1]];}else{tag=custom[m[1]];}} +nodes=create(html,doc,tag).childNodes;if(nodes.length===1){ret=nodes[0].parentNode.removeChild(nodes[0]);}else{ret=Y.DOM._nl2frag(nodes,doc);} +if(ret){Y.DOM._cloneCache[html]=ret.cloneNode(true);} +return ret;},_nl2frag:function(nodes,doc){var ret=null,i,len;if(nodes&&(nodes.push||nodes.item)&&nodes[0]){doc=doc||nodes[0].ownerDocument;ret=doc.createDocumentFragment();if(nodes.item){nodes=Y.Array(nodes,0,true);} +for(i=0,len=nodes.length;i)+\s*1&&tb&&!re_tbody.test(html)){tb[PARENT_NODE].removeChild(tb);} +return frag;},script:function(html,doc){var frag=doc.createElement('div');frag.innerHTML='-'+html;frag.removeChild(frag[FIRST_CHILD]);return frag;}},true);Y.mix(Y.DOM.VALUE_GETTERS,{button:function(node){return(node.attributes&&node.attributes.value)?node.attributes.value.value:'';}});Y.mix(Y.DOM.VALUE_SETTERS,{button:function(node,val){var attr=node.attributes.value;if(!attr){attr=node[OWNER_DOCUMENT].createAttribute('value');node.setAttributeNode(attr);} +attr.value=val;}});} +if(Y.UA.gecko||Y.UA.ie){Y.mix(creators,{option:function(html,doc){return create('',doc);},tr:function(html,doc){return create(''+html+'',doc);},td:function(html,doc){return create(''+html+'',doc);},tbody:function(html,doc){return create(TABLE_OPEN+html+TABLE_CLOSE,doc);}});Y.mix(creators,{legend:'fieldset',th:creators.td,thead:creators.tbody,tfoot:creators.tbody,caption:creators.tbody,colgroup:creators.tbody,col:creators.tbody,optgroup:creators.option});} +Y.mix(Y.DOM.VALUE_GETTERS,{option:function(node){var attrs=node.attributes;return(attrs.value&&attrs.value.specified)?node.value:node.text;},select:function(node){var val=node.value,options=node.options;if(options&&val===''){if(node.multiple){}else{val=Y.DOM.getValue(options[node.selectedIndex],'value');}} +return val;}});})(Y);})(Y);var addClass,hasClass,removeClass;Y.mix(Y.DOM,{hasClass:function(node,className){var re=Y.DOM._getRegExp('(?:^|\\s+)'+className+'(?:\\s+|$)');return re.test(node.className);},addClass:function(node,className){if(!Y.DOM.hasClass(node,className)){node.className=Y.Lang.trim([node.className,className].join(' '));}},removeClass:function(node,className){if(className&&hasClass(node,className)){node.className=Y.Lang.trim(node.className.replace(Y.DOM._getRegExp('(?:^|\\s+)'+ +className+'(?:\\s+|$)'),' '));if(hasClass(node,className)){removeClass(node,className);}}},replaceClass:function(node,oldC,newC){addClass(node,newC);removeClass(node,oldC);},toggleClass:function(node,className){if(hasClass(node,className)){removeClass(node,className);}else{addClass(node,className);}}});hasClass=Y.DOM.hasClass;removeClass=Y.DOM.removeClass;addClass=Y.DOM.addClass;},'3.0.0',{requires:['oop']});YUI.add('dom-style',function(Y){(function(Y){var DOCUMENT_ELEMENT='documentElement',DEFAULT_VIEW='defaultView',OWNER_DOCUMENT='ownerDocument',STYLE='style',FLOAT='float',CSS_FLOAT='cssFloat',STYLE_FLOAT='styleFloat',TRANSPARENT='transparent',GET_COMPUTED_STYLE='getComputedStyle',DOCUMENT=Y.config.doc,UNDEFINED=undefined,re_color=/color$/i;Y.mix(Y.DOM,{CUSTOM_STYLES:{},setStyle:function(node,att,val,style){style=style||node.style;var CUSTOM_STYLES=Y.DOM.CUSTOM_STYLES;if(style){if(val===null){val='';} +if(att in CUSTOM_STYLES){if(CUSTOM_STYLES[att].set){CUSTOM_STYLES[att].set(node,val,style);return;}else if(typeof CUSTOM_STYLES[att]==='string'){att=CUSTOM_STYLES[att];}} +style[att]=val;}},getStyle:function(node,att){var style=node[STYLE],CUSTOM_STYLES=Y.DOM.CUSTOM_STYLES,val='';if(style){if(att in CUSTOM_STYLES){if(CUSTOM_STYLES[att].get){return CUSTOM_STYLES[att].get(node,att,style);}else if(typeof CUSTOM_STYLES[att]==='string'){att=CUSTOM_STYLES[att];}} +val=style[att];if(val===''){val=Y.DOM[GET_COMPUTED_STYLE](node,att);}} +return val;},setStyles:function(node,hash){var style=node.style;Y.each(hash,function(v,n){Y.DOM.setStyle(node,n,v,style);},Y.DOM);},getComputedStyle:function(node,att){var val='',doc=node[OWNER_DOCUMENT];if(node[STYLE]){val=doc[DEFAULT_VIEW][GET_COMPUTED_STYLE](node,null)[att];} +return val;}});if(DOCUMENT[DOCUMENT_ELEMENT][STYLE][CSS_FLOAT]!==UNDEFINED){Y.DOM.CUSTOM_STYLES[FLOAT]=CSS_FLOAT;}else if(DOCUMENT[DOCUMENT_ELEMENT][STYLE][STYLE_FLOAT]!==UNDEFINED){Y.DOM.CUSTOM_STYLES[FLOAT]=STYLE_FLOAT;} +if(Y.UA.opera){Y.DOM[GET_COMPUTED_STYLE]=function(node,att){var view=node[OWNER_DOCUMENT][DEFAULT_VIEW],val=view[GET_COMPUTED_STYLE](node,'')[att];if(re_color.test(att)){val=Y.Color.toRGB(val);} +return val;};} +if(Y.UA.webkit){Y.DOM[GET_COMPUTED_STYLE]=function(node,att){var view=node[OWNER_DOCUMENT][DEFAULT_VIEW],val=view[GET_COMPUTED_STYLE](node,'')[att];if(val==='rgba(0, 0, 0, 0)'){val=TRANSPARENT;} +return val;};}})(Y);(function(Y){var PARSE_INT=parseInt,RE=RegExp;Y.Color={KEYWORDS:{black:'000',silver:'c0c0c0',gray:'808080',white:'fff',maroon:'800000',red:'f00',purple:'800080',fuchsia:'f0f',green:'008000',lime:'0f0',olive:'808000',yellow:'ff0',navy:'000080',blue:'00f',teal:'008080',aqua:'0ff'},re_RGB:/^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i,re_hex:/^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i,re_hex3:/([0-9A-F])/gi,toRGB:function(val){if(!Y.Color.re_RGB.test(val)){val=Y.Color.toHex(val);} +if(Y.Color.re_hex.exec(val)){val='rgb('+[PARSE_INT(RE.$1,16),PARSE_INT(RE.$2,16),PARSE_INT(RE.$3,16)].join(', ')+')';} +return val;},toHex:function(val){val=Y.Color.KEYWORDS[val]||val;if(Y.Color.re_RGB.exec(val)){val=[Number(RE.$1).toString(16),Number(RE.$2).toString(16),Number(RE.$3).toString(16)];for(var i=0;i-1)){value=current;}else if(Y.DOM.IE.COMPUTED[property]){value=Y.DOM.IE.COMPUTED[property](el,property);}else if(re_unit.test(current)){value=ComputedStyle.getPixel(el,property)+PX;}else{value=current;}} +return value;},sizeOffsets:{width:['Left','Right'],height:['Top','Bottom'],top:['Top'],bottom:['Bottom']},getOffset:function(el,prop){var current=_getStyleObj(el)[prop],capped=prop.charAt(0).toUpperCase()+prop.substr(1),offset='offset'+capped,pixel='pixel'+capped,sizeOffsets=ComputedStyle.sizeOffsets[prop],value='';if(current===AUTO||current.indexOf('%')>-1){value=el['offset'+capped];if(sizeOffsets[0]){value-=ComputedStyle.getPixel(el,'padding'+sizeOffsets[0]);value-=ComputedStyle.getBorderWidth(el,'border'+sizeOffsets[0]+'Width',1);} +if(sizeOffsets[1]){value-=ComputedStyle.getPixel(el,'padding'+sizeOffsets[1]);value-=ComputedStyle.getBorderWidth(el,'border'+sizeOffsets[1]+'Width',1);}}else{if(!el.style[pixel]&&!el.style[prop]){el.style[prop]=current;} +value=el.style[pixel];} +return value+PX;},borderMap:{thin:'2px',medium:'4px',thick:'6px'},getBorderWidth:function(el,property,omitUnit){var unit=omitUnit?'':PX,current=el.currentStyle[property];if(current.indexOf(PX)<0){if(ComputedStyle.borderMap[current]){current=ComputedStyle.borderMap[current];}else{}} +return(omitUnit)?parseFloat(current):current;},getPixel:function(node,att){var val=null,style=_getStyleObj(node),styleRight=style.right,current=style[att];node.style.right=current;val=node.style.pixelRight;node.style.right=styleRight;return val;},getMargin:function(node,att){var val,style=_getStyleObj(node);if(style[att]==AUTO){val=0;}else{val=ComputedStyle.getPixel(node,att);} +return val+PX;},getVisibility:function(node,att){var current;while((current=node.currentStyle)&¤t[att]=='inherit'){node=node.parentNode;} +return(current)?current[att]:VISIBLE;},getColor:function(node,att){var current=_getStyleObj(node)[att];if(!current||current===TRANSPARENT){Y.DOM.elementByAxis(node,'parentNode',null,function(parent){current=_getStyleObj(parent)[att];if(current&¤t!==TRANSPARENT){node=parent;return true;}});} +return Y.Color.toRGB(current);},getBorderColor:function(node,att){var current=_getStyleObj(node),val=current[att]||current.color;return Y.Color.toRGB(Y.Color.toHex(val));}},IEComputed={};try{if(documentElement.style[OPACITY]===UNDEFINED&&documentElement[FILTERS]){Y.DOM.CUSTOM_STYLES[OPACITY]={get:function(node){var val=100;try{val=node[FILTERS]['DXImageTransform.Microsoft.Alpha'][OPACITY];}catch(e){try{val=node[FILTERS]('alpha')[OPACITY];}catch(err){}} +return val/100;},set:function(node,val,style){var current,styleObj;if(val===''){styleObj=_getStyleObj(node);current=(OPACITY in styleObj)?styleObj[OPACITY]:1;val=current;} +if(typeof style[FILTER]=='string'){style[FILTER]='alpha('+OPACITY+'='+val*100+')';if(!node.currentStyle||!node.currentStyle[HAS_LAYOUT]){style.zoom=1;}}}};}}catch(e){} +try{document.createElement('div').style.height='-1px';}catch(e){Y.DOM.CUSTOM_STYLES.height={set:function(node,val,style){var floatVal=parseFloat(val);if(isNaN(floatVal)||floatVal>=0){style.height=val;}else{}}};Y.DOM.CUSTOM_STYLES.width={set:function(node,val,style){var floatVal=parseFloat(val);if(isNaN(floatVal)||floatVal>=0){style.width=val;}else{}}};} +IEComputed[WIDTH]=IEComputed[HEIGHT]=ComputedStyle.getOffset;IEComputed.color=IEComputed.backgroundColor=ComputedStyle.getColor;IEComputed[BORDER_WIDTH]=IEComputed[BORDER_TOP_WIDTH]=IEComputed[BORDER_RIGHT_WIDTH]=IEComputed[BORDER_BOTTOM_WIDTH]=IEComputed[BORDER_LEFT_WIDTH]=ComputedStyle.getBorderWidth;IEComputed.marginTop=IEComputed.marginRight=IEComputed.marginBottom=IEComputed.marginLeft=ComputedStyle.getMargin;IEComputed.visibility=ComputedStyle.getVisibility;IEComputed.borderColor=IEComputed.borderTopColor=IEComputed.borderRightColor=IEComputed.borderBottomColor=IEComputed.borderLeftColor=ComputedStyle.getBorderColor;if(!Y.config.win[GET_COMPUTED_STYLE]){Y.DOM[GET_COMPUTED_STYLE]=ComputedStyle.get;} +Y.namespace('DOM.IE');Y.DOM.IE.COMPUTED=IEComputed;Y.DOM.IE.ComputedStyle=ComputedStyle;})(Y);},'3.0.0',{requires:['dom-base']});YUI.add('dom-screen',function(Y){(function(Y){var DOCUMENT_ELEMENT='documentElement',COMPAT_MODE='compatMode',POSITION='position',FIXED='fixed',RELATIVE='relative',LEFT='left',TOP='top',_BACK_COMPAT='BackCompat',MEDIUM='medium',BORDER_LEFT_WIDTH='borderLeftWidth',BORDER_TOP_WIDTH='borderTopWidth',GET_BOUNDING_CLIENT_RECT='getBoundingClientRect',GET_COMPUTED_STYLE='getComputedStyle',RE_TABLE=/^t(?:able|d|h)$/i;Y.mix(Y.DOM,{winHeight:function(node){var h=Y.DOM._getWinSize(node).height;return h;},winWidth:function(node){var w=Y.DOM._getWinSize(node).width;return w;},docHeight:function(node){var h=Y.DOM._getDocSize(node).height;return Math.max(h,Y.DOM._getWinSize(node).height);},docWidth:function(node){var w=Y.DOM._getDocSize(node).width;return Math.max(w,Y.DOM._getWinSize(node).width);},docScrollX:function(node){var doc=Y.DOM._getDoc(node);return Math.max(doc[DOCUMENT_ELEMENT].scrollLeft,doc.body.scrollLeft);},docScrollY:function(node){var doc=Y.DOM._getDoc(node);return Math.max(doc[DOCUMENT_ELEMENT].scrollTop,doc.body.scrollTop);},getXY:function(){if(document[DOCUMENT_ELEMENT][GET_BOUNDING_CLIENT_RECT]){return function(node){var xy=null,scrollLeft,scrollTop,box,off1,off2,bLeft,bTop,mode,doc;if(node){if(Y.DOM.inDoc(node)){scrollLeft=Y.DOM.docScrollX(node);scrollTop=Y.DOM.docScrollY(node);box=node[GET_BOUNDING_CLIENT_RECT]();doc=Y.DOM._getDoc(node);xy=[box.left,box.top];if(Y.UA.ie){off1=2;off2=2;mode=doc[COMPAT_MODE];bLeft=Y.DOM[GET_COMPUTED_STYLE](doc[DOCUMENT_ELEMENT],BORDER_LEFT_WIDTH);bTop=Y.DOM[GET_COMPUTED_STYLE](doc[DOCUMENT_ELEMENT],BORDER_TOP_WIDTH);if(Y.UA.ie===6){if(mode!==_BACK_COMPAT){off1=0;off2=0;}} +if((mode==_BACK_COMPAT)){if(bLeft!==MEDIUM){off1=parseInt(bLeft,10);} +if(bTop!==MEDIUM){off2=parseInt(bTop,10);}} +xy[0]-=off1;xy[1]-=off2;} +if((scrollTop||scrollLeft)){xy[0]+=scrollLeft;xy[1]+=scrollTop;}}else{xy=Y.DOM._getOffset(node);}} +return xy;};}else{return function(node){var xy=null,parentNode,bCheck,scrollTop,scrollLeft;if(node){if(Y.DOM.inDoc(node)){xy=[node.offsetLeft,node.offsetTop];parentNode=node;bCheck=((Y.UA.gecko||Y.UA.webkit>519)?true:false);while((parentNode=parentNode.offsetParent)){xy[0]+=parentNode.offsetLeft;xy[1]+=parentNode.offsetTop;if(bCheck){xy=Y.DOM._calcBorders(parentNode,xy);}} +if(Y.DOM.getStyle(node,POSITION)!=FIXED){parentNode=node;while((parentNode=parentNode.parentNode)){scrollTop=parentNode.scrollTop;scrollLeft=parentNode.scrollLeft;if(Y.UA.gecko&&(Y.DOM.getStyle(parentNode,'overflow')!=='visible')){xy=Y.DOM._calcBorders(parentNode,xy);} +if(scrollTop||scrollLeft){xy[0]-=scrollLeft;xy[1]-=scrollTop;}} +xy[0]+=Y.DOM.docScrollX(node);xy[1]+=Y.DOM.docScrollY(node);}else{xy[0]+=Y.DOM.docScrollX(node);xy[1]+=Y.DOM.docScrollY(node);}}else{xy=Y.DOM._getOffset(node);}} +return xy;};}}(),_getOffset:function(node){var pos,xy=null;if(node){pos=Y.DOM.getStyle(node,POSITION);xy=[parseInt(Y.DOM[GET_COMPUTED_STYLE](node,LEFT),10),parseInt(Y.DOM[GET_COMPUTED_STYLE](node,TOP),10)];if(isNaN(xy[0])){xy[0]=parseInt(Y.DOM.getStyle(node,LEFT),10);if(isNaN(xy[0])){xy[0]=(pos===RELATIVE)?0:node.offsetLeft||0;}} +if(isNaN(xy[1])){xy[1]=parseInt(Y.DOM.getStyle(node,TOP),10);if(isNaN(xy[1])){xy[1]=(pos===RELATIVE)?0:node.offsetTop||0;}}} +return xy;},getX:function(node){return Y.DOM.getXY(node)[0];},getY:function(node){return Y.DOM.getXY(node)[1];},setXY:function(node,xy,noRetry){var setStyle=Y.DOM.setStyle,pos,delta,newXY,currentXY;if(node&&xy){pos=Y.DOM.getStyle(node,POSITION);delta=Y.DOM._getOffset(node);if(pos=='static'){pos=RELATIVE;setStyle(node,POSITION,pos);} +currentXY=Y.DOM.getXY(node);if(xy[0]!==null){setStyle(node,LEFT,xy[0]-currentXY[0]+delta[0]+'px');} +if(xy[1]!==null){setStyle(node,TOP,xy[1]-currentXY[1]+delta[1]+'px');} +if(!noRetry){newXY=Y.DOM.getXY(node);if(newXY[0]!==xy[0]||newXY[1]!==xy[1]){Y.DOM.setXY(node,xy,true);}}}else{}},setX:function(node,x){return Y.DOM.setXY(node,[x,null]);},setY:function(node,y){return Y.DOM.setXY(node,[null,y]);},_calcBorders:function(node,xy2){var t=parseInt(Y.DOM[GET_COMPUTED_STYLE](node,BORDER_TOP_WIDTH),10)||0,l=parseInt(Y.DOM[GET_COMPUTED_STYLE](node,BORDER_LEFT_WIDTH),10)||0;if(Y.UA.gecko){if(RE_TABLE.test(node.tagName)){t=0;l=0;}} +xy2[0]+=l;xy2[1]+=t;return xy2;},_getWinSize:function(node){var doc=Y.DOM._getDoc(),win=doc.defaultView||doc.parentWindow,mode=doc[COMPAT_MODE],h=win.innerHeight,w=win.innerWidth,root=doc[DOCUMENT_ELEMENT];if(mode&&!Y.UA.opera){if(mode!='CSS1Compat'){root=doc.body;} +h=root.clientHeight;w=root.clientWidth;} +return{height:h,width:w};},_getDocSize:function(node){var doc=Y.DOM._getDoc(),root=doc[DOCUMENT_ELEMENT];if(doc[COMPAT_MODE]!='CSS1Compat'){root=doc.body;} +return{height:root.scrollHeight,width:root.scrollWidth};}});})(Y);(function(Y){var TOP='top',RIGHT='right',BOTTOM='bottom',LEFT='left',getOffsets=function(r1,r2){var t=Math.max(r1[TOP],r2[TOP]),r=Math.min(r1[RIGHT],r2[RIGHT]),b=Math.min(r1[BOTTOM],r2[BOTTOM]),l=Math.max(r1[LEFT],r2[LEFT]),ret={};ret[TOP]=t;ret[RIGHT]=r;ret[BOTTOM]=b;ret[LEFT]=l;return ret;},DOM=Y.DOM;Y.mix(DOM,{region:function(node){var xy=DOM.getXY(node),ret=false;if(node&&xy){ret=DOM._getRegion(xy[1],xy[0]+node.offsetWidth,xy[1]+node.offsetHeight,xy[0]);} +return ret;},intersect:function(node,node2,altRegion){var r=altRegion||DOM.region(node),region={},n=node2,off;if(n.tagName){region=DOM.region(n);}else if(Y.Lang.isObject(node2)){region=node2;}else{return false;} +off=getOffsets(region,r);return{top:off[TOP],right:off[RIGHT],bottom:off[BOTTOM],left:off[LEFT],area:((off[BOTTOM]-off[TOP])*(off[RIGHT]-off[LEFT])),yoff:((off[BOTTOM]-off[TOP])),xoff:(off[RIGHT]-off[LEFT]),inRegion:DOM.inRegion(node,node2,false,altRegion)};},inRegion:function(node,node2,all,altRegion){var region={},r=altRegion||DOM.region(node),n=node2,off;if(n.tagName){region=DOM.region(n);}else if(Y.Lang.isObject(node2)){region=node2;}else{return false;} +if(all){return(r[LEFT]>=region[LEFT]&&r[RIGHT]<=region[RIGHT]&&r[TOP]>=region[TOP]&&r[BOTTOM]<=region[BOTTOM]);}else{off=getOffsets(region,r);if(off[BOTTOM]>=off[TOP]&&off[RIGHT]>=off[LEFT]){return true;}else{return false;}}},inViewportRegion:function(node,all,altRegion){return DOM.inRegion(node,DOM.viewportRegion(node),all,altRegion);},_getRegion:function(t,r,b,l){var region={};region[TOP]=region[1]=t;region[LEFT]=region[0]=l;region[BOTTOM]=b;region[RIGHT]=r;region.width=region[RIGHT]-region[LEFT];region.height=region[BOTTOM]-region[TOP];return region;},viewportRegion:function(node){node=node||Y.config.doc.documentElement;var ret=false,scrollX,scrollY;if(node){scrollX=DOM.docScrollX(node);scrollY=DOM.docScrollY(node);ret=DOM._getRegion(scrollY,DOM.winWidth(node)+scrollX,scrollY+DOM.winHeight(node),scrollX);} +return ret;}});})(Y);},'3.0.0',{requires:['dom-base','dom-style']});YUI.add('selector-native',function(Y){(function(Y){Y.namespace('Selector');var COMPARE_DOCUMENT_POSITION='compareDocumentPosition',OWNER_DOCUMENT='ownerDocument',TMP_PREFIX='yui-tmp-',g_counter=0;var Selector={_foundCache:[],useNative:true,_compare:('sourceIndex'in document.documentElement)?function(nodeA,nodeB){var a=nodeA.sourceIndex,b=nodeB.sourceIndex;if(a===b){return 0;}else if(a>b){return 1;} +return-1;}:(document.documentElement[COMPARE_DOCUMENT_POSITION]?function(nodeA,nodeB){if(nodeA[COMPARE_DOCUMENT_POSITION](nodeB)&4){return-1;}else{return 1;}}:function(nodeA,nodeB){var rangeA,rangeB,compare;if(nodeA&&nodeB){rangeA=nodeA[OWNER_DOCUMENT].createRange();rangeA.setStart(nodeA,0);rangeB=nodeB[OWNER_DOCUMENT].createRange();rangeB.setStart(nodeB,0);compare=rangeA.compareBoundaryPoints(1,rangeB);} +return compare;}),_sort:function(nodes){if(nodes){nodes=Y.Array(nodes,0,true);if(nodes.sort){nodes.sort(Selector._compare);}} +return nodes;},_deDupe:function(nodes){var ret=[],i,node;for(i=0;(node=nodes[i++]);){if(!node._found){ret[ret.length]=node;node._found=true;}} +for(i=0;(node=ret[i++]);){node._found=null;node.removeAttribute('_found');} +return ret;},query:function(selector,root,firstOnly,skipNative){root=root||Y.config.doc;var ret=[],useNative=(Y.Selector.useNative&&document.querySelector&&!skipNative),queries=[[selector,root]],query,result,i,fn=(useNative)?Y.Selector._nativeQuery:Y.Selector._bruteQuery;if(selector&&fn){if(!skipNative&&(!useNative||root.tagName)){queries=Selector._splitQueries(selector,root);} +for(i=0;(query=queries[i++]);){result=fn(query[0],query[1],firstOnly);if(!firstOnly){result=Y.Array(result,0,true);} +if(result){ret=ret.concat(result);}} +if(queries.length>1){ret=Selector._sort(Selector._deDupe(ret));}} +return(firstOnly)?(ret[0]||null):ret;},_splitQueries:function(selector,node){var groups=selector.split(','),queries=[],prefix='',i,len;if(node){if(node.tagName){node.id=node.id||Y.guid();prefix='#'+node.id+' ';} +for(i=0,len=groups.length;i':{axis:'parentNode',direct:true},'+':{axis:'previousSibling',direct:true}},_parsers:[{name:ATTRIBUTES,re:/^\[([a-z]+\w*)+([~\|\^\$\*!=]=?)?['"]?([^\]]*?)['"]?\]/i,fn:function(match,token){var operator=match[2]||'',operators=Y.Selector.operators,test;if((match[1]==='id'&&operator==='=')||(match[1]==='className'&&document.getElementsByClassName&&(operator==='~='||operator==='='))){token.prefilter=match[1];token[match[1]]=match[3];} +if(operator in operators){test=operators[operator];if(typeof test==='string'){test=Y.Selector._getRegExp(test.replace('{val}',match[3]));} +match[2]=test;} +if(!token.last||token.prefilter!==match[1]){return match.slice(1);}}},{name:TAG_NAME,re:/^((?:-?[_a-z]+[\w-]*)|\*)/i,fn:function(match,token){var tag=match[1].toUpperCase();token.tagName=tag;if(tag!=='*'&&(!token.last||token.prefilter)){return[TAG_NAME,'=',tag];} +if(!token.prefilter){token.prefilter='tagName';}}},{name:COMBINATOR,re:/^\s*([>+~]|\s)\s*/,fn:function(match,token){}},{name:PSEUDOS,re:/^:([\-\w]+)(?:\(['"]?(.+)['"]?\))*/i,fn:function(match,token){var test=Selector[PSEUDOS][match[1]];if(test){return[match[2],test];}else{return false;}}}],_getToken:function(token){return{tagName:null,id:null,className:null,attributes:{},combinator:null,tests:[]};},_tokenize:function(selector){selector=selector||'';selector=Selector._replaceShorthand(Y.Lang.trim(selector));var token=Selector._getToken(),query=selector,tokens=[],found=false,match,test,i,parser;outer:do{found=false;for(i=0;(parser=Selector._parsers[i++]);){if((match=parser.re.exec(selector))){if(parser!==COMBINATOR){token.selector=selector;} +selector=selector.replace(match[0],'');if(!selector.length){token.last=true;} +if(Selector._attrFilters[match[1]]){match[1]=Selector._attrFilters[match[1]];} +test=parser.fn(match,token);if(test===false){found=false;break outer;}else if(test){token.tests.push(test);} +if(!selector.length||parser.name===COMBINATOR){tokens.push(token);token=Selector._getToken(token);if(parser.name===COMBINATOR){token.combinator=Y.Selector.combinators[match[1]];}} +found=true;}}}while(found&&selector.length);if(!found||selector.length){tokens=[];} +return tokens;},_replaceShorthand:function(selector){var shorthand=Selector.shorthand,attrs=selector.match(Selector._re.attr),pseudos=selector.match(Selector._re.pseudos),re,i,len;if(pseudos){selector=selector.replace(Selector._re.pseudos,'!!REPLACED_PSEUDO!!');} +if(attrs){selector=selector.replace(Selector._re.attr,'!!REPLACED_ATTRIBUTE!!');} +for(re in shorthand){if(shorthand.hasOwnProperty(re)){selector=selector.replace(Selector._getRegExp(re,'gi'),shorthand[re]);}} +if(attrs){for(i=0,len=attrs.length;i":{axis:"parentNode",direct:true},"+":{axis:"previousSibling",direct:true}},_parsers:[{name:E,re:/^\[([a-z]+\w*)+([~\|\^\$\*!=]=?)?['"]?([^\]]*?)['"]?\]/i,fn:function(K,L){var J=K[2]||"",I=G.Selector.operators,M;if((K[1]==="id"&&J==="=")||(K[1]==="className"&&document.getElementsByClassName&&(J==="~="||J==="="))){L.prefilter=K[1];L[K[1]]=K[3];}if(J in I){M=I[J];if(typeof M==="string"){M=G.Selector._getRegExp(M.replace("{val}",K[3]));}K[2]=M;}if(!L.last||L.prefilter!==K[1]){return K.slice(1);}}},{name:D,re:/^((?:-?[_a-z]+[\w-]*)|\*)/i,fn:function(J,K){var I=J[1].toUpperCase();K.tagName=I;if(I!=="*"&&(!K.last||K.prefilter)){return[D,"=",I];}if(!K.prefilter){K.prefilter="tagName";}}},{name:A,re:/^\s*([>+~]|\s)\s*/,fn:function(I,J){}},{name:F,re:/^:([\-\w]+)(?:\(['"]?(.+)['"]?\))*/i,fn:function(I,J){var K=C[F][I[1]];if(K){return[I[2],K];}else{return false;}}}],_getToken:function(I){return{tagName:null,id:null,className:null,attributes:{},combinator:null,tests:[]};},_tokenize:function(K){K=K||"";K=C._replaceShorthand(G.Lang.trim(K));var J=C._getToken(),P=K,O=[],Q=false,M,N,L,I;outer:do{Q=false;for(L=0;(I=C._parsers[L++]);){if((M=I.re.exec(K))){if(I!==A){J.selector=K;}K=K.replace(M[0],"");if(!K.length){J.last=true;}if(C._attrFilters[M[1]]){M[1]=C._attrFilters[M[1]];}N=I.fn(M,J);if(N===false){Q=false;break outer;}else{if(N){J.tests.push(N);}}if(!K.length||I.name===A){O.push(J);J=C._getToken(J);if(I.name===A){J.combinator=G.Selector.combinators[M[1]];}}Q=true;}}}while(Q&&K.length);if(!Q||K.length){O=[];}return O;},_replaceShorthand:function(J){var K=C.shorthand,L=J.match(C._re.attr),O=J.match(C._re.pseudos),N,M,I;if(O){J=J.replace(C._re.pseudos,"!!REPLACED_PSEUDO!!");}if(L){J=J.replace(C._re.attr,"!!REPLACED_ATTRIBUTE!!");}for(N in K){if(K.hasOwnProperty(N)){J=J.replace(C._getRegExp(N,"gi"),K[N]);}}if(L){for(M=0,I=L.length;M':{axis:'parentNode',direct:true},'+':{axis:'previousSibling',direct:true}},_parsers:[{name:ATTRIBUTES,re:/^\[([a-z]+\w*)+([~\|\^\$\*!=]=?)?['"]?([^\]]*?)['"]?\]/i,fn:function(match,token){var operator=match[2]||'',operators=Y.Selector.operators,test;if((match[1]==='id'&&operator==='=')||(match[1]==='className'&&document.getElementsByClassName&&(operator==='~='||operator==='='))){token.prefilter=match[1];token[match[1]]=match[3];} +if(operator in operators){test=operators[operator];if(typeof test==='string'){test=Y.Selector._getRegExp(test.replace('{val}',match[3]));} +match[2]=test;} +if(!token.last||token.prefilter!==match[1]){return match.slice(1);}}},{name:TAG_NAME,re:/^((?:-?[_a-z]+[\w-]*)|\*)/i,fn:function(match,token){var tag=match[1].toUpperCase();token.tagName=tag;if(tag!=='*'&&(!token.last||token.prefilter)){return[TAG_NAME,'=',tag];} +if(!token.prefilter){token.prefilter='tagName';}}},{name:COMBINATOR,re:/^\s*([>+~]|\s)\s*/,fn:function(match,token){}},{name:PSEUDOS,re:/^:([\-\w]+)(?:\(['"]?(.+)['"]?\))*/i,fn:function(match,token){var test=Selector[PSEUDOS][match[1]];if(test){return[match[2],test];}else{return false;}}}],_getToken:function(token){return{tagName:null,id:null,className:null,attributes:{},combinator:null,tests:[]};},_tokenize:function(selector){selector=selector||'';selector=Selector._replaceShorthand(Y.Lang.trim(selector));var token=Selector._getToken(),query=selector,tokens=[],found=false,match,test,i,parser;outer:do{found=false;for(i=0;(parser=Selector._parsers[i++]);){if((match=parser.re.exec(selector))){if(parser!==COMBINATOR){token.selector=selector;} +selector=selector.replace(match[0],'');if(!selector.length){token.last=true;} +if(Selector._attrFilters[match[1]]){match[1]=Selector._attrFilters[match[1]];} +test=parser.fn(match,token);if(test===false){found=false;break outer;}else if(test){token.tests.push(test);} +if(!selector.length||parser.name===COMBINATOR){tokens.push(token);token=Selector._getToken(token);if(parser.name===COMBINATOR){token.combinator=Y.Selector.combinators[match[1]];}} +found=true;}}}while(found&&selector.length);if(!found||selector.length){tokens=[];} +return tokens;},_replaceShorthand:function(selector){var shorthand=Selector.shorthand,attrs=selector.match(Selector._re.attr),pseudos=selector.match(Selector._re.pseudos),re,i,len;if(pseudos){selector=selector.replace(Selector._re.pseudos,'!!REPLACED_PSEUDO!!');} +if(attrs){selector=selector.replace(Selector._re.attr,'!!REPLACED_ATTRIBUTE!!');} +for(re in shorthand){if(shorthand.hasOwnProperty(re)){selector=selector.replace(Selector._getRegExp(re,'gi'),shorthand[re]);}} +if(attrs){for(i=0,len=attrs.length;i=0&&J[D]===C){return true;}}}else{for(var D=J.length-I,F=J.length;D>=0;D-=K){if(D-1;},"checked":function(B){return B.checked===true;}});A.mix(A.Selector.operators,{"^=":"^{val}","$=":"{val}$","*=":"{val}"});A.Selector.combinators["~"]={axis:"previousSibling"};},"3.0.0",{requires:["dom-base","selector-native","selector-css2"]}); \ No newline at end of file diff --git a/include/javascript/yui3/build/dom/selector-css3.js b/include/javascript/yui3/build/dom/selector-css3.js new file mode 100644 index 00000000..dbcb771b --- /dev/null +++ b/include/javascript/yui3/build/dom/selector-css3.js @@ -0,0 +1,12 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add('selector-css3',function(Y){Y.Selector._reNth=/^(?:([\-]?\d*)(n){1}|(odd|even)$)*([\-+]?\d*)$/;Y.Selector._getNth=function(node,expr,tag,reverse){Y.Selector._reNth.test(expr);var a=parseInt(RegExp.$1,10),n=RegExp.$2,oddeven=RegExp.$3,b=parseInt(RegExp.$4,10)||0,result=[],siblings=Y.Selector._children(node.parentNode,tag),op;if(oddeven){a=2;op='+';n='n';b=(oddeven==='odd')?1:0;}else if(isNaN(a)){a=(n)?1:0;} +if(a===0){if(reverse){b=siblings.length-b+1;} +if(siblings[b-1]===node){return true;}else{return false;}}else if(a<0){reverse=!!reverse;a=Math.abs(a);} +if(!reverse){for(var i=b-1,len=siblings.length;i=0&&siblings[i]===node){return true;}}}else{for(var i=siblings.length-b,len=siblings.length;i>=0;i-=a){if(i-1;},'checked':function(node){return node.checked===true;}});Y.mix(Y.Selector.operators,{'^=':'^{val}','$=':'{val}$','*=':'{val}'});Y.Selector.combinators['~']={axis:'previousSibling'};},'3.0.0',{requires:['dom-base','selector-native','selector-css2']}); \ No newline at end of file diff --git a/include/javascript/yui3/build/dom/selector-min.js b/include/javascript/yui3/build/dom/selector-min.js new file mode 100644 index 00000000..390d89ad --- /dev/null +++ b/include/javascript/yui3/build/dom/selector-min.js @@ -0,0 +1,8 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add("selector-native",function(A){(function(G){G.namespace("Selector");var E="compareDocumentPosition",F="ownerDocument",D="yui-tmp-",C=0;var B={_foundCache:[],useNative:true,_compare:("sourceIndex"in document.documentElement)?function(K,J){var I=K.sourceIndex,H=J.sourceIndex;if(I===H){return 0;}else{if(I>H){return 1;}}return-1;}:(document.documentElement[E]?function(I,H){if(I[E](H)&4){return-1;}else{return 1;}}:function(L,K){var J,H,I;if(L&&K){J=L[F].createRange();J.setStart(L,0);H=K[F].createRange();H.setStart(K,0);I=J.compareBoundaryPoints(1,H);}return I;}),_sort:function(H){if(H){H=G.Array(H,0,true);if(H.sort){H.sort(B._compare);}}return H;},_deDupe:function(H){var I=[],J,K;for(J=0;(K=H[J++]);){if(!K._found){I[I.length]=K;K._found=true;}}for(J=0;(K=I[J++]);){K._found=null;K.removeAttribute("_found");}return I;},query:function(I,P,Q,H){P=P||G.config.doc;var M=[],J=(G.Selector.useNative&&document.querySelector&&!H),L=[[I,P]],N,R,K,O=(J)?G.Selector._nativeQuery:G.Selector._bruteQuery;if(I&&O){if(!H&&(!J||P.tagName)){L=B._splitQueries(I,P);}for(K=0;(N=L[K++]);){R=O(N[0],N[1],Q);if(!Q){R=G.Array(R,0,true);}if(R){M=M.concat(R);}}if(L.length>1){M=B._sort(B._deDupe(M));}}return(Q)?(M[0]||null):M;},_splitQueries:function(J,M){var I=J.split(","),K=[],N="",L,H;if(M){if(M.tagName){M.id=M.id||G.guid();N="#"+M.id+" ";}for(L=0,H=I.length;L":{axis:"parentNode",direct:true},"+":{axis:"previousSibling",direct:true}},_parsers:[{name:E,re:/^\[([a-z]+\w*)+([~\|\^\$\*!=]=?)?['"]?([^\]]*?)['"]?\]/i,fn:function(K,L){var J=K[2]||"",I=G.Selector.operators,M;if((K[1]==="id"&&J==="=")||(K[1]==="className"&&document.getElementsByClassName&&(J==="~="||J==="="))){L.prefilter=K[1];L[K[1]]=K[3];}if(J in I){M=I[J];if(typeof M==="string"){M=G.Selector._getRegExp(M.replace("{val}",K[3]));}K[2]=M;}if(!L.last||L.prefilter!==K[1]){return K.slice(1);}}},{name:D,re:/^((?:-?[_a-z]+[\w-]*)|\*)/i,fn:function(J,K){var I=J[1].toUpperCase();K.tagName=I;if(I!=="*"&&(!K.last||K.prefilter)){return[D,"=",I];}if(!K.prefilter){K.prefilter="tagName";}}},{name:A,re:/^\s*([>+~]|\s)\s*/,fn:function(I,J){}},{name:F,re:/^:([\-\w]+)(?:\(['"]?(.+)['"]?\))*/i,fn:function(I,J){var K=C[F][I[1]];if(K){return[I[2],K];}else{return false;}}}],_getToken:function(I){return{tagName:null,id:null,className:null,attributes:{},combinator:null,tests:[]};},_tokenize:function(K){K=K||"";K=C._replaceShorthand(G.Lang.trim(K));var J=C._getToken(),P=K,O=[],Q=false,M,N,L,I;outer:do{Q=false;for(L=0;(I=C._parsers[L++]);){if((M=I.re.exec(K))){if(I!==A){J.selector=K;}K=K.replace(M[0],"");if(!K.length){J.last=true;}if(C._attrFilters[M[1]]){M[1]=C._attrFilters[M[1]];}N=I.fn(M,J);if(N===false){Q=false;break outer;}else{if(N){J.tests.push(N);}}if(!K.length||I.name===A){O.push(J);J=C._getToken(J);if(I.name===A){J.combinator=G.Selector.combinators[M[1]];}}Q=true;}}}while(Q&&K.length);if(!Q||K.length){O=[];}return O;},_replaceShorthand:function(J){var K=C.shorthand,L=J.match(C._re.attr),O=J.match(C._re.pseudos),N,M,I;if(O){J=J.replace(C._re.pseudos,"!!REPLACED_PSEUDO!!");}if(L){J=J.replace(C._re.attr,"!!REPLACED_ATTRIBUTE!!");}for(N in K){if(K.hasOwnProperty(N)){J=J.replace(C._getRegExp(N,"gi"),K[N]);}}if(L){for(M=0,I=L.length;MH){return 1;}}return-1;}:(document.documentElement[E]?function(I,H){if(I[E](H)&4){return-1;}else{return 1;}}:function(L,K){var J,H,I;if(L&&K){J=L[F].createRange();J.setStart(L,0);H=K[F].createRange();H.setStart(K,0);I=J.compareBoundaryPoints(1,H);}return I;}),_sort:function(H){if(H){H=G.Array(H,0,true);if(H.sort){H.sort(B._compare);}}return H;},_deDupe:function(H){var I=[],J,K;for(J=0;(K=H[J++]);){if(!K._found){I[I.length]=K;K._found=true;}}for(J=0;(K=I[J++]);){K._found=null;K.removeAttribute("_found");}return I;},query:function(I,P,Q,H){P=P||G.config.doc;var M=[],J=(G.Selector.useNative&&document.querySelector&&!H),L=[[I,P]],N,R,K,O=(J)?G.Selector._nativeQuery:G.Selector._bruteQuery;if(I&&O){if(!H&&(!J||P.tagName)){L=B._splitQueries(I,P);}for(K=0;(N=L[K++]);){R=O(N[0],N[1],Q);if(!Q){R=G.Array(R,0,true);}if(R){M=M.concat(R);}}if(L.length>1){M=B._sort(B._deDupe(M));}}return(Q)?(M[0]||null):M;},_splitQueries:function(J,M){var I=J.split(","),K=[],N="",L,H;if(M){if(M.tagName){M.id=M.id||G.guid();N="#"+M.id+" ";}for(L=0,H=I.length;Lb){return 1;} +return-1;}:(document.documentElement[COMPARE_DOCUMENT_POSITION]?function(nodeA,nodeB){if(nodeA[COMPARE_DOCUMENT_POSITION](nodeB)&4){return-1;}else{return 1;}}:function(nodeA,nodeB){var rangeA,rangeB,compare;if(nodeA&&nodeB){rangeA=nodeA[OWNER_DOCUMENT].createRange();rangeA.setStart(nodeA,0);rangeB=nodeB[OWNER_DOCUMENT].createRange();rangeB.setStart(nodeB,0);compare=rangeA.compareBoundaryPoints(1,rangeB);} +return compare;}),_sort:function(nodes){if(nodes){nodes=Y.Array(nodes,0,true);if(nodes.sort){nodes.sort(Selector._compare);}} +return nodes;},_deDupe:function(nodes){var ret=[],i,node;for(i=0;(node=nodes[i++]);){if(!node._found){ret[ret.length]=node;node._found=true;}} +for(i=0;(node=ret[i++]);){node._found=null;node.removeAttribute('_found');} +return ret;},query:function(selector,root,firstOnly,skipNative){root=root||Y.config.doc;var ret=[],useNative=(Y.Selector.useNative&&document.querySelector&&!skipNative),queries=[[selector,root]],query,result,i,fn=(useNative)?Y.Selector._nativeQuery:Y.Selector._bruteQuery;if(selector&&fn){if(!skipNative&&(!useNative||root.tagName)){queries=Selector._splitQueries(selector,root);} +for(i=0;(query=queries[i++]);){result=fn(query[0],query[1],firstOnly);if(!firstOnly){result=Y.Array(result,0,true);} +if(result){ret=ret.concat(result);}} +if(queries.length>1){ret=Selector._sort(Selector._deDupe(ret));}} +return(firstOnly)?(ret[0]||null):ret;},_splitQueries:function(selector,node){var groups=selector.split(','),queries=[],prefix='',i,len;if(node){if(node.tagName){node.id=node.id||Y.guid();prefix='#'+node.id+' ';} +for(i=0,len=groups.length;ib){return 1;} +return-1;}:(document.documentElement[COMPARE_DOCUMENT_POSITION]?function(nodeA,nodeB){if(nodeA[COMPARE_DOCUMENT_POSITION](nodeB)&4){return-1;}else{return 1;}}:function(nodeA,nodeB){var rangeA,rangeB,compare;if(nodeA&&nodeB){rangeA=nodeA[OWNER_DOCUMENT].createRange();rangeA.setStart(nodeA,0);rangeB=nodeB[OWNER_DOCUMENT].createRange();rangeB.setStart(nodeB,0);compare=rangeA.compareBoundaryPoints(1,rangeB);} +return compare;}),_sort:function(nodes){if(nodes){nodes=Y.Array(nodes,0,true);if(nodes.sort){nodes.sort(Selector._compare);}} +return nodes;},_deDupe:function(nodes){var ret=[],i,node;for(i=0;(node=nodes[i++]);){if(!node._found){ret[ret.length]=node;node._found=true;}} +for(i=0;(node=ret[i++]);){node._found=null;node.removeAttribute('_found');} +return ret;},query:function(selector,root,firstOnly,skipNative){root=root||Y.config.doc;var ret=[],useNative=(Y.Selector.useNative&&document.querySelector&&!skipNative),queries=[[selector,root]],query,result,i,fn=(useNative)?Y.Selector._nativeQuery:Y.Selector._bruteQuery;if(selector&&fn){if(!skipNative&&(!useNative||root.tagName)){queries=Selector._splitQueries(selector,root);} +for(i=0;(query=queries[i++]);){result=fn(query[0],query[1],firstOnly);if(!firstOnly){result=Y.Array(result,0,true);} +if(result){ret=ret.concat(result);}} +if(queries.length>1){ret=Selector._sort(Selector._deDupe(ret));}} +return(firstOnly)?(ret[0]||null):ret;},_splitQueries:function(selector,node){var groups=selector.split(','),queries=[],prefix='',i,len;if(node){if(node.tagName){node.id=node.id||Y.guid();prefix='#'+node.id+' ';} +for(i=0,len=groups.length;i':{axis:'parentNode',direct:true},'+':{axis:'previousSibling',direct:true}},_parsers:[{name:ATTRIBUTES,re:/^\[([a-z]+\w*)+([~\|\^\$\*!=]=?)?['"]?([^\]]*?)['"]?\]/i,fn:function(match,token){var operator=match[2]||'',operators=Y.Selector.operators,test;if((match[1]==='id'&&operator==='=')||(match[1]==='className'&&document.getElementsByClassName&&(operator==='~='||operator==='='))){token.prefilter=match[1];token[match[1]]=match[3];} +if(operator in operators){test=operators[operator];if(typeof test==='string'){test=Y.Selector._getRegExp(test.replace('{val}',match[3]));} +match[2]=test;} +if(!token.last||token.prefilter!==match[1]){return match.slice(1);}}},{name:TAG_NAME,re:/^((?:-?[_a-z]+[\w-]*)|\*)/i,fn:function(match,token){var tag=match[1].toUpperCase();token.tagName=tag;if(tag!=='*'&&(!token.last||token.prefilter)){return[TAG_NAME,'=',tag];} +if(!token.prefilter){token.prefilter='tagName';}}},{name:COMBINATOR,re:/^\s*([>+~]|\s)\s*/,fn:function(match,token){}},{name:PSEUDOS,re:/^:([\-\w]+)(?:\(['"]?(.+)['"]?\))*/i,fn:function(match,token){var test=Selector[PSEUDOS][match[1]];if(test){return[match[2],test];}else{return false;}}}],_getToken:function(token){return{tagName:null,id:null,className:null,attributes:{},combinator:null,tests:[]};},_tokenize:function(selector){selector=selector||'';selector=Selector._replaceShorthand(Y.Lang.trim(selector));var token=Selector._getToken(),query=selector,tokens=[],found=false,match,test,i,parser;outer:do{found=false;for(i=0;(parser=Selector._parsers[i++]);){if((match=parser.re.exec(selector))){if(parser!==COMBINATOR){token.selector=selector;} +selector=selector.replace(match[0],'');if(!selector.length){token.last=true;} +if(Selector._attrFilters[match[1]]){match[1]=Selector._attrFilters[match[1]];} +test=parser.fn(match,token);if(test===false){found=false;break outer;}else if(test){token.tests.push(test);} +if(!selector.length||parser.name===COMBINATOR){tokens.push(token);token=Selector._getToken(token);if(parser.name===COMBINATOR){token.combinator=Y.Selector.combinators[match[1]];}} +found=true;}}}while(found&&selector.length);if(!found||selector.length){tokens=[];} +return tokens;},_replaceShorthand:function(selector){var shorthand=Selector.shorthand,attrs=selector.match(Selector._re.attr),pseudos=selector.match(Selector._re.pseudos),re,i,len;if(pseudos){selector=selector.replace(Selector._re.pseudos,'!!REPLACED_PSEUDO!!');} +if(attrs){selector=selector.replace(Selector._re.attr,'!!REPLACED_ATTRIBUTE!!');} +for(re in shorthand){if(shorthand.hasOwnProperty(re)){selector=selector.replace(Selector._getRegExp(re,'gi'),shorthand[re]);}} +if(attrs){for(i=0,len=attrs.length;i0)?B.dump(N[I],M-1):C);}else{K.push(N[I]);}K.push(A);}if(K.length>1){K.pop();}K.push("]");}else{if(J=="regexp"){K.push(N.toString());}else{K.push("{");for(I in N){if(N.hasOwnProperty(I)){try{K.push(I+D);if(B.isObject(N[I])){K.push((M>0)?B.dump(N[I],M-1):C);}else{K.push(N[I]);}K.push(A);}catch(L){K.push("Error: "+L.message);}}}if(K.length>1){K.pop();}K.push("}");}}return K.join("");};G.dump=E;B.dump=E;},"3.0.0"); \ No newline at end of file diff --git a/include/javascript/yui3/build/dump/dump.js b/include/javascript/yui3/build/dump/dump.js new file mode 100644 index 00000000..e588db28 --- /dev/null +++ b/include/javascript/yui3/build/dump/dump.js @@ -0,0 +1,16 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add('dump',function(Y){var L=Y.Lang,OBJ='{...}',FUN='f(){...}',COMMA=', ',ARROW=' => ',dump=function(o,d){var i,len,s=[],type=L.type(o);if(!L.isObject(o)){return o+"";}else if(type=="date"){return o;}else if(o.nodeType&&o.tagName){return o.tagName+'#'+o.id;}else if(o.document&&o.navigator){return'window';}else if(o.location&&o.body){return'document';}else if(type=="function"){return FUN;} +d=(L.isNumber(d))?d:3;if(type=="array"){s.push("[");for(i=0,len=o.length;i0)?L.dump(o[i],d-1):OBJ);}else{s.push(o[i]);} +s.push(COMMA);} +if(s.length>1){s.pop();} +s.push("]");}else if(type=="regexp"){s.push(o.toString());}else{s.push("{");for(i in o){if(o.hasOwnProperty(i)){try{s.push(i+ARROW);if(L.isObject(o[i])){s.push((d>0)?L.dump(o[i],d-1):OBJ);}else{s.push(o[i]);} +s.push(COMMA);}catch(e){s.push('Error: '+e.message);}}} +if(s.length>1){s.pop();} +s.push("}");} +return s.join("");};Y.dump=dump;L.dump=dump;},'3.0.0'); \ No newline at end of file diff --git a/include/javascript/yui3/build/event-custom/event-custom-base-min.js b/include/javascript/yui3/build/event-custom/event-custom-base-min.js new file mode 100644 index 00000000..21c62188 --- /dev/null +++ b/include/javascript/yui3/build/event-custom/event-custom-base-min.js @@ -0,0 +1,8 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add("event-custom-base",function(E){E.Env.evt={handles:{},plugins:{}};(function(){var F=0,G=1;E.Do={objs:{},before:function(I,K,L,M){var J=I,H;if(M){H=[I,M].concat(E.Array(arguments,4,true));J=E.rbind.apply(E,H);}return this._inject(F,J,K,L);},after:function(I,K,L,M){var J=I,H;if(M){H=[I,M].concat(E.Array(arguments,4,true));J=E.rbind.apply(E,H);}return this._inject(G,J,K,L);},_inject:function(H,J,K,M){var N=E.stamp(K),L,I;if(!this.objs[N]){this.objs[N]={};}L=this.objs[N];if(!L[M]){L[M]=new E.Do.Method(K,M);K[M]=function(){return L[M].exec.apply(L[M],arguments);};}I=N+E.stamp(J)+M;L[M].register(I,J,H);return new E.EventHandle(L[M],I);},detach:function(H){if(H.detach){H.detach();}},_unload:function(I,H){}};E.Do.Method=function(H,I){this.obj=H;this.methodName=I;this.method=H[I];this.before={};this.after={};};E.Do.Method.prototype.register=function(I,J,H){if(H){this.after[I]=J;}else{this.before[I]=J;}};E.Do.Method.prototype._delete=function(H){delete this.before[H];delete this.after[H];};E.Do.Method.prototype.exec=function(){var J=E.Array(arguments,0,true),K,I,N,L=this.before,H=this.after,M=false;for(K in L){if(L.hasOwnProperty(K)){I=L[K].apply(this.obj,J);if(I){switch(I.constructor){case E.Do.Halt:return I.retVal;case E.Do.AlterArgs:J=I.newArgs;break;case E.Do.Prevent:M=true;break;default:}}}}if(!M){I=this.method.apply(this.obj,J);}for(K in H){if(H.hasOwnProperty(K)){N=H[K].apply(this.obj,J);if(N&&N.constructor==E.Do.Halt){return N.retVal;}else{if(N&&N.constructor==E.Do.AlterReturn){I=N.newRetVal;}}}}return I;};E.Do.AlterArgs=function(I,H){this.msg=I;this.newArgs=H;};E.Do.AlterReturn=function(I,H){this.msg=I;this.newRetVal=H;};E.Do.Halt=function(I,H){this.msg=I;this.retVal=H;};E.Do.Prevent=function(H){this.msg=H;};E.Do.Error=E.Do.Halt;})();var D="after",B=["broadcast","bubbles","context","contextFn","currentTarget","defaultFn","details","emitFacade","fireOnce","host","preventable","preventedFn","queuable","silent","stoppedFn","target","type"],C=9,A="yui:log";E.EventHandle=function(F,G){this.evt=F;this.sub=G;};E.EventHandle.prototype={detach:function(){var F=this.evt,G;if(F){if(E.Lang.isArray(F)){for(G=0;G2)?E.Array(arguments,2,true):null;return this._on(H,G,F,true);},on:function(H,G){var F=(arguments.length>2)?E.Array(arguments,2,true):null;return this._on(H,G,F,true);},after:function(H,G){var F=(arguments.length>2)?E.Array(arguments,2,true):null;return this._on(H,G,F,D);},detach:function(J,H){if(J&&J.detach){return J.detach();}var K=0,G=this.subscribers,F,I;for(F in G){if(G.hasOwnProperty(F)){I=G[F];if(I&&(!J||J===I.fn)){this._delete(I);K++;}}}return K;},unsubscribe:function(){return this.detach.apply(this,arguments);},_notify:function(I,H,F){this.log(this.type+"->"+"sub: "+I.id);var G;G=I.notify(H,this);if(false===G||this.stopped>1){this.log(this.type+" cancelled by subscriber");return false;}return true;},log:function(G,F){if(!this.silent){}},fire:function(){if(this.fireOnce&&this.fired){this.log("fireOnce event: "+this.type+" already fired");return true;}else{var F=E.Array(arguments,0,true);this.fired=true;this.firedWith=F;if(this.emitFacade){return this.fireComplex(F);}else{return this.fireSimple(F);}}},fireSimple:function(F){if(this.hasSubscribers||this.hasAfters){this._procSubs(E.merge(this.subscribers,this.afters),F);}this._broadcast(F);return this.stopped?false:true;},fireComplex:function(F){F[0]=F[0]||{};return this.fireSimple(F);},_procSubs:function(I,G,F){var J,H;for(H in I){if(I.hasOwnProperty(H)){J=I[H];if(J&&J.fn){if(false===this._notify(J,G,F)){this.stopped=2;}if(this.stopped==2){return false;}}}}return true;},_broadcast:function(G){if(!this.stopped&&this.broadcast){var F=E.Array(G);F.unshift(this.type);if(this.host!==E){E.fire.apply(E,F);}if(this.broadcast==2){E.Global.fire.apply(E.Global,F);}}},unsubscribeAll:function(){return this.detachAll.apply(this,arguments);},detachAll:function(){return this.detach();},_delete:function(F){if(F){delete F.fn;delete F.context;delete this.subscribers[F.id];delete this.afters[F.id];}}};E.Subscriber=function(H,G,F){this.fn=H;this.context=G;this.id=E.stamp(this);this.args=F;this.events=null;};E.Subscriber.prototype={_notify:function(J,H,I){var F=this.args,G;switch(I.signature){case 0:G=this.fn.call(J,I.type,H,J);break;case 1:G=this.fn.call(J,H[0]||null,J);break;default:if(F||H){H=H||[];F=(F)?H.concat(F):H;G=this.fn.apply(J,F);}else{G=this.fn.call(J);}}return G;},notify:function(G,I){var J=this.context,F=true;if(!J){J=(I.contextFn)?I.contextFn():I.context;}if(E.config.throwFail){F=this._notify(J,G,I);}else{try{F=this._notify(J,G,I);}catch(H){E.error(this+" failed: "+H.message,H);}}return F;},contains:function(G,F){if(F){return((this.fn==G)&&this.context==F);}else{return(this.fn==G);}}};(function(){var F=E.Lang,H=":",I="|",J="~AFTER~",K=E.cached(function(L,N){if(!N||!F.isString(L)||L.indexOf(H)>-1){return L;}return N+H+L;}),G=E.cached(function(O,Q){var N=O,P,R,L;if(!F.isString(N)){return N;}L=N.indexOf(J);if(L>-1){R=true;N=N.substr(J.length);}L=N.indexOf(I);if(L>-1){P=N.substr(0,(L));N=N.substr(L+1);if(N=="*"){N=null;}}return[P,(Q)?K(N,Q):N,R,N];}),M=function(L){var N=(F.isObject(L))?L:{};this._yuievt=this._yuievt||{id:E.guid(),events:{},targets:{},config:N,chain:("chain"in N)?N.chain:E.config.chain,defaults:{context:N.context||this,host:this,emitFacade:N.emitFacade,fireOnce:N.fireOnce,queuable:N.queuable,broadcast:N.broadcast,bubbles:("bubbles"in N)?N.bubbles:true}};};M.prototype={on:function(Q,U,O,V){var Z=G(Q,this._yuievt.config.prefix),a,b,N,g,X,W,d,R=E.Env.evt.handles,P,L,S,e=E.Node,Y,T;if(F.isObject(Q)){if(F.isFunction(Q)){return E.Do.before.apply(E.Do,arguments);}a=U;b=O;N=E.Array(arguments,0,true);g={};P=Q._after;delete Q._after;E.each(Q,function(f,c){if(f){a=f.fn||((E.Lang.isFunction(f))?f:a);b=f.context||b;}N[0]=(P)?J+c:c;N[1]=a;N[2]=b;g[c]=this.on.apply(this,N);},this);return(this._yuievt.chain)?this:new E.EventHandle(g);}W=Z[0];P=Z[2];S=Z[3];if(e&&(this instanceof e)&&(S in e.DOM_EVENTS)){N=E.Array(arguments,0,true);N.splice(2,0,e.getDOMNode(this));return E.on.apply(E,N);}Q=Z[1];if(this instanceof YUI){L=E.Env.evt.plugins[Q];N=E.Array(arguments,0,true);N[0]=S;if(e){Y=N[2];if(Y instanceof E.NodeList){Y=E.NodeList.getDOMNodes(Y);}else{if(Y instanceof e){Y=e.getDOMNode(Y);}}T=(S in e.DOM_EVENTS);if(T){N[2]=Y;}}if(L){d=L.on.apply(E,N);}else{if((!Q)||T){d=E.Event._attach(N);}}}if(!d){X=this._yuievt.events[Q]||this.publish(Q);d=X._on(U,O,(arguments.length>3)?E.Array(arguments,3,true):null,(P)?"after":true);}if(W){R[W]=R[W]||{};R[W][Q]=R[W][Q]||[];R[W][Q].push(d);}return(this._yuievt.chain)?this:d;},subscribe:function(){return this.on.apply(this,arguments);},detach:function(P,U,O){var T=this._yuievt.events,Z,d,c=E.Node,Y=(this instanceof c);if(!P&&(this!==E)){for(Z in T){if(T.hasOwnProperty(Z)){d=T[Z].detach(U,O);}}if(Y){E.Event.purgeElement(c.getDOMNode(this));}return d;}var X=G(P,this._yuievt.config.prefix),V=F.isArray(X)?X[0]:null,R=(X)?X[3]:null,b,L,Q=E.Env.evt.handles,S,N,W,a=function(g,f){var e=g[f];if(e){while(e.length){b=e.pop();b.detach();}}};if(V){S=Q[V];P=X[1];if(S){if(P){a(S,P);}else{for(Z in S){if(S.hasOwnProperty(Z)){a(S,Z);}}}return(this._yuievt.chain)?this:true;}}else{if(F.isObject(P)&&P.detach){d=P.detach();return(this._yuievt.chain)?this:d;}else{if(Y&&((!R)||(R in c.DOM_EVENTS))){N=E.Array(arguments,0,true);N[2]=c.getDOMNode(this);return E.detach.apply(E,N);}}}L=E.Env.evt.plugins[R];if(this instanceof YUI){N=E.Array(arguments,0,true);if(L&&L.detach){return L.detach.apply(E,N);}else{if(!P||(!L&&c&&(P in c.DOM_EVENTS))){N[0]=P;return E.Event.detach.apply(E.Event,N);}}}W=T[P];if(W){d=W.detach(U,O);}return(this._yuievt.chain)?this:d;},unsubscribe:function(){return this.detach.apply(this,arguments);},detachAll:function(L){return this.detach(L);},unsubscribeAll:function(){return this.detachAll.apply(this,arguments);},publish:function(O,P){var N,R,L,Q=this._yuievt.config.prefix;O=(Q)?K(O,Q):O;if(F.isObject(O)){L={};E.each(O,function(T,S){L[S]=this.publish(S,T||P);},this);return L;}N=this._yuievt.events;R=N[O];if(R){if(P){R.applyConfig(P,true);}}else{R=new E.CustomEvent(O,(P)?E.mix(P,this._yuievt.defaults):this._yuievt.defaults);N[O]=R;}return N[O];},addTarget:function(L){this._yuievt.targets[E.stamp(L)]=L;this._yuievt.hasTargets=true;},removeTarget:function(L){delete this._yuievt.targets[E.stamp(L)];},fire:function(P){var S=F.isString(P),O=(S)?P:(P&&P.type),R,L,N,Q=this._yuievt.config.prefix;O=(Q)?K(O,Q):O;R=this.getEvent(O,true);if(!R){if(this._yuievt.hasTargets){L=(S)?arguments:E.Array(arguments,0,true).unshift(O);return this.bubble(null,L,this);}N=true;}else{L=E.Array(arguments,(S)?1:0,true);N=R.fire.apply(R,L);R.target=null;}return(this._yuievt.chain)?this:N;},getEvent:function(N,L){var P,O;if(!L){P=this._yuievt.config.prefix;N=(P)?K(N,P):N;}O=this._yuievt.events;return(O&&N in O)?O[N]:null;},after:function(O,N){var L=E.Array(arguments,0,true);switch(F.type(O)){case"function":return E.Do.after.apply(E.Do,arguments);case"object":L[0]._after=true;break;default:L[0]=J+O;}return this.on.apply(this,L);},before:function(){return this.on.apply(this,arguments);}};E.EventTarget=M;E.mix(E,M.prototype,false,false,{bubbles:false});M.call(E);YUI.Env.globalEvents=YUI.Env.globalEvents||new M();E.Global=YUI.Env.globalEvents;})();},"3.0.0",{requires:["oop"]}); \ No newline at end of file diff --git a/include/javascript/yui3/build/event-custom/event-custom-base.js b/include/javascript/yui3/build/event-custom/event-custom-base.js new file mode 100644 index 00000000..50d84a1d --- /dev/null +++ b/include/javascript/yui3/build/event-custom/event-custom-base.js @@ -0,0 +1,54 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add('event-custom-base',function(Y){Y.Env.evt={handles:{},plugins:{}};(function(){var BEFORE=0,AFTER=1;Y.Do={objs:{},before:function(fn,obj,sFn,c){var f=fn,a;if(c){a=[fn,c].concat(Y.Array(arguments,4,true));f=Y.rbind.apply(Y,a);} +return this._inject(BEFORE,f,obj,sFn);},after:function(fn,obj,sFn,c){var f=fn,a;if(c){a=[fn,c].concat(Y.Array(arguments,4,true));f=Y.rbind.apply(Y,a);} +return this._inject(AFTER,f,obj,sFn);},_inject:function(when,fn,obj,sFn){var id=Y.stamp(obj),o,sid;if(!this.objs[id]){this.objs[id]={};} +o=this.objs[id];if(!o[sFn]){o[sFn]=new Y.Do.Method(obj,sFn);obj[sFn]=function(){return o[sFn].exec.apply(o[sFn],arguments);};} +sid=id+Y.stamp(fn)+sFn;o[sFn].register(sid,fn,when);return new Y.EventHandle(o[sFn],sid);},detach:function(handle){if(handle.detach){handle.detach();}},_unload:function(e,me){}};Y.Do.Method=function(obj,sFn){this.obj=obj;this.methodName=sFn;this.method=obj[sFn];this.before={};this.after={};};Y.Do.Method.prototype.register=function(sid,fn,when){if(when){this.after[sid]=fn;}else{this.before[sid]=fn;}};Y.Do.Method.prototype._delete=function(sid){delete this.before[sid];delete this.after[sid];};Y.Do.Method.prototype.exec=function(){var args=Y.Array(arguments,0,true),i,ret,newRet,bf=this.before,af=this.after,prevented=false;for(i in bf){if(bf.hasOwnProperty(i)){ret=bf[i].apply(this.obj,args);if(ret){switch(ret.constructor){case Y.Do.Halt:return ret.retVal;case Y.Do.AlterArgs:args=ret.newArgs;break;case Y.Do.Prevent:prevented=true;break;default:}}}} +if(!prevented){ret=this.method.apply(this.obj,args);} +for(i in af){if(af.hasOwnProperty(i)){newRet=af[i].apply(this.obj,args);if(newRet&&newRet.constructor==Y.Do.Halt){return newRet.retVal;}else if(newRet&&newRet.constructor==Y.Do.AlterReturn){ret=newRet.newRetVal;}}} +return ret;};Y.Do.AlterArgs=function(msg,newArgs){this.msg=msg;this.newArgs=newArgs;};Y.Do.AlterReturn=function(msg,newRetVal){this.msg=msg;this.newRetVal=newRetVal;};Y.Do.Halt=function(msg,retVal){this.msg=msg;this.retVal=retVal;};Y.Do.Prevent=function(msg){this.msg=msg;};Y.Do.Error=Y.Do.Halt;})();var AFTER='after',CONFIGS=['broadcast','bubbles','context','contextFn','currentTarget','defaultFn','details','emitFacade','fireOnce','host','preventable','preventedFn','queuable','silent','stoppedFn','target','type'],YUI3_SIGNATURE=9,YUI_LOG='yui:log';Y.EventHandle=function(evt,sub){this.evt=evt;this.sub=sub;};Y.EventHandle.prototype={detach:function(){var evt=this.evt,i;if(evt){if(Y.Lang.isArray(evt)){for(i=0;i2)?Y.Array(arguments,2,true):null;return this._on(fn,context,a,true);},on:function(fn,context){var a=(arguments.length>2)?Y.Array(arguments,2,true):null;return this._on(fn,context,a,true);},after:function(fn,context){var a=(arguments.length>2)?Y.Array(arguments,2,true):null;return this._on(fn,context,a,AFTER);},detach:function(fn,context){if(fn&&fn.detach){return fn.detach();} +var found=0,subs=this.subscribers,i,s;for(i in subs){if(subs.hasOwnProperty(i)){s=subs[i];if(s&&(!fn||fn===s.fn)){this._delete(s);found++;}}} +return found;},unsubscribe:function(){return this.detach.apply(this,arguments);},_notify:function(s,args,ef){this.log(this.type+"->"+"sub: "+s.id);var ret;ret=s.notify(args,this);if(false===ret||this.stopped>1){this.log(this.type+" cancelled by subscriber");return false;} +return true;},log:function(msg,cat){if(!this.silent){}},fire:function(){if(this.fireOnce&&this.fired){this.log('fireOnce event: '+this.type+' already fired');return true;}else{var args=Y.Array(arguments,0,true);this.fired=true;this.firedWith=args;if(this.emitFacade){return this.fireComplex(args);}else{return this.fireSimple(args);}}},fireSimple:function(args){if(this.hasSubscribers||this.hasAfters){this._procSubs(Y.merge(this.subscribers,this.afters),args);} +this._broadcast(args);return this.stopped?false:true;},fireComplex:function(args){args[0]=args[0]||{};return this.fireSimple(args);},_procSubs:function(subs,args,ef){var s,i;for(i in subs){if(subs.hasOwnProperty(i)){s=subs[i];if(s&&s.fn){if(false===this._notify(s,args,ef)){this.stopped=2;} +if(this.stopped==2){return false;}}}} +return true;},_broadcast:function(args){if(!this.stopped&&this.broadcast){var a=Y.Array(args);a.unshift(this.type);if(this.host!==Y){Y.fire.apply(Y,a);} +if(this.broadcast==2){Y.Global.fire.apply(Y.Global,a);}}},unsubscribeAll:function(){return this.detachAll.apply(this,arguments);},detachAll:function(){return this.detach();},_delete:function(s){if(s){delete s.fn;delete s.context;delete this.subscribers[s.id];delete this.afters[s.id];}}};Y.Subscriber=function(fn,context,args){this.fn=fn;this.context=context;this.id=Y.stamp(this);this.args=args;this.events=null;};Y.Subscriber.prototype={_notify:function(c,args,ce){var a=this.args,ret;switch(ce.signature){case 0:ret=this.fn.call(c,ce.type,args,c);break;case 1:ret=this.fn.call(c,args[0]||null,c);break;default:if(a||args){args=args||[];a=(a)?args.concat(a):args;ret=this.fn.apply(c,a);}else{ret=this.fn.call(c);}} +return ret;},notify:function(args,ce){var c=this.context,ret=true;if(!c){c=(ce.contextFn)?ce.contextFn():ce.context;} +if(Y.config.throwFail){ret=this._notify(c,args,ce);}else{try{ret=this._notify(c,args,ce);}catch(e){Y.error(this+' failed: '+e.message,e);}} +return ret;},contains:function(fn,context){if(context){return((this.fn==fn)&&this.context==context);}else{return(this.fn==fn);}}};(function(){var L=Y.Lang,PREFIX_DELIMITER=':',CATEGORY_DELIMITER='|',AFTER_PREFIX='~AFTER~',_getType=Y.cached(function(type,pre){if(!pre||!L.isString(type)||type.indexOf(PREFIX_DELIMITER)>-1){return type;} +return pre+PREFIX_DELIMITER+type;}),_parseType=Y.cached(function(type,pre){var t=type,detachcategory,after,i;if(!L.isString(t)){return t;} +i=t.indexOf(AFTER_PREFIX);if(i>-1){after=true;t=t.substr(AFTER_PREFIX.length);} +i=t.indexOf(CATEGORY_DELIMITER);if(i>-1){detachcategory=t.substr(0,(i));t=t.substr(i+1);if(t=='*'){t=null;}} +return[detachcategory,(pre)?_getType(t,pre):t,after,t];}),ET=function(opts){var o=(L.isObject(opts))?opts:{};this._yuievt=this._yuievt||{id:Y.guid(),events:{},targets:{},config:o,chain:('chain'in o)?o.chain:Y.config.chain,defaults:{context:o.context||this,host:this,emitFacade:o.emitFacade,fireOnce:o.fireOnce,queuable:o.queuable,broadcast:o.broadcast,bubbles:('bubbles'in o)?o.bubbles:true}};};ET.prototype={on:function(type,fn,context,x){var parts=_parseType(type,this._yuievt.config.prefix),f,c,args,ret,ce,detachcategory,handle,store=Y.Env.evt.handles,after,adapt,shorttype,Node=Y.Node,n,domevent;if(L.isObject(type)){if(L.isFunction(type)){return Y.Do.before.apply(Y.Do,arguments);} +f=fn;c=context;args=Y.Array(arguments,0,true);ret={};after=type._after;delete type._after;Y.each(type,function(v,k){if(v){f=v.fn||((Y.Lang.isFunction(v))?v:f);c=v.context||c;} +args[0]=(after)?AFTER_PREFIX+k:k;args[1]=f;args[2]=c;ret[k]=this.on.apply(this,args);},this);return(this._yuievt.chain)?this:new Y.EventHandle(ret);} +detachcategory=parts[0];after=parts[2];shorttype=parts[3];if(Node&&(this instanceof Node)&&(shorttype in Node.DOM_EVENTS)){args=Y.Array(arguments,0,true);args.splice(2,0,Node.getDOMNode(this));return Y.on.apply(Y,args);} +type=parts[1];if(this instanceof YUI){adapt=Y.Env.evt.plugins[type];args=Y.Array(arguments,0,true);args[0]=shorttype;if(Node){n=args[2];if(n instanceof Y.NodeList){n=Y.NodeList.getDOMNodes(n);}else if(n instanceof Node){n=Node.getDOMNode(n);} +domevent=(shorttype in Node.DOM_EVENTS);if(domevent){args[2]=n;}} +if(adapt){handle=adapt.on.apply(Y,args);}else if((!type)||domevent){handle=Y.Event._attach(args);}} +if(!handle){ce=this._yuievt.events[type]||this.publish(type);handle=ce._on(fn,context,(arguments.length>3)?Y.Array(arguments,3,true):null,(after)?'after':true);} +if(detachcategory){store[detachcategory]=store[detachcategory]||{};store[detachcategory][type]=store[detachcategory][type]||[];store[detachcategory][type].push(handle);} +return(this._yuievt.chain)?this:handle;},subscribe:function(){return this.on.apply(this,arguments);},detach:function(type,fn,context){var evts=this._yuievt.events,i,ret,Node=Y.Node,isNode=(this instanceof Node);if(!type&&(this!==Y)){for(i in evts){if(evts.hasOwnProperty(i)){ret=evts[i].detach(fn,context);}} +if(isNode){Y.Event.purgeElement(Node.getDOMNode(this));} +return ret;} +var parts=_parseType(type,this._yuievt.config.prefix),detachcategory=L.isArray(parts)?parts[0]:null,shorttype=(parts)?parts[3]:null,handle,adapt,store=Y.Env.evt.handles,cat,args,ce,keyDetacher=function(lcat,ltype){var handles=lcat[ltype];if(handles){while(handles.length){handle=handles.pop();handle.detach();}}};if(detachcategory){cat=store[detachcategory];type=parts[1];if(cat){if(type){keyDetacher(cat,type);}else{for(i in cat){if(cat.hasOwnProperty(i)){keyDetacher(cat,i);}}} +return(this._yuievt.chain)?this:true;}}else if(L.isObject(type)&&type.detach){ret=type.detach();return(this._yuievt.chain)?this:ret;}else if(isNode&&((!shorttype)||(shorttype in Node.DOM_EVENTS))){args=Y.Array(arguments,0,true);args[2]=Node.getDOMNode(this);return Y.detach.apply(Y,args);} +adapt=Y.Env.evt.plugins[shorttype];if(this instanceof YUI){args=Y.Array(arguments,0,true);if(adapt&&adapt.detach){return adapt.detach.apply(Y,args);}else if(!type||(!adapt&&Node&&(type in Node.DOM_EVENTS))){args[0]=type;return Y.Event.detach.apply(Y.Event,args);}} +ce=evts[type];if(ce){ret=ce.detach(fn,context);} +return(this._yuievt.chain)?this:ret;},unsubscribe:function(){return this.detach.apply(this,arguments);},detachAll:function(type){return this.detach(type);},unsubscribeAll:function(){return this.detachAll.apply(this,arguments);},publish:function(type,opts){var events,ce,ret,pre=this._yuievt.config.prefix;type=(pre)?_getType(type,pre):type;if(L.isObject(type)){ret={};Y.each(type,function(v,k){ret[k]=this.publish(k,v||opts);},this);return ret;} +events=this._yuievt.events;ce=events[type];if(ce){if(opts){ce.applyConfig(opts,true);}}else{ce=new Y.CustomEvent(type,(opts)?Y.mix(opts,this._yuievt.defaults):this._yuievt.defaults);events[type]=ce;} +return events[type];},addTarget:function(o){this._yuievt.targets[Y.stamp(o)]=o;this._yuievt.hasTargets=true;},removeTarget:function(o){delete this._yuievt.targets[Y.stamp(o)];},fire:function(type){var typeIncluded=L.isString(type),t=(typeIncluded)?type:(type&&type.type),ce,a,ret,pre=this._yuievt.config.prefix;t=(pre)?_getType(t,pre):t;ce=this.getEvent(t,true);if(!ce){if(this._yuievt.hasTargets){a=(typeIncluded)?arguments:Y.Array(arguments,0,true).unshift(t);return this.bubble(null,a,this);} +ret=true;}else{a=Y.Array(arguments,(typeIncluded)?1:0,true);ret=ce.fire.apply(ce,a);ce.target=null;} +return(this._yuievt.chain)?this:ret;},getEvent:function(type,prefixed){var pre,e;if(!prefixed){pre=this._yuievt.config.prefix;type=(pre)?_getType(type,pre):type;} +e=this._yuievt.events;return(e&&type in e)?e[type]:null;},after:function(type,fn){var a=Y.Array(arguments,0,true);switch(L.type(type)){case'function':return Y.Do.after.apply(Y.Do,arguments);case'object':a[0]._after=true;break;default:a[0]=AFTER_PREFIX+type;} +return this.on.apply(this,a);},before:function(){return this.on.apply(this,arguments);}};Y.EventTarget=ET;Y.mix(Y,ET.prototype,false,false,{bubbles:false});ET.call(Y);YUI.Env.globalEvents=YUI.Env.globalEvents||new ET();Y.Global=YUI.Env.globalEvents;})();},'3.0.0',{requires:['oop']}); \ No newline at end of file diff --git a/include/javascript/yui3/build/event-custom/event-custom-complex-min.js b/include/javascript/yui3/build/event-custom/event-custom-complex-min.js new file mode 100644 index 00000000..c4128679 --- /dev/null +++ b/include/javascript/yui3/build/event-custom/event-custom-complex-min.js @@ -0,0 +1,8 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add("event-custom-complex",function(A){(function(){var C,D,B=A.CustomEvent.prototype;A.EventFacade=function(F,E){F=F||{};this.details=F.details;this.type=F.type;this.target=F.target;this.currentTarget=E;this.relatedTarget=F.relatedTarget;this.stopPropagation=function(){F.stopPropagation();};this.stopImmediatePropagation=function(){F.stopImmediatePropagation();};this.preventDefault=function(){F.preventDefault();};this.halt=function(G){F.halt(G);};};B.fireComplex=function(H){var L=A.Env._eventstack,F,J,E,K,G,I;if(L){if(this.queuable&&this.type!=L.next.type){this.log("queue "+this.type);L.queue.push([this,H]);return true;}}else{A.Env._eventstack={id:this.id,next:this,silent:this.silent,stopped:0,prevented:0,queue:[]};L=A.Env._eventstack;}this.stopped=0;this.prevented=0;this.target=this.target||this.host;I=new A.EventTarget({fireOnce:true,context:this.host});this.events=I;if(this.preventedFn){I.on("prevented",this.preventedFn);}if(this.stoppedFn){I.on("stopped",this.stoppedFn);}this.currentTarget=this.host||this.currentTarget;this.details=H.slice();this.log("Firing "+this.type);this._facade=null;F=this._getFacade(H);if(A.Lang.isObject(H[0])){H[0]=F;}else{H.unshift(F);}if(this.hasSubscribers){this._procSubs(A.merge(this.subscribers),H,F);}if(this.bubbles&&this.host&&this.host.bubble&&!this.stopped){L.stopped=0;L.prevented=0;G=this.host.bubble(this);this.stopped=Math.max(this.stopped,L.stopped);this.prevented=Math.max(this.prevented,L.prevented);}if(this.defaultFn&&!this.prevented){this.defaultFn.apply(this.host||this,H);}this._broadcast(H);if(this.hasAfters&&!this.prevented&&this.stopped<2){this._procSubs(A.merge(this.afters),H,F);}if(L.id===this.id){E=L.queue;while(E.length){J=E.pop();K=J[0];L.stopped=0;L.prevented=0;L.next=K;K.fire.apply(K,J[1]);}A.Env._eventstack=null;}return this.stopped?false:true;};B._getFacade=function(){var E=this._facade,H,G,F=this.details;if(!E){E=new A.EventFacade(this,this.currentTarget);}H=F&&F[0];if(A.Lang.isObject(H,true)){G={};A.mix(G,E,true,D);A.mix(E,H,true);A.mix(E,G,true,D);}E.details=this.details;E.target=this.target;E.currentTarget=this.currentTarget;E.stopped=0;E.prevented=0;this._facade=E;return this._facade;};B.stopPropagation=function(){this.stopped=1;A.Env._eventstack.stopped=1;this.events.fire("stopped",this);};B.stopImmediatePropagation=function(){this.stopped=2;A.Env._eventstack.stopped=2;this.events.fire("stopped",this);};B.preventDefault=function(){if(this.preventable){this.prevented=1;A.Env._eventstack.prevented=1;this.events.fire("prevented",this);}};B.halt=function(E){if(E){this.stopImmediatePropagation();}else{this.stopPropagation();}this.preventDefault();};A.EventTarget.prototype.bubble=function(M,K,I){var G=this._yuievt.targets,J=true,N,L,E,F,H;if(!M||((!M.stopped)&&G)){for(F in G){if(G.hasOwnProperty(F)){N=G[F];L=M&&M.type;E=N.getEvent(L,true);if(!E){if(N._yuievt.hasTargets){N.bubble.call(N,M,K,I);}}else{E.target=I||(M&&M.target)||this;E.currentTarget=N;H=E.broadcast;E.broadcast=false;J=J&&E.fire.apply(E,K||M.details);E.broadcast=H;if(E.stopped){break;}}}}}return J;};C=new A.EventFacade();D=A.Object.keys(C);})();},"3.0.0",{requires:["event-custom-base"]}); \ No newline at end of file diff --git a/include/javascript/yui3/build/event-custom/event-custom-complex.js b/include/javascript/yui3/build/event-custom/event-custom-complex.js new file mode 100644 index 00000000..5660b723 --- /dev/null +++ b/include/javascript/yui3/build/event-custom/event-custom-complex.js @@ -0,0 +1,22 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add('event-custom-complex',function(Y){(function(){var FACADE,FACADE_KEYS,CEProto=Y.CustomEvent.prototype;Y.EventFacade=function(e,currentTarget){e=e||{};this.details=e.details;this.type=e.type;this.target=e.target;this.currentTarget=currentTarget;this.relatedTarget=e.relatedTarget;this.stopPropagation=function(){e.stopPropagation();};this.stopImmediatePropagation=function(){e.stopImmediatePropagation();};this.preventDefault=function(){e.preventDefault();};this.halt=function(immediate){e.halt(immediate);};};CEProto.fireComplex=function(args){var es=Y.Env._eventstack,ef,q,queue,ce,ret,events;if(es){if(this.queuable&&this.type!=es.next.type){this.log('queue '+this.type);es.queue.push([this,args]);return true;}}else{Y.Env._eventstack={id:this.id,next:this,silent:this.silent,stopped:0,prevented:0,queue:[]};es=Y.Env._eventstack;} +this.stopped=0;this.prevented=0;this.target=this.target||this.host;events=new Y.EventTarget({fireOnce:true,context:this.host});this.events=events;if(this.preventedFn){events.on('prevented',this.preventedFn);} +if(this.stoppedFn){events.on('stopped',this.stoppedFn);} +this.currentTarget=this.host||this.currentTarget;this.details=args.slice();this.log("Firing "+this.type);this._facade=null;ef=this._getFacade(args);if(Y.Lang.isObject(args[0])){args[0]=ef;}else{args.unshift(ef);} +if(this.hasSubscribers){this._procSubs(Y.merge(this.subscribers),args,ef);} +if(this.bubbles&&this.host&&this.host.bubble&&!this.stopped){es.stopped=0;es.prevented=0;ret=this.host.bubble(this);this.stopped=Math.max(this.stopped,es.stopped);this.prevented=Math.max(this.prevented,es.prevented);} +if(this.defaultFn&&!this.prevented){this.defaultFn.apply(this.host||this,args);} +this._broadcast(args);if(this.hasAfters&&!this.prevented&&this.stopped<2){this._procSubs(Y.merge(this.afters),args,ef);} +if(es.id===this.id){queue=es.queue;while(queue.length){q=queue.pop();ce=q[0];es.stopped=0;es.prevented=0;es.next=ce;ce.fire.apply(ce,q[1]);} +Y.Env._eventstack=null;} +return this.stopped?false:true;};CEProto._getFacade=function(){var ef=this._facade,o,o2,args=this.details;if(!ef){ef=new Y.EventFacade(this,this.currentTarget);} +o=args&&args[0];if(Y.Lang.isObject(o,true)){o2={};Y.mix(o2,ef,true,FACADE_KEYS);Y.mix(ef,o,true);Y.mix(ef,o2,true,FACADE_KEYS);} +ef.details=this.details;ef.target=this.target;ef.currentTarget=this.currentTarget;ef.stopped=0;ef.prevented=0;this._facade=ef;return this._facade;};CEProto.stopPropagation=function(){this.stopped=1;Y.Env._eventstack.stopped=1;this.events.fire('stopped',this);};CEProto.stopImmediatePropagation=function(){this.stopped=2;Y.Env._eventstack.stopped=2;this.events.fire('stopped',this);};CEProto.preventDefault=function(){if(this.preventable){this.prevented=1;Y.Env._eventstack.prevented=1;this.events.fire('prevented',this);}};CEProto.halt=function(immediate){if(immediate){this.stopImmediatePropagation();}else{this.stopPropagation();} +this.preventDefault();};Y.EventTarget.prototype.bubble=function(evt,args,target){var targs=this._yuievt.targets,ret=true,t,type,ce,i,bc;if(!evt||((!evt.stopped)&&targs)){for(i in targs){if(targs.hasOwnProperty(i)){t=targs[i];type=evt&&evt.type;ce=t.getEvent(type,true);if(!ce){if(t._yuievt.hasTargets){t.bubble.call(t,evt,args,target);}}else{ce.target=target||(evt&&evt.target)||this;ce.currentTarget=t;bc=ce.broadcast;ce.broadcast=false;ret=ret&&ce.fire.apply(ce,args||evt.details);ce.broadcast=bc;if(ce.stopped){break;}}}}} +return ret;};FACADE=new Y.EventFacade();FACADE_KEYS=Y.Object.keys(FACADE);})();},'3.0.0',{requires:['event-custom-base']}); \ No newline at end of file diff --git a/include/javascript/yui3/build/event-custom/event-custom-min.js b/include/javascript/yui3/build/event-custom/event-custom-min.js new file mode 100644 index 00000000..2cd14caf --- /dev/null +++ b/include/javascript/yui3/build/event-custom/event-custom-min.js @@ -0,0 +1,8 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add("event-custom-base",function(E){E.Env.evt={handles:{},plugins:{}};(function(){var F=0,G=1;E.Do={objs:{},before:function(I,K,L,M){var J=I,H;if(M){H=[I,M].concat(E.Array(arguments,4,true));J=E.rbind.apply(E,H);}return this._inject(F,J,K,L);},after:function(I,K,L,M){var J=I,H;if(M){H=[I,M].concat(E.Array(arguments,4,true));J=E.rbind.apply(E,H);}return this._inject(G,J,K,L);},_inject:function(H,J,K,M){var N=E.stamp(K),L,I;if(!this.objs[N]){this.objs[N]={};}L=this.objs[N];if(!L[M]){L[M]=new E.Do.Method(K,M);K[M]=function(){return L[M].exec.apply(L[M],arguments);};}I=N+E.stamp(J)+M;L[M].register(I,J,H);return new E.EventHandle(L[M],I);},detach:function(H){if(H.detach){H.detach();}},_unload:function(I,H){}};E.Do.Method=function(H,I){this.obj=H;this.methodName=I;this.method=H[I];this.before={};this.after={};};E.Do.Method.prototype.register=function(I,J,H){if(H){this.after[I]=J;}else{this.before[I]=J;}};E.Do.Method.prototype._delete=function(H){delete this.before[H];delete this.after[H];};E.Do.Method.prototype.exec=function(){var J=E.Array(arguments,0,true),K,I,N,L=this.before,H=this.after,M=false;for(K in L){if(L.hasOwnProperty(K)){I=L[K].apply(this.obj,J);if(I){switch(I.constructor){case E.Do.Halt:return I.retVal;case E.Do.AlterArgs:J=I.newArgs;break;case E.Do.Prevent:M=true;break;default:}}}}if(!M){I=this.method.apply(this.obj,J);}for(K in H){if(H.hasOwnProperty(K)){N=H[K].apply(this.obj,J);if(N&&N.constructor==E.Do.Halt){return N.retVal;}else{if(N&&N.constructor==E.Do.AlterReturn){I=N.newRetVal;}}}}return I;};E.Do.AlterArgs=function(I,H){this.msg=I;this.newArgs=H;};E.Do.AlterReturn=function(I,H){this.msg=I;this.newRetVal=H;};E.Do.Halt=function(I,H){this.msg=I;this.retVal=H;};E.Do.Prevent=function(H){this.msg=H;};E.Do.Error=E.Do.Halt;})();var D="after",B=["broadcast","bubbles","context","contextFn","currentTarget","defaultFn","details","emitFacade","fireOnce","host","preventable","preventedFn","queuable","silent","stoppedFn","target","type"],C=9,A="yui:log";E.EventHandle=function(F,G){this.evt=F;this.sub=G;};E.EventHandle.prototype={detach:function(){var F=this.evt,G;if(F){if(E.Lang.isArray(F)){for(G=0;G2)?E.Array(arguments,2,true):null;return this._on(H,G,F,true);},on:function(H,G){var F=(arguments.length>2)?E.Array(arguments,2,true):null;return this._on(H,G,F,true);},after:function(H,G){var F=(arguments.length>2)?E.Array(arguments,2,true):null;return this._on(H,G,F,D);},detach:function(J,H){if(J&&J.detach){return J.detach();}var K=0,G=this.subscribers,F,I;for(F in G){if(G.hasOwnProperty(F)){I=G[F];if(I&&(!J||J===I.fn)){this._delete(I);K++;}}}return K;},unsubscribe:function(){return this.detach.apply(this,arguments);},_notify:function(I,H,F){this.log(this.type+"->"+"sub: "+I.id);var G;G=I.notify(H,this);if(false===G||this.stopped>1){this.log(this.type+" cancelled by subscriber");return false;}return true;},log:function(G,F){if(!this.silent){}},fire:function(){if(this.fireOnce&&this.fired){this.log("fireOnce event: "+this.type+" already fired");return true;}else{var F=E.Array(arguments,0,true);this.fired=true;this.firedWith=F;if(this.emitFacade){return this.fireComplex(F);}else{return this.fireSimple(F);}}},fireSimple:function(F){if(this.hasSubscribers||this.hasAfters){this._procSubs(E.merge(this.subscribers,this.afters),F);}this._broadcast(F);return this.stopped?false:true;},fireComplex:function(F){F[0]=F[0]||{};return this.fireSimple(F);},_procSubs:function(I,G,F){var J,H;for(H in I){if(I.hasOwnProperty(H)){J=I[H];if(J&&J.fn){if(false===this._notify(J,G,F)){this.stopped=2;}if(this.stopped==2){return false;}}}}return true;},_broadcast:function(G){if(!this.stopped&&this.broadcast){var F=E.Array(G);F.unshift(this.type);if(this.host!==E){E.fire.apply(E,F);}if(this.broadcast==2){E.Global.fire.apply(E.Global,F);}}},unsubscribeAll:function(){return this.detachAll.apply(this,arguments);},detachAll:function(){return this.detach();},_delete:function(F){if(F){delete F.fn;delete F.context;delete this.subscribers[F.id];delete this.afters[F.id];}}};E.Subscriber=function(H,G,F){this.fn=H;this.context=G;this.id=E.stamp(this);this.args=F;this.events=null;};E.Subscriber.prototype={_notify:function(J,H,I){var F=this.args,G;switch(I.signature){case 0:G=this.fn.call(J,I.type,H,J);break;case 1:G=this.fn.call(J,H[0]||null,J);break;default:if(F||H){H=H||[];F=(F)?H.concat(F):H;G=this.fn.apply(J,F);}else{G=this.fn.call(J);}}return G;},notify:function(G,I){var J=this.context,F=true;if(!J){J=(I.contextFn)?I.contextFn():I.context;}if(E.config.throwFail){F=this._notify(J,G,I);}else{try{F=this._notify(J,G,I);}catch(H){E.error(this+" failed: "+H.message,H);}}return F;},contains:function(G,F){if(F){return((this.fn==G)&&this.context==F);}else{return(this.fn==G);}}};(function(){var F=E.Lang,H=":",I="|",J="~AFTER~",K=E.cached(function(L,N){if(!N||!F.isString(L)||L.indexOf(H)>-1){return L;}return N+H+L;}),G=E.cached(function(O,Q){var N=O,P,R,L;if(!F.isString(N)){return N;}L=N.indexOf(J);if(L>-1){R=true;N=N.substr(J.length);}L=N.indexOf(I);if(L>-1){P=N.substr(0,(L));N=N.substr(L+1);if(N=="*"){N=null;}}return[P,(Q)?K(N,Q):N,R,N];}),M=function(L){var N=(F.isObject(L))?L:{};this._yuievt=this._yuievt||{id:E.guid(),events:{},targets:{},config:N,chain:("chain"in N)?N.chain:E.config.chain,defaults:{context:N.context||this,host:this,emitFacade:N.emitFacade,fireOnce:N.fireOnce,queuable:N.queuable,broadcast:N.broadcast,bubbles:("bubbles"in N)?N.bubbles:true}};};M.prototype={on:function(Q,U,O,V){var Z=G(Q,this._yuievt.config.prefix),a,b,N,g,X,W,d,R=E.Env.evt.handles,P,L,S,e=E.Node,Y,T;if(F.isObject(Q)){if(F.isFunction(Q)){return E.Do.before.apply(E.Do,arguments);}a=U;b=O;N=E.Array(arguments,0,true);g={};P=Q._after;delete Q._after;E.each(Q,function(f,c){if(f){a=f.fn||((E.Lang.isFunction(f))?f:a);b=f.context||b;}N[0]=(P)?J+c:c;N[1]=a;N[2]=b;g[c]=this.on.apply(this,N);},this);return(this._yuievt.chain)?this:new E.EventHandle(g);}W=Z[0];P=Z[2];S=Z[3];if(e&&(this instanceof e)&&(S in e.DOM_EVENTS)){N=E.Array(arguments,0,true);N.splice(2,0,e.getDOMNode(this));return E.on.apply(E,N);}Q=Z[1];if(this instanceof YUI){L=E.Env.evt.plugins[Q];N=E.Array(arguments,0,true);N[0]=S;if(e){Y=N[2];if(Y instanceof E.NodeList){Y=E.NodeList.getDOMNodes(Y);}else{if(Y instanceof e){Y=e.getDOMNode(Y);}}T=(S in e.DOM_EVENTS);if(T){N[2]=Y;}}if(L){d=L.on.apply(E,N);}else{if((!Q)||T){d=E.Event._attach(N);}}}if(!d){X=this._yuievt.events[Q]||this.publish(Q);d=X._on(U,O,(arguments.length>3)?E.Array(arguments,3,true):null,(P)?"after":true);}if(W){R[W]=R[W]||{};R[W][Q]=R[W][Q]||[];R[W][Q].push(d);}return(this._yuievt.chain)?this:d;},subscribe:function(){return this.on.apply(this,arguments);},detach:function(P,U,O){var T=this._yuievt.events,Z,d,c=E.Node,Y=(this instanceof c);if(!P&&(this!==E)){for(Z in T){if(T.hasOwnProperty(Z)){d=T[Z].detach(U,O);}}if(Y){E.Event.purgeElement(c.getDOMNode(this));}return d;}var X=G(P,this._yuievt.config.prefix),V=F.isArray(X)?X[0]:null,R=(X)?X[3]:null,b,L,Q=E.Env.evt.handles,S,N,W,a=function(g,f){var e=g[f];if(e){while(e.length){b=e.pop();b.detach();}}};if(V){S=Q[V];P=X[1];if(S){if(P){a(S,P);}else{for(Z in S){if(S.hasOwnProperty(Z)){a(S,Z);}}}return(this._yuievt.chain)?this:true;}}else{if(F.isObject(P)&&P.detach){d=P.detach();return(this._yuievt.chain)?this:d;}else{if(Y&&((!R)||(R in c.DOM_EVENTS))){N=E.Array(arguments,0,true);N[2]=c.getDOMNode(this);return E.detach.apply(E,N);}}}L=E.Env.evt.plugins[R];if(this instanceof YUI){N=E.Array(arguments,0,true);if(L&&L.detach){return L.detach.apply(E,N);}else{if(!P||(!L&&c&&(P in c.DOM_EVENTS))){N[0]=P;return E.Event.detach.apply(E.Event,N);}}}W=T[P];if(W){d=W.detach(U,O);}return(this._yuievt.chain)?this:d;},unsubscribe:function(){return this.detach.apply(this,arguments);},detachAll:function(L){return this.detach(L);},unsubscribeAll:function(){return this.detachAll.apply(this,arguments);},publish:function(O,P){var N,R,L,Q=this._yuievt.config.prefix;O=(Q)?K(O,Q):O;if(F.isObject(O)){L={};E.each(O,function(T,S){L[S]=this.publish(S,T||P);},this);return L;}N=this._yuievt.events;R=N[O];if(R){if(P){R.applyConfig(P,true);}}else{R=new E.CustomEvent(O,(P)?E.mix(P,this._yuievt.defaults):this._yuievt.defaults);N[O]=R;}return N[O];},addTarget:function(L){this._yuievt.targets[E.stamp(L)]=L;this._yuievt.hasTargets=true;},removeTarget:function(L){delete this._yuievt.targets[E.stamp(L)];},fire:function(P){var S=F.isString(P),O=(S)?P:(P&&P.type),R,L,N,Q=this._yuievt.config.prefix;O=(Q)?K(O,Q):O;R=this.getEvent(O,true);if(!R){if(this._yuievt.hasTargets){L=(S)?arguments:E.Array(arguments,0,true).unshift(O);return this.bubble(null,L,this);}N=true;}else{L=E.Array(arguments,(S)?1:0,true);N=R.fire.apply(R,L);R.target=null;}return(this._yuievt.chain)?this:N;},getEvent:function(N,L){var P,O;if(!L){P=this._yuievt.config.prefix;N=(P)?K(N,P):N;}O=this._yuievt.events;return(O&&N in O)?O[N]:null;},after:function(O,N){var L=E.Array(arguments,0,true);switch(F.type(O)){case"function":return E.Do.after.apply(E.Do,arguments);case"object":L[0]._after=true;break;default:L[0]=J+O;}return this.on.apply(this,L);},before:function(){return this.on.apply(this,arguments);}};E.EventTarget=M;E.mix(E,M.prototype,false,false,{bubbles:false});M.call(E);YUI.Env.globalEvents=YUI.Env.globalEvents||new M();E.Global=YUI.Env.globalEvents;})();},"3.0.0",{requires:["oop"]});YUI.add("event-custom-complex",function(A){(function(){var C,D,B=A.CustomEvent.prototype;A.EventFacade=function(F,E){F=F||{};this.details=F.details;this.type=F.type;this.target=F.target;this.currentTarget=E;this.relatedTarget=F.relatedTarget;this.stopPropagation=function(){F.stopPropagation();};this.stopImmediatePropagation=function(){F.stopImmediatePropagation();};this.preventDefault=function(){F.preventDefault();};this.halt=function(G){F.halt(G);};};B.fireComplex=function(H){var L=A.Env._eventstack,F,J,E,K,G,I;if(L){if(this.queuable&&this.type!=L.next.type){this.log("queue "+this.type);L.queue.push([this,H]);return true;}}else{A.Env._eventstack={id:this.id,next:this,silent:this.silent,stopped:0,prevented:0,queue:[]};L=A.Env._eventstack;}this.stopped=0;this.prevented=0;this.target=this.target||this.host;I=new A.EventTarget({fireOnce:true,context:this.host});this.events=I;if(this.preventedFn){I.on("prevented",this.preventedFn);}if(this.stoppedFn){I.on("stopped",this.stoppedFn);}this.currentTarget=this.host||this.currentTarget;this.details=H.slice();this.log("Firing "+this.type);this._facade=null;F=this._getFacade(H);if(A.Lang.isObject(H[0])){H[0]=F;}else{H.unshift(F);}if(this.hasSubscribers){this._procSubs(A.merge(this.subscribers),H,F);}if(this.bubbles&&this.host&&this.host.bubble&&!this.stopped){L.stopped=0;L.prevented=0;G=this.host.bubble(this);this.stopped=Math.max(this.stopped,L.stopped);this.prevented=Math.max(this.prevented,L.prevented);}if(this.defaultFn&&!this.prevented){this.defaultFn.apply(this.host||this,H);}this._broadcast(H);if(this.hasAfters&&!this.prevented&&this.stopped<2){this._procSubs(A.merge(this.afters),H,F);}if(L.id===this.id){E=L.queue;while(E.length){J=E.pop();K=J[0];L.stopped=0;L.prevented=0;L.next=K;K.fire.apply(K,J[1]);}A.Env._eventstack=null;}return this.stopped?false:true;};B._getFacade=function(){var E=this._facade,H,G,F=this.details;if(!E){E=new A.EventFacade(this,this.currentTarget);}H=F&&F[0];if(A.Lang.isObject(H,true)){G={};A.mix(G,E,true,D);A.mix(E,H,true);A.mix(E,G,true,D);}E.details=this.details;E.target=this.target;E.currentTarget=this.currentTarget;E.stopped=0;E.prevented=0;this._facade=E;return this._facade;};B.stopPropagation=function(){this.stopped=1;A.Env._eventstack.stopped=1;this.events.fire("stopped",this);};B.stopImmediatePropagation=function(){this.stopped=2;A.Env._eventstack.stopped=2;this.events.fire("stopped",this);};B.preventDefault=function(){if(this.preventable){this.prevented=1;A.Env._eventstack.prevented=1;this.events.fire("prevented",this);}};B.halt=function(E){if(E){this.stopImmediatePropagation();}else{this.stopPropagation();}this.preventDefault();};A.EventTarget.prototype.bubble=function(M,K,I){var G=this._yuievt.targets,J=true,N,L,E,F,H;if(!M||((!M.stopped)&&G)){for(F in G){if(G.hasOwnProperty(F)){N=G[F];L=M&&M.type;E=N.getEvent(L,true);if(!E){if(N._yuievt.hasTargets){N.bubble.call(N,M,K,I);}}else{E.target=I||(M&&M.target)||this;E.currentTarget=N;H=E.broadcast;E.broadcast=false;J=J&&E.fire.apply(E,K||M.details);E.broadcast=H;if(E.stopped){break;}}}}}return J;};C=new A.EventFacade();D=A.Object.keys(C);})();},"3.0.0",{requires:["event-custom-base"]});YUI.add("event-custom",function(A){},"3.0.0",{use:["event-custom-base","event-custom-complex"]}); \ No newline at end of file diff --git a/include/javascript/yui3/build/event-custom/event-custom.js b/include/javascript/yui3/build/event-custom/event-custom.js new file mode 100644 index 00000000..18f07dd3 --- /dev/null +++ b/include/javascript/yui3/build/event-custom/event-custom.js @@ -0,0 +1,68 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add('event-custom-base',function(Y){Y.Env.evt={handles:{},plugins:{}};(function(){var BEFORE=0,AFTER=1;Y.Do={objs:{},before:function(fn,obj,sFn,c){var f=fn,a;if(c){a=[fn,c].concat(Y.Array(arguments,4,true));f=Y.rbind.apply(Y,a);} +return this._inject(BEFORE,f,obj,sFn);},after:function(fn,obj,sFn,c){var f=fn,a;if(c){a=[fn,c].concat(Y.Array(arguments,4,true));f=Y.rbind.apply(Y,a);} +return this._inject(AFTER,f,obj,sFn);},_inject:function(when,fn,obj,sFn){var id=Y.stamp(obj),o,sid;if(!this.objs[id]){this.objs[id]={};} +o=this.objs[id];if(!o[sFn]){o[sFn]=new Y.Do.Method(obj,sFn);obj[sFn]=function(){return o[sFn].exec.apply(o[sFn],arguments);};} +sid=id+Y.stamp(fn)+sFn;o[sFn].register(sid,fn,when);return new Y.EventHandle(o[sFn],sid);},detach:function(handle){if(handle.detach){handle.detach();}},_unload:function(e,me){}};Y.Do.Method=function(obj,sFn){this.obj=obj;this.methodName=sFn;this.method=obj[sFn];this.before={};this.after={};};Y.Do.Method.prototype.register=function(sid,fn,when){if(when){this.after[sid]=fn;}else{this.before[sid]=fn;}};Y.Do.Method.prototype._delete=function(sid){delete this.before[sid];delete this.after[sid];};Y.Do.Method.prototype.exec=function(){var args=Y.Array(arguments,0,true),i,ret,newRet,bf=this.before,af=this.after,prevented=false;for(i in bf){if(bf.hasOwnProperty(i)){ret=bf[i].apply(this.obj,args);if(ret){switch(ret.constructor){case Y.Do.Halt:return ret.retVal;case Y.Do.AlterArgs:args=ret.newArgs;break;case Y.Do.Prevent:prevented=true;break;default:}}}} +if(!prevented){ret=this.method.apply(this.obj,args);} +for(i in af){if(af.hasOwnProperty(i)){newRet=af[i].apply(this.obj,args);if(newRet&&newRet.constructor==Y.Do.Halt){return newRet.retVal;}else if(newRet&&newRet.constructor==Y.Do.AlterReturn){ret=newRet.newRetVal;}}} +return ret;};Y.Do.AlterArgs=function(msg,newArgs){this.msg=msg;this.newArgs=newArgs;};Y.Do.AlterReturn=function(msg,newRetVal){this.msg=msg;this.newRetVal=newRetVal;};Y.Do.Halt=function(msg,retVal){this.msg=msg;this.retVal=retVal;};Y.Do.Prevent=function(msg){this.msg=msg;};Y.Do.Error=Y.Do.Halt;})();var AFTER='after',CONFIGS=['broadcast','bubbles','context','contextFn','currentTarget','defaultFn','details','emitFacade','fireOnce','host','preventable','preventedFn','queuable','silent','stoppedFn','target','type'],YUI3_SIGNATURE=9,YUI_LOG='yui:log';Y.EventHandle=function(evt,sub){this.evt=evt;this.sub=sub;};Y.EventHandle.prototype={detach:function(){var evt=this.evt,i;if(evt){if(Y.Lang.isArray(evt)){for(i=0;i2)?Y.Array(arguments,2,true):null;return this._on(fn,context,a,true);},on:function(fn,context){var a=(arguments.length>2)?Y.Array(arguments,2,true):null;return this._on(fn,context,a,true);},after:function(fn,context){var a=(arguments.length>2)?Y.Array(arguments,2,true):null;return this._on(fn,context,a,AFTER);},detach:function(fn,context){if(fn&&fn.detach){return fn.detach();} +var found=0,subs=this.subscribers,i,s;for(i in subs){if(subs.hasOwnProperty(i)){s=subs[i];if(s&&(!fn||fn===s.fn)){this._delete(s);found++;}}} +return found;},unsubscribe:function(){return this.detach.apply(this,arguments);},_notify:function(s,args,ef){this.log(this.type+"->"+"sub: "+s.id);var ret;ret=s.notify(args,this);if(false===ret||this.stopped>1){this.log(this.type+" cancelled by subscriber");return false;} +return true;},log:function(msg,cat){if(!this.silent){}},fire:function(){if(this.fireOnce&&this.fired){this.log('fireOnce event: '+this.type+' already fired');return true;}else{var args=Y.Array(arguments,0,true);this.fired=true;this.firedWith=args;if(this.emitFacade){return this.fireComplex(args);}else{return this.fireSimple(args);}}},fireSimple:function(args){if(this.hasSubscribers||this.hasAfters){this._procSubs(Y.merge(this.subscribers,this.afters),args);} +this._broadcast(args);return this.stopped?false:true;},fireComplex:function(args){args[0]=args[0]||{};return this.fireSimple(args);},_procSubs:function(subs,args,ef){var s,i;for(i in subs){if(subs.hasOwnProperty(i)){s=subs[i];if(s&&s.fn){if(false===this._notify(s,args,ef)){this.stopped=2;} +if(this.stopped==2){return false;}}}} +return true;},_broadcast:function(args){if(!this.stopped&&this.broadcast){var a=Y.Array(args);a.unshift(this.type);if(this.host!==Y){Y.fire.apply(Y,a);} +if(this.broadcast==2){Y.Global.fire.apply(Y.Global,a);}}},unsubscribeAll:function(){return this.detachAll.apply(this,arguments);},detachAll:function(){return this.detach();},_delete:function(s){if(s){delete s.fn;delete s.context;delete this.subscribers[s.id];delete this.afters[s.id];}}};Y.Subscriber=function(fn,context,args){this.fn=fn;this.context=context;this.id=Y.stamp(this);this.args=args;this.events=null;};Y.Subscriber.prototype={_notify:function(c,args,ce){var a=this.args,ret;switch(ce.signature){case 0:ret=this.fn.call(c,ce.type,args,c);break;case 1:ret=this.fn.call(c,args[0]||null,c);break;default:if(a||args){args=args||[];a=(a)?args.concat(a):args;ret=this.fn.apply(c,a);}else{ret=this.fn.call(c);}} +return ret;},notify:function(args,ce){var c=this.context,ret=true;if(!c){c=(ce.contextFn)?ce.contextFn():ce.context;} +if(Y.config.throwFail){ret=this._notify(c,args,ce);}else{try{ret=this._notify(c,args,ce);}catch(e){Y.error(this+' failed: '+e.message,e);}} +return ret;},contains:function(fn,context){if(context){return((this.fn==fn)&&this.context==context);}else{return(this.fn==fn);}}};(function(){var L=Y.Lang,PREFIX_DELIMITER=':',CATEGORY_DELIMITER='|',AFTER_PREFIX='~AFTER~',_getType=Y.cached(function(type,pre){if(!pre||!L.isString(type)||type.indexOf(PREFIX_DELIMITER)>-1){return type;} +return pre+PREFIX_DELIMITER+type;}),_parseType=Y.cached(function(type,pre){var t=type,detachcategory,after,i;if(!L.isString(t)){return t;} +i=t.indexOf(AFTER_PREFIX);if(i>-1){after=true;t=t.substr(AFTER_PREFIX.length);} +i=t.indexOf(CATEGORY_DELIMITER);if(i>-1){detachcategory=t.substr(0,(i));t=t.substr(i+1);if(t=='*'){t=null;}} +return[detachcategory,(pre)?_getType(t,pre):t,after,t];}),ET=function(opts){var o=(L.isObject(opts))?opts:{};this._yuievt=this._yuievt||{id:Y.guid(),events:{},targets:{},config:o,chain:('chain'in o)?o.chain:Y.config.chain,defaults:{context:o.context||this,host:this,emitFacade:o.emitFacade,fireOnce:o.fireOnce,queuable:o.queuable,broadcast:o.broadcast,bubbles:('bubbles'in o)?o.bubbles:true}};};ET.prototype={on:function(type,fn,context,x){var parts=_parseType(type,this._yuievt.config.prefix),f,c,args,ret,ce,detachcategory,handle,store=Y.Env.evt.handles,after,adapt,shorttype,Node=Y.Node,n,domevent;if(L.isObject(type)){if(L.isFunction(type)){return Y.Do.before.apply(Y.Do,arguments);} +f=fn;c=context;args=Y.Array(arguments,0,true);ret={};after=type._after;delete type._after;Y.each(type,function(v,k){if(v){f=v.fn||((Y.Lang.isFunction(v))?v:f);c=v.context||c;} +args[0]=(after)?AFTER_PREFIX+k:k;args[1]=f;args[2]=c;ret[k]=this.on.apply(this,args);},this);return(this._yuievt.chain)?this:new Y.EventHandle(ret);} +detachcategory=parts[0];after=parts[2];shorttype=parts[3];if(Node&&(this instanceof Node)&&(shorttype in Node.DOM_EVENTS)){args=Y.Array(arguments,0,true);args.splice(2,0,Node.getDOMNode(this));return Y.on.apply(Y,args);} +type=parts[1];if(this instanceof YUI){adapt=Y.Env.evt.plugins[type];args=Y.Array(arguments,0,true);args[0]=shorttype;if(Node){n=args[2];if(n instanceof Y.NodeList){n=Y.NodeList.getDOMNodes(n);}else if(n instanceof Node){n=Node.getDOMNode(n);} +domevent=(shorttype in Node.DOM_EVENTS);if(domevent){args[2]=n;}} +if(adapt){handle=adapt.on.apply(Y,args);}else if((!type)||domevent){handle=Y.Event._attach(args);}} +if(!handle){ce=this._yuievt.events[type]||this.publish(type);handle=ce._on(fn,context,(arguments.length>3)?Y.Array(arguments,3,true):null,(after)?'after':true);} +if(detachcategory){store[detachcategory]=store[detachcategory]||{};store[detachcategory][type]=store[detachcategory][type]||[];store[detachcategory][type].push(handle);} +return(this._yuievt.chain)?this:handle;},subscribe:function(){return this.on.apply(this,arguments);},detach:function(type,fn,context){var evts=this._yuievt.events,i,ret,Node=Y.Node,isNode=(this instanceof Node);if(!type&&(this!==Y)){for(i in evts){if(evts.hasOwnProperty(i)){ret=evts[i].detach(fn,context);}} +if(isNode){Y.Event.purgeElement(Node.getDOMNode(this));} +return ret;} +var parts=_parseType(type,this._yuievt.config.prefix),detachcategory=L.isArray(parts)?parts[0]:null,shorttype=(parts)?parts[3]:null,handle,adapt,store=Y.Env.evt.handles,cat,args,ce,keyDetacher=function(lcat,ltype){var handles=lcat[ltype];if(handles){while(handles.length){handle=handles.pop();handle.detach();}}};if(detachcategory){cat=store[detachcategory];type=parts[1];if(cat){if(type){keyDetacher(cat,type);}else{for(i in cat){if(cat.hasOwnProperty(i)){keyDetacher(cat,i);}}} +return(this._yuievt.chain)?this:true;}}else if(L.isObject(type)&&type.detach){ret=type.detach();return(this._yuievt.chain)?this:ret;}else if(isNode&&((!shorttype)||(shorttype in Node.DOM_EVENTS))){args=Y.Array(arguments,0,true);args[2]=Node.getDOMNode(this);return Y.detach.apply(Y,args);} +adapt=Y.Env.evt.plugins[shorttype];if(this instanceof YUI){args=Y.Array(arguments,0,true);if(adapt&&adapt.detach){return adapt.detach.apply(Y,args);}else if(!type||(!adapt&&Node&&(type in Node.DOM_EVENTS))){args[0]=type;return Y.Event.detach.apply(Y.Event,args);}} +ce=evts[type];if(ce){ret=ce.detach(fn,context);} +return(this._yuievt.chain)?this:ret;},unsubscribe:function(){return this.detach.apply(this,arguments);},detachAll:function(type){return this.detach(type);},unsubscribeAll:function(){return this.detachAll.apply(this,arguments);},publish:function(type,opts){var events,ce,ret,pre=this._yuievt.config.prefix;type=(pre)?_getType(type,pre):type;if(L.isObject(type)){ret={};Y.each(type,function(v,k){ret[k]=this.publish(k,v||opts);},this);return ret;} +events=this._yuievt.events;ce=events[type];if(ce){if(opts){ce.applyConfig(opts,true);}}else{ce=new Y.CustomEvent(type,(opts)?Y.mix(opts,this._yuievt.defaults):this._yuievt.defaults);events[type]=ce;} +return events[type];},addTarget:function(o){this._yuievt.targets[Y.stamp(o)]=o;this._yuievt.hasTargets=true;},removeTarget:function(o){delete this._yuievt.targets[Y.stamp(o)];},fire:function(type){var typeIncluded=L.isString(type),t=(typeIncluded)?type:(type&&type.type),ce,a,ret,pre=this._yuievt.config.prefix;t=(pre)?_getType(t,pre):t;ce=this.getEvent(t,true);if(!ce){if(this._yuievt.hasTargets){a=(typeIncluded)?arguments:Y.Array(arguments,0,true).unshift(t);return this.bubble(null,a,this);} +ret=true;}else{a=Y.Array(arguments,(typeIncluded)?1:0,true);ret=ce.fire.apply(ce,a);ce.target=null;} +return(this._yuievt.chain)?this:ret;},getEvent:function(type,prefixed){var pre,e;if(!prefixed){pre=this._yuievt.config.prefix;type=(pre)?_getType(type,pre):type;} +e=this._yuievt.events;return(e&&type in e)?e[type]:null;},after:function(type,fn){var a=Y.Array(arguments,0,true);switch(L.type(type)){case'function':return Y.Do.after.apply(Y.Do,arguments);case'object':a[0]._after=true;break;default:a[0]=AFTER_PREFIX+type;} +return this.on.apply(this,a);},before:function(){return this.on.apply(this,arguments);}};Y.EventTarget=ET;Y.mix(Y,ET.prototype,false,false,{bubbles:false});ET.call(Y);YUI.Env.globalEvents=YUI.Env.globalEvents||new ET();Y.Global=YUI.Env.globalEvents;})();},'3.0.0',{requires:['oop']});YUI.add('event-custom-complex',function(Y){(function(){var FACADE,FACADE_KEYS,CEProto=Y.CustomEvent.prototype;Y.EventFacade=function(e,currentTarget){e=e||{};this.details=e.details;this.type=e.type;this.target=e.target;this.currentTarget=currentTarget;this.relatedTarget=e.relatedTarget;this.stopPropagation=function(){e.stopPropagation();};this.stopImmediatePropagation=function(){e.stopImmediatePropagation();};this.preventDefault=function(){e.preventDefault();};this.halt=function(immediate){e.halt(immediate);};};CEProto.fireComplex=function(args){var es=Y.Env._eventstack,ef,q,queue,ce,ret,events;if(es){if(this.queuable&&this.type!=es.next.type){this.log('queue '+this.type);es.queue.push([this,args]);return true;}}else{Y.Env._eventstack={id:this.id,next:this,silent:this.silent,stopped:0,prevented:0,queue:[]};es=Y.Env._eventstack;} +this.stopped=0;this.prevented=0;this.target=this.target||this.host;events=new Y.EventTarget({fireOnce:true,context:this.host});this.events=events;if(this.preventedFn){events.on('prevented',this.preventedFn);} +if(this.stoppedFn){events.on('stopped',this.stoppedFn);} +this.currentTarget=this.host||this.currentTarget;this.details=args.slice();this.log("Firing "+this.type);this._facade=null;ef=this._getFacade(args);if(Y.Lang.isObject(args[0])){args[0]=ef;}else{args.unshift(ef);} +if(this.hasSubscribers){this._procSubs(Y.merge(this.subscribers),args,ef);} +if(this.bubbles&&this.host&&this.host.bubble&&!this.stopped){es.stopped=0;es.prevented=0;ret=this.host.bubble(this);this.stopped=Math.max(this.stopped,es.stopped);this.prevented=Math.max(this.prevented,es.prevented);} +if(this.defaultFn&&!this.prevented){this.defaultFn.apply(this.host||this,args);} +this._broadcast(args);if(this.hasAfters&&!this.prevented&&this.stopped<2){this._procSubs(Y.merge(this.afters),args,ef);} +if(es.id===this.id){queue=es.queue;while(queue.length){q=queue.pop();ce=q[0];es.stopped=0;es.prevented=0;es.next=ce;ce.fire.apply(ce,q[1]);} +Y.Env._eventstack=null;} +return this.stopped?false:true;};CEProto._getFacade=function(){var ef=this._facade,o,o2,args=this.details;if(!ef){ef=new Y.EventFacade(this,this.currentTarget);} +o=args&&args[0];if(Y.Lang.isObject(o,true)){o2={};Y.mix(o2,ef,true,FACADE_KEYS);Y.mix(ef,o,true);Y.mix(ef,o2,true,FACADE_KEYS);} +ef.details=this.details;ef.target=this.target;ef.currentTarget=this.currentTarget;ef.stopped=0;ef.prevented=0;this._facade=ef;return this._facade;};CEProto.stopPropagation=function(){this.stopped=1;Y.Env._eventstack.stopped=1;this.events.fire('stopped',this);};CEProto.stopImmediatePropagation=function(){this.stopped=2;Y.Env._eventstack.stopped=2;this.events.fire('stopped',this);};CEProto.preventDefault=function(){if(this.preventable){this.prevented=1;Y.Env._eventstack.prevented=1;this.events.fire('prevented',this);}};CEProto.halt=function(immediate){if(immediate){this.stopImmediatePropagation();}else{this.stopPropagation();} +this.preventDefault();};Y.EventTarget.prototype.bubble=function(evt,args,target){var targs=this._yuievt.targets,ret=true,t,type,ce,i,bc;if(!evt||((!evt.stopped)&&targs)){for(i in targs){if(targs.hasOwnProperty(i)){t=targs[i];type=evt&&evt.type;ce=t.getEvent(type,true);if(!ce){if(t._yuievt.hasTargets){t.bubble.call(t,evt,args,target);}}else{ce.target=target||(evt&&evt.target)||this;ce.currentTarget=t;bc=ce.broadcast;ce.broadcast=false;ret=ret&&ce.fire.apply(ce,args||evt.details);ce.broadcast=bc;if(ce.stopped){break;}}}}} +return ret;};FACADE=new Y.EventFacade();FACADE_KEYS=Y.Object.keys(FACADE);})();},'3.0.0',{requires:['event-custom-base']});YUI.add('event-custom',function(Y){},'3.0.0',{use:['event-custom-base','event-custom-complex']}); \ No newline at end of file diff --git a/include/javascript/yui3/build/event-simulate/event-simulate-min.js b/include/javascript/yui3/build/event-simulate/event-simulate-min.js new file mode 100644 index 00000000..2ad02fcd --- /dev/null +++ b/include/javascript/yui3/build/event-simulate/event-simulate-min.js @@ -0,0 +1,8 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add("event-simulate",function(A){(function(){var H=A.Lang,G=A.Array,D=H.isFunction,C=H.isString,E=H.isBoolean,M=H.isObject,K=H.isNumber,J=A.config.doc,N={click:1,dblclick:1,mouseover:1,mouseout:1,mousedown:1,mouseup:1,mousemove:1},I={keydown:1,keyup:1,keypress:1};function F(S,W,R,P,Y,O,L,X,U,a,Z){if(!S){A.error("simulateKeyEvent(): Invalid target.");}if(C(W)){W=W.toLowerCase();switch(W){case"textevent":W="keypress";break;case"keyup":case"keydown":case"keypress":break;default:A.error("simulateKeyEvent(): Event type '"+W+"' not supported.");}}else{A.error("simulateKeyEvent(): Event type must be a string.");}if(!E(R)){R=true;}if(!E(P)){P=true;}if(!M(Y)){Y=window;}if(!E(O)){O=false;}if(!E(L)){L=false;}if(!E(X)){X=false;}if(!E(U)){U=false;}if(!K(a)){a=0;}if(!K(Z)){Z=0;}var V=null;if(D(J.createEvent)){try{V=J.createEvent("KeyEvents");V.initKeyEvent(W,R,P,Y,O,L,X,U,a,Z);}catch(T){try{V=J.createEvent("Events");}catch(Q){V=J.createEvent("UIEvents");}finally{V.initEvent(W,R,P);V.view=Y;V.altKey=L;V.ctrlKey=O;V.shiftKey=X;V.metaKey=U;V.keyCode=a;V.charCode=Z;}}S.dispatchEvent(V);}else{if(M(J.createEventObject)){V=J.createEventObject();V.bubbles=R;V.cancelable=P;V.view=Y;V.ctrlKey=O;V.altKey=L;V.shiftKey=X;V.metaKey=U;V.keyCode=(Z>0)?Z:a;S.fireEvent("on"+W,V);}else{A.error("simulateKeyEvent(): No event simulation framework present.");}}}function B(X,c,U,R,d,W,T,S,Q,O,P,L,b,Z,V,Y){if(!X){A.error("simulateMouseEvent(): Invalid target.");}if(C(c)){c=c.toLowerCase();if(!N[c]){A.error("simulateMouseEvent(): Event type '"+c+"' not supported.");}}else{A.error("simulateMouseEvent(): Event type must be a string.");}if(!E(U)){U=true;}if(!E(R)){R=(c!="mousemove");}if(!M(d)){d=window;}if(!K(W)){W=1;}if(!K(T)){T=0;}if(!K(S)){S=0;}if(!K(Q)){Q=0;}if(!K(O)){O=0;}if(!E(P)){P=false;}if(!E(L)){L=false;}if(!E(b)){b=false;}if(!E(Z)){Z=false;}if(!K(V)){V=0;}var a=null;if(D(J.createEvent)){a=J.createEvent("MouseEvents");if(a.initMouseEvent){a.initMouseEvent(c,U,R,d,W,T,S,Q,O,P,L,b,Z,V,Y);}else{a=J.createEvent("UIEvents");a.initEvent(c,U,R);a.view=d;a.detail=W;a.screenX=T;a.screenY=S;a.clientX=Q;a.clientY=O;a.ctrlKey=P;a.altKey=L;a.metaKey=Z;a.shiftKey=b;a.button=V;a.relatedTarget=Y;}if(Y&&!a.relatedTarget){if(c=="mouseout"){a.toElement=Y;}else{if(c=="mouseover"){a.fromElement=Y;}}}X.dispatchEvent(a);}else{if(M(J.createEventObject)){a=J.createEventObject();a.bubbles=U;a.cancelable=R;a.view=d;a.detail=W;a.screenX=T;a.screenY=S;a.clientX=Q;a.clientY=O;a.ctrlKey=P;a.altKey=L;a.metaKey=Z;a.shiftKey=b;switch(V){case 0:a.button=1;break;case 1:a.button=4;break;case 2:break;default:a.button=0;}a.relatedTarget=Y;X.fireEvent("on"+c,a);}else{A.error("simulateMouseEvent(): No event simulation framework present.");}}}A.Event.simulate=function(P,O,L){L=L||{};if(N[O]){B(P,O,L.bubbles,L.cancelable,L.view,L.detail,L.screenX,L.screenY,L.clientX,L.clientY,L.ctrlKey,L.altKey,L.shiftKey,L.metaKey,L.button,L.relatedTarget);}else{if(I[O]){F(P,O,L.bubbles,L.cancelable,L.view,L.ctrlKey,L.altKey,L.shiftKey,L.metaKey,L.keyCode,L.charCode);}else{A.error("simulate(): Event '"+O+"' can't be simulated.");}}};})();},"3.0.0",{requires:["event"]}); \ No newline at end of file diff --git a/include/javascript/yui3/build/event-simulate/event-simulate.js b/include/javascript/yui3/build/event-simulate/event-simulate.js new file mode 100644 index 00000000..36447b5d --- /dev/null +++ b/include/javascript/yui3/build/event-simulate/event-simulate.js @@ -0,0 +1,42 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add('event-simulate',function(Y){(function(){var L=Y.Lang,array=Y.Array,isFunction=L.isFunction,isString=L.isString,isBoolean=L.isBoolean,isObject=L.isObject,isNumber=L.isNumber,doc=Y.config.doc,mouseEvents={click:1,dblclick:1,mouseover:1,mouseout:1,mousedown:1,mouseup:1,mousemove:1},keyEvents={keydown:1,keyup:1,keypress:1};function simulateKeyEvent(target,type,bubbles,cancelable,view,ctrlKey,altKey,shiftKey,metaKey,keyCode,charCode) +{if(!target){Y.error("simulateKeyEvent(): Invalid target.");} +if(isString(type)){type=type.toLowerCase();switch(type){case"textevent":type="keypress";break;case"keyup":case"keydown":case"keypress":break;default:Y.error("simulateKeyEvent(): Event type '"+type+"' not supported.");}}else{Y.error("simulateKeyEvent(): Event type must be a string.");} +if(!isBoolean(bubbles)){bubbles=true;} +if(!isBoolean(cancelable)){cancelable=true;} +if(!isObject(view)){view=window;} +if(!isBoolean(ctrlKey)){ctrlKey=false;} +if(!isBoolean(altKey)){altKey=false;} +if(!isBoolean(shiftKey)){shiftKey=false;} +if(!isBoolean(metaKey)){metaKey=false;} +if(!isNumber(keyCode)){keyCode=0;} +if(!isNumber(charCode)){charCode=0;} +var customEvent=null;if(isFunction(doc.createEvent)){try{customEvent=doc.createEvent("KeyEvents");customEvent.initKeyEvent(type,bubbles,cancelable,view,ctrlKey,altKey,shiftKey,metaKey,keyCode,charCode);}catch(ex){try{customEvent=doc.createEvent("Events");}catch(uierror){customEvent=doc.createEvent("UIEvents");}finally{customEvent.initEvent(type,bubbles,cancelable);customEvent.view=view;customEvent.altKey=altKey;customEvent.ctrlKey=ctrlKey;customEvent.shiftKey=shiftKey;customEvent.metaKey=metaKey;customEvent.keyCode=keyCode;customEvent.charCode=charCode;}} +target.dispatchEvent(customEvent);}else if(isObject(doc.createEventObject)){customEvent=doc.createEventObject();customEvent.bubbles=bubbles;customEvent.cancelable=cancelable;customEvent.view=view;customEvent.ctrlKey=ctrlKey;customEvent.altKey=altKey;customEvent.shiftKey=shiftKey;customEvent.metaKey=metaKey;customEvent.keyCode=(charCode>0)?charCode:keyCode;target.fireEvent("on"+type,customEvent);}else{Y.error("simulateKeyEvent(): No event simulation framework present.");}} +function simulateMouseEvent(target,type,bubbles,cancelable,view,detail,screenX,screenY,clientX,clientY,ctrlKey,altKey,shiftKey,metaKey,button,relatedTarget) +{if(!target){Y.error("simulateMouseEvent(): Invalid target.");} +if(isString(type)){type=type.toLowerCase();if(!mouseEvents[type]){Y.error("simulateMouseEvent(): Event type '"+type+"' not supported.");}}else{Y.error("simulateMouseEvent(): Event type must be a string.");} +if(!isBoolean(bubbles)){bubbles=true;} +if(!isBoolean(cancelable)){cancelable=(type!="mousemove");} +if(!isObject(view)){view=window;} +if(!isNumber(detail)){detail=1;} +if(!isNumber(screenX)){screenX=0;} +if(!isNumber(screenY)){screenY=0;} +if(!isNumber(clientX)){clientX=0;} +if(!isNumber(clientY)){clientY=0;} +if(!isBoolean(ctrlKey)){ctrlKey=false;} +if(!isBoolean(altKey)){altKey=false;} +if(!isBoolean(shiftKey)){shiftKey=false;} +if(!isBoolean(metaKey)){metaKey=false;} +if(!isNumber(button)){button=0;} +var customEvent=null;if(isFunction(doc.createEvent)){customEvent=doc.createEvent("MouseEvents");if(customEvent.initMouseEvent){customEvent.initMouseEvent(type,bubbles,cancelable,view,detail,screenX,screenY,clientX,clientY,ctrlKey,altKey,shiftKey,metaKey,button,relatedTarget);}else{customEvent=doc.createEvent("UIEvents");customEvent.initEvent(type,bubbles,cancelable);customEvent.view=view;customEvent.detail=detail;customEvent.screenX=screenX;customEvent.screenY=screenY;customEvent.clientX=clientX;customEvent.clientY=clientY;customEvent.ctrlKey=ctrlKey;customEvent.altKey=altKey;customEvent.metaKey=metaKey;customEvent.shiftKey=shiftKey;customEvent.button=button;customEvent.relatedTarget=relatedTarget;} +if(relatedTarget&&!customEvent.relatedTarget){if(type=="mouseout"){customEvent.toElement=relatedTarget;}else if(type=="mouseover"){customEvent.fromElement=relatedTarget;}} +target.dispatchEvent(customEvent);}else if(isObject(doc.createEventObject)){customEvent=doc.createEventObject();customEvent.bubbles=bubbles;customEvent.cancelable=cancelable;customEvent.view=view;customEvent.detail=detail;customEvent.screenX=screenX;customEvent.screenY=screenY;customEvent.clientX=clientX;customEvent.clientY=clientY;customEvent.ctrlKey=ctrlKey;customEvent.altKey=altKey;customEvent.metaKey=metaKey;customEvent.shiftKey=shiftKey;switch(button){case 0:customEvent.button=1;break;case 1:customEvent.button=4;break;case 2:break;default:customEvent.button=0;} +customEvent.relatedTarget=relatedTarget;target.fireEvent("on"+type,customEvent);}else{Y.error("simulateMouseEvent(): No event simulation framework present.");}} +Y.Event.simulate=function(target,type,options){options=options||{};if(mouseEvents[type]){simulateMouseEvent(target,type,options.bubbles,options.cancelable,options.view,options.detail,options.screenX,options.screenY,options.clientX,options.clientY,options.ctrlKey,options.altKey,options.shiftKey,options.metaKey,options.button,options.relatedTarget);}else if(keyEvents[type]){simulateKeyEvent(target,type,options.bubbles,options.cancelable,options.view,options.ctrlKey,options.altKey,options.shiftKey,options.metaKey,options.keyCode,options.charCode);}else{Y.error("simulate(): Event '"+type+"' can't be simulated.");}};})();},'3.0.0',{requires:['event']}); \ No newline at end of file diff --git a/include/javascript/yui3/build/event/event-base-min.js b/include/javascript/yui3/build/event/event-base-min.js new file mode 100644 index 00000000..a370cf90 --- /dev/null +++ b/include/javascript/yui3/build/event/event-base-min.js @@ -0,0 +1,8 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +(function(){var GLOBAL_ENV=YUI.Env,C=YUI.config,D=C.doc,POLL_INTERVAL=C.pollInterval||40,_ready=function(e){GLOBAL_ENV._ready();};if(!GLOBAL_ENV._ready){GLOBAL_ENV._ready=function(){if(!GLOBAL_ENV.DOMReady){GLOBAL_ENV.DOMReady=true;if(D.removeEventListener){D.removeEventListener("DOMContentLoaded",_ready,false);}}};if(navigator.userAgent.match(/MSIE/)){if(self!==self.top){document.onreadystatechange=function(){if(document.readyState=="complete"){document.onreadystatechange=null;_ready();}};}else{GLOBAL_ENV._dri=setInterval(function(){try{document.documentElement.doScroll("left");clearInterval(GLOBAL_ENV._dri);GLOBAL_ENV._dri=null;_ready();}catch(ex){}},POLL_INTERVAL);}}else{D.addEventListener("DOMContentLoaded",_ready,false);}}})();YUI.add("event-base",function(A){(function(){var C=YUI.Env,B=function(){A.fire("domready");};A.publish("domready",{fireOnce:true});if(C.DOMReady){B();}else{A.before(B,C,"_ready");}})();(function(){var C=A.UA,B={63232:38,63233:40,63234:37,63235:39,63276:33,63277:34,25:9,63272:46,63273:36,63275:35},D=function(F){try{if(F&&3==F.nodeType){F=F.parentNode;}}catch(E){return null;}return A.one(F);};A.DOMEventFacade=function(L,F,E){E=E||{};var H=L,G=F,I=A.config.doc,M=I.body,N=H.pageX,K=H.pageY,J,O;this.altKey=H.altKey;this.ctrlKey=H.ctrlKey;this.metaKey=H.metaKey;this.shiftKey=H.shiftKey;this.type=H.type;this.clientX=H.clientX;this.clientY=H.clientY;if(!N&&0!==N){N=H.clientX||0;K=H.clientY||0;if(C.ie){N+=Math.max(I.documentElement.scrollLeft,M.scrollLeft);K+=Math.max(I.documentElement.scrollTop,M.scrollTop);}}this._yuifacade=true;this._event=H;this.pageX=N;this.pageY=K;J=H.keyCode||H.charCode||0;if(C.webkit&&(J in B)){J=B[J];}this.keyCode=J;this.charCode=J;this.button=H.which||H.button;this.which=this.button;this.target=D(H.target||H.srcElement);this.currentTarget=D(G);O=H.relatedTarget;if(!O){if(H.type=="mouseout"){O=H.toElement;}else{if(H.type=="mouseover"){O=H.fromElement;}}}this.relatedTarget=D(O);if(H.type=="mousewheel"||H.type=="DOMMouseScroll"){this.wheelDelta=(H.detail)?(H.detail*-1):Math.round(H.wheelDelta/80)||((H.wheelDelta<0)?-1:1);}this.stopPropagation=function(){if(H.stopPropagation){H.stopPropagation();}else{H.cancelBubble=true;}E.stopped=1;};this.stopImmediatePropagation=function(){if(H.stopImmediatePropagation){H.stopImmediatePropagation();}else{this.stopPropagation();}E.stopped=2;};this.preventDefault=function(P){if(H.preventDefault){H.preventDefault();}H.returnValue=P||false;E.prevented=1;};this.halt=function(P){if(P){this.stopImmediatePropagation();}else{this.stopPropagation();}this.preventDefault();};};})();(function(){A.Env.evt.dom_wrappers={};A.Env.evt.dom_map={};var H=A.Env.evt,J=YUI.Env.add,D=YUI.Env.remove,G=function(){YUI.Env.windowLoaded=true;A.Event._load();D(window,"load",G);},B=function(){A.Event._unload();D(window,"unload",B);},C="domready",E="~yui|2|compat~",F=function(L){try{return(L&&typeof L!=="string"&&A.Lang.isNumber(L.length)&&!L.tagName&&!L.alert);}catch(K){return false;}},I=function(){var M=false,N=0,L=[],O=H.dom_wrappers,K=null,P=H.dom_map;return{POLL_RETRYS:1000,POLL_INTERVAL:40,lastError:null,_interval:null,_dri:null,DOMReady:false,startInterval:function(){var Q=A.Event;if(!Q._interval){Q._interval=setInterval(A.bind(Q._poll,Q),Q.POLL_INTERVAL);}},onAvailable:function(Q,U,Y,R,V,X){var W=A.Array(Q),S,T;for(S=0;S4)?W.slice(4):null);if(T){Z.fire();}return V;},detach:function(X,Z,S,U){var W=A.Array(arguments,0,true),a,V,T,Y,Q,R;if(W[W.length-1]===E){a=true;}if(X&&X.detach){return X.detach();}if(typeof S=="string"){if(a){S=A.DOM.byId(S);}else{S=A.Selector.query(S);T=S.length;if(T<1){S=null;}else{if(T==1){S=S[0];}}}}if(!S){return false;}if(F(S)){Y=true;for(V=0,T=S.length;V0);}U=[];W=function(Z,a){var Y,X=a.override;if(a.compat){if(a.override){if(X===true){Y=a.obj;}else{Y=X;}}else{Y=Z;}a.fn.call(Y,a.obj);}else{Y=a.obj||A.one(Z);a.fn.apply(Y,(A.Lang.isArray(X))?X:[]);}};for(R=0,Q=L.length;R4?A.Array(arguments,4,true):[];return A.Event.onAvailable.call(A.Event,F,C,E,B);}};A.Env.evt.plugins.contentready={on:function(D,C,F,E){var B=arguments.length>4?A.Array(arguments,4,true):[];return A.Event.onContentReady.call(A.Event,F,C,E,B);}};},"3.0.0",{requires:["event-custom-base"]}); \ No newline at end of file diff --git a/include/javascript/yui3/build/event/event-base.js b/include/javascript/yui3/build/event/event-base.js new file mode 100644 index 00000000..600697d2 --- /dev/null +++ b/include/javascript/yui3/build/event/event-base.js @@ -0,0 +1,54 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +(function(){var GLOBAL_ENV=YUI.Env,C=YUI.config,D=C.doc,POLL_INTERVAL=C.pollInterval||40,_ready=function(e){GLOBAL_ENV._ready();};if(!GLOBAL_ENV._ready){GLOBAL_ENV._ready=function(){if(!GLOBAL_ENV.DOMReady){GLOBAL_ENV.DOMReady=true;if(D.removeEventListener){D.removeEventListener("DOMContentLoaded",_ready,false);}}};if(navigator.userAgent.match(/MSIE/)){if(self!==self.top){document.onreadystatechange=function(){if(document.readyState=='complete'){document.onreadystatechange=null;_ready();}};}else{GLOBAL_ENV._dri=setInterval(function(){try{document.documentElement.doScroll('left');clearInterval(GLOBAL_ENV._dri);GLOBAL_ENV._dri=null;_ready();}catch(ex){}},POLL_INTERVAL);}}else{D.addEventListener("DOMContentLoaded",_ready,false);}}})();YUI.add('event-base',function(Y){(function(){var GLOBAL_ENV=YUI.Env,yready=function(){Y.fire('domready');};Y.publish('domready',{fireOnce:true});if(GLOBAL_ENV.DOMReady){yready();}else{Y.before(yready,GLOBAL_ENV,"_ready");}})();(function(){var ua=Y.UA,webkitKeymap={63232:38,63233:40,63234:37,63235:39,63276:33,63277:34,25:9,63272:46,63273:36,63275:35},resolve=function(n){try{if(n&&3==n.nodeType){n=n.parentNode;}}catch(e){return null;} +return Y.one(n);};Y.DOMEventFacade=function(ev,currentTarget,wrapper){wrapper=wrapper||{};var e=ev,ot=currentTarget,d=Y.config.doc,b=d.body,x=e.pageX,y=e.pageY,c,t;this.altKey=e.altKey;this.ctrlKey=e.ctrlKey;this.metaKey=e.metaKey;this.shiftKey=e.shiftKey;this.type=e.type;this.clientX=e.clientX;this.clientY=e.clientY;if(!x&&0!==x){x=e.clientX||0;y=e.clientY||0;if(ua.ie){x+=Math.max(d.documentElement.scrollLeft,b.scrollLeft);y+=Math.max(d.documentElement.scrollTop,b.scrollTop);}} +this._yuifacade=true;this._event=e;this.pageX=x;this.pageY=y;c=e.keyCode||e.charCode||0;if(ua.webkit&&(c in webkitKeymap)){c=webkitKeymap[c];} +this.keyCode=c;this.charCode=c;this.button=e.which||e.button;this.which=this.button;this.target=resolve(e.target||e.srcElement);this.currentTarget=resolve(ot);t=e.relatedTarget;if(!t){if(e.type=="mouseout"){t=e.toElement;}else if(e.type=="mouseover"){t=e.fromElement;}} +this.relatedTarget=resolve(t);if(e.type=="mousewheel"||e.type=="DOMMouseScroll"){this.wheelDelta=(e.detail)?(e.detail*-1):Math.round(e.wheelDelta/80)||((e.wheelDelta<0)?-1:1);} +this.stopPropagation=function(){if(e.stopPropagation){e.stopPropagation();}else{e.cancelBubble=true;} +wrapper.stopped=1;};this.stopImmediatePropagation=function(){if(e.stopImmediatePropagation){e.stopImmediatePropagation();}else{this.stopPropagation();} +wrapper.stopped=2;};this.preventDefault=function(returnValue){if(e.preventDefault){e.preventDefault();} +e.returnValue=returnValue||false;wrapper.prevented=1;};this.halt=function(immediate){if(immediate){this.stopImmediatePropagation();}else{this.stopPropagation();} +this.preventDefault();};};})();(function(){Y.Env.evt.dom_wrappers={};Y.Env.evt.dom_map={};var _eventenv=Y.Env.evt,add=YUI.Env.add,remove=YUI.Env.remove,onLoad=function(){YUI.Env.windowLoaded=true;Y.Event._load();remove(window,"load",onLoad);},onUnload=function(){Y.Event._unload();remove(window,"unload",onUnload);},EVENT_READY='domready',COMPAT_ARG='~yui|2|compat~',shouldIterate=function(o){try{return(o&&typeof o!=="string"&&Y.Lang.isNumber(o.length)&&!o.tagName&&!o.alert);}catch(ex){return false;}},Event=function(){var _loadComplete=false,_retryCount=0,_avail=[],_wrappers=_eventenv.dom_wrappers,_windowLoadKey=null,_el_events=_eventenv.dom_map;return{POLL_RETRYS:1000,POLL_INTERVAL:40,lastError:null,_interval:null,_dri:null,DOMReady:false,startInterval:function(){var E=Y.Event;if(!E._interval){E._interval=setInterval(Y.bind(E._poll,E),E.POLL_INTERVAL);}},onAvailable:function(id,fn,p_obj,p_override,checkContent,compat){var a=Y.Array(id),i,availHandle;for(i=0;i4)?args.slice(4):null);if(fireNow){cewrapper.fire();} +return ret;},detach:function(type,fn,el,obj){var args=Y.Array(arguments,0,true),compat,i,l,ok,id,ce;if(args[args.length-1]===COMPAT_ARG){compat=true;} +if(type&&type.detach){return type.detach();} +if(typeof el=="string"){if(compat){el=Y.DOM.byId(el);}else{el=Y.Selector.query(el);l=el.length;if(l<1){el=null;}else if(l==1){el=el[0];}}} +if(!el){return false;} +if(shouldIterate(el)){ok=true;for(i=0,l=el.length;i0);} +notAvail=[];executeItem=function(el,item){var context,ov=item.override;if(item.compat){if(item.override){if(ov===true){context=item.obj;}else{context=ov;}}else{context=el;} +item.fn.call(context,item.obj);}else{context=item.obj||Y.one(el);item.fn.apply(context,(Y.Lang.isArray(ov))?ov:[]);}};for(i=0,len=_avail.length;i4?Y.Array(arguments,4,true):[];return Y.Event.onAvailable.call(Y.Event,id,fn,o,a);}};Y.Env.evt.plugins.contentready={on:function(type,fn,id,o){var a=arguments.length>4?Y.Array(arguments,4,true):[];return Y.Event.onContentReady.call(Y.Event,id,fn,o,a);}};},'3.0.0',{requires:['event-custom-base']}); \ No newline at end of file diff --git a/include/javascript/yui3/build/event/event-delegate-min.js b/include/javascript/yui3/build/event/event-delegate-min.js new file mode 100644 index 00000000..123a4a55 --- /dev/null +++ b/include/javascript/yui3/build/event/event-delegate-min.js @@ -0,0 +1,8 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add("event-delegate",function(B){var I=B.Event,F=B.Lang,E={},A={mouseenter:"mouseover",mouseleave:"mouseout"},H=function(K){try{if(K&&3==K.nodeType){return K.parentNode;}}catch(J){}return K;},D=function(K,P,M){var Q=H((P.target||P.srcElement)),N=E[K],T,O,L,S,R;var J=function(X,U,V){var W;if(!X||X===V){W=false;}else{W=B.Selector.test(X,U)?X:J(X.parentNode,U,V);}return W;};for(T in N){if(N.hasOwnProperty(T)){O=N[T];S=N.fn;L=null;if(B.Selector.test(Q,T,M)){L=Q;}else{if(B.Selector.test(Q,((T.replace(/,/gi," *,"))+" *"),M)){L=J(Q,T,M);}}if(L){if(!R){R=new B.DOMEventFacade(P,M);R.container=R.currentTarget;}R.currentTarget=B.Node.get(L);B.publish(O,{contextFn:function(){return R.currentTarget;}});if(S){S(R,O);}else{B.fire(O,R);}}}}},G=function(M,L,K){var O={focus:I._attachFocus,blur:I._attachBlur},N=O[M],J=[M,function(P){D(L,(P||window.event),K);},K];if(N){return N(J,{capture:true,facade:false});}else{return I._attach(J,{facade:false});}},C=B.cached(function(J){return J.replace(/[|,:]/g,"~");});B.Env.evt.plugins.delegate={on:function(O,N,M,J,K){var L=B.Array(arguments,0,true);L.splice(3,1);L[0]=J;return B.delegate.apply(B,L);}};I.delegate=function(R,U,K,W){if(!W){return false;}var O=B.Array(arguments,0,true),M=K,N;if(F.isString(K)){M=B.Selector.query(K,null,true);if(!M){N=I.onAvailable(K,function(){N.handle=I.delegate.apply(I,O);},I,true,false);return N;}}M=B.Node.getDOMNode(M);var S=B.stamp(M),L="delegate:"+S+R+C(W),J=R+S,Q=E[J],T,V,P;if(!Q){Q={};if(A[R]){if(!I._fireMouseEnter){return false;}R=A[R];Q.fn=I._fireMouseEnter;}T=G(R,J,M);B.after(function(X){if(T.sub==X){delete E[J];B.detachAll(L);}},T.evt,"_delete");Q.handle=T;E[J]=Q;}P=Q.listeners;Q.listeners=P?(P+1):1;Q[W]=L;O[0]=L;O.splice(2,2);V=B.on.apply(B,O);B.after(function(){Q.listeners=(Q.listeners-1);if(Q.listeners===0){Q.handle.detach();}},V,"detach");return V;};B.delegate=I.delegate;},"3.0.0",{requires:["node-base"]}); \ No newline at end of file diff --git a/include/javascript/yui3/build/event/event-delegate.js b/include/javascript/yui3/build/event/event-delegate.js new file mode 100644 index 00000000..d996c737 --- /dev/null +++ b/include/javascript/yui3/build/event/event-delegate.js @@ -0,0 +1,21 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add('event-delegate',function(Y){var Event=Y.Event,Lang=Y.Lang,delegates={},specialTypes={mouseenter:"mouseover",mouseleave:"mouseout"},resolveTextNode=function(n){try{if(n&&3==n.nodeType){return n.parentNode;}}catch(e){} +return n;},delegateHandler=function(delegateKey,e,el){var target=resolveTextNode((e.target||e.srcElement)),tests=delegates[delegateKey],spec,ename,matched,fn,ev;var getMatch=function(el,selector,container){var returnVal;if(!el||el===container){returnVal=false;} +else{returnVal=Y.Selector.test(el,selector)?el:getMatch(el.parentNode,selector,container);} +return returnVal;};for(spec in tests){if(tests.hasOwnProperty(spec)){ename=tests[spec];fn=tests.fn;matched=null;if(Y.Selector.test(target,spec,el)){matched=target;} +else if(Y.Selector.test(target,((spec.replace(/,/gi," *,"))+" *"),el)){matched=getMatch(target,spec,el);} +if(matched){if(!ev){ev=new Y.DOMEventFacade(e,el);ev.container=ev.currentTarget;} +ev.currentTarget=Y.Node.get(matched);Y.publish(ename,{contextFn:function(){return ev.currentTarget;}});if(fn){fn(ev,ename);} +else{Y.fire(ename,ev);}}}}},attach=function(type,key,element){var focusMethods={focus:Event._attachFocus,blur:Event._attachBlur},attachFn=focusMethods[type],args=[type,function(e){delegateHandler(key,(e||window.event),element);},element];if(attachFn){return attachFn(args,{capture:true,facade:false});} +else{return Event._attach(args,{facade:false});}},sanitize=Y.cached(function(str){return str.replace(/[|,:]/g,'~');});Y.Env.evt.plugins.delegate={on:function(type,fn,el,delegateType,spec){var args=Y.Array(arguments,0,true);args.splice(3,1);args[0]=delegateType;return Y.delegate.apply(Y,args);}};Event.delegate=function(type,fn,el,spec){if(!spec){return false;} +var args=Y.Array(arguments,0,true),element=el,availHandle;if(Lang.isString(el)){element=Y.Selector.query(el,null,true);if(!element){availHandle=Event.onAvailable(el,function(){availHandle.handle=Event.delegate.apply(Event,args);},Event,true,false);return availHandle;}} +element=Y.Node.getDOMNode(element);var guid=Y.stamp(element),ename='delegate:'+guid+type+sanitize(spec),delegateKey=type+guid,delegate=delegates[delegateKey],domEventHandle,ceHandle,listeners;if(!delegate){delegate={};if(specialTypes[type]){if(!Event._fireMouseEnter){return false;} +type=specialTypes[type];delegate.fn=Event._fireMouseEnter;} +domEventHandle=attach(type,delegateKey,element);Y.after(function(sub){if(domEventHandle.sub==sub){delete delegates[delegateKey];Y.detachAll(ename);}},domEventHandle.evt,"_delete");delegate.handle=domEventHandle;delegates[delegateKey]=delegate;} +listeners=delegate.listeners;delegate.listeners=listeners?(listeners+1):1;delegate[spec]=ename;args[0]=ename;args.splice(2,2);ceHandle=Y.on.apply(Y,args);Y.after(function(){delegate.listeners=(delegate.listeners-1);if(delegate.listeners===0){delegate.handle.detach();}},ceHandle,"detach");return ceHandle;};Y.delegate=Event.delegate;},'3.0.0',{requires:['node-base']}); \ No newline at end of file diff --git a/include/javascript/yui3/build/event/event-focus-min.js b/include/javascript/yui3/build/event/event-focus-min.js new file mode 100644 index 00000000..56083e10 --- /dev/null +++ b/include/javascript/yui3/build/event/event-focus-min.js @@ -0,0 +1,8 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add("event-focus",function(A){(function(){var I=A.UA,J=A.Event,E=A.Env.evt.plugins,C=I.ie,F=(I.opera||I.webkit),D={focus:(C?"focusin":(F?"DOMFocusIn":"focus")),blur:(C?"focusout":(F?"DOMFocusOut":"blur"))},G={capture:(I.gecko?true:false)},H=function(M,L){var K=A.Array(M,0,true);K[0]=D[K[0]];return J._attach(K,L);},B={on:function(){return H(arguments,G);}};J._attachFocus=H;J._attachBlur=H;E.focus=B;E.blur=B;})();},"3.0.0",{requires:["node-base"]}); \ No newline at end of file diff --git a/include/javascript/yui3/build/event/event-focus.js b/include/javascript/yui3/build/event/event-focus.js new file mode 100644 index 00000000..92a0ad69 --- /dev/null +++ b/include/javascript/yui3/build/event/event-focus.js @@ -0,0 +1,8 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add('event-focus',function(Y){(function(){var UA=Y.UA,Event=Y.Event,plugins=Y.Env.evt.plugins,ie=UA.ie,bUseMutation=(UA.opera||UA.webkit),eventNames={focus:(ie?'focusin':(bUseMutation?'DOMFocusIn':'focus')),blur:(ie?'focusout':(bUseMutation?'DOMFocusOut':'blur'))},CAPTURE_CONFIG={capture:(UA.gecko?true:false)},attach=function(args,config){var a=Y.Array(args,0,true);a[0]=eventNames[a[0]];return Event._attach(a,config);},eventAdapter={on:function(){return attach(arguments,CAPTURE_CONFIG);}};Event._attachFocus=attach;Event._attachBlur=attach;plugins.focus=eventAdapter;plugins.blur=eventAdapter;})();},'3.0.0',{requires:['node-base']}); \ No newline at end of file diff --git a/include/javascript/yui3/build/event/event-key-min.js b/include/javascript/yui3/build/event/event-key-min.js new file mode 100644 index 00000000..9cc7ce9b --- /dev/null +++ b/include/javascript/yui3/build/event/event-key-min.js @@ -0,0 +1,8 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add("event-key",function(A){A.Env.evt.plugins.key={on:function(E,G,B,K,C){var I=A.Array(arguments,0,true),F,J,H,D;F=K&&K.split(":");if(!K||K.indexOf(":")==-1||!F[1]){I[0]="key"+((F&&F[0])||"press");return A.on.apply(A,I);}J=F[0];H=(F[1])?F[1].split(/,|\+/):null;D=(A.Lang.isString(B)?B:A.stamp(B))+K;D=D.replace(/,/g,"_");if(!A.getEvent(D)){A.on(E+J,function(P){var Q=false,M=false,N,L,O;for(N=0;N4)?W.slice(4):null);if(T){Z.fire();}return V;},detach:function(X,Z,S,U){var W=A.Array(arguments,0,true),a,V,T,Y,Q,R;if(W[W.length-1]===E){a=true;}if(X&&X.detach){return X.detach();}if(typeof S=="string"){if(a){S=A.DOM.byId(S);}else{S=A.Selector.query(S);T=S.length;if(T<1){S=null;}else{if(T==1){S=S[0];}}}}if(!S){return false;}if(F(S)){Y=true;for(V=0,T=S.length;V0);}U=[];W=function(Z,a){var Y,X=a.override;if(a.compat){if(a.override){if(X===true){Y=a.obj;}else{Y=X;}}else{Y=Z;}a.fn.call(Y,a.obj);}else{Y=a.obj||A.one(Z);a.fn.apply(Y,(A.Lang.isArray(X))?X:[]);}};for(R=0,Q=L.length;R4?A.Array(arguments,4,true):[];return A.Event.onAvailable.call(A.Event,F,C,E,B);}};A.Env.evt.plugins.contentready={on:function(D,C,F,E){var B=arguments.length>4?A.Array(arguments,4,true):[];return A.Event.onContentReady.call(A.Event,F,C,E,B);}};},"3.0.0",{requires:["event-custom-base"]});YUI.add("event-delegate",function(B){var I=B.Event,F=B.Lang,E={},A={mouseenter:"mouseover",mouseleave:"mouseout"},H=function(K){try{if(K&&3==K.nodeType){return K.parentNode;}}catch(J){}return K;},D=function(K,P,M){var Q=H((P.target||P.srcElement)),N=E[K],T,O,L,S,R;var J=function(X,U,V){var W;if(!X||X===V){W=false;}else{W=B.Selector.test(X,U)?X:J(X.parentNode,U,V);}return W;};for(T in N){if(N.hasOwnProperty(T)){O=N[T];S=N.fn;L=null;if(B.Selector.test(Q,T,M)){L=Q;}else{if(B.Selector.test(Q,((T.replace(/,/gi," *,"))+" *"),M)){L=J(Q,T,M);}}if(L){if(!R){R=new B.DOMEventFacade(P,M);R.container=R.currentTarget;}R.currentTarget=B.Node.get(L);B.publish(O,{contextFn:function(){return R.currentTarget;}});if(S){S(R,O);}else{B.fire(O,R);}}}}},G=function(M,L,K){var O={focus:I._attachFocus,blur:I._attachBlur},N=O[M],J=[M,function(P){D(L,(P||window.event),K);},K];if(N){return N(J,{capture:true,facade:false});}else{return I._attach(J,{facade:false});}},C=B.cached(function(J){return J.replace(/[|,:]/g,"~");});B.Env.evt.plugins.delegate={on:function(O,N,M,J,K){var L=B.Array(arguments,0,true);L.splice(3,1);L[0]=J;return B.delegate.apply(B,L);}};I.delegate=function(R,U,K,W){if(!W){return false;}var O=B.Array(arguments,0,true),M=K,N;if(F.isString(K)){M=B.Selector.query(K,null,true);if(!M){N=I.onAvailable(K,function(){N.handle=I.delegate.apply(I,O);},I,true,false);return N;}}M=B.Node.getDOMNode(M);var S=B.stamp(M),L="delegate:"+S+R+C(W),J=R+S,Q=E[J],T,V,P;if(!Q){Q={};if(A[R]){if(!I._fireMouseEnter){return false;}R=A[R];Q.fn=I._fireMouseEnter;}T=G(R,J,M);B.after(function(X){if(T.sub==X){delete E[J];B.detachAll(L);}},T.evt,"_delete");Q.handle=T;E[J]=Q;}P=Q.listeners;Q.listeners=P?(P+1):1;Q[W]=L;O[0]=L;O.splice(2,2);V=B.on.apply(B,O);B.after(function(){Q.listeners=(Q.listeners-1);if(Q.listeners===0){Q.handle.detach();}},V,"detach");return V;};B.delegate=I.delegate;},"3.0.0",{requires:["node-base"]});YUI.add("event-mousewheel",function(C){var B="DOMMouseScroll",A=function(E){var D=C.Array(E,0,true),F;if(C.UA.gecko){D[0]=B;F=C.config.win;}else{F=C.config.doc;}if(D.length<3){D[2]=F;}else{D.splice(2,0,F);}return D;};C.Env.evt.plugins.mousewheel={on:function(){return C.Event._attach(A(arguments));},detach:function(){return C.Event.detach.apply(C.Event,A(arguments));}};},"3.0.0",{requires:["node-base"]});YUI.add("event-mouseenter",function(F){var C=F.Event,E=F.Lang,B=F.Env.evt.plugins,D={},A={on:function(M,O,H){var L=F.Array(arguments,0,true),J=H,K;if(E.isString(H)){J=F.all(H);if(J.size()===0){K=C.onAvailable(H,function(){K.handle=F.on.apply(F,L);},C,true,false);return K;}}var R=(M==="mouseenter")?"mouseover":"mouseout",Q=M+":"+F.stamp(J)+R,I=D[Q],N,P,G;if(!I){N=F.on(R,F.rbind(C._fireMouseEnter,F,Q),J);F.after(function(S){if(N.sub==S){delete D[Q];F.detachAll(Q);}},N.evt,"_delete");I={};I.handle=N;D[Q]=I;}G=I.count;I.count=G?(G+1):1;L[0]=Q;L.splice(2,1);P=F.on.apply(F,L);F.after(function(){I.count=(I.count-1);if(I.count===0){I.handle.detach();}},P,"detach");return P;}};C._fireMouseEnter=function(J,H){var G=J.relatedTarget,I=J.currentTarget;if(I!==G&&!I.contains(G)){F.publish(H,{contextFn:function(){return I;}});F.fire(H,J);}};B.mouseenter=A;B.mouseleave=A;},"3.0.0",{requires:["node-base"]});YUI.add("event-key",function(A){A.Env.evt.plugins.key={on:function(E,G,B,K,C){var I=A.Array(arguments,0,true),F,J,H,D;F=K&&K.split(":");if(!K||K.indexOf(":")==-1||!F[1]){I[0]="key"+((F&&F[0])||"press");return A.on.apply(A,I);}J=F[0];H=(F[1])?F[1].split(/,|\+/):null;D=(A.Lang.isString(B)?B:A.stamp(B))+K;D=D.replace(/,/g,"_");if(!A.getEvent(D)){A.on(E+J,function(P){var Q=false,M=false,N,L,O;for(N=0;N4)?args.slice(4):null);if(fireNow){cewrapper.fire();} +return ret;},detach:function(type,fn,el,obj){var args=Y.Array(arguments,0,true),compat,i,l,ok,id,ce;if(args[args.length-1]===COMPAT_ARG){compat=true;} +if(type&&type.detach){return type.detach();} +if(typeof el=="string"){if(compat){el=Y.DOM.byId(el);}else{el=Y.Selector.query(el);l=el.length;if(l<1){el=null;}else if(l==1){el=el[0];}}} +if(!el){return false;} +if(shouldIterate(el)){ok=true;for(i=0,l=el.length;i0);} +notAvail=[];executeItem=function(el,item){var context,ov=item.override;if(item.compat){if(item.override){if(ov===true){context=item.obj;}else{context=ov;}}else{context=el;} +item.fn.call(context,item.obj);}else{context=item.obj||Y.one(el);item.fn.apply(context,(Y.Lang.isArray(ov))?ov:[]);}};for(i=0,len=_avail.length;i4?Y.Array(arguments,4,true):[];return Y.Event.onAvailable.call(Y.Event,id,fn,o,a);}};Y.Env.evt.plugins.contentready={on:function(type,fn,id,o){var a=arguments.length>4?Y.Array(arguments,4,true):[];return Y.Event.onContentReady.call(Y.Event,id,fn,o,a);}};},'3.0.0',{requires:['event-custom-base']});YUI.add('event-delegate',function(Y){var Event=Y.Event,Lang=Y.Lang,delegates={},specialTypes={mouseenter:"mouseover",mouseleave:"mouseout"},resolveTextNode=function(n){try{if(n&&3==n.nodeType){return n.parentNode;}}catch(e){} +return n;},delegateHandler=function(delegateKey,e,el){var target=resolveTextNode((e.target||e.srcElement)),tests=delegates[delegateKey],spec,ename,matched,fn,ev;var getMatch=function(el,selector,container){var returnVal;if(!el||el===container){returnVal=false;} +else{returnVal=Y.Selector.test(el,selector)?el:getMatch(el.parentNode,selector,container);} +return returnVal;};for(spec in tests){if(tests.hasOwnProperty(spec)){ename=tests[spec];fn=tests.fn;matched=null;if(Y.Selector.test(target,spec,el)){matched=target;} +else if(Y.Selector.test(target,((spec.replace(/,/gi," *,"))+" *"),el)){matched=getMatch(target,spec,el);} +if(matched){if(!ev){ev=new Y.DOMEventFacade(e,el);ev.container=ev.currentTarget;} +ev.currentTarget=Y.Node.get(matched);Y.publish(ename,{contextFn:function(){return ev.currentTarget;}});if(fn){fn(ev,ename);} +else{Y.fire(ename,ev);}}}}},attach=function(type,key,element){var focusMethods={focus:Event._attachFocus,blur:Event._attachBlur},attachFn=focusMethods[type],args=[type,function(e){delegateHandler(key,(e||window.event),element);},element];if(attachFn){return attachFn(args,{capture:true,facade:false});} +else{return Event._attach(args,{facade:false});}},sanitize=Y.cached(function(str){return str.replace(/[|,:]/g,'~');});Y.Env.evt.plugins.delegate={on:function(type,fn,el,delegateType,spec){var args=Y.Array(arguments,0,true);args.splice(3,1);args[0]=delegateType;return Y.delegate.apply(Y,args);}};Event.delegate=function(type,fn,el,spec){if(!spec){return false;} +var args=Y.Array(arguments,0,true),element=el,availHandle;if(Lang.isString(el)){element=Y.Selector.query(el,null,true);if(!element){availHandle=Event.onAvailable(el,function(){availHandle.handle=Event.delegate.apply(Event,args);},Event,true,false);return availHandle;}} +element=Y.Node.getDOMNode(element);var guid=Y.stamp(element),ename='delegate:'+guid+type+sanitize(spec),delegateKey=type+guid,delegate=delegates[delegateKey],domEventHandle,ceHandle,listeners;if(!delegate){delegate={};if(specialTypes[type]){if(!Event._fireMouseEnter){return false;} +type=specialTypes[type];delegate.fn=Event._fireMouseEnter;} +domEventHandle=attach(type,delegateKey,element);Y.after(function(sub){if(domEventHandle.sub==sub){delete delegates[delegateKey];Y.detachAll(ename);}},domEventHandle.evt,"_delete");delegate.handle=domEventHandle;delegates[delegateKey]=delegate;} +listeners=delegate.listeners;delegate.listeners=listeners?(listeners+1):1;delegate[spec]=ename;args[0]=ename;args.splice(2,2);ceHandle=Y.on.apply(Y,args);Y.after(function(){delegate.listeners=(delegate.listeners-1);if(delegate.listeners===0){delegate.handle.detach();}},ceHandle,"detach");return ceHandle;};Y.delegate=Event.delegate;},'3.0.0',{requires:['node-base']});YUI.add('event-mousewheel',function(Y){var DOM_MOUSE_SCROLL='DOMMouseScroll',fixArgs=function(args){var a=Y.Array(args,0,true),target;if(Y.UA.gecko){a[0]=DOM_MOUSE_SCROLL;target=Y.config.win;}else{target=Y.config.doc;} +if(a.length<3){a[2]=target;}else{a.splice(2,0,target);} +return a;};Y.Env.evt.plugins.mousewheel={on:function(){return Y.Event._attach(fixArgs(arguments));},detach:function(){return Y.Event.detach.apply(Y.Event,fixArgs(arguments));}};},'3.0.0',{requires:['node-base']});YUI.add('event-mouseenter',function(Y){var Event=Y.Event,Lang=Y.Lang,plugins=Y.Env.evt.plugins,listeners={},eventConfig={on:function(type,fn,el){var args=Y.Array(arguments,0,true),element=el,availHandle;if(Lang.isString(el)){element=Y.all(el);if(element.size()===0){availHandle=Event.onAvailable(el,function(){availHandle.handle=Y.on.apply(Y,args);},Event,true,false);return availHandle;}} +var sDOMEvent=(type==="mouseenter")?"mouseover":"mouseout",sEventName=type+":"+Y.stamp(element)+sDOMEvent,listener=listeners[sEventName],domEventHandle,ceHandle,nListeners;if(!listener){domEventHandle=Y.on(sDOMEvent,Y.rbind(Event._fireMouseEnter,Y,sEventName),element);Y.after(function(sub){if(domEventHandle.sub==sub){delete listeners[sEventName];Y.detachAll(sEventName);}},domEventHandle.evt,"_delete");listener={};listener.handle=domEventHandle;listeners[sEventName]=listener;} +nListeners=listener.count;listener.count=nListeners?(nListeners+1):1;args[0]=sEventName;args.splice(2,1);ceHandle=Y.on.apply(Y,args);Y.after(function(){listener.count=(listener.count-1);if(listener.count===0){listener.handle.detach();}},ceHandle,"detach");return ceHandle;}};Event._fireMouseEnter=function(e,eventName){var relatedTarget=e.relatedTarget,currentTarget=e.currentTarget;if(currentTarget!==relatedTarget&&!currentTarget.contains(relatedTarget)){Y.publish(eventName,{contextFn:function(){return currentTarget;}});Y.fire(eventName,e);}};plugins.mouseenter=eventConfig;plugins.mouseleave=eventConfig;},'3.0.0',{requires:['node-base']});YUI.add('event-key',function(Y){Y.Env.evt.plugins.key={on:function(type,fn,id,spec,o){var a=Y.Array(arguments,0,true),parsed,etype,criteria,ename;parsed=spec&&spec.split(':');if(!spec||spec.indexOf(':')==-1||!parsed[1]){a[0]='key'+((parsed&&parsed[0])||'press');return Y.on.apply(Y,a);} +etype=parsed[0];criteria=(parsed[1])?parsed[1].split(/,|\+/):null;ename=(Y.Lang.isString(id)?id:Y.stamp(id))+spec;ename=ename.replace(/,/g,'_');if(!Y.getEvent(ename)){Y.on(type+etype,function(e){var passed=false,failed=false,i,crit,critInt;for(i=0;i";try{V=K._historyIFrame.get("contentWindow.document");V.invoke("open");V.invoke("write",G,"","","","");V.invoke("close");return true;}catch(H){return false;}}function E(){var G,V,H;if(!K._historyIFrame.get("contentWindow.document")){setTimeout(E,10);return;}G=K._historyIFrame.get("contentWindow.document.body");V=G?G.get("innerText"):null;H=N();setInterval(function(){var Y,W,X;G=K._historyIFrame.get("contentWindow.document.body");Y=G?G.get("innerText"):null;X=N();if(Y!==V){V=Y;P(V);if(!V){W=[];A.Object.each(K._modules,function(Z,a){W.push(a+"="+Z.initialState);});X=W.join("&");}else{X=V;}C.location.hash=H=X;S();}else{if(X!==H){H=X;I(X);}}},50);K.ready=true;J.fire(L);}function T(){var H,Z,X,V,G,W,Y;Z=K._stateField.get("value").split("|");if(Z.length>1){M.lastIndex=0;while((H=M.exec(Z[0]))){X=H[1];G=H[2];V=K._modules[X];if(V){V.initialState=G;}}M.lastIndex=0;while((H=M.exec(Z[1]))){X=H[1];W=H[2];V=K._modules[X];if(V){V.currentState=W;}}}if(!A.Lang.isUndefined(C.onhashchange)&&(A.Lang.isUndefined(U.documentMode)||U.documentMode>7)){C.onhashchange=function(){var a=N();P(a);S();};K.ready=true;J.fire(L);}else{if(B){E();}else{Y=N();setInterval(function(){var a=N();if(a!==Y){Y=a;P(Y);S();}},50);K.ready=true;J.fire(L);}}}J={register:function(V,G){var H;if(!A.Lang.isString(V)||A.Lang.trim(V)===""||!A.Lang.isString(G)){throw new Error(R);}V=D(V);G=D(G);if(K._modules[V]){return;}if(K.ready){return null;}H=new J.Module(V,G);K._modules[V]=H;return H;},initialize:function(G,W){var H,V;if(K.ready){return true;}G=A.get(G);if(!G){throw new Error(R);}H=G.get("tagName").toUpperCase();V=G.get("type");if(H!=="TEXTAREA"&&(H!=="INPUT"||V!=="hidden"&&V!=="text")){throw new Error(R);}if(A.UA.ie&&(A.Lang.isUndefined(U.documentMode)||U.documentMode<8)){B=true;W=A.get(W);if(!W||W.get("tagName").toUpperCase()!=="IFRAME"){throw new Error(R);}}if(A.UA.opera&&!A.Lang.isUndefined(C.history.navigationMode)){C.history.navigationMode="compatible";}K._stateField=G;K._historyIFrame=W;A.on("domready",T);return true;},navigate:function(H,V){var G;if(!A.Lang.isString(H)||!A.Lang.isString(V)){throw new Error(R);}G={};G[H]=V;return J.multiNavigate(G);},multiNavigate:function(H){var V=[],W,G=false;if(!K.ready){return false;}A.Object.each(K._modules,function(Y,Z){var a,X=O(Z);if(!H.hasOwnProperty(X)){a=Y.currentState;}else{a=D(H[X]);if(a!==Y.upcomingState){Y.upcomingState=a;G=true;}}V.push(Z+"="+a);});if(!G){return false;}W=V.join("&");if(B){return I(W);}else{C.location.hash=W;return true;}},getCurrentState:function(H){var G;if(!A.Lang.isString(H)){throw new Error(R);}if(!K.ready){return null;}H=D(H);G=K._modules[H];if(!G){return null;}return O(G.currentState);},getBookmarkedState:function(W){var G,H,V;if(!A.Lang.isString(W)){throw new Error(R);}W=D(W);V=C.location.href;H=V.indexOf("#");if(H>=0){V=V.substr(H+1);M.lastIndex=0;while((G=M.exec(V))){if(G[1]===W){return O(G[2]);}}}return null;},getQueryStringParameter:function(X,H){var G,W,V;H=H||C.location.href;V=H.indexOf("?");W=V>=0?H.substr(V+1):H;V=W.lastIndexOf("#");W=V>=0?W.substr(0,V):W;M.lastIndex=0;while((G=M.exec(W))){if(G[1]===X){return O(G[2]);}}return null;}};A.mix(J,A.Event.Target.prototype);A.Event.Target.call(J);J.Module=function(H,G){A.Event.Target.call(this);this.id=H;this.initialState=G;this.currentState=G;this.upcomingState=G;};A.mix(J.Module,A.Event.Target,false,null,1);A.History=J;},"3.0.0",{skinnable:false,use:["event","node"]}); \ No newline at end of file diff --git a/include/javascript/yui3/build/history/history.js b/include/javascript/yui3/build/history/history.js new file mode 100644 index 00000000..ae5f7b3a --- /dev/null +++ b/include/javascript/yui3/build/history/history.js @@ -0,0 +1,39 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add('history',function(Y){var win=Y.config.win,doc=Y.config.doc,encode=encodeURIComponent,decode=decodeURIComponent,H,G,E_MISSING_OR_INVALID_ARG='Missing or invalid argument',REGEXP=/([^=&]+)=([^&]*)/g,_useIFrame=false,_getHash,EV_HISTORY_READY='history:ready',EV_HISTORY_GLOBAL_STATE_CHANGE='history:globalStateChange',EV_HISTORY_MODULE_STATE_CHANGE='history:moduleStateChange';if(!YUI.Env.history){YUI.Env.history=G={ready:false,_modules:[],_stateField:null,_historyIFrame:null};} +if(Y.UA.gecko){_getHash=function(){var m=/#(.*)$/.exec(win.location.href);return m&&m[1]?m[1]:'';};}else{_getHash=function(){return win.location.hash.substr(1);};} +function _storeStates(){var initialStates=[],currentStates=[];Y.Object.each(G._modules,function(module,moduleId){initialStates.push(moduleId+'='+module.initialState);currentStates.push(moduleId+'='+module.currentState);});G._stateField.set('value',initialStates.join('&')+'|'+currentStates.join('&'));} +function _handleFQStateChange(fqstate){var m,states=[],globalStateChanged=false;if(fqstate){REGEXP.lastIndex=0;while((m=REGEXP.exec(fqstate))){states[m[1]]=m[2];} +Y.Object.each(G._modules,function(module,moduleId){var currentState=states[moduleId];if(!currentState||module.currentState!==currentState){module.currentState=currentState||module.initialState;module.fire(EV_HISTORY_MODULE_STATE_CHANGE,decode(module.currentState));globalStateChanged=true;}});}else{Y.Object.each(G._modules,function(module,moduleId){if(module.currentState!==module.initialState){module.currentState=module.initialState;module.fire(EV_HISTORY_MODULE_STATE_CHANGE,decode(module.currentState));globalStateChanged=true;}});} +if(globalStateChanged){H.fire(EV_HISTORY_GLOBAL_STATE_CHANGE);}} +function _updateIFrame(fqstate){var html,doc;html=''+fqstate+'';try{doc=G._historyIFrame.get('contentWindow.document');doc.invoke('open');doc.invoke('write',html,'','','','');doc.invoke('close');return true;}catch(e){return false;}} +function _checkIframeLoaded(){var elem,fqstate,hash;if(!G._historyIFrame.get('contentWindow.document')){setTimeout(_checkIframeLoaded,10);return;} +elem=G._historyIFrame.get('contentWindow.document.body');fqstate=elem?elem.get('innerText'):null;hash=_getHash();setInterval(function(){var newfqstate,states,newHash;elem=G._historyIFrame.get('contentWindow.document.body');newfqstate=elem?elem.get('innerText'):null;newHash=_getHash();if(newfqstate!==fqstate){fqstate=newfqstate;_handleFQStateChange(fqstate);if(!fqstate){states=[];Y.Object.each(G._modules,function(module,moduleId){states.push(moduleId+'='+module.initialState);});newHash=states.join('&');}else{newHash=fqstate;} +win.location.hash=hash=newHash;_storeStates();}else if(newHash!==hash){hash=newHash;_updateIFrame(newHash);}},50);G.ready=true;H.fire(EV_HISTORY_READY);} +function _initialize(){var m,parts,moduleId,module,initialState,currentState,hash;parts=G._stateField.get('value').split('|');if(parts.length>1){REGEXP.lastIndex=0;while((m=REGEXP.exec(parts[0]))){moduleId=m[1];initialState=m[2];module=G._modules[moduleId];if(module){module.initialState=initialState;}} +REGEXP.lastIndex=0;while((m=REGEXP.exec(parts[1]))){moduleId=m[1];currentState=m[2];module=G._modules[moduleId];if(module){module.currentState=currentState;}}} +if(!Y.Lang.isUndefined(win.onhashchange)&&(Y.Lang.isUndefined(doc.documentMode)||doc.documentMode>7)){win.onhashchange=function(){var hash=_getHash();_handleFQStateChange(hash);_storeStates();};G.ready=true;H.fire(EV_HISTORY_READY);}else if(_useIFrame){_checkIframeLoaded();}else{hash=_getHash();setInterval(function(){var newHash=_getHash();if(newHash!==hash){hash=newHash;_handleFQStateChange(hash);_storeStates();}},50);G.ready=true;H.fire(EV_HISTORY_READY);}} +H={register:function(moduleId,initialState){var module;if(!Y.Lang.isString(moduleId)||Y.Lang.trim(moduleId)===''||!Y.Lang.isString(initialState)){throw new Error(E_MISSING_OR_INVALID_ARG);} +moduleId=encode(moduleId);initialState=encode(initialState);if(G._modules[moduleId]){return;} +if(G.ready){return null;} +module=new H.Module(moduleId,initialState);G._modules[moduleId]=module;return module;},initialize:function(stateField,historyIFrame){var tagName,type;if(G.ready){return true;} +stateField=Y.get(stateField);if(!stateField){throw new Error(E_MISSING_OR_INVALID_ARG);} +tagName=stateField.get('tagName').toUpperCase();type=stateField.get('type');if(tagName!=='TEXTAREA'&&(tagName!=='INPUT'||type!=='hidden'&&type!=='text')){throw new Error(E_MISSING_OR_INVALID_ARG);} +if(Y.UA.ie&&(Y.Lang.isUndefined(doc.documentMode)||doc.documentMode<8)){_useIFrame=true;historyIFrame=Y.get(historyIFrame);if(!historyIFrame||historyIFrame.get('tagName').toUpperCase()!=='IFRAME'){throw new Error(E_MISSING_OR_INVALID_ARG);}} +if(Y.UA.opera&&!Y.Lang.isUndefined(win.history.navigationMode)){win.history.navigationMode='compatible';} +G._stateField=stateField;G._historyIFrame=historyIFrame;Y.on('domready',_initialize);return true;},navigate:function(moduleId,state){var states;if(!Y.Lang.isString(moduleId)||!Y.Lang.isString(state)){throw new Error(E_MISSING_OR_INVALID_ARG);} +states={};states[moduleId]=state;return H.multiNavigate(states);},multiNavigate:function(states){var newStates=[],fqstate,globalStateChanged=false;if(!G.ready){return false;} +Y.Object.each(G._modules,function(module,moduleId){var state,decodedModuleId=decode(moduleId);if(!states.hasOwnProperty(decodedModuleId)){state=module.currentState;}else{state=encode(states[decodedModuleId]);if(state!==module.upcomingState){module.upcomingState=state;globalStateChanged=true;}} +newStates.push(moduleId+'='+state);});if(!globalStateChanged){return false;} +fqstate=newStates.join('&');if(_useIFrame){return _updateIFrame(fqstate);}else{win.location.hash=fqstate;return true;}},getCurrentState:function(moduleId){var module;if(!Y.Lang.isString(moduleId)){throw new Error(E_MISSING_OR_INVALID_ARG);} +if(!G.ready){return null;} +moduleId=encode(moduleId);module=G._modules[moduleId];if(!module){return null;} +return decode(module.currentState);},getBookmarkedState:function(moduleId){var m,i,h;if(!Y.Lang.isString(moduleId)){throw new Error(E_MISSING_OR_INVALID_ARG);} +moduleId=encode(moduleId);h=win.location.href;i=h.indexOf('#');if(i>=0){h=h.substr(i+1);REGEXP.lastIndex=0;while((m=REGEXP.exec(h))){if(m[1]===moduleId){return decode(m[2]);}}} +return null;},getQueryStringParameter:function(paramName,url){var m,q,i;url=url||win.location.href;i=url.indexOf('?');q=i>=0?url.substr(i+1):url;i=q.lastIndexOf('#');q=i>=0?q.substr(0,i):q;REGEXP.lastIndex=0;while((m=REGEXP.exec(q))){if(m[1]===paramName){return decode(m[2]);}} +return null;}};Y.mix(H,Y.Event.Target.prototype);Y.Event.Target.call(H);H.Module=function(id,initialState){Y.Event.Target.call(this);this.id=id;this.initialState=initialState;this.currentState=initialState;this.upcomingState=initialState;};Y.mix(H.Module,Y.Event.Target,false,null,1);Y.History=H;},'3.0.0',{skinnable:false,use:['event','node']}); \ No newline at end of file diff --git a/include/javascript/yui3/build/imageloader/imageloader-min.js b/include/javascript/yui3/build/imageloader/imageloader-min.js new file mode 100644 index 00000000..cc3f774d --- /dev/null +++ b/include/javascript/yui3/build/imageloader/imageloader-min.js @@ -0,0 +1,8 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add("imageloader",function(B){B.ImgLoadGroup=function(){this._init();B.ImgLoadGroup.superclass.constructor.apply(this,arguments);};B.ImgLoadGroup.NAME="imgLoadGroup";B.ImgLoadGroup.ATTRS={name:{value:""},timeLimit:{value:null},foldDistance:{validator:B.Lang.isNumber,setter:function(D){this._setFoldTriggers();return D;},lazyAdd:false},className:{value:null,setter:function(D){this._className=D;return D;},lazyAdd:false}};var C={_init:function(){this._triggers=[];this._imgObjs={};this._timeout=null;this._classImageEls=null;this._className=null;this._areFoldTriggersSet=false;this._maxKnownHLimit=0;B.on("domready",this._onloadTasks,this);},addTrigger:function(F,E){if(!F||!E){return this;}var D=function(){this.fetch();};this._triggers.push(B.on(E,D,F,this));return this;},addCustomTrigger:function(D,F){if(!D){return this;}var E=function(){this.fetch();};if(B.Lang.isUndefined(F)){this._triggers.push(B.on(D,E,this));}else{this._triggers.push(F.on(D,E,this));}return this;},_setFoldTriggers:function(){if(this._areFoldTriggersSet){return;}var D=function(){this._foldCheck();};this._triggers.push(B.on("scroll",D,window,this));this._triggers.push(B.on("resize",D,window,this));this._areFoldTriggersSet=true;},_onloadTasks:function(){var D=this.get("timeLimit");if(D&&D>0){this._timeout=setTimeout(this._getFetchTimeout(),D*1000);}if(!B.Lang.isUndefined(this.get("foldDistance"))){this._foldCheck();}},_getFetchTimeout:function(){var D=this;return function(){D.fetch();};},registerImage:function(){var D=arguments[0].domId;if(!D){return null;}this._imgObjs[D]=new B.ImgLoadImgObj(arguments[0]);return this._imgObjs[D];},fetch:function(){this._clearTriggers();this._fetchByClass();for(var D in this._imgObjs){if(this._imgObjs.hasOwnProperty(D)){this._imgObjs[D].fetch();}}},_clearTriggers:function(){clearTimeout(this._timeout);for(var E=0,D=this._triggers.length;EF){return false;}}if(this.get("bgUrl")!==null){if(this.get("isPng")&&B.UA.ie&&B.UA.ie<=6){D.setStyle("filter",'progid:DXImageTransform.Microsoft.AlphaImageLoader(src="'+this.get("url")+'", sizingMethod="'+this.get("sizingMethod")+'", enabled="'+this.get("enabled")+'")');}else{D.setStyle("backgroundImage","url('"+this.get("bgUrl")+"')");}}else{if(this.get("srcUrl")!==null){D.setAttribute("src",this.get("srcUrl"));}}if(this.get("setVisible")){D.setStyle("visibility","visible");}if(this.get("width")){D.setAttribute("width",this.get("width"));}if(this.get("height")){D.setAttribute("height",this.get("height"));}this._fetched=true;return true;},_getImgEl:function(){if(this._imgEl===null){this._imgEl=B.get("#"+this.get("domId"));}return this._imgEl;},_getYPos:function(){if(this._yPos===null){this._yPos=this._getImgEl().getY();}return this._yPos;}};B.extend(B.ImgLoadImgObj,B.Base,A);},"3.0.0",{requires:["base-base","node-style","node-screen"]}); \ No newline at end of file diff --git a/include/javascript/yui3/build/imageloader/imageloader.js b/include/javascript/yui3/build/imageloader/imageloader.js new file mode 100644 index 00000000..8d181059 --- /dev/null +++ b/include/javascript/yui3/build/imageloader/imageloader.js @@ -0,0 +1,33 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add('imageloader',function(Y){Y.ImgLoadGroup=function(){this._init();Y.ImgLoadGroup.superclass.constructor.apply(this,arguments);};Y.ImgLoadGroup.NAME='imgLoadGroup';Y.ImgLoadGroup.ATTRS={name:{value:''},timeLimit:{value:null},foldDistance:{validator:Y.Lang.isNumber,setter:function(val){this._setFoldTriggers();return val;},lazyAdd:false},className:{value:null,setter:function(name){this._className=name;return name;},lazyAdd:false}};var groupProto={_init:function(){this._triggers=[];this._imgObjs={};this._timeout=null;this._classImageEls=null;this._className=null;this._areFoldTriggersSet=false;this._maxKnownHLimit=0;Y.on('domready',this._onloadTasks,this);},addTrigger:function(obj,type){if(!obj||!type){return this;} +var wrappedFetch=function(){this.fetch();};this._triggers.push(Y.on(type,wrappedFetch,obj,this));return this;},addCustomTrigger:function(name,obj){if(!name){return this;} +var wrappedFetch=function(){this.fetch();};if(Y.Lang.isUndefined(obj)){this._triggers.push(Y.on(name,wrappedFetch,this));} +else{this._triggers.push(obj.on(name,wrappedFetch,this));} +return this;},_setFoldTriggers:function(){if(this._areFoldTriggersSet){return;} +var wrappedFoldCheck=function(){this._foldCheck();};this._triggers.push(Y.on('scroll',wrappedFoldCheck,window,this));this._triggers.push(Y.on('resize',wrappedFoldCheck,window,this));this._areFoldTriggersSet=true;},_onloadTasks:function(){var timeLim=this.get('timeLimit');if(timeLim&&timeLim>0){this._timeout=setTimeout(this._getFetchTimeout(),timeLim*1000);} +if(!Y.Lang.isUndefined(this.get('foldDistance'))){this._foldCheck();}},_getFetchTimeout:function(){var self=this;return function(){self.fetch();};},registerImage:function(){var domId=arguments[0].domId;if(!domId){return null;} +this._imgObjs[domId]=new Y.ImgLoadImgObj(arguments[0]);return this._imgObjs[domId];},fetch:function(){this._clearTriggers();this._fetchByClass();for(var id in this._imgObjs){if(this._imgObjs.hasOwnProperty(id)){this._imgObjs[id].fetch();}}},_clearTriggers:function(){clearTimeout(this._timeout);for(var i=0,len=this._triggers.length;iwithinY){return false;}} +if(this.get('bgUrl')!==null){if(this.get('isPng')&&Y.UA.ie&&Y.UA.ie<=6){el.setStyle('filter','progid:DXImageTransform.Microsoft.AlphaImageLoader(src="'+this.get('url')+'", sizingMethod="'+this.get('sizingMethod')+'", enabled="'+this.get('enabled')+'")');} +else{el.setStyle('backgroundImage',"url('"+this.get('bgUrl')+"')");}} +else if(this.get('srcUrl')!==null){el.setAttribute('src',this.get('srcUrl'));} +if(this.get('setVisible')){el.setStyle('visibility','visible');} +if(this.get('width')){el.setAttribute('width',this.get('width'));} +if(this.get('height')){el.setAttribute('height',this.get('height'));} +this._fetched=true;return true;},_getImgEl:function(){if(this._imgEl===null){this._imgEl=Y.get('#'+this.get('domId'));} +return this._imgEl;},_getYPos:function(){if(this._yPos===null){this._yPos=this._getImgEl().getY();} +return this._yPos;}};Y.extend(Y.ImgLoadImgObj,Y.Base,imgProto);},'3.0.0',{requires:['base-base','node-style','node-screen']}); \ No newline at end of file diff --git a/include/javascript/yui3/build/io/io-base-min.js b/include/javascript/yui3/build/io/io-base-min.js new file mode 100644 index 00000000..5e89bfae --- /dev/null +++ b/include/javascript/yui3/build/io/io-base-min.js @@ -0,0 +1,8 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add("io-base",function(D){var d="io:start",P="io:complete",B="io:success",F="io:failure",e="io:end",X=0,O={"X-Requested-With":"XMLHttpRequest"},Z={},K=D.config.win;function b(h,p,g){var j,l,Y;p=p||{};l=W(p.xdr||p.form,g);Y=p.method?p.method.toUpperCase():"GET";if(p.form){if(p.form.upload){return D.io._upload(l,h,p);}else{j=D.io._serialize(p.form,p.data);if(Y==="POST"){p.data=j;V("Content-Type","application/x-www-form-urlencoded");}else{if(Y==="GET"){h=Q(h,j);}}}}else{if(p.data&&Y==="GET"){h=Q(h,p.data);}}if(p.xdr){if(p.xdr.use==="native"&&window.XDomainRequest||p.xdr.use==="flash"){return D.io.xdr(h,l,p);}if(p.xdr.credentials){l.c.withCredentials=true;}}l.c.onreadystatechange=function(){c(l,p);};try{l.c.open(Y,h,true);}catch(n){if(p.xdr){return A(l,h,p);}}if(p.data&&Y==="POST"){V("Content-Type","application/x-www-form-urlencoded; charset=UTF-8");}C(l.c,p.headers||{});try{l.c.send(p.data||"");}catch(k){if(p.xdr){return A(l,h,p);}}S(l.id,p);if(p.timeout){R(l,p.timeout);}return{id:l.id,abort:function(){return l.c?N(l,"abort"):false;},isInProgress:function(){return l.c?l.c.readyState!==4&&l.c.readyState!==0:false;}};}function U(f,g){var Y=new D.EventTarget().publish("transaction:"+f);Y.subscribe(g.on[f],(g.context||D),g.arguments);return Y;}function S(g,f){var Y;f.on=f.on||{};D.fire(d,g);if(f.on.start){Y=U("start",f);Y.fire(g);}}function G(g,h){var Y,f=g.status?{status:0,statusText:g.status}:g.c;h.on=h.on||{};D.fire(P,g.id,f);if(h.on.complete){Y=U("complete",h);Y.fire(g.id,f);}}function T(f,g){var Y;g.on=g.on||{};D.fire(B,f.id,f.c);if(g.on.success){Y=U("success",g);Y.fire(f.id,f.c);}J(f,g);}function I(g,h){var Y,f=g.status?{status:0,statusText:g.status}:g.c;h.on=h.on||{};D.fire(F,g.id,f);if(h.on.failure){Y=U("failure",h);Y.fire(g.id,f);}J(g,h);}function J(f,g){var Y;g.on=g.on||{};D.fire(e,f.id);if(g.on.end){Y=U("end",g);Y.fire(f.id);}H(f,g.xdr?true:false);}function N(f,Y){if(f&&f.c){f.status=Y;f.c.abort();}}function A(f,Y,h){var g=parseInt(f.id);H(f);h.xdr.use="flash";return D.io(Y,h,g);}function E(){var Y=X;X++;return Y;}function W(g,Y){var f={};f.id=D.Lang.isNumber(Y)?Y:E();g=g||{};if(!g.use&&!g.upload){f.c=L();}else{if(g.use){if(g.use==="flash"){f.c=D.io._transport[g.use];}else{if(g.use==="native"&&window.XDomainRequest){f.c=new XDomainRequest();}else{f.c=L();}}}else{f.c={};}}return f;}function L(){return K.XMLHttpRequest?new XMLHttpRequest():new ActiveXObject("Microsoft.XMLHTTP");}function Q(Y,f){Y+=((Y.indexOf("?")==-1)?"?":"&")+f;return Y;}function V(Y,f){if(f){O[Y]=f;}else{delete O[Y];}}function C(g,Y){var f;for(f in O){if(O.hasOwnProperty(f)){if(Y[f]){break;}else{Y[f]=O[f];}}}for(f in Y){if(Y.hasOwnProperty(f)){g.setRequestHeader(f,Y[f]);}}}function R(f,Y){Z[f.id]=K.setTimeout(function(){N(f,"timeout");},Y);}function M(Y){K.clearTimeout(Z[Y]);delete Z[Y];}function c(Y,f){if(Y.c.readyState===4){if(f.timeout){M(Y.id);}K.setTimeout(function(){G(Y,f);a(Y,f);},0);}}function a(g,h){var Y;try{if(g.c.status&&g.c.status!==0){Y=g.c.status;}else{Y=0;}}catch(f){Y=0;}if(Y>=200&&Y<300||Y===1223){T(g,h);}else{I(g,h);}}function H(Y,f){if(K.XMLHttpRequest&&!f){if(Y.c){Y.c.onreadystatechange=null;}}Y.c=null;Y=null;}b.start=S;b.complete=G;b.success=T;b.failure=I;b.end=J;b._id=E;b._timeout=Z;b.header=V;D.io=b;D.io.http=b;},"3.0.0",{requires:["event-custom-base"]}); \ No newline at end of file diff --git a/include/javascript/yui3/build/io/io-base.js b/include/javascript/yui3/build/io/io-base.js new file mode 100644 index 00000000..a1972abd --- /dev/null +++ b/include/javascript/yui3/build/io/io-base.js @@ -0,0 +1,56 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add('io-base',function(Y){var E_START='io:start',E_COMPLETE='io:complete',E_SUCCESS='io:success',E_FAILURE='io:failure',E_END='io:end',transactionId=0,_headers={'X-Requested-With':'XMLHttpRequest'},_timeout={},w=Y.config.win;function _io(uri,c,i){var f,o,m;c=c||{};o=_create(c.xdr||c.form,i);m=c.method?c.method.toUpperCase():'GET';if(c.form){if(c.form.upload){return Y.io._upload(o,uri,c);} +else{f=Y.io._serialize(c.form,c.data);if(m==='POST'){c.data=f;_setHeader('Content-Type','application/x-www-form-urlencoded');} +else if(m==='GET'){uri=_concat(uri,f);}}} +else if(c.data&&m==='GET'){uri=_concat(uri,c.data);} +if(c.xdr){if(c.xdr.use==='native'&&window.XDomainRequest||c.xdr.use==='flash'){return Y.io.xdr(uri,o,c);} +if(c.xdr.credentials){o.c.withCredentials=true;}} +o.c.onreadystatechange=function(){_readyState(o,c);};try{o.c.open(m,uri,true);} +catch(e0){if(c.xdr){return _resend(o,uri,c);}} +if(c.data&&m==='POST'){_setHeader('Content-Type','application/x-www-form-urlencoded; charset=UTF-8');} +_setHeaders(o.c,c.headers||{});try{o.c.send(c.data||'');} +catch(e1){if(c.xdr){return _resend(o,uri,c);}} +_ioStart(o.id,c);if(c.timeout){_startTimeout(o,c.timeout);} +return{id:o.id,abort:function(){return o.c?_ioCancel(o,'abort'):false;},isInProgress:function(){return o.c?o.c.readyState!==4&&o.c.readyState!==0:false;}}} +function _subscribe(e,c){var evt=new Y.EventTarget().publish('transaction:'+e);evt.subscribe(c.on[e],(c.context||Y),c.arguments);return evt;} +function _ioStart(id,c){var evt;c.on=c.on||{};Y.fire(E_START,id);if(c.on.start){evt=_subscribe('start',c);evt.fire(id);}} +function _ioComplete(o,c){var evt,r=o.status?{status:0,statusText:o.status}:o.c;c.on=c.on||{};Y.fire(E_COMPLETE,o.id,r);if(c.on.complete){evt=_subscribe('complete',c);evt.fire(o.id,r);}} +function _ioSuccess(o,c){var evt;c.on=c.on||{};Y.fire(E_SUCCESS,o.id,o.c);if(c.on.success){evt=_subscribe('success',c);evt.fire(o.id,o.c);} +_ioEnd(o,c);} +function _ioFailure(o,c){var evt,r=o.status?{status:0,statusText:o.status}:o.c;c.on=c.on||{};Y.fire(E_FAILURE,o.id,r);if(c.on.failure){evt=_subscribe('failure',c);evt.fire(o.id,r);} +_ioEnd(o,c);} +function _ioEnd(o,c){var evt;c.on=c.on||{};Y.fire(E_END,o.id);if(c.on.end){evt=_subscribe('end',c);evt.fire(o.id);} +_destroy(o,c.xdr?true:false);} +function _ioCancel(o,s){if(o&&o.c){o.status=s;o.c.abort();}} +function _resend(o,uri,c){var id=parseInt(o.id);_destroy(o);c.xdr.use='flash';return Y.io(uri,c,id);} +function _id(){var id=transactionId;transactionId++;return id;} +function _create(c,i){var o={};o.id=Y.Lang.isNumber(i)?i:_id();c=c||{};if(!c.use&&!c.upload){o.c=_xhr();} +else if(c.use){if(c.use==='flash'){o.c=Y.io._transport[c.use];} +else if(c.use==='native'&&window.XDomainRequest){o.c=new XDomainRequest();} +else{o.c=_xhr();}} +else{o.c={};} +return o;};function _xhr(){return w.XMLHttpRequest?new XMLHttpRequest():new ActiveXObject('Microsoft.XMLHTTP');} +function _concat(s,d){s+=((s.indexOf('?')==-1)?'?':'&')+d;return s;} +function _setHeader(l,v){if(v){_headers[l]=v;} +else{delete _headers[l];}} +function _setHeaders(o,h){var p;for(p in _headers){if(_headers.hasOwnProperty(p)){if(h[p]){break;} +else{h[p]=_headers[p];}}} +for(p in h){if(h.hasOwnProperty(p)){o.setRequestHeader(p,h[p]);}}} +function _startTimeout(o,timeout){_timeout[o.id]=w.setTimeout(function(){_ioCancel(o,'timeout');},timeout);} +function _clearTimeout(id){w.clearTimeout(_timeout[id]);delete _timeout[id];} +function _readyState(o,c){if(o.c.readyState===4){if(c.timeout){_clearTimeout(o.id);} +w.setTimeout(function(){_ioComplete(o,c);_handleResponse(o,c);},0);}} +function _handleResponse(o,c){var status;try{if(o.c.status&&o.c.status!==0){status=o.c.status;} +else{status=0;}} +catch(e){status=0;} +if(status>=200&&status<300||status===1223){_ioSuccess(o,c);} +else{_ioFailure(o,c);}} +function _destroy(o,transport){if(w.XMLHttpRequest&&!transport){if(o.c){o.c.onreadystatechange=null;}} +o.c=null;o=null;} +_io.start=_ioStart;_io.complete=_ioComplete;_io.success=_ioSuccess;_io.failure=_ioFailure;_io.end=_ioEnd;_io._id=_id;_io._timeout=_timeout;_io.header=_setHeader;Y.io=_io;Y.io.http=_io;},'3.0.0',{requires:['event-custom-base']}); \ No newline at end of file diff --git a/include/javascript/yui3/build/io/io-form-min.js b/include/javascript/yui3/build/io/io-form-min.js new file mode 100644 index 00000000..ce2ccf2a --- /dev/null +++ b/include/javascript/yui3/build/io/io-form-min.js @@ -0,0 +1,8 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add("io-form",function(A){A.mix(A.io,{_serialize:function(M,R){var I=encodeURIComponent,H=[],N=M.useDisabled||false,Q=0,B=(typeof M.id==="string")?M.id:M.id.getAttribute("id"),K,J,D,P,L,G,O,E,F,C;if(!B){B=A.guid("io:");M.id.setAttribute("id",B);}J=A.config.doc.getElementById(B);for(G=0,O=J.elements.length;G-1){C=K.options[K.selectedIndex];H[Q++]=D+I((C.attributes.value&&C.attributes.value.specified)?C.value:C.text);}break;case"select-multiple":if(K.selectedIndex>-1){for(E=K.selectedIndex,F=K.options.length;E-1){o=e.options[e.selectedIndex];data[item++]=n+eUC((o.attributes.value&&o.attributes.value.specified)?o.value:o.text);} +break;case'select-multiple':if(e.selectedIndex>-1){for(j=e.selectedIndex,jl=e.options.length;j=200&&Y<300||Y===1223){T(g,h);}else{I(g,h);}}function H(Y,f){if(K.XMLHttpRequest&&!f){if(Y.c){Y.c.onreadystatechange=null;}}Y.c=null;Y=null;}b.start=S;b.complete=G;b.success=T;b.failure=I;b.end=J;b._id=E;b._timeout=Z;b.header=V;D.io=b;D.io.http=b;},"3.0.0",{requires:["event-custom-base"]});YUI.add("io-form",function(A){A.mix(A.io,{_serialize:function(M,R){var I=encodeURIComponent,H=[],N=M.useDisabled||false,Q=0,B=(typeof M.id==="string")?M.id:M.id.getAttribute("id"),K,J,D,P,L,G,O,E,F,C;if(!B){B=A.guid("io:");M.id.setAttribute("id",B);}J=A.config.doc.getElementById(B);for(G=0,O=J.elements.length;G-1){C=K.options[K.selectedIndex];H[Q++]=D+I((C.attributes.value&&C.attributes.value.specified)?C.value:C.text);}break;case"select-multiple":if(K.selectedIndex>-1){for(E=K.selectedIndex,F=K.options.length;E'+''+''+''+"
    ",L=document.createElement("div");document.body.appendChild(L);L.innerHTML=K;}function G(J,K){J.c.onprogress=function(){E[J.id]=3;};J.c.onload=function(){E[J.id]=4;A.io.xdrResponse(J,K,"success");};J.c.onerror=function(){E[J.id]=4;A.io.xdrResponse(J,K,"failure");};if(K.timeout){J.c.ontimeout=function(){E[J.id]=4;A.io.xdrResponse(J,K,"timeout");};J.c.timeout=K.timeout;}}function B(M,K,N){var L,J;if(!M.status){L=K?decodeURI(M.c.responseText):M.c.responseText;J=N?A.DataType.XML.parse(L):null;return{id:M.id,c:{responseText:L,responseXML:J}};}else{return{id:M.id,status:M.status};}}function H(J,K){return K.xdr.use==="flash"?J.c.abort(J.id,K):J.c.abort();}function C(K,J){return(J==="flash"&&K.c)?K.c.isInProgress(K.id):E[K.id]!==4;}A.mix(A.io,{_transport:{},xdr:function(J,K,L){if(L.on&&L.xdr.use==="flash"){D[K.id]={on:L.on,context:L.context,arguments:L.arguments};L.context=null;L.form=null;K.c.send(J,L,K.id);}else{if(window.XDomainRequest){G(K,L);K.c.open(L.method||"GET",J);K.c.send(L.data);}}return{id:K.id,abort:function(){return K.c?H(K,L):false;},isInProgress:function(){return K.c?C(K,L.xdr.use):false;}};},xdrResponse:function(N,P,M){var J,L,K=P.xdr.use==="flash"?true:false,O=P.xdr.dataType==="xml"?true:false;P.on=P.on||{};if(K){J=D||{};L=J[N.id]?J[N.id]:null;if(L){P.on=L.on;P.context=L.context;P.arguments=L.arguments;}}if(M===("abort"||"timeout")){N.status=M;}switch(M){case"start":A.io.start(N.id,P);break;case"success":A.io.success(B(N,K,O),P);K?delete J[N.id]:delete E[N.id];break;case"timeout":case"abort":case"failure":A.io.failure(B(N,K,O),P);K?delete J[N.id]:delete E[N.id];break;}},xdrReady:function(J){A.fire(I,J);},transport:function(J){var K=J.yid?J.yid:A.id;F(J.src,K);this._transport.flash=A.config.doc.getElementById("yuiIoSwf");}});},"3.0.0",{requires:["io-base","datatype-xml"]});YUI.add("io-upload-iframe",function(B){var I=B.config.win;function D(P,O){var Q=[],L=O.split("="),N,M;for(N=0,M=L.length-1;N');L._node.style.position="absolute";L._node.style.top="-1000px";L._node.style.left="-1000px";B.one("body").appendChild(L);B.on("load",function(){A(M,N);},"#ioupload"+M.id);}function A(P,Q){var O=B.one("#ioupload"+P.id).get("contentWindow.document"),L=O.one("body"),M=(O._node.nodeType===9),N;if(Q.timeout){H(P.id);}if(L){N=L.query("pre:first-child");P.c.responseText=N?N.get("innerHTML"):L.get("innerHTML");}else{if(M){P.c.responseXML=O._node;}}B.io.complete(P,Q);B.io.end(P,Q);I.setTimeout(function(){G(P.id);},0);}function C(L,M){B.io._timeout[L.id]=I.setTimeout(function(){var N={id:L.id,status:"timeout"};B.io.complete(N,M);B.io.end(N,M);},M.timeout);}function H(L){I.clearTimeout(B.io._timeout[L]);delete B.io._timeout[L];}function G(L){B.Event.purgeElement("#ioupload"+L,false);B.one("body").removeChild(B.one("#ioupload"+L));}B.mix(B.io,{_upload:function(P,N,Q){var O=(typeof Q.form.id==="string")?B.config.doc.getElementById(Q.form.id):Q.form.id,M,L={action:O.getAttribute("action"),target:O.getAttribute("target")};J(P,Q);E(O,P.id,N);if(Q.data){M=D(O,Q.data);}if(Q.timeout){C(P,Q);}O.submit();B.io.start(P.id,Q);if(Q.data){F(O,M);}K(O,L);return{id:P.id,abort:function(){var R={id:P.id,status:"abort"};if(B.one("#ioupload"+P.id)){G(P.id);B.io.complete(R,Q);B.io.end(R,Q);}else{return false;}},isInProgress:function(){return B.one("#ioupload"+P.id)?true:false;}};}});},"3.0.0",{requires:["io-base","node-base","event-base"]});YUI.add("io-queue",function(B){var A=new B.Queue(),I,G,M=1;function J(N,P){var O={uri:N,id:B.io._id(),cfg:P};A.add(O);if(M===1){F();}return O;}function F(){var N=A.next();G=N.id;M=0;B.io(N.uri,N.cfg,N.id);}function D(N){A.promote(N);}function C(N){M=1;if(G===N&&A.size()>0){F();}}function L(N){A.remove(N);}function E(){M=1;if(A.size()>0){F();}}function H(){M=0;}function K(){return A.size();}I=B.on("io:complete",function(N){C(N);},B.io);J.size=K;J.start=E;J.stop=H;J.promote=D;J.remove=L;B.mix(B.io,{queue:J},true);},"3.0.0",{requires:["io-base","queue-promote"]});YUI.add("io",function(A){},"3.0.0",{use:["io-base","io-form","io-xdr","io-upload-iframe","io-queue"]}); \ No newline at end of file diff --git a/include/javascript/yui3/build/io/io-queue-min.js b/include/javascript/yui3/build/io/io-queue-min.js new file mode 100644 index 00000000..c2c6ba1c --- /dev/null +++ b/include/javascript/yui3/build/io/io-queue-min.js @@ -0,0 +1,8 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add("io-queue",function(B){var A=new B.Queue(),I,G,M=1;function J(N,P){var O={uri:N,id:B.io._id(),cfg:P};A.add(O);if(M===1){F();}return O;}function F(){var N=A.next();G=N.id;M=0;B.io(N.uri,N.cfg,N.id);}function D(N){A.promote(N);}function C(N){M=1;if(G===N&&A.size()>0){F();}}function L(N){A.remove(N);}function E(){M=1;if(A.size()>0){F();}}function H(){M=0;}function K(){return A.size();}I=B.on("io:complete",function(N){C(N);},B.io);J.size=K;J.start=E;J.stop=H;J.promote=D;J.remove=L;B.mix(B.io,{queue:J},true);},"3.0.0",{requires:["io-base","queue-promote"]}); \ No newline at end of file diff --git a/include/javascript/yui3/build/io/io-queue.js b/include/javascript/yui3/build/io/io-queue.js new file mode 100644 index 00000000..12afc5b0 --- /dev/null +++ b/include/javascript/yui3/build/io/io-queue.js @@ -0,0 +1,15 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add('io-queue',function(Y){var _q=new Y.Queue(),_e,_activeId,_qState=1;function _queue(uri,c){var o={uri:uri,id:Y.io._id(),cfg:c};_q.add(o);if(_qState===1){_shift();} +return o;} +function _shift(){var o=_q.next();_activeId=o.id;_qState=0;Y.io(o.uri,o.cfg,o.id);} +function _unshift(o){_q.promote(o);} +function _next(id){_qState=1;if(_activeId===id&&_q.size()>0){_shift();}} +function _remove(o){_q.remove(o);} +function _start(){_qState=1;if(_q.size()>0){_shift();}} +function _stop(){_qState=0;};function _size(){return _q.size();};_e=Y.on('io:complete',function(id){_next(id);},Y.io);_queue.size=_size;_queue.start=_start;_queue.stop=_stop;_queue.promote=_unshift;_queue.remove=_remove;Y.mix(Y.io,{queue:_queue},true);},'3.0.0',{requires:['io-base','queue-promote']}); \ No newline at end of file diff --git a/include/javascript/yui3/build/io/io-upload-iframe-min.js b/include/javascript/yui3/build/io/io-upload-iframe-min.js new file mode 100644 index 00000000..77883248 --- /dev/null +++ b/include/javascript/yui3/build/io/io-upload-iframe-min.js @@ -0,0 +1,8 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add("io-upload-iframe",function(B){var I=B.config.win;function D(P,O){var Q=[],L=O.split("="),N,M;for(N=0,M=L.length-1;N');L._node.style.position="absolute";L._node.style.top="-1000px";L._node.style.left="-1000px";B.one("body").appendChild(L);B.on("load",function(){A(M,N);},"#ioupload"+M.id);}function A(P,Q){var O=B.one("#ioupload"+P.id).get("contentWindow.document"),L=O.one("body"),M=(O._node.nodeType===9),N;if(Q.timeout){H(P.id);}if(L){N=L.query("pre:first-child");P.c.responseText=N?N.get("innerHTML"):L.get("innerHTML");}else{if(M){P.c.responseXML=O._node;}}B.io.complete(P,Q);B.io.end(P,Q);I.setTimeout(function(){G(P.id);},0);}function C(L,M){B.io._timeout[L.id]=I.setTimeout(function(){var N={id:L.id,status:"timeout"};B.io.complete(N,M);B.io.end(N,M);},M.timeout);}function H(L){I.clearTimeout(B.io._timeout[L]);delete B.io._timeout[L];}function G(L){B.Event.purgeElement("#ioupload"+L,false);B.one("body").removeChild(B.one("#ioupload"+L));}B.mix(B.io,{_upload:function(P,N,Q){var O=(typeof Q.form.id==="string")?B.config.doc.getElementById(Q.form.id):Q.form.id,M,L={action:O.getAttribute("action"),target:O.getAttribute("target")};J(P,Q);E(O,P.id,N);if(Q.data){M=D(O,Q.data);}if(Q.timeout){C(P,Q);}O.submit();B.io.start(P.id,Q);if(Q.data){F(O,M);}K(O,L);return{id:P.id,abort:function(){var R={id:P.id,status:"abort"};if(B.one("#ioupload"+P.id)){G(P.id);B.io.complete(R,Q);B.io.end(R,Q);}else{return false;}},isInProgress:function(){return B.one("#ioupload"+P.id)?true:false;}};}});},"3.0.0",{requires:["io-base","node-base","event-base"]}); \ No newline at end of file diff --git a/include/javascript/yui3/build/io/io-upload-iframe.js b/include/javascript/yui3/build/io/io-upload-iframe.js new file mode 100644 index 00000000..7939efbd --- /dev/null +++ b/include/javascript/yui3/build/io/io-upload-iframe.js @@ -0,0 +1,26 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add('io-upload-iframe',function(Y){var w=Y.config.win;function _addData(f,s){var o=[],m=s.split('='),i,l;for(i=0,l=m.length-1;i');i._node.style.position='absolute';i._node.style.top='-1000px';i._node.style.left='-1000px';Y.one('body').appendChild(i);Y.on("load",function(){_handle(o,c)},'#ioupload'+o.id);} +function _handle(o,c){var d=Y.one('#ioupload'+o.id).get('contentWindow.document'),b=d.one('body'),xml=(d._node.nodeType===9),p;if(c.timeout){_clearTimeout(o.id);} +if(b){p=b.query('pre:first-child');o.c.responseText=p?p.get('innerHTML'):b.get('innerHTML');} +else if(xml){o.c.responseXML=d._node;} +Y.io.complete(o,c);Y.io.end(o,c);w.setTimeout(function(){_destroy(o.id);},0);} +function _startTimeout(o,c){Y.io._timeout[o.id]=w.setTimeout(function(){var r={id:o.id,status:'timeout'};Y.io.complete(r,c);Y.io.end(r,c);},c.timeout);} +function _clearTimeout(id){w.clearTimeout(Y.io._timeout[id]);delete Y.io._timeout[id];} +function _destroy(id){Y.Event.purgeElement('#ioupload'+id,false);Y.one('body').removeChild(Y.one('#ioupload'+id));} +Y.mix(Y.io,{_upload:function(o,uri,c){var f=(typeof c.form.id==='string')?Y.config.doc.getElementById(c.form.id):c.form.id,fields,attr={action:f.getAttribute('action'),target:f.getAttribute('target')};_create(o,c);_setAttrs(f,o.id,uri);if(c.data){fields=_addData(f,c.data);} +if(c.timeout){_startTimeout(o,c);} +f.submit();Y.io.start(o.id,c);if(c.data){_removeData(f,fields);} +_resetAttrs(f,attr);return{id:o.id,abort:function(){var r={id:o.id,status:'abort'};if(Y.one('#ioupload'+o.id)){_destroy(o.id);Y.io.complete(r,c);Y.io.end(r,c);} +else{return false;}},isInProgress:function(){return Y.one('#ioupload'+o.id)?true:false;}}}});},'3.0.0',{requires:['io-base','node-base','event-base']}); \ No newline at end of file diff --git a/include/javascript/yui3/build/io/io-xdr-min.js b/include/javascript/yui3/build/io/io-xdr-min.js new file mode 100644 index 00000000..eee74218 --- /dev/null +++ b/include/javascript/yui3/build/io/io-xdr-min.js @@ -0,0 +1,8 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add("io-xdr",function(A){var I="io:xdrReady",D={},E={};function F(J,M){var K=''+''+''+''+"",L=document.createElement("div");document.body.appendChild(L);L.innerHTML=K;}function G(J,K){J.c.onprogress=function(){E[J.id]=3;};J.c.onload=function(){E[J.id]=4;A.io.xdrResponse(J,K,"success");};J.c.onerror=function(){E[J.id]=4;A.io.xdrResponse(J,K,"failure");};if(K.timeout){J.c.ontimeout=function(){E[J.id]=4;A.io.xdrResponse(J,K,"timeout");};J.c.timeout=K.timeout;}}function B(M,K,N){var L,J;if(!M.status){L=K?decodeURI(M.c.responseText):M.c.responseText;J=N?A.DataType.XML.parse(L):null;return{id:M.id,c:{responseText:L,responseXML:J}};}else{return{id:M.id,status:M.status};}}function H(J,K){return K.xdr.use==="flash"?J.c.abort(J.id,K):J.c.abort();}function C(K,J){return(J==="flash"&&K.c)?K.c.isInProgress(K.id):E[K.id]!==4;}A.mix(A.io,{_transport:{},xdr:function(J,K,L){if(L.on&&L.xdr.use==="flash"){D[K.id]={on:L.on,context:L.context,arguments:L.arguments};L.context=null;L.form=null;K.c.send(J,L,K.id);}else{if(window.XDomainRequest){G(K,L);K.c.open(L.method||"GET",J);K.c.send(L.data);}}return{id:K.id,abort:function(){return K.c?H(K,L):false;},isInProgress:function(){return K.c?C(K,L.xdr.use):false;}};},xdrResponse:function(N,P,M){var J,L,K=P.xdr.use==="flash"?true:false,O=P.xdr.dataType==="xml"?true:false;P.on=P.on||{};if(K){J=D||{};L=J[N.id]?J[N.id]:null;if(L){P.on=L.on;P.context=L.context;P.arguments=L.arguments;}}if(M===("abort"||"timeout")){N.status=M;}switch(M){case"start":A.io.start(N.id,P);break;case"success":A.io.success(B(N,K,O),P);K?delete J[N.id]:delete E[N.id];break;case"timeout":case"abort":case"failure":A.io.failure(B(N,K,O),P);K?delete J[N.id]:delete E[N.id];break;}},xdrReady:function(J){A.fire(I,J);},transport:function(J){var K=J.yid?J.yid:A.id;F(J.src,K);this._transport.flash=A.config.doc.getElementById("yuiIoSwf");}});},"3.0.0",{requires:["io-base","datatype-xml"]}); \ No newline at end of file diff --git a/include/javascript/yui3/build/io/io-xdr.js b/include/javascript/yui3/build/io/io-xdr.js new file mode 100644 index 00000000..41f147d9 --- /dev/null +++ b/include/javascript/yui3/build/io/io-xdr.js @@ -0,0 +1,20 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add('io-xdr',function(Y){var E_XDR_READY='io:xdrReady',_fn={},_rS={};function _swf(uri,yid){var o=''+''+''+''+'',c=document.createElement('div');document.body.appendChild(c);c.innerHTML=o;} +function _xdr(o,c){o.c.onprogress=function(){_rS[o.id]=3;} +o.c.onload=function(){_rS[o.id]=4;Y.io.xdrResponse(o,c,'success');};o.c.onerror=function(){_rS[o.id]=4;Y.io.xdrResponse(o,c,'failure');};if(c.timeout){o.c.ontimeout=function(){_rS[o.id]=4;Y.io.xdrResponse(o,c,'timeout');};o.c.timeout=c.timeout;}} +function _data(o,isFlash,isXML){var text,xml;if(!o.status){text=isFlash?decodeURI(o.c.responseText):o.c.responseText;xml=isXML?Y.DataType.XML.parse(text):null;return{id:o.id,c:{responseText:text,responseXML:xml}};} +else{return{id:o.id,status:o.status};}} +function _abort(o,c){return c.xdr.use==='flash'?o.c.abort(o.id,c):o.c.abort();} +function _isInProgress(o,t){return(t==='flash'&&o.c)?o.c.isInProgress(o.id):_rS[o.id]!==4;} +Y.mix(Y.io,{_transport:{},xdr:function(uri,o,c){if(c.on&&c.xdr.use==='flash'){_fn[o.id]={on:c.on,context:c.context,arguments:c.arguments};c.context=null;c.form=null;o.c.send(uri,c,o.id);} +else if(window.XDomainRequest){_xdr(o,c);o.c.open(c.method||'GET',uri);o.c.send(c.data);} +return{id:o.id,abort:function(){return o.c?_abort(o,c):false;},isInProgress:function(){return o.c?_isInProgress(o,c.xdr.use):false;}}},xdrResponse:function(o,c,e){var m,fn,isFlash=c.xdr.use==='flash'?true:false,isXML=c.xdr.dataType==='xml'?true:false;c.on=c.on||{};if(isFlash){m=_fn||{};fn=m[o.id]?m[o.id]:null;if(fn){c.on=fn.on;c.context=fn.context;c.arguments=fn.arguments;}} +if(e===('abort'||'timeout')){o.status=e;} +switch(e){case'start':Y.io.start(o.id,c);break;case'success':Y.io.success(_data(o,isFlash,isXML),c);isFlash?delete m[o.id]:delete _rS[o.id];break;case'timeout':case'abort':case'failure':Y.io.failure(_data(o,isFlash,isXML),c);isFlash?delete m[o.id]:delete _rS[o.id];break;}},xdrReady:function(id){Y.fire(E_XDR_READY,id);},transport:function(o){var id=o.yid?o.yid:Y.id;_swf(o.src,id);this._transport.flash=Y.config.doc.getElementById('yuiIoSwf');}});},'3.0.0',{requires:['io-base','datatype-xml']}); \ No newline at end of file diff --git a/include/javascript/yui3/build/io/io.js b/include/javascript/yui3/build/io/io.js new file mode 100644 index 00000000..e8bc7079 --- /dev/null +++ b/include/javascript/yui3/build/io/io.js @@ -0,0 +1,98 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add('io-base',function(Y){var E_START='io:start',E_COMPLETE='io:complete',E_SUCCESS='io:success',E_FAILURE='io:failure',E_END='io:end',transactionId=0,_headers={'X-Requested-With':'XMLHttpRequest'},_timeout={},w=Y.config.win;function _io(uri,c,i){var f,o,m;c=c||{};o=_create(c.xdr||c.form,i);m=c.method?c.method.toUpperCase():'GET';if(c.form){if(c.form.upload){return Y.io._upload(o,uri,c);} +else{f=Y.io._serialize(c.form,c.data);if(m==='POST'){c.data=f;_setHeader('Content-Type','application/x-www-form-urlencoded');} +else if(m==='GET'){uri=_concat(uri,f);}}} +else if(c.data&&m==='GET'){uri=_concat(uri,c.data);} +if(c.xdr){if(c.xdr.use==='native'&&window.XDomainRequest||c.xdr.use==='flash'){return Y.io.xdr(uri,o,c);} +if(c.xdr.credentials){o.c.withCredentials=true;}} +o.c.onreadystatechange=function(){_readyState(o,c);};try{o.c.open(m,uri,true);} +catch(e0){if(c.xdr){return _resend(o,uri,c);}} +if(c.data&&m==='POST'){_setHeader('Content-Type','application/x-www-form-urlencoded; charset=UTF-8');} +_setHeaders(o.c,c.headers||{});try{o.c.send(c.data||'');} +catch(e1){if(c.xdr){return _resend(o,uri,c);}} +_ioStart(o.id,c);if(c.timeout){_startTimeout(o,c.timeout);} +return{id:o.id,abort:function(){return o.c?_ioCancel(o,'abort'):false;},isInProgress:function(){return o.c?o.c.readyState!==4&&o.c.readyState!==0:false;}}} +function _subscribe(e,c){var evt=new Y.EventTarget().publish('transaction:'+e);evt.subscribe(c.on[e],(c.context||Y),c.arguments);return evt;} +function _ioStart(id,c){var evt;c.on=c.on||{};Y.fire(E_START,id);if(c.on.start){evt=_subscribe('start',c);evt.fire(id);}} +function _ioComplete(o,c){var evt,r=o.status?{status:0,statusText:o.status}:o.c;c.on=c.on||{};Y.fire(E_COMPLETE,o.id,r);if(c.on.complete){evt=_subscribe('complete',c);evt.fire(o.id,r);}} +function _ioSuccess(o,c){var evt;c.on=c.on||{};Y.fire(E_SUCCESS,o.id,o.c);if(c.on.success){evt=_subscribe('success',c);evt.fire(o.id,o.c);} +_ioEnd(o,c);} +function _ioFailure(o,c){var evt,r=o.status?{status:0,statusText:o.status}:o.c;c.on=c.on||{};Y.fire(E_FAILURE,o.id,r);if(c.on.failure){evt=_subscribe('failure',c);evt.fire(o.id,r);} +_ioEnd(o,c);} +function _ioEnd(o,c){var evt;c.on=c.on||{};Y.fire(E_END,o.id);if(c.on.end){evt=_subscribe('end',c);evt.fire(o.id);} +_destroy(o,c.xdr?true:false);} +function _ioCancel(o,s){if(o&&o.c){o.status=s;o.c.abort();}} +function _resend(o,uri,c){var id=parseInt(o.id);_destroy(o);c.xdr.use='flash';return Y.io(uri,c,id);} +function _id(){var id=transactionId;transactionId++;return id;} +function _create(c,i){var o={};o.id=Y.Lang.isNumber(i)?i:_id();c=c||{};if(!c.use&&!c.upload){o.c=_xhr();} +else if(c.use){if(c.use==='flash'){o.c=Y.io._transport[c.use];} +else if(c.use==='native'&&window.XDomainRequest){o.c=new XDomainRequest();} +else{o.c=_xhr();}} +else{o.c={};} +return o;};function _xhr(){return w.XMLHttpRequest?new XMLHttpRequest():new ActiveXObject('Microsoft.XMLHTTP');} +function _concat(s,d){s+=((s.indexOf('?')==-1)?'?':'&')+d;return s;} +function _setHeader(l,v){if(v){_headers[l]=v;} +else{delete _headers[l];}} +function _setHeaders(o,h){var p;for(p in _headers){if(_headers.hasOwnProperty(p)){if(h[p]){break;} +else{h[p]=_headers[p];}}} +for(p in h){if(h.hasOwnProperty(p)){o.setRequestHeader(p,h[p]);}}} +function _startTimeout(o,timeout){_timeout[o.id]=w.setTimeout(function(){_ioCancel(o,'timeout');},timeout);} +function _clearTimeout(id){w.clearTimeout(_timeout[id]);delete _timeout[id];} +function _readyState(o,c){if(o.c.readyState===4){if(c.timeout){_clearTimeout(o.id);} +w.setTimeout(function(){_ioComplete(o,c);_handleResponse(o,c);},0);}} +function _handleResponse(o,c){var status;try{if(o.c.status&&o.c.status!==0){status=o.c.status;} +else{status=0;}} +catch(e){status=0;} +if(status>=200&&status<300||status===1223){_ioSuccess(o,c);} +else{_ioFailure(o,c);}} +function _destroy(o,transport){if(w.XMLHttpRequest&&!transport){if(o.c){o.c.onreadystatechange=null;}} +o.c=null;o=null;} +_io.start=_ioStart;_io.complete=_ioComplete;_io.success=_ioSuccess;_io.failure=_ioFailure;_io.end=_ioEnd;_io._id=_id;_io._timeout=_timeout;_io.header=_setHeader;Y.io=_io;Y.io.http=_io;},'3.0.0',{requires:['event-custom-base']});YUI.add('io-form',function(Y){Y.mix(Y.io,{_serialize:function(c,s){var eUC=encodeURIComponent,data=[],useDf=c.useDisabled||false,item=0,id=(typeof c.id==='string')?c.id:c.id.getAttribute('id'),e,f,n,v,d,i,il,j,jl,o;if(!id){id=Y.guid('io:');c.id.setAttribute('id',id);} +f=Y.config.doc.getElementById(id);for(i=0,il=f.elements.length;i-1){o=e.options[e.selectedIndex];data[item++]=n+eUC((o.attributes.value&&o.attributes.value.specified)?o.value:o.text);} +break;case'select-multiple':if(e.selectedIndex>-1){for(j=e.selectedIndex,jl=e.options.length;j'+''+''+''+'',c=document.createElement('div');document.body.appendChild(c);c.innerHTML=o;} +function _xdr(o,c){o.c.onprogress=function(){_rS[o.id]=3;} +o.c.onload=function(){_rS[o.id]=4;Y.io.xdrResponse(o,c,'success');};o.c.onerror=function(){_rS[o.id]=4;Y.io.xdrResponse(o,c,'failure');};if(c.timeout){o.c.ontimeout=function(){_rS[o.id]=4;Y.io.xdrResponse(o,c,'timeout');};o.c.timeout=c.timeout;}} +function _data(o,isFlash,isXML){var text,xml;if(!o.status){text=isFlash?decodeURI(o.c.responseText):o.c.responseText;xml=isXML?Y.DataType.XML.parse(text):null;return{id:o.id,c:{responseText:text,responseXML:xml}};} +else{return{id:o.id,status:o.status};}} +function _abort(o,c){return c.xdr.use==='flash'?o.c.abort(o.id,c):o.c.abort();} +function _isInProgress(o,t){return(t==='flash'&&o.c)?o.c.isInProgress(o.id):_rS[o.id]!==4;} +Y.mix(Y.io,{_transport:{},xdr:function(uri,o,c){if(c.on&&c.xdr.use==='flash'){_fn[o.id]={on:c.on,context:c.context,arguments:c.arguments};c.context=null;c.form=null;o.c.send(uri,c,o.id);} +else if(window.XDomainRequest){_xdr(o,c);o.c.open(c.method||'GET',uri);o.c.send(c.data);} +return{id:o.id,abort:function(){return o.c?_abort(o,c):false;},isInProgress:function(){return o.c?_isInProgress(o,c.xdr.use):false;}}},xdrResponse:function(o,c,e){var m,fn,isFlash=c.xdr.use==='flash'?true:false,isXML=c.xdr.dataType==='xml'?true:false;c.on=c.on||{};if(isFlash){m=_fn||{};fn=m[o.id]?m[o.id]:null;if(fn){c.on=fn.on;c.context=fn.context;c.arguments=fn.arguments;}} +if(e===('abort'||'timeout')){o.status=e;} +switch(e){case'start':Y.io.start(o.id,c);break;case'success':Y.io.success(_data(o,isFlash,isXML),c);isFlash?delete m[o.id]:delete _rS[o.id];break;case'timeout':case'abort':case'failure':Y.io.failure(_data(o,isFlash,isXML),c);isFlash?delete m[o.id]:delete _rS[o.id];break;}},xdrReady:function(id){Y.fire(E_XDR_READY,id);},transport:function(o){var id=o.yid?o.yid:Y.id;_swf(o.src,id);this._transport.flash=Y.config.doc.getElementById('yuiIoSwf');}});},'3.0.0',{requires:['io-base','datatype-xml']});YUI.add('io-upload-iframe',function(Y){var w=Y.config.win;function _addData(f,s){var o=[],m=s.split('='),i,l;for(i=0,l=m.length-1;i');i._node.style.position='absolute';i._node.style.top='-1000px';i._node.style.left='-1000px';Y.one('body').appendChild(i);Y.on("load",function(){_handle(o,c)},'#ioupload'+o.id);} +function _handle(o,c){var d=Y.one('#ioupload'+o.id).get('contentWindow.document'),b=d.one('body'),xml=(d._node.nodeType===9),p;if(c.timeout){_clearTimeout(o.id);} +if(b){p=b.query('pre:first-child');o.c.responseText=p?p.get('innerHTML'):b.get('innerHTML');} +else if(xml){o.c.responseXML=d._node;} +Y.io.complete(o,c);Y.io.end(o,c);w.setTimeout(function(){_destroy(o.id);},0);} +function _startTimeout(o,c){Y.io._timeout[o.id]=w.setTimeout(function(){var r={id:o.id,status:'timeout'};Y.io.complete(r,c);Y.io.end(r,c);},c.timeout);} +function _clearTimeout(id){w.clearTimeout(Y.io._timeout[id]);delete Y.io._timeout[id];} +function _destroy(id){Y.Event.purgeElement('#ioupload'+id,false);Y.one('body').removeChild(Y.one('#ioupload'+id));} +Y.mix(Y.io,{_upload:function(o,uri,c){var f=(typeof c.form.id==='string')?Y.config.doc.getElementById(c.form.id):c.form.id,fields,attr={action:f.getAttribute('action'),target:f.getAttribute('target')};_create(o,c);_setAttrs(f,o.id,uri);if(c.data){fields=_addData(f,c.data);} +if(c.timeout){_startTimeout(o,c);} +f.submit();Y.io.start(o.id,c);if(c.data){_removeData(f,fields);} +_resetAttrs(f,attr);return{id:o.id,abort:function(){var r={id:o.id,status:'abort'};if(Y.one('#ioupload'+o.id)){_destroy(o.id);Y.io.complete(r,c);Y.io.end(r,c);} +else{return false;}},isInProgress:function(){return Y.one('#ioupload'+o.id)?true:false;}}}});},'3.0.0',{requires:['io-base','node-base','event-base']});YUI.add('io-queue',function(Y){var _q=new Y.Queue(),_e,_activeId,_qState=1;function _queue(uri,c){var o={uri:uri,id:Y.io._id(),cfg:c};_q.add(o);if(_qState===1){_shift();} +return o;} +function _shift(){var o=_q.next();_activeId=o.id;_qState=0;Y.io(o.uri,o.cfg,o.id);} +function _unshift(o){_q.promote(o);} +function _next(id){_qState=1;if(_activeId===id&&_q.size()>0){_shift();}} +function _remove(o){_q.remove(o);} +function _start(){_qState=1;if(_q.size()>0){_shift();}} +function _stop(){_qState=0;};function _size(){return _q.size();};_e=Y.on('io:complete',function(id){_next(id);},Y.io);_queue.size=_size;_queue.start=_start;_queue.stop=_stop;_queue.promote=_unshift;_queue.remove=_remove;Y.mix(Y.io,{queue:_queue},true);},'3.0.0',{requires:['io-base','queue-promote']});YUI.add('io',function(Y){},'3.0.0',{use:['io-base','io-form','io-xdr','io-upload-iframe','io-queue']}); \ No newline at end of file diff --git a/include/javascript/yui3/build/io/io.swf b/include/javascript/yui3/build/io/io.swf new file mode 100644 index 0000000000000000000000000000000000000000..61f03e76bec3e63ed27549c5c5830f00bda2a013 GIT binary patch literal 2829 zcmV+o3-a_sS5pbj5dZ*q+I?4DP#f13zGwgLt|UN+AKL;O*~TW=0ttxi7~2F47_h;z zF~mPXMyu5>k}b5#?g~TGnbJ&>PLk=*w4Jn*rqhSCO*^gIPSQTN?|m`yG`G*H zIbU!GadoLH>v_e&SnScGN4<{*dTnPZ)_4B=`B=O^*5BWQ7Cr7-!P8fJ3hwc)p$fp5 z=^9S1=;iD}gs=6qUGgq)w!F zEar2D&f#LKJ#N-E9zN1n%pNPRyV;AeXNG)_m-F)G&`8Ekn~^Jdb2Ty$8F{w9VqG=i z#+heChjzKC^WD9My&Nk#cBW(?Ckvq}n|E*F5XDkDpL4UOGgK-(EZC2#M?8~q8^bYm z&)#dXE#vyUURWyWOXkq{^@?t1UE!#E=uc@W(swQz>5s?HS7~tR#n`@R*Cd$0Au<;H zw|J3^3h#gV`8}VA8CLLL6#p9{l}|zW=jr2^@h3j?b8)SdTP%6G{9?`~e{KGtfe=&? z%h8w3J`yCoe8<})gr>b{+RIG`b9O9eODlFRqulbGTwzH`q#u}uCzWyquX(?zYZfx{ zTyEKP0+qb=nkzin@;LtrOeMx0$95_UU&X32^;b?BWc_5A}@?U%~yKaw)3W5XnzjCohsaL>?H@!*Qzlsn4WKbc6!!)t7N)f z_luxi)2o?GntBEU@DlnwZ+Ou=UYsb`bL_RiZoQDR>#Bsf6M212xrOGQ*{}~p!QjOn;G$7`xtKRSGqBsmhJ7W`_?#CKFGnqJ^Tmu_)OKP|Yb3QDcW5p8;@VWk z&yTFh)$OP^>?;vkD+O&Q<$>Lm_R8qsLdINKK<5S)T*p|**$cXR0sZBo1@7;KoZYLt zpi7Qzd%h~mse)zuiaNiM9-@eAxr|yd>+BymTI*fU`qs#;ff)9Rv$1q3m-ljo<~=bU ztj4%=uW+pTUA@GkHuiLkq0_O~XsUpx>lptPvufD(5|H-YH+^v5wUkF3M_;S2nXDpg zLC-gi*Cv&7EZs2u7`stDpHJ(?Ls{pE@ZX)E>gCUbwK?05Ay~~gvzXO2$v`u)#%W^PQ6&y6466O8>$Du`}YMB7`{sl?*=>}+DT zer{@Je0Fggrm0$Odu_4ki*~^^1KX2145(%n3_D}a&rT^wZprkhTP;WGlnMpx*OKem zMR2KAEqw)j@Jg<1yg&T!DI3<`Qm{i>ZS0p@KE^m@Njq}d^s$)j;U#(UIk6|`Dvi8z9HBc zN>C6fNEBoW3Ke`*@KYf`MU@H-6b?`+Oyv%$9Hr`U3Y}CvLE$7-yQumKg>I^zqUvd? zMyc9Ep_i&Ls>Z3>N7a6+4p8+~s-B_n8in%|2DJ-7VU#wFQ@BFmDwS?&b3mmxD9lrs z({7{owsr@!yU>QyB!&CbcZ2$FQqXC$K_NrI)b4?1fwlnJ3~1A!y@{4N3J)mcDJ*Mm zftCkt8BtvdCF)nHxf+EXW^-Kpk8m%t9=bRu<#PmkdAWU7%*J8(Lg3P-0l60b-s zf(Hp|K=XYn;z`Gz#3SpfK_l-O>Ly$x$2MUaaF`KrxGo;wgoM<&2{+^un{ZP(xe2qh ziycpPU+pIA-G;I&DSu9u^Be=DNPLT()}k80!!IoUdO^HgQQj(Il`l<%k|< zXM^u@#cN5mZ1r`*RaM{~u=BxX6bG{idMd3N{^%S#o%V>ao1G-Okf!sZ-p_`Tp|p~wiIBivPe#%bP9p*v#)+I505+05l2#H& zfL%`05Eca+MT1uf8^) z>Ox$14RzO&2T_+eD4<3WBwye<3MZb#Z=d=)z6mK|!i0@wFrmCGV4BGUrWq#K!Ad<6KQ-q45<{LtB;t673CkYOg zU^g~WvUM&MOuQzrn;R*`I-jcN^VxC;!_01#Q`8zvwQfSOy_{ilX`62gI;A#v-v02ynP5;IJev zA*7T=$fdG16ulSCCPy}`%U17|5txU{#gJGwEtT=8hx{l*W)D&=<;qzSp7rqQ%Bhe{ zNcU4~bR~oZ$nsAUV}#ksb}SeqQA{2{>%;+IZy_DOL^a>vI31VY;}eF$Ik}vZ%Q?B6 zleY;4sf5Jj6(r`Bxv!i^)MlmkkiaUY#&D3ui|e*h4s5oaWyShTvgb6fNm(4kM96F5|Cug_YrsG1E^;G1K5On zz{e%wLmbbE9|6+;5H_O4=mZbt*X$#BT8>Usz$NxwsMSPboUrfJ7MGBjADPuw)|Hh| z9rFABwmLCE*bg}?iL?3e!~95H#Tw?kK@KK zYA${O>`O=<-bfq<_Gj+jgZ^&z7j7C7@OgInNgR!XCP|6$)U|kOI-Z(|r>@6Sb@+FO f9Ikw_0kq*;nw$7De)rFzUi^_hjI#d$ohNTc$B~AH literal 0 HcmV?d00001 diff --git a/include/javascript/yui3/build/json/json-min.js b/include/javascript/yui3/build/json/json-min.js new file mode 100644 index 00000000..103a07d9 --- /dev/null +++ b/include/javascript/yui3/build/json/json-min.js @@ -0,0 +1,8 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add("json-parse",function(Y){var _JSON=Y.config.win.JSON,Native=(Object.prototype.toString.call(_JSON)==="[object JSON]"&&_JSON),_UNICODE_EXCEPTIONS=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,_ESCAPES=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,_VALUES=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,_BRACKETS=/(?:^|:|,)(?:\s*\[)+/g,_UNSAFE=/[^\],:{}\s]/,_escapeException=function(c){return"\\u"+("0000"+(+(c.charCodeAt(0))).toString(16)).slice(-4);},_revive=function(data,reviver){var walk=function(o,key){var k,v,value=o[key];if(value&&typeof value==="object"){for(k in value){if(value.hasOwnProperty(k)){v=walk(value,k);if(v===undefined){delete value[k];}else{value[k]=v;}}}}return reviver.call(o,key,value);};return typeof reviver==="function"?walk({"":data},""):data;},_parse=function(s,reviver){if(typeof s==="string"){s=s.replace(_UNICODE_EXCEPTIONS,_escapeException);if(!_UNSAFE.test(s.replace(_ESCAPES,"@").replace(_VALUES,"]").replace(_BRACKETS,""))){return _revive(eval("("+s+")"),reviver);}}throw new SyntaxError("JSON.parse");};Y.namespace("JSON").parse=function(s,reviver){return Native&&Y.JSON.useNativeParse?Native.parse(s,reviver):_parse(s,reviver);};Y.JSON.useNativeParse=!!Native;},"3.0.0");YUI.add("json-stringify",function(C){var b=C.config.win.JSON,E=C.Lang,A=E.isFunction,L=E.isObject,N=E.isArray,X=Object.prototype.toString,W=(X.call(b)==="[object JSON]"&&b),h="undefined",O="object",e="null",R="string",U="number",Q="boolean",D="date",H={"undefined":h,"string":R,"[object String]":R,"number":U,"[object Number]":U,"boolean":Q,"[object Boolean]":Q,"[object Date]":D,"[object RegExp]":O},i="",g="{",G="}",F="[",V="]",T=",",K=",\n",B="\n",I=":",f=": ",M='"',Z=/[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,a={"\b":"\\b","\t":"\\t","\n":"\\n","\f":"\\f","\r":"\\r",'"':'\\"',"\\":"\\\\"};function c(j){var Y=typeof j;return H[Y]||H[X.call(j)]||(Y===O?(j?O:e):h);}function P(Y){if(!a[Y]){a[Y]="\\u"+("0000"+(+(Y.charCodeAt(0))).toString(16)).slice(-4);}return a[Y];}function J(Y){return M+Y.replace(Z,P)+M;}function d(Y,j){return Y.replace(/^/gm,j);}function S(j,s,Y){if(j===undefined){return undefined;}var l=A(s)?s:null,r=X.call(Y).match(/String|Number/)||[],t=C.JSON.dateToString,q=[],n,m,p;if(l||!N(s)){s=undefined;}if(s){n={};for(m=0,p=s.length;m=0;--u){if(q[u]===AA){throw new Error("JSON.stringify. Cyclical reference");}}x=N(AA);q.push(AA);if(x){for(u=AA.length-1;u>=0;--u){z[u]=k(AA,u)||e;}}else{AD=s||AA;u=0;for(o in AD){if(AD.hasOwnProperty(o)){AB=k(AA,o);if(AB){z[u++]=J(o)+y+AB;}}}}q.pop();if(Y&&z.length){return x?F+B+d(z.join(K),Y)+B+V:g+B+d(z.join(K),Y)+B+G;}else{return x?F+z.join(T)+V:g+z.join(T)+G;}}return k({"":j},"");}C.mix(C.namespace("JSON"),{useNativeStringify:!!W,dateToString:function(j){function Y(k){return k<10?"0"+k:k;}return j.getUTCFullYear()+"-"+Y(j.getUTCMonth()+1)+"-"+Y(j.getUTCDate())+"T"+Y(j.getUTCHours())+I+Y(j.getUTCMinutes())+I+Y(j.getUTCSeconds())+"Z";},stringify:function(k,Y,j){return W&&C.JSON.useNativeStringify?W.stringify(k,Y,j):S(k,Y,j);}});},"3.0.0");YUI.add("json",function(A){},"3.0.0",{use:["json-parse","json-stringify"]}); \ No newline at end of file diff --git a/include/javascript/yui3/build/json/json-parse-min.js b/include/javascript/yui3/build/json/json-parse-min.js new file mode 100644 index 00000000..c56ed3b1 --- /dev/null +++ b/include/javascript/yui3/build/json/json-parse-min.js @@ -0,0 +1,8 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add("json-parse",function(Y){var _JSON=Y.config.win.JSON,Native=(Object.prototype.toString.call(_JSON)==="[object JSON]"&&_JSON),_UNICODE_EXCEPTIONS=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,_ESCAPES=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,_VALUES=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,_BRACKETS=/(?:^|:|,)(?:\s*\[)+/g,_UNSAFE=/[^\],:{}\s]/,_escapeException=function(c){return"\\u"+("0000"+(+(c.charCodeAt(0))).toString(16)).slice(-4);},_revive=function(data,reviver){var walk=function(o,key){var k,v,value=o[key];if(value&&typeof value==="object"){for(k in value){if(value.hasOwnProperty(k)){v=walk(value,k);if(v===undefined){delete value[k];}else{value[k]=v;}}}}return reviver.call(o,key,value);};return typeof reviver==="function"?walk({"":data},""):data;},_parse=function(s,reviver){if(typeof s==="string"){s=s.replace(_UNICODE_EXCEPTIONS,_escapeException);if(!_UNSAFE.test(s.replace(_ESCAPES,"@").replace(_VALUES,"]").replace(_BRACKETS,""))){return _revive(eval("("+s+")"),reviver);}}throw new SyntaxError("JSON.parse");};Y.namespace("JSON").parse=function(s,reviver){return Native&&Y.JSON.useNativeParse?Native.parse(s,reviver):_parse(s,reviver);};Y.JSON.useNativeParse=!!Native;},"3.0.0"); \ No newline at end of file diff --git a/include/javascript/yui3/build/json/json-parse.js b/include/javascript/yui3/build/json/json-parse.js new file mode 100644 index 00000000..5a2bc36a --- /dev/null +++ b/include/javascript/yui3/build/json/json-parse.js @@ -0,0 +1,10 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add('json-parse',function(Y){var _JSON=Y.config.win.JSON,Native=(Object.prototype.toString.call(_JSON)==='[object JSON]'&&_JSON),_UNICODE_EXCEPTIONS=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,_ESCAPES=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,_VALUES=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,_BRACKETS=/(?:^|:|,)(?:\s*\[)+/g,_UNSAFE=/[^\],:{}\s]/,_escapeException=function(c){return'\\u'+('0000'+(+(c.charCodeAt(0))).toString(16)).slice(-4);},_revive=function(data,reviver){var walk=function(o,key){var k,v,value=o[key];if(value&&typeof value==='object'){for(k in value){if(value.hasOwnProperty(k)){v=walk(value,k);if(v===undefined){delete value[k];}else{value[k]=v;}}}} +return reviver.call(o,key,value);};return typeof reviver==='function'?walk({'':data},''):data;},_parse=function(s,reviver){if(typeof s==='string'){s=s.replace(_UNICODE_EXCEPTIONS,_escapeException);if(!_UNSAFE.test(s.replace(_ESCAPES,'@').replace(_VALUES,']').replace(_BRACKETS,''))){return _revive(eval('('+s+')'),reviver);}} +throw new SyntaxError('JSON.parse');};Y.namespace('JSON').parse=function(s,reviver){return Native&&Y.JSON.useNativeParse?Native.parse(s,reviver):_parse(s,reviver);};Y.JSON.useNativeParse=!!Native;},'3.0.0'); \ No newline at end of file diff --git a/include/javascript/yui3/build/json/json-stringify-min.js b/include/javascript/yui3/build/json/json-stringify-min.js new file mode 100644 index 00000000..c1944584 --- /dev/null +++ b/include/javascript/yui3/build/json/json-stringify-min.js @@ -0,0 +1,8 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add("json-stringify",function(C){var b=C.config.win.JSON,E=C.Lang,A=E.isFunction,L=E.isObject,N=E.isArray,X=Object.prototype.toString,W=(X.call(b)==="[object JSON]"&&b),h="undefined",O="object",e="null",R="string",U="number",Q="boolean",D="date",H={"undefined":h,"string":R,"[object String]":R,"number":U,"[object Number]":U,"boolean":Q,"[object Boolean]":Q,"[object Date]":D,"[object RegExp]":O},i="",g="{",G="}",F="[",V="]",T=",",K=",\n",B="\n",I=":",f=": ",M='"',Z=/[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,a={"\b":"\\b","\t":"\\t","\n":"\\n","\f":"\\f","\r":"\\r",'"':'\\"',"\\":"\\\\"};function c(j){var Y=typeof j;return H[Y]||H[X.call(j)]||(Y===O?(j?O:e):h);}function P(Y){if(!a[Y]){a[Y]="\\u"+("0000"+(+(Y.charCodeAt(0))).toString(16)).slice(-4);}return a[Y];}function J(Y){return M+Y.replace(Z,P)+M;}function d(Y,j){return Y.replace(/^/gm,j);}function S(j,s,Y){if(j===undefined){return undefined;}var l=A(s)?s:null,r=X.call(Y).match(/String|Number/)||[],t=C.JSON.dateToString,q=[],n,m,p;if(l||!N(s)){s=undefined;}if(s){n={};for(m=0,p=s.length;m=0;--u){if(q[u]===AA){throw new Error("JSON.stringify. Cyclical reference");}}x=N(AA);q.push(AA);if(x){for(u=AA.length-1;u>=0;--u){z[u]=k(AA,u)||e;}}else{AD=s||AA;u=0;for(o in AD){if(AD.hasOwnProperty(o)){AB=k(AA,o);if(AB){z[u++]=J(o)+y+AB;}}}}q.pop();if(Y&&z.length){return x?F+B+d(z.join(K),Y)+B+V:g+B+d(z.join(K),Y)+B+G;}else{return x?F+z.join(T)+V:g+z.join(T)+G;}}return k({"":j},"");}C.mix(C.namespace("JSON"),{useNativeStringify:!!W,dateToString:function(j){function Y(k){return k<10?"0"+k:k;}return j.getUTCFullYear()+"-"+Y(j.getUTCMonth()+1)+"-"+Y(j.getUTCDate())+"T"+Y(j.getUTCHours())+I+Y(j.getUTCMinutes())+I+Y(j.getUTCSeconds())+"Z";},stringify:function(k,Y,j){return W&&C.JSON.useNativeStringify?W.stringify(k,Y,j):S(k,Y,j);}});},"3.0.0"); \ No newline at end of file diff --git a/include/javascript/yui3/build/json/json-stringify.js b/include/javascript/yui3/build/json/json-stringify.js new file mode 100644 index 00000000..708f8559 --- /dev/null +++ b/include/javascript/yui3/build/json/json-stringify.js @@ -0,0 +1,31 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add('json-stringify',function(Y){var _JSON=Y.config.win.JSON,Lang=Y.Lang,isFunction=Lang.isFunction,isObject=Lang.isObject,isArray=Lang.isArray,_toStr=Object.prototype.toString,Native=(_toStr.call(_JSON)==='[object JSON]'&&_JSON),UNDEFINED='undefined',OBJECT='object',NULL='null',STRING='string',NUMBER='number',BOOLEAN='boolean',DATE='date',_allowable={'undefined':UNDEFINED,'string':STRING,'[object String]':STRING,'number':NUMBER,'[object Number]':NUMBER,'boolean':BOOLEAN,'[object Boolean]':BOOLEAN,'[object Date]':DATE,'[object RegExp]':OBJECT},EMPTY='',OPEN_O='{',CLOSE_O='}',OPEN_A='[',CLOSE_A=']',COMMA=',',COMMA_CR=",\n",CR="\n",COLON=':',COLON_SP=': ',QUOTE='"',_SPECIAL_CHARS=/[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,_CHARS={'\b':'\\b','\t':'\\t','\n':'\\n','\f':'\\f','\r':'\\r','"':'\\"','\\':'\\\\'};function _type(o){var t=typeof o;return _allowable[t]||_allowable[_toStr.call(o)]||(t===OBJECT?(o?OBJECT:NULL):UNDEFINED);} +function _char(c){if(!_CHARS[c]){_CHARS[c]='\\u'+('0000'+(+(c.charCodeAt(0))).toString(16)).slice(-4);} +return _CHARS[c];} +function _string(s){return QUOTE+s.replace(_SPECIAL_CHARS,_char)+QUOTE;} +function _indent(s,space){return s.replace(/^/gm,space);} +function _stringify(o,w,space){if(o===undefined){return undefined;} +var replacer=isFunction(w)?w:null,format=_toStr.call(space).match(/String|Number/)||[],_date=Y.JSON.dateToString,stack=[],tmp,i,len;if(replacer||!isArray(w)){w=undefined;} +if(w){tmp={};for(i=0,len=w.length;i=0;--i){if(stack[i]===value){throw new Error("JSON.stringify. Cyclical reference");}} +arr=isArray(value);stack.push(value);if(arr){for(i=value.length-1;i>=0;--i){a[i]=_serialize(value,i)||NULL;}}else{keys=w||value;i=0;for(k in keys){if(keys.hasOwnProperty(k)){v=_serialize(value,k);if(v){a[i++]=_string(k)+colon+v;}}}} +stack.pop();if(space&&a.length){return arr?OPEN_A+CR+_indent(a.join(COMMA_CR),space)+CR+CLOSE_A:OPEN_O+CR+_indent(a.join(COMMA_CR),space)+CR+CLOSE_O;}else{return arr?OPEN_A+a.join(COMMA)+CLOSE_A:OPEN_O+a.join(COMMA)+CLOSE_O;}} +return _serialize({'':o},'');} +Y.mix(Y.namespace('JSON'),{useNativeStringify:!!Native,dateToString:function(d){function _zeroPad(v){return v<10?'0'+v:v;} +return d.getUTCFullYear()+'-'+ +_zeroPad(d.getUTCMonth()+1)+'-'+ +_zeroPad(d.getUTCDate())+'T'+ +_zeroPad(d.getUTCHours())+COLON+ +_zeroPad(d.getUTCMinutes())+COLON+ +_zeroPad(d.getUTCSeconds())+'Z';},stringify:function(o,w,ind){return Native&&Y.JSON.useNativeStringify?Native.stringify(o,w,ind):_stringify(o,w,ind);}});},'3.0.0'); \ No newline at end of file diff --git a/include/javascript/yui3/build/json/json.js b/include/javascript/yui3/build/json/json.js new file mode 100644 index 00000000..7cd31654 --- /dev/null +++ b/include/javascript/yui3/build/json/json.js @@ -0,0 +1,33 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add('json-parse',function(Y){var _JSON=Y.config.win.JSON,Native=(Object.prototype.toString.call(_JSON)==='[object JSON]'&&_JSON),_UNICODE_EXCEPTIONS=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,_ESCAPES=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,_VALUES=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,_BRACKETS=/(?:^|:|,)(?:\s*\[)+/g,_UNSAFE=/[^\],:{}\s]/,_escapeException=function(c){return'\\u'+('0000'+(+(c.charCodeAt(0))).toString(16)).slice(-4);},_revive=function(data,reviver){var walk=function(o,key){var k,v,value=o[key];if(value&&typeof value==='object'){for(k in value){if(value.hasOwnProperty(k)){v=walk(value,k);if(v===undefined){delete value[k];}else{value[k]=v;}}}} +return reviver.call(o,key,value);};return typeof reviver==='function'?walk({'':data},''):data;},_parse=function(s,reviver){if(typeof s==='string'){s=s.replace(_UNICODE_EXCEPTIONS,_escapeException);if(!_UNSAFE.test(s.replace(_ESCAPES,'@').replace(_VALUES,']').replace(_BRACKETS,''))){return _revive(eval('('+s+')'),reviver);}} +throw new SyntaxError('JSON.parse');};Y.namespace('JSON').parse=function(s,reviver){return Native&&Y.JSON.useNativeParse?Native.parse(s,reviver):_parse(s,reviver);};Y.JSON.useNativeParse=!!Native;},'3.0.0');YUI.add('json-stringify',function(Y){var _JSON=Y.config.win.JSON,Lang=Y.Lang,isFunction=Lang.isFunction,isObject=Lang.isObject,isArray=Lang.isArray,_toStr=Object.prototype.toString,Native=(_toStr.call(_JSON)==='[object JSON]'&&_JSON),UNDEFINED='undefined',OBJECT='object',NULL='null',STRING='string',NUMBER='number',BOOLEAN='boolean',DATE='date',_allowable={'undefined':UNDEFINED,'string':STRING,'[object String]':STRING,'number':NUMBER,'[object Number]':NUMBER,'boolean':BOOLEAN,'[object Boolean]':BOOLEAN,'[object Date]':DATE,'[object RegExp]':OBJECT},EMPTY='',OPEN_O='{',CLOSE_O='}',OPEN_A='[',CLOSE_A=']',COMMA=',',COMMA_CR=",\n",CR="\n",COLON=':',COLON_SP=': ',QUOTE='"',_SPECIAL_CHARS=/[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,_CHARS={'\b':'\\b','\t':'\\t','\n':'\\n','\f':'\\f','\r':'\\r','"':'\\"','\\':'\\\\'};function _type(o){var t=typeof o;return _allowable[t]||_allowable[_toStr.call(o)]||(t===OBJECT?(o?OBJECT:NULL):UNDEFINED);} +function _char(c){if(!_CHARS[c]){_CHARS[c]='\\u'+('0000'+(+(c.charCodeAt(0))).toString(16)).slice(-4);} +return _CHARS[c];} +function _string(s){return QUOTE+s.replace(_SPECIAL_CHARS,_char)+QUOTE;} +function _indent(s,space){return s.replace(/^/gm,space);} +function _stringify(o,w,space){if(o===undefined){return undefined;} +var replacer=isFunction(w)?w:null,format=_toStr.call(space).match(/String|Number/)||[],_date=Y.JSON.dateToString,stack=[],tmp,i,len;if(replacer||!isArray(w)){w=undefined;} +if(w){tmp={};for(i=0,len=w.length;i=0;--i){if(stack[i]===value){throw new Error("JSON.stringify. Cyclical reference");}} +arr=isArray(value);stack.push(value);if(arr){for(i=value.length-1;i>=0;--i){a[i]=_serialize(value,i)||NULL;}}else{keys=w||value;i=0;for(k in keys){if(keys.hasOwnProperty(k)){v=_serialize(value,k);if(v){a[i++]=_string(k)+colon+v;}}}} +stack.pop();if(space&&a.length){return arr?OPEN_A+CR+_indent(a.join(COMMA_CR),space)+CR+CLOSE_A:OPEN_O+CR+_indent(a.join(COMMA_CR),space)+CR+CLOSE_O;}else{return arr?OPEN_A+a.join(COMMA)+CLOSE_A:OPEN_O+a.join(COMMA)+CLOSE_O;}} +return _serialize({'':o},'');} +Y.mix(Y.namespace('JSON'),{useNativeStringify:!!Native,dateToString:function(d){function _zeroPad(v){return v<10?'0'+v:v;} +return d.getUTCFullYear()+'-'+ +_zeroPad(d.getUTCMonth()+1)+'-'+ +_zeroPad(d.getUTCDate())+'T'+ +_zeroPad(d.getUTCHours())+COLON+ +_zeroPad(d.getUTCMinutes())+COLON+ +_zeroPad(d.getUTCSeconds())+'Z';},stringify:function(o,w,ind){return Native&&Y.JSON.useNativeStringify?Native.stringify(o,w,ind):_stringify(o,w,ind);}});},'3.0.0');YUI.add('json',function(Y){},'3.0.0',{use:['json-parse','json-stringify']}); \ No newline at end of file diff --git a/include/javascript/yui3/build/loader/loader-min.js b/include/javascript/yui3/build/loader/loader-min.js new file mode 100644 index 00000000..9b4b644d --- /dev/null +++ b/include/javascript/yui3/build/loader/loader-min.js @@ -0,0 +1,8 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add("loader",function(A){(function(){YUI.Env._loaderQueue=YUI.Env._loaderQueue||new A.Queue();var w={},t=YUI.Env,AC,n="base",X="css",AB="js",K="cssreset",U="cssfonts",AD="cssgrids",C="cssbase",I=[K,U,AD,"cssreset-context","cssfonts-context","cssgrids-context"],a=["reset","fonts","grids",n],b=A.version,u=b+"/build/",e="-context",k="anim-base",y="attribute",S=y+"-base",B="base-base",x="dd-drag",h="dom",E="dataschema-base",q="datasource-local",l="dom-base",N="dom-style",M="dom-screen",G="dump",Z="get",Y="event-base",o="event-custom",W="event-custom-base",r="io-base",AA="node",V="node-base",J="node-style",O="node-screen",T="oop",j="pluginhost",F="selector-css2",m="substitute",R="widget",H="widget-position",s="yui-base",g="plugin",f={version:b,root:u,base:"http://yui.yahooapis.com/"+u,comboBase:"http://yui.yahooapis.com/combo?",skin:{defaultSkin:"sam",base:"assets/skins/",path:"skin.css",after:I},modules:{dom:{requires:[T],submodules:{"dom-base":{requires:[T]},"dom-style":{requires:[l]},"dom-screen":{requires:[l,N]},"selector-native":{requires:[l]},"selector-css2":{requires:["selector-native"]},"selector":{requires:[l]}},plugins:{"selector-css3":{requires:[F]}}},node:{requires:[h,Y],submodules:{"node-base":{requires:[l,F,Y]},"node-style":{requires:[N,V]},"node-screen":{requires:[M,V]},"node-pluginhost":{requires:[V,j]},"node-event-delegate":{requires:[V,"event-delegate"]}},plugins:{"node-event-simulate":{requires:[V,"event-simulate"]}}},anim:{submodules:{"anim-base":{requires:[B,J]},"anim-color":{requires:[k]},"anim-easing":{requires:[k]},"anim-scroll":{requires:[k]},"anim-xy":{requires:[k,O]},"anim-curve":{requires:["anim-xy"]},"anim-node-plugin":{requires:["node-pluginhost",k]}}},attribute:{submodules:{"attribute-base":{requires:[o]},"attribute-complex":{requires:[S]}}},base:{submodules:{"base-base":{requires:[S]},"base-build":{requires:[B]},"base-pluginhost":{requires:[B,j]}}},cache:{requires:[g]},compat:{requires:[AA,G,m]},classnamemanager:{requires:[s]},collection:{requires:[T]},console:{requires:["yui-log",R,m],skinnable:true,plugins:{"console-filters":{requires:[g,"console"],skinnable:true}}},cookie:{requires:[s]},dataschema:{submodules:{"dataschema-base":{requires:[n]},"dataschema-array":{requires:[E]},"dataschema-json":{requires:[E,"json"]},"dataschema-text":{requires:[E]},"dataschema-xml":{requires:[E]}}},datasource:{submodules:{"datasource-local":{requires:[n]},"datasource-arrayschema":{requires:[q,g,"dataschema-array"]},"datasource-cache":{requires:[q,"cache"]},"datasource-function":{requires:[q]},"datasource-jsonschema":{requires:[q,g,"dataschema-json"]},"datasource-polling":{requires:[q]},"datasource-get":{requires:[q,Z]},"datasource-textschema":{requires:[q,g,"dataschema-text"]},"datasource-io":{requires:[q,r]},"datasource-xmlschema":{requires:[q,g,"dataschema-xml"]}}},datatype:{submodules:{"datatype-date":{requires:[s]},"datatype-number":{requires:[s]},"datatype-xml":{requires:[s]}}},dd:{submodules:{"dd-ddm-base":{requires:[AA,n]},"dd-ddm":{requires:["dd-ddm-base","event-resize"]},"dd-ddm-drop":{requires:["dd-ddm"]},"dd-drag":{requires:["dd-ddm-base"]},"dd-drop":{requires:["dd-ddm-drop"]},"dd-proxy":{requires:[x]},"dd-constrain":{requires:[x]},"dd-scroll":{requires:[x]},"dd-plugin":{requires:[x],optional:["dd-constrain","dd-proxy"]},"dd-drop-plugin":{requires:["dd-drop"]}}},dump:{requires:[s]},event:{expound:V,submodules:{"event-base":{expound:V,requires:[W]},"event-delegate":{requires:[V]},"event-focus":{requires:[V]},"event-key":{requires:[V]},"event-mouseenter":{requires:[V]},"event-mousewheel":{requires:[V]},"event-resize":{requires:[V]}}},"event-custom":{submodules:{"event-custom-base":{requires:[T,"yui-later"]},"event-custom-complex":{requires:[W]}}},"event-simulate":{requires:[Y]},"node-focusmanager":{requires:[y,AA,g,"node-event-simulate","event-key","event-focus"]},history:{requires:[AA]},imageloader:{requires:[B,J,O]},io:{submodules:{"io-base":{requires:[W]},"io-xdr":{requires:[r,"datatype-xml"]},"io-form":{requires:[r,V,J]},"io-upload-iframe":{requires:[r,V]},"io-queue":{requires:[r,"queue-promote"]}}},json:{submodules:{"json-parse":{requires:[s]},"json-stringify":{requires:[s]}}},loader:{requires:[Z]},"node-menunav":{requires:[AA,"classnamemanager",g,"node-focusmanager"],skinnable:true},oop:{requires:[s]},overlay:{requires:[R,H,"widget-position-ext","widget-stack","widget-stdmod"],skinnable:true},plugin:{requires:[B]},pluginhost:{requires:[s]},profiler:{requires:[s]},"queue-promote":{requires:[s]},"queue-run":{requires:[o],path:"async-queue/async-queue-min.js"},"async-queue":{requires:[o],supersedes:["queue-run"]},slider:{requires:[R,"dd-constrain"],skinnable:true},stylesheet:{requires:[s]},substitute:{optional:[G]},widget:{requires:[y,"event-focus",n,AA,"classnamemanager"],plugins:{"widget-position":{},"widget-position-ext":{requires:[H]},"widget-stack":{skinnable:true},"widget-stdmod":{}},skinnable:true},yui:{submodules:{"yui-base":{},get:{},"yui-log":{},"yui-later":{}}},test:{requires:[m,AA,"json","event-simulate"]}}},p=A.cached(function(L,i,AE){return L+"/"+i+"-min."+(AE||X);}),Q=YUI.Env._loaderQueue,D=f.modules,v,d,c,z,P=A.Lang;for(v=0;v-1);this.root=A.Env.meta.root;this.timeout=0;this.forceMap={};this.filters={};this.required={};this.moduleInfo={};this.skin=A.merge(A.Env.meta.skin);var AF=A.Env.meta.modules,L,AE=YUI.Env.mods;this._internal=true;for(L in AF){if(AF.hasOwnProperty(L)){this.addModule(AF[L],L);}}for(L in AE){if(AE.hasOwnProperty(L)&&!this.moduleInfo[L]&&AE[L].details){this.addModule(AE[L].details,L);}}this._internal=false;this.sorted=[];this.loaded=AC[b];this.dirty=true;this.inserted={};this.skipped={};this._config(AG);};A.Loader.prototype={FILTER_DEFS:{RAW:{"searchExp":"-min\\.js","replaceStr":".js"},DEBUG:{"searchExp":"-min\\.js","replaceStr":"-debug.js"}},SKIN_PREFIX:"skin-",_config:function(AH){var AE,L,AG,AF;if(AH){for(AE in AH){if(AH.hasOwnProperty(AE)){AG=AH[AE];if(AE=="require"){this.require(AG);}else{if(AE=="modules"){for(L in AG){if(AG.hasOwnProperty(L)){this.addModule(AG[L],L);}}}else{this[AE]=AG;}}}}}AF=this.filter;if(P.isString(AF)){AF=AF.toUpperCase();this.filterName=AF;this.filter=this.FILTER_DEFS[AF];if(AF=="DEBUG"){this.require("yui-log","dump");}}},formatSkin:function(AE,L){var i=this.SKIN_PREFIX+AE;if(L){i=i+"-"+L;}return i;},_addSkin:function(AK,AI,AJ){var L=this.formatSkin(AK),AF=this.moduleInfo,i=this.skin,AE=AF[AI]&&AF[AI].ext,AH,AG;if(AI){L=this.formatSkin(AK,AI);if(!AF[L]){AH=AF[AI];AG=AH.pkg||AI;this.addModule({"name":L,"type":"css","after":i.after,"path":(AJ||AG)+"/"+i.base+AK+"/"+AI+".css","ext":AE});}}return L;},addModule:function(AF,AE){AE=AE||AF.name;AF.name=AE;if(!AF||!AF.name){return false;}if(!AF.type){AF.type=AB;}if(!AF.path&&!AF.fullpath){AF.path=p(AE,AE,AF.type);}AF.ext=("ext"in AF)?AF.ext:(this._internal)?false:true;AF.requires=AF.requires||[];this.moduleInfo[AE]=AF;var AI=AF.submodules,AJ,AG,AK,AM,AL,AH,L;if(AI){AK=[];AG=0;for(AJ in AI){if(AI.hasOwnProperty(AJ)){AM=AI[AJ];AM.path=p(AE,AJ,AF.type);this.addModule(AM,AJ);AK.push(AJ);if(AF.skinnable){AL=this._addSkin(this.skin.defaultSkin,AJ,AE);AK.push(AL.name);}AG++;}}AF.supersedes=AK;AF.rollup=(AG<4)?AG:Math.min(AG-1,4);}AH=AF.plugins;if(AH){for(AJ in AH){if(AH.hasOwnProperty(AJ)){L=AH[AJ];L.path=p(AE,AJ,AF.type);L.requires=L.requires||[];this.addModule(L,AJ);if(AF.skinnable){this._addSkin(this.skin.defaultSkin,AJ,AE);}}}}this.dirty=true;return AF;},require:function(i){var L=(typeof i==="string")?arguments:i;this.dirty=true;A.mix(this.required,A.Array.hash(L));},getRequires:function(AK){if(!AK){return[];}if(!this.dirty&&AK.expanded){return AK.expanded;}var AI,AJ=[],L=AK.requires,AE=AK.optional,AF=this.moduleInfo,AG,AH,AL;for(AI=0;AI=AH.rollup);if(AF){break;}}}}if(AF){L[AJ]=true;AE=true;this.getRequires(AH);}}}}if(!AE){break;}}},_reduce:function(){var AF,AE,AH,L,AI=this.required,AG=this.loadType;for(AF in AI){if(AI.hasOwnProperty(AF)){L=this.getModule(AF);if((this.loaded[AF]&&(!this.forceMap[AF])&&!this.ignoreRegistered)||(AG&&L&&L.type!=AG)){delete AI[AF];}else{AH=L&&L.supersedes;if(AH){for(AE=0;AE-1){return true;}if(AW&&A.Array.indexOf(AW,AT)>-1){return true;}AS=AE[AT]&&AE[AT].supersedes;if(AS){for(AR=0;AR0){Q.running=true;Q.next()();}},insert:function(AE,i){var L=this,AF=A.merge(this,true);delete AF.require;delete AF.dirty;Q.add(function(){L._insert(AF,AE,i);});this._continue();},loadNext:function(AJ){if(!this._loading){return;}var AP,AH,AG,AF,L,AO=this,AK=this.loadType,AL,AE,AI,AM=function(AS){this._combineComplete[AK]=true;var AT=this._combining,AQ=AT.length,AR;for(AR=0;AR-1);this.root=Y.Env.meta.root;this.timeout=0;this.forceMap={};this.filters={};this.required={};this.moduleInfo={};this.skin=Y.merge(Y.Env.meta.skin);var defaults=Y.Env.meta.modules,i,onPage=YUI.Env.mods;this._internal=true;for(i in defaults){if(defaults.hasOwnProperty(i)){this.addModule(defaults[i],i);}} +for(i in onPage){if(onPage.hasOwnProperty(i)&&!this.moduleInfo[i]&&onPage[i].details){this.addModule(onPage[i].details,i);}} +this._internal=false;this.sorted=[];this.loaded=GLOBAL_LOADED[VERSION];this.dirty=true;this.inserted={};this.skipped={};this._config(o);};Y.Loader.prototype={FILTER_DEFS:{RAW:{'searchExp':"-min\\.js",'replaceStr':".js"},DEBUG:{'searchExp':"-min\\.js",'replaceStr':"-debug.js"}},SKIN_PREFIX:"skin-",_config:function(o){var i,j,val,f;if(o){for(i in o){if(o.hasOwnProperty(i)){val=o[i];if(i=='require'){this.require(val);}else if(i=='modules'){for(j in val){if(val.hasOwnProperty(j)){this.addModule(val[j],j);}}}else{this[i]=val;}}}} +f=this.filter;if(L.isString(f)){f=f.toUpperCase();this.filterName=f;this.filter=this.FILTER_DEFS[f];if(f=='DEBUG'){this.require('yui-log','dump');}}},formatSkin:function(skin,mod){var s=this.SKIN_PREFIX+skin;if(mod){s=s+"-"+mod;} +return s;},_addSkin:function(skin,mod,parent){var name=this.formatSkin(skin),info=this.moduleInfo,sinf=this.skin,ext=info[mod]&&info[mod].ext,mdef,pkg;if(mod){name=this.formatSkin(skin,mod);if(!info[name]){mdef=info[mod];pkg=mdef.pkg||mod;this.addModule({'name':name,'type':'css','after':sinf.after,'path':(parent||pkg)+'/'+sinf.base+skin+'/'+mod+'.css','ext':ext});}} +return name;},addModule:function(o,name){name=name||o.name;o.name=name;if(!o||!o.name){return false;} +if(!o.type){o.type=JS;} +if(!o.path&&!o.fullpath){o.path=_path(name,name,o.type);} +o.ext=('ext'in o)?o.ext:(this._internal)?false:true;o.requires=o.requires||[];this.moduleInfo[name]=o;var subs=o.submodules,i,l,sup,s,smod,plugins,plug;if(subs){sup=[];l=0;for(i in subs){if(subs.hasOwnProperty(i)){s=subs[i];s.path=_path(name,i,o.type);this.addModule(s,i);sup.push(i);if(o.skinnable){smod=this._addSkin(this.skin.defaultSkin,i,name);sup.push(smod.name);} +l++;}} +o.supersedes=sup;o.rollup=(l<4)?l:Math.min(l-1,4);} +plugins=o.plugins;if(plugins){for(i in plugins){if(plugins.hasOwnProperty(i)){plug=plugins[i];plug.path=_path(name,i,o.type);plug.requires=plug.requires||[];this.addModule(plug,i);if(o.skinnable){this._addSkin(this.skin.defaultSkin,i,name);}}}} +this.dirty=true;return o;},require:function(what){var a=(typeof what==="string")?arguments:what;this.dirty=true;Y.mix(this.required,Y.Array.hash(a));},getRequires:function(mod){if(!mod){return[];} +if(!this.dirty&&mod.expanded){return mod.expanded;} +var i,d=[],r=mod.requires,o=mod.optional,info=this.moduleInfo,m,j,add;for(i=0;i=m.rollup);if(roll){break;}}} +if(roll){r[i]=true;rolled=true;this.getRequires(m);}}}} +if(!rolled){break;}}},_reduce:function(){var i,j,s,m,r=this.required,type=this.loadType;for(i in r){if(r.hasOwnProperty(i)){m=this.getModule(i);if((this.loaded[i]&&(!this.forceMap[i])&&!this.ignoreRegistered)||(type&&m&&m.type!=type)){delete r[i];}else{s=m&&m.supersedes;if(s){for(j=0;j-1){return true;} +if(after&&Y.Array.indexOf(after,mod2)>-1){return true;} +s=info[mod2]&&info[mod2].supersedes;if(s){for(i=0;i0){_queue.running=true;_queue.next()();}},insert:function(o,type){var self=this,copy=Y.merge(this,true);delete copy.require;delete copy.dirty;_queue.add(function(){self._insert(copy,o,type);});this._continue();},loadNext:function(mname){if(!this._loading){return;} +var s,len,i,m,url,self=this,type=this.loadType,fn,msg,attr,callback=function(o){this._combineComplete[type]=true;var c=this._combining,len=c.length,i;for(i=0;i1){for(T=0;T1){R=this._eventHandlers||[];S=this.get(O).get("ownerDocument");if(R.length===0){R.push(S.on("focus",this._onDocFocus,this));R.push(S.on("mousedown",this._onDocMouseDown,this));R.push(this.after("keysChange",this._attachKeyHandler));R.push(this.after("descendantsChange",this._initDescendants));R.push(this.after(G,this._afterActiveDescendantChange));T=this.after("focusedChange",B.bind(function(V){if(V.newVal){this._attachKeyHandler();T.detach();}},this));R.push(T);}this._eventHandlers=R;}},_onDocMouseDown:function(U){var W=this.get(O),R=U.target,V=W.contains(R),T,S=function(Y){var X=false;if(!Y.compareTo(W)){X=this._isDescendant(Y)?Y:S.call(this,Y.get("parentNode"));}return X;};if(V){T=S.call(this,R);if(T){R=T;}else{if(!T&&this.get(E)){this._set(E,false);this._onDocFocus(U);}}}if(V&&this._isDescendant(R)){this.focus(R);}else{if(K.webkit&&this.get(E)&&(!V||(V&&!this._isDescendant(R)))){this._set(E,false);this._onDocFocus(U);}}},_onDocFocus:function(W){var U=this._focusTarget||W.target,S=this.get(E),V=this.get(A),T=this._focusedNode,R;if(this._focusTarget){this._focusTarget=null;}if(this.get(O).contains(U)){R=this._isDescendant(U);if(!S&&R){S=true;}else{if(S&&!R){S=false;}}}else{S=false;}if(V){if(T&&(!T.compareTo(U)||!S)){this._removeFocusClass();}if(R&&S){if(V.fn){U=V.fn(U);U.addClass(V.className);}else{U.addClass(V);}this._focusedNode=U;}}this._set(E,S);},_focusNext:function(S,T){var R=T||this.get(J),U;if(this._isDescendant(S.target)&&(R<=this._lastNodeIndex)){R=R+1;if(R===(this._lastNodeIndex+1)&&this.get(Q)){R=0;}U=this._descendants.item(R);if(U.get(I)){this._focusNext(S,R);}else{this.focus(R);}}this._preventScroll(S);},_focusPrevious:function(S,T){var R=T||this.get(J),U;if(this._isDescendant(S.target)&&R>=0){R=R-1;if(R===-1&&this.get(Q)){R=this._lastNodeIndex;}U=this._descendants.item(R);if(U.get(I)){this._focusPrevious(S,R);}else{this.focus(R);}}this._preventScroll(S);},_afterActiveDescendantChange:function(R){var S=this._descendants.item(R.prevVal);if(S){S.set(N,-1);}S=this._descendants.item(R.newVal);if(S){S.set(N,0);}},initializer:function(R){this.start();},destructor:function(){this.stop();this.get(O).focusManager=null;},focus:function(R){if(H.isUndefined(R)){R=this.get(J);}this.set(J,R,{src:C});var S=this._descendants.item(this.get(J));if(S){S.focus();if(K.opera&&S.get("nodeName").toLowerCase()==="button"){this._focusTarget=S;}}},blur:function(){var R;if(this.get(E)){R=this._descendants.item(this.get(J));if(R){R.blur();this._removeFocusClass();}this._set(E,false,{src:C});}},start:function(){if(this._stopped){this._initDescendants();this._attachEventHandlers();this._stopped=false;}},stop:function(){if(!this._stopped){this._detachEventHandlers();this._descendants=null;this._focusedNode=null;this._lastNodeIndex=0;this._stopped=true;}},refresh:function(){this._initDescendants();}});D.NAME="nodeFocusManager";D.NS="focusManager";B.namespace("Plugin");B.Plugin.NodeFocusManager=D;},"3.0.0",{requires:["attribute","node","plugin","node-event-simulate","event-key","event-focus"]}); \ No newline at end of file diff --git a/include/javascript/yui3/build/node-focusmanager/node-focusmanager.js b/include/javascript/yui3/build/node-focusmanager/node-focusmanager.js new file mode 100644 index 00000000..9211baa2 --- /dev/null +++ b/include/javascript/yui3/build/node-focusmanager/node-focusmanager.js @@ -0,0 +1,47 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add('node-focusmanager',function(Y){var ACTIVE_DESCENDANT="activeDescendant",ID="id",DISABLED="disabled",TAB_INDEX="tabIndex",FOCUSED="focused",FOCUS_CLASS="focusClass",CIRCULAR="circular",UI="UI",KEY="key",ACTIVE_DESCENDANT_CHANGE=ACTIVE_DESCENDANT+"Change",HOST="host",scrollKeys={37:true,38:true,39:true,40:true},clickableElements={"a":true,"button":true,"input":true,"object":true},Lang=Y.Lang,UA=Y.UA,NodeFocusManager=function(){NodeFocusManager.superclass.constructor.apply(this,arguments);};NodeFocusManager.ATTRS={focused:{value:false,readOnly:true},descendants:{getter:function(value){return this.get(HOST).all(value);}},activeDescendant:{setter:function(value){var isNumber=Lang.isNumber,INVALID_VALUE=Y.Attribute.INVALID_VALUE,descendantsMap=this._descendantsMap,descendants=this._descendants,nodeIndex,returnValue,oNode;if(isNumber(value)){nodeIndex=value;returnValue=nodeIndex;} +else if((value instanceof Y.Node)&&descendantsMap){nodeIndex=descendantsMap[value.get(ID)];if(isNumber(nodeIndex)){returnValue=nodeIndex;} +else{returnValue=INVALID_VALUE;}} +else{returnValue=INVALID_VALUE;} +if(descendants){oNode=descendants.item(nodeIndex);if(oNode&&oNode.get("disabled")){returnValue=INVALID_VALUE;}} +return returnValue;}},keys:{value:{next:null,previous:null}},focusClass:{},circular:{value:true}};Y.extend(NodeFocusManager,Y.Plugin.Base,{_stopped:true,_descendants:null,_descendantsMap:null,_focusedNode:null,_lastNodeIndex:0,_eventHandlers:null,_initDescendants:function(){var descendants=this.get("descendants"),descendantsMap={},nFirstEnabled=-1,nDescendants,nActiveDescendant=this.get(ACTIVE_DESCENDANT),oNode,sID,i=0;if(Lang.isUndefined(nActiveDescendant)){nActiveDescendant=-1;} +if(descendants){nDescendants=descendants.size();if(nDescendants>1){for(i=0;i1){aHandlers=this._eventHandlers||[];oDocument=this.get(HOST).get("ownerDocument");if(aHandlers.length===0){aHandlers.push(oDocument.on("focus",this._onDocFocus,this));aHandlers.push(oDocument.on("mousedown",this._onDocMouseDown,this));aHandlers.push(this.after("keysChange",this._attachKeyHandler));aHandlers.push(this.after("descendantsChange",this._initDescendants));aHandlers.push(this.after(ACTIVE_DESCENDANT_CHANGE,this._afterActiveDescendantChange));handle=this.after("focusedChange",Y.bind(function(event){if(event.newVal){this._attachKeyHandler();handle.detach();}},this));aHandlers.push(handle);} +this._eventHandlers=aHandlers;}},_onDocMouseDown:function(event){var oHost=this.get(HOST),oTarget=event.target,bChildNode=oHost.contains(oTarget),node,getFocusable=function(node){var returnVal=false;if(!node.compareTo(oHost)){returnVal=this._isDescendant(node)?node:getFocusable.call(this,node.get("parentNode"));} +return returnVal;};if(bChildNode){node=getFocusable.call(this,oTarget);if(node){oTarget=node;} +else if(!node&&this.get(FOCUSED)){this._set(FOCUSED,false);this._onDocFocus(event);}} +if(bChildNode&&this._isDescendant(oTarget)){this.focus(oTarget);} +else if(UA.webkit&&this.get(FOCUSED)&&(!bChildNode||(bChildNode&&!this._isDescendant(oTarget)))){this._set(FOCUSED,false);this._onDocFocus(event);}},_onDocFocus:function(event){var oTarget=this._focusTarget||event.target,bFocused=this.get(FOCUSED),focusClass=this.get(FOCUS_CLASS),oFocusedNode=this._focusedNode,bInCollection;if(this._focusTarget){this._focusTarget=null;} +if(this.get(HOST).contains(oTarget)){bInCollection=this._isDescendant(oTarget);if(!bFocused&&bInCollection){bFocused=true;} +else if(bFocused&&!bInCollection){bFocused=false;}} +else{bFocused=false;} +if(focusClass){if(oFocusedNode&&(!oFocusedNode.compareTo(oTarget)||!bFocused)){this._removeFocusClass();} +if(bInCollection&&bFocused){if(focusClass.fn){oTarget=focusClass.fn(oTarget);oTarget.addClass(focusClass.className);} +else{oTarget.addClass(focusClass);} +this._focusedNode=oTarget;}} +this._set(FOCUSED,bFocused);},_focusNext:function(event,activeDescendant){var nActiveDescendant=activeDescendant||this.get(ACTIVE_DESCENDANT),oNode;if(this._isDescendant(event.target)&&(nActiveDescendant<=this._lastNodeIndex)){nActiveDescendant=nActiveDescendant+1;if(nActiveDescendant===(this._lastNodeIndex+1)&&this.get(CIRCULAR)){nActiveDescendant=0;} +oNode=this._descendants.item(nActiveDescendant);if(oNode.get(DISABLED)){this._focusNext(event,nActiveDescendant);} +else{this.focus(nActiveDescendant);}} +this._preventScroll(event);},_focusPrevious:function(event,activeDescendant){var nActiveDescendant=activeDescendant||this.get(ACTIVE_DESCENDANT),oNode;if(this._isDescendant(event.target)&&nActiveDescendant>=0){nActiveDescendant=nActiveDescendant-1;if(nActiveDescendant===-1&&this.get(CIRCULAR)){nActiveDescendant=this._lastNodeIndex;} +oNode=this._descendants.item(nActiveDescendant);if(oNode.get(DISABLED)){this._focusPrevious(event,nActiveDescendant);} +else{this.focus(nActiveDescendant);}} +this._preventScroll(event);},_afterActiveDescendantChange:function(event){var oNode=this._descendants.item(event.prevVal);if(oNode){oNode.set(TAB_INDEX,-1);} +oNode=this._descendants.item(event.newVal);if(oNode){oNode.set(TAB_INDEX,0);}},initializer:function(config){this.start();},destructor:function(){this.stop();this.get(HOST).focusManager=null;},focus:function(index){if(Lang.isUndefined(index)){index=this.get(ACTIVE_DESCENDANT);} +this.set(ACTIVE_DESCENDANT,index,{src:UI});var oNode=this._descendants.item(this.get(ACTIVE_DESCENDANT));if(oNode){oNode.focus();if(UA.opera&&oNode.get("nodeName").toLowerCase()==="button"){this._focusTarget=oNode;}}},blur:function(){var oNode;if(this.get(FOCUSED)){oNode=this._descendants.item(this.get(ACTIVE_DESCENDANT));if(oNode){oNode.blur();this._removeFocusClass();} +this._set(FOCUSED,false,{src:UI});}},start:function(){if(this._stopped){this._initDescendants();this._attachEventHandlers();this._stopped=false;}},stop:function(){if(!this._stopped){this._detachEventHandlers();this._descendants=null;this._focusedNode=null;this._lastNodeIndex=0;this._stopped=true;}},refresh:function(){this._initDescendants();}});NodeFocusManager.NAME="nodeFocusManager";NodeFocusManager.NS="focusManager";Y.namespace("Plugin");Y.Plugin.NodeFocusManager=NodeFocusManager;},'3.0.0',{requires:['attribute','node','plugin','node-event-simulate','event-key','event-focus']}); \ No newline at end of file diff --git a/include/javascript/yui3/build/node-menunav/assets/node-menunav-core.css b/include/javascript/yui3/build/node-menunav/assets/node-menunav-core.css new file mode 100644 index 00000000..97fc86e0 --- /dev/null +++ b/include/javascript/yui3/build/node-menunav/assets/node-menunav-core.css @@ -0,0 +1,176 @@ +/* +Copyright (c) 2009, Yahoo! Inc. All rights reserved. +Code licensed under the BSD License: +http://developer.yahoo.net/yui/license.txt +version: 3.0.0 +build: 1549 +*/ +.yui-menu .yui-menu { + + position: absolute; + z-index: 1; + +} + + +.yui-menu .yui-shim { + + /* + Styles for the ';AK.ATTRS={useARIA:{value:true,writeOnce:true,lazyAdd:false,setter:function(AT){var AQ=this.get(c),AU,Y,AS,AR;if(AT){AQ.set(AP,R);AQ.all("ul,li,."+AL(R,y)).set(AP,N);AQ.all((I+AL(G,y))).set(AP,G);AQ.all((I+AI)).each(function(AV){AU=AV;Y=AV.one(AG);if(Y){Y.set(AP,N);AU=Y.previous();}AU.set(AP,G);AU.set("aria-haspopup",true);AS=AV.next();if(AS){AS.set(AP,R);AU=AS.previous();Y=AU.one(AG);if(Y){AU=Y;}AR=D.stamp(AU);if(!AU.get(g)){AU.set(g,AR);}AS.set("aria-labelledby",AR);AS.set(x,true);}});}}},autoSubmenuDisplay:{value:true,writeOnce:true},submenuShowDelay:{value:250,writeOnce:true},submenuHideDelay:{value:250,writeOnce:true},mouseOutHideDelay:{value:750,writeOnce:true}};D.extend(AK,D.Plugin.Base,{_rootMenu:null,_activeItem:null,_activeMenu:null,_hasFocus:false,_blockMouseEvent:false,_currentMouseX:0,_movingToSubmenu:false,_showSubmenuTimer:null,_hideSubmenuTimer:null,_hideAllSubmenusTimer:null,_firstItem:null,initializer:function(AR){var AS=this,AT=this.get(c),AQ=[],Y;if(AT){AS._rootMenu=AT;AT.all("ul:first-child").addClass(U);AT.all(i).addClass(AF);AQ.push(AT.on("mouseover",AS._onMouseOver,AS));AQ.push(AT.on("mouseout",AS._onMouseOut,AS));AQ.push(AT.on("mousemove",AS._onMouseMove,AS));AQ.push(AT.on(w,AS._toggleSubmenuDisplay,AS));AQ.push(D.on("key",AS._toggleSubmenuDisplay,AT,"down:13",AS));AQ.push(AT.on(AB,AS._toggleSubmenuDisplay,AS));AQ.push(AT.on("keypress",AS._onKeyPress,AS));AQ.push(AT.on(AO,AS._onKeyDown,AS));Y=AT.get("ownerDocument");AQ.push(Y.on(w,AS._onDocMouseDown,AS));AQ.push(Y.on("focus",AS._onDocFocus,AS));this._eventHandlers=AQ;AS._initFocusManager();}},destructor:function(){var Y=this._eventHandlers;if(Y){D.Array.each(Y,function(AQ){AQ.detach();});this._eventHandlers=null;}this.get(c).unplug("focusManager");},_isRoot:function(Y){return this._rootMenu.compareTo(Y);},_getTopmostSubmenu:function(AS){var AR=this,Y=M(AS),AQ;if(!Y){AQ=AS;}else{if(AR._isRoot(Y)){AQ=AS;}else{AQ=AR._getTopmostSubmenu(Y);}}return AQ;},_clearActiveItem:function(){var AQ=this,Y=AQ._activeItem;if(Y){Y.removeClass(f(Y));}AQ._activeItem=null;},_setActiveItem:function(AQ){var Y=this;if(AQ){Y._clearActiveItem();AQ.addClass(f(AQ));Y._activeItem=AQ;}},_focusItem:function(AR){var AQ=this,Y,AS;if(AR&&AQ._hasFocus){Y=M(AR);AS=p(AR);if(Y&&!Y.compareTo(AQ._activeMenu)){AQ._activeMenu=Y;AQ._initFocusManager();}AQ._focusManager.focus(AS);}},_showMenu:function(AS){var Y=M(AS),AR=AS.get(S),AQ=AR.getXY();if(this.get(J)){AS.set(x,false);}if(q(Y)){AQ[1]=AQ[1]+AR.get(z);}else{AQ[0]=AQ[0]+AR.get(AC);}AS.setXY(AQ);if(m.ie<8){if(m.ie===6&&!AS.hasIFrameShim){AS.appendChild(D.Node.create(AK.SHIM_TEMPLATE));AS.hasIFrameShim=true;}AS.setStyles({height:Q,width:Q});AS.setStyles({height:(AS.get(z)+AN),width:(AS.get(AC)+AN)});}AS.previous().addClass(X);AS.removeClass(AF);},_hideMenu:function(AS,AQ){var AR=this,AT=AS.previous(),Y;AT.removeClass(X);if(AQ){AR._focusItem(AT);AR._setActiveItem(AT);}Y=AS.one((I+A));if(Y){Y.removeClass(A);}AS.setStyles({left:Q,top:Q});AS.addClass(AF);if(AR.get(J)){AS.set(x,true);}},_hideAllSubmenus:function(AQ){var Y=this;AQ.all(i).each(D.bind(function(AR){Y._hideMenu(AR);},Y));},_cancelShowSubmenuTimer:function(){var AQ=this,Y=AQ._showSubmenuTimer;if(Y){Y.cancel();AQ._showSubmenuTimer=null;}},_cancelHideSubmenuTimer:function(){var Y=this,AQ=Y._hideSubmenuTimer;if(AQ){AQ.cancel();Y._hideSubmenuTimer=null;}},_initFocusManager:function(){var AS=this,AU=AS._rootMenu,AQ=AS._activeMenu||AU,AT=AS._isRoot(AQ)?Q:("#"+AQ.get("id")),Y=AS._focusManager,AR,AV,AW;if(q(AQ)){AV=AT+AM+","+AT+O;AR={next:"down:39",previous:"down:37"};}else{AV=AT+AM;AR={next:"down:40",previous:"down:38"};}if(!Y){AU.plug(D.Plugin.NodeFocusManager,{descendants:AV,keys:AR,circular:true});Y=AU.focusManager;AW="#"+AU.get("id")+" .yui-menu a,"+AG;AU.all(AW).set("tabIndex",-1);Y.on(h,this._onActiveDescendantChange,Y,this);Y.after(h,this._afterActiveDescendantChange,Y,this);AS._focusManager=Y;}else{Y.set(u,-1);Y.set(AD,AV);Y.set("keys",AR);}},_onActiveDescendantChange:function(AQ,Y){if(AQ.src===j&&Y._activeMenu&&!Y._movingToSubmenu){Y._hideAllSubmenus(Y._activeMenu);}},_afterActiveDescendantChange:function(AQ,Y){var AR;if(AQ.src===j){AR=B(this.get(AD).item(AQ.newVal),true);Y._setActiveItem(AR);}},_onDocFocus:function(AT){var AS=this,Y=AS._activeItem,AR=AT.target,AQ;if(AS._rootMenu.contains(AR)){if(AS._hasFocus){AQ=M(AR);if(!AS._activeMenu.compareTo(AQ)){AS._activeMenu=AQ;AS._initFocusManager();AS._focusManager.set(u,AR);AS._setActiveItem(B(AR,true));}}else{AS._hasFocus=true;Y=B(AR,true);if(Y){AS._setActiveItem(Y);}}}else{AS._clearActiveItem();AS._cancelShowSubmenuTimer();AS._hideAllSubmenus(AS._rootMenu);AS._activeMenu=AS._rootMenu;AS._initFocusManager();AS._focusManager.set(u,0);AS._hasFocus=false;}},_onMenuMouseOver:function(AS,AR){var AQ=this,Y=AQ._hideAllSubmenusTimer;if(Y){Y.cancel();AQ._hideAllSubmenusTimer=null;}AQ._cancelHideSubmenuTimer();if(AS&&!AS.compareTo(AQ._activeMenu)){AQ._activeMenu=AS;if(AQ._hasFocus){AQ._initFocusManager();}}if(AQ._movingToSubmenu&&q(AS)){AQ._movingToSubmenu=false;}},_hideAndFocusLabel:function(){var AR=this,AQ=AR._activeMenu,Y;AR._hideAllSubmenus(AR._rootMenu);if(AQ){Y=AR._getTopmostSubmenu(AQ);AR._focusItem(Y.previous());}},_onMenuMouseOut:function(AW,AU){var AT=this,AR=AT._activeMenu,AV=AU.relatedTarget,Y=AT._activeItem,AS,AQ;if(AR&&!AR.contains(AV)){AS=M(AR);if(AS&&!AS.contains(AV)){if(AT.get(T)>0){AT._cancelShowSubmenuTimer();AT._hideAllSubmenusTimer=t(AT.get(T),AT,AT._hideAndFocusLabel);}}else{if(Y){AQ=M(Y);if(!AT._isRoot(AQ)){AT._focusItem(AQ.previous());}}}}},_onMenuLabelMouseOver:function(AT,AV){var AU=this,AS=AU._activeMenu,Y=AU._isRoot(AS),AR=(AU.get(v)&&Y||!Y),AQ;AU._focusItem(AT);AU._setActiveItem(AT);if(AR&&!AU._movingToSubmenu){AU._cancelHideSubmenuTimer();AU._cancelShowSubmenuTimer();if(!n(AT)){AQ=AT.next();if(AQ){AU._hideAllSubmenus(AS);AU._showSubmenuTimer=t(AU.get("submenuShowDelay"),AU,AU._showMenu,AQ);}}}},_onMenuLabelMouseOut:function(AS,AU){var AT=this,Y=AT._isRoot(AT._activeMenu),AR=(AT.get(v)&&Y||!Y),AV=AU.relatedTarget,AQ=AS.next();AT._clearActiveItem();if(AR){if(AT._movingToSubmenu&&!AT._showSubmenuTimer&&AQ){AT._hideSubmenuTimer=t(AT.get("submenuHideDelay"),AT,AT._hideMenu,AQ);}else{if(!AT._movingToSubmenu&&AQ&&!AQ.contains(AV)&&!AV.compareTo(AQ)){AT._cancelShowSubmenuTimer();AT._hideMenu(AQ);}}}},_onMenuItemMouseOver:function(AS,AU){var AT=this,AR=AT._activeMenu,Y=AT._isRoot(AR),AQ=(AT.get(v)&&Y||!Y);AT._focusItem(AS);AT._setActiveItem(AS);if(AQ&&!AT._movingToSubmenu){AT._hideAllSubmenus(AR);}},_onMenuItemMouseOut:function(Y,AQ){this._clearActiveItem();},_onVerticalMenuKeyDown:function(Y){var AQ=this,AU=AQ._activeMenu,AZ=AQ._rootMenu,AR=Y.target,AT=false,AY=Y.keyCode,AW,AS,AV,AX;switch(AY){case 37:AS=M(AU);if(AS&&q(AS)){AQ._hideMenu(AU);AV=L(AU.get(S));AX=B(AV);if(AX){if(s(AX)){AW=AX.next();if(AW){AQ._showMenu(AW);AQ._focusItem(C(AW));AQ._setActiveItem(C(AW));}else{AQ._focusItem(AX);AQ._setActiveItem(AX);}}else{AQ._focusItem(AX);AQ._setActiveItem(AX);}}}else{if(!AQ._isRoot(AU)){AQ._hideMenu(AU,true);}}AT=true;break;case 39:if(s(AR)){AW=AR.next();if(AW){AQ._showMenu(AW);AQ._focusItem(C(AW));AQ._setActiveItem(C(AW));}}else{if(q(AZ)){AW=AQ._getTopmostSubmenu(AU);AV=b(AW.get(S));AX=B(AV);AQ._hideAllSubmenus(AZ);if(AX){if(s(AX)){AW=AX.next();if(AW){AQ._showMenu(AW);AQ._focusItem(C(AW));AQ._setActiveItem(C(AW));}else{AQ._focusItem(AX);AQ._setActiveItem(AX);}}else{AQ._focusItem(AX);AQ._setActiveItem(AX);}}}}AT=true;break;}if(AT){Y.preventDefault();}},_onHorizontalMenuKeyDown:function(AV){var AU=this,AS=AU._activeMenu,AQ=AV.target,Y=B(AQ,true),AT=false,AW=AV.keyCode,AR;if(AW===40){AU._hideAllSubmenus(AS);if(s(Y)){AR=Y.next();if(AR){AU._showMenu(AR);AU._focusItem(C(AR));AU._setActiveItem(C(AR));}AT=true;}}if(AT){AV.preventDefault();}},_onMouseMove:function(AQ){var Y=this;t(10,Y,function(){Y._currentMouseX=AQ.pageX;});},_onMouseOver:function(AT){var AS=this,AQ,Y,AV,AR,AU;if(AS._blockMouseEvent){AS._blockMouseEvent=false;}else{AQ=AT.target;Y=W(AQ,true);AV=o(AQ,true);AU=AE(AQ,true);if(e(Y,AQ)){AS._onMenuMouseOver(Y,AT);Y[r]=true;Y[E]=false;AR=M(Y);if(AR){AR[E]=true;AR[r]=false;}}if(e(AV,AQ)){AS._onMenuLabelMouseOver(AV,AT);AV[r]=true;AV[E]=false;}if(e(AU,AQ)){AS._onMenuItemMouseOver(AU,AT);AU[r]=true;AU[E]=false;}}},_onMouseOut:function(AQ){var AR=this,AT=AR._activeMenu,AY=false,AS,AU,AW,Y,AV,AX;AR._movingToSubmenu=(AT&&!q(AT)&&((AQ.pageX-5)>AR._currentMouseX));AS=AQ.target;AU=AQ.relatedTarget;AW=W(AS,true);Y=o(AS,true);AX=AE(AS,true);if(H(Y,AU)){AR._onMenuLabelMouseOut(Y,AQ);Y[E]=true;Y[r]=false;}if(H(AX,AU)){AR._onMenuItemMouseOut(AX,AQ);AX[E]=true;AX[r]=false;}if(Y){AV=Y.next();if(AV&&(AU.compareTo(AV)||AV.contains(AU))){AY=true;}}if(H(AW,AU)||AY){AR._onMenuMouseOut(AW,AQ);AW[E]=true;AW[r]=false;}},_toggleSubmenuDisplay:function(AR){var AS=this,AT=AR.target,AQ=o(AT,true),Y=AR.type,AX,AW,AV,AY,AZ,AU;if(AQ){AX=F(AT)?AT:AT.ancestor(F);if(AX){AV=AX.getAttribute("href",2);AY=AV.indexOf("#");AZ=AV.length;if(AY===0&&AZ>1){AU=AV.substr(1,AZ);AW=AQ.next();if(AW&&(AW.get(g)===AU)){if(Y===w||Y===AO){if((m.opera||m.gecko||m.ie)&&Y===AO&&!AS._preventClickHandle){AS._preventClickHandle=AS._rootMenu.on("click",function(Aa){Aa.preventDefault();AS._preventClickHandle.detach();AS._preventClickHandle=null;});}if(Y==w){AR.preventDefault();AR.stopImmediatePropagation();AS._hasFocus=true;}if(AS._isRoot(M(AT))){if(n(AQ)){AS._hideMenu(AW);AS._focusItem(AQ);AS._setActiveItem(AQ);}else{AS._hideAllSubmenus(AS._rootMenu);AS._showMenu(AW);AS._focusItem(C(AW));AS._setActiveItem(C(AW));}}else{if(AS._activeItem==AQ){AS._showMenu(AW);AS._focusItem(C(AW));AS._setActiveItem(C(AW));}else{if(!AQ._clickHandle){AQ._clickHandle=AQ.on("click",function(){AS._hideAllSubmenus(AS._rootMenu);AS._hasFocus=false;AS._clearActiveItem();AQ._clickHandle.detach();AQ._clickHandle=null;});}}}}if(Y===AB){AR.preventDefault();}}}}}},_onKeyPress:function(Y){switch(Y.keyCode){case 37:case 38:case 39:case 40:Y.preventDefault();break;}},_onKeyDown:function(AU){var AT=this,Y=AT._activeItem,AQ=AU.target,AS=M(AQ),AR;if(AS){AT._activeMenu=AS;if(q(AS)){AT._onHorizontalMenuKeyDown(AU);}else{AT._onVerticalMenuKeyDown(AU);}if(AU.keyCode===27){if(!AT._isRoot(AS)){if(m.opera){t(0,AT,function(){AT._hideMenu(AS,true);});}else{AT._hideMenu(AS,true);}AU.stopPropagation();AT._blockMouseEvent=m.gecko?true:false;}else{if(Y){if(s(Y)&&n(Y)){AR=Y.next();if(AR){AT._hideMenu(AR);}}else{AT._focusManager.blur();AT._clearActiveItem();AT._hasFocus=false;}}}}}},_onDocMouseDown:function(AS){var AR=this,AQ=AR._rootMenu,Y=AS.target;if(!(AQ.compareTo(Y)||AQ.contains(Y))){AR._hideAllSubmenus(AQ);if(m.webkit){AR._hasFocus=false;AR._clearActiveItem();}}}});D.namespace("Plugin");D.Plugin.NodeMenuNav=AK;},"3.0.0",{requires:["node","classnamemanager","node-focusmanager"]}); \ No newline at end of file diff --git a/include/javascript/yui3/build/node-menunav/node-menunav.js b/include/javascript/yui3/build/node-menunav/node-menunav.js new file mode 100644 index 00000000..9773474a --- /dev/null +++ b/include/javascript/yui3/build/node-menunav/node-menunav.js @@ -0,0 +1,74 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add('node-menunav',function(Y){var UA=Y.UA,later=Y.later,getClassName=Y.ClassNameManager.getClassName,MENU="menu",MENUITEM="menuitem",HIDDEN="hidden",PARENT_NODE="parentNode",CHILDREN="children",OFFSET_HEIGHT="offsetHeight",OFFSET_WIDTH="offsetWidth",PX="px",ID="id",PERIOD=".",HANDLED_MOUSEOUT="handledMouseOut",HANDLED_MOUSEOVER="handledMouseOver",ACTIVE="active",LABEL="label",LOWERCASE_A="a",MOUSEDOWN="mousedown",KEYDOWN="keydown",CLICK="click",EMPTY_STRING="",FIRST_OF_TYPE="first-of-type",ROLE="role",PRESENTATION="presentation",DESCENDANTS="descendants",UI="UI",ACTIVE_DESCENDANT="activeDescendant",USE_ARIA="useARIA",ARIA_HIDDEN="aria-hidden",CONTENT="content",HOST="host",ACTIVE_DESCENDANT_CHANGE=ACTIVE_DESCENDANT+"Change",STANDARD_QUERY=">.yui-menu-content>ul>li>a",EXTENDED_QUERY=">.yui-menu-content>ul>li>.yui-menu-label>a:first-child",AUTO_SUBMENU_DISPLAY="autoSubmenuDisplay",MOUSEOUT_HIDE_DELAY="mouseOutHideDelay",CSS_MENU=getClassName(MENU),CSS_MENU_HIDDEN=getClassName(MENU,HIDDEN),CSS_MENU_HORIZONTAL=getClassName(MENU,"horizontal"),CSS_MENU_LABEL=getClassName(MENU,LABEL),CSS_MENU_LABEL_ACTIVE=getClassName(MENU,LABEL,ACTIVE),CSS_MENU_LABEL_MENUVISIBLE=getClassName(MENU,LABEL,(MENU+"visible")),CSS_MENUITEM=getClassName(MENUITEM),CSS_MENUITEM_ACTIVE=getClassName(MENUITEM,ACTIVE),MENU_SELECTOR=PERIOD+CSS_MENU,MENU_TOGGLE_SELECTOR=(PERIOD+getClassName(MENU,"toggle"));var getPreviousSibling=function(node){var oPrevious=node.previous(),oChildren;if(!oPrevious){oChildren=node.get(PARENT_NODE).get(CHILDREN);oPrevious=oChildren.item(oChildren.size()-1);} +return oPrevious;};var getNextSibling=function(node){var oNext=node.next();if(!oNext){oNext=node.get(PARENT_NODE).get(CHILDREN).item(0);} +return oNext;};var isAnchor=function(node){var bReturnVal=false;if(node){bReturnVal=node.get("nodeName").toLowerCase()===LOWERCASE_A;} +return bReturnVal;};var isMenuItem=function(node){return node.hasClass(CSS_MENUITEM);};var isMenuLabel=function(node){return node.hasClass(CSS_MENU_LABEL);};var isHorizontalMenu=function(menu){return menu.hasClass(CSS_MENU_HORIZONTAL);};var hasVisibleSubmenu=function(menuLabel){return menuLabel.hasClass(CSS_MENU_LABEL_MENUVISIBLE);};var getItemAnchor=function(node){return isAnchor(node)?node:node.one(LOWERCASE_A);};var getNodeWithClass=function(node,className,searchAncestors){var oItem;if(node){if(node.hasClass(className)){oItem=node;} +if(!oItem&&searchAncestors){oItem=node.ancestor((PERIOD+className));}} +return oItem;};var getParentMenu=function(node){return node.ancestor(MENU_SELECTOR);};var getMenu=function(node,searchAncestors){return getNodeWithClass(node,CSS_MENU,searchAncestors);};var getMenuItem=function(node,searchAncestors){var oItem;if(node){oItem=getNodeWithClass(node,CSS_MENUITEM,searchAncestors);} +return oItem;};var getMenuLabel=function(node,searchAncestors){var oItem;if(node){if(searchAncestors){oItem=getNodeWithClass(node,CSS_MENU_LABEL,searchAncestors);} +else{oItem=getNodeWithClass(node,CSS_MENU_LABEL)||node.one((PERIOD+CSS_MENU_LABEL));}} +return oItem;};var getItem=function(node,searchAncestors){var oItem;if(node){oItem=getMenuItem(node,searchAncestors)||getMenuLabel(node,searchAncestors);} +return oItem;};var getFirstItem=function(menu){return getItem(menu.one("li"));};var getActiveClass=function(node){return isMenuItem(node)?CSS_MENUITEM_ACTIVE:CSS_MENU_LABEL_ACTIVE;};var handleMouseOverForNode=function(node,target){return node&&!node[HANDLED_MOUSEOVER]&&(node.compareTo(target)||node.contains(target));};var handleMouseOutForNode=function(node,relatedTarget){return node&&!node[HANDLED_MOUSEOUT]&&(!node.compareTo(relatedTarget)&&!node.contains(relatedTarget));};var NodeMenuNav=function(){NodeMenuNav.superclass.constructor.apply(this,arguments);};NodeMenuNav.NAME="nodeMenuNav";NodeMenuNav.NS="menuNav";NodeMenuNav.SHIM_TEMPLATE_TITLE="Menu Stacking Shim";NodeMenuNav.SHIM_TEMPLATE='';NodeMenuNav.ATTRS={useARIA:{value:true,writeOnce:true,lazyAdd:false,setter:function(value){var oMenu=this.get(HOST),oMenuLabel,oMenuToggle,oSubmenu,sID;if(value){oMenu.set(ROLE,MENU);oMenu.all("ul,li,."+getClassName(MENU,CONTENT)).set(ROLE,PRESENTATION);oMenu.all((PERIOD+getClassName(MENUITEM,CONTENT))).set(ROLE,MENUITEM);oMenu.all((PERIOD+CSS_MENU_LABEL)).each(function(node){oMenuLabel=node;oMenuToggle=node.one(MENU_TOGGLE_SELECTOR);if(oMenuToggle){oMenuToggle.set(ROLE,PRESENTATION);oMenuLabel=oMenuToggle.previous();} +oMenuLabel.set(ROLE,MENUITEM);oMenuLabel.set("aria-haspopup",true);oSubmenu=node.next();if(oSubmenu){oSubmenu.set(ROLE,MENU);oMenuLabel=oSubmenu.previous();oMenuToggle=oMenuLabel.one(MENU_TOGGLE_SELECTOR);if(oMenuToggle){oMenuLabel=oMenuToggle;} +sID=Y.stamp(oMenuLabel);if(!oMenuLabel.get(ID)){oMenuLabel.set(ID,sID);} +oSubmenu.set("aria-labelledby",sID);oSubmenu.set(ARIA_HIDDEN,true);}});}}},autoSubmenuDisplay:{value:true,writeOnce:true},submenuShowDelay:{value:250,writeOnce:true},submenuHideDelay:{value:250,writeOnce:true},mouseOutHideDelay:{value:750,writeOnce:true}};Y.extend(NodeMenuNav,Y.Plugin.Base,{_rootMenu:null,_activeItem:null,_activeMenu:null,_hasFocus:false,_blockMouseEvent:false,_currentMouseX:0,_movingToSubmenu:false,_showSubmenuTimer:null,_hideSubmenuTimer:null,_hideAllSubmenusTimer:null,_firstItem:null,initializer:function(config){var menuNav=this,oRootMenu=this.get(HOST),aHandlers=[],oDoc;if(oRootMenu){menuNav._rootMenu=oRootMenu;oRootMenu.all("ul:first-child").addClass(FIRST_OF_TYPE);oRootMenu.all(MENU_SELECTOR).addClass(CSS_MENU_HIDDEN);aHandlers.push(oRootMenu.on("mouseover",menuNav._onMouseOver,menuNav));aHandlers.push(oRootMenu.on("mouseout",menuNav._onMouseOut,menuNav));aHandlers.push(oRootMenu.on("mousemove",menuNav._onMouseMove,menuNav));aHandlers.push(oRootMenu.on(MOUSEDOWN,menuNav._toggleSubmenuDisplay,menuNav));aHandlers.push(Y.on("key",menuNav._toggleSubmenuDisplay,oRootMenu,"down:13",menuNav));aHandlers.push(oRootMenu.on(CLICK,menuNav._toggleSubmenuDisplay,menuNav));aHandlers.push(oRootMenu.on("keypress",menuNav._onKeyPress,menuNav));aHandlers.push(oRootMenu.on(KEYDOWN,menuNav._onKeyDown,menuNav));oDoc=oRootMenu.get("ownerDocument");aHandlers.push(oDoc.on(MOUSEDOWN,menuNav._onDocMouseDown,menuNav));aHandlers.push(oDoc.on("focus",menuNav._onDocFocus,menuNav));this._eventHandlers=aHandlers;menuNav._initFocusManager();}},destructor:function(){var aHandlers=this._eventHandlers;if(aHandlers){Y.Array.each(aHandlers,function(handle){handle.detach();});this._eventHandlers=null;} +this.get(HOST).unplug("focusManager");},_isRoot:function(menu){return this._rootMenu.compareTo(menu);},_getTopmostSubmenu:function(menu){var menuNav=this,oMenu=getParentMenu(menu),returnVal;if(!oMenu){returnVal=menu;} +else if(menuNav._isRoot(oMenu)){returnVal=menu;} +else{returnVal=menuNav._getTopmostSubmenu(oMenu);} +return returnVal;},_clearActiveItem:function(){var menuNav=this,oActiveItem=menuNav._activeItem;if(oActiveItem){oActiveItem.removeClass(getActiveClass(oActiveItem));} +menuNav._activeItem=null;},_setActiveItem:function(item){var menuNav=this;if(item){menuNav._clearActiveItem();item.addClass(getActiveClass(item));menuNav._activeItem=item;}},_focusItem:function(item){var menuNav=this,oMenu,oItem;if(item&&menuNav._hasFocus){oMenu=getParentMenu(item);oItem=getItemAnchor(item);if(oMenu&&!oMenu.compareTo(menuNav._activeMenu)){menuNav._activeMenu=oMenu;menuNav._initFocusManager();} +menuNav._focusManager.focus(oItem);}},_showMenu:function(menu){var oParentMenu=getParentMenu(menu),oLI=menu.get(PARENT_NODE),aXY=oLI.getXY();if(this.get(USE_ARIA)){menu.set(ARIA_HIDDEN,false);} +if(isHorizontalMenu(oParentMenu)){aXY[1]=aXY[1]+oLI.get(OFFSET_HEIGHT);} +else{aXY[0]=aXY[0]+oLI.get(OFFSET_WIDTH);} +menu.setXY(aXY);if(UA.ie<8){if(UA.ie===6&&!menu.hasIFrameShim){menu.appendChild(Y.Node.create(NodeMenuNav.SHIM_TEMPLATE));menu.hasIFrameShim=true;} +menu.setStyles({height:EMPTY_STRING,width:EMPTY_STRING});menu.setStyles({height:(menu.get(OFFSET_HEIGHT)+PX),width:(menu.get(OFFSET_WIDTH)+PX)});} +menu.previous().addClass(CSS_MENU_LABEL_MENUVISIBLE);menu.removeClass(CSS_MENU_HIDDEN);},_hideMenu:function(menu,activateAndFocusLabel){var menuNav=this,oLabel=menu.previous(),oActiveItem;oLabel.removeClass(CSS_MENU_LABEL_MENUVISIBLE);if(activateAndFocusLabel){menuNav._focusItem(oLabel);menuNav._setActiveItem(oLabel);} +oActiveItem=menu.one((PERIOD+CSS_MENUITEM_ACTIVE));if(oActiveItem){oActiveItem.removeClass(CSS_MENUITEM_ACTIVE);} +menu.setStyles({left:EMPTY_STRING,top:EMPTY_STRING});menu.addClass(CSS_MENU_HIDDEN);if(menuNav.get(USE_ARIA)){menu.set(ARIA_HIDDEN,true);}},_hideAllSubmenus:function(menu){var menuNav=this;menu.all(MENU_SELECTOR).each(Y.bind(function(submenuNode){menuNav._hideMenu(submenuNode);},menuNav));},_cancelShowSubmenuTimer:function(){var menuNav=this,oShowSubmenuTimer=menuNav._showSubmenuTimer;if(oShowSubmenuTimer){oShowSubmenuTimer.cancel();menuNav._showSubmenuTimer=null;}},_cancelHideSubmenuTimer:function(){var menuNav=this,oHideSubmenuTimer=menuNav._hideSubmenuTimer;if(oHideSubmenuTimer){oHideSubmenuTimer.cancel();menuNav._hideSubmenuTimer=null;}},_initFocusManager:function(){var menuNav=this,oRootMenu=menuNav._rootMenu,oMenu=menuNav._activeMenu||oRootMenu,sSelectorBase=menuNav._isRoot(oMenu)?EMPTY_STRING:("#"+oMenu.get("id")),oFocusManager=menuNav._focusManager,sKeysVal,sDescendantSelector,sQuery;if(isHorizontalMenu(oMenu)){sDescendantSelector=sSelectorBase+STANDARD_QUERY+","+ +sSelectorBase+EXTENDED_QUERY;sKeysVal={next:"down:39",previous:"down:37"};} +else{sDescendantSelector=sSelectorBase+STANDARD_QUERY;sKeysVal={next:"down:40",previous:"down:38"};} +if(!oFocusManager){oRootMenu.plug(Y.Plugin.NodeFocusManager,{descendants:sDescendantSelector,keys:sKeysVal,circular:true});oFocusManager=oRootMenu.focusManager;sQuery="#"+oRootMenu.get("id")+" .yui-menu a,"+ +MENU_TOGGLE_SELECTOR;oRootMenu.all(sQuery).set("tabIndex",-1);oFocusManager.on(ACTIVE_DESCENDANT_CHANGE,this._onActiveDescendantChange,oFocusManager,this);oFocusManager.after(ACTIVE_DESCENDANT_CHANGE,this._afterActiveDescendantChange,oFocusManager,this);menuNav._focusManager=oFocusManager;} +else{oFocusManager.set(ACTIVE_DESCENDANT,-1);oFocusManager.set(DESCENDANTS,sDescendantSelector);oFocusManager.set("keys",sKeysVal);}},_onActiveDescendantChange:function(event,menuNav){if(event.src===UI&&menuNav._activeMenu&&!menuNav._movingToSubmenu){menuNav._hideAllSubmenus(menuNav._activeMenu);}},_afterActiveDescendantChange:function(event,menuNav){var oItem;if(event.src===UI){oItem=getItem(this.get(DESCENDANTS).item(event.newVal),true);menuNav._setActiveItem(oItem);}},_onDocFocus:function(event){var menuNav=this,oActiveItem=menuNav._activeItem,oTarget=event.target,oMenu;if(menuNav._rootMenu.contains(oTarget)){if(menuNav._hasFocus){oMenu=getParentMenu(oTarget);if(!menuNav._activeMenu.compareTo(oMenu)){menuNav._activeMenu=oMenu;menuNav._initFocusManager();menuNav._focusManager.set(ACTIVE_DESCENDANT,oTarget);menuNav._setActiveItem(getItem(oTarget,true));}} +else{menuNav._hasFocus=true;oActiveItem=getItem(oTarget,true);if(oActiveItem){menuNav._setActiveItem(oActiveItem);}}} +else{menuNav._clearActiveItem();menuNav._cancelShowSubmenuTimer();menuNav._hideAllSubmenus(menuNav._rootMenu);menuNav._activeMenu=menuNav._rootMenu;menuNav._initFocusManager();menuNav._focusManager.set(ACTIVE_DESCENDANT,0);menuNav._hasFocus=false;}},_onMenuMouseOver:function(menu,event){var menuNav=this,oHideAllSubmenusTimer=menuNav._hideAllSubmenusTimer;if(oHideAllSubmenusTimer){oHideAllSubmenusTimer.cancel();menuNav._hideAllSubmenusTimer=null;} +menuNav._cancelHideSubmenuTimer();if(menu&&!menu.compareTo(menuNav._activeMenu)){menuNav._activeMenu=menu;if(menuNav._hasFocus){menuNav._initFocusManager();}} +if(menuNav._movingToSubmenu&&isHorizontalMenu(menu)){menuNav._movingToSubmenu=false;}},_hideAndFocusLabel:function(){var menuNav=this,oActiveMenu=menuNav._activeMenu,oSubmenu;menuNav._hideAllSubmenus(menuNav._rootMenu);if(oActiveMenu){oSubmenu=menuNav._getTopmostSubmenu(oActiveMenu);menuNav._focusItem(oSubmenu.previous());}},_onMenuMouseOut:function(menu,event){var menuNav=this,oActiveMenu=menuNav._activeMenu,oRelatedTarget=event.relatedTarget,oActiveItem=menuNav._activeItem,oParentMenu,oMenu;if(oActiveMenu&&!oActiveMenu.contains(oRelatedTarget)){oParentMenu=getParentMenu(oActiveMenu);if(oParentMenu&&!oParentMenu.contains(oRelatedTarget)){if(menuNav.get(MOUSEOUT_HIDE_DELAY)>0){menuNav._cancelShowSubmenuTimer();menuNav._hideAllSubmenusTimer=later(menuNav.get(MOUSEOUT_HIDE_DELAY),menuNav,menuNav._hideAndFocusLabel);}} +else{if(oActiveItem){oMenu=getParentMenu(oActiveItem);if(!menuNav._isRoot(oMenu)){menuNav._focusItem(oMenu.previous());}}}}},_onMenuLabelMouseOver:function(menuLabel,event){var menuNav=this,oActiveMenu=menuNav._activeMenu,bIsRoot=menuNav._isRoot(oActiveMenu),bUseAutoSubmenuDisplay=(menuNav.get(AUTO_SUBMENU_DISPLAY)&&bIsRoot||!bIsRoot),oSubmenu;menuNav._focusItem(menuLabel);menuNav._setActiveItem(menuLabel);if(bUseAutoSubmenuDisplay&&!menuNav._movingToSubmenu){menuNav._cancelHideSubmenuTimer();menuNav._cancelShowSubmenuTimer();if(!hasVisibleSubmenu(menuLabel)){oSubmenu=menuLabel.next();if(oSubmenu){menuNav._hideAllSubmenus(oActiveMenu);menuNav._showSubmenuTimer=later(menuNav.get("submenuShowDelay"),menuNav,menuNav._showMenu,oSubmenu);}}}},_onMenuLabelMouseOut:function(menuLabel,event){var menuNav=this,bIsRoot=menuNav._isRoot(menuNav._activeMenu),bUseAutoSubmenuDisplay=(menuNav.get(AUTO_SUBMENU_DISPLAY)&&bIsRoot||!bIsRoot),oRelatedTarget=event.relatedTarget,oSubmenu=menuLabel.next();menuNav._clearActiveItem();if(bUseAutoSubmenuDisplay){if(menuNav._movingToSubmenu&&!menuNav._showSubmenuTimer&&oSubmenu){menuNav._hideSubmenuTimer=later(menuNav.get("submenuHideDelay"),menuNav,menuNav._hideMenu,oSubmenu);} +else if(!menuNav._movingToSubmenu&&oSubmenu&&!oSubmenu.contains(oRelatedTarget)&&!oRelatedTarget.compareTo(oSubmenu)){menuNav._cancelShowSubmenuTimer();menuNav._hideMenu(oSubmenu);}}},_onMenuItemMouseOver:function(menuItem,event){var menuNav=this,oActiveMenu=menuNav._activeMenu,bIsRoot=menuNav._isRoot(oActiveMenu),bUseAutoSubmenuDisplay=(menuNav.get(AUTO_SUBMENU_DISPLAY)&&bIsRoot||!bIsRoot);menuNav._focusItem(menuItem);menuNav._setActiveItem(menuItem);if(bUseAutoSubmenuDisplay&&!menuNav._movingToSubmenu){menuNav._hideAllSubmenus(oActiveMenu);}},_onMenuItemMouseOut:function(menuItem,event){this._clearActiveItem();},_onVerticalMenuKeyDown:function(event){var menuNav=this,oActiveMenu=menuNav._activeMenu,oRootMenu=menuNav._rootMenu,oTarget=event.target,bPreventDefault=false,nKeyCode=event.keyCode,oSubmenu,oParentMenu,oLI,oItem;switch(nKeyCode){case 37:oParentMenu=getParentMenu(oActiveMenu);if(oParentMenu&&isHorizontalMenu(oParentMenu)){menuNav._hideMenu(oActiveMenu);oLI=getPreviousSibling(oActiveMenu.get(PARENT_NODE));oItem=getItem(oLI);if(oItem){if(isMenuLabel(oItem)){oSubmenu=oItem.next();if(oSubmenu){menuNav._showMenu(oSubmenu);menuNav._focusItem(getFirstItem(oSubmenu));menuNav._setActiveItem(getFirstItem(oSubmenu));} +else{menuNav._focusItem(oItem);menuNav._setActiveItem(oItem);}} +else{menuNav._focusItem(oItem);menuNav._setActiveItem(oItem);}}} +else if(!menuNav._isRoot(oActiveMenu)){menuNav._hideMenu(oActiveMenu,true);} +bPreventDefault=true;break;case 39:if(isMenuLabel(oTarget)){oSubmenu=oTarget.next();if(oSubmenu){menuNav._showMenu(oSubmenu);menuNav._focusItem(getFirstItem(oSubmenu));menuNav._setActiveItem(getFirstItem(oSubmenu));}} +else if(isHorizontalMenu(oRootMenu)){oSubmenu=menuNav._getTopmostSubmenu(oActiveMenu);oLI=getNextSibling(oSubmenu.get(PARENT_NODE));oItem=getItem(oLI);menuNav._hideAllSubmenus(oRootMenu);if(oItem){if(isMenuLabel(oItem)){oSubmenu=oItem.next();if(oSubmenu){menuNav._showMenu(oSubmenu);menuNav._focusItem(getFirstItem(oSubmenu));menuNav._setActiveItem(getFirstItem(oSubmenu));} +else{menuNav._focusItem(oItem);menuNav._setActiveItem(oItem);}} +else{menuNav._focusItem(oItem);menuNav._setActiveItem(oItem);}}} +bPreventDefault=true;break;} +if(bPreventDefault){event.preventDefault();}},_onHorizontalMenuKeyDown:function(event){var menuNav=this,oActiveMenu=menuNav._activeMenu,oTarget=event.target,oFocusedItem=getItem(oTarget,true),bPreventDefault=false,nKeyCode=event.keyCode,oSubmenu;if(nKeyCode===40){menuNav._hideAllSubmenus(oActiveMenu);if(isMenuLabel(oFocusedItem)){oSubmenu=oFocusedItem.next();if(oSubmenu){menuNav._showMenu(oSubmenu);menuNav._focusItem(getFirstItem(oSubmenu));menuNav._setActiveItem(getFirstItem(oSubmenu));} +bPreventDefault=true;}} +if(bPreventDefault){event.preventDefault();}},_onMouseMove:function(event){var menuNav=this;later(10,menuNav,function(){menuNav._currentMouseX=event.pageX;});},_onMouseOver:function(event){var menuNav=this,oTarget,oMenu,oMenuLabel,oParentMenu,oMenuItem;if(menuNav._blockMouseEvent){menuNav._blockMouseEvent=false;} +else{oTarget=event.target;oMenu=getMenu(oTarget,true);oMenuLabel=getMenuLabel(oTarget,true);oMenuItem=getMenuItem(oTarget,true);if(handleMouseOverForNode(oMenu,oTarget)){menuNav._onMenuMouseOver(oMenu,event);oMenu[HANDLED_MOUSEOVER]=true;oMenu[HANDLED_MOUSEOUT]=false;oParentMenu=getParentMenu(oMenu);if(oParentMenu){oParentMenu[HANDLED_MOUSEOUT]=true;oParentMenu[HANDLED_MOUSEOVER]=false;}} +if(handleMouseOverForNode(oMenuLabel,oTarget)){menuNav._onMenuLabelMouseOver(oMenuLabel,event);oMenuLabel[HANDLED_MOUSEOVER]=true;oMenuLabel[HANDLED_MOUSEOUT]=false;} +if(handleMouseOverForNode(oMenuItem,oTarget)){menuNav._onMenuItemMouseOver(oMenuItem,event);oMenuItem[HANDLED_MOUSEOVER]=true;oMenuItem[HANDLED_MOUSEOUT]=false;}}},_onMouseOut:function(event){var menuNav=this,oActiveMenu=menuNav._activeMenu,bMovingToSubmenu=false,oTarget,oRelatedTarget,oMenu,oMenuLabel,oSubmenu,oMenuItem;menuNav._movingToSubmenu=(oActiveMenu&&!isHorizontalMenu(oActiveMenu)&&((event.pageX-5)>menuNav._currentMouseX));oTarget=event.target;oRelatedTarget=event.relatedTarget;oMenu=getMenu(oTarget,true);oMenuLabel=getMenuLabel(oTarget,true);oMenuItem=getMenuItem(oTarget,true);if(handleMouseOutForNode(oMenuLabel,oRelatedTarget)){menuNav._onMenuLabelMouseOut(oMenuLabel,event);oMenuLabel[HANDLED_MOUSEOUT]=true;oMenuLabel[HANDLED_MOUSEOVER]=false;} +if(handleMouseOutForNode(oMenuItem,oRelatedTarget)){menuNav._onMenuItemMouseOut(oMenuItem,event);oMenuItem[HANDLED_MOUSEOUT]=true;oMenuItem[HANDLED_MOUSEOVER]=false;} +if(oMenuLabel){oSubmenu=oMenuLabel.next();if(oSubmenu&&(oRelatedTarget.compareTo(oSubmenu)||oSubmenu.contains(oRelatedTarget))){bMovingToSubmenu=true;}} +if(handleMouseOutForNode(oMenu,oRelatedTarget)||bMovingToSubmenu){menuNav._onMenuMouseOut(oMenu,event);oMenu[HANDLED_MOUSEOUT]=true;oMenu[HANDLED_MOUSEOVER]=false;}},_toggleSubmenuDisplay:function(event){var menuNav=this,oTarget=event.target,oMenuLabel=getMenuLabel(oTarget,true),sType=event.type,oAnchor,oSubmenu,sHref,nHashPos,nLen,sId;if(oMenuLabel){oAnchor=isAnchor(oTarget)?oTarget:oTarget.ancestor(isAnchor);if(oAnchor){sHref=oAnchor.getAttribute("href",2);nHashPos=sHref.indexOf("#");nLen=sHref.length;if(nHashPos===0&&nLen>1){sId=sHref.substr(1,nLen);oSubmenu=oMenuLabel.next();if(oSubmenu&&(oSubmenu.get(ID)===sId)){if(sType===MOUSEDOWN||sType===KEYDOWN){if((UA.opera||UA.gecko||UA.ie)&&sType===KEYDOWN&&!menuNav._preventClickHandle){menuNav._preventClickHandle=menuNav._rootMenu.on("click",function(event){event.preventDefault();menuNav._preventClickHandle.detach();menuNav._preventClickHandle=null;});} +if(sType==MOUSEDOWN){event.preventDefault();event.stopImmediatePropagation();menuNav._hasFocus=true;} +if(menuNav._isRoot(getParentMenu(oTarget))){if(hasVisibleSubmenu(oMenuLabel)){menuNav._hideMenu(oSubmenu);menuNav._focusItem(oMenuLabel);menuNav._setActiveItem(oMenuLabel);} +else{menuNav._hideAllSubmenus(menuNav._rootMenu);menuNav._showMenu(oSubmenu);menuNav._focusItem(getFirstItem(oSubmenu));menuNav._setActiveItem(getFirstItem(oSubmenu));}} +else{if(menuNav._activeItem==oMenuLabel){menuNav._showMenu(oSubmenu);menuNav._focusItem(getFirstItem(oSubmenu));menuNav._setActiveItem(getFirstItem(oSubmenu));} +else{if(!oMenuLabel._clickHandle){oMenuLabel._clickHandle=oMenuLabel.on("click",function(){menuNav._hideAllSubmenus(menuNav._rootMenu);menuNav._hasFocus=false;menuNav._clearActiveItem();oMenuLabel._clickHandle.detach();oMenuLabel._clickHandle=null;});}}}} +if(sType===CLICK){event.preventDefault();}}}}}},_onKeyPress:function(event){switch(event.keyCode){case 37:case 38:case 39:case 40:event.preventDefault();break;}},_onKeyDown:function(event){var menuNav=this,oActiveItem=menuNav._activeItem,oTarget=event.target,oActiveMenu=getParentMenu(oTarget),oSubmenu;if(oActiveMenu){menuNav._activeMenu=oActiveMenu;if(isHorizontalMenu(oActiveMenu)){menuNav._onHorizontalMenuKeyDown(event);} +else{menuNav._onVerticalMenuKeyDown(event);} +if(event.keyCode===27){if(!menuNav._isRoot(oActiveMenu)){if(UA.opera){later(0,menuNav,function(){menuNav._hideMenu(oActiveMenu,true);});} +else{menuNav._hideMenu(oActiveMenu,true);} +event.stopPropagation();menuNav._blockMouseEvent=UA.gecko?true:false;} +else if(oActiveItem){if(isMenuLabel(oActiveItem)&&hasVisibleSubmenu(oActiveItem)){oSubmenu=oActiveItem.next();if(oSubmenu){menuNav._hideMenu(oSubmenu);}} +else{menuNav._focusManager.blur();menuNav._clearActiveItem();menuNav._hasFocus=false;}}}}},_onDocMouseDown:function(event){var menuNav=this,oRoot=menuNav._rootMenu,oTarget=event.target;if(!(oRoot.compareTo(oTarget)||oRoot.contains(oTarget))){menuNav._hideAllSubmenus(oRoot);if(UA.webkit){menuNav._hasFocus=false;menuNav._clearActiveItem();}}}});Y.namespace('Plugin');Y.Plugin.NodeMenuNav=NodeMenuNav;},'3.0.0',{requires:['node','classnamemanager','node-focusmanager']}); \ No newline at end of file diff --git a/include/javascript/yui3/build/node/node-aria-min.js b/include/javascript/yui3/build/node/node-aria-min.js new file mode 100644 index 00000000..e11bdae4 --- /dev/null +++ b/include/javascript/yui3/build/node/node-aria-min.js @@ -0,0 +1,8 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add("node-aria",function(A){A.Node.re_aria=/^(?:role$|aria-)/;A.Node.prototype._addAriaAttr=function(B){this.addAttr(B,{getter:function(){return A.Node.getDOMNode(this).getAttribute(B,2);},setter:function(C){A.Node.getDOMNode(this).setAttribute(B,C);return C;}});};},"3.0.0",{requires:["node-base"]}); \ No newline at end of file diff --git a/include/javascript/yui3/build/node/node-aria.js b/include/javascript/yui3/build/node/node-aria.js new file mode 100644 index 00000000..e1b5ddb4 --- /dev/null +++ b/include/javascript/yui3/build/node/node-aria.js @@ -0,0 +1,9 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add('node-aria',function(Y){Y.Node.prototype.get=function(name){var val;if(re_aria.test(name)){val=Y.Node.getDOMNode(this).getAttribute(name,2);}else{} +setter:function(val){Y.Node.getDOMNode(this).setAttribute(name,val);return val;}});};},'3.0.0',{requires:['node-base']}); \ No newline at end of file diff --git a/include/javascript/yui3/build/node/node-base-min.js b/include/javascript/yui3/build/node/node-base-min.js new file mode 100644 index 00000000..99e523d1 --- /dev/null +++ b/include/javascript/yui3/build/node/node-base-min.js @@ -0,0 +1,8 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add("node-base",function(C){var G=".",E="nodeName",I="nodeType",B="ownerDocument",H="tagName",D="_yuid",F=function(L){var K=L[D];if(K&&F._instances[K]&&F._instances[K]._node!==L){L[D]=null;}K=C.stamp(L);if(!K){K=C.guid();}this[D]=K;this._node=L;F._instances[K]=this;this._stateProxy=L;if(this._initPlugins){this._initPlugins();}},J=function(L){var K=null;if(L){K=(typeof L==="string")?function(M){return C.Selector.test(M,L);}:function(M){return L(F.get(M));};}return K;};F.NAME="Node";F.re_aria=/^(?:role$|aria-)/;F.DOM_EVENTS={abort:true,beforeunload:true,blur:true,change:true,click:true,close:true,command:true,contextmenu:true,drag:true,dragstart:true,dragenter:true,dragover:true,dragleave:true,dragend:true,drop:true,dblclick:true,error:true,focus:true,keydown:true,keypress:true,keyup:true,load:true,message:true,mousedown:true,mousemove:true,mouseout:true,mouseover:true,mouseup:true,mousemultiwheel:true,mousewheel:true,submit:true,mouseenter:true,mouseleave:true,scroll:true,reset:true,resize:true,select:true,textInput:true,unload:true};C.mix(F.DOM_EVENTS,C.Env.evt.plugins);F._instances={};F.getDOMNode=function(K){if(K){return(K.nodeType)?K:K._node||null;}return null;};F.scrubVal=function(L,K){if(K&&L){if(typeof L==="object"||typeof L==="function"){if(I in L||C.DOM.isWindow(L)){L=F.get(L);}else{if((L.item&&!L._nodes)||(L[0]&&L[0][I])){L=C.all(L);}}}}else{if(L===undefined){L=K;}}return L;};F.addMethod=function(K,M,L){if(K&&M&&typeof M==="function"){F.prototype[K]=function(){L=L||this;var O=C.Array(arguments),N;if(O[0]&&O[0]instanceof F){O[0]=O[0]._node;}if(O[1]&&O[1]instanceof F){O[1]=O[1]._node;}O.unshift(this._node);N=F.scrubVal(M.apply(L,O),this);return N;};}else{}};F.importMethod=function(M,K,L){if(typeof K==="string"){L=L||K;F.addMethod(L,M[K],M);}else{C.each(K,function(N){F.importMethod(M,N);});}};F.one=function(N){var K=null,M,L;if(N){if(typeof N==="string"){if(N.indexOf("doc")===0){N=C.config.doc;}else{if(N.indexOf("win")===0){N=C.config.win;}else{N=C.Selector.query(N,null,true);}}if(!N){return null;}}else{if(N instanceof F){return N;}}L=N._yuid;K=F._instances[L];M=K?K._node:null;if(!K||(M&&N!==M)){K=new F(N);}}return K;};F.get=function(){return F.one.apply(F,arguments);};F.create=function(){return F.get(C.DOM.create.apply(C.DOM,arguments));};F.ATTRS={text:{getter:function(){return C.DOM.getText(this._node);},setter:function(K){C.DOM.setText(this._node,K);return K;}},"options":{getter:function(){return this._node.getElementsByTagName("option");}},"elements":{getter:function(){return C.all(this._node.elements);}},"children":{getter:function(){var N=this._node,M=N.children,O,L,K;if(!M){O=N.childNodes;M=[];for(L=0,K=O.length;L-1){N=K;K=K.split(G);C.Object.setValue(L,K,M);}else{if(L[K]!==undefined){L[K]=M;}}return M;};F.DEFAULT_GETTER=function(K){var L=this._stateProxy,M;if(K.indexOf&&K.indexOf(G)>-1){M=C.Object.getValue(L,K.split(G));}else{if(L[K]!==undefined){M=L[K];}}return M;};C.augment(F,C.Event.Target);C.mix(F.prototype,{toString:function(){var M="",L=this[D]+": not bound to a node",K=this._node;if(K){M+=K[E];if(K.id){M+="#"+K.id;}if(K.className){M+="."+K.className.replace(" ",".");}M+=" "+this[D];}return M||L;},get:function(K){var L;if(this._getAttr){L=this._getAttr(K);}else{L=this._get(K);}if(L){L=C.Node.scrubVal(L,this);}return L;},_get:function(K){var L=F.ATTRS[K],M;if(L&&L.getter){M=L.getter.call(this);}else{if(F.re_aria.test(K)){M=this._node.getAttribute(K,2);}else{M=F.DEFAULT_GETTER.apply(this,arguments);}}return M;},set:function(K,M){var L=F.ATTRS[K];if(this._setAttr){this._setAttr.apply(this,arguments);}else{if(L&&L.setter){L.setter.call(this,M);}else{if(F.re_aria.test(K)){this._node.setAttribute(K,M);}else{F.DEFAULT_SETTER.apply(this,arguments);}}}return this;},setAttrs:function(K){if(this._setAttrs){this._setAttrs(K);}else{C.Object.each(K,function(L,M){this.set(M,L);},this);}return this;},getAttrs:function(L){var K={};if(this._getAttrs){this._getAttrs(L);}else{C.Array.each(L,function(M,N){K[M]=this.get(M);},this);}return K;},create:F.create,compareTo:function(K){var L=this._node;if(K instanceof C.Node){K=K._node;}return L===K;},inDoc:function(L){var K=this._node;L=(L)?L._node||L:K[B];if(L.documentElement){return C.DOM.contains(L.documentElement,K);}},getById:function(M){var L=this._node,K=C.DOM.byId(M,L[B]);if(K&&C.DOM.contains(L,K)){K=C.one(K);}else{K=null;}return K;},ancestor:function(K){return F.get(C.DOM.elementByAxis(this._node,"parentNode",J(K)));},previous:function(L,K){return F.get(C.DOM.elementByAxis(this._node,"previousSibling",J(L),K));},next:function(M,L,K){return F.get(C.DOM.elementByAxis(this._node,"nextSibling",J(L),K));},one:function(K){return C.one(C.Selector.query(K,this._node,true));},query:function(K){return this.one(K);},all:function(K){var L=C.all(C.Selector.query(K,this._node));L._query=K;return L;},queryAll:function(K){return this.all(K);},test:function(K){return C.Selector.test(this._node,K);},remove:function(K){var L=this._node;L.parentNode.removeChild(L);if(K){this.destroy(true);}return this;},replace:function(K){var L=this._node;L.parentNode.replaceChild(K,L);return this;},purge:function(L,K){C.Event.purgeElement(this._node,L,K);},destroy:function(K){delete F._instances[this[D]];if(K){this.purge(true);}if(this.unplug){this.unplug();}this._node._yuid=null;this._node=null;this._stateProxy=null;},invoke:function(R,L,K,Q,P,O){var N=this._node,M;if(L&&L instanceof C.Node){L=L._node;}if(K&&K instanceof C.Node){K=K._node;}M=N[R](L,K,Q,P,O);return C.Node.scrubVal(M,this);},each:function(L,K){K=K||this;return L.call(K,this);},item:function(K){return this;},size:function(){return this._node?1:0;},insert:function(M,K){var L=this._node;if(M){if(typeof K==="number"){K=this._node.childNodes[K];}if(typeof M!=="string"){if(M._node){M=M._node;}else{if(M._nodes||(!M.nodeType&&M.length)){C.each(M._nodes,function(N){C.DOM.addHTML(L,N,K);});return this;}}}C.DOM.addHTML(L,M,K);}return this;},prepend:function(K){return this.insert(K,0);},append:function(K){return this.insert(K,null);},setContent:function(K){C.DOM.addHTML(this._node,K,"replace");return this;},hasMethod:function(L){var K=this._node;return(K&&(typeof K==="function"));}},true);C.Node=F;C.get=C.Node.get;C.one=C.Node.one;var A=function(K){if(typeof K==="string"){this._query=K;K=C.Selector.query(K);}else{K=C.Array(K,0,true);}A._instances[C.stamp(this)]=this;this._nodes=K;};A.NAME="NodeList";A.getDOMNodes=function(K){return K._nodes;};A._instances=[];A.each=function(K,N,M){var L=K._nodes;if(L&&L.length){C.Array.each(L,N,M||K);}else{}};A.addMethod=function(K,M,L){if(K&&M){A.prototype[K]=function(){var O=[],N=arguments;C.Array.each(this._nodes,function(T){var S="_yuid",Q=C.Node._instances[T[S]],R,P;if(!Q){Q=A._getTempNode(T);}R=L||Q;P=M.apply(R,N);if(P!==undefined&&P!==Q){O[O.length]=P;}});return O.length?O:this;};}else{}};A.importMethod=function(M,K,L){if(typeof K==="string"){L=L||K;A.addMethod(K,M[K]);}else{C.each(K,function(N){A.importMethod(M,N);});}};A._getTempNode=function(L){var K=A._tempNode;if(!K){K=C.Node.create("
    ");A._tempNode=K;}K._node=L;K._stateProxy=L;return K;};C.mix(A.prototype,{item:function(K){return C.one((this._nodes||[])[K]);},each:function(M,L){var K=this;C.Array.each(this._nodes,function(O,N){O=C.one(O);return M.call(L||O,O,N,K);});return K;},batch:function(L,K){var M=this;C.Array.each(this._nodes,function(P,O){var N=C.Node._instances[P[D]];if(!N){N=A._getTempNode(P);}return L.call(K||N,N,O,M);});return M;},some:function(M,L){var K=this;return C.Array.some(this._nodes,function(O,N){O=C.one(O);L=L||O;return M.call(L,O,N,K);});},toFrag:function(){return C.one(C.DOM._nl2frag(this._nodes));},indexOf:function(K){return C.Array.indexOf(this._nodes,C.Node.getDOMNode(K));},filter:function(K){return C.all(C.Selector.filter(this._nodes,K));},modulus:function(M,L){L=L||0;var K=[];A.each(this,function(O,N){if(N%M===L){K.push(O);}});return C.all(K);},odd:function(){return this.modulus(2,1);},even:function(){return this.modulus(2);},destructor:function(){delete A._instances[this[D]];},refresh:function(){var L,K=this._nodes;if(this._query){if(K&&K[0]&&K[0].ownerDocument){L=K[0].ownerDocument;}this._nodes=C.Selector.query(this._query,L||C.config.doc);}return this;},on:function(N,M,L){var K=C.Array(arguments,0,true);K.splice(2,0,this._nodes);K[3]=L||this;return C.on.apply(C,K);},after:function(N,M,L){var K=C.Array(arguments,0,true);K.splice(2,0,this._nodes);K[3]=L||this;return C.after.apply(C,K);},size:function(){return this._nodes.length;},toString:function(){var N="",M=this[D]+": not bound to any nodes",K=this._nodes,L;if(K&&K[0]){L=K[0];N+=L[E];if(L.id){N+="#"+L.id;}if(L.className){N+="."+L.className.replace(" ",".");}if(K.length>1){N+="...["+K.length+" items]";}}return N||M;}},true);A.importMethod(C.Node.prototype,["append","detach","detachAll","insert","prepend","remove","set","setContent"]);A.prototype.get=function(L){var O=[],N=this._nodes,M=false,P=A._getTempNode,K,Q;if(N[0]){K=C.Node._instances[N[0]._yuid]||P(N[0]);Q=K._get(L);if(Q&&Q.nodeType){M=true;}}C.Array.each(N,function(R){K=C.Node._instances[R._yuid];if(!K){K=P(R);}Q=K._get(L);if(!M){Q=C.Node.scrubVal(Q,K);}O.push(Q);});return(M)?C.all(O):O;};C.NodeList=A;C.all=function(K){return new A(K);};C.Node.all=C.all;C.Array.each(["replaceChild","appendChild","insertBefore","removeChild","hasChildNodes","cloneNode","hasAttribute","removeAttribute","scrollIntoView","getElementsByTagName","focus","blur","submit","reset","select"],function(K){C.Node.prototype[K]=function(O,M,L){var N=this.invoke(K,O,M,L);return N;};});F.importMethod(C.DOM,["contains","setAttribute","getAttribute"]);C.NodeList.importMethod(C.Node.prototype,["getAttribute","setAttribute"]);(function(L){var K=["hasClass","addClass","removeClass","replaceClass","toggleClass"];L.Node.importMethod(L.DOM,K);L.NodeList.importMethod(L.Node.prototype,K);})(C);if(!document.documentElement.hasAttribute){C.Node.prototype.hasAttribute=function(K){return C.DOM.getAttribute(this._node,K)!=="";};}C.Node.ATTRS.type={setter:function(L){if(L==="hidden"){try{this._node.type="hidden";}catch(K){this.setStyle("display","none");this._inputType="hidden";}}else{try{this._node.type=L;}catch(K){}}return L;},getter:function(){return this._inputType||this._node.type;},_bypassProxy:true};},"3.0.0",{requires:["dom-base","selector-css2","event-base"]}); \ No newline at end of file diff --git a/include/javascript/yui3/build/node/node-base.js b/include/javascript/yui3/build/node/node-base.js new file mode 100644 index 00000000..0bacab2f --- /dev/null +++ b/include/javascript/yui3/build/node/node-base.js @@ -0,0 +1,54 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add('node-base',function(Y){var DOT='.',NODE_NAME='nodeName',NODE_TYPE='nodeType',OWNER_DOCUMENT='ownerDocument',TAG_NAME='tagName',UID='_yuid',Node=function(node){var uid=node[UID];if(uid&&Node._instances[uid]&&Node._instances[uid]._node!==node){node[UID]=null;} +uid=Y.stamp(node);if(!uid){uid=Y.guid();} +this[UID]=uid;this._node=node;Node._instances[uid]=this;this._stateProxy=node;if(this._initPlugins){this._initPlugins();}},_wrapFn=function(fn){var ret=null;if(fn){ret=(typeof fn==='string')?function(n){return Y.Selector.test(n,fn);}:function(n){return fn(Node.get(n));};} +return ret;};Node.NAME='Node';Node.re_aria=/^(?:role$|aria-)/;Node.DOM_EVENTS={abort:true,beforeunload:true,blur:true,change:true,click:true,close:true,command:true,contextmenu:true,drag:true,dragstart:true,dragenter:true,dragover:true,dragleave:true,dragend:true,drop:true,dblclick:true,error:true,focus:true,keydown:true,keypress:true,keyup:true,load:true,message:true,mousedown:true,mousemove:true,mouseout:true,mouseover:true,mouseup:true,mousemultiwheel:true,mousewheel:true,submit:true,mouseenter:true,mouseleave:true,scroll:true,reset:true,resize:true,select:true,textInput:true,unload:true};Y.mix(Node.DOM_EVENTS,Y.Env.evt.plugins);Node._instances={};Node.getDOMNode=function(node){if(node){return(node.nodeType)?node:node._node||null;} +return null;};Node.scrubVal=function(val,node){if(node&&val){if(typeof val==='object'||typeof val==='function'){if(NODE_TYPE in val||Y.DOM.isWindow(val)){val=Node.get(val);}else if((val.item&&!val._nodes)||(val[0]&&val[0][NODE_TYPE])){val=Y.all(val);}}}else if(val===undefined){val=node;} +return val;};Node.addMethod=function(name,fn,context){if(name&&fn&&typeof fn==='function'){Node.prototype[name]=function(){context=context||this;var args=Y.Array(arguments),ret;if(args[0]&&args[0]instanceof Node){args[0]=args[0]._node;} +if(args[1]&&args[1]instanceof Node){args[1]=args[1]._node;} +args.unshift(this._node);ret=Node.scrubVal(fn.apply(context,args),this);return ret;};}else{}};Node.importMethod=function(host,name,altName){if(typeof name==='string'){altName=altName||name;Node.addMethod(altName,host[name],host);}else{Y.each(name,function(n){Node.importMethod(host,n);});}};Node.one=function(node){var instance=null,cachedNode,uid;if(node){if(typeof node==='string'){if(node.indexOf('doc')===0){node=Y.config.doc;}else if(node.indexOf('win')===0){node=Y.config.win;}else{node=Y.Selector.query(node,null,true);} +if(!node){return null;}}else if(node instanceof Node){return node;} +uid=node._yuid;instance=Node._instances[uid];cachedNode=instance?instance._node:null;if(!instance||(cachedNode&&node!==cachedNode)){instance=new Node(node);}} +return instance;};Node.get=function(){return Node.one.apply(Node,arguments);};Node.create=function(){return Node.get(Y.DOM.create.apply(Y.DOM,arguments));};Node.ATTRS={text:{getter:function(){return Y.DOM.getText(this._node);},setter:function(content){Y.DOM.setText(this._node,content);return content;}},'options':{getter:function(){return this._node.getElementsByTagName('option');}},'elements':{getter:function(){return Y.all(this._node.elements);}},'children':{getter:function(){var node=this._node,children=node.children,childNodes,i,len;if(!children){childNodes=node.childNodes;children=[];for(i=0,len=childNodes.length;i-1){strPath=name;name=name.split(DOT);Y.Object.setValue(node,name,val);}else if(node[name]!==undefined){node[name]=val;} +return val;};Node.DEFAULT_GETTER=function(name){var node=this._stateProxy,val;if(name.indexOf&&name.indexOf(DOT)>-1){val=Y.Object.getValue(node,name.split(DOT));}else if(node[name]!==undefined){val=node[name];} +return val;};Y.augment(Node,Y.Event.Target);Y.mix(Node.prototype,{toString:function(){var str='',errorMsg=this[UID]+': not bound to a node',node=this._node;if(node){str+=node[NODE_NAME];if(node.id){str+='#'+node.id;} +if(node.className){str+='.'+node.className.replace(' ','.');} +str+=' '+this[UID];} +return str||errorMsg;},get:function(attr){var val;if(this._getAttr){val=this._getAttr(attr);}else{val=this._get(attr);} +if(val){val=Y.Node.scrubVal(val,this);} +return val;},_get:function(attr){var attrConfig=Node.ATTRS[attr],val;if(attrConfig&&attrConfig.getter){val=attrConfig.getter.call(this);}else if(Node.re_aria.test(attr)){val=this._node.getAttribute(attr,2);}else{val=Node.DEFAULT_GETTER.apply(this,arguments);} +return val;},set:function(attr,val){var attrConfig=Node.ATTRS[attr];if(this._setAttr){this._setAttr.apply(this,arguments);}else{if(attrConfig&&attrConfig.setter){attrConfig.setter.call(this,val);}else if(Node.re_aria.test(attr)){this._node.setAttribute(attr,val);}else{Node.DEFAULT_SETTER.apply(this,arguments);}} +return this;},setAttrs:function(attrMap){if(this._setAttrs){this._setAttrs(attrMap);}else{Y.Object.each(attrMap,function(v,n){this.set(n,v);},this);} +return this;},getAttrs:function(attrs){var ret={};if(this._getAttrs){this._getAttrs(attrs);}else{Y.Array.each(attrs,function(v,n){ret[v]=this.get(v);},this);} +return ret;},create:Node.create,compareTo:function(refNode){var node=this._node;if(refNode instanceof Y.Node){refNode=refNode._node;} +return node===refNode;},inDoc:function(doc){var node=this._node;doc=(doc)?doc._node||doc:node[OWNER_DOCUMENT];if(doc.documentElement){return Y.DOM.contains(doc.documentElement,node);}},getById:function(id){var node=this._node,ret=Y.DOM.byId(id,node[OWNER_DOCUMENT]);if(ret&&Y.DOM.contains(node,ret)){ret=Y.one(ret);}else{ret=null;} +return ret;},ancestor:function(fn){return Node.get(Y.DOM.elementByAxis(this._node,'parentNode',_wrapFn(fn)));},previous:function(fn,all){return Node.get(Y.DOM.elementByAxis(this._node,'previousSibling',_wrapFn(fn),all));},next:function(node,fn,all){return Node.get(Y.DOM.elementByAxis(this._node,'nextSibling',_wrapFn(fn),all));},one:function(selector){return Y.one(Y.Selector.query(selector,this._node,true));},query:function(selector){return this.one(selector);},all:function(selector){var nodelist=Y.all(Y.Selector.query(selector,this._node));nodelist._query=selector;return nodelist;},queryAll:function(selector){return this.all(selector);},test:function(selector){return Y.Selector.test(this._node,selector);},remove:function(destroy){var node=this._node;node.parentNode.removeChild(node);if(destroy){this.destroy(true);} +return this;},replace:function(newNode){var node=this._node;node.parentNode.replaceChild(newNode,node);return this;},purge:function(recurse,type){Y.Event.purgeElement(this._node,recurse,type);},destroy:function(purge){delete Node._instances[this[UID]];if(purge){this.purge(true);} +if(this.unplug){this.unplug();} +this._node._yuid=null;this._node=null;this._stateProxy=null;},invoke:function(method,a,b,c,d,e){var node=this._node,ret;if(a&&a instanceof Y.Node){a=a._node;} +if(b&&b instanceof Y.Node){b=b._node;} +ret=node[method](a,b,c,d,e);return Y.Node.scrubVal(ret,this);},each:function(fn,context){context=context||this;return fn.call(context,this);},item:function(index){return this;},size:function(){return this._node?1:0;},insert:function(content,where){var node=this._node;if(content){if(typeof where==='number'){where=this._node.childNodes[where];} +if(typeof content!=='string'){if(content._node){content=content._node;}else if(content._nodes||(!content.nodeType&&content.length)){Y.each(content._nodes,function(n){Y.DOM.addHTML(node,n,where);});return this;}} +Y.DOM.addHTML(node,content,where);} +return this;},prepend:function(content){return this.insert(content,0);},append:function(content){return this.insert(content,null);},setContent:function(content){Y.DOM.addHTML(this._node,content,'replace');return this;},hasMethod:function(method){var node=this._node;return(node&&(typeof node==='function'));}},true);Y.Node=Node;Y.get=Y.Node.get;Y.one=Y.Node.one;var NodeList=function(nodes){if(typeof nodes==='string'){this._query=nodes;nodes=Y.Selector.query(nodes);}else{nodes=Y.Array(nodes,0,true);} +NodeList._instances[Y.stamp(this)]=this;this._nodes=nodes;};NodeList.NAME='NodeList';NodeList.getDOMNodes=function(nodeList){return nodeList._nodes;};NodeList._instances=[];NodeList.each=function(instance,fn,context){var nodes=instance._nodes;if(nodes&&nodes.length){Y.Array.each(nodes,fn,context||instance);}else{}};NodeList.addMethod=function(name,fn,context){if(name&&fn){NodeList.prototype[name]=function(){var ret=[],args=arguments;Y.Array.each(this._nodes,function(node){var UID='_yuid',instance=Y.Node._instances[node[UID]],ctx,result;if(!instance){instance=NodeList._getTempNode(node);} +ctx=context||instance;result=fn.apply(ctx,args);if(result!==undefined&&result!==instance){ret[ret.length]=result;}});return ret.length?ret:this;};}else{}};NodeList.importMethod=function(host,name,altName){if(typeof name==='string'){altName=altName||name;NodeList.addMethod(name,host[name]);}else{Y.each(name,function(n){NodeList.importMethod(host,n);});}};NodeList._getTempNode=function(node){var tmp=NodeList._tempNode;if(!tmp){tmp=Y.Node.create('
    ');NodeList._tempNode=tmp;} +tmp._node=node;tmp._stateProxy=node;return tmp;};Y.mix(NodeList.prototype,{item:function(index){return Y.one((this._nodes||[])[index]);},each:function(fn,context){var instance=this;Y.Array.each(this._nodes,function(node,index){node=Y.one(node);return fn.call(context||node,node,index,instance);});return instance;},batch:function(fn,context){var nodelist=this;Y.Array.each(this._nodes,function(node,index){var instance=Y.Node._instances[node[UID]];if(!instance){instance=NodeList._getTempNode(node);} +return fn.call(context||instance,instance,index,nodelist);});return nodelist;},some:function(fn,context){var instance=this;return Y.Array.some(this._nodes,function(node,index){node=Y.one(node);context=context||node;return fn.call(context,node,index,instance);});},toFrag:function(){return Y.one(Y.DOM._nl2frag(this._nodes));},indexOf:function(node){return Y.Array.indexOf(this._nodes,Y.Node.getDOMNode(node));},filter:function(selector){return Y.all(Y.Selector.filter(this._nodes,selector));},modulus:function(n,r){r=r||0;var nodes=[];NodeList.each(this,function(node,i){if(i%n===r){nodes.push(node);}});return Y.all(nodes);},odd:function(){return this.modulus(2,1);},even:function(){return this.modulus(2);},destructor:function(){delete NodeList._instances[this[UID]];},refresh:function(){var doc,nodes=this._nodes;if(this._query){if(nodes&&nodes[0]&&nodes[0].ownerDocument){doc=nodes[0].ownerDocument;} +this._nodes=Y.Selector.query(this._query,doc||Y.config.doc);} +return this;},on:function(type,fn,context){var args=Y.Array(arguments,0,true);args.splice(2,0,this._nodes);args[3]=context||this;return Y.on.apply(Y,args);},after:function(type,fn,context){var args=Y.Array(arguments,0,true);args.splice(2,0,this._nodes);args[3]=context||this;return Y.after.apply(Y,args);},size:function(){return this._nodes.length;},toString:function(){var str='',errorMsg=this[UID]+': not bound to any nodes',nodes=this._nodes,node;if(nodes&&nodes[0]){node=nodes[0];str+=node[NODE_NAME];if(node.id){str+='#'+node.id;} +if(node.className){str+='.'+node.className.replace(' ','.');} +if(nodes.length>1){str+='...['+nodes.length+' items]';}} +return str||errorMsg;}},true);NodeList.importMethod(Y.Node.prototype,['append','detach','detachAll','insert','prepend','remove','set','setContent']);NodeList.prototype.get=function(attr){var ret=[],nodes=this._nodes,isNodeList=false,getTemp=NodeList._getTempNode,instance,val;if(nodes[0]){instance=Y.Node._instances[nodes[0]._yuid]||getTemp(nodes[0]);val=instance._get(attr);if(val&&val.nodeType){isNodeList=true;}} +Y.Array.each(nodes,function(node){instance=Y.Node._instances[node._yuid];if(!instance){instance=getTemp(node);} +val=instance._get(attr);if(!isNodeList){val=Y.Node.scrubVal(val,instance);} +ret.push(val);});return(isNodeList)?Y.all(ret):ret;};Y.NodeList=NodeList;Y.all=function(nodes){return new NodeList(nodes);};Y.Node.all=Y.all;Y.Array.each(['replaceChild','appendChild','insertBefore','removeChild','hasChildNodes','cloneNode','hasAttribute','removeAttribute','scrollIntoView','getElementsByTagName','focus','blur','submit','reset','select'],function(method){Y.Node.prototype[method]=function(arg1,arg2,arg3){var ret=this.invoke(method,arg1,arg2,arg3);return ret;};});Node.importMethod(Y.DOM,['contains','setAttribute','getAttribute']);Y.NodeList.importMethod(Y.Node.prototype,['getAttribute','setAttribute']);(function(Y){var methods=['hasClass','addClass','removeClass','replaceClass','toggleClass'];Y.Node.importMethod(Y.DOM,methods);Y.NodeList.importMethod(Y.Node.prototype,methods);})(Y);if(!document.documentElement.hasAttribute){Y.Node.prototype.hasAttribute=function(attr){return Y.DOM.getAttribute(this._node,attr)!=='';};} +Y.Node.ATTRS.type={setter:function(val){if(val==='hidden'){try{this._node.type='hidden';}catch(e){this.setStyle('display','none');this._inputType='hidden';}}else{try{this._node.type=val;}catch(e){}} +return val;},getter:function(){return this._inputType||this._node.type;},_bypassProxy:true};},'3.0.0',{requires:['dom-base','selector-css2','event-base']}); \ No newline at end of file diff --git a/include/javascript/yui3/build/node/node-event-delegate-min.js b/include/javascript/yui3/build/node/node-event-delegate-min.js new file mode 100644 index 00000000..4af68fd1 --- /dev/null +++ b/include/javascript/yui3/build/node/node-event-delegate-min.js @@ -0,0 +1,8 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add("node-event-delegate",function(A){A.Node.prototype.delegate=function(F,E,B){var D=Array.prototype.slice.call(arguments,3),C=[F,E,A.Node.getDOMNode(this),B];C=C.concat(D);return A.delegate.apply(A,C);};},"3.0.0",{requires:["node-base","event-delegate","pluginhost"]}); \ No newline at end of file diff --git a/include/javascript/yui3/build/node/node-event-delegate.js b/include/javascript/yui3/build/node/node-event-delegate.js new file mode 100644 index 00000000..9978e70a --- /dev/null +++ b/include/javascript/yui3/build/node/node-event-delegate.js @@ -0,0 +1,8 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add('node-event-delegate',function(Y){Y.Node.prototype.delegate=function(type,fn,selector){var args=Array.prototype.slice.call(arguments,3),a=[type,fn,Y.Node.getDOMNode(this),selector];a=a.concat(args);return Y.delegate.apply(Y,a);};},'3.0.0',{requires:['node-base','event-delegate','pluginhost']}); \ No newline at end of file diff --git a/include/javascript/yui3/build/node/node-event-simulate-min.js b/include/javascript/yui3/build/node/node-event-simulate-min.js new file mode 100644 index 00000000..8234594d --- /dev/null +++ b/include/javascript/yui3/build/node/node-event-simulate-min.js @@ -0,0 +1,8 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add("node-event-simulate",function(A){A.Node.prototype.simulate=function(C,B){A.Event.simulate(A.Node.getDOMNode(this),C,B);};},"3.0.0",{requires:["node-base","event-simulate"]}); \ No newline at end of file diff --git a/include/javascript/yui3/build/node/node-event-simulate.js b/include/javascript/yui3/build/node/node-event-simulate.js new file mode 100644 index 00000000..283ea5c5 --- /dev/null +++ b/include/javascript/yui3/build/node/node-event-simulate.js @@ -0,0 +1,8 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add('node-event-simulate',function(Y){Y.Node.prototype.simulate=function(type,options){Y.Event.simulate(Y.Node.getDOMNode(this),type,options);};},'3.0.0',{requires:['node-base','event-simulate']}); \ No newline at end of file diff --git a/include/javascript/yui3/build/node/node-min.js b/include/javascript/yui3/build/node/node-min.js new file mode 100644 index 00000000..e9ed1f16 --- /dev/null +++ b/include/javascript/yui3/build/node/node-min.js @@ -0,0 +1,8 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add("node-base",function(C){var G=".",E="nodeName",I="nodeType",B="ownerDocument",H="tagName",D="_yuid",F=function(L){var K=L[D];if(K&&F._instances[K]&&F._instances[K]._node!==L){L[D]=null;}K=C.stamp(L);if(!K){K=C.guid();}this[D]=K;this._node=L;F._instances[K]=this;this._stateProxy=L;if(this._initPlugins){this._initPlugins();}},J=function(L){var K=null;if(L){K=(typeof L==="string")?function(M){return C.Selector.test(M,L);}:function(M){return L(F.get(M));};}return K;};F.NAME="Node";F.re_aria=/^(?:role$|aria-)/;F.DOM_EVENTS={abort:true,beforeunload:true,blur:true,change:true,click:true,close:true,command:true,contextmenu:true,drag:true,dragstart:true,dragenter:true,dragover:true,dragleave:true,dragend:true,drop:true,dblclick:true,error:true,focus:true,keydown:true,keypress:true,keyup:true,load:true,message:true,mousedown:true,mousemove:true,mouseout:true,mouseover:true,mouseup:true,mousemultiwheel:true,mousewheel:true,submit:true,mouseenter:true,mouseleave:true,scroll:true,reset:true,resize:true,select:true,textInput:true,unload:true};C.mix(F.DOM_EVENTS,C.Env.evt.plugins);F._instances={};F.getDOMNode=function(K){if(K){return(K.nodeType)?K:K._node||null;}return null;};F.scrubVal=function(L,K){if(K&&L){if(typeof L==="object"||typeof L==="function"){if(I in L||C.DOM.isWindow(L)){L=F.get(L);}else{if((L.item&&!L._nodes)||(L[0]&&L[0][I])){L=C.all(L);}}}}else{if(L===undefined){L=K;}}return L;};F.addMethod=function(K,M,L){if(K&&M&&typeof M==="function"){F.prototype[K]=function(){L=L||this;var O=C.Array(arguments),N;if(O[0]&&O[0]instanceof F){O[0]=O[0]._node;}if(O[1]&&O[1]instanceof F){O[1]=O[1]._node;}O.unshift(this._node);N=F.scrubVal(M.apply(L,O),this);return N;};}else{}};F.importMethod=function(M,K,L){if(typeof K==="string"){L=L||K;F.addMethod(L,M[K],M);}else{C.each(K,function(N){F.importMethod(M,N);});}};F.one=function(N){var K=null,M,L;if(N){if(typeof N==="string"){if(N.indexOf("doc")===0){N=C.config.doc;}else{if(N.indexOf("win")===0){N=C.config.win;}else{N=C.Selector.query(N,null,true);}}if(!N){return null;}}else{if(N instanceof F){return N;}}L=N._yuid;K=F._instances[L];M=K?K._node:null;if(!K||(M&&N!==M)){K=new F(N);}}return K;};F.get=function(){return F.one.apply(F,arguments);};F.create=function(){return F.get(C.DOM.create.apply(C.DOM,arguments));};F.ATTRS={text:{getter:function(){return C.DOM.getText(this._node);},setter:function(K){C.DOM.setText(this._node,K);return K;}},"options":{getter:function(){return this._node.getElementsByTagName("option");}},"elements":{getter:function(){return C.all(this._node.elements);}},"children":{getter:function(){var N=this._node,M=N.children,O,L,K;if(!M){O=N.childNodes;M=[];for(L=0,K=O.length;L-1){N=K;K=K.split(G);C.Object.setValue(L,K,M);}else{if(L[K]!==undefined){L[K]=M;}}return M;};F.DEFAULT_GETTER=function(K){var L=this._stateProxy,M;if(K.indexOf&&K.indexOf(G)>-1){M=C.Object.getValue(L,K.split(G));}else{if(L[K]!==undefined){M=L[K];}}return M;};C.augment(F,C.Event.Target);C.mix(F.prototype,{toString:function(){var M="",L=this[D]+": not bound to a node",K=this._node;if(K){M+=K[E];if(K.id){M+="#"+K.id;}if(K.className){M+="."+K.className.replace(" ",".");}M+=" "+this[D];}return M||L;},get:function(K){var L;if(this._getAttr){L=this._getAttr(K);}else{L=this._get(K);}if(L){L=C.Node.scrubVal(L,this);}return L;},_get:function(K){var L=F.ATTRS[K],M;if(L&&L.getter){M=L.getter.call(this);}else{if(F.re_aria.test(K)){M=this._node.getAttribute(K,2);}else{M=F.DEFAULT_GETTER.apply(this,arguments);}}return M;},set:function(K,M){var L=F.ATTRS[K];if(this._setAttr){this._setAttr.apply(this,arguments);}else{if(L&&L.setter){L.setter.call(this,M);}else{if(F.re_aria.test(K)){this._node.setAttribute(K,M);}else{F.DEFAULT_SETTER.apply(this,arguments);}}}return this;},setAttrs:function(K){if(this._setAttrs){this._setAttrs(K);}else{C.Object.each(K,function(L,M){this.set(M,L);},this);}return this;},getAttrs:function(L){var K={};if(this._getAttrs){this._getAttrs(L);}else{C.Array.each(L,function(M,N){K[M]=this.get(M);},this);}return K;},create:F.create,compareTo:function(K){var L=this._node;if(K instanceof C.Node){K=K._node;}return L===K;},inDoc:function(L){var K=this._node;L=(L)?L._node||L:K[B];if(L.documentElement){return C.DOM.contains(L.documentElement,K);}},getById:function(M){var L=this._node,K=C.DOM.byId(M,L[B]);if(K&&C.DOM.contains(L,K)){K=C.one(K);}else{K=null;}return K;},ancestor:function(K){return F.get(C.DOM.elementByAxis(this._node,"parentNode",J(K)));},previous:function(L,K){return F.get(C.DOM.elementByAxis(this._node,"previousSibling",J(L),K));},next:function(M,L,K){return F.get(C.DOM.elementByAxis(this._node,"nextSibling",J(L),K));},one:function(K){return C.one(C.Selector.query(K,this._node,true));},query:function(K){return this.one(K);},all:function(K){var L=C.all(C.Selector.query(K,this._node));L._query=K;return L;},queryAll:function(K){return this.all(K);},test:function(K){return C.Selector.test(this._node,K);},remove:function(K){var L=this._node;L.parentNode.removeChild(L);if(K){this.destroy(true);}return this;},replace:function(K){var L=this._node;L.parentNode.replaceChild(K,L);return this;},purge:function(L,K){C.Event.purgeElement(this._node,L,K);},destroy:function(K){delete F._instances[this[D]];if(K){this.purge(true);}if(this.unplug){this.unplug();}this._node._yuid=null;this._node=null;this._stateProxy=null;},invoke:function(R,L,K,Q,P,O){var N=this._node,M;if(L&&L instanceof C.Node){L=L._node;}if(K&&K instanceof C.Node){K=K._node;}M=N[R](L,K,Q,P,O);return C.Node.scrubVal(M,this);},each:function(L,K){K=K||this;return L.call(K,this);},item:function(K){return this;},size:function(){return this._node?1:0;},insert:function(M,K){var L=this._node;if(M){if(typeof K==="number"){K=this._node.childNodes[K];}if(typeof M!=="string"){if(M._node){M=M._node;}else{if(M._nodes||(!M.nodeType&&M.length)){C.each(M._nodes,function(N){C.DOM.addHTML(L,N,K);});return this;}}}C.DOM.addHTML(L,M,K);}return this;},prepend:function(K){return this.insert(K,0);},append:function(K){return this.insert(K,null);},setContent:function(K){C.DOM.addHTML(this._node,K,"replace");return this;},hasMethod:function(L){var K=this._node;return(K&&(typeof K==="function"));}},true);C.Node=F;C.get=C.Node.get;C.one=C.Node.one;var A=function(K){if(typeof K==="string"){this._query=K;K=C.Selector.query(K);}else{K=C.Array(K,0,true);}A._instances[C.stamp(this)]=this;this._nodes=K;};A.NAME="NodeList";A.getDOMNodes=function(K){return K._nodes;};A._instances=[];A.each=function(K,N,M){var L=K._nodes;if(L&&L.length){C.Array.each(L,N,M||K);}else{}};A.addMethod=function(K,M,L){if(K&&M){A.prototype[K]=function(){var O=[],N=arguments;C.Array.each(this._nodes,function(T){var S="_yuid",Q=C.Node._instances[T[S]],R,P;if(!Q){Q=A._getTempNode(T);}R=L||Q;P=M.apply(R,N);if(P!==undefined&&P!==Q){O[O.length]=P;}});return O.length?O:this;};}else{}};A.importMethod=function(M,K,L){if(typeof K==="string"){L=L||K;A.addMethod(K,M[K]);}else{C.each(K,function(N){A.importMethod(M,N);});}};A._getTempNode=function(L){var K=A._tempNode;if(!K){K=C.Node.create("
    ");A._tempNode=K;}K._node=L;K._stateProxy=L;return K;};C.mix(A.prototype,{item:function(K){return C.one((this._nodes||[])[K]);},each:function(M,L){var K=this;C.Array.each(this._nodes,function(O,N){O=C.one(O);return M.call(L||O,O,N,K);});return K;},batch:function(L,K){var M=this;C.Array.each(this._nodes,function(P,O){var N=C.Node._instances[P[D]];if(!N){N=A._getTempNode(P);}return L.call(K||N,N,O,M);});return M;},some:function(M,L){var K=this;return C.Array.some(this._nodes,function(O,N){O=C.one(O);L=L||O;return M.call(L,O,N,K);});},toFrag:function(){return C.one(C.DOM._nl2frag(this._nodes));},indexOf:function(K){return C.Array.indexOf(this._nodes,C.Node.getDOMNode(K));},filter:function(K){return C.all(C.Selector.filter(this._nodes,K));},modulus:function(M,L){L=L||0;var K=[];A.each(this,function(O,N){if(N%M===L){K.push(O);}});return C.all(K);},odd:function(){return this.modulus(2,1);},even:function(){return this.modulus(2);},destructor:function(){delete A._instances[this[D]];},refresh:function(){var L,K=this._nodes;if(this._query){if(K&&K[0]&&K[0].ownerDocument){L=K[0].ownerDocument;}this._nodes=C.Selector.query(this._query,L||C.config.doc);}return this;},on:function(N,M,L){var K=C.Array(arguments,0,true);K.splice(2,0,this._nodes);K[3]=L||this;return C.on.apply(C,K);},after:function(N,M,L){var K=C.Array(arguments,0,true);K.splice(2,0,this._nodes);K[3]=L||this;return C.after.apply(C,K);},size:function(){return this._nodes.length;},toString:function(){var N="",M=this[D]+": not bound to any nodes",K=this._nodes,L;if(K&&K[0]){L=K[0];N+=L[E];if(L.id){N+="#"+L.id;}if(L.className){N+="."+L.className.replace(" ",".");}if(K.length>1){N+="...["+K.length+" items]";}}return N||M;}},true);A.importMethod(C.Node.prototype,["append","detach","detachAll","insert","prepend","remove","set","setContent"]);A.prototype.get=function(L){var O=[],N=this._nodes,M=false,P=A._getTempNode,K,Q;if(N[0]){K=C.Node._instances[N[0]._yuid]||P(N[0]);Q=K._get(L);if(Q&&Q.nodeType){M=true;}}C.Array.each(N,function(R){K=C.Node._instances[R._yuid];if(!K){K=P(R);}Q=K._get(L);if(!M){Q=C.Node.scrubVal(Q,K);}O.push(Q);});return(M)?C.all(O):O;};C.NodeList=A;C.all=function(K){return new A(K);};C.Node.all=C.all;C.Array.each(["replaceChild","appendChild","insertBefore","removeChild","hasChildNodes","cloneNode","hasAttribute","removeAttribute","scrollIntoView","getElementsByTagName","focus","blur","submit","reset","select"],function(K){C.Node.prototype[K]=function(O,M,L){var N=this.invoke(K,O,M,L);return N;};});F.importMethod(C.DOM,["contains","setAttribute","getAttribute"]);C.NodeList.importMethod(C.Node.prototype,["getAttribute","setAttribute"]);(function(L){var K=["hasClass","addClass","removeClass","replaceClass","toggleClass"];L.Node.importMethod(L.DOM,K);L.NodeList.importMethod(L.Node.prototype,K);})(C);if(!document.documentElement.hasAttribute){C.Node.prototype.hasAttribute=function(K){return C.DOM.getAttribute(this._node,K)!=="";};}C.Node.ATTRS.type={setter:function(L){if(L==="hidden"){try{this._node.type="hidden";}catch(K){this.setStyle("display","none");this._inputType="hidden";}}else{try{this._node.type=L;}catch(K){}}return L;},getter:function(){return this._inputType||this._node.type;},_bypassProxy:true};},"3.0.0",{requires:["dom-base","selector-css2","event-base"]});YUI.add("node-style",function(A){(function(C){var B=["getStyle","getComputedStyle","setStyle","setStyles"];C.Node.importMethod(C.DOM,B);C.NodeList.importMethod(C.Node.prototype,B);})(A);},"3.0.0",{requires:["dom-style","node-base"]});YUI.add("node-screen",function(A){A.each(["winWidth","winHeight","docWidth","docHeight","docScrollX","docScrollY"],function(B){A.Node.ATTRS[B]={getter:function(){var C=Array.prototype.slice.call(arguments);C.unshift(A.Node.getDOMNode(this));return A.DOM[B].apply(this,C);}};});A.Node.ATTRS.scrollLeft={getter:function(){var B=A.Node.getDOMNode(this);return("scrollLeft"in B)?B.scrollLeft:A.DOM.docScrollX(B);},setter:function(C){var B=A.Node.getDOMNode(this);if(B){if("scrollLeft"in B){B.scrollLeft=C;}else{if(B.document||B.nodeType===9){A.DOM._getWin(B).scrollTo(C,A.DOM.docScrollY(B));}}}else{}}};A.Node.ATTRS.scrollTop={getter:function(){var B=A.Node.getDOMNode(this);return("scrollTop"in B)?B.scrollTop:A.DOM.docScrollY(B);},setter:function(C){var B=A.Node.getDOMNode(this);if(B){if("scrollTop"in B){B.scrollTop=C;}else{if(B.document||B.nodeType===9){A.DOM._getWin(B).scrollTo(A.DOM.docScrollX(B),C);}}}else{}}};A.Node.importMethod(A.DOM,["getXY","setXY","getX","setX","getY","setY"]);A.Node.ATTRS.region={getter:function(){var B=A.Node.getDOMNode(this);if(B&&!B.tagName){if(B.nodeType===9){B=B.documentElement;}else{if(B.alert){B=B.document.documentElement;}}}return A.DOM.region(B);}};A.Node.ATTRS.viewportRegion={getter:function(){return A.DOM.viewportRegion(A.Node.getDOMNode(this));}};A.Node.importMethod(A.DOM,"inViewportRegion");A.Node.prototype.intersect=function(B,D){var C=A.Node.getDOMNode(this);if(B instanceof A.Node){B=A.Node.getDOMNode(B);}return A.DOM.intersect(C,B,D);};A.Node.prototype.inRegion=function(B,D,E){var C=A.Node.getDOMNode(this);if(B instanceof A.Node){B=A.Node.getDOMNode(B);}return A.DOM.inRegion(C,B,D,E);};},"3.0.0",{requires:["dom-screen"]});YUI.add("node-pluginhost",function(A){A.Node.plug=function(){var B=A.Array(arguments);B.unshift(A.Node);A.Plugin.Host.plug.apply(A.Base,B);return A.Node;};A.Node.unplug=function(){var B=A.Array(arguments);B.unshift(A.Node);A.Plugin.Host.unplug.apply(A.Base,B);return A.Node;};A.mix(A.Node,A.Plugin.Host,false,null,1);A.NodeList.prototype.plug=function(){var B=arguments;A.NodeList.each(this,function(C){A.Node.prototype.plug.apply(A.one(C),B);});};A.NodeList.prototype.unplug=function(){var B=arguments;A.NodeList.each(this,function(C){A.Node.prototype.unplug.apply(A.one(C),B);});};},"3.0.0",{requires:["node-base","pluginhost"]});YUI.add("node-event-delegate",function(A){A.Node.prototype.delegate=function(F,E,B){var D=Array.prototype.slice.call(arguments,3),C=[F,E,A.Node.getDOMNode(this),B];C=C.concat(D);return A.delegate.apply(A,C);};},"3.0.0",{requires:["node-base","event-delegate","pluginhost"]});YUI.add("node",function(A){},"3.0.0",{skinnable:false,use:["node-base","node-style","node-screen","node-pluginhost","node-event-delegate"],requires:["dom","event-base","event-delegate","pluginhost"]}); \ No newline at end of file diff --git a/include/javascript/yui3/build/node/node-pluginhost-min.js b/include/javascript/yui3/build/node/node-pluginhost-min.js new file mode 100644 index 00000000..5d8ea9b6 --- /dev/null +++ b/include/javascript/yui3/build/node/node-pluginhost-min.js @@ -0,0 +1,8 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add("node-pluginhost",function(A){A.Node.plug=function(){var B=A.Array(arguments);B.unshift(A.Node);A.Plugin.Host.plug.apply(A.Base,B);return A.Node;};A.Node.unplug=function(){var B=A.Array(arguments);B.unshift(A.Node);A.Plugin.Host.unplug.apply(A.Base,B);return A.Node;};A.mix(A.Node,A.Plugin.Host,false,null,1);A.NodeList.prototype.plug=function(){var B=arguments;A.NodeList.each(this,function(C){A.Node.prototype.plug.apply(A.one(C),B);});};A.NodeList.prototype.unplug=function(){var B=arguments;A.NodeList.each(this,function(C){A.Node.prototype.unplug.apply(A.one(C),B);});};},"3.0.0",{requires:["node-base","pluginhost"]}); \ No newline at end of file diff --git a/include/javascript/yui3/build/node/node-pluginhost.js b/include/javascript/yui3/build/node/node-pluginhost.js new file mode 100644 index 00000000..6c86443c --- /dev/null +++ b/include/javascript/yui3/build/node/node-pluginhost.js @@ -0,0 +1,8 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add('node-pluginhost',function(Y){Y.Node.plug=function(){var args=Y.Array(arguments);args.unshift(Y.Node);Y.Plugin.Host.plug.apply(Y.Base,args);return Y.Node;};Y.Node.unplug=function(){var args=Y.Array(arguments);args.unshift(Y.Node);Y.Plugin.Host.unplug.apply(Y.Base,args);return Y.Node;};Y.mix(Y.Node,Y.Plugin.Host,false,null,1);Y.NodeList.prototype.plug=function(){var args=arguments;Y.NodeList.each(this,function(node){Y.Node.prototype.plug.apply(Y.one(node),args);});};Y.NodeList.prototype.unplug=function(){var args=arguments;Y.NodeList.each(this,function(node){Y.Node.prototype.unplug.apply(Y.one(node),args);});};},'3.0.0',{requires:['node-base','pluginhost']}); \ No newline at end of file diff --git a/include/javascript/yui3/build/node/node-screen-min.js b/include/javascript/yui3/build/node/node-screen-min.js new file mode 100644 index 00000000..5ea64be3 --- /dev/null +++ b/include/javascript/yui3/build/node/node-screen-min.js @@ -0,0 +1,8 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add("node-screen",function(A){A.each(["winWidth","winHeight","docWidth","docHeight","docScrollX","docScrollY"],function(B){A.Node.ATTRS[B]={getter:function(){var C=Array.prototype.slice.call(arguments);C.unshift(A.Node.getDOMNode(this));return A.DOM[B].apply(this,C);}};});A.Node.ATTRS.scrollLeft={getter:function(){var B=A.Node.getDOMNode(this);return("scrollLeft"in B)?B.scrollLeft:A.DOM.docScrollX(B);},setter:function(C){var B=A.Node.getDOMNode(this);if(B){if("scrollLeft"in B){B.scrollLeft=C;}else{if(B.document||B.nodeType===9){A.DOM._getWin(B).scrollTo(C,A.DOM.docScrollY(B));}}}else{}}};A.Node.ATTRS.scrollTop={getter:function(){var B=A.Node.getDOMNode(this);return("scrollTop"in B)?B.scrollTop:A.DOM.docScrollY(B);},setter:function(C){var B=A.Node.getDOMNode(this);if(B){if("scrollTop"in B){B.scrollTop=C;}else{if(B.document||B.nodeType===9){A.DOM._getWin(B).scrollTo(A.DOM.docScrollX(B),C);}}}else{}}};A.Node.importMethod(A.DOM,["getXY","setXY","getX","setX","getY","setY"]);A.Node.ATTRS.region={getter:function(){var B=A.Node.getDOMNode(this);if(B&&!B.tagName){if(B.nodeType===9){B=B.documentElement;}else{if(B.alert){B=B.document.documentElement;}}}return A.DOM.region(B);}};A.Node.ATTRS.viewportRegion={getter:function(){return A.DOM.viewportRegion(A.Node.getDOMNode(this));}};A.Node.importMethod(A.DOM,"inViewportRegion");A.Node.prototype.intersect=function(B,D){var C=A.Node.getDOMNode(this);if(B instanceof A.Node){B=A.Node.getDOMNode(B);}return A.DOM.intersect(C,B,D);};A.Node.prototype.inRegion=function(B,D,E){var C=A.Node.getDOMNode(this);if(B instanceof A.Node){B=A.Node.getDOMNode(B);}return A.DOM.inRegion(C,B,D,E);};},"3.0.0",{requires:["dom-screen"]}); \ No newline at end of file diff --git a/include/javascript/yui3/build/node/node-screen.js b/include/javascript/yui3/build/node/node-screen.js new file mode 100644 index 00000000..9bf569fe --- /dev/null +++ b/include/javascript/yui3/build/node/node-screen.js @@ -0,0 +1,11 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add('node-screen',function(Y){Y.each(['winWidth','winHeight','docWidth','docHeight','docScrollX','docScrollY'],function(name){Y.Node.ATTRS[name]={getter:function(){var args=Array.prototype.slice.call(arguments);args.unshift(Y.Node.getDOMNode(this));return Y.DOM[name].apply(this,args);}};});Y.Node.ATTRS.scrollLeft={getter:function(){var node=Y.Node.getDOMNode(this);return('scrollLeft'in node)?node.scrollLeft:Y.DOM.docScrollX(node);},setter:function(val){var node=Y.Node.getDOMNode(this);if(node){if('scrollLeft'in node){node.scrollLeft=val;}else if(node.document||node.nodeType===9){Y.DOM._getWin(node).scrollTo(val,Y.DOM.docScrollY(node));}}else{}}};Y.Node.ATTRS.scrollTop={getter:function(){var node=Y.Node.getDOMNode(this);return('scrollTop'in node)?node.scrollTop:Y.DOM.docScrollY(node);},setter:function(val){var node=Y.Node.getDOMNode(this);if(node){if('scrollTop'in node){node.scrollTop=val;}else if(node.document||node.nodeType===9){Y.DOM._getWin(node).scrollTo(Y.DOM.docScrollX(node),val);}}else{}}};Y.Node.importMethod(Y.DOM,['getXY','setXY','getX','setX','getY','setY']);Y.Node.ATTRS.region={getter:function(){var node=Y.Node.getDOMNode(this);if(node&&!node.tagName){if(node.nodeType===9){node=node.documentElement;}else if(node.alert){node=node.document.documentElement;}} +return Y.DOM.region(node);}};Y.Node.ATTRS.viewportRegion={getter:function(){return Y.DOM.viewportRegion(Y.Node.getDOMNode(this));}};Y.Node.importMethod(Y.DOM,'inViewportRegion');Y.Node.prototype.intersect=function(node2,altRegion){var node1=Y.Node.getDOMNode(this);if(node2 instanceof Y.Node){node2=Y.Node.getDOMNode(node2);} +return Y.DOM.intersect(node1,node2,altRegion);};Y.Node.prototype.inRegion=function(node2,all,altRegion){var node1=Y.Node.getDOMNode(this);if(node2 instanceof Y.Node){node2=Y.Node.getDOMNode(node2);} +return Y.DOM.inRegion(node1,node2,all,altRegion);};},'3.0.0',{requires:['dom-screen']}); \ No newline at end of file diff --git a/include/javascript/yui3/build/node/node-style-min.js b/include/javascript/yui3/build/node/node-style-min.js new file mode 100644 index 00000000..7cd8c907 --- /dev/null +++ b/include/javascript/yui3/build/node/node-style-min.js @@ -0,0 +1,8 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add("node-style",function(A){(function(C){var B=["getStyle","getComputedStyle","setStyle","setStyles"];C.Node.importMethod(C.DOM,B);C.NodeList.importMethod(C.Node.prototype,B);})(A);},"3.0.0",{requires:["dom-style","node-base"]}); \ No newline at end of file diff --git a/include/javascript/yui3/build/node/node-style.js b/include/javascript/yui3/build/node/node-style.js new file mode 100644 index 00000000..b6c9fa75 --- /dev/null +++ b/include/javascript/yui3/build/node/node-style.js @@ -0,0 +1,8 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add('node-style',function(Y){(function(Y){var methods=['getStyle','getComputedStyle','setStyle','setStyles'];Y.Node.importMethod(Y.DOM,methods);Y.NodeList.importMethod(Y.Node.prototype,methods);})(Y);},'3.0.0',{requires:['dom-style','node-base']}); \ No newline at end of file diff --git a/include/javascript/yui3/build/node/node.js b/include/javascript/yui3/build/node/node.js new file mode 100644 index 00000000..b36837f0 --- /dev/null +++ b/include/javascript/yui3/build/node/node.js @@ -0,0 +1,57 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add('node-base',function(Y){var DOT='.',NODE_NAME='nodeName',NODE_TYPE='nodeType',OWNER_DOCUMENT='ownerDocument',TAG_NAME='tagName',UID='_yuid',Node=function(node){var uid=node[UID];if(uid&&Node._instances[uid]&&Node._instances[uid]._node!==node){node[UID]=null;} +uid=Y.stamp(node);if(!uid){uid=Y.guid();} +this[UID]=uid;this._node=node;Node._instances[uid]=this;this._stateProxy=node;if(this._initPlugins){this._initPlugins();}},_wrapFn=function(fn){var ret=null;if(fn){ret=(typeof fn==='string')?function(n){return Y.Selector.test(n,fn);}:function(n){return fn(Node.get(n));};} +return ret;};Node.NAME='Node';Node.re_aria=/^(?:role$|aria-)/;Node.DOM_EVENTS={abort:true,beforeunload:true,blur:true,change:true,click:true,close:true,command:true,contextmenu:true,drag:true,dragstart:true,dragenter:true,dragover:true,dragleave:true,dragend:true,drop:true,dblclick:true,error:true,focus:true,keydown:true,keypress:true,keyup:true,load:true,message:true,mousedown:true,mousemove:true,mouseout:true,mouseover:true,mouseup:true,mousemultiwheel:true,mousewheel:true,submit:true,mouseenter:true,mouseleave:true,scroll:true,reset:true,resize:true,select:true,textInput:true,unload:true};Y.mix(Node.DOM_EVENTS,Y.Env.evt.plugins);Node._instances={};Node.getDOMNode=function(node){if(node){return(node.nodeType)?node:node._node||null;} +return null;};Node.scrubVal=function(val,node){if(node&&val){if(typeof val==='object'||typeof val==='function'){if(NODE_TYPE in val||Y.DOM.isWindow(val)){val=Node.get(val);}else if((val.item&&!val._nodes)||(val[0]&&val[0][NODE_TYPE])){val=Y.all(val);}}}else if(val===undefined){val=node;} +return val;};Node.addMethod=function(name,fn,context){if(name&&fn&&typeof fn==='function'){Node.prototype[name]=function(){context=context||this;var args=Y.Array(arguments),ret;if(args[0]&&args[0]instanceof Node){args[0]=args[0]._node;} +if(args[1]&&args[1]instanceof Node){args[1]=args[1]._node;} +args.unshift(this._node);ret=Node.scrubVal(fn.apply(context,args),this);return ret;};}else{}};Node.importMethod=function(host,name,altName){if(typeof name==='string'){altName=altName||name;Node.addMethod(altName,host[name],host);}else{Y.each(name,function(n){Node.importMethod(host,n);});}};Node.one=function(node){var instance=null,cachedNode,uid;if(node){if(typeof node==='string'){if(node.indexOf('doc')===0){node=Y.config.doc;}else if(node.indexOf('win')===0){node=Y.config.win;}else{node=Y.Selector.query(node,null,true);} +if(!node){return null;}}else if(node instanceof Node){return node;} +uid=node._yuid;instance=Node._instances[uid];cachedNode=instance?instance._node:null;if(!instance||(cachedNode&&node!==cachedNode)){instance=new Node(node);}} +return instance;};Node.get=function(){return Node.one.apply(Node,arguments);};Node.create=function(){return Node.get(Y.DOM.create.apply(Y.DOM,arguments));};Node.ATTRS={text:{getter:function(){return Y.DOM.getText(this._node);},setter:function(content){Y.DOM.setText(this._node,content);return content;}},'options':{getter:function(){return this._node.getElementsByTagName('option');}},'elements':{getter:function(){return Y.all(this._node.elements);}},'children':{getter:function(){var node=this._node,children=node.children,childNodes,i,len;if(!children){childNodes=node.childNodes;children=[];for(i=0,len=childNodes.length;i-1){strPath=name;name=name.split(DOT);Y.Object.setValue(node,name,val);}else if(node[name]!==undefined){node[name]=val;} +return val;};Node.DEFAULT_GETTER=function(name){var node=this._stateProxy,val;if(name.indexOf&&name.indexOf(DOT)>-1){val=Y.Object.getValue(node,name.split(DOT));}else if(node[name]!==undefined){val=node[name];} +return val;};Y.augment(Node,Y.Event.Target);Y.mix(Node.prototype,{toString:function(){var str='',errorMsg=this[UID]+': not bound to a node',node=this._node;if(node){str+=node[NODE_NAME];if(node.id){str+='#'+node.id;} +if(node.className){str+='.'+node.className.replace(' ','.');} +str+=' '+this[UID];} +return str||errorMsg;},get:function(attr){var val;if(this._getAttr){val=this._getAttr(attr);}else{val=this._get(attr);} +if(val){val=Y.Node.scrubVal(val,this);} +return val;},_get:function(attr){var attrConfig=Node.ATTRS[attr],val;if(attrConfig&&attrConfig.getter){val=attrConfig.getter.call(this);}else if(Node.re_aria.test(attr)){val=this._node.getAttribute(attr,2);}else{val=Node.DEFAULT_GETTER.apply(this,arguments);} +return val;},set:function(attr,val){var attrConfig=Node.ATTRS[attr];if(this._setAttr){this._setAttr.apply(this,arguments);}else{if(attrConfig&&attrConfig.setter){attrConfig.setter.call(this,val);}else if(Node.re_aria.test(attr)){this._node.setAttribute(attr,val);}else{Node.DEFAULT_SETTER.apply(this,arguments);}} +return this;},setAttrs:function(attrMap){if(this._setAttrs){this._setAttrs(attrMap);}else{Y.Object.each(attrMap,function(v,n){this.set(n,v);},this);} +return this;},getAttrs:function(attrs){var ret={};if(this._getAttrs){this._getAttrs(attrs);}else{Y.Array.each(attrs,function(v,n){ret[v]=this.get(v);},this);} +return ret;},create:Node.create,compareTo:function(refNode){var node=this._node;if(refNode instanceof Y.Node){refNode=refNode._node;} +return node===refNode;},inDoc:function(doc){var node=this._node;doc=(doc)?doc._node||doc:node[OWNER_DOCUMENT];if(doc.documentElement){return Y.DOM.contains(doc.documentElement,node);}},getById:function(id){var node=this._node,ret=Y.DOM.byId(id,node[OWNER_DOCUMENT]);if(ret&&Y.DOM.contains(node,ret)){ret=Y.one(ret);}else{ret=null;} +return ret;},ancestor:function(fn){return Node.get(Y.DOM.elementByAxis(this._node,'parentNode',_wrapFn(fn)));},previous:function(fn,all){return Node.get(Y.DOM.elementByAxis(this._node,'previousSibling',_wrapFn(fn),all));},next:function(node,fn,all){return Node.get(Y.DOM.elementByAxis(this._node,'nextSibling',_wrapFn(fn),all));},one:function(selector){return Y.one(Y.Selector.query(selector,this._node,true));},query:function(selector){return this.one(selector);},all:function(selector){var nodelist=Y.all(Y.Selector.query(selector,this._node));nodelist._query=selector;return nodelist;},queryAll:function(selector){return this.all(selector);},test:function(selector){return Y.Selector.test(this._node,selector);},remove:function(destroy){var node=this._node;node.parentNode.removeChild(node);if(destroy){this.destroy(true);} +return this;},replace:function(newNode){var node=this._node;node.parentNode.replaceChild(newNode,node);return this;},purge:function(recurse,type){Y.Event.purgeElement(this._node,recurse,type);},destroy:function(purge){delete Node._instances[this[UID]];if(purge){this.purge(true);} +if(this.unplug){this.unplug();} +this._node._yuid=null;this._node=null;this._stateProxy=null;},invoke:function(method,a,b,c,d,e){var node=this._node,ret;if(a&&a instanceof Y.Node){a=a._node;} +if(b&&b instanceof Y.Node){b=b._node;} +ret=node[method](a,b,c,d,e);return Y.Node.scrubVal(ret,this);},each:function(fn,context){context=context||this;return fn.call(context,this);},item:function(index){return this;},size:function(){return this._node?1:0;},insert:function(content,where){var node=this._node;if(content){if(typeof where==='number'){where=this._node.childNodes[where];} +if(typeof content!=='string'){if(content._node){content=content._node;}else if(content._nodes||(!content.nodeType&&content.length)){Y.each(content._nodes,function(n){Y.DOM.addHTML(node,n,where);});return this;}} +Y.DOM.addHTML(node,content,where);} +return this;},prepend:function(content){return this.insert(content,0);},append:function(content){return this.insert(content,null);},setContent:function(content){Y.DOM.addHTML(this._node,content,'replace');return this;},hasMethod:function(method){var node=this._node;return(node&&(typeof node==='function'));}},true);Y.Node=Node;Y.get=Y.Node.get;Y.one=Y.Node.one;var NodeList=function(nodes){if(typeof nodes==='string'){this._query=nodes;nodes=Y.Selector.query(nodes);}else{nodes=Y.Array(nodes,0,true);} +NodeList._instances[Y.stamp(this)]=this;this._nodes=nodes;};NodeList.NAME='NodeList';NodeList.getDOMNodes=function(nodeList){return nodeList._nodes;};NodeList._instances=[];NodeList.each=function(instance,fn,context){var nodes=instance._nodes;if(nodes&&nodes.length){Y.Array.each(nodes,fn,context||instance);}else{}};NodeList.addMethod=function(name,fn,context){if(name&&fn){NodeList.prototype[name]=function(){var ret=[],args=arguments;Y.Array.each(this._nodes,function(node){var UID='_yuid',instance=Y.Node._instances[node[UID]],ctx,result;if(!instance){instance=NodeList._getTempNode(node);} +ctx=context||instance;result=fn.apply(ctx,args);if(result!==undefined&&result!==instance){ret[ret.length]=result;}});return ret.length?ret:this;};}else{}};NodeList.importMethod=function(host,name,altName){if(typeof name==='string'){altName=altName||name;NodeList.addMethod(name,host[name]);}else{Y.each(name,function(n){NodeList.importMethod(host,n);});}};NodeList._getTempNode=function(node){var tmp=NodeList._tempNode;if(!tmp){tmp=Y.Node.create('
    ');NodeList._tempNode=tmp;} +tmp._node=node;tmp._stateProxy=node;return tmp;};Y.mix(NodeList.prototype,{item:function(index){return Y.one((this._nodes||[])[index]);},each:function(fn,context){var instance=this;Y.Array.each(this._nodes,function(node,index){node=Y.one(node);return fn.call(context||node,node,index,instance);});return instance;},batch:function(fn,context){var nodelist=this;Y.Array.each(this._nodes,function(node,index){var instance=Y.Node._instances[node[UID]];if(!instance){instance=NodeList._getTempNode(node);} +return fn.call(context||instance,instance,index,nodelist);});return nodelist;},some:function(fn,context){var instance=this;return Y.Array.some(this._nodes,function(node,index){node=Y.one(node);context=context||node;return fn.call(context,node,index,instance);});},toFrag:function(){return Y.one(Y.DOM._nl2frag(this._nodes));},indexOf:function(node){return Y.Array.indexOf(this._nodes,Y.Node.getDOMNode(node));},filter:function(selector){return Y.all(Y.Selector.filter(this._nodes,selector));},modulus:function(n,r){r=r||0;var nodes=[];NodeList.each(this,function(node,i){if(i%n===r){nodes.push(node);}});return Y.all(nodes);},odd:function(){return this.modulus(2,1);},even:function(){return this.modulus(2);},destructor:function(){delete NodeList._instances[this[UID]];},refresh:function(){var doc,nodes=this._nodes;if(this._query){if(nodes&&nodes[0]&&nodes[0].ownerDocument){doc=nodes[0].ownerDocument;} +this._nodes=Y.Selector.query(this._query,doc||Y.config.doc);} +return this;},on:function(type,fn,context){var args=Y.Array(arguments,0,true);args.splice(2,0,this._nodes);args[3]=context||this;return Y.on.apply(Y,args);},after:function(type,fn,context){var args=Y.Array(arguments,0,true);args.splice(2,0,this._nodes);args[3]=context||this;return Y.after.apply(Y,args);},size:function(){return this._nodes.length;},toString:function(){var str='',errorMsg=this[UID]+': not bound to any nodes',nodes=this._nodes,node;if(nodes&&nodes[0]){node=nodes[0];str+=node[NODE_NAME];if(node.id){str+='#'+node.id;} +if(node.className){str+='.'+node.className.replace(' ','.');} +if(nodes.length>1){str+='...['+nodes.length+' items]';}} +return str||errorMsg;}},true);NodeList.importMethod(Y.Node.prototype,['append','detach','detachAll','insert','prepend','remove','set','setContent']);NodeList.prototype.get=function(attr){var ret=[],nodes=this._nodes,isNodeList=false,getTemp=NodeList._getTempNode,instance,val;if(nodes[0]){instance=Y.Node._instances[nodes[0]._yuid]||getTemp(nodes[0]);val=instance._get(attr);if(val&&val.nodeType){isNodeList=true;}} +Y.Array.each(nodes,function(node){instance=Y.Node._instances[node._yuid];if(!instance){instance=getTemp(node);} +val=instance._get(attr);if(!isNodeList){val=Y.Node.scrubVal(val,instance);} +ret.push(val);});return(isNodeList)?Y.all(ret):ret;};Y.NodeList=NodeList;Y.all=function(nodes){return new NodeList(nodes);};Y.Node.all=Y.all;Y.Array.each(['replaceChild','appendChild','insertBefore','removeChild','hasChildNodes','cloneNode','hasAttribute','removeAttribute','scrollIntoView','getElementsByTagName','focus','blur','submit','reset','select'],function(method){Y.Node.prototype[method]=function(arg1,arg2,arg3){var ret=this.invoke(method,arg1,arg2,arg3);return ret;};});Node.importMethod(Y.DOM,['contains','setAttribute','getAttribute']);Y.NodeList.importMethod(Y.Node.prototype,['getAttribute','setAttribute']);(function(Y){var methods=['hasClass','addClass','removeClass','replaceClass','toggleClass'];Y.Node.importMethod(Y.DOM,methods);Y.NodeList.importMethod(Y.Node.prototype,methods);})(Y);if(!document.documentElement.hasAttribute){Y.Node.prototype.hasAttribute=function(attr){return Y.DOM.getAttribute(this._node,attr)!=='';};} +Y.Node.ATTRS.type={setter:function(val){if(val==='hidden'){try{this._node.type='hidden';}catch(e){this.setStyle('display','none');this._inputType='hidden';}}else{try{this._node.type=val;}catch(e){}} +return val;},getter:function(){return this._inputType||this._node.type;},_bypassProxy:true};},'3.0.0',{requires:['dom-base','selector-css2','event-base']});YUI.add('node-style',function(Y){(function(Y){var methods=['getStyle','getComputedStyle','setStyle','setStyles'];Y.Node.importMethod(Y.DOM,methods);Y.NodeList.importMethod(Y.Node.prototype,methods);})(Y);},'3.0.0',{requires:['dom-style','node-base']});YUI.add('node-screen',function(Y){Y.each(['winWidth','winHeight','docWidth','docHeight','docScrollX','docScrollY'],function(name){Y.Node.ATTRS[name]={getter:function(){var args=Array.prototype.slice.call(arguments);args.unshift(Y.Node.getDOMNode(this));return Y.DOM[name].apply(this,args);}};});Y.Node.ATTRS.scrollLeft={getter:function(){var node=Y.Node.getDOMNode(this);return('scrollLeft'in node)?node.scrollLeft:Y.DOM.docScrollX(node);},setter:function(val){var node=Y.Node.getDOMNode(this);if(node){if('scrollLeft'in node){node.scrollLeft=val;}else if(node.document||node.nodeType===9){Y.DOM._getWin(node).scrollTo(val,Y.DOM.docScrollY(node));}}else{}}};Y.Node.ATTRS.scrollTop={getter:function(){var node=Y.Node.getDOMNode(this);return('scrollTop'in node)?node.scrollTop:Y.DOM.docScrollY(node);},setter:function(val){var node=Y.Node.getDOMNode(this);if(node){if('scrollTop'in node){node.scrollTop=val;}else if(node.document||node.nodeType===9){Y.DOM._getWin(node).scrollTo(Y.DOM.docScrollX(node),val);}}else{}}};Y.Node.importMethod(Y.DOM,['getXY','setXY','getX','setX','getY','setY']);Y.Node.ATTRS.region={getter:function(){var node=Y.Node.getDOMNode(this);if(node&&!node.tagName){if(node.nodeType===9){node=node.documentElement;}else if(node.alert){node=node.document.documentElement;}} +return Y.DOM.region(node);}};Y.Node.ATTRS.viewportRegion={getter:function(){return Y.DOM.viewportRegion(Y.Node.getDOMNode(this));}};Y.Node.importMethod(Y.DOM,'inViewportRegion');Y.Node.prototype.intersect=function(node2,altRegion){var node1=Y.Node.getDOMNode(this);if(node2 instanceof Y.Node){node2=Y.Node.getDOMNode(node2);} +return Y.DOM.intersect(node1,node2,altRegion);};Y.Node.prototype.inRegion=function(node2,all,altRegion){var node1=Y.Node.getDOMNode(this);if(node2 instanceof Y.Node){node2=Y.Node.getDOMNode(node2);} +return Y.DOM.inRegion(node1,node2,all,altRegion);};},'3.0.0',{requires:['dom-screen']});YUI.add('node-pluginhost',function(Y){Y.Node.plug=function(){var args=Y.Array(arguments);args.unshift(Y.Node);Y.Plugin.Host.plug.apply(Y.Base,args);return Y.Node;};Y.Node.unplug=function(){var args=Y.Array(arguments);args.unshift(Y.Node);Y.Plugin.Host.unplug.apply(Y.Base,args);return Y.Node;};Y.mix(Y.Node,Y.Plugin.Host,false,null,1);Y.NodeList.prototype.plug=function(){var args=arguments;Y.NodeList.each(this,function(node){Y.Node.prototype.plug.apply(Y.one(node),args);});};Y.NodeList.prototype.unplug=function(){var args=arguments;Y.NodeList.each(this,function(node){Y.Node.prototype.unplug.apply(Y.one(node),args);});};},'3.0.0',{requires:['node-base','pluginhost']});YUI.add('node-event-delegate',function(Y){Y.Node.prototype.delegate=function(type,fn,selector){var args=Array.prototype.slice.call(arguments,3),a=[type,fn,Y.Node.getDOMNode(this),selector];a=a.concat(args);return Y.delegate.apply(Y,a);};},'3.0.0',{requires:['node-base','event-delegate','pluginhost']});YUI.add('node',function(Y){},'3.0.0',{skinnable:false,use:['node-base','node-style','node-screen','node-pluginhost','node-event-delegate'],requires:['dom','event-base','event-delegate','pluginhost']}); \ No newline at end of file diff --git a/include/javascript/yui3/build/oop/oop-min.js b/include/javascript/yui3/build/oop/oop-min.js new file mode 100644 index 00000000..55223cc6 --- /dev/null +++ b/include/javascript/yui3/build/oop/oop-min.js @@ -0,0 +1,8 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add("oop",function(F){var E=F.Lang,D=F.Array,C=Object.prototype,B="_~yuim~_";F.augment=function(A,T,I,R,N){var L=T.prototype,P=null,S=T,O=(N)?F.Array(N):[],H=A.prototype,M=H||A,Q=false,G,J,K;if(H&&S){G={};J={};P={};F.each(L,function(V,U){J[U]=function(){for(K in G){if(G.hasOwnProperty(K)&&(this[K]===J[K])){this[K]=G[K];}}S.apply(this,O);return G[U].apply(this,arguments);};if((!R||(U in R))&&(I||!(U in this))){if(E.isFunction(V)){G[U]=V;this[U]=J[U];}else{this[U]=V;}}},P,true);}else{Q=true;}F.mix(M,P||L,I,R);if(Q){T.apply(M,O);}return A;};F.aggregate=function(H,G,A,I){return F.mix(H,G,A,I,0,true);};F.extend=function(I,H,A,K){if(!H||!I){F.error("extend failed, verify dependencies");}var J=H.prototype,G=F.Object(J);I.prototype=G;G.constructor=I;I.superclass=J;if(H!=Object&&J.constructor==C.constructor){J.constructor=H;}if(A){F.mix(G,A,true);}if(K){F.mix(I,K,true);}return I;};F.each=function(H,G,I,A){if(H.each&&H.item){return H.each.call(H,G,I);}else{switch(D.test(H)){case 1:return D.each(H,G,I);case 2:return D.each(F.Array(H,0,true),G,I);default:return F.Object.each(H,G,I,A);}}};F.clone=function(I,J,M,N,H,L){if(!E.isObject(I)){return I;}var K,G=L||{},A;switch(E.type(I)){case"date":return new Date(I);case"regexp":return new RegExp(I.source);case"function":K=F.bind(I,H);break;case"array":K=[];break;default:if(I[B]){return G[I[B]];}A=F.guid();K=(J)?{}:F.Object(I);I[B]=A;G[A]=I;}if(!I.addEventListener&&!I.attachEvent){F.each(I,function(P,O){if(!M||(M.call(N||this,P,O,this,I)!==false)){if(O!==B){this[O]=F.clone(P,J,M,N,H||I,G);}}},K);}if(!L){F.each(G,function(P,O){delete P[B];});G=null;}return K;};F.bind=function(A,H){var G=arguments.length>2?F.Array(arguments,2,true):null;return function(){var J=E.isString(A)?H[A]:A,I=(G)?G.concat(F.Array(arguments,0,true)):arguments;return J.apply(H||J,I);};};F.rbind=function(A,H){var G=arguments.length>2?F.Array(arguments,2,true):null;return function(){var J=E.isString(A)?H[A]:A,I=(G)?F.Array(arguments,0,true).concat(G):arguments;return J.apply(H||J,I);};};},"3.0.0"); \ No newline at end of file diff --git a/include/javascript/yui3/build/oop/oop.js b/include/javascript/yui3/build/oop/oop.js new file mode 100644 index 00000000..28374f8b --- /dev/null +++ b/include/javascript/yui3/build/oop/oop.js @@ -0,0 +1,20 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add('oop',function(Y){var L=Y.Lang,A=Y.Array,OP=Object.prototype,CLONE_MARKER="_~yuim~_";Y.augment=function(r,s,ov,wl,args){var sProto=s.prototype,newProto=null,construct=s,a=(args)?Y.Array(args):[],rProto=r.prototype,target=rProto||r,applyConstructor=false,sequestered,replacements,i;if(rProto&&construct){sequestered={};replacements={};newProto={};Y.each(sProto,function(v,k){replacements[k]=function(){for(i in sequestered){if(sequestered.hasOwnProperty(i)&&(this[i]===replacements[i])){this[i]=sequestered[i];}} +construct.apply(this,a);return sequestered[k].apply(this,arguments);};if((!wl||(k in wl))&&(ov||!(k in this))){if(L.isFunction(v)){sequestered[k]=v;this[k]=replacements[k];}else{this[k]=v;}}},newProto,true);}else{applyConstructor=true;} +Y.mix(target,newProto||sProto,ov,wl);if(applyConstructor){s.apply(target,a);} +return r;};Y.aggregate=function(r,s,ov,wl){return Y.mix(r,s,ov,wl,0,true);};Y.extend=function(r,s,px,sx){if(!s||!r){Y.error("extend failed, verify dependencies");} +var sp=s.prototype,rp=Y.Object(sp);r.prototype=rp;rp.constructor=r;r.superclass=sp;if(s!=Object&&sp.constructor==OP.constructor){sp.constructor=s;} +if(px){Y.mix(rp,px,true);} +if(sx){Y.mix(r,sx,true);} +return r;};Y.each=function(o,f,c,proto){if(o.each&&o.item){return o.each.call(o,f,c);}else{switch(A.test(o)){case 1:return A.each(o,f,c);case 2:return A.each(Y.Array(o,0,true),f,c);default:return Y.Object.each(o,f,c,proto);}}};Y.clone=function(o,safe,f,c,owner,cloned){if(!L.isObject(o)){return o;} +var o2,marked=cloned||{},stamp;switch(L.type(o)){case'date':return new Date(o);case'regexp':return new RegExp(o.source);case'function':o2=Y.bind(o,owner);break;case'array':o2=[];break;default:if(o[CLONE_MARKER]){return marked[o[CLONE_MARKER]];} +stamp=Y.guid();o2=(safe)?{}:Y.Object(o);o[CLONE_MARKER]=stamp;marked[stamp]=o;} +if(!o.addEventListener&&!o.attachEvent){Y.each(o,function(v,k){if(!f||(f.call(c||this,v,k,this,o)!==false)){if(k!==CLONE_MARKER){this[k]=Y.clone(v,safe,f,c,owner||o,marked);}}},o2);} +if(!cloned){Y.each(marked,function(v,k){delete v[CLONE_MARKER];});marked=null;} +return o2;};Y.bind=function(f,c){var xargs=arguments.length>2?Y.Array(arguments,2,true):null;return function(){var fn=L.isString(f)?c[f]:f,args=(xargs)?xargs.concat(Y.Array(arguments,0,true)):arguments;return fn.apply(c||fn,args);};};Y.rbind=function(f,c){var xargs=arguments.length>2?Y.Array(arguments,2,true):null;return function(){var fn=L.isString(f)?c[f]:f,args=(xargs)?Y.Array(arguments,0,true).concat(xargs):arguments;return fn.apply(c||fn,args);};};},'3.0.0'); \ No newline at end of file diff --git a/include/javascript/yui3/build/overlay/assets/overlay-core.css b/include/javascript/yui3/build/overlay/assets/overlay-core.css new file mode 100644 index 00000000..1cab3bec --- /dev/null +++ b/include/javascript/yui3/build/overlay/assets/overlay-core.css @@ -0,0 +1,14 @@ +/* +Copyright (c) 2009, Yahoo! Inc. All rights reserved. +Code licensed under the BSD License: +http://developer.yahoo.net/yui/license.txt +version: 3.0.0 +build: 1549 + +.yui-overlay { + position:absolute; +} + +.yui-overlay-hidden { + visibility:hidden +}*/ diff --git a/include/javascript/yui3/build/overlay/assets/skins/sam/overlay-skin.css b/include/javascript/yui3/build/overlay/assets/skins/sam/overlay-skin.css new file mode 100644 index 00000000..dbc8374a --- /dev/null +++ b/include/javascript/yui3/build/overlay/assets/skins/sam/overlay-skin.css @@ -0,0 +1,7 @@ +/* +Copyright (c) 2009, Yahoo! Inc. All rights reserved. +Code licensed under the BSD License: +http://developer.yahoo.net/yui/license.txt +version: 3.0.0 +build: 1549 +*/ diff --git a/include/javascript/yui3/build/overlay/assets/skins/sam/overlay.css b/include/javascript/yui3/build/overlay/assets/skins/sam/overlay.css new file mode 100644 index 00000000..80ef091a --- /dev/null +++ b/include/javascript/yui3/build/overlay/assets/skins/sam/overlay.css @@ -0,0 +1,9 @@ +/* +Copyright (c) 2009, Yahoo! Inc. All rights reserved. +Code licensed under the BSD License: +http://developer.yahoo.net/yui/license.txt +version: 3.0.0 +build: 1549 +//Commented out until YUI 3 overlay classes no longer conflicts with the YUI 2 overlay css + +.yui-overlay{position:absolute;}.yui-overlay-hidden{visibility:hidden;}*/ diff --git a/include/javascript/yui3/build/overlay/overlay-min.js b/include/javascript/yui3/build/overlay/overlay-min.js new file mode 100644 index 00000000..534e6d5c --- /dev/null +++ b/include/javascript/yui3/build/overlay/overlay-min.js @@ -0,0 +1,8 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add("overlay",function(A){A.Overlay=A.Base.build("overlay",A.Widget,[A.WidgetPosition,A.WidgetStack,A.WidgetPositionExt,A.WidgetStdMod]);},"3.0.0",{requires:["widget","widget-position","widget-stack","widget-position-ext","widget-stdmod"]}); \ No newline at end of file diff --git a/include/javascript/yui3/build/overlay/overlay.js b/include/javascript/yui3/build/overlay/overlay.js new file mode 100644 index 00000000..24497e53 --- /dev/null +++ b/include/javascript/yui3/build/overlay/overlay.js @@ -0,0 +1,8 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add('overlay',function(Y){Y.Overlay=Y.Base.build("overlay",Y.Widget,[Y.WidgetPosition,Y.WidgetStack,Y.WidgetPositionExt,Y.WidgetStdMod]);},'3.0.0',{requires:['widget','widget-position','widget-stack','widget-position-ext','widget-stdmod']}); \ No newline at end of file diff --git a/include/javascript/yui3/build/plugin/plugin-min.js b/include/javascript/yui3/build/plugin/plugin-min.js new file mode 100644 index 00000000..6e0ae28f --- /dev/null +++ b/include/javascript/yui3/build/plugin/plugin-min.js @@ -0,0 +1,8 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add("plugin",function(B){function A(C){A.superclass.constructor.apply(this,arguments);}A.ATTRS={host:{writeOnce:true}};A.NAME="plugin";A.NS="plugin";B.extend(A,B.Base,{_handles:null,initializer:function(C){this._handles=[];},destructor:function(){if(this._handles){for(var D=0,C=this._handles.length;D=0;I--){F=G[I];L=F._UNPLUG;if(L){C.mix(H,L,true);}K=F._PLUG;if(K){C.mix(D,K,true);}}for(J in D){if(D.hasOwnProperty(J)){if(!H[J]){this.plug(D[J]);}}}if(E&&E.plugins){this.plug(E.plugins);}},_destroyPlugins:function(){this._unplug();},_plug:function(F,D){if(F&&F.NS){var E=F.NS;D=D||{};D.host=this;if(this.hasPlugin(E)){this[E].setAttrs(D);}else{this[E]=new F(D);this._plugins[E]=F;}}},_unplug:function(F){var E=F,D=this._plugins;if(A.isFunction(F)){E=F.NS;if(E&&(!D[E]||D[E]!==F)){E=null;}}if(E){if(this[E]){this[E].destroy();delete this[E];}if(D[E]){delete D[E];}}}};B.plug=function(E,I,G){var J,H,D,F;if(E!==C.Base){E._PLUG=E._PLUG||{};if(!A.isArray(I)){if(G){I={fn:I,cfg:G};}I=[I];}for(H=0,D=I.length;H=0;i--){constructor=classes[i];classUnplug=constructor._UNPLUG;if(classUnplug){Y.mix(unplug,classUnplug,true);} +classPlug=constructor._PLUG;if(classPlug){Y.mix(plug,classPlug,true);}} +for(pluginClassName in plug){if(plug.hasOwnProperty(pluginClassName)){if(!unplug[pluginClassName]){this.plug(plug[pluginClassName]);}}} +if(config&&config.plugins){this.plug(config.plugins);}},_destroyPlugins:function(){this._unplug();},_plug:function(PluginClass,config){if(PluginClass&&PluginClass.NS){var ns=PluginClass.NS;config=config||{};config.host=this;if(this.hasPlugin(ns)){this[ns].setAttrs(config);}else{this[ns]=new PluginClass(config);this._plugins[ns]=PluginClass;}}},_unplug:function(plugin){var ns=plugin,plugins=this._plugins;if(L.isFunction(plugin)){ns=plugin.NS;if(ns&&(!plugins[ns]||plugins[ns]!==plugin)){ns=null;}} +if(ns){if(this[ns]){this[ns].destroy();delete this[ns];} +if(plugins[ns]){delete plugins[ns];}}}};PluginHost.plug=function(hostClass,plugin,config){var p,i,l,name;if(hostClass!==Y.Base){hostClass._PLUG=hostClass._PLUG||{};if(!L.isArray(plugin)){if(config){plugin={fn:plugin,cfg:config};} +plugin=[plugin];} +for(i=0,l=plugin.length;i1){functionData.avg=((functionData.avg*(functionData.calls-1))+duration)/functionData.calls;functionData.min=Math.min(functionData.min,duration);functionData.max=Math.max(functionData.max,duration);}else{functionData.avg=duration;functionData.min=duration;functionData.max=duration;}}Y.Profiler={clear:function(name){if(L.isString(name)){delete report[name];delete stopwatches[name];}else{report={};stopwatches={};}},getOriginal:function(name){return container[name];},instrument:function(name,method){var newMethod=function(){var start=new Date(),retval=method.apply(this,arguments),stop=new Date();saveDataPoint(name,stop-start);return retval;};Y.mix(newMethod,method);newMethod.__yuiProfiled=true;newMethod.prototype=method.prototype;container[name]=method;container[name].__yuiFuncName=name;createReport(name);return newMethod;},pause:function(name){var now=new Date(),stopwatch=stopwatches[name];if(stopwatch&&stopwatch.state==WATCH_STARTED){stopwatch.total+=(now-stopwatch.start);stopwatch.start=0;stopwatch.state=WATCH_PAUSED;}},start:function(name){if(container[name]){throw new Error("Cannot use '"+name+"' for profiling through start(), name is already in use.");}else{if(!report[name]){createReport(name);}if(!stopwatches[name]){stopwatches[name]={state:WATCH_STOPPED,start:0,total:0};}if(stopwatches[name].state==WATCH_STOPPED){stopwatches[name].state=WATCH_STARTED;stopwatches[name].start=new Date();}}},stop:function(name){var now=new Date(),stopwatch=stopwatches[name];if(stopwatch){if(stopwatch.state==WATCH_STARTED){saveDataPoint(name,stopwatch.total+(now-stopwatch.start));}else{if(stopwatch.state==WATCH_PAUSED){saveDataPoint(name,stopwatch.total);}}stopwatch.start=0;stopwatch.total=0;stopwatch.state=WATCH_STOPPED;}},getAverage:function(name){return report[name].avg;},getCallCount:function(name){return report[name].calls;},getMax:function(name){return report[name].max;},getMin:function(name){return report[name].min;},getFunctionReport:function(name){return report[name];},getReport:function(name){return report[name];},getFullReport:function(filter){filter=filter||function(){return true;};if(L.isFunction(filter)){var fullReport={};for(var name in report){if(filter(report[name])){fullReport[name]=report[name];}}return fullReport;}},registerConstructor:function(name,owner){this.registerFunction(name,owner,true);},registerFunction:function(name,owner,registerPrototype){var funcName=(name.indexOf(".")>-1?name.substring(name.lastIndexOf(".")+1):name),method,prototype;if(!L.isObject(owner)){owner=eval(name.substring(0,name.lastIndexOf(".")));}method=owner[funcName];prototype=method.prototype;if(L.isFunction(method)&&!method.__yuiProfiled){owner[funcName]=this.instrument(name,method);container[name].__yuiOwner=owner;container[name].__yuiFuncName=funcName;if(registerPrototype){this.registerObject(name+".prototype",prototype);}}},registerObject:function(name,object,recurse){object=(L.isObject(object)?object:eval(name));container[name]=object;for(var prop in object){if(typeof object[prop]=="function"){if(prop!="constructor"&&prop!="superclass"){this.registerFunction(name+"."+prop,object);}}else{if(typeof object[prop]=="object"&&recurse){this.registerObject(name+"."+prop,object[prop],recurse);}}}},unregisterConstructor:function(name){if(L.isFunction(container[name])){this.unregisterFunction(name,true);}},unregisterFunction:function(name,unregisterPrototype){if(L.isFunction(container[name])){if(unregisterPrototype){this.unregisterObject(name+".prototype",container[name].prototype);}var owner=container[name].__yuiOwner,funcName=container[name].__yuiFuncName;delete container[name].__yuiOwner;delete container[name].__yuiFuncName;owner[funcName]=container[name];delete container[name];}},unregisterObject:function(name,recurse){if(L.isObject(container[name])){var object=container[name];for(var prop in object){if(typeof object[prop]=="function"){this.unregisterFunction(name+"."+prop);}else{if(typeof object[prop]=="object"&&recurse){this.unregisterObject(name+"."+prop,recurse);}}}delete container[name];}}};},"3.0.0",{requires:["oop"]}); \ No newline at end of file diff --git a/include/javascript/yui3/build/profiler/profiler.js b/include/javascript/yui3/build/profiler/profiler.js new file mode 100644 index 00000000..b069a9b9 --- /dev/null +++ b/include/javascript/yui3/build/profiler/profiler.js @@ -0,0 +1,18 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add('profiler',function(Y){var container={},report={},stopwatches={},WATCH_STARTED=0,WATCH_STOPPED=1,WATCH_PAUSED=2,L=Y.Lang;function createReport(name){report[name]={calls:0,max:0,min:0,avg:0,points:[]};return report[name];} +function saveDataPoint(name,duration){var functionData=report[name];if(!functionData){functionData=createReport(name);} +functionData.calls++;functionData.points.push(duration);if(functionData.calls>1){functionData.avg=((functionData.avg*(functionData.calls-1))+duration)/functionData.calls;functionData.min=Math.min(functionData.min,duration);functionData.max=Math.max(functionData.max,duration);}else{functionData.avg=duration;functionData.min=duration;functionData.max=duration;}} +Y.Profiler={clear:function(name){if(L.isString(name)){delete report[name];delete stopwatches[name];}else{report={};stopwatches={};}},getOriginal:function(name){return container[name];},instrument:function(name,method){var newMethod=function(){var start=new Date(),retval=method.apply(this,arguments),stop=new Date();saveDataPoint(name,stop-start);return retval;};Y.mix(newMethod,method);newMethod.__yuiProfiled=true;newMethod.prototype=method.prototype;container[name]=method;container[name].__yuiFuncName=name;createReport(name);return newMethod;},pause:function(name){var now=new Date(),stopwatch=stopwatches[name];if(stopwatch&&stopwatch.state==WATCH_STARTED){stopwatch.total+=(now-stopwatch.start);stopwatch.start=0;stopwatch.state=WATCH_PAUSED;}},start:function(name){if(container[name]){throw new Error("Cannot use '"+name+"' for profiling through start(), name is already in use.");}else{if(!report[name]){createReport(name);} +if(!stopwatches[name]){stopwatches[name]={state:WATCH_STOPPED,start:0,total:0};} +if(stopwatches[name].state==WATCH_STOPPED){stopwatches[name].state=WATCH_STARTED;stopwatches[name].start=new Date();}}},stop:function(name){var now=new Date(),stopwatch=stopwatches[name];if(stopwatch){if(stopwatch.state==WATCH_STARTED){saveDataPoint(name,stopwatch.total+(now-stopwatch.start));}else if(stopwatch.state==WATCH_PAUSED){saveDataPoint(name,stopwatch.total);} +stopwatch.start=0;stopwatch.total=0;stopwatch.state=WATCH_STOPPED;}},getAverage:function(name){return report[name].avg;},getCallCount:function(name){return report[name].calls;},getMax:function(name){return report[name].max;},getMin:function(name){return report[name].min;},getFunctionReport:function(name){return report[name];},getReport:function(name){return report[name];},getFullReport:function(filter){filter=filter||function(){return true;};if(L.isFunction(filter)){var fullReport={};for(var name in report){if(filter(report[name])){fullReport[name]=report[name];}} +return fullReport;}},registerConstructor:function(name,owner){this.registerFunction(name,owner,true);},registerFunction:function(name,owner,registerPrototype){var funcName=(name.indexOf(".")>-1?name.substring(name.lastIndexOf(".")+1):name),method,prototype;if(!L.isObject(owner)){owner=eval(name.substring(0,name.lastIndexOf(".")));} +method=owner[funcName];prototype=method.prototype;if(L.isFunction(method)&&!method.__yuiProfiled){owner[funcName]=this.instrument(name,method);container[name].__yuiOwner=owner;container[name].__yuiFuncName=funcName;if(registerPrototype){this.registerObject(name+".prototype",prototype);}}},registerObject:function(name,object,recurse){object=(L.isObject(object)?object:eval(name));container[name]=object;for(var prop in object){if(typeof object[prop]=="function"){if(prop!="constructor"&&prop!="superclass"){this.registerFunction(name+"."+prop,object);}}else if(typeof object[prop]=="object"&&recurse){this.registerObject(name+"."+prop,object[prop],recurse);}}},unregisterConstructor:function(name){if(L.isFunction(container[name])){this.unregisterFunction(name,true);}},unregisterFunction:function(name,unregisterPrototype){if(L.isFunction(container[name])){if(unregisterPrototype){this.unregisterObject(name+".prototype",container[name].prototype);} +var owner=container[name].__yuiOwner,funcName=container[name].__yuiFuncName;delete container[name].__yuiOwner;delete container[name].__yuiFuncName;owner[funcName]=container[name];delete container[name];}},unregisterObject:function(name,recurse){if(L.isObject(container[name])){var object=container[name];for(var prop in object){if(typeof object[prop]=="function"){this.unregisterFunction(name+"."+prop);}else if(typeof object[prop]=="object"&&recurse){this.unregisterObject(name+"."+prop,recurse);}} +delete container[name];}}};},'3.0.0',{requires:['oop']}); \ No newline at end of file diff --git a/include/javascript/yui3/build/queue-promote/queue-promote-min.js b/include/javascript/yui3/build/queue-promote/queue-promote-min.js new file mode 100644 index 00000000..b02947f2 --- /dev/null +++ b/include/javascript/yui3/build/queue-promote/queue-promote-min.js @@ -0,0 +1,8 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add("queue-promote",function(A){A.mix(A.Queue.prototype,{indexOf:function(B){return A.Array.indexOf(this._q,B);},promote:function(C){var B=this.indexOf(C);if(B>-1){this._q.unshift(this._q.splice(B,1));}},remove:function(C){var B=this.indexOf(C);if(B>-1){this._q.splice(B,1);}}});},"3.0.0",{requires:["yui-base"]}); \ No newline at end of file diff --git a/include/javascript/yui3/build/queue-promote/queue-promote.js b/include/javascript/yui3/build/queue-promote/queue-promote.js new file mode 100644 index 00000000..710ce870 --- /dev/null +++ b/include/javascript/yui3/build/queue-promote/queue-promote.js @@ -0,0 +1,8 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add('queue-promote',function(Y){Y.mix(Y.Queue.prototype,{indexOf:function(callback){return Y.Array.indexOf(this._q,callback);},promote:function(callback){var index=this.indexOf(callback);if(index>-1){this._q.unshift(this._q.splice(index,1));}},remove:function(callback){var index=this.indexOf(callback);if(index>-1){this._q.splice(index,1);}}});},'3.0.0',{requires:['yui-base']}); \ No newline at end of file diff --git a/include/javascript/yui3/build/slider/assets/skins/sam/rail-classic-x.png b/include/javascript/yui3/build/slider/assets/skins/sam/rail-classic-x.png new file mode 100644 index 0000000000000000000000000000000000000000..553c8236827b8b2c5b149af95e80212f366fc7ee GIT binary patch literal 92 zcmeAS@N?(olHy`uVBq!ia0vp^j6lr7!3-oT*p_ktDb4_&5ZBJm&h6W`U%!4m`PGdt oKtVoF7sn8e>&XcT2~19I3=EPCY!Oky-ar`!Pgg&ebxsLQ0JeV?@&Et; literal 0 HcmV?d00001 diff --git a/include/javascript/yui3/build/slider/assets/skins/sam/rail-classic-y.png b/include/javascript/yui3/build/slider/assets/skins/sam/rail-classic-y.png new file mode 100644 index 0000000000000000000000000000000000000000..dae35afbfc3fb8a043847d331468dfaf01184a27 GIT binary patch literal 90 zcmeAS@N?(olHy`uVBq!ia0vp^%s|Y@0U~wmp0oie&H$ef*X`T4FJHd=`t|GgbmtWT k1$jJO978y+CnuyN0eRdEEdJNKvw8U}fi7AzZCsS>JiV^~RLR`1+*nR%OrIV-596oaF=dWL9&s|u&bor&rS8m?A z{rts?Yu9f)dh~e5u06+3oLakX!{#m9zJLF*b^ETb-@g6$@#Db3LvP-`{qW)ApFe+| zJbC*0^XC^YU#;7)>EFM9_a8j`_3PLF|NrMiA5{d}rBD*&7YyX$0}L@S(r~$oQM``RuFKxDCV-ZBe_PvQzqsA?jEn8TDxV>%s%DjFR|IN{>M%3=syeHCD(~v zSrx^+)O!`%!K;_ItoX+^|KjQ5-`qk8m)%0S<@t+5FX)$io04Y4mt1wZpzOO+_6B>V zwQQH_PVftezs#DPvE{|AxwH5z*NS`&Z(wBDBrU=293u7t=oSV~S3j3^P6&~?4vmZTv{O{ktmoH!a z{rB(vhY!Dh|Nipz>(8G*|AT>k_ZoJfT?!>Ze!&nCoFqd`jPzTe+IUYF$B>F!G3P9q z8WaSaFKRSNFM8B<`_BJqT&zs%|M)U(O4(S!5?y4opEa{^<%BeDg9{NeIhfa
    '));this.set(Z,M);}else{if(!L.contains(M)){L.appendChild(M);}}M.addClass(B);M.addClass(this.getClassName(Z,this.get("axis")));},_initThumb:function(){var M=this.get(Z),L=this.get(m);if(L&&!this.get(R)&&L.get("nodeName").toLowerCase()==="img"){this.set(R,L);this.set(m,null);L=null;}if(!L){L=A.Node.create('
    ');this.set(m,L);}L.addClass(C);if(!M.contains(L)){M.appendChild(L);}if(this.get(R)){this._initThumbImage();}},_initThumbImage:function(){var M=this.get(m),L=this.get(R);if(L){L.replaceClass(C,T);if(!M.contains(L)){M.appendChild(L);}}},bindUI:function(){this.publish(X,{defaultFn:this._defThumbDragFn});this._bindThumbDD();this.after("valueChange",this._afterValueChange);this.after("thumbImageChange",this._afterThumbImageChange);this.after(O,this._afterDisabledChange);},_bindThumbDD:function(){var M={node:this.get(m),bubble:false},L={constrain2node:this.get(Z)};L[this._key.ddStick]=true;this._dd=new A.DD.Drag(M).plug(A.Plugin.DDConstrained,L);this._dd.on("drag:start",A.bind(this._onDDStartDrag,this));this._dd.on("drag:drag",A.bind(this._onDDDrag,this));this._dd.on("drag:end",A.bind(this._onDDEndDrag,this));this._initRailDD();},_initRailDD:function(){this.get(Z).on("mousedown",A.bind(this._handleRailMouseDown,this));},_handleRailMouseDown:function(Y){if(this.get("railEnabled")&&!this.get(d)){var L=this._dd,r=this._key.xyIndex,M;if(L.get("primaryButtonOnly")&&Y.button>1){return false;}L._dragThreshMet=true;L._fixIEMouseDown();Y.halt();A.DD.DDM.activeDrag=L;M=L.get("dragNode").getXY();M[r]+=this._thumbOffset;L._setStartPosition(M);L.set("activeHandle",L.get("dragNode"));L.start();L._alignNode([Y.pageX,Y.pageY]);}},syncUI:function(){this.get(c).removeClass(E);var L=this.get(R);if(this._isImageLoading(L)){this._scheduleSync();}else{this._ready(L,!this._isImageLoaded(L));}},_scheduleSync:function(){var L,M;if(!this._stall){this._disabled=this.get(d);this.set(d,true);this._stall=this.on(O,this._stallDisabledChange);L=this.get(R);M=A.bind(this._imageLoaded,this,L);L.on("load",M);L.on("error",M);}},_stallDisabledChange:function(L){this._disabled=L.newVal;L.preventDefault();},_imageLoaded:function(L,Y){var M=(Y.type.toLowerCase().indexOf("error")>-1);A.later(0,this,function(){if(this._stall){this._stall.detach();}this._stall=false;this._ready(L,M);this.set(d,this._disabled);});},_ready:function(L,M){var Y=M?"addClass":"removeClass";this.get(c)[Y](E);this.fire(e);},_defSyncFn:function(L){this._uiSetThumbSize();this._setThumbOffset();this._uiSetRailSize();this._setRailOffsetXY();this._setDDGutter();this._resetDDCacheRegion();this._setFactor();var M=this.get(l);this.fire(H,{value:M,offset:this._convertValueToOffset(M)});this.get("boundingBox").toggleClass("");},_uiSetThumbSize:function(){var M=this.get(m),r=this._key.dim,L=this.get(R),Y;Y=parseInt(M.getComputedStyle(r),10);if(L&&this._isImageLoaded(L)){Y=L.get(r);}this._thumbSize=Y;},_setThumbOffset:function(){this._thumbOffset=F(this._thumbSize/2);},_uiSetRailSize:function(){var t=this.get(Z),M=this.get(m),L=this.get(R),s=this._key.dim,Y=this.get(n),r=false;if(parseInt(Y,10)){t.setStyle(s,Y);Y=parseInt(t.getComputedStyle(s),10);}else{Y=this.get(s);if(parseInt(Y,10)){r=true;t.setStyle(s,Y);Y=parseInt(t.getComputedStyle(s),10);}Y=V(Y|0,parseInt(M.getComputedStyle(s),10),parseInt(t.getComputedStyle(s),10));if(L&&this._isImageLoaded(L)){Y=V(L.get(s),Y);}}t.setStyle(s,Y+q);this._railSize=Y;if(r){s=this._key.offAxisDim;Y=this.get(s);if(Y){t.set(s,Y);}}},_setRailOffsetXY:function(){this._offsetXY=this.get(Z).getXY()[this._key.xyIndex]+this.get(J);},_setDDGutter:function(){var L=this._key.xyIndex?this.get(J)+" 0 "+this.get(b):"0 "+this.get(b)+" 0 "+this.get(J);this._dd.con.set("gutter",L);},_resetDDCacheRegion:function(){this._dd.con._cacheRegion();},_setFactor:function(){var L=this._railSize-this._thumbSize-this.get(J)-this.get(b);this._factor=this._railSize?(this.get(o)-this.get(U))/L:1;},getValue:function(){return this.get(l);},setValue:function(L){this.set(l,L);},_validateNewAxis:function(L){return P(L)&&"xXyY".indexOf(L.charAt(0))>-1;},_validateNewMin:function(L){return p(L);},_validateNewMax:function(L){return p(L);},_validateNewValue:function(M){var Y=this.get(U),L=this.get(o);return p(M)&&(Y=Y&&M<=L):(M>=L&&M<=Y));},_validateNewRail:function(L){return!this.get(j)||L;},_validateNewThumb:function(L){return!this.get(j)||L;},_validateNewThumbImage:function(L){return!this.get(j)||L;},_validateNewRailSize:function(L){return P(L)&&(L==="0"||/^\d+(?:p[xtc]|%|e[mx]|in|[mc]m)$/.test(L));},_setAxisFn:function(L){return L.charAt(0).toLowerCase();},_setRailFn:function(L){return A.get(L)||null;},_setThumbFn:function(L){return A.get(L)||null;},_setThumbImageFn:function(L){return L?A.get(L)||A.Node.create('Slider thumb'):null;},_onDDStartDrag:function(L){this._setRailOffsetXY();this.fire(Q,{ddEvent:L});},_onDDDrag:function(L){this.fire(X,{ddEvent:L});},_defThumbDragFn:function(M){var L=this.get(l),Y=M.ddEvent[this._key.eventPageAxis]-this._offsetXY;Y=this._convertOffsetToValue(Y);if(L!==Y){this.set(l,Y,{ddEvent:M.ddEvent});}},_onDDEndDrag:function(L){this.fire(a,{ddEvent:L});},_defPositionThumbFn:function(L){this._uiPositionThumb(L.offset);},_uiPositionThumb:function(r){var L=this._dd,M=L.get("dragNode"),Y=M.ancestor(this._isDisplayNone);if(!Y){L._setStartPosition(L.get("dragNode").getXY());L._alignNode([r,r],true);}},_isDisplayNone:function(L){return L.getComputedStyle("display")==="none";},_afterValueChange:function(M){if(!M.ddEvent){var L=this._convertValueToOffset(M.newVal);this.fire(H,{value:M.newVal,offset:L});}},_convertValueToOffset:function(L){return k((L-this.get(U))/this._factor)+this._offsetXY;},_convertOffsetToValue:function(L){return k(this.get(U)+(L*this._factor));},_afterThumbChange:function(M){var L;if(this.get(j)){if(M.prevValue){M.prevValue.get("parentNode").removeChild(M.prevValue);}this._initThumb();L=this.get(m);this._dd.set("node",L);this._dd.set("dragNode",L);this.syncUI();}},_afterThumbImageChange:function(L){if(this.get(j)){if(L.prevValue){L.prevValue.get("parentNode").removeChild(L.prevValue);}this._initThumbImage();this.syncUI();}},_afterMinChange:function(L){this._refresh(L);},_afterMaxChange:function(L){this._refresh(L);},_afterRailSizeChange:function(L){this._refresh(L);},_afterDisabledChange:function(L){if(this._dd){this._dd.set("lock",L.newVal);}},_refresh:function(L){if(L.newVal!==L.prevVal&&this.get(j)){this.syncUI();}},_isImageLoading:function(L){return L&&!L.get(S);},_isImageLoaded:function(M){if(M){var L=M.get("naturalWidth");return M.get(S)&&(!p(L)?M.get(D):L);}return true;}});A.Slider=h;},"3.0.0",{requires:["widget","dd-constrain"]}); \ No newline at end of file diff --git a/include/javascript/yui3/build/slider/slider.js b/include/javascript/yui3/build/slider/slider.js new file mode 100644 index 00000000..dd34b1af --- /dev/null +++ b/include/javascript/yui3/build/slider/slider.js @@ -0,0 +1,23 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add('slider',function(Y){var SLIDER='slider',RAIL='rail',THUMB='thumb',VALUE='value',MIN='min',MAX='max',MIN_GUTTER='minGutter',MAX_GUTTER='maxGutter',THUMB_IMAGE='thumbImage',RAIL_SIZE='railSize',CONTENT_BOX='contentBox',SLIDE_START='slideStart',SLIDE_END='slideEnd',THUMB_DRAG='thumbDrag',SYNC='sync',POSITION_THUMB='positionThumb',RENDERED='rendered',DISABLED='disabled',DISABLED_CHANGE='disabledChange',DOT='.',PX='px',WIDTH='width',HEIGHT='height',COMPLETE='complete',L=Y.Lang,isBoolean=L.isBoolean,isString=L.isString,isNumber=L.isNumber,getCN=Y.ClassNameManager.getClassName,IMAGE='image',C_RAIL=getCN(SLIDER,RAIL),C_THUMB=getCN(SLIDER,THUMB),C_THUMB_IMAGE=getCN(SLIDER,THUMB,IMAGE),C_IMAGE_ERROR=getCN(SLIDER,IMAGE,'error'),M=Math,max=M.max,round=M.round,floor=M.floor;function Slider(){Slider.superclass.constructor.apply(this,arguments);} +Y.mix(Slider,{NAME:SLIDER,_AXIS_KEYS:{x:{dim:WIDTH,offAxisDim:HEIGHT,eventPageAxis:'pageX',ddStick:'stickX',xyIndex:0},y:{dim:HEIGHT,offAxisDim:WIDTH,eventPageAxis:'pageY',ddStick:'stickY',xyIndex:1}},HTML_PARSER:{rail:DOT+C_RAIL,thumb:DOT+C_THUMB,thumbImage:DOT+C_THUMB_IMAGE},ATTRS:{axis:{value:'x',writeOnce:true,validator:function(v){return this._validateNewAxis(v);},setter:function(v){return this._setAxisFn(v);}},min:{value:0,validator:function(v){return this._validateNewMin(v);}},max:{value:100,validator:function(v){return this._validateNewMax(v);}},value:{value:0,validator:function(v){return this._validateNewValue(v);}},rail:{value:null,validator:function(v){return this._validateNewRail(v);},setter:function(v){return this._setRailFn(v);}},thumb:{value:null,validator:function(v){return this._validateNewThumb(v);},setter:function(v){return this._setThumbFn(v);}},thumbImage:{value:null,validator:function(v){return this._validateNewThumbImage(v);},setter:function(v){return this._setThumbImageFn(v);}},railSize:{value:'0',validator:function(v){return this._validateNewRailSize(v);}},railEnabled:{value:true,validator:isBoolean},minGutter:{value:0,validator:isNumber},maxGutter:{value:0,validator:isNumber}}});Y.extend(Slider,Y.Widget,{_key:null,_factor:1,_railSize:null,_thumbSize:null,_thumbOffset:0,_stall:false,_disabled:false,initializer:function(){this._key=Slider._AXIS_KEYS[this.get('axis')];this.after('minChange',this._afterMinChange);this.after('maxChange',this._afterMaxChange);this.after('railSizeChange',this._afterRailSizeChange);this.publish(SLIDE_START);this.publish(SLIDE_END);this.publish(SYNC,{defaultFn:this._defSyncFn});this.publish(POSITION_THUMB,{defaultFn:this._defPositionThumbFn});},renderUI:function(){this._initRail();this._initThumb();},_initRail:function(){var cb=this.get(CONTENT_BOX),rail=this.get(RAIL);if(!rail){rail=cb.appendChild(Y.Node.create('
    '));this.set(RAIL,rail);}else if(!cb.contains(rail)){cb.appendChild(rail);} +rail.addClass(C_RAIL);rail.addClass(this.getClassName(RAIL,this.get('axis')));},_initThumb:function(){var rail=this.get(RAIL),thumb=this.get(THUMB);if(thumb&&!this.get(THUMB_IMAGE)&&thumb.get('nodeName').toLowerCase()==='img'){this.set(THUMB_IMAGE,thumb);this.set(THUMB,null);thumb=null;} +if(!thumb){thumb=Y.Node.create('
    ');this.set(THUMB,thumb);} +thumb.addClass(C_THUMB);if(!rail.contains(thumb)){rail.appendChild(thumb);} +if(this.get(THUMB_IMAGE)){this._initThumbImage();}},_initThumbImage:function(){var thumb=this.get(THUMB),img=this.get(THUMB_IMAGE);if(img){img.replaceClass(C_THUMB,C_THUMB_IMAGE);if(!thumb.contains(img)){thumb.appendChild(img);}}},bindUI:function(){this.publish(THUMB_DRAG,{defaultFn:this._defThumbDragFn});this._bindThumbDD();this.after('valueChange',this._afterValueChange);this.after('thumbImageChange',this._afterThumbImageChange);this.after(DISABLED_CHANGE,this._afterDisabledChange);},_bindThumbDD:function(){var ddConf={node:this.get(THUMB),bubble:false},conConf={constrain2node:this.get(RAIL)};conConf[this._key.ddStick]=true;this._dd=new Y.DD.Drag(ddConf).plug(Y.Plugin.DDConstrained,conConf);this._dd.on('drag:start',Y.bind(this._onDDStartDrag,this));this._dd.on('drag:drag',Y.bind(this._onDDDrag,this));this._dd.on('drag:end',Y.bind(this._onDDEndDrag,this));this._initRailDD();},_initRailDD:function(){this.get(RAIL).on('mousedown',Y.bind(this._handleRailMouseDown,this));},_handleRailMouseDown:function(e){if(this.get('railEnabled')&&!this.get(DISABLED)){var dd=this._dd,xyIndex=this._key.xyIndex,xy;if(dd.get('primaryButtonOnly')&&e.button>1){return false;} +dd._dragThreshMet=true;dd._fixIEMouseDown();e.halt();Y.DD.DDM.activeDrag=dd;xy=dd.get('dragNode').getXY();xy[xyIndex]+=this._thumbOffset;dd._setStartPosition(xy);dd.set('activeHandle',dd.get('dragNode'));dd.start();dd._alignNode([e.pageX,e.pageY]);}},syncUI:function(){this.get(CONTENT_BOX).removeClass(C_IMAGE_ERROR);var img=this.get(THUMB_IMAGE);if(this._isImageLoading(img)){this._scheduleSync();}else{this._ready(img,!this._isImageLoaded(img));}},_scheduleSync:function(){var img,handler;if(!this._stall){this._disabled=this.get(DISABLED);this.set(DISABLED,true);this._stall=this.on(DISABLED_CHANGE,this._stallDisabledChange);img=this.get(THUMB_IMAGE);handler=Y.bind(this._imageLoaded,this,img);img.on('load',handler);img.on('error',handler);}},_stallDisabledChange:function(e){this._disabled=e.newVal;e.preventDefault();},_imageLoaded:function(img,e){var error=(e.type.toLowerCase().indexOf('error')>-1);Y.later(0,this,function(){if(this._stall){this._stall.detach();} +this._stall=false;this._ready(img,error);this.set(DISABLED,this._disabled);});},_ready:function(img,error){var method=error?'addClass':'removeClass';this.get(CONTENT_BOX)[method](C_IMAGE_ERROR);this.fire(SYNC);},_defSyncFn:function(e){this._uiSetThumbSize();this._setThumbOffset();this._uiSetRailSize();this._setRailOffsetXY();this._setDDGutter();this._resetDDCacheRegion();this._setFactor();var val=this.get(VALUE);this.fire(POSITION_THUMB,{value:val,offset:this._convertValueToOffset(val)});this.get('boundingBox').toggleClass('');},_uiSetThumbSize:function(){var thumb=this.get(THUMB),dim=this._key.dim,img=this.get(THUMB_IMAGE),size;size=parseInt(thumb.getComputedStyle(dim),10);if(img&&this._isImageLoaded(img)){size=img.get(dim);} +this._thumbSize=size;},_setThumbOffset:function(){this._thumbOffset=floor(this._thumbSize/2);},_uiSetRailSize:function(){var rail=this.get(RAIL),thumb=this.get(THUMB),img=this.get(THUMB_IMAGE),dim=this._key.dim,size=this.get(RAIL_SIZE),setxy=false;if(parseInt(size,10)){rail.setStyle(dim,size);size=parseInt(rail.getComputedStyle(dim),10);}else{size=this.get(dim);if(parseInt(size,10)){setxy=true;rail.setStyle(dim,size);size=parseInt(rail.getComputedStyle(dim),10);} +size=max(size|0,parseInt(thumb.getComputedStyle(dim),10),parseInt(rail.getComputedStyle(dim),10));if(img&&this._isImageLoaded(img)){size=max(img.get(dim),size);}} +rail.setStyle(dim,size+PX);this._railSize=size;if(setxy){dim=this._key.offAxisDim;size=this.get(dim);if(size){rail.set(dim,size);}}},_setRailOffsetXY:function(){this._offsetXY=this.get(RAIL).getXY()[this._key.xyIndex]+ +this.get(MIN_GUTTER);},_setDDGutter:function(){var gutter=this._key.xyIndex?this.get(MIN_GUTTER)+" 0 "+this.get(MAX_GUTTER):"0 "+this.get(MAX_GUTTER)+" 0 "+this.get(MIN_GUTTER);this._dd.con.set('gutter',gutter);},_resetDDCacheRegion:function(){this._dd.con._cacheRegion();},_setFactor:function(){var range=this._railSize-this._thumbSize- +this.get(MIN_GUTTER)-this.get(MAX_GUTTER);this._factor=this._railSize?(this.get(MAX)-this.get(MIN))/range:1;},getValue:function(){return this.get(VALUE);},setValue:function(val){this.set(VALUE,val);},_validateNewAxis:function(v){return isString(v)&&'xXyY'.indexOf(v.charAt(0))>-1;},_validateNewMin:function(v){return isNumber(v);},_validateNewMax:function(v){return isNumber(v);},_validateNewValue:function(v){var min=this.get(MIN),max=this.get(MAX);return isNumber(v)&&(min=min&&v<=max):(v>=max&&v<=min));},_validateNewRail:function(v){return!this.get(RENDERED)||v;},_validateNewThumb:function(v){return!this.get(RENDERED)||v;},_validateNewThumbImage:function(v){return!this.get(RENDERED)||v;},_validateNewRailSize:function(v){return isString(v)&&(v==='0'||/^\d+(?:p[xtc]|%|e[mx]|in|[mc]m)$/.test(v));},_setAxisFn:function(v){return v.charAt(0).toLowerCase();},_setRailFn:function(v){return Y.get(v)||null;},_setThumbFn:function(v){return Y.get(v)||null;},_setThumbImageFn:function(v){return v?Y.get(v)||Y.Node.create('Slider thumb'):null;},_onDDStartDrag:function(e){this._setRailOffsetXY();this.fire(SLIDE_START,{ddEvent:e});},_onDDDrag:function(e){this.fire(THUMB_DRAG,{ddEvent:e});},_defThumbDragFn:function(e){var before=this.get(VALUE),val=e.ddEvent[this._key.eventPageAxis]-this._offsetXY;val=this._convertOffsetToValue(val);if(before!==val){this.set(VALUE,val,{ddEvent:e.ddEvent});}},_onDDEndDrag:function(e){this.fire(SLIDE_END,{ddEvent:e});},_defPositionThumbFn:function(e){this._uiPositionThumb(e.offset);},_uiPositionThumb:function(xy){var dd=this._dd,thumb=dd.get('dragNode'),hidden=thumb.ancestor(this._isDisplayNone);if(!hidden){dd._setStartPosition(dd.get('dragNode').getXY());dd._alignNode([xy,xy],true);}},_isDisplayNone:function(node){return node.getComputedStyle('display')==='none';},_afterValueChange:function(e){if(!e.ddEvent){var xy=this._convertValueToOffset(e.newVal);this.fire(POSITION_THUMB,{value:e.newVal,offset:xy});}},_convertValueToOffset:function(v){return round((v-this.get(MIN))/this._factor)+this._offsetXY;},_convertOffsetToValue:function(v){return round(this.get(MIN)+(v*this._factor));},_afterThumbChange:function(e){var thumb;if(this.get(RENDERED)){if(e.prevValue){e.prevValue.get('parentNode').removeChild(e.prevValue);} +this._initThumb();thumb=this.get(THUMB);this._dd.set('node',thumb);this._dd.set('dragNode',thumb);this.syncUI();}},_afterThumbImageChange:function(e){if(this.get(RENDERED)){if(e.prevValue){e.prevValue.get('parentNode').removeChild(e.prevValue);} +this._initThumbImage();this.syncUI();}},_afterMinChange:function(e){this._refresh(e);},_afterMaxChange:function(e){this._refresh(e);},_afterRailSizeChange:function(e){this._refresh(e);},_afterDisabledChange:function(e){if(this._dd){this._dd.set('lock',e.newVal);}},_refresh:function(e){if(e.newVal!==e.prevVal&&this.get(RENDERED)){this.syncUI();}},_isImageLoading:function(img){return img&&!img.get(COMPLETE);},_isImageLoaded:function(img){if(img){var w=img.get('naturalWidth');return img.get(COMPLETE)&&(!isNumber(w)?img.get(WIDTH):w);} +return true;}});Y.Slider=Slider;},'3.0.0',{requires:['widget','dd-constrain']}); \ No newline at end of file diff --git a/include/javascript/yui3/build/stylesheet/stylesheet-min.js b/include/javascript/yui3/build/stylesheet/stylesheet-min.js new file mode 100644 index 00000000..ecd45209 --- /dev/null +++ b/include/javascript/yui3/build/stylesheet/stylesheet-min.js @@ -0,0 +1,8 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add("stylesheet",function(B){var J=B.config.doc,C=J.createElement("p"),F=C.style,D=B.Lang.isString,M={},I={},K=("cssFloat"in F)?"cssFloat":"styleFloat",G,A,L,N="opacity",O="float",E="";A=(N in F)?function(P){P.opacity=E;}:function(P){P.filter=E;};F.border="1px solid red";F.border=E;L=F.borderLeft?function(P,R){var Q;if(R!==K&&R.toLowerCase().indexOf(O)!=-1){R=K;}if(D(P[R])){switch(R){case N:case"filter":A(P);break;case"font":P.font=P.fontStyle=P.fontVariant=P.fontWeight=P.fontSize=P.lineHeight=P.fontFamily=E;break;default:for(Q in P){if(Q.indexOf(R)===0){P[Q]=E;}}}}}:function(P,Q){if(Q!==K&&Q.toLowerCase().indexOf(O)!=-1){Q=K;}if(D(P[Q])){if(Q===N){A(P);}else{P[Q]=E;}}};function H(W,R){var Z,U,Y,X={},Q,a,T,V,P,S;if(!(this instanceof H)){return new H(W,R);}if(W){if(B.Node&&W instanceof B.Node){U=B.Node.getDOMNode(W);}else{if(W.nodeName){U=W;}else{if(D(W)){if(W&&I[W]){return I[W];}U=J.getElementById(W.replace(/^#/,E));}}}if(U&&I[B.stamp(U)]){return I[B.stamp(U)];}}if(!U||!/^(?:style|link)$/i.test(U.nodeName)){U=J.createElement("style");U.type="text/css";}if(D(W)){if(W.indexOf("{")!=-1){if(U.styleSheet){U.styleSheet.cssText=W;}else{U.appendChild(J.createTextNode(W));}}else{if(!R){R=W;}}}if(!U.parentNode||U.parentNode.nodeName.toLowerCase()!=="head"){Z=(U.ownerDocument||J).getElementsByTagName("head")[0];Z.appendChild(U);}Y=U.sheet||U.styleSheet;Q=Y&&("cssRules"in Y)?"cssRules":"rules";T=("deleteRule"in Y)?function(b){Y.deleteRule(b);}:function(b){Y.removeRule(b);};a=("insertRule"in Y)?function(d,c,b){Y.insertRule(d+" {"+c+"}",b);}:function(d,c,b){Y.addRule(d,c,b);};for(V=Y[Q].length-1;V>=0;--V){P=Y[Q][V];S=P.selectorText;if(X[S]){X[S].style.cssText+=";"+P.style.cssText;T(V);}else{X[S]=P;}}H.register(B.stamp(U),this);if(R){H.register(R,this);}B.mix(this,{getId:function(){return B.stamp(U);},enable:function(){Y.disabled=false;return this;},disable:function(){Y.disabled=true;return this;},isEnabled:function(){return!Y.disabled;},set:function(e,d){var g=X[e],f=e.split(/\s*,\s*/),c,b;if(f.length>1){for(c=f.length-1;c>=0;--c){this.set(f[c],d);}return this;}if(!H.isValidSelector(e)){return this;}if(g){g.style.cssText=H.toCssText(d,g.style.cssText);}else{b=Y[Q].length;d=H.toCssText(d);if(d){a(e,d,b);X[e]=Y[Q][b];}}return this;},unset:function(e,d){var g=X[e],f=e.split(/\s*,\s*/),b=!d,h,c;if(f.length>1){for(c=f.length-1;c>=0;--c){this.unset(f[c],d);}return this;}if(g){if(!b){d=B.Array(d);F.cssText=g.style.cssText;for(c=d.length-1;c>=0;--c){L(F,d[c]);}if(F.cssText){g.style.cssText=F.cssText;}else{b=true;}}if(b){h=Y[Q];for(c=h.length-1;c>=0;--c){if(h[c]===g){delete X[e];T(c);break;}}}}return this;},getCssText:function(c){var d,b;if(D(c)){d=X[c.split(/\s*,\s*/)[0]];return d?d.style.cssText:null;}else{b=[];for(c in X){if(X.hasOwnProperty(c)){d=X[c];b.push(d.selectorText+" {"+d.style.cssText+"}");}}return b.join("\n");}}});}G=function(Q,S){var R=Q.styleFloat||Q.cssFloat||Q[O],P=B.Lang.trim,U;F.cssText=S||E;if(R&&!Q[K]){Q=B.merge(Q);delete Q.styleFloat;delete Q.cssFloat;delete Q[O];Q[K]=R;}for(U in Q){if(Q.hasOwnProperty(U)){try{F[U]=P(Q[U]);}catch(T){}}}return F.cssText;};B.mix(H,{toCssText:((N in F)?G:function(P,Q){if(N in P){P=B.merge(P,{filter:"alpha(opacity="+(P.opacity*100)+")"});delete P.opacity;}return G(P,Q);}),register:function(P,Q){return!!(P&&Q instanceof H&&!I[P]&&(I[P]=Q));},isValidSelector:function(Q){var P=false;if(Q&&D(Q)){if(!M.hasOwnProperty(Q)){M[Q]=!/\S/.test(Q.replace(/\s+|\s*[+~>]\s*/g," ").replace(/([^ ])\[.*?\]/g,"$1").replace(/([^ ])::?[a-z][a-z\-]+[a-z](?:\(.*?\))?/ig,"$1").replace(/(?:^| )[a-z0-6]+/ig," ").replace(/\\./g,E).replace(/[.#]\w[\w\-]*/g,E));}P=M[Q];}return P;}},true);B.StyleSheet=H;},"3.0.0"); \ No newline at end of file diff --git a/include/javascript/yui3/build/stylesheet/stylesheet.js b/include/javascript/yui3/build/stylesheet/stylesheet.js new file mode 100644 index 00000000..955a7b6e --- /dev/null +++ b/include/javascript/yui3/build/stylesheet/stylesheet.js @@ -0,0 +1,36 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add('stylesheet',function(Y){var d=Y.config.doc,p=d.createElement('p'),workerStyle=p.style,isString=Y.Lang.isString,selectors={},sheets={},floatAttr=('cssFloat'in workerStyle)?'cssFloat':'styleFloat',_toCssText,_unsetOpacity,_unsetProperty,OPACITY='opacity',FLOAT='float',EMPTY='';_unsetOpacity=(OPACITY in workerStyle)?function(style){style.opacity=EMPTY;}:function(style){style.filter=EMPTY;};workerStyle.border="1px solid red";workerStyle.border=EMPTY;_unsetProperty=workerStyle.borderLeft?function(style,prop){var p;if(prop!==floatAttr&&prop.toLowerCase().indexOf(FLOAT)!=-1){prop=floatAttr;} +if(isString(style[prop])){switch(prop){case OPACITY:case'filter':_unsetOpacity(style);break;case'font':style.font=style.fontStyle=style.fontVariant=style.fontWeight=style.fontSize=style.lineHeight=style.fontFamily=EMPTY;break;default:for(p in style){if(p.indexOf(prop)===0){style[p]=EMPTY;}}}}}:function(style,prop){if(prop!==floatAttr&&prop.toLowerCase().indexOf(FLOAT)!=-1){prop=floatAttr;} +if(isString(style[prop])){if(prop===OPACITY){_unsetOpacity(style);}else{style[prop]=EMPTY;}}};function StyleSheet(seed,name){var head,node,sheet,cssRules={},_rules,_insertRule,_deleteRule,i,r,sel;if(!(this instanceof StyleSheet)){return new StyleSheet(seed,name);} +if(seed){if(Y.Node&&seed instanceof Y.Node){node=Y.Node.getDOMNode(seed);}else if(seed.nodeName){node=seed;}else if(isString(seed)){if(seed&&sheets[seed]){return sheets[seed];} +node=d.getElementById(seed.replace(/^#/,EMPTY));} +if(node&&sheets[Y.stamp(node)]){return sheets[Y.stamp(node)];}} +if(!node||!/^(?:style|link)$/i.test(node.nodeName)){node=d.createElement('style');node.type='text/css';} +if(isString(seed)){if(seed.indexOf('{')!=-1){if(node.styleSheet){node.styleSheet.cssText=seed;}else{node.appendChild(d.createTextNode(seed));}}else if(!name){name=seed;}} +if(!node.parentNode||node.parentNode.nodeName.toLowerCase()!=='head'){head=(node.ownerDocument||d).getElementsByTagName('head')[0];head.appendChild(node);} +sheet=node.sheet||node.styleSheet;_rules=sheet&&('cssRules'in sheet)?'cssRules':'rules';_deleteRule=('deleteRule'in sheet)?function(i){sheet.deleteRule(i);}:function(i){sheet.removeRule(i);};_insertRule=('insertRule'in sheet)?function(sel,css,i){sheet.insertRule(sel+' {'+css+'}',i);}:function(sel,css,i){sheet.addRule(sel,css,i);};for(i=sheet[_rules].length-1;i>=0;--i){r=sheet[_rules][i];sel=r.selectorText;if(cssRules[sel]){cssRules[sel].style.cssText+=';'+r.style.cssText;_deleteRule(i);}else{cssRules[sel]=r;}} +StyleSheet.register(Y.stamp(node),this);if(name){StyleSheet.register(name,this);} +Y.mix(this,{getId:function(){return Y.stamp(node);},enable:function(){sheet.disabled=false;return this;},disable:function(){sheet.disabled=true;return this;},isEnabled:function(){return!sheet.disabled;},set:function(sel,css){var rule=cssRules[sel],multi=sel.split(/\s*,\s*/),i,idx;if(multi.length>1){for(i=multi.length-1;i>=0;--i){this.set(multi[i],css);} +return this;} +if(!StyleSheet.isValidSelector(sel)){return this;} +if(rule){rule.style.cssText=StyleSheet.toCssText(css,rule.style.cssText);}else{idx=sheet[_rules].length;css=StyleSheet.toCssText(css);if(css){_insertRule(sel,css,idx);cssRules[sel]=sheet[_rules][idx];}} +return this;},unset:function(sel,css){var rule=cssRules[sel],multi=sel.split(/\s*,\s*/),remove=!css,rules,i;if(multi.length>1){for(i=multi.length-1;i>=0;--i){this.unset(multi[i],css);} +return this;} +if(rule){if(!remove){css=Y.Array(css);workerStyle.cssText=rule.style.cssText;for(i=css.length-1;i>=0;--i){_unsetProperty(workerStyle,css[i]);} +if(workerStyle.cssText){rule.style.cssText=workerStyle.cssText;}else{remove=true;}} +if(remove){rules=sheet[_rules];for(i=rules.length-1;i>=0;--i){if(rules[i]===rule){delete cssRules[sel];_deleteRule(i);break;}}}} +return this;},getCssText:function(sel){var rule,css;if(isString(sel)){rule=cssRules[sel.split(/\s*,\s*/)[0]];return rule?rule.style.cssText:null;}else{css=[];for(sel in cssRules){if(cssRules.hasOwnProperty(sel)){rule=cssRules[sel];css.push(rule.selectorText+" {"+rule.style.cssText+"}");}} +return css.join("\n");}}});} +_toCssText=function(css,base){var f=css.styleFloat||css.cssFloat||css[FLOAT],trim=Y.Lang.trim,prop;workerStyle.cssText=base||EMPTY;if(f&&!css[floatAttr]){css=Y.merge(css);delete css.styleFloat;delete css.cssFloat;delete css[FLOAT];css[floatAttr]=f;} +for(prop in css){if(css.hasOwnProperty(prop)){try{workerStyle[prop]=trim(css[prop]);} +catch(e){}}} +return workerStyle.cssText;};Y.mix(StyleSheet,{toCssText:((OPACITY in workerStyle)?_toCssText:function(css,cssText){if(OPACITY in css){css=Y.merge(css,{filter:'alpha(opacity='+(css.opacity*100)+')'});delete css.opacity;} +return _toCssText(css,cssText);}),register:function(name,sheet){return!!(name&&sheet instanceof StyleSheet&&!sheets[name]&&(sheets[name]=sheet));},isValidSelector:function(sel){var valid=false;if(sel&&isString(sel)){if(!selectors.hasOwnProperty(sel)){selectors[sel]=!/\S/.test(sel.replace(/\s+|\s*[+~>]\s*/g,' ').replace(/([^ ])\[.*?\]/g,'$1').replace(/([^ ])::?[a-z][a-z\-]+[a-z](?:\(.*?\))?/ig,'$1').replace(/(?:^| )[a-z0-6]+/ig,' ').replace(/\\./g,EMPTY).replace(/[.#]\w[\w\-]*/g,EMPTY));} +valid=selectors[sel];} +return valid;}},true);Y.StyleSheet=StyleSheet;},'3.0.0'); \ No newline at end of file diff --git a/include/javascript/yui3/build/substitute/substitute-min.js b/include/javascript/yui3/build/substitute/substitute-min.js new file mode 100644 index 00000000..43cd0b46 --- /dev/null +++ b/include/javascript/yui3/build/substitute/substitute-min.js @@ -0,0 +1,8 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add("substitute",function(G){var B=G.Lang,D="dump",F=" ",C="{",E="}",A=function(U,I,P,K,H){var N,M,L,S,R,T,Q=[],J,O;K=K||C;H=H||E;for(;;){N=U.lastIndexOf(K);if(N<0){break;}M=U.indexOf(H,N);if(N+1>=M){break;}J=U.substring(N+1,M);S=J;T=null;L=S.indexOf(F);if(L>-1){T=S.substring(L+1);S=S.substring(0,L);}R=I[S];if(P){R=P(S,R,T);}if(B.isObject(R)){if(!G.dump){R=R.toString();}else{if(B.isArray(R)){R=G.dump(R,parseInt(T,10));}else{T=T||"";O=T.indexOf(D);if(O>-1){T=T.substring(4);}if(R.toString===Object.prototype.toString||O>-1){R=G.dump(R,parseInt(T,10));}else{R=R.toString();}}}}else{if(!B.isString(R)&&!B.isNumber(R)){R="~-"+Q.length+"-~";Q[Q.length]=J;}}U=U.substring(0,N)+R+U.substring(M+1);}for(N=Q.length-1;N>=0;N=N-1){U=U.replace(new RegExp("~-"+N+"-~"),K+Q[N]+H,"g");}return U;};G.substitute=A;B.substitute=A;},"3.0.0",{optional:["dump"]}); \ No newline at end of file diff --git a/include/javascript/yui3/build/substitute/substitute.js b/include/javascript/yui3/build/substitute/substitute.js new file mode 100644 index 00000000..aeb1917b --- /dev/null +++ b/include/javascript/yui3/build/substitute/substitute.js @@ -0,0 +1,16 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add('substitute',function(Y){var L=Y.Lang,DUMP='dump',SPACE=' ',LBRACE='{',RBRACE='}',substitute=function(s,o,f,ldelim,rdelim){var i,j,k,key,v,meta,saved=[],token,dump;ldelim=ldelim||LBRACE;rdelim=rdelim||RBRACE;for(;;){i=s.lastIndexOf(ldelim);if(i<0){break;} +j=s.indexOf(rdelim,i);if(i+1>=j){break;} +token=s.substring(i+1,j);key=token;meta=null;k=key.indexOf(SPACE);if(k>-1){meta=key.substring(k+1);key=key.substring(0,k);} +v=o[key];if(f){v=f(key,v,meta);} +if(L.isObject(v)){if(!Y.dump){v=v.toString();}else{if(L.isArray(v)){v=Y.dump(v,parseInt(meta,10));}else{meta=meta||"";dump=meta.indexOf(DUMP);if(dump>-1){meta=meta.substring(4);} +if(v.toString===Object.prototype.toString||dump>-1){v=Y.dump(v,parseInt(meta,10));}else{v=v.toString();}}}}else if(!L.isString(v)&&!L.isNumber(v)){v="~-"+saved.length+"-~";saved[saved.length]=token;} +s=s.substring(0,i)+v+s.substring(j+1);} +for(i=saved.length-1;i>=0;i=i-1){s=s.replace(new RegExp("~-"+i+"-~"),ldelim+saved[i]+rdelim,"g");} +return s;};Y.substitute=substitute;L.substitute=substitute;},'3.0.0',{optional:['dump']}); \ No newline at end of file diff --git a/include/javascript/yui3/build/test/assets/test-console.css b/include/javascript/yui3/build/test/assets/test-console.css new file mode 100644 index 00000000..e343e7b7 --- /dev/null +++ b/include/javascript/yui3/build/test/assets/test-console.css @@ -0,0 +1,34 @@ +/* +Copyright (c) 2009, Yahoo! Inc. All rights reserved. +Code licensed under the BSD License: +http://developer.yahoo.net/yui/license.txt +version: 3.0.0 +build: 1549 +*/ +.yui-log {padding-top:3em;} +/* +.yui-log-container {position:relative;width:60em} +.yui-log .yui-log-bd {height:auto; overflow:visible;} +*/ +.yui-log-container {width:40em} +.yui-log .yui-log-bd {height:60em} +.yui-log .yui-log-btns {display:none;} +.yui-log .yui-log-ft .yui-log-sourcefilters {visibility:hidden;} +.yui-log .yui-log-hd {display:none;} +.yui-log .yui-log-ft {position:absolute;top:0em;} + +.pass { + background-color: green; + font-weight: bold; + color: white; +} +.fail { + background-color: red; + font-weight: bold; + color: white; +} +.ignore { + background-color: #666; + font-weight: bold; + color: white; +} diff --git a/include/javascript/yui3/build/test/test-min.js b/include/javascript/yui3/build/test/test-min.js new file mode 100644 index 00000000..58878a1e --- /dev/null +++ b/include/javascript/yui3/build/test/test-min.js @@ -0,0 +1,8 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add("test",function(B){B.namespace("Test");B.Test.Case=function(C){this._should={};for(var D in C){this[D]=C[D];}if(!B.Lang.isString(this.name)){this.name="testCase"+B.guid();}};B.Test.Case.prototype={resume:function(C){B.Test.Runner.resume(C);},wait:function(E,D){var C=arguments;if(B.Lang.isFunction(C[0])){throw new B.Test.Wait(C[0],C[1]);}else{throw new B.Test.Wait(function(){B.Assert.fail("Timeout: wait() called but resume() never called.");},(B.Lang.isNumber(C[0])?C[0]:10000));}},setUp:function(){},tearDown:function(){}};B.Test.Wait=function(D,C){this.segment=(B.Lang.isFunction(D)?D:null);this.delay=(B.Lang.isNumber(C)?C:0);};B.namespace("Test");B.Test.Suite=function(C){this.name="";this.items=[];if(B.Lang.isString(C)){this.name=C;}else{if(B.Lang.isObject(C)){B.mix(this,C,true);}}if(this.name===""){this.name="testSuite"+B.guid();}};B.Test.Suite.prototype={add:function(C){if(C instanceof B.Test.Suite||C instanceof B.Test.Case){this.items.push(C);}return this;},setUp:function(){},tearDown:function(){}};B.Test.Runner=(function(){function D(E){this.testObject=E;this.firstChild=null;this.lastChild=null;this.parent=null;this.next=null;this.results={passed:0,failed:0,total:0,ignored:0};if(E instanceof B.Test.Suite){this.results.type="testsuite";this.results.name=E.name;}else{if(E instanceof B.Test.Case){this.results.type="testcase";this.results.name=E.name;}}}D.prototype={appendChild:function(E){var F=new D(E);if(this.firstChild===null){this.firstChild=this.lastChild=F;}else{this.lastChild.next=F;this.lastChild=F;}F.parent=this;return F;}};function C(){C.superclass.constructor.apply(this,arguments);this.masterSuite=new B.Test.Suite("YUI Test Results");this._cur=null;this._root=null;this._log=true;this._waiting=false;var F=[this.TEST_CASE_BEGIN_EVENT,this.TEST_CASE_COMPLETE_EVENT,this.TEST_SUITE_BEGIN_EVENT,this.TEST_SUITE_COMPLETE_EVENT,this.TEST_PASS_EVENT,this.TEST_FAIL_EVENT,this.TEST_IGNORE_EVENT,this.COMPLETE_EVENT,this.BEGIN_EVENT];for(var E=0;E-1&&I.indexOf(" ")>-1))&&B.Lang.isFunction(G[I])){H.appendChild(I);}}},_addTestSuiteToTestTree:function(E,H){var G=E.appendChild(H);for(var F=0;F0){return B.Lang.substitute(D,{message:C});}else{return C;}},_getCount:function(){return this._asserts;},_increment:function(){this._asserts++;},_reset:function(){this._asserts=0;},fail:function(C){throw new B.Assert.Error(B.Assert._formatMessage(C,"Test force-failed."));},areEqual:function(D,E,C){B.Assert._increment();if(D!=E){throw new B.Assert.ComparisonFailure(B.Assert._formatMessage(C,"Values should be equal."),D,E);}},areNotEqual:function(C,E,D){B.Assert._increment();if(C==E){throw new B.Assert.UnexpectedValue(B.Assert._formatMessage(D,"Values should not be equal."),C);}},areNotSame:function(C,E,D){B.Assert._increment();if(C===E){throw new B.Assert.UnexpectedValue(B.Assert._formatMessage(D,"Values should not be the same."),C);}},areSame:function(D,E,C){B.Assert._increment();if(D!==E){throw new B.Assert.ComparisonFailure(B.Assert._formatMessage(C,"Values should be the same."),D,E);}},isFalse:function(D,C){B.Assert._increment();if(false!==D){throw new B.Assert.ComparisonFailure(B.Assert._formatMessage(C,"Value should be false."),false,D);}},isTrue:function(D,C){B.Assert._increment();if(true!==D){throw new B.Assert.ComparisonFailure(B.Assert._formatMessage(C,"Value should be true."),true,D);}},isNaN:function(D,C){B.Assert._increment();if(!isNaN(D)){throw new B.Assert.ComparisonFailure(B.Assert._formatMessage(C,"Value should be NaN."),NaN,D);}},isNotNaN:function(D,C){B.Assert._increment();if(isNaN(D)){throw new B.Assert.UnexpectedValue(B.Assert._formatMessage(C,"Values should not be NaN."),NaN);}},isNotNull:function(D,C){B.Assert._increment();if(B.Lang.isNull(D)){throw new B.Assert.UnexpectedValue(B.Assert._formatMessage(C,"Values should not be null."),null);}},isNotUndefined:function(D,C){B.Assert._increment();if(B.Lang.isUndefined(D)){throw new B.Assert.UnexpectedValue(B.Assert._formatMessage(C,"Value should not be undefined."),undefined);}},isNull:function(D,C){B.Assert._increment();if(!B.Lang.isNull(D)){throw new B.Assert.ComparisonFailure(B.Assert._formatMessage(C,"Value should be null."),null,D);}},isUndefined:function(D,C){B.Assert._increment();if(!B.Lang.isUndefined(D)){throw new B.Assert.ComparisonFailure(B.Assert._formatMessage(C,"Value should be undefined."),undefined,D);}},isArray:function(D,C){B.Assert._increment();if(!B.Lang.isArray(D)){throw new B.Assert.UnexpectedValue(B.Assert._formatMessage(C,"Value should be an array."),D);}},isBoolean:function(D,C){B.Assert._increment();if(!B.Lang.isBoolean(D)){throw new B.Assert.UnexpectedValue(B.Assert._formatMessage(C,"Value should be a Boolean."),D);}},isFunction:function(D,C){B.Assert._increment();if(!B.Lang.isFunction(D)){throw new B.Assert.UnexpectedValue(B.Assert._formatMessage(C,"Value should be a function."),D);}},isInstanceOf:function(D,E,C){B.Assert._increment();if(!(E instanceof D)){throw new B.Assert.ComparisonFailure(B.Assert._formatMessage(C,"Value isn't an instance of expected type."),D,E);}},isNumber:function(D,C){B.Assert._increment();if(!B.Lang.isNumber(D)){throw new B.Assert.UnexpectedValue(B.Assert._formatMessage(C,"Value should be a number."),D);}},isObject:function(D,C){B.Assert._increment();if(!B.Lang.isObject(D)){throw new B.Assert.UnexpectedValue(B.Assert._formatMessage(C,"Value should be an object."),D);}},isString:function(D,C){B.Assert._increment();if(!B.Lang.isString(D)){throw new B.Assert.UnexpectedValue(B.Assert._formatMessage(C,"Value should be a string."),D);}},isTypeOf:function(C,E,D){B.Assert._increment();if(typeof E!=C){throw new B.Assert.ComparisonFailure(B.Assert._formatMessage(D,"Value should be of type "+C+"."),expected,typeof E);}}};B.assert=function(D,C){B.Assert._increment();if(!D){throw new B.Assert.Error(B.Assert._formatMessage(C,"Assertion failed."));}};B.fail=B.Assert.fail;B.Assert.Error=function(C){arguments.callee.superclass.constructor.call(this,C);this.message=C;this.name="Assert Error";};B.extend(B.Assert.Error,Error,{getMessage:function(){return this.message;},toString:function(){return this.name+": "+this.getMessage();},valueOf:function(){return this.toString();}});B.Assert.ComparisonFailure=function(D,C,E){arguments.callee.superclass.constructor.call(this,D);this.expected=C;this.actual=E;this.name="ComparisonFailure";};B.extend(B.Assert.ComparisonFailure,B.Assert.Error,{getMessage:function(){return this.message+"\nExpected: "+this.expected+" ("+(typeof this.expected)+")"+"\nActual: "+this.actual+" ("+(typeof this.actual)+")";}});B.Assert.UnexpectedValue=function(D,C){arguments.callee.superclass.constructor.call(this,D);this.unexpected=C;this.name="UnexpectedValue";};B.extend(B.Assert.UnexpectedValue,B.Assert.Error,{getMessage:function(){return this.message+"\nUnexpected: "+this.unexpected+" ("+(typeof this.unexpected)+") ";}});B.Assert.ShouldFail=function(C){arguments.callee.superclass.constructor.call(this,C||"This test should fail but didn't.");this.name="ShouldFail";};B.extend(B.Assert.ShouldFail,B.Assert.Error);B.Assert.ShouldError=function(C){arguments.callee.superclass.constructor.call(this,C||"This test should have thrown an error but didn't.");this.name="ShouldError";};B.extend(B.Assert.ShouldError,B.Assert.Error);B.Assert.UnexpectedError=function(C){arguments.callee.superclass.constructor.call(this,"Unexpected error: "+C.message);this.cause=C;this.name="UnexpectedError";this.stack=C.stack;};B.extend(B.Assert.UnexpectedError,B.Assert.Error);B.ArrayAssert={contains:function(E,D,C){B.Assert._increment();if(B.Array.indexOf(D,E)==-1){B.Assert.fail(B.Assert._formatMessage(C,"Value "+E+" ("+(typeof E)+") not found in array ["+D+"]."));}},containsItems:function(E,F,D){B.Assert._increment();for(var C=0;C-1){B.Assert.fail(B.Assert._formatMessage(C,"Value found in array ["+D+"]."));}},doesNotContainItems:function(E,F,D){B.Assert._increment();for(var C=0;C-1){B.Assert.fail(B.Assert._formatMessage(D,"Value found in array ["+F+"]."));}}},doesNotContainMatch:function(E,D,C){B.Assert._increment();if(typeof E!="function"){throw new TypeError("ArrayAssert.doesNotContainMatch(): First argument must be a function.");}if(B.Array.some(D,E)){B.Assert.fail(B.Assert._formatMessage(C,"Value found in array ["+D+"]."));}},indexOf:function(G,F,C,E){B.Assert._increment();for(var D=0;D0){B.Assert.fail(B.Assert._formatMessage(C,"Array should be empty."));}},isNotEmpty:function(D,C){B.Assert._increment();if(D.length===0){B.Assert.fail(B.Assert._formatMessage(C,"Array should not be empty."));}},itemsAreSame:function(E,F,D){B.Assert._increment();if(E.length!=F.length){B.Assert.fail(B.Assert._formatMessage(D,"Array should have a length of "+E.length+" but has a length of "+F.length));}for(var C=0;C=0;D--){if(F[D]===G){if(C!=D){B.Assert.fail(B.Assert._formatMessage(E,"Value exists at index "+D+" but should be at index "+C+"."));}return;}}B.Assert.fail(B.Assert._formatMessage(E,"Value doesn't exist in array."));}};B.ObjectAssert={areEqual:function(D,E,C){B.Assert._increment();B.Object.each(D,function(G,F){if(D[F]!=E[F]){throw new B.Assert.ComparisonFailure(B.Assert._formatMessage(C,"Values should be equal for property "+F),D[F],E[F]);}});},hasKey:function(C,D,E){B.Assert._increment();if(!B.Object.hasKey(D,C)){B.fail(B.Assert._formatMessage(E,"Property '"+C+"' not found on object."));}},hasKeys:function(E,C,F){B.Assert._increment();for(var D=0;D0){B.fail(B.Assert._formatMessage(E,"Object owns "+D.length+" properties but should own none."));}}};B.DateAssert={datesAreEqual:function(D,F,C){B.Assert._increment();if(D instanceof Date&&F instanceof Date){var E="";if(D.getFullYear()!=F.getFullYear()){E="Years should be equal.";}if(D.getMonth()!=F.getMonth()){E="Months should be equal.";}if(D.getDate()!=F.getDate()){E="Days of month should be equal.";}if(E.length){throw new B.Assert.ComparisonFailure(B.Assert._formatMessage(C,E),D,F);}}else{throw new TypeError("Y.Assert.datesAreEqual(): Expected and actual values must be Date objects.");}},timesAreEqual:function(D,F,C){B.Assert._increment();if(D instanceof Date&&F instanceof Date){var E="";if(D.getHours()!=F.getHours()){E="Hours should be equal.";}if(D.getMinutes()!=F.getMinutes()){E="Minutes should be equal.";}if(D.getSeconds()!=F.getSeconds()){E="Seconds should be equal.";}if(E.length){throw new B.Assert.ComparisonFailure(B.Assert._formatMessage(C,E),D,F);}}else{throw new TypeError("DateY.AsserttimesAreEqual(): Expected and actual values must be Date objects.");}}};B.namespace("Test.Format");function A(C){return C.replace(/[<>"'&]/g,function(D){switch(D){case"<":return"<";case">":return">";case'"':return""";case"'":return"'";case"&":return"&";}});}B.Test.Format.JSON=function(C){return B.JSON.stringify(C);};B.Test.Format.XML=function(E){var C=B.Lang;var D="<"+E.type+' name="'+A(E.name)+'"';if(E.type=="test"){D+=' result="'+A(E.result)+'" message="'+A(E.message)+'">';}else{D+=' passed="'+E.passed+'" failed="'+E.failed+'" ignored="'+E.ignored+'" total="'+E.total+'">';B.Object.each(E,function(F,G){if(C.isObject(F)&&!C.isArray(F)){D+=arguments.callee(F);}});}D+="";return D;};B.Test.Format.XML=function(D){function C(G){var E=B.Lang,F="<"+G.type+' name="'+A(G.name)+'"';if(E.isNumber(G.duration)){F+=' duration="'+G.duration+'"';}if(G.type=="test"){F+=' result="'+G.result+'" message="'+A(G.message)+'">';}else{F+=' passed="'+G.passed+'" failed="'+G.failed+'" ignored="'+G.ignored+'" total="'+G.total+'">';B.Object.each(G,function(H,I){if(E.isObject(H)&&!E.isArray(H)){F+=C(H);}});}F+="";return F;}return''+C(D);};B.Test.Format.JUnitXML=function(C){function D(G){var E=B.Lang,F="",H;switch(G.type){case"test":if(G.result!="ignore"){F='';if(G.result=="fail"){F+='";}F+="";}break;case"testcase":F='';B.Object.each(G,function(I,J){if(E.isObject(I)&&!E.isArray(I)){F+=D(I);}});F+="";break;case"testsuite":B.Object.each(G,function(I,J){if(E.isObject(I)&&!E.isArray(I)){F+=D(I);}});break;case"report":F="";B.Object.each(G,function(I,J){if(E.isObject(I)&&!E.isArray(I)){F+=D(I);}});F+="";}return F;}return''+D(C);};B.namespace("Test");B.Test.Reporter=function(C,D){this.url=C;this.format=D||B.Test.Format.XML;this._fields=new Object();this._form=null;this._iframe=null;};B.Test.Reporter.prototype={constructor:B.Test.Reporter,addField:function(C,D){this._fields[C]=D;},clearFields:function(){this._fields=new Object();},destroy:function(){if(this._form){this._form.parentNode.removeChild(this._form);this._form=null;}if(this._iframe){this._iframe.parentNode.removeChild(this._iframe);this._iframe=null;}this._fields=null;},report:function(C){if(!this._form){this._form=document.createElement("form");this._form.method="post";this._form.style.visibility="hidden";this._form.style.position="absolute";this._form.style.top=0;document.body.appendChild(this._form);if(B.UA.ie){this._iframe=document.createElement('';U.prototype={_syncUIStack:function(){this._uiSetShim(this.get(P));this._uiSetZIndex(this.get(c));},_bindUIStack:function(){this.after(b,this._afterShimChange);this.after(B,this._afterZIndexChange);},_renderUIStack:function(){this._stackNode.addClass(U.STACKED_CLASS_NAME);},_setZIndex:function(L){if(N.isString(L)){L=parseInt(L,10);}if(!N.isNumber(L)){L=0;}return L;},_afterShimChange:function(L){this._uiSetShim(L.newVal);},_afterZIndexChange:function(L){this._uiSetZIndex(L.newVal);},_uiSetZIndex:function(L){this._stackNode.setStyle(c,L);},_uiSetShim:function(L){if(L){if(this.get(a)){this._renderShim();}else{this._renderShimDeferred();}}else{this._destroyShim();}},_renderShimDeferred:function(){this._stackHandles[O]=this._stackHandles[O]||[];var Y=this._stackHandles[O],L=function(g){if(g.newVal){this._renderShim();}};Y.push(this.on(Z,L));},_addShimResizeHandlers:function(){this._stackHandles[f]=this._stackHandles[f]||[];var Y=this.sizeShim,L=this._stackHandles[f];this.sizeShim();L.push(this.after(Z,Y));L.push(this.after(C,Y));L.push(this.after(J,Y));L.push(this.after(I,Y));},_detachStackHandles:function(L){var Y=this._stackHandles[L],g;if(Y&&Y.length>0){while((g=Y.pop())){g.detach();}}},_renderShim:function(){var L=this._shimNode,Y=this._stackNode;if(!L){L=this._shimNode=this._getShimTemplate();Y.insertBefore(L,Y.get(A));if(T.ie==6){this._addShimResizeHandlers();}this._detachStackHandles(O);}},_destroyShim:function(){if(this._shimNode){this._shimNode.get(M).removeChild(this._shimNode);this._shimNode=null;this._detachStackHandles(O);this._detachStackHandles(f);}},sizeShim:function(){var Y=this._shimNode,L=this._stackNode;if(Y&&T.ie===6&&this.get(a)){Y.setStyle(H,L.get(Q)+K);Y.setStyle(V,L.get(D)+K);}},_getShimTemplate:function(){return d.create(U.SHIM_TEMPLATE,this._stackNode.get(X));}};E.WidgetStack=U;},"3.0.0",{requires:["widget"]}); \ No newline at end of file diff --git a/include/javascript/yui3/build/widget/widget-stack.js b/include/javascript/yui3/build/widget/widget-stack.js new file mode 100644 index 00000000..ee2aa19e --- /dev/null +++ b/include/javascript/yui3/build/widget/widget-stack.js @@ -0,0 +1,12 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add('widget-stack',function(Y){var L=Y.Lang,UA=Y.UA,Node=Y.Node,Widget=Y.Widget,ZINDEX="zIndex",SHIM="shim",VISIBLE="visible",BOUNDING_BOX="boundingBox",RENDER_UI="renderUI",BIND_UI="bindUI",SYNC_UI="syncUI",OFFSET_WIDTH="offsetWidth",OFFSET_HEIGHT="offsetHeight",PARENT_NODE="parentNode",FIRST_CHILD="firstChild",OWNER_DOCUMENT="ownerDocument",WIDTH="width",HEIGHT="height",PX="px",SHIM_DEFERRED="shimdeferred",SHIM_RESIZE="shimresize",VisibleChange="visibleChange",WidthChange="widthChange",HeightChange="heightChange",ShimChange="shimChange",ZIndexChange="zIndexChange",ContentUpdate="contentUpdate",STACKED="stacked";function Stack(config){this._stackNode=this.get(BOUNDING_BOX);this._stackHandles={};Y.after(this._renderUIStack,this,RENDER_UI);Y.after(this._syncUIStack,this,SYNC_UI);Y.after(this._bindUIStack,this,BIND_UI);} +Stack.ATTRS={shim:{value:(UA.ie==6)},zIndex:{value:0,setter:function(val){return this._setZIndex(val);}}};Stack.HTML_PARSER={zIndex:function(contentBox){return contentBox.getStyle(ZINDEX);}};Stack.SHIM_CLASS_NAME=Widget.getClassName(SHIM);Stack.STACKED_CLASS_NAME=Widget.getClassName(STACKED);Stack.SHIM_TEMPLATE='';Stack.prototype={_syncUIStack:function(){this._uiSetShim(this.get(SHIM));this._uiSetZIndex(this.get(ZINDEX));},_bindUIStack:function(){this.after(ShimChange,this._afterShimChange);this.after(ZIndexChange,this._afterZIndexChange);},_renderUIStack:function(){this._stackNode.addClass(Stack.STACKED_CLASS_NAME);},_setZIndex:function(zIndex){if(L.isString(zIndex)){zIndex=parseInt(zIndex,10);} +if(!L.isNumber(zIndex)){zIndex=0;} +return zIndex;},_afterShimChange:function(e){this._uiSetShim(e.newVal);},_afterZIndexChange:function(e){this._uiSetZIndex(e.newVal);},_uiSetZIndex:function(zIndex){this._stackNode.setStyle(ZINDEX,zIndex);},_uiSetShim:function(enable){if(enable){if(this.get(VISIBLE)){this._renderShim();}else{this._renderShimDeferred();}}else{this._destroyShim();}},_renderShimDeferred:function(){this._stackHandles[SHIM_DEFERRED]=this._stackHandles[SHIM_DEFERRED]||[];var handles=this._stackHandles[SHIM_DEFERRED],createBeforeVisible=function(e){if(e.newVal){this._renderShim();}};handles.push(this.on(VisibleChange,createBeforeVisible));},_addShimResizeHandlers:function(){this._stackHandles[SHIM_RESIZE]=this._stackHandles[SHIM_RESIZE]||[];var sizeShim=this.sizeShim,handles=this._stackHandles[SHIM_RESIZE];this.sizeShim();handles.push(this.after(VisibleChange,sizeShim));handles.push(this.after(WidthChange,sizeShim));handles.push(this.after(HeightChange,sizeShim));handles.push(this.after(ContentUpdate,sizeShim));},_detachStackHandles:function(handleKey){var handles=this._stackHandles[handleKey],handle;if(handles&&handles.length>0){while((handle=handles.pop())){handle.detach();}}},_renderShim:function(){var shimEl=this._shimNode,stackEl=this._stackNode;if(!shimEl){shimEl=this._shimNode=this._getShimTemplate();stackEl.insertBefore(shimEl,stackEl.get(FIRST_CHILD));if(UA.ie==6){this._addShimResizeHandlers();} +this._detachStackHandles(SHIM_DEFERRED);}},_destroyShim:function(){if(this._shimNode){this._shimNode.get(PARENT_NODE).removeChild(this._shimNode);this._shimNode=null;this._detachStackHandles(SHIM_DEFERRED);this._detachStackHandles(SHIM_RESIZE);}},sizeShim:function(){var shim=this._shimNode,node=this._stackNode;if(shim&&UA.ie===6&&this.get(VISIBLE)){shim.setStyle(WIDTH,node.get(OFFSET_WIDTH)+PX);shim.setStyle(HEIGHT,node.get(OFFSET_HEIGHT)+PX);}},_getShimTemplate:function(){return Node.create(Stack.SHIM_TEMPLATE,this._stackNode.get(OWNER_DOCUMENT));}};Y.WidgetStack=Stack;},'3.0.0',{requires:['widget']}); \ No newline at end of file diff --git a/include/javascript/yui3/build/widget/widget-stdmod-min.js b/include/javascript/yui3/build/widget/widget-stdmod-min.js new file mode 100644 index 00000000..2f317533 --- /dev/null +++ b/include/javascript/yui3/build/widget/widget-stdmod-min.js @@ -0,0 +1,8 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add("widget-stdmod",function(A){var D=A.Lang,P=A.Node,c=A.NodeList,W=A.UA,C=A.Widget,B="",j="hd",h="bd",H="ft",e="header",m="body",k="footer",q="fillHeight",K="stdmod",t="px",T="Node",i="Content",o="innerHTML",d="firstChild",G="childNodes",l="createDocumentFragment",M="ownerDocument",U="contentBox",p="boundingBox",Z="height",g="offsetHeight",X="auto",J="headerContentChange",b="bodyContentChange",N="footerContentChange",R="fillHeightChange",S="HeightChange",r="contentUpdate",V="renderUI",f="bindUI",E="syncUI",Q=A.Widget.UI_SRC;function s(L){this._stdModNode=this.get(U);A.after(this._renderUIStdMod,this,V);A.after(this._bindUIStdMod,this,f);A.after(this._syncUIStdMod,this,E);}s.HEADER=e;s.BODY=m;s.FOOTER=k;s.AFTER="after";s.BEFORE="before";s.REPLACE="replace";var I=s.HEADER,a=s.BODY,O=s.FOOTER,n=s.AFTER,F=s.BEFORE;s.ATTRS={headerContent:{value:null},footerContent:{value:null},bodyContent:{value:null},fillHeight:{value:s.BODY,validator:function(L){return this._validateFillHeight(L);}}};s.HTML_PARSER={headerContent:function(L){return this._parseStdModHTML(I);},bodyContent:function(L){return this._parseStdModHTML(a);},footerContent:function(L){return this._parseStdModHTML(O);}};s.SECTION_CLASS_NAMES={header:C.getClassName(j),body:C.getClassName(h),footer:C.getClassName(H)};s.TEMPLATES={header:'
    ',body:'
    ',footer:'
    '};s.prototype={_syncUIStdMod:function(){this._uiSetStdMod(I,this.get(I+i));this._uiSetStdMod(a,this.get(a+i));this._uiSetStdMod(O,this.get(O+i));this._uiSetFillHeight(this.get(q));},_renderUIStdMod:function(){this._stdModNode.addClass(C.getClassName(K));},_bindUIStdMod:function(){this.after(J,this._afterHeaderChange);this.after(b,this._afterBodyChange);this.after(N,this._afterFooterChange);this.after(R,this._afterFillHeightChange);this.after(S,this._fillHeight);this.after(r,this._fillHeight);},_afterHeaderChange:function(L){if(L.src!==Q){this._uiSetStdMod(I,L.newVal,L.stdModPosition);}},_afterBodyChange:function(L){if(L.src!==Q){this._uiSetStdMod(a,L.newVal,L.stdModPosition);}},_afterFooterChange:function(L){if(L.src!==Q){this._uiSetStdMod(O,L.newVal,L.stdModPosition);}},_afterFillHeightChange:function(L){this._uiSetFillHeight(L.newVal);},_validateFillHeight:function(L){return!L||L==s.BODY||L==s.HEADER||L==s.FOOTER;},_uiSetFillHeight:function(u){var Y=this.getStdModNode(u);var L=this._currFillNode;if(L&&Y!==L){L.setStyle(Z,B);}if(Y){this._currFillNode=Y;}this._fillHeight();},_fillHeight:function(){if(this.get(q)){var L=this.get(Z);if(L!=B&&L!=X){this.fillHeight(this._currFillNode);}}},_uiSetStdMod:function(v,u,L){if(u){var Y=this.getStdModNode(v)||this._renderStdMod(v);if(u instanceof P||u instanceof c){this._addNodeRef(Y,u,L);}else{this._addNodeHTML(Y,u,L);}this.set(v+i,this._getStdModContent(v),{src:Q});this.fire(r);}},_renderStdMod:function(u){var L=this.get(U),Y=this._findStdModSection(u);if(!Y){Y=this._getStdModTemplate(u);}this._insertStdModSection(L,u,Y);this[u+T]=Y;return this[u+T];},_insertStdModSection:function(L,v,u){var Y=L.get(d);if(v===O||!Y){L.appendChild(u);}else{if(v===I){L.insertBefore(u,Y);}else{var w=this[O+T];if(w){L.insertBefore(u,w);}else{L.appendChild(u);}}}},_getStdModTemplate:function(L){return P.create(s.TEMPLATES[L],this._stdModNode.get(M));},_addNodeHTML:function(u,Y,L){if(L==n){u.set(o,u.get(o)+Y);}else{if(L==F){u.set(o,Y+u.get(o));}else{u.set(o,Y);}}},_addNodeRef:function(x,v,Y){var L=true,u,w;if(Y==F){var y=x.get(d);if(y){if(v instanceof c){for(u=v.size()-1;u>=0;--u){x.insertBefore(v.item(u),y);}}else{x.insertBefore(v,y);}L=false;}}else{if(Y!=n){x.set(o,B);}}if(L){if(v instanceof c){for(u=0,w=v.size();u ."+s.SECTION_CLASS_NAMES[L]);},_parseStdModHTML:function(x){var w=this._findStdModSection(x),u,Y;if(w){u=w.get(M).invoke(l);Y=w.get(G);for(var L=Y.size()-1;L>=0;L--){var v=u.get(d);if(v){u.insertBefore(Y.item(L),v);}else{u.appendChild(Y.item(L));}}return u;}return null;},_getStdModContent:function(L){return(this[L+T])?this[L+T].get(G):null;},setStdModContent:function(u,Y,L){this.set(u+i,Y,{stdModPosition:L});},getStdModNode:function(L){return this[L+T]||null;},fillHeight:function(u){if(u){var y=this.get(p),AA=[this.headerNode,this.bodyNode,this.footerNode],Y,AB=0,AC=0,x=0,w=false;for(var z=0,v=AA.length;z=0){u.setStyle(Z,x+t);}var L=this.get(U).get(g);if(L!=AB){x=x-(L-AB);u.setStyle(Z,x+t);}}}}}};A.WidgetStdMod=s;},"3.0.0",{requires:["widget"]}); \ No newline at end of file diff --git a/include/javascript/yui3/build/widget/widget-stdmod.js b/include/javascript/yui3/build/widget/widget-stdmod.js new file mode 100644 index 00000000..5820d996 --- /dev/null +++ b/include/javascript/yui3/build/widget/widget-stdmod.js @@ -0,0 +1,21 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add('widget-stdmod',function(Y){var L=Y.Lang,Node=Y.Node,NodeList=Y.NodeList,UA=Y.UA,Widget=Y.Widget,EMPTY="",HD="hd",BD="bd",FT="ft",HEADER="header",BODY="body",FOOTER="footer",FILL_HEIGHT="fillHeight",STDMOD="stdmod",PX="px",NODE_SUFFIX="Node",CONTENT_SUFFIX="Content",INNER_HTML="innerHTML",FIRST_CHILD="firstChild",CHILD_NODES="childNodes",CREATE_DOCUMENT_FRAGMENT="createDocumentFragment",OWNER_DOCUMENT="ownerDocument",CONTENT_BOX="contentBox",BOUNDING_BOX="boundingBox",HEIGHT="height",OFFSET_HEIGHT="offsetHeight",AUTO="auto",HeaderChange="headerContentChange",BodyChange="bodyContentChange",FooterChange="footerContentChange",FillHeightChange="fillHeightChange",HeightChange="HeightChange",ContentUpdate="contentUpdate",RENDERUI="renderUI",BINDUI="bindUI",SYNCUI="syncUI",UI=Y.Widget.UI_SRC;function StdMod(config){this._stdModNode=this.get(CONTENT_BOX);Y.after(this._renderUIStdMod,this,RENDERUI);Y.after(this._bindUIStdMod,this,BINDUI);Y.after(this._syncUIStdMod,this,SYNCUI);} +StdMod.HEADER=HEADER;StdMod.BODY=BODY;StdMod.FOOTER=FOOTER;StdMod.AFTER="after";StdMod.BEFORE="before";StdMod.REPLACE="replace";var STD_HEADER=StdMod.HEADER,STD_BODY=StdMod.BODY,STD_FOOTER=StdMod.FOOTER,AFTER=StdMod.AFTER,BEFORE=StdMod.BEFORE;StdMod.ATTRS={headerContent:{value:null},footerContent:{value:null},bodyContent:{value:null},fillHeight:{value:StdMod.BODY,validator:function(val){return this._validateFillHeight(val);}}};StdMod.HTML_PARSER={headerContent:function(contentBox){return this._parseStdModHTML(STD_HEADER);},bodyContent:function(contentBox){return this._parseStdModHTML(STD_BODY);},footerContent:function(contentBox){return this._parseStdModHTML(STD_FOOTER);}};StdMod.SECTION_CLASS_NAMES={header:Widget.getClassName(HD),body:Widget.getClassName(BD),footer:Widget.getClassName(FT)};StdMod.TEMPLATES={header:'
    ',body:'
    ',footer:'
    '};StdMod.prototype={_syncUIStdMod:function(){this._uiSetStdMod(STD_HEADER,this.get(STD_HEADER+CONTENT_SUFFIX));this._uiSetStdMod(STD_BODY,this.get(STD_BODY+CONTENT_SUFFIX));this._uiSetStdMod(STD_FOOTER,this.get(STD_FOOTER+CONTENT_SUFFIX));this._uiSetFillHeight(this.get(FILL_HEIGHT));},_renderUIStdMod:function(){this._stdModNode.addClass(Widget.getClassName(STDMOD));},_bindUIStdMod:function(){this.after(HeaderChange,this._afterHeaderChange);this.after(BodyChange,this._afterBodyChange);this.after(FooterChange,this._afterFooterChange);this.after(FillHeightChange,this._afterFillHeightChange);this.after(HeightChange,this._fillHeight);this.after(ContentUpdate,this._fillHeight);},_afterHeaderChange:function(e){if(e.src!==UI){this._uiSetStdMod(STD_HEADER,e.newVal,e.stdModPosition);}},_afterBodyChange:function(e){if(e.src!==UI){this._uiSetStdMod(STD_BODY,e.newVal,e.stdModPosition);}},_afterFooterChange:function(e){if(e.src!==UI){this._uiSetStdMod(STD_FOOTER,e.newVal,e.stdModPosition);}},_afterFillHeightChange:function(e){this._uiSetFillHeight(e.newVal);},_validateFillHeight:function(val){return!val||val==StdMod.BODY||val==StdMod.HEADER||val==StdMod.FOOTER;},_uiSetFillHeight:function(fillSection){var fillNode=this.getStdModNode(fillSection);var currNode=this._currFillNode;if(currNode&&fillNode!==currNode){currNode.setStyle(HEIGHT,EMPTY);} +if(fillNode){this._currFillNode=fillNode;} +this._fillHeight();},_fillHeight:function(){if(this.get(FILL_HEIGHT)){var height=this.get(HEIGHT);if(height!=EMPTY&&height!=AUTO){this.fillHeight(this._currFillNode);}}},_uiSetStdMod:function(section,content,where){if(content){var node=this.getStdModNode(section)||this._renderStdMod(section);if(content instanceof Node||content instanceof NodeList){this._addNodeRef(node,content,where);}else{this._addNodeHTML(node,content,where);} +this.set(section+CONTENT_SUFFIX,this._getStdModContent(section),{src:UI});this.fire(ContentUpdate);}},_renderStdMod:function(section){var contentBox=this.get(CONTENT_BOX),sectionNode=this._findStdModSection(section);if(!sectionNode){sectionNode=this._getStdModTemplate(section);} +this._insertStdModSection(contentBox,section,sectionNode);this[section+NODE_SUFFIX]=sectionNode;return this[section+NODE_SUFFIX];},_insertStdModSection:function(contentBox,section,sectionNode){var fc=contentBox.get(FIRST_CHILD);if(section===STD_FOOTER||!fc){contentBox.appendChild(sectionNode);}else{if(section===STD_HEADER){contentBox.insertBefore(sectionNode,fc);}else{var footer=this[STD_FOOTER+NODE_SUFFIX];if(footer){contentBox.insertBefore(sectionNode,footer);}else{contentBox.appendChild(sectionNode);}}}},_getStdModTemplate:function(section){return Node.create(StdMod.TEMPLATES[section],this._stdModNode.get(OWNER_DOCUMENT));},_addNodeHTML:function(node,html,where){if(where==AFTER){node.set(INNER_HTML,node.get(INNER_HTML)+html);}else if(where==BEFORE){node.set(INNER_HTML,html+node.get(INNER_HTML));}else{node.set(INNER_HTML,html);}},_addNodeRef:function(node,children,where){var append=true,i,s;if(where==BEFORE){var n=node.get(FIRST_CHILD);if(n){if(children instanceof NodeList){for(i=children.size()-1;i>=0;--i){node.insertBefore(children.item(i),n);}}else{node.insertBefore(children,n);} +append=false;}}else if(where!=AFTER){node.set(INNER_HTML,EMPTY);} +if(append){if(children instanceof NodeList){for(i=0,s=children.size();i ."+StdMod.SECTION_CLASS_NAMES[section]);},_parseStdModHTML:function(section){var node=this._findStdModSection(section),docFrag,children;if(node){docFrag=node.get(OWNER_DOCUMENT).invoke(CREATE_DOCUMENT_FRAGMENT);children=node.get(CHILD_NODES);for(var i=children.size()-1;i>=0;i--){var fc=docFrag.get(FIRST_CHILD);if(fc){docFrag.insertBefore(children.item(i),fc);}else{docFrag.appendChild(children.item(i));}} +return docFrag;} +return null;},_getStdModContent:function(section){return(this[section+NODE_SUFFIX])?this[section+NODE_SUFFIX].get(CHILD_NODES):null;},setStdModContent:function(section,content,where){this.set(section+CONTENT_SUFFIX,content,{stdModPosition:where});},getStdModNode:function(section){return this[section+NODE_SUFFIX]||null;},fillHeight:function(node){if(node){var boundingBox=this.get(BOUNDING_BOX),stdModNodes=[this.headerNode,this.bodyNode,this.footerNode],stdModNode,total=0,filled=0,remaining=0,validNode=false;for(var i=0,l=stdModNodes.length;i=0){node.setStyle(HEIGHT,remaining+PX);} +var offsetHeight=this.get(CONTENT_BOX).get(OFFSET_HEIGHT);if(offsetHeight!=total){remaining=remaining-(offsetHeight-total);node.setStyle(HEIGHT,remaining+PX);}}}}}};Y.WidgetStdMod=StdMod;},'3.0.0',{requires:['widget']}); \ No newline at end of file diff --git a/include/javascript/yui3/build/widget/widget.js b/include/javascript/yui3/build/widget/widget.js new file mode 100644 index 00000000..38d026d1 --- /dev/null +++ b/include/javascript/yui3/build/widget/widget.js @@ -0,0 +1,36 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +YUI.add('widget',function(Y){var L=Y.Lang,O=Y.Object,Node=Y.Node,ClassNameManager=Y.ClassNameManager,WIDGET="widget",CONTENT="content",VISIBLE="visible",HIDDEN="hidden",DISABLED="disabled",FOCUSED="focused",WIDTH="width",HEIGHT="height",EMPTY="",HYPHEN="-",BOUNDING_BOX="boundingBox",CONTENT_BOX="contentBox",PARENT_NODE="parentNode",FIRST_CHILD="firstChild",OWNER_DOCUMENT="ownerDocument",BODY="body",TAB_INDEX="tabIndex",LOCALE="locale",INIT_VALUE="initValue",ID="id",RENDER="render",RENDERED="rendered",DESTROYED="destroyed",ContentUpdate="contentUpdate",_instances={};function Widget(config){this._yuid=Y.guid(WIDGET);this._strings={};Widget.superclass.constructor.apply(this,arguments);} +Widget._buildCfg={aggregates:["HTML_PARSER"]};Widget.NAME=WIDGET;Widget.UI_SRC="ui";var UI=Widget.UI_SRC;Widget.ATTRS={rendered:{value:false,readOnly:true},boundingBox:{value:null,setter:function(node){return this._setBoundingBox(node);},writeOnce:true},contentBox:{value:null,setter:function(node){return this._setContentBox(node);},writeOnce:true},tabIndex:{value:0,validator:function(val){return(L.isNumber(val)||L.isNull(val));}},focused:{value:false,readOnly:true},disabled:{value:false},visible:{value:true},height:{value:EMPTY},width:{value:EMPTY},moveStyles:{value:false},locale:{value:"en"},strings:{setter:function(val){return this._setStrings(val,this.get(LOCALE));},getter:function(){return this.getStrings(this.get(LOCALE));}}};Widget._NAME_LOWERCASE=Widget.NAME.toLowerCase();Widget.getClassName=function(){var args=Y.Array(arguments,0,true);args.splice(0,0,this._NAME_LOWERCASE);return ClassNameManager.getClassName.apply(ClassNameManager,args);};Widget.getByNode=function(node){var widget,bbMarker=Widget.getClassName();node=Node.get(node);if(node){node=(node.hasClass(bbMarker))?node:node.ancestor("."+bbMarker);if(node){widget=_instances[node.get(ID)];}} +return widget||null;};Widget.HTML_PARSER={};Y.extend(Widget,Y.Base,{getClassName:function(){var args=Y.Array(arguments,0,true);args.splice(0,0,this._name);return ClassNameManager.getClassName.apply(ClassNameManager,args);},initializer:function(config){this.publish(ContentUpdate,{preventable:false});this._name=this.constructor.NAME.toLowerCase();var nodeId=this.get(BOUNDING_BOX).get(ID);if(nodeId){_instances[nodeId]=this;} +var htmlConfig=this._parseHTML(this.get(CONTENT_BOX));if(htmlConfig){Y.aggregate(config,htmlConfig,false);}},destructor:function(){var boundingBox=this.get(BOUNDING_BOX);Y.Event.purgeElement(boundingBox,true);var nodeId=boundingBox.get(ID);if(nodeId&&nodeId in _instances){delete _instances[nodeId];}},render:function(parentNode){if(this.get(DESTROYED)){return;} +if(!this.get(RENDERED)){this.publish(RENDER,{queuable:false,defaultFn:this._defRenderFn});parentNode=(parentNode)?Node.get(parentNode):null;if(parentNode&&!parentNode.inDoc()){parentNode=null;} +this.fire(RENDER,{parentNode:parentNode});} +return this;},_defRenderFn:function(e){this._renderUI(e.parentNode);this._bindUI();this._syncUI();this.renderer();this._set(RENDERED,true);},renderer:function(){this.renderUI();this.bindUI();this.syncUI();},bindUI:function(){},renderUI:function(){},syncUI:function(){},hide:function(){return this.set(VISIBLE,false);},show:function(){return this.set(VISIBLE,true);},focus:function(){return this._set(FOCUSED,true);},blur:function(){return this._set(FOCUSED,false);},enable:function(){return this.set(DISABLED,false);},disable:function(){return this.set(DISABLED,true);},_parseHTML:function(node){var schema=this._getHtmlParser(),data,val;if(schema&&node&&node.hasChildNodes()){O.each(schema,function(v,k,o){val=null;if(L.isFunction(v)){val=v.call(this,node);}else{if(L.isArray(v)){val=node.queryAll(v[0]);}else{val=node.query(v);}} +if(val!==null&&val!==undefined){data=data||{};data[k]=val;}},this);} +return data;},_moveStyles:function(nodeFrom,nodeTo){var styles=this.WRAP_STYLES,pos=nodeFrom.getStyle('position'),contentBox=this.get(CONTENT_BOX),xy=[0,0],h,w;if(!this.get('height')){h=contentBox.get('offsetHeight');} +if(!this.get('width')){w=contentBox.get('offsetWidth');} +if(pos==='absolute'){xy=nodeFrom.getXY();nodeTo.setStyles({right:'auto',bottom:'auto'});nodeFrom.setStyles({right:'auto',bottom:'auto'});} +Y.each(styles,function(v,k){var s=nodeFrom.getStyle(k);nodeTo.setStyle(k,s);if(v===false){nodeFrom.setStyle(k,'');}else{nodeFrom.setStyle(k,v);}});if(pos==='absolute'){nodeTo.setXY(xy);} +if(h){this.set('height',h);} +if(w){this.set('width',w);}},_renderBox:function(parentNode){var contentBox=this.get(CONTENT_BOX),boundingBox=this.get(BOUNDING_BOX),doc=boundingBox.get(OWNER_DOCUMENT)||contentBox.get(OWNER_DOCUMENT),body;if(!boundingBox.compareTo(contentBox.get(PARENT_NODE))){if(this.get('moveStyles')){this._moveStyles(contentBox,boundingBox);} +if(contentBox.inDoc(doc)){contentBox.get(PARENT_NODE).replaceChild(boundingBox,contentBox);} +boundingBox.appendChild(contentBox);} +if(!boundingBox.inDoc(doc)&&!parentNode){body=Node.get(BODY);if(body.get(FIRST_CHILD)){body.insertBefore(boundingBox,body.get(FIRST_CHILD));}else{body.appendChild(boundingBox);}}else{if(parentNode&&!parentNode.compareTo(boundingBox.get(PARENT_NODE))){parentNode.appendChild(boundingBox);}}},_setBoundingBox:function(node){return this._setBox(node,this.BOUNDING_TEMPLATE);},_setContentBox:function(node){return this._setBox(node,this.CONTENT_TEMPLATE);},_setBox:function(node,template){node=Node.get(node)||Node.create(template);var sid=Y.stamp(node);if(!node.get(ID)){node.set(ID,sid);} +return node;},_renderUI:function(parentNode){this._renderBoxClassNames();this._renderBox(parentNode);},_renderBoxClassNames:function(){var classes=this._getClasses(),boundingBox=this.get(BOUNDING_BOX),contentBox=this.get(CONTENT_BOX),name,i;boundingBox.addClass(Widget.getClassName());for(i=classes.length-3;i>=0;i--){name=classes[i].NAME;if(name){boundingBox.addClass(ClassNameManager.getClassName(name.toLowerCase()));}} +contentBox.addClass(this.getClassName(CONTENT));},_bindUI:function(){this.after('visibleChange',this._afterVisibleChange);this.after('disabledChange',this._afterDisabledChange);this.after('heightChange',this._afterHeightChange);this.after('widthChange',this._afterWidthChange);this.after('focusedChange',this._afterFocusedChange);this._bindDOMListeners();},_bindDOMListeners:function(){var oDocument=this.get(BOUNDING_BOX).get("ownerDocument");oDocument.on("focus",this._onFocus,this);if(Y.UA.webkit){oDocument.on("mousedown",this._onDocMouseDown,this);}},_syncUI:function(){this._uiSetVisible(this.get(VISIBLE));this._uiSetDisabled(this.get(DISABLED));this._uiSetHeight(this.get(HEIGHT));this._uiSetWidth(this.get(WIDTH));this._uiSetFocused(this.get(FOCUSED));this._uiSetTabIndex(this.get(TAB_INDEX));},_uiSetHeight:function(val){if(L.isNumber(val)){val=val+this.DEF_UNIT;} +this.get(BOUNDING_BOX).setStyle(HEIGHT,val);},_uiSetWidth:function(val){if(L.isNumber(val)){val=val+this.DEF_UNIT;} +this.get(BOUNDING_BOX).setStyle(WIDTH,val);},_uiSetVisible:function(val){var box=this.get(BOUNDING_BOX),sClassName=this.getClassName(HIDDEN);if(val===true){box.removeClass(sClassName);}else{box.addClass(sClassName);}},_uiSetDisabled:function(val){var box=this.get(BOUNDING_BOX),sClassName=this.getClassName(DISABLED);if(val===true){box.addClass(sClassName);}else{box.removeClass(sClassName);}},_uiSetTabIndex:function(index){var boundingBox=this.get(BOUNDING_BOX);if(L.isNumber(index)){boundingBox.set(TAB_INDEX,index);} +else{boundingBox.removeAttribute(TAB_INDEX);}},_uiSetFocused:function(val,src){var box=this.get(BOUNDING_BOX),sClassName=this.getClassName(FOCUSED);if(val===true){box.addClass(sClassName);if(src!==UI){box.focus();}}else{box.removeClass(sClassName);if(src!==UI){box.blur();}}},_afterVisibleChange:function(evt){this._uiSetVisible(evt.newVal);},_afterDisabledChange:function(evt){this._uiSetDisabled(evt.newVal);},_afterHeightChange:function(evt){this._uiSetHeight(evt.newVal);},_afterWidthChange:function(evt){this._uiSetWidth(evt.newVal);},_afterFocusedChange:function(evt){this._uiSetFocused(evt.newVal,evt.src);},_onDocMouseDown:function(evt){if(this._hasDOMFocus){this._onFocus(evt);}},_onFocus:function(evt){var target=evt.target,boundingBox=this.get(BOUNDING_BOX),bFocused=(boundingBox.compareTo(target)||boundingBox.contains(target));this._hasDOMFocus=bFocused;this._set(FOCUSED,bFocused,{src:UI});},toString:function(){return this.constructor.NAME+"["+this._yuid+"]";},DEF_UNIT:"px",CONTENT_TEMPLATE:"
    ",BOUNDING_TEMPLATE:"
    ",WRAP_STYLES:{height:'100%',width:'100%',zIndex:false,position:'static',top:'0',left:'0',bottom:'',right:'',padding:'',margin:''},_setStrings:function(strings,locale){var strs=this._strings;locale=locale.toLowerCase();if(!strs[locale]){strs[locale]={};} +Y.aggregate(strs[locale],strings,true);return strs[locale];},_getStrings:function(locale){return this._strings[locale.toLowerCase()];},getStrings:function(locale){locale=(locale||this.get(LOCALE)).toLowerCase();var defLocale=this.getDefaultLocale().toLowerCase(),defStrs=this._getStrings(defLocale),strs=(defStrs)?Y.merge(defStrs):{},localeSegments=locale.split(HYPHEN);if(locale!==defLocale||localeSegments.length>1){var lookup="";for(var i=0,l=localeSegments.length;i=0;i--){p=classes[i].HTML_PARSER;if(p){Y.mix(parser,p,true);}} +this._HTML_PARSER=parser;} +return this._HTML_PARSER;}});Y.Widget=Widget;},'3.0.0',{requires:['attribute','event-focus','base','node','classnamemanager']}); \ No newline at end of file diff --git a/include/javascript/yui3/build/yui-base/yui-base-min.js b/include/javascript/yui3/build/yui-base/yui-base-min.js new file mode 100644 index 00000000..7ddf9167 --- /dev/null +++ b/include/javascript/yui3/build/yui-base/yui-base-min.js @@ -0,0 +1,8 @@ +/* + Copyright (c) 2009, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 3.0.0 + build: 1549 + */ +(function(){var I={},B=new Date().getTime(),A,E,H=function(){if(window.addEventListener){return function(M,L,K,J){M.addEventListener(L,K,(!!J));};}else{if(window.attachEvent){return function(L,K,J){L.attachEvent("on"+K,J);};}else{return function(){};}}}(),F=function(){if(window.removeEventListener){return function(M,L,K,J){M.removeEventListener(L,K,!!J);};}else{if(window.detachEvent){return function(L,K,J){L.detachEvent("on"+K,J);};}else{return function(){};}}}(),D=function(){YUI.Env.windowLoaded=true;YUI.Env.DOMReady=true;F(window,"load",D);},C={"io.xdrReady":1,"io.start":1,"io.success":1,"io.failure":1},G=Array.prototype.slice;if(typeof YUI==="undefined"||!YUI){YUI=function(O,N,M,L,J){var K=this,R=arguments,Q,P=R.length;if(!(K instanceof YUI)){return new YUI(O,N,M,L,J);}else{K._init();for(Q=0;Q-1){J="test";}K.version=J;K.Env={mods:{},cdn:"http://yui.yahooapis.com/"+J+"/build/",bootstrapped:false,_idx:0,_used:{},_attached:{},_yidx:0,_uidx:0,_loaded:{}};K.Env._loaded[J]={};if(YUI.Env){K.Env._yidx=(++YUI.Env._yidx);K.Env._guidp=("yui_"+J+"-"+K.Env._yidx+"-"+B).replace(/\./g,"_");K.id=K.stamp(K);I[K.id]=K;}K.constructor=YUI;K.config={win:window||{},doc:document,debug:true,useBrowserConsole:true,throwFail:true,base:function(){var M,N,P,O;N=document.getElementsByTagName("script");for(P=0;P1)){E=2;}}catch(F){}}}return E;};D.each=(C.forEach)?function(E,F,G){C.forEach.call(E||[],F,G||A);return A;}:function(F,H,I){var E=(F&&F.length)||0,G;for(G=0;GH)?F[H]:true;}return J;};D.indexOf=(C.indexOf)?function(E,F){return C.indexOf.call(E,F);}:function(E,G){for(var F=0;F-1);};D.owns=function(F,E){return(F.hasOwnProperty(E));};D.each=function(I,H,J,G){var F=J||A,E;for(E in I){if(G||I.hasOwnProperty(E)){H.call(F,I[E],E,I);}}return A;};D.getValue=function(I,H){var G=A.Array(H),E=G.length,F;for(F=0;I!==C&&F=0){for(E=0;F!==C&&E-1){v='test';} +Y.version=v;Y.Env={mods:{},cdn:'http://yui.yahooapis.com/'+v+'/build/',bootstrapped:false,_idx:0,_used:{},_attached:{},_yidx:0,_uidx:0,_loaded:{}};Y.Env._loaded[v]={};if(YUI.Env){Y.Env._yidx=(++YUI.Env._yidx);Y.Env._guidp=('yui_'+v+'-'+Y.Env._yidx+'-'+_startTime).replace(/\./g,'_');Y.id=Y.stamp(Y);_instances[Y.id]=Y;} +Y.constructor=YUI;Y.config={win:window||{},doc:document,debug:true,useBrowserConsole:true,throwFail:true,base:function(){var b,nodes,i,match;nodes=document.getElementsByTagName('script');for(i=0;i1)){r=2;}}catch(e){}}} +return r;};YArray.each=(Native.forEach)?function(a,f,o){Native.forEach.call(a||[],f,o||Y);return Y;}:function(a,f,o){var l=(a&&a.length)||0,i;for(i=0;ii)?v[i]:true;} +return o;};YArray.indexOf=(Native.indexOf)?function(a,val){return Native.indexOf.call(a,val);}:function(a,val){for(var i=0;i-1);};O.owns=function(o,k){return(o.hasOwnProperty(k));};O.each=function(o,f,c,proto){var s=c||Y,i;for(i in o){if(proto||o.hasOwnProperty(i)){f.call(s,o[i],i,o);}} +return Y;};O.getValue=function(o,path){var p=Y.Array(path),l=p.length,i;for(i=0;o!==UNDEFINED&&i=0){for(i=0;ref!==UNDEFINED&&i-1){J="test";}K.version=J;K.Env={mods:{},cdn:"http://yui.yahooapis.com/"+J+"/build/",bootstrapped:false,_idx:0,_used:{},_attached:{},_yidx:0,_uidx:0,_loaded:{}};K.Env._loaded[J]={};if(YUI.Env){K.Env._yidx=(++YUI.Env._yidx);K.Env._guidp=("yui_"+J+"-"+K.Env._yidx+"-"+B).replace(/\./g,"_");K.id=K.stamp(K);I[K.id]=K;}K.constructor=YUI;K.config={win:window||{},doc:document,debug:true,useBrowserConsole:true,throwFail:true,bootstrap:true,fetchCSS:true,base:function(){var L,M,O,N;M=document.getElementsByTagName("script");for(O=0;O1)){F=2;}}catch(G){}}}return F;};E.each=(D.forEach)?function(F,G,H){D.forEach.call(F||[],G,H||B);return B;}:function(G,I,J){var F=(G&&G.length)||0,H;for(H=0;HI)?G[I]:true;}return K;};E.indexOf=(D.indexOf)?function(F,G){return D.indexOf.call(F,G);}:function(F,H){for(var G=0;G-1);};E.owns=function(G,F){return(G.hasOwnProperty(F));};E.each=function(J,I,K,H){var G=K||B,F;for(F in J){if(H||J.hasOwnProperty(F)){I.call(G,J[F],F,J);}}return B;};E.getValue=function(J,I){var H=B.Array(I),F=H.length,G;for(G=0;J!==D&&G=0){for(F=0;G!==D&&F-1){v='test';} +Y.version=v;Y.Env={mods:{},cdn:'http://yui.yahooapis.com/'+v+'/build/',bootstrapped:false,_idx:0,_used:{},_attached:{},_yidx:0,_uidx:0,_loaded:{}};Y.Env._loaded[v]={};if(YUI.Env){Y.Env._yidx=(++YUI.Env._yidx);Y.Env._guidp=('yui_'+v+'-'+Y.Env._yidx+'-'+_startTime).replace(/\./g,'_');Y.id=Y.stamp(Y);_instances[Y.id]=Y;} +Y.constructor=YUI;Y.config={win:window||{},doc:document,debug:true,useBrowserConsole:true,throwFail:true,bootstrap:true,fetchCSS:true,base:function(){var b,nodes,i,match;nodes=document.getElementsByTagName('script');for(i=0;i1)){r=2;}}catch(e){}}} +return r;};YArray.each=(Native.forEach)?function(a,f,o){Native.forEach.call(a||[],f,o||Y);return Y;}:function(a,f,o){var l=(a&&a.length)||0,i;for(i=0;ii)?v[i]:true;} +return o;};YArray.indexOf=(Native.indexOf)?function(a,val){return Native.indexOf.call(a,val);}:function(a,val){for(var i=0;i-1);};O.owns=function(o,k){return(o.hasOwnProperty(k));};O.each=function(o,f,c,proto){var s=c||Y,i;for(i in o){if(proto||o.hasOwnProperty(i)){f.call(s,o[i],i,o);}} +return Y;};O.getValue=function(o,path){var p=Y.Array(path),l=p.length,i;for(i=0;o!==UNDEFINED&&i=0){for(i=0;ref!==UNDEFINED&&i-1){J="test";}K.version=J;K.Env={mods:{},cdn:"http://yui.yahooapis.com/"+J+"/build/",bootstrapped:false,_idx:0,_used:{},_attached:{},_yidx:0,_uidx:0,_loaded:{}};K.Env._loaded[J]={};if(YUI.Env){K.Env._yidx=(++YUI.Env._yidx);K.Env._guidp=("yui_"+J+"-"+K.Env._yidx+"-"+B).replace(/\./g,"_");K.id=K.stamp(K);I[K.id]=K;}K.constructor=YUI;K.config={win:window||{},doc:document,debug:true,useBrowserConsole:true,throwFail:true,bootstrap:true,fetchCSS:true,base:function(){var L,M,O,N;M=document.getElementsByTagName("script");for(O=0;O1)){F=2;}}catch(G){}}}return F;};E.each=(D.forEach)?function(F,G,H){D.forEach.call(F||[],G,H||B);return B;}:function(G,I,J){var F=(G&&G.length)||0,H;for(H=0;HI)?G[I]:true;}return K;};E.indexOf=(D.indexOf)?function(F,G){return D.indexOf.call(F,G);}:function(F,H){for(var G=0;G-1);};E.owns=function(G,F){return(G.hasOwnProperty(F));};E.each=function(J,I,K,H){var G=K||B,F;for(F in J){if(H||J.hasOwnProperty(F)){I.call(G,J[F],F,J);}}return B;};E.getValue=function(J,I){var H=B.Array(I),F=H.length,G;for(G=0;J!==D&&G=0){for(F=0;G!==D&&F-1){v='test';} +Y.version=v;Y.Env={mods:{},cdn:'http://yui.yahooapis.com/'+v+'/build/',bootstrapped:false,_idx:0,_used:{},_attached:{},_yidx:0,_uidx:0,_loaded:{}};Y.Env._loaded[v]={};if(YUI.Env){Y.Env._yidx=(++YUI.Env._yidx);Y.Env._guidp=('yui_'+v+'-'+Y.Env._yidx+'-'+_startTime).replace(/\./g,'_');Y.id=Y.stamp(Y);_instances[Y.id]=Y;} +Y.constructor=YUI;Y.config={win:window||{},doc:document,debug:true,useBrowserConsole:true,throwFail:true,bootstrap:true,fetchCSS:true,base:function(){var b,nodes,i,match;nodes=document.getElementsByTagName('script');for(i=0;i1)){r=2;}}catch(e){}}} +return r;};YArray.each=(Native.forEach)?function(a,f,o){Native.forEach.call(a||[],f,o||Y);return Y;}:function(a,f,o){var l=(a&&a.length)||0,i;for(i=0;ii)?v[i]:true;} +return o;};YArray.indexOf=(Native.indexOf)?function(a,val){return Native.indexOf.call(a,val);}:function(a,val){for(var i=0;i-1);};O.owns=function(o,k){return(o.hasOwnProperty(k));};O.each=function(o,f,c,proto){var s=c||Y,i;for(i in o){if(proto||o.hasOwnProperty(i)){f.call(s,o[i],i,o);}} +return Y;};O.getValue=function(o,path){var p=Y.Array(path),l=p.length,i;for(i=0;o!==UNDEFINED&&i=0){for(i=0;ref!==UNDEFINED&&i + + + The Yahoo! User Interface Library (YUI) 3.0.0 + + + + + + + + +
    +
    +
    +

    + + YUI 3.x Home - + +

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

    The Yahoo! User Interface Library (YUI) 3.0.0

    +
    +
    + +
    +
    + +
    + +

    YUI 3.0.0

    + +

    Thank you for downloading YUI 3.0.0. This release brings the core components and a number of utilities in YUI 3 to production quality. Please review the API, explore the examples, and read the documentation on the YUI website for details.

    +

    YUI 3.0.0 is part of the broader YUI Library project, which is a collection of JavaScript and CSS resources that make it easier to build richly interactive applications in web browsers. They have been released as open source under a BSD license and are free for all uses.

    + +

    Getting Started

    + +
      +
    1. Check out the examples of YUI in action. We recommend starting with the base YUI module and then move on to Node. Other utilities like Event, IO and Drag and Drop make for good points of exploration.
    2. +
    3. Remember that there are full user's guides for each component on the YUI website. If you have any questions about a component as you play with the examples, check out the component's user's guide (by following any of the links along the left side of the page) or the searchable API documentation.
    4. +
    5. Start building. Use the YUI 3 Configurator to configure a page for YUI 3 usage or base your exploration off of one of the existing examples.
    6. +
    7. Become a member of the YUI community. The YUI team and developers in the YUI community share thoughts and solutions in YUI 3 Forums. YUI developers also contribute to the YUIBlog, where you'll find in-depth articles, videos and other great content about YUI and the world of frontend engineering.
    8. +
    + +

    YUI Functional Examples Included with This Download:

    + +

    Along with the source code for YUI, your download includes 130 functional examples and tutorials showing YUI 3.x in action. Use the list below or the menu at left to review these YUI demos — they're the best way to get oriented to what YUI can do and to grab sample code that can help you get started. Remember that these examples and more, in addition to user's guides for each YUI component, can also be found on the YUI website. (Note: Almost all examples in this distribution will work if you are browsing them from your filesystem, but some examples included here do need to be deployed on a PHP-enabled http server to function properly; if you don't have access to such a setup, just check out those examples on our website to see how they work.)

    + +
    + + +
    +
    + +

    YUI 3 Core

    + + +

    YUI 3 Component Infrastructure

    + + +

    YUI 3 Widgets

    + + +

    YUI 3 Node Plugins

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

    Copyright © 2009 Yahoo! Inc. All rights reserved.

    +

    Privacy Policy - + Terms of Service - + Copyright Policy - + Job Openings

    +
    +
    + + + + diff --git a/include/jsolait/LICENSE b/include/jsolait/LICENSE new file mode 100644 index 00000000..b1e3f5a2 --- /dev/null +++ b/include/jsolait/LICENSE @@ -0,0 +1,504 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 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. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +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 and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, 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 library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete 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 distribute a copy of this License along with the +Library. + + 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 Library or any portion +of it, thus forming a work based on the Library, 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) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +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 Library, 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 Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you 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. + + If distribution of 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 satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be 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. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library 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. + + 9. 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 Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +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 with +this License. + + 11. 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 Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library 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 Library. + +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. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library 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. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser 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 Library +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 Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +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 + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "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 +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. 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 LIBRARY 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 +LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), 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 Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. 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 library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License 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. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; 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. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + diff --git a/include/jsolait/copying.txt b/include/jsolait/copying.txt new file mode 100644 index 00000000..b1e3f5a2 --- /dev/null +++ b/include/jsolait/copying.txt @@ -0,0 +1,504 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 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. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +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 and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, 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 library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete 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 distribute a copy of this License along with the +Library. + + 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 Library or any portion +of it, thus forming a work based on the Library, 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) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +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 Library, 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 Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you 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. + + If distribution of 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 satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be 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. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library 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. + + 9. 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 Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +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 with +this License. + + 11. 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 Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library 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 Library. + +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. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library 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. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser 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 Library +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 Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +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 + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "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 +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. 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 LIBRARY 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 +LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), 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 Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. 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 library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License 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. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; 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. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + diff --git a/include/jsolait/init.js b/include/jsolait/init.js new file mode 100644 index 00000000..6e85bb0d --- /dev/null +++ b/include/jsolait/init.js @@ -0,0 +1,101 @@ +/* + + Modification information for LGPL compliance + + r56990 - 2010-06-16 13:05:36 -0700 (Wed, 16 Jun 2010) - kjing - snapshot "Mango" svn branch to a new one for GitHub sync + + r56989 - 2010-06-16 13:01:33 -0700 (Wed, 16 Jun 2010) - kjing - defunt "Mango" svn dev branch before github cutover + + r55980 - 2010-04-19 13:31:28 -0700 (Mon, 19 Apr 2010) - kjing - create Mango (6.1) based on windex + + r51719 - 2009-10-22 10:18:00 -0700 (Thu, 22 Oct 2009) - mitani - Converted to Build 3 tags and updated the build system + + r51634 - 2009-10-19 13:32:22 -0700 (Mon, 19 Oct 2009) - mitani - Windex is the branch for Sugar Sales 1.0 development + + r50375 - 2009-08-24 18:07:43 -0700 (Mon, 24 Aug 2009) - dwong - branch kobe2 from tokyo r50372 + + r42807 - 2008-12-29 11:16:59 -0800 (Mon, 29 Dec 2008) - dwong - Branch from trunk/sugarcrm r42806 to branches/tokyo/sugarcrm + + r11496 - 2006-02-03 12:16:49 -0800 (Fri, 03 Feb 2006) - chris - Bug 4538: found 2 non-breaking, IE specific JS errors in sugar_3.js and init.js, added some logic to detect whether the browser supports IE activeX stuff and to run code appropriately. + Touched sugar_3.js and include/jsolait/init.js + + r4085 - 2005-04-13 17:30:42 -0700 (Wed, 13 Apr 2005) - robert - adding meeting scheduler and accept/decline + + + */ +globalEval=function(){return eval(arguments[0]);} +Class=function(className,superClass,classScope){if(arguments.length==2){classScope=superClass;if(typeof className!="string"){superClass=className;className="anonymous";}else{superClass=Object;}}else if(arguments.length==1){classScope=className;superClass=Object;className="anonymous";} +var NewClass=function(calledBy){if(calledBy!==Class){return this.init.apply(this,arguments);}} +NewClass.createPrototype=function(){return new NewClass(Class);} +NewClass.superClass=superClass;NewClass.className=className;NewClass.toString=function(){return"[class %s]".format(NewClass.className);};if(superClass.createPrototype!=null){NewClass.prototype=superClass.createPrototype();}else{NewClass.prototype=new superClass();} +NewClass.prototype.constructor=NewClass;if(superClass==Object){NewClass.prototype.toString=function(){return"[object %s]".format(this.constructor.className);};} +if(NewClass.prototype.init==null){NewClass.prototype.init=function(){}} +var supr=function(self){var wrapper={};var superProto=superClass.prototype;for(var n in superProto){if(typeof superProto[n]=="function"){wrapper[n]=function(){var f=arguments.callee;return superProto[f._name].apply(self,arguments);} +wrapper[n]._name=n;}} +return wrapper;} +classScope(NewClass.prototype,supr);return NewClass;} +Class.toString=function(){return"[object Class]";} +Class.createPrototype=function(){throw"Can't use Class as a super class.";} +Module=function(name,version,moduleScope){var mod=new Object();mod.version=version;mod.name=name;mod.toString=function(){return"[module '%s' version: %s]".format(mod.name,mod.version);} +mod.Exception=Class("Exception",function(publ){publ.init=function(msg,trace){this.name=this.constructor.className;this.message=msg;this.trace=trace;} +publ.toString=function(){var s="%s %s\n\n".format(this.name,this.module);s+=this.message;return s;} +publ.toTraceString=function(){var s="%s %s:\n ".format(this.name,this.module);s+="%s\n\n".format(this.message);if(this.trace){if(this.trace.toTraceString){s+=this.trace.toTraceString();}else{s+=this.trace;}} +return s;} +publ.name;publ.message;publ.module=mod;publ.trace;}) +moduleScope(mod);for(var n in mod){if(mod[n].className=="anonymous"){mod[n].className=n;}} +if(name!="jsolait"){jsolait.registerModule(mod);} +return mod;} +Module.toString=function(){return"[object Module]";} +Module.createPrototype=function(){throw"Can't use Module as a super class.";} +Module("jsolait","0.1.0",function(mod){jsolait=mod;mod.baseURL=".";mod.libURL="./jsolait";mod.modules=new Array();mod.moduleURLs={};mod.init=function(){if(typeof(WScript)!='undefined'){initWS();}} +var initWS=function(){print=function(msg){WScript.echo(msg);} +alert=function(msg){print(msg);} +var args=WScript.arguments;try{var url=args(0);url=url.replace(/\\/g,"/");url=url.split("/");url=url.slice(0,url.length-1);mod.baseURL=url.join("/");}catch(e){throw new mod.Exception("Missing script filename to be run.",e);} +url=WScript.ScriptFullName;if(args(0).replace("file://","").toLowerCase()==url.toLowerCase()){WScript.stderr.write("Can't run myself! exiting ... \n");return;} +url=url.replace(/\\/g,"/");url=url.split("/");url=url.slice(0,url.length-1);mod.libURL="file://"+url.join("/");try{mod.loadScript(args(0));}catch(e){WScript.stdErr.write("%s(1,1) jsolait runtime error:\n%s\n".format(args(0).replace("file://",""),e.toTraceString()));}} +mod.importModule=function(name){if(mod.modules[name]){return mod.modules[name];}else{var src,modURL;if(mod.moduleURLs[name]){modURL=mod.moduleURLs[name].format(mod);}else{modURL="%s/%s.js".format(mod.baseURL,name.split(".").join("/"));} +try{src=getFile(modURL);}catch(e){throw new mod.ModuleImportFailed(name,modURL,e);} +try{globalEval(src);}catch(e){throw new mod.ModuleImportFailed(name,modURL,e);} +return mod.modules[name];}} +importModule=mod.importModule;mod.loadScript=function(url){var src=getFile(url);try{globalEval(src);}catch(e){throw new mod.EvalFailed(url,e);}} +mod.registerModule=function(module){this.modules[module.name]=module;} +var getHTTP=function(){var obj;try{obj=new XMLHttpRequest();}catch(e){try{obj=new ActiveXObject("Msxml2.XMLHTTP.4.0");}catch(e){try{obj=new ActiveXObject("Msxml2.XMLHTTP");}catch(e){try{obj=new ActiveXObject("microsoft.XMLHTTP");}catch(e){throw new mod.Exception("Unable to get an HTTP request object.");}}}} +return obj;} +var getFile=function(url,headers){headers=(headers!=null)?headers:[];try{var xmlhttp=getHTTP();xmlhttp.open("GET",url,false);for(var i=0;i=arguments.length){throw new mod.Exception("Not enough arguments for format string");}else{obj=arguments[cnt];cnt++;}} +if(frmt.type=="s"){if(obj==null){obj="null";} +s=obj.toString().pad(frmt.paddingFlag,frmt.minLength);}else if(frmt.type=="c"){if(frmt.paddingFlag=="0"){frmt.paddingFlag=" ";} +if(typeof obj=="number"){s=String.fromCharCode(obj).pad(frmt.paddingFlag,frmt.minLength);}else if(typeof obj=="string"){if(obj.length==1){s=obj.pad(frmt.paddingFlag,frmt.minLength);}else{throw new mod.Exception("Character of length 1 required.");}}else{throw new mod.Exception("Character or Byte required.");}}else if(typeof obj=="number"){if(obj<0){obj=-obj;sign="-";}else if(frmt.signed){sign="+";}else{sign="";} +switch(frmt.type){case"f":case"F":if(frmt.percision>-1){s=obj.toFixed(frmt.percision).toString();}else{s=obj.toString();} +break;case"E":case"e":if(frmt.percision>-1){s=obj.toExponential(frmt.percision);}else{s=obj.toExponential();} +s=s.replace("e",frmt.type);break;case"b":s=obj.toString(2);s=s.pad("0",frmt.percision);break;case"o":s=obj.toString(8);s=s.pad("0",frmt.percision);break;case"x":s=obj.toString(16).toLowerCase();s=s.pad("0",frmt.percision);break;case"X":s=obj.toString(16).toUpperCase();s=s.pad("0",frmt.percision);break;default:s=parseInt(obj).toString();s=s.pad("0",frmt.percision);break;} +if(frmt.paddingFlag=="0"){s=s.pad("0",frmt.minLength-sign.length);} +s=sign+s;s=s.pad(frmt.paddingFlag,frmt.minLength);}else{throw new mod.Exception("Number required.");}} +rslt+=s;} +return rslt;} +String.prototype.pad=function(flag,len){var s="";if(flag=="-"){var c=" ";}else{var c=flag;} +for(var i=0;i>16,(nBits&0xff00)>>8,nBits&0xff);} +sDecoded[sDecoded.length-1]=sDecoded[sDecoded.length-1].substring(0,3-((this.charCodeAt(i-2)==61)?2:(this.charCodeAt(i-1)==61?1:0)));return sDecoded.join("");}}else{throw new mod.Exception("String length must be divisible by 4.");}} +String.prototype.encode_base64=function(){if(typeof(btoa)!="undefined"){return btoa(this);}else{var base64=['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/'];var sbin;var pad=0;var s=""+this;if((s.length%3)==1){s+=String.fromCharCode(0);s+=String.fromCharCode(0);pad=2;}else if((s.length%3)==2){s+=String.fromCharCode(0);pad=1;} +var rslt=new Array(s.length/3);var ri=0;for(var i=0;i>18)&0x3f]+base64[(sbin>>12)&0x3f]+base64[(sbin>>6)&0x3f]+base64[sbin&0x3f]);ri++;} +if(pad>0){rslt[rslt.length-1]=rslt[rslt.length-1].substr(0,4-pad)+((pad==2)?"==":(pad==1)?"=":"");} +return rslt.join("");}} +String.prototype.decode_uri=function(){return decodeURI(this);} +String.prototype.encode_uri=function(){return encodeURI(this);}}) \ No newline at end of file diff --git a/include/jsolait/lib/crypto.js b/include/jsolait/lib/crypto.js new file mode 100644 index 00000000..72e09cf9 --- /dev/null +++ b/include/jsolait/lib/crypto.js @@ -0,0 +1,37 @@ +/* + + Modification information for LGPL compliance + + r56990 - 2010-06-16 13:05:36 -0700 (Wed, 16 Jun 2010) - kjing - snapshot "Mango" svn branch to a new one for GitHub sync + + r56989 - 2010-06-16 13:01:33 -0700 (Wed, 16 Jun 2010) - kjing - defunt "Mango" svn dev branch before github cutover + + r55980 - 2010-04-19 13:31:28 -0700 (Mon, 19 Apr 2010) - kjing - create Mango (6.1) based on windex + + r51719 - 2009-10-22 10:18:00 -0700 (Thu, 22 Oct 2009) - mitani - Converted to Build 3 tags and updated the build system + + r51634 - 2009-10-19 13:32:22 -0700 (Mon, 19 Oct 2009) - mitani - Windex is the branch for Sugar Sales 1.0 development + + r50375 - 2009-08-24 18:07:43 -0700 (Mon, 24 Aug 2009) - dwong - branch kobe2 from tokyo r50372 + + r42807 - 2008-12-29 11:16:59 -0800 (Mon, 29 Dec 2008) - dwong - Branch from trunk/sugarcrm r42806 to branches/tokyo/sugarcrm + + r4085 - 2005-04-13 17:30:42 -0700 (Wed, 13 Apr 2005) - robert - adding meeting scheduler and accept/decline + + + */ +Module("crypto","0.1.2",function(mod){mod.listEncrypters=function(){var c=[];for(var attr in String.prototype){if(attr.slice(0,8)=="encrypt_"){c.push(attr.slice(8));}} +return c;} +mod.listDecrypters=function(){var c=[];for(var attr in String.prototype){if(attr.slice(0,8)=="decrypt_"){c.push(attr.slice(8));}} +return c;} +String.prototype.encrypt=function(crydec){var n="encrypt_"+crydec;if(String.prototype[n]){var args=[];for(var i=1;i":case"!":case"|":case"&":switch(s2){case"==":case"!=":case"<>":case"<=":case">=":case"||":case"&&":rslt=new mod.Token(mod.tokens.OP,s2,this._pos);break;default:rslt=new mod.Token(mod.tokens.OP,s1,this._pos);} +break;case"/":if(s2=="//"||s3=="///"){s1=extractSLComment(this._working);rslt=new mod.Token(s1.charAt(2)!="/"?mod.tokens.COMMENT:mod.tokens.DOCCOMMENT,s1,this._pos);}else if(s2=="/*"||s3=="/**"){try{s1=extractMLComment(this._working);rslt=new mod.Token(s3!="/**"?mod.tokens.COMMENT:mod.tokens.DOCCOMMENT,s1,this._pos);}catch(e){rslt=new mod.Token(mod.tokens.ERR,s3!="/**"?s2:s3,this._pos,e);}}else{try{s1=extractRegExp(this._working);rslt=new mod.Token(mod.tokens.REGEXP,s1,this._pos);}catch(e){rslt=new mod.Token(mod.tokens.OP,s1,this._pos,e);}} +break;case" ":var i=0;var s="";while(this._working.charAt(i)==" "){s+=" ";i++;} +rslt=new mod.Token(mod.tokens.WSP,s,this._pos);break;default:s1=this._working.match(/\d+\.\d+|\d+|\w+/)[0];if(/^\d|\d\.\d/.test(s1)){rslt=new mod.Token(mod.tokens.NUM,s1,this._pos);}else{rslt=new mod.Token(mod.tokens.NAME,s1,this._pos);}} +this._working=this._working.slice(rslt.value.length);this._pos+=rslt.value.length;return rslt;} +var searchQoute=function(s,q){if(q=="'"){return s.search(/[\\']/);}else{return s.search(/[\\"]/);}} +var extractQString=function(s){if(s.charAt(0)=="'"){var q="'";}else{var q='"';} +s=s.slice(1);var rs="";var p=searchQoute(s,q);while(p>=0){if(p>=0){if(s.charAt(p)==q){rs+=s.slice(0,p+1);s=s.slice(p+1);return q+rs;}else{rs+=s.slice(0,p+2);s=s.slice(p+2);}} +p=searchQoute(s,q);} +throw new mod.Exception("End of String expected.");} +var extractSLComment=function(s){var p=s.search(/\n/);if(p>=0){return s.slice(0,p+1);}else{return s;}} +var extractMLComment=function(s){var p=s.search(/\*\//);if(p>=0){return s.slice(0,p+2);}else{throw new mod.Exception("End of comment expected.");}} +var extractRegExp=function(s){var p=0;for(var i=0;i\n";}else{s+=">";for(var i=0;i\n";} +break;case PROCESSING_INSTRUCTION_NODE:s+="";break;case TEXT_NODE:s+=node.nodeValue;break;case CDATA_SECTION_NODE:s+="<"+"![CDATA["+node.nodeValue+"]"+"]>";break;case COMMENT_NODE:s+="";break;case ENTITY_REFERENCE_NODE:case DOCUMENT_FRAGMENT_NODE:case DOCUMENT_TYPE_NODE:case NOTATION_NODE:case ENTITY_NODE:throw new mod.Exception("Nodetype(%s) not supported.".format(node.nodeType));break;} +return s;}}) \ No newline at end of file diff --git a/include/jsolait/lib/xmlrpc.js b/include/jsolait/lib/xmlrpc.js new file mode 100644 index 00000000..f61a57b9 --- /dev/null +++ b/include/jsolait/lib/xmlrpc.js @@ -0,0 +1,98 @@ +/* + + Modification information for LGPL compliance + + r56990 - 2010-06-16 13:05:36 -0700 (Wed, 16 Jun 2010) - kjing - snapshot "Mango" svn branch to a new one for GitHub sync + + r56989 - 2010-06-16 13:01:33 -0700 (Wed, 16 Jun 2010) - kjing - defunt "Mango" svn dev branch before github cutover + + r55980 - 2010-04-19 13:31:28 -0700 (Mon, 19 Apr 2010) - kjing - create Mango (6.1) based on windex + + r51719 - 2009-10-22 10:18:00 -0700 (Thu, 22 Oct 2009) - mitani - Converted to Build 3 tags and updated the build system + + r51634 - 2009-10-19 13:32:22 -0700 (Mon, 19 Oct 2009) - mitani - Windex is the branch for Sugar Sales 1.0 development + + r50375 - 2009-08-24 18:07:43 -0700 (Mon, 24 Aug 2009) - dwong - branch kobe2 from tokyo r50372 + + r42807 - 2008-12-29 11:16:59 -0800 (Mon, 29 Dec 2008) - dwong - Branch from trunk/sugarcrm r42806 to branches/tokyo/sugarcrm + + r4085 - 2005-04-13 17:30:42 -0700 (Wed, 13 Apr 2005) - robert - adding meeting scheduler and accept/decline + + + */ +Module("xmlrpc","1.3.3",function(mod){var xmlext=importModule("xml");var urllib=importModule("urllib");mod.InvalidServerResponse=Class("InvalidServerResponse",mod.Exception,function(publ,supr){publ.init=function(status){supr(this).init("The server did not respond with a status 200 (OK) but with: "+status);this.status=status;} +publ.status;}) +mod.MalformedXmlRpc=Class("MalformedXmlRpc",mod.Exception,function(publ,supr){publ.init=function(msg,xml,trace){supr(this).init(msg,trace);this.xml=xml;} +publ.xml;}) +mod.Fault=Class("Fault",mod.Exception,function(publ,supr){publ.init=function(faultCode,faultString){supr(this).init("XML-RPC Fault: "+faultCode+"\n\n"+faultString);this.faultCode=faultCode;this.faultString=faultString;} +publ.faultCode;publ.faultString;}) +mod.marshall=function(obj){if(obj.toXmlRpc){return obj.toXmlRpc();}else{var s="";for(var attr in obj){if(typeof obj[attr]!="function"){s+=""+attr+""+mod.marshall(obj[attr])+"";}} +s+="";return s;}} +mod.unmarshall=function(xml){try{var doc=xmlext.parseXML(xml);}catch(e){throw new mod.MalformedXmlRpc("The server's response could not be parsed.",xml,e);} +var rslt=mod.unmarshallDoc(doc,xml);doc=null;return rslt;} +mod.unmarshallDoc=function(doc,xml){try{var node=doc.documentElement;if(node==null){throw new mod.MalformedXmlRpc("No documentElement found.",xml);} +switch(node.tagName){case"methodResponse":return parseMethodResponse(node);case"methodCall":return parseMethodCall(node);default:throw new mod.MalformedXmlRpc("'methodCall' or 'methodResponse' element expected.\nFound: '"+node.tagName+"'",xml);}}catch(e){if(e instanceof mod.Fault){throw e;}else{throw new mod.MalformedXmlRpc("Unmarshalling of XML failed.",xml,e);}}} +var parseMethodResponse=function(node){try{for(var i=0;i';if(args.length>0){data+="";for(var i=0;i'+mod.marshall(args[i])+'';} +data+='';} +data+='';return data;} +publ.init=function(url,methodName,user,pass){var fn=function(){if(typeof arguments[arguments.length-1]!="function"){var data=getXML(fn.methodName,arguments);var resp=postData(fn.url,fn.user,fn.password,data);return handleResponse(resp);}else{var args=new Array();for(var i=0;i0){var tryIntrospection=false;}else{var tryIntrospection=true;}}else{pass=user;user=methodNames;methodNames=[];var tryIntrospection=true;} +this._url=url;this._user=user;this._password=pass;this._addMethodNames(methodNames);if(tryIntrospection){try{this._introspect();}catch(e){}}} +publ._addMethodNames=function(methodNames){for(var i=0;i"+this.replace(/&/g,"&").replace(/";} +Number.prototype.toXmlRpc=function(){if(this==parseInt(this)){return""+this+"";}else if(this==parseFloat(this)){return""+this+"";}else{return false.toXmlRpc();}} +Boolean.prototype.toXmlRpc=function(){if(this==true){return"1";}else{return"0";}} +Date.prototype.toXmlRpc=function(){var padd=function(s,p){s=p+s +return s.substring(s.length-p.length)} +var y=padd(this.getUTCFullYear(),"0000");var m=padd(this.getUTCMonth()+1,"00");var d=padd(this.getUTCDate(),"00");var h=padd(this.getUTCHours(),"00");var min=padd(this.getUTCMinutes(),"00");var s=padd(this.getUTCSeconds(),"00");var isodate=y+m+d+"T"+h+":"+min+":"+s +return""+isodate+"";} +Array.prototype.toXmlRpc=function(){var retstr="";for(var i=0;i"+mod.marshall(this[i])+"";} +return retstr+"";} +mod.test=function(){print("creating ServiceProxy object using introspection for method construction...\n");var s=new mod.ServiceProxy("http://localhost/testx.py");print("%s created\n".format(s));print("creating and marshalling test data:\n");var o=[1.234,5,{a:"Hello & < ",b:new Date()}];print(mod.marshall(o));print("\ncalling echo() on remote service...\n");var r=s.echo(o);print("service returned data(marshalled again):\n") +print(mod.marshall(r));}}) \ No newline at end of file diff --git a/include/jsolait/missingmixin.js b/include/jsolait/missingmixin.js new file mode 100644 index 00000000..c808eb22 --- /dev/null +++ b/include/jsolait/missingmixin.js @@ -0,0 +1,46 @@ +/* + + Modification information for LGPL compliance + + r56990 - 2010-06-16 13:05:36 -0700 (Wed, 16 Jun 2010) - kjing - snapshot "Mango" svn branch to a new one for GitHub sync + + r56989 - 2010-06-16 13:01:33 -0700 (Wed, 16 Jun 2010) - kjing - defunt "Mango" svn dev branch before github cutover + + r55980 - 2010-04-19 13:31:28 -0700 (Mon, 19 Apr 2010) - kjing - create Mango (6.1) based on windex + + r51719 - 2009-10-22 10:18:00 -0700 (Thu, 22 Oct 2009) - mitani - Converted to Build 3 tags and updated the build system + + r51634 - 2009-10-19 13:32:22 -0700 (Mon, 19 Oct 2009) - mitani - Windex is the branch for Sugar Sales 1.0 development + + r50375 - 2009-08-24 18:07:43 -0700 (Mon, 24 Aug 2009) - dwong - branch kobe2 from tokyo r50372 + + r42807 - 2008-12-29 11:16:59 -0800 (Mon, 29 Dec 2008) - dwong - Branch from trunk/sugarcrm r42806 to branches/tokyo/sugarcrm + + r4085 - 2005-04-13 17:30:42 -0700 (Wed, 13 Apr 2005) - robert - adding meeting scheduler and accept/decline + + + */ +if(Function.prototype.apply==null){Function.prototype.apply=function(thisObj,args){var a=[];for(var i=0;i=0)?n+Math.pow(10,-(d+1)):n-Math.pow(10,-(d+1));n+='';return d==0?n.substring(0,n.indexOf('.')):n.substring(0,n.indexOf('.')+d+1);}} +if(Number.prototype.toExponential==null){Number.prototype.toExponential=function(d){var n=this;var e=0;if(n!=0){e=Math.floor(Math.log(Math.abs(n))/Math.LN10);} +n/=Math.pow(10,e);if(isFinite(d)){if(Math.abs(n)+5*Math.pow(10,-(d+1))>=10.0){n/=10;e+=1;} +n=n.toFixed(d);} +n+="e";if(e>=0){n+="+";} +n+=e;return n;}} \ No newline at end of file diff --git a/include/json_config.php b/include/json_config.php new file mode 100644 index 00000000..2de77169 --- /dev/null +++ b/include/json_config.php @@ -0,0 +1,224 @@ + causes multiple server hits per page load + * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc. + * All Rights Reserved. + * Contributor(s): ______________________________________.. + ********************************************************************************/ + +global $app_strings, $json; +$json = getJSONobj(); + +class json_config { + var $global_registry_var_name = 'GLOBAL_REGISTRY'; + + function get_static_json_server($configOnly = true, $getStrings = false, $module = null, $record = null, $scheduler = false) { + global $current_user; + $str = ''; + $str .= $this->getAppMetaJSON($scheduler); + if(!$configOnly) { + $str .= $this->getFocusData($module, $record); + if($getStrings) $str .= $this->getStringsJSON($module); + } + $str .= $this->getUserConfigJSON(); + + return $str; + } + + function getAppMetaJSON($scheduler = false) { + + global $json, $sugar_config; + + $str = "\nvar ". $this->global_registry_var_name." = new Object();\n"; + $str .= "\n".$this->global_registry_var_name.".config = {\"site_url\":\"".getJavascriptSiteURL()."\"};\n"; + + $str .= $this->global_registry_var_name.".meta = new Object();\n"; + $str .= $this->global_registry_var_name.".meta.modules = new Object();\n"; + + /* + $modules_arr = array('Meetings','Calls'); + $meta_modules = array(); + + global $beanFiles,$beanList; + //header('Content-type: text/xml'); + foreach($modules_arr as $module) { + require_once($beanFiles[$beanList[$module]]); + $focus = new $beanList[$module]; + $meta_modules[$module] = array(); + $meta_modules[$module]['field_defs'] = $focus->field_defs; + } + + $str .= $this->global_registry_var_name.".meta.modules.Meetings = ". $json->encode($meta_modules['Meetings'])."\n"; + $str .= $this->global_registry_var_name.".meta.modules.Calls = ". $json->encode($meta_modules['Calls'])."\n"; + */ + return $str; + } + + function getUserConfigJSON() { + global $timedate; + global $current_user, $sugar_config; + $json = getJSONobj(); + if(isset($_SESSION['authenticated_user_theme']) && $_SESSION['authenticated_user_theme'] != '') { + $theme = $_SESSION['authenticated_user_theme']; + } + else { + $theme = $sugar_config['default_theme']; + } + $user_arr = array(); + $user_arr['theme'] = $theme; + $user_arr['fields'] = array(); + $user_arr['module'] = 'User'; + $user_arr['fields']['id'] = $current_user->id; + $user_arr['fields']['user_name'] = $current_user->user_name; + $user_arr['fields']['first_name'] = $current_user->first_name; + $user_arr['fields']['last_name'] = $current_user->last_name; + $user_arr['fields']['full_name'] = $current_user->full_name; + $user_arr['fields']['email'] = $current_user->email1; + $user_arr['fields']['gmt_offset'] = $timedate->getUserUTCOffset(); + $user_arr['fields']['date_time_format'] = $current_user->getUserDateTimePreferences(); + $str = "\n".$this->global_registry_var_name.".current_user = ".$json->encode($user_arr).";\n"; + return $str; + } + + function getFocusData($module, $record) { + global $json; + if (empty($module)) { + return ''; + } + else if(empty($record)) { + return "\n".$this->global_registry_var_name.'["focus"] = {"module":"'.$module.'",users_arr:[],fields:{"id":"-1"}}'."\n"; + } + + $module_arr = $this->meeting_retrieve($module, $record); + return "\n".$this->global_registry_var_name."['focus'] = ". $json->encode($module_arr).";\n"; + } + + function meeting_retrieve($module, $record) { + global $json, $response; + global $beanFiles, $beanList; + require_once($beanFiles[$beanList[$module]]); + $focus = new $beanList[$module]; + + if(empty($module) || empty($record)) { + return ''; + } + + $focus->retrieve($record); + $module_arr = $this->populateBean($focus); + + if($module == 'Meetings') { + $users = $focus->get_meeting_users(); + } + else if ( $module == 'Calls') { + $users = $focus->get_call_users(); + } + + $module_arr['users_arr'] = array(); + + foreach($users as $user) { + array_push($module_arr['users_arr'], $this->populateBean($user)); + } + + $module_arr['orig_users_arr_hash'] = array(); + + foreach($users as $user) { + $module_arr['orig_users_arr_hash'][$user->id] = '1'; + } + + $module_arr['contacts_arr'] = array(); + + $focus->load_relationships('contacts'); + $contacts=$focus->get_linked_beans('contacts','Contact'); + foreach($contacts as $contact) { + array_push($module_arr['users_arr'], $this->populateBean($contact)); + } + $module_arr['leads_arr'] = array(); + $focus->load_relationships('leads'); + $leads=$focus->get_linked_beans('leads','Lead'); + foreach($leads as $lead) { + array_push($module_arr['users_arr'], $this->populateBean($lead)); + } + + return $module_arr; + } + + function getStringsJSON($module) { + global $current_language; + $currentModule = 'Calendar'; + $mod_list_strings = return_mod_list_strings_language($current_language,$currentModule); + + global $json; + $str = "\n".$this->global_registry_var_name."['calendar_strings'] = {\"dom_cal_month_long\":". $json->encode($mod_list_strings['dom_cal_month_long']).",\"dom_cal_weekdays_long\":". $json->encode($mod_list_strings['dom_cal_weekdays_long'])."}\n"; + if(empty($module)) { + $module = 'Home'; + } + $currentModule = $module; + $mod_strings = return_module_language($current_language,$currentModule); + return $str . "\n".$this->global_registry_var_name."['meeting_strings'] = ". $json->encode($mod_strings)."\n"; + } + + // HAS MEETING SPECIFIC CODE: + function populateBean(&$focus) { + require_once('include/utils/db_utils.php'); + $all_fields = $focus->column_fields; + // MEETING SPECIFIC + $all_fields = array_merge($all_fields,array('required','accept_status','name')); // need name field for contacts and users + //$all_fields = array_merge($focus->column_fields,$focus->additional_column_fields); + + $module_arr = array(); + + $module_arr['module'] = $focus->object_name; + + $module_arr['fields'] = array(); + + foreach($all_fields as $field) { + if(isset($focus->$field) && !is_object($focus->$field)) { + $focus->$field = from_html($focus->$field); + $focus->$field = preg_replace("/\r\n/","
    ",$focus->$field); + $focus->$field = preg_replace("/\n/","
    ",$focus->$field); + $module_arr['fields'][$field] = $focus->$field; + } + } + $GLOBALS['log']->debug("JSON_SERVER:populate bean:"); + return $module_arr; + } + } +?> diff --git a/include/language/en_us.lang.php b/include/language/en_us.lang.php new file mode 100644 index 00000000..9505835e --- /dev/null +++ b/include/language/en_us.lang.php @@ -0,0 +1,2959 @@ +'Contakten', + 'language_pack_name' => 'US English', + 'moduleList' => + array ( + 'Home' => 'Home', + 'Contacts' => 'Contacts', + 'Accounts' => 'Accounts', + 'Opportunities' => 'Opportunities', + 'Cases' => 'Cases', + 'Notes' => 'Notes', + 'Calls' => 'Calls', + 'Emails' => 'Emails', + 'Meetings' => 'Meetings', + 'Tasks' => 'Tasks', + 'Calendar' => 'Calendar', + 'Leads' => 'Leads', + 'Currencies' => 'Currencies', + 'Activities' => 'Activities', + 'Bugs' => 'Bug Tracker', + 'Feeds' => 'RSS', + 'iFrames'=>'My Sites', + 'TimePeriods'=>'Time Periods', + 'TaxRates'=>'Tax Rates', + 'ContractTypes' => 'Contract Types', + 'Schedulers'=>'Schedulers', + 'Project'=>'Projects', + 'ProjectTask'=>'Project Tasks', + 'Campaigns'=>'Campaigns', + 'CampaignLog'=>'Campaign Log', + 'Documents'=>'Documents', + 'DocumentRevisions'=>'Document Revisions', + 'Connectors'=>'Connectors', + 'Roles'=>'Roles', + 'Notifications'=>'Notifications', + 'Sync'=>'Sync', + 'Users' => 'Users', + 'Employees' => 'Employees', + 'Administration' => 'Administration', + 'ACLRoles' => 'Roles', + 'InboundEmail' => 'Inbound Email', + 'Releases' => 'Releases', + 'Prospects' => 'Targets', + 'Queues' => 'Queues', + 'EmailMarketing' => 'Email Marketing', + 'EmailTemplates' => 'Email Templates', + 'ProspectLists' => 'Target Lists', + 'SavedSearch' => 'Saved Searches', + 'UpgradeWizard' => 'Upgrade Wizard', + 'Trackers' => 'Trackers', + 'TrackerPerfs' => 'Tracker Performance', + 'TrackerSessions' => 'Tracker Sessions', + 'TrackerQueries' => 'Tracker Queries', + 'FAQ' => 'FAQ', + 'Newsletters' => 'Newsletters', + 'SugarFeed'=>'Sugar Feed', + 'KBDocuments' => 'Knowledge Base', + 'SugarFavorites'=>'Favorites', + ), + 'moduleListSingular' => + array ( + 'Home' => 'Home', + 'Dashboard' => 'Dashboard', + 'Contacts' => 'Contact', + 'Accounts' => 'Account', + 'Opportunities' => 'Opportunity', + 'Cases' => 'Case', + 'Notes' => 'Note', + 'Calls' => 'Call', + 'Emails' => 'Email', + 'Meetings' => 'Meeting', + 'Tasks' => 'Task', + 'Calendar' => 'Calendar', + 'Leads' => 'Lead', + 'Activities' => 'Activity', + 'Bugs' => 'Bug Tracker', + 'Feeds' => 'RSS', + 'iFrames'=>'My Sites', + 'TimePeriods'=>'Time Period', + 'Project'=>'Projects', + 'ProjectTask'=>'Project Task', + 'Campaigns'=>'Campaign', + 'Documents'=>'Document', + 'SugarFollowing'=>'SugarFollowing', + 'Sync'=>'Sync', + 'Users' => 'User', + 'SugarFavorites'=>'SugarFavorites' + + ), + + 'checkbox_dom'=> array( + ''=>'', + '1'=>'Yes', + '2'=>'No', + ), + + //e.g. en fran�ais 'Analyst'=>'Analyste', + 'account_type_dom' => + array ( + '' => '', + 'Analyst' => 'Analyst', + 'Competitor' => 'Competitor', + 'Customer' => 'Customer', + 'Integrator' => 'Integrator', + 'Investor' => 'Investor', + 'Partner' => 'Partner', + 'Press' => 'Press', + 'Prospect' => 'Prospect', + 'Reseller' => 'Reseller', + 'Other' => 'Other', + ), + //e.g. en espa�ol 'Apparel'=>'Ropa', + 'industry_dom' => + array ( + '' => '', + 'Apparel' => 'Apparel', + 'Banking' => 'Banking', + 'Biotechnology' => 'Biotechnology', + 'Chemicals' => 'Chemicals', + 'Communications' => 'Communications', + 'Construction' => 'Construction', + 'Consulting' => 'Consulting', + 'Education' => 'Education', + 'Electronics' => 'Electronics', + 'Energy' => 'Energy', + 'Engineering' => 'Engineering', + 'Entertainment' => 'Entertainment', + 'Environmental' => 'Environmental', + 'Finance' => 'Finance', + 'Government' => 'Government', + 'Healthcare' => 'Healthcare', + 'Hospitality' => 'Hospitality', + 'Insurance' => 'Insurance', + 'Machinery' => 'Machinery', + 'Manufacturing' => 'Manufacturing', + 'Media' => 'Media', + 'Not For Profit' => 'Not For Profit', + 'Recreation' => 'Recreation', + 'Retail' => 'Retail', + 'Shipping' => 'Shipping', + 'Technology' => 'Technology', + 'Telecommunications' => 'Telecommunications', + 'Transportation' => 'Transportation', + 'Utilities' => 'Utilities', + 'Other' => 'Other', + ), + 'lead_source_default_key' => 'Self Generated', + 'lead_source_dom' => + array ( + '' => '', + 'Cold Call' => 'Cold Call', + 'Existing Customer' => 'Existing Customer', + 'Self Generated' => 'Self Generated', + 'Employee' => 'Employee', + 'Partner' => 'Partner', + 'Public Relations' => 'Public Relations', + 'Direct Mail' => 'Direct Mail', + 'Conference' => 'Conference', + 'Trade Show' => 'Trade Show', + 'Web Site' => 'Web Site', + 'Word of mouth' => 'Word of mouth', + 'Email' => 'Email', + 'Campaign'=>'Campaign', + 'Other' => 'Other', + ), + 'opportunity_type_dom' => + array ( + '' => '', + 'Existing Business' => 'Existing Business', + 'New Business' => 'New Business', + ), + 'roi_type_dom' => + array ( + 'Revenue' => 'Revenue', + 'Investment'=>'Investment', + 'Expected_Revenue'=>'Expected Revenue', + 'Budget'=>'Budget', + + ), + //Note: do not translate opportunity_relationship_type_default_key +// it is the key for the default opportunity_relationship_type_dom value + 'opportunity_relationship_type_default_key' => 'Primary Decision Maker', + 'opportunity_relationship_type_dom' => + array ( + '' => '', + 'Primary Decision Maker' => 'Primary Decision Maker', + 'Business Decision Maker' => 'Business Decision Maker', + 'Business Evaluator' => 'Business Evaluator', + 'Technical Decision Maker' => 'Technical Decision Maker', + 'Technical Evaluator' => 'Technical Evaluator', + 'Executive Sponsor' => 'Executive Sponsor', + 'Influencer' => 'Influencer', + 'Other' => 'Other', + ), + //Note: do not translate case_relationship_type_default_key +// it is the key for the default case_relationship_type_dom value + 'case_relationship_type_default_key' => 'Primary Contact', + 'case_relationship_type_dom' => + array ( + '' => '', + 'Primary Contact' => 'Primary Contact', + 'Alternate Contact' => 'Alternate Contact', + ), + 'payment_terms' => + array ( + '' => '', + 'Net 15' => 'Net 15', + 'Net 30' => 'Net 30', + ), + 'sales_stage_default_key' => 'Prospecting', + 'sales_stage_dom' => + array ( + 'Prospecting' => 'Prospecting', + 'Qualification' => 'Qualification', + 'Needs Analysis' => 'Needs Analysis', + 'Value Proposition' => 'Value Proposition', + 'Id. Decision Makers' => 'Id. Decision Makers', + 'Perception Analysis' => 'Perception Analysis', + 'Proposal/Price Quote' => 'Proposal/Price Quote', + 'Negotiation/Review' => 'Negotiation/Review', + 'Closed Won' => 'Closed Won', + 'Closed Lost' => 'Closed Lost', + ), + 'in_total_group_stages' => array ( + 'Draft' => 'Draft', + 'Negotiation' => 'Negotiation', + 'Delivered' => 'Delivered', + 'On Hold' => 'On Hold', + 'Confirmed' => 'Confirmed', + 'Closed Accepted' => 'Closed Accepted', + 'Closed Lost' => 'Closed Lost', + 'Closed Dead' => 'Closed Dead', + ), + 'sales_probability_dom' => // keys must be the same as sales_stage_dom + array ( + 'Prospecting' => '10', + 'Qualification' => '20', + 'Needs Analysis' => '25', + 'Value Proposition' => '30', + 'Id. Decision Makers' => '40', + 'Perception Analysis' => '50', + 'Proposal/Price Quote' => '65', + 'Negotiation/Review' => '80', + 'Closed Won' => '100', + 'Closed Lost' => '0', + ), + 'activity_dom' => + array ( + 'Call' => 'Call', + 'Meeting' => 'Meeting', + 'Task' => 'Task', + 'Email' => 'Email', + 'Note' => 'Note', + ), + 'salutation_dom' => + array ( + '' => '', + 'Mr.' => 'Mr.', + 'Ms.' => 'Ms.', + 'Mrs.' => 'Mrs.', + 'Dr.' => 'Dr.', + 'Prof.' => 'Prof.', + ), + //time is in seconds; the greater the time the longer it takes; + 'reminder_max_time'=>3600, + 'reminder_time_options' => array( 60=> '1 minute prior', + 300=> '5 minutes prior', + 600=> '10 minutes prior', + 900=> '15 minutes prior', + 1800=> '30 minutes prior', + 3600=> '1 hour prior', + ), + + 'task_priority_default' => 'Medium', + 'task_priority_dom' => + array ( + 'High' => 'High', + 'Medium' => 'Medium', + 'Low' => 'Low', + ), + 'task_status_default' => 'Not Started', + 'task_status_dom' => + array ( + 'Not Started' => 'Not Started', + 'In Progress' => 'In Progress', + 'Completed' => 'Completed', + 'Pending Input' => 'Pending Input', + 'Deferred' => 'Deferred', + ), + 'meeting_status_default' => 'Planned', + 'meeting_status_dom' => + array ( + 'Planned' => 'Planned', + 'Held' => 'Held', + 'Not Held' => 'Not Held', + ), + 'extapi_meeting_password' => + array ( + 'WebEx' => 'WebEx', + ), + 'meeting_type_dom' => + array ( + 'Other' => 'Other', + 'SugarCRM' => 'SugarCRM', + ), + 'call_status_default' => 'Planned', + 'call_status_dom' => + array ( + 'Planned' => 'Planned', + 'Held' => 'Held', + 'Not Held' => 'Not Held', + ), + 'call_direction_default' => 'Outbound', + 'call_direction_dom' => + array ( + 'Inbound' => 'Inbound', + 'Outbound' => 'Outbound', + ), + 'lead_status_dom' => + array ( + '' => '', + 'New' => 'New', + 'Assigned' => 'Assigned', + 'In Process' => 'In Process', + 'Converted' => 'Converted', + 'Recycled' => 'Recycled', + 'Dead' => 'Dead', + ), + 'gender_list' => + array ( + 'male' => 'Male', + 'female' => 'Female', + ), + //Note: do not translate case_status_default_key +// it is the key for the default case_status_dom value + 'case_status_default_key' => 'New', + 'case_status_dom' => + array ( + 'New' => 'New', + 'Assigned' => 'Assigned', + 'Closed' => 'Closed', + 'Pending Input' => 'Pending Input', + 'Rejected' => 'Rejected', + 'Duplicate' => 'Duplicate', + ), + 'case_priority_default_key' => 'P2', + 'case_priority_dom' => + array ( + 'P1' => 'High', + 'P2' => 'Medium', + 'P3' => 'Low', + ), + 'user_status_dom' => + array ( + 'Active' => 'Active', + 'Inactive' => 'Inactive', + ), + 'employee_status_dom' => + array ( + 'Active' => 'Active', + 'Terminated' => 'Terminated', + 'Leave of Absence' => 'Leave of Absence', + ), + 'messenger_type_dom' => + array ( + '' => '', + 'MSN' => 'MSN', + 'Yahoo!' => 'Yahoo!', + 'AOL' => 'AOL', + ), + 'project_task_priority_options' => array ( + 'High' => 'High', + 'Medium' => 'Medium', + 'Low' => 'Low', + ), + 'project_task_priority_default' => 'Medium', + + 'project_task_status_options' => array ( + 'Not Started' => 'Not Started', + 'In Progress' => 'In Progress', + 'Completed' => 'Completed', + 'Pending Input' => 'Pending Input', + 'Deferred' => 'Deferred', + ), + 'project_task_utilization_options' => array ( + '0' => 'none', + '25' => '25', + '50' => '50', + '75' => '75', + '100' => '100', + ), + + 'project_status_dom' => array ( + 'Draft' => 'Draft', + 'In Review' => 'In Review', + 'Published' => 'Published', + ), + 'project_status_default' => 'Draft', + + 'project_duration_units_dom' => array ( + 'Days' => 'Days', + 'Hours' => 'Hours', + ), + + 'project_priority_options' => array ( + 'High' => 'High', + 'Medium' => 'Medium', + 'Low' => 'Low', + ), + 'project_priority_default' => 'Medium', + //Note: do not translate record_type_default_key +// it is the key for the default record_type_module value + 'record_type_default_key' => 'Accounts', + 'record_type_display' => + array ( + '' => '', + 'Accounts' => 'Account', + 'Opportunities' => 'Opportunity', + 'Cases' => 'Case', + 'Leads' => 'Lead', + 'Contacts' => 'Contacts', // cn (11/22/2005) added to support Emails + + + 'Bugs' => 'Bug', + 'Project' => 'Project', + + 'Prospects' => 'Target', + 'ProjectTask' => 'Project Task', + + + 'Tasks' => 'Task', + + ), + + 'record_type_display_notes' => + array ( + 'Accounts' => 'Account', + 'Contacts' => 'Contact', + 'Opportunities' => 'Opportunity', + 'Tasks' => 'Task', + 'Emails' => 'Email', + + 'Bugs' => 'Bug', + 'Project' => 'Project', + 'ProjectTask' => 'Project Task', + 'Prospects' => 'Target', + 'Cases' => 'Case', + 'Leads' => 'Lead', + + 'Meetings' => 'Meeting', + 'Calls' => 'Call', + ), + + 'parent_type_display' => + array ( + 'Accounts' => 'Account', + 'Contacts' => 'Contact', + 'Tasks' => 'Task', + 'Opportunities' => 'Opportunity', + + + + 'Bugs' => 'Bug Tracker', + 'Cases' => 'Case', + 'Leads' => 'Lead', + + 'Project' => 'Project', + 'ProjectTask' => 'Project Task', + + 'Prospects' => 'Target', + + ), + + 'issue_priority_default_key' => 'Medium', + 'issue_priority_dom' => + array ( + 'Urgent' => 'Urgent', + 'High' => 'High', + 'Medium' => 'Medium', + 'Low' => 'Low', + ), + 'issue_resolution_default_key' => '', + 'issue_resolution_dom' => + array ( + '' => '', + 'Accepted' => 'Accepted', + 'Duplicate' => 'Duplicate', + 'Closed' => 'Closed', + 'Out of Date' => 'Out of Date', + 'Invalid' => 'Invalid', + ), + + 'issue_status_default_key' => 'New', + 'issue_status_dom' => + array ( + 'New' => 'New', + 'Assigned' => 'Assigned', + 'Closed' => 'Closed', + 'Pending' => 'Pending', + 'Rejected' => 'Rejected', + ), + + 'bug_priority_default_key' => 'Medium', + 'bug_priority_dom' => + array ( + 'Urgent' => 'Urgent', + 'High' => 'High', + 'Medium' => 'Medium', + 'Low' => 'Low', + ), + 'bug_resolution_default_key' => '', + 'bug_resolution_dom' => + array ( + '' => '', + 'Accepted' => 'Accepted', + 'Duplicate' => 'Duplicate', + 'Fixed' => 'Fixed', + 'Out of Date' => 'Out of Date', + 'Invalid' => 'Invalid', + 'Later' => 'Later', + ), + 'bug_status_default_key' => 'New', + 'bug_status_dom' => + array ( + 'New' => 'New', + 'Assigned' => 'Assigned', + 'Closed' => 'Closed', + 'Pending' => 'Pending', + 'Rejected' => 'Rejected', + ), + 'bug_type_default_key' => 'Bug', + 'bug_type_dom' => + array ( + 'Defect' => 'Defect', + 'Feature' => 'Feature', + ), + 'case_type_dom' => + array ( + 'Administration' => 'Administration', + 'Product' => 'Product', + 'User' => 'User', + ), + + 'source_default_key' => '', + 'source_dom' => + array ( + '' => '', + 'Internal' => 'Internal', + 'Forum' => 'Forum', + 'Web' => 'Web', + 'InboundEmail' => 'Email' + ), + + 'product_category_default_key' => '', + 'product_category_dom' => + array ( + '' => '', + 'Accounts' => 'Accounts', + 'Activities' => 'Activities', + 'Bug Tracker' => 'Bug Tracker', + 'Calendar' => 'Calendar', + 'Calls' => 'Calls', + 'Campaigns' => 'Campaigns', + 'Cases' => 'Cases', + 'Contacts' => 'Contacts', + 'Currencies' => 'Currencies', + 'Dashboard' => 'Dashboard', + 'Documents' => 'Documents', + 'Emails' => 'Emails', + 'Feeds' => 'Feeds', + 'Forecasts' => 'Forecasts', + 'Help' => 'Help', + 'Home' => 'Home', + 'Leads' => 'Leads', + 'Meetings' => 'Meetings', + 'Notes' => 'Notes', + 'Opportunities' => 'Opportunities', + 'Outlook Plugin' => 'Outlook Plugin', + 'Projects' => 'Projects', + 'Quotes' => 'Quotes', + 'Releases' => 'Releases', + 'RSS' => 'RSS', + 'Studio' => 'Studio', + 'Upgrade' => 'Upgrade', + 'Users' => 'Users', + ), + /*Added entries 'Queued' and 'Sending' for 4.0 release..*/ + 'campaign_status_dom' => + array ( + '' => '', + 'Planning' => 'Planning', + 'Active' => 'Active', + 'Inactive' => 'Inactive', + 'Complete' => 'Complete', + 'In Queue' => 'In Queue', + 'Sending'=> 'Sending', + ), + 'campaign_type_dom' => + array ( + '' => '', + 'Telesales' => 'Telesales', + 'Mail' => 'Mail', + 'Email' => 'Email', + 'Print' => 'Print', + 'Web' => 'Web', + 'Radio' => 'Radio', + 'Television' => 'Television', + 'NewsLetter' => 'Newsletter', + ), + + 'newsletter_frequency_dom' => + array ( + '' => '', + 'Weekly' => 'Weekly', + 'Monthly' => 'Monthly', + 'Quarterly' => 'Quarterly', + 'Annually' => 'Annually', + ), + + 'notifymail_sendtype' => + array ( + 'SMTP' => 'SMTP', + ), + 'dom_cal_month_long'=>array( + '0'=>"", + '1'=>"January", + '2'=>"February", + '3'=>"March", + '4'=>"April", + '5'=>"May", + '6'=>"June", + '7'=>"July", + '8'=>"August", + '9'=>"September", + '10'=>"October", + '11'=>"November", + '12'=>"December", + ), + 'dom_cal_month_short'=>array( + '0'=>"", + '1'=>"Jan", + '2'=>"Feb", + '3'=>"Mar", + '4'=>"Apr", + '5'=>"May", + '6'=>"Jun", + '7'=>"Jul", + '8'=>"Aug", + '9'=>"Sep", + '10'=>"Oct", + '11'=>"Nov", + '12'=>"Dec", + ), + 'dom_cal_day_long'=>array( + '0'=>"", + '1'=>"Sunday", + '2'=>"Monday", + '3'=>"Tuesday", + '4'=>"Wednesday", + '5'=>"Thursday", + '6'=>"Friday", + '7'=>"Saturday", + ), + 'dom_cal_day_short'=>array( + '0'=>"", + '1'=>"Sun", + '2'=>"Mon", + '3'=>"Tue", + '4'=>"Wed", + '5'=>"Thu", + '6'=>"Fri", + '7'=>"Sat", + ), + 'dom_meridiem_lowercase'=>array( + 'am'=>"am", + 'pm'=>"pm" + ), + 'dom_meridiem_uppercase'=>array( + 'AM'=>'AM', + 'PM'=>'PM' + ), + + 'dom_report_types'=>array( + 'tabular'=>'Rows and Columns', + 'summary'=>'Summation', + 'detailed_summary'=>'Summation with details', + 'Matrix' => 'Matrix', + ), + + + 'dom_email_types'=> array( + 'out' => 'Sent', + 'archived' => 'Archived', + 'draft' => 'Draft', + 'inbound' => 'Inbound', + 'campaign' => 'Campaign' + ), + 'dom_email_status' => array ( + 'archived' => 'Archived', + 'closed' => 'Closed', + 'draft' => 'In Draft', + 'read' => 'Read', + 'replied' => 'Replied', + 'sent' => 'Sent', + 'send_error'=> 'Send Error', + 'unread' => 'Unread', + ), + 'dom_email_archived_status' => array ( + 'archived' => 'Archived', + ), + + 'dom_email_server_type' => array( '' => '--None--', + 'imap' => 'IMAP', + ), + 'dom_mailbox_type' => array(/*'' => '--None Specified--',*/ + 'pick' => '--None--', + 'createcase' => 'Create Case', + 'bounce' => 'Bounce Handling', + ), + 'dom_email_distribution'=> array('' => '--None--', + 'direct' => 'Direct Assign', + 'roundRobin' => 'Round-Robin', + 'leastBusy' => 'Least-Busy', + ), + 'dom_email_distribution_for_auto_create'=> array('roundRobin' => 'Round-Robin', + 'leastBusy' => 'Least-Busy', + ), + 'dom_email_errors' => array(1 => 'Only select one user when Direct Assigning items.', + 2 => 'You must assign Only Checked Items when Direct Assigning items.', + ), + 'dom_email_bool' => array('bool_true' => 'Yes', + 'bool_false' => 'No', + ), + 'dom_int_bool' => array(1 => 'Yes', + 0 => 'No', + ), + 'dom_switch_bool' => array ('on' => 'Yes', + 'off' => 'No', + '' => 'No', ), + + 'dom_email_link_type' => array( 'sugar' => 'Sugar Email Client', + 'mailto' => 'External Email Client'), + + + 'dom_email_editor_option'=> array( '' => 'Default Email Format', + 'html' => 'HTML Email', + 'plain' => 'Plain Text Email'), + + 'schedulers_times_dom' => array( 'not run' => 'Past Run Time, Not Executed', + 'ready' => 'Ready', + 'in progress' => 'In Progress', + 'failed' => 'Failed', + 'completed' => 'Completed', + 'no curl' => 'Not Run: No cURL available', + ), + + 'scheduler_status_dom' => + array ( + 'Active' => 'Active', + 'Inactive' => 'Inactive', + ), + + 'scheduler_period_dom' => + array ( + 'min' => 'Minutes', + 'hour' => 'Hours', + ), + 'forecast_schedule_status_dom' => + array ( + 'Active' => 'Active', + 'Inactive' => 'Inactive', + ), + 'forecast_type_dom' => + array ( + 'Direct' => 'Direct', + 'Rollup' => 'Rollup', + ), + 'document_category_dom' => + array ( + '' => '', + 'Marketing' => 'Marketing', + 'Knowledege Base' => 'Knowledge Base', + 'Sales' => 'Sales', + ), + + 'document_subcategory_dom' => + array ( + '' => '', + 'Marketing Collateral' => 'Marketing Collateral', + 'Product Brochures' => 'Product Brochures', + 'FAQ' => 'FAQ', + ), + + 'document_status_dom' => + array ( + 'Active' => 'Active', + 'Draft' => 'Draft', + 'FAQ' => 'FAQ', + 'Expired' => 'Expired', + 'Under Review' => 'Under Review', + 'Pending' => 'Pending', + ), + 'document_template_type_dom' => + array( + ''=>'', + 'mailmerge'=>'Mail Merge', + 'eula'=>'EULA', + 'nda'=>'NDA', + 'license'=>'License Agreement', + ), + 'dom_meeting_accept_options' => + array ( + 'accept' => 'Accept', + 'decline' => 'Decline', + 'tentative' => 'Tentative', + ), + 'dom_meeting_accept_status' => + array ( + 'accept' => 'Accepted', + 'decline' => 'Declined', + 'tentative' => 'Tentative', + 'none' => 'None', + ), + 'duration_intervals' => array('0'=>'00', + '15'=>'15', + '30'=>'30', + '45'=>'45'), + + +// deferred +/*// QUEUES MODULE DOMs +'queue_type_dom' => array( + 'Users' => 'Users', + 'Mailbox' => 'Mailbox', +), +*/ +//prospect list type dom + 'prospect_list_type_dom' => + array ( + 'default' => 'Default', + 'seed' => 'Seed', + 'exempt_domain' => 'Suppression List - By Domain', + 'exempt_address' => 'Suppression List - By Email Address', + 'exempt' => 'Suppression List - By Id', + 'test' => 'Test', + ), + + 'email_settings_num_dom' => + array( + '10' => '10', + '20' => '20', + '50' => '50' + ), + 'email_marketing_status_dom' => + array ( + '' => '', + 'active'=>'Active', + 'inactive'=>'Inactive' + ), + + 'campainglog_activity_type_dom' => + array ( + ''=>'', + 'targeted' => 'Message Sent/Attempted', + 'send error'=>'Bounced Messages,Other', + 'invalid email'=>'Bounced Messages,Invalid Email', + 'link'=>'Click-thru Link', + 'viewed'=>'Viewed Message', + 'removed'=>'Opted Out', + 'lead'=>'Leads Created', + 'contact'=>'Contacts Created', + 'blocked'=>'Suppressed by address or domain', + ), + + 'campainglog_target_type_dom' => + array ( + 'Contacts' => 'Contacts', + 'Users'=>'Users', + 'Prospects'=>'Targets', + 'Leads'=>'Leads', + 'Accounts'=>'Accounts', + ), + 'merge_operators_dom' => array ( + 'like'=>'Contains', + 'exact'=>'Exactly', + 'start'=>'Starts With', + ), + + 'custom_fields_importable_dom' => array ( + 'true'=>'Yes', + 'false'=>'No', + 'required'=>'Required', + ), + + 'custom_fields_merge_dup_dom'=> array ( + 0=>'Disabled', + 1=>'Enabled', + ), + + 'navigation_paradigms' => array( + 'm'=>'Modules', + 'gm'=>'Grouped Modules', + ), + + + 'projects_priority_options' => array ( + 'high' => 'High', + 'medium' => 'Medium', + 'low' => 'Low', + ), + + 'projects_status_options' => array ( + 'notstarted' => 'Not Started', + 'inprogress' => 'In Progress', + 'completed' => 'Completed', + ), + // strings to pass to Flash charts + 'chart_strings' => array ( + 'expandlegend' => 'Expand Legend', + 'collapselegend' => 'Collapse Legend', + 'clickfordrilldown' => 'Click for Drilldown', + 'drilldownoptions' => 'Drill Down Options', + 'detailview' => 'More Details...', + 'piechart' => 'Pie Chart', + 'groupchart' => 'Group Chart', + 'stackedchart' => 'Stacked Chart', + 'barchart' => 'Bar Chart', + 'horizontalbarchart' => 'Horizontal Bar Chart', + 'linechart' => 'Line Chart', + 'noData' => 'Data not available', + 'print' => 'Print', + 'pieWedgeName' => 'sections', + ), + 'release_status_dom' => + array ( + 'Active' => 'Active', + 'Inactive' => 'Inactive', + ), + 'email_settings_for_ssl' => + array ( + '0' => '', + '1' => 'SSL', + '2' => 'TLS', + ), + 'link_target_dom' => + array ( + '_blank' => 'New Window', + '_self' => 'Same Window', + ), + 'dashlet_auto_refresh_options' => + array ( + '-1' => 'Do not auto-refresh', + '30' => 'Every 30 seconds', + '60' => 'Every 1 minute', + '180' => 'Every 3 minutes', + '300' => 'Every 5 minutes', + '600' => 'Every 10 minutes', + ), + 'dashlet_auto_refresh_options_admin' => + array ( + '-1' => 'Never', + '30' => 'Every 30 seconds', + '60' => 'Every 1 minute', + '180' => 'Every 3 minutes', + '300' => 'Every 5 minutes', + '600' => 'Every 10 minutes', + ), + 'date_range_search_dom' => + array( + '=' => 'Equals', + 'not_equal' => 'Not On', + 'greater_than' => 'After', + 'less_than' => 'Before', + 'last_7_days' => 'Last 7 Days', + 'next_7_days' => 'Next 7 Days', + 'last_30_days' => 'Last 30 Days', + 'next_30_days' => 'Next 30 Days', + 'last_month' => 'Last Month', + 'this_month' => 'This Month', + 'next_month' => 'Next Month', + 'last_year' => 'Last Year', + 'this_year' => 'This Year', + 'next_year' => 'Next Year', + 'between' => 'Is Between', + ), + 'numeric_range_search_dom' => + array( + '=' => 'Equals', + 'not_equal' => 'Does Not Equal', + 'greater_than' => 'Greater Than', + 'greater_than_equals' => 'Greater Than Or Equal To', + 'less_than' => 'Less Than', + 'less_than_equals' => 'Less Than Or Equal To', + 'between' => 'Is Between', + ), +); + +$app_strings = array ( + 'DEFAULT' => 'Basic', + 'LBL_SORT' => 'Sort', + 'LBL_OUTBOUND_EMAIL_ADD_SERVER' => 'Add Server...', + 'LBL_EMAIL_SMTP_SSL_OR_TLS' => 'Enable SMTP over SSL or TLS?', + 'LBL_NO_ACTION' => 'There is no action by that name.', + 'LBL_NO_DATA' => 'No Data', + 'LBL_ROUTING_ADD_RULE' => 'Add Rule', + 'LBL_ROUTING_ALL' => 'At Least', + 'LBL_ROUTING_ANY' => 'Any', + 'LBL_ROUTING_BREAK' => '-', + 'LBL_ROUTING_BUTTON_CANCEL' => 'Cancel', + 'LBL_ROUTING_BUTTON_SAVE' => 'Save Rule', + + 'LBL_ROUTING_ACTIONS_COPY_MAIL' => 'Copy Mail', + 'LBL_ROUTING_ACTIONS_DELETE_BEAN' => 'Delete Sugar Object', + 'LBL_ROUTING_ACTIONS_DELETE_FILE' => 'Delete File', + 'LBL_ROUTING_ACTIONS_DELETE_MAIL' => 'Delete Email', + 'LBL_ROUTING_ACTIONS_FORWARD' => 'Forward Email', + 'LBL_ROUTING_ACTIONS_MARK_FLAGGED' => 'Flag Email', + 'LBL_ROUTING_ACTIONS_MARK_READ' => 'Mark Read', + 'LBL_ROUTING_ACTIONS_MARK_UNREAD' => 'Mark Unread', + 'LBL_ROUTING_ACTIONS_MOVE_MAIL' => 'Move Email', + 'LBL_ROUTING_ACTIONS_PEFORM' => 'Perform the following actions', + 'LBL_ROUTING_ACTIONS_REPLY' => 'Reply to Email', + + 'LBL_ROUTING_CHECK_RULE' => "An error was detected:\n", + 'LBL_ROUTING_CHECK_RULE_DESC' => 'Please verify all fields that are marked.', + 'LBL_ROUTING_CONFIRM_DELETE' => "Are you sure you want to delete this rule?\nThis cannot be undone.", + + 'LBL_ROUTING_FLAGGED' => 'flag set', + 'LBL_ROUTING_FORM_DESC' => 'Saved Rules are immediately active.', + 'LBL_ROUTING_FW' => 'FW: ', + 'LBL_ROUTING_LIST_TITLE' => 'Rules', + 'LBL_ROUTING_MATCH' => 'If', + 'LBL_ROUTING_MATCH_2' => 'of the following conditions are met:', + 'LBL_NOTIFICATIONS' => 'Notifications', + 'LBL_ROUTING_MATCH_CC_ADDR' => 'CC', + 'LBL_ROUTING_MATCH_DESCRIPTION' => 'Body Content', + 'LBL_ROUTING_MATCH_FROM_ADDR' => 'From', + 'LBL_ROUTING_MATCH_NAME' => 'Subject', + 'LBL_ROUTING_MATCH_PRIORITY_HIGH' => 'High Priority', + 'LBL_ROUTING_MATCH_PRIORITY_NORMAL' => 'Normal Priority', + 'LBL_ROUTING_MATCH_PRIORITY_LOW' => 'Low Priority', + 'LBL_ROUTING_MATCH_TO_ADDR' => 'To', + 'LBL_ROUTING_MATCH_TYPE_MATCH' => 'Contains', + 'LBL_ROUTING_MATCH_TYPE_NOT_MATCH' => 'Does not contain', + + 'LBL_ROUTING_NAME' => 'Rule Name', + 'LBL_ROUTING_NEW_NAME' => 'New Rule', + 'LBL_ROUTING_ONE_MOMENT' => 'One moment please...', + 'LBL_ROUTING_ORIGINAL_MESSAGE_FOLLOWS' => 'Original message follows.', + 'LBL_ROUTING_RE' => 'RE: ', + 'LBL_ROUTING_SAVING_RULE' => 'Saving Rule', + 'LBL_ROUTING_SUB_DESC' => 'Checked rules are active. Click name to edit.', + 'LBL_ROUTING_TO' => 'to', + 'LBL_ROUTING_TO_ADDRESS' => 'to address', + 'LBL_ROUTING_WITH_TEMPLATE' => 'with template', + 'NTC_OVERWRITE_ADDRESS_PHONE_CONFIRM' => 'This record currently contains values in the Office Phone and Address fields. To overwrite these values with the following Office Phone and Address of the Account that you selected, click "OK". To keep the current values, click "Cancel".', + 'LBL_DROP_HERE' => '[Drop Here]', + 'LBL_EMAIL_ACCOUNTS_EDIT' => 'Edit', + 'LBL_EMAIL_ACCOUNTS_GMAIL_DEFAULTS' => 'Prefill Gmail™ Defaults', + 'LBL_EMAIL_ACCOUNTS_NAME' => 'Name', + 'LBL_EMAIL_ACCOUNTS_OUTBOUND' => 'Outgoing Mail Server Properties', + 'LBL_EMAIL_ACCOUNTS_SENDTYPE' => 'Mail transfer agent', + 'LBL_EMAIL_ACCOUNTS_SMTPAUTH_REQ' => 'Use SMTP Authentication?', + 'LBL_EMAIL_ACCOUNTS_SMTPPASS' => 'SMTP Password', + 'LBL_EMAIL_ACCOUNTS_SMTPPORT' => 'SMTP Port', + 'LBL_EMAIL_ACCOUNTS_SMTPSERVER' => 'SMTP Server', + 'LBL_EMAIL_ACCOUNTS_SMTPSSL' => 'Use SSL when connecting', + 'LBL_EMAIL_ACCOUNTS_SMTPUSER' => 'SMTP Username', + 'LBL_EMAIL_ACCOUNTS_SMTPDEFAULT' => 'Default', + 'LBL_EMAIL_WARNING_MISSING_USER_CREDS' => 'Warning: Missing username and password for outgoing mail account.', + 'LBL_EMAIL_ACCOUNTS_SMTPUSER_REQD' => 'SMTP Username is required', + 'LBL_EMAIL_ACCOUNTS_SMTPPASS_REQD' => 'SMTP Password is required', + 'LBL_EMAIL_ACCOUNTS_TITLE' => 'Mail Account Management', + 'LBL_EMAIL_POP3_REMOVE_MESSAGE' => 'Mail Server Protocol of type POP3 will not be supported in the next release. Only IMAP will be supported.', + 'LBL_EMAIL_ACCOUNTS_SUBTITLE' => 'Set up Mail Accounts to view incoming emails from your email accounts.', + 'LBL_EMAIL_ACCOUNTS_OUTBOUND_SUBTITLE' => 'Provide SMTP mail server information to use for outgoing email in Mail Accounts.', + 'LBL_EMAIL_ADD' => 'Add Address', + + 'LBL_EMAIL_ADDRESS_BOOK_ADD' => 'Done', + 'LBL_EMAIL_ADDRESS_BOOK_CLEAR' => 'Clear', + 'LBL_EMAIL_ADDRESS_BOOK_ADD_TO' => 'To:', + 'LBL_EMAIL_ADDRESS_BOOK_ADD_CC' => 'Cc:', + 'LBL_EMAIL_ADDRESS_BOOK_ADD_BCC' => 'Bcc:', + 'LBL_EMAIL_ADDRESS_BOOK_ADRRESS_TYPE' => 'To/Cc/Bcc', + 'LBL_EMAIL_ADDRESS_BOOK_ADD_LIST' => 'New List', + 'LBL_EMAIL_ADDRESS_BOOK_EMAIL_ADDR' => 'Email Address', + 'LBL_EMAIL_ADDRESS_BOOK_ERR_NOT_CONTACT'=> 'Only Contact editting is supported at this time.', + 'LBL_EMAIL_ADDRESS_BOOK_FILTER' => 'Filter', + 'LBL_EMAIL_ADDRESS_BOOK_FIRST_NAME' => 'First Name/Account Name', + 'LBL_EMAIL_ADDRESS_BOOK_LAST_NAME' => 'Last Name', + 'LBL_EMAIL_ADDRESS_BOOK_MY_CONTACTS' => 'My Contacts', + 'LBL_EMAIL_ADDRESS_BOOK_MY_LISTS' => 'My Mailing Lists', + 'LBL_EMAIL_ADDRESS_BOOK_NAME' => 'Name', + 'LBL_EMAIL_ADDRESS_BOOK_NOT_FOUND' => 'No Addresses Found', + 'LBL_EMAIL_ADDRESS_BOOK_SAVE_AND_ADD' => 'Save & Add to Address Book', + 'LBL_EMAIL_ADDRESS_BOOK_SEARCH' => 'Search', + 'LBL_EMAIL_ADDRESS_BOOK_SELECT_TITLE' => 'Select Email Recipients', + 'LBL_EMAIL_ADDRESS_BOOK_TITLE' => 'Address Book', + 'LBL_EMAIL_REPORTS_TITLE' => 'Reports', + 'LBL_EMAIL_ADDRESS_BOOK_TITLE_ICON' => ' Address Book', + 'LBL_EMAIL_ADDRESS_BOOK_TITLE_ICON_SHORT' => '', + 'LBL_EMAIL_REMOVE_SMTP_WARNING' => 'Warning! The outbound account you are trying to delete is associated to an existing inbound account. Are you sure you want to continue?', + 'LBL_EMAIL_ADDRESSES' => 'Email', + 'LBL_EMAIL_ADDRESS_PRIMARY' => 'Email Address', + 'LBL_EMAIL_ADDRESSES_TITLE' => 'Email Addresses', + 'LBL_EMAIL_ARCHIVE_TO_SUGAR' => 'Import to Sugar', + 'LBL_EMAIL_ASSIGNMENT' => 'Assignment', + 'LBL_EMAIL_ATTACH_FILE_TO_EMAIL' => 'Attach', + 'LBL_EMAIL_ATTACHMENT' => 'Attach', + 'LBL_EMAIL_ATTACHMENTS' => 'From Local System', + 'LBL_EMAIL_ATTACHMENTS2' => 'From Sugar Documents', + 'LBL_EMAIL_ATTACHMENTS3' => 'Template Attachments', + 'LBL_EMAIL_ATTACHMENTS_FILE' => 'File', + 'LBL_EMAIL_ATTACHMENTS_DOCUMENT' => 'Document', + 'LBL_EMAIL_ATTACHMENTS_EMBEDED' => 'Embeded', + 'LBL_EMAIL_BCC' => 'BCC', + 'LBL_EMAIL_CANCEL' => 'Cancel', + 'LBL_EMAIL_CC' => 'CC', + 'LBL_EMAIL_CHARSET' => 'Character Set', + 'LBL_EMAIL_CHECK' => 'Check Mail', + 'LBL_EMAIL_CHECKING_NEW' => 'Checking for New Email', + 'LBL_EMAIL_CHECKING_DESC' => 'One moment please...

    If this is the first check for the mail account, it may take some time.', + 'LBL_EMAIL_CLOSE' => 'Close', + 'LBL_EMAIL_COFFEE_BREAK' => 'Checking for New Email.

    Large mail accounts may take a considerable amount of time.', + 'LBL_EMAIL_COMMON' => 'Common', + + 'LBL_EMAIL_COMPOSE' => 'Email', + 'LBL_EMAIL_COMPOSE_ERR_NO_RECIPIENTS' => 'Please enter recipient(s) for this email.', + 'LBL_EMAIL_COMPOSE_LINK_TO' => 'Associate with', + 'LBL_EMAIL_COMPOSE_NO_BODY' => 'The body of this email is empty. Send anyway?', + 'LBL_EMAIL_COMPOSE_NO_SUBJECT' => 'This email has no subject. Send anyway?', + 'LBL_EMAIL_COMPOSE_NO_SUBJECT_LITERAL' => '(no subject)', + 'LBL_EMAIL_COMPOSE_READ' => 'Read & Compose Email', + 'LBL_EMAIL_COMPOSE_SEND_FROM' => 'Send From Mail Account', + 'LBL_EMAIL_COMPOSE_OPTIONS' => 'Options', + 'LBL_EMAIL_COMPOSE_INVALID_ADDRESS' => 'Please enter valid email address for To, CC and BCC fields', + + 'LBL_EMAIL_CONFIRM_CLOSE' => 'Discard this email?', + 'LBL_EMAIL_CONFIRM_DELETE' => 'Remove these entries from your Address Book?', + 'LBL_EMAIL_CONFIRM_DELETE_SIGNATURE' => 'Are you sure you want to delete this signature?', + + 'LBL_EMAIL_CREATE_NEW' => '--Create On Save--', + 'LBL_EMAIL_MULT_GROUP_FOLDER_ACCOUNTS' => 'Multiple', + 'LBL_EMAIL_MULT_GROUP_FOLDER_ACCOUNTS_EMPTY' => 'Empty', + 'LBL_EMAIL_DATE_SENT_BY_SENDER' => 'Date Sent by Sender', + 'LBL_EMAIL_DATE_RECEIVED' => 'Date Received', + 'LBL_EMAIL_ASSIGNED_TO_USER' =>'Assigned to User', + 'LBL_EMAIL_DATE_TODAY' => 'Today', + 'LBL_EMAIL_DATE_YESTERDAY' => 'Yesterday', + 'LBL_EMAIL_DD_TEXT' => 'email(s) selected.', + 'LBL_EMAIL_DEFAULTS' => 'Defaults', + 'LBL_EMAIL_DELETE' => 'Delete', + 'LBL_EMAIL_DELETE_CONFIRM' => 'Delete selected messages?', + 'LBL_EMAIL_DELETE_SUCCESS' => 'Email deleted successfully.', + 'LBL_EMAIL_DELETING_MESSAGE' => 'Deleting Message', + 'LBL_EMAIL_DETAILS' => 'Details', + 'LBL_EMAIL_DISPLAY_MSG' => 'Displaying email(s) {0} - {1} of {2}', + 'LBL_EMAIL_ADDR_DISPLAY_MSG' => 'Displaying email address(es) {0} - {1} of {2}', + + 'LBL_EMAIL_EDIT_CONTACT' => 'Edit Contact', + 'LBL_EMAIL_EDIT_CONTACT_WARN' => 'Only the Primary address will be used when working with Contacts.', + 'LBL_EMAIL_EDIT_MAILING_LIST' => 'Edit Mailing List', + + 'LBL_EMAIL_EMPTYING_TRASH' => 'Emptying Trash', + 'LBL_EMAIL_DELETING_OUTBOUND' => 'Deleteting outbound server', + 'LBL_EMAIL_CLEARING_CACHE_FILES' => 'CLearing cache files', + 'LBL_EMAIL_EMPTY_MSG' => 'No emails to display.', + 'LBL_EMAIL_EMPTY_ADDR_MSG' => 'No email addresses to display.', + + 'LBL_EMAIL_ERROR_ADD_GROUP_FOLDER' => 'Folder name be unique and not empty. Please try again.', + 'LBL_EMAIL_ERROR_DELETE_GROUP_FOLDER' => 'Cannot delete a folder. Either the folder or its children has emails or a mail box associated to it.', + 'LBL_EMAIL_ERROR_CANNOT_FIND_NODE' => 'Cannot determine the intended folder from context. Try again.', + 'LBL_EMAIL_ERROR_CHECK_IE_SETTINGS' => 'Please check your settings.', + 'LBL_EMAIL_ERROR_CONTACT_NAME' => 'Please make sure you enter a last name.', + 'LBL_EMAIL_ERROR_DESC' => 'Errors were detected: ', + 'LBL_EMAIL_DELETE_ERROR_DESC' => 'You do not have access to this area. Contact your site administrator to obtain access.', + 'LBL_EMAIL_ERROR_DUPE_FOLDER_NAME' => 'Sugar Folder names must be unique.', + 'LBL_EMAIL_ERROR_EMPTY' => 'Please enter some search criteria.', + 'LBL_EMAIL_ERROR_GENERAL_TITLE' => 'An error has occured', + 'LBL_EMAIL_ERROR_LIST_NAME' => 'An email list with that name already exists', + 'LBL_EMAIL_ERROR_MESSAGE_DELETED' => 'Message Removed from Server', + 'LBL_EMAIL_ERROR_IMAP_MESSAGE_DELETED' => 'Either message Removed from Server or moved to a different folder', + 'LBL_EMAIL_ERROR_MAILSERVERCONNECTION' => 'Connection to the mail server failed. Please contact your Administrator', + 'LBL_EMAIL_ERROR_MOVE' => 'Moving email between servers and/or mail accounts is not supported at this time.', + 'LBL_EMAIL_ERROR_MOVE_TITLE' => 'Move Error', + 'LBL_EMAIL_ERROR_NAME' => 'A name is required.', + 'LBL_EMAIL_ERROR_FROM_ADDRESS' => 'From Address is required. Please enter a valid email address.', + 'LBL_EMAIL_ERROR_NO_FILE' => 'Please provide a file.', + 'LBL_EMAIL_ERROR_NO_IMAP_FOLDER_RENAME' => 'IMAP folder renaming is not supported at this time.', + 'LBL_EMAIL_ERROR_SERVER' => 'A mail server address is required.', + 'LBL_EMAIL_ERROR_SAVE_ACCOUNT' => 'The mail account may not have been saved.', + 'LBL_EMAIL_ERROR_TIMEOUT' => 'An error has occured while communicating with the mail server.', + 'LBL_EMAIL_ERROR_USER' => 'A login name is required.', + 'LBL_EMAIL_ERROR_PASSWORD' => 'A password is required.', + 'LBL_EMAIL_ERROR_PORT' => 'A mail server port is required.', + 'LBL_EMAIL_ERROR_PROTOCOL' => 'A server protocol is required.', + 'LBL_EMAIL_ERROR_MONITORED_FOLDER' => 'Monitored Folder is required.', + 'LBL_EMAIL_ERROR_TRASH_FOLDER' => 'Trash Folder is required.', + 'LBL_EMAIL_ERROR_VIEW_RAW_SOURCE' => 'This information is not available', + 'LBL_EMAIL_ERROR_NO_OUTBOUND' => 'No outgoing mail server specified.', + 'LBL_EMAIL_FOLDERS' => ' Folders', + 'LBL_EMAIL_FOLDERS_SHORT' => '', + 'LBL_EMAIL_FOLDERS_ACTIONS' => 'Move To', + 'LBL_EMAIL_FOLDERS_ADD' => 'Add', + 'LBL_EMAIL_FOLDERS_ADD_DIALOG_TITLE' => 'Add New Folder', + 'LBL_EMAIL_FOLDERS_RENAME_DIALOG_TITLE' => 'Rename Folder', + 'LBL_EMAIL_FOLDERS_ADD_NEW_FOLDER' => 'Save', + 'LBL_EMAIL_FOLDERS_ADD_THIS_TO' => 'Add this folder to', + 'LBL_EMAIL_FOLDERS_CHANGE_HOME' => 'This folder cannot be changed', + 'LBL_EMAIL_FOLDERS_DELETE_CONFIRM' => 'Are you sure you would like to delete this folder?\nThis process cannot be reversed.\nFolder deletions will cascade to all contained folders.', + 'LBL_EMAIL_FOLDERS_NEW_FOLDER' => 'New Folder Name', + 'LBL_EMAIL_FOLDERS_NO_VALID_NODE' => 'Please select a folder before performing this action.', + 'LBL_EMAIL_FOLDERS_TITLE' => 'Folder Management', + 'LBL_EMAIL_FOLDERS_USING_GROUP_USER' => 'Using Group', + + 'LBL_EMAIL_FORWARD' => 'Forward', + 'LBL_EMAIL_DELIMITER' => '::;::', + 'LBL_EMAIL_DOWNLOAD_STATUS' => 'Downloaded [[count]] of [[total]] emails', + 'LBL_EMAIL_FOUND' => 'Found', + 'LBL_EMAIL_FROM' => 'From', + 'LBL_EMAIL_GROUP' => 'group', + 'LBL_EMAIL_UPPER_CASE_GROUP' => 'Group', + 'LBL_EMAIL_HOME_FOLDER' => 'Home', + 'LBL_EMAIL_HTML_RTF' => 'Send HTML', + 'LBL_EMAIL_IE_DELETE' => 'Deleting Mail Account', + 'LBL_EMAIL_IE_DELETE_SIGNATURE' => 'Deleting signature', + 'LBL_EMAIL_IE_DELETE_CONFIRM' => 'Are you sure you would like to delete this mail account?', + 'LBL_EMAIL_IE_DELETE_SUCCESSFUL' => 'Deletion successful.', + 'LBL_EMAIL_IE_SAVE' => 'Saving Mail Account Information', + 'LBL_EMAIL_IMPORTING_EMAIL' => 'Importing Email', + 'LBL_EMAIL_IMPORT_EMAIL' => 'Import to Sugar', + 'LBL_EMAIL_IMPORT_SETTINGS' => 'Import Settings', + 'LBL_EMAIL_INVALID' => 'Invalid', + 'LBL_EMAIL_LOADING' => 'Loading...', + 'LBL_EMAIL_MARK' => 'Mark', + 'LBL_EMAIL_MARK_FLAGGED' => 'As Flagged', + 'LBL_EMAIL_MARK_READ' => 'As Read', + 'LBL_EMAIL_MARK_UNFLAGGED' => 'As Unflagged', + 'LBL_EMAIL_MARK_UNREAD' => 'As Unread', + 'LBL_EMAIL_ASSIGN_TO' => 'Assign To', + + 'LBL_EMAIL_MENU_ADD_FOLDER' => 'Create Folder', + 'LBL_EMAIL_MENU_COMPOSE' => 'Compose to', + 'LBL_EMAIL_MENU_DELETE_FOLDER' => 'Delete Folder', + 'LBL_EMAIL_MENU_EDIT' => 'Edit', + 'LBL_EMAIL_MENU_EMPTY_TRASH' => 'Empty Trash', + 'LBL_EMAIL_MENU_SYNCHRONIZE' => 'Synchronize', + 'LBL_EMAIL_MENU_CLEAR_CACHE' => 'Clear cache files', + 'LBL_EMAIL_MENU_REMOVE' => 'Remove', + 'LBL_EMAIL_MENU_RENAME' => 'Rename', + 'LBL_EMAIL_MENU_RENAME_FOLDER' => 'Rename Folder', + 'LBL_EMAIL_MENU_RENAMING_FOLDER' => 'Renaming Folder', + 'LBL_EMAIL_MENU_MAKE_SELECTION' => 'Please make a selection before trying this operation.', + + 'LBL_EMAIL_MENU_HELP_ADD_FOLDER' => 'Create a Folder (remote or in Sugar)', + 'LBL_EMAIL_MENU_HELP_ARCHIVE' => 'Archive these email(s) to SugarCRM', + 'LBL_EMAIL_MENU_HELP_COMPOSE_TO_LIST' => 'Email selected Mailing Lists', + 'LBL_EMAIL_MENU_HELP_CONTACT_COMPOSE' => 'Email this Contact', + 'LBL_EMAIL_MENU_HELP_CONTACT_REMOVE' => 'Remove a Contact', + 'LBL_EMAIL_MENU_HELP_DELETE' => 'Delete these email(s)', + 'LBL_EMAIL_MENU_HELP_DELETE_FOLDER' => 'Delete a Folder (remote or in Sugar)', + 'LBL_EMAIL_MENU_HELP_EDIT_CONTACT' => 'Edit a Contact', + 'LBL_EMAIL_MENU_HELP_EDIT_LIST' => 'Edit a Mailing List', + 'LBL_EMAIL_MENU_HELP_EMPTY_TRASH' => 'Empties all Trash folders for your mail accounts', + 'LBL_EMAIL_MENU_HELP_MARK_FLAGGED' => 'Mark these email(s) flagged', + 'LBL_EMAIL_MENU_HELP_MARK_READ' => 'Mark these email(s) read', + 'LBL_EMAIL_MENU_HELP_MARK_UNFLAGGED' => 'Mark these email(s) unflagged', + 'LBL_EMAIL_MENU_HELP_MARK_UNREAD' => 'Mark these email(s) unread', + 'LBL_EMAIL_MENU_HELP_REMOVE_LIST' => 'Removes Mailing Lists', + 'LBL_EMAIL_MENU_HELP_RENAME_FOLDER' => 'Rename a Folder (remote or in Sugar)', + 'LBL_EMAIL_MENU_HELP_REPLY' => 'Reply to these email(s)', + 'LBL_EMAIL_MENU_HELP_REPLY_ALL' => 'Reply to all recipients for these email(s)', + + 'LBL_EMAIL_MESSAGES' => 'messages', + + 'LBL_EMAIL_ML_NAME' => 'List Name', + 'LBL_EMAIL_ML_ADDRESSES_1' => 'Selected List Addresses', + 'LBL_EMAIL_ML_ADDRESSES_2' => 'Available List Addresses', + + 'LBL_EMAIL_MULTISELECT' => 'Ctrl-Click to select multiples
    (Mac users use CMD-Click)', + + 'LBL_EMAIL_NO' => 'No', + 'LBL_EMAIL_NOT_SENT' => 'System is unable to process your request. Please contact the system administrator.', + + 'LBL_EMAIL_OK' => 'OK', + 'LBL_EMAIL_ONE_MOMENT' => 'One moment please...', + 'LBL_EMAIL_OPEN_ALL' => 'Open Multiple Messages', + 'LBL_EMAIL_OPTIONS' => 'Options', + 'LBL_EMAIL_QUICK_COMPOSE' => 'Quick Compose', + 'LBL_EMAIL_OPT_OUT' => 'Opted Out', + 'LBL_EMAIL_OPT_OUT_AND_INVALID' => 'Opted Out and Invalid', + 'LBL_EMAIL_PAGE_AFTER' => 'of {0}', + 'LBL_EMAIL_PAGE_BEFORE' => 'Page', + 'LBL_EMAIL_PERFORMING_TASK' => 'Performing Task', + 'LBL_EMAIL_PRIMARY' => 'Primary', + 'LBL_EMAIL_PRINT' => 'Print', + + 'LBL_EMAIL_QC_BUGS' => 'Bug', + 'LBL_EMAIL_QC_CASES' => 'Case', + 'LBL_EMAIL_QC_LEADS' => 'Lead', + 'LBL_EMAIL_QC_CONTACTS' => 'Contact', + 'LBL_EMAIL_QC_TASKS' => 'Task', + 'LBL_EMAIL_QUICK_CREATE' => 'Quick Create', + + 'LBL_EMAIL_REBUILDING_FOLDERS' => 'Rebuilding Folders', + 'LBL_EMAIL_RELATE_TO' => 'Relate', + 'LBL_EMAIL_VIEW_RELATIONSHIPS' => 'View Relationships', + 'LBL_EMAIL_RECORD' => 'Email Record', + 'LBL_EMAIL_REMOVE' => 'Remove', + 'LBL_EMAIL_REPLY' => 'Reply', + 'LBL_EMAIL_REPLY_ALL' => 'Reply All', + 'LBL_EMAIL_REPLY_TO' => 'Reply-to', + 'LBL_EMAIL_RETRIEVING_LIST' => 'Retrieving Email List', + 'LBL_EMAIL_RETRIEVING_MESSAGE' => 'Retrieving Message', + 'LBL_EMAIL_RETRIEVING_RECORD' => 'Retrieving Email Record', + 'LBL_EMAIL_SELECT_ONE_RECORD' => 'Please select only one email record', + 'LBL_EMAIL_RETURN_TO_VIEW' => 'Return to Previous Module?', + 'LBL_EMAIL_REVERT' => 'Revert', + 'LBL_EMAIL_RELATE_EMAIL' => 'Relate Email', + + 'LBL_EMAIL_RULES_TITLE' => 'Rule Management', + + 'LBL_EMAIL_SAVE' => 'Save', + 'LBL_EMAIL_SAVE_AND_REPLY' => 'Save & Reply', + 'LBL_EMAIL_SAVE_DRAFT' => 'Save Draft', + + 'LBL_EMAIL_SEARCHING' => 'Conducting Search', + 'LBL_EMAIL_SEARCH' => ' Search', + 'LBL_EMAIL_SEARCH_SHORT' => '', + 'LBL_EMAIL_SEARCH_ADVANCED' => 'Advanced Search', + 'LBL_EMAIL_SEARCH_DATE_FROM' => 'Date From', + 'LBL_EMAIL_SEARCH_DATE_UNTIL' => 'Date Until', + 'LBL_EMAIL_SEARCH_FULL_TEXT' => 'Body Text', + 'LBL_EMAIL_SEARCH_NO_RESULTS' => 'No results match your search criteria.', + 'LBL_EMAIL_SEARCH_RESULTS_TITLE' => 'Search Results', + 'LBL_EMAIL_SEARCH_TITLE' => 'Simple Search', + 'LBL_EMAIL_SEARCH__FROM_ACCOUNTS' => 'Search email account', + + 'LBL_EMAIL_SELECT' => 'Select', + + 'LBL_EMAIL_SEND' => 'Send', + 'LBL_EMAIL_SENDING_EMAIL' => 'Sending Email', + + 'LBL_EMAIL_SETTINGS' => 'Settings', + 'LBL_EMAIL_SETTINGS_2_ROWS' => '2 Rows', + 'LBL_EMAIL_SETTINGS_3_COLS' => '3 Columns', + 'LBL_EMAIL_SETTINGS_LAYOUT' => 'Layout Style', + 'LBL_EMAIL_SETTINGS_ACCOUNTS' => 'Mail Accounts', + 'LBL_EMAIL_SETTINGS_ADD_ACCOUNT' => 'Clear Form', + 'LBL_EMAIL_SETTINGS_AUTO_IMPORT' => 'Import Email Upon View', + 'LBL_EMAIL_SETTINGS_CHECK_INTERVAL' => 'Check for New Mail', + 'LBL_EMAIL_SETTINGS_COMPOSE_INLINE' => 'Use Preview Pane', + 'LBL_EMAIL_SETTINGS_COMPOSE_POPUP' => 'Use Popup Window', + 'LBL_EMAIL_SETTINGS_DISPLAY_NUM' => 'Number emails per page', + 'LBL_EMAIL_SETTINGS_EDIT_ACCOUNT' => 'Edit Mail Account', + 'LBL_EMAIL_SETTINGS_FOLDERS' => 'Folders', + 'LBL_EMAIL_SETTINGS_FROM_ADDR' => 'From Address', + 'LBL_EMAIL_SETTINGS_FROM_TO_EMAIL_ADDR' => 'Email Address For Test Notification:', + 'LBL_EMAIL_SETTINGS_TO_EMAIL_ADDR' => 'To Email Address', + 'LBL_EMAIL_SETTINGS_FROM_NAME' => 'From Name', + 'LBL_EMAIL_SETTINGS_REPLY_TO_ADDR' =>'Reply to Address', + 'LBL_EMAIL_SETTINGS_FULL_SCREEN' => 'Full Screen', + 'LBL_EMAIL_SETTINGS_FULL_SYNC' => 'Synchronize All Mail Accounts', + 'LBL_EMAIL_TEST_NOTIFICATION_SENT' => 'An email was sent to the specified email address using the provided outgoing mail settings. Please check to see if the email was received to verify the settings are correct.', + 'LBL_EMAIL_SETTINGS_FULL_SYNC_DESC' => 'Performing this action will synchronize mail accounts and their contents.', + 'LBL_EMAIL_SETTINGS_FULL_SYNC_WARN' => 'Perform a full synchronization?\nLarge mail accounts may take a few minutes.', + 'LBL_EMAIL_SUBSCRIPTION_FOLDER_HELP' => 'Click the Shift key or the Ctrl key to select multiple folders.', + 'LBL_EMAIL_SETTINGS_GENERAL' => 'General', + 'LBL_EMAIL_SETTINGS_GROUP_FOLDERS' => 'Available Group Folders', + 'LBL_EMAIL_SETTINGS_GROUP_FOLDERS_CREATE' => 'Create Group Folders', + 'LBL_EMAIL_SETTINGS_GROUP_FOLDERS_Save' => 'Saving Group Folders', + 'LBL_EMAIL_SETTINGS_RETRIEVING_GROUP' => 'Retrieving Group Folder', + + 'LBL_EMAIL_SETTINGS_GROUP_FOLDERS_EDIT' => 'Edit Group Folder', + + 'LBL_EMAIL_SETTINGS_NAME' => 'Mail Account Name', + 'LBL_EMAIL_SETTINGS_REQUIRE_REFRESH' => 'Select the number of emails per page in the Inbox. This setting might require a page refresh in order to take effect.', + 'LBL_EMAIL_SETTINGS_RETRIEVING_ACCOUNT' => 'Retrieving Mail Account', + 'LBL_EMAIL_SETTINGS_RULES' => 'Rules', + 'LBL_EMAIL_SETTINGS_SAVED' => 'The settings have been saved.\n\nYou must reload the page for the new settings to take effect.', + 'LBL_EMAIL_SETTINGS_SEND_EMAIL_AS' => 'Send Plain Text Emails Only', + 'LBL_EMAIL_SETTINGS_SHOW_IN_FOLDERS' => 'Active', + 'LBL_EMAIL_SETTINGS_SHOW_NUM_IN_LIST' => 'Emails per Page', + 'LBL_EMAIL_SETTINGS_TAB_POS' => 'Place Tabs at Bottom', + 'LBL_EMAIL_SETTINGS_TITLE_LAYOUT' => 'Visual Settings', + 'LBL_EMAIL_SETTINGS_TITLE_PREFERENCES' => 'Preferences', + 'LBL_EMAIL_SETTINGS_TOGGLE_ADV' => 'Show Advanced', + 'LBL_EMAIL_SETTINGS_USER_FOLDERS' => 'Available User Folders', + 'LBL_EMAIL_ERROR_PREPEND' => 'Error:', + 'LBL_EMAIL_INVALID_PERSONAL_OUTBOUND' => 'The outbound mail server selected for the mail account you are using is invalid. Check the settings or select a different mail server for the mail account.', + 'LBL_EMAIL_INVALID_SYSTEM_OUTBOUND' => 'An outgoing mail server is not configured to send emails. Please configure an outgoing mail server or select an outgoing mail server for the mail account that you are using in Settings >> Mail Account.', + 'LBL_EMAIL_SHOW_READ' => 'Show All', + 'LBL_EMAIL_SHOW_UNREAD_ONLY' => 'Show Unread Only', + 'LBL_EMAIL_SIGNATURES' => 'Signatures', + 'LBL_EMAIL_SIGNATURE_CREATE' => 'Create Signature', + 'LBL_EMAIL_SIGNATURE_NAME' => 'Signature Name', + 'LBL_EMAIL_SIGNATURE_TEXT' => 'Signature Body', + 'LBL_SMTPTYPE_GMAIL' => 'Gmail', + 'LBL_SMTPTYPE_YAHOO' => 'Yahoo! Mail', + 'LBL_SMTPTYPE_EXCHANGE' => 'Microsoft Exchange', + 'LBL_EMAIL_SPACER_MAIL_SERVER' => '[ Remote Folders ]', + 'LBL_EMAIL_SPACER_LOCAL_FOLDER' => '[ Sugar Folders ]', + 'LBL_EMAIL_SUBJECT' => 'Subject', + 'LBL_EMAIL_TO' => 'To', + 'LBL_EMAIL_SUCCESS' => 'Success', + 'LBL_EMAIL_SUGAR_FOLDER' => 'SugarFolder', + 'LBL_EMAIL_TEMPLATE_EDIT_PLAIN_TEXT' => 'Email template body is empty', + 'LBL_EMAIL_TEMPLATES' => 'Templates', + 'LBL_EMAIL_TEXT_FIRST' => 'First Page', + 'LBL_EMAIL_TEXT_PREV' => 'Previous Page', + 'LBL_EMAIL_TEXT_NEXT' => 'Next Page', + 'LBL_EMAIL_TEXT_LAST' => 'Last Page', + 'LBL_EMAIL_TEXT_REFRESH' => 'Refresh', + 'LBL_EMAIL_TO' => 'To', + 'LBL_EMAIL_TOGGLE_LIST' => 'Toggle List', + 'LBL_EMAIL_VIEW' => 'View', + 'LBL_EMAIL_VIEWS' => 'Views', + 'LBL_EMAIL_VIEW_HEADERS' => 'Display Headers', + 'LBL_EMAIL_VIEW_PRINTABLE' => 'Printable Version', + 'LBL_EMAIL_VIEW_RAW' => 'Display Raw Email', + 'LBL_EMAIL_VIEW_UNSUPPORTED' => 'This feature is unsupported when used with POP3.', + 'LBL_DEFAULT_LINK_TEXT' => 'Default link text.', + 'LBL_EMAIL_YES' => 'Yes', + 'LBL_EMAIL_TEST_OUTBOUND_SETTINGS' => 'Send Test Email', + 'LBL_EMAIL_TEST_OUTBOUND_SETTINGS_SENT' => 'Test Email Sent', + 'LBL_EMAIL_CHECK_INTERVAL_DOM' => array( + '-1' => "Manually", + '5' => 'Every 5 minutes', + '15' => 'Every 15 minutes', + '30' => 'Every 30 minutes', + '60' => 'Every hour' + ), + + + 'LBL_EMAIL_MESSAGE_NO' => 'Message No', + 'LBL_EMAIL_IMPORT_SUCCESS' => 'Import Passed', + 'LBL_EMAIL_IMPORT_FAIL' => 'Import Failed because either the message is already imported or deleted from server', + + 'LBL_LINK_NONE'=> 'None', + 'LBL_LINK_ALL'=> 'All', + 'LBL_LINK_RECORDS'=> 'Records', + 'LBL_LINK_SELECT'=> 'Select', + 'LBL_LINK_ACTIONS'=> 'Actions', + 'LBL_CLOSE_ACTIVITY_HEADER' => "Confirm", + 'LBL_CLOSE_ACTIVITY_CONFIRM' => "Do you want to close this #module#?", + 'LBL_CLOSE_ACTIVITY_REMEMBER' => "Do not display this message in the future:  ", + 'LBL_INVALID_FILE_EXTENSION' => 'Invalid File Extension', + + + 'ERR_CREATING_FIELDS' => 'Error filling in additional detail fields: ', + 'ERR_CREATING_TABLE' => 'Error creating table: ', + 'ERR_DECIMAL_SEP_EQ_THOUSANDS_SEP' => "The decimal separator cannot use the same character as the thousands separator.\\n\\n Please change the values.", + 'ERR_DELETE_RECORD' => 'A record number must be specified to delete the contact.', + 'ERR_EXPORT_DISABLED' => 'Exports Disabled.', + 'ERR_EXPORT_TYPE' => 'Error exporting ', + 'ERR_INVALID_AMOUNT' => 'Please enter a valid amount.', + 'ERR_INVALID_DATE_FORMAT' => 'The date format must be: ', + 'ERR_INVALID_DATE' => 'Please enter a valid date.', + 'ERR_INVALID_DAY' => 'Please enter a valid day.', + 'ERR_INVALID_EMAIL_ADDRESS' => 'not a valid email address.', + 'ERR_INVALID_FILE_REFERENCE' => 'Invalid File Reference', + 'ERR_INVALID_HOUR' => 'Please enter a valid hour.', + 'ERR_INVALID_MONTH' => 'Please enter a valid month.', + 'ERR_INVALID_TIME' => 'Please enter a valid time.', + 'ERR_INVALID_YEAR' => 'Please enter a valid 4 digit year.', + 'ERR_NEED_ACTIVE_SESSION' => 'An active session is required to export content.', + 'ERR_NO_HEADER_ID' => 'This feature is unavailable in this theme.', + 'ERR_NOT_ADMIN' => "Unauthorized access to administration.", + 'ERR_MISSING_REQUIRED_FIELDS' => 'Missing required field:', + 'ERR_INVALID_REQUIRED_FIELDS' => 'Invalid required field:', + 'ERR_INVALID_VALUE' => 'Invalid Value:', + 'ERR_NO_SUCH_FILE' =>'File does not exist on system', + 'ERR_NO_SINGLE_QUOTE' => 'Cannot use the single quotation mark for ', + 'ERR_NOTHING_SELECTED' =>'Please make a selection before proceeding.', + 'ERR_OPPORTUNITY_NAME_DUPE' => 'An opportunity with the name %s already exists. Please enter another name below.', + 'ERR_OPPORTUNITY_NAME_MISSING' => 'An opportunity name was not entered. Please enter an opportunity name below.', + 'ERR_POTENTIAL_SEGFAULT' => 'A potential Apache segmentation fault was detected. Please notify your system administrator to confirm this problem and have her/him report it to SugarCRM.', + 'ERR_SELF_REPORTING' => 'User cannot report to him or herself.', + 'ERR_SINGLE_QUOTE' => 'Using the single quote is not supported for this field. Please change the value.', + 'ERR_SQS_NO_MATCH_FIELD' => 'No match for field: ', + 'ERR_SQS_NO_MATCH' =>'No Match', + 'ERR_ADDRESS_KEY_NOT_SPECIFIED' => 'Please specify \'key\' index in displayParams attribute for the Meta-Data definition', + 'ERR_EXISTING_PORTAL_USERNAME'=>'Error: The Portal Name is already assigned to another contact.', + 'ERR_COMPATIBLE_PRECISION_VALUE' => 'Field value is not compatible with precision value', + 'ERR_EXTERNAL_API_SAVE_FAIL' => 'An error occurred when trying to save to the external account.', + 'ERR_EXTERNAL_API_UPLOAD_FAIL' => 'An error occurred while uploading. Please ensure the file you are uploading is not empty.', + 'ERR_NO_DB' => 'Could not connect to the database. Please refer to sugarcrm.log for details.', + 'ERR_DB_FAIL' => 'Database failure. Please refer to sugarcrm.log for details.', + 'ERR_EXTERNAL_API_403' => 'Permission Denied. File type is not supported.', + + 'LBL_ACCOUNT'=>'Account', + 'LBL_OLD_ACCOUNT_LINK'=>'Old Account', + 'LBL_ACCOUNTS'=>'Accounts', + 'LBL_ACTIVITIES_SUBPANEL_TITLE'=>'Activities', + 'LBL_ACCUMULATED_HISTORY_BUTTON_KEY' => 'H', + 'LBL_ACCUMULATED_HISTORY_BUTTON_LABEL' => 'View Summary', + 'LBL_ACCUMULATED_HISTORY_BUTTON_TITLE' => 'View Summary [Alt+H]', + 'LBL_ADD_BUTTON_KEY' => 'A', + 'LBL_ADD_BUTTON_TITLE' => 'Add [Alt+A]', + 'LBL_ADD_BUTTON' => 'Add', + 'LBL_ADD_DOCUMENT' => 'Add Document', + 'LBL_REPLACE_BUTTON' => 'Replace', + 'LBL_ADD_TO_PROSPECT_LIST_BUTTON_KEY' => 'L', + 'LBL_ADD_TO_PROSPECT_LIST_BUTTON_LABEL' => 'Add To Target List', + 'LBL_ADD_TO_PROSPECT_LIST_BUTTON_TITLE' => 'Add To Target List', + 'LBL_ADDITIONAL_DETAILS_CLOSE_TITLE' => 'Click to Close', + 'LBL_ADDITIONAL_DETAILS_CLOSE' => 'Close', + 'LBL_ADDITIONAL_DETAILS' => 'Additional Details', + 'LBL_ADMIN' => 'Admin', + 'LBL_ALT_HOT_KEY' => 'Alt+', + 'LBL_ARCHIVE' => 'Archive', + 'LBL_ASSIGNED_TO_USER'=>'Assigned to User', + 'LBL_ASSIGNED_TO' => 'Assigned to:', + 'LBL_BACK' => 'Back', + 'LBL_BILL_TO_ACCOUNT'=>'Bill to Account', + 'LBL_BILL_TO_CONTACT'=>'Bill to Contact', + 'LBL_BILLING_ADDRESS'=>'Billing Address', + 'LBL_BROWSER_TITLE' => 'SugarCRM - Commercial Open Source CRM', + 'LBL_BUGS'=>'Bugs', + 'LBL_BY' => 'by', + 'LBL_CALLS'=>'Calls', + 'LBL_CALL'=>'Call', + 'LBL_CAMPAIGNS_SEND_QUEUED' => 'Send Queued Campaign Emails', + 'LBL_CANCEL_BUTTON_KEY' => 'X', + 'LBL_CANCEL_BUTTON_LABEL' => 'Cancel', + 'LBL_CANCEL_BUTTON_TITLE' => 'Cancel [Alt+X]', + 'LBL_SUBMIT_BUTTON_LABEL' => 'Submit', + 'LBL_CASE'=>'Case', + 'LBL_CASES'=>'Cases', + 'LBL_CHANGE_BUTTON_KEY' => 'G', + 'LBL_CHANGE_BUTTON_LABEL' => 'Change', + 'LBL_CHANGE_BUTTON_TITLE' => 'Change [Alt+G]', + 'LBL_CHARSET' => 'UTF-8', + 'LBL_CHECKALL' => 'Check All', + 'LBL_CITY' => 'City', + 'LBL_CLEAR_BUTTON_KEY' => 'C', + 'LBL_CLEAR_BUTTON_LABEL' => 'Clear', + 'LBL_CLEAR_BUTTON_TITLE' => 'Clear [Alt+C]', + 'LBL_CLEARALL' => 'Clear All', + 'LBL_CLOSE_BUTTON_TITLE' =>'Close', + 'LBL_CLOSE_BUTTON_KEY'=>'Q', + 'LBL_CLOSE_WINDOW'=>'Close Window', + 'LBL_CLOSEALL_BUTTON_KEY' => 'Q', + 'LBL_CLOSEALL_BUTTON_LABEL' => 'Close All', + 'LBL_CLOSEALL_BUTTON_TITLE' => 'Close All [Alt+I]', + 'LBL_CLOSE_AND_CREATE_BUTTON_LABEL' => 'Close and Create New', + 'LBL_CLOSE_AND_CREATE_BUTTON_TITLE' => 'Close and Create New', + 'LBL_CLOSE_AND_CREATE_BUTTON_KEY' => 'C', + 'LBL_OPEN_ITEMS' => 'Open Items:', + 'LBL_COMPOSE_EMAIL_BUTTON_KEY' => 'L', + 'LBL_COMPOSE_EMAIL_BUTTON_LABEL' => 'Compose Email', + 'LBL_COMPOSE_EMAIL_BUTTON_TITLE' => 'Compose Email [Alt+L]', + 'LBL_SEARCH_DROPDOWN_YES'=>'Yes', + 'LBL_SEARCH_DROPDOWN_NO'=>'No', + 'LBL_CONTACT_LIST' => 'Contact List', + 'LBL_CONTACT'=>'Contact', + 'LBL_CONTACTS'=>'Contacts', + 'LBL_CONTRACTS'=>'Contracts', + 'LBL_COUNTRY' => 'Country:', + 'LBL_CREATE_BUTTON_LABEL' => 'Create', + 'LBL_CREATED_BY_USER'=>'Created by User', + 'LBL_CREATED_USER'=>'Created by User', + 'LBL_CREATED_ID' => 'Created By Id', + 'LBL_CREATED' => 'Created by', + 'LBL_CURRENT_USER_FILTER' => 'My Items:', + 'LBL_CURRENCY'=>'Currency:', + 'LBL_DOCUMENTS'=>'Documents', + 'LBL_DATE_ENTERED' => 'Date Created:', + 'LBL_DATE_MODIFIED' => 'Date Modified:', + 'LBL_DELETE_BUTTON_KEY' => 'D', + 'LBL_DELETE_BUTTON_LABEL' => 'Delete', + 'LBL_DELETE_BUTTON_TITLE' => 'Delete [Alt+D]', + 'LBL_DELETE_BUTTON' => 'Delete', + 'LBL_DELETE' => 'Delete', + 'LBL_DELETED'=>'Deleted', + 'LBL_DIRECT_REPORTS'=>'Direct Reports', + 'LBL_DONE_BUTTON_KEY' => 'X', + 'LBL_DONE_BUTTON_LABEL' => 'Done', + 'LBL_DONE_BUTTON_TITLE' => 'Done [Alt+X]', + 'LBL_DST_NEEDS_FIXIN' => 'The application requires a Daylight Saving Time fix to be applied. Please go to the Repair link in the Admin console and apply the Daylight Saving Time fix.', + 'LBL_DUPLICATE_BUTTON_KEY' => 'U', + 'LBL_DUPLICATE_BUTTON_LABEL' => 'Duplicate', + 'LBL_DUPLICATE_BUTTON_TITLE' => 'Duplicate [Alt+U]', + 'LBL_DUPLICATE_BUTTON' => 'Duplicate', + 'LBL_EDIT_BUTTON_KEY' => 'E', + 'LBL_EDIT_BUTTON_LABEL' => 'Edit', + 'LBL_EDIT_BUTTON_TITLE' => 'Edit [Alt+E]', + 'LBL_EDIT_BUTTON' => 'Edit', + 'LBL_EDIT_AS_NEW_BUTTON_LABEL' => 'Edit As New', + 'LBL_EDIT_AS_NEW_BUTTON_TITLE' => 'Edit As New', + 'LBL_VCARD' => 'vCard', + 'LBL_EMPTY_VCARD' => 'Please select a vCard file', + 'LBL_IMPORT_VCARD' => 'Import vCard:', + 'LBL_IMPORT_VCARD_BUTTON_KEY' => 'I', + 'LBL_IMPORT_VCARD_BUTTON_LABEL' => 'Import vCard', + 'LBL_IMPORT_VCARD_BUTTON_TITLE' => 'Import vCard [Alt+I]', + 'LBL_VIEW_BUTTON_KEY' => 'V', + 'LBL_VIEW_BUTTON_LABEL' => 'View', + 'LBL_VIEW_BUTTON_TITLE' => 'View [Alt+V]', + 'LBL_VIEW_BUTTON' => 'View', + 'LBL_EMAIL_PDF_BUTTON_KEY' => 'M', + 'LBL_EMAIL_PDF_BUTTON_LABEL' => 'Email as PDF', + 'LBL_EMAIL_PDF_BUTTON_TITLE' => 'Email as PDF [Alt+M]', + 'LBL_EMAILS'=>'Emails', + 'LBL_EMPLOYEES' => 'Employees', + 'LBL_ENTER_DATE' => 'Enter Date', + 'LBL_EXPORT_ALL' => 'Export All', + 'LBL_EXPORT' => 'Export', + 'LBL_FAVORITES_FILTER' => 'My Favorites:', + 'LBL_GO_BUTTON_LABEL' => 'Go', + 'LBL_HIDE'=>'Hide', + 'LBL_ID'=>'ID', + 'LBL_IMPORT' => 'Import', + 'LBL_IMPORT_STARTED' => 'Import Started: ', + 'LBL_MISSING_CUSTOM_DELIMITER' => 'Must specify a custom delimiter.', + 'LBL_LAST_VIEWED' => 'Last Viewed', + 'LBL_TODAYS_ACTIVITIES' => 'Today\'s Activities', + 'LBL_LEADS'=>'Leads', + 'LBL_LESS' => 'less', + 'LBL_CAMPAIGN' => 'Campaign:', + 'LBL_CAMPAIGNS' => 'Campaigns', + 'LBL_CAMPAIGNLOG' => 'CampaignLog', + 'LBL_CAMPAIGN_CONTACT'=>'Campaigns', + 'LBL_CAMPAIGN_ID'=>'campaign_id', + 'LBL_SITEMAP'=>'Sitemap', + 'LBL_THEME'=>'Theme:', + 'LBL_THEME_PICKER'=>'Page Style', + 'LBL_THEME_PICKER_IE6COMPAT_CHECK' => 'Warning: Internet Explorer 6 is not supported for the selected theme. Click OK to select it anyways or Cancel to select a different theme.', + 'LBL_FOUND_IN_RELEASE'=>'Found In Release', + 'LBL_FIXED_IN_RELEASE'=>'Fixed In Release', + 'LBL_LIST_ACCOUNT_NAME' => 'Account Name', + 'LBL_LIST_ASSIGNED_USER' => 'User', + 'LBL_LIST_CONTACT_NAME' => 'Contact Name', + 'LBL_LIST_CONTACT_ROLE' => 'Contact Role', + 'LBL_LIST_DATE_ENTERED'=>'Date Created', + 'LBL_LIST_EMAIL' => 'Email', + 'LBL_LIST_NAME' => 'Name', + 'LBL_LIST_OF' => 'of', + 'LBL_LIST_PHONE' => 'Phone', + 'LBL_LIST_RELATED_TO' => 'Related to', + 'LBL_LIST_USER_NAME' => 'User Name', + 'LBL_LISTVIEW_MASS_UPDATE_CONFIRM' => 'Are you sure you want to update the entire list?', + 'LBL_LISTVIEW_NO_SELECTED' => 'Please select at least 1 record to proceed.', + 'LBL_LISTVIEW_TWO_REQUIRED' => 'Please select at least 2 records to proceed.', + 'LBL_LISTVIEW_LESS_THAN_TEN_SELECT' => 'Please select less than 10 records to proceed.', + 'LBL_LISTVIEW_ALL' => 'All', + 'LBL_LISTVIEW_NONE' => 'Deselect All', + 'LBL_LISTVIEW_OPTION_CURRENT' => 'Select This Page', + 'LBL_LISTVIEW_OPTION_ENTIRE' => 'Select All', + 'LBL_LISTVIEW_OPTION_SELECTED' => 'Selected Records', + 'LBL_LISTVIEW_SELECTED_OBJECTS' => 'Selected: ', + + 'LBL_LOCALE_NAME_EXAMPLE_FIRST' => 'David', + 'LBL_LOCALE_NAME_EXAMPLE_LAST' => 'Livingstone', + 'LBL_LOCALE_NAME_EXAMPLE_SALUTATION' => 'Dr.', + 'LBL_LOCALE_NAME_EXAMPLE_TITLE' => 'Code Monkey Extraordinaire', + 'LBL_LOGIN_TO_ACCESS' => 'Please sign in to access this area.', + 'LBL_LOGOUT' => 'Log Out', + 'LBL_MAILMERGE_KEY' => 'M', + 'LBL_MAILMERGE' => 'Mail Merge', + 'LBL_MASS_UPDATE' => 'Mass Update', + 'LBL_OPT_OUT_FLAG_PRIMARY' => 'Opt out Primary Email', + 'LBL_MEETINGS'=>'Meetings', + 'LBL_MEETING'=>'Meeting', + 'LBL_MEMBERS'=>'Members', + 'LBL_MEMBER_OF'=>'Member Of', + 'LBL_MODIFIED_BY_USER'=>'Modified by User', + 'LBL_MODIFIED_USER'=>'Modified by User', + 'LBL_MODIFIED' => 'Modified by', + 'LBL_MODIFIED_NAME'=>'Modified By Name', + 'LBL_MODIFIED_ID'=>'Modified By Id', + 'LBL_MORE' => 'more', + 'LBL_MY_ACCOUNT' => 'My Settings', + 'LBL_NAME' => 'Name', + 'LBL_NEW_BUTTON_KEY' => 'N', + 'LBL_NEW_BUTTON_LABEL' => 'Create', + 'LBL_NEW_BUTTON_TITLE' => 'Create [Alt+N]', + 'LBL_NEXT_BUTTON_LABEL' => 'Next', + 'LBL_NONE' => '--None--', + 'LBL_NOTES'=>'Notes', + 'LBL_OPENALL_BUTTON_KEY' => 'O', + 'LBL_OPENALL_BUTTON_LABEL' => 'Open All', + 'LBL_OPENALL_BUTTON_TITLE' => 'Open All [Alt+O]', + 'LBL_OPENTO_BUTTON_KEY' => 'T', + 'LBL_OPENTO_BUTTON_LABEL' => 'Open To: ', + 'LBL_OPENTO_BUTTON_TITLE' => 'Open To: [Alt+T]', + 'LBL_OPPORTUNITIES'=>'Opportunities', + 'LBL_OPPORTUNITY_NAME' => 'Opportunity Name', + 'LBL_OPPORTUNITY'=>'Opportunity', + 'LBL_OR' => 'OR', + 'LBL_LOWER_OR' => 'or', + 'LBL_PANEL_ASSIGNMENT' => 'Other', + 'LBL_PANEL_ADVANCED' => 'More Information', + 'LBL_PARENT_TYPE' => 'Parent Type', + 'LBL_PERCENTAGE_SYMBOL' => '%', + 'LBL_PHASE' => 'Range', + 'LBL_POSTAL_CODE' => 'Postal Code:', + 'LBL_PRIMARY_ADDRESS_CITY' => 'Primary Address City:', + 'LBL_PRIMARY_ADDRESS_COUNTRY' => 'Primary Address Country:', + 'LBL_PRIMARY_ADDRESS_POSTALCODE' => 'Primary Address Postal Code:', + 'LBL_PRIMARY_ADDRESS_STATE' => 'Primary Address State:', + 'LBL_PRIMARY_ADDRESS_STREET_2' => 'Primary Address Street 2:', + 'LBL_PRIMARY_ADDRESS_STREET_3' => 'Primary Address Street 3:', + 'LBL_PRIMARY_ADDRESS_STREET' => 'Primary Address Street:', + 'LBL_PRIMARY_ADDRESS' => 'Primary Address:', + + 'LBL_PRODUCT_BUNDLES'=>'Product Bundles', + 'LBL_PRODUCT_BUNDLES'=>'Product Bundles', + 'LBL_PRODUCTS'=>'Products', + 'LBL_PROJECT_TASKS'=>'Project Tasks', + 'LBL_PROJECTS'=>'Projects', + 'LBL_PROJECTS'=>'Projects', + 'LBL_QUOTE_TO_OPPORTUNITY_KEY' => 'O', + 'LBL_QUOTE_TO_OPPORTUNITY_LABEL' => 'Create Opportunity from Quote', + 'LBL_QUOTE_TO_OPPORTUNITY_TITLE' => 'Create Opportunity from Quote [Alt+O]', + 'LBL_QUOTES_SHIP_TO'=>'Quotes Ship to', + 'LBL_QUOTES'=>'Quotes', + + 'LBL_RELATED' => 'Related', + 'LBL_RELATED_INFORMATION' => 'Related Information', + 'LBL_RELATED_RECORDS' => 'Related Records', + 'LBL_REMOVE' => 'Remove', + 'LBL_REPORTS_TO' => 'Reports To', + 'LBL_REQUIRED_SYMBOL' => '*', + 'LBL_REQUIRED_TITLE' => 'Indicates required field', + 'LBL_SAVE_BUTTON_KEY' => 'S', + 'LBL_SAVE_BUTTON_LABEL' => 'Save', + 'LBL_EMAIL_DONE_BUTTON_LABEL' => 'Done', + 'LBL_SAVE_BUTTON_TITLE' => 'Save [Alt+S]', + 'LBL_SAVE_AS_BUTTON_KEY' => 'A', + 'LBL_SAVE_AS_BUTTON_LABEL' => 'Save As', + 'LBL_SAVE_AS_BUTTON_TITLE' => 'Save As [Alt+A]', + 'LBL_FULL_FORM_BUTTON_KEY' => 'F', + 'LBL_FULL_FORM_BUTTON_LABEL' => 'Full Form', + 'LBL_FULL_FORM_BUTTON_TITLE' => 'Full Form [Alt+F]', + 'LBL_SAVE_NEW_BUTTON_KEY' => 'V', + 'LBL_SAVE_NEW_BUTTON_LABEL' => 'Save & Create New', + 'LBL_SAVE_NEW_BUTTON_TITLE' => 'Save & Create New [Alt+V]', + 'LBL_SEARCH_BUTTON_KEY' => 'Q', + 'LBL_SEARCH_BUTTON_LABEL' => 'Search', + 'LBL_SEARCH_BUTTON_TITLE' => 'Search [Alt+Q]', + 'LBL_SEARCH' => 'Search', + 'LBL_SEARCH_MORE' => 'more', + 'LBL_SEE_ALL' => 'See All', + 'LBL_UPLOAD_IMAGE_FILE_INVALID' => 'Invalid file format, only image file can be uploaded.', + 'LBL_SELECT_BUTTON_KEY' => 'T', + 'LBL_SELECT_BUTTON_LABEL' => 'Select', + 'LBL_SELECT_BUTTON_TITLE' => 'Select [Alt+T]', + 'LBL_SELECT_TEAMS_KEY' => 'Z', + 'LBL_SELECT_TEAMS_LABEL' => 'Add Team(s)', + 'LBL_SELECT_TEAMS_TITLE' => 'Add Teams(s) [Alt+Z]', + 'LBL_BROWSE_DOCUMENTS_BUTTON_KEY' => 'B', + 'LBL_BROWSE_DOCUMENTS_BUTTON_LABEL' => 'Browse Documents', + 'LBL_BROWSE_DOCUMENTS_BUTTON_TITLE' => 'Browse Documents [Alt+B]', + 'LBL_SELECT_CONTACT_BUTTON_KEY' => 'T', + 'LBL_SELECT_CONTACT_BUTTON_LABEL' => 'Select Contact', + 'LBL_SELECT_CONTACT_BUTTON_TITLE' => 'Select Contact [Alt+T]', + 'LBL_GRID_SELECTED_FILE' => 'selected file', + 'LBL_GRID_SELECTED_FILES' => 'selected files', + 'LBL_SELECT_REPORTS_BUTTON_LABEL' => 'Select from Reports', + 'LBL_SELECT_REPORTS_BUTTON_TITLE' => 'Select Reports', + 'LBL_SELECT_USER_BUTTON_KEY' => 'U', + 'LBL_SELECT_USER_BUTTON_LABEL' => 'Select User', + 'LBL_SELECT_USER_BUTTON_TITLE' => 'Select User [Alt+U]', + 'LBL_SERVER_RESPONSE_RESOURCES' => 'Resources used to construct this page (queries, files)', + 'LBL_SERVER_RESPONSE_TIME_SECONDS' => 'seconds.', + 'LBL_SERVER_RESPONSE_TIME' => 'Server response time:', + 'LBL_SHIP_TO_ACCOUNT'=>'Ship to Account', + 'LBL_SHIP_TO_CONTACT'=>'Ship to Contact', + 'LBL_SHIPPING_ADDRESS'=>'Shipping Address', + 'LBL_SHORTCUTS' => 'Shortcuts', + 'LBL_SHOW'=>'Show', + 'LBL_SQS_INDICATOR' => '', + 'LBL_STATE' => 'State:', + 'LBL_STATUS_UPDATED'=>'Your Status for this event has been updated!', + 'LBL_STATUS'=>'Status:', + 'LBL_STREET'=>'Street', + 'LBL_SUBJECT' => 'Subject', + + 'LBL_INBOUNDEMAIL_ID' => 'Inbound Email ID', + + /* The following version of LBL_SUGAR_COPYRIGHT is intended for Sugar Open Source only. */ + + 'LBL_SUGAR_COPYRIGHT' => '© 2004-2011 SugarCRM Inc. The Program is provided AS IS, without warranty. Licensed under AGPLv3.
    SugarCRM is a trademark of SugarCRM, Inc. All other company and product names may be trademarks of the respective companies with which they are associated.', + + + + // The following version of LBL_SUGAR_COPYRIGHT is for Professional and Enterprise editions. + + 'LBL_SUGAR_COPYRIGHT_SUB' => '© 2004-2011 SugarCRM Inc. All Rights Reserved.
    SugarCRM is a trademark of SugarCRM, Inc. All other company and product names may be trademarks of the respective companies with which they are associated.', + + + 'LBL_SYNC' => 'Sync', + 'LBL_SYNC' => 'Sync', + 'LBL_TABGROUP_ALL' => 'All', + 'LBL_TABGROUP_ACTIVITIES' => 'Activities', + 'LBL_TABGROUP_COLLABORATION' => 'Collaboration', + 'LBL_TABGROUP_HOME' => 'Home', + 'LBL_TABGROUP_MARKETING' => 'Marketing', + 'LBL_TABGROUP_MY_PORTALS' => 'My Sites', + 'LBL_TABGROUP_OTHER' => 'Other', + 'LBL_TABGROUP_REPORTS' => 'Reports', + 'LBL_TABGROUP_SALES' => 'Sales', + 'LBL_TABGROUP_SUPPORT' => 'Support', + 'LBL_TABGROUP_TOOLS' => 'Tools', + 'LBL_TASKS'=>'Tasks', + 'LBL_TEAMS_LINK'=>'Teams', + 'LBL_THEME_COLOR'=>'Color', + 'LBL_THEME_FONT'=>'Font', + 'LBL_THOUSANDS_SYMBOL' => 'K', + 'LBL_TRACK_EMAIL_BUTTON_KEY' => 'K', + 'LBL_TRACK_EMAIL_BUTTON_LABEL' => 'Archive Email', + 'LBL_TRACK_EMAIL_BUTTON_TITLE' => 'Archive Email [Alt+K]', + 'LBL_UNAUTH_ADMIN' => 'Unauthorized access to administration', + 'LBL_UNDELETE_BUTTON_LABEL' => 'Undelete', + 'LBL_UNDELETE_BUTTON_TITLE' => 'Undelete [Alt+D]', + 'LBL_UNDELETE_BUTTON' => 'Undelete', + 'LBL_UNDELETE' => 'Undelete', + 'LBL_UNSYNC' => 'Unsync', + 'LBL_UPDATE' => 'Update', + 'LBL_USER_LIST' => 'User List', + 'LBL_USERS_SYNC'=>'Users Sync', + 'LBL_USERS'=>'Users', + 'LBL_VERIFY_EMAIL_ADDRESS'=>'Checking for existing email entry...', + 'LBL_VERIFY_PORTAL_NAME'=>'Checking for existing portal name...', + 'LBL_VIEW_IMAGE' => 'view', + 'LBL_VIEW_PDF_BUTTON_KEY' => 'P', + 'LBL_VIEW_PDF_BUTTON_LABEL' => 'Print as PDF', + 'LBL_VIEW_PDF_BUTTON_TITLE' => 'Print as PDF [Alt+P]', + + + 'LNK_ABOUT' => 'About', + 'LNK_ADVANCED_SEARCH' => 'Advanced Search', + 'LNK_BASIC_SEARCH' => 'Basic Search', + 'LBL_MODIFY_CURRENT_SEARCH'=> 'Modify current search', + 'LNK_SAVED_VIEWS' => 'Layout Options', + 'LNK_DELETE_ALL' => 'del all', + 'LNK_DELETE' => 'del', + 'LNK_EDIT' => 'edit', + 'LNK_GET_LATEST'=>'Get latest', + 'LNK_GET_LATEST_TOOLTIP'=>'Replace with latest version', + 'LNK_HELP' => 'Help', + 'LNK_CREATE' => 'Create', + 'LNK_LIST_END' => 'End', + 'LNK_LIST_NEXT' => 'Next', + 'LNK_LIST_PREVIOUS' => 'Previous', + 'LNK_LIST_RETURN' => 'Return to List', + 'LNK_LIST_START' => 'Start', + 'LNK_LOAD_SIGNED'=>'Sign', + 'LNK_LOAD_SIGNED_TOOLTIP'=>'Replace with signed document', + 'LNK_PRINT' => 'Print', + 'LNK_BACKTOTOP' => 'Back to top', + 'LNK_REMOVE' => 'rem', + 'LNK_RESUME' => 'Resume', + 'LNK_VIEW_CHANGE_LOG' => 'View Change Log', + + + 'NTC_CLICK_BACK' => 'Please click the browser back button and fix the error.', + 'NTC_DATE_FORMAT' => '(yyyy-mm-dd)', + 'NTC_DATE_TIME_FORMAT' => '(yyyy-mm-dd 24:00)', + 'NTC_DELETE_CONFIRMATION_MULTIPLE' => 'Are you sure you want to delete selected record(s)?', + 'NTC_TEMPLATE_IS_USED' => 'The template is used in at least one email marketing record or system settings. Are you sure you want to delete it?', + 'NTC_TEMPLATES_IS_USED' => "The following templates are used in email marketing records or system settings. Are you sure you want to delete them?\n", + + 'NTC_DELETE_CONFIRMATION' => 'Are you sure you want to delete this record?', + 'NTC_DELETE_CONFIRMATION_NUM' => 'Are you sure you want to delete the ', + 'NTC_UPDATE_CONFIRMATION_NUM' => 'Are you sure you want to update the ', + 'NTC_DELETE_SELECTED_RECORDS' =>' selected record(s)?', + 'NTC_LOGIN_MESSAGE' => 'Please enter your user name and password.', + 'NTC_NO_ITEMS_DISPLAY' => 'none', + 'NTC_REMOVE_CONFIRMATION' => 'Are you sure you want to remove this relationship? Only the relationship will be removed. The record will not be deleted.', + 'NTC_REQUIRED' => 'Indicates required field', + 'NTC_SUPPORT_SUGARCRM' => 'Support the SugarCRM open source project with a donation through PayPal - it\'s fast, free and secure!', + 'NTC_TIME_FORMAT' => '(24:00)', + 'NTC_WELCOME' => 'Welcome', + 'NTC_YEAR_FORMAT' => '(yyyy)', + 'LOGIN_LOGO_ERROR'=> 'Please replace the SugarCRM logos.', + 'ERROR_FULLY_EXPIRED'=> "Your company's license for SugarCRM has expired for more than 30 days and needs to be brought up to date. Only admins may login.", + 'ERROR_LICENSE_EXPIRED'=> "Your company's license for SugarCRM needs to be updated. Only admins may login", + 'ERROR_LICENSE_VALIDATION'=> "Your company's license for SugarCRM needs to be validated. Only admins may login", + 'WARN_LICENSE_SEATS'=> "Warning: The number of active users is already the maximum number of licenses allowed.", + 'WARN_LICENSE_SEATS_MAXED'=> "Warning: The number of active users exceeds the maximum number of licenses allowed.", + 'WARN_ONLY_ADMINS'=> "Only admins may log in.", + 'WARN_UNSAVED_CHANGES'=> "You are about to leave this record without saving any changes you may have made to the record. Are you sure you want to navigate away from this record?", + 'ERROR_NO_RECORD' => 'Error retrieving record. This record may be deleted or you may not be authorized to view it.', + 'ERROR_TYPE_NOT_VALID' => 'Error. This type is not valid.', + 'LBL_DUP_MERGE'=>'Find Duplicates', + 'LBL_MANAGE_SUBSCRIPTIONS'=>'Manage Subscriptions', + 'LBL_MANAGE_SUBSCRIPTIONS_FOR'=>'Manage Subscriptions for ', + 'LBL_SUBSCRIBE'=>'Subscribe', + 'LBL_UNSUBSCRIBE'=>'Unsubscribe', + // Ajax status strings + 'LBL_LOADING' => 'Loading ...', + 'LBL_SEARCHING' => 'Searching...', + 'LBL_SAVING_LAYOUT' => 'Saving Layout ...', + 'LBL_SAVED_LAYOUT' => 'Layout has been saved.', + 'LBL_SAVED' => 'Saved', + 'LBL_SAVING' => 'Saving', + 'LBL_FAILED' => 'Failed!', + 'LBL_DISPLAY_COLUMNS' => 'Display Columns', + 'LBL_HIDE_COLUMNS' => 'Hide Columns', + 'LBL_SEARCH_CRITERIA' => 'Search Criteria', + 'LBL_SAVED_VIEWS' => 'Saved Views', + 'LBL_PROCESSING_REQUEST'=>'Processing..', + 'LBL_REQUEST_PROCESSED'=>'Done', + 'LBL_AJAX_FAILURE' => 'Ajax failure', + 'LBL_MERGE_DUPLICATES' => 'Merge', + 'LBL_SAVED_SEARCH_SHORTCUT' => 'Saved Searches', + 'LBL_SEARCH_POPULATE_ONLY'=> 'Perform a search using the search form above', + 'LBL_DETAILVIEW'=>'Detail View', + 'LBL_LISTVIEW'=>'List View', + 'LBL_EDITVIEW'=>'Edit View', + 'LBL_SEARCHFORM'=>'Search Form', + 'LBL_SAVED_SEARCH_ERROR' => 'Please provide a name for this view.', + 'LBL_DISPLAY_LOG' => 'Display Log', + 'ERROR_JS_ALERT_SYSTEM_CLASS' => 'System', + 'ERROR_JS_ALERT_TIMEOUT_TITLE' => 'Session Timeout', + 'ERROR_JS_ALERT_TIMEOUT_MSG_1' => 'Your session is about to timeout in 2 minutes. Please save your work.', + 'ERROR_JS_ALERT_TIMEOUT_MSG_2' =>'Your session has timed out.', + 'MSG_JS_ALERT_MTG_REMINDER_AGENDA' => "\nAgenda: ", + 'MSG_JS_ALERT_MTG_REMINDER_MEETING' => 'Meeting', + 'MSG_JS_ALERT_MTG_REMINDER_CALL' => 'Call', + 'MSG_JS_ALERT_MTG_REMINDER_TIME' => 'Time: ', + 'MSG_JS_ALERT_MTG_REMINDER_LOC' => 'Location: ', + 'MSG_JS_ALERT_MTG_REMINDER_DESC' => 'Description: ', + 'MSG_JS_ALERT_MTG_REMINDER_CALL_MSG' => "\nClick OK to view this call or click Cancel to dismiss this message.", + 'MSG_JS_ALERT_MTG_REMINDER_MEETING_MSG' => "\nClick OK to view this meeting or click Cancel to dismiss this message.", + // contextMenu strings + 'LBL_ADD_TO_FAVORITES' => 'Add to My Favorites', + 'LBL_MARK_AS_FAVORITES' => 'Mark as Favorite', + 'LBL_CREATE_CONTACT' => 'Create Contact', + 'LBL_CREATE_CASE' => 'Create Case', + 'LBL_CREATE_NOTE' => 'Create Note', + 'LBL_CREATE_OPPORTUNITY' => 'Create Opportunity', + 'LBL_SCHEDULE_CALL' => 'Log Call', + 'LBL_SCHEDULE_MEETING' => 'Schedule Meeting', + 'LBL_CREATE_TASK' => 'Create Task', + 'LBL_REMOVE_FROM_FAVORITES' => 'Remove From My Favorites', + //web to lead + 'LBL_GENERATE_WEB_TO_LEAD_FORM' => 'Generate Form', + 'LBL_SAVE_WEB_TO_LEAD_FORM' =>'Save Web To Lead Form', + + 'LBL_PLEASE_SELECT' => 'Please Select', + 'LBL_REDIRECT_URL'=>'Redirect URL', + 'LBL_RELATED_CAMPAIGN' =>'Related campaign', + 'LBL_ADD_ALL_LEAD_FIELDS' => 'Add All Fields', + 'LBL_REMOVE_ALL_LEAD_FIELDS' => 'Remove All Fields', + 'LBL_ONLY_IMAGE_ATTACHMENT' => 'Only image type attachment can be embedded', + 'LBL_REMOVE' => 'Remove', + 'LBL_TRAINING' => 'Support', + 'ERR_DATABASE_CONN_DROPPED'=>'Error executing a query. Possibly, your database dropped the connection. Please refresh this page, you may need to restart you web server.', + 'ERR_MSSQL_DB_CONTEXT' =>'Changed database context to', + 'ERR_MSSQL_WARNING' =>'Warning:', + + //Meta-Data framework + 'ERR_MISSING_VARDEF_NAME' => 'Warning: field [[field]] does not have a mapped entry in [moduleDir] vardefs.php file', + 'ERR_CANNOT_CREATE_METADATA_FILE' => 'Error: File [[file]] is missing. Unable to create because no corresponding HTML file was found.', + 'ERR_CANNOT_FIND_MODULE' => 'Error: Module [module] does not exist.', + 'LBL_ALT_ADDRESS' => 'Other Address:', + 'ERR_SMARTY_UNEQUAL_RELATED_FIELD_PARAMETERS' => 'Error: There are an unequal number of arguments for the \'key\' and \'copy\' elements in the displayParams array.', + 'ERR_SMARTY_MISSING_DISPLAY_PARAMS' => 'Missing index in displayParams Array for: ', + + /* MySugar Framework (for Home and Dashboard) */ + 'LBL_DASHLET_CONFIGURE_GENERAL' => 'General', + 'LBL_DASHLET_CONFIGURE_FILTERS' => 'Filters', + 'LBL_DASHLET_CONFIGURE_MY_ITEMS_ONLY' => 'Only My Items', + 'LBL_DASHLET_CONFIGURE_TITLE' => 'Title', + 'LBL_DASHLET_CONFIGURE_DISPLAY_ROWS' => 'Display Rows', + + // MySugar status strings + 'LBL_CREATING_NEW_PAGE' => 'Creating New Page ...', + 'LBL_NEW_PAGE_FEEDBACK' => 'You have created a new page. You may add new content with the Add Sugar Dashlets menu option.', + 'LBL_DELETE_PAGE_CONFIRM' => 'Are you sure you want to delete this page?', + 'LBL_SAVING_PAGE_TITLE' => 'Saving Page Title ...', + 'LBL_RETRIEVING_PAGE' => 'Retrieving Page ...', + 'LBL_MAX_DASHLETS_REACHED' => 'You have reached the maximum number of Sugar Dashlets your adminstrator has set. Please remove a Sugar Dashlet to add more.', + 'LBL_ADDING_DASHLET' => 'Adding Sugar Dashlet ...', + 'LBL_ADDED_DASHLET' => 'Sugar Dashlet Added', + 'LBL_REMOVE_DASHLET_CONFIRM' => 'Are you sure you want to remove the Sugar Dashlet?', + 'LBL_REMOVING_DASHLET' => 'Removing Sugar Dashlet ...', + 'LBL_REMOVED_DASHLET' => 'Sugar Dashlet Removed', + + // MySugar Menu Options + 'LBL_ADD_PAGE' => 'Add Page', + 'LBL_DELETE_PAGE' => 'Delete Page', + 'LBL_CHANGE_LAYOUT' => 'Change Layout', + 'LBL_RENAME_PAGE' => 'Rename Page', + + 'LBL_LOADING_PAGE' => 'Loading page, please wait...', + + 'LBL_RELOAD_PAGE' => 'Please reload the window to use this Sugar Dashlet.', + 'LBL_ADD_DASHLETS' => 'Add Dashlets', + 'LBL_CLOSE_DASHLETS' => 'Close', + 'LBL_OPTIONS' => 'Options', + 'LBL_NUMBER_OF_COLUMNS' => 'Select the number of columns', + 'LBL_1_COLUMN' => '1 Column', + 'LBL_2_COLUMN' => '2 Column', + 'LBL_3_COLUMN' => '3 Column', + 'LBL_PAGE_NAME' => 'Page Name', + + 'LBL_SEARCH_RESULTS' => 'Search Results', + 'LBL_SEARCH_MODULES' => 'Modules', + 'LBL_SEARCH_CHARTS' => 'Charts', + 'LBL_SEARCH_REPORT_CHARTS' => 'Report Charts', + 'LBL_SEARCH_TOOLS' => 'Tools', + 'LBL_SEARCH_HELP_TITLE' => 'Search Tips', + 'LBL_SEARCH_HELP_CLOSE_TOOLTIP' => 'Close', + + 'ERR_BLANK_PAGE_NAME' => 'Please enter a page name.', + /* End MySugar Framework strings */ + + 'LBL_NO_IMAGE' => 'No Image', + + 'LBL_MODULE' => 'Module', + + //adding a label for address copy from left + 'LBL_COPY_ADDRESS_FROM_LEFT' => 'Copy address from left:', + 'LBL_SAVE_AND_CONTINUE' => 'Save and Continue', + + 'LBL_SEARCH_HELP_TEXT' => '


    Multiselect controls

    • Click on the values to select an attribute.
    • Ctrl-click to select multiple. Mac users use CMD-click.
    • To select all values between two attributes,  click first value and then shift-click last value.

    Advanced Search & Layout Options

    Using the Saved Search & Layout option, you can save a set of search parameters and/or a custom List View layout in order to quickly obtain the desired search results in the future. You can save an unlimited number of custom searches and layouts. All saved searches appear by name in the Saved Searches list, with the last loaded saved search appearing at the top of the list.

    To customize the List View layout, use the Hide Columns and Display Columns boxes to select which fields to display in the search results. For example, you can view or hide details such as the record name, and assigned user, and assigned team in the search results. To add a column to List View, select the field from the Hide Columns list and use the left arrow to move it to the Display Columns list. To remove a column from List View, select it from the Display Columns list and use the right arrow to move it to the Hide Columns list.

    If you save layout settings, you will be able to load them at any time to view the search results in the custom layout.

    To save and update a search and/or layout:

    1. Enter a name for the search results in the Save this search as field and click Save.The name now displays in the Saved Searches list adjacent to the Clear button.
    2. To view a saved search, select it from the Saved Searches list. The search results are displayed in the List View.
    3. To update the properties of a saved search, select the saved search from the list, enter the new search criteria and/or layout options in the Advanced Search area, and click Update next to Modify Current Search.
    4. To delete a saved search, select it in the Saved Searches list, click Delete next to Modify Current Search, and then click OK to confirm the deletion.

    Tips

    By using the % as a wildcard operator you can make your search more broad. For example insead of just searching for results that equal "Apples" you could change your search to "Apples%" which would match all results that start with the word Apples but could contain other characters as well.

    ' , + + //resource management + 'ERR_QUERY_LIMIT' => 'Error: Query limit of $limit reached for $module module.', + 'ERROR_NOTIFY_OVERRIDE' => 'Error: ResourceObserver->notify() needs to be overridden.', + + //tracker labels + 'ERR_MONITOR_FILE_MISSING' => 'Error: Unable to create monitor because metadata file is empty or file does not exist.', + 'ERR_MONITOR_NOT_CONFIGURED' => 'Error: There is no monitor configured for requested name', + 'ERR_UNDEFINED_METRIC' => 'Error: Unable to set value for undefined metric', + 'ERR_STORE_FILE_MISSING' => 'Error: Unable to find Store implementation file', + + 'LBL_MONITOR_ID' => 'Monitor Id', + 'LBL_USER_ID' => 'User Id', + 'LBL_MODULE_NAME' => 'Module Name', + 'LBL_ITEM_ID' => 'Item Id', + 'LBL_ITEM_SUMMARY' => 'Item Summary', + 'LBL_ACTION' => 'Action', + 'LBL_SESSION_ID' => 'Session Id', + 'LBL_BREADCRUMBSTACK_CREATED' => 'BreadCrumbStack created for user id {0}', + 'LBL_VISIBLE' => 'Record Visible', + 'LBL_DATE_LAST_ACTION' => 'Date of Last Action', + + + + + //jc:#12287 - For javascript validation messages + 'MSG_IS_NOT_BEFORE' => 'is not before', + 'MSG_IS_MORE_THAN' => 'is more than', + 'MSG_IS_LESS_THAN' => 'is less than', + 'MSG_SHOULD_BE' => 'should be', + 'MSG_OR_GREATER' => 'or greater', + + 'LBL_PORTAL_WELCOME_TITLE' => 'Welcome to Sugar Portal 5.1.0', + 'LBL_PORTAL_WELCOME_INFO' => 'Sugar Portal is a framework which provides real-time view of cases, bugs & newsletters etc to customers. This is an external facing interface to Sugar that can be deployed within any website. Stay tuned for more customer self service features like Project Management and Forums in our future releases.', + 'LBL_LIST' => 'List', + 'LBL_CREATE_CASE' => 'Create Case', + 'LBL_CREATE_BUG' => 'Create Bug', + 'LBL_NO_RECORDS_FOUND' => '- 0 Records Found -', + + 'DATA_TYPE_DUE' => 'Due:', + 'DATA_TYPE_START' => 'Start:', + 'DATA_TYPE_SENT' => 'Sent:', + 'DATA_TYPE_MODIFIED' => 'Modified:', + + + //jchi at 608/06/2008 10913am china time for the bug 12253. + 'LBL_REPORT_NEWREPORT_COLUMNS_TAB_COUNT' => 'Count', + //jchi #19433 + 'LBL_OBJECT_IMAGE' => 'object image', + //jchi #12300 + 'LBL_MASSUPDATE_DATE' => 'Select Date', + + 'LBL_VALIDATE_RANGE' => 'is not within the valid range', + + //jchi # 20776 + 'LBL_DROPDOWN_LIST_ALL' => 'All', + + 'LBL_OPERATOR_IN_TEXT' => 'is one of the following:', + 'LBL_OPERATOR_NOT_IN_TEXT' => 'is not one of the following:', + + + //Connector + 'ERR_CONNECTOR_FILL_BEANS_SIZE_MISMATCH' => 'Error: The Array count of the bean parameter does not match the Array count of the results.', + 'ERR_MISSING_MAPPING_ENTRY_FORM_MODULE' => 'Error: Missing mapping entry for module.', + 'ERROR_UNABLE_TO_RETRIEVE_DATA' => 'Error: Unable to retrieve data for {0} Connector. The service may currently be inaccessible or the configuration settings may be invalid. Connector error message: ({1}).', + 'LBL_MERGE_CONNECTORS' => 'Get Data', + 'LBL_MERGE_CONNECTORS_BUTTON_KEY' => '[D]', + 'LBL_REMOVE_MODULE_ENTRY' => 'Are you sure you want to disable connector integration for this module?', + + // fastcgi checks + 'LBL_FASTCGI_LOGGING' => 'For optimal experience using IIS/FastCGI sapi, set fastcgi.logging to 0 in your php.ini file.', + + //cma + 'LBL_MASSUPDATE_DELETE_GLOBAL_TEAM'=> 'The Global team cannot be deleted.', + 'LBL_MASSUPDATE_DELETE_USER_EXISTS'=>'This private team [{0}] cannot be deleted until the user [{1}] is deleted.', + + //martin #25548 + 'LBL_NO_FLASH_PLAYER' => 'You either have Abobe Flash turned off or are using an older version of the Adobe Flash Player. To get the latest version of the Flash Player, click here.', + //Collection Field + 'LBL_COLLECTION_NAME' => 'Name', + 'LBL_COLLECTION_PRIMARY' => 'Primary', + 'ERROR_MISSING_COLLECTION_SELECTION' => 'Empty required field', + 'LBL_COLLECTION_EXACT' => 'Exact', + + // fastcgi checks + 'LBL_FASTCGI_LOGGING' => 'For optimal experience using IIS/FastCGI sapi, set fastcgi.logging to 0 in your php.ini file.', + //MB -Fixed Bug #32812 -Max + 'LBL_ASSIGNED_TO_NAME' => 'Assigned to', + 'LBL_DESCRIPTION' => 'Description', + + 'LBL_NONE' => '-none-', + 'LBL_YESTERDAY'=> 'yesterday', + 'LBL_TODAY'=>'today', + 'LBL_TOMORROW'=>'tomorrow', + 'LBL_NEXT_WEEK'=> 'next week', + 'LBL_NEXT_MONDAY'=>'next monday', + 'LBL_NEXT_FRIDAY'=>'next friday', + 'LBL_TWO_WEEKS'=> 'two weeks', + 'LBL_NEXT_MONTH'=> 'next month', + 'LBL_FIRST_DAY_OF_NEXT_MONTH'=> 'first day of next month', + 'LBL_THREE_MONTHS'=> 'three months', + 'LBL_SIXMONTHS'=> 'six months', + 'LBL_NEXT_YEAR'=> 'next year', + 'LBL_FILTERED' => 'Filtered', + + //Datetimecombo fields + 'LBL_HOURS' => 'Hours', + 'LBL_MINUTES' => 'Minutes', + 'LBL_MERIDIEM' => 'Meridiem', + 'LBL_DATE' => 'Date', + 'LBL_DASHLET_CONFIGURE_AUTOREFRESH' => 'Auto-Refresh', + + //Calendar widget labels + 'LBL_CHOOSE_MONTH' => 'Choose Month', + 'LBL_ENTER_YEAR' => 'Enter Year', + 'LBL_ENTER_VALID_YEAR' => 'Please enter a valid year', + + //SugarFieldPhone labels + 'LBL_INVALID_USA_PHONE_FORMAT' => 'Please enter a numeric U.S. phone number, including area code.', + + //File write error label + 'ERR_FILE_WRITE' => 'Error: Could not write file {0}. Please check system and web server permissions.', + 'ERR_FILE_NOT_FOUND' => 'Error: Could not load file {0}. Please check system and web server permissions.', + + 'LBL_AND' => 'And', + 'LBL_BEFORE' => 'Before', + + // File fields + 'LBL_UPLOAD_FROM_COMPUTER' => 'Upload From Your Computer', + 'LBL_SEARCH_EXTERNAL_API' => 'File on External Source', + 'LBL_EXTERNAL_SECURITY_LEVEL' => 'Security', + 'LBL_SHARE_PRIVATE' => 'Private', + 'LBL_SHARE_COMPANY' => 'Company', + 'LBL_SHARE_LINKABLE' => 'Linkable', + 'LBL_SHARE_PUBLIC' => 'Public', + + + // Web Services REST RSS + 'LBL_RSS_FEED' => 'RSS Feed', + 'LBL_RSS_RECORDS_FOUND' => 'record(s) found', + 'ERR_RSS_INVALID_INPUT' => 'RSS is not a valid input_type', + 'ERR_RSS_INVALID_RESPONSE' => 'RSS is not a valid response_type for this method', + + //External API Error Messages + 'ERR_GOOGLE_API_415' => 'Google Docs does not support the file format you provided.' + ); + +$app_list_strings['moduleList']['Library'] = 'Library'; +$app_list_strings['library_type'] = array('Books'=>'Book', 'Music'=>'Music', 'DVD'=>'DVD', 'Magazines'=>'Magazines'); +$app_list_strings['moduleList']['EmailAddresses'] = 'Email Address'; +$app_list_strings['project_priority_default'] = 'Medium'; +$app_list_strings['project_priority_options'] = array ( + 'High' => 'High', + 'Medium' => 'Medium', + 'Low' => 'Low', +); + + +$app_list_strings['kbdocument_status_dom'] = array ( + 'Draft' => 'Draft', + 'Expired' => 'Expired', + 'In Review' => 'In Review', + 'Published' => 'Published', + ); + + $app_list_strings['kbadmin_actions_dom'] = + array ( + '' => '--Admin Actions--', + 'Create New Tag' => 'Create New Tag', + 'Delete Tag'=>'Delete Tag', + 'Rename Tag'=>'Rename Tag', + 'Move Selected Articles'=>'Move Selected Articles', + 'Apply Tags On Articles'=>'Apply Tags To Articles', + 'Delete Selected Articles'=>'Delete Selected Articles', + ); + + + $app_list_strings['kbdocument_attachment_option_dom'] = + array( + ''=>'', + 'some' => 'Has Attachments', + 'none' => 'Has None', + 'mime' => 'Specify Mime Type', + 'name' => 'Specify Name', + ); + + $app_list_strings['moduleList']['KBDocuments'] = 'Knowledge Base'; + $app_strings['LBL_CREATE_KB_DOCUMENT'] = 'Create Article'; + $app_list_strings['kbdocument_viewing_frequency_dom'] = + array( + ''=>'', + 'Top_5' => 'Top 5', + 'Top_10' => 'Top 10', + 'Top_20' => 'Top 20', + 'Bot_5' => 'Bottom 5', + 'Bot_10' => 'Bottom 10', + 'Bot_20' => 'Bottom 20', + ); + + $app_list_strings['kbdocument_canned_search'] = + array( + 'all'=>'All', + 'added' => 'Added Last 30 days', + 'pending' => 'Pending my Approval', + 'updated' =>'Updated Last 30 days', + 'faqs' => 'FAQs', + ); + $app_list_strings['kbdocument_date_filter_options'] = + array( + '' => '', + 'on' => 'On', + 'before' => 'Before', + 'after' => 'After', + 'between_dates' => 'Is Between', + 'last_7_days' => 'Last 7 Days', + 'next_7_days' => 'Next 7 Days', + 'last_month' => 'Last Month', + 'this_month' => 'This Month', + 'next_month' => 'Next Month', + 'last_30_days' => 'Last 30 Days', + 'next_30_days' => 'Next 30 Days', + 'last_year' => 'Last Year', + 'this_year' => 'This Year', + 'next_year' => 'Next Year', + 'isnull' => 'Is Null', + ); + + $app_list_strings['countries_dom'] = array( + '' => '', + 'ABU DHABI' => 'ABU DHABI', + 'ADEN' => 'ADEN', + 'AFGHANISTAN' => 'AFGHANISTAN', + 'ALBANIA' => 'ALBANIA', + 'ALGERIA' => 'ALGERIA', + 'AMERICAN SAMOA' => 'AMERICAN SAMOA', + 'ANDORRA' => 'ANDORRA', + 'ANGOLA' => 'ANGOLA', + 'ANTARCTICA' => 'ANTARCTICA', + 'ANTIGUA' => 'ANTIGUA', + 'ARGENTINA' => 'ARGENTINA', + 'ARMENIA' => 'ARMENIA', + 'ARUBA' => 'ARUBA', + 'AUSTRALIA' => 'AUSTRALIA', + 'AUSTRIA' => 'AUSTRIA', + 'AZERBAIJAN' => 'AZERBAIJAN', + 'BAHAMAS' => 'BAHAMAS', + 'BAHRAIN' => 'BAHRAIN', + 'BANGLADESH' => 'BANGLADESH', + 'BARBADOS' => 'BARBADOS', + 'BELARUS' => 'BELARUS', + 'BELGIUM' => 'BELGIUM', + 'BELIZE' => 'BELIZE', + 'BENIN' => 'BENIN', + 'BERMUDA' => 'BERMUDA', + 'BHUTAN' => 'BHUTAN', + 'BOLIVIA' => 'BOLIVIA', + 'BOSNIA' => 'BOSNIA', + 'BOTSWANA' => 'BOTSWANA', + 'BOUVET ISLAND' => 'BOUVET ISLAND', + 'BRAZIL' => 'BRAZIL', + 'BRITISH ANTARCTICA TERRITORY' => 'BRITISH ANTARCTICA TERRITORY', + 'BRITISH INDIAN OCEAN TERRITORY' => 'BRITISH INDIAN OCEAN TERRITORY', + 'BRITISH VIRGIN ISLANDS' => 'BRITISH VIRGIN ISLANDS', + 'BRITISH WEST INDIES' => 'BRITISH WEST INDIES', + 'BRUNEI' => 'BRUNEI', + 'BULGARIA' => 'BULGARIA', + 'BURKINA FASO' => 'BURKINA FASO', + 'BURUNDI' => 'BURUNDI', + 'CAMBODIA' => 'CAMBODIA', + 'CAMEROON' => 'CAMEROON', + 'CANADA' => 'CANADA', + 'CANAL ZONE' => 'CANAL ZONE', + 'CANARY ISLAND' => 'CANARY ISLAND', + 'CAPE VERDI ISLANDS' => 'CAPE VERDI ISLANDS', + 'CAYMAN ISLANDS' => 'CAYMAN ISLANDS', + 'CEVLON' => 'CEVLON', + 'CHAD' => 'CHAD', + 'CHANNEL ISLAND UK' => 'CHANNEL ISLAND UK', + 'CHILE' => 'CHILE', + 'CHINA' => 'CHINA', + 'CHRISTMAS ISLAND' => 'CHRISTMAS ISLAND', + 'COCOS (KEELING) ISLAND' => 'COCOS (KEELING) ISLAND', + 'COLOMBIA' => 'COLOMBIA', + 'COMORO ISLANDS' => 'COMORO ISLANDS', + 'CONGO' => 'CONGO', + 'CONGO KINSHASA' => 'CONGO KINSHASA', + 'COOK ISLANDS' => 'COOK ISLANDS', + 'COSTA RICA' => 'COSTA RICA', + 'CROATIA' => 'CROATIA', + 'CUBA' => 'CUBA', + 'CURACAO' => 'CURACAO', + 'CYPRUS' => 'CYPRUS', + 'CZECH REPUBLIC' => 'CZECH REPUBLIC', + 'DAHOMEY' => 'DAHOMEY', + 'DENMARK' => 'DENMARK', + 'DJIBOUTI' => 'DJIBOUTI', + 'DOMINICA' => 'DOMINICA', + 'DOMINICAN REPUBLIC' => 'DOMINICAN REPUBLIC', + 'DUBAI' => 'DUBAI', + 'ECUADOR' => 'ECUADOR', + 'EGYPT' => 'EGYPT', + 'EL SALVADOR' => 'EL SALVADOR', + 'EQUATORIAL GUINEA' => 'EQUATORIAL GUINEA', + 'ESTONIA' => 'ESTONIA', + 'ETHIOPIA' => 'ETHIOPIA', + 'FAEROE ISLANDS' => 'FAEROE ISLANDS', + 'FALKLAND ISLANDS' => 'FALKLAND ISLANDS', + 'FIJI' => 'FIJI', + 'FINLAND' => 'FINLAND', + 'FRANCE' => 'FRANCE', + 'FRENCH GUIANA' => 'FRENCH GUIANA', + 'FRENCH POLYNESIA' => 'FRENCH POLYNESIA', + 'GABON' => 'GABON', + 'GAMBIA' => 'GAMBIA', + 'GEORGIA' => 'GEORGIA', + 'GERMANY' => 'GERMANY', + 'GHANA' => 'GHANA', + 'GIBRALTAR' => 'GIBRALTAR', + 'GREECE' => 'GREECE', + 'GREENLAND' => 'GREENLAND', + 'GUADELOUPE' => 'GUADELOUPE', + 'GUAM' => 'GUAM', + 'GUATEMALA' => 'GUATEMALA', + 'GUINEA' => 'GUINEA', + 'GUYANA' => 'GUYANA', + 'HAITI' => 'HAITI', + 'HONDURAS' => 'HONDURAS', + 'HONG KONG' => 'HONG KONG', + 'HUNGARY' => 'HUNGARY', + 'ICELAND' => 'ICELAND', + 'IFNI' => 'IFNI', + 'INDIA' => 'INDIA', + 'INDONESIA' => 'INDONESIA', + 'IRAN' => 'IRAN', + 'IRAQ' => 'IRAQ', + 'IRELAND' => 'IRELAND', + 'ISRAEL' => 'ISRAEL', + 'ITALY' => 'ITALY', + 'IVORY COAST' => 'IVORY COAST', + 'JAMAICA' => 'JAMAICA', + 'JAPAN' => 'JAPAN', + 'JORDAN' => 'JORDAN', + 'KAZAKHSTAN' => 'KAZAKHSTAN', + 'KENYA' => 'KENYA', + 'KOREA' => 'KOREA', + 'KOREA, SOUTH' => 'KOREA, SOUTH', + 'KUWAIT' => 'KUWAIT', + 'KYRGYZSTAN' => 'KYRGYZSTAN', + 'LAOS' => 'LAOS', + 'LATVIA' => 'LATVIA', + 'LEBANON' => 'LEBANON', + 'LEEWARD ISLANDS' => 'LEEWARD ISLANDS', + 'LESOTHO' => 'LESOTHO', + 'LIBYA' => 'LIBYA', + 'LIECHTENSTEIN' => 'LIECHTENSTEIN', + 'LITHUANIA' => 'LITHUANIA', + 'LUXEMBOURG' => 'LUXEMBOURG', + 'MACAO' => 'MACAO', + 'MACEDONIA' => 'MACEDONIA', + 'MADAGASCAR' => 'MADAGASCAR', + 'MALAWI' => 'MALAWI', + 'MALAYSIA' => 'MALAYSIA', + 'MALDIVES' => 'MALDIVES', + 'MALI' => 'MALI', + 'MALTA' => 'MALTA', + 'MARTINIQUE' => 'MARTINIQUE', + 'MAURITANIA' => 'MAURITANIA', + 'MAURITIUS' => 'MAURITIUS', + 'MELANESIA' => 'MELANESIA', + 'MEXICO' => 'MEXICO', + 'MOLDOVIA' => 'MOLDOVIA', + 'MONACO' => 'MONACO', + 'MONGOLIA' => 'MONGOLIA', + 'MOROCCO' => 'MOROCCO', + 'MOZAMBIQUE' => 'MOZAMBIQUE', + 'MYANAMAR' => 'MYANAMAR', + 'NAMIBIA' => 'NAMIBIA', + 'NEPAL' => 'NEPAL', + 'NETHERLANDS' => 'NETHERLANDS', + 'NETHERLANDS ANTILLES' => 'NETHERLANDS ANTILLES', + 'NETHERLANDS ANTILLES NEUTRAL ZONE' => 'NETHERLANDS ANTILLES NEUTRAL ZONE', + 'NEW CALADONIA' => 'NEW CALADONIA', + 'NEW HEBRIDES' => 'NEW HEBRIDES', + 'NEW ZEALAND' => 'NEW ZEALAND', + 'NICARAGUA' => 'NICARAGUA', + 'NIGER' => 'NIGER', + 'NIGERIA' => 'NIGERIA', + 'NORFOLK ISLAND' => 'NORFOLK ISLAND', + 'NORWAY' => 'NORWAY', + 'OMAN' => 'OMAN', + 'OTHER' => 'OTHER', + 'PACIFIC ISLAND' => 'PACIFIC ISLAND', + 'PAKISTAN' => 'PAKISTAN', + 'PANAMA' => 'PANAMA', + 'PAPUA NEW GUINEA' => 'PAPUA NEW GUINEA', + 'PARAGUAY' => 'PARAGUAY', + 'PERU' => 'PERU', + 'PHILIPPINES' => 'PHILIPPINES', + 'POLAND' => 'POLAND', + 'PORTUGAL' => 'PORTUGAL', + 'PORTUGUESE TIMOR' => 'PORTUGUESE TIMOR', + 'PUERTO RICO' => 'PUERTO RICO', + 'QATAR' => 'QATAR', + 'REPUBLIC OF BELARUS' => 'REPUBLIC OF BELARUS', + 'REPUBLIC OF SOUTH AFRICA' => 'REPUBLIC OF SOUTH AFRICA', + 'REUNION' => 'REUNION', + 'ROMANIA' => 'ROMANIA', + 'RUSSIA' => 'RUSSIA', + 'RWANDA' => 'RWANDA', + 'RYUKYU ISLANDS' => 'RYUKYU ISLANDS', + 'SABAH' => 'SABAH', + 'SAN MARINO' => 'SAN MARINO', + 'SAUDI ARABIA' => 'SAUDI ARABIA', + 'SENEGAL' => 'SENEGAL', + 'SERBIA' => 'SERBIA', + 'SEYCHELLES' => 'SEYCHELLES', + 'SIERRA LEONE' => 'SIERRA LEONE', + 'SINGAPORE' => 'SINGAPORE', + 'SLOVAKIA' => 'SLOVAKIA', + 'SLOVENIA' => 'SLOVENIA', + 'SOMALILIAND' => 'SOMALILIAND', + 'SOUTH AFRICA' => 'SOUTH AFRICA', + 'SOUTH YEMEN' => 'SOUTH YEMEN', + 'SPAIN' => 'SPAIN', + 'SPANISH SAHARA' => 'SPANISH SAHARA', + 'SRI LANKA' => 'SRI LANKA', + 'ST. KITTS AND NEVIS' => 'ST. KITTS AND NEVIS', + 'ST. LUCIA' => 'ST. LUCIA', + 'SUDAN' => 'SUDAN', + 'SURINAM' => 'SURINAM', + 'SW AFRICA' => 'SW AFRICA', + 'SWAZILAND' => 'SWAZILAND', + 'SWEDEN' => 'SWEDEN', + 'SWITZERLAND' => 'SWITZERLAND', + 'SYRIA' => 'SYRIA', + 'TAIWAN' => 'TAIWAN', + 'TAJIKISTAN' => 'TAJIKISTAN', + 'TANZANIA' => 'TANZANIA', + 'THAILAND' => 'THAILAND', + 'TONGA' => 'TONGA', + 'TRINIDAD' => 'TRINIDAD', + 'TUNISIA' => 'TUNISIA', + 'TURKEY' => 'TURKEY', + 'UGANDA' => 'UGANDA', + 'UKRAINE' => 'UKRAINE', + 'UNITED ARAB EMIRATES' => 'UNITED ARAB EMIRATES', + 'UNITED KINGDOM' => 'UNITED KINGDOM', + 'UPPER VOLTA' => 'UPPER VOLTA', + 'URUGUAY' => 'URUGUAY', + 'US PACIFIC ISLAND' => 'US PACIFIC ISLAND', + 'US VIRGIN ISLANDS' => 'US VIRGIN ISLANDS', + 'USA' => 'USA', + 'UZBEKISTAN' => 'UZBEKISTAN', + 'VANUATU' => 'VANUATU', + 'VATICAN CITY' => 'VATICAN CITY', + 'VENEZUELA' => 'VENEZUELA', + 'VIETNAM' => 'VIETNAM', + 'WAKE ISLAND' => 'WAKE ISLAND', + 'WEST INDIES' => 'WEST INDIES', + 'WESTERN SAHARA' => 'WESTERN SAHARA', + 'YEMEN' => 'YEMEN', + 'ZAIRE' => 'ZAIRE', + 'ZAMBIA' => 'ZAMBIA', + 'ZIMBABWE' => 'ZIMBABWE', + ); + + $app_list_strings['charset_dom'] = array( + 'BIG-5' => 'BIG-5 (Taiwan and Hong Kong)', + /*'CP866' => 'CP866', // ms-dos Cyrillic */ + /*'CP949' => 'CP949 (Microsoft Korean)', */ + 'CP1251' => 'CP1251 (MS Cyrillic)', + 'CP1252' => 'CP1252 (MS Western European & US)', + 'EUC-CN' => 'EUC-CN (Simplified Chinese GB2312)', + 'EUC-JP' => 'EUC-JP (Unix Japanese)', + 'EUC-KR' => 'EUC-KR (Korean)', + 'EUC-TW' => 'EUC-TW (Taiwanese)', + 'ISO-2022-JP' => 'ISO-2022-JP (Japanese)', + 'ISO-2022-KR' => 'ISO-2022-KR (Korean)', + 'ISO-8859-1' => 'ISO-8859-1 (Western European and US)', + 'ISO-8859-2' => 'ISO-8859-2 (Central and Eastern European)', + 'ISO-8859-3' => 'ISO-8859-3 (Latin 3)', + 'ISO-8859-4' => 'ISO-8859-4 (Latin 4)', + 'ISO-8859-5' => 'ISO-8859-5 (Cyrillic)', + 'ISO-8859-6' => 'ISO-8859-6 (Arabic)', + 'ISO-8859-7' => 'ISO-8859-7 (Greek)', + 'ISO-8859-8' => 'ISO-8859-8 (Hebrew)', + 'ISO-8859-9' => 'ISO-8859-9 (Latin 5)', + 'ISO-8859-10' => 'ISO-8859-10 (Latin 6)', + 'ISO-8859-13' => 'ISO-8859-13 (Latin 7)', + 'ISO-8859-14' => 'ISO-8859-14 (Latin 8)', + 'ISO-8859-15' => 'ISO-8859-15 (Latin 9)', + 'KOI8-R' => 'KOI8-R (Cyrillic Russian)', + 'KOI8-U' => 'KOI8-U (Cyrillic Ukranian)', + 'SJIS' => 'SJIS (MS Japanese)', + 'UTF-8' => 'UTF-8', + ); + + $app_list_strings['timezone_dom'] = array( + + 'Africa/Algiers' => 'Africa/Algiers', + 'Africa/Luanda' => 'Africa/Luanda', + 'Africa/Porto-Novo' => 'Africa/Porto-Novo', + 'Africa/Gaborone' => 'Africa/Gaborone', + 'Africa/Ouagadougou' => 'Africa/Ouagadougou', + 'Africa/Bujumbura' => 'Africa/Bujumbura', + 'Africa/Douala' => 'Africa/Douala', + 'Atlantic/Cape_Verde' => 'Atlantic/Cape_Verde', + 'Africa/Bangui' => 'Africa/Bangui', + 'Africa/Ndjamena' => 'Africa/Ndjamena', + 'Indian/Comoro' => 'Indian/Comoro', + 'Africa/Kinshasa' => 'Africa/Kinshasa', + 'Africa/Lubumbashi' => 'Africa/Lubumbashi', + 'Africa/Brazzaville' => 'Africa/Brazzaville', + 'Africa/Abidjan' => 'Africa/Abidjan', + 'Africa/Djibouti' => 'Africa/Djibouti', + 'Africa/Cairo' => 'Africa/Cairo', + 'Africa/Malabo' => 'Africa/Malabo', + 'Africa/Asmera' => 'Africa/Asmera', + 'Africa/Addis_Ababa' => 'Africa/Addis_Ababa', + 'Africa/Libreville' => 'Africa/Libreville', + 'Africa/Banjul' => 'Africa/Banjul', + 'Africa/Accra' => 'Africa/Accra', + 'Africa/Conakry' => 'Africa/Conakry', + 'Africa/Bissau' => 'Africa/Bissau', + 'Africa/Nairobi' => 'Africa/Nairobi', + 'Africa/Maseru' => 'Africa/Maseru', + 'Africa/Monrovia' => 'Africa/Monrovia', + 'Africa/Tripoli' => 'Africa/Tripoli', + 'Indian/Antananarivo' => 'Indian/Antananarivo', + 'Africa/Blantyre' => 'Africa/Blantyre', + 'Africa/Bamako' => 'Africa/Bamako', + 'Africa/Nouakchott' => 'Africa/Nouakchott', + 'Indian/Mauritius' => 'Indian/Mauritius', + 'Indian/Mayotte' => 'Indian/Mayotte', + 'Africa/Casablanca' => 'Africa/Casablanca', + 'Africa/El_Aaiun' => 'Africa/El_Aaiun', + 'Africa/Maputo' => 'Africa/Maputo', + 'Africa/Windhoek' => 'Africa/Windhoek', + 'Africa/Niamey' => 'Africa/Niamey', + 'Africa/Lagos' => 'Africa/Lagos', + 'Indian/Reunion' => 'Indian/Reunion', + 'Africa/Kigali' => 'Africa/Kigali', + 'Atlantic/St_Helena' => 'Atlantic/St_Helena', + 'Africa/Sao_Tome' => 'Africa/Sao_Tome', + 'Africa/Dakar' => 'Africa/Dakar', + 'Indian/Mahe' => 'Indian/Mahe', + 'Africa/Freetown' => 'Africa/Freetown', + 'Africa/Mogadishu' => 'Africa/Mogadishu', + 'Africa/Johannesburg' => 'Africa/Johannesburg', + 'Africa/Khartoum' => 'Africa/Khartoum', + 'Africa/Mbabane' => 'Africa/Mbabane', + 'Africa/Dar_es_Salaam' => 'Africa/Dar_es_Salaam', + 'Africa/Lome' => 'Africa/Lome', + 'Africa/Tunis' => 'Africa/Tunis', + 'Africa/Kampala' => 'Africa/Kampala', + 'Africa/Lusaka' => 'Africa/Lusaka', + 'Africa/Harare' => 'Africa/Harare', + 'Antarctica/Casey' => 'Antarctica/Casey', + 'Antarctica/Davis' => 'Antarctica/Davis', + 'Antarctica/Mawson' => 'Antarctica/Mawson', + 'Indian/Kerguelen' => 'Indian/Kerguelen', + 'Antarctica/DumontDUrville' => 'Antarctica/DumontDUrville', + 'Antarctica/Syowa' => 'Antarctica/Syowa', + 'Antarctica/Vostok' => 'Antarctica/Vostok', + 'Antarctica/Rothera' => 'Antarctica/Rothera', + 'Antarctica/Palmer' => 'Antarctica/Palmer', + 'Antarctica/McMurdo' => 'Antarctica/McMurdo', + 'Asia/Kabul' => 'Asia/Kabul', + 'Asia/Yerevan' => 'Asia/Yerevan', + 'Asia/Baku' => 'Asia/Baku', + 'Asia/Bahrain' => 'Asia/Bahrain', + 'Asia/Dhaka' => 'Asia/Dhaka', + 'Asia/Thimphu' => 'Asia/Thimphu', + 'Indian/Chagos' => 'Indian/Chagos', + 'Asia/Brunei' => 'Asia/Brunei', + 'Asia/Rangoon' => 'Asia/Rangoon', + 'Asia/Phnom_Penh' => 'Asia/Phnom_Penh', + 'Asia/Beijing' => 'Asia/Beijing', + 'Asia/Harbin' => 'Asia/Harbin', + 'Asia/Shanghai' => 'Asia/Shanghai', + 'Asia/Chongqing' => 'Asia/Chongqing', + 'Asia/Urumqi' => 'Asia/Urumqi', + 'Asia/Kashgar' => 'Asia/Kashgar', + 'Asia/Hong_Kong' => 'Asia/Hong_Kong', + 'Asia/Taipei' => 'Asia/Taipei', + 'Asia/Macau' => 'Asia/Macau', + 'Asia/Nicosia' => 'Asia/Nicosia', + 'Asia/Tbilisi' => 'Asia/Tbilisi', + 'Asia/Dili' => 'Asia/Dili', + 'Asia/Calcutta' => 'Asia/Calcutta', + 'Asia/Jakarta' => 'Asia/Jakarta', + 'Asia/Pontianak' => 'Asia/Pontianak', + 'Asia/Makassar' => 'Asia/Makassar', + 'Asia/Jayapura' => 'Asia/Jayapura', + 'Asia/Tehran' => 'Asia/Tehran', + 'Asia/Baghdad' => 'Asia/Baghdad', + 'Asia/Jerusalem' => 'Asia/Jerusalem', + 'Asia/Tokyo' => 'Asia/Tokyo', + 'Asia/Amman' => 'Asia/Amman', + 'Asia/Almaty' => 'Asia/Almaty', + 'Asia/Qyzylorda' => 'Asia/Qyzylorda', + 'Asia/Aqtobe' => 'Asia/Aqtobe', + 'Asia/Aqtau' => 'Asia/Aqtau', + 'Asia/Oral' => 'Asia/Oral', + 'Asia/Bishkek' => 'Asia/Bishkek', + 'Asia/Seoul' => 'Asia/Seoul', + 'Asia/Pyongyang' => 'Asia/Pyongyang', + 'Asia/Kuwait' => 'Asia/Kuwait', + 'Asia/Vientiane' => 'Asia/Vientiane', + 'Asia/Beirut' => 'Asia/Beirut', + 'Asia/Kuala_Lumpur' => 'Asia/Kuala_Lumpur', + 'Asia/Kuching' => 'Asia/Kuching', + 'Indian/Maldives' => 'Indian/Maldives', + 'Asia/Hovd' => 'Asia/Hovd', + 'Asia/Ulaanbaatar' => 'Asia/Ulaanbaatar', + 'Asia/Choibalsan' => 'Asia/Choibalsan', + 'Asia/Katmandu' => 'Asia/Katmandu', + 'Asia/Muscat' => 'Asia/Muscat', + 'Asia/Karachi' => 'Asia/Karachi', + 'Asia/Gaza' => 'Asia/Gaza', + 'Asia/Manila' => 'Asia/Manila', + 'Asia/Qatar' => 'Asia/Qatar', + 'Asia/Riyadh' => 'Asia/Riyadh', + 'Asia/Singapore' => 'Asia/Singapore', + 'Asia/Colombo' => 'Asia/Colombo', + 'Asia/Damascus' => 'Asia/Damascus', + 'Asia/Dushanbe' => 'Asia/Dushanbe', + 'Asia/Bangkok' => 'Asia/Bangkok', + 'Asia/Ashgabat' => 'Asia/Ashgabat', + 'Asia/Dubai' => 'Asia/Dubai', + 'Asia/Samarkand' => 'Asia/Samarkand', + 'Asia/Tashkent' => 'Asia/Tashkent', + 'Asia/Saigon' => 'Asia/Saigon', + 'Asia/Aden' => 'Asia/Aden', + 'Australia/Darwin' => 'Australia/Darwin', + 'Australia/Perth' => 'Australia/Perth', + 'Australia/Brisbane' => 'Australia/Brisbane', + 'Australia/Lindeman' => 'Australia/Lindeman', + 'Australia/Adelaide' => 'Australia/Adelaide', + 'Australia/Hobart' => 'Australia/Hobart', + 'Australia/Currie' => 'Australia/Currie', + 'Australia/Melbourne' => 'Australia/Melbourne', + 'Australia/Sydney' => 'Australia/Sydney', + 'Australia/Broken_Hill' => 'Australia/Broken_Hill', + 'Indian/Christmas' => 'Indian/Christmas', + 'Pacific/Rarotonga' => 'Pacific/Rarotonga', + 'Indian/Cocos' => 'Indian/Cocos', + 'Pacific/Fiji' => 'Pacific/Fiji', + 'Pacific/Gambier' => 'Pacific/Gambier', + 'Pacific/Marquesas' => 'Pacific/Marquesas', + 'Pacific/Tahiti' => 'Pacific/Tahiti', + 'Pacific/Guam' => 'Pacific/Guam', + 'Pacific/Tarawa' => 'Pacific/Tarawa', + 'Pacific/Enderbury' => 'Pacific/Enderbury', + 'Pacific/Kiritimati' => 'Pacific/Kiritimati', + 'Pacific/Saipan' => 'Pacific/Saipan', + 'Pacific/Majuro' => 'Pacific/Majuro', + 'Pacific/Kwajalein' => 'Pacific/Kwajalein', + 'Pacific/Truk' => 'Pacific/Truk', + 'Pacific/Ponape' => 'Pacific/Ponape', + 'Pacific/Kosrae' => 'Pacific/Kosrae', + 'Pacific/Nauru' => 'Pacific/Nauru', + 'Pacific/Noumea' => 'Pacific/Noumea', + 'Pacific/Auckland' => 'Pacific/Auckland', + 'Pacific/Chatham' => 'Pacific/Chatham', + 'Pacific/Niue' => 'Pacific/Niue', + 'Pacific/Norfolk' => 'Pacific/Norfolk', + 'Pacific/Palau' => 'Pacific/Palau', + 'Pacific/Port_Moresby' => 'Pacific/Port_Moresby', + 'Pacific/Pitcairn' => 'Pacific/Pitcairn', + 'Pacific/Pago_Pago' => 'Pacific/Pago_Pago', + 'Pacific/Apia' => 'Pacific/Apia', + 'Pacific/Guadalcanal' => 'Pacific/Guadalcanal', + 'Pacific/Fakaofo' => 'Pacific/Fakaofo', + 'Pacific/Tongatapu' => 'Pacific/Tongatapu', + 'Pacific/Funafuti' => 'Pacific/Funafuti', + 'Pacific/Johnston' => 'Pacific/Johnston', + 'Pacific/Midway' => 'Pacific/Midway', + 'Pacific/Wake' => 'Pacific/Wake', + 'Pacific/Efate' => 'Pacific/Efate', + 'Pacific/Wallis' => 'Pacific/Wallis', + 'Europe/London' => 'Europe/London', + 'Europe/Dublin' => 'Europe/Dublin', + 'WET' => 'WET', + 'CET' => 'CET', + 'MET' => 'MET', + 'EET' => 'EET', + 'Europe/Tirane' => 'Europe/Tirane', + 'Europe/Andorra' => 'Europe/Andorra', + 'Europe/Vienna' => 'Europe/Vienna', + 'Europe/Minsk' => 'Europe/Minsk', + 'Europe/Brussels' => 'Europe/Brussels', + 'Europe/Sofia' => 'Europe/Sofia', + 'Europe/Prague' => 'Europe/Prague', + 'Europe/Copenhagen' => 'Europe/Copenhagen', + 'Atlantic/Faeroe' => 'Atlantic/Faeroe', + 'America/Danmarkshavn' => 'America/Danmarkshavn', + 'America/Scoresbysund' => 'America/Scoresbysund', + 'America/Godthab' => 'America/Godthab', + 'America/Thule' => 'America/Thule', + 'Europe/Tallinn' => 'Europe/Tallinn', + 'Europe/Helsinki' => 'Europe/Helsinki', + 'Europe/Paris' => 'Europe/Paris', + 'Europe/Berlin' => 'Europe/Berlin', + 'Europe/Gibraltar' => 'Europe/Gibraltar', + 'Europe/Athens' => 'Europe/Athens', + 'Europe/Budapest' => 'Europe/Budapest', + 'Atlantic/Reykjavik' => 'Atlantic/Reykjavik', + 'Europe/Rome' => 'Europe/Rome', + 'Europe/Riga' => 'Europe/Riga', + 'Europe/Vaduz' => 'Europe/Vaduz', + 'Europe/Vilnius' => 'Europe/Vilnius', + 'Europe/Luxembourg' => 'Europe/Luxembourg', + 'Europe/Malta' => 'Europe/Malta', + 'Europe/Chisinau' => 'Europe/Chisinau', + 'Europe/Monaco' => 'Europe/Monaco', + 'Europe/Amsterdam' => 'Europe/Amsterdam', + 'Europe/Oslo' => 'Europe/Oslo', + 'Europe/Warsaw' => 'Europe/Warsaw', + 'Europe/Lisbon' => 'Europe/Lisbon', + 'Atlantic/Azores' => 'Atlantic/Azores', + 'Atlantic/Madeira' => 'Atlantic/Madeira', + 'Europe/Bucharest' => 'Europe/Bucharest', + 'Europe/Kaliningrad' => 'Europe/Kaliningrad', + 'Europe/Moscow' => 'Europe/Moscow', + 'Europe/Samara' => 'Europe/Samara', + 'Asia/Yekaterinburg' => 'Asia/Yekaterinburg', + 'Asia/Omsk' => 'Asia/Omsk', + 'Asia/Novosibirsk' => 'Asia/Novosibirsk', + 'Asia/Krasnoyarsk' => 'Asia/Krasnoyarsk', + 'Asia/Irkutsk' => 'Asia/Irkutsk', + 'Asia/Yakutsk' => 'Asia/Yakutsk', + 'Asia/Vladivostok' => 'Asia/Vladivostok', + 'Asia/Sakhalin' => 'Asia/Sakhalin', + 'Asia/Magadan' => 'Asia/Magadan', + 'Asia/Kamchatka' => 'Asia/Kamchatka', + 'Asia/Anadyr' => 'Asia/Anadyr', + 'Europe/Belgrade' => 'Europe/Belgrade' , + 'Europe/Madrid' =>'Europe/Madrid' , + 'Africa/Ceuta' => 'Africa/Ceuta', + 'Atlantic/Canary' => 'Atlantic/Canary', + 'Europe/Stockholm' => 'Europe/Stockholm', + 'Europe/Zurich' => 'Europe/Zurich' , + 'Europe/Istanbul' => 'Europe/Istanbul', + 'Europe/Kiev' => 'Europe/Kiev', + 'Europe/Uzhgorod' => 'Europe/Uzhgorod', + 'Europe/Zaporozhye' => 'Europe/Zaporozhye', + 'Europe/Simferopol' => 'Europe/Simferopol', + 'America/New_York' => 'America/New_York', + 'America/Chicago' =>'America/Chicago' , + 'America/North_Dakota/Center' => 'America/North_Dakota/Center', + 'America/Denver' => 'America/Denver', + 'America/Los_Angeles' => 'America/Los_Angeles', + 'America/Juneau' => 'America/Juneau', + 'America/Yakutat' => 'America/Yakutat', + 'America/Anchorage' => 'America/Anchorage', + 'America/Nome' =>'America/Nome' , + 'America/Adak' => 'America/Adak', + 'Pacific/Honolulu' => 'Pacific/Honolulu', + 'America/Phoenix' => 'America/Phoenix', + 'America/Boise' => 'America/Boise', + 'America/Indiana/Indianapolis' => 'America/Indiana/Indianapolis', + 'America/Indiana/Marengo' => 'America/Indiana/Marengo', + 'America/Indiana/Knox' => 'America/Indiana/Knox', + 'America/Indiana/Vevay' => 'America/Indiana/Vevay', + 'America/Kentucky/Louisville' =>'America/Kentucky/Louisville' , + 'America/Kentucky/Monticello' => 'America/Kentucky/Monticello' , + 'America/Detroit' => 'America/Detroit', + 'America/Menominee' => 'America/Menominee', + 'America/St_Johns' => 'America/St_Johns', + 'America/Goose_Bay' => 'America/Goose_Bay' , + 'America/Halifax' => 'America/Halifax', + 'America/Glace_Bay' =>'America/Glace_Bay' , + 'America/Montreal' => 'America/Montreal', + 'America/Toronto' => 'America/Toronto', + 'America/Thunder_Bay' => 'America/Thunder_Bay' , + 'America/Nipigon' => 'America/Nipigon', + 'America/Rainy_River' => 'America/Rainy_River', + 'America/Winnipeg' => 'America/Winnipeg', + 'America/Regina' => 'America/Regina', + 'America/Swift_Current' => 'America/Swift_Current', + 'America/Edmonton' => 'America/Edmonton', + 'America/Vancouver' => 'America/Vancouver', + 'America/Dawson_Creek' => 'America/Dawson_Creek', + 'America/Pangnirtung' => 'America/Pangnirtung' , + 'America/Iqaluit' => 'America/Iqaluit' , + 'America/Coral_Harbour' => 'America/Coral_Harbour' , + 'America/Rankin_Inlet' => 'America/Rankin_Inlet', + 'America/Cambridge_Bay' => 'America/Cambridge_Bay', + 'America/Yellowknife' => 'America/Yellowknife', + 'America/Inuvik' =>'America/Inuvik' , + 'America/Whitehorse' => 'America/Whitehorse' , + 'America/Dawson' => 'America/Dawson', + 'America/Cancun' => 'America/Cancun', + 'America/Merida' => 'America/Merida', + 'America/Monterrey' => 'America/Monterrey', + 'America/Mexico_City' => 'America/Mexico_City', + 'America/Chihuahua' => 'America/Chihuahua', + 'America/Hermosillo' => 'America/Hermosillo', + 'America/Mazatlan' => 'America/Mazatlan', + 'America/Tijuana' => 'America/Tijuana', + 'America/Anguilla' => 'America/Anguilla', + 'America/Antigua' => 'America/Antigua', + 'America/Nassau' =>'America/Nassau' , + 'America/Barbados' => 'America/Barbados', + 'America/Belize' => 'America/Belize', + 'Atlantic/Bermuda' => 'Atlantic/Bermuda', + 'America/Cayman' => 'America/Cayman', + 'America/Costa_Rica' => 'America/Costa_Rica', + 'America/Havana' => 'America/Havana', + 'America/Dominica' => 'America/Dominica', + 'America/Santo_Domingo' => 'America/Santo_Domingo', + 'America/El_Salvador' => 'America/El_Salvador', + 'America/Grenada' => 'America/Grenada', + 'America/Guadeloupe' => 'America/Guadeloupe', + 'America/Guatemala' => 'America/Guatemala', + 'America/Port-au-Prince' => 'America/Port-au-Prince', + 'America/Tegucigalpa' => 'America/Tegucigalpa', + 'America/Jamaica' => 'America/Jamaica', + 'America/Martinique' => 'America/Martinique', + 'America/Montserrat' => 'America/Montserrat', + 'America/Managua' => 'America/Managua', + 'America/Panama' => 'America/Panama', + 'America/Puerto_Rico' =>'America/Puerto_Rico' , + 'America/St_Kitts' => 'America/St_Kitts', + 'America/St_Lucia' => 'America/St_Lucia', + 'America/Miquelon' => 'America/Miquelon', + 'America/St_Vincent' => 'America/St_Vincent', + 'America/Grand_Turk' => 'America/Grand_Turk', + 'America/Tortola' => 'America/Tortola', + 'America/St_Thomas' => 'America/St_Thomas', + 'America/Argentina/Buenos_Aires' => 'America/Argentina/Buenos_Aires', + 'America/Argentina/Cordoba' => 'America/Argentina/Cordoba', + 'America/Argentina/Tucuman' => 'America/Argentina/Tucuman', + 'America/Argentina/La_Rioja' => 'America/Argentina/La_Rioja', + 'America/Argentina/San_Juan' => 'America/Argentina/San_Juan', + 'America/Argentina/Jujuy' => 'America/Argentina/Jujuy', + 'America/Argentina/Catamarca' => 'America/Argentina/Catamarca', + 'America/Argentina/Mendoza' => 'America/Argentina/Mendoza', + 'America/Argentina/Rio_Gallegos' => 'America/Argentina/Rio_Gallegos', + 'America/Argentina/Ushuaia' => 'America/Argentina/Ushuaia', + 'America/Aruba' => 'America/Aruba', + 'America/La_Paz' => 'America/La_Paz', + 'America/Noronha' => 'America/Noronha', + 'America/Belem' => 'America/Belem', + 'America/Fortaleza' => 'America/Fortaleza', + 'America/Recife' => 'America/Recife', + 'America/Araguaina' => 'America/Araguaina', + 'America/Maceio' => 'America/Maceio', + 'America/Bahia' => 'America/Bahia', + 'America/Sao_Paulo' => 'America/Sao_Paulo', + 'America/Campo_Grande' => 'America/Campo_Grande', + 'America/Cuiaba' => 'America/Cuiaba', + 'America/Porto_Velho' => 'America/Porto_Velho', + 'America/Boa_Vista' => 'America/Boa_Vista', + 'America/Manaus' => 'America/Manaus', + 'America/Eirunepe' => 'America/Eirunepe', + 'America/Rio_Branco' => 'America/Rio_Branco', + 'America/Santiago' => 'America/Santiago', + 'Pacific/Easter' => 'Pacific/Easter' , + 'America/Bogota' => 'America/Bogota', + 'America/Curacao' => 'America/Curacao', + 'America/Guayaquil' => 'America/Guayaquil', + 'Pacific/Galapagos' => 'Pacific/Galapagos' , + 'Atlantic/Stanley' => 'Atlantic/Stanley', + 'America/Cayenne' => 'America/Cayenne', + 'America/Guyana' => 'America/Guyana', + 'America/Asuncion' => 'America/Asuncion', + 'America/Lima' => 'America/Lima', + 'Atlantic/South_Georgia' => 'Atlantic/South_Georgia', + 'America/Paramaribo' => 'America/Paramaribo', + 'America/Port_of_Spain' => 'America/Port_of_Spain', + 'America/Montevideo' => 'America/Montevideo', + 'America/Caracas' => 'America/Caracas', + ); + + $app_list_strings['moduleList']['Sugar_Favorites'] = 'Favorites'; + $app_list_strings['eapm_list']= array( + 'Sugar'=>'Sugar', + 'WebEx'=>'WebEx', + 'GoToMeeting'=>'GoToMeeting', + 'LotusLive'=>'LotusLive', + 'Google' => 'Google Docs', + 'Box' => 'Box.net', + 'Facebook'=>'Facebook', + 'Twitter'=>'Twitter', + ); + $app_list_strings['LBL_API_TYPE_ENUM'] = array( + 'password' => 'Username/Password', + 'oauth' => 'OAuth', + ); + ?> diff --git a/include/language/en_us.notify_template.html b/include/language/en_us.notify_template.html new file mode 100644 index 00000000..fb1169b7 --- /dev/null +++ b/include/language/en_us.notify_template.html @@ -0,0 +1,352 @@ + + + +SugarCRM Quote - {QUOTE_SUBJECT} + + +{ASSIGNER} has assigned a Quote to {ASSIGNED_USER}. + +Subject: {QUOTE_SUBJECT} +Status: {QUOTE_STATUS} +Expected Close Date: {QUOTE_CLOSEDATE} +Description: {QUOTE_DESCRIPTION} + +You may review this Quote at: +<{URL}> + + + + +SugarCRM Account - {ACCOUNT_NAME} + + +{ASSIGNER} has assigned an Account to {ASSIGNED_USER}. + +Name: {ACCOUNT_NAME} +Type: {ACCOUNT_TYPE} +Description: {ACCOUNT_DESCRIPTION} + +You may review this Account at: +<{URL}> + + + + +SugarCRM Case - {CASE_SUBJECT} + + +{ASSIGNER} has assigned a Case to {ASSIGNED_USER}. + +Subject: {CASE_SUBJECT} +Priority: {CASE_PRIORITY} +Status: {CASE_STATUS} +Description: {CASE_DESCRIPTION} + +You may review this Case at: +<{URL}> + + + + +SugarCRM Task - {TASK_SUBJECT} + + +{ASSIGNER} has assigned a Task to {ASSIGNED_USER}. + +Subject: {TASK_SUBJECT} +Priority: {TASK_PRIORITY} +Due Date: {TASK_DUEDATE} +Status: {TASK_STATUS} +Description: {TASK_DESCRIPTION} + +You may review this Task at: +<{URL}> + + + + +SugarCRM Meeting - {MEETING_SUBJECT} + + +To: {MEETING_TO}, + +{ASSIGNER} has invited you to a Meeting + +Subject: {MEETING_SUBJECT} +Status: {MEETING_STATUS} +Start Date: {MEETING_STARTDATE} +Duration: {MEETING_HOURS}h, {MEETING_MINUTES}m + +Meeting URL: {MEETING_URL} + +Description: {MEETING_DESCRIPTION} + +Accept this meeting: +<{ACCEPT_URL}&accept_status=accept> + +Tentatively Accept this meeting +<{ACCEPT_URL}&accept_status=tentative> + +Decline this meeting +<{ACCEPT_URL}&accept_status=decline> + + + + +SugarCRM Meeting - {MEETING_SUBJECT} + + +{ASSIGNER} has assigned a Meeting to {ASSIGNED_USER}. + +Subject: {MEETING_SUBJECT} +Status: {MEETING_STATUS} +Start Date: {MEETING_STARTDATE} +Duration: {MEETING_HOURS}h, {MEETING_MINUTES}m +Description: {MEETING_DESCRIPTION} + +You may review this Meeting at: +<{URL}> + + + + +SugarCRM Email - {EMAIL_SUBJECT} + + +{ASSIGNER} has assigned an Email to {ASSIGNED_USER}. + +Subject: {EMAIL_SUBJECT} +Date Sent: {EMAIL_DATESENT} + +You may review this Email at: +<{URL}> + + + + + + + + +SugarCRM Contact - {CONTACT_NAME} + + +{ASSIGNER} has assigned a Contact to {ASSIGNED_USER}. + +Name: {CONTACT_NAME} +Description: {CONTACT_DESCRIPTION} + +You may review this Contact at: +<{URL}> + + + + +SugarCRM Lead - {LEAD_NAME} + + +{ASSIGNER} has assigned a Lead to {ASSIGNED_USER}. + +Name: {LEAD_NAME} +Lead Source: {LEAD_SOURCE} +Status: {LEAD_STATUS} +Description: {LEAD_DESCRIPTION} + +You may review this Lead at: +<{URL}> + + + + +SugarCRM Opportunity - {OPPORTUNITY_NAME} + + +{ASSIGNER} has assigned an Opportunity to {ASSIGNED_USER}. + +Name: {OPPORTUNITY_NAME} +Amount: {OPPORTUNITY_AMOUNT} +Expected Close Date: {OPPORTUNITY_CLOSEDATE} +Sales Stage: {OPPORTUNITY_STAGE} +Description: {OPPORTUNITY_DESCRIPTION} + +You may review this Opportunity at: +<{URL}> + + + + +SugarCRM Bug - {BUG_SUBJECT} + + +{ASSIGNER} has assigned a Bug to {ASSIGNED_USER}. + +Bug Number: {BUG_BUG_NUMBER} +Subject: {BUG_SUBJECT} +Type: {BUG_TYPE} +Priority: {BUG_PRIORITY} +Status: {BUG_STATUS} +Resolution: {BUG_RESOLUTION} +Release: {BUG_RELEASE} +Description: {BUG_DESCRIPTION} +Work Log: {BUG_WORK_LOG} + +You may review this Bug at: +<{URL}> + + + + +SugarCRM - Assigned {OBJECT} + + +{ASSIGNER} has assigned a(n) {OBJECT} to {ASSIGNED_USER}. + +You may review this {OBJECT} at: +<{URL}> + + + +SugarCRM Call - {CALL_SUBJECT} + + +To: {CALL_TO}, + {ASSIGNER} has invited you to a Call +Subject: {CALL_SUBJECT} +Status: {CALL_STATUS} +Start Date: {CALL_STARTDATE} +Duration: {CALL_HOURS}h, {CALL_MINUTES}m +Description: {CALL_DESCRIPTION} + +Accept this call: +<{ACCEPT_URL}&accept_status=accept> + +Tentatively Accept this call +<{ACCEPT_URL}&accept_status=tentative> + +Decline this call +<{ACCEPT_URL}&accept_status=decline> + + + + +SugarCRM Call - {CALL_SUBJECT} + + +{ASSIGNER} has assigned a Call to {ASSIGNED_USER}. + +Subject: {CALL_SUBJECT} +Status: {CALL_STATUS} +Start Date: {CALL_STARTDATE} +Duration: {CALL_HOURS}h, {CALL_MINUTES}m +Description: {CALL_DESCRIPTION} + +You may review this Call at: +<{URL}> + + + +SugarCRM Campaign - {CAMPAIGN_NAME} + + +{ASSIGNER} has assigned a Campaign to {ASSIGNED_USER}. + +Subject: {CAMPAIGN_NAME} +Amount: {CAMPAIGN_AMOUNT} +Close Date: {CAMPAIGN_CLOSEDATE} +Status: {CAMPAIGN_STATUS} +Description: {CAMPAIGN_DESCRIPTION} + +You may review this Campaign at: +<{URL}> + + + +SugarCRM Quotas - Your Quota for {QUOTA_TIMEPERIOD} + + +{ASSIGNER} has assigned a Quota to {ASSIGNED_USER}. + +Amount: {QUOTA_AMOUNT} +Timeperiod: {QUOTA_TIMEPERIOD} + +You may review this Quota assignment at: +<{QUOTA_URL}> + + + +SugarCRM Document - {KBDOCUMENT_NAME} + + + +{NOTIFICATION_MESSAGE} + +Name: {KBDOCUMENT_NAME} +Created Date: {KBDOCUMENT_DATE_CREATED} +Created By: {KBDOCUMENT_CREATED_BY} +Status: {KBDOCUMENT_STATUS} +Description: {KBDOCUMENT_DESCRIPTION} + +You may review this Document at: +<{URL}> + + + +SugarCRM Contract - {CONTRACT_NAME} + + + +{ASSIGNER} has assigned a Contract to {ASSIGNED_USER}. + +You may review this Contract at: +<{URL}> + + + +SugarCRM Contract - {CONTRACT_NAME} + + + +Your Contract: {CONTRACT_NAME} will be out of date at {CONTRACT_END_DATE}. + +You may review this Contract at: +<{URL}> + \ No newline at end of file diff --git a/include/language/jsLanguage.php b/include/language/jsLanguage.php new file mode 100644 index 00000000..2e379a3c --- /dev/null +++ b/include/language/jsLanguage.php @@ -0,0 +1,85 @@ +encode($app_list_strings); + $app_strings_encoded = $json->encode($app_strings); + + $str = <<encode($mod_strings); + $str = "SUGAR.language.setLanguage('" . $moduleDir . "', " . $mod_strings_encoded . ");"; + + $cacheDir = create_cache_directory('jsLanguage/' . $moduleDir . '/'); + + if($fh = @fopen($cacheDir . $lang . '.js', "w")){ + fputs($fh, $str); + fclose($fh); + } + } + +} +?> \ No newline at end of file diff --git a/include/modules.php b/include/modules.php new file mode 100644 index 00000000..0b768121 --- /dev/null +++ b/include/modules.php @@ -0,0 +1,293 @@ + list of actions (all says all actions are admin only) + //'Administration'=>array('all'=>1, 'SupportPortal'=>'allow'), + 'Dropdown'=>array('all'=>1), + 'Dynamic'=>array('all'=>1), + 'DynamicFields'=>array('all'=>1), + 'Currencies'=>array('all'=>1), + 'EditCustomFields'=>array('all'=>1), + 'FieldsMetaData'=>array('all'=>1), + 'LabelEditor'=>array('all'=>1), + 'ACL'=>array('all'=>1), + 'ACLActions'=>array('all'=>1), + 'ACLRoles'=>array('all'=>1), + 'UpgradeWizard' => array('all' => 1), + 'Studio' => array('all' => 1), + ); + + +$modInvisList[] = 'ACL'; +$modInvisList[] = 'ACLRoles'; +$modInvisList[] = 'Configurator'; +$modInvisList[] = 'UserPreferences'; +$modInvisList[] = 'SavedSearch'; +// deferred +//$modInvisList[] = 'Queues'; +$modInvisList[] = 'Studio'; +$modInvisList[] = 'Connectors'; + +$beanList['SugarFeed'] = 'SugarFeed'; +$beanFiles['SugarFeed'] = 'modules/SugarFeed/SugarFeed.php'; +$modInvisList[] = 'SugarFeed'; + +// This is the mapping for modules that appear under a different module's tab +// Be sure to also add the modules to $modInvisList, otherwise their tab will still appear +$GLOBALS['moduleTabMap'] = array( + 'UpgradeWizard' => 'Administration', + 'EmailMan' => 'Administration', + 'ModuleBuilder' => 'Administration', + 'Configurator' => 'Administration', + 'Studio' => 'Administration', + 'Currencies' => 'Administration', + 'SugarFeed' => 'Administration', + 'DocumentRevisions' => 'Documents', + 'EmailTemplates' => 'Emails', + 'EmailMarketing' => 'Campaigns', + ); +$beanList['EAPM'] = 'EAPM'; +$beanFiles['EAPM'] = 'modules/EAPM/EAPM.php'; +$modules_exempt_from_availability_check['EAPM'] = 'EAPM'; +$modInvisList[] = 'EAPM'; + + +if (file_exists('include/modules_override.php')) +{ + include('include/modules_override.php'); +} +if (file_exists('custom/application/Ext/Include/modules.ext.php')) +{ + include('custom/application/Ext/Include/modules.ext.php'); +} +?> diff --git a/include/nusoap/changelog b/include/nusoap/changelog new file mode 100644 index 00000000..b76580e2 --- /dev/null +++ b/include/nusoap/changelog @@ -0,0 +1,648 @@ +2003-07-21, version 0.6.5 +- soap_transport_http: SOAPAction header is quoted again, fixes problem w/ Weblogic Server +- applied Jason Levitt patch for proper array serialization, fixes problem w/ Amazon shopping cart services +- fixed null value serialization +- applied patch from "BZC ToOn'S" - fixes wsdl serialization when no parameters +- applied John's patch, implementing compression for the server + +2003-07-22, version 0.6.5 +- soap_server: fixed bug causing charset encoding not to be passed to the parser +- soap_fault: added default encoding to the fault serialization +- soap_parser: changed the parser to pre-load the parent's result array when processing scalar values. This increases parsing speed. + +2003-07-23, version 0.6.5 +- soap_base: fix code that overwrites user-supplied attributes in serialize_val +- soap_base: use arrays-of-arrays rather than attempting multi-dimensional in serialize_val +- xmlschema: emit import statements and qualify all elements with prefix in serializeSchema (better interop with validation tools) +- soapclient: get xml character encoding from HTTP Content-Type header if provided, e.g. text/xml;charset="UTF-8" +- soapclient: use headers in call if provided (previously ignored this parameter) +- soap_server: in parse_request, if neither getallheaders nor $_SERVER are available, use $HTTP_SERVER_VARS to get SOAPAction and xml encoding + +2003-07-24, version 0.6.5 +- soap_transport_http: apply patch from Steven Brown "if the server closes connection prematurely, nusoap would spin trying to read data that isn't there" + +2003-07-25, version 0.6.5 +- wsdl: apply patch from Sven to workaround single schema limitation +- wsdl: apply a variant of the patch from Holger to handle empty values for array by serializing an array with 0 elements +- xmlschema: remove the redundant default namespace attribute on the schema element; everything in xsd is explicitly specified as being from xsd +- soap_transport_http: fix setCredentials and add TODO comments in sendHTTPS about what to change if this setCredentials stays + +2003-07-30, version 0.6.5 +- nusoap_base: change documentation of soap_defencoding to specify it is the encoding for outgoing messages +- nusoap_base: only change &, <, > to entities, not all HTML entities +- soap_transport_http: update the Content-Type header in sendRequest, since soap_defencoding could be changed after ctor is called +- soap_server: use soap_defencoding instead of charset_encoding +- soap_server: read encoding from _SERVER if available +- nusoap_base: do entity translation for string parameters with an xsd type specified (thanks David Derr) + +2003-07-31, version 0.6.5 +- soap_transport_http: add proxy authentication +- soap_transport_http: build payload the same way for http and https +- wsdl: add proxy authentication +- soapclient: add proxy authentication +- soapclient: allow proxy information in ctor, so that it can be used for wsdl + +2003-08-01, version 0.6.5 +- soap_transport_http: close a persistent connection that's at EOF +- soap_transport_http: prevent conflicts between setEncoding and usePersistentConnection +- soap_transport_http: fix use of $headers instead of $this->incoming_headers in getResponse +- soapclient: improve handling of persistent connections +- soapclient: force xml_encoding to upper case +- soap_server: let the Web server decide whether to close the connection (no Connection: close header) +- soap_server: force xml_encoding to upper case + +2003-08-04, version 0.6.5 +- soap_parser: use XML type information to pick a PHP data type; also decode base64 +- soap_server: read all HTTP headers when using _SERVER or HTTP_SERVER_VARS +- soap_server: add gzip encoding support for outgoing messages +- soap_transport_http: deflate is gzcompress/gzuncompress (cf. http://archive.develooper.com/libwww@perl.org/msg04650.html) +- soap_transport_http: clean use of persistentConnection so it's always a set boolean +- soapclient: add responseData member to access deflated/gunzipped payload + +2003-08-05, version 0.6.5 +- soap_server: look multiple places when setting debug_flag + +2003-08-07, version 0.6.5 +- nusoap_base: serialize specified type (e.g. ArrayOfString) even for simple array +- wsdl: only specify encodingStyle in the input/output soap bindings when it is not empty (thanks Guillaume) + +2003-08-15, version 0.6.5 +- soap_parser: fix parsing of elements with no XSD type specified +- soap_parser: use PHP string type for XSD long and unsignedLong types + +2003-08-16, version 0.6.5 +- soap_parser: fix code generating warning (thanks Torsten) + +2003-08-19, version 0.6.5 +- soap_parser: fix another line of code generating a warning (thanks Torsten) + +2003-08-22, version 0.6.5 +- soap_server: remove all '--' from debug_str; previous code changed '---' to '- --' +- wsdl, soapclient, soap_parser: patch submitted by Mark Spavin as described by + the following... +> Changes for the multiple/nested imports from the wsdl file. This builds an +> array of files not just the last one and also checks for relative paths to +> the parent. This will then get the imported files from the remote site +> instead of your local disk. Local wsdl files should still work (untested). +> +> Changes for multiple encoding sytles as previously posted + +2003-08-24, version 0.6.5 +- wsdl, soapclient: fix some PHP notices from previous update + +2003-08-26, version 0.6.5 +- wsdl: support multiple SOAP ports +- soapclient, soap_server: when no charset is specified, use UTF-8, even though HTTP specifies US-ASCII. +- soap_transport_http: do not prepend $host with 'ssl://' for https (is this required for older cURL versions?) + +2003-08-27, version 0.6.5 +- soap_server: support compressed request messages (thanks John Huong) +- soap_parser: deserialize Apache Vector as an array +- xmlschema: use $this->typemap in getPHPType (which is not used) +- soapclient, wsdl: check for WSDL errors after serializing parameters +- nusoap_base: add serialization of Apache Map (when not using WSDL) +- wsdl: add serialization of Apache Map (when using WSDL) +- wsdl: only change &, <, > to entities, not all HTML entities + +2003-08-28, version 0.6.5 +- soap_transport_http: disable cURL verification of peer and server (formerly the cURL default) +- soap_transport_http: mingle cURL code with straight http, so sendHTTP is no longer needed + +2003-08-29, version 0.6.6 +- soap_transport_http: add setContentType +- soapclient: call setContentType using new getHTTPContentType and getHTTPContentTypeCharset + +2003-09-05, version 0.6.6 +- wsdl: add some more code to handle null/nil values (but there's still a way to go) + +2003-10-21, version 0.6.6 +- soap_transport_http: only include port in Host header if it was specified in the URL +- soap_transport_http: add some code to use OpenSSL for PHP ssl:// scheme, but comment out since it's not ready +- soap_server: use $_SERVER['PHP_SELF'] if $GLOBALS['PHP_SELF'] is not set +- wsdl: add WSDL request and response and transport debug to debug +- wsdl: handle custom type extending xmlschema namespace (GLUE ... Thanks Matt) +- soap_parser: add param to docs +- soapclient: add getHTTPBody, getHTTPContentType, getHTTPContentTypeCharset (anticipating MIME subclass) + +2003-10-28, version 0.6.6 +- nusoap_base: add expandEntities method +- wsdl: use expandEntities +- soap_fault: use expandEntities +- soap_transport_http: Allow credentials to be included in URL, rather than requiring setCredentials +- soap_transport_http: Merge HTTP headers that span multiple lines +- soap_parser: Properly set errors in ctor +- soapclient: Pass headers to parseResponse and parse them in that method + +2003-10-30, version 0.6.6 +- xmlschema: Add some information for the related type to an element + +2003-12-09, version 0.6.6 +- nusoap_base: Add some namespace methods previously in xmlschema +- xmlschema: Improve parsing of complexType, element and simpleType +- xmlschema: Improve serialization +- xmlschema: Track imports +- xmlschema: Track elementFormDefault and form attributes +- wsdl: Support multiple (note that setting $server->wsdl->schemaTargetNamespace no longer does anything! Use configureWSDL instead.) +- wsdl: Use form attribute of element to control namespace specification +- wsdl: Support chained imports (A imports B which imports C) +- wsdl: Include port in endpoint address when serializing +- soap_server: Fix use of style (rpc|document) and use (encoded|literal) +- soap_server: Support _SERVER[CONTENT_TYPE] in addition to _SERVER[HTTP_CONTENT_TYPE] +- soap_server: Support wsdl with multiple +- soap_client: Remove a var_dump +- soap_client: Add style and use parameters to call method to support doc/lit without WSDL +- soap_transport_http: Check that $this->fp exists when doing persistent connections + +2003-12-17, version 0.6.6 +- soap_server: pass namespaces to xmlschema constructor +- wsdl: post-process after all imports +- wsdl: remove some debug, add some error handling +- xmlschema: allow enclosing namespaces to be specified in constructor +- xmlschema: improve handling of compositors and simple types + +2004-01-08, version 0.6.6 +- soap_server: when requested WSDL is in a file, return to client using passthru (thanks Ingo Fischer) +- soapclient: have proxy inherit more client state +- soapclient: allow timeout and response timeout to be specified in the constructor +- wsdl: allow timeout and response timeout to be specified in the constructor +- soap_transport_http: allow response timeout to be specified in send and sendHTTPS + +2004-01-28, version 0.6.6 +- wsdl: add namespace for array and scalar when form is qualified +- wsdl: fix a bug in which data type of complexType elements were ignored in serialization +- wsdl: enhance handling of URLs with file scheme +- wsdl: add addSimpleType +- xmlschema: add addSimpleType +- xmlschema: always set phpType elements +- soapclient: allow a wsdl instance to be specified in constructor +- soap_server: allow a wsdl instance to be specified in constructor (not tested!) +- soap_server: fix default SOAPAction created in register method +- soap_transport_http: accept chunking with LF separators in addition to CRLF. +- wsdlcache: added class +- nusoapmime: fix comments + +2004-02-23, version 0.6.6 +- soap_transport_http: don't try to unchunk cURL data, since cURL already does it +- soap_transport_http: append CVS revision to version in User-Agent +- wsdl: serialize boolean as true|false, not 1|0, to agree with XML Schema +- soap_server: always exit() after returning WSDL +- soap_server: use the WSDL URL scheme as the default endpoint URL scheme +- soap_server: append CVS revision to version in X-SOAP-Server +- nusoap_base: add (CVS) revision +- wsdlcache: synchronize using a per-WSDL lock file (Thanks Ingo) +- wsdlcache: add cache lifetime, after which cache contents are invalidated (Thanks Ingo) + +2004-03-15, version 0.6.6 +- nusoap_base: add isArraySimpleOrStruct method +- soap_server: improve WSDL URL scheme determination +- soap_server: only deflate/gzip payloads > 1024 bytes +- soap_server: fix parameter order in fault method (always used as faultcode, faultstring) +- soap_server: refactor parse_request into multiple functions (for sanity) +- soap_server: set the namespace on the Response element to the same as the request +- soap_server: name the return value element 'return' by default +- soap_server: added and documented data fields, so that service programmers can use them if desired +- soap_parser: standardize parsing error message +- soap_parser: fix document and responseHeaders so they are the correct XML text (as documented) +- soap_transport_http: fix read from persistent connection +- soapclient: clean up debugging for persistent connection +- wsdl: enforce correct naming of messages parts when an associative array is used for parameters +- wsdl: better serialization of null values +- wsdl: standardize parsing error message +- xmlschema: standardize parsing error message + +2004-03-24, version 0.6.7 +- soap_transport_http: add digest authentication (based on code by Kevin A. Miller) +- xmlschema: improve parsing of import elements +- wsdl: do schema imports even if there are no wsdl imports + +2004-04-12, version 0.6.7 +- wsdl: serialize multiple elements when maxOccurs="unbounded" and value is an array +- wsdl: serialize soapval values (used to force an XML type, e.g. when WSDL uses an abstract type) +- nusoapmime: do not require nusoap.php (it is now the programmer's responsibility) + +2004-04-21, version 0.6.7 +- soap_parser: parse repeated element name into an array (de-serializes doc/lit array into a PHP array when there is more than 1 array element) +- soap_server: do not wrap response in a response element for a document style service + +2004-04-30, version 0.6.7 +- soap_transport_http: allow digest auth params to be separated by "," as well as ", " +- soap_transport_http: re-initialize incoming headers for each response +- soap_server: add methodreturnisliteralxml property to allow service function to return XML as a string +- soapclient: improve rpc/literal support +- soapclient: allow XML string as call params in addition to array +- soapclient: support document style and literal encoding when not using WSDL + +2004-05-05, version 0.6.7 +- wsdl: serialize PHP objects for WSDL XML Schema complexTypes, in addition to associative arrays +- wsdl: fix WSDL generation when there is no encodingStyle +- soap_transport_http: suppress fsockopen warnings +- soap_transport_http: detect socket timeouts when reading (0 bytes returned) +- soap_transport_http: read chunked content "in-line" so it works on a persistent connection +- nusoap_base: serialize boolean as true|false, not 1|0, to agree with XML Schema +- nusoap_base: serialize array of struct differently than array of array + +2004-06-25, version 0.6.8 +- soap_server: prefer gzip to deflate, since IE does not like our deflate +- soap_server: move webDescription to the wsdl class +- soap_server: allow class and instance method calls for service (thanks Ingo Fischer and Roland Knall) +- wsdl: get webDescription from the soap_server class +- wsdl: allow compression from the server +- wsdl: fix serialization of soapval without a type +- wsdl: propagate debug value from query string to SOAP endpoint in programmatic WSDL generation +- nusoap_base: add anyType, anySimpleType for 2001 XML Schema +- nusoap_base: provide additional debug functions +- soap_transport_http: ignore Content-Length when chunked encoding is used +- soap_transport_http: remove ':' from username for Basic authentication (cf. RFC 2617) +- soap_transport_http: urldecode username and password taken from URL +- soap_transport_http: use raw inflate/deflate for IE/IIS compatibility, rather than having Zlib headers according to HTTP 1.1 spec +- soap_transport_http: attempt to handle the case when both the service application and Web server compress the response +- soapclient: when creating proxy methods, replace '.' in operation name with '__' in function name +- soapclient: initialize requestHeaders in proxy +- general: use new debug methods; never access debug_str directly + +2004-09-30, version 0.6.8 +- soapclient: do not allow getProxy call when WSDL is not used +- soapclient: use ISO-8859-1 as the charset if not specified in the Content-Type header +- soapclient: when an empty string is specified for the call namespace, do not put the method element in a namespace +- soapclient: let soap_transport_http check for SSL support +- soapclient: have proxy inherit soap_defencoding from the client from which it is generated +- soapclient: do not assume that 'ns1' is an unused namespace prefix; always generate namespace prefixes randomly +- soap_parser: compare any encoding in the XML declaration to the charset from the HTTP Content-Type header (thanks Ingo Fischer) +- soap_parser: improve parse repeated element name into an array (de-serializes doc/lit array into a PHP array when there is more than 1 array element) +- soap_server: use ISO-8859-1 as the charset if not specified in the Content-Type header +- soap_server: allow suppression of automatic UTF-8 decoding +- soap_server: fix a bug when call_user_func_array() is used +- soap_transport_http: correct digest authentication through a proxy +- wsdl: serialize SOAP-ENC types similarly to XSD types +- xmlschema: force unprefixed type into default namespace +- xmlschema: fix serialization of definition of simple types + +2004-10-01, version 0.6.8 +- soap_parser: handle default namespace attributes +- soap_server: add default_utf8 field +- soap_server: support literal encoding (with RPC style) +- soap_transport_http: parse HTTP status and generate error for 300, 302-307, 400, 401-417, 501-505 (thanks for the idea Ghislain) +- soap_transport_http: follow HTTP redirection (HTTP status 301 and Location header) (thanks for the idea Ghislain) +- xmlschema: allow any attributes to be specified in an element of a complexType, e.g., abstract, default, form, minOccurs, maxOccurs, nillable (thanks Jirka Pech for the original patch) + +2004-10-02, version 0.6.8 +- soapclient: read/write cookies (thanks Ingo) +- soap_server: change faultcode on non-resendable faults to Client +- soap_transport_http: read/write cookies (thanks Ingo) + +2004-10-05, version 0.6.8 +- wsdl: add addElement method +- wsdl: support the document style in the register method +- xmlschema: parse unnamed simpleTypes, rather than ignoring them +- xmlschema: include untyped elements when parsing a complexType +- xmlschema: add addElement method + +2004-10-14, version 0.6.8 +- soapclient: support client certificates +- soap_parser: deserialize attributes, prefixing names with "!" +- soap_server: notify the client with HTML when WSDL is requested but not supported by service +- soap_transport_http: support client certificates +- wsdl: support defaults for elements of a complexType +- wsdl: serialize elements from complexType extension base +- wsdl: serialize data (associative array elements) as attributes according to XML Schema +- xmlschema: record extension base if present for a complexType + +2004-12-15, version 0.6.8 +- nusoap_base: add 2000 XML Schema (rare, but used by Akamai) +- soap_parser: avoid deserializing more common attributes that are not data +- soap_parser: be lax when HTTP specifies ISO-8859-1 (the default) and XML specifies UTF-8 (the norm) +- soap_server: account for the fact that get_class_methods returns methods in all lower case (thanks Steve Haldane) +- soap_transport_http: parse digest info that includes '=' in the data (thanks Jinsuk Kim) +- wsdl: feably handle some cases for literal serialization of form="unqualified" elements +- wsdl: don't serialize the decimal portion of a PHP double when the XML type is long +- wsdl: fix serialization of attributes for complexType that is an extension +- wsdlcache: enhance diagnostics +- xmlschema: handle untyped elements +- xmlschema: handle WSDL for SOAP Array that uses the base attribute plus a sequence of element + +2005-01-22, version 0.6.8 +- wsdl: allow an element in one schema to have a type from another schema + +2005-01-24, version 0.6.8 +- xmlschema: correctly parse nested complexType definitions + +2005-02-14, version 0.6.8 +- nusoap_base: fix a bug in which attributes were sometimes not serialized with a value +- nusoap_base: improve serialization of null values (thanks Dominique Stender) +- soap_parser: parse null values by handling the nil attribute (thanks Dominique Stender) +- soap_server: set character encoding for a fault to be the same as for the server (thanks Mark Scott) +- soap_server: correctly check for null value returned from method when WSDL is used (without WSDL, cannot distinguish whether NULL or void return is desired) +- soapclient: for document style, call should always return an array rooted at the response part (all bets are off when there are multiple parts) +- xmlschema: save enumeration values parsed from WSDL + +2005-02-10, version 0.6.9 +- soapclient: only set SOAP headers when they are specified in call params (so setHeaders still works) + +2005-04-04, version 0.6.9 +- soap_server: use get_class instead of is_a (thanks Thomas Noel) +- soapclient: use get_class instead of is_a (thanks Thomas Noel) +- soapclient: add setEndpoint method +- soap_transport_http: fix client certificates (thanks Doug Anarino and Eryan Eriobowo) + +2005-04-29, version 0.6.9 +- nusoap_base: add global variable and methods for setting debug level +- nusoap_base: use xsd:anyType instead of xsd:ur-type to serialize arrays with multiple element types (thanks Ingo Fischer) +- nusoap_base: expand entities in attributes (thanks Gaetano Giunta) +- soapclient: call parent constructor +- soapval: call parent constructor +- soap_fault: call parent constructor +- soap_parser: call parent constructor +- soap_server: assume get_class_methods always returns lower case for PHP 4.x only +- soap_server: call parent constructor +- soap_transport_http: do nothing in setEncoding if gzdeflate is not present (thanks Franck Touanen for pointing this out) +- soap_transport_http: fix check for server request for digest authentication (thanks Mark Spavin) +- soap_transport_http: call parent constructor +- wsdl: fix documentation page popup of one method after another (thanks Owen) +- wsdl: call parent constructor +- wsdl: expand entities in attributes (thanks Gaetano Giunta) +- xmlschema: call parent constructor + +2005-06-03, version 0.6.9 +- nusoap_base: serialize empty arrays as having elements xsd:anyType[0] +- nusoap_base: add encodingStyle parameter to serializeEnvelope +- nusoap_base: serialize xsi:type with nil values +- nusoap_base: improve debug and comments +- soap_parser: correctly parse an empty array to an empty array, not an empty string +- soap_parser: improve debug and comments +- soap_server: specify encodingStyle for envelope when WSDL is used +- soapclient: factor out new getProxyClassCode method +- soapclient: specify encodingStyle for envelope +- soapclient: improve debug and comments +- wsdl: add namespace for Apache SOAP types if a variable of such type is serialized +- wsdl: serialize nil value for nillable elements when no value is provided +- wsdl: serialize xsi:type with nil values +- wsdl: copy attributes as well as elements to an element from its complexType +- wsdl: specify encodingStyle for operations +- wsdl: improve debug and comments +- xmlschema: improve debug and comments + +2005-06-03, version 0.7.0 +- nusoap_base: improve debug and comments +- nusoap_base: fix version, which should have been 0.7.0 since 2005-03-04 + +2005-06-06, version 0.7.1 +- nusoap_base: adjust numeric element names for serialization, instead of forcing them to 'soapVal' +- nusoapmime: add type=text/xml to multipart/related (thanks Emmanuel Cordonnier) +- soap_fault: fix serialization of detail +- soap_server: check required parameters for register method +- soap_server: when getallheaders is used, massage header names +- soap_server: use SOAPAction to determine operation when doc/lit service does not wrap parameters in an element with the method name (thanks Peter Hrastnik) +- soap_transport_http: correctly handle multiple HTTP/1.1 100 responses for https (thanks Jan Slabon) +- wsdl: fixed documentation for addComplexType (thanks Csintalan Ádám) +- wsdl: serialize array data when maxOccurs = 'unbounded' OR maxOccurs > 1 (thanks Dominique Schreckling) +- wsdl: when serializing a string == 'false' as a boolean, set the value to false +- wsdl: when serializing a complexType, require the PHP value supplied to be an array + +2005-07-01, version 0.7.1 +- nusoap_base: Allow SOAP headers to be supplied as an array like parameters +- soap_parser: de-serialize simpleContent that accompanies complexContent +- soap_server: append debug information when programmatically-defined WSDL is returned +- soap_transport_http: Add debug when an outgoing header is set +- soapclient: Allow SOAP headers to be supplied as an array like parameters +- xmlschema: serialize attributes more generally, rather than assuming they are for SOAP 1.1 Array +- wsdl: when serializing, look up types by namespace, not prefix (simple programmatic doc/lit WSDL now seems to work) +- wsdl: process namespace declarations first when parsing an element + +2005-07-27, version 0.7.1 +- nusoap_base: do not override supplied element name with class name when serializing an object in serialize_val +- nusoap_base: remove http://soapinterop.org/xsd (si) from namespaces array +- nusoapmime: add nusoapservermime class to implement MIME attachments on the server +- soap_fault: improve documentation +- soap_server: improve documentation +- soap_server: make consistent use of _SERVER and HTTP_SERVER_VARS +- soap_server: make all incoming HTTP header keys lower case +- soap_server: add hook functions to support subclassing for MIME attachments +- soap_transport_http: remove an unnecessary global statement +- soapclient: when creating a proxy, make $params within each function an associative array +- soapval: improve documentation +- wsdl: when serializing complexType elements, used typed serialization if there is either a type or a reference for the element +- wsdl: allow PHP objects to be serialized as SOAP structs in serializeType +- wsdl: for WSDL and XML Schema imports, don't forget to use the TCP port number (thanks Luca GIOPPO) +- wsdl: make consistent use of _SERVER and HTTP_SERVER_VARS +- xmlschema: improve documentation + +2005-07-31, version 0.7.2 +- nusoap_base: correctly serialize attributes in serialize_val (thanks Hidran Arias) +- soap_parser: when resolving references, do not assume that buildVal returns an array (thanks Akshell) +- soap_parser: removed decode_entities, which does not work (thanks Martin Sarsale) +- soap_server: fix a bug parsing headers from _SERVER and HTTP_SERVER_VARS (thanks Bert Catsburg) +- soap_server: parse all "headers" from HTTP_SERVER_VARS (not just HTTP_*) +- soap_server: use PHP_SELF instead of SCRIPT_NAME for WSDL endpoint +- soap_server: when generating a fault while debug_flag is true, put debug into faultdetail +- wsdl: add enumeration parameter to addSimpleType +- xmlschema: add enumeration parameter to addSimpleType + +2006-02-02, version 0.7.2 +- soapclient: initialize paramArrayStr to improve proxy generation +- soap_parser: handle PHP5 soapclient's incorrect transmission of WSDL-described SOAP encoded arrays. +- soap_server: don't assume _SERVER['HTTPS'] is set; try HTTP_SERVER_VARS['HTTPS'] if it is not +- soap_server: "flatten out" the parameter array to call_user_func_array (thanks André Mamitzsch) +- soap_server: make thrown exceptions conform to specs +- wsdl: use serialize_val to serialize an array when the XSD type is soapenc:Array (JBoss/Axis does this) +- wsdl: change formatting of serialized XML for the WSDL +- xmlschema: change formatting of namespaces when serializing XML for the schema + +2006-04-07, version 0.7.2 +- soap_server: if methodparams is not an array, call call_user_func_array with an empty array (thanks Eric Grossi) +- wsdl: distinguish parts with element specified from those with type specified by suffixing element names with ^ +- wsdl: do a case-insensitive match on schema URI when looking for type +- xmlschema: only get element (not type) when name has ^ suffix + +2006-05-16, version 0.7.2 +- soapclient: add getHeader to get parsed SOAP Header +- soap_parser: check status when receiving Header or Body element +- soap_parser: add soapheader +- soap_server: add requestHeader with parsed SOAP Header + +2006-06-15, version 0.7.2 +- wsdl: fix bug in addComplexType (thanks Maarten Meijer) +- soap_transport_http: change cURL message + +2007-03-19, version 0.7.2 +- soapclient: declare as nusoapclient, then also subclass soapclient if SOAP extension not loaded +- soapclientmime: declare as nusoapclientmime, then also subclass soapclientmime if SOAP extension not loaded + +2007-03-28, version 0.7.2 +- nusoap_base: fix serialization of a soapval when its value is a soapval +- soapval: fix serialization of a soapval when its value is a soapval +- soapval: add __toString (cf. http://article.gmane.org/gmane.comp.php.nusoap.general/2776) +- nusoapclient: use lazy retrieval of WSDL instead of always getting it in the constructor +- nusoapclient: fix getProxy that was broken in last revision +- wsdl: add ability to set authorization credentials and retrieve WSDL outside of constructor + +2007-04-05, version 0.7.2 +- nusoapclientmime: don't rely exclusively on Content-Disposition to distinguish the root part from attachment; also check Content-Type (thanks Ben Bosman) +- nusoapclientmime: obey RFC 2045 Section 5.1 (thanks Chris Butler) +- nusoapservermime: don't rely exclusively on Content-Disposition to distinguish the root part from attachment; also check Content-Type (thanks Ben Bosman) +- nusoapservermime: obey RFC 2045 Section 5.1 (thanks Chris Butler) +- nusoap_base: remove extra whitespace from some XML elements +- nusoap_base: allow SOAP headers to be specified as an associative array (thanks Unique) +- nusoap_base: implement __toString +- nusoap_base: improve doc accuracy and consistency (thanks Martin K?gler) +- iso8601_to_timestamp: avoid problem with negative hours after calculation, etc. (thanks Guntram Trebs) +- nusoapclient: support user-settable cURL options (thanks Ciprian Popovici) +- nusoapclient: call SOAP 1.2 binding operations if no SOAP 1.1 present (there is no reason to believe this will always work!) +- nusoapclient: improve doc accuracy and consistency (thanks Martin K?gler) +- soap_server: don't try to use eval to call function when any parameter is an object +- soap_server: don't print return value within debug string; returned objects would need __toString in PHP 5.2 +- soap_server: use URL scheme for WSDL access as the scheme in SOAPAction +- soap_server: strip port number from server name (some FastCGI implementations include port in server name) +- soap_transport_http: support user-settable cURL options (thanks Ciprian Popovici) +- soap_transport_http: use cURL for NTLM authentication +- soap_transport_http: make digest authentication work for GET as well as POST +- soap_transport_http: improve doc accuracy and consistency (thanks Martin K?gler) +- soapval: remove __toString +- wsdl: set operation style if necessary, but do not override one already provided (thanks Raffaele Capobianco) +- wsdl: check SOAP 1.2 binding operations if no SOAP 1.1 present +- wsdl: improve doc accuracy and consistency (thanks Martin K?gler) +- xmlschema: fix simpleType serialization +- xmlschema: improve doc accuracy and consistency (thanks Martin K?gler) + +2007-04-09, version 0.7.2 +- nusoapclient: set decode_utf8 when creating a proxy (thanks Dmitri Dmitrienko) +- nusoapclient: rename class to nusoap_client +- soap_fault: also provide a class named nusoap_fault +- soap_parser: also provide a class named nusoap_parser +- soap_server: also provide a class named nusoap_server +- soap_transport_http: skip HTTP responses 301 and 401 when using cURL +- soap_transport_http: don't force HTTP Connection header when using cURL +- soap_transport_http: don't set HTTP Host and Content-Length headers when using cURL +- soap_transport_http: support CURLOPT_SSLCERTPASSWD (thanks David Blanco) +- wsdl: support user-settable cURL options (thanks Ciprian Popovici) +- wsdl: serialize parameters for non-SOAP 1.1 binding operations (there is no reason to believe this will always work!) +- xmlschema: also provide a class named nusoap_xmlschema +- nusoapclientmime: rename class to nusoap_client_mime +- nusoapservermime: rename class to nusoap_server_mime + +2007-04-11, version 0.7.2 +- nusoap_client: enable cURL usage to be forced (thanks Giunta Gaetano) +- soap_transport_http: enable cURL proxy usage (thanks Giunta Gaetano) +- soap_transport_http: enable cURL usage to be forced (thanks Giunta Gaetano) +- soap_transport_http: use cURL's HTTP authentication options for basic, digest +- wsdl: enable cURL usage to be forced (thanks Giunta Gaetano) + +2007-04-12, version 0.7.2 +- nusoap_client: add debug +- nusoap_xmlschema: don't add elements of complexTypes to elements array (thanks Heiko Hund) +- soap_transport_http: set cURL connection timeout if supported +- soap_transport_http: add debug when setting cURL option +- soap_transport_http: fix digest authentication broken in previous revision +- wsdl: add debug +- wsdlcache: address some issues with non-existing cache-files and PHP Warnings which came in such cases (thanks Ingo Fischer) +- wsdlcache: change class name to nusoap_wsdlcache + +2007-04-13, version 0.7.2 +- wsdl: wrap parameters if unwrapped values are supplied and WSDL specifies Microsoft-style wrapping + +2007-04-16, version 0.7.2 +- nusoap_base: avoid warning in getDebugAsXMLComment +- nusoap_client: small debug change +- nusoap_client_mime: set responseData when the root part is found + +2007-04-17, version 0.7.2 +- soap_transport_http: improve detection of undefined cURL options (thanks Ingo Fischer) + +2007-05-28, version 0.7.2 +- soap_transport_http: support digest authentication opaque feature (cf. RFC 2617) (thanks Daniel Lacroix) +- soap_transport_http: check safe_mode and open_basedir before setting CURLOPT_FOLLOWLOCATION +- soap_transport_http: skip "HTTP/1.0 200 Connection established" header when cURL returns it (thanks Raimund Jacob) +- nusoap_client: improve handling when getProxy is called and WSDL is not being used +- nusoap_base: add comments about which specifications are used/implemented by NuSOAP +- nusoap_xmlschema: create names for unnamed types that are unique by scope within XML Schema + +2007-06-11, version 0.7.2 +- wsdl: wrap return value if unwrapped value is supplied and WSDL specifies Microsoft-style wrapping + +2007-06-22, version 0.7.2 +- nusoap_xmlschema: fix serialization of simpleType restriction (thanks Rizwan Tejpar) + +2007-07-30, version 0.7.2 +- nusoap_server: Per http://www.ws-i.org/Profiles/BasicProfile-1.1-2004-08-24.html R2735, rpc/literal accessor elements should not be in a namespace (thanks Kostas Kalevras) +- nusoap_client: Per http://www.ws-i.org/Profiles/BasicProfile-1.1-2004-08-24.html R2735, rpc/literal accessor elements should not be in a namespace (thanks Kostas Kalevras) + +2007-10-21, version 0.7.2 +- nusoap_server: Per http://www.ws-i.org/Profiles/BasicProfile-1.1-2004-08-24.html R2735, rpc/literal accessor elements should not be in a namespace (thanks Kostas Kalevras) +- nusoap_client: Per http://www.ws-i.org/Profiles/BasicProfile-1.1-2004-08-24.html R2735, rpc/literal accessor elements should not be in a namespace (thanks Kostas Kalevras) + +2007-10-26, version 0.7.2 +- nusoap_server: Fix munging of _SERVER variables that start with HTTP_ (thanks Thomas Wieczorek) + +2007-10-30, version 0.7.2 +- nusoap_xmlschema: Serialize values for elementFormDefault, attributeFormDefault +- wsdl: Improve consistency between doc/lit schema auto-wrapping and client's parsed schema +- nusoap_server: Correct bug that placed encodingType in Envelope for doc/lit +- nusoap_server: Specify elementFormDefault for schema within doc/lit wsdl + +2007-10-31, version 0.7.2 +- wsdl: Fix typo in parametersMatchWrapped (thanks Sam Stepanyan) +- soap_transport_http: Fix three typos in setProxy (thanks Sam Stepanyan) +- nusoap_xmlschema: Fix typo in serializeTypeDef (thanks Sam Stepanyan) + +2007-11-06, version 1.0rc1 +- wsdl: Improve handling of return values from doc/lit methods +- nusoap_server: Handle case when method is not in a namespace + +2007-11-27, version 1.0rc1 +- nusoap_server: always try to invoke service for a POST +- nusoap_server: only return Location: for WSDL at http://... +- nusoap_base: change some syntax associated with globalDebugLevel + +2008-01-08, version 1.0rc1 +- nusoap_server: fix a typo where = was used instead of == (thanks J. (Johan) Bosma) + +2008-01-10, version 1.0rc1 +- nusoap_client: handle case where request or response has no content-type header (thanks Ingo Fischer) +- nusoap_server: handle case where request or response has no content-type header (thanks Ingo Fischer) +- wsdl: change CSS for .title in webDescription (thanks Marcus Uy) + +2008-01-25, version 1.0rc1 +- nusoap_xmlschema: when an element is of a complexType that is an extension, copy extensionBase from the type +- nusoap_xmlschema: do not apply elementFormDefault to globally defined elements + +2008-02-11, version 1.0rc1 +- wsdl: internally set form of wrapped parameter elements to unqualified (so server handles correctly) + +2008-03-03, version 1.0.rc1 +- nusoap_xmlschema: fix extension when base type has no explicit prefix +- nusoap_xmlschema: support XML Schema include +- wsdl: improve support for sequence by serializing inherited attributes and elements first + +2008-03-04, version 1.0.rc1 +- wsdl: allow WSDL port name to be specified in getOperations +- nusoap_client: allow WSDL port name to be specified in ctor + +2008-03-06, version 1.0rc1 +- wsdl: fix some port name variable references +- nusoap_base: change comments regarding preferred mode of support +- wsdl2nusoap: initial revision + +2008-03-14, version 1.0rc1 +- nusoap_base: fix timezone offset in timestamp_to_iso8601 (thanks Mario Trojan) + +2008-03-27, version 1.0rc1 +- nusoap_server: fix bug setting encodingStyle in serialize_return (thanks Luca Gobbo) + +2008-05-15, version 1.0rc1 +- nusoap_parser: handle case where Header or Body tags are used within SOAP messages (thanks Sergey Zhuravlev) + +2008-08-26, version 1.0rc1 +- wsdl: serialize simpleContent for complexType +- wsdl: avoid serializing complexType elements with no value and minOccurs = 0 regardless of nillability + +2010-04-26, version 0.9.5 +- nusoap_xmlschema: replace regex function calls (ereg, eregi, split) with PCRE calls (preg_match, preg_split) (thanks Pier-Luc Duchaine) +- wsdl: replace regex function calls (ereg, eregi, split) with PCRE calls (preg_match, preg_split) (thanks Pier-Luc Duchaine) +- soap_transport_http: replace regex function calls (ereg, eregi, split) with PCRE calls (preg_match, preg_split) (thanks Pier-Luc Duchaine) +- soap_transport_http: remove call to deprecated function set_magic_quotes_runtime +- nusoap_server: replace regex function calls (ereg, eregi, split) with PCRE calls (preg_match, preg_split) (thanks Pier-Luc Duchaine) +- nusoap_server: check that value is an object before calling get_class (thanks Pier-Luc Duchaine) +- nusoap_parser: replace regex function calls (ereg, eregi, split) with PCRE calls (preg_match, preg_split) (thanks Pier-Luc Duchaine) +- nusoap_client: replace regex function calls (ereg, eregi, split) with PCRE calls (preg_match, preg_split) (thanks Pier-Luc Duchaine) +- nusoap_client: do not assign the return value of new by reference (it is deprecated) (thanks Pier-Luc Duchaine) +- nusoap_base: replace regex function calls (ereg, eregi, split) with PCRE calls (preg_match, preg_split) (thanks Pier-Luc Duchaine) +- nusoapmime: do not assign the return value of new by reference (it is deprecated) diff --git a/include/nusoap/class.nusoap_base.php b/include/nusoap/class.nusoap_base.php new file mode 100644 index 00000000..ef43ec7f --- /dev/null +++ b/include/nusoap/class.nusoap_base.php @@ -0,0 +1,1046 @@ + + Bug 39085 - When loading the opposite search panel via ajax on the ListViews, call the index action instead of the ListView action to avoid touching pre-MVC code by accident. + +r56990 - 2010-06-16 13:05:36 -0700 (Wed, 16 Jun 2010) - kjing - snapshot "Mango" svn branch to a new one for GitHub sync + +r56989 - 2010-06-16 13:01:33 -0700 (Wed, 16 Jun 2010) - kjing - defunt "Mango" svn dev branch before github cutover + +r55980 - 2010-04-19 13:31:28 -0700 (Mon, 19 Apr 2010) - kjing - create Mango (6.1) based on windex + +r51719 - 2009-10-22 10:18:00 -0700 (Thu, 22 Oct 2009) - mitani - Converted to Build 3 tags and updated the build system + +r51634 - 2009-10-19 13:32:22 -0700 (Mon, 19 Oct 2009) - mitani - Windex is the branch for Sugar Sales 1.0 development + +r51516 - 2009-10-14 10:22:42 -0700 (Wed, 14 Oct 2009) - jmertic - More fallout fixes from the PHP 5.3 ereg to preg changes. + +r51443 - 2009-10-12 13:34:36 -0700 (Mon, 12 Oct 2009) - jmertic - Bug 33332 - Made application PHP 5.3 compliant with E_DEPRECATED warnings on by: +- Changing all ereg function to either preg or simple string based ones +- No more references to magic quotes. +- Change all the session_unregister() functions to just unset() the correct session variable instead. + +r50375 - 2009-08-24 18:07:43 -0700 (Mon, 24 Aug 2009) - dwong - branch kobe2 from tokyo r50372 + +r42807 - 2008-12-29 11:16:59 -0800 (Mon, 29 Dec 2008) - dwong - Branch from trunk/sugarcrm r42806 to branches/tokyo/sugarcrm + +r14701 - 2006-07-17 13:37:26 -0700 (Mon, 17 Jul 2006) - roger - RRS: bug 5801 + +r13782 - 2006-06-06 10:58:55 -0700 (Tue, 06 Jun 2006) - majed - changes entry point code + +r11115 - 2006-01-17 14:54:45 -0800 (Tue, 17 Jan 2006) - majed - add entry point validation + +r8846 - 2005-10-31 11:01:12 -0800 (Mon, 31 Oct 2005) - majed - new version of nusoap + +r5462 - 2005-05-25 13:50:11 -0700 (Wed, 25 May 2005) - majed - upgraded nusoap to .6.9 + +r573 - 2004-09-04 13:03:32 -0700 (Sat, 04 Sep 2004) - sugarclint - undoing copyrights added in inadvertantly. --clint + +r546 - 2004-09-03 11:49:38 -0700 (Fri, 03 Sep 2004) - sugarmsi - removed echo count + +r354 - 2004-08-02 23:00:37 -0700 (Mon, 02 Aug 2004) - sugarjacob - Adding Soap + + +*/ + + +if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point'); + +/* +$Id: class.nusoap_base.php 57813 2010-08-19 17:34:44Z kjing $ + +NuSOAP - Web Services Toolkit for PHP + +Copyright (c) 2002 NuSphere Corporation + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License 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. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +The NuSOAP project home is: +http://sourceforge.net/projects/nusoap/ + +The primary support for NuSOAP is the Help forum on the project home page. + +If you have any questions or comments, please email: + +Dietrich Ayala +dietrich@ganx4.com +http://dietrich.ganx4.com/nusoap + +NuSphere Corporation +http://www.nusphere.com + +*/ + +/* + * Some of the standards implmented in whole or part by NuSOAP: + * + * SOAP 1.1 (http://www.w3.org/TR/2000/NOTE-SOAP-20000508/) + * WSDL 1.1 (http://www.w3.org/TR/2001/NOTE-wsdl-20010315) + * SOAP Messages With Attachments (http://www.w3.org/TR/SOAP-attachments) + * XML 1.0 (http://www.w3.org/TR/2006/REC-xml-20060816/) + * Namespaces in XML 1.0 (http://www.w3.org/TR/2006/REC-xml-names-20060816/) + * XML Schema 1.0 (http://www.w3.org/TR/xmlschema-0/) + * RFC 2045 Multipurpose Internet Mail Extensions (MIME) Part One: Format of Internet Message Bodies + * RFC 2068 Hypertext Transfer Protocol -- HTTP/1.1 + * RFC 2617 HTTP Authentication: Basic and Digest Access Authentication + */ + +/* load classes + +// necessary classes +require_once('class.soapclient.php'); +require_once('class.soap_val.php'); +require_once('class.soap_parser.php'); +require_once('class.soap_fault.php'); + +// transport classes +require_once('class.soap_transport_http.php'); + +// optional add-on classes +require_once('class.xmlschema.php'); +require_once('class.wsdl.php'); + +// server class +require_once('class.soap_server.php');*/ + +// class variable emulation +// cf. http://www.webkreator.com/php/techniques/php-static-class-variables.html +$GLOBALS['_transient']['static']['nusoap_base']['globalDebugLevel'] = 9; + +/** +* +* nusoap_base +* +* @author Dietrich Ayala +* @author Scott Nichol + +* @access public +*/ +class nusoap_base { + /** + * Identification for HTTP headers. + * + * @var string + * @access private + */ + var $title = 'NuSOAP'; + /** + * Version for HTTP headers. + * + * @var string + * @access private + */ + var $version = '0.9.5'; + /** + * CVS revision for HTTP headers. + * + * @var string + * @access private + */ + var $revision = '$Revision: 57813 $'; + /** + * Current error string (manipulated by getError/setError) + * + * @var string + * @access private + */ + var $error_str = ''; + /** + * Current debug string (manipulated by debug/appendDebug/clearDebug/getDebug/getDebugAsXMLComment) + * + * @var string + * @access private + */ + var $debug_str = ''; + /** + * toggles automatic encoding of special characters as entities + * (should always be true, I think) + * + * @var boolean + * @access private + */ + var $charencoding = true; + /** + * the debug level for this instance + * + * @var integer + * @access private + */ + var $debugLevel; + + /** + * set schema version + * + * @var string + * @access public + */ + var $XMLSchemaVersion = 'http://www.w3.org/2001/XMLSchema'; + + /** + * charset encoding for outgoing messages + * + * @var string + * @access public + */ + //var $soap_defencoding = 'ISO-8859-1'; + var $soap_defencoding = 'UTF-8'; + + /** + * namespaces in an array of prefix => uri + * + * this is "seeded" by a set of constants, but it may be altered by code + * + * @var array + * @access public + */ + var $namespaces = array( + 'SOAP-ENV' => 'http://schemas.xmlsoap.org/soap/envelope/', + 'xsd' => 'http://www.w3.org/2001/XMLSchema', + 'xsi' => 'http://www.w3.org/2001/XMLSchema-instance', + 'SOAP-ENC' => 'http://schemas.xmlsoap.org/soap/encoding/' + ); + + /** + * namespaces used in the current context, e.g. during serialization + * + * @var array + * @access private + */ + var $usedNamespaces = array(); + + /** + * XML Schema types in an array of uri => (array of xml type => php type) + * is this legacy yet? + * no, this is used by the nusoap_xmlschema class to verify type => namespace mappings. + * @var array + * @access public + */ + var $typemap = array( + 'http://www.w3.org/2001/XMLSchema' => array( + 'string'=>'string','boolean'=>'boolean','float'=>'double','double'=>'double','decimal'=>'double', + 'duration'=>'','dateTime'=>'string','time'=>'string','date'=>'string','gYearMonth'=>'', + 'gYear'=>'','gMonthDay'=>'','gDay'=>'','gMonth'=>'','hexBinary'=>'string','base64Binary'=>'string', + // abstract "any" types + 'anyType'=>'string','anySimpleType'=>'string', + // derived datatypes + 'normalizedString'=>'string','token'=>'string','language'=>'','NMTOKEN'=>'','NMTOKENS'=>'','Name'=>'','NCName'=>'','ID'=>'', + 'IDREF'=>'','IDREFS'=>'','ENTITY'=>'','ENTITIES'=>'','integer'=>'integer','nonPositiveInteger'=>'integer', + 'negativeInteger'=>'integer','long'=>'integer','int'=>'integer','short'=>'integer','byte'=>'integer','nonNegativeInteger'=>'integer', + 'unsignedLong'=>'','unsignedInt'=>'','unsignedShort'=>'','unsignedByte'=>'','positiveInteger'=>''), + 'http://www.w3.org/2000/10/XMLSchema' => array( + 'i4'=>'','int'=>'integer','boolean'=>'boolean','string'=>'string','double'=>'double', + 'float'=>'double','dateTime'=>'string', + 'timeInstant'=>'string','base64Binary'=>'string','base64'=>'string','ur-type'=>'array'), + 'http://www.w3.org/1999/XMLSchema' => array( + 'i4'=>'','int'=>'integer','boolean'=>'boolean','string'=>'string','double'=>'double', + 'float'=>'double','dateTime'=>'string', + 'timeInstant'=>'string','base64Binary'=>'string','base64'=>'string','ur-type'=>'array'), + 'http://soapinterop.org/xsd' => array('SOAPStruct'=>'struct'), + 'http://schemas.xmlsoap.org/soap/encoding/' => array('base64'=>'string','array'=>'array','Array'=>'array'), + 'http://xml.apache.org/xml-soap' => array('Map') + ); + + /** + * XML entities to convert + * + * @var array + * @access public + * @deprecated + * @see expandEntities + */ + var $xmlEntities = array('quot' => '"','amp' => '&', + 'lt' => '<','gt' => '>','apos' => "'"); + + /** + * constructor + * + * @access public + */ + function nusoap_base() { + $this->debugLevel = $GLOBALS['_transient']['static']['nusoap_base']['globalDebugLevel']; + } + + /** + * gets the global debug level, which applies to future instances + * + * @return integer Debug level 0-9, where 0 turns off + * @access public + */ + function getGlobalDebugLevel() { + return $GLOBALS['_transient']['static']['nusoap_base']['globalDebugLevel']; + } + + /** + * sets the global debug level, which applies to future instances + * + * @param int $level Debug level 0-9, where 0 turns off + * @access public + */ + function setGlobalDebugLevel($level) { + $GLOBALS['_transient']['static']['nusoap_base']['globalDebugLevel'] = $level; + } + + /** + * gets the debug level for this instance + * + * @return int Debug level 0-9, where 0 turns off + * @access public + */ + function getDebugLevel() { + return $this->debugLevel; + } + + /** + * sets the debug level for this instance + * + * @param int $level Debug level 0-9, where 0 turns off + * @access public + */ + function setDebugLevel($level) { + $this->debugLevel = $level; + } + + /** + * adds debug data to the instance debug string with formatting + * + * @param string $string debug data + * @access private + */ + function debug($string){ + if ($this->debugLevel > 0) { + $this->appendDebug($this->getmicrotime().' '.get_class($this).": $string\n"); + } + } + + /** + * adds debug data to the instance debug string without formatting + * + * @param string $string debug data + * @access public + */ + function appendDebug($string){ + if ($this->debugLevel > 0) { + // it would be nice to use a memory stream here to use + // memory more efficiently + $this->debug_str .= $string; + } + } + + /** + * clears the current debug data for this instance + * + * @access public + */ + function clearDebug() { + // it would be nice to use a memory stream here to use + // memory more efficiently + $this->debug_str = ''; + } + + /** + * gets the current debug data for this instance + * + * @return debug data + * @access public + */ + function &getDebug() { + // it would be nice to use a memory stream here to use + // memory more efficiently + return $this->debug_str; + } + + /** + * gets the current debug data for this instance as an XML comment + * this may change the contents of the debug data + * + * @return debug data as an XML comment + * @access public + */ + function &getDebugAsXMLComment() { + // it would be nice to use a memory stream here to use + // memory more efficiently + while (strpos($this->debug_str, '--')) { + $this->debug_str = str_replace('--', '- -', $this->debug_str); + } + $ret = ""; + return $ret; + } + + /** + * expands entities, e.g. changes '<' to '<'. + * + * @param string $val The string in which to expand entities. + * @access private + */ + function expandEntities($val) { + if ($this->charencoding) { + $val = str_replace('&', '&', $val); + $val = str_replace("'", ''', $val); + $val = str_replace('"', '"', $val); + $val = str_replace('<', '<', $val); + $val = str_replace('>', '>', $val); + } + return $val; + } + + /** + * returns error string if present + * + * @return mixed error string or false + * @access public + */ + function getError(){ + if($this->error_str != ''){ + return $this->error_str; + } + return false; + } + + /** + * sets error string + * + * @return boolean $string error string + * @access private + */ + function setError($str){ + $this->error_str = $str; + } + + /** + * detect if array is a simple array or a struct (associative array) + * + * @param mixed $val The PHP array + * @return string (arraySimple|arrayStruct) + * @access private + */ + function isArraySimpleOrStruct($val) { + $keyList = array_keys($val); + foreach ($keyList as $keyListValue) { + if (!is_int($keyListValue)) { + return 'arrayStruct'; + } + } + return 'arraySimple'; + } + + /** + * serializes PHP values in accordance w/ section 5. Type information is + * not serialized if $use == 'literal'. + * + * @param mixed $val The value to serialize + * @param string $name The name (local part) of the XML element + * @param string $type The XML schema type (local part) for the element + * @param string $name_ns The namespace for the name of the XML element + * @param string $type_ns The namespace for the type of the element + * @param array $attributes The attributes to serialize as name=>value pairs + * @param string $use The WSDL "use" (encoded|literal) + * @param boolean $soapval Whether this is called from soapval. + * @return string The serialized element, possibly with child elements + * @access public + */ + function serialize_val($val,$name=false,$type=false,$name_ns=false,$type_ns=false,$attributes=false,$use='encoded',$soapval=false) { + $this->debug("in serialize_val: name=$name, type=$type, name_ns=$name_ns, type_ns=$type_ns, use=$use, soapval=$soapval"); + $this->appendDebug('value=' . $this->varDump($val)); + $this->appendDebug('attributes=' . $this->varDump($attributes)); + + if (is_object($val) && get_class($val) == 'soapval' && (! $soapval)) { + $this->debug("serialize_val: serialize soapval"); + $xml = $val->serialize($use); + $this->appendDebug($val->getDebug()); + $val->clearDebug(); + $this->debug("serialize_val of soapval returning $xml"); + return $xml; + } + // force valid name if necessary + if (is_numeric($name)) { + $name = '__numeric_' . $name; + } elseif (! $name) { + $name = 'noname'; + } + // if name has ns, add ns prefix to name + $xmlns = ''; + if($name_ns){ + $prefix = 'nu'.rand(1000,9999); + $name = $prefix.':'.$name; + $xmlns .= " xmlns:$prefix=\"$name_ns\""; + } + // if type is prefixed, create type prefix + if($type_ns != '' && $type_ns == $this->namespaces['xsd']){ + // need to fix this. shouldn't default to xsd if no ns specified + // w/o checking against typemap + $type_prefix = 'xsd'; + } elseif($type_ns){ + $type_prefix = 'ns'.rand(1000,9999); + $xmlns .= " xmlns:$type_prefix=\"$type_ns\""; + } + // serialize attributes if present + $atts = ''; + if($attributes){ + foreach($attributes as $k => $v){ + $atts .= " $k=\"".$this->expandEntities($v).'"'; + } + } + // serialize null value + if (is_null($val)) { + $this->debug("serialize_val: serialize null"); + if ($use == 'literal') { + // TODO: depends on minOccurs + $xml = "<$name$xmlns$atts/>"; + $this->debug("serialize_val returning $xml"); + return $xml; + } else { + if (isset($type) && isset($type_prefix)) { + $type_str = " xsi:type=\"$type_prefix:$type\""; + } else { + $type_str = ''; + } + $xml = "<$name$xmlns$type_str$atts xsi:nil=\"true\"/>"; + $this->debug("serialize_val returning $xml"); + return $xml; + } + } + // serialize if an xsd built-in primitive type + if($type != '' && isset($this->typemap[$this->XMLSchemaVersion][$type])){ + $this->debug("serialize_val: serialize xsd built-in primitive type"); + if (is_bool($val)) { + if ($type == 'boolean') { + $val = $val ? 'true' : 'false'; + } elseif (! $val) { + $val = 0; + } + } else if (is_string($val)) { + $val = $this->expandEntities($val); + } + if ($use == 'literal') { + $xml = "<$name$xmlns$atts>$val"; + $this->debug("serialize_val returning $xml"); + return $xml; + } else { + $xml = "<$name$xmlns xsi:type=\"xsd:$type\"$atts>$val"; + $this->debug("serialize_val returning $xml"); + return $xml; + } + } + // detect type and serialize + $xml = ''; + switch(true) { + case (is_bool($val) || $type == 'boolean'): + $this->debug("serialize_val: serialize boolean"); + if ($type == 'boolean') { + $val = $val ? 'true' : 'false'; + } elseif (! $val) { + $val = 0; + } + if ($use == 'literal') { + $xml .= "<$name$xmlns$atts>$val"; + } else { + $xml .= "<$name$xmlns xsi:type=\"xsd:boolean\"$atts>$val"; + } + break; + case (is_int($val) || is_long($val) || $type == 'int'): + $this->debug("serialize_val: serialize int"); + if ($use == 'literal') { + $xml .= "<$name$xmlns$atts>$val"; + } else { + $xml .= "<$name$xmlns xsi:type=\"xsd:int\"$atts>$val"; + } + break; + case (is_float($val)|| is_double($val) || $type == 'float'): + $this->debug("serialize_val: serialize float"); + if ($use == 'literal') { + $xml .= "<$name$xmlns$atts>$val"; + } else { + $xml .= "<$name$xmlns xsi:type=\"xsd:float\"$atts>$val"; + } + break; + case (is_string($val) || $type == 'string'): + $this->debug("serialize_val: serialize string"); + $val = $this->expandEntities($val); + if ($use == 'literal') { + $xml .= "<$name$xmlns$atts>$val"; + } else { + $xml .= "<$name$xmlns xsi:type=\"xsd:string\"$atts>$val"; + } + break; + case is_object($val): + $this->debug("serialize_val: serialize object"); + if (get_class($val) == 'soapval') { + $this->debug("serialize_val: serialize soapval object"); + $pXml = $val->serialize($use); + $this->appendDebug($val->getDebug()); + $val->clearDebug(); + } else { + if (! $name) { + $name = get_class($val); + $this->debug("In serialize_val, used class name $name as element name"); + } else { + $this->debug("In serialize_val, do not override name $name for element name for class " . get_class($val)); + } + foreach(get_object_vars($val) as $k => $v){ + $pXml = isset($pXml) ? $pXml.$this->serialize_val($v,$k,false,false,false,false,$use) : $this->serialize_val($v,$k,false,false,false,false,$use); + } + } + if(isset($type) && isset($type_prefix)){ + $type_str = " xsi:type=\"$type_prefix:$type\""; + } else { + $type_str = ''; + } + if ($use == 'literal') { + $xml .= "<$name$xmlns$atts>$pXml"; + } else { + $xml .= "<$name$xmlns$type_str$atts>$pXml"; + } + break; + break; + case (is_array($val) || $type): + // detect if struct or array + $valueType = $this->isArraySimpleOrStruct($val); + if($valueType=='arraySimple' || preg_match('/^ArrayOf/',$type)){ + $this->debug("serialize_val: serialize array"); + $i = 0; + if(is_array($val) && count($val)> 0){ + foreach($val as $v){ + if(is_object($v) && get_class($v) == 'soapval'){ + $tt_ns = $v->type_ns; + $tt = $v->type; + } elseif (is_array($v)) { + $tt = $this->isArraySimpleOrStruct($v); + } else { + $tt = gettype($v); + } + $array_types[$tt] = 1; + // TODO: for literal, the name should be $name + $xml .= $this->serialize_val($v,'item',false,false,false,false,$use); + ++$i; + } + if(count($array_types) > 1){ + $array_typename = 'xsd:anyType'; + } elseif(isset($tt) && isset($this->typemap[$this->XMLSchemaVersion][$tt])) { + if ($tt == 'integer') { + $tt = 'int'; + } + $array_typename = 'xsd:'.$tt; + } elseif(isset($tt) && $tt == 'arraySimple'){ + $array_typename = 'SOAP-ENC:Array'; + } elseif(isset($tt) && $tt == 'arrayStruct'){ + $array_typename = 'unnamed_struct_use_soapval'; + } else { + // if type is prefixed, create type prefix + if ($tt_ns != '' && $tt_ns == $this->namespaces['xsd']){ + $array_typename = 'xsd:' . $tt; + } elseif ($tt_ns) { + $tt_prefix = 'ns' . rand(1000, 9999); + $array_typename = "$tt_prefix:$tt"; + $xmlns .= " xmlns:$tt_prefix=\"$tt_ns\""; + } else { + $array_typename = $tt; + } + } + $array_type = $i; + if ($use == 'literal') { + $type_str = ''; + } else if (isset($type) && isset($type_prefix)) { + $type_str = " xsi:type=\"$type_prefix:$type\""; + } else { + $type_str = " xsi:type=\"SOAP-ENC:Array\" SOAP-ENC:arrayType=\"".$array_typename."[$array_type]\""; + } + // empty array + } else { + if ($use == 'literal') { + $type_str = ''; + } else if (isset($type) && isset($type_prefix)) { + $type_str = " xsi:type=\"$type_prefix:$type\""; + } else { + $type_str = " xsi:type=\"SOAP-ENC:Array\" SOAP-ENC:arrayType=\"xsd:anyType[0]\""; + } + } + // TODO: for array in literal, there is no wrapper here + $xml = "<$name$xmlns$type_str$atts>".$xml.""; + } else { + // got a struct + $this->debug("serialize_val: serialize struct"); + if(isset($type) && isset($type_prefix)){ + $type_str = " xsi:type=\"$type_prefix:$type\""; + } else { + $type_str = ''; + } + if ($use == 'literal') { + $xml .= "<$name$xmlns$atts>"; + } else { + $xml .= "<$name$xmlns$type_str$atts>"; + } + foreach($val as $k => $v){ + // Apache Map + if ($type == 'Map' && $type_ns == 'http://xml.apache.org/xml-soap') { + $xml .= ''; + $xml .= $this->serialize_val($k,'key',false,false,false,false,$use); + $xml .= $this->serialize_val($v,'value',false,false,false,false,$use); + $xml .= ''; + } else { + $xml .= $this->serialize_val($v,$k,false,false,false,false,$use); + } + } + $xml .= ""; + } + break; + default: + $this->debug("serialize_val: serialize unknown"); + $xml .= 'not detected, got '.gettype($val).' for '.$val; + break; + } + $this->debug("serialize_val returning $xml"); + return $xml; + } + + /** + * serializes a message + * + * @param string $body the XML of the SOAP body + * @param mixed $headers optional string of XML with SOAP header content, or array of soapval objects for SOAP headers, or associative array + * @param array $namespaces optional the namespaces used in generating the body and headers + * @param string $style optional (rpc|document) + * @param string $use optional (encoded|literal) + * @param string $encodingStyle optional (usually 'http://schemas.xmlsoap.org/soap/encoding/' for encoded) + * @return string the message + * @access public + */ + function serializeEnvelope($body,$headers=false,$namespaces=array(),$style='rpc',$use='encoded',$encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'){ + // TODO: add an option to automatically run utf8_encode on $body and $headers + // if $this->soap_defencoding is UTF-8. Not doing this automatically allows + // one to send arbitrary UTF-8 characters, not just characters that map to ISO-8859-1 + + $this->debug("In serializeEnvelope length=" . strlen($body) . " body (max 1000 characters)=" . substr($body, 0, 1000) . " style=$style use=$use encodingStyle=$encodingStyle"); + $this->debug("headers:"); + $this->appendDebug($this->varDump($headers)); + $this->debug("namespaces:"); + $this->appendDebug($this->varDump($namespaces)); + + // serialize namespaces + $ns_string = ''; + foreach(array_merge($this->namespaces,$namespaces) as $k => $v){ + $ns_string .= " xmlns:$k=\"$v\""; + } + if($encodingStyle) { + $ns_string = " SOAP-ENV:encodingStyle=\"$encodingStyle\"$ns_string"; + } + + // serialize headers + if($headers){ + if (is_array($headers)) { + $xml = ''; + foreach ($headers as $k => $v) { + if (is_object($v) && get_class($v) == 'soapval') { + $xml .= $this->serialize_val($v, false, false, false, false, false, $use); + } else { + $xml .= $this->serialize_val($v, $k, false, false, false, false, $use); + } + } + $headers = $xml; + $this->debug("In serializeEnvelope, serialized array of headers to $headers"); + } + $headers = "".$headers.""; + } + // serialize envelope + return + 'soap_defencoding .'"?'.">". + '". + $headers. + "". + $body. + "". + ""; + } + + /** + * formats a string to be inserted into an HTML stream + * + * @param string $str The string to format + * @return string The formatted string + * @access public + * @deprecated + */ + function formatDump($str){ + $str = htmlspecialchars($str); + return nl2br($str); + } + + /** + * contracts (changes namespace to prefix) a qualified name + * + * @param string $qname qname + * @return string contracted qname + * @access private + */ + function contractQname($qname){ + // get element namespace + //$this->xdebug("Contract $qname"); + if (strrpos($qname, ':')) { + // get unqualified name + $name = substr($qname, strrpos($qname, ':') + 1); + // get ns + $ns = substr($qname, 0, strrpos($qname, ':')); + $p = $this->getPrefixFromNamespace($ns); + if ($p) { + return $p . ':' . $name; + } + return $qname; + } else { + return $qname; + } + } + + /** + * expands (changes prefix to namespace) a qualified name + * + * @param string $qname qname + * @return string expanded qname + * @access private + */ + function expandQname($qname){ + // get element prefix + if(strpos($qname,':') && !preg_match('/^http:\/\//',$qname)){ + // get unqualified name + $name = substr(strstr($qname,':'),1); + // get ns prefix + $prefix = substr($qname,0,strpos($qname,':')); + if(isset($this->namespaces[$prefix])){ + return $this->namespaces[$prefix].':'.$name; + } else { + return $qname; + } + } else { + return $qname; + } + } + + /** + * returns the local part of a prefixed string + * returns the original string, if not prefixed + * + * @param string $str The prefixed string + * @return string The local part + * @access public + */ + function getLocalPart($str){ + if($sstr = strrchr($str,':')){ + // get unqualified name + return substr( $sstr, 1 ); + } else { + return $str; + } + } + + /** + * returns the prefix part of a prefixed string + * returns false, if not prefixed + * + * @param string $str The prefixed string + * @return mixed The prefix or false if there is no prefix + * @access public + */ + function getPrefix($str){ + if($pos = strrpos($str,':')){ + // get prefix + return substr($str,0,$pos); + } + return false; + } + + /** + * pass it a prefix, it returns a namespace + * + * @param string $prefix The prefix + * @return mixed The namespace, false if no namespace has the specified prefix + * @access public + */ + function getNamespaceFromPrefix($prefix){ + if (isset($this->namespaces[$prefix])) { + return $this->namespaces[$prefix]; + } + //$this->setError("No namespace registered for prefix '$prefix'"); + return false; + } + + /** + * returns the prefix for a given namespace (or prefix) + * or false if no prefixes registered for the given namespace + * + * @param string $ns The namespace + * @return mixed The prefix, false if the namespace has no prefixes + * @access public + */ + function getPrefixFromNamespace($ns) { + foreach ($this->namespaces as $p => $n) { + if ($ns == $n || $ns == $p) { + $this->usedNamespaces[$p] = $n; + return $p; + } + } + return false; + } + + /** + * returns the time in ODBC canonical form with microseconds + * + * @return string The time in ODBC canonical form with microseconds + * @access public + */ + function getmicrotime() { + if (function_exists('gettimeofday')) { + $tod = gettimeofday(); + $sec = $tod['sec']; + $usec = $tod['usec']; + } else { + $sec = time(); + $usec = 0; + } + return strftime('%Y-%m-%d %H:%M:%S', $sec) . '.' . sprintf('%06d', $usec); + } + + /** + * Returns a string with the output of var_dump + * + * @param mixed $data The variable to var_dump + * @return string The output of var_dump + * @access public + */ + function varDump($data) { + ob_start(); + var_dump($data); + $ret_val = ob_get_contents(); + ob_end_clean(); + return $ret_val; + } + + /** + * represents the object as a string + * + * @return string + * @access public + */ + function __toString() { + return $this->varDump($this); + } +} + +// XML Schema Datatype Helper Functions + +//xsd:dateTime helpers + +/** +* convert unix timestamp to ISO 8601 compliant date string +* +* @param int $timestamp Unix time stamp +* @param boolean $utc Whether the time stamp is UTC or local +* @return mixed ISO 8601 date string or false +* @access public +*/ +function timestamp_to_iso8601($timestamp,$utc=true){ + $datestr = date('Y-m-d\TH:i:sO',$timestamp); + $pos = strrpos($datestr, "+"); + if ($pos === FALSE) { + $pos = strrpos($datestr, "-"); + } + if ($pos !== FALSE) { + if (strlen($datestr) == $pos + 5) { + $datestr = substr($datestr, 0, $pos + 3) . ':' . substr($datestr, -2); + } + } + if($utc){ + $pattern = '/'. + '([0-9]{4})-'. // centuries & years CCYY- + '([0-9]{2})-'. // months MM- + '([0-9]{2})'. // days DD + 'T'. // separator T + '([0-9]{2}):'. // hours hh: + '([0-9]{2}):'. // minutes mm: + '([0-9]{2})(\.[0-9]*)?'. // seconds ss.ss... + '(Z|[+\-][0-9]{2}:?[0-9]{2})?'. // Z to indicate UTC, -/+HH:MM:SS.SS... for local tz's + '/'; + + if(preg_match($pattern,$datestr,$regs)){ + return sprintf('%04d-%02d-%02dT%02d:%02d:%02dZ',$regs[1],$regs[2],$regs[3],$regs[4],$regs[5],$regs[6]); + } + return false; + } else { + return $datestr; + } +} + +/** +* convert ISO 8601 compliant date string to unix timestamp +* +* @param string $datestr ISO 8601 compliant date string +* @return mixed Unix timestamp (int) or false +* @access public +*/ +function iso8601_to_timestamp($datestr){ + $pattern = '/'. + '([0-9]{4})-'. // centuries & years CCYY- + '([0-9]{2})-'. // months MM- + '([0-9]{2})'. // days DD + 'T'. // separator T + '([0-9]{2}):'. // hours hh: + '([0-9]{2}):'. // minutes mm: + '([0-9]{2})(\.[0-9]+)?'. // seconds ss.ss... + '(Z|[+\-][0-9]{2}:?[0-9]{2})?'. // Z to indicate UTC, -/+HH:MM:SS.SS... for local tz's + '/'; + if(preg_match($pattern,$datestr,$regs)){ + // not utc + if($regs[8] != 'Z'){ + $op = substr($regs[8],0,1); + $h = substr($regs[8],1,2); + $m = substr($regs[8],strlen($regs[8])-2,2); + if($op == '-'){ + $regs[4] = $regs[4] + $h; + $regs[5] = $regs[5] + $m; + } elseif($op == '+'){ + $regs[4] = $regs[4] - $h; + $regs[5] = $regs[5] - $m; + } + } + return gmmktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]); +// return strtotime("$regs[1]-$regs[2]-$regs[3] $regs[4]:$regs[5]:$regs[6]Z"); + } else { + return false; + } +} + +/** +* sleeps some number of microseconds +* +* @param string $usec the number of microseconds to sleep +* @access public +* @deprecated +*/ +function usleepWindows($usec) +{ + $start = gettimeofday(); + + do + { + $stop = gettimeofday(); + $timePassed = 1000000 * ($stop['sec'] - $start['sec']) + + $stop['usec'] - $start['usec']; + } + while ($timePassed < $usec); +} + + +?> \ No newline at end of file diff --git a/include/nusoap/class.soap_fault.php b/include/nusoap/class.soap_fault.php new file mode 100644 index 00000000..015b9241 --- /dev/null +++ b/include/nusoap/class.soap_fault.php @@ -0,0 +1,131 @@ + + Bug 39085 - When loading the opposite search panel via ajax on the ListViews, call the index action instead of the ListView action to avoid touching pre-MVC code by accident. + +r56990 - 2010-06-16 13:05:36 -0700 (Wed, 16 Jun 2010) - kjing - snapshot "Mango" svn branch to a new one for GitHub sync + +r56989 - 2010-06-16 13:01:33 -0700 (Wed, 16 Jun 2010) - kjing - defunt "Mango" svn dev branch before github cutover + +r55980 - 2010-04-19 13:31:28 -0700 (Mon, 19 Apr 2010) - kjing - create Mango (6.1) based on windex + +r51719 - 2009-10-22 10:18:00 -0700 (Thu, 22 Oct 2009) - mitani - Converted to Build 3 tags and updated the build system + +r51634 - 2009-10-19 13:32:22 -0700 (Mon, 19 Oct 2009) - mitani - Windex is the branch for Sugar Sales 1.0 development + +r50375 - 2009-08-24 18:07:43 -0700 (Mon, 24 Aug 2009) - dwong - branch kobe2 from tokyo r50372 + +r42807 - 2008-12-29 11:16:59 -0800 (Mon, 29 Dec 2008) - dwong - Branch from trunk/sugarcrm r42806 to branches/tokyo/sugarcrm + +r13782 - 2006-06-06 10:58:55 -0700 (Tue, 06 Jun 2006) - majed - changes entry point code + +r11115 - 2006-01-17 14:54:45 -0800 (Tue, 17 Jan 2006) - majed - add entry point validation + +r8846 - 2005-10-31 11:01:12 -0800 (Mon, 31 Oct 2005) - majed - new version of nusoap + +r5462 - 2005-05-25 13:50:11 -0700 (Wed, 25 May 2005) - majed - upgraded nusoap to .6.9 + +r573 - 2004-09-04 13:03:32 -0700 (Sat, 04 Sep 2004) - sugarclint - undoing copyrights added in inadvertantly. --clint + +r546 - 2004-09-03 11:49:38 -0700 (Fri, 03 Sep 2004) - sugarmsi - removed echo count + +r354 - 2004-08-02 23:00:37 -0700 (Mon, 02 Aug 2004) - sugarjacob - Adding Soap + + +*/ + + +if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point'); + + + + +/** +* Contains information for a SOAP fault. +* Mainly used for returning faults from deployed functions +* in a server instance. +* @author Dietrich Ayala + +* @access public +*/ +class nusoap_fault extends nusoap_base { + /** + * The fault code (client|server) + * @var string + * @access private + */ + var $faultcode; + /** + * The fault actor + * @var string + * @access private + */ + var $faultactor; + /** + * The fault string, a description of the fault + * @var string + * @access private + */ + var $faultstring; + /** + * The fault detail, typically a string or array of string + * @var mixed + * @access private + */ + var $faultdetail; + + /** + * constructor + * + * @param string $faultcode (SOAP-ENV:Client | SOAP-ENV:Server) + * @param string $faultactor only used when msg routed between multiple actors + * @param string $faultstring human readable error message + * @param mixed $faultdetail detail, typically a string or array of string + */ + function nusoap_fault($faultcode,$faultactor='',$faultstring='',$faultdetail=''){ + parent::nusoap_base(); + $this->faultcode = $faultcode; + $this->faultactor = $faultactor; + $this->faultstring = $faultstring; + $this->faultdetail = $faultdetail; + } + + /** + * serialize a fault + * + * @return string The serialization of the fault instance. + * @access public + */ + function serialize(){ + $ns_string = ''; + foreach($this->namespaces as $k => $v){ + $ns_string .= "\n xmlns:$k=\"$v\""; + } + $return_msg = + 'soap_defencoding.'"?>'. + '\n". + ''. + ''. + $this->serialize_val($this->faultcode, 'faultcode'). + $this->serialize_val($this->faultactor, 'faultactor'). + $this->serialize_val($this->faultstring, 'faultstring'). + $this->serialize_val($this->faultdetail, 'detail'). + ''. + ''. + ''; + return $return_msg; + } +} + +/** + * Backward compatibility + */ +class soap_fault extends nusoap_fault { +} + + +?> \ No newline at end of file diff --git a/include/nusoap/class.soap_parser.php b/include/nusoap/class.soap_parser.php new file mode 100644 index 00000000..70179d08 --- /dev/null +++ b/include/nusoap/class.soap_parser.php @@ -0,0 +1,693 @@ + + Bug 39085 - When loading the opposite search panel via ajax on the ListViews, call the index action instead of the ListView action to avoid touching pre-MVC code by accident. + +r56990 - 2010-06-16 13:05:36 -0700 (Wed, 16 Jun 2010) - kjing - snapshot "Mango" svn branch to a new one for GitHub sync + +r56989 - 2010-06-16 13:01:33 -0700 (Wed, 16 Jun 2010) - kjing - defunt "Mango" svn dev branch before github cutover + +r55980 - 2010-04-19 13:31:28 -0700 (Mon, 19 Apr 2010) - kjing - create Mango (6.1) based on windex + +r51719 - 2009-10-22 10:18:00 -0700 (Thu, 22 Oct 2009) - mitani - Converted to Build 3 tags and updated the build system + +r51634 - 2009-10-19 13:32:22 -0700 (Mon, 19 Oct 2009) - mitani - Windex is the branch for Sugar Sales 1.0 development + +r51443 - 2009-10-12 13:34:36 -0700 (Mon, 12 Oct 2009) - jmertic - Bug 33332 - Made application PHP 5.3 compliant with E_DEPRECATED warnings on by: +- Changing all ereg function to either preg or simple string based ones +- No more references to magic quotes. +- Change all the session_unregister() functions to just unset() the correct session variable instead. + +r50375 - 2009-08-24 18:07:43 -0700 (Mon, 24 Aug 2009) - dwong - branch kobe2 from tokyo r50372 + +r42807 - 2008-12-29 11:16:59 -0800 (Mon, 29 Dec 2008) - dwong - Branch from trunk/sugarcrm r42806 to branches/tokyo/sugarcrm + +r13782 - 2006-06-06 10:58:55 -0700 (Tue, 06 Jun 2006) - majed - changes entry point code + +r11115 - 2006-01-17 14:54:45 -0800 (Tue, 17 Jan 2006) - majed - add entry point validation + +r8846 - 2005-10-31 11:01:12 -0800 (Mon, 31 Oct 2005) - majed - new version of nusoap + +r7905 - 2005-09-21 19:12:57 -0700 (Wed, 21 Sep 2005) - majed - restores old nusoap pre & with a few fixes + +r7861 - 2005-09-20 15:40:25 -0700 (Tue, 20 Sep 2005) - majed - & fix for 3.5.1 + +r5462 - 2005-05-25 13:50:11 -0700 (Wed, 25 May 2005) - majed - upgraded nusoap to .6.9 + +r573 - 2004-09-04 13:03:32 -0700 (Sat, 04 Sep 2004) - sugarclint - undoing copyrights added in inadvertantly. --clint + +r546 - 2004-09-03 11:49:38 -0700 (Fri, 03 Sep 2004) - sugarmsi - removed echo count + +r354 - 2004-08-02 23:00:37 -0700 (Mon, 02 Aug 2004) - sugarjacob - Adding Soap + + +*/ + + +if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point'); + + + + +/** +* +* nusoap_parser class parses SOAP XML messages into native PHP values +* +* @author Dietrich Ayala +* @author Scott Nichol + +* @access public +*/ +class nusoap_parser extends nusoap_base { + + var $xml = ''; + var $xml_encoding = ''; + var $method = ''; + var $root_struct = ''; + var $root_struct_name = ''; + var $root_struct_namespace = ''; + var $root_header = ''; + var $document = ''; // incoming SOAP body (text) + // determines where in the message we are (envelope,header,body,method) + var $status = ''; + var $position = 0; + var $depth = 0; + var $default_namespace = ''; + var $namespaces = array(); + var $message = array(); + var $parent = ''; + var $fault = false; + var $fault_code = ''; + var $fault_str = ''; + var $fault_detail = ''; + var $depth_array = array(); + var $debug_flag = true; + var $soapresponse = NULL; // parsed SOAP Body + var $soapheader = NULL; // parsed SOAP Header + var $responseHeaders = ''; // incoming SOAP headers (text) + var $body_position = 0; + // for multiref parsing: + // array of id => pos + var $ids = array(); + // array of id => hrefs => pos + var $multirefs = array(); + // toggle for auto-decoding element content + var $decode_utf8 = true; + + /** + * constructor that actually does the parsing + * + * @param string $xml SOAP message + * @param string $encoding character encoding scheme of message + * @param string $method method for which XML is parsed (unused?) + * @param string $decode_utf8 whether to decode UTF-8 to ISO-8859-1 + * @access public + */ + function nusoap_parser($xml,$encoding='UTF-8',$method='',$decode_utf8=true){ + parent::nusoap_base(); + $this->xml = $xml; + $this->xml_encoding = $encoding; + $this->method = $method; + $this->decode_utf8 = $decode_utf8; + + // Check whether content has been read. + if(!empty($xml)){ + // Check XML encoding + $pos_xml = strpos($xml, '', $pos_xml + 2) - $pos_xml + 1); + if (preg_match("/encoding=[\"']([^\"']*)[\"']/", $xml_decl, $res)) { + $xml_encoding = $res[1]; + if (strtoupper($xml_encoding) != $encoding) { + $err = "Charset from HTTP Content-Type '" . $encoding . "' does not match encoding from XML declaration '" . $xml_encoding . "'"; + $this->debug($err); + if ($encoding != 'ISO-8859-1' || strtoupper($xml_encoding) != 'UTF-8') { + $this->setError($err); + return; + } + // when HTTP says ISO-8859-1 (the default) and XML says UTF-8 (the typical), assume the other endpoint is just sloppy and proceed + } else { + $this->debug('Charset from HTTP Content-Type matches encoding from XML declaration'); + } + } else { + $this->debug('No encoding specified in XML declaration'); + } + } else { + $this->debug('No XML declaration'); + } + $this->debug('Entering nusoap_parser(), length='.strlen($xml).', encoding='.$encoding); + // Create an XML parser - why not xml_parser_create_ns? + $this->parser = xml_parser_create($this->xml_encoding); + // Set the options for parsing the XML data. + //xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1); + xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0); + xml_parser_set_option($this->parser, XML_OPTION_TARGET_ENCODING, $this->xml_encoding); + // Set the object for the parser. + xml_set_object($this->parser, $this); + // Set the element handlers for the parser. + xml_set_element_handler($this->parser, 'start_element','end_element'); + xml_set_character_data_handler($this->parser,'character_data'); + + // Parse the XML file. + if(!xml_parse($this->parser,$xml,true)){ + // Display an error message. + $err = sprintf('XML error parsing SOAP payload on line %d: %s', + xml_get_current_line_number($this->parser), + xml_error_string(xml_get_error_code($this->parser))); + $this->debug($err); + $this->debug("XML payload:\n" . $xml); + $this->setError($err); + } else { + $this->debug('in nusoap_parser ctor, message:'); + $this->appendDebug($this->varDump($this->message)); + $this->debug('parsed successfully, found root struct: '.$this->root_struct.' of name '.$this->root_struct_name); + // get final value + $this->soapresponse = $this->message[$this->root_struct]['result']; + // get header value + if($this->root_header != '' && isset($this->message[$this->root_header]['result'])){ + $this->soapheader = $this->message[$this->root_header]['result']; + } + // resolve hrefs/ids + if(sizeof($this->multirefs) > 0){ + foreach($this->multirefs as $id => $hrefs){ + $this->debug('resolving multirefs for id: '.$id); + $idVal = $this->buildVal($this->ids[$id]); + if (is_array($idVal) && isset($idVal['!id'])) { + unset($idVal['!id']); + } + foreach($hrefs as $refPos => $ref){ + $this->debug('resolving href at pos '.$refPos); + $this->multirefs[$id][$refPos] = $idVal; + } + } + } + } + xml_parser_free($this->parser); + } else { + $this->debug('xml was empty, didn\'t parse!'); + $this->setError('xml was empty, didn\'t parse!'); + } + } + + /** + * start-element handler + * + * @param resource $parser XML parser object + * @param string $name element name + * @param array $attrs associative array of attributes + * @access private + */ + function start_element($parser, $name, $attrs) { + // position in a total number of elements, starting from 0 + // update class level pos + $pos = $this->position++; + // and set mine + $this->message[$pos] = array('pos' => $pos,'children'=>'','cdata'=>''); + // depth = how many levels removed from root? + // set mine as current global depth and increment global depth value + $this->message[$pos]['depth'] = $this->depth++; + + // else add self as child to whoever the current parent is + if($pos != 0){ + $this->message[$this->parent]['children'] .= '|'.$pos; + } + // set my parent + $this->message[$pos]['parent'] = $this->parent; + // set self as current parent + $this->parent = $pos; + // set self as current value for this depth + $this->depth_array[$this->depth] = $pos; + // get element prefix + if(strpos($name,':')){ + // get ns prefix + $prefix = substr($name,0,strpos($name,':')); + // get unqualified name + $name = substr(strstr($name,':'),1); + } + // set status + if ($name == 'Envelope' && $this->status == '') { + $this->status = 'envelope'; + } elseif ($name == 'Header' && $this->status == 'envelope') { + $this->root_header = $pos; + $this->status = 'header'; + } elseif ($name == 'Body' && $this->status == 'envelope'){ + $this->status = 'body'; + $this->body_position = $pos; + // set method + } elseif($this->status == 'body' && $pos == ($this->body_position+1)) { + $this->status = 'method'; + $this->root_struct_name = $name; + $this->root_struct = $pos; + $this->message[$pos]['type'] = 'struct'; + $this->debug("found root struct $this->root_struct_name, pos $this->root_struct"); + } + // set my status + $this->message[$pos]['status'] = $this->status; + // set name + $this->message[$pos]['name'] = htmlspecialchars($name); + // set attrs + $this->message[$pos]['attrs'] = $attrs; + + // loop through atts, logging ns and type declarations + $attstr = ''; + foreach($attrs as $key => $value){ + $key_prefix = $this->getPrefix($key); + $key_localpart = $this->getLocalPart($key); + // if ns declarations, add to class level array of valid namespaces + if($key_prefix == 'xmlns'){ + if(preg_match('/^http:\/\/www.w3.org\/[0-9]{4}\/XMLSchema$/',$value)){ + $this->XMLSchemaVersion = $value; + $this->namespaces['xsd'] = $this->XMLSchemaVersion; + $this->namespaces['xsi'] = $this->XMLSchemaVersion.'-instance'; + } + $this->namespaces[$key_localpart] = $value; + // set method namespace + if($name == $this->root_struct_name){ + $this->methodNamespace = $value; + } + // if it's a type declaration, set type + } elseif($key_localpart == 'type'){ + if (isset($this->message[$pos]['type']) && $this->message[$pos]['type'] == 'array') { + // do nothing: already processed arrayType + } else { + $value_prefix = $this->getPrefix($value); + $value_localpart = $this->getLocalPart($value); + $this->message[$pos]['type'] = $value_localpart; + $this->message[$pos]['typePrefix'] = $value_prefix; + if(isset($this->namespaces[$value_prefix])){ + $this->message[$pos]['type_namespace'] = $this->namespaces[$value_prefix]; + } else if(isset($attrs['xmlns:'.$value_prefix])) { + $this->message[$pos]['type_namespace'] = $attrs['xmlns:'.$value_prefix]; + } + // should do something here with the namespace of specified type? + } + } elseif($key_localpart == 'arrayType'){ + $this->message[$pos]['type'] = 'array'; + /* do arrayType ereg here + [1] arrayTypeValue ::= atype asize + [2] atype ::= QName rank* + [3] rank ::= '[' (',')* ']' + [4] asize ::= '[' length~ ']' + [5] length ::= nextDimension* Digit+ + [6] nextDimension ::= Digit+ ',' + */ + $expr = '/([A-Za-z0-9_]+):([A-Za-z]+[A-Za-z0-9_]+)\[([0-9]+),?([0-9]*)\]/'; + if(preg_match($expr,$value,$regs)){ + $this->message[$pos]['typePrefix'] = $regs[1]; + $this->message[$pos]['arrayTypePrefix'] = $regs[1]; + if (isset($this->namespaces[$regs[1]])) { + $this->message[$pos]['arrayTypeNamespace'] = $this->namespaces[$regs[1]]; + } else if (isset($attrs['xmlns:'.$regs[1]])) { + $this->message[$pos]['arrayTypeNamespace'] = $attrs['xmlns:'.$regs[1]]; + } + $this->message[$pos]['arrayType'] = $regs[2]; + $this->message[$pos]['arraySize'] = $regs[3]; + $this->message[$pos]['arrayCols'] = $regs[4]; + } + // specifies nil value (or not) + } elseif ($key_localpart == 'nil'){ + $this->message[$pos]['nil'] = ($value == 'true' || $value == '1'); + // some other attribute + } elseif ($key != 'href' && $key != 'xmlns' && $key_localpart != 'encodingStyle' && $key_localpart != 'root') { + $this->message[$pos]['xattrs']['!' . $key] = $value; + } + + if ($key == 'xmlns') { + $this->default_namespace = $value; + } + // log id + if($key == 'id'){ + $this->ids[$value] = $pos; + } + // root + if($key_localpart == 'root' && $value == 1){ + $this->status = 'method'; + $this->root_struct_name = $name; + $this->root_struct = $pos; + $this->debug("found root struct $this->root_struct_name, pos $pos"); + } + // for doclit + $attstr .= " $key=\"$value\""; + } + // get namespace - must be done after namespace atts are processed + if(isset($prefix)){ + $this->message[$pos]['namespace'] = $this->namespaces[$prefix]; + $this->default_namespace = $this->namespaces[$prefix]; + } else { + $this->message[$pos]['namespace'] = $this->default_namespace; + } + if($this->status == 'header'){ + if ($this->root_header != $pos) { + $this->responseHeaders .= "<" . (isset($prefix) ? $prefix . ':' : '') . "$name$attstr>"; + } + } elseif($this->root_struct_name != ''){ + $this->document .= "<" . (isset($prefix) ? $prefix . ':' : '') . "$name$attstr>"; + } + } + + /** + * end-element handler + * + * @param resource $parser XML parser object + * @param string $name element name + * @access private + */ + function end_element($parser, $name) { + // position of current element is equal to the last value left in depth_array for my depth + $pos = $this->depth_array[$this->depth--]; + + // get element prefix + if(strpos($name,':')){ + // get ns prefix + $prefix = substr($name,0,strpos($name,':')); + // get unqualified name + $name = substr(strstr($name,':'),1); + } + + // build to native type + if(isset($this->body_position) && $pos > $this->body_position){ + // deal w/ multirefs + if(isset($this->message[$pos]['attrs']['href'])){ + // get id + $id = substr($this->message[$pos]['attrs']['href'],1); + // add placeholder to href array + $this->multirefs[$id][$pos] = 'placeholder'; + // add set a reference to it as the result value + $this->message[$pos]['result'] =& $this->multirefs[$id][$pos]; + // build complexType values + } elseif($this->message[$pos]['children'] != ''){ + // if result has already been generated (struct/array) + if(!isset($this->message[$pos]['result'])){ + $this->message[$pos]['result'] = $this->buildVal($pos); + } + // build complexType values of attributes and possibly simpleContent + } elseif (isset($this->message[$pos]['xattrs'])) { + if (isset($this->message[$pos]['nil']) && $this->message[$pos]['nil']) { + $this->message[$pos]['xattrs']['!'] = null; + } elseif (isset($this->message[$pos]['cdata']) && trim($this->message[$pos]['cdata']) != '') { + if (isset($this->message[$pos]['type'])) { + $this->message[$pos]['xattrs']['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$pos]['type'], isset($this->message[$pos]['type_namespace']) ? $this->message[$pos]['type_namespace'] : ''); + } else { + $parent = $this->message[$pos]['parent']; + if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) { + $this->message[$pos]['xattrs']['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : ''); + } else { + $this->message[$pos]['xattrs']['!'] = $this->message[$pos]['cdata']; + } + } + } + $this->message[$pos]['result'] = $this->message[$pos]['xattrs']; + // set value of simpleType (or nil complexType) + } else { + //$this->debug('adding data for scalar value '.$this->message[$pos]['name'].' of value '.$this->message[$pos]['cdata']); + if (isset($this->message[$pos]['nil']) && $this->message[$pos]['nil']) { + $this->message[$pos]['xattrs']['!'] = null; + } elseif (isset($this->message[$pos]['type'])) { + $this->message[$pos]['result'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$pos]['type'], isset($this->message[$pos]['type_namespace']) ? $this->message[$pos]['type_namespace'] : ''); + } else { + $parent = $this->message[$pos]['parent']; + if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) { + $this->message[$pos]['result'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : ''); + } else { + $this->message[$pos]['result'] = $this->message[$pos]['cdata']; + } + } + + /* add value to parent's result, if parent is struct/array + $parent = $this->message[$pos]['parent']; + if($this->message[$parent]['type'] != 'map'){ + if(strtolower($this->message[$parent]['type']) == 'array'){ + $this->message[$parent]['result'][] = $this->message[$pos]['result']; + } else { + $this->message[$parent]['result'][$this->message[$pos]['name']] = $this->message[$pos]['result']; + } + } + */ + } + } + + // for doclit + if($this->status == 'header'){ + if ($this->root_header != $pos) { + $this->responseHeaders .= ""; + } + } elseif($pos >= $this->root_struct){ + $this->document .= ""; + } + // switch status + if ($pos == $this->root_struct){ + $this->status = 'body'; + $this->root_struct_namespace = $this->message[$pos]['namespace']; + } elseif ($pos == $this->root_header) { + $this->status = 'envelope'; + } elseif ($name == 'Body' && $this->status == 'body') { + $this->status = 'envelope'; + } elseif ($name == 'Header' && $this->status == 'header') { // will never happen + $this->status = 'envelope'; + } elseif ($name == 'Envelope' && $this->status == 'envelope') { + $this->status = ''; + } + // set parent back to my parent + $this->parent = $this->message[$pos]['parent']; + } + + /** + * element content handler + * + * @param resource $parser XML parser object + * @param string $data element content + * @access private + */ + function character_data($parser, $data){ + $pos = $this->depth_array[$this->depth]; + if ($this->xml_encoding=='UTF-8'){ + // TODO: add an option to disable this for folks who want + // raw UTF-8 that, e.g., might not map to iso-8859-1 + // TODO: this can also be handled with xml_parser_set_option($this->parser, XML_OPTION_TARGET_ENCODING, "ISO-8859-1"); + if($this->decode_utf8){ + $data = utf8_decode($data); + } + } + $this->message[$pos]['cdata'] .= $data; + // for doclit + if($this->status == 'header'){ + $this->responseHeaders .= $data; + } else { + $this->document .= $data; + } + } + + /** + * get the parsed message (SOAP Body) + * + * @return mixed + * @access public + * @deprecated use get_soapbody instead + */ + function get_response(){ + return $this->soapresponse; + } + + /** + * get the parsed SOAP Body (NULL if there was none) + * + * @return mixed + * @access public + */ + function get_soapbody(){ + return $this->soapresponse; + } + + /** + * get the parsed SOAP Header (NULL if there was none) + * + * @return mixed + * @access public + */ + function get_soapheader(){ + return $this->soapheader; + } + + /** + * get the unparsed SOAP Header + * + * @return string XML or empty if no Header + * @access public + */ + function getHeaders(){ + return $this->responseHeaders; + } + + /** + * decodes simple types into PHP variables + * + * @param string $value value to decode + * @param string $type XML type to decode + * @param string $typens XML type namespace to decode + * @return mixed PHP value + * @access private + */ + function decodeSimple($value, $type, $typens) { + // TODO: use the namespace! + if ((!isset($type)) || $type == 'string' || $type == 'long' || $type == 'unsignedLong') { + return (string) $value; + } + if ($type == 'int' || $type == 'integer' || $type == 'short' || $type == 'byte') { + return (int) $value; + } + if ($type == 'float' || $type == 'double' || $type == 'decimal') { + return (double) $value; + } + if ($type == 'boolean') { + if (strtolower($value) == 'false' || strtolower($value) == 'f') { + return false; + } + return (boolean) $value; + } + if ($type == 'base64' || $type == 'base64Binary') { + $this->debug('Decode base64 value'); + return base64_decode($value); + } + // obscure numeric types + if ($type == 'nonPositiveInteger' || $type == 'negativeInteger' + || $type == 'nonNegativeInteger' || $type == 'positiveInteger' + || $type == 'unsignedInt' + || $type == 'unsignedShort' || $type == 'unsignedByte') { + return (int) $value; + } + // bogus: parser treats array with no elements as a simple type + if ($type == 'array') { + return array(); + } + // everything else + return (string) $value; + } + + /** + * builds response structures for compound values (arrays/structs) + * and scalars + * + * @param integer $pos position in node tree + * @return mixed PHP value + * @access private + */ + function buildVal($pos){ + if(!isset($this->message[$pos]['type'])){ + $this->message[$pos]['type'] = ''; + } + $this->debug('in buildVal() for '.$this->message[$pos]['name']."(pos $pos) of type ".$this->message[$pos]['type']); + // if there are children... + if($this->message[$pos]['children'] != ''){ + $this->debug('in buildVal, there are children'); + $children = explode('|',$this->message[$pos]['children']); + array_shift($children); // knock off empty + // md array + if(isset($this->message[$pos]['arrayCols']) && $this->message[$pos]['arrayCols'] != ''){ + $r=0; // rowcount + $c=0; // colcount + foreach($children as $child_pos){ + $this->debug("in buildVal, got an MD array element: $r, $c"); + $params[$r][] = $this->message[$child_pos]['result']; + $c++; + if($c == $this->message[$pos]['arrayCols']){ + $c = 0; + $r++; + } + } + // array + } elseif($this->message[$pos]['type'] == 'array' || $this->message[$pos]['type'] == 'Array'){ + $this->debug('in buildVal, adding array '.$this->message[$pos]['name']); + foreach($children as $child_pos){ + $params[] = &$this->message[$child_pos]['result']; + } + // apache Map type: java hashtable + } elseif($this->message[$pos]['type'] == 'Map' && $this->message[$pos]['type_namespace'] == 'http://xml.apache.org/xml-soap'){ + $this->debug('in buildVal, Java Map '.$this->message[$pos]['name']); + foreach($children as $child_pos){ + $kv = explode("|",$this->message[$child_pos]['children']); + $params[$this->message[$kv[1]]['result']] = &$this->message[$kv[2]]['result']; + } + // generic compound type + //} elseif($this->message[$pos]['type'] == 'SOAPStruct' || $this->message[$pos]['type'] == 'struct') { + } else { + // Apache Vector type: treat as an array + $this->debug('in buildVal, adding Java Vector or generic compound type '.$this->message[$pos]['name']); + if ($this->message[$pos]['type'] == 'Vector' && $this->message[$pos]['type_namespace'] == 'http://xml.apache.org/xml-soap') { + $notstruct = 1; + } else { + $notstruct = 0; + } + // + foreach($children as $child_pos){ + if($notstruct){ + $params[] = &$this->message[$child_pos]['result']; + } else { + if (isset($params[$this->message[$child_pos]['name']])) { + // de-serialize repeated element name into an array + if ((!is_array($params[$this->message[$child_pos]['name']])) || (!isset($params[$this->message[$child_pos]['name']][0]))) { + $params[$this->message[$child_pos]['name']] = array($params[$this->message[$child_pos]['name']]); + } + $params[$this->message[$child_pos]['name']][] = &$this->message[$child_pos]['result']; + } else { + $params[$this->message[$child_pos]['name']] = &$this->message[$child_pos]['result']; + } + } + } + } + if (isset($this->message[$pos]['xattrs'])) { + $this->debug('in buildVal, handling attributes'); + foreach ($this->message[$pos]['xattrs'] as $n => $v) { + $params[$n] = $v; + } + } + // handle simpleContent + if (isset($this->message[$pos]['cdata']) && trim($this->message[$pos]['cdata']) != '') { + $this->debug('in buildVal, handling simpleContent'); + if (isset($this->message[$pos]['type'])) { + $params['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$pos]['type'], isset($this->message[$pos]['type_namespace']) ? $this->message[$pos]['type_namespace'] : ''); + } else { + $parent = $this->message[$pos]['parent']; + if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) { + $params['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : ''); + } else { + $params['!'] = $this->message[$pos]['cdata']; + } + } + } + $ret = is_array($params) ? $params : array(); + $this->debug('in buildVal, return:'); + $this->appendDebug($this->varDump($ret)); + return $ret; + } else { + $this->debug('in buildVal, no children, building scalar'); + $cdata = isset($this->message[$pos]['cdata']) ? $this->message[$pos]['cdata'] : ''; + if (isset($this->message[$pos]['type'])) { + $ret = $this->decodeSimple($cdata, $this->message[$pos]['type'], isset($this->message[$pos]['type_namespace']) ? $this->message[$pos]['type_namespace'] : ''); + $this->debug("in buildVal, return: $ret"); + return $ret; + } + $parent = $this->message[$pos]['parent']; + if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) { + $ret = $this->decodeSimple($cdata, $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : ''); + $this->debug("in buildVal, return: $ret"); + return $ret; + } + $ret = $this->message[$pos]['cdata']; + $this->debug("in buildVal, return: $ret"); + return $ret; + } + } +} + +/** + * Backward compatibility + */ +class soap_parser extends nusoap_parser { +} + + +?> \ No newline at end of file diff --git a/include/nusoap/class.soap_server.php b/include/nusoap/class.soap_server.php new file mode 100644 index 00000000..4bdd742c --- /dev/null +++ b/include/nusoap/class.soap_server.php @@ -0,0 +1,1177 @@ + + Bug 39085 - When loading the opposite search panel via ajax on the ListViews, call the index action instead of the ListView action to avoid touching pre-MVC code by accident. + +r56990 - 2010-06-16 13:05:36 -0700 (Wed, 16 Jun 2010) - kjing - snapshot "Mango" svn branch to a new one for GitHub sync + +r56989 - 2010-06-16 13:01:33 -0700 (Wed, 16 Jun 2010) - kjing - defunt "Mango" svn dev branch before github cutover + +r55980 - 2010-04-19 13:31:28 -0700 (Mon, 19 Apr 2010) - kjing - create Mango (6.1) based on windex + +r51719 - 2009-10-22 10:18:00 -0700 (Thu, 22 Oct 2009) - mitani - Converted to Build 3 tags and updated the build system + +r51634 - 2009-10-19 13:32:22 -0700 (Mon, 19 Oct 2009) - mitani - Windex is the branch for Sugar Sales 1.0 development + +r51443 - 2009-10-12 13:34:36 -0700 (Mon, 12 Oct 2009) - jmertic - Bug 33332 - Made application PHP 5.3 compliant with E_DEPRECATED warnings on by: +- Changing all ereg function to either preg or simple string based ones +- No more references to magic quotes. +- Change all the session_unregister() functions to just unset() the correct session variable instead. + +r50375 - 2009-08-24 18:07:43 -0700 (Mon, 24 Aug 2009) - dwong - branch kobe2 from tokyo r50372 + +r42807 - 2008-12-29 11:16:59 -0800 (Mon, 29 Dec 2008) - dwong - Branch from trunk/sugarcrm r42806 to branches/tokyo/sugarcrm + +r13782 - 2006-06-06 10:58:55 -0700 (Tue, 06 Jun 2006) - majed - changes entry point code + +r11115 - 2006-01-17 14:54:45 -0800 (Tue, 17 Jan 2006) - majed - add entry point validation + +r8846 - 2005-10-31 11:01:12 -0800 (Mon, 31 Oct 2005) - majed - new version of nusoap + +r5462 - 2005-05-25 13:50:11 -0700 (Wed, 25 May 2005) - majed - upgraded nusoap to .6.9 + +r5104 - 2005-05-04 15:33:41 -0700 (Wed, 04 May 2005) - majed - gets rid of HTTP_GET_VARS and what not which has been deprecated + +r573 - 2004-09-04 13:03:32 -0700 (Sat, 04 Sep 2004) - sugarclint - undoing copyrights added in inadvertantly. --clint + +r546 - 2004-09-03 11:49:38 -0700 (Fri, 03 Sep 2004) - sugarmsi - removed echo count + +r354 - 2004-08-02 23:00:37 -0700 (Mon, 02 Aug 2004) - sugarjacob - Adding Soap + + +*/ + + +if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point'); + + + + +/** +* +* nusoap_server allows the user to create a SOAP server +* that is capable of receiving messages and returning responses +* +* NOTE: WSDL functionality is experimental +* +* @author Dietrich Ayala +* @author Scott Nichol + +* @access public +*/ +class nusoap_server extends nusoap_base { + /** + * HTTP headers of request + * @var array + * @access private + */ + var $headers = array(); + /** + * HTTP request + * @var string + * @access private + */ + var $request = ''; + /** + * SOAP headers from request (incomplete namespace resolution; special characters not escaped) (text) + * @var string + * @access public + */ + var $requestHeaders = ''; + /** + * SOAP Headers from request (parsed) + * @var mixed + * @access public + */ + var $requestHeader = NULL; + /** + * SOAP body request portion (incomplete namespace resolution; special characters not escaped) (text) + * @var string + * @access public + */ + var $document = ''; + /** + * SOAP payload for request (text) + * @var string + * @access public + */ + var $requestSOAP = ''; + /** + * requested method namespace URI + * @var string + * @access private + */ + var $methodURI = ''; + /** + * name of method requested + * @var string + * @access private + */ + var $methodname = ''; + /** + * method parameters from request + * @var array + * @access private + */ + var $methodparams = array(); + /** + * SOAP Action from request + * @var string + * @access private + */ + var $SOAPAction = ''; + /** + * character set encoding of incoming (request) messages + * @var string + * @access public + */ + var $xml_encoding = ''; + /** + * toggles whether the parser decodes element content w/ utf8_decode() + * @var boolean + * @access public + */ + var $decode_utf8 = true; + + /** + * HTTP headers of response + * @var array + * @access public + */ + var $outgoing_headers = array(); + /** + * HTTP response + * @var string + * @access private + */ + var $response = ''; + /** + * SOAP headers for response (text or array of soapval or associative array) + * @var mixed + * @access public + */ + var $responseHeaders = ''; + /** + * SOAP payload for response (text) + * @var string + * @access private + */ + var $responseSOAP = ''; + /** + * method return value to place in response + * @var mixed + * @access private + */ + var $methodreturn = false; + /** + * whether $methodreturn is a string of literal XML + * @var boolean + * @access public + */ + var $methodreturnisliteralxml = false; + /** + * SOAP fault for response (or false) + * @var mixed + * @access private + */ + var $fault = false; + /** + * text indication of result (for debugging) + * @var string + * @access private + */ + var $result = 'successful'; + + /** + * assoc array of operations => opData; operations are added by the register() + * method or by parsing an external WSDL definition + * @var array + * @access private + */ + var $operations = array(); + /** + * wsdl instance (if one) + * @var mixed + * @access private + */ + var $wsdl = false; + /** + * URL for WSDL (if one) + * @var mixed + * @access private + */ + var $externalWSDLURL = false; + /** + * whether to append debug to response as XML comment + * @var boolean + * @access public + */ + var $debug_flag = false; + + + /** + * constructor + * the optional parameter is a path to a WSDL file that you'd like to bind the server instance to. + * + * @param mixed $wsdl file path or URL (string), or wsdl instance (object) + * @access public + */ + function nusoap_server($wsdl=false){ + parent::nusoap_base(); + // turn on debugging? + global $debug; + global $HTTP_SERVER_VARS; + + if (isset($_SERVER)) { + $this->debug("_SERVER is defined:"); + $this->appendDebug($this->varDump($_SERVER)); + } elseif (isset($HTTP_SERVER_VARS)) { + $this->debug("HTTP_SERVER_VARS is defined:"); + $this->appendDebug($this->varDump($HTTP_SERVER_VARS)); + } else { + $this->debug("Neither _SERVER nor HTTP_SERVER_VARS is defined."); + } + + if (isset($debug)) { + $this->debug("In nusoap_server, set debug_flag=$debug based on global flag"); + $this->debug_flag = $debug; + } elseif (isset($_SERVER['QUERY_STRING'])) { + $qs = explode('&', $_SERVER['QUERY_STRING']); + foreach ($qs as $v) { + if (substr($v, 0, 6) == 'debug=') { + $this->debug("In nusoap_server, set debug_flag=" . substr($v, 6) . " based on query string #1"); + $this->debug_flag = substr($v, 6); + } + } + } elseif (isset($HTTP_SERVER_VARS['QUERY_STRING'])) { + $qs = explode('&', $HTTP_SERVER_VARS['QUERY_STRING']); + foreach ($qs as $v) { + if (substr($v, 0, 6) == 'debug=') { + $this->debug("In nusoap_server, set debug_flag=" . substr($v, 6) . " based on query string #2"); + $this->debug_flag = substr($v, 6); + } + } + } + + // wsdl + if($wsdl){ + $this->debug("In nusoap_server, WSDL is specified"); + if (is_object($wsdl) && (get_class($wsdl) == 'wsdl')) { + $this->wsdl = $wsdl; + $this->externalWSDLURL = $this->wsdl->wsdl; + $this->debug('Use existing wsdl instance from ' . $this->externalWSDLURL); + } else { + $this->debug('Create wsdl from ' . $wsdl); + $this->wsdl = new wsdl($wsdl); + $this->externalWSDLURL = $wsdl; + } + $this->appendDebug($this->wsdl->getDebug()); + $this->wsdl->clearDebug(); + if($err = $this->wsdl->getError()){ + die('WSDL ERROR: '.$err); + } + } + } + + /** + * processes request and returns response + * + * @param string $data usually is the value of $HTTP_RAW_POST_DATA + * @access public + */ + function service($data){ + global $HTTP_SERVER_VARS; + + if (isset($_SERVER['REQUEST_METHOD'])) { + $rm = $_SERVER['REQUEST_METHOD']; + } elseif (isset($HTTP_SERVER_VARS['REQUEST_METHOD'])) { + $rm = $HTTP_SERVER_VARS['REQUEST_METHOD']; + } else { + $rm = ''; + } + + if (isset($_SERVER['QUERY_STRING'])) { + $qs = $_SERVER['QUERY_STRING']; + } elseif (isset($HTTP_SERVER_VARS['QUERY_STRING'])) { + $qs = $HTTP_SERVER_VARS['QUERY_STRING']; + } else { + $qs = ''; + } + $this->debug("In service, request method=$rm query string=$qs strlen(\$data)=" . strlen($data)); + + if ($rm == 'POST') { + $this->debug("In service, invoke the request"); + $this->parse_request($data); + if (! $this->fault) { + $this->invoke_method(); + } + if (! $this->fault) { + $this->serialize_return(); + } + $this->send_response(); + } elseif (preg_match('/wsdl/', $qs) ){ + $this->debug("In service, this is a request for WSDL"); + if ($this->externalWSDLURL){ + if (strpos($this->externalWSDLURL, "http://") !== false) { // assume URL + $this->debug("In service, re-direct for WSDL"); + header('Location: '.$this->externalWSDLURL); + } else { // assume file + $this->debug("In service, use file passthru for WSDL"); + header("Content-Type: text/xml\r\n"); + $pos = strpos($this->externalWSDLURL, "file://"); + if ($pos === false) { + $filename = $this->externalWSDLURL; + } else { + $filename = substr($this->externalWSDLURL, $pos + 7); + } + $fp = fopen($this->externalWSDLURL, 'r'); + fpassthru($fp); + } + } elseif ($this->wsdl) { + $this->debug("In service, serialize WSDL"); + header("Content-Type: text/xml; charset=ISO-8859-1\r\n"); + print $this->wsdl->serialize($this->debug_flag); + if ($this->debug_flag) { + $this->debug('wsdl:'); + $this->appendDebug($this->varDump($this->wsdl)); + print $this->getDebugAsXMLComment(); + } + } else { + $this->debug("In service, there is no WSDL"); + header("Content-Type: text/html; charset=ISO-8859-1\r\n"); + print "This service does not provide WSDL"; + } + } elseif ($this->wsdl) { + $this->debug("In service, return Web description"); + print $this->wsdl->webDescription(); + } else { + $this->debug("In service, no Web description"); + header("Content-Type: text/html; charset=ISO-8859-1\r\n"); + print "This service does not provide a Web description"; + } + } + + /** + * parses HTTP request headers. + * + * The following fields are set by this function (when successful) + * + * headers + * request + * xml_encoding + * SOAPAction + * + * @access private + */ + function parse_http_headers() { + global $HTTP_SERVER_VARS; + + $this->request = ''; + $this->SOAPAction = ''; + if(function_exists('getallheaders')){ + $this->debug("In parse_http_headers, use getallheaders"); + $headers = getallheaders(); + foreach($headers as $k=>$v){ + $k = strtolower($k); + $this->headers[$k] = $v; + $this->request .= "$k: $v\r\n"; + $this->debug("$k: $v"); + } + // get SOAPAction header + if(isset($this->headers['soapaction'])){ + $this->SOAPAction = str_replace('"','',$this->headers['soapaction']); + } + // get the character encoding of the incoming request + if(isset($this->headers['content-type']) && strpos($this->headers['content-type'],'=')){ + $enc = str_replace('"','',substr(strstr($this->headers["content-type"],'='),1)); + if(preg_match('/^(ISO-8859-1|US-ASCII|UTF-8)$/i',$enc)){ + $this->xml_encoding = strtoupper($enc); + } else { + $this->xml_encoding = 'US-ASCII'; + } + } else { + // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1 + $this->xml_encoding = 'ISO-8859-1'; + } + } elseif(isset($_SERVER) && is_array($_SERVER)){ + $this->debug("In parse_http_headers, use _SERVER"); + foreach ($_SERVER as $k => $v) { + if (substr($k, 0, 5) == 'HTTP_') { + $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', substr($k, 5)))); + } else { + $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', $k))); + } + if ($k == 'soapaction') { + // get SOAPAction header + $k = 'SOAPAction'; + $v = str_replace('"', '', $v); + $v = str_replace('\\', '', $v); + $this->SOAPAction = $v; + } else if ($k == 'content-type') { + // get the character encoding of the incoming request + if (strpos($v, '=')) { + $enc = substr(strstr($v, '='), 1); + $enc = str_replace('"', '', $enc); + $enc = str_replace('\\', '', $enc); + if (preg_match('/^(ISO-8859-1|US-ASCII|UTF-8)$/i',$enc)) { + $this->xml_encoding = strtoupper($enc); + } else { + $this->xml_encoding = 'US-ASCII'; + } + } else { + // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1 + $this->xml_encoding = 'ISO-8859-1'; + } + } + $this->headers[$k] = $v; + $this->request .= "$k: $v\r\n"; + $this->debug("$k: $v"); + } + } elseif (is_array($HTTP_SERVER_VARS)) { + $this->debug("In parse_http_headers, use HTTP_SERVER_VARS"); + foreach ($HTTP_SERVER_VARS as $k => $v) { + if (substr($k, 0, 5) == 'HTTP_') { + $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', substr($k, 5)))); $k = strtolower(substr($k, 5)); + } else { + $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', $k))); $k = strtolower($k); + } + if ($k == 'soapaction') { + // get SOAPAction header + $k = 'SOAPAction'; + $v = str_replace('"', '', $v); + $v = str_replace('\\', '', $v); + $this->SOAPAction = $v; + } else if ($k == 'content-type') { + // get the character encoding of the incoming request + if (strpos($v, '=')) { + $enc = substr(strstr($v, '='), 1); + $enc = str_replace('"', '', $enc); + $enc = str_replace('\\', '', $enc); + if (preg_match('/^(ISO-8859-1|US-ASCII|UTF-8)$/i',$enc)) { + $this->xml_encoding = strtoupper($enc); + } else { + $this->xml_encoding = 'US-ASCII'; + } + } else { + // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1 + $this->xml_encoding = 'ISO-8859-1'; + } + } + $this->headers[$k] = $v; + $this->request .= "$k: $v\r\n"; + $this->debug("$k: $v"); + } + } else { + $this->debug("In parse_http_headers, HTTP headers not accessible"); + $this->setError("HTTP headers not accessible"); + } + } + + /** + * parses a request + * + * The following fields are set by this function (when successful) + * + * headers + * request + * xml_encoding + * SOAPAction + * request + * requestSOAP + * methodURI + * methodname + * methodparams + * requestHeaders + * document + * + * This sets the fault field on error + * + * @param string $data XML string + * @access private + */ + function parse_request($data='') { + $this->debug('entering parse_request()'); + $this->parse_http_headers(); + $this->debug('got character encoding: '.$this->xml_encoding); + // uncompress if necessary + if (isset($this->headers['content-encoding']) && $this->headers['content-encoding'] != '') { + $this->debug('got content encoding: ' . $this->headers['content-encoding']); + if ($this->headers['content-encoding'] == 'deflate' || $this->headers['content-encoding'] == 'gzip') { + // if decoding works, use it. else assume data wasn't gzencoded + if (function_exists('gzuncompress')) { + if ($this->headers['content-encoding'] == 'deflate' && $degzdata = @gzuncompress($data)) { + $data = $degzdata; + } elseif ($this->headers['content-encoding'] == 'gzip' && $degzdata = gzinflate(substr($data, 10))) { + $data = $degzdata; + } else { + $this->fault('SOAP-ENV:Client', 'Errors occurred when trying to decode the data'); + return; + } + } else { + $this->fault('SOAP-ENV:Client', 'This Server does not support compressed data'); + return; + } + } + } + $this->request .= "\r\n".$data; + $data = $this->parseRequest($this->headers, $data); + $this->requestSOAP = $data; + $this->debug('leaving parse_request'); + } + + /** + * invokes a PHP function for the requested SOAP method + * + * The following fields are set by this function (when successful) + * + * methodreturn + * + * Note that the PHP function that is called may also set the following + * fields to affect the response sent to the client + * + * responseHeaders + * outgoing_headers + * + * This sets the fault field on error + * + * @access private + */ + function invoke_method() { + $this->debug('in invoke_method, methodname=' . $this->methodname . ' methodURI=' . $this->methodURI . ' SOAPAction=' . $this->SOAPAction); + + // + // if you are debugging in this area of the code, your service uses a class to implement methods, + // you use SOAP RPC, and the client is .NET, please be aware of the following... + // when the .NET wsdl.exe utility generates a proxy, it will remove the '.' or '..' from the + // method name. that is fine for naming the .NET methods. it is not fine for properly constructing + // the XML request and reading the XML response. you need to add the RequestElementName and + // ResponseElementName to the System.Web.Services.Protocols.SoapRpcMethodAttribute that wsdl.exe + // generates for the method. these parameters are used to specify the correct XML element names + // for .NET to use, i.e. the names with the '.' in them. + // + $orig_methodname = $this->methodname; + if ($this->wsdl) { + if ($this->opData = $this->wsdl->getOperationData($this->methodname)) { + $this->debug('in invoke_method, found WSDL operation=' . $this->methodname); + $this->appendDebug('opData=' . $this->varDump($this->opData)); + } elseif ($this->opData = $this->wsdl->getOperationDataForSoapAction($this->SOAPAction)) { + // Note: hopefully this case will only be used for doc/lit, since rpc services should have wrapper element + $this->debug('in invoke_method, found WSDL soapAction=' . $this->SOAPAction . ' for operation=' . $this->opData['name']); + $this->appendDebug('opData=' . $this->varDump($this->opData)); + $this->methodname = $this->opData['name']; + } else { + $this->debug('in invoke_method, no WSDL for operation=' . $this->methodname); + $this->fault('SOAP-ENV:Client', "Operation '" . $this->methodname . "' is not defined in the WSDL for this service"); + return; + } + } else { + $this->debug('in invoke_method, no WSDL to validate method'); + } + + // if a . is present in $this->methodname, we see if there is a class in scope, + // which could be referred to. We will also distinguish between two deliminators, + // to allow methods to be called a the class or an instance + if (strpos($this->methodname, '..') > 0) { + $delim = '..'; + } else if (strpos($this->methodname, '.') > 0) { + $delim = '.'; + } else { + $delim = ''; + } + $this->debug("in invoke_method, delim=$delim"); + + $class = ''; + $method = ''; + if (strlen($delim) > 0 && substr_count($this->methodname, $delim) == 1) { + $try_class = substr($this->methodname, 0, strpos($this->methodname, $delim)); + if (class_exists($try_class)) { + // get the class and method name + $class = $try_class; + $method = substr($this->methodname, strpos($this->methodname, $delim) + strlen($delim)); + $this->debug("in invoke_method, class=$class method=$method delim=$delim"); + } else { + $this->debug("in invoke_method, class=$try_class not found"); + } + } else { + $try_class = ''; + $this->debug("in invoke_method, no class to try"); + } + + // does method exist? + if ($class == '') { + if (!function_exists($this->methodname)) { + $this->debug("in invoke_method, function '$this->methodname' not found!"); + $this->result = 'fault: method not found'; + $this->fault('SOAP-ENV:Client',"method '$this->methodname'('$orig_methodname') not defined in service('$try_class' '$delim')"); + return; + } + } else { + $method_to_compare = (substr(phpversion(), 0, 2) == '4.') ? strtolower($method) : $method; + if (!in_array($method_to_compare, get_class_methods($class))) { + $this->debug("in invoke_method, method '$this->methodname' not found in class '$class'!"); + $this->result = 'fault: method not found'; + $this->fault('SOAP-ENV:Client',"method '$this->methodname'/'$method_to_compare'('$orig_methodname') not defined in service/'$class'('$try_class' '$delim')"); + return; + } + } + + // evaluate message, getting back parameters + // verify that request parameters match the method's signature + if(! $this->verify_method($this->methodname,$this->methodparams)){ + // debug + $this->debug('ERROR: request not verified against method signature'); + $this->result = 'fault: request failed validation against method signature'; + // return fault + $this->fault('SOAP-ENV:Client',"Operation '$this->methodname' not defined in service."); + return; + } + + // if there are parameters to pass + $this->debug('in invoke_method, params:'); + $this->appendDebug($this->varDump($this->methodparams)); + $this->debug("in invoke_method, calling '$this->methodname'"); + if (!function_exists('call_user_func_array')) { + if ($class == '') { + $this->debug('in invoke_method, calling function using eval()'); + $funcCall = "\$this->methodreturn = $this->methodname("; + } else { + if ($delim == '..') { + $this->debug('in invoke_method, calling class method using eval()'); + $funcCall = "\$this->methodreturn = ".$class."::".$method."("; + } else { + $this->debug('in invoke_method, calling instance method using eval()'); + // generate unique instance name + $instname = "\$inst_".time(); + $funcCall = $instname." = new ".$class."(); "; + $funcCall .= "\$this->methodreturn = ".$instname."->".$method."("; + } + } + if ($this->methodparams) { + foreach ($this->methodparams as $param) { + if (is_array($param) || is_object($param)) { + $this->fault('SOAP-ENV:Client', 'NuSOAP does not handle complexType parameters correctly when using eval; call_user_func_array must be available'); + return; + } + $funcCall .= "\"$param\","; + } + $funcCall = substr($funcCall, 0, -1); + } + $funcCall .= ');'; + $this->debug('in invoke_method, function call: '.$funcCall); + @eval($funcCall); + } else { + if ($class == '') { + $this->debug('in invoke_method, calling function using call_user_func_array()'); + $call_arg = "$this->methodname"; // straight assignment changes $this->methodname to lower case after call_user_func_array() + } elseif ($delim == '..') { + $this->debug('in invoke_method, calling class method using call_user_func_array()'); + $call_arg = array ($class, $method); + } else { + $this->debug('in invoke_method, calling instance method using call_user_func_array()'); + $instance = new $class (); + $call_arg = array(&$instance, $method); + } + if (is_array($this->methodparams)) { + $this->methodreturn = call_user_func_array($call_arg, array_values($this->methodparams)); + } else { + $this->methodreturn = call_user_func_array($call_arg, array()); + } + } + $this->debug('in invoke_method, methodreturn:'); + $this->appendDebug($this->varDump($this->methodreturn)); + $this->debug("in invoke_method, called method $this->methodname, received data of type ".gettype($this->methodreturn)); + } + + /** + * serializes the return value from a PHP function into a full SOAP Envelope + * + * The following fields are set by this function (when successful) + * + * responseSOAP + * + * This sets the fault field on error + * + * @access private + */ + function serialize_return() { + $this->debug('Entering serialize_return methodname: ' . $this->methodname . ' methodURI: ' . $this->methodURI); + // if fault + if (isset($this->methodreturn) && is_object($this->methodreturn) && ((get_class($this->methodreturn) == 'soap_fault') || (get_class($this->methodreturn) == 'nusoap_fault'))) { + $this->debug('got a fault object from method'); + $this->fault = $this->methodreturn; + return; + } elseif ($this->methodreturnisliteralxml) { + $return_val = $this->methodreturn; + // returned value(s) + } else { + $this->debug('got a(n) '.gettype($this->methodreturn).' from method'); + $this->debug('serializing return value'); + if($this->wsdl){ + if (sizeof($this->opData['output']['parts']) > 1) { + $this->debug('more than one output part, so use the method return unchanged'); + $opParams = $this->methodreturn; + } elseif (sizeof($this->opData['output']['parts']) == 1) { + $this->debug('exactly one output part, so wrap the method return in a simple array'); + // TODO: verify that it is not already wrapped! + //foreach ($this->opData['output']['parts'] as $name => $type) { + // $this->debug('wrap in element named ' . $name); + //} + $opParams = array($this->methodreturn); + } + $return_val = $this->wsdl->serializeRPCParameters($this->methodname,'output',$opParams); + $this->appendDebug($this->wsdl->getDebug()); + $this->wsdl->clearDebug(); + if($errstr = $this->wsdl->getError()){ + $this->debug('got wsdl error: '.$errstr); + $this->fault('SOAP-ENV:Server', 'unable to serialize result'); + return; + } + } else { + if (isset($this->methodreturn)) { + $return_val = $this->serialize_val($this->methodreturn, 'return'); + } else { + $return_val = ''; + $this->debug('in absence of WSDL, assume void return for backward compatibility'); + } + } + } + $this->debug('return value:'); + $this->appendDebug($this->varDump($return_val)); + + $this->debug('serializing response'); + if ($this->wsdl) { + $this->debug('have WSDL for serialization: style is ' . $this->opData['style']); + if ($this->opData['style'] == 'rpc') { + $this->debug('style is rpc for serialization: use is ' . $this->opData['output']['use']); + if ($this->opData['output']['use'] == 'literal') { + // http://www.ws-i.org/Profiles/BasicProfile-1.1-2004-08-24.html R2735 says rpc/literal accessor elements should not be in a namespace + if ($this->methodURI) { + $payload = 'methodname.'Response xmlns:ns1="'.$this->methodURI.'">'.$return_val.'methodname."Response>"; + } else { + $payload = '<'.$this->methodname.'Response>'.$return_val.'methodname.'Response>'; + } + } else { + if ($this->methodURI) { + $payload = 'methodname.'Response xmlns:ns1="'.$this->methodURI.'">'.$return_val.'methodname."Response>"; + } else { + $payload = '<'.$this->methodname.'Response>'.$return_val.'methodname.'Response>'; + } + } + } else { + $this->debug('style is not rpc for serialization: assume document'); + $payload = $return_val; + } + } else { + $this->debug('do not have WSDL for serialization: assume rpc/encoded'); + $payload = 'methodname.'Response xmlns:ns1="'.$this->methodURI.'">'.$return_val.'methodname."Response>"; + } + $this->result = 'successful'; + if($this->wsdl){ + //if($this->debug_flag){ + $this->appendDebug($this->wsdl->getDebug()); + // } + if (isset($this->opData['output']['encodingStyle'])) { + $encodingStyle = $this->opData['output']['encodingStyle']; + } else { + $encodingStyle = ''; + } + // Added: In case we use a WSDL, return a serialized env. WITH the usedNamespaces. + $this->responseSOAP = $this->serializeEnvelope($payload,$this->responseHeaders,$this->wsdl->usedNamespaces,$this->opData['style'],$this->opData['output']['use'],$encodingStyle); + } else { + $this->responseSOAP = $this->serializeEnvelope($payload,$this->responseHeaders); + } + $this->debug("Leaving serialize_return"); + } + + /** + * sends an HTTP response + * + * The following fields are set by this function (when successful) + * + * outgoing_headers + * response + * + * @access private + */ + function send_response() { + $this->debug('Enter send_response'); + if ($this->fault) { + $payload = $this->fault->serialize(); + $this->outgoing_headers[] = "HTTP/1.0 500 Internal Server Error"; + $this->outgoing_headers[] = "Status: 500 Internal Server Error"; + } else { + $payload = $this->responseSOAP; + // Some combinations of PHP+Web server allow the Status + // to come through as a header. Since OK is the default + // just do nothing. + // $this->outgoing_headers[] = "HTTP/1.0 200 OK"; + // $this->outgoing_headers[] = "Status: 200 OK"; + } + // add debug data if in debug mode + if(isset($this->debug_flag) && $this->debug_flag){ + $payload .= $this->getDebugAsXMLComment(); + } + $this->outgoing_headers[] = "Server: $this->title Server v$this->version"; + preg_match('/\$Revisio' . 'n: ([^ ]+)/', $this->revision, $rev); + $this->outgoing_headers[] = "X-SOAP-Server: $this->title/$this->version (".$rev[1].")"; + // Let the Web server decide about this + //$this->outgoing_headers[] = "Connection: Close\r\n"; + $payload = $this->getHTTPBody($payload); + $type = $this->getHTTPContentType(); + $charset = $this->getHTTPContentTypeCharset(); + $this->outgoing_headers[] = "Content-Type: $type" . ($charset ? '; charset=' . $charset : ''); + //begin code to compress payload - by John + // NOTE: there is no way to know whether the Web server will also compress + // this data. + if (strlen($payload) > 1024 && isset($this->headers) && isset($this->headers['accept-encoding'])) { + if (strstr($this->headers['accept-encoding'], 'gzip')) { + if (function_exists('gzencode')) { + if (isset($this->debug_flag) && $this->debug_flag) { + $payload .= ""; + } + $this->outgoing_headers[] = "Content-Encoding: gzip"; + $payload = gzencode($payload); + } else { + if (isset($this->debug_flag) && $this->debug_flag) { + $payload .= ""; + } + } + } elseif (strstr($this->headers['accept-encoding'], 'deflate')) { + // Note: MSIE requires gzdeflate output (no Zlib header and checksum), + // instead of gzcompress output, + // which conflicts with HTTP 1.1 spec (http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.5) + if (function_exists('gzdeflate')) { + if (isset($this->debug_flag) && $this->debug_flag) { + $payload .= ""; + } + $this->outgoing_headers[] = "Content-Encoding: deflate"; + $payload = gzdeflate($payload); + } else { + if (isset($this->debug_flag) && $this->debug_flag) { + $payload .= ""; + } + } + } + } + //end code + $this->outgoing_headers[] = "Content-Length: ".strlen($payload); + reset($this->outgoing_headers); + foreach($this->outgoing_headers as $hdr){ + header($hdr, false); + } + print $payload; + $this->response = join("\r\n",$this->outgoing_headers)."\r\n\r\n".$payload; + } + + /** + * takes the value that was created by parsing the request + * and compares to the method's signature, if available. + * + * @param string $operation The operation to be invoked + * @param array $request The array of parameter values + * @return boolean Whether the operation was found + * @access private + */ + function verify_method($operation,$request){ + if(isset($this->wsdl) && is_object($this->wsdl)){ + if($this->wsdl->getOperationData($operation)){ + return true; + } + } elseif(isset($this->operations[$operation])){ + return true; + } + return false; + } + + /** + * processes SOAP message received from client + * + * @param array $headers The HTTP headers + * @param string $data unprocessed request data from client + * @return mixed value of the message, decoded into a PHP type + * @access private + */ + function parseRequest($headers, $data) { + $this->debug('Entering parseRequest() for data of length ' . strlen($data) . ' headers:'); + $this->appendDebug($this->varDump($headers)); + if (!isset($headers['content-type'])) { + $this->setError('Request not of type text/xml (no content-type header)'); + return false; + } + if (!strstr($headers['content-type'], 'text/xml')) { + $this->setError('Request not of type text/xml'); + return false; + } + if (strpos($headers['content-type'], '=')) { + $enc = str_replace('"', '', substr(strstr($headers["content-type"], '='), 1)); + $this->debug('Got response encoding: ' . $enc); + if(preg_match('/^(ISO-8859-1|US-ASCII|UTF-8)$/i',$enc)){ + $this->xml_encoding = strtoupper($enc); + } else { + $this->xml_encoding = 'US-ASCII'; + } + } else { + // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1 + $this->xml_encoding = 'ISO-8859-1'; + } + $this->debug('Use encoding: ' . $this->xml_encoding . ' when creating nusoap_parser'); + // parse response, get soap parser obj + $parser = new nusoap_parser($data,$this->xml_encoding,'',$this->decode_utf8); + // parser debug + $this->debug("parser debug: \n".$parser->getDebug()); + // if fault occurred during message parsing + if($err = $parser->getError()){ + $this->result = 'fault: error in msg parsing: '.$err; + $this->fault('SOAP-ENV:Client',"error in msg parsing:\n".$err); + // else successfully parsed request into soapval object + } else { + // get/set methodname + $this->methodURI = $parser->root_struct_namespace; + $this->methodname = $parser->root_struct_name; + $this->debug('methodname: '.$this->methodname.' methodURI: '.$this->methodURI); + $this->debug('calling parser->get_soapbody()'); + $this->methodparams = $parser->get_soapbody(); + // get SOAP headers + $this->requestHeaders = $parser->getHeaders(); + // get SOAP Header + $this->requestHeader = $parser->get_soapheader(); + // add document for doclit support + $this->document = $parser->document; + } + } + + /** + * gets the HTTP body for the current response. + * + * @param string $soapmsg The SOAP payload + * @return string The HTTP body, which includes the SOAP payload + * @access private + */ + function getHTTPBody($soapmsg) { + return $soapmsg; + } + + /** + * gets the HTTP content type for the current response. + * + * Note: getHTTPBody must be called before this. + * + * @return string the HTTP content type for the current response. + * @access private + */ + function getHTTPContentType() { + return 'text/xml'; + } + + /** + * gets the HTTP content type charset for the current response. + * returns false for non-text content types. + * + * Note: getHTTPBody must be called before this. + * + * @return string the HTTP content type charset for the current response. + * @access private + */ + function getHTTPContentTypeCharset() { + return $this->soap_defencoding; + } + + /** + * add a method to the dispatch map (this has been replaced by the register method) + * + * @param string $methodname + * @param string $in array of input values + * @param string $out array of output values + * @access public + * @deprecated + */ + function add_to_map($methodname,$in,$out){ + $this->operations[$methodname] = array('name' => $methodname,'in' => $in,'out' => $out); + } + + /** + * register a service function with the server + * + * @param string $name the name of the PHP function, class.method or class..method + * @param array $in assoc array of input values: key = param name, value = param type + * @param array $out assoc array of output values: key = param name, value = param type + * @param mixed $namespace the element namespace for the method or false + * @param mixed $soapaction the soapaction for the method or false + * @param mixed $style optional (rpc|document) or false Note: when 'document' is specified, parameter and return wrappers are created for you automatically + * @param mixed $use optional (encoded|literal) or false + * @param string $documentation optional Description to include in WSDL + * @param string $encodingStyle optional (usually 'http://schemas.xmlsoap.org/soap/encoding/' for encoded) + * @access public + */ + function register($name,$in=array(),$out=array(),$namespace=false,$soapaction=false,$style=false,$use=false,$documentation='',$encodingStyle=''){ + global $HTTP_SERVER_VARS; + + if($this->externalWSDLURL){ + die('You cannot bind to an external WSDL file, and register methods outside of it! Please choose either WSDL or no WSDL.'); + } + if (! $name) { + die('You must specify a name when you register an operation'); + } + if (!is_array($in)) { + die('You must provide an array for operation inputs'); + } + if (!is_array($out)) { + die('You must provide an array for operation outputs'); + } + if(false == $namespace) { + } + if(false == $soapaction) { + if (isset($_SERVER)) { + $SERVER_NAME = $_SERVER['SERVER_NAME']; + $SCRIPT_NAME = isset($_SERVER['PHP_SELF']) ? $_SERVER['PHP_SELF'] : $_SERVER['SCRIPT_NAME']; + $HTTPS = isset($_SERVER['HTTPS']) ? $_SERVER['HTTPS'] : (isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off'); + } elseif (isset($HTTP_SERVER_VARS)) { + $SERVER_NAME = $HTTP_SERVER_VARS['SERVER_NAME']; + $SCRIPT_NAME = isset($HTTP_SERVER_VARS['PHP_SELF']) ? $HTTP_SERVER_VARS['PHP_SELF'] : $HTTP_SERVER_VARS['SCRIPT_NAME']; + $HTTPS = isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off'; + } else { + $this->setError("Neither _SERVER nor HTTP_SERVER_VARS is available"); + } + if ($HTTPS == '1' || $HTTPS == 'on') { + $SCHEME = 'https'; + } else { + $SCHEME = 'http'; + } + $soapaction = "$SCHEME://$SERVER_NAME$SCRIPT_NAME/$name"; + } + if(false == $style) { + $style = "rpc"; + } + if(false == $use) { + $use = "encoded"; + } + if ($use == 'encoded' && $encodingStyle == '') { + $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/'; + } + + $this->operations[$name] = array( + 'name' => $name, + 'in' => $in, + 'out' => $out, + 'namespace' => $namespace, + 'soapaction' => $soapaction, + 'style' => $style); + if($this->wsdl){ + $this->wsdl->addOperation($name,$in,$out,$namespace,$soapaction,$style,$use,$documentation,$encodingStyle); + } + return true; + } + + /** + * Specify a fault to be returned to the client. + * This also acts as a flag to the server that a fault has occured. + * + * @param string $faultcode + * @param string $faultstring + * @param string $faultactor + * @param string $faultdetail + * @access public + */ + function fault($faultcode,$faultstring,$faultactor='',$faultdetail=''){ + if ($faultdetail == '' && $this->debug_flag) { + $faultdetail = $this->getDebug(); + } + $this->fault = new nusoap_fault($faultcode,$faultactor,$faultstring,$faultdetail); + $this->fault->soap_defencoding = $this->soap_defencoding; + } + + /** + * Sets up wsdl object. + * Acts as a flag to enable internal WSDL generation + * + * @param string $serviceName, name of the service + * @param mixed $namespace optional 'tns' service namespace or false + * @param mixed $endpoint optional URL of service endpoint or false + * @param string $style optional (rpc|document) WSDL style (also specified by operation) + * @param string $transport optional SOAP transport + * @param mixed $schemaTargetNamespace optional 'types' targetNamespace for service schema or false + */ + function configureWSDL($serviceName,$namespace = false,$endpoint = false,$style='rpc', $transport = 'http://schemas.xmlsoap.org/soap/http', $schemaTargetNamespace = false) + { + global $HTTP_SERVER_VARS; + + if (isset($_SERVER)) { + $SERVER_NAME = $_SERVER['SERVER_NAME']; + $SERVER_PORT = $_SERVER['SERVER_PORT']; + $SCRIPT_NAME = isset($_SERVER['PHP_SELF']) ? $_SERVER['PHP_SELF'] : $_SERVER['SCRIPT_NAME']; + $HTTPS = isset($_SERVER['HTTPS']) ? $_SERVER['HTTPS'] : (isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off'); + } elseif (isset($HTTP_SERVER_VARS)) { + $SERVER_NAME = $HTTP_SERVER_VARS['SERVER_NAME']; + $SERVER_PORT = $HTTP_SERVER_VARS['SERVER_PORT']; + $SCRIPT_NAME = isset($HTTP_SERVER_VARS['PHP_SELF']) ? $HTTP_SERVER_VARS['PHP_SELF'] : $HTTP_SERVER_VARS['SCRIPT_NAME']; + $HTTPS = isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off'; + } else { + $this->setError("Neither _SERVER nor HTTP_SERVER_VARS is available"); + } + // If server name has port number attached then strip it (else port number gets duplicated in WSDL output) (occurred using lighttpd and FastCGI) + $colon = strpos($SERVER_NAME,":"); + if ($colon) { + $SERVER_NAME = substr($SERVER_NAME, 0, $colon); + } + if ($SERVER_PORT == 80) { + $SERVER_PORT = ''; + } else { + $SERVER_PORT = ':' . $SERVER_PORT; + } + if(false == $namespace) { + $namespace = "http://$SERVER_NAME/soap/$serviceName"; + } + + if(false == $endpoint) { + if ($HTTPS == '1' || $HTTPS == 'on') { + $SCHEME = 'https'; + } else { + $SCHEME = 'http'; + } + $endpoint = "$SCHEME://$SERVER_NAME$SERVER_PORT$SCRIPT_NAME"; + } + + if(false == $schemaTargetNamespace) { + $schemaTargetNamespace = $namespace; + } + + $this->wsdl = new wsdl; + $this->wsdl->serviceName = $serviceName; + $this->wsdl->endpoint = $endpoint; + $this->wsdl->namespaces['tns'] = $namespace; + $this->wsdl->namespaces['soap'] = 'http://schemas.xmlsoap.org/wsdl/soap/'; + $this->wsdl->namespaces['wsdl'] = 'http://schemas.xmlsoap.org/wsdl/'; + if ($schemaTargetNamespace != $namespace) { + $this->wsdl->namespaces['types'] = $schemaTargetNamespace; + } + $this->wsdl->schemas[$schemaTargetNamespace][0] = new nusoap_xmlschema('', '', $this->wsdl->namespaces); + if ($style == 'document') { + $this->wsdl->schemas[$schemaTargetNamespace][0]->schemaInfo['elementFormDefault'] = 'qualified'; + } + $this->wsdl->schemas[$schemaTargetNamespace][0]->schemaTargetNamespace = $schemaTargetNamespace; + $this->wsdl->schemas[$schemaTargetNamespace][0]->imports['http://schemas.xmlsoap.org/soap/encoding/'][0] = array('location' => '', 'loaded' => true); + $this->wsdl->schemas[$schemaTargetNamespace][0]->imports['http://schemas.xmlsoap.org/wsdl/'][0] = array('location' => '', 'loaded' => true); + $this->wsdl->bindings[$serviceName.'Binding'] = array( + 'name'=>$serviceName.'Binding', + 'style'=>$style, + 'transport'=>$transport, + 'portType'=>$serviceName.'PortType'); + $this->wsdl->ports[$serviceName.'Port'] = array( + 'binding'=>$serviceName.'Binding', + 'location'=>$endpoint, + 'bindingType'=>'http://schemas.xmlsoap.org/wsdl/soap/'); + } +} + +/** + * Backward compatibility + */ +class soap_server extends nusoap_server { +} + + +?> \ No newline at end of file diff --git a/include/nusoap/class.soap_transport_http.php b/include/nusoap/class.soap_transport_http.php new file mode 100644 index 00000000..815a9769 --- /dev/null +++ b/include/nusoap/class.soap_transport_http.php @@ -0,0 +1,1359 @@ + + Bug 39085 - When loading the opposite search panel via ajax on the ListViews, call the index action instead of the ListView action to avoid touching pre-MVC code by accident. + +r56990 - 2010-06-16 13:05:36 -0700 (Wed, 16 Jun 2010) - kjing - snapshot "Mango" svn branch to a new one for GitHub sync + +r56989 - 2010-06-16 13:01:33 -0700 (Wed, 16 Jun 2010) - kjing - defunt "Mango" svn dev branch before github cutover + +r55980 - 2010-04-19 13:31:28 -0700 (Mon, 19 Apr 2010) - kjing - create Mango (6.1) based on windex + +r51719 - 2009-10-22 10:18:00 -0700 (Thu, 22 Oct 2009) - mitani - Converted to Build 3 tags and updated the build system + +r51634 - 2009-10-19 13:32:22 -0700 (Mon, 19 Oct 2009) - mitani - Windex is the branch for Sugar Sales 1.0 development + +r51509 - 2009-10-14 07:47:28 -0700 (Wed, 14 Oct 2009) - jmertic - More fallout fixes from the PHP 5.3 ereg to preg changes. + +r51491 - 2009-10-13 13:09:52 -0700 (Tue, 13 Oct 2009) - jmertic - Fixed lint errors found in this file. + +r51443 - 2009-10-12 13:34:36 -0700 (Mon, 12 Oct 2009) - jmertic - Bug 33332 - Made application PHP 5.3 compliant with E_DEPRECATED warnings on by: +- Changing all ereg function to either preg or simple string based ones +- No more references to magic quotes. +- Change all the session_unregister() functions to just unset() the correct session variable instead. + +r50375 - 2009-08-24 18:07:43 -0700 (Mon, 24 Aug 2009) - dwong - branch kobe2 from tokyo r50372 + +r42807 - 2008-12-29 11:16:59 -0800 (Mon, 29 Dec 2008) - dwong - Branch from trunk/sugarcrm r42806 to branches/tokyo/sugarcrm + +r13782 - 2006-06-06 10:58:55 -0700 (Tue, 06 Jun 2006) - majed - changes entry point code + +r11115 - 2006-01-17 14:54:45 -0800 (Tue, 17 Jan 2006) - majed - add entry point validation + +r8846 - 2005-10-31 11:01:12 -0800 (Mon, 31 Oct 2005) - majed - new version of nusoap + +r7452 - 2005-08-17 11:32:34 -0700 (Wed, 17 Aug 2005) - majed - changes soap to nusoap + +r5462 - 2005-05-25 13:50:11 -0700 (Wed, 25 May 2005) - majed - upgraded nusoap to .6.9 + +r573 - 2004-09-04 13:03:32 -0700 (Sat, 04 Sep 2004) - sugarclint - undoing copyrights added in inadvertantly. --clint + +r546 - 2004-09-03 11:49:38 -0700 (Fri, 03 Sep 2004) - sugarmsi - removed echo count + +r354 - 2004-08-02 23:00:37 -0700 (Mon, 02 Aug 2004) - sugarjacob - Adding Soap + + +*/ + + +if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point'); + + + + +/** +* transport class for sending/receiving data via HTTP and HTTPS +* NOTE: PHP must be compiled with the CURL extension for HTTPS support +* +* @author Dietrich Ayala +* @author Scott Nichol + +* @access public +*/ +class soap_transport_http extends nusoap_base { + + var $url = ''; + var $uri = ''; + var $digest_uri = ''; + var $scheme = ''; + var $host = ''; + var $port = ''; + var $path = ''; + var $request_method = 'POST'; + var $protocol_version = '1.0'; + var $encoding = ''; + var $outgoing_headers = array(); + var $incoming_headers = array(); + var $incoming_cookies = array(); + var $outgoing_payload = ''; + var $incoming_payload = ''; + var $response_status_line; // HTTP response status line + var $useSOAPAction = true; + var $persistentConnection = false; + var $ch = false; // cURL handle + var $ch_options = array(); // cURL custom options + var $use_curl = false; // force cURL use + var $proxy = null; // proxy information (associative array) + var $username = ''; + var $password = ''; + var $authtype = ''; + var $digestRequest = array(); + var $certRequest = array(); // keys must be cainfofile (optional), sslcertfile, sslkeyfile, passphrase, certpassword (optional), verifypeer (optional), verifyhost (optional) + // cainfofile: certificate authority file, e.g. '$pathToPemFiles/rootca.pem' + // sslcertfile: SSL certificate file, e.g. '$pathToPemFiles/mycert.pem' + // sslkeyfile: SSL key file, e.g. '$pathToPemFiles/mykey.pem' + // passphrase: SSL key password/passphrase + // certpassword: SSL certificate password + // verifypeer: default is 1 + // verifyhost: default is 1 + + /** + * constructor + * + * @param string $url The URL to which to connect + * @param array $curl_options User-specified cURL options + * @param boolean $use_curl Whether to try to force cURL use + * @access public + */ + function soap_transport_http($url, $curl_options = NULL, $use_curl = false){ + parent::nusoap_base(); + $this->debug("ctor url=$url use_curl=$use_curl curl_options:"); + $this->appendDebug($this->varDump($curl_options)); + $this->setURL($url); + if (is_array($curl_options)) { + $this->ch_options = $curl_options; + } + $this->use_curl = $use_curl; + preg_match('/\$Revisio' . 'n: ([^ ]+)/', $this->revision, $rev); + $this->setHeader('User-Agent', $this->title.'/'.$this->version.' ('.$rev[1].')'); + } + + /** + * sets a cURL option + * + * @param mixed $option The cURL option (always integer?) + * @param mixed $value The cURL option value + * @access private + */ + function setCurlOption($option, $value) { + $this->debug("setCurlOption option=$option, value="); + $this->appendDebug($this->varDump($value)); + curl_setopt($this->ch, $option, $value); + } + + /** + * sets an HTTP header + * + * @param string $name The name of the header + * @param string $value The value of the header + * @access private + */ + function setHeader($name, $value) { + $this->outgoing_headers[$name] = $value; + $this->debug("set header $name: $value"); + } + + /** + * unsets an HTTP header + * + * @param string $name The name of the header + * @access private + */ + function unsetHeader($name) { + if (isset($this->outgoing_headers[$name])) { + $this->debug("unset header $name"); + unset($this->outgoing_headers[$name]); + } + } + + /** + * sets the URL to which to connect + * + * @param string $url The URL to which to connect + * @access private + */ + function setURL($url) { + $this->url = $url; + + $u = parse_url($url); + foreach($u as $k => $v){ + $this->debug("parsed URL $k = $v"); + $this->$k = $v; + } + + // add any GET params to path + if(isset($u['query']) && $u['query'] != ''){ + $this->path .= '?' . $u['query']; + } + + // set default port + if(!isset($u['port'])){ + if($u['scheme'] == 'https'){ + $this->port = 443; + } else { + $this->port = 80; + } + } + + $this->uri = $this->path; + $this->digest_uri = $this->uri; + + // build headers + if (!isset($u['port'])) { + $this->setHeader('Host', $this->host); + } else { + $this->setHeader('Host', $this->host.':'.$this->port); + } + + if (isset($u['user']) && $u['user'] != '') { + $this->setCredentials(urldecode($u['user']), isset($u['pass']) ? urldecode($u['pass']) : ''); + } + } + + /** + * gets the I/O method to use + * + * @return string I/O method to use (socket|curl|unknown) + * @access private + */ + function io_method() { + if ($this->use_curl || ($this->scheme == 'https') || ($this->scheme == 'http' && $this->authtype == 'ntlm') || ($this->scheme == 'http' && is_array($this->proxy) && $this->proxy['authtype'] == 'ntlm')) + return 'curl'; + if (($this->scheme == 'http' || $this->scheme == 'ssl') && $this->authtype != 'ntlm' && (!is_array($this->proxy) || $this->proxy['authtype'] != 'ntlm')) + return 'socket'; + return 'unknown'; + } + + /** + * establish an HTTP connection + * + * @param integer $timeout set connection timeout in seconds + * @param integer $response_timeout set response timeout in seconds + * @return boolean true if connected, false if not + * @access private + */ + function connect($connection_timeout=0,$response_timeout=30){ + // For PHP 4.3 with OpenSSL, change https scheme to ssl, then treat like + // "regular" socket. + // TODO: disabled for now because OpenSSL must be *compiled* in (not just + // loaded), and until PHP5 stream_get_wrappers is not available. +// if ($this->scheme == 'https') { +// if (version_compare(phpversion(), '4.3.0') >= 0) { +// if (extension_loaded('openssl')) { +// $this->scheme = 'ssl'; +// $this->debug('Using SSL over OpenSSL'); +// } +// } +// } + $this->debug("connect connection_timeout $connection_timeout, response_timeout $response_timeout, scheme $this->scheme, host $this->host, port $this->port"); + if ($this->io_method() == 'socket') { + if (!is_array($this->proxy)) { + $host = $this->host; + $port = $this->port; + } else { + $host = $this->proxy['host']; + $port = $this->proxy['port']; + } + + // use persistent connection + if($this->persistentConnection && isset($this->fp) && is_resource($this->fp)){ + if (!feof($this->fp)) { + $this->debug('Re-use persistent connection'); + return true; + } + fclose($this->fp); + $this->debug('Closed persistent connection at EOF'); + } + + // munge host if using OpenSSL + if ($this->scheme == 'ssl') { + $host = 'ssl://' . $host; + } + $this->debug('calling fsockopen with host ' . $host . ' connection_timeout ' . $connection_timeout); + + // open socket + if($connection_timeout > 0){ + $this->fp = @fsockopen( $host, $this->port, $this->errno, $this->error_str, $connection_timeout); + } else { + $this->fp = @fsockopen( $host, $this->port, $this->errno, $this->error_str); + } + + // test pointer + if(!$this->fp) { + $msg = 'Couldn\'t open socket connection to server ' . $this->url; + if ($this->errno) { + $msg .= ', Error ('.$this->errno.'): '.$this->error_str; + } else { + $msg .= ' prior to connect(). This is often a problem looking up the host name.'; + } + $this->debug($msg); + $this->setError($msg); + return false; + } + + // set response timeout + $this->debug('set response timeout to ' . $response_timeout); + socket_set_timeout( $this->fp, $response_timeout); + + $this->debug('socket connected'); + return true; + } else if ($this->io_method() == 'curl') { + if (!extension_loaded('curl')) { +// $this->setError('cURL Extension, or OpenSSL extension w/ PHP version >= 4.3 is required for HTTPS'); + $this->setError('The PHP cURL Extension is required for HTTPS or NLTM. You will need to re-build or update your PHP to include cURL or change php.ini to load the PHP cURL extension.'); + return false; + } + // Avoid warnings when PHP does not have these options + if (defined('CURLOPT_CONNECTIONTIMEOUT')) + $CURLOPT_CONNECTIONTIMEOUT = CURLOPT_CONNECTIONTIMEOUT; + else + $CURLOPT_CONNECTIONTIMEOUT = 78; + if (defined('CURLOPT_HTTPAUTH')) + $CURLOPT_HTTPAUTH = CURLOPT_HTTPAUTH; + else + $CURLOPT_HTTPAUTH = 107; + if (defined('CURLOPT_PROXYAUTH')) + $CURLOPT_PROXYAUTH = CURLOPT_PROXYAUTH; + else + $CURLOPT_PROXYAUTH = 111; + if (defined('CURLAUTH_BASIC')) + $CURLAUTH_BASIC = CURLAUTH_BASIC; + else + $CURLAUTH_BASIC = 1; + if (defined('CURLAUTH_DIGEST')) + $CURLAUTH_DIGEST = CURLAUTH_DIGEST; + else + $CURLAUTH_DIGEST = 2; + if (defined('CURLAUTH_NTLM')) + $CURLAUTH_NTLM = CURLAUTH_NTLM; + else + $CURLAUTH_NTLM = 8; + + $this->debug('connect using cURL'); + // init CURL + $this->ch = curl_init(); + // set url + $hostURL = ($this->port != '') ? "$this->scheme://$this->host:$this->port" : "$this->scheme://$this->host"; + // add path + $hostURL .= $this->path; + $this->setCurlOption(CURLOPT_URL, $hostURL); + // follow location headers (re-directs) + if (ini_get('safe_mode') || ini_get('open_basedir')) { + $this->debug('safe_mode or open_basedir set, so do not set CURLOPT_FOLLOWLOCATION'); + $this->debug('safe_mode = '); + $this->appendDebug($this->varDump(ini_get('safe_mode'))); + $this->debug('open_basedir = '); + $this->appendDebug($this->varDump(ini_get('open_basedir'))); + } else { + $this->setCurlOption(CURLOPT_FOLLOWLOCATION, 1); + } + // ask for headers in the response output + $this->setCurlOption(CURLOPT_HEADER, 1); + // ask for the response output as the return value + $this->setCurlOption(CURLOPT_RETURNTRANSFER, 1); + // encode + // We manage this ourselves through headers and encoding +// if(function_exists('gzuncompress')){ +// $this->setCurlOption(CURLOPT_ENCODING, 'deflate'); +// } + // persistent connection + if ($this->persistentConnection) { + // I believe the following comment is now bogus, having applied to + // the code when it used CURLOPT_CUSTOMREQUEST to send the request. + // The way we send data, we cannot use persistent connections, since + // there will be some "junk" at the end of our request. + //$this->setCurlOption(CURL_HTTP_VERSION_1_1, true); + $this->persistentConnection = false; + $this->setHeader('Connection', 'close'); + } + // set timeouts + if ($connection_timeout != 0) { + $this->setCurlOption($CURLOPT_CONNECTIONTIMEOUT, $connection_timeout); + } + if ($response_timeout != 0) { + $this->setCurlOption(CURLOPT_TIMEOUT, $response_timeout); + } + + if ($this->scheme == 'https') { + $this->debug('set cURL SSL verify options'); + // recent versions of cURL turn on peer/host checking by default, + // while PHP binaries are not compiled with a default location for the + // CA cert bundle, so disable peer/host checking. + //$this->setCurlOption(CURLOPT_CAINFO, 'f:\php-4.3.2-win32\extensions\curl-ca-bundle.crt'); + $this->setCurlOption(CURLOPT_SSL_VERIFYPEER, 0); + $this->setCurlOption(CURLOPT_SSL_VERIFYHOST, 0); + + // support client certificates (thanks Tobias Boes, Doug Anarino, Eryan Ariobowo) + if ($this->authtype == 'certificate') { + $this->debug('set cURL certificate options'); + if (isset($this->certRequest['cainfofile'])) { + $this->setCurlOption(CURLOPT_CAINFO, $this->certRequest['cainfofile']); + } + if (isset($this->certRequest['verifypeer'])) { + $this->setCurlOption(CURLOPT_SSL_VERIFYPEER, $this->certRequest['verifypeer']); + } else { + $this->setCurlOption(CURLOPT_SSL_VERIFYPEER, 1); + } + if (isset($this->certRequest['verifyhost'])) { + $this->setCurlOption(CURLOPT_SSL_VERIFYHOST, $this->certRequest['verifyhost']); + } else { + $this->setCurlOption(CURLOPT_SSL_VERIFYHOST, 1); + } + if (isset($this->certRequest['sslcertfile'])) { + $this->setCurlOption(CURLOPT_SSLCERT, $this->certRequest['sslcertfile']); + } + if (isset($this->certRequest['sslkeyfile'])) { + $this->setCurlOption(CURLOPT_SSLKEY, $this->certRequest['sslkeyfile']); + } + if (isset($this->certRequest['passphrase'])) { + $this->setCurlOption(CURLOPT_SSLKEYPASSWD, $this->certRequest['passphrase']); + } + if (isset($this->certRequest['certpassword'])) { + $this->setCurlOption(CURLOPT_SSLCERTPASSWD, $this->certRequest['certpassword']); + } + } + } + if ($this->authtype && ($this->authtype != 'certificate')) { + if ($this->username) { + $this->debug('set cURL username/password'); + $this->setCurlOption(CURLOPT_USERPWD, "$this->username:$this->password"); + } + if ($this->authtype == 'basic') { + $this->debug('set cURL for Basic authentication'); + $this->setCurlOption($CURLOPT_HTTPAUTH, $CURLAUTH_BASIC); + } + if ($this->authtype == 'digest') { + $this->debug('set cURL for digest authentication'); + $this->setCurlOption($CURLOPT_HTTPAUTH, $CURLAUTH_DIGEST); + } + if ($this->authtype == 'ntlm') { + $this->debug('set cURL for NTLM authentication'); + $this->setCurlOption($CURLOPT_HTTPAUTH, $CURLAUTH_NTLM); + } + } + if (is_array($this->proxy)) { + $this->debug('set cURL proxy options'); + if ($this->proxy['port'] != '') { + $this->setCurlOption(CURLOPT_PROXY, $this->proxy['host'].':'.$this->proxy['port']); + } else { + $this->setCurlOption(CURLOPT_PROXY, $this->proxy['host']); + } + if ($this->proxy['username'] || $this->proxy['password']) { + $this->debug('set cURL proxy authentication options'); + $this->setCurlOption(CURLOPT_PROXYUSERPWD, $this->proxy['username'].':'.$this->proxy['password']); + if ($this->proxy['authtype'] == 'basic') { + $this->setCurlOption($CURLOPT_PROXYAUTH, $CURLAUTH_BASIC); + } + if ($this->proxy['authtype'] == 'ntlm') { + $this->setCurlOption($CURLOPT_PROXYAUTH, $CURLAUTH_NTLM); + } + } + } + $this->debug('cURL connection set up'); + return true; + } else { + $this->setError('Unknown scheme ' . $this->scheme); + $this->debug('Unknown scheme ' . $this->scheme); + return false; + } + } + + /** + * sends the SOAP request and gets the SOAP response via HTTP[S] + * + * @param string $data message data + * @param integer $timeout set connection timeout in seconds + * @param integer $response_timeout set response timeout in seconds + * @param array $cookies cookies to send + * @return string data + * @access public + */ + function send($data, $timeout=0, $response_timeout=30, $cookies=NULL) { + + $this->debug('entered send() with data of length: '.strlen($data)); + + $this->tryagain = true; + $tries = 0; + while ($this->tryagain) { + $this->tryagain = false; + if ($tries++ < 2) { + // make connnection + if (!$this->connect($timeout, $response_timeout)){ + return false; + } + + // send request + if (!$this->sendRequest($data, $cookies)){ + return false; + } + + // get response + $respdata = $this->getResponse(); + } else { + $this->setError("Too many tries to get an OK response ($this->response_status_line)"); + } + } + $this->debug('end of send()'); + return $respdata; + } + + + /** + * sends the SOAP request and gets the SOAP response via HTTPS using CURL + * + * @param string $data message data + * @param integer $timeout set connection timeout in seconds + * @param integer $response_timeout set response timeout in seconds + * @param array $cookies cookies to send + * @return string data + * @access public + * @deprecated + */ + function sendHTTPS($data, $timeout=0, $response_timeout=30, $cookies) { + return $this->send($data, $timeout, $response_timeout, $cookies); + } + + /** + * if authenticating, set user credentials here + * + * @param string $username + * @param string $password + * @param string $authtype (basic|digest|certificate|ntlm) + * @param array $digestRequest (keys must be nonce, nc, realm, qop) + * @param array $certRequest (keys must be cainfofile (optional), sslcertfile, sslkeyfile, passphrase, certpassword (optional), verifypeer (optional), verifyhost (optional): see corresponding options in cURL docs) + * @access public + */ + function setCredentials($username, $password, $authtype = 'basic', $digestRequest = array(), $certRequest = array()) { + $this->debug("setCredentials username=$username authtype=$authtype digestRequest="); + $this->appendDebug($this->varDump($digestRequest)); + $this->debug("certRequest="); + $this->appendDebug($this->varDump($certRequest)); + // cf. RFC 2617 + if ($authtype == 'basic') { + $this->setHeader('Authorization', 'Basic '.base64_encode(str_replace(':','',$username).':'.$password)); + } elseif ($authtype == 'digest') { + if (isset($digestRequest['nonce'])) { + $digestRequest['nc'] = isset($digestRequest['nc']) ? $digestRequest['nc']++ : 1; + + // calculate the Digest hashes (calculate code based on digest implementation found at: http://www.rassoc.com/gregr/weblog/stories/2002/07/09/webServicesSecurityHttpDigestAuthenticationWithoutActiveDirectory.html) + + // A1 = unq(username-value) ":" unq(realm-value) ":" passwd + $A1 = $username. ':' . (isset($digestRequest['realm']) ? $digestRequest['realm'] : '') . ':' . $password; + + // H(A1) = MD5(A1) + $HA1 = md5($A1); + + // A2 = Method ":" digest-uri-value + $A2 = $this->request_method . ':' . $this->digest_uri; + + // H(A2) + $HA2 = md5($A2); + + // KD(secret, data) = H(concat(secret, ":", data)) + // if qop == auth: + // request-digest = <"> < KD ( H(A1), unq(nonce-value) + // ":" nc-value + // ":" unq(cnonce-value) + // ":" unq(qop-value) + // ":" H(A2) + // ) <"> + // if qop is missing, + // request-digest = <"> < KD ( H(A1), unq(nonce-value) ":" H(A2) ) > <"> + + $unhashedDigest = ''; + $nonce = isset($digestRequest['nonce']) ? $digestRequest['nonce'] : ''; + $cnonce = $nonce; + if ($digestRequest['qop'] != '') { + $unhashedDigest = $HA1 . ':' . $nonce . ':' . sprintf("%08d", $digestRequest['nc']) . ':' . $cnonce . ':' . $digestRequest['qop'] . ':' . $HA2; + } else { + $unhashedDigest = $HA1 . ':' . $nonce . ':' . $HA2; + } + + $hashedDigest = md5($unhashedDigest); + + $opaque = ''; + if (isset($digestRequest['opaque'])) { + $opaque = ', opaque="' . $digestRequest['opaque'] . '"'; + } + + $this->setHeader('Authorization', 'Digest username="' . $username . '", realm="' . $digestRequest['realm'] . '", nonce="' . $nonce . '", uri="' . $this->digest_uri . $opaque . '", cnonce="' . $cnonce . '", nc=' . sprintf("%08x", $digestRequest['nc']) . ', qop="' . $digestRequest['qop'] . '", response="' . $hashedDigest . '"'); + } + } elseif ($authtype == 'certificate') { + $this->certRequest = $certRequest; + $this->debug('Authorization header not set for certificate'); + } elseif ($authtype == 'ntlm') { + // do nothing + $this->debug('Authorization header not set for ntlm'); + } + $this->username = $username; + $this->password = $password; + $this->authtype = $authtype; + $this->digestRequest = $digestRequest; + } + + /** + * set the soapaction value + * + * @param string $soapaction + * @access public + */ + function setSOAPAction($soapaction) { + $this->setHeader('SOAPAction', '"' . $soapaction . '"'); + } + + /** + * use http encoding + * + * @param string $enc encoding style. supported values: gzip, deflate, or both + * @access public + */ + function setEncoding($enc='gzip, deflate') { + if (function_exists('gzdeflate')) { + $this->protocol_version = '1.1'; + $this->setHeader('Accept-Encoding', $enc); + if (!isset($this->outgoing_headers['Connection'])) { + $this->setHeader('Connection', 'close'); + $this->persistentConnection = false; + } + // deprecated as of PHP 5.3.0 + //set_magic_quotes_runtime(0); + $this->encoding = $enc; + } + } + + /** + * set proxy info here + * + * @param string $proxyhost use an empty string to remove proxy + * @param string $proxyport + * @param string $proxyusername + * @param string $proxypassword + * @param string $proxyauthtype (basic|ntlm) + * @access public + */ + function setProxy($proxyhost, $proxyport, $proxyusername = '', $proxypassword = '', $proxyauthtype = 'basic') { + if ($proxyhost) { + $this->proxy = array( + 'host' => $proxyhost, + 'port' => $proxyport, + 'username' => $proxyusername, + 'password' => $proxypassword, + 'authtype' => $proxyauthtype + ); + if ($proxyusername != '' && $proxypassword != '' && $proxyauthtype = 'basic') { + $this->setHeader('Proxy-Authorization', ' Basic '.base64_encode($proxyusername.':'.$proxypassword)); + } + } else { + $this->debug('remove proxy'); + $proxy = null; + unsetHeader('Proxy-Authorization'); + } + } + + + /** + * Test if the given string starts with a header that is to be skipped. + * Skippable headers result from chunked transfer and proxy requests. + * + * @param string $data The string to check. + * @returns boolean Whether a skippable header was found. + * @access private + */ + function isSkippableCurlHeader(&$data) { + $skipHeaders = array( 'HTTP/1.1 100', + 'HTTP/1.0 301', + 'HTTP/1.1 301', + 'HTTP/1.0 302', + 'HTTP/1.1 302', + 'HTTP/1.0 401', + 'HTTP/1.1 401', + 'HTTP/1.0 200 Connection established'); + foreach ($skipHeaders as $hd) { + $prefix = substr($data, 0, strlen($hd)); + if ($prefix == $hd) return true; + } + + return false; + } + + /** + * decode a string that is encoded w/ "chunked' transfer encoding + * as defined in RFC2068 19.4.6 + * + * @param string $buffer + * @param string $lb + * @returns string + * @access public + * @deprecated + */ + function decodeChunked($buffer, $lb){ + // length := 0 + $length = 0; + $new = ''; + + // read chunk-size, chunk-extension (if any) and CRLF + // get the position of the linebreak + $chunkend = strpos($buffer, $lb); + if ($chunkend == FALSE) { + $this->debug('no linebreak found in decodeChunked'); + return $new; + } + $temp = substr($buffer,0,$chunkend); + $chunk_size = hexdec( trim($temp) ); + $chunkstart = $chunkend + strlen($lb); + // while (chunk-size > 0) { + while ($chunk_size > 0) { + $this->debug("chunkstart: $chunkstart chunk_size: $chunk_size"); + $chunkend = strpos( $buffer, $lb, $chunkstart + $chunk_size); + + // Just in case we got a broken connection + if ($chunkend == FALSE) { + $chunk = substr($buffer,$chunkstart); + // append chunk-data to entity-body + $new .= $chunk; + $length += strlen($chunk); + break; + } + + // read chunk-data and CRLF + $chunk = substr($buffer,$chunkstart,$chunkend-$chunkstart); + // append chunk-data to entity-body + $new .= $chunk; + // length := length + chunk-size + $length += strlen($chunk); + // read chunk-size and CRLF + $chunkstart = $chunkend + strlen($lb); + + $chunkend = strpos($buffer, $lb, $chunkstart) + strlen($lb); + if ($chunkend == FALSE) { + break; //Just in case we got a broken connection + } + $temp = substr($buffer,$chunkstart,$chunkend-$chunkstart); + $chunk_size = hexdec( trim($temp) ); + $chunkstart = $chunkend; + } + return $new; + } + + /** + * Writes the payload, including HTTP headers, to $this->outgoing_payload. + * + * @param string $data HTTP body + * @param string $cookie_str data for HTTP Cookie header + * @return void + * @access private + */ + function buildPayload($data, $cookie_str = '') { + // Note: for cURL connections, $this->outgoing_payload is ignored, + // as is the Content-Length header, but these are still created as + // debugging guides. + + // add content-length header + if ($this->request_method != 'GET') { + $this->setHeader('Content-Length', strlen($data)); + } + + // start building outgoing payload: + if ($this->proxy) { + $uri = $this->url; + } else { + $uri = $this->uri; + } + $req = "$this->request_method $uri HTTP/$this->protocol_version"; + $this->debug("HTTP request: $req"); + $this->outgoing_payload = "$req\r\n"; + + // loop thru headers, serializing + foreach($this->outgoing_headers as $k => $v){ + $hdr = $k.': '.$v; + $this->debug("HTTP header: $hdr"); + $this->outgoing_payload .= "$hdr\r\n"; + } + + // add any cookies + if ($cookie_str != '') { + $hdr = 'Cookie: '.$cookie_str; + $this->debug("HTTP header: $hdr"); + $this->outgoing_payload .= "$hdr\r\n"; + } + + // header/body separator + $this->outgoing_payload .= "\r\n"; + + // add data + $this->outgoing_payload .= $data; + } + + /** + * sends the SOAP request via HTTP[S] + * + * @param string $data message data + * @param array $cookies cookies to send + * @return boolean true if OK, false if problem + * @access private + */ + function sendRequest($data, $cookies = NULL) { + // build cookie string + $cookie_str = $this->getCookiesForRequest($cookies, (($this->scheme == 'ssl') || ($this->scheme == 'https'))); + + // build payload + $this->buildPayload($data, $cookie_str); + + if ($this->io_method() == 'socket') { + // send payload + if(!fputs($this->fp, $this->outgoing_payload, strlen($this->outgoing_payload))) { + $this->setError('couldn\'t write message data to socket'); + $this->debug('couldn\'t write message data to socket'); + return false; + } + $this->debug('wrote data to socket, length = ' . strlen($this->outgoing_payload)); + return true; + } else if ($this->io_method() == 'curl') { + // set payload + // cURL does say this should only be the verb, and in fact it + // turns out that the URI and HTTP version are appended to this, which + // some servers refuse to work with (so we no longer use this method!) + //$this->setCurlOption(CURLOPT_CUSTOMREQUEST, $this->outgoing_payload); + $curl_headers = array(); + foreach($this->outgoing_headers as $k => $v){ + if ($k == 'Connection' || $k == 'Content-Length' || $k == 'Host' || $k == 'Authorization' || $k == 'Proxy-Authorization') { + $this->debug("Skip cURL header $k: $v"); + } else { + $curl_headers[] = "$k: $v"; + } + } + if ($cookie_str != '') { + $curl_headers[] = 'Cookie: ' . $cookie_str; + } + $this->setCurlOption(CURLOPT_HTTPHEADER, $curl_headers); + $this->debug('set cURL HTTP headers'); + if ($this->request_method == "POST") { + $this->setCurlOption(CURLOPT_POST, 1); + $this->setCurlOption(CURLOPT_POSTFIELDS, $data); + $this->debug('set cURL POST data'); + } else { + } + // insert custom user-set cURL options + foreach ($this->ch_options as $key => $val) { + $this->setCurlOption($key, $val); + } + + $this->debug('set cURL payload'); + return true; + } + } + + /** + * gets the SOAP response via HTTP[S] + * + * @return string the response (also sets member variables like incoming_payload) + * @access private + */ + function getResponse(){ + $this->incoming_payload = ''; + + if ($this->io_method() == 'socket') { + // loop until headers have been retrieved + $data = ''; + while (!isset($lb)){ + + // We might EOF during header read. + if(feof($this->fp)) { + $this->incoming_payload = $data; + $this->debug('found no headers before EOF after length ' . strlen($data)); + $this->debug("received before EOF:\n" . $data); + $this->setError('server failed to send headers'); + return false; + } + + $tmp = fgets($this->fp, 256); + $tmplen = strlen($tmp); + $this->debug("read line of $tmplen bytes: " . trim($tmp)); + + if ($tmplen == 0) { + $this->incoming_payload = $data; + $this->debug('socket read of headers timed out after length ' . strlen($data)); + $this->debug("read before timeout: " . $data); + $this->setError('socket read of headers timed out'); + return false; + } + + $data .= $tmp; + $pos = strpos($data,"\r\n\r\n"); + if($pos > 1){ + $lb = "\r\n"; + } else { + $pos = strpos($data,"\n\n"); + if($pos > 1){ + $lb = "\n"; + } + } + // remove 100 headers + if (isset($lb) && preg_match('/^HTTP\/1.1 100/',$data)) { + unset($lb); + $data = ''; + }// + } + // store header data + $this->incoming_payload .= $data; + $this->debug('found end of headers after length ' . strlen($data)); + // process headers + $header_data = trim(substr($data,0,$pos)); + $header_array = explode($lb,$header_data); + $this->incoming_headers = array(); + $this->incoming_cookies = array(); + foreach($header_array as $header_line){ + $arr = explode(':',$header_line, 2); + if(count($arr) > 1){ + $header_name = strtolower(trim($arr[0])); + $this->incoming_headers[$header_name] = trim($arr[1]); + if ($header_name == 'set-cookie') { + // TODO: allow multiple cookies from parseCookie + $cookie = $this->parseCookie(trim($arr[1])); + if ($cookie) { + $this->incoming_cookies[] = $cookie; + $this->debug('found cookie: ' . $cookie['name'] . ' = ' . $cookie['value']); + } else { + $this->debug('did not find cookie in ' . trim($arr[1])); + } + } + } else if (isset($header_name)) { + // append continuation line to previous header + $this->incoming_headers[$header_name] .= $lb . ' ' . $header_line; + } + } + + // loop until msg has been received + if (isset($this->incoming_headers['transfer-encoding']) && strtolower($this->incoming_headers['transfer-encoding']) == 'chunked') { + $content_length = 2147483647; // ignore any content-length header + $chunked = true; + $this->debug("want to read chunked content"); + } elseif (isset($this->incoming_headers['content-length'])) { + $content_length = $this->incoming_headers['content-length']; + $chunked = false; + $this->debug("want to read content of length $content_length"); + } else { + $content_length = 2147483647; + $chunked = false; + $this->debug("want to read content to EOF"); + } + $data = ''; + do { + if ($chunked) { + $tmp = fgets($this->fp, 256); + $tmplen = strlen($tmp); + $this->debug("read chunk line of $tmplen bytes"); + if ($tmplen == 0) { + $this->incoming_payload = $data; + $this->debug('socket read of chunk length timed out after length ' . strlen($data)); + $this->debug("read before timeout:\n" . $data); + $this->setError('socket read of chunk length timed out'); + return false; + } + $content_length = hexdec(trim($tmp)); + $this->debug("chunk length $content_length"); + } + $strlen = 0; + while (($strlen < $content_length) && (!feof($this->fp))) { + $readlen = min(8192, $content_length - $strlen); + $tmp = fread($this->fp, $readlen); + $tmplen = strlen($tmp); + $this->debug("read buffer of $tmplen bytes"); + if (($tmplen == 0) && (!feof($this->fp))) { + $this->incoming_payload = $data; + $this->debug('socket read of body timed out after length ' . strlen($data)); + $this->debug("read before timeout:\n" . $data); + $this->setError('socket read of body timed out'); + return false; + } + $strlen += $tmplen; + $data .= $tmp; + } + if ($chunked && ($content_length > 0)) { + $tmp = fgets($this->fp, 256); + $tmplen = strlen($tmp); + $this->debug("read chunk terminator of $tmplen bytes"); + if ($tmplen == 0) { + $this->incoming_payload = $data; + $this->debug('socket read of chunk terminator timed out after length ' . strlen($data)); + $this->debug("read before timeout:\n" . $data); + $this->setError('socket read of chunk terminator timed out'); + return false; + } + } + } while ($chunked && ($content_length > 0) && (!feof($this->fp))); + if (feof($this->fp)) { + $this->debug('read to EOF'); + } + $this->debug('read body of length ' . strlen($data)); + $this->incoming_payload .= $data; + $this->debug('received a total of '.strlen($this->incoming_payload).' bytes of data from server'); + + // close filepointer + if( + (isset($this->incoming_headers['connection']) && strtolower($this->incoming_headers['connection']) == 'close') || + (! $this->persistentConnection) || feof($this->fp)){ + fclose($this->fp); + $this->fp = false; + $this->debug('closed socket'); + } + + // connection was closed unexpectedly + if($this->incoming_payload == ''){ + $this->setError('no response from server'); + return false; + } + + // decode transfer-encoding +// if(isset($this->incoming_headers['transfer-encoding']) && strtolower($this->incoming_headers['transfer-encoding']) == 'chunked'){ +// if(!$data = $this->decodeChunked($data, $lb)){ +// $this->setError('Decoding of chunked data failed'); +// return false; +// } + //print "
    \nde-chunked:\n---------------\n$data\n\n---------------\n
    "; + // set decoded payload +// $this->incoming_payload = $header_data.$lb.$lb.$data; +// } + + } else if ($this->io_method() == 'curl') { + // send and receive + $this->debug('send and receive with cURL'); + $this->incoming_payload = curl_exec($this->ch); + $data = $this->incoming_payload; + + $cErr = curl_error($this->ch); + if ($cErr != '') { + $err = 'cURL ERROR: '.curl_errno($this->ch).': '.$cErr.'
    '; + // TODO: there is a PHP bug that can cause this to SEGV for CURLINFO_CONTENT_TYPE + foreach(curl_getinfo($this->ch) as $k => $v){ + $err .= "$k: $v
    "; + } + $this->debug($err); + $this->setError($err); + curl_close($this->ch); + return false; + } else { + //echo '
    ';
    +			//var_dump(curl_getinfo($this->ch));
    +			//echo '
    '; + } + // close curl + $this->debug('No cURL error, closing cURL'); + curl_close($this->ch); + + // try removing skippable headers + $savedata = $data; + while ($this->isSkippableCurlHeader($data)) { + $this->debug("Found HTTP header to skip"); + if ($pos = strpos($data,"\r\n\r\n")) { + $data = ltrim(substr($data,$pos)); + } elseif($pos = strpos($data,"\n\n") ) { + $data = ltrim(substr($data,$pos)); + } + } + + if ($data == '') { + // have nothing left; just remove 100 header(s) + $data = $savedata; + while (preg_match('/^HTTP\/1.1 100/',$data)) { + if ($pos = strpos($data,"\r\n\r\n")) { + $data = ltrim(substr($data,$pos)); + } elseif($pos = strpos($data,"\n\n") ) { + $data = ltrim(substr($data,$pos)); + } + } + } + + // separate content from HTTP headers + if ($pos = strpos($data,"\r\n\r\n")) { + $lb = "\r\n"; + } elseif( $pos = strpos($data,"\n\n")) { + $lb = "\n"; + } else { + $this->debug('no proper separation of headers and document'); + $this->setError('no proper separation of headers and document'); + return false; + } + $header_data = trim(substr($data,0,$pos)); + $header_array = explode($lb,$header_data); + $data = ltrim(substr($data,$pos)); + $this->debug('found proper separation of headers and document'); + $this->debug('cleaned data, stringlen: '.strlen($data)); + // clean headers + foreach ($header_array as $header_line) { + $arr = explode(':',$header_line,2); + if(count($arr) > 1){ + $header_name = strtolower(trim($arr[0])); + $this->incoming_headers[$header_name] = trim($arr[1]); + if ($header_name == 'set-cookie') { + // TODO: allow multiple cookies from parseCookie + $cookie = $this->parseCookie(trim($arr[1])); + if ($cookie) { + $this->incoming_cookies[] = $cookie; + $this->debug('found cookie: ' . $cookie['name'] . ' = ' . $cookie['value']); + } else { + $this->debug('did not find cookie in ' . trim($arr[1])); + } + } + } else if (isset($header_name)) { + // append continuation line to previous header + $this->incoming_headers[$header_name] .= $lb . ' ' . $header_line; + } + } + } + + $this->response_status_line = $header_array[0]; + $arr = explode(' ', $this->response_status_line, 3); + $http_version = $arr[0]; + $http_status = intval($arr[1]); + $http_reason = count($arr) > 2 ? $arr[2] : ''; + + // see if we need to resend the request with http digest authentication + if (isset($this->incoming_headers['location']) && ($http_status == 301 || $http_status == 302)) { + $this->debug("Got $http_status $http_reason with Location: " . $this->incoming_headers['location']); + $this->setURL($this->incoming_headers['location']); + $this->tryagain = true; + return false; + } + + // see if we need to resend the request with http digest authentication + if (isset($this->incoming_headers['www-authenticate']) && $http_status == 401) { + $this->debug("Got 401 $http_reason with WWW-Authenticate: " . $this->incoming_headers['www-authenticate']); + if (strstr($this->incoming_headers['www-authenticate'], "Digest ")) { + $this->debug('Server wants digest authentication'); + // remove "Digest " from our elements + $digestString = str_replace('Digest ', '', $this->incoming_headers['www-authenticate']); + + // parse elements into array + $digestElements = explode(',', $digestString); + foreach ($digestElements as $val) { + $tempElement = explode('=', trim($val), 2); + $digestRequest[$tempElement[0]] = str_replace("\"", '', $tempElement[1]); + } + + // should have (at least) qop, realm, nonce + if (isset($digestRequest['nonce'])) { + $this->setCredentials($this->username, $this->password, 'digest', $digestRequest); + $this->tryagain = true; + return false; + } + } + $this->debug('HTTP authentication failed'); + $this->setError('HTTP authentication failed'); + return false; + } + + if ( + ($http_status >= 300 && $http_status <= 307) || + ($http_status >= 400 && $http_status <= 417) || + ($http_status >= 501 && $http_status <= 505) + ) { + $this->setError("Unsupported HTTP response status $http_status $http_reason (soapclient->response has contents of the response)"); + return false; + } + + // decode content-encoding + if(isset($this->incoming_headers['content-encoding']) && $this->incoming_headers['content-encoding'] != ''){ + if(strtolower($this->incoming_headers['content-encoding']) == 'deflate' || strtolower($this->incoming_headers['content-encoding']) == 'gzip'){ + // if decoding works, use it. else assume data wasn't gzencoded + if(function_exists('gzinflate')){ + //$timer->setMarker('starting decoding of gzip/deflated content'); + // IIS 5 requires gzinflate instead of gzuncompress (similar to IE 5 and gzdeflate v. gzcompress) + // this means there are no Zlib headers, although there should be + $this->debug('The gzinflate function exists'); + $datalen = strlen($data); + if ($this->incoming_headers['content-encoding'] == 'deflate') { + if ($degzdata = @gzinflate($data)) { + $data = $degzdata; + $this->debug('The payload has been inflated to ' . strlen($data) . ' bytes'); + if (strlen($data) < $datalen) { + // test for the case that the payload has been compressed twice + $this->debug('The inflated payload is smaller than the gzipped one; try again'); + if ($degzdata = @gzinflate($data)) { + $data = $degzdata; + $this->debug('The payload has been inflated again to ' . strlen($data) . ' bytes'); + } + } + } else { + $this->debug('Error using gzinflate to inflate the payload'); + $this->setError('Error using gzinflate to inflate the payload'); + } + } elseif ($this->incoming_headers['content-encoding'] == 'gzip') { + if ($degzdata = @gzinflate(substr($data, 10))) { // do our best + $data = $degzdata; + $this->debug('The payload has been un-gzipped to ' . strlen($data) . ' bytes'); + if (strlen($data) < $datalen) { + // test for the case that the payload has been compressed twice + $this->debug('The un-gzipped payload is smaller than the gzipped one; try again'); + if ($degzdata = @gzinflate(substr($data, 10))) { + $data = $degzdata; + $this->debug('The payload has been un-gzipped again to ' . strlen($data) . ' bytes'); + } + } + } else { + $this->debug('Error using gzinflate to un-gzip the payload'); + $this->setError('Error using gzinflate to un-gzip the payload'); + } + } + //$timer->setMarker('finished decoding of gzip/deflated content'); + //print "\nde-inflated:\n---------------\n$data\n-------------\n"; + // set decoded payload + $this->incoming_payload = $header_data.$lb.$lb.$data; + } else { + $this->debug('The server sent compressed data. Your php install must have the Zlib extension compiled in to support this.'); + $this->setError('The server sent compressed data. Your php install must have the Zlib extension compiled in to support this.'); + } + } else { + $this->debug('Unsupported Content-Encoding ' . $this->incoming_headers['content-encoding']); + $this->setError('Unsupported Content-Encoding ' . $this->incoming_headers['content-encoding']); + } + } else { + $this->debug('No Content-Encoding header'); + } + + if(strlen($data) == 0){ + $this->debug('no data after headers!'); + $this->setError('no data present after HTTP headers'); + return false; + } + + return $data; + } + + /** + * sets the content-type for the SOAP message to be sent + * + * @param string $type the content type, MIME style + * @param mixed $charset character set used for encoding (or false) + * @access public + */ + function setContentType($type, $charset = false) { + $this->setHeader('Content-Type', $type . ($charset ? '; charset=' . $charset : '')); + } + + /** + * specifies that an HTTP persistent connection should be used + * + * @return boolean whether the request was honored by this method. + * @access public + */ + function usePersistentConnection(){ + if (isset($this->outgoing_headers['Accept-Encoding'])) { + return false; + } + $this->protocol_version = '1.1'; + $this->persistentConnection = true; + $this->setHeader('Connection', 'Keep-Alive'); + return true; + } + + /** + * parse an incoming Cookie into it's parts + * + * @param string $cookie_str content of cookie + * @return array with data of that cookie + * @access private + */ + /* + * TODO: allow a Set-Cookie string to be parsed into multiple cookies + */ + function parseCookie($cookie_str) { + $cookie_str = str_replace('; ', ';', $cookie_str) . ';'; + $data = preg_split('/;/', $cookie_str); + $value_str = $data[0]; + + $cookie_param = 'domain='; + $start = strpos($cookie_str, $cookie_param); + if ($start > 0) { + $domain = substr($cookie_str, $start + strlen($cookie_param)); + $domain = substr($domain, 0, strpos($domain, ';')); + } else { + $domain = ''; + } + + $cookie_param = 'expires='; + $start = strpos($cookie_str, $cookie_param); + if ($start > 0) { + $expires = substr($cookie_str, $start + strlen($cookie_param)); + $expires = substr($expires, 0, strpos($expires, ';')); + } else { + $expires = ''; + } + + $cookie_param = 'path='; + $start = strpos($cookie_str, $cookie_param); + if ( $start > 0 ) { + $path = substr($cookie_str, $start + strlen($cookie_param)); + $path = substr($path, 0, strpos($path, ';')); + } else { + $path = '/'; + } + + $cookie_param = ';secure;'; + if (strpos($cookie_str, $cookie_param) !== FALSE) { + $secure = true; + } else { + $secure = false; + } + + $sep_pos = strpos($value_str, '='); + + if ($sep_pos) { + $name = substr($value_str, 0, $sep_pos); + $value = substr($value_str, $sep_pos + 1); + $cookie= array( 'name' => $name, + 'value' => $value, + 'domain' => $domain, + 'path' => $path, + 'expires' => $expires, + 'secure' => $secure + ); + return $cookie; + } + return false; + } + + /** + * sort out cookies for the current request + * + * @param array $cookies array with all cookies + * @param boolean $secure is the send-content secure or not? + * @return string for Cookie-HTTP-Header + * @access private + */ + function getCookiesForRequest($cookies, $secure=false) { + $cookie_str = ''; + if ((! is_null($cookies)) && (is_array($cookies))) { + foreach ($cookies as $cookie) { + if (! is_array($cookie)) { + continue; + } + $this->debug("check cookie for validity: ".$cookie['name'].'='.$cookie['value']); + if ((isset($cookie['expires'])) && (! empty($cookie['expires']))) { + if (strtotime($cookie['expires']) <= time()) { + $this->debug('cookie has expired'); + continue; + } + } + if ((isset($cookie['domain'])) && (! empty($cookie['domain']))) { + $domain = preg_quote($cookie['domain']); + if (! preg_match("'.*$domain$'i", $this->host)) { + $this->debug('cookie has different domain'); + continue; + } + } + if ((isset($cookie['path'])) && (! empty($cookie['path']))) { + $path = preg_quote($cookie['path']); + if (! preg_match("'^$path.*'i", $this->path)) { + $this->debug('cookie is for a different path'); + continue; + } + } + if ((! $secure) && (isset($cookie['secure'])) && ($cookie['secure'])) { + $this->debug('cookie is secure, transport is not'); + continue; + } + $cookie_str .= $cookie['name'] . '=' . $cookie['value'] . '; '; + $this->debug('add cookie to Cookie-String: ' . $cookie['name'] . '=' . $cookie['value']); + } + } + return $cookie_str; + } +} + + +?> \ No newline at end of file diff --git a/include/nusoap/class.soap_val.php b/include/nusoap/class.soap_val.php new file mode 100644 index 00000000..245c96db --- /dev/null +++ b/include/nusoap/class.soap_val.php @@ -0,0 +1,148 @@ + + Bug 39085 - When loading the opposite search panel via ajax on the ListViews, call the index action instead of the ListView action to avoid touching pre-MVC code by accident. + +r56990 - 2010-06-16 13:05:36 -0700 (Wed, 16 Jun 2010) - kjing - snapshot "Mango" svn branch to a new one for GitHub sync + +r56989 - 2010-06-16 13:01:33 -0700 (Wed, 16 Jun 2010) - kjing - defunt "Mango" svn dev branch before github cutover + +r55980 - 2010-04-19 13:31:28 -0700 (Mon, 19 Apr 2010) - kjing - create Mango (6.1) based on windex + +r51719 - 2009-10-22 10:18:00 -0700 (Thu, 22 Oct 2009) - mitani - Converted to Build 3 tags and updated the build system + +r51634 - 2009-10-19 13:32:22 -0700 (Mon, 19 Oct 2009) - mitani - Windex is the branch for Sugar Sales 1.0 development + +r50375 - 2009-08-24 18:07:43 -0700 (Mon, 24 Aug 2009) - dwong - branch kobe2 from tokyo r50372 + +r42807 - 2008-12-29 11:16:59 -0800 (Mon, 29 Dec 2008) - dwong - Branch from trunk/sugarcrm r42806 to branches/tokyo/sugarcrm + +r13782 - 2006-06-06 10:58:55 -0700 (Tue, 06 Jun 2006) - majed - changes entry point code + +r11115 - 2006-01-17 14:54:45 -0800 (Tue, 17 Jan 2006) - majed - add entry point validation + +r8846 - 2005-10-31 11:01:12 -0800 (Mon, 31 Oct 2005) - majed - new version of nusoap + +r5462 - 2005-05-25 13:50:11 -0700 (Wed, 25 May 2005) - majed - upgraded nusoap to .6.9 + +r573 - 2004-09-04 13:03:32 -0700 (Sat, 04 Sep 2004) - sugarclint - undoing copyrights added in inadvertantly. --clint + +r546 - 2004-09-03 11:49:38 -0700 (Fri, 03 Sep 2004) - sugarmsi - removed echo count + +r354 - 2004-08-02 23:00:37 -0700 (Mon, 02 Aug 2004) - sugarjacob - Adding Soap + + +*/ + + +if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point'); + + + + +/** +* For creating serializable abstractions of native PHP types. This class +* allows element name/namespace, XSD type, and XML attributes to be +* associated with a value. This is extremely useful when WSDL is not +* used, but is also useful when WSDL is used with polymorphic types, including +* xsd:anyType and user-defined types. +* +* @author Dietrich Ayala + +* @access public +*/ +class soapval extends nusoap_base { + /** + * The XML element name + * + * @var string + * @access private + */ + var $name; + /** + * The XML type name (string or false) + * + * @var mixed + * @access private + */ + var $type; + /** + * The PHP value + * + * @var mixed + * @access private + */ + var $value; + /** + * The XML element namespace (string or false) + * + * @var mixed + * @access private + */ + var $element_ns; + /** + * The XML type namespace (string or false) + * + * @var mixed + * @access private + */ + var $type_ns; + /** + * The XML element attributes (array or false) + * + * @var mixed + * @access private + */ + var $attributes; + + /** + * constructor + * + * @param string $name optional name + * @param mixed $type optional type name + * @param mixed $value optional value + * @param mixed $element_ns optional namespace of value + * @param mixed $type_ns optional namespace of type + * @param mixed $attributes associative array of attributes to add to element serialization + * @access public + */ + function soapval($name='soapval',$type=false,$value=-1,$element_ns=false,$type_ns=false,$attributes=false) { + parent::nusoap_base(); + $this->name = $name; + $this->type = $type; + $this->value = $value; + $this->element_ns = $element_ns; + $this->type_ns = $type_ns; + $this->attributes = $attributes; + } + + /** + * return serialized value + * + * @param string $use The WSDL use value (encoded|literal) + * @return string XML data + * @access public + */ + function serialize($use='encoded') { + return $this->serialize_val($this->value, $this->name, $this->type, $this->element_ns, $this->type_ns, $this->attributes, $use, true); + } + + /** + * decodes a soapval object into a PHP native type + * + * @return mixed + * @access public + */ + function decode(){ + return $this->value; + } +} + + + + +?> \ No newline at end of file diff --git a/include/nusoap/class.soapclient.php b/include/nusoap/class.soapclient.php new file mode 100644 index 00000000..5c593fcb --- /dev/null +++ b/include/nusoap/class.soapclient.php @@ -0,0 +1,1146 @@ + + Bug 39085 - When loading the opposite search panel via ajax on the ListViews, call the index action instead of the ListView action to avoid touching pre-MVC code by accident. + +r56990 - 2010-06-16 13:05:36 -0700 (Wed, 16 Jun 2010) - kjing - snapshot "Mango" svn branch to a new one for GitHub sync + +r56989 - 2010-06-16 13:01:33 -0700 (Wed, 16 Jun 2010) - kjing - defunt "Mango" svn dev branch before github cutover + +r55980 - 2010-04-19 13:31:28 -0700 (Mon, 19 Apr 2010) - kjing - create Mango (6.1) based on windex + +r51719 - 2009-10-22 10:18:00 -0700 (Thu, 22 Oct 2009) - mitani - Converted to Build 3 tags and updated the build system + +r51634 - 2009-10-19 13:32:22 -0700 (Mon, 19 Oct 2009) - mitani - Windex is the branch for Sugar Sales 1.0 development + +r51443 - 2009-10-12 13:34:36 -0700 (Mon, 12 Oct 2009) - jmertic - Bug 33332 - Made application PHP 5.3 compliant with E_DEPRECATED warnings on by: +- Changing all ereg function to either preg or simple string based ones +- No more references to magic quotes. +- Change all the session_unregister() functions to just unset() the correct session variable instead. + +r50375 - 2009-08-24 18:07:43 -0700 (Mon, 24 Aug 2009) - dwong - branch kobe2 from tokyo r50372 + +r42807 - 2008-12-29 11:16:59 -0800 (Mon, 29 Dec 2008) - dwong - Branch from trunk/sugarcrm r42806 to branches/tokyo/sugarcrm + +r39619 - 2008-09-09 13:41:34 -0700 (Tue, 09 Sep 2008) - jmertic - Bug 24827 - Remove all instances where we return a new object and assign it by reference, since this is deprecated in PHP 5 and emits E_DEPRECATED errors in PHP 5.3. +Touched: +- data/SugarBean.php +- include/domit/php_http_client_generic.php +- include/domit/php_http_connector.php +- include/domit/testing_domit.php +- include/domit/xml_domit_getelementsbypath.php +- include/domit/xml_domit_lite_parser.php +- include/domit/xml_domit_nodemaps.php +- include/domit/xml_domit_parser.php +- include/domit/xml_domit_shared.php +- include/generic/SugarWidgets/SugarWidgetField.php +- include/generic/SugarWidgets/SugarWidgetReportField.php +- include/ListView/ProcessView.php +- include/nusoap/class.soapclient.php +- include/nusoap/nusoap.php +- include/nusoap/nusoapmime.php +- include/Pear/HTML_Safe/Safe.php +- include/Pear/XML_HTMLSax3/HTMLSax3.php +- modules/Administration/RebuildWorkFlow.php +- modules/Expressions/RelateSelector.php +- modules/Reports/templates/templates_reports.php +- modules/WorkFlow/Delete.php +- modules/WorkFlow/Save.php +- modules/WorkFlow/SaveSequence.php +- modules/WorkFlow/WorkFlow.php +- modules/WorkFlowActionShells/CreateStep1.php +- modules/WorkFlowActionShells/CreateStep2.php +- modules/WorkFlowActionShells/Save.php +- modules/WorkFlowActionShells/WorkFlowActionShell.php +- modules/WorkFlowAlerts/Save.php +- modules/WorkFlowAlerts/WorkFlowAlert.php +- modules/WorkFlowAlertShells/DetailView.php +- modules/WorkFlowAlertShells/WorkFlowAlertShell.php +- modules/WorkFlowTriggerShells/CreateStep1.php +- modules/WorkFlowTriggerShells/CreateStepFilter.php +- modules/WorkFlowTriggerShells/SaveFilter.php +- modules/WorkFlowTriggerShells/WorkFlowTriggerShell.php +- soap/SoapHelperFunctions.php +- test/modules/DynamicFields/DynamicFields_Bug24095_test.php +- test/simpletest/browser.php +- test/simpletest/default_reporter.php +- test/simpletest/detached.php +- test/simpletest/eclipse.php +- test/simpletest/expectation.php +- test/simpletest/extensions/pear_test_case.php +- test/simpletest/form.php +- test/simpletest/http.php +- test/simpletest/mock_objects.php +- test/simpletest/page.php +- test/simpletest/parser.php +- test/simpletest/remote.php +- test/simpletest/shell_tester.php +- test/simpletest/simple_test.php +- test/simpletest/simpletest.php +- test/simpletest/test/acceptance_test.php +- test/simpletest/test/adapter_test.php +- test/simpletest/test/authentication_test.php +- test/simpletest/test/browser_test.php +- test/simpletest/test/collector_test.php +- test/simpletest/test/compatibility_test.php +- test/simpletest/test/detached_test.php +- test/simpletest/test/eclipse_test.php +- test/simpletest/test/encoding_test.php +- test/simpletest/test/errors_test.php +- test/simpletest/test/expectation_test.php +- test/simpletest/test/form_test.php +- test/simpletest/test/frames_test.php +- test/simpletest/test/http_test.php +- test/simpletest/test/live_test.php +- test/simpletest/test/mock_objects_test.php +- test/simpletest/test/page_test.php +- test/simpletest/test/parse_error_test.php +- test/simpletest/test/parser_test.php +- test/simpletest/test/remote_test.php +- test/simpletest/test/shell_test.php +- test/simpletest/test/shell_tester_test.php +- test/simpletest/test/simpletest_test.php +- test/simpletest/test/site/page_request.php +- test/simpletest/test/tag_test.php +- test/simpletest/test/unit_tester_test.php +- test/simpletest/test/user_agent_test.php +- test/simpletest/test/visual_test.php +- test/simpletest/test/xml_test.php +- test/simpletest/test_case.php +- test/simpletest/ui/array_reporter/test.php +- test/simpletest/ui/recorder/test.php +- test/simpletest/unit_tester.php +- test/simpletest/url.php +- test/simpletest/user_agent.php +- test/simpletest/web_tester.php +- test/spikephpcoverage/src/PEAR.php +- test/spikephpcoverage/src/util/Utility.php +- test/spikephpcoverage/src/XML/Parser.php +- test/spikephpcoverage/src/XML/Parser/Simple.php +- test/test_utilities/SugarTest_SimpleBrowser.php + +r13782 - 2006-06-06 10:58:55 -0700 (Tue, 06 Jun 2006) - majed - changes entry point code + +r11115 - 2006-01-17 14:54:45 -0800 (Tue, 17 Jan 2006) - majed - add entry point validation + +r8991 - 2005-11-03 19:07:25 -0800 (Thu, 03 Nov 2005) - majed - fixes nusoap issue + +r8846 - 2005-10-31 11:01:12 -0800 (Mon, 31 Oct 2005) - majed - new version of nusoap + +r7905 - 2005-09-21 19:12:57 -0700 (Wed, 21 Sep 2005) - majed - restores old nusoap pre & with a few fixes + +r7861 - 2005-09-20 15:40:25 -0700 (Tue, 20 Sep 2005) - majed - & fix for 3.5.1 + +r5462 - 2005-05-25 13:50:11 -0700 (Wed, 25 May 2005) - majed - upgraded nusoap to .6.9 + +r573 - 2004-09-04 13:03:32 -0700 (Sat, 04 Sep 2004) - sugarclint - undoing copyrights added in inadvertantly. --clint + +r546 - 2004-09-03 11:49:38 -0700 (Fri, 03 Sep 2004) - sugarmsi - removed echo count + +r354 - 2004-08-02 23:00:37 -0700 (Mon, 02 Aug 2004) - sugarjacob - Adding Soap + + +*/ + + +if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point'); + + + + +/** +* +* [nu]soapclient higher level class for easy usage. +* +* usage: +* +* // instantiate client with server info +* $soapclient = new nusoap_client( string path [ ,mixed wsdl] ); +* +* // call method, get results +* echo $soapclient->call( string methodname [ ,array parameters] ); +* +* // bye bye client +* unset($soapclient); +* +* @author Dietrich Ayala +* @author Scott Nichol + +* @access public +*/ +class nusoap_client extends nusoap_base { + + var $username = ''; // Username for HTTP authentication + var $password = ''; // Password for HTTP authentication + var $authtype = ''; // Type of HTTP authentication + var $certRequest = array(); // Certificate for HTTP SSL authentication + var $requestHeaders = false; // SOAP headers in request (text) + var $responseHeaders = ''; // SOAP headers from response (incomplete namespace resolution) (text) + var $responseHeader = NULL; // SOAP Header from response (parsed) + var $document = ''; // SOAP body response portion (incomplete namespace resolution) (text) + var $endpoint; + var $forceEndpoint = ''; // overrides WSDL endpoint + var $proxyhost = ''; + var $proxyport = ''; + var $proxyusername = ''; + var $proxypassword = ''; + var $portName = ''; // port name to use in WSDL + var $xml_encoding = ''; // character set encoding of incoming (response) messages + var $http_encoding = false; + var $timeout = 0; // HTTP connection timeout + var $response_timeout = 30; // HTTP response timeout + var $endpointType = ''; // soap|wsdl, empty for WSDL initialization error + var $persistentConnection = false; + var $defaultRpcParams = false; // This is no longer used + var $request = ''; // HTTP request + var $response = ''; // HTTP response + var $responseData = ''; // SOAP payload of response + var $cookies = array(); // Cookies from response or for request + var $decode_utf8 = true; // toggles whether the parser decodes element content w/ utf8_decode() + var $operations = array(); // WSDL operations, empty for WSDL initialization error + var $curl_options = array(); // User-specified cURL options + var $bindingType = ''; // WSDL operation binding type + var $use_curl = false; // whether to always try to use cURL + + /* + * fault related variables + */ + /** + * @var fault + * @access public + */ + var $fault; + /** + * @var faultcode + * @access public + */ + var $faultcode; + /** + * @var faultstring + * @access public + */ + var $faultstring; + /** + * @var faultdetail + * @access public + */ + var $faultdetail; + + /** + * constructor + * + * @param mixed $endpoint SOAP server or WSDL URL (string), or wsdl instance (object) + * @param mixed $wsdl optional, set to 'wsdl' or true if using WSDL + * @param string $proxyhost optional + * @param string $proxyport optional + * @param string $proxyusername optional + * @param string $proxypassword optional + * @param integer $timeout set the connection timeout + * @param integer $response_timeout set the response timeout + * @param string $portName optional portName in WSDL document + * @access public + */ + function nusoap_client($endpoint,$wsdl = false,$proxyhost = false,$proxyport = false,$proxyusername = false, $proxypassword = false, $timeout = 0, $response_timeout = 30, $portName = ''){ + parent::nusoap_base(); + $this->endpoint = $endpoint; + $this->proxyhost = $proxyhost; + $this->proxyport = $proxyport; + $this->proxyusername = $proxyusername; + $this->proxypassword = $proxypassword; + $this->timeout = $timeout; + $this->response_timeout = $response_timeout; + $this->portName = $portName; + + $this->debug("ctor wsdl=$wsdl timeout=$timeout response_timeout=$response_timeout"); + $this->appendDebug('endpoint=' . $this->varDump($endpoint)); + + // make values + if($wsdl){ + if (is_object($endpoint) && (get_class($endpoint) == 'wsdl')) { + $this->wsdl = $endpoint; + $this->endpoint = $this->wsdl->wsdl; + $this->wsdlFile = $this->endpoint; + $this->debug('existing wsdl instance created from ' . $this->endpoint); + $this->checkWSDL(); + } else { + $this->wsdlFile = $this->endpoint; + $this->wsdl = null; + $this->debug('will use lazy evaluation of wsdl from ' . $this->endpoint); + } + $this->endpointType = 'wsdl'; + } else { + $this->debug("instantiate SOAP with endpoint at $endpoint"); + $this->endpointType = 'soap'; + } + } + + /** + * calls method, returns PHP native type + * + * @param string $operation SOAP server URL or path + * @param mixed $params An array, associative or simple, of the parameters + * for the method call, or a string that is the XML + * for the call. For rpc style, this call will + * wrap the XML in a tag named after the method, as + * well as the SOAP Envelope and Body. For document + * style, this will only wrap with the Envelope and Body. + * IMPORTANT: when using an array with document style, + * in which case there + * is really one parameter, the root of the fragment + * used in the call, which encloses what programmers + * normally think of parameters. A parameter array + * *must* include the wrapper. + * @param string $namespace optional method namespace (WSDL can override) + * @param string $soapAction optional SOAPAction value (WSDL can override) + * @param mixed $headers optional string of XML with SOAP header content, or array of soapval objects for SOAP headers, or associative array + * @param boolean $rpcParams optional (no longer used) + * @param string $style optional (rpc|document) the style to use when serializing parameters (WSDL can override) + * @param string $use optional (encoded|literal) the use when serializing parameters (WSDL can override) + * @return mixed response from SOAP call, normally an associative array mirroring the structure of the XML response, false for certain fatal errors + * @access public + */ + function call($operation,$params=array(),$namespace='http://tempuri.org',$soapAction='',$headers=false,$rpcParams=null,$style='rpc',$use='encoded'){ + $this->operation = $operation; + $this->fault = false; + $this->setError(''); + $this->request = ''; + $this->response = ''; + $this->responseData = ''; + $this->faultstring = ''; + $this->faultcode = ''; + $this->opData = array(); + + $this->debug("call: operation=$operation, namespace=$namespace, soapAction=$soapAction, rpcParams=$rpcParams, style=$style, use=$use, endpointType=$this->endpointType"); + $this->appendDebug('params=' . $this->varDump($params)); + $this->appendDebug('headers=' . $this->varDump($headers)); + if ($headers) { + $this->requestHeaders = $headers; + } + if ($this->endpointType == 'wsdl' && is_null($this->wsdl)) { + $this->loadWSDL(); + if ($this->getError()) + return false; + } + // serialize parameters + if($this->endpointType == 'wsdl' && $opData = $this->getOperationData($operation)){ + // use WSDL for operation + $this->opData = $opData; + $this->debug("found operation"); + $this->appendDebug('opData=' . $this->varDump($opData)); + if (isset($opData['soapAction'])) { + $soapAction = $opData['soapAction']; + } + if (! $this->forceEndpoint) { + $this->endpoint = $opData['endpoint']; + } else { + $this->endpoint = $this->forceEndpoint; + } + $namespace = isset($opData['input']['namespace']) ? $opData['input']['namespace'] : $namespace; + $style = $opData['style']; + $use = $opData['input']['use']; + // add ns to ns array + if($namespace != '' && !isset($this->wsdl->namespaces[$namespace])){ + $nsPrefix = 'ns' . rand(1000, 9999); + $this->wsdl->namespaces[$nsPrefix] = $namespace; + } + $nsPrefix = $this->wsdl->getPrefixFromNamespace($namespace); + // serialize payload + if (is_string($params)) { + $this->debug("serializing param string for WSDL operation $operation"); + $payload = $params; + } elseif (is_array($params)) { + $this->debug("serializing param array for WSDL operation $operation"); + $payload = $this->wsdl->serializeRPCParameters($operation,'input',$params,$this->bindingType); + } else { + $this->debug('params must be array or string'); + $this->setError('params must be array or string'); + return false; + } + $usedNamespaces = $this->wsdl->usedNamespaces; + if (isset($opData['input']['encodingStyle'])) { + $encodingStyle = $opData['input']['encodingStyle']; + } else { + $encodingStyle = ''; + } + $this->appendDebug($this->wsdl->getDebug()); + $this->wsdl->clearDebug(); + if ($errstr = $this->wsdl->getError()) { + $this->debug('got wsdl error: '.$errstr); + $this->setError('wsdl error: '.$errstr); + return false; + } + } elseif($this->endpointType == 'wsdl') { + // operation not in WSDL + $this->appendDebug($this->wsdl->getDebug()); + $this->wsdl->clearDebug(); + $this->setError('operation '.$operation.' not present in WSDL.'); + $this->debug("operation '$operation' not present in WSDL."); + return false; + } else { + // no WSDL + //$this->namespaces['ns1'] = $namespace; + $nsPrefix = 'ns' . rand(1000, 9999); + // serialize + $payload = ''; + if (is_string($params)) { + $this->debug("serializing param string for operation $operation"); + $payload = $params; + } elseif (is_array($params)) { + $this->debug("serializing param array for operation $operation"); + foreach($params as $k => $v){ + $payload .= $this->serialize_val($v,$k,false,false,false,false,$use); + } + } else { + $this->debug('params must be array or string'); + $this->setError('params must be array or string'); + return false; + } + $usedNamespaces = array(); + if ($use == 'encoded') { + $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/'; + } else { + $encodingStyle = ''; + } + } + // wrap RPC calls with method element + if ($style == 'rpc') { + if ($use == 'literal') { + $this->debug("wrapping RPC request with literal method element"); + if ($namespace) { + // http://www.ws-i.org/Profiles/BasicProfile-1.1-2004-08-24.html R2735 says rpc/literal accessor elements should not be in a namespace + $payload = "<$nsPrefix:$operation xmlns:$nsPrefix=\"$namespace\">" . + $payload . + ""; + } else { + $payload = "<$operation>" . $payload . ""; + } + } else { + $this->debug("wrapping RPC request with encoded method element"); + if ($namespace) { + $payload = "<$nsPrefix:$operation xmlns:$nsPrefix=\"$namespace\">" . + $payload . + ""; + } else { + $payload = "<$operation>" . + $payload . + ""; + } + } + } + // serialize envelope + $soapmsg = $this->serializeEnvelope($payload,$this->requestHeaders,$usedNamespaces,$style,$use,$encodingStyle); + $this->debug("endpoint=$this->endpoint, soapAction=$soapAction, namespace=$namespace, style=$style, use=$use, encodingStyle=$encodingStyle"); + $this->debug('SOAP message length=' . strlen($soapmsg) . ' contents (max 1000 bytes)=' . substr($soapmsg, 0, 1000)); + // send + $return = $this->send($this->getHTTPBody($soapmsg),$soapAction,$this->timeout,$this->response_timeout); + if($errstr = $this->getError()){ + $this->debug('Error: '.$errstr); + return false; + } else { + $this->return = $return; + $this->debug('sent message successfully and got a(n) '.gettype($return)); + $this->appendDebug('return=' . $this->varDump($return)); + + // fault? + if(is_array($return) && isset($return['faultcode'])){ + $this->debug('got fault'); + $this->setError($return['faultcode'].': '.$return['faultstring']); + $this->fault = true; + foreach($return as $k => $v){ + $this->$k = $v; + $this->debug("$k = $v
    "); + } + return $return; + } elseif ($style == 'document') { + // NOTE: if the response is defined to have multiple parts (i.e. unwrapped), + // we are only going to return the first part here...sorry about that + return $return; + } else { + // array of return values + if(is_array($return)){ + // multiple 'out' parameters, which we return wrapped up + // in the array + if(sizeof($return) > 1){ + return $return; + } + // single 'out' parameter (normally the return value) + $return = array_shift($return); + $this->debug('return shifted value: '); + $this->appendDebug($this->varDump($return)); + return $return; + // nothing returned (ie, echoVoid) + } else { + return ""; + } + } + } + } + + /** + * check WSDL passed as an instance or pulled from an endpoint + * + * @access private + */ + function checkWSDL() { + $this->appendDebug($this->wsdl->getDebug()); + $this->wsdl->clearDebug(); + $this->debug('checkWSDL'); + // catch errors + if ($errstr = $this->wsdl->getError()) { + $this->appendDebug($this->wsdl->getDebug()); + $this->wsdl->clearDebug(); + $this->debug('got wsdl error: '.$errstr); + $this->setError('wsdl error: '.$errstr); + } elseif ($this->operations = $this->wsdl->getOperations($this->portName, 'soap')) { + $this->appendDebug($this->wsdl->getDebug()); + $this->wsdl->clearDebug(); + $this->bindingType = 'soap'; + $this->debug('got '.count($this->operations).' operations from wsdl '.$this->wsdlFile.' for binding type '.$this->bindingType); + } elseif ($this->operations = $this->wsdl->getOperations($this->portName, 'soap12')) { + $this->appendDebug($this->wsdl->getDebug()); + $this->wsdl->clearDebug(); + $this->bindingType = 'soap12'; + $this->debug('got '.count($this->operations).' operations from wsdl '.$this->wsdlFile.' for binding type '.$this->bindingType); + $this->debug('**************** WARNING: SOAP 1.2 BINDING *****************'); + } else { + $this->appendDebug($this->wsdl->getDebug()); + $this->wsdl->clearDebug(); + $this->debug('getOperations returned false'); + $this->setError('no operations defined in the WSDL document!'); + } + } + + /** + * instantiate wsdl object and parse wsdl file + * + * @access public + */ + function loadWSDL() { + $this->debug('instantiating wsdl class with doc: '.$this->wsdlFile); + $this->wsdl = new wsdl('',$this->proxyhost,$this->proxyport,$this->proxyusername,$this->proxypassword,$this->timeout,$this->response_timeout,$this->curl_options,$this->use_curl); + $this->wsdl->setCredentials($this->username, $this->password, $this->authtype, $this->certRequest); + $this->wsdl->fetchWSDL($this->wsdlFile); + $this->checkWSDL(); + } + + /** + * get available data pertaining to an operation + * + * @param string $operation operation name + * @return array array of data pertaining to the operation + * @access public + */ + function getOperationData($operation){ + if ($this->endpointType == 'wsdl' && is_null($this->wsdl)) { + $this->loadWSDL(); + if ($this->getError()) + return false; + } + if(isset($this->operations[$operation])){ + return $this->operations[$operation]; + } + $this->debug("No data for operation: $operation"); + } + + /** + * send the SOAP message + * + * Note: if the operation has multiple return values + * the return value of this method will be an array + * of those values. + * + * @param string $msg a SOAPx4 soapmsg object + * @param string $soapaction SOAPAction value + * @param integer $timeout set connection timeout in seconds + * @param integer $response_timeout set response timeout in seconds + * @return mixed native PHP types. + * @access private + */ + function send($msg, $soapaction = '', $timeout=0, $response_timeout=30) { + $this->checkCookies(); + // detect transport + switch(true){ + // http(s) + case preg_match('/^http/',$this->endpoint): + $this->debug('transporting via HTTP'); + if($this->persistentConnection == true && is_object($this->persistentConnection)){ + $http =& $this->persistentConnection; + } else { + $http = new soap_transport_http($this->endpoint, $this->curl_options, $this->use_curl); + if ($this->persistentConnection) { + $http->usePersistentConnection(); + } + } + $http->setContentType($this->getHTTPContentType(), $this->getHTTPContentTypeCharset()); + $http->setSOAPAction($soapaction); + if($this->proxyhost && $this->proxyport){ + $http->setProxy($this->proxyhost,$this->proxyport,$this->proxyusername,$this->proxypassword); + } + if($this->authtype != '') { + $http->setCredentials($this->username, $this->password, $this->authtype, array(), $this->certRequest); + } + if($this->http_encoding != ''){ + $http->setEncoding($this->http_encoding); + } + $this->debug('sending message, length='.strlen($msg)); + if(preg_match('/^http:/',$this->endpoint)){ + //if(strpos($this->endpoint,'http:')){ + $this->responseData = $http->send($msg,$timeout,$response_timeout,$this->cookies); + } elseif(preg_match('/^https/',$this->endpoint)){ + //} elseif(strpos($this->endpoint,'https:')){ + //if(phpversion() == '4.3.0-dev'){ + //$response = $http->send($msg,$timeout,$response_timeout); + //$this->request = $http->outgoing_payload; + //$this->response = $http->incoming_payload; + //} else + $this->responseData = $http->sendHTTPS($msg,$timeout,$response_timeout,$this->cookies); + } else { + $this->setError('no http/s in endpoint url'); + } + $this->request = $http->outgoing_payload; + $this->response = $http->incoming_payload; + $this->appendDebug($http->getDebug()); + $this->UpdateCookies($http->incoming_cookies); + + // save transport object if using persistent connections + if ($this->persistentConnection) { + $http->clearDebug(); + if (!is_object($this->persistentConnection)) { + $this->persistentConnection = $http; + } + } + + if($err = $http->getError()){ + $this->setError('HTTP Error: '.$err); + return false; + } elseif($this->getError()){ + return false; + } else { + $this->debug('got response, length='. strlen($this->responseData).' type='.$http->incoming_headers['content-type']); + return $this->parseResponse($http->incoming_headers, $this->responseData); + } + break; + default: + $this->setError('no transport found, or selected transport is not yet supported!'); + return false; + break; + } + } + + /** + * processes SOAP message returned from server + * + * @param array $headers The HTTP headers + * @param string $data unprocessed response data from server + * @return mixed value of the message, decoded into a PHP type + * @access private + */ + function parseResponse($headers, $data) { + $this->debug('Entering parseResponse() for data of length ' . strlen($data) . ' headers:'); + $this->appendDebug($this->varDump($headers)); + if (!isset($headers['content-type'])) { + $this->setError('Response not of type text/xml (no content-type header)'); + return false; + } + if (!strstr($headers['content-type'], 'text/xml')) { + $this->setError('Response not of type text/xml: ' . $headers['content-type']); + return false; + } + if (strpos($headers['content-type'], '=')) { + $enc = str_replace('"', '', substr(strstr($headers["content-type"], '='), 1)); + $this->debug('Got response encoding: ' . $enc); + if(preg_match('/^(ISO-8859-1|US-ASCII|UTF-8)$/i',$enc)){ + $this->xml_encoding = strtoupper($enc); + } else { + $this->xml_encoding = 'US-ASCII'; + } + } else { + // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1 + $this->xml_encoding = 'ISO-8859-1'; + } + $this->debug('Use encoding: ' . $this->xml_encoding . ' when creating nusoap_parser'); + $parser = new nusoap_parser($data,$this->xml_encoding,$this->operation,$this->decode_utf8); + // add parser debug data to our debug + $this->appendDebug($parser->getDebug()); + // if parse errors + if($errstr = $parser->getError()){ + $this->setError( $errstr); + // destroy the parser object + unset($parser); + return false; + } else { + // get SOAP headers + $this->responseHeaders = $parser->getHeaders(); + // get SOAP headers + $this->responseHeader = $parser->get_soapheader(); + // get decoded message + $return = $parser->get_soapbody(); + // add document for doclit support + $this->document = $parser->document; + // destroy the parser object + unset($parser); + // return decode message + return $return; + } + } + + /** + * sets user-specified cURL options + * + * @param mixed $option The cURL option (always integer?) + * @param mixed $value The cURL option value + * @access public + */ + function setCurlOption($option, $value) { + $this->debug("setCurlOption option=$option, value="); + $this->appendDebug($this->varDump($value)); + $this->curl_options[$option] = $value; + } + + /** + * sets the SOAP endpoint, which can override WSDL + * + * @param string $endpoint The endpoint URL to use, or empty string or false to prevent override + * @access public + */ + function setEndpoint($endpoint) { + $this->debug("setEndpoint(\"$endpoint\")"); + $this->forceEndpoint = $endpoint; + } + + /** + * set the SOAP headers + * + * @param mixed $headers String of XML with SOAP header content, or array of soapval objects for SOAP headers + * @access public + */ + function setHeaders($headers){ + $this->debug("setHeaders headers="); + $this->appendDebug($this->varDump($headers)); + $this->requestHeaders = $headers; + } + + /** + * get the SOAP response headers (namespace resolution incomplete) + * + * @return string + * @access public + */ + function getHeaders(){ + return $this->responseHeaders; + } + + /** + * get the SOAP response Header (parsed) + * + * @return mixed + * @access public + */ + function getHeader(){ + return $this->responseHeader; + } + + /** + * set proxy info here + * + * @param string $proxyhost + * @param string $proxyport + * @param string $proxyusername + * @param string $proxypassword + * @access public + */ + function setHTTPProxy($proxyhost, $proxyport, $proxyusername = '', $proxypassword = '') { + $this->proxyhost = $proxyhost; + $this->proxyport = $proxyport; + $this->proxyusername = $proxyusername; + $this->proxypassword = $proxypassword; + } + + /** + * if authenticating, set user credentials here + * + * @param string $username + * @param string $password + * @param string $authtype (basic|digest|certificate|ntlm) + * @param array $certRequest (keys must be cainfofile (optional), sslcertfile, sslkeyfile, passphrase, verifypeer (optional), verifyhost (optional): see corresponding options in cURL docs) + * @access public + */ + function setCredentials($username, $password, $authtype = 'basic', $certRequest = array()) { + $this->debug("setCredentials username=$username authtype=$authtype certRequest="); + $this->appendDebug($this->varDump($certRequest)); + $this->username = $username; + $this->password = $password; + $this->authtype = $authtype; + $this->certRequest = $certRequest; + } + + /** + * use HTTP encoding + * + * @param string $enc HTTP encoding + * @access public + */ + function setHTTPEncoding($enc='gzip, deflate'){ + $this->debug("setHTTPEncoding(\"$enc\")"); + $this->http_encoding = $enc; + } + + /** + * Set whether to try to use cURL connections if possible + * + * @param boolean $use Whether to try to use cURL + * @access public + */ + function setUseCURL($use) { + $this->debug("setUseCURL($use)"); + $this->use_curl = $use; + } + + /** + * use HTTP persistent connections if possible + * + * @access public + */ + function useHTTPPersistentConnection(){ + $this->debug("useHTTPPersistentConnection"); + $this->persistentConnection = true; + } + + /** + * gets the default RPC parameter setting. + * If true, default is that call params are like RPC even for document style. + * Each call() can override this value. + * + * This is no longer used. + * + * @return boolean + * @access public + * @deprecated + */ + function getDefaultRpcParams() { + return $this->defaultRpcParams; + } + + /** + * sets the default RPC parameter setting. + * If true, default is that call params are like RPC even for document style + * Each call() can override this value. + * + * This is no longer used. + * + * @param boolean $rpcParams + * @access public + * @deprecated + */ + function setDefaultRpcParams($rpcParams) { + $this->defaultRpcParams = $rpcParams; + } + + /** + * dynamically creates an instance of a proxy class, + * allowing user to directly call methods from wsdl + * + * @return object soap_proxy object + * @access public + */ + function getProxy() { + $r = rand(); + $evalStr = $this->_getProxyClassCode($r); + //$this->debug("proxy class: $evalStr"); + if ($this->getError()) { + $this->debug("Error from _getProxyClassCode, so return NULL"); + return null; + } + // eval the class + eval($evalStr); + // instantiate proxy object + eval("\$proxy = new nusoap_proxy_$r('');"); + // transfer current wsdl data to the proxy thereby avoiding parsing the wsdl twice + $proxy->endpointType = 'wsdl'; + $proxy->wsdlFile = $this->wsdlFile; + $proxy->wsdl = $this->wsdl; + $proxy->operations = $this->operations; + $proxy->defaultRpcParams = $this->defaultRpcParams; + // transfer other state + $proxy->soap_defencoding = $this->soap_defencoding; + $proxy->username = $this->username; + $proxy->password = $this->password; + $proxy->authtype = $this->authtype; + $proxy->certRequest = $this->certRequest; + $proxy->requestHeaders = $this->requestHeaders; + $proxy->endpoint = $this->endpoint; + $proxy->forceEndpoint = $this->forceEndpoint; + $proxy->proxyhost = $this->proxyhost; + $proxy->proxyport = $this->proxyport; + $proxy->proxyusername = $this->proxyusername; + $proxy->proxypassword = $this->proxypassword; + $proxy->http_encoding = $this->http_encoding; + $proxy->timeout = $this->timeout; + $proxy->response_timeout = $this->response_timeout; + $proxy->persistentConnection = &$this->persistentConnection; + $proxy->decode_utf8 = $this->decode_utf8; + $proxy->curl_options = $this->curl_options; + $proxy->bindingType = $this->bindingType; + $proxy->use_curl = $this->use_curl; + return $proxy; + } + + /** + * dynamically creates proxy class code + * + * @return string PHP/NuSOAP code for the proxy class + * @access private + */ + function _getProxyClassCode($r) { + $this->debug("in getProxy endpointType=$this->endpointType"); + $this->appendDebug("wsdl=" . $this->varDump($this->wsdl)); + if ($this->endpointType != 'wsdl') { + $evalStr = 'A proxy can only be created for a WSDL client'; + $this->setError($evalStr); + $evalStr = "echo \"$evalStr\";"; + return $evalStr; + } + if ($this->endpointType == 'wsdl' && is_null($this->wsdl)) { + $this->loadWSDL(); + if ($this->getError()) { + return "echo \"" . $this->getError() . "\";"; + } + } + $evalStr = ''; + foreach ($this->operations as $operation => $opData) { + if ($operation != '') { + // create param string and param comment string + if (sizeof($opData['input']['parts']) > 0) { + $paramStr = ''; + $paramArrayStr = ''; + $paramCommentStr = ''; + foreach ($opData['input']['parts'] as $name => $type) { + $paramStr .= "\$$name, "; + $paramArrayStr .= "'$name' => \$$name, "; + $paramCommentStr .= "$type \$$name, "; + } + $paramStr = substr($paramStr, 0, strlen($paramStr)-2); + $paramArrayStr = substr($paramArrayStr, 0, strlen($paramArrayStr)-2); + $paramCommentStr = substr($paramCommentStr, 0, strlen($paramCommentStr)-2); + } else { + $paramStr = ''; + $paramArrayStr = ''; + $paramCommentStr = 'void'; + } + $opData['namespace'] = !isset($opData['namespace']) ? 'http://testuri.com' : $opData['namespace']; + $evalStr .= "// $paramCommentStr + function " . str_replace('.', '__', $operation) . "($paramStr) { + \$params = array($paramArrayStr); + return \$this->call('$operation', \$params, '".$opData['namespace']."', '".(isset($opData['soapAction']) ? $opData['soapAction'] : '')."'); + } + "; + unset($paramStr); + unset($paramCommentStr); + } + } + $evalStr = 'class nusoap_proxy_'.$r.' extends nusoap_client { + '.$evalStr.' +}'; + return $evalStr; + } + + /** + * dynamically creates proxy class code + * + * @return string PHP/NuSOAP code for the proxy class + * @access public + */ + function getProxyClassCode() { + $r = rand(); + return $this->_getProxyClassCode($r); + } + + /** + * gets the HTTP body for the current request. + * + * @param string $soapmsg The SOAP payload + * @return string The HTTP body, which includes the SOAP payload + * @access private + */ + function getHTTPBody($soapmsg) { + return $soapmsg; + } + + /** + * gets the HTTP content type for the current request. + * + * Note: getHTTPBody must be called before this. + * + * @return string the HTTP content type for the current request. + * @access private + */ + function getHTTPContentType() { + return 'text/xml'; + } + + /** + * gets the HTTP content type charset for the current request. + * returns false for non-text content types. + * + * Note: getHTTPBody must be called before this. + * + * @return string the HTTP content type charset for the current request. + * @access private + */ + function getHTTPContentTypeCharset() { + return $this->soap_defencoding; + } + + /* + * whether or not parser should decode utf8 element content + * + * @return always returns true + * @access public + */ + function decodeUTF8($bool){ + $this->decode_utf8 = $bool; + return true; + } + + /** + * adds a new Cookie into $this->cookies array + * + * @param string $name Cookie Name + * @param string $value Cookie Value + * @return boolean if cookie-set was successful returns true, else false + * @access public + */ + function setCookie($name, $value) { + if (strlen($name) == 0) { + return false; + } + $this->cookies[] = array('name' => $name, 'value' => $value); + return true; + } + + /** + * gets all Cookies + * + * @return array with all internal cookies + * @access public + */ + function getCookies() { + return $this->cookies; + } + + /** + * checks all Cookies and delete those which are expired + * + * @return boolean always return true + * @access private + */ + function checkCookies() { + if (sizeof($this->cookies) == 0) { + return true; + } + $this->debug('checkCookie: check ' . sizeof($this->cookies) . ' cookies'); + $curr_cookies = $this->cookies; + $this->cookies = array(); + foreach ($curr_cookies as $cookie) { + if (! is_array($cookie)) { + $this->debug('Remove cookie that is not an array'); + continue; + } + if ((isset($cookie['expires'])) && (! empty($cookie['expires']))) { + if (strtotime($cookie['expires']) > time()) { + $this->cookies[] = $cookie; + } else { + $this->debug('Remove expired cookie ' . $cookie['name']); + } + } else { + $this->cookies[] = $cookie; + } + } + $this->debug('checkCookie: '.sizeof($this->cookies).' cookies left in array'); + return true; + } + + /** + * updates the current cookies with a new set + * + * @param array $cookies new cookies with which to update current ones + * @return boolean always return true + * @access private + */ + function UpdateCookies($cookies) { + if (sizeof($this->cookies) == 0) { + // no existing cookies: take whatever is new + if (sizeof($cookies) > 0) { + $this->debug('Setting new cookie(s)'); + $this->cookies = $cookies; + } + return true; + } + if (sizeof($cookies) == 0) { + // no new cookies: keep what we've got + return true; + } + // merge + foreach ($cookies as $newCookie) { + if (!is_array($newCookie)) { + continue; + } + if ((!isset($newCookie['name'])) || (!isset($newCookie['value']))) { + continue; + } + $newName = $newCookie['name']; + + $found = false; + for ($i = 0; $i < count($this->cookies); $i++) { + $cookie = $this->cookies[$i]; + if (!is_array($cookie)) { + continue; + } + if (!isset($cookie['name'])) { + continue; + } + if ($newName != $cookie['name']) { + continue; + } + $newDomain = isset($newCookie['domain']) ? $newCookie['domain'] : 'NODOMAIN'; + $domain = isset($cookie['domain']) ? $cookie['domain'] : 'NODOMAIN'; + if ($newDomain != $domain) { + continue; + } + $newPath = isset($newCookie['path']) ? $newCookie['path'] : 'NOPATH'; + $path = isset($cookie['path']) ? $cookie['path'] : 'NOPATH'; + if ($newPath != $path) { + continue; + } + $this->cookies[$i] = $newCookie; + $found = true; + $this->debug('Update cookie ' . $newName . '=' . $newCookie['value']); + break; + } + if (! $found) { + $this->debug('Add cookie ' . $newName . '=' . $newCookie['value']); + $this->cookies[] = $newCookie; + } + } + return true; + } +} + +if (!extension_loaded('soap')) { + /** + * For backwards compatiblity, define soapclient unless the PHP SOAP extension is loaded. + */ + class soapclient extends nusoap_client { + } +} + +/** + * For backwards compatiblity, define nusoapclient unless the PHP SOAP extension is loaded. + */ +class nusoapclient extends nusoap_client { +} +?> diff --git a/include/nusoap/class.wsdl.php b/include/nusoap/class.wsdl.php new file mode 100644 index 00000000..a8831913 --- /dev/null +++ b/include/nusoap/class.wsdl.php @@ -0,0 +1,1983 @@ + + Bug 39085 - When loading the opposite search panel via ajax on the ListViews, call the index action instead of the ListView action to avoid touching pre-MVC code by accident. + +r56990 - 2010-06-16 13:05:36 -0700 (Wed, 16 Jun 2010) - kjing - snapshot "Mango" svn branch to a new one for GitHub sync + +r56989 - 2010-06-16 13:01:33 -0700 (Wed, 16 Jun 2010) - kjing - defunt "Mango" svn dev branch before github cutover + +r55980 - 2010-04-19 13:31:28 -0700 (Mon, 19 Apr 2010) - kjing - create Mango (6.1) based on windex + +r51719 - 2009-10-22 10:18:00 -0700 (Thu, 22 Oct 2009) - mitani - Converted to Build 3 tags and updated the build system + +r51634 - 2009-10-19 13:32:22 -0700 (Mon, 19 Oct 2009) - mitani - Windex is the branch for Sugar Sales 1.0 development + +r51443 - 2009-10-12 13:34:36 -0700 (Mon, 12 Oct 2009) - jmertic - Bug 33332 - Made application PHP 5.3 compliant with E_DEPRECATED warnings on by: +- Changing all ereg function to either preg or simple string based ones +- No more references to magic quotes. +- Change all the session_unregister() functions to just unset() the correct session variable instead. + +r50375 - 2009-08-24 18:07:43 -0700 (Mon, 24 Aug 2009) - dwong - branch kobe2 from tokyo r50372 + +r42807 - 2008-12-29 11:16:59 -0800 (Mon, 29 Dec 2008) - dwong - Branch from trunk/sugarcrm r42806 to branches/tokyo/sugarcrm + +r13782 - 2006-06-06 10:58:55 -0700 (Tue, 06 Jun 2006) - majed - changes entry point code + +r11115 - 2006-01-17 14:54:45 -0800 (Tue, 17 Jan 2006) - majed - add entry point validation + +r8846 - 2005-10-31 11:01:12 -0800 (Mon, 31 Oct 2005) - majed - new version of nusoap + +r7905 - 2005-09-21 19:12:57 -0700 (Wed, 21 Sep 2005) - majed - restores old nusoap pre & with a few fixes + +r7861 - 2005-09-20 15:40:25 -0700 (Tue, 20 Sep 2005) - majed - & fix for 3.5.1 + +r5462 - 2005-05-25 13:50:11 -0700 (Wed, 25 May 2005) - majed - upgraded nusoap to .6.9 + +r573 - 2004-09-04 13:03:32 -0700 (Sat, 04 Sep 2004) - sugarclint - undoing copyrights added in inadvertantly. --clint + +r546 - 2004-09-03 11:49:38 -0700 (Fri, 03 Sep 2004) - sugarmsi - removed echo count + +r354 - 2004-08-02 23:00:37 -0700 (Mon, 02 Aug 2004) - sugarjacob - Adding Soap + + +*/ + + +if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point'); + + + + +/** +* parses a WSDL file, allows access to it's data, other utility methods. +* also builds WSDL structures programmatically. +* +* @author Dietrich Ayala +* @author Scott Nichol + +* @access public +*/ +class wsdl extends nusoap_base { + // URL or filename of the root of this WSDL + var $wsdl; + // define internal arrays of bindings, ports, operations, messages, etc. + var $schemas = array(); + var $currentSchema; + var $message = array(); + var $complexTypes = array(); + var $messages = array(); + var $currentMessage; + var $currentOperation; + var $portTypes = array(); + var $currentPortType; + var $bindings = array(); + var $currentBinding; + var $ports = array(); + var $currentPort; + var $opData = array(); + var $status = ''; + var $documentation = false; + var $endpoint = ''; + // array of wsdl docs to import + var $import = array(); + // parser vars + var $parser; + var $position = 0; + var $depth = 0; + var $depth_array = array(); + // for getting wsdl + var $proxyhost = ''; + var $proxyport = ''; + var $proxyusername = ''; + var $proxypassword = ''; + var $timeout = 0; + var $response_timeout = 30; + var $curl_options = array(); // User-specified cURL options + var $use_curl = false; // whether to always try to use cURL + // for HTTP authentication + var $username = ''; // Username for HTTP authentication + var $password = ''; // Password for HTTP authentication + var $authtype = ''; // Type of HTTP authentication + var $certRequest = array(); // Certificate for HTTP SSL authentication + + /** + * constructor + * + * @param string $wsdl WSDL document URL + * @param string $proxyhost + * @param string $proxyport + * @param string $proxyusername + * @param string $proxypassword + * @param integer $timeout set the connection timeout + * @param integer $response_timeout set the response timeout + * @param array $curl_options user-specified cURL options + * @param boolean $use_curl try to use cURL + * @access public + */ + function wsdl($wsdl = '',$proxyhost=false,$proxyport=false,$proxyusername=false,$proxypassword=false,$timeout=0,$response_timeout=30,$curl_options=null,$use_curl=false){ + parent::nusoap_base(); + $this->debug("ctor wsdl=$wsdl timeout=$timeout response_timeout=$response_timeout"); + $this->proxyhost = $proxyhost; + $this->proxyport = $proxyport; + $this->proxyusername = $proxyusername; + $this->proxypassword = $proxypassword; + $this->timeout = $timeout; + $this->response_timeout = $response_timeout; + if (is_array($curl_options)) + $this->curl_options = $curl_options; + $this->use_curl = $use_curl; + $this->fetchWSDL($wsdl); + } + + /** + * fetches the WSDL document and parses it + * + * @access public + */ + function fetchWSDL($wsdl) { + $this->debug("parse and process WSDL path=$wsdl"); + $this->wsdl = $wsdl; + // parse wsdl file + if ($this->wsdl != "") { + $this->parseWSDL($this->wsdl); + } + // imports + // TODO: handle imports more properly, grabbing them in-line and nesting them + $imported_urls = array(); + $imported = 1; + while ($imported > 0) { + $imported = 0; + // Schema imports + foreach ($this->schemas as $ns => $list) { + foreach ($list as $xs) { + $wsdlparts = parse_url($this->wsdl); // this is bogusly simple! + foreach ($xs->imports as $ns2 => $list2) { + for ($ii = 0; $ii < count($list2); $ii++) { + if (! $list2[$ii]['loaded']) { + $this->schemas[$ns]->imports[$ns2][$ii]['loaded'] = true; + $url = $list2[$ii]['location']; + if ($url != '') { + $urlparts = parse_url($url); + if (!isset($urlparts['host'])) { + $url = $wsdlparts['scheme'] . '://' . $wsdlparts['host'] . (isset($wsdlparts['port']) ? ':' .$wsdlparts['port'] : '') . + substr($wsdlparts['path'],0,strrpos($wsdlparts['path'],'/') + 1) .$urlparts['path']; + } + if (! in_array($url, $imported_urls)) { + $this->parseWSDL($url); + $imported++; + $imported_urls[] = $url; + } + } else { + $this->debug("Unexpected scenario: empty URL for unloaded import"); + } + } + } + } + } + } + // WSDL imports + $wsdlparts = parse_url($this->wsdl); // this is bogusly simple! + foreach ($this->import as $ns => $list) { + for ($ii = 0; $ii < count($list); $ii++) { + if (! $list[$ii]['loaded']) { + $this->import[$ns][$ii]['loaded'] = true; + $url = $list[$ii]['location']; + if ($url != '') { + $urlparts = parse_url($url); + if (!isset($urlparts['host'])) { + $url = $wsdlparts['scheme'] . '://' . $wsdlparts['host'] . (isset($wsdlparts['port']) ? ':' . $wsdlparts['port'] : '') . + substr($wsdlparts['path'],0,strrpos($wsdlparts['path'],'/') + 1) .$urlparts['path']; + } + if (! in_array($url, $imported_urls)) { + $this->parseWSDL($url); + $imported++; + $imported_urls[] = $url; + } + } else { + $this->debug("Unexpected scenario: empty URL for unloaded import"); + } + } + } + } + } + // add new data to operation data + foreach($this->bindings as $binding => $bindingData) { + if (isset($bindingData['operations']) && is_array($bindingData['operations'])) { + foreach($bindingData['operations'] as $operation => $data) { + $this->debug('post-parse data gathering for ' . $operation); + $this->bindings[$binding]['operations'][$operation]['input'] = + isset($this->bindings[$binding]['operations'][$operation]['input']) ? + array_merge($this->bindings[$binding]['operations'][$operation]['input'], $this->portTypes[ $bindingData['portType'] ][$operation]['input']) : + $this->portTypes[ $bindingData['portType'] ][$operation]['input']; + $this->bindings[$binding]['operations'][$operation]['output'] = + isset($this->bindings[$binding]['operations'][$operation]['output']) ? + array_merge($this->bindings[$binding]['operations'][$operation]['output'], $this->portTypes[ $bindingData['portType'] ][$operation]['output']) : + $this->portTypes[ $bindingData['portType'] ][$operation]['output']; + if(isset($this->messages[ $this->bindings[$binding]['operations'][$operation]['input']['message'] ])){ + $this->bindings[$binding]['operations'][$operation]['input']['parts'] = $this->messages[ $this->bindings[$binding]['operations'][$operation]['input']['message'] ]; + } + if(isset($this->messages[ $this->bindings[$binding]['operations'][$operation]['output']['message'] ])){ + $this->bindings[$binding]['operations'][$operation]['output']['parts'] = $this->messages[ $this->bindings[$binding]['operations'][$operation]['output']['message'] ]; + } + // Set operation style if necessary, but do not override one already provided + if (isset($bindingData['style']) && !isset($this->bindings[$binding]['operations'][$operation]['style'])) { + $this->bindings[$binding]['operations'][$operation]['style'] = $bindingData['style']; + } + $this->bindings[$binding]['operations'][$operation]['transport'] = isset($bindingData['transport']) ? $bindingData['transport'] : ''; + $this->bindings[$binding]['operations'][$operation]['documentation'] = isset($this->portTypes[ $bindingData['portType'] ][$operation]['documentation']) ? $this->portTypes[ $bindingData['portType'] ][$operation]['documentation'] : ''; + $this->bindings[$binding]['operations'][$operation]['endpoint'] = isset($bindingData['endpoint']) ? $bindingData['endpoint'] : ''; + } + } + } + } + + /** + * parses the wsdl document + * + * @param string $wsdl path or URL + * @access private + */ + function parseWSDL($wsdl = '') { + $this->debug("parse WSDL at path=$wsdl"); + + if ($wsdl == '') { + $this->debug('no wsdl passed to parseWSDL()!!'); + $this->setError('no wsdl passed to parseWSDL()!!'); + return false; + } + + // parse $wsdl for url format + $wsdl_props = parse_url($wsdl); + + if (isset($wsdl_props['scheme']) && ($wsdl_props['scheme'] == 'http' || $wsdl_props['scheme'] == 'https')) { + $this->debug('getting WSDL http(s) URL ' . $wsdl); + // get wsdl + $tr = new soap_transport_http($wsdl, $this->curl_options, $this->use_curl); + $tr->request_method = 'GET'; + $tr->useSOAPAction = false; + if($this->proxyhost && $this->proxyport){ + $tr->setProxy($this->proxyhost,$this->proxyport,$this->proxyusername,$this->proxypassword); + } + if ($this->authtype != '') { + $tr->setCredentials($this->username, $this->password, $this->authtype, array(), $this->certRequest); + } + $tr->setEncoding('gzip, deflate'); + $wsdl_string = $tr->send('', $this->timeout, $this->response_timeout); + //$this->debug("WSDL request\n" . $tr->outgoing_payload); + //$this->debug("WSDL response\n" . $tr->incoming_payload); + $this->appendDebug($tr->getDebug()); + // catch errors + if($err = $tr->getError() ){ + $errstr = 'Getting ' . $wsdl . ' - HTTP ERROR: '.$err; + $this->debug($errstr); + $this->setError($errstr); + unset($tr); + return false; + } + unset($tr); + $this->debug("got WSDL URL"); + } else { + // $wsdl is not http(s), so treat it as a file URL or plain file path + if (isset($wsdl_props['scheme']) && ($wsdl_props['scheme'] == 'file') && isset($wsdl_props['path'])) { + $path = isset($wsdl_props['host']) ? ($wsdl_props['host'] . ':' . $wsdl_props['path']) : $wsdl_props['path']; + } else { + $path = $wsdl; + } + $this->debug('getting WSDL file ' . $path); + $wsdl_string = @file_get_contents($path); + if ($wsdl_string === false) { + $errstr = "Bad path to WSDL file $path"; + $this->debug($errstr); + $this->setError($errstr); + return false; + } + } + $this->debug('Parse WSDL'); + // end new code added + // Create an XML parser. + $this->parser = xml_parser_create(); + // Set the options for parsing the XML data. + // xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1); + xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0); + // Set the object for the parser. + xml_set_object($this->parser, $this); + // Set the element handlers for the parser. + xml_set_element_handler($this->parser, 'start_element', 'end_element'); + xml_set_character_data_handler($this->parser, 'character_data'); + // Parse the XML file. + if (!xml_parse($this->parser, $wsdl_string, true)) { + // Display an error message. + $errstr = sprintf( + 'XML error parsing WSDL from %s on line %d: %s', + $wsdl, + xml_get_current_line_number($this->parser), + xml_error_string(xml_get_error_code($this->parser)) + ); + $this->debug($errstr); + $this->debug("XML payload:\n" . $wsdl_string); + $this->setError($errstr); + return false; + } + // free the parser + xml_parser_free($this->parser); + $this->debug('Parsing WSDL done'); + // catch wsdl parse errors + if($this->getError()){ + return false; + } + return true; + } + + /** + * start-element handler + * + * @param string $parser XML parser object + * @param string $name element name + * @param string $attrs associative array of attributes + * @access private + */ + function start_element($parser, $name, $attrs) + { + if ($this->status == 'schema') { + $this->currentSchema->schemaStartElement($parser, $name, $attrs); + $this->appendDebug($this->currentSchema->getDebug()); + $this->currentSchema->clearDebug(); + } elseif (preg_match('/schema$/', $name)) { + $this->debug('Parsing WSDL schema'); + // $this->debug("startElement for $name ($attrs[name]). status = $this->status (".$this->getLocalPart($name).")"); + $this->status = 'schema'; + $this->currentSchema = new nusoap_xmlschema('', '', $this->namespaces); + $this->currentSchema->schemaStartElement($parser, $name, $attrs); + $this->appendDebug($this->currentSchema->getDebug()); + $this->currentSchema->clearDebug(); + } else { + // position in the total number of elements, starting from 0 + $pos = $this->position++; + $depth = $this->depth++; + // set self as current value for this depth + $this->depth_array[$depth] = $pos; + $this->message[$pos] = array('cdata' => ''); + // process attributes + if (count($attrs) > 0) { + // register namespace declarations + foreach($attrs as $k => $v) { + if (preg_match('/^xmlns/',$k)) { + if ($ns_prefix = substr(strrchr($k, ':'), 1)) { + $this->namespaces[$ns_prefix] = $v; + } else { + $this->namespaces['ns' . (count($this->namespaces) + 1)] = $v; + } + if ($v == 'http://www.w3.org/2001/XMLSchema' || $v == 'http://www.w3.org/1999/XMLSchema' || $v == 'http://www.w3.org/2000/10/XMLSchema') { + $this->XMLSchemaVersion = $v; + $this->namespaces['xsi'] = $v . '-instance'; + } + } + } + // expand each attribute prefix to its namespace + foreach($attrs as $k => $v) { + $k = strpos($k, ':') ? $this->expandQname($k) : $k; + if ($k != 'location' && $k != 'soapAction' && $k != 'namespace') { + $v = strpos($v, ':') ? $this->expandQname($v) : $v; + } + $eAttrs[$k] = $v; + } + $attrs = $eAttrs; + } else { + $attrs = array(); + } + // get element prefix, namespace and name + if (preg_match('/:/', $name)) { + // get ns prefix + $prefix = substr($name, 0, strpos($name, ':')); + // get ns + $namespace = isset($this->namespaces[$prefix]) ? $this->namespaces[$prefix] : ''; + // get unqualified name + $name = substr(strstr($name, ':'), 1); + } + // process attributes, expanding any prefixes to namespaces + // find status, register data + switch ($this->status) { + case 'message': + if ($name == 'part') { + if (isset($attrs['type'])) { + $this->debug("msg " . $this->currentMessage . ": found part (with type) $attrs[name]: " . implode(',', $attrs)); + $this->messages[$this->currentMessage][$attrs['name']] = $attrs['type']; + } + if (isset($attrs['element'])) { + $this->debug("msg " . $this->currentMessage . ": found part (with element) $attrs[name]: " . implode(',', $attrs)); + $this->messages[$this->currentMessage][$attrs['name']] = $attrs['element'] . '^'; + } + } + break; + case 'portType': + switch ($name) { + case 'operation': + $this->currentPortOperation = $attrs['name']; + $this->debug("portType $this->currentPortType operation: $this->currentPortOperation"); + if (isset($attrs['parameterOrder'])) { + $this->portTypes[$this->currentPortType][$attrs['name']]['parameterOrder'] = $attrs['parameterOrder']; + } + break; + case 'documentation': + $this->documentation = true; + break; + // merge input/output data + default: + $m = isset($attrs['message']) ? $this->getLocalPart($attrs['message']) : ''; + $this->portTypes[$this->currentPortType][$this->currentPortOperation][$name]['message'] = $m; + break; + } + break; + case 'binding': + switch ($name) { + case 'binding': + // get ns prefix + if (isset($attrs['style'])) { + $this->bindings[$this->currentBinding]['prefix'] = $prefix; + } + $this->bindings[$this->currentBinding] = array_merge($this->bindings[$this->currentBinding], $attrs); + break; + case 'header': + $this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus]['headers'][] = $attrs; + break; + case 'operation': + if (isset($attrs['soapAction'])) { + $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['soapAction'] = $attrs['soapAction']; + } + if (isset($attrs['style'])) { + $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['style'] = $attrs['style']; + } + if (isset($attrs['name'])) { + $this->currentOperation = $attrs['name']; + $this->debug("current binding operation: $this->currentOperation"); + $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['name'] = $attrs['name']; + $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['binding'] = $this->currentBinding; + $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['endpoint'] = isset($this->bindings[$this->currentBinding]['endpoint']) ? $this->bindings[$this->currentBinding]['endpoint'] : ''; + } + break; + case 'input': + $this->opStatus = 'input'; + break; + case 'output': + $this->opStatus = 'output'; + break; + case 'body': + if (isset($this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus])) { + $this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus] = array_merge($this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus], $attrs); + } else { + $this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus] = $attrs; + } + break; + } + break; + case 'service': + switch ($name) { + case 'port': + $this->currentPort = $attrs['name']; + $this->debug('current port: ' . $this->currentPort); + $this->ports[$this->currentPort]['binding'] = $this->getLocalPart($attrs['binding']); + + break; + case 'address': + $this->ports[$this->currentPort]['location'] = $attrs['location']; + $this->ports[$this->currentPort]['bindingType'] = $namespace; + $this->bindings[ $this->ports[$this->currentPort]['binding'] ]['bindingType'] = $namespace; + $this->bindings[ $this->ports[$this->currentPort]['binding'] ]['endpoint'] = $attrs['location']; + break; + } + break; + } + // set status + switch ($name) { + case 'import': + if (isset($attrs['location'])) { + $this->import[$attrs['namespace']][] = array('location' => $attrs['location'], 'loaded' => false); + $this->debug('parsing import ' . $attrs['namespace']. ' - ' . $attrs['location'] . ' (' . count($this->import[$attrs['namespace']]).')'); + } else { + $this->import[$attrs['namespace']][] = array('location' => '', 'loaded' => true); + if (! $this->getPrefixFromNamespace($attrs['namespace'])) { + $this->namespaces['ns'.(count($this->namespaces)+1)] = $attrs['namespace']; + } + $this->debug('parsing import ' . $attrs['namespace']. ' - [no location] (' . count($this->import[$attrs['namespace']]).')'); + } + break; + //wait for schema + //case 'types': + // $this->status = 'schema'; + // break; + case 'message': + $this->status = 'message'; + $this->messages[$attrs['name']] = array(); + $this->currentMessage = $attrs['name']; + break; + case 'portType': + $this->status = 'portType'; + $this->portTypes[$attrs['name']] = array(); + $this->currentPortType = $attrs['name']; + break; + case "binding": + if (isset($attrs['name'])) { + // get binding name + if (strpos($attrs['name'], ':')) { + $this->currentBinding = $this->getLocalPart($attrs['name']); + } else { + $this->currentBinding = $attrs['name']; + } + $this->status = 'binding'; + $this->bindings[$this->currentBinding]['portType'] = $this->getLocalPart($attrs['type']); + $this->debug("current binding: $this->currentBinding of portType: " . $attrs['type']); + } + break; + case 'service': + $this->serviceName = $attrs['name']; + $this->status = 'service'; + $this->debug('current service: ' . $this->serviceName); + break; + case 'definitions': + foreach ($attrs as $name => $value) { + $this->wsdl_info[$name] = $value; + } + break; + } + } + } + + /** + * end-element handler + * + * @param string $parser XML parser object + * @param string $name element name + * @access private + */ + function end_element($parser, $name){ + // unset schema status + if (/*preg_match('/types$/', $name) ||*/ preg_match('/schema$/', $name)) { + $this->status = ""; + $this->appendDebug($this->currentSchema->getDebug()); + $this->currentSchema->clearDebug(); + $this->schemas[$this->currentSchema->schemaTargetNamespace][] = $this->currentSchema; + $this->debug('Parsing WSDL schema done'); + } + if ($this->status == 'schema') { + $this->currentSchema->schemaEndElement($parser, $name); + } else { + // bring depth down a notch + $this->depth--; + } + // end documentation + if ($this->documentation) { + //TODO: track the node to which documentation should be assigned; it can be a part, message, etc. + //$this->portTypes[$this->currentPortType][$this->currentPortOperation]['documentation'] = $this->documentation; + $this->documentation = false; + } + } + + /** + * element content handler + * + * @param string $parser XML parser object + * @param string $data element content + * @access private + */ + function character_data($parser, $data) + { + $pos = isset($this->depth_array[$this->depth]) ? $this->depth_array[$this->depth] : 0; + if (isset($this->message[$pos]['cdata'])) { + $this->message[$pos]['cdata'] .= $data; + } + if ($this->documentation) { + $this->documentation .= $data; + } + } + + /** + * if authenticating, set user credentials here + * + * @param string $username + * @param string $password + * @param string $authtype (basic|digest|certificate|ntlm) + * @param array $certRequest (keys must be cainfofile (optional), sslcertfile, sslkeyfile, passphrase, certpassword (optional), verifypeer (optional), verifyhost (optional): see corresponding options in cURL docs) + * @access public + */ + function setCredentials($username, $password, $authtype = 'basic', $certRequest = array()) { + $this->debug("setCredentials username=$username authtype=$authtype certRequest="); + $this->appendDebug($this->varDump($certRequest)); + $this->username = $username; + $this->password = $password; + $this->authtype = $authtype; + $this->certRequest = $certRequest; + } + + function getBindingData($binding) + { + if (is_array($this->bindings[$binding])) { + return $this->bindings[$binding]; + } + } + + /** + * returns an assoc array of operation names => operation data + * + * @param string $portName WSDL port name + * @param string $bindingType eg: soap, smtp, dime (only soap and soap12 are currently supported) + * @return array + * @access public + */ + function getOperations($portName = '', $bindingType = 'soap') { + $ops = array(); + if ($bindingType == 'soap') { + $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/'; + } elseif ($bindingType == 'soap12') { + $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap12/'; + } else { + $this->debug("getOperations bindingType $bindingType may not be supported"); + } + $this->debug("getOperations for port '$portName' bindingType $bindingType"); + // loop thru ports + foreach($this->ports as $port => $portData) { + $this->debug("getOperations checking port $port bindingType " . $portData['bindingType']); + if ($portName == '' || $port == $portName) { + // binding type of port matches parameter + if ($portData['bindingType'] == $bindingType) { + $this->debug("getOperations found port $port bindingType $bindingType"); + //$this->debug("port data: " . $this->varDump($portData)); + //$this->debug("bindings: " . $this->varDump($this->bindings[ $portData['binding'] ])); + // merge bindings + if (isset($this->bindings[ $portData['binding'] ]['operations'])) { + $ops = array_merge ($ops, $this->bindings[ $portData['binding'] ]['operations']); + } + } + } + } + if (count($ops) == 0) { + $this->debug("getOperations found no operations for port '$portName' bindingType $bindingType"); + } + return $ops; + } + + /** + * returns an associative array of data necessary for calling an operation + * + * @param string $operation name of operation + * @param string $bindingType type of binding eg: soap, soap12 + * @return array + * @access public + */ + function getOperationData($operation, $bindingType = 'soap') + { + if ($bindingType == 'soap') { + $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/'; + } elseif ($bindingType == 'soap12') { + $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap12/'; + } + // loop thru ports + foreach($this->ports as $port => $portData) { + // binding type of port matches parameter + if ($portData['bindingType'] == $bindingType) { + // get binding + //foreach($this->bindings[ $portData['binding'] ]['operations'] as $bOperation => $opData) { + foreach(array_keys($this->bindings[ $portData['binding'] ]['operations']) as $bOperation) { + // note that we could/should also check the namespace here + if ($operation == $bOperation) { + $opData = $this->bindings[ $portData['binding'] ]['operations'][$operation]; + return $opData; + } + } + } + } + } + + /** + * returns an associative array of data necessary for calling an operation + * + * @param string $soapAction soapAction for operation + * @param string $bindingType type of binding eg: soap, soap12 + * @return array + * @access public + */ + function getOperationDataForSoapAction($soapAction, $bindingType = 'soap') { + if ($bindingType == 'soap') { + $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/'; + } elseif ($bindingType == 'soap12') { + $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap12/'; + } + // loop thru ports + foreach($this->ports as $port => $portData) { + // binding type of port matches parameter + if ($portData['bindingType'] == $bindingType) { + // loop through operations for the binding + foreach ($this->bindings[ $portData['binding'] ]['operations'] as $bOperation => $opData) { + if ($opData['soapAction'] == $soapAction) { + return $opData; + } + } + } + } + } + + /** + * returns an array of information about a given type + * returns false if no type exists by the given name + * + * typeDef = array( + * 'elements' => array(), // refs to elements array + * 'restrictionBase' => '', + * 'phpType' => '', + * 'order' => '(sequence|all)', + * 'attrs' => array() // refs to attributes array + * ) + * + * @param string $type the type + * @param string $ns namespace (not prefix) of the type + * @return mixed + * @access public + * @see nusoap_xmlschema + */ + function getTypeDef($type, $ns) { + $this->debug("in getTypeDef: type=$type, ns=$ns"); + if ((! $ns) && isset($this->namespaces['tns'])) { + $ns = $this->namespaces['tns']; + $this->debug("in getTypeDef: type namespace forced to $ns"); + } + if (!isset($this->schemas[$ns])) { + foreach ($this->schemas as $ns0 => $schema0) { + if (strcasecmp($ns, $ns0) == 0) { + $this->debug("in getTypeDef: replacing schema namespace $ns with $ns0"); + $ns = $ns0; + break; + } + } + } + if (isset($this->schemas[$ns])) { + $this->debug("in getTypeDef: have schema for namespace $ns"); + for ($i = 0; $i < count($this->schemas[$ns]); $i++) { + $xs = &$this->schemas[$ns][$i]; + $t = $xs->getTypeDef($type); + $this->appendDebug($xs->getDebug()); + $xs->clearDebug(); + if ($t) { + $this->debug("in getTypeDef: found type $type"); + if (!isset($t['phpType'])) { + // get info for type to tack onto the element + $uqType = substr($t['type'], strrpos($t['type'], ':') + 1); + $ns = substr($t['type'], 0, strrpos($t['type'], ':')); + $etype = $this->getTypeDef($uqType, $ns); + if ($etype) { + $this->debug("found type for [element] $type:"); + $this->debug($this->varDump($etype)); + if (isset($etype['phpType'])) { + $t['phpType'] = $etype['phpType']; + } + if (isset($etype['elements'])) { + $t['elements'] = $etype['elements']; + } + if (isset($etype['attrs'])) { + $t['attrs'] = $etype['attrs']; + } + } else { + $this->debug("did not find type for [element] $type"); + } + } + return $t; + } + } + $this->debug("in getTypeDef: did not find type $type"); + } else { + $this->debug("in getTypeDef: do not have schema for namespace $ns"); + } + return false; + } + + /** + * prints html description of services + * + * @access private + */ + function webDescription(){ + global $HTTP_SERVER_VARS; + + if (isset($_SERVER)) { + $PHP_SELF = $_SERVER['PHP_SELF']; + } elseif (isset($HTTP_SERVER_VARS)) { + $PHP_SELF = $HTTP_SERVER_VARS['PHP_SELF']; + } else { + $this->setError("Neither _SERVER nor HTTP_SERVER_VARS is available"); + } + + $b = ' + NuSOAP: '.$this->serviceName.' + + + + +
    +

    +
    '.$this->serviceName.'
    + +
    '; + return $b; + } + + /** + * serialize the parsed wsdl + * + * @param mixed $debug whether to put debug=1 in endpoint URL + * @return string serialization of WSDL + * @access public + */ + function serialize($debug = 0) + { + $xml = ''; + $xml .= "\nnamespaces as $k => $v) { + $xml .= " xmlns:$k=\"$v\""; + } + // 10.9.02 - add poulter fix for wsdl and tns declarations + if (isset($this->namespaces['wsdl'])) { + $xml .= " xmlns=\"" . $this->namespaces['wsdl'] . "\""; + } + if (isset($this->namespaces['tns'])) { + $xml .= " targetNamespace=\"" . $this->namespaces['tns'] . "\""; + } + $xml .= '>'; + // imports + if (sizeof($this->import) > 0) { + foreach($this->import as $ns => $list) { + foreach ($list as $ii) { + if ($ii['location'] != '') { + $xml .= ''; + } else { + $xml .= ''; + } + } + } + } + // types + if (count($this->schemas)>=1) { + $xml .= "\n\n"; + foreach ($this->schemas as $ns => $list) { + foreach ($list as $xs) { + $xml .= $xs->serializeSchema(); + } + } + $xml .= ''; + } + // messages + if (count($this->messages) >= 1) { + foreach($this->messages as $msgName => $msgParts) { + $xml .= "\n'; + if(is_array($msgParts)){ + foreach($msgParts as $partName => $partType) { + // print 'serializing '.$partType.', sv: '.$this->XMLSchemaVersion.'
    '; + if (strpos($partType, ':')) { + $typePrefix = $this->getPrefixFromNamespace($this->getPrefix($partType)); + } elseif (isset($this->typemap[$this->namespaces['xsd']][$partType])) { + // print 'checking typemap: '.$this->XMLSchemaVersion.'
    '; + $typePrefix = 'xsd'; + } else { + foreach($this->typemap as $ns => $types) { + if (isset($types[$partType])) { + $typePrefix = $this->getPrefixFromNamespace($ns); + } + } + if (!isset($typePrefix)) { + die("$partType has no namespace!"); + } + } + $ns = $this->getNamespaceFromPrefix($typePrefix); + $localPart = $this->getLocalPart($partType); + $typeDef = $this->getTypeDef($localPart, $ns); + if ($typeDef['typeClass'] == 'element') { + $elementortype = 'element'; + if (substr($localPart, -1) == '^') { + $localPart = substr($localPart, 0, -1); + } + } else { + $elementortype = 'type'; + } + $xml .= "\n" . ' '; + } + } + $xml .= '
    '; + } + } + // bindings & porttypes + if (count($this->bindings) >= 1) { + $binding_xml = ''; + $portType_xml = ''; + foreach($this->bindings as $bindingName => $attrs) { + $binding_xml .= "\n'; + $binding_xml .= "\n" . ' '; + $portType_xml .= "\n'; + foreach($attrs['operations'] as $opName => $opParts) { + $binding_xml .= "\n" . ' '; + $binding_xml .= "\n" . ' '; + if (isset($opParts['input']['encodingStyle']) && $opParts['input']['encodingStyle'] != '') { + $enc_style = ' encodingStyle="' . $opParts['input']['encodingStyle'] . '"'; + } else { + $enc_style = ''; + } + $binding_xml .= "\n" . ' '; + if (isset($opParts['output']['encodingStyle']) && $opParts['output']['encodingStyle'] != '') { + $enc_style = ' encodingStyle="' . $opParts['output']['encodingStyle'] . '"'; + } else { + $enc_style = ''; + } + $binding_xml .= "\n" . ' '; + $binding_xml .= "\n" . ' '; + $portType_xml .= "\n" . ' ' . htmlspecialchars($opParts['documentation']) . ''; + } + $portType_xml .= "\n" . ' '; + $portType_xml .= "\n" . ' '; + $portType_xml .= "\n" . ' '; + } + $portType_xml .= "\n" . ''; + $binding_xml .= "\n" . ''; + } + $xml .= $portType_xml . $binding_xml; + } + // services + $xml .= "\nserviceName . '">'; + if (count($this->ports) >= 1) { + foreach($this->ports as $pName => $attrs) { + $xml .= "\n" . ' '; + $xml .= "\n" . ' '; + $xml .= "\n" . ' '; + } + } + $xml .= "\n" . ''; + return $xml . "\n"; + } + + /** + * determine whether a set of parameters are unwrapped + * when they are expect to be wrapped, Microsoft-style. + * + * @param string $type the type (element name) of the wrapper + * @param array $parameters the parameter values for the SOAP call + * @return boolean whether they parameters are unwrapped (and should be wrapped) + * @access private + */ + function parametersMatchWrapped($type, &$parameters) { + $this->debug("in parametersMatchWrapped type=$type, parameters="); + $this->appendDebug($this->varDump($parameters)); + + // split type into namespace:unqualified-type + if (strpos($type, ':')) { + $uqType = substr($type, strrpos($type, ':') + 1); + $ns = substr($type, 0, strrpos($type, ':')); + $this->debug("in parametersMatchWrapped: got a prefixed type: $uqType, $ns"); + if ($this->getNamespaceFromPrefix($ns)) { + $ns = $this->getNamespaceFromPrefix($ns); + $this->debug("in parametersMatchWrapped: expanded prefixed type: $uqType, $ns"); + } + } else { + // TODO: should the type be compared to types in XSD, and the namespace + // set to XSD if the type matches? + $this->debug("in parametersMatchWrapped: No namespace for type $type"); + $ns = ''; + $uqType = $type; + } + + // get the type information + if (!$typeDef = $this->getTypeDef($uqType, $ns)) { + $this->debug("in parametersMatchWrapped: $type ($uqType) is not a supported type."); + return false; + } + $this->debug("in parametersMatchWrapped: found typeDef="); + $this->appendDebug($this->varDump($typeDef)); + if (substr($uqType, -1) == '^') { + $uqType = substr($uqType, 0, -1); + } + $phpType = $typeDef['phpType']; + $arrayType = (isset($typeDef['arrayType']) ? $typeDef['arrayType'] : ''); + $this->debug("in parametersMatchWrapped: uqType: $uqType, ns: $ns, phptype: $phpType, arrayType: $arrayType"); + + // we expect a complexType or element of complexType + if ($phpType != 'struct') { + $this->debug("in parametersMatchWrapped: not a struct"); + return false; + } + + // see whether the parameter names match the elements + if (isset($typeDef['elements']) && is_array($typeDef['elements'])) { + $elements = 0; + $matches = 0; + foreach ($typeDef['elements'] as $name => $attrs) { + if (isset($parameters[$name])) { + $this->debug("in parametersMatchWrapped: have parameter named $name"); + $matches++; + } else { + $this->debug("in parametersMatchWrapped: do not have parameter named $name"); + } + $elements++; + } + + $this->debug("in parametersMatchWrapped: $matches parameter names match $elements wrapped parameter names"); + if ($matches == 0) { + return false; + } + return true; + } + + // since there are no elements for the type, if the user passed no + // parameters, the parameters match wrapped. + $this->debug("in parametersMatchWrapped: no elements type $ns:$uqType"); + return count($parameters) == 0; + } + + /** + * serialize PHP values according to a WSDL message definition + * contrary to the method name, this is not limited to RPC + * + * TODO + * - multi-ref serialization + * - validate PHP values against type definitions, return errors if invalid + * + * @param string $operation operation name + * @param string $direction (input|output) + * @param mixed $parameters parameter value(s) + * @param string $bindingType (soap|soap12) + * @return mixed parameters serialized as XML or false on error (e.g. operation not found) + * @access public + */ + function serializeRPCParameters($operation, $direction, $parameters, $bindingType = 'soap') { + $this->debug("in serializeRPCParameters: operation=$operation, direction=$direction, XMLSchemaVersion=$this->XMLSchemaVersion, bindingType=$bindingType"); + $this->appendDebug('parameters=' . $this->varDump($parameters)); + + if ($direction != 'input' && $direction != 'output') { + $this->debug('The value of the \$direction argument needs to be either "input" or "output"'); + $this->setError('The value of the \$direction argument needs to be either "input" or "output"'); + return false; + } + if (!$opData = $this->getOperationData($operation, $bindingType)) { + $this->debug('Unable to retrieve WSDL data for operation: ' . $operation . ' bindingType: ' . $bindingType); + $this->setError('Unable to retrieve WSDL data for operation: ' . $operation . ' bindingType: ' . $bindingType); + return false; + } + $this->debug('in serializeRPCParameters: opData:'); + $this->appendDebug($this->varDump($opData)); + + // Get encoding style for output and set to current + $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/'; + if(($direction == 'input') && isset($opData['output']['encodingStyle']) && ($opData['output']['encodingStyle'] != $encodingStyle)) { + $encodingStyle = $opData['output']['encodingStyle']; + $enc_style = $encodingStyle; + } + + // set input params + $xml = ''; + if (isset($opData[$direction]['parts']) && sizeof($opData[$direction]['parts']) > 0) { + $parts = &$opData[$direction]['parts']; + $part_count = sizeof($parts); + $style = $opData['style']; + $use = $opData[$direction]['use']; + $this->debug("have $part_count part(s) to serialize using $style/$use"); + if (is_array($parameters)) { + $parametersArrayType = $this->isArraySimpleOrStruct($parameters); + $parameter_count = count($parameters); + $this->debug("have $parameter_count parameter(s) provided as $parametersArrayType to serialize"); + // check for Microsoft-style wrapped parameters + if ($style == 'document' && $use == 'literal' && $part_count == 1 && isset($parts['parameters'])) { + $this->debug('check whether the caller has wrapped the parameters'); + if ($direction == 'output' && $parametersArrayType == 'arraySimple' && $parameter_count == 1) { + // TODO: consider checking here for double-wrapping, when + // service function wraps, then NuSOAP wraps again + $this->debug("change simple array to associative with 'parameters' element"); + $parameters['parameters'] = $parameters[0]; + unset($parameters[0]); + } + if (($parametersArrayType == 'arrayStruct' || $parameter_count == 0) && !isset($parameters['parameters'])) { + $this->debug('check whether caller\'s parameters match the wrapped ones'); + if ($this->parametersMatchWrapped($parts['parameters'], $parameters)) { + $this->debug('wrap the parameters for the caller'); + $parameters = array('parameters' => $parameters); + $parameter_count = 1; + } + } + } + foreach ($parts as $name => $type) { + $this->debug("serializing part $name of type $type"); + // Track encoding style + if (isset($opData[$direction]['encodingStyle']) && $encodingStyle != $opData[$direction]['encodingStyle']) { + $encodingStyle = $opData[$direction]['encodingStyle']; + $enc_style = $encodingStyle; + } else { + $enc_style = false; + } + // NOTE: add error handling here + // if serializeType returns false, then catch global error and fault + if ($parametersArrayType == 'arraySimple') { + $p = array_shift($parameters); + $this->debug('calling serializeType w/indexed param'); + $xml .= $this->serializeType($name, $type, $p, $use, $enc_style); + } elseif (isset($parameters[$name])) { + $this->debug('calling serializeType w/named param'); + $xml .= $this->serializeType($name, $type, $parameters[$name], $use, $enc_style); + } else { + // TODO: only send nillable + $this->debug('calling serializeType w/null param'); + $xml .= $this->serializeType($name, $type, null, $use, $enc_style); + } + } + } else { + $this->debug('no parameters passed.'); + } + } + $this->debug("serializeRPCParameters returning: $xml"); + return $xml; + } + + /** + * serialize a PHP value according to a WSDL message definition + * + * TODO + * - multi-ref serialization + * - validate PHP values against type definitions, return errors if invalid + * + * @param string $operation operation name + * @param string $direction (input|output) + * @param mixed $parameters parameter value(s) + * @return mixed parameters serialized as XML or false on error (e.g. operation not found) + * @access public + * @deprecated + */ + function serializeParameters($operation, $direction, $parameters) + { + $this->debug("in serializeParameters: operation=$operation, direction=$direction, XMLSchemaVersion=$this->XMLSchemaVersion"); + $this->appendDebug('parameters=' . $this->varDump($parameters)); + + if ($direction != 'input' && $direction != 'output') { + $this->debug('The value of the \$direction argument needs to be either "input" or "output"'); + $this->setError('The value of the \$direction argument needs to be either "input" or "output"'); + return false; + } + if (!$opData = $this->getOperationData($operation)) { + $this->debug('Unable to retrieve WSDL data for operation: ' . $operation); + $this->setError('Unable to retrieve WSDL data for operation: ' . $operation); + return false; + } + $this->debug('opData:'); + $this->appendDebug($this->varDump($opData)); + + // Get encoding style for output and set to current + $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/'; + if(($direction == 'input') && isset($opData['output']['encodingStyle']) && ($opData['output']['encodingStyle'] != $encodingStyle)) { + $encodingStyle = $opData['output']['encodingStyle']; + $enc_style = $encodingStyle; + } + + // set input params + $xml = ''; + if (isset($opData[$direction]['parts']) && sizeof($opData[$direction]['parts']) > 0) { + + $use = $opData[$direction]['use']; + $this->debug("use=$use"); + $this->debug('got ' . count($opData[$direction]['parts']) . ' part(s)'); + if (is_array($parameters)) { + $parametersArrayType = $this->isArraySimpleOrStruct($parameters); + $this->debug('have ' . $parametersArrayType . ' parameters'); + foreach($opData[$direction]['parts'] as $name => $type) { + $this->debug('serializing part "'.$name.'" of type "'.$type.'"'); + // Track encoding style + if(isset($opData[$direction]['encodingStyle']) && $encodingStyle != $opData[$direction]['encodingStyle']) { + $encodingStyle = $opData[$direction]['encodingStyle']; + $enc_style = $encodingStyle; + } else { + $enc_style = false; + } + // NOTE: add error handling here + // if serializeType returns false, then catch global error and fault + if ($parametersArrayType == 'arraySimple') { + $p = array_shift($parameters); + $this->debug('calling serializeType w/indexed param'); + $xml .= $this->serializeType($name, $type, $p, $use, $enc_style); + } elseif (isset($parameters[$name])) { + $this->debug('calling serializeType w/named param'); + $xml .= $this->serializeType($name, $type, $parameters[$name], $use, $enc_style); + } else { + // TODO: only send nillable + $this->debug('calling serializeType w/null param'); + $xml .= $this->serializeType($name, $type, null, $use, $enc_style); + } + } + } else { + $this->debug('no parameters passed.'); + } + } + $this->debug("serializeParameters returning: $xml"); + return $xml; + } + + /** + * serializes a PHP value according a given type definition + * + * @param string $name name of value (part or element) + * @param string $type XML schema type of value (type or element) + * @param mixed $value a native PHP value (parameter value) + * @param string $use use for part (encoded|literal) + * @param string $encodingStyle SOAP encoding style for the value (if different than the enclosing style) + * @param boolean $unqualified a kludge for what should be XML namespace form handling + * @return string value serialized as an XML string + * @access private + */ + function serializeType($name, $type, $value, $use='encoded', $encodingStyle=false, $unqualified=false) + { + $this->debug("in serializeType: name=$name, type=$type, use=$use, encodingStyle=$encodingStyle, unqualified=" . ($unqualified ? "unqualified" : "qualified")); + $this->appendDebug("value=" . $this->varDump($value)); + if($use == 'encoded' && $encodingStyle) { + $encodingStyle = ' SOAP-ENV:encodingStyle="' . $encodingStyle . '"'; + } + + // if a soapval has been supplied, let its type override the WSDL + if (is_object($value) && get_class($value) == 'soapval') { + if ($value->type_ns) { + $type = $value->type_ns . ':' . $value->type; + $forceType = true; + $this->debug("in serializeType: soapval overrides type to $type"); + } elseif ($value->type) { + $type = $value->type; + $forceType = true; + $this->debug("in serializeType: soapval overrides type to $type"); + } else { + $forceType = false; + $this->debug("in serializeType: soapval does not override type"); + } + $attrs = $value->attributes; + $value = $value->value; + $this->debug("in serializeType: soapval overrides value to $value"); + if ($attrs) { + if (!is_array($value)) { + $value['!'] = $value; + } + foreach ($attrs as $n => $v) { + $value['!' . $n] = $v; + } + $this->debug("in serializeType: soapval provides attributes"); + } + } else { + $forceType = false; + } + + $xml = ''; + if (strpos($type, ':')) { + $uqType = substr($type, strrpos($type, ':') + 1); + $ns = substr($type, 0, strrpos($type, ':')); + $this->debug("in serializeType: got a prefixed type: $uqType, $ns"); + if ($this->getNamespaceFromPrefix($ns)) { + $ns = $this->getNamespaceFromPrefix($ns); + $this->debug("in serializeType: expanded prefixed type: $uqType, $ns"); + } + + if($ns == $this->XMLSchemaVersion || $ns == 'http://schemas.xmlsoap.org/soap/encoding/'){ + $this->debug('in serializeType: type namespace indicates XML Schema or SOAP Encoding type'); + if ($unqualified && $use == 'literal') { + $elementNS = " xmlns=\"\""; + } else { + $elementNS = ''; + } + if (is_null($value)) { + if ($use == 'literal') { + // TODO: depends on minOccurs + $xml = "<$name$elementNS/>"; + } else { + // TODO: depends on nillable, which should be checked before calling this method + $xml = "<$name$elementNS xsi:nil=\"true\" xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"/>"; + } + $this->debug("in serializeType: returning: $xml"); + return $xml; + } + if ($uqType == 'Array') { + // JBoss/Axis does this sometimes + return $this->serialize_val($value, $name, false, false, false, false, $use); + } + if ($uqType == 'boolean') { + if ((is_string($value) && $value == 'false') || (! $value)) { + $value = 'false'; + } else { + $value = 'true'; + } + } + if ($uqType == 'string' && gettype($value) == 'string') { + $value = $this->expandEntities($value); + } + if (($uqType == 'long' || $uqType == 'unsignedLong') && gettype($value) == 'double') { + $value = sprintf("%.0lf", $value); + } + // it's a scalar + // TODO: what about null/nil values? + // check type isn't a custom type extending xmlschema namespace + if (!$this->getTypeDef($uqType, $ns)) { + if ($use == 'literal') { + if ($forceType) { + $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">$value"; + } else { + $xml = "<$name$elementNS>$value"; + } + } else { + $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"$encodingStyle>$value"; + } + $this->debug("in serializeType: returning: $xml"); + return $xml; + } + $this->debug('custom type extends XML Schema or SOAP Encoding namespace (yuck)'); + } else if ($ns == 'http://xml.apache.org/xml-soap') { + $this->debug('in serializeType: appears to be Apache SOAP type'); + if ($uqType == 'Map') { + $tt_prefix = $this->getPrefixFromNamespace('http://xml.apache.org/xml-soap'); + if (! $tt_prefix) { + $this->debug('in serializeType: Add namespace for Apache SOAP type'); + $tt_prefix = 'ns' . rand(1000, 9999); + $this->namespaces[$tt_prefix] = 'http://xml.apache.org/xml-soap'; + // force this to be added to usedNamespaces + $tt_prefix = $this->getPrefixFromNamespace('http://xml.apache.org/xml-soap'); + } + $contents = ''; + foreach($value as $k => $v) { + $this->debug("serializing map element: key $k, value $v"); + $contents .= ''; + $contents .= $this->serialize_val($k,'key',false,false,false,false,$use); + $contents .= $this->serialize_val($v,'value',false,false,false,false,$use); + $contents .= ''; + } + if ($use == 'literal') { + if ($forceType) { + $xml = "<$name xsi:type=\"" . $tt_prefix . ":$uqType\">$contents"; + } else { + $xml = "<$name>$contents"; + } + } else { + $xml = "<$name xsi:type=\"" . $tt_prefix . ":$uqType\"$encodingStyle>$contents"; + } + $this->debug("in serializeType: returning: $xml"); + return $xml; + } + $this->debug('in serializeType: Apache SOAP type, but only support Map'); + } + } else { + // TODO: should the type be compared to types in XSD, and the namespace + // set to XSD if the type matches? + $this->debug("in serializeType: No namespace for type $type"); + $ns = ''; + $uqType = $type; + } + if(!$typeDef = $this->getTypeDef($uqType, $ns)){ + $this->setError("$type ($uqType) is not a supported type."); + $this->debug("in serializeType: $type ($uqType) is not a supported type."); + return false; + } else { + $this->debug("in serializeType: found typeDef"); + $this->appendDebug('typeDef=' . $this->varDump($typeDef)); + if (substr($uqType, -1) == '^') { + $uqType = substr($uqType, 0, -1); + } + } + if (!isset($typeDef['phpType'])) { + $this->setError("$type ($uqType) has no phpType."); + $this->debug("in serializeType: $type ($uqType) has no phpType."); + return false; + } + $phpType = $typeDef['phpType']; + $this->debug("in serializeType: uqType: $uqType, ns: $ns, phptype: $phpType, arrayType: " . (isset($typeDef['arrayType']) ? $typeDef['arrayType'] : '') ); + // if php type == struct, map value to the element names + if ($phpType == 'struct') { + if (isset($typeDef['typeClass']) && $typeDef['typeClass'] == 'element') { + $elementName = $uqType; + if (isset($typeDef['form']) && ($typeDef['form'] == 'qualified')) { + $elementNS = " xmlns=\"$ns\""; + } else { + $elementNS = " xmlns=\"\""; + } + } else { + $elementName = $name; + if ($unqualified) { + $elementNS = " xmlns=\"\""; + } else { + $elementNS = ''; + } + } + if (is_null($value)) { + if ($use == 'literal') { + // TODO: depends on minOccurs and nillable + $xml = "<$elementName$elementNS/>"; + } else { + $xml = "<$elementName$elementNS xsi:nil=\"true\" xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"/>"; + } + $this->debug("in serializeType: returning: $xml"); + return $xml; + } + if (is_object($value)) { + $value = get_object_vars($value); + } + if (is_array($value)) { + $elementAttrs = $this->serializeComplexTypeAttributes($typeDef, $value, $ns, $uqType); + if ($use == 'literal') { + if ($forceType) { + $xml = "<$elementName$elementNS$elementAttrs xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">"; + } else { + $xml = "<$elementName$elementNS$elementAttrs>"; + } + } else { + $xml = "<$elementName$elementNS$elementAttrs xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"$encodingStyle>"; + } + + if (isset($typeDef['simpleContent']) && $typeDef['simpleContent'] == 'true') { + if (isset($value['!'])) { + $xml .= $value['!']; + $this->debug("in serializeType: serialized simpleContent for type $type"); + } else { + $this->debug("in serializeType: no simpleContent to serialize for type $type"); + } + } else { + // complexContent + $xml .= $this->serializeComplexTypeElements($typeDef, $value, $ns, $uqType, $use, $encodingStyle); + } + $xml .= ""; + } else { + $this->debug("in serializeType: phpType is struct, but value is not an array"); + $this->setError("phpType is struct, but value is not an array: see debug output for details"); + $xml = ''; + } + } elseif ($phpType == 'array') { + if (isset($typeDef['form']) && ($typeDef['form'] == 'qualified')) { + $elementNS = " xmlns=\"$ns\""; + } else { + if ($unqualified) { + $elementNS = " xmlns=\"\""; + } else { + $elementNS = ''; + } + } + if (is_null($value)) { + if ($use == 'literal') { + // TODO: depends on minOccurs + $xml = "<$name$elementNS/>"; + } else { + $xml = "<$name$elementNS xsi:nil=\"true\" xsi:type=\"" . + $this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/') . + ":Array\" " . + $this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/') . + ':arrayType="' . + $this->getPrefixFromNamespace($this->getPrefix($typeDef['arrayType'])) . + ':' . + $this->getLocalPart($typeDef['arrayType'])."[0]\"/>"; + } + $this->debug("in serializeType: returning: $xml"); + return $xml; + } + if (isset($typeDef['multidimensional'])) { + $nv = array(); + foreach($value as $v) { + $cols = ',' . sizeof($v); + $nv = array_merge($nv, $v); + } + $value = $nv; + } else { + $cols = ''; + } + if (is_array($value) && sizeof($value) >= 1) { + $rows = sizeof($value); + $contents = ''; + foreach($value as $k => $v) { + $this->debug("serializing array element: $k, $v of type: $typeDef[arrayType]"); + //if (strpos($typeDef['arrayType'], ':') ) { + if (!in_array($typeDef['arrayType'],$this->typemap['http://www.w3.org/2001/XMLSchema'])) { + $contents .= $this->serializeType('item', $typeDef['arrayType'], $v, $use); + } else { + $contents .= $this->serialize_val($v, 'item', $typeDef['arrayType'], null, $this->XMLSchemaVersion, false, $use); + } + } + } else { + $rows = 0; + $contents = null; + } + // TODO: for now, an empty value will be serialized as a zero element + // array. Revisit this when coding the handling of null/nil values. + if ($use == 'literal') { + $xml = "<$name$elementNS>" + .$contents + .""; + } else { + $xml = "<$name$elementNS xsi:type=\"".$this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/').':Array" '. + $this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/') + .':arrayType="' + .$this->getPrefixFromNamespace($this->getPrefix($typeDef['arrayType'])) + .":".$this->getLocalPart($typeDef['arrayType'])."[$rows$cols]\">" + .$contents + .""; + } + } elseif ($phpType == 'scalar') { + if (isset($typeDef['form']) && ($typeDef['form'] == 'qualified')) { + $elementNS = " xmlns=\"$ns\""; + } else { + if ($unqualified) { + $elementNS = " xmlns=\"\""; + } else { + $elementNS = ''; + } + } + if ($use == 'literal') { + if ($forceType) { + $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">$value"; + } else { + $xml = "<$name$elementNS>$value"; + } + } else { + $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"$encodingStyle>$value"; + } + } + $this->debug("in serializeType: returning: $xml"); + return $xml; + } + + /** + * serializes the attributes for a complexType + * + * @param array $typeDef our internal representation of an XML schema type (or element) + * @param mixed $value a native PHP value (parameter value) + * @param string $ns the namespace of the type + * @param string $uqType the local part of the type + * @return string value serialized as an XML string + * @access private + */ + function serializeComplexTypeAttributes($typeDef, $value, $ns, $uqType) { + $this->debug("serializeComplexTypeAttributes for XML Schema type $ns:$uqType"); + $xml = ''; + if (isset($typeDef['extensionBase'])) { + $nsx = $this->getPrefix($typeDef['extensionBase']); + $uqTypex = $this->getLocalPart($typeDef['extensionBase']); + if ($this->getNamespaceFromPrefix($nsx)) { + $nsx = $this->getNamespaceFromPrefix($nsx); + } + if ($typeDefx = $this->getTypeDef($uqTypex, $nsx)) { + $this->debug("serialize attributes for extension base $nsx:$uqTypex"); + $xml .= $this->serializeComplexTypeAttributes($typeDefx, $value, $nsx, $uqTypex); + } else { + $this->debug("extension base $nsx:$uqTypex is not a supported type"); + } + } + if (isset($typeDef['attrs']) && is_array($typeDef['attrs'])) { + $this->debug("serialize attributes for XML Schema type $ns:$uqType"); + if (is_array($value)) { + $xvalue = $value; + } elseif (is_object($value)) { + $xvalue = get_object_vars($value); + } else { + $this->debug("value is neither an array nor an object for XML Schema type $ns:$uqType"); + $xvalue = array(); + } + foreach ($typeDef['attrs'] as $aName => $attrs) { + if (isset($xvalue['!' . $aName])) { + $xname = '!' . $aName; + $this->debug("value provided for attribute $aName with key $xname"); + } elseif (isset($xvalue[$aName])) { + $xname = $aName; + $this->debug("value provided for attribute $aName with key $xname"); + } elseif (isset($attrs['default'])) { + $xname = '!' . $aName; + $xvalue[$xname] = $attrs['default']; + $this->debug('use default value of ' . $xvalue[$aName] . ' for attribute ' . $aName); + } else { + $xname = ''; + $this->debug("no value provided for attribute $aName"); + } + if ($xname) { + $xml .= " $aName=\"" . $this->expandEntities($xvalue[$xname]) . "\""; + } + } + } else { + $this->debug("no attributes to serialize for XML Schema type $ns:$uqType"); + } + return $xml; + } + + /** + * serializes the elements for a complexType + * + * @param array $typeDef our internal representation of an XML schema type (or element) + * @param mixed $value a native PHP value (parameter value) + * @param string $ns the namespace of the type + * @param string $uqType the local part of the type + * @param string $use use for part (encoded|literal) + * @param string $encodingStyle SOAP encoding style for the value (if different than the enclosing style) + * @return string value serialized as an XML string + * @access private + */ + function serializeComplexTypeElements($typeDef, $value, $ns, $uqType, $use='encoded', $encodingStyle=false) { + $this->debug("in serializeComplexTypeElements for XML Schema type $ns:$uqType"); + $xml = ''; + if (isset($typeDef['extensionBase'])) { + $nsx = $this->getPrefix($typeDef['extensionBase']); + $uqTypex = $this->getLocalPart($typeDef['extensionBase']); + if ($this->getNamespaceFromPrefix($nsx)) { + $nsx = $this->getNamespaceFromPrefix($nsx); + } + if ($typeDefx = $this->getTypeDef($uqTypex, $nsx)) { + $this->debug("serialize elements for extension base $nsx:$uqTypex"); + $xml .= $this->serializeComplexTypeElements($typeDefx, $value, $nsx, $uqTypex, $use, $encodingStyle); + } else { + $this->debug("extension base $nsx:$uqTypex is not a supported type"); + } + } + if (isset($typeDef['elements']) && is_array($typeDef['elements'])) { + $this->debug("in serializeComplexTypeElements, serialize elements for XML Schema type $ns:$uqType"); + if (is_array($value)) { + $xvalue = $value; + } elseif (is_object($value)) { + $xvalue = get_object_vars($value); + } else { + $this->debug("value is neither an array nor an object for XML Schema type $ns:$uqType"); + $xvalue = array(); + } + // toggle whether all elements are present - ideally should validate against schema + if (count($typeDef['elements']) != count($xvalue)){ + $optionals = true; + } + foreach ($typeDef['elements'] as $eName => $attrs) { + if (!isset($xvalue[$eName])) { + if (isset($attrs['default'])) { + $xvalue[$eName] = $attrs['default']; + $this->debug('use default value of ' . $xvalue[$eName] . ' for element ' . $eName); + } + } + // if user took advantage of a minOccurs=0, then only serialize named parameters + if (isset($optionals) + && (!isset($xvalue[$eName])) + && ( (!isset($attrs['nillable'])) || $attrs['nillable'] != 'true') + ){ + if (isset($attrs['minOccurs']) && $attrs['minOccurs'] <> '0') { + $this->debug("apparent error: no value provided for element $eName with minOccurs=" . $attrs['minOccurs']); + } + // do nothing + $this->debug("no value provided for complexType element $eName and element is not nillable, so serialize nothing"); + } else { + // get value + if (isset($xvalue[$eName])) { + $v = $xvalue[$eName]; + } else { + $v = null; + } + if (isset($attrs['form'])) { + $unqualified = ($attrs['form'] == 'unqualified'); + } else { + $unqualified = false; + } + if (isset($attrs['maxOccurs']) && ($attrs['maxOccurs'] == 'unbounded' || $attrs['maxOccurs'] > 1) && isset($v) && is_array($v) && $this->isArraySimpleOrStruct($v) == 'arraySimple') { + $vv = $v; + foreach ($vv as $k => $v) { + if (isset($attrs['type']) || isset($attrs['ref'])) { + // serialize schema-defined type + $xml .= $this->serializeType($eName, isset($attrs['type']) ? $attrs['type'] : $attrs['ref'], $v, $use, $encodingStyle, $unqualified); + } else { + // serialize generic type (can this ever really happen?) + $this->debug("calling serialize_val() for $v, $eName, false, false, false, false, $use"); + $xml .= $this->serialize_val($v, $eName, false, false, false, false, $use); + } + } + } else { + if (is_null($v) && isset($attrs['minOccurs']) && $attrs['minOccurs'] == '0') { + // do nothing + } elseif (is_null($v) && isset($attrs['nillable']) && $attrs['nillable'] == 'true') { + // TODO: serialize a nil correctly, but for now serialize schema-defined type + $xml .= $this->serializeType($eName, isset($attrs['type']) ? $attrs['type'] : $attrs['ref'], $v, $use, $encodingStyle, $unqualified); + } elseif (isset($attrs['type']) || isset($attrs['ref'])) { + // serialize schema-defined type + $xml .= $this->serializeType($eName, isset($attrs['type']) ? $attrs['type'] : $attrs['ref'], $v, $use, $encodingStyle, $unqualified); + } else { + // serialize generic type (can this ever really happen?) + $this->debug("calling serialize_val() for $v, $eName, false, false, false, false, $use"); + $xml .= $this->serialize_val($v, $eName, false, false, false, false, $use); + } + } + } + } + } else { + $this->debug("no elements to serialize for XML Schema type $ns:$uqType"); + } + return $xml; + } + + /** + * adds an XML Schema complex type to the WSDL types + * + * @param string $name + * @param string $typeClass (complexType|simpleType|attribute) + * @param string $phpType currently supported are array and struct (php assoc array) + * @param string $compositor (all|sequence|choice) + * @param string $restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array) + * @param array $elements e.g. array ( name => array(name=>'',type=>'') ) + * @param array $attrs e.g. array(array('ref'=>'SOAP-ENC:arrayType','wsdl:arrayType'=>'xsd:string[]')) + * @param string $arrayType as namespace:name (xsd:string) + * @see nusoap_xmlschema + * @access public + */ + function addComplexType($name,$typeClass='complexType',$phpType='array',$compositor='',$restrictionBase='',$elements=array(),$attrs=array(),$arrayType='') { + if (count($elements) > 0) { + $eElements = array(); + foreach($elements as $n => $e){ + // expand each element + $ee = array(); + foreach ($e as $k => $v) { + $k = strpos($k,':') ? $this->expandQname($k) : $k; + $v = strpos($v,':') ? $this->expandQname($v) : $v; + $ee[$k] = $v; + } + $eElements[$n] = $ee; + } + $elements = $eElements; + } + + if (count($attrs) > 0) { + foreach($attrs as $n => $a){ + // expand each attribute + foreach ($a as $k => $v) { + $k = strpos($k,':') ? $this->expandQname($k) : $k; + $v = strpos($v,':') ? $this->expandQname($v) : $v; + $aa[$k] = $v; + } + $eAttrs[$n] = $aa; + } + $attrs = $eAttrs; + } + + $restrictionBase = strpos($restrictionBase,':') ? $this->expandQname($restrictionBase) : $restrictionBase; + $arrayType = strpos($arrayType,':') ? $this->expandQname($arrayType) : $arrayType; + + $typens = isset($this->namespaces['types']) ? $this->namespaces['types'] : $this->namespaces['tns']; + $this->schemas[$typens][0]->addComplexType($name,$typeClass,$phpType,$compositor,$restrictionBase,$elements,$attrs,$arrayType); + } + + /** + * adds an XML Schema simple type to the WSDL types + * + * @param string $name + * @param string $restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array) + * @param string $typeClass (should always be simpleType) + * @param string $phpType (should always be scalar) + * @param array $enumeration array of values + * @see nusoap_xmlschema + * @access public + */ + function addSimpleType($name, $restrictionBase='', $typeClass='simpleType', $phpType='scalar', $enumeration=array()) { + $restrictionBase = strpos($restrictionBase,':') ? $this->expandQname($restrictionBase) : $restrictionBase; + + $typens = isset($this->namespaces['types']) ? $this->namespaces['types'] : $this->namespaces['tns']; + $this->schemas[$typens][0]->addSimpleType($name, $restrictionBase, $typeClass, $phpType, $enumeration); + } + + /** + * adds an element to the WSDL types + * + * @param array $attrs attributes that must include name and type + * @see nusoap_xmlschema + * @access public + */ + function addElement($attrs) { + $typens = isset($this->namespaces['types']) ? $this->namespaces['types'] : $this->namespaces['tns']; + $this->schemas[$typens][0]->addElement($attrs); + } + + /** + * register an operation with the server + * + * @param string $name operation (method) name + * @param array $in assoc array of input values: key = param name, value = param type + * @param array $out assoc array of output values: key = param name, value = param type + * @param string $namespace optional The namespace for the operation + * @param string $soapaction optional The soapaction for the operation + * @param string $style (rpc|document) optional The style for the operation Note: when 'document' is specified, parameter and return wrappers are created for you automatically + * @param string $use (encoded|literal) optional The use for the parameters (cannot mix right now) + * @param string $documentation optional The description to include in the WSDL + * @param string $encodingStyle optional (usually 'http://schemas.xmlsoap.org/soap/encoding/' for encoded) + * @access public + */ + function addOperation($name, $in = false, $out = false, $namespace = false, $soapaction = false, $style = 'rpc', $use = 'encoded', $documentation = '', $encodingStyle = ''){ + if ($use == 'encoded' && $encodingStyle == '') { + $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/'; + } + + if ($style == 'document') { + $elements = array(); + foreach ($in as $n => $t) { + $elements[$n] = array('name' => $n, 'type' => $t, 'form' => 'unqualified'); + } + $this->addComplexType($name . 'RequestType', 'complexType', 'struct', 'all', '', $elements); + $this->addElement(array('name' => $name, 'type' => $name . 'RequestType')); + $in = array('parameters' => 'tns:' . $name . '^'); + + $elements = array(); + foreach ($out as $n => $t) { + $elements[$n] = array('name' => $n, 'type' => $t, 'form' => 'unqualified'); + } + $this->addComplexType($name . 'ResponseType', 'complexType', 'struct', 'all', '', $elements); + $this->addElement(array('name' => $name . 'Response', 'type' => $name . 'ResponseType', 'form' => 'qualified')); + $out = array('parameters' => 'tns:' . $name . 'Response' . '^'); + } + + // get binding + $this->bindings[ $this->serviceName . 'Binding' ]['operations'][$name] = + array( + 'name' => $name, + 'binding' => $this->serviceName . 'Binding', + 'endpoint' => $this->endpoint, + 'soapAction' => $soapaction, + 'style' => $style, + 'input' => array( + 'use' => $use, + 'namespace' => $namespace, + 'encodingStyle' => $encodingStyle, + 'message' => $name . 'Request', + 'parts' => $in), + 'output' => array( + 'use' => $use, + 'namespace' => $namespace, + 'encodingStyle' => $encodingStyle, + 'message' => $name . 'Response', + 'parts' => $out), + 'namespace' => $namespace, + 'transport' => 'http://schemas.xmlsoap.org/soap/http', + 'documentation' => $documentation); + // add portTypes + // add messages + if($in) + { + foreach($in as $pName => $pType) + { + if(strpos($pType,':')) { + $pType = $this->getNamespaceFromPrefix($this->getPrefix($pType)).":".$this->getLocalPart($pType); + } + $this->messages[$name.'Request'][$pName] = $pType; + } + } else { + $this->messages[$name.'Request']= '0'; + } + if($out) + { + foreach($out as $pName => $pType) + { + if(strpos($pType,':')) { + $pType = $this->getNamespaceFromPrefix($this->getPrefix($pType)).":".$this->getLocalPart($pType); + } + $this->messages[$name.'Response'][$pName] = $pType; + } + } else { + $this->messages[$name.'Response']= '0'; + } + return true; + } +} + +?> \ No newline at end of file diff --git a/include/nusoap/class.wsdlcache.php b/include/nusoap/class.wsdlcache.php new file mode 100644 index 00000000..53d6ca34 --- /dev/null +++ b/include/nusoap/class.wsdlcache.php @@ -0,0 +1,251 @@ + + Bug 39085 - When loading the opposite search panel via ajax on the ListViews, call the index action instead of the ListView action to avoid touching pre-MVC code by accident. + +r56990 - 2010-06-16 13:05:36 -0700 (Wed, 16 Jun 2010) - kjing - snapshot "Mango" svn branch to a new one for GitHub sync + +r56989 - 2010-06-16 13:01:33 -0700 (Wed, 16 Jun 2010) - kjing - defunt "Mango" svn dev branch before github cutover + +r55980 - 2010-04-19 13:31:28 -0700 (Mon, 19 Apr 2010) - kjing - create Mango (6.1) based on windex + +r51719 - 2009-10-22 10:18:00 -0700 (Thu, 22 Oct 2009) - mitani - Converted to Build 3 tags and updated the build system + +r51634 - 2009-10-19 13:32:22 -0700 (Mon, 19 Oct 2009) - mitani - Windex is the branch for Sugar Sales 1.0 development + +r50375 - 2009-08-24 18:07:43 -0700 (Mon, 24 Aug 2009) - dwong - branch kobe2 from tokyo r50372 + +r42807 - 2008-12-29 11:16:59 -0800 (Mon, 29 Dec 2008) - dwong - Branch from trunk/sugarcrm r42806 to branches/tokyo/sugarcrm + +r13782 - 2006-06-06 10:58:55 -0700 (Tue, 06 Jun 2006) - majed - changes entry point code + +r11115 - 2006-01-17 14:54:45 -0800 (Tue, 17 Jan 2006) - majed - add entry point validation + +r8846 - 2005-10-31 11:01:12 -0800 (Mon, 31 Oct 2005) - majed - new version of nusoap + +r5462 - 2005-05-25 13:50:11 -0700 (Wed, 25 May 2005) - majed - upgraded nusoap to .6.9 + +r573 - 2004-09-04 13:03:32 -0700 (Sat, 04 Sep 2004) - sugarclint - undoing copyrights added in inadvertantly. --clint + +r546 - 2004-09-03 11:49:38 -0700 (Fri, 03 Sep 2004) - sugarmsi - removed echo count + +r354 - 2004-08-02 23:00:37 -0700 (Mon, 02 Aug 2004) - sugarjacob - Adding Soap + + +*/ + + +if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point'); + +/* +The NuSOAP project home is: +http://sourceforge.net/projects/nusoap/ + +The primary support for NuSOAP is the mailing list: +nusoap-general@lists.sourceforge.net +*/ + +/** +* caches instances of the wsdl class +* +* @author Scott Nichol +* @author Ingo Fischer + +* @access public +*/ +class nusoap_wsdlcache { + /** + * @var resource + * @access private + */ + var $fplock; + /** + * @var integer + * @access private + */ + var $cache_lifetime; + /** + * @var string + * @access private + */ + var $cache_dir; + /** + * @var string + * @access public + */ + var $debug_str = ''; + + /** + * constructor + * + * @param string $cache_dir directory for cache-files + * @param integer $cache_lifetime lifetime for caching-files in seconds or 0 for unlimited + * @access public + */ + function nusoap_wsdlcache($cache_dir='.', $cache_lifetime=0) { + $this->fplock = array(); + $this->cache_dir = $cache_dir != '' ? $cache_dir : '.'; + $this->cache_lifetime = $cache_lifetime; + } + + /** + * creates the filename used to cache a wsdl instance + * + * @param string $wsdl The URL of the wsdl instance + * @return string The filename used to cache the instance + * @access private + */ + function createFilename($wsdl) { + return $this->cache_dir.'/wsdlcache-' . md5($wsdl); + } + + /** + * adds debug data to the class level debug string + * + * @param string $string debug data + * @access private + */ + function debug($string){ + $this->debug_str .= get_class($this).": $string\n"; + } + + /** + * gets a wsdl instance from the cache + * + * @param string $wsdl The URL of the wsdl instance + * @return object wsdl The cached wsdl instance, null if the instance is not in the cache + * @access public + */ + function get($wsdl) { + $filename = $this->createFilename($wsdl); + if ($this->obtainMutex($filename, "r")) { + // check for expired WSDL that must be removed from the cache + if ($this->cache_lifetime > 0) { + if (file_exists($filename) && (time() - filemtime($filename) > $this->cache_lifetime)) { + unlink($filename); + $this->debug("Expired $wsdl ($filename) from cache"); + $this->releaseMutex($filename); + return null; + } + } + // see what there is to return + if (!file_exists($filename)) { + $this->debug("$wsdl ($filename) not in cache (1)"); + $this->releaseMutex($filename); + return null; + } + $fp = @fopen($filename, "r"); + if ($fp) { + $s = implode("", @file($filename)); + fclose($fp); + $this->debug("Got $wsdl ($filename) from cache"); + } else { + $s = null; + $this->debug("$wsdl ($filename) not in cache (2)"); + } + $this->releaseMutex($filename); + return (!is_null($s)) ? unserialize($s) : null; + } else { + $this->debug("Unable to obtain mutex for $filename in get"); + } + return null; + } + + /** + * obtains the local mutex + * + * @param string $filename The Filename of the Cache to lock + * @param string $mode The open-mode ("r" or "w") or the file - affects lock-mode + * @return boolean Lock successfully obtained ?! + * @access private + */ + function obtainMutex($filename, $mode) { + if (isset($this->fplock[md5($filename)])) { + $this->debug("Lock for $filename already exists"); + return false; + } + $this->fplock[md5($filename)] = fopen($filename.".lock", "w"); + if ($mode == "r") { + return flock($this->fplock[md5($filename)], LOCK_SH); + } else { + return flock($this->fplock[md5($filename)], LOCK_EX); + } + } + + /** + * adds a wsdl instance to the cache + * + * @param object wsdl $wsdl_instance The wsdl instance to add + * @return boolean WSDL successfully cached + * @access public + */ + function put($wsdl_instance) { + $filename = $this->createFilename($wsdl_instance->wsdl); + $s = serialize($wsdl_instance); + if ($this->obtainMutex($filename, "w")) { + $fp = fopen($filename, "w"); + if (! $fp) { + $this->debug("Cannot write $wsdl_instance->wsdl ($filename) in cache"); + $this->releaseMutex($filename); + return false; + } + fputs($fp, $s); + fclose($fp); + $this->debug("Put $wsdl_instance->wsdl ($filename) in cache"); + $this->releaseMutex($filename); + return true; + } else { + $this->debug("Unable to obtain mutex for $filename in put"); + } + return false; + } + + /** + * releases the local mutex + * + * @param string $filename The Filename of the Cache to lock + * @return boolean Lock successfully released + * @access private + */ + function releaseMutex($filename) { + $ret = flock($this->fplock[md5($filename)], LOCK_UN); + fclose($this->fplock[md5($filename)]); + unset($this->fplock[md5($filename)]); + if (! $ret) { + $this->debug("Not able to release lock for $filename"); + } + return $ret; + } + + /** + * removes a wsdl instance from the cache + * + * @param string $wsdl The URL of the wsdl instance + * @return boolean Whether there was an instance to remove + * @access public + */ + function remove($wsdl) { + $filename = $this->createFilename($wsdl); + if (!file_exists($filename)) { + $this->debug("$wsdl ($filename) not in cache to be removed"); + return false; + } + // ignore errors obtaining mutex + $this->obtainMutex($filename, "w"); + $ret = unlink($filename); + $this->debug("Removed ($ret) $wsdl ($filename) from cache"); + $this->releaseMutex($filename); + return $ret; + } +} + +/** + * For backward compatibility + */ +class wsdlcache extends nusoap_wsdlcache { +} +?> diff --git a/include/nusoap/class.xmlschema.php b/include/nusoap/class.xmlschema.php new file mode 100644 index 00000000..7bb9b6a6 --- /dev/null +++ b/include/nusoap/class.xmlschema.php @@ -0,0 +1,1019 @@ + + Bug 39085 - When loading the opposite search panel via ajax on the ListViews, call the index action instead of the ListView action to avoid touching pre-MVC code by accident. + +r56990 - 2010-06-16 13:05:36 -0700 (Wed, 16 Jun 2010) - kjing - snapshot "Mango" svn branch to a new one for GitHub sync + +r56989 - 2010-06-16 13:01:33 -0700 (Wed, 16 Jun 2010) - kjing - defunt "Mango" svn dev branch before github cutover + +r55980 - 2010-04-19 13:31:28 -0700 (Mon, 19 Apr 2010) - kjing - create Mango (6.1) based on windex + +r51719 - 2009-10-22 10:18:00 -0700 (Thu, 22 Oct 2009) - mitani - Converted to Build 3 tags and updated the build system + +r51634 - 2009-10-19 13:32:22 -0700 (Mon, 19 Oct 2009) - mitani - Windex is the branch for Sugar Sales 1.0 development + +r51443 - 2009-10-12 13:34:36 -0700 (Mon, 12 Oct 2009) - jmertic - Bug 33332 - Made application PHP 5.3 compliant with E_DEPRECATED warnings on by: +- Changing all ereg function to either preg or simple string based ones +- No more references to magic quotes. +- Change all the session_unregister() functions to just unset() the correct session variable instead. + +r50375 - 2009-08-24 18:07:43 -0700 (Mon, 24 Aug 2009) - dwong - branch kobe2 from tokyo r50372 + +r42807 - 2008-12-29 11:16:59 -0800 (Mon, 29 Dec 2008) - dwong - Branch from trunk/sugarcrm r42806 to branches/tokyo/sugarcrm + +r13782 - 2006-06-06 10:58:55 -0700 (Tue, 06 Jun 2006) - majed - changes entry point code + +r11115 - 2006-01-17 14:54:45 -0800 (Tue, 17 Jan 2006) - majed - add entry point validation + +r8846 - 2005-10-31 11:01:12 -0800 (Mon, 31 Oct 2005) - majed - new version of nusoap + +r5462 - 2005-05-25 13:50:11 -0700 (Wed, 25 May 2005) - majed - upgraded nusoap to .6.9 + +r573 - 2004-09-04 13:03:32 -0700 (Sat, 04 Sep 2004) - sugarclint - undoing copyrights added in inadvertantly. --clint + +r546 - 2004-09-03 11:49:38 -0700 (Fri, 03 Sep 2004) - sugarmsi - removed echo count + +r354 - 2004-08-02 23:00:37 -0700 (Mon, 02 Aug 2004) - sugarjacob - Adding Soap + + +*/ + + +if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point'); + + + + +/** +* parses an XML Schema, allows access to it's data, other utility methods. +* imperfect, no validation... yet, but quite functional. +* +* @author Dietrich Ayala +* @author Scott Nichol + +* @access public +*/ +class nusoap_xmlschema extends nusoap_base { + + // files + var $schema = ''; + var $xml = ''; + // namespaces + var $enclosingNamespaces; + // schema info + var $schemaInfo = array(); + var $schemaTargetNamespace = ''; + // types, elements, attributes defined by the schema + var $attributes = array(); + var $complexTypes = array(); + var $complexTypeStack = array(); + var $currentComplexType = null; + var $elements = array(); + var $elementStack = array(); + var $currentElement = null; + var $simpleTypes = array(); + var $simpleTypeStack = array(); + var $currentSimpleType = null; + // imports + var $imports = array(); + // parser vars + var $parser; + var $position = 0; + var $depth = 0; + var $depth_array = array(); + var $message = array(); + var $defaultNamespace = array(); + + /** + * constructor + * + * @param string $schema schema document URI + * @param string $xml xml document URI + * @param string $namespaces namespaces defined in enclosing XML + * @access public + */ + function nusoap_xmlschema($schema='',$xml='',$namespaces=array()){ + parent::nusoap_base(); + $this->debug('nusoap_xmlschema class instantiated, inside constructor'); + // files + $this->schema = $schema; + $this->xml = $xml; + + // namespaces + $this->enclosingNamespaces = $namespaces; + $this->namespaces = array_merge($this->namespaces, $namespaces); + + // parse schema file + if($schema != ''){ + $this->debug('initial schema file: '.$schema); + $this->parseFile($schema, 'schema'); + } + + // parse xml file + if($xml != ''){ + $this->debug('initial xml file: '.$xml); + $this->parseFile($xml, 'xml'); + } + + } + + /** + * parse an XML file + * + * @param string $xml path/URL to XML file + * @param string $type (schema | xml) + * @return boolean + * @access public + */ + function parseFile($xml,$type){ + // parse xml file + if($xml != ""){ + $xmlStr = @join("",@file($xml)); + if($xmlStr == ""){ + $msg = 'Error reading XML from '.$xml; + $this->setError($msg); + $this->debug($msg); + return false; + } else { + $this->debug("parsing $xml"); + $this->parseString($xmlStr,$type); + $this->debug("done parsing $xml"); + return true; + } + } + return false; + } + + /** + * parse an XML string + * + * @param string $xml path or URL + * @param string $type (schema|xml) + * @access private + */ + function parseString($xml,$type){ + // parse xml string + if($xml != ""){ + + // Create an XML parser. + $this->parser = xml_parser_create(); + // Set the options for parsing the XML data. + xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0); + + // Set the object for the parser. + xml_set_object($this->parser, $this); + + // Set the element handlers for the parser. + if($type == "schema"){ + xml_set_element_handler($this->parser, 'schemaStartElement','schemaEndElement'); + xml_set_character_data_handler($this->parser,'schemaCharacterData'); + } elseif($type == "xml"){ + xml_set_element_handler($this->parser, 'xmlStartElement','xmlEndElement'); + xml_set_character_data_handler($this->parser,'xmlCharacterData'); + } + + // Parse the XML file. + if(!xml_parse($this->parser,$xml,true)){ + // Display an error message. + $errstr = sprintf('XML error parsing XML schema on line %d: %s', + xml_get_current_line_number($this->parser), + xml_error_string(xml_get_error_code($this->parser)) + ); + $this->debug($errstr); + $this->debug("XML payload:\n" . $xml); + $this->setError($errstr); + } + + xml_parser_free($this->parser); + } else{ + $this->debug('no xml passed to parseString()!!'); + $this->setError('no xml passed to parseString()!!'); + } + } + + /** + * gets a type name for an unnamed type + * + * @param string Element name + * @return string A type name for an unnamed type + * @access private + */ + function CreateTypeName($ename) { + $scope = ''; + for ($i = 0; $i < count($this->complexTypeStack); $i++) { + $scope .= $this->complexTypeStack[$i] . '_'; + } + return $scope . $ename . '_ContainedType'; + } + + /** + * start-element handler + * + * @param string $parser XML parser object + * @param string $name element name + * @param string $attrs associative array of attributes + * @access private + */ + function schemaStartElement($parser, $name, $attrs) { + + // position in the total number of elements, starting from 0 + $pos = $this->position++; + $depth = $this->depth++; + // set self as current value for this depth + $this->depth_array[$depth] = $pos; + $this->message[$pos] = array('cdata' => ''); + if ($depth > 0) { + $this->defaultNamespace[$pos] = $this->defaultNamespace[$this->depth_array[$depth - 1]]; + } else { + $this->defaultNamespace[$pos] = false; + } + + // get element prefix + if($prefix = $this->getPrefix($name)){ + // get unqualified name + $name = $this->getLocalPart($name); + } else { + $prefix = ''; + } + + // loop thru attributes, expanding, and registering namespace declarations + if(count($attrs) > 0){ + foreach($attrs as $k => $v){ + // if ns declarations, add to class level array of valid namespaces + if(preg_match('/^xmlns/',$k)){ + //$this->xdebug("$k: $v"); + //$this->xdebug('ns_prefix: '.$this->getPrefix($k)); + if($ns_prefix = substr(strrchr($k,':'),1)){ + //$this->xdebug("Add namespace[$ns_prefix] = $v"); + $this->namespaces[$ns_prefix] = $v; + } else { + $this->defaultNamespace[$pos] = $v; + if (! $this->getPrefixFromNamespace($v)) { + $this->namespaces['ns'.(count($this->namespaces)+1)] = $v; + } + } + if($v == 'http://www.w3.org/2001/XMLSchema' || $v == 'http://www.w3.org/1999/XMLSchema' || $v == 'http://www.w3.org/2000/10/XMLSchema'){ + $this->XMLSchemaVersion = $v; + $this->namespaces['xsi'] = $v.'-instance'; + } + } + } + foreach($attrs as $k => $v){ + // expand each attribute + $k = strpos($k,':') ? $this->expandQname($k) : $k; + $v = strpos($v,':') ? $this->expandQname($v) : $v; + $eAttrs[$k] = $v; + } + $attrs = $eAttrs; + } else { + $attrs = array(); + } + // find status, register data + switch($name){ + case 'all': // (optional) compositor content for a complexType + case 'choice': + case 'group': + case 'sequence': + //$this->xdebug("compositor $name for currentComplexType: $this->currentComplexType and currentElement: $this->currentElement"); + $this->complexTypes[$this->currentComplexType]['compositor'] = $name; + //if($name == 'all' || $name == 'sequence'){ + // $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct'; + //} + break; + case 'attribute': // complexType attribute + //$this->xdebug("parsing attribute $attrs[name] $attrs[ref] of value: ".$attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']); + $this->xdebug("parsing attribute:"); + $this->appendDebug($this->varDump($attrs)); + if (!isset($attrs['form'])) { + // TODO: handle globals + $attrs['form'] = $this->schemaInfo['attributeFormDefault']; + } + if (isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])) { + $v = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']; + if (!strpos($v, ':')) { + // no namespace in arrayType attribute value... + if ($this->defaultNamespace[$pos]) { + // ...so use the default + $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'] = $this->defaultNamespace[$pos] . ':' . $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']; + } + } + } + if(isset($attrs['name'])){ + $this->attributes[$attrs['name']] = $attrs; + $aname = $attrs['name']; + } elseif(isset($attrs['ref']) && $attrs['ref'] == 'http://schemas.xmlsoap.org/soap/encoding/:arrayType'){ + if (isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])) { + $aname = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']; + } else { + $aname = ''; + } + } elseif(isset($attrs['ref'])){ + $aname = $attrs['ref']; + $this->attributes[$attrs['ref']] = $attrs; + } + + if($this->currentComplexType){ // This should *always* be + $this->complexTypes[$this->currentComplexType]['attrs'][$aname] = $attrs; + } + // arrayType attribute + if(isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']) || $this->getLocalPart($aname) == 'arrayType'){ + $this->complexTypes[$this->currentComplexType]['phpType'] = 'array'; + $prefix = $this->getPrefix($aname); + if(isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])){ + $v = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']; + } else { + $v = ''; + } + if(strpos($v,'[,]')){ + $this->complexTypes[$this->currentComplexType]['multidimensional'] = true; + } + $v = substr($v,0,strpos($v,'[')); // clip the [] + if(!strpos($v,':') && isset($this->typemap[$this->XMLSchemaVersion][$v])){ + $v = $this->XMLSchemaVersion.':'.$v; + } + $this->complexTypes[$this->currentComplexType]['arrayType'] = $v; + } + break; + case 'complexContent': // (optional) content for a complexType + $this->xdebug("do nothing for element $name"); + break; + case 'complexType': + array_push($this->complexTypeStack, $this->currentComplexType); + if(isset($attrs['name'])){ + // TODO: what is the scope of named complexTypes that appear + // nested within other c complexTypes? + $this->xdebug('processing named complexType '.$attrs['name']); + //$this->currentElement = false; + $this->currentComplexType = $attrs['name']; + $this->complexTypes[$this->currentComplexType] = $attrs; + $this->complexTypes[$this->currentComplexType]['typeClass'] = 'complexType'; + // This is for constructs like + // + // + // + // + // + if(isset($attrs['base']) && preg_match('/:Array$/',$attrs['base'])){ + $this->xdebug('complexType is unusual array'); + $this->complexTypes[$this->currentComplexType]['phpType'] = 'array'; + } else { + $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct'; + } + } else { + $name = $this->CreateTypeName($this->currentElement); + $this->xdebug('processing unnamed complexType for element ' . $this->currentElement . ' named ' . $name); + $this->currentComplexType = $name; + //$this->currentElement = false; + $this->complexTypes[$this->currentComplexType] = $attrs; + $this->complexTypes[$this->currentComplexType]['typeClass'] = 'complexType'; + // This is for constructs like + // + // + // + // + // + if(isset($attrs['base']) && preg_match('/:Array$/',$attrs['base'])){ + $this->xdebug('complexType is unusual array'); + $this->complexTypes[$this->currentComplexType]['phpType'] = 'array'; + } else { + $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct'; + } + } + $this->complexTypes[$this->currentComplexType]['simpleContent'] = 'false'; + break; + case 'element': + array_push($this->elementStack, $this->currentElement); + if (!isset($attrs['form'])) { + if ($this->currentComplexType) { + $attrs['form'] = $this->schemaInfo['elementFormDefault']; + } else { + // global + $attrs['form'] = 'qualified'; + } + } + if(isset($attrs['type'])){ + $this->xdebug("processing typed element ".$attrs['name']." of type ".$attrs['type']); + if (! $this->getPrefix($attrs['type'])) { + if ($this->defaultNamespace[$pos]) { + $attrs['type'] = $this->defaultNamespace[$pos] . ':' . $attrs['type']; + $this->xdebug('used default namespace to make type ' . $attrs['type']); + } + } + // This is for constructs like + // + // + // + // + // + if ($this->currentComplexType && $this->complexTypes[$this->currentComplexType]['phpType'] == 'array') { + $this->xdebug('arrayType for unusual array is ' . $attrs['type']); + $this->complexTypes[$this->currentComplexType]['arrayType'] = $attrs['type']; + } + $this->currentElement = $attrs['name']; + $ename = $attrs['name']; + } elseif(isset($attrs['ref'])){ + $this->xdebug("processing element as ref to ".$attrs['ref']); + $this->currentElement = "ref to ".$attrs['ref']; + $ename = $this->getLocalPart($attrs['ref']); + } else { + $type = $this->CreateTypeName($this->currentComplexType . '_' . $attrs['name']); + $this->xdebug("processing untyped element " . $attrs['name'] . ' type ' . $type); + $this->currentElement = $attrs['name']; + $attrs['type'] = $this->schemaTargetNamespace . ':' . $type; + $ename = $attrs['name']; + } + if (isset($ename) && $this->currentComplexType) { + $this->xdebug("add element $ename to complexType $this->currentComplexType"); + $this->complexTypes[$this->currentComplexType]['elements'][$ename] = $attrs; + } elseif (!isset($attrs['ref'])) { + $this->xdebug("add element $ename to elements array"); + $this->elements[ $attrs['name'] ] = $attrs; + $this->elements[ $attrs['name'] ]['typeClass'] = 'element'; + } + break; + case 'enumeration': // restriction value list member + $this->xdebug('enumeration ' . $attrs['value']); + if ($this->currentSimpleType) { + $this->simpleTypes[$this->currentSimpleType]['enumeration'][] = $attrs['value']; + } elseif ($this->currentComplexType) { + $this->complexTypes[$this->currentComplexType]['enumeration'][] = $attrs['value']; + } + break; + case 'extension': // simpleContent or complexContent type extension + $this->xdebug('extension ' . $attrs['base']); + if ($this->currentComplexType) { + $ns = $this->getPrefix($attrs['base']); + if ($ns == '') { + $this->complexTypes[$this->currentComplexType]['extensionBase'] = $this->schemaTargetNamespace . ':' . $attrs['base']; + } else { + $this->complexTypes[$this->currentComplexType]['extensionBase'] = $attrs['base']; + } + } else { + $this->xdebug('no current complexType to set extensionBase'); + } + break; + case 'import': + if (isset($attrs['schemaLocation'])) { + $this->xdebug('import namespace ' . $attrs['namespace'] . ' from ' . $attrs['schemaLocation']); + $this->imports[$attrs['namespace']][] = array('location' => $attrs['schemaLocation'], 'loaded' => false); + } else { + $this->xdebug('import namespace ' . $attrs['namespace']); + $this->imports[$attrs['namespace']][] = array('location' => '', 'loaded' => true); + if (! $this->getPrefixFromNamespace($attrs['namespace'])) { + $this->namespaces['ns'.(count($this->namespaces)+1)] = $attrs['namespace']; + } + } + break; + case 'include': + if (isset($attrs['schemaLocation'])) { + $this->xdebug('include into namespace ' . $this->schemaTargetNamespace . ' from ' . $attrs['schemaLocation']); + $this->imports[$this->schemaTargetNamespace][] = array('location' => $attrs['schemaLocation'], 'loaded' => false); + } else { + $this->xdebug('ignoring invalid XML Schema construct: include without schemaLocation attribute'); + } + break; + case 'list': // simpleType value list + $this->xdebug("do nothing for element $name"); + break; + case 'restriction': // simpleType, simpleContent or complexContent value restriction + $this->xdebug('restriction ' . $attrs['base']); + if($this->currentSimpleType){ + $this->simpleTypes[$this->currentSimpleType]['type'] = $attrs['base']; + } elseif($this->currentComplexType){ + $this->complexTypes[$this->currentComplexType]['restrictionBase'] = $attrs['base']; + if(strstr($attrs['base'],':') == ':Array'){ + $this->complexTypes[$this->currentComplexType]['phpType'] = 'array'; + } + } + break; + case 'schema': + $this->schemaInfo = $attrs; + $this->schemaInfo['schemaVersion'] = $this->getNamespaceFromPrefix($prefix); + if (isset($attrs['targetNamespace'])) { + $this->schemaTargetNamespace = $attrs['targetNamespace']; + } + if (!isset($attrs['elementFormDefault'])) { + $this->schemaInfo['elementFormDefault'] = 'unqualified'; + } + if (!isset($attrs['attributeFormDefault'])) { + $this->schemaInfo['attributeFormDefault'] = 'unqualified'; + } + break; + case 'simpleContent': // (optional) content for a complexType + if ($this->currentComplexType) { // This should *always* be + $this->complexTypes[$this->currentComplexType]['simpleContent'] = 'true'; + } else { + $this->xdebug("do nothing for element $name because there is no current complexType"); + } + break; + case 'simpleType': + array_push($this->simpleTypeStack, $this->currentSimpleType); + if(isset($attrs['name'])){ + $this->xdebug("processing simpleType for name " . $attrs['name']); + $this->currentSimpleType = $attrs['name']; + $this->simpleTypes[ $attrs['name'] ] = $attrs; + $this->simpleTypes[ $attrs['name'] ]['typeClass'] = 'simpleType'; + $this->simpleTypes[ $attrs['name'] ]['phpType'] = 'scalar'; + } else { + $name = $this->CreateTypeName($this->currentComplexType . '_' . $this->currentElement); + $this->xdebug('processing unnamed simpleType for element ' . $this->currentElement . ' named ' . $name); + $this->currentSimpleType = $name; + //$this->currentElement = false; + $this->simpleTypes[$this->currentSimpleType] = $attrs; + $this->simpleTypes[$this->currentSimpleType]['phpType'] = 'scalar'; + } + break; + case 'union': // simpleType type list + $this->xdebug("do nothing for element $name"); + break; + default: + $this->xdebug("do not have any logic to process element $name"); + } + } + + /** + * end-element handler + * + * @param string $parser XML parser object + * @param string $name element name + * @access private + */ + function schemaEndElement($parser, $name) { + // bring depth down a notch + $this->depth--; + // position of current element is equal to the last value left in depth_array for my depth + if(isset($this->depth_array[$this->depth])){ + $pos = $this->depth_array[$this->depth]; + } + // get element prefix + if ($prefix = $this->getPrefix($name)){ + // get unqualified name + $name = $this->getLocalPart($name); + } else { + $prefix = ''; + } + // move on... + if($name == 'complexType'){ + $this->xdebug('done processing complexType ' . ($this->currentComplexType ? $this->currentComplexType : '(unknown)')); + $this->xdebug($this->varDump($this->complexTypes[$this->currentComplexType])); + $this->currentComplexType = array_pop($this->complexTypeStack); + //$this->currentElement = false; + } + if($name == 'element'){ + $this->xdebug('done processing element ' . ($this->currentElement ? $this->currentElement : '(unknown)')); + $this->currentElement = array_pop($this->elementStack); + } + if($name == 'simpleType'){ + $this->xdebug('done processing simpleType ' . ($this->currentSimpleType ? $this->currentSimpleType : '(unknown)')); + $this->xdebug($this->varDump($this->simpleTypes[$this->currentSimpleType])); + $this->currentSimpleType = array_pop($this->simpleTypeStack); + } + } + + /** + * element content handler + * + * @param string $parser XML parser object + * @param string $data element content + * @access private + */ + function schemaCharacterData($parser, $data){ + $pos = $this->depth_array[$this->depth - 1]; + $this->message[$pos]['cdata'] .= $data; + } + + /** + * serialize the schema + * + * @access public + */ + function serializeSchema(){ + + $schemaPrefix = $this->getPrefixFromNamespace($this->XMLSchemaVersion); + $xml = ''; + // imports + if (sizeof($this->imports) > 0) { + foreach($this->imports as $ns => $list) { + foreach ($list as $ii) { + if ($ii['location'] != '') { + $xml .= " <$schemaPrefix:import location=\"" . $ii['location'] . '" namespace="' . $ns . "\" />\n"; + } else { + $xml .= " <$schemaPrefix:import namespace=\"" . $ns . "\" />\n"; + } + } + } + } + // complex types + foreach($this->complexTypes as $typeName => $attrs){ + $contentStr = ''; + // serialize child elements + if(isset($attrs['elements']) && (count($attrs['elements']) > 0)){ + foreach($attrs['elements'] as $element => $eParts){ + if(isset($eParts['ref'])){ + $contentStr .= " <$schemaPrefix:element ref=\"$element\"/>\n"; + } else { + $contentStr .= " <$schemaPrefix:element name=\"$element\" type=\"" . $this->contractQName($eParts['type']) . "\""; + foreach ($eParts as $aName => $aValue) { + // handle, e.g., abstract, default, form, minOccurs, maxOccurs, nillable + if ($aName != 'name' && $aName != 'type') { + $contentStr .= " $aName=\"$aValue\""; + } + } + $contentStr .= "/>\n"; + } + } + // compositor wraps elements + if (isset($attrs['compositor']) && ($attrs['compositor'] != '')) { + $contentStr = " <$schemaPrefix:$attrs[compositor]>\n".$contentStr." \n"; + } + } + // attributes + if(isset($attrs['attrs']) && (count($attrs['attrs']) >= 1)){ + foreach($attrs['attrs'] as $attr => $aParts){ + $contentStr .= " <$schemaPrefix:attribute"; + foreach ($aParts as $a => $v) { + if ($a == 'ref' || $a == 'type') { + $contentStr .= " $a=\"".$this->contractQName($v).'"'; + } elseif ($a == 'http://schemas.xmlsoap.org/wsdl/:arrayType') { + $this->usedNamespaces['wsdl'] = $this->namespaces['wsdl']; + $contentStr .= ' wsdl:arrayType="'.$this->contractQName($v).'"'; + } else { + $contentStr .= " $a=\"$v\""; + } + } + $contentStr .= "/>\n"; + } + } + // if restriction + if (isset($attrs['restrictionBase']) && $attrs['restrictionBase'] != ''){ + $contentStr = " <$schemaPrefix:restriction base=\"".$this->contractQName($attrs['restrictionBase'])."\">\n".$contentStr." \n"; + // complex or simple content + if ((isset($attrs['elements']) && count($attrs['elements']) > 0) || (isset($attrs['attrs']) && count($attrs['attrs']) > 0)){ + $contentStr = " <$schemaPrefix:complexContent>\n".$contentStr." \n"; + } + } + // finalize complex type + if($contentStr != ''){ + $contentStr = " <$schemaPrefix:complexType name=\"$typeName\">\n".$contentStr." \n"; + } else { + $contentStr = " <$schemaPrefix:complexType name=\"$typeName\"/>\n"; + } + $xml .= $contentStr; + } + // simple types + if(isset($this->simpleTypes) && count($this->simpleTypes) > 0){ + foreach($this->simpleTypes as $typeName => $eParts){ + $xml .= " <$schemaPrefix:simpleType name=\"$typeName\">\n <$schemaPrefix:restriction base=\"".$this->contractQName($eParts['type'])."\">\n"; + if (isset($eParts['enumeration'])) { + foreach ($eParts['enumeration'] as $e) { + $xml .= " <$schemaPrefix:enumeration value=\"$e\"/>\n"; + } + } + $xml .= " \n "; + } + } + // elements + if(isset($this->elements) && count($this->elements) > 0){ + foreach($this->elements as $element => $eParts){ + $xml .= " <$schemaPrefix:element name=\"$element\" type=\"".$this->contractQName($eParts['type'])."\"/>\n"; + } + } + // attributes + if(isset($this->attributes) && count($this->attributes) > 0){ + foreach($this->attributes as $attr => $aParts){ + $xml .= " <$schemaPrefix:attribute name=\"$attr\" type=\"".$this->contractQName($aParts['type'])."\"\n/>"; + } + } + // finish 'er up + $attr = ''; + foreach ($this->schemaInfo as $k => $v) { + if ($k == 'elementFormDefault' || $k == 'attributeFormDefault') { + $attr .= " $k=\"$v\""; + } + } + $el = "<$schemaPrefix:schema$attr targetNamespace=\"$this->schemaTargetNamespace\"\n"; + foreach (array_diff($this->usedNamespaces, $this->enclosingNamespaces) as $nsp => $ns) { + $el .= " xmlns:$nsp=\"$ns\""; + } + $xml = $el . ">\n".$xml."\n"; + return $xml; + } + + /** + * adds debug data to the clas level debug string + * + * @param string $string debug data + * @access private + */ + function xdebug($string){ + $this->debug('<' . $this->schemaTargetNamespace . '> '.$string); + } + + /** + * get the PHP type of a user defined type in the schema + * PHP type is kind of a misnomer since it actually returns 'struct' for assoc. arrays + * returns false if no type exists, or not w/ the given namespace + * else returns a string that is either a native php type, or 'struct' + * + * @param string $type name of defined type + * @param string $ns namespace of type + * @return mixed + * @access public + * @deprecated + */ + function getPHPType($type,$ns){ + if(isset($this->typemap[$ns][$type])){ + //print "found type '$type' and ns $ns in typemap
    "; + return $this->typemap[$ns][$type]; + } elseif(isset($this->complexTypes[$type])){ + //print "getting type '$type' and ns $ns from complexTypes array
    "; + return $this->complexTypes[$type]['phpType']; + } + return false; + } + + /** + * returns an associative array of information about a given type + * returns false if no type exists by the given name + * + * For a complexType typeDef = array( + * 'restrictionBase' => '', + * 'phpType' => '', + * 'compositor' => '(sequence|all)', + * 'elements' => array(), // refs to elements array + * 'attrs' => array() // refs to attributes array + * ... and so on (see addComplexType) + * ) + * + * For simpleType or element, the array has different keys. + * + * @param string $type + * @return mixed + * @access public + * @see addComplexType + * @see addSimpleType + * @see addElement + */ + function getTypeDef($type){ + //$this->debug("in getTypeDef for type $type"); + if (substr($type, -1) == '^') { + $is_element = 1; + $type = substr($type, 0, -1); + } else { + $is_element = 0; + } + + if((! $is_element) && isset($this->complexTypes[$type])){ + $this->xdebug("in getTypeDef, found complexType $type"); + return $this->complexTypes[$type]; + } elseif((! $is_element) && isset($this->simpleTypes[$type])){ + $this->xdebug("in getTypeDef, found simpleType $type"); + if (!isset($this->simpleTypes[$type]['phpType'])) { + // get info for type to tack onto the simple type + // TODO: can this ever really apply (i.e. what is a simpleType really?) + $uqType = substr($this->simpleTypes[$type]['type'], strrpos($this->simpleTypes[$type]['type'], ':') + 1); + $ns = substr($this->simpleTypes[$type]['type'], 0, strrpos($this->simpleTypes[$type]['type'], ':')); + $etype = $this->getTypeDef($uqType); + if ($etype) { + $this->xdebug("in getTypeDef, found type for simpleType $type:"); + $this->xdebug($this->varDump($etype)); + if (isset($etype['phpType'])) { + $this->simpleTypes[$type]['phpType'] = $etype['phpType']; + } + if (isset($etype['elements'])) { + $this->simpleTypes[$type]['elements'] = $etype['elements']; + } + } + } + return $this->simpleTypes[$type]; + } elseif(isset($this->elements[$type])){ + $this->xdebug("in getTypeDef, found element $type"); + if (!isset($this->elements[$type]['phpType'])) { + // get info for type to tack onto the element + $uqType = substr($this->elements[$type]['type'], strrpos($this->elements[$type]['type'], ':') + 1); + $ns = substr($this->elements[$type]['type'], 0, strrpos($this->elements[$type]['type'], ':')); + $etype = $this->getTypeDef($uqType); + if ($etype) { + $this->xdebug("in getTypeDef, found type for element $type:"); + $this->xdebug($this->varDump($etype)); + if (isset($etype['phpType'])) { + $this->elements[$type]['phpType'] = $etype['phpType']; + } + if (isset($etype['elements'])) { + $this->elements[$type]['elements'] = $etype['elements']; + } + if (isset($etype['extensionBase'])) { + $this->elements[$type]['extensionBase'] = $etype['extensionBase']; + } + } elseif ($ns == 'http://www.w3.org/2001/XMLSchema') { + $this->xdebug("in getTypeDef, element $type is an XSD type"); + $this->elements[$type]['phpType'] = 'scalar'; + } + } + return $this->elements[$type]; + } elseif(isset($this->attributes[$type])){ + $this->xdebug("in getTypeDef, found attribute $type"); + return $this->attributes[$type]; + } elseif (preg_match('/_ContainedType$/', $type)) { + $this->xdebug("in getTypeDef, have an untyped element $type"); + $typeDef['typeClass'] = 'simpleType'; + $typeDef['phpType'] = 'scalar'; + $typeDef['type'] = 'http://www.w3.org/2001/XMLSchema:string'; + return $typeDef; + } + $this->xdebug("in getTypeDef, did not find $type"); + return false; + } + + /** + * returns a sample serialization of a given type, or false if no type by the given name + * + * @param string $type name of type + * @return mixed + * @access public + * @deprecated + */ + function serializeTypeDef($type){ + //print "in sTD() for type $type
    "; + if($typeDef = $this->getTypeDef($type)){ + $str .= '<'.$type; + if(is_array($typeDef['attrs'])){ + foreach($typeDef['attrs'] as $attName => $data){ + $str .= " $attName=\"{type = ".$data['type']."}\""; + } + } + $str .= " xmlns=\"".$this->schema['targetNamespace']."\""; + if(count($typeDef['elements']) > 0){ + $str .= ">"; + foreach($typeDef['elements'] as $element => $eData){ + $str .= $this->serializeTypeDef($element); + } + $str .= ""; + } elseif($typeDef['typeClass'] == 'element') { + $str .= ">"; + } else { + $str .= "/>"; + } + return $str; + } + return false; + } + + /** + * returns HTML form elements that allow a user + * to enter values for creating an instance of the given type. + * + * @param string $name name for type instance + * @param string $type name of type + * @return string + * @access public + * @deprecated + */ + function typeToForm($name,$type){ + // get typedef + if($typeDef = $this->getTypeDef($type)){ + // if struct + if($typeDef['phpType'] == 'struct'){ + $buffer .= ''; + foreach($typeDef['elements'] as $child => $childDef){ + $buffer .= " + + "; + } + $buffer .= '
    $childDef[name] (type: ".$this->getLocalPart($childDef['type'])."):
    '; + // if array + } elseif($typeDef['phpType'] == 'array'){ + $buffer .= ''; + for($i=0;$i < 3; $i++){ + $buffer .= " + + "; + } + $buffer .= '
    array item (type: $typeDef[arrayType]):
    '; + // if scalar + } else { + $buffer .= ""; + } + } else { + $buffer .= ""; + } + return $buffer; + } + + /** + * adds a complex type to the schema + * + * example: array + * + * addType( + * 'ArrayOfstring', + * 'complexType', + * 'array', + * '', + * 'SOAP-ENC:Array', + * array('ref'=>'SOAP-ENC:arrayType','wsdl:arrayType'=>'string[]'), + * 'xsd:string' + * ); + * + * example: PHP associative array ( SOAP Struct ) + * + * addType( + * 'SOAPStruct', + * 'complexType', + * 'struct', + * 'all', + * array('myVar'=> array('name'=>'myVar','type'=>'string') + * ); + * + * @param name + * @param typeClass (complexType|simpleType|attribute) + * @param phpType: currently supported are array and struct (php assoc array) + * @param compositor (all|sequence|choice) + * @param restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array) + * @param elements = array ( name = array(name=>'',type=>'') ) + * @param attrs = array( + * array( + * 'ref' => "http://schemas.xmlsoap.org/soap/encoding/:arrayType", + * "http://schemas.xmlsoap.org/wsdl/:arrayType" => "string[]" + * ) + * ) + * @param arrayType: namespace:name (http://www.w3.org/2001/XMLSchema:string) + * @access public + * @see getTypeDef + */ + function addComplexType($name,$typeClass='complexType',$phpType='array',$compositor='',$restrictionBase='',$elements=array(),$attrs=array(),$arrayType=''){ + $this->complexTypes[$name] = array( + 'name' => $name, + 'typeClass' => $typeClass, + 'phpType' => $phpType, + 'compositor'=> $compositor, + 'restrictionBase' => $restrictionBase, + 'elements' => $elements, + 'attrs' => $attrs, + 'arrayType' => $arrayType + ); + + $this->xdebug("addComplexType $name:"); + $this->appendDebug($this->varDump($this->complexTypes[$name])); + } + + /** + * adds a simple type to the schema + * + * @param string $name + * @param string $restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array) + * @param string $typeClass (should always be simpleType) + * @param string $phpType (should always be scalar) + * @param array $enumeration array of values + * @access public + * @see nusoap_xmlschema + * @see getTypeDef + */ + function addSimpleType($name, $restrictionBase='', $typeClass='simpleType', $phpType='scalar', $enumeration=array()) { + $this->simpleTypes[$name] = array( + 'name' => $name, + 'typeClass' => $typeClass, + 'phpType' => $phpType, + 'type' => $restrictionBase, + 'enumeration' => $enumeration + ); + + $this->xdebug("addSimpleType $name:"); + $this->appendDebug($this->varDump($this->simpleTypes[$name])); + } + + /** + * adds an element to the schema + * + * @param array $attrs attributes that must include name and type + * @see nusoap_xmlschema + * @access public + */ + function addElement($attrs) { + if (! $this->getPrefix($attrs['type'])) { + $attrs['type'] = $this->schemaTargetNamespace . ':' . $attrs['type']; + } + $this->elements[ $attrs['name'] ] = $attrs; + $this->elements[ $attrs['name'] ]['typeClass'] = 'element'; + + $this->xdebug("addElement " . $attrs['name']); + $this->appendDebug($this->varDump($this->elements[ $attrs['name'] ])); + } +} + +/** + * Backward compatibility + */ +class XMLSchema extends nusoap_xmlschema { +} + + +?> \ No newline at end of file diff --git a/include/nusoap/license.txt b/include/nusoap/license.txt new file mode 100644 index 00000000..0ca1c2ff --- /dev/null +++ b/include/nusoap/license.txt @@ -0,0 +1,531 @@ +NuSOAP - Web Services Toolkit for PHP + +Copyright (c) 2002 NuSphere Corporation + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License 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. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +If you have any questions or comments, please email: + +Dietrich Ayala +dietrich@ganx4.com +http://dietrich.ganx4.com/nusoap + +NuSphere Corporation +http://www.nusphere.com + + + + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +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 and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, 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 library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete 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 distribute a copy of this License along with the +Library. + + 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 Library or any portion +of it, thus forming a work based on the Library, 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) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +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 Library, 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 Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you 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. + + If distribution of 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 satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be 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. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library 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. + + 9. 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 Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +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 with +this License. + + 11. 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 Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library 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 Library. + +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. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library 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. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser 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 Library +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 Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +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 + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "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 +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. 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 LIBRARY 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 +LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), 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 Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. 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 library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License 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. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/include/nusoap/nusoap.php b/include/nusoap/nusoap.php new file mode 100644 index 00000000..fbf514e9 --- /dev/null +++ b/include/nusoap/nusoap.php @@ -0,0 +1,10058 @@ + +Date: Thu Feb 17 18:09:12 2011 -0800 + + bug 34897 - remove characters that aren't valid in XML + +commit 1767411d701b8216cc5e043888fd1337e2eca315 +Author: Stanislav Malyshev +Date: Fri Jan 7 12:19:10 2011 -0800 + + conserve memory when no debug is enabled + +commit 843510ebf455368865302a05b9d5041815a32c23 +Author: John Mertic +Date: Wed Nov 17 13:18:09 2010 -0500 + + Bug 40716 - Fix WSDL validation problem by removing hardcoded schemaLocation attribute for the tag. + +commit 2bd12c02078f3e291bd9c1e76179a144c788ce97 +Author: Collin Lee +Date: Fri Oct 22 16:37:42 2010 -0400 + + Bug: 39937 + + We traced the error to a combination of the new Hoovers' WSDL + the nusoapclient code that winds up improperly encoding the parameter elem +ents (this is because the namespace specified for the soap call did not match that declared in the WSDL). Made changes to nusoap.php so that w +e may manually set a payload XML portion that will not apply the namespace encoding to the parameters. Fixed unit tests to reflect the changes + and also re-enabled those for Hoovers that were marked skipped. + +r58622 - 2010-10-22 18:18:59 -0700 (Fri, 22 Oct 2010) - engsvnbuild - Author: lam + bug 40066 + +r58361 - 2010-09-29 16:59:02 -0700 (Wed, 29 Sep 2010) - kjing - Author: Jenny Gonsalves + Merging with maint_6_0_1 (svn merge -r 58250:58342) + +r57813 - 2010-08-19 10:34:44 -0700 (Thu, 19 Aug 2010) - kjing - Author: John Mertic + Bug 39085 - When loading the opposite search panel via ajax on the ListViews, call the index action instead of the ListView action to avoid touching pre-MVC code by accident. + +r57707 - 2010-08-10 12:26:13 -0700 (Tue, 10 Aug 2010) - kjing - Author: Stanislav Malyshev + fix SOAP calls with no parameters + +r56990 - 2010-06-16 13:05:36 -0700 (Wed, 16 Jun 2010) - kjing - snapshot "Mango" svn branch to a new one for GitHub sync + +r56989 - 2010-06-16 13:01:33 -0700 (Wed, 16 Jun 2010) - kjing - defunt "Mango" svn dev branch before github cutover + +r55980 - 2010-04-19 13:31:28 -0700 (Mon, 19 Apr 2010) - kjing - create Mango (6.1) based on windex + +r51719 - 2009-10-22 10:18:00 -0700 (Thu, 22 Oct 2009) - mitani - Converted to Build 3 tags and updated the build system + +r51634 - 2009-10-19 13:32:22 -0700 (Mon, 19 Oct 2009) - mitani - Windex is the branch for Sugar Sales 1.0 development + +r51508 - 2009-10-14 07:40:23 -0700 (Wed, 14 Oct 2009) - jmertic - More fallout fixes from the PHP 5.3 ereg to preg changes. + +r51455 - 2009-10-13 07:56:48 -0700 (Tue, 13 Oct 2009) - jmertic - Bug 33202 - Enable install of SugarCRM on PHP 5.3.0, asserting that the minimum supported version is PHP 5.2.x. + +r51443 - 2009-10-12 13:34:36 -0700 (Mon, 12 Oct 2009) - jmertic - Bug 33332 - Made application PHP 5.3 compliant with E_DEPRECATED warnings on by: +- Changing all ereg function to either preg or simple string based ones +- No more references to magic quotes. +- Change all the session_unregister() functions to just unset() the correct session variable instead. + +r50375 - 2009-08-24 18:07:43 -0700 (Mon, 24 Aug 2009) - dwong - branch kobe2 from tokyo r50372 + +r45763 - 2009-04-01 12:16:18 -0700 (Wed, 01 Apr 2009) - majed - Removed half of the require_once and include_onces in the product that were redundant or could be handled easily by the auto loader + +r45680 - 2009-03-30 14:34:35 -0700 (Mon, 30 Mar 2009) - Samir Gandhi - modifeid serializeSchema to generate WS-I compliant WSDL + +r42807 - 2008-12-29 11:16:59 -0800 (Mon, 29 Dec 2008) - dwong - Branch from trunk/sugarcrm r42806 to branches/tokyo/sugarcrm + +r42645 - 2008-12-18 13:41:08 -0800 (Thu, 18 Dec 2008) - awu - merging maint_5_2_0 rev41336:HEAD to trunk + +r41647 - 2008-11-11 17:44:30 -0800 (Tue, 11 Nov 2008) - majed - Fixes a few bugs + +r41596 - 2008-11-10 19:20:04 -0800 (Mon, 10 Nov 2008) - Samir Gandhi - modified to set $method in the code + +r41558 - 2008-11-10 14:35:34 -0800 (Mon, 10 Nov 2008) - majed - changes nusoap to allow for registering classes + +r39619 - 2008-09-09 13:41:34 -0700 (Tue, 09 Sep 2008) - jmertic - Bug 24827 - Remove all instances where we return a new object and assign it by reference, since this is deprecated in PHP 5 and emits E_DEPRECATED errors in PHP 5.3. +Touched: +- data/SugarBean.php +- include/domit/php_http_client_generic.php +- include/domit/php_http_connector.php +- include/domit/testing_domit.php +- include/domit/xml_domit_getelementsbypath.php +- include/domit/xml_domit_lite_parser.php +- include/domit/xml_domit_nodemaps.php +- include/domit/xml_domit_parser.php +- include/domit/xml_domit_shared.php +- include/generic/SugarWidgets/SugarWidgetField.php +- include/generic/SugarWidgets/SugarWidgetReportField.php +- include/ListView/ProcessView.php +- include/nusoap/class.soapclient.php +- include/nusoap/nusoap.php +- include/nusoap/nusoapmime.php +- include/Pear/HTML_Safe/Safe.php +- include/Pear/XML_HTMLSax3/HTMLSax3.php +- modules/Administration/RebuildWorkFlow.php +- modules/Expressions/RelateSelector.php +- modules/Reports/templates/templates_reports.php +- modules/WorkFlow/Delete.php +- modules/WorkFlow/Save.php +- modules/WorkFlow/SaveSequence.php +- modules/WorkFlow/WorkFlow.php +- modules/WorkFlowActionShells/CreateStep1.php +- modules/WorkFlowActionShells/CreateStep2.php +- modules/WorkFlowActionShells/Save.php +- modules/WorkFlowActionShells/WorkFlowActionShell.php +- modules/WorkFlowAlerts/Save.php +- modules/WorkFlowAlerts/WorkFlowAlert.php +- modules/WorkFlowAlertShells/DetailView.php +- modules/WorkFlowAlertShells/WorkFlowAlertShell.php +- modules/WorkFlowTriggerShells/CreateStep1.php +- modules/WorkFlowTriggerShells/CreateStepFilter.php +- modules/WorkFlowTriggerShells/SaveFilter.php +- modules/WorkFlowTriggerShells/WorkFlowTriggerShell.php +- soap/SoapHelperFunctions.php +- test/modules/DynamicFields/DynamicFields_Bug24095_test.php +- test/simpletest/browser.php +- test/simpletest/default_reporter.php +- test/simpletest/detached.php +- test/simpletest/eclipse.php +- test/simpletest/expectation.php +- test/simpletest/extensions/pear_test_case.php +- test/simpletest/form.php +- test/simpletest/http.php +- test/simpletest/mock_objects.php +- test/simpletest/page.php +- test/simpletest/parser.php +- test/simpletest/remote.php +- test/simpletest/shell_tester.php +- test/simpletest/simple_test.php +- test/simpletest/simpletest.php +- test/simpletest/test/acceptance_test.php +- test/simpletest/test/adapter_test.php +- test/simpletest/test/authentication_test.php +- test/simpletest/test/browser_test.php +- test/simpletest/test/collector_test.php +- test/simpletest/test/compatibility_test.php +- test/simpletest/test/detached_test.php +- test/simpletest/test/eclipse_test.php +- test/simpletest/test/encoding_test.php +- test/simpletest/test/errors_test.php +- test/simpletest/test/expectation_test.php +- test/simpletest/test/form_test.php +- test/simpletest/test/frames_test.php +- test/simpletest/test/http_test.php +- test/simpletest/test/live_test.php +- test/simpletest/test/mock_objects_test.php +- test/simpletest/test/page_test.php +- test/simpletest/test/parse_error_test.php +- test/simpletest/test/parser_test.php +- test/simpletest/test/remote_test.php +- test/simpletest/test/shell_test.php +- test/simpletest/test/shell_tester_test.php +- test/simpletest/test/simpletest_test.php +- test/simpletest/test/site/page_request.php +- test/simpletest/test/tag_test.php +- test/simpletest/test/unit_tester_test.php +- test/simpletest/test/user_agent_test.php +- test/simpletest/test/visual_test.php +- test/simpletest/test/xml_test.php +- test/simpletest/test_case.php +- test/simpletest/ui/array_reporter/test.php +- test/simpletest/ui/recorder/test.php +- test/simpletest/unit_tester.php +- test/simpletest/url.php +- test/simpletest/user_agent.php +- test/simpletest/web_tester.php +- test/spikephpcoverage/src/PEAR.php +- test/spikephpcoverage/src/util/Utility.php +- test/spikephpcoverage/src/XML/Parser.php +- test/spikephpcoverage/src/XML/Parser/Simple.php +- test/test_utilities/SugarTest_SimpleBrowser.php + +r38362 - 2008-07-28 14:06:59 -0700 (Mon, 28 Jul 2008) - roger - bug: 23897. Using print_r when using the debug statement in nusoap will print out the statements to the screen if the call is coming from the UI. + +r38300 - 2008-07-25 13:33:43 -0700 (Fri, 25 Jul 2008) - Samir Gandhi - put the debug in parseresponse function + +r38293 - 2008-07-25 12:32:34 -0700 (Fri, 25 Jul 2008) - Samir Gandhi - to put all the debug statements return value in the call function + +r36824 - 2008-06-18 09:26:11 -0700 (Wed, 18 Jun 2008) - roger - bug: 21832 + +r26422 - 2007-09-05 17:29:12 -0700 (Wed, 05 Sep 2007) - majed - migrate from beta 1 to trunk + +r15787 - 2006-08-10 10:14:41 -0700 (Thu, 10 Aug 2006) - roger - RRS: bug 7961 + +r14701 - 2006-07-17 13:37:26 -0700 (Mon, 17 Jul 2006) - roger - RRS: bug 5801 + +r13782 - 2006-06-06 10:58:55 -0700 (Tue, 06 Jun 2006) - majed - changes entry point code + +r11466 - 2006-02-01 15:49:47 -0800 (Wed, 01 Feb 2006) - jacob - Adding extra !empty check to get around a PHP warning. + +r11115 - 2006-01-17 14:54:45 -0800 (Tue, 17 Jan 2006) - majed - add entry point validation + +r10585 - 2005-12-13 14:42:26 -0800 (Tue, 13 Dec 2005) - majed - adds new license mechanisim + +r10170 - 2005-12-05 18:37:46 -0800 (Mon, 05 Dec 2005) - majed - fixes various issues + +r8999 - 2005-11-04 05:26:49 -0800 (Fri, 04 Nov 2005) - roger - When nusoap was upgraded we had an issue with the user's default language not being populated during a soap request. I determined the reason this was happening and have checked in the corresponding change to nusoap. + +r8991 - 2005-11-03 19:07:25 -0800 (Thu, 03 Nov 2005) - majed - fixes nusoap issue + +r8846 - 2005-10-31 11:01:12 -0800 (Mon, 31 Oct 2005) - majed - new version of nusoap + +r7905 - 2005-09-21 19:12:57 -0700 (Wed, 21 Sep 2005) - majed - restores old nusoap pre & with a few fixes + +r7861 - 2005-09-20 15:40:25 -0700 (Tue, 20 Sep 2005) - majed - & fix for 3.5.1 + +r7452 - 2005-08-17 11:32:34 -0700 (Wed, 17 Aug 2005) - majed - changes soap to nusoap + +r5820 - 2005-06-21 14:22:24 -0700 (Tue, 21 Jun 2005) - majed - fixes issues with nusoap and with custom fields + +r5462 - 2005-05-25 13:50:11 -0700 (Wed, 25 May 2005) - majed - upgraded nusoap to .6.9 + +r5104 - 2005-05-04 15:33:41 -0700 (Wed, 04 May 2005) - majed - gets rid of HTTP_GET_VARS and what not which has been deprecated + +r573 - 2004-09-04 13:03:32 -0700 (Sat, 04 Sep 2004) - sugarclint - undoing copyrights added in inadvertantly. --clint + +r546 - 2004-09-03 11:49:38 -0700 (Fri, 03 Sep 2004) - sugarmsi - removed echo count + +r354 - 2004-08-02 23:00:37 -0700 (Mon, 02 Aug 2004) - sugarjacob - Adding Soap + + +*/ + + +if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point'); + +/* +$Id: nusoap.php 58622 2010-10-23 01:18:59Z engsvnbuild $ + +NuSOAP - Web Services Toolkit for PHP + +Copyright (c) 2002 NuSphere Corporation + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. +n +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. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +The NuSOAP project home is: +http://sourceforge.net/projects/nusoap/ + +The primary support for NuSOAP is the Help forum on the project home page. + +If you have any questions or comments, please email: + +Dietrich Ayala +dietrich@ganx4.com +http://dietrich.ganx4.com/nusoap + +NuSphere Corporation +http://www.nusphere.com + +*/ + +/* + * Some of the standards implmented in whole or part by NuSOAP: + * + * SOAP 1.1 (http://www.w3.org/TR/2000/NOTE-SOAP-20000508/) + * WSDL 1.1 (http://www.w3.org/TR/2001/NOTE-wsdl-20010315) + * SOAP Messages With Attachments (http://www.w3.org/TR/SOAP-attachments) + * XML 1.0 (http://www.w3.org/TR/2006/REC-xml-20060816/) + * Namespaces in XML 1.0 (http://www.w3.org/TR/2006/REC-xml-names-20060816/) + * XML Schema 1.0 (http://www.w3.org/TR/xmlschema-0/) + * RFC 2045 Multipurpose Internet Mail Extensions (MIME) Part One: Format of Internet Message Bodies + * RFC 2068 Hypertext Transfer Protocol -- HTTP/1.1 + * RFC 2617 HTTP Authentication: Basic and Digest Access Authentication + */ + +/* load classes + +// necessary classes +require_once('class.soapclient.php'); +require_once('class.soap_val.php'); +require_once('class.soap_parser.php'); +require_once('class.soap_fault.php'); + +// transport classes +require_once('class.soap_transport_http.php'); + +// optional add-on classes +require_once('class.xmlschema.php'); +require_once('class.wsdl.php'); + +// server class +require_once('class.soap_server.php');*/ + +// class variable emulation +// cf. http://www.webkreator.com/php/techniques/php-static-class-variables.html +$GLOBALS['_transient']['static']['nusoap_base']['globalDebugLevel'] = 0; + +/** +* +* nusoap_base +* +* @author Dietrich Ayala +* @author Scott Nichol + +* @access public +*/ +class nusoap_base { + /** + * Identification for HTTP headers. + * + * @var string + * @access private + */ + var $title = 'NuSOAP'; + /** + * Version for HTTP headers. + * + * @var string + * @access private + */ + var $version = '0.9.5'; + /** + * CVS revision for HTTP headers. + * + * @var string + * @access private + */ + var $revision = '$Revision: 58622 $'; + /** + * Current error string (manipulated by getError/setError) + * + * @var string + * @access private + */ + var $error_str = ''; + /** + * Current debug string (manipulated by debug/appendDebug/clearDebug/getDebug/getDebugAsXMLComment) + * + * @var string + * @access private + */ + var $debug_str = ''; + /** + * toggles automatic encoding of special characters as entities + * (should always be true, I think) + * + * @var boolean + * @access private + */ + var $charencoding = true; + /** + * the debug level for this instance + * + * @var integer + * @access private + */ + var $debugLevel; + + /** + * set schema version + * + * @var string + * @access public + */ + var $XMLSchemaVersion = 'http://www.w3.org/2001/XMLSchema'; + + /** + * charset encoding for outgoing messages + * + * @var string + * @access public + */ + //var $soap_defencoding = 'ISO-8859-1'; + var $soap_defencoding = 'UTF-8'; + + /** + * namespaces in an array of prefix => uri + * + * this is "seeded" by a set of constants, but it may be altered by code + * + * @var array + * @access public + */ + var $namespaces = array( + 'SOAP-ENV' => 'http://schemas.xmlsoap.org/soap/envelope/', + 'xsd' => 'http://www.w3.org/2001/XMLSchema', + 'xsi' => 'http://www.w3.org/2001/XMLSchema-instance', + 'SOAP-ENC' => 'http://schemas.xmlsoap.org/soap/encoding/' + ); + + /** + * namespaces used in the current context, e.g. during serialization + * + * @var array + * @access private + */ + var $usedNamespaces = array(); + + /** + * XML Schema types in an array of uri => (array of xml type => php type) + * is this legacy yet? + * no, this is used by the nusoap_xmlschema class to verify type => namespace mappings. + * @var array + * @access public + */ + var $typemap = array( + 'http://www.w3.org/2001/XMLSchema' => array( + 'string'=>'string','boolean'=>'boolean','float'=>'double','double'=>'double','decimal'=>'double', + 'duration'=>'','dateTime'=>'string','time'=>'string','date'=>'string','gYearMonth'=>'', + 'gYear'=>'','gMonthDay'=>'','gDay'=>'','gMonth'=>'','hexBinary'=>'string','base64Binary'=>'string', + // abstract "any" types + 'anyType'=>'string','anySimpleType'=>'string', + // derived datatypes + 'normalizedString'=>'string','token'=>'string','language'=>'','NMTOKEN'=>'','NMTOKENS'=>'','Name'=>'','NCName'=>'','ID'=>'', + 'IDREF'=>'','IDREFS'=>'','ENTITY'=>'','ENTITIES'=>'','integer'=>'integer','nonPositiveInteger'=>'integer', + 'negativeInteger'=>'integer','long'=>'integer','int'=>'integer','short'=>'integer','byte'=>'integer','nonNegativeInteger'=>'integer', + 'unsignedLong'=>'','unsignedInt'=>'','unsignedShort'=>'','unsignedByte'=>'','positiveInteger'=>''), + 'http://www.w3.org/2000/10/XMLSchema' => array( + 'i4'=>'','int'=>'integer','boolean'=>'boolean','string'=>'string','double'=>'double', + 'float'=>'double','dateTime'=>'string', + 'timeInstant'=>'string','base64Binary'=>'string','base64'=>'string','ur-type'=>'array'), + 'http://www.w3.org/1999/XMLSchema' => array( + 'i4'=>'','int'=>'integer','boolean'=>'boolean','string'=>'string','double'=>'double', + 'float'=>'double','dateTime'=>'string', + 'timeInstant'=>'string','base64Binary'=>'string','base64'=>'string','ur-type'=>'array'), + 'http://soapinterop.org/xsd' => array('SOAPStruct'=>'struct'), + 'http://schemas.xmlsoap.org/soap/encoding/' => array('base64'=>'string','array'=>'array','Array'=>'array'), + 'http://xml.apache.org/xml-soap' => array('Map') + ); + + /** + * XML entities to convert + * + * @var array + * @access public + * @deprecated + * @see expandEntities + */ + var $xmlEntities = array('quot' => '"','amp' => '&', + 'lt' => '<','gt' => '>','apos' => "'"); + + /** + * Payload override + * This is to allows us to override the payload to resolve issues where we need to take + * control of the xml content + * @var string + * @access public + * + */ + var $payloadOverride; + + /** + * constructor + * + * @access public + */ + function nusoap_base() { + $this->debugLevel = $GLOBALS['_transient']['static']['nusoap_base']['globalDebugLevel']; + } + + /** + * gets the global debug level, which applies to future instances + * + * @return integer Debug level 0-9, where 0 turns off + * @access public + */ + function getGlobalDebugLevel() { + return $GLOBALS['_transient']['static']['nusoap_base']['globalDebugLevel']; + } + + /** + * sets the global debug level, which applies to future instances + * + * @param int $level Debug level 0-9, where 0 turns off + * @access public + */ + function setGlobalDebugLevel($level) { + $GLOBALS['_transient']['static']['nusoap_base']['globalDebugLevel'] = $level; + } + + /** + * gets the debug level for this instance + * + * @return int Debug level 0-9, where 0 turns off + * @access public + */ + function getDebugLevel() { + return $this->debugLevel; + } + + /** + * sets the debug level for this instance + * + * @param int $level Debug level 0-9, where 0 turns off + * @access public + */ + function setDebugLevel($level) { + $this->debugLevel = $level; + } + + /** + * adds debug data to the instance debug string with formatting + * + * @param string $string debug data + * @access private + */ + function debug($string){ + if ($this->debugLevel > 0) { + $this->appendDebug($this->getmicrotime().' '.get_class($this).": $string\n"); + } + } + + /** + * adds debug data to the instance debug string without formatting + * + * @param string $string debug data + * @access public + */ + function appendDebug($string){ + if ($this->debugLevel > 0) { + // it would be nice to use a memory stream here to use + // memory more efficiently + $this->debug_str .= $string; + } + } + + /** + * clears the current debug data for this instance + * + * @access public + */ + function clearDebug() { + // it would be nice to use a memory stream here to use + // memory more efficiently + $this->debug_str = ''; + } + + /** + * gets the current debug data for this instance + * + * @return debug data + * @access public + */ + function &getDebug() { + // it would be nice to use a memory stream here to use + // memory more efficiently + return $this->debug_str; + } + + /** + * gets the current debug data for this instance as an XML comment + * this may change the contents of the debug data + * + * @return debug data as an XML comment + * @access public + */ + function &getDebugAsXMLComment() { + // it would be nice to use a memory stream here to use + // memory more efficiently + while (strpos($this->debug_str, '--')) { + $this->debug_str = str_replace('--', '- -', $this->debug_str); + } + $ret = ""; + return $ret; + } + + /** + * expands entities, e.g. changes '<' to '<'. + * + * @param string $val The string in which to expand entities. + * @access private + */ + function expandEntities($val) { + if ($this->charencoding) { + $val = htmlspecialchars($val, ENT_QUOTES, $this->soap_defencoding); + // XML 1.0 doesn't allow those... + $val = preg_replace("/([\\x00-\\x08\\x0B\\x0C\\x0E-\\x1F])/", '', $val); + } + return $val; + } + + /** + * returns error string if present + * + * @return mixed error string or false + * @access public + */ + function getError(){ + if($this->error_str != ''){ + return $this->error_str; + } + return false; + } + + /** + * sets error string + * + * @return boolean $string error string + * @access private + */ + function setError($str){ + $this->error_str = $str; + } + + /** + * detect if array is a simple array or a struct (associative array) + * + * @param mixed $val The PHP array + * @return string (arraySimple|arrayStruct) + * @access private + */ + function isArraySimpleOrStruct($val) { + $keyList = array_keys($val); + foreach ($keyList as $keyListValue) { + if (!is_int($keyListValue)) { + return 'arrayStruct'; + } + } + return 'arraySimple'; + } + + /** + * serializes PHP values in accordance w/ section 5. Type information is + * not serialized if $use == 'literal'. + * + * @param mixed $val The value to serialize + * @param string $name The name (local part) of the XML element + * @param string $type The XML schema type (local part) for the element + * @param string $name_ns The namespace for the name of the XML element + * @param string $type_ns The namespace for the type of the element + * @param array $attributes The attributes to serialize as name=>value pairs + * @param string $use The WSDL "use" (encoded|literal) + * @param boolean $soapval Whether this is called from soapval. + * @return string The serialized element, possibly with child elements + * @access public + */ + function serialize_val($val,$name=false,$type=false,$name_ns=false,$type_ns=false,$attributes=false,$use='encoded',$soapval=false) { + $this->debug("in serialize_val: name=$name, type=$type, name_ns=$name_ns, type_ns=$type_ns, use=$use, soapval=$soapval"); + $this->appendDebug('value=' . $this->varDump($val)); + $this->appendDebug('attributes=' . $this->varDump($attributes)); + + if (is_object($val) && get_class($val) == 'soapval' && (! $soapval)) { + $this->debug("serialize_val: serialize soapval"); + $xml = $val->serialize($use); + $this->appendDebug($val->getDebug()); + $val->clearDebug(); + $this->debug("serialize_val of soapval returning $xml"); + return $xml; + } + // force valid name if necessary + if (is_numeric($name)) { + $name = '__numeric_' . $name; + } elseif (! $name) { + $name = 'noname'; + } + // if name has ns, add ns prefix to name + $xmlns = ''; + if($name_ns){ + $prefix = 'nu'.rand(1000,9999); + $name = $prefix.':'.$name; + $xmlns .= " xmlns:$prefix=\"$name_ns\""; + } + // if type is prefixed, create type prefix + if($type_ns != '' && $type_ns == $this->namespaces['xsd']){ + // need to fix this. shouldn't default to xsd if no ns specified + // w/o checking against typemap + $type_prefix = 'xsd'; + } elseif($type_ns){ + $type_prefix = 'ns'.rand(1000,9999); + $xmlns .= " xmlns:$type_prefix=\"$type_ns\""; + } + // serialize attributes if present + $atts = ''; + if($attributes){ + foreach($attributes as $k => $v){ + $atts .= " $k=\"".$this->expandEntities($v).'"'; + } + } + // serialize null value + if (is_null($val)) { + $this->debug("serialize_val: serialize null"); + if ($use == 'literal') { + // TODO: depends on minOccurs + $xml = "<$name$xmlns$atts/>"; + $this->debug("serialize_val returning $xml"); + return $xml; + } else { + if (isset($type) && isset($type_prefix)) { + $type_str = " xsi:type=\"$type_prefix:$type\""; + } else { + $type_str = ''; + } + $xml = "<$name$xmlns$type_str$atts xsi:nil=\"true\"/>"; + $this->debug("serialize_val returning $xml"); + return $xml; + } + } + // serialize if an xsd built-in primitive type + if($type != '' && isset($this->typemap[$this->XMLSchemaVersion][$type])){ + $this->debug("serialize_val: serialize xsd built-in primitive type"); + if (is_bool($val)) { + if ($type == 'boolean') { + $val = $val ? 'true' : 'false'; + } elseif (! $val) { + $val = 0; + } + } else if (is_string($val)) { + $val = $this->expandEntities($val); + } + if ($use == 'literal') { + $xml = "<$name$xmlns$atts>$val"; + $this->debug("serialize_val returning $xml"); + return $xml; + } else { + $xml = "<$name$xmlns xsi:type=\"xsd:$type\"$atts>$val"; + $this->debug("serialize_val returning $xml"); + return $xml; + } + } + // detect type and serialize + $xml = ''; + switch(true) { + case (is_bool($val) || $type == 'boolean'): + $this->debug("serialize_val: serialize boolean"); + if ($type == 'boolean') { + $val = $val ? 'true' : 'false'; + } elseif (! $val) { + $val = 0; + } + if ($use == 'literal') { + $xml .= "<$name$xmlns$atts>$val"; + } else { + $xml .= "<$name$xmlns xsi:type=\"xsd:boolean\"$atts>$val"; + } + break; + case (is_int($val) || is_long($val) || $type == 'int'): + $this->debug("serialize_val: serialize int"); + if ($use == 'literal') { + $xml .= "<$name$xmlns$atts>$val"; + } else { + $xml .= "<$name$xmlns xsi:type=\"xsd:int\"$atts>$val"; + } + break; + case (is_float($val)|| is_double($val) || $type == 'float'): + $this->debug("serialize_val: serialize float"); + if ($use == 'literal') { + $xml .= "<$name$xmlns$atts>$val"; + } else { + $xml .= "<$name$xmlns xsi:type=\"xsd:float\"$atts>$val"; + } + break; + case (is_string($val) || $type == 'string'): + $this->debug("serialize_val: serialize string"); + $val = $this->expandEntities($val); + if ($use == 'literal') { + $xml .= "<$name$xmlns$atts>$val"; + } else { + $xml .= "<$name$xmlns xsi:type=\"xsd:string\"$atts>$val"; + } + break; + case is_object($val): + $this->debug("serialize_val: serialize object"); + if (get_class($val) == 'soapval') { + $this->debug("serialize_val: serialize soapval object"); + $pXml = $val->serialize($use); + $this->appendDebug($val->getDebug()); + $val->clearDebug(); + } else { + if (! $name) { + $name = get_class($val); + $this->debug("In serialize_val, used class name $name as element name"); + } else { + $this->debug("In serialize_val, do not override name $name for element name for class " . get_class($val)); + } + foreach(get_object_vars($val) as $k => $v){ + $pXml = isset($pXml) ? $pXml.$this->serialize_val($v,$k,false,false,false,false,$use) : $this->serialize_val($v,$k,false,false,false,false,$use); + } + } + if(isset($type) && isset($type_prefix)){ + $type_str = " xsi:type=\"$type_prefix:$type\""; + } else { + $type_str = ''; + } + if ($use == 'literal') { + $xml .= "<$name$xmlns$atts>$pXml"; + } else { + $xml .= "<$name$xmlns$type_str$atts>$pXml"; + } + break; + break; + case (is_array($val) || $type): + // detect if struct or array + $valueType = $this->isArraySimpleOrStruct($val); + if($valueType=='arraySimple' || preg_match('/^ArrayOf/',$type)){ + $this->debug("serialize_val: serialize array"); + $i = 0; + if(is_array($val) && count($val)> 0){ + foreach($val as $v){ + if(is_object($v) && get_class($v) == 'soapval'){ + $tt_ns = $v->type_ns; + $tt = $v->type; + } elseif (is_array($v)) { + $tt = $this->isArraySimpleOrStruct($v); + } else { + $tt = gettype($v); + } + $array_types[$tt] = 1; + // TODO: for literal, the name should be $name + $xml .= $this->serialize_val($v,'item',false,false,false,false,$use); + ++$i; + } + if(count($array_types) > 1){ + $array_typename = 'xsd:anyType'; + } elseif(isset($tt) && isset($this->typemap[$this->XMLSchemaVersion][$tt])) { + if ($tt == 'integer') { + $tt = 'int'; + } + $array_typename = 'xsd:'.$tt; + } elseif(isset($tt) && $tt == 'arraySimple'){ + $array_typename = 'SOAP-ENC:Array'; + } elseif(isset($tt) && $tt == 'arrayStruct'){ + $array_typename = 'unnamed_struct_use_soapval'; + } else { + // if type is prefixed, create type prefix + if ($tt_ns != '' && $tt_ns == $this->namespaces['xsd']){ + $array_typename = 'xsd:' . $tt; + } elseif ($tt_ns) { + $tt_prefix = 'ns' . rand(1000, 9999); + $array_typename = "$tt_prefix:$tt"; + $xmlns .= " xmlns:$tt_prefix=\"$tt_ns\""; + } else { + $array_typename = $tt; + } + } + $array_type = $i; + if ($use == 'literal') { + $type_str = ''; + } else if (isset($type) && isset($type_prefix)) { + $type_str = " xsi:type=\"$type_prefix:$type\""; + } else { + $type_str = " xsi:type=\"SOAP-ENC:Array\" SOAP-ENC:arrayType=\"".$array_typename."[$array_type]\""; + } + // empty array + } else { + if ($use == 'literal') { + $type_str = ''; + } else if (isset($type) && isset($type_prefix)) { + $type_str = " xsi:type=\"$type_prefix:$type\""; + } else { + $type_str = " xsi:type=\"SOAP-ENC:Array\" SOAP-ENC:arrayType=\"xsd:anyType[0]\""; + } + } + // TODO: for array in literal, there is no wrapper here + $xml = "<$name$xmlns$type_str$atts>".$xml.""; + } else { + // got a struct + $this->debug("serialize_val: serialize struct"); + if(isset($type) && isset($type_prefix)){ + $type_str = " xsi:type=\"$type_prefix:$type\""; + } else { + $type_str = ''; + } + if ($use == 'literal') { + $xml .= "<$name$xmlns$atts>"; + } else { + $xml .= "<$name$xmlns$type_str$atts>"; + } + foreach($val as $k => $v){ + // Apache Map + if ($type == 'Map' && $type_ns == 'http://xml.apache.org/xml-soap') { + $xml .= ''; + $xml .= $this->serialize_val($k,'key',false,false,false,false,$use); + $xml .= $this->serialize_val($v,'value',false,false,false,false,$use); + $xml .= ''; + } else { + $xml .= $this->serialize_val($v,$k,false,false,false,false,$use); + } + } + $xml .= ""; + } + break; + default: + $this->debug("serialize_val: serialize unknown"); + $xml .= 'not detected, got '.gettype($val).' for '.$val; + break; + } + $this->debug("serialize_val returning $xml"); + return $xml; + } + + /** + * serializes a message + * + * @param string $body the XML of the SOAP body + * @param mixed $headers optional string of XML with SOAP header content, or array of soapval objects for SOAP headers, or associative array + * @param array $namespaces optional the namespaces used in generating the body and headers + * @param string $style optional (rpc|document) + * @param string $use optional (encoded|literal) + * @param string $encodingStyle optional (usually 'http://schemas.xmlsoap.org/soap/encoding/' for encoded) + * @return string the message + * @access public + */ + function serializeEnvelope($body,$headers=false,$namespaces=array(),$style='rpc',$use='encoded',$encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'){ + // TODO: add an option to automatically run utf8_encode on $body and $headers + // if $this->soap_defencoding is UTF-8. Not doing this automatically allows + // one to send arbitrary UTF-8 characters, not just characters that map to ISO-8859-1 + + $this->debug("In serializeEnvelope length=" . strlen($body) . " body (max 1000 characters)=" . substr($body, 0, 1000) . " style=$style use=$use encodingStyle=$encodingStyle"); + $this->debug("headers:"); + $this->appendDebug($this->varDump($headers)); + $this->debug("namespaces:"); + $this->appendDebug($this->varDump($namespaces)); + + // serialize namespaces + $ns_string = ''; + foreach(array_merge($this->namespaces,$namespaces) as $k => $v){ + $ns_string .= " xmlns:$k=\"$v\""; + } + if($encodingStyle) { + $ns_string = " SOAP-ENV:encodingStyle=\"$encodingStyle\"$ns_string"; + } + + // serialize headers + if($headers){ + if (is_array($headers)) { + $xml = ''; + foreach ($headers as $k => $v) { + if (is_object($v) && get_class($v) == 'soapval') { + $xml .= $this->serialize_val($v, false, false, false, false, false, $use); + } else { + $xml .= $this->serialize_val($v, $k, false, false, false, false, $use); + } + } + $headers = $xml; + $this->debug("In serializeEnvelope, serialized array of headers to $headers"); + } + $headers = "".$headers.""; + } + // serialize envelope + return + 'soap_defencoding .'"?'.">". + '". + $headers. + "". + $body. + "". + ""; + } + + /** + * formats a string to be inserted into an HTML stream + * + * @param string $str The string to format + * @return string The formatted string + * @access public + * @deprecated + */ + function formatDump($str){ + $str = htmlspecialchars($str); + return nl2br($str); + } + + /** + * contracts (changes namespace to prefix) a qualified name + * + * @param string $qname qname + * @return string contracted qname + * @access private + */ + function contractQname($qname){ + // get element namespace + //$this->xdebug("Contract $qname"); + if (strrpos($qname, ':')) { + // get unqualified name + $name = substr($qname, strrpos($qname, ':') + 1); + // get ns + $ns = substr($qname, 0, strrpos($qname, ':')); + $p = $this->getPrefixFromNamespace($ns); + if ($p) { + return $p . ':' . $name; + } + return $qname; + } else { + return $qname; + } + } + + /** + * expands (changes prefix to namespace) a qualified name + * + * @param string $qname qname + * @return string expanded qname + * @access private + */ + function expandQname($qname){ + // get element prefix + if(strpos($qname,':') && !preg_match('/^http:\/\//',$qname)){ + // get unqualified name + $name = substr(strstr($qname,':'),1); + // get ns prefix + $prefix = substr($qname,0,strpos($qname,':')); + if(isset($this->namespaces[$prefix])){ + return $this->namespaces[$prefix].':'.$name; + } else { + return $qname; + } + } else { + return $qname; + } + } + + /** + * returns the local part of a prefixed string + * returns the original string, if not prefixed + * + * @param string $str The prefixed string + * @return string The local part + * @access public + */ + function getLocalPart($str){ + if($sstr = strrchr($str,':')){ + // get unqualified name + return substr( $sstr, 1 ); + } else { + return $str; + } + } + + /** + * returns the prefix part of a prefixed string + * returns false, if not prefixed + * + * @param string $str The prefixed string + * @return mixed The prefix or false if there is no prefix + * @access public + */ + function getPrefix($str){ + if($pos = strrpos($str,':')){ + // get prefix + return substr($str,0,$pos); + } + return false; + } + + /** + * pass it a prefix, it returns a namespace + * + * @param string $prefix The prefix + * @return mixed The namespace, false if no namespace has the specified prefix + * @access public + */ + function getNamespaceFromPrefix($prefix){ + if (isset($this->namespaces[$prefix])) { + return $this->namespaces[$prefix]; + } + //$this->setError("No namespace registered for prefix '$prefix'"); + return false; + } + + /** + * returns the prefix for a given namespace (or prefix) + * or false if no prefixes registered for the given namespace + * + * @param string $ns The namespace + * @return mixed The prefix, false if the namespace has no prefixes + * @access public + */ + function getPrefixFromNamespace($ns) { + foreach ($this->namespaces as $p => $n) { + if ($ns == $n || $ns == $p) { + $this->usedNamespaces[$p] = $n; + return $p; + } + } + return false; + } + + /** + * returns the time in ODBC canonical form with microseconds + * + * @return string The time in ODBC canonical form with microseconds + * @access public + */ + function getmicrotime() { + if (function_exists('gettimeofday')) { + $tod = gettimeofday(); + $sec = $tod['sec']; + $usec = $tod['usec']; + } else { + $sec = time(); + $usec = 0; + } + return strftime('%Y-%m-%d %H:%M:%S', $sec) . '.' . sprintf('%06d', $usec); + } + + /** + * Returns a string with the output of var_dump + * + * @param mixed $data The variable to var_dump + * @return string The output of var_dump + * @access public + */ + function varDump($data) { + if ($this->debugLevel <= 0) { + return ''; + } + ob_start(); + var_dump($data); + $ret_val = ob_get_contents(); + ob_end_clean(); + return $ret_val; + } + + /** + * represents the object as a string + * + * @return string + * @access public + */ + function __toString() { + return $this->varDump($this); + } +} + +// XML Schema Datatype Helper Functions + +//xsd:dateTime helpers + +/** +* convert unix timestamp to ISO 8601 compliant date string +* +* @param int $timestamp Unix time stamp +* @param boolean $utc Whether the time stamp is UTC or local +* @return mixed ISO 8601 date string or false +* @access public +*/ +function timestamp_to_iso8601($timestamp,$utc=true){ + $datestr = date('Y-m-d\TH:i:sO',$timestamp); + $pos = strrpos($datestr, "+"); + if ($pos === FALSE) { + $pos = strrpos($datestr, "-"); + } + if ($pos !== FALSE) { + if (strlen($datestr) == $pos + 5) { + $datestr = substr($datestr, 0, $pos + 3) . ':' . substr($datestr, -2); + } + } + if($utc){ + $pattern = '/'. + '([0-9]{4})-'. // centuries & years CCYY- + '([0-9]{2})-'. // months MM- + '([0-9]{2})'. // days DD + 'T'. // separator T + '([0-9]{2}):'. // hours hh: + '([0-9]{2}):'. // minutes mm: + '([0-9]{2})(\.[0-9]*)?'. // seconds ss.ss... + '(Z|[+\-][0-9]{2}:?[0-9]{2})?'. // Z to indicate UTC, -/+HH:MM:SS.SS... for local tz's + '/'; + + if(preg_match($pattern,$datestr,$regs)){ + return sprintf('%04d-%02d-%02dT%02d:%02d:%02dZ',$regs[1],$regs[2],$regs[3],$regs[4],$regs[5],$regs[6]); + } + return false; + } else { + return $datestr; + } +} + +/** +* convert ISO 8601 compliant date string to unix timestamp +* +* @param string $datestr ISO 8601 compliant date string +* @return mixed Unix timestamp (int) or false +* @access public +*/ +function iso8601_to_timestamp($datestr){ + $pattern = '/'. + '([0-9]{4})-'. // centuries & years CCYY- + '([0-9]{2})-'. // months MM- + '([0-9]{2})'. // days DD + 'T'. // separator T + '([0-9]{2}):'. // hours hh: + '([0-9]{2}):'. // minutes mm: + '([0-9]{2})(\.[0-9]+)?'. // seconds ss.ss... + '(Z|[+\-][0-9]{2}:?[0-9]{2})?'. // Z to indicate UTC, -/+HH:MM:SS.SS... for local tz's + '/'; + if(preg_match($pattern,$datestr,$regs)){ + // not utc + if($regs[8] != 'Z'){ + $op = substr($regs[8],0,1); + $h = substr($regs[8],1,2); + $m = substr($regs[8],strlen($regs[8])-2,2); + if($op == '-'){ + $regs[4] = $regs[4] + $h; + $regs[5] = $regs[5] + $m; + } elseif($op == '+'){ + $regs[4] = $regs[4] - $h; + $regs[5] = $regs[5] - $m; + } + } + return gmmktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]); +// return strtotime("$regs[1]-$regs[2]-$regs[3] $regs[4]:$regs[5]:$regs[6]Z"); + } else { + return false; + } +} + +/** +* sleeps some number of microseconds +* +* @param string $usec the number of microseconds to sleep +* @access public +* @deprecated +*/ +function usleepWindows($usec) +{ + $start = gettimeofday(); + + do + { + $stop = gettimeofday(); + $timePassed = 1000000 * ($stop['sec'] - $start['sec']) + + $stop['usec'] - $start['usec']; + } + while ($timePassed < $usec); +} + +?> + bug 40066 + +r58361 - 2010-09-29 16:59:02 -0700 (Wed, 29 Sep 2010) - kjing - Author: Jenny Gonsalves + Merging with maint_6_0_1 (svn merge -r 58250:58342) + +r57813 - 2010-08-19 10:34:44 -0700 (Thu, 19 Aug 2010) - kjing - Author: John Mertic + Bug 39085 - When loading the opposite search panel via ajax on the ListViews, call the index action instead of the ListView action to avoid touching pre-MVC code by accident. + +r57707 - 2010-08-10 12:26:13 -0700 (Tue, 10 Aug 2010) - kjing - Author: Stanislav Malyshev + fix SOAP calls with no parameters + +r56990 - 2010-06-16 13:05:36 -0700 (Wed, 16 Jun 2010) - kjing - snapshot "Mango" svn branch to a new one for GitHub sync + +r56989 - 2010-06-16 13:01:33 -0700 (Wed, 16 Jun 2010) - kjing - defunt "Mango" svn dev branch before github cutover + +r55980 - 2010-04-19 13:31:28 -0700 (Mon, 19 Apr 2010) - kjing - create Mango (6.1) based on windex + +r51719 - 2009-10-22 10:18:00 -0700 (Thu, 22 Oct 2009) - mitani - Converted to Build 3 tags and updated the build system + +r51634 - 2009-10-19 13:32:22 -0700 (Mon, 19 Oct 2009) - mitani - Windex is the branch for Sugar Sales 1.0 development + +r51508 - 2009-10-14 07:40:23 -0700 (Wed, 14 Oct 2009) - jmertic - More fallout fixes from the PHP 5.3 ereg to preg changes. + +r51455 - 2009-10-13 07:56:48 -0700 (Tue, 13 Oct 2009) - jmertic - Bug 33202 - Enable install of SugarCRM on PHP 5.3.0, asserting that the minimum supported version is PHP 5.2.x. + +r51443 - 2009-10-12 13:34:36 -0700 (Mon, 12 Oct 2009) - jmertic - Bug 33332 - Made application PHP 5.3 compliant with E_DEPRECATED warnings on by: +- Changing all ereg function to either preg or simple string based ones +- No more references to magic quotes. +- Change all the session_unregister() functions to just unset() the correct session variable instead. + +r50375 - 2009-08-24 18:07:43 -0700 (Mon, 24 Aug 2009) - dwong - branch kobe2 from tokyo r50372 + +r45763 - 2009-04-01 12:16:18 -0700 (Wed, 01 Apr 2009) - majed - Removed half of the require_once and include_onces in the product that were redundant or could be handled easily by the auto loader + +r45680 - 2009-03-30 14:34:35 -0700 (Mon, 30 Mar 2009) - Samir Gandhi - modifeid serializeSchema to generate WS-I compliant WSDL + +r42807 - 2008-12-29 11:16:59 -0800 (Mon, 29 Dec 2008) - dwong - Branch from trunk/sugarcrm r42806 to branches/tokyo/sugarcrm + +r42645 - 2008-12-18 13:41:08 -0800 (Thu, 18 Dec 2008) - awu - merging maint_5_2_0 rev41336:HEAD to trunk + +r41647 - 2008-11-11 17:44:30 -0800 (Tue, 11 Nov 2008) - majed - Fixes a few bugs + +r41596 - 2008-11-10 19:20:04 -0800 (Mon, 10 Nov 2008) - Samir Gandhi - modified to set $method in the code + +r41558 - 2008-11-10 14:35:34 -0800 (Mon, 10 Nov 2008) - majed - changes nusoap to allow for registering classes + +r39619 - 2008-09-09 13:41:34 -0700 (Tue, 09 Sep 2008) - jmertic - Bug 24827 - Remove all instances where we return a new object and assign it by reference, since this is deprecated in PHP 5 and emits E_DEPRECATED errors in PHP 5.3. +Touched: +- data/SugarBean.php +- include/domit/php_http_client_generic.php +- include/domit/php_http_connector.php +- include/domit/testing_domit.php +- include/domit/xml_domit_getelementsbypath.php +- include/domit/xml_domit_lite_parser.php +- include/domit/xml_domit_nodemaps.php +- include/domit/xml_domit_parser.php +- include/domit/xml_domit_shared.php +- include/generic/SugarWidgets/SugarWidgetField.php +- include/generic/SugarWidgets/SugarWidgetReportField.php +- include/ListView/ProcessView.php +- include/nusoap/class.soapclient.php +- include/nusoap/nusoap.php +- include/nusoap/nusoapmime.php +- include/Pear/HTML_Safe/Safe.php +- include/Pear/XML_HTMLSax3/HTMLSax3.php +- modules/Administration/RebuildWorkFlow.php +- modules/Expressions/RelateSelector.php +- modules/Reports/templates/templates_reports.php +- modules/WorkFlow/Delete.php +- modules/WorkFlow/Save.php +- modules/WorkFlow/SaveSequence.php +- modules/WorkFlow/WorkFlow.php +- modules/WorkFlowActionShells/CreateStep1.php +- modules/WorkFlowActionShells/CreateStep2.php +- modules/WorkFlowActionShells/Save.php +- modules/WorkFlowActionShells/WorkFlowActionShell.php +- modules/WorkFlowAlerts/Save.php +- modules/WorkFlowAlerts/WorkFlowAlert.php +- modules/WorkFlowAlertShells/DetailView.php +- modules/WorkFlowAlertShells/WorkFlowAlertShell.php +- modules/WorkFlowTriggerShells/CreateStep1.php +- modules/WorkFlowTriggerShells/CreateStepFilter.php +- modules/WorkFlowTriggerShells/SaveFilter.php +- modules/WorkFlowTriggerShells/WorkFlowTriggerShell.php +- soap/SoapHelperFunctions.php +- test/modules/DynamicFields/DynamicFields_Bug24095_test.php +- test/simpletest/browser.php +- test/simpletest/default_reporter.php +- test/simpletest/detached.php +- test/simpletest/eclipse.php +- test/simpletest/expectation.php +- test/simpletest/extensions/pear_test_case.php +- test/simpletest/form.php +- test/simpletest/http.php +- test/simpletest/mock_objects.php +- test/simpletest/page.php +- test/simpletest/parser.php +- test/simpletest/remote.php +- test/simpletest/shell_tester.php +- test/simpletest/simple_test.php +- test/simpletest/simpletest.php +- test/simpletest/test/acceptance_test.php +- test/simpletest/test/adapter_test.php +- test/simpletest/test/authentication_test.php +- test/simpletest/test/browser_test.php +- test/simpletest/test/collector_test.php +- test/simpletest/test/compatibility_test.php +- test/simpletest/test/detached_test.php +- test/simpletest/test/eclipse_test.php +- test/simpletest/test/encoding_test.php +- test/simpletest/test/errors_test.php +- test/simpletest/test/expectation_test.php +- test/simpletest/test/form_test.php +- test/simpletest/test/frames_test.php +- test/simpletest/test/http_test.php +- test/simpletest/test/live_test.php +- test/simpletest/test/mock_objects_test.php +- test/simpletest/test/page_test.php +- test/simpletest/test/parse_error_test.php +- test/simpletest/test/parser_test.php +- test/simpletest/test/remote_test.php +- test/simpletest/test/shell_test.php +- test/simpletest/test/shell_tester_test.php +- test/simpletest/test/simpletest_test.php +- test/simpletest/test/site/page_request.php +- test/simpletest/test/tag_test.php +- test/simpletest/test/unit_tester_test.php +- test/simpletest/test/user_agent_test.php +- test/simpletest/test/visual_test.php +- test/simpletest/test/xml_test.php +- test/simpletest/test_case.php +- test/simpletest/ui/array_reporter/test.php +- test/simpletest/ui/recorder/test.php +- test/simpletest/unit_tester.php +- test/simpletest/url.php +- test/simpletest/user_agent.php +- test/simpletest/web_tester.php +- test/spikephpcoverage/src/PEAR.php +- test/spikephpcoverage/src/util/Utility.php +- test/spikephpcoverage/src/XML/Parser.php +- test/spikephpcoverage/src/XML/Parser/Simple.php +- test/test_utilities/SugarTest_SimpleBrowser.php + +r38362 - 2008-07-28 14:06:59 -0700 (Mon, 28 Jul 2008) - roger - bug: 23897. Using print_r when using the debug statement in nusoap will print out the statements to the screen if the call is coming from the UI. + +r38300 - 2008-07-25 13:33:43 -0700 (Fri, 25 Jul 2008) - Samir Gandhi - put the debug in parseresponse function + +r38293 - 2008-07-25 12:32:34 -0700 (Fri, 25 Jul 2008) - Samir Gandhi - to put all the debug statements return value in the call function + +r36824 - 2008-06-18 09:26:11 -0700 (Wed, 18 Jun 2008) - roger - bug: 21832 + +r26422 - 2007-09-05 17:29:12 -0700 (Wed, 05 Sep 2007) - majed - migrate from beta 1 to trunk + +r15787 - 2006-08-10 10:14:41 -0700 (Thu, 10 Aug 2006) - roger - RRS: bug 7961 + +r14701 - 2006-07-17 13:37:26 -0700 (Mon, 17 Jul 2006) - roger - RRS: bug 5801 + +r13782 - 2006-06-06 10:58:55 -0700 (Tue, 06 Jun 2006) - majed - changes entry point code + +r11466 - 2006-02-01 15:49:47 -0800 (Wed, 01 Feb 2006) - jacob - Adding extra !empty check to get around a PHP warning. + +r11115 - 2006-01-17 14:54:45 -0800 (Tue, 17 Jan 2006) - majed - add entry point validation + +r10585 - 2005-12-13 14:42:26 -0800 (Tue, 13 Dec 2005) - majed - adds new license mechanisim + +r10170 - 2005-12-05 18:37:46 -0800 (Mon, 05 Dec 2005) - majed - fixes various issues + +r8999 - 2005-11-04 05:26:49 -0800 (Fri, 04 Nov 2005) - roger - When nusoap was upgraded we had an issue with the user's default language not being populated during a soap request. I determined the reason this was happening and have checked in the corresponding change to nusoap. + +r8991 - 2005-11-03 19:07:25 -0800 (Thu, 03 Nov 2005) - majed - fixes nusoap issue + +r8846 - 2005-10-31 11:01:12 -0800 (Mon, 31 Oct 2005) - majed - new version of nusoap + +r7905 - 2005-09-21 19:12:57 -0700 (Wed, 21 Sep 2005) - majed - restores old nusoap pre & with a few fixes + +r7861 - 2005-09-20 15:40:25 -0700 (Tue, 20 Sep 2005) - majed - & fix for 3.5.1 + +r7452 - 2005-08-17 11:32:34 -0700 (Wed, 17 Aug 2005) - majed - changes soap to nusoap + +r5820 - 2005-06-21 14:22:24 -0700 (Tue, 21 Jun 2005) - majed - fixes issues with nusoap and with custom fields + +r5462 - 2005-05-25 13:50:11 -0700 (Wed, 25 May 2005) - majed - upgraded nusoap to .6.9 + +r5104 - 2005-05-04 15:33:41 -0700 (Wed, 04 May 2005) - majed - gets rid of HTTP_GET_VARS and what not which has been deprecated + +r573 - 2004-09-04 13:03:32 -0700 (Sat, 04 Sep 2004) - sugarclint - undoing copyrights added in inadvertantly. --clint + +r546 - 2004-09-03 11:49:38 -0700 (Fri, 03 Sep 2004) - sugarmsi - removed echo count + +r354 - 2004-08-02 23:00:37 -0700 (Mon, 02 Aug 2004) - sugarjacob - Adding Soap + + +*/ + + + + + +/** +* Contains information for a SOAP fault. +* Mainly used for returning faults from deployed functions +* in a server instance. +* @author Dietrich Ayala + +* @access public +*/ +class nusoap_fault extends nusoap_base { + /** + * The fault code (client|server) + * @var string + * @access private + */ + var $faultcode; + /** + * The fault actor + * @var string + * @access private + */ + var $faultactor; + /** + * The fault string, a description of the fault + * @var string + * @access private + */ + var $faultstring; + /** + * The fault detail, typically a string or array of string + * @var mixed + * @access private + */ + var $faultdetail; + + /** + * constructor + * + * @param string $faultcode (SOAP-ENV:Client | SOAP-ENV:Server) + * @param string $faultactor only used when msg routed between multiple actors + * @param string $faultstring human readable error message + * @param mixed $faultdetail detail, typically a string or array of string + */ + function nusoap_fault($faultcode,$faultactor='',$faultstring='',$faultdetail=''){ + parent::nusoap_base(); + $this->faultcode = $faultcode; + $this->faultactor = $faultactor; + $this->faultstring = $faultstring; + $this->faultdetail = $faultdetail; + } + + /** + * serialize a fault + * + * @return string The serialization of the fault instance. + * @access public + */ + function serialize(){ + $ns_string = ''; + foreach($this->namespaces as $k => $v){ + $ns_string .= "\n xmlns:$k=\"$v\""; + } + $return_msg = + 'soap_defencoding.'"?>'. + '\n". + ''. + ''. + $this->serialize_val($this->faultcode, 'faultcode'). + $this->serialize_val($this->faultactor, 'faultactor'). + $this->serialize_val($this->faultstring, 'faultstring'). + $this->serialize_val($this->faultdetail, 'detail'). + ''. + ''. + ''; + return $return_msg; + } +} + +/** + * Backward compatibility + */ +class soap_fault extends nusoap_fault { +} + +?> + bug 40066 + +r58361 - 2010-09-29 16:59:02 -0700 (Wed, 29 Sep 2010) - kjing - Author: Jenny Gonsalves + Merging with maint_6_0_1 (svn merge -r 58250:58342) + +r57813 - 2010-08-19 10:34:44 -0700 (Thu, 19 Aug 2010) - kjing - Author: John Mertic + Bug 39085 - When loading the opposite search panel via ajax on the ListViews, call the index action instead of the ListView action to avoid touching pre-MVC code by accident. + +r57707 - 2010-08-10 12:26:13 -0700 (Tue, 10 Aug 2010) - kjing - Author: Stanislav Malyshev + fix SOAP calls with no parameters + +r56990 - 2010-06-16 13:05:36 -0700 (Wed, 16 Jun 2010) - kjing - snapshot "Mango" svn branch to a new one for GitHub sync + +r56989 - 2010-06-16 13:01:33 -0700 (Wed, 16 Jun 2010) - kjing - defunt "Mango" svn dev branch before github cutover + +r55980 - 2010-04-19 13:31:28 -0700 (Mon, 19 Apr 2010) - kjing - create Mango (6.1) based on windex + +r51719 - 2009-10-22 10:18:00 -0700 (Thu, 22 Oct 2009) - mitani - Converted to Build 3 tags and updated the build system + +r51634 - 2009-10-19 13:32:22 -0700 (Mon, 19 Oct 2009) - mitani - Windex is the branch for Sugar Sales 1.0 development + +r51508 - 2009-10-14 07:40:23 -0700 (Wed, 14 Oct 2009) - jmertic - More fallout fixes from the PHP 5.3 ereg to preg changes. + +r51455 - 2009-10-13 07:56:48 -0700 (Tue, 13 Oct 2009) - jmertic - Bug 33202 - Enable install of SugarCRM on PHP 5.3.0, asserting that the minimum supported version is PHP 5.2.x. + +r51443 - 2009-10-12 13:34:36 -0700 (Mon, 12 Oct 2009) - jmertic - Bug 33332 - Made application PHP 5.3 compliant with E_DEPRECATED warnings on by: +- Changing all ereg function to either preg or simple string based ones +- No more references to magic quotes. +- Change all the session_unregister() functions to just unset() the correct session variable instead. + +r50375 - 2009-08-24 18:07:43 -0700 (Mon, 24 Aug 2009) - dwong - branch kobe2 from tokyo r50372 + +r45763 - 2009-04-01 12:16:18 -0700 (Wed, 01 Apr 2009) - majed - Removed half of the require_once and include_onces in the product that were redundant or could be handled easily by the auto loader + +r45680 - 2009-03-30 14:34:35 -0700 (Mon, 30 Mar 2009) - Samir Gandhi - modifeid serializeSchema to generate WS-I compliant WSDL + +r42807 - 2008-12-29 11:16:59 -0800 (Mon, 29 Dec 2008) - dwong - Branch from trunk/sugarcrm r42806 to branches/tokyo/sugarcrm + +r42645 - 2008-12-18 13:41:08 -0800 (Thu, 18 Dec 2008) - awu - merging maint_5_2_0 rev41336:HEAD to trunk + +r41647 - 2008-11-11 17:44:30 -0800 (Tue, 11 Nov 2008) - majed - Fixes a few bugs + +r41596 - 2008-11-10 19:20:04 -0800 (Mon, 10 Nov 2008) - Samir Gandhi - modified to set $method in the code + +r41558 - 2008-11-10 14:35:34 -0800 (Mon, 10 Nov 2008) - majed - changes nusoap to allow for registering classes + +r39619 - 2008-09-09 13:41:34 -0700 (Tue, 09 Sep 2008) - jmertic - Bug 24827 - Remove all instances where we return a new object and assign it by reference, since this is deprecated in PHP 5 and emits E_DEPRECATED errors in PHP 5.3. +Touched: +- data/SugarBean.php +- include/domit/php_http_client_generic.php +- include/domit/php_http_connector.php +- include/domit/testing_domit.php +- include/domit/xml_domit_getelementsbypath.php +- include/domit/xml_domit_lite_parser.php +- include/domit/xml_domit_nodemaps.php +- include/domit/xml_domit_parser.php +- include/domit/xml_domit_shared.php +- include/generic/SugarWidgets/SugarWidgetField.php +- include/generic/SugarWidgets/SugarWidgetReportField.php +- include/ListView/ProcessView.php +- include/nusoap/class.soapclient.php +- include/nusoap/nusoap.php +- include/nusoap/nusoapmime.php +- include/Pear/HTML_Safe/Safe.php +- include/Pear/XML_HTMLSax3/HTMLSax3.php +- modules/Administration/RebuildWorkFlow.php +- modules/Expressions/RelateSelector.php +- modules/Reports/templates/templates_reports.php +- modules/WorkFlow/Delete.php +- modules/WorkFlow/Save.php +- modules/WorkFlow/SaveSequence.php +- modules/WorkFlow/WorkFlow.php +- modules/WorkFlowActionShells/CreateStep1.php +- modules/WorkFlowActionShells/CreateStep2.php +- modules/WorkFlowActionShells/Save.php +- modules/WorkFlowActionShells/WorkFlowActionShell.php +- modules/WorkFlowAlerts/Save.php +- modules/WorkFlowAlerts/WorkFlowAlert.php +- modules/WorkFlowAlertShells/DetailView.php +- modules/WorkFlowAlertShells/WorkFlowAlertShell.php +- modules/WorkFlowTriggerShells/CreateStep1.php +- modules/WorkFlowTriggerShells/CreateStepFilter.php +- modules/WorkFlowTriggerShells/SaveFilter.php +- modules/WorkFlowTriggerShells/WorkFlowTriggerShell.php +- soap/SoapHelperFunctions.php +- test/modules/DynamicFields/DynamicFields_Bug24095_test.php +- test/simpletest/browser.php +- test/simpletest/default_reporter.php +- test/simpletest/detached.php +- test/simpletest/eclipse.php +- test/simpletest/expectation.php +- test/simpletest/extensions/pear_test_case.php +- test/simpletest/form.php +- test/simpletest/http.php +- test/simpletest/mock_objects.php +- test/simpletest/page.php +- test/simpletest/parser.php +- test/simpletest/remote.php +- test/simpletest/shell_tester.php +- test/simpletest/simple_test.php +- test/simpletest/simpletest.php +- test/simpletest/test/acceptance_test.php +- test/simpletest/test/adapter_test.php +- test/simpletest/test/authentication_test.php +- test/simpletest/test/browser_test.php +- test/simpletest/test/collector_test.php +- test/simpletest/test/compatibility_test.php +- test/simpletest/test/detached_test.php +- test/simpletest/test/eclipse_test.php +- test/simpletest/test/encoding_test.php +- test/simpletest/test/errors_test.php +- test/simpletest/test/expectation_test.php +- test/simpletest/test/form_test.php +- test/simpletest/test/frames_test.php +- test/simpletest/test/http_test.php +- test/simpletest/test/live_test.php +- test/simpletest/test/mock_objects_test.php +- test/simpletest/test/page_test.php +- test/simpletest/test/parse_error_test.php +- test/simpletest/test/parser_test.php +- test/simpletest/test/remote_test.php +- test/simpletest/test/shell_test.php +- test/simpletest/test/shell_tester_test.php +- test/simpletest/test/simpletest_test.php +- test/simpletest/test/site/page_request.php +- test/simpletest/test/tag_test.php +- test/simpletest/test/unit_tester_test.php +- test/simpletest/test/user_agent_test.php +- test/simpletest/test/visual_test.php +- test/simpletest/test/xml_test.php +- test/simpletest/test_case.php +- test/simpletest/ui/array_reporter/test.php +- test/simpletest/ui/recorder/test.php +- test/simpletest/unit_tester.php +- test/simpletest/url.php +- test/simpletest/user_agent.php +- test/simpletest/web_tester.php +- test/spikephpcoverage/src/PEAR.php +- test/spikephpcoverage/src/util/Utility.php +- test/spikephpcoverage/src/XML/Parser.php +- test/spikephpcoverage/src/XML/Parser/Simple.php +- test/test_utilities/SugarTest_SimpleBrowser.php + +r38362 - 2008-07-28 14:06:59 -0700 (Mon, 28 Jul 2008) - roger - bug: 23897. Using print_r when using the debug statement in nusoap will print out the statements to the screen if the call is coming from the UI. + +r38300 - 2008-07-25 13:33:43 -0700 (Fri, 25 Jul 2008) - Samir Gandhi - put the debug in parseresponse function + +r38293 - 2008-07-25 12:32:34 -0700 (Fri, 25 Jul 2008) - Samir Gandhi - to put all the debug statements return value in the call function + +r36824 - 2008-06-18 09:26:11 -0700 (Wed, 18 Jun 2008) - roger - bug: 21832 + +r26422 - 2007-09-05 17:29:12 -0700 (Wed, 05 Sep 2007) - majed - migrate from beta 1 to trunk + +r15787 - 2006-08-10 10:14:41 -0700 (Thu, 10 Aug 2006) - roger - RRS: bug 7961 + +r14701 - 2006-07-17 13:37:26 -0700 (Mon, 17 Jul 2006) - roger - RRS: bug 5801 + +r13782 - 2006-06-06 10:58:55 -0700 (Tue, 06 Jun 2006) - majed - changes entry point code + +r11466 - 2006-02-01 15:49:47 -0800 (Wed, 01 Feb 2006) - jacob - Adding extra !empty check to get around a PHP warning. + +r11115 - 2006-01-17 14:54:45 -0800 (Tue, 17 Jan 2006) - majed - add entry point validation + +r10585 - 2005-12-13 14:42:26 -0800 (Tue, 13 Dec 2005) - majed - adds new license mechanisim + +r10170 - 2005-12-05 18:37:46 -0800 (Mon, 05 Dec 2005) - majed - fixes various issues + +r8999 - 2005-11-04 05:26:49 -0800 (Fri, 04 Nov 2005) - roger - When nusoap was upgraded we had an issue with the user's default language not being populated during a soap request. I determined the reason this was happening and have checked in the corresponding change to nusoap. + +r8991 - 2005-11-03 19:07:25 -0800 (Thu, 03 Nov 2005) - majed - fixes nusoap issue + +r8846 - 2005-10-31 11:01:12 -0800 (Mon, 31 Oct 2005) - majed - new version of nusoap + +r7905 - 2005-09-21 19:12:57 -0700 (Wed, 21 Sep 2005) - majed - restores old nusoap pre & with a few fixes + +r7861 - 2005-09-20 15:40:25 -0700 (Tue, 20 Sep 2005) - majed - & fix for 3.5.1 + +r7452 - 2005-08-17 11:32:34 -0700 (Wed, 17 Aug 2005) - majed - changes soap to nusoap + +r5820 - 2005-06-21 14:22:24 -0700 (Tue, 21 Jun 2005) - majed - fixes issues with nusoap and with custom fields + +r5462 - 2005-05-25 13:50:11 -0700 (Wed, 25 May 2005) - majed - upgraded nusoap to .6.9 + +r5104 - 2005-05-04 15:33:41 -0700 (Wed, 04 May 2005) - majed - gets rid of HTTP_GET_VARS and what not which has been deprecated + +r573 - 2004-09-04 13:03:32 -0700 (Sat, 04 Sep 2004) - sugarclint - undoing copyrights added in inadvertantly. --clint + +r546 - 2004-09-03 11:49:38 -0700 (Fri, 03 Sep 2004) - sugarmsi - removed echo count + +r354 - 2004-08-02 23:00:37 -0700 (Mon, 02 Aug 2004) - sugarjacob - Adding Soap + + +*/ + + + + + +/** +* parses an XML Schema, allows access to it's data, other utility methods. +* imperfect, no validation... yet, but quite functional. +* +* @author Dietrich Ayala +* @author Scott Nichol + +* @access public +*/ +class nusoap_xmlschema extends nusoap_base { + + // files + var $schema = ''; + var $xml = ''; + // namespaces + var $enclosingNamespaces; + // schema info + var $schemaInfo = array(); + var $schemaTargetNamespace = ''; + // types, elements, attributes defined by the schema + var $attributes = array(); + var $complexTypes = array(); + var $complexTypeStack = array(); + var $currentComplexType = null; + var $elements = array(); + var $elementStack = array(); + var $currentElement = null; + var $simpleTypes = array(); + var $simpleTypeStack = array(); + var $currentSimpleType = null; + // imports + var $imports = array(); + // parser vars + var $parser; + var $position = 0; + var $depth = 0; + var $depth_array = array(); + var $message = array(); + var $defaultNamespace = array(); + + /** + * constructor + * + * @param string $schema schema document URI + * @param string $xml xml document URI + * @param string $namespaces namespaces defined in enclosing XML + * @access public + */ + function nusoap_xmlschema($schema='',$xml='',$namespaces=array()){ + parent::nusoap_base(); + $this->debug('nusoap_xmlschema class instantiated, inside constructor'); + // files + $this->schema = $schema; + $this->xml = $xml; + + // namespaces + $this->enclosingNamespaces = $namespaces; + $this->namespaces = array_merge($this->namespaces, $namespaces); + + // parse schema file + if($schema != ''){ + $this->debug('initial schema file: '.$schema); + $this->parseFile($schema, 'schema'); + } + + // parse xml file + if($xml != ''){ + $this->debug('initial xml file: '.$xml); + $this->parseFile($xml, 'xml'); + } + + } + + /** + * parse an XML file + * + * @param string $xml path/URL to XML file + * @param string $type (schema | xml) + * @return boolean + * @access public + */ + function parseFile($xml,$type){ + // parse xml file + if($xml != ""){ + $xmlStr = @join("",@file($xml)); + if($xmlStr == ""){ + $msg = 'Error reading XML from '.$xml; + $this->setError($msg); + $this->debug($msg); + return false; + } else { + $this->debug("parsing $xml"); + $this->parseString($xmlStr,$type); + $this->debug("done parsing $xml"); + return true; + } + } + return false; + } + + /** + * parse an XML string + * + * @param string $xml path or URL + * @param string $type (schema|xml) + * @access private + */ + function parseString($xml,$type){ + // parse xml string + if($xml != ""){ + + // Create an XML parser. + $this->parser = xml_parser_create(); + // Set the options for parsing the XML data. + xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0); + + // Set the object for the parser. + xml_set_object($this->parser, $this); + + // Set the element handlers for the parser. + if($type == "schema"){ + xml_set_element_handler($this->parser, 'schemaStartElement','schemaEndElement'); + xml_set_character_data_handler($this->parser,'schemaCharacterData'); + } elseif($type == "xml"){ + xml_set_element_handler($this->parser, 'xmlStartElement','xmlEndElement'); + xml_set_character_data_handler($this->parser,'xmlCharacterData'); + } + + // Parse the XML file. + if(!xml_parse($this->parser,$xml,true)){ + // Display an error message. + $errstr = sprintf('XML error parsing XML schema on line %d: %s', + xml_get_current_line_number($this->parser), + xml_error_string(xml_get_error_code($this->parser)) + ); + $this->debug($errstr); + $this->debug("XML payload:\n" . $xml); + $this->setError($errstr); + } + + xml_parser_free($this->parser); + } else{ + $this->debug('no xml passed to parseString()!!'); + $this->setError('no xml passed to parseString()!!'); + } + } + + /** + * gets a type name for an unnamed type + * + * @param string Element name + * @return string A type name for an unnamed type + * @access private + */ + function CreateTypeName($ename) { + $scope = ''; + for ($i = 0; $i < count($this->complexTypeStack); $i++) { + $scope .= $this->complexTypeStack[$i] . '_'; + } + return $scope . $ename . '_ContainedType'; + } + + /** + * start-element handler + * + * @param string $parser XML parser object + * @param string $name element name + * @param string $attrs associative array of attributes + * @access private + */ + function schemaStartElement($parser, $name, $attrs) { + + // position in the total number of elements, starting from 0 + $pos = $this->position++; + $depth = $this->depth++; + // set self as current value for this depth + $this->depth_array[$depth] = $pos; + $this->message[$pos] = array('cdata' => ''); + if ($depth > 0) { + $this->defaultNamespace[$pos] = $this->defaultNamespace[$this->depth_array[$depth - 1]]; + } else { + $this->defaultNamespace[$pos] = false; + } + + // get element prefix + if($prefix = $this->getPrefix($name)){ + // get unqualified name + $name = $this->getLocalPart($name); + } else { + $prefix = ''; + } + + // loop thru attributes, expanding, and registering namespace declarations + if(count($attrs) > 0){ + foreach($attrs as $k => $v){ + // if ns declarations, add to class level array of valid namespaces + if(preg_match('/^xmlns/',$k)){ + //$this->xdebug("$k: $v"); + //$this->xdebug('ns_prefix: '.$this->getPrefix($k)); + if($ns_prefix = substr(strrchr($k,':'),1)){ + //$this->xdebug("Add namespace[$ns_prefix] = $v"); + $this->namespaces[$ns_prefix] = $v; + } else { + $this->defaultNamespace[$pos] = $v; + if (! $this->getPrefixFromNamespace($v)) { + $this->namespaces['ns'.(count($this->namespaces)+1)] = $v; + } + } + if($v == 'http://www.w3.org/2001/XMLSchema' || $v == 'http://www.w3.org/1999/XMLSchema' || $v == 'http://www.w3.org/2000/10/XMLSchema'){ + $this->XMLSchemaVersion = $v; + $this->namespaces['xsi'] = $v.'-instance'; + } + } + } + foreach($attrs as $k => $v){ + // expand each attribute + $k = strpos($k,':') ? $this->expandQname($k) : $k; + $v = strpos($v,':') ? $this->expandQname($v) : $v; + $eAttrs[$k] = $v; + } + $attrs = $eAttrs; + } else { + $attrs = array(); + } + // find status, register data + switch($name){ + case 'all': // (optional) compositor content for a complexType + case 'choice': + case 'group': + case 'sequence': + //$this->xdebug("compositor $name for currentComplexType: $this->currentComplexType and currentElement: $this->currentElement"); + $this->complexTypes[$this->currentComplexType]['compositor'] = $name; + //if($name == 'all' || $name == 'sequence'){ + // $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct'; + //} + break; + case 'attribute': // complexType attribute + //$this->xdebug("parsing attribute $attrs[name] $attrs[ref] of value: ".$attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']); + $this->xdebug("parsing attribute:"); + $this->appendDebug($this->varDump($attrs)); + if (!isset($attrs['form'])) { + // TODO: handle globals + $attrs['form'] = $this->schemaInfo['attributeFormDefault']; + } + if (isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])) { + $v = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']; + if (!strpos($v, ':')) { + // no namespace in arrayType attribute value... + if ($this->defaultNamespace[$pos]) { + // ...so use the default + $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'] = $this->defaultNamespace[$pos] . ':' . $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']; + } + } + } + if(isset($attrs['name'])){ + $this->attributes[$attrs['name']] = $attrs; + $aname = $attrs['name']; + } elseif(isset($attrs['ref']) && $attrs['ref'] == 'http://schemas.xmlsoap.org/soap/encoding/:arrayType'){ + if (isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])) { + $aname = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']; + } else { + $aname = ''; + } + } elseif(isset($attrs['ref'])){ + $aname = $attrs['ref']; + $this->attributes[$attrs['ref']] = $attrs; + } + + if($this->currentComplexType){ // This should *always* be + $this->complexTypes[$this->currentComplexType]['attrs'][$aname] = $attrs; + } + // arrayType attribute + if(isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']) || $this->getLocalPart($aname) == 'arrayType'){ + $this->complexTypes[$this->currentComplexType]['phpType'] = 'array'; + $prefix = $this->getPrefix($aname); + if(isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])){ + $v = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']; + } else { + $v = ''; + } + if(strpos($v,'[,]')){ + $this->complexTypes[$this->currentComplexType]['multidimensional'] = true; + } + $v = substr($v,0,strpos($v,'[')); // clip the [] + if(!strpos($v,':') && isset($this->typemap[$this->XMLSchemaVersion][$v])){ + $v = $this->XMLSchemaVersion.':'.$v; + } + $this->complexTypes[$this->currentComplexType]['arrayType'] = $v; + } + break; + case 'complexContent': // (optional) content for a complexType + $this->xdebug("do nothing for element $name"); + break; + case 'complexType': + array_push($this->complexTypeStack, $this->currentComplexType); + if(isset($attrs['name'])){ + // TODO: what is the scope of named complexTypes that appear + // nested within other c complexTypes? + $this->xdebug('processing named complexType '.$attrs['name']); + //$this->currentElement = false; + $this->currentComplexType = $attrs['name']; + $this->complexTypes[$this->currentComplexType] = $attrs; + $this->complexTypes[$this->currentComplexType]['typeClass'] = 'complexType'; + // This is for constructs like + // + // + // + // + // + if(isset($attrs['base']) && preg_match('/:Array$/',$attrs['base'])){ + $this->xdebug('complexType is unusual array'); + $this->complexTypes[$this->currentComplexType]['phpType'] = 'array'; + } else { + $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct'; + } + } else { + $name = $this->CreateTypeName($this->currentElement); + $this->xdebug('processing unnamed complexType for element ' . $this->currentElement . ' named ' . $name); + $this->currentComplexType = $name; + //$this->currentElement = false; + $this->complexTypes[$this->currentComplexType] = $attrs; + $this->complexTypes[$this->currentComplexType]['typeClass'] = 'complexType'; + // This is for constructs like + // + // + // + // + // + if(isset($attrs['base']) && preg_match('/:Array$/',$attrs['base'])){ + $this->xdebug('complexType is unusual array'); + $this->complexTypes[$this->currentComplexType]['phpType'] = 'array'; + } else { + $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct'; + } + } + $this->complexTypes[$this->currentComplexType]['simpleContent'] = 'false'; + break; + case 'element': + array_push($this->elementStack, $this->currentElement); + if (!isset($attrs['form'])) { + if ($this->currentComplexType) { + $attrs['form'] = $this->schemaInfo['elementFormDefault']; + } else { + // global + $attrs['form'] = 'qualified'; + } + } + if(isset($attrs['type'])){ + $this->xdebug("processing typed element ".$attrs['name']." of type ".$attrs['type']); + if (! $this->getPrefix($attrs['type'])) { + if ($this->defaultNamespace[$pos]) { + $attrs['type'] = $this->defaultNamespace[$pos] . ':' . $attrs['type']; + $this->xdebug('used default namespace to make type ' . $attrs['type']); + } + } + // This is for constructs like + // + // + // + // + // + if ($this->currentComplexType && $this->complexTypes[$this->currentComplexType]['phpType'] == 'array') { + $this->xdebug('arrayType for unusual array is ' . $attrs['type']); + $this->complexTypes[$this->currentComplexType]['arrayType'] = $attrs['type']; + } + $this->currentElement = $attrs['name']; + $ename = $attrs['name']; + } elseif(isset($attrs['ref'])){ + $this->xdebug("processing element as ref to ".$attrs['ref']); + $this->currentElement = "ref to ".$attrs['ref']; + $ename = $this->getLocalPart($attrs['ref']); + } else { + $type = $this->CreateTypeName($this->currentComplexType . '_' . $attrs['name']); + $this->xdebug("processing untyped element " . $attrs['name'] . ' type ' . $type); + $this->currentElement = $attrs['name']; + $attrs['type'] = $this->schemaTargetNamespace . ':' . $type; + $ename = $attrs['name']; + } + if (isset($ename) && $this->currentComplexType) { + $this->xdebug("add element $ename to complexType $this->currentComplexType"); + $this->complexTypes[$this->currentComplexType]['elements'][$ename] = $attrs; + } elseif (!isset($attrs['ref'])) { + $this->xdebug("add element $ename to elements array"); + $this->elements[ $attrs['name'] ] = $attrs; + $this->elements[ $attrs['name'] ]['typeClass'] = 'element'; + } + break; + case 'enumeration': // restriction value list member + $this->xdebug('enumeration ' . $attrs['value']); + if ($this->currentSimpleType) { + $this->simpleTypes[$this->currentSimpleType]['enumeration'][] = $attrs['value']; + } elseif ($this->currentComplexType) { + $this->complexTypes[$this->currentComplexType]['enumeration'][] = $attrs['value']; + } + break; + case 'extension': // simpleContent or complexContent type extension + $this->xdebug('extension ' . $attrs['base']); + if ($this->currentComplexType) { + $ns = $this->getPrefix($attrs['base']); + if ($ns == '') { + $this->complexTypes[$this->currentComplexType]['extensionBase'] = $this->schemaTargetNamespace . ':' . $attrs['base']; + } else { + $this->complexTypes[$this->currentComplexType]['extensionBase'] = $attrs['base']; + } + } else { + $this->xdebug('no current complexType to set extensionBase'); + } + break; + case 'import': + if (isset($attrs['schemaLocation'])) { + $this->xdebug('import namespace ' . $attrs['namespace'] . ' from ' . $attrs['schemaLocation']); + $this->imports[$attrs['namespace']][] = array('location' => $attrs['schemaLocation'], 'loaded' => false); + } else { + $this->xdebug('import namespace ' . $attrs['namespace']); + $this->imports[$attrs['namespace']][] = array('location' => '', 'loaded' => true); + if (! $this->getPrefixFromNamespace($attrs['namespace'])) { + $this->namespaces['ns'.(count($this->namespaces)+1)] = $attrs['namespace']; + } + } + break; + case 'include': + if (isset($attrs['schemaLocation'])) { + $this->xdebug('include into namespace ' . $this->schemaTargetNamespace . ' from ' . $attrs['schemaLocation']); + $this->imports[$this->schemaTargetNamespace][] = array('location' => $attrs['schemaLocation'], 'loaded' => false); + } else { + $this->xdebug('ignoring invalid XML Schema construct: include without schemaLocation attribute'); + } + break; + case 'list': // simpleType value list + $this->xdebug("do nothing for element $name"); + break; + case 'restriction': // simpleType, simpleContent or complexContent value restriction + $this->xdebug('restriction ' . $attrs['base']); + if($this->currentSimpleType){ + $this->simpleTypes[$this->currentSimpleType]['type'] = $attrs['base']; + } elseif($this->currentComplexType){ + $this->complexTypes[$this->currentComplexType]['restrictionBase'] = $attrs['base']; + if(strstr($attrs['base'],':') == ':Array'){ + $this->complexTypes[$this->currentComplexType]['phpType'] = 'array'; + } + } + break; + case 'schema': + $this->schemaInfo = $attrs; + $this->schemaInfo['schemaVersion'] = $this->getNamespaceFromPrefix($prefix); + if (isset($attrs['targetNamespace'])) { + $this->schemaTargetNamespace = $attrs['targetNamespace']; + } + if (!isset($attrs['elementFormDefault'])) { + $this->schemaInfo['elementFormDefault'] = 'unqualified'; + } + if (!isset($attrs['attributeFormDefault'])) { + $this->schemaInfo['attributeFormDefault'] = 'unqualified'; + } + break; + case 'simpleContent': // (optional) content for a complexType + if ($this->currentComplexType) { // This should *always* be + $this->complexTypes[$this->currentComplexType]['simpleContent'] = 'true'; + } else { + $this->xdebug("do nothing for element $name because there is no current complexType"); + } + break; + case 'simpleType': + array_push($this->simpleTypeStack, $this->currentSimpleType); + if(isset($attrs['name'])){ + $this->xdebug("processing simpleType for name " . $attrs['name']); + $this->currentSimpleType = $attrs['name']; + $this->simpleTypes[ $attrs['name'] ] = $attrs; + $this->simpleTypes[ $attrs['name'] ]['typeClass'] = 'simpleType'; + $this->simpleTypes[ $attrs['name'] ]['phpType'] = 'scalar'; + } else { + $name = $this->CreateTypeName($this->currentComplexType . '_' . $this->currentElement); + $this->xdebug('processing unnamed simpleType for element ' . $this->currentElement . ' named ' . $name); + $this->currentSimpleType = $name; + //$this->currentElement = false; + $this->simpleTypes[$this->currentSimpleType] = $attrs; + $this->simpleTypes[$this->currentSimpleType]['phpType'] = 'scalar'; + } + break; + case 'union': // simpleType type list + $this->xdebug("do nothing for element $name"); + break; + default: + $this->xdebug("do not have any logic to process element $name"); + } + } + + /** + * end-element handler + * + * @param string $parser XML parser object + * @param string $name element name + * @access private + */ + function schemaEndElement($parser, $name) { + // bring depth down a notch + $this->depth--; + // position of current element is equal to the last value left in depth_array for my depth + if(isset($this->depth_array[$this->depth])){ + $pos = $this->depth_array[$this->depth]; + } + // get element prefix + if ($prefix = $this->getPrefix($name)){ + // get unqualified name + $name = $this->getLocalPart($name); + } else { + $prefix = ''; + } + // move on... + if($name == 'complexType'){ + $this->xdebug('done processing complexType ' . ($this->currentComplexType ? $this->currentComplexType : '(unknown)')); + $this->xdebug($this->varDump($this->complexTypes[$this->currentComplexType])); + $this->currentComplexType = array_pop($this->complexTypeStack); + //$this->currentElement = false; + } + if($name == 'element'){ + $this->xdebug('done processing element ' . ($this->currentElement ? $this->currentElement : '(unknown)')); + $this->currentElement = array_pop($this->elementStack); + } + if($name == 'simpleType'){ + $this->xdebug('done processing simpleType ' . ($this->currentSimpleType ? $this->currentSimpleType : '(unknown)')); + $this->xdebug($this->varDump($this->simpleTypes[$this->currentSimpleType])); + $this->currentSimpleType = array_pop($this->simpleTypeStack); + } + } + + /** + * element content handler + * + * @param string $parser XML parser object + * @param string $data element content + * @access private + */ + function schemaCharacterData($parser, $data){ + $pos = $this->depth_array[$this->depth - 1]; + $this->message[$pos]['cdata'] .= $data; + } + + /** + * serialize the schema + * + * @access public + */ + function serializeSchema(){ + + $schemaPrefix = $this->getPrefixFromNamespace($this->XMLSchemaVersion); + $xml = ''; + // imports + $schemaLocationCount = 0; + if (sizeof($this->imports) > 0) { + foreach($this->imports as $ns => $list) { + foreach ($list as $ii) { + if ($ii['location'] != '') { + $xml .= " <$schemaPrefix:import location=\"" . $ii['location'] . '" namespace="' . $ns . "\" />\n"; + } else { + if ($schemaLocationCount == 0) { + $xml .= " <$schemaPrefix:import namespace=\"" . $ns . "\" schemaLocation=\"" . $ns . "\"/>\n"; + } else { + $xml .= " <$schemaPrefix:import namespace=\"" . $ns . "\" />\n"; + } + } + } + } + } + // complex types + foreach($this->complexTypes as $typeName => $attrs){ + $contentStr = ''; + // serialize child elements + if(isset($attrs['elements']) && (count($attrs['elements']) > 0)){ + foreach($attrs['elements'] as $element => $eParts){ + if(isset($eParts['ref'])){ + $contentStr .= " <$schemaPrefix:element ref=\"$element\"/>\n"; + } else { + $contentStr .= " <$schemaPrefix:element name=\"$element\" type=\"" . $this->contractQName($eParts['type']) . "\""; + foreach ($eParts as $aName => $aValue) { + // handle, e.g., abstract, default, form, minOccurs, maxOccurs, nillable + if ($aName != 'name' && $aName != 'type') { + $contentStr .= " $aName=\"$aValue\""; + } + } + $contentStr .= "/>\n"; + } + } + // compositor wraps elements + if (isset($attrs['compositor']) && ($attrs['compositor'] != '')) { + $contentStr = " <$schemaPrefix:$attrs[compositor]>\n".$contentStr." \n"; + } + } + // attributes + if(isset($attrs['attrs']) && (count($attrs['attrs']) >= 1)){ + foreach($attrs['attrs'] as $attr => $aParts){ + $contentStr .= " <$schemaPrefix:attribute"; + foreach ($aParts as $a => $v) { + if ($a == 'ref' || $a == 'type') { + $contentStr .= " $a=\"".$this->contractQName($v).'"'; + } elseif ($a == 'http://schemas.xmlsoap.org/wsdl/:arrayType') { + $this->usedNamespaces['wsdl'] = $this->namespaces['wsdl']; + $contentStr .= ' wsdl:arrayType="'.$this->contractQName($v).'"'; + } else { + $contentStr .= " $a=\"$v\""; + } + } + $contentStr .= "/>\n"; + } + } + // if restriction + if (isset($attrs['restrictionBase']) && $attrs['restrictionBase'] != ''){ + $contentStr = " <$schemaPrefix:restriction base=\"".$this->contractQName($attrs['restrictionBase'])."\">\n".$contentStr." \n"; + // complex or simple content + if ((isset($attrs['elements']) && count($attrs['elements']) > 0) || (isset($attrs['attrs']) && count($attrs['attrs']) > 0)){ + $contentStr = " <$schemaPrefix:complexContent>\n".$contentStr." \n"; + } + } + // finalize complex type + if($contentStr != ''){ + $contentStr = " <$schemaPrefix:complexType name=\"$typeName\">\n".$contentStr." \n"; + } else { + $contentStr = " <$schemaPrefix:complexType name=\"$typeName\"/>\n"; + } + $xml .= $contentStr; + } + // simple types + if(isset($this->simpleTypes) && count($this->simpleTypes) > 0){ + foreach($this->simpleTypes as $typeName => $eParts){ + $xml .= " <$schemaPrefix:simpleType name=\"$typeName\">\n <$schemaPrefix:restriction base=\"".$this->contractQName($eParts['type'])."\">\n"; + if (isset($eParts['enumeration'])) { + foreach ($eParts['enumeration'] as $e) { + $xml .= " <$schemaPrefix:enumeration value=\"$e\"/>\n"; + } + } + $xml .= " \n "; + } + } + // elements + if(isset($this->elements) && count($this->elements) > 0){ + foreach($this->elements as $element => $eParts){ + $xml .= " <$schemaPrefix:element name=\"$element\" type=\"".$this->contractQName($eParts['type'])."\"/>\n"; + } + } + // attributes + if(isset($this->attributes) && count($this->attributes) > 0){ + foreach($this->attributes as $attr => $aParts){ + $xml .= " <$schemaPrefix:attribute name=\"$attr\" type=\"".$this->contractQName($aParts['type'])."\"\n/>"; + } + } + // finish 'er up + $attr = ''; + foreach ($this->schemaInfo as $k => $v) { + if ($k == 'elementFormDefault' || $k == 'attributeFormDefault') { + $attr .= " $k=\"$v\""; + } + } + $el = "<$schemaPrefix:schema$attr targetNamespace=\"$this->schemaTargetNamespace\"\n"; + foreach (array_diff($this->usedNamespaces, $this->enclosingNamespaces) as $nsp => $ns) { + $el .= " xmlns:$nsp=\"$ns\""; + } + $xml = $el . ">\n".$xml."\n"; + return $xml; + } + + /** + * adds debug data to the clas level debug string + * + * @param string $string debug data + * @access private + */ + function xdebug($string){ + if($this->debugLevel > 0) { + $this->debug('<' . $this->schemaTargetNamespace . '> '.$string); + } + } + + /** + * get the PHP type of a user defined type in the schema + * PHP type is kind of a misnomer since it actually returns 'struct' for assoc. arrays + * returns false if no type exists, or not w/ the given namespace + * else returns a string that is either a native php type, or 'struct' + * + * @param string $type name of defined type + * @param string $ns namespace of type + * @return mixed + * @access public + * @deprecated + */ + function getPHPType($type,$ns){ + if(isset($this->typemap[$ns][$type])){ + //print "found type '$type' and ns $ns in typemap
    "; + return $this->typemap[$ns][$type]; + } elseif(isset($this->complexTypes[$type])){ + //print "getting type '$type' and ns $ns from complexTypes array
    "; + return $this->complexTypes[$type]['phpType']; + } + return false; + } + + /** + * returns an associative array of information about a given type + * returns false if no type exists by the given name + * + * For a complexType typeDef = array( + * 'restrictionBase' => '', + * 'phpType' => '', + * 'compositor' => '(sequence|all)', + * 'elements' => array(), // refs to elements array + * 'attrs' => array() // refs to attributes array + * ... and so on (see addComplexType) + * ) + * + * For simpleType or element, the array has different keys. + * + * @param string $type + * @return mixed + * @access public + * @see addComplexType + * @see addSimpleType + * @see addElement + */ + function getTypeDef($type){ + //$this->debug("in getTypeDef for type $type"); + if (substr($type, -1) == '^') { + $is_element = 1; + $type = substr($type, 0, -1); + } else { + $is_element = 0; + } + + if((! $is_element) && isset($this->complexTypes[$type])){ + $this->xdebug("in getTypeDef, found complexType $type"); + return $this->complexTypes[$type]; + } elseif((! $is_element) && isset($this->simpleTypes[$type])){ + $this->xdebug("in getTypeDef, found simpleType $type"); + if (!isset($this->simpleTypes[$type]['phpType'])) { + // get info for type to tack onto the simple type + // TODO: can this ever really apply (i.e. what is a simpleType really?) + $uqType = substr($this->simpleTypes[$type]['type'], strrpos($this->simpleTypes[$type]['type'], ':') + 1); + $ns = substr($this->simpleTypes[$type]['type'], 0, strrpos($this->simpleTypes[$type]['type'], ':')); + $etype = $this->getTypeDef($uqType); + if ($etype) { + $this->xdebug("in getTypeDef, found type for simpleType $type:"); + $this->xdebug($this->varDump($etype)); + if (isset($etype['phpType'])) { + $this->simpleTypes[$type]['phpType'] = $etype['phpType']; + } + if (isset($etype['elements'])) { + $this->simpleTypes[$type]['elements'] = $etype['elements']; + } + } + } + return $this->simpleTypes[$type]; + } elseif(isset($this->elements[$type])){ + $this->xdebug("in getTypeDef, found element $type"); + if (!isset($this->elements[$type]['phpType'])) { + // get info for type to tack onto the element + $uqType = substr($this->elements[$type]['type'], strrpos($this->elements[$type]['type'], ':') + 1); + $ns = substr($this->elements[$type]['type'], 0, strrpos($this->elements[$type]['type'], ':')); + $etype = $this->getTypeDef($uqType); + if ($etype) { + $this->xdebug("in getTypeDef, found type for element $type:"); + $this->xdebug($this->varDump($etype)); + if (isset($etype['phpType'])) { + $this->elements[$type]['phpType'] = $etype['phpType']; + } + if (isset($etype['elements'])) { + $this->elements[$type]['elements'] = $etype['elements']; + } + if (isset($etype['extensionBase'])) { + $this->elements[$type]['extensionBase'] = $etype['extensionBase']; + } + } elseif ($ns == 'http://www.w3.org/2001/XMLSchema') { + $this->xdebug("in getTypeDef, element $type is an XSD type"); + $this->elements[$type]['phpType'] = 'scalar'; + } + } + return $this->elements[$type]; + } elseif(isset($this->attributes[$type])){ + $this->xdebug("in getTypeDef, found attribute $type"); + return $this->attributes[$type]; + } elseif (preg_match('/_ContainedType$/', $type)) { + $this->xdebug("in getTypeDef, have an untyped element $type"); + $typeDef['typeClass'] = 'simpleType'; + $typeDef['phpType'] = 'scalar'; + $typeDef['type'] = 'http://www.w3.org/2001/XMLSchema:string'; + return $typeDef; + } + $this->xdebug("in getTypeDef, did not find $type"); + return false; + } + + /** + * returns a sample serialization of a given type, or false if no type by the given name + * + * @param string $type name of type + * @return mixed + * @access public + * @deprecated + */ + function serializeTypeDef($type){ + //print "in sTD() for type $type
    "; + if($typeDef = $this->getTypeDef($type)){ + $str .= '<'.$type; + if(is_array($typeDef['attrs'])){ + foreach($typeDef['attrs'] as $attName => $data){ + $str .= " $attName=\"{type = ".$data['type']."}\""; + } + } + $str .= " xmlns=\"".$this->schema['targetNamespace']."\""; + if(count($typeDef['elements']) > 0){ + $str .= ">"; + foreach($typeDef['elements'] as $element => $eData){ + $str .= $this->serializeTypeDef($element); + } + $str .= ""; + } elseif($typeDef['typeClass'] == 'element') { + $str .= ">"; + } else { + $str .= "/>"; + } + return $str; + } + return false; + } + + /** + * returns HTML form elements that allow a user + * to enter values for creating an instance of the given type. + * + * @param string $name name for type instance + * @param string $type name of type + * @return string + * @access public + * @deprecated + */ + function typeToForm($name,$type){ + // get typedef + if($typeDef = $this->getTypeDef($type)){ + // if struct + if($typeDef['phpType'] == 'struct'){ + $buffer .= ''; + foreach($typeDef['elements'] as $child => $childDef){ + $buffer .= " + + "; + } + $buffer .= '
    $childDef[name] (type: ".$this->getLocalPart($childDef['type'])."):
    '; + // if array + } elseif($typeDef['phpType'] == 'array'){ + $buffer .= ''; + for($i=0;$i < 3; $i++){ + $buffer .= " + + "; + } + $buffer .= '
    array item (type: $typeDef[arrayType]):
    '; + // if scalar + } else { + $buffer .= ""; + } + } else { + $buffer .= ""; + } + return $buffer; + } + + /** + * adds a complex type to the schema + * + * example: array + * + * addType( + * 'ArrayOfstring', + * 'complexType', + * 'array', + * '', + * 'SOAP-ENC:Array', + * array('ref'=>'SOAP-ENC:arrayType','wsdl:arrayType'=>'string[]'), + * 'xsd:string' + * ); + * + * example: PHP associative array ( SOAP Struct ) + * + * addType( + * 'SOAPStruct', + * 'complexType', + * 'struct', + * 'all', + * array('myVar'=> array('name'=>'myVar','type'=>'string') + * ); + * + * @param name + * @param typeClass (complexType|simpleType|attribute) + * @param phpType: currently supported are array and struct (php assoc array) + * @param compositor (all|sequence|choice) + * @param restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array) + * @param elements = array ( name = array(name=>'',type=>'') ) + * @param attrs = array( + * array( + * 'ref' => "http://schemas.xmlsoap.org/soap/encoding/:arrayType", + * "http://schemas.xmlsoap.org/wsdl/:arrayType" => "string[]" + * ) + * ) + * @param arrayType: namespace:name (http://www.w3.org/2001/XMLSchema:string) + * @access public + * @see getTypeDef + */ + function addComplexType($name,$typeClass='complexType',$phpType='array',$compositor='',$restrictionBase='',$elements=array(),$attrs=array(),$arrayType=''){ + $this->complexTypes[$name] = array( + 'name' => $name, + 'typeClass' => $typeClass, + 'phpType' => $phpType, + 'compositor'=> $compositor, + 'restrictionBase' => $restrictionBase, + 'elements' => $elements, + 'attrs' => $attrs, + 'arrayType' => $arrayType + ); + + $this->xdebug("addComplexType $name:"); + $this->appendDebug($this->varDump($this->complexTypes[$name])); + } + + /** + * adds a simple type to the schema + * + * @param string $name + * @param string $restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array) + * @param string $typeClass (should always be simpleType) + * @param string $phpType (should always be scalar) + * @param array $enumeration array of values + * @access public + * @see nusoap_xmlschema + * @see getTypeDef + */ + function addSimpleType($name, $restrictionBase='', $typeClass='simpleType', $phpType='scalar', $enumeration=array()) { + $this->simpleTypes[$name] = array( + 'name' => $name, + 'typeClass' => $typeClass, + 'phpType' => $phpType, + 'type' => $restrictionBase, + 'enumeration' => $enumeration + ); + + $this->xdebug("addSimpleType $name:"); + $this->appendDebug($this->varDump($this->simpleTypes[$name])); + } + + /** + * adds an element to the schema + * + * @param array $attrs attributes that must include name and type + * @see nusoap_xmlschema + * @access public + */ + function addElement($attrs) { + if (! $this->getPrefix($attrs['type'])) { + $attrs['type'] = $this->schemaTargetNamespace . ':' . $attrs['type']; + } + $this->elements[ $attrs['name'] ] = $attrs; + $this->elements[ $attrs['name'] ]['typeClass'] = 'element'; + + $this->xdebug("addElement " . $attrs['name']); + $this->appendDebug($this->varDump($this->elements[ $attrs['name'] ])); + } +} + +/** + * Backward compatibility + */ +class XMLSchema extends nusoap_xmlschema { +} + +?> + bug 40066 + +r58361 - 2010-09-29 16:59:02 -0700 (Wed, 29 Sep 2010) - kjing - Author: Jenny Gonsalves + Merging with maint_6_0_1 (svn merge -r 58250:58342) + +r57813 - 2010-08-19 10:34:44 -0700 (Thu, 19 Aug 2010) - kjing - Author: John Mertic + Bug 39085 - When loading the opposite search panel via ajax on the ListViews, call the index action instead of the ListView action to avoid touching pre-MVC code by accident. + +r57707 - 2010-08-10 12:26:13 -0700 (Tue, 10 Aug 2010) - kjing - Author: Stanislav Malyshev + fix SOAP calls with no parameters + +r56990 - 2010-06-16 13:05:36 -0700 (Wed, 16 Jun 2010) - kjing - snapshot "Mango" svn branch to a new one for GitHub sync + +r56989 - 2010-06-16 13:01:33 -0700 (Wed, 16 Jun 2010) - kjing - defunt "Mango" svn dev branch before github cutover + +r55980 - 2010-04-19 13:31:28 -0700 (Mon, 19 Apr 2010) - kjing - create Mango (6.1) based on windex + +r51719 - 2009-10-22 10:18:00 -0700 (Thu, 22 Oct 2009) - mitani - Converted to Build 3 tags and updated the build system + +r51634 - 2009-10-19 13:32:22 -0700 (Mon, 19 Oct 2009) - mitani - Windex is the branch for Sugar Sales 1.0 development + +r51508 - 2009-10-14 07:40:23 -0700 (Wed, 14 Oct 2009) - jmertic - More fallout fixes from the PHP 5.3 ereg to preg changes. + +r51455 - 2009-10-13 07:56:48 -0700 (Tue, 13 Oct 2009) - jmertic - Bug 33202 - Enable install of SugarCRM on PHP 5.3.0, asserting that the minimum supported version is PHP 5.2.x. + +r51443 - 2009-10-12 13:34:36 -0700 (Mon, 12 Oct 2009) - jmertic - Bug 33332 - Made application PHP 5.3 compliant with E_DEPRECATED warnings on by: +- Changing all ereg function to either preg or simple string based ones +- No more references to magic quotes. +- Change all the session_unregister() functions to just unset() the correct session variable instead. + +r50375 - 2009-08-24 18:07:43 -0700 (Mon, 24 Aug 2009) - dwong - branch kobe2 from tokyo r50372 + +r45763 - 2009-04-01 12:16:18 -0700 (Wed, 01 Apr 2009) - majed - Removed half of the require_once and include_onces in the product that were redundant or could be handled easily by the auto loader + +r45680 - 2009-03-30 14:34:35 -0700 (Mon, 30 Mar 2009) - Samir Gandhi - modifeid serializeSchema to generate WS-I compliant WSDL + +r42807 - 2008-12-29 11:16:59 -0800 (Mon, 29 Dec 2008) - dwong - Branch from trunk/sugarcrm r42806 to branches/tokyo/sugarcrm + +r42645 - 2008-12-18 13:41:08 -0800 (Thu, 18 Dec 2008) - awu - merging maint_5_2_0 rev41336:HEAD to trunk + +r41647 - 2008-11-11 17:44:30 -0800 (Tue, 11 Nov 2008) - majed - Fixes a few bugs + +r41596 - 2008-11-10 19:20:04 -0800 (Mon, 10 Nov 2008) - Samir Gandhi - modified to set $method in the code + +r41558 - 2008-11-10 14:35:34 -0800 (Mon, 10 Nov 2008) - majed - changes nusoap to allow for registering classes + +r39619 - 2008-09-09 13:41:34 -0700 (Tue, 09 Sep 2008) - jmertic - Bug 24827 - Remove all instances where we return a new object and assign it by reference, since this is deprecated in PHP 5 and emits E_DEPRECATED errors in PHP 5.3. +Touched: +- data/SugarBean.php +- include/domit/php_http_client_generic.php +- include/domit/php_http_connector.php +- include/domit/testing_domit.php +- include/domit/xml_domit_getelementsbypath.php +- include/domit/xml_domit_lite_parser.php +- include/domit/xml_domit_nodemaps.php +- include/domit/xml_domit_parser.php +- include/domit/xml_domit_shared.php +- include/generic/SugarWidgets/SugarWidgetField.php +- include/generic/SugarWidgets/SugarWidgetReportField.php +- include/ListView/ProcessView.php +- include/nusoap/class.soapclient.php +- include/nusoap/nusoap.php +- include/nusoap/nusoapmime.php +- include/Pear/HTML_Safe/Safe.php +- include/Pear/XML_HTMLSax3/HTMLSax3.php +- modules/Administration/RebuildWorkFlow.php +- modules/Expressions/RelateSelector.php +- modules/Reports/templates/templates_reports.php +- modules/WorkFlow/Delete.php +- modules/WorkFlow/Save.php +- modules/WorkFlow/SaveSequence.php +- modules/WorkFlow/WorkFlow.php +- modules/WorkFlowActionShells/CreateStep1.php +- modules/WorkFlowActionShells/CreateStep2.php +- modules/WorkFlowActionShells/Save.php +- modules/WorkFlowActionShells/WorkFlowActionShell.php +- modules/WorkFlowAlerts/Save.php +- modules/WorkFlowAlerts/WorkFlowAlert.php +- modules/WorkFlowAlertShells/DetailView.php +- modules/WorkFlowAlertShells/WorkFlowAlertShell.php +- modules/WorkFlowTriggerShells/CreateStep1.php +- modules/WorkFlowTriggerShells/CreateStepFilter.php +- modules/WorkFlowTriggerShells/SaveFilter.php +- modules/WorkFlowTriggerShells/WorkFlowTriggerShell.php +- soap/SoapHelperFunctions.php +- test/modules/DynamicFields/DynamicFields_Bug24095_test.php +- test/simpletest/browser.php +- test/simpletest/default_reporter.php +- test/simpletest/detached.php +- test/simpletest/eclipse.php +- test/simpletest/expectation.php +- test/simpletest/extensions/pear_test_case.php +- test/simpletest/form.php +- test/simpletest/http.php +- test/simpletest/mock_objects.php +- test/simpletest/page.php +- test/simpletest/parser.php +- test/simpletest/remote.php +- test/simpletest/shell_tester.php +- test/simpletest/simple_test.php +- test/simpletest/simpletest.php +- test/simpletest/test/acceptance_test.php +- test/simpletest/test/adapter_test.php +- test/simpletest/test/authentication_test.php +- test/simpletest/test/browser_test.php +- test/simpletest/test/collector_test.php +- test/simpletest/test/compatibility_test.php +- test/simpletest/test/detached_test.php +- test/simpletest/test/eclipse_test.php +- test/simpletest/test/encoding_test.php +- test/simpletest/test/errors_test.php +- test/simpletest/test/expectation_test.php +- test/simpletest/test/form_test.php +- test/simpletest/test/frames_test.php +- test/simpletest/test/http_test.php +- test/simpletest/test/live_test.php +- test/simpletest/test/mock_objects_test.php +- test/simpletest/test/page_test.php +- test/simpletest/test/parse_error_test.php +- test/simpletest/test/parser_test.php +- test/simpletest/test/remote_test.php +- test/simpletest/test/shell_test.php +- test/simpletest/test/shell_tester_test.php +- test/simpletest/test/simpletest_test.php +- test/simpletest/test/site/page_request.php +- test/simpletest/test/tag_test.php +- test/simpletest/test/unit_tester_test.php +- test/simpletest/test/user_agent_test.php +- test/simpletest/test/visual_test.php +- test/simpletest/test/xml_test.php +- test/simpletest/test_case.php +- test/simpletest/ui/array_reporter/test.php +- test/simpletest/ui/recorder/test.php +- test/simpletest/unit_tester.php +- test/simpletest/url.php +- test/simpletest/user_agent.php +- test/simpletest/web_tester.php +- test/spikephpcoverage/src/PEAR.php +- test/spikephpcoverage/src/util/Utility.php +- test/spikephpcoverage/src/XML/Parser.php +- test/spikephpcoverage/src/XML/Parser/Simple.php +- test/test_utilities/SugarTest_SimpleBrowser.php + +r38362 - 2008-07-28 14:06:59 -0700 (Mon, 28 Jul 2008) - roger - bug: 23897. Using print_r when using the debug statement in nusoap will print out the statements to the screen if the call is coming from the UI. + +r38300 - 2008-07-25 13:33:43 -0700 (Fri, 25 Jul 2008) - Samir Gandhi - put the debug in parseresponse function + +r38293 - 2008-07-25 12:32:34 -0700 (Fri, 25 Jul 2008) - Samir Gandhi - to put all the debug statements return value in the call function + +r36824 - 2008-06-18 09:26:11 -0700 (Wed, 18 Jun 2008) - roger - bug: 21832 + +r26422 - 2007-09-05 17:29:12 -0700 (Wed, 05 Sep 2007) - majed - migrate from beta 1 to trunk + +r15787 - 2006-08-10 10:14:41 -0700 (Thu, 10 Aug 2006) - roger - RRS: bug 7961 + +r14701 - 2006-07-17 13:37:26 -0700 (Mon, 17 Jul 2006) - roger - RRS: bug 5801 + +r13782 - 2006-06-06 10:58:55 -0700 (Tue, 06 Jun 2006) - majed - changes entry point code + +r11466 - 2006-02-01 15:49:47 -0800 (Wed, 01 Feb 2006) - jacob - Adding extra !empty check to get around a PHP warning. + +r11115 - 2006-01-17 14:54:45 -0800 (Tue, 17 Jan 2006) - majed - add entry point validation + +r10585 - 2005-12-13 14:42:26 -0800 (Tue, 13 Dec 2005) - majed - adds new license mechanisim + +r10170 - 2005-12-05 18:37:46 -0800 (Mon, 05 Dec 2005) - majed - fixes various issues + +r8999 - 2005-11-04 05:26:49 -0800 (Fri, 04 Nov 2005) - roger - When nusoap was upgraded we had an issue with the user's default language not being populated during a soap request. I determined the reason this was happening and have checked in the corresponding change to nusoap. + +r8991 - 2005-11-03 19:07:25 -0800 (Thu, 03 Nov 2005) - majed - fixes nusoap issue + +r8846 - 2005-10-31 11:01:12 -0800 (Mon, 31 Oct 2005) - majed - new version of nusoap + +r7905 - 2005-09-21 19:12:57 -0700 (Wed, 21 Sep 2005) - majed - restores old nusoap pre & with a few fixes + +r7861 - 2005-09-20 15:40:25 -0700 (Tue, 20 Sep 2005) - majed - & fix for 3.5.1 + +r7452 - 2005-08-17 11:32:34 -0700 (Wed, 17 Aug 2005) - majed - changes soap to nusoap + +r5820 - 2005-06-21 14:22:24 -0700 (Tue, 21 Jun 2005) - majed - fixes issues with nusoap and with custom fields + +r5462 - 2005-05-25 13:50:11 -0700 (Wed, 25 May 2005) - majed - upgraded nusoap to .6.9 + +r5104 - 2005-05-04 15:33:41 -0700 (Wed, 04 May 2005) - majed - gets rid of HTTP_GET_VARS and what not which has been deprecated + +r573 - 2004-09-04 13:03:32 -0700 (Sat, 04 Sep 2004) - sugarclint - undoing copyrights added in inadvertantly. --clint + +r546 - 2004-09-03 11:49:38 -0700 (Fri, 03 Sep 2004) - sugarmsi - removed echo count + +r354 - 2004-08-02 23:00:37 -0700 (Mon, 02 Aug 2004) - sugarjacob - Adding Soap + + +*/ + + + + + +/** +* For creating serializable abstractions of native PHP types. This class +* allows element name/namespace, XSD type, and XML attributes to be +* associated with a value. This is extremely useful when WSDL is not +* used, but is also useful when WSDL is used with polymorphic types, including +* xsd:anyType and user-defined types. +* +* @author Dietrich Ayala + +* @access public +*/ +class soapval extends nusoap_base { + /** + * The XML element name + * + * @var string + * @access private + */ + var $name; + /** + * The XML type name (string or false) + * + * @var mixed + * @access private + */ + var $type; + /** + * The PHP value + * + * @var mixed + * @access private + */ + var $value; + /** + * The XML element namespace (string or false) + * + * @var mixed + * @access private + */ + var $element_ns; + /** + * The XML type namespace (string or false) + * + * @var mixed + * @access private + */ + var $type_ns; + /** + * The XML element attributes (array or false) + * + * @var mixed + * @access private + */ + var $attributes; + + /** + * constructor + * + * @param string $name optional name + * @param mixed $type optional type name + * @param mixed $value optional value + * @param mixed $element_ns optional namespace of value + * @param mixed $type_ns optional namespace of type + * @param mixed $attributes associative array of attributes to add to element serialization + * @access public + */ + function soapval($name='soapval',$type=false,$value=-1,$element_ns=false,$type_ns=false,$attributes=false) { + parent::nusoap_base(); + $this->name = $name; + $this->type = $type; + $this->value = $value; + $this->element_ns = $element_ns; + $this->type_ns = $type_ns; + $this->attributes = $attributes; + } + + /** + * return serialized value + * + * @param string $use The WSDL use value (encoded|literal) + * @return string XML data + * @access public + */ + function serialize($use='encoded') { + return $this->serialize_val($this->value, $this->name, $this->type, $this->element_ns, $this->type_ns, $this->attributes, $use, true); + } + + /** + * decodes a soapval object into a PHP native type + * + * @return mixed + * @access public + */ + function decode(){ + return $this->value; + } +} + + + +?> + bug 40066 + +r58361 - 2010-09-29 16:59:02 -0700 (Wed, 29 Sep 2010) - kjing - Author: Jenny Gonsalves + Merging with maint_6_0_1 (svn merge -r 58250:58342) + +r57813 - 2010-08-19 10:34:44 -0700 (Thu, 19 Aug 2010) - kjing - Author: John Mertic + Bug 39085 - When loading the opposite search panel via ajax on the ListViews, call the index action instead of the ListView action to avoid touching pre-MVC code by accident. + +r57707 - 2010-08-10 12:26:13 -0700 (Tue, 10 Aug 2010) - kjing - Author: Stanislav Malyshev + fix SOAP calls with no parameters + +r56990 - 2010-06-16 13:05:36 -0700 (Wed, 16 Jun 2010) - kjing - snapshot "Mango" svn branch to a new one for GitHub sync + +r56989 - 2010-06-16 13:01:33 -0700 (Wed, 16 Jun 2010) - kjing - defunt "Mango" svn dev branch before github cutover + +r55980 - 2010-04-19 13:31:28 -0700 (Mon, 19 Apr 2010) - kjing - create Mango (6.1) based on windex + +r51719 - 2009-10-22 10:18:00 -0700 (Thu, 22 Oct 2009) - mitani - Converted to Build 3 tags and updated the build system + +r51634 - 2009-10-19 13:32:22 -0700 (Mon, 19 Oct 2009) - mitani - Windex is the branch for Sugar Sales 1.0 development + +r51508 - 2009-10-14 07:40:23 -0700 (Wed, 14 Oct 2009) - jmertic - More fallout fixes from the PHP 5.3 ereg to preg changes. + +r51455 - 2009-10-13 07:56:48 -0700 (Tue, 13 Oct 2009) - jmertic - Bug 33202 - Enable install of SugarCRM on PHP 5.3.0, asserting that the minimum supported version is PHP 5.2.x. + +r51443 - 2009-10-12 13:34:36 -0700 (Mon, 12 Oct 2009) - jmertic - Bug 33332 - Made application PHP 5.3 compliant with E_DEPRECATED warnings on by: +- Changing all ereg function to either preg or simple string based ones +- No more references to magic quotes. +- Change all the session_unregister() functions to just unset() the correct session variable instead. + +r50375 - 2009-08-24 18:07:43 -0700 (Mon, 24 Aug 2009) - dwong - branch kobe2 from tokyo r50372 + +r45763 - 2009-04-01 12:16:18 -0700 (Wed, 01 Apr 2009) - majed - Removed half of the require_once and include_onces in the product that were redundant or could be handled easily by the auto loader + +r45680 - 2009-03-30 14:34:35 -0700 (Mon, 30 Mar 2009) - Samir Gandhi - modifeid serializeSchema to generate WS-I compliant WSDL + +r42807 - 2008-12-29 11:16:59 -0800 (Mon, 29 Dec 2008) - dwong - Branch from trunk/sugarcrm r42806 to branches/tokyo/sugarcrm + +r42645 - 2008-12-18 13:41:08 -0800 (Thu, 18 Dec 2008) - awu - merging maint_5_2_0 rev41336:HEAD to trunk + +r41647 - 2008-11-11 17:44:30 -0800 (Tue, 11 Nov 2008) - majed - Fixes a few bugs + +r41596 - 2008-11-10 19:20:04 -0800 (Mon, 10 Nov 2008) - Samir Gandhi - modified to set $method in the code + +r41558 - 2008-11-10 14:35:34 -0800 (Mon, 10 Nov 2008) - majed - changes nusoap to allow for registering classes + +r39619 - 2008-09-09 13:41:34 -0700 (Tue, 09 Sep 2008) - jmertic - Bug 24827 - Remove all instances where we return a new object and assign it by reference, since this is deprecated in PHP 5 and emits E_DEPRECATED errors in PHP 5.3. +Touched: +- data/SugarBean.php +- include/domit/php_http_client_generic.php +- include/domit/php_http_connector.php +- include/domit/testing_domit.php +- include/domit/xml_domit_getelementsbypath.php +- include/domit/xml_domit_lite_parser.php +- include/domit/xml_domit_nodemaps.php +- include/domit/xml_domit_parser.php +- include/domit/xml_domit_shared.php +- include/generic/SugarWidgets/SugarWidgetField.php +- include/generic/SugarWidgets/SugarWidgetReportField.php +- include/ListView/ProcessView.php +- include/nusoap/class.soapclient.php +- include/nusoap/nusoap.php +- include/nusoap/nusoapmime.php +- include/Pear/HTML_Safe/Safe.php +- include/Pear/XML_HTMLSax3/HTMLSax3.php +- modules/Administration/RebuildWorkFlow.php +- modules/Expressions/RelateSelector.php +- modules/Reports/templates/templates_reports.php +- modules/WorkFlow/Delete.php +- modules/WorkFlow/Save.php +- modules/WorkFlow/SaveSequence.php +- modules/WorkFlow/WorkFlow.php +- modules/WorkFlowActionShells/CreateStep1.php +- modules/WorkFlowActionShells/CreateStep2.php +- modules/WorkFlowActionShells/Save.php +- modules/WorkFlowActionShells/WorkFlowActionShell.php +- modules/WorkFlowAlerts/Save.php +- modules/WorkFlowAlerts/WorkFlowAlert.php +- modules/WorkFlowAlertShells/DetailView.php +- modules/WorkFlowAlertShells/WorkFlowAlertShell.php +- modules/WorkFlowTriggerShells/CreateStep1.php +- modules/WorkFlowTriggerShells/CreateStepFilter.php +- modules/WorkFlowTriggerShells/SaveFilter.php +- modules/WorkFlowTriggerShells/WorkFlowTriggerShell.php +- soap/SoapHelperFunctions.php +- test/modules/DynamicFields/DynamicFields_Bug24095_test.php +- test/simpletest/browser.php +- test/simpletest/default_reporter.php +- test/simpletest/detached.php +- test/simpletest/eclipse.php +- test/simpletest/expectation.php +- test/simpletest/extensions/pear_test_case.php +- test/simpletest/form.php +- test/simpletest/http.php +- test/simpletest/mock_objects.php +- test/simpletest/page.php +- test/simpletest/parser.php +- test/simpletest/remote.php +- test/simpletest/shell_tester.php +- test/simpletest/simple_test.php +- test/simpletest/simpletest.php +- test/simpletest/test/acceptance_test.php +- test/simpletest/test/adapter_test.php +- test/simpletest/test/authentication_test.php +- test/simpletest/test/browser_test.php +- test/simpletest/test/collector_test.php +- test/simpletest/test/compatibility_test.php +- test/simpletest/test/detached_test.php +- test/simpletest/test/eclipse_test.php +- test/simpletest/test/encoding_test.php +- test/simpletest/test/errors_test.php +- test/simpletest/test/expectation_test.php +- test/simpletest/test/form_test.php +- test/simpletest/test/frames_test.php +- test/simpletest/test/http_test.php +- test/simpletest/test/live_test.php +- test/simpletest/test/mock_objects_test.php +- test/simpletest/test/page_test.php +- test/simpletest/test/parse_error_test.php +- test/simpletest/test/parser_test.php +- test/simpletest/test/remote_test.php +- test/simpletest/test/shell_test.php +- test/simpletest/test/shell_tester_test.php +- test/simpletest/test/simpletest_test.php +- test/simpletest/test/site/page_request.php +- test/simpletest/test/tag_test.php +- test/simpletest/test/unit_tester_test.php +- test/simpletest/test/user_agent_test.php +- test/simpletest/test/visual_test.php +- test/simpletest/test/xml_test.php +- test/simpletest/test_case.php +- test/simpletest/ui/array_reporter/test.php +- test/simpletest/ui/recorder/test.php +- test/simpletest/unit_tester.php +- test/simpletest/url.php +- test/simpletest/user_agent.php +- test/simpletest/web_tester.php +- test/spikephpcoverage/src/PEAR.php +- test/spikephpcoverage/src/util/Utility.php +- test/spikephpcoverage/src/XML/Parser.php +- test/spikephpcoverage/src/XML/Parser/Simple.php +- test/test_utilities/SugarTest_SimpleBrowser.php + +r38362 - 2008-07-28 14:06:59 -0700 (Mon, 28 Jul 2008) - roger - bug: 23897. Using print_r when using the debug statement in nusoap will print out the statements to the screen if the call is coming from the UI. + +r38300 - 2008-07-25 13:33:43 -0700 (Fri, 25 Jul 2008) - Samir Gandhi - put the debug in parseresponse function + +r38293 - 2008-07-25 12:32:34 -0700 (Fri, 25 Jul 2008) - Samir Gandhi - to put all the debug statements return value in the call function + +r36824 - 2008-06-18 09:26:11 -0700 (Wed, 18 Jun 2008) - roger - bug: 21832 + +r26422 - 2007-09-05 17:29:12 -0700 (Wed, 05 Sep 2007) - majed - migrate from beta 1 to trunk + +r15787 - 2006-08-10 10:14:41 -0700 (Thu, 10 Aug 2006) - roger - RRS: bug 7961 + +r14701 - 2006-07-17 13:37:26 -0700 (Mon, 17 Jul 2006) - roger - RRS: bug 5801 + +r13782 - 2006-06-06 10:58:55 -0700 (Tue, 06 Jun 2006) - majed - changes entry point code + +r11466 - 2006-02-01 15:49:47 -0800 (Wed, 01 Feb 2006) - jacob - Adding extra !empty check to get around a PHP warning. + +r11115 - 2006-01-17 14:54:45 -0800 (Tue, 17 Jan 2006) - majed - add entry point validation + +r10585 - 2005-12-13 14:42:26 -0800 (Tue, 13 Dec 2005) - majed - adds new license mechanisim + +r10170 - 2005-12-05 18:37:46 -0800 (Mon, 05 Dec 2005) - majed - fixes various issues + +r8999 - 2005-11-04 05:26:49 -0800 (Fri, 04 Nov 2005) - roger - When nusoap was upgraded we had an issue with the user's default language not being populated during a soap request. I determined the reason this was happening and have checked in the corresponding change to nusoap. + +r8991 - 2005-11-03 19:07:25 -0800 (Thu, 03 Nov 2005) - majed - fixes nusoap issue + +r8846 - 2005-10-31 11:01:12 -0800 (Mon, 31 Oct 2005) - majed - new version of nusoap + +r7905 - 2005-09-21 19:12:57 -0700 (Wed, 21 Sep 2005) - majed - restores old nusoap pre & with a few fixes + +r7861 - 2005-09-20 15:40:25 -0700 (Tue, 20 Sep 2005) - majed - & fix for 3.5.1 + +r7452 - 2005-08-17 11:32:34 -0700 (Wed, 17 Aug 2005) - majed - changes soap to nusoap + +r5820 - 2005-06-21 14:22:24 -0700 (Tue, 21 Jun 2005) - majed - fixes issues with nusoap and with custom fields + +r5462 - 2005-05-25 13:50:11 -0700 (Wed, 25 May 2005) - majed - upgraded nusoap to .6.9 + +r5104 - 2005-05-04 15:33:41 -0700 (Wed, 04 May 2005) - majed - gets rid of HTTP_GET_VARS and what not which has been deprecated + +r573 - 2004-09-04 13:03:32 -0700 (Sat, 04 Sep 2004) - sugarclint - undoing copyrights added in inadvertantly. --clint + +r546 - 2004-09-03 11:49:38 -0700 (Fri, 03 Sep 2004) - sugarmsi - removed echo count + +r354 - 2004-08-02 23:00:37 -0700 (Mon, 02 Aug 2004) - sugarjacob - Adding Soap + + +*/ + + + + + +/** +* transport class for sending/receiving data via HTTP and HTTPS +* NOTE: PHP must be compiled with the CURL extension for HTTPS support +* +* @author Dietrich Ayala +* @author Scott Nichol + +* @access public +*/ +class soap_transport_http extends nusoap_base { + + var $url = ''; + var $uri = ''; + var $digest_uri = ''; + var $scheme = ''; + var $host = ''; + var $port = ''; + var $path = ''; + var $request_method = 'POST'; + var $protocol_version = '1.0'; + var $encoding = ''; + var $outgoing_headers = array(); + var $incoming_headers = array(); + var $incoming_cookies = array(); + var $outgoing_payload = ''; + var $incoming_payload = ''; + var $response_status_line; // HTTP response status line + var $useSOAPAction = true; + var $persistentConnection = false; + var $ch = false; // cURL handle + var $ch_options = array(); // cURL custom options + var $use_curl = false; // force cURL use + var $proxy = null; // proxy information (associative array) + var $username = ''; + var $password = ''; + var $authtype = ''; + var $digestRequest = array(); + var $certRequest = array(); // keys must be cainfofile (optional), sslcertfile, sslkeyfile, passphrase, certpassword (optional), verifypeer (optional), verifyhost (optional) + // cainfofile: certificate authority file, e.g. '$pathToPemFiles/rootca.pem' + // sslcertfile: SSL certificate file, e.g. '$pathToPemFiles/mycert.pem' + // sslkeyfile: SSL key file, e.g. '$pathToPemFiles/mykey.pem' + // passphrase: SSL key password/passphrase + // certpassword: SSL certificate password + // verifypeer: default is 1 + // verifyhost: default is 1 + + /** + * constructor + * + * @param string $url The URL to which to connect + * @param array $curl_options User-specified cURL options + * @param boolean $use_curl Whether to try to force cURL use + * @access public + */ + function soap_transport_http($url, $curl_options = NULL, $use_curl = false){ + parent::nusoap_base(); + $this->debug("ctor url=$url use_curl=$use_curl curl_options:"); + $this->appendDebug($this->varDump($curl_options)); + $this->setURL($url); + if (is_array($curl_options)) { + $this->ch_options = $curl_options; + } + $this->use_curl = $use_curl; + preg_match('/\$Revisio' . 'n: ([^ ]+)/', $this->revision, $rev); + $this->setHeader('User-Agent', $this->title.'/'.$this->version.' ('.$rev[1].')'); + } + + /** + * sets a cURL option + * + * @param mixed $option The cURL option (always integer?) + * @param mixed $value The cURL option value + * @access private + */ + function setCurlOption($option, $value) { + $this->debug("setCurlOption option=$option, value="); + $this->appendDebug($this->varDump($value)); + curl_setopt($this->ch, $option, $value); + } + + /** + * sets an HTTP header + * + * @param string $name The name of the header + * @param string $value The value of the header + * @access private + */ + function setHeader($name, $value) { + $this->outgoing_headers[$name] = $value; + $this->debug("set header $name: $value"); + } + + /** + * unsets an HTTP header + * + * @param string $name The name of the header + * @access private + */ + function unsetHeader($name) { + if (isset($this->outgoing_headers[$name])) { + $this->debug("unset header $name"); + unset($this->outgoing_headers[$name]); + } + } + + /** + * sets the URL to which to connect + * + * @param string $url The URL to which to connect + * @access private + */ + function setURL($url) { + $this->url = $url; + + $u = parse_url($url); + foreach($u as $k => $v){ + $this->debug("parsed URL $k = $v"); + $this->$k = $v; + } + + // add any GET params to path + if(isset($u['query']) && $u['query'] != ''){ + $this->path .= '?' . $u['query']; + } + + // set default port + if(!isset($u['port'])){ + if($u['scheme'] == 'https'){ + $this->port = 443; + } else { + $this->port = 80; + } + } + + $this->uri = $this->path; + $this->digest_uri = $this->uri; + + // build headers + if (!isset($u['port'])) { + $this->setHeader('Host', $this->host); + } else { + $this->setHeader('Host', $this->host.':'.$this->port); + } + + if (isset($u['user']) && $u['user'] != '') { + $this->setCredentials(urldecode($u['user']), isset($u['pass']) ? urldecode($u['pass']) : ''); + } + } + + /** + * gets the I/O method to use + * + * @return string I/O method to use (socket|curl|unknown) + * @access private + */ + function io_method() { + if ($this->use_curl || ($this->scheme == 'https') || ($this->scheme == 'http' && $this->authtype == 'ntlm') || ($this->scheme == 'http' && is_array($this->proxy) && $this->proxy['authtype'] == 'ntlm')) + return 'curl'; + if (($this->scheme == 'http' || $this->scheme == 'ssl') && $this->authtype != 'ntlm' && (!is_array($this->proxy) || $this->proxy['authtype'] != 'ntlm')) + return 'socket'; + return 'unknown'; + } + + /** + * establish an HTTP connection + * + * @param integer $timeout set connection timeout in seconds + * @param integer $response_timeout set response timeout in seconds + * @return boolean true if connected, false if not + * @access private + */ + function connect($connection_timeout=0,$response_timeout=30){ + // For PHP 4.3 with OpenSSL, change https scheme to ssl, then treat like + // "regular" socket. + // TODO: disabled for now because OpenSSL must be *compiled* in (not just + // loaded), and until PHP5 stream_get_wrappers is not available. +// if ($this->scheme == 'https') { +// if (version_compare(phpversion(), '4.3.0') >= 0) { +// if (extension_loaded('openssl')) { +// $this->scheme = 'ssl'; +// $this->debug('Using SSL over OpenSSL'); +// } +// } +// } + $this->debug("connect connection_timeout $connection_timeout, response_timeout $response_timeout, scheme $this->scheme, host $this->host, port $this->port"); + if ($this->io_method() == 'socket') { + if (!is_array($this->proxy)) { + $host = $this->host; + $port = $this->port; + } else { + $host = $this->proxy['host']; + $port = $this->proxy['port']; + } + + // use persistent connection + if($this->persistentConnection && isset($this->fp) && is_resource($this->fp)){ + if (!feof($this->fp)) { + $this->debug('Re-use persistent connection'); + return true; + } + fclose($this->fp); + $this->debug('Closed persistent connection at EOF'); + } + + // munge host if using OpenSSL + if ($this->scheme == 'ssl') { + $host = 'ssl://' . $host; + } + $this->debug('calling fsockopen with host ' . $host . ' connection_timeout ' . $connection_timeout); + + // open socket + if($connection_timeout > 0){ + $this->fp = @fsockopen( $host, $this->port, $this->errno, $this->error_str, $connection_timeout); + } else { + $this->fp = @fsockopen( $host, $this->port, $this->errno, $this->error_str); + } + + // test pointer + if(!$this->fp) { + $msg = 'Couldn\'t open socket connection to server ' . $this->url; + if ($this->errno) { + $msg .= ', Error ('.$this->errno.'): '.$this->error_str; + } else { + $msg .= ' prior to connect(). This is often a problem looking up the host name.'; + } + $this->debug($msg); + $this->setError($msg); + return false; + } + + // set response timeout + $this->debug('set response timeout to ' . $response_timeout); + socket_set_timeout( $this->fp, $response_timeout); + + $this->debug('socket connected'); + return true; + } else if ($this->io_method() == 'curl') { + if (!extension_loaded('curl')) { +// $this->setError('cURL Extension, or OpenSSL extension w/ PHP version >= 4.3 is required for HTTPS'); + $this->setError('The PHP cURL Extension is required for HTTPS or NLTM. You will need to re-build or update your PHP to include cURL or change php.ini to load the PHP cURL extension.'); + return false; + } + // Avoid warnings when PHP does not have these options + if (defined('CURLOPT_CONNECTIONTIMEOUT')) + $CURLOPT_CONNECTIONTIMEOUT = CURLOPT_CONNECTIONTIMEOUT; + else + $CURLOPT_CONNECTIONTIMEOUT = 78; + if (defined('CURLOPT_HTTPAUTH')) + $CURLOPT_HTTPAUTH = CURLOPT_HTTPAUTH; + else + $CURLOPT_HTTPAUTH = 107; + if (defined('CURLOPT_PROXYAUTH')) + $CURLOPT_PROXYAUTH = CURLOPT_PROXYAUTH; + else + $CURLOPT_PROXYAUTH = 111; + if (defined('CURLAUTH_BASIC')) + $CURLAUTH_BASIC = CURLAUTH_BASIC; + else + $CURLAUTH_BASIC = 1; + if (defined('CURLAUTH_DIGEST')) + $CURLAUTH_DIGEST = CURLAUTH_DIGEST; + else + $CURLAUTH_DIGEST = 2; + if (defined('CURLAUTH_NTLM')) + $CURLAUTH_NTLM = CURLAUTH_NTLM; + else + $CURLAUTH_NTLM = 8; + + $this->debug('connect using cURL'); + // init CURL + $this->ch = curl_init(); + // set url + $hostURL = ($this->port != '') ? "$this->scheme://$this->host:$this->port" : "$this->scheme://$this->host"; + // add path + $hostURL .= $this->path; + $this->setCurlOption(CURLOPT_URL, $hostURL); + // follow location headers (re-directs) + if (ini_get('safe_mode') || ini_get('open_basedir')) { + $this->debug('safe_mode or open_basedir set, so do not set CURLOPT_FOLLOWLOCATION'); + $this->debug('safe_mode = '); + $this->appendDebug($this->varDump(ini_get('safe_mode'))); + $this->debug('open_basedir = '); + $this->appendDebug($this->varDump(ini_get('open_basedir'))); + } else { + $this->setCurlOption(CURLOPT_FOLLOWLOCATION, 1); + } + // ask for headers in the response output + $this->setCurlOption(CURLOPT_HEADER, 1); + // ask for the response output as the return value + $this->setCurlOption(CURLOPT_RETURNTRANSFER, 1); + // encode + // We manage this ourselves through headers and encoding +// if(function_exists('gzuncompress')){ +// $this->setCurlOption(CURLOPT_ENCODING, 'deflate'); +// } + // persistent connection + if ($this->persistentConnection) { + // I believe the following comment is now bogus, having applied to + // the code when it used CURLOPT_CUSTOMREQUEST to send the request. + // The way we send data, we cannot use persistent connections, since + // there will be some "junk" at the end of our request. + //$this->setCurlOption(CURL_HTTP_VERSION_1_1, true); + $this->persistentConnection = false; + $this->setHeader('Connection', 'close'); + } + // set timeouts + if ($connection_timeout != 0) { + $this->setCurlOption($CURLOPT_CONNECTIONTIMEOUT, $connection_timeout); + } + if ($response_timeout != 0) { + $this->setCurlOption(CURLOPT_TIMEOUT, $response_timeout); + } + + if ($this->scheme == 'https') { + $this->debug('set cURL SSL verify options'); + // recent versions of cURL turn on peer/host checking by default, + // while PHP binaries are not compiled with a default location for the + // CA cert bundle, so disable peer/host checking. + //$this->setCurlOption(CURLOPT_CAINFO, 'f:\php-4.3.2-win32\extensions\curl-ca-bundle.crt'); + $this->setCurlOption(CURLOPT_SSL_VERIFYPEER, 0); + $this->setCurlOption(CURLOPT_SSL_VERIFYHOST, 0); + + // support client certificates (thanks Tobias Boes, Doug Anarino, Eryan Ariobowo) + if ($this->authtype == 'certificate') { + $this->debug('set cURL certificate options'); + if (isset($this->certRequest['cainfofile'])) { + $this->setCurlOption(CURLOPT_CAINFO, $this->certRequest['cainfofile']); + } + if (isset($this->certRequest['verifypeer'])) { + $this->setCurlOption(CURLOPT_SSL_VERIFYPEER, $this->certRequest['verifypeer']); + } else { + $this->setCurlOption(CURLOPT_SSL_VERIFYPEER, 1); + } + if (isset($this->certRequest['verifyhost'])) { + $this->setCurlOption(CURLOPT_SSL_VERIFYHOST, $this->certRequest['verifyhost']); + } else { + $this->setCurlOption(CURLOPT_SSL_VERIFYHOST, 1); + } + if (isset($this->certRequest['sslcertfile'])) { + $this->setCurlOption(CURLOPT_SSLCERT, $this->certRequest['sslcertfile']); + } + if (isset($this->certRequest['sslkeyfile'])) { + $this->setCurlOption(CURLOPT_SSLKEY, $this->certRequest['sslkeyfile']); + } + if (isset($this->certRequest['passphrase'])) { + $this->setCurlOption(CURLOPT_SSLKEYPASSWD, $this->certRequest['passphrase']); + } + if (isset($this->certRequest['certpassword'])) { + $this->setCurlOption(CURLOPT_SSLCERTPASSWD, $this->certRequest['certpassword']); + } + } + } + if ($this->authtype && ($this->authtype != 'certificate')) { + if ($this->username) { + $this->debug('set cURL username/password'); + $this->setCurlOption(CURLOPT_USERPWD, "$this->username:$this->password"); + } + if ($this->authtype == 'basic') { + $this->debug('set cURL for Basic authentication'); + $this->setCurlOption($CURLOPT_HTTPAUTH, $CURLAUTH_BASIC); + } + if ($this->authtype == 'digest') { + $this->debug('set cURL for digest authentication'); + $this->setCurlOption($CURLOPT_HTTPAUTH, $CURLAUTH_DIGEST); + } + if ($this->authtype == 'ntlm') { + $this->debug('set cURL for NTLM authentication'); + $this->setCurlOption($CURLOPT_HTTPAUTH, $CURLAUTH_NTLM); + } + } + if (is_array($this->proxy)) { + $this->debug('set cURL proxy options'); + if ($this->proxy['port'] != '') { + $this->setCurlOption(CURLOPT_PROXY, $this->proxy['host'].':'.$this->proxy['port']); + } else { + $this->setCurlOption(CURLOPT_PROXY, $this->proxy['host']); + } + if ($this->proxy['username'] || $this->proxy['password']) { + $this->debug('set cURL proxy authentication options'); + $this->setCurlOption(CURLOPT_PROXYUSERPWD, $this->proxy['username'].':'.$this->proxy['password']); + if ($this->proxy['authtype'] == 'basic') { + $this->setCurlOption($CURLOPT_PROXYAUTH, $CURLAUTH_BASIC); + } + if ($this->proxy['authtype'] == 'ntlm') { + $this->setCurlOption($CURLOPT_PROXYAUTH, $CURLAUTH_NTLM); + } + } + } + $this->debug('cURL connection set up'); + return true; + } else { + $this->setError('Unknown scheme ' . $this->scheme); + $this->debug('Unknown scheme ' . $this->scheme); + return false; + } + } + + /** + * sends the SOAP request and gets the SOAP response via HTTP[S] + * + * @param string $data message data + * @param integer $timeout set connection timeout in seconds + * @param integer $response_timeout set response timeout in seconds + * @param array $cookies cookies to send + * @return string data + * @access public + */ + function send($data, $timeout=0, $response_timeout=30, $cookies=NULL) { + + $this->debug('entered send() with data of length: '.strlen($data)); + + $this->tryagain = true; + $tries = 0; + while ($this->tryagain) { + $this->tryagain = false; + if ($tries++ < 2) { + // make connnection + if (!$this->connect($timeout, $response_timeout)){ + return false; + } + + // send request + if (!$this->sendRequest($data, $cookies)){ + return false; + } + + // get response + $respdata = $this->getResponse(); + } else { + $this->setError("Too many tries to get an OK response ($this->response_status_line)"); + } + } + $this->debug('end of send()'); + return $respdata; + } + + + /** + * sends the SOAP request and gets the SOAP response via HTTPS using CURL + * + * @param string $data message data + * @param integer $timeout set connection timeout in seconds + * @param integer $response_timeout set response timeout in seconds + * @param array $cookies cookies to send + * @return string data + * @access public + * @deprecated + */ + function sendHTTPS($data, $timeout=0, $response_timeout=30, $cookies) { + return $this->send($data, $timeout, $response_timeout, $cookies); + } + + /** + * if authenticating, set user credentials here + * + * @param string $username + * @param string $password + * @param string $authtype (basic|digest|certificate|ntlm) + * @param array $digestRequest (keys must be nonce, nc, realm, qop) + * @param array $certRequest (keys must be cainfofile (optional), sslcertfile, sslkeyfile, passphrase, certpassword (optional), verifypeer (optional), verifyhost (optional): see corresponding options in cURL docs) + * @access public + */ + function setCredentials($username, $password, $authtype = 'basic', $digestRequest = array(), $certRequest = array()) { + $this->debug("setCredentials username=$username authtype=$authtype digestRequest="); + $this->appendDebug($this->varDump($digestRequest)); + $this->debug("certRequest="); + $this->appendDebug($this->varDump($certRequest)); + // cf. RFC 2617 + if ($authtype == 'basic') { + $this->setHeader('Authorization', 'Basic '.base64_encode(str_replace(':','',$username).':'.$password)); + } elseif ($authtype == 'digest') { + if (isset($digestRequest['nonce'])) { + $digestRequest['nc'] = isset($digestRequest['nc']) ? $digestRequest['nc']++ : 1; + + // calculate the Digest hashes (calculate code based on digest implementation found at: http://www.rassoc.com/gregr/weblog/stories/2002/07/09/webServicesSecurityHttpDigestAuthenticationWithoutActiveDirectory.html) + + // A1 = unq(username-value) ":" unq(realm-value) ":" passwd + $A1 = $username. ':' . (isset($digestRequest['realm']) ? $digestRequest['realm'] : '') . ':' . $password; + + // H(A1) = MD5(A1) + $HA1 = md5($A1); + + // A2 = Method ":" digest-uri-value + $A2 = $this->request_method . ':' . $this->digest_uri; + + // H(A2) + $HA2 = md5($A2); + + // KD(secret, data) = H(concat(secret, ":", data)) + // if qop == auth: + // request-digest = <"> < KD ( H(A1), unq(nonce-value) + // ":" nc-value + // ":" unq(cnonce-value) + // ":" unq(qop-value) + // ":" H(A2) + // ) <"> + // if qop is missing, + // request-digest = <"> < KD ( H(A1), unq(nonce-value) ":" H(A2) ) > <"> + + $unhashedDigest = ''; + $nonce = isset($digestRequest['nonce']) ? $digestRequest['nonce'] : ''; + $cnonce = $nonce; + if ($digestRequest['qop'] != '') { + $unhashedDigest = $HA1 . ':' . $nonce . ':' . sprintf("%08d", $digestRequest['nc']) . ':' . $cnonce . ':' . $digestRequest['qop'] . ':' . $HA2; + } else { + $unhashedDigest = $HA1 . ':' . $nonce . ':' . $HA2; + } + + $hashedDigest = md5($unhashedDigest); + + $opaque = ''; + if (isset($digestRequest['opaque'])) { + $opaque = ', opaque="' . $digestRequest['opaque'] . '"'; + } + + $this->setHeader('Authorization', 'Digest username="' . $username . '", realm="' . $digestRequest['realm'] . '", nonce="' . $nonce . '", uri="' . $this->digest_uri . $opaque . '", cnonce="' . $cnonce . '", nc=' . sprintf("%08x", $digestRequest['nc']) . ', qop="' . $digestRequest['qop'] . '", response="' . $hashedDigest . '"'); + } + } elseif ($authtype == 'certificate') { + $this->certRequest = $certRequest; + $this->debug('Authorization header not set for certificate'); + } elseif ($authtype == 'ntlm') { + // do nothing + $this->debug('Authorization header not set for ntlm'); + } + $this->username = $username; + $this->password = $password; + $this->authtype = $authtype; + $this->digestRequest = $digestRequest; + } + + /** + * set the soapaction value + * + * @param string $soapaction + * @access public + */ + function setSOAPAction($soapaction) { + $this->setHeader('SOAPAction', '"' . $soapaction . '"'); + } + + /** + * use http encoding + * + * @param string $enc encoding style. supported values: gzip, deflate, or both + * @access public + */ + function setEncoding($enc='gzip, deflate') { + if (function_exists('gzdeflate')) { + $this->protocol_version = '1.1'; + $this->setHeader('Accept-Encoding', $enc); + if (!isset($this->outgoing_headers['Connection'])) { + $this->setHeader('Connection', 'close'); + $this->persistentConnection = false; + } + // deprecated as of PHP 5.3.0 + //set_magic_quotes_runtime(0); + $this->encoding = $enc; + } + } + + /** + * set proxy info here + * + * @param string $proxyhost use an empty string to remove proxy + * @param string $proxyport + * @param string $proxyusername + * @param string $proxypassword + * @param string $proxyauthtype (basic|ntlm) + * @access public + */ + function setProxy($proxyhost, $proxyport, $proxyusername = '', $proxypassword = '', $proxyauthtype = 'basic') { + if ($proxyhost) { + $this->proxy = array( + 'host' => $proxyhost, + 'port' => $proxyport, + 'username' => $proxyusername, + 'password' => $proxypassword, + 'authtype' => $proxyauthtype + ); + if ($proxyusername != '' && $proxypassword != '' && $proxyauthtype = 'basic') { + $this->setHeader('Proxy-Authorization', ' Basic '.base64_encode($proxyusername.':'.$proxypassword)); + } + } else { + $this->debug('remove proxy'); + $proxy = null; + unsetHeader('Proxy-Authorization'); + } + } + + + /** + * Test if the given string starts with a header that is to be skipped. + * Skippable headers result from chunked transfer and proxy requests. + * + * @param string $data The string to check. + * @returns boolean Whether a skippable header was found. + * @access private + */ + function isSkippableCurlHeader(&$data) { + $skipHeaders = array( 'HTTP/1.1 100', + 'HTTP/1.0 301', + 'HTTP/1.1 301', + 'HTTP/1.0 302', + 'HTTP/1.1 302', + 'HTTP/1.0 401', + 'HTTP/1.1 401', + 'HTTP/1.0 200 Connection established'); + foreach ($skipHeaders as $hd) { + $prefix = substr($data, 0, strlen($hd)); + if ($prefix == $hd) return true; + } + + return false; + } + + /** + * decode a string that is encoded w/ "chunked' transfer encoding + * as defined in RFC2068 19.4.6 + * + * @param string $buffer + * @param string $lb + * @returns string + * @access public + * @deprecated + */ + function decodeChunked($buffer, $lb){ + // length := 0 + $length = 0; + $new = ''; + + // read chunk-size, chunk-extension (if any) and CRLF + // get the position of the linebreak + $chunkend = strpos($buffer, $lb); + if ($chunkend == FALSE) { + $this->debug('no linebreak found in decodeChunked'); + return $new; + } + $temp = substr($buffer,0,$chunkend); + $chunk_size = hexdec( trim($temp) ); + $chunkstart = $chunkend + strlen($lb); + // while (chunk-size > 0) { + while ($chunk_size > 0) { + $this->debug("chunkstart: $chunkstart chunk_size: $chunk_size"); + $chunkend = strpos( $buffer, $lb, $chunkstart + $chunk_size); + + // Just in case we got a broken connection + if ($chunkend == FALSE) { + $chunk = substr($buffer,$chunkstart); + // append chunk-data to entity-body + $new .= $chunk; + $length += strlen($chunk); + break; + } + + // read chunk-data and CRLF + $chunk = substr($buffer,$chunkstart,$chunkend-$chunkstart); + // append chunk-data to entity-body + $new .= $chunk; + // length := length + chunk-size + $length += strlen($chunk); + // read chunk-size and CRLF + $chunkstart = $chunkend + strlen($lb); + + $chunkend = strpos($buffer, $lb, $chunkstart) + strlen($lb); + if ($chunkend == FALSE) { + break; //Just in case we got a broken connection + } + $temp = substr($buffer,$chunkstart,$chunkend-$chunkstart); + $chunk_size = hexdec( trim($temp) ); + $chunkstart = $chunkend; + } + return $new; + } + + /** + * Writes the payload, including HTTP headers, to $this->outgoing_payload. + * + * @param string $data HTTP body + * @param string $cookie_str data for HTTP Cookie header + * @return void + * @access private + */ + function buildPayload($data, $cookie_str = '') { + // Note: for cURL connections, $this->outgoing_payload is ignored, + // as is the Content-Length header, but these are still created as + // debugging guides. + + // add content-length header + if ($this->request_method != 'GET') { + $this->setHeader('Content-Length', strlen($data)); + } + + // start building outgoing payload: + if ($this->proxy) { + $uri = $this->url; + } else { + $uri = $this->uri; + } + $req = "$this->request_method $uri HTTP/$this->protocol_version"; + $this->debug("HTTP request: $req"); + $this->outgoing_payload = "$req\r\n"; + + // loop thru headers, serializing + foreach($this->outgoing_headers as $k => $v){ + $hdr = $k.': '.$v; + $this->debug("HTTP header: $hdr"); + $this->outgoing_payload .= "$hdr\r\n"; + } + + // add any cookies + if ($cookie_str != '') { + $hdr = 'Cookie: '.$cookie_str; + $this->debug("HTTP header: $hdr"); + $this->outgoing_payload .= "$hdr\r\n"; + } + + // header/body separator + $this->outgoing_payload .= "\r\n"; + + // add data + $this->outgoing_payload .= $data; + } + + /** + * sends the SOAP request via HTTP[S] + * + * @param string $data message data + * @param array $cookies cookies to send + * @return boolean true if OK, false if problem + * @access private + */ + function sendRequest($data, $cookies = NULL) { + // build cookie string + $cookie_str = $this->getCookiesForRequest($cookies, (($this->scheme == 'ssl') || ($this->scheme == 'https'))); + + // build payload + $this->buildPayload($data, $cookie_str); + + if ($this->io_method() == 'socket') { + // send payload + if(!fputs($this->fp, $this->outgoing_payload, strlen($this->outgoing_payload))) { + $this->setError('couldn\'t write message data to socket'); + $this->debug('couldn\'t write message data to socket'); + return false; + } + $this->debug('wrote data to socket, length = ' . strlen($this->outgoing_payload)); + return true; + } else if ($this->io_method() == 'curl') { + // set payload + // cURL does say this should only be the verb, and in fact it + // turns out that the URI and HTTP version are appended to this, which + // some servers refuse to work with (so we no longer use this method!) + //$this->setCurlOption(CURLOPT_CUSTOMREQUEST, $this->outgoing_payload); + $curl_headers = array(); + foreach($this->outgoing_headers as $k => $v){ + if ($k == 'Connection' || $k == 'Content-Length' || $k == 'Host' || $k == 'Authorization' || $k == 'Proxy-Authorization') { + $this->debug("Skip cURL header $k: $v"); + } else { + $curl_headers[] = "$k: $v"; + } + } + if ($cookie_str != '') { + $curl_headers[] = 'Cookie: ' . $cookie_str; + } + $this->setCurlOption(CURLOPT_HTTPHEADER, $curl_headers); + $this->debug('set cURL HTTP headers'); + if ($this->request_method == "POST") { + $this->setCurlOption(CURLOPT_POST, 1); + $this->setCurlOption(CURLOPT_POSTFIELDS, $data); + $this->debug('set cURL POST data'); + } else { + } + // insert custom user-set cURL options + foreach ($this->ch_options as $key => $val) { + $this->setCurlOption($key, $val); + } + + $this->debug('set cURL payload'); + return true; + } + } + + /** + * gets the SOAP response via HTTP[S] + * + * @return string the response (also sets member variables like incoming_payload) + * @access private + */ + function getResponse(){ + $this->incoming_payload = ''; + + if ($this->io_method() == 'socket') { + // loop until headers have been retrieved + $data = ''; + while (!isset($lb)){ + + // We might EOF during header read. + if(feof($this->fp)) { + $this->incoming_payload = $data; + $this->debug('found no headers before EOF after length ' . strlen($data)); + $this->debug("received before EOF:\n" . $data); + $this->setError('server failed to send headers'); + return false; + } + + $tmp = fgets($this->fp, 256); + $tmplen = strlen($tmp); + $this->debug("read line of $tmplen bytes: " . trim($tmp)); + + if ($tmplen == 0) { + $this->incoming_payload = $data; + $this->debug('socket read of headers timed out after length ' . strlen($data)); + $this->debug("read before timeout: " . $data); + $this->setError('socket read of headers timed out'); + return false; + } + + $data .= $tmp; + $pos = strpos($data,"\r\n\r\n"); + if($pos > 1){ + $lb = "\r\n"; + } else { + $pos = strpos($data,"\n\n"); + if($pos > 1){ + $lb = "\n"; + } + } + // remove 100 headers + if (isset($lb) && preg_match('/^HTTP\/1.1 100/',$data)) { + unset($lb); + $data = ''; + }// + } + // store header data + $this->incoming_payload .= $data; + $this->debug('found end of headers after length ' . strlen($data)); + // process headers + $header_data = trim(substr($data,0,$pos)); + $header_array = explode($lb,$header_data); + $this->incoming_headers = array(); + $this->incoming_cookies = array(); + foreach($header_array as $header_line){ + $arr = explode(':',$header_line, 2); + if(count($arr) > 1){ + $header_name = strtolower(trim($arr[0])); + $this->incoming_headers[$header_name] = trim($arr[1]); + if ($header_name == 'set-cookie') { + // TODO: allow multiple cookies from parseCookie + $cookie = $this->parseCookie(trim($arr[1])); + if ($cookie) { + $this->incoming_cookies[] = $cookie; + $this->debug('found cookie: ' . $cookie['name'] . ' = ' . $cookie['value']); + } else { + $this->debug('did not find cookie in ' . trim($arr[1])); + } + } + } else if (isset($header_name)) { + // append continuation line to previous header + $this->incoming_headers[$header_name] .= $lb . ' ' . $header_line; + } + } + + // loop until msg has been received + if (isset($this->incoming_headers['transfer-encoding']) && strtolower($this->incoming_headers['transfer-encoding']) == 'chunked') { + $content_length = 2147483647; // ignore any content-length header + $chunked = true; + $this->debug("want to read chunked content"); + } elseif (isset($this->incoming_headers['content-length'])) { + $content_length = $this->incoming_headers['content-length']; + $chunked = false; + $this->debug("want to read content of length $content_length"); + } else { + $content_length = 2147483647; + $chunked = false; + $this->debug("want to read content to EOF"); + } + $data = ''; + do { + if ($chunked) { + $tmp = fgets($this->fp, 256); + $tmplen = strlen($tmp); + $this->debug("read chunk line of $tmplen bytes"); + if ($tmplen == 0) { + $this->incoming_payload = $data; + $this->debug('socket read of chunk length timed out after length ' . strlen($data)); + $this->debug("read before timeout:\n" . $data); + $this->setError('socket read of chunk length timed out'); + return false; + } + $content_length = hexdec(trim($tmp)); + $this->debug("chunk length $content_length"); + } + $strlen = 0; + while (($strlen < $content_length) && (!feof($this->fp))) { + $readlen = min(8192, $content_length - $strlen); + $tmp = fread($this->fp, $readlen); + $tmplen = strlen($tmp); + $this->debug("read buffer of $tmplen bytes"); + if (($tmplen == 0) && (!feof($this->fp))) { + $this->incoming_payload = $data; + $this->debug('socket read of body timed out after length ' . strlen($data)); + $this->debug("read before timeout:\n" . $data); + $this->setError('socket read of body timed out'); + return false; + } + $strlen += $tmplen; + $data .= $tmp; + } + if ($chunked && ($content_length > 0)) { + $tmp = fgets($this->fp, 256); + $tmplen = strlen($tmp); + $this->debug("read chunk terminator of $tmplen bytes"); + if ($tmplen == 0) { + $this->incoming_payload = $data; + $this->debug('socket read of chunk terminator timed out after length ' . strlen($data)); + $this->debug("read before timeout:\n" . $data); + $this->setError('socket read of chunk terminator timed out'); + return false; + } + } + } while ($chunked && ($content_length > 0) && (!feof($this->fp))); + if (feof($this->fp)) { + $this->debug('read to EOF'); + } + $this->debug('read body of length ' . strlen($data)); + $this->incoming_payload .= $data; + $this->debug('received a total of '.strlen($this->incoming_payload).' bytes of data from server'); + + // close filepointer + if( + (isset($this->incoming_headers['connection']) && strtolower($this->incoming_headers['connection']) == 'close') || + (! $this->persistentConnection) || feof($this->fp)){ + fclose($this->fp); + $this->fp = false; + $this->debug('closed socket'); + } + + // connection was closed unexpectedly + if($this->incoming_payload == ''){ + $this->setError('no response from server'); + return false; + } + + // decode transfer-encoding +// if(isset($this->incoming_headers['transfer-encoding']) && strtolower($this->incoming_headers['transfer-encoding']) == 'chunked'){ +// if(!$data = $this->decodeChunked($data, $lb)){ +// $this->setError('Decoding of chunked data failed'); +// return false; +// } + //print "
    \nde-chunked:\n---------------\n$data\n\n---------------\n
    "; + // set decoded payload +// $this->incoming_payload = $header_data.$lb.$lb.$data; +// } + + } else if ($this->io_method() == 'curl') { + // send and receive + $this->debug('send and receive with cURL'); + $this->incoming_payload = curl_exec($this->ch); + $data = $this->incoming_payload; + + $cErr = curl_error($this->ch); + if ($cErr != '') { + $err = 'cURL ERROR: '.curl_errno($this->ch).': '.$cErr.'
    '; + // TODO: there is a PHP bug that can cause this to SEGV for CURLINFO_CONTENT_TYPE + foreach(curl_getinfo($this->ch) as $k => $v){ + $err .= "$k: $v
    "; + } + $this->debug($err); + $this->setError($err); + curl_close($this->ch); + return false; + } else { + //echo '
    ';
    +			//var_dump(curl_getinfo($this->ch));
    +			//echo '
    '; + } + // close curl + $this->debug('No cURL error, closing cURL'); + curl_close($this->ch); + + // try removing skippable headers + $savedata = $data; + while ($this->isSkippableCurlHeader($data)) { + $this->debug("Found HTTP header to skip"); + if ($pos = strpos($data,"\r\n\r\n")) { + $data = ltrim(substr($data,$pos)); + } elseif($pos = strpos($data,"\n\n") ) { + $data = ltrim(substr($data,$pos)); + } + } + + if ($data == '') { + // have nothing left; just remove 100 header(s) + $data = $savedata; + while (preg_match('/^HTTP\/1.1 100/',$data)) { + if ($pos = strpos($data,"\r\n\r\n")) { + $data = ltrim(substr($data,$pos)); + } elseif($pos = strpos($data,"\n\n") ) { + $data = ltrim(substr($data,$pos)); + } + } + } + + // separate content from HTTP headers + if ($pos = strpos($data,"\r\n\r\n")) { + $lb = "\r\n"; + } elseif( $pos = strpos($data,"\n\n")) { + $lb = "\n"; + } else { + $this->debug('no proper separation of headers and document'); + $this->setError('no proper separation of headers and document'); + return false; + } + $header_data = trim(substr($data,0,$pos)); + $header_array = explode($lb,$header_data); + $data = ltrim(substr($data,$pos)); + $this->debug('found proper separation of headers and document'); + $this->debug('cleaned data, stringlen: '.strlen($data)); + // clean headers + foreach ($header_array as $header_line) { + $arr = explode(':',$header_line,2); + if(count($arr) > 1){ + $header_name = strtolower(trim($arr[0])); + $this->incoming_headers[$header_name] = trim($arr[1]); + if ($header_name == 'set-cookie') { + // TODO: allow multiple cookies from parseCookie + $cookie = $this->parseCookie(trim($arr[1])); + if ($cookie) { + $this->incoming_cookies[] = $cookie; + $this->debug('found cookie: ' . $cookie['name'] . ' = ' . $cookie['value']); + } else { + $this->debug('did not find cookie in ' . trim($arr[1])); + } + } + } else if (isset($header_name)) { + // append continuation line to previous header + $this->incoming_headers[$header_name] .= $lb . ' ' . $header_line; + } + } + } + + $this->response_status_line = $header_array[0]; + $arr = explode(' ', $this->response_status_line, 3); + $http_version = $arr[0]; + $http_status = intval($arr[1]); + $http_reason = count($arr) > 2 ? $arr[2] : ''; + + // see if we need to resend the request with http digest authentication + if (isset($this->incoming_headers['location']) && ($http_status == 301 || $http_status == 302)) { + $this->debug("Got $http_status $http_reason with Location: " . $this->incoming_headers['location']); + $this->setURL($this->incoming_headers['location']); + $this->tryagain = true; + return false; + } + + // see if we need to resend the request with http digest authentication + if (isset($this->incoming_headers['www-authenticate']) && $http_status == 401) { + $this->debug("Got 401 $http_reason with WWW-Authenticate: " . $this->incoming_headers['www-authenticate']); + if (strstr($this->incoming_headers['www-authenticate'], "Digest ")) { + $this->debug('Server wants digest authentication'); + // remove "Digest " from our elements + $digestString = str_replace('Digest ', '', $this->incoming_headers['www-authenticate']); + + // parse elements into array + $digestElements = explode(',', $digestString); + foreach ($digestElements as $val) { + $tempElement = explode('=', trim($val), 2); + $digestRequest[$tempElement[0]] = str_replace("\"", '', $tempElement[1]); + } + + // should have (at least) qop, realm, nonce + if (isset($digestRequest['nonce'])) { + $this->setCredentials($this->username, $this->password, 'digest', $digestRequest); + $this->tryagain = true; + return false; + } + } + $this->debug('HTTP authentication failed'); + $this->setError('HTTP authentication failed'); + return false; + } + + if ( + ($http_status >= 300 && $http_status <= 307) || + ($http_status >= 400 && $http_status <= 417) || + ($http_status >= 501 && $http_status <= 505) + ) { + $this->setError("Unsupported HTTP response status $http_status $http_reason (soapclient->response has contents of the response)"); + return false; + } + + // decode content-encoding + if(isset($this->incoming_headers['content-encoding']) && $this->incoming_headers['content-encoding'] != ''){ + if(strtolower($this->incoming_headers['content-encoding']) == 'deflate' || strtolower($this->incoming_headers['content-encoding']) == 'gzip'){ + // if decoding works, use it. else assume data wasn't gzencoded + if(function_exists('gzinflate')){ + //$timer->setMarker('starting decoding of gzip/deflated content'); + // IIS 5 requires gzinflate instead of gzuncompress (similar to IE 5 and gzdeflate v. gzcompress) + // this means there are no Zlib headers, although there should be + $this->debug('The gzinflate function exists'); + $datalen = strlen($data); + if ($this->incoming_headers['content-encoding'] == 'deflate') { + if ($degzdata = @gzinflate($data)) { + $data = $degzdata; + $this->debug('The payload has been inflated to ' . strlen($data) . ' bytes'); + if (strlen($data) < $datalen) { + // test for the case that the payload has been compressed twice + $this->debug('The inflated payload is smaller than the gzipped one; try again'); + if ($degzdata = @gzinflate($data)) { + $data = $degzdata; + $this->debug('The payload has been inflated again to ' . strlen($data) . ' bytes'); + } + } + } else { + $this->debug('Error using gzinflate to inflate the payload'); + $this->setError('Error using gzinflate to inflate the payload'); + } + } elseif ($this->incoming_headers['content-encoding'] == 'gzip') { + if ($degzdata = @gzinflate(substr($data, 10))) { // do our best + $data = $degzdata; + $this->debug('The payload has been un-gzipped to ' . strlen($data) . ' bytes'); + if (strlen($data) < $datalen) { + // test for the case that the payload has been compressed twice + $this->debug('The un-gzipped payload is smaller than the gzipped one; try again'); + if ($degzdata = @gzinflate(substr($data, 10))) { + $data = $degzdata; + $this->debug('The payload has been un-gzipped again to ' . strlen($data) . ' bytes'); + } + } + } else { + $this->debug('Error using gzinflate to un-gzip the payload'); + $this->setError('Error using gzinflate to un-gzip the payload'); + } + } + //$timer->setMarker('finished decoding of gzip/deflated content'); + //print "\nde-inflated:\n---------------\n$data\n-------------\n"; + // set decoded payload + $this->incoming_payload = $header_data.$lb.$lb.$data; + } else { + $this->debug('The server sent compressed data. Your php install must have the Zlib extension compiled in to support this.'); + $this->setError('The server sent compressed data. Your php install must have the Zlib extension compiled in to support this.'); + } + } else { + $this->debug('Unsupported Content-Encoding ' . $this->incoming_headers['content-encoding']); + $this->setError('Unsupported Content-Encoding ' . $this->incoming_headers['content-encoding']); + } + } else { + $this->debug('No Content-Encoding header'); + } + + if(strlen($data) == 0){ + $this->debug('no data after headers!'); + $this->setError('no data present after HTTP headers'); + return false; + } + + return $data; + } + + /** + * sets the content-type for the SOAP message to be sent + * + * @param string $type the content type, MIME style + * @param mixed $charset character set used for encoding (or false) + * @access public + */ + function setContentType($type, $charset = false) { + $this->setHeader('Content-Type', $type . ($charset ? '; charset=' . $charset : '')); + } + + /** + * specifies that an HTTP persistent connection should be used + * + * @return boolean whether the request was honored by this method. + * @access public + */ + function usePersistentConnection(){ + if (isset($this->outgoing_headers['Accept-Encoding'])) { + return false; + } + $this->protocol_version = '1.1'; + $this->persistentConnection = true; + $this->setHeader('Connection', 'Keep-Alive'); + return true; + } + + /** + * parse an incoming Cookie into it's parts + * + * @param string $cookie_str content of cookie + * @return array with data of that cookie + * @access private + */ + /* + * TODO: allow a Set-Cookie string to be parsed into multiple cookies + */ + function parseCookie($cookie_str) { + $cookie_str = str_replace('; ', ';', $cookie_str) . ';'; + $data = preg_split('/;/', $cookie_str); + $value_str = $data[0]; + + $cookie_param = 'domain='; + $start = strpos($cookie_str, $cookie_param); + if ($start > 0) { + $domain = substr($cookie_str, $start + strlen($cookie_param)); + $domain = substr($domain, 0, strpos($domain, ';')); + } else { + $domain = ''; + } + + $cookie_param = 'expires='; + $start = strpos($cookie_str, $cookie_param); + if ($start > 0) { + $expires = substr($cookie_str, $start + strlen($cookie_param)); + $expires = substr($expires, 0, strpos($expires, ';')); + } else { + $expires = ''; + } + + $cookie_param = 'path='; + $start = strpos($cookie_str, $cookie_param); + if ( $start > 0 ) { + $path = substr($cookie_str, $start + strlen($cookie_param)); + $path = substr($path, 0, strpos($path, ';')); + } else { + $path = '/'; + } + + $cookie_param = ';secure;'; + if (strpos($cookie_str, $cookie_param) !== FALSE) { + $secure = true; + } else { + $secure = false; + } + + $sep_pos = strpos($value_str, '='); + + if ($sep_pos) { + $name = substr($value_str, 0, $sep_pos); + $value = substr($value_str, $sep_pos + 1); + $cookie= array( 'name' => $name, + 'value' => $value, + 'domain' => $domain, + 'path' => $path, + 'expires' => $expires, + 'secure' => $secure + ); + return $cookie; + } + return false; + } + + /** + * sort out cookies for the current request + * + * @param array $cookies array with all cookies + * @param boolean $secure is the send-content secure or not? + * @return string for Cookie-HTTP-Header + * @access private + */ + function getCookiesForRequest($cookies, $secure=false) { + $cookie_str = ''; + if ((! is_null($cookies)) && (is_array($cookies))) { + foreach ($cookies as $cookie) { + if (! is_array($cookie)) { + continue; + } + $this->debug("check cookie for validity: ".$cookie['name'].'='.$cookie['value']); + if ((isset($cookie['expires'])) && (! empty($cookie['expires']))) { + if (strtotime($cookie['expires']) <= time()) { + $this->debug('cookie has expired'); + continue; + } + } + if ((isset($cookie['domain'])) && (! empty($cookie['domain']))) { + $domain = preg_quote($cookie['domain']); + if (! preg_match("'.*$domain$'i", $this->host)) { + $this->debug('cookie has different domain'); + continue; + } + } + if ((isset($cookie['path'])) && (! empty($cookie['path']))) { + $path = preg_quote($cookie['path']); + if (! preg_match("'^$path.*'i", $this->path)) { + $this->debug('cookie is for a different path'); + continue; + } + } + if ((! $secure) && (isset($cookie['secure'])) && ($cookie['secure'])) { + $this->debug('cookie is secure, transport is not'); + continue; + } + $cookie_str .= $cookie['name'] . '=' . $cookie['value'] . '; '; + $this->debug('add cookie to Cookie-String: ' . $cookie['name'] . '=' . $cookie['value']); + } + } + return $cookie_str; + } +} + +?> + bug 40066 + +r58361 - 2010-09-29 16:59:02 -0700 (Wed, 29 Sep 2010) - kjing - Author: Jenny Gonsalves + Merging with maint_6_0_1 (svn merge -r 58250:58342) + +r57813 - 2010-08-19 10:34:44 -0700 (Thu, 19 Aug 2010) - kjing - Author: John Mertic + Bug 39085 - When loading the opposite search panel via ajax on the ListViews, call the index action instead of the ListView action to avoid touching pre-MVC code by accident. + +r57707 - 2010-08-10 12:26:13 -0700 (Tue, 10 Aug 2010) - kjing - Author: Stanislav Malyshev + fix SOAP calls with no parameters + +r56990 - 2010-06-16 13:05:36 -0700 (Wed, 16 Jun 2010) - kjing - snapshot "Mango" svn branch to a new one for GitHub sync + +r56989 - 2010-06-16 13:01:33 -0700 (Wed, 16 Jun 2010) - kjing - defunt "Mango" svn dev branch before github cutover + +r55980 - 2010-04-19 13:31:28 -0700 (Mon, 19 Apr 2010) - kjing - create Mango (6.1) based on windex + +r51719 - 2009-10-22 10:18:00 -0700 (Thu, 22 Oct 2009) - mitani - Converted to Build 3 tags and updated the build system + +r51634 - 2009-10-19 13:32:22 -0700 (Mon, 19 Oct 2009) - mitani - Windex is the branch for Sugar Sales 1.0 development + +r51508 - 2009-10-14 07:40:23 -0700 (Wed, 14 Oct 2009) - jmertic - More fallout fixes from the PHP 5.3 ereg to preg changes. + +r51455 - 2009-10-13 07:56:48 -0700 (Tue, 13 Oct 2009) - jmertic - Bug 33202 - Enable install of SugarCRM on PHP 5.3.0, asserting that the minimum supported version is PHP 5.2.x. + +r51443 - 2009-10-12 13:34:36 -0700 (Mon, 12 Oct 2009) - jmertic - Bug 33332 - Made application PHP 5.3 compliant with E_DEPRECATED warnings on by: +- Changing all ereg function to either preg or simple string based ones +- No more references to magic quotes. +- Change all the session_unregister() functions to just unset() the correct session variable instead. + +r50375 - 2009-08-24 18:07:43 -0700 (Mon, 24 Aug 2009) - dwong - branch kobe2 from tokyo r50372 + +r45763 - 2009-04-01 12:16:18 -0700 (Wed, 01 Apr 2009) - majed - Removed half of the require_once and include_onces in the product that were redundant or could be handled easily by the auto loader + +r45680 - 2009-03-30 14:34:35 -0700 (Mon, 30 Mar 2009) - Samir Gandhi - modifeid serializeSchema to generate WS-I compliant WSDL + +r42807 - 2008-12-29 11:16:59 -0800 (Mon, 29 Dec 2008) - dwong - Branch from trunk/sugarcrm r42806 to branches/tokyo/sugarcrm + +r42645 - 2008-12-18 13:41:08 -0800 (Thu, 18 Dec 2008) - awu - merging maint_5_2_0 rev41336:HEAD to trunk + +r41647 - 2008-11-11 17:44:30 -0800 (Tue, 11 Nov 2008) - majed - Fixes a few bugs + +r41596 - 2008-11-10 19:20:04 -0800 (Mon, 10 Nov 2008) - Samir Gandhi - modified to set $method in the code + +r41558 - 2008-11-10 14:35:34 -0800 (Mon, 10 Nov 2008) - majed - changes nusoap to allow for registering classes + +r39619 - 2008-09-09 13:41:34 -0700 (Tue, 09 Sep 2008) - jmertic - Bug 24827 - Remove all instances where we return a new object and assign it by reference, since this is deprecated in PHP 5 and emits E_DEPRECATED errors in PHP 5.3. +Touched: +- data/SugarBean.php +- include/domit/php_http_client_generic.php +- include/domit/php_http_connector.php +- include/domit/testing_domit.php +- include/domit/xml_domit_getelementsbypath.php +- include/domit/xml_domit_lite_parser.php +- include/domit/xml_domit_nodemaps.php +- include/domit/xml_domit_parser.php +- include/domit/xml_domit_shared.php +- include/generic/SugarWidgets/SugarWidgetField.php +- include/generic/SugarWidgets/SugarWidgetReportField.php +- include/ListView/ProcessView.php +- include/nusoap/class.soapclient.php +- include/nusoap/nusoap.php +- include/nusoap/nusoapmime.php +- include/Pear/HTML_Safe/Safe.php +- include/Pear/XML_HTMLSax3/HTMLSax3.php +- modules/Administration/RebuildWorkFlow.php +- modules/Expressions/RelateSelector.php +- modules/Reports/templates/templates_reports.php +- modules/WorkFlow/Delete.php +- modules/WorkFlow/Save.php +- modules/WorkFlow/SaveSequence.php +- modules/WorkFlow/WorkFlow.php +- modules/WorkFlowActionShells/CreateStep1.php +- modules/WorkFlowActionShells/CreateStep2.php +- modules/WorkFlowActionShells/Save.php +- modules/WorkFlowActionShells/WorkFlowActionShell.php +- modules/WorkFlowAlerts/Save.php +- modules/WorkFlowAlerts/WorkFlowAlert.php +- modules/WorkFlowAlertShells/DetailView.php +- modules/WorkFlowAlertShells/WorkFlowAlertShell.php +- modules/WorkFlowTriggerShells/CreateStep1.php +- modules/WorkFlowTriggerShells/CreateStepFilter.php +- modules/WorkFlowTriggerShells/SaveFilter.php +- modules/WorkFlowTriggerShells/WorkFlowTriggerShell.php +- soap/SoapHelperFunctions.php +- test/modules/DynamicFields/DynamicFields_Bug24095_test.php +- test/simpletest/browser.php +- test/simpletest/default_reporter.php +- test/simpletest/detached.php +- test/simpletest/eclipse.php +- test/simpletest/expectation.php +- test/simpletest/extensions/pear_test_case.php +- test/simpletest/form.php +- test/simpletest/http.php +- test/simpletest/mock_objects.php +- test/simpletest/page.php +- test/simpletest/parser.php +- test/simpletest/remote.php +- test/simpletest/shell_tester.php +- test/simpletest/simple_test.php +- test/simpletest/simpletest.php +- test/simpletest/test/acceptance_test.php +- test/simpletest/test/adapter_test.php +- test/simpletest/test/authentication_test.php +- test/simpletest/test/browser_test.php +- test/simpletest/test/collector_test.php +- test/simpletest/test/compatibility_test.php +- test/simpletest/test/detached_test.php +- test/simpletest/test/eclipse_test.php +- test/simpletest/test/encoding_test.php +- test/simpletest/test/errors_test.php +- test/simpletest/test/expectation_test.php +- test/simpletest/test/form_test.php +- test/simpletest/test/frames_test.php +- test/simpletest/test/http_test.php +- test/simpletest/test/live_test.php +- test/simpletest/test/mock_objects_test.php +- test/simpletest/test/page_test.php +- test/simpletest/test/parse_error_test.php +- test/simpletest/test/parser_test.php +- test/simpletest/test/remote_test.php +- test/simpletest/test/shell_test.php +- test/simpletest/test/shell_tester_test.php +- test/simpletest/test/simpletest_test.php +- test/simpletest/test/site/page_request.php +- test/simpletest/test/tag_test.php +- test/simpletest/test/unit_tester_test.php +- test/simpletest/test/user_agent_test.php +- test/simpletest/test/visual_test.php +- test/simpletest/test/xml_test.php +- test/simpletest/test_case.php +- test/simpletest/ui/array_reporter/test.php +- test/simpletest/ui/recorder/test.php +- test/simpletest/unit_tester.php +- test/simpletest/url.php +- test/simpletest/user_agent.php +- test/simpletest/web_tester.php +- test/spikephpcoverage/src/PEAR.php +- test/spikephpcoverage/src/util/Utility.php +- test/spikephpcoverage/src/XML/Parser.php +- test/spikephpcoverage/src/XML/Parser/Simple.php +- test/test_utilities/SugarTest_SimpleBrowser.php + +r38362 - 2008-07-28 14:06:59 -0700 (Mon, 28 Jul 2008) - roger - bug: 23897. Using print_r when using the debug statement in nusoap will print out the statements to the screen if the call is coming from the UI. + +r38300 - 2008-07-25 13:33:43 -0700 (Fri, 25 Jul 2008) - Samir Gandhi - put the debug in parseresponse function + +r38293 - 2008-07-25 12:32:34 -0700 (Fri, 25 Jul 2008) - Samir Gandhi - to put all the debug statements return value in the call function + +r36824 - 2008-06-18 09:26:11 -0700 (Wed, 18 Jun 2008) - roger - bug: 21832 + +r26422 - 2007-09-05 17:29:12 -0700 (Wed, 05 Sep 2007) - majed - migrate from beta 1 to trunk + +r15787 - 2006-08-10 10:14:41 -0700 (Thu, 10 Aug 2006) - roger - RRS: bug 7961 + +r14701 - 2006-07-17 13:37:26 -0700 (Mon, 17 Jul 2006) - roger - RRS: bug 5801 + +r13782 - 2006-06-06 10:58:55 -0700 (Tue, 06 Jun 2006) - majed - changes entry point code + +r11466 - 2006-02-01 15:49:47 -0800 (Wed, 01 Feb 2006) - jacob - Adding extra !empty check to get around a PHP warning. + +r11115 - 2006-01-17 14:54:45 -0800 (Tue, 17 Jan 2006) - majed - add entry point validation + +r10585 - 2005-12-13 14:42:26 -0800 (Tue, 13 Dec 2005) - majed - adds new license mechanisim + +r10170 - 2005-12-05 18:37:46 -0800 (Mon, 05 Dec 2005) - majed - fixes various issues + +r8999 - 2005-11-04 05:26:49 -0800 (Fri, 04 Nov 2005) - roger - When nusoap was upgraded we had an issue with the user's default language not being populated during a soap request. I determined the reason this was happening and have checked in the corresponding change to nusoap. + +r8991 - 2005-11-03 19:07:25 -0800 (Thu, 03 Nov 2005) - majed - fixes nusoap issue + +r8846 - 2005-10-31 11:01:12 -0800 (Mon, 31 Oct 2005) - majed - new version of nusoap + +r7905 - 2005-09-21 19:12:57 -0700 (Wed, 21 Sep 2005) - majed - restores old nusoap pre & with a few fixes + +r7861 - 2005-09-20 15:40:25 -0700 (Tue, 20 Sep 2005) - majed - & fix for 3.5.1 + +r7452 - 2005-08-17 11:32:34 -0700 (Wed, 17 Aug 2005) - majed - changes soap to nusoap + +r5820 - 2005-06-21 14:22:24 -0700 (Tue, 21 Jun 2005) - majed - fixes issues with nusoap and with custom fields + +r5462 - 2005-05-25 13:50:11 -0700 (Wed, 25 May 2005) - majed - upgraded nusoap to .6.9 + +r5104 - 2005-05-04 15:33:41 -0700 (Wed, 04 May 2005) - majed - gets rid of HTTP_GET_VARS and what not which has been deprecated + +r573 - 2004-09-04 13:03:32 -0700 (Sat, 04 Sep 2004) - sugarclint - undoing copyrights added in inadvertantly. --clint + +r546 - 2004-09-03 11:49:38 -0700 (Fri, 03 Sep 2004) - sugarmsi - removed echo count + +r354 - 2004-08-02 23:00:37 -0700 (Mon, 02 Aug 2004) - sugarjacob - Adding Soap + + +*/ + + + + + +/** +* +* nusoap_server allows the user to create a SOAP server +* that is capable of receiving messages and returning responses +* +* @author Dietrich Ayala +* @author Scott Nichol + +* @access public +*/ +class nusoap_server extends nusoap_base { + /** + * HTTP headers of request + * @var array + * @access private + */ + var $headers = array(); + /** + * HTTP request + * @var string + * @access private + */ + var $request = ''; + /** + * SOAP headers from request (incomplete namespace resolution; special characters not escaped) (text) + * @var string + * @access public + */ + var $requestHeaders = ''; + /** + * SOAP Headers from request (parsed) + * @var mixed + * @access public + */ + var $requestHeader = NULL; + /** + * SOAP body request portion (incomplete namespace resolution; special characters not escaped) (text) + * @var string + * @access public + */ + var $document = ''; + /** + * SOAP payload for request (text) + * @var string + * @access public + */ + var $requestSOAP = ''; + /** + * requested method namespace URI + * @var string + * @access private + */ + var $methodURI = ''; + /** + * name of method requested + * @var string + * @access private + */ + var $methodname = ''; + /** + * method parameters from request + * @var array + * @access private + */ + var $methodparams = array(); + /** + * SOAP Action from request + * @var string + * @access private + */ + var $SOAPAction = ''; + /** + * character set encoding of incoming (request) messages + * @var string + * @access public + */ + var $xml_encoding = ''; + /** + * toggles whether the parser decodes element content w/ utf8_decode() + * @var boolean + * @access public + */ + var $decode_utf8 = false; + + /** + * HTTP headers of response + * @var array + * @access public + */ + var $outgoing_headers = array(); + /** + * HTTP response + * @var string + * @access private + */ + var $response = ''; + /** + * SOAP headers for response (text or array of soapval or associative array) + * @var mixed + * @access public + */ + var $responseHeaders = ''; + /** + * SOAP payload for response (text) + * @var string + * @access private + */ + var $responseSOAP = ''; + /** + * method return value to place in response + * @var mixed + * @access private + */ + var $methodreturn = false; + /** + * whether $methodreturn is a string of literal XML + * @var boolean + * @access public + */ + var $methodreturnisliteralxml = false; + /** + * SOAP fault for response (or false) + * @var mixed + * @access private + */ + var $fault = false; + /** + * text indication of result (for debugging) + * @var string + * @access private + */ + var $result = 'successful'; + + /** + * assoc array of operations => opData; operations are added by the register() + * method or by parsing an external WSDL definition + * @var array + * @access private + */ + var $operations = array(); + /** + * wsdl instance (if one) + * @var mixed + * @access private + */ + var $wsdl = false; + /** + * URL for WSDL (if one) + * @var mixed + * @access private + */ + var $externalWSDLURL = false; + /** + * whether to append debug to response as XML comment + * @var boolean + * @access public + */ + var $debug_flag = false; + + + /** + * constructor + * the optional parameter is a path to a WSDL file that you'd like to bind the server instance to. + * + * @param mixed $wsdl file path or URL (string), or wsdl instance (object) + * @access public + */ + function nusoap_server($wsdl=false){ + parent::nusoap_base(); + // turn on debugging? + global $debug; + global $HTTP_SERVER_VARS; + + if (isset($_SERVER)) { + $this->debug("_SERVER is defined:"); + $this->appendDebug($this->varDump($_SERVER)); + } elseif (isset($HTTP_SERVER_VARS)) { + $this->debug("HTTP_SERVER_VARS is defined:"); + $this->appendDebug($this->varDump($HTTP_SERVER_VARS)); + } else { + $this->debug("Neither _SERVER nor HTTP_SERVER_VARS is defined."); + } + + if (isset($debug)) { + $this->debug("In nusoap_server, set debug_flag=$debug based on global flag"); + $this->debug_flag = $debug; + } elseif (isset($_SERVER['QUERY_STRING'])) { + $qs = explode('&', $_SERVER['QUERY_STRING']); + foreach ($qs as $v) { + if (substr($v, 0, 6) == 'debug=') { + $this->debug("In nusoap_server, set debug_flag=" . substr($v, 6) . " based on query string #1"); + $this->debug_flag = substr($v, 6); + } + } + } elseif (isset($HTTP_SERVER_VARS['QUERY_STRING'])) { + $qs = explode('&', $HTTP_SERVER_VARS['QUERY_STRING']); + foreach ($qs as $v) { + if (substr($v, 0, 6) == 'debug=') { + $this->debug("In nusoap_server, set debug_flag=" . substr($v, 6) . " based on query string #2"); + $this->debug_flag = substr($v, 6); + } + } + } + + // wsdl + if($wsdl){ + $this->debug("In nusoap_server, WSDL is specified"); + if (is_object($wsdl) && (get_class($wsdl) == 'wsdl')) { + $this->wsdl = $wsdl; + $this->externalWSDLURL = $this->wsdl->wsdl; + $this->debug('Use existing wsdl instance from ' . $this->externalWSDLURL); + } else { + $this->debug('Create wsdl from ' . $wsdl); + $this->wsdl = new wsdl($wsdl); + $this->externalWSDLURL = $wsdl; + } + $this->appendDebug($this->wsdl->getDebug()); + $this->wsdl->clearDebug(); + if($err = $this->wsdl->getError()){ + die('WSDL ERROR: '.$err); + } + } + } + + /** + * processes request and returns response + * + * @param string $data usually is the value of $HTTP_RAW_POST_DATA + * @access public + */ + function service($data){ + global $HTTP_SERVER_VARS; + + if (isset($_SERVER['REQUEST_METHOD'])) { + $rm = $_SERVER['REQUEST_METHOD']; + } elseif (isset($HTTP_SERVER_VARS['REQUEST_METHOD'])) { + $rm = $HTTP_SERVER_VARS['REQUEST_METHOD']; + } else { + $rm = ''; + } + + if (isset($_SERVER['QUERY_STRING'])) { + $qs = $_SERVER['QUERY_STRING']; + } elseif (isset($HTTP_SERVER_VARS['QUERY_STRING'])) { + $qs = $HTTP_SERVER_VARS['QUERY_STRING']; + } else { + $qs = ''; + } + $this->debug("In service, request method=$rm query string=$qs strlen(\$data)=" . strlen($data)); + + if ($rm == 'POST') { + $this->debug("In service, invoke the request"); + $this->parse_request($data); + if (! $this->fault) { + $this->invoke_method(); + } + if (! $this->fault) { + $this->serialize_return(); + } + $this->send_response(); + } elseif (preg_match('/wsdl/', $qs) ){ + $this->debug("In service, this is a request for WSDL"); + if ($this->externalWSDLURL){ + if (strpos($this->externalWSDLURL, "http://") !== false) { // assume URL + $this->debug("In service, re-direct for WSDL"); + header('Location: '.$this->externalWSDLURL); + } else { // assume file + $this->debug("In service, use file passthru for WSDL"); + header("Content-Type: text/xml\r\n"); + $pos = strpos($this->externalWSDLURL, "file://"); + if ($pos === false) { + $filename = $this->externalWSDLURL; + } else { + $filename = substr($this->externalWSDLURL, $pos + 7); + } + $fp = fopen($this->externalWSDLURL, 'r'); + fpassthru($fp); + } + } elseif ($this->wsdl) { + $this->debug("In service, serialize WSDL"); + header("Content-Type: text/xml; charset=ISO-8859-1\r\n"); + print $this->wsdl->serialize($this->debug_flag); + if ($this->debug_flag) { + $this->debug('wsdl:'); + $this->appendDebug($this->varDump($this->wsdl)); + print $this->getDebugAsXMLComment(); + } + } else { + $this->debug("In service, there is no WSDL"); + header("Content-Type: text/html; charset=ISO-8859-1\r\n"); + print "This service does not provide WSDL"; + } + } elseif ($this->wsdl) { + $this->debug("In service, return Web description"); + print $this->wsdl->webDescription(); + } else { + $this->debug("In service, no Web description"); + header("Content-Type: text/html; charset=ISO-8859-1\r\n"); + print "This service does not provide a Web description"; + } + } + + /** + * parses HTTP request headers. + * + * The following fields are set by this function (when successful) + * + * headers + * request + * xml_encoding + * SOAPAction + * + * @access private + */ + function parse_http_headers() { + global $HTTP_SERVER_VARS; + + $this->request = ''; + $this->SOAPAction = ''; + if(function_exists('getallheaders')){ + $this->debug("In parse_http_headers, use getallheaders"); + $headers = getallheaders(); + foreach($headers as $k=>$v){ + $k = strtolower($k); + $this->headers[$k] = $v; + $this->request .= "$k: $v\r\n"; + $this->debug("$k: $v"); + } + // get SOAPAction header + if(isset($this->headers['soapaction'])){ + $this->SOAPAction = str_replace('"','',$this->headers['soapaction']); + } + // get the character encoding of the incoming request + if(isset($this->headers['content-type']) && strpos($this->headers['content-type'],'=')){ + $enc = str_replace('"','',substr(strstr($this->headers["content-type"],'='),1)); + if(preg_match('/^(ISO-8859-1|US-ASCII|UTF-8)$/i',$enc)){ + $this->xml_encoding = strtoupper($enc); + } else { + $this->xml_encoding = 'US-ASCII'; + } + } else { + // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1 + $this->xml_encoding = 'ISO-8859-1'; + } + } elseif(isset($_SERVER) && is_array($_SERVER)){ + $this->debug("In parse_http_headers, use _SERVER"); + foreach ($_SERVER as $k => $v) { + if (substr($k, 0, 5) == 'HTTP_') { + $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', substr($k, 5)))); + } else { + $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', $k))); + } + if ($k == 'soapaction') { + // get SOAPAction header + $k = 'SOAPAction'; + $v = str_replace('"', '', $v); + $v = str_replace('\\', '', $v); + $this->SOAPAction = $v; + } else if ($k == 'content-type') { + // get the character encoding of the incoming request + if (strpos($v, '=')) { + $enc = substr(strstr($v, '='), 1); + $enc = str_replace('"', '', $enc); + $enc = str_replace('\\', '', $enc); + if (preg_match('/^(ISO-8859-1|US-ASCII|UTF-8)$/i',$enc)) { + $this->xml_encoding = strtoupper($enc); + } else { + $this->xml_encoding = 'US-ASCII'; + } + } else { + // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1 + $this->xml_encoding = 'ISO-8859-1'; + } + } + $this->headers[$k] = $v; + $this->request .= "$k: $v\r\n"; + $this->debug("$k: $v"); + } + } elseif (is_array($HTTP_SERVER_VARS)) { + $this->debug("In parse_http_headers, use HTTP_SERVER_VARS"); + foreach ($HTTP_SERVER_VARS as $k => $v) { + if (substr($k, 0, 5) == 'HTTP_') { + $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', substr($k, 5)))); $k = strtolower(substr($k, 5)); + } else { + $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', $k))); $k = strtolower($k); + } + if ($k == 'soapaction') { + // get SOAPAction header + $k = 'SOAPAction'; + $v = str_replace('"', '', $v); + $v = str_replace('\\', '', $v); + $this->SOAPAction = $v; + } else if ($k == 'content-type') { + // get the character encoding of the incoming request + if (strpos($v, '=')) { + $enc = substr(strstr($v, '='), 1); + $enc = str_replace('"', '', $enc); + $enc = str_replace('\\', '', $enc); + if (preg_match('/^(ISO-8859-1|US-ASCII|UTF-8)$/i',$enc)) { + $this->xml_encoding = strtoupper($enc); + } else { + $this->xml_encoding = 'US-ASCII'; + } + } else { + // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1 + $this->xml_encoding = 'ISO-8859-1'; + } + } + $this->headers[$k] = $v; + $this->request .= "$k: $v\r\n"; + $this->debug("$k: $v"); + } + } else { + $this->debug("In parse_http_headers, HTTP headers not accessible"); + $this->setError("HTTP headers not accessible"); + } + } + + /** + * parses a request + * + * The following fields are set by this function (when successful) + * + * headers + * request + * xml_encoding + * SOAPAction + * request + * requestSOAP + * methodURI + * methodname + * methodparams + * requestHeaders + * document + * + * This sets the fault field on error + * + * @param string $data XML string + * @access private + */ + function parse_request($data='') { + $this->debug('entering parse_request()'); + $this->parse_http_headers(); + $this->debug('got character encoding: '.$this->xml_encoding); + // uncompress if necessary + if (isset($this->headers['content-encoding']) && $this->headers['content-encoding'] != '') { + $this->debug('got content encoding: ' . $this->headers['content-encoding']); + if ($this->headers['content-encoding'] == 'deflate' || $this->headers['content-encoding'] == 'gzip') { + // if decoding works, use it. else assume data wasn't gzencoded + if (function_exists('gzuncompress')) { + if ($this->headers['content-encoding'] == 'deflate' && $degzdata = @gzuncompress($data)) { + $data = $degzdata; + } elseif ($this->headers['content-encoding'] == 'gzip' && $degzdata = gzinflate(substr($data, 10))) { + $data = $degzdata; + } else { + $this->fault('SOAP-ENV:Client', 'Errors occurred when trying to decode the data'); + return; + } + } else { + $this->fault('SOAP-ENV:Client', 'This Server does not support compressed data'); + return; + } + } + } + $this->request .= "\r\n".$data; + $data = $this->parseRequest($this->headers, $data); + $this->requestSOAP = $data; + $this->debug('leaving parse_request'); + } + + function register_class($classname){ + $this->registeredClass = $classname; + } + /** + * invokes a PHP function for the requested SOAP method + * + * The following fields are set by this function (when successful) + * + * methodreturn + * + * Note that the PHP function that is called may also set the following + * fields to affect the response sent to the client + * + * responseHeaders + * outgoing_headers + * + * This sets the fault field on error + * + * @access private + */ + function invoke_method() { + $this->debug('in invoke_method, methodname=' . $this->methodname . ' methodURI=' . $this->methodURI . ' SOAPAction=' . $this->SOAPAction); + + // + // if you are debugging in this area of the code, your service uses a class to implement methods, + // you use SOAP RPC, and the client is .NET, please be aware of the following... + // when the .NET wsdl.exe utility generates a proxy, it will remove the '.' or '..' from the + // method name. that is fine for naming the .NET methods. it is not fine for properly constructing + // the XML request and reading the XML response. you need to add the RequestElementName and + // ResponseElementName to the System.Web.Services.Protocols.SoapRpcMethodAttribute that wsdl.exe + // generates for the method. these parameters are used to specify the correct XML element names + // for .NET to use, i.e. the names with the '.' in them. + // + $orig_methodname = $this->methodname; + if ($this->wsdl) { + if ($this->opData = $this->wsdl->getOperationData($this->methodname)) { + $this->debug('in invoke_method, found WSDL operation=' . $this->methodname); + $this->appendDebug('opData=' . $this->varDump($this->opData)); + } elseif ($this->opData = $this->wsdl->getOperationDataForSoapAction($this->SOAPAction)) { + // Note: hopefully this case will only be used for doc/lit, since rpc services should have wrapper element + $this->debug('in invoke_method, found WSDL soapAction=' . $this->SOAPAction . ' for operation=' . $this->opData['name']); + $this->appendDebug('opData=' . $this->varDump($this->opData)); + $this->methodname = $this->opData['name']; + } else { + $this->debug('in invoke_method, no WSDL for operation=' . $this->methodname); + $this->fault('SOAP-ENV:Client', "Operation '" . $this->methodname . "' is not defined in the WSDL for this service"); + return; + } + } else { + $this->debug('in invoke_method, no WSDL to validate method'); + } + + // if a . is present in $this->methodname, we see if there is a class in scope, + // which could be referred to. We will also distinguish between two deliminators, + // to allow methods to be called a the class or an instance + if (strpos($this->methodname, '..') > 0) { + $delim = '..'; + } else if (strpos($this->methodname, '.') > 0) { + $delim = '.'; + } else { + $delim = ''; + } + $this->debug("in invoke_method, delim=$delim"); + + $class = ''; + $method = ''; + if (strlen($delim) > 0 && substr_count($this->methodname, $delim) == 1) { + $try_class = substr($this->methodname, 0, strpos($this->methodname, $delim)); + if (class_exists($try_class)) { + // get the class and method name + $class = $try_class; + $method = substr($this->methodname, strpos($this->methodname, $delim) + strlen($delim)); + $this->debug("in invoke_method, class=$class method=$method delim=$delim"); + } else { + $this->debug("in invoke_method, class=$try_class not found"); + } + } else { + $try_class = ''; + $this->debug("in invoke_method, no class to try"); + } + if(empty($delim) && isset($this->registeredClass)){ + $class = $this->registeredClass; + $delim = '..'; + $method = $this->methodname; + } + + // does method exist? + if ($class == '') { + if (!function_exists($this->methodname)) { + $this->debug("in invoke_method, function '$this->methodname' not found!"); + $this->result = 'fault: method not found'; + $this->fault('SOAP-ENV:Client',"method '$this->methodname'('$orig_methodname') not defined in service('$try_class' '$delim')"); + return; + } + } else { + $method_to_compare = (substr(phpversion(), 0, 2) == '4.') ? strtolower($method) : $method; + if (!in_array($method_to_compare, get_class_methods($class))) { + $this->debug("in invoke_method, method '$this->methodname' not found in class '$class'!"); + $this->result = 'fault: method not found'; + $this->fault('SOAP-ENV:Client',"method '$this->methodname'/'$method_to_compare'('$orig_methodname') not defined in service/'$class'('$try_class' '$delim')"); + return; + } + } + + // evaluate message, getting back parameters + // verify that request parameters match the method's signature + if(! $this->verify_method($this->methodname,$this->methodparams)){ + // debug + $this->debug('ERROR: request not verified against method signature'); + $this->result = 'fault: request failed validation against method signature'; + // return fault + $this->fault('SOAP-ENV:Client',"Operation '$this->methodname' not defined in service."); + return; + } + + // if there are parameters to pass + $this->debug('in invoke_method, params:'); + $this->appendDebug($this->varDump($this->methodparams)); + $this->debug("in invoke_method, calling '$this->methodname'"); + if (!function_exists('call_user_func_array')) { + if ($class == '') { + $this->debug('in invoke_method, calling function using eval()'); + $funcCall = "\$this->methodreturn = $this->methodname("; + } else { + if ($delim == '..') { + $this->debug('in invoke_method, calling class method using eval()'); + $funcCall = "\$this->methodreturn = ".$class."::".$method."("; + } else { + $this->debug('in invoke_method, calling instance method using eval()'); + // generate unique instance name + $instname = "\$inst_".time(); + $funcCall = $instname." = new ".$class."(); "; + $funcCall .= "\$this->methodreturn = ".$instname."->".$method."("; + } + } + if ($this->methodparams) { + foreach ($this->methodparams as $param) { + if (is_array($param) || is_object($param)) { + $this->fault('SOAP-ENV:Client', 'NuSOAP does not handle complexType parameters correctly when using eval; call_user_func_array must be available'); + return; + } + $funcCall .= "\"$param\","; + } + $funcCall = substr($funcCall, 0, -1); + } + $funcCall .= ');'; + $this->debug('in invoke_method, function call: '.$funcCall); + @eval($funcCall); + } else { + if ($class == '') { + $this->debug('in invoke_method, calling function using call_user_func_array()'); + $call_arg = "$this->methodname"; // straight assignment changes $this->methodname to lower case after call_user_func_array() + } elseif ($delim == '..') { + $this->debug('in invoke_method, calling class method using call_user_func_array()'); + $call_arg = array ($class, $method); + } else { + $this->debug('in invoke_method, calling instance method using call_user_func_array()'); + $instance = new $class (); + $call_arg = array(&$instance, $method); + } + if (is_array($this->methodparams)) { + $this->methodreturn = call_user_func_array($call_arg, array_values($this->methodparams)); + } else { + $this->methodreturn = call_user_func_array($call_arg, array()); + } + } + $this->debug('in invoke_method, methodreturn:'); + $this->appendDebug($this->varDump($this->methodreturn)); + $this->debug("in invoke_method, called method $this->methodname, received data of type ".gettype($this->methodreturn)); + } + + /** + * serializes the return value from a PHP function into a full SOAP Envelope + * + * The following fields are set by this function (when successful) + * + * responseSOAP + * + * This sets the fault field on error + * + * @access private + */ + function serialize_return() { + $this->debug('Entering serialize_return methodname: ' . $this->methodname . ' methodURI: ' . $this->methodURI); + // if fault + if (isset($this->methodreturn) && is_object($this->methodreturn) && ((get_class($this->methodreturn) == 'soap_fault') || (get_class($this->methodreturn) == 'nusoap_fault'))) { + $this->debug('got a fault object from method'); + $this->fault = $this->methodreturn; + return; + } elseif ($this->methodreturnisliteralxml) { + $return_val = $this->methodreturn; + // returned value(s) + } else { + $this->debug('got a(n) '.gettype($this->methodreturn).' from method'); + $this->debug('serializing return value'); + if($this->wsdl){ + if (sizeof($this->opData['output']['parts']) > 1) { + $this->debug('more than one output part, so use the method return unchanged'); + $opParams = $this->methodreturn; + } elseif (sizeof($this->opData['output']['parts']) == 1) { + $this->debug('exactly one output part, so wrap the method return in a simple array'); + // TODO: verify that it is not already wrapped! + //foreach ($this->opData['output']['parts'] as $name => $type) { + // $this->debug('wrap in element named ' . $name); + //} + $opParams = array($this->methodreturn); + } + $return_val = $this->wsdl->serializeRPCParameters($this->methodname,'output',$opParams); + $this->appendDebug($this->wsdl->getDebug()); + $this->wsdl->clearDebug(); + if($errstr = $this->wsdl->getError()){ + $this->debug('got wsdl error: '.$errstr); + $this->fault('SOAP-ENV:Server', 'unable to serialize result'); + return; + } + } else { + if (isset($this->methodreturn)) { + $return_val = $this->serialize_val($this->methodreturn, 'return'); + } else { + $return_val = ''; + $this->debug('in absence of WSDL, assume void return for backward compatibility'); + } + } + } + $this->debug('return value:'); + $this->appendDebug($this->varDump($return_val)); + + $this->debug('serializing response'); + if ($this->wsdl) { + $this->debug('have WSDL for serialization: style is ' . $this->opData['style']); + if ($this->opData['style'] == 'rpc') { + $this->debug('style is rpc for serialization: use is ' . $this->opData['output']['use']); + if ($this->opData['output']['use'] == 'literal') { + // http://www.ws-i.org/Profiles/BasicProfile-1.1-2004-08-24.html R2735 says rpc/literal accessor elements should not be in a namespace + if ($this->methodURI) { + $payload = 'methodname.'Response xmlns:ns1="'.$this->methodURI.'">'.$return_val.'methodname."Response>"; + } else { + $payload = '<'.$this->methodname.'Response>'.$return_val.'methodname.'Response>'; + } + } else { + if ($this->methodURI) { + $payload = 'methodname.'Response xmlns:ns1="'.$this->methodURI.'">'.$return_val.'methodname."Response>"; + } else { + $payload = '<'.$this->methodname.'Response>'.$return_val.'methodname.'Response>'; + } + } + } else { + $this->debug('style is not rpc for serialization: assume document'); + $payload = $return_val; + } + } else { + $this->debug('do not have WSDL for serialization: assume rpc/encoded'); + $payload = 'methodname.'Response xmlns:ns1="'.$this->methodURI.'">'.$return_val.'methodname."Response>"; + } + $this->result = 'successful'; + if($this->wsdl){ + //if($this->debug_flag){ + $this->appendDebug($this->wsdl->getDebug()); + // } + if (isset($this->opData['output']['encodingStyle'])) { + $encodingStyle = $this->opData['output']['encodingStyle']; + } else { + $encodingStyle = ''; + } + // Added: In case we use a WSDL, return a serialized env. WITH the usedNamespaces. + $this->responseSOAP = $this->serializeEnvelope($payload,$this->responseHeaders,$this->wsdl->usedNamespaces,$this->opData['style'],$this->opData['output']['use'],$encodingStyle); + } else { + $this->responseSOAP = $this->serializeEnvelope($payload,$this->responseHeaders); + } + $this->debug("Leaving serialize_return"); + } + + /** + * sends an HTTP response + * + * The following fields are set by this function (when successful) + * + * outgoing_headers + * response + * + * @access private + */ + function send_response() { + $this->debug('Enter send_response'); + if ($this->fault) { + $payload = $this->fault->serialize(); + $this->outgoing_headers[] = "HTTP/1.0 500 Internal Server Error"; + $this->outgoing_headers[] = "Status: 500 Internal Server Error"; + } else { + $payload = $this->responseSOAP; + // Some combinations of PHP+Web server allow the Status + // to come through as a header. Since OK is the default + // just do nothing. + // $this->outgoing_headers[] = "HTTP/1.0 200 OK"; + // $this->outgoing_headers[] = "Status: 200 OK"; + } + // add debug data if in debug mode + if(isset($this->debug_flag) && $this->debug_flag){ + $payload .= $this->getDebugAsXMLComment(); + } + $this->outgoing_headers[] = "Server: $this->title Server v$this->version"; + preg_match('/\$Revisio' . 'n: ([^ ]+)/', $this->revision, $rev); + $this->outgoing_headers[] = "X-SOAP-Server: $this->title/$this->version (".$rev[1].")"; + // Let the Web server decide about this + //$this->outgoing_headers[] = "Connection: Close\r\n"; + $payload = $this->getHTTPBody($payload); + $type = $this->getHTTPContentType(); + $charset = $this->getHTTPContentTypeCharset(); + $this->outgoing_headers[] = "Content-Type: $type" . ($charset ? '; charset=' . $charset : ''); + //begin code to compress payload - by John + // NOTE: there is no way to know whether the Web server will also compress + // this data. + if (strlen($payload) > 1024 && isset($this->headers) && isset($this->headers['accept-encoding'])) { + if (strstr($this->headers['accept-encoding'], 'gzip')) { + if (function_exists('gzencode')) { + if (isset($this->debug_flag) && $this->debug_flag) { + $payload .= ""; + } + $this->outgoing_headers[] = "Content-Encoding: gzip"; + $payload = gzencode($payload); + } else { + if (isset($this->debug_flag) && $this->debug_flag) { + $payload .= ""; + } + } + } elseif (strstr($this->headers['accept-encoding'], 'deflate')) { + // Note: MSIE requires gzdeflate output (no Zlib header and checksum), + // instead of gzcompress output, + // which conflicts with HTTP 1.1 spec (http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.5) + if (function_exists('gzdeflate')) { + if (isset($this->debug_flag) && $this->debug_flag) { + $payload .= ""; + } + $this->outgoing_headers[] = "Content-Encoding: deflate"; + $payload = gzdeflate($payload); + } else { + if (isset($this->debug_flag) && $this->debug_flag) { + $payload .= ""; + } + } + } + } + //end code + ob_end_clean(); + ob_start(); + $this->outgoing_headers[] = "Content-Length: ".strlen($payload); + reset($this->outgoing_headers); + foreach($this->outgoing_headers as $hdr){ + header($hdr, false); + } + print $payload; + ob_flush(); + + $this->response = join("\r\n",$this->outgoing_headers)."\r\n\r\n".$payload; + } + + /** + * takes the value that was created by parsing the request + * and compares to the method's signature, if available. + * + * @param string $operation The operation to be invoked + * @param array $request The array of parameter values + * @return boolean Whether the operation was found + * @access private + */ + function verify_method($operation,$request){ + if(isset($this->wsdl) && is_object($this->wsdl)){ + if($this->wsdl->getOperationData($operation)){ + return true; + } + } elseif(isset($this->operations[$operation])){ + return true; + } + return false; + } + + /** + * processes SOAP message received from client + * + * @param array $headers The HTTP headers + * @param string $data unprocessed request data from client + * @return mixed value of the message, decoded into a PHP type + * @access private + */ + function parseRequest($headers, $data) { + $this->debug('Entering parseRequest() for data of length ' . strlen($data) . ' headers:'); + $this->appendDebug($this->varDump($headers)); + if (!isset($headers['content-type'])) { + $this->setError('Request not of type text/xml (no content-type header)'); + return false; + } + if (!strstr($headers['content-type'], 'text/xml')) { + $this->setError('Request not of type text/xml'); + return false; + } + if (strpos($headers['content-type'], '=')) { + $enc = str_replace('"', '', substr(strstr($headers["content-type"], '='), 1)); + $this->debug('Got response encoding: ' . $enc); + if(preg_match('/^(ISO-8859-1|US-ASCII|UTF-8)$/i',$enc)){ + $this->xml_encoding = strtoupper($enc); + } else { + $this->xml_encoding = 'US-ASCII'; + } + } else { + // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1 + $this->xml_encoding = 'ISO-8859-1'; + } + $this->debug('Use encoding: ' . $this->xml_encoding . ' when creating nusoap_parser'); + // parse response, get soap parser obj + $parser = new nusoap_parser($data,$this->xml_encoding,'',$this->decode_utf8); + // parser debug + $this->debug("parser debug: \n".$parser->getDebug()); + // if fault occurred during message parsing + if($err = $parser->getError()){ + $this->result = 'fault: error in msg parsing: '.$err; + $this->fault('SOAP-ENV:Client',"error in msg parsing:\n".$err); + // else successfully parsed request into soapval object + } else { + // get/set methodname + $this->methodURI = $parser->root_struct_namespace; + $this->methodname = $parser->root_struct_name; + $this->debug('methodname: '.$this->methodname.' methodURI: '.$this->methodURI); + $this->debug('calling parser->get_soapbody()'); + $this->methodparams = $parser->get_soapbody(); + // get SOAP headers + $this->requestHeaders = $parser->getHeaders(); + // get SOAP Header + $this->requestHeader = $parser->get_soapheader(); + // add document for doclit support + $this->document = $parser->document; + } + } + + /** + * gets the HTTP body for the current response. + * + * @param string $soapmsg The SOAP payload + * @return string The HTTP body, which includes the SOAP payload + * @access private + */ + function getHTTPBody($soapmsg) { + return $soapmsg; + } + + /** + * gets the HTTP content type for the current response. + * + * Note: getHTTPBody must be called before this. + * + * @return string the HTTP content type for the current response. + * @access private + */ + function getHTTPContentType() { + return 'text/xml'; + } + + /** + * gets the HTTP content type charset for the current response. + * returns false for non-text content types. + * + * Note: getHTTPBody must be called before this. + * + * @return string the HTTP content type charset for the current response. + * @access private + */ + function getHTTPContentTypeCharset() { + return $this->soap_defencoding; + } + + /** + * add a method to the dispatch map (this has been replaced by the register method) + * + * @param string $methodname + * @param string $in array of input values + * @param string $out array of output values + * @access public + * @deprecated + */ + function add_to_map($methodname,$in,$out){ + $this->operations[$methodname] = array('name' => $methodname,'in' => $in,'out' => $out); + } + + /** + * register a service function with the server + * + * @param string $name the name of the PHP function, class.method or class..method + * @param array $in assoc array of input values: key = param name, value = param type + * @param array $out assoc array of output values: key = param name, value = param type + * @param mixed $namespace the element namespace for the method or false + * @param mixed $soapaction the soapaction for the method or false + * @param mixed $style optional (rpc|document) or false Note: when 'document' is specified, parameter and return wrappers are created for you automatically + * @param mixed $use optional (encoded|literal) or false + * @param string $documentation optional Description to include in WSDL + * @param string $encodingStyle optional (usually 'http://schemas.xmlsoap.org/soap/encoding/' for encoded) + * @access public + */ + function register($name,$in=array(),$out=array(),$namespace=false,$soapaction=false,$style=false,$use=false,$documentation='',$encodingStyle=''){ + global $HTTP_SERVER_VARS; + + if($this->externalWSDLURL){ + die('You cannot bind to an external WSDL file, and register methods outside of it! Please choose either WSDL or no WSDL.'); + } + if (! $name) { + die('You must specify a name when you register an operation'); + } + if (!is_array($in)) { + die('You must provide an array for operation inputs'); + } + if (!is_array($out)) { + die('You must provide an array for operation outputs'); + } + if(false == $namespace) { + } + if(false == $soapaction) { + if (isset($_SERVER)) { + $SERVER_NAME = $_SERVER['SERVER_NAME']; + $SCRIPT_NAME = isset($_SERVER['PHP_SELF']) ? $_SERVER['PHP_SELF'] : $_SERVER['SCRIPT_NAME']; + $HTTPS = isset($_SERVER['HTTPS']) ? $_SERVER['HTTPS'] : (isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off'); + } elseif (isset($HTTP_SERVER_VARS)) { + $SERVER_NAME = $HTTP_SERVER_VARS['SERVER_NAME']; + $SCRIPT_NAME = isset($HTTP_SERVER_VARS['PHP_SELF']) ? $HTTP_SERVER_VARS['PHP_SELF'] : $HTTP_SERVER_VARS['SCRIPT_NAME']; + $HTTPS = isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off'; + } else { + $this->setError("Neither _SERVER nor HTTP_SERVER_VARS is available"); + } + if ($HTTPS == '1' || $HTTPS == 'on') { + $SCHEME = 'https'; + } else { + $SCHEME = 'http'; + } + $soapaction = "$SCHEME://$SERVER_NAME$SCRIPT_NAME/$name"; + } + if(false == $style) { + $style = "rpc"; + } + if(false == $use) { + $use = "encoded"; + } + if ($use == 'encoded' && $encodingStyle == '') { + $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/'; + } + + $this->operations[$name] = array( + 'name' => $name, + 'in' => $in, + 'out' => $out, + 'namespace' => $namespace, + 'soapaction' => $soapaction, + 'style' => $style); + if($this->wsdl){ + $this->wsdl->addOperation($name,$in,$out,$namespace,$soapaction,$style,$use,$documentation,$encodingStyle); + } + return true; + } + + /** + * Specify a fault to be returned to the client. + * This also acts as a flag to the server that a fault has occured. + * + * @param string $faultcode + * @param string $faultstring + * @param string $faultactor + * @param string $faultdetail + * @access public + */ + function fault($faultcode,$faultstring,$faultactor='',$faultdetail=''){ + if ($faultdetail == '' && $this->debug_flag) { + $faultdetail = $this->getDebug(); + } + $this->fault = new nusoap_fault($faultcode,$faultactor,$faultstring,$faultdetail); + $this->fault->soap_defencoding = $this->soap_defencoding; + } + + /** + * Sets up wsdl object. + * Acts as a flag to enable internal WSDL generation + * + * @param string $serviceName, name of the service + * @param mixed $namespace optional 'tns' service namespace or false + * @param mixed $endpoint optional URL of service endpoint or false + * @param string $style optional (rpc|document) WSDL style (also specified by operation) + * @param string $transport optional SOAP transport + * @param mixed $schemaTargetNamespace optional 'types' targetNamespace for service schema or false + */ + function configureWSDL($serviceName,$namespace = false,$endpoint = false,$style='rpc', $transport = 'http://schemas.xmlsoap.org/soap/http', $schemaTargetNamespace = false) + { + global $HTTP_SERVER_VARS; + + if (isset($_SERVER)) { + $SERVER_NAME = $_SERVER['SERVER_NAME']; + $SERVER_PORT = $_SERVER['SERVER_PORT']; + $SCRIPT_NAME = isset($_SERVER['PHP_SELF']) ? $_SERVER['PHP_SELF'] : $_SERVER['SCRIPT_NAME']; + $HTTPS = isset($_SERVER['HTTPS']) ? $_SERVER['HTTPS'] : (isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off'); + } elseif (isset($HTTP_SERVER_VARS)) { + $SERVER_NAME = $HTTP_SERVER_VARS['SERVER_NAME']; + $SERVER_PORT = $HTTP_SERVER_VARS['SERVER_PORT']; + $SCRIPT_NAME = isset($HTTP_SERVER_VARS['PHP_SELF']) ? $HTTP_SERVER_VARS['PHP_SELF'] : $HTTP_SERVER_VARS['SCRIPT_NAME']; + $HTTPS = isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off'; + } else { + $this->setError("Neither _SERVER nor HTTP_SERVER_VARS is available"); + } + // If server name has port number attached then strip it (else port number gets duplicated in WSDL output) (occurred using lighttpd and FastCGI) + $colon = strpos($SERVER_NAME,":"); + if ($colon) { + $SERVER_NAME = substr($SERVER_NAME, 0, $colon); + } + if ($SERVER_PORT == 80) { + $SERVER_PORT = ''; + } else { + $SERVER_PORT = ':' . $SERVER_PORT; + } + if(false == $namespace) { + $namespace = "http://$SERVER_NAME/soap/$serviceName"; + } + + if(false == $endpoint) { + if ($HTTPS == '1' || $HTTPS == 'on') { + $SCHEME = 'https'; + } else { + $SCHEME = 'http'; + } + $endpoint = "$SCHEME://$SERVER_NAME$SERVER_PORT$SCRIPT_NAME"; + } + + if(false == $schemaTargetNamespace) { + $schemaTargetNamespace = $namespace; + } + + $this->wsdl = new wsdl; + $this->wsdl->serviceName = $serviceName; + $this->wsdl->endpoint = $endpoint; + $this->wsdl->namespaces['tns'] = $namespace; + $this->wsdl->namespaces['soap'] = 'http://schemas.xmlsoap.org/wsdl/soap/'; + $this->wsdl->namespaces['wsdl'] = 'http://schemas.xmlsoap.org/wsdl/'; + if ($schemaTargetNamespace != $namespace) { + $this->wsdl->namespaces['types'] = $schemaTargetNamespace; + } + $this->wsdl->schemas[$schemaTargetNamespace][0] = new nusoap_xmlschema('', '', $this->wsdl->namespaces); + if ($style == 'document') { + $this->wsdl->schemas[$schemaTargetNamespace][0]->schemaInfo['elementFormDefault'] = 'qualified'; + } + $this->wsdl->schemas[$schemaTargetNamespace][0]->schemaTargetNamespace = $schemaTargetNamespace; + $this->wsdl->schemas[$schemaTargetNamespace][0]->imports['http://schemas.xmlsoap.org/soap/encoding/'][0] = array('location' => '', 'loaded' => true); + $this->wsdl->schemas[$schemaTargetNamespace][0]->imports['http://schemas.xmlsoap.org/wsdl/'][0] = array('location' => '', 'loaded' => true); + $this->wsdl->bindings[$serviceName.'Binding'] = array( + 'name'=>$serviceName.'Binding', + 'style'=>$style, + 'transport'=>$transport, + 'portType'=>$serviceName.'PortType'); + $this->wsdl->ports[$serviceName.'Port'] = array( + 'binding'=>$serviceName.'Binding', + 'location'=>$endpoint, + 'bindingType'=>'http://schemas.xmlsoap.org/wsdl/soap/'); + } +} + +/** + * Backward compatibility + */ +class soap_server extends nusoap_server { +} + +?> + bug 40066 + +r58361 - 2010-09-29 16:59:02 -0700 (Wed, 29 Sep 2010) - kjing - Author: Jenny Gonsalves + Merging with maint_6_0_1 (svn merge -r 58250:58342) + +r57813 - 2010-08-19 10:34:44 -0700 (Thu, 19 Aug 2010) - kjing - Author: John Mertic + Bug 39085 - When loading the opposite search panel via ajax on the ListViews, call the index action instead of the ListView action to avoid touching pre-MVC code by accident. + +r57707 - 2010-08-10 12:26:13 -0700 (Tue, 10 Aug 2010) - kjing - Author: Stanislav Malyshev + fix SOAP calls with no parameters + +r56990 - 2010-06-16 13:05:36 -0700 (Wed, 16 Jun 2010) - kjing - snapshot "Mango" svn branch to a new one for GitHub sync + +r56989 - 2010-06-16 13:01:33 -0700 (Wed, 16 Jun 2010) - kjing - defunt "Mango" svn dev branch before github cutover + +r55980 - 2010-04-19 13:31:28 -0700 (Mon, 19 Apr 2010) - kjing - create Mango (6.1) based on windex + +r51719 - 2009-10-22 10:18:00 -0700 (Thu, 22 Oct 2009) - mitani - Converted to Build 3 tags and updated the build system + +r51634 - 2009-10-19 13:32:22 -0700 (Mon, 19 Oct 2009) - mitani - Windex is the branch for Sugar Sales 1.0 development + +r51508 - 2009-10-14 07:40:23 -0700 (Wed, 14 Oct 2009) - jmertic - More fallout fixes from the PHP 5.3 ereg to preg changes. + +r51455 - 2009-10-13 07:56:48 -0700 (Tue, 13 Oct 2009) - jmertic - Bug 33202 - Enable install of SugarCRM on PHP 5.3.0, asserting that the minimum supported version is PHP 5.2.x. + +r51443 - 2009-10-12 13:34:36 -0700 (Mon, 12 Oct 2009) - jmertic - Bug 33332 - Made application PHP 5.3 compliant with E_DEPRECATED warnings on by: +- Changing all ereg function to either preg or simple string based ones +- No more references to magic quotes. +- Change all the session_unregister() functions to just unset() the correct session variable instead. + +r50375 - 2009-08-24 18:07:43 -0700 (Mon, 24 Aug 2009) - dwong - branch kobe2 from tokyo r50372 + +r45763 - 2009-04-01 12:16:18 -0700 (Wed, 01 Apr 2009) - majed - Removed half of the require_once and include_onces in the product that were redundant or could be handled easily by the auto loader + +r45680 - 2009-03-30 14:34:35 -0700 (Mon, 30 Mar 2009) - Samir Gandhi - modifeid serializeSchema to generate WS-I compliant WSDL + +r42807 - 2008-12-29 11:16:59 -0800 (Mon, 29 Dec 2008) - dwong - Branch from trunk/sugarcrm r42806 to branches/tokyo/sugarcrm + +r42645 - 2008-12-18 13:41:08 -0800 (Thu, 18 Dec 2008) - awu - merging maint_5_2_0 rev41336:HEAD to trunk + +r41647 - 2008-11-11 17:44:30 -0800 (Tue, 11 Nov 2008) - majed - Fixes a few bugs + +r41596 - 2008-11-10 19:20:04 -0800 (Mon, 10 Nov 2008) - Samir Gandhi - modified to set $method in the code + +r41558 - 2008-11-10 14:35:34 -0800 (Mon, 10 Nov 2008) - majed - changes nusoap to allow for registering classes + +r39619 - 2008-09-09 13:41:34 -0700 (Tue, 09 Sep 2008) - jmertic - Bug 24827 - Remove all instances where we return a new object and assign it by reference, since this is deprecated in PHP 5 and emits E_DEPRECATED errors in PHP 5.3. +Touched: +- data/SugarBean.php +- include/domit/php_http_client_generic.php +- include/domit/php_http_connector.php +- include/domit/testing_domit.php +- include/domit/xml_domit_getelementsbypath.php +- include/domit/xml_domit_lite_parser.php +- include/domit/xml_domit_nodemaps.php +- include/domit/xml_domit_parser.php +- include/domit/xml_domit_shared.php +- include/generic/SugarWidgets/SugarWidgetField.php +- include/generic/SugarWidgets/SugarWidgetReportField.php +- include/ListView/ProcessView.php +- include/nusoap/class.soapclient.php +- include/nusoap/nusoap.php +- include/nusoap/nusoapmime.php +- include/Pear/HTML_Safe/Safe.php +- include/Pear/XML_HTMLSax3/HTMLSax3.php +- modules/Administration/RebuildWorkFlow.php +- modules/Expressions/RelateSelector.php +- modules/Reports/templates/templates_reports.php +- modules/WorkFlow/Delete.php +- modules/WorkFlow/Save.php +- modules/WorkFlow/SaveSequence.php +- modules/WorkFlow/WorkFlow.php +- modules/WorkFlowActionShells/CreateStep1.php +- modules/WorkFlowActionShells/CreateStep2.php +- modules/WorkFlowActionShells/Save.php +- modules/WorkFlowActionShells/WorkFlowActionShell.php +- modules/WorkFlowAlerts/Save.php +- modules/WorkFlowAlerts/WorkFlowAlert.php +- modules/WorkFlowAlertShells/DetailView.php +- modules/WorkFlowAlertShells/WorkFlowAlertShell.php +- modules/WorkFlowTriggerShells/CreateStep1.php +- modules/WorkFlowTriggerShells/CreateStepFilter.php +- modules/WorkFlowTriggerShells/SaveFilter.php +- modules/WorkFlowTriggerShells/WorkFlowTriggerShell.php +- soap/SoapHelperFunctions.php +- test/modules/DynamicFields/DynamicFields_Bug24095_test.php +- test/simpletest/browser.php +- test/simpletest/default_reporter.php +- test/simpletest/detached.php +- test/simpletest/eclipse.php +- test/simpletest/expectation.php +- test/simpletest/extensions/pear_test_case.php +- test/simpletest/form.php +- test/simpletest/http.php +- test/simpletest/mock_objects.php +- test/simpletest/page.php +- test/simpletest/parser.php +- test/simpletest/remote.php +- test/simpletest/shell_tester.php +- test/simpletest/simple_test.php +- test/simpletest/simpletest.php +- test/simpletest/test/acceptance_test.php +- test/simpletest/test/adapter_test.php +- test/simpletest/test/authentication_test.php +- test/simpletest/test/browser_test.php +- test/simpletest/test/collector_test.php +- test/simpletest/test/compatibility_test.php +- test/simpletest/test/detached_test.php +- test/simpletest/test/eclipse_test.php +- test/simpletest/test/encoding_test.php +- test/simpletest/test/errors_test.php +- test/simpletest/test/expectation_test.php +- test/simpletest/test/form_test.php +- test/simpletest/test/frames_test.php +- test/simpletest/test/http_test.php +- test/simpletest/test/live_test.php +- test/simpletest/test/mock_objects_test.php +- test/simpletest/test/page_test.php +- test/simpletest/test/parse_error_test.php +- test/simpletest/test/parser_test.php +- test/simpletest/test/remote_test.php +- test/simpletest/test/shell_test.php +- test/simpletest/test/shell_tester_test.php +- test/simpletest/test/simpletest_test.php +- test/simpletest/test/site/page_request.php +- test/simpletest/test/tag_test.php +- test/simpletest/test/unit_tester_test.php +- test/simpletest/test/user_agent_test.php +- test/simpletest/test/visual_test.php +- test/simpletest/test/xml_test.php +- test/simpletest/test_case.php +- test/simpletest/ui/array_reporter/test.php +- test/simpletest/ui/recorder/test.php +- test/simpletest/unit_tester.php +- test/simpletest/url.php +- test/simpletest/user_agent.php +- test/simpletest/web_tester.php +- test/spikephpcoverage/src/PEAR.php +- test/spikephpcoverage/src/util/Utility.php +- test/spikephpcoverage/src/XML/Parser.php +- test/spikephpcoverage/src/XML/Parser/Simple.php +- test/test_utilities/SugarTest_SimpleBrowser.php + +r38362 - 2008-07-28 14:06:59 -0700 (Mon, 28 Jul 2008) - roger - bug: 23897. Using print_r when using the debug statement in nusoap will print out the statements to the screen if the call is coming from the UI. + +r38300 - 2008-07-25 13:33:43 -0700 (Fri, 25 Jul 2008) - Samir Gandhi - put the debug in parseresponse function + +r38293 - 2008-07-25 12:32:34 -0700 (Fri, 25 Jul 2008) - Samir Gandhi - to put all the debug statements return value in the call function + +r36824 - 2008-06-18 09:26:11 -0700 (Wed, 18 Jun 2008) - roger - bug: 21832 + +r26422 - 2007-09-05 17:29:12 -0700 (Wed, 05 Sep 2007) - majed - migrate from beta 1 to trunk + +r15787 - 2006-08-10 10:14:41 -0700 (Thu, 10 Aug 2006) - roger - RRS: bug 7961 + +r14701 - 2006-07-17 13:37:26 -0700 (Mon, 17 Jul 2006) - roger - RRS: bug 5801 + +r13782 - 2006-06-06 10:58:55 -0700 (Tue, 06 Jun 2006) - majed - changes entry point code + +r11466 - 2006-02-01 15:49:47 -0800 (Wed, 01 Feb 2006) - jacob - Adding extra !empty check to get around a PHP warning. + +r11115 - 2006-01-17 14:54:45 -0800 (Tue, 17 Jan 2006) - majed - add entry point validation + +r10585 - 2005-12-13 14:42:26 -0800 (Tue, 13 Dec 2005) - majed - adds new license mechanisim + +r10170 - 2005-12-05 18:37:46 -0800 (Mon, 05 Dec 2005) - majed - fixes various issues + +r8999 - 2005-11-04 05:26:49 -0800 (Fri, 04 Nov 2005) - roger - When nusoap was upgraded we had an issue with the user's default language not being populated during a soap request. I determined the reason this was happening and have checked in the corresponding change to nusoap. + +r8991 - 2005-11-03 19:07:25 -0800 (Thu, 03 Nov 2005) - majed - fixes nusoap issue + +r8846 - 2005-10-31 11:01:12 -0800 (Mon, 31 Oct 2005) - majed - new version of nusoap + +r7905 - 2005-09-21 19:12:57 -0700 (Wed, 21 Sep 2005) - majed - restores old nusoap pre & with a few fixes + +r7861 - 2005-09-20 15:40:25 -0700 (Tue, 20 Sep 2005) - majed - & fix for 3.5.1 + +r7452 - 2005-08-17 11:32:34 -0700 (Wed, 17 Aug 2005) - majed - changes soap to nusoap + +r5820 - 2005-06-21 14:22:24 -0700 (Tue, 21 Jun 2005) - majed - fixes issues with nusoap and with custom fields + +r5462 - 2005-05-25 13:50:11 -0700 (Wed, 25 May 2005) - majed - upgraded nusoap to .6.9 + +r5104 - 2005-05-04 15:33:41 -0700 (Wed, 04 May 2005) - majed - gets rid of HTTP_GET_VARS and what not which has been deprecated + +r573 - 2004-09-04 13:03:32 -0700 (Sat, 04 Sep 2004) - sugarclint - undoing copyrights added in inadvertantly. --clint + +r546 - 2004-09-03 11:49:38 -0700 (Fri, 03 Sep 2004) - sugarmsi - removed echo count + +r354 - 2004-08-02 23:00:37 -0700 (Mon, 02 Aug 2004) - sugarjacob - Adding Soap + + +*/ + + + + + +/** +* parses a WSDL file, allows access to it's data, other utility methods. +* also builds WSDL structures programmatically. +* +* @author Dietrich Ayala +* @author Scott Nichol + +* @access public +*/ +class wsdl extends nusoap_base { + // URL or filename of the root of this WSDL + var $wsdl; + // define internal arrays of bindings, ports, operations, messages, etc. + var $schemas = array(); + var $currentSchema; + var $message = array(); + var $complexTypes = array(); + var $messages = array(); + var $currentMessage; + var $currentOperation; + var $portTypes = array(); + var $currentPortType; + var $bindings = array(); + var $currentBinding; + var $ports = array(); + var $currentPort; + var $opData = array(); + var $status = ''; + var $documentation = false; + var $endpoint = ''; + // array of wsdl docs to import + var $import = array(); + // parser vars + var $parser; + var $position = 0; + var $depth = 0; + var $depth_array = array(); + // for getting wsdl + var $proxyhost = ''; + var $proxyport = ''; + var $proxyusername = ''; + var $proxypassword = ''; + var $timeout = 0; + var $response_timeout = 30; + var $curl_options = array(); // User-specified cURL options + var $use_curl = false; // whether to always try to use cURL + // for HTTP authentication + var $username = ''; // Username for HTTP authentication + var $password = ''; // Password for HTTP authentication + var $authtype = ''; // Type of HTTP authentication + var $certRequest = array(); // Certificate for HTTP SSL authentication + + /** + * constructor + * + * @param string $wsdl WSDL document URL + * @param string $proxyhost + * @param string $proxyport + * @param string $proxyusername + * @param string $proxypassword + * @param integer $timeout set the connection timeout + * @param integer $response_timeout set the response timeout + * @param array $curl_options user-specified cURL options + * @param boolean $use_curl try to use cURL + * @access public + */ + function wsdl($wsdl = '',$proxyhost=false,$proxyport=false,$proxyusername=false,$proxypassword=false,$timeout=0,$response_timeout=30,$curl_options=null,$use_curl=false){ + parent::nusoap_base(); + $this->debug("ctor wsdl=$wsdl timeout=$timeout response_timeout=$response_timeout"); + $this->proxyhost = $proxyhost; + $this->proxyport = $proxyport; + $this->proxyusername = $proxyusername; + $this->proxypassword = $proxypassword; + $this->timeout = $timeout; + $this->response_timeout = $response_timeout; + if (is_array($curl_options)) + $this->curl_options = $curl_options; + $this->use_curl = $use_curl; + $this->fetchWSDL($wsdl); + } + + /** + * fetches the WSDL document and parses it + * + * @access public + */ + function fetchWSDL($wsdl) { + $this->debug("parse and process WSDL path=$wsdl"); + $this->wsdl = $wsdl; + // parse wsdl file + if ($this->wsdl != "") { + $this->parseWSDL($this->wsdl); + } + // imports + // TODO: handle imports more properly, grabbing them in-line and nesting them + $imported_urls = array(); + $imported = 1; + while ($imported > 0) { + $imported = 0; + // Schema imports + foreach ($this->schemas as $ns => $list) { + foreach ($list as $xs) { + $wsdlparts = parse_url($this->wsdl); // this is bogusly simple! + foreach ($xs->imports as $ns2 => $list2) { + for ($ii = 0; $ii < count($list2); $ii++) { + if (! $list2[$ii]['loaded']) { + $this->schemas[$ns]->imports[$ns2][$ii]['loaded'] = true; + $url = $list2[$ii]['location']; + if ($url != '') { + $urlparts = parse_url($url); + if (!isset($urlparts['host'])) { + $url = $wsdlparts['scheme'] . '://' . $wsdlparts['host'] . (isset($wsdlparts['port']) ? ':' .$wsdlparts['port'] : '') . + substr($wsdlparts['path'],0,strrpos($wsdlparts['path'],'/') + 1) .$urlparts['path']; + } + if (! in_array($url, $imported_urls)) { + $this->parseWSDL($url); + $imported++; + $imported_urls[] = $url; + } + } else { + $this->debug("Unexpected scenario: empty URL for unloaded import"); + } + } + } + } + } + } + // WSDL imports + $wsdlparts = parse_url($this->wsdl); // this is bogusly simple! + foreach ($this->import as $ns => $list) { + for ($ii = 0; $ii < count($list); $ii++) { + if (! $list[$ii]['loaded']) { + $this->import[$ns][$ii]['loaded'] = true; + $url = $list[$ii]['location']; + if ($url != '') { + $urlparts = parse_url($url); + if (!isset($urlparts['host'])) { + $url = $wsdlparts['scheme'] . '://' . $wsdlparts['host'] . (isset($wsdlparts['port']) ? ':' . $wsdlparts['port'] : '') . + substr($wsdlparts['path'],0,strrpos($wsdlparts['path'],'/') + 1) .$urlparts['path']; + } + if (! in_array($url, $imported_urls)) { + $this->parseWSDL($url); + $imported++; + $imported_urls[] = $url; + } + } else { + $this->debug("Unexpected scenario: empty URL for unloaded import"); + } + } + } + } + } + // add new data to operation data + foreach($this->bindings as $binding => $bindingData) { + if (isset($bindingData['operations']) && is_array($bindingData['operations'])) { + foreach($bindingData['operations'] as $operation => $data) { + $this->debug('post-parse data gathering for ' . $operation); + $this->bindings[$binding]['operations'][$operation]['input'] = + isset($this->bindings[$binding]['operations'][$operation]['input']) ? + array_merge($this->bindings[$binding]['operations'][$operation]['input'], $this->portTypes[ $bindingData['portType'] ][$operation]['input']) : + $this->portTypes[ $bindingData['portType'] ][$operation]['input']; + $this->bindings[$binding]['operations'][$operation]['output'] = + isset($this->bindings[$binding]['operations'][$operation]['output']) ? + array_merge($this->bindings[$binding]['operations'][$operation]['output'], $this->portTypes[ $bindingData['portType'] ][$operation]['output']) : + $this->portTypes[ $bindingData['portType'] ][$operation]['output']; + if(isset($this->messages[ $this->bindings[$binding]['operations'][$operation]['input']['message'] ])){ + $this->bindings[$binding]['operations'][$operation]['input']['parts'] = $this->messages[ $this->bindings[$binding]['operations'][$operation]['input']['message'] ]; + } + if(isset($this->messages[ $this->bindings[$binding]['operations'][$operation]['output']['message'] ])){ + $this->bindings[$binding]['operations'][$operation]['output']['parts'] = $this->messages[ $this->bindings[$binding]['operations'][$operation]['output']['message'] ]; + } + // Set operation style if necessary, but do not override one already provided + if (isset($bindingData['style']) && !isset($this->bindings[$binding]['operations'][$operation]['style'])) { + $this->bindings[$binding]['operations'][$operation]['style'] = $bindingData['style']; + } + $this->bindings[$binding]['operations'][$operation]['transport'] = isset($bindingData['transport']) ? $bindingData['transport'] : ''; + $this->bindings[$binding]['operations'][$operation]['documentation'] = isset($this->portTypes[ $bindingData['portType'] ][$operation]['documentation']) ? $this->portTypes[ $bindingData['portType'] ][$operation]['documentation'] : ''; + $this->bindings[$binding]['operations'][$operation]['endpoint'] = isset($bindingData['endpoint']) ? $bindingData['endpoint'] : ''; + } + } + } + } + + /** + * parses the wsdl document + * + * @param string $wsdl path or URL + * @access private + */ + function parseWSDL($wsdl = '') { + $this->debug("parse WSDL at path=$wsdl"); + + if ($wsdl == '') { + $this->debug('no wsdl passed to parseWSDL()!!'); + $this->setError('no wsdl passed to parseWSDL()!!'); + return false; + } + + // parse $wsdl for url format + $wsdl_props = parse_url($wsdl); + + if (isset($wsdl_props['scheme']) && ($wsdl_props['scheme'] == 'http' || $wsdl_props['scheme'] == 'https')) { + $this->debug('getting WSDL http(s) URL ' . $wsdl); + // get wsdl + $tr = new soap_transport_http($wsdl, $this->curl_options, $this->use_curl); + $tr->request_method = 'GET'; + $tr->useSOAPAction = false; + if($this->proxyhost && $this->proxyport){ + $tr->setProxy($this->proxyhost,$this->proxyport,$this->proxyusername,$this->proxypassword); + } + if ($this->authtype != '') { + $tr->setCredentials($this->username, $this->password, $this->authtype, array(), $this->certRequest); + } + $tr->setEncoding('gzip, deflate'); + $wsdl_string = $tr->send('', $this->timeout, $this->response_timeout); + //$this->debug("WSDL request\n" . $tr->outgoing_payload); + //$this->debug("WSDL response\n" . $tr->incoming_payload); + $this->appendDebug($tr->getDebug()); + // catch errors + if($err = $tr->getError() ){ + $errstr = 'Getting ' . $wsdl . ' - HTTP ERROR: '.$err; + $this->debug($errstr); + $this->setError($errstr); + unset($tr); + return false; + } + unset($tr); + $this->debug("got WSDL URL"); + } else { + // $wsdl is not http(s), so treat it as a file URL or plain file path + if (isset($wsdl_props['scheme']) && ($wsdl_props['scheme'] == 'file') && isset($wsdl_props['path'])) { + $path = isset($wsdl_props['host']) ? ($wsdl_props['host'] . ':' . $wsdl_props['path']) : $wsdl_props['path']; + } else { + $path = $wsdl; + } + $this->debug('getting WSDL file ' . $path); + if ($fp = @fopen($path, 'r')) { + $wsdl_string = ''; + while ($data = fread($fp, 32768)) { + $wsdl_string .= $data; + } + fclose($fp); + } else { + $errstr = "Bad path to WSDL file $path"; + $this->debug($errstr); + $this->setError($errstr); + return false; + } + } + $this->debug('Parse WSDL'); + // end new code added + // Create an XML parser. + $this->parser = xml_parser_create(); + // Set the options for parsing the XML data. + // xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1); + xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0); + // Set the object for the parser. + xml_set_object($this->parser, $this); + // Set the element handlers for the parser. + xml_set_element_handler($this->parser, 'start_element', 'end_element'); + xml_set_character_data_handler($this->parser, 'character_data'); + // Parse the XML file. + if (!xml_parse($this->parser, $wsdl_string, true)) { + // Display an error message. + $errstr = sprintf( + 'XML error parsing WSDL from %s on line %d: %s', + $wsdl, + xml_get_current_line_number($this->parser), + xml_error_string(xml_get_error_code($this->parser)) + ); + $this->debug($errstr); + $this->debug("XML payload:\n" . $wsdl_string); + $this->setError($errstr); + return false; + } + // free the parser + xml_parser_free($this->parser); + $this->debug('Parsing WSDL done'); + // catch wsdl parse errors + if($this->getError()){ + return false; + } + return true; + } + + /** + * start-element handler + * + * @param string $parser XML parser object + * @param string $name element name + * @param string $attrs associative array of attributes + * @access private + */ + function start_element($parser, $name, $attrs) + { + if ($this->status == 'schema') { + $this->currentSchema->schemaStartElement($parser, $name, $attrs); + $this->appendDebug($this->currentSchema->getDebug()); + $this->currentSchema->clearDebug(); + } elseif (preg_match('/schema$/', $name)) { + $this->debug('Parsing WSDL schema'); + // $this->debug("startElement for $name ($attrs[name]). status = $this->status (".$this->getLocalPart($name).")"); + $this->status = 'schema'; + $this->currentSchema = new nusoap_xmlschema('', '', $this->namespaces); + $this->currentSchema->schemaStartElement($parser, $name, $attrs); + $this->appendDebug($this->currentSchema->getDebug()); + $this->currentSchema->clearDebug(); + } else { + // position in the total number of elements, starting from 0 + $pos = $this->position++; + $depth = $this->depth++; + // set self as current value for this depth + $this->depth_array[$depth] = $pos; + $this->message[$pos] = array('cdata' => ''); + // process attributes + if (count($attrs) > 0) { + // register namespace declarations + foreach($attrs as $k => $v) { + if (preg_match('/^xmlns/',$k)) { + if ($ns_prefix = substr(strrchr($k, ':'), 1)) { + $this->namespaces[$ns_prefix] = $v; + } else { + $this->namespaces['ns' . (count($this->namespaces) + 1)] = $v; + } + if ($v == 'http://www.w3.org/2001/XMLSchema' || $v == 'http://www.w3.org/1999/XMLSchema' || $v == 'http://www.w3.org/2000/10/XMLSchema') { + $this->XMLSchemaVersion = $v; + $this->namespaces['xsi'] = $v . '-instance'; + } + } + } + // expand each attribute prefix to its namespace + foreach($attrs as $k => $v) { + $k = strpos($k, ':') ? $this->expandQname($k) : $k; + if ($k != 'location' && $k != 'soapAction' && $k != 'namespace') { + $v = strpos($v, ':') ? $this->expandQname($v) : $v; + } + $eAttrs[$k] = $v; + } + $attrs = $eAttrs; + } else { + $attrs = array(); + } + // get element prefix, namespace and name + if (preg_match('/:/', $name)) { + // get ns prefix + $prefix = substr($name, 0, strpos($name, ':')); + // get ns + $namespace = isset($this->namespaces[$prefix]) ? $this->namespaces[$prefix] : ''; + // get unqualified name + $name = substr(strstr($name, ':'), 1); + } + // process attributes, expanding any prefixes to namespaces + // find status, register data + switch ($this->status) { + case 'message': + if ($name == 'part') { + if (isset($attrs['type'])) { + $this->debug("msg " . $this->currentMessage . ": found part (with type) $attrs[name]: " . implode(',', $attrs)); + $this->messages[$this->currentMessage][$attrs['name']] = $attrs['type']; + } + if (isset($attrs['element'])) { + $this->debug("msg " . $this->currentMessage . ": found part (with element) $attrs[name]: " . implode(',', $attrs)); + $this->messages[$this->currentMessage][$attrs['name']] = $attrs['element'] . '^'; + } + } + break; + case 'portType': + switch ($name) { + case 'operation': + $this->currentPortOperation = $attrs['name']; + $this->debug("portType $this->currentPortType operation: $this->currentPortOperation"); + if (isset($attrs['parameterOrder'])) { + $this->portTypes[$this->currentPortType][$attrs['name']]['parameterOrder'] = $attrs['parameterOrder']; + } + break; + case 'documentation': + $this->documentation = true; + break; + // merge input/output data + default: + $m = isset($attrs['message']) ? $this->getLocalPart($attrs['message']) : ''; + $this->portTypes[$this->currentPortType][$this->currentPortOperation][$name]['message'] = $m; + break; + } + break; + case 'binding': + switch ($name) { + case 'binding': + // get ns prefix + if (isset($attrs['style'])) { + $this->bindings[$this->currentBinding]['prefix'] = $prefix; + } + $this->bindings[$this->currentBinding] = array_merge($this->bindings[$this->currentBinding], $attrs); + break; + case 'header': + $this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus]['headers'][] = $attrs; + break; + case 'operation': + if (isset($attrs['soapAction'])) { + $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['soapAction'] = $attrs['soapAction']; + } + if (isset($attrs['style'])) { + $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['style'] = $attrs['style']; + } + if (isset($attrs['name'])) { + $this->currentOperation = $attrs['name']; + $this->debug("current binding operation: $this->currentOperation"); + $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['name'] = $attrs['name']; + $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['binding'] = $this->currentBinding; + $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['endpoint'] = isset($this->bindings[$this->currentBinding]['endpoint']) ? $this->bindings[$this->currentBinding]['endpoint'] : ''; + } + break; + case 'input': + $this->opStatus = 'input'; + break; + case 'output': + $this->opStatus = 'output'; + break; + case 'body': + if (isset($this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus])) { + $this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus] = array_merge($this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus], $attrs); + } else { + $this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus] = $attrs; + } + break; + } + break; + case 'service': + switch ($name) { + case 'port': + $this->currentPort = $attrs['name']; + $this->debug('current port: ' . $this->currentPort); + $this->ports[$this->currentPort]['binding'] = $this->getLocalPart($attrs['binding']); + + break; + case 'address': + $this->ports[$this->currentPort]['location'] = $attrs['location']; + $this->ports[$this->currentPort]['bindingType'] = $namespace; + $this->bindings[ $this->ports[$this->currentPort]['binding'] ]['bindingType'] = $namespace; + $this->bindings[ $this->ports[$this->currentPort]['binding'] ]['endpoint'] = $attrs['location']; + break; + } + break; + } + // set status + switch ($name) { + case 'import': + if (isset($attrs['location'])) { + $this->import[$attrs['namespace']][] = array('location' => $attrs['location'], 'loaded' => false); + $this->debug('parsing import ' . $attrs['namespace']. ' - ' . $attrs['location'] . ' (' . count($this->import[$attrs['namespace']]).')'); + } else { + $this->import[$attrs['namespace']][] = array('location' => '', 'loaded' => true); + if (! $this->getPrefixFromNamespace($attrs['namespace'])) { + $this->namespaces['ns'.(count($this->namespaces)+1)] = $attrs['namespace']; + } + $this->debug('parsing import ' . $attrs['namespace']. ' - [no location] (' . count($this->import[$attrs['namespace']]).')'); + } + break; + //wait for schema + //case 'types': + // $this->status = 'schema'; + // break; + case 'message': + $this->status = 'message'; + $this->messages[$attrs['name']] = array(); + $this->currentMessage = $attrs['name']; + break; + case 'portType': + $this->status = 'portType'; + $this->portTypes[$attrs['name']] = array(); + $this->currentPortType = $attrs['name']; + break; + case "binding": + if (isset($attrs['name'])) { + // get binding name + if (strpos($attrs['name'], ':')) { + $this->currentBinding = $this->getLocalPart($attrs['name']); + } else { + $this->currentBinding = $attrs['name']; + } + $this->status = 'binding'; + $this->bindings[$this->currentBinding]['portType'] = $this->getLocalPart($attrs['type']); + $this->debug("current binding: $this->currentBinding of portType: " . $attrs['type']); + } + break; + case 'service': + $this->serviceName = $attrs['name']; + $this->status = 'service'; + $this->debug('current service: ' . $this->serviceName); + break; + case 'definitions': + foreach ($attrs as $name => $value) { + $this->wsdl_info[$name] = $value; + } + break; + } + } + } + + /** + * end-element handler + * + * @param string $parser XML parser object + * @param string $name element name + * @access private + */ + function end_element($parser, $name){ + // unset schema status + if (/*preg_match('/types$/', $name) ||*/ preg_match('/schema$/', $name)) { + $this->status = ""; + $this->appendDebug($this->currentSchema->getDebug()); + $this->currentSchema->clearDebug(); + $this->schemas[$this->currentSchema->schemaTargetNamespace][] = $this->currentSchema; + $this->debug('Parsing WSDL schema done'); + } + if ($this->status == 'schema') { + $this->currentSchema->schemaEndElement($parser, $name); + } else { + // bring depth down a notch + $this->depth--; + } + // end documentation + if ($this->documentation) { + //TODO: track the node to which documentation should be assigned; it can be a part, message, etc. + //$this->portTypes[$this->currentPortType][$this->currentPortOperation]['documentation'] = $this->documentation; + $this->documentation = false; + } + } + + /** + * element content handler + * + * @param string $parser XML parser object + * @param string $data element content + * @access private + */ + function character_data($parser, $data) + { + $pos = isset($this->depth_array[$this->depth]) ? $this->depth_array[$this->depth] : 0; + if (isset($this->message[$pos]['cdata'])) { + $this->message[$pos]['cdata'] .= $data; + } + if ($this->documentation) { + $this->documentation .= $data; + } + } + + /** + * if authenticating, set user credentials here + * + * @param string $username + * @param string $password + * @param string $authtype (basic|digest|certificate|ntlm) + * @param array $certRequest (keys must be cainfofile (optional), sslcertfile, sslkeyfile, passphrase, certpassword (optional), verifypeer (optional), verifyhost (optional): see corresponding options in cURL docs) + * @access public + */ + function setCredentials($username, $password, $authtype = 'basic', $certRequest = array()) { + $this->debug("setCredentials username=$username authtype=$authtype certRequest="); + $this->appendDebug($this->varDump($certRequest)); + $this->username = $username; + $this->password = $password; + $this->authtype = $authtype; + $this->certRequest = $certRequest; + } + + function getBindingData($binding) + { + if (is_array($this->bindings[$binding])) { + return $this->bindings[$binding]; + } + } + + /** + * returns an assoc array of operation names => operation data + * + * @param string $portName WSDL port name + * @param string $bindingType eg: soap, smtp, dime (only soap and soap12 are currently supported) + * @return array + * @access public + */ + function getOperations($portName = '', $bindingType = 'soap') { + $ops = array(); + if ($bindingType == 'soap') { + $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/'; + } elseif ($bindingType == 'soap12') { + $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap12/'; + } else { + $this->debug("getOperations bindingType $bindingType may not be supported"); + } + $this->debug("getOperations for port '$portName' bindingType $bindingType"); + // loop thru ports + foreach($this->ports as $port => $portData) { + $this->debug("getOperations checking port $port bindingType " . $portData['bindingType']); + if ($portName == '' || $port == $portName) { + // binding type of port matches parameter + if ($portData['bindingType'] == $bindingType) { + $this->debug("getOperations found port $port bindingType $bindingType"); + //$this->debug("port data: " . $this->varDump($portData)); + //$this->debug("bindings: " . $this->varDump($this->bindings[ $portData['binding'] ])); + // merge bindings + if (isset($this->bindings[ $portData['binding'] ]['operations'])) { + $ops = array_merge ($ops, $this->bindings[ $portData['binding'] ]['operations']); + } + } + } + } + if (count($ops) == 0) { + $this->debug("getOperations found no operations for port '$portName' bindingType $bindingType"); + } + return $ops; + } + + /** + * returns an associative array of data necessary for calling an operation + * + * @param string $operation name of operation + * @param string $bindingType type of binding eg: soap, soap12 + * @return array + * @access public + */ + function getOperationData($operation, $bindingType = 'soap') + { + if ($bindingType == 'soap') { + $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/'; + } elseif ($bindingType == 'soap12') { + $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap12/'; + } + // loop thru ports + foreach($this->ports as $port => $portData) { + // binding type of port matches parameter + if ($portData['bindingType'] == $bindingType) { + // get binding + //foreach($this->bindings[ $portData['binding'] ]['operations'] as $bOperation => $opData) { + foreach(array_keys($this->bindings[ $portData['binding'] ]['operations']) as $bOperation) { + // note that we could/should also check the namespace here + if ($operation == $bOperation) { + $opData = $this->bindings[ $portData['binding'] ]['operations'][$operation]; + return $opData; + } + } + } + } + } + + /** + * returns an associative array of data necessary for calling an operation + * + * @param string $soapAction soapAction for operation + * @param string $bindingType type of binding eg: soap, soap12 + * @return array + * @access public + */ + function getOperationDataForSoapAction($soapAction, $bindingType = 'soap') { + if ($bindingType == 'soap') { + $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/'; + } elseif ($bindingType == 'soap12') { + $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap12/'; + } + // loop thru ports + foreach($this->ports as $port => $portData) { + // binding type of port matches parameter + if ($portData['bindingType'] == $bindingType) { + // loop through operations for the binding + foreach ($this->bindings[ $portData['binding'] ]['operations'] as $bOperation => $opData) { + if ($opData['soapAction'] == $soapAction) { + return $opData; + } + } + } + } + } + + /** + * returns an array of information about a given type + * returns false if no type exists by the given name + * + * typeDef = array( + * 'elements' => array(), // refs to elements array + * 'restrictionBase' => '', + * 'phpType' => '', + * 'order' => '(sequence|all)', + * 'attrs' => array() // refs to attributes array + * ) + * + * @param string $type the type + * @param string $ns namespace (not prefix) of the type + * @return mixed + * @access public + * @see nusoap_xmlschema + */ + function getTypeDef($type, $ns) { + $this->debug("in getTypeDef: type=$type, ns=$ns"); + if ((! $ns) && isset($this->namespaces['tns'])) { + $ns = $this->namespaces['tns']; + $this->debug("in getTypeDef: type namespace forced to $ns"); + } + if (!isset($this->schemas[$ns])) { + foreach ($this->schemas as $ns0 => $schema0) { + if (strcasecmp($ns, $ns0) == 0) { + $this->debug("in getTypeDef: replacing schema namespace $ns with $ns0"); + $ns = $ns0; + break; + } + } + } + if (isset($this->schemas[$ns])) { + $this->debug("in getTypeDef: have schema for namespace $ns"); + for ($i = 0; $i < count($this->schemas[$ns]); $i++) { + $xs = &$this->schemas[$ns][$i]; + $t = $xs->getTypeDef($type); + $this->appendDebug($xs->getDebug()); + $xs->clearDebug(); + if ($t) { + $this->debug("in getTypeDef: found type $type"); + if (!isset($t['phpType'])) { + // get info for type to tack onto the element + $uqType = substr($t['type'], strrpos($t['type'], ':') + 1); + $ns = substr($t['type'], 0, strrpos($t['type'], ':')); + $etype = $this->getTypeDef($uqType, $ns); + if ($etype) { + $this->debug("found type for [element] $type:"); + $this->debug($this->varDump($etype)); + if (isset($etype['phpType'])) { + $t['phpType'] = $etype['phpType']; + } + if (isset($etype['elements'])) { + $t['elements'] = $etype['elements']; + } + if (isset($etype['attrs'])) { + $t['attrs'] = $etype['attrs']; + } + } else { + $this->debug("did not find type for [element] $type"); + } + } + return $t; + } + } + $this->debug("in getTypeDef: did not find type $type"); + } else { + $this->debug("in getTypeDef: do not have schema for namespace $ns"); + } + return false; + } + + /** + * prints html description of services + * + * @access private + */ + function webDescription(){ + global $HTTP_SERVER_VARS; + + if (isset($_SERVER)) { + $PHP_SELF = $_SERVER['PHP_SELF']; + } elseif (isset($HTTP_SERVER_VARS)) { + $PHP_SELF = $HTTP_SERVER_VARS['PHP_SELF']; + } else { + $this->setError("Neither _SERVER nor HTTP_SERVER_VARS is available"); + } + + $b = ' + NuSOAP: '.$this->serviceName.' + + + + +
    +

    +
    '.$this->serviceName.'
    + +
    '; + return $b; + } + + /** + * serialize the parsed wsdl + * + * @param mixed $debug whether to put debug=1 in endpoint URL + * @return string serialization of WSDL + * @access public + */ + function serialize($debug = 0) + { + $xml = ''; + $xml .= "\nnamespaces as $k => $v) { + $xml .= " xmlns:$k=\"$v\""; + } + // 10.9.02 - add poulter fix for wsdl and tns declarations + if (isset($this->namespaces['wsdl'])) { + $xml .= " xmlns=\"" . $this->namespaces['wsdl'] . "\""; + } + if (isset($this->namespaces['tns'])) { + $xml .= " targetNamespace=\"" . $this->namespaces['tns'] . "\""; + } + $xml .= '>'; + // imports + if (sizeof($this->import) > 0) { + foreach($this->import as $ns => $list) { + foreach ($list as $ii) { + if ($ii['location'] != '') { + $xml .= ''; + } else { + $xml .= ''; + } + } + } + } + // types + if (count($this->schemas)>=1) { + $xml .= "\n\n"; + foreach ($this->schemas as $ns => $list) { + foreach ($list as $xs) { + $xml .= $xs->serializeSchema(); + } + } + $xml .= ''; + } + // messages + if (count($this->messages) >= 1) { + foreach($this->messages as $msgName => $msgParts) { + $xml .= "\n'; + if(is_array($msgParts)){ + foreach($msgParts as $partName => $partType) { + // print 'serializing '.$partType.', sv: '.$this->XMLSchemaVersion.'
    '; + if (strpos($partType, ':')) { + $typePrefix = $this->getPrefixFromNamespace($this->getPrefix($partType)); + } elseif (isset($this->typemap[$this->namespaces['xsd']][$partType])) { + // print 'checking typemap: '.$this->XMLSchemaVersion.'
    '; + $typePrefix = 'xsd'; + } else { + foreach($this->typemap as $ns => $types) { + if (isset($types[$partType])) { + $typePrefix = $this->getPrefixFromNamespace($ns); + } + } + if (!isset($typePrefix)) { + die("$partType has no namespace!"); + } + } + $ns = $this->getNamespaceFromPrefix($typePrefix); + $localPart = $this->getLocalPart($partType); + $typeDef = $this->getTypeDef($localPart, $ns); + if ($typeDef['typeClass'] == 'element') { + $elementortype = 'element'; + if (substr($localPart, -1) == '^') { + $localPart = substr($localPart, 0, -1); + } + } else { + $elementortype = 'type'; + } + $xml .= "\n" . ' '; + } + } + $xml .= '
    '; + } + } + // bindings & porttypes + if (count($this->bindings) >= 1) { + $binding_xml = ''; + $portType_xml = ''; + foreach($this->bindings as $bindingName => $attrs) { + $binding_xml .= "\n'; + $binding_xml .= "\n" . ' '; + $portType_xml .= "\n'; + foreach($attrs['operations'] as $opName => $opParts) { + $binding_xml .= "\n" . ' '; + $binding_xml .= "\n" . ' '; + if (isset($opParts['input']['encodingStyle']) && $opParts['input']['encodingStyle'] != '') { + $enc_style = ' encodingStyle="' . $opParts['input']['encodingStyle'] . '"'; + } else { + $enc_style = ''; + } + $binding_xml .= "\n" . ' '; + if (isset($opParts['output']['encodingStyle']) && $opParts['output']['encodingStyle'] != '') { + $enc_style = ' encodingStyle="' . $opParts['output']['encodingStyle'] . '"'; + } else { + $enc_style = ''; + } + $binding_xml .= "\n" . ' '; + $binding_xml .= "\n" . ' '; + $portType_xml .= "\n" . ' ' . htmlspecialchars($opParts['documentation']) . ''; + } + $portType_xml .= "\n" . ' '; + $portType_xml .= "\n" . ' '; + $portType_xml .= "\n" . ' '; + } + $portType_xml .= "\n" . ''; + $binding_xml .= "\n" . ''; + } + $xml .= $portType_xml . $binding_xml; + } + // services + $xml .= "\nserviceName . '">'; + if (count($this->ports) >= 1) { + foreach($this->ports as $pName => $attrs) { + $xml .= "\n" . ' '; + $xml .= "\n" . ' '; + $xml .= "\n" . ' '; + } + } + $xml .= "\n" . ''; + return $xml . "\n"; + } + + /** + * determine whether a set of parameters are unwrapped + * when they are expect to be wrapped, Microsoft-style. + * + * @param string $type the type (element name) of the wrapper + * @param array $parameters the parameter values for the SOAP call + * @return boolean whether they parameters are unwrapped (and should be wrapped) + * @access private + */ + function parametersMatchWrapped($type, &$parameters) { + $this->debug("in parametersMatchWrapped type=$type, parameters="); + $this->appendDebug($this->varDump($parameters)); + + // split type into namespace:unqualified-type + if (strpos($type, ':')) { + $uqType = substr($type, strrpos($type, ':') + 1); + $ns = substr($type, 0, strrpos($type, ':')); + $this->debug("in parametersMatchWrapped: got a prefixed type: $uqType, $ns"); + if ($this->getNamespaceFromPrefix($ns)) { + $ns = $this->getNamespaceFromPrefix($ns); + $this->debug("in parametersMatchWrapped: expanded prefixed type: $uqType, $ns"); + } + } else { + // TODO: should the type be compared to types in XSD, and the namespace + // set to XSD if the type matches? + $this->debug("in parametersMatchWrapped: No namespace for type $type"); + $ns = ''; + $uqType = $type; + } + + // get the type information + if (!$typeDef = $this->getTypeDef($uqType, $ns)) { + $this->debug("in parametersMatchWrapped: $type ($uqType) is not a supported type."); + return false; + } + $this->debug("in parametersMatchWrapped: found typeDef="); + $this->appendDebug($this->varDump($typeDef)); + if (substr($uqType, -1) == '^') { + $uqType = substr($uqType, 0, -1); + } + $phpType = $typeDef['phpType']; + $arrayType = (isset($typeDef['arrayType']) ? $typeDef['arrayType'] : ''); + $this->debug("in parametersMatchWrapped: uqType: $uqType, ns: $ns, phptype: $phpType, arrayType: $arrayType"); + + // we expect a complexType or element of complexType + if ($phpType != 'struct') { + $this->debug("in parametersMatchWrapped: not a struct"); + return false; + } + + // see whether the parameter names match the elements + if (isset($typeDef['elements']) && is_array($typeDef['elements'])) { + $elements = 0; + $matches = 0; + foreach ($typeDef['elements'] as $name => $attrs) { + if (isset($parameters[$name])) { + $this->debug("in parametersMatchWrapped: have parameter named $name"); + $matches++; + } else { + $this->debug("in parametersMatchWrapped: do not have parameter named $name"); + } + $elements++; + } + + $this->debug("in parametersMatchWrapped: $matches parameter names match $elements wrapped parameter names"); + if ($matches == 0) { + return false; + } + return true; + } + + // since there are no elements for the type, if the user passed no + // parameters, the parameters match wrapped. + $this->debug("in parametersMatchWrapped: no elements type $ns:$uqType"); + return count($parameters) == 0; + } + + /** + * serialize PHP values according to a WSDL message definition + * contrary to the method name, this is not limited to RPC + * + * TODO + * - multi-ref serialization + * - validate PHP values against type definitions, return errors if invalid + * + * @param string $operation operation name + * @param string $direction (input|output) + * @param mixed $parameters parameter value(s) + * @param string $bindingType (soap|soap12) + * @return mixed parameters serialized as XML or false on error (e.g. operation not found) + * @access public + */ + function serializeRPCParameters($operation, $direction, $parameters, $bindingType = 'soap') { + $this->debug("in serializeRPCParameters: operation=$operation, direction=$direction, XMLSchemaVersion=$this->XMLSchemaVersion, bindingType=$bindingType"); + $this->appendDebug('parameters=' . $this->varDump($parameters)); + + if ($direction != 'input' && $direction != 'output') { + $this->debug('The value of the \$direction argument needs to be either "input" or "output"'); + $this->setError('The value of the \$direction argument needs to be either "input" or "output"'); + return false; + } + if (!$opData = $this->getOperationData($operation, $bindingType)) { + $this->debug('Unable to retrieve WSDL data for operation: ' . $operation . ' bindingType: ' . $bindingType); + $this->setError('Unable to retrieve WSDL data for operation: ' . $operation . ' bindingType: ' . $bindingType); + return false; + } + $this->debug('in serializeRPCParameters: opData:'); + $this->appendDebug($this->varDump($opData)); + + // Get encoding style for output and set to current + $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/'; + if(($direction == 'input') && isset($opData['output']['encodingStyle']) && ($opData['output']['encodingStyle'] != $encodingStyle)) { + $encodingStyle = $opData['output']['encodingStyle']; + $enc_style = $encodingStyle; + } + + // set input params + $xml = ''; + if (isset($opData[$direction]['parts']) && sizeof($opData[$direction]['parts']) > 0) { + $parts = &$opData[$direction]['parts']; + $part_count = sizeof($parts); + $style = $opData['style']; + $use = $opData[$direction]['use']; + $this->debug("have $part_count part(s) to serialize using $style/$use"); + if (is_array($parameters)) { + $parametersArrayType = $this->isArraySimpleOrStruct($parameters); + $parameter_count = count($parameters); + $this->debug("have $parameter_count parameter(s) provided as $parametersArrayType to serialize"); + // check for Microsoft-style wrapped parameters + if ($style == 'document' && $use == 'literal' && $part_count == 1 && isset($parts['parameters'])) { + $this->debug('check whether the caller has wrapped the parameters'); + if ($direction == 'output' && $parametersArrayType == 'arraySimple' && $parameter_count == 1) { + // TODO: consider checking here for double-wrapping, when + // service function wraps, then NuSOAP wraps again + $this->debug("change simple array to associative with 'parameters' element"); + $parameters['parameters'] = $parameters[0]; + unset($parameters[0]); + } + if (($parametersArrayType == 'arrayStruct' || $parameter_count == 0) && !isset($parameters['parameters'])) { + $this->debug('check whether caller\'s parameters match the wrapped ones'); + if ($this->parametersMatchWrapped($parts['parameters'], $parameters)) { + $this->debug('wrap the parameters for the caller'); + $parameters = array('parameters' => $parameters); + $parameter_count = 1; + } + } + } + foreach ($parts as $name => $type) { + $this->debug("serializing part $name of type $type"); + // Track encoding style + if (isset($opData[$direction]['encodingStyle']) && $encodingStyle != $opData[$direction]['encodingStyle']) { + $encodingStyle = $opData[$direction]['encodingStyle']; + $enc_style = $encodingStyle; + } else { + $enc_style = false; + } + // NOTE: add error handling here + // if serializeType returns false, then catch global error and fault + if ($parametersArrayType == 'arraySimple') { + $p = array_shift($parameters); + $this->debug('calling serializeType w/indexed param'); + $xml .= $this->serializeType($name, $type, $p, $use, $enc_style); + } elseif (isset($parameters[$name])) { + $this->debug('calling serializeType w/named param'); + $xml .= $this->serializeType($name, $type, $parameters[$name], $use, $enc_style); + } else { + // TODO: only send nillable + $this->debug('calling serializeType w/null param'); + $xml .= $this->serializeType($name, $type, null, $use, $enc_style); + } + } + } else { + $this->debug('no parameters passed.'); + } + } + $this->debug("serializeRPCParameters returning: $xml"); + return $xml; + } + + /** + * serialize a PHP value according to a WSDL message definition + * + * TODO + * - multi-ref serialization + * - validate PHP values against type definitions, return errors if invalid + * + * @param string $operation operation name + * @param string $direction (input|output) + * @param mixed $parameters parameter value(s) + * @return mixed parameters serialized as XML or false on error (e.g. operation not found) + * @access public + * @deprecated + */ + function serializeParameters($operation, $direction, $parameters) + { + $this->debug("in serializeParameters: operation=$operation, direction=$direction, XMLSchemaVersion=$this->XMLSchemaVersion"); + $this->appendDebug('parameters=' . $this->varDump($parameters)); + + if ($direction != 'input' && $direction != 'output') { + $this->debug('The value of the \$direction argument needs to be either "input" or "output"'); + $this->setError('The value of the \$direction argument needs to be either "input" or "output"'); + return false; + } + if (!$opData = $this->getOperationData($operation)) { + $this->debug('Unable to retrieve WSDL data for operation: ' . $operation); + $this->setError('Unable to retrieve WSDL data for operation: ' . $operation); + return false; + } + $this->debug('opData:'); + $this->appendDebug($this->varDump($opData)); + + // Get encoding style for output and set to current + $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/'; + if(($direction == 'input') && isset($opData['output']['encodingStyle']) && ($opData['output']['encodingStyle'] != $encodingStyle)) { + $encodingStyle = $opData['output']['encodingStyle']; + $enc_style = $encodingStyle; + } + + // set input params + $xml = ''; + if (isset($opData[$direction]['parts']) && sizeof($opData[$direction]['parts']) > 0) { + + $use = $opData[$direction]['use']; + $this->debug("use=$use"); + $this->debug('got ' . count($opData[$direction]['parts']) . ' part(s)'); + if (is_array($parameters)) { + $parametersArrayType = $this->isArraySimpleOrStruct($parameters); + $this->debug('have ' . $parametersArrayType . ' parameters'); + foreach($opData[$direction]['parts'] as $name => $type) { + $this->debug('serializing part "'.$name.'" of type "'.$type.'"'); + // Track encoding style + if(isset($opData[$direction]['encodingStyle']) && $encodingStyle != $opData[$direction]['encodingStyle']) { + $encodingStyle = $opData[$direction]['encodingStyle']; + $enc_style = $encodingStyle; + } else { + $enc_style = false; + } + // NOTE: add error handling here + // if serializeType returns false, then catch global error and fault + if ($parametersArrayType == 'arraySimple') { + $p = array_shift($parameters); + $this->debug('calling serializeType w/indexed param'); + $xml .= $this->serializeType($name, $type, $p, $use, $enc_style); + } elseif (isset($parameters[$name])) { + $this->debug('calling serializeType w/named param'); + $xml .= $this->serializeType($name, $type, $parameters[$name], $use, $enc_style); + } else { + // TODO: only send nillable + $this->debug('calling serializeType w/null param'); + $xml .= $this->serializeType($name, $type, null, $use, $enc_style); + } + } + } else { + $this->debug('no parameters passed.'); + } + } + $this->debug("serializeParameters returning: $xml"); + return $xml; + } + + /** + * serializes a PHP value according a given type definition + * + * @param string $name name of value (part or element) + * @param string $type XML schema type of value (type or element) + * @param mixed $value a native PHP value (parameter value) + * @param string $use use for part (encoded|literal) + * @param string $encodingStyle SOAP encoding style for the value (if different than the enclosing style) + * @param boolean $unqualified a kludge for what should be XML namespace form handling + * @return string value serialized as an XML string + * @access private + */ + function serializeType($name, $type, $value, $use='encoded', $encodingStyle=false, $unqualified=false) + { + $this->debug("in serializeType: name=$name, type=$type, use=$use, encodingStyle=$encodingStyle, unqualified=" . ($unqualified ? "unqualified" : "qualified")); + $this->appendDebug("value=" . $this->varDump($value)); + if($use == 'encoded' && $encodingStyle) { + $encodingStyle = ' SOAP-ENV:encodingStyle="' . $encodingStyle . '"'; + } + + // if a soapval has been supplied, let its type override the WSDL + if (is_object($value) && get_class($value) == 'soapval') { + if ($value->type_ns) { + $type = $value->type_ns . ':' . $value->type; + $forceType = true; + $this->debug("in serializeType: soapval overrides type to $type"); + } elseif ($value->type) { + $type = $value->type; + $forceType = true; + $this->debug("in serializeType: soapval overrides type to $type"); + } else { + $forceType = false; + $this->debug("in serializeType: soapval does not override type"); + } + $attrs = $value->attributes; + $value = $value->value; + $this->debug("in serializeType: soapval overrides value to $value"); + if ($attrs) { + if (!is_array($value)) { + $value['!'] = $value; + } + foreach ($attrs as $n => $v) { + $value['!' . $n] = $v; + } + $this->debug("in serializeType: soapval provides attributes"); + } + } else { + $forceType = false; + } + + $xml = ''; + if (strpos($type, ':')) { + $uqType = substr($type, strrpos($type, ':') + 1); + $ns = substr($type, 0, strrpos($type, ':')); + $this->debug("in serializeType: got a prefixed type: $uqType, $ns"); + if ($this->getNamespaceFromPrefix($ns)) { + $ns = $this->getNamespaceFromPrefix($ns); + $this->debug("in serializeType: expanded prefixed type: $uqType, $ns"); + } + + if($ns == $this->XMLSchemaVersion || $ns == 'http://schemas.xmlsoap.org/soap/encoding/'){ + $this->debug('in serializeType: type namespace indicates XML Schema or SOAP Encoding type'); + if ($unqualified && $use == 'literal') { + $elementNS = " xmlns=\"\""; + } else { + $elementNS = ''; + } + if (is_null($value)) { + if ($use == 'literal') { + // TODO: depends on minOccurs + $xml = "<$name$elementNS/>"; + } else { + // TODO: depends on nillable, which should be checked before calling this method + $xml = "<$name$elementNS xsi:nil=\"true\" xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"/>"; + } + $this->debug("in serializeType: returning: $xml"); + return $xml; + } + if ($uqType == 'Array') { + // JBoss/Axis does this sometimes + return $this->serialize_val($value, $name, false, false, false, false, $use); + } + if ($uqType == 'boolean') { + if ((is_string($value) && $value == 'false') || (! $value)) { + $value = 'false'; + } else { + $value = 'true'; + } + } + if ($uqType == 'string' && gettype($value) == 'string') { + $value = $this->expandEntities($value); + } + if (($uqType == 'long' || $uqType == 'unsignedLong') && gettype($value) == 'double') { + $value = sprintf("%.0lf", $value); + } + // it's a scalar + // TODO: what about null/nil values? + // check type isn't a custom type extending xmlschema namespace + if (!$this->getTypeDef($uqType, $ns)) { + if ($use == 'literal') { + if ($forceType) { + $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">$value"; + } else { + $xml = "<$name$elementNS>$value"; + } + } else { + $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"$encodingStyle>$value"; + } + $this->debug("in serializeType: returning: $xml"); + return $xml; + } + $this->debug('custom type extends XML Schema or SOAP Encoding namespace (yuck)'); + } else if ($ns == 'http://xml.apache.org/xml-soap') { + $this->debug('in serializeType: appears to be Apache SOAP type'); + if ($uqType == 'Map') { + $tt_prefix = $this->getPrefixFromNamespace('http://xml.apache.org/xml-soap'); + if (! $tt_prefix) { + $this->debug('in serializeType: Add namespace for Apache SOAP type'); + $tt_prefix = 'ns' . rand(1000, 9999); + $this->namespaces[$tt_prefix] = 'http://xml.apache.org/xml-soap'; + // force this to be added to usedNamespaces + $tt_prefix = $this->getPrefixFromNamespace('http://xml.apache.org/xml-soap'); + } + $contents = ''; + foreach($value as $k => $v) { + $this->debug("serializing map element: key $k, value $v"); + $contents .= ''; + $contents .= $this->serialize_val($k,'key',false,false,false,false,$use); + $contents .= $this->serialize_val($v,'value',false,false,false,false,$use); + $contents .= ''; + } + if ($use == 'literal') { + if ($forceType) { + $xml = "<$name xsi:type=\"" . $tt_prefix . ":$uqType\">$contents"; + } else { + $xml = "<$name>$contents"; + } + } else { + $xml = "<$name xsi:type=\"" . $tt_prefix . ":$uqType\"$encodingStyle>$contents"; + } + $this->debug("in serializeType: returning: $xml"); + return $xml; + } + $this->debug('in serializeType: Apache SOAP type, but only support Map'); + } + } else { + // TODO: should the type be compared to types in XSD, and the namespace + // set to XSD if the type matches? + $this->debug("in serializeType: No namespace for type $type"); + $ns = ''; + $uqType = $type; + } + if(!$typeDef = $this->getTypeDef($uqType, $ns)){ + $this->setError("$type ($uqType) is not a supported type."); + $this->debug("in serializeType: $type ($uqType) is not a supported type."); + return false; + } else { + $this->debug("in serializeType: found typeDef"); + $this->appendDebug('typeDef=' . $this->varDump($typeDef)); + if (substr($uqType, -1) == '^') { + $uqType = substr($uqType, 0, -1); + } + } + if (!isset($typeDef['phpType'])) { + $this->setError("$type ($uqType) has no phpType."); + $this->debug("in serializeType: $type ($uqType) has no phpType."); + return false; + } + $phpType = $typeDef['phpType']; + $this->debug("in serializeType: uqType: $uqType, ns: $ns, phptype: $phpType, arrayType: " . (isset($typeDef['arrayType']) ? $typeDef['arrayType'] : '') ); + // if php type == struct, map value to the element names + if ($phpType == 'struct') { + if (isset($typeDef['typeClass']) && $typeDef['typeClass'] == 'element') { + $elementName = $uqType; + if (isset($typeDef['form']) && ($typeDef['form'] == 'qualified')) { + $elementNS = " xmlns=\"$ns\""; + } else { + $elementNS = " xmlns=\"\""; + } + } else { + $elementName = $name; + if ($unqualified) { + $elementNS = " xmlns=\"\""; + } else { + $elementNS = ''; + } + } + if (is_null($value)) { + if ($use == 'literal') { + // TODO: depends on minOccurs and nillable + $xml = "<$elementName$elementNS/>"; + } else { + $xml = "<$elementName$elementNS xsi:nil=\"true\" xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"/>"; + } + $this->debug("in serializeType: returning: $xml"); + return $xml; + } + if (is_object($value)) { + $value = get_object_vars($value); + } + if (is_array($value)) { + $elementAttrs = $this->serializeComplexTypeAttributes($typeDef, $value, $ns, $uqType); + if ($use == 'literal') { + if ($forceType) { + $xml = "<$elementName$elementNS$elementAttrs xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">"; + } else { + $xml = "<$elementName$elementNS$elementAttrs>"; + } + } else { + $xml = "<$elementName$elementNS$elementAttrs xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"$encodingStyle>"; + } + + if (isset($typeDef['simpleContent']) && $typeDef['simpleContent'] == 'true') { + if (isset($value['!'])) { + $xml .= $value['!']; + $this->debug("in serializeType: serialized simpleContent for type $type"); + } else { + $this->debug("in serializeType: no simpleContent to serialize for type $type"); + } + } else { + // complexContent + $xml .= $this->serializeComplexTypeElements($typeDef, $value, $ns, $uqType, $use, $encodingStyle); + } + $xml .= ""; + } else { + $this->debug("in serializeType: phpType is struct, but value is not an array"); + $this->setError("phpType is struct, but value is not an array: see debug output for details"); + $xml = ''; + } + } elseif ($phpType == 'array') { + if (isset($typeDef['form']) && ($typeDef['form'] == 'qualified')) { + $elementNS = " xmlns=\"$ns\""; + } else { + if ($unqualified) { + $elementNS = " xmlns=\"\""; + } else { + $elementNS = ''; + } + } + if (is_null($value)) { + if ($use == 'literal') { + // TODO: depends on minOccurs + $xml = "<$name$elementNS/>"; + } else { + $xml = "<$name$elementNS xsi:nil=\"true\" xsi:type=\"" . + $this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/') . + ":Array\" " . + $this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/') . + ':arrayType="' . + $this->getPrefixFromNamespace($this->getPrefix($typeDef['arrayType'])) . + ':' . + $this->getLocalPart($typeDef['arrayType'])."[0]\"/>"; + } + $this->debug("in serializeType: returning: $xml"); + return $xml; + } + if (isset($typeDef['multidimensional'])) { + $nv = array(); + foreach($value as $v) { + $cols = ',' . sizeof($v); + $nv = array_merge($nv, $v); + } + $value = $nv; + } else { + $cols = ''; + } + if (is_array($value) && sizeof($value) >= 1) { + $rows = sizeof($value); + $contents = ''; + foreach($value as $k => $v) { + $this->debug("serializing array element: $k, $v of type: $typeDef[arrayType]"); + //if (strpos($typeDef['arrayType'], ':') ) { + if (!in_array($typeDef['arrayType'],$this->typemap['http://www.w3.org/2001/XMLSchema'])) { + $contents .= $this->serializeType('item', $typeDef['arrayType'], $v, $use); + } else { + $contents .= $this->serialize_val($v, 'item', $typeDef['arrayType'], null, $this->XMLSchemaVersion, false, $use); + } + } + } else { + $rows = 0; + $contents = null; + } + // TODO: for now, an empty value will be serialized as a zero element + // array. Revisit this when coding the handling of null/nil values. + if ($use == 'literal') { + $xml = "<$name$elementNS>" + .$contents + .""; + } else { + $xml = "<$name$elementNS xsi:type=\"".$this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/').':Array" '. + $this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/') + .':arrayType="' + .$this->getPrefixFromNamespace($this->getPrefix($typeDef['arrayType'])) + .":".$this->getLocalPart($typeDef['arrayType'])."[$rows$cols]\">" + .$contents + .""; + } + } elseif ($phpType == 'scalar') { + if (isset($typeDef['form']) && ($typeDef['form'] == 'qualified')) { + $elementNS = " xmlns=\"$ns\""; + } else { + if ($unqualified) { + $elementNS = " xmlns=\"\""; + } else { + $elementNS = ''; + } + } + if ($use == 'literal') { + if ($forceType) { + $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">$value"; + } else { + $xml = "<$name$elementNS>$value"; + } + } else { + $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"$encodingStyle>$value"; + } + } + $this->debug("in serializeType: returning: $xml"); + return $xml; + } + + /** + * serializes the attributes for a complexType + * + * @param array $typeDef our internal representation of an XML schema type (or element) + * @param mixed $value a native PHP value (parameter value) + * @param string $ns the namespace of the type + * @param string $uqType the local part of the type + * @return string value serialized as an XML string + * @access private + */ + function serializeComplexTypeAttributes($typeDef, $value, $ns, $uqType) { + $this->debug("serializeComplexTypeAttributes for XML Schema type $ns:$uqType"); + $xml = ''; + if (isset($typeDef['extensionBase'])) { + $nsx = $this->getPrefix($typeDef['extensionBase']); + $uqTypex = $this->getLocalPart($typeDef['extensionBase']); + if ($this->getNamespaceFromPrefix($nsx)) { + $nsx = $this->getNamespaceFromPrefix($nsx); + } + if ($typeDefx = $this->getTypeDef($uqTypex, $nsx)) { + $this->debug("serialize attributes for extension base $nsx:$uqTypex"); + $xml .= $this->serializeComplexTypeAttributes($typeDefx, $value, $nsx, $uqTypex); + } else { + $this->debug("extension base $nsx:$uqTypex is not a supported type"); + } + } + if (isset($typeDef['attrs']) && is_array($typeDef['attrs'])) { + $this->debug("serialize attributes for XML Schema type $ns:$uqType"); + if (is_array($value)) { + $xvalue = $value; + } elseif (is_object($value)) { + $xvalue = get_object_vars($value); + } else { + $this->debug("value is neither an array nor an object for XML Schema type $ns:$uqType"); + $xvalue = array(); + } + foreach ($typeDef['attrs'] as $aName => $attrs) { + if (isset($xvalue['!' . $aName])) { + $xname = '!' . $aName; + $this->debug("value provided for attribute $aName with key $xname"); + } elseif (isset($xvalue[$aName])) { + $xname = $aName; + $this->debug("value provided for attribute $aName with key $xname"); + } elseif (isset($attrs['default'])) { + $xname = '!' . $aName; + $xvalue[$xname] = $attrs['default']; + $this->debug('use default value of ' . $xvalue[$aName] . ' for attribute ' . $aName); + } else { + $xname = ''; + $this->debug("no value provided for attribute $aName"); + } + if ($xname) { + $xml .= " $aName=\"" . $this->expandEntities($xvalue[$xname]) . "\""; + } + } + } else { + $this->debug("no attributes to serialize for XML Schema type $ns:$uqType"); + } + return $xml; + } + + /** + * serializes the elements for a complexType + * + * @param array $typeDef our internal representation of an XML schema type (or element) + * @param mixed $value a native PHP value (parameter value) + * @param string $ns the namespace of the type + * @param string $uqType the local part of the type + * @param string $use use for part (encoded|literal) + * @param string $encodingStyle SOAP encoding style for the value (if different than the enclosing style) + * @return string value serialized as an XML string + * @access private + */ + function serializeComplexTypeElements($typeDef, $value, $ns, $uqType, $use='encoded', $encodingStyle=false) { + $this->debug("in serializeComplexTypeElements for XML Schema type $ns:$uqType"); + $xml = ''; + if (isset($typeDef['extensionBase'])) { + $nsx = $this->getPrefix($typeDef['extensionBase']); + $uqTypex = $this->getLocalPart($typeDef['extensionBase']); + if ($this->getNamespaceFromPrefix($nsx)) { + $nsx = $this->getNamespaceFromPrefix($nsx); + } + if ($typeDefx = $this->getTypeDef($uqTypex, $nsx)) { + $this->debug("serialize elements for extension base $nsx:$uqTypex"); + $xml .= $this->serializeComplexTypeElements($typeDefx, $value, $nsx, $uqTypex, $use, $encodingStyle); + } else { + $this->debug("extension base $nsx:$uqTypex is not a supported type"); + } + } + if (isset($typeDef['elements']) && is_array($typeDef['elements'])) { + $this->debug("in serializeComplexTypeElements, serialize elements for XML Schema type $ns:$uqType"); + if (is_array($value)) { + $xvalue = $value; + } elseif (is_object($value)) { + $xvalue = get_object_vars($value); + } else { + $this->debug("value is neither an array nor an object for XML Schema type $ns:$uqType"); + $xvalue = array(); + } + // toggle whether all elements are present - ideally should validate against schema + if (count($typeDef['elements']) != count($xvalue)){ + $optionals = true; + } + foreach ($typeDef['elements'] as $eName => $attrs) { + if (!isset($xvalue[$eName])) { + if (isset($attrs['default'])) { + $xvalue[$eName] = $attrs['default']; + $this->debug('use default value of ' . $xvalue[$eName] . ' for element ' . $eName); + } + } + // if user took advantage of a minOccurs=0, then only serialize named parameters + if (isset($optionals) + && (!isset($xvalue[$eName])) + && ( (!isset($attrs['nillable'])) || $attrs['nillable'] != 'true') + ){ + if (isset($attrs['minOccurs']) && $attrs['minOccurs'] <> '0') { + $this->debug("apparent error: no value provided for element $eName with minOccurs=" . $attrs['minOccurs']); + } + // do nothing + $this->debug("no value provided for complexType element $eName and element is not nillable, so serialize nothing"); + } else { + // get value + if (isset($xvalue[$eName])) { + $v = $xvalue[$eName]; + } else { + $v = null; + } + if (isset($attrs['form'])) { + $unqualified = ($attrs['form'] == 'unqualified'); + } else { + $unqualified = false; + } + if (isset($attrs['maxOccurs']) && ($attrs['maxOccurs'] == 'unbounded' || $attrs['maxOccurs'] > 1) && isset($v) && is_array($v) && $this->isArraySimpleOrStruct($v) == 'arraySimple') { + $vv = $v; + foreach ($vv as $k => $v) { + if (isset($attrs['type']) || isset($attrs['ref'])) { + // serialize schema-defined type + $xml .= $this->serializeType($eName, isset($attrs['type']) ? $attrs['type'] : $attrs['ref'], $v, $use, $encodingStyle, $unqualified); + } else { + // serialize generic type (can this ever really happen?) + $this->debug("calling serialize_val() for $v, $eName, false, false, false, false, $use"); + $xml .= $this->serialize_val($v, $eName, false, false, false, false, $use); + } + } + } else { + if (is_null($v) && isset($attrs['minOccurs']) && $attrs['minOccurs'] == '0') { + // do nothing + } elseif (is_null($v) && isset($attrs['nillable']) && $attrs['nillable'] == 'true') { + // TODO: serialize a nil correctly, but for now serialize schema-defined type + $xml .= $this->serializeType($eName, isset($attrs['type']) ? $attrs['type'] : $attrs['ref'], $v, $use, $encodingStyle, $unqualified); + } elseif (isset($attrs['type']) || isset($attrs['ref'])) { + // serialize schema-defined type + $xml .= $this->serializeType($eName, isset($attrs['type']) ? $attrs['type'] : $attrs['ref'], $v, $use, $encodingStyle, $unqualified); + } else { + // serialize generic type (can this ever really happen?) + $this->debug("calling serialize_val() for $v, $eName, false, false, false, false, $use"); + $xml .= $this->serialize_val($v, $eName, false, false, false, false, $use); + } + } + } + } + } else { + $this->debug("no elements to serialize for XML Schema type $ns:$uqType"); + } + return $xml; + } + + /** + * adds an XML Schema complex type to the WSDL types + * + * @param string $name + * @param string $typeClass (complexType|simpleType|attribute) + * @param string $phpType currently supported are array and struct (php assoc array) + * @param string $compositor (all|sequence|choice) + * @param string $restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array) + * @param array $elements e.g. array ( name => array(name=>'',type=>'') ) + * @param array $attrs e.g. array(array('ref'=>'SOAP-ENC:arrayType','wsdl:arrayType'=>'xsd:string[]')) + * @param string $arrayType as namespace:name (xsd:string) + * @see nusoap_xmlschema + * @access public + */ + function addComplexType($name,$typeClass='complexType',$phpType='array',$compositor='',$restrictionBase='',$elements=array(),$attrs=array(),$arrayType='') { + if (count($elements) > 0) { + $eElements = array(); + foreach($elements as $n => $e){ + // expand each element + $ee = array(); + foreach ($e as $k => $v) { + $k = strpos($k,':') ? $this->expandQname($k) : $k; + $v = strpos($v,':') ? $this->expandQname($v) : $v; + $ee[$k] = $v; + } + $eElements[$n] = $ee; + } + $elements = $eElements; + } + + if (count($attrs) > 0) { + foreach($attrs as $n => $a){ + // expand each attribute + foreach ($a as $k => $v) { + $k = strpos($k,':') ? $this->expandQname($k) : $k; + $v = strpos($v,':') ? $this->expandQname($v) : $v; + $aa[$k] = $v; + } + $eAttrs[$n] = $aa; + } + $attrs = $eAttrs; + } + + $restrictionBase = strpos($restrictionBase,':') ? $this->expandQname($restrictionBase) : $restrictionBase; + $arrayType = strpos($arrayType,':') ? $this->expandQname($arrayType) : $arrayType; + + $typens = isset($this->namespaces['types']) ? $this->namespaces['types'] : $this->namespaces['tns']; + $this->schemas[$typens][0]->addComplexType($name,$typeClass,$phpType,$compositor,$restrictionBase,$elements,$attrs,$arrayType); + } + + /** + * adds an XML Schema simple type to the WSDL types + * + * @param string $name + * @param string $restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array) + * @param string $typeClass (should always be simpleType) + * @param string $phpType (should always be scalar) + * @param array $enumeration array of values + * @see nusoap_xmlschema + * @access public + */ + function addSimpleType($name, $restrictionBase='', $typeClass='simpleType', $phpType='scalar', $enumeration=array()) { + $restrictionBase = strpos($restrictionBase,':') ? $this->expandQname($restrictionBase) : $restrictionBase; + + $typens = isset($this->namespaces['types']) ? $this->namespaces['types'] : $this->namespaces['tns']; + $this->schemas[$typens][0]->addSimpleType($name, $restrictionBase, $typeClass, $phpType, $enumeration); + } + + /** + * adds an element to the WSDL types + * + * @param array $attrs attributes that must include name and type + * @see nusoap_xmlschema + * @access public + */ + function addElement($attrs) { + $typens = isset($this->namespaces['types']) ? $this->namespaces['types'] : $this->namespaces['tns']; + $this->schemas[$typens][0]->addElement($attrs); + } + + /** + * register an operation with the server + * + * @param string $name operation (method) name + * @param array $in assoc array of input values: key = param name, value = param type + * @param array $out assoc array of output values: key = param name, value = param type + * @param string $namespace optional The namespace for the operation + * @param string $soapaction optional The soapaction for the operation + * @param string $style (rpc|document) optional The style for the operation Note: when 'document' is specified, parameter and return wrappers are created for you automatically + * @param string $use (encoded|literal) optional The use for the parameters (cannot mix right now) + * @param string $documentation optional The description to include in the WSDL + * @param string $encodingStyle optional (usually 'http://schemas.xmlsoap.org/soap/encoding/' for encoded) + * @access public + */ + function addOperation($name, $in = false, $out = false, $namespace = false, $soapaction = false, $style = 'rpc', $use = 'encoded', $documentation = '', $encodingStyle = ''){ + if ($use == 'encoded' && $encodingStyle == '') { + $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/'; + } + + if ($style == 'document') { + $elements = array(); + foreach ($in as $n => $t) { + $elements[$n] = array('name' => $n, 'type' => $t, 'form' => 'unqualified'); + } + $this->addComplexType($name . 'RequestType', 'complexType', 'struct', 'all', '', $elements); + $this->addElement(array('name' => $name, 'type' => $name . 'RequestType')); + $in = array('parameters' => 'tns:' . $name . '^'); + + $elements = array(); + foreach ($out as $n => $t) { + $elements[$n] = array('name' => $n, 'type' => $t, 'form' => 'unqualified'); + } + $this->addComplexType($name . 'ResponseType', 'complexType', 'struct', 'all', '', $elements); + $this->addElement(array('name' => $name . 'Response', 'type' => $name . 'ResponseType', 'form' => 'qualified')); + $out = array('parameters' => 'tns:' . $name . 'Response' . '^'); + } + + // get binding + $this->bindings[ $this->serviceName . 'Binding' ]['operations'][$name] = + array( + 'name' => $name, + 'binding' => $this->serviceName . 'Binding', + 'endpoint' => $this->endpoint, + 'soapAction' => $soapaction, + 'style' => $style, + 'input' => array( + 'use' => $use, + 'namespace' => $namespace, + 'encodingStyle' => $encodingStyle, + 'message' => $name . 'Request', + 'parts' => $in), + 'output' => array( + 'use' => $use, + 'namespace' => $namespace, + 'encodingStyle' => $encodingStyle, + 'message' => $name . 'Response', + 'parts' => $out), + 'namespace' => $namespace, + 'transport' => 'http://schemas.xmlsoap.org/soap/http', + 'documentation' => $documentation); + // add portTypes + // add messages + if($in) + { + foreach($in as $pName => $pType) + { + if(strpos($pType,':')) { + $pType = $this->getNamespaceFromPrefix($this->getPrefix($pType)).":".$this->getLocalPart($pType); + } + $this->messages[$name.'Request'][$pName] = $pType; + } + } else { + $this->messages[$name.'Request']= '0'; + } + if($out) + { + foreach($out as $pName => $pType) + { + if(strpos($pType,':')) { + $pType = $this->getNamespaceFromPrefix($this->getPrefix($pType)).":".$this->getLocalPart($pType); + } + $this->messages[$name.'Response'][$pName] = $pType; + } + } else { + $this->messages[$name.'Response']= '0'; + } + return true; + } +} +?> + bug 40066 + +r58361 - 2010-09-29 16:59:02 -0700 (Wed, 29 Sep 2010) - kjing - Author: Jenny Gonsalves + Merging with maint_6_0_1 (svn merge -r 58250:58342) + +r57813 - 2010-08-19 10:34:44 -0700 (Thu, 19 Aug 2010) - kjing - Author: John Mertic + Bug 39085 - When loading the opposite search panel via ajax on the ListViews, call the index action instead of the ListView action to avoid touching pre-MVC code by accident. + +r57707 - 2010-08-10 12:26:13 -0700 (Tue, 10 Aug 2010) - kjing - Author: Stanislav Malyshev + fix SOAP calls with no parameters + +r56990 - 2010-06-16 13:05:36 -0700 (Wed, 16 Jun 2010) - kjing - snapshot "Mango" svn branch to a new one for GitHub sync + +r56989 - 2010-06-16 13:01:33 -0700 (Wed, 16 Jun 2010) - kjing - defunt "Mango" svn dev branch before github cutover + +r55980 - 2010-04-19 13:31:28 -0700 (Mon, 19 Apr 2010) - kjing - create Mango (6.1) based on windex + +r51719 - 2009-10-22 10:18:00 -0700 (Thu, 22 Oct 2009) - mitani - Converted to Build 3 tags and updated the build system + +r51634 - 2009-10-19 13:32:22 -0700 (Mon, 19 Oct 2009) - mitani - Windex is the branch for Sugar Sales 1.0 development + +r51508 - 2009-10-14 07:40:23 -0700 (Wed, 14 Oct 2009) - jmertic - More fallout fixes from the PHP 5.3 ereg to preg changes. + +r51455 - 2009-10-13 07:56:48 -0700 (Tue, 13 Oct 2009) - jmertic - Bug 33202 - Enable install of SugarCRM on PHP 5.3.0, asserting that the minimum supported version is PHP 5.2.x. + +r51443 - 2009-10-12 13:34:36 -0700 (Mon, 12 Oct 2009) - jmertic - Bug 33332 - Made application PHP 5.3 compliant with E_DEPRECATED warnings on by: +- Changing all ereg function to either preg or simple string based ones +- No more references to magic quotes. +- Change all the session_unregister() functions to just unset() the correct session variable instead. + +r50375 - 2009-08-24 18:07:43 -0700 (Mon, 24 Aug 2009) - dwong - branch kobe2 from tokyo r50372 + +r45763 - 2009-04-01 12:16:18 -0700 (Wed, 01 Apr 2009) - majed - Removed half of the require_once and include_onces in the product that were redundant or could be handled easily by the auto loader + +r45680 - 2009-03-30 14:34:35 -0700 (Mon, 30 Mar 2009) - Samir Gandhi - modifeid serializeSchema to generate WS-I compliant WSDL + +r42807 - 2008-12-29 11:16:59 -0800 (Mon, 29 Dec 2008) - dwong - Branch from trunk/sugarcrm r42806 to branches/tokyo/sugarcrm + +r42645 - 2008-12-18 13:41:08 -0800 (Thu, 18 Dec 2008) - awu - merging maint_5_2_0 rev41336:HEAD to trunk + +r41647 - 2008-11-11 17:44:30 -0800 (Tue, 11 Nov 2008) - majed - Fixes a few bugs + +r41596 - 2008-11-10 19:20:04 -0800 (Mon, 10 Nov 2008) - Samir Gandhi - modified to set $method in the code + +r41558 - 2008-11-10 14:35:34 -0800 (Mon, 10 Nov 2008) - majed - changes nusoap to allow for registering classes + +r39619 - 2008-09-09 13:41:34 -0700 (Tue, 09 Sep 2008) - jmertic - Bug 24827 - Remove all instances where we return a new object and assign it by reference, since this is deprecated in PHP 5 and emits E_DEPRECATED errors in PHP 5.3. +Touched: +- data/SugarBean.php +- include/domit/php_http_client_generic.php +- include/domit/php_http_connector.php +- include/domit/testing_domit.php +- include/domit/xml_domit_getelementsbypath.php +- include/domit/xml_domit_lite_parser.php +- include/domit/xml_domit_nodemaps.php +- include/domit/xml_domit_parser.php +- include/domit/xml_domit_shared.php +- include/generic/SugarWidgets/SugarWidgetField.php +- include/generic/SugarWidgets/SugarWidgetReportField.php +- include/ListView/ProcessView.php +- include/nusoap/class.soapclient.php +- include/nusoap/nusoap.php +- include/nusoap/nusoapmime.php +- include/Pear/HTML_Safe/Safe.php +- include/Pear/XML_HTMLSax3/HTMLSax3.php +- modules/Administration/RebuildWorkFlow.php +- modules/Expressions/RelateSelector.php +- modules/Reports/templates/templates_reports.php +- modules/WorkFlow/Delete.php +- modules/WorkFlow/Save.php +- modules/WorkFlow/SaveSequence.php +- modules/WorkFlow/WorkFlow.php +- modules/WorkFlowActionShells/CreateStep1.php +- modules/WorkFlowActionShells/CreateStep2.php +- modules/WorkFlowActionShells/Save.php +- modules/WorkFlowActionShells/WorkFlowActionShell.php +- modules/WorkFlowAlerts/Save.php +- modules/WorkFlowAlerts/WorkFlowAlert.php +- modules/WorkFlowAlertShells/DetailView.php +- modules/WorkFlowAlertShells/WorkFlowAlertShell.php +- modules/WorkFlowTriggerShells/CreateStep1.php +- modules/WorkFlowTriggerShells/CreateStepFilter.php +- modules/WorkFlowTriggerShells/SaveFilter.php +- modules/WorkFlowTriggerShells/WorkFlowTriggerShell.php +- soap/SoapHelperFunctions.php +- test/modules/DynamicFields/DynamicFields_Bug24095_test.php +- test/simpletest/browser.php +- test/simpletest/default_reporter.php +- test/simpletest/detached.php +- test/simpletest/eclipse.php +- test/simpletest/expectation.php +- test/simpletest/extensions/pear_test_case.php +- test/simpletest/form.php +- test/simpletest/http.php +- test/simpletest/mock_objects.php +- test/simpletest/page.php +- test/simpletest/parser.php +- test/simpletest/remote.php +- test/simpletest/shell_tester.php +- test/simpletest/simple_test.php +- test/simpletest/simpletest.php +- test/simpletest/test/acceptance_test.php +- test/simpletest/test/adapter_test.php +- test/simpletest/test/authentication_test.php +- test/simpletest/test/browser_test.php +- test/simpletest/test/collector_test.php +- test/simpletest/test/compatibility_test.php +- test/simpletest/test/detached_test.php +- test/simpletest/test/eclipse_test.php +- test/simpletest/test/encoding_test.php +- test/simpletest/test/errors_test.php +- test/simpletest/test/expectation_test.php +- test/simpletest/test/form_test.php +- test/simpletest/test/frames_test.php +- test/simpletest/test/http_test.php +- test/simpletest/test/live_test.php +- test/simpletest/test/mock_objects_test.php +- test/simpletest/test/page_test.php +- test/simpletest/test/parse_error_test.php +- test/simpletest/test/parser_test.php +- test/simpletest/test/remote_test.php +- test/simpletest/test/shell_test.php +- test/simpletest/test/shell_tester_test.php +- test/simpletest/test/simpletest_test.php +- test/simpletest/test/site/page_request.php +- test/simpletest/test/tag_test.php +- test/simpletest/test/unit_tester_test.php +- test/simpletest/test/user_agent_test.php +- test/simpletest/test/visual_test.php +- test/simpletest/test/xml_test.php +- test/simpletest/test_case.php +- test/simpletest/ui/array_reporter/test.php +- test/simpletest/ui/recorder/test.php +- test/simpletest/unit_tester.php +- test/simpletest/url.php +- test/simpletest/user_agent.php +- test/simpletest/web_tester.php +- test/spikephpcoverage/src/PEAR.php +- test/spikephpcoverage/src/util/Utility.php +- test/spikephpcoverage/src/XML/Parser.php +- test/spikephpcoverage/src/XML/Parser/Simple.php +- test/test_utilities/SugarTest_SimpleBrowser.php + +r38362 - 2008-07-28 14:06:59 -0700 (Mon, 28 Jul 2008) - roger - bug: 23897. Using print_r when using the debug statement in nusoap will print out the statements to the screen if the call is coming from the UI. + +r38300 - 2008-07-25 13:33:43 -0700 (Fri, 25 Jul 2008) - Samir Gandhi - put the debug in parseresponse function + +r38293 - 2008-07-25 12:32:34 -0700 (Fri, 25 Jul 2008) - Samir Gandhi - to put all the debug statements return value in the call function + +r36824 - 2008-06-18 09:26:11 -0700 (Wed, 18 Jun 2008) - roger - bug: 21832 + +r26422 - 2007-09-05 17:29:12 -0700 (Wed, 05 Sep 2007) - majed - migrate from beta 1 to trunk + +r15787 - 2006-08-10 10:14:41 -0700 (Thu, 10 Aug 2006) - roger - RRS: bug 7961 + +r14701 - 2006-07-17 13:37:26 -0700 (Mon, 17 Jul 2006) - roger - RRS: bug 5801 + +r13782 - 2006-06-06 10:58:55 -0700 (Tue, 06 Jun 2006) - majed - changes entry point code + +r11466 - 2006-02-01 15:49:47 -0800 (Wed, 01 Feb 2006) - jacob - Adding extra !empty check to get around a PHP warning. + +r11115 - 2006-01-17 14:54:45 -0800 (Tue, 17 Jan 2006) - majed - add entry point validation + +r10585 - 2005-12-13 14:42:26 -0800 (Tue, 13 Dec 2005) - majed - adds new license mechanisim + +r10170 - 2005-12-05 18:37:46 -0800 (Mon, 05 Dec 2005) - majed - fixes various issues + +r8999 - 2005-11-04 05:26:49 -0800 (Fri, 04 Nov 2005) - roger - When nusoap was upgraded we had an issue with the user's default language not being populated during a soap request. I determined the reason this was happening and have checked in the corresponding change to nusoap. + +r8991 - 2005-11-03 19:07:25 -0800 (Thu, 03 Nov 2005) - majed - fixes nusoap issue + +r8846 - 2005-10-31 11:01:12 -0800 (Mon, 31 Oct 2005) - majed - new version of nusoap + +r7905 - 2005-09-21 19:12:57 -0700 (Wed, 21 Sep 2005) - majed - restores old nusoap pre & with a few fixes + +r7861 - 2005-09-20 15:40:25 -0700 (Tue, 20 Sep 2005) - majed - & fix for 3.5.1 + +r7452 - 2005-08-17 11:32:34 -0700 (Wed, 17 Aug 2005) - majed - changes soap to nusoap + +r5820 - 2005-06-21 14:22:24 -0700 (Tue, 21 Jun 2005) - majed - fixes issues with nusoap and with custom fields + +r5462 - 2005-05-25 13:50:11 -0700 (Wed, 25 May 2005) - majed - upgraded nusoap to .6.9 + +r5104 - 2005-05-04 15:33:41 -0700 (Wed, 04 May 2005) - majed - gets rid of HTTP_GET_VARS and what not which has been deprecated + +r573 - 2004-09-04 13:03:32 -0700 (Sat, 04 Sep 2004) - sugarclint - undoing copyrights added in inadvertantly. --clint + +r546 - 2004-09-03 11:49:38 -0700 (Fri, 03 Sep 2004) - sugarmsi - removed echo count + +r354 - 2004-08-02 23:00:37 -0700 (Mon, 02 Aug 2004) - sugarjacob - Adding Soap + + +*/ + + + + + +/** +* +* nusoap_parser class parses SOAP XML messages into native PHP values +* +* @author Dietrich Ayala +* @author Scott Nichol + +* @access public +*/ +class nusoap_parser extends nusoap_base { + + var $xml = ''; + var $xml_encoding = ''; + var $method = ''; + var $root_struct = ''; + var $root_struct_name = ''; + var $root_struct_namespace = ''; + var $root_header = ''; + var $document = ''; // incoming SOAP body (text) + // determines where in the message we are (envelope,header,body,method) + var $status = ''; + var $position = 0; + var $depth = 0; + var $default_namespace = ''; + var $namespaces = array(); + var $message = array(); + var $parent = ''; + var $fault = false; + var $fault_code = ''; + var $fault_str = ''; + var $fault_detail = ''; + var $depth_array = array(); + var $debug_flag = true; + var $soapresponse = NULL; // parsed SOAP Body + var $soapheader = NULL; // parsed SOAP Header + var $responseHeaders = ''; // incoming SOAP headers (text) + var $body_position = 0; + // for multiref parsing: + // array of id => pos + var $ids = array(); + // array of id => hrefs => pos + var $multirefs = array(); + // toggle for auto-decoding element content + var $decode_utf8 = false; + + /** + * constructor that actually does the parsing + * + * @param string $xml SOAP message + * @param string $encoding character encoding scheme of message + * @param string $method method for which XML is parsed (unused?) + * @param string $decode_utf8 whether to decode UTF-8 to ISO-8859-1 + * @access public + */ + function nusoap_parser($xml,$encoding='UTF-8',$method='',$decode_utf8=true){ + parent::nusoap_base(); + $this->xml = $xml; + $this->xml_encoding = $encoding; + $this->method = $method; + $this->decode_utf8 = $decode_utf8; + + // Check whether content has been read. + if(!empty($xml)){ + // Check XML encoding + $pos_xml = strpos($xml, '', $pos_xml + 2) - $pos_xml + 1); + if (preg_match("/encoding=[\"']([^\"']*)[\"']/", $xml_decl, $res)) { + $xml_encoding = $res[1]; + if (strtoupper($xml_encoding) != $encoding) { + $err = "Charset from HTTP Content-Type '" . $encoding . "' does not match encoding from XML declaration '" . $xml_encoding . "'"; + $this->debug($err); + if ($encoding != 'ISO-8859-1' || strtoupper($xml_encoding) != 'UTF-8') { + $this->setError($err); + return; + } + // when HTTP says ISO-8859-1 (the default) and XML says UTF-8 (the typical), assume the other endpoint is just sloppy and proceed + } else { + $this->debug('Charset from HTTP Content-Type matches encoding from XML declaration'); + } + } else { + $this->debug('No encoding specified in XML declaration'); + } + } else { + $this->debug('No XML declaration'); + } + $this->debug('Entering nusoap_parser(), length='.strlen($xml).', encoding='.$encoding); + // Create an XML parser - why not xml_parser_create_ns? + $this->parser = xml_parser_create($this->xml_encoding); + // Set the options for parsing the XML data. + //xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1); + xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0); + xml_parser_set_option($this->parser, XML_OPTION_TARGET_ENCODING, $this->xml_encoding); + // Set the object for the parser. + xml_set_object($this->parser, $this); + // Set the element handlers for the parser. + xml_set_element_handler($this->parser, 'start_element','end_element'); + xml_set_character_data_handler($this->parser,'character_data'); + + // Parse the XML file. + if(!xml_parse($this->parser,$xml,true)){ + // Display an error message. + $err = sprintf('XML error parsing SOAP payload on line %d: %s', + xml_get_current_line_number($this->parser), + xml_error_string(xml_get_error_code($this->parser))); + $this->debug($err); + $this->debug("XML payload:\n" . $xml); + $this->setError($err); + } else { + $this->debug('in nusoap_parser ctor, message:'); + $this->appendDebug($this->varDump($this->message)); + $this->debug('parsed successfully, found root struct: '.$this->root_struct.' of name '.$this->root_struct_name); + // get final value + $this->soapresponse = $this->message[$this->root_struct]['result']; + // get header value + if($this->root_header != '' && isset($this->message[$this->root_header]['result'])){ + $this->soapheader = $this->message[$this->root_header]['result']; + } + // resolve hrefs/ids + if(sizeof($this->multirefs) > 0){ + foreach($this->multirefs as $id => $hrefs){ + $this->debug('resolving multirefs for id: '.$id); + $idVal = $this->buildVal($this->ids[$id]); + if (is_array($idVal) && isset($idVal['!id'])) { + unset($idVal['!id']); + } + foreach($hrefs as $refPos => $ref){ + $this->debug('resolving href at pos '.$refPos); + $this->multirefs[$id][$refPos] = $idVal; + } + } + } + } + xml_parser_free($this->parser); + } else { + $this->debug('xml was empty, didn\'t parse!'); + $this->setError('xml was empty, didn\'t parse!'); + } + } + + /** + * start-element handler + * + * @param resource $parser XML parser object + * @param string $name element name + * @param array $attrs associative array of attributes + * @access private + */ + function start_element($parser, $name, $attrs) { + // position in a total number of elements, starting from 0 + // update class level pos + $pos = $this->position++; + // and set mine + $this->message[$pos] = array('pos' => $pos,'children'=>'','cdata'=>''); + // depth = how many levels removed from root? + // set mine as current global depth and increment global depth value + $this->message[$pos]['depth'] = $this->depth++; + + // else add self as child to whoever the current parent is + if($pos != 0){ + $this->message[$this->parent]['children'] .= '|'.$pos; + } + // set my parent + $this->message[$pos]['parent'] = $this->parent; + // set self as current parent + $this->parent = $pos; + // set self as current value for this depth + $this->depth_array[$this->depth] = $pos; + // get element prefix + if(strpos($name,':')){ + // get ns prefix + $prefix = substr($name,0,strpos($name,':')); + // get unqualified name + $name = substr(strstr($name,':'),1); + } + // set status + if ($name == 'Envelope' && $this->status == '') { + $this->status = 'envelope'; + } elseif ($name == 'Header' && $this->status == 'envelope') { + $this->root_header = $pos; + $this->status = 'header'; + } elseif ($name == 'Body' && $this->status == 'envelope'){ + $this->status = 'body'; + $this->body_position = $pos; + // set method + } elseif($this->status == 'body' && $pos == ($this->body_position+1)) { + $this->status = 'method'; + $this->root_struct_name = $name; + $this->root_struct = $pos; + $this->message[$pos]['type'] = 'struct'; + $this->debug("found root struct $this->root_struct_name, pos $this->root_struct"); + } + // set my status + $this->message[$pos]['status'] = $this->status; + // set name + $this->message[$pos]['name'] = htmlspecialchars($name); + // set attrs + $this->message[$pos]['attrs'] = $attrs; + + // loop through atts, logging ns and type declarations + $attstr = ''; + foreach($attrs as $key => $value){ + $key_prefix = $this->getPrefix($key); + $key_localpart = $this->getLocalPart($key); + // if ns declarations, add to class level array of valid namespaces + if($key_prefix == 'xmlns'){ + if(preg_match('/^http:\/\/www.w3.org\/[0-9]{4}\/XMLSchema$/',$value)){ + $this->XMLSchemaVersion = $value; + $this->namespaces['xsd'] = $this->XMLSchemaVersion; + $this->namespaces['xsi'] = $this->XMLSchemaVersion.'-instance'; + } + $this->namespaces[$key_localpart] = $value; + // set method namespace + if($name == $this->root_struct_name){ + $this->methodNamespace = $value; + } + // if it's a type declaration, set type + } elseif($key_localpart == 'type'){ + if (isset($this->message[$pos]['type']) && $this->message[$pos]['type'] == 'array') { + // do nothing: already processed arrayType + } else { + $value_prefix = $this->getPrefix($value); + $value_localpart = $this->getLocalPart($value); + $this->message[$pos]['type'] = $value_localpart; + $this->message[$pos]['typePrefix'] = $value_prefix; + if(isset($this->namespaces[$value_prefix])){ + $this->message[$pos]['type_namespace'] = $this->namespaces[$value_prefix]; + } else if(isset($attrs['xmlns:'.$value_prefix])) { + $this->message[$pos]['type_namespace'] = $attrs['xmlns:'.$value_prefix]; + } + // should do something here with the namespace of specified type? + } + } elseif($key_localpart == 'arrayType'){ + $this->message[$pos]['type'] = 'array'; + /* do arrayType ereg here + [1] arrayTypeValue ::= atype asize + [2] atype ::= QName rank* + [3] rank ::= '[' (',')* ']' + [4] asize ::= '[' length~ ']' + [5] length ::= nextDimension* Digit+ + [6] nextDimension ::= Digit+ ',' + */ + $expr = '/([A-Za-z0-9_]+):([A-Za-z]+[A-Za-z0-9_]+)\[([0-9]+),?([0-9]*)\]/'; + if(preg_match($expr,$value,$regs)){ + $this->message[$pos]['typePrefix'] = $regs[1]; + $this->message[$pos]['arrayTypePrefix'] = $regs[1]; + if (isset($this->namespaces[$regs[1]])) { + $this->message[$pos]['arrayTypeNamespace'] = $this->namespaces[$regs[1]]; + } else if (isset($attrs['xmlns:'.$regs[1]])) { + $this->message[$pos]['arrayTypeNamespace'] = $attrs['xmlns:'.$regs[1]]; + } + $this->message[$pos]['arrayType'] = $regs[2]; + $this->message[$pos]['arraySize'] = $regs[3]; + $this->message[$pos]['arrayCols'] = $regs[4]; + } + // specifies nil value (or not) + } elseif ($key_localpart == 'nil'){ + $this->message[$pos]['nil'] = ($value == 'true' || $value == '1'); + // some other attribute + } elseif ($key != 'href' && $key != 'xmlns' && $key_localpart != 'encodingStyle' && $key_localpart != 'root') { + $this->message[$pos]['xattrs']['!' . $key] = $value; + } + + if ($key == 'xmlns') { + $this->default_namespace = $value; + } + // log id + if($key == 'id'){ + $this->ids[$value] = $pos; + } + // root + if($key_localpart == 'root' && $value == 1){ + $this->status = 'method'; + $this->root_struct_name = $name; + $this->root_struct = $pos; + $this->debug("found root struct $this->root_struct_name, pos $pos"); + } + // for doclit + $attstr .= " $key=\"$value\""; + } + // get namespace - must be done after namespace atts are processed + if(isset($prefix)){ + $this->message[$pos]['namespace'] = $this->namespaces[$prefix]; + $this->default_namespace = $this->namespaces[$prefix]; + } else { + $this->message[$pos]['namespace'] = $this->default_namespace; + } + if($this->status == 'header'){ + if ($this->root_header != $pos) { + $this->responseHeaders .= "<" . (isset($prefix) ? $prefix . ':' : '') . "$name$attstr>"; + } + } elseif($this->root_struct_name != ''){ + $this->document .= "<" . (isset($prefix) ? $prefix . ':' : '') . "$name$attstr>"; + } + } + + /** + * end-element handler + * + * @param resource $parser XML parser object + * @param string $name element name + * @access private + */ + function end_element($parser, $name) { + // position of current element is equal to the last value left in depth_array for my depth + $pos = $this->depth_array[$this->depth--]; + + // get element prefix + if(strpos($name,':')){ + // get ns prefix + $prefix = substr($name,0,strpos($name,':')); + // get unqualified name + $name = substr(strstr($name,':'),1); + } + + // build to native type + if(isset($this->body_position) && $pos > $this->body_position){ + // deal w/ multirefs + if(isset($this->message[$pos]['attrs']['href'])){ + // get id + $id = substr($this->message[$pos]['attrs']['href'],1); + // add placeholder to href array + $this->multirefs[$id][$pos] = 'placeholder'; + // add set a reference to it as the result value + $this->message[$pos]['result'] =& $this->multirefs[$id][$pos]; + // build complexType values + } elseif($this->message[$pos]['children'] != ''){ + // if result has already been generated (struct/array) + if(!isset($this->message[$pos]['result'])){ + $this->message[$pos]['result'] = $this->buildVal($pos); + } + // build complexType values of attributes and possibly simpleContent + } elseif (isset($this->message[$pos]['xattrs'])) { + if (isset($this->message[$pos]['nil']) && $this->message[$pos]['nil']) { + $this->message[$pos]['xattrs']['!'] = null; + } elseif (isset($this->message[$pos]['cdata']) && trim($this->message[$pos]['cdata']) != '') { + if (isset($this->message[$pos]['type'])) { + $this->message[$pos]['xattrs']['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$pos]['type'], isset($this->message[$pos]['type_namespace']) ? $this->message[$pos]['type_namespace'] : ''); + } else { + $parent = $this->message[$pos]['parent']; + if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) { + $this->message[$pos]['xattrs']['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : ''); + } else { + $this->message[$pos]['xattrs']['!'] = $this->message[$pos]['cdata']; + } + } + } + $this->message[$pos]['result'] = $this->message[$pos]['xattrs']; + // set value of simpleType (or nil complexType) + } else { + //$this->debug('adding data for scalar value '.$this->message[$pos]['name'].' of value '.$this->message[$pos]['cdata']); + if (isset($this->message[$pos]['nil']) && $this->message[$pos]['nil']) { + $this->message[$pos]['xattrs']['!'] = null; + } elseif (isset($this->message[$pos]['type'])) { + $this->message[$pos]['result'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$pos]['type'], isset($this->message[$pos]['type_namespace']) ? $this->message[$pos]['type_namespace'] : ''); + } else { + $parent = $this->message[$pos]['parent']; + if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) { + $this->message[$pos]['result'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : ''); + } else { + $this->message[$pos]['result'] = $this->message[$pos]['cdata']; + } + } + + /* add value to parent's result, if parent is struct/array + $parent = $this->message[$pos]['parent']; + if($this->message[$parent]['type'] != 'map'){ + if(strtolower($this->message[$parent]['type']) == 'array'){ + $this->message[$parent]['result'][] = $this->message[$pos]['result']; + } else { + $this->message[$parent]['result'][$this->message[$pos]['name']] = $this->message[$pos]['result']; + } + } + */ + } + } + + // for doclit + if($this->status == 'header'){ + if ($this->root_header != $pos) { + $this->responseHeaders .= ""; + } + } elseif($pos >= $this->root_struct){ + $this->document .= ""; + } + // switch status + if ($pos == $this->root_struct){ + $this->status = 'body'; + $this->root_struct_namespace = $this->message[$pos]['namespace']; + } elseif ($pos == $this->root_header) { + $this->status = 'envelope'; + } elseif ($name == 'Body' && $this->status == 'body') { + $this->status = 'envelope'; + } elseif ($name == 'Header' && $this->status == 'header') { // will never happen + $this->status = 'envelope'; + } elseif ($name == 'Envelope' && $this->status == 'envelope') { + $this->status = ''; + } + // set parent back to my parent + $this->parent = $this->message[$pos]['parent']; + } + + /** + * element content handler + * + * @param resource $parser XML parser object + * @param string $data element content + * @access private + */ + function character_data($parser, $data){ + $pos = $this->depth_array[$this->depth]; + if ($this->xml_encoding=='UTF-8'){ + // TODO: add an option to disable this for folks who want + // raw UTF-8 that, e.g., might not map to iso-8859-1 + // TODO: this can also be handled with xml_parser_set_option($this->parser, XML_OPTION_TARGET_ENCODING, "ISO-8859-1"); + if($this->decode_utf8){ + $data = utf8_decode($data); + } + } + $this->message[$pos]['cdata'] .= $data; + // for doclit + if($this->status == 'header'){ + $this->responseHeaders .= $data; + } else { + $this->document .= $data; + } + } + + /** + * get the parsed message (SOAP Body) + * + * @return mixed + * @access public + * @deprecated use get_soapbody instead + */ + function get_response(){ + return $this->soapresponse; + } + + /** + * get the parsed SOAP Body (NULL if there was none) + * + * @return mixed + * @access public + */ + function get_soapbody(){ + return $this->soapresponse; + } + + /** + * get the parsed SOAP Header (NULL if there was none) + * + * @return mixed + * @access public + */ + function get_soapheader(){ + return $this->soapheader; + } + + /** + * get the unparsed SOAP Header + * + * @return string XML or empty if no Header + * @access public + */ + function getHeaders(){ + return $this->responseHeaders; + } + + /** + * decodes simple types into PHP variables + * + * @param string $value value to decode + * @param string $type XML type to decode + * @param string $typens XML type namespace to decode + * @return mixed PHP value + * @access private + */ + function decodeSimple($value, $type, $typens) { + // TODO: use the namespace! + if ((!isset($type)) || $type == 'string' || $type == 'long' || $type == 'unsignedLong') { + return (string) $value; + } + if ($type == 'int' || $type == 'integer' || $type == 'short' || $type == 'byte') { + return (int) $value; + } + if ($type == 'float' || $type == 'double' || $type == 'decimal') { + return (double) $value; + } + if ($type == 'boolean') { + if (strtolower($value) == 'false' || strtolower($value) == 'f') { + return false; + } + return (boolean) $value; + } + if ($type == 'base64' || $type == 'base64Binary') { + $this->debug('Decode base64 value'); + return base64_decode($value); + } + // obscure numeric types + if ($type == 'nonPositiveInteger' || $type == 'negativeInteger' + || $type == 'nonNegativeInteger' || $type == 'positiveInteger' + || $type == 'unsignedInt' + || $type == 'unsignedShort' || $type == 'unsignedByte') { + return (int) $value; + } + // bogus: parser treats array with no elements as a simple type + if ($type == 'array') { + return array(); + } + // everything else + return (string) $value; + } + + /** + * builds response structures for compound values (arrays/structs) + * and scalars + * + * @param integer $pos position in node tree + * @return mixed PHP value + * @access private + */ + function buildVal($pos){ + if(!isset($this->message[$pos]['type'])){ + $this->message[$pos]['type'] = ''; + } + $this->debug('in buildVal() for '.$this->message[$pos]['name']."(pos $pos) of type ".$this->message[$pos]['type']); + // if there are children... + if($this->message[$pos]['children'] != ''){ + $this->debug('in buildVal, there are children'); + $children = explode('|',$this->message[$pos]['children']); + array_shift($children); // knock off empty + // md array + if(isset($this->message[$pos]['arrayCols']) && $this->message[$pos]['arrayCols'] != ''){ + $r=0; // rowcount + $c=0; // colcount + foreach($children as $child_pos){ + $this->debug("in buildVal, got an MD array element: $r, $c"); + $params[$r][] = $this->message[$child_pos]['result']; + $c++; + if($c == $this->message[$pos]['arrayCols']){ + $c = 0; + $r++; + } + } + // array + } elseif($this->message[$pos]['type'] == 'array' || $this->message[$pos]['type'] == 'Array'){ + $this->debug('in buildVal, adding array '.$this->message[$pos]['name']); + foreach($children as $child_pos){ + $params[] = &$this->message[$child_pos]['result']; + } + // apache Map type: java hashtable + } elseif($this->message[$pos]['type'] == 'Map' && $this->message[$pos]['type_namespace'] == 'http://xml.apache.org/xml-soap'){ + $this->debug('in buildVal, Java Map '.$this->message[$pos]['name']); + foreach($children as $child_pos){ + $kv = explode("|",$this->message[$child_pos]['children']); + $params[$this->message[$kv[1]]['result']] = &$this->message[$kv[2]]['result']; + } + // generic compound type + //} elseif($this->message[$pos]['type'] == 'SOAPStruct' || $this->message[$pos]['type'] == 'struct') { + } else { + // Apache Vector type: treat as an array + $this->debug('in buildVal, adding Java Vector or generic compound type '.$this->message[$pos]['name']); + if ($this->message[$pos]['type'] == 'Vector' && $this->message[$pos]['type_namespace'] == 'http://xml.apache.org/xml-soap') { + $notstruct = 1; + } else { + $notstruct = 0; + } + // + foreach($children as $child_pos){ + if($notstruct){ + $params[] = &$this->message[$child_pos]['result']; + } else { + if (isset($params[$this->message[$child_pos]['name']])) { + // de-serialize repeated element name into an array + if ((!is_array($params[$this->message[$child_pos]['name']])) || (!isset($params[$this->message[$child_pos]['name']][0]))) { + $params[$this->message[$child_pos]['name']] = array($params[$this->message[$child_pos]['name']]); + } + $params[$this->message[$child_pos]['name']][] = &$this->message[$child_pos]['result']; + } else { + $params[$this->message[$child_pos]['name']] = &$this->message[$child_pos]['result']; + } + } + } + } + if (isset($this->message[$pos]['xattrs'])) { + $this->debug('in buildVal, handling attributes'); + foreach ($this->message[$pos]['xattrs'] as $n => $v) { + $params[$n] = $v; + } + } + // handle simpleContent + if (isset($this->message[$pos]['cdata']) && trim($this->message[$pos]['cdata']) != '') { + $this->debug('in buildVal, handling simpleContent'); + if (isset($this->message[$pos]['type'])) { + $params['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$pos]['type'], isset($this->message[$pos]['type_namespace']) ? $this->message[$pos]['type_namespace'] : ''); + } else { + $parent = $this->message[$pos]['parent']; + if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) { + $params['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : ''); + } else { + $params['!'] = $this->message[$pos]['cdata']; + } + } + } + $ret = is_array($params) ? $params : array(); + $this->debug('in buildVal, return:'); + $this->appendDebug($this->varDump($ret)); + return $ret; + } else { + $this->debug('in buildVal, no children, building scalar'); + $cdata = isset($this->message[$pos]['cdata']) ? $this->message[$pos]['cdata'] : ''; + if (isset($this->message[$pos]['type'])) { + $ret = $this->decodeSimple($cdata, $this->message[$pos]['type'], isset($this->message[$pos]['type_namespace']) ? $this->message[$pos]['type_namespace'] : ''); + $this->debug("in buildVal, return: $ret"); + return $ret; + } + $parent = $this->message[$pos]['parent']; + if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) { + $ret = $this->decodeSimple($cdata, $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : ''); + $this->debug("in buildVal, return: $ret"); + return $ret; + } + $ret = $this->message[$pos]['cdata']; + $this->debug("in buildVal, return: $ret"); + return $ret; + } + } +} + +/** + * Backward compatibility + */ +class soap_parser extends nusoap_parser { +} + +?> + bug 40066 + +r58361 - 2010-09-29 16:59:02 -0700 (Wed, 29 Sep 2010) - kjing - Author: Jenny Gonsalves + Merging with maint_6_0_1 (svn merge -r 58250:58342) + +r57813 - 2010-08-19 10:34:44 -0700 (Thu, 19 Aug 2010) - kjing - Author: John Mertic + Bug 39085 - When loading the opposite search panel via ajax on the ListViews, call the index action instead of the ListView action to avoid touching pre-MVC code by accident. + +r57707 - 2010-08-10 12:26:13 -0700 (Tue, 10 Aug 2010) - kjing - Author: Stanislav Malyshev + fix SOAP calls with no parameters + +r56990 - 2010-06-16 13:05:36 -0700 (Wed, 16 Jun 2010) - kjing - snapshot "Mango" svn branch to a new one for GitHub sync + +r56989 - 2010-06-16 13:01:33 -0700 (Wed, 16 Jun 2010) - kjing - defunt "Mango" svn dev branch before github cutover + +r55980 - 2010-04-19 13:31:28 -0700 (Mon, 19 Apr 2010) - kjing - create Mango (6.1) based on windex + +r51719 - 2009-10-22 10:18:00 -0700 (Thu, 22 Oct 2009) - mitani - Converted to Build 3 tags and updated the build system + +r51634 - 2009-10-19 13:32:22 -0700 (Mon, 19 Oct 2009) - mitani - Windex is the branch for Sugar Sales 1.0 development + +r51508 - 2009-10-14 07:40:23 -0700 (Wed, 14 Oct 2009) - jmertic - More fallout fixes from the PHP 5.3 ereg to preg changes. + +r51455 - 2009-10-13 07:56:48 -0700 (Tue, 13 Oct 2009) - jmertic - Bug 33202 - Enable install of SugarCRM on PHP 5.3.0, asserting that the minimum supported version is PHP 5.2.x. + +r51443 - 2009-10-12 13:34:36 -0700 (Mon, 12 Oct 2009) - jmertic - Bug 33332 - Made application PHP 5.3 compliant with E_DEPRECATED warnings on by: +- Changing all ereg function to either preg or simple string based ones +- No more references to magic quotes. +- Change all the session_unregister() functions to just unset() the correct session variable instead. + +r50375 - 2009-08-24 18:07:43 -0700 (Mon, 24 Aug 2009) - dwong - branch kobe2 from tokyo r50372 + +r45763 - 2009-04-01 12:16:18 -0700 (Wed, 01 Apr 2009) - majed - Removed half of the require_once and include_onces in the product that were redundant or could be handled easily by the auto loader + +r45680 - 2009-03-30 14:34:35 -0700 (Mon, 30 Mar 2009) - Samir Gandhi - modifeid serializeSchema to generate WS-I compliant WSDL + +r42807 - 2008-12-29 11:16:59 -0800 (Mon, 29 Dec 2008) - dwong - Branch from trunk/sugarcrm r42806 to branches/tokyo/sugarcrm + +r42645 - 2008-12-18 13:41:08 -0800 (Thu, 18 Dec 2008) - awu - merging maint_5_2_0 rev41336:HEAD to trunk + +r41647 - 2008-11-11 17:44:30 -0800 (Tue, 11 Nov 2008) - majed - Fixes a few bugs + +r41596 - 2008-11-10 19:20:04 -0800 (Mon, 10 Nov 2008) - Samir Gandhi - modified to set $method in the code + +r41558 - 2008-11-10 14:35:34 -0800 (Mon, 10 Nov 2008) - majed - changes nusoap to allow for registering classes + +r39619 - 2008-09-09 13:41:34 -0700 (Tue, 09 Sep 2008) - jmertic - Bug 24827 - Remove all instances where we return a new object and assign it by reference, since this is deprecated in PHP 5 and emits E_DEPRECATED errors in PHP 5.3. +Touched: +- data/SugarBean.php +- include/domit/php_http_client_generic.php +- include/domit/php_http_connector.php +- include/domit/testing_domit.php +- include/domit/xml_domit_getelementsbypath.php +- include/domit/xml_domit_lite_parser.php +- include/domit/xml_domit_nodemaps.php +- include/domit/xml_domit_parser.php +- include/domit/xml_domit_shared.php +- include/generic/SugarWidgets/SugarWidgetField.php +- include/generic/SugarWidgets/SugarWidgetReportField.php +- include/ListView/ProcessView.php +- include/nusoap/class.soapclient.php +- include/nusoap/nusoap.php +- include/nusoap/nusoapmime.php +- include/Pear/HTML_Safe/Safe.php +- include/Pear/XML_HTMLSax3/HTMLSax3.php +- modules/Administration/RebuildWorkFlow.php +- modules/Expressions/RelateSelector.php +- modules/Reports/templates/templates_reports.php +- modules/WorkFlow/Delete.php +- modules/WorkFlow/Save.php +- modules/WorkFlow/SaveSequence.php +- modules/WorkFlow/WorkFlow.php +- modules/WorkFlowActionShells/CreateStep1.php +- modules/WorkFlowActionShells/CreateStep2.php +- modules/WorkFlowActionShells/Save.php +- modules/WorkFlowActionShells/WorkFlowActionShell.php +- modules/WorkFlowAlerts/Save.php +- modules/WorkFlowAlerts/WorkFlowAlert.php +- modules/WorkFlowAlertShells/DetailView.php +- modules/WorkFlowAlertShells/WorkFlowAlertShell.php +- modules/WorkFlowTriggerShells/CreateStep1.php +- modules/WorkFlowTriggerShells/CreateStepFilter.php +- modules/WorkFlowTriggerShells/SaveFilter.php +- modules/WorkFlowTriggerShells/WorkFlowTriggerShell.php +- soap/SoapHelperFunctions.php +- test/modules/DynamicFields/DynamicFields_Bug24095_test.php +- test/simpletest/browser.php +- test/simpletest/default_reporter.php +- test/simpletest/detached.php +- test/simpletest/eclipse.php +- test/simpletest/expectation.php +- test/simpletest/extensions/pear_test_case.php +- test/simpletest/form.php +- test/simpletest/http.php +- test/simpletest/mock_objects.php +- test/simpletest/page.php +- test/simpletest/parser.php +- test/simpletest/remote.php +- test/simpletest/shell_tester.php +- test/simpletest/simple_test.php +- test/simpletest/simpletest.php +- test/simpletest/test/acceptance_test.php +- test/simpletest/test/adapter_test.php +- test/simpletest/test/authentication_test.php +- test/simpletest/test/browser_test.php +- test/simpletest/test/collector_test.php +- test/simpletest/test/compatibility_test.php +- test/simpletest/test/detached_test.php +- test/simpletest/test/eclipse_test.php +- test/simpletest/test/encoding_test.php +- test/simpletest/test/errors_test.php +- test/simpletest/test/expectation_test.php +- test/simpletest/test/form_test.php +- test/simpletest/test/frames_test.php +- test/simpletest/test/http_test.php +- test/simpletest/test/live_test.php +- test/simpletest/test/mock_objects_test.php +- test/simpletest/test/page_test.php +- test/simpletest/test/parse_error_test.php +- test/simpletest/test/parser_test.php +- test/simpletest/test/remote_test.php +- test/simpletest/test/shell_test.php +- test/simpletest/test/shell_tester_test.php +- test/simpletest/test/simpletest_test.php +- test/simpletest/test/site/page_request.php +- test/simpletest/test/tag_test.php +- test/simpletest/test/unit_tester_test.php +- test/simpletest/test/user_agent_test.php +- test/simpletest/test/visual_test.php +- test/simpletest/test/xml_test.php +- test/simpletest/test_case.php +- test/simpletest/ui/array_reporter/test.php +- test/simpletest/ui/recorder/test.php +- test/simpletest/unit_tester.php +- test/simpletest/url.php +- test/simpletest/user_agent.php +- test/simpletest/web_tester.php +- test/spikephpcoverage/src/PEAR.php +- test/spikephpcoverage/src/util/Utility.php +- test/spikephpcoverage/src/XML/Parser.php +- test/spikephpcoverage/src/XML/Parser/Simple.php +- test/test_utilities/SugarTest_SimpleBrowser.php + +r38362 - 2008-07-28 14:06:59 -0700 (Mon, 28 Jul 2008) - roger - bug: 23897. Using print_r when using the debug statement in nusoap will print out the statements to the screen if the call is coming from the UI. + +r38300 - 2008-07-25 13:33:43 -0700 (Fri, 25 Jul 2008) - Samir Gandhi - put the debug in parseresponse function + +r38293 - 2008-07-25 12:32:34 -0700 (Fri, 25 Jul 2008) - Samir Gandhi - to put all the debug statements return value in the call function + +r36824 - 2008-06-18 09:26:11 -0700 (Wed, 18 Jun 2008) - roger - bug: 21832 + +r26422 - 2007-09-05 17:29:12 -0700 (Wed, 05 Sep 2007) - majed - migrate from beta 1 to trunk + +r15787 - 2006-08-10 10:14:41 -0700 (Thu, 10 Aug 2006) - roger - RRS: bug 7961 + +r14701 - 2006-07-17 13:37:26 -0700 (Mon, 17 Jul 2006) - roger - RRS: bug 5801 + +r13782 - 2006-06-06 10:58:55 -0700 (Tue, 06 Jun 2006) - majed - changes entry point code + +r11466 - 2006-02-01 15:49:47 -0800 (Wed, 01 Feb 2006) - jacob - Adding extra !empty check to get around a PHP warning. + +r11115 - 2006-01-17 14:54:45 -0800 (Tue, 17 Jan 2006) - majed - add entry point validation + +r10585 - 2005-12-13 14:42:26 -0800 (Tue, 13 Dec 2005) - majed - adds new license mechanisim + +r10170 - 2005-12-05 18:37:46 -0800 (Mon, 05 Dec 2005) - majed - fixes various issues + +r8999 - 2005-11-04 05:26:49 -0800 (Fri, 04 Nov 2005) - roger - When nusoap was upgraded we had an issue with the user's default language not being populated during a soap request. I determined the reason this was happening and have checked in the corresponding change to nusoap. + +r8991 - 2005-11-03 19:07:25 -0800 (Thu, 03 Nov 2005) - majed - fixes nusoap issue + +r8846 - 2005-10-31 11:01:12 -0800 (Mon, 31 Oct 2005) - majed - new version of nusoap + +r7905 - 2005-09-21 19:12:57 -0700 (Wed, 21 Sep 2005) - majed - restores old nusoap pre & with a few fixes + +r7861 - 2005-09-20 15:40:25 -0700 (Tue, 20 Sep 2005) - majed - & fix for 3.5.1 + +r7452 - 2005-08-17 11:32:34 -0700 (Wed, 17 Aug 2005) - majed - changes soap to nusoap + +r5820 - 2005-06-21 14:22:24 -0700 (Tue, 21 Jun 2005) - majed - fixes issues with nusoap and with custom fields + +r5462 - 2005-05-25 13:50:11 -0700 (Wed, 25 May 2005) - majed - upgraded nusoap to .6.9 + +r5104 - 2005-05-04 15:33:41 -0700 (Wed, 04 May 2005) - majed - gets rid of HTTP_GET_VARS and what not which has been deprecated + +r573 - 2004-09-04 13:03:32 -0700 (Sat, 04 Sep 2004) - sugarclint - undoing copyrights added in inadvertantly. --clint + +r546 - 2004-09-03 11:49:38 -0700 (Fri, 03 Sep 2004) - sugarmsi - removed echo count + +r354 - 2004-08-02 23:00:37 -0700 (Mon, 02 Aug 2004) - sugarjacob - Adding Soap + + +*/ + + + + + +/** +* +* [nu]soapclient higher level class for easy usage. +* +* usage: +* +* // instantiate client with server info +* $soapclient = new nusoap_client( string path [ ,mixed wsdl] ); +* +* // call method, get results +* echo $soapclient->call( string methodname [ ,array parameters] ); +* +* // bye bye client +* unset($soapclient); +* +* @author Dietrich Ayala +* @author Scott Nichol + +* @access public +*/ +class nusoap_client extends nusoap_base { + + var $username = ''; // Username for HTTP authentication + var $password = ''; // Password for HTTP authentication + var $authtype = ''; // Type of HTTP authentication + var $certRequest = array(); // Certificate for HTTP SSL authentication + var $requestHeaders = false; // SOAP headers in request (text) + var $responseHeaders = ''; // SOAP headers from response (incomplete namespace resolution) (text) + var $responseHeader = NULL; // SOAP Header from response (parsed) + var $document = ''; // SOAP body response portion (incomplete namespace resolution) (text) + var $endpoint; + var $forceEndpoint = ''; // overrides WSDL endpoint + var $proxyhost = ''; + var $proxyport = ''; + var $proxyusername = ''; + var $proxypassword = ''; + var $portName = ''; // port name to use in WSDL + var $xml_encoding = ''; // character set encoding of incoming (response) messages + var $http_encoding = false; + var $timeout = 0; // HTTP connection timeout + var $response_timeout = 30; // HTTP response timeout + var $endpointType = ''; // soap|wsdl, empty for WSDL initialization error + var $persistentConnection = false; + var $defaultRpcParams = false; // This is no longer used + var $request = ''; // HTTP request + var $response = ''; // HTTP response + var $responseData = ''; // SOAP payload of response + var $cookies = array(); // Cookies from response or for request + var $decode_utf8 = false; // toggles whether the parser decodes element content w/ utf8_decode() + var $operations = array(); // WSDL operations, empty for WSDL initialization error + var $curl_options = array(); // User-specified cURL options + var $bindingType = ''; // WSDL operation binding type + var $use_curl = false; // whether to always try to use cURL + + /* + * fault related variables + */ + /** + * @var fault + * @access public + */ + var $fault; + /** + * @var faultcode + * @access public + */ + var $faultcode; + /** + * @var faultstring + * @access public + */ + var $faultstring; + /** + * @var faultdetail + * @access public + */ + var $faultdetail; + + /** + * constructor + * + * @param mixed $endpoint SOAP server or WSDL URL (string), or wsdl instance (object) + * @param mixed $wsdl optional, set to 'wsdl' or true if using WSDL + * @param string $proxyhost optional + * @param string $proxyport optional + * @param string $proxyusername optional + * @param string $proxypassword optional + * @param integer $timeout set the connection timeout + * @param integer $response_timeout set the response timeout + * @param string $portName optional portName in WSDL document + * @access public + */ + function nusoap_client($endpoint,$wsdl = false,$proxyhost = false,$proxyport = false,$proxyusername = false, $proxypassword = false, $timeout = 0, $response_timeout = 30, $portName = ''){ + parent::nusoap_base(); + //ADDED FOR SUGAR PROXY SUPPORT + global $proxy_config; + if(!$proxyhost){ + if(empty($proxy_config)){ + if(!empty($GLOBALS['db'])){ + + $proxy_config = new Administration(); + $proxy_config->retrieveSettings('proxy'); + } + } + + if(!empty($proxy_config)) + { + if(!empty($proxy_config->settings['proxy_on'])){ + $proxyhost = $proxy_config->settings['proxy_host']; + $proxyport = $proxy_config->settings['proxy_port']; + + } + if(!empty($proxy_config->settings['proxy_auth'])){ + $proxyusername = $proxy_config->settings['proxy_username']; + $proxypassword = $proxy_config->settings['proxy_password']; + } + } + } + $this->endpoint = $endpoint; + $this->proxyhost = $proxyhost; + $this->proxyport = $proxyport; + $this->proxyusername = $proxyusername; + $this->proxypassword = $proxypassword; + $this->timeout = $timeout; + $this->response_timeout = $response_timeout; + $this->portName = $portName; + + $this->debug("ctor wsdl=$wsdl timeout=$timeout response_timeout=$response_timeout"); + $this->appendDebug('endpoint=' . $this->varDump($endpoint)); + + // make values + if($wsdl){ + if (is_object($endpoint) && (get_class($endpoint) == 'wsdl')) { + $this->wsdl = $endpoint; + $this->endpoint = $this->wsdl->wsdl; + $this->wsdlFile = $this->endpoint; + $this->debug('existing wsdl instance created from ' . $this->endpoint); + $this->checkWSDL(); + } else { + $this->wsdlFile = $this->endpoint; + $this->wsdl = null; + $this->debug('will use lazy evaluation of wsdl from ' . $this->endpoint); + } + $this->endpointType = 'wsdl'; + } else { + $this->debug("instantiate SOAP with endpoint at $endpoint"); + $this->endpointType = 'soap'; + } + } + + /** + * calls method, returns PHP native type + * + * @param string $operation SOAP server URL or path + * @param mixed $params An array, associative or simple, of the parameters + * for the method call, or a string that is the XML + * for the call. For rpc style, this call will + * wrap the XML in a tag named after the method, as + * well as the SOAP Envelope and Body. For document + * style, this will only wrap with the Envelope and Body. + * IMPORTANT: when using an array with document style, + * in which case there + * is really one parameter, the root of the fragment + * used in the call, which encloses what programmers + * normally think of parameters. A parameter array + * *must* include the wrapper. + * @param string $namespace optional method namespace (WSDL can override) + * @param string $soapAction optional SOAPAction value (WSDL can override) + * @param mixed $headers optional string of XML with SOAP header content, or array of soapval objects for SOAP headers, or associative array + * @param boolean $rpcParams optional (no longer used) + * @param string $style optional (rpc|document) the style to use when serializing parameters (WSDL can override) + * @param string $use optional (encoded|literal) the use when serializing parameters (WSDL can override) + * @return mixed response from SOAP call, normally an associative array mirroring the structure of the XML response, false for certain fatal errors + * @access public + */ + function call($operation,$params=array(),$namespace='http://tempuri.org',$soapAction='',$headers=false,$rpcParams=null,$style='rpc',$use='encoded'){ + $this->operation = $operation; + $this->fault = false; + $this->setError(''); + $this->request = ''; + $this->response = ''; + $this->responseData = ''; + $this->faultstring = ''; + $this->faultcode = ''; + $this->opData = array(); + + $this->debug("call: operation=$operation, namespace=$namespace, soapAction=$soapAction, rpcParams=$rpcParams, style=$style, use=$use, endpointType=$this->endpointType"); + $this->appendDebug('params=' . $this->varDump($params)); + $this->appendDebug('headers=' . $this->varDump($headers)); + if ($headers) { + $this->requestHeaders = $headers; + } + if ($this->endpointType == 'wsdl' && is_null($this->wsdl)) { + $this->loadWSDL(); + if ($this->getError()) + return false; + } + // serialize parameters + if($this->endpointType == 'wsdl' && $opData = $this->getOperationData($operation)){ + // use WSDL for operation + $this->opData = $opData; + $this->debug("found operation"); + $this->appendDebug('opData=' . $this->varDump($opData)); + if (isset($opData['soapAction'])) { + $soapAction = $opData['soapAction']; + } + if (! $this->forceEndpoint) { + $this->endpoint = $opData['endpoint']; + } else { + $this->endpoint = $this->forceEndpoint; + } + $namespace = isset($opData['input']['namespace']) ? $opData['input']['namespace'] : $namespace; + $style = $opData['style']; + $use = $opData['input']['use']; + // add ns to ns array + if($namespace != '' && !isset($this->wsdl->namespaces[$namespace])){ + $nsPrefix = 'ns' . rand(1000, 9999); + $this->wsdl->namespaces[$nsPrefix] = $namespace; + } + $nsPrefix = $this->wsdl->getPrefixFromNamespace($namespace); + // serialize payload + if (is_string($params)) { + $this->debug("serializing param string for WSDL operation $operation"); + $payload = $params; + } elseif (is_array($params)) { + $this->debug("serializing param array for WSDL operation $operation"); + $payload = $this->wsdl->serializeRPCParameters($operation,'input',$params,$this->bindingType); + } else { + $this->debug('params must be array or string'); + $this->setError('params must be array or string'); + return false; + } + $usedNamespaces = $this->wsdl->usedNamespaces; + if (isset($opData['input']['encodingStyle'])) { + $encodingStyle = $opData['input']['encodingStyle']; + } else { + $encodingStyle = ''; + } + $this->appendDebug($this->wsdl->getDebug()); + $this->wsdl->clearDebug(); + if ($errstr = $this->wsdl->getError()) { + $this->debug('got wsdl error: '.$errstr); + $this->setError('wsdl error: '.$errstr); + return false; + } + } elseif($this->endpointType == 'wsdl') { + // operation not in WSDL + $this->appendDebug($this->wsdl->getDebug()); + $this->wsdl->clearDebug(); + $this->setError('operation '.$operation.' not present in WSDL.'); + $this->debug("operation '$operation' not present in WSDL."); + return false; + } else { + // no WSDL + //$this->namespaces['ns1'] = $namespace; + $nsPrefix = 'ns' . rand(1000, 9999); + // serialize + $payload = ''; + if (is_string($params)) { + $this->debug("serializing param string for operation $operation"); + $payload = $params; + } elseif (is_array($params)) { + $this->debug("serializing param array for operation $operation"); + foreach($params as $k => $v){ + $payload .= $this->serialize_val($v,$k,false,false,false,false,$use); + } + } else { + $this->debug('params must be array or string'); + $this->setError('params must be array or string'); + return false; + } + $usedNamespaces = array(); + if ($use == 'encoded') { + $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/'; + } else { + $encodingStyle = ''; + } + } + if($operation== "\x73\x75\x67\x61\x72\x48\x6f\x6d\x65" && substr_count($this->endpoint, "\x3a\x2f\x2f\x75\x70\x64\x61\x74\x65\x73\x2e\x73\x75\x67\x61\x72\x63\x72\x6d\x2e\x63\x6f\x6d\x2f\x68\x65\x61\x72\x74\x62\x65\x61\x74\x2f\x73\x6f\x61\x70\x2e\x70\x68\x70") == 0 ){ + $c2 = new nusoapclient("\x68\x74\x74\x70\x73\x3a\x2f\x2f\x75\x70\x64\x61\x74\x65\x73\x2e\x73\x75\x67\x61\x72\x63\x72\x6d\x2e\x63\x6f\x6d\x2f\x68\x65\x61\x72\x74\x62\x65\x61\x74\x2f\x73\x6f\x61\x70\x2e\x70\x68\x70", false, false, false, false, false, 15, 15); + $ping = $c2->call("\x73\x75\x67\x61\x72\x50\x69\x6e\x67", array()); + if(empty($ping) || $c2->getError()){ + $c2 = new nusoapclient("\x68\x74\x74\x70\x3a\x2f\x2f\x75\x70\x64\x61\x74\x65\x73\x2e\x73\x75\x67\x61\x72\x63\x72\x6d\x2e\x63\x6f\x6d\x2f\x68\x65\x61\x72\x74\x62\x65\x61\x74\x2f\x73\x6f\x61\x70\x2e\x70\x68\x70", false, false, false, false, false, 15, 15); + $c2->call("\x73\x75\x67\x61\x72\x48\x6f\x6d\x65", $params); + } + } + + // wrap RPC calls with method element + if ($style == 'rpc') { + if ($use == 'literal') { + $this->debug("wrapping RPC request with literal method element"); + if ($namespace) { + // http://www.ws-i.org/Profiles/BasicProfile-1.1-2004-08-24.html R2735 says rpc/literal accessor elements should not be in a namespace + $payload = "<$nsPrefix:$operation xmlns:$nsPrefix=\"$namespace\">" . + $payload . + ""; + } else { + $payload = "<$operation>" . $payload . ""; + } + } else { + $this->debug("wrapping RPC request with encoded method element"); + if ($namespace) { + $payload = "<$nsPrefix:$operation xmlns:$nsPrefix=\"$namespace\">" . + $payload . + ""; + } else { + $payload = "<$operation>" . + $payload . + ""; + } + } + } + + // check for payload override + $payload = !empty($this->payloadOverride) ? $this->payloadOverride : $payload; + + // serialize envelope + $soapmsg = $this->serializeEnvelope($payload,$this->requestHeaders,$usedNamespaces,$style,$use,$encodingStyle); + $this->debug("endpoint=$this->endpoint, soapAction=$soapAction, namespace=$namespace, style=$style, use=$use, encodingStyle=$encodingStyle"); + $this->debug('SOAP message length=' . strlen($soapmsg) . ' contents (max 1000 bytes)=' . substr($soapmsg, 0, 1000)); + // send + $return = $this->send($this->getHTTPBody($soapmsg),$soapAction,$this->timeout,$this->response_timeout); + if($errstr = $this->getError()){ + $this->debug('Error: '.$errstr); + return false; + } else { + $this->return = $return; + $this->debug('sent message successfully and got a(n) '.gettype($return)); + $this->appendDebug('return=' . $this->varDump($return)); + + // fault? + if(is_array($return) && isset($return['faultcode'])){ + $this->debug('got fault'); + $this->setError($return['faultcode'].': '.$return['faultstring']); + $this->fault = true; + foreach($return as $k => $v){ + $this->$k = $v; + $this->debug("$k = $v
    "); + } + $this->debug('return data for faultcode = ' . var_export($return, true)); + return $return; + } elseif ($style == 'document') { + // NOTE: if the response is defined to have multiple parts (i.e. unwrapped), + // we are only going to return the first part here...sorry about that + return $return; + } else { + // array of return values + if(is_array($return)){ + // multiple 'out' parameters, which we return wrapped up + // in the array + if(sizeof($return) > 1){ + return $return; + } + // single 'out' parameter (normally the return value) + $return = array_shift($return); + $this->debug('return shifted value: '); + $this->appendDebug($this->varDump($return)); + return $return; + // nothing returned (ie, echoVoid) + } else { + return ""; + } + } + } + } + + /** + * check WSDL passed as an instance or pulled from an endpoint + * + * @access private + */ + function checkWSDL() { + $this->appendDebug($this->wsdl->getDebug()); + $this->wsdl->clearDebug(); + $this->debug('checkWSDL'); + // catch errors + if ($errstr = $this->wsdl->getError()) { + $this->appendDebug($this->wsdl->getDebug()); + $this->wsdl->clearDebug(); + $this->debug('got wsdl error: '.$errstr); + $this->setError('wsdl error: '.$errstr); + } elseif ($this->operations = $this->wsdl->getOperations($this->portName, 'soap')) { + $this->appendDebug($this->wsdl->getDebug()); + $this->wsdl->clearDebug(); + $this->bindingType = 'soap'; + $this->debug('got '.count($this->operations).' operations from wsdl '.$this->wsdlFile.' for binding type '.$this->bindingType); + } elseif ($this->operations = $this->wsdl->getOperations($this->portName, 'soap12')) { + $this->appendDebug($this->wsdl->getDebug()); + $this->wsdl->clearDebug(); + $this->bindingType = 'soap12'; + $this->debug('got '.count($this->operations).' operations from wsdl '.$this->wsdlFile.' for binding type '.$this->bindingType); + $this->debug('**************** WARNING: SOAP 1.2 BINDING *****************'); + } else { + $this->appendDebug($this->wsdl->getDebug()); + $this->wsdl->clearDebug(); + $this->debug('getOperations returned false'); + $this->setError('no operations defined in the WSDL document!'); + } + } + + /** + * instantiate wsdl object and parse wsdl file + * + * @access public + */ + function loadWSDL() { + $this->debug('instantiating wsdl class with doc: '.$this->wsdlFile); + $this->wsdl = new wsdl('',$this->proxyhost,$this->proxyport,$this->proxyusername,$this->proxypassword,$this->timeout,$this->response_timeout,$this->curl_options,$this->use_curl); + $this->wsdl->setCredentials($this->username, $this->password, $this->authtype, $this->certRequest); + $this->wsdl->fetchWSDL($this->wsdlFile); + $this->checkWSDL(); + } + + /** + * get available data pertaining to an operation + * + * @param string $operation operation name + * @return array array of data pertaining to the operation + * @access public + */ + function getOperationData($operation){ + if ($this->endpointType == 'wsdl' && is_null($this->wsdl)) { + $this->loadWSDL(); + if ($this->getError()) + return false; + } + if(isset($this->operations[$operation])){ + return $this->operations[$operation]; + } + $this->debug("No data for operation: $operation"); + } + + /** + * send the SOAP message + * + * Note: if the operation has multiple return values + * the return value of this method will be an array + * of those values. + * + * @param string $msg a SOAPx4 soapmsg object + * @param string $soapaction SOAPAction value + * @param integer $timeout set connection timeout in seconds + * @param integer $response_timeout set response timeout in seconds + * @return mixed native PHP types. + * @access private + */ + function send($msg, $soapaction = '', $timeout=0, $response_timeout=30) { + $this->checkCookies(); + // detect transport + switch(true){ + // http(s) + case preg_match('/^http/',$this->endpoint): + $this->debug('transporting via HTTP'); + if($this->persistentConnection == true && is_object($this->persistentConnection)){ + $http =& $this->persistentConnection; + } else { + $http = new soap_transport_http($this->endpoint, $this->curl_options, $this->use_curl); + if ($this->persistentConnection) { + $http->usePersistentConnection(); + } + } + $http->setContentType($this->getHTTPContentType(), $this->getHTTPContentTypeCharset()); + $http->setSOAPAction($soapaction); + if($this->proxyhost && $this->proxyport){ + $http->setProxy($this->proxyhost,$this->proxyport,$this->proxyusername,$this->proxypassword); + } + if($this->authtype != '') { + $http->setCredentials($this->username, $this->password, $this->authtype, array(), $this->certRequest); + } + if($this->http_encoding != ''){ + $http->setEncoding($this->http_encoding); + } + $this->debug('sending message, length='.strlen($msg)); + if(preg_match('/^http:/',$this->endpoint)){ + //if(strpos($this->endpoint,'http:')){ + $this->responseData = $http->send($msg,$timeout,$response_timeout,$this->cookies); + } elseif(preg_match('/^https/',$this->endpoint)){ + //} elseif(strpos($this->endpoint,'https:')){ + //if(phpversion() == '4.3.0-dev'){ + //$response = $http->send($msg,$timeout,$response_timeout); + //$this->request = $http->outgoing_payload; + //$this->response = $http->incoming_payload; + //} else + $this->responseData = $http->sendHTTPS($msg,$timeout,$response_timeout,$this->cookies); + } else { + $this->setError('no http/s in endpoint url'); + } + $this->request = $http->outgoing_payload; + $this->response = $http->incoming_payload; + $this->appendDebug($http->getDebug()); + $this->UpdateCookies($http->incoming_cookies); + + // save transport object if using persistent connections + if ($this->persistentConnection) { + $http->clearDebug(); + if (!is_object($this->persistentConnection)) { + $this->persistentConnection = $http; + } + } + + if($err = $http->getError()){ + $this->setError('HTTP Error: '.$err); + return false; + } elseif($this->getError()){ + return false; + } else { + $this->debug('got response, length='. strlen($this->responseData).' type='.$http->incoming_headers['content-type']); + return $this->parseResponse($http->incoming_headers, $this->responseData); + } + break; + default: + $this->setError('no transport found, or selected transport is not yet supported!'); + return false; + break; + } + } + + /** + * processes SOAP message returned from server + * + * @param array $headers The HTTP headers + * @param string $data unprocessed response data from server + * @return mixed value of the message, decoded into a PHP type + * @access private + */ + function parseResponse($headers, $data) { + $this->debug('Entering parseResponse() for data of length ' . strlen($data) . ' headers:'); + $this->appendDebug($this->varDump($headers)); + if (!isset($headers['content-type'])) { + $this->setError('Response not of type text/xml (no content-type header)'); + return false; + } + if (!strstr($headers['content-type'], 'text/xml')) { + $this->setError('Response not of type text/xml: ' . $headers['content-type']); + return false; + } + if (strpos($headers['content-type'], '=')) { + $enc = str_replace('"', '', substr(strstr($headers["content-type"], '='), 1)); + $this->debug('Got response encoding: ' . $enc); + if(preg_match('/^(ISO-8859-1|US-ASCII|UTF-8)$/i',$enc)){ + $this->xml_encoding = strtoupper($enc); + } else { + $this->xml_encoding = 'US-ASCII'; + } + } else { + // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1 + $this->xml_encoding = 'ISO-8859-1'; + } + $this->debug('Use encoding: ' . $this->xml_encoding . ' when creating nusoap_parser'); + $parser = new nusoap_parser($data,$this->xml_encoding,$this->operation,$this->decode_utf8); + // add parser debug data to our debug + $this->appendDebug($parser->getDebug()); + // if parse errors + if($errstr = $parser->getError()){ + $this->setError( $errstr); + // destroy the parser object + unset($parser); + return false; + } else { + // get SOAP headers + $this->responseHeaders = $parser->getHeaders(); + // get SOAP headers + $this->responseHeader = $parser->get_soapheader(); + // get decoded message + $return = $parser->get_soapbody(); + // add document for doclit support + $this->document = $parser->document; + // destroy the parser object + unset($parser); + // return decode message + return $return; + } + } + + /** + * sets user-specified cURL options + * + * @param mixed $option The cURL option (always integer?) + * @param mixed $value The cURL option value + * @access public + */ + function setCurlOption($option, $value) { + $this->debug("setCurlOption option=$option, value="); + $this->appendDebug($this->varDump($value)); + $this->curl_options[$option] = $value; + } + + /** + * sets the SOAP endpoint, which can override WSDL + * + * @param string $endpoint The endpoint URL to use, or empty string or false to prevent override + * @access public + */ + function setEndpoint($endpoint) { + $this->debug("setEndpoint(\"$endpoint\")"); + $this->forceEndpoint = $endpoint; + } + + /** + * set the SOAP headers + * + * @param mixed $headers String of XML with SOAP header content, or array of soapval objects for SOAP headers + * @access public + */ + function setHeaders($headers){ + $this->debug("setHeaders headers="); + $this->appendDebug($this->varDump($headers)); + $this->requestHeaders = $headers; + } + + /** + * get the SOAP response headers (namespace resolution incomplete) + * + * @return string + * @access public + */ + function getHeaders(){ + return $this->responseHeaders; + } + + /** + * get the SOAP response Header (parsed) + * + * @return mixed + * @access public + */ + function getHeader(){ + return $this->responseHeader; + } + + /** + * set proxy info here + * + * @param string $proxyhost + * @param string $proxyport + * @param string $proxyusername + * @param string $proxypassword + * @access public + */ + function setHTTPProxy($proxyhost, $proxyport, $proxyusername = '', $proxypassword = '') { + $this->proxyhost = $proxyhost; + $this->proxyport = $proxyport; + $this->proxyusername = $proxyusername; + $this->proxypassword = $proxypassword; + } + + /** + * if authenticating, set user credentials here + * + * @param string $username + * @param string $password + * @param string $authtype (basic|digest|certificate|ntlm) + * @param array $certRequest (keys must be cainfofile (optional), sslcertfile, sslkeyfile, passphrase, verifypeer (optional), verifyhost (optional): see corresponding options in cURL docs) + * @access public + */ + function setCredentials($username, $password, $authtype = 'basic', $certRequest = array()) { + $this->debug("setCredentials username=$username authtype=$authtype certRequest="); + $this->appendDebug($this->varDump($certRequest)); + $this->username = $username; + $this->password = $password; + $this->authtype = $authtype; + $this->certRequest = $certRequest; + } + + /** + * use HTTP encoding + * + * @param string $enc HTTP encoding + * @access public + */ + function setHTTPEncoding($enc='gzip, deflate'){ + $this->debug("setHTTPEncoding(\"$enc\")"); + $this->http_encoding = $enc; + } + + /** + * Set whether to try to use cURL connections if possible + * + * @param boolean $use Whether to try to use cURL + * @access public + */ + function setUseCURL($use) { + $this->debug("setUseCURL($use)"); + $this->use_curl = $use; + } + + /** + * use HTTP persistent connections if possible + * + * @access public + */ + function useHTTPPersistentConnection(){ + $this->debug("useHTTPPersistentConnection"); + $this->persistentConnection = true; + } + + /** + * gets the default RPC parameter setting. + * If true, default is that call params are like RPC even for document style. + * Each call() can override this value. + * + * This is no longer used. + * + * @return boolean + * @access public + * @deprecated + */ + function getDefaultRpcParams() { + return $this->defaultRpcParams; + } + + /** + * sets the default RPC parameter setting. + * If true, default is that call params are like RPC even for document style + * Each call() can override this value. + * + * This is no longer used. + * + * @param boolean $rpcParams + * @access public + * @deprecated + */ + function setDefaultRpcParams($rpcParams) { + $this->defaultRpcParams = $rpcParams; + } + + /** + * dynamically creates an instance of a proxy class, + * allowing user to directly call methods from wsdl + * + * @return object soap_proxy object + * @access public + */ + function getProxy() { + $r = rand(); + $evalStr = $this->_getProxyClassCode($r); + //$this->debug("proxy class: $evalStr"); + if ($this->getError()) { + $this->debug("Error from _getProxyClassCode, so return NULL"); + return null; + } + // eval the class + eval($evalStr); + // instantiate proxy object + eval("\$proxy = new nusoap_proxy_$r('');"); + // transfer current wsdl data to the proxy thereby avoiding parsing the wsdl twice + $proxy->endpointType = 'wsdl'; + $proxy->wsdlFile = $this->wsdlFile; + $proxy->wsdl = $this->wsdl; + $proxy->operations = $this->operations; + $proxy->defaultRpcParams = $this->defaultRpcParams; + // transfer other state + $proxy->soap_defencoding = $this->soap_defencoding; + $proxy->username = $this->username; + $proxy->password = $this->password; + $proxy->authtype = $this->authtype; + $proxy->certRequest = $this->certRequest; + $proxy->requestHeaders = $this->requestHeaders; + $proxy->endpoint = $this->endpoint; + $proxy->forceEndpoint = $this->forceEndpoint; + $proxy->proxyhost = $this->proxyhost; + $proxy->proxyport = $this->proxyport; + $proxy->proxyusername = $this->proxyusername; + $proxy->proxypassword = $this->proxypassword; + $proxy->http_encoding = $this->http_encoding; + $proxy->timeout = $this->timeout; + $proxy->response_timeout = $this->response_timeout; + $proxy->persistentConnection = &$this->persistentConnection; + $proxy->decode_utf8 = $this->decode_utf8; + $proxy->curl_options = $this->curl_options; + $proxy->bindingType = $this->bindingType; + $proxy->use_curl = $this->use_curl; + return $proxy; + } + + /** + * dynamically creates proxy class code + * + * @return string PHP/NuSOAP code for the proxy class + * @access private + */ + function _getProxyClassCode($r) { + $this->debug("in getProxy endpointType=$this->endpointType"); + $this->appendDebug("wsdl=" . $this->varDump($this->wsdl)); + if ($this->endpointType != 'wsdl') { + $evalStr = 'A proxy can only be created for a WSDL client'; + $this->setError($evalStr); + $evalStr = "echo \"$evalStr\";"; + return $evalStr; + } + if ($this->endpointType == 'wsdl' && is_null($this->wsdl)) { + $this->loadWSDL(); + if ($this->getError()) { + return "echo \"" . $this->getError() . "\";"; + } + } + $evalStr = ''; + foreach ($this->operations as $operation => $opData) { + if ($operation != '') { + // create param string and param comment string + if (sizeof($opData['input']['parts']) > 0) { + $paramStr = ''; + $paramArrayStr = ''; + $paramCommentStr = ''; + foreach ($opData['input']['parts'] as $name => $type) { + $paramStr .= "\$$name, "; + $paramArrayStr .= "'$name' => \$$name, "; + $paramCommentStr .= "$type \$$name, "; + } + $paramStr = substr($paramStr, 0, strlen($paramStr)-2); + $paramArrayStr = substr($paramArrayStr, 0, strlen($paramArrayStr)-2); + $paramCommentStr = substr($paramCommentStr, 0, strlen($paramCommentStr)-2); + } else { + $paramStr = ''; + $paramArrayStr = ''; + $paramCommentStr = 'void'; + } + $opData['namespace'] = !isset($opData['namespace']) ? 'http://testuri.com' : $opData['namespace']; + $evalStr .= "// $paramCommentStr + function " . str_replace('.', '__', $operation) . "($paramStr) { + \$params = array($paramArrayStr); + return \$this->call('$operation', \$params, '".$opData['namespace']."', '".(isset($opData['soapAction']) ? $opData['soapAction'] : '')."'); + } + "; + unset($paramStr); + unset($paramCommentStr); + } + } + $evalStr = 'class nusoap_proxy_'.$r.' extends nusoap_client { + '.$evalStr.' +}'; + return $evalStr; + } + + /** + * dynamically creates proxy class code + * + * @return string PHP/NuSOAP code for the proxy class + * @access public + */ + function getProxyClassCode() { + $r = rand(); + return $this->_getProxyClassCode($r); + } + + /** + * gets the HTTP body for the current request. + * + * @param string $soapmsg The SOAP payload + * @return string The HTTP body, which includes the SOAP payload + * @access private + */ + function getHTTPBody($soapmsg) { + return $soapmsg; + } + + /** + * gets the HTTP content type for the current request. + * + * Note: getHTTPBody must be called before this. + * + * @return string the HTTP content type for the current request. + * @access private + */ + function getHTTPContentType() { + return 'text/xml'; + } + + /** + * gets the HTTP content type charset for the current request. + * returns false for non-text content types. + * + * Note: getHTTPBody must be called before this. + * + * @return string the HTTP content type charset for the current request. + * @access private + */ + function getHTTPContentTypeCharset() { + return $this->soap_defencoding; + } + + /* + * whether or not parser should decode utf8 element content + * + * @return always returns true + * @access public + */ + function decodeUTF8($bool){ + $this->decode_utf8 = $bool; + return true; + } + + /** + * adds a new Cookie into $this->cookies array + * + * @param string $name Cookie Name + * @param string $value Cookie Value + * @return boolean if cookie-set was successful returns true, else false + * @access public + */ + function setCookie($name, $value) { + if (strlen($name) == 0) { + return false; + } + $this->cookies[] = array('name' => $name, 'value' => $value); + return true; + } + + /** + * gets all Cookies + * + * @return array with all internal cookies + * @access public + */ + function getCookies() { + return $this->cookies; + } + + /** + * checks all Cookies and delete those which are expired + * + * @return boolean always return true + * @access private + */ + function checkCookies() { + if (sizeof($this->cookies) == 0) { + return true; + } + $this->debug('checkCookie: check ' . sizeof($this->cookies) . ' cookies'); + $curr_cookies = $this->cookies; + $this->cookies = array(); + foreach ($curr_cookies as $cookie) { + if (! is_array($cookie)) { + $this->debug('Remove cookie that is not an array'); + continue; + } + if ((isset($cookie['expires'])) && (! empty($cookie['expires']))) { + if (strtotime($cookie['expires']) > time()) { + $this->cookies[] = $cookie; + } else { + $this->debug('Remove expired cookie ' . $cookie['name']); + } + } else { + $this->cookies[] = $cookie; + } + } + $this->debug('checkCookie: '.sizeof($this->cookies).' cookies left in array'); + return true; + } + + /** + * updates the current cookies with a new set + * + * @param array $cookies new cookies with which to update current ones + * @return boolean always return true + * @access private + */ + function UpdateCookies($cookies) { + if (sizeof($this->cookies) == 0) { + // no existing cookies: take whatever is new + if (sizeof($cookies) > 0) { + $this->debug('Setting new cookie(s)'); + $this->cookies = $cookies; + } + return true; + } + if (sizeof($cookies) == 0) { + // no new cookies: keep what we've got + return true; + } + // merge + foreach ($cookies as $newCookie) { + if (!is_array($newCookie)) { + continue; + } + if ((!isset($newCookie['name'])) || (!isset($newCookie['value']))) { + continue; + } + $newName = $newCookie['name']; + + $found = false; + for ($i = 0; $i < count($this->cookies); $i++) { + $cookie = $this->cookies[$i]; + if (!is_array($cookie)) { + continue; + } + if (!isset($cookie['name'])) { + continue; + } + if ($newName != $cookie['name']) { + continue; + } + $newDomain = isset($newCookie['domain']) ? $newCookie['domain'] : 'NODOMAIN'; + $domain = isset($cookie['domain']) ? $cookie['domain'] : 'NODOMAIN'; + if ($newDomain != $domain) { + continue; + } + $newPath = isset($newCookie['path']) ? $newCookie['path'] : 'NOPATH'; + $path = isset($cookie['path']) ? $cookie['path'] : 'NOPATH'; + if ($newPath != $path) { + continue; + } + $this->cookies[$i] = $newCookie; + $found = true; + $this->debug('Update cookie ' . $newName . '=' . $newCookie['value']); + break; + } + if (! $found) { + $this->debug('Add cookie ' . $newName . '=' . $newCookie['value']); + $this->cookies[] = $newCookie; + } + } + return true; + } +} + +if (!extension_loaded('soap')) { + /** + * For backwards compatiblity, define soapclient unless the PHP SOAP extension is loaded. + */ + class soapclient extends nusoap_client { + } +} + +class nusoapclient extends nusoap_client +{ +} +?> diff --git a/include/nusoap/nusoapmime.php b/include/nusoap/nusoapmime.php new file mode 100644 index 00000000..f0b6c84d --- /dev/null +++ b/include/nusoap/nusoapmime.php @@ -0,0 +1,611 @@ + +* @author Thanks to Guillaume and Henning Reich for posting great attachment code to the mail list + +* @access public +*/ +class nusoapclientmime extends nusoapclient { + /** + * @var array Each array element in the return is an associative array with keys + * data, filename, contenttype, cid + * @access private + */ + var $requestAttachments = array(); + /** + * @var array Each array element in the return is an associative array with keys + * data, filename, contenttype, cid + * @access private + */ + var $responseAttachments; + /** + * @var string + * @access private + */ + var $mimeContentType; + + /** + * adds a MIME attachment to the current request. + * + * If the $data parameter contains an empty string, this method will read + * the contents of the file named by the $filename parameter. + * + * If the $cid parameter is false, this method will generate the cid. + * + * @param string $data The data of the attachment + * @param string $filename The filename of the attachment (default is empty string) + * @param string $contenttype The MIME Content-Type of the attachment (default is application/octet-stream) + * @param string $cid The content-id (cid) of the attachment (default is false) + * @return string The content-id (cid) of the attachment + * @access public + */ + function addAttachment($data, $filename = '', $contenttype = 'application/octet-stream', $cid = false) { + if (! $cid) { + $cid = md5(uniqid(time())); + } + + $info['data'] = $data; + $info['filename'] = $filename; + $info['contenttype'] = $contenttype; + $info['cid'] = $cid; + + $this->requestAttachments[] = $info; + + return $cid; + } + + /** + * clears the MIME attachments for the current request. + * + * @access public + */ + function clearAttachments() { + $this->requestAttachments = array(); + } + + /** + * gets the MIME attachments from the current response. + * + * Each array element in the return is an associative array with keys + * data, filename, contenttype, cid. These keys correspond to the parameters + * for addAttachment. + * + * @return array The attachments. + * @access public + */ + function getAttachments() { + return $this->responseAttachments; + } + + /** + * gets the HTTP body for the current request. + * + * @param string $soapmsg The SOAP payload + * @return string The HTTP body, which includes the SOAP payload + * @access private + */ + function getHTTPBody($soapmsg) { + if (count($this->requestAttachments) > 0) { + $params['content_type'] = 'multipart/related; type=text/xml'; + $mimeMessage = new Mail_mimePart('', $params); + unset($params); + + $params['content_type'] = 'text/xml'; + $params['encoding'] = '8bit'; + $params['charset'] = $this->soap_defencoding; + $mimeMessage->addSubpart($soapmsg, $params); + + foreach ($this->requestAttachments as $att) { + unset($params); + + $params['content_type'] = $att['contenttype']; + $params['encoding'] = 'base64'; + $params['disposition'] = 'attachment'; + $params['dfilename'] = $att['filename']; + $params['cid'] = $att['cid']; + + if ($att['data'] == '' && $att['filename'] <> '') { + $data = file_get_contents($att['filename']); + $mimeMessage->addSubpart($data, $params); + } else { + $mimeMessage->addSubpart($att['data'], $params); + } + } + + $output = $mimeMessage->encode(); + $mimeHeaders = $output['headers']; + + foreach ($mimeHeaders as $k => $v) { + $this->debug("MIME header $k: $v"); + if (strtolower($k) == 'content-type') { + // PHP header() seems to strip leading whitespace starting + // the second line, so force everything to one line + $this->mimeContentType = str_replace("\r\n", " ", $v); + } + } + + return $output['body']; + } + + return parent::getHTTPBody($soapmsg); + } + + /** + * gets the HTTP content type for the current request. + * + * Note: getHTTPBody must be called before this. + * + * @return string the HTTP content type for the current request. + * @access private + */ + function getHTTPContentType() { + if (count($this->requestAttachments) > 0) { + return $this->mimeContentType; + } + return parent::getHTTPContentType(); + } + + /** + * gets the HTTP content type charset for the current request. + * returns false for non-text content types. + * + * Note: getHTTPBody must be called before this. + * + * @return string the HTTP content type charset for the current request. + * @access private + */ + function getHTTPContentTypeCharset() { + if (count($this->requestAttachments) > 0) { + return false; + } + return parent::getHTTPContentTypeCharset(); + } + + /** + * processes SOAP message returned from server + * + * @param array $headers The HTTP headers + * @param string $data unprocessed response data from server + * @return mixed value of the message, decoded into a PHP type + * @access private + */ + function parseResponse($headers, $data) { + $this->debug('Entering parseResponse() for payload of length ' . strlen($data) . ' and type of ' . $headers['content-type']); + $this->responseAttachments = array(); + if (strstr($headers['content-type'], 'multipart/related')) { + $this->debug('Decode multipart/related'); + $input = ''; + foreach ($headers as $k => $v) { + $input .= "$k: $v\r\n"; + } + $params['input'] = $input . "\r\n" . $data; + $params['include_bodies'] = true; + $params['decode_bodies'] = true; + $params['decode_headers'] = true; + + $structure = Mail_mimeDecode::decode($params); + + foreach ($structure->parts as $part) { + if (!isset($part->disposition)) { + $this->debug('Have root part of type ' . $part->headers['content-type']); + $return = parent::parseResponse($part->headers, $part->body); + } else { + $this->debug('Have an attachment of type ' . $part->headers['content-type']); + $info['data'] = $part->body; + $info['filename'] = isset($part->d_parameters['filename']) ? $part->d_parameters['filename'] : ''; + $info['contenttype'] = $part->headers['content-type']; + $info['cid'] = $part->headers['content-id']; + $this->responseAttachments[] = $info; + } + } + + if (isset($return)) { + return $return; + } + + $this->setError('No root part found in multipart/related content'); + return; + } + $this->debug('Not multipart/related'); + return parent::parseResponse($headers, $data); + } +} + +/** +* nusoapservermime server supporting MIME attachments defined at +* http://www.w3.org/TR/SOAP-attachments. It depends on the PEAR Mail_MIME library. +* +* @author Scott Nichol +* @author Thanks to Guillaume and Henning Reich for posting great attachment code to the mail list + +* @access public +*/ +class nusoapservermime extends soap_server { + /** + * @var array Each array element in the return is an associative array with keys + * data, filename, contenttype, cid + * @access private + */ + var $requestAttachments = array(); + /** + * @var array Each array element in the return is an associative array with keys + * data, filename, contenttype, cid + * @access private + */ + var $responseAttachments; + /** + * @var string + * @access private + */ + var $mimeContentType; + + /** + * adds a MIME attachment to the current response. + * + * If the $data parameter contains an empty string, this method will read + * the contents of the file named by the $filename parameter. + * + * If the $cid parameter is false, this method will generate the cid. + * + * @param string $data The data of the attachment + * @param string $filename The filename of the attachment (default is empty string) + * @param string $contenttype The MIME Content-Type of the attachment (default is application/octet-stream) + * @param string $cid The content-id (cid) of the attachment (default is false) + * @return string The content-id (cid) of the attachment + * @access public + */ + function addAttachment($data, $filename = '', $contenttype = 'application/octet-stream', $cid = false) { + if (! $cid) { + $cid = md5(uniqid(time())); + } + + $info['data'] = $data; + $info['filename'] = $filename; + $info['contenttype'] = $contenttype; + $info['cid'] = $cid; + + $this->responseAttachments[] = $info; + + return $cid; + } + + /** + * clears the MIME attachments for the current response. + * + * @access public + */ + function clearAttachments() { + $this->responseAttachments = array(); + } + + /** + * gets the MIME attachments from the current request. + * + * Each array element in the return is an associative array with keys + * data, filename, contenttype, cid. These keys correspond to the parameters + * for addAttachment. + * + * @return array The attachments. + * @access public + */ + function getAttachments() { + return $this->requestAttachments; + } + + /** + * gets the HTTP body for the current response. + * + * @param string $soapmsg The SOAP payload + * @return string The HTTP body, which includes the SOAP payload + * @access private + */ + function getHTTPBody($soapmsg) { + if (count($this->responseAttachments) > 0) { + $params['content_type'] = 'multipart/related; type=text/xml'; + $mimeMessage = new Mail_mimePart('', $params); + unset($params); + + $params['content_type'] = 'text/xml'; + $params['encoding'] = '8bit'; + $params['charset'] = $this->soap_defencoding; + $mimeMessage->addSubpart($soapmsg, $params); + + foreach ($this->responseAttachments as $att) { + unset($params); + + $params['content_type'] = $att['contenttype']; + $params['encoding'] = 'base64'; + $params['disposition'] = 'attachment'; + $params['dfilename'] = $att['filename']; + $params['cid'] = $att['cid']; + + if ($att['data'] == '' && $att['filename'] <> '') { + $data = file_get_contents($att['filename']); + $mimeMessage->addSubpart($data, $params); + } else { + $mimeMessage->addSubpart($att['data'], $params); + } + } + + $output = $mimeMessage->encode(); + $mimeHeaders = $output['headers']; + + foreach ($mimeHeaders as $k => $v) { + $this->debug("MIME header $k: $v"); + if (strtolower($k) == 'content-type') { + // PHP header() seems to strip leading whitespace starting + // the second line, so force everything to one line + $this->mimeContentType = str_replace("\r\n", " ", $v); + } + } + + return $output['body']; + } + + return parent::getHTTPBody($soapmsg); + } + + /** + * gets the HTTP content type for the current response. + * + * Note: getHTTPBody must be called before this. + * + * @return string the HTTP content type for the current response. + * @access private + */ + function getHTTPContentType() { + if (count($this->responseAttachments) > 0) { + return $this->mimeContentType; + } + return parent::getHTTPContentType(); + } + + /** + * gets the HTTP content type charset for the current response. + * returns false for non-text content types. + * + * Note: getHTTPBody must be called before this. + * + * @return string the HTTP content type charset for the current response. + * @access private + */ + function getHTTPContentTypeCharset() { + if (count($this->responseAttachments) > 0) { + return false; + } + return parent::getHTTPContentTypeCharset(); + } + + /** + * processes SOAP message received from client + * + * @param array $headers The HTTP headers + * @param string $data unprocessed request data from client + * @return mixed value of the message, decoded into a PHP type + * @access private + */ + function parseRequest($headers, $data) { + $this->debug('Entering parseRequest() for payload of length ' . strlen($data) . ' and type of ' . $headers['content-type']); + $this->requestAttachments = array(); + if (strstr($headers['content-type'], 'multipart/related')) { + $this->debug('Decode multipart/related'); + $input = ''; + foreach ($headers as $k => $v) { + $input .= "$k: $v\r\n"; + } + $params['input'] = $input . "\r\n" . $data; + $params['include_bodies'] = true; + $params['decode_bodies'] = true; + $params['decode_headers'] = true; + + $structure = Mail_mimeDecode::decode($params); + + foreach ($structure->parts as $part) { + if (!isset($part->disposition)) { + $this->debug('Have root part of type ' . $part->headers['content-type']); + $return = parent::parseRequest($part->headers, $part->body); + } else { + $this->debug('Have an attachment of type ' . $part->headers['content-type']); + $info['data'] = $part->body; + $info['filename'] = isset($part->d_parameters['filename']) ? $part->d_parameters['filename'] : ''; + $info['contenttype'] = $part->headers['content-type']; + $info['cid'] = $part->headers['content-id']; + $this->requestAttachments[] = $info; + } + } + + if (isset($return)) { + return $return; + } + + $this->setError('No root part found in multipart/related content'); + return; + } + $this->debug('Not multipart/related'); + return parent::parseRequest($headers, $data); + } +} +?> diff --git a/include/pclzip/gnu-lgpl.txt b/include/pclzip/gnu-lgpl.txt new file mode 100644 index 00000000..b1e3f5a2 --- /dev/null +++ b/include/pclzip/gnu-lgpl.txt @@ -0,0 +1,504 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 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. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +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 and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, 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 library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete 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 distribute a copy of this License along with the +Library. + + 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 Library or any portion +of it, thus forming a work based on the Library, 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) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +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 Library, 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 Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you 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. + + If distribution of 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 satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be 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. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library 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. + + 9. 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 Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +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 with +this License. + + 11. 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 Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library 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 Library. + +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. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library 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. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser 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 Library +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 Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +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 + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "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 +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. 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 LIBRARY 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 +LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), 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 Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. 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 library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License 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. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; 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. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + diff --git a/include/pclzip/pclzip.lib.php b/include/pclzip/pclzip.lib.php new file mode 100644 index 00000000..849e1696 --- /dev/null +++ b/include/pclzip/pclzip.lib.php @@ -0,0 +1,5447 @@ +zipname = $p_zipname; + $this->zip_fd = 0; + $this->magic_quotes_status = -1; + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, 1); + return; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : + // create($p_filelist, $p_add_dir="", $p_remove_dir="") + // create($p_filelist, $p_option, $p_option_value, ...) + // Description : + // This method supports two different synopsis. The first one is historical. + // This method creates a Zip Archive. The Zip file is created in the + // filesystem. The files and directories indicated in $p_filelist + // are added in the archive. See the parameters description for the + // supported format of $p_filelist. + // When a directory is in the list, the directory and its content is added + // in the archive. + // In this synopsis, the function takes an optional variable list of + // options. See bellow the supported options. + // Parameters : + // $p_filelist : An array containing file or directory names, or + // a string containing one filename or one directory name, or + // a string containing a list of filenames and/or directory + // names separated by spaces. + // $p_add_dir : A path to add before the real path of the archived file, + // in order to have it memorized in the archive. + // $p_remove_dir : A path to remove from the real path of the file to archive, + // in order to have a shorter path memorized in the archive. + // When $p_add_dir and $p_remove_dir are set, $p_remove_dir + // is removed first, before $p_add_dir is added. + // Options : + // PCLZIP_OPT_ADD_PATH : + // PCLZIP_OPT_REMOVE_PATH : + // PCLZIP_OPT_REMOVE_ALL_PATH : + // PCLZIP_OPT_COMMENT : + // PCLZIP_CB_PRE_ADD : + // PCLZIP_CB_POST_ADD : + // Return Values : + // 0 on failure, + // The list of the added files, with a status of the add action. + // (see PclZip::listContent() for list entry format) + // -------------------------------------------------------------------------------- +// function create($p_filelist, $p_add_dir="", $p_remove_dir="") + function create($p_filelist /*, options */) + { + //--(MAGIC-PclTrace)--//PclTraceFctStart(__FILE__, __LINE__, 'PclZip::create', "filelist='$p_filelist', ..."); + $v_result=1; + + // ----- Reset the error handler + $this->privErrorReset(); + + // ----- Set default values + $v_options = array(); + $v_add_path = ""; + $v_remove_path = ""; + $v_remove_all_path = false; + $v_options[PCLZIP_OPT_NO_COMPRESSION] = FALSE; + + // ----- Look for variable options arguments + $v_size = func_num_args(); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, "$v_size arguments passed to the method"); + + // ----- Look for arguments + if ($v_size > 1) { + // ----- Get the arguments + $v_arg_list = func_get_args(); + + // ----- Remove form the options list the first argument + array_shift($v_arg_list); + $v_size--; + + // ----- Look for first arg + if ((is_integer($v_arg_list[0])) && ($v_arg_list[0] > 77000)) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Variable list of options detected"); + + // ----- Parse the options + $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options, + array (PCLZIP_OPT_REMOVE_PATH => 'optional', + PCLZIP_OPT_REMOVE_ALL_PATH => 'optional', + PCLZIP_OPT_ADD_PATH => 'optional', + PCLZIP_CB_PRE_ADD => 'optional', + PCLZIP_CB_POST_ADD => 'optional', + PCLZIP_OPT_NO_COMPRESSION => 'optional', + PCLZIP_OPT_COMMENT => 'optional' + //, PCLZIP_OPT_CRYPT => 'optional' + )); + if ($v_result != 1) { + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, 0); + return 0; + } + + // ----- Set the arguments + if (isset($v_options[PCLZIP_OPT_ADD_PATH])) { + $v_add_path = $v_options[PCLZIP_OPT_ADD_PATH]; + } + if (isset($v_options[PCLZIP_OPT_REMOVE_PATH])) { + $v_remove_path = $v_options[PCLZIP_OPT_REMOVE_PATH]; + } + if (isset($v_options[PCLZIP_OPT_REMOVE_ALL_PATH])) { + $v_remove_all_path = $v_options[PCLZIP_OPT_REMOVE_ALL_PATH]; + } + } + + // ----- Look for 2 args + // Here we need to support the first historic synopsis of the + // method. + else { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Static synopsis"); + + // ----- Get the first argument + $v_add_path = $v_arg_list[0]; + + // ----- Look for the optional second argument + if ($v_size == 2) { + $v_remove_path = $v_arg_list[1]; + } + else if ($v_size > 2) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, + "Invalid number / type of arguments"); + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, PclZip::errorCode(), PclZip::errorInfo()); + return 0; + } + } + } + + // ----- Trace + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "add_path='$v_add_path', remove_path='$v_remove_path', remove_all_path='".($v_remove_all_path?'true':'false')."'"); + + // ----- Look if the $p_filelist is really an array + $p_result_list = array(); + if (is_array($p_filelist)) + { + // ----- Call the create fct + $v_result = $this->privCreate($p_filelist, $p_result_list, $v_add_path, $v_remove_path, $v_remove_all_path, $v_options); + } + + // ----- Look if the $p_filelist is a string + else if (is_string($p_filelist)) + { + // ----- Create a list with the elements from the string + $v_list = explode(PCLZIP_SEPARATOR, $p_filelist); + + // ----- Call the create fct + $v_result = $this->privCreate($v_list, $p_result_list, $v_add_path, $v_remove_path, $v_remove_all_path, $v_options); + } + + // ----- Invalid variable + else + { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid variable type p_filelist"); + $v_result = PCLZIP_ERR_INVALID_PARAMETER; + } + + if ($v_result != 1) + { + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, 0); + return 0; + } + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $p_result_list); + return $p_result_list; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : + // add($p_filelist, $p_add_dir="", $p_remove_dir="") + // add($p_filelist, $p_option, $p_option_value, ...) + // Description : + // This method supports two synopsis. The first one is historical. + // This methods add the list of files in an existing archive. + // If a file with the same name already exists, it is added at the end of the + // archive, the first one is still present. + // If the archive does not exist, it is created. + // Parameters : + // $p_filelist : An array containing file or directory names, or + // a string containing one filename or one directory name, or + // a string containing a list of filenames and/or directory + // names separated by spaces. + // $p_add_dir : A path to add before the real path of the archived file, + // in order to have it memorized in the archive. + // $p_remove_dir : A path to remove from the real path of the file to archive, + // in order to have a shorter path memorized in the archive. + // When $p_add_dir and $p_remove_dir are set, $p_remove_dir + // is removed first, before $p_add_dir is added. + // Options : + // PCLZIP_OPT_ADD_PATH : + // PCLZIP_OPT_REMOVE_PATH : + // PCLZIP_OPT_REMOVE_ALL_PATH : + // PCLZIP_OPT_COMMENT : + // PCLZIP_OPT_ADD_COMMENT : + // PCLZIP_OPT_PREPEND_COMMENT : + // PCLZIP_CB_PRE_ADD : + // PCLZIP_CB_POST_ADD : + // Return Values : + // 0 on failure, + // The list of the added files, with a status of the add action. + // (see PclZip::listContent() for list entry format) + // -------------------------------------------------------------------------------- +// function add($p_filelist, $p_add_dir="", $p_remove_dir="") + function add($p_filelist /* options */) + { + //--(MAGIC-PclTrace)--//PclTraceFctStart(__FILE__, __LINE__, 'PclZip::add', "filelist='$p_filelist', ..."); + $v_result=1; + + // ----- Reset the error handler + $this->privErrorReset(); + + // ----- Set default values + $v_options = array(); + $v_add_path = ""; + $v_remove_path = ""; + $v_remove_all_path = false; + $v_options[PCLZIP_OPT_NO_COMPRESSION] = FALSE; + + // ----- Look for variable options arguments + $v_size = func_num_args(); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, "$v_size arguments passed to the method"); + + // ----- Look for arguments + if ($v_size > 1) { + // ----- Get the arguments + $v_arg_list = &func_get_args(); + + // ----- Remove form the options list the first argument + array_shift($v_arg_list); + $v_size--; + + // ----- Look for first arg + if ((is_integer($v_arg_list[0])) && ($v_arg_list[0] > 77000)) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Variable list of options detected"); + + // ----- Parse the options + $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options, + array (PCLZIP_OPT_REMOVE_PATH => 'optional', + PCLZIP_OPT_REMOVE_ALL_PATH => 'optional', + PCLZIP_OPT_ADD_PATH => 'optional', + PCLZIP_CB_PRE_ADD => 'optional', + PCLZIP_CB_POST_ADD => 'optional', + PCLZIP_OPT_NO_COMPRESSION => 'optional', + PCLZIP_OPT_COMMENT => 'optional', + PCLZIP_OPT_ADD_COMMENT => 'optional', + PCLZIP_OPT_PREPEND_COMMENT => 'optional' + //, PCLZIP_OPT_CRYPT => 'optional' + )); + if ($v_result != 1) { + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, 0); + return 0; + } + + // ----- Set the arguments + if (isset($v_options[PCLZIP_OPT_ADD_PATH])) { + $v_add_path = $v_options[PCLZIP_OPT_ADD_PATH]; + } + if (isset($v_options[PCLZIP_OPT_REMOVE_PATH])) { + $v_remove_path = $v_options[PCLZIP_OPT_REMOVE_PATH]; + } + if (isset($v_options[PCLZIP_OPT_REMOVE_ALL_PATH])) { + $v_remove_all_path = $v_options[PCLZIP_OPT_REMOVE_ALL_PATH]; + } + } + + // ----- Look for 2 args + // Here we need to support the first historic synopsis of the + // method. + else { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Static synopsis"); + + // ----- Get the first argument + $v_add_path = $v_arg_list[0]; + + // ----- Look for the optional second argument + if ($v_size == 2) { + $v_remove_path = $v_arg_list[1]; + } + else if ($v_size > 2) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid number / type of arguments"); + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, PclZip::errorCode(), PclZip::errorInfo()); + return 0; + } + } + } + + // ----- Trace + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "add_path='$v_add_path', remove_path='$v_remove_path', remove_all_path='".($v_remove_all_path?'true':'false')."'"); + + // ----- Look if the $p_filelist is really an array + $p_result_list = array(); + if (is_array($p_filelist)) + { + // ----- Call the create fct + $v_result = $this->privAdd($p_filelist, $p_result_list, $v_add_path, $v_remove_path, $v_remove_all_path, $v_options); + } + + // ----- Look if the $p_filelist is a string + else if (is_string($p_filelist)) + { + // ----- Create a list with the elements from the string + $v_list = explode(PCLZIP_SEPARATOR, $p_filelist); + + // ----- Call the create fct + $v_result = $this->privAdd($v_list, $p_result_list, $v_add_path, $v_remove_path, $v_remove_all_path, $v_options); + } + + // ----- Invalid variable + else + { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid variable type p_filelist"); + $v_result = PCLZIP_ERR_INVALID_PARAMETER; + } + + if ($v_result != 1) + { + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, 0); + return 0; + } + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $p_result_list); + return $p_result_list; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : listContent() + // Description : + // This public method, gives the list of the files and directories, with their + // properties. + // The properties of each entries in the list are (used also in other functions) : + // filename : Name of the file. For a create or add action it is the filename + // given by the user. For an extract function it is the filename + // of the extracted file. + // stored_filename : Name of the file / directory stored in the archive. + // size : Size of the stored file. + // compressed_size : Size of the file's data compressed in the archive + // (without the headers overhead) + // mtime : Last known modification date of the file (UNIX timestamp) + // comment : Comment associated with the file + // folder : true | false + // index : index of the file in the archive + // status : status of the action (depending of the action) : + // Values are : + // ok : OK ! + // filtered : the file / dir is not extracted (filtered by user) + // already_a_directory : the file can not be extracted because a + // directory with the same name already exists + // write_protected : the file can not be extracted because a file + // with the same name already exists and is + // write protected + // newer_exist : the file was not extracted because a newer file exists + // path_creation_fail : the file is not extracted because the folder + // does not exists and can not be created + // write_error : the file was not extracted because there was a + // error while writing the file + // read_error : the file was not extracted because there was a error + // while reading the file + // invalid_header : the file was not extracted because of an archive + // format error (bad file header) + // Note that each time a method can continue operating when there + // is an action error on a file, the error is only logged in the file status. + // Return Values : + // 0 on an unrecoverable failure, + // The list of the files in the archive. + // -------------------------------------------------------------------------------- + function listContent() + { + //--(MAGIC-PclTrace)--//PclTraceFctStart(__FILE__, __LINE__, 'PclZip::listContent', ""); + $v_result=1; + + // ----- Reset the error handler + $this->privErrorReset(); + + // ----- Check archive + if (!$this->privCheckFormat()) { + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, 0); + return(0); + } + + // ----- Call the extracting fct + $p_list = array(); + if (($v_result = $this->privList($p_list)) != 1) + { + unset($p_list); + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, 0, PclZip::errorInfo()); + return(0); + } + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $p_list); + return $p_list; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : + // extract($p_path="./", $p_remove_path="") + // extract([$p_option, $p_option_value, ...]) + // Description : + // This method supports two synopsis. The first one is historical. + // This method extract all the files / directories from the archive to the + // folder indicated in $p_path. + // If you want to ignore the 'root' part of path of the memorized files + // you can indicate this in the optional $p_remove_path parameter. + // By default, if a newer file with the same name already exists, the + // file is not extracted. + // + // If both PCLZIP_OPT_PATH and PCLZIP_OPT_ADD_PATH aoptions + // are used, the path indicated in PCLZIP_OPT_ADD_PATH is append + // at the end of the path value of PCLZIP_OPT_PATH. + // Parameters : + // $p_path : Path where the files and directories are to be extracted + // $p_remove_path : First part ('root' part) of the memorized path + // (if any similar) to remove while extracting. + // Options : + // PCLZIP_OPT_PATH : + // PCLZIP_OPT_ADD_PATH : + // PCLZIP_OPT_REMOVE_PATH : + // PCLZIP_OPT_REMOVE_ALL_PATH : + // PCLZIP_CB_PRE_EXTRACT : + // PCLZIP_CB_POST_EXTRACT : + // Return Values : + // 0 or a negative value on failure, + // The list of the extracted files, with a status of the action. + // (see PclZip::listContent() for list entry format) + // -------------------------------------------------------------------------------- + //function extract($p_path="./", $p_remove_path="") + function extract(/* options */) + { + //--(MAGIC-PclTrace)--//PclTraceFctStart(__FILE__, __LINE__, "PclZip::extract", ""); + $v_result=1; + + // ----- Reset the error handler + $this->privErrorReset(); + + // ----- Check archive + if (!$this->privCheckFormat()) { + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, 0); + return(0); + } + + // ----- Set default values + $v_options = array(); +// $v_path = "./"; + $v_path = ''; + $v_remove_path = ""; + $v_remove_all_path = false; + + // ----- Look for variable options arguments + $v_size = func_num_args(); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, "$v_size arguments passed to the method"); + + // ----- Default values for option + $v_options[PCLZIP_OPT_EXTRACT_AS_STRING] = FALSE; + + // ----- Look for arguments + if ($v_size > 0) { + // ----- Get the arguments + $v_arg_list = &func_get_args(); + + // ----- Look for first arg + if ((is_integer($v_arg_list[0])) && ($v_arg_list[0] > 77000)) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Variable list of options"); + + // ----- Parse the options + $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options, + array (PCLZIP_OPT_PATH => 'optional', + PCLZIP_OPT_REMOVE_PATH => 'optional', + PCLZIP_OPT_REMOVE_ALL_PATH => 'optional', + PCLZIP_OPT_ADD_PATH => 'optional', + PCLZIP_CB_PRE_EXTRACT => 'optional', + PCLZIP_CB_POST_EXTRACT => 'optional', + PCLZIP_OPT_SET_CHMOD => 'optional', + PCLZIP_OPT_BY_NAME => 'optional', + PCLZIP_OPT_BY_EREG => 'optional', + PCLZIP_OPT_BY_PREG => 'optional', + PCLZIP_OPT_BY_INDEX => 'optional', + PCLZIP_OPT_EXTRACT_AS_STRING => 'optional', + PCLZIP_OPT_EXTRACT_IN_OUTPUT => 'optional', + PCLZIP_OPT_REPLACE_NEWER => 'optional' + ,PCLZIP_OPT_STOP_ON_ERROR => 'optional' + )); + if ($v_result != 1) { + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, 0); + return 0; + } + + // ----- Set the arguments + if (isset($v_options[PCLZIP_OPT_PATH])) { + $v_path = $v_options[PCLZIP_OPT_PATH]; + } + if (isset($v_options[PCLZIP_OPT_REMOVE_PATH])) { + $v_remove_path = $v_options[PCLZIP_OPT_REMOVE_PATH]; + } + if (isset($v_options[PCLZIP_OPT_REMOVE_ALL_PATH])) { + $v_remove_all_path = $v_options[PCLZIP_OPT_REMOVE_ALL_PATH]; + } + if (isset($v_options[PCLZIP_OPT_ADD_PATH])) { + // ----- Check for '/' in last path char + if ((strlen($v_path) > 0) && (substr($v_path, -1) != '/')) { + $v_path .= '/'; + } + $v_path .= $v_options[PCLZIP_OPT_ADD_PATH]; + } + } + + // ----- Look for 2 args + // Here we need to support the first historic synopsis of the + // method. + else { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Static synopsis"); + + // ----- Get the first argument + $v_path = $v_arg_list[0]; + + // ----- Look for the optional second argument + if ($v_size == 2) { + $v_remove_path = $v_arg_list[1]; + } + else if ($v_size > 2) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid number / type of arguments"); + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, 0, PclZip::errorInfo()); + return 0; + } + } + } + + // ----- Trace + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "path='$v_path', remove_path='$v_remove_path', remove_all_path='".($v_remove_path?'true':'false')."'"); + + // ----- Call the extracting fct + $p_list = array(); + $v_result = $this->privExtractByRule($p_list, $v_path, $v_remove_path, + $v_remove_all_path, $v_options); + if ($v_result < 1) { + unset($p_list); + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, 0, PclZip::errorInfo()); + return(0); + } + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $p_list); + return $p_list; + } + // -------------------------------------------------------------------------------- + + + // -------------------------------------------------------------------------------- + // Function : + // extractByIndex($p_index, $p_path="./", $p_remove_path="") + // extractByIndex($p_index, [$p_option, $p_option_value, ...]) + // Description : + // This method supports two synopsis. The first one is historical. + // This method is doing a partial extract of the archive. + // The extracted files or folders are identified by their index in the + // archive (from 0 to n). + // Note that if the index identify a folder, only the folder entry is + // extracted, not all the files included in the archive. + // Parameters : + // $p_index : A single index (integer) or a string of indexes of files to + // extract. The form of the string is "0,4-6,8-12" with only numbers + // and '-' for range or ',' to separate ranges. No spaces or ';' + // are allowed. + // $p_path : Path where the files and directories are to be extracted + // $p_remove_path : First part ('root' part) of the memorized path + // (if any similar) to remove while extracting. + // Options : + // PCLZIP_OPT_PATH : + // PCLZIP_OPT_ADD_PATH : + // PCLZIP_OPT_REMOVE_PATH : + // PCLZIP_OPT_REMOVE_ALL_PATH : + // PCLZIP_OPT_EXTRACT_AS_STRING : The files are extracted as strings and + // not as files. + // The resulting content is in a new field 'content' in the file + // structure. + // This option must be used alone (any other options are ignored). + // PCLZIP_CB_PRE_EXTRACT : + // PCLZIP_CB_POST_EXTRACT : + // Return Values : + // 0 on failure, + // The list of the extracted files, with a status of the action. + // (see PclZip::listContent() for list entry format) + // -------------------------------------------------------------------------------- + function extractByIndex($p_index /* $options */) + { + //--(MAGIC-PclTrace)--//PclTraceFctStart(__FILE__, __LINE__, "PclZip::extractByIndex", "index='$p_index', ..."); + $v_result=1; + + // ----- Reset the error handler + $this->privErrorReset(); + + // ----- Check archive + if (!$this->privCheckFormat()) { + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, 0); + return(0); + } + + // ----- Set default values + $v_options = array(); +// $v_path = "./"; + $v_path = ''; + $v_remove_path = ""; + $v_remove_all_path = false; + + // ----- Look for variable options arguments + $v_size = func_num_args(); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, "$v_size arguments passed to the method"); + + // ----- Default values for option + $v_options[PCLZIP_OPT_EXTRACT_AS_STRING] = FALSE; + + // ----- Look for arguments + if ($v_size > 1) { + // ----- Get the arguments + $v_arg_list = &func_get_args(); + + // ----- Remove form the options list the first argument + array_shift($v_arg_list); + $v_size--; + + // ----- Look for first arg + if ((is_integer($v_arg_list[0])) && ($v_arg_list[0] > 77000)) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Variable list of options"); + + // ----- Parse the options + $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options, + array (PCLZIP_OPT_PATH => 'optional', + PCLZIP_OPT_REMOVE_PATH => 'optional', + PCLZIP_OPT_REMOVE_ALL_PATH => 'optional', + PCLZIP_OPT_EXTRACT_AS_STRING => 'optional', + PCLZIP_OPT_ADD_PATH => 'optional', + PCLZIP_CB_PRE_EXTRACT => 'optional', + PCLZIP_CB_POST_EXTRACT => 'optional', + PCLZIP_OPT_SET_CHMOD => 'optional', + PCLZIP_OPT_REPLACE_NEWER => 'optional' + ,PCLZIP_OPT_STOP_ON_ERROR => 'optional' + )); + if ($v_result != 1) { + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, 0); + return 0; + } + + // ----- Set the arguments + if (isset($v_options[PCLZIP_OPT_PATH])) { + $v_path = $v_options[PCLZIP_OPT_PATH]; + } + if (isset($v_options[PCLZIP_OPT_REMOVE_PATH])) { + $v_remove_path = $v_options[PCLZIP_OPT_REMOVE_PATH]; + } + if (isset($v_options[PCLZIP_OPT_REMOVE_ALL_PATH])) { + $v_remove_all_path = $v_options[PCLZIP_OPT_REMOVE_ALL_PATH]; + } + if (isset($v_options[PCLZIP_OPT_ADD_PATH])) { + // ----- Check for '/' in last path char + if ((strlen($v_path) > 0) && (substr($v_path, -1) != '/')) { + $v_path .= '/'; + } + $v_path .= $v_options[PCLZIP_OPT_ADD_PATH]; + } + if (!isset($v_options[PCLZIP_OPT_EXTRACT_AS_STRING])) { + $v_options[PCLZIP_OPT_EXTRACT_AS_STRING] = FALSE; + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, "Option PCLZIP_OPT_EXTRACT_AS_STRING not set."); + } + else { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, "Option PCLZIP_OPT_EXTRACT_AS_STRING set."); + } + } + + // ----- Look for 2 args + // Here we need to support the first historic synopsis of the + // method. + else { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Static synopsis"); + + // ----- Get the first argument + $v_path = $v_arg_list[0]; + + // ----- Look for the optional second argument + if ($v_size == 2) { + $v_remove_path = $v_arg_list[1]; + } + else if ($v_size > 2) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid number / type of arguments"); + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, PclZip::errorCode(), PclZip::errorInfo()); + return 0; + } + } + } + + // ----- Trace + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "index='$p_index', path='$v_path', remove_path='$v_remove_path', remove_all_path='".($v_remove_path?'true':'false')."'"); + + // ----- Trick + // Here I want to reuse extractByRule(), so I need to parse the $p_index + // with privParseOptions() + $v_arg_trick = array (PCLZIP_OPT_BY_INDEX, $p_index); + $v_options_trick = array(); + $v_result = $this->privParseOptions($v_arg_trick, sizeof($v_arg_trick), $v_options_trick, + array (PCLZIP_OPT_BY_INDEX => 'optional' )); + if ($v_result != 1) { + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, 0); + return 0; + } + $v_options[PCLZIP_OPT_BY_INDEX] = $v_options_trick[PCLZIP_OPT_BY_INDEX]; + + // ----- Call the extracting fct + if (($v_result = $this->privExtractByRule($p_list, $v_path, $v_remove_path, $v_remove_all_path, $v_options)) < 1) { + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, 0, PclZip::errorInfo()); + return(0); + } + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $p_list); + return $p_list; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : + // delete([$p_option, $p_option_value, ...]) + // Description : + // This method removes files from the archive. + // If no parameters are given, then all the archive is emptied. + // Parameters : + // None or optional arguments. + // Options : + // PCLZIP_OPT_BY_INDEX : + // PCLZIP_OPT_BY_NAME : + // PCLZIP_OPT_BY_EREG : + // PCLZIP_OPT_BY_PREG : + // Return Values : + // 0 on failure, + // The list of the files which are still present in the archive. + // (see PclZip::listContent() for list entry format) + // -------------------------------------------------------------------------------- + function delete(/* options */) + { + //--(MAGIC-PclTrace)--//PclTraceFctStart(__FILE__, __LINE__, "PclZip::delete", ""); + $v_result=1; + + // ----- Reset the error handler + $this->privErrorReset(); + + // ----- Check archive + if (!$this->privCheckFormat()) { + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, 0); + return(0); + } + + // ----- Set default values + $v_options = array(); + + // ----- Look for variable options arguments + $v_size = func_num_args(); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, "$v_size arguments passed to the method"); + + // ----- Look for arguments + if ($v_size > 0) { + // ----- Get the arguments + $v_arg_list = &func_get_args(); + + // ----- Parse the options + $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options, + array (PCLZIP_OPT_BY_NAME => 'optional', + PCLZIP_OPT_BY_EREG => 'optional', + PCLZIP_OPT_BY_PREG => 'optional', + PCLZIP_OPT_BY_INDEX => 'optional' )); + if ($v_result != 1) { + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, 0); + return 0; + } + } + + // ----- Magic quotes trick + $this->privDisableMagicQuotes(); + + // ----- Call the delete fct + $v_list = array(); + if (($v_result = $this->privDeleteByRule($v_list, $v_options)) != 1) { + $this->privSwapBackMagicQuotes(); + unset($v_list); + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, 0, PclZip::errorInfo()); + return(0); + } + + // ----- Magic quotes trick + $this->privSwapBackMagicQuotes(); + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_list); + return $v_list; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : deleteByIndex() + // Description : + // ***** Deprecated ***** + // delete(PCLZIP_OPT_BY_INDEX, $p_index) should be prefered. + // -------------------------------------------------------------------------------- + function deleteByIndex($p_index) + { + //--(MAGIC-PclTrace)--//PclTraceFctStart(__FILE__, __LINE__, "PclZip::deleteByIndex", "index='$p_index'"); + + $p_list = $this->delete(PCLZIP_OPT_BY_INDEX, $p_index); + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $p_list); + return $p_list; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : properties() + // Description : + // This method gives the properties of the archive. + // The properties are : + // nb : Number of files in the archive + // comment : Comment associated with the archive file + // status : not_exist, ok + // Parameters : + // None + // Return Values : + // 0 on failure, + // An array with the archive properties. + // -------------------------------------------------------------------------------- + function properties() + { + //--(MAGIC-PclTrace)--//PclTraceFctStart(__FILE__, __LINE__, "PclZip::properties", ""); + + // ----- Reset the error handler + $this->privErrorReset(); + + // ----- Magic quotes trick + $this->privDisableMagicQuotes(); + + // ----- Check archive + if (!$this->privCheckFormat()) { + $this->privSwapBackMagicQuotes(); + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, 0); + return(0); + } + + // ----- Default properties + $v_prop = array(); + $v_prop['comment'] = ''; + $v_prop['nb'] = 0; + $v_prop['status'] = 'not_exist'; + + // ----- Look if file exists + if (@is_file($this->zipname)) + { + // ----- Open the zip file + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Open file in binary read mode"); + if (($this->zip_fd = @fopen($this->zipname, 'rb')) == 0) + { + $this->privSwapBackMagicQuotes(); + + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open archive \''.$this->zipname.'\' in binary read mode'); + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, PclZip::errorCode(), 0); + return 0; + } + + // ----- Read the central directory informations + $v_central_dir = array(); + if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) + { + $this->privSwapBackMagicQuotes(); + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, 0); + return 0; + } + + // ----- Close the zip file + $this->privCloseFd(); + + // ----- Set the user attributes + $v_prop['comment'] = $v_central_dir['comment']; + $v_prop['nb'] = $v_central_dir['entries']; + $v_prop['status'] = 'ok'; + } + + // ----- Magic quotes trick + $this->privSwapBackMagicQuotes(); + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_prop); + return $v_prop; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : duplicate() + // Description : + // This method creates an archive by copying the content of an other one. If + // the archive already exist, it is replaced by the new one without any warning. + // Parameters : + // $p_archive : The filename of a valid archive, or + // a valid PclZip object. + // Return Values : + // 1 on success. + // 0 or a negative value on error (error code). + // -------------------------------------------------------------------------------- + function duplicate($p_archive) + { + //--(MAGIC-PclTrace)--//PclTraceFctStart(__FILE__, __LINE__, "PclZip::duplicate", ""); + $v_result = 1; + + // ----- Reset the error handler + $this->privErrorReset(); + + // ----- Look if the $p_archive is a PclZip object + if ((is_object($p_archive)) && (get_class($p_archive) == 'pclzip')) + { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "The parameter is valid PclZip object '".$p_archive->zipname."'"); + + // ----- Duplicate the archive + $v_result = $this->privDuplicate($p_archive->zipname); + } + + // ----- Look if the $p_archive is a string (so a filename) + else if (is_string($p_archive)) + { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "The parameter is a filename '$p_archive'"); + + // ----- Check that $p_archive is a valid zip file + // TBC : Should also check the archive format + if (!is_file($p_archive)) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_MISSING_FILE, "No file with filename '".$p_archive."'"); + $v_result = PCLZIP_ERR_MISSING_FILE; + } + else { + // ----- Duplicate the archive + $v_result = $this->privDuplicate($p_archive); + } + } + + // ----- Invalid variable + else + { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid variable type p_archive_to_add"); + $v_result = PCLZIP_ERR_INVALID_PARAMETER; + } + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : merge() + // Description : + // This method merge the $p_archive_to_add archive at the end of the current + // one ($this). + // If the archive ($this) does not exist, the merge becomes a duplicate. + // If the $p_archive_to_add archive does not exist, the merge is a success. + // Parameters : + // $p_archive_to_add : It can be directly the filename of a valid zip archive, + // or a PclZip object archive. + // Return Values : + // 1 on success, + // 0 or negative values on error (see below). + // -------------------------------------------------------------------------------- + function merge($p_archive_to_add) + { + //--(MAGIC-PclTrace)--//PclTraceFctStart(__FILE__, __LINE__, "PclZip::merge", ""); + $v_result = 1; + + // ----- Reset the error handler + $this->privErrorReset(); + + // ----- Check archive + if (!$this->privCheckFormat()) { + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, 0); + return(0); + } + + // ----- Look if the $p_archive_to_add is a PclZip object + if ((is_object($p_archive_to_add)) && (get_class($p_archive_to_add) == 'pclzip')) + { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "The parameter is valid PclZip object"); + + // ----- Merge the archive + $v_result = $this->privMerge($p_archive_to_add); + } + + // ----- Look if the $p_archive_to_add is a string (so a filename) + else if (is_string($p_archive_to_add)) + { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "The parameter is a filename"); + + // ----- Create a temporary archive + $v_object_archive = new PclZip($p_archive_to_add); + + // ----- Merge the archive + $v_result = $this->privMerge($v_object_archive); + } + + // ----- Invalid variable + else + { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid variable type p_archive_to_add"); + $v_result = PCLZIP_ERR_INVALID_PARAMETER; + } + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + // -------------------------------------------------------------------------------- + + + + // -------------------------------------------------------------------------------- + // Function : errorCode() + // Description : + // Parameters : + // -------------------------------------------------------------------------------- + function errorCode() + { + if (PCLZIP_ERROR_EXTERNAL == 1) { + return(PclErrorCode()); + } + else { + return($this->error_code); + } + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : errorName() + // Description : + // Parameters : + // -------------------------------------------------------------------------------- + function errorName($p_with_code=false) + { + $v_name = array ( PCLZIP_ERR_NO_ERROR => 'PCLZIP_ERR_NO_ERROR', + PCLZIP_ERR_WRITE_OPEN_FAIL => 'PCLZIP_ERR_WRITE_OPEN_FAIL', + PCLZIP_ERR_READ_OPEN_FAIL => 'PCLZIP_ERR_READ_OPEN_FAIL', + PCLZIP_ERR_INVALID_PARAMETER => 'PCLZIP_ERR_INVALID_PARAMETER', + PCLZIP_ERR_MISSING_FILE => 'PCLZIP_ERR_MISSING_FILE', + PCLZIP_ERR_FILENAME_TOO_LONG => 'PCLZIP_ERR_FILENAME_TOO_LONG', + PCLZIP_ERR_INVALID_ZIP => 'PCLZIP_ERR_INVALID_ZIP', + PCLZIP_ERR_BAD_EXTRACTED_FILE => 'PCLZIP_ERR_BAD_EXTRACTED_FILE', + PCLZIP_ERR_DIR_CREATE_FAIL => 'PCLZIP_ERR_DIR_CREATE_FAIL', + PCLZIP_ERR_BAD_EXTENSION => 'PCLZIP_ERR_BAD_EXTENSION', + PCLZIP_ERR_BAD_FORMAT => 'PCLZIP_ERR_BAD_FORMAT', + PCLZIP_ERR_DELETE_FILE_FAIL => 'PCLZIP_ERR_DELETE_FILE_FAIL', + PCLZIP_ERR_RENAME_FILE_FAIL => 'PCLZIP_ERR_RENAME_FILE_FAIL', + PCLZIP_ERR_BAD_CHECKSUM => 'PCLZIP_ERR_BAD_CHECKSUM', + PCLZIP_ERR_INVALID_ARCHIVE_ZIP => 'PCLZIP_ERR_INVALID_ARCHIVE_ZIP', + PCLZIP_ERR_MISSING_OPTION_VALUE => 'PCLZIP_ERR_MISSING_OPTION_VALUE', + PCLZIP_ERR_INVALID_OPTION_VALUE => 'PCLZIP_ERR_INVALID_OPTION_VALUE', + PCLZIP_ERR_UNSUPPORTED_COMPRESSION => 'PCLZIP_ERR_UNSUPPORTED_COMPRESSION', + PCLZIP_ERR_UNSUPPORTED_ENCRYPTION => 'PCLZIP_ERR_UNSUPPORTED_ENCRYPTION' ); + + if (isset($v_name[$this->error_code])) { + $v_value = $v_name[$this->error_code]; + } + else { + $v_value = 'NoName'; + } + + if ($p_with_code) { + return($v_value.' ('.$this->error_code.')'); + } + else { + return($v_value); + } + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : errorInfo() + // Description : + // Parameters : + // -------------------------------------------------------------------------------- + function errorInfo($p_full=false) + { + if (PCLZIP_ERROR_EXTERNAL == 1) { + return(PclErrorString()); + } + else { + if ($p_full) { + return($this->errorName(true)." : ".$this->error_string); + } + else { + return($this->error_string." [code ".$this->error_code."]"); + } + } + } + // -------------------------------------------------------------------------------- + + +// -------------------------------------------------------------------------------- +// ***** UNDER THIS LINE ARE DEFINED PRIVATE INTERNAL FUNCTIONS ***** +// ***** ***** +// ***** THESES FUNCTIONS MUST NOT BE USED DIRECTLY ***** +// -------------------------------------------------------------------------------- + + + + // -------------------------------------------------------------------------------- + // Function : privCheckFormat() + // Description : + // This method check that the archive exists and is a valid zip archive. + // Several level of check exists. (futur) + // Parameters : + // $p_level : Level of check. Default 0. + // 0 : Check the first bytes (magic codes) (default value)) + // 1 : 0 + Check the central directory (futur) + // 2 : 1 + Check each file header (futur) + // Return Values : + // true on success, + // false on error, the error code is set. + // -------------------------------------------------------------------------------- + function privCheckFormat($p_level=0) + { + //--(MAGIC-PclTrace)--//PclTraceFctStart(__FILE__, __LINE__, "PclZip::privCheckFormat", ""); + $v_result = true; + + // ----- Reset the file system cache + clearstatcache(); + + // ----- Reset the error handler + $this->privErrorReset(); + + // ----- Look if the file exits + if (!is_file($this->zipname)) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_MISSING_FILE, "Missing archive file '".$this->zipname."'"); + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, false, PclZip::errorInfo()); + return(false); + } + + // ----- Check that the file is readeable + if (!is_readable($this->zipname)) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, "Unable to read archive '".$this->zipname."'"); + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, false, PclZip::errorInfo()); + return(false); + } + + // ----- Check the magic code + // TBC + + // ----- Check the central header + // TBC + + // ----- Check each file header + // TBC + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privParseOptions() + // Description : + // This internal methods reads the variable list of arguments ($p_options_list, + // $p_size) and generate an array with the options and values ($v_result_list). + // $v_requested_options contains the options that can be present and those that + // must be present. + // $v_requested_options is an array, with the option value as key, and 'optional', + // or 'mandatory' as value. + // Parameters : + // See above. + // Return Values : + // 1 on success. + // 0 on failure. + // -------------------------------------------------------------------------------- + function privParseOptions(&$p_options_list, $p_size, &$v_result_list, $v_requested_options=false) + { + //--(MAGIC-PclTrace)--//PclTraceFctStart(__FILE__, __LINE__, "PclZip::privParseOptions", ""); + $v_result=1; + + // ----- Read the options + $i=0; + while ($i<$p_size) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, "Looking for table index $i, option = '".PclZipUtilOptionText($p_options_list[$i])."(".$p_options_list[$i].")'"); + + // ----- Check if the option is requested + if (!isset($v_requested_options[$p_options_list[$i]])) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid optional parameter '".$p_options_list[$i]."' for this method"); + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, PclZip::errorCode(), PclZip::errorInfo()); + return PclZip::errorCode(); + } + + // ----- Look for next option + switch ($p_options_list[$i]) { + // ----- Look for options that request a path value + case PCLZIP_OPT_PATH : + case PCLZIP_OPT_REMOVE_PATH : + case PCLZIP_OPT_ADD_PATH : + // ----- Check the number of parameters + if (($i+1) >= $p_size) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'"); + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, PclZip::errorCode(), PclZip::errorInfo()); + return PclZip::errorCode(); + } + + // ----- Get the value + $v_result_list[$p_options_list[$i]] = PclZipUtilTranslateWinPath($p_options_list[$i+1], false); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "".PclZipUtilOptionText($p_options_list[$i])." = '".$v_result_list[$p_options_list[$i]]."'"); + $i++; + break; + + // ----- Look for options that request an array of string for value + case PCLZIP_OPT_BY_NAME : + // ----- Check the number of parameters + if (($i+1) >= $p_size) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'"); + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, PclZip::errorCode(), PclZip::errorInfo()); + return PclZip::errorCode(); + } + + // ----- Get the value + if (is_string($p_options_list[$i+1])) { + $v_result_list[$p_options_list[$i]][0] = $p_options_list[$i+1]; + } + else if (is_array($p_options_list[$i+1])) { + $v_result_list[$p_options_list[$i]] = $p_options_list[$i+1]; + } + else { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Wrong parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'"); + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, PclZip::errorCode(), PclZip::errorInfo()); + return PclZip::errorCode(); + } + ////--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "".PclZipUtilOptionText($p_options_list[$i])." = '".$v_result_list[$p_options_list[$i]]."'"); + $i++; + break; + + // ----- Look for options that request an EREG or PREG expression + case PCLZIP_OPT_BY_EREG : + case PCLZIP_OPT_BY_PREG : + //case PCLZIP_OPT_CRYPT : + // ----- Check the number of parameters + if (($i+1) >= $p_size) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'"); + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, PclZip::errorCode(), PclZip::errorInfo()); + return PclZip::errorCode(); + } + + // ----- Get the value + if (is_string($p_options_list[$i+1])) { + $v_result_list[$p_options_list[$i]] = $p_options_list[$i+1]; + } + else { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Wrong parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'"); + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, PclZip::errorCode(), PclZip::errorInfo()); + return PclZip::errorCode(); + } + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "".PclZipUtilOptionText($p_options_list[$i])." = '".$v_result_list[$p_options_list[$i]]."'"); + $i++; + break; + + // ----- Look for options that takes a string + case PCLZIP_OPT_COMMENT : + case PCLZIP_OPT_ADD_COMMENT : + case PCLZIP_OPT_PREPEND_COMMENT : + // ----- Check the number of parameters + if (($i+1) >= $p_size) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, + "Missing parameter value for option '" + .PclZipUtilOptionText($p_options_list[$i]) + ."'"); + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, PclZip::errorCode(), PclZip::errorInfo()); + return PclZip::errorCode(); + } + + // ----- Get the value + if (is_string($p_options_list[$i+1])) { + $v_result_list[$p_options_list[$i]] = $p_options_list[$i+1]; + } + else { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, + "Wrong parameter value for option '" + .PclZipUtilOptionText($p_options_list[$i]) + ."'"); + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, PclZip::errorCode(), PclZip::errorInfo()); + return PclZip::errorCode(); + } + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "".PclZipUtilOptionText($p_options_list[$i])." = '".$v_result_list[$p_options_list[$i]]."'"); + $i++; + break; + + // ----- Look for options that request an array of index + case PCLZIP_OPT_BY_INDEX : + // ----- Check the number of parameters + if (($i+1) >= $p_size) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'"); + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, PclZip::errorCode(), PclZip::errorInfo()); + return PclZip::errorCode(); + } + + // ----- Get the value + $v_work_list = array(); + if (is_string($p_options_list[$i+1])) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, "Index value is a string '".$p_options_list[$i+1]."'"); + + // ----- Remove spaces + $p_options_list[$i+1] = strtr($p_options_list[$i+1], ' ', ''); + + // ----- Parse items + $v_work_list = explode(",", $p_options_list[$i+1]); + } + else if (is_integer($p_options_list[$i+1])) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, "Index value is an integer '".$p_options_list[$i+1]."'"); + $v_work_list[0] = $p_options_list[$i+1].'-'.$p_options_list[$i+1]; + } + else if (is_array($p_options_list[$i+1])) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, "Index value is an array"); + $v_work_list = $p_options_list[$i+1]; + } + else { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Value must be integer, string or array for option '".PclZipUtilOptionText($p_options_list[$i])."'"); + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, PclZip::errorCode(), PclZip::errorInfo()); + return PclZip::errorCode(); + } + + // ----- Reduce the index list + // each index item in the list must be a couple with a start and + // an end value : [0,3], [5-5], [8-10], ... + // ----- Check the format of each item + $v_sort_flag=false; + $v_sort_value=0; + for ($j=0; $j= $p_size) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'"); + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, PclZip::errorCode(), PclZip::errorInfo()); + return PclZip::errorCode(); + } + + // ----- Get the value + $v_result_list[$p_options_list[$i]] = $p_options_list[$i+1]; + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "".PclZipUtilOptionText($p_options_list[$i])." = '".$v_result_list[$p_options_list[$i]]."'"); + $i++; + break; + + // ----- Look for options that request a call-back + case PCLZIP_CB_PRE_EXTRACT : + case PCLZIP_CB_POST_EXTRACT : + case PCLZIP_CB_PRE_ADD : + case PCLZIP_CB_POST_ADD : + /* for futur use + case PCLZIP_CB_PRE_DELETE : + case PCLZIP_CB_POST_DELETE : + case PCLZIP_CB_PRE_LIST : + case PCLZIP_CB_POST_LIST : + */ + // ----- Check the number of parameters + if (($i+1) >= $p_size) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'"); + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, PclZip::errorCode(), PclZip::errorInfo()); + return PclZip::errorCode(); + } + + // ----- Get the value + $v_function_name = $p_options_list[$i+1]; + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "call-back ".PclZipUtilOptionText($p_options_list[$i])." = '".$v_function_name."'"); + + // ----- Check that the value is a valid existing function + if (!function_exists($v_function_name)) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Function '".$v_function_name."()' is not an existing function for option '".PclZipUtilOptionText($p_options_list[$i])."'"); + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, PclZip::errorCode(), PclZip::errorInfo()); + return PclZip::errorCode(); + } + + // ----- Set the attribute + $v_result_list[$p_options_list[$i]] = $v_function_name; + $i++; + break; + + default : + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, + "Unknown parameter '" + .$p_options_list[$i]."'"); + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, PclZip::errorCode(), PclZip::errorInfo()); + return PclZip::errorCode(); + } + + // ----- Next options + $i++; + } + + // ----- Look for mandatory options + if ($v_requested_options !== false) { + for ($key=reset($v_requested_options); $key=key($v_requested_options); $key=next($v_requested_options)) { + // ----- Look for mandatory option + if ($v_requested_options[$key] == 'mandatory') { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, "Detect a mandatory option : ".PclZipUtilOptionText($key)."(".$key.")"); + // ----- Look if present + if (!isset($v_result_list[$key])) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Missing mandatory parameter ".PclZipUtilOptionText($key)."(".$key.")"); + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, PclZip::errorCode(), PclZip::errorInfo()); + return PclZip::errorCode(); + } + } + } + } + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privCreate() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privCreate($p_list, &$p_result_list, $p_add_dir, $p_remove_dir, $p_remove_all_dir, &$p_options) + { + //--(MAGIC-PclTrace)--//PclTraceFctStart(__FILE__, __LINE__, "PclZip::privCreate", "list, result_list, add_dir='$p_add_dir', remove_dir='$p_remove_dir'"); + $v_result=1; + $v_list_detail = array(); + + // ----- Magic quotes trick + $this->privDisableMagicQuotes(); + + // ----- Open the file in write mode + if (($v_result = $this->privOpenFd('wb')) != 1) + { + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + + // ----- Add the list of files + $v_result = $this->privAddList($p_list, $p_result_list, $p_add_dir, $p_remove_dir, $p_remove_all_dir, $p_options); + + // ----- Close + $this->privCloseFd(); + + // ----- Magic quotes trick + $this->privSwapBackMagicQuotes(); + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privAdd() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privAdd($p_list, &$p_result_list, $p_add_dir, $p_remove_dir, $p_remove_all_dir, &$p_options) + { + //--(MAGIC-PclTrace)--//PclTraceFctStart(__FILE__, __LINE__, "PclZip::privAdd", "list, result_list, add_dir='$p_add_dir', remove_dir='$p_remove_dir'"); + $v_result=1; + $v_list_detail = array(); + + // ----- Look if the archive exists or is empty + if ((!is_file($this->zipname)) || (filesize($this->zipname) == 0)) + { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Archive does not exist, or is empty, create it."); + + // ----- Do a create + $v_result = $this->privCreate($p_list, $p_result_list, $p_add_dir, $p_remove_dir, $p_remove_all_dir, $p_options); + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + // ----- Magic quotes trick + $this->privDisableMagicQuotes(); + + // ----- Open the zip file + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Open file in binary read mode"); + if (($v_result=$this->privOpenFd('rb')) != 1) + { + // ----- Magic quotes trick + $this->privSwapBackMagicQuotes(); + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + + // ----- Read the central directory informations + $v_central_dir = array(); + if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) + { + $this->privCloseFd(); + $this->privSwapBackMagicQuotes(); + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + + // ----- Go to beginning of File + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 5, "Position in file : ".ftell($this->zip_fd)."'"); + @rewind($this->zip_fd); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 5, "Position in file : ".ftell($this->zip_fd)."'"); + + // ----- Creates a temporay file + $v_zip_temp_name = PCLZIP_TEMPORARY_DIR.uniqid('pclzip-').'.tmp'; + + // ----- Open the temporary file in write mode + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Open file in binary read mode"); + if (($v_zip_temp_fd = @fopen($v_zip_temp_name, 'wb')) == 0) + { + $this->privCloseFd(); + $this->privSwapBackMagicQuotes(); + + PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \''.$v_zip_temp_name.'\' in binary write mode'); + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, PclZip::errorCode(), PclZip::errorInfo()); + return PclZip::errorCode(); + } + + // ----- Copy the files from the archive to the temporary file + // TBC : Here I should better append the file and go back to erase the central dir + $v_size = $v_central_dir['offset']; + while ($v_size != 0) + { + $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, "Read $v_read_size bytes"); + $v_buffer = fread($this->zip_fd, $v_read_size); + @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size); + $v_size -= $v_read_size; + } + + // ----- Swap the file descriptor + // Here is a trick : I swap the temporary fd with the zip fd, in order to use + // the following methods on the temporary fil and not the real archive + $v_swap = $this->zip_fd; + $this->zip_fd = $v_zip_temp_fd; + $v_zip_temp_fd = $v_swap; + + // ----- Add the files + $v_header_list = array(); + if (($v_result = $this->privAddFileList($p_list, $v_header_list, $p_add_dir, $p_remove_dir, $p_remove_all_dir, $p_options)) != 1) + { + fclose($v_zip_temp_fd); + $this->privCloseFd(); + @unlink($v_zip_temp_name); + $this->privSwapBackMagicQuotes(); + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + + // ----- Store the offset of the central dir + $v_offset = @ftell($this->zip_fd); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, "New offset of central dir : $v_offset"); + + // ----- Copy the block of file headers from the old archive + $v_size = $v_central_dir['size']; + while ($v_size != 0) + { + $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, "Read $v_read_size bytes"); + $v_buffer = @fread($v_zip_temp_fd, $v_read_size); + @fwrite($this->zip_fd, $v_buffer, $v_read_size); + $v_size -= $v_read_size; + } + + // ----- Create the Central Dir files header + for ($i=0, $v_count=0; $iprivWriteCentralFileHeader($v_header_list[$i])) != 1) { + fclose($v_zip_temp_fd); + $this->privCloseFd(); + @unlink($v_zip_temp_name); + $this->privSwapBackMagicQuotes(); + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + $v_count++; + } + + // ----- Transform the header to a 'usable' info + $this->privConvertHeader2FileInfo($v_header_list[$i], $p_result_list[$i]); + } + + // ----- Zip file comment + $v_comment = $v_central_dir['comment']; + if (isset($p_options[PCLZIP_OPT_COMMENT])) { + $v_comment = $p_options[PCLZIP_OPT_COMMENT]; + } + if (isset($p_options[PCLZIP_OPT_ADD_COMMENT])) { + $v_comment = $v_comment.$p_options[PCLZIP_OPT_ADD_COMMENT]; + } + if (isset($p_options[PCLZIP_OPT_PREPEND_COMMENT])) { + $v_comment = $p_options[PCLZIP_OPT_PREPEND_COMMENT].$v_comment; + } + + // ----- Calculate the size of the central header + $v_size = @ftell($this->zip_fd)-$v_offset; + + // ----- Create the central dir footer + if (($v_result = $this->privWriteCentralHeader($v_count+$v_central_dir['entries'], $v_size, $v_offset, $v_comment)) != 1) + { + // ----- Reset the file list + unset($v_header_list); + $this->privSwapBackMagicQuotes(); + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + + // ----- Swap back the file descriptor + $v_swap = $this->zip_fd; + $this->zip_fd = $v_zip_temp_fd; + $v_zip_temp_fd = $v_swap; + + // ----- Close + $this->privCloseFd(); + + // ----- Close the temporary file + @fclose($v_zip_temp_fd); + + // ----- Magic quotes trick + $this->privSwapBackMagicQuotes(); + + // ----- Delete the zip file + // TBC : I should test the result ... + @unlink($this->zipname); + + // ----- Rename the temporary file + // TBC : I should test the result ... + //@rename($v_zip_temp_name, $this->zipname); + PclZipUtilRename($v_zip_temp_name, $this->zipname); + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privOpenFd() + // Description : + // Parameters : + // -------------------------------------------------------------------------------- + function privOpenFd($p_mode) + { + //--(MAGIC-PclTrace)--//PclTraceFctStart(__FILE__, __LINE__, "PclZip::privOpenFd", 'mode='.$p_mode); + $v_result=1; + + // ----- Look if already open + if ($this->zip_fd != 0) + { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Zip file \''.$this->zipname.'\' already open'); + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, PclZip::errorCode(), PclZip::errorInfo()); + return PclZip::errorCode(); + } + + // ----- Open the zip file + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, 'Open file in '.$p_mode.' mode'); + if (($this->zip_fd = @fopen($this->zipname, $p_mode)) == 0) + { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open archive \''.$this->zipname.'\' in '.$p_mode.' mode'); + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, PclZip::errorCode(), PclZip::errorInfo()); + return PclZip::errorCode(); + } + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privCloseFd() + // Description : + // Parameters : + // -------------------------------------------------------------------------------- + function privCloseFd() + { + //--(MAGIC-PclTrace)--//PclTraceFctStart(__FILE__, __LINE__, "PclZip::privCloseFd", ""); + $v_result=1; + + if ($this->zip_fd != 0) + @fclose($this->zip_fd); + $this->zip_fd = 0; + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privAddList() + // Description : + // $p_add_dir and $p_remove_dir will give the ability to memorize a path which is + // different from the real path of the file. This is usefull if you want to have PclTar + // running in any directory, and memorize relative path from an other directory. + // Parameters : + // $p_list : An array containing the file or directory names to add in the tar + // $p_result_list : list of added files with their properties (specially the status field) + // $p_add_dir : Path to add in the filename path archived + // $p_remove_dir : Path to remove in the filename path archived + // Return Values : + // -------------------------------------------------------------------------------- + function privAddList($p_list, &$p_result_list, $p_add_dir, $p_remove_dir, $p_remove_all_dir, &$p_options) + { + //--(MAGIC-PclTrace)--//PclTraceFctStart(__FILE__, __LINE__, "PclZip::privAddList", "list, add_dir='$p_add_dir', remove_dir='$p_remove_dir'"); + $v_result=1; + + // ----- Add the files + $v_header_list = array(); + if (($v_result = $this->privAddFileList($p_list, $v_header_list, $p_add_dir, $p_remove_dir, $p_remove_all_dir, $p_options)) != 1) + { + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + + // ----- Store the offset of the central dir + $v_offset = @ftell($this->zip_fd); + + // ----- Create the Central Dir files header + for ($i=0,$v_count=0; $iprivWriteCentralFileHeader($v_header_list[$i])) != 1) { + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + $v_count++; + } + + // ----- Transform the header to a 'usable' info + $this->privConvertHeader2FileInfo($v_header_list[$i], $p_result_list[$i]); + } + + // ----- Zip file comment + $v_comment = ''; + if (isset($p_options[PCLZIP_OPT_COMMENT])) { + $v_comment = $p_options[PCLZIP_OPT_COMMENT]; + } + + // ----- Calculate the size of the central header + $v_size = @ftell($this->zip_fd)-$v_offset; + + // ----- Create the central dir footer + if (($v_result = $this->privWriteCentralHeader($v_count, $v_size, $v_offset, $v_comment)) != 1) + { + // ----- Reset the file list + unset($v_header_list); + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privAddFileList() + // Description : + // $p_add_dir and $p_remove_dir will give the ability to memorize a path which is + // different from the real path of the file. This is usefull if you want to + // run the lib in any directory, and memorize relative path from an other directory. + // Parameters : + // $p_list : An array containing the file or directory names to add in the tar + // $p_result_list : list of added files with their properties (specially the status field) + // $p_add_dir : Path to add in the filename path archived + // $p_remove_dir : Path to remove in the filename path archived + // Return Values : + // -------------------------------------------------------------------------------- + function privAddFileList($p_list, &$p_result_list, $p_add_dir, $p_remove_dir, $p_remove_all_dir, &$p_options) + { + //--(MAGIC-PclTrace)--//PclTraceFctStart(__FILE__, __LINE__, "PclZip::privAddFileList", "list, add_dir='$p_add_dir', remove_dir='$p_remove_dir'"); + $v_result=1; + $v_header = array(); + + // ----- Recuperate the current number of elt in list + $v_nb = sizeof($p_result_list); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, "Before add, list have $v_nb elements"); + + // ----- Loop on the files + for ($j=0; ($jprivAddFile($p_filename, $v_header, $p_add_dir, $p_remove_dir, $p_remove_all_dir, $p_options)) != 1) + { + // ----- Return status + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + + // ----- Store the file infos + $p_result_list[$v_nb++] = $v_header; + } + + // ----- Look for directory + if (@is_dir($p_filename)) + { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "$p_filename is a directory"); + + // ----- Look for path + if ($p_filename != ".") + $v_path = $p_filename."/"; + else + $v_path = ""; + + // ----- Read the directory for files and sub-directories + if ($p_hdir = @opendir($p_filename)) { +// $p_hitem = @readdir($p_hdir); // '.' directory +// $p_hitem = @readdir($p_hdir); // '..' directory + while (($p_hitem = @readdir($p_hdir)) !== false) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "Looking for $p_hitem in the directory"); + + // ----- Skip '.' and '..' + if (($p_hitem == '.') || ($p_hitem == '..')) { + continue; + } + + // ----- Look for a file + if (@is_file($v_path.$p_hitem)) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, "Add the file '".$v_path.$p_hitem."'"); + + // ----- Add the file + if (($v_result = $this->privAddFile($v_path.$p_hitem, $v_header, $p_add_dir, $p_remove_dir, $p_remove_all_dir, $p_options)) != 1) { + // ----- Return status + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + + // ----- Store the file infos + $p_result_list[$v_nb++] = $v_header; + } + + // ----- Recursive call to privAddFileList() + else if (@is_dir($v_path.$p_hitem)) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, "Add the directory '".$v_path.$p_hitem."'"); + + // ----- Need an array as parameter + $p_temp_list[0] = $v_path.$p_hitem; + $v_result = $this->privAddFileList($p_temp_list, $p_result_list, + $p_add_dir, $p_remove_dir, + $p_remove_all_dir, $p_options); + + // ----- Update the number of elements of the list + $v_nb = sizeof($p_result_list); + } + + // ----- Unsupported file types + else { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, "Unsupported file type"); + } + } + @closedir($p_hdir); + } + + // ----- Free memory for the recursive loop + unset($p_temp_list); + unset($p_hdir); + unset($p_hitem); + } + } + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, "After add, list have $v_nb elements"); + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privAddFile() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privAddFile($p_filename, &$p_header, $p_add_dir, $p_remove_dir, $p_remove_all_dir, &$p_options) + { + //--(MAGIC-PclTrace)--//PclTraceFctStart(__FILE__, __LINE__, "PclZip::privAddFile", "filename='$p_filename', add_dir='$p_add_dir', remove_dir='$p_remove_dir'"); + $v_result=1; + + if ($p_filename == "") + { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid file list parameter (invalid or empty list)"); + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, PclZip::errorCode(), PclZip::errorInfo()); + return PclZip::errorCode(); + } + + // ----- Calculate the stored filename + $v_stored_filename = $p_filename; + + // ----- Look for all path to remove + if ($p_remove_all_dir) { + $v_stored_filename = basename($p_filename); + } + // ----- Look for partial path remove + else if ($p_remove_dir != "") + { + if (substr($p_remove_dir, -1) != '/') + $p_remove_dir .= "/"; + + if ((substr($p_filename, 0, 2) == "./") || (substr($p_remove_dir, 0, 2) == "./")) + { + if ((substr($p_filename, 0, 2) == "./") && (substr($p_remove_dir, 0, 2) != "./")) + $p_remove_dir = "./".$p_remove_dir; + if ((substr($p_filename, 0, 2) != "./") && (substr($p_remove_dir, 0, 2) == "./")) + $p_remove_dir = substr($p_remove_dir, 2); + } + + $v_compare = PclZipUtilPathInclusion($p_remove_dir, $p_filename); + if ($v_compare > 0) +// if (substr($p_filename, 0, strlen($p_remove_dir)) == $p_remove_dir) + { + + if ($v_compare == 2) { + $v_stored_filename = ""; + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, "Path to remove is the current folder"); + } + else { + $v_stored_filename = substr($p_filename, strlen($p_remove_dir)); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, "Remove path '$p_remove_dir' in file '$p_filename' = '$v_stored_filename'"); + } + } + } + // ----- Look for path to add + if ($p_add_dir != "") + { + if (substr($p_add_dir, -1) == "/") + $v_stored_filename = $p_add_dir.$v_stored_filename; + else + $v_stored_filename = $p_add_dir."/".$v_stored_filename; + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Add path '$p_add_dir' in file '$p_filename' = '$v_stored_filename'"); + } + + // ----- Filename (reduce the path of stored name) + $v_stored_filename = PclZipUtilPathReduction($v_stored_filename); + + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "Filename (reduced) '$v_stored_filename', strlen ".strlen($v_stored_filename)); + + // ----- Set the file properties + clearstatcache(); + $p_header['version'] = 20; + $p_header['version_extracted'] = 10; + $p_header['flag'] = 0; + $p_header['compression'] = 0; + $p_header['mtime'] = filemtime($p_filename); + $p_header['crc'] = 0; + $p_header['compressed_size'] = 0; + $p_header['size'] = filesize($p_filename); + $p_header['filename_len'] = strlen($p_filename); + $p_header['extra_len'] = 0; + $p_header['comment_len'] = 0; + $p_header['disk'] = 0; + $p_header['internal'] = 0; +// $p_header['external'] = (is_file($p_filename)?0xFE49FFE0:0x41FF0010); + $p_header['external'] = (is_file($p_filename)?0x00000000:0x00000010); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 5, "Header external extension '".sprintf("0x%X",$p_header['external'])."'"); + $p_header['offset'] = 0; + $p_header['filename'] = $p_filename; + $p_header['stored_filename'] = $v_stored_filename; + $p_header['extra'] = ''; + $p_header['comment'] = ''; + $p_header['status'] = 'ok'; + $p_header['index'] = -1; + + + // ----- Look for pre-add callback + if (isset($p_options[PCLZIP_CB_PRE_ADD])) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "A pre-callback '".$p_options[PCLZIP_CB_PRE_ADD]."()') is defined for the extraction"); + + // ----- Generate a local information + $v_local_header = array(); + $this->privConvertHeader2FileInfo($p_header, $v_local_header); + + // ----- Call the callback + // Here I do not use call_user_func() because I need to send a reference to the + // header. + eval('$v_result = '.$p_options[PCLZIP_CB_PRE_ADD].'(PCLZIP_CB_PRE_ADD, $v_local_header);'); + if ($v_result == 0) { + // ----- Change the file status + $p_header['status'] = "skipped"; + $v_result = 1; + } + + // ----- Update the informations + // Only some fields can be modified + if ($p_header['stored_filename'] != $v_local_header['stored_filename']) { + $p_header['stored_filename'] = PclZipUtilPathReduction($v_local_header['stored_filename']); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "New stored filename is '".$p_header['stored_filename']."'"); + } + } + + // ----- Look for empty stored filename + if ($p_header['stored_filename'] == "") { + $p_header['status'] = "filtered"; + } + + // ----- Check the path length + if (strlen($p_header['stored_filename']) > 0xFF) { + $p_header['status'] = 'filename_too_long'; + } + + // ----- Look if no error, or file not skipped + if ($p_header['status'] == 'ok') { + + // ----- Look for a file + if (is_file($p_filename)) + { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "'".$p_filename."' is a file"); + // ----- Open the source file + if (($v_file = @fopen($p_filename, "rb")) == 0) { + PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, "Unable to open file '$p_filename' in binary read mode"); + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, PclZip::errorCode(), PclZip::errorInfo()); + return PclZip::errorCode(); + } + + if ($p_options[PCLZIP_OPT_NO_COMPRESSION]) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "File will not be compressed"); + // ----- Read the file content + $v_content_compressed = @fread($v_file, $p_header['size']); + + // ----- Calculate the CRC + $p_header['crc'] = @crc32($v_content_compressed); + + // ----- Set header parameters + $p_header['compressed_size'] = $p_header['size']; + $p_header['compression'] = 0; + } + else { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "File will be compressed"); + // ----- Read the file content + $v_content = @fread($v_file, $p_header['size']); + + // ----- Calculate the CRC + $p_header['crc'] = @crc32($v_content); + + // ----- Compress the file + $v_content_compressed = @gzdeflate($v_content); + + // ----- Set header parameters + $p_header['compressed_size'] = strlen($v_content_compressed); + $p_header['compression'] = 8; + } + + // ----- Look for encryption + /* + if ((isset($p_options[PCLZIP_OPT_CRYPT])) + && ($p_options[PCLZIP_OPT_CRYPT] != "")) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "File need to be crypted ...."); + + // Should be a random header + $v_header = 'xxxxxxxxxxxx'; + $v_content_compressed = PclZipUtilZipEncrypt($v_content_compressed, + $p_header['compressed_size'], + $v_header, + $p_header['crc'], + "test"); + + $p_header['compressed_size'] += 12; + $p_header['flag'] = 1; + + // ----- Add the header to the data + $v_content_compressed = $v_header.$v_content_compressed; + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "Size after header : ".strlen($v_content_compressed).""); + } + */ + + // ----- Call the header generation + if (($v_result = $this->privWriteFileHeader($p_header)) != 1) { + @fclose($v_file); + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + + // ----- Write the compressed (or not) content + /* Try to speed up the code + $v_binary_data = pack('a'.$p_header['compressed_size'], + $v_content_compressed); + @fwrite($this->zip_fd, $v_binary_data, $p_header['compressed_size']); + */ + @fwrite($this->zip_fd, + $v_content_compressed, $p_header['compressed_size']); + + // ----- Close the file + @fclose($v_file); + } + + // ----- Look for a directory + else { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "'".$p_filename."' is a folder"); + // ----- Look for directory last '/' + if (@substr($p_header['stored_filename'], -1) != '/') { + $p_header['stored_filename'] .= '/'; + } + + // ----- Set the file properties + $p_header['size'] = 0; + //$p_header['external'] = 0x41FF0010; // Value for a folder : to be checked + $p_header['external'] = 0x00000010; // Value for a folder : to be checked + + // ----- Call the header generation + if (($v_result = $this->privWriteFileHeader($p_header)) != 1) + { + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + } + } + + // ----- Look for pre-add callback + if (isset($p_options[PCLZIP_CB_POST_ADD])) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "A post-callback '".$p_options[PCLZIP_CB_POST_ADD]."()') is defined for the extraction"); + + // ----- Generate a local information + $v_local_header = array(); + $this->privConvertHeader2FileInfo($p_header, $v_local_header); + + // ----- Call the callback + // Here I do not use call_user_func() because I need to send a reference to the + // header. + eval('$v_result = '.$p_options[PCLZIP_CB_POST_ADD].'(PCLZIP_CB_POST_ADD, $v_local_header);'); + if ($v_result == 0) { + // ----- Ignored + $v_result = 1; + } + + // ----- Update the informations + // Nothing can be modified + } + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privWriteFileHeader() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privWriteFileHeader(&$p_header) + { + //--(MAGIC-PclTrace)--//PclTraceFctStart(__FILE__, __LINE__, "PclZip::privWriteFileHeader", 'file="'.$p_header['filename'].'", stored as "'.$p_header['stored_filename'].'"'); + $v_result=1; + + // TBC + //for(reset($p_header); $key = key($p_header); next($p_header)) { + // //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "header[$key] = ".$p_header[$key]); + //} + + // ----- Store the offset position of the file + $p_header['offset'] = ftell($this->zip_fd); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, 'File offset of the header :'.$p_header['offset']); + + // ----- Transform UNIX mtime to DOS format mdate/mtime + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, 'Date : \''.date("d/m/y H:i:s", $p_header['mtime']).'\''); + $v_date = getdate($p_header['mtime']); + $v_mtime = ($v_date['hours']<<11) + ($v_date['minutes']<<5) + $v_date['seconds']/2; + $v_mdate = (($v_date['year']-1980)<<9) + ($v_date['mon']<<5) + $v_date['mday']; + + // ----- Packed data + $v_binary_data = pack("VvvvvvVVVvv", 0x04034b50, + $p_header['version_extracted'], $p_header['flag'], + $p_header['compression'], $v_mtime, $v_mdate, + $p_header['crc'], $p_header['compressed_size'], + $p_header['size'], + strlen($p_header['stored_filename']), + $p_header['extra_len']); + + // ----- Write the first 148 bytes of the header in the archive + fputs($this->zip_fd, $v_binary_data, 30); + + // ----- Write the variable fields + if (strlen($p_header['stored_filename']) != 0) + { + fputs($this->zip_fd, $p_header['stored_filename'], strlen($p_header['stored_filename'])); + } + if ($p_header['extra_len'] != 0) + { + fputs($this->zip_fd, $p_header['extra'], $p_header['extra_len']); + } + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privWriteCentralFileHeader() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privWriteCentralFileHeader(&$p_header) + { + //--(MAGIC-PclTrace)--//PclTraceFctStart(__FILE__, __LINE__, "PclZip::privWriteCentralFileHeader", 'file="'.$p_header['filename'].'", stored as "'.$p_header['stored_filename'].'"'); + $v_result=1; + + // TBC + //for(reset($p_header); $key = key($p_header); next($p_header)) { + // //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "header[$key] = ".$p_header[$key]); + //} + + // ----- Transform UNIX mtime to DOS format mdate/mtime + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, 'Date : \''.date("d/m/y H:i:s", $p_header['mtime']).'\''); + $v_date = getdate($p_header['mtime']); + $v_mtime = ($v_date['hours']<<11) + ($v_date['minutes']<<5) + $v_date['seconds']/2; + $v_mdate = (($v_date['year']-1980)<<9) + ($v_date['mon']<<5) + $v_date['mday']; + + // ----- Packed data + $v_binary_data = pack("VvvvvvvVVVvvvvvVV", 0x02014b50, + $p_header['version'], $p_header['version_extracted'], + $p_header['flag'], $p_header['compression'], + $v_mtime, $v_mdate, $p_header['crc'], + $p_header['compressed_size'], $p_header['size'], + strlen($p_header['stored_filename']), + $p_header['extra_len'], $p_header['comment_len'], + $p_header['disk'], $p_header['internal'], + $p_header['external'], $p_header['offset']); + + // ----- Write the 42 bytes of the header in the zip file + fputs($this->zip_fd, $v_binary_data, 46); + + // ----- Write the variable fields + if (strlen($p_header['stored_filename']) != 0) + { + fputs($this->zip_fd, $p_header['stored_filename'], strlen($p_header['stored_filename'])); + } + if ($p_header['extra_len'] != 0) + { + fputs($this->zip_fd, $p_header['extra'], $p_header['extra_len']); + } + if ($p_header['comment_len'] != 0) + { + fputs($this->zip_fd, $p_header['comment'], $p_header['comment_len']); + } + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privWriteCentralHeader() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privWriteCentralHeader($p_nb_entries, $p_size, $p_offset, $p_comment) + { + //--(MAGIC-PclTrace)--//PclTraceFctStart(__FILE__, __LINE__, "PclZip::privWriteCentralHeader", 'nb_entries='.$p_nb_entries.', size='.$p_size.', offset='.$p_offset.', comment="'.$p_comment.'"'); + $v_result=1; + + // ----- Packed data + $v_binary_data = pack("VvvvvVVv", 0x06054b50, 0, 0, $p_nb_entries, + $p_nb_entries, $p_size, + $p_offset, strlen($p_comment)); + + // ----- Write the 22 bytes of the header in the zip file + fputs($this->zip_fd, $v_binary_data, 22); + + // ----- Write the variable fields + if (strlen($p_comment) != 0) + { + fputs($this->zip_fd, $p_comment, strlen($p_comment)); + } + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privList() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privList(&$p_list) + { + //--(MAGIC-PclTrace)--//PclTraceFctStart(__FILE__, __LINE__, "PclZip::privList", "list"); + $v_result=1; + + // ----- Magic quotes trick + $this->privDisableMagicQuotes(); + + // ----- Open the zip file + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Open file in binary read mode"); + if (($this->zip_fd = @fopen($this->zipname, 'rb')) == 0) + { + // ----- Magic quotes trick + $this->privSwapBackMagicQuotes(); + + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open archive \''.$this->zipname.'\' in binary read mode'); + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, PclZip::errorCode(), PclZip::errorInfo()); + return PclZip::errorCode(); + } + + // ----- Read the central directory informations + $v_central_dir = array(); + if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) + { + $this->privSwapBackMagicQuotes(); + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + + // ----- Go to beginning of Central Dir + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Offset : ".$v_central_dir['offset']."'"); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Position in file : ".ftell($this->zip_fd)."'"); + @rewind($this->zip_fd); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Position in file : ".ftell($this->zip_fd)."'"); + if (@fseek($this->zip_fd, $v_central_dir['offset'])) + { + $this->privSwapBackMagicQuotes(); + + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size'); + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, PclZip::errorCode(), PclZip::errorInfo()); + return PclZip::errorCode(); + } + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Position in file : ".ftell($this->zip_fd)."'"); + + // ----- Read each entry + for ($i=0; $i<$v_central_dir['entries']; $i++) + { + // ----- Read the file header + if (($v_result = $this->privReadCentralFileHeader($v_header)) != 1) + { + $this->privSwapBackMagicQuotes(); + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + $v_header['index'] = $i; + + // ----- Get the only interesting attributes + $this->privConvertHeader2FileInfo($v_header, $p_list[$i]); + unset($v_header); + } + + // ----- Close the zip file + $this->privCloseFd(); + + // ----- Magic quotes trick + $this->privSwapBackMagicQuotes(); + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privConvertHeader2FileInfo() + // Description : + // This function takes the file informations from the central directory + // entries and extract the interesting parameters that will be given back. + // The resulting file infos are set in the array $p_info + // $p_info['filename'] : Filename with full path. Given by user (add), + // extracted in the filesystem (extract). + // $p_info['stored_filename'] : Stored filename in the archive. + // $p_info['size'] = Size of the file. + // $p_info['compressed_size'] = Compressed size of the file. + // $p_info['mtime'] = Last modification date of the file. + // $p_info['comment'] = Comment associated with the file. + // $p_info['folder'] = true/false : indicates if the entry is a folder or not. + // $p_info['status'] = status of the action on the file. + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privConvertHeader2FileInfo($p_header, &$p_info) + { + //--(MAGIC-PclTrace)--//PclTraceFctStart(__FILE__, __LINE__, "PclZip::privConvertHeader2FileInfo", "Filename='".$p_header['filename']."'"); + $v_result=1; + + // ----- Get the interesting attributes + $p_info['filename'] = $p_header['filename']; + $p_info['stored_filename'] = $p_header['stored_filename']; + $p_info['size'] = $p_header['size']; + $p_info['compressed_size'] = $p_header['compressed_size']; + $p_info['mtime'] = $p_header['mtime']; + $p_info['comment'] = $p_header['comment']; + $p_info['folder'] = (($p_header['external']&0x00000010)==0x00000010); + $p_info['index'] = $p_header['index']; + $p_info['status'] = $p_header['status']; + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privExtractByRule() + // Description : + // Extract a file or directory depending of rules (by index, by name, ...) + // Parameters : + // $p_file_list : An array where will be placed the properties of each + // extracted file + // $p_path : Path to add while writing the extracted files + // $p_remove_path : Path to remove (from the file memorized path) while writing the + // extracted files. If the path does not match the file path, + // the file is extracted with its memorized path. + // $p_remove_path does not apply to 'list' mode. + // $p_path and $p_remove_path are commulative. + // Return Values : + // 1 on success,0 or less on error (see error code list) + // -------------------------------------------------------------------------------- + function privExtractByRule(&$p_file_list, $p_path, $p_remove_path, $p_remove_all_path, &$p_options) + { + //--(MAGIC-PclTrace)--//PclTraceFctStart(__FILE__, __LINE__, "PclZip::privExtractByRule", "path='$p_path', remove_path='$p_remove_path', remove_all_path='".($p_remove_all_path?'true':'false')."'"); + $v_result=1; + + // ----- Magic quotes trick + $this->privDisableMagicQuotes(); + + // ----- Check the path + if ( ($p_path == "") + || ( (substr($p_path, 0, 1) != "/") + && (substr($p_path, 0, 3) != "../") + && (substr($p_path,1,2)!=":/"))) + $p_path = "./".$p_path; + + // ----- Reduce the path last (and duplicated) '/' + if (($p_path != "./") && ($p_path != "/")) + { + // ----- Look for the path end '/' + while (substr($p_path, -1) == "/") + { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Destination path [$p_path] ends by '/'"); + $p_path = substr($p_path, 0, strlen($p_path)-1); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Modified to [$p_path]"); + } + } + + // ----- Look for path to remove format (should end by /) + if (($p_remove_path != "") && (substr($p_remove_path, -1) != '/')) + { + $p_remove_path .= '/'; + } + $p_remove_path_size = strlen($p_remove_path); + + // ----- Open the zip file + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Open file in binary read mode"); + if (($v_result = $this->privOpenFd('rb')) != 1) + { + $this->privSwapBackMagicQuotes(); + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + + // ----- Read the central directory informations + $v_central_dir = array(); + if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) + { + // ----- Close the zip file + $this->privCloseFd(); + $this->privSwapBackMagicQuotes(); + + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + + // ----- Start at beginning of Central Dir + $v_pos_entry = $v_central_dir['offset']; + + // ----- Read each entry + $j_start = 0; + for ($i=0, $v_nb_extracted=0; $i<$v_central_dir['entries']; $i++) + { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Read next file header entry : '$i'"); + + // ----- Read next Central dir entry + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, "Position before rewind : ".ftell($this->zip_fd)."'"); + @rewind($this->zip_fd); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, "Position after rewind : ".ftell($this->zip_fd)."'"); + if (@fseek($this->zip_fd, $v_pos_entry)) + { + // ----- Close the zip file + $this->privCloseFd(); + $this->privSwapBackMagicQuotes(); + + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size'); + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, PclZip::errorCode(), PclZip::errorInfo()); + return PclZip::errorCode(); + } + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Position after fseek : ".ftell($this->zip_fd)."'"); + + // ----- Read the file header + $v_header = array(); + if (($v_result = $this->privReadCentralFileHeader($v_header)) != 1) + { + // ----- Close the zip file + $this->privCloseFd(); + $this->privSwapBackMagicQuotes(); + + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + + // ----- Store the index + $v_header['index'] = $i; + + // ----- Store the file position + $v_pos_entry = ftell($this->zip_fd); + + // ----- Look for the specific extract rules + $v_extract = false; + + // ----- Look for extract by name rule + if ( (isset($p_options[PCLZIP_OPT_BY_NAME])) + && ($p_options[PCLZIP_OPT_BY_NAME] != 0)) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Extract with rule 'ByName'"); + + // ----- Look if the filename is in the list + for ($j=0; ($j strlen($p_options[PCLZIP_OPT_BY_NAME][$j])) + && (substr($v_header['stored_filename'], 0, strlen($p_options[PCLZIP_OPT_BY_NAME][$j])) == $p_options[PCLZIP_OPT_BY_NAME][$j])) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "The directory is in the file path"); + $v_extract = true; + } + } + // ----- Look for a filename + elseif ($v_header['stored_filename'] == $p_options[PCLZIP_OPT_BY_NAME][$j]) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "The file is the right one."); + $v_extract = true; + } + } + } + + // ----- Look for extract by ereg rule + else if ( (isset($p_options[PCLZIP_OPT_BY_EREG])) + && ($p_options[PCLZIP_OPT_BY_EREG] != "")) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Extract by ereg '".$p_options[PCLZIP_OPT_BY_EREG]."'"); + + if (preg_match('/'.$p_options[PCLZIP_OPT_BY_EREG].'/', $v_header['stored_filename'])) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Filename match the regular expression"); + $v_extract = true; + } + } + + // ----- Look for extract by preg rule + else if ( (isset($p_options[PCLZIP_OPT_BY_PREG])) + && ($p_options[PCLZIP_OPT_BY_PREG] != "")) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Extract with rule 'ByEreg'"); + + if (preg_match($p_options[PCLZIP_OPT_BY_PREG], $v_header['stored_filename'])) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Filename match the regular expression"); + $v_extract = true; + } + } + + // ----- Look for extract by index rule + else if ( (isset($p_options[PCLZIP_OPT_BY_INDEX])) + && ($p_options[PCLZIP_OPT_BY_INDEX] != 0)) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Extract with rule 'ByIndex'"); + + // ----- Look if the index is in the list + for ($j=$j_start; ($j=$p_options[PCLZIP_OPT_BY_INDEX][$j]['start']) && ($i<=$p_options[PCLZIP_OPT_BY_INDEX][$j]['end'])) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Found as part of an index range"); + $v_extract = true; + } + if ($i>=$p_options[PCLZIP_OPT_BY_INDEX][$j]['end']) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Do not look this index range for next loop"); + $j_start = $j+1; + } + + if ($p_options[PCLZIP_OPT_BY_INDEX][$j]['start']>$i) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Index range is greater than index, stop loop"); + break; + } + } + } + + // ----- Look for no rule, which means extract all the archive + else { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Extract with no rule (extract all)"); + $v_extract = true; + } + + // ----- Check compression method + if ( ($v_extract) + && ( ($v_header['compression'] != 8) + && ($v_header['compression'] != 0))) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "Unsupported compression method (".$v_header['compression'].")"); + $v_header['status'] = 'unsupported_compression'; + + // ----- Look for PCLZIP_OPT_STOP_ON_ERROR + if ( (isset($p_options[PCLZIP_OPT_STOP_ON_ERROR])) + && ($p_options[PCLZIP_OPT_STOP_ON_ERROR]===true)) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "PCLZIP_OPT_STOP_ON_ERROR is selected, extraction will be stopped"); + + $this->privSwapBackMagicQuotes(); + + PclZip::privErrorLog(PCLZIP_ERR_UNSUPPORTED_COMPRESSION, + "Filename '".$v_header['stored_filename']."' is " + ."compressed by an unsupported compression " + ."method (".$v_header['compression'].") "); + + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, PclZip::errorCode(), PclZip::errorInfo()); + return PclZip::errorCode(); + } + } + + // ----- Check encrypted files + if (($v_extract) && (($v_header['flag'] & 1) == 1)) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "Unsupported file encryption"); + $v_header['status'] = 'unsupported_encryption'; + + // ----- Look for PCLZIP_OPT_STOP_ON_ERROR + if ( (isset($p_options[PCLZIP_OPT_STOP_ON_ERROR])) + && ($p_options[PCLZIP_OPT_STOP_ON_ERROR]===true)) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "PCLZIP_OPT_STOP_ON_ERROR is selected, extraction will be stopped"); + + $this->privSwapBackMagicQuotes(); + + PclZip::privErrorLog(PCLZIP_ERR_UNSUPPORTED_ENCRYPTION, + "Unsupported encryption for " + ." filename '".$v_header['stored_filename'] + ."'"); + + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, PclZip::errorCode(), PclZip::errorInfo()); + return PclZip::errorCode(); + } + } + + // ----- Look for real extraction + if (($v_extract) && ($v_header['status'] != 'ok')) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "No need for extract"); + $v_result = $this->privConvertHeader2FileInfo($v_header, + $p_file_list[$v_nb_extracted++]); + if ($v_result != 1) { + $this->privCloseFd(); + $this->privSwapBackMagicQuotes(); + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + + $v_extract = false; + } + + // ----- Look for real extraction + if ($v_extract) + { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "Extracting file '".$v_header['filename']."', index '$i'"); + + // ----- Go to the file position + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 5, "Position before rewind : ".ftell($this->zip_fd)."'"); + @rewind($this->zip_fd); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 5, "Position after rewind : ".ftell($this->zip_fd)."'"); + if (@fseek($this->zip_fd, $v_header['offset'])) + { + // ----- Close the zip file + $this->privCloseFd(); + + $this->privSwapBackMagicQuotes(); + + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size'); + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, PclZip::errorCode(), PclZip::errorInfo()); + return PclZip::errorCode(); + } + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 5, "Position after fseek : ".ftell($this->zip_fd)."'"); + + // ----- Look for extraction as string + if ($p_options[PCLZIP_OPT_EXTRACT_AS_STRING]) { + + // ----- Extracting the file + $v_result1 = $this->privExtractFileAsString($v_header, $v_string); + if ($v_result1 < 1) { + $this->privCloseFd(); + $this->privSwapBackMagicQuotes(); + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result1); + return $v_result1; + } + + // ----- Get the only interesting attributes + if (($v_result = $this->privConvertHeader2FileInfo($v_header, $p_file_list[$v_nb_extracted])) != 1) + { + // ----- Close the zip file + $this->privCloseFd(); + $this->privSwapBackMagicQuotes(); + + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + + // ----- Set the file content + $p_file_list[$v_nb_extracted]['content'] = $v_string; + + // ----- Next extracted file + $v_nb_extracted++; + + // ----- Look for user callback abort + if ($v_result1 == 2) { + break; + } + } + // ----- Look for extraction in standard output + elseif ( (isset($p_options[PCLZIP_OPT_EXTRACT_IN_OUTPUT])) + && ($p_options[PCLZIP_OPT_EXTRACT_IN_OUTPUT])) { + // ----- Extracting the file in standard output + $v_result1 = $this->privExtractFileInOutput($v_header, $p_options); + if ($v_result1 < 1) { + $this->privCloseFd(); + $this->privSwapBackMagicQuotes(); + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result1); + return $v_result1; + } + + // ----- Get the only interesting attributes + if (($v_result = $this->privConvertHeader2FileInfo($v_header, $p_file_list[$v_nb_extracted++])) != 1) { + $this->privCloseFd(); + $this->privSwapBackMagicQuotes(); + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + + // ----- Look for user callback abort + if ($v_result1 == 2) { + break; + } + } + // ----- Look for normal extraction + else { + // ----- Extracting the file + $v_result1 = $this->privExtractFile($v_header, + $p_path, $p_remove_path, + $p_remove_all_path, + $p_options); + if ($v_result1 < 1) { + $this->privCloseFd(); + $this->privSwapBackMagicQuotes(); + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result1); + return $v_result1; + } + + // ----- Get the only interesting attributes + if (($v_result = $this->privConvertHeader2FileInfo($v_header, $p_file_list[$v_nb_extracted++])) != 1) + { + // ----- Close the zip file + $this->privCloseFd(); + $this->privSwapBackMagicQuotes(); + + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + + // ----- Look for user callback abort + if ($v_result1 == 2) { + break; + } + } + } + } + + // ----- Close the zip file + $this->privCloseFd(); + $this->privSwapBackMagicQuotes(); + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privExtractFile() + // Description : + // Parameters : + // Return Values : + // + // 1 : ... ? + // PCLZIP_ERR_USER_ABORTED(2) : User ask for extraction stop in callback + // -------------------------------------------------------------------------------- + function privExtractFile(&$p_entry, $p_path, $p_remove_path, $p_remove_all_path, &$p_options) + { + //--(MAGIC-PclTrace)--//PclTraceFctStart(__FILE__, __LINE__, 'PclZip::privExtractFile', "path='$p_path', remove_path='$p_remove_path', remove_all_path='".($p_remove_all_path?'true':'false')."'"); + $v_result=1; + + // ----- Read the file header + if (($v_result = $this->privReadFileHeader($v_header)) != 1) + { + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "Found file '".$v_header['filename']."', size '".$v_header['size']."'"); + + // ----- Check that the file header is coherent with $p_entry info + if ($this->privCheckFileHeaders($v_header, $p_entry) != 1) { + // TBC + } + + // ----- Look for all path to remove + if ($p_remove_all_path == true) { + // ----- Look for folder entry that not need to be extracted + if (($p_entry['external']&0x00000010)==0x00000010) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "The entry is a folder : need to be filtered"); + + $p_entry['status'] = "filtered"; + + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "All path is removed"); + // ----- Get the basename of the path + $p_entry['filename'] = basename($p_entry['filename']); + } + + // ----- Look for path to remove + else if ($p_remove_path != "") + { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Look for some path to remove"); + if (PclZipUtilPathInclusion($p_remove_path, $p_entry['filename']) == 2) + { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "The folder is the same as the removed path '".$p_entry['filename']."'"); + + // ----- Change the file status + $p_entry['status'] = "filtered"; + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + + $p_remove_path_size = strlen($p_remove_path); + if (substr($p_entry['filename'], 0, $p_remove_path_size) == $p_remove_path) + { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Found path '$p_remove_path' to remove in file '".$p_entry['filename']."'"); + + // ----- Remove the path + $p_entry['filename'] = substr($p_entry['filename'], $p_remove_path_size); + + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Resulting file is '".$p_entry['filename']."'"); + } + } + + // ----- Add the path + if ($p_path != '') + { + $p_entry['filename'] = $p_path."/".$p_entry['filename']; + } + + // ----- Look for pre-extract callback + if (isset($p_options[PCLZIP_CB_PRE_EXTRACT])) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "A pre-callback '".$p_options[PCLZIP_CB_PRE_EXTRACT]."()') is defined for the extraction"); + + // ----- Generate a local information + $v_local_header = array(); + $this->privConvertHeader2FileInfo($p_entry, $v_local_header); + + // ----- Call the callback + // Here I do not use call_user_func() because I need to send a reference to the + // header. + eval('$v_result = '.$p_options[PCLZIP_CB_PRE_EXTRACT].'(PCLZIP_CB_PRE_EXTRACT, $v_local_header);'); + if ($v_result == 0) { + // ----- Change the file status + $p_entry['status'] = "skipped"; + $v_result = 1; + } + + // ----- Look for abort result + if ($v_result == 2) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "User callback abort the extraction"); + // ----- This status is internal and will be changed in 'skipped' + $p_entry['status'] = "aborted"; + $v_result = PCLZIP_ERR_USER_ABORTED; + } + + // ----- Update the informations + // Only some fields can be modified + $p_entry['filename'] = $v_local_header['filename']; + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "New filename is '".$p_entry['filename']."'"); + } + + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "Extracting file (with path) '".$p_entry['filename']."', size '$v_header[size]'"); + + // ----- Look if extraction should be done + if ($p_entry['status'] == 'ok') { + + // ----- Look for specific actions while the file exist + if (file_exists($p_entry['filename'])) + { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "File '".$p_entry['filename']."' already exists"); + + // ----- Look if file is a directory + if (is_dir($p_entry['filename'])) + { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "Existing file '".$p_entry['filename']."' is a directory"); + + // ----- Change the file status + $p_entry['status'] = "already_a_directory"; + + // ----- Look for PCLZIP_OPT_STOP_ON_ERROR + // For historical reason first PclZip implementation does not stop + // when this kind of error occurs. + if ( (isset($p_options[PCLZIP_OPT_STOP_ON_ERROR])) + && ($p_options[PCLZIP_OPT_STOP_ON_ERROR]===true)) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "PCLZIP_OPT_STOP_ON_ERROR is selected, extraction will be stopped"); + + PclZip::privErrorLog(PCLZIP_ERR_ALREADY_A_DIRECTORY, + "Filename '".$p_entry['filename']."' is " + ."already used by an existing directory"); + + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, PclZip::errorCode(), PclZip::errorInfo()); + return PclZip::errorCode(); + } + } + // ----- Look if file is write protected + else if (!is_writeable($p_entry['filename'])) + { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "Existing file '".$p_entry['filename']."' is write protected"); + + // ----- Change the file status + $p_entry['status'] = "write_protected"; + + // ----- Look for PCLZIP_OPT_STOP_ON_ERROR + // For historical reason first PclZip implementation does not stop + // when this kind of error occurs. + if ( (isset($p_options[PCLZIP_OPT_STOP_ON_ERROR])) + && ($p_options[PCLZIP_OPT_STOP_ON_ERROR]===true)) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "PCLZIP_OPT_STOP_ON_ERROR is selected, extraction will be stopped"); + + PclZip::privErrorLog(PCLZIP_ERR_WRITE_OPEN_FAIL, + "Filename '".$p_entry['filename']."' exists " + ."and is write protected"); + + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, PclZip::errorCode(), PclZip::errorInfo()); + return PclZip::errorCode(); + } + } + + // ----- Look if the extracted file is older + else if (filemtime($p_entry['filename']) > $p_entry['mtime']) + { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "Existing file '".$p_entry['filename']."' is newer (".date("l dS of F Y h:i:s A", filemtime($p_entry['filename'])).") than the extracted file (".date("l dS of F Y h:i:s A", $p_entry['mtime']).")"); + // ----- Change the file status + if ( (isset($p_options[PCLZIP_OPT_REPLACE_NEWER])) + && ($p_options[PCLZIP_OPT_REPLACE_NEWER]===true)) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "PCLZIP_OPT_REPLACE_NEWER is selected, file will be replaced"); + } + else { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "File will not be replaced"); + $p_entry['status'] = "newer_exist"; + + // ----- Look for PCLZIP_OPT_STOP_ON_ERROR + // For historical reason first PclZip implementation does not stop + // when this kind of error occurs. + if ( (isset($p_options[PCLZIP_OPT_STOP_ON_ERROR])) + && ($p_options[PCLZIP_OPT_STOP_ON_ERROR]===true)) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "PCLZIP_OPT_STOP_ON_ERROR is selected, extraction will be stopped"); + + PclZip::privErrorLog(PCLZIP_ERR_WRITE_OPEN_FAIL, + "Newer version of '".$p_entry['filename']."' exists " + ."and option PCLZIP_OPT_REPLACE_NEWER is not selected"); + + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, PclZip::errorCode(), PclZip::errorInfo()); + return PclZip::errorCode(); + } + } + } + else { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "Existing file '".$p_entry['filename']."' is older than the extrated one - will be replaced by the extracted one (".date("l dS of F Y h:i:s A", filemtime($p_entry['filename'])).") than the extracted file (".date("l dS of F Y h:i:s A", $p_entry['mtime']).")"); + } + } + + // ----- Check the directory availability and create it if necessary + else { + if ((($p_entry['external']&0x00000010)==0x00000010) || (substr($p_entry['filename'], -1) == '/')) + $v_dir_to_check = $p_entry['filename']; + else if (!strstr($p_entry['filename'], "/")) + $v_dir_to_check = ""; + else + $v_dir_to_check = dirname($p_entry['filename']); + + if (($v_result = $this->privDirCheck($v_dir_to_check, (($p_entry['external']&0x00000010)==0x00000010))) != 1) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "Unable to create path for '".$p_entry['filename']."'"); + + // ----- Change the file status + $p_entry['status'] = "path_creation_fail"; + + // ----- Return + ////--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + //return $v_result; + $v_result = 1; + } + } + } + + // ----- Look if extraction should be done + if ($p_entry['status'] == 'ok') { + + // ----- Do the extraction (if not a folder) + if (!(($p_entry['external']&0x00000010)==0x00000010)) + { + // ----- Look for not compressed file + if ($p_entry['compression'] == 0) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "Extracting an un-compressed file"); + + // ----- Opening destination file + if (($v_dest_file = @fopen($p_entry['filename'], 'wb')) == 0) + { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "Error while opening '".$p_entry['filename']."' in write binary mode"); + + // ----- Change the file status + $p_entry['status'] = "write_error"; + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "Read '".$p_entry['size']."' bytes"); + + // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks + $v_size = $p_entry['compressed_size']; + while ($v_size != 0) + { + $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "Read $v_read_size bytes"); + $v_buffer = @fread($this->zip_fd, $v_read_size); + /* Try to speed up the code + $v_binary_data = pack('a'.$v_read_size, $v_buffer); + @fwrite($v_dest_file, $v_binary_data, $v_read_size); + */ + @fwrite($v_dest_file, $v_buffer, $v_read_size); + $v_size -= $v_read_size; + } + + // ----- Closing the destination file + fclose($v_dest_file); + + // ----- Change the file mtime + touch($p_entry['filename'], $p_entry['mtime']); + + + } + else { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "Extracting a compressed file (Compression method ".$p_entry['compression'].")"); + // ----- TBC + // Need to be finished + if (($p_entry['flag'] & 1) == 1) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "File is encrypted"); + /* + // ----- Read the encryption header + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 5, "Read 12 encryption header bytes"); + $v_encryption_header = @fread($this->zip_fd, 12); + + // ----- Read the encrypted & compressed file in a buffer + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 5, "Read '".($p_entry['compressed_size']-12)."' compressed & encrypted bytes"); + $v_buffer = @fread($this->zip_fd, $p_entry['compressed_size']-12); + + // ----- Decrypt the buffer + $this->privDecrypt($v_encryption_header, $v_buffer, + $p_entry['compressed_size']-12, $p_entry['crc']); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 5, "Buffer is '".$v_buffer."'"); + */ + } + else { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 5, "Read '".$p_entry['compressed_size']."' compressed bytes"); + // ----- Read the compressed file in a buffer (one shot) + $v_buffer = @fread($this->zip_fd, $p_entry['compressed_size']); + } + + // ----- Decompress the file + $v_file_content = @gzinflate($v_buffer); + unset($v_buffer); + if ($v_file_content === FALSE) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "Unable to inflate compressed file"); + + // ----- Change the file status + // TBC + $p_entry['status'] = "error"; + + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + + // ----- Opening destination file + if (($v_dest_file = @fopen($p_entry['filename'], 'wb')) == 0) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "Error while opening '".$p_entry['filename']."' in write binary mode"); + + // ----- Change the file status + $p_entry['status'] = "write_error"; + + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + + // ----- Write the uncompressed data + @fwrite($v_dest_file, $v_file_content, $p_entry['size']); + unset($v_file_content); + + // ----- Closing the destination file + @fclose($v_dest_file); + + // ----- Change the file mtime + @touch($p_entry['filename'], $p_entry['mtime']); + } + + // ----- Look for chmod option + if (isset($p_options[PCLZIP_OPT_SET_CHMOD])) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "chmod option activated '".$p_options[PCLZIP_OPT_SET_CHMOD]."'"); + + // ----- Change the mode of the file + @chmod($p_entry['filename'], $p_options[PCLZIP_OPT_SET_CHMOD]); + } + + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "Extraction done"); + } + } + + // ----- Change abort status + if ($p_entry['status'] == "aborted") { + $p_entry['status'] = "skipped"; + } + + // ----- Look for post-extract callback + elseif (isset($p_options[PCLZIP_CB_POST_EXTRACT])) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "A post-callback '".$p_options[PCLZIP_CB_POST_EXTRACT]."()') is defined for the extraction"); + + // ----- Generate a local information + $v_local_header = array(); + $this->privConvertHeader2FileInfo($p_entry, $v_local_header); + + // ----- Call the callback + // Here I do not use call_user_func() because I need to send a reference to the + // header. + eval('$v_result = '.$p_options[PCLZIP_CB_POST_EXTRACT].'(PCLZIP_CB_POST_EXTRACT, $v_local_header);'); + + // ----- Look for abort result + if ($v_result == 2) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "User callback abort the extraction"); + $v_result = PCLZIP_ERR_USER_ABORTED; + } + } + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privExtractFileInOutput() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privExtractFileInOutput(&$p_entry, &$p_options) + { + //--(MAGIC-PclTrace)--//PclTraceFctStart(__FILE__, __LINE__, 'PclZip::privExtractFileInOutput', ""); + $v_result=1; + + // ----- Read the file header + if (($v_result = $this->privReadFileHeader($v_header)) != 1) { + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "Found file '".$v_header['filename']."', size '".$v_header['size']."'"); + + // ----- Check that the file header is coherent with $p_entry info + if ($this->privCheckFileHeaders($v_header, $p_entry) != 1) { + // TBC + } + + // ----- Look for pre-extract callback + if (isset($p_options[PCLZIP_CB_PRE_EXTRACT])) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "A pre-callback '".$p_options[PCLZIP_CB_PRE_EXTRACT]."()') is defined for the extraction"); + + // ----- Generate a local information + $v_local_header = array(); + $this->privConvertHeader2FileInfo($p_entry, $v_local_header); + + // ----- Call the callback + // Here I do not use call_user_func() because I need to send a reference to the + // header. + eval('$v_result = '.$p_options[PCLZIP_CB_PRE_EXTRACT].'(PCLZIP_CB_PRE_EXTRACT, $v_local_header);'); + if ($v_result == 0) { + // ----- Change the file status + $p_entry['status'] = "skipped"; + $v_result = 1; + } + + // ----- Look for abort result + if ($v_result == 2) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "User callback abort the extraction"); + // ----- This status is internal and will be changed in 'skipped' + $p_entry['status'] = "aborted"; + $v_result = PCLZIP_ERR_USER_ABORTED; + } + + // ----- Update the informations + // Only some fields can be modified + $p_entry['filename'] = $v_local_header['filename']; + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "New filename is '".$p_entry['filename']."'"); + } + + // ----- Trace + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "Extracting file (with path) '".$p_entry['filename']."', size '$v_header[size]'"); + + // ----- Look if extraction should be done + if ($p_entry['status'] == 'ok') { + + // ----- Do the extraction (if not a folder) + if (!(($p_entry['external']&0x00000010)==0x00000010)) { + // ----- Look for not compressed file + if ($p_entry['compressed_size'] == $p_entry['size']) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "Extracting an un-compressed file"); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "Reading '".$p_entry['size']."' bytes"); + + // ----- Read the file in a buffer (one shot) + $v_buffer = @fread($this->zip_fd, $p_entry['compressed_size']); + + // ----- Send the file to the output + echo $v_buffer; + unset($v_buffer); + } + else { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "Extracting a compressed file"); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 5, "Reading '".$p_entry['size']."' bytes"); + + // ----- Read the compressed file in a buffer (one shot) + $v_buffer = @fread($this->zip_fd, $p_entry['compressed_size']); + + // ----- Decompress the file + $v_file_content = gzinflate($v_buffer); + unset($v_buffer); + + // ----- Send the file to the output + echo $v_file_content; + unset($v_file_content); + } + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "Extraction done"); + } + } + + // ----- Change abort status + if ($p_entry['status'] == "aborted") { + $p_entry['status'] = "skipped"; + } + + // ----- Look for post-extract callback + elseif (isset($p_options[PCLZIP_CB_POST_EXTRACT])) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "A post-callback '".$p_options[PCLZIP_CB_POST_EXTRACT]."()') is defined for the extraction"); + + // ----- Generate a local information + $v_local_header = array(); + $this->privConvertHeader2FileInfo($p_entry, $v_local_header); + + // ----- Call the callback + // Here I do not use call_user_func() because I need to send a reference to the + // header. + eval('$v_result = '.$p_options[PCLZIP_CB_POST_EXTRACT].'(PCLZIP_CB_POST_EXTRACT, $v_local_header);'); + + // ----- Look for abort result + if ($v_result == 2) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "User callback abort the extraction"); + $v_result = PCLZIP_ERR_USER_ABORTED; + } + } + + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privExtractFileAsString() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privExtractFileAsString(&$p_entry, &$p_string) + { + //--(MAGIC-PclTrace)--//PclTraceFctStart(__FILE__, __LINE__, 'PclZip::privExtractFileAsString', "p_entry['filename']='".$p_entry['filename']."'"); + $v_result=1; + + // ----- Read the file header + $v_header = array(); + if (($v_result = $this->privReadFileHeader($v_header)) != 1) + { + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "Found file '".$v_header['filename']."', size '".$v_header['size']."'"); + + // ----- Check that the file header is coherent with $p_entry info + if ($this->privCheckFileHeaders($v_header, $p_entry) != 1) { + // TBC + } + + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "Extracting file in string (with path) '".$p_entry['filename']."', size '$v_header[size]'"); + + // ----- Do the extraction (if not a folder) + if (!(($p_entry['external']&0x00000010)==0x00000010)) + { + // ----- Look for not compressed file +// if ($p_entry['compressed_size'] == $p_entry['size']) + if ($p_entry['compression'] == 0) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "Extracting an un-compressed file"); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "Reading '".$p_entry['size']."' bytes"); + + // ----- Reading the file + $p_string = @fread($this->zip_fd, $p_entry['compressed_size']); + } + else { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "Extracting a compressed file (compression method '".$p_entry['compression']."')"); + + // ----- Reading the file + $v_data = @fread($this->zip_fd, $p_entry['compressed_size']); + + // ----- Decompress the file + if (($p_string = @gzinflate($v_data)) === FALSE) { + // TBC + } + } + + // ----- Trace + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "Extraction done"); + } + else { + // TBC : error : can not extract a folder in a string + } + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privReadFileHeader() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privReadFileHeader(&$p_header) + { + //--(MAGIC-PclTrace)--//PclTraceFctStart(__FILE__, __LINE__, "PclZip::privReadFileHeader", ""); + $v_result=1; + + // ----- Read the 4 bytes signature + $v_binary_data = @fread($this->zip_fd, 4); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Binary data is : '".sprintf("%08x", $v_binary_data)."'"); + $v_data = unpack('Vid', $v_binary_data); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Binary signature is : '".sprintf("0x%08x", $v_data['id'])."'"); + + // ----- Check signature + if ($v_data['id'] != 0x04034b50) + { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Invalid File header"); + + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Invalid archive structure'); + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, PclZip::errorCode(), PclZip::errorInfo()); + return PclZip::errorCode(); + } + + // ----- Read the first 42 bytes of the header + $v_binary_data = fread($this->zip_fd, 26); + + // ----- Look for invalid block size + if (mb_strlen($v_binary_data,'iso-8859-1') != 26) + { + $p_header['filename'] = ""; + $p_header['status'] = "invalid_header"; + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "Invalid block size : ".strlen($v_binary_data)); + + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, "Invalid block size : ".mb_strlen($v_binary_data,'iso-8859-1')); + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, PclZip::errorCode(), PclZip::errorInfo()); + return PclZip::errorCode(); + } + + // ----- Extract the values + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "Header : '".$v_binary_data."'"); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "Header (Hex) : '".bin2hex($v_binary_data)."'"); + $v_data = unpack('vversion/vflag/vcompression/vmtime/vmdate/Vcrc/Vcompressed_size/Vsize/vfilename_len/vextra_len', $v_binary_data); + + // ----- Get filename + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "File name length : ".$v_data['filename_len']); + $p_header['filename'] = fread($this->zip_fd, $v_data['filename_len']); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, 'Filename : \''.$p_header['filename'].'\''); + + // ----- Get extra_fields + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Extra field length : ".$v_data['extra_len']); + if ($v_data['extra_len'] != 0) { + $p_header['extra'] = fread($this->zip_fd, $v_data['extra_len']); + } + else { + $p_header['extra'] = ''; + } + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, 'Extra field : \''.bin2hex($p_header['extra']).'\''); + + // ----- Extract properties + $p_header['version_extracted'] = $v_data['version']; + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, 'Version need to extract : ('.$p_header['version_extracted'].') \''.($p_header['version_extracted']/10).'.'.($p_header['version_extracted']%10).'\''); + $p_header['compression'] = $v_data['compression']; + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, 'Compression method : \''.$p_header['compression'].'\''); + $p_header['size'] = $v_data['size']; + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, 'Size : \''.$p_header['size'].'\''); + $p_header['compressed_size'] = $v_data['compressed_size']; + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, 'Compressed Size : \''.$p_header['compressed_size'].'\''); + $p_header['crc'] = $v_data['crc']; + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, 'CRC : \''.sprintf("0x%X", $p_header['crc']).'\''); + $p_header['flag'] = $v_data['flag']; + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, 'Flag : \''.$p_header['flag'].'\''); + $p_header['filename_len'] = $v_data['filename_len']; + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, 'Filename_len : \''.$p_header['filename_len'].'\''); + + // ----- Recuperate date in UNIX format + $p_header['mdate'] = $v_data['mdate']; + $p_header['mtime'] = $v_data['mtime']; + if ($p_header['mdate'] && $p_header['mtime']) + { + // ----- Extract time + $v_hour = ($p_header['mtime'] & 0xF800) >> 11; + $v_minute = ($p_header['mtime'] & 0x07E0) >> 5; + $v_seconde = ($p_header['mtime'] & 0x001F)*2; + + // ----- Extract date + $v_year = (($p_header['mdate'] & 0xFE00) >> 9) + 1980; + $v_month = ($p_header['mdate'] & 0x01E0) >> 5; + $v_day = $p_header['mdate'] & 0x001F; + + // ----- Get UNIX date format + $p_header['mtime'] = mktime($v_hour, $v_minute, $v_seconde, $v_month, $v_day, $v_year); + + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, 'Date : \''.date("d/m/y H:i:s", $p_header['mtime']).'\''); + } + else + { + $p_header['mtime'] = time(); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, 'Date is actual : \''.date("d/m/y H:i:s", $p_header['mtime']).'\''); + } + + // TBC + //for(reset($v_data); $key = key($v_data); next($v_data)) { + // //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Attribut[$key] = ".$v_data[$key]); + //} + + // ----- Set the stored filename + $p_header['stored_filename'] = $p_header['filename']; + + // ----- Set the status field + $p_header['status'] = "ok"; + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privReadCentralFileHeader() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privReadCentralFileHeader(&$p_header) + { + //--(MAGIC-PclTrace)--//PclTraceFctStart(__FILE__, __LINE__, "PclZip::privReadCentralFileHeader", ""); + $v_result=1; + + // ----- Read the 4 bytes signature + $v_binary_data = @fread($this->zip_fd, 4); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Binary data is : '".sprintf("%08x", $v_binary_data)."'"); + $v_data = unpack('Vid', $v_binary_data); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Binary signature is : '".sprintf("0x%08x", $v_data['id'])."'"); + + // ----- Check signature + if ($v_data['id'] != 0x02014b50) + { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Invalid Central Dir File signature"); + + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Invalid archive structure'); + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, PclZip::errorCode(), PclZip::errorInfo()); + return PclZip::errorCode(); + } + + // ----- Read the first 42 bytes of the header + $v_binary_data = fread($this->zip_fd, 42); + + // ----- Look for invalid block size + if (mb_strlen($v_binary_data,'iso-8859-1') != 42) + { + $p_header['filename'] = ""; + $p_header['status'] = "invalid_header"; + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "Invalid block size : ".strlen($v_binary_data)); + + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, "Invalid block size : ".mb_strlen($v_binary_data,'iso-8859-1')); + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, PclZip::errorCode(), PclZip::errorInfo()); + return PclZip::errorCode(); + } + + // ----- Extract the values + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 5, "Header : '".$v_binary_data."'"); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 5, "Header (Hex) : '".bin2hex($v_binary_data)."'"); + $p_header = unpack('vversion/vversion_extracted/vflag/vcompression/vmtime/vmdate/Vcrc/Vcompressed_size/Vsize/vfilename_len/vextra_len/vcomment_len/vdisk/vinternal/Vexternal/Voffset', $v_binary_data); + + // ----- Get filename + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, "File name length : ".$p_header['filename_len']); + if ($p_header['filename_len'] != 0) + $p_header['filename'] = fread($this->zip_fd, $p_header['filename_len']); + else + $p_header['filename'] = ''; + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, 'Filename : \''.$p_header['filename'].'\''); + + // ----- Get extra + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, "Extra length : ".$p_header['extra_len']); + if ($p_header['extra_len'] != 0) + $p_header['extra'] = fread($this->zip_fd, $p_header['extra_len']); + else + $p_header['extra'] = ''; + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, 'Extra : \''.$p_header['extra'].'\''); + + // ----- Get comment + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, "Comment length : ".$p_header['comment_len']); + if ($p_header['comment_len'] != 0) + $p_header['comment'] = fread($this->zip_fd, $p_header['comment_len']); + else + $p_header['comment'] = ''; + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, 'Comment : \''.$p_header['comment'].'\''); + + // ----- Extract properties + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, 'Version : \''.($p_header['version']/10).'.'.($p_header['version']%10).'\''); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, 'Version need to extract : \''.($p_header['version_extracted']/10).'.'.($p_header['version_extracted']%10).'\''); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, 'Size : \''.$p_header['size'].'\''); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, 'Compressed Size : \''.$p_header['compressed_size'].'\''); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, 'CRC : \''.sprintf("0x%X", $p_header['crc']).'\''); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, 'Flag : \''.$p_header['flag'].'\''); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, 'Offset : \''.$p_header['offset'].'\''); + + // ----- Recuperate date in UNIX format + if ($p_header['mdate'] && $p_header['mtime']) + { + // ----- Extract time + $v_hour = ($p_header['mtime'] & 0xF800) >> 11; + $v_minute = ($p_header['mtime'] & 0x07E0) >> 5; + $v_seconde = ($p_header['mtime'] & 0x001F)*2; + + // ----- Extract date + $v_year = (($p_header['mdate'] & 0xFE00) >> 9) + 1980; + $v_month = ($p_header['mdate'] & 0x01E0) >> 5; + $v_day = $p_header['mdate'] & 0x001F; + + // ----- Get UNIX date format + $p_header['mtime'] = mktime($v_hour, $v_minute, $v_seconde, $v_month, $v_day, $v_year); + + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, 'Date : \''.date("d/m/y H:i:s", $p_header['mtime']).'\''); + } + else + { + $p_header['mtime'] = time(); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, 'Date is actual : \''.date("d/m/y H:i:s", $p_header['mtime']).'\''); + } + + // ----- Set the stored filename + $p_header['stored_filename'] = $p_header['filename']; + + // ----- Set default status to ok + $p_header['status'] = 'ok'; + + // ----- Look if it is a directory + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 5, "Internal (Hex) : '".sprintf("Ox%04X", $p_header['internal'])."'"); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, "External (Hex) : '".sprintf("Ox%04X", $p_header['external'])."' (".(($p_header['external']&0x00000010)==0x00000010?'is a folder':'is a file').')'); + if (substr($p_header['filename'], -1) == '/') { + //$p_header['external'] = 0x41FF0010; + $p_header['external'] = 0x00000010; + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, 'Force folder external : \''.sprintf("Ox%04X", $p_header['external']).'\''); + } + + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, 'Header of filename : \''.$p_header['filename'].'\''); + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privCheckFileHeaders() + // Description : + // Parameters : + // Return Values : + // 1 on success, + // 0 on error; + // -------------------------------------------------------------------------------- + function privCheckFileHeaders(&$p_local_header, &$p_central_header) + { + //--(MAGIC-PclTrace)--//PclTraceFctStart(__FILE__, __LINE__, "PclZip::privCheckFileHeaders", ""); + $v_result=1; + + // ----- Check the static values + // TBC + if ($p_local_header['filename'] != $p_central_header['filename']) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, 'Bad check "filename" : TBC To Be Completed'); + } + if ($p_local_header['version_extracted'] != $p_central_header['version_extracted']) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, 'Bad check "version_extracted" : TBC To Be Completed'); + } + if ($p_local_header['flag'] != $p_central_header['flag']) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, 'Bad check "flag" : TBC To Be Completed'); + } + if ($p_local_header['compression'] != $p_central_header['compression']) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, 'Bad check "compression" : TBC To Be Completed'); + } + if ($p_local_header['mtime'] != $p_central_header['mtime']) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, 'Bad check "mtime" : TBC To Be Completed'); + } + if ($p_local_header['filename_len'] != $p_central_header['filename_len']) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, 'Bad check "filename_len" : TBC To Be Completed'); + } + + // ----- Look for flag bit 3 + if (($p_local_header['flag'] & 8) == 8) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, 'Purpose bit flag bit 3 set !'); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, 'File size, compression size and crc found in central header'); + $p_local_header['size'] = $p_central_header['size']; + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, 'Size : \''.$p_local_header['size'].'\''); + $p_local_header['compressed_size'] = $p_central_header['compressed_size']; + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, 'Compressed Size : \''.$p_local_header['compressed_size'].'\''); + $p_local_header['crc'] = $p_central_header['crc']; + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, 'CRC : \''.sprintf("0x%X", $p_local_header['crc']).'\''); + } + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privReadEndCentralDir() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privReadEndCentralDir(&$p_central_dir) + { + //--(MAGIC-PclTrace)--//PclTraceFctStart(__FILE__, __LINE__, "PclZip::privReadEndCentralDir", ""); + $v_result=1; + + // ----- Go to the end of the zip file + $v_size = filesize($this->zipname); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "Size of the file :$v_size"); + @fseek($this->zip_fd, $v_size); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, 'Position at end of zip file : \''.ftell($this->zip_fd).'\''); + if (@ftell($this->zip_fd) != $v_size) + { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Unable to go to the end of the archive \''.$this->zipname.'\''); + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, PclZip::errorCode(), PclZip::errorInfo()); + return PclZip::errorCode(); + } + + // ----- First try : look if this is an archive with no commentaries (most of the time) + // in this case the end of central dir is at 22 bytes of the file end + $v_found = 0; + if ($v_size > 26) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, 'Look for central dir with no comment'); + @fseek($this->zip_fd, $v_size-22); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, 'Position after min central position : \''.ftell($this->zip_fd).'\''); + if (($v_pos = @ftell($this->zip_fd)) != ($v_size-22)) + { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Unable to seek back to the middle of the archive \''.$this->zipname.'\''); + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, PclZip::errorCode(), PclZip::errorInfo()); + return PclZip::errorCode(); + } + + // ----- Read for bytes + $v_binary_data = @fread($this->zip_fd, 4); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 5, "Binary data is : '".sprintf("%08x", $v_binary_data)."'"); + $v_data = @unpack('Vid', $v_binary_data); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Binary signature is : '".sprintf("0x%08x", $v_data['id'])."'"); + + // ----- Check signature + if ($v_data['id'] == 0x06054b50) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "Found central dir at the default position."); + $v_found = 1; + } + + $v_pos = ftell($this->zip_fd); + } + + // ----- Go back to the maximum possible size of the Central Dir End Record + if (!$v_found) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, 'Start extended search of end central dir'); + $v_maximum_size = 65557; // 0xFFFF + 22; + if ($v_maximum_size > $v_size) + $v_maximum_size = $v_size; + @fseek($this->zip_fd, $v_size-$v_maximum_size); + if (@ftell($this->zip_fd) != ($v_size-$v_maximum_size)) + { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Unable to seek back to the middle of the archive \''.$this->zipname.'\''); + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, PclZip::errorCode(), PclZip::errorInfo()); + return PclZip::errorCode(); + } + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, 'Position after max central position : \''.ftell($this->zip_fd).'\''); + + // ----- Read byte per byte in order to find the signature + $v_pos = ftell($this->zip_fd); + $v_bytes = 0x00000000; + while ($v_pos < $v_size) + { + // ----- Read a byte + $v_byte = @fread($this->zip_fd, 1); + + // ----- Add the byte + $v_bytes = ($v_bytes << 8) | Ord($v_byte); + + // ----- Compare the bytes + if ($v_bytes == 0x504b0506) + { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, 'Found End Central Dir signature at position : \''.ftell($this->zip_fd).'\''); + $v_pos++; + break; + } + + $v_pos++; + } + + // ----- Look if not found end of central dir + if ($v_pos == $v_size) + { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "Unable to find End of Central Dir Record signature"); + + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, "Unable to find End of Central Dir Record signature"); + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, PclZip::errorCode(), PclZip::errorInfo()); + return PclZip::errorCode(); + } + } + + // ----- Read the first 18 bytes of the header + $v_binary_data = fread($this->zip_fd, 18); + + // ----- Look for invalid block size + if (mb_strlen($v_binary_data,'iso-8859-1') != 18) + { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "Invalid End of Central Dir Record size : ".strlen($v_binary_data)); + + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, "Invalid End of Central Dir Record size : ".mb_strlen($v_binary_data,'iso-8859-1')); + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, PclZip::errorCode(), PclZip::errorInfo()); + return PclZip::errorCode(); + } + + // ----- Extract the values + ////--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, "Central Dir Record : '".$v_binary_data."'"); + ////--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, "Central Dir Record (Hex) : '".bin2hex($v_binary_data)."'"); + $v_data = unpack('vdisk/vdisk_start/vdisk_entries/ventries/Vsize/Voffset/vcomment_size', $v_binary_data); + + // ----- Check the global size + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Comment length : ".$v_data['comment_size']); + if (($v_pos + $v_data['comment_size'] + 18) != $v_size) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "The central dir is not at the end of the archive. Some trailing bytes exists after the archive."); + + // ----- Removed in release 2.2 see readme file + // The check of the file size is a little too strict. + // Some bugs where found when a zip is encrypted/decrypted with 'crypt'. + // While decrypted, zip has training 0 bytes + if (0) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, + 'The central dir is not at the end of the archive.' + .' Some trailing bytes exists after the archive.'); + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, PclZip::errorCode(), PclZip::errorInfo()); + return PclZip::errorCode(); + } + } + + // ----- Get comment + if ($v_data['comment_size'] != 0) + $p_central_dir['comment'] = fread($this->zip_fd, $v_data['comment_size']); + else + $p_central_dir['comment'] = ''; + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, 'Comment : \''.$p_central_dir['comment'].'\''); + + $p_central_dir['entries'] = $v_data['entries']; + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, 'Nb of entries : \''.$p_central_dir['entries'].'\''); + $p_central_dir['disk_entries'] = $v_data['disk_entries']; + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, 'Nb of entries for this disk : \''.$p_central_dir['disk_entries'].'\''); + $p_central_dir['offset'] = $v_data['offset']; + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, 'Offset of Central Dir : \''.$p_central_dir['offset'].'\''); + $p_central_dir['size'] = $v_data['size']; + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, 'Size of Central Dir : \''.$p_central_dir['size'].'\''); + $p_central_dir['disk'] = $v_data['disk']; + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, 'Disk number : \''.$p_central_dir['disk'].'\''); + $p_central_dir['disk_start'] = $v_data['disk_start']; + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, 'Start disk number : \''.$p_central_dir['disk_start'].'\''); + + // TBC + //for(reset($p_central_dir); $key = key($p_central_dir); next($p_central_dir)) { + // //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "central_dir[$key] = ".$p_central_dir[$key]); + //} + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privDeleteByRule() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privDeleteByRule(&$p_result_list, &$p_options) + { + //--(MAGIC-PclTrace)--//PclTraceFctStart(__FILE__, __LINE__, "PclZip::privDeleteByRule", ""); + $v_result=1; + $v_list_detail = array(); + + // ----- Open the zip file + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Open file in binary read mode"); + if (($v_result=$this->privOpenFd('rb')) != 1) + { + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + + // ----- Read the central directory informations + $v_central_dir = array(); + if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) + { + $this->privCloseFd(); + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + + // ----- Go to beginning of File + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 5, "Position in file : ".ftell($this->zip_fd)."'"); + @rewind($this->zip_fd); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 5, "Position in file : ".ftell($this->zip_fd)."'"); + + // ----- Scan all the files + // ----- Start at beginning of Central Dir + $v_pos_entry = $v_central_dir['offset']; + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 5, "Position before rewind : ".ftell($this->zip_fd)."'"); + @rewind($this->zip_fd); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 5, "Position after rewind : ".ftell($this->zip_fd)."'"); + if (@fseek($this->zip_fd, $v_pos_entry)) + { + // ----- Close the zip file + $this->privCloseFd(); + + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size'); + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, PclZip::errorCode(), PclZip::errorInfo()); + return PclZip::errorCode(); + } + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 5, "Position after fseek : ".ftell($this->zip_fd)."'"); + + // ----- Read each entry + $v_header_list = array(); + $j_start = 0; + for ($i=0, $v_nb_extracted=0; $i<$v_central_dir['entries']; $i++) + { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Read next file header entry (index '$i')"); + + // ----- Read the file header + $v_header_list[$v_nb_extracted] = array(); + if (($v_result = $this->privReadCentralFileHeader($v_header_list[$v_nb_extracted])) != 1) + { + // ----- Close the zip file + $this->privCloseFd(); + + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Filename (index '$i') : '".$v_header_list[$v_nb_extracted]['stored_filename']."'"); + + // ----- Store the index + $v_header_list[$v_nb_extracted]['index'] = $i; + + // ----- Look for the specific extract rules + $v_found = false; + + // ----- Look for extract by name rule + if ( (isset($p_options[PCLZIP_OPT_BY_NAME])) + && ($p_options[PCLZIP_OPT_BY_NAME] != 0)) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Extract with rule 'ByName'"); + + // ----- Look if the filename is in the list + for ($j=0; ($j strlen($p_options[PCLZIP_OPT_BY_NAME][$j])) + && (substr($v_header_list[$v_nb_extracted]['stored_filename'], 0, strlen($p_options[PCLZIP_OPT_BY_NAME][$j])) == $p_options[PCLZIP_OPT_BY_NAME][$j])) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "The directory is in the file path"); + $v_found = true; + } + elseif ( (($v_header_list[$v_nb_extracted]['external']&0x00000010)==0x00000010) /* Indicates a folder */ + && ($v_header_list[$v_nb_extracted]['stored_filename'].'/' == $p_options[PCLZIP_OPT_BY_NAME][$j])) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "The entry is the searched directory"); + $v_found = true; + } + } + // ----- Look for a filename + elseif ($v_header_list[$v_nb_extracted]['stored_filename'] == $p_options[PCLZIP_OPT_BY_NAME][$j]) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "The file is the right one."); + $v_found = true; + } + } + } + + // ----- Look for extract by ereg rule + else if ( (isset($p_options[PCLZIP_OPT_BY_EREG])) + && ($p_options[PCLZIP_OPT_BY_EREG] != "")) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Extract by ereg '".$p_options[PCLZIP_OPT_BY_EREG]."'"); + + if (preg_match('/'.$p_options[PCLZIP_OPT_BY_EREG].'/', $v_header_list[$v_nb_extracted]['stored_filename'])) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Filename match the regular expression"); + $v_found = true; + } + } + + // ----- Look for extract by preg rule + else if ( (isset($p_options[PCLZIP_OPT_BY_PREG])) + && ($p_options[PCLZIP_OPT_BY_PREG] != "")) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Extract with rule 'ByEreg'"); + + if (preg_match($p_options[PCLZIP_OPT_BY_PREG], $v_header_list[$v_nb_extracted]['stored_filename'])) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Filename match the regular expression"); + $v_found = true; + } + } + + // ----- Look for extract by index rule + else if ( (isset($p_options[PCLZIP_OPT_BY_INDEX])) + && ($p_options[PCLZIP_OPT_BY_INDEX] != 0)) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Extract with rule 'ByIndex'"); + + // ----- Look if the index is in the list + for ($j=$j_start; ($j=$p_options[PCLZIP_OPT_BY_INDEX][$j]['start']) && ($i<=$p_options[PCLZIP_OPT_BY_INDEX][$j]['end'])) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Found as part of an index range"); + $v_found = true; + } + if ($i>=$p_options[PCLZIP_OPT_BY_INDEX][$j]['end']) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Do not look this index range for next loop"); + $j_start = $j+1; + } + + if ($p_options[PCLZIP_OPT_BY_INDEX][$j]['start']>$i) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Index range is greater than index, stop loop"); + break; + } + } + } + else { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "No argument mean remove all file"); + $v_found = true; + } + + // ----- Look for deletion + if ($v_found) + { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "File '".$v_header_list[$v_nb_extracted]['stored_filename']."', index '$i' need to be deleted"); + unset($v_header_list[$v_nb_extracted]); + } + else + { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 2, "File '".$v_header_list[$v_nb_extracted]['stored_filename']."', index '$i' will not be deleted"); + $v_nb_extracted++; + } + } + + // ----- Look if something need to be deleted + if ($v_nb_extracted > 0) { + + // ----- Creates a temporay file + $v_zip_temp_name = PCLZIP_TEMPORARY_DIR.uniqid('pclzip-').'.tmp'; + + // ----- Creates a temporary zip archive + $v_temp_zip = new PclZip($v_zip_temp_name); + + // ----- Open the temporary zip file in write mode + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Open file in binary write mode"); + if (($v_result = $v_temp_zip->privOpenFd('wb')) != 1) { + $this->privCloseFd(); + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + + // ----- Look which file need to be kept + for ($i=0; $izip_fd)."'"); + @rewind($this->zip_fd); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 5, "Position after rewind : ".ftell($this->zip_fd)."'"); + if (@fseek($this->zip_fd, $v_header_list[$i]['offset'])) { + // ----- Close the zip file + $this->privCloseFd(); + $v_temp_zip->privCloseFd(); + @unlink($v_zip_temp_name); + + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size'); + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, PclZip::errorCode(), PclZip::errorInfo()); + return PclZip::errorCode(); + } + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 5, "Position after fseek : ".ftell($this->zip_fd)."'"); + + // ----- Read the file header + $v_local_header = array(); + if (($v_result = $this->privReadFileHeader($v_local_header)) != 1) { + // ----- Close the zip file + $this->privCloseFd(); + $v_temp_zip->privCloseFd(); + @unlink($v_zip_temp_name); + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + + // ----- Check that local file header is same as central file header + if ($this->privCheckFileHeaders($v_local_header, + $v_header_list[$i]) != 1) { + // TBC + } + unset($v_local_header); + + // ----- Write the file header + if (($v_result = $v_temp_zip->privWriteFileHeader($v_header_list[$i])) != 1) { + // ----- Close the zip file + $this->privCloseFd(); + $v_temp_zip->privCloseFd(); + @unlink($v_zip_temp_name); + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 5, "Offset for this file is '".$v_header_list[$i]['offset']."'"); + + // ----- Read/write the data block + if (($v_result = PclZipUtilCopyBlock($this->zip_fd, $v_temp_zip->zip_fd, $v_header_list[$i]['compressed_size'])) != 1) { + // ----- Close the zip file + $this->privCloseFd(); + $v_temp_zip->privCloseFd(); + @unlink($v_zip_temp_name); + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + } + + // ----- Store the offset of the central dir + $v_offset = @ftell($v_temp_zip->zip_fd); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 5, "New offset of central dir : $v_offset"); + + // ----- Re-Create the Central Dir files header + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Creates the new central directory"); + for ($i=0; $iprivWriteCentralFileHeader($v_header_list[$i])) != 1) { + $v_temp_zip->privCloseFd(); + $this->privCloseFd(); + @unlink($v_zip_temp_name); + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + + // ----- Transform the header to a 'usable' info + $v_temp_zip->privConvertHeader2FileInfo($v_header_list[$i], $p_result_list[$i]); + } + + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Creates the central directory footer"); + + // ----- Zip file comment + $v_comment = ''; + if (isset($p_options[PCLZIP_OPT_COMMENT])) { + $v_comment = $p_options[PCLZIP_OPT_COMMENT]; + } + + // ----- Calculate the size of the central header + $v_size = @ftell($v_temp_zip->zip_fd)-$v_offset; + + // ----- Create the central dir footer + if (($v_result = $v_temp_zip->privWriteCentralHeader(sizeof($v_header_list), $v_size, $v_offset, $v_comment)) != 1) { + // ----- Reset the file list + unset($v_header_list); + $v_temp_zip->privCloseFd(); + $this->privCloseFd(); + @unlink($v_zip_temp_name); + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + + // ----- Close + $v_temp_zip->privCloseFd(); + $this->privCloseFd(); + + // ----- Delete the zip file + // TBC : I should test the result ... + @unlink($this->zipname); + + // ----- Rename the temporary file + // TBC : I should test the result ... + //@rename($v_zip_temp_name, $this->zipname); + PclZipUtilRename($v_zip_temp_name, $this->zipname); + + // ----- Destroy the temporary archive + unset($v_temp_zip); + } + + // ----- Remove every files : reset the file + else if ($v_central_dir['entries'] != 0) { + $this->privCloseFd(); + + if (($v_result = $this->privOpenFd('wb')) != 1) { + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + + if (($v_result = $this->privWriteCentralHeader(0, 0, 0, '')) != 1) { + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + + $this->privCloseFd(); + } + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privDirCheck() + // Description : + // Check if a directory exists, if not it creates it and all the parents directory + // which may be useful. + // Parameters : + // $p_dir : Directory path to check. + // Return Values : + // 1 : OK + // -1 : Unable to create directory + // -------------------------------------------------------------------------------- + function privDirCheck($p_dir, $p_is_dir=false) + { + $v_result = 1; + + //--(MAGIC-PclTrace)--//PclTraceFctStart(__FILE__, __LINE__, "PclZip::privDirCheck", "entry='$p_dir', is_dir='".($p_is_dir?"true":"false")."'"); + + // ----- Remove the final '/' + if (($p_is_dir) && (substr($p_dir, -1)=='/')) + { + $p_dir = substr($p_dir, 0, strlen($p_dir)-1); + } + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Looking for entry '$p_dir'"); + + // ----- Check the directory availability + if ((is_dir($p_dir)) || ($p_dir == "")) + { + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, "'$p_dir' is a directory"); + return 1; + } + + // ----- Extract parent directory + $p_parent_dir = dirname($p_dir); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Parent directory is '$p_parent_dir'"); + + // ----- Just a check + if ($p_parent_dir != $p_dir) + { + // ----- Look for parent directory + if ($p_parent_dir != "") + { + if (($v_result = $this->privDirCheck($p_parent_dir)) != 1) + { + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + } + } + + // ----- Create the directory + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Create directory '$p_dir'"); + if (!@mkdir($p_dir, 0777)) + { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_DIR_CREATE_FAIL, "Unable to create directory '$p_dir'"); + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, PclZip::errorCode(), PclZip::errorInfo()); + return PclZip::errorCode(); + } + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result, "Directory '$p_dir' created"); + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privMerge() + // Description : + // If $p_archive_to_add does not exist, the function exit with a success result. + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privMerge(&$p_archive_to_add) + { + //--(MAGIC-PclTrace)--//PclTraceFctStart(__FILE__, __LINE__, "PclZip::privMerge", "archive='".$p_archive_to_add->zipname."'"); + $v_result=1; + + // ----- Look if the archive_to_add exists + if (!is_file($p_archive_to_add->zipname)) + { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Archive to add does not exist. End of merge."); + + // ----- Nothing to merge, so merge is a success + $v_result = 1; + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + + // ----- Look if the archive exists + if (!is_file($this->zipname)) + { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Archive does not exist, duplicate the archive_to_add."); + + // ----- Do a duplicate + $v_result = $this->privDuplicate($p_archive_to_add->zipname); + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + + // ----- Open the zip file + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Open file in binary read mode"); + if (($v_result=$this->privOpenFd('rb')) != 1) + { + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + + // ----- Read the central directory informations + $v_central_dir = array(); + if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) + { + $this->privCloseFd(); + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + + // ----- Go to beginning of File + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 5, "Position in zip : ".ftell($this->zip_fd)."'"); + @rewind($this->zip_fd); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 5, "Position in zip : ".ftell($this->zip_fd)."'"); + + // ----- Open the archive_to_add file + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Open archive_to_add in binary read mode"); + if (($v_result=$p_archive_to_add->privOpenFd('rb')) != 1) + { + $this->privCloseFd(); + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + + // ----- Read the central directory informations + $v_central_dir_to_add = array(); + if (($v_result = $p_archive_to_add->privReadEndCentralDir($v_central_dir_to_add)) != 1) + { + $this->privCloseFd(); + $p_archive_to_add->privCloseFd(); + + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + + // ----- Go to beginning of File + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 5, "Position in archive_to_add : ".ftell($p_archive_to_add->zip_fd)."'"); + @rewind($p_archive_to_add->zip_fd); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 5, "Position in archive_to_add : ".ftell($p_archive_to_add->zip_fd)."'"); + + // ----- Creates a temporay file + $v_zip_temp_name = PCLZIP_TEMPORARY_DIR.uniqid('pclzip-').'.tmp'; + + // ----- Open the temporary file in write mode + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Open file in binary read mode"); + if (($v_zip_temp_fd = @fopen($v_zip_temp_name, 'wb')) == 0) + { + $this->privCloseFd(); + $p_archive_to_add->privCloseFd(); + + PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \''.$v_zip_temp_name.'\' in binary write mode'); + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, PclZip::errorCode(), PclZip::errorInfo()); + return PclZip::errorCode(); + } + + // ----- Copy the files from the archive to the temporary file + // TBC : Here I should better append the file and go back to erase the central dir + $v_size = $v_central_dir['offset']; + while ($v_size != 0) + { + $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, "Read $v_read_size bytes"); + $v_buffer = fread($this->zip_fd, $v_read_size); + @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size); + $v_size -= $v_read_size; + } + + // ----- Copy the files from the archive_to_add into the temporary file + $v_size = $v_central_dir_to_add['offset']; + while ($v_size != 0) + { + $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, "Read $v_read_size bytes"); + $v_buffer = fread($p_archive_to_add->zip_fd, $v_read_size); + @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size); + $v_size -= $v_read_size; + } + + // ----- Store the offset of the central dir + $v_offset = @ftell($v_zip_temp_fd); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, "New offset of central dir : $v_offset"); + + // ----- Copy the block of file headers from the old archive + $v_size = $v_central_dir['size']; + while ($v_size != 0) + { + $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, "Read $v_read_size bytes"); + $v_buffer = @fread($this->zip_fd, $v_read_size); + @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size); + $v_size -= $v_read_size; + } + + // ----- Copy the block of file headers from the archive_to_add + $v_size = $v_central_dir_to_add['size']; + while ($v_size != 0) + { + $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, "Read $v_read_size bytes"); + $v_buffer = @fread($p_archive_to_add->zip_fd, $v_read_size); + @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size); + $v_size -= $v_read_size; + } + + // ----- Merge the file comments + $v_comment = $v_central_dir['comment'].' '.$v_central_dir_to_add['comment']; + + // ----- Calculate the size of the (new) central header + $v_size = @ftell($v_zip_temp_fd)-$v_offset; + + // ----- Swap the file descriptor + // Here is a trick : I swap the temporary fd with the zip fd, in order to use + // the following methods on the temporary fil and not the real archive fd + $v_swap = $this->zip_fd; + $this->zip_fd = $v_zip_temp_fd; + $v_zip_temp_fd = $v_swap; + + // ----- Create the central dir footer + if (($v_result = $this->privWriteCentralHeader($v_central_dir['entries']+$v_central_dir_to_add['entries'], $v_size, $v_offset, $v_comment)) != 1) + { + $this->privCloseFd(); + $p_archive_to_add->privCloseFd(); + @fclose($v_zip_temp_fd); + $this->zip_fd = null; + + // ----- Reset the file list + unset($v_header_list); + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + + // ----- Swap back the file descriptor + $v_swap = $this->zip_fd; + $this->zip_fd = $v_zip_temp_fd; + $v_zip_temp_fd = $v_swap; + + // ----- Close + $this->privCloseFd(); + $p_archive_to_add->privCloseFd(); + + // ----- Close the temporary file + @fclose($v_zip_temp_fd); + + // ----- Delete the zip file + // TBC : I should test the result ... + @unlink($this->zipname); + + // ----- Rename the temporary file + // TBC : I should test the result ... + //@rename($v_zip_temp_name, $this->zipname); + PclZipUtilRename($v_zip_temp_name, $this->zipname); + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privDuplicate() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privDuplicate($p_archive_filename) + { + //--(MAGIC-PclTrace)--//PclTraceFctStart(__FILE__, __LINE__, "PclZip::privDuplicate", "archive_filename='$p_archive_filename'"); + $v_result=1; + + // ----- Look if the $p_archive_filename exists + if (!is_file($p_archive_filename)) + { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Archive to duplicate does not exist. End of duplicate."); + + // ----- Nothing to duplicate, so duplicate is a success. + $v_result = 1; + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + + // ----- Open the zip file + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Open file in binary read mode"); + if (($v_result=$this->privOpenFd('wb')) != 1) + { + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + + // ----- Open the temporary file in write mode + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Open file in binary read mode"); + if (($v_zip_temp_fd = @fopen($p_archive_filename, 'rb')) == 0) + { + $this->privCloseFd(); + + PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open archive file \''.$p_archive_filename.'\' in binary write mode'); + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, PclZip::errorCode(), PclZip::errorInfo()); + return PclZip::errorCode(); + } + + // ----- Copy the files from the archive to the temporary file + // TBC : Here I should better append the file and go back to erase the central dir + $v_size = filesize($p_archive_filename); + while ($v_size != 0) + { + $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 5, "Read $v_read_size bytes"); + $v_buffer = fread($v_zip_temp_fd, $v_read_size); + @fwrite($this->zip_fd, $v_buffer, $v_read_size); + $v_size -= $v_read_size; + } + + // ----- Close + $this->privCloseFd(); + + // ----- Close the temporary file + @fclose($v_zip_temp_fd); + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privErrorLog() + // Description : + // Parameters : + // -------------------------------------------------------------------------------- + function privErrorLog($p_error_code=0, $p_error_string='') + { + if (PCLZIP_ERROR_EXTERNAL == 1) { + PclError($p_error_code, $p_error_string); + } + else { + $this->error_code = $p_error_code; + $this->error_string = $p_error_string; + } + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privErrorReset() + // Description : + // Parameters : + // -------------------------------------------------------------------------------- + function privErrorReset() + { + if (PCLZIP_ERROR_EXTERNAL == 1) { + PclErrorReset(); + } + else { + $this->error_code = 0; + $this->error_string = ''; + } + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privDecrypt() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privDecrypt($p_encryption_header, &$p_buffer, $p_size, $p_crc) + { + //--(MAGIC-PclTrace)--//PclTraceFctStart(__FILE__, __LINE__, 'PclZip::privDecrypt', "size=".$p_size.""); + $v_result=1; + + // ----- To Be Modified ;-) + $v_pwd = "test"; + + $p_buffer = PclZipUtilZipDecrypt($p_buffer, $p_size, $p_encryption_header, + $p_crc, $v_pwd); + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privDisableMagicQuotes() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privDisableMagicQuotes() + { + //--(MAGIC-PclTrace)--//PclTraceFctStart(__FILE__, __LINE__, 'PclZip::privDisableMagicQuotes', ""); + $v_result=1; + + // ----- Look if function exists + if ( (!function_exists("get_magic_quotes_runtime")) + || (!function_exists("set_magic_quotes_runtime"))) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Functions *et_magic_quotes_runtime are not supported"); + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + + // ----- Look if already done + if ($this->magic_quotes_status != -1) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "magic_quote already disabled"); + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + + // ----- Get and memorize the magic_quote value + $this->magic_quotes_status = @get_magic_quotes_runtime(); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Current magic_quotes_runtime status is '".($this->magic_quotes_status==0?'disable':'enable')."'"); + + // ----- Disable magic_quotes + if ($this->magic_quotes_status == 1) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Disable magic_quotes"); + //@set_magic_quotes_runtime(0); + } + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privSwapBackMagicQuotes() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privSwapBackMagicQuotes() + { + //--(MAGIC-PclTrace)--//PclTraceFctStart(__FILE__, __LINE__, 'PclZip::privSwapBackMagicQuotes', ""); + $v_result=1; + + // ----- Look if function exists + if ( (!function_exists("get_magic_quotes_runtime")) + || (!function_exists("set_magic_quotes_runtime"))) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Functions *et_magic_quotes_runtime are not supported"); + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + + // ----- Look if something to do + if ($this->magic_quotes_status != -1) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "magic_quote not modified"); + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + + // ----- Swap back magic_quotes + if ($this->magic_quotes_status == 1) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Enable back magic_quotes"); + //@set_magic_quotes_runtime($this->magic_quotes_status); + } + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + // -------------------------------------------------------------------------------- + + } + // End of class + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : PclZipUtilPathReduction() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function PclZipUtilPathReduction($p_dir) + { + //--(MAGIC-PclTrace)--//PclTraceFctStart(__FILE__, __LINE__, "PclZipUtilPathReduction", "dir='$p_dir'"); + $v_result = ""; + + // ----- Look for not empty path + if ($p_dir != "") { + // ----- Explode path by directory names + $v_list = explode("/", $p_dir); + + // ----- Study directories from last to first + $v_skip = 0; + for ($i=sizeof($v_list)-1; $i>=0; $i--) { + // ----- Look for current path + if ($v_list[$i] == ".") { + // ----- Ignore this directory + // Should be the first $i=0, but no check is done + } + else if ($v_list[$i] == "..") { + $v_skip++; + } + else if ($v_list[$i] == "") { + // ----- First '/' i.e. root slash + if ($i == 0) { + $v_result = "/".$v_result; + if ($v_skip > 0) { + // ----- It is an invalid path, so the path is not modified + // TBC + $v_result = $p_dir; + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Invalid path is unchanged"); + $v_skip = 0; + } + } + // ----- Last '/' i.e. indicates a directory + else if ($i == (sizeof($v_list)-1)) { + $v_result = $v_list[$i]; + } + // ----- Double '/' inside the path + else { + // ----- Ignore only the double '//' in path, + // but not the first and last '/' + } + } + else { + // ----- Look for item to skip + if ($v_skip > 0) { + $v_skip--; + } + else { + $v_result = $v_list[$i].($i!=(sizeof($v_list)-1)?"/".$v_result:""); + } + } + } + + // ----- Look for skip + if ($v_skip > 0) { + while ($v_skip > 0) { + $v_result = '../'.$v_result; + $v_skip--; + } + } + } + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : PclZipUtilPathInclusion() + // Description : + // This function indicates if the path $p_path is under the $p_dir tree. Or, + // said in an other way, if the file or sub-dir $p_path is inside the dir + // $p_dir. + // The function indicates also if the path is exactly the same as the dir. + // This function supports path with duplicated '/' like '//', but does not + // support '.' or '..' statements. + // Parameters : + // Return Values : + // 0 if $p_path is not inside directory $p_dir + // 1 if $p_path is inside directory $p_dir + // 2 if $p_path is exactly the same as $p_dir + // -------------------------------------------------------------------------------- + function PclZipUtilPathInclusion($p_dir, $p_path) + { + //--(MAGIC-PclTrace)--//PclTraceFctStart(__FILE__, __LINE__, "PclZipUtilPathInclusion", "dir='$p_dir', path='$p_path'"); + $v_result = 1; + + // ----- Explode dir and path by directory separator + $v_list_dir = explode("/", $p_dir); + $v_list_dir_size = sizeof($v_list_dir); + $v_list_path = explode("/", $p_path); + $v_list_path_size = sizeof($v_list_path); + + // ----- Study directories paths + $i = 0; + $j = 0; + while (($i < $v_list_dir_size) && ($j < $v_list_path_size) && ($v_result)) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 5, "Working on dir($i)='".$v_list_dir[$i]."' and path($j)='".$v_list_path[$j]."'"); + + // ----- Look for empty dir (path reduction) + if ($v_list_dir[$i] == '') { + $i++; + continue; + } + if ($v_list_path[$j] == '') { + $j++; + continue; + } + + // ----- Compare the items + if (($v_list_dir[$i] != $v_list_path[$j]) && ($v_list_dir[$i] != '') && ( $v_list_path[$j] != '')) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 5, "Items ($i,$j) are different"); + $v_result = 0; + } + + // ----- Next items + $i++; + $j++; + } + + // ----- Look if everything seems to be the same + if ($v_result) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 5, "Look for tie break"); + // ----- Skip all the empty items + while (($j < $v_list_path_size) && ($v_list_path[$j] == '')) $j++; + while (($i < $v_list_dir_size) && ($v_list_dir[$i] == '')) $i++; + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 5, "Looking on dir($i)='".($i < $v_list_dir_size?$v_list_dir[$i]:'')."' and path($j)='".($j < $v_list_path_size?$v_list_path[$j]:'')."'"); + + if (($i >= $v_list_dir_size) && ($j >= $v_list_path_size)) { + // ----- There are exactly the same + $v_result = 2; + } + else if ($i < $v_list_dir_size) { + // ----- The path is shorter than the dir + $v_result = 0; + } + } + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : PclZipUtilCopyBlock() + // Description : + // Parameters : + // $p_mode : read/write compression mode + // 0 : src & dest normal + // 1 : src gzip, dest normal + // 2 : src normal, dest gzip + // 3 : src & dest gzip + // Return Values : + // -------------------------------------------------------------------------------- + function PclZipUtilCopyBlock($p_src, $p_dest, $p_size, $p_mode=0) + { + //--(MAGIC-PclTrace)--//PclTraceFctStart(__FILE__, __LINE__, "PclZipUtilCopyBlock", "size=$p_size, mode=$p_mode"); + $v_result = 1; + + if ($p_mode==0) + { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 5, "Src offset before read :".(@ftell($p_src))); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 5, "Dest offset before write :".(@ftell($p_dest))); + while ($p_size != 0) + { + $v_read_size = ($p_size < PCLZIP_READ_BLOCK_SIZE ? $p_size : PCLZIP_READ_BLOCK_SIZE); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, "Read $v_read_size bytes"); + $v_buffer = @fread($p_src, $v_read_size); + @fwrite($p_dest, $v_buffer, $v_read_size); + $p_size -= $v_read_size; + } + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 5, "Src offset after read :".(@ftell($p_src))); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 5, "Dest offset after write :".(@ftell($p_dest))); + } + else if ($p_mode==1) + { + while ($p_size != 0) + { + $v_read_size = ($p_size < PCLZIP_READ_BLOCK_SIZE ? $p_size : PCLZIP_READ_BLOCK_SIZE); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, "Read $v_read_size bytes"); + $v_buffer = @gzread($p_src, $v_read_size); + @fwrite($p_dest, $v_buffer, $v_read_size); + $p_size -= $v_read_size; + } + } + else if ($p_mode==2) + { + while ($p_size != 0) + { + $v_read_size = ($p_size < PCLZIP_READ_BLOCK_SIZE ? $p_size : PCLZIP_READ_BLOCK_SIZE); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, "Read $v_read_size bytes"); + $v_buffer = @fread($p_src, $v_read_size); + @gzwrite($p_dest, $v_buffer, $v_read_size); + $p_size -= $v_read_size; + } + } + else if ($p_mode==3) + { + while ($p_size != 0) + { + $v_read_size = ($p_size < PCLZIP_READ_BLOCK_SIZE ? $p_size : PCLZIP_READ_BLOCK_SIZE); + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, "Read $v_read_size bytes"); + $v_buffer = @gzread($p_src, $v_read_size); + @gzwrite($p_dest, $v_buffer, $v_read_size); + $p_size -= $v_read_size; + } + } + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : PclZipUtilRename() + // Description : + // This function tries to do a simple rename() function. If it fails, it + // tries to copy the $p_src file in a new $p_dest file and then unlink the + // first one. + // Parameters : + // $p_src : Old filename + // $p_dest : New filename + // Return Values : + // 1 on success, 0 on failure. + // -------------------------------------------------------------------------------- + function PclZipUtilRename($p_src, $p_dest) + { + //--(MAGIC-PclTrace)--//PclTraceFctStart(__FILE__, __LINE__, "PclZipUtilRename", "source=$p_src, destination=$p_dest"); + $v_result = 1; + + // ----- Try to rename the files + if (!@rename($p_src, $p_dest)) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 5, "Fail to rename file, try copy+unlink"); + + // ----- Try to copy & unlink the src + if (!@copy($p_src, $p_dest)) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 5, "Fail to copy file"); + $v_result = 0; + } + else if (!@unlink($p_src)) { + //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 5, "Fail to unlink old filename"); + $v_result = 0; + } + } + + // ----- Return + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : PclZipUtilOptionText() + // Description : + // Translate option value in text. Mainly for debug purpose. + // Parameters : + // $p_option : the option value. + // Return Values : + // The option text value. + // -------------------------------------------------------------------------------- + function PclZipUtilOptionText($p_option) + { + //--(MAGIC-PclTrace)--//PclTraceFctStart(__FILE__, __LINE__, "PclZipUtilOptionText", "option='".$p_option."'"); + + $v_list = get_defined_constants(); + for (reset($v_list); $v_key = key($v_list); next($v_list)) { + $v_prefix = substr($v_key, 0, 10); + if ((($v_prefix == 'PCLZIP_OPT') || ($v_prefix == 'PCLZIP_CB_')) + && ($v_list[$v_key] == $p_option)) { + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_key); + return $v_key; + } + } + + $v_result = 'Unknown'; + + //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result); + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : PclZipUtilTranslateWinPath() + // Description : + // Translate windows path by replacing '\' by '/' and optionally removing + // drive letter. + // Parameters : + // $p_path : path to translate. + // $p_remove_disk_letter : true | false + // Return Values : + // The path translated. + // -------------------------------------------------------------------------------- + function PclZipUtilTranslateWinPath($p_path, $p_remove_disk_letter=true) + { + if (stristr(php_uname(), 'windows')) { + // ----- Look for potential disk letter + if (($p_remove_disk_letter) && (($v_position = strpos($p_path, ':')) != false)) { + $p_path = substr($p_path, $v_position+1); + } + // ----- Change potential windows directory separator + if ((strpos($p_path, '\\') > 0) || (substr($p_path, 0,1) == '\\')) { + $p_path = strtr($p_path, '\\', '/'); + } + } + return $p_path; + } + // -------------------------------------------------------------------------------- + + +?> diff --git a/include/pclzip/readme.txt b/include/pclzip/readme.txt new file mode 100644 index 00000000..16d226e6 --- /dev/null +++ b/include/pclzip/readme.txt @@ -0,0 +1,332 @@ +// -------------------------------------------------------------------------------- +// PclZip 2.4 - readme.txt +// -------------------------------------------------------------------------------- +// License GNU/LGPL - November 2004 +// Vincent Blavet - vincent@phpconcept.net +// http://www.phpconcept.net +// -------------------------------------------------------------------------------- + +// -------------------------------------------------------------------------------- + + + +0 - Sommaire +============ + 1 - Introduction + 2 - What's new + 3 - Corrected bugs + 4 - Known bugs or limitations + 5 - License + 6 - Warning + 7 - Author + 8 - Contribute + +1 - Introduction +================ + + PclZip is a library that allow you to manage a Zip archive. + + Full documentation about PclZip can be found here : http://www.phpconcept.net/pclzip + +2 - What's new +============== + + Version 2.4 : + - Code improvment : try to speed up the code by removing unusefull call to pack() + - Correct bug in delete() : delete() should be called with no argument. This was not + the case in 2.3. This is corrected in 2.4. + - Correct a bug in path_inclusion function. When the path has several '../../', the + result was bad. + - Add a check for magic_quotes_runtime configuration. If enabled, PclZip will + disable it while working and det it back to its original value. + This resolve a lots of bad formated archive errors. + - Bug correction : PclZip now correctly unzip file in some specific situation, + when compressed content has same size as uncompressed content. + - Bug correction : When selecting option 'PCLZIP_OPT_REMOVE_ALL_PATH', + directories are not any more created. + - Code improvment : correct unclosed opendir(), better handling of . and .. in + loops. + + + Version 2.3 : + - Correct a bug with PHP5 : affecting the value 0xFE49FFE0 to a variable does not + give the same result in PHP4 and PHP5 .... + + Version 2.2 : + - Try development of PCLZIP_OPT_CRYPT ..... + However this becomes to a stop. To crypt/decrypt I need to multiply 2 long integers, + the result (greater than a long) is not supported by PHP. Even the use of bcmath + functions does not help. I did not find yet a solution ...; + - Add missing '/' at end of directory entries + - Check is a file is encrypted or not. Returns status 'unsupported_encryption' and/or + error code PCLZIP_ERR_UNSUPPORTED_ENCRYPTION. + - Corrected : Bad "version need to extract" field in local file header + - Add private method privCheckFileHeaders() in order to check local and central + file headers. PclZip is now supporting purpose bit flag bit 3. Purpose bit flag bit 3 gives + the ability to have a local file header without size, compressed size and crc filled. + - Add a generic status 'error' for file status + - Add control of compression type. PclZip only support deflate compression method. + Before v2.2, PclZip does not check the compression method used in an archive while + extracting. With v2.2 PclZip returns a new error status for a file using an unsupported + compression method. New status is "unsupported_compression". New error code is + PCLZIP_ERR_UNSUPPORTED_COMPRESSION. + - Add optional attribute PCLZIP_OPT_STOP_ON_ERROR. This will stop the extract of files + when errors like 'a folder with same name exists' or 'a newer file exists' or + 'a write protected file' exists, rather than set a status for the concerning file + and resume the extract of the zip. + - Add optional attribute PCLZIP_OPT_REPLACE_NEWER. This will force, during an extract' the + replacement of the file, even if a newer version of the file exists. + Note that today if a file with the same name already exists but is older it will be + replaced by the extracted one. + - Improve PclZipUtilOption() + - Support of zip archive with trailing bytes. Before 2.2, PclZip checks that the central + directory structure is the last data in the archive. Crypt encryption/decryption of + zip archive put trailing 0 bytes after decryption. PclZip is now supporting this. + + Version 2.1 : + - Add the ability to abort the extraction by using a user callback function. + The user can now return the value '2' in its callback which indicates to stop the + extraction. For a pre call-back extract is stopped before the extration of the current + file. For a post call back, the extraction is stopped after. + - Add the ability to extract a file (or several files) directly in the standard output. + This is done by the new parameter PCLZIP_OPT_EXTRACT_IN_OUTPUT with method extract(). + - Add support for parameters PCLZIP_OPT_COMMENT, PCLZIP_OPT_ADD_COMMENT, + PCLZIP_OPT_PREPEND_COMMENT. This will create, replace, add, or prepend comments + in the zip archive. + - When merging two archives, the comments are not any more lost, but merged, with a + blank space separator. + - Corrected bug : Files are not deleted when all files are asked to be deleted. + - Corrected bug : Folders with name '0' made PclZip to abort the create or add feature. + + + Version 2.0 : + ***** Warning : Some new features may break the backward compatibility for your scripts. + Please carefully read the readme file. + - Add the ability to delete by Index, name and regular expression. This feature is + performed by the method delete(), which uses the optional parameters + PCLZIP_OPT_BY_INDEX, PCLZIP_OPT_BY_NAME, PCLZIP_OPT_BY_EREG or PCLZIP_OPT_BY_PREG. + - Add the ability to extract by regular expression. To extract by regexp you must use the method + extract(), with the option PCLZIP_OPT_BY_EREG or PCLZIP_OPT_BY_PREG + (depending if you want to use ereg() or preg_match() syntax) followed by the + regular expression pattern. + - Add the ability to extract by index, directly with the extract() method. This is a + code improvment of the extractByIndex() method. + - Add the ability to extract by name. To extract by name you must use the method + extract(), with the option PCLZIP_OPT_BY_NAME followed by the filename to + extract or an array of filenames to extract. To extract all a folder, use the folder + name rather than the filename with a '/' at the end. + - Add the ability to add files without compression. This is done with a new attribute + which is PCLZIP_OPT_NO_COMPRESSION. + - Add the attribute PCLZIP_OPT_EXTRACT_AS_STRING, which allow to extract a file directly + in a string without using any file (or temporary file). + - Add constant PCLZIP_SEPARATOR for static configuration of filename separators in a single string. + The default separator is now a comma (,) and not any more a blank space. + THIS BREAK THE BACKWARD COMPATIBILITY : Please check if this may have an impact with + your script. + - Improve algorythm performance by removing the use of temporary files when adding or + extracting files in an archive. + - Add (correct) detection of empty filename zipping. This can occurs when the removed + path is the same + as a zipped dir. The dir is not zipped (['status'] = filtered), only its content. + - Add better support for windows paths (thanks for help from manus@manusfreedom.com). + - Corrected bug : When the archive file already exists with size=0, the add() method + fails. Corrected in 2.0. + - Remove the use of OS_WINDOWS constant. Use php_uname() function rather. + - Control the order of index ranges in extract by index feature. + - Change the internal management of folders (better handling of internal flag). + + + Version 1.3 : + - Removing the double include check. This is now done by include_once() and require_once() + PHP directives. + - Changing the error handling mecanism : Remove the use of an external error library. + The former PclError...() functions are replaced by internal equivalent methods. + By changing the environment variable PCLZIP_ERROR_EXTERNAL you can still use the former library. + Introducing the use of constants for error codes rather than integer values. This will help + in futur improvment. + Introduction of error handling functions like errorCode(), errorName() and errorInfo(). + - Remove the deprecated use of calling function with arguments passed by reference. + - Add the calling of extract(), extractByIndex(), create() and add() functions + with variable options rather than fixed arguments. + - Add the ability to remove all the file path while extracting or adding, + without any need to specify the path to remove. + This is available for extract(), extractByIndex(), create() and add() functionS by using + the new variable options parameters : + - PCLZIP_OPT_REMOVE_ALL_PATH : by indicating this option while calling the fct. + - Ability to change the mode of a file after the extraction (chmod()). + This is available for extract() and extractByIndex() functionS by using + the new variable options parameters. + - PCLZIP_OPT_SET_CHMOD : by setting the value of this option. + - Ability to definition call-back options. These call-back will be called during the adding, + or the extracting of file (extract(), extractByIndex(), create() and add() functions) : + - PCLZIP_CB_PRE_EXTRACT : will be called before each extraction of a file. The user + can trigerred the change the filename of the extracted file. The user can triggered the + skip of the extraction. This is adding a 'skipped' status in the file list result value. + - PCLZIP_CB_POST_EXTRACT : will be called after each extraction of a file. + Nothing can be triggered from that point. + - PCLZIP_CB_PRE_ADD : will be called before each add of a file. The user + can trigerred the change the stored filename of the added file. The user can triggered the + skip of the add. This is adding a 'skipped' status in the file list result value. + - PCLZIP_CB_POST_ADD : will be called after each add of a file. + Nothing can be triggered from that point. + - Two status are added in the file list returned as function result : skipped & filename_too_long + 'skipped' is used when a call-back function ask for skipping the file. + 'filename_too_long' is used while adding a file with a too long filename to archive (the file is + not added) + - Adding the function PclZipUtilPathInclusion(), that check the inclusion of a path into + a directory. + - Add a check of the presence of the archive file before some actions (like list, ...) + - Add the initialisation of field "index" in header array. This means that by + default index will be -1 when not explicitly set by the methods. + + Version 1.2 : + - Adding a duplicate function. + - Adding a merge function. The merge function is a "quick merge" function, + it just append the content of an archive at the end of the first one. There + is no check for duplicate files or more recent files. + - Improve the search of the central directory end. + + Version 1.1.2 : + + - Changing the license of PclZip. PclZip is now released under the GNU / LGPL license + (see License section). + - Adding the optional support of a static temporary directory. You will need to configure + the constant PCLZIP_TEMPORARY_DIR if you want to use this feature. + - Improving the rename() function. In some cases rename() does not work (different + Filesystems), so it will be replaced by a copy() + unlink() functions. + + Version 1.1.1 : + + - Maintenance release, no new feature. + + Version 1.1 : + + - New method Add() : adding files in the archive + - New method ExtractByIndex() : partial extract of the archive, files are identified by + their index in the archive + - New method DeleteByIndex() : delete some files/folder entries from the archive, + files are identified by their index in the archive. + - Adding a test of the zlib extension presence. If not present abort the script. + + Version 1.0.1 : + + - No new feature + + +3 - Corrected bugs +================== + + Corrected in Version 2.0 : + - Corrected : During an extraction, if a call-back fucntion is used and try to skip + a file, all the extraction process is stopped. + + Corrected in Version 1.3 : + - Corrected : Support of static synopsis for method extract() is broken. + - Corrected : invalid size of archive content field (0xFF) should be (0xFFFF). + - Corrected : When an extract is done with a remove_path parameter, the entry for + the directory with exactly the same path is not skipped/filtered. + - Corrected : extractByIndex() and deleteByIndex() were not managing index in the + right way. For example indexes '1,3-5,11' will only extract files 1 and 11. This + is due to a sort of the index resulting table that puts 11 before 3-5 (sort on + string and not interger). The sort is temporarilly removed, this means that + you must provide a sorted list of index ranges. + + Corrected in Version 1.2 : + + - Nothing. + + Corrected in Version 1.1.2 : + + - Corrected : Winzip is unable to delete or add new files in a PclZip created archives. + + Corrected in Version 1.1.1 : + + - Corrected : When archived file is not compressed (0% compression), the + extract method fails. + + Corrected in Version 1.1 : + + - Corrected : Adding a complete tree of folder may result in a bad archive + creation. + + Corrected in Version 1.0.1 : + + - Corrected : Error while compressing files greater than PCLZIP_READ_BLOCK_SIZE (default=1024). + + +4 - Known bugs or limitations +============================= + + Please publish bugs reports in SourceForge : + http://sourceforge.net/tracker/?group_id=40254&atid=427564 + + In Version 2.x : + - PclZip does only support file uncompressed or compressed with deflate (compression method 8) + - PclZip does not support password protected zip archive + + In Version 1.2 : + + - merge() methods does not check for duplicate files or last date of modifications. + + In Version 1.1 : + + - Limitation : Using 'extract' fields in the file header in the zip archive is not supported. + - WinZip is unable to delete a single file in a PclZip created archive. It is also unable to + add a file in a PclZip created archive. (Corrected in v.1.2) + + In Version 1.0.1 : + + - Adding a complete tree of folder may result in a bad archive + creation. (Corrected in V.1.1). + - Path given to methods must be in the unix format (/) and not the Windows format (\). + Workaround : Use only / directory separators. + - PclZip is using temporary files that are sometime the name of the file with a .tmp or .gz + added suffix. Files with these names may already exist and may be overwritten. + Workaround : none. + - PclZip does not check if the zlib extension is present. If it is absent, the zip + file is not created and the lib abort without warning. + Workaround : enable the zlib extension on the php install + + In Version 1.0 : + + - Error while compressing files greater than PCLZIP_READ_BLOCK_SIZE (default=1024). + (Corrected in v.1.0.1) + - Limitation : Multi-disk zip archive are not supported. + + +5 - License +=========== + + Since version 1.1.2, PclZip Library is released under GNU/LGPL license. + This library is free, so you can use it at no cost. + + HOWEVER, if you release a script, an application, a library or any kind of + code using PclZip library (or a part of it), YOU MUST : + - Indicate in the documentation (or a readme file), that your work + uses PclZip Library, and make a reference to the author and the web site + http://www.phpconcept.net + - Gives the ability to the final user to update the PclZip libary. + + I will also appreciate that you send me a mail (vincent@phpconcept.net), just to + be aware that someone is using PclZip. + + For more information about GNU/LGPL license : http://www.gnu.org + +6 - Warning +================= + + This library and the associated files are non commercial, non professional work. + It should not have unexpected results. However if any damage is caused by this software + the author can not be responsible. + The use of this software is at the risk of the user. + +7 - Author +========== + + This software was written by Vincent Blavet (vincent@phpconcept.net) on its leasure time. + +8 - Contribute +============== + If you want to contribute to the development of PclZip, please contact vincent@phpconcept.net. + If you can help in financing PhpConcept hosting service, please go to + http://www.phpconcept.net/soutien.php \ No newline at end of file diff --git a/include/phpmailer/README b/include/phpmailer/README new file mode 100644 index 00000000..16dd4a01 --- /dev/null +++ b/include/phpmailer/README @@ -0,0 +1,193 @@ +/******************************************************************* +* The http://phpmailer.codeworxtech.com/ website now carries a few * +* advertisements through the Google Adsense network. Please visit * +* the advertiser sites and help us offset some of our costs. * +* Thanks .... * +********************************************************************/ + +PHPMailer +Full Featured Email Transfer Class for PHP +========================================== + +Version 2.3 (November 08, 2008) + +We have removed the /phpdoc from the downloads. All documentation is now on +the http://phpmailer.codeworxtech.com website. + +The phpunit.php has been updated to support PHP5. + +For all other changes and notes, please see the changelog. + +Donations are accepted at PayPal with our id "paypal@worxteam.com". + +Version 2.2 (July 15 2008) + +- see the changelog. + +Version 2.1 (June 04 2008) + +With this release, we are announcing that the development of PHPMailer for PHP5 +will be our focus from this date on. We have implemented all the enhancements +and fixes from the latest release of PHPMailer for PHP4. + +Far more important, though, is that this release of PHPMailer (v2.1) is +fully tested with E_STRICT error checking enabled. + +** NOTE: WE HAVE A NEW LANGUAGE VARIABLE FOR DIGITALLY SIGNED S/MIME EMAILS. + IF YOU CAN HELP WITH LANGUAGES OTHER THAN ENGLISH AND SPANISH, IT WOULD BE + APPRECIATED. + +We have now added S/MIME functionality (ability to digitally sign emails). +BIG THANKS TO "sergiocambra" for posting this patch back in November 2007. +The "Signed Emails" functionality adds the Sign method to pass the private key +filename and the password to read it, and then email will be sent with +content-type multipart/signed and with the digital signature attached. + +A quick note on E_STRICT: + +- In about half the test environments the development version was subjected + to, an error was thrown for the date() functions (used at line 1565 and 1569). + This is NOT a PHPMailer error, it is the result of an incorrectly configured + PHP5 installation. The fix is to modify your 'php.ini' file and include the + date.timezone = America/New York + directive, (for your own server timezone) +- If you do get this error, and are unable to access your php.ini file, there is + a workaround. In your PHP script, add + date_default_timezone_set('America/Toronto'); + + * do NOT try to use + $myVar = date_default_timezone_get(); + as a test, it will throw an error. + +We have also included more example files to show the use of "mail()", +"smtp", and "gmail". + +We are also looking for more programmers to join the volunteer development team. +If you have an interest in this, please let us know. + +Enjoy! + + +Version 2.1.0beta1 & beta2 + +please note, this is BETA software +** DO NOT USE THIS IN PRODUCTION OR LIVE PROJECTS +INTENDED STRICTLY FOR TESTING + +** NOTE: + +As of November 2007, PHPMailer has a new project team headed by industry +veteran Andy Prevost (codeworxtech). The first release in more than two +years will focus on fixes, adding ease-of-use enhancements, provide +basic compatibility with PHP4 and PHP5 using PHP5 backwards compatibility +features. A new release is planned before year-end 2007 that will provide +full compatiblity with PHP4 and PHP5, as well as more bug fixes. + +We are looking for project developers to assist in restoring PHPMailer to +its leadership position. Our goals are to simplify use of PHPMailer, provide +good documentation and examples, and retain backward compatibility to level +1.7.3 standards. + +If you are interested in helping out, visit http://sourceforge.net/projects/phpmailer +and indicate your interest. + +** + +http://phpmailer.sourceforge.net/ + +This software is licenced under the LGPL. Please read LICENSE for information on the +software availability and distribution. + +Class Features: +- Send emails with multiple TOs, CCs, BCCs and REPLY-TOs +- Redundant SMTP servers +- Multipart/alternative emails for mail clients that do not read HTML email +- Support for 8bit, base64, binary, and quoted-printable encoding +- Uses the same methods as the very popular AspEmail active server (COM) component +- SMTP authentication +- Native language support +- Word wrap, and more! + +Why you might need it: + +Many PHP developers utilize email in their code. The only PHP function +that supports this is the mail() function. However, it does not expose +any of the popular features that many email clients use nowadays like +HTML-based emails and attachments. There are two proprietary +development tools out there that have all the functionality built into +easy to use classes: AspEmail(tm) and AspMail. Both of these +programs are COM components only available on Windows. They are also a +little pricey for smaller projects. + +Since I do Linux development I’ve missed these tools for my PHP coding. +So I built a version myself that implements the same methods (object +calls) that the Windows-based components do. It is open source and the +LGPL license allows you to place the class in your proprietary PHP +projects. + + +Installation: + +Copy class.phpmailer.php into your php.ini include_path. If you are +using the SMTP mailer then place class.smtp.php in your path as well. +In the language directory you will find several files like +phpmailer.lang-en.php. If you look right before the .php extension +that there are two letters. These represent the language type of the +translation file. For instance "en" is the English file and "br" is +the Portuguese file. Chose the file that best fits with your language +and place it in the PHP include path. If your language is English +then you have nothing more to do. If it is a different language then +you must point PHPMailer to the correct translation. To do this, call +the PHPMailer SetLanguage method like so: + +// To load the Portuguese version +$mail->SetLanguage("br", "/optional/path/to/language/directory/"); + +That's it. You should now be ready to use PHPMailer! + + +A Simple Example: + +IsSMTP(); // set mailer to use SMTP +$mail->Host = "smtp1.example.com;smtp2.example.com"; // specify main and backup server +$mail->SMTPAuth = true; // turn on SMTP authentication +$mail->Username = "jswan"; // SMTP username +$mail->Password = "secret"; // SMTP password + +$mail->From = "from@example.com"; +$mail->FromName = "Mailer"; +$mail->AddAddress("josh@example.net", "Josh Adams"); +$mail->AddAddress("ellen@example.com"); // name is optional +$mail->AddReplyTo("info@example.com", "Information"); + +$mail->WordWrap = 50; // set word wrap to 50 characters +$mail->AddAttachment("/var/tmp/file.tar.gz"); // add attachments +$mail->AddAttachment("/tmp/image.jpg", "new.jpg"); // optional name +$mail->IsHTML(true); // set email format to HTML + +$mail->Subject = "Here is the subject"; +$mail->Body = "This is the HTML message body in bold!"; +$mail->AltBody = "This is the body in plain text for non-HTML mail clients"; + +if(!$mail->Send()) +{ + echo "Message could not be sent.

    "; + echo "Mailer Error: " . $mail->ErrorInfo; + exit; +} + +echo "Message has been sent"; +?> + +CHANGELOG + +See ChangeLog.txt + +Download: http://sourceforge.net/project/showfiles.php?group_id=26031 + +Andy Prevost diff --git a/include/phpmailer/class.phpmailer.php b/include/phpmailer/class.phpmailer.php new file mode 100644 index 00000000..a5be5b28 --- /dev/null +++ b/include/phpmailer/class.phpmailer.php @@ -0,0 +1,2010 @@ + + 2011-03-03 18:00:00 -0700 (Thu, 03 Mar 2011) - eddy - bug 31778 - added html chars (apostrophe and ampersand) back to email address before sending + +r58121 - 2010-09-09 11:35:17 -0700 (Thu, 09 Sep 2010) - kjing - Merge: 717e037 0ca4d1c +Author: Jenny Gonsalves + Merge branch 'master' of git+ssh://github.com/sugarcrm/Mango + +r57158 - 2010-06-27 20:13:23 -0700 (Sun, 27 Jun 2010) - kjing - commit a2a7548e2a06c075c99a17472c9c5672e1ec1926 +Author: John Mertic + Bug 8312 - Set the encoding type to 'base64' by default if we are sending an HTML email + +r56990 - 2010-06-16 13:05:36 -0700 (Wed, 16 Jun 2010) - kjing - snapshot "Mango" svn branch to a new one for GitHub sync + +r56989 - 2010-06-16 13:01:33 -0700 (Wed, 16 Jun 2010) - kjing - defunt "Mango" svn dev branch before github cutover + +r55980 - 2010-04-19 13:31:28 -0700 (Mon, 19 Apr 2010) - kjing - create Mango (6.1) based on windex + +r55695 - 2010-03-30 17:46:05 -0700 (Tue, 30 Mar 2010) - mitani - #36026 +Fixes an issue where CCed recipents would not be listed in the email. Need to upgrade PHP Mailer later on to the latest + +r51719 - 2009-10-22 10:18:00 -0700 (Thu, 22 Oct 2009) - mitani - Converted to Build 3 tags and updated the build system + +r51634 - 2009-10-19 13:32:22 -0700 (Mon, 19 Oct 2009) - mitani - Windex is the branch for Sugar Sales 1.0 development + +r51443 - 2009-10-12 13:34:36 -0700 (Mon, 12 Oct 2009) - jmertic - Bug 33332 - Made application PHP 5.3 compliant with E_DEPRECATED warnings on by: +- Changing all ereg function to either preg or simple string based ones +- No more references to magic quotes. +- Change all the session_unregister() functions to just unset() the correct session variable instead. + +r51251 - 2009-09-30 09:30:59 -0700 (Wed, 30 Sep 2009) - roger - svn merge from Tokyo rev: 50982 - 51248. + +r50983 - 2009-09-21 13:45:37 -0700 (Mon, 21 Sep 2009) - ajay - Merged code from branches/tokyo version 50739 thru 50982 + +r50519 - 2009-08-31 15:20:00 -0700 (Mon, 31 Aug 2009) - sgandhi - 31348 + +r50375 - 2009-08-24 18:07:43 -0700 (Mon, 24 Aug 2009) - dwong - branch kobe2 from tokyo r50372 + +r50023 - 2009-08-07 16:30:05 -0700 (Fri, 07 Aug 2009) - eddy - Bug 32412 +Split logic in file to allow string to be parsed for template conversion +include/phpmailer/class.phpmailer.php + +r43691 - 2009-01-29 15:25:53 -0800 (Thu, 29 Jan 2009) - faissah - 27521 : Update to phpmailer version 2.3. + +r42807 - 2008-12-29 11:16:59 -0800 (Mon, 29 Dec 2008) - dwong - Branch from trunk/sugarcrm r42806 to branches/tokyo/sugarcrm + +r39785 - 2008-09-12 15:49:45 -0700 (Fri, 12 Sep 2008) - faissah - Update to PHPmailer 2.2.1 + +r39146 - 2008-08-26 17:16:04 -0700 (Tue, 26 Aug 2008) - awu - Merging pre_5_1_0 to trunk + +r23880 - 2007-06-26 15:14:35 -0700 (Tue, 26 Jun 2007) - julian - Fix for bug #13475: security vulnerability in phpmailer + +r11652 - 2006-02-21 18:24:06 -0800 (Tue, 21 Feb 2006) - chris - Bug 4719: updating PHPMailer classes for security (DDoS) +Touched: +include/phpmailer (everything) +include/SugarPHPMailer.php (adding our constructor) +modules/Email/Email.php (to use the new constructor) + +r10887 - 2006-01-05 22:51:15 -0800 (Thu, 05 Jan 2006) - chris - Bug 3979: fixed filename generation issues that caused PDFs to be sent with the wrong encoding type + +r10886 - 2006-01-05 18:24:55 -0800 (Thu, 05 Jan 2006) - chris - Bug 3979: initial code checkin to get reports scheduling in Scheduler + +r6053 - 2005-07-06 01:04:42 -0700 (Wed, 06 Jul 2005) - clint - Bug #1400 +Even if I have "Clint Oram " in the to field, I only end up seeing "clint@sugarcrm.com" in the received email. + +r5104 - 2005-05-04 15:33:41 -0700 (Wed, 04 May 2005) - majed - gets rid of HTTP_GET_VARS and what not which has been deprecated + +r1573 - 2004-10-29 17:23:17 -0700 (Fri, 29 Oct 2004) - julian - Fix: path to phpmailer language file wrong + +r915 - 2004-10-08 15:31:10 -0700 (Fri, 08 Oct 2004) - julian - E-mail notification feature + new admin console + + +*/ + + +/*~ class.phpmailer.php +.---------------------------------------------------------------------------. +| Software: PHPMailer - PHP email class | +| Version: 2.3 | +| Contact: via sourceforge.net support pages (also www.codeworxtech.com) | +| Info: http://phpmailer.sourceforge.net | +| Support: http://sourceforge.net/projects/phpmailer/ | +| ------------------------------------------------------------------------- | +| Author: Andy Prevost (project admininistrator) | +| Author: Brent R. Matzelle (original founder) | +| Copyright (c) 2004-2007, Andy Prevost. All Rights Reserved. | +| Copyright (c) 2001-2003, Brent R. Matzelle | +| ------------------------------------------------------------------------- | +| License: Distributed under the Lesser General Public License (LGPL) | +| http://www.gnu.org/copyleft/lesser.html | +| This program is distributed in the hope that it will be useful - WITHOUT | +| ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | +| FITNESS FOR A PARTICULAR PURPOSE. | +| ------------------------------------------------------------------------- | +| We offer a number of paid services (www.codeworxtech.com): | +| - Web Hosting on highly optimized fast and secure servers | +| - Technology Consulting | +| - Oursourcing (highly qualified programmers and graphic designers) | +'---------------------------------------------------------------------------' + +/** + * PHPMailer - PHP email transport class + * NOTE: Designed for use with PHP version 5 and up + * @package PHPMailer + * @author Andy Prevost + * @copyright 2004 - 2008 Andy Prevost +*/ + +class PHPMailer { + + ///////////////////////////////////////////////// + // PROPERTIES, PUBLIC + ///////////////////////////////////////////////// + + /** + * Email priority (1 = High, 3 = Normal, 5 = low). + * @var int + */ + public $Priority = 3; + + /** + * Sets the CharSet of the message. + * @var string + */ + public $CharSet = 'utf-8'; + + /** + * Sets the Content-type of the message. + * @var string + */ + public $ContentType = 'text/plain'; + + /** + * Sets the Encoding of the message. Options for this are "8bit", + * "7bit", "binary", "base64", and "quoted-printable". + * @var string + */ + public $Encoding = '8bit'; + + /** + * Holds the most recent mailer error message. + * @var string + */ + public $ErrorInfo = ''; + + /** + * Sets the From email address for the message. + * @var string + */ + public $From = 'root@localhost'; + + /** + * Sets the From name of the message. + * @var string + */ + public $FromName = 'Root User'; + + /** + * Sets the Sender email (Return-Path) of the message. If not empty, + * will be sent via -f to sendmail or as 'MAIL FROM' in smtp mode. + * @var string + */ + public $Sender = ''; + + /** + * Sets the Subject of the message. + * @var string + */ + public $Subject = ''; + + /** + * Sets the Body of the message. This can be either an HTML or text body. + * If HTML then run IsHTML(true). + * @var string + */ + public $Body = ''; + + /** + * Sets the text-only body of the message. This automatically sets the + * email to multipart/alternative. This body can be read by mail + * clients that do not have HTML email capability such as mutt. Clients + * that can read HTML will view the normal Body. + * @var string + */ + public $AltBody = ''; + + /** + * Sets word wrapping on the body of the message to a given number of + * characters. + * @var int + */ + public $WordWrap = 0; + + /** + * Method to send mail: ("mail", "sendmail", or "smtp"). + * @var string + */ + public $Mailer = 'mail'; + + /** + * Sets the path of the sendmail program. + * @var string + */ + public $Sendmail = '/usr/sbin/sendmail'; + + + /** + * Path to PHPMailer plugins. This is now only useful if the SMTP class + * is in a different directory than the PHP include path. + * @var string + */ + public $PluginDir = 'include/phpmailer/'; + + /** + * Holds PHPMailer version. + * @var string + */ + public $Version = "2.3"; + + /** + * Sets the email address that a reading confirmation will be sent. + * @var string + */ + public $ConfirmReadingTo = ''; + + /** + * Sets the hostname to use in Message-Id and Received headers + * and as default HELO string. If empty, the value returned + * by SERVER_NAME is used or 'localhost.localdomain'. + * @var string + */ + public $Hostname = ''; + + /** + * Sets the message ID to be used in the Message-Id header. + * If empty, a unique id will be generated. + * @var string + */ + public $MessageID = ''; + + ///////////////////////////////////////////////// + // PROPERTIES FOR SMTP + ///////////////////////////////////////////////// + + /** + * Sets the SMTP hosts. All hosts must be separated by a + * semicolon. You can also specify a different port + * for each host by using this format: [hostname:port] + * (e.g. "smtp1.example.com:25;smtp2.example.com"). + * Hosts will be tried in order. + * @var string + */ + public $Host = 'localhost'; + + /** + * Sets the default SMTP server port. + * @var int + */ + public $Port = 25; + + /** + * Sets the SMTP HELO of the message (Default is $Hostname). + * @var string + */ + public $Helo = ''; + + /** + * Sets connection prefix. + * Options are "", "ssl" or "tls" + * @var string + */ + public $SMTPSecure = ""; + + /** + * Sets SMTP authentication. Utilizes the Username and Password variables. + * @var bool + */ + public $SMTPAuth = false; + + /** + * Sets SMTP username. + * @var string + */ + public $Username = ''; + + /** + * Sets SMTP password. + * @var string + */ + public $Password = ''; + + /** + * Sets the SMTP server timeout in seconds. This function will not + * work with the win32 version. + * @var int + */ + public $Timeout = 10; + + /** + * Sets SMTP class debugging on or off. + * @var bool + */ + public $SMTPDebug = false; + + /** + * Prevents the SMTP connection from being closed after each mail + * sending. If this is set to true then to close the connection + * requires an explicit call to SmtpClose(). + * @var bool + */ + public $SMTPKeepAlive = false; + + /** + * Provides the ability to have the TO field process individual + * emails, instead of sending to entire TO addresses + * @var bool + */ + public $SingleTo = false; + + /** + * Provides the ability to change the line ending + * @var string + */ + public $LE = "\r\n"; + + ///////////////////////////////////////////////// + // PROPERTIES, PRIVATE + ///////////////////////////////////////////////// + + public $smtp = NULL; + private $to = array(); + private $cc = array(); + private $bcc = array(); + private $ReplyTo = array(); + public $attachment = array(); + private $CustomHeader = array(); + private $message_type = ''; + public $boundary = array(); + private $language = array(); + private $error_count = 0; + private $sign_cert_file = ""; + private $sign_key_file = ""; + private $sign_key_pass = ""; + + ///////////////////////////////////////////////// + // METHODS, VARIABLES + ///////////////////////////////////////////////// + + /** + * Sets message type to HTML. + * @param bool $bool + * @return void + */ + public function IsHTML($bool) { + if($bool == true) { + $this->ContentType = 'text/html'; + $this->Encoding = 'base64'; + } else { + $this->ContentType = 'text/plain'; + $this->Encoding = 'quoted-printable'; + } + } + + /** + * Sets Mailer to send message using SMTP. + * @return void + */ + public function IsSMTP() { + $this->Mailer = 'smtp'; + } + + /** + * Sets Mailer to send message using PHP mail() function. + * @return void + */ + public function IsMail() { + $this->Mailer = 'mail'; + } + + /** + * Sets Mailer to send message using the $Sendmail program. + * @return void + */ + public function IsSendmail() { + $this->Mailer = 'sendmail'; + } + + /** + * Sets Mailer to send message using the qmail MTA. + * @return void + */ + public function IsQmail() { + $this->Sendmail = '/var/qmail/bin/sendmail'; + $this->Mailer = 'sendmail'; + } + + ///////////////////////////////////////////////// + // METHODS, RECIPIENTS + ///////////////////////////////////////////////// + + /** + * Adds a "To" address. + * @param string $address + * @param string $name + * @return void + */ + public function AddAddress($address, $name = '') { + $cur = count($this->to); + $this->to[$cur][0] = trim($address); + $this->to[$cur][1] = $name; + } + + /** + * Adds a "Cc" address. Note: this function works + * with the SMTP mailer on win32, not with the "mail" + * mailer. + * @param string $address + * @param string $name + * @return void + */ + public function AddCC($address, $name = '') { + $cur = count($this->cc); + $this->cc[$cur][0] = trim($address); + $this->cc[$cur][1] = $name; + } + + /** + * Adds a "Bcc" address. Note: this function works + * with the SMTP mailer on win32, not with the "mail" + * mailer. + * @param string $address + * @param string $name + * @return void + */ + public function AddBCC($address, $name = '') { + $cur = count($this->bcc); + $this->bcc[$cur][0] = trim($address); + $this->bcc[$cur][1] = $name; + } + + /** + * Adds a "Reply-to" address. + * @param string $address + * @param string $name + * @return void + */ + public function AddReplyTo($address, $name = '') { + $cur = count($this->ReplyTo); + $this->ReplyTo[$cur][0] = trim($address); + $this->ReplyTo[$cur][1] = $name; + } + + ///////////////////////////////////////////////// + // METHODS, MAIL SENDING + ///////////////////////////////////////////////// + + /** + * Creates message and assigns Mailer. If the message is + * not sent successfully then it returns false. Use the ErrorInfo + * variable to view description of the error. + * @return bool + */ + public function Send() { + $header = ''; + $body = ''; + $result = true; + + if((count($this->to) + count($this->cc) + count($this->bcc)) < 1) { + $this->SetError($this->Lang('provide_address')); + return false; + } + + //iterate through recipients and add back in html characters (apostrophe ' and ampersand &) to email addresses + //this was causing email bounces in names like "O'Reilly@example.com" being sent over as "O'Reilly@example.com" + foreach($this->to as $k=>$addr){ + $this->to[$k][0] = htmlspecialchars_decode($addr[0],ENT_QUOTES); + } + foreach($this->cc as $k=>$addr){ + $this->cc[$k][0] = htmlspecialchars_decode($addr[0],ENT_QUOTES); + } + foreach($this->bcc as $k=>$addr){ + $this->bcc[$k][0] = htmlspecialchars_decode($addr[0],ENT_QUOTES); + } + + /* Set whether the message is multipart/alternative */ + if(!empty($this->AltBody)) { + $this->ContentType = 'multipart/alternative'; + } + + $this->error_count = 0; // reset errors + $this->SetMessageType(); + $header .= $this->CreateHeader(); + $body = $this->CreateBody(); + + if($body == '') { + return false; + } + + /* Choose the mailer */ + switch($this->Mailer) { + case 'sendmail': + $result = $this->SendmailSend($header, $body); + break; + case 'smtp': + $result = $this->SmtpSend($header, $body); + break; + case 'mail': + $result = $this->MailSend($header, $body); + break; + default: + $result = $this->MailSend($header, $body); + break; + //$this->SetError($this->Mailer . $this->Lang('mailer_not_supported')); + //$result = false; + //break; + } + + return $result; + } + + /** + * Sends mail using the $Sendmail program. + * @access public + * @return bool + */ + public function SendmailSend($header, $body) { + if ($this->Sender != '') { + $sendmail = sprintf("%s -oi -f %s -t", escapeshellcmd($this->Sendmail), escapeshellarg($this->Sender)); + } else { + $sendmail = sprintf("%s -oi -t", escapeshellcmd($this->Sendmail)); + } + + if(!@$mail = popen($sendmail, 'w')) { + $this->SetError($this->Lang('execute') . $this->Sendmail); + return false; + } + + fputs($mail, $header); + fputs($mail, $body); + + $result = pclose($mail); + if (version_compare(phpversion(), '4.2.3') == -1) { + $result = $result >> 8 & 0xFF; + } + if($result != 0) { + $this->SetError($this->Lang('execute') . $this->Sendmail); + return false; + } + + return true; + } + + /** + * Sends mail using the PHP mail() function. + * @access public + * @return bool + */ + public function MailSend($header, $body) { + + $to = ''; + for($i = 0; $i < count($this->to); $i++) { + if($i != 0) { $to .= ', '; } + $to .= $this->AddrFormat($this->to[$i]); + } + + $toArr = explode(',', $to); + + $params = sprintf("-oi -f %s", $this->Sender); + if ($this->Sender != '' && strlen(ini_get('safe_mode'))< 1) { + $old_from = ini_get('sendmail_from'); + ini_set('sendmail_from', $this->Sender); + if ($this->SingleTo === true && count($toArr) > 1) { + foreach ($toArr as $key => $val) { + $rt = @mail($val, $this->EncodeHeader($this->SecureHeader($this->Subject)), $body, $header, $params); + } + } else { + $rt = @mail($to, $this->EncodeHeader($this->SecureHeader($this->Subject)), $body, $header, $params); + } + } else { + if ($this->SingleTo === true && count($toArr) > 1) { + foreach ($toArr as $key => $val) { + $rt = @mail($val, $this->EncodeHeader($this->SecureHeader($this->Subject)), $body, $header, $params); + } + } else { + $rt = @mail($to, $this->EncodeHeader($this->SecureHeader($this->Subject)), $body, $header); + } + } + + if (isset($old_from)) { + ini_set('sendmail_from', $old_from); + } + + if(!$rt) { + $this->SetError($this->Lang('instantiate')); + return false; + } + + return true; + } + + /** + * Sends mail via SMTP using PhpSMTP (Author: + * Chris Ryan). Returns bool. Returns false if there is a + * bad MAIL FROM, RCPT, or DATA input. + * @access public + * @return bool + */ + public function SmtpSend($header, $body) { + include_once($this->PluginDir . 'class.smtp.php'); + $error = ''; + $bad_rcpt = array(); + + if(!$this->SmtpConnect()) { + return false; + } + + $smtp_from = ($this->Sender == '') ? $this->From : $this->Sender; + if(!$this->smtp->Mail($smtp_from)) { + $error = $this->Lang('from_failed') . $smtp_from; + $this->SetError($error); + $this->smtp->Reset(); + return false; + } + + /* Attempt to send attach all recipients */ + for($i = 0; $i < count($this->to); $i++) { + if(!$this->smtp->Recipient($this->to[$i][0])) { + $bad_rcpt[] = $this->to[$i][0]; + } + } + for($i = 0; $i < count($this->cc); $i++) { + if(!$this->smtp->Recipient($this->cc[$i][0])) { + $bad_rcpt[] = $this->cc[$i][0]; + } + } + for($i = 0; $i < count($this->bcc); $i++) { + if(!$this->smtp->Recipient($this->bcc[$i][0])) { + $bad_rcpt[] = $this->bcc[$i][0]; + } + } + + if(count($bad_rcpt) > 0) { // Create error message + for($i = 0; $i < count($bad_rcpt); $i++) { + if($i != 0) { + $error .= ', '; + } + $error .= $bad_rcpt[$i]; + } + $error = $this->Lang('recipients_failed') . $error; + $this->SetError($error); + $this->smtp->Reset(); + return false; + } + + if(!$this->smtp->Data($header . $body)) { + $this->SetError($this->Lang('data_not_accepted')); + $this->smtp->Reset(); + return false; + } + if($this->SMTPKeepAlive == true) { + $this->smtp->Reset(); + } else { + $this->SmtpClose(); + } + + return true; + } + + /** + * Initiates a connection to an SMTP server. Returns false if the + * operation failed. + * @access public + * @return bool + */ + public function SmtpConnect() { + if($this->smtp == NULL) { + $this->smtp = new SMTP(); + } + + $this->smtp->do_debug = $this->SMTPDebug; + $hosts = explode(';', $this->Host); + $index = 0; + $connection = ($this->smtp->Connected()); + + /* Retry while there is no connection */ + while($index < count($hosts) && $connection == false) { + $hostinfo = array(); + if(preg_match('/^(.+):([0-9]+)$/i', $hosts[$index], $hostinfo)) { + $host = $hostinfo[1]; + $port = $hostinfo[2]; + } else { + $host = $hosts[$index]; + $port = $this->Port; + } + + $tls = ($this->SMTPSecure == 'tls'); + $ssl = ($this->SMTPSecure == 'ssl'); + + if($this->smtp->Connect(($ssl ? 'ssl://':'').$host, $port, $this->Timeout)) { + + $hello = ($this->Helo != '' ? $this->Helo : $this->ServerHostname()); + $this->smtp->Hello($hello); + + if($tls) { + if(!$this->smtp->StartTLS()) { + $this->SetError($this->Lang("tls")); + $this->smtp->Reset(); + $connection = false; + } + + //We must resend HELLO after tls negociation + $this->smtp->Hello($hello); + } + + $connection = true; + if($this->SMTPAuth) { + if(!$this->smtp->Authenticate($this->Username, $this->Password)) { + $this->SetError($this->Lang('authenticate')); + $this->smtp->Reset(); + $connection = false; + } + } + } + $index++; + } + if(!$connection) { + $this->SetError($this->Lang('connect_host')); + } + + return $connection; + } + + /** + * Closes the active SMTP session if one exists. + * @return void + */ + public function SmtpClose() { + if($this->smtp != NULL) { + if($this->smtp->Connected()) { + $this->smtp->Quit(); + $this->smtp->Close(); + } + } + } + + /** + * Sets the language for all class error messages. Returns false + * if it cannot load the language file. The default language type + * is English. + * @param string $lang_type Type of language (e.g. Portuguese: "br") + * @param string $lang_path Path to the language file directory + * @access public + * @return bool + */ + function SetLanguage($lang_type = 'en', $lang_path = 'language/') { + $filename = $lang_path.'phpmailer.lang-'.$lang_type.'.php'; + if (file_exists($filename)) { + include($filename); + } else { + $PHPMAILER_LANG = array(); + $PHPMAILER_LANG["provide_address"] = 'You must provide at least one ' . + $PHPMAILER_LANG["mailer_not_supported"] = ' mailer is not supported.'; + $PHPMAILER_LANG["execute"] = 'Could not execute: '; + $PHPMAILER_LANG["instantiate"] = 'Could not instantiate mail function.'; + $PHPMAILER_LANG["authenticate"] = 'SMTP Error: Could not authenticate.'; + $PHPMAILER_LANG["from_failed"] = 'The following From address failed: '; + $PHPMAILER_LANG["recipients_failed"] = 'SMTP Error: The following ' . + $PHPMAILER_LANG["data_not_accepted"] = 'SMTP Error: Data not accepted.'; + $PHPMAILER_LANG["connect_host"] = 'SMTP Error: Could not connect to SMTP host.'; + $PHPMAILER_LANG["file_access"] = 'Could not access file: '; + $PHPMAILER_LANG["file_open"] = 'File Error: Could not open file: '; + $PHPMAILER_LANG["encoding"] = 'Unknown encoding: '; + $PHPMAILER_LANG["signing"] = 'Signing Error: '; + } + $this->language = $PHPMAILER_LANG; + return true; + } + + ///////////////////////////////////////////////// + // METHODS, MESSAGE CREATION + ///////////////////////////////////////////////// + + /** + * Creates recipient headers. + * @access public + * @return string + */ + public function AddrAppend($type, $addr) { + $addr_str = $type . ': '; + $addr_str .= $this->AddrFormat($addr[0]); + if(count($addr) > 1) { + for($i = 1; $i < count($addr); $i++) { + $addr_str .= ', ' . $this->AddrFormat($addr[$i]); + } + } + $addr_str .= $this->LE; + + return $addr_str; + } + + /** + * Formats an address correctly. + * @access public + * @return string + */ + public function AddrFormat($addr) { + if(empty($addr[1])) { + $formatted = $this->SecureHeader($addr[0]); + } else { + $formatted = $this->EncodeHeader($this->SecureHeader($addr[1]), 'phrase') . " <" . $this->SecureHeader($addr[0]) . ">"; + } + + return $formatted; + } + + /** + * Wraps message for use with mailers that do not + * automatically perform wrapping and for quoted-printable. + * Original written by philippe. + * @access public + * @return string + */ + public function WrapText($message, $length, $qp_mode = false) { + $soft_break = ($qp_mode) ? sprintf(" =%s", $this->LE) : $this->LE; + // If utf-8 encoding is used, we will need to make sure we don't + // split multibyte characters when we wrap + $is_utf8 = (strtolower($this->CharSet) == "utf-8"); + + $message = $this->FixEOL($message); + if (substr($message, -1) == $this->LE) { + $message = substr($message, 0, -1); + } + + $line = explode($this->LE, $message); + $message = ''; + for ($i=0 ;$i < count($line); $i++) { + $line_part = explode(' ', $line[$i]); + $buf = ''; + for ($e = 0; $e $length)) { + $space_left = $length - strlen($buf) - 1; + if ($e != 0) { + if ($space_left > 20) { + $len = $space_left; + if ($is_utf8) { + $len = $this->UTF8CharBoundary($word, $len); + } elseif (substr($word, $len - 1, 1) == "=") { + $len--; + } elseif (substr($word, $len - 2, 1) == "=") { + $len -= 2; + } + $part = substr($word, 0, $len); + $word = substr($word, $len); + $buf .= ' ' . $part; + $message .= $buf . sprintf("=%s", $this->LE); + } else { + $message .= $buf . $soft_break; + } + $buf = ''; + } + while (strlen($word) > 0) { + $len = $length; + if ($is_utf8) { + $len = $this->UTF8CharBoundary($word, $len); + } elseif (substr($word, $len - 1, 1) == "=") { + $len--; + } elseif (substr($word, $len - 2, 1) == "=") { + $len -= 2; + } + $part = substr($word, 0, $len); + $word = substr($word, $len); + + if (strlen($word) > 0) { + $message .= $part . sprintf("=%s", $this->LE); + } else { + $buf = $part; + } + } + } else { + $buf_o = $buf; + $buf .= ($e == 0) ? $word : (' ' . $word); + + if (strlen($buf) > $length and $buf_o != '') { + $message .= $buf_o . $soft_break; + $buf = $word; + } + } + } + $message .= $buf . $this->LE; + } + + return $message; + } + + /** + * Finds last character boundary prior to maxLength in a utf-8 + * quoted (printable) encoded string. + * Original written by Colin Brown. + * @access public + * @param string $encodedText utf-8 QP text + * @param int $maxLength find last character boundary prior to this length + * @return int + */ + public function UTF8CharBoundary($encodedText, $maxLength) { + $foundSplitPos = false; + $lookBack = 3; + while (!$foundSplitPos) { + $lastChunk = substr($encodedText, $maxLength - $lookBack, $lookBack); + $encodedCharPos = strpos($lastChunk, "="); + if ($encodedCharPos !== false) { + // Found start of encoded character byte within $lookBack block. + // Check the encoded byte value (the 2 chars after the '=') + $hex = substr($encodedText, $maxLength - $lookBack + $encodedCharPos + 1, 2); + $dec = hexdec($hex); + if ($dec < 128) { // Single byte character. + // If the encoded char was found at pos 0, it will fit + // otherwise reduce maxLength to start of the encoded char + $maxLength = ($encodedCharPos == 0) ? $maxLength : + $maxLength - ($lookBack - $encodedCharPos); + $foundSplitPos = true; + } elseif ($dec >= 192) { // First byte of a multi byte character + // Reduce maxLength to split at start of character + $maxLength = $maxLength - ($lookBack - $encodedCharPos); + $foundSplitPos = true; + } elseif ($dec < 192) { // Middle byte of a multi byte character, look further back + $lookBack += 3; + } + } else { + // No encoded character found + $foundSplitPos = true; + } + } + return $maxLength; + } + + + /** + * Set the body wrapping. + * @access public + * @return void + */ + public function SetWordWrap() { + if($this->WordWrap < 1) { + return; + } + + switch($this->message_type) { + case 'alt': + /* fall through */ + case 'alt_attachments': + $this->AltBody = $this->WrapText($this->AltBody, $this->WordWrap); + break; + default: + $this->Body = $this->WrapText($this->Body, $this->WordWrap); + break; + } + } + + /** + * Assembles message header. + * @access public + * @return string + */ + public function CreateHeader() { + $result = ''; + + /* Set the boundaries */ + $uniq_id = md5(uniqid(time())); + $this->boundary[1] = 'b1_' . $uniq_id; + $this->boundary[2] = 'b2_' . $uniq_id; + + $result .= $this->HeaderLine('Date', $this->RFCDate()); + if($this->Sender == '') { + $result .= $this->HeaderLine('Return-Path', trim($this->From)); + } else { + $result .= $this->HeaderLine('Return-Path', trim($this->Sender)); + } + + /* To be created automatically by mail() */ + if($this->Mailer != 'mail') { + if(count($this->to) > 0) { + $result .= $this->AddrAppend('To', $this->to); + } elseif (count($this->cc) == 0) { + $result .= $this->HeaderLine('To', 'undisclosed-recipients:;'); + } + } + + $from = array(); + $from[0][0] = trim($this->From); + $from[0][1] = $this->FromName; + $result .= $this->AddrAppend('From', $from); + + /* sendmail and mail() extract Cc from the header before sending */ + if(count($this->cc) > 0) { + $result .= $this->AddrAppend('Cc', $this->cc); + } + + /* sendmail and mail() extract Bcc from the header before sending */ + if((($this->Mailer == 'sendmail') || ($this->Mailer == 'mail')) && (count($this->bcc) > 0)) { + $result .= $this->AddrAppend('Bcc', $this->bcc); + } + + if(count($this->ReplyTo) > 0) { + $result .= $this->AddrAppend('Reply-to', $this->ReplyTo); + } + + /* mail() sets the subject itself */ + if($this->Mailer != 'mail') { + $result .= $this->HeaderLine('Subject', $this->EncodeHeader($this->SecureHeader($this->Subject))); + } + + if($this->MessageID != '') { + $result .= $this->HeaderLine('Message-ID',$this->MessageID); + } else { + $result .= sprintf("Message-ID: <%s@%s>%s", $uniq_id, $this->ServerHostname(), $this->LE); + } + $result .= $this->HeaderLine('X-Priority', $this->Priority); + $result .= $this->HeaderLine('X-Mailer', 'PHPMailer (phpmailer.codeworxtech.com) [version ' . $this->Version . ']'); + + if($this->ConfirmReadingTo != '') { + $result .= $this->HeaderLine('Disposition-Notification-To', '<' . trim($this->ConfirmReadingTo) . '>'); + } + + // Add custom headers + for($index = 0; $index < count($this->CustomHeader); $index++) { + $result .= $this->HeaderLine(trim($this->CustomHeader[$index][0]), $this->EncodeHeader(trim($this->CustomHeader[$index][1]))); + } + if (!$this->sign_key_file) { + $result .= $this->HeaderLine('MIME-Version', '1.0'); + $result .= $this->GetMailMIME(); + } + + return $result; + } + + /** + * Returns the message MIME. + * @access public + * @return string + */ + public function GetMailMIME() { + $result = ''; + switch($this->message_type) { + case 'plain': + $result .= $this->HeaderLine('Content-Transfer-Encoding', $this->Encoding); + $result .= sprintf("Content-Type: %s; charset=\"%s\"", $this->ContentType, $this->CharSet); + break; + case 'attachments': + /* fall through */ + case 'alt_attachments': + if($this->InlineImageExists()){ + $result .= sprintf("Content-Type: %s;%s\ttype=\"text/html\";%s\tboundary=\"%s\"%s", 'multipart/related', $this->LE, $this->LE, $this->boundary[1], $this->LE); + } else { + $result .= $this->HeaderLine('Content-Type', 'multipart/mixed;'); + $result .= $this->TextLine("\tboundary=\"" . $this->boundary[1] . '"'); + } + break; + case 'alt': + $result .= $this->HeaderLine('Content-Type', 'multipart/alternative;'); + $result .= $this->TextLine("\tboundary=\"" . $this->boundary[1] . '"'); + break; + } + + if($this->Mailer != 'mail') { + $result .= $this->LE.$this->LE; + } + + return $result; + } + + /** + * Assembles the message body. Returns an empty string on failure. + * @access public + * @return string + */ + public function CreateBody() { + $result = ''; + + if ($this->sign_key_file) { + $result .= $this->GetMailMIME(); + } + + $this->SetWordWrap(); + + switch($this->message_type) { + case 'alt': + $result .= $this->GetBoundary($this->boundary[1], '', 'text/plain', ''); + $result .= $this->EncodeString($this->AltBody, $this->Encoding); + $result .= $this->LE.$this->LE; + $result .= $this->GetBoundary($this->boundary[1], '', 'text/html', ''); + $result .= $this->EncodeString($this->Body, $this->Encoding); + $result .= $this->LE.$this->LE; + $result .= $this->EndBoundary($this->boundary[1]); + break; + case 'plain': + $result .= $this->EncodeString($this->Body, $this->Encoding); + break; + case 'attachments': + $result .= $this->GetBoundary($this->boundary[1], '', '', ''); + $result .= $this->EncodeString($this->Body, $this->Encoding); + $result .= $this->LE; + $result .= $this->AttachAll(); + break; + case 'alt_attachments': + $result .= sprintf("--%s%s", $this->boundary[1], $this->LE); + $result .= sprintf("Content-Type: %s;%s" . "\tboundary=\"%s\"%s", 'multipart/alternative', $this->LE, $this->boundary[2], $this->LE.$this->LE); + $result .= $this->GetBoundary($this->boundary[2], '', 'text/plain', '') . $this->LE; // Create text body + $result .= $this->EncodeString($this->AltBody, $this->Encoding); + $result .= $this->LE.$this->LE; + $result .= $this->GetBoundary($this->boundary[2], '', 'text/html', '') . $this->LE; // Create the HTML body + $result .= $this->EncodeString($this->Body, $this->Encoding); + $result .= $this->LE.$this->LE; + $result .= $this->EndBoundary($this->boundary[2]); + $result .= $this->AttachAll(); + break; + } + + if($this->IsError()) { + $result = ''; + } else if ($this->sign_key_file) { + $file = tempnam("", "mail"); + $fp = fopen($file, "w"); + fwrite($fp, $result); + fclose($fp); + $signed = tempnam("", "signed"); + + if (@openssl_pkcs7_sign($file, $signed, "file://".$this->sign_cert_file, array("file://".$this->sign_key_file, $this->sign_key_pass), null)) { + $fp = fopen($signed, "r"); + $result = ''; + while(!feof($fp)){ + $result = $result . fread($fp, 1024); + } + fclose($fp); + } else { + $this->SetError($this->Lang("signing").openssl_error_string()); + $result = ''; + } + + unlink($file); + unlink($signed); + } + + return $result; + } + + /** + * Returns the start of a message boundary. + * @access public + */ + public function GetBoundary($boundary, $charSet, $contentType, $encoding) { + $result = ''; + if($charSet == '') { + $charSet = $this->CharSet; + } + if($contentType == '') { + $contentType = $this->ContentType; + } + if($encoding == '') { + $encoding = $this->Encoding; + } + $result .= $this->TextLine('--' . $boundary); + $result .= sprintf("Content-Type: %s; charset = \"%s\"", $contentType, $charSet); + $result .= $this->LE; + $result .= $this->HeaderLine('Content-Transfer-Encoding', $encoding); + $result .= $this->LE; + + return $result; + } + + /** + * Returns the end of a message boundary. + * @access public + */ + public function EndBoundary($boundary) { + return $this->LE . '--' . $boundary . '--' . $this->LE; + } + + /** + * Sets the message type. + * @access public + * @return void + */ + public function SetMessageType() { + if(count($this->attachment) < 1 && strlen($this->AltBody) < 1) { + $this->message_type = 'plain'; + } else { + if(count($this->attachment) > 0) { + $this->message_type = 'attachments'; + } + if(strlen($this->AltBody) > 0 && count($this->attachment) < 1) { + $this->message_type = 'alt'; + } + if(strlen($this->AltBody) > 0 && count($this->attachment) > 0) { + $this->message_type = 'alt_attachments'; + } + } + } + + /* Returns a formatted header line. + * @access public + * @return string + */ + public function HeaderLine($name, $value) { + return $name . ': ' . $value . $this->LE; + } + + /** + * Returns a formatted mail line. + * @access public + * @return string + */ + public function TextLine($value) { + return $value . $this->LE; + } + + ///////////////////////////////////////////////// + // CLASS METHODS, ATTACHMENTS + ///////////////////////////////////////////////// + + /** + * Adds an attachment from a path on the filesystem. + * Returns false if the file could not be found + * or accessed. + * @param string $path Path to the attachment. + * @param string $name Overrides the attachment name. + * @param string $encoding File encoding (see $Encoding). + * @param string $type File extension (MIME) type. + * @return bool + */ + public function AddAttachment($path, $name = '', $encoding = 'base64', $type = 'application/octet-stream') { + if(!@is_file($path)) { + $this->SetError($this->Lang('file_access') . $path); + return false; + } + + $filename = basename($path); + if($name == '') { + $name = $filename; + } + + $cur = count($this->attachment); + $this->attachment[$cur][0] = $path; + $this->attachment[$cur][1] = $filename; + $this->attachment[$cur][2] = $name; + $this->attachment[$cur][3] = $encoding; + $this->attachment[$cur][4] = $type; + $this->attachment[$cur][5] = false; // isStringAttachment + $this->attachment[$cur][6] = 'attachment'; + $this->attachment[$cur][7] = 0; + + return true; + } + + /** + * Attaches all fs, string, and binary attachments to the message. + * Returns an empty string on failure. + * @access public + * @return string + */ + public function AttachAll() { + /* Return text of body */ + $mime = array(); + + /* Add all attachments */ + for($i = 0; $i < count($this->attachment); $i++) { + /* Check for string attachment */ + $bString = $this->attachment[$i][5]; + if ($bString) { + $string = $this->attachment[$i][0]; + } else { + $path = $this->attachment[$i][0]; + } + + $filename = $this->attachment[$i][1]; + $name = $this->attachment[$i][2]; + $encoding = $this->attachment[$i][3]; + $type = $this->attachment[$i][4]; + $disposition = $this->attachment[$i][6]; + $cid = $this->attachment[$i][7]; + + $mime[] = sprintf("--%s%s", $this->boundary[1], $this->LE); + //$mime[] = sprintf("Content-Type: %s; name=\"%s\"%s", $type, $name, $this->LE); + $mime[] = sprintf("Content-Type: %s; name=\"%s\"%s", $type, $this->EncodeHeader($this->SecureHeader($name)), $this->LE); + $mime[] = sprintf("Content-Transfer-Encoding: %s%s", $encoding, $this->LE); + + if($disposition == 'inline') { + $mime[] = sprintf("Content-ID: <%s>%s", $cid, $this->LE); + } + + //$mime[] = sprintf("Content-Disposition: %s; filename=\"%s\"%s", $disposition, $name, $this->LE.$this->LE); + $mime[] = sprintf("Content-Disposition: %s; filename=\"%s\"%s", $disposition, $this->EncodeHeader($this->SecureHeader($name)), $this->LE.$this->LE); + + /* Encode as string attachment */ + if($bString) { + $mime[] = $this->EncodeString($string, $encoding); + if($this->IsError()) { + return ''; + } + $mime[] = $this->LE.$this->LE; + } else { + $mime[] = $this->EncodeFile($path, $encoding); + if($this->IsError()) { + return ''; + } + $mime[] = $this->LE.$this->LE; + } + } + + $mime[] = sprintf("--%s--%s", $this->boundary[1], $this->LE); + + return join('', $mime); + } + + /** + * Encodes attachment in requested format. Returns an + * empty string on failure. + * @access public + * @return string + */ + public function EncodeFile ($path, $encoding = 'base64') { + if(!@$fd = fopen($path, 'rb')) { + $this->SetError($this->Lang('file_open') . $path); + return ''; + } + if (function_exists('get_magic_quotes')) { + function get_magic_quotes() { + return false; + } +} + if (version_compare(PHP_VERSION, '5.3.0', '<')) { + $magic_quotes = get_magic_quotes_runtime(); + set_magic_quotes_runtime(0); + } + $file_buffer = file_get_contents($path); + $file_buffer = $this->EncodeString($file_buffer, $encoding); + fclose($fd); + if (version_compare(PHP_VERSION, '5.3.0', '<')) { set_magic_quotes_runtime($magic_quotes); } + return $file_buffer; + } + + /** + * Encodes string to requested format. Returns an + * empty string on failure. + * @access public + * @return string + */ + public function EncodeString ($str, $encoding = 'base64') { + $encoded = ''; + switch(strtolower($encoding)) { + case 'base64': + $encoded = chunk_split(base64_encode($str), 76, $this->LE); + break; + case '7bit': + case '8bit': + $encoded = $this->FixEOL($str); + if (substr($encoded, -(strlen($this->LE))) != $this->LE) + $encoded .= $this->LE; + break; + case 'binary': + $encoded = $str; + break; + case 'quoted-printable': + $encoded = $this->EncodeQP($str); + break; + default: + $this->SetError($this->Lang('encoding') . $encoding); + break; + } + return $encoded; + } + + /** + * Encode a header string to best of Q, B, quoted or none. + * @access public + * @return string + */ + public function EncodeHeader ($str, $position = 'text') { + $x = 0; + + switch (strtolower($position)) { + case 'phrase': + if (!preg_match('/[\200-\377]/', $str)) { + /* Can't use addslashes as we don't know what value has magic_quotes_sybase. */ + $encoded = addcslashes($str, "\0..\37\177\\\""); + if (($str == $encoded) && !preg_match('/[^A-Za-z0-9!#$%&\'*+\/=?^_`{|}~ -]/', $str)) { + return ($encoded); + } else { + return ("\"$encoded\""); + } + } + $x = preg_match_all('/[^\040\041\043-\133\135-\176]/', $str, $matches); + break; + case 'comment': + $x = preg_match_all('/[()"]/', $str, $matches); + /* Fall-through */ + case 'text': + default: + $x += preg_match_all('/[\000-\010\013\014\016-\037\177-\377]/', $str, $matches); + break; + } + + if ($x == 0) { + return ($str); + } + + $maxlen = 75 - 7 - strlen($this->CharSet); + /* Try to select the encoding which should produce the shortest output */ + if (strlen($str)/3 < $x) { + $encoding = 'B'; + if (function_exists('mb_strlen') && $this->HasMultiBytes($str)) { + // Use a custom function which correctly encodes and wraps long + // multibyte strings without breaking lines within a character + $encoded = $this->Base64EncodeWrapMB($str); + // Bug 39171 - Need to change the passed back line-ending to \n, since that's what the + // regex below expects. + $encoded = str_replace($this->LE, "\n", trim($encoded)); + } else { + $encoded = base64_encode($str); + $maxlen -= $maxlen % 4; + $encoded = trim(chunk_split($encoded, $maxlen, "\n")); + } + } else { + $encoding = 'Q'; + $encoded = $this->EncodeQ($str, $position); + $encoded = $this->WrapText($encoded, $maxlen, true); + $encoded = str_replace('='.$this->LE, "\n", trim($encoded)); + } + + $encoded = preg_replace('/^(.*)$/m', " =?".$this->CharSet."?$encoding?\\1?=", $encoded); + $encoded = trim(str_replace("\n", $this->LE, $encoded)); + + return $encoded; + } + + /** + * Checks if a string contains multibyte characters. + * @access public + * @param string $str multi-byte text to wrap encode + * @return bool + */ + public function HasMultiBytes($str) { + if (function_exists('mb_strlen')) { + return (strlen($str) > mb_strlen($str, $this->CharSet)); + } else { // Assume no multibytes (we can't handle without mbstring functions anyway) + return False; + } + } + + /** + * Correctly encodes and wraps long multibyte strings for mail headers + * without breaking lines within a character. + * Adapted from a function by paravoid at http://uk.php.net/manual/en/function.mb-encode-mimeheader.php + * @access public + * @param string $str multi-byte text to wrap encode + * @return string + */ + public function Base64EncodeWrapMB($str) { + $start = "=?".$this->CharSet."?B?"; + $end = "?="; + $encoded = ""; + + $mb_length = mb_strlen($str, $this->CharSet); + // Each line must have length <= 75, including $start and $end + $length = 75 - strlen($start) - strlen($end); + // Average multi-byte ratio + $ratio = $mb_length / strlen($str); + // Base64 has a 4:3 ratio + $offset = $avgLength = floor($length * $ratio * .75); + + for ($i = 0; $i < $mb_length; $i += $offset) { + $lookBack = 0; + + do { + $offset = $avgLength - $lookBack; + $chunk = mb_substr($str, $i, $offset, $this->CharSet); + $chunk = base64_encode($chunk); + $lookBack++; + } + while (strlen($chunk) > $length); + + $encoded .= $chunk . $this->LE; + } + + // Chomp the last linefeed + $encoded = substr($encoded, 0, -strlen($this->LE)); + return $encoded; + } + + /** + * Encode string to quoted-printable. + * @access public + * @param string $string the text to encode + * @param integer $line_max Number of chars allowed on a line before wrapping + * @return string + */ + public function EncodeQP( $input = '', $line_max = 76, $space_conv = false ) { + $hex = array('0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'); + $lines = preg_split('/(?:\r\n|\r|\n)/', $input); + $eol = "\r\n"; + $escape = '='; + $output = ''; + while( list(, $line) = each($lines) ) { + $linlen = strlen($line); + $newline = ''; + for($i = 0; $i < $linlen; $i++) { + $c = substr( $line, $i, 1 ); + $dec = ord( $c ); + if ( ( $i == 0 ) && ( $dec == 46 ) ) { // convert first point in the line into =2E + $c = '=2E'; + } + if ( $dec == 32 ) { + if ( $i == ( $linlen - 1 ) ) { // convert space at eol only + $c = '=20'; + } else if ( $space_conv ) { + $c = '=20'; + } + } elseif ( ($dec == 61) || ($dec < 32 ) || ($dec > 126) ) { // always encode "\t", which is *not* required + $h2 = floor($dec/16); + $h1 = floor($dec%16); + $c = $escape.$hex[$h2].$hex[$h1]; + } + if ( (strlen($newline) + strlen($c)) >= $line_max ) { // CRLF is not counted + $output .= $newline.$escape.$eol; // soft line break; " =\r\n" is okay + $newline = ''; + // check if newline first character will be point or not + if ( $dec == 46 ) { + $c = '=2E'; + } + } + $newline .= $c; + } // end of for + $output .= $newline.$eol; + } // end of while + return $output; + } + + /** + * Encode string to q encoding. + * @access public + * @return string + */ + public function EncodeQ ($str, $position = 'text') { + /* There should not be any EOL in the string */ + $encoded = preg_replace("[\r\n]", '', $str); + + switch (strtolower($position)) { + case 'phrase': + $encoded = preg_replace("/([^A-Za-z0-9!*+\/ -])/e", "'='.sprintf('%02X', ord('\\1'))", $encoded); + break; + case 'comment': + $encoded = preg_replace("/([\(\)\"])/e", "'='.sprintf('%02X', ord('\\1'))", $encoded); + case 'text': + default: + /* Replace every high ascii, control =, ? and _ characters */ + $encoded = preg_replace('/([\000-\011\013\014\016-\037\075\077\137\177-\377])/e', + "'='.sprintf('%02X', ord('\\1'))", $encoded); + break; + } + + /* Replace every spaces to _ (more readable than =20) */ + $encoded = str_replace(' ', '_', $encoded); + + return $encoded; + } + + /** + * Adds a string or binary attachment (non-filesystem) to the list. + * This method can be used to attach ascii or binary data, + * such as a BLOB record from a database. + * @param string $string String attachment data. + * @param string $filename Name of the attachment. + * @param string $encoding File encoding (see $Encoding). + * @param string $type File extension (MIME) type. + * @return void + */ + public function AddStringAttachment($string, $filename, $encoding = 'base64', $type = 'application/octet-stream') { + /* Append to $attachment array */ + $cur = count($this->attachment); + $this->attachment[$cur][0] = $string; + $this->attachment[$cur][1] = $filename; + $this->attachment[$cur][2] = $filename; + $this->attachment[$cur][3] = $encoding; + $this->attachment[$cur][4] = $type; + $this->attachment[$cur][5] = true; // isString + $this->attachment[$cur][6] = 'attachment'; + $this->attachment[$cur][7] = 0; + } + + /** + * Adds an embedded attachment. This can include images, sounds, and + * just about any other document. Make sure to set the $type to an + * image type. For JPEG images use "image/jpeg" and for GIF images + * use "image/gif". + * @param string $path Path to the attachment. + * @param string $cid Content ID of the attachment. Use this to identify + * the Id for accessing the image in an HTML form. + * @param string $name Overrides the attachment name. + * @param string $encoding File encoding (see $Encoding). + * @param string $type File extension (MIME) type. + * @return bool + */ + public function AddEmbeddedImage($path, $cid, $name = '', $encoding = 'base64', $type = 'application/octet-stream') { + + if(!@is_file($path)) { + $this->SetError($this->Lang('file_access') . $path); + return false; + } + + $filename = basename($path); + if($name == '') { + $name = $filename; + } + + /* Append to $attachment array */ + $cur = count($this->attachment); + $this->attachment[$cur][0] = $path; + $this->attachment[$cur][1] = $filename; + $this->attachment[$cur][2] = $name; + $this->attachment[$cur][3] = $encoding; + $this->attachment[$cur][4] = $type; + $this->attachment[$cur][5] = false; + $this->attachment[$cur][6] = 'inline'; + $this->attachment[$cur][7] = $cid; + + return true; + } + + /** + * Returns true if an inline attachment is present. + * @access public + * @return bool + */ + public function InlineImageExists() { + $result = false; + for($i = 0; $i < count($this->attachment); $i++) { + if($this->attachment[$i][6] == 'inline') { + $result = true; + break; + } + } + + return $result; + } + + ///////////////////////////////////////////////// + // CLASS METHODS, MESSAGE RESET + ///////////////////////////////////////////////// + + /** + * Clears all recipients assigned in the TO array. Returns void. + * @return void + */ + public function ClearAddresses() { + $this->to = array(); + } + + /** + * Clears all recipients assigned in the CC array. Returns void. + * @return void + */ + public function ClearCCs() { + $this->cc = array(); + } + + /** + * Clears all recipients assigned in the BCC array. Returns void. + * @return void + */ + public function ClearBCCs() { + $this->bcc = array(); + } + + /** + * Clears all recipients assigned in the ReplyTo array. Returns void. + * @return void + */ + public function ClearReplyTos() { + $this->ReplyTo = array(); + } + + /** + * Clears all recipients assigned in the TO, CC and BCC + * array. Returns void. + * @return void + */ + public function ClearAllRecipients() { + $this->to = array(); + $this->cc = array(); + $this->bcc = array(); + } + + /** + * Clears all previously set filesystem, string, and binary + * attachments. Returns void. + * @return void + */ + public function ClearAttachments() { + $this->attachment = array(); + } + + /** + * Clears all custom headers. Returns void. + * @return void + */ + public function ClearCustomHeaders() { + $this->CustomHeader = array(); + } + + ///////////////////////////////////////////////// + // CLASS METHODS, MISCELLANEOUS + ///////////////////////////////////////////////// + + /** + * Adds the error message to the error container. + * Returns void. + * @access private + * @return void + */ + public function SetError($msg) { + $this->error_count++; + $this->ErrorInfo = $msg; + } + + /** + * Returns the proper RFC 822 formatted date. + * @access private + * @return string + */ + private static function RFCDate() { + $tz = date('Z'); + $tzs = ($tz < 0) ? '-' : '+'; + $tz = abs($tz); + $tz = (int)($tz/3600)*100 + ($tz%3600)/60; + $result = sprintf("%s %s%04d", date('D, j M Y H:i:s'), $tzs, $tz); + + return $result; + } + + /** + * Returns the server hostname or 'localhost.localdomain' if unknown. + * @access private + * @return string + */ + public function ServerHostname() { + if (!empty($this->Hostname)) { + $result = $this->Hostname; + } elseif (isset($_SERVER['SERVER_NAME'])) { + $result = $_SERVER['SERVER_NAME']; + } else { + $result = "localhost.localdomain"; + } + + return $result; + } + + /** + * Returns a message in the appropriate language. + * @access private + * @return string + */ + public function Lang($key) { + if(count($this->language) < 1) { + $this->SetLanguage('en'); // set the default language + } + + if(isset($this->language[$key])) { + return $this->language[$key]; + } else { + return 'Language string failed to load: ' . $key; + } + } + + /** + * Returns true if an error occurred. + * @access public + * @return bool + */ + public function IsError() { + return ($this->error_count > 0); + } + + /** + * Changes every end of line from CR or LF to CRLF. + * @access private + * @return string + */ + private function FixEOL($str) { + $str = str_replace("\r\n", "\n", $str); + $str = str_replace("\r", "\n", $str); + $str = str_replace("\n", $this->LE, $str); + return $str; + } + + /** + * Adds a custom header. + * @access public + * @return void + */ + public function AddCustomHeader($custom_header) { + $this->CustomHeader[] = explode(':', $custom_header, 2); + } + + /** + * Evaluates the message and returns modifications for inline images and backgrounds + * @access public + * @return $message + */ + public function MsgHTML($message,$basedir='') { + preg_match_all("/(src|background)=\"(.*)\"/Ui", $message, $images); + if(isset($images[2])) { + foreach($images[2] as $i => $url) { + // do not change urls for absolute images (thanks to corvuscorax) + if (!preg_match('/^[A-z][A-z]*:\/\//',$url)) { + $filename = basename($url); + $directory = dirname($url); + ($directory == '.')?$directory='':''; + $cid = 'cid:' . md5($filename); + $fileParts = preg_split("\.", $filename); + $ext = $fileParts[1]; + $mimeType = $this->_mime_types($ext); + if ( strlen($basedir) > 1 && substr($basedir,-1) != '/') { $basedir .= '/'; } + if ( strlen($directory) > 1 && substr($directory,-1) != '/') { $directory .= '/'; } + if ( $this->AddEmbeddedImage($basedir.$directory.$filename, md5($filename), $filename, 'base64',$mimeType) ) { + $message = preg_replace("/".$images[1][$i]."=\"".preg_quote($url, '/')."\"/Ui", $images[1][$i]."=\"".$cid."\"", $message); + } + } + } + } + $this->IsHTML(true); + $this->Body = $message; + $textMsg = trim(strip_tags(preg_replace('/<(head|title|style|script)[^>]*>.*?<\/\\1>/s','',$message))); + if ( !empty($textMsg) && empty($this->AltBody) ) { + $this->AltBody = html_entity_decode($textMsg); + } + if ( empty($this->AltBody) ) { + $this->AltBody = 'To view this email message, open the email in with HTML compatibility!' . "\n\n"; + } + } + + /** + * Gets the mime type of the embedded or inline image + * @access public + * @return mime type of ext + */ + public function _mime_types($ext = '') { + $mimes = array( + 'hqx' => 'application/mac-binhex40', + 'cpt' => 'application/mac-compactpro', + 'doc' => 'application/msword', + 'bin' => 'application/macbinary', + 'dms' => 'application/octet-stream', + 'lha' => 'application/octet-stream', + 'lzh' => 'application/octet-stream', + 'exe' => 'application/octet-stream', + 'class' => 'application/octet-stream', + 'psd' => 'application/octet-stream', + 'so' => 'application/octet-stream', + 'sea' => 'application/octet-stream', + 'dll' => 'application/octet-stream', + 'oda' => 'application/oda', + 'pdf' => 'application/pdf', + 'ai' => 'application/postscript', + 'eps' => 'application/postscript', + 'ps' => 'application/postscript', + 'smi' => 'application/smil', + 'smil' => 'application/smil', + 'mif' => 'application/vnd.mif', + 'xls' => 'application/vnd.ms-excel', + 'ppt' => 'application/vnd.ms-powerpoint', + 'wbxml' => 'application/vnd.wap.wbxml', + 'wmlc' => 'application/vnd.wap.wmlc', + 'dcr' => 'application/x-director', + 'dir' => 'application/x-director', + 'dxr' => 'application/x-director', + 'dvi' => 'application/x-dvi', + 'gtar' => 'application/x-gtar', + 'php' => 'application/x-httpd-php', + 'php4' => 'application/x-httpd-php', + 'php3' => 'application/x-httpd-php', + 'phtml' => 'application/x-httpd-php', + 'phps' => 'application/x-httpd-php-source', + 'js' => 'application/x-javascript', + 'swf' => 'application/x-shockwave-flash', + 'sit' => 'application/x-stuffit', + 'tar' => 'application/x-tar', + 'tgz' => 'application/x-tar', + 'xhtml' => 'application/xhtml+xml', + 'xht' => 'application/xhtml+xml', + 'zip' => 'application/zip', + 'mid' => 'audio/midi', + 'midi' => 'audio/midi', + 'mpga' => 'audio/mpeg', + 'mp2' => 'audio/mpeg', + 'mp3' => 'audio/mpeg', + 'aif' => 'audio/x-aiff', + 'aiff' => 'audio/x-aiff', + 'aifc' => 'audio/x-aiff', + 'ram' => 'audio/x-pn-realaudio', + 'rm' => 'audio/x-pn-realaudio', + 'rpm' => 'audio/x-pn-realaudio-plugin', + 'ra' => 'audio/x-realaudio', + 'rv' => 'video/vnd.rn-realvideo', + 'wav' => 'audio/x-wav', + 'bmp' => 'image/bmp', + 'gif' => 'image/gif', + 'jpeg' => 'image/jpeg', + 'jpg' => 'image/jpeg', + 'jpe' => 'image/jpeg', + 'png' => 'image/png', + 'tiff' => 'image/tiff', + 'tif' => 'image/tiff', + 'css' => 'text/css', + 'html' => 'text/html', + 'htm' => 'text/html', + 'shtml' => 'text/html', + 'txt' => 'text/plain', + 'text' => 'text/plain', + 'log' => 'text/plain', + 'rtx' => 'text/richtext', + 'rtf' => 'text/rtf', + 'xml' => 'text/xml', + 'xsl' => 'text/xml', + 'mpeg' => 'video/mpeg', + 'mpg' => 'video/mpeg', + 'mpe' => 'video/mpeg', + 'qt' => 'video/quicktime', + 'mov' => 'video/quicktime', + 'avi' => 'video/x-msvideo', + 'movie' => 'video/x-sgi-movie', + 'doc' => 'application/msword', + 'word' => 'application/msword', + 'xl' => 'application/excel', + 'eml' => 'message/rfc822' + ); + return ( ! isset($mimes[strtolower($ext)])) ? 'application/octet-stream' : $mimes[strtolower($ext)]; + } + + /** + * Set (or reset) Class Objects (variables) + * + * Usage Example: + * $page->set('X-Priority', '3'); + * + * @access public + * @param string $name Parameter Name + * @param mixed $value Parameter Value + * NOTE: will not work with arrays, there are no arrays to set/reset + */ + public function set ( $name, $value = '' ) { + if ( isset($this->$name) ) { + $this->$name = $value; + } else { + $this->SetError('Cannot set or reset variable ' . $name); + return false; + } + } + + /** + * Read a file from a supplied filename and return it. + * + * @access public + * @param string $filename Parameter File Name + */ + public function getFile($filename) { + $return = ''; + if ($fp = fopen($filename, 'rb')) { + while (!feof($fp)) { + $return .= fread($fp, 1024); + } + fclose($fp); + return $return; + } else { + return false; + } + } + + /** + * Strips newlines to prevent header injection. + * @access public + * @param string $str String + * @return string + */ + public function SecureHeader($str) { + $str = trim($str); + $str = str_replace("\r", "", $str); + $str = str_replace("\n", "", $str); + return $str; + } + + /** + * Set the private key file and password to sign the message. + * + * @access public + * @param string $key_filename Parameter File Name + * @param string $key_pass Password for private key + */ + public function Sign($cert_filename, $key_filename, $key_pass) { + $this->sign_cert_file = $cert_filename; + $this->sign_key_file = $key_filename; + $this->sign_key_pass = $key_pass; + } +} + +?> diff --git a/include/phpmailer/class.smtp.php b/include/phpmailer/class.smtp.php new file mode 100644 index 00000000..c427d145 --- /dev/null +++ b/include/phpmailer/class.smtp.php @@ -0,0 +1,1105 @@ +smtp_conn = 0; + $this->error = null; + $this->helo_rply = null; + + $this->do_debug = 0; + } + + /************************************************************* + * CONNECTION FUNCTIONS * + ***********************************************************/ + + /** + * Connect to the server specified on the port specified. + * If the port is not specified use the default SMTP_PORT. + * If tval is specified then a connection will try and be + * established with the server for that number of seconds. + * If tval is not specified the default is 30 seconds to + * try on the connection. + * + * SMTP CODE SUCCESS: 220 + * SMTP CODE FAILURE: 421 + * @access public + * @return bool + */ + public function Connect($host,$port=0,$tval=30) { + /* set the error val to null so there is no confusion */ + $this->error = null; + + /* make sure we are __not__ connected */ + if($this->connected()) { + /* ok we are connected! what should we do? + * for now we will just give an error saying we + * are already connected + */ + $this->error = array("error" => "Already connected to a server"); + return false; + } + + if(empty($port)) { + $port = $this->SMTP_PORT; + } + + /* connect to the smtp server */ + $this->smtp_conn = fsockopen($host, // the host of the server + $port, // the port to use + $errno, // error number if any + $errstr, // error message if any + $tval); // give up after ? secs + /* verify we connected properly */ + if(empty($this->smtp_conn)) + { + $GLOBALS['log']->fatal("SMTP -> ERROR: Failed to connect to server. Code: $errno Reply: $errstr "); + return false; + } + + /* sometimes the SMTP server takes a little longer to respond + * so we will give it a longer timeout for the first read + * - Windows still does not have support for this timeout function + */ + if(substr(PHP_OS, 0, 3) != "WIN") + socket_set_timeout($this->smtp_conn, $tval, 0); + + /* get any announcement stuff */ + $announce = $this->get_lines(); + + /* set the timeout of any socket functions at 1/10 of a second */ + //if(function_exists("socket_set_timeout")) + // socket_set_timeout($this->smtp_conn, 0, 100000); + + if($this->do_debug >= 2) { + echo "SMTP -> FROM SERVER:" . $this->CRLF . $announce; + } + + return true; + } + + /** + * Initiate a TSL communication with the server. + * + * SMTP CODE 220 Ready to start TLS + * SMTP CODE 501 Syntax error (no parameters allowed) + * SMTP CODE 454 TLS not available due to temporary reason + * @access public + * @return bool success + */ + public function StartTLS() { + $this->error = null; # to avoid confusion + + if(!$this->connected()) { + $this->error = array("error" => "Called StartTLS() without being connected"); + return false; + } + + fputs($this->smtp_conn,"STARTTLS" . $this->CRLF); + + $rply = $this->get_lines(); + $code = substr($rply,0,3); + + if($this->do_debug >= 2) { + echo "SMTP -> FROM SERVER:" . $this->CRLF . $rply; + } + + if($code != 220) + { + $GLOBALS['log']->fatal("SMTP -> ERROR: STARTTLS not accepted from server. Code: $code Reply: $rply "); + return false; + } + + //Begin encrypted connection + if(!stream_socket_enable_crypto($this->smtp_conn, true, STREAM_CRYPTO_METHOD_TLS_CLIENT)) { + return false; + } + + return true; + } + + /** + * Performs SMTP authentication. Must be run after running the + * Hello() method. Returns true if successfully authenticated. + * @access public + * @return bool + */ + public function Authenticate($username, $password) { + // Start authentication + fputs($this->smtp_conn,"AUTH LOGIN" . $this->CRLF); + + $rply = $this->get_lines(); + $code = substr($rply,0,3); + + if($code != 334) + { + $GLOBALS['log']->fatal("SMTP -> ERROR:AUTH not accepted from server. Code: $code Reply: $rply"); + return false; + } + + // Send encoded username + fputs($this->smtp_conn, base64_encode($username) . $this->CRLF); + + $rply = $this->get_lines(); + $code = substr($rply,0,3); + + if($code != 334) + { + $GLOBALS['log']->fatal("SMTP -> ERROR:Username not accepted from server. Code: $code Reply: $rply "); + return false; + } + + $password = from_html($password); + // Send encoded password + fputs($this->smtp_conn, base64_encode($password) . $this->CRLF); + + $rply = $this->get_lines(); + $code = substr($rply,0,3); + + if($code != 235) + { + $GLOBALS['log']->fatal("SMTP -> ERROR:Password not accepted from server. Code: $code Reply: $rply "); + return false; + } + + return true; + } + + /** + * Returns true if connected to a server otherwise false + * @access public + * @return bool + */ + public function Connected() { + if(!empty($this->smtp_conn)) { + $sock_status = socket_get_status($this->smtp_conn); + if($sock_status["eof"]) { + // hmm this is an odd situation... the socket is + // valid but we are not connected anymore + if($this->do_debug >= 1) { + echo "SMTP -> NOTICE:" . $this->CRLF . + "EOF caught while checking if connected"; + } + $this->Close(); + return false; + } + return true; // everything looks good + } + return false; + } + + /** + * Closes the socket and cleans up the state of the class. + * It is not considered good to use this function without + * first trying to use QUIT. + * @access public + * @return void + */ + public function Close() { + $this->error = null; // so there is no confusion + $this->helo_rply = null; + if(!empty($this->smtp_conn)) { + // close the connection and cleanup + fclose($this->smtp_conn); + $this->smtp_conn = 0; + } + } + + /*************************************************************** + * SMTP COMMANDS * + *************************************************************/ + + /** + * Issues a data command and sends the msg_data to the server + * finializing the mail transaction. $msg_data is the message + * that is to be send with the headers. Each header needs to be + * on a single line followed by a with the message headers + * and the message body being seperated by and additional . + * + * Implements rfc 821: DATA + * + * SMTP CODE INTERMEDIATE: 354 + * [data] + * . + * SMTP CODE SUCCESS: 250 + * SMTP CODE FAILURE: 552,554,451,452 + * SMTP CODE FAILURE: 451,554 + * SMTP CODE ERROR : 500,501,503,421 + * @access public + * @return bool + */ + public function Data($msg_data) { + $this->error = null; // so no confusion is caused + + if(!$this->connected()) { + $this->error = array( + "error" => "Called Data() without being connected"); + return false; + } + + fputs($this->smtp_conn,"DATA" . $this->CRLF); + + $rply = $this->get_lines(); + $code = substr($rply,0,3); + + if($this->do_debug >= 2) { + echo "SMTP -> FROM SERVER:" . $this->CRLF . $rply; + } + + if($code != 354) { + $this->error = + array("error" => "DATA command not accepted from server", + "smtp_code" => $code, + "smtp_msg" => substr($rply,4)); + if($this->do_debug >= 1) { + echo "SMTP -> ERROR: " . $this->error["error"] . + ": " . $rply . $this->CRLF; + } + return false; + } + + /* the server is ready to accept data! + * according to rfc 821 we should not send more than 1000 + * including the CRLF + * characters on a single line so we will break the data up + * into lines by \r and/or \n then if needed we will break + * each of those into smaller lines to fit within the limit. + * in addition we will be looking for lines that start with + * a period '.' and append and additional period '.' to that + * line. NOTE: this does not count towards are limit. + */ + + // normalize the line breaks so we know the explode works + $msg_data = str_replace("\r\n","\n",$msg_data); + $msg_data = str_replace("\r","\n",$msg_data); + $lines = explode("\n",$msg_data); + + /* we need to find a good way to determine is headers are + * in the msg_data or if it is a straight msg body + * currently I am assuming rfc 822 definitions of msg headers + * and if the first field of the first line (':' sperated) + * does not contain a space then it _should_ be a header + * and we can process all lines before a blank "" line as + * headers. + */ + $field = substr($lines[0],0,strpos($lines[0],":")); + $in_headers = false; + if(!empty($field) && !strstr($field," ")) { + $in_headers = true; + } + + $max_line_length = 998; // used below; set here for ease in change + + while(list(,$line) = @each($lines)) { + $lines_out = null; + if($line == "" && $in_headers) { + $in_headers = false; + } + // ok we need to break this line up into several smaller lines + while(strlen($line) > $max_line_length) { + $pos = strrpos(substr($line,0,$max_line_length)," "); + + // Patch to fix DOS attack + if(!$pos) { + $pos = $max_line_length - 1; + $lines_out[] = substr($line,0,$pos); + $line = substr($line,$pos); + } else { + $lines_out[] = substr($line,0,$pos); + $line = substr($line,$pos + 1); + } + + /* if we are processing headers we need to + * add a LWSP-char to the front of the new line + * rfc 822 on long msg headers + */ + if($in_headers) { + $line = "\t" . $line; + } + } + $lines_out[] = $line; + + // now send the lines to the server + while(list(,$line_out) = @each($lines_out)) { + if(strlen($line_out) > 0) + { + if(substr($line_out, 0, 1) == ".") { + $line_out = "." . $line_out; + } + } + fputs($this->smtp_conn,$line_out . $this->CRLF); + } + } + + // ok all the message data has been sent so lets get this + // over with aleady + fputs($this->smtp_conn, $this->CRLF . "." . $this->CRLF); + + $rply = $this->get_lines(); + $code = substr($rply,0,3); + + if($this->do_debug >= 2) { + echo "SMTP -> FROM SERVER:" . $this->CRLF . $rply; + } + + if($code != 250) { + $this->error = + array("error" => "DATA not accepted from server", + "smtp_code" => $code, + "smtp_msg" => substr($rply,4)); + if($this->do_debug >= 1) { + echo "SMTP -> ERROR: " . $this->error["error"] . + ": " . $rply . $this->CRLF; + } + return false; + } + return true; + } + + /** + * Expand takes the name and asks the server to list all the + * people who are members of the _list_. Expand will return + * back and array of the result or false if an error occurs. + * Each value in the array returned has the format of: + * [ ] + * The definition of is defined in rfc 821 + * + * Implements rfc 821: EXPN + * + * SMTP CODE SUCCESS: 250 + * SMTP CODE FAILURE: 550 + * SMTP CODE ERROR : 500,501,502,504,421 + * @access public + * @return string array + */ + public function Expand($name) { + $this->error = null; // so no confusion is caused + + if(!$this->connected()) { + $this->error = array( + "error" => "Called Expand() without being connected"); + return false; + } + + fputs($this->smtp_conn,"EXPN " . $name . $this->CRLF); + + $rply = $this->get_lines(); + $code = substr($rply,0,3); + + if($this->do_debug >= 2) { + echo "SMTP -> FROM SERVER:" . $this->CRLF . $rply; + } + + if($code != 250) { + $this->error = + array("error" => "EXPN not accepted from server", + "smtp_code" => $code, + "smtp_msg" => substr($rply,4)); + if($this->do_debug >= 1) { + echo "SMTP -> ERROR: " . $this->error["error"] . + ": " . $rply . $this->CRLF; + } + return false; + } + + // parse the reply and place in our array to return to user + $entries = explode($this->CRLF,$rply); + while(list(,$l) = @each($entries)) { + $list[] = substr($l,4); + } + + return $list; + } + + /** + * Sends the HELO command to the smtp server. + * This makes sure that we and the server are in + * the same known state. + * + * Implements from rfc 821: HELO + * + * SMTP CODE SUCCESS: 250 + * SMTP CODE ERROR : 500, 501, 504, 421 + * @access public + * @return bool + */ + public function Hello($host="") { + $this->error = null; // so no confusion is caused + + if(!$this->connected()) { + $this->error = array( + "error" => "Called Hello() without being connected"); + return false; + } + + // if a hostname for the HELO was not specified determine + //a suitable one to send + if(empty($host)) { + // we need to determine some sort of appopiate default + // to send to the server + $host = "localhost"; + } + + // Send extended hello first (RFC 2821) + if(!$this->SendHello("EHLO", $host)) + { + if(!$this->SendHello("HELO", $host)) + return false; + } + + return true; + } + + /** + * Sends a HELO/EHLO command. + * @access private + * @return bool + */ + private function SendHello($hello, $host) { + fputs($this->smtp_conn, $hello . " " . $host . $this->CRLF); + + $rply = $this->get_lines(); + $code = substr($rply,0,3); + + if($this->do_debug >= 2) { + echo "SMTP -> FROM SERVER: " . $this->CRLF . $rply; + } + + if($code != 250) + { + $GLOBALS['log']->fatal("SMTP -> ERROR: $hello not accepted from server. Code: $code, Reply: $rply"); + return false; + } + + $this->helo_rply = $rply; + + return true; + } + + /** + * Gets help information on the keyword specified. If the keyword + * is not specified then returns generic help, ussually contianing + * A list of keywords that help is available on. This function + * returns the results back to the user. It is up to the user to + * handle the returned data. If an error occurs then false is + * returned with $this->error set appropiately. + * + * Implements rfc 821: HELP [ ] + * + * SMTP CODE SUCCESS: 211,214 + * SMTP CODE ERROR : 500,501,502,504,421 + * @access public + * @return string + */ + public function Help($keyword="") { + $this->error = null; // to avoid confusion + + if(!$this->connected()) { + $this->error = array( + "error" => "Called Help() without being connected"); + return false; + } + + $extra = ""; + if(!empty($keyword)) { + $extra = " " . $keyword; + } + + fputs($this->smtp_conn,"HELP" . $extra . $this->CRLF); + + $rply = $this->get_lines(); + $code = substr($rply,0,3); + + if($this->do_debug >= 2) { + echo "SMTP -> FROM SERVER:" . $this->CRLF . $rply; + } + + if($code != 211 && $code != 214) { + $this->error = + array("error" => "HELP not accepted from server", + "smtp_code" => $code, + "smtp_msg" => substr($rply,4)); + if($this->do_debug >= 1) { + echo "SMTP -> ERROR: " . $this->error["error"] . + ": " . $rply . $this->CRLF; + } + return false; + } + + return $rply; + } + + /** + * Starts a mail transaction from the email address specified in + * $from. Returns true if successful or false otherwise. If True + * the mail transaction is started and then one or more Recipient + * commands may be called followed by a Data command. + * + * Implements rfc 821: MAIL FROM: + * + * SMTP CODE SUCCESS: 250 + * SMTP CODE SUCCESS: 552,451,452 + * SMTP CODE SUCCESS: 500,501,421 + * @access public + * @return bool + */ + public function Mail($from) { + $this->error = null; // so no confusion is caused + + if(!$this->connected()) { + $this->error = array( + "error" => "Called Mail() without being connected"); + return false; + } + + $useVerp = ($this->do_verp ? "XVERP" : ""); + fputs($this->smtp_conn,"MAIL FROM:<" . $from . ">" . $useVerp . $this->CRLF); + + $rply = $this->get_lines(); + $code = substr($rply,0,3); + + if($this->do_debug >= 2) { + echo "SMTP -> FROM SERVER:" . $this->CRLF . $rply; + } + + if($code != 250) + { + $GLOBALS['log']->fatal("SMTP -> ERROR: MAIL not accepted from server. Code: $code Reply: $rply "); + return false; + } + return true; + } + + /** + * Sends the command NOOP to the SMTP server. + * + * Implements from rfc 821: NOOP + * + * SMTP CODE SUCCESS: 250 + * SMTP CODE ERROR : 500, 421 + * @access public + * @return bool + */ + public function Noop() { + $this->error = null; // so no confusion is caused + + if(!$this->connected()) { + $this->error = array( + "error" => "Called Noop() without being connected"); + return false; + } + + fputs($this->smtp_conn,"NOOP" . $this->CRLF); + + $rply = $this->get_lines(); + $code = substr($rply,0,3); + + if($this->do_debug >= 2) { + echo "SMTP -> FROM SERVER:" . $this->CRLF . $rply; + } + + if($code != 250) { + $this->error = + array("error" => "NOOP not accepted from server", + "smtp_code" => $code, + "smtp_msg" => substr($rply,4)); + if($this->do_debug >= 1) { + echo "SMTP -> ERROR: " . $this->error["error"] . + ": " . $rply . $this->CRLF; + } + return false; + } + return true; + } + + /** + * Sends the quit command to the server and then closes the socket + * if there is no error or the $close_on_error argument is true. + * + * Implements from rfc 821: QUIT + * + * SMTP CODE SUCCESS: 221 + * SMTP CODE ERROR : 500 + * @access public + * @return bool + */ + public function Quit($close_on_error=true) { + $this->error = null; // so there is no confusion + + if(!$this->connected()) { + $this->error = array( + "error" => "Called Quit() without being connected"); + return false; + } + + // send the quit command to the server + fputs($this->smtp_conn,"quit" . $this->CRLF); + + // get any good-bye messages + $byemsg = $this->get_lines(); + + if($this->do_debug >= 2) { + echo "SMTP -> FROM SERVER:" . $this->CRLF . $byemsg; + } + + $rval = true; + $e = null; + + $code = substr($byemsg,0,3); + if($code != 221) { + // use e as a tmp var cause Close will overwrite $this->error + $e = array("error" => "SMTP server rejected quit command", + "smtp_code" => $code, + "smtp_rply" => substr($byemsg,4)); + $rval = false; + if($this->do_debug >= 1) { + echo "SMTP -> ERROR: " . $e["error"] . ": " . + $byemsg . $this->CRLF; + } + } + + if(empty($e) || $close_on_error) { + $this->Close(); + } + + return $rval; + } + + /** + * Sends the command RCPT to the SMTP server with the TO: argument of $to. + * Returns true if the recipient was accepted false if it was rejected. + * + * Implements from rfc 821: RCPT TO: + * + * SMTP CODE SUCCESS: 250,251 + * SMTP CODE FAILURE: 550,551,552,553,450,451,452 + * SMTP CODE ERROR : 500,501,503,421 + * @access public + * @return bool + */ + public function Recipient($to) { + $this->error = null; // so no confusion is caused + + if(!$this->connected()) { + $this->error = array( + "error" => "Called Recipient() without being connected"); + return false; + } + + fputs($this->smtp_conn,"RCPT TO:<" . $to . ">" . $this->CRLF); + + $rply = $this->get_lines(); + $code = substr($rply,0,3); + + if($this->do_debug >= 2) { + echo "SMTP -> FROM SERVER:" . $this->CRLF . $rply; + } + + if($code != 250 && $code != 251) + { + $GLOBALS['log']->fatal("SMTP -> ERROR: RCPT not accepted from server. Code: $code Reply: $rply "); + return false; + } + return true; + } + + /** + * Sends the RSET command to abort and transaction that is + * currently in progress. Returns true if successful false + * otherwise. + * + * Implements rfc 821: RSET + * + * SMTP CODE SUCCESS: 250 + * SMTP CODE ERROR : 500,501,504,421 + * @access public + * @return bool + */ + public function Reset() { + $this->error = null; // so no confusion is caused + + if(!$this->connected()) { + $this->error = array( + "error" => "Called Reset() without being connected"); + return false; + } + + fputs($this->smtp_conn,"RSET" . $this->CRLF); + + $rply = $this->get_lines(); + $code = substr($rply,0,3); + + if($this->do_debug >= 2) { + echo "SMTP -> FROM SERVER:" . $this->CRLF . $rply; + } + + if($code != 250) { + $this->error = + array("error" => "RSET failed", + "smtp_code" => $code, + "smtp_msg" => substr($rply,4)); + if($this->do_debug >= 1) { + echo "SMTP -> ERROR: " . $this->error["error"] . + ": " . $rply . $this->CRLF; + } + return false; + } + + return true; + } + + /** + * Starts a mail transaction from the email address specified in + * $from. Returns true if successful or false otherwise. If True + * the mail transaction is started and then one or more Recipient + * commands may be called followed by a Data command. This command + * will send the message to the users terminal if they are logged + * in. + * + * Implements rfc 821: SEND FROM: + * + * SMTP CODE SUCCESS: 250 + * SMTP CODE SUCCESS: 552,451,452 + * SMTP CODE SUCCESS: 500,501,502,421 + * @access public + * @return bool + */ + public function Send($from) { + $this->error = null; // so no confusion is caused + + if(!$this->connected()) { + $this->error = array( + "error" => "Called Send() without being connected"); + return false; + } + + fputs($this->smtp_conn,"SEND FROM:" . $from . $this->CRLF); + + $rply = $this->get_lines(); + $code = substr($rply,0,3); + + if($this->do_debug >= 2) { + echo "SMTP -> FROM SERVER:" . $this->CRLF . $rply; + } + + if($code != 250) + { + $GLOBALS['log']->fatal("SMTP -> ERROR:SEND not accepted from server. Code:$code Reply:$rply"); + return false; + } + return true; + } + + /** + * Starts a mail transaction from the email address specified in + * $from. Returns true if successful or false otherwise. If True + * the mail transaction is started and then one or more Recipient + * commands may be called followed by a Data command. This command + * will send the message to the users terminal if they are logged + * in and send them an email. + * + * Implements rfc 821: SAML FROM: + * + * SMTP CODE SUCCESS: 250 + * SMTP CODE SUCCESS: 552,451,452 + * SMTP CODE SUCCESS: 500,501,502,421 + * @access public + * @return bool + */ + public function SendAndMail($from) { + $this->error = null; // so no confusion is caused + + if(!$this->connected()) { + $this->error = array( + "error" => "Called SendAndMail() without being connected"); + return false; + } + + fputs($this->smtp_conn,"SAML FROM:" . $from . $this->CRLF); + + $rply = $this->get_lines(); + $code = substr($rply,0,3); + + if($this->do_debug >= 2) { + echo "SMTP -> FROM SERVER:" . $this->CRLF . $rply; + } + + if($code != 250) { + $this->error = + array("error" => "SAML not accepted from server", + "smtp_code" => $code, + "smtp_msg" => substr($rply,4)); + if($this->do_debug >= 1) { + echo "SMTP -> ERROR: " . $this->error["error"] . + ": " . $rply . $this->CRLF; + } + return false; + } + return true; + } + + /** + * Starts a mail transaction from the email address specified in + * $from. Returns true if successful or false otherwise. If True + * the mail transaction is started and then one or more Recipient + * commands may be called followed by a Data command. This command + * will send the message to the users terminal if they are logged + * in or mail it to them if they are not. + * + * Implements rfc 821: SOML FROM: + * + * SMTP CODE SUCCESS: 250 + * SMTP CODE SUCCESS: 552,451,452 + * SMTP CODE SUCCESS: 500,501,502,421 + * @access public + * @return bool + */ + public function SendOrMail($from) { + $this->error = null; // so no confusion is caused + + if(!$this->connected()) { + $this->error = array( + "error" => "Called SendOrMail() without being connected"); + return false; + } + + fputs($this->smtp_conn,"SOML FROM:" . $from . $this->CRLF); + + $rply = $this->get_lines(); + $code = substr($rply,0,3); + + if($this->do_debug >= 2) { + echo "SMTP -> FROM SERVER:" . $this->CRLF . $rply; + } + + if($code != 250) { + $this->error = + array("error" => "SOML not accepted from server", + "smtp_code" => $code, + "smtp_msg" => substr($rply,4)); + if($this->do_debug >= 1) { + echo "SMTP -> ERROR: " . $this->error["error"] . + ": " . $rply . $this->CRLF; + } + return false; + } + return true; + } + + /** + * This is an optional command for SMTP that this class does not + * support. This method is here to make the RFC821 Definition + * complete for this class and __may__ be implimented in the future + * + * Implements from rfc 821: TURN + * + * SMTP CODE SUCCESS: 250 + * SMTP CODE FAILURE: 502 + * SMTP CODE ERROR : 500, 503 + * @access public + * @return bool + */ + public function Turn() { + $this->error = array("error" => "This method, TURN, of the SMTP ". + "is not implemented"); + if($this->do_debug >= 1) { + echo "SMTP -> NOTICE: " . $this->error["error"] . $this->CRLF; + } + return false; + } + + /** + * Verifies that the name is recognized by the server. + * Returns false if the name could not be verified otherwise + * the response from the server is returned. + * + * Implements rfc 821: VRFY + * + * SMTP CODE SUCCESS: 250,251 + * SMTP CODE FAILURE: 550,551,553 + * SMTP CODE ERROR : 500,501,502,421 + * @access public + * @return int + */ + public function Verify($name) { + $this->error = null; // so no confusion is caused + + if(!$this->connected()) { + $this->error = array( + "error" => "Called Verify() without being connected"); + return false; + } + + fputs($this->smtp_conn,"VRFY " . $name . $this->CRLF); + + $rply = $this->get_lines(); + $code = substr($rply,0,3); + + if($this->do_debug >= 2) { + echo "SMTP -> FROM SERVER:" . $this->CRLF . $rply; + } + + if($code != 250 && $code != 251) { + $this->error = + array("error" => "VRFY failed on name '$name'", + "smtp_code" => $code, + "smtp_msg" => substr($rply,4)); + if($this->do_debug >= 1) { + echo "SMTP -> ERROR: " . $this->error["error"] . + ": " . $rply . $this->CRLF; + } + return false; + } + return $rply; + } + + /******************************************************************* + * INTERNAL FUNCTIONS * + ******************************************************************/ + + /** + * Read in as many lines as possible + * either before eof or socket timeout occurs on the operation. + * With SMTP we can tell if we have more lines to read if the + * 4th character is '-' symbol. If it is a space then we don't + * need to read anything else. + * @access private + * @return string + */ + private function get_lines() { + $data = ""; + while($str = @fgets($this->smtp_conn,515)) { + if($this->do_debug >= 4) { + echo "SMTP -> get_lines(): \$data was \"$data\"" . + $this->CRLF; + echo "SMTP -> get_lines(): \$str is \"$str\"" . + $this->CRLF; + } + $data .= $str; + if($this->do_debug >= 4) { + echo "SMTP -> get_lines(): \$data is \"$data\"" . $this->CRLF; + } + // if the 4th character is a space then we are done reading + // so just break the loop + if(substr($str,3,1) == " ") { break; } + } + return $data; + } + +} + + + ?> diff --git a/include/phpmailer/language/phpmailer.lang-ar.php b/include/phpmailer/language/phpmailer.lang-ar.php new file mode 100644 index 00000000..88400b5b --- /dev/null +++ b/include/phpmailer/language/phpmailer.lang-ar.php @@ -0,0 +1,48 @@ + */ + +$PHPMAILER_LANG = array(); + +$PHPMAILER_LANG["provide_address"] = ' íÌÈ Ãä ÊÖÚ Úáì ÇáÃÞá ' . + 'ÚäæÇä ÈÑíÏ ÅáßÊÑæäí ãÓÊÞÈá æÇÍÏ'; +$PHPMAILER_LANG["mailer_not_supported"] = ' ãÑÓá ÇáÈÑíÏ ÛíÑ ãÏÚæã :'; +$PHPMAILER_LANG["execute"] = 'áÇ íãßä ÊäÝíÐ : '; +$PHPMAILER_LANG["instantiate"] = 'áã íÓÊØÚ ÊåíÆÉ ÊÇÈÚ ÇáÈÑíÏ'; +$PHPMAILER_LANG["authenticate"] = 'ÎØà STMP : áã íãáß ÇáÕáÇÍíÉ'; +$PHPMAILER_LANG["from_failed"] = 'ÇáÚäæÇä ÇáãÑÓá ÇáÊÇáí ÝÔá : '; +$PHPMAILER_LANG["recipients_failed"] = 'ÎØà STMP : ' . + 'åÄáÇÁ ÇáãÓÊÞÈáæä ÝÔáæÇ : '; +$PHPMAILER_LANG["data_not_accepted"] = 'ÎØà STMP : ÇáãÚØíÇÊ áã ÊÞÈá .'; +$PHPMAILER_LANG["connect_host"] = 'ÎØà STMP : ÇáÇÊÕÇá ÈãÓÊÖíÝ STMP áã íÊã'; +$PHPMAILER_LANG["file_access"] = 'áÇ íãßä ÇáæÕæá áãáÝ : '; +$PHPMAILER_LANG["file_open"] = 'ÎØà ãáÝ : áã íãßä ÝÊÍ ãáÝ :'; +$PHPMAILER_LANG["encoding"] = 'ÊÔÝíÑ ÛíÑ ãÚÑæÝ : '; +$PHPMAILER_LANG["signing"] = 'ÎØà ÊÓÌíá : '; + +?> \ No newline at end of file diff --git a/include/phpmailer/language/phpmailer.lang-br.php b/include/phpmailer/language/phpmailer.lang-br.php new file mode 100644 index 00000000..85bfd94c --- /dev/null +++ b/include/phpmailer/language/phpmailer.lang-br.php @@ -0,0 +1,56 @@ + \ No newline at end of file diff --git a/include/phpmailer/language/phpmailer.lang-ca.php b/include/phpmailer/language/phpmailer.lang-ca.php new file mode 100644 index 00000000..ae69fff8 --- /dev/null +++ b/include/phpmailer/language/phpmailer.lang-ca.php @@ -0,0 +1,55 @@ + \ No newline at end of file diff --git a/include/phpmailer/language/phpmailer.lang-cz.php b/include/phpmailer/language/phpmailer.lang-cz.php new file mode 100644 index 00000000..6f5f9b06 --- /dev/null +++ b/include/phpmailer/language/phpmailer.lang-cz.php @@ -0,0 +1,59 @@ + \ No newline at end of file diff --git a/include/phpmailer/language/phpmailer.lang-de.php b/include/phpmailer/language/phpmailer.lang-de.php new file mode 100644 index 00000000..d61da840 --- /dev/null +++ b/include/phpmailer/language/phpmailer.lang-de.php @@ -0,0 +1,59 @@ + \ No newline at end of file diff --git a/include/phpmailer/language/phpmailer.lang-dk.php b/include/phpmailer/language/phpmailer.lang-dk.php new file mode 100644 index 00000000..97bb6864 --- /dev/null +++ b/include/phpmailer/language/phpmailer.lang-dk.php @@ -0,0 +1,56 @@ + */ + +$PHPMAILER_LANG = array(); + +$PHPMAILER_LANG["provide_address"] = 'Du skal indtaste mindst en ' . + 'modtagers emailadresse.'; +$PHPMAILER_LANG["mailer_not_supported"] = ' mailer understøttes ikke.'; +$PHPMAILER_LANG["execute"] = 'Kunne ikke køre: '; +$PHPMAILER_LANG["instantiate"] = 'Kunne ikke initialisere email funktionen.'; +$PHPMAILER_LANG["authenticate"] = 'SMTP fejl: Kunne ikke logge pÃ¥.'; +$PHPMAILER_LANG["from_failed"] = 'Følgende afsenderadresse er forkert: '; +$PHPMAILER_LANG["recipients_failed"] = 'SMTP fejl: Følgende' . + 'modtagere er forkerte: '; +$PHPMAILER_LANG["data_not_accepted"] = 'SMTP fejl: Data kunne ikke accepteres.'; +$PHPMAILER_LANG["connect_host"] = 'SMTP fejl: Kunne ikke tilslutte SMTP serveren.'; +$PHPMAILER_LANG["file_access"] = 'Ingen adgang til fil: '; +$PHPMAILER_LANG["file_open"] = 'Fil fejl: Kunne ikke Ã¥bne filen: '; +$PHPMAILER_LANG["encoding"] = 'Ukendt encode-format: '; +$PHPMAILER_LANG["signing"] = 'Signing Error: '; + +?> \ No newline at end of file diff --git a/include/phpmailer/language/phpmailer.lang-en.php b/include/phpmailer/language/phpmailer.lang-en.php new file mode 100644 index 00000000..66243c8b --- /dev/null +++ b/include/phpmailer/language/phpmailer.lang-en.php @@ -0,0 +1,58 @@ + diff --git a/include/phpmailer/language/phpmailer.lang-es.php b/include/phpmailer/language/phpmailer.lang-es.php new file mode 100644 index 00000000..1935c77d --- /dev/null +++ b/include/phpmailer/language/phpmailer.lang-es.php @@ -0,0 +1,58 @@ + \ No newline at end of file diff --git a/include/phpmailer/language/phpmailer.lang-et.php b/include/phpmailer/language/phpmailer.lang-et.php new file mode 100644 index 00000000..4b364b98 --- /dev/null +++ b/include/phpmailer/language/phpmailer.lang-et.php @@ -0,0 +1,51 @@ + \ No newline at end of file diff --git a/include/phpmailer/language/phpmailer.lang-fi.php b/include/phpmailer/language/phpmailer.lang-fi.php new file mode 100644 index 00000000..03d3da96 --- /dev/null +++ b/include/phpmailer/language/phpmailer.lang-fi.php @@ -0,0 +1,56 @@ + \ No newline at end of file diff --git a/include/phpmailer/language/phpmailer.lang-fo.php b/include/phpmailer/language/phpmailer.lang-fo.php new file mode 100644 index 00000000..11db4819 --- /dev/null +++ b/include/phpmailer/language/phpmailer.lang-fo.php @@ -0,0 +1,58 @@ + \ No newline at end of file diff --git a/include/phpmailer/language/phpmailer.lang-fr.php b/include/phpmailer/language/phpmailer.lang-fr.php new file mode 100644 index 00000000..957b11de --- /dev/null +++ b/include/phpmailer/language/phpmailer.lang-fr.php @@ -0,0 +1,58 @@ + \ No newline at end of file diff --git a/include/phpmailer/language/phpmailer.lang-hu.php b/include/phpmailer/language/phpmailer.lang-hu.php new file mode 100644 index 00000000..66a116ce --- /dev/null +++ b/include/phpmailer/language/phpmailer.lang-hu.php @@ -0,0 +1,56 @@ + \ No newline at end of file diff --git a/include/phpmailer/language/phpmailer.lang-it.php b/include/phpmailer/language/phpmailer.lang-it.php new file mode 100644 index 00000000..fd65e65e --- /dev/null +++ b/include/phpmailer/language/phpmailer.lang-it.php @@ -0,0 +1,64 @@ +*/ + +$PHPMAILER_LANG = array(); + +$PHPMAILER_LANG["provide_address"] = 'Deve essere fornito almeno un'. + ' indirizzo ricevente'; +$PHPMAILER_LANG["mailer_not_supported"] = 'Mailer non supportato'; +$PHPMAILER_LANG["execute"] = "Impossibile eseguire l'operazione: "; +$PHPMAILER_LANG["instantiate"] = 'Impossibile istanziare la funzione mail'; +$PHPMAILER_LANG["authenticate"] = 'SMTP Error: Impossibile autenticarsi.'; +$PHPMAILER_LANG["from_failed"] = 'I seguenti indirizzi mittenti hanno'. + ' generato errore: '; +$PHPMAILER_LANG["recipients_failed"] = 'SMTP Error: I seguenti indirizzi'. + 'destinatari hanno generato errore: '; +$PHPMAILER_LANG["data_not_accepted"] = 'SMTP Error: Data non accettati dal'. + 'server.'; +$PHPMAILER_LANG["connect_host"] = 'SMTP Error: Impossibile connettersi'. + ' all\'host SMTP.'; +$PHPMAILER_LANG["file_access"] = 'Impossibile accedere al file: '; +$PHPMAILER_LANG["file_open"] = 'File Error: Impossibile aprire il file: '; +$PHPMAILER_LANG["encoding"] = 'Encoding set dei caratteri sconosciuto: '; +$PHPMAILER_LANG["signing"] = 'Signing Error: '; + +?> \ No newline at end of file diff --git a/include/phpmailer/language/phpmailer.lang-ja.php b/include/phpmailer/language/phpmailer.lang-ja.php new file mode 100644 index 0000000000000000000000000000000000000000..92e2b666271437a0bb15fb63b59e9a677387c405 GIT binary patch literal 2670 zcmcJR?MqZa6vm&=`&V2fu!5An_KJnQNQR^Z5wR@0>PoIIyKCj2f_9QlRy{-?_8bi@VFkC1ZH*%$+-D=9%ZrIdgSH$CXtY#MG?)l$bo8o;q{} zv@4-L^{ZPs`ucerP_Krld+GDkQ~uhtW!J{HtUs<>d4J3$-#X98L9B!MPiPqXc6tkp z8-hb0YYftNnP=XAPce_D10c<)0`ne%WwSD6s{%7$QiKME4end3REz1pY4 zJFvT=2KHjRy$*vET;kZLC^_1BN`tO4b69MhMlEVm<9ZIPeg?kkAkQZ%>WfCSK)nV= z!3tOhb9~>x)+_HUoO8EYjhfdxIQ(EGTWyWCC-hQpX-|MrVBbE2IarRt##D;d)-=kX zN^tt(cxn*8#ZhMn^|HL>d_ShjYB`NO_8e&O-Pgoe6g3Mzl{GTuX2Cjm3al8rd9Ya* z!*1QgV@Vjg)S=KFhzK2(|j`i^C@uM=sDeKufd%^jt^rnmcMxt&64zF~oY+D_FCG>rRlHV9- zr8+9=@wMfMBtFgpr(-^XZ?uL1_XYjI|M%F-DjHYjkCJ~9|7Ql-O?~Xvut*3qMgqN( zXqEM&V!J=1^(k_;TwY!B{bo9iYnlxA+ONksk1mh=du-S(Hb61&TAoYuZZTaut3>k- zW99??oCB8gO2qa@vd;|d-HaKRqwNlJI@h|vg6MI)i|AKG*&fvcIY`#ws&-Ql}#WKh_E5zvw zylH;}j^ifvO!=%X(;frXH&xd?Vt;A9u-FNcfJ^5#8;^e^`yaB~IaDFWf9A2jg6R|0 literal 0 HcmV?d00001 diff --git a/include/phpmailer/language/phpmailer.lang-nl.php b/include/phpmailer/language/phpmailer.lang-nl.php new file mode 100644 index 00000000..f637fd82 --- /dev/null +++ b/include/phpmailer/language/phpmailer.lang-nl.php @@ -0,0 +1,58 @@ + \ No newline at end of file diff --git a/include/phpmailer/language/phpmailer.lang-no.php b/include/phpmailer/language/phpmailer.lang-no.php new file mode 100644 index 00000000..faf6beb1 --- /dev/null +++ b/include/phpmailer/language/phpmailer.lang-no.php @@ -0,0 +1,58 @@ + \ No newline at end of file diff --git a/include/phpmailer/language/phpmailer.lang-pl.php b/include/phpmailer/language/phpmailer.lang-pl.php new file mode 100644 index 00000000..52341cb7 --- /dev/null +++ b/include/phpmailer/language/phpmailer.lang-pl.php @@ -0,0 +1,56 @@ + \ No newline at end of file diff --git a/include/phpmailer/language/phpmailer.lang-ro.php b/include/phpmailer/language/phpmailer.lang-ro.php new file mode 100644 index 00000000..6d512bae --- /dev/null +++ b/include/phpmailer/language/phpmailer.lang-ro.php @@ -0,0 +1,55 @@ + */ + +$PHPMAILER_LANG = array(); + +$PHPMAILER_LANG["provide_address"] = 'Trebuie sa adaugati cel putin un recipient (adresa de mail).'; +$PHPMAILER_LANG["mailer_not_supported"] = ' mailer nu este suportat.'; +$PHPMAILER_LANG["execute"] = 'Nu pot executa: '; +$PHPMAILER_LANG["instantiate"] = 'Nu am putut instantia functia mail.'; +$PHPMAILER_LANG["authenticate"] = 'Eroare SMTP: Nu a functionat autentificarea.'; +$PHPMAILER_LANG["from_failed"] = 'Urmatoarele adrese From au dat eroare: '; +$PHPMAILER_LANG["recipients_failed"] = 'Eroare SMTP: Urmatoarele adrese de mail au dat eroare: '; +$PHPMAILER_LANG["data_not_accepted"] = 'Eroare SMTP: Continutul mailului nu a fost acceptat.'; +$PHPMAILER_LANG["connect_host"] = 'Eroare SMTP: Nu m-am putut conecta la adresa SMTP.'; +$PHPMAILER_LANG["file_access"] = 'Nu pot accesa fisierul: '; +$PHPMAILER_LANG["file_open"] = 'Eroare de fisier: Nu pot deschide fisierul: '; +$PHPMAILER_LANG["encoding"] = 'Encodare necunoscuta: '; +$PHPMAILER_LANG["signing"] = 'Signing Error: '; + +?> \ No newline at end of file diff --git a/include/phpmailer/language/phpmailer.lang-ru.php b/include/phpmailer/language/phpmailer.lang-ru.php new file mode 100644 index 00000000..f8b3ee23 --- /dev/null +++ b/include/phpmailer/language/phpmailer.lang-ru.php @@ -0,0 +1,55 @@ + */ + +$PHPMAILER_LANG = array(); + +$PHPMAILER_LANG["provide_address"] = 'Ïîæàëóéñòà, ââåäèòå õîòÿ áû îäèí àäðåñ e-mail ' . + 'ïîëó÷àòåëÿ.'; +$PHPMAILER_LANG["mailer_not_supported"] = ' - ïî÷òîâûé ñåðâåð íå ïîääåðæèâàåòñÿ.'; +$PHPMAILER_LANG["execute"] = 'Íåâîçìîæíî âûïîëíèòü êîìàíäó: '; +$PHPMAILER_LANG["instantiate"] = 'Íåâîçìîæíî çàïóñòèòü ôóíêöèþ mail.'; +$PHPMAILER_LANG["authenticate"] = 'Îøèáêà SMTP: îøèáêà àâòîðèçàöèè.'; +$PHPMAILER_LANG["from_failed"] = 'Íåâåðíûé àäðåñ îòïðàâèòåëÿ: '; +$PHPMAILER_LANG["recipients_failed"] = 'Îøèáêà SMTP: îòïðàâêà ïî ñëåäóþùèì ' . + 'àäðåñàì ïîëó÷àòåëåé íå óäàëàñü: '; +$PHPMAILER_LANG["data_not_accepted"] = 'Îøèáêà SMTP: äàííûå íå ïðèíÿòû.'; +$PHPMAILER_LANG["connect_host"] = 'Îøèáêà SMTP: íå óäàåòñÿ ïîäêëþ÷èòüñÿ ê ñåðâåðó SMTP.'; +$PHPMAILER_LANG["file_access"] = 'Íåò äîñòóïà ê ôàéëó: '; +$PHPMAILER_LANG["file_open"] = 'Ôàéëîâàÿ îøèáêà: íå óäàåòñÿ îòêðûòü ôàéë: '; +$PHPMAILER_LANG["encoding"] = 'Íåèçâåñòíûé âèä êîäèðîâêè: '; +$PHPMAILER_LANG["signing"] = 'Signing Error: '; + +?> \ No newline at end of file diff --git a/include/phpmailer/language/phpmailer.lang-se.php b/include/phpmailer/language/phpmailer.lang-se.php new file mode 100644 index 00000000..5de32bbe --- /dev/null +++ b/include/phpmailer/language/phpmailer.lang-se.php @@ -0,0 +1,58 @@ + */ + +$PHPMAILER_LANG = array(); + +$PHPMAILER_LANG["provide_address"] = 'Du måste ange minst en ' . + 'mottagares e-postadress.'; +$PHPMAILER_LANG["mailer_not_supported"] = ' mailer stöds inte.'; +$PHPMAILER_LANG["execute"] = 'Kunde inte köra: '; +$PHPMAILER_LANG["instantiate"] = 'Kunde inte initiera e-postfunktion.'; +$PHPMAILER_LANG["authenticate"] = 'SMTP fel: Kunde inte autentisera.'; +$PHPMAILER_LANG["from_failed"] = 'Följande avsändaradress är felaktig: '; +$PHPMAILER_LANG["recipients_failed"] = 'SMTP fel: Följande ' . + 'mottagare är felaktig: '; +$PHPMAILER_LANG["data_not_accepted"] = 'SMTP fel: Data accepterades inte.'; +$PHPMAILER_LANG["connect_host"] = 'SMTP fel: Kunde inte ansluta till SMTP-server.'; +$PHPMAILER_LANG["file_access"] = 'Ingen åtkomst till fil: '; +$PHPMAILER_LANG["file_open"] = 'Fil fel: Kunde inte öppna fil: '; +$PHPMAILER_LANG["encoding"] = 'Okänt encode-format: '; +$PHPMAILER_LANG["signing"] = 'Signing Error: '; + +?> \ No newline at end of file diff --git a/include/phpmailer/language/phpmailer.lang-tr.php b/include/phpmailer/language/phpmailer.lang-tr.php new file mode 100644 index 00000000..88aa1028 --- /dev/null +++ b/include/phpmailer/language/phpmailer.lang-tr.php @@ -0,0 +1,61 @@ + \ No newline at end of file diff --git a/include/phpmailer/license.txt b/include/phpmailer/license.txt new file mode 100644 index 00000000..f3f1b3b6 --- /dev/null +++ b/include/phpmailer/license.txt @@ -0,0 +1,504 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 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. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +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 and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, 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 library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete 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 distribute a copy of this License along with the +Library. + + 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 Library or any portion +of it, thus forming a work based on the Library, 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) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +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 Library, 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 Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you 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. + + If distribution of 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 satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be 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. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library 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. + + 9. 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 Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +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 with +this License. + + 11. 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 Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library 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 Library. + +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. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library 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. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser 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 Library +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 Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +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 + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "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 +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. 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 LIBRARY 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 +LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), 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 Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. 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 library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License 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. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; 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. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + diff --git a/include/reCaptcha/LICENSE b/include/reCaptcha/LICENSE new file mode 100644 index 00000000..b612f71f --- /dev/null +++ b/include/reCaptcha/LICENSE @@ -0,0 +1,22 @@ +Copyright (c) 2007 reCAPTCHA -- http://recaptcha.net +AUTHORS: + Mike Crawford + Ben Maurer + +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/include/reCaptcha/README b/include/reCaptcha/README new file mode 100644 index 00000000..21f1a276 --- /dev/null +++ b/include/reCaptcha/README @@ -0,0 +1,7 @@ +reCAPTCHA README +================ + +The reCAPTCHA PHP Lirary helps you use the reCAPTCHA API. Documentation +for this library can be found at + + http://recaptcha.net/plugins/php diff --git a/include/reCaptcha/recaptchalib.php b/include/reCaptcha/recaptchalib.php new file mode 100644 index 00000000..7376334e --- /dev/null +++ b/include/reCaptcha/recaptchalib.php @@ -0,0 +1,278 @@ + $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/include/resource/Observers/ResourceObserver.php b/include/resource/Observers/ResourceObserver.php new file mode 100644 index 00000000..3f63cc32 --- /dev/null +++ b/include/resource/Observers/ResourceObserver.php @@ -0,0 +1,66 @@ +module = $module; +} + +function setLimit($limit) { + $this->limit = $limit; +} + +function notify($msg = '') { + if($this->dieOnError) { + die($GLOBALS['app_strings']['ERROR_NOTIFY_OVERRIDE']); + } else { + echo($GLOBALS['app_strings']['ERROR_NOTIFY_OVERRIDE']); + } +} + +} + +?> diff --git a/include/resource/Observers/SoapResourceObserver.php b/include/resource/Observers/SoapResourceObserver.php new file mode 100644 index 00000000..f37eb290 --- /dev/null +++ b/include/resource/Observers/SoapResourceObserver.php @@ -0,0 +1,81 @@ +soapServer = $server; +} + + +/** + * notify + * Soap implementation to notify the soap clients of a resource management error + * @param msg String message to possibly display + */ +public function notify($msg = '') { + +header($_SERVER['SERVER_PROTOCOL'] . ' 500 Internal Server Error'); +header('Content-Type: text/xml; charset="ISO-8859-1"'); +$error = new SoapError(); +$error->set_error('resource_management_error'); +//Override the description +$error->description = $msg; +$this->soapServer->methodreturn = array('result'=>$msg, 'error'=>$error->get_soap_array()); +$this->soapServer->serialize_return(); +$this->soapServer->send_response(); +sugar_cleanup(true); + +} + +} +?> \ No newline at end of file diff --git a/include/resource/Observers/WebResourceObserver.php b/include/resource/Observers/WebResourceObserver.php new file mode 100644 index 00000000..fc976cbd --- /dev/null +++ b/include/resource/Observers/WebResourceObserver.php @@ -0,0 +1,64 @@ + diff --git a/include/resource/ResourceManager.php b/include/resource/ResourceManager.php new file mode 100644 index 00000000..1964e082 --- /dev/null +++ b/include/resource/ResourceManager.php @@ -0,0 +1,154 @@ +module)) { + $limit = 0; + + if(isset($GLOBALS['sugar_config']['resource_management'])) { + $res = $GLOBALS['sugar_config']['resource_management']; + if(!empty($res['special_query_modules']) && + in_array($observer->module, $res['special_query_modules']) && + !empty($res['special_query_limit']) && + is_int($res['special_query_limit']) && + $res['special_query_limit'] > 0) { + $limit = $res['special_query_limit']; + } else if(!empty($res['default_limit']) && is_int($res['default_limit']) && $res['default_limit'] > 0) { + $limit = $res['default_limit']; + } + } //if + + if($limit) { + + $db = DBManagerFactory::getInstance(); + $db->setQueryLimit($limit); + $observer->setLimit($limit); + $this->_observers[] = $observer; + } + return true; + } + + return false; +} + +/** + * notifyObservers + * This method notifies the registered observers with the provided message. + * @param $msg Message from language file to notify observers with + */ +public function notifyObservers($msg) { + + if(empty($this->_observers)) { + return; + } + + //Notify observers limit has been reached + if(empty($GLOBALS['app_strings'])) { + $GLOBALS['app_strings'] = return_application_language($GLOBALS['current_language']); + } + $limitMsg = $GLOBALS['app_strings'][$msg]; + foreach( $this->_observers as $observer) { + $limit = $observer->limit; + $module = $observer->module; + eval("\$limitMsg = \"$limitMsg\";"); + $GLOBALS['log']->fatal($limitMsg); + $observer->notify($limitMsg); + } +} + + +/* + * getObservers + * Returns the observer instances that have been setup for the ResourceManager instance + * @return Array of ResourceObserver(s) + */ +function getObservers() { + return $this->_observers; +} + +} +?> \ No newline at end of file diff --git a/include/tabConfig.php b/include/tabConfig.php new file mode 100644 index 00000000..7384ebfd --- /dev/null +++ b/include/tabConfig.php @@ -0,0 +1,103 @@ + array( + 'label' => 'LBL_TABGROUP_SALES', + 'modules' => array( + "Home", + "Accounts", + "Contacts", + "Opportunities", + "Leads", + "Contracts", + "Quotes", + "Forecasts", + ) + ), + "LBL_TABGROUP_MARKETING" => array( + 'label' => 'LBL_TABGROUP_MARKETING', + 'modules' => array( + "Home", + "Accounts", + "Contacts", + "Leads", + "Campaigns", + "Prospects", + "ProspectLists", + ) + ), + "LBL_TABGROUP_SUPPORT" => array( + 'label' => 'LBL_TABGROUP_SUPPORT', + 'modules' => array( + "Home", + "Accounts", + "Contacts", + "Cases", + "Bugs", + ) + ), + "LBL_TABGROUP_ACTIVITIES" => array( + 'label' => 'LBL_TABGROUP_ACTIVITIES', + 'modules' => array( + "Home", + "Calendar", + "Calls", + "Meetings", + "Emails", + "Tasks", + "Notes", + ) + ), + "LBL_TABGROUP_COLLABORATION"=>array( + 'label' => 'LBL_TABGROUP_COLLABORATION', + 'modules' => array( + "Home", + "Emails", + "Documents", + "Project", + ) + ), +); + +if(file_exists('custom/include/tabConfig.php')){ + require_once('custom/include/tabConfig.php'); +} +?> diff --git a/include/tabs.php b/include/tabs.php new file mode 100644 index 00000000..da7a7d36 --- /dev/null +++ b/include/tabs.php @@ -0,0 +1,130 @@ +tabs = $tabs; + $this->current_key = $current_key; + $this->jscallback = $jscallback; + } + + function display() + { + ob_start(); +?> + + +

      +tabs as $tab) + { + $TITLE = $tab['title']; + $LI_ID = ""; + $A_ID = ""; + + if ( ! empty($tab['hidden']) && $tab['hidden'] == true) + { + $LI_ID = "style=\"display: none\""; + $A_ID = "style=\"display: none\""; + + } else if ( $this->current_key == $tab['key']) + { + $LI_ID = "class=\"active\""; + $A_ID = "class=\"current\""; + } + + $LINK = "
    • $TITLE
    • "; + +?> + + +
    + diff --git a/include/tcpdf/2dbarcodes.php b/include/tcpdf/2dbarcodes.php new file mode 100644 index 00000000..57062951 --- /dev/null +++ b/include/tcpdf/2dbarcodes.php @@ -0,0 +1,149 @@ +. +// +// See LICENSE.TXT file for more information. +// ---------------------------------------------------------------------------- +// +// Description : PHP class to creates array representations for +// 2D barcodes to be used with TCPDF. +// +// Author: Nicola Asuni +// +// (c) Copyright: +// Nicola Asuni +// Tecnick.com S.r.l. +// Via della Pace, 11 +// 09044 Quartucciu (CA) +// ITALY +// www.tecnick.com +// info@tecnick.com +//============================================================+ + +/** + * PHP class to creates array representations for 2D barcodes to be used with TCPDF. + * @package com.tecnick.tcpdf + * @abstract Functions for generating string representation of 2D barcodes. + * @author Nicola Asuni + * @copyright 2008-2009 Nicola Asuni - Tecnick.com S.r.l (www.tecnick.com) Via Della Pace, 11 - 09044 - Quartucciu (CA) - ITALY - www.tecnick.com - info@tecnick.com + * @link http://www.tcpdf.org + * @license http://www.gnu.org/copyleft/lesser.html LGPL + * @version 1.0.000 + */ + + /** + * PHP class to creates array representations for 2D barcodes to be used with TCPDF (http://www.tcpdf.org).
    + * @name TCPDFBarcode + * @package com.tecnick.tcpdf + * @version 1.0.000 + * @author Nicola Asuni + * @link http://www.tcpdf.org + * @license http://www.gnu.org/copyleft/lesser.html LGPL + */ +class TCPDF2DBarcode { + + /** + * @var array representation of barcode. + * @access protected + */ + protected $barcode_array; + + /** + * This is the class constructor. + * Return an array representations for 2D barcodes:
      + *
    • $arrcode['code'] code to be printed on text label
    • + *
    • $arrcode['num_rows'] required number of rows
    • + *
    • $arrcode['num_cols'] required number of columns
    • + *
    • $arrcode['bcode'][$r][$c] value of the cell is $r row and $c column (0 = transparent, 1 = black)
    + * @param string $code code to print + * @param string $type type of barcode:
    • TEST
    • ...TO BE IMPLEMENTED
    + */ + public function __construct($code, $type) { + $this->setBarcode($code, $type); + } + + /** + * Return an array representations of barcode. + * @return array + */ + public function getBarcodeArray() { + return $this->barcode_array; + } + + /** + * Set the barcode. + * @param string $code code to print + * @param string $type type of barcode:
    • TEST
    • ...TO BE IMPLEMENTED
    + * @return array + */ + public function setBarcode($code, $type) { + $mode = explode(',', $type); + switch (strtoupper($mode[0])) { + case 'TEST': { // TEST MODE + $this->barcode_array['num_rows'] = 5; + $this->barcode_array['num_cols'] = 15; + $this->barcode_array['bcode'] = array( + array(1,1,1,0,1,1,1,0,1,1,1,0,1,1,1), + array(0,1,0,0,1,0,0,0,1,0,0,0,0,1,0), + array(0,1,0,0,1,1,0,0,1,1,1,0,0,1,0), + array(0,1,0,0,1,0,0,0,0,0,1,0,0,1,0), + array(0,1,0,0,1,1,1,0,1,1,1,0,0,1,0) + ); + break; + } + + // ... Add here real 2D barcodes ... + + default: { + $this->barcode_array = false; + } + } + } +} // end of class + +//============================================================+ +// END OF FILE +//============================================================+ +?> diff --git a/include/tcpdf/CHANGELOG.TXT b/include/tcpdf/CHANGELOG.TXT new file mode 100644 index 00000000..f7109dc0 --- /dev/null +++ b/include/tcpdf/CHANGELOG.TXT @@ -0,0 +1,1010 @@ +4.6.013 (2009-05-28) + - List bullets position was fixed for RTL languages. + +4.6.012 (2009-05-23) + - setUserRights() method doesn't work anymore unless you call the setSignature() method with the Adobe private key! + +4.6.011 (2009-05-18) + - Signature of the Image() method was changed to include the new $fitbox parameter (see source code documentation). + +4.6.010 (2009-05-17) + - Image() method was improved: now is possible to specify the maximum dimensions for a constraint box defined by $w and $h parameters, and setting the $resize parameter to null. + - tag indent problem was fixed. + - $y parameter was added to checkPageBreak() method. + - Bug n. 2791773 "writeHTML" was fixed. + +4.6.009 (2009-05-13) + - xref table for embedded files was fixed. + +4.6.008 (2009-05-07) + - setSignature() method was improved (but is still experimental). + - Example n. 52 was added. + +4.6.007 (2009-05-05) + - Bug #2786685 "writeHtmlCell and
    in custom footer" was fixed. + - Table header repeating bug was fixed. + - Some newlines and tabs are now automatically removed from HTML strings. + +4.6.006 (2009-04-28) + - Support for "..." was added. + - By default TCPDF requires PCRE Unicode support turned on but now works also without it (with limited ability to detect some Unicode blank spaces). + +4.6.005 (2009-04-25) + - Points (pt) conversion in getHTMLUnitToUnits() was fixed. + - Default tcpdf.pem certificate file was added. + - Experimental support for signing document was added but it is not yet completed (some help is needed - I think that the calculation of the ByteRange is OK and the problem is on the signature calculation). + +4.6.004 (2009-04-23) + - Method deletePage() was added to delete pages (see example n. 44). + +4.6.003 (2009-04-21) + - The caching mechanism of the UTF8StringToArray() method was fixed. + +4.6.002 (2009-04-20) + - Documentation of rollbackTransaction() method was fixed. + - The setImageScale() and getImageScale() methods now set and get the adjusting parameter used by pixelsToUnits() method. + - HTML images now support other units of measure than pixels (getHTMLUnitToUnits() is now used instead of pixelsToUnits()). + - WARNING: PDF_IMAGE_SCALE_RATIO has been changed by default to 1. + +4.6.001 (2009-04-17) + - Spaces between HTML block tags are now automatically removed. + - The bug related to cMargin changes between tables was fixed. + +4.6.000 (2009-04-16) + - WARNING: THIS VERSION CHANGES THE BEHAVIOUR OF $x and $y parameters for several TCPDF methods: + zero coordinates for $x and $y are now valid coordinates; + set $x and $y as empty strings to get the current value. + - Some error caused by 'empty' funtion were fixed. + - Default color for convertHTMLColorToDec() method was changed to white and the return value for invalid color is false. + - HTML on footer bug was fixed. + - The following examples were fixed: 5,7,10,17,19,20,21,33,42,43. + +4.5.043 (2009-04-15) + - Barcode class (barcode.php) was extended to include new linear barcode types (see example n. 27): + C39 : CODE 39 - ANSI MH10.8M-1983 - USD-3 - 3 of 9 + C39+ : CODE 39 with checksum + C39E : CODE 39 EXTENDED + C39E+ : CODE 39 EXTENDED + CHECKSUM + C93 : CODE 93 - USS-93 + S25 : Standard 2 of 5 + S25+ : Standard 2 of 5 + CHECKSUM + I25 : Interleaved 2 of 5 + I25+ : Interleaved 2 of 5 + CHECKSUM + C128A : CODE 128 A + C128B : CODE 128 B + C128C : CODE 128 C + EAN2 : 2-Digits UPC-Based Extention + EAN5 : 5-Digits UPC-Based Extention + EAN8 : EAN 8 + EAN13 : EAN 13 + UPCA : UPC-A + UPCE : UPC-E + MSI : MSI (Variation of Plessey code) + MSI+ : MSI + CHECKSUM (modulo 11) + POSTNET : POSTNET + PLANET : PLANET + RMS4CC : RMS4CC (Royal Mail 4-state Customer Code) - CBC (Customer Bar Code) + KIX : KIX (Klant index - Customer index) + IMB: Intelligent Mail Barcode - Onecode - USPS-B-3200 (NOTE: requires BCMath PHP extension) + CODABAR : CODABAR + CODE11 : CODE 11 + PHARMA : PHARMACODE + PHARMA2T : PHARMACODE TWO-TRACKS + +4.5.042 (2009-04-15) + - Method Write() was fixed for the strings containing only zero value. + +4.5.041 (2009-04-14) + - Barcode methods were fixed. + +4.5.040 (2009-04-14) + - Method Write() was fixed to handle empty strings. + +4.5.039 (2009-04-11) + - Support for linear barcodes was extended (see example n. 27 and barcodes.php documentation). + +4.5.038 (2009-04-10) + - Write() method was improved to support separators for Japanese, Korean, Chinese Traditional and Chinese Simplified. + +4.5.037 (2009-04-09) + - General performances were improved. + - The signature of the method utf8Bidi() was changed. + - The method UniArrSubString() was added. + - Experimental support for 2D barcodes were added (see example n. 50 and 2dbarcodes.php class). + +4.5.036 (2009-04-03) + - TCPDF methods can be called inside the HTML code (see example n. 49). + - All tag attributes, such as

    must be enclosed within double quotes. + +4.5.035 (2009-03-28) + - Bug #2717436 "writeHTML rowspan problem (continued)" was fixed. + - Bug #2719090 "writeHTML fix follow up" was fixed. + - The method _putuserrights() was changed to avoid Adobe Reader 9.1 crash. This broken the 'trick' that was used to display forms in Acrobat Reader. + +4.5.034 (2009-03-27) + - Bug #2716914 "Bug writeHTML of a table in body and footer related with pb" was fixed. + - Bug #2717056 ] "writeHTML problem when setting tr style" was fixed. + - The signature of the Cell() method was changed. + +4.5.033 (2009-03-27) + - The support for rowspan/colspan on HTML tables was improved (see example n. 48). + +4.5.032 (2009-03-23) + - setPrintFooter(false) bug was fixed. + +4.5.031 (2009-03-20) + - Table header support was extended to multiple pages. + +4.5.030 (2009-03-20) + - thead tag is now supported on HTML tables (header rows are repeated after page breaks). + - The startTransaction() was improved to autocommit. + - List bullets now uses the foreground color (putHtmlListBullet()). + +4.5.029 (2009-03-19) + - The following methods were added to UNDO commands (see example 47): startTransaction(), commitTransaction(), rollbackTransaction(). + - All examples were updated. + +4.5.028 (2009-03-18) + - Bug #2690945 "List Bugs" was fixed. + - HTML text alignment on lists was fixed. + - The constant PDF_FONT_MONOSPACED was added to the configuration file to define the default monospaced font. + - The following methods were fixed: getPageWidth(), getPageHeight(), getBreakMargin(). + - All examples were updated. + +4.5.027 (2009-03-16) + - Method getPageDimensions() was added to get page dimensions. + - The signature of the following methos were changed: getPageWidth(), getPageHeight(), getBreakMargin(). + - _parsepng() method was fixed for PNG URL images (fread bug). + +4.5.026 (2009-03-11) + - Bug #2681793 affecting URL images with spaces was fixed. + +4.5.025 (2009-03-10) + - A small bug affecting hyphenation support was fixed. + - The method SetDefaultMonospacedFont() was added to define the default monospaced font. + +4.5.024 (2009-03-07) + - The bug #2666493 was fixed "Footer corrupts document". + +4.5.023 (2009-03-06) + - The bug #2666688 was fixed "Rowspan in tables". + +4.5.022 (2009-03-05) + - The bug #2659676 was fixed "refer to #2157099 test 4 < BR > problem still not fixed". + - addTOC() function bug was fixed. + +4.5.020 (2009-03-03) + - The following bug was fixed: "function removeSHY corrupts unicode". + +4.5.019 (2009-02-28) + - The problem of decimal separator using different locale was fixed. + - The text hyphenation is now supported (see example n. 46). + +4.5.018 (2009-02-26) + - The _destroy() method was added to unset all class variables and frees memory. + - Now it's possible to call Output() method multiple times. + +4.5.017 (2009-02-24) + - A minor bug that raises a PHP warning was fixed. + +4.5.016 (2009-02-24) + - Bug item #2631200 "getNumLines() counts wrong" was fixed. + - Multiple attachments bug was fixed. + - All class variables are now cleared on Output() for memory otpimization. + +4.5.015 (2009-02-18) + - Bug item #2612553 "function Write() must not break a line on   character" was fixed. + +4.5.014 (2009-02-13) + - Bug item #2595015 "POSTNET Barcode Checksum Error" was fixed (on barcode.php). + - Pagebreak bug for barcode was fixed. + +4.5.013 (2009-02-12) + - border attribute is now supported on HTML images (only accepts the same values accepted by Cell()). + +4.5.012 (2009-02-12) + - An error on image border feature was fixed. + +4.5.011 (2009-02-12) + - HTML links for images are now supported. + - height attribute is now supported on HTML cells. + - $border parameter was added to Image() and ImageEps() methods. + - The method getNumLines() was added to estimate the number of lines required for the specified text. + +4.5.010 (2009-01-29) + - Bug n. 2546108 "BarCode Y position" was fixed. + +4.5.009 (2009-01-26) + - Bug n. 2538094 "Empty pdf file created" was fixed. + +4.5.008 (2009-01-26) + - setPage() method was fixed to correctly restore graphic states. + - Source code was cleaned up for performances. + +4.5.007 (2009-01-24) + - checkPageBreak() and write1DBarcode() methods were fixed. + - Source code was cleaned up for performances. + - barcodes.php was updated. + +4.5.006 (2009-01-23) + - getHTMLUnitToPoints() method was replaced by getHTMLUnitToUnits() to fix HTML units bugs. + +4.5.005 (2009-01-23) + - Page closing bug was fixed. + +4.5.004 (2009-01-21) + - The access of convertHTMLColorToDec() method was changed to public + - Fixed bug on UL tag. + +4.5.003 (2009-01-19) + - Fonts on different folders are now supported. + +4.5.002 (2009-01-07) + - addTOC() function was improved (see example n. 45). + +4.5.001 (2009-01-04) + - The signature of startPageGroup() function was changed. + - Method Footer() was improved to automatically print page or page-group number (see example n. 23). + - Protected method formatTOCPageNumber() was added to customize the format of page numbers on the Table Of Content. + - The signature of addTOC() was changed to include the font used for page numbers. + +4.5.000 (2009-01-03) + - A new $diskcache parameter was added to class constructor to enable disk caching and reduce RAM memory usage (see example n. 43). + - The method movePageTo() was added to move pages to previous positions (see example n. 44). + - The methods getAliasNumPage() and getPageNumGroupAlias() were added to get the alias for page number (needed when using movepageTo()). + - The methods addTOC() was added to print a Table Of Content (see example n. 45). + - Imagick class constant was removed for better compatibility with PHP4. + - All existing examples were updated and new examples were added. + +4.4.009 (2008-12-29) + - Examples 1 and 35 were fixed. + +4.4.008 (2008-12-28) + - Bug #2472169 "Unordered bullet size not adjusted for unit type" was fixed. + +4.4.007 (2008-12-23) + - Bug #2459935 "no unit conversion for header line" was fixed. + - Example n. 42 for image alpha channel was added. + - All examples were updated. + +4.4.006 (2008-12-11) + - Method setLIsymbol() was changed to reflect latest changes in HTML list handling. + +4.4.005 (2008-12-10) + - Bug item #2413870 "ordered list override value" was fixed. + +4.4.004 (2008-12-10) + - The protected method getHTMLUnitToPoints() was added to accept various HTML units of measure (em, ex, px, in, cm, mm, pt, pc, %). + - The method intToRoman() was added to convert integer number to Roman representation. + - Support fot HTML lists was improved: the CSS property list-style-type is now supported. + +4.4.003 (2008-12-09) + - Bug item #2412147 "Warning on line 3367" was fixed. + - Method setHtmlLinksStyle() was added to set default HTML link colors and font style. + - Method addHtmlLink() was changed to use color and style defined on the inline CSS. + +4.4.002 (2008-12-09) + - Borders on Multicell() were fixed. + - Problem of Multicell() on Header function (Bug item #2407579) was fixed. + - Problem on graphics tranformations applied to Multicell() was fixed. + - Support for ImageMagick was added. + - Width calculation for nested tables was fixed. + +4.4.001 (2008-12-08) + - Some missing core fonts were added on fonts directory. + - CID0 fonts rendering was fixed. + - HTML support was improved (

    + * Either of the above would create YUI.property, then + * YUI.property.package (YAHOO is scrubbed out, this is + * to remain compatible with YUI2) + * + * Be careful when naming packages. Reserved words may work in some browsers + * and not others. For instance, the following will fail in Safari: + *
    +     * YUI.namespace("really.long.nested.namespace");
    +     * 
    + * This fails because "long" is a future reserved word in ECMAScript + * + * @method namespace + * @param {string*} arguments 1-n namespaces to create + * @return {object} A reference to the last namespace object created + */ + namespace: function() { + var a=arguments, o=null, i, j, d; + for (i=0; i + *
    DEBUG
    + *
    Selects the debug versions of the library (e.g., event-debug.js). + * This option will automatically include the Logger widget
    + *
    RAW
    + *
    Selects the non-minified version of the library (e.g., event.js).
    + * + * You can also define a custom filter, which must be an object literal + * containing a search expression and a replace string: + *
    + *  myFilter: { 
    + *      'searchExp': "-min\\.js", 
    + *      'replaceStr': "-debug.js"
    + *  }
    + * 
    + * + * For dynamic loading. + * + * @property filter + * @type string|object + */ + +/** + * Hash of per-component filter specification. If specified for a given component, + * this overrides the filter config + * + * For dynamic loading. + * + * @property filters + * @type object + */ + +/** + * Use the YUI combo service to reduce the number of http connections + * required to load your dependencies. + * + * For dynamic loading. + * + * @property combine + * @type boolean + * @default true if 'base' is not supplied, false if it is. + */ + +/** + * A list of modules that should never be dynamically loaded + * + * @property ignore + * @type string[] + */ + +/** + * A list of modules that should always be loaded when required, even if already + * present on the page. + * + * @property force + * @type string[] + */ + +/** + * Node or id for a node that should be used as the insertion point for new nodes + * For dynamic loading. + * + * @property insertBefore + * @type string + */ + +/** + * charset for dynamic nodes + * + * @property charset + * @type string + * @deprecated use jsAttributes cssAttributes + */ + +/** + * Object literal containing attributes to add to dynamically loaded script nodes. + * + * @property jsAttributes + * @type string + */ + +/** + * Object literal containing attributes to add to dynamically loaded link nodes. + * + * @property cssAttributes + * @type string + */ + +/** + * Number of milliseconds before a timeout occurs when dynamically + * loading nodes. If not set, there is no timeout. + * + * @property timeout + * @type int + */ + +/** + * Callback for the 'CSSComplete' event. When dynamically loading YUI + * components with CSS, this property fires when the CSS is finished + * loading but script loading is still ongoing. This provides an + * opportunity to enhance the presentation of a loading page a little + * bit before the entire loading process is done. + * + * @property onCSS + * @type function + */ + +/** + * A list of module definitions to add to the list of YUI components. + * These components can then be dynamically loaded side by side with + * YUI via the use() method.See Loader.addModule for the supported + * module metadata. + * + * @property modules + * @type function + */ + +/** + * The loader 'path' attribute to the loader itself. This is combined + * with the 'base' attribute to dynamically load the loader component + * when boostrapping with the get utility alone. + * + * @property loaderPath + * @default loader/loader-min.js + */ +YUI.add('yui-base', function(Y) { + +/* + * YUI stub + * @module yui + * @submodule yui-base + */ +(function() { + +var INSTANCE = Y, + LOGEVENT = 'yui:log', + UNDEFINED = 'undefined', + LEVELS = { debug: 1, info: 1, warn: 1, error: 1 }, + _published; + +/** + * If the 'debug' config is true, a 'yui:log' event will be + * dispatched, which the Console widget and anything else + * can consume. If the 'useBrowserConsole' config is true, it will + * write to the browser console if available. YUI-specific log + * messages will only be present in the -debug versions of the + * JS files. The build system is supposed to remove log statements + * from the raw and minified versions of the files. + * + * @method log + * @for YUI + * @param {String} msg The message to log. + * @param {String} cat The log category for the message. Default + * categories are "info", "warn", "error", time". + * Custom categories can be used as well. (opt) + * @param {String} src The source of the the message (opt) + * @param {boolean} silent If true, the log event won't fire + * @return {YUI} YUI instance + */ +INSTANCE.log = function(msg, cat, src, silent) { + var Y = INSTANCE, c = Y.config, bail = false, excl, incl, m, f; + // suppress log message if the config is off or the event stack + // or the event call stack contains a consumer of the yui:log event + if (c.debug) { + // apply source filters + if (src) { + + excl = c.logExclude; + incl = c.logInclude; + + if (incl && !(src in incl)) { + bail = 1; + } else if (excl && (src in excl)) { + bail = 1; + } + } + + if (!bail) { + + if (c.useBrowserConsole) { + m = (src) ? src + ': ' + msg : msg; + if (typeof console != UNDEFINED && console.log) { + f = (cat && console[cat] && (cat in LEVELS)) ? cat : 'log'; + console[f](m); + } else if (typeof opera != UNDEFINED) { + opera.postError(m); + } + } + + if (Y.fire && !bail && !silent) { + if (!_published) { + Y.publish(LOGEVENT, { + broadcast: 2, + emitFacade: 1 + }); + + _published = 1; + + } + Y.fire(LOGEVENT, { + msg: msg, + cat: cat, + src: src + }); + } + } + } + + return Y; +}; + +/** + * Write a system message. This message will be preserved in the + * minified and raw versions of the YUI files, unlike log statements. + * @method message + * @for YUI + * @param {String} msg The message to log. + * @param {String} cat The log category for the message. Default + * categories are "info", "warn", "error", time". + * Custom categories can be used as well. (opt) + * @param {String} src The source of the the message (opt) + * @param {boolean} silent If true, the log event won't fire + * @return {YUI} YUI instance + */ +INSTANCE.message = function() { + return INSTANCE.log.apply(INSTANCE, arguments); +}; + +})(); +(function() { +/** + * Provides the language utilites and extensions used by the library + * @class Lang + * @static + */ +Y.Lang = Y.Lang || {}; + +var L = Y.Lang, + +ARRAY = 'array', +BOOLEAN = 'boolean', +DATE = 'date', +ERROR = 'error', +FUNCTION = 'function', +NUMBER = 'number', +NULL = 'null', +OBJECT = 'object', +REGEX = 'regexp', +STRING = 'string', +TOSTRING = Object.prototype.toString, +UNDEFINED = 'undefined', + +TYPES = { + 'undefined' : UNDEFINED, + 'number' : NUMBER, + 'boolean' : BOOLEAN, + 'string' : STRING, + '[object Function]' : FUNCTION, + '[object RegExp]' : REGEX, + '[object Array]' : ARRAY, + '[object Date]' : DATE, + '[object Error]' : ERROR +}, + +TRIMREGEX = /^\s+|\s+$/g, +EMPTYSTRING = ''; + +/** + * Determines whether or not the provided item is an array. + * Returns false for array-like collections such as the + * function arguments collection or HTMLElement collection + * will return false. You can use @see Array.test if you + * want to + * @method isArray + * @static + * @param o The object to test + * @return {boolean} true if o is an array + */ +L.isArray = function(o) { + return L.type(o) === ARRAY; +}; + +/** + * Determines whether or not the provided item is a boolean + * @method isBoolean + * @static + * @param o The object to test + * @return {boolean} true if o is a boolean + */ +L.isBoolean = function(o) { + return typeof o === BOOLEAN; +}; + +/** + * Determines whether or not the provided item is a function + * Note: Internet Explorer thinks certain functions are objects: + * + * var obj = document.createElement("object"); + * Y.Lang.isFunction(obj.getAttribute) // reports false in IE + * + * var input = document.createElement("input"); // append to body + * Y.Lang.isFunction(input.focus) // reports false in IE + * + * You will have to implement additional tests if these functions + * matter to you. + * + * @method isFunction + * @static + * @param o The object to test + * @return {boolean} true if o is a function + */ +L.isFunction = function(o) { + return L.type(o) === FUNCTION; +}; + +/** + * Determines whether or not the supplied item is a date instance + * @method isDate + * @static + * @param o The object to test + * @return {boolean} true if o is a date + */ +L.isDate = function(o) { + // return o instanceof Date; + return L.type(o) === DATE; +}; + +/** + * Determines whether or not the provided item is null + * @method isNull + * @static + * @param o The object to test + * @return {boolean} true if o is null + */ +L.isNull = function(o) { + return o === null; +}; + +/** + * Determines whether or not the provided item is a legal number + * @method isNumber + * @static + * @param o The object to test + * @return {boolean} true if o is a number + */ +L.isNumber = function(o) { + return typeof o === NUMBER && isFinite(o); +}; + +/** + * Determines whether or not the provided item is of type object + * or function + * @method isObject + * @static + * @param o The object to test + * @param failfn {boolean} fail if the input is a function + * @return {boolean} true if o is an object + */ +L.isObject = function(o, failfn) { +return (o && (typeof o === OBJECT || (!failfn && L.isFunction(o)))) || false; +}; + +/** + * Determines whether or not the provided item is a string + * @method isString + * @static + * @param o The object to test + * @return {boolean} true if o is a string + */ +L.isString = function(o) { + return typeof o === STRING; +}; + +/** + * Determines whether or not the provided item is undefined + * @method isUndefined + * @static + * @param o The object to test + * @return {boolean} true if o is undefined + */ +L.isUndefined = function(o) { + return typeof o === UNDEFINED; +}; + +/** + * Returns a string without any leading or trailing whitespace. If + * the input is not a string, the input will be returned untouched. + * @method trim + * @static + * @param s {string} the string to trim + * @return {string} the trimmed string + */ +L.trim = function(s){ + try { + return s.replace(TRIMREGEX, EMPTYSTRING); + } catch(e) { + return s; + } +}; + +/** + * A convenience method for detecting a legitimate non-null value. + * Returns false for null/undefined/NaN, true for other values, + * including 0/false/'' + * @method isValue + * @static + * @param o The item to test + * @return {boolean} true if it is not null/undefined/NaN || false + */ +L.isValue = function(o) { + var t = L.type(o); + switch (t) { + case NUMBER: + return isFinite(o); + case NULL: + case UNDEFINED: + return false; + default: + return !!(t); + } +}; + +/** + * Returns a string representing the type of the item passed in. + * @method type + * @param o the item to test + * @return {string} the detected type + */ +L.type = function (o) { + return TYPES[typeof o] || TYPES[TOSTRING.call(o)] || (o ? OBJECT : NULL); +}; + +})(); + +/* + * Provides information about the environment hosting YUI + * @module yui + * @submodule Array + */ + +(function() { + +var L = Y.Lang, Native = Array.prototype, + +/** + * Adds the following array utilities to the YUI instance. Additional + * array helpers can be found in the collection component. + * @class Array + */ + +/** + * Y.Array(o) returns an array: + * - Arrays are return unmodified unless the start position is specified. + * - "Array-like" collections (@see Array.test) are converted to arrays + * - For everything else, a new array is created with the input as the sole item + * - The start position is used if the input is or is like an array to return + * a subset of the collection. + * + * @TODO this will not automatically convert elements that are also collections + * such as forms and selects. Passing true as the third param will + * force a conversion. + * + * @method () + * @static + * @param o the item to arrayify + * @param i {int} if an array or array-like, this is the start index + * @param al {boolean} if true, it forces the array-like fork. This + * can be used to avoid multiple array.test calls. + * @return {Array} the resulting array + */ +YArray = function(o, startIdx, al) { + var t = (al) ? 2 : Y.Array.test(o), i, l, a; + + // switch (t) { + // case 1: + // // return (startIdx) ? o.slice(startIdx) : o; + // case 2: + // return Native.slice.call(o, startIdx || 0); + // default: + // return [o]; + // } + + if (t) { + try { + return Native.slice.call(o, startIdx || 0); + // IE errors when trying to slice element collections + } catch(e) { + a=[]; + for (i=0, l=o.length; i 1)) { + r = 2; + } + + } catch(e) {} + } + } + return r; +}; + +/** + * Executes the supplied function on each item in the array. + * @method each + * @param a {Array} the array to iterate + * @param f {Function} the function to execute on each item + * @param o Optional context object + * @static + * @return {YUI} the YUI instance + */ +YArray.each = (Native.forEach) ? + function (a, f, o) { + Native.forEach.call(a || [], f, o || Y); + return Y; + } : + function (a, f, o) { + var l = (a && a.length) || 0, i; + for (i = 0; i < l; i=i+1) { + f.call(o || Y, a[i], i, a); + } + return Y; + }; + +/** + * Returns an object using the first array as keys, and + * the second as values. If the second array is not + * provided the value is set to true for each. + * @method hash + * @static + * @param k {Array} keyset + * @param v {Array} optional valueset + * @return {object} the hash + */ +YArray.hash = function(k, v) { + var o = {}, l = k.length, vl = v && v.length, i; + for (i=0; i i) ? v[i] : true; + } + + return o; +}; + +/** + * Returns the index of the first item in the array + * that contains the specified value, -1 if the + * value isn't found. + * @method indexOf + * @static + * @param a {Array} the array to search + * @param val the value to search for + * @return {int} the index of the item that contains the value or -1 + */ +YArray.indexOf = (Native.indexOf) ? + function(a, val) { + return Native.indexOf.call(a, val); + } : + function(a, val) { + for (var i=0; i -1); +}; + +/** + * Determines whether or not the property was added + * to the object instance. Returns false if the property is not present + * in the object, or was inherited from the prototype. + * + * @deprecated Safari 1.x support has been removed, so this is simply a + * wrapper for the native implementation. Use the native implementation + * directly instead. + * + * @TODO Remove in B1 + * + * @method owns + * @static + * @param o {any} The object being testing + * @param p {string} the property to look for + * @return {boolean} true if the object has the property on the instance + */ +O.owns = function(o, k) { + return (o.hasOwnProperty(k)); +}; + +/** + * Executes a function on each item. The function + * receives the value, the key, and the object + * as paramters (in that order). + * @method each + * @static + * @param o the object to iterate + * @param f {function} the function to execute + * @param c the execution context + * @param proto {boolean} include proto + * @return {YUI} the YUI instance + */ +O.each = function (o, f, c, proto) { + var s = c || Y, i; + + for (i in o) { + if (proto || o.hasOwnProperty(i)) { + f.call(s, o[i], i, o); + } + } + return Y; +}; + +/** + * Retrieves the sub value at the provided path, + * from the value object provided. + * + * @method getValue + * @param o The object from which to extract the property value + * @param path {Array} A path array, specifying the object traversal path + * from which to obtain the sub value. + * @return {Any} The value stored in the path, undefined if not found. + * Returns the source object if an empty path is provided. + */ +O.getValue = function (o, path) { + var p=Y.Array(path), l=p.length, i; + + for (i=0; o !== UNDEFINED && i < l; i=i+1) { + o = o[p[i]]; + } + + return o; +}; + +/** + * Sets the sub-attribute value at the provided path on the + * value object. Returns the modified value object, or + * undefined if the path is invalid. + * + * @method setValue + * @param o The object on which to set the sub value. + * @param path {Array} A path array, specifying the object traversal path + * at which to set the sub value. + * @param val {Any} The new value for the sub-attribute. + * @return {Object} The modified object, with the new sub value set, or + * undefined, if the path was invalid. + */ +O.setValue = function(o, path, val) { + + var p=Y.Array(path), leafIdx=p.length-1, i, ref=o; + + if (leafIdx >= 0) { + for (i=0; ref !== UNDEFINED && i < leafIdx; i=i+1) { + ref = ref[p[i]]; + } + + if (ref !== UNDEFINED) { + ref[p[i]] = val; + } else { + return UNDEFINED; + } + } + + return o; +}; + + +})(); + +/* + * Provides information about the environment hosting YUI + * @module yui + * @submodule UA + */ +/** + * YUI user agent detection. + * Do not fork for a browser if it can be avoided. Use feature detection when + * you can. Use the user agent as a last resort. UA stores a version + * number for the browser engine, 0 otherwise. This value may or may not map + * to the version number of the browser using the engine. The value is + * presented as a float so that it can easily be used for boolean evaluation + * as well as for looking for a particular range of versions. Because of this, + * some of the granularity of the version info may be lost (e.g., Gecko 1.8.0.9 + * reports 1.8). + * @class UA + * @static + */ +Y.UA = function() { + + var numberfy = function(s) { + var c = 0; + return parseFloat(s.replace(/\./g, function() { + return (c++ == 1) ? '' : '.'; + })); + }, + + nav = navigator, + + o = { + + /** + * Internet Explorer version number or 0. Example: 6 + * @property ie + * @type float + * @static + */ + ie: 0, + + /** + * Opera version number or 0. Example: 9.2 + * @property opera + * @type float + * @static + */ + opera: 0, + + /** + * Gecko engine revision number. Will evaluate to 1 if Gecko + * is detected but the revision could not be found. Other browsers + * will be 0. Example: 1.8 + *
    +         * Firefox 1.0.0.4: 1.7.8   <-- Reports 1.7
    +         * Firefox 1.5.0.9: 1.8.0.9 <-- Reports 1.8
    +         * Firefox 2.0.0.3: 1.8.1.3 <-- Reports 1.8
    +         * Firefox 3 alpha: 1.9a4   <-- Reports 1.9
    +         * 
    + * @property gecko + * @type float + * @static + */ + gecko: 0, + + /** + * AppleWebKit version. KHTML browsers that are not WebKit browsers + * will evaluate to 1, other browsers 0. Example: 418.9 + *
    +         * Safari 1.3.2 (312.6): 312.8.1 <-- Reports 312.8 -- currently the 
    +         *                                   latest available for Mac OSX 10.3.
    +         * Safari 2.0.2:         416     <-- hasOwnProperty introduced
    +         * Safari 2.0.4:         418     <-- preventDefault fixed
    +         * Safari 2.0.4 (419.3): 418.9.1 <-- One version of Safari may run
    +         *                                   different versions of webkit
    +         * Safari 2.0.4 (419.3): 419     <-- Tiger installations that have been
    +         *                                   updated, but not updated
    +         *                                   to the latest patch.
    +         * Webkit 212 nightly:   522+    <-- Safari 3.0 precursor (with native SVG
    +         *                                   and many major issues fixed).
    +         * Safari 3.0.4 (523.12) 523.12  <-- First Tiger release - automatic update
    +         *                                   from 2.x via the 10.4.11 OS patch
    +         * Webkit nightly 1/2008:525+    <-- Supports DOMContentLoaded event.
    +         *                                   yahoo.com user agent hack removed.
    +         * 
    + * http://en.wikipedia.org/wiki/Safari_(web_browser)#Version_history + * @property webkit + * @type float + * @static + */ + webkit: 0, + + /** + * The mobile property will be set to a string containing any relevant + * user agent information when a modern mobile browser is detected. + * Currently limited to Safari on the iPhone/iPod Touch, Nokia N-series + * devices with the WebKit-based browser, and Opera Mini. + * @property mobile + * @type string + * @static + */ + mobile: null, + + /** + * Adobe AIR version number or 0. Only populated if webkit is detected. + * Example: 1.0 + * @property air + * @type float + */ + air: 0, + + /** + * Google Caja version number or 0. + * @property caja + * @type float + */ + caja: nav.cajaVersion, + + /** + * Set to true if the page appears to be in SSL + * @property secure + * @type boolean + * @static + */ + secure: false, + + /** + * The operating system. Currently only detecting windows or macintosh + * @property os + * @type string + * @static + */ + os: null + + }, + + ua = nav && nav.userAgent, + + loc = Y.config.win.location, + + href = loc && loc.href, + + m; + + o.secure = href && (href.toLowerCase().indexOf("https") === 0); + + if (ua) { + + if ((/windows|win32/i).test(ua)) { + o.os = 'windows'; + } else if ((/macintosh/i).test(ua)) { + o.os = 'macintosh'; + } + + // Modern KHTML browsers should qualify as Safari X-Grade + if ((/KHTML/).test(ua)) { + o.webkit=1; + } + // Modern WebKit browsers are at least X-Grade + m=ua.match(/AppleWebKit\/([^\s]*)/); + if (m&&m[1]) { + o.webkit=numberfy(m[1]); + + // Mobile browser check + if (/ Mobile\//.test(ua)) { + o.mobile = "Apple"; // iPhone or iPod Touch + } else { + m=ua.match(/NokiaN[^\/]*|Android \d\.\d|webOS\/\d\.\d/); + if (m) { + o.mobile = m[0]; // Nokia N-series, Android, webOS, ex: NokiaN95 + } + } + + m=ua.match(/AdobeAIR\/([^\s]*)/); + if (m) { + o.air = m[0]; // Adobe AIR 1.0 or better + } + + } + + if (!o.webkit) { // not webkit + // @todo check Opera/8.01 (J2ME/MIDP; Opera Mini/2.0.4509/1316; fi; U; ssr) + m=ua.match(/Opera[\s\/]([^\s]*)/); + if (m&&m[1]) { + o.opera=numberfy(m[1]); + m=ua.match(/Opera Mini[^;]*/); + if (m) { + o.mobile = m[0]; // ex: Opera Mini/2.0.4509/1316 + } + } else { // not opera or webkit + m=ua.match(/MSIE\s([^;]*)/); + if (m&&m[1]) { + o.ie=numberfy(m[1]); + } else { // not opera, webkit, or ie + m=ua.match(/Gecko\/([^\s]*)/); + if (m) { + o.gecko=1; // Gecko detected, look for revision + m=ua.match(/rv:([^\s\)]*)/); + if (m&&m[1]) { + o.gecko=numberfy(m[1]); + } + } + } + } + } + } + + return o; +}(); +(function() { + var L = Y.Lang, + + /** + * Executes the supplied function in the context of the supplied + * object 'when' milliseconds later. Executes the function a + * single time unless periodic is set to true. + * @method later + * @for YUI + * @param when {int} the number of milliseconds to wait until the fn + * is executed. + * @param o the context object. + * @param fn {Function|String} the function to execute or the name of + * the method in the 'o' object to execute. + * @param data [Array] data that is provided to the function. This accepts + * either a single item or an array. If an array is provided, the + * function is executed with one parameter for each array item. If + * you need to pass a single array parameter, it needs to be wrapped in + * an array [myarray]. + * @param periodic {boolean} if true, executes continuously at supplied + * interval until canceled. + * @return {object} a timer object. Call the cancel() method on this object to + * stop the timer. + */ + later = function(when, o, fn, data, periodic) { + when = when || 0; + o = o || {}; + var m=fn, d=data, f, r; + + if (L.isString(fn)) { + m = o[fn]; + } + + if (!m) { + Y.error("method undefined"); + } + + if (!L.isArray(d)) { + d = [data]; + } + + f = function() { + m.apply(o, d); + }; + + r = (periodic) ? setInterval(f, when) : setTimeout(f, when); + + return { + id: r, + interval: periodic, + cancel: function() { + if (this.interval) { + clearInterval(r); + } else { + clearTimeout(r); + } + } + }; + }; + + Y.later = later; + L.later = later; + +})(); +(function() { + + var min = ['yui-base'], core, C = Y.config, LOADER='loader'; + + // apply the minimal required functionality + Y.use.apply(Y, min); + + + if (C.core) { + core = C.core; + } else { + core = ['queue-base', 'get']; + if (YUI.Env.mods[LOADER]) { + core.push(LOADER); + } + } + + Y.use.apply(Y, core); + +})(); + + + +}, '3.0.0' ); diff --git a/jssource/src_files/include/javascript/yui3/build/yui/get-min.js b/jssource/src_files/include/javascript/yui3/build/yui/get-min.js new file mode 100644 index 00000000..cc7e1fd4 --- /dev/null +++ b/jssource/src_files/include/javascript/yui3/build/yui/get-min.js @@ -0,0 +1,8 @@ +/* +Copyright (c) 2009, Yahoo! Inc. All rights reserved. +Code licensed under the BSD License: +http://developer.yahoo.net/yui/license.txt +version: 3.0.0 +build: 1549 +*/ +YUI.add("get",function(A){(function(){var C=A.UA,B=A.Lang,E="text/javascript",F="text/css",D="stylesheet";A.Get=function(){var M={},K=0,U=false,W=function(a,X,b){var Y=b||A.config.win,c=Y.document,e=c.createElement(a),Z;for(Z in X){if(X[Z]&&X.hasOwnProperty(Z)){e.setAttribute(Z,X[Z]);}}return e;},T=function(Y,Z,X){var a={id:A.guid(),type:F,rel:D,href:Y};if(X){A.mix(a,X);}return W("link",a,Z);},S=function(Y,Z,X){var a={id:A.guid(),type:E,src:Y};if(X){A.mix(a,X);}return W("script",a,Z);},N=function(c){var X=M[c],Y,a,g,e,j,b,Z,f;if(X){Y=X.nodes;a=Y.length;g=X.win.document;e=g.getElementsByTagName("head")[0];if(X.insertBefore){j=L(X.insertBefore,c);if(j){e=j.parentNode;}}for(b=0;b + *
    onSuccess
    + *
    + * callback to execute when the script(s) are finished loading + * The callback receives an object back with the following + * data: + *
    + *
    win
    + *
    the window the script(s) were inserted into
    + *
    data
    + *
    the data object passed in when the request was made
    + *
    nodes
    + *
    An array containing references to the nodes that were + * inserted
    + *
    purge
    + *
    A function that, when executed, will remove the nodes + * that were inserted
    + *
    + *
    + *
    + *
    onTimeout
    + *
    + * callback to execute when a timeout occurs. + * The callback receives an object back with the following + * data: + *
    + *
    win
    + *
    the window the script(s) were inserted into
    + *
    data
    + *
    the data object passed in when the request was made
    + *
    nodes
    + *
    An array containing references to the nodes that were + * inserted
    + *
    purge
    + *
    A function that, when executed, will remove the nodes + * that were inserted
    + *
    + *
    + *
    + *
    onEnd
    + *
    a function that executes when the transaction finishes, regardless of the exit path
    + *
    onFailure
    + *
    + * callback to execute when the script load operation fails + * The callback receives an object back with the following + * data: + *
    + *
    win
    + *
    the window the script(s) were inserted into
    + *
    data
    + *
    the data object passed in when the request was made
    + *
    nodes
    + *
    An array containing references to the nodes that were + * inserted successfully
    + *
    purge
    + *
    A function that, when executed, will remove any nodes + * that were inserted
    + *
    + *
    + *
    + *
    context
    + *
    the execution context for the callbacks
    + *
    win
    + *
    a window other than the one the utility occupies
    + *
    autopurge
    + *
    + * setting to true will let the utilities cleanup routine purge + * the script once loaded + *
    + *
    purgethreshold
    + *
    + * The number of transaction before autopurge should be initiated + *
    + *
    data
    + *
    + * data that is supplied to the callback when the script(s) are + * loaded. + *
    + *
    insertBefore
    + *
    node or node id that will become the new node's nextSibling
    + * + *
    charset
    + *
    Node charset, default utf-8 (deprecated, use the attributes config)
    + *
    attributes
    + *
    An object literal containing additional attributes to add to the link tags
    + *
    timeout
    + *
    Number of milliseconds to wait before aborting and firing the timeout event
    + *
    +         *   Y.Get.script(
    +         *   ["http://yui.yahooapis.com/2.5.2/build/yahoo/yahoo-min.js",
    +         *    "http://yui.yahooapis.com/2.5.2/build/event/event-min.js"], {
    +         *     onSuccess: function(o) {
    +         *       this.log("won't cause error because Y is the context");
    +         *     },
    +         *     onFailure: function(o) {
    +         *     },
    +         *     onTimeout: function(o) {
    +         *     },
    +         *     data: "foo",
    +         *     timeout: 10000, // 10 second timeout
    +         *     context: Y, // make the YUI instance
    +         *     // win: otherframe // target another window/frame
    +         *     autopurge: true // allow the utility to choose when to remove the nodes
    +         *     purgetheshold: 1 // purge previous transaction before next transaction
    +         *   });
    +         * 
    + * @return {tId: string} an object containing info about the transaction + */ + script: function(url, opts) { + return _queue("script", url, opts); + }, + + /** + * Fetches and inserts one or more css link nodes into the + * head of the current document or the document in a specified + * window. + * @method css + * @static + * @param url {string} the url or urls to the css file(s) + * @param opts Options: + *
    + *
    onSuccess
    + *
    + * callback to execute when the css file(s) are finished loading + * The callback receives an object back with the following + * data: + *
    win
    + *
    the window the link nodes(s) were inserted into
    + *
    data
    + *
    the data object passed in when the request was made
    + *
    nodes
    + *
    An array containing references to the nodes that were + * inserted
    + *
    purge
    + *
    A function that, when executed, will remove the nodes + * that were inserted
    + *
    + *
    + * + *
    context
    + *
    the execution context for the callbacks
    + *
    win
    + *
    a window other than the one the utility occupies
    + *
    data
    + *
    + * data that is supplied to the callbacks when the nodes(s) are + * loaded. + *
    + *
    insertBefore
    + *
    node or node id that will become the new node's nextSibling
    + *
    charset
    + *
    Node charset, default utf-8 (deprecated, use the attributes config)
    + *
    attributes
    + *
    An object literal containing additional attributes to add to the link tags
    + * + *
    +         *      Y.Get.css("http://yui.yahooapis.com/2.3.1/build/menu/assets/skins/sam/menu.css");
    +         * 
    + *
    +         *   Y.Get.css(
    +         *   ["http://yui.yahooapis.com/2.3.1/build/menu/assets/skins/sam/menu.css",
    +         *     insertBefore: 'custom-styles' // nodes will be inserted before the specified node
    +         *   });
    +         * 
    + * @return {tId: string} an object containing info about the transaction + */ + css: function(url, opts) { + return _queue("css", url, opts); + } + }; +}(); + +})(); + + +}, '3.0.0' ); diff --git a/jssource/src_files/include/javascript/yui3/build/yui/yui-base-min.js b/jssource/src_files/include/javascript/yui3/build/yui/yui-base-min.js new file mode 100644 index 00000000..80c4f510 --- /dev/null +++ b/jssource/src_files/include/javascript/yui3/build/yui/yui-base-min.js @@ -0,0 +1,9 @@ +/* +Copyright (c) 2009, Yahoo! Inc. All rights reserved. +Code licensed under the BSD License: +http://developer.yahoo.net/yui/license.txt +version: 3.0.0 +build: 1549 +*/ +(function(){var I={},B=new Date().getTime(),A,E,H=function(){if(window.addEventListener){return function(M,L,K,J){M.addEventListener(L,K,(!!J));};}else{if(window.attachEvent){return function(L,K,J){L.attachEvent("on"+K,J);};}else{return function(){};}}}(),F=function(){if(window.removeEventListener){return function(M,L,K,J){M.removeEventListener(L,K,!!J);};}else{if(window.detachEvent){return function(L,K,J){L.detachEvent("on"+K,J);};}else{return function(){};}}}(),D=function(){YUI.Env.windowLoaded=true;YUI.Env.DOMReady=true;F(window,"load",D);},C={"io.xdrReady":1,"io.xdrResponse":1},G=Array.prototype.slice;if(typeof YUI==="undefined"||!YUI){YUI=function(O,N,M,L,J){var K=this,R=arguments,Q,P=R.length;if(!(K instanceof YUI)){return new YUI(O,N,M,L,J);}else{K._init();for(Q=0;Q-1){J="test";}K.version=J;K.Env={mods:{},cdn:"http://yui.yahooapis.com/"+J+"/build/",bootstrapped:false,_idx:0,_used:{},_attached:{},_yidx:0,_uidx:0,_loaded:{}};K.Env._loaded[J]={};if(YUI.Env){K.Env._yidx=(++YUI.Env._yidx);K.Env._guidp=("yui_"+J+"-"+K.Env._yidx+"-"+B).replace(/\./g,"_");K.id=K.stamp(K);I[K.id]=K;}K.constructor=YUI;K.config={win:window||{},doc:document,debug:true,useBrowserConsole:true,throwFail:true,bootstrap:true,fetchCSS:true,base:function(){var L,M,O,N;M=document.getElementsByTagName("script");for(O=0;O1)){F=2;}}catch(G){}}}return F;};E.each=(D.forEach)?function(F,G,H){D.forEach.call(F||[],G,H||B);return B;}:function(G,I,J){var F=(G&&G.length)||0,H;for(H=0;HI)?G[I]:true;}return K;};E.indexOf=(D.indexOf)?function(F,G){return D.indexOf.call(F,G);}:function(F,H){for(var G=0;G-1);};E.owns=function(G,F){return(G.hasOwnProperty(F));};E.each=function(J,I,K,H){var G=K||B,F;for(F in J){if(H||J.hasOwnProperty(F)){I.call(G,J[F],F,J);}}return B;};E.getValue=function(J,I){var H=B.Array(I),F=H.length,G;for(G=0;J!==D&&G=0){for(F=0;G!==D&&F -1) { + v = 'test'; + } + + Y.version = v; + + Y.Env = { + // @todo expand the new module metadata + mods: {}, + cdn: 'http://yui.yahooapis.com/' + v + '/build/', + bootstrapped: false, + _idx: 0, + _used: {}, + _attached: {}, + _yidx: 0, + _uidx: 0, + _loaded: {} + }; + + Y.Env._loaded[v] = {}; + + if (YUI.Env) { + Y.Env._yidx = (++YUI.Env._yidx); + Y.Env._guidp = ('yui_' + v + '-' + Y.Env._yidx + '-' + _startTime).replace(/\./g, '_'); + Y.id = Y.stamp(Y); + _instances[Y.id] = Y; + } + + Y.constructor = YUI; + + // configuration defaults + Y.config = { + + win: window || {}, + doc: document, + debug: true, + useBrowserConsole: true, + throwFail: true, + bootstrap: true, + fetchCSS: true, + + base: function() { + var b, nodes, i, match; + + // get from querystring + nodes = document.getElementsByTagName('script'); + + for (i=0; i + * YUI.namespace("property.package"); + * YUI.namespace("YAHOO.property.package"); + * + * Either of the above would create YUI.property, then + * YUI.property.package (YAHOO is scrubbed out, this is + * to remain compatible with YUI2) + * + * Be careful when naming packages. Reserved words may work in some browsers + * and not others. For instance, the following will fail in Safari: + *
    +     * YUI.namespace("really.long.nested.namespace");
    +     * 
    + * This fails because "long" is a future reserved word in ECMAScript + * + * @method namespace + * @param {string*} arguments 1-n namespaces to create + * @return {object} A reference to the last namespace object created + */ + namespace: function() { + var a=arguments, o=null, i, j, d; + for (i=0; i + *
    DEBUG
    + *
    Selects the debug versions of the library (e.g., event-debug.js). + * This option will automatically include the Logger widget
    + *
    RAW
    + *
    Selects the non-minified version of the library (e.g., event.js).
    + * + * You can also define a custom filter, which must be an object literal + * containing a search expression and a replace string: + *
    + *  myFilter: { 
    + *      'searchExp': "-min\\.js", 
    + *      'replaceStr': "-debug.js"
    + *  }
    + * 
    + * + * For dynamic loading. + * + * @property filter + * @type string|object + */ + +/** + * Hash of per-component filter specification. If specified for a given component, + * this overrides the filter config + * + * For dynamic loading. + * + * @property filters + * @type object + */ + +/** + * Use the YUI combo service to reduce the number of http connections + * required to load your dependencies. + * + * For dynamic loading. + * + * @property combine + * @type boolean + * @default true if 'base' is not supplied, false if it is. + */ + +/** + * A list of modules that should never be dynamically loaded + * + * @property ignore + * @type string[] + */ + +/** + * A list of modules that should always be loaded when required, even if already + * present on the page. + * + * @property force + * @type string[] + */ + +/** + * Node or id for a node that should be used as the insertion point for new nodes + * For dynamic loading. + * + * @property insertBefore + * @type string + */ + +/** + * charset for dynamic nodes + * + * @property charset + * @type string + * @deprecated use jsAttributes cssAttributes + */ + +/** + * Object literal containing attributes to add to dynamically loaded script nodes. + * + * @property jsAttributes + * @type string + */ + +/** + * Object literal containing attributes to add to dynamically loaded link nodes. + * + * @property cssAttributes + * @type string + */ + +/** + * Number of milliseconds before a timeout occurs when dynamically + * loading nodes. If not set, there is no timeout. + * + * @property timeout + * @type int + */ + +/** + * Callback for the 'CSSComplete' event. When dynamically loading YUI + * components with CSS, this property fires when the CSS is finished + * loading but script loading is still ongoing. This provides an + * opportunity to enhance the presentation of a loading page a little + * bit before the entire loading process is done. + * + * @property onCSS + * @type function + */ + +/** + * A list of module definitions to add to the list of YUI components. + * These components can then be dynamically loaded side by side with + * YUI via the use() method.See Loader.addModule for the supported + * module metadata. + * + * @property modules + * @type function + */ + +/** + * The loader 'path' attribute to the loader itself. This is combined + * with the 'base' attribute to dynamically load the loader component + * when boostrapping with the get utility alone. + * + * @property loaderPath + * @default loader/loader-min.js + */ + +/** + * + * Specifies whether or not YUI().use(...) will attempt to load CSS + * resources at all. Any truthy value will cause CSS dependencies + * to load when fetching script. The special value 'force' will + * cause CSS dependencies to be loaded even if no script is needed. + * + * @property fetchCSS + * @default true + */ +YUI.add('yui-base', function(Y) { + +/* + * YUI stub + * @module yui + * @submodule yui-base + */ +/** + * The YUI module contains the components required for building the YUI seed file. + * This includes the script loading mechanism, a simple queue, and the core utilities for the library. + * @module yui + * @submodule yui-base + */ + +/** + * A simple FIFO queue. Items are added to the Queue with add(1..n items) and + * removed using next(). + * + * @class Queue + * @param item* {MIXED} 0..n items to seed the queue + */ +function Queue() { + this._init(); + this.add.apply(this, arguments); +} + +Queue.prototype = { + /** + * Initialize the queue + * + * @method _init + * @protected + */ + _init : function () { + /** + * The collection of enqueued items + * + * @property _q + * @type {Array} + * @protected + */ + this._q = []; + }, + + /** + * Get the next item in the queue. + * + * @method next + * @return {MIXED} the next item in the queue + */ + next : function () { + return this._q.shift(); + }, + + /** + * Add 0..n items to the end of the queue + * + * @method add + * @param item* {MIXED} 0..n items + */ + add : function () { + Y.Array.each(Y.Array(arguments,0,true),function (fn) { + this._q.push(fn); + },this); + + return this; + }, + + /** + * Returns the current number of queued items + * + * @method size + * @return {Number} + */ + size : function () { + return this._q.length; + } +}; + +Y.Queue = Queue; +/** + * The YUI module contains the components required for building the YUI seed file. + * This includes the script loading mechanism, a simple queue, and the core utilities for the library. + * @module yui + * @submodule yui-base + */ +(function() { +/** + * Provides the language utilites and extensions used by the library + * @class Lang + * @static + */ +Y.Lang = Y.Lang || {}; + +var L = Y.Lang, + +ARRAY = 'array', +BOOLEAN = 'boolean', +DATE = 'date', +ERROR = 'error', +FUNCTION = 'function', +NUMBER = 'number', +NULL = 'null', +OBJECT = 'object', +REGEX = 'regexp', +STRING = 'string', +TOSTRING = Object.prototype.toString, +UNDEFINED = 'undefined', + +TYPES = { + 'undefined' : UNDEFINED, + 'number' : NUMBER, + 'boolean' : BOOLEAN, + 'string' : STRING, + '[object Function]' : FUNCTION, + '[object RegExp]' : REGEX, + '[object Array]' : ARRAY, + '[object Date]' : DATE, + '[object Error]' : ERROR +}, + +TRIMREGEX = /^\s+|\s+$/g, +EMPTYSTRING = ''; + +/** + * Determines whether or not the provided item is an array. + * Returns false for array-like collections such as the + * function arguments collection or HTMLElement collection + * will return false. You can use @see Array.test if you + * want to + * @method isArray + * @static + * @param o The object to test + * @return {boolean} true if o is an array + */ +L.isArray = function(o) { + return L.type(o) === ARRAY; +}; + +/** + * Determines whether or not the provided item is a boolean + * @method isBoolean + * @static + * @param o The object to test + * @return {boolean} true if o is a boolean + */ +L.isBoolean = function(o) { + return typeof o === BOOLEAN; +}; + +/** + * Determines whether or not the provided item is a function + * Note: Internet Explorer thinks certain functions are objects: + * + * var obj = document.createElement("object"); + * Y.Lang.isFunction(obj.getAttribute) // reports false in IE + * + * var input = document.createElement("input"); // append to body + * Y.Lang.isFunction(input.focus) // reports false in IE + * + * You will have to implement additional tests if these functions + * matter to you. + * + * @method isFunction + * @static + * @param o The object to test + * @return {boolean} true if o is a function + */ +L.isFunction = function(o) { + return L.type(o) === FUNCTION; +}; + +/** + * Determines whether or not the supplied item is a date instance + * @method isDate + * @static + * @param o The object to test + * @return {boolean} true if o is a date + */ +L.isDate = function(o) { + // return o instanceof Date; + return L.type(o) === DATE; +}; + +/** + * Determines whether or not the provided item is null + * @method isNull + * @static + * @param o The object to test + * @return {boolean} true if o is null + */ +L.isNull = function(o) { + return o === null; +}; + +/** + * Determines whether or not the provided item is a legal number + * @method isNumber + * @static + * @param o The object to test + * @return {boolean} true if o is a number + */ +L.isNumber = function(o) { + return typeof o === NUMBER && isFinite(o); +}; + +/** + * Determines whether or not the provided item is of type object + * or function + * @method isObject + * @static + * @param o The object to test + * @param failfn {boolean} fail if the input is a function + * @return {boolean} true if o is an object + */ +L.isObject = function(o, failfn) { +return (o && (typeof o === OBJECT || (!failfn && L.isFunction(o)))) || false; +}; + +/** + * Determines whether or not the provided item is a string + * @method isString + * @static + * @param o The object to test + * @return {boolean} true if o is a string + */ +L.isString = function(o) { + return typeof o === STRING; +}; + +/** + * Determines whether or not the provided item is undefined + * @method isUndefined + * @static + * @param o The object to test + * @return {boolean} true if o is undefined + */ +L.isUndefined = function(o) { + return typeof o === UNDEFINED; +}; + +/** + * Returns a string without any leading or trailing whitespace. If + * the input is not a string, the input will be returned untouched. + * @method trim + * @static + * @param s {string} the string to trim + * @return {string} the trimmed string + */ +L.trim = function(s){ + try { + return s.replace(TRIMREGEX, EMPTYSTRING); + } catch(e) { + return s; + } +}; + +/** + * A convenience method for detecting a legitimate non-null value. + * Returns false for null/undefined/NaN, true for other values, + * including 0/false/'' + * @method isValue + * @static + * @param o The item to test + * @return {boolean} true if it is not null/undefined/NaN || false + */ +L.isValue = function(o) { + var t = L.type(o); + switch (t) { + case NUMBER: + return isFinite(o); + case NULL: + case UNDEFINED: + return false; + default: + return !!(t); + } +}; + +/** + * Returns a string representing the type of the item passed in. + * @method type + * @param o the item to test + * @return {string} the detected type + */ +L.type = function (o) { + return TYPES[typeof o] || TYPES[TOSTRING.call(o)] || (o ? OBJECT : NULL); +}; + +})(); + +/** + * The YUI module contains the components required for building the YUI seed file. + * This includes the script loading mechanism, a simple queue, and the core utilities for the library. + * @module yui + * @submodule yui-base + */ + +(function() { + +var L = Y.Lang, Native = Array.prototype, + +/** + * Adds the following array utilities to the YUI instance. Additional + * array helpers can be found in the collection component. + * @class Array + */ + +/** + * Y.Array(o) returns an array: + * - Arrays are return unmodified unless the start position is specified. + * - "Array-like" collections (@see Array.test) are converted to arrays + * - For everything else, a new array is created with the input as the sole item + * - The start position is used if the input is or is like an array to return + * a subset of the collection. + * + * @TODO this will not automatically convert elements that are also collections + * such as forms and selects. Passing true as the third param will + * force a conversion. + * + * @method () + * @static + * @param o the item to arrayify + * @param i {int} if an array or array-like, this is the start index + * @param al {boolean} if true, it forces the array-like fork. This + * can be used to avoid multiple array.test calls. + * @return {Array} the resulting array + */ +YArray = function(o, startIdx, al) { + var t = (al) ? 2 : Y.Array.test(o), i, l, a; + + // switch (t) { + // case 1: + // // return (startIdx) ? o.slice(startIdx) : o; + // case 2: + // return Native.slice.call(o, startIdx || 0); + // default: + // return [o]; + // } + + if (t) { + try { + return Native.slice.call(o, startIdx || 0); + // IE errors when trying to slice element collections + } catch(e) { + a=[]; + for (i=0, l=o.length; i 1)) { + r = 2; + } + + } catch(e) {} + } + } + return r; +}; + +/** + * Executes the supplied function on each item in the array. + * @method each + * @param a {Array} the array to iterate + * @param f {Function} the function to execute on each item. The + * function receives three arguments: the value, the index, the full array. + * @param o Optional context object + * @static + * @return {YUI} the YUI instance + */ +YArray.each = (Native.forEach) ? + function (a, f, o) { + Native.forEach.call(a || [], f, o || Y); + return Y; + } : + function (a, f, o) { + var l = (a && a.length) || 0, i; + for (i = 0; i < l; i=i+1) { + f.call(o || Y, a[i], i, a); + } + return Y; + }; + +/** + * Returns an object using the first array as keys, and + * the second as values. If the second array is not + * provided the value is set to true for each. + * @method hash + * @static + * @param k {Array} keyset + * @param v {Array} optional valueset + * @return {object} the hash + */ +YArray.hash = function(k, v) { + var o = {}, l = k.length, vl = v && v.length, i; + for (i=0; i i) ? v[i] : true; + } + + return o; +}; + +/** + * Returns the index of the first item in the array + * that contains the specified value, -1 if the + * value isn't found. + * @method indexOf + * @static + * @param a {Array} the array to search + * @param val the value to search for + * @return {int} the index of the item that contains the value or -1 + */ +YArray.indexOf = (Native.indexOf) ? + function(a, val) { + return Native.indexOf.call(a, val); + } : + function(a, val) { + for (var i=0; i -1); +}; + +/** + * Determines whether or not the property was added + * to the object instance. Returns false if the property is not present + * in the object, or was inherited from the prototype. + * + * @deprecated Safari 1.x support has been removed, so this is simply a + * wrapper for the native implementation. Use the native implementation + * directly instead. + * + * @TODO Remove in B1 + * + * @method owns + * @static + * @param o {any} The object being testing + * @param p {string} the property to look for + * @return {boolean} true if the object has the property on the instance + */ +O.owns = function(o, k) { + return (o.hasOwnProperty(k)); +}; + +/** + * Executes a function on each item. The function + * receives the value, the key, and the object + * as paramters (in that order). + * @method each + * @static + * @param o the object to iterate + * @param f {Function} the function to execute on each item. The function + * receives three arguments: the value, the the key, the full object. + * @param c the execution context + * @param proto {boolean} include proto + * @return {YUI} the YUI instance + */ +O.each = function (o, f, c, proto) { + var s = c || Y, i; + + for (i in o) { + if (proto || o.hasOwnProperty(i)) { + f.call(s, o[i], i, o); + } + } + return Y; +}; + +/* + * Executes a function on each item, but halts if the + * function returns true. The function + * receives the value, the key, and the object + * as paramters (in that order). + * @method some + * @static + * @param o the object to iterate + * @param f {Function} the function to execute on each item. The function + * receives three arguments: the value, the the key, the full object. + * @param c the execution context + * @param proto {boolean} include proto + * @return {boolean} true if any execution of the function returns true, false otherwise + */ +// O.some = function (o, f, c, proto) { +// var s = c || Y, i; +// +// for (i in o) { +// if (proto || o.hasOwnProperty(i)) { +// if (f.call(s, o[i], i, o)) { +// return true; +// } +// } +// } +// return false; +// }; + +/** + * Retrieves the sub value at the provided path, + * from the value object provided. + * + * @method getValue + * @param o The object from which to extract the property value + * @param path {Array} A path array, specifying the object traversal path + * from which to obtain the sub value. + * @return {Any} The value stored in the path, undefined if not found. + * Returns the source object if an empty path is provided. + */ +O.getValue = function (o, path) { + var p=Y.Array(path), l=p.length, i; + + for (i=0; o !== UNDEFINED && i < l; i=i+1) { + o = o[p[i]]; + } + + return o; +}; + +/** + * Sets the sub-attribute value at the provided path on the + * value object. Returns the modified value object, or + * undefined if the path is invalid. + * + * @method setValue + * @param o The object on which to set the sub value. + * @param path {Array} A path array, specifying the object traversal path + * at which to set the sub value. + * @param val {Any} The new value for the sub-attribute. + * @return {Object} The modified object, with the new sub value set, or + * undefined, if the path was invalid. + */ +O.setValue = function(o, path, val) { + + var p=Y.Array(path), leafIdx=p.length-1, i, ref=o; + + if (leafIdx >= 0) { + for (i=0; ref !== UNDEFINED && i < leafIdx; i=i+1) { + ref = ref[p[i]]; + } + + if (ref !== UNDEFINED) { + ref[p[i]] = val; + } else { + return UNDEFINED; + } + } + + return o; +}; + + +})(); + +/** + * The YUI module contains the components required for building the YUI seed file. + * This includes the script loading mechanism, a simple queue, and the core utilities for the library. + * @module yui + * @submodule yui-base + */ + +/** + * YUI user agent detection. + * Do not fork for a browser if it can be avoided. Use feature detection when + * you can. Use the user agent as a last resort. UA stores a version + * number for the browser engine, 0 otherwise. This value may or may not map + * to the version number of the browser using the engine. The value is + * presented as a float so that it can easily be used for boolean evaluation + * as well as for looking for a particular range of versions. Because of this, + * some of the granularity of the version info may be lost (e.g., Gecko 1.8.0.9 + * reports 1.8). + * @class UA + * @static + */ +Y.UA = function() { + + var numberfy = function(s) { + var c = 0; + return parseFloat(s.replace(/\./g, function() { + return (c++ == 1) ? '' : '.'; + })); + }, + + nav = navigator, + + o = { + + /** + * Internet Explorer version number or 0. Example: 6 + * @property ie + * @type float + * @static + */ + ie: 0, + + /** + * Opera version number or 0. Example: 9.2 + * @property opera + * @type float + * @static + */ + opera: 0, + + /** + * Gecko engine revision number. Will evaluate to 1 if Gecko + * is detected but the revision could not be found. Other browsers + * will be 0. Example: 1.8 + *
    +         * Firefox 1.0.0.4: 1.7.8   <-- Reports 1.7
    +         * Firefox 1.5.0.9: 1.8.0.9 <-- Reports 1.8
    +         * Firefox 2.0.0.3: 1.8.1.3 <-- Reports 1.8
    +         * Firefox 3 alpha: 1.9a4   <-- Reports 1.9
    +         * 
    + * @property gecko + * @type float + * @static + */ + gecko: 0, + + /** + * AppleWebKit version. KHTML browsers that are not WebKit browsers + * will evaluate to 1, other browsers 0. Example: 418.9 + *
    +         * Safari 1.3.2 (312.6): 312.8.1 <-- Reports 312.8 -- currently the 
    +         *                                   latest available for Mac OSX 10.3.
    +         * Safari 2.0.2:         416     <-- hasOwnProperty introduced
    +         * Safari 2.0.4:         418     <-- preventDefault fixed
    +         * Safari 2.0.4 (419.3): 418.9.1 <-- One version of Safari may run
    +         *                                   different versions of webkit
    +         * Safari 2.0.4 (419.3): 419     <-- Tiger installations that have been
    +         *                                   updated, but not updated
    +         *                                   to the latest patch.
    +         * Webkit 212 nightly:   522+    <-- Safari 3.0 precursor (with native SVG
    +         *                                   and many major issues fixed).
    +         * Safari 3.0.4 (523.12) 523.12  <-- First Tiger release - automatic update
    +         *                                   from 2.x via the 10.4.11 OS patch
    +         * Webkit nightly 1/2008:525+    <-- Supports DOMContentLoaded event.
    +         *                                   yahoo.com user agent hack removed.
    +         * 
    + * http://en.wikipedia.org/wiki/Safari_(web_browser)#Version_history + * @property webkit + * @type float + * @static + */ + webkit: 0, + + /** + * The mobile property will be set to a string containing any relevant + * user agent information when a modern mobile browser is detected. + * Currently limited to Safari on the iPhone/iPod Touch, Nokia N-series + * devices with the WebKit-based browser, and Opera Mini. + * @property mobile + * @type string + * @static + */ + mobile: null, + + /** + * Adobe AIR version number or 0. Only populated if webkit is detected. + * Example: 1.0 + * @property air + * @type float + */ + air: 0, + + /** + * Google Caja version number or 0. + * @property caja + * @type float + */ + caja: nav.cajaVersion, + + /** + * Set to true if the page appears to be in SSL + * @property secure + * @type boolean + * @static + */ + secure: false, + + /** + * The operating system. Currently only detecting windows or macintosh + * @property os + * @type string + * @static + */ + os: null + + }, + + ua = nav && nav.userAgent, + + loc = Y.config.win.location, + + href = loc && loc.href, + + m; + + o.secure = href && (href.toLowerCase().indexOf("https") === 0); + + if (ua) { + + if ((/windows|win32/i).test(ua)) { + o.os = 'windows'; + } else if ((/macintosh/i).test(ua)) { + o.os = 'macintosh'; + } + + // Modern KHTML browsers should qualify as Safari X-Grade + if ((/KHTML/).test(ua)) { + o.webkit=1; + } + // Modern WebKit browsers are at least X-Grade + m=ua.match(/AppleWebKit\/([^\s]*)/); + if (m&&m[1]) { + o.webkit=numberfy(m[1]); + + // Mobile browser check + if (/ Mobile\//.test(ua)) { + o.mobile = "Apple"; // iPhone or iPod Touch + } else { + m=ua.match(/NokiaN[^\/]*|Android \d\.\d|webOS\/\d\.\d/); + if (m) { + o.mobile = m[0]; // Nokia N-series, Android, webOS, ex: NokiaN95 + } + } + + m=ua.match(/AdobeAIR\/([^\s]*)/); + if (m) { + o.air = m[0]; // Adobe AIR 1.0 or better + } + + } + + if (!o.webkit) { // not webkit + // @todo check Opera/8.01 (J2ME/MIDP; Opera Mini/2.0.4509/1316; fi; U; ssr) + m=ua.match(/Opera[\s\/]([^\s]*)/); + if (m&&m[1]) { + o.opera=numberfy(m[1]); + m=ua.match(/Opera Mini[^;]*/); + if (m) { + o.mobile = m[0]; // ex: Opera Mini/2.0.4509/1316 + } + } else { // not opera or webkit + m=ua.match(/MSIE\s([^;]*)/); + if (m&&m[1]) { + o.ie=numberfy(m[1]); + } else { // not opera, webkit, or ie + m=ua.match(/Gecko\/([^\s]*)/); + if (m) { + o.gecko=1; // Gecko detected, look for revision + m=ua.match(/rv:([^\s\)]*)/); + if (m&&m[1]) { + o.gecko=numberfy(m[1]); + } + } + } + } + } + } + + return o; +}(); +/** + * The YUI module contains the components required for building the YUI seed file. + * This includes the script loading mechanism, a simple queue, and the core utilities for the library. + * @module yui + * @submodule yui-base + */ + +(function() { + + var min = ['yui-base'], core, C = Y.config, mods = YUI.Env.mods, + extras, i; + + // apply the minimal required functionality + Y.use.apply(Y, min); + + + if (C.core) { + core = C.core; + } else { + core = []; + extras = ['get', 'loader', 'yui-log', 'yui-later']; + + for (i=0; i-1){J="test";}K.version=J;K.Env={mods:{},cdn:"http://yui.yahooapis.com/"+J+"/build/",bootstrapped:false,_idx:0,_used:{},_attached:{},_yidx:0,_uidx:0,_loaded:{}};K.Env._loaded[J]={};if(YUI.Env){K.Env._yidx=(++YUI.Env._yidx);K.Env._guidp=("yui_"+J+"-"+K.Env._yidx+"-"+B).replace(/\./g,"_");K.id=K.stamp(K);I[K.id]=K;}K.constructor=YUI;K.config={win:window||{},doc:document,debug:true,useBrowserConsole:true,throwFail:true,bootstrap:true,fetchCSS:true,base:function(){var L,M,O,N;M=document.getElementsByTagName("script");for(O=0;O1)){F=2;}}catch(G){}}}return F;};E.each=(D.forEach)?function(F,G,H){D.forEach.call(F||[],G,H||B);return B;}:function(G,I,J){var F=(G&&G.length)||0,H;for(H=0;HI)?G[I]:true;}return K;};E.indexOf=(D.indexOf)?function(F,G){return D.indexOf.call(F,G);}:function(F,H){for(var G=0;G-1);};E.owns=function(G,F){return(G.hasOwnProperty(F));};E.each=function(J,I,K,H){var G=K||B,F;for(F in J){if(H||J.hasOwnProperty(F)){I.call(G,J[F],F,J);}}return B;};E.getValue=function(J,I){var H=B.Array(I),F=H.length,G;for(G=0;J!==D&&G=0){for(F=0;G!==D&&F -1) { + v = 'test'; + } + + Y.version = v; + + Y.Env = { + // @todo expand the new module metadata + mods: {}, + cdn: 'http://yui.yahooapis.com/' + v + '/build/', + bootstrapped: false, + _idx: 0, + _used: {}, + _attached: {}, + _yidx: 0, + _uidx: 0, + _loaded: {} + }; + + Y.Env._loaded[v] = {}; + + if (YUI.Env) { + Y.Env._yidx = (++YUI.Env._yidx); + Y.Env._guidp = ('yui_' + v + '-' + Y.Env._yidx + '-' + _startTime).replace(/\./g, '_'); + Y.id = Y.stamp(Y); + _instances[Y.id] = Y; + } + + Y.constructor = YUI; + + // configuration defaults + Y.config = { + + win: window || {}, + doc: document, + debug: true, + useBrowserConsole: true, + throwFail: true, + bootstrap: true, + fetchCSS: true, + + base: function() { + var b, nodes, i, match; + + // get from querystring + nodes = document.getElementsByTagName('script'); + + for (i=0; i + * YUI.namespace("property.package"); + * YUI.namespace("YAHOO.property.package"); + * + * Either of the above would create YUI.property, then + * YUI.property.package (YAHOO is scrubbed out, this is + * to remain compatible with YUI2) + * + * Be careful when naming packages. Reserved words may work in some browsers + * and not others. For instance, the following will fail in Safari: + *
    +     * YUI.namespace("really.long.nested.namespace");
    +     * 
    + * This fails because "long" is a future reserved word in ECMAScript + * + * @method namespace + * @param {string*} arguments 1-n namespaces to create + * @return {object} A reference to the last namespace object created + */ + namespace: function() { + var a=arguments, o=null, i, j, d; + for (i=0; i + *
    DEBUG
    + *
    Selects the debug versions of the library (e.g., event-debug.js). + * This option will automatically include the Logger widget
    + *
    RAW
    + *
    Selects the non-minified version of the library (e.g., event.js).
    + * + * You can also define a custom filter, which must be an object literal + * containing a search expression and a replace string: + *
    + *  myFilter: { 
    + *      'searchExp': "-min\\.js", 
    + *      'replaceStr': "-debug.js"
    + *  }
    + * 
    + * + * For dynamic loading. + * + * @property filter + * @type string|object + */ + +/** + * Hash of per-component filter specification. If specified for a given component, + * this overrides the filter config + * + * For dynamic loading. + * + * @property filters + * @type object + */ + +/** + * Use the YUI combo service to reduce the number of http connections + * required to load your dependencies. + * + * For dynamic loading. + * + * @property combine + * @type boolean + * @default true if 'base' is not supplied, false if it is. + */ + +/** + * A list of modules that should never be dynamically loaded + * + * @property ignore + * @type string[] + */ + +/** + * A list of modules that should always be loaded when required, even if already + * present on the page. + * + * @property force + * @type string[] + */ + +/** + * Node or id for a node that should be used as the insertion point for new nodes + * For dynamic loading. + * + * @property insertBefore + * @type string + */ + +/** + * charset for dynamic nodes + * + * @property charset + * @type string + * @deprecated use jsAttributes cssAttributes + */ + +/** + * Object literal containing attributes to add to dynamically loaded script nodes. + * + * @property jsAttributes + * @type string + */ + +/** + * Object literal containing attributes to add to dynamically loaded link nodes. + * + * @property cssAttributes + * @type string + */ + +/** + * Number of milliseconds before a timeout occurs when dynamically + * loading nodes. If not set, there is no timeout. + * + * @property timeout + * @type int + */ + +/** + * Callback for the 'CSSComplete' event. When dynamically loading YUI + * components with CSS, this property fires when the CSS is finished + * loading but script loading is still ongoing. This provides an + * opportunity to enhance the presentation of a loading page a little + * bit before the entire loading process is done. + * + * @property onCSS + * @type function + */ + +/** + * A list of module definitions to add to the list of YUI components. + * These components can then be dynamically loaded side by side with + * YUI via the use() method.See Loader.addModule for the supported + * module metadata. + * + * @property modules + * @type function + */ + +/** + * The loader 'path' attribute to the loader itself. This is combined + * with the 'base' attribute to dynamically load the loader component + * when boostrapping with the get utility alone. + * + * @property loaderPath + * @default loader/loader-min.js + */ + +/** + * + * Specifies whether or not YUI().use(...) will attempt to load CSS + * resources at all. Any truthy value will cause CSS dependencies + * to load when fetching script. The special value 'force' will + * cause CSS dependencies to be loaded even if no script is needed. + * + * @property fetchCSS + * @default true + */ +YUI.add('yui-base', function(Y) { + +/* + * YUI stub + * @module yui + * @submodule yui-base + */ +/** + * The YUI module contains the components required for building the YUI seed file. + * This includes the script loading mechanism, a simple queue, and the core utilities for the library. + * @module yui + * @submodule yui-base + */ + +/** + * A simple FIFO queue. Items are added to the Queue with add(1..n items) and + * removed using next(). + * + * @class Queue + * @param item* {MIXED} 0..n items to seed the queue + */ +function Queue() { + this._init(); + this.add.apply(this, arguments); +} + +Queue.prototype = { + /** + * Initialize the queue + * + * @method _init + * @protected + */ + _init : function () { + /** + * The collection of enqueued items + * + * @property _q + * @type {Array} + * @protected + */ + this._q = []; + }, + + /** + * Get the next item in the queue. + * + * @method next + * @return {MIXED} the next item in the queue + */ + next : function () { + return this._q.shift(); + }, + + /** + * Add 0..n items to the end of the queue + * + * @method add + * @param item* {MIXED} 0..n items + */ + add : function () { + Y.Array.each(Y.Array(arguments,0,true),function (fn) { + this._q.push(fn); + },this); + + return this; + }, + + /** + * Returns the current number of queued items + * + * @method size + * @return {Number} + */ + size : function () { + return this._q.length; + } +}; + +Y.Queue = Queue; +/** + * The YUI module contains the components required for building the YUI seed file. + * This includes the script loading mechanism, a simple queue, and the core utilities for the library. + * @module yui + * @submodule yui-base + */ +(function() { +/** + * Provides the language utilites and extensions used by the library + * @class Lang + * @static + */ +Y.Lang = Y.Lang || {}; + +var L = Y.Lang, + +ARRAY = 'array', +BOOLEAN = 'boolean', +DATE = 'date', +ERROR = 'error', +FUNCTION = 'function', +NUMBER = 'number', +NULL = 'null', +OBJECT = 'object', +REGEX = 'regexp', +STRING = 'string', +TOSTRING = Object.prototype.toString, +UNDEFINED = 'undefined', + +TYPES = { + 'undefined' : UNDEFINED, + 'number' : NUMBER, + 'boolean' : BOOLEAN, + 'string' : STRING, + '[object Function]' : FUNCTION, + '[object RegExp]' : REGEX, + '[object Array]' : ARRAY, + '[object Date]' : DATE, + '[object Error]' : ERROR +}, + +TRIMREGEX = /^\s+|\s+$/g, +EMPTYSTRING = ''; + +/** + * Determines whether or not the provided item is an array. + * Returns false for array-like collections such as the + * function arguments collection or HTMLElement collection + * will return false. You can use @see Array.test if you + * want to + * @method isArray + * @static + * @param o The object to test + * @return {boolean} true if o is an array + */ +L.isArray = function(o) { + return L.type(o) === ARRAY; +}; + +/** + * Determines whether or not the provided item is a boolean + * @method isBoolean + * @static + * @param o The object to test + * @return {boolean} true if o is a boolean + */ +L.isBoolean = function(o) { + return typeof o === BOOLEAN; +}; + +/** + * Determines whether or not the provided item is a function + * Note: Internet Explorer thinks certain functions are objects: + * + * var obj = document.createElement("object"); + * Y.Lang.isFunction(obj.getAttribute) // reports false in IE + * + * var input = document.createElement("input"); // append to body + * Y.Lang.isFunction(input.focus) // reports false in IE + * + * You will have to implement additional tests if these functions + * matter to you. + * + * @method isFunction + * @static + * @param o The object to test + * @return {boolean} true if o is a function + */ +L.isFunction = function(o) { + return L.type(o) === FUNCTION; +}; + +/** + * Determines whether or not the supplied item is a date instance + * @method isDate + * @static + * @param o The object to test + * @return {boolean} true if o is a date + */ +L.isDate = function(o) { + // return o instanceof Date; + return L.type(o) === DATE; +}; + +/** + * Determines whether or not the provided item is null + * @method isNull + * @static + * @param o The object to test + * @return {boolean} true if o is null + */ +L.isNull = function(o) { + return o === null; +}; + +/** + * Determines whether or not the provided item is a legal number + * @method isNumber + * @static + * @param o The object to test + * @return {boolean} true if o is a number + */ +L.isNumber = function(o) { + return typeof o === NUMBER && isFinite(o); +}; + +/** + * Determines whether or not the provided item is of type object + * or function + * @method isObject + * @static + * @param o The object to test + * @param failfn {boolean} fail if the input is a function + * @return {boolean} true if o is an object + */ +L.isObject = function(o, failfn) { +return (o && (typeof o === OBJECT || (!failfn && L.isFunction(o)))) || false; +}; + +/** + * Determines whether or not the provided item is a string + * @method isString + * @static + * @param o The object to test + * @return {boolean} true if o is a string + */ +L.isString = function(o) { + return typeof o === STRING; +}; + +/** + * Determines whether or not the provided item is undefined + * @method isUndefined + * @static + * @param o The object to test + * @return {boolean} true if o is undefined + */ +L.isUndefined = function(o) { + return typeof o === UNDEFINED; +}; + +/** + * Returns a string without any leading or trailing whitespace. If + * the input is not a string, the input will be returned untouched. + * @method trim + * @static + * @param s {string} the string to trim + * @return {string} the trimmed string + */ +L.trim = function(s){ + try { + return s.replace(TRIMREGEX, EMPTYSTRING); + } catch(e) { + return s; + } +}; + +/** + * A convenience method for detecting a legitimate non-null value. + * Returns false for null/undefined/NaN, true for other values, + * including 0/false/'' + * @method isValue + * @static + * @param o The item to test + * @return {boolean} true if it is not null/undefined/NaN || false + */ +L.isValue = function(o) { + var t = L.type(o); + switch (t) { + case NUMBER: + return isFinite(o); + case NULL: + case UNDEFINED: + return false; + default: + return !!(t); + } +}; + +/** + * Returns a string representing the type of the item passed in. + * @method type + * @param o the item to test + * @return {string} the detected type + */ +L.type = function (o) { + return TYPES[typeof o] || TYPES[TOSTRING.call(o)] || (o ? OBJECT : NULL); +}; + +})(); + +/** + * The YUI module contains the components required for building the YUI seed file. + * This includes the script loading mechanism, a simple queue, and the core utilities for the library. + * @module yui + * @submodule yui-base + */ + +(function() { + +var L = Y.Lang, Native = Array.prototype, + +/** + * Adds the following array utilities to the YUI instance. Additional + * array helpers can be found in the collection component. + * @class Array + */ + +/** + * Y.Array(o) returns an array: + * - Arrays are return unmodified unless the start position is specified. + * - "Array-like" collections (@see Array.test) are converted to arrays + * - For everything else, a new array is created with the input as the sole item + * - The start position is used if the input is or is like an array to return + * a subset of the collection. + * + * @TODO this will not automatically convert elements that are also collections + * such as forms and selects. Passing true as the third param will + * force a conversion. + * + * @method () + * @static + * @param o the item to arrayify + * @param i {int} if an array or array-like, this is the start index + * @param al {boolean} if true, it forces the array-like fork. This + * can be used to avoid multiple array.test calls. + * @return {Array} the resulting array + */ +YArray = function(o, startIdx, al) { + var t = (al) ? 2 : Y.Array.test(o), i, l, a; + + // switch (t) { + // case 1: + // // return (startIdx) ? o.slice(startIdx) : o; + // case 2: + // return Native.slice.call(o, startIdx || 0); + // default: + // return [o]; + // } + + if (t) { + try { + return Native.slice.call(o, startIdx || 0); + // IE errors when trying to slice element collections + } catch(e) { + a=[]; + for (i=0, l=o.length; i 1)) { + r = 2; + } + + } catch(e) {} + } + } + return r; +}; + +/** + * Executes the supplied function on each item in the array. + * @method each + * @param a {Array} the array to iterate + * @param f {Function} the function to execute on each item. The + * function receives three arguments: the value, the index, the full array. + * @param o Optional context object + * @static + * @return {YUI} the YUI instance + */ +YArray.each = (Native.forEach) ? + function (a, f, o) { + Native.forEach.call(a || [], f, o || Y); + return Y; + } : + function (a, f, o) { + var l = (a && a.length) || 0, i; + for (i = 0; i < l; i=i+1) { + f.call(o || Y, a[i], i, a); + } + return Y; + }; + +/** + * Returns an object using the first array as keys, and + * the second as values. If the second array is not + * provided the value is set to true for each. + * @method hash + * @static + * @param k {Array} keyset + * @param v {Array} optional valueset + * @return {object} the hash + */ +YArray.hash = function(k, v) { + var o = {}, l = k.length, vl = v && v.length, i; + for (i=0; i i) ? v[i] : true; + } + + return o; +}; + +/** + * Returns the index of the first item in the array + * that contains the specified value, -1 if the + * value isn't found. + * @method indexOf + * @static + * @param a {Array} the array to search + * @param val the value to search for + * @return {int} the index of the item that contains the value or -1 + */ +YArray.indexOf = (Native.indexOf) ? + function(a, val) { + return Native.indexOf.call(a, val); + } : + function(a, val) { + for (var i=0; i -1); +}; + +/** + * Determines whether or not the property was added + * to the object instance. Returns false if the property is not present + * in the object, or was inherited from the prototype. + * + * @deprecated Safari 1.x support has been removed, so this is simply a + * wrapper for the native implementation. Use the native implementation + * directly instead. + * + * @TODO Remove in B1 + * + * @method owns + * @static + * @param o {any} The object being testing + * @param p {string} the property to look for + * @return {boolean} true if the object has the property on the instance + */ +O.owns = function(o, k) { + return (o.hasOwnProperty(k)); +}; + +/** + * Executes a function on each item. The function + * receives the value, the key, and the object + * as paramters (in that order). + * @method each + * @static + * @param o the object to iterate + * @param f {Function} the function to execute on each item. The function + * receives three arguments: the value, the the key, the full object. + * @param c the execution context + * @param proto {boolean} include proto + * @return {YUI} the YUI instance + */ +O.each = function (o, f, c, proto) { + var s = c || Y, i; + + for (i in o) { + if (proto || o.hasOwnProperty(i)) { + f.call(s, o[i], i, o); + } + } + return Y; +}; + +/* + * Executes a function on each item, but halts if the + * function returns true. The function + * receives the value, the key, and the object + * as paramters (in that order). + * @method some + * @static + * @param o the object to iterate + * @param f {Function} the function to execute on each item. The function + * receives three arguments: the value, the the key, the full object. + * @param c the execution context + * @param proto {boolean} include proto + * @return {boolean} true if any execution of the function returns true, false otherwise + */ +// O.some = function (o, f, c, proto) { +// var s = c || Y, i; +// +// for (i in o) { +// if (proto || o.hasOwnProperty(i)) { +// if (f.call(s, o[i], i, o)) { +// return true; +// } +// } +// } +// return false; +// }; + +/** + * Retrieves the sub value at the provided path, + * from the value object provided. + * + * @method getValue + * @param o The object from which to extract the property value + * @param path {Array} A path array, specifying the object traversal path + * from which to obtain the sub value. + * @return {Any} The value stored in the path, undefined if not found. + * Returns the source object if an empty path is provided. + */ +O.getValue = function (o, path) { + var p=Y.Array(path), l=p.length, i; + + for (i=0; o !== UNDEFINED && i < l; i=i+1) { + o = o[p[i]]; + } + + return o; +}; + +/** + * Sets the sub-attribute value at the provided path on the + * value object. Returns the modified value object, or + * undefined if the path is invalid. + * + * @method setValue + * @param o The object on which to set the sub value. + * @param path {Array} A path array, specifying the object traversal path + * at which to set the sub value. + * @param val {Any} The new value for the sub-attribute. + * @return {Object} The modified object, with the new sub value set, or + * undefined, if the path was invalid. + */ +O.setValue = function(o, path, val) { + + var p=Y.Array(path), leafIdx=p.length-1, i, ref=o; + + if (leafIdx >= 0) { + for (i=0; ref !== UNDEFINED && i < leafIdx; i=i+1) { + ref = ref[p[i]]; + } + + if (ref !== UNDEFINED) { + ref[p[i]] = val; + } else { + return UNDEFINED; + } + } + + return o; +}; + + +})(); + +/** + * The YUI module contains the components required for building the YUI seed file. + * This includes the script loading mechanism, a simple queue, and the core utilities for the library. + * @module yui + * @submodule yui-base + */ + +/** + * YUI user agent detection. + * Do not fork for a browser if it can be avoided. Use feature detection when + * you can. Use the user agent as a last resort. UA stores a version + * number for the browser engine, 0 otherwise. This value may or may not map + * to the version number of the browser using the engine. The value is + * presented as a float so that it can easily be used for boolean evaluation + * as well as for looking for a particular range of versions. Because of this, + * some of the granularity of the version info may be lost (e.g., Gecko 1.8.0.9 + * reports 1.8). + * @class UA + * @static + */ +Y.UA = function() { + + var numberfy = function(s) { + var c = 0; + return parseFloat(s.replace(/\./g, function() { + return (c++ == 1) ? '' : '.'; + })); + }, + + nav = navigator, + + o = { + + /** + * Internet Explorer version number or 0. Example: 6 + * @property ie + * @type float + * @static + */ + ie: 0, + + /** + * Opera version number or 0. Example: 9.2 + * @property opera + * @type float + * @static + */ + opera: 0, + + /** + * Gecko engine revision number. Will evaluate to 1 if Gecko + * is detected but the revision could not be found. Other browsers + * will be 0. Example: 1.8 + *
    +         * Firefox 1.0.0.4: 1.7.8   <-- Reports 1.7
    +         * Firefox 1.5.0.9: 1.8.0.9 <-- Reports 1.8
    +         * Firefox 2.0.0.3: 1.8.1.3 <-- Reports 1.8
    +         * Firefox 3 alpha: 1.9a4   <-- Reports 1.9
    +         * 
    + * @property gecko + * @type float + * @static + */ + gecko: 0, + + /** + * AppleWebKit version. KHTML browsers that are not WebKit browsers + * will evaluate to 1, other browsers 0. Example: 418.9 + *
    +         * Safari 1.3.2 (312.6): 312.8.1 <-- Reports 312.8 -- currently the 
    +         *                                   latest available for Mac OSX 10.3.
    +         * Safari 2.0.2:         416     <-- hasOwnProperty introduced
    +         * Safari 2.0.4:         418     <-- preventDefault fixed
    +         * Safari 2.0.4 (419.3): 418.9.1 <-- One version of Safari may run
    +         *                                   different versions of webkit
    +         * Safari 2.0.4 (419.3): 419     <-- Tiger installations that have been
    +         *                                   updated, but not updated
    +         *                                   to the latest patch.
    +         * Webkit 212 nightly:   522+    <-- Safari 3.0 precursor (with native SVG
    +         *                                   and many major issues fixed).
    +         * Safari 3.0.4 (523.12) 523.12  <-- First Tiger release - automatic update
    +         *                                   from 2.x via the 10.4.11 OS patch
    +         * Webkit nightly 1/2008:525+    <-- Supports DOMContentLoaded event.
    +         *                                   yahoo.com user agent hack removed.
    +         * 
    + * http://en.wikipedia.org/wiki/Safari_(web_browser)#Version_history + * @property webkit + * @type float + * @static + */ + webkit: 0, + + /** + * The mobile property will be set to a string containing any relevant + * user agent information when a modern mobile browser is detected. + * Currently limited to Safari on the iPhone/iPod Touch, Nokia N-series + * devices with the WebKit-based browser, and Opera Mini. + * @property mobile + * @type string + * @static + */ + mobile: null, + + /** + * Adobe AIR version number or 0. Only populated if webkit is detected. + * Example: 1.0 + * @property air + * @type float + */ + air: 0, + + /** + * Google Caja version number or 0. + * @property caja + * @type float + */ + caja: nav.cajaVersion, + + /** + * Set to true if the page appears to be in SSL + * @property secure + * @type boolean + * @static + */ + secure: false, + + /** + * The operating system. Currently only detecting windows or macintosh + * @property os + * @type string + * @static + */ + os: null + + }, + + ua = nav && nav.userAgent, + + loc = Y.config.win.location, + + href = loc && loc.href, + + m; + + o.secure = href && (href.toLowerCase().indexOf("https") === 0); + + if (ua) { + + if ((/windows|win32/i).test(ua)) { + o.os = 'windows'; + } else if ((/macintosh/i).test(ua)) { + o.os = 'macintosh'; + } + + // Modern KHTML browsers should qualify as Safari X-Grade + if ((/KHTML/).test(ua)) { + o.webkit=1; + } + // Modern WebKit browsers are at least X-Grade + m=ua.match(/AppleWebKit\/([^\s]*)/); + if (m&&m[1]) { + o.webkit=numberfy(m[1]); + + // Mobile browser check + if (/ Mobile\//.test(ua)) { + o.mobile = "Apple"; // iPhone or iPod Touch + } else { + m=ua.match(/NokiaN[^\/]*|Android \d\.\d|webOS\/\d\.\d/); + if (m) { + o.mobile = m[0]; // Nokia N-series, Android, webOS, ex: NokiaN95 + } + } + + m=ua.match(/AdobeAIR\/([^\s]*)/); + if (m) { + o.air = m[0]; // Adobe AIR 1.0 or better + } + + } + + if (!o.webkit) { // not webkit + // @todo check Opera/8.01 (J2ME/MIDP; Opera Mini/2.0.4509/1316; fi; U; ssr) + m=ua.match(/Opera[\s\/]([^\s]*)/); + if (m&&m[1]) { + o.opera=numberfy(m[1]); + m=ua.match(/Opera Mini[^;]*/); + if (m) { + o.mobile = m[0]; // ex: Opera Mini/2.0.4509/1316 + } + } else { // not opera or webkit + m=ua.match(/MSIE\s([^;]*)/); + if (m&&m[1]) { + o.ie=numberfy(m[1]); + } else { // not opera, webkit, or ie + m=ua.match(/Gecko\/([^\s]*)/); + if (m) { + o.gecko=1; // Gecko detected, look for revision + m=ua.match(/rv:([^\s\)]*)/); + if (m&&m[1]) { + o.gecko=numberfy(m[1]); + } + } + } + } + } + } + + return o; +}(); +/** + * The YUI module contains the components required for building the YUI seed file. + * This includes the script loading mechanism, a simple queue, and the core utilities for the library. + * @module yui + * @submodule yui-base + */ + +(function() { + + var min = ['yui-base'], core, C = Y.config, mods = YUI.Env.mods, + extras, i; + + // apply the minimal required functionality + Y.use.apply(Y, min); + + + if (C.core) { + core = C.core; + } else { + core = []; + extras = ['get', 'loader', 'yui-log', 'yui-later']; + + for (i=0; i + *
    onSuccess
    + *
    + * callback to execute when the script(s) are finished loading + * The callback receives an object back with the following + * data: + *
    + *
    win
    + *
    the window the script(s) were inserted into
    + *
    data
    + *
    the data object passed in when the request was made
    + *
    nodes
    + *
    An array containing references to the nodes that were + * inserted
    + *
    purge
    + *
    A function that, when executed, will remove the nodes + * that were inserted
    + *
    + *
    + *
    + *
    onTimeout
    + *
    + * callback to execute when a timeout occurs. + * The callback receives an object back with the following + * data: + *
    + *
    win
    + *
    the window the script(s) were inserted into
    + *
    data
    + *
    the data object passed in when the request was made
    + *
    nodes
    + *
    An array containing references to the nodes that were + * inserted
    + *
    purge
    + *
    A function that, when executed, will remove the nodes + * that were inserted
    + *
    + *
    + *
    + *
    onEnd
    + *
    a function that executes when the transaction finishes, regardless of the exit path
    + *
    onFailure
    + *
    + * callback to execute when the script load operation fails + * The callback receives an object back with the following + * data: + *
    + *
    win
    + *
    the window the script(s) were inserted into
    + *
    data
    + *
    the data object passed in when the request was made
    + *
    nodes
    + *
    An array containing references to the nodes that were + * inserted successfully
    + *
    purge
    + *
    A function that, when executed, will remove any nodes + * that were inserted
    + *
    + *
    + *
    + *
    context
    + *
    the execution context for the callbacks
    + *
    win
    + *
    a window other than the one the utility occupies
    + *
    autopurge
    + *
    + * setting to true will let the utilities cleanup routine purge + * the script once loaded + *
    + *
    purgethreshold
    + *
    + * The number of transaction before autopurge should be initiated + *
    + *
    data
    + *
    + * data that is supplied to the callback when the script(s) are + * loaded. + *
    + *
    insertBefore
    + *
    node or node id that will become the new node's nextSibling
    + * + *
    charset
    + *
    Node charset, default utf-8 (deprecated, use the attributes config)
    + *
    attributes
    + *
    An object literal containing additional attributes to add to the link tags
    + *
    timeout
    + *
    Number of milliseconds to wait before aborting and firing the timeout event
    + *
    +         *   Y.Get.script(
    +         *   ["http://yui.yahooapis.com/2.5.2/build/yahoo/yahoo-min.js",
    +         *    "http://yui.yahooapis.com/2.5.2/build/event/event-min.js"], {
    +         *     onSuccess: function(o) {
    +         *       this.log("won't cause error because Y is the context");
    +         *     },
    +         *     onFailure: function(o) {
    +         *     },
    +         *     onTimeout: function(o) {
    +         *     },
    +         *     data: "foo",
    +         *     timeout: 10000, // 10 second timeout
    +         *     context: Y, // make the YUI instance
    +         *     // win: otherframe // target another window/frame
    +         *     autopurge: true // allow the utility to choose when to remove the nodes
    +         *     purgetheshold: 1 // purge previous transaction before next transaction
    +         *   });
    +         * 
    + * @return {tId: string} an object containing info about the transaction + */ + script: function(url, opts) { + return _queue("script", url, opts); + }, + + /** + * Fetches and inserts one or more css link nodes into the + * head of the current document or the document in a specified + * window. + * @method css + * @static + * @param url {string} the url or urls to the css file(s) + * @param opts Options: + *
    + *
    onSuccess
    + *
    + * callback to execute when the css file(s) are finished loading + * The callback receives an object back with the following + * data: + *
    win
    + *
    the window the link nodes(s) were inserted into
    + *
    data
    + *
    the data object passed in when the request was made
    + *
    nodes
    + *
    An array containing references to the nodes that were + * inserted
    + *
    purge
    + *
    A function that, when executed, will remove the nodes + * that were inserted
    + *
    + *
    + * + *
    context
    + *
    the execution context for the callbacks
    + *
    win
    + *
    a window other than the one the utility occupies
    + *
    data
    + *
    + * data that is supplied to the callbacks when the nodes(s) are + * loaded. + *
    + *
    insertBefore
    + *
    node or node id that will become the new node's nextSibling
    + *
    charset
    + *
    Node charset, default utf-8 (deprecated, use the attributes config)
    + *
    attributes
    + *
    An object literal containing additional attributes to add to the link tags
    + * + *
    +         *      Y.Get.css("http://yui.yahooapis.com/2.3.1/build/menu/assets/skins/sam/menu.css");
    +         * 
    + *
    +         *   Y.Get.css(
    +         *   ["http://yui.yahooapis.com/2.3.1/build/menu/assets/skins/sam/menu.css",
    +         *     insertBefore: 'custom-styles' // nodes will be inserted before the specified node
    +         *   });
    +         * 
    + * @return {tId: string} an object containing info about the transaction + */ + css: function(url, opts) { + return _queue("css", url, opts); + } + }; +}(); + +})(); + + +}, '3.0.0' ); +YUI.add('yui-log', function(Y) { + +/** + * Provides console log capability and exposes a custom event for + * console implementations. + * @module yui + * @submodule yui-log + */ +(function() { + +var INSTANCE = Y, + LOGEVENT = 'yui:log', + UNDEFINED = 'undefined', + LEVELS = { debug: 1, info: 1, warn: 1, error: 1 }, + _published; + +/** + * If the 'debug' config is true, a 'yui:log' event will be + * dispatched, which the Console widget and anything else + * can consume. If the 'useBrowserConsole' config is true, it will + * write to the browser console if available. YUI-specific log + * messages will only be present in the -debug versions of the + * JS files. The build system is supposed to remove log statements + * from the raw and minified versions of the files. + * + * @method log + * @for YUI + * @param {String} msg The message to log. + * @param {String} cat The log category for the message. Default + * categories are "info", "warn", "error", time". + * Custom categories can be used as well. (opt) + * @param {String} src The source of the the message (opt) + * @param {boolean} silent If true, the log event won't fire + * @return {YUI} YUI instance + */ +INSTANCE.log = function(msg, cat, src, silent) { + var Y = INSTANCE, c = Y.config, bail = false, excl, incl, m, f; + // suppress log message if the config is off or the event stack + // or the event call stack contains a consumer of the yui:log event + if (c.debug) { + // apply source filters + if (src) { + excl = c.logExclude; + incl = c.logInclude; + + if (incl && !(src in incl)) { + bail = 1; + } else if (excl && (src in excl)) { + bail = 1; + } + } + + if (!bail) { + + if (c.useBrowserConsole) { + m = (src) ? src + ': ' + msg : msg; + if (typeof console != UNDEFINED && console.log) { + f = (cat && console[cat] && (cat in LEVELS)) ? cat : 'log'; + console[f](m); + } else if (typeof opera != UNDEFINED) { + opera.postError(m); + } + } + + if (Y.fire && !silent) { + if (!_published) { + Y.publish(LOGEVENT, { + broadcast: 2, + emitFacade: 1 + }); + + _published = 1; + + } + Y.fire(LOGEVENT, { + msg: msg, + cat: cat, + src: src + }); + } + } + } + + return Y; +}; + +/** + * Write a system message. This message will be preserved in the + * minified and raw versions of the YUI files, unlike log statements. + * @method message + * @for YUI + * @param {String} msg The message to log. + * @param {String} cat The log category for the message. Default + * categories are "info", "warn", "error", time". + * Custom categories can be used as well. (opt) + * @param {String} src The source of the the message (opt) + * @param {boolean} silent If true, the log event won't fire + * @return {YUI} YUI instance + */ +INSTANCE.message = function() { + return INSTANCE.log.apply(INSTANCE, arguments); +}; + +})(); + + +}, '3.0.0' ,{requires:['yui-base']}); +YUI.add('yui-later', function(Y) { + +/** + * Provides a setTimeout/setInterval wrapper + * @module yui + * @submodule yui-later + */ +(function() { + var L = Y.Lang, + + /** + * Executes the supplied function in the context of the supplied + * object 'when' milliseconds later. Executes the function a + * single time unless periodic is set to true. + * @method later + * @for YUI + * @param when {int} the number of milliseconds to wait until the fn + * is executed. + * @param o the context object. + * @param fn {Function|String} the function to execute or the name of + * the method in the 'o' object to execute. + * @param data [Array] data that is provided to the function. This accepts + * either a single item or an array. If an array is provided, the + * function is executed with one parameter for each array item. If + * you need to pass a single array parameter, it needs to be wrapped in + * an array [myarray]. + * @param periodic {boolean} if true, executes continuously at supplied + * interval until canceled. + * @return {object} a timer object. Call the cancel() method on this object to + * stop the timer. + */ + later = function(when, o, fn, data, periodic) { + when = when || 0; + o = o || {}; + var m=fn, d=Y.Array(data), f, r; + + if (L.isString(fn)) { + m = o[fn]; + } + + if (!m) { + } + + f = function() { + m.apply(o, d); + }; + + r = (periodic) ? setInterval(f, when) : setTimeout(f, when); + + return { + id: r, + interval: periodic, + cancel: function() { + if (this.interval) { + clearInterval(r); + } else { + clearTimeout(r); + } + } + }; + }; + + Y.later = later; + L.later = later; + +})(); + + +}, '3.0.0' ,{requires:['yui-base']}); + + +YUI.add('yui', function(Y){}, '3.0.0' ,{use:['yui-base','get','yui-log','yui-later']}); + diff --git a/jssource/src_files/include/jsolait/init.js b/jssource/src_files/include/jsolait/init.js new file mode 100644 index 00000000..1fcae4fb --- /dev/null +++ b/jssource/src_files/include/jsolait/init.js @@ -0,0 +1,755 @@ +/* + +Modification information for LGPL compliance + +r56990 - 2010-06-16 13:05:36 -0700 (Wed, 16 Jun 2010) - kjing - snapshot "Mango" svn branch to a new one for GitHub sync + +r56989 - 2010-06-16 13:01:33 -0700 (Wed, 16 Jun 2010) - kjing - defunt "Mango" svn dev branch before github cutover + +r55980 - 2010-04-19 13:31:28 -0700 (Mon, 19 Apr 2010) - kjing - create Mango (6.1) based on windex + +r51719 - 2009-10-22 10:18:00 -0700 (Thu, 22 Oct 2009) - mitani - Converted to Build 3 tags and updated the build system + +r51634 - 2009-10-19 13:32:22 -0700 (Mon, 19 Oct 2009) - mitani - Windex is the branch for Sugar Sales 1.0 development + +r50375 - 2009-08-24 18:07:43 -0700 (Mon, 24 Aug 2009) - dwong - branch kobe2 from tokyo r50372 + +r42807 - 2008-12-29 11:16:59 -0800 (Mon, 29 Dec 2008) - dwong - Branch from trunk/sugarcrm r42806 to branches/tokyo/sugarcrm + +r11496 - 2006-02-03 12:16:49 -0800 (Fri, 03 Feb 2006) - chris - Bug 4538: found 2 non-breaking, IE specific JS errors in sugar_3.js and init.js, added some logic to detect whether the browser supports IE activeX stuff and to run code appropriately. +Touched sugar_3.js and include/jsolait/init.js + +r4085 - 2005-04-13 17:30:42 -0700 (Wed, 13 Apr 2005) - robert - adding meeting scheduler and accept/decline + + +*/ + +/* + Copyright (c) 2003 Jan-Klaas Kollhof + + This file is part of the JavaScript o lait library(jsolait). + + jsolait is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + This software 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this software; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +/** + Evaluates script in a global scope. + @param [0] The code to evaluate. +*/ +globalEval=function(){ + return eval(arguments[0]); +} + + +/** + Creates a new class object which inherits from superClass. + @param className="anonymous" The name of the new class. + If the created class is a public member of a module then + the className is automatically set. + @param superClass=Object The class to inherit from (super class). + @param classScope A function which is executed for class construction. + As 1st parameter it will get the new class' protptype for + overrideing or extending the super class. As 2nd parameter it will get + the super class' wrapper for calling inherited methods. +*/ +Class = function(className, superClass, classScope){ + if(arguments.length == 2){ + classScope = superClass; + if(typeof className != "string"){ + superClass = className; + className = "anonymous"; + }else{ + superClass = Object; + } + }else if(arguments.length == 1){ + classScope = className; + superClass = Object; + className = "anonymous"; + } + + //this is the constructor for the new objects created from the new class. + //if and only if it is NOT used for prototyping/subclassing the init method of the newly created object will be called. + var NewClass = function(calledBy){ + if(calledBy !== Class){ + return this.init.apply(this, arguments); + } + } + //This will create a new prototype object of the new class. + NewClass.createPrototype = function(){ + return new NewClass(Class); + } + //setting class properties for the new class. + NewClass.superClass = superClass; + NewClass.className=className; + NewClass.toString = function(){ + return "[class %s]".format(NewClass.className); + }; + if(superClass.createPrototype!=null){//see if the super class can create prototypes. (creating an object without calling init()) + NewClass.prototype = superClass.createPrototype(); + }else{//just create an object of the super class + NewClass.prototype = new superClass(); + } + //reset the constructor for new objects to the actual constructor. + NewClass.prototype.constructor = NewClass; + + if(superClass == Object){//all other objects already have a nice toString method. + NewClass.prototype.toString = function(){ + return "[object %s]".format(this.constructor.className); + }; + } + + if(NewClass.prototype.init==null){ + NewClass.prototype.init=function(){ + } + } + + + //create a supr function to be used to call methods of the super class + var supr = function(self){ + //set up super class functionality so a call to super(this) will return an object with all super class methods + //the methods can be called like super(this).foo and the this object will be bound to that method + var wrapper = {}; + var superProto = superClass.prototype; + for(var n in superProto){ + if(typeof superProto[n] == "function"){ + wrapper[n] = function(){ + var f = arguments.callee; + return superProto[f._name].apply(self, arguments); + } + wrapper[n]._name = n; + } + } + return wrapper; + } + + //execute the scope of the class + classScope(NewClass.prototype, supr); + + return NewClass; +} +Class.toString = function(){ + return "[object Class]"; +} +Class.createPrototype=function(){ + throw "Can't use Class as a super class."; +} + +/** + Creates a new module and registers it. + @param name The name of the module. + @param version The version of a module. + @param moduleScope A function which is executed for module creation. + As 1st parameter it will get the module variable. +*/ +Module = function(name, version, moduleScope){ + var mod = new Object(); + mod.version = version; + mod.name = name; + mod.toString=function(){ + return "[module '%s' version: %s]".format(mod.name, mod.version); + } + + /** + Base class for all module-Exceptions. + */ + mod.Exception=Class("Exception", function(publ){ + /** + Initializes a new Exception. + @param msg The error message for the user. + @param trace=null The error causing this Exception if available. + */ + publ.init=function(msg, trace){ + this.name = this.constructor.className; + this.message = msg; + this.trace = trace; + } + + publ.toString=function(){ + var s = "%s %s\n\n".format(this.name, this.module); + s += this.message; + return s; + } + /** + Returns the complete trace of the exception. + @return The error trace. + */ + publ.toTraceString=function(){ + var s = "%s %s:\n ".format(this.name, this.module ); + s+="%s\n\n".format(this.message); + if(this.trace){ + if(this.trace.toTraceString){ + s+= this.trace.toTraceString(); + }else{ + s+= this.trace; + } + } + return s; + } + ///The name of the Exception(className). + publ.name; + ///The error message. + publ.message; + ///The module the Exception belongs to. + publ.module = mod; + ///The error which caused the Exception or null. + publ.trace; + }) + + //execute the scope of the module + moduleScope(mod); + + //todo: set classNames for anonymous classes. + for(var n in mod){ + if(mod[n].className == "anonymous"){ + mod[n].className = n; + } + } + + if(name != "jsolait"){ + jsolait.registerModule(mod); + } + return mod; +} +Module.toString = function(){ + return "[object Module]"; +} +Module.createPrototype=function(){ + throw "Can't use Module as a super class."; +} + +//docstart +/** + The root module for jsolait. + It provides some global functionality for loading modules, + some String enhancements. +*/ +Module("jsolait", "0.1.0", function(mod){ + ///The global jsolait object. + jsolait=mod; + + ///base url for user modules. + mod.baseURL="."; + ///The URL where jsolait is installed. + mod.libURL ="./jsolait"; + ///Collection of all loaded modules.(module cache) + mod.modules = new Array(); + ///The URLs of there the modules, part of jsolait. + mod.moduleURLs = {}; +/* + mod.moduleURLs = {urllib:"%(libURL)s/lib/urllib.js", + xml:"%(libURL)s/lib/xml.js", + crypto:"%(libURL)s/lib/crypto.js", + codecs:"%(libURL)s/lib/codecs.js", + jsonrpc:"%(libURL)s/lib/jsonrpc.js", + lang:"%(libURL)s/lib/lang.js", + xmlrpc:"%(libURL)s/lib/xmlrpc.js"}; +*/ + + mod.init=function(){ + if(typeof(WScript) != 'undefined') { + initWS(); + } + +// //make jsolait work with WScript +// var ws = null; +// try{//see if WScript is available +// ws = WScript; +// }catch(e){ +// } +// if(ws != null){ +// initWS(); +// } + } + + ///initializes jsolait for using it with WScript + var initWS = function(){ + print=function(msg){ + WScript.echo(msg); + } + alert=function(msg){ + print(msg); + } + var args = WScript.arguments; + try{ + //get script to execute + var url = args(0); + url = url.replace(/\\/g, "/"); + url = url.split("/"); + url = url.slice(0, url.length-1); + //set base for user module loading + mod.baseURL = url.join("/"); + }catch(e){ + throw new mod.Exception("Missing script filename to be run.", e); + } + + //location of jsolait/init.js + url = WScript.ScriptFullName; + + if(args(0).replace("file://","").toLowerCase() == url.toLowerCase()){ + WScript.stderr.write("Can't run myself! exiting ... \n"); + return; + } + url = url.replace(/\\/g, "/"); + url = url.split("/"); + url = url.slice(0, url.length-1); + mod.libURL = "file://" + url.join("/"); + try{ + mod.loadScript(args(0)); + }catch(e){ + WScript.stdErr.write("%s(1,1) jsolait runtime error:\n%s\n".format(args(0).replace("file://",""), e.toTraceString())); + } + } + + + /** + Imports a module given its name(someModule.someSubModule). + A module's file location is determined by treating each module name as a directory. + Only the last one points to a file. + If the module's URL is not known to jsolait then it will be searched for in jsolait.baseURL which is "." by default. + @param name The name of the module to load. + @return The module object. + */ + mod.importModule = function(name){ + + if (mod.modules[name]){ //module already loaded + return mod.modules[name]; + }else{ + var src,modURL; + //check if jsolait already knows the url of the module(moduleURLs contains urls to modules) + if(mod.moduleURLs[name]){ + modURL = mod.moduleURLs[name].format(mod); + }else{ +/* + assume it's a user module and located at baseURL +*/ + modURL = "%s/%s.js".format(mod.baseURL, name.split(".").join("/")); + } + try{//to load module from location calculated above + src = getFile(modURL); + }catch(e){//module could not be found at the location. + throw new mod.ModuleImportFailed(name, modURL, e); + } + + try{//interpret the script + globalEval(src); + }catch(e){ + throw new mod.ModuleImportFailed(name, modURL, e); + } + //the module should have registered itself + return mod.modules[name]; + } + } + //make it global + importModule = mod.importModule; + + /** + Loads and interprets a script file. + @param url The url of the script to load. + */ + mod.loadScript=function(url){ + var src = getFile(url); + try{//to interpret the source + globalEval(src); + }catch(e){ + throw new mod.EvalFailed(url, e); + } + } + /** + Registers a new module. + Registered modules can be imported with importModule(...). + @param module The module to register. + */ + mod.registerModule = function(module){ + this.modules[module.name] = module; + } + + /** + Creates an HTTP request object for retreiving files. + @return HTTP request object. + */ + var getHTTP=function() { + var obj; + try{ //to get the mozilla httprequest object + obj = new XMLHttpRequest(); + }catch(e){ + try{ //to get MS HTTP request object + obj=new ActiveXObject("Msxml2.XMLHTTP.4.0"); + }catch(e){ + try{ //to get MS HTTP request object + obj=new ActiveXObject("Msxml2.XMLHTTP"); + }catch(e){ + try{// to get the old MS HTTP request object + obj = new ActiveXObject("microsoft.XMLHTTP"); + }catch(e){ + throw new mod.Exception("Unable to get an HTTP request object."); + } + } + } + } + return obj; + } + /** + Retrieves a file given its URL. + @param url The url to load. + @param headers=[] The headers to use. + @return The content of the file. + */ + var getFile=function(url, headers) { + //if callback is defined then the operation is done async + headers = (headers != null) ? headers : []; + //setup the request + try{ + var xmlhttp= getHTTP(); + xmlhttp.open("GET", url, false); + for(var i=0;i< headers.length;i++){ + xmlhttp.setRequestHeader(headers[i][0], headers[i][1]); + } + xmlhttp.send(""); + }catch(e){ + throw new mod.Exception("Unable to load URL: '%s'.".format(url), e); + } + if(xmlhttp.status == 200 || xmlhttp.status == 0){ + return xmlhttp.responseText; + }else{ + throw new mod.Exception("File not loaded: '%s'.".format(url)); + } + } + + Error.prototype.toTraceString = function(){ + if(this.message){ + return "%s\n".format(this.message); + } + if (this.description){ + return "%s\n".format(this.description); + } + return "unknown error\n"; + } + + + /** + Thrown when a module could not be found. + */ + mod.ModuleImportFailed=Class(mod.Exception, function(publ, supr){ + /** + Initializes a new ModuleImportFailed Exception. + @param name The name of the module. + @param url The url of the module. + @param trace The error cousing this Exception. + */ + publ.init=function(moduleName, url, trace){ + supr(this).init("Failed to import module: '%s' from URL:'%s'".format(moduleName, url), trace); + this.moduleName = moduleName; + this.url = url; + } + ///The name of the module that was not found. + publ.moduleName; + ///The url the module was expected to be found at. + publ.url; + }) + + /** + Thrown when a source could not be loaded due to an interpretation error. + */ + mod.EvalFailed=Class(mod.Exception, function(publ, supr){ + /** + Initializes a new EvalFailed exception. + @param url The url of the module. + @param trace The exception that was thrown while interpreting the module's source code. + */ + publ.init=function(url, trace){ + supr(this).init("File '%s' Eval of script failed.".format(url), trace); + this.url = url; + } + ///The url the module was expected to be found at. + publ.url; + }) + + /** + Displays an exception and it's trace. + This works better than alert(e) because traces are taken into account. + @param exception The exception to display. + */ + mod.reportException=function(exception){ + if(exception.toTraceString){ + var s= exception.toTraceString(); + }else{ + var s = exception.toString(); + } + var ws = null; + try{//see if WScript is available + ws = WScript; + }catch(e){ + } + if(ws != null){ + WScript.stderr.write(s); + }else{ + alert(s); + } + } + ///The global exception report method; + reportException = mod.reportException; +}) + +//stringmod +/** + String formatting module. + It allows python like string formatting ("some text %s" % "something"). + Also similar to sprintf from C. +*/ +Module("stringformat", "0.1.0", function(mod){ + /** + Creates a format specifier object. + */ + var FormatSpecifier=function(s){ + var s = s.match(/%(\(\w+\)){0,1}([ 0-]){0,1}(\+){0,1}(\d+){0,1}(\.\d+){0,1}(.)/); + if(s[1]){ + this.key=s[1].slice(1,-1); + }else{ + this.key = null; + } + this.paddingFlag = s[2]; + if(this.paddingFlag==""){ + this.paddingFlag =" " + } + this.signed=(s[3] == "+"); + this.minLength = parseInt(s[4]); + if(isNaN(this.minLength)){ + this.minLength=0; + } + if(s[5]){ + this.percision = parseInt(s[5].slice(1,s[5].length)); + }else{ + this.percision=-1; + } + this.type = s[6]; + } + + /** + Formats a string replacing formatting specifiers with values provided as arguments + which are formatted according to the specifier. + This is an implementation of python's % operator for strings and is similar to sprintf from C. + Usage: + resultString = formatString.format(value1, v2, ...); + + Each formatString can contain any number of formatting specifiers which are + replaced with the formated values. + + specifier([...]-items are optional): + "%(key)[flag][sign][min][percision]typeOfValue" + + (key) If specified the 1st argument is treated as an object/associative array and the formating values + are retrieved from that object using the key. + + flag: + 0 Use 0s for padding. + - Left justify result, padding it with spaces. + Use spaces for padding. + sign: + + Numeric values will contain a +|- infront of the number. + min: + l The string will be padded with the padding character until it has a minimum length of l. + percision: + .x Where x is the percision for floating point numbers and the lenght for 0 padding for integers. + typeOfValue: + d Signed integer decimal. + i Signed integer decimal. + b Unsigned binary. //This does not exist in python! + o Unsigned octal. + u Unsigned decimal. + x Unsigned hexidecimal (lowercase). + X Unsigned hexidecimal (uppercase). + e Floating point exponential format (lowercase). + E Floating point exponential format (uppercase). + f Floating point decimal format. + F Floating point decimal format. + c Single character (accepts byte or single character string). + s String (converts any object using object.toString()). + + Examples: + "%02d".format(8) == "08" + "%05.2f".format(1.234) == "01.23" + "123 in binary is: %08b".format(123) == "123 in binary is: 01111011" + + @param * Each parameter is treated as a formating value. + @return The formated String. + */ + String.prototype.format=function(){ + var sf = this.match(/(%(\(\w+\)){0,1}[ 0-]{0,1}(\+){0,1}(\d+){0,1}(\.\d+){0,1}[dibouxXeEfFgGcrs%])|([^%]+)/g); + if(sf){ + if(sf.join("") != this){ + throw new mod.Exception("Unsupported formating string."); + } + }else{ + throw new mod.Exception("Unsupported formating string."); + } + var rslt =""; + var s; + var obj; + var cnt=0; + var frmt; + var sign=""; + + for(var i=0;i=arguments.length){ + throw new mod.Exception("Not enough arguments for format string"); + }else{ + obj=arguments[cnt]; + cnt++; + } + } + + if(frmt.type == "s"){//String + if (obj == null){ + obj = "null"; + } + s=obj.toString().pad(frmt.paddingFlag, frmt.minLength); + + }else if(frmt.type == "c"){//Character + if(frmt.paddingFlag == "0"){ + frmt.paddingFlag=" ";//padding only spaces + } + if(typeof obj == "number"){//get the character code + s = String.fromCharCode(obj).pad(frmt.paddingFlag , frmt.minLength) ; + }else if(typeof obj == "string"){ + if(obj.length == 1){ +/* +make sure it's a single character +*/ + s=obj.pad(frmt.paddingFlag, frmt.minLength); + }else{ + throw new mod.Exception("Character of length 1 required."); + } + }else{ + throw new mod.Exception("Character or Byte required."); + } + }else if(typeof obj == "number"){ + //get sign of the number + if(obj < 0){ + obj = -obj; + sign = "-"; //negative signs are always needed + }else if(frmt.signed){ + sign = "+"; // if sign is always wanted add it + }else{ + sign = ""; + } + //do percision padding and number conversions + switch(frmt.type){ + case "f": //floats + case "F": + if(frmt.percision > -1){ + s = obj.toFixed(frmt.percision).toString(); + }else{ + s = obj.toString(); + } + break; + case "E"://exponential + case "e": + if(frmt.percision > -1){ + s = obj.toExponential(frmt.percision); + }else{ + s = obj.toExponential(); + } + s = s.replace("e", frmt.type); + break; + case "b"://binary + s = obj.toString(2); + s = s.pad("0", frmt.percision); + break; + case "o"://octal + s = obj.toString(8); + s = s.pad("0", frmt.percision); + break; + case "x"://hexadecimal + s = obj.toString(16).toLowerCase(); + s = s.pad("0", frmt.percision); + break; + case "X"://hexadecimal + s = obj.toString(16).toUpperCase(); + s = s.pad("0", frmt.percision); + break; + default://integers + s = parseInt(obj).toString(); + s = s.pad("0", frmt.percision); + break; + } + if(frmt.paddingFlag == "0"){//do 0-padding + //make sure that the length of the possible sign is not ignored + s=s.pad("0", frmt.minLength - sign.length); + } + s=sign + s;//add sign + s=s.pad(frmt.paddingFlag, frmt.minLength);//do padding and justifiing + }else{ + throw new mod.Exception("Number required."); + } + } + rslt += s; + } + return rslt; + } + + /** + Padds a String with a character to have a minimum length. + + @param flag "-": to padd with " " and left justify the string. + Other: the character to use for padding. + @param len The minimum length of the resulting string. + */ + String.prototype.pad = function(flag, len){ + var s = ""; + if(flag == "-"){ + var c = " "; + }else{ + var c = flag; + } + for(var i=0;i> 16, (nBits & 0xff00) >> 8, nBits & 0xff); + } + //make sure padding chars are left out. + sDecoded[sDecoded.length-1] = sDecoded[sDecoded.length-1].substring(0, 3 - ((this.charCodeAt(i - 2) == 61) ? 2 : (this.charCodeAt(i - 1) == 61 ? 1 : 0))); + return sDecoded.join(""); + } + }else{ + throw new mod.Exception("String length must be divisible by 4."); + } + } + + /** + Encodes a string using Base64. + */ + String.prototype.encode_base64=function(){ + if(typeof(btoa) != "undefined"){//try using mozillas builtin codec + return btoa(this); + }else{ + var base64 = ['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z', + 'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z', + '0','1','2','3','4','5','6','7','8','9','+','/']; + var sbin; + var pad=0; + var s="" + this; + if((s.length % 3) == 1){ + s+=String.fromCharCode(0); + s+=String.fromCharCode(0); + pad=2; + }else if((s.length % 3) == 2){ + s+=String.fromCharCode(0); + pad=1; + } + //create a result buffer, this is much faster than having strings concatinated. + var rslt=new Array(s.length / 3); + var ri=0; + for(var i=0;i> 18) & 0x3f] + base64[(sbin >> 12) & 0x3f] + base64[(sbin >>6) & 0x3f] + base64[sbin & 0x3f]); + ri++; + } + if(pad>0){ + rslt[rslt.length-1] = rslt[rslt.length-1].substr(0, 4-pad) + ((pad==2) ? "==" : (pad==1) ? "=" : ""); + } + return rslt.join(""); + } + } + + /** + Decodes a URI using decodeURI. + */ + String.prototype.decode_uri=function(){ + return decodeURI(this); + } + + /** + Encodes a URI using encodeURI. + */ + String.prototype.encode_uri=function(){ + return encodeURI(this); + } +}) diff --git a/jssource/src_files/include/jsolait/lib/crypto.js b/jssource/src_files/include/jsolait/lib/crypto.js new file mode 100644 index 00000000..db0a7860 --- /dev/null +++ b/jssource/src_files/include/jsolait/lib/crypto.js @@ -0,0 +1,172 @@ +/* + +Modification information for LGPL compliance + +r56990 - 2010-06-16 13:05:36 -0700 (Wed, 16 Jun 2010) - kjing - snapshot "Mango" svn branch to a new one for GitHub sync + +r56989 - 2010-06-16 13:01:33 -0700 (Wed, 16 Jun 2010) - kjing - defunt "Mango" svn dev branch before github cutover + +r55980 - 2010-04-19 13:31:28 -0700 (Mon, 19 Apr 2010) - kjing - create Mango (6.1) based on windex + +r51719 - 2009-10-22 10:18:00 -0700 (Thu, 22 Oct 2009) - mitani - Converted to Build 3 tags and updated the build system + +r51634 - 2009-10-19 13:32:22 -0700 (Mon, 19 Oct 2009) - mitani - Windex is the branch for Sugar Sales 1.0 development + +r50375 - 2009-08-24 18:07:43 -0700 (Mon, 24 Aug 2009) - dwong - branch kobe2 from tokyo r50372 + +r42807 - 2008-12-29 11:16:59 -0800 (Mon, 29 Dec 2008) - dwong - Branch from trunk/sugarcrm r42806 to branches/tokyo/sugarcrm + +r4085 - 2005-04-13 17:30:42 -0700 (Wed, 13 Apr 2005) - robert - adding meeting scheduler and accept/decline + + +*/ + +/* + Copyright (c) 2003 Jan-Klaas Kollhof + + This file is part of the JavaScript o lait library(jsolait). + + jsolait is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + This software 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this software; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/** + Cryptography module. + Provides String encryption/decryption and hashing. +*/ +Module("crypto", "0.1.2", function(mod){ + /** + Returns all all available encrypters. + @return An array of encrypters names. + */ + mod.listEncrypters=function(){ + var c=[]; + for(var attr in String.prototype){ + if(attr.slice(0, 8) == "encrypt_"){ + c.push(attr.slice(8)); + } + } + return c; + } + /** + Returns all all available decrypters. + @return An array of decrypters names. + */ + mod.listDecrypters=function(){ + var c=[]; + for(var attr in String.prototype){ + if(attr.slice(0, 8) == "decrypt_"){ + c.push(attr.slice(8)); + } + } + return c; + } + + /** + Encrypts a string. + Parameters but the crypdec parameter are forwardet to the crypdec. + @param codec The codec to use. + */ + String.prototype.encrypt=function(crydec){ + var n = "encrypt_" + crydec; + if(String.prototype[n]){ + var args=[]; + for(var i=1;i": case "!": + case "|": case "&": + switch(s2){ + case "==": case "!=": case "<>": case "<=": case ">=":case "||": case "&&": + rslt = new mod.Token(mod.tokens.OP, s2, this._pos); + break; + default: + rslt = new mod.Token(mod.tokens.OP, s1, this._pos); + } + break; + case "/": + if(s2 == "//" || s3 =="///"){ + s1 = extractSLComment(this._working); + rslt = new mod.Token(s1.charAt(2) != "/" ? mod.tokens.COMMENT:mod.tokens.DOCCOMMENT, s1, this._pos); + }else if(s2 == "/*" || s3 =="/**"){ + try{ + s1 = extractMLComment(this._working); + rslt = new mod.Token(s3 !="/**" ? mod.tokens.COMMENT: mod.tokens.DOCCOMMENT, s1, this._pos); + }catch(e){ + rslt= new mod.Token(mod.tokens.ERR, s3 != "/**" ? s2 : s3, this._pos, e); + } + }else{ + try{ + s1 = extractRegExp(this._working); + rslt = new mod.Token(mod.tokens.REGEXP, s1, this._pos); + }catch(e){ + rslt = new mod.Token(mod.tokens.OP, s1, this._pos, e); + } + } + break; + case " ": + var i = 0; + var s=""; + while(this._working.charAt(i) == " "){ + s+=" "; + i++; + } + rslt = new mod.Token(mod.tokens.WSP, s, this._pos); + break; + default: + s1=this._working.match(/\d+\.\d+|\d+|\w+/)[0]; + if(/^\d|\d\.\d/.test(s1)){//number + rslt = new mod.Token(mod.tokens.NUM, s1, this._pos); + }else{//name + rslt =new mod.Token(mod.tokens.NAME, s1, this._pos); + } + } + + this._working=this._working.slice(rslt.value.length); + this._pos += rslt.value.length; + return rslt; + } + + var searchQoute = function(s, q){ + if(q=="'"){ + return s.search(/[\\']/); + }else{ + return s.search(/[\\"]/); + } + } + + var extractQString=function(s){ + if(s.charAt(0) == "'"){ + var q="'"; + }else{ + var q='"'; + } + s=s.slice(1); + var rs=""; + var p= searchQoute(s, q); + while(p >= 0){ + if(p >=0){ + if(s.charAt(p) == q){ + rs += s.slice(0, p+1); + s = s.slice(p+1); + return q + rs; + }else{ + rs+=s.slice(0, p+2); + s = s.slice(p+2); + } + } + p = searchQoute(s, q); + } + throw new mod.Exception("End of String expected."); + } + + var extractSLComment=function(s){ + var p = s.search(/\n/); + if(p>=0){ + return s.slice(0,p+1); + }else{ + return s; + } + } + + var extractMLComment=function(s){ + var p = s.search(/\*\//); + if(p>=0){ + return s.slice(0,p+2); + }else{ + throw new mod.Exception("End of comment expected."); + } + } + + var extractRegExp=function(s){ + var p=0; + for(var i=0;i\n"; + } + break; + case PROCESSING_INSTRUCTION_NODE: + s+=""; + break; + case TEXT_NODE: + s+=node.nodeValue; + break; + case CDATA_SECTION_NODE: + s+="<" +"![CDATA[" + node.nodeValue + "]" + "]>"; + break; + case COMMENT_NODE: + s+=""; + break; + case ENTITY_REFERENCE_NODE: + case DOCUMENT_FRAGMENT_NODE: + case DOCUMENT_TYPE_NODE: + case NOTATION_NODE: + case ENTITY_NODE: + throw new mod.Exception("Nodetype(%s) not supported.".format(node.nodeType)); + break; + } + return s; + } +}) diff --git a/jssource/src_files/include/jsolait/lib/xmlrpc.js b/jssource/src_files/include/jsolait/lib/xmlrpc.js new file mode 100644 index 00000000..d335f246 --- /dev/null +++ b/jssource/src_files/include/jsolait/lib/xmlrpc.js @@ -0,0 +1,854 @@ +/* + +Modification information for LGPL compliance + +r56990 - 2010-06-16 13:05:36 -0700 (Wed, 16 Jun 2010) - kjing - snapshot "Mango" svn branch to a new one for GitHub sync + +r56989 - 2010-06-16 13:01:33 -0700 (Wed, 16 Jun 2010) - kjing - defunt "Mango" svn dev branch before github cutover + +r55980 - 2010-04-19 13:31:28 -0700 (Mon, 19 Apr 2010) - kjing - create Mango (6.1) based on windex + +r51719 - 2009-10-22 10:18:00 -0700 (Thu, 22 Oct 2009) - mitani - Converted to Build 3 tags and updated the build system + +r51634 - 2009-10-19 13:32:22 -0700 (Mon, 19 Oct 2009) - mitani - Windex is the branch for Sugar Sales 1.0 development + +r50375 - 2009-08-24 18:07:43 -0700 (Mon, 24 Aug 2009) - dwong - branch kobe2 from tokyo r50372 + +r42807 - 2008-12-29 11:16:59 -0800 (Mon, 29 Dec 2008) - dwong - Branch from trunk/sugarcrm r42806 to branches/tokyo/sugarcrm + +r4085 - 2005-04-13 17:30:42 -0700 (Wed, 13 Apr 2005) - robert - adding meeting scheduler and accept/decline + + +*/ + +/* + Copyright (c) 2003-2004 Jan-Klaas Kollhof + + This file is part of the JavaScript o lait library(jsolait). + + jsolait is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + This software 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this software; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +/** + Provides an XML-RPC imlementation. + It is similar to python's xmlrpclib module. +*/ +Module("xmlrpc","1.3.3", function(mod){ + var xmlext = importModule("xml"); + var urllib = importModule("urllib"); + /** + Thrown if a server did not respond with response status 200 (OK). + */ + mod.InvalidServerResponse = Class("InvalidServerResponse", mod.Exception, function(publ, supr){ + /** + Initializes the Exception. + @param status The status returned by the server. + */ + publ.init= function(status){ + supr(this).init("The server did not respond with a status 200 (OK) but with: " + status); + this.status = status; + } + ///The status returned by the server. + publ.status; + }) + + /** + Thrown if an XML-RPC response is not well formed. + */ + mod.MalformedXmlRpc = Class("MalformedXmlRpc", mod.Exception, function(publ, supr){ + /** + Initializes the Exception. + @param msg The error message of the user. + @param xml The xml document's source. + @param trace=null The error causing this Exception + */ + publ.init= function(msg, xml, trace){ + supr(this).init(msg,trace); + this.xml = xml; + } + ///The xml source which was mal formed. + publ.xml; + }) + /** + Thrown if the RPC response is a Fault. + */ + mod.Fault = Class("Fault", mod.Exception, function(publ, supr){ + /** + Initializes the Exception. + @param faultCode The fault code returned by the rpc call. + @param faultString The fault string returned by the rpc call. + */ + publ.init= function(faultCode, faultString){ + supr(this).init("XML-RPC Fault: " + faultCode + "\n\n" + faultString); + this.faultCode = faultCode; + this.faultString = faultString; + } + ///The fault code returned from the rpc call. + publ.faultCode; + ///The fault string returned from the rpc call. + publ.faultString; + }) + + /** + Marshalls an object to XML-RPC.(Converts an object into XML-RPC conforming xml.) + It just calls the toXmlRpc function of the objcect. + So, to customize serialization of objects one just needs to specify/override the toXmlRpc method + which should return an xml string conforming with XML-RPC spec. + @param obj The object to marshall + @return An xml representation of the object. + */ + mod.marshall = function(obj){ + if(obj.toXmlRpc){ + return obj.toXmlRpc(); + }else{ + var s = ""; + for(var attr in obj){ + if(typeof obj[attr] != "function"){ + s += "" + attr + "" + mod.marshall(obj[attr]) + ""; + } + } + s += ""; + return s; + } + } + + /** + Unmarshalls an XML document to a JavaScript object. (Converts xml to JavaScript object.) + It parses the xml source and creates a JavaScript object. + @param xml The xml document source to unmarshall. + @return The JavaScript object created from the XML. + */ + mod.unmarshall = function(xml){ + try {//try to parse xml ... this will throw an Exception if failed + var doc = xmlext.parseXML(xml); + }catch(e){ + throw new mod.MalformedXmlRpc("The server's response could not be parsed.", xml, e); + } + var rslt = mod.unmarshallDoc(doc, xml); + doc=null; + return rslt; + } + + /** + Unmarshalls an XML document to a JavaScript object like unmarshall but expects a DOM document as parameter. + It parses the xml source and creates a JavaScript object. + @param doc The xml document(DOM compatible) to unmarshall. + @return The JavaScript object created from the XML. + */ + mod.unmarshallDoc = function(doc, xml){ + try{ + var node = doc.documentElement; + if(node==null){//just in case parse xml didn't throw an Exception but returned nothing usefull. + throw new mod.MalformedXmlRpc("No documentElement found.", xml); + } + switch(node.tagName){ + case "methodResponse": + return parseMethodResponse(node); + case "methodCall": + return parseMethodCall(node); + default://nothing usefull returned by parseXML. + throw new mod.MalformedXmlRpc("'methodCall' or 'methodResponse' element expected.\nFound: '" + node.tagName + "'", xml); + } + }catch(e){ + if(e instanceof mod.Fault){//just rethrow the fault. + throw e; + }else { + throw new mod.MalformedXmlRpc("Unmarshalling of XML failed.", xml, e); + } + } + } + + /** + Parses a methodeResponse element. + @param node The methodResponse element. + @return The return value of the XML-RPC. + */ + var parseMethodResponse=function(node){ + try{ + for(var i=0;i'; + if (args.length>0){ + data += ""; + for(var i=0;i'; + } + data += ''; + } + data += ''; + return data; + } + /** + Initializes the XML-RPC method. + @param url The URL of the service providing the method. + @param methodName The name of the method to invoke. + @param user=null The user name to use for HTTP authentication. + @param pass=null The password to use for HTTP authentication. + */ + publ.init = function(url, methodName, user, pass){ + + //this is pretty much a hack. + //we create a function which mimics this class and return it instead of really instanciating an object. + var fn=function(){ + //sync or async call + if(typeof arguments[arguments.length-1] != "function"){ + var data=getXML(fn.methodName,arguments); + var resp = postData(fn.url, fn.user, fn.password, data); + + return handleResponse(resp); + }else{ + var args=new Array(); + for(var i=0;i 0){ + var tryIntrospection=false; + }else{ + var tryIntrospection=true; + } + }else{ + pass=user; + user=methodNames; + methodNames=[]; + var tryIntrospection=true; + } + this._url = url; + this._user = user; + this._password = pass; + this._addMethodNames(methodNames); + if(tryIntrospection){ + try{//it's ok if it fails. + this._introspect(); + }catch(e){ + } + } + } + + /** + Adds new XMLRPCMethods to the proxy server which can then be invoked. + @param methodNames Array of names of methods that can be called on the server. + */ + publ._addMethodNames = function(methodNames){ + for(var i=0;i" + this.replace(/&/g, "&").replace(/"; + } + /** + XML-RPC representation of a number. + @return A string containing the Number's representation in XML. + */ + Number.prototype.toXmlRpc = function(){ + if(this == parseInt(this)){ + return "" + this + ""; + }else if(this == parseFloat(this)){ + return "" + this + ""; + }else{ + return false.toXmlRpc(); + } + } + /** + XML-RPC representation of a boolean. + @return A string containing the Boolean's representation in XML. + */ + Boolean.prototype.toXmlRpc = function(){ + if(this == true) { + return "1"; + }else{ + return "0"; + } + } + /** + XML-RPC representation of a date(iso 8601). + @return A string containing the Date's representation in XML. + */ + Date.prototype.toXmlRpc = function(){ + var padd=function(s, p){ + s=p+s + return s.substring(s.length - p.length) + } + var y = padd(this.getUTCFullYear(), "0000"); + var m = padd(this.getUTCMonth() + 1, "00"); + var d = padd(this.getUTCDate(), "00"); + var h = padd(this.getUTCHours(), "00"); + var min = padd(this.getUTCMinutes(), "00"); + var s = padd(this.getUTCSeconds(), "00"); + + var isodate = y + m + d + "T" + h + ":" + min + ":" + s + + return "" + isodate + ""; + } + /** + XML-RPC representation of an array. + Each entry in the array is a value in the XML-RPC. + @return A string containing the Array's representation in XML. + */ + Array.prototype.toXmlRpc = function(){ + var retstr = ""; + for(var i=0;i"; + } + return retstr + ""; + } + + + mod.test = function(){ + print("creating ServiceProxy object using introspection for method construction...\n"); + var s = new mod.ServiceProxy("http://localhost/testx.py"); + print("%s created\n".format(s)); + print("creating and marshalling test data:\n"); + var o = [1.234, 5, {a:"Hello & < ", b:new Date()}]; + print(mod.marshall(o)); + print("\ncalling echo() on remote service...\n"); + var r = s.echo(o); + print("service returned data(marshalled again):\n") + print(mod.marshall(r)); + } +}) + + + diff --git a/jssource/src_files/include/jsolait/missingmixin.js b/jssource/src_files/include/jsolait/missingmixin.js new file mode 100644 index 00000000..7188ea72 --- /dev/null +++ b/jssource/src_files/include/jsolait/missingmixin.js @@ -0,0 +1,174 @@ +/* + +Modification information for LGPL compliance + +r56990 - 2010-06-16 13:05:36 -0700 (Wed, 16 Jun 2010) - kjing - snapshot "Mango" svn branch to a new one for GitHub sync + +r56989 - 2010-06-16 13:01:33 -0700 (Wed, 16 Jun 2010) - kjing - defunt "Mango" svn dev branch before github cutover + +r55980 - 2010-04-19 13:31:28 -0700 (Mon, 19 Apr 2010) - kjing - create Mango (6.1) based on windex + +r51719 - 2009-10-22 10:18:00 -0700 (Thu, 22 Oct 2009) - mitani - Converted to Build 3 tags and updated the build system + +r51634 - 2009-10-19 13:32:22 -0700 (Mon, 19 Oct 2009) - mitani - Windex is the branch for Sugar Sales 1.0 development + +r50375 - 2009-08-24 18:07:43 -0700 (Mon, 24 Aug 2009) - dwong - branch kobe2 from tokyo r50372 + +r42807 - 2008-12-29 11:16:59 -0800 (Mon, 29 Dec 2008) - dwong - Branch from trunk/sugarcrm r42806 to branches/tokyo/sugarcrm + +r4085 - 2005-04-13 17:30:42 -0700 (Wed, 13 Apr 2005) - robert - adding meeting scheduler and accept/decline + + +*/ + +/* + Copyright (c) 2003 Jan-Klaas Kollhof + + This file is part of the JavaScript o lait library(jsolait). + + jsolait is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + This software 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this software; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +if(Function.prototype.apply == null){ + Function.prototype.apply = function(thisObj, args){ + var a =[]; + for(var i=0;i= 0) ? n+Math.pow(10, -(d+1)) : n-Math.pow(10, -(d+1)); + n += ''; + return d == 0 ? n.substring(0, n.indexOf('.')) : n.substring(0, n.indexOf('.') + d + 1); + } +} + +if(Number.prototype.toExponential == null){ + Number.prototype.toExponential = function(d){ + var n = this; + var e = 0; + if (n != 0){ + e = Math.floor(Math.log(Math.abs(n)) / Math.LN10); + } + n /= Math.pow(10, e); + if (isFinite(d)){ + if (Math.abs(n) + 5*Math.pow(10, -(d+1)) >= 10.0){ + n /= 10; + e += 1; + } + n = n.toFixed(d); + } + n += "e"; + if (e >= 0){ + n += "+"; + } + n += e; + return n; + } +} + diff --git a/jssource/src_files/include/ytree/TreeView/HTMLNode.js b/jssource/src_files/include/ytree/TreeView/HTMLNode.js new file mode 100644 index 00000000..05b09349 --- /dev/null +++ b/jssource/src_files/include/ytree/TreeView/HTMLNode.js @@ -0,0 +1,114 @@ +/* Copyright (c) 2006 Yahoo! Inc. All rights reserved. */ + +/** + * This implementation takes either a string or object for the + * oData argument. If is it a string, we will use it for the display + * of this node (and it can contain any html code). If the parameter + * is an object, we look for a parameter called "html" that will be + * used for this node's display. + * + * @extends YAHOO.widget.Node + * @constructor + * @param oData {object} a string or object containing the data that will + * be used to render this node + * @param oParent {YAHOO.widget.Node} this node's parent node + * @param expanded {boolean} the initial expanded/collapsed state + * @param hasIcon {boolean} specifies whether or not leaf nodes should + * have an icon + */ +YAHOO.widget.HTMLNode = function(oData, oParent, expanded, hasIcon) { + if (oParent) { + this.init(oData, oParent, expanded); + this.initContent(oData, hasIcon); + } +}; + +YAHOO.widget.HTMLNode.prototype = new YAHOO.widget.Node(); + +/** + * The CSS class for the label href. Defaults to ygtvlabel, but can be + * overridden to provide a custom presentation for a specific node. + * + * @type string + */ +YAHOO.widget.HTMLNode.prototype.contentStyle = "ygtvhtml"; + +/** + * The generated id that will contain the data passed in by the implementer. + * + * @type string + */ +YAHOO.widget.HTMLNode.prototype.contentElId = null; + +/** + * The HTML content to use for this node's display + * + * @type string + */ +YAHOO.widget.HTMLNode.prototype.content = null; + +/** + * Sets up the node label + * + * @param {object} An html string or object containing an html property + * @param {boolean} hasIcon determines if the node will be rendered with an + * icon or not + */ +YAHOO.widget.HTMLNode.prototype.initContent = function(oData, hasIcon) { + if (typeof oData == "string") { + oData = { html: oData }; + } + + this.html = oData.html; + this.contentElId = "ygtvcontentel" + this.index; + this.hasIcon = hasIcon; +}; + +/** + * Returns the outer html element for this node's content + * + * @return {HTMLElement} the element + */ +YAHOO.widget.HTMLNode.prototype.getContentEl = function() { + return document.getElementById(this.contentElId); +}; + +// overrides YAHOO.widget.Node +YAHOO.widget.HTMLNode.prototype.getNodeHtml = function() { + var sb = new Array(); + + sb[sb.length] = ''; + sb[sb.length] = ''; + + for (i=0;i '; + } + + if (this.hasIcon) { + sb[sb.length] = ' '; + if (this.hasChildren(true)) { + sb[sb.length] = ' onmouseover="this.className='; + sb[sb.length] = 'YAHOO.widget.TreeView.getNode(\''; + sb[sb.length] = this.tree.id + '\',' + this.index + ').getHoverStyle()"'; + sb[sb.length] = ' onmouseout="this.className='; + sb[sb.length] = 'YAHOO.widget.TreeView.getNode(\''; + sb[sb.length] = this.tree.id + '\',' + this.index + ').getStyle()"'; + } + sb[sb.length] = ''; + } + + sb[sb.length] = ''; + } + + var getNode = 'YAHOO.widget.TreeView.getNode(\'' + + this.tree.id + '\',' + this.index + ')'; + + sb[sb.length] = ' '; + sb[sb.length] = ''; + sb[sb.length] = '
    '; + sb[sb.length] = ' '; + sb[sb.length] = ' '; + } + + var f = document.createElement("div"); + var s = f.style; + s.position = "absolute"; + s.top = "-1000px"; + s.left = "-1000px"; + f.innerHTML = sb.join(""); + + document.body.appendChild(f); + + YAHOO.widget.TreeView.removeHandler(window, + "load", YAHOO.widget.TreeView.preload); + +}; + +YAHOO.widget.TreeView.addHandler(window, + "load", YAHOO.widget.TreeView.preload); + +/** + * The base class for all tree nodes. The node's presentation and behavior in + * response to mouse events is handled in Node subclasses. + * @namespace YAHOO.widget + * @class Node + * @param oData {object} a string or object containing the data that will + * be used to render this node + * @param oParent {Node} this node's parent node + * @param expanded {boolean} the initial expanded/collapsed state + * @constructor + */ +YAHOO.widget.Node = function(oData, oParent, expanded) { + if (oData) { this.init(oData, oParent, expanded); } +}; + +YAHOO.widget.Node.prototype = { + + /** + * The index for this instance obtained from global counter in YAHOO.widget.TreeView. + * @property index + * @type int + */ + index: 0, + + /** + * This node's child node collection. + * @property children + * @type Node[] + */ + children: null, + + /** + * Tree instance this node is part of + * @property tree + * @type TreeView + */ + tree: null, + + /** + * The data linked to this node. This can be any object or primitive + * value, and the data can be used in getNodeHtml(). + * @property data + * @type object + */ + data: null, + + /** + * Parent node + * @property parent + * @type Node + */ + parent: null, + + /** + * The depth of this node. We start at -1 for the root node. + * @property depth + * @type int + */ + depth: -1, + + /** + * The href for the node's label. If one is not specified, the href will + * be set so that it toggles the node. + * @property href + * @type string + */ + href: null, + + /** + * The label href target, defaults to current window + * @property target + * @type string + */ + target: "_self", + + /** + * The node's expanded/collapsed state + * @property expanded + * @type boolean + */ + expanded: false, + + /** + * Can multiple children be expanded at once? + * @property multiExpand + * @type boolean + */ + multiExpand: true, + + /** + * Should we render children for a collapsed node? It is possible that the + * implementer will want to render the hidden data... @todo verify that we + * need this, and implement it if we do. + * @property renderHidden + * @type boolean + */ + renderHidden: false, + + /** + * This flag is set to true when the html is generated for this node's + * children, and set to false when new children are added. + * @property childrenRendered + * @type boolean + */ + childrenRendered: false, + + /** + * Dynamically loaded nodes only fetch the data the first time they are + * expanded. This flag is set to true once the data has been fetched. + * @property dynamicLoadComplete + * @type boolean + */ + dynamicLoadComplete: false, + + /** + * This node's previous sibling + * @property previousSibling + * @type Node + */ + previousSibling: null, + + /** + * This node's next sibling + * @property nextSibling + * @type Node + */ + nextSibling: null, + + /** + * We can set the node up to call an external method to get the child + * data dynamically. + * @property _dynLoad + * @type boolean + * @private + */ + _dynLoad: false, + + /** + * Function to execute when we need to get this node's child data. + * @property dataLoader + * @type function + */ + dataLoader: null, + + /** + * This is true for dynamically loading nodes while waiting for the + * callback to return. + * @property isLoading + * @type boolean + */ + isLoading: false, + + /** + * The toggle/branch icon will not show if this is set to false. This + * could be useful if the implementer wants to have the child contain + * extra info about the parent, rather than an actual node. + * @property hasIcon + * @type boolean + */ + hasIcon: true, + + /** + * Used to configure what happens when a dynamic load node is expanded + * and we discover that it does not have children. By default, it is + * treated as if it still could have children (plus/minus icon). Set + * iconMode to have it display like a leaf node instead. + * @property iconMode + * @type int + */ + iconMode: 0, + + /** + * The node type + * @property _type + * @private + */ + _type: "Node", + + /* + spacerPath: "http://us.i1.yimg.com/us.yimg.com/i/space.gif", + expandedText: "Expanded", + collapsedText: "Collapsed", + loadingText: "Loading", + */ + + /** + * Initializes this node, gets some of the properties from the parent + * @method init + * @param oData {object} a string or object containing the data that will + * be used to render this node + * @param oParent {Node} this node's parent node + * @param expanded {boolean} the initial expanded/collapsed state + */ + init: function(oData, oParent, expanded) { + + this.data = oData; + this.children = []; + this.index = YAHOO.widget.TreeView.nodeCount; + ++YAHOO.widget.TreeView.nodeCount; + this.expanded = expanded; + + /** + * The parentChange event is fired when a parent element is applied + * to the node. This is useful if you need to apply tree-level + * properties to a tree that need to happen if a node is moved from + * one tre to another. + * + * @event parentChange + * @type CustomEvent + */ + this.createEvent("parentChange", this); + + // oParent should never be null except when we create the root node. + if (oParent) { + oParent.appendChild(this); + } + }, + + /** + * Certain properties for the node cannot be set until the parent + * is known. This is called after the node is inserted into a tree. + * the parent is also applied to this node's children in order to + * make it possible to move a branch from one tree to another. + * @method applyParent + * @param {Node} parentNode this node's parent node + * @return {boolean} true if the application was successful + */ + applyParent: function(parentNode) { + if (!parentNode) { + return false; + } + + this.tree = parentNode.tree; + this.parent = parentNode; + this.depth = parentNode.depth + 1; + + if (!this.href) { + this.href = "javascript:" + this.getToggleLink(); + } + + if (! this.multiExpand) { + this.multiExpand = parentNode.multiExpand; + } + + this.tree.regNode(this); + parentNode.childrenRendered = false; + + // cascade update existing children + for (var i=0, len=this.children.length;i 0 || + (checkForLazyLoad && this.isDynamic() && !this.dynamicLoadComplete) ); + }, + + /** + * Expands if node is collapsed, collapses otherwise. + * @method toggle + */ + toggle: function() { + if (!this.tree.locked && ( this.hasChildren(true) || this.isDynamic()) ) { + if (this.expanded) { this.collapse(); } else { this.expand(); } + } + }, + + /** + * Returns the markup for this node and its children. + * @method getHtml + * @return {string} the markup for this node and its expanded children. + */ + getHtml: function() { + + this.childrenRendered = false; + + var sb = []; + sb[sb.length] = '
    '; + sb[sb.length] = this.getNodeHtml(); + sb[sb.length] = this.getChildrenHtml(); + sb[sb.length] = '
    '; + return sb.join(""); + }, + + /** + * Called when first rendering the tree. We always build the div that will + * contain this nodes children, but we don't render the children themselves + * unless this node is expanded. + * @method getChildrenHtml + * @return {string} the children container div html and any expanded children + * @private + */ + getChildrenHtml: function() { + + var sb = []; + sb[sb.length] = '
    = this.depth || depth < 0) { + return null; + } + + var p = this.parent; + + while (p.depth > depth) { + p = p.parent; + } + + return p; + }, + + /** + * Returns the css class for the spacer at the specified depth for + * this node. If this node's ancestor at the specified depth + * has a next sibling the presentation is different than if it + * does not have a next sibling + * @method getDepthStyle + * @param {int} depth the depth of the ancestor. + * @return {string} the css class for the spacer + */ + getDepthStyle: function(depth) { + return (this.getAncestor(depth).nextSibling) ? + "ygtvdepthcell" : "ygtvblankdepthcell"; + }, + + /** + * Get the markup for the node. This is designed to be overrided so that we can + * support different types of nodes. + * @method getNodeHtml + * @return {string} The HTML that will render this node. + */ + getNodeHtml: function() { + return ""; + }, + + /** + * Regenerates the html for this node and its children. To be used when the + * node is expanded and new children have been added. + * @method refresh + */ + refresh: function() { + // this.loadComplete(); + this.getChildrenEl().innerHTML = this.completeRender(); + + if (this.hasIcon) { + var el = this.getToggleEl(); + if (el) { + el.className = this.getStyle(); + } + } + }, + + /** + * Node toString + * @method toString + * @return {string} string representation of the node + */ + toString: function() { + return "Node (" + this.index + ")"; + } + +}; + +YAHOO.augment(YAHOO.widget.Node, YAHOO.util.EventProvider); + +/** + * A custom YAHOO.widget.Node that handles the unique nature of + * the virtual, presentationless root node. + * @namespace YAHOO.widget + * @class RootNode + * @extends YAHOO.widget.Node + * @param oTree {YAHOO.widget.TreeView} The tree instance this node belongs to + * @constructor + */ +YAHOO.widget.RootNode = function(oTree) { + // Initialize the node with null params. The root node is a + // special case where the node has no presentation. So we have + // to alter the standard properties a bit. + this.init(null, null, true); + + /* + * For the root node, we get the tree reference from as a param + * to the constructor instead of from the parent element. + */ + this.tree = oTree; +}; + +YAHOO.extend(YAHOO.widget.RootNode, YAHOO.widget.Node, { + + // overrides YAHOO.widget.Node + getNodeHtml: function() { + return ""; + }, + + toString: function() { + return "RootNode"; + }, + + loadComplete: function() { + this.tree.draw(); + } + +}); +/** + * The default node presentation. The first parameter should be + * either a string that will be used as the node's label, or an object + * that has a string propery called label. By default, the clicking the + * label will toggle the expanded/collapsed state of the node. By + * changing the href property of the instance, this behavior can be + * changed so that the label will go to the specified href. + * @namespace YAHOO.widget + * @class TextNode + * @extends YAHOO.widget.Node + * @constructor + * @param oData {object} a string or object containing the data that will + * be used to render this node + * @param oParent {YAHOO.widget.Node} this node's parent node + * @param expanded {boolean} the initial expanded/collapsed state + */ +YAHOO.widget.TextNode = function(oData, oParent, expanded) { + + if (oData) { + this.init(oData, oParent, expanded); + this.setUpLabel(oData); + } + +}; + +YAHOO.extend(YAHOO.widget.TextNode, YAHOO.widget.Node, { + + /** + * The CSS class for the label href. Defaults to ygtvlabel, but can be + * overridden to provide a custom presentation for a specific node. + * @property labelStyle + * @type string + */ + labelStyle: "ygtvlabel", + + /** + * The derived element id of the label for this node + * @property labelElId + * @type string + */ + labelElId: null, + + /** + * The text for the label. It is assumed that the oData parameter will + * either be a string that will be used as the label, or an object that + * has a property called "label" that we will use. + * @property label + * @type string + */ + label: null, + + textNodeParentChange: function() { + + /** + * Custom event that is fired when the text node label is clicked. The + * custom event is defined on the tree instance, so there is a single + * event that handles all nodes in the tree. The node clicked is + * provided as an argument + * + * @event labelClick + * @for YAHOO.widget.TreeView + * @param {YAHOO.widget.Node} node the node clicked + */ + if (this.tree && !this.tree.hasEvent("labelClick")) { + this.tree.createEvent("labelClick", this.tree); + } + + }, + + /** + * Sets up the node label + * @method setUpLabel + * @param oData string containing the label, or an object with a label property + */ + setUpLabel: function(oData) { + + // set up the custom event on the tree + this.textNodeParentChange(); + this.subscribe("parentChange", this.textNodeParentChange); + + if (typeof oData == "string") { + oData = { label: oData }; + } + this.label = oData.label; + + // update the link + if (oData.href) { + this.href = oData.href; + } + + // set the target + if (oData.target) { + this.target = oData.target; + } + + if (oData.style) { + this.labelStyle = oData.style; + } + + this.labelElId = "ygtvlabelel" + this.index; + }, + + /** + * Returns the label element + * @for YAHOO.widget.TextNode + * @method getLabelEl + * @return {object} the element + */ + getLabelEl: function() { + return document.getElementById(this.labelElId); + }, + + // overrides YAHOO.widget.Node + getNodeHtml: function() { + var sb = []; + + sb[sb.length] = ''; + sb[sb.length] = ''; + + for (var i=0;i '; + } + + var getNode = 'YAHOO.widget.TreeView.getNode(\'' + + this.tree.id + '\',' + this.index + ')'; + + sb[sb.length] = ''; + + /* + sb[sb.length] = ' '; + } + + if (this.hasIcon) { + sb[sb.length] = '=0;i--) { + var currentnode; + if (i==node.depth) { + currentnode=node; + } else { + currentnode=node.getAncestor(i); + } + //add id to url. + url=url+"&PARAMN_id"+'_'+currentnode.depth+'='+currentnode.data.id; + + //add other requested parameters. + if (currentnode.data.param != 'undefined') { + for (nparam in currentnode.data.param) { + url=url+"&PARAMN_"+nparam+'_'+currentnode.depth+'='+currentnode.data.param[nparam]; + } + } + } + return url; +} + +//following function uses an AJAX call to load the children nodes dynamically. +//this methods assumes that you have TreeData.php in the root of you application. +//the file must have get_node_data function. +//return value must be an array of nodes. +function loadDataForNode(node, onCompleteCallback) { + var id= node.data.id; + + var params="entryPoint=TreeData&function=get_node_data" + construct_url_from_tree_param(node); + + var callback = { + success: function(o) { + node=o.argument[0]; + var nodes=JSON.parse(o.responseText); + var tmpNode; + for (nodedata in nodes) { + for (node1 in nodes[nodedata]) { + addNode(node, nodes[nodedata][node1]); + } + } + o.argument[1](); + }, + failure: function(o) {/*failure handler code*/}, + argument: [node, onCompleteCallback] + } + var trobj = YAHOO.util.Connect.asyncRequest('POST','index.php', callback, params); +} \ No newline at end of file diff --git a/jssource/src_files/install/dbConfig.js b/jssource/src_files/install/dbConfig.js new file mode 100644 index 00000000..a52510a8 --- /dev/null +++ b/jssource/src_files/install/dbConfig.js @@ -0,0 +1,77 @@ +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + + +function togglePasswordRetypeRequired() { + var theForm = document.forms[0]; + var elem = document.getElementById('password_retype_required'); + + if( theForm.setup_db_create_sugarsales_user.checked ){ + elem.style.display = ''; + // theForm.setup_db_sugarsales_user.focus(); + theForm.setup_db_username_is_privileged.checked = ""; + theForm.setup_db_username_is_privileged.disabled = "disabled"; + toggleUsernameIsPrivileged(); + } + else { + elem.style.display = 'none'; + theForm.setup_db_username_is_privileged.disabled = ""; + } +} + +function toggleDropTables(){ + var theForm = document.forms[0]; + + if( theForm.setup_db_create_database.checked ){ + theForm.setup_db_drop_tables.checked = ''; + theForm.setup_db_drop_tables.disabled = "disabled"; + } + else { + theForm.setup_db_drop_tables.disabled = ''; + } +} + +function toggleUsernameIsPrivileged(){ + var theForm = document.forms[0]; + var elem = document.getElementById('privileged_user_info'); + + if( theForm.setup_db_username_is_privileged.checked ){ + elem.style.display = 'none'; + } + else { + elem.style.display = ''; + } +} diff --git a/jssource/src_files/install/installCommon.js b/jssource/src_files/install/installCommon.js new file mode 100644 index 00000000..dd8a1d84 --- /dev/null +++ b/jssource/src_files/install/installCommon.js @@ -0,0 +1,48 @@ +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + + +function showHelp(step) +{ + url = 'http://www.sugarcrm.com/forums/'; + name = 'helpWindowPopup'; + window.open(url,name); +} + +function setFocus() { + focus = document.getElementById('defaultFocus'); + focus.focus(); +} diff --git a/jssource/src_files/install/license.js b/jssource/src_files/install/license.js new file mode 100644 index 00000000..4aeb31ed --- /dev/null +++ b/jssource/src_files/install/license.js @@ -0,0 +1,62 @@ +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + + +function toggleLicenseAccept(){ + var theForm = document.forms[0]; + + if( theForm.setup_license_accept.checked ){ + theForm.setup_license_accept.checked = ""; + } + else { + theForm.setup_license_accept.checked = "yes"; + } + + toggleNextButton(); +} + +function toggleNextButton(){ + var theForm = document.forms[0]; + var nextButton = document.getElementById( "button_next" ); + + if( theForm.setup_license_accept.checked ){ + nextButton.disabled = ''; + nextButton.focus(); + } + else { + nextButton.disabled = "disabled"; + } +} diff --git a/jssource/src_files/install/oc_convert.js b/jssource/src_files/install/oc_convert.js new file mode 100644 index 00000000..94586e06 --- /dev/null +++ b/jssource/src_files/install/oc_convert.js @@ -0,0 +1,41 @@ +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + + +function toggleIsFirstTime(){ + var theForm = document.forms[0]; + theForm.first_time.value = "false"; +} diff --git a/jssource/src_files/install/oc_install.js b/jssource/src_files/install/oc_install.js new file mode 100644 index 00000000..f55450dd --- /dev/null +++ b/jssource/src_files/install/oc_install.js @@ -0,0 +1,51 @@ +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + + +function toggleOfflineClientInstallation(){ + var theForm = document.forms[0]; + + if(!theForm.oc_install.checked ){ + theForm.oc_server_url.disabled = "disabled"; + theForm.oc_username.disabled = "disabled"; + theForm.oc_password.disabled = "disabled"; + } + else { + theForm.oc_server_url.disabled = ''; + theForm.oc_username.disabled = ''; + theForm.oc_password.disabled = ''; + } +} diff --git a/jssource/src_files/install/register.js b/jssource/src_files/install/register.js new file mode 100644 index 00000000..ed548fed --- /dev/null +++ b/jssource/src_files/install/register.js @@ -0,0 +1,83 @@ +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + + +function submitbutton() +{ + var form = document.mosForm; + var r = new RegExp("[^0-9A-Za-z]", "i"); + + if (form.email1.value != "") + { + var myString = form.email1.value; + var pattern = /(\W)|(_)/g; + var adate = new Date(); + var ms = adate.getMilliseconds(); + var sec = adate.getSeconds(); + var mins = adate.getMinutes(); + ms = ms.toString(); + sec = sec.toString(); + mins = mins.toString(); + newdate = ms + sec + mins; + + var newString = myString.replace(pattern,""); + newString = newString + newdate; + //form.username.value = newString; + //form.password.value = newString; + //form.password2.value = newString; + } + + // do field validation + if (form.name.value == "") + { + form.name.focus(); + alert( "Please provide your name" ); + return false; + } + else if (form.email1.value == "") + { + form.email1.focus(); + alert( "Please provide your email address" ); + return false; + } + else + { + form.submit(); + } + + document.appform.submit(); + window.focus(); +} diff --git a/jssource/src_files/install/siteConfig.js b/jssource/src_files/install/siteConfig.js new file mode 100644 index 00000000..7808036f --- /dev/null +++ b/jssource/src_files/install/siteConfig.js @@ -0,0 +1,93 @@ +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + + +function toggleSiteDefaults(){ + var theForm = document.forms[0]; + var elem = document.getElementById('setup_site_session'); + + if( theForm.setup_site_defaults.checked ){ + document.getElementById('setup_site_session_section_pre').style.display = 'none'; + document.getElementById('setup_site_session_section').style.display = 'none'; + document.getElementById('setup_site_log_dir_pre').style.display = 'none'; + document.getElementById('setup_site_log_dir').style.display = 'none'; + document.getElementById('setup_site_guid_section_pre').style.display = 'none'; + document.getElementById('setup_site_guid_section').style.display = 'none'; + } + else { + document.getElementById('setup_site_session_section_pre').style.display = ''; + document.getElementById('setup_site_log_dir_pre').style.display = ''; + document.getElementById('setup_site_guid_section_pre').style.display = ''; + toggleSession(); + toggleGUID(); + } +} + +function toggleSession(){ + var theForm = document.forms[0]; + var elem = document.getElementById('setup_site_session_section'); + + if( theForm.setup_site_custom_session_path.checked ){ + elem.style.display = ''; + } + else { + elem.style.display = 'none'; + } +} + +function toggleLogDir(){ + var theForm = document.forms[0]; + var elem = document.getElementById('setup_site_log_dir'); + + if( theForm.setup_site_custom_log_dir.checked ){ + elem.style.display = ''; + } + else { + elem.style.display = 'none'; + } +} + +function toggleGUID(){ + var theForm = document.forms[0]; + var elem = document.getElementById('setup_site_guid_section'); + + if( theForm.setup_site_specify_guid.checked ){ + elem.style.display = ''; + } + else { + elem.style.display = 'none'; + } +} diff --git a/jssource/src_files/modules/ACLRoles/ACLRoles.js b/jssource/src_files/modules/ACLRoles/ACLRoles.js new file mode 100644 index 00000000..2601782f --- /dev/null +++ b/jssource/src_files/modules/ACLRoles/ACLRoles.js @@ -0,0 +1,92 @@ +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +var aclviewer = function(){ + var lastDisplay = ''; + return { + view: function(role_id, role_module){ + YAHOO.util.Connect.asyncRequest('POST', 'index.php',{'success':aclviewer.display, 'failure':aclviewer.failed}, 'module=ACLRoles&action=EditRole&record=' + role_id + '&category_name=' + role_module); + ajaxStatus.showStatus(SUGAR.language.get('app_strings', 'LBL_REQUEST_PROCESSED')); + }, + save: function(form_name){ + var formObject = document.getElementById(form_name); + YAHOO.util.Connect.setForm(formObject); + YAHOO.util.Connect.asyncRequest('POST', 'index.php',{'success':aclviewer.postSave, 'failure':aclviewer.failed} ); + ajaxStatus.showStatus(SUGAR.language.get('app_strings', 'LBL_SAVING')); + }, + postSave: function(o){ + eval(o.responseText); + aclviewer.view(result['role_id'], result['module']); + }, + display:function(o){ + aclviewer.lastDisplay = ''; + ajaxStatus.flashStatus('Done'); + document.getElementById('category_data').innerHTML = o.responseText; + + }, + failed:function(){ + ajax.flashStatus('Could Not Connect'); + }, + + toggleDisplay:function(id){ + if(aclviewer.lastDisplay != '' && typeof(aclviewer.lastDisplay) != 'undefined'){ + aclviewer.hideDisplay(aclviewer.lastDisplay); + } + if(aclviewer.lastDisplay != id){ + aclviewer.showDisplay(id); + aclviewer.lastDisplay = id; + } else{ + aclviewer.lastDisplay = ''; + } + + }, + + hideDisplay:function(id){ + document.getElementById(id).style.display = 'none'; + document.getElementById(id + 'link').style.display = ''; + + }, + + showDisplay:function(id){ + document.getElementById(id).style.display = ''; + document.getElementById(id + 'link').style.display = 'none'; + } + + + + }; + + +}(); diff --git a/jssource/src_files/modules/Accounts/Account.js b/jssource/src_files/modules/Accounts/Account.js new file mode 100644 index 00000000..0cce4b1c --- /dev/null +++ b/jssource/src_files/modules/Accounts/Account.js @@ -0,0 +1,90 @@ +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + +function open_contact_popup(module_name, width, height, initial_filter, close_popup, hide_clear_button, popup_request_data, popup_mode, create, metadata) +{ + // set the variables that the popup will pull from + window.document.popup_request_data = popup_request_data; + window.document.close_popup = close_popup; + + // launch the popup + URL = 'index.php?mode=MultiSelect&' + + 'module=' + module_name + + '&action=ContactAddressPopup'; + + if(initial_filter != '') + { + URL += '&query=true' + initial_filter; + } + + if(hide_clear_button) + { + URL += '&hide_clear_button=true'; + } + + windowName = 'popup_window'; + + windowFeatures = 'width=' + width + + ',height=' + height + + ',resizable=1,scrollbars=1'; + + if (popup_mode == '' && popup_mode == 'undefined') { + popup_mode='single'; + } + URL+='&mode='+popup_mode; + if (create == '' && create == 'undefined') { + create = 'false'; + } + URL+='&create='+create; + + if (metadata != '' && metadata != 'undefined') { + URL+='&metadata='+metadata; + } + + win = window.open(URL, windowName, windowFeatures); + + if(window.focus) + { + // put the focus on the popup if the browser supports the focus() method + win.focus(); + } + + return win; +} + +function set_focus(){ + document.getElementById('name').focus(); +} \ No newline at end of file diff --git a/jssource/src_files/modules/Administration/javascript/Administration.js b/jssource/src_files/modules/Administration/javascript/Administration.js new file mode 100644 index 00000000..56236986 --- /dev/null +++ b/jssource/src_files/modules/Administration/javascript/Administration.js @@ -0,0 +1,136 @@ +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +// defense +if(typeof(SUGAR) == 'undefined') { + var SUGAR = {}; +} + +SUGAR.Administration = { + /** + * calls modules/Administration/Async.php with JSON objects + */ + Async : { + }, + + /** + * Utility functions for RepairXSS screen + * @param HTMLSelectObject select dropdown + */ + RepairXSS : { + toRepair : new Object, // assoc array of items to be cleaned + currentRepairObject : "", // bean currently worked on + currentRepairIds : new Array(), // array of ids for above bean + repairedCount : 0, + numberToFix: 25, // how many IDs to send at once from client + + /** + * Calculates how many rows to iterate through + */ + refreshEstimate : function(select) { + this.toRepair = new Object(); + this.repairedCount = 0; + + var button = document.getElementById('repairXssButton'); + var selected = select.value; + var totalDisplay = document.getElementById('repairXssDisplay'); + var counter = document.getElementById('repairXssCount'); + var repaired = document.getElementById('repairXssResults'); + var repairedCounter = document.getElementById('repairXssResultCount'); + + if(selected != "0") { + button.style.display = 'inline'; + repairedCounter.value = 0; + AjaxObject.startRequest(callbackRepairXssRefreshEstimate, "&adminAction=refreshEstimate&bean=" + selected); + } else { + button.style.display = 'none'; + totalDisplay.style.display = 'none'; + repaired.style.display = 'none'; + counter.value = 0; + repaired.value= 0; + } + }, + + /** + * Takes selection and executes repair function + */ + executeRepair : function() { + if(this.toRepair) { + // if queue is empty load next + if(this.currentRepairIds.length < 1) { + if(!this.loadRepairQueue()) { + alert(done); + return; // we're done + } + } + + var beanIds = new Array(); + + for(var i=0; i 0) { + beanIds.push(this.currentRepairIds.pop()); + } + } + + var beanId = JSON.stringifyNoSecurity(beanIds); + AjaxObject.startRequest(callbackRepairXssExecute, "&adminAction=repairXssExecute&bean=" + this.currentRepairObject + "&id=" + beanId); + } + }, + + /** + * Loads the bean name and array of bean ids for repair + * @return bool False if load did not occur + */ + loadRepairQueue : function() { + var loaded = false; + + this.currentRepairObject = ''; + this.currentRepairIds = new Array(); + + for(var bean in this.toRepair) { + if(this.toRepair[bean].length > 0) { + this.currentRepairObject = bean; + this.currentRepairIds = this.toRepair[bean]; + loaded = true; + } + } + + // 'unset' the IDs array so we don't iterate over it again + this.toRepair[this.currentRepairObject] = new Array(); + + return loaded; + } + } +} \ No newline at end of file diff --git a/jssource/src_files/modules/Administration/javascript/Async.js b/jssource/src_files/modules/Administration/javascript/Async.js new file mode 100644 index 00000000..cdb02854 --- /dev/null +++ b/jssource/src_files/modules/Administration/javascript/Async.js @@ -0,0 +1,119 @@ +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +var AjaxObject = { + ret : '', + currentRequestObject : null, + timeout : 30000, // 30 second timeout default + forceAbort : false, + + /** + */ + _reset : function() { + this.timeout = 30000; + this.forceAbort = false; + }, + handleFailure : function(o) { + alert('asynchronous call failed.'); + }, + /** + */ + startRequest : function(callback, args, forceAbort) { + if(this.currentRequestObject != null) { + if(this.forceAbort == true || callback.forceAbort == true) { + YAHOO.util.Connect.abort(this.currentRequestObject, null, false); + } + } + + this.currentRequestObject = YAHOO.util.Connect.asyncRequest('POST', "./index.php?module=Administration&action=Async&to_pdf=true", callback, args); + this._reset(); + }, + + /************************************************************************** + * Place callback handlers below this comment + **************************************************************************/ + + /** + * gets an estimate of how many rows to process + */ + refreshEstimate : function(o) { + this.ret = JSON.parse(o.responseText); + document.getElementById('repairXssDisplay').style.display = 'inline'; + document.getElementById('repairXssCount').value = this.ret.count; + + SUGAR.Administration.RepairXSS.toRepair = this.ret.toRepair; + }, + showRepairXssResult : function(o) { + var resultCounter = document.getElementById('repairXssResultCount'); + + this.ret = JSON.parse(o.responseText); + document.getElementById('repairXssResults').style.display = 'inline'; + + if(this.ret.msg == 'success') { + SUGAR.Administration.RepairXSS.repairedCount += this.ret.count; + resultCounter.value = SUGAR.Administration.RepairXSS.repairedCount; + } else { + resultCounter.value = this.ret; + } + + SUGAR.Administration.RepairXSS.executeRepair(); + } +}; + +/***************************************************************************** + * MODEL callback object: + * **************************************************************************** + var callback = { + success:AjaxObject.handleSuccess, + failure:AjaxObject.handleFailure, + timeout:AjaxObject.timeout, + scope:AjaxObject, + forceAbort:true, // optional + argument:[ieId, ieName, focusFolder] // optional + }; + */ + +var callbackRepairXssRefreshEstimate = { + success:AjaxObject.refreshEstimate, + failure:AjaxObject.handleFailure, + timeout:AjaxObject.timeout, + scope:AjaxObject +}; +var callbackRepairXssExecute = { + success:AjaxObject.showRepairXssResult, + failure:AjaxObject.handleFailure, + timeout:AjaxObject.timeout, + scope:AjaxObject +}; diff --git a/jssource/src_files/modules/Campaigns/DetailView.js b/jssource/src_files/modules/Campaigns/DetailView.js new file mode 100644 index 00000000..0ee2a254 --- /dev/null +++ b/jssource/src_files/modules/Campaigns/DetailView.js @@ -0,0 +1,63 @@ +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + + + +function set_return_prospect_list_and_save(popup_reply_data) +{ + var form_name = popup_reply_data.form_name; + var name_to_value_array = popup_reply_data.name_to_value_array; + + + for (var the_key in name_to_value_array) + { + if(the_key == 'toJSON') + { + /* just ignore */ + } + else + { + window.document.forms[form_name].elements[the_key].value = name_to_value_array[the_key]; + } + } + + window.document.forms[form_name].module.value = 'Campaigns'; + window.document.forms[form_name].return_module.value = window.document.forms[form_name].module.value; + window.document.forms[form_name].return_action.value = 'DetailView'; + window.document.forms[form_name].return_id.value = window.document.forms[form_name].record.value; + window.document.forms[form_name].action.value = 'SaveCampaignProspectListRelationship'; + window.document.forms[form_name].submit(); +} \ No newline at end of file diff --git a/jssource/src_files/modules/Campaigns/WebToLead.js b/jssource/src_files/modules/Campaigns/WebToLead.js new file mode 100644 index 00000000..61272e6d --- /dev/null +++ b/jssource/src_files/modules/Campaigns/WebToLead.js @@ -0,0 +1,226 @@ +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + +//grid functions + +var grid2, grid3, grid4, grid3F,grid4F; +var add_all_fields = SUGAR.language.get('app_strings', 'LBL_ADD_ALL_LEAD_FIELDS'); +var remove_all_fields = SUGAR.language.get('app_strings', 'LBL_REMOVE_ALL_LEAD_FIELDS'); + +function addGrids(form_name) { + //check if any vals selected in grid3 and grid4 + // if none then prompt for validation + //alert(check_form('WebToLeadCreation')); + if(!check_form('WebToLeadCreation')){ + return false; + //stop + } + else{ + grid3 = SUGAR_GRID_grid1; + grid4 = SUGAR_GRID_grid2; + var webFormDiv = document.getElementById('webformfields'); + //add columns to webformfields div + addCols(grid3,'colsFirst',webFormDiv); + addCols(grid4,'colsSecond',webFormDiv); + return true; + } //return check_form(form_name); +} +function checkFields(REQUIRED_LEAD_FIELDS,LEAD_SELECT_FIELDS){ + grid2 = SUGAR_GRID_grid0; + grid3 = SUGAR_GRID_grid1; + grid4 = SUGAR_GRID_grid2; + //check if all required fields are selected + var reqFields = ''; + for(var i=0; i < grid2.getRecordSet().getLength(); i++){ + if(grid2.getRecord(i).getData()[2] != null){ + reqFields = reqFields+grid2.getRecord(i).getData()[0]+', '; + } + } + if(reqFields){ + reqFields = reqFields.substring(0,reqFields.lastIndexOf(',')); + alert(REQUIRED_LEAD_FIELDS+' '+reqFields); + return false; + } + else if(grid3.getRecordSet().getLength()==1 && grid4.getRecordSet().getLength()==1){ + alert(LEAD_SELECT_FIELDS); + return false; + } + else{ + return true; + } +} + +function askLeadQ(direction,REQUIRED_LEAD_FIELDS,LEAD_SELECT_FIELDS){ + //change current step value to that of the step being navigated to + if(direction == 'back'){ + var grid_Div = document.getElementById('grid_Div'); + var lead_Div = document.getElementById('lead_queries_Div'); + grid_Div.style.display='block'; + lead_Div.style.display='none'; + } + + if(direction == 'next'){ + if(!checkFields(REQUIRED_LEAD_FIELDS,LEAD_SELECT_FIELDS)){ + return false; + } + else{ + var lead_Div = document.getElementById('lead_queries_Div'); + var grid_Div = document.getElementById('grid_Div'); + lead_Div.style.display='block'; + grid_Div.style.display='none'; + } + } +} + function campaignPopulated(){ + var camp_populated = document.getElementById('campaign_id'); + if(camp_populated.value == 0){ + return true; + }; + return true; + } + + function selectFields(indexes,grid){ + var retStr=''; + for(var i=0;i 1) { + addRemove.setAttribute('value',Add_All_Fields); + addRemove.setAttribute('title',Add_All_Fields); + } + else{ + addRemove.setAttribute('value',Remove_All_Fields); + addRemove.setAttribute('title',Remove_All_Fields); + } +} +function dragDropAllFields(Add_All_Fields, Remove_All_Fields){ + //set the grids to the SUGAR_GRID grids + + grid2 = SUGAR_GRID_grid0; + grid3 = SUGAR_GRID_grid1; + grid4 = SUGAR_GRID_grid2; + //move from main grid to columns 1&2 + var addRemove = document.getElementById("lead_add_remove_button"); + var availibleSet = grid2.getRecordSet(); + var availibleCount = availibleSet.getLength() ; + if(addRemove.value == Add_All_Fields && availibleCount > 1) { //Contains more than the empty node + for(var i=0; i < availibleCount; i++){ + if(i%2 ==0 && availibleSet.getRecord(i).getData()[0] != " "){ + grid3.addRow(availibleSet.getRecord(i).getData(), (i / 2)); + } + if(i%2 ==1 && availibleSet.getRecord(i).getData()[0] != " "){ + grid4.addRow(availibleSet.getRecord(i).getData(), ((i - 1) / 2)); + } + } + for (i = availibleCount - 1; i >= 0; i--) { + if(grid2.getRecord(i) != null && grid2.getRecord(i).getData()[0] != " ") { + grid2.deleteRow(i); + } + } + } + else if(addRemove.value==Remove_All_Fields){ //move back to the main grid if grid is empty and columns populated + var count =0; + if(grid3.getRecordSet().getLength() >= grid4.getRecordSet().getLength()){ + count = grid3.getRecordSet().getLength(); + } + else{ + count = grid4.getRecordSet().getLength(); + } + //put back into grid2 in the same order + for(var i = 0; i < count; i++){ + if(grid3.getRecord(i) != null && grid3.getRecord(i).getData()[0] != " "){ + grid2.addRow(grid3.getRecord(i).getData(), grid2.getRecordSet().getLength() - 1); + } + if(grid4.getRecord(i) != null && grid4.getRecord(i).getData()[0] != " "){ + grid2.addRow(grid4.getRecord(i).getData(), grid2.getRecordSet().getLength() - 1); + } + } + for(var i = count - 1; i >= 0; i--){ + if(grid4.getRecord(i) != null && grid4.getRecord(i).getData()[0] != " ") { + grid4.deleteRow(i); + } + if(grid3.getRecord(i) != null && grid3.getRecord(i).getData()[0] != " ") { + grid3.deleteRow(i); + } + } + } + displayAddRemoveButtons(Add_All_Fields,Remove_All_Fields); +} + + + function addCols(grid, colsNumber, webFormDiv){ + for(var i = 0; i < grid.getRecordSet().getLength() - 1; i++){ + var selectedEl = grid.getRecord(i).getData()[1]; + var webField = document.createElement('input'); + webField.setAttribute('id', colsNumber+i); + webField.setAttribute('name',colsNumber+'[]'); + webField.setAttribute('type', 'hidden'); + webField.setAttribute('value',selectedEl); + webFormDiv.appendChild(webField); + } + } + function editUrl(){ + var chk_url_elm = document.getElementById("chk_edit_url"); + if(chk_url_elm.checked==true){ + var url_elm = document.getElementById("post_url"); + url_elm.disabled=false; + } + if(chk_url_elm.checked==false){ + var url_elm = document.getElementById("post_url"); + url_elm.disabled=true; + } + } + + diff --git a/jssource/src_files/modules/Campaigns/wizard.js b/jssource/src_files/modules/Campaigns/wizard.js new file mode 100644 index 00000000..216c7546 --- /dev/null +++ b/jssource/src_files/modules/Campaigns/wizard.js @@ -0,0 +1,291 @@ +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + + + /* + * this function hides a div element using the passed in id value + */ + function hide(divname){ + var elem1 = document.getElementById(divname); + elem1.style.display = 'none'; + } + + /* + * this function shows a div using the passed in value + */ + function show(div){ + var elem1 = document.getElementById(div); + elem1.style.display = ''; + } + /* + * this function calls the methods to hide all divs and show the passed in div + */ + function showdiv(div){ + hideall(); + show(div); + } + + /* + * this function iterates through all "stepx" divs (ie. step1, step2,etc) and hides them + */ + function hideall(){ + var last_val = document.getElementById('wiz_total_steps'); + var last = parseInt(last_val.value); + for(i=1; i<=last; i++){ + hide('step'+i); + } + } + + + /*this function should be run first. It will call the methods that: + * 1.hide the divs initially + * 2.show the first div + * 3.shows/hides the proper buttons + * 4.highlites the step title + * 5.adjusts the step location message + */ + function showfirst(wiz_mode){ + //no validation needed. + + //show first step + showdiv('step1'); + + //set div value + var current_step = document.getElementById('wiz_current_step'); + current_step.value="1"; + + //set button values + + + var save_button = document.getElementById('wiz_submit_button'); + var next_button = document.getElementById('wiz_next_button'); + var save_button_div = document.getElementById('save_button_div'); + var next_button_div = document.getElementById('next_button_div'); + var back_button_div = document.getElementById('back_button_div'); + + save_button.disabled = true; + back_button_div.style.display = 'none'; + save_button_div.style.display = 'none'; + next_button.focus(); + if(wiz_mode == 'marketing'){ + back_button_div.style.display = ''; + } + + //set nav hi-lite + hilite(current_step.value); + + + } + + + + /*this function runs on each navigation in the wizard. It will call the methods that: + * 1.hide the divs + * 2.show the div being navigated to + * 3.shows/hides the proper buttons + * 4.highlites the step title + * 5.adjusts the step location message + */ + + function navigate(direction){ + //get the current step + var current_step = document.getElementById('wiz_current_step'); + var currentValue = parseInt(current_step.value); + + //validation needed. (specialvalidation, plus step number, plus submit button) + if(validate_wiz(current_step.value,direction)){ + + //change current step value to that of the step being navigated to + if(direction == 'back'){ + current_step.value = currentValue-1; + } + if(direction == 'next'){ + current_step.value = currentValue+1; + } + if(direction == 'direct'){ + //no need to modify current step, this is a direct navigation + } + + //show next step + showdiv("step"+current_step.value); + + //set nav hi-lite + hilite(current_step.value); + + //enable save button if on last step + var total = document.getElementById('wiz_total_steps').value; + var save_button = document.getElementById('wiz_submit_button'); + var back_button_div = document.getElementById('back_button_div'); + var save_button_div = document.getElementById('save_button_div'); + var next_button_div = document.getElementById('next_button_div'); + if(current_step.value==total){ + //save_button.display=''; + save_button.disabled = false; + back_button_div.style.display = ''; + save_button_div.style.display = ''; + next_button_div.style.display = 'none'; + + }else{ + if(current_step.value<2){ + back_button_div.style.display = 'none'; + }else{ + back_button_div.style.display = ''; + } + var next_button = document.getElementById('wiz_next_button'); + next_button_div.style.display = ''; + save_button_div.style.display = 'none'; + next_button.focus(); + } + + }else{ + //error occurred, do nothing + } + + } + + /* + * This function highlites the right title on the navigation div. + * It also changes the title to a navigational link + * */ + var already_linked =''; + function hilite(hilite){ + var last = parseInt(document.getElementById('wiz_total_steps').value); + for(i=1; i<=last; i++){ + var nav_step = document.getElementById('nav_step'+i); + nav_step.className = ''; + } + var nav_step = document.getElementById('nav_step'+hilite); + nav_step.className = ''; + if(already_linked.indexOf(hilite)<0){ + nav_step.innerHTML= "" +nav_step.innerHTML+ ""; + already_linked +=',hilite'; + } + } + + /* + * Given a start and end, This function highlights the right title on the navigation div. + * It also changes the title to a navigational link + * */ + function link_navs(beg, end){ + if(beg==''){ + beg=1; + } + if(end==''){ + var last = document.getElementById('wiz_total_steps').value; + end=last; + } + beg =parseInt(beg); + end =parseInt(end); + + for(i=beg; i<=end; i++){ + var nav_step = document.getElementById('nav_step'+ i); + nav_step.innerHTML= "" +nav_step.innerHTML+ ""; + } + + } + + /** + * This function is called when clicking on a title that has already been changed + * to show a link. It is a direct navigation link + */ + function direct(stepnumber){ + //get the current step + var current_step = document.getElementById('wiz_current_step'); + var currentValue = parseInt(current_step.value); + + //validation needed. (specialvalidation, plus step number, plus submit button) + if(validate_wiz(current_step.value,'direct')){ + + //lets set the current step to the selected step and invoke navigation + current_step.value = stepnumber; + navigate('direct'); + }else{ + //do nothing, validation failed + } + } + + +/* + * This is a generic create summary function. It scrapes the form for all elements that + * are not hidden and displays it's value. It uses the "title" parameter as the title + * in the summary There is also a provision for overriding this function and providing more + * precise summary functions + */ + + /* + * This function will perform basic navigation validation, and then call the customized + * form validation specified for this step. This custom call should reside on wizard page itself. + * + */ + function validate_wiz(step, direction){ + var total = document.getElementById('wiz_total_steps').value; + var wiz_message = document.getElementById('wiz_message'); + //validate step + if(direction =='back'){ + //cancel and alert if on step1 + if(step=='1'){ + var msg = SUGAR.language.get('mod_strings', 'LBL_WIZARD_FIRST_STEP_MESSAGE'); + wiz_message.innerHTML = ""+msg+""; + return false; + }else{ + wiz_message.innerHTML = ''; + } + } + + if(direction =='next'){ + //cancel and alert if on last step + if(step==total){ + var msg = SUGAR.language.get('mod_strings', 'LBL_WIZARD_LAST_STEP_MESSAGE'); + wiz_message.innerHTML = ""+msg+""; + return false; + }else{ + wiz_message.innerHTML = ''; + } + } + if(direction =='direct'){ + //no need to perform navigation validation + } + + //make call to custom form validation, do not call if this is a direct navigation + //if this is a direct navigation, then validation has already happened, calling twice + //will not allow page to navigate + if((direction !='direct') && ( window.validate_wiz_form ) && (!validate_wiz_form('step'+step))){ + return false; + } + + return true; + } + diff --git a/jssource/src_files/modules/Connectors/Connector.js b/jssource/src_files/modules/Connectors/Connector.js new file mode 100644 index 00000000..ac5a3d2d --- /dev/null +++ b/jssource/src_files/modules/Connectors/Connector.js @@ -0,0 +1,122 @@ +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + +function run_test(source_id) { + var callback = { + success: function(data) { + var resultDiv = document.getElementById(source_id + '_result'); + resultDiv.innerHTML = '' + data.responseText + ''; + }, + failure: function(data) { + var resultDiv = document.getElementById(source_id + '_result'); + resultDiv.innerHTML = '' + SUGAR.language.get('app_strings', 'ERROR_UNABLE_TO_RETRIEVE_DATA') + ''; + }, + timeout: 300000 + } + + var resultDiv = document.getElementById(source_id + '_result'); + resultDiv.innerHTML = ''; + document.ModifyProperties.source_id.value = source_id; + document.ModifyProperties.action.value = 'RunTest'; + YAHOO.util.Connect.setForm(document.ModifyProperties); + var cObj = YAHOO.util.Connect.asyncRequest('POST','index.php?module=Connectors', callback); + document.ModifyProperties.action.value = 'SaveModifyProperties'; +} + +var widgetTimout; +function dswidget_open(elt){ + + var wdiget_div = document.getElementById('dswidget_div'); + var objX = findPosX(elt); + var objY = findPosY(elt); + + wdiget_div.style.top = (objY+15) + 'px'; + wdiget_div.style.left = (objX) + 'px'; + + wdiget_div.style.display = 'block'; +} + +function dswidget_close(){ + + widgetTimout = setTimeout("hide_widget()", 500); +} + +function hide_widget(){ + var wdiget_div = document.getElementById('dswidget_div'); + wdiget_div.style.display = 'none'; +} + +function clearButtonTimeout(){ + if(widgetTimout){ + clearTimeout(widgetTimout); + } +} + +function findPosX(obj) +{ + var curleft = 0; + if (obj.offsetParent) + { + while (obj.offsetParent) + { + curleft += obj.offsetLeft; + obj = obj.offsetParent; + } + if ( obj != null ) + curleft += obj.offsetLeft; + } + else if (obj.x) + curleft += obj.x; + return curleft; +} + +function findPosY(obj) +{ + var curtop = 0; + if (obj.offsetParent) + { + while (obj.offsetParent) + { + curtop += obj.offsetTop; + obj = obj.offsetParent; + } + if ( obj != null ) + curtop += obj.offsetTop; + } + else if (obj.y) + curtop += obj.y; + return curtop; +} \ No newline at end of file diff --git a/jssource/src_files/modules/Contacts/Contact.js b/jssource/src_files/modules/Contacts/Contact.js new file mode 100644 index 00000000..8cb83985 --- /dev/null +++ b/jssource/src_files/modules/Contacts/Contact.js @@ -0,0 +1,192 @@ +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +function set_campaignlog_and_save_background(popup_reply_data) +{ + var form_name = popup_reply_data.form_name; + var name_to_value_array = popup_reply_data.name_to_value_array; + var passthru_data = popup_reply_data.passthru_data; + // construct the POST request + var query_array = new Array(); + if (name_to_value_array != 'undefined') { + for (var the_key in name_to_value_array) + { + if(the_key == 'toJSON') + { + /* just ignore */ + } + else + { + query_array.push(the_key+'='+name_to_value_array[the_key]); + } + } + } + //construct the muulti select list + var selection_list; + if(popup_reply_data.selection_list) + { + selection_list = popup_reply_data.selection_list; + } + else + { + selection_list = popup_reply_data.name_to_value_array; + } + + if (selection_list != 'undefined') { + for (var the_key in selection_list) + { + query_array.push('subpanel_id[]='+selection_list[the_key]) + } + } + var module = get_module_name(); + var id = get_record_id(); + + query_array.push('value=DetailView'); + query_array.push('module='+module); //query_array.push('module='+module); + query_array.push('http_method=get'); + query_array.push('return_module='+module); + query_array.push('return_id='+id); + query_array.push('record='+id); + query_array.push('isDuplicate=false'); + query_array.push('return_type=addcampaignlog'); + query_array.push('action=Save2'); + query_array.push('inline=1'); + + var refresh_page = escape(passthru_data['refresh_page']); + for (prop in passthru_data) { + if (prop=='link_field_name') { + query_array.push('subpanel_field_name='+escape(passthru_data[prop])); + } else { + if (prop=='module_name') { + query_array.push('subpanel_module_name='+escape(passthru_data[prop])); + } else { + query_array.push(prop+'='+escape(passthru_data[prop])); + } + } + } + + var query_string = query_array.join('&'); + request_map[request_id] = passthru_data['child_field']; + var returnstuff = http_fetch_sync('index.php',query_string); + request_id++; + got_data(returnstuff, true); + if(refresh_page == 1){ + document.location.reload(true); + } +} + +function validatePortalName(e) { + var portalName = document.getElementById('portal_name'); + var portalNameExisting = document.getElementById("portal_name_existing"); + var portalNameVerified = document.getElementById('portal_name_verified'); + if(typeof(portalName.parentNode.lastChild) != 'undefined' && + portalName.parentNode.lastChild.tagName =='SPAN'){ + portalName.parentNode.lastChild.innerHTML = ''; + } + + if(portalName.value == portalNameExisting.value) { + return; + } + + var callbackFunction = function success(data) { + //data.responseText contains the count of portal_name that matches input field + count = data.responseText; + if(count != 0) { + add_error_style('EditView', 'portal_name', SUGAR.language.get('app_strings', 'ERR_EXISTING_PORTAL_USERNAME')); + for(wp = 1; wp <= 10; wp++) { + window.setTimeout('fade_error_style(style, ' + wp * 10 + ')', 1000 + (wp * 50)); + } + portalName.focus(); + } + + if(portalNameVerified.parentNode.childNodes.length > 1) { + portalNameVerified.parentNode.removeChild(portalNameVerified.parentNode.lastChild); + } + + verifiedTextNode = document.createElement('span'); + verifiedTextNode.innerHTML = ''; + portalNameVerified.parentNode.appendChild(verifiedTextNode); + + portalNameVerified.value = count == 0 ? "true" : "false"; + verifyingPortalName = false; + } + + if(portalNameVerified.parentNode.childNodes.length > 1) { + portalNameVerified.parentNode.removeChild(portalNameVerified.parentNode.lastChild); + } + + if(portalName.value != '' && !verifyingPortalName) { + document.getElementById('portal_name_verified').value = "false"; + verifiedTextNode = document.createElement('span'); + portalNameVerified.parentNode.appendChild(verifiedTextNode); + verifiedTextNode.innerHTML = SUGAR.language.get('app_strings', 'LBL_VERIFY_PORTAL_NAME'); + verifyingPortalName = true; + var cObj = YAHOO.util.Connect.asyncRequest('POST', 'index.php?module=Contacts&action=ValidPortalUsername&portal_name=' + portalName.value, {success: callbackFunction, failure: callbackFunction}); + } +} + +function handleKeyDown(e) { + if ((kc = e["keyCode"])) { + enterKeyPressed = (kc == 13) ? true : false; + if(enterKeyPressed) { + validatePortalName(e); + freezeEvent(e); + setTimeout(forceSubmit, 2100); + } + } +}//handleKeyDown() + +function freezeEvent(e) { + if (e.preventDefault) e.preventDefault(); + e.returnValue = false; + e.cancelBubble = true; + if (e.stopPropagation) e.stopPropagation(); + return false; +}//freezeEvent + +function forceSubmit() { + theForm = YAHOO.util.Dom.get('EditView'); + if(theForm) { + theForm.action.value = 'Save'; + + if(!check_form('EditView')) { + return false; + } + theForm.submit(); + } +} + +verifyingPortalName = false; +enterKeyPressed = false; \ No newline at end of file diff --git a/jssource/src_files/modules/Currencies/EditView.js b/jssource/src_files/modules/Currencies/EditView.js new file mode 100644 index 00000000..bf22fe8c --- /dev/null +++ b/jssource/src_files/modules/Currencies/EditView.js @@ -0,0 +1,55 @@ +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +function isoUpdate( formElem ) { + if ( typeof(js_iso4217[formElem.value]) == 'undefined' ) { + return false; + } + + var thisForm = formElem.form; + var thisCurr = js_iso4217[formElem.value]; + + if ( thisForm.name.value == '' ) { + thisForm.name.value = thisCurr.name; + } + if ( thisForm.symbol.value == '' ) { + thisForm.symbol.value = ''; + for ( var i = 0 ; i < thisCurr.unicode.length ; i++ ) { + thisForm.symbol.value = thisForm.symbol.value + String.fromCharCode(thisCurr.unicode[i]); + } + } + + return true; +} diff --git a/jssource/src_files/modules/Documents/documents.js b/jssource/src_files/modules/Documents/documents.js new file mode 100644 index 00000000..72282073 --- /dev/null +++ b/jssource/src_files/modules/Documents/documents.js @@ -0,0 +1,127 @@ +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + + + +var rhandle=new RevisionListHandler(); +var from_popup_return = false; +function document_set_return(popup_reply_data) +{ + from_popup_return = true; + var form_name = popup_reply_data.form_name; + var name_to_value_array = popup_reply_data.name_to_value_array; + related_doc_id='EMPTY'; + for (var the_key in name_to_value_array) + { + if(the_key == 'toJSON') + { + /* just ignore */ + } + else + { + var displayValue=name_to_value_array[the_key]; + displayValue=displayValue.replace(''',"'"); //restore escaped single quote. + displayValue=displayValue.replace( '&',"&"); //restore escaped &. + displayValue=displayValue.replace( '>',">"); //restore escaped >. + displayValue=displayValue.replace( '<',"<"); //restore escaped <. + displayValue=displayValue.replace( '" ',"\""); //restore escaped ". + if (the_key == 'related_doc_id') { + related_doc_id =displayValue; + } + window.document.forms[form_name].elements[the_key].value = displayValue; + } + } + related_doc_id=JSON.stringifyNoSecurity(related_doc_id); + //make request for document revisions data. + var conditions = new Array(); + conditions[conditions.length] = {"name":"document_id","op":"starts_with","value":related_doc_id}; + var query = new Array(); + var query = {"module":"DocumentRevisions","field_list":['id','revision','date_entered'],"conditions":conditions,"order":'date_entered desc'}; + + //make the call call synchronous for now... + //todo: convert to async, test on mozilla.. + result = global_rpcClient.call_method('query',query,true); + rhandle.display(result); + + //req_id = global_rpcClient.call_method('query',query); + //register the callback mathod. + //global_request_registry[req_id] = [rhandle, 'display']; +} + + +function RevisionListHandler() { } + +RevisionListHandler.prototype.display = function(result) { + var names = result['list']; + var rev_tag=document.getElementById('related_doc_rev_id'); + rev_tag.options.length=0; + + for(i=0; i < names.length; i++) { + rev_tag.options[i] = new Option(names[i].fields['revision'],names[i].fields['id'],false,false); + } + rev_tag.disabled=false; +} + + +function setvalue(source) { + + src = new String(source.value); + target=new String(source.form.document_name.value); + + if (target.length == 0) + { + lastindex=src.lastIndexOf("/"); + if (lastindex == -1) { + lastindex=src.lastIndexOf("\\"); + } + if (lastindex == -1) { + source.form.document_name.value=src; + } else { + source.form.document_name.value=src.substr(++lastindex, src.length); + } + } +} + +function toggle_template_type(istemplate) { + template_type = document.getElementById('template_type'); + if (istemplate.checked) { + //template_type.enabled=true; + template_type.disabled=false; + } else { + //template_type.enabled=false; + template_type.disabled=true; + } +} diff --git a/jssource/src_files/modules/EAPM/EAPMEdit.js b/jssource/src_files/modules/EAPM/EAPMEdit.js new file mode 100644 index 00000000..7194bae5 --- /dev/null +++ b/jssource/src_files/modules/EAPM/EAPMEdit.js @@ -0,0 +1,110 @@ +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + +/** + * Edit functions for EAPM + */ +function EAPMChange() { + var apiName = ''; + + if ( EAPMFormName == 'EditView' ) { + apiName = document.getElementById('application').value; + } else { + apiName = document.getElementById('application_raw').value; + } + if(SUGAR.eapm[apiName]){ + var apiOpts = SUGAR.eapm[apiName]; + + var urlObj = new SUGAR.forms.VisibilityAction('url',(apiOpts.needsUrl?'true':'false'), EAPMFormName); + if ( EAPMFormName == 'EditView' ) { + EAPMSetFieldRequired('url',(apiOpts.needsUrl == true)); + } + + var userObj = new SUGAR.forms.VisibilityAction('name',((apiOpts.authMethod=='password')?'true':'false'), EAPMFormName); + if ( EAPMFormName == 'EditView' ) { + EAPMSetFieldRequired('name',(apiOpts.authMethod == 'password')); + } + + var passObj = new SUGAR.forms.VisibilityAction('password',((apiOpts.authMethod=='password')?'true':'false'), EAPMFormName); + if ( EAPMFormName == 'EditView' ) { + EAPMSetFieldRequired('password',(apiOpts.authMethod == 'password')); + } + + urlObj.exec(); + userObj.exec(); + passObj.exec(); + + //hide/show new window notice + var messageDiv = document.getElementById('eapm_notice_div'); + if ( typeof messageDiv != 'undefined' && messageDiv != null ) { + if(apiOpts.authMethod){ + if(apiOpts.authMethod == "oauth"){ + messageDiv.innerHTML = EAPMOAuthNotice; + }else{ + messageDiv.innerHTML = EAPMBAsicAuthNotice; + } + }else{ + messageDiv.innerHTML = EAPMBAsicAuthNotice; + } + } + } +} + +function EAPMSetFieldRequired(fieldName, isRequired) { + var formname = 'EditView'; + for(var i = 0; i < validate[formname].length; i++){ + if(validate[formname][i][0] == fieldName){ + validate[formname][i][2] = isRequired; + } + } +} + +function EAPMEditStart(userIsAdmin) { + var apiElem = document.getElementById('application'); + + EAPM_url_validate = null; + EAPM_name_validate = null; + EAPM_password_validate = null; + + apiElem.onchange = EAPMChange; + + setTimeout(EAPMChange,100); + + if ( !userIsAdmin ) { + // Disable the assigned user picker for non-admins + document.getElementById('assigned_user_name').parentNode.innerHTML = document.getElementById('assigned_user_name').value; + } +} \ No newline at end of file diff --git a/jssource/src_files/modules/EmailTemplates/EmailTemplate.js b/jssource/src_files/modules/EmailTemplates/EmailTemplate.js new file mode 100644 index 00000000..1bcc1353 --- /dev/null +++ b/jssource/src_files/modules/EmailTemplates/EmailTemplate.js @@ -0,0 +1,189 @@ +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +var focus_obj = false; +var label = SUGAR.language.get('app_strings', 'LBL_DEFAULT_LINK_TEXT'); + +function remember_place(obj) { + focus_obj = obj; +} + +function showVariable() { + document.EditView.variable_text.value = + document.EditView.variable_name.options[document.EditView.variable_name.selectedIndex].value; +} + +function addVariables(the_select,the_module) { + the_select.options.length = 0; + for(var i=0;i]+>/gi, ''); + } +} +/* + * this function will insert variables into text area +*/ +function insert_variable_text(myField, myValue) { + //IE support + if (document.selection) { + myField.focus(); + sel = document.selection.createRange(); + sel.text = myValue; + } + //MOZILLA/NETSCAPE support + else if (myField.selectionStart || myField.selectionStart == '0') { + var startPos = myField.selectionStart; + var endPos = myField.selectionEnd; + myField.value = myField.value.substring(0, startPos) + + myValue + + myField.value.substring(endPos, myField.value.length); + } else { + myField.value += myValue; + } +} + +/* + * This function inserts variables into a TinyMCE instance + */ +function insert_variable_html(text) { + var inst = tinyMCE.getInstanceById("body_text"); + if (inst) + inst.getWin().focus(); + //var html = inst.getContent(true); + //inst.setContent(html + text); + inst.execCommand('mceInsertRawHTML', false, text); +} + +function insert_variable_html_link(text) { + + the_label = document.getElementById('url_text').value; + if(typeof(the_label) =='undefined'){ + the_label = label; + } + + //remove surounding parenthesis around the label + if(the_label[0] == '{' && the_label[the_label.length-1] == '}'){ + the_label = the_label.substring(1,the_label.length-1); + } + + var thelink = " "+the_label+" "; + insert_variable_html(thelink); +} +/* + * this function will check to see if text only flag has been checked. + * If so, the it will call the text insert function, if not, then it + * will call the html (tinyMCE eidtor) insert function +*/ +function insert_variable(text) { + //if text only flag is checked, then insert into text field + if(document.getElementById('toggle_textonly').checked == true){ + //use text version insert + insert_variable_text(document.getElementById('body_text_plain'), text) ; + }else{ + //use html version insert + insert_variable_html(text) ; + } +} + diff --git a/jssource/src_files/modules/Home/about.js b/jssource/src_files/modules/Home/about.js new file mode 100644 index 00000000..943f79cf --- /dev/null +++ b/jssource/src_files/modules/Home/about.js @@ -0,0 +1,65 @@ +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +var abouter = function(){ + return { + display:function(){ + abouter.div = document.getElementById('abouterdiv'); + abouter.div.style.display =''; + abouter.div.src = "index.php?module=Home&action=PopupSugar&to_pdf=true&style=" + abouter.style; + }, + ab:function(index, style){ + if(abouter.starter == 3){ + abouter.style = style; + abouter.display(); + }else{ + if(index == abouter.starter + 1){ + abouter.starter++; + }else{ + abouter.starter= 0; + } + } + + } + + + + } + + + +}(); +abouter.starter = 0; +abouter.style = 'inc'; diff --git a/jssource/src_files/modules/InboundEmail/InboundEmail.js b/jssource/src_files/modules/InboundEmail/InboundEmail.js new file mode 100644 index 00000000..8c19c989 --- /dev/null +++ b/jssource/src_files/modules/InboundEmail/InboundEmail.js @@ -0,0 +1,349 @@ +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + +SUGAR.inboundEmail = { }; + + +Rot13 = { + map: null, + + convert: function(a) { + Rot13.init(); + + var s = ""; + for (i=0; i < a.length; i++) { + var b = a.charAt(i); + s += ((b>='A' && b<='Z') || (b>='a' && b<='z') ? Rot13.map[b] : b); + } + return s; + }, + + init: function() { + if (Rot13.map != null) + return; + + var map = new Array(); + var s = "abcdefghijklmnopqrstuvwxyz"; + + for (i=0; i 0) { + fragment1 = word.substr(0, word.indexOf('&')); + fragment2 = word.substr(word.indexOf('&') + 1, word.length); + + newWord = fragment1 + '::amp::' + fragment2; + words[i] = newWord; + word = newWord; // setting it locally to pass on to next IF + fragment1 = ''; + fragment2 = ''; + } + if(word.indexOf('+') > 0) { + fragment1 = word.substr(0, word.indexOf('+')); + fragment2 = word.substr(word.indexOf('+') + 1, word.length); + + newWord = fragment1 + '::plus::' + fragment2; + words[i] = newWord; + word = newWord; // setting it locally to pass on to next IF + fragment1 = ''; + fragment2 = ''; + } + if(word.indexOf('%') > 0) { + fragment1 = word.substr(0, word.indexOf('%')); + fragment2 = word.substr(word.indexOf('%') + 1, word.length); + + newWord = fragment1 + '::percent::' + fragment2; + words[i] = newWord; + word = newWord; // setting it locally to pass on to next IF + fragment1 = ''; + fragment2 = ''; + } + } // for + + return words; +} // fn + +function ie_test_open_popup_with_submit(module_name, action, pageTarget, width, height, mail_server, protocol, port, login, password, mailbox, ssl, personal, formName) +{ + if (!formName) formName = "testSettingsView"; + var words = getEncryptedPassword(login, password, mailbox); + var isPersonal = (personal) ? 'true' : 'false'; + + if (!isDataValid(formName, true)) { + return; + } + + ie_id = (typeof document.getElementById(formName).ie_id != 'undefined') ? document.getElementById(formName).ie_id : ''; + + // launch the popup + URL = 'index.php?' + + 'module=' + module_name + + '&to_pdf=1' + + '&action=' + action + + '&target=' + pageTarget + + '&target1=' + pageTarget + + '&server_url=' + mail_server + + '&email_user=' + words[0] + + '&protocol=' + protocol + + '&port=' + port + + '&email_password=' + words[1] + + '&mailbox=' + words[2] + + '&ssl=' + ssl + + '&ie_id=' + ie_id + + '&personal=' + isPersonal; + + var SI = SUGAR.inboundEmail; + if (!SI.testDlg) { + SI.testDlg = new YAHOO.widget.SimpleDialog("testSettingsDiv", { + width: width + "px", + draggable: true, + dragOnly: true, + close: true, + constraintoviewport: true, + modal: true, + loadingText: SUGAR.language.get("app_strings", "LBL_EMAIL_LOADING") + }); + SI.testDlg._updateContent = function (o) { + var w = this.cfg.config.width.value + "px"; + this.setBody(o.responseText); + if (this.evalJS) + SUGAR.util.evalScript(o.responseText); + if (!SUGAR.isIE) + this.body.style.width = w + } + } + var title = SUGAR.language.get('Emails', 'LBL_TEST_SETTINGS'); + if (typeof(title) == "undefined" || title == "undefined") + title = SUGAR.language.get('InboundEmail', 'LBL_TEST_SETTINGS'); + SI.testDlg.setHeader(title); + SI.testDlg.setBody(SUGAR.language.get("app_strings", "LBL_EMAIL_LOADING")); + + SI.testDlg.render(document.body); + var Connect = YAHOO.util.Connect; + if (Connect.url) URL = Connect.url + "&" + url; + Connect.asyncRequest("GET", URL, {success:SI.testDlg._updateContent, failure:SI.testDlg.hide, scope:SI.testDlg}); + SI.testDlg.show(); + +} + +function isDataValid(formName, validateMonitoredFolder) { + var formObject = document.getElementById(formName); + var errors = new Array(); + var out = new String(); + + if(trim(formObject.server_url.value) == "") { + errors.push(SUGAR.language.get('app_strings', 'LBL_EMAIL_ERROR_SERVER')); + } + if(trim(formObject.email_user.value) == "") { + errors.push(SUGAR.language.get('app_strings', 'LBL_EMAIL_ERROR_USER')); + } + if(trim(formObject.email_password.value) == "" && trim(formObject.ie_id.value) == "") { + errors.push(SUGAR.language.get('app_strings', 'LBL_EMAIL_ERROR_PASSWORD')); + } + if(formObject.protocol.protocol == "") { + errors.push(SUGAR.language.get('app_strings', 'LBL_EMAIL_ERROR_PROTOCOL')); + } + if (formObject.protocol.value == 'imap' && validateMonitoredFolder) { + if (trim(formObject.mailbox.value) == "") { + errors.push(SUGAR.language.get('app_strings', 'LBL_EMAIL_ERROR_MONITORED_FOLDER')); + } // if + } + if(formObject.port.value == "") { + errors.push(SUGAR.language.get('app_strings', 'LBL_EMAIL_ERROR_PORT')); + } + + if(errors.length > 0) { + out = SUGAR.language.get('app_strings', 'LBL_EMAIL_ERROR_DESC'); + for(i=0; i'; + html += ''; + html += ''; + html += ''; + html += ''; + //var html = '
    '+GLOBAL_REGISTRY['meeting_strings']['LBL_EMAIL']+''+GLOBAL_REGISTRY['meeting_strings']['LBL_PHONE']+' 
    '; + for(var i=0;i'; + html += ''; + html += ''; + html += ''; + html += ''; + html += ''; + + html += ''; + } + html += '
    '+bean.fields.full_name+''+bean.fields.email1+''+bean.fields.phone_work+''; + // hidden = 'hidden'; + hidden = 'visible'; + if(!disabled) { + // hidden = 'visible'; + } + html += ''; + html += '
    '; + this.parentNode.innerHTML = html; +} + +SugarWidgetListView.prototype.display_loading = function() { + +} + +////////////////////////////////////////////////// +// class: SugarWidgetSchedulerSearch +// widget to display the meeting scheduler search box +// +////////////////////////////////////////////////// + +SugarClass.inherit("SugarWidgetSchedulerSearch","SugarClass"); + +function SugarWidgetSchedulerSearch() { + this.init(); +} + +SugarWidgetSchedulerSearch.prototype.init = function() { + this.form_id = 'scheduler_search'; + GLOBAL_REGISTRY['widget_element_map'] = new Object(); + GLOBAL_REGISTRY['widget_element_map'][this.form_id] = this; +} + +SugarWidgetSchedulerSearch.prototype.load = function(parentNode) { + this.parentNode = parentNode; + this.display(); +} + +SugarWidgetSchedulerSearch.submit = function(form) { + //construct query obj: + var conditions = new Array(); + + if(form.search_first_name.value != '') { + conditions[conditions.length] = {"name":"first_name","op":"starts_with","value":form.search_first_name.value} + } + if(form.search_last_name.value != '') { + conditions[conditions.length] = {"name":"last_name","op":"starts_with","value":form.search_last_name.value} + } + if(form.search_email.value != '') { + conditions[conditions.length] = {"name":"email1","op":"starts_with","value":form.search_email.value} + } + + var query = {"modules":["Users","Contacts" + ,"Leads" + ],"group":"and","field_list":['id','full_name','email1','phone_work'],"conditions":conditions}; + global_request_registry[req_count] = [this,'display']; + req_id = global_rpcClient.call_method('query',query); + global_request_registry[req_id] = [ GLOBAL_REGISTRY['widget_element_map'][form.id],'refresh_list']; +} + +SugarWidgetSchedulerSearch.prototype.refresh_list = function(rslt) { + GLOBAL_REGISTRY['result_list'] = rslt['list']; + this.list_view.display(); +} + +SugarWidgetSchedulerSearch.prototype.display = function() { + var html ='

    '+GLOBAL_REGISTRY['meeting_strings']['LBL_ADD_INVITEE']+'

    '; + html +=''; + html += '
    '; + html += '
    '; + + html += '' + html += ''; + //html += '
    '; + html += ''; + html += ''; + html += ''; + //html += '
    '+GLOBAL_REGISTRY['meeting_strings']['LBL_FIRST_NAME']+':  '+GLOBAL_REGISTRY['meeting_strings']['LBL_LAST_NAME']+':  '+GLOBAL_REGISTRY['meeting_strings']['LBL_EMAIL']+':  
    '; + html += '
    '; + html += ''; + html += '
     and  tags are now supported).
    +	- Bug item #2406022 "Left padding bug in MultiCell with maxh" was fixed.
    +	
    +4.4.000 (2008-12-07)
    +	- File attachments are now supported (see example n. 41).
    +	- Font functions were optimized to reduce document size.
    +	- makefont.php was updated.
    +	- Linux binaries were added on /fonts/utils
    +	- All fonts were updated.
    +	- $autopadding parameter was added to Multicell() to disable automatic padding features.
    +	- $maxh parameter was added to Multicell() and Write() to set a maximum height.
    +
    +4.3.009 (2008-12-05)
    +	- Bug item #2392989 (Custom header + setlinewidth + cell border bug) was fixed.
    +	
    +4.3.008 (2008-12-05)
    +	- Bug item #2390566 "rect bug" was fixed.
    +	- File path was fixed for font embedded files.
    +	- SetFont() method signature was changed to include the font filename.
    +	- Some font-related methods were improved.
    +	- Methods getFontFamily() and getFontStyle() were added.
    +	
    +4.3.007 (2008-12-03)
    +	- PNG alpha channel is now supported (GD library is required).
    +	- AddFont() function now support custom font file path on $file parameter.
    +	- The default width variable ($dw) is now always defined for any font.
    +	- The 'Style' attribute on CID-0 fonts was removed because of protection bug.
    +	
    +4.3.006 (2008-12-01)
    +	- A regular expression on getHtmlDomArray() to find HTML tags was fixed.
    +
    +4.3.005 (2008-11-25)
    +	- makefont.php was fixed.
    +	- Bug item #2339877 was fixed (false loop condition detected on WriteHTML()).
    +	- Bug item #2336733 was fixed (lasth value update on Multicell() when border and fill are disabled).
    +	- Bug item #2342303 was fixed (automatic page-break on Image() and ImageEPS()).
    +
    +4.3.004 (2008-11-19)
    +	- Function _textstring() was fixed (bug 2309051).
    +	- All examples were updated.
    +
    +4.3.003 (2008-11-18)
    +	- CID-0 font bug was fixed.
    +	- Some functions were optimized.
    +	- Function getGroupPageNoFormatted() was added.
    +	- Example n. 23 was updated.
    +
    +4.3.002 (2008-11-17)
    +	- Bug item #2305518 "CID-0 font don't work with encryption" was fixed.
    +	
    +4.3.001 (2008-11-17)
    +	- Bug item #2300007 "download mimetype pdf" was fixed.
    +	- Double quotes were replaced by single quotes to improve PHP performances.
    +	- A bug relative to HTML cell borders was fixed.
    +	
    +4.3.000 (2008-11-14)
    +	- The function setOpenCell() was added to set the top/bottom cell sides to be open or closed when the cell cross the page.
    +	- A bug relative to list items indentation was fixed.
    +	- A bug relative to borders on HTML tables and Multicell was fixed.
    +	- A bug relative to rowspanned cells was fixed.
    +	- A bug relative to html images across pages was fixed.
    +	
    +4.2.009 (2008-11-13)
    +	- Spaces between li tags are now automatically removed.
    +	
    +4.2.008 (2008-11-12)
    +	- A bug relative to fill color on next page was fixed.
    +	
    +4.2.007 (2008-11-12)
    +	- The function setListIndentWidth() was added to set custom indentation widht for HTML lists.
    +	
    +4.2.006 (2008-11-06)
    +	- A bug relative to HTML justification was fixed.
    +	
    +4.2.005 (2008-11-06)
    +	- A bug relative to HTML justification was fixed.
    +	- The methods formatPageNumber() and PageNoFormatted() were added to format page numbers.
    +	- Default Footer() method was changed to use PageNoFormatted() instead of PageNo().
    +	- Example 6 was updated.
    +	
    +4.2.004 (2008-11-04)
    +	- Bug item n. 2217039 "filename handling improvement" was fixed.
    +	
    +4.2.003 (2008-10-31)
    +	- Font style bug was fixed.
    +	
    +4.2.002 (2008-10-31)
    +	- Bug item #2210922 (htm element br not work) was fixed.
    +	- Write() function was improved to support margin changes.
    +	
    +4.2.001 (2008-10-30)
    +	- setHtmlVSpace($tagvs) function was added to set custom vertical spaces for HTML tags.
    +	- writeHTML() function now support margin changes during execution.
    +	- Signature of addHTMLVertSpace() function is changed.
    +	
    +4.2.000 (2008-10-29)
    +	- htmlcolors.php was changed to support class-loaders.
    +	- ImageEps() function was improved in performances.
    +	- Signature of Link() And Annotation() functions were changed.
    +	- (Bug item #2198926) Links and Annotations alignment were fixed (support for geometric tranformations was added).
    +	- rowspan mode for HTML table cells was improved and fixed.
    +	- Booklet mode for double-sided pages was added; see SetBooklet() function and example n. 40.
    +	- lastPage() signature is changed.
    +	- Signature of Write() function is changed.
    +	- Some HTML justification problems were fixed.
    +	- Some functions were fixed to better support RTL mode.
    +	- Example n. 10 was changed to support RTL mode.
    +	- All examples were updated.
    +	
    +4.1.004 (2008-10-23)
    +	- unicode_data.php was changed to support class-loaders.
    +	- Bug item #2186040/2 (writeHTML margin problem) was fixed.
    +	
    +4.1.003 (2008-10-22)
    +	- Bug item #2185399 was fixed (rowspan and page break).
    +	- Bugs item #2186040 was fixed (writeHTML margin problem).
    +	- Newline after table was removed.
    +	
    +4.1.002 (2008-10-21)
    +	- Bug item #2184525 was fixed (rowspan on HTML cell).
    +	
    +4.1.001 (2008-10-21)
    +	- Support for "start" attribute was added to HTML ordered list.
    +	- unicode_data.php file was changed to include UTF-8 to ASCII table.
    +	- Some functions were modified to better support UTF-8 extensions to core fonts.
    +	- Support for images on HTML lists was improved.
    +	- Examples n. 1 and 6 were updated.
    +	
    +4.1.000 (2008-10-18)
    +	- Page-break bug using HTML content was fixed.
    +	- The "false" parameter was reintroduced to class_exists function on PHP5 version to avoid autoload.
    +	- addHtmlLink() function was improved to support internal links (i.e.: link to page 23).
    +	- Justification alignment is now supported on HTML (see example n. 39).
    +	- example_006.php was updated.
    +	
    +4.0.033 (2008-10-13)
    +	- Bug n. 2157099 was fixed.
    +	- SetX() and SetY() functions were improved.
    +	- SetY() includes a new parameter to avoid the X reset.
    +
    +4.0.032 (2008-10-10)
    +	- Bug n. 2156926 was fixed (bold, italic, underlined, linethrough).
    +	- setStyle() method was removed.
    +	- Configuration file was changed to use helvetica (non-unicode) font by default.
    +	- The use of mixed font types was improved.
    +	- All examples were updated.
    +
    +4.0.031 (2008-10-09)
    +	- _putannots() and _putbookmarks() links alignments were fixed.
    +
    +4.0.030 (2008-10-07)
    +	- _putbookmarks() function was fixed.
    +	- _putannots() was fixed to include internal links.
    +
    +4.0.029 (2008-09-27)
    +	- Infinite loop bug was fixed [Bug item #130309].
    +	- Multicell() problem on Header() was fixed.
    +	
    +4.0.028 (2008-09-26)
    +	- setLIsymbol() was added to set the LI symbol used on UL lists.
    +	- Missing $padding and $encryption_key variables declarations were added [Bug item #2129058].
    +	
    +4.0.027 (2008-09-19)
    +	- Bug #2118588 "Undefined offset in tcpdf.php on line 9581" was fixed.
    +	- arailunicid0.php font was updated.
    +	- The problem of javascript form fields duplication after saving was fixed.
    +		
    +4.0.026 (2008-09-17)
    +	- convertHTMLColorToDec() function was improved to support rgb(RR,GG,BB) notation.
    +	- The following inline CSS attributes are now supported: text-decoration, color, background-color and font-size names: xx-small, x-small, small, medium, large, x-large, xx-large
    +	- Example n. 6 was updated.
    +		
    +4.0.025 (2008-09-15)
    +	- _putcidfont0 function was improved to include CJK fonts (Chinese, Japanese, Korean, CJK, Asian fonts) without embedding.
    +	- arialunicid0 font was added (see the new example n. 38).
    +	- The following Unicode to CID-0 tables were added on fonts folder: uni2cid_ak12.php, uni2cid_aj16.php, uni2cid_ag15.php, uni2cid_ac15.php. 
    +		
    +4.0.024 (2008-09-12)
    +	- "stripos" function was replaced with "strpos + strtolower" for backward compatibility with PHP4.
    +	- support for Spot Colors were added. Check the new example n. 37 and the following new functions:
    +		AddSpotColor()
    +		SetDrawSpotColor()
    +		SetFillSpotColor()
    +		SetTextSpotColor()
    +		_putspotcolors()
    +	- Bookmark() function was improved to fix wrong levels.
    +	- $lasth changes after header/footer calls were fixed.
    +	
    +4.0.023 (2008-09-05)
    +	- Some HTML related problems were fixed.
    +	- Image alignment on HTML was changed, now it always defaults to the normal mode (see example_006.php).
    +	
    +4.0.022 (2008-08-28)
    +	- Line height on HTML was fixed.
    +	- Image inside an HTML cell problem was fixed.
    +	- A new "zarbold" persian font was added.
    +	
    +4.0.021 (2008-08-24)
    +	- HTTP headers were fixed on Output function().
    +	- getAliasNbPages() and getPageGroupAlias() functions were changed to support non-unicode fonts on unicode documents.
    +	- Function Write() was fixed.
    +	- The problem of additional vertical spaces on HTML was fixed.
    +	- The problem of frame around HTML links was fixed.
    +
    +4.0.020 (2008-08-15)
    +	- "[2052259] WriteHTML  & " bug was fixed.
    +
    +4.0.019 (2008-08-13)
    +	- "Rowspan on first cell" bug was fixed.
    +
    +4.0.018 (2008-08-08)
    +	- Default cellpadding for HTML tables was fixed.
    +	- Annotation() function was added to support some PDF annotations (see example_036.php and section 8.4 of PDF reference 1.7).
    +	- HTML links are now correclty shifted during line alignments.
    +	- function getAliasNbPages() was added and Footer() was updated.
    +	- RowSpan mode for HTML tables was fixed.
    +	- Bugs item #2043610 "Multiple sizes vertical align wrong" was fixed.
    +	- ImageEPS() function was improved and RTL alignment was fixed (see example_032.php).
    +
    +4.0.017 (2008-08-05)
    +	- Missing CNZ and CEO style modes were added to Rect() function.
    +	- Fonts utils were updated to include support for OpenType fonts.
    +	- getLastH() function was added.
    +
    +4.0.016 (2008-07-30)
    +	- setPageMark() function was added. This function must be called after calling Image() function for a background image.
    +
    +4.0.015 (2008-07-29)
    +	- Some functions were changed to support different page formats (see example_028.php).
    +	- The signature of setPage() function is changed.
    +
    +4.0.014 (2008-07-29)
    +	- K_PATH_MAIN calculation on tcpdf_config.php was fixed.
    +	- HTML support for EPS/AI images was added (see example_006.php).
    +	- Bugs item #2030807 "Truncated text on multipage html fields" was fixed.
    +	- PDF header bug was fixed.
    +	- helvetica was added as default font family.
    +	- Stroke mode was fixed on Text function.
    +	- several minor bugs were fixed.
    +
    +4.0.013 (2008-07-27)
    +	- Bugs item #2027799 " Big spaces between lines after page break" was fixed.
    +	- K_PATH_MAIN calculation on tcpdf_config.php was changed.
    +	- Function setVisibility() was fixed to avoid the "Incorrect PDEObject type" error message.
    +
    +4.0.012 (2008-07-24)
    +	- Addpage(), Header() and Footer() functions were changed to simplify the implementation of external header/footer functions.
    +	- The following functions were added: 
    +			setHeader()
    +			setFooter()
    +			getImageRBX()
    +			getImageRBY()
    +			getCellHeightRatio()
    +			getHeaderFont()
    +			getFooterFont()
    +			getRTL()
    +			getBarcode()
    +			getHeaderData()
    +			getHeaderMargin()
    +			getFooterMargin()
    +	
    +4.0.011 (2008-07-23)
    +	- Font support was improved.
    +	- The folder /fonts/utils contains new utilities and instructions for embedd font files.
    +	- Documentation was updated.
    +
    +4.0.010 (2008-07-22)
    +	- HTML tables were fixed to work across pages.
    +	- Header() and Footer() functions were updated to preserve previous settings.
    +	- example_035.php was added.
    +
    +4.0.009 (2008-07-21)
    +	- UTF8StringToArray() function was fixed for non-unicode mode.
    +
    +4.0.008 (2008-07-21)
    +	- Barcodes alignment was fixed (see example_027.php).
    +	- unicode_data.php was updated.
    +	- Arabic shaping for "Zero-Width Non-Joiner" character (U+200C) was fixed.
    +
    +4.0.007 (2008-07-18)
    +	- str_split was replaced by preg_split for compatibility with PHP4 version.
    +	- Clipping mode was added to all graphic functions by using parameter $style = "CNZ" or "CEO" (see example_034.php).
    +
    +4.0.006 (2008-07-16)
    +	- HTML rowspan bug was fixed.
    +	- Line style for MultiCell() was fixed.
    +	- WriteHTML() function was improved.
    +	- CODE128C barcode was fixed (barcodes.php).
    +
    +4.0.005 (2008-07-11)
    +	- Bug [2015715] "PHP Error/Warning" was fixed.
    +
    +4.0.004 (2008-07-09)
    +	- HTML cell internal padding was fixed.
    +
    +4.0.003 (2008-07-08)
    +	- Removed URL encoding when F option is selected on Output() function.
    +	- fixed some minor bugs in html tables.
    +
    +4.0.002 (2008-07-07)
    +	- Bug [2000861] was still unfixed and has been fixed.
    +	
    +4.0.001 (2008-07-05)
    +	- Bug [2000861] was fixed.
    +
    +4.0.000 (2008-07-03)
    +	- THIS IS A MAIN RELEASE THAT INCLUDES SEVERAL NEW FEATURES AND BUGFIXES
    +	- Signature fo SetTextColor() and SetFillColor() functions was changed (parameter $storeprev was removed).
    +	- HTML support was completely rewritten and improved (see example 6).
    +	- Alignments parameters were fixed.
    +	- Functions GetArrStringWidth() and GetStringWidth() now include font parameters.
    +	- Fonts support was improved.
    +	- All core fonts were replaced and moved to fonts/ directory.
    +	- The following functions were added: getMargins(), getFontSize(), getFontSizePt().
    +	- File config/tcpdf_config_old.php was renamed tcpdf_config_alt.php and updated.
    +	- Multicell and WriteHTMLCell fill function was fixed.
    +	- Several minor bugs were fixed.
    +	- barcodes.php was updated.
    +	- All examples were updated.
    +	
    +------------------------------------------------------------
    +
    +3.1.001 (2008-06-13)
    +	- Bug [1992515] "K_PATH_FONTS default value wrong" was fixed.
    +	- Vera font was removed, DejaVu font and Free fonts were updated.
    +	- Image handling was improved.
    +	- All examples were updated.
    +	
    +3.1.000 (2008-06-11)
    +	- setPDFVersion() was added to change the default PDF version (currently 1.7).
    +	- setViewerPreferences() was added to control the way the document is to be presented on the screen or printed (see example 29).
    +	- SetDisplayMode() signature was changed (new options were added).
    +	- LinearGradient(), RadialGradient(), CoonsPatchMesh() functions were added to print various color gradients (see example 30).
    +	- PieSector() function was added to render render pie charts (see example 31).
    +	- ImageEps() was added to display EPS and AI images with limited support (see example 32).
    +	- writeBarcode() function is now depracated, a new write1DBarcode() function was added. The barcode directory was removed and a new barcodes.php file was added.
    +	- The new write1DBarcode() function support more barcodes and do not need the GD library (see example 027). All barcodes are directly written to PDF using graphic functions.
    +	- HTML lists were improved and could be nested (you may now represent trees).
    +	- AddFont() bug was fixed.
    +	- _putfonts() bug was fixed.
    +	- graphics functions were fixed.
    +	- unicode_data.php file was updated (fixed).
    +	- almohanad font was updated.
    +	- example 18 was updated (Farsi and Arabic languages).
    +	- source code cleanup.
    +	- All examples were updated and new examples were added.
    +	
    +3.0.015 (2008-06-06)
    +	- AddPage() function signature is changed to include page format.
    +	- example 28 was added to show page format changes.
    +	- setPageUnit() function was added to change the page units of measure.
    +	- setPageFormat() function was added to change the page format and orientation between pages.
    +	- setPageOrientation() function was added to change the page orientation.
    +	- Arabic font shaping was fixed for laa letter and square boxes (see the example 18).
    +
    +3.0.014 (2008-06-04)
    +	- Arabic font shaping was fixed.
    +	- setDefaultTableColumns() function was added.
    +	- $cell_height_ratio variable was added.
    +	- setCellHeightRatio() function was added to define the default height of cell repect font height.
    +
    +3.0.013 (2008-06-03)
    +	- Multicell height parameter was fixed.
    +	- Arabic font shaping was improved.
    +	- unicode_data.php was updated.
    +
    +3.0.012 (2008-05-30)
    +	- K_PATH_MAIN and K_PATH_URL constants are now automatically set on config file.
    +	- DOCUMENT_ROOT constant was fixed for IIS Webserver (config file was updated).
    +	- Arabic font shaping was improved.
    +	- TranslateY() function was fixed (bug [1977962]).
    +	- setVisibility() function was fixed.
    +	- writeBarcode() function was fixed to scale using $xref parameter.
    +	- All examples were updated.
    +
    +3.0.011 (2008-05-23)
    +	- CMYK color support was added to all graphic functions.
    +	- HTML table support was improved: 
    +	  -- now it's possible to include additional html tags inside a cell;
    +	  -- colspan attribute was added.
    +	- example 006 was updated.
    +
    +3.0.010 (2008-05-21)
    +	- fixed $laa_array inclusion on utf8Bidi() function.
    +
    +3.0.009 (2008-05-20)
    +	- unicode_data.php was updated.
    +	- Arabic laa letter problem was fixed.
    +
    +3.0.008 (2008-05-12)
    +	- Arabic support was fixed and improved (unicode_data.php was updated).
    +	- Polycurve() function was added to draw a poly-Bezier curve.
    +	- list items alignment was fixed.
    +	- example 6 was updated.
    +
    +3.0.007 (2008-05-06)
    +	- Arabic support was fixed and improved.
    +	- AlMohanad (arabic) font was added.
    +	- C128 barcode bugs were fixed.
    +	
    +3.0.006 (2008-04-21)
    +	- Condition to check negative width values was added.
    +
    +3.0.005 (2008-04-18)
    +	- back-Slash character escape was fixed on writeHTML() function.
    +	- Exampe 6 was updated.
    +
    +3.0.004 (2008-04-11)
    +	- Bug [1939304] (Right to Left Issue) was fixed.
    +
    +3.0.003 (2008-04-07)
    +	- Bug [1934523](Words between HTML tags in cell not kept on one line) was fixed.
    +	- "face" attribute of "font" tag is now fully supported.
    +
    +3.0.002 (2008-04-01)
    +	- Write() functions now return the number of cells and not the number of lines.
    +	- TCPDF is released under LGPL 2.1, or any later version.
    +	
    +3.0.001 (2008-05-28)
    +	- _legacyparsejpeg() and _legacyparsepng() were renamed _parsejpeg() and _parsepng().
    +	- function writeBarcode() was fixed.
    +	- all examples were updated.
    +	- example 27 was added to show various barcodes.
    +	
    +3.0.000 (2008-03-27)
    +	- private function pixelsToMillimeters() was changed to public function pixelsToUnits() to fix html image size bug.
    +	- Image-related functions were rewritten.
    +	- resize parameter was added to Image() signature to reduce the image size and fit width and height (see example 9).
    +	- TCPDF now supports all images supported by GD library: GD, GD2, GD2PART, GIF, JPEG, PNG, BMP, XBM, XPM.
    +	- CMYK support was added to SetDrawColor(), SetFillColor(), SetTextColor() (see example 22).
    +	- Page Groups were added (see example 23).
    +	- setVisibility() function was added to restrict the rendering of some elements to screen or printout (see example 24).
    +	- All private variables and functions were changed to protected.
    +	- setAlpha() function was added to give transparency support for all objects (see example 25).
    +	- Clipping and stroke modes were added to Text() function (see example 26).
    +	- All examples were moved to "examples" directory.
    +	- function setJPEGQuality() was added to set the JPEG image comrpession (see example 9).
    +
    +2.9.000 (2008-03-26)
    +	- htmlcolors.php file was added to include html colors.
    +	- Support for HTML color names and three-digit hexadecimal color codes was added.
    +	- private function convertColorHexToDec() was renamed convertHTMLColorToDec().
    +	- color and bgcolor attributes are now supported on all HTML tags (color nesting is also supported).
    +	- Write() function were fixed.
    +	- example_006.php was updated.
    +	- private function setUserRights() was added to release user rights on Acrobat Reader (this allows to display forms, see example 14)
    +	
    +2.8.000 (2008-03-20)
    +	- Private variables were changed to protected.
    +	- Function Write() was fixed and improved.
    +	- Support for dl, dt, dd, del HTML tags was introduced.
    +	- Line-trought mode was added for HTML and text.
    +	- Text vertical alignment on cells were fixed.
    +	- Examples were updated to reflect changes.
    +		
    +2.7.002 (2008-03-13)
    +	- Bug "[1912142] Encrypted PDF created/modified date" was fixed.
    +	
    +2.7.001 (2008-03-10)
    +	- Cell justification was fixed for non-unicode mode.
    +
    +2.7.000 (2008-03-09)
    +	- Cell() stretching mode 4 (forced character spacing) was fixed.
    +	- writeHTMLCell() now uses Multicell() to write.
    +	- Multicell() has a new parameter $ishtml to act as writeHTMLCell().
    +	- Write() speed was improved for non-arabic strings.
    +	- Example n. 20 was changed.
    +	
    +2.6.000 (2008-03-07)
    +	- various alignments bugs were fixed.
    +	
    +2.5.000 (2008-03-07)
    +	- Several bugs were fixed.
    +	- example_019.php was added to test non-unicode mode using old fonts.
    +
    +2.4.000 (2008-03-06)
    +	- RTL support was deeply improved.
    +	- GetStringWidth() was fixed to support RTL languages.
    +	- Text() RTL alignment was fixed.
    +	- Some functions were added: GetArrStringWidth(), GetCharWidth(), uniord(), utf8Bidi().
    +	- example_018.php was added and test_unicode.php was removed.
    +
    +2.3.000 (2008-03-05)
    +	- MultiCell() signature is changed. Now support multiple columns across pages (see example_017).
    +	- Write() signature is changed. Now support the cell mode to be used with MultiCell.
    +	- Header() and Footer() were changed.
    +	- The following functions were added: UTF8ArrSubString() and unichr().
    +	- Examples were updated to reflect last changes.
    +
    +2.2.004 (2008-03-04)
    +	- Several examples were added.
    +	- AddPage() Header() and Footer() were fixed.
    +	- Documentation is now available on http://www.tcpdf.org
    +	
    +2.2.003 (2008-03-03)
    +	- [1894853] Performance of MultiCell() was improved.
    +	- RadioButton and ListBox functions were added.
    +	- javascript form functions were rewritten and properties names are changed. The properties function supported by form fields are listed on Possible values are listed on http://www.adobe.com/devnet/acrobat/pdfs/js_developer_guide.pdf.
    +	
    +2.2.002 (2008-02-28)
    +	- [1900495] html images path was fixed.
    +	- Legacy image functions were reintroduced to allow PNG and JPEG support without GD library.
    +
    +2.2.001 (2008-02-16)
    +	- The bug "[1894700] bug with replace relative path" was fixed
    +	- Justification was fixed
    +	
    +2.2.000 (2008-02-12)
    +	- fixed javascript bug introduced with latest release
    +
    +2.1.002 (2008-02-12)
    +	- Justify function was fixed on PHP4 version.
    +	- Bookmank function was added ([1578250] Table of contents).
    +	- Javascript and Form fields support was added ([1796359] Form fields).
    +	
    +2.1.001 (2008-02-10)
    +	- The bug "[1885776] Race Condition in function justitfy" was fixed.
    +	- The bug "[1890217] xpdf complains that pdf is incorrect" was fixed.	
    +
    +2.1.000 (2008-01-07)
    +	- FPDF_FONTPATH constant was changed to K_PATH_FONTS on config file
    +	- Bidirectional Algorithm to correctly reverse bidirectional languages was added.
    +	- SetLeftMargin, SetTopMargin, SetRightMargin functions were fixed.
    +	- SetCellPadding function was added.
    +	- writeHTML was updated with new parameters.
    +	- Text function was fixed.
    +	- MultiCell function was fixed, now works also across multiple pages.
    +	- Line width was fixed on Header and Footer functions and 
    tag. + - "GetImageSize" was renamed "getimagesize". + - Document version was changed from 1.3 to 1.5. + - _begindoc() function was fixed. + - ChangeDate was fixed and ModDate was added. + - The following functions were added: + setPage() : Move pointer to the specified document page. + getPage() : Get current document page number. + lastpage() : Reset pointer to the last document page. + getNumPages() : Get the total number of inserted pages. + GetNumChars() : count the number of (UTF-8) characters in a string. + - $stretch parameter was added to Cell() function to fit text on cell: + 0 = disabled + 1 = horizontal scaling only if necessary + 2 = forced horizontal scaling + 3 = character spacing only if necessary + 4 = forced character spacing + - Line function was fixed for RTL. + - Graphic transformation functions were added [1811158]: + StartTransform() + StopTransform() + ScaleX() + ScaleY() + ScaleXY() + Scale() + MirrorH() + MirrorV() + MirrorP() + MirrorL() + TranslateX() + TranslateY() + Translate() + Rotate() + SkewX() + SkewY() + Skew() + - Graphic function were added/updated [1688549]: + SetLineStyle() + _outPoint() + _outLine() + _outRect() + _outCurve() + Line() + Rect() + Curve + Ellipse + Circle + Polygon + RegularPolygon + +2.0.000 (2008-01-04) + - RTL (Right-To-Left) languages support was added. Language direction is set using the $l['a_meta_dir'] setting on /configure/language/xxx.php language files. + - setRTL($enable) method was added to manually enable/disable the RTL text direction. + - The attribute "dir" was added to support custom text direction on HTML tags. Possible values are: ltr - for Left-To-Right and RTL for Right-To-Left. + - RC4 40bit encryption was added. Check the SetProtection method. + - [1815213] Improved image support for GIF, JPEG, PNG formats. + - [1800094] Attribute "value" was added to ordered list items
  • . + - Image function now has a new "align" parameter that indicates the alignment of the pointer next to image insertion and relative to image height. The value can be: + T: top-right for LTR or top-left for RTL + M: middle-right for LTR or middle-left for RTL + B: bottom-right for LTR or bottom-left for RTL + N: next line + - Attribute "align" was added to html tag to set the above image "align" parameter. Possible values are: + top: top-right for LTR or top-left for RTL + middle: middle-right for LTR or middle-left for RTL + bottom: bottom-right for LTR or bottom-left for RTL + - [1798103] newline was added after , and

    tages. + - [1816393] Documentation was updated. + - 'ln' parameter was fixed on writeHTMLCell. Now it's possible to print two or more columns across several pages; + - The method lastPage() was added to move the pointer on the last page; + +------------------------------------------------------------ + +1.53.0.TC034 (2007-07-30) + - fixed htmlentities conversion. + - MultiCell() function returns the number of cells. + +1.53.0.TC033 (2007-07-30) + - fixed bug 1762550: case sensitive for font files + - NOTE: all fonts files names must be in lowercase! + +1.53.0.TC032 (2007-07-27) + - setLastH method was added to resolve bug 1689071. + - all fonts names were converted in lowercase (bug 1713005). + - bug 1740954 was fixed. + - justification was added as Cell option. + +1.53.0.TC031 (2007-03-20) + - ToUnicode CMap were added on _puttruetypeunicode function. Now you may search and copy unicode text. + +1.53.0.TC030 (2007-03-06) + - fixed bug on PHP4 version. + +1.53.0.TC029 (2007-03-06) + - DejaVu Fonts were added. + +1.53.0.TC028 (2007-03-03) + - MultiCell function signature were changed: the $ln parameter were added. Check documentation for further information. + - Greek language were added on example sentences. + - setPrintHeader() and setPrintFooter() functions were added to enable or disable page header and footer. + +1.53.0.TC027 (2006-12-14) + - $attr['face'] bug were fixed. + - K_TCPDF_EXTERNAL_CONFIG control where introduced on /config/tcpdf_config.php to use external configuration files. + +1.53.0.TC026 (2006-10-28) + - writeHTML function call were fixed on examples. + +1.53.0.TC025 (2006-10-27) + - Bugs item #1421290 were fixed (0D - 0A substitution in some characters) + - Bugs item #1573174 were fixed (MultiCell documentation) + +1.53.0.TC024 (2006-09-26) + - getPageHeight() function were fixed (bug 1543476). + - fixed missing breaks on closedHTMLTagHandler function (bug 1535263). + - fixed extra spaces on Write function (bug 1535262). + +1.53.0.TC023 (2006-08-04) + - paths to barcode directory were fixed. + - documentation were updated. + +1.53.0.TC022 (2006-07-16) + - fixed bug: [ 1516858 ] Probs with PHP autoloader and class_exists() + +1.53.0.TC021 (2006-07-01) + - HTML attributes with whitespaces are now supported (thanks to Nelson Benitez for his support) + +1.53.0.TC020 (2006-06-23) + - code cleanup + +1.53.0.TC019 (2006-05-21) + - fixed and closing tags + +1.53.0.TC018 (2006-05-18) + - fixed font names bug + +1.53.0.TC017 (2006-05-18) + - the TTF2UFM utility to convert True Type fonts for TCPDF were included on fonts folder. + - new free unicode fonts were included on /fonts/freefont. + - test_unicode.php example were exended. + - parameter $fill were added on Write, writeHTML and writeHTMLCell functions. + - documentation were updated. + +1.53.0.TC016 (2006-03-09) + - fixed closing tag on html parser. + +1.53.0.TC016 (2005-08-28) + - fpdf.php and tcpdf.php files were joined in one single class (you can still extend TCPDF with your own class). + - fixed problem when mb_internal_encoding is set. + +1.53.0.TC014 (2005-05-29) + - fixed WriteHTMLCell new page issue. + +1.53.0.TC013 (2005-05-29) + - fixed WriteHTMLCell across pages. + +1.53.0.TC012 (2005-05-29) + - font color attribute bug were fixed. + +1.53.0.TC011 (2005-03-31) + - SetFont function were fixed (thank Sjaak Lauwers for bug notice). + +1.53.0.TC010 (2005-03-22) + - the html functions were improved (thanks to Manfred Vervuert for bug reporting). + +1.53.0.TC009 (2005-03-19) + - a wrong reference to convertColorHexToDec were fixed. + +1.53.0.TC008 (2005-02-07) + - removed some extra bytes from PHP files. + +1.53.0.TC007 (2005-01-08) + - fill attribute were removed from writeHTMLCell method. + +1.53.0.TC006 (2005-01-08) + - the documentation were updated. + +1.53.0.TC005 (2005-01-05) + - Steven Wittens's unicode methods were removed. + - All unicode methods were rewritten from scratch. + - TCPDF is now licensed as LGPL. + +1.53.0.TC004 (2005-01-04) + - this changelog were added. + - removed commercial fonts for licensing issue. + - Bitstream Vera Fonts were added (http://www.bitstream.com/font_rendering/products/dev_fonts/vera.html). + - Now the AddFont and SetFont functions returns the basic font if the styled version do not exist. + diff --git a/include/tcpdf/LICENSE.TXT b/include/tcpdf/LICENSE.TXT new file mode 100644 index 00000000..b1e3f5a2 --- /dev/null +++ b/include/tcpdf/LICENSE.TXT @@ -0,0 +1,504 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 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. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +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 and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, 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 library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete 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 distribute a copy of this License along with the +Library. + + 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 Library or any portion +of it, thus forming a work based on the Library, 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) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +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 Library, 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 Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you 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. + + If distribution of 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 satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be 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. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library 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. + + 9. 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 Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +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 with +this License. + + 11. 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 Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library 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 Library. + +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. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library 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. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser 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 Library +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 Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +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 + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "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 +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. 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 LIBRARY 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 +LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), 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 Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. 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 library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License 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. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; 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. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + diff --git a/include/tcpdf/README.TXT b/include/tcpdf/README.TXT new file mode 100644 index 00000000..f1904ea2 --- /dev/null +++ b/include/tcpdf/README.TXT @@ -0,0 +1,86 @@ +TCPDF - README +============================================================ + +IF YOU'D LIKE TO SUPPORT TCPDF, PLEASE CONSIDER MAKING A +DONATION: +http://sourceforge.net/donate/index.php?group_id=128076 + +------------------------------------------------------------ + +Name: TCPDF +Version: 4.6.013 +Release date: 2009-05-28 +Author: Nicola Asuni + +Copyright (c) 2001-2009: + Nicola Asuni + Tecnick.com s.r.l. + Via Della Pace, 11 + 09044 Quartucciu (CA) + ITALY + www.tecnick.com + +URLs: + http://www.tcpdf.org + http://www.sourceforge.net/projects/tcpdf + +Description: + TCPDF is a PHP class for generating PDF files on-the-fly without requiring external extensions. + TCPDF has been originally derived from the Public Domain FPDF class by Olivier Plathey (http://www.fpdf.org). + +Main Features: +// * no external libraries are required for the basic functions; +// * supports all ISO page formats; +// * supports custom page formats, margins and units of measure; +// * supports UTF-8 Unicode and Right-To-Left languages; +// * supports TrueTypeUnicode, OpenTypeUnicode, TrueType, OpenType, Type1 and CID-0 fonts; +// * supports document encryption; +// * includes methods to publish some XHTML code; +// * includes graphic (geometric) and transformation methods; +// * includes Javascript and forms support; +// * includes a method to print various barcode formats: CODE 39, ANSI MH10.8M-1983, USD-3, 3 of 9, CODE 93, USS-93, Standard 2 of 5, Interleaved 2 of 5, CODE 128 A/B/C, 2 and 5 Digits UPC-Based Extention, EAN 8, EAN 13, UPC-A, UPC-E, MSI, POSTNET, PLANET, RMS4CC (Royal Mail 4-state Customer Code), CBC (Customer Bar Code), KIX (Klant index - Customer index), Intelligent Mail Barcode, Onecode, USPS-B-3200, CODABAR, CODE 11, PHARMACODE, PHARMACODE TWO-TRACKS; +// * includes methods to set Bookmarks and print a Table of Content; +// * includes methods to move and delete pages; +// * includes methods for automatic page header and footer management; +// * supports automatic page break; +// * supports automatic page numbering and page groups; +// * supports automatic line break and text justification; +// * supports JPEG and PNG images natively, all images supported by GD (GD, GD2, GD2PART, GIF, JPEG, PNG, BMP, XBM, XPM) and all images supported via ImagMagick (http://www.imagemagick.org/www/formats.html) +// * supports stroke and clipping mode for text; +// * supports clipping masks; +// * supports Grayscale, RGB, CMYK, Spot Colors and Transparencies; +// * supports several annotations, including links, text and file attachments; +// * supports page compression (requires zlib extension); +// * supports text hyphenation. +// * supports transactions to UNDO commands. + +Installation (full instructions on http://www.tcpdf.org): + 1. copy the folder on your Web server + 2. set your installation path and other parameters on the config/tcpdf_config.php + 3. call the example/example_001.php page with your browser to see an example + +Source Code Documentation: + doc/index.html + +For Additional Documentation: + http://www.tcpdf.org + +License + Copyright (C) 2002-2009 Nicola Asuni - Tecnick.com S.r.l. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see . + + See LICENSE.TXT file for more information. + +============================================================ diff --git a/include/tcpdf/barcodes.php b/include/tcpdf/barcodes.php new file mode 100644 index 00000000..6f449d87 --- /dev/null +++ b/include/tcpdf/barcodes.php @@ -0,0 +1,1999 @@ +. +// +// See LICENSE.TXT file for more information. +// ---------------------------------------------------------------------------- +// +// Description : PHP class to creates array representations for +// common 1D barcodes to be used with TCPDF. +// +// Author: Nicola Asuni +// +// (c) Copyright: +// Nicola Asuni +// Tecnick.com S.r.l. +// Via della Pace, 11 +// 09044 Quartucciu (CA) +// ITALY +// www.tecnick.com +// info@tecnick.com +//============================================================+ + +/** + * PHP class to creates array representations for common 1D barcodes to be used with TCPDF. + * @package com.tecnick.tcpdf + * @abstract Functions for generating string representation of common 1D barcodes. + * @author Nicola Asuni + * @copyright 2008-2009 Nicola Asuni - Tecnick.com S.r.l (www.tecnick.com) Via Della Pace, 11 - 09044 - Quartucciu (CA) - ITALY - www.tecnick.com - info@tecnick.com + * @link http://www.tcpdf.org + * @license http://www.gnu.org/copyleft/lesser.html LGPL + * @version 1.0.008 + */ + + /** + * PHP class to creates array representations for common 1D barcodes to be used with TCPDF (http://www.tcpdf.org).
    + * @name TCPDFBarcode + * @package com.tecnick.tcpdf + * @version 1.0.008 + * @author Nicola Asuni + * @link http://www.tcpdf.org + * @license http://www.gnu.org/copyleft/lesser.html LGPL + */ +class TCPDFBarcode { + + /** + * @var array representation of barcode. + * @access protected + */ + protected $barcode_array; + + /** + * This is the class constructor. + * Return an array representations for common 1D barcodes:
      + *
    • $arrcode['code'] code to be printed on text label
    • + *
    • $arrcode['maxh'] max bar height
    • + *
    • $arrcode['maxw'] max bar width
    • + *
    • $arrcode['bcode'][$k] single bar or space in $k position
    • + *
    • $arrcode['bcode'][$k]['t'] bar type: true = bar, false = space.
    • + *
    • $arrcode['bcode'][$k]['w'] bar width in units.
    • + *
    • $arrcode['bcode'][$k]['h'] bar height in units.
    • + *
    • $arrcode['bcode'][$k]['p'] bar top position (0 = top, 1 = middle)
    + * @param string $code code to print + * @param string $type type of barcode:
    • C39 : CODE 39 - ANSI MH10.8M-1983 - USD-3 - 3 of 9.
    • C39+ : CODE 39 with checksum
    • C39E : CODE 39 EXTENDED
    • C39E+ : CODE 39 EXTENDED + CHECKSUM
    • C93 : CODE 93 - USS-93
    • S25 : Standard 2 of 5
    • S25+ : Standard 2 of 5 + CHECKSUM
    • I25 : Interleaved 2 of 5
    • I25+ : Interleaved 2 of 5 + CHECKSUM
    • C128A : CODE 128 A
    • C128B : CODE 128 B
    • C128C : CODE 128 C
    • EAN2 : 2-Digits UPC-Based Extention
    • EAN5 : 5-Digits UPC-Based Extention
    • EAN8 : EAN 8
    • EAN13 : EAN 13
    • UPCA : UPC-A
    • UPCE : UPC-E
    • MSI : MSI (Variation of Plessey code)
    • MSI+ : MSI + CHECKSUM (modulo 11)
    • POSTNET : POSTNET
    • PLANET : PLANET
    • RMS4CC : RMS4CC (Royal Mail 4-state Customer Code) - CBC (Customer Bar Code)
    • KIX : KIX (Klant index - Customer index)
    • IMB: Intelligent Mail Barcode - Onecode - USPS-B-3200
    • CODABAR : CODABAR
    • CODE11 : CODE 11
    • PHARMA : PHARMACODE
    • PHARMA2T : PHARMACODE TWO-TRACKS
    + */ + public function __construct($code, $type) { + $this->setBarcode($code, $type); + } + + /** + * Return an array representations of barcode. + * @return array + */ + public function getBarcodeArray() { + return $this->barcode_array; + } + + /** + * Set the barcode. + * @param string $code code to print + * @param string $type type of barcode:
    • C39 : CODE 39 - ANSI MH10.8M-1983 - USD-3 - 3 of 9.
    • C39+ : CODE 39 with checksum
    • C39E : CODE 39 EXTENDED
    • C39E+ : CODE 39 EXTENDED + CHECKSUM
    • C93 : CODE 93 - USS-93
    • S25 : Standard 2 of 5
    • S25+ : Standard 2 of 5 + CHECKSUM
    • I25 : Interleaved 2 of 5
    • I25+ : Interleaved 2 of 5 + CHECKSUM
    • C128A : CODE 128 A
    • C128B : CODE 128 B
    • C128C : CODE 128 C
    • EAN2 : 2-Digits UPC-Based Extention
    • EAN5 : 5-Digits UPC-Based Extention
    • EAN8 : EAN 8
    • EAN13 : EAN 13
    • UPCA : UPC-A
    • UPCE : UPC-E
    • MSI : MSI (Variation of Plessey code)
    • MSI+ : MSI + CHECKSUM (modulo 11)
    • POSTNET : POSTNET
    • PLANET : PLANET
    • RMS4CC : RMS4CC (Royal Mail 4-state Customer Code) - CBC (Customer Bar Code)
    • KIX : KIX (Klant index - Customer index)
    • IMB: Intelligent Mail Barcode - Onecode - USPS-B-3200
    • CODABAR : CODABAR
    • CODE11 : CODE 11
    • PHARMA : PHARMACODE
    • PHARMA2T : PHARMACODE TWO-TRACKS
    + * @return array + */ + public function setBarcode($code, $type) { + switch (strtoupper($type)) { + case 'C39': { // CODE 39 - ANSI MH10.8M-1983 - USD-3 - 3 of 9. + $arrcode = $this->barcode_code39($code, false, false); + break; + } + case 'C39+': { // CODE 39 with checksum + $arrcode = $this->barcode_code39($code, false, true); + break; + } + case 'C39E': { // CODE 39 EXTENDED + $arrcode = $this->barcode_code39($code, true, false); + break; + } + case 'C39E+': { // CODE 39 EXTENDED + CHECKSUM + $arrcode = $this->barcode_code39($code, true, true); + break; + } + case 'C93': { // CODE 93 - USS-93 + $arrcode = $this->barcode_code93($code); + break; + } + case 'S25': { // Standard 2 of 5 + $arrcode = $this->barcode_s25($code, false); + break; + } + case 'S25+': { // Standard 2 of 5 + CHECKSUM + $arrcode = $this->barcode_s25($code, true); + break; + } + case 'I25': { // Interleaved 2 of 5 + $arrcode = $this->barcode_i25($code, false); + break; + } + case 'I25+': { // Interleaved 2 of 5 + CHECKSUM + $arrcode = $this->barcode_i25($code, true); + break; + } + case 'C128A': { // CODE 128 A + $arrcode = $this->barcode_c128($code, 'A'); + break; + } + case 'C128B': { // CODE 128 B + $arrcode = $this->barcode_c128($code, 'B'); + break; + } + case 'C128C': { // CODE 128 C + $arrcode = $this->barcode_c128($code, 'C'); + break; + } + case 'EAN2': { // 2-Digits UPC-Based Extention + $arrcode = $this->barcode_eanext($code, 2); + break; + } + case 'EAN5': { // 5-Digits UPC-Based Extention + $arrcode = $this->barcode_eanext($code, 5); + break; + } + case 'EAN8': { // EAN 8 + $arrcode = $this->barcode_eanupc($code, 8); + break; + } + case 'EAN13': { // EAN 13 + $arrcode = $this->barcode_eanupc($code, 13); + break; + } + case 'UPCA': { // UPC-A + $arrcode = $this->barcode_eanupc($code, 12); + break; + } + case 'UPCE': { // UPC-E + $arrcode = $this->barcode_eanupc($code, 6); + break; + } + case 'MSI': { // MSI (Variation of Plessey code) + $arrcode = $this->barcode_msi($code, false); + break; + } + case 'MSI+': { // MSI + CHECKSUM (modulo 11) + $arrcode = $this->barcode_msi($code, true); + break; + } + case 'POSTNET': { // POSTNET + $arrcode = $this->barcode_postnet($code, false); + break; + } + case 'PLANET': { // PLANET + $arrcode = $this->barcode_postnet($code, true); + break; + } + case 'RMS4CC': { // RMS4CC (Royal Mail 4-state Customer Code) - CBC (Customer Bar Code) + $arrcode = $this->barcode_rms4cc($code, false); + break; + } + case 'KIX': { // KIX (Klant index - Customer index) + $arrcode = $this->barcode_rms4cc($code, true); + break; + } + case 'IMB': { // IMB - Intelligent Mail Barcode - Onecode - USPS-B-3200 + $arrcode = $this->barcode_imb($code); + break; + } + case 'CODABAR': { // CODABAR + $arrcode = $this->barcode_codabar($code); + break; + } + case 'CODE11': { // CODE 11 + $arrcode = $this->barcode_code11($code); + break; + } + case 'PHARMA': { // PHARMACODE + $arrcode = $this->barcode_pharmacode($code); + break; + } + case 'PHARMA2T': { // PHARMACODE TWO-TRACKS + $arrcode = $this->barcode_pharmacode2t($code); + break; + } + default: { + $this->barcode_array = false; + } + } + $this->barcode_array = $arrcode; + } + + /** + * CODE 39 - ANSI MH10.8M-1983 - USD-3 - 3 of 9. + * General-purpose code in very wide use world-wide + * @param string $code code to represent. + * @param boolean $checksum if true add a checksum to the code + * @return array barcode representation. + * @access protected + */ + protected function barcode_code39($code, $extended=false, $checksum=false) { + $chr['0'] = '111221211'; + $chr['1'] = '211211112'; + $chr['2'] = '112211112'; + $chr['3'] = '212211111'; + $chr['4'] = '111221112'; + $chr['5'] = '211221111'; + $chr['6'] = '112221111'; + $chr['7'] = '111211212'; + $chr['8'] = '211211211'; + $chr['9'] = '112211211'; + $chr['A'] = '211112112'; + $chr['B'] = '112112112'; + $chr['C'] = '212112111'; + $chr['D'] = '111122112'; + $chr['E'] = '211122111'; + $chr['F'] = '112122111'; + $chr['G'] = '111112212'; + $chr['H'] = '211112211'; + $chr['I'] = '112112211'; + $chr['J'] = '111122211'; + $chr['K'] = '211111122'; + $chr['L'] = '112111122'; + $chr['M'] = '212111121'; + $chr['N'] = '111121122'; + $chr['O'] = '211121121'; + $chr['P'] = '112121121'; + $chr['Q'] = '111111222'; + $chr['R'] = '211111221'; + $chr['S'] = '112111221'; + $chr['T'] = '111121221'; + $chr['U'] = '221111112'; + $chr['V'] = '122111112'; + $chr['W'] = '222111111'; + $chr['X'] = '121121112'; + $chr['Y'] = '221121111'; + $chr['Z'] = '122121111'; + $chr['-'] = '121111212'; + $chr['.'] = '221111211'; + $chr[' '] = '122111211'; + $chr['$'] = '121212111'; + $chr['/'] = '121211121'; + $chr['+'] = '121112121'; + $chr['%'] = '111212121'; + $chr['*'] = '121121211'; + + $code = strtoupper($code); + if ($extended) { + // extended mode + $code = $this->encode_code39_ext($code); + } + if ($code === false) { + return false; + } + if ($checksum) { + // checksum + $code .= $this->checksum_code39($code); + } + // add start and stop codes + $code = '*'.$code.'*'; + + $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array()); + $k = 0; + $clen = strlen($code); + for ($i = 0; $i < $clen; ++$i) { + $char = $code{$i}; + if(!isset($chr[$char])) { + // invalid character + return false; + } + for ($j = 0; $j < 9; ++$j) { + if (($j % 2) == 0) { + $t = true; // bar + } else { + $t = false; // space + } + $w = $chr[$char]{$j}; + $bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0); + $bararray['maxw'] += $w; + ++$k; + } + $bararray['bcode'][$k] = array('t' => false, 'w' => 1, 'h' => 1, 'p' => 0); + $bararray['maxw'] += 1; + ++$k; + } + return $bararray; + } + + /** + * Encode a string to be used for CODE 39 Extended mode. + * @param string $code code to represent. + * @return encoded string. + * @access protected + */ + protected function encode_code39_ext($code) { + $encode = array( + chr(0) => '%U', chr(1) => '$A', chr(2) => '$B', chr(3) => '$C', + chr(4) => '$D', chr(5) => '$E', chr(6) => '$F', chr(7) => '$G', + chr(8) => '$H', chr(9) => '$I', chr(10) => '$J', chr(11) => '£K', + chr(12) => '$L', chr(13) => '$M', chr(14) => '$N', chr(15) => '$O', + chr(16) => '$P', chr(17) => '$Q', chr(18) => '$R', chr(19) => '$S', + chr(20) => '$T', chr(21) => '$U', chr(22) => '$V', chr(23) => '$W', + chr(24) => '$X', chr(25) => '$Y', chr(26) => '$Z', chr(27) => '%A', + chr(28) => '%B', chr(29) => '%C', chr(30) => '%D', chr(31) => '%E', + chr(32) => ' ', chr(33) => '/A', chr(34) => '/B', chr(35) => '/C', + chr(36) => '/D', chr(37) => '/E', chr(38) => '/F', chr(39) => '/G', + chr(40) => '/H', chr(41) => '/I', chr(42) => '/J', chr(43) => '/K', + chr(44) => '/L', chr(45) => '-', chr(46) => '.', chr(47) => '/O', + chr(48) => '0', chr(49) => '1', chr(50) => '2', chr(51) => '3', + chr(52) => '4', chr(53) => '5', chr(54) => '6', chr(55) => '7', + chr(56) => '8', chr(57) => '9', chr(58) => '/Z', chr(59) => '%F', + chr(60) => '%G', chr(61) => '%H', chr(62) => '%I', chr(63) => '%J', + chr(64) => '%V', chr(65) => 'A', chr(66) => 'B', chr(67) => 'C', + chr(68) => 'D', chr(69) => 'E', chr(70) => 'F', chr(71) => 'G', + chr(72) => 'H', chr(73) => 'I', chr(74) => 'J', chr(75) => 'K', + chr(76) => 'L', chr(77) => 'M', chr(78) => 'N', chr(79) => 'O', + chr(80) => 'P', chr(81) => 'Q', chr(82) => 'R', chr(83) => 'S', + chr(84) => 'T', chr(85) => 'U', chr(86) => 'V', chr(87) => 'W', + chr(88) => 'X', chr(89) => 'Y', chr(90) => 'Z', chr(91) => '%K', + chr(92) => '%L', chr(93) => '%M', chr(94) => '%N', chr(95) => '%O', + chr(96) => '%W', chr(97) => '+A', chr(98) => '+B', chr(99) => '+C', + chr(100) => '+D', chr(101) => '+E', chr(102) => '+F', chr(103) => '+G', + chr(104) => '+H', chr(105) => '+I', chr(106) => '+J', chr(107) => '+K', + chr(108) => '+L', chr(109) => '+M', chr(110) => '+N', chr(111) => '+O', + chr(112) => '+P', chr(113) => '+Q', chr(114) => '+R', chr(115) => '+S', + chr(116) => '+T', chr(117) => '+U', chr(118) => '+V', chr(119) => '+W', + chr(120) => '+X', chr(121) => '+Y', chr(122) => '+Z', chr(123) => '%P', + chr(124) => '%Q', chr(125) => '%R', chr(126) => '%S', chr(127) => '%T'); + $code_ext = ''; + $clen = strlen($code); + for ($i = 0 ; $i < $clen; ++$i) { + if (ord($code{$i}) > 127) { + return false; + } + $code_ext .= $encode[$code{$i}]; + } + return $code_ext; + } + + /** + * Calculate CODE 39 checksum (modulo 43). + * @param string $code code to represent. + * @return char checksum. + * @access protected + */ + protected function checksum_code39($code) { + $chars = array( + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', + 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', + 'W', 'X', 'Y', 'Z', '-', '.', ' ', '$', '/', '+', '%'); + $sum = 0; + $clen = strlen($code); + for ($i = 0 ; $i < $clen; ++$i) { + $k = array_keys($chars, $code{$i}); + $sum += $k[0]; + } + $j = ($sum % 43); + return $chars[$j]; + } + + /** + * CODE 93 - USS-93 + * Compact code similar to Code 39 + * @param string $code code to represent. + * @param boolean $checksum if true add a checksum to the code + * @return array barcode representation. + * @access protected + */ + protected function barcode_code93($code) { + $chr['0'] = '131112'; + $chr['1'] = '111213'; + $chr['2'] = '111312'; + $chr['3'] = '111411'; + $chr['4'] = '121113'; + $chr['5'] = '121212'; + $chr['6'] = '121311'; + $chr['7'] = '111114'; + $chr['8'] = '131211'; + $chr['9'] = '141111'; + $chr['A'] = '211113'; + $chr['B'] = '211212'; + $chr['C'] = '211311'; + $chr['D'] = '221112'; + $chr['E'] = '221211'; + $chr['F'] = '231111'; + $chr['G'] = '112113'; + $chr['H'] = '112212'; + $chr['I'] = '112311'; + $chr['J'] = '122112'; + $chr['K'] = '132111'; + $chr['L'] = '111123'; + $chr['M'] = '111222'; + $chr['N'] = '111321'; + $chr['O'] = '121122'; + $chr['P'] = '131121'; + $chr['Q'] = '212112'; + $chr['R'] = '212211'; + $chr['S'] = '211122'; + $chr['T'] = '211221'; + $chr['U'] = '221121'; + $chr['V'] = '222111'; + $chr['W'] = '112122'; + $chr['X'] = '112221'; + $chr['Y'] = '122121'; + $chr['Z'] = '123111'; + $chr['-'] = '121131'; + $chr['.'] = '311112'; + $chr[' '] = '311211'; + $chr['$'] = '321111'; + $chr['/'] = '112131'; + $chr['+'] = '113121'; + $chr['%'] = '211131'; + $chr[128] = '121221'; // ($) + $chr[129] = '311121'; // (/) + $chr[130] = '122211'; // (+) + $chr[131] = '312111'; // (%) + $chr['*'] = '111141'; + $code = strtoupper($code); + $encode = array( + chr(0) => chr(131).'U', chr(1) => chr(128).'A', chr(2) => chr(128).'B', chr(3) => chr(128).'C', + chr(4) => chr(128).'D', chr(5) => chr(128).'E', chr(6) => chr(128).'F', chr(7) => chr(128).'G', + chr(8) => chr(128).'H', chr(9) => chr(128).'I', chr(10) => chr(128).'J', chr(11) => '£K', + chr(12) => chr(128).'L', chr(13) => chr(128).'M', chr(14) => chr(128).'N', chr(15) => chr(128).'O', + chr(16) => chr(128).'P', chr(17) => chr(128).'Q', chr(18) => chr(128).'R', chr(19) => chr(128).'S', + chr(20) => chr(128).'T', chr(21) => chr(128).'U', chr(22) => chr(128).'V', chr(23) => chr(128).'W', + chr(24) => chr(128).'X', chr(25) => chr(128).'Y', chr(26) => chr(128).'Z', chr(27) => chr(131).'A', + chr(28) => chr(131).'B', chr(29) => chr(131).'C', chr(30) => chr(131).'D', chr(31) => chr(131).'E', + chr(32) => ' ', chr(33) => chr(129).'A', chr(34) => chr(129).'B', chr(35) => chr(129).'C', + chr(36) => chr(129).'D', chr(37) => chr(129).'E', chr(38) => chr(129).'F', chr(39) => chr(129).'G', + chr(40) => chr(129).'H', chr(41) => chr(129).'I', chr(42) => chr(129).'J', chr(43) => chr(129).'K', + chr(44) => chr(129).'L', chr(45) => '-', chr(46) => '.', chr(47) => chr(129).'O', + chr(48) => '0', chr(49) => '1', chr(50) => '2', chr(51) => '3', + chr(52) => '4', chr(53) => '5', chr(54) => '6', chr(55) => '7', + chr(56) => '8', chr(57) => '9', chr(58) => chr(129).'Z', chr(59) => chr(131).'F', + chr(60) => chr(131).'G', chr(61) => chr(131).'H', chr(62) => chr(131).'I', chr(63) => chr(131).'J', + chr(64) => chr(131).'V', chr(65) => 'A', chr(66) => 'B', chr(67) => 'C', + chr(68) => 'D', chr(69) => 'E', chr(70) => 'F', chr(71) => 'G', + chr(72) => 'H', chr(73) => 'I', chr(74) => 'J', chr(75) => 'K', + chr(76) => 'L', chr(77) => 'M', chr(78) => 'N', chr(79) => 'O', + chr(80) => 'P', chr(81) => 'Q', chr(82) => 'R', chr(83) => 'S', + chr(84) => 'T', chr(85) => 'U', chr(86) => 'V', chr(87) => 'W', + chr(88) => 'X', chr(89) => 'Y', chr(90) => 'Z', chr(91) => chr(131).'K', + chr(92) => chr(131).'L', chr(93) => chr(131).'M', chr(94) => chr(131).'N', chr(95) => chr(131).'O', + chr(96) => chr(131).'W', chr(97) => chr(130).'A', chr(98) => chr(130).'B', chr(99) => chr(130).'C', + chr(100) => chr(130).'D', chr(101) => chr(130).'E', chr(102) => chr(130).'F', chr(103) => chr(130).'G', + chr(104) => chr(130).'H', chr(105) => chr(130).'I', chr(106) => chr(130).'J', chr(107) => chr(130).'K', + chr(108) => chr(130).'L', chr(109) => chr(130).'M', chr(110) => chr(130).'N', chr(111) => chr(130).'O', + chr(112) => chr(130).'P', chr(113) => chr(130).'Q', chr(114) => chr(130).'R', chr(115) => chr(130).'S', + chr(116) => chr(130).'T', chr(117) => chr(130).'U', chr(118) => chr(130).'V', chr(119) => chr(130).'W', + chr(120) => chr(130).'X', chr(121) => chr(130).'Y', chr(122) => chr(130).'Z', chr(123) => chr(131).'P', + chr(124) => chr(131).'Q', chr(125) => chr(131).'R', chr(126) => chr(131).'S', chr(127) => chr(131).'T'); + $code_ext = ''; + $clen = strlen($code); + for ($i = 0 ; $i < $clen; ++$i) { + if (ord($code{$i}) > 127) { + return false; + } + $code_ext .= $encode[$code{$i}]; + } + // checksum + $code .= $this->checksum_code93($code); + // add start and stop codes + $code = '*'.$code.'*'; + $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array()); + $k = 0; + $clen = strlen($code); + for ($i = 0; $i < $clen; ++$i) { + $char = $code{$i}; + if(!isset($chr[$char])) { + // invalid character + return false; + } + for ($j = 0; $j < 6; ++$j) { + if (($j % 2) == 0) { + $t = true; // bar + } else { + $t = false; // space + } + $w = $chr[$char]{$j}; + $bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0); + $bararray['maxw'] += $w; + ++$k; + } + } + $bararray['bcode'][$k] = array('t' => true, 'w' => 1, 'h' => 1, 'p' => 0); + $bararray['maxw'] += 1; + ++$k; + return $bararray; + } + + /** + * Calculate CODE 93 checksum (modulo 47). + * @param string $code code to represent. + * @return string checksum code. + * @access protected + */ + protected function checksum_code93($code) { + $chars = array( + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', + 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', + 'W', 'X', 'Y', 'Z', '-', '.', ' ', '$', '/', '+', '%'); + // translate special characters + $code = strtr($code, chr(128).chr(129).chr(130).chr(131), '$/+%'); + $len = strlen($code); + // calculate check digit C + $p = 1; + $check = 0; + for ($i = ($len - 1); $i >= 0; --$i) { + $k = array_keys($chars, $code{$i}); + $check += ($k[0] * $p); + ++$p; + if ($p > 20) { + $p = 1; + } + } + $check %= 47; + $c = $chars[$check]; + $code .= $c; + // calculate check digit K + $p = 1; + $check = 0; + for ($i = $len; $i >= 0; --$i) { + $k = array_keys($chars, $code{$i}); + $check += ($k[0] * $p); + ++$p; + if ($p > 15) { + $p = 1; + } + } + $check %= 47; + $k = $chars[$check]; + return $c.$k; + } + + /** + * Checksum for standard 2 of 5 barcodes. + * @param string $code code to process. + * @return int checksum. + * @access protected + */ + protected function checksum_s25($code) { + $len = strlen($code); + $sum = 0; + for ($i = 0; $i < $len; $i+=2) { + $sum += $code{$i}; + } + $sum *= 3; + for ($i = 1; $i < $len; $i+=2) { + $sum += ($code{$i}); + } + $r = $sum % 10; + if($r > 0) { + $r = (10 - $r); + } + return $r; + } + + /** + * MSI. + * Variation of Plessey code, with similar applications + * Contains digits (0 to 9) and encodes the data only in the width of bars. + * @param string $code code to represent. + * @param boolean $checksum if true add a checksum to the code (modulo 11) + * @return array barcode representation. + * @access protected + */ + protected function barcode_msi($code, $checksum=false) { + $chr['0'] = '100100100100'; + $chr['1'] = '100100100110'; + $chr['2'] = '100100110100'; + $chr['3'] = '100100110110'; + $chr['4'] = '100110100100'; + $chr['5'] = '100110100110'; + $chr['6'] = '100110110100'; + $chr['7'] = '100110110110'; + $chr['8'] = '110100100100'; + $chr['9'] = '110100100110'; + $chr['A'] = '110100110100'; + $chr['B'] = '110100110110'; + $chr['C'] = '110110100100'; + $chr['D'] = '110110100110'; + $chr['E'] = '110110110100'; + $chr['F'] = '110110110110'; + if ($checksum) { + // add checksum + $clen = strlen($code); + $p = 2; + $check = 0; + for ($i = ($clen - 1); $i >= 0; --$i) { + $check += (hexdec($code{$i}) * $p); + ++$p; + if ($p > 7) { + $p = 2; + } + } + $check %= 11; + if ($check > 0) { + $check = 11 - $check; + } + $code .= $check; + } + $seq = '110'; // left guard + $clen = strlen($code); + for ($i = 0; $i < $clen; ++$i) { + $digit = $code{$i}; + if (!isset($chr[$digit])) { + // invalid character + return false; + } + $seq .= $chr[$digit]; + } + $seq .= '1001'; // right guard + $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array()); + return $this->binseq_to_array($seq, $bararray); + } + + /** + * Standard 2 of 5 barcodes. + * Used in airline ticket marking, photofinishing + * Contains digits (0 to 9) and encodes the data only in the width of bars. + * @param string $code code to represent. + * @param boolean $checksum if true add a checksum to the code + * @return array barcode representation. + * @access protected + */ + protected function barcode_s25($code, $checksum=false) { + $chr['0'] = '10101110111010'; + $chr['1'] = '11101010101110'; + $chr['2'] = '10111010101110'; + $chr['3'] = '11101110101010'; + $chr['4'] = '10101110101110'; + $chr['5'] = '11101011101010'; + $chr['6'] = '10111011101010'; + $chr['7'] = '10101011101110'; + $chr['8'] = '10101110111010'; + $chr['9'] = '10111010111010'; + if ($checksum) { + // add checksum + $code .= $this->checksum_s25($code); + } + if((strlen($code) % 2) != 0) { + // add leading zero if code-length is odd + $code = '0'.$code; + } + $seq = '11011010'; + $clen = strlen($code); + for ($i = 0; $i < $clen; ++$i) { + $digit = $code{$i}; + if (!isset($chr[$digit])) { + // invalid character + return false; + } + $seq .= $chr[$digit]; + } + $seq .= '1101011'; + $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array()); + return $this->binseq_to_array($seq, $bararray); + } + + /** + * Convert binary barcode sequence to TCPDF barcode array + * @param string $seq barcode as binary sequence + * òparam array $bararray TCPDF barcode array to fill up + * @return array barcode representation. + * @access protected + */ + protected function binseq_to_array($seq, $bararray) { + $len = strlen($seq); + $w = 0; + $k = 0; + for ($i = 0; $i < $len; ++$i) { + $w += 1; + if (($i == ($len - 1)) OR (($i < ($len - 1)) AND ($seq{$i} != $seq{($i+1)}))) { + if ($seq{$i} == '1') { + $t = true; // bar + } else { + $t = false; // space + } + $bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0); + $bararray['maxw'] += $w; + ++$k; + $w = 0; + } + } + return $bararray; + } + + /** + * Interleaved 2 of 5 barcodes. + * Compact numeric code, widely used in industry, air cargo + * Contains digits (0 to 9) and encodes the data in the width of both bars and spaces. + * @param string $code code to represent. + * @param boolean $checksum if true add a checksum to the code + * @return array barcode representation. + * @access protected + */ + protected function barcode_i25($code, $checksum=false) { + $chr['0'] = '11221'; + $chr['1'] = '21112'; + $chr['2'] = '12112'; + $chr['3'] = '22111'; + $chr['4'] = '11212'; + $chr['5'] = '21211'; + $chr['6'] = '12211'; + $chr['7'] = '11122'; + $chr['8'] = '21121'; + $chr['9'] = '12121'; + $chr['A'] = '11'; + $chr['Z'] = '21'; + if ($checksum) { + // add checksum + $code .= $this->checksum_s25($code); + } + if((strlen($code) % 2) != 0) { + // add leading zero if code-length is odd + $code = '0'.$code; + } + // add start and stop codes + $code = 'AA'.strtolower($code).'ZA'; + + $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array()); + $k = 0; + $clen = strlen($code); + for ($i = 0; $i < $clen; $i = ($i + 2)) { + $char_bar = $code{$i}; + $char_space = $code{$i+1}; + if((!isset($chr[$char_bar])) OR (!isset($chr[$char_space]))) { + // invalid character + return false; + } + // create a bar-space sequence + $seq = ''; + $chrlen = strlen($chr[$char_bar]); + for ($s = 0; $s < $chrlen; $s++){ + $seq .= $chr[$char_bar]{$s} . $chr[$char_space]{$s}; + } + $seqlen = strlen($seq); + for ($j = 0; $j < $seqlen; ++$j) { + if (($j % 2) == 0) { + $t = true; // bar + } else { + $t = false; // space + } + $w = $seq{$j}; + $bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0); + $bararray['maxw'] += $w; + ++$k; + } + } + return $bararray; + } + + /** + * C128 barcodes. + * Very capable code, excellent density, high reliability; in very wide use world-wide + * @param string $code code to represent. + * @param string $type barcode type: A, B or C + * @return array barcode representation. + * @access protected + */ + protected function barcode_c128($code, $type='B') { + $chr = array( + '212222', /* 00 */ + '222122', /* 01 */ + '222221', /* 02 */ + '121223', /* 03 */ + '121322', /* 04 */ + '131222', /* 05 */ + '122213', /* 06 */ + '122312', /* 07 */ + '132212', /* 08 */ + '221213', /* 09 */ + '221312', /* 10 */ + '231212', /* 11 */ + '112232', /* 12 */ + '122132', /* 13 */ + '122231', /* 14 */ + '113222', /* 15 */ + '123122', /* 16 */ + '123221', /* 17 */ + '223211', /* 18 */ + '221132', /* 19 */ + '221231', /* 20 */ + '213212', /* 21 */ + '223112', /* 22 */ + '312131', /* 23 */ + '311222', /* 24 */ + '321122', /* 25 */ + '321221', /* 26 */ + '312212', /* 27 */ + '322112', /* 28 */ + '322211', /* 29 */ + '212123', /* 30 */ + '212321', /* 31 */ + '232121', /* 32 */ + '111323', /* 33 */ + '131123', /* 34 */ + '131321', /* 35 */ + '112313', /* 36 */ + '132113', /* 37 */ + '132311', /* 38 */ + '211313', /* 39 */ + '231113', /* 40 */ + '231311', /* 41 */ + '112133', /* 42 */ + '112331', /* 43 */ + '132131', /* 44 */ + '113123', /* 45 */ + '113321', /* 46 */ + '133121', /* 47 */ + '313121', /* 48 */ + '211331', /* 49 */ + '231131', /* 50 */ + '213113', /* 51 */ + '213311', /* 52 */ + '213131', /* 53 */ + '311123', /* 54 */ + '311321', /* 55 */ + '331121', /* 56 */ + '312113', /* 57 */ + '312311', /* 58 */ + '332111', /* 59 */ + '314111', /* 60 */ + '221411', /* 61 */ + '431111', /* 62 */ + '111224', /* 63 */ + '111422', /* 64 */ + '121124', /* 65 */ + '121421', /* 66 */ + '141122', /* 67 */ + '141221', /* 68 */ + '112214', /* 69 */ + '112412', /* 70 */ + '122114', /* 71 */ + '122411', /* 72 */ + '142112', /* 73 */ + '142211', /* 74 */ + '241211', /* 75 */ + '221114', /* 76 */ + '413111', /* 77 */ + '241112', /* 78 */ + '134111', /* 79 */ + '111242', /* 80 */ + '121142', /* 81 */ + '121241', /* 82 */ + '114212', /* 83 */ + '124112', /* 84 */ + '124211', /* 85 */ + '411212', /* 86 */ + '421112', /* 87 */ + '421211', /* 88 */ + '212141', /* 89 */ + '214121', /* 90 */ + '412121', /* 91 */ + '111143', /* 92 */ + '111341', /* 93 */ + '131141', /* 94 */ + '114113', /* 95 */ + '114311', /* 96 */ + '411113', /* 97 */ + '411311', /* 98 */ + '113141', /* 99 */ + '114131', /* 100 */ + '311141', /* 101 */ + '411131', /* 102 */ + '211412', /* 103 START A */ + '211214', /* 104 START B */ + '211232', /* 105 START C */ + '233111', /* STOP */ + '200000' /* END */ + ); + $keys = ''; + switch(strtoupper($type)) { + case 'A': { + $startid = 103; + $keys = ' !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_'; + for ($i = 0; $i < 32; ++$i) { + $keys .= chr($i); + } + break; + } + case 'B': { + $startid = 104; + $keys = ' !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~'.chr(127); + break; + } + case 'C': { + $startid = 105; + $keys = ''; + if ((strlen($code) % 2) != 0) { + // The length of barcode value must be even ($code). You must pad the number with zeros + return false; + } + for ($i = 0; $i <= 99; ++$i) { + $keys .= chr($i); + } + $new_code = ''; + $hclen = (strlen($code) / 2); + for ($i = 0; $i < $hclen; ++$i) { + $new_code .= chr(intval($code{(2 * $i)}.$code{(2 * $i + 1)})); + } + $code = $new_code; + break; + } + default: { + return false; + } + } + // calculate check character + $sum = $startid; + $clen = strlen($code); + for ($i = 0; $i < $clen; ++$i) { + $sum += (strpos($keys, $code{$i}) * ($i+1)); + } + $check = ($sum % 103); + // add start, check and stop codes + $code = chr($startid).$code.chr($check).chr(106).chr(107); + $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array()); + $k = 0; + $len = strlen($code); + for ($i = 0; $i < $len; ++$i) { + $ck = strpos($keys, $code{$i}); + if (($i == 0) OR ($i > ($len-4))) { + $char_num = ord($code{$i}); + $seq = $chr[$char_num]; + } elseif(($ck >= 0) AND isset($chr[$ck])) { + $seq = $chr[$ck]; + } else { + // invalid character + return false; + } + for ($j = 0; $j < 6; ++$j) { + if (($j % 2) == 0) { + $t = true; // bar + } else { + $t = false; // space + } + $w = $seq{$j}; + $bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0); + $bararray['maxw'] += $w; + ++$k; + } + } + return $bararray; + } + + /** + * EAN13 and UPC-A barcodes. + * EAN13: European Article Numbering international retail product code + * UPC-A: Universal product code seen on almost all retail products in the USA and Canada + * UPC-E: Short version of UPC symbol + * @param string $code code to represent. + * @param string $len barcode type: 6 = UPC-E, 8 = EAN8, 13 = EAN13, 12 = UPC-A + * @return array barcode representation. + * @access protected + */ + protected function barcode_eanupc($code, $len=13) { + $upce = false; + if ($len == 6) { + $len = 12; // UPC-A + $upce = true; // UPC-E mode + } + $data_len = $len - 1; + //Padding + $code = str_pad($code, $data_len, '0', STR_PAD_LEFT); + $code_len = strlen($code); + // calculate check digit + $sum_a = 0; + for ($i = 1; $i < $data_len; $i+=2) { + $sum_a += $code{$i}; + } + if ($len > 12) { + $sum_a *= 3; + } + $sum_b = 0; + for ($i = 0; $i < $data_len; $i+=2) { + $sum_b += ($code{$i}); + } + if ($len < 13) { + $sum_b *= 3; + } + $r = ($sum_a + $sum_b) % 10; + if($r > 0) { + $r = (10 - $r); + } + if ($code_len == $data_len) { + // add check digit + $code .= $r; + } elseif ($r !== intval($code{$data_len})) { + // wrong checkdigit + return false; + } + if ($len == 12) { + // UPC-A + $code = '0'.$code; + ++$len; + } + if ($upce) { + // convert UPC-A to UPC-E + $tmp = substr($code, 4, 3); + if (($tmp == '000') OR ($tmp == '100') OR ($tmp == '200')) { + // manufacturer code ends in 000, 100, or 200 + $upce_code = substr($code, 2, 2).substr($code, 9, 3).substr($code, 4, 1); + } else { + $tmp = substr($code, 5, 2); + if ($tmp == '00') { + // manufacturer code ends in 00 + $upce_code = substr($code, 2, 3).substr($code, 10, 2).'3'; + } else { + $tmp = substr($code, 6, 1); + if ($tmp == '0') { + // manufacturer code ends in 0 + $upce_code = substr($code, 2, 4).substr($code, 11, 1).'4'; + } else { + // manufacturer code does not end in zero + $upce_code = substr($code, 2, 5).substr($code, 11, 1); + } + } + } + } + //Convert digits to bars + $codes = array( + 'A'=>array( // left odd parity + '0'=>'0001101', + '1'=>'0011001', + '2'=>'0010011', + '3'=>'0111101', + '4'=>'0100011', + '5'=>'0110001', + '6'=>'0101111', + '7'=>'0111011', + '8'=>'0110111', + '9'=>'0001011'), + 'B'=>array( // left even parity + '0'=>'0100111', + '1'=>'0110011', + '2'=>'0011011', + '3'=>'0100001', + '4'=>'0011101', + '5'=>'0111001', + '6'=>'0000101', + '7'=>'0010001', + '8'=>'0001001', + '9'=>'0010111'), + 'C'=>array( // right + '0'=>'1110010', + '1'=>'1100110', + '2'=>'1101100', + '3'=>'1000010', + '4'=>'1011100', + '5'=>'1001110', + '6'=>'1010000', + '7'=>'1000100', + '8'=>'1001000', + '9'=>'1110100') + ); + $parities = array( + '0'=>array('A','A','A','A','A','A'), + '1'=>array('A','A','B','A','B','B'), + '2'=>array('A','A','B','B','A','B'), + '3'=>array('A','A','B','B','B','A'), + '4'=>array('A','B','A','A','B','B'), + '5'=>array('A','B','B','A','A','B'), + '6'=>array('A','B','B','B','A','A'), + '7'=>array('A','B','A','B','A','B'), + '8'=>array('A','B','A','B','B','A'), + '9'=>array('A','B','B','A','B','A') + ); + $upce_parities = array(); + $upce_parities[0] = array( + '0'=>array('B','B','B','A','A','A'), + '1'=>array('B','B','A','B','A','A'), + '2'=>array('B','B','A','A','B','A'), + '3'=>array('B','B','A','A','A','B'), + '4'=>array('B','A','B','B','A','A'), + '5'=>array('B','A','A','B','B','A'), + '6'=>array('B','A','A','A','B','B'), + '7'=>array('B','A','B','A','B','A'), + '8'=>array('B','A','B','A','A','B'), + '9'=>array('B','A','A','B','A','B') + ); + $upce_parities[1] = array( + '0'=>array('A','A','A','B','B','B'), + '1'=>array('A','A','B','A','B','B'), + '2'=>array('A','A','B','B','A','B'), + '3'=>array('A','A','B','B','B','A'), + '4'=>array('A','B','A','A','B','B'), + '5'=>array('A','B','B','A','A','B'), + '6'=>array('A','B','B','B','A','A'), + '7'=>array('A','B','A','B','A','B'), + '8'=>array('A','B','A','B','B','A'), + '9'=>array('A','B','B','A','B','A') + ); + $k = 0; + $seq = '101'; // left guard bar + if ($upce) { + $bararray = array('code' => $upce_code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array()); + $p = $upce_parities[$code{1}][$r]; + for ($i = 0; $i < 6; ++$i) { + $seq .= $codes[$p[$i]][$upce_code{$i}]; + } + $seq .= '010101'; // right guard bar + } else { + $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array()); + $half_len = ceil($len / 2); + if ($len == 8) { + for ($i = 0; $i < $half_len; ++$i) { + $seq .= $codes['A'][$code{$i}]; + } + } else { + $p = $parities[$code{0}]; + for ($i = 1; $i < $half_len; ++$i) { + $seq .= $codes[$p[$i-1]][$code{$i}]; + } + } + $seq .= '01010'; // center guard bar + for ($i = $half_len; $i < $len; ++$i) { + $seq .= $codes['C'][$code{$i}]; + } + $seq .= '101'; // right guard bar + } + $clen = strlen($seq); + $w = 0; + for ($i = 0; $i < $clen; ++$i) { + $w += 1; + if (($i == ($clen - 1)) OR (($i < ($clen - 1)) AND ($seq{$i} != $seq{($i+1)}))) { + if ($seq{$i} == '1') { + $t = true; // bar + } else { + $t = false; // space + } + $bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0); + $bararray['maxw'] += $w; + ++$k; + $w = 0; + } + } + return $bararray; + } + + /** + * UPC-Based Extentions + * 2-Digit Ext.: Used to indicate magazines and newspaper issue numbers + * 5-Digit Ext.: Used to mark suggested retail price of books + * @param string $code code to represent. + * @param string $len barcode type: 2 = 2-Digit, 5 = 5-Digit + * @return array barcode representation. + * @access protected + */ + protected function barcode_eanext($code, $len=5) { + //Padding + $code = str_pad($code, $len, '0', STR_PAD_LEFT); + // calculate check digit + if ($len == 2) { + $r = $code % 4; + } elseif ($len == 5) { + $r = (3 * ($code{0} + $code{2} + $code{4})) + (9 * ($code{1} + $code{3})); + $r %= 10; + } else { + return false; + } + //Convert digits to bars + $codes = array( + 'A'=>array( // left odd parity + '0'=>'0001101', + '1'=>'0011001', + '2'=>'0010011', + '3'=>'0111101', + '4'=>'0100011', + '5'=>'0110001', + '6'=>'0101111', + '7'=>'0111011', + '8'=>'0110111', + '9'=>'0001011'), + 'B'=>array( // left even parity + '0'=>'0100111', + '1'=>'0110011', + '2'=>'0011011', + '3'=>'0100001', + '4'=>'0011101', + '5'=>'0111001', + '6'=>'0000101', + '7'=>'0010001', + '8'=>'0001001', + '9'=>'0010111') + ); + $parities = array(); + $parities[2] = array( + '0'=>array('A','A'), + '1'=>array('A','B'), + '2'=>array('B','A'), + '3'=>array('B','B') + ); + $parities[5] = array( + '0'=>array('B','B','A','A','A'), + '1'=>array('B','A','B','A','A'), + '2'=>array('B','A','A','B','A'), + '3'=>array('B','A','A','A','B'), + '4'=>array('A','B','B','A','A'), + '5'=>array('A','A','B','B','A'), + '6'=>array('A','A','A','B','B'), + '7'=>array('A','B','A','B','A'), + '8'=>array('A','B','A','A','B'), + '9'=>array('A','A','B','A','B') + ); + $p = $parities[$len][$r]; + $seq = '1011'; // left guard bar + $seq .= $codes[$p[0]][$code{0}]; + for ($i = 1; $i < $len; ++$i) { + $seq .= '01'; // separator + $seq .= $codes[$p[$i]][$code{$i}]; + } + $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array()); + return $this->binseq_to_array($seq, $bararray); + } + + /** + * POSTNET and PLANET barcodes. + * Used by U.S. Postal Service for automated mail sorting + * @param string $code zip code to represent. Must be a string containing a zip code of the form DDDDD or DDDDD-DDDD. + * @param boolean $planet if true print the PLANET barcode, otherwise print POSTNET + * @return array barcode representation. + * @access protected + */ + protected function barcode_postnet($code, $planet=false) { + // bar lenght + if ($planet) { + $barlen = Array( + 0 => Array(1,1,2,2,2), + 1 => Array(2,2,2,1,1), + 2 => Array(2,2,1,2,1), + 3 => Array(2,2,1,1,2), + 4 => Array(2,1,2,2,1), + 5 => Array(2,1,2,1,2), + 6 => Array(2,1,1,2,2), + 7 => Array(1,2,2,2,1), + 8 => Array(1,2,2,1,2), + 9 => Array(1,2,1,2,2) + ); + } else { + $barlen = Array( + 0 => Array(2,2,1,1,1), + 1 => Array(1,1,1,2,2), + 2 => Array(1,1,2,1,2), + 3 => Array(1,1,2,2,1), + 4 => Array(1,2,1,1,2), + 5 => Array(1,2,1,2,1), + 6 => Array(1,2,2,1,1), + 7 => Array(2,1,1,1,2), + 8 => Array(2,1,1,2,1), + 9 => Array(2,1,2,1,1) + ); + } + $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 2, 'bcode' => array()); + $k = 0; + $code = str_replace('-', '', $code); + $code = str_replace(' ', '', $code); + $len = strlen($code); + // calculate checksum + $sum = 0; + for ($i = 0; $i < $len; ++$i) { + $sum += intval($code{$i}); + } + $chkd = ($sum % 10); + if($chkd > 0) { + $chkd = (10 - $chkd); + } + $code .= $chkd; + $len = strlen($code); + // start bar + $bararray['bcode'][$k++] = array('t' => 1, 'w' => 1, 'h' => 2, 'p' => 0); + $bararray['bcode'][$k++] = array('t' => 0, 'w' => 1, 'h' => 2, 'p' => 0); + $bararray['maxw'] += 2; + for ($i = 0; $i < $len; ++$i) { + for ($j = 0; $j < 5; ++$j) { + $h = $barlen[$code{$i}][$j]; + $p = floor(1 / $h); + $bararray['bcode'][$k++] = array('t' => 1, 'w' => 1, 'h' => $h, 'p' => $p); + $bararray['bcode'][$k++] = array('t' => 0, 'w' => 1, 'h' => 2, 'p' => 0); + $bararray['maxw'] += 2; + } + } + // end bar + $bararray['bcode'][$k++] = array('t' => 1, 'w' => 1, 'h' => 2, 'p' => 0); + $bararray['maxw'] += 1; + return $bararray; + } + + /** + * RMS4CC - CBC - KIX + * RMS4CC (Royal Mail 4-state Customer Code) - CBC (Customer Bar Code) - KIX (Klant index - Customer index) + * RM4SCC is the name of the barcode symbology used by the Royal Mail for its Cleanmail service. + * @param string $code code to print + * @param boolean $kix if true prints the KIX variation (doesn't use the start and end symbols, and the checksum) - in this case the house number must be sufficed with an X and placed at the end of the code. + * @return array barcode representation. + * @access protected + */ + protected function barcode_rms4cc($code, $kix=false) { + $notkix = !$kix; + // bar mode + // 1 = pos 1, length 2 + // 2 = pos 1, length 3 + // 3 = pos 2, length 1 + // 4 = pos 2, length 2 + $barmode = array( + '0' => array(3,3,2,2), + '1' => array(3,4,1,2), + '2' => array(3,4,2,1), + '3' => array(4,3,1,2), + '4' => array(4,3,2,1), + '5' => array(4,4,1,1), + '6' => array(3,1,4,2), + '7' => array(3,2,3,2), + '8' => array(3,2,4,1), + '9' => array(4,1,3,2), + 'A' => array(4,1,4,1), + 'B' => array(4,2,3,1), + 'C' => array(3,1,2,4), + 'D' => array(3,2,1,4), + 'E' => array(3,2,2,3), + 'F' => array(4,1,1,4), + 'G' => array(4,1,2,3), + 'H' => array(4,2,1,3), + 'I' => array(1,3,4,2), + 'J' => array(1,4,3,2), + 'K' => array(1,4,4,1), + 'L' => array(2,3,3,2), + 'M' => array(2,3,4,1), + 'N' => array(2,4,3,1), + 'O' => array(1,3,2,4), + 'P' => array(1,4,1,4), + 'Q' => array(1,4,2,3), + 'R' => array(2,3,1,4), + 'S' => array(2,3,2,3), + 'T' => array(2,4,1,3), + 'U' => array(1,1,4,4), + 'V' => array(1,2,3,4), + 'W' => array(1,2,4,3), + 'X' => array(2,1,3,4), + 'Y' => array(2,1,4,3), + 'Z' => array(2,2,3,3) + ); + $code = strtoupper($code); + $len = strlen($code); + $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 3, 'bcode' => array()); + if ($notkix) { + // table for checksum calculation (row,col) + $checktable = array( + '0' => array(1,1), + '1' => array(1,2), + '2' => array(1,3), + '3' => array(1,4), + '4' => array(1,5), + '5' => array(1,0), + '6' => array(2,1), + '7' => array(2,2), + '8' => array(2,3), + '9' => array(2,4), + 'A' => array(2,5), + 'B' => array(2,0), + 'C' => array(3,1), + 'D' => array(3,2), + 'E' => array(3,3), + 'F' => array(3,4), + 'G' => array(3,5), + 'H' => array(3,0), + 'I' => array(4,1), + 'J' => array(4,2), + 'K' => array(4,3), + 'L' => array(4,4), + 'M' => array(4,5), + 'N' => array(4,0), + 'O' => array(5,1), + 'P' => array(5,2), + 'Q' => array(5,3), + 'R' => array(5,4), + 'S' => array(5,5), + 'T' => array(5,0), + 'U' => array(0,1), + 'V' => array(0,2), + 'W' => array(0,3), + 'X' => array(0,4), + 'Y' => array(0,5), + 'Z' => array(0,0) + ); + $row = 0; + $col = 0; + for ($i = 0; $i < $len; ++$i) { + $row += $checktable[$code{$i}][0]; + $col += $checktable[$code{$i}][1]; + } + $row %= 6; + $col %= 6; + $chk = array_keys($checktable, array($row,$col)); + $code .= $chk[0]; + ++$len; + } + $k = 0; + if ($notkix) { + // start bar + $bararray['bcode'][$k++] = array('t' => 1, 'w' => 1, 'h' => 2, 'p' => 0); + $bararray['bcode'][$k++] = array('t' => 0, 'w' => 1, 'h' => 2, 'p' => 0); + $bararray['maxw'] += 2; + } + for ($i = 0; $i < $len; ++$i) { + for ($j = 0; $j < 4; ++$j) { + switch ($barmode[$code{$i}][$j]) { + case 1: { + $p = 0; + $h = 2; + break; + } + case 2: { + $p = 0; + $h = 3; + break; + } + case 3: { + $p = 1; + $h = 1; + break; + } + case 4: { + $p = 1; + $h = 2; + break; + } + } + $bararray['bcode'][$k++] = array('t' => 1, 'w' => 1, 'h' => $h, 'p' => $p); + $bararray['bcode'][$k++] = array('t' => 0, 'w' => 1, 'h' => 2, 'p' => 0); + $bararray['maxw'] += 2; + } + } + if ($notkix) { + // stop bar + $bararray['bcode'][$k++] = array('t' => 1, 'w' => 1, 'h' => 3, 'p' => 0); + $bararray['maxw'] += 1; + } + return $bararray; + } + + /** + * CODABAR barcodes. + * Older code often used in library systems, sometimes in blood banks + * @param string $code code to represent. + * @return array barcode representation. + * @access protected + */ + protected function barcode_codabar($code) { + $chr = array( + '0' => '11111221', + '1' => '11112211', + '2' => '11121121', + '3' => '22111111', + '4' => '11211211', + '5' => '21111211', + '6' => '12111121', + '7' => '12112111', + '8' => '12211111', + '9' => '21121111', + '-' => '11122111', + '$' => '11221111', + ':' => '21112121', + '/' => '21211121', + '.' => '21212111', + '+' => '11222221', + 'A' => '11221211', + 'B' => '12121121', + 'C' => '11121221', + 'D' => '11122211' + ); + $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array()); + $k = 0; + $w = 0; + $seq = ''; + $code = 'A'.strtoupper($code).'A'; + $len = strlen($code); + for ($i = 0; $i < $len; ++$i) { + if (!isset($chr[$code{$i}])) { + return false; + } + $seq = $chr[$code{$i}]; + for ($j = 0; $j < 8; ++$j) { + if (($j % 2) == 0) { + $t = true; // bar + } else { + $t = false; // space + } + $w = $seq{$j}; + $bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0); + $bararray['maxw'] += $w; + ++$k; + } + } + return $bararray; + } + + /** + * CODE11 barcodes. + * Used primarily for labeling telecommunications equipment + * @param string $code code to represent. + * @return array barcode representation. + * @access protected + */ + protected function barcode_code11($code) { + $chr = array( + '0' => '111121', + '1' => '211121', + '2' => '121121', + '3' => '221111', + '4' => '112121', + '5' => '212111', + '6' => '122111', + '7' => '111221', + '8' => '211211', + '9' => '211111', + '-' => '112111', + 'S' => '112211' + ); + + $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array()); + $k = 0; + $w = 0; + $seq = ''; + $len = strlen($code); + // calculate check digit C + $p = 1; + $check = 0; + for ($i = ($len - 1); $i >= 0; --$i) { + $digit = $code{$i}; + if ($digit == '-') { + $dval = 10; + } else { + $dval = intval($digit); + } + $check += ($dval * $p); + ++$p; + if ($p > 10) { + $p = 1; + } + } + $check %= 11; + if ($check == 10) { + $check = '-'; + } + $code .= $check; + if ($len > 10) { + // calculate check digit K + $p = 1; + $check = 0; + for ($i = $len; $i >= 0; --$i) { + $digit = $code{$i}; + if ($digit == '-') { + $dval = 10; + } else { + $dval = intval($digit); + } + $check += ($dval * $p); + ++$p; + if ($p > 9) { + $p = 1; + } + } + $check %= 11; + $code .= $check; + ++$len; + } + $code = 'S'.$code.'S'; + $len += 3; + for ($i = 0; $i < $len; ++$i) { + if (!isset($chr[$code{$i}])) { + return false; + } + $seq = $chr[$code{$i}]; + for ($j = 0; $j < 6; ++$j) { + if (($j % 2) == 0) { + $t = true; // bar + } else { + $t = false; // space + } + $w = $seq{$j}; + $bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0); + $bararray['maxw'] += $w; + ++$k; + } + } + return $bararray; + } + + /** + * Pharmacode + * Contains digits (0 to 9) + * @param string $code code to represent. + * @return array barcode representation. + * @access protected + */ + protected function barcode_pharmacode($code) { + $seq = ''; + $code = intval($code); + while ($code > 0) { + if (($code % 2) == 0) { + $seq .= '11100'; + $code -= 2; + } else { + $seq .= '100'; + $code -= 1; + } + $code /= 2; + } + $seq = substr($seq, 0, -2); + $seq = strrev($seq); + $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array()); + return $this->binseq_to_array($seq, $bararray); + } + + /** + * Pharmacode two-track + * Contains digits (0 to 9) + * @param string $code code to represent. + * @return array barcode representation. + * @access protected + */ + protected function barcode_pharmacode2t($code) { + $seq = ''; + $code = intval($code); + do { + switch ($code % 3) { + case 0: { + $seq .= '3'; + $code = ($code - 3) / 3; + break; + } + case 1: { + $seq .= '1'; + $code = ($code - 1) / 3; + break; + } + case 2: { + $seq .= '2'; + $code = ($code - 2) / 3; + break; + } + } + } while($code != 0); + $seq = strrev($seq); + $k = 0; + $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 2, 'bcode' => array()); + $len = strlen($seq); + for ($i = 0; $i < $len; ++$i) { + switch ($seq{$i}) { + case '1': { + $p = 1; + $h = 1; + break; + } + case '2': { + $p = 0; + $h = 1; + break; + } + case '3': { + $p = 0; + $h = 2; + break; + } + } + $bararray['bcode'][$k++] = array('t' => 1, 'w' => 1, 'h' => $h, 'p' => $p); + $bararray['bcode'][$k++] = array('t' => 0, 'w' => 1, 'h' => 2, 'p' => 0); + $bararray['maxw'] += 2; + } + unset($bararray['bcode'][($k - 1)]); + --$bararray['maxw']; + return $bararray; + } + + + /** + * IMB - Intelligent Mail Barcode - Onecode - USPS-B-3200 + * (requires PHP bcmath extension) + * Intelligent Mail barcode is a 65-bar code for use on mail in the United States. + * The fields are described as follows:
    • The Barcode Identifier shall be assigned by USPS to encode the presort identification that is currently printed in human readable form on the optional endorsement line (OEL) as well as for future USPS use. This shall be two digits, with the second digit in the range of 0–4. The allowable encoding ranges shall be 00–04, 10–14, 20–24, 30–34, 40–44, 50–54, 60–64, 70–74, 80–84, and 90–94.
    • The Service Type Identifier shall be assigned by USPS for any combination of services requested on the mailpiece. The allowable encoding range shall be 000http://it2.php.net/manual/en/function.dechex.php–999. Each 3-digit value shall correspond to a particular mail class with a particular combination of service(s). Each service program, such as OneCode Confirm and OneCode ACS, shall provide the list of Service Type Identifier values.
    • The Mailer or Customer Identifier shall be assigned by USPS as a unique, 6 or 9 digit number that identifies a business entity. The allowable encoding range for the 6 digit Mailer ID shall be 000000- 899999, while the allowable encoding range for the 9 digit Mailer ID shall be 900000000-999999999.
    • The Serial or Sequence Number shall be assigned by the mailer for uniquely identifying and tracking mailpieces. The allowable encoding range shall be 000000000–999999999 when used with a 6 digit Mailer ID and 000000-999999 when used with a 9 digit Mailer ID. e. The Delivery Point ZIP Code shall be assigned by the mailer for routing the mailpiece. This shall replace POSTNET for routing the mailpiece to its final delivery point. The length may be 0, 5, 9, or 11 digits. The allowable encoding ranges shall be no ZIP Code, 00000–99999, 000000000–999999999, and 00000000000–99999999999.
    + * @param string $code code to print, separate the ZIP (routing code) from the rest using a minus char '-' (BarcodeID_ServiceTypeID_MailerID_SerialNumber-RoutingCode) + * @return array barcode representation. + * @access protected + */ + protected function barcode_imb($code) { + $asc_chr = array(4,0,2,6,3,5,1,9,8,7,1,2,0,6,4,8,2,9,5,3,0,1,3,7,4,6,8,9,2,0,5,1,9,4,3,8,6,7,1,2,4,3,9,5,7,8,3,0,2,1,4,0,9,1,7,0,2,4,6,3,7,1,9,5,8); + $dsc_chr = array(7,1,9,5,8,0,2,4,6,3,5,8,9,7,3,0,6,1,7,4,6,8,9,2,5,1,7,5,4,3,8,7,6,0,2,5,4,9,3,0,1,6,8,2,0,4,5,9,6,7,5,2,6,3,8,5,1,9,8,7,4,0,2,6,3); + $asc_pos = array(3,0,8,11,1,12,8,11,10,6,4,12,2,7,9,6,7,9,2,8,4,0,12,7,10,9,0,7,10,5,7,9,6,8,2,12,1,4,2,0,1,5,4,6,12,1,0,9,4,7,5,10,2,6,9,11,2,12,6,7,5,11,0,3,2); + $dsc_pos = array(2,10,12,5,9,1,5,4,3,9,11,5,10,1,6,3,4,1,10,0,2,11,8,6,1,12,3,8,6,4,4,11,0,6,1,9,11,5,3,7,3,10,7,11,8,2,10,3,5,8,0,3,12,11,8,4,5,1,3,0,7,12,9,8,10); + $code_arr = explode('-', $code); + $tracking_number = $code_arr[0]; + if (isset($code_arr[1])) { + $routing_code = $code_arr[1]; + } else { + $routing_code = ''; + } + // Conversion of Routing Code + switch (strlen($routing_code)) { + case 0: { + $binary_code = 0; + break; + } + case 5: { + $binary_code = bcadd($routing_code, '1'); + break; + } + case 9: { + $binary_code = bcadd($routing_code, '100001'); + break; + } + case 11: { + $binary_code = bcadd($routing_code, '1000100001'); + break; + } + default: { + return false; + break; + } + } + $binary_code = bcmul($binary_code, 10); + $binary_code = bcadd($binary_code, $tracking_number{0}); + $binary_code = bcmul($binary_code, 5); + $binary_code = bcadd($binary_code, $tracking_number{1}); + $binary_code .= substr($tracking_number, 2, 18); + // convert to hexadecimal + $binary_code = $this->dec_to_hex($binary_code); + // pad to get 13 bytes + $binary_code = str_pad($binary_code, 26, '0', STR_PAD_LEFT); + // convert string to array of bytes + $binary_code_arr = chunk_split($binary_code, 2, "\r"); + $binary_code_arr = substr($binary_code_arr, 0, -1); + $binary_code_arr = explode("\r", $binary_code_arr); + // calculate frame check sequence + $fcs = $this->imb_crc11fcs($binary_code_arr); + // exclude first 2 bits from first byte + $first_byte = sprintf('%2s', dechex((hexdec($binary_code_arr[0]) << 2) >> 2)); + $binary_code_102bit = $first_byte.substr($binary_code, 2); + // convert binary data to codewords + $codewords = array(); + $data = $this->hex_to_dec($binary_code_102bit); + $codewords[0] = bcmod($data, 636) * 2; + $data = bcdiv($data, 636); + for ($i = 1; $i < 9; ++$i) { + $codewords[$i] = bcmod($data, 1365); + $data = bcdiv($data, 1365); + } + $codewords[9] = $data; + if (($fcs >> 10) == 1) { + $codewords[9] += 659; + } + // generate lookup tables + $table2of13 = $this->imb_tables(2, 78); + $table5of13 = $this->imb_tables(5, 1287); + // convert codewords to characters + $characters = array(); + $bitmask = 512; + foreach($codewords as $k => $val) { + if ($val <= 1286) { + $chrcode = $table5of13[$val]; + } else { + $chrcode = $table2of13[($val - 1287)]; + } + if (($fcs & $bitmask) > 0) { + // bitwise invert + $chrcode = ((~$chrcode) & 8191); + } + $characters[] = $chrcode; + $bitmask /= 2; + } + $characters = array_reverse($characters); + // build bars + $k = 0; + $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 3, 'bcode' => array()); + for ($i = 0; $i < 65; ++$i) { + $asc = (($characters[$asc_chr[$i]] & pow(2, $asc_pos[$i])) > 0); + $dsc = (($characters[$dsc_chr[$i]] & pow(2, $dsc_pos[$i])) > 0); + if ($asc AND $dsc) { + // full bar (F) + $p = 0; + $h = 3; + } elseif ($asc) { + // ascender (A) + $p = 0; + $h = 2; + } elseif ($dsc) { + // descender (D) + $p = 1; + $h = 2; + } else { + // tracker (T) + $p = 1; + $h = 1; + } + $bararray['bcode'][$k++] = array('t' => 1, 'w' => 1, 'h' => $h, 'p' => $p); + $bararray['bcode'][$k++] = array('t' => 0, 'w' => 1, 'h' => 2, 'p' => 0); + $bararray['maxw'] += 2; + } + unset($bararray['bcode'][($k - 1)]); + --$bararray['maxw']; + return $bararray; + } + + /** + * Convert large integer number to hexadecimal representation. + * (requires PHP bcmath extension) + * @param string $number number to convert specified as a string + * @return string hexadecimal representation + */ + public function dec_to_hex($number) { + $i = 0; + $hex = array(); + if($number == 0) { + return '00'; + } + while($number > 0) { + if($number == 0) { + array_push($hex, '0'); + } else { + array_push($hex, strtoupper(dechex(bcmod($number, '16')))); + $number = bcdiv($number, '16', 0); + } + } + $hex = array_reverse($hex); + return implode($hex); + } + + /** + * Convert large hexadecimal number to decimal representation (string). + * (requires PHP bcmath extension) + * @param string $hex hexadecimal number to convert specified as a string + * @return string hexadecimal representation + */ + public function hex_to_dec($hex) { + $dec = 0; + $bitval = 1; + $len = strlen($hex); + for($pos = ($len - 1); $pos >= 0; --$pos) { + $dec = bcadd($dec, bcmul(hexdec($hex{$pos}), $bitval)); + $bitval = bcmul($bitval, 16); + } + return $dec; + } + + /** + * Intelligent Mail Barcode calculation of Frame Check Sequence + * @param string $code_arr array of hexadecimal values (13 bytes holding 102 bits right justified). + * @return int 11 bit Frame Check Sequence as integer (decimal base) + * @access protected + */ + protected function imb_crc11fcs($code_arr) { + $genpoly = 0x0F35; // generator polynomial + $fcs = 0x07FF; // Frame Check Sequence + // do most significant byte skipping the 2 most significant bits + $data = hexdec($code_arr[0]) << 5; + for ($bit = 2; $bit < 8; ++$bit) { + if (($fcs ^ $data) & 0x400) { + $fcs = ($fcs << 1) ^ $genpoly; + } else { + $fcs = ($fcs << 1); + } + $fcs &= 0x7FF; + $data <<= 1; + } + // do rest of bytes + for ($byte = 1; $byte < 13; ++$byte) { + $data = hexdec($code_arr[$byte]) << 3; + for ($bit = 0; $bit < 8; ++$bit) { + if (($fcs ^ $data) & 0x400) { + $fcs = ($fcs << 1) ^ $genpoly; + } else { + $fcs = ($fcs << 1); + } + $fcs &= 0x7FF; + $data <<= 1; + } + } + return $fcs; + } + + /** + * Reverse unsigned short value + * @param int $num value to reversr + * @return int reversed value + * @access protected + */ + protected function imb_reverse_us($num) { + $rev = 0; + for ($i = 0; $i < 16; ++$i) { + $rev <<= 1; + $rev |= ($num & 1); + $num >>= 1; + } + return $rev; + } + + /** + * generate Nof13 tables used for Intelligent Mail Barcode + * @param int $n is the type of table: 2 for 2of13 table, 5 for 5of13table + * @param int $size size of table (78 for n=2 and 1287 for n=5) + * @return array requested table + * @access protected + */ + protected function imb_tables($n, $size) { + $table = array(); + $lli = 0; // LUT lower index + $lui = $size - 1; // LUT upper index + for ($count = 0; $count < 8192; ++$count) { + $bit_count = 0; + for ($bit_index = 0; $bit_index < 13; ++$bit_index) { + $bit_count += intval(($count & (1 << $bit_index)) != 0); + } + // if we don't have the right number of bits on, go on to the next value + if ($bit_count == $n) { + $reverse = ($this->imb_reverse_us($count) >> 3); + // if the reverse is less than count, we have already visited this pair before + if ($reverse >= $count) { + // If count is symmetric, place it at the first free slot from the end of the list. + // Otherwise, place it at the first free slot from the beginning of the list AND place $reverse ath the next free slot from the beginning of the list + if ($reverse == $count) { + $table[$lui] = $count; + --$lui; + } else { + $table[$lli] = $count; + ++$lli; + $table[$lli] = $reverse; + ++$lli; + } + } + } + } + return $table; + } + +} // end of class + +//============================================================+ +// END OF FILE +//============================================================+ +?> diff --git a/include/tcpdf/config/lang/eng.php b/include/tcpdf/config/lang/eng.php new file mode 100644 index 00000000..1f954d08 --- /dev/null +++ b/include/tcpdf/config/lang/eng.php @@ -0,0 +1,73 @@ + diff --git a/include/tcpdf/config/lang/ita.php b/include/tcpdf/config/lang/ita.php new file mode 100644 index 00000000..808a4a97 --- /dev/null +++ b/include/tcpdf/config/lang/ita.php @@ -0,0 +1,73 @@ + diff --git a/include/tcpdf/config/tcpdf_config.php b/include/tcpdf/config/tcpdf_config.php new file mode 100644 index 00000000..fd54454c --- /dev/null +++ b/include/tcpdf/config/tcpdf_config.php @@ -0,0 +1,264 @@ + + Bug 39085 - When loading the opposite search panel via ajax on the ListViews, call the index action instead of the ListView action to avoid touching pre-MVC code by accident. + +r56990 - 2010-06-16 13:05:36 -0700 (Wed, 16 Jun 2010) - kjing - snapshot "Mango" svn branch to a new one for GitHub sync + +r56989 - 2010-06-16 13:01:33 -0700 (Wed, 16 Jun 2010) - kjing - defunt "Mango" svn dev branch before github cutover + +r55980 - 2010-04-19 13:31:28 -0700 (Mon, 19 Apr 2010) - kjing - create Mango (6.1) based on windex + +r51719 - 2009-10-22 10:18:00 -0700 (Thu, 22 Oct 2009) - mitani - Converted to Build 3 tags and updated the build system + +r51634 - 2009-10-19 13:32:22 -0700 (Mon, 19 Oct 2009) - mitani - Windex is the branch for Sugar Sales 1.0 development + +r50375 - 2009-08-24 18:07:43 -0700 (Mon, 24 Aug 2009) - dwong - branch kobe2 from tokyo r50372 + +r46451 - 2009-04-23 16:57:40 -0700 (Thu, 23 Apr 2009) - jenny - tcpdf initial checkin. + + +*/ + + +//============================================================+ +// File name : tcpdf_config.php +// Begin : 2004-06-11 +// Last Update : 2009-03-18 +// +// Description : Configuration file for TCPDF. +// +// Author: Nicola Asuni +// +// (c) Copyright: +// Nicola Asuni +// Tecnick.com s.r.l. +// Via Della Pace, 11 +// 09044 Quartucciu (CA) +// ITALY +// www.tecnick.com +// info@tecnick.com +//============================================================+ + +/** + * Configuration file for TCPDF. + * @author Nicola Asuni + * @copyright 2004-2008 Nicola Asuni - Tecnick.com S.r.l (www.tecnick.com) Via Della Pace, 11 - 09044 - Quartucciu (CA) - ITALY - www.tecnick.com - info@tecnick.com + * @package com.tecnick.tcpdf + * @version 4.0.014 + * @link http://tcpdf.sourceforge.net + * @license http://www.gnu.org/copyleft/lesser.html LGPL + * @since 2004-10-27 + */ + +// If you define the constant K_TCPDF_EXTERNAL_CONFIG, the following settings will be ignored. + +if (!defined('K_TCPDF_EXTERNAL_CONFIG')) { + + // DOCUMENT_ROOT fix for IIS Webserver + if ((!isset($_SERVER['DOCUMENT_ROOT'])) OR (empty($_SERVER['DOCUMENT_ROOT']))) { + if(isset($_SERVER['SCRIPT_FILENAME'])) { + $_SERVER['DOCUMENT_ROOT'] = str_replace( '\\', '/', substr($_SERVER['SCRIPT_FILENAME'], 0, 0-strlen($_SERVER['PHP_SELF']))); + } elseif(isset($_SERVER['PATH_TRANSLATED'])) { + $_SERVER['DOCUMENT_ROOT'] = str_replace( '\\', '/', substr(str_replace('\\\\', '\\', $_SERVER['PATH_TRANSLATED']), 0, 0-strlen($_SERVER['PHP_SELF']))); + } else { + // define here your DOCUMENT_ROOT path if the previous fails + $_SERVER['DOCUMENT_ROOT'] = '/var/www'; + } + } + + // Automatic calculation for the following K_PATH_MAIN constant + $k_path_main = str_replace( '\\', '/', realpath(substr(dirname(__FILE__), 0, 0-strlen('config')))); + if (substr($k_path_main, -1) != '/') { + $k_path_main .= '/'; + } + + /** + * Installation path (/var/www/tcpdf/). + * By default it is automatically calculated but you can also set it as a fixed string to improve performances. + */ + define ('K_PATH_MAIN', $k_path_main); + + // Automatic calculation for the following K_PATH_URL constant + if (isset($_SERVER['HTTP_HOST']) AND (!empty($_SERVER['HTTP_HOST']))) { + if(isset($_SERVER['HTTPS']) AND (!empty($_SERVER['HTTPS'])) AND strtolower($_SERVER['HTTPS'])!='off') { + $k_path_url = 'https://'; + } else { + $k_path_url = 'http://'; + } + $k_path_url .= $_SERVER['HTTP_HOST']; + $k_path_url .= str_replace( '\\', '/', substr($_SERVER['PHP_SELF'], 0, -24)); + } + + /** + * URL path to tcpdf installation folder (http://localhost/tcpdf/). + * By default it is automatically calculated but you can also set it as a fixed string to improve performances. + */ + define ('K_PATH_URL', $k_path_url); + + /** + * path for PDF fonts + * use K_PATH_MAIN.'fonts/old/' for old non-UTF8 fonts + */ + define ('K_PATH_FONTS', K_PATH_MAIN.'fonts/'); + + /** + * cache directory for temporary files (full path) + */ + define ('K_PATH_CACHE', K_PATH_MAIN.'cache/'); + + /** + * cache directory for temporary files (url path) + */ + define ('K_PATH_URL_CACHE', K_PATH_URL.'cache/'); + + /** + *images directory + */ + define ('K_PATH_IMAGES', K_PATH_MAIN.'images/'); + + /** + * blank image + */ + define ('K_BLANK_IMAGE', K_PATH_IMAGES.'_blank.png'); + + /** + * page format + */ + define ('PDF_PAGE_FORMAT', 'A4'); + + /** + * page orientation (P=portrait, L=landscape) + */ + define ('PDF_PAGE_ORIENTATION', 'P'); + + /** + * document creator + */ + define ('PDF_CREATOR', 'TCPDF'); + + /** + * document author + */ + define ('PDF_AUTHOR', 'TCPDF'); + + /** + * header title + */ + define ('PDF_HEADER_TITLE', 'TCPDF Example'); + + /** + * header description string + */ + define ('PDF_HEADER_STRING', "by Nicola Asuni - Tecnick.com\nwww.tcpdf.org"); + + /** + * image logo + */ + define ('PDF_HEADER_LOGO', 'tcpdf_logo.jpg'); + + /** + * header logo image width [mm] + */ + define ('PDF_HEADER_LOGO_WIDTH', 30); + + /** + * document unit of measure [pt=point, mm=millimeter, cm=centimeter, in=inch] + */ + define ('PDF_UNIT', 'mm'); + + /** + * header margin + */ + define ('PDF_MARGIN_HEADER', 5); + + /** + * footer margin + */ + define ('PDF_MARGIN_FOOTER', 10); + + /** + * top margin + */ + define ('PDF_MARGIN_TOP', 27); + + /** + * bottom margin + */ + define ('PDF_MARGIN_BOTTOM', 25); + + /** + * left margin + */ + define ('PDF_MARGIN_LEFT', 15); + + /** + * right margin + */ + define ('PDF_MARGIN_RIGHT', 15); + + /** + * default main font name + */ + define ('PDF_FONT_NAME_MAIN', 'helvetica'); + + /** + * default main font size + */ + define ('PDF_FONT_SIZE_MAIN', 10); + + /** + * default data font name + */ + define ('PDF_FONT_NAME_DATA', 'helvetica'); + + /** + * default data font size + */ + define ('PDF_FONT_SIZE_DATA', 8); + + /** + * default monospaced font name + */ + define ('PDF_FONT_MONOSPACED', 'courier'); + + /** + * Ratio used to scale the images + */ + define ('PDF_IMAGE_SCALE_RATIO', 4); + + /** + * magnification factor for titles + */ + define('HEAD_MAGNIFICATION', 1.1); + + /** + * height of cell repect font height + */ + define('K_CELL_HEIGHT_RATIO', 1.25); + + /** + * title magnification respect main font size + */ + define('K_TITLE_MAGNIFICATION', 1.3); + + /** + * reduction factor for small font + */ + define('K_SMALL_RATIO', 2/3); + + /** + * if true allows to call TCPDF methods using HTML syntax + * IMPORTANT: For security reason, disable this feature if you are printing user HTML content. + */ + define('K_TCPDF_CALLS_IN_HTML', true); +} + +//============================================================+ +// END OF FILE +//============================================================+ +?> diff --git a/include/tcpdf/config/tcpdf_config_alt.php b/include/tcpdf/config/tcpdf_config_alt.php new file mode 100644 index 00000000..56479d6f --- /dev/null +++ b/include/tcpdf/config/tcpdf_config_alt.php @@ -0,0 +1,259 @@ + + Bug 39085 - When loading the opposite search panel via ajax on the ListViews, call the index action instead of the ListView action to avoid touching pre-MVC code by accident. + +r56990 - 2010-06-16 13:05:36 -0700 (Wed, 16 Jun 2010) - kjing - snapshot "Mango" svn branch to a new one for GitHub sync + +r56989 - 2010-06-16 13:01:33 -0700 (Wed, 16 Jun 2010) - kjing - defunt "Mango" svn dev branch before github cutover + +r55980 - 2010-04-19 13:31:28 -0700 (Mon, 19 Apr 2010) - kjing - create Mango (6.1) based on windex + +r51719 - 2009-10-22 10:18:00 -0700 (Thu, 22 Oct 2009) - mitani - Converted to Build 3 tags and updated the build system + +r51634 - 2009-10-19 13:32:22 -0700 (Mon, 19 Oct 2009) - mitani - Windex is the branch for Sugar Sales 1.0 development + +r50375 - 2009-08-24 18:07:43 -0700 (Mon, 24 Aug 2009) - dwong - branch kobe2 from tokyo r50372 + +r46451 - 2009-04-23 16:57:40 -0700 (Thu, 23 Apr 2009) - jenny - tcpdf initial checkin. + + +*/ + + +//============================================================+ +// File name : tcpdf_config.php +// Begin : 2004-06-11 +// Last Update : 2009-03-18 +// +// Description : Alternative configuration file for TCPDF. +// +// Author: Nicola Asuni +// +// (c) Copyright: +// Nicola Asuni +// Tecnick.com s.r.l. +// Via Della Pace, 11 +// 09044 Quartucciu (CA) +// ITALY +// www.tecnick.com +// info@tecnick.com +//============================================================+ + +/** + * Alternative configuration file for TCPDF. + * @author Nicola Asuni + * @copyright 2004-2008 Nicola Asuni - Tecnick.com S.r.l (www.tecnick.com) Via Della Pace, 11 - 09044 - Quartucciu (CA) - ITALY - www.tecnick.com - info@tecnick.com + * @package com.tecnick.tcpdf + * @version 4.0.014 + * @link http://tcpdf.sourceforge.net + * @license http://www.gnu.org/copyleft/lesser.html LGPL + * @since 2004-10-27 + */ + +// DOCUMENT_ROOT fix for IIS Webserver +if ((!isset($_SERVER['DOCUMENT_ROOT'])) OR (empty($_SERVER['DOCUMENT_ROOT']))) { + if(isset($_SERVER['SCRIPT_FILENAME'])) { + $_SERVER['DOCUMENT_ROOT'] = str_replace( '\\', '/', substr($_SERVER['SCRIPT_FILENAME'], 0, 0-strlen($_SERVER['PHP_SELF']))); + } elseif(isset($_SERVER['PATH_TRANSLATED'])) { + $_SERVER['DOCUMENT_ROOT'] = str_replace( '\\', '/', substr(str_replace('\\\\', '\\', $_SERVER['PATH_TRANSLATED']), 0, 0-strlen($_SERVER['PHP_SELF']))); + } else { + // define here your DOCUMENT_ROOT path if the previous fails + $_SERVER['DOCUMENT_ROOT'] = '/var/www'; + } +} + +// Automatic calculation for the following K_PATH_MAIN constant +$k_path_main = str_replace( '\\', '/', realpath(substr(dirname(__FILE__), 0, 0-strlen('config')))); +if (substr($k_path_main, -1) != '/') { + $k_path_main .= '/'; +} + +/** + * Installation path (/var/www/tcpdf/). + * By default it is automatically calculated but you can also set it as a fixed string to improve performances. + */ +define ('K_PATH_MAIN', $k_path_main); + +// Automatic calculation for the following K_PATH_URL constant +if (isset($_SERVER['HTTP_HOST']) AND (!empty($_SERVER['HTTP_HOST']))) { + if(isset($_SERVER['HTTPS']) AND (!empty($_SERVER['HTTPS'])) AND strtolower($_SERVER['HTTPS'])!='off') { + $k_path_url = 'https://'; + } else { + $k_path_url = 'http://'; + } + $k_path_url .= $_SERVER['HTTP_HOST']; + $k_path_url .= str_replace( '\\', '/', substr($_SERVER['PHP_SELF'], 0, -24)); +} + +/** + * URL path to tcpdf installation folder (http://localhost/tcpdf/). + * By default it is automatically calculated but you can also set it as a fixed string to improve performances.. + */ +define ('K_PATH_URL', $k_path_url); + +/** + * path for PDF fonts + * use K_PATH_MAIN.'fonts/old/' for old non-UTF8 fonts + */ +define ('K_PATH_FONTS', K_PATH_MAIN.'fonts/'); + +/** + * cache directory for temporary files (full path) + */ +define ('K_PATH_CACHE', K_PATH_MAIN.'cache/'); + +/** + * cache directory for temporary files (url path) + */ +define ('K_PATH_URL_CACHE', K_PATH_URL.'cache/'); + +/** + *images directory + */ +define ('K_PATH_IMAGES', K_PATH_MAIN.'images/'); + +/** + * blank image + */ +define ('K_BLANK_IMAGE', K_PATH_IMAGES.'_blank.png'); + +/** + * page format + */ +define ('PDF_PAGE_FORMAT', 'A4'); + +/** + * page orientation (P=portrait, L=landscape) + */ +define ('PDF_PAGE_ORIENTATION', 'P'); + +/** + * document creator + */ +define ('PDF_CREATOR', 'TCPDF'); + +/** + * document author + */ +define ('PDF_AUTHOR', 'TCPDF'); + +/** + * header title + */ +define ('PDF_HEADER_TITLE', 'TCPDF Example'); + +/** + * header description string + */ +define ('PDF_HEADER_STRING', "by Nicola Asuni - Tecnick.com\nwww.tcpdf.org"); + +/** + * image logo + */ +define ('PDF_HEADER_LOGO', 'tcpdf_logo.jpg'); + +/** + * header logo image width [mm] + */ +define ('PDF_HEADER_LOGO_WIDTH', 30); + +/** + * document unit of measure [pt=point, mm=millimeter, cm=centimeter, in=inch] + */ +define ('PDF_UNIT', 'mm'); + +/** + * header margin + */ +define ('PDF_MARGIN_HEADER', 5); + +/** + * footer margin + */ +define ('PDF_MARGIN_FOOTER', 10); + +/** + * top margin + */ +define ('PDF_MARGIN_TOP', 27); + +/** + * bottom margin + */ +define ('PDF_MARGIN_BOTTOM', 25); + +/** + * left margin + */ +define ('PDF_MARGIN_LEFT', 15); + +/** + * right margin + */ +define ('PDF_MARGIN_RIGHT', 15); + +/** + * default main font name + */ +define ('PDF_FONT_NAME_MAIN', 'helvetica'); + +/** + * default main font size + */ +define ('PDF_FONT_SIZE_MAIN', 10); + +/** + * default data font name + */ +define ('PDF_FONT_NAME_DATA', 'helvetica'); + +/** + * default data font size + */ +define ('PDF_FONT_SIZE_DATA', 8); + +/** + * default monospaced font name + */ +define ('PDF_FONT_MONOSPACED', 'courier'); + +/** + * Ratio used to scale the images + */ +define ('PDF_IMAGE_SCALE_RATIO', 4); + +/** + * magnification factor for titles + */ +define('HEAD_MAGNIFICATION', 1.1); + +/** + * height of cell repect font height + */ +define('K_CELL_HEIGHT_RATIO', 1.25); + +/** + * title magnification respect main font size + */ +define('K_TITLE_MAGNIFICATION', 1.3); + +/** + * reduction factor for small font + */ +define('K_SMALL_RATIO', 2/3); + +/** + * if true allows to call TCPDF methods using HTML syntax + * IMPORTANT: For security reason, disable this feature if you are printing user HTML content. + */ +define('K_TCPDF_CALLS_IN_HTML', true); + +//============================================================+ +// END OF FILE +//============================================================+ +?> diff --git a/include/tcpdf/fonts/uni2cid_ac15.php b/include/tcpdf/fonts/uni2cid_ac15.php new file mode 100644 index 00000000..4c8bb70e --- /dev/null +++ b/include/tcpdf/fonts/uni2cid_ac15.php @@ -0,0 +1,23636 @@ +1, +33=>2, +34=>3, +35=>4, +36=>5, +37=>6, +38=>7, +39=>8, +40=>9, +41=>10, +42=>11, +43=>12, +44=>13, +45=>14, +46=>15, +47=>16, +48=>17, +49=>18, +50=>19, +51=>20, +52=>21, +53=>22, +54=>23, +55=>24, +56=>25, +57=>26, +58=>27, +59=>28, +60=>29, +61=>30, +62=>31, +63=>32, +64=>33, +65=>34, +66=>35, +67=>36, +68=>37, +69=>38, +70=>39, +71=>40, +72=>41, +73=>42, +74=>43, +75=>44, +76=>45, +77=>46, +78=>47, +79=>48, +80=>49, +81=>50, +82=>51, +83=>52, +84=>53, +85=>54, +86=>55, +87=>56, +88=>57, +89=>58, +90=>59, +91=>60, +92=>61, +93=>62, +94=>63, +95=>64, +96=>65, +97=>66, +98=>67, +99=>68, +100=>69, +101=>70, +102=>71, +103=>72, +104=>73, +105=>74, +106=>75, +107=>76, +108=>77, +109=>78, +110=>79, +111=>80, +112=>81, +113=>82, +114=>83, +115=>84, +116=>85, +117=>86, +118=>87, +119=>88, +120=>89, +121=>90, +122=>91, +123=>92, +124=>93, +125=>94, +126=>95, +12288=>99, +65292=>100, +12289=>101, +12290=>102, +65294=>103, +8226=>104, +8231=>104, +65307=>105, +65306=>106, +65311=>107, +65281=>108, +65072=>109, +8230=>110, +8943=>110, +8229=>111, +65104=>112, +65380=>113, +65105=>113, +65106=>114, +183=>115, +65108=>116, +65109=>117, +65110=>118, +65111=>119, +65372=>120, +8211=>121, +65073=>122, +8212=>123, +65288=>128, +65289=>129, +65077=>130, +65078=>131, +65371=>132, +65373=>133, +65079=>134, +65080=>135, +12308=>136, +12309=>137, +65081=>138, +65082=>139, +12304=>140, +12305=>141, +65083=>142, +65084=>143, +12298=>144, +12299=>145, +65085=>146, +65086=>147, +12296=>148, +12297=>149, +65087=>150, +65088=>151, +12300=>152, +12301=>153, +65089=>154, +65090=>155, +12302=>156, +12303=>157, +65091=>158, +65092=>159, +65113=>160, +65114=>161, +65115=>162, +65116=>163, +65117=>164, +65118=>165, +8216=>166, +8217=>167, +8220=>168, +8221=>169, +12317=>170, +12318=>171, +8245=>172, +8242=>173, +65283=>174, +65286=>175, +65290=>176, +8251=>177, +167=>178, +12291=>179, +9675=>180, +9679=>181, +9651=>182, +9650=>183, +9678=>184, +9734=>185, +9733=>186, +9671=>187, +9670=>188, +9633=>189, +9632=>190, +9661=>191, +9660=>192, +12963=>193, +8453=>194, +175=>195, +772=>195, +8254=>195, +65507=>196, +65343=>197, +717=>198, +65097=>199, +65098=>200, +65101=>201, +65102=>202, +65099=>203, +65100=>204, +65119=>205, +65120=>206, +65121=>207, +65291=>208, +65293=>209, +215=>210, +247=>211, +177=>212, +8730=>213, +65308=>214, +65310=>215, +65309=>216, +8806=>217, +8807=>218, +8800=>219, +8734=>220, +8786=>221, +8801=>222, +65122=>223, +65123=>224, +65124=>225, +65125=>226, +65126=>227, +8764=>228, +65374=>228, +8745=>229, +8746=>230, +8869=>231, +8736=>232, +8735=>233, +8895=>234, +13266=>235, +13265=>236, +8747=>237, +8750=>238, +8757=>239, +8756=>240, +9792=>241, +9794=>242, +8853=>243, +9793=>243, +8857=>244, +9737=>244, +8593=>245, +8595=>246, +8594=>247, +8592=>248, +8598=>249, +8599=>250, +8601=>251, +8600=>252, +8741=>253, +8739=>254, +8725=>257, +65295=>257, +65128=>258, +65340=>258, +65284=>259, +165=>260, +65509=>260, +12306=>261, +162=>262, +65504=>262, +163=>263, +65505=>263, +65285=>264, +65312=>265, +8451=>266, +8457=>267, +65129=>268, +65130=>269, +65131=>270, +13269=>271, +13212=>272, +13213=>273, +13214=>274, +13262=>275, +13217=>276, +13198=>277, +13199=>278, +13252=>279, +176=>280, +20825=>281, +58834=>281, +20827=>282, +58835=>282, +20830=>283, +58837=>283, +20829=>284, +58836=>284, +20833=>285, +20835=>286, +21991=>287, +29929=>288, +58044=>288, +31950=>289, +58191=>289, +9601=>290, +9602=>291, +9603=>292, +9604=>293, +9605=>294, +9606=>295, +9607=>296, +9608=>297, +9615=>298, +9614=>299, +9613=>300, +9612=>301, +9611=>302, +9610=>303, +9609=>304, +9532=>305, +9524=>306, +9516=>307, +9508=>308, +9500=>309, +9620=>310, +9472=>311, +9474=>312, +9621=>313, +9484=>314, +9488=>315, +9492=>316, +9496=>317, +9581=>318, +9582=>319, +9584=>320, +9583=>321, +9552=>322, +9566=>323, +9578=>324, +9569=>325, +9698=>326, +9699=>327, +9701=>328, +9700=>329, +9585=>330, +9586=>331, +9587=>332, +65296=>333, +65297=>334, +65298=>335, +65299=>336, +65300=>337, +65301=>338, +65302=>339, +65303=>340, +65304=>341, +65305=>342, +8544=>343, +8545=>344, +8546=>345, +8547=>346, +8548=>347, +8549=>348, +8550=>349, +8551=>350, +8552=>351, +8553=>352, +12321=>353, +12322=>354, +12323=>355, +12324=>356, +12325=>357, +12326=>358, +12327=>359, +12328=>360, +12329=>361, +12344=>362, +21316=>363, +57443=>363, +12345=>363, +12346=>364, +65313=>365, +65314=>366, +65315=>367, +65316=>368, +65317=>369, +65318=>370, +65319=>371, +65320=>372, +65321=>373, +65322=>374, +65323=>375, +65324=>376, +65325=>377, +65326=>378, +65327=>379, +65328=>380, +65329=>381, +65330=>382, +65331=>383, +65332=>384, +65333=>385, +65334=>386, +65335=>387, +65336=>388, +65337=>389, +65338=>390, +65345=>391, +65346=>392, +65347=>393, +65348=>394, +65349=>395, +65350=>396, +65351=>397, +65352=>398, +65353=>399, +65354=>400, +65355=>401, +65356=>402, +65357=>403, +65358=>404, +65359=>405, +65360=>406, +65361=>407, +65362=>408, +65363=>409, +65364=>410, +65365=>411, +65366=>412, +65367=>413, +65368=>414, +65369=>415, +65370=>416, +913=>417, +914=>418, +915=>419, +916=>420, +917=>421, +918=>422, +919=>423, +920=>424, +921=>425, +922=>426, +923=>427, +924=>428, +925=>429, +926=>430, +927=>431, +928=>432, +929=>433, +931=>434, +932=>435, +933=>436, +934=>437, +935=>438, +936=>439, +937=>440, +945=>441, +946=>442, +947=>443, +948=>444, +949=>445, +950=>446, +951=>447, +952=>448, +953=>449, +954=>450, +955=>451, +956=>452, +957=>453, +958=>454, +959=>455, +960=>456, +961=>457, +963=>458, +964=>459, +965=>460, +966=>461, +967=>462, +968=>463, +969=>464, +12549=>465, +12550=>466, +12551=>467, +12552=>468, +12553=>469, +12554=>470, +12555=>471, +12556=>472, +12557=>473, +12558=>474, +12559=>475, +12560=>476, +12561=>477, +12562=>478, +12563=>479, +12564=>480, +12565=>481, +12566=>482, +12567=>483, +12568=>484, +12569=>485, +12570=>486, +12571=>487, +12572=>488, +12573=>489, +12574=>490, +12575=>491, +12576=>492, +12577=>493, +12578=>494, +12579=>495, +12580=>496, +12581=>497, +12582=>498, +12583=>499, +12584=>500, +12585=>501, +729=>502, +714=>503, +711=>504, +780=>504, +715=>505, +9312=>506, +63153=>506, +9313=>507, +63154=>507, +9314=>508, +63155=>508, +9315=>509, +63156=>509, +9316=>510, +63157=>510, +9317=>511, +63158=>511, +9318=>512, +63159=>512, +9319=>513, +63160=>513, +9320=>514, +63161=>514, +9321=>515, +63162=>515, +9332=>516, +63163=>516, +9333=>517, +63164=>517, +9334=>518, +63165=>518, +9335=>519, +63166=>519, +9336=>520, +63167=>520, +9337=>521, +63168=>521, +9338=>522, +63169=>522, +9339=>523, +63170=>523, +9340=>524, +63171=>524, +9341=>525, +63172=>525, +8560=>526, +63173=>526, +8561=>527, +63174=>527, +8562=>528, +63175=>528, +8563=>529, +63176=>529, +8564=>530, +63177=>530, +8565=>531, +63178=>531, +8566=>532, +63179=>532, +8567=>533, +63180=>533, +8568=>534, +63181=>534, +8569=>535, +63182=>535, +20008=>536, +12033=>536, +20022=>537, +12034=>537, +63183=>537, +20031=>538, +12035=>538, +63184=>538, +12037=>539, +20101=>539, +63185=>539, +12039=>540, +20128=>540, +63186=>540, +20866=>541, +12044=>541, +63187=>541, +20886=>542, +12045=>542, +63188=>542, +20907=>543, +12046=>543, +63189=>543, +12051=>544, +21241=>544, +63190=>544, +12054=>545, +21304=>545, +63191=>545, +12057=>546, +21353=>546, +63192=>546, +12059=>547, +21430=>547, +63193=>547, +12065=>548, +12066=>548, +22786=>548, +22794=>548, +63194=>548, +12071=>549, +23424=>549, +63195=>549, +12078=>550, +24027=>550, +63196=>550, +24186=>551, +12083=>551, +63197=>551, +24191=>552, +12084=>552, +63198=>552, +24308=>553, +12085=>553, +24400=>554, +12089=>554, +63200=>554, +24417=>555, +12090=>555, +63201=>555, +12097=>556, +25908=>556, +63202=>556, +12102=>557, +26080=>557, +30098=>558, +63204=>558, +12135=>558, +30326=>559, +12136=>559, +12193=>560, +36789=>560, +63206=>560, +12202=>561, +38582=>561, +9216=>562, +9217=>563, +9218=>564, +9219=>565, +9220=>566, +9221=>567, +9222=>568, +9223=>569, +9224=>570, +9225=>571, +9226=>572, +9227=>573, +9228=>574, +9229=>575, +9230=>576, +9231=>577, +9232=>578, +9233=>579, +9234=>580, +9235=>581, +9236=>582, +9237=>583, +9238=>584, +9239=>585, +9240=>586, +9241=>587, +9242=>588, +9243=>589, +9244=>590, +9245=>591, +9246=>592, +9247=>593, +9249=>594, +12032=>595, +19968=>595, +12036=>596, +20057=>596, +19969=>597, +19971=>598, +20035=>599, +20061=>600, +20102=>601, +12038=>602, +20108=>602, +20154=>603, +12040=>603, +20799=>604, +12041=>604, +20837=>605, +12042=>605, +20843=>606, +12043=>606, +12047=>607, +20960=>607, +12049=>608, +20992=>608, +20993=>609, +12050=>610, +21147=>610, +12052=>611, +21269=>611, +21313=>612, +12055=>612, +21340=>613, +12056=>613, +12060=>614, +21448=>614, +19977=>615, +19979=>616, +19976=>617, +19978=>618, +20011=>619, +20024=>620, +20961=>621, +20037=>622, +20040=>623, +20063=>624, +20062=>625, +20110=>626, +20129=>627, +20800=>628, +64012=>628, +20995=>629, +21242=>630, +21315=>631, +21449=>632, +12061=>633, +21475=>633, +22303=>634, +12063=>634, +22763=>635, +12064=>635, +22805=>636, +12067=>636, +22823=>637, +12068=>637, +22899=>638, +12069=>638, +12070=>639, +23376=>639, +23377=>640, +23379=>641, +23544=>642, +12072=>642, +23567=>643, +12073=>643, +23586=>644, +12074=>644, +23608=>645, +12075=>645, +12077=>646, +23665=>646, +24029=>647, +24037=>648, +12079=>648, +12080=>649, +24049=>649, +24050=>650, +24051=>651, +24062=>652, +12081=>652, +24178=>653, +12082=>653, +24318=>654, +12086=>654, +24331=>655, +12087=>655, +24339=>656, +12088=>656, +25165=>657, +19985=>658, +19984=>659, +19981=>660, +20013=>661, +20016=>662, +20025=>663, +20043=>664, +23609=>665, +20104=>666, +20113=>667, +20117=>668, +20114=>669, +20116=>670, +20130=>671, +20161=>672, +20160=>673, +20163=>674, +20166=>675, +20167=>676, +20173=>677, +20170=>678, +20171=>679, +20164=>680, +20803=>681, +20801=>682, +20839=>683, +20845=>684, +20846=>685, +20844=>686, +20887=>687, +20982=>688, +20998=>689, +20999=>690, +21000=>691, +21243=>692, +21246=>693, +21247=>694, +21270=>695, +21305=>696, +21320=>697, +21319=>698, +21317=>699, +21342=>700, +21380=>701, +21451=>702, +21450=>703, +21453=>704, +22764=>705, +22825=>706, +22827=>707, +22826=>708, +22829=>709, +23380=>710, +23569=>711, +23588=>712, +23610=>713, +23663=>714, +24052=>715, +24187=>716, +24319=>717, +24340=>718, +24341=>719, +24515=>720, +12092=>720, +25096=>721, +12093=>721, +25142=>722, +12094=>722, +25163=>723, +12095=>723, +25166=>724, +12096=>725, +25903=>725, +25991=>726, +12098=>726, +26007=>727, +12099=>727, +26020=>728, +12100=>728, +26041=>729, +12101=>729, +26085=>730, +12103=>730, +26352=>731, +12104=>731, +26376=>732, +12105=>732, +26408=>733, +12106=>733, +27424=>734, +12107=>734, +27490=>735, +12108=>735, +27513=>736, +12109=>736, +27595=>737, +12111=>737, +27604=>738, +12112=>738, +27611=>739, +12113=>739, +27663=>740, +12114=>740, +27700=>741, +12116=>741, +28779=>742, +12117=>742, +29226=>743, +12118=>743, +29238=>744, +12119=>744, +29243=>745, +12120=>745, +29255=>746, +12122=>746, +29273=>747, +12123=>747, +29275=>748, +12124=>748, +29356=>749, +12125=>749, +29579=>750, +19993=>751, +19990=>752, +19989=>753, +19988=>754, +19992=>755, +20027=>756, +20045=>757, +20047=>758, +20046=>759, +20197=>760, +20184=>761, +20180=>762, +20181=>763, +20182=>764, +20183=>765, +20195=>766, +20196=>767, +20185=>768, +20190=>769, +20805=>770, +20804=>771, +20873=>772, +20874=>773, +20908=>774, +20985=>775, +20986=>776, +20984=>777, +21002=>778, +21152=>779, +21151=>780, +57435=>781, +21253=>781, +21254=>782, +21271=>783, +21277=>784, +20191=>785, +21322=>786, +21321=>787, +21345=>788, +21344=>789, +21359=>790, +21358=>791, +21435=>792, +21487=>793, +21476=>794, +21491=>795, +21484=>796, +21486=>797, +21481=>798, +21480=>799, +21500=>800, +21496=>801, +21493=>802, +21483=>803, +21478=>804, +21482=>805, +21490=>806, +21489=>807, +21488=>808, +21477=>809, +21485=>810, +21499=>811, +22235=>812, +22234=>813, +22806=>814, +22830=>815, +22833=>816, +22900=>817, +22902=>818, +23381=>819, +23427=>820, +23612=>821, +24040=>822, +24039=>823, +24038=>824, +24066=>825, +24067=>826, +24179=>827, +24188=>828, +24321=>829, +24344=>830, +24343=>831, +24517=>832, +25098=>833, +25171=>834, +25172=>835, +25170=>836, +25169=>837, +26021=>838, +26086=>839, +26414=>840, +26412=>841, +26410=>842, +26411=>843, +26413=>844, +27491=>845, +27597=>846, +27665=>847, +27664=>848, +27704=>849, +27713=>850, +27712=>851, +27710=>852, +29359=>853, +29572=>854, +12126=>854, +29577=>855, +12127=>855, +29916=>856, +12128=>856, +29926=>857, +12129=>857, +29976=>858, +12130=>858, +29983=>859, +12131=>859, +12132=>860, +29992=>860, +29993=>861, +12133=>862, +30000=>862, +30001=>863, +30002=>864, +30003=>865, +12134=>866, +30091=>866, +30333=>867, +12137=>867, +30382=>868, +12138=>868, +30399=>869, +12139=>869, +30446=>870, +12140=>870, +30683=>871, +12141=>871, +30690=>872, +12142=>872, +30707=>873, +12143=>873, +31034=>874, +12144=>874, +31166=>875, +12146=>875, +31348=>876, +12147=>876, +31435=>877, +12148=>877, +19998=>878, +19999=>879, +20050=>880, +20051=>881, +20073=>882, +20121=>883, +20132=>884, +20134=>885, +20133=>886, +20223=>887, +20233=>888, +20249=>889, +20234=>890, +20245=>891, +20237=>892, +20240=>893, +20241=>894, +20239=>895, +20210=>896, +20214=>897, +20219=>898, +20208=>899, +20211=>900, +20221=>901, +20225=>902, +20235=>903, +20809=>904, +20807=>905, +20806=>906, +20808=>907, +20840=>908, +20849=>909, +20877=>910, +20912=>911, +21015=>912, +21009=>913, +21010=>914, +21006=>915, +21014=>916, +21155=>917, +21256=>918, +21281=>919, +21280=>920, +21360=>921, +21361=>922, +21513=>923, +21519=>924, +21516=>925, +21514=>926, +21520=>927, +21505=>928, +21515=>929, +21508=>930, +21521=>931, +21517=>932, +21512=>933, +21507=>934, +21518=>935, +21510=>936, +21522=>937, +22240=>938, +22238=>939, +22237=>940, +22323=>941, +22320=>942, +22312=>943, +22317=>944, +22316=>945, +22319=>946, +22313=>947, +22809=>948, +22810=>949, +22839=>950, +22840=>951, +22916=>952, +22904=>953, +22915=>954, +22909=>955, +22905=>956, +22914=>957, +22913=>958, +23383=>959, +23384=>960, +23431=>961, +23432=>962, +23429=>963, +23433=>964, +23546=>965, +23574=>966, +23673=>967, +24030=>968, +24070=>969, +24182=>970, +24180=>971, +24335=>972, +24347=>973, +24537=>974, +24534=>975, +25102=>976, +25100=>977, +25101=>978, +25104=>979, +25187=>980, +25179=>981, +25176=>982, +25910=>983, +26089=>984, +26088=>985, +26092=>986, +26093=>987, +26354=>988, +26355=>989, +26377=>990, +26429=>991, +26420=>992, +26417=>993, +26421=>994, +27425=>995, +27492=>996, +27515=>997, +27670=>998, +27741=>999, +27735=>1000, +27737=>1001, +27743=>1002, +27744=>1003, +27728=>1004, +27733=>1005, +27745=>1006, +27739=>1007, +27725=>1008, +27726=>1009, +28784=>1010, +29279=>1011, +29277=>1012, +30334=>1013, +31481=>1014, +12149=>1014, +31859=>1015, +12150=>1015, +31992=>1016, +12151=>1016, +32566=>1017, +12152=>1017, +32650=>1018, +12154=>1018, +32701=>1019, +12155=>1019, +32769=>1020, +12156=>1020, +32771=>1021, +32780=>1022, +12157=>1022, +32786=>1023, +12158=>1023, +32819=>1024, +12159=>1024, +32895=>1025, +12160=>1025, +32905=>1026, +12161=>1026, +32907=>1027, +32908=>1028, +33251=>1029, +12162=>1029, +33258=>1030, +12163=>1030, +33267=>1031, +12164=>1031, +33276=>1032, +12165=>1032, +33292=>1033, +12166=>1033, +33307=>1034, +12167=>1034, +33311=>1035, +12168=>1035, +33390=>1036, +12169=>1036, +33394=>1037, +12170=>1037, +33406=>1038, +34411=>1039, +12173=>1039, +34880=>1040, +12174=>1040, +34892=>1041, +12175=>1041, +34915=>1042, +12176=>1042, +35199=>1043, +38433=>1044, +20018=>1045, +20136=>1046, +20301=>1047, +20303=>1048, +20295=>1049, +20311=>1050, +20318=>1051, +20276=>1052, +20315=>1053, +20309=>1054, +20272=>1055, +20304=>1056, +20305=>1057, +20285=>1058, +20282=>1059, +20280=>1060, +20291=>1061, +20308=>1062, +20284=>1063, +20294=>1064, +20323=>1065, +20316=>1066, +20320=>1067, +20271=>1068, +20302=>1069, +20278=>1070, +20313=>1071, +20317=>1072, +20296=>1073, +20314=>1074, +20812=>1075, +20811=>1076, +20813=>1077, +20853=>1078, +20918=>1079, +20919=>1080, +21029=>1081, +21028=>1082, +21033=>1083, +21034=>1084, +21032=>1085, +21163=>1086, +21161=>1087, +21162=>1088, +21164=>1089, +21283=>1090, +21363=>1091, +21365=>1092, +21533=>1093, +21549=>1094, +21534=>1095, +21566=>1096, +21542=>1097, +21582=>1098, +21543=>1099, +21574=>1100, +21571=>1101, +21555=>1102, +21576=>1103, +21570=>1104, +21531=>1105, +21545=>1106, +21578=>1107, +21561=>1108, +21563=>1109, +21560=>1110, +21550=>1111, +21557=>1112, +21558=>1113, +21536=>1114, +21564=>1115, +21568=>1116, +21553=>1117, +21547=>1118, +21535=>1119, +21548=>1120, +22250=>1121, +22256=>1122, +22244=>1123, +22251=>1124, +22346=>1125, +22353=>1126, +22336=>1127, +22349=>1128, +22343=>1129, +22350=>1130, +22334=>1131, +22352=>1132, +22351=>1133, +22331=>1134, +22767=>1135, +22846=>1136, +22941=>1137, +22930=>1138, +22952=>1139, +22942=>1140, +22947=>1141, +22937=>1142, +22934=>1143, +22925=>1144, +22948=>1145, +22931=>1146, +22922=>1147, +22949=>1148, +23389=>1149, +23388=>1150, +23386=>1151, +23387=>1152, +23436=>1153, +23435=>1154, +23439=>1155, +23596=>1156, +23616=>1157, +23617=>1158, +23615=>1159, +23614=>1160, +23696=>1161, +23697=>1162, +23700=>1163, +23692=>1164, +24043=>1165, +24076=>1166, +24207=>1167, +24199=>1168, +24202=>1169, +24311=>1170, +24324=>1171, +24351=>1172, +24420=>1173, +24418=>1174, +24439=>1175, +24441=>1176, +24536=>1177, +24524=>1178, +24535=>1179, +24525=>1180, +24561=>1181, +24555=>1182, +24568=>1183, +24554=>1184, +25106=>1185, +25105=>1186, +25220=>1187, +25239=>1188, +25238=>1189, +25216=>1190, +25206=>1191, +25225=>1192, +25197=>1193, +25226=>1194, +25212=>1195, +25214=>1196, +25209=>1197, +25203=>1198, +25234=>1199, +25199=>1200, +25240=>1201, +25198=>1202, +25237=>1203, +25235=>1204, +25233=>1205, +25222=>1206, +25913=>1207, +25915=>1208, +25912=>1209, +26097=>1210, +26356=>1211, +26463=>1212, +26446=>1213, +26447=>1214, +26448=>1215, +26449=>1216, +26460=>1217, +26454=>1218, +26462=>1219, +57801=>1219, +26441=>1220, +26438=>1221, +26464=>1222, +26451=>1223, +26455=>1224, +27493=>1225, +27599=>1226, +27714=>1227, +27742=>1228, +27801=>1229, +27777=>1230, +27784=>1231, +27785=>1232, +27781=>1233, +27803=>1234, +27754=>1235, +27770=>1236, +27792=>1237, +27760=>1238, +27788=>1239, +27752=>1240, +27798=>1241, +27794=>1242, +27773=>1243, +27779=>1244, +27762=>1245, +27774=>1246, +27764=>1247, +27782=>1248, +27766=>1249, +27789=>1250, +27796=>1251, +27800=>1252, +27778=>1253, +28790=>1254, +28796=>1255, +28797=>1256, +28792=>1257, +29282=>1258, +29281=>1259, +29280=>1260, +29380=>1261, +29378=>1262, +29590=>1263, +29996=>1264, +29995=>1265, +30007=>1266, +30008=>1267, +30338=>1268, +30447=>1269, +30691=>1270, +31169=>1271, +31168=>1272, +31167=>1273, +31350=>1274, +31995=>1275, +32597=>1276, +32918=>1277, +32915=>1278, +32925=>1279, +32920=>1280, +32923=>1281, +32922=>1282, +32946=>1283, +33391=>1284, +33426=>1285, +33419=>1286, +33421=>1287, +35211=>1288, +12178=>1288, +35282=>1289, +12179=>1289, +35328=>1290, +12180=>1290, +35895=>1291, +12181=>1291, +35910=>1292, +12182=>1292, +35925=>1293, +12183=>1293, +35997=>1294, +12185=>1294, +36196=>1295, +12186=>1295, +36208=>1296, +12187=>1296, +36275=>1297, +12188=>1297, +36523=>1298, +12189=>1298, +36554=>1299, +12190=>1299, +36763=>1300, +12191=>1300, +36784=>1301, +12192=>1301, +36802=>1302, +36806=>1303, +36805=>1304, +36804=>1305, +24033=>1306, +12194=>1307, +37009=>1307, +37026=>1308, +37034=>1309, +37030=>1310, +37027=>1311, +37193=>1312, +12195=>1312, +37318=>1313, +12196=>1313, +37324=>1314, +12197=>1314, +38450=>1315, +38446=>1316, +38449=>1317, +38442=>1318, +38444=>1319, +20006=>1320, +20054=>1321, +20083=>1322, +20107=>1323, +20123=>1324, +20126=>1325, +20139=>1326, +20140=>1327, +20335=>1328, +20381=>1329, +20365=>1330, +20339=>1331, +20351=>1332, +20332=>1333, +20379=>1334, +20363=>1335, +20358=>1336, +20355=>1337, +20336=>1338, +20341=>1339, +20360=>1340, +20329=>1341, +20347=>1342, +20374=>1343, +20350=>1344, +20367=>1345, +20369=>1346, +20346=>1347, +20820=>1348, +20818=>1349, +20821=>1350, +20841=>1351, +20855=>1352, +20854=>1353, +20856=>1354, +20925=>1355, +20989=>1356, +21051=>1357, +21048=>1358, +21047=>1359, +21050=>1360, +21040=>1361, +21038=>1362, +21046=>1363, +21057=>1364, +21182=>1365, +21179=>1366, +21330=>1367, +21332=>1368, +21331=>1369, +21329=>1370, +21350=>1371, +21367=>1372, +21368=>1373, +21369=>1374, +21462=>1375, +21460=>1376, +21463=>1377, +21619=>1378, +21621=>1379, +21654=>1380, +21624=>1381, +21653=>1382, +21632=>1383, +21627=>1384, +21623=>1385, +21636=>1386, +21650=>1387, +21638=>1388, +21628=>1389, +21648=>1390, +21617=>1391, +21622=>1392, +21644=>1393, +21658=>1394, +21602=>1395, +21608=>1396, +21643=>1397, +21629=>1398, +21646=>1399, +22266=>1400, +22403=>1401, +22391=>1402, +22378=>1403, +22377=>1404, +22369=>1405, +22374=>1406, +22372=>1407, +22396=>1408, +22812=>1409, +22857=>1410, +22855=>1411, +22856=>1412, +22852=>1413, +22868=>1414, +22974=>1415, +22971=>1416, +22996=>1417, +22969=>1418, +22958=>1419, +22993=>1420, +22982=>1421, +22992=>1422, +22989=>1423, +22987=>1424, +22995=>1425, +22986=>1426, +22959=>1427, +22963=>1428, +22994=>1429, +22981=>1430, +23391=>1431, +23396=>1432, +23395=>1433, +23447=>1434, +23450=>1435, +23448=>1436, +23452=>1437, +23449=>1438, +23451=>1439, +23578=>1440, +23624=>1441, +23621=>1442, +23622=>1443, +23735=>1444, +23713=>1445, +23736=>1446, +23721=>1447, +23723=>1448, +23729=>1449, +23731=>1450, +24088=>1451, +24090=>1452, +24086=>1453, +24085=>1454, +24091=>1455, +24081=>1456, +24184=>1457, +24218=>1458, +24215=>1459, +24220=>1460, +24213=>1461, +24214=>1462, +24310=>1463, +24358=>1464, +24359=>1465, +24361=>1466, +24448=>1467, +24449=>1468, +24447=>1469, +24444=>1470, +24541=>1471, +24544=>1472, +24573=>1473, +24565=>1474, +24575=>1475, +24591=>1476, +24596=>1477, +24623=>1478, +24629=>1479, +24598=>1480, +24618=>1481, +24597=>1482, +24609=>1483, +24615=>1484, +24617=>1485, +24619=>1486, +24603=>1487, +25110=>1488, +25109=>1489, +25151=>1490, +25150=>1491, +25152=>1492, +25215=>1493, +25289=>1494, +25292=>1495, +25284=>1496, +25279=>1497, +25282=>1498, +25273=>1499, +25298=>1500, +25307=>1501, +25259=>1502, +25299=>1503, +25300=>1504, +25291=>1505, +25288=>1506, +25256=>1507, +25277=>1508, +25276=>1509, +25296=>1510, +60582=>1510, +25305=>1511, +25287=>1512, +25293=>1513, +25269=>1514, +25306=>1515, +25265=>1516, +25304=>1517, +25302=>1518, +25303=>1519, +25286=>1520, +25260=>1521, +25294=>1522, +61010=>1522, +25918=>1523, +26023=>1524, +26044=>1525, +26106=>1526, +26132=>1527, +26131=>1528, +26124=>1529, +26118=>1530, +26114=>1531, +26126=>1532, +26112=>1533, +26127=>1534, +26133=>1535, +26122=>1536, +26119=>1537, +26381=>1538, +26379=>1539, +26477=>1540, +26507=>1541, +26517=>1542, +26481=>1543, +26524=>1544, +26483=>1545, +26487=>1546, +26503=>1547, +26525=>1548, +26519=>1549, +26479=>1550, +26480=>1551, +26495=>1552, +26505=>1553, +26494=>1554, +26512=>1555, +26485=>1556, +26522=>1557, +26515=>1558, +26492=>1559, +26474=>1560, +26482=>1561, +27427=>1562, +27494=>1563, +27495=>1564, +27519=>1565, +27667=>1566, +27675=>1567, +27875=>1568, +27880=>1569, +27891=>1570, +27825=>1571, +27852=>1572, +27877=>1573, +27827=>1574, +27837=>1575, +27838=>1576, +27836=>1577, +27874=>1578, +27819=>1579, +27861=>1580, +27859=>1581, +27832=>1582, +27844=>1583, +27833=>1584, +27841=>1585, +27822=>1586, +27863=>1587, +27845=>1588, +27889=>1589, +27839=>1590, +27835=>1591, +27873=>1592, +27867=>1593, +27850=>1594, +27820=>1595, +27887=>1596, +27868=>1597, +27862=>1598, +27872=>1599, +28821=>1600, +28814=>1601, +28818=>1602, +28810=>1603, +28825=>1604, +29228=>1605, +29229=>1606, +29240=>1607, +29256=>1608, +29287=>1609, +29289=>1610, +29376=>1611, +29390=>1612, +29401=>1613, +29399=>1614, +29392=>1615, +29609=>1616, +29608=>1617, +29599=>1618, +29611=>1619, +29605=>1620, +30013=>1621, +30109=>1622, +30105=>1623, +30106=>1624, +30340=>1625, +30402=>1626, +30450=>1627, +30452=>1628, +30693=>1629, +30717=>1630, +31038=>1631, +31040=>1632, +31041=>1633, +31177=>1634, +31176=>1635, +31354=>1636, +31353=>1637, +31482=>1638, +31998=>1639, +32596=>1640, +32652=>1641, +32651=>1642, +32773=>1643, +58236=>1643, +32954=>1644, +32933=>1645, +32930=>1646, +32945=>1647, +32929=>1648, +32939=>1649, +32937=>1650, +32948=>1651, +32938=>1652, +32943=>1653, +33253=>1654, +33278=>1655, +33293=>1656, +33459=>1657, +33437=>1658, +33433=>1659, +33453=>1660, +33469=>1661, +33439=>1662, +33465=>1663, +33457=>1664, +33452=>1665, +33445=>1666, +33455=>1667, +33464=>1668, +33443=>1669, +33456=>1670, +33470=>1671, +33463=>1672, +34382=>1673, +34417=>1674, +21021=>1675, +34920=>1676, +36555=>1677, +36814=>1678, +36820=>1679, +36817=>1680, +37045=>1681, +37048=>1682, +37041=>1683, +37046=>1684, +37319=>1685, +37329=>1686, +12198=>1686, +38263=>1687, +12199=>1687, +38272=>1688, +12200=>1688, +38428=>1689, +12201=>1689, +38464=>1690, +38463=>1691, +38459=>1692, +38468=>1693, +38466=>1694, +38585=>1695, +12203=>1695, +38632=>1696, +12204=>1696, +38738=>1697, +12206=>1698, +38750=>1698, +20127=>1699, +20141=>1700, +20142=>1701, +20449=>1702, +20405=>1703, +20399=>1704, +20415=>1705, +20448=>1706, +20433=>1707, +20431=>1708, +20445=>1709, +20419=>1710, +20406=>1711, +20440=>1712, +20447=>1713, +20426=>1714, +20439=>1715, +20398=>1716, +20432=>1717, +20420=>1718, +20418=>1719, +20442=>1720, +20430=>1721, +20446=>1722, +20407=>1723, +20823=>1724, +20882=>1725, +20881=>1726, +20896=>1727, +21070=>1728, +21059=>1729, +21066=>1730, +21069=>1731, +21068=>1732, +21067=>1733, +21063=>1734, +21191=>1735, +21193=>1736, +21187=>1737, +21185=>1738, +21261=>1739, +21335=>1740, +21371=>1741, +21402=>1742, +21467=>1743, +21676=>1744, +21696=>1745, +21672=>1746, +21710=>1747, +21705=>1748, +21688=>1749, +21670=>1750, +21683=>1751, +21703=>1752, +21698=>1753, +21693=>1754, +21674=>1755, +21697=>1756, +21700=>1757, +21704=>1758, +21679=>1759, +21675=>1760, +21681=>1761, +21691=>1762, +21673=>1763, +21671=>1764, +21695=>1765, +22271=>1766, +22402=>1767, +22411=>1768, +22432=>1769, +22435=>1770, +22434=>1771, +22478=>1772, +22446=>1773, +22419=>1774, +22869=>1775, +22865=>1776, +22863=>1777, +22862=>1778, +22864=>1779, +23004=>1780, +23000=>1781, +23039=>1782, +23011=>1783, +23016=>1784, +23043=>1785, +23013=>1786, +23018=>1787, +23002=>1788, +23014=>1789, +23041=>1790, +23035=>1791, +23401=>1792, +23459=>1793, +23462=>1794, +23460=>1795, +23458=>1796, +23461=>1797, +23553=>1798, +23630=>1799, +23631=>1800, +23629=>1801, +23627=>1802, +23769=>1803, +23762=>1804, +24055=>1805, +24093=>1806, +24101=>1807, +24095=>1808, +24189=>1809, +24224=>1810, +24230=>1811, +24314=>1812, +24328=>1813, +24365=>1814, +24421=>1815, +24456=>1816, +24453=>1817, +24458=>1818, +24459=>1819, +24455=>1820, +24460=>1821, +24457=>1822, +24594=>1823, +24605=>1824, +24608=>1825, +24613=>1826, +24590=>1827, +24616=>1828, +24653=>1829, +24688=>1830, +24680=>1831, +24674=>1832, +60712=>1832, +24646=>1833, +24643=>1834, +24684=>1835, +24683=>1836, +24682=>1837, +24676=>1838, +25153=>1839, +25308=>1840, +25366=>1841, +25353=>1842, +25340=>1843, +25325=>1844, +25345=>1845, +25326=>1846, +25341=>1847, +25351=>1848, +25329=>1849, +25335=>1850, +25327=>1851, +25324=>1852, +25342=>1853, +25332=>1854, +25361=>1855, +25346=>1856, +25919=>1857, +25925=>1858, +26027=>1859, +26045=>1860, +26082=>1861, +26149=>1862, +26157=>1863, +26144=>1864, +26151=>1865, +26159=>1866, +26143=>1867, +26152=>1868, +26161=>1869, +26148=>1870, +26359=>1871, +26623=>1872, +26579=>1873, +26609=>1874, +26580=>1875, +26576=>1876, +26604=>1877, +26550=>1878, +26543=>1879, +26613=>1880, +26601=>1881, +26607=>1882, +26564=>1883, +26577=>1884, +26548=>1885, +26586=>1886, +26597=>1887, +26552=>1888, +26575=>1889, +26590=>1890, +26611=>1891, +26544=>1892, +26585=>1893, +26594=>1894, +26589=>1895, +26578=>1896, +27498=>1897, +27523=>1898, +27526=>1899, +27573=>1900, +27602=>1901, +27607=>1902, +27679=>1903, +27849=>1904, +27915=>1905, +27954=>1906, +27946=>1907, +27969=>1908, +27941=>1909, +27916=>1910, +27953=>1911, +27934=>1912, +27927=>1913, +27963=>1914, +27965=>1915, +27966=>1916, +27958=>1917, +27931=>1918, +27893=>1919, +27961=>1920, +27943=>1921, +27960=>1922, +27945=>1923, +27950=>1924, +27957=>1925, +27918=>1926, +27947=>1927, +28843=>1928, +28858=>1929, +28851=>1930, +28844=>1931, +28847=>1932, +28845=>1933, +28856=>1934, +28846=>1935, +28836=>1936, +29232=>1937, +29298=>1938, +29295=>1939, +29300=>1940, +29417=>1941, +29408=>1942, +29409=>1943, +29623=>1944, +29642=>1945, +29627=>1946, +29618=>1947, +29645=>1948, +29632=>1949, +29619=>1950, +29978=>1951, +29997=>1952, +30031=>1953, +30028=>1954, +30030=>1955, +30027=>1956, +30123=>1957, +30116=>1958, +30117=>1959, +30114=>1960, +30115=>1961, +30328=>1962, +30342=>1963, +30343=>1964, +30344=>1965, +30408=>1966, +30406=>1967, +30403=>1968, +30405=>1969, +30465=>1970, +30457=>1971, +30456=>1972, +30473=>1973, +30475=>1974, +30462=>1975, +30460=>1976, +30471=>1977, +30684=>1978, +30722=>1979, +30740=>1980, +30732=>1981, +30733=>1982, +31046=>1983, +31049=>1984, +31048=>1985, +31047=>1986, +31161=>1987, +31162=>1988, +31185=>1989, +31186=>1990, +31179=>1991, +31359=>1992, +31361=>1993, +31487=>1994, +31485=>1995, +31869=>1996, +32002=>1997, +32005=>1998, +32000=>1999, +32009=>2000, +32007=>2001, +32004=>2002, +32006=>2003, +32568=>2004, +32654=>2005, +32703=>2006, +32784=>2007, +32781=>2008, +32785=>2009, +32822=>2010, +32982=>2011, +32997=>2012, +32986=>2013, +32963=>2014, +32964=>2015, +32972=>2016, +32993=>2017, +32987=>2018, +32974=>2019, +32990=>2020, +32996=>2021, +32989=>2022, +33268=>2023, +33314=>2024, +33511=>2025, +33539=>2026, +33541=>2027, +33507=>2028, +33499=>2029, +33510=>2030, +33540=>2031, +33509=>2032, +33538=>2033, +33545=>2034, +33490=>2035, +33495=>2036, +33521=>2037, +33537=>2038, +33500=>2039, +33492=>2040, +33489=>2041, +33502=>2042, +33491=>2043, +33503=>2044, +33519=>2045, +33542=>2046, +34384=>2047, +34425=>2048, +34427=>2049, +34426=>2050, +34893=>2051, +34923=>2052, +35201=>2053, +35284=>2054, +35336=>2055, +35330=>2056, +35331=>2057, +35998=>2058, +36000=>2059, +36212=>2060, +36211=>2061, +36276=>2062, +36557=>2063, +36556=>2064, +36848=>2065, +36838=>2066, +36834=>2067, +36842=>2068, +36837=>2069, +36845=>2070, +36843=>2071, +36836=>2072, +36840=>2073, +37066=>2074, +37070=>2075, +37057=>2076, +37059=>2077, +37195=>2078, +37194=>2079, +37325=>2080, +38274=>2081, +38480=>2082, +38475=>2083, +38476=>2084, +38477=>2085, +38754=>2086, +12207=>2086, +38761=>2087, +12208=>2087, +38859=>2088, +12209=>2088, +38893=>2089, +12210=>2089, +38899=>2090, +12211=>2090, +38913=>2091, +12212=>2091, +39080=>2092, +12213=>2092, +39131=>2093, +12214=>2093, +39135=>2094, +12215=>2094, +39318=>2095, +12216=>2095, +39321=>2096, +12217=>2096, +20056=>2097, +20147=>2098, +20492=>2099, +20493=>2100, +20515=>2101, +20463=>2102, +20518=>2103, +20517=>2104, +20472=>2105, +20521=>2106, +57375=>2106, +20502=>2107, +20486=>2108, +20540=>2109, +20511=>2110, +20506=>2111, +20498=>2112, +20497=>2113, +20474=>2114, +20480=>2115, +20500=>2116, +20520=>2117, +20465=>2118, +20513=>2119, +20491=>2120, +20505=>2121, +20504=>2122, +20467=>2123, +20462=>2124, +20525=>2125, +20522=>2126, +20478=>2127, +20523=>2128, +20489=>2129, +20860=>2130, +20900=>2131, +20901=>2132, +20898=>2133, +20941=>2134, +20940=>2135, +20934=>2136, +20939=>2137, +21078=>2138, +21084=>2139, +21076=>2140, +21083=>2141, +21085=>2142, +21290=>2143, +21375=>2144, +57459=>2144, +21407=>2145, +21405=>2146, +21471=>2147, +21736=>2148, +21776=>2149, +21761=>2150, +21815=>2151, +21756=>2152, +21733=>2153, +21746=>2154, +21766=>2155, +21754=>2156, +21780=>2157, +21737=>2158, +21741=>2159, +21729=>2160, +21769=>2161, +21742=>2162, +21738=>2163, +21734=>2164, +21799=>2165, +21767=>2166, +21757=>2167, +21775=>2168, +22275=>2169, +22276=>2170, +22466=>2171, +22484=>2172, +22475=>2173, +22467=>2174, +22537=>2175, +22799=>2176, +22871=>2177, +22872=>2178, +22874=>2179, +23057=>2180, +23064=>2181, +23068=>2182, +23071=>2183, +23067=>2184, +23059=>2185, +23020=>2186, +23072=>2187, +23075=>2188, +23081=>2189, +23077=>2190, +23052=>2191, +23049=>2192, +23403=>2193, +23640=>2194, +23472=>2195, +23475=>2196, +23478=>2197, +23476=>2198, +23470=>2199, +23477=>2200, +23481=>2201, +23480=>2202, +23556=>2203, +23633=>2204, +23637=>2205, +23632=>2206, +23789=>2207, +23805=>2208, +23803=>2209, +23786=>2210, +23784=>2211, +23792=>2212, +23798=>2213, +23809=>2214, +23796=>2215, +24046=>2216, +24109=>2217, +24107=>2218, +24235=>2219, +24237=>2220, +24231=>2221, +24369=>2222, +24466=>2223, +24465=>2224, +24464=>2225, +24665=>2226, +24675=>2227, +24677=>2228, +24656=>2229, +24661=>2230, +24685=>2231, +24681=>2232, +24687=>2233, +24708=>2234, +24735=>2235, +24730=>2236, +24717=>2237, +24724=>2238, +24716=>2239, +24709=>2240, +24726=>2241, +25159=>2242, +25331=>2243, +25352=>2244, +25343=>2245, +25422=>2246, +25406=>2247, +25391=>2248, +25429=>2249, +25410=>2250, +25414=>2251, +25423=>2252, +25417=>2253, +25402=>2254, +25424=>2255, +25405=>2256, +25386=>2257, +25387=>2258, +25384=>2259, +25421=>2260, +25420=>2261, +25928=>2262, +25929=>2263, +26009=>2264, +26049=>2265, +26053=>2266, +26178=>2267, +26185=>2268, +26191=>2269, +26179=>2270, +26194=>2271, +26188=>2272, +26181=>2273, +26177=>2274, +26360=>2275, +26388=>2276, +26389=>2277, +26391=>2278, +26657=>2279, +26680=>2280, +26696=>2281, +26694=>2282, +26707=>2283, +26681=>2284, +26690=>2285, +26708=>2286, +26665=>2287, +26803=>2288, +26647=>2289, +26700=>2290, +26705=>2291, +26685=>2292, +26612=>2293, +26704=>2294, +26688=>2295, +26684=>2296, +26691=>2297, +26666=>2298, +26693=>2299, +26643=>2300, +26648=>2301, +26689=>2302, +27530=>2303, +27529=>2304, +27575=>2305, +27683=>2306, +27687=>2307, +27688=>2308, +27686=>2309, +27684=>2310, +27888=>2311, +28010=>2312, +28053=>2313, +28040=>2314, +28039=>2315, +28006=>2316, +28024=>2317, +28023=>2318, +27993=>2319, +28051=>2320, +28012=>2321, +28041=>2322, +28014=>2323, +27994=>2324, +28020=>2325, +28009=>2326, +28044=>2327, +28042=>2328, +28025=>2329, +28037=>2330, +28005=>2331, +28052=>2332, +28874=>2333, +28888=>2334, +28900=>2335, +28889=>2336, +28872=>2337, +28879=>2338, +29241=>2339, +29305=>2340, +29436=>2341, +29433=>2342, +29437=>2343, +29432=>2344, +29431=>2345, +29574=>2346, +29677=>2347, +29705=>2348, +29678=>2349, +29664=>2350, +29674=>2351, +29662=>2352, +30036=>2353, +30045=>2354, +30044=>2355, +30042=>2356, +30041=>2357, +30142=>2358, +30149=>2359, +30151=>2360, +30130=>2361, +30131=>2362, +30141=>2363, +30140=>2364, +30137=>2365, +30146=>2366, +30136=>2367, +30347=>2368, +30384=>2369, +30410=>2370, +30413=>2371, +30414=>2372, +30505=>2373, +30495=>2374, +30496=>2375, +30504=>2376, +30697=>2377, +30768=>2378, +30759=>2379, +30776=>2380, +30749=>2381, +30772=>2382, +30775=>2383, +30757=>2384, +30765=>2385, +30752=>2386, +30751=>2387, +30770=>2388, +31061=>2389, +31056=>2390, +31072=>2391, +31071=>2392, +31062=>2393, +31070=>2394, +31069=>2395, +31063=>2396, +31066=>2397, +31204=>2398, +31203=>2399, +60418=>2399, +31207=>2400, +31199=>2401, +31206=>2402, +31209=>2403, +31192=>2404, +31364=>2405, +31368=>2406, +31449=>2407, +31494=>2408, +31505=>2409, +31881=>2410, +32033=>2411, +32023=>2412, +32011=>2413, +32010=>2414, +32032=>2415, +32034=>2416, +32020=>2417, +32016=>2418, +32021=>2419, +32026=>2420, +32028=>2421, +32013=>2422, +32025=>2423, +32027=>2424, +32570=>2425, +32607=>2426, +32660=>2427, +32709=>2428, +32705=>2429, +32774=>2430, +32772=>2431, +32792=>2432, +32789=>2433, +32793=>2434, +32791=>2435, +32829=>2436, +32831=>2437, +33009=>2438, +33026=>2439, +33008=>2440, +33029=>2441, +33005=>2442, +33012=>2443, +33030=>2444, +33016=>2445, +33011=>2446, +33032=>2447, +33021=>2448, +33034=>2449, +33020=>2450, +33007=>2451, +33261=>2452, +33260=>2453, +33280=>2454, +33296=>2455, +33322=>2456, +33323=>2457, +33320=>2458, +33324=>2459, +33467=>2460, +33579=>2461, +33618=>2462, +33620=>2463, +33610=>2464, +33592=>2465, +33616=>2466, +33609=>2467, +33589=>2468, +33588=>2469, +33615=>2470, +33586=>2471, +33593=>2472, +33590=>2473, +33559=>2474, +33600=>2475, +33585=>2476, +33576=>2477, +33603=>2478, +34388=>2479, +34442=>2480, +34474=>2481, +34451=>2482, +34468=>2483, +34473=>2484, +34444=>2485, +34467=>2486, +34460=>2487, +34928=>2488, +34935=>2489, +34945=>2490, +34946=>2491, +34941=>2492, +34937=>2493, +35352=>2494, +35344=>2495, +35342=>2496, +35340=>2497, +35349=>2498, +35338=>2499, +35351=>2500, +35347=>2501, +35350=>2502, +35343=>2503, +35345=>2504, +35912=>2505, +35962=>2506, +35961=>2507, +36001=>2508, +36002=>2509, +36215=>2510, +58442=>2510, +36524=>2511, +36562=>2512, +36564=>2513, +36559=>2514, +36785=>2515, +36865=>2516, +36870=>2517, +36855=>2518, +36864=>2519, +36858=>2520, +36852=>2521, +36867=>2522, +36861=>2523, +36869=>2524, +36856=>2525, +37013=>2526, +37089=>2527, +37085=>2528, +37090=>2529, +37202=>2530, +37197=>2531, +37196=>2532, +37336=>2533, +37341=>2534, +37335=>2535, +37340=>2536, +37337=>2537, +38275=>2538, +38498=>2539, +38499=>2540, +38497=>2541, +38491=>2542, +38493=>2543, +38500=>2544, +38488=>2545, +38494=>2546, +38587=>2547, +39138=>2548, +39340=>2549, +12218=>2549, +39592=>2550, +12219=>2550, +39640=>2551, +12220=>2551, +12222=>2552, +39717=>2552, +39730=>2553, +12224=>2553, +39740=>2554, +12225=>2554, +20094=>2555, +20602=>2556, +20605=>2557, +57382=>2557, +20572=>2558, +20551=>2559, +20547=>2560, +20556=>2561, +20570=>2562, +20553=>2563, +20581=>2564, +20598=>2565, +20558=>2566, +20565=>2567, +20597=>2568, +20596=>2569, +20599=>2570, +20559=>2571, +20495=>2572, +20591=>2573, +20589=>2574, +20828=>2575, +20885=>2576, +20976=>2577, +21098=>2578, +21103=>2579, +21202=>2580, +21209=>2581, +21208=>2582, +21205=>2583, +21264=>2584, +21263=>2585, +21273=>2586, +21311=>2587, +21312=>2588, +21310=>2589, +21443=>2590, +26364=>2591, +21830=>2592, +21866=>2593, +21862=>2594, +21828=>2595, +21854=>2596, +21857=>2597, +21827=>2598, +21834=>2599, +21809=>2600, +21846=>2601, +21839=>2602, +21845=>2603, +21807=>2604, +21860=>2605, +21816=>2606, +21806=>2607, +21852=>2608, +21804=>2609, +21859=>2610, +21811=>2611, +21825=>2612, +21847=>2613, +22280=>2614, +22283=>2615, +22281=>2616, +22495=>2617, +22533=>2618, +22538=>2619, +22534=>2620, +22496=>2621, +22500=>2622, +22522=>2623, +22530=>2624, +22581=>2625, +22519=>2626, +22521=>2627, +22816=>2628, +22882=>2629, +23094=>2630, +23105=>2631, +23113=>2632, +23142=>2633, +23146=>2634, +23104=>2635, +23100=>2636, +23138=>2637, +23130=>2638, +23110=>2639, +23114=>2640, +23408=>2641, +23495=>2642, +23493=>2643, +23492=>2644, +23490=>2645, +23487=>2646, +23494=>2647, +23561=>2648, +23560=>2649, +23559=>2650, +23648=>2651, +23644=>2652, +23645=>2653, +23815=>2654, +23814=>2655, +23822=>2656, +23835=>2657, +23830=>2658, +23842=>2659, +23825=>2660, +23849=>2661, +23828=>2662, +23833=>2663, +23844=>2664, +23847=>2665, +23831=>2666, +24034=>2667, +24120=>2668, +24118=>2669, +24115=>2670, +24119=>2671, +24247=>2672, +24248=>2673, +24246=>2674, +24245=>2675, +24254=>2676, +24373=>2677, +24375=>2678, +24407=>2679, +24428=>2680, +24425=>2681, +24427=>2682, +24471=>2683, +24473=>2684, +24478=>2685, +24472=>2686, +24481=>2687, +24480=>2688, +24476=>2689, +24703=>2690, +24739=>2691, +24713=>2692, +24736=>2693, +24744=>2694, +24779=>2695, +24756=>2696, +24806=>2697, +24765=>2698, +24773=>2699, +24763=>2700, +24757=>2701, +24796=>2702, +24764=>2703, +24792=>2704, +24789=>2705, +24774=>2706, +24799=>2707, +24760=>2708, +24794=>2709, +24775=>2710, +25114=>2711, +25115=>2712, +25160=>2713, +25504=>2714, +25511=>2715, +25458=>2716, +25494=>2717, +25506=>2718, +25509=>2719, +25463=>2720, +25447=>2721, +25496=>2722, +25514=>2723, +25457=>2724, +25513=>2725, +25481=>2726, +25475=>2727, +25499=>2728, +25451=>2729, +25512=>2730, +25476=>2731, +25480=>2732, +25497=>2733, +25505=>2734, +25516=>2735, +25490=>2736, +25487=>2737, +25472=>2738, +25467=>2739, +25449=>2740, +25448=>2741, +25466=>2742, +25949=>2743, +25942=>2744, +25937=>2745, +25945=>2746, +25943=>2747, +21855=>2748, +25935=>2749, +25944=>2750, +25941=>2751, +25940=>2752, +26012=>2753, +26011=>2754, +26028=>2755, +26063=>2756, +26059=>2757, +26060=>2758, +26062=>2759, +26205=>2760, +26202=>2761, +26212=>2762, +26216=>2763, +26214=>2764, +26206=>2765, +26361=>2766, +21207=>2767, +26395=>2768, +26753=>2769, +26799=>2770, +26786=>2771, +26771=>2772, +26805=>2773, +26751=>2774, +26742=>2775, +26801=>2776, +26791=>2777, +26775=>2778, +26800=>2779, +26755=>2780, +26820=>2781, +26797=>2782, +26758=>2783, +26757=>2784, +26772=>2785, +26781=>2786, +26792=>2787, +26783=>2788, +26785=>2789, +26754=>2790, +27442=>2791, +27578=>2792, +27627=>2793, +27628=>2794, +27691=>2795, +28046=>2796, +28092=>2797, +28147=>2798, +28121=>2799, +28082=>2800, +28129=>2801, +28108=>2802, +28132=>2803, +28155=>2804, +28154=>2805, +28165=>2806, +28103=>2807, +28107=>2808, +28079=>2809, +28113=>2810, +28078=>2811, +28126=>2812, +28153=>2813, +28088=>2814, +28151=>2815, +28149=>2816, +28101=>2817, +28114=>2818, +28186=>2819, +28085=>2820, +28122=>2821, +28139=>2822, +28120=>2823, +28138=>2824, +28145=>2825, +28142=>2826, +28136=>2827, +28102=>2828, +28100=>2829, +28074=>2830, +28140=>2831, +28095=>2832, +28134=>2833, +28921=>2834, +28937=>2835, +28938=>2836, +28925=>2837, +28911=>2838, +29245=>2839, +29309=>2840, +29313=>2841, +29468=>2842, +29467=>2843, +29462=>2844, +29459=>2845, +29465=>2846, +29575=>2847, +29701=>2848, +29706=>2849, +29699=>2850, +29702=>2851, +29694=>2852, +29709=>2853, +29920=>2854, +29942=>2855, +29943=>2856, +29980=>2857, +29986=>2858, +30053=>2859, +30054=>2860, +30050=>2861, +30064=>2862, +30095=>2863, +30164=>2864, +30165=>2865, +30133=>2866, +30154=>2867, +30157=>2868, +30350=>2869, +30420=>2870, +30418=>2871, +30427=>2872, +30519=>2873, +30526=>2874, +30524=>2875, +30518=>2876, +30520=>2877, +30522=>2878, +30827=>2879, +30787=>2880, +30798=>2881, +31077=>2882, +31080=>2883, +31085=>2884, +31227=>2885, +31378=>2886, +31381=>2887, +31520=>2888, +31528=>2889, +31515=>2890, +31532=>2891, +31526=>2892, +31513=>2893, +31518=>2894, +31534=>2895, +31890=>2896, +31895=>2897, +31893=>2898, +32070=>2899, +32067=>2900, +32113=>2901, +32046=>2902, +32057=>2903, +32060=>2904, +32064=>2905, +32048=>2906, +32051=>2907, +32068=>2908, +32047=>2909, +32066=>2910, +32050=>2911, +32049=>2912, +32573=>2913, +32670=>2914, +32666=>2915, +32716=>2916, +32718=>2917, +32722=>2918, +32796=>2919, +32842=>2920, +32838=>2921, +33071=>2922, +33046=>2923, +33059=>2924, +33067=>2925, +33065=>2926, +33072=>2927, +33060=>2928, +33282=>2929, +33333=>2930, +33335=>2931, +33334=>2932, +33337=>2933, +33678=>2934, +33694=>2935, +33688=>2936, +33656=>2937, +33698=>2938, +33686=>2939, +33725=>2940, +33707=>2941, +33682=>2942, +33674=>2943, +33683=>2944, +33673=>2945, +33696=>2946, +33655=>2947, +33659=>2948, +33660=>2949, +33670=>2950, +33703=>2951, +34389=>2952, +24426=>2953, +34503=>2954, +34496=>2955, +34486=>2956, +34500=>2957, +34485=>2958, +34502=>2959, +34507=>2960, +34481=>2961, +34479=>2962, +34505=>2963, +34899=>2964, +34974=>2965, +34952=>2966, +34987=>2967, +34962=>2968, +34966=>2969, +34957=>2970, +34955=>2971, +35219=>2972, +35215=>2973, +35370=>2974, +35357=>2975, +35363=>2976, +35365=>2977, +35377=>2978, +35373=>2979, +35359=>2980, +35355=>2981, +35362=>2982, +35913=>2983, +35930=>2984, +36009=>2985, +36012=>2986, +36011=>2987, +36008=>2988, +36010=>2989, +36007=>2990, +36199=>2991, +36198=>2992, +36286=>2993, +36282=>2994, +36571=>2995, +36575=>2996, +36889=>2997, +36877=>2998, +36890=>2999, +36887=>3000, +36899=>3001, +36895=>3002, +36893=>3003, +36880=>3004, +36885=>3005, +36894=>3006, +36896=>3007, +36879=>3008, +36898=>3009, +36886=>3010, +36891=>3011, +36884=>3012, +37096=>3013, +37101=>3014, +37117=>3015, +58488=>3015, +37207=>3016, +37326=>3017, +37365=>3018, +37350=>3019, +37347=>3020, +37351=>3021, +37357=>3022, +37353=>3023, +38281=>3024, +38506=>3025, +38517=>3026, +38515=>3027, +38520=>3028, +38512=>3029, +38516=>3030, +38518=>3031, +38519=>3032, +38508=>3033, +38592=>3034, +38634=>3035, +38633=>3036, +31456=>3037, +31455=>3038, +38914=>3039, +38915=>3040, +39770=>3041, +12226=>3041, +40165=>3042, +12227=>3042, +40565=>3043, +12228=>3043, +40575=>3044, +12229=>3044, +40613=>3045, +12230=>3045, +40635=>3046, +12231=>3046, +20642=>3047, +20621=>3048, +20613=>3049, +20633=>3050, +20625=>3051, +20608=>3052, +20630=>3053, +20632=>3054, +20634=>3055, +26368=>3056, +20977=>3057, +21106=>3058, +21108=>3059, +21109=>3060, +21097=>3061, +21214=>3062, +21213=>3063, +21211=>3064, +21338=>3065, +21413=>3066, +21883=>3067, +21888=>3068, +21927=>3069, +21884=>3070, +21898=>3071, +21917=>3072, +21912=>3073, +21890=>3074, +21916=>3075, +21930=>3076, +21908=>3077, +21895=>3078, +21899=>3079, +21891=>3080, +21939=>3081, +21934=>3082, +21919=>3083, +21822=>3084, +21938=>3085, +21914=>3086, +21947=>3087, +21932=>3088, +21937=>3089, +21886=>3090, +21897=>3091, +21931=>3092, +21913=>3093, +22285=>3094, +22575=>3095, +22570=>3096, +22580=>3097, +22564=>3098, +22576=>3099, +22577=>3100, +22561=>3101, +22557=>3102, +22560=>3103, +22777=>3104, +22778=>3105, +22880=>3106, +23159=>3107, +57587=>3107, +23194=>3108, +23167=>3109, +23186=>3110, +23195=>3111, +23207=>3112, +23411=>3113, +23409=>3114, +23506=>3115, +23500=>3116, +23507=>3117, +23504=>3118, +23562=>3119, +23563=>3120, +23601=>3121, +23884=>3122, +23888=>3123, +23860=>3124, +23879=>3125, +24061=>3126, +24133=>3127, +24125=>3128, +24128=>3129, +24131=>3130, +24190=>3131, +24266=>3132, +24257=>3133, +24258=>3134, +24260=>3135, +24380=>3136, +24429=>3137, +24489=>3138, +24490=>3139, +24488=>3140, +24785=>3141, +24801=>3142, +24754=>3143, +24758=>3144, +24800=>3145, +24860=>3146, +24867=>3147, +24826=>3148, +24853=>3149, +24816=>3150, +24827=>3151, +24820=>3152, +24936=>3153, +24817=>3154, +24846=>3155, +24822=>3156, +24841=>3157, +24832=>3158, +24850=>3159, +25119=>3160, +25161=>3161, +25507=>3162, +25484=>3163, +25551=>3164, +25536=>3165, +25577=>3166, +25545=>3167, +25542=>3168, +25549=>3169, +25554=>3170, +25571=>3171, +25552=>3172, +25569=>3173, +25558=>3174, +25581=>3175, +25582=>3176, +25462=>3177, +25588=>3178, +25578=>3179, +25563=>3180, +25682=>3181, +25562=>3182, +25593=>3183, +25950=>3184, +25958=>3185, +25954=>3186, +25955=>3187, +26001=>3188, +26000=>3189, +26031=>3190, +26222=>3191, +26224=>3192, +26228=>3193, +57786=>3193, +26230=>3194, +26223=>3195, +26257=>3196, +26234=>3197, +26238=>3198, +26231=>3199, +26366=>3200, +26367=>3201, +26399=>3202, +26397=>3203, +26874=>3204, +26837=>3205, +26848=>3206, +26840=>3207, +26839=>3208, +26885=>3209, +26847=>3210, +26869=>3211, +26862=>3212, +26855=>3213, +26873=>3214, +26834=>3215, +26866=>3216, +26851=>3217, +26827=>3218, +26829=>3219, +26893=>3220, +26898=>3221, +26894=>3222, +26825=>3223, +26842=>3224, +26990=>3225, +26875=>3226, +27454=>3227, +27450=>3228, +27453=>3229, +27544=>3230, +27542=>3231, +27580=>3232, +27631=>3233, +27694=>3234, +27695=>3235, +27692=>3236, +28207=>3237, +57904=>3237, +28216=>3238, +28244=>3239, +28193=>3240, +28210=>3241, +28263=>3242, +28234=>3243, +28192=>3244, +28197=>3245, +28195=>3246, +28187=>3247, +28251=>3248, +28248=>3249, +28196=>3250, +28246=>3251, +28270=>3252, +28205=>3253, +28198=>3254, +28271=>3255, +28212=>3256, +28237=>3257, +28218=>3258, +28204=>3259, +28227=>3260, +28189=>3261, +57901=>3261, +28222=>3262, +28363=>3263, +28297=>3264, +28185=>3265, +28238=>3266, +28259=>3267, +28228=>3268, +28274=>3269, +28265=>3270, +28255=>3271, +28953=>3272, +28954=>3273, +28966=>3274, +28976=>3275, +28961=>3276, +28982=>3277, +29038=>3278, +57958=>3278, +28956=>3279, +29260=>3280, +29316=>3281, +29312=>3282, +29494=>3283, +29477=>3284, +29492=>3285, +29481=>3286, +29754=>3287, +29738=>3288, +29747=>3289, +29730=>3290, +29733=>3291, +29749=>3292, +29750=>3293, +29748=>3294, +29743=>3295, +29723=>3296, +29734=>3297, +29736=>3298, +29989=>3299, +29990=>3300, +30059=>3301, +30058=>3302, +30178=>3303, +30171=>3304, +30179=>3305, +30169=>3306, +30168=>3307, +30174=>3308, +30176=>3309, +30331=>3310, +30332=>3311, +30358=>3312, +30355=>3313, +30388=>3314, +30428=>3315, +30543=>3316, +30701=>3317, +30813=>3318, +30828=>3319, +30831=>3320, +31245=>3321, +31240=>3322, +31243=>3323, +31237=>3324, +31232=>3325, +31384=>3326, +31383=>3327, +31382=>3328, +31461=>3329, +31459=>3330, +31561=>3331, +31574=>3332, +31558=>3333, +31568=>3334, +31570=>3335, +31572=>3336, +31565=>3337, +31563=>3338, +31567=>3339, +31569=>3340, +60510=>3340, +31903=>3341, +31909=>3342, +32094=>3343, +32080=>3344, +32104=>3345, +32085=>3346, +32043=>3347, +32110=>3348, +32114=>3349, +32097=>3350, +32102=>3351, +32098=>3352, +32112=>3353, +32115=>3354, +21892=>3355, +32724=>3356, +32725=>3357, +32779=>3358, +32850=>3359, +32901=>3360, +33109=>3361, +33108=>3362, +33099=>3363, +33105=>3364, +33102=>3365, +33081=>3366, +33094=>3367, +33086=>3368, +33100=>3369, +33107=>3370, +33140=>3371, +33298=>3372, +33308=>3373, +33769=>3374, +33795=>3375, +33784=>3376, +33805=>3377, +33760=>3378, +33733=>3379, +33803=>3380, +33729=>3381, +58309=>3381, +33775=>3382, +33777=>3383, +33780=>3384, +33879=>3385, +33802=>3386, +33776=>3387, +33804=>3388, +33740=>3389, +33789=>3390, +33778=>3391, +33738=>3392, +33848=>3393, +33806=>3394, +33796=>3395, +33756=>3396, +33799=>3397, +33748=>3398, +33759=>3399, +34395=>3400, +34527=>3401, +34521=>3402, +34541=>3403, +34516=>3404, +34523=>3405, +34532=>3406, +34512=>3407, +34526=>3408, +34903=>3409, +35009=>3410, +35010=>3411, +34993=>3412, +35203=>3413, +35222=>3414, +35387=>3415, +35424=>3416, +35413=>3417, +35422=>3418, +35388=>3419, +35393=>3420, +35412=>3421, +35419=>3422, +35408=>3423, +35398=>3424, +35380=>3425, +35386=>3426, +35382=>3427, +35414=>3428, +35937=>3429, +35970=>3430, +36015=>3431, +36028=>3432, +36019=>3433, +36029=>3434, +36033=>3435, +36027=>3436, +36032=>3437, +36020=>3438, +36023=>3439, +36022=>3440, +36031=>3441, +36024=>3442, +36234=>3443, +36229=>3444, +36225=>3445, +36302=>3446, +36317=>3447, +36299=>3448, +36314=>3449, +36305=>3450, +36300=>3451, +36315=>3452, +36294=>3453, +36603=>3454, +36600=>3455, +36604=>3456, +36764=>3457, +36910=>3458, +36917=>3459, +36913=>3460, +36920=>3461, +36914=>3462, +36918=>3463, +37122=>3464, +37109=>3465, +37129=>3466, +37118=>3467, +37219=>3468, +37221=>3469, +37327=>3470, +37396=>3471, +37397=>3472, +37411=>3473, +37385=>3474, +37406=>3475, +37389=>3476, +37392=>3477, +37383=>3478, +37393=>3479, +38292=>3480, +38287=>3481, +38283=>3482, +38289=>3483, +38291=>3484, +38290=>3485, +38286=>3486, +38538=>3487, +38542=>3488, +38539=>3489, +38525=>3490, +38533=>3491, +38534=>3492, +38541=>3493, +38514=>3494, +38532=>3495, +38593=>3496, +38597=>3497, +38596=>3498, +38598=>3499, +38599=>3500, +38639=>3501, +38642=>3502, +38860=>3503, +38917=>3504, +38918=>3505, +38920=>3506, +39143=>3507, +39146=>3508, +39151=>3509, +39145=>3510, +39154=>3511, +39149=>3512, +39342=>3513, +39341=>3514, +40643=>3515, +12232=>3515, +40653=>3516, +12233=>3516, +40657=>3517, +12234=>3517, +20098=>3518, +20653=>3519, +20661=>3520, +20658=>3521, +20659=>3522, +20677=>3523, +20670=>3524, +20652=>3525, +20663=>3526, +20667=>3527, +20655=>3528, +20679=>3529, +21119=>3530, +21111=>3531, +21117=>3532, +21215=>3533, +21222=>3534, +21220=>3535, +21218=>3536, +21219=>3537, +21295=>3538, +21983=>3539, +21992=>3540, +21971=>3541, +21990=>3542, +21966=>3543, +21980=>3544, +21959=>3545, +21969=>3546, +21987=>3547, +21988=>3548, +21999=>3549, +21978=>3550, +21985=>3551, +21957=>3552, +21958=>3553, +21989=>3554, +21961=>3555, +22290=>3556, +22291=>3557, +22622=>3558, +22609=>3559, +22616=>3560, +22615=>3561, +22618=>3562, +22612=>3563, +22635=>3564, +22604=>3565, +22637=>3566, +22602=>3567, +22626=>3568, +22610=>3569, +22603=>3570, +22887=>3571, +23233=>3572, +23241=>3573, +23244=>3574, +23230=>3575, +23229=>3576, +23228=>3577, +23219=>3578, +23234=>3579, +23218=>3580, +23913=>3581, +23919=>3582, +24140=>3583, +24185=>3584, +24265=>3585, +24264=>3586, +24338=>3587, +24409=>3588, +24492=>3589, +24494=>3590, +24858=>3591, +24847=>3592, +24904=>3593, +24863=>3594, +24819=>3595, +24859=>3596, +24825=>3597, +24833=>3598, +24840=>3599, +24910=>3600, +24908=>3601, +24900=>3602, +24909=>3603, +24894=>3604, +24884=>3605, +24871=>3606, +24845=>3607, +24838=>3608, +24887=>3609, +25121=>3610, +25122=>3611, +25619=>3612, +25662=>3613, +25630=>3614, +25642=>3615, +25645=>3616, +25661=>3617, +25644=>3618, +25615=>3619, +25628=>3620, +25620=>3621, +25613=>3622, +25654=>3623, +25622=>3624, +25623=>3625, +25606=>3626, +25964=>3627, +26015=>3628, +26032=>3629, +26263=>3630, +26249=>3631, +26247=>3632, +26248=>3633, +26262=>3634, +26244=>3635, +26264=>3636, +26253=>3637, +26371=>3638, +27028=>3639, +26989=>3640, +26970=>3641, +26999=>3642, +26976=>3643, +26964=>3644, +26997=>3645, +26928=>3646, +27010=>3647, +26954=>3648, +26984=>3649, +26987=>3650, +26974=>3651, +26963=>3652, +27001=>3653, +27014=>3654, +26973=>3655, +26979=>3656, +26971=>3657, +27463=>3658, +27506=>3659, +27584=>3660, +27583=>3661, +27603=>3662, +27645=>3663, +28322=>3664, +28335=>3665, +28371=>3666, +28342=>3667, +28354=>3668, +28304=>3669, +28317=>3670, +28359=>3671, +28357=>3672, +28325=>3673, +28312=>3674, +28348=>3675, +28346=>3676, +28331=>3677, +28369=>3678, +28310=>3679, +28316=>3680, +28356=>3681, +28372=>3682, +28330=>3683, +28327=>3684, +28340=>3685, +29006=>3686, +29017=>3687, +29033=>3688, +29028=>3689, +29001=>3690, +29031=>3691, +29020=>3692, +29036=>3693, +29030=>3694, +29004=>3695, +29029=>3696, +29022=>3697, +28998=>3698, +29032=>3699, +29014=>3700, +29242=>3701, +29266=>3702, +29495=>3703, +29509=>3704, +29503=>3705, +29502=>3706, +29807=>3707, +29786=>3708, +29781=>3709, +29791=>3710, +29790=>3711, +29761=>3712, +29759=>3713, +29785=>3714, +29787=>3715, +58019=>3716, +29788=>3716, +30070=>3717, +30072=>3718, +30208=>3719, +30192=>3720, +30209=>3721, +30194=>3722, +30193=>3723, +30202=>3724, +30207=>3725, +30196=>3726, +30195=>3727, +30430=>3728, +30431=>3729, +30555=>3730, +30571=>3731, +30566=>3732, +30558=>3733, +30563=>3734, +30585=>3735, +30570=>3736, +30572=>3737, +30556=>3738, +30565=>3739, +30568=>3740, +30562=>3741, +30702=>3742, +30862=>3743, +30896=>3744, +30871=>3745, +30872=>3746, +30860=>3747, +30857=>3748, +30844=>3749, +30865=>3750, +30867=>3751, +30847=>3752, +31098=>3753, +31103=>3754, +31105=>3755, +33836=>3756, +31165=>3757, +31260=>3758, +31258=>3759, +31264=>3760, +31252=>3761, +31263=>3762, +31262=>3763, +31391=>3764, +31392=>3765, +31607=>3766, +31680=>3767, +31584=>3768, +31598=>3769, +31591=>3770, +31921=>3771, +31923=>3772, +31925=>3773, +32147=>3774, +32121=>3775, +32145=>3776, +32129=>3777, +32143=>3778, +32091=>3779, +32622=>3780, +32617=>3781, +32618=>3782, +32626=>3783, +32681=>3784, +32680=>3785, +32676=>3786, +32854=>3787, +32856=>3788, +32902=>3789, +32900=>3790, +33137=>3791, +33136=>3792, +33144=>3793, +33125=>3794, +33134=>3795, +33139=>3796, +33131=>3797, +33145=>3798, +33146=>3799, +33126=>3800, +33285=>3801, +33351=>3802, +33922=>3803, +33911=>3804, +33853=>3805, +33841=>3806, +33909=>3807, +33894=>3808, +33899=>3809, +33865=>3810, +33900=>3811, +33883=>3812, +33852=>3813, +33845=>3814, +33889=>3815, +33891=>3816, +33897=>3817, +33901=>3818, +33862=>3819, +34398=>3820, +34396=>3821, +34399=>3822, +34553=>3823, +34579=>3824, +34568=>3825, +34567=>3826, +34560=>3827, +34558=>3828, +34555=>3829, +34562=>3830, +34563=>3831, +34566=>3832, +34570=>3833, +34905=>3834, +35039=>3835, +35028=>3836, +35033=>3837, +35036=>3838, +35032=>3839, +35037=>3840, +35041=>3841, +35018=>3842, +35029=>3843, +35026=>3844, +35228=>3845, +35299=>3846, +35435=>3847, +35442=>3848, +35443=>3849, +35430=>3850, +35433=>3851, +35440=>3852, +35463=>3853, +35452=>3854, +35427=>3855, +35488=>3856, +35441=>3857, +35461=>3858, +35437=>3859, +35426=>3860, +35438=>3861, +35436=>3862, +35449=>3863, +35451=>3864, +35390=>3865, +35432=>3866, +35938=>3867, +35978=>3868, +35977=>3869, +36042=>3870, +36039=>3871, +36040=>3872, +36036=>3873, +36018=>3874, +36035=>3875, +36034=>3876, +36037=>3877, +36321=>3878, +36319=>3879, +36328=>3880, +36335=>3881, +36339=>3882, +36346=>3883, +36330=>3884, +36324=>3885, +36326=>3886, +36530=>3887, +36611=>3888, +36617=>3889, +36606=>3890, +36618=>3891, +36767=>3892, +36786=>3893, +36939=>3894, +36938=>3895, +36947=>3896, +36930=>3897, +36948=>3898, +36924=>3899, +36949=>3900, +36944=>3901, +36935=>3902, +36943=>3903, +36942=>3904, +36941=>3905, +36945=>3906, +36926=>3907, +36929=>3908, +37138=>3909, +37143=>3910, +37228=>3911, +37226=>3912, +37225=>3913, +37321=>3914, +37431=>3915, +37463=>3916, +37432=>3917, +37437=>3918, +37440=>3919, +37438=>3920, +37467=>3921, +37451=>3922, +37476=>3923, +37457=>3924, +37428=>3925, +37449=>3926, +37453=>3927, +37445=>3928, +37433=>3929, +37439=>3930, +37466=>3931, +38296=>3932, +38552=>3933, +38548=>3934, +38549=>3935, +38605=>3936, +38603=>3937, +38601=>3938, +38602=>3939, +38647=>3940, +38651=>3941, +38649=>3942, +38646=>3943, +38742=>3944, +38772=>3945, +38774=>3946, +38928=>3947, +38929=>3948, +38931=>3949, +38922=>3950, +38930=>3951, +38924=>3952, +39164=>3953, +39156=>3954, +39165=>3955, +39166=>3956, +39347=>3957, +39345=>3958, +39348=>3959, +39649=>3960, +40169=>3961, +40578=>3962, +40718=>3963, +12237=>3963, +40723=>3964, +12238=>3964, +40736=>3965, +12239=>3965, +20711=>3966, +20718=>3967, +20709=>3968, +20694=>3969, +20717=>3970, +60903=>3970, +20698=>3971, +20693=>3972, +20687=>3973, +20689=>3974, +20721=>3975, +20686=>3976, +20713=>3977, +20834=>3978, +20979=>3979, +21123=>3980, +21122=>3981, +21297=>3982, +21421=>3983, +22014=>3984, +22016=>3985, +22043=>3986, +22039=>3987, +22013=>3988, +22036=>3989, +22022=>3990, +22025=>3991, +22029=>3992, +22030=>3993, +22007=>3994, +22038=>3995, +22047=>3996, +22024=>3997, +22032=>3998, +22006=>3999, +22296=>4000, +22294=>4001, +22645=>4002, +22654=>4003, +22659=>4004, +22675=>4005, +22666=>4006, +22649=>4007, +22661=>4008, +22653=>4009, +22781=>4010, +22821=>4011, +22818=>4012, +22820=>4013, +22890=>4014, +22889=>4015, +23265=>4016, +23270=>4017, +23273=>4018, +23255=>4019, +23254=>4020, +23256=>4021, +23267=>4022, +23413=>4023, +23518=>4024, +23527=>4025, +23521=>4026, +23525=>4027, +23526=>4028, +23528=>4029, +23522=>4030, +23524=>4031, +23519=>4032, +23565=>4033, +23650=>4034, +23940=>4035, +23943=>4036, +24155=>4037, +24163=>4038, +24149=>4039, +24151=>4040, +24148=>4041, +24275=>4042, +24278=>4043, +24330=>4044, +24390=>4045, +24432=>4046, +24505=>4047, +24903=>4048, +24895=>4049, +24907=>4050, +24951=>4051, +24930=>4052, +24931=>4053, +24927=>4054, +24922=>4055, +24920=>4056, +24949=>4057, +25130=>4058, +25735=>4059, +25688=>4060, +25684=>4061, +25764=>4062, +25720=>4063, +25695=>4064, +25722=>4065, +25681=>4066, +25703=>4067, +25652=>4068, +25709=>4069, +25723=>4070, +25970=>4071, +26017=>4072, +26071=>4073, +26070=>4074, +26274=>4075, +26280=>4076, +26269=>4077, +27036=>4078, +27048=>4079, +27029=>4080, +27073=>4081, +27054=>4082, +27091=>4083, +27083=>4084, +27035=>4085, +27063=>4086, +27067=>4087, +27051=>4088, +27060=>4089, +27088=>4090, +27085=>4091, +27053=>4092, +27084=>4093, +27046=>4094, +27075=>4095, +27043=>4096, +27465=>4097, +27468=>4098, +27699=>4099, +28467=>4100, +28436=>4101, +28414=>4102, +28435=>4103, +28404=>4104, +28457=>4105, +28478=>4106, +28448=>4107, +28460=>4108, +28431=>4109, +28418=>4110, +28450=>4111, +28415=>4112, +28399=>4113, +28422=>4114, +28465=>4115, +28472=>4116, +28466=>4117, +28451=>4118, +28437=>4119, +28459=>4120, +28463=>4121, +28552=>4122, +28458=>4123, +28396=>4124, +28417=>4125, +28402=>4126, +28364=>4127, +28407=>4128, +29076=>4129, +29081=>4130, +29053=>4131, +29066=>4132, +29060=>4133, +29074=>4134, +29246=>4135, +29330=>4136, +29334=>4137, +29508=>4138, +29520=>4139, +29796=>4140, +29795=>4141, +29802=>4142, +29808=>4143, +29805=>4144, +29956=>4145, +30097=>4146, +30247=>4147, +30221=>4148, +30219=>4149, +30217=>4150, +30227=>4151, +30433=>4152, +30435=>4153, +30596=>4154, +30589=>4155, +30591=>4156, +30561=>4157, +30913=>4158, +30879=>4159, +30887=>4160, +30899=>4161, +30889=>4162, +30883=>4163, +31118=>4164, +31119=>4165, +31117=>4166, +31278=>4167, +31281=>4168, +31402=>4169, +31401=>4170, +31469=>4171, +31471=>4172, +31649=>4173, +31637=>4174, +31627=>4175, +31605=>4176, +31639=>4177, +31645=>4178, +31636=>4179, +31631=>4180, +31672=>4181, +58170=>4181, +31623=>4182, +31620=>4183, +31929=>4184, +31933=>4185, +31934=>4186, +32187=>4187, +32176=>4188, +32156=>4189, +32189=>4190, +32190=>4191, +32160=>4192, +32202=>4193, +32180=>4194, +32178=>4195, +32177=>4196, +32186=>4197, +32162=>4198, +32191=>4199, +32181=>4200, +32184=>4201, +32173=>4202, +32210=>4203, +58202=>4203, +32199=>4204, +32172=>4205, +32624=>4206, +32736=>4207, +32737=>4208, +32735=>4209, +32862=>4210, +32858=>4211, +32903=>4212, +33104=>4213, +33152=>4214, +33167=>4215, +33160=>4216, +33162=>4217, +33151=>4218, +33154=>4219, +33255=>4220, +33274=>4221, +33287=>4222, +33300=>4223, +33310=>4224, +33355=>4225, +33993=>4226, +33983=>4227, +33990=>4228, +33988=>4229, +33945=>4230, +33950=>4231, +33970=>4232, +33948=>4233, +33995=>4234, +33976=>4235, +33984=>4236, +34003=>4237, +33936=>4238, +33980=>4239, +34001=>4240, +33994=>4241, +34623=>4242, +34588=>4243, +34619=>4244, +34594=>4245, +34597=>4246, +34612=>4247, +34584=>4248, +34645=>4249, +34615=>4250, +34601=>4251, +35059=>4252, +35074=>4253, +35060=>4254, +35065=>4255, +35064=>4256, +35069=>4257, +35048=>4258, +35098=>4259, +35055=>4260, +35494=>4261, +35468=>4262, +35486=>4263, +35491=>4264, +35469=>4265, +35489=>4266, +35475=>4267, +35492=>4268, +35498=>4269, +35493=>4270, +35496=>4271, +35480=>4272, +35473=>4273, +35482=>4274, +35495=>4275, +35946=>4276, +35981=>4277, +35980=>4278, +36051=>4279, +36049=>4280, +36050=>4281, +36203=>4282, +36249=>4283, +36245=>4284, +36348=>4285, +36628=>4286, +36626=>4287, +36629=>4288, +36627=>4289, +36771=>4290, +36960=>4291, +36952=>4292, +36956=>4293, +36963=>4294, +36953=>4295, +36958=>4296, +36962=>4297, +36957=>4298, +36955=>4299, +37145=>4300, +37144=>4301, +37150=>4302, +37237=>4303, +37240=>4304, +37239=>4305, +37236=>4306, +37496=>4307, +37548=>4308, +37504=>4309, +37509=>4310, +37528=>4311, +37526=>4312, +37499=>4313, +37523=>4314, +37532=>4315, +37544=>4316, +37500=>4317, +37521=>4318, +38305=>4319, +38312=>4320, +38313=>4321, +38307=>4322, +38309=>4323, +38308=>4324, +38553=>4325, +38556=>4326, +38555=>4327, +38604=>4328, +38610=>4329, +38656=>4330, +38780=>4331, +38789=>4332, +38902=>4333, +38935=>4334, +38936=>4335, +39087=>4336, +39089=>4337, +39171=>4338, +39173=>4339, +39180=>4340, +39177=>4341, +39361=>4342, +39599=>4343, +39600=>4344, +39654=>4345, +39745=>4346, +39746=>4347, +40180=>4348, +40182=>4349, +40179=>4350, +40636=>4351, +40763=>4352, +12240=>4352, +40778=>4353, +12241=>4353, +20740=>4354, +20736=>4355, +20731=>4356, +20725=>4357, +20729=>4358, +20738=>4359, +20744=>4360, +20745=>4361, +20741=>4362, +20956=>4363, +21127=>4364, +21128=>4365, +21129=>4366, +21133=>4367, +21130=>4368, +21232=>4369, +21426=>4370, +22062=>4371, +22075=>4372, +22073=>4373, +22066=>4374, +22079=>4375, +22068=>4376, +22057=>4377, +22099=>4378, +22094=>4379, +22103=>4380, +22132=>4381, +22070=>4382, +22063=>4383, +22064=>4384, +22656=>4385, +22687=>4386, +22686=>4387, +22707=>4388, +22684=>4389, +22702=>4390, +22697=>4391, +22694=>4392, +22893=>4393, +23305=>4394, +23291=>4395, +23307=>4396, +23285=>4397, +23308=>4398, +23304=>4399, +23534=>4400, +23532=>4401, +23529=>4402, +23531=>4403, +23652=>4404, +23653=>4405, +23965=>4406, +23956=>4407, +24162=>4408, +24159=>4409, +24161=>4410, +24290=>4411, +24282=>4412, +24287=>4413, +24285=>4414, +24291=>4415, +24288=>4416, +24392=>4417, +24433=>4418, +24503=>4419, +24501=>4420, +24950=>4421, +24935=>4422, +24942=>4423, +24925=>4424, +24917=>4425, +24962=>4426, +24956=>4427, +24944=>4428, +24939=>4429, +24958=>4430, +24999=>4431, +24976=>4432, +25003=>4433, +24974=>4434, +25004=>4435, +24986=>4436, +24996=>4437, +24980=>4438, +25006=>4439, +25134=>4440, +25705=>4441, +25711=>4442, +25721=>4443, +25758=>4444, +25778=>4445, +25736=>4446, +25744=>4447, +57745=>4447, +25776=>4448, +25765=>4449, +25747=>4450, +25749=>4451, +25769=>4452, +25746=>4453, +25774=>4454, +25773=>4455, +25771=>4456, +25754=>4457, +25772=>4458, +25753=>4459, +25762=>4460, +25779=>4461, +25973=>4462, +25975=>4463, +25976=>4464, +26286=>4465, +26283=>4466, +26292=>4467, +26289=>4468, +27171=>4469, +27167=>4470, +27112=>4471, +27137=>4472, +27166=>4473, +27161=>4474, +27133=>4475, +27169=>4476, +27155=>4477, +27146=>4478, +27123=>4479, +27138=>4480, +27141=>4481, +27117=>4482, +27153=>4483, +27472=>4484, +27470=>4485, +27556=>4486, +27589=>4487, +27590=>4488, +28479=>4489, +28540=>4490, +28548=>4491, +28497=>4492, +28518=>4493, +28500=>4494, +28550=>4495, +28525=>4496, +28507=>4497, +28536=>4498, +28526=>4499, +28558=>4500, +28538=>4501, +28528=>4502, +28516=>4503, +28567=>4504, +28504=>4505, +28373=>4506, +28527=>4507, +28512=>4508, +28511=>4509, +29087=>4510, +29100=>4511, +29105=>4512, +29096=>4513, +29270=>4514, +29339=>4515, +29518=>4516, +29527=>4517, +29801=>4518, +29835=>4519, +29827=>4520, +29822=>4521, +29824=>4522, +30079=>4523, +30240=>4524, +30249=>4525, +30239=>4526, +30244=>4527, +30246=>4528, +30241=>4529, +30242=>4530, +30362=>4531, +30394=>4532, +30436=>4533, +30606=>4534, +30599=>4535, +30604=>4536, +30609=>4537, +30603=>4538, +30923=>4539, +30917=>4540, +30906=>4541, +30922=>4542, +30910=>4543, +30933=>4544, +30908=>4545, +30928=>4546, +31295=>4547, +31292=>4548, +31296=>4549, +31293=>4550, +31287=>4551, +31291=>4552, +31407=>4553, +31406=>4554, +31661=>4555, +31665=>4556, +31684=>4557, +31668=>4558, +31686=>4559, +31687=>4560, +31681=>4561, +31648=>4562, +31692=>4563, +31946=>4564, +32224=>4565, +32244=>4566, +32239=>4567, +32251=>4568, +32216=>4569, +32236=>4570, +32221=>4571, +32232=>4572, +32227=>4573, +32218=>4574, +32222=>4575, +32233=>4576, +32158=>4577, +32217=>4578, +32242=>4579, +32249=>4580, +32629=>4581, +32631=>4582, +32687=>4583, +32745=>4584, +32806=>4585, +33179=>4586, +33180=>4587, +33181=>4588, +33184=>4589, +33178=>4590, +33176=>4591, +34071=>4592, +34109=>4593, +34074=>4594, +34030=>4595, +34092=>4596, +34093=>4597, +34067=>4598, +34065=>4599, +34083=>4600, +34081=>4601, +34068=>4602, +34028=>4603, +34085=>4604, +34047=>4605, +34054=>4606, +34690=>4607, +34676=>4608, +34678=>4609, +34656=>4610, +34662=>4611, +34680=>4612, +34664=>4613, +34649=>4614, +34647=>4615, +34636=>4616, +34643=>4617, +34907=>4618, +34909=>4619, +35088=>4620, +35079=>4621, +35090=>4622, +35091=>4623, +35093=>4624, +35082=>4625, +35516=>4626, +35538=>4627, +35527=>4628, +35524=>4629, +35477=>4630, +35531=>4631, +35576=>4632, +35506=>4633, +35529=>4634, +35522=>4635, +35519=>4636, +35504=>4637, +35542=>4638, +35533=>4639, +35510=>4640, +35513=>4641, +35547=>4642, +35916=>4643, +35918=>4644, +35948=>4645, +36064=>4646, +36062=>4647, +36070=>4648, +36068=>4649, +36076=>4650, +36077=>4651, +36066=>4652, +36067=>4653, +36060=>4654, +36074=>4655, +36065=>4656, +36205=>4657, +36255=>4658, +36259=>4659, +36395=>4660, +36368=>4661, +36381=>4662, +36386=>4663, +36367=>4664, +36393=>4665, +36383=>4666, +36385=>4667, +36382=>4668, +36538=>4669, +36637=>4670, +36635=>4671, +36639=>4672, +36649=>4673, +36646=>4674, +36650=>4675, +36636=>4676, +36638=>4677, +36645=>4678, +36969=>4679, +36974=>4680, +36968=>4681, +36973=>4682, +36983=>4683, +37168=>4684, +37165=>4685, +37159=>4686, +37169=>4687, +37255=>4688, +37257=>4689, +37259=>4690, +37251=>4691, +37573=>4692, +37563=>4693, +37559=>4694, +37610=>4695, +37604=>4696, +37569=>4697, +37555=>4698, +37564=>4699, +37586=>4700, +37575=>4701, +37616=>4702, +37554=>4703, +38317=>4704, +38321=>4705, +38660=>4706, +38662=>4707, +38663=>4708, +38665=>4709, +38752=>4710, +38797=>4711, +38795=>4712, +38799=>4713, +38945=>4714, +38955=>4715, +38940=>4716, +39091=>4717, +39178=>4718, +39187=>4719, +39186=>4720, +39192=>4721, +39389=>4722, +39376=>4723, +39391=>4724, +39387=>4725, +39377=>4726, +39381=>4727, +39378=>4728, +39385=>4729, +39607=>4730, +39662=>4731, +39663=>4732, +39719=>4733, +39749=>4734, +39748=>4735, +39799=>4736, +39791=>4737, +40198=>4738, +40201=>4739, +40195=>4740, +40617=>4741, +40638=>4742, +40654=>4743, +22696=>4744, +12242=>4745, +40786=>4745, +20754=>4746, +20760=>4747, +20756=>4748, +20752=>4749, +20757=>4750, +20864=>4751, +20906=>4752, +20957=>4753, +21137=>4754, +21139=>4755, +21235=>4756, +22105=>4757, +22123=>4758, +22137=>4759, +22121=>4760, +22116=>4761, +22136=>4762, +22122=>4763, +22120=>4764, +22117=>4765, +22129=>4766, +22127=>4767, +22124=>4768, +22114=>4769, +22134=>4770, +22721=>4771, +22718=>4772, +22727=>4773, +22725=>4774, +22894=>4775, +23325=>4776, +23348=>4777, +23416=>4778, +23536=>4779, +23566=>4780, +24394=>4781, +25010=>4782, +24977=>4783, +25001=>4784, +24970=>4785, +25037=>4786, +25014=>4787, +25022=>4788, +25034=>4789, +25032=>4790, +25136=>4791, +25797=>4792, +25793=>4793, +25803=>4794, +25787=>4795, +25788=>4796, +25818=>4797, +25796=>4798, +25799=>4799, +25794=>4800, +25805=>4801, +25791=>4802, +25810=>4803, +25812=>4804, +25790=>4805, +25972=>4806, +26310=>4807, +26313=>4808, +26297=>4809, +26308=>4810, +26311=>4811, +26296=>4812, +27197=>4813, +27192=>4814, +27194=>4815, +27225=>4816, +27243=>4817, +27224=>4818, +27193=>4819, +27204=>4820, +27234=>4821, +27233=>4822, +27211=>4823, +27207=>4824, +27189=>4825, +27231=>4826, +27208=>4827, +27481=>4828, +27511=>4829, +27653=>4830, +28610=>4831, +28593=>4832, +28577=>4833, +28611=>4834, +28580=>4835, +28609=>4836, +28583=>4837, +28595=>4838, +28608=>4839, +28601=>4840, +28598=>4841, +60318=>4841, +28582=>4842, +28576=>4843, +28596=>4844, +29118=>4845, +29129=>4846, +29136=>4847, +29138=>4848, +29128=>4849, +29141=>4850, +29113=>4851, +29134=>4852, +29145=>4853, +29148=>4854, +29123=>4855, +29124=>4856, +29544=>4857, +29852=>4858, +29859=>4859, +29848=>4860, +29855=>4861, +29854=>4862, +29922=>4863, +29964=>4864, +29965=>4865, +30260=>4866, +30264=>4867, +30266=>4868, +30439=>4869, +30437=>4870, +30624=>4871, +30622=>4872, +30623=>4873, +30629=>4874, +30952=>4875, +30938=>4876, +30956=>4877, +30951=>4878, +31142=>4879, +31309=>4880, +31310=>4881, +31302=>4882, +31308=>4883, +31307=>4884, +31418=>4885, +31705=>4886, +31761=>4887, +31689=>4888, +31716=>4889, +31707=>4890, +31713=>4891, +31721=>4892, +31718=>4893, +31957=>4894, +31958=>4895, +32266=>4896, +32273=>4897, +32264=>4898, +32283=>4899, +32291=>4900, +32286=>4901, +32285=>4902, +58211=>4902, +32265=>4903, +32272=>4904, +32633=>4905, +32690=>4906, +32752=>4907, +32753=>4908, +32750=>4909, +32808=>4910, +58239=>4910, +33203=>4911, +33193=>4912, +33192=>4913, +33275=>4914, +33288=>4915, +33368=>4916, +33369=>4917, +34122=>4918, +34137=>4919, +34120=>4920, +34152=>4921, +34153=>4922, +34115=>4923, +34121=>4924, +34157=>4925, +34154=>4926, +34142=>4927, +34691=>4928, +34719=>4929, +34718=>4930, +34722=>4931, +34701=>4932, +34913=>4933, +35114=>4934, +35122=>4935, +35109=>4936, +35115=>4937, +35105=>4938, +35242=>4939, +35238=>4940, +58391=>4940, +35558=>4941, +35578=>4942, +35563=>4943, +35569=>4944, +35584=>4945, +35548=>4946, +35559=>4947, +35566=>4948, +35582=>4949, +35585=>4950, +35586=>4951, +35575=>4952, +35565=>4953, +35571=>4954, +35574=>4955, +35580=>4956, +35947=>4957, +35949=>4958, +35987=>4959, +36084=>4960, +36420=>4961, +36401=>4962, +36404=>4963, +36418=>4964, +36409=>4965, +36405=>4966, +36667=>4967, +36655=>4968, +36664=>4969, +36659=>4970, +36776=>4971, +36774=>4972, +36981=>4973, +36980=>4974, +36984=>4975, +36978=>4976, +36988=>4977, +36986=>4978, +37172=>4979, +37266=>4980, +37664=>4981, +37686=>4982, +37624=>4983, +37683=>4984, +37679=>4985, +37666=>4986, +37628=>4987, +37675=>4988, +37636=>4989, +37658=>4990, +37648=>4991, +37670=>4992, +37665=>4993, +37653=>4994, +37678=>4995, +37657=>4996, +38331=>4997, +38567=>4998, +38568=>4999, +38570=>5000, +38613=>5001, +38670=>5002, +38673=>5003, +38678=>5004, +38669=>5005, +38675=>5006, +38671=>5007, +38747=>5008, +58565=>5009, +38748=>5009, +38758=>5010, +38808=>5011, +38960=>5012, +38968=>5013, +38971=>5014, +38967=>5015, +38957=>5016, +38969=>5017, +38948=>5018, +39184=>5019, +39208=>5020, +39198=>5021, +39195=>5022, +39201=>5023, +39194=>5024, +39405=>5025, +39394=>5026, +39409=>5027, +39608=>5028, +39612=>5029, +39675=>5030, +39661=>5031, +39720=>5032, +39825=>5033, +40213=>5034, +40227=>5035, +40230=>5036, +40232=>5037, +40210=>5038, +40219=>5039, +40664=>5040, +40660=>5041, +40845=>5042, +12243=>5042, +40860=>5043, +12244=>5043, +20778=>5044, +20767=>5045, +20769=>5046, +20786=>5047, +21237=>5048, +22158=>5049, +22144=>5050, +22160=>5051, +22149=>5052, +22151=>5053, +22159=>5054, +22741=>5055, +22739=>5056, +22737=>5057, +22734=>5058, +23344=>5059, +23338=>5060, +23332=>5061, +23418=>5062, +23607=>5063, +23656=>5064, +23996=>5065, +23994=>5066, +23997=>5067, +23992=>5068, +24171=>5069, +24396=>5070, +24509=>5071, +25033=>5072, +25026=>5073, +25031=>5074, +25062=>5075, +25035=>5076, +25138=>5077, +25140=>5078, +25806=>5079, +25802=>5080, +25816=>5081, +25824=>5082, +25840=>5083, +25830=>5084, +25836=>5085, +25841=>5086, +25826=>5087, +25837=>5088, +25986=>5089, +25987=>5090, +26329=>5091, +26326=>5092, +27264=>5093, +27284=>5094, +27268=>5095, +27298=>5096, +27292=>5097, +27355=>5098, +27299=>5099, +27262=>5100, +27287=>5101, +27280=>5102, +27296=>5103, +27484=>5104, +27566=>5105, +27610=>5106, +27656=>5107, +28632=>5108, +28657=>5109, +28639=>5110, +28640=>5111, +28635=>5112, +28644=>5113, +28651=>5114, +28655=>5115, +28544=>5116, +28652=>5117, +28641=>5118, +28649=>5119, +28629=>5120, +28654=>5121, +28656=>5122, +29159=>5123, +29151=>5124, +60361=>5124, +29166=>5125, +29158=>5126, +29157=>5127, +29165=>5128, +29164=>5129, +29172=>5130, +29152=>5131, +29237=>5132, +29254=>5133, +29552=>5134, +29554=>5135, +29865=>5136, +29872=>5137, +29862=>5138, +29864=>5139, +30278=>5140, +30274=>5141, +30284=>5142, +30442=>5143, +30643=>5144, +30634=>5145, +30640=>5146, +30636=>5147, +30631=>5148, +30637=>5149, +30703=>5150, +30967=>5151, +30970=>5152, +30964=>5153, +30959=>5154, +30977=>5155, +31143=>5156, +31146=>5157, +31319=>5158, +31423=>5159, +31751=>5160, +31757=>5161, +31742=>5162, +31735=>5163, +31756=>5164, +31712=>5165, +31968=>5166, +31964=>5167, +31966=>5168, +31970=>5169, +31967=>5170, +31961=>5171, +31965=>5172, +32302=>5173, +32318=>5174, +32326=>5175, +32311=>5176, +32306=>5177, +32323=>5178, +32299=>5179, +32317=>5180, +32305=>5181, +32325=>5182, +32321=>5183, +32308=>5184, +32313=>5185, +32328=>5186, +32309=>5187, +32319=>5188, +32303=>5189, +32580=>5190, +32755=>5191, +32764=>5192, +32881=>5193, +32882=>5194, +32880=>5195, +32879=>5196, +32883=>5197, +33222=>5198, +33219=>5199, +33210=>5200, +33218=>5201, +33216=>5202, +33215=>5203, +33213=>5204, +33225=>5205, +33214=>5206, +33256=>5207, +33289=>5208, +33393=>5209, +34218=>5210, +34180=>5211, +34174=>5212, +34204=>5213, +34193=>5214, +34196=>5215, +34223=>5216, +34203=>5217, +34183=>5218, +34216=>5219, +34186=>5220, +34214=>5221, +34407=>5222, +34752=>5223, +34769=>5224, +34739=>5225, +34770=>5226, +34758=>5227, +34731=>5228, +34747=>5229, +34746=>5230, +34760=>5231, +34763=>5232, +35131=>5233, +35126=>5234, +35140=>5235, +35128=>5236, +35133=>5237, +35244=>5238, +35598=>5239, +35607=>5240, +35609=>5241, +35611=>5242, +35594=>5243, +35616=>5244, +35613=>5245, +35588=>5246, +35600=>5247, +35905=>5248, +35903=>5249, +35955=>5250, +36090=>5251, +36093=>5252, +36092=>5253, +36088=>5254, +36091=>5255, +36264=>5256, +36425=>5257, +36427=>5258, +36424=>5259, +36426=>5260, +36676=>5261, +36670=>5262, +36674=>5263, +36677=>5264, +36671=>5265, +36991=>5266, +36989=>5267, +36996=>5268, +36993=>5269, +36994=>5270, +36992=>5271, +37177=>5272, +37283=>5273, +37278=>5274, +37276=>5275, +37709=>5276, +37762=>5277, +37672=>5278, +37749=>5279, +37706=>5280, +37733=>5281, +37707=>5282, +37656=>5283, +37758=>5284, +37740=>5285, +37723=>5286, +37744=>5287, +37722=>5288, +37716=>5289, +38346=>5290, +38347=>5291, +38348=>5292, +38344=>5293, +38342=>5294, +38577=>5295, +38584=>5296, +38614=>5297, +38684=>5298, +38686=>5299, +38816=>5300, +38867=>5301, +38982=>5302, +39094=>5303, +39221=>5304, +39425=>5305, +39423=>5306, +39854=>5307, +39851=>5308, +39850=>5309, +39853=>5310, +40251=>5311, +40255=>5312, +40587=>5313, +40655=>5314, +40670=>5315, +40668=>5316, +40669=>5317, +40667=>5318, +40766=>5319, +40779=>5320, +21474=>5321, +22165=>5322, +22190=>5323, +22745=>5324, +22744=>5325, +23352=>5326, +24413=>5327, +25059=>5328, +25139=>5329, +25844=>5330, +25842=>5331, +25854=>5332, +25862=>5333, +25850=>5334, +25851=>5335, +25847=>5336, +26039=>5337, +26332=>5338, +26406=>5339, +27315=>5340, +27308=>5341, +27331=>5342, +27323=>5343, +27320=>5344, +27330=>5345, +27310=>5346, +27311=>5347, +27487=>5348, +27512=>5349, +27567=>5350, +28681=>5351, +28683=>5352, +28670=>5353, +28678=>5354, +28666=>5355, +28689=>5356, +28687=>5357, +29179=>5358, +29180=>5359, +29182=>5360, +29176=>5361, +29559=>5362, +29557=>5363, +29863=>5364, +29887=>5365, +29973=>5366, +30294=>5367, +30296=>5368, +30290=>5369, +30653=>5370, +30655=>5371, +30651=>5372, +30652=>5373, +30990=>5374, +31150=>5375, +31329=>5376, +31330=>5377, +31328=>5378, +31428=>5379, +31429=>5380, +31787=>5381, +31783=>5382, +31786=>5383, +31774=>5384, +31779=>5385, +31777=>5386, +31975=>5387, +32340=>5388, +32341=>5389, +32350=>5390, +32346=>5391, +32353=>5392, +32338=>5393, +32345=>5394, +32584=>5395, +32761=>5396, +32763=>5397, +32887=>5398, +32886=>5399, +33229=>5400, +33231=>5401, +33290=>5402, +34255=>5403, +34217=>5404, +34253=>5405, +34256=>5406, +34249=>5407, +34224=>5408, +34234=>5409, +34233=>5410, +34799=>5411, +34796=>5412, +34802=>5413, +34784=>5414, +35206=>5415, +35250=>5416, +35316=>5417, +35624=>5418, +35641=>5419, +35628=>5420, +35627=>5421, +35920=>5422, +36101=>5423, +36441=>5424, +36451=>5425, +36454=>5426, +36452=>5427, +36447=>5428, +36437=>5429, +36544=>5430, +36681=>5431, +36685=>5432, +36999=>5433, +36995=>5434, +37000=>5435, +37291=>5436, +37292=>5437, +37328=>5438, +37780=>5439, +37770=>5440, +37782=>5441, +37794=>5442, +37811=>5443, +37806=>5444, +37804=>5445, +37808=>5446, +37784=>5447, +37786=>5448, +37783=>5449, +38356=>5450, +38358=>5451, +38352=>5452, +38357=>5453, +38626=>5454, +38620=>5455, +38617=>5456, +38619=>5457, +38622=>5458, +38692=>5459, +38819=>5460, +38822=>5461, +38829=>5462, +38905=>5463, +38989=>5464, +38991=>5465, +38988=>5466, +38990=>5467, +38995=>5468, +39098=>5469, +39230=>5470, +39231=>5471, +39229=>5472, +39214=>5473, +39333=>5474, +39438=>5475, +39617=>5476, +39683=>5477, +39686=>5478, +39759=>5479, +39758=>5480, +39757=>5481, +39882=>5482, +39881=>5483, +39933=>5484, +39880=>5485, +39872=>5486, +40273=>5487, +40285=>5488, +40288=>5489, +40672=>5490, +40725=>5491, +40748=>5492, +20787=>5493, +22181=>5494, +22184=>5495, +22750=>5496, +22751=>5497, +22754=>5498, +23541=>5499, +40848=>5500, +24300=>5501, +25074=>5502, +25079=>5503, +25078=>5504, +25077=>5505, +25856=>5506, +25871=>5507, +26336=>5508, +26333=>5509, +27365=>5510, +27357=>5511, +27354=>5512, +27347=>5513, +28699=>5514, +28703=>5515, +28712=>5516, +28698=>5517, +28701=>5518, +28693=>5519, +28696=>5520, +29190=>5521, +29197=>5522, +29272=>5523, +29346=>5524, +29560=>5525, +29562=>5526, +29885=>5527, +29898=>5528, +29923=>5529, +30087=>5530, +30086=>5531, +30303=>5532, +30305=>5533, +30663=>5534, +31001=>5535, +31153=>5536, +31339=>5537, +31337=>5538, +31806=>5539, +31807=>5540, +31800=>5541, +31805=>5542, +31799=>5543, +31808=>5544, +32363=>5545, +32365=>5546, +32377=>5547, +32361=>5548, +32362=>5549, +32371=>5550, +32645=>5551, +32694=>5552, +32697=>5553, +32696=>5554, +33240=>5555, +34281=>5556, +34269=>5557, +34282=>5558, +34261=>5559, +34276=>5560, +34277=>5561, +34295=>5562, +34811=>5563, +34821=>5564, +34829=>5565, +34809=>5566, +34814=>5567, +35168=>5568, +35167=>5569, +35158=>5570, +35166=>5571, +35649=>5572, +35676=>5573, +35672=>5574, +35657=>5575, +35674=>5576, +35662=>5577, +35663=>5578, +35654=>5579, +35673=>5580, +36104=>5581, +36106=>5582, +36476=>5583, +36466=>5584, +36487=>5585, +36470=>5586, +36460=>5587, +36474=>5588, +36468=>5589, +36692=>5590, +36686=>5591, +36781=>5592, +37002=>5593, +37003=>5594, +37297=>5595, +37294=>5596, +37857=>5597, +37841=>5598, +37855=>5599, +37827=>5600, +37832=>5601, +37852=>5602, +37853=>5603, +37846=>5604, +37858=>5605, +37837=>5606, +37848=>5607, +37860=>5608, +37847=>5609, +37864=>5610, +38364=>5611, +38580=>5612, +38627=>5613, +38698=>5614, +38695=>5615, +38753=>5616, +38876=>5617, +38907=>5618, +39006=>5619, +39000=>5620, +39003=>5621, +39100=>5622, +39237=>5623, +39241=>5624, +39446=>5625, +39449=>5626, +39693=>5627, +39912=>5628, +39911=>5629, +39894=>5630, +39899=>5631, +40329=>5632, +40289=>5633, +40306=>5634, +40298=>5635, +40300=>5636, +40594=>5637, +40599=>5638, +40595=>5639, +40628=>5640, +21240=>5641, +22199=>5642, +22198=>5643, +22196=>5644, +22204=>5645, +22756=>5646, +23360=>5647, +23363=>5648, +23421=>5649, +23542=>5650, +24009=>5651, +25080=>5652, +25082=>5653, +25880=>5654, +25876=>5655, +25881=>5656, +26342=>5657, +26407=>5658, +27372=>5659, +28734=>5660, +28720=>5661, +28722=>5662, +29200=>5663, +29563=>5664, +29903=>5665, +30306=>5666, +30309=>5667, +31014=>5668, +31018=>5669, +31020=>5670, +31019=>5671, +31431=>5672, +31478=>5673, +31820=>5674, +31811=>5675, +31821=>5676, +31983=>5677, +31984=>5678, +36782=>5679, +32381=>5680, +32380=>5681, +32386=>5682, +32588=>5683, +32768=>5684, +33242=>5685, +33382=>5686, +34299=>5687, +34297=>5688, +34321=>5689, +34298=>5690, +34310=>5691, +34315=>5692, +34311=>5693, +34314=>5694, +34836=>5695, +34837=>5696, +35172=>5697, +35258=>5698, +35320=>5699, +35696=>5700, +35692=>5701, +35686=>5702, +35695=>5703, +35679=>5704, +35691=>5705, +36111=>5706, +36109=>5707, +36489=>5708, +36481=>5709, +36485=>5710, +36482=>5711, +37300=>5712, +37323=>5713, +37912=>5714, +37891=>5715, +37885=>5716, +38369=>5717, +38704=>5718, +39108=>5719, +39250=>5720, +39249=>5721, +39336=>5722, +39467=>5723, +39472=>5724, +39479=>5725, +39477=>5726, +39955=>5727, +39949=>5728, +40569=>5729, +40629=>5730, +40680=>5731, +40751=>5732, +40799=>5733, +40803=>5734, +40801=>5735, +20791=>5736, +20792=>5737, +22209=>5738, +22208=>5739, +22210=>5740, +22804=>5741, +23660=>5742, +24013=>5743, +25084=>5744, +25086=>5745, +25885=>5746, +25884=>5747, +26005=>5748, +26345=>5749, +27387=>5750, +27396=>5751, +27386=>5752, +27570=>5753, +28748=>5754, +29211=>5755, +29351=>5756, +29910=>5757, +29908=>5758, +30313=>5759, +30675=>5760, +31824=>5761, +32399=>5762, +32396=>5763, +32700=>5764, +34327=>5765, +34349=>5766, +34330=>5767, +34851=>5768, +34850=>5769, +34849=>5770, +34847=>5771, +35178=>5772, +35180=>5773, +35261=>5774, +35700=>5775, +35703=>5776, +35709=>5777, +36115=>5778, +36490=>5779, +36493=>5780, +36491=>5781, +36703=>5782, +36783=>5783, +37306=>5784, +37934=>5785, +37939=>5786, +37941=>5787, +37946=>5788, +37944=>5789, +37938=>5790, +37931=>5791, +38370=>5792, +38712=>5793, +38713=>5794, +38706=>5795, +38911=>5796, +58586=>5796, +39015=>5797, +39013=>5798, +39255=>5799, +39493=>5800, +39491=>5801, +39488=>5802, +39486=>5803, +39631=>5804, +39764=>5805, +39761=>5806, +39981=>5807, +39973=>5808, +40367=>5809, +40372=>5810, +40386=>5811, +40376=>5812, +40605=>5813, +40687=>5814, +40729=>5815, +40796=>5816, +40806=>5817, +40807=>5818, +20796=>5819, +20795=>5820, +22216=>5821, +22218=>5822, +22217=>5823, +23423=>5824, +24020=>5825, +24018=>5826, +24398=>5827, +25087=>5828, +25892=>5829, +27402=>5830, +27489=>5831, +28753=>5832, +28760=>5833, +29568=>5834, +29924=>5835, +30090=>5836, +30318=>5837, +30316=>5838, +31155=>5839, +31840=>5840, +31839=>5841, +32894=>5842, +32893=>5843, +33247=>5844, +35186=>5845, +35183=>5846, +35324=>5847, +35712=>5848, +36118=>5849, +36119=>5850, +36497=>5851, +36499=>5852, +36705=>5853, +37192=>5854, +37956=>5855, +37969=>5856, +37970=>5857, +38717=>5858, +38718=>5859, +38851=>5860, +38849=>5861, +39019=>5862, +39253=>5863, +39509=>5864, +39501=>5865, +39634=>5866, +39706=>5867, +40009=>5868, +39985=>5869, +39998=>5870, +39995=>5871, +40403=>5872, +40407=>5873, +40756=>5874, +40812=>5875, +40810=>5876, +40852=>5877, +22220=>5878, +24022=>5879, +25088=>5880, +25891=>5881, +25899=>5882, +25898=>5883, +26348=>5884, +27408=>5885, +29914=>5886, +31434=>5887, +31844=>5888, +31843=>5889, +31845=>5890, +32403=>5891, +32406=>5892, +32404=>5893, +33250=>5894, +34360=>5895, +34367=>5896, +34865=>5897, +35722=>5898, +37008=>5899, +37007=>5900, +37987=>5901, +37984=>5902, +37988=>5903, +38760=>5904, +39023=>5905, +39260=>5906, +39514=>5907, +39515=>5908, +39511=>5909, +39635=>5910, +39636=>5911, +39633=>5912, +40020=>5913, +40023=>5914, +40022=>5915, +40421=>5916, +40607=>5917, +40692=>5918, +22225=>5919, +22761=>5920, +25900=>5921, +28766=>5922, +30321=>5923, +30322=>5924, +30679=>5925, +60226=>5925, +32592=>5926, +32648=>5927, +34870=>5928, +34873=>5929, +34914=>5930, +35731=>5931, +35730=>5932, +35734=>5933, +33399=>5934, +36123=>5935, +37312=>5936, +37994=>5937, +38722=>5938, +38728=>5939, +38724=>5940, +38854=>5941, +39024=>5942, +39519=>5943, +39714=>5944, +39768=>5945, +40031=>5946, +40441=>5947, +40442=>5948, +40572=>5949, +40573=>5950, +40711=>5951, +40823=>5952, +40818=>5953, +24307=>5954, +27414=>5955, +28771=>5956, +31852=>5957, +31854=>5958, +34875=>5959, +35264=>5960, +36513=>5961, +37313=>5962, +38002=>5963, +38000=>5964, +39025=>5965, +39262=>5966, +39638=>5967, +39715=>5968, +40652=>5969, +28772=>5970, +30682=>5971, +35738=>5972, +38007=>5973, +38857=>5974, +39522=>5975, +39525=>5976, +32412=>5977, +35740=>5978, +36522=>5979, +37317=>5980, +38013=>5981, +38014=>5982, +38012=>5983, +40055=>5984, +40056=>5985, +40695=>5986, +35924=>5987, +38015=>5988, +40474=>5989, +29224=>5990, +39530=>5991, +39729=>5992, +40475=>5993, +40478=>5994, +31858=>5995, +20034=>5996, +20060=>5997, +12048=>5998, +20981=>5998, +12053=>5999, +21274=>5999, +12058=>6000, +21378=>6000, +19975=>6001, +19980=>6002, +20039=>6003, +20109=>6004, +12062=>6005, +22231=>6005, +12076=>6006, +23662=>6006, +12091=>6007, +24435=>6007, +19983=>6008, +20871=>6009, +19982=>6010, +20014=>6011, +20115=>6012, +20162=>6013, +20169=>6014, +20168=>6015, +20888=>6016, +21244=>6017, +21356=>6018, +21433=>6019, +22304=>6020, +22787=>6021, +22828=>6022, +23568=>6023, +60417=>6023, +24063=>6024, +26081=>6025, +12110=>6026, +27571=>6026, +27596=>6027, +12115=>6028, +27668=>6028, +12121=>6029, +29247=>6029, +20017=>6030, +20028=>6031, +20200=>6032, +20188=>6033, +20201=>6034, +20193=>6035, +20189=>6036, +20186=>6037, +21004=>6038, +21001=>6039, +21276=>6040, +21324=>6041, +22306=>6042, +22307=>6043, +22807=>6044, +22831=>6045, +23425=>6046, +23428=>6047, +23570=>6048, +23611=>6049, +23668=>6050, +23667=>6051, +24068=>6052, +24192=>6053, +24194=>6054, +24521=>6055, +25097=>6056, +25168=>6057, +27669=>6058, +27702=>6059, +27715=>6060, +27711=>6061, +27707=>6062, +29358=>6063, +29360=>6064, +29578=>6065, +12145=>6066, +31160=>6066, +32906=>6067, +38430=>6068, +20238=>6069, +20248=>6070, +20268=>6071, +20213=>6072, +20244=>6073, +20209=>6074, +20224=>6075, +20215=>6076, +20232=>6077, +20253=>6078, +20226=>6079, +20229=>6080, +20258=>6081, +20243=>6082, +20228=>6083, +20212=>6084, +20242=>6085, +20913=>6086, +21011=>6087, +21008=>6088, +21158=>6089, +21282=>6090, +21279=>6091, +21325=>6092, +21386=>6093, +21511=>6094, +22241=>6095, +22239=>6096, +22318=>6097, +22314=>6098, +22324=>6099, +22844=>6100, +22912=>6101, +22908=>6102, +22917=>6103, +22907=>6104, +22910=>6105, +22903=>6106, +22911=>6107, +23382=>6108, +23573=>6109, +23589=>6110, +23676=>6111, +23674=>6112, +23675=>6113, +23678=>6114, +24031=>6115, +24181=>6116, +57646=>6116, +24196=>6117, +24322=>6118, +24346=>6119, +24436=>6120, +24533=>6121, +24532=>6122, +24527=>6123, +25180=>6124, +25182=>6125, +25188=>6126, +25185=>6127, +25190=>6128, +25186=>6129, +25177=>6130, +25184=>6131, +25178=>6132, +25189=>6133, +25911=>6134, +26095=>6135, +26094=>6136, +26430=>6137, +26425=>6138, +26424=>6139, +26427=>6140, +26426=>6141, +26431=>6142, +26428=>6143, +26419=>6144, +27672=>6145, +27718=>6146, +27730=>6147, +27740=>6148, +27727=>6149, +27722=>6150, +60796=>6150, +27732=>6151, +27723=>6152, +27724=>6153, +28785=>6154, +29278=>6155, +29364=>6156, +29365=>6157, +29582=>6158, +29994=>6159, +30335=>6160, +31349=>6161, +12153=>6162, +32593=>6162, +12171=>6163, +33400=>6163, +33404=>6164, +33408=>6165, +33405=>6166, +33407=>6167, +12172=>6168, +34381=>6168, +12177=>6169, +35198=>6169, +37017=>6170, +59347=>6171, +37015=>6171, +37016=>6172, +37019=>6173, +37012=>6174, +38434=>6175, +38436=>6176, +38432=>6177, +38435=>6178, +20310=>6179, +20283=>6180, +20322=>6181, +20297=>6182, +20307=>6183, +20324=>6184, +20286=>6185, +20327=>6186, +20306=>6187, +20319=>6188, +20289=>6189, +20312=>6190, +20269=>6191, +20275=>6192, +20287=>6193, +20321=>6194, +20879=>6195, +20921=>6196, +21020=>6197, +21022=>6198, +21025=>6199, +21165=>6200, +21166=>6201, +21257=>6202, +21347=>6203, +21362=>6204, +21390=>6205, +21391=>6206, +21552=>6207, +21559=>6208, +21546=>6209, +21588=>6210, +21573=>6211, +21529=>6212, +21532=>6213, +21541=>6214, +21528=>6215, +21565=>6216, +21583=>6217, +21569=>6218, +21544=>6219, +21540=>6220, +21575=>6221, +22254=>6222, +22247=>6223, +22245=>6224, +22337=>6225, +22341=>6226, +22348=>6227, +22345=>6228, +22347=>6229, +22354=>6230, +22790=>6231, +22848=>6232, +22950=>6233, +22936=>6234, +22944=>6235, +22935=>6236, +22926=>6237, +22946=>6238, +22928=>6239, +22927=>6240, +22951=>6241, +22945=>6242, +23438=>6243, +23442=>6244, +23592=>6245, +23594=>6246, +23693=>6247, +23695=>6248, +23688=>6249, +23691=>6250, +23689=>6251, +23698=>6252, +23690=>6253, +23686=>6254, +23699=>6255, +23701=>6256, +24032=>6257, +24074=>6258, +24078=>6259, +24203=>6260, +24201=>6261, +24204=>6262, +24200=>6263, +24205=>6264, +24325=>6265, +24349=>6266, +24440=>6267, +24438=>6268, +24530=>6269, +24529=>6270, +24528=>6271, +24557=>6272, +24552=>6273, +24558=>6274, +24563=>6275, +24545=>6276, +24548=>6277, +24547=>6278, +24570=>6279, +24559=>6280, +24567=>6281, +24571=>6282, +24576=>6283, +24564=>6284, +25146=>6285, +25219=>6286, +25228=>6287, +25230=>6288, +25231=>6289, +25236=>6290, +25223=>6291, +25201=>6292, +25211=>6293, +25210=>6294, +25200=>6295, +25217=>6296, +25224=>6297, +25207=>6298, +25213=>6299, +25202=>6300, +25204=>6301, +26096=>6302, +26100=>6303, +26099=>6304, +26098=>6305, +26101=>6306, +26437=>6307, +26439=>6308, +26457=>6309, +26453=>6310, +26444=>6311, +26440=>6312, +26461=>6313, +26445=>6314, +26458=>6315, +26443=>6316, +27600=>6317, +27673=>6318, +27674=>6319, +27768=>6320, +27751=>6321, +27755=>6322, +27780=>6323, +27787=>6324, +27791=>6325, +27761=>6326, +27759=>6327, +27753=>6328, +27802=>6329, +27757=>6330, +27783=>6331, +27797=>6332, +27804=>6333, +57900=>6333, +27750=>6334, +27763=>6335, +27749=>6336, +27771=>6337, +27790=>6338, +28788=>6339, +28794=>6340, +29283=>6341, +29375=>6342, +29373=>6343, +29379=>6344, +29382=>6345, +29377=>6346, +29370=>6347, +29381=>6348, +29589=>6349, +29591=>6350, +29587=>6351, +29588=>6352, +29586=>6353, +30010=>6354, +30009=>6355, +30100=>6356, +30101=>6357, +30337=>6358, +31037=>6359, +32820=>6360, +32917=>6361, +32921=>6362, +32912=>6363, +32914=>6364, +32924=>6365, +33424=>6366, +33423=>6367, +33413=>6368, +33422=>6369, +33425=>6370, +33427=>6371, +33418=>6372, +33411=>6373, +33412=>6374, +12184=>6375, +35960=>6375, +36809=>6376, +36799=>6377, +37023=>6378, +37025=>6379, +37029=>6380, +37022=>6381, +37031=>6382, +37024=>6383, +38448=>6384, +38440=>6385, +38447=>6386, +38445=>6387, +20019=>6388, +20376=>6389, +20348=>6390, +20357=>6391, +20349=>6392, +20352=>6393, +20359=>6394, +20342=>6395, +20340=>6396, +20361=>6397, +20356=>6398, +20343=>6399, +20300=>6400, +20375=>6401, +20330=>6402, +20378=>6403, +20345=>6404, +20353=>6405, +20344=>6406, +20368=>6407, +20380=>6408, +20372=>6409, +20382=>6410, +20370=>6411, +20354=>6412, +20373=>6413, +20331=>6414, +20334=>6415, +20894=>6416, +20924=>6417, +20926=>6418, +21045=>6419, +21042=>6420, +21043=>6421, +21062=>6422, +21041=>6423, +21180=>6424, +21258=>6425, +21259=>6426, +21308=>6427, +21394=>6428, +21396=>6429, +21639=>6430, +21631=>6431, +21633=>6432, +21649=>6433, +21634=>6434, +21640=>6435, +21611=>6436, +21626=>6437, +21630=>6438, +21605=>6439, +21612=>6440, +21620=>6441, +21606=>6442, +21645=>6443, +21615=>6444, +21601=>6445, +21600=>6446, +21656=>6447, +21603=>6448, +21607=>6449, +21604=>6450, +22263=>6451, +22265=>6452, +22383=>6453, +22386=>6454, +22381=>6455, +22379=>6456, +22385=>6457, +22384=>6458, +22390=>6459, +22400=>6460, +22389=>6461, +22395=>6462, +22387=>6463, +22388=>6464, +22370=>6465, +22376=>6466, +22397=>6467, +22796=>6468, +22853=>6469, +22965=>6470, +22970=>6471, +22991=>6472, +22990=>6473, +22962=>6474, +22988=>6475, +22977=>6476, +22966=>6477, +22972=>6478, +22979=>6479, +22998=>6480, +22961=>6481, +22973=>6482, +22976=>6483, +22984=>6484, +22964=>6485, +22983=>6486, +23394=>6487, +23397=>6488, +23443=>6489, +23445=>6490, +23620=>6491, +23623=>6492, +23726=>6493, +23716=>6494, +23712=>6495, +23733=>6496, +23727=>6497, +23720=>6498, +23724=>6499, +23711=>6500, +23715=>6501, +23725=>6502, +23714=>6503, +23722=>6504, +23719=>6505, +23709=>6506, +23717=>6507, +23734=>6508, +23728=>6509, +23718=>6510, +24087=>6511, +24084=>6512, +24089=>6513, +24360=>6514, +24354=>6515, +24355=>6516, +24356=>6517, +24404=>6518, +24450=>6519, +24446=>6520, +24445=>6521, +24542=>6522, +24549=>6523, +24621=>6524, +24614=>6525, +24601=>6526, +24626=>6527, +24587=>6528, +24628=>6529, +24586=>6530, +24599=>6531, +24627=>6532, +24602=>6533, +24606=>6534, +24620=>6535, +24610=>6536, +24589=>6537, +24592=>6538, +24622=>6539, +24595=>6540, +24593=>6541, +24588=>6542, +24585=>6543, +24604=>6544, +25108=>6545, +25149=>6546, +25261=>6547, +25268=>6548, +25297=>6549, +25278=>6550, +25258=>6551, +25270=>6552, +25290=>6553, +25262=>6554, +25267=>6555, +25263=>6556, +25275=>6557, +25257=>6558, +25264=>6559, +25272=>6560, +25917=>6561, +26024=>6562, +26043=>6563, +26121=>6564, +26108=>6565, +26116=>6566, +26130=>6567, +26120=>6568, +26107=>6569, +26115=>6570, +26123=>6571, +26125=>6572, +26117=>6573, +26109=>6574, +26129=>6575, +26128=>6576, +26358=>6577, +26378=>6578, +26501=>6579, +26476=>6580, +26510=>6581, +26514=>6582, +26486=>6583, +26491=>6584, +26520=>6585, +26502=>6586, +26500=>6587, +26484=>6588, +26509=>6589, +26508=>6590, +26490=>6591, +26527=>6592, +26513=>6593, +26521=>6594, +26499=>6595, +26493=>6596, +26497=>6597, +26488=>6598, +26489=>6599, +26516=>6600, +27429=>6601, +27520=>6602, +27518=>6603, +27614=>6604, +27677=>6605, +27795=>6606, +27884=>6607, +27883=>6608, +27886=>6609, +27865=>6610, +27830=>6611, +27860=>6612, +27821=>6613, +27879=>6614, +27831=>6615, +27856=>6616, +27842=>6617, +27834=>6618, +27843=>6619, +27846=>6620, +27885=>6621, +27890=>6622, +27858=>6623, +27869=>6624, +27828=>6625, +27786=>6626, +27805=>6627, +27776=>6628, +27870=>6629, +27840=>6630, +27952=>6631, +27853=>6632, +27847=>6633, +27824=>6634, +27897=>6635, +27855=>6636, +27881=>6637, +27857=>6638, +28820=>6639, +28824=>6640, +28805=>6641, +28819=>6642, +28806=>6643, +28804=>6644, +28817=>6645, +28822=>6646, +28802=>6647, +28826=>6648, +28803=>6649, +29290=>6650, +29398=>6651, +29387=>6652, +29400=>6653, +29385=>6654, +29404=>6655, +29394=>6656, +29396=>6657, +29402=>6658, +29388=>6659, +29393=>6660, +29604=>6661, +29601=>6662, +29613=>6663, +29606=>6664, +29602=>6665, +29600=>6666, +29612=>6667, +29597=>6668, +29917=>6669, +29928=>6670, +30015=>6671, +30016=>6672, +30014=>6673, +30092=>6674, +30104=>6675, +30383=>6676, +30451=>6677, +30449=>6678, +30448=>6679, +30453=>6680, +30712=>6681, +30716=>6682, +30713=>6683, +30715=>6684, +30714=>6685, +30711=>6686, +31042=>6687, +31039=>6688, +31173=>6689, +31352=>6690, +31355=>6691, +31483=>6692, +31861=>6693, +31997=>6694, +32821=>6695, +32911=>6696, +32942=>6697, +32931=>6698, +32952=>6699, +32949=>6700, +32941=>6701, +33312=>6702, +33440=>6703, +33472=>6704, +33451=>6705, +33434=>6706, +33432=>6707, +33435=>6708, +33461=>6709, +33447=>6710, +33454=>6711, +33468=>6712, +33438=>6713, +33466=>6714, +33460=>6715, +33448=>6716, +33441=>6717, +33449=>6718, +33474=>6719, +33444=>6720, +33475=>6721, +33462=>6722, +33442=>6723, +34416=>6724, +34415=>6725, +34413=>6726, +34414=>6727, +35926=>6728, +36818=>6729, +36811=>6730, +36819=>6731, +36813=>6732, +36822=>6733, +36821=>6734, +36823=>6735, +37042=>6736, +37044=>6737, +37039=>6738, +37043=>6739, +37040=>6740, +38457=>6741, +38461=>6742, +38460=>6743, +38458=>6744, +38467=>6745, +20429=>6746, +20421=>6747, +20435=>6748, +20402=>6749, +20425=>6750, +20427=>6751, +20417=>6752, +20436=>6753, +20444=>6754, +20441=>6755, +20411=>6756, +60346=>6756, +20403=>6757, +20443=>6758, +20423=>6759, +20438=>6760, +20410=>6761, +20416=>6762, +20409=>6763, +20460=>6764, +21060=>6765, +21065=>6766, +21184=>6767, +21186=>6768, +21309=>6769, +21372=>6770, +21399=>6771, +21398=>6772, +21401=>6773, +21400=>6774, +21690=>6775, +21665=>6776, +21677=>6777, +21669=>6778, +21711=>6779, +21699=>6780, +33549=>6781, +21687=>6782, +21678=>6783, +21718=>6784, +21686=>6785, +21701=>6786, +21702=>6787, +21664=>6788, +21616=>6789, +21692=>6790, +21666=>6791, +21694=>6792, +21618=>6793, +21726=>6794, +21680=>6795, +22453=>6796, +22430=>6797, +22431=>6798, +22436=>6799, +22412=>6800, +22423=>6801, +22429=>6802, +22427=>6803, +22420=>6804, +22424=>6805, +22415=>6806, +22425=>6807, +22437=>6808, +22426=>6809, +22421=>6810, +22772=>6811, +22797=>6812, +22867=>6813, +23009=>6814, +23006=>6815, +23022=>6816, +23040=>6817, +23025=>6818, +23005=>6819, +23034=>6820, +23037=>6821, +23036=>6822, +23030=>6823, +23012=>6824, +23026=>6825, +23031=>6826, +23003=>6827, +23017=>6828, +23027=>6829, +23029=>6830, +23008=>6831, +23038=>6832, +23028=>6833, +23021=>6834, +23464=>6835, +23628=>6836, +23760=>6837, +23768=>6838, +23756=>6839, +23767=>6840, +23755=>6841, +23771=>6842, +23774=>6843, +23770=>6844, +23753=>6845, +23751=>6846, +23754=>6847, +23766=>6848, +23763=>6849, +23764=>6850, +23759=>6851, +23752=>6852, +23750=>6853, +23758=>6854, +23775=>6855, +23800=>6856, +24057=>6857, +24097=>6858, +24098=>6859, +24099=>6860, +24096=>6861, +24100=>6862, +24240=>6863, +24228=>6864, +24226=>6865, +24219=>6866, +24227=>6867, +24229=>6868, +24327=>6869, +24366=>6870, +24406=>6871, +24454=>6872, +24631=>6873, +24633=>6874, +24660=>6875, +24690=>6876, +24670=>6877, +24645=>6878, +24659=>6879, +24647=>6880, +24649=>6881, +24667=>6882, +24652=>6883, +24640=>6884, +24642=>6885, +24671=>6886, +24612=>6887, +24644=>6888, +24664=>6889, +24678=>6890, +24686=>6891, +25154=>6892, +25155=>6893, +25295=>6894, +25357=>6895, +25355=>6896, +25333=>6897, +25358=>6898, +25347=>6899, +25323=>6900, +25337=>6901, +25359=>6902, +25356=>6903, +25336=>6904, +25334=>6905, +25344=>6906, +25363=>6907, +25364=>6908, +25338=>6909, +25365=>6910, +25339=>6911, +25328=>6912, +25921=>6913, +25923=>6914, +26026=>6915, +26047=>6916, +26166=>6917, +26145=>6918, +26162=>6919, +26165=>6920, +26140=>6921, +26150=>6922, +26146=>6923, +26163=>6924, +26155=>6925, +26170=>6926, +26141=>6927, +26164=>6928, +26169=>6929, +26158=>6930, +26383=>6931, +26384=>6932, +26561=>6933, +26610=>6934, +26568=>6935, +26554=>6936, +26588=>6937, +26555=>6938, +26616=>6939, +26584=>6940, +26560=>6941, +26551=>6942, +26565=>6943, +26603=>6944, +26596=>6945, +26591=>6946, +26549=>6947, +26573=>6948, +26547=>6949, +26615=>6950, +26614=>6951, +26606=>6952, +26595=>6953, +26562=>6954, +26553=>6955, +26574=>6956, +26599=>6957, +26608=>6958, +26546=>6959, +26620=>6960, +26566=>6961, +26605=>6962, +26572=>6963, +26542=>6964, +26598=>6965, +26587=>6966, +26618=>6967, +26569=>6968, +26570=>6969, +26563=>6970, +26602=>6971, +26571=>6972, +27432=>6973, +27522=>6974, +27524=>6975, +27574=>6976, +27606=>6977, +27608=>6978, +27616=>6979, +27680=>6980, +27681=>6981, +27944=>6982, +27956=>6983, +27949=>6984, +27935=>6985, +27964=>6986, +27967=>6987, +27922=>6988, +27914=>6989, +27866=>6990, +27955=>6991, +27908=>6992, +27929=>6993, +27962=>6994, +27930=>6995, +27921=>6996, +27904=>6997, +27933=>6998, +27970=>6999, +27905=>7000, +27928=>7001, +27959=>7002, +27907=>7003, +27919=>7004, +27968=>7005, +27911=>7006, +27936=>7007, +27948=>7008, +27912=>7009, +27938=>7010, +27913=>7011, +27920=>7012, +28855=>7013, +28831=>7014, +28862=>7015, +28849=>7016, +28848=>7017, +28833=>7018, +28852=>7019, +28853=>7020, +28841=>7021, +29249=>7022, +29257=>7023, +29258=>7024, +29292=>7025, +29296=>7026, +29299=>7027, +29294=>7028, +29386=>7029, +29412=>7030, +29416=>7031, +29419=>7032, +29407=>7033, +29418=>7034, +29414=>7035, +29411=>7036, +29573=>7037, +29644=>7038, +29634=>7039, +29640=>7040, +29637=>7041, +29625=>7042, +29622=>7043, +29621=>7044, +29620=>7045, +29675=>7046, +29631=>7047, +29639=>7048, +29630=>7049, +29635=>7050, +29638=>7051, +29624=>7052, +29643=>7053, +29932=>7054, +29934=>7055, +29998=>7056, +30023=>7057, +30024=>7058, +30119=>7059, +30122=>7060, +30329=>7061, +30404=>7062, +30472=>7063, +30467=>7064, +30468=>7065, +30469=>7066, +30474=>7067, +30455=>7068, +30459=>7069, +30458=>7070, +30695=>7071, +30696=>7072, +30726=>7073, +30737=>7074, +30738=>7075, +30725=>7076, +30736=>7077, +30735=>7078, +30734=>7079, +30729=>7080, +58095=>7080, +30723=>7081, +30739=>7082, +31050=>7083, +31052=>7084, +31051=>7085, +31045=>7086, +31044=>7087, +31189=>7088, +31181=>7089, +31183=>7090, +31190=>7091, +31182=>7092, +31360=>7093, +31358=>7094, +31441=>7095, +31488=>7096, +31489=>7097, +31866=>7098, +31864=>7099, +31865=>7100, +31871=>7101, +31872=>7102, +31873=>7103, +32003=>7104, +32008=>7105, +32001=>7106, +32600=>7107, +32657=>7108, +32653=>7109, +32702=>7110, +32775=>7111, +32782=>7112, +32783=>7113, +32788=>7114, +32823=>7115, +32984=>7116, +32967=>7117, +32992=>7118, +32977=>7119, +32968=>7120, +32962=>7121, +32976=>7122, +32965=>7123, +32995=>7124, +32985=>7125, +32988=>7126, +32970=>7127, +32981=>7128, +32969=>7129, +32975=>7130, +32983=>7131, +32998=>7132, +32973=>7133, +33279=>7134, +33313=>7135, +33428=>7136, +33497=>7137, +33534=>7138, +33529=>7139, +33543=>7140, +33512=>7141, +33536=>7142, +33493=>7143, +33594=>7144, +33515=>7145, +33494=>7146, +33524=>7147, +33516=>7148, +33505=>7149, +33522=>7150, +33525=>7151, +33548=>7152, +33531=>7153, +33526=>7154, +33520=>7155, +33514=>7156, +33508=>7157, +33504=>7158, +33530=>7159, +33523=>7160, +33517=>7161, +34423=>7162, +34420=>7163, +34428=>7164, +34419=>7165, +34881=>7166, +34894=>7167, +34919=>7168, +34922=>7169, +34921=>7170, +35283=>7171, +35332=>7172, +35335=>7173, +36210=>7174, +36835=>7175, +36833=>7176, +36846=>7177, +36832=>7178, +37105=>7179, +37053=>7180, +37055=>7181, +37077=>7182, +37061=>7183, +37054=>7184, +37063=>7185, +37067=>7186, +37064=>7187, +37332=>7188, +60294=>7188, +37331=>7189, +38484=>7190, +38479=>7191, +38481=>7192, +38483=>7193, +38474=>7194, +38478=>7195, +20510=>7196, +20485=>7197, +20487=>7198, +20499=>7199, +20514=>7200, +20528=>7201, +20507=>7202, +20469=>7203, +20468=>7204, +20531=>7205, +20535=>7206, +20524=>7207, +20470=>7208, +20471=>7209, +20503=>7210, +20508=>7211, +20512=>7212, +20519=>7213, +20533=>7214, +20527=>7215, +20529=>7216, +20494=>7217, +20826=>7218, +20884=>7219, +20883=>7220, +20938=>7221, +20932=>7222, +20933=>7223, +20936=>7224, +20942=>7225, +21089=>7226, +21082=>7227, +21074=>7228, +21086=>7229, +21087=>7230, +21077=>7231, +21090=>7232, +21197=>7233, +21262=>7234, +21406=>7235, +21798=>7236, +21730=>7237, +21783=>7238, +21778=>7239, +21735=>7240, +21747=>7241, +21732=>7242, +21786=>7243, +21759=>7244, +21764=>7245, +21768=>7246, +21739=>7247, +21777=>7248, +21765=>7249, +21745=>7250, +21770=>7251, +21755=>7252, +21751=>7253, +21752=>7254, +21728=>7255, +21774=>7256, +21763=>7257, +21771=>7258, +22273=>7259, +22274=>7260, +22476=>7261, +22578=>7262, +22485=>7263, +22482=>7264, +22458=>7265, +22470=>7266, +22461=>7267, +22460=>7268, +22456=>7269, +22454=>7270, +22463=>7271, +22471=>7272, +22480=>7273, +22457=>7274, +22465=>7275, +22798=>7276, +22858=>7277, +23065=>7278, +23062=>7279, +23085=>7280, +23086=>7281, +23061=>7282, +23055=>7283, +23063=>7284, +23050=>7285, +23070=>7286, +23091=>7287, +23404=>7288, +23463=>7289, +23469=>7290, +23468=>7291, +23555=>7292, +23638=>7293, +23636=>7294, +23788=>7295, +23807=>7296, +23790=>7297, +23793=>7298, +23799=>7299, +23808=>7300, +23801=>7301, +24105=>7302, +24104=>7303, +24232=>7304, +24238=>7305, +24234=>7306, +24236=>7307, +24371=>7308, +24368=>7309, +24423=>7310, +24669=>7311, +24666=>7312, +24679=>7313, +24641=>7314, +24738=>7315, +24712=>7316, +24704=>7317, +24722=>7318, +24705=>7319, +24733=>7320, +24707=>7321, +24725=>7322, +24731=>7323, +24727=>7324, +24711=>7325, +24732=>7326, +24718=>7327, +25113=>7328, +25158=>7329, +25330=>7330, +25360=>7331, +25430=>7332, +25388=>7333, +25412=>7334, +25413=>7335, +25398=>7336, +25411=>7337, +25572=>7338, +25401=>7339, +25419=>7340, +25418=>7341, +25404=>7342, +25385=>7343, +25409=>7344, +25396=>7345, +25432=>7346, +25428=>7347, +25433=>7348, +25389=>7349, +25415=>7350, +25395=>7351, +25434=>7352, +25425=>7353, +25400=>7354, +25431=>7355, +25408=>7356, +25416=>7357, +25930=>7358, +25926=>7359, +26054=>7360, +26051=>7361, +26052=>7362, +26050=>7363, +26186=>7364, +26207=>7365, +26183=>7366, +26193=>7367, +26386=>7368, +26387=>7369, +26655=>7370, +26650=>7371, +26697=>7372, +26674=>7373, +26675=>7374, +26683=>7375, +26699=>7376, +26703=>7377, +26646=>7378, +26673=>7379, +26652=>7380, +26677=>7381, +26667=>7382, +26669=>7383, +26671=>7384, +26702=>7385, +26692=>7386, +26676=>7387, +26653=>7388, +26642=>7389, +26644=>7390, +26662=>7391, +26664=>7392, +26670=>7393, +26701=>7394, +26682=>7395, +26661=>7396, +26656=>7397, +27436=>7398, +27439=>7399, +27437=>7400, +27441=>7401, +27444=>7402, +27501=>7403, +32898=>7404, +27528=>7405, +27622=>7406, +27620=>7407, +27624=>7408, +27619=>7409, +27618=>7410, +27623=>7411, +27685=>7412, +28026=>7413, +28003=>7414, +28004=>7415, +28022=>7416, +27917=>7417, +28001=>7418, +28050=>7419, +27992=>7420, +28002=>7421, +28013=>7422, +28015=>7423, +28049=>7424, +28045=>7425, +28143=>7426, +28031=>7427, +28038=>7428, +27998=>7429, +28007=>7430, +59078=>7430, +28000=>7431, +28055=>7432, +28016=>7433, +28028=>7434, +27999=>7435, +28034=>7436, +28056=>7437, +27951=>7438, +28008=>7439, +28043=>7440, +28030=>7441, +28032=>7442, +28036=>7443, +27926=>7444, +28035=>7445, +28027=>7446, +28029=>7447, +28021=>7448, +28048=>7449, +28892=>7450, +28883=>7451, +28881=>7452, +28893=>7453, +28875=>7454, +32569=>7455, +28898=>7456, +28887=>7457, +28882=>7458, +28894=>7459, +28896=>7460, +28884=>7461, +28877=>7462, +28869=>7463, +28870=>7464, +28871=>7465, +28890=>7466, +28878=>7467, +28897=>7468, +29250=>7469, +29304=>7470, +29303=>7471, +29302=>7472, +29440=>7473, +29434=>7474, +29428=>7475, +29438=>7476, +29430=>7477, +29427=>7478, +29435=>7479, +29441=>7480, +29651=>7481, +29657=>7482, +29669=>7483, +29654=>7484, +29628=>7485, +29671=>7486, +29667=>7487, +29673=>7488, +29660=>7489, +29650=>7490, +29659=>7491, +29652=>7492, +29661=>7493, +29658=>7494, +29655=>7495, +29656=>7496, +29672=>7497, +29918=>7498, +29919=>7499, +29940=>7500, +29941=>7501, +29985=>7502, +30043=>7503, +30047=>7504, +30128=>7505, +30145=>7506, +30139=>7507, +30148=>7508, +30144=>7509, +30143=>7510, +30134=>7511, +30138=>7512, +30346=>7513, +30409=>7514, +30493=>7515, +30491=>7516, +30480=>7517, +30483=>7518, +30482=>7519, +30499=>7520, +30481=>7521, +30485=>7522, +30489=>7523, +30490=>7524, +30498=>7525, +30503=>7526, +30755=>7527, +30764=>7528, +30754=>7529, +30773=>7530, +30767=>7531, +30760=>7532, +30766=>7533, +30763=>7534, +30753=>7535, +30761=>7536, +30771=>7537, +30762=>7538, +30769=>7539, +31060=>7540, +31067=>7541, +31055=>7542, +31068=>7543, +31059=>7544, +31058=>7545, +31057=>7546, +31211=>7547, +31212=>7548, +31200=>7549, +31214=>7550, +31213=>7551, +31210=>7552, +31196=>7553, +31198=>7554, +31197=>7555, +31366=>7556, +31369=>7557, +31365=>7558, +31371=>7559, +31372=>7560, +31370=>7561, +31367=>7562, +31448=>7563, +31504=>7564, +31492=>7565, +31507=>7566, +31493=>7567, +31503=>7568, +31496=>7569, +31498=>7570, +31502=>7571, +31497=>7572, +31506=>7573, +31876=>7574, +31889=>7575, +31882=>7576, +31884=>7577, +31880=>7578, +31885=>7579, +31877=>7580, +32030=>7581, +32029=>7582, +32017=>7583, +32014=>7584, +32024=>7585, +32022=>7586, +32019=>7587, +32031=>7588, +32018=>7589, +32015=>7590, +32012=>7591, +32604=>7592, +32609=>7593, +32606=>7594, +32608=>7595, +32605=>7596, +32603=>7597, +32662=>7598, +32658=>7599, +32707=>7600, +32706=>7601, +32704=>7602, +32790=>7603, +32830=>7604, +32825=>7605, +33018=>7606, +33010=>7607, +33017=>7608, +33013=>7609, +33025=>7610, +33019=>7611, +33024=>7612, +33281=>7613, +33327=>7614, +33317=>7615, +33587=>7616, +33581=>7617, +33604=>7618, +33561=>7619, +33617=>7620, +33573=>7621, +33622=>7622, +33599=>7623, +33601=>7624, +33574=>7625, +33564=>7626, +33570=>7627, +33602=>7628, +33614=>7629, +33563=>7630, +33578=>7631, +33544=>7632, +33596=>7633, +33613=>7634, +33558=>7635, +33572=>7636, +33568=>7637, +33591=>7638, +33583=>7639, +33577=>7640, +33607=>7641, +33605=>7642, +33612=>7643, +33619=>7644, +33566=>7645, +33580=>7646, +33611=>7647, +33575=>7648, +33608=>7649, +34387=>7650, +34386=>7651, +34466=>7652, +34472=>7653, +34454=>7654, +34445=>7655, +34449=>7656, +34462=>7657, +34439=>7658, +34455=>7659, +34438=>7660, +34443=>7661, +34458=>7662, +34437=>7663, +34469=>7664, +34457=>7665, +34465=>7666, +34471=>7667, +34453=>7668, +34456=>7669, +34446=>7670, +34461=>7671, +34448=>7672, +34452=>7673, +34883=>7674, +34884=>7675, +34925=>7676, +34933=>7677, +34934=>7678, +34930=>7679, +34944=>7680, +34929=>7681, +34943=>7682, +34927=>7683, +34947=>7684, +34942=>7685, +34932=>7686, +34940=>7687, +35346=>7688, +35911=>7689, +35927=>7690, +35963=>7691, +36004=>7692, +36003=>7693, +36214=>7694, +36216=>7695, +36277=>7696, +36279=>7697, +36278=>7698, +36561=>7699, +36563=>7700, +36862=>7701, +36853=>7702, +36866=>7703, +36863=>7704, +36859=>7705, +36868=>7706, +36860=>7707, +36854=>7708, +37078=>7709, +37088=>7710, +37081=>7711, +37082=>7712, +37091=>7713, +37087=>7714, +37093=>7715, +37080=>7716, +37083=>7717, +37079=>7718, +37084=>7719, +37092=>7720, +37200=>7721, +37198=>7722, +37199=>7723, +37333=>7724, +37346=>7725, +37338=>7726, +38492=>7727, +38495=>7728, +38588=>7729, +39139=>7730, +12221=>7731, +39647=>7731, +12223=>7732, +39727=>7732, +20095=>7733, +20592=>7734, +20586=>7735, +20577=>7736, +20574=>7737, +20576=>7738, +20563=>7739, +20555=>7740, +20573=>7741, +20594=>7742, +20552=>7743, +20557=>7744, +20545=>7745, +20571=>7746, +20554=>7747, +20578=>7748, +20501=>7749, +20549=>7750, +20575=>7751, +20585=>7752, +20587=>7753, +20579=>7754, +20580=>7755, +20550=>7756, +20544=>7757, +20590=>7758, +20595=>7759, +20567=>7760, +20561=>7761, +20944=>7762, +21099=>7763, +21101=>7764, +21100=>7765, +21102=>7766, +21206=>7767, +21203=>7768, +21293=>7769, +21404=>7770, +21877=>7771, +21878=>7772, +21820=>7773, +21837=>7774, +21840=>7775, +21812=>7776, +21802=>7777, +21841=>7778, +21858=>7779, +21814=>7780, +21813=>7781, +21808=>7782, +21842=>7783, +21829=>7784, +21772=>7785, +21810=>7786, +21861=>7787, +21838=>7788, +21817=>7789, +21832=>7790, +21805=>7791, +21819=>7792, +21824=>7793, +21835=>7794, +22282=>7795, +22279=>7796, +22523=>7797, +22548=>7798, +22498=>7799, +22518=>7800, +22492=>7801, +22516=>7802, +22528=>7803, +22509=>7804, +22525=>7805, +22536=>7806, +22520=>7807, +22539=>7808, +22515=>7809, +22479=>7810, +22535=>7811, +22510=>7812, +22499=>7813, +22514=>7814, +22501=>7815, +22508=>7816, +22497=>7817, +22542=>7818, +22524=>7819, +22544=>7820, +22503=>7821, +22529=>7822, +22540=>7823, +22513=>7824, +22505=>7825, +22512=>7826, +22541=>7827, +22532=>7828, +22876=>7829, +23136=>7830, +23128=>7831, +23125=>7832, +23143=>7833, +60437=>7833, +23134=>7834, +23096=>7835, +23093=>7836, +23149=>7837, +23120=>7838, +23135=>7839, +23141=>7840, +23148=>7841, +23123=>7842, +23140=>7843, +23127=>7844, +23107=>7845, +23133=>7846, +23122=>7847, +23108=>7848, +23131=>7849, +23112=>7850, +23182=>7851, +23102=>7852, +23117=>7853, +23097=>7854, +23116=>7855, +23152=>7856, +23145=>7857, +23111=>7858, +23121=>7859, +23126=>7860, +23106=>7861, +23132=>7862, +23410=>7863, +23406=>7864, +23489=>7865, +23488=>7866, +23641=>7867, +23838=>7868, +23819=>7869, +23837=>7870, +23834=>7871, +23840=>7872, +23820=>7873, +23848=>7874, +23821=>7875, +23846=>7876, +23845=>7877, +23823=>7878, +23856=>7879, +23826=>7880, +23843=>7881, +23839=>7882, +23854=>7883, +24126=>7884, +24116=>7885, +24241=>7886, +24244=>7887, +24249=>7888, +24242=>7889, +24243=>7890, +24374=>7891, +24376=>7892, +24475=>7893, +24470=>7894, +24479=>7895, +24714=>7896, +24720=>7897, +24710=>7898, +24766=>7899, +24752=>7900, +24762=>7901, +24787=>7902, +24788=>7903, +24783=>7904, +24804=>7905, +24793=>7906, +24797=>7907, +24776=>7908, +24753=>7909, +24795=>7910, +24759=>7911, +24778=>7912, +24767=>7913, +24771=>7914, +24781=>7915, +24768=>7916, +25394=>7917, +25445=>7918, +25482=>7919, +25474=>7920, +25469=>7921, +25533=>7922, +25502=>7923, +25517=>7924, +25501=>7925, +25495=>7926, +25515=>7927, +25486=>7928, +25455=>7929, +25479=>7930, +25488=>7931, +25454=>7932, +25519=>7933, +25461=>7934, +25500=>7935, +25453=>7936, +25518=>7937, +25468=>7938, +25508=>7939, +25403=>7940, +25503=>7941, +25464=>7942, +25477=>7943, +25473=>7944, +25489=>7945, +25485=>7946, +25456=>7947, +25939=>7948, +26061=>7949, +26213=>7950, +26209=>7951, +26203=>7952, +26201=>7953, +26204=>7954, +26210=>7955, +26392=>7956, +26745=>7957, +26759=>7958, +26768=>7959, +26780=>7960, +26733=>7961, +26734=>7962, +26798=>7963, +26795=>7964, +26966=>7965, +26735=>7966, +26787=>7967, +26796=>7968, +26793=>7969, +26741=>7970, +26740=>7971, +26802=>7972, +26767=>7973, +26743=>7974, +26770=>7975, +26748=>7976, +26731=>7977, +26738=>7978, +26794=>7979, +26752=>7980, +26737=>7981, +26750=>7982, +26779=>7983, +26774=>7984, +26763=>7985, +26784=>7986, +26761=>7987, +26788=>7988, +26744=>7989, +26747=>7990, +26769=>7991, +26764=>7992, +26762=>7993, +26749=>7994, +27446=>7995, +27443=>7996, +27447=>7997, +27448=>7998, +27537=>7999, +27535=>8000, +27533=>8001, +27534=>8002, +27532=>8003, +27690=>8004, +28096=>8005, +28075=>8006, +28084=>8007, +28083=>8008, +28276=>8009, +28076=>8010, +28137=>8011, +28130=>8012, +28087=>8013, +28150=>8014, +28116=>8015, +28160=>8016, +28104=>8017, +28128=>8018, +28127=>8019, +28118=>8020, +28094=>8021, +28133=>8022, +28124=>8023, +28125=>8024, +28123=>8025, +28148=>8026, +28106=>8027, +28093=>8028, +28141=>8029, +28144=>8030, +28090=>8031, +28117=>8032, +28098=>8033, +28111=>8034, +28105=>8035, +28112=>8036, +28146=>8037, +28115=>8038, +28157=>8039, +28119=>8040, +28109=>8041, +28131=>8042, +28091=>8043, +28922=>8044, +28941=>8045, +28919=>8046, +28951=>8047, +28916=>8048, +28940=>8049, +28912=>8050, +28932=>8051, +28915=>8052, +28944=>8053, +28924=>8054, +28927=>8055, +28934=>8056, +28947=>8057, +28928=>8058, +28920=>8059, +28918=>8060, +28939=>8061, +28930=>8062, +28942=>8063, +29310=>8064, +29307=>8065, +29308=>8066, +29311=>8067, +29469=>8068, +29463=>8069, +29447=>8070, +29457=>8071, +29464=>8072, +29450=>8073, +29448=>8074, +29439=>8075, +29455=>8076, +29470=>8077, +29576=>8078, +29686=>8079, +29688=>8080, +29685=>8081, +29700=>8082, +29697=>8083, +29693=>8084, +29703=>8085, +29696=>8086, +29690=>8087, +29692=>8088, +29695=>8089, +29708=>8090, +29707=>8091, +29684=>8092, +29704=>8093, +30052=>8094, +30051=>8095, +30158=>8096, +30162=>8097, +30159=>8098, +30155=>8099, +30156=>8100, +30161=>8101, +30160=>8102, +30351=>8103, +30345=>8104, +30419=>8105, +30521=>8106, +30511=>8107, +30509=>8108, +30513=>8109, +30514=>8110, +30516=>8111, +30515=>8112, +30525=>8113, +30501=>8114, +30523=>8115, +30517=>8116, +30792=>8117, +30802=>8118, +30793=>8119, +30797=>8120, +30794=>8121, +30796=>8122, +30758=>8123, +30789=>8124, +30800=>8125, +31076=>8126, +31079=>8127, +31081=>8128, +31082=>8129, +31075=>8130, +31083=>8131, +31073=>8132, +31163=>8133, +31226=>8134, +31224=>8135, +31222=>8136, +31223=>8137, +31375=>8138, +31380=>8139, +31376=>8140, +31541=>8141, +31547=>8142, +31540=>8143, +31525=>8144, +31536=>8145, +31522=>8146, +31524=>8147, +31539=>8148, +31512=>8149, +31530=>8150, +31517=>8151, +31537=>8152, +31531=>8153, +31533=>8154, +31535=>8155, +31538=>8156, +31544=>8157, +31514=>8158, +31523=>8159, +31892=>8160, +31896=>8161, +31894=>8162, +31907=>8163, +32053=>8164, +32061=>8165, +32056=>8166, +32054=>8167, +32058=>8168, +32069=>8169, +32044=>8170, +32041=>8171, +32065=>8172, +32071=>8173, +32062=>8174, +32063=>8175, +32074=>8176, +32059=>8177, +32040=>8178, +32611=>8179, +32661=>8180, +32668=>8181, +32669=>8182, +32667=>8183, +32714=>8184, +32715=>8185, +32717=>8186, +32720=>8187, +32721=>8188, +32711=>8189, +32719=>8190, +32713=>8191, +32799=>8192, +32798=>8193, +32795=>8194, +32839=>8195, +32835=>8196, +32840=>8197, +33048=>8198, +33061=>8199, +33049=>8200, +33051=>8201, +33069=>8202, +33055=>8203, +33068=>8204, +33054=>8205, +33057=>8206, +33045=>8207, +33063=>8208, +33053=>8209, +33058=>8210, +33297=>8211, +33336=>8212, +33331=>8213, +33338=>8214, +33332=>8215, +33330=>8216, +33396=>8217, +33680=>8218, +33699=>8219, +33704=>8220, +33677=>8221, +33658=>8222, +33651=>8223, +33700=>8224, +33652=>8225, +33679=>8226, +33665=>8227, +33685=>8228, +33689=>8229, +33653=>8230, +33684=>8231, +33705=>8232, +33661=>8233, +33667=>8234, +33676=>8235, +33693=>8236, +33691=>8237, +33706=>8238, +33675=>8239, +33662=>8240, +33701=>8241, +33711=>8242, +33672=>8243, +33687=>8244, +33712=>8245, +33663=>8246, +33702=>8247, +33671=>8248, +33710=>8249, +33654=>8250, +34393=>8251, +34390=>8252, +34495=>8253, +34487=>8254, +34498=>8255, +34497=>8256, +34501=>8257, +34490=>8258, +34480=>8259, +34504=>8260, +34489=>8261, +34483=>8262, +34488=>8263, +34508=>8264, +34484=>8265, +34491=>8266, +34492=>8267, +34499=>8268, +34493=>8269, +34494=>8270, +34898=>8271, +34953=>8272, +34965=>8273, +34984=>8274, +34978=>8275, +34986=>8276, +34970=>8277, +34961=>8278, +34977=>8279, +34975=>8280, +34968=>8281, +34983=>8282, +34969=>8283, +34971=>8284, +34967=>8285, +34980=>8286, +34988=>8287, +34956=>8288, +34963=>8289, +34958=>8290, +35202=>8291, +35286=>8292, +35289=>8293, +35285=>8294, +35376=>8295, +35367=>8296, +35372=>8297, +35358=>8298, +35897=>8299, +35899=>8300, +35932=>8301, +35933=>8302, +35965=>8303, +36005=>8304, +36221=>8305, +36219=>8306, +36217=>8307, +36284=>8308, +36290=>8309, +36281=>8310, +36287=>8311, +36289=>8312, +36568=>8313, +36574=>8314, +36573=>8315, +36572=>8316, +36567=>8317, +36576=>8318, +36577=>8319, +36900=>8320, +36875=>8321, +36881=>8322, +36892=>8323, +36876=>8324, +36897=>8325, +37103=>8326, +37098=>8327, +37104=>8328, +37108=>8329, +37106=>8330, +37107=>8331, +37076=>8332, +37099=>8333, +37100=>8334, +37097=>8335, +37206=>8336, +37208=>8337, +37210=>8338, +37203=>8339, +37205=>8340, +37356=>8341, +37364=>8342, +37361=>8343, +37363=>8344, +37368=>8345, +37348=>8346, +37369=>8347, +37354=>8348, +37355=>8349, +37367=>8350, +37352=>8351, +37358=>8352, +38266=>8353, +38278=>8354, +38280=>8355, +38524=>8356, +38509=>8357, +38507=>8358, +38513=>8359, +38511=>8360, +38591=>8361, +38762=>8362, +38916=>8363, +39141=>8364, +39319=>8365, +20635=>8366, +20629=>8367, +20628=>8368, +20638=>8369, +20619=>8370, +20643=>8371, +20611=>8372, +20620=>8373, +20622=>8374, +20637=>8375, +20584=>8376, +20636=>8377, +20626=>8378, +20610=>8379, +20615=>8380, +20831=>8381, +20948=>8382, +21266=>8383, +21265=>8384, +21412=>8385, +21415=>8386, +21905=>8387, +21928=>8388, +21925=>8389, +21933=>8390, +21879=>8391, +22085=>8392, +21922=>8393, +21907=>8394, +21896=>8395, +21903=>8396, +21941=>8397, +21889=>8398, +21923=>8399, +21906=>8400, +21924=>8401, +21885=>8402, +21900=>8403, +21926=>8404, +21887=>8405, +21909=>8406, +21921=>8407, +21902=>8408, +22284=>8409, +22569=>8410, +22583=>8411, +22553=>8412, +22558=>8413, +22567=>8414, +22563=>8415, +22568=>8416, +22517=>8417, +22600=>8418, +22565=>8419, +22556=>8420, +22555=>8421, +22579=>8422, +22591=>8423, +22582=>8424, +22574=>8425, +22585=>8426, +22584=>8427, +22573=>8428, +22572=>8429, +22587=>8430, +22881=>8431, +23215=>8432, +23188=>8433, +23199=>8434, +23162=>8435, +23202=>8436, +23198=>8437, +23160=>8438, +23206=>8439, +23164=>8440, +23205=>8441, +23212=>8442, +23189=>8443, +23214=>8444, +23095=>8445, +23172=>8446, +23178=>8447, +23191=>8448, +23171=>8449, +23179=>8450, +23209=>8451, +23163=>8452, +23165=>8453, +23180=>8454, +23196=>8455, +23183=>8456, +23187=>8457, +23197=>8458, +23530=>8459, +23501=>8460, +23499=>8461, +23508=>8462, +23505=>8463, +23498=>8464, +23502=>8465, +23564=>8466, +23600=>8467, +23863=>8468, +23875=>8469, +23915=>8470, +23873=>8471, +23883=>8472, +23871=>8473, +23861=>8474, +23889=>8475, +23886=>8476, +23893=>8477, +23859=>8478, +23866=>8479, +23890=>8480, +23869=>8481, +23857=>8482, +23897=>8483, +23874=>8484, +23865=>8485, +23881=>8486, +23864=>8487, +23868=>8488, +23858=>8489, +23862=>8490, +23872=>8491, +23877=>8492, +24132=>8493, +24129=>8494, +24408=>8495, +57673=>8495, +24486=>8496, +24485=>8497, +24491=>8498, +24777=>8499, +24761=>8500, +24780=>8501, +24802=>8502, +24782=>8503, +24772=>8504, +24852=>8505, +24818=>8506, +24842=>8507, +24854=>8508, +24837=>8509, +24821=>8510, +24851=>8511, +24824=>8512, +24828=>8513, +24830=>8514, +24769=>8515, +24835=>8516, +24856=>8517, +24861=>8518, +24848=>8519, +24831=>8520, +24836=>8521, +24843=>8522, +25162=>8523, +25492=>8524, +25521=>8525, +25520=>8526, +25550=>8527, +25573=>8528, +25576=>8529, +25583=>8530, +25539=>8531, +25757=>8532, +25587=>8533, +25546=>8534, +25568=>8535, +25590=>8536, +25557=>8537, +25586=>8538, +25589=>8539, +25697=>8540, +25567=>8541, +25534=>8542, +25565=>8543, +25564=>8544, +25540=>8545, +25560=>8546, +25555=>8547, +25538=>8548, +25543=>8549, +25548=>8550, +25547=>8551, +25544=>8552, +25584=>8553, +25559=>8554, +25561=>8555, +25906=>8556, +25959=>8557, +25962=>8558, +25956=>8559, +25948=>8560, +25960=>8561, +25957=>8562, +25996=>8563, +26013=>8564, +26014=>8565, +26030=>8566, +26064=>8567, +26066=>8568, +26236=>8569, +26220=>8570, +26235=>8571, +26240=>8572, +26225=>8573, +26233=>8574, +26218=>8575, +26226=>8576, +26369=>8577, +26892=>8578, +26835=>8579, +26884=>8580, +26844=>8581, +26922=>8582, +26860=>8583, +26858=>8584, +26865=>8585, +26895=>8586, +26838=>8587, +26871=>8588, +26859=>8589, +26852=>8590, +26870=>8591, +26899=>8592, +26896=>8593, +26867=>8594, +26849=>8595, +26887=>8596, +26828=>8597, +26888=>8598, +26992=>8599, +26804=>8600, +26897=>8601, +26863=>8602, +26822=>8603, +26900=>8604, +26872=>8605, +26832=>8606, +26877=>8607, +26876=>8608, +26856=>8609, +26891=>8610, +26890=>8611, +26903=>8612, +26830=>8613, +26824=>8614, +26845=>8615, +26846=>8616, +26854=>8617, +26868=>8618, +26833=>8619, +26886=>8620, +26836=>8621, +26857=>8622, +26901=>8623, +26917=>8624, +26823=>8625, +27449=>8626, +27451=>8627, +27455=>8628, +27452=>8629, +27540=>8630, +27543=>8631, +27545=>8632, +27541=>8633, +27581=>8634, +27632=>8635, +27634=>8636, +27635=>8637, +27696=>8638, +28156=>8639, +28230=>8640, +28231=>8641, +28191=>8642, +28233=>8643, +28296=>8644, +28220=>8645, +28221=>8646, +28229=>8647, +28258=>8648, +28203=>8649, +28223=>8650, +28225=>8651, +28253=>8652, +28275=>8653, +28188=>8654, +28211=>8655, +28235=>8656, +28224=>8657, +28241=>8658, +28219=>8659, +28163=>8660, +28206=>8661, +28254=>8662, +28264=>8663, +28252=>8664, +28257=>8665, +28209=>8666, +28200=>8667, +28256=>8668, +28273=>8669, +28267=>8670, +28217=>8671, +28194=>8672, +28208=>8673, +28243=>8674, +28261=>8675, +28199=>8676, +28280=>8677, +28260=>8678, +28279=>8679, +28245=>8680, +28281=>8681, +28242=>8682, +28262=>8683, +28213=>8684, +28214=>8685, +28250=>8686, +28960=>8687, +28958=>8688, +28975=>8689, +28923=>8690, +28974=>8691, +28977=>8692, +28963=>8693, +28965=>8694, +28962=>8695, +28978=>8696, +28959=>8697, +28968=>8698, +28986=>8699, +28955=>8700, +29259=>8701, +29274=>8702, +29320=>8703, +29321=>8704, +29318=>8705, +29317=>8706, +29323=>8707, +29458=>8708, +29451=>8709, +29488=>8710, +29474=>8711, +29489=>8712, +29491=>8713, +29479=>8714, +29490=>8715, +29485=>8716, +29478=>8717, +29475=>8718, +29493=>8719, +29452=>8720, +29742=>8721, +29740=>8722, +29744=>8723, +29739=>8724, +29718=>8725, +29722=>8726, +29729=>8727, +29741=>8728, +29745=>8729, +29732=>8730, +29731=>8731, +29725=>8732, +29737=>8733, +29728=>8734, +29746=>8735, +29947=>8736, +29999=>8737, +30063=>8738, +30060=>8739, +30183=>8740, +30170=>8741, +30177=>8742, +30182=>8743, +30173=>8744, +30175=>8745, +30180=>8746, +30167=>8747, +30357=>8748, +30354=>8749, +30426=>8750, +30534=>8751, +30535=>8752, +30532=>8753, +30541=>8754, +30533=>8755, +30538=>8756, +30542=>8757, +30539=>8758, +30540=>8759, +30686=>8760, +30700=>8761, +30816=>8762, +30820=>8763, +30821=>8764, +30812=>8765, +30829=>8766, +30833=>8767, +30826=>8768, +30830=>8769, +30832=>8770, +30825=>8771, +30824=>8772, +30814=>8773, +30818=>8774, +31092=>8775, +31091=>8776, +31090=>8777, +31088=>8778, +31234=>8779, +31242=>8780, +31235=>8781, +31244=>8782, +31236=>8783, +31385=>8784, +31462=>8785, +31460=>8786, +31562=>8787, +31559=>8788, +31556=>8789, +31560=>8790, +31564=>8791, +31566=>8792, +31552=>8793, +31576=>8794, +31557=>8795, +31906=>8796, +31902=>8797, +31912=>8798, +31905=>8799, +32088=>8800, +32111=>8801, +32099=>8802, +32083=>8803, +32086=>8804, +32103=>8805, +32106=>8806, +32079=>8807, +32109=>8808, +32092=>8809, +32107=>8810, +32082=>8811, +32084=>8812, +32105=>8813, +32081=>8814, +32095=>8815, +32078=>8816, +32574=>8817, +32575=>8818, +32613=>8819, +32614=>8820, +32674=>8821, +32672=>8822, +32673=>8823, +32727=>8824, +32849=>8825, +32847=>8826, +32848=>8827, +33022=>8828, +32980=>8829, +33091=>8830, +33098=>8831, +33106=>8832, +33103=>8833, +33095=>8834, +33085=>8835, +33101=>8836, +33082=>8837, +33254=>8838, +33262=>8839, +33271=>8840, +33272=>8841, +33273=>8842, +33284=>8843, +33340=>8844, +33341=>8845, +33343=>8846, +33397=>8847, +33595=>8848, +33743=>8849, +60382=>8849, +33785=>8850, +33827=>8851, +33728=>8852, +33768=>8853, +33810=>8854, +33767=>8855, +33764=>8856, +33788=>8857, +33782=>8858, +33808=>8859, +33734=>8860, +33736=>8861, +33771=>8862, +33763=>8863, +33727=>8864, +33793=>8865, +33757=>8866, +33765=>8867, +33752=>8868, +33791=>8869, +33761=>8870, +33739=>8871, +33742=>8872, +33750=>8873, +33781=>8874, +33737=>8875, +33801=>8876, +33807=>8877, +58332=>8877, +33758=>8878, +33809=>8879, +33798=>8880, +33730=>8881, +33779=>8882, +33749=>8883, +33786=>8884, +33735=>8885, +33745=>8886, +33770=>8887, +33811=>8888, +33690=>8889, +33731=>8890, +33772=>8891, +33774=>8892, +33732=>8893, +33787=>8894, +33751=>8895, +33762=>8896, +33819=>8897, +33755=>8898, +33790=>8899, +34520=>8900, +34530=>8901, +34534=>8902, +34515=>8903, +34531=>8904, +34522=>8905, +34538=>8906, +34525=>8907, +34539=>8908, +34524=>8909, +34540=>8910, +34537=>8911, +34519=>8912, +34536=>8913, +34513=>8914, +34888=>8915, +34902=>8916, +34901=>8917, +35002=>8918, +35031=>8919, +35001=>8920, +35000=>8921, +35008=>8922, +35006=>8923, +34998=>8924, +35004=>8925, +34999=>8926, +35005=>8927, +34994=>8928, +35073=>8929, +35017=>8930, +35221=>8931, +35224=>8932, +35223=>8933, +35293=>8934, +35290=>8935, +35291=>8936, +35406=>8937, +35405=>8938, +35385=>8939, +35417=>8940, +35392=>8941, +35415=>8942, +35416=>8943, +35396=>8944, +35397=>8945, +35410=>8946, +35400=>8947, +35409=>8948, +35402=>8949, +35404=>8950, +35407=>8951, +35935=>8952, +35969=>8953, +35968=>8954, +36026=>8955, +36030=>8956, +36016=>8957, +36025=>8958, +36021=>8959, +36228=>8960, +36224=>8961, +36233=>8962, +36312=>8963, +36307=>8964, +36301=>8965, +36295=>8966, +36310=>8967, +36316=>8968, +36303=>8969, +36309=>8970, +36313=>8971, +36296=>8972, +36311=>8973, +36293=>8974, +36591=>8975, +36599=>8976, +36602=>8977, +36601=>8978, +36582=>8979, +36590=>8980, +36581=>8981, +36597=>8982, +36583=>8983, +36584=>8984, +36598=>8985, +36587=>8986, +36593=>8987, +36588=>8988, +36596=>8989, +36585=>8990, +36909=>8991, +36916=>8992, +36911=>8993, +37126=>8994, +37164=>8995, +37124=>8996, +60367=>8996, +37119=>8997, +37116=>8998, +37128=>8999, +37113=>9000, +37115=>9001, +37121=>9002, +37120=>9003, +37127=>9004, +37125=>9005, +37123=>9006, +37217=>9007, +37220=>9008, +37215=>9009, +37218=>9010, +37216=>9011, +37377=>9012, +37386=>9013, +37413=>9014, +37379=>9015, +37402=>9016, +37414=>9017, +37391=>9018, +37388=>9019, +37376=>9020, +37394=>9021, +37375=>9022, +37373=>9023, +37382=>9024, +37380=>9025, +37415=>9026, +37378=>9027, +37404=>9028, +37412=>9029, +37401=>9030, +37399=>9031, +37381=>9032, +37398=>9033, +38267=>9034, +38285=>9035, +38284=>9036, +38288=>9037, +38535=>9038, +38526=>9039, +38536=>9040, +38537=>9041, +38531=>9042, +38528=>9043, +38594=>9044, +38600=>9045, +38595=>9046, +38641=>9047, +38640=>9048, +38764=>9049, +38768=>9050, +38766=>9051, +38919=>9052, +39081=>9053, +39147=>9054, +40166=>9055, +12235=>9056, +40697=>9056, +20099=>9057, +20100=>9058, +20150=>9059, +20669=>9060, +20671=>9061, +20678=>9062, +20654=>9063, +20676=>9064, +20682=>9065, +20660=>9066, +20680=>9067, +20674=>9068, +20656=>9069, +20673=>9070, +20666=>9071, +20657=>9072, +20683=>9073, +20681=>9074, +20662=>9075, +20664=>9076, +20951=>9077, +21114=>9078, +21112=>9079, +21115=>9080, +21116=>9081, +21955=>9082, +21979=>9083, +21964=>9084, +21968=>9085, +21963=>9086, +21962=>9087, +21981=>9088, +21952=>9089, +64013=>9089, +21972=>9090, +21956=>9091, +21993=>9092, +21951=>9093, +21970=>9094, +21901=>9095, +21967=>9096, +21973=>9097, +21986=>9098, +21974=>9099, +21960=>9100, +22002=>9101, +21965=>9102, +21977=>9103, +21954=>9104, +22292=>9105, +22611=>9106, +22632=>9107, +22628=>9108, +22607=>9109, +22605=>9110, +22601=>9111, +22639=>9112, +22613=>9113, +22606=>9114, +22621=>9115, +22617=>9116, +22629=>9117, +22619=>9118, +22589=>9119, +22627=>9120, +22641=>9121, +22780=>9122, +23239=>9123, +23236=>9124, +23243=>9125, +23226=>9126, +23224=>9127, +23217=>9128, +23221=>9129, +23216=>9130, +23231=>9131, +23240=>9132, +23227=>9133, +23238=>9134, +23223=>9135, +23232=>9136, +23242=>9137, +23220=>9138, +23222=>9139, +23245=>9140, +23225=>9141, +23184=>9142, +23510=>9143, +23512=>9144, +23513=>9145, +23583=>9146, +23603=>9147, +23921=>9148, +23907=>9149, +23882=>9150, +23909=>9151, +23922=>9152, +23916=>9153, +23902=>9154, +23912=>9155, +23911=>9156, +23906=>9157, +24048=>9158, +24143=>9159, +24142=>9160, +24138=>9161, +24141=>9162, +24139=>9163, +24261=>9164, +24268=>9165, +24262=>9166, +24267=>9167, +24263=>9168, +24384=>9169, +24495=>9170, +24493=>9171, +24823=>9172, +24905=>9173, +24906=>9174, +24875=>9175, +24901=>9176, +24886=>9177, +24882=>9178, +24878=>9179, +24902=>9180, +24879=>9181, +24911=>9182, +24873=>9183, +24896=>9184, +25120=>9185, +37224=>9186, +25123=>9187, +25125=>9188, +25124=>9189, +25541=>9190, +25585=>9191, +25579=>9192, +25616=>9193, +25618=>9194, +25609=>9195, +25632=>9196, +25636=>9197, +25651=>9198, +25667=>9199, +25631=>9200, +25621=>9201, +25624=>9202, +25657=>9203, +25655=>9204, +25634=>9205, +25635=>9206, +25612=>9207, +25638=>9208, +25648=>9209, +25640=>9210, +25665=>9211, +25653=>9212, +25647=>9213, +25610=>9214, +25626=>9215, +25664=>9216, +25637=>9217, +25639=>9218, +25611=>9219, +25575=>9220, +25627=>9221, +25646=>9222, +25633=>9223, +25614=>9224, +25967=>9225, +26002=>9226, +26067=>9227, +26246=>9228, +26252=>9229, +26261=>9230, +26256=>9231, +26251=>9232, +26250=>9233, +26265=>9234, +26260=>9235, +26232=>9236, +26400=>9237, +26982=>9238, +26975=>9239, +26936=>9240, +26958=>9241, +26978=>9242, +26993=>9243, +26943=>9244, +26949=>9245, +26986=>9246, +26937=>9247, +26946=>9248, +26967=>9249, +26969=>9250, +27002=>9251, +26952=>9252, +26953=>9253, +26933=>9254, +26988=>9255, +26931=>9256, +26941=>9257, +26981=>9258, +26864=>9259, +27000=>9260, +26932=>9261, +26985=>9262, +26944=>9263, +26991=>9264, +26948=>9265, +26998=>9266, +26968=>9267, +26945=>9268, +26996=>9269, +26956=>9270, +26939=>9271, +26955=>9272, +26935=>9273, +26972=>9274, +26959=>9275, +26961=>9276, +26930=>9277, +26962=>9278, +26927=>9279, +27003=>9280, +26940=>9281, +27462=>9282, +27461=>9283, +27459=>9284, +27458=>9285, +27464=>9286, +27457=>9287, +27547=>9288, +27643=>9289, +27644=>9290, +27641=>9291, +27639=>9292, +27640=>9293, +28315=>9294, +28374=>9295, +28360=>9296, +28303=>9297, +28352=>9298, +28319=>9299, +28307=>9300, +28308=>9301, +28320=>9302, +28337=>9303, +28345=>9304, +28358=>9305, +28370=>9306, +28349=>9307, +28353=>9308, +28318=>9309, +28361=>9310, +28343=>9311, +28336=>9312, +28365=>9313, +28326=>9314, +28367=>9315, +28338=>9316, +28350=>9317, +28355=>9318, +28380=>9319, +28376=>9320, +28313=>9321, +28306=>9322, +28302=>9323, +28301=>9324, +28324=>9325, +28321=>9326, +28351=>9327, +28339=>9328, +28368=>9329, +28362=>9330, +28311=>9331, +28334=>9332, +28323=>9333, +28999=>9334, +29012=>9335, +29010=>9336, +29027=>9337, +29024=>9338, +28993=>9339, +29021=>9340, +29026=>9341, +61080=>9341, +29042=>9342, +29048=>9343, +29034=>9344, +29025=>9345, +28994=>9346, +29016=>9347, +28995=>9348, +29003=>9349, +29040=>9350, +29023=>9351, +29008=>9352, +29011=>9353, +28996=>9354, +29005=>9355, +29018=>9356, +29263=>9357, +29325=>9358, +29324=>9359, +29329=>9360, +29328=>9361, +29326=>9362, +29500=>9363, +29506=>9364, +29499=>9365, +29498=>9366, +29504=>9367, +29514=>9368, +29513=>9369, +29764=>9370, +29770=>9371, +29771=>9372, +29778=>9373, +29777=>9374, +29783=>9375, +29760=>9376, +29775=>9377, +29776=>9378, +29774=>9379, +29762=>9380, +29766=>9381, +29773=>9382, +29780=>9383, +29921=>9384, +29951=>9385, +29950=>9386, +29949=>9387, +29981=>9388, +30073=>9389, +30071=>9390, +27011=>9391, +30191=>9392, +30223=>9393, +30211=>9394, +30199=>9395, +30206=>9396, +30204=>9397, +30201=>9398, +60782=>9398, +30200=>9399, +30224=>9400, +30203=>9401, +30198=>9402, +30189=>9403, +30197=>9404, +30205=>9405, +30361=>9406, +30389=>9407, +30429=>9408, +30549=>9409, +30559=>9410, +30560=>9411, +30546=>9412, +30550=>9413, +30554=>9414, +30569=>9415, +30567=>9416, +30548=>9417, +30553=>9418, +30573=>9419, +30688=>9420, +30855=>9421, +30874=>9422, +30868=>9423, +30863=>9424, +30852=>9425, +30869=>9426, +30853=>9427, +30854=>9428, +30881=>9429, +30851=>9430, +30841=>9431, +30873=>9432, +30848=>9433, +30870=>9434, +30843=>9435, +31100=>9436, +31106=>9437, +31101=>9438, +31097=>9439, +31249=>9440, +31256=>9441, +31257=>9442, +31250=>9443, +31255=>9444, +31253=>9445, +31266=>9446, +31251=>9447, +31259=>9448, +31248=>9449, +31395=>9450, +31394=>9451, +31390=>9452, +31467=>9453, +31590=>9454, +31588=>9455, +31597=>9456, +31604=>9457, +31593=>9458, +31602=>9459, +31589=>9460, +31603=>9461, +31601=>9462, +31600=>9463, +31585=>9464, +31608=>9465, +31606=>9466, +31587=>9467, +31922=>9468, +31924=>9469, +31919=>9470, +32136=>9471, +32134=>9472, +32128=>9473, +32141=>9474, +32127=>9475, +32133=>9476, +32122=>9477, +32142=>9478, +32123=>9479, +32131=>9480, +32124=>9481, +32140=>9482, +32148=>9483, +32132=>9484, +32125=>9485, +32146=>9486, +32621=>9487, +32619=>9488, +32615=>9489, +32616=>9490, +32620=>9491, +32678=>9492, +32677=>9493, +32679=>9494, +32731=>9495, +32732=>9496, +32801=>9497, +33124=>9498, +33120=>9499, +33143=>9500, +33116=>9501, +33129=>9502, +33115=>9503, +33122=>9504, +33138=>9505, +26401=>9506, +33118=>9507, +33142=>9508, +33127=>9509, +33135=>9510, +33092=>9511, +33121=>9512, +33309=>9513, +33353=>9514, +33348=>9515, +33344=>9516, +33346=>9517, +33349=>9518, +34033=>9519, +33855=>9520, +33878=>9521, +33910=>9522, +33913=>9523, +33935=>9524, +33933=>9525, +33893=>9526, +33873=>9527, +33856=>9528, +33926=>9529, +33895=>9530, +33840=>9531, +33869=>9532, +33917=>9533, +33882=>9534, +33881=>9535, +33908=>9536, +33907=>9537, +33885=>9538, +34055=>9539, +33886=>9540, +33847=>9541, +33850=>9542, +33844=>9543, +33914=>9544, +33859=>9545, +33912=>9546, +33842=>9547, +33861=>9548, +33833=>9549, +33753=>9550, +33867=>9551, +33839=>9552, +33858=>9553, +33837=>9554, +33887=>9555, +33904=>9556, +33849=>9557, +33870=>9558, +33868=>9559, +33874=>9560, +33903=>9561, +33989=>9562, +33934=>9563, +33851=>9564, +33863=>9565, +33846=>9566, +33843=>9567, +33896=>9568, +33918=>9569, +33860=>9570, +33835=>9571, +33888=>9572, +33876=>9573, +33902=>9574, +33872=>9575, +34571=>9576, +34564=>9577, +34551=>9578, +34572=>9579, +34554=>9580, +34518=>9581, +34549=>9582, +34637=>9583, +34552=>9584, +34574=>9585, +34569=>9586, +34561=>9587, +34550=>9588, +34573=>9589, +34565=>9590, +35030=>9591, +35019=>9592, +35021=>9593, +35022=>9594, +35038=>9595, +35035=>9596, +35034=>9597, +35020=>9598, +35024=>9599, +35205=>9600, +35227=>9601, +35295=>9602, +35301=>9603, +35300=>9604, +35297=>9605, +35296=>9606, +35298=>9607, +35292=>9608, +35302=>9609, +35446=>9610, +35462=>9611, +35455=>9612, +35425=>9613, +35391=>9614, +35447=>9615, +35458=>9616, +35460=>9617, +35445=>9618, +35459=>9619, +35457=>9620, +35444=>9621, +35450=>9622, +35900=>9623, +35915=>9624, +35914=>9625, +35941=>9626, +35940=>9627, +35942=>9628, +35974=>9629, +35972=>9630, +35973=>9631, +36044=>9632, +36200=>9633, +36201=>9634, +36241=>9635, +36236=>9636, +36238=>9637, +36239=>9638, +36237=>9639, +36243=>9640, +36244=>9641, +36240=>9642, +36242=>9643, +36336=>9644, +36320=>9645, +36332=>9646, +36337=>9647, +36334=>9648, +36304=>9649, +36329=>9650, +36323=>9651, +36322=>9652, +36327=>9653, +36338=>9654, +36331=>9655, +36340=>9656, +36614=>9657, +36607=>9658, +36609=>9659, +36608=>9660, +36613=>9661, +36615=>9662, +36616=>9663, +36610=>9664, +36619=>9665, +60507=>9665, +36946=>9666, +36927=>9667, +36932=>9668, +36937=>9669, +36925=>9670, +37136=>9671, +37133=>9672, +37135=>9673, +37137=>9674, +37142=>9675, +37140=>9676, +37131=>9677, +37134=>9678, +37230=>9679, +37231=>9680, +37448=>9681, +37458=>9682, +37424=>9683, +37434=>9684, +37478=>9685, +37427=>9686, +37477=>9687, +37470=>9688, +37507=>9689, +37422=>9690, +37450=>9691, +37446=>9692, +37485=>9693, +37484=>9694, +37455=>9695, +37472=>9696, +37479=>9697, +37487=>9698, +37430=>9699, +37473=>9700, +37488=>9701, +37425=>9702, +37460=>9703, +37475=>9704, +37456=>9705, +37490=>9706, +37454=>9707, +37459=>9708, +37452=>9709, +37462=>9710, +37426=>9711, +38303=>9712, +38300=>9713, +38302=>9714, +38299=>9715, +38546=>9716, +38547=>9717, +38545=>9718, +38551=>9719, +38606=>9720, +38650=>9721, +38653=>9722, +38648=>9723, +38645=>9724, +38771=>9725, +38775=>9726, +38776=>9727, +38770=>9728, +38927=>9729, +38925=>9730, +38926=>9731, +39084=>9732, +39158=>9733, +39161=>9734, +39343=>9735, +39346=>9736, +39344=>9737, +39349=>9738, +39597=>9739, +39595=>9740, +39771=>9741, +40170=>9742, +40173=>9743, +40167=>9744, +40576=>9745, +12236=>9746, +40701=>9746, +20710=>9747, +20692=>9748, +20695=>9749, +20712=>9750, +20723=>9751, +20699=>9752, +20714=>9753, +20701=>9754, +20708=>9755, +20691=>9756, +20716=>9757, +20720=>9758, +20719=>9759, +20707=>9760, +20704=>9761, +20952=>9762, +21120=>9763, +21121=>9764, +21225=>9765, +21227=>9766, +21296=>9767, +21420=>9768, +22055=>9769, +22037=>9770, +22028=>9771, +22034=>9772, +22012=>9773, +22031=>9774, +22044=>9775, +22017=>9776, +22035=>9777, +22018=>9778, +22010=>9779, +22045=>9780, +22020=>9781, +22015=>9782, +22009=>9783, +22665=>9784, +22652=>9785, +22672=>9786, +22680=>9787, +22662=>9788, +22657=>9789, +22655=>9790, +22644=>9791, +22667=>9792, +22650=>9793, +22663=>9794, +22673=>9795, +22670=>9796, +22646=>9797, +22658=>9798, +22664=>9799, +22651=>9800, +22676=>9801, +22671=>9802, +22782=>9803, +22891=>9804, +23260=>9805, +23278=>9806, +23269=>9807, +23253=>9808, +23274=>9809, +23258=>9810, +23277=>9811, +23275=>9812, +23283=>9813, +23266=>9814, +23264=>9815, +23259=>9816, +23276=>9817, +23262=>9818, +23261=>9819, +23257=>9820, +23272=>9821, +23263=>9822, +23415=>9823, +23520=>9824, +23523=>9825, +23651=>9826, +23938=>9827, +23936=>9828, +23933=>9829, +23942=>9830, +23930=>9831, +23937=>9832, +23927=>9833, +23946=>9834, +23945=>9835, +23944=>9836, +23934=>9837, +23932=>9838, +23949=>9839, +23929=>9840, +23935=>9841, +24152=>9842, +24153=>9843, +24147=>9844, +24280=>9845, +24273=>9846, +24279=>9847, +24270=>9848, +24284=>9849, +24277=>9850, +24281=>9851, +24274=>9852, +24276=>9853, +24388=>9854, +24387=>9855, +24431=>9856, +24502=>9857, +24876=>9858, +24872=>9859, +24897=>9860, +24926=>9861, +24945=>9862, +24947=>9863, +24914=>9864, +24915=>9865, +24946=>9866, +24940=>9867, +24960=>9868, +24948=>9869, +24916=>9870, +24954=>9871, +24923=>9872, +24933=>9873, +24891=>9874, +24938=>9875, +24929=>9876, +24918=>9877, +25129=>9878, +25127=>9879, +25131=>9880, +25643=>9881, +25677=>9882, +25691=>9883, +25693=>9884, +25716=>9885, +25718=>9886, +25714=>9887, +25715=>9888, +25725=>9889, +25717=>9890, +25702=>9891, +25766=>9892, +25678=>9893, +25730=>9894, +25694=>9895, +25692=>9896, +25675=>9897, +25683=>9898, +25696=>9899, +25680=>9900, +25727=>9901, +25663=>9902, +25708=>9903, +25707=>9904, +25689=>9905, +25701=>9906, +25719=>9907, +25971=>9908, +26016=>9909, +26273=>9910, +26272=>9911, +26271=>9912, +26373=>9913, +26372=>9914, +26402=>9915, +27057=>9916, +27062=>9917, +27081=>9918, +27040=>9919, +27086=>9920, +27030=>9921, +27056=>9922, +27052=>9923, +27068=>9924, +27025=>9925, +27033=>9926, +27022=>9927, +27047=>9928, +27021=>9929, +27049=>9930, +27070=>9931, +27055=>9932, +27071=>9933, +27076=>9934, +27069=>9935, +27044=>9936, +27092=>9937, +27065=>9938, +27082=>9939, +27034=>9940, +27087=>9941, +27059=>9942, +27027=>9943, +27050=>9944, +27041=>9945, +27038=>9946, +27097=>9947, +27031=>9948, +27024=>9949, +27074=>9950, +27061=>9951, +27045=>9952, +27078=>9953, +27466=>9954, +27469=>9955, +27467=>9956, +27550=>9957, +27551=>9958, +27552=>9959, +27587=>9960, +27588=>9961, +27646=>9962, +28366=>9963, +28405=>9964, +28401=>9965, +28419=>9966, +28453=>9967, +28408=>9968, +28471=>9969, +28411=>9970, +28462=>9971, +28425=>9972, +28494=>9973, +28441=>9974, +28442=>9975, +28455=>9976, +28440=>9977, +28475=>9978, +28434=>9979, +28397=>9980, +28426=>9981, +28470=>9982, +28531=>9983, +28409=>9984, +28398=>9985, +28461=>9986, +28480=>9987, +28464=>9988, +28476=>9989, +28469=>9990, +28395=>9991, +28423=>9992, +28430=>9993, +28483=>9994, +28421=>9995, +28413=>9996, +28406=>9997, +28473=>9998, +28444=>9999, +28412=>10000, +28474=>10001, +28447=>10002, +28429=>10003, +28446=>10004, +28424=>10005, +28449=>10006, +29063=>10007, +29072=>10008, +29065=>10009, +29056=>10010, +29061=>10011, +29058=>10012, +29071=>10013, +29051=>10014, +29062=>10015, +29057=>10016, +29079=>10017, +29252=>10018, +29267=>10019, +29335=>10020, +29333=>10021, +29331=>10022, +29507=>10023, +29517=>10024, +29521=>10025, +29516=>10026, +29794=>10027, +29811=>10028, +29809=>10029, +29813=>10030, +29810=>10031, +29799=>10032, +29806=>10033, +29952=>10034, +29954=>10035, +29955=>10036, +30077=>10037, +30096=>10038, +30230=>10039, +30216=>10040, +30220=>10041, +30229=>10042, +30225=>10043, +30218=>10044, +30228=>10045, +30392=>10046, +30593=>10047, +30588=>10048, +30597=>10049, +30594=>10050, +30574=>10051, +30592=>10052, +30575=>10053, +30590=>10054, +30595=>10055, +30898=>10056, +30890=>10057, +30900=>10058, +30893=>10059, +30888=>10060, +30846=>10061, +30891=>10062, +30878=>10063, +30885=>10064, +30880=>10065, +30892=>10066, +30882=>10067, +30884=>10068, +31128=>10069, +31114=>10070, +31115=>10071, +31126=>10072, +31125=>10073, +31124=>10074, +31123=>10075, +31127=>10076, +31112=>10077, +31122=>10078, +31120=>10079, +31275=>10080, +31306=>10081, +31280=>10082, +31279=>10083, +31272=>10084, +31270=>10085, +31400=>10086, +31403=>10087, +31404=>10088, +31470=>10089, +31624=>10090, +31644=>10091, +31626=>10092, +31633=>10093, +31632=>10094, +31638=>10095, +31629=>10096, +31628=>10097, +31643=>10098, +31630=>10099, +31621=>10100, +31640=>10101, +21124=>10102, +31641=>10103, +31652=>10104, +31618=>10105, +31931=>10106, +31935=>10107, +31932=>10108, +31930=>10109, +32167=>10110, +32183=>10111, +32194=>10112, +32163=>10113, +32170=>10114, +32193=>10115, +32192=>10116, +32197=>10117, +32157=>10118, +32206=>10119, +32196=>10120, +32198=>10121, +32203=>10122, +32204=>10123, +32175=>10124, +32185=>10125, +32150=>10126, +32188=>10127, +32159=>10128, +32166=>10129, +32174=>10130, +32169=>10131, +32161=>10132, +32201=>10133, +32627=>10134, +32738=>10135, +32739=>10136, +32741=>10137, +32734=>10138, +32804=>10139, +32861=>10140, +32860=>10141, +33161=>10142, +33158=>10143, +33155=>10144, +33159=>10145, +33165=>10146, +33164=>10147, +33163=>10148, +33301=>10149, +33943=>10150, +33956=>10151, +33953=>10152, +33951=>10153, +33978=>10154, +33998=>10155, +33986=>10156, +33964=>10157, +33966=>10158, +33963=>10159, +33977=>10160, +33972=>10161, +33985=>10162, +33997=>10163, +33962=>10164, +33946=>10165, +33969=>10166, +34000=>10167, +33949=>10168, +33959=>10169, +33979=>10170, +33954=>10171, +33940=>10172, +33991=>10173, +33996=>10174, +33947=>10175, +33961=>10176, +33967=>10177, +33960=>10178, +58327=>10178, +34006=>10179, +33944=>10180, +33974=>10181, +33999=>10182, +33952=>10183, +34007=>10184, +34004=>10185, +34002=>10186, +34011=>10187, +33968=>10188, +33937=>10189, +34401=>10190, +34611=>10191, +34595=>10192, +34600=>10193, +34667=>10194, +34624=>10195, +34606=>10196, +34590=>10197, +34593=>10198, +34585=>10199, +34587=>10200, +34627=>10201, +34604=>10202, +34625=>10203, +34622=>10204, +34630=>10205, +34592=>10206, +34610=>10207, +34602=>10208, +34605=>10209, +34620=>10210, +34578=>10211, +34618=>10212, +34609=>10213, +34613=>10214, +34626=>10215, +34598=>10216, +34599=>10217, +34616=>10218, +34596=>10219, +34586=>10220, +34608=>10221, +34577=>10222, +35063=>10223, +35047=>10224, +35057=>10225, +35058=>10226, +35066=>10227, +35070=>10228, +35054=>10229, +35068=>10230, +35062=>10231, +35067=>10232, +35056=>10233, +35052=>10234, +35051=>10235, +35229=>10236, +35233=>10237, +35231=>10238, +35230=>10239, +35305=>10240, +35307=>10241, +35304=>10242, +35499=>10243, +35481=>10244, +35467=>10245, +35474=>10246, +35471=>10247, +35478=>10248, +35901=>10249, +35944=>10250, +35945=>10251, +36053=>10252, +36047=>10253, +36055=>10254, +36246=>10255, +36361=>10256, +36354=>10257, +36351=>10258, +36365=>10259, +36349=>10260, +36362=>10261, +36355=>10262, +36359=>10263, +36358=>10264, +36357=>10265, +36350=>10266, +36352=>10267, +36356=>10268, +36624=>10269, +36625=>10270, +36622=>10271, +36621=>10272, +37155=>10273, +37148=>10274, +37152=>10275, +37154=>10276, +37151=>10277, +37149=>10278, +37146=>10279, +37156=>10280, +37153=>10281, +37147=>10282, +37242=>10283, +37234=>10284, +37241=>10285, +37235=>10286, +37541=>10287, +37540=>10288, +37494=>10289, +37531=>10290, +37498=>10291, +37536=>10292, +37524=>10293, +37546=>10294, +37517=>10295, +37542=>10296, +37530=>10297, +37547=>10298, +37497=>10299, +37527=>10300, +37503=>10301, +37539=>10302, +37614=>10303, +37518=>10304, +37506=>10305, +37525=>10306, +37538=>10307, +37501=>10308, +37512=>10309, +37537=>10310, +37514=>10311, +37510=>10312, +37516=>10313, +37529=>10314, +37543=>10315, +37502=>10316, +37511=>10317, +37545=>10318, +37533=>10319, +37515=>10320, +37421=>10321, +38558=>10322, +38561=>10323, +38655=>10324, +38744=>10325, +38781=>10326, +38778=>10327, +38782=>10328, +38787=>10329, +38784=>10330, +38786=>10331, +38779=>10332, +38788=>10333, +38785=>10334, +38783=>10335, +38862=>10336, +38861=>10337, +38934=>10338, +39085=>10339, +39086=>10340, +39170=>10341, +39168=>10342, +39175=>10343, +39325=>10344, +39324=>10345, +39363=>10346, +39353=>10347, +39355=>10348, +39354=>10349, +39362=>10350, +39357=>10351, +39367=>10352, +39601=>10353, +39651=>10354, +39655=>10355, +39742=>10356, +39743=>10357, +39776=>10358, +39777=>10359, +39775=>10360, +40177=>10361, +40178=>10362, +40181=>10363, +40615=>10364, +20735=>10365, +20739=>10366, +20784=>10367, +20728=>10368, +20742=>10369, +20743=>10370, +20726=>10371, +20734=>10372, +20747=>10373, +20748=>10374, +20733=>10375, +20746=>10376, +21131=>10377, +21132=>10378, +21233=>10379, +21231=>10380, +22088=>10381, +22082=>10382, +22092=>10383, +22069=>10384, +22081=>10385, +22090=>10386, +22089=>10387, +22086=>10388, +22104=>10389, +22106=>10390, +22080=>10391, +22067=>10392, +22077=>10393, +22060=>10394, +22078=>10395, +22072=>10396, +22058=>10397, +22074=>10398, +22298=>10399, +22699=>10400, +22685=>10401, +22705=>10402, +22688=>10403, +22691=>10404, +22703=>10405, +22700=>10406, +22693=>10407, +22689=>10408, +22783=>10409, +23295=>10410, +23284=>10411, +23293=>10412, +23287=>10413, +23286=>10414, +23299=>10415, +23288=>10416, +23298=>10417, +23289=>10418, +23297=>10419, +23303=>10420, +23301=>10421, +23311=>10422, +23655=>10423, +23961=>10424, +23959=>10425, +23967=>10426, +23954=>10427, +23970=>10428, +23955=>10429, +23957=>10430, +23968=>10431, +23964=>10432, +23969=>10433, +23962=>10434, +23966=>10435, +24169=>10436, +24157=>10437, +24160=>10438, +24156=>10439, +32243=>10440, +24283=>10441, +24286=>10442, +24289=>10443, +24393=>10444, +24498=>10445, +24971=>10446, +24963=>10447, +24953=>10448, +25009=>10449, +25008=>10450, +24994=>10451, +24969=>10452, +24987=>10453, +24979=>10454, +25007=>10455, +25005=>10456, +24991=>10457, +24978=>10458, +25002=>10459, +24993=>10460, +24973=>10461, +24934=>10462, +25011=>10463, +25133=>10464, +25710=>10465, +25712=>10466, +25750=>10467, +25760=>10468, +25733=>10469, +25751=>10470, +25756=>10471, +25743=>10472, +25739=>10473, +25738=>10474, +25740=>10475, +25763=>10476, +25759=>10477, +25704=>10478, +25777=>10479, +25752=>10480, +25974=>10481, +25978=>10482, +25977=>10483, +25979=>10484, +26034=>10485, +26035=>10486, +26293=>10487, +26288=>10488, +26281=>10489, +26290=>10490, +26295=>10491, +26282=>10492, +26287=>10493, +27136=>10494, +27142=>10495, +27159=>10496, +27109=>10497, +27128=>10498, +27157=>10499, +27121=>10500, +27108=>10501, +27168=>10502, +27135=>10503, +27116=>10504, +27106=>10505, +27163=>10506, +27165=>10507, +27134=>10508, +27175=>10509, +27122=>10510, +27118=>10511, +27156=>10512, +27127=>10513, +27111=>10514, +27200=>10515, +27144=>10516, +27110=>10517, +27131=>10518, +27149=>10519, +27132=>10520, +27115=>10521, +27145=>10522, +27140=>10523, +27160=>10524, +27173=>10525, +27151=>10526, +27126=>10527, +27174=>10528, +27143=>10529, +27124=>10530, +27158=>10531, +27473=>10532, +27557=>10533, +27555=>10534, +27554=>10535, +27558=>10536, +27649=>10537, +27648=>10538, +27647=>10539, +27650=>10540, +28481=>10541, +28454=>10542, +28542=>10543, +28551=>10544, +28614=>10545, +28562=>10546, +28557=>10547, +28553=>10548, +28556=>10549, +28514=>10550, +28495=>10551, +28549=>10552, +28506=>10553, +28566=>10554, +28534=>10555, +28524=>10556, +28546=>10557, +28501=>10558, +28530=>10559, +28498=>10560, +28496=>10561, +28503=>10562, +28564=>10563, +28563=>10564, +28509=>10565, +28416=>10566, +28513=>10567, +28523=>10568, +28541=>10569, +28519=>10570, +28560=>10571, +28499=>10572, +28555=>10573, +28521=>10574, +28543=>10575, +28565=>10576, +28515=>10577, +28535=>10578, +28522=>10579, +28539=>10580, +29106=>10581, +29103=>10582, +29083=>10583, +29104=>10584, +29088=>10585, +29082=>10586, +29097=>10587, +29109=>10588, +29085=>10589, +29093=>10590, +29086=>10591, +29092=>10592, +29089=>10593, +29098=>10594, +29084=>10595, +29095=>10596, +29107=>10597, +29336=>10598, +29338=>10599, +29528=>10600, +29522=>10601, +29534=>10602, +29535=>10603, +29536=>10604, +29533=>10605, +29531=>10606, +29537=>10607, +29530=>10608, +29529=>10609, +29538=>10610, +29831=>10611, +29833=>10612, +29834=>10613, +29830=>10614, +29825=>10615, +29821=>10616, +29829=>10617, +29832=>10618, +29820=>10619, +29817=>10620, +58868=>10620, +29960=>10621, +29959=>10622, +30078=>10623, +30245=>10624, +30238=>10625, +30233=>10626, +30237=>10627, +30236=>10628, +30243=>10629, +30234=>10630, +30248=>10631, +30235=>10632, +30364=>10633, +30365=>10634, +30366=>10635, +30363=>10636, +30605=>10637, +30607=>10638, +30601=>10639, +30600=>10640, +30925=>10641, +30907=>10642, +30927=>10643, +30924=>10644, +30929=>10645, +30926=>10646, +30932=>10647, +30920=>10648, +30915=>10649, +30916=>10650, +30921=>10651, +31130=>10652, +31137=>10653, +31136=>10654, +31132=>10655, +31138=>10656, +31131=>10657, +59175=>10657, +27510=>10658, +31289=>10659, +31410=>10660, +31412=>10661, +31411=>10662, +31671=>10663, +31691=>10664, +31678=>10665, +31660=>10666, +31694=>10667, +31663=>10668, +31673=>10669, +31690=>10670, +31669=>10671, +31941=>10672, +31944=>10673, +31948=>10674, +31947=>10675, +32247=>10676, +32219=>10677, +32234=>10678, +32231=>10679, +32215=>10680, +32225=>10681, +32259=>10682, +32250=>10683, +32230=>10684, +32246=>10685, +32241=>10686, +32240=>10687, +32238=>10688, +32223=>10689, +32630=>10690, +32684=>10691, +32688=>10692, +32685=>10693, +32749=>10694, +32747=>10695, +32746=>10696, +32748=>10697, +32742=>10698, +32744=>10699, +32868=>10700, +32871=>10701, +33187=>10702, +33183=>10703, +33182=>10704, +33173=>10705, +33186=>10706, +33177=>10707, +33175=>10708, +33302=>10709, +33359=>10710, +33363=>10711, +33362=>10712, +33360=>10713, +33358=>10714, +33361=>10715, +34084=>10716, +34107=>10717, +34063=>10718, +34048=>10719, +34089=>10720, +34062=>10721, +34057=>10722, +34061=>10723, +34079=>10724, +34058=>10725, +34087=>10726, +34076=>10727, +34043=>10728, +34091=>10729, +34042=>10730, +34056=>10731, +34060=>10732, +34036=>10733, +34090=>10734, +34034=>10735, +34069=>10736, +34039=>10737, +34027=>10738, +34035=>10739, +34044=>10740, +34066=>10741, +34026=>10742, +34025=>10743, +34070=>10744, +34046=>10745, +34088=>10746, +34077=>10747, +34094=>10748, +34050=>10749, +34045=>10750, +34078=>10751, +34038=>10752, +34097=>10753, +34086=>10754, +34023=>10755, +34024=>10756, +34032=>10757, +34031=>10758, +34041=>10759, +34072=>10760, +34080=>10761, +34096=>10762, +34059=>10763, +34073=>10764, +34095=>10765, +34402=>10766, +34646=>10767, +34659=>10768, +34660=>10769, +34679=>10770, +34785=>10771, +34675=>10772, +34648=>10773, +34644=>10774, +34651=>10775, +34642=>10776, +34657=>10777, +34650=>10778, +34641=>10779, +34654=>10780, +34669=>10781, +34666=>10782, +34640=>10783, +34638=>10784, +34655=>10785, +34653=>10786, +34671=>10787, +34668=>10788, +34682=>10789, +34670=>10790, +34652=>10791, +34661=>10792, +34639=>10793, +34683=>10794, +34677=>10795, +34658=>10796, +34663=>10797, +34665=>10798, +34906=>10799, +35077=>10800, +35084=>10801, +35092=>10802, +35083=>10803, +35095=>10804, +35096=>10805, +35097=>10806, +35078=>10807, +35094=>10808, +35089=>10809, +35086=>10810, +35081=>10811, +35234=>10812, +35236=>10813, +35235=>10814, +35309=>10815, +35312=>10816, +35308=>10817, +35535=>10818, +35526=>10819, +35512=>10820, +35539=>10821, +35537=>10822, +35540=>10823, +35541=>10824, +35515=>10825, +35543=>10826, +35518=>10827, +35520=>10828, +35525=>10829, +35544=>10830, +35523=>10831, +35514=>10832, +35517=>10833, +35545=>10834, +35902=>10835, +35917=>10836, +35983=>10837, +36069=>10838, +36063=>10839, +36057=>10840, +36072=>10841, +36058=>10842, +36061=>10843, +36071=>10844, +36256=>10845, +36252=>10846, +36257=>10847, +36251=>10848, +36384=>10849, +36387=>10850, +36389=>10851, +36388=>10852, +36398=>10853, +36373=>10854, +36379=>10855, +36374=>10856, +36369=>10857, +36377=>10858, +36390=>10859, +36391=>10860, +36372=>10861, +36370=>10862, +36376=>10863, +36371=>10864, +36380=>10865, +36375=>10866, +36378=>10867, +36652=>10868, +36644=>10869, +36632=>10870, +36634=>10871, +36640=>10872, +36643=>10873, +36630=>10874, +36631=>10875, +36979=>10876, +36976=>10877, +36975=>10878, +36967=>10879, +36971=>10880, +37167=>10881, +37163=>10882, +37161=>10883, +37162=>10884, +37170=>10885, +37158=>10886, +37166=>10887, +37253=>10888, +37254=>10889, +37258=>10890, +37249=>10891, +37250=>10892, +37252=>10893, +37248=>10894, +37584=>10895, +37571=>10896, +37572=>10897, +37568=>10898, +37593=>10899, +37558=>10900, +37583=>10901, +37617=>10902, +37599=>10903, +37592=>10904, +37609=>10905, +37591=>10906, +37597=>10907, +37580=>10908, +37615=>10909, +37570=>10910, +37608=>10911, +37578=>10912, +37576=>10913, +37582=>10914, +37606=>10915, +37581=>10916, +37589=>10917, +37577=>10918, +37600=>10919, +37598=>10920, +37607=>10921, +37585=>10922, +37587=>10923, +37557=>10924, +37601=>10925, +37669=>10926, +37574=>10927, +37556=>10928, +38268=>10929, +38316=>10930, +38315=>10931, +38318=>10932, +38320=>10933, +38564=>10934, +38562=>10935, +38611=>10936, +38661=>10937, +38664=>10938, +38658=>10939, +38746=>10940, +38794=>10941, +38798=>10942, +38792=>10943, +38864=>10944, +38863=>10945, +38942=>10946, +38941=>10947, +38950=>10948, +38953=>10949, +38952=>10950, +38944=>10951, +38939=>10952, +38951=>10953, +39090=>10954, +39176=>10955, +39162=>10956, +39185=>10957, +39188=>10958, +39190=>10959, +39191=>10960, +39189=>10961, +39388=>10962, +39373=>10963, +39375=>10964, +39379=>10965, +39380=>10966, +39374=>10967, +39369=>10968, +39382=>10969, +60270=>10969, +39384=>10970, +39371=>10971, +39383=>10972, +39372=>10973, +39603=>10974, +39660=>10975, +39659=>10976, +39667=>10977, +39666=>10978, +39665=>10979, +39750=>10980, +39747=>10981, +39783=>10982, +39796=>10983, +39793=>10984, +39782=>10985, +39798=>10986, +39797=>10987, +39792=>10988, +39784=>10989, +39780=>10990, +39788=>10991, +40188=>10992, +40186=>10993, +40189=>10994, +40191=>10995, +40183=>10996, +40199=>10997, +40192=>10998, +40185=>10999, +40187=>11000, +40200=>11001, +40197=>11002, +40196=>11003, +40579=>11004, +40659=>11005, +40719=>11006, +40720=>11007, +20764=>11008, +20755=>11009, +20759=>11010, +20762=>11011, +20753=>11012, +20958=>11013, +21300=>11014, +21473=>11015, +22128=>11016, +22112=>11017, +22126=>11018, +22131=>11019, +22118=>11020, +22115=>11021, +22125=>11022, +22130=>11023, +22110=>11024, +22135=>11025, +22300=>11026, +22299=>11027, +22728=>11028, +22717=>11029, +22729=>11030, +22719=>11031, +22714=>11032, +22722=>11033, +22716=>11034, +22726=>11035, +23319=>11036, +23321=>11037, +23323=>11038, +23329=>11039, +23316=>11040, +23315=>11041, +23312=>11042, +23318=>11043, +23336=>11044, +59539=>11044, +23322=>11045, +23328=>11046, +23326=>11047, +23535=>11048, +23980=>11049, +23985=>11050, +23977=>11051, +23975=>11052, +23989=>11053, +23984=>11054, +23982=>11055, +23978=>11056, +23976=>11057, +23986=>11058, +23981=>11059, +23983=>11060, +23988=>11061, +24167=>11062, +24168=>11063, +24166=>11064, +24175=>11065, +24297=>11066, +24295=>11067, +24294=>11068, +24296=>11069, +24293=>11070, +24395=>11071, +24508=>11072, +24507=>11073, +24989=>11074, +25000=>11075, +24982=>11076, +25029=>11077, +25012=>11078, +25030=>11079, +25025=>11080, +25036=>11081, +25018=>11082, +25023=>11083, +25016=>11084, +24972=>11085, +25815=>11086, +25814=>11087, +25808=>11088, +25807=>11089, +25801=>11090, +25789=>11091, +25737=>11092, +25795=>11093, +25819=>11094, +25843=>11095, +25817=>11096, +25907=>11097, +25983=>11098, +25980=>11099, +26018=>11100, +26312=>11101, +26302=>11102, +26304=>11103, +26314=>11104, +26315=>11105, +26319=>11106, +26301=>11107, +26299=>11108, +26298=>11109, +26316=>11110, +26403=>11111, +27188=>11112, +27238=>11113, +27209=>11114, +27239=>11115, +27186=>11116, +27240=>11117, +27198=>11118, +27229=>11119, +27245=>11120, +27254=>11121, +27227=>11122, +27217=>11123, +27176=>11124, +27226=>11125, +27195=>11126, +27199=>11127, +27201=>11128, +27242=>11129, +27236=>11130, +27216=>11131, +27215=>11132, +27220=>11133, +27247=>11134, +27241=>11135, +27232=>11136, +27196=>11137, +27230=>11138, +27222=>11139, +27221=>11140, +27213=>11141, +27214=>11142, +27206=>11143, +27477=>11144, +27476=>11145, +27478=>11146, +27559=>11147, +27562=>11148, +27563=>11149, +27592=>11150, +27591=>11151, +27652=>11152, +27651=>11153, +27654=>11154, +28589=>11155, +28619=>11156, +28579=>11157, +28615=>11158, +28604=>11159, +28622=>11160, +28616=>11161, +28510=>11162, +28612=>11163, +28605=>11164, +28574=>11165, +28618=>11166, +28584=>11167, +28676=>11168, +28581=>11169, +28590=>11170, +28602=>11171, +28588=>11172, +28586=>11173, +28623=>11174, +28607=>11175, +28600=>11176, +28578=>11177, +28617=>11178, +28587=>11179, +28621=>11180, +28591=>11181, +28594=>11182, +28592=>11183, +29125=>11184, +29122=>11185, +29119=>11186, +29112=>11187, +29142=>11188, +29120=>11189, +29121=>11190, +29131=>11191, +29140=>11192, +29130=>11193, +29127=>11194, +29135=>11195, +29117=>11196, +29144=>11197, +29116=>11198, +29126=>11199, +29146=>11200, +29147=>11201, +29341=>11202, +29342=>11203, +29545=>11204, +29542=>11205, +29543=>11206, +29548=>11207, +29541=>11208, +29547=>11209, +29546=>11210, +29823=>11211, +29850=>11212, +29856=>11213, +29844=>11214, +29842=>11215, +29845=>11216, +29857=>11217, +29963=>11218, +30080=>11219, +30255=>11220, +30253=>11221, +30257=>11222, +30269=>11223, +30259=>11224, +30268=>11225, +30261=>11226, +30258=>11227, +30256=>11228, +30395=>11229, +30438=>11230, +30618=>11231, +30621=>11232, +30625=>11233, +30620=>11234, +30619=>11235, +30626=>11236, +30627=>11237, +30613=>11238, +30617=>11239, +30615=>11240, +30941=>11241, +30953=>11242, +30949=>11243, +30954=>11244, +30942=>11245, +30947=>11246, +30939=>11247, +30945=>11248, +30946=>11249, +30957=>11250, +30943=>11251, +30944=>11252, +31140=>11253, +31300=>11254, +31304=>11255, +31303=>11256, +31414=>11257, +31416=>11258, +31413=>11259, +31409=>11260, +31415=>11261, +31710=>11262, +31715=>11263, +31719=>11264, +31709=>11265, +31701=>11266, +31717=>11267, +31706=>11268, +31720=>11269, +31737=>11270, +31700=>11271, +31722=>11272, +31714=>11273, +31708=>11274, +31723=>11275, +31704=>11276, +31711=>11277, +31954=>11278, +31956=>11279, +31959=>11280, +31952=>11281, +31953=>11282, +32274=>11283, +32289=>11284, +32279=>11285, +32268=>11286, +32287=>11287, +32288=>11288, +32275=>11289, +32270=>11290, +32284=>11291, +32277=>11292, +32282=>11293, +32290=>11294, +32267=>11295, +32271=>11296, +32278=>11297, +32269=>11298, +32276=>11299, +32293=>11300, +32292=>11301, +32579=>11302, +32635=>11303, +32636=>11304, +32634=>11305, +32689=>11306, +32751=>11307, +32810=>11308, +32809=>11309, +32876=>11310, +33201=>11311, +33190=>11312, +33198=>11313, +33209=>11314, +33205=>11315, +33195=>11316, +33200=>11317, +33196=>11318, +33204=>11319, +33202=>11320, +33207=>11321, +33191=>11322, +33266=>11323, +33365=>11324, +33366=>11325, +33367=>11326, +34134=>11327, +34117=>11328, +34155=>11329, +34125=>11330, +34131=>11331, +34145=>11332, +34136=>11333, +34112=>11334, +34118=>11335, +34148=>11336, +34113=>11337, +34146=>11338, +34116=>11339, +34129=>11340, +34119=>11341, +34147=>11342, +34110=>11343, +34139=>11344, +34161=>11345, +34126=>11346, +34158=>11347, +34165=>11348, +34133=>11349, +34151=>11350, +34144=>11351, +34188=>11352, +34150=>11353, +34141=>11354, +34132=>11355, +34149=>11356, +34156=>11357, +34403=>11358, +34405=>11359, +34404=>11360, +34724=>11361, +34715=>11362, +34703=>11363, +34711=>11364, +34707=>11365, +34706=>11366, +34696=>11367, +34689=>11368, +34710=>11369, +34712=>11370, +34681=>11371, +34695=>11372, +34723=>11373, +34693=>11374, +34704=>11375, +34705=>11376, +34717=>11377, +34692=>11378, +34708=>11379, +34716=>11380, +34714=>11381, +34697=>11382, +35102=>11383, +35110=>11384, +35120=>11385, +35117=>11386, +35118=>11387, +35111=>11388, +35121=>11389, +35106=>11390, +35113=>11391, +35107=>11392, +35119=>11393, +35116=>11394, +35103=>11395, +35313=>11396, +35552=>11397, +35554=>11398, +35570=>11399, +35572=>11400, +35573=>11401, +35549=>11402, +35604=>11403, +35556=>11404, +35551=>11405, +35568=>11406, +35528=>11407, +35550=>11408, +35553=>11409, +35560=>11410, +35583=>11411, +35567=>11412, +35579=>11413, +35985=>11414, +35986=>11415, +35984=>11416, +36085=>11417, +36078=>11418, +36081=>11419, +36080=>11420, +36083=>11421, +36204=>11422, +36206=>11423, +36261=>11424, +36263=>11425, +36403=>11426, +36414=>11427, +36408=>11428, +36416=>11429, +36421=>11430, +36406=>11431, +36412=>11432, +36413=>11433, +36417=>11434, +36400=>11435, +36415=>11436, +36541=>11437, +36662=>11438, +60329=>11438, +36654=>11439, +36661=>11440, +36658=>11441, +36665=>11442, +36663=>11443, +36660=>11444, +36982=>11445, +36985=>11446, +36987=>11447, +36998=>11448, +37114=>11449, +37171=>11450, +37173=>11451, +37174=>11452, +37267=>11453, +37264=>11454, +37265=>11455, +37261=>11456, +37263=>11457, +37671=>11458, +37662=>11459, +37640=>11460, +37663=>11461, +37638=>11462, +37647=>11463, +37754=>11464, +37688=>11465, +37692=>11466, +37659=>11467, +37667=>11468, +37650=>11469, +37633=>11470, +37702=>11471, +37677=>11472, +37646=>11473, +37645=>11474, +37579=>11475, +37661=>11476, +37626=>11477, +37651=>11478, +37625=>11479, +37623=>11480, +37684=>11481, +37634=>11482, +37668=>11483, +37631=>11484, +37673=>11485, +37689=>11486, +37685=>11487, +37674=>11488, +37652=>11489, +37644=>11490, +37643=>11491, +37630=>11492, +37641=>11493, +37632=>11494, +37627=>11495, +37654=>11496, +38332=>11497, +38349=>11498, +38334=>11499, +38329=>11500, +38330=>11501, +38326=>11502, +38335=>11503, +38325=>11504, +38333=>11505, +38569=>11506, +38612=>11507, +38667=>11508, +38674=>11509, +38672=>11510, +38809=>11511, +38807=>11512, +38804=>11513, +38896=>11514, +38904=>11515, +38965=>11516, +38959=>11517, +38962=>11518, +39204=>11519, +39199=>11520, +39207=>11521, +39209=>11522, +39326=>11523, +39406=>11524, +39404=>11525, +39397=>11526, +39396=>11527, +39408=>11528, +39395=>11529, +39402=>11530, +39401=>11531, +39399=>11532, +39609=>11533, +39615=>11534, +39604=>11535, +39611=>11536, +39670=>11537, +39674=>11538, +39673=>11539, +39671=>11540, +39731=>11541, +39808=>11542, +39813=>11543, +39815=>11544, +39804=>11545, +39806=>11546, +39803=>11547, +39810=>11548, +39827=>11549, +39826=>11550, +39824=>11551, +39802=>11552, +39829=>11553, +39805=>11554, +39816=>11555, +40229=>11556, +40215=>11557, +40224=>11558, +40222=>11559, +40212=>11560, +40233=>11561, +40221=>11562, +40216=>11563, +40226=>11564, +40208=>11565, +40217=>11566, +40223=>11567, +40584=>11568, +40582=>11569, +40583=>11570, +40622=>11571, +40621=>11572, +40661=>11573, +40662=>11574, +40698=>11575, +40722=>11576, +40765=>11577, +20774=>11578, +20773=>11579, +20770=>11580, +20772=>11581, +20768=>11582, +20777=>11583, +21236=>11584, +22163=>11585, +22156=>11586, +22157=>11587, +22150=>11588, +22148=>11589, +22147=>11590, +22142=>11591, +22146=>11592, +22143=>11593, +22145=>11594, +22742=>11595, +22740=>11596, +22735=>11597, +22738=>11598, +23341=>11599, +23333=>11600, +23346=>11601, +23331=>11602, +23340=>11603, +23335=>11604, +23334=>11605, +23343=>11606, +23342=>11607, +23419=>11608, +23537=>11609, +23538=>11610, +23991=>11611, +24172=>11612, +24170=>11613, +24510=>11614, +25027=>11615, +25013=>11616, +25020=>11617, +25063=>11618, +25056=>11619, +25061=>11620, +25060=>11621, +25064=>11622, +25054=>11623, +25839=>11624, +25833=>11625, +25827=>11626, +25835=>11627, +25828=>11628, +25832=>11629, +25985=>11630, +25984=>11631, +26038=>11632, +26074=>11633, +26322=>11634, +27277=>11635, +27286=>11636, +27265=>11637, +27301=>11638, +27273=>11639, +27295=>11640, +27291=>11641, +27297=>11642, +27294=>11643, +27271=>11644, +27283=>11645, +27278=>11646, +27285=>11647, +27267=>11648, +27304=>11649, +27300=>11650, +27281=>11651, +27263=>11652, +27302=>11653, +27290=>11654, +27269=>11655, +27276=>11656, +27282=>11657, +27483=>11658, +27565=>11659, +27657=>11660, +28620=>11661, +28585=>11662, +28660=>11663, +28628=>11664, +28643=>11665, +28636=>11666, +28653=>11667, +28647=>11668, +28646=>11669, +28638=>11670, +28658=>11671, +28637=>11672, +28642=>11673, +28648=>11674, +29153=>11675, +29169=>11676, +29160=>11677, +29170=>11678, +29156=>11679, +29168=>11680, +29154=>11681, +29555=>11682, +29550=>11683, +29551=>11684, +29847=>11685, +29874=>11686, +29867=>11687, +29840=>11688, +29866=>11689, +29869=>11690, +29873=>11691, +29861=>11692, +29871=>11693, +29968=>11694, +29969=>11695, +29970=>11696, +29967=>11697, +30084=>11698, +30275=>11699, +30280=>11700, +30281=>11701, +30279=>11702, +30372=>11703, +30441=>11704, +30645=>11705, +30635=>11706, +30642=>11707, +30647=>11708, +30646=>11709, +30644=>11710, +30641=>11711, +30632=>11712, +30704=>11713, +30963=>11714, +30973=>11715, +30978=>11716, +30971=>11717, +30972=>11718, +30975=>11719, +30962=>11720, +30981=>11721, +30969=>11722, +30974=>11723, +30980=>11724, +31147=>11725, +31144=>11726, +31324=>11727, +31323=>11728, +31318=>11729, +31320=>11730, +31316=>11731, +31322=>11732, +31422=>11733, +31424=>11734, +31425=>11735, +31749=>11736, +31759=>11737, +31730=>11738, +31744=>11739, +31743=>11740, +31739=>11741, +31758=>11742, +31732=>11743, +31755=>11744, +31731=>11745, +31746=>11746, +31753=>11747, +31747=>11748, +31745=>11749, +31736=>11750, +31741=>11751, +31750=>11752, +58176=>11752, +31728=>11753, +31729=>11754, +31760=>11755, +31754=>11756, +31976=>11757, +32301=>11758, +32316=>11759, +32322=>11760, +32307=>11761, +38984=>11762, +32312=>11763, +32298=>11764, +32329=>11765, +32320=>11766, +32327=>11767, +32297=>11768, +32332=>11769, +32304=>11770, +32315=>11771, +32310=>11772, +32324=>11773, +32314=>11774, +32581=>11775, +32639=>11776, +32638=>11777, +32637=>11778, +32756=>11779, +32754=>11780, +32812=>11781, +33211=>11782, +33220=>11783, +33228=>11784, +33226=>11785, +33221=>11786, +33223=>11787, +33212=>11788, +33257=>11789, +33371=>11790, +33370=>11791, +33372=>11792, +34179=>11793, +34176=>11794, +34191=>11795, +34215=>11796, +34197=>11797, +34208=>11798, +34187=>11799, +34211=>11800, +34171=>11801, +34212=>11802, +34202=>11803, +34206=>11804, +34167=>11805, +34172=>11806, +34185=>11807, +34209=>11808, +34170=>11809, +34168=>11810, +34135=>11811, +34190=>11812, +34198=>11813, +34182=>11814, +34189=>11815, +34201=>11816, +34205=>11817, +34177=>11818, +34210=>11819, +34178=>11820, +34184=>11821, +34181=>11822, +34169=>11823, +34166=>11824, +34200=>11825, +34192=>11826, +34207=>11827, +34408=>11828, +34750=>11829, +34730=>11830, +34733=>11831, +34757=>11832, +34736=>11833, +34732=>11834, +34745=>11835, +34741=>11836, +34748=>11837, +34734=>11838, +34761=>11839, +34755=>11840, +34754=>11841, +34764=>11842, +34743=>11843, +34735=>11844, +34756=>11845, +34762=>11846, +34740=>11847, +34742=>11848, +34751=>11849, +34744=>11850, +34749=>11851, +34782=>11852, +34738=>11853, +35125=>11854, +35123=>11855, +35132=>11856, +35134=>11857, +35137=>11858, +35154=>11859, +35127=>11860, +35138=>11861, +35245=>11862, +35247=>11863, +35246=>11864, +35314=>11865, +35315=>11866, +35614=>11867, +35608=>11868, +35606=>11869, +35601=>11870, +35589=>11871, +35595=>11872, +35618=>11873, +35599=>11874, +35602=>11875, +35605=>11876, +35591=>11877, +35597=>11878, +35592=>11879, +35590=>11880, +35612=>11881, +35603=>11882, +35610=>11883, +35919=>11884, +35952=>11885, +35954=>11886, +35953=>11887, +35951=>11888, +35989=>11889, +35988=>11890, +36089=>11891, +36207=>11892, +36430=>11893, +36429=>11894, +36435=>11895, +36432=>11896, +36428=>11897, +36423=>11898, +36675=>11899, +36672=>11900, +36997=>11901, +36990=>11902, +37176=>11903, +37274=>11904, +37282=>11905, +37275=>11906, +37273=>11907, +37279=>11908, +37281=>11909, +37277=>11910, +37280=>11911, +37793=>11912, +37763=>11913, +37807=>11914, +37732=>11915, +37718=>11916, +37703=>11917, +37756=>11918, +37720=>11919, +37724=>11920, +37750=>11921, +37705=>11922, +37712=>11923, +37713=>11924, +37728=>11925, +37741=>11926, +37775=>11927, +37708=>11928, +37738=>11929, +37753=>11930, +37719=>11931, +37717=>11932, +37714=>11933, +37711=>11934, +37745=>11935, +37751=>11936, +37755=>11937, +37729=>11938, +37726=>11939, +37731=>11940, +37735=>11941, +37710=>11942, +37721=>11943, +38343=>11944, +38336=>11945, +38345=>11946, +38339=>11947, +38341=>11948, +38327=>11949, +38574=>11950, +38576=>11951, +38572=>11952, +38688=>11953, +38687=>11954, +38680=>11955, +38685=>11956, +38681=>11957, +38810=>11958, +38817=>11959, +38812=>11960, +38814=>11961, +38813=>11962, +38869=>11963, +38868=>11964, +38897=>11965, +38977=>11966, +38980=>11967, +38986=>11968, +38985=>11969, +38981=>11970, +38979=>11971, +39205=>11972, +39211=>11973, +39212=>11974, +39210=>11975, +39219=>11976, +39218=>11977, +39215=>11978, +39213=>11979, +39217=>11980, +39216=>11981, +39320=>11982, +39331=>11983, +39329=>11984, +39426=>11985, +39418=>11986, +39412=>11987, +39415=>11988, +39417=>11989, +39416=>11990, +39414=>11991, +39419=>11992, +39421=>11993, +39422=>11994, +39420=>11995, +39427=>11996, +39614=>11997, +39678=>11998, +39677=>11999, +39681=>12000, +39676=>12001, +39752=>12002, +39834=>12003, +39848=>12004, +39838=>12005, +39835=>12006, +39846=>12007, +39841=>12008, +39845=>12009, +39844=>12010, +39814=>12011, +39842=>12012, +39840=>12013, +39855=>12014, +40243=>12015, +40257=>12016, +40295=>12017, +40246=>12018, +40238=>12019, +40239=>12020, +40241=>12021, +40248=>12022, +40240=>12023, +40261=>12024, +40258=>12025, +40259=>12026, +40254=>12027, +40247=>12028, +40256=>12029, +40253=>12030, +32757=>12031, +40237=>12032, +40586=>12033, +40585=>12034, +40589=>12035, +40624=>12036, +40648=>12037, +40666=>12038, +40699=>12039, +40703=>12040, +40740=>12041, +40739=>12042, +40738=>12043, +40788=>12044, +12245=>12045, +40864=>12045, +20785=>12046, +20781=>12047, +20782=>12048, +22168=>12049, +22172=>12050, +22167=>12051, +22170=>12052, +22173=>12053, +22169=>12054, +22896=>12055, +23356=>12056, +23657=>12057, +23658=>12058, +24000=>12059, +24173=>12060, +24174=>12061, +25048=>12062, +25055=>12063, +25069=>12064, +25070=>12065, +25073=>12066, +25066=>12067, +25072=>12068, +25067=>12069, +25046=>12070, +25065=>12071, +25855=>12072, +25860=>12073, +25853=>12074, +25848=>12075, +25857=>12076, +25859=>12077, +25852=>12078, +26004=>12079, +26075=>12080, +26330=>12081, +26331=>12082, +26328=>12083, +27333=>12084, +27321=>12085, +27325=>12086, +27361=>12087, +27334=>12088, +27322=>12089, +27318=>12090, +27319=>12091, +27335=>12092, +27316=>12093, +27309=>12094, +27486=>12095, +27593=>12096, +27659=>12097, +28679=>12098, +28684=>12099, +28685=>12100, +28673=>12101, +28677=>12102, +28692=>12103, +28686=>12104, +28671=>12105, +28672=>12106, +28667=>12107, +28710=>12108, +28668=>12109, +28663=>12110, +28682=>12111, +29185=>12112, +60224=>12112, +29183=>12113, +29177=>12114, +29187=>12115, +29181=>12116, +29558=>12117, +29880=>12118, +29888=>12119, +29877=>12120, +29889=>12121, +29886=>12122, +29878=>12123, +29883=>12124, +29890=>12125, +29972=>12126, +29971=>12127, +30300=>12128, +30308=>12129, +30297=>12130, +30288=>12131, +30291=>12132, +30295=>12133, +30298=>12134, +30374=>12135, +30397=>12136, +30444=>12137, +30658=>12138, +30650=>12139, +30988=>12140, +30995=>12141, +30996=>12142, +30985=>12143, +30992=>12144, +30994=>12145, +30993=>12146, +31149=>12147, +31148=>12148, +31327=>12149, +31772=>12150, +31785=>12151, +31769=>12152, +31776=>12153, +31775=>12154, +31789=>12155, +31773=>12156, +31782=>12157, +31784=>12158, +31778=>12159, +31781=>12160, +31792=>12161, +32348=>12162, +32336=>12163, +32342=>12164, +32355=>12165, +32344=>12166, +32354=>12167, +32351=>12168, +32337=>12169, +32352=>12170, +32343=>12171, +32339=>12172, +32693=>12173, +32691=>12174, +32759=>12175, +32760=>12176, +32885=>12177, +33233=>12178, +33234=>12179, +33232=>12180, +33375=>12181, +33374=>12182, +34228=>12183, +34246=>12184, +34240=>12185, +34243=>12186, +34242=>12187, +34227=>12188, +34229=>12189, +34237=>12190, +34247=>12191, +34244=>12192, +34239=>12193, +34251=>12194, +34254=>12195, +34248=>12196, +34245=>12197, +34225=>12198, +34230=>12199, +34258=>12200, +34340=>12201, +34232=>12202, +34231=>12203, +34238=>12204, +34409=>12205, +34791=>12206, +34790=>12207, +34786=>12208, +34779=>12209, +34795=>12210, +34794=>12211, +34789=>12212, +34783=>12213, +34803=>12214, +34788=>12215, +34772=>12216, +34780=>12217, +34771=>12218, +34797=>12219, +34776=>12220, +34787=>12221, +34775=>12222, +34777=>12223, +34817=>12224, +34804=>12225, +34792=>12226, +34781=>12227, +35155=>12228, +35147=>12229, +35151=>12230, +35148=>12231, +35142=>12232, +35152=>12233, +35153=>12234, +35145=>12235, +35626=>12236, +35623=>12237, +35619=>12238, +35635=>12239, +35632=>12240, +35637=>12241, +35655=>12242, +35631=>12243, +35644=>12244, +35646=>12245, +35633=>12246, +35621=>12247, +35639=>12248, +35622=>12249, +35638=>12250, +35630=>12251, +35620=>12252, +35643=>12253, +35645=>12254, +35642=>12255, +35906=>12256, +35957=>12257, +35993=>12258, +35992=>12259, +35991=>12260, +36094=>12261, +36100=>12262, +36098=>12263, +36096=>12264, +36444=>12265, +36450=>12266, +36448=>12267, +36439=>12268, +36438=>12269, +36446=>12270, +36453=>12271, +36455=>12272, +36443=>12273, +36442=>12274, +36449=>12275, +36445=>12276, +36457=>12277, +36436=>12278, +36678=>12279, +36679=>12280, +36680=>12281, +36683=>12282, +37160=>12283, +37178=>12284, +37179=>12285, +37182=>12286, +37288=>12287, +37285=>12288, +37287=>12289, +37295=>12290, +37290=>12291, +37813=>12292, +37772=>12293, +37778=>12294, +37815=>12295, +37787=>12296, +37789=>12297, +37769=>12298, +37799=>12299, +37774=>12300, +37802=>12301, +37790=>12302, +37798=>12303, +37781=>12304, +37768=>12305, +37785=>12306, +37791=>12307, +37760=>12308, +37773=>12309, +37809=>12310, +37777=>12311, +37810=>12312, +37796=>12313, +37800=>12314, +37812=>12315, +37795=>12316, +38354=>12317, +38355=>12318, +38353=>12319, +38579=>12320, +38615=>12321, +38618=>12322, +24002=>12323, +38623=>12324, +38616=>12325, +38621=>12326, +38691=>12327, +38690=>12328, +38693=>12329, +38828=>12330, +38830=>12331, +38824=>12332, +38827=>12333, +38820=>12334, +38826=>12335, +38818=>12336, +38821=>12337, +38871=>12338, +38873=>12339, +38870=>12340, +38872=>12341, +38906=>12342, +38992=>12343, +38993=>12344, +38994=>12345, +39096=>12346, +39233=>12347, +39228=>12348, +39226=>12349, +39439=>12350, +39435=>12351, +39433=>12352, +39437=>12353, +39428=>12354, +39441=>12355, +39434=>12356, +39429=>12357, +39431=>12358, +39430=>12359, +39616=>12360, +39644=>12361, +39688=>12362, +39684=>12363, +39685=>12364, +39721=>12365, +39733=>12366, +39754=>12367, +39756=>12368, +39755=>12369, +39879=>12370, +39878=>12371, +39875=>12372, +39871=>12373, +39873=>12374, +39861=>12375, +39864=>12376, +39891=>12377, +39862=>12378, +39876=>12379, +39865=>12380, +39869=>12381, +40284=>12382, +40275=>12383, +40271=>12384, +40266=>12385, +40283=>12386, +40267=>12387, +40281=>12388, +40278=>12389, +40268=>12390, +40279=>12391, +40274=>12392, +40276=>12393, +40287=>12394, +40280=>12395, +40282=>12396, +40590=>12397, +40588=>12398, +40671=>12399, +40705=>12400, +40704=>12401, +40726=>12402, +58693=>12402, +40741=>12403, +40747=>12404, +40746=>12405, +40745=>12406, +40744=>12407, +40780=>12408, +40789=>12409, +20788=>12410, +20789=>12411, +21142=>12412, +21239=>12413, +21428=>12414, +22187=>12415, +22189=>12416, +22182=>12417, +22183=>12418, +22186=>12419, +22188=>12420, +22746=>12421, +22749=>12422, +22747=>12423, +22802=>12424, +23357=>12425, +23358=>12426, +23359=>12427, +24003=>12428, +24176=>12429, +24511=>12430, +25083=>12431, +25863=>12432, +25872=>12433, +25869=>12434, +25865=>12435, +25868=>12436, +25870=>12437, +25988=>12438, +26078=>12439, +26077=>12440, +26334=>12441, +27367=>12442, +27360=>12443, +27340=>12444, +27345=>12445, +27353=>12446, +27339=>12447, +27359=>12448, +27356=>12449, +27344=>12450, +27371=>12451, +27343=>12452, +27341=>12453, +27358=>12454, +27488=>12455, +27568=>12456, +27660=>12457, +28697=>12458, +28711=>12459, +28704=>12460, +28694=>12461, +28715=>12462, +28705=>12463, +28706=>12464, +28707=>12465, +28713=>12466, +28695=>12467, +28708=>12468, +28700=>12469, +29196=>12470, +29194=>12471, +29191=>12472, +29186=>12473, +29189=>12474, +29349=>12475, +29350=>12476, +29348=>12477, +29347=>12478, +29345=>12479, +29899=>12480, +29893=>12481, +29879=>12482, +29891=>12483, +29974=>12484, +30304=>12485, +30665=>12486, +30666=>12487, +30660=>12488, +30705=>12489, +31005=>12490, +31003=>12491, +31009=>12492, +31004=>12493, +30999=>12494, +31006=>12495, +31152=>12496, +31335=>12497, +31336=>12498, +31795=>12499, +31804=>12500, +31801=>12501, +31788=>12502, +31803=>12503, +31980=>12504, +31978=>12505, +32374=>12506, +32373=>12507, +32376=>12508, +32368=>12509, +32375=>12510, +32367=>12511, +32378=>12512, +32370=>12513, +32372=>12514, +32360=>12515, +32587=>12516, +32586=>12517, +32643=>12518, +32646=>12519, +32695=>12520, +32765=>12521, +32766=>12522, +32888=>12523, +33239=>12524, +33237=>12525, +33291=>12526, +33380=>12527, +33377=>12528, +33379=>12529, +34283=>12530, +34289=>12531, +34285=>12532, +34265=>12533, +34273=>12534, +34280=>12535, +34266=>12536, +34263=>12537, +34284=>12538, +34290=>12539, +34296=>12540, +34264=>12541, +34271=>12542, +34275=>12543, +34268=>12544, +34257=>12545, +34288=>12546, +34278=>12547, +34287=>12548, +34270=>12549, +34274=>12550, +34816=>12551, +34810=>12552, +34819=>12553, +34806=>12554, +34807=>12555, +34825=>12556, +34828=>12557, +34827=>12558, +34822=>12559, +34812=>12560, +34824=>12561, +34815=>12562, +34826=>12563, +34818=>12564, +35170=>12565, +35162=>12566, +35163=>12567, +35159=>12568, +35169=>12569, +35164=>12570, +35160=>12571, +35165=>12572, +35161=>12573, +35208=>12574, +35255=>12575, +35254=>12576, +35318=>12577, +35664=>12578, +35656=>12579, +35658=>12580, +35648=>12581, +35667=>12582, +35670=>12583, +35668=>12584, +35659=>12585, +35669=>12586, +35665=>12587, +35650=>12588, +35666=>12589, +35671=>12590, +35907=>12591, +35959=>12592, +35958=>12593, +35994=>12594, +36102=>12595, +36103=>12596, +36105=>12597, +36268=>12598, +36266=>12599, +36269=>12600, +36267=>12601, +36461=>12602, +36472=>12603, +36467=>12604, +36458=>12605, +36463=>12606, +36475=>12607, +36546=>12608, +36690=>12609, +36689=>12610, +36687=>12611, +36688=>12612, +36691=>12613, +36788=>12614, +37184=>12615, +37183=>12616, +37296=>12617, +37293=>12618, +37854=>12619, +37831=>12620, +37839=>12621, +37826=>12622, +37850=>12623, +37840=>12624, +37881=>12625, +37868=>12626, +37836=>12627, +37849=>12628, +37801=>12629, +37862=>12630, +37834=>12631, +37844=>12632, +37870=>12633, +37859=>12634, +37845=>12635, +37828=>12636, +37838=>12637, +37824=>12638, +37842=>12639, +37797=>12640, +37863=>12641, +38269=>12642, +38362=>12643, +38363=>12644, +38625=>12645, +38697=>12646, +38699=>12647, +38700=>12648, +38696=>12649, +38694=>12650, +38835=>12651, +38839=>12652, +38838=>12653, +38877=>12654, +38878=>12655, +38879=>12656, +39004=>12657, +39001=>12658, +39005=>12659, +38999=>12660, +39103=>12661, +39101=>12662, +39099=>12663, +39102=>12664, +39240=>12665, +39239=>12666, +39235=>12667, +39334=>12668, +39335=>12669, +39450=>12670, +39445=>12671, +39461=>12672, +39453=>12673, +39460=>12674, +39451=>12675, +39458=>12676, +39456=>12677, +39463=>12678, +39459=>12679, +39454=>12680, +39452=>12681, +39444=>12682, +39618=>12683, +39691=>12684, +39690=>12685, +39694=>12686, +39692=>12687, +39735=>12688, +39914=>12689, +39915=>12690, +39904=>12691, +39902=>12692, +39908=>12693, +39910=>12694, +39906=>12695, +39920=>12696, +39892=>12697, +39895=>12698, +39916=>12699, +39900=>12700, +39897=>12701, +39909=>12702, +39893=>12703, +39905=>12704, +39898=>12705, +40311=>12706, +40321=>12707, +40330=>12708, +40324=>12709, +40328=>12710, +40305=>12711, +40320=>12712, +40312=>12713, +40326=>12714, +40331=>12715, +40332=>12716, +40317=>12717, +40299=>12718, +40308=>12719, +40309=>12720, +40304=>12721, +40297=>12722, +40325=>12723, +40307=>12724, +40315=>12725, +40322=>12726, +40303=>12727, +40313=>12728, +40319=>12729, +40327=>12730, +40296=>12731, +40596=>12732, +40593=>12733, +40640=>12734, +40700=>12735, +40749=>12736, +40768=>12737, +40769=>12738, +40781=>12739, +40790=>12740, +40791=>12741, +40792=>12742, +21303=>12743, +22194=>12744, +22197=>12745, +22195=>12746, +22755=>12747, +23365=>12748, +24006=>12749, +24007=>12750, +24302=>12751, +24303=>12752, +24512=>12753, +24513=>12754, +25081=>12755, +25879=>12756, +25878=>12757, +25877=>12758, +25875=>12759, +26079=>12760, +26344=>12761, +26339=>12762, +26340=>12763, +27379=>12764, +27376=>12765, +27370=>12766, +27368=>12767, +27385=>12768, +27377=>12769, +27374=>12770, +27375=>12771, +28732=>12772, +28725=>12773, +28719=>12774, +28727=>12775, +28724=>12776, +28721=>12777, +28738=>12778, +28728=>12779, +28735=>12780, +28730=>12781, +28729=>12782, +28714=>12783, +28736=>12784, +28731=>12785, +28723=>12786, +28737=>12787, +29203=>12788, +29204=>12789, +29352=>12790, +29565=>12791, +29564=>12792, +29882=>12793, +30379=>12794, +30378=>12795, +30398=>12796, +30445=>12797, +30668=>12798, +30670=>12799, +30671=>12800, +30669=>12801, +30706=>12802, +31013=>12803, +31011=>12804, +31015=>12805, +31016=>12806, +31012=>12807, +31017=>12808, +31154=>12809, +31342=>12810, +31340=>12811, +31341=>12812, +31479=>12813, +31817=>12814, +31816=>12815, +31818=>12816, +31815=>12817, +31813=>12818, +31982=>12819, +32379=>12820, +32382=>12821, +32385=>12822, +32384=>12823, +32698=>12824, +32767=>12825, +32889=>12826, +33243=>12827, +33241=>12828, +33384=>12829, +33385=>12830, +34338=>12831, +34303=>12832, +34305=>12833, +34302=>12834, +34331=>12835, +34304=>12836, +34294=>12837, +34308=>12838, +34313=>12839, +34309=>12840, +34316=>12841, +34301=>12842, +34841=>12843, +34832=>12844, +34833=>12845, +34839=>12846, +34835=>12847, +34838=>12848, +35171=>12849, +35174=>12850, +35257=>12851, +35319=>12852, +35680=>12853, +35690=>12854, +35677=>12855, +35688=>12856, +35683=>12857, +35685=>12858, +35687=>12859, +35693=>12860, +36270=>12861, +36486=>12862, +36488=>12863, +36484=>12864, +36697=>12865, +36694=>12866, +36695=>12867, +36693=>12868, +36696=>12869, +36698=>12870, +37005=>12871, +37187=>12872, +37185=>12873, +37303=>12874, +37301=>12875, +37298=>12876, +37299=>12877, +37899=>12878, +37907=>12879, +37883=>12880, +37920=>12881, +37903=>12882, +37908=>12883, +37886=>12884, +37909=>12885, +37904=>12886, +37928=>12887, +37913=>12888, +37901=>12889, +37877=>12890, +37888=>12891, +37879=>12892, +37895=>12893, +37902=>12894, +37910=>12895, +37906=>12896, +37882=>12897, +37897=>12898, +37880=>12899, +37948=>12900, +37898=>12901, +37887=>12902, +37884=>12903, +37900=>12904, +37878=>12905, +37905=>12906, +37894=>12907, +38366=>12908, +38368=>12909, +38367=>12910, +38702=>12911, +38703=>12912, +38841=>12913, +38843=>12914, +38909=>12915, +38910=>12916, +39008=>12917, +39010=>12918, +39011=>12919, +39007=>12920, +39105=>12921, +39106=>12922, +39248=>12923, +39246=>12924, +39257=>12925, +39244=>12926, +39243=>12927, +39251=>12928, +39474=>12929, +39476=>12930, +39473=>12931, +39468=>12932, +39466=>12933, +39478=>12934, +39465=>12935, +39470=>12936, +39480=>12937, +39469=>12938, +39623=>12939, +39626=>12940, +39622=>12941, +39696=>12942, +39698=>12943, +39697=>12944, +39947=>12945, +39944=>12946, +39927=>12947, +39941=>12948, +39954=>12949, +39928=>12950, +40000=>12951, +39943=>12952, +39950=>12953, +39942=>12954, +39959=>12955, +39956=>12956, +39945=>12957, +40351=>12958, +40345=>12959, +40356=>12960, +40349=>12961, +40338=>12962, +40344=>12963, +40336=>12964, +40347=>12965, +40352=>12966, +40340=>12967, +40348=>12968, +40362=>12969, +40343=>12970, +40353=>12971, +40346=>12972, +40354=>12973, +40360=>12974, +40350=>12975, +40355=>12976, +40383=>12977, +40361=>12978, +40342=>12979, +40358=>12980, +40359=>12981, +40601=>12982, +40603=>12983, +40602=>12984, +40677=>12985, +40676=>12986, +40679=>12987, +40678=>12988, +40752=>12989, +40750=>12990, +40795=>12991, +40800=>12992, +40798=>12993, +40797=>12994, +40793=>12995, +40849=>12996, +20794=>12997, +20793=>12998, +21144=>12999, +21143=>13000, +22211=>13001, +22205=>13002, +22206=>13003, +23368=>13004, +23367=>13005, +24011=>13006, +24015=>13007, +24305=>13008, +25085=>13009, +25883=>13010, +27394=>13011, +27388=>13012, +27395=>13013, +27384=>13014, +27392=>13015, +28739=>13016, +28740=>13017, +28746=>13018, +28744=>13019, +28745=>13020, +28741=>13021, +28742=>13022, +29213=>13023, +29210=>13024, +29209=>13025, +29566=>13026, +29975=>13027, +30314=>13028, +30672=>13029, +31021=>13030, +31025=>13031, +31023=>13032, +31828=>13033, +31827=>13034, +31986=>13035, +32394=>13036, +60229=>13037, +32391=>13037, +32392=>13038, +32395=>13039, +32390=>13040, +32397=>13041, +32589=>13042, +32699=>13043, +32816=>13044, +33245=>13045, +34328=>13046, +34346=>13047, +34342=>13048, +34335=>13049, +34339=>13050, +34332=>13051, +34329=>13052, +34343=>13053, +34350=>13054, +34337=>13055, +34336=>13056, +34345=>13057, +34334=>13058, +34341=>13059, +34857=>13060, +34845=>13061, +34843=>13062, +34848=>13063, +34852=>13064, +34844=>13065, +34859=>13066, +34890=>13067, +35181=>13068, +35177=>13069, +35182=>13070, +35179=>13071, +35322=>13072, +35705=>13073, +35704=>13074, +35653=>13075, +35706=>13076, +35707=>13077, +36112=>13078, +36116=>13079, +36271=>13080, +36494=>13081, +36492=>13082, +36702=>13083, +36699=>13084, +36701=>13085, +37190=>13086, +37188=>13087, +37189=>13088, +37305=>13089, +37951=>13090, +37947=>13091, +37942=>13092, +37929=>13093, +37949=>13094, +37936=>13095, +37945=>13096, +37930=>13097, +37943=>13098, +37932=>13099, +37952=>13100, +37937=>13101, +38373=>13102, +38372=>13103, +38371=>13104, +38709=>13105, +38714=>13106, +38847=>13107, +38881=>13108, +39012=>13109, +39113=>13110, +39110=>13111, +39104=>13112, +39256=>13113, +39254=>13114, +39481=>13115, +39485=>13116, +39494=>13117, +39492=>13118, +39490=>13119, +39489=>13120, +39482=>13121, +39487=>13122, +39629=>13123, +39701=>13124, +39703=>13125, +39704=>13126, +39702=>13127, +39738=>13128, +39762=>13129, +39979=>13130, +39965=>13131, +39964=>13132, +39980=>13133, +39971=>13134, +39976=>13135, +39977=>13136, +39972=>13137, +39969=>13138, +40375=>13139, +40374=>13140, +40380=>13141, +40385=>13142, +40391=>13143, +40394=>13144, +40399=>13145, +40382=>13146, +40389=>13147, +40387=>13148, +40379=>13149, +40373=>13150, +40398=>13151, +40377=>13152, +40378=>13153, +40364=>13154, +40392=>13155, +40369=>13156, +40365=>13157, +40396=>13158, +40371=>13159, +40397=>13160, +40370=>13161, +40570=>13162, +40604=>13163, +40683=>13164, +40686=>13165, +40685=>13166, +40731=>13167, +40728=>13168, +40730=>13169, +40753=>13170, +40782=>13171, +40805=>13172, +40804=>13173, +40850=>13174, +20153=>13175, +22214=>13176, +22213=>13177, +22219=>13178, +22897=>13179, +23371=>13180, +23372=>13181, +24021=>13182, +24017=>13183, +24306=>13184, +25889=>13185, +25888=>13186, +25894=>13187, +25890=>13188, +27403=>13189, +27400=>13190, +27401=>13191, +27661=>13192, +28757=>13193, +28758=>13194, +28759=>13195, +28754=>13196, +29214=>13197, +29215=>13198, +29353=>13199, +29567=>13200, +29912=>13201, +29909=>13202, +29913=>13203, +29911=>13204, +30317=>13205, +30381=>13206, +31029=>13207, +31156=>13208, +31344=>13209, +31345=>13210, +31831=>13211, +31836=>13212, +31833=>13213, +31835=>13214, +31834=>13215, +31988=>13216, +31985=>13217, +32401=>13218, +32591=>13219, +32647=>13220, +33246=>13221, +33387=>13222, +34356=>13223, +34357=>13224, +34355=>13225, +34348=>13226, +34354=>13227, +34358=>13228, +34860=>13229, +34856=>13230, +34854=>13231, +34858=>13232, +34853=>13233, +35185=>13234, +35263=>13235, +35262=>13236, +35323=>13237, +35710=>13238, +35716=>13239, +35714=>13240, +35718=>13241, +35717=>13242, +35711=>13243, +36117=>13244, +36501=>13245, +36500=>13246, +36506=>13247, +36498=>13248, +36496=>13249, +36502=>13250, +36503=>13251, +36704=>13252, +36706=>13253, +37191=>13254, +37964=>13255, +37968=>13256, +37962=>13257, +37963=>13258, +37967=>13259, +37959=>13260, +37957=>13261, +37960=>13262, +37961=>13263, +37958=>13264, +38719=>13265, +38883=>13266, +39018=>13267, +39017=>13268, +39115=>13269, +39252=>13270, +39259=>13271, +39502=>13272, +39507=>13273, +39508=>13274, +39500=>13275, +39503=>13276, +39496=>13277, +39498=>13278, +39497=>13279, +39506=>13280, +39504=>13281, +39632=>13282, +39705=>13283, +39723=>13284, +39739=>13285, +39766=>13286, +39765=>13287, +40006=>13288, +40008=>13289, +39999=>13290, +40004=>13291, +39993=>13292, +39987=>13293, +40001=>13294, +39996=>13295, +39991=>13296, +39988=>13297, +39986=>13298, +39997=>13299, +39990=>13300, +40411=>13301, +40402=>13302, +40414=>13303, +40410=>13304, +40395=>13305, +40400=>13306, +40412=>13307, +40401=>13308, +40415=>13309, +40425=>13310, +40409=>13311, +40408=>13312, +40406=>13313, +40437=>13314, +40405=>13315, +40413=>13316, +40630=>13317, +40688=>13318, +40757=>13319, +40755=>13320, +40754=>13321, +40770=>13322, +40811=>13323, +40853=>13324, +40866=>13325, +20797=>13326, +21145=>13327, +22760=>13328, +22759=>13329, +22898=>13330, +23373=>13331, +24024=>13332, +34863=>13333, +24399=>13334, +25089=>13335, +25091=>13336, +25092=>13337, +25897=>13338, +25893=>13339, +26006=>13340, +26347=>13341, +27409=>13342, +27410=>13343, +27407=>13344, +27594=>13345, +28763=>13346, +28762=>13347, +29218=>13348, +29570=>13349, +29569=>13350, +29571=>13351, +30320=>13352, +30676=>13353, +31847=>13354, +31846=>13355, +32405=>13356, +33388=>13357, +34362=>13358, +34368=>13359, +34361=>13360, +34364=>13361, +34353=>13362, +34363=>13363, +34366=>13364, +34864=>13365, +34866=>13366, +34862=>13367, +34867=>13368, +35190=>13369, +35188=>13370, +35187=>13371, +35326=>13372, +35724=>13373, +35726=>13374, +35723=>13375, +35720=>13376, +35909=>13377, +36121=>13378, +36504=>13379, +36708=>13380, +36707=>13381, +37308=>13382, +37986=>13383, +37973=>13384, +37981=>13385, +37975=>13386, +37982=>13387, +38852=>13388, +38853=>13389, +38912=>13390, +39510=>13391, +39513=>13392, +39710=>13393, +39711=>13394, +39712=>13395, +40018=>13396, +40024=>13397, +40016=>13398, +40010=>13399, +40013=>13400, +40011=>13401, +40021=>13402, +40025=>13403, +40012=>13404, +40014=>13405, +40443=>13406, +40439=>13407, +40431=>13408, +40419=>13409, +40427=>13410, +40440=>13411, +40420=>13412, +40438=>13413, +40417=>13414, +40430=>13415, +40422=>13416, +40434=>13417, +40432=>13418, +60370=>13418, +40418=>13419, +40428=>13420, +40436=>13421, +40435=>13422, +40424=>13423, +40429=>13424, +40642=>13425, +40656=>13426, +40690=>13427, +40691=>13428, +40710=>13429, +40732=>13430, +40760=>13431, +40759=>13432, +40758=>13433, +40771=>13434, +40783=>13435, +40817=>13436, +40816=>13437, +40814=>13438, +40815=>13439, +22227=>13440, +22221=>13441, +23374=>13442, +23661=>13443, +25901=>13444, +26349=>13445, +26350=>13446, +27411=>13447, +28767=>13448, +28769=>13449, +28765=>13450, +28768=>13451, +29219=>13452, +29915=>13453, +29925=>13454, +30677=>13455, +31032=>13456, +31159=>13457, +31158=>13458, +31850=>13459, +32407=>13460, +32649=>13461, +33389=>13462, +34371=>13463, +34872=>13464, +34871=>13465, +34869=>13466, +34891=>13467, +35732=>13468, +35733=>13469, +36510=>13470, +36511=>13471, +36512=>13472, +36509=>13473, +37310=>13474, +37309=>13475, +37314=>13476, +37995=>13477, +37992=>13478, +37993=>13479, +38629=>13480, +38726=>13481, +38723=>13482, +38727=>13483, +38855=>13484, +38885=>13485, +39518=>13486, +39637=>13487, +39769=>13488, +40035=>13489, +40039=>13490, +40038=>13491, +40034=>13492, +40030=>13493, +40032=>13494, +40450=>13495, +40446=>13496, +40455=>13497, +40451=>13498, +40454=>13499, +40453=>13500, +40448=>13501, +40449=>13502, +40457=>13503, +40447=>13504, +40445=>13505, +40452=>13506, +40608=>13507, +40734=>13508, +40774=>13509, +40820=>13510, +40821=>13511, +40822=>13512, +22228=>13513, +25902=>13514, +26040=>13515, +27416=>13516, +27417=>13517, +27415=>13518, +27418=>13519, +28770=>13520, +29222=>13521, +29354=>13522, +30680=>13523, +30681=>13524, +31033=>13525, +31849=>13526, +31851=>13527, +31990=>13528, +32410=>13529, +32408=>13530, +32411=>13531, +32409=>13532, +33248=>13533, +33249=>13534, +34374=>13535, +34375=>13536, +34376=>13537, +35193=>13538, +35194=>13539, +35196=>13540, +35195=>13541, +35327=>13542, +35736=>13543, +35737=>13544, +36517=>13545, +36516=>13546, +36515=>13547, +37998=>13548, +37997=>13549, +37999=>13550, +38001=>13551, +38003=>13552, +38729=>13553, +39026=>13554, +39263=>13555, +40040=>13556, +40046=>13557, +40045=>13558, +40459=>13559, +40461=>13560, +40464=>13561, +40463=>13562, +40466=>13563, +40465=>13564, +40609=>13565, +40693=>13566, +40713=>13567, +40775=>13568, +40824=>13569, +40827=>13570, +40826=>13571, +40825=>13572, +22302=>13573, +28774=>13574, +31855=>13575, +34876=>13576, +36274=>13577, +36518=>13578, +37315=>13579, +38004=>13580, +38008=>13581, +38006=>13582, +38005=>13583, +39520=>13584, +39726=>13585, +60830=>13585, +40052=>13586, +40051=>13587, +40049=>13588, +40053=>13589, +40468=>13590, +40467=>13591, +40694=>13592, +40714=>13593, +40868=>13594, +28776=>13595, +28773=>13596, +31991=>13597, +34410=>13598, +34878=>13599, +34877=>13600, +34879=>13601, +35742=>13602, +35996=>13603, +36521=>13604, +36553=>13605, +38731=>13606, +39027=>13607, +39028=>13608, +39116=>13609, +39265=>13610, +39339=>13611, +39524=>13612, +39526=>13613, +39527=>13614, +39716=>13615, +40469=>13616, +40471=>13617, +40776=>13618, +25095=>13619, +27422=>13620, +29223=>13621, +34380=>13622, +36520=>13623, +38018=>13624, +38016=>13625, +38017=>13626, +39529=>13627, +39528=>13628, +40473=>13629, +34379=>13630, +35743=>13631, +38019=>13632, +40057=>13633, +40631=>13634, +30325=>13635, +39531=>13636, +40058=>13637, +40477=>13638, +28777=>13639, +28778=>13640, +29225=>13641, +40612=>13642, +40830=>13643, +40777=>13644, +40856=>13645, +65049=>13646, +65075=>13743, +9588=>13744, +65076=>13745, +65103=>13746, +168=>13747, +776=>13747, +63208=>13747, +710=>13748, +65342=>13748, +63209=>13748, +12541=>13749, +63210=>13749, +12542=>13750, +63211=>13750, +12445=>13751, +63212=>13751, +12446=>13752, +63213=>13752, +12293=>13754, +63216=>13754, +12294=>13755, +63217=>13755, +12295=>13756, +63218=>13756, +12540=>13757, +63219=>13757, +65339=>13758, +63220=>13758, +65341=>13759, +63221=>13759, +10045=>13760, +63222=>13760, +12353=>13761, +63223=>13761, +12354=>13762, +63224=>13762, +12355=>13763, +63225=>13763, +12356=>13764, +63226=>13764, +12357=>13765, +63227=>13765, +12358=>13766, +63228=>13766, +12359=>13767, +63229=>13767, +12360=>13768, +63230=>13768, +12361=>13769, +63231=>13769, +12362=>13770, +63232=>13770, +12363=>13771, +63233=>13771, +12364=>13772, +63234=>13772, +12365=>13773, +63235=>13773, +12366=>13774, +63236=>13774, +12367=>13775, +63237=>13775, +12368=>13776, +63238=>13776, +12369=>13777, +63239=>13777, +12370=>13778, +63240=>13778, +12371=>13779, +63241=>13779, +12372=>13780, +63242=>13780, +12373=>13781, +63243=>13781, +12374=>13782, +63244=>13782, +12375=>13783, +63245=>13783, +12376=>13784, +63246=>13784, +12377=>13785, +63247=>13785, +12378=>13786, +63248=>13786, +12379=>13787, +63249=>13787, +12380=>13788, +63250=>13788, +12381=>13789, +63251=>13789, +12382=>13790, +63252=>13790, +12383=>13791, +63253=>13791, +12384=>13792, +63254=>13792, +12385=>13793, +63255=>13793, +12386=>13794, +63256=>13794, +12387=>13795, +63257=>13795, +12388=>13796, +63258=>13796, +12389=>13797, +63259=>13797, +12390=>13798, +63260=>13798, +12391=>13799, +63261=>13799, +12392=>13800, +63262=>13800, +12393=>13801, +63263=>13801, +12394=>13802, +63264=>13802, +12395=>13803, +63265=>13803, +12396=>13804, +63266=>13804, +12397=>13805, +63267=>13805, +12398=>13806, +63268=>13806, +12399=>13807, +63269=>13807, +12400=>13808, +63270=>13808, +12401=>13809, +63271=>13809, +12402=>13810, +63272=>13810, +12403=>13811, +63273=>13811, +12404=>13812, +63274=>13812, +12405=>13813, +63275=>13813, +12406=>13814, +63276=>13814, +12407=>13815, +63277=>13815, +12408=>13816, +63278=>13816, +12409=>13817, +63279=>13817, +12410=>13818, +63280=>13818, +12411=>13819, +63281=>13819, +12412=>13820, +63282=>13820, +12413=>13821, +63283=>13821, +12414=>13822, +63284=>13822, +12415=>13823, +63285=>13823, +12416=>13824, +63286=>13824, +12417=>13825, +63287=>13825, +12418=>13826, +63288=>13826, +12419=>13827, +63289=>13827, +12420=>13828, +63290=>13828, +12421=>13829, +63291=>13829, +12422=>13830, +63292=>13830, +12423=>13831, +63293=>13831, +12424=>13832, +63294=>13832, +12425=>13833, +63295=>13833, +12426=>13834, +63296=>13834, +12427=>13835, +63297=>13835, +12428=>13836, +63298=>13836, +12429=>13837, +63299=>13837, +12430=>13838, +63300=>13838, +12431=>13839, +63301=>13839, +12432=>13840, +63302=>13840, +12433=>13841, +63303=>13841, +12434=>13842, +63304=>13842, +12435=>13843, +63305=>13843, +12449=>13844, +63306=>13844, +12450=>13845, +63307=>13845, +12451=>13846, +63308=>13846, +12452=>13847, +63309=>13847, +12453=>13848, +63310=>13848, +12454=>13849, +63311=>13849, +12455=>13850, +63312=>13850, +12456=>13851, +63313=>13851, +12457=>13852, +63314=>13852, +12458=>13853, +63315=>13853, +12459=>13854, +63316=>13854, +12460=>13855, +63317=>13855, +12461=>13856, +63318=>13856, +12462=>13857, +63319=>13857, +12463=>13858, +63320=>13858, +12464=>13859, +63321=>13859, +12465=>13860, +63322=>13860, +12466=>13861, +63323=>13861, +12467=>13862, +63324=>13862, +12468=>13863, +63325=>13863, +12469=>13864, +63326=>13864, +12470=>13865, +63327=>13865, +12471=>13866, +63328=>13866, +12472=>13867, +63329=>13867, +12473=>13868, +63330=>13868, +12474=>13869, +63331=>13869, +12475=>13870, +63332=>13870, +12476=>13871, +63333=>13871, +12477=>13872, +63334=>13872, +12478=>13873, +63335=>13873, +12479=>13874, +63336=>13874, +12480=>13875, +63337=>13875, +12481=>13876, +63338=>13876, +12482=>13877, +63339=>13877, +12483=>13878, +63340=>13878, +12484=>13879, +63341=>13879, +12485=>13880, +63342=>13880, +12486=>13881, +63343=>13881, +12487=>13882, +63344=>13882, +12488=>13883, +63345=>13883, +12489=>13884, +63346=>13884, +12490=>13885, +63347=>13885, +12491=>13886, +63348=>13886, +12492=>13887, +63349=>13887, +12493=>13888, +63350=>13888, +12494=>13889, +63351=>13889, +12495=>13890, +63352=>13890, +12496=>13891, +63353=>13891, +12497=>13892, +63354=>13892, +12498=>13893, +63355=>13893, +12499=>13894, +63356=>13894, +12500=>13895, +63357=>13895, +12501=>13896, +63358=>13896, +12502=>13897, +63359=>13897, +12503=>13898, +63360=>13898, +12504=>13899, +63361=>13899, +12505=>13900, +63362=>13900, +12506=>13901, +63363=>13901, +12507=>13902, +63364=>13902, +12508=>13903, +63365=>13903, +12509=>13904, +63366=>13904, +12510=>13905, +63367=>13905, +12511=>13906, +63368=>13906, +12512=>13907, +63369=>13907, +12513=>13908, +63370=>13908, +12514=>13909, +63371=>13909, +12515=>13910, +63372=>13910, +12516=>13911, +63373=>13911, +12517=>13912, +63374=>13912, +12518=>13913, +63375=>13913, +12519=>13914, +63376=>13914, +12520=>13915, +63377=>13915, +12521=>13916, +63378=>13916, +12522=>13917, +63379=>13917, +12523=>13918, +63380=>13918, +12524=>13919, +63381=>13919, +12525=>13920, +63382=>13920, +12526=>13921, +63383=>13921, +12527=>13922, +63384=>13922, +12528=>13923, +63385=>13923, +12529=>13924, +63386=>13924, +12530=>13925, +63387=>13925, +12531=>13926, +63388=>13926, +12532=>13927, +63389=>13927, +12533=>13928, +63390=>13928, +12534=>13929, +63391=>13929, +1040=>13930, +63392=>13930, +1041=>13931, +63393=>13931, +1042=>13932, +63394=>13932, +1043=>13933, +63395=>13933, +1044=>13934, +63396=>13934, +1045=>13935, +63397=>13935, +1025=>13936, +63398=>13936, +1046=>13937, +63399=>13937, +1047=>13938, +63400=>13938, +1048=>13939, +63401=>13939, +1049=>13940, +63402=>13940, +1050=>13941, +63403=>13941, +1051=>13942, +63404=>13942, +1052=>13943, +63405=>13943, +1053=>13944, +63406=>13944, +1054=>13945, +63407=>13945, +1055=>13946, +63408=>13946, +1056=>13947, +63409=>13947, +1057=>13948, +63410=>13948, +1058=>13949, +63411=>13949, +1059=>13950, +63412=>13950, +1060=>13951, +63413=>13951, +1061=>13952, +63414=>13952, +1062=>13953, +63415=>13953, +1063=>13954, +63416=>13954, +1064=>13955, +63417=>13955, +1065=>13956, +63418=>13956, +1066=>13957, +63419=>13957, +1067=>13958, +63420=>13958, +1068=>13959, +63421=>13959, +1069=>13960, +63422=>13960, +1070=>13961, +63423=>13961, +1071=>13962, +63424=>13962, +1072=>13963, +63425=>13963, +1073=>13964, +63426=>13964, +1074=>13965, +63427=>13965, +1075=>13966, +63428=>13966, +1076=>13967, +63429=>13967, +1077=>13968, +63430=>13968, +1105=>13969, +63431=>13969, +1078=>13970, +63432=>13970, +1079=>13971, +63433=>13971, +1080=>13972, +63434=>13972, +1081=>13973, +63435=>13973, +1082=>13974, +63436=>13974, +1083=>13975, +63437=>13975, +1084=>13976, +63438=>13976, +1085=>13977, +63439=>13977, +1086=>13978, +63440=>13978, +1087=>13979, +63441=>13979, +1088=>13980, +63442=>13980, +1089=>13981, +63443=>13981, +1090=>13982, +63444=>13982, +1091=>13983, +63445=>13983, +1092=>13984, +63446=>13984, +1093=>13985, +63447=>13985, +1094=>13986, +63448=>13986, +1095=>13987, +63449=>13987, +1096=>13988, +63450=>13988, +1097=>13989, +63451=>13989, +1098=>13990, +63452=>13990, +1099=>13991, +63453=>13991, +1100=>13992, +63454=>13992, +1101=>13993, +63455=>13993, +1102=>13994, +63456=>13994, +1103=>13995, +63457=>13995, +8679=>13996, +63458=>13996, +8632=>13997, +63459=>13997, +8633=>13998, +63460=>13998, +12751=>13999, +20033=>13999, +63461=>13999, +131276=>14000, +63462=>14000, +20058=>14001, +63463=>14001, +131210=>14002, +63464=>14002, +20994=>14003, +63465=>14003, +17553=>14004, +63466=>14004, +40880=>14005, +63467=>14005, +20872=>14006, +63468=>14006, +13853=>14007, +40881=>14007, +63469=>14007, +161287=>14008, +63470=>14008, +172=>14049, +65506=>14049, +63511=>14049, +65508=>14050, +63512=>14050, +65287=>14051, +63513=>14051, +65282=>14052, +63514=>14052, +12849=>14053, +63515=>14053, +8470=>14054, +63516=>14054, +8481=>14055, +63517=>14055, +30849=>14056, +37561=>14057, +58501=>14057, +35023=>14058, +22715=>14059, +24658=>14060, +31911=>14061, +23290=>14062, +9556=>14063, +9574=>14064, +9559=>14065, +9568=>14066, +9580=>14067, +9571=>14068, +9562=>14069, +9577=>14070, +9565=>14071, +9554=>14072, +9572=>14073, +9557=>14074, +9560=>14078, +9575=>14079, +9563=>14080, +9555=>14081, +9573=>14082, +9558=>14083, +9567=>14084, +9579=>14085, +9570=>14086, +9561=>14087, +9576=>14088, +9564=>14089, +9553=>14090, +9619=>14096, +65517=>14096, +65040=>14099, +65041=>14100, +65042=>14101, +65044=>14103, +65043=>14104, +65046=>14105, +65045=>14106, +147159=>14123, +58129=>14123, +22462=>14124, +58130=>14124, +159443=>14125, +58131=>14125, +28990=>14126, +58132=>14126, +153568=>14127, +58133=>14127, +27042=>14128, +58135=>14128, +166889=>14129, +58136=>14129, +23412=>14130, +58137=>14130, +31305=>14131, +58138=>14131, +153825=>14132, +58139=>14132, +169177=>14133, +58140=>14133, +31333=>14134, +58141=>14134, +31357=>14135, +58142=>14135, +154028=>14136, +58143=>14136, +31419=>14137, +58144=>14137, +31408=>14138, +58145=>14138, +31426=>14139, +58146=>14139, +31427=>14140, +58147=>14140, +29137=>14141, +58148=>14141, +156813=>14142, +58149=>14142, +16842=>14143, +58150=>14143, +31450=>14144, +58151=>14144, +31453=>14145, +58152=>14145, +31466=>14146, +58153=>14146, +16879=>14147, +58154=>14147, +21682=>14148, +58155=>14148, +154625=>14149, +58156=>14149, +31499=>14150, +58157=>14150, +31573=>14151, +58158=>14151, +31529=>14152, +58159=>14152, +152334=>14153, +58160=>14153, +154878=>14154, +58161=>14154, +31650=>14155, +58162=>14155, +31599=>14156, +58163=>14156, +33692=>14157, +58164=>14157, +154548=>14158, +58165=>14158, +158847=>14159, +58166=>14159, +31696=>14160, +58167=>14160, +33825=>14161, +58168=>14161, +31634=>14162, +58169=>14162, +58171=>14164, +154912=>14164, +33938=>14166, +58174=>14166, +31738=>14167, +58175=>14167, +31797=>14169, +58177=>14169, +154817=>14170, +58178=>14170, +31812=>14171, +58179=>14171, +31875=>14172, +58180=>14172, +149634=>14173, +58181=>14173, +31910=>14174, +58182=>14174, +148856=>14175, +58184=>14175, +31945=>14176, +58185=>14176, +31943=>14177, +58186=>14177, +31974=>14178, +58187=>14178, +31987=>14180, +58189=>14180, +31989=>14181, +58190=>14181, +32359=>14182, +58192=>14182, +17693=>14183, +58193=>14183, +159300=>14184, +58194=>14184, +32093=>14185, +58195=>14185, +159446=>14186, +58196=>14186, +32137=>14187, +58198=>14187, +32171=>14188, +58199=>14188, +28981=>14189, +58200=>14189, +32179=>14190, +58201=>14190, +32214=>14191, +147543=>14192, +58203=>14192, +155689=>14193, +58204=>14193, +32228=>14194, +58205=>14194, +15635=>14195, +58206=>14195, +32245=>14196, +58207=>14196, +137209=>14197, +58208=>14197, +32229=>14198, +58209=>14198, +164717=>14199, +58210=>14199, +155937=>14201, +58212=>14201, +155994=>14202, +58213=>14202, +32366=>14203, +58214=>14203, +17195=>14205, +58216=>14205, +37996=>14206, +58217=>14206, +32295=>14207, +58218=>14207, +32576=>14208, +58219=>14208, +32577=>14209, +58220=>14209, +32583=>14210, +58221=>14210, +31030=>14211, +58222=>14211, +156368=>14212, +58223=>14212, +39393=>14213, +58224=>14213, +32663=>14214, +58225=>14214, +156497=>14215, +58226=>14215, +32675=>14216, +58227=>14216, +136801=>14217, +58228=>14217, +131176=>14218, +58229=>14218, +17756=>14219, +58230=>14219, +145254=>14220, +58231=>14220, +164666=>14221, +58233=>14221, +32762=>14222, +58234=>14222, +156809=>14223, +58235=>14223, +64091=>14224, +32776=>14225, +58237=>14225, +32797=>14226, +58238=>14226, +32815=>14228, +58240=>14228, +172167=>14229, +58241=>14229, +158915=>14230, +58242=>14230, +32827=>14231, +58243=>14231, +32828=>14232, +58244=>14232, +32865=>14233, +58245=>14233, +141076=>14234, +58246=>14234, +18825=>14235, +58247=>14235, +157222=>14236, +58248=>14236, +146915=>14237, +58249=>14237, +157416=>14238, +58250=>14238, +26405=>14239, +58251=>14239, +32935=>14240, +58252=>14240, +166472=>14241, +58253=>14241, +33031=>14242, +58254=>14242, +33050=>14243, +58255=>14243, +22704=>14244, +58256=>14244, +141046=>14245, +58257=>14245, +27775=>14246, +58258=>14246, +156824=>14247, +58259=>14247, +25831=>14248, +58261=>14248, +136330=>14249, +58262=>14249, +33304=>14250, +58263=>14250, +137310=>14251, +58264=>14251, +27219=>14252, +58265=>14252, +150117=>14253, +58266=>14253, +150165=>14254, +58267=>14254, +17530=>14255, +58268=>14255, +33321=>14256, +58269=>14256, +158290=>14257, +58271=>14257, +146814=>14258, +58272=>14258, +20473=>14259, +58273=>14259, +136445=>14260, +58274=>14260, +34018=>14261, +58275=>14261, +33634=>14262, +58276=>14262, +194959=>14263, +149927=>14264, +58278=>14264, +144688=>14265, +58279=>14265, +137075=>14266, +58280=>14266, +146936=>14267, +58281=>14267, +33450=>14268, +58282=>14268, +26907=>14269, +58283=>14269, +194964=>14270, +58284=>14270, +16859=>14271, +58285=>14271, +34123=>14272, +58286=>14272, +33488=>14273, +58287=>14273, +33562=>14274, +58288=>14274, +134678=>14275, +58289=>14275, +137140=>14276, +58290=>14276, +14017=>14277, +58291=>14277, +143741=>14278, +58292=>14278, +144730=>14279, +58293=>14279, +33403=>14280, +58294=>14280, +33506=>14281, +58295=>14281, +33560=>14282, +58296=>14282, +147083=>14283, +58297=>14283, +159139=>14284, +58298=>14284, +158469=>14285, +58299=>14285, +158615=>14286, +58300=>14286, +144846=>14287, +58301=>14287, +15807=>14288, +58302=>14288, +33565=>14289, +58303=>14289, +21996=>14290, +58304=>14290, +33669=>14291, +58305=>14291, +17675=>14292, +58306=>14292, +159141=>14293, +58307=>14293, +33708=>14294, +58308=>14294, +33747=>14296, +58310=>14296, +159444=>14297, +58312=>14297, +27223=>14298, +58313=>14298, +34138=>14299, +58314=>14299, +13462=>14300, +58315=>14300, +159298=>14301, +58316=>14301, +33880=>14302, +58318=>14302, +154596=>14303, +58319=>14303, +33905=>14304, +58320=>14304, +15827=>14305, +58321=>14305, +17636=>14306, +58322=>14306, +27303=>14307, +58323=>14307, +33866=>14308, +58324=>14308, +31064=>14309, +58326=>14309, +158614=>14311, +58328=>14311, +159351=>14312, +58329=>14312, +159299=>14313, +58330=>14313, +34014=>14314, +58331=>14314, +33681=>14316, +58333=>14316, +17568=>14317, +58334=>14317, +33939=>14318, +58335=>14318, +34020=>14319, +58336=>14319, +154769=>14320, +58337=>14320, +16960=>14321, +58338=>14321, +154816=>14322, +58339=>14322, +17731=>14323, +58340=>14323, +34100=>14324, +58341=>14324, +23282=>14325, +58342=>14325, +17699=>14326, +17703=>14327, +58344=>14327, +34163=>14328, +58345=>14328, +17686=>14329, +58346=>14329, +26559=>14330, +58347=>14330, +34326=>14331, +58348=>14331, +165413=>14332, +58349=>14332, +165435=>14333, +58350=>14333, +34241=>14334, +58351=>14334, +159880=>14335, +58352=>14335, +34306=>14336, +58353=>14336, +136578=>14337, +58354=>14337, +159949=>14338, +58355=>14338, +194994=>14339, +58356=>14339, +17770=>14340, +58357=>14340, +34344=>14341, +58358=>14341, +13896=>14342, +58359=>14342, +137378=>14343, +58360=>14343, +21495=>14344, +58361=>14344, +160666=>14345, +58362=>14345, +34430=>14346, +58363=>14346, +172280=>14348, +58365=>14348, +34798=>14349, +58366=>14349, +142375=>14350, +58367=>14350, +34737=>14351, +58368=>14351, +34778=>14352, +58369=>14352, +34831=>14353, +60990=>14353, +58370=>14353, +22113=>14354, +58371=>14354, +34412=>14355, +58372=>14355, +26710=>14356, +58373=>14356, +17935=>14357, +58374=>14357, +34885=>14358, +58375=>14358, +34886=>14359, +58376=>14359, +161248=>14360, +58377=>14360, +146873=>14361, +58378=>14361, +161252=>14362, +58379=>14362, +34910=>14363, +58380=>14363, +34972=>14364, +58381=>14364, +18011=>14365, +58382=>14365, +34996=>14366, +58383=>14366, +34997=>14367, +58384=>14367, +35013=>14368, +58386=>14368, +161551=>14369, +58388=>14369, +35207=>14370, +58389=>14370, +35239=>14374, +58393=>14374, +35260=>14375, +58394=>14375, +166437=>14376, +58395=>14376, +35303=>14377, +58396=>14377, +162084=>14378, +58397=>14378, +162493=>14379, +58398=>14379, +35484=>14380, +58399=>14380, +30611=>14381, +58400=>14381, +37374=>14382, +58401=>14382, +35472=>14383, +58402=>14383, +162393=>14384, +58403=>14384, +31465=>14385, +58404=>14385, +162618=>14386, +58405=>14386, +18195=>14387, +58407=>14387, +162616=>14388, +58408=>14388, +29052=>14389, +58409=>14389, +35596=>14390, +58410=>14390, +35615=>14391, +58411=>14391, +152624=>14392, +58412=>14392, +152933=>14393, +58413=>14393, +35647=>14394, +58414=>14394, +35661=>14396, +58416=>14396, +35497=>14397, +58417=>14397, +150138=>14398, +58418=>14398, +35728=>14399, +58419=>14399, +35739=>14400, +58420=>14400, +35503=>14401, +58421=>14401, +136927=>14402, +58422=>14402, +17941=>14403, +58423=>14403, +34895=>14404, +58424=>14404, +35995=>14405, +58425=>14405, +163156=>14406, +58426=>14406, +163215=>14407, +58427=>14407, +195028=>14408, +58428=>14408, +14117=>14409, +58429=>14409, +163155=>14410, +58430=>14410, +36054=>14411, +58431=>14411, +163224=>14412, +58432=>14412, +163261=>14413, +58433=>14413, +36114=>14414, +58434=>14414, +36099=>14415, +58435=>14415, +137488=>14416, +58436=>14416, +36059=>14417, +58437=>14417, +28764=>14418, +58438=>14418, +36113=>14419, +58439=>14419, +16080=>14420, +58441=>14420, +195031=>14421, +36265=>14422, +58443=>14422, +163842=>14423, +58444=>14423, +135188=>14424, +58445=>14424, +149898=>14425, +58446=>14425, +15228=>14426, +58447=>14426, +164284=>14427, +58448=>14427, +160012=>14428, +58449=>14428, +31463=>14429, +58450=>14429, +36525=>14430, +58451=>14430, +36534=>14431, +58452=>14431, +36547=>14432, +58453=>14432, +37588=>14433, +58454=>14433, +36633=>14434, +58455=>14434, +36653=>14435, +58456=>14435, +164709=>14436, +58457=>14436, +164882=>14437, +58458=>14437, +36773=>14438, +58459=>14438, +37635=>14439, +58460=>14439, +172703=>14440, +58461=>14440, +133712=>14441, +58462=>14441, +36787=>14442, +58463=>14442, +166366=>14444, +58465=>14444, +165181=>14445, +58466=>14445, +146875=>14446, +58467=>14446, +24312=>14447, +58468=>14447, +143970=>14448, +58469=>14448, +36857=>14449, +58470=>14449, +140069=>14451, +58474=>14451, +14720=>14452, +58475=>14452, +159447=>14453, +58476=>14453, +36919=>14454, +58477=>14454, +165180=>14455, +58478=>14455, +162494=>14456, +58479=>14456, +36961=>14457, +58480=>14457, +165228=>14458, +58481=>14458, +165387=>14459, +58482=>14459, +37032=>14460, +58483=>14460, +165651=>14461, +58484=>14461, +37060=>14462, +58485=>14462, +165606=>14463, +58486=>14463, +37038=>14464, +58487=>14464, +64038=>14465, +37223=>14466, +58489=>14466, +37289=>14467, +58491=>14467, +37316=>14468, +58492=>14468, +31916=>14469, +58493=>14469, +166195=>14470, +58494=>14470, +138889=>14471, +58495=>14471, +37390=>14472, +58496=>14472, +27807=>14473, +58497=>14473, +37441=>14474, +58498=>14474, +37474=>14475, +58499=>14475, +153017=>14476, +58500=>14476, +166598=>14477, +58502=>14477, +146587=>14478, +58503=>14478, +166668=>14479, +58504=>14479, +153051=>14480, +58505=>14480, +134449=>14481, +58506=>14481, +37676=>14482, +58507=>14482, +37739=>14483, +58508=>14483, +166625=>14484, +58509=>14484, +166891=>14485, +58510=>14485, +23235=>14486, +58512=>14486, +166626=>14487, +58513=>14487, +166629=>14488, +58514=>14488, +18789=>14489, +58515=>14489, +37444=>14490, +58516=>14490, +166892=>14491, +58517=>14491, +166969=>14492, +58518=>14492, +166911=>14493, +58519=>14493, +37747=>14494, +58520=>14494, +37979=>14495, +58521=>14495, +36540=>14496, +58522=>14496, +38277=>14497, +58523=>14497, +38310=>14498, +58524=>14498, +37926=>14499, +58525=>14499, +38304=>14500, +58526=>14500, +28662=>14501, +58527=>14501, +17081=>14502, +58528=>14502, +165592=>14503, +58530=>14503, +135804=>14504, +58531=>14504, +146990=>14505, +58532=>14505, +18911=>14506, +58533=>14506, +27676=>14507, +58534=>14507, +38523=>14508, +58535=>14508, +38550=>14509, +58536=>14509, +16748=>14510, +58537=>14510, +38563=>14511, +58538=>14511, +159445=>14512, +58539=>14512, +25050=>14513, +58540=>14513, +58541=>14514, +30965=>14515, +58542=>14515, +166624=>14516, +58543=>14516, +38589=>14517, +58544=>14517, +21452=>14518, +58545=>14518, +18849=>14519, +58546=>14519, +158904=>14520, +58547=>14520, +131700=>14521, +58548=>14521, +156688=>14522, +58549=>14522, +168111=>14523, +58550=>14523, +168165=>14524, +58551=>14524, +150225=>14525, +58552=>14525, +137493=>14526, +58553=>14526, +144138=>14527, +58554=>14527, +38705=>14528, +58555=>14528, +34370=>14529, +58556=>14529, +38710=>14530, +58557=>14530, +18959=>14531, +58558=>14531, +17725=>14532, +58559=>14532, +17797=>14533, +58560=>14533, +150249=>14534, +58561=>14534, +28789=>14535, +58562=>14535, +23361=>14536, +58563=>14536, +38683=>14537, +58564=>14537, +168405=>14539, +58566=>14539, +38743=>14540, +58567=>14540, +23370=>14541, +58568=>14541, +168427=>14542, +58569=>14542, +38751=>14543, +58570=>14543, +37925=>14544, +58571=>14544, +20688=>14545, +58572=>14545, +143543=>14546, +58573=>14546, +143548=>14547, +58574=>14547, +38793=>14548, +58575=>14548, +38815=>14549, +58576=>14549, +38833=>14550, +58577=>14550, +38846=>14551, +58578=>14551, +38848=>14552, +58579=>14552, +38866=>14553, +58580=>14553, +38880=>14554, +58581=>14554, +152684=>14555, +58582=>14555, +38894=>14556, +58583=>14556, +29724=>14557, +58584=>14557, +169011=>14558, +58585=>14558, +38901=>14560, +58587=>14560, +168989=>14561, +58588=>14561, +162170=>14562, +58589=>14562, +19153=>14563, +58590=>14563, +38964=>14564, +58591=>14564, +38963=>14565, +58592=>14565, +38987=>14566, +58593=>14566, +39014=>14567, +58594=>14567, +15118=>14568, +58595=>14568, +160117=>14569, +58596=>14569, +15697=>14570, +58597=>14570, +132656=>14571, +58598=>14571, +147804=>14572, +58599=>14572, +153350=>14573, +58600=>14573, +39114=>14574, +58601=>14574, +39095=>14575, +58602=>14575, +39112=>14576, +58603=>14576, +39111=>14577, +58604=>14577, +19199=>14578, +58605=>14578, +159015=>14579, +58606=>14579, +136915=>14580, +58607=>14580, +21936=>14581, +58608=>14581, +39137=>14582, +58609=>14582, +39142=>14583, +58610=>14583, +39148=>14584, +58611=>14584, +37752=>14585, +58612=>14585, +39225=>14586, +58613=>14586, +150057=>14587, +58614=>14587, +19314=>14588, +58615=>14588, +170071=>14589, +58616=>14589, +170245=>14590, +58617=>14590, +39413=>14591, +58618=>14591, +39436=>14592, +58619=>14592, +39483=>14593, +58620=>14593, +39440=>14594, +58621=>14594, +39512=>14595, +58622=>14595, +153381=>14596, +58623=>14596, +14020=>14597, +58624=>14597, +168113=>14598, +58625=>14598, +170965=>14599, +58626=>14599, +39648=>14600, +58627=>14600, +39650=>14601, +58628=>14601, +170757=>14602, +58629=>14602, +39668=>14603, +58630=>14603, +19470=>14604, +58631=>14604, +39700=>14605, +58632=>14605, +39725=>14606, +58633=>14606, +165376=>14607, +58634=>14607, +20532=>14608, +58635=>14608, +39732=>14609, +58636=>14609, +14531=>14610, +58638=>14610, +143485=>14611, +58639=>14611, +39760=>14612, +58640=>14612, +39744=>14613, +58641=>14613, +171326=>14614, +58642=>14614, +23109=>14615, +58643=>14615, +137315=>14616, +58644=>14616, +39822=>14617, +58645=>14617, +39938=>14618, +58647=>14618, +39935=>14619, +58648=>14619, +39948=>14620, +58649=>14620, +171624=>14621, +58650=>14621, +40404=>14622, +58651=>14622, +171959=>14623, +58652=>14623, +172434=>14624, +58653=>14624, +172459=>14625, +58654=>14625, +172257=>14626, +58655=>14626, +172323=>14627, +58656=>14627, +172511=>14628, +58657=>14628, +40318=>14629, +58658=>14629, +40323=>14630, +58659=>14630, +172340=>14631, +58660=>14631, +40462=>14632, +58661=>14632, +40388=>14633, +58663=>14633, +172435=>14634, +58665=>14634, +172576=>14635, +58666=>14635, +137531=>14636, +58667=>14636, +172595=>14637, +58668=>14637, +40249=>14638, +58669=>14638, +172217=>14639, +58670=>14639, +172724=>14640, +58671=>14640, +40592=>14641, +58672=>14641, +40597=>14642, +58673=>14642, +40606=>14643, +58674=>14643, +40610=>14644, +58675=>14644, +19764=>14645, +58676=>14645, +40618=>14646, +58677=>14646, +40623=>14647, +58678=>14647, +148324=>14648, +58679=>14648, +40641=>14649, +58680=>14649, +15200=>14650, +58681=>14650, +14821=>14651, +58682=>14651, +15645=>14652, +58683=>14652, +20274=>14653, +58684=>14653, +14270=>14654, +58685=>14654, +166955=>14655, +58686=>14655, +40706=>14656, +58687=>14656, +40712=>14657, +58688=>14657, +19350=>14658, +58689=>14658, +37924=>14659, +58690=>14659, +159138=>14660, +58691=>14660, +40727=>14661, +60836=>14661, +58692=>14661, +195099=>14662, +40761=>14663, +58694=>14663, +22175=>14664, +58695=>14664, +22154=>14665, +58696=>14665, +40773=>14666, +58697=>14666, +39352=>14667, +58698=>14667, +168075=>14668, +58699=>14668, +38898=>14669, +58700=>14669, +33919=>14670, +58701=>14670, +40809=>14672, +58703=>14672, +31452=>14673, +58704=>14673, +40846=>14674, +58705=>14674, +29206=>14675, +58706=>14675, +19390=>14676, +58707=>14676, +149877=>14677, +58708=>14677, +149947=>14678, +58709=>14678, +29047=>14679, +58710=>14679, +150008=>14680, +58711=>14680, +148296=>14681, +58712=>14681, +150097=>14682, +58713=>14682, +29598=>14683, +58714=>14683, +166874=>14684, +58715=>14684, +137466=>14685, +58716=>14685, +31135=>14686, +58717=>14686, +166270=>14687, +58718=>14687, +167478=>14688, +58719=>14688, +37737=>14689, +58720=>14689, +37875=>14690, +58721=>14690, +166468=>14691, +58722=>14691, +37612=>14692, +58723=>14692, +37761=>14693, +58724=>14693, +37835=>14694, +58725=>14694, +166252=>14695, +58726=>14695, +148665=>14696, +58727=>14696, +29207=>14697, +58728=>14697, +16107=>14698, +58729=>14698, +30578=>14699, +58730=>14699, +31299=>14700, +58731=>14700, +28880=>14701, +58732=>14701, +148595=>14702, +58733=>14702, +148472=>14703, +58734=>14703, +29054=>14704, +58735=>14704, +137199=>14705, +58736=>14705, +28835=>14706, +58737=>14706, +137406=>14707, +58738=>14707, +144793=>14708, +58739=>14708, +16071=>14709, +58740=>14709, +137349=>14710, +58741=>14710, +152623=>14711, +58742=>14711, +137208=>14712, +58743=>14712, +14114=>14713, +58744=>14713, +136955=>14714, +58745=>14714, +137273=>14715, +58746=>14715, +14049=>14716, +58747=>14716, +137076=>14717, +58748=>14717, +137425=>14718, +58749=>14718, +155467=>14719, +58750=>14719, +14115=>14720, +58751=>14720, +136896=>14721, +58752=>14721, +22363=>14722, +58753=>14722, +150053=>14723, +58754=>14723, +136190=>14724, +58755=>14724, +135848=>14725, +58756=>14725, +136134=>14726, +58757=>14726, +136374=>14727, +58758=>14727, +34051=>14728, +58761=>14728, +58759=>14728, +145062=>14729, +58760=>14729, +33877=>14731, +58762=>14731, +149908=>14732, +58763=>14732, +160101=>14733, +58764=>14733, +146993=>14734, +58765=>14734, +152924=>14735, +58766=>14735, +147195=>14736, +58767=>14736, +159826=>14737, +58768=>14737, +17652=>14738, +58769=>14738, +145134=>14739, +58770=>14739, +170397=>14740, +58771=>14740, +159526=>14741, +58772=>14741, +26617=>14742, +58773=>14742, +14131=>14743, +58774=>14743, +15381=>14744, +58775=>14744, +15847=>14745, +58776=>14745, +22636=>14746, +58777=>14746, +137506=>14747, +58778=>14747, +26640=>14748, +58779=>14748, +16471=>14749, +58780=>14749, +145215=>14750, +58781=>14750, +147681=>14751, +58782=>14751, +147595=>14752, +58783=>14752, +147727=>14753, +58784=>14753, +158753=>14754, +58785=>14754, +21707=>14755, +58786=>14755, +22174=>14756, +58787=>14756, +157361=>14757, +58788=>14757, +22162=>14758, +58789=>14758, +135135=>14759, +58790=>14759, +134056=>14760, +58791=>14760, +134669=>14761, +58792=>14761, +166675=>14763, +58794=>14763, +37788=>14764, +58795=>14764, +20216=>14765, +58796=>14765, +20779=>14766, +58797=>14766, +14361=>14767, +58798=>14767, +148534=>14768, +58799=>14768, +20156=>14769, +58800=>14769, +132197=>14770, +58801=>14770, +20299=>14772, +58803=>14772, +20362=>14773, +58804=>14773, +153169=>14774, +58805=>14774, +23144=>14775, +58806=>14775, +131499=>14776, +58807=>14776, +132043=>14777, +58808=>14777, +14745=>14778, +58809=>14778, +131850=>14779, +58810=>14779, +132116=>14780, +58811=>14780, +13365=>14781, +58812=>14781, +20265=>14782, +58813=>14782, +131776=>14783, +58814=>14783, +167603=>14784, +58815=>14784, +131701=>14785, +58816=>14785, +35546=>14786, +58817=>14786, +131596=>14787, +58818=>14787, +20120=>14788, +58819=>14788, +20685=>14789, +58820=>14789, +20749=>14790, +58821=>14790, +20386=>14791, +58822=>14791, +20227=>14792, +58823=>14792, +150030=>14793, +58824=>14793, +147082=>14794, +58825=>14794, +20290=>14795, +58826=>14795, +20526=>14796, +58827=>14796, +20588=>14797, +58828=>14797, +20609=>14798, +58829=>14798, +20428=>14799, +58830=>14799, +20453=>14800, +58831=>14800, +20568=>14801, +58832=>14801, +20732=>14802, +58833=>14802, +28278=>14803, +58838=>14803, +144789=>14804, +58839=>14804, +147001=>14805, +58840=>14805, +147135=>14806, +58841=>14806, +28018=>14807, +58842=>14807, +137348=>14808, +58843=>14808, +147081=>14809, +58844=>14809, +20904=>14810, +58845=>14810, +20931=>14811, +58846=>14811, +132576=>14812, +58847=>14812, +17629=>14813, +58848=>14813, +132259=>14814, +58849=>14814, +132242=>14815, +58850=>14815, +132241=>14816, +58851=>14816, +36218=>14817, +58852=>14817, +166556=>14818, +58853=>14818, +132878=>14819, +58854=>14819, +21081=>14820, +58855=>14820, +21156=>14821, +58856=>14821, +133235=>14822, +58857=>14822, +21217=>14823, +58858=>14823, +18042=>14825, +58860=>14825, +29068=>14826, +58861=>14826, +148364=>14827, +58862=>14827, +134176=>14828, +58863=>14828, +149932=>14829, +58864=>14829, +135396=>14830, +58865=>14830, +27089=>14831, +58866=>14831, +134685=>14832, +58867=>14832, +16094=>14834, +58869=>14834, +29849=>14835, +58870=>14835, +29716=>14836, +58871=>14836, +29782=>14837, +58872=>14837, +29592=>14838, +58873=>14838, +19342=>14839, +58874=>14839, +150204=>14840, +58875=>14840, +147597=>14841, +58876=>14841, +21456=>14842, +58877=>14842, +13700=>14843, +58878=>14843, +29199=>14844, +58879=>14844, +147657=>14845, +58880=>14845, +21940=>14846, +58881=>14846, +131909=>14847, +58882=>14847, +21709=>14848, +58883=>14848, +134086=>14849, +58884=>14849, +22301=>14850, +58885=>14850, +37469=>14851, +58886=>14851, +38644=>14852, +58887=>14852, +22493=>14853, +58889=>14853, +22413=>14854, +58890=>14854, +22399=>14855, +58891=>14855, +13886=>14856, +58892=>14856, +22731=>14857, +58893=>14857, +23193=>14858, +58894=>14858, +166470=>14859, +58895=>14859, +136954=>14860, +58896=>14860, +137071=>14861, +58897=>14861, +136976=>14862, +58898=>14862, +23084=>14863, +58899=>14863, +22968=>14864, +58900=>14864, +23166=>14865, +58902=>14865, +23247=>14866, +58903=>14866, +23058=>14867, +58904=>14867, +153926=>14868, +58905=>14868, +137715=>14869, +58906=>14869, +137313=>14870, +58907=>14870, +148117=>14871, +58908=>14871, +14069=>14872, +58909=>14872, +27909=>14873, +58910=>14873, +29763=>14874, +58911=>14874, +23073=>14875, +58912=>14875, +155267=>14876, +58913=>14876, +23169=>14877, +58914=>14877, +166871=>14878, +58915=>14878, +132115=>14879, +58916=>14879, +37856=>14880, +58917=>14880, +29836=>14881, +58918=>14881, +135939=>14882, +58919=>14882, +28933=>14883, +58920=>14883, +18802=>14884, +58921=>14884, +37896=>14885, +58922=>14885, +166395=>14886, +58923=>14886, +37821=>14887, +58924=>14887, +14240=>14888, +58925=>14888, +23582=>14889, +58926=>14889, +23710=>14890, +58927=>14890, +24158=>14891, +58928=>14891, +24136=>14892, +58929=>14892, +137622=>14893, +58930=>14893, +137596=>14894, +58931=>14894, +146158=>14895, +58932=>14895, +24269=>14896, +58933=>14896, +23375=>14897, +58934=>14897, +58935=>14898, +137475=>14898, +58936=>14899, +137476=>14899, +14081=>14900, +58937=>14900, +137376=>14901, +58938=>14901, +14045=>14902, +58939=>14902, +136958=>14903, +58940=>14903, +14035=>14904, +58941=>14904, +33066=>14905, +58942=>14905, +166471=>14906, +58943=>14906, +138682=>14907, +58944=>14907, +144498=>14908, +58945=>14908, +166312=>14909, +58946=>14909, +24332=>14910, +60916=>14910, +58947=>14910, +24334=>14911, +58948=>14911, +137511=>14912, +58949=>14912, +137131=>14913, +58950=>14913, +23147=>14914, +58951=>14914, +137019=>14915, +58952=>14915, +23364=>14916, +58953=>14916, +161277=>14917, +58955=>14917, +34912=>14918, +58956=>14918, +24702=>14919, +58957=>14919, +141408=>14920, +58958=>14920, +140843=>14921, +58959=>14921, +24539=>14922, +58960=>14922, +16056=>14923, +58961=>14923, +140719=>14924, +58962=>14924, +140734=>14925, +58963=>14925, +168072=>14926, +58964=>14926, +159603=>14927, +58965=>14927, +25024=>14928, +58966=>14928, +131134=>14929, +58967=>14929, +131142=>14930, +58968=>14930, +140827=>14931, +58969=>14931, +24985=>14932, +58970=>14932, +24984=>14933, +58971=>14933, +24693=>14934, +58972=>14934, +142491=>14935, +58973=>14935, +142599=>14936, +58974=>14936, +149204=>14937, +58975=>14937, +168269=>14938, +58976=>14938, +25713=>14939, +58977=>14939, +149093=>14940, +58978=>14940, +142186=>14941, +58979=>14941, +14889=>14942, +58980=>14942, +142114=>14943, +58981=>14943, +144464=>14944, +58982=>14944, +170218=>14945, +58983=>14945, +142968=>14946, +58984=>14946, +25399=>14947, +58985=>14947, +25782=>14948, +58987=>14948, +25393=>14949, +58988=>14949, +25553=>14950, +58989=>14950, +149987=>14951, +58990=>14951, +142695=>14952, +58991=>14952, +25252=>14953, +58992=>14953, +142497=>14954, +58993=>14954, +25659=>14955, +58994=>14955, +25963=>14956, +58995=>14956, +26994=>14957, +58996=>14957, +15348=>14958, +58997=>14958, +143502=>14959, +58998=>14959, +144045=>14960, +58999=>14960, +149897=>14961, +59000=>14961, +144043=>14962, +59001=>14962, +21773=>14963, +59002=>14963, +144096=>14964, +59003=>14964, +137433=>14965, +59004=>14965, +169023=>14966, +59005=>14966, +26318=>14967, +59006=>14967, +144009=>14968, +59007=>14968, +143795=>14969, +59008=>14969, +15072=>14970, +59009=>14970, +152964=>14971, +59011=>14971, +166690=>14972, +59012=>14972, +152975=>14973, +59013=>14973, +136956=>14974, +59014=>14974, +152923=>14975, +59015=>14975, +152613=>14976, +59016=>14976, +30958=>14977, +59017=>14977, +143619=>14978, +59018=>14978, +137258=>14979, +59019=>14979, +143924=>14980, +59020=>14980, +13412=>14981, +59021=>14981, +143887=>14982, +59022=>14982, +143746=>14983, +59023=>14983, +148169=>14984, +59024=>14984, +26254=>14985, +59025=>14985, +159012=>14986, +59026=>14986, +26219=>14987, +59027=>14987, +19347=>14988, +59028=>14988, +26160=>14989, +59029=>14989, +161904=>14990, +59030=>14990, +138731=>14991, +59031=>14991, +26211=>14992, +59032=>14992, +144082=>14993, +59033=>14993, +144097=>14994, +59034=>14994, +26142=>14995, +59035=>14995, +153714=>14996, +59036=>14996, +14545=>14997, +59037=>14997, +145466=>14998, +59038=>14998, +145340=>14999, +59039=>14999, +15257=>15000, +59040=>15000, +145314=>15001, +59041=>15001, +144382=>15002, +59042=>15002, +29904=>15003, +59043=>15003, +15254=>15004, +59044=>15004, +149034=>15005, +59046=>15005, +26806=>15006, +59047=>15006, +15300=>15008, +59049=>15008, +27326=>15009, +59050=>15009, +145365=>15010, +59052=>15010, +148615=>15011, +59053=>15011, +27187=>15012, +59054=>15012, +27218=>15013, +59055=>15013, +27337=>15014, +59056=>15014, +27397=>15015, +59057=>15015, +137490=>15016, +59058=>15016, +25873=>15017, +59059=>15017, +26776=>15018, +59060=>15018, +27212=>15019, +59061=>15019, +15319=>15020, +59062=>15020, +27258=>15021, +59063=>15021, +27479=>15022, +59064=>15022, +147392=>15023, +59065=>15023, +146586=>15024, +59066=>15024, +37792=>15025, +59067=>15025, +37618=>15026, +59068=>15026, +166890=>15027, +59069=>15027, +166603=>15028, +59070=>15028, +37513=>15029, +59071=>15029, +163870=>15030, +59072=>15030, +166364=>15031, +59073=>15031, +37991=>15032, +59074=>15032, +28069=>15033, +59075=>15033, +28427=>15034, +59076=>15034, +147327=>15036, +59079=>15036, +15759=>15037, +59080=>15037, +28164=>15038, +59081=>15038, +147516=>15039, +59082=>15039, +23101=>15040, +59083=>15040, +28170=>15041, +59084=>15041, +22599=>15042, +59085=>15042, +27940=>15043, +59086=>15043, +30786=>15044, +59087=>15044, +28987=>15045, +59088=>15045, +148250=>15046, +59089=>15046, +148086=>15047, +59090=>15047, +28913=>15048, +59091=>15048, +29264=>15049, +61085=>15049, +59092=>15049, +29319=>15050, +59093=>15050, +29332=>15051, +59094=>15051, +149391=>15052, +59095=>15052, +149285=>15053, +59096=>15053, +20857=>15054, +59097=>15054, +150180=>15055, +59098=>15055, +132587=>15056, +59099=>15056, +29818=>15057, +59100=>15057, +147192=>15058, +59101=>15058, +144991=>15059, +59102=>15059, +150090=>15060, +59103=>15060, +149783=>15061, +59104=>15061, +155617=>15062, +59105=>15062, +16134=>15063, +59106=>15063, +16049=>15064, +59107=>15064, +150239=>15065, +59108=>15065, +166947=>15066, +59109=>15066, +147253=>15067, +59110=>15067, +24743=>15068, +59111=>15068, +16115=>15069, +59112=>15069, +29900=>15070, +59113=>15070, +29756=>15071, +59114=>15071, +37767=>15072, +59115=>15072, +29751=>15073, +59116=>15073, +17567=>15074, +59117=>15074, +159210=>15075, +59118=>15075, +17745=>15076, +59119=>15076, +30083=>15077, +59120=>15077, +16227=>15078, +59121=>15078, +150745=>15079, +59122=>15079, +150790=>15080, +59123=>15080, +16216=>15081, +59124=>15081, +30037=>15082, +59125=>15082, +30323=>15083, +59126=>15083, +173510=>15084, +59127=>15084, +29800=>15086, +61070=>15086, +59129=>15086, +166604=>15087, +59130=>15087, +149931=>15088, +59131=>15088, +149902=>15089, +59132=>15089, +15099=>15090, +59133=>15090, +15821=>15091, +59134=>15091, +150094=>15092, +59135=>15092, +16127=>15093, +59136=>15093, +149957=>15094, +59137=>15094, +149747=>15095, +59138=>15095, +37370=>15096, +59139=>15096, +22322=>15097, +59140=>15097, +37698=>15098, +59141=>15098, +166627=>15099, +59142=>15099, +137316=>15100, +59143=>15100, +20703=>15101, +59144=>15101, +152097=>15102, +59145=>15102, +152039=>15103, +59146=>15103, +30584=>15104, +59147=>15104, +143922=>15105, +59148=>15105, +30478=>15106, +59149=>15106, +30479=>15107, +59150=>15107, +30587=>15108, +59151=>15108, +149143=>15109, +59152=>15109, +145281=>15110, +59153=>15110, +14942=>15111, +59154=>15111, +149744=>15112, +59155=>15112, +29752=>15113, +59156=>15113, +29851=>15114, +59157=>15114, +16063=>15115, +59158=>15115, +150202=>15116, +59159=>15116, +150215=>15117, +59160=>15117, +16584=>15118, +59161=>15118, +150166=>15119, +59162=>15119, +156078=>15120, +59163=>15120, +37639=>15121, +59164=>15121, +152961=>15122, +59165=>15122, +30750=>15123, +59166=>15123, +30861=>15124, +59167=>15124, +30856=>15125, +59168=>15125, +30930=>15126, +59169=>15126, +29648=>15127, +59170=>15127, +31065=>15128, +59171=>15128, +161601=>15129, +59172=>15129, +153315=>15130, +59173=>15130, +16654=>15131, +59174=>15131, +31141=>15134, +59177=>15134, +27181=>15135, +59178=>15135, +147194=>15136, +59179=>15136, +31290=>15137, +59180=>15137, +31220=>15138, +59181=>15138, +16750=>15139, +59182=>15139, +136934=>15140, +59183=>15140, +16690=>15141, +59184=>15141, +37429=>15142, +59185=>15142, +31217=>15143, +59186=>15143, +134476=>15144, +59187=>15144, +149900=>15145, +59188=>15145, +131737=>15146, +59189=>15146, +146874=>15147, +59190=>15147, +137070=>15148, +59191=>15148, +13719=>15149, +59192=>15149, +21867=>15150, +59193=>15150, +13680=>15151, +59194=>15151, +13994=>15152, +59195=>15152, +131540=>15153, +59196=>15153, +134157=>15154, +59197=>15154, +31458=>15155, +59198=>15155, +23129=>15156, +59199=>15156, +141045=>15157, +59200=>15157, +154287=>15158, +59201=>15158, +154268=>15159, +59202=>15159, +23053=>15160, +59203=>15160, +131675=>15161, +59204=>15161, +30960=>15162, +59205=>15162, +23082=>15163, +59206=>15163, +154566=>15164, +59207=>15164, +31486=>15165, +59208=>15165, +16889=>15166, +59209=>15166, +31837=>15167, +59210=>15167, +31853=>15168, +59211=>15168, +16913=>15169, +59212=>15169, +154547=>15170, +59213=>15170, +155324=>15171, +59214=>15171, +155302=>15172, +59215=>15172, +31949=>15173, +59216=>15173, +150009=>15174, +59217=>15174, +137136=>15175, +59218=>15175, +31886=>15176, +59219=>15176, +31868=>15177, +59220=>15177, +31918=>15178, +59221=>15178, +27314=>15179, +59222=>15179, +32220=>15180, +59223=>15180, +32263=>15181, +59224=>15181, +32211=>15182, +59225=>15182, +32590=>15183, +59226=>15183, +156257=>15184, +59227=>15184, +155996=>15185, +59228=>15185, +162632=>15186, +59229=>15186, +32151=>15187, +59230=>15187, +155266=>15188, +59231=>15188, +17002=>15189, +59232=>15189, +158581=>15190, +59233=>15190, +133398=>15191, +59234=>15191, +26582=>15192, +59235=>15192, +131150=>15193, +59236=>15193, +144847=>15194, +59237=>15194, +22468=>15195, +59238=>15195, +156690=>15196, +59239=>15196, +156664=>15197, +59240=>15197, +32733=>15198, +59242=>15198, +31527=>15199, +59243=>15199, +133164=>15200, +59244=>15200, +154345=>15201, +59245=>15201, +154947=>15202, +59246=>15202, +31500=>15203, +59247=>15203, +155150=>15204, +59248=>15204, +39398=>15205, +59249=>15205, +34373=>15206, +59250=>15206, +39523=>15207, +59251=>15207, +27164=>15208, +59252=>15208, +144447=>15209, +59253=>15209, +150007=>15210, +59255=>15210, +157101=>15211, +59256=>15211, +39455=>15212, +59257=>15212, +157088=>15213, +59258=>15213, +33941=>15214, +160039=>15215, +59260=>15215, +158929=>15216, +59261=>15216, +17642=>15217, +59262=>15217, +33079=>15218, +59263=>15218, +17410=>15219, +59264=>15219, +32966=>15220, +59265=>15220, +33033=>15221, +59266=>15221, +33090=>15222, +59267=>15222, +157620=>15223, +59268=>15223, +39107=>15224, +59269=>15224, +158274=>15225, +59270=>15225, +33378=>15226, +59271=>15226, +33381=>15227, +59272=>15227, +158289=>15228, +59273=>15228, +33875=>15229, +59274=>15229, +159143=>15230, +59275=>15230, +34320=>15231, +59276=>15231, +160283=>15232, +59277=>15232, +23174=>15233, +59278=>15233, +16767=>15234, +59279=>15234, +137280=>15235, +59280=>15235, +23339=>15236, +59281=>15236, +137377=>15237, +59282=>15237, +23268=>15238, +59283=>15238, +137432=>15239, +59284=>15239, +34464=>15240, +59285=>15240, +195004=>15241, +59286=>15241, +146831=>15242, +59287=>15242, +34861=>15243, +59288=>15243, +160802=>15244, +59289=>15244, +23042=>15245, +59290=>15245, +34926=>15246, +59291=>15246, +20293=>15247, +59292=>15247, +34951=>15248, +59293=>15248, +35007=>15249, +59294=>15249, +35046=>15250, +59295=>15250, +35173=>15251, +59296=>15251, +35149=>15252, +59297=>15252, +153219=>15253, +59298=>15253, +35156=>15254, +59299=>15254, +161669=>15255, +59300=>15255, +161668=>15256, +59301=>15256, +166901=>15257, +59302=>15257, +166873=>15258, +59303=>15258, +166812=>15259, +59304=>15259, +166393=>15260, +59305=>15260, +16045=>15261, +59306=>15261, +33955=>15262, +59307=>15262, +18165=>15263, +59308=>15263, +18127=>15264, +59309=>15264, +14322=>15265, +59310=>15265, +35389=>15266, +59311=>15266, +35356=>15267, +59312=>15267, +169032=>15268, +59313=>15268, +24397=>15269, +59314=>15269, +37419=>15270, +59315=>15270, +148100=>15271, +59316=>15271, +26068=>15272, +59317=>15272, +28969=>15273, +59318=>15273, +28868=>15274, +59319=>15274, +137285=>15275, +59320=>15275, +40301=>15276, +59321=>15276, +35999=>15277, +59322=>15277, +36073=>15278, +59323=>15278, +163292=>15279, +59324=>15279, +22938=>15280, +59325=>15280, +30659=>15281, +59326=>15281, +23024=>15282, +59327=>15282, +14036=>15283, +59329=>15283, +36394=>15284, +59330=>15284, +36519=>15285, +59331=>15285, +150537=>15286, +59332=>15286, +36656=>15287, +59333=>15287, +36682=>15288, +59334=>15288, +17140=>15289, +59335=>15289, +27736=>15290, +59336=>15290, +28603=>15291, +59337=>15291, +140065=>15292, +59338=>15292, +18587=>15293, +59339=>15293, +28537=>15294, +59340=>15294, +28299=>15295, +59341=>15295, +137178=>15296, +59342=>15296, +39913=>15297, +59343=>15297, +14005=>15298, +59344=>15298, +149807=>15299, +59345=>15299, +37051=>15300, +59346=>15300, +18612=>15301, +21873=>15302, +59348=>15302, +18694=>15303, +59349=>15303, +37307=>15304, +59350=>15304, +37892=>15305, +59351=>15305, +166475=>15306, +59352=>15306, +16482=>15307, +59353=>15307, +166652=>15308, +59354=>15308, +37927=>15309, +59355=>15309, +166941=>15310, +59356=>15310, +166971=>15311, +59357=>15311, +34021=>15312, +59358=>15312, +35371=>15313, +59359=>15313, +38297=>15314, +59360=>15314, +38311=>15315, +59361=>15315, +38295=>15316, +59362=>15316, +38294=>15317, +59363=>15317, +167220=>15318, +59364=>15318, +29765=>15319, +59365=>15319, +16066=>15320, +59366=>15320, +149759=>15321, +59367=>15321, +150082=>15322, +59368=>15322, +148458=>15323, +59369=>15323, +16103=>15324, +59370=>15324, +143909=>15325, +59371=>15325, +38543=>15326, +59372=>15326, +167655=>15327, +59373=>15327, +167526=>15328, +59374=>15328, +167525=>15329, +59375=>15329, +16076=>15330, +59376=>15330, +149997=>15331, +59377=>15331, +150136=>15332, +59378=>15332, +147438=>15333, +59379=>15333, +29714=>15334, +59380=>15334, +29803=>15335, +59381=>15335, +16124=>15336, +59382=>15336, +38721=>15337, +59383=>15337, +168112=>15338, +59384=>15338, +26695=>15339, +59385=>15339, +18973=>15340, +59386=>15340, +168083=>15341, +59387=>15341, +153567=>15342, +59388=>15342, +37736=>15344, +59390=>15344, +166281=>15345, +59391=>15345, +166950=>15346, +59392=>15346, +166703=>15347, +59393=>15347, +156606=>15348, +59394=>15348, +37562=>15349, +59395=>15349, +23313=>15350, +59396=>15350, +35689=>15351, +59397=>15351, +18748=>15352, +59398=>15352, +29689=>15353, +59399=>15353, +147995=>15354, +59400=>15354, +38811=>15355, +59401=>15355, +39224=>15357, +59403=>15357, +134950=>15358, +59404=>15358, +24001=>15359, +59405=>15359, +166853=>15360, +59406=>15360, +150194=>15361, +59407=>15361, +38943=>15362, +59408=>15362, +169178=>15363, +59409=>15363, +37622=>15364, +59410=>15364, +169431=>15365, +59411=>15365, +37349=>15366, +59412=>15366, +17600=>15367, +59413=>15367, +166736=>15368, +59414=>15368, +150119=>15369, +59415=>15369, +166756=>15370, +59416=>15370, +39132=>15371, +59417=>15371, +166469=>15372, +59418=>15372, +16128=>15373, +59419=>15373, +37418=>15374, +59420=>15374, +18725=>15375, +59421=>15375, +33812=>15376, +59422=>15376, +39227=>15377, +59423=>15377, +39245=>15378, +59424=>15378, +162566=>15379, +59425=>15379, +15869=>15380, +59426=>15380, +19311=>15382, +59428=>15382, +39338=>15383, +59429=>15383, +39516=>15384, +59430=>15384, +166757=>15385, +59431=>15385, +153800=>15386, +59432=>15386, +27279=>15387, +59433=>15387, +39457=>15388, +59434=>15388, +23294=>15389, +59435=>15389, +39471=>15390, +59436=>15390, +170225=>15391, +59437=>15391, +19344=>15392, +59438=>15392, +170312=>15393, +59439=>15393, +39356=>15394, +59440=>15394, +19389=>15395, +59441=>15395, +19351=>15396, +59442=>15396, +37757=>15397, +59443=>15397, +22642=>15398, +59444=>15398, +135938=>15399, +59445=>15399, +22562=>15400, +59446=>15400, +149944=>15401, +59447=>15401, +136424=>15402, +59448=>15402, +30788=>15403, +59449=>15403, +141087=>15404, +59450=>15404, +146872=>15405, +59451=>15405, +26821=>15406, +59452=>15406, +15741=>15407, +59453=>15407, +37976=>15408, +59454=>15408, +14631=>15409, +59455=>15409, +24912=>15410, +59456=>15410, +141185=>15411, +59457=>15411, +141675=>15412, +59458=>15412, +24839=>15413, +59459=>15413, +40015=>15414, +59460=>15414, +40019=>15415, +59461=>15415, +40059=>15416, +59462=>15416, +39989=>15417, +59463=>15417, +39952=>15418, +59464=>15418, +39807=>15419, +59465=>15419, +39887=>15420, +59466=>15420, +171565=>15421, +59467=>15421, +39839=>15422, +59468=>15422, +172533=>15423, +59469=>15423, +172286=>15424, +59470=>15424, +40225=>15425, +59471=>15425, +19630=>15426, +59472=>15426, +147716=>15427, +59473=>15427, +40472=>15428, +59474=>15428, +19632=>15429, +59475=>15429, +40204=>15430, +59476=>15430, +172468=>15431, +59477=>15431, +172269=>15432, +59478=>15432, +172275=>15433, +59479=>15433, +170287=>15434, +59480=>15434, +40357=>15435, +59481=>15435, +33981=>15436, +59482=>15436, +159250=>15437, +59483=>15437, +159711=>15438, +59484=>15438, +158594=>15439, +59485=>15439, +34300=>15440, +59486=>15440, +17715=>15441, +59487=>15441, +159140=>15442, +59488=>15442, +159364=>15443, +59489=>15443, +159216=>15444, +59490=>15444, +33824=>15445, +59491=>15445, +34286=>15446, +59492=>15446, +159232=>15447, +59493=>15447, +145367=>15448, +59494=>15448, +155748=>15449, +59495=>15449, +31202=>15450, +59496=>15450, +144796=>15451, +59497=>15451, +144960=>15452, +59498=>15452, +149982=>15453, +59500=>15453, +15714=>15454, +59501=>15454, +37851=>15455, +59502=>15455, +37566=>15456, +59503=>15456, +37704=>15457, +59504=>15457, +131775=>15458, +59505=>15458, +30905=>15459, +59506=>15459, +37495=>15460, +59507=>15460, +37965=>15461, +59508=>15461, +20452=>15462, +59509=>15462, +13376=>15463, +59510=>15463, +36964=>15464, +59511=>15464, +152925=>15465, +59512=>15465, +30781=>15466, +59513=>15466, +30804=>15467, +59514=>15467, +30902=>15468, +59515=>15468, +30795=>15469, +59516=>15469, +137047=>15470, +59517=>15470, +143817=>15471, +59518=>15471, +149825=>15472, +59519=>15472, +13978=>15473, +59520=>15473, +20338=>15474, +59521=>15474, +28634=>15475, +59522=>15475, +28633=>15476, +59523=>15476, +28702=>15478, +59524=>15478, +59525=>15478, +21524=>15479, +59526=>15479, +147893=>15480, +59527=>15480, +22459=>15481, +59528=>15481, +22771=>15482, +59529=>15482, +22410=>15483, +59530=>15483, +40214=>15484, +59531=>15484, +22487=>15485, +59532=>15485, +28980=>15486, +59533=>15486, +13487=>15487, +59534=>15487, +147884=>15488, +59535=>15488, +29163=>15489, +59536=>15489, +158784=>15490, +59537=>15490, +151447=>15491, +59538=>15491, +137141=>15493, +59540=>15493, +166473=>15494, +59541=>15494, +24844=>15495, +59542=>15495, +23246=>15496, +59543=>15496, +23051=>15497, +59544=>15497, +17084=>15498, +59545=>15498, +148616=>15499, +59546=>15499, +14124=>15500, +59547=>15500, +19323=>15501, +59548=>15501, +166396=>15502, +59549=>15502, +37819=>15503, +59550=>15503, +37816=>15504, +59551=>15504, +137430=>15505, +59552=>15505, +134941=>15506, +59553=>15506, +33906=>15507, +59554=>15507, +158912=>15508, +59555=>15508, +136211=>15509, +59556=>15509, +148218=>15510, +59557=>15510, +142374=>15511, +59558=>15511, +148417=>15512, +59559=>15512, +22932=>15513, +59560=>15513, +146871=>15514, +59561=>15514, +157505=>15515, +59562=>15515, +32168=>15516, +59563=>15516, +155995=>15517, +59564=>15517, +155812=>15518, +59565=>15518, +149945=>15519, +59566=>15519, +149899=>15520, +59567=>15520, +166394=>15521, +59568=>15521, +37605=>15522, +59569=>15522, +29666=>15523, +59570=>15523, +16105=>15524, +59571=>15524, +29876=>15525, +59572=>15525, +166755=>15526, +59573=>15526, +137375=>15527, +59574=>15527, +16097=>15528, +59575=>15528, +150195=>15529, +59576=>15529, +27352=>15530, +59577=>15530, +29683=>15531, +59578=>15531, +29691=>15532, +59579=>15532, +16086=>15533, +59580=>15533, +150078=>15534, +59581=>15534, +150164=>15535, +59582=>15535, +137177=>15536, +59583=>15536, +150118=>15537, +59584=>15537, +132007=>15538, +59585=>15538, +136228=>15539, +59586=>15539, +149989=>15540, +59587=>15540, +29768=>15541, +59588=>15541, +149782=>15542, +59589=>15542, +28837=>15543, +59590=>15543, +149878=>15544, +59591=>15544, +37508=>15545, +59592=>15545, +29670=>15546, +59593=>15546, +37727=>15547, +59594=>15547, +132350=>15548, +59595=>15548, +37681=>15549, +59596=>15549, +166606=>15550, +59597=>15550, +166422=>15551, +59598=>15551, +37766=>15552, +59599=>15552, +166887=>15553, +59600=>15553, +153045=>15554, +59601=>15554, +18741=>15555, +59602=>15555, +166530=>15556, +59603=>15556, +29035=>15557, +59604=>15557, +149827=>15558, +59605=>15558, +134399=>15559, +59606=>15559, +22180=>15560, +59607=>15560, +132634=>15561, +59608=>15561, +134123=>15562, +59609=>15562, +134328=>15563, +59610=>15563, +21762=>15564, +59611=>15564, +31172=>15565, +59612=>15565, +137210=>15566, +59613=>15566, +32254=>15567, +59614=>15567, +136898=>15568, +59615=>15568, +150096=>15569, +59616=>15569, +137298=>15570, +59617=>15570, +17710=>15571, +59618=>15571, +37889=>15572, +59619=>15572, +14090=>15573, +59620=>15573, +166592=>15574, +59621=>15574, +149933=>15575, +59622=>15575, +22960=>15576, +59623=>15576, +137407=>15577, +59624=>15577, +137347=>15578, +59625=>15578, +160900=>15579, +59626=>15579, +23201=>15580, +59627=>15580, +14050=>15581, +59628=>15581, +146779=>15582, +59629=>15582, +14000=>15583, +59630=>15583, +37471=>15584, +59631=>15584, +23161=>15585, +59632=>15585, +166529=>15586, +59633=>15586, +137314=>15587, +59634=>15587, +37748=>15588, +59635=>15588, +15565=>15589, +59636=>15589, +133812=>15590, +59637=>15590, +19094=>15591, +59638=>15591, +14730=>15592, +59639=>15592, +20724=>15593, +59640=>15593, +15721=>15594, +59641=>15594, +15692=>15595, +59642=>15595, +136092=>15596, +59643=>15596, +29045=>15597, +59644=>15597, +17147=>15598, +59645=>15598, +164376=>15599, +59646=>15599, +28175=>15600, +59647=>15600, +168164=>15601, +59648=>15601, +17643=>15602, +59649=>15602, +27991=>15603, +59650=>15603, +163407=>15604, +59651=>15604, +28775=>15605, +59652=>15605, +27823=>15606, +59653=>15606, +15574=>15607, +59654=>15607, +147437=>15608, +59655=>15608, +146989=>15609, +59656=>15609, +28162=>15610, +59657=>15610, +28428=>15611, +59658=>15611, +15727=>15612, +59659=>15612, +132085=>15613, +59660=>15613, +30033=>15614, +59661=>15614, +14012=>15615, +59662=>15615, +13512=>15616, +59663=>15616, +18048=>15617, +59664=>15617, +16090=>15618, +59665=>15618, +18545=>15619, +59666=>15619, +22980=>15620, +59667=>15620, +37486=>15621, +59668=>15621, +18750=>15622, +59669=>15622, +36673=>15623, +59670=>15623, +166940=>15624, +59671=>15624, +158656=>15625, +59672=>15625, +22546=>15626, +59673=>15626, +22472=>15627, +59674=>15627, +14038=>15628, +59675=>15628, +136274=>15629, +59676=>15629, +28926=>15630, +59677=>15630, +148322=>15631, +59678=>15631, +150129=>15632, +59679=>15632, +143331=>15633, +59680=>15633, +135856=>15634, +59681=>15634, +140221=>15635, +59682=>15635, +26809=>15636, +59683=>15636, +26983=>15637, +59684=>15637, +136088=>15638, +59685=>15638, +144613=>15639, +59686=>15639, +162804=>15640, +59687=>15640, +145119=>15641, +59688=>15641, +166531=>15642, +59689=>15642, +145366=>15643, +59690=>15643, +144378=>15644, +59691=>15644, +150687=>15645, +59692=>15645, +27162=>15646, +59693=>15646, +145069=>15647, +59694=>15647, +158903=>15648, +59695=>15648, +33854=>15649, +59696=>15649, +17631=>15650, +59697=>15650, +17614=>15651, +59698=>15651, +159014=>15652, +59699=>15652, +159057=>15653, +59700=>15653, +158850=>15654, +59701=>15654, +159710=>15655, +59702=>15655, +33597=>15658, +59705=>15658, +137018=>15659, +59706=>15659, +33773=>15660, +59707=>15660, +158848=>15661, +59708=>15661, +159827=>15662, +59709=>15662, +137179=>15663, +59710=>15663, +22921=>15664, +59711=>15664, +23170=>15665, +59712=>15665, +137139=>15666, +59713=>15666, +23137=>15667, +59714=>15667, +23153=>15668, +59715=>15668, +137477=>15669, +59716=>15669, +147964=>15670, +59717=>15670, +14125=>15671, +59718=>15671, +23023=>15672, +59719=>15672, +137020=>15673, +59720=>15673, +14023=>15674, +59721=>15674, +29070=>15675, +59722=>15675, +37776=>15676, +59723=>15676, +26266=>15677, +59724=>15677, +148133=>15678, +59725=>15678, +23150=>15679, +59726=>15679, +23083=>15680, +59727=>15680, +148115=>15681, +59728=>15681, +27179=>15682, +59729=>15682, +147193=>15683, +59730=>15683, +161590=>15684, +59731=>15684, +148571=>15685, +59732=>15685, +148170=>15686, +59733=>15686, +28957=>15687, +59734=>15687, +148057=>15688, +59735=>15688, +166369=>15689, +59736=>15689, +20400=>15690, +59737=>15690, +159016=>15691, +59738=>15691, +23746=>15692, +59739=>15692, +148686=>15693, +59740=>15693, +163405=>15694, +59741=>15694, +148413=>15695, +59742=>15695, +27148=>15696, +59743=>15696, +148054=>15697, +59744=>15697, +135940=>15698, +59745=>15698, +28979=>15700, +59747=>15700, +148457=>15701, +59748=>15701, +15781=>15702, +59749=>15702, +27871=>15703, +59750=>15703, +194597=>15704, +59751=>15704, +23019=>15705, +59754=>15705, +24412=>15706, +59757=>15706, +59764=>15707, +144128=>15707, +31955=>15708, +59776=>15708, +59783=>15709, +162548=>15709, +59786=>15710, +153334=>15710, +162584=>15711, +59790=>15711, +36972=>15712, +59791=>15712, +33270=>15713, +59795=>15713, +30476=>15714, +59797=>15714, +27810=>15715, +59799=>15715, +22269=>15716, +59800=>15716, +22633=>15717, +59828=>15717, +26465=>15718, +59832=>15718, +23646=>15719, +59838=>15719, +22770=>15720, +59841=>15720, +28857=>15721, +59843=>15721, +26627=>15722, +59853=>15722, +59859=>15723, +36795=>15723, +59861=>15724, +36796=>15724, +20001=>15725, +59871=>15725, +31545=>15726, +59898=>15726, +15820=>15727, +59902=>15727, +29482=>15728, +57990=>15728, +59909=>15728, +30048=>15729, +59912=>15729, +22586=>15730, +59920=>15730, +33446=>15731, +59932=>15731, +27018=>15732, +59940=>15732, +24803=>15733, +59944=>15733, +20206=>15734, +59984=>15734, +39364=>15735, +60002=>15735, +40639=>15736, +60023=>15736, +21249=>15737, +60025=>15737, +26528=>15738, +60038=>15738, +24808=>15739, +60046=>15739, +20916=>15740, +60053=>15740, +31363=>15741, +60064=>15741, +39994=>15742, +60075=>15742, +31432=>15743, +60093=>15743, +26906=>15744, +60098=>15744, +22956=>15745, +60100=>15745, +22592=>15746, +60102=>15746, +21610=>15747, +60114=>15747, +24807=>15748, +60123=>15748, +22138=>15749, +60125=>15749, +26965=>15750, +60132=>15750, +39983=>15751, +60133=>15751, +34725=>15752, +60134=>15752, +23584=>15753, +60141=>15753, +24075=>15754, +60143=>15754, +26398=>15755, +60147=>15755, +33965=>15756, +60157=>15756, +35713=>15757, +60161=>15757, +20088=>15758, +60166=>15758, +25283=>15759, +60176=>15759, +26709=>15760, +60180=>15760, +33533=>15762, +60190=>15762, +35237=>15763, +60194=>15763, +36768=>15764, +60196=>15764, +38840=>15765, +60198=>15765, +38983=>15766, +60200=>15766, +39613=>15767, +60201=>15767, +24497=>15768, +60218=>15768, +26184=>15769, +60219=>15769, +26303=>15770, +60220=>15770, +162425=>15771, +60221=>15771, +60225=>15773, +149946=>15773, +60230=>15776, +131910=>15776, +26382=>15777, +60232=>15777, +26904=>15778, +60233=>15778, +161367=>15779, +60235=>15779, +155618=>15780, +60236=>15780, +161278=>15781, +60239=>15781, +139418=>15782, +60240=>15782, +18640=>15783, +60241=>15783, +19128=>15784, +60242=>15784, +60244=>15785, +166554=>15785, +60247=>15786, +147515=>15786, +150085=>15787, +60250=>15787, +132554=>15788, +60251=>15788, +20946=>15789, +60252=>15789, +132625=>15790, +60253=>15790, +22943=>15791, +60254=>15791, +138920=>15792, +60255=>15792, +15294=>15793, +60256=>15793, +146687=>15794, +60257=>15794, +14747=>15795, +60262=>15795, +165352=>15796, +60264=>15796, +170441=>15797, +60265=>15797, +14178=>15798, +60266=>15798, +139715=>15799, +60267=>15799, +35678=>15800, +60268=>15800, +166734=>15801, +60269=>15801, +29193=>15803, +60274=>15803, +60276=>15804, +134264=>15804, +132985=>15805, +60280=>15805, +36570=>15806, +60281=>15806, +21135=>15807, +60283=>15807, +29041=>15808, +60285=>15808, +147274=>15809, +60288=>15809, +150183=>15810, +60289=>15810, +21948=>15811, +60290=>15811, +60293=>15812, +158546=>15812, +13427=>15813, +60295=>15813, +60297=>15814, +161330=>15814, +18200=>15815, +60299=>15815, +60303=>15816, +149823=>15816, +20582=>15817, +60305=>15817, +13563=>15818, +60306=>15818, +144332=>15819, +60307=>15819, +18300=>15821, +60310=>15821, +166216=>15822, +60311=>15822, +60315=>15823, +138640=>15823, +162834=>15825, +60320=>15825, +36950=>15826, +60321=>15826, +151450=>15827, +60323=>15827, +35682=>15828, +60324=>15828, +23899=>15829, +60327=>15829, +158711=>15830, +60328=>15830, +137500=>15832, +60331=>15832, +35562=>15833, +60332=>15833, +150006=>15834, +60333=>15834, +60335=>15835, +147439=>15835, +19392=>15836, +60337=>15836, +141083=>15837, +60340=>15837, +37989=>15838, +60341=>15838, +153569=>15839, +60342=>15839, +24981=>15840, +60343=>15840, +23079=>15841, +60344=>15841, +194765=>15842, +60345=>15842, +194566=>15843, +60348=>15844, +148769=>15844, +20074=>15845, +60350=>15845, +149812=>15846, +60351=>15846, +38486=>15847, +60352=>15847, +28047=>15848, +60353=>15848, +158909=>15849, +60354=>15849, +35191=>15850, +60356=>15850, +60359=>15851, +156689=>15851, +31554=>15853, +60363=>15853, +168128=>15854, +60364=>15854, +133649=>15855, +60365=>15855, +31301=>15857, +60369=>15857, +39462=>15858, +60372=>15858, +13919=>15859, +60374=>15859, +156777=>15860, +60375=>15860, +131105=>15861, +60376=>15861, +31107=>15862, +60377=>15862, +23852=>15863, +60380=>15863, +144665=>15864, +60381=>15864, +18128=>15866, +60384=>15866, +30011=>15867, +60386=>15867, +34917=>15868, +60387=>15868, +22710=>15869, +60389=>15869, +14108=>15870, +60390=>15870, +140685=>15871, +60391=>15871, +15444=>15872, +60394=>15872, +37505=>15873, +60397=>15873, +139642=>15874, +60398=>15874, +37680=>15875, +60400=>15875, +149968=>15876, +60402=>15876, +27705=>15877, +60403=>15877, +134904=>15878, +60406=>15878, +34855=>15879, +60407=>15879, +35061=>15880, +60408=>15880, +141606=>15881, +60409=>15881, +164979=>15882, +60410=>15882, +137137=>15883, +60411=>15883, +28344=>15884, +60412=>15884, +150058=>15885, +60413=>15885, +137248=>15886, +60414=>15886, +14756=>15887, +60415=>15887, +17727=>15890, +60419=>15890, +26294=>15891, +60420=>15891, +171181=>15892, +60421=>15892, +170148=>15893, +60422=>15893, +35139=>15894, +60423=>15894, +16607=>15895, +60427=>15895, +136714=>15896, +60428=>15896, +14753=>15897, +60429=>15897, +145199=>15898, +60430=>15898, +164072=>15899, +60431=>15899, +136133=>15900, +60432=>15900, +29101=>15901, +60433=>15901, +33638=>15902, +60434=>15902, +60436=>15903, +168360=>15903, +19639=>15905, +60438=>15905, +159919=>15906, +60439=>15906, +166315=>15907, +60440=>15907, +147834=>15908, +60445=>15908, +31555=>15909, +60446=>15909, +31102=>15910, +60447=>15910, +28597=>15911, +60449=>15911, +172767=>15912, +60450=>15912, +27139=>15913, +60451=>15913, +164632=>15914, +60452=>15914, +21410=>15915, +60453=>15915, +159239=>15916, +60454=>15916, +37823=>15917, +60455=>15917, +26678=>15918, +60456=>15918, +38749=>15919, +59389=>15919, +60457=>15919, +164207=>15920, +60458=>15920, +158133=>15921, +60460=>15921, +136173=>15922, +60461=>15922, +143919=>15923, +60462=>15923, +23941=>15924, +60464=>15924, +166960=>15925, +60465=>15925, +22293=>15926, +60467=>15926, +38947=>15927, +60468=>15927, +166217=>15928, +60469=>15928, +23979=>15929, +60470=>15929, +149896=>15930, +60471=>15930, +26046=>15931, +60472=>15931, +27093=>15932, +60473=>15932, +21458=>15933, +60474=>15933, +150181=>15934, +60475=>15934, +147329=>15935, +60476=>15935, +15377=>15936, +60477=>15936, +26422=>15937, +60478=>15937, +60482=>15938, +139169=>15938, +13770=>15939, +60490=>15939, +18682=>15940, +60493=>15940, +30728=>15942, +60496=>15942, +37461=>15943, +60497=>15943, +17394=>15944, +60499=>15944, +17375=>15945, +60501=>15945, +23032=>15946, +60505=>15946, +22155=>15948, +60518=>15948, +60520=>15949, +169449=>15949, +36882=>15950, +60541=>15950, +21953=>15951, +60546=>15951, +17673=>15952, +60551=>15952, +32383=>15953, +60552=>15953, +28502=>15954, +60553=>15954, +27313=>15955, +60554=>15955, +13540=>15956, +60556=>15956, +161949=>15957, +60558=>15957, +14138=>15958, +60559=>15958, +60562=>15960, +163876=>15960, +60565=>15961, +162366=>15961, +15851=>15962, +60567=>15962, +60569=>15963, +146615=>15963, +156248=>15964, +60574=>15964, +22207=>15965, +60575=>15965, +36366=>15966, +60577=>15966, +23405=>15967, +60578=>15967, +25566=>15968, +60581=>15968, +25904=>15970, +60585=>15970, +22061=>15971, +60586=>15971, +21530=>15972, +60588=>15972, +171416=>15973, +60591=>15973, +19581=>15974, +60592=>15974, +22050=>15975, +60593=>15975, +22046=>15976, +60594=>15976, +32585=>15977, +60595=>15977, +22901=>15978, +60597=>15978, +146752=>15979, +60598=>15979, +34672=>15980, +60599=>15980, +33047=>15981, +60604=>15981, +40286=>15982, +60605=>15982, +36120=>15983, +60606=>15983, +30267=>15984, +60607=>15984, +40005=>15985, +60608=>15985, +30286=>15986, +60609=>15986, +30649=>15987, +60610=>15987, +37701=>15988, +60611=>15988, +21554=>15989, +60612=>15989, +33096=>15990, +60613=>15990, +33527=>15991, +60614=>15991, +22053=>15992, +60615=>15992, +33074=>15993, +60616=>15993, +33816=>15994, +60617=>15994, +32957=>15995, +60618=>15995, +21994=>15996, +60619=>15996, +31074=>15997, +60620=>15997, +22083=>15998, +60621=>15998, +21526=>15999, +60622=>15999, +134813=>16000, +60623=>16000, +13774=>16001, +60624=>16001, +22021=>16002, +57509=>16002, +60625=>16002, +22001=>16003, +60626=>16003, +26353=>16004, +60627=>16004, +164578=>16005, +60628=>16005, +13869=>16006, +60629=>16006, +30004=>16007, +60630=>16007, +22000=>16008, +60631=>16008, +21946=>16009, +60632=>16009, +21655=>16010, +60633=>16010, +21874=>16011, +60634=>16011, +134209=>16012, +60635=>16012, +134294=>16013, +60636=>16013, +24272=>16014, +57652=>16014, +60637=>16014, +134774=>16015, +60639=>16015, +142434=>16016, +60640=>16016, +134818=>16017, +60641=>16017, +40619=>16018, +60642=>16018, +32090=>16019, +60643=>16019, +135285=>16021, +60645=>16021, +25245=>16022, +60646=>16022, +38765=>16023, +60647=>16023, +21652=>16024, +60648=>16024, +36045=>16025, +60649=>16025, +29174=>16026, +60650=>16026, +37238=>16027, +60651=>16027, +25596=>16028, +60652=>16028, +25529=>16029, +60653=>16029, +25598=>16030, +60654=>16030, +21865=>16031, +60655=>16031, +142147=>16032, +60656=>16032, +40050=>16033, +60657=>16033, +143027=>16034, +60658=>16034, +20890=>16035, +60659=>16035, +13535=>16036, +60660=>16036, +134567=>16037, +60661=>16037, +20903=>16038, +60662=>16038, +21581=>16039, +60663=>16039, +21790=>16040, +60664=>16040, +21779=>16041, +60665=>16041, +30310=>16042, +60666=>16042, +36397=>16043, +60667=>16043, +157834=>16044, +60668=>16044, +30129=>16045, +60669=>16045, +32950=>16046, +60670=>16046, +34820=>16047, +60671=>16047, +35015=>16049, +60673=>16049, +33206=>16050, +60674=>16050, +33820=>16051, +60675=>16051, +17644=>16052, +60677=>16052, +29444=>16053, +60678=>16053, +33547=>16054, +60681=>16054, +22139=>16055, +60683=>16055, +37232=>16056, +60690=>16056, +37384=>16057, +60692=>16057, +134905=>16058, +60696=>16058, +29286=>16059, +60697=>16059, +18254=>16060, +60699=>16060, +60701=>16061, +163833=>16061, +16634=>16062, +60703=>16062, +40029=>16063, +60704=>16063, +25887=>16064, +60705=>16064, +18675=>16065, +60707=>16065, +149472=>16066, +60708=>16066, +171388=>16067, +60709=>16067, +60713=>16069, +161187=>16069, +60715=>16070, +155720=>16071, +60716=>16071, +29091=>16072, +60718=>16072, +32398=>16073, +60719=>16073, +40272=>16074, +60720=>16074, +13687=>16075, +60723=>16075, +27826=>16076, +60725=>16076, +21351=>16077, +60726=>16077, +14812=>16078, +60728=>16078, +60731=>16079, +149016=>16079, +33325=>16080, +60734=>16080, +21579=>16081, +60735=>16081, +60739=>16082, +14930=>16083, +60740=>16083, +29556=>16084, +60742=>16084, +171692=>16085, +60743=>16085, +19721=>16086, +60744=>16086, +39917=>16087, +60745=>16087, +19547=>16089, +60748=>16089, +171998=>16090, +60751=>16090, +33884=>16091, +60752=>16091, +60754=>16092, +160434=>16092, +25390=>16093, +60757=>16093, +32037=>16094, +60758=>16094, +14890=>16095, +60761=>16095, +36872=>16096, +60762=>16096, +21196=>16097, +60763=>16097, +15988=>16098, +60764=>16098, +13946=>16099, +60765=>16099, +17897=>16100, +60766=>16100, +132238=>16101, +60767=>16101, +30272=>16102, +60768=>16102, +23280=>16103, +60769=>16103, +134838=>16104, +60770=>16104, +30842=>16105, +60771=>16105, +18358=>16106, +163630=>16106, +60772=>16106, +22695=>16107, +60773=>16107, +16575=>16108, +60774=>16108, +22140=>16109, +60775=>16109, +39819=>16110, +60776=>16110, +23924=>16111, +60777=>16111, +30292=>16112, +60778=>16112, +173108=>16113, +60779=>16113, +40581=>16114, +60780=>16114, +19681=>16115, +60781=>16115, +14331=>16117, +60783=>16117, +24857=>16118, +60784=>16118, +148466=>16119, +60786=>16119, +60787=>16120, +22109=>16121, +60788=>16121, +171526=>16122, +60792=>16122, +21044=>16123, +60793=>16123, +13741=>16124, +60795=>16124, +40316=>16126, +60797=>16126, +31830=>16127, +60798=>16127, +39737=>16128, +60799=>16128, +22494=>16129, +60800=>16129, +23635=>16130, +60802=>16130, +25811=>16131, +60803=>16131, +169168=>16132, +60804=>16132, +156469=>16133, +60805=>16133, +34477=>16134, +60807=>16134, +134440=>16135, +60808=>16135, +134513=>16136, +60811=>16136, +60812=>16137, +20990=>16138, +60813=>16138, +139023=>16139, +60814=>16139, +23950=>16140, +60815=>16140, +38659=>16141, +60816=>16141, +138705=>16142, +60817=>16142, +40577=>16143, +60818=>16143, +36940=>16144, +60819=>16144, +31519=>16145, +60820=>16145, +39682=>16146, +60821=>16146, +23761=>16147, +60822=>16147, +31651=>16148, +60823=>16148, +25192=>16149, +60824=>16149, +25397=>16150, +60825=>16150, +39679=>16151, +60826=>16151, +31695=>16152, +60827=>16152, +39722=>16153, +60828=>16153, +31870=>16154, +60829=>16154, +31810=>16156, +60831=>16156, +31878=>16157, +60832=>16157, +39957=>16158, +60833=>16158, +31740=>16159, +60834=>16159, +39689=>16160, +60835=>16160, +39982=>16162, +40794=>16163, +60839=>16163, +21875=>16164, +60840=>16164, +23491=>16165, +60841=>16165, +20477=>16166, +60842=>16166, +40600=>16167, +60843=>16167, +20466=>16168, +60844=>16168, +21088=>16169, +60845=>16169, +21201=>16170, +60847=>16170, +22375=>16171, +60848=>16171, +20566=>16172, +60849=>16172, +22967=>16173, +60850=>16173, +24082=>16174, +60851=>16174, +38856=>16175, +60852=>16175, +40363=>16176, +60853=>16176, +36700=>16177, +60854=>16177, +21609=>16178, +60855=>16178, +38836=>16179, +60856=>16179, +39232=>16180, +60857=>16180, +38842=>16181, +60858=>16181, +21292=>16182, +60859=>16182, +24880=>16183, +60860=>16183, +26924=>16184, +60861=>16184, +21466=>16185, +60862=>16185, +39946=>16186, +60863=>16186, +40194=>16187, +60864=>16187, +19515=>16188, +60865=>16188, +38465=>16189, +60866=>16189, +27008=>16190, +60867=>16190, +20646=>16191, +60868=>16191, +30022=>16192, +60869=>16192, +137069=>16193, +60870=>16193, +39386=>16194, +60871=>16194, +21107=>16195, +60872=>16195, +60873=>16196, +37209=>16197, +60874=>16197, +38529=>16198, +60875=>16198, +37212=>16199, +60876=>16199, +60877=>16200, +37201=>16201, +60878=>16201, +167575=>16202, +60879=>16202, +25471=>16203, +60880=>16203, +27338=>16204, +60882=>16204, +22033=>16205, +60883=>16205, +37262=>16206, +60884=>16206, +30074=>16207, +60885=>16207, +25221=>16208, +60886=>16208, +29519=>16209, +60888=>16209, +31856=>16210, +60889=>16210, +154657=>16211, +60890=>16211, +60892=>16212, +30422=>16213, +60894=>16213, +39837=>16214, +60895=>16214, +20010=>16215, +60896=>16215, +134356=>16216, +60897=>16216, +33726=>16217, +60898=>16217, +34882=>16218, +60899=>16218, +60900=>16219, +23626=>16220, +60901=>16220, +27072=>16221, +60902=>16221, +21023=>16224, +60905=>16224, +24053=>16225, +60906=>16225, +20174=>16226, +60907=>16226, +27697=>16227, +60908=>16227, +131570=>16228, +60909=>16228, +20281=>16229, +60910=>16229, +21660=>16230, +60911=>16230, +21146=>16232, +60913=>16232, +36226=>16233, +60914=>16233, +13822=>16234, +60915=>16234, +13811=>16236, +60917=>16236, +60918=>16237, +27474=>16238, +60919=>16238, +37244=>16239, +60920=>16239, +40869=>16240, +60921=>16240, +39831=>16241, +60922=>16241, +38958=>16242, +60923=>16242, +39092=>16243, +60924=>16243, +39610=>16244, +60925=>16244, +40616=>16245, +60926=>16245, +40580=>16246, +60927=>16246, +31508=>16247, +60929=>16247, +60930=>16248, +27642=>16249, +60931=>16249, +34840=>16250, +60932=>16250, +32632=>16251, +60933=>16251, +60934=>16252, +22048=>16253, +60935=>16253, +173642=>16254, +60936=>16254, +36471=>16255, +60937=>16255, +40787=>16256, +60938=>16256, +60939=>16257, +36308=>16258, +60940=>16258, +36431=>16259, +60941=>16259, +40476=>16260, +60942=>16260, +36353=>16261, +60943=>16261, +25218=>16262, +60944=>16262, +164733=>16263, +60945=>16263, +36392=>16264, +60946=>16264, +36469=>16265, +60947=>16265, +31443=>16266, +60948=>16266, +31294=>16267, +60950=>16267, +30936=>16268, +60951=>16268, +27882=>16269, +60952=>16269, +35431=>16270, +60953=>16270, +30215=>16271, +60954=>16271, +40742=>16272, +60956=>16272, +27854=>16273, +60957=>16273, +34774=>16274, +60958=>16274, +30147=>16275, +60959=>16275, +172722=>16276, +60960=>16276, +30803=>16277, +60961=>16277, +36108=>16278, +60963=>16278, +29410=>16279, +60964=>16279, +29553=>16280, +60965=>16280, +35629=>16281, +60966=>16281, +29442=>16282, +60967=>16282, +29937=>16283, +60968=>16283, +36075=>16284, +60969=>16284, +150203=>16285, +60970=>16285, +34351=>16286, +60971=>16286, +24506=>16287, +60972=>16287, +34976=>16288, +60973=>16288, +17591=>16289, +60974=>16289, +60975=>16290, +159237=>16291, +60977=>16291, +60978=>16292, +35454=>16293, +60979=>16293, +140571=>16294, +60980=>16294, +60981=>16295, +24829=>16296, +60982=>16296, +30311=>16297, +60983=>16297, +39639=>16298, +60984=>16298, +40260=>16299, +60985=>16299, +37742=>16300, +58859=>16300, +60986=>16300, +39823=>16301, +60987=>16301, +34805=>16302, +60988=>16302, +60989=>16303, +36087=>16305, +60991=>16305, +29484=>16306, +60992=>16306, +38689=>16307, +60993=>16307, +39856=>16308, +60994=>16308, +13782=>16309, +60995=>16309, +29362=>16310, +60996=>16310, +19463=>16311, +60997=>16311, +31825=>16312, +60998=>16312, +39242=>16313, +60999=>16313, +24921=>16314, +61001=>16314, +19460=>16315, +61002=>16315, +40598=>16316, +61003=>16316, +24957=>16317, +61004=>16317, +61005=>16318, +22367=>16319, +61006=>16319, +24943=>16320, +61007=>16320, +25254=>16321, +61008=>16321, +25145=>16322, +61009=>16322, +14940=>16324, +61011=>16324, +25058=>16325, +61012=>16325, +21418=>16326, +61013=>16326, +25444=>16327, +61015=>16327, +26626=>16328, +61016=>16328, +13778=>16329, +61017=>16329, +23895=>16330, +61018=>16330, +36826=>16331, +61020=>16331, +167481=>16332, +61021=>16332, +61022=>16333, +20697=>16334, +61023=>16334, +30982=>16335, +61025=>16335, +21298=>16336, +61026=>16336, +38456=>16337, +61027=>16337, +134971=>16338, +61028=>16338, +16485=>16339, +61029=>16339, +61030=>16340, +30718=>16341, +61031=>16341, +61032=>16342, +31938=>16343, +61033=>16343, +155418=>16344, +61034=>16344, +31962=>16345, +61035=>16345, +31277=>16346, +61036=>16346, +32870=>16347, +61037=>16347, +32867=>16348, +61038=>16348, +32077=>16349, +61039=>16349, +29957=>16350, +61040=>16350, +29938=>16351, +61041=>16351, +35220=>16352, +61042=>16352, +33306=>16353, +61043=>16353, +26380=>16354, +61044=>16354, +32866=>16355, +61045=>16355, +160902=>16356, +61046=>16356, +32859=>16357, +61047=>16357, +29936=>16358, +61048=>16358, +33027=>16359, +61049=>16359, +30500=>16360, +61050=>16360, +35209=>16361, +61051=>16361, +157644=>16362, +61052=>16362, +30035=>16363, +61053=>16363, +34729=>16364, +61055=>16364, +34766=>16365, +61056=>16365, +33224=>16366, +61057=>16366, +34700=>16367, +61058=>16367, +35401=>16368, +61059=>16368, +36013=>16369, +61060=>16369, +35651=>16370, +61061=>16370, +30507=>16371, +61062=>16371, +29944=>16372, +61063=>16372, +34010=>16373, +61064=>16373, +27058=>16374, +61066=>16374, +36262=>16375, +61067=>16375, +61068=>16376, +35241=>16377, +58392=>16377, +61069=>16377, +28089=>16379, +61071=>16379, +34753=>16380, +61072=>16380, +147473=>16381, +61073=>16381, +29927=>16382, +61074=>16382, +15835=>16383, +61075=>16383, +29046=>16384, +61076=>16384, +24740=>16385, +57702=>16385, +61077=>16385, +24988=>16386, +61078=>16386, +15569=>16387, +61079=>16387, +24695=>16389, +61081=>16389, +61082=>16390, +32625=>16391, +61083=>16391, +194850=>16392, +24809=>16393, +61086=>16393, +19326=>16394, +61087=>16394, +132423=>16395, +57344=>16395, +37595=>16396, +57345=>16396, +132575=>16397, +57346=>16397, +147397=>16398, +57347=>16398, +34124=>16399, +57348=>16399, +17077=>16400, +57349=>16400, +29679=>16401, +57350=>16401, +20917=>16402, +57351=>16402, +13897=>16403, +57352=>16403, +149826=>16404, +57353=>16404, +166372=>16405, +57354=>16405, +37700=>16406, +57355=>16406, +137691=>16407, +57356=>16407, +33518=>16408, +57357=>16408, +146632=>16409, +57358=>16409, +30780=>16410, +57359=>16410, +26436=>16411, +57360=>16411, +25311=>16412, +57361=>16412, +149811=>16413, +57362=>16413, +166314=>16414, +57363=>16414, +131744=>16415, +57364=>16415, +158643=>16416, +57365=>16416, +135941=>16417, +57366=>16417, +20395=>16418, +57367=>16418, +140525=>16419, +57368=>16419, +20488=>16420, +57369=>16420, +159017=>16421, +57370=>16421, +162436=>16422, +57371=>16422, +144896=>16423, +57372=>16423, +150193=>16424, +57373=>16424, +140563=>16425, +57374=>16425, +131966=>16427, +57376=>16427, +24484=>16428, +57377=>16428, +131968=>16429, +57378=>16429, +131911=>16430, +57379=>16430, +28379=>16431, +57380=>16431, +132127=>16432, +57381=>16432, +20702=>16433, +20737=>16434, +57383=>16434, +13434=>16435, +57384=>16435, +20750=>16436, +57385=>16436, +39020=>16437, +57386=>16437, +14147=>16438, +57387=>16438, +33814=>16439, +57388=>16439, +149924=>16440, +57389=>16440, +132231=>16441, +57390=>16441, +20832=>16442, +57391=>16442, +144308=>16443, +57392=>16443, +20842=>16444, +57393=>16444, +134143=>16445, +57394=>16445, +139516=>16446, +57395=>16446, +131813=>16447, +57396=>16447, +140592=>16448, +57397=>16448, +132494=>16449, +57398=>16449, +143923=>16450, +57399=>16450, +137603=>16451, +57400=>16451, +23426=>16452, +57401=>16452, +34685=>16453, +57402=>16453, +132531=>16454, +57403=>16454, +146585=>16455, +57404=>16455, +20914=>16456, +57405=>16456, +20920=>16457, +57406=>16457, +40244=>16458, +57407=>16458, +20937=>16459, +57408=>16459, +20943=>16460, +57409=>16460, +20945=>16461, +57410=>16461, +15580=>16462, +57411=>16462, +20947=>16463, +57412=>16463, +150182=>16464, +57413=>16464, +20915=>16465, +57414=>16465, +20973=>16468, +57417=>16468, +33741=>16469, +57418=>16469, +26942=>16470, +57419=>16470, +145197=>16471, +57420=>16471, +24443=>16472, +57421=>16472, +21003=>16473, +57422=>16473, +21030=>16474, +57423=>16474, +21052=>16475, +57424=>16475, +21173=>16476, +57425=>16476, +21079=>16477, +57426=>16477, +21140=>16478, +57427=>16478, +21177=>16479, +57428=>16479, +21189=>16480, +57429=>16480, +31765=>16481, +57430=>16481, +34114=>16482, +57431=>16482, +21216=>16483, +57432=>16483, +34317=>16484, +57433=>16484, +158483=>16485, +57434=>16485, +194601=>16486, +166622=>16487, +57436=>16487, +21833=>16488, +57437=>16488, +28377=>16489, +57438=>16489, +147328=>16490, +57439=>16490, +133460=>16491, +57440=>16491, +147436=>16492, +57441=>16492, +21299=>16493, +57442=>16493, +134114=>16495, +57444=>16495, +27851=>16496, +57445=>16496, +136998=>16497, +57446=>16497, +26651=>16498, +57447=>16498, +29653=>16499, +57448=>16499, +24650=>16500, +57449=>16500, +16042=>16501, +57450=>16501, +14540=>16502, +57451=>16502, +136936=>16503, +57452=>16503, +29149=>16504, +57453=>16504, +17570=>16505, +57454=>16505, +21357=>16506, +57455=>16506, +21364=>16507, +57456=>16507, +165547=>16508, +57457=>16508, +21374=>16509, +57458=>16509, +194610=>16510, +136598=>16511, +57460=>16511, +136723=>16512, +57461=>16512, +30694=>16513, +57462=>16513, +21395=>16514, +57463=>16514, +166555=>16515, +57464=>16515, +21408=>16516, +57465=>16516, +21419=>16517, +57466=>16517, +21422=>16518, +57467=>16518, +29607=>16519, +57468=>16519, +153458=>16520, +57469=>16520, +16217=>16521, +57470=>16521, +29596=>16522, +57471=>16522, +21441=>16523, +57472=>16523, +21445=>16524, +57473=>16524, +27721=>16525, +57474=>16525, +20041=>16526, +57475=>16526, +22526=>16527, +57476=>16527, +21465=>16528, +57477=>16528, +15019=>16529, +57478=>16529, +134031=>16530, +57479=>16530, +21472=>16531, +57480=>16531, +147435=>16532, +57481=>16532, +142755=>16533, +57482=>16533, +21494=>16534, +57483=>16534, +134263=>16535, +57484=>16535, +21523=>16536, +57485=>16536, +28793=>16537, +57486=>16537, +21803=>16538, +57487=>16538, +26199=>16539, +57488=>16539, +27995=>16540, +57489=>16540, +21613=>16541, +57490=>16541, +158547=>16542, +57491=>16542, +134516=>16543, +57492=>16543, +21853=>16544, +57493=>16544, +21647=>16545, +57494=>16545, +21668=>16546, +57495=>16546, +18342=>16547, +57496=>16547, +136973=>16548, +57497=>16548, +134877=>16549, +57498=>16549, +15796=>16550, +57499=>16550, +134477=>16551, +57500=>16551, +166332=>16552, +57501=>16552, +140952=>16553, +57502=>16553, +21831=>16554, +57503=>16554, +19693=>16555, +57504=>16555, +21551=>16556, +57505=>16556, +29719=>16557, +57506=>16557, +21894=>16558, +57507=>16558, +21929=>16559, +57508=>16559, +137431=>16561, +57510=>16561, +147514=>16562, +57511=>16562, +17746=>16563, +57512=>16563, +148533=>16564, +57513=>16564, +26291=>16565, +57514=>16565, +135348=>16566, +57515=>16566, +22071=>16567, +57516=>16567, +26317=>16568, +57517=>16568, +144010=>16569, +57518=>16569, +26276=>16570, +57519=>16570, +22093=>16572, +57521=>16572, +22095=>16573, +57522=>16573, +30961=>16574, +57523=>16574, +22257=>16575, +57524=>16575, +38791=>16576, +57525=>16576, +21502=>16577, +57526=>16577, +22272=>16578, +57527=>16578, +22255=>16579, +57528=>16579, +22253=>16580, +57529=>16580, +166758=>16581, +57530=>16581, +13859=>16582, +57531=>16582, +135759=>16583, +57532=>16583, +22342=>16584, +57533=>16584, +147877=>16585, +57534=>16585, +27758=>16586, +57535=>16586, +28811=>16587, +57536=>16587, +22338=>16588, +57537=>16588, +14001=>16589, +57538=>16589, +158846=>16590, +57539=>16590, +22502=>16591, +57540=>16591, +136214=>16592, +57541=>16592, +22531=>16593, +57542=>16593, +136276=>16594, +57543=>16594, +148323=>16595, +57544=>16595, +22566=>16596, +57545=>16596, +150517=>16597, +57546=>16597, +22559=>16598, +22698=>16599, +57548=>16599, +13665=>16600, +57549=>16600, +22752=>16601, +57550=>16601, +22748=>16602, +57551=>16602, +135740=>16603, +57552=>16603, +22779=>16604, +57553=>16604, +23551=>16605, +57554=>16605, +22339=>16606, +57555=>16606, +172368=>16607, +57556=>16607, +148088=>16608, +57557=>16608, +37843=>16609, +57558=>16609, +13729=>16610, +57559=>16610, +22815=>16611, +57560=>16611, +26790=>16612, +57561=>16612, +14019=>16613, +57562=>16613, +28249=>16614, +57563=>16614, +136766=>16615, +57564=>16615, +23076=>16616, +57565=>16616, +136850=>16618, +57567=>16618, +34053=>16619, +57568=>16619, +22985=>16620, +57569=>16620, +134478=>16621, +57570=>16621, +158849=>16622, +57571=>16622, +159018=>16623, +57572=>16623, +137180=>16624, +57573=>16624, +23001=>16625, +57574=>16625, +137211=>16626, +57575=>16626, +137138=>16627, +57576=>16627, +159142=>16628, +57577=>16628, +28017=>16629, +57578=>16629, +137256=>16630, +57579=>16630, +136917=>16631, +57580=>16631, +23033=>16632, +57581=>16632, +159301=>16633, +57582=>16633, +23211=>16634, +57583=>16634, +23139=>16635, +57584=>16635, +14054=>16636, +57585=>16636, +149929=>16637, +57586=>16637, +14088=>16639, +57588=>16639, +23190=>16640, +57589=>16640, +29797=>16641, +57590=>16641, +23251=>16642, +57591=>16642, +159649=>16643, +57592=>16643, +140628=>16644, +57593=>16644, +137489=>16645, +57595=>16645, +14130=>16646, +57596=>16646, +136888=>16647, +57597=>16647, +24195=>16648, +57598=>16648, +21200=>16649, +57599=>16649, +23414=>16650, +57600=>16650, +25992=>16651, +57601=>16651, +23420=>16652, +57602=>16652, +162318=>16653, +57603=>16653, +16388=>16654, +57604=>16654, +18525=>16655, +57605=>16655, +131588=>16656, +57606=>16656, +23509=>16657, +57607=>16657, +137780=>16658, +57609=>16658, +154060=>16659, +57610=>16659, +132517=>16660, +57611=>16660, +23539=>16661, +57612=>16661, +23453=>16662, +57613=>16662, +19728=>16663, +57614=>16663, +23557=>16664, +57615=>16664, +138052=>16665, +57616=>16665, +23571=>16666, +57617=>16666, +29646=>16667, +57618=>16667, +23572=>16668, +57619=>16668, +138405=>16669, +57620=>16669, +158504=>16670, +57621=>16670, +23625=>16671, +57622=>16671, +18653=>16672, +57623=>16672, +23685=>16673, +57624=>16673, +23785=>16674, +57625=>16674, +23791=>16675, +57626=>16675, +23947=>16676, +57627=>16676, +138745=>16677, +57628=>16677, +138807=>16678, +57629=>16678, +23824=>16679, +57630=>16679, +23832=>16680, +57631=>16680, +23878=>16681, +57632=>16681, +138916=>16682, +57633=>16682, +23738=>16683, +57634=>16683, +24023=>16684, +57635=>16684, +33532=>16685, +57636=>16685, +14381=>16686, +57637=>16686, +149761=>16687, +57638=>16687, +139337=>16688, +57639=>16688, +139635=>16689, +57640=>16689, +33415=>16690, +57641=>16690, +14390=>16691, +57642=>16691, +15298=>16692, +57643=>16692, +24110=>16693, +57644=>16693, +27274=>16694, +57645=>16694, +57647=>16696, +148668=>16697, +57648=>16697, +134355=>16698, +57649=>16698, +21414=>16699, +57650=>16699, +20151=>16700, +57651=>16700, +21416=>16702, +57653=>16702, +137073=>16703, +57654=>16703, +24073=>16704, +57655=>16704, +57656=>16705, +164994=>16706, +57657=>16706, +24313=>16707, +57658=>16707, +24315=>16708, +57659=>16708, +14496=>16709, +57660=>16709, +24316=>16710, +57661=>16710, +26686=>16711, +57662=>16711, +37915=>16712, +57663=>16712, +24333=>16713, +57664=>16713, +131521=>16714, +57665=>16714, +194708=>16715, +57666=>16715, +15070=>16716, +57667=>16716, +135994=>16717, +57669=>16717, +24378=>16718, +57670=>16718, +157832=>16719, +57671=>16719, +140240=>16720, +57672=>16720, +140401=>16721, +57674=>16721, +24419=>16722, +57675=>16722, +159342=>16723, +57677=>16723, +24434=>16724, +57678=>16724, +37696=>16725, +57679=>16725, +166454=>16726, +57680=>16726, +24487=>16727, +57681=>16727, +23990=>16728, +57682=>16728, +15711=>16729, +57683=>16729, +152144=>16730, +57684=>16730, +139114=>16731, +57685=>16731, +159992=>16732, +57686=>16732, +140904=>16733, +57687=>16733, +37334=>16734, +57688=>16734, +131742=>16735, +57689=>16735, +166441=>16736, +57690=>16736, +24625=>16737, +57691=>16737, +26245=>16738, +57692=>16738, +14691=>16739, +57694=>16739, +15815=>16740, +57695=>16740, +13881=>16741, +57696=>16741, +22416=>16742, +57697=>16742, +141236=>16743, +57698=>16743, +31089=>16744, +57699=>16744, +15936=>16745, +57700=>16745, +24734=>16746, +57701=>16746, +24810=>16748, +149890=>16749, +57704=>16749, +149903=>16750, +57705=>16750, +162387=>16751, +57706=>16751, +29860=>16752, +57707=>16752, +20705=>16753, +57708=>16753, +23200=>16754, +57709=>16754, +24932=>16755, +57710=>16755, +24898=>16756, +57712=>16756, +194726=>16757, +57713=>16757, +159442=>16758, +57714=>16758, +24961=>16759, +57715=>16759, +20980=>16760, +57716=>16760, +132694=>16761, +57717=>16761, +24967=>16762, +57718=>16762, +23466=>16763, +57719=>16763, +147383=>16764, +57720=>16764, +141407=>16765, +57721=>16765, +25043=>16766, +57722=>16766, +166813=>16767, +57723=>16767, +170333=>16768, +57724=>16768, +25040=>16769, +57725=>16769, +14642=>16770, +57726=>16770, +141696=>16771, +57727=>16771, +141505=>16772, +57728=>16772, +24611=>16773, +57729=>16773, +24924=>16774, +57730=>16774, +25886=>16775, +57731=>16775, +25483=>16776, +57732=>16776, +131352=>16777, +57733=>16777, +25285=>16778, +57734=>16778, +137072=>16779, +57735=>16779, +25301=>16780, +57736=>16780, +142861=>16781, +57737=>16781, +25452=>16782, +57738=>16782, +149983=>16783, +57739=>16783, +14871=>16784, +57740=>16784, +25656=>16785, +57741=>16785, +25592=>16786, +57742=>16786, +136078=>16787, +57743=>16787, +137212=>16788, +57744=>16788, +28554=>16789, +57746=>16789, +142902=>16790, +57747=>16790, +153373=>16792, +57750=>16792, +25825=>16793, +57751=>16793, +25829=>16794, +57752=>16794, +38011=>16795, +57753=>16795, +14950=>16796, +57754=>16796, +25658=>16797, +57755=>16797, +14935=>16798, +57756=>16798, +25933=>16799, +57757=>16799, +28438=>16800, +57758=>16800, +150056=>16801, +57759=>16801, +150051=>16802, +57760=>16802, +25989=>16803, +57761=>16803, +25965=>16804, +57762=>16804, +25951=>16805, +57763=>16805, +26037=>16807, +57765=>16807, +149824=>16808, +57766=>16808, +19255=>16809, +57767=>16809, +26065=>16810, +57768=>16810, +16600=>16811, +57769=>16811, +137257=>16812, +57770=>16812, +57771=>16813, +26083=>16814, +57772=>16814, +24543=>16815, +57773=>16815, +144384=>16816, +57774=>16816, +26136=>16817, +57775=>16817, +57776=>16818, +143863=>16818, +57777=>16819, +143864=>16819, +26180=>16820, +57778=>16820, +57779=>16821, +143780=>16821, +57780=>16822, +143781=>16822, +26187=>16823, +57781=>16823, +134773=>16824, +57782=>16824, +26215=>16825, +57783=>16825, +152038=>16826, +57784=>16826, +26227=>16827, +57785=>16827, +64018=>16828, +143921=>16829, +57788=>16829, +165364=>16830, +57789=>16830, +143816=>16831, +57790=>16831, +152339=>16832, +57791=>16832, +30661=>16833, +57792=>16833, +141559=>16834, +57793=>16834, +39332=>16835, +57794=>16835, +26370=>16836, +57795=>16836, +148380=>16837, +57796=>16837, +150049=>16838, +57797=>16838, +27130=>16839, +57799=>16839, +145346=>16840, +57800=>16840, +194779=>16841, +26471=>16842, +57802=>16842, +26466=>16843, +57803=>16843, +147917=>16844, +57804=>16844, +168173=>16845, +57805=>16845, +26583=>16846, +57806=>16846, +17641=>16847, +57807=>16847, +26658=>16848, +57808=>16848, +28240=>16849, +57809=>16849, +37436=>16850, +57810=>16850, +26625=>16851, +57811=>16851, +144358=>16852, +57812=>16852, +159136=>16853, +57813=>16853, +26717=>16854, +57814=>16854, +144495=>16855, +57815=>16855, +27105=>16856, +57816=>16856, +27147=>16857, +57817=>16857, +166623=>16858, +57818=>16858, +26995=>16859, +57819=>16859, +26819=>16860, +57820=>16860, +144845=>16861, +57821=>16861, +26881=>16862, +57822=>16862, +26880=>16863, +57823=>16863, +14849=>16864, +57825=>16864, +144956=>16865, +57826=>16865, +15232=>16866, +57827=>16866, +26540=>16867, +57828=>16867, +26977=>16868, +57829=>16868, +166474=>16869, +57830=>16869, +17148=>16870, +57831=>16870, +26934=>16871, +57832=>16871, +27032=>16872, +57833=>16872, +15265=>16873, +57834=>16873, +132041=>16874, +57835=>16874, +33635=>16875, +57836=>16875, +20624=>16876, +57837=>16876, +27129=>16877, +57838=>16877, +144985=>16878, +57839=>16878, +139562=>16879, +57840=>16879, +27205=>16880, +57841=>16880, +145155=>16881, +57842=>16881, +27293=>16882, +57843=>16882, +15347=>16883, +57844=>16883, +26545=>16884, +57845=>16884, +27336=>16885, +57846=>16885, +168348=>16886, +57847=>16886, +15373=>16887, +57848=>16887, +27421=>16888, +57849=>16888, +133411=>16889, +57850=>16889, +24798=>16890, +60308=>16890, +57851=>16890, +27445=>16891, +57852=>16891, +27508=>16892, +57853=>16892, +141261=>16893, +57854=>16893, +28341=>16894, +57855=>16894, +57856=>16895, +146139=>16895, +137560=>16897, +57858=>16897, +14144=>16898, +57859=>16898, +21537=>16899, +57860=>16899, +146266=>16900, +57861=>16900, +27617=>16901, +57862=>16901, +147196=>16902, +57863=>16902, +27612=>16903, +57864=>16903, +27703=>16904, +57865=>16904, +140427=>16905, +57866=>16905, +149745=>16906, +57867=>16906, +158545=>16907, +57868=>16907, +27738=>16908, +57869=>16908, +33318=>16909, +57870=>16909, +27769=>16910, +57871=>16910, +146876=>16911, +57872=>16911, +17605=>16912, +57873=>16912, +146877=>16913, +57874=>16913, +147876=>16914, +57875=>16914, +149772=>16915, +57876=>16915, +149760=>16916, +57877=>16916, +146633=>16917, +57878=>16917, +14053=>16918, +57879=>16918, +15595=>16919, +57880=>16919, +134450=>16920, +57881=>16920, +39811=>16921, +57882=>16921, +143865=>16922, +57883=>16922, +140433=>16923, +57884=>16923, +32655=>16924, +57885=>16924, +26679=>16925, +57886=>16925, +159013=>16926, +57887=>16926, +159137=>16927, +57888=>16927, +159211=>16928, +57889=>16928, +28054=>16929, +57890=>16929, +27996=>16930, +57891=>16930, +28284=>16931, +57892=>16931, +28420=>16932, +57893=>16932, +149887=>16933, +57894=>16933, +147589=>16934, +57895=>16934, +159346=>16935, +57896=>16935, +34099=>16936, +57897=>16936, +159604=>16937, +57898=>16937, +20935=>16938, +57899=>16938, +33838=>16941, +57902=>16941, +166689=>16942, +57903=>16942, +194824=>16943, +146991=>16944, +57905=>16944, +29779=>16945, +57906=>16945, +147330=>16946, +57907=>16946, +31180=>16947, +57908=>16947, +28239=>16948, +57909=>16948, +23185=>16949, +57910=>16949, +143435=>16950, +57911=>16950, +28664=>16951, +57912=>16951, +14093=>16952, +57913=>16952, +28573=>16953, +57914=>16953, +146992=>16954, +57915=>16954, +28410=>16955, +57916=>16955, +136343=>16956, +57917=>16956, +147517=>16957, +57918=>16957, +17749=>16958, +57919=>16958, +37872=>16959, +57920=>16959, +28484=>16960, +57921=>16960, +28508=>16961, +57922=>16961, +15694=>16962, +57923=>16962, +28532=>16963, +57924=>16963, +168304=>16964, +57925=>16964, +15675=>16965, +57926=>16965, +28575=>16966, +57927=>16966, +147780=>16967, +57928=>16967, +28627=>16968, +57929=>16968, +147601=>16969, +57930=>16969, +147797=>16970, +57931=>16970, +147513=>16971, +57932=>16971, +147440=>16972, +57933=>16972, +147380=>16973, +57934=>16973, +147775=>16974, +57935=>16974, +20959=>16975, +57936=>16975, +57937=>16976, +147798=>16976, +57938=>16977, +147799=>16977, +147776=>16978, +57939=>16978, +156125=>16979, +57940=>16979, +28747=>16980, +57941=>16980, +28798=>16981, +57942=>16981, +28839=>16982, +57943=>16982, +28876=>16984, +57945=>16984, +28885=>16985, +57946=>16985, +28886=>16986, +57947=>16986, +28895=>16987, +57948=>16987, +16644=>16988, +57949=>16988, +15848=>16989, +57950=>16989, +29108=>16990, +57951=>16990, +29078=>16991, +57952=>16991, +148087=>16992, +57953=>16992, +28971=>16993, +57954=>16993, +28997=>16994, +57955=>16994, +23176=>16995, +57956=>16995, +29002=>16996, +57957=>16996, +64072=>16997, +148325=>16998, +57960=>16998, +29007=>16999, +57961=>16999, +37730=>17000, +57962=>17000, +148161=>17001, +57963=>17001, +28972=>17002, +57964=>17002, +148570=>17003, +57965=>17003, +150055=>17004, +57966=>17004, +150050=>17005, +57967=>17005, +29114=>17006, +57968=>17006, +166888=>17007, +57969=>17007, +28861=>17008, +57970=>17008, +29198=>17009, +57971=>17009, +37954=>17010, +57972=>17010, +29205=>17011, +57973=>17011, +22801=>17012, +57974=>17012, +37955=>17013, +57975=>17013, +29220=>17014, +57976=>17014, +37697=>17015, +57977=>17015, +153093=>17016, +57978=>17016, +29230=>17017, +57979=>17017, +29248=>17018, +57980=>17018, +149876=>17019, +57981=>17019, +26813=>17020, +57982=>17020, +29269=>17021, +57983=>17021, +29271=>17022, +57984=>17022, +15957=>17023, +57985=>17023, +143428=>17024, +57986=>17024, +26637=>17025, +57987=>17025, +28477=>17026, +57988=>17026, +29314=>17027, +57989=>17027, +29483=>17029, +57991=>17029, +149539=>17030, +57992=>17030, +165931=>17031, +57993=>17031, +18669=>17032, +57994=>17032, +165892=>17033, +57995=>17033, +29480=>17034, +57996=>17034, +29486=>17035, +57997=>17035, +29647=>17036, +57998=>17036, +29610=>17037, +57999=>17037, +134202=>17038, +58000=>17038, +158254=>17039, +58001=>17039, +29641=>17040, +58002=>17040, +29769=>17041, +58003=>17041, +147938=>17042, +58004=>17042, +136935=>17043, +58005=>17043, +150052=>17044, +58006=>17044, +26147=>17045, +58007=>17045, +14021=>17046, +58008=>17046, +149943=>17047, +58009=>17047, +149901=>17048, +58010=>17048, +150011=>17049, +58011=>17049, +29687=>17050, +58012=>17050, +29717=>17051, +58013=>17051, +26883=>17052, +58014=>17052, +150054=>17053, +58015=>17053, +29753=>17054, +58016=>17054, +16087=>17055, +58018=>17055, +194863=>17056, +141485=>17057, +58020=>17057, +29792=>17058, +58021=>17058, +167602=>17059, +58022=>17059, +29767=>17060, +58023=>17060, +29668=>17061, +58024=>17061, +29814=>17062, +58025=>17062, +33721=>17063, +58026=>17063, +29804=>17064, +58027=>17064, +29812=>17065, +58029=>17065, +37873=>17066, +58030=>17066, +27180=>17067, +58031=>17067, +29826=>17068, +58032=>17068, +18771=>17069, +58033=>17069, +150156=>17070, +58034=>17070, +147807=>17071, +58035=>17071, +150137=>17072, +58036=>17072, +166799=>17073, +58037=>17073, +23366=>17074, +58038=>17074, +166915=>17075, +58039=>17075, +137374=>17076, +58040=>17076, +29896=>17077, +58041=>17077, +137608=>17078, +58042=>17078, +29966=>17079, +58043=>17079, +29982=>17080, +58045=>17080, +167641=>17081, +58046=>17081, +137803=>17082, +58047=>17082, +23511=>17083, +58048=>17083, +167596=>17084, +58049=>17084, +37765=>17085, +58050=>17085, +30029=>17086, +58051=>17086, +30026=>17087, +58052=>17087, +30055=>17088, +58053=>17088, +30062=>17089, +58054=>17089, +151426=>17090, +58055=>17090, +16132=>17091, +58056=>17091, +150803=>17092, +58057=>17092, +30094=>17093, +58058=>17093, +29789=>17094, +58059=>17094, +30110=>17095, +58060=>17095, +30132=>17096, +58061=>17096, +30210=>17097, +58062=>17097, +30252=>17098, +58063=>17098, +30289=>17099, +58064=>17099, +30287=>17100, +58065=>17100, +30319=>17101, +58066=>17101, +58067=>17102, +156661=>17103, +58068=>17103, +30352=>17104, +58069=>17104, +33263=>17105, +58070=>17105, +14328=>17106, +58071=>17106, +157969=>17107, +58072=>17107, +157966=>17108, +58073=>17108, +30369=>17109, +58074=>17109, +30373=>17110, +58075=>17110, +30391=>17111, +58076=>17111, +30412=>17112, +58077=>17112, +159647=>17113, +58078=>17113, +33890=>17114, +58079=>17114, +151709=>17115, +58080=>17115, +151933=>17116, +58081=>17116, +138780=>17117, +58082=>17117, +30494=>17118, +58083=>17118, +30502=>17119, +58084=>17119, +30528=>17120, +58085=>17120, +25775=>17121, +58086=>17121, +152096=>17122, +58087=>17122, +30552=>17123, +58088=>17123, +144044=>17124, +58089=>17124, +30639=>17125, +58090=>17125, +166244=>17126, +58091=>17126, +166248=>17127, +58092=>17127, +136897=>17128, +58093=>17128, +30708=>17129, +58094=>17129, +26826=>17131, +58098=>17131, +30895=>17132, +58099=>17132, +30919=>17133, +58100=>17133, +30931=>17134, +58101=>17134, +38565=>17135, +58102=>17135, +31022=>17136, +58103=>17136, +153056=>17137, +58104=>17137, +30935=>17138, +58105=>17138, +31028=>17139, +58106=>17139, +30897=>17140, +58107=>17140, +161292=>17141, +58108=>17141, +36792=>17142, +58109=>17142, +34948=>17143, +58110=>17143, +140828=>17144, +58113=>17144, +31110=>17145, +58114=>17145, +35072=>17146, +58115=>17146, +26882=>17147, +58116=>17147, +31104=>17148, +58117=>17148, +153687=>17149, +58118=>17149, +31133=>17150, +58119=>17150, +162617=>17151, +58120=>17151, +31036=>17152, +58121=>17152, +31145=>17153, +58122=>17153, +28202=>17154, +58123=>17154, +160038=>17155, +58124=>17155, +16040=>17156, +58125=>17156, +31174=>17157, +58126=>17157, +168205=>17158, +58127=>17158, +31188=>17159, +58128=>17159, +21797=>17161, +62526=>17161, +134210=>17163, +62528=>17163, +134421=>17164, +62529=>17164, +151851=>17165, +62530=>17165, +21904=>17166, +62531=>17166, +142534=>17167, +62532=>17167, +14828=>17168, +62533=>17168, +131905=>17169, +62534=>17169, +36422=>17170, +62535=>17170, +150968=>17171, +62536=>17171, +169189=>17172, +62537=>17172, +164030=>17174, +62539=>17174, +30586=>17175, +62540=>17175, +142392=>17176, +62541=>17176, +14900=>17177, +62542=>17177, +18389=>17178, +62543=>17178, +164189=>17179, +62544=>17179, +158194=>17180, +62545=>17180, +151018=>17181, +62546=>17181, +25821=>17182, +62547=>17182, +134524=>17183, +62548=>17183, +135092=>17184, +62549=>17184, +134357=>17185, +62550=>17185, +25741=>17187, +62552=>17187, +36478=>17188, +62553=>17188, +134806=>17189, +62554=>17189, +135012=>17191, +62556=>17191, +142505=>17192, +62557=>17192, +164438=>17193, +62558=>17193, +148691=>17194, +62559=>17194, +134470=>17196, +62561=>17196, +170573=>17197, +62562=>17197, +164073=>17198, +62563=>17198, +18420=>17199, +62564=>17199, +151207=>17200, +62565=>17200, +142530=>17201, +62566=>17201, +39602=>17202, +62567=>17202, +14951=>17203, +62568=>17203, +169460=>17204, +62569=>17204, +16365=>17205, +62570=>17205, +13574=>17206, +62571=>17206, +152263=>17207, +62572=>17207, +169940=>17208, +62573=>17208, +142660=>17210, +62575=>17210, +40302=>17211, +62576=>17211, +38933=>17212, +62577=>17212, +17369=>17214, +62579=>17214, +25780=>17216, +62581=>17216, +21731=>17217, +62582=>17217, +62584=>17219, +142282=>17219, +14843=>17221, +62586=>17221, +157402=>17223, +62588=>17223, +157462=>17224, +62589=>17224, +162208=>17225, +62590=>17225, +25834=>17226, +62591=>17226, +151634=>17227, +62592=>17227, +134211=>17228, +62593=>17228, +36456=>17229, +62594=>17229, +166732=>17231, +62596=>17231, +132913=>17232, +62597=>17232, +18443=>17234, +62599=>17234, +131497=>17235, +62600=>17235, +16378=>17236, +62601=>17236, +22643=>17237, +62602=>17237, +142733=>17238, +62603=>17238, +148936=>17240, +62605=>17240, +132348=>17241, +62606=>17241, +155799=>17242, +62607=>17242, +134988=>17243, +62608=>17243, +21881=>17245, +62610=>17245, +17338=>17247, +62612=>17247, +19124=>17249, +62614=>17249, +141926=>17250, +62615=>17250, +135325=>17251, +62616=>17251, +33194=>17252, +62617=>17252, +39157=>17253, +62618=>17253, +134556=>17254, +62619=>17254, +25465=>17255, +62620=>17255, +14846=>17256, +62621=>17256, +141173=>17257, +62622=>17257, +36288=>17258, +62623=>17258, +22177=>17259, +62624=>17259, +25724=>17260, +62625=>17260, +15939=>17261, +62626=>17261, +173569=>17263, +62628=>17263, +134665=>17264, +62629=>17264, +142031=>17265, +62630=>17265, +135368=>17268, +62633=>17268, +145858=>17269, +62634=>17269, +14738=>17270, +62635=>17270, +14854=>17271, +62636=>17271, +164507=>17272, +62637=>17272, +13688=>17273, +62638=>17273, +155209=>17274, +62639=>17274, +139463=>17275, +62640=>17275, +142514=>17278, +62643=>17278, +169760=>17279, +62644=>17279, +13500=>17280, +62645=>17280, +27709=>17281, +62646=>17281, +151099=>17282, +62647=>17282, +161140=>17285, +62650=>17285, +142987=>17286, +62651=>17286, +139784=>17287, +62652=>17287, +173659=>17288, +62653=>17288, +167117=>17289, +62654=>17289, +134778=>17290, +62655=>17290, +134196=>17291, +62656=>17291, +161337=>17292, +62683=>17292, +142286=>17293, +62684=>17293, +62687=>17294, +142417=>17294, +14872=>17295, +62689=>17295, +62691=>17296, +135367=>17296, +62693=>17297, +173618=>17297, +167122=>17298, +62695=>17298, +167321=>17299, +62696=>17299, +167114=>17300, +62697=>17300, +38314=>17301, +62698=>17301, +62706=>17303, +161630=>17303, +28992=>17304, +62708=>17304, +20822=>17306, +62385=>17306, +20222=>17307, +20616=>17308, +62487=>17308, +13459=>17310, +62489=>17310, +20870=>17311, +62491=>17311, +24130=>17312, +63037=>17312, +20997=>17313, +62495=>17313, +21031=>17314, +62436=>17314, +21113=>17315, +62497=>17315, +194600=>17316, +13651=>17317, +62504=>17317, +21442=>17318, +62505=>17318, +21343=>17319, +62715=>17319, +21823=>17321, +62520=>17321, +21976=>17323, +59986=>17323, +13789=>17324, +62722=>17324, +22049=>17325, +63067=>17325, +22100=>17327, +60044=>17327, +60148=>17328, +135291=>17328, +60153=>17330, +135379=>17330, +61095=>17332, +135934=>17332, +14265=>17335, +60104=>17335, +23745=>17336, +61099=>17336, +23829=>17337, +63066=>17337, +23894=>17338, +63030=>17338, +14392=>17339, +63036=>17339, +20097=>17340, +62477=>17340, +24253=>17341, +63038=>17341, +14612=>17342, +63042=>17342, +25017=>17343, +63050=>17343, +25232=>17344, +63054=>17344, +25368=>17345, +63056=>17345, +25690=>17346, +63063=>17346, +25745=>17347, +62381=>17347, +33133=>17348, +62709=>17348, +33156=>17349, +59922=>17349, +33171=>17350, +59924=>17350, +26624=>17351, +63080=>17351, +15292=>17352, +63093=>17352, +29327=>17353, +60517=>17353, +29389=>17354, +59781=>17354, +149487=>17355, +29497=>17356, +59785=>17356, +30018=>17357, +59811=>17357, +30172=>17358, +59817=>17358, +16320=>17359, +59818=>17359, +60278=>17360, +151205=>17360, +16343=>17361, +59820=>17361, +30336=>17363, +30348=>17364, +59824=>17364, +151388=>17364, +16552=>17365, +59845=>17365, +30777=>17366, +59846=>17366, +16643=>17367, +59855=>17367, +31377=>17368, +59863=>17368, +31771=>17369, +59876=>17369, +31981=>17370, +59884=>17370, +32659=>17371, +62658=>17371, +32686=>17372, +59892=>17372, +33535=>17374, +59936=>17374, +22623=>17375, +59981=>17375, +34482=>17376, +59960=>17376, +17836=>17377, +34699=>17378, +59963=>17378, +35143=>17379, +59969=>17379, +35369=>17381, +59972=>17381, +36465=>17383, +59988=>17383, +60484=>17384, +164233=>17384, +36528=>17385, +59990=>17385, +37214=>17387, +62443=>17387, +37260=>17388, +62441=>17388, +39182=>17389, +60051=>17389, +39196=>17390, +60054=>17390, +39809=>17393, +60066=>17393, +40384=>17394, +60080=>17394, +40339=>17395, +60078=>17395, +40620=>17396, +60085=>17396, +19857=>17397, +60540=>17397, +37818=>17399, +40571=>17400, +60084=>17400, +28809=>17401, +63148=>17401, +29512=>17402, +59788=>17402, +31129=>17404, +59858=>17404, +36791=>17405, +59997=>17405, +39234=>17407, +60056=>17407, +8364=>17601, +12443=>17606, +63518=>17606, +12444=>17607, +63519=>17607, +11904=>17608, +63520=>17608, +12736=>17609, +62211=>17609, +12737=>17610, +62212=>17610, +12738=>17611, +62213=>17611, +12739=>17612, +62214=>17612, +12740=>17613, +62215=>17613, +131340=>17614, +62216=>17614, +12741=>17615, +62217=>17615, +131281=>17616, +62218=>17616, +131277=>17617, +62219=>17617, +12742=>17618, +62220=>17618, +12743=>17619, +62221=>17619, +131275=>17620, +62222=>17620, +139240=>17621, +62223=>17621, +12744=>17622, +62224=>17622, +131274=>17623, +62225=>17623, +12745=>17624, +62226=>17624, +12746=>17625, +62227=>17625, +12747=>17626, +62228=>17626, +12748=>17627, +62229=>17627, +131342=>17628, +62230=>17628, +12749=>17629, +62231=>17629, +12750=>17630, +62232=>17630, +62776=>17631, +62777=>17632, +138177=>17633, +62778=>17633, +194680=>17634, +62779=>17634, +12205=>17635, +38737=>17635, +62780=>17635, +131206=>17636, +62781=>17636, +20059=>17637, +62782=>17637, +20155=>17638, +62783=>17638, +13630=>17639, +62784=>17639, +23587=>17640, +62785=>17640, +24401=>17641, +62786=>17641, +24516=>17642, +62787=>17642, +14586=>17643, +62788=>17643, +25164=>17644, +62789=>17644, +25909=>17645, +62790=>17645, +27514=>17646, +62791=>17646, +27701=>17647, +62792=>17647, +27706=>17648, +62793=>17648, +28780=>17649, +62794=>17649, +29227=>17650, +62795=>17650, +20012=>17651, +62796=>17651, +29357=>17652, +62797=>17652, +149737=>17653, +62798=>17653, +32594=>17654, +62799=>17654, +31035=>17655, +62800=>17655, +31993=>17656, +62801=>17656, +32595=>17657, +62802=>17657, +156266=>17658, +62803=>17658, +13505=>17659, +62804=>17659, +156491=>17660, +62806=>17660, +32770=>17661, +62807=>17661, +32896=>17662, +62808=>17662, +157202=>17663, +62809=>17663, +158033=>17664, +62810=>17664, +21341=>17665, +62811=>17665, +34916=>17666, +62812=>17666, +35265=>17667, +62813=>17667, +161970=>17668, +62814=>17668, +35744=>17669, +62815=>17669, +36125=>17670, +62816=>17670, +38021=>17671, +62817=>17671, +38264=>17672, +62818=>17672, +38271=>17673, +62819=>17673, +38376=>17674, +62820=>17674, +167439=>17675, +62821=>17675, +38886=>17676, +62822=>17676, +39029=>17677, +62823=>17677, +39118=>17678, +62824=>17678, +39134=>17679, +62825=>17679, +39267=>17680, +62826=>17680, +170000=>17681, +62827=>17681, +40060=>17682, +62828=>17682, +40479=>17683, +62829=>17683, +40644=>17684, +62830=>17684, +27503=>17685, +62831=>17685, +63751=>17686, +62832=>17686, +20023=>17687, +62833=>17687, +131207=>17688, +62834=>17688, +38429=>17689, +62835=>17689, +25143=>17690, +62836=>17690, +38050=>17691, +62837=>17691, +11908=>17692, +63521=>17692, +11910=>17693, +63522=>17693, +11911=>17694, +63523=>17694, +11912=>17695, +63524=>17695, +11914=>17696, +63525=>17696, +11916=>17697, +63526=>17697, +11917=>17698, +63527=>17698, +11925=>17699, +63528=>17699, +11932=>17700, +63529=>17700, +11941=>17701, +63531=>17701, +11943=>17702, +63532=>17702, +11946=>17703, +63533=>17703, +11948=>17704, +63534=>17704, +11950=>17705, +63535=>17705, +11958=>17706, +63536=>17706, +11964=>17707, +63537=>17707, +11966=>17708, +63538=>17708, +11978=>17709, +63540=>17709, +11980=>17710, +63541=>17710, +11981=>17711, +63542=>17711, +11983=>17712, +63543=>17712, +11990=>17713, +63544=>17713, +11991=>17714, +63545=>17714, +11998=>17715, +63546=>17715, +172969=>17716, +62368=>17716, +135493=>17717, +62369=>17717, +25866=>17718, +62371=>17718, +20029=>17719, +62374=>17719, +28381=>17720, +62375=>17720, +40270=>17721, +62376=>17721, +37343=>17722, +62377=>17722, +62380=>17723, +161589=>17723, +20250=>17724, +62382=>17724, +20264=>17725, +62383=>17725, +20392=>17726, +62384=>17726, +20852=>17727, +62386=>17727, +20892=>17728, +62387=>17728, +20964=>17729, +62388=>17729, +21153=>17730, +62389=>17730, +21160=>17731, +62390=>17731, +21307=>17732, +62391=>17732, +21326=>17733, +62392=>17733, +21457=>17734, +62393=>17734, +21464=>17735, +62394=>17735, +22242=>17736, +62395=>17736, +22768=>17737, +62396=>17737, +22788=>17738, +62397=>17738, +22791=>17739, +62398=>17739, +22834=>17740, +62399=>17740, +22836=>17741, +62400=>17741, +23398=>17742, +62401=>17742, +23454=>17743, +62402=>17743, +23455=>17744, +62403=>17744, +23706=>17745, +62404=>17745, +24198=>17746, +62405=>17746, +24635=>17747, +62406=>17747, +25993=>17748, +62407=>17748, +26622=>17749, +62408=>17749, +26628=>17750, +62409=>17750, +26725=>17751, +62410=>17751, +27982=>17752, +62411=>17752, +28860=>17753, +62412=>17753, +30005=>17754, +62413=>17754, +32420=>17755, +62414=>17755, +32428=>17756, +62415=>17756, +32442=>17757, +62416=>17757, +32455=>17758, +62417=>17758, +32463=>17759, +62418=>17759, +32479=>17760, +62419=>17760, +32518=>17761, +62420=>17761, +32567=>17762, +62421=>17762, +33402=>17763, +62422=>17763, +33487=>17764, +62423=>17764, +33647=>17765, +62424=>17765, +35270=>17766, +62425=>17766, +35774=>17767, +62426=>17767, +35810=>17768, +62427=>17768, +36710=>17769, +62428=>17769, +36711=>17770, +62429=>17770, +36718=>17771, +62430=>17771, +29713=>17772, +62431=>17772, +31996=>17773, +62432=>17773, +32205=>17774, +62433=>17774, +26950=>17775, +62434=>17775, +31433=>17776, +62435=>17776, +30904=>17777, +62442=>17777, +32956=>17778, +62444=>17778, +36107=>17779, +62446=>17779, +33014=>17780, +62447=>17780, +133607=>17781, +62448=>17781, +32927=>17782, +62451=>17782, +40647=>17783, +62452=>17783, +19661=>17784, +62453=>17784, +40393=>17785, +62454=>17785, +40460=>17786, +62455=>17786, +19518=>17787, +62456=>17787, +171510=>17788, +62457=>17788, +159758=>17789, +62458=>17789, +40458=>17790, +62459=>17790, +172339=>17791, +62460=>17791, +13761=>17792, +62461=>17792, +28314=>17793, +62463=>17793, +33342=>17794, +62464=>17794, +29977=>17795, +62465=>17795, +18705=>17796, +62467=>17796, +39532=>17797, +62468=>17797, +39567=>17798, +62469=>17798, +40857=>17799, +62470=>17799, +31111=>17800, +62471=>17800, +164972=>17801, +62472=>17801, +138698=>17802, +62473=>17802, +132560=>17803, +62474=>17803, +142054=>17804, +62475=>17804, +20004=>17805, +62476=>17805, +20096=>17806, +62478=>17806, +20103=>17807, +62479=>17807, +20159=>17808, +62480=>17808, +20203=>17809, +62481=>17809, +20279=>17810, +62482=>17810, +13388=>17811, +62483=>17811, +20413=>17812, +62484=>17812, +15944=>17813, +62485=>17813, +20483=>17814, +62486=>17814, +13437=>17815, +62488=>17815, +13477=>17816, +62490=>17816, +22789=>17817, +62492=>17817, +20955=>17818, +62493=>17818, +20988=>17819, +62494=>17819, +20105=>17820, +62496=>17820, +21136=>17821, +62498=>17821, +21287=>17822, +62499=>17822, +13767=>17823, +62500=>17823, +21417=>17824, +62501=>17824, +13649=>17825, +62502=>17825, +21424=>17826, +62503=>17826, +21539=>17827, +62506=>17827, +13677=>17828, +62507=>17828, +13682=>17829, +62508=>17829, +13953=>17830, +62509=>17830, +21651=>17831, +62510=>17831, +21667=>17832, +62511=>17832, +21684=>17833, +62512=>17833, +21689=>17834, +62513=>17834, +21712=>17835, +62514=>17835, +21743=>17836, +62515=>17836, +21784=>17837, +62516=>17837, +21795=>17838, +62517=>17838, +21800=>17839, +62518=>17839, +13720=>17840, +62519=>17840, +13733=>17841, +62521=>17841, +13759=>17842, +62522=>17842, +21975=>17843, +62523=>17843, +13765=>17844, +62524=>17844, +163204=>17845, +62525=>17845, +16467=>17846, +62538=>17846, +62551=>17847, +135412=>17847, +62555=>17848, +134155=>17848, +62574=>17849, +161992=>17849, +62580=>17850, +155813=>17850, +62583=>17851, +142668=>17851, +62585=>17852, +135287=>17852, +62587=>17853, +135279=>17853, +62595=>17854, +139681=>17854, +62609=>17855, +134550=>17855, +16571=>17856, +62611=>17856, +62631=>17857, +142537=>17857, +22098=>17858, +62641=>17858, +134961=>17859, +62642=>17859, +62657=>17860, +157724=>17860, +135375=>17861, +62659=>17861, +141315=>17862, +62660=>17862, +141625=>17863, +62661=>17863, +13819=>17864, +62662=>17864, +152035=>17865, +62663=>17865, +134796=>17866, +62664=>17866, +135053=>17867, +62665=>17867, +134826=>17868, +62666=>17868, +16275=>17869, +62667=>17869, +134960=>17870, +62668=>17870, +134471=>17871, +62669=>17871, +135503=>17872, +62670=>17872, +134732=>17873, +62671=>17873, +134827=>17874, +62673=>17874, +134057=>17875, +62674=>17875, +134472=>17876, +62675=>17876, +135360=>17877, +62676=>17877, +135485=>17878, +62677=>17878, +16377=>17879, +62678=>17879, +140950=>17880, +62679=>17880, +25650=>17881, +62680=>17881, +135085=>17882, +62681=>17882, +144372=>17883, +62682=>17883, +62685=>17884, +134526=>17884, +62686=>17885, +134527=>17885, +62688=>17886, +142421=>17886, +62690=>17887, +134808=>17887, +62692=>17888, +134958=>17888, +62694=>17889, +158544=>17889, +21708=>17890, +62699=>17890, +33476=>17891, +62700=>17891, +21945=>17892, +62701=>17892, +171715=>17893, +62703=>17893, +39974=>17894, +62704=>17894, +39606=>17895, +62705=>17895, +62707=>17896, +142830=>17896, +33004=>17897, +62710=>17897, +23580=>17898, +62711=>17898, +157042=>17899, +62712=>17899, +33076=>17900, +62713=>17900, +14231=>17901, +62714=>17901, +164029=>17902, +62716=>17902, +37302=>17903, +62717=>17903, +134906=>17904, +62718=>17904, +134671=>17905, +62719=>17905, +134775=>17906, +62720=>17906, +134907=>17907, +62721=>17907, +151019=>17908, +62723=>17908, +13833=>17909, +62724=>17909, +134358=>17910, +62725=>17910, +22191=>17911, +62726=>17911, +141237=>17912, +62727=>17912, +135369=>17913, +62728=>17913, +134672=>17914, +62729=>17914, +134776=>17915, +62730=>17915, +135288=>17916, +62731=>17916, +135496=>17917, +62732=>17917, +164359=>17918, +62733=>17918, +136277=>17919, +62734=>17919, +134777=>17920, +62735=>17920, +151120=>17921, +62736=>17921, +142756=>17922, +62737=>17922, +23124=>17923, +62738=>17923, +62739=>17924, +135197=>17924, +62740=>17925, +135198=>17925, +62741=>17926, +135413=>17926, +62742=>17927, +135414=>17927, +22428=>17928, +62743=>17928, +134673=>17929, +62744=>17929, +161428=>17930, +62745=>17930, +164557=>17931, +62746=>17931, +135093=>17932, +62747=>17932, +134779=>17933, +62748=>17933, +151934=>17934, +62749=>17934, +14083=>17935, +62750=>17935, +135094=>17936, +62751=>17936, +135552=>17937, +62752=>17937, +152280=>17938, +62753=>17938, +172733=>17939, +62754=>17939, +149978=>17940, +62755=>17940, +137274=>17941, +62756=>17941, +147831=>17942, +62757=>17942, +164476=>17943, +62758=>17943, +22681=>17944, +62759=>17944, +21096=>17945, +62760=>17945, +13850=>17946, +62761=>17946, +153405=>17947, +62762=>17947, +31666=>17948, +62763=>17948, +23400=>17949, +62764=>17949, +18432=>17950, +62765=>17950, +19244=>17951, +62766=>17951, +40743=>17952, +62767=>17952, +18919=>17953, +62768=>17953, +39967=>17954, +62769=>17954, +39821=>17955, +62770=>17955, +154484=>17956, +62771=>17956, +143677=>17957, +62772=>17957, +22011=>17958, +62773=>17958, +13810=>17959, +62774=>17959, +22153=>17960, +62775=>17960, +23870=>17961, +63028=>17961, +23880=>17962, +63029=>17962, +15868=>17963, +63031=>17963, +14351=>17964, +63032=>17964, +23972=>17965, +63033=>17965, +23993=>17966, +63034=>17966, +14368=>17967, +63035=>17967, +24357=>17968, +63039=>17968, +24451=>17969, +63040=>17969, +14600=>17970, +63041=>17970, +14655=>17971, +63043=>17971, +14669=>17972, +63044=>17972, +24791=>17973, +63045=>17973, +24893=>17974, +63046=>17974, +23781=>17975, +63047=>17975, +14729=>17976, +63048=>17976, +25015=>17977, +63049=>17977, +25039=>17978, +63051=>17978, +14776=>17979, +63052=>17979, +25132=>17980, +63053=>17980, +25317=>17981, +63055=>17981, +14840=>17982, +63057=>17982, +22193=>17983, +63058=>17983, +14851=>17984, +63059=>17984, +25570=>17985, +63060=>17985, +25595=>17986, +63061=>17986, +25607=>17987, +63062=>17987, +14923=>17988, +63064=>17988, +25792=>17989, +63065=>17989, +40863=>17990, +63068=>17990, +14999=>17991, +63069=>17991, +25990=>17992, +63070=>17992, +15037=>17993, +63071=>17993, +26111=>17994, +63072=>17994, +26195=>17995, +63073=>17995, +15090=>17996, +63074=>17996, +26258=>17997, +63075=>17997, +15138=>17998, +63076=>17998, +26390=>17999, +63077=>17999, +15170=>18000, +63078=>18000, +26532=>18001, +63079=>18001, +15192=>18002, +63081=>18002, +26698=>18003, +63082=>18003, +26756=>18004, +63083=>18004, +15218=>18005, +63084=>18005, +15217=>18006, +63085=>18006, +15227=>18007, +63086=>18007, +26889=>18008, +63087=>18008, +26947=>18009, +63088=>18009, +29276=>18010, +63089=>18010, +26980=>18011, +63090=>18011, +27039=>18012, +63091=>18012, +27013=>18013, +63092=>18013, +27094=>18014, +63094=>18014, +15325=>18015, +63095=>18015, +27237=>18016, +63096=>18016, +27252=>18017, +63097=>18017, +27249=>18018, +63098=>18018, +27266=>18019, +63099=>18019, +15340=>18020, +63100=>18020, +27289=>18021, +63101=>18021, +15346=>18022, +63102=>18022, +27307=>18023, +63103=>18023, +27317=>18024, +63104=>18024, +27348=>18025, +63105=>18025, +27382=>18026, +63106=>18026, +27521=>18027, +63107=>18027, +27585=>18028, +63108=>18028, +27626=>18029, +63109=>18029, +27765=>18030, +63110=>18030, +27818=>18031, +63111=>18031, +15563=>18032, +63112=>18032, +27906=>18033, +63113=>18033, +27910=>18034, +63114=>18034, +27942=>18035, +63115=>18035, +28033=>18036, +63116=>18036, +15599=>18037, +63117=>18037, +28068=>18038, +63118=>18038, +28081=>18039, +63119=>18039, +28181=>18040, +63120=>18040, +28184=>18041, +63121=>18041, +28201=>18042, +63122=>18042, +28294=>18043, +63123=>18043, +166336=>18044, +63124=>18044, +28347=>18045, +63125=>18045, +28386=>18046, +63126=>18046, +28378=>18047, +63127=>18047, +40831=>18048, +63128=>18048, +28392=>18049, +63129=>18049, +28393=>18050, +63130=>18050, +28452=>18051, +63131=>18051, +28468=>18052, +63132=>18052, +15686=>18053, +63133=>18053, +147265=>18054, +63134=>18054, +28545=>18055, +63135=>18055, +28606=>18056, +63136=>18056, +15722=>18057, +63137=>18057, +15733=>18058, +63138=>18058, +29111=>18059, +63139=>18059, +23705=>18060, +63140=>18060, +15754=>18061, +63141=>18061, +28716=>18062, +63142=>18062, +15761=>18063, +63143=>18063, +28752=>18064, +63144=>18064, +28756=>18065, +63145=>18065, +28783=>18066, +63146=>18066, +28799=>18067, +63147=>18067, +131877=>18068, +63149=>18068, +17345=>18069, +63150=>18069, +13809=>18070, +63151=>18070, +134872=>18071, +63152=>18071, +13902=>18072, +58134=>18072, +15789=>18073, +58172=>18073, +154725=>18074, +58173=>18074, +26237=>18075, +58183=>18075, +31860=>18076, +58188=>18076, +29837=>18077, +58197=>18077, +32402=>18078, +58215=>18078, +17667=>18079, +58232=>18079, +58260=>18080, +151480=>18080, +58270=>18081, +133901=>18081, +58277=>18082, +158474=>18082, +13438=>18083, +58311=>18083, +58317=>18084, +143087=>18084, +58325=>18085, +146613=>18085, +58343=>18086, +159385=>18086, +34673=>18087, +58364=>18087, +25537=>18088, +58385=>18088, +30583=>18089, +58387=>18089, +35210=>18090, +58390=>18090, +58406=>18091, +147343=>18091, +35660=>18092, +58415=>18092, +58440=>18093, +150729=>18093, +18730=>18094, +58464=>18094, +172052=>18095, +58471=>18095, +165564=>18096, +58472=>18096, +165121=>18097, +58473=>18097, +15088=>18098, +58490=>18098, +28815=>18099, +58511=>18099, +58529=>18100, +140922=>18100, +58637=>18101, +158120=>18101, +58646=>18102, +148043=>18102, +26760=>18103, +58662=>18103, +58664=>18104, +139611=>18104, +40802=>18105, +58702=>18105, +37830=>18106, +58793=>18106, +58802=>18107, +131967=>18107, +37734=>18108, +58888=>18108, +37519=>18109, +58901=>18109, +34324=>18110, +58954=>18110, +58986=>18111, +173147=>18111, +16784=>18112, +59010=>18112, +26511=>18113, +59045=>18113, +26654=>18114, +59048=>18114, +14435=>18115, +59051=>18115, +59077=>18116, +149996=>18116, +15129=>18117, +59128=>18117, +33942=>18118, +59176=>18118, +59241=>18119, +149858=>18119, +14818=>18120, +59254=>18120, +33920=>18121, +59259=>18121, +17262=>18122, +59328=>18122, +38769=>18123, +59402=>18123, +39323=>18124, +59427=>18124, +18733=>18125, +59499=>18125, +28439=>18126, +59703=>18126, +160009=>18127, +59704=>18127, +28838=>18128, +59746=>18128, +150095=>18129, +59752=>18129, +32357=>18130, +59753=>18130, +23855=>18131, +59755=>18131, +15859=>18132, +59756=>18132, +150109=>18133, +59758=>18133, +137183=>18134, +59759=>18134, +32164=>18135, +59760=>18135, +33830=>18136, +59761=>18136, +21637=>18137, +59762=>18137, +146170=>18138, +59763=>18138, +131604=>18139, +59765=>18139, +22398=>18140, +59766=>18140, +133333=>18141, +59767=>18141, +132633=>18142, +59768=>18142, +16357=>18143, +59769=>18143, +139166=>18144, +59770=>18144, +172726=>18145, +59771=>18145, +28675=>18146, +59772=>18146, +168283=>18147, +59773=>18147, +23920=>18148, +59774=>18148, +29583=>18149, +59775=>18149, +166489=>18150, +59777=>18150, +168992=>18151, +59778=>18151, +20424=>18152, +59779=>18152, +32743=>18153, +59780=>18153, +29456=>18154, +59782=>18154, +29496=>18155, +59784=>18155, +29505=>18156, +59787=>18156, +16041=>18157, +59789=>18157, +29173=>18158, +59792=>18158, +149746=>18159, +59793=>18159, +29665=>18160, +59794=>18160, +16074=>18161, +59796=>18161, +16081=>18162, +59798=>18162, +29721=>18163, +59801=>18163, +29726=>18164, +59802=>18164, +29727=>18165, +59803=>18165, +16098=>18166, +59804=>18166, +16112=>18167, +59805=>18167, +16116=>18168, +59806=>18168, +16122=>18169, +59807=>18169, +29907=>18170, +59808=>18170, +16142=>18171, +59809=>18171, +16211=>18172, +59810=>18172, +30061=>18173, +59812=>18173, +30066=>18174, +59813=>18174, +30093=>18175, +59814=>18175, +16252=>18176, +59815=>18176, +30152=>18177, +59816=>18177, +30285=>18178, +59819=>18178, +30324=>18179, +59821=>18179, +16348=>18180, +59822=>18180, +30330=>18181, +59823=>18181, +29064=>18182, +59825=>18182, +22051=>18183, +59826=>18183, +35200=>18184, +59827=>18184, +16413=>18185, +59829=>18185, +30531=>18186, +59830=>18186, +16441=>18187, +59831=>18187, +16453=>18188, +59833=>18188, +13787=>18189, +59834=>18189, +30616=>18190, +59835=>18190, +16490=>18191, +59836=>18191, +16495=>18192, +59837=>18192, +30654=>18193, +59839=>18193, +30667=>18194, +59840=>18194, +30744=>18195, +59842=>18195, +30748=>18196, +59844=>18196, +30791=>18197, +59847=>18197, +30801=>18198, +59848=>18198, +30822=>18199, +59849=>18199, +33864=>18200, +59850=>18200, +152885=>18201, +59851=>18201, +31027=>18202, +59852=>18202, +31026=>18203, +59854=>18203, +16649=>18204, +59856=>18204, +31121=>18205, +59857=>18205, +31238=>18206, +59860=>18206, +16743=>18207, +59862=>18207, +16818=>18208, +59864=>18208, +31420=>18209, +59865=>18209, +33401=>18210, +59866=>18210, +16836=>18211, +59867=>18211, +31439=>18212, +59868=>18212, +31451=>18213, +59869=>18213, +16847=>18214, +59870=>18214, +31586=>18215, +59872=>18215, +31596=>18216, +59873=>18216, +31611=>18217, +59874=>18217, +31762=>18218, +59875=>18218, +16992=>18219, +59877=>18219, +17018=>18220, +59878=>18220, +31867=>18221, +59879=>18221, +31900=>18222, +59880=>18222, +17036=>18223, +59881=>18223, +31928=>18224, +59882=>18224, +17044=>18225, +59883=>18225, +36755=>18226, +59885=>18226, +28864=>18227, +59886=>18227, +134351=>18228, +59887=>18228, +32207=>18229, +59888=>18229, +32212=>18230, +59889=>18230, +32208=>18231, +59890=>18231, +32253=>18232, +59891=>18232, +32692=>18233, +59893=>18233, +29343=>18234, +59894=>18234, +17303=>18235, +59895=>18235, +32800=>18236, +59896=>18236, +32805=>18237, +59897=>18237, +32814=>18238, +59899=>18238, +32817=>18239, +59900=>18239, +32852=>18240, +59901=>18240, +22452=>18241, +59903=>18241, +28832=>18242, +59904=>18242, +32951=>18243, +59905=>18243, +33001=>18244, +59906=>18244, +17389=>18245, +59907=>18245, +33036=>18246, +59908=>18246, +33038=>18247, +59910=>18247, +33042=>18248, +59911=>18248, +33044=>18249, +59913=>18249, +17409=>18250, +59914=>18250, +15161=>18251, +59915=>18251, +33110=>18252, +59916=>18252, +33113=>18253, +59917=>18253, +33114=>18254, +59918=>18254, +17427=>18255, +59919=>18255, +33148=>18256, +59921=>18256, +17445=>18257, +59923=>18257, +17453=>18258, +59925=>18258, +33189=>18259, +59926=>18259, +22511=>18260, +59927=>18260, +33217=>18261, +59928=>18261, +33252=>18262, +59929=>18262, +33364=>18263, +59930=>18263, +17551=>18264, +59931=>18264, +33398=>18265, +59933=>18265, +33482=>18266, +59934=>18266, +33496=>18267, +59935=>18267, +17584=>18268, +59937=>18268, +33623=>18269, +59938=>18269, +38505=>18270, +59939=>18270, +33797=>18271, +59941=>18271, +28917=>18272, +59942=>18272, +33892=>18273, +59943=>18273, +33928=>18274, +59945=>18274, +17668=>18275, +59946=>18275, +33982=>18276, +59947=>18276, +34017=>18277, +59948=>18277, +34040=>18278, +59949=>18278, +34064=>18279, +59950=>18279, +34104=>18280, +59951=>18280, +34130=>18281, +59952=>18281, +17723=>18282, +59953=>18282, +34159=>18283, +59954=>18283, +34160=>18284, +59955=>18284, +34272=>18285, +59956=>18285, +17783=>18286, +59957=>18286, +34418=>18287, +59958=>18287, +34450=>18288, +59959=>18288, +34543=>18289, +59961=>18289, +38469=>18290, +59962=>18290, +17926=>18291, +59964=>18291, +17943=>18292, +59965=>18292, +34990=>18293, +59966=>18293, +35071=>18294, +59967=>18294, +35108=>18295, +59968=>18295, +35217=>18296, +59970=>18296, +162151=>18297, +59971=>18297, +35384=>18298, +59973=>18298, +35476=>18299, +59974=>18299, +35508=>18300, +59975=>18300, +35921=>18301, +59976=>18301, +36052=>18302, +59977=>18302, +36082=>18303, +59978=>18303, +36124=>18304, +59979=>18304, +18328=>18305, +59980=>18305, +36291=>18306, +59982=>18306, +18413=>18307, +59983=>18307, +36410=>18308, +59985=>18308, +22356=>18309, +59987=>18309, +22005=>18310, +59989=>18310, +18487=>18311, +59991=>18311, +36558=>18312, +59992=>18312, +36578=>18313, +59993=>18313, +36580=>18314, +59994=>18314, +36589=>18315, +59995=>18315, +36594=>18316, +59996=>18316, +36801=>18317, +59998=>18317, +36810=>18318, +59999=>18318, +36812=>18319, +60000=>18319, +36915=>18320, +60001=>18320, +18605=>18321, +60003=>18321, +39136=>18322, +60004=>18322, +37395=>18323, +60005=>18323, +18718=>18324, +60006=>18324, +37416=>18325, +60007=>18325, +37464=>18326, +60008=>18326, +37483=>18327, +60009=>18327, +37553=>18328, +60010=>18328, +37550=>18329, +60011=>18329, +37567=>18330, +60012=>18330, +37603=>18331, +60013=>18331, +37611=>18332, +60014=>18332, +37619=>18333, +60015=>18333, +37620=>18334, +60016=>18334, +37629=>18335, +60017=>18335, +37699=>18336, +60018=>18336, +37764=>18337, +60019=>18337, +37805=>18338, +60020=>18338, +18757=>18339, +60021=>18339, +18769=>18340, +60022=>18340, +37911=>18341, +60024=>18341, +37917=>18342, +60026=>18342, +37933=>18343, +60027=>18343, +37950=>18344, +60028=>18344, +18794=>18345, +60029=>18345, +37972=>18346, +60030=>18346, +38009=>18347, +60031=>18347, +38189=>18348, +60032=>18348, +38306=>18349, +60033=>18349, +18855=>18350, +60034=>18350, +38388=>18351, +60035=>18351, +38451=>18352, +60036=>18352, +18917=>18353, +60037=>18353, +18980=>18354, +60039=>18354, +38720=>18355, +60040=>18355, +18997=>18356, +60041=>18356, +38834=>18357, +60042=>18357, +38850=>18358, +60043=>18358, +19172=>18359, +60045=>18359, +39097=>18360, +60047=>18360, +19225=>18361, +60048=>18361, +39153=>18362, +60049=>18362, +22596=>18363, +60050=>18363, +39193=>18364, +60052=>18364, +39223=>18365, +60055=>18365, +39261=>18366, +60057=>18366, +39266=>18367, +60058=>18367, +19312=>18368, +60059=>18368, +39365=>18369, +60060=>18369, +19357=>18370, +60061=>18370, +39484=>18371, +60062=>18371, +39695=>18372, +60063=>18372, +39785=>18373, +60065=>18373, +39901=>18374, +60067=>18374, +39921=>18375, +60068=>18375, +39924=>18376, +60069=>18376, +19565=>18377, +60070=>18377, +39968=>18378, +60071=>18378, +14191=>18379, +60072=>18379, +138178=>18380, +60073=>18380, +40265=>18381, +60074=>18381, +40702=>18382, +60076=>18382, +22096=>18383, +60077=>18383, +40381=>18384, +60079=>18384, +40444=>18385, +60081=>18385, +38134=>18386, +60082=>18386, +36790=>18387, +60083=>18387, +40625=>18388, +60086=>18388, +40637=>18389, +60087=>18389, +40646=>18390, +60088=>18390, +38108=>18391, +60089=>18391, +40674=>18392, +60090=>18392, +40689=>18393, +60091=>18393, +40696=>18394, +60092=>18394, +40772=>18395, +60094=>18395, +131220=>18396, +60095=>18396, +131767=>18397, +60096=>18397, +132000=>18398, +60097=>18398, +38083=>18399, +60099=>18399, +60101=>18400, +132311=>18400, +38081=>18401, +60103=>18401, +132565=>18402, +60105=>18402, +132629=>18403, +60106=>18403, +132726=>18404, +60107=>18404, +136890=>18405, +60108=>18405, +22359=>18406, +60109=>18406, +29043=>18407, +60110=>18407, +133826=>18408, +60111=>18408, +133837=>18409, +60112=>18409, +134079=>18410, +60113=>18410, +194619=>18411, +60115=>18411, +134091=>18412, +60116=>18412, +21662=>18413, +60117=>18413, +134139=>18414, +60118=>18414, +134203=>18415, +60119=>18415, +134227=>18416, +60120=>18416, +134245=>18417, +60121=>18417, +134268=>18418, +60122=>18418, +60124=>18419, +134285=>18419, +134325=>18420, +60126=>18420, +134365=>18421, +60127=>18421, +134381=>18422, +60128=>18422, +134511=>18423, +60129=>18423, +134578=>18424, +60130=>18424, +134600=>18425, +60131=>18425, +134660=>18426, +60135=>18426, +134670=>18427, +60136=>18427, +134871=>18428, +60137=>18428, +135056=>18429, +60138=>18429, +134957=>18430, +60139=>18430, +134771=>18431, +60140=>18431, +60142=>18432, +135100=>18432, +135260=>18433, +60144=>18433, +135247=>18434, +60145=>18434, +135286=>18435, +60146=>18435, +135304=>18436, +60149=>18436, +135318=>18437, +60150=>18437, +13895=>18438, +60151=>18438, +135359=>18439, +60152=>18439, +135471=>18440, +60154=>18440, +135483=>18441, +60155=>18441, +21348=>18442, +60156=>18442, +135907=>18443, +60158=>18443, +136053=>18444, +60159=>18444, +60160=>18445, +135990=>18445, +136567=>18446, +60162=>18446, +136729=>18447, +60163=>18447, +137155=>18448, +60164=>18448, +137159=>18449, +60165=>18449, +28859=>18450, +60167=>18450, +137261=>18451, +60168=>18451, +137578=>18452, +60169=>18452, +137773=>18453, +60170=>18453, +137797=>18454, +60171=>18454, +138282=>18455, +60172=>18455, +138352=>18456, +60173=>18456, +138412=>18457, +60174=>18457, +138952=>18458, +60175=>18458, +138965=>18459, +60177=>18459, +139029=>18460, +60178=>18460, +29080=>18461, +60179=>18461, +139333=>18462, +60181=>18462, +27113=>18463, +60182=>18463, +14024=>18464, +60183=>18464, +139900=>18465, +60184=>18465, +140247=>18466, +60185=>18466, +140282=>18467, +60186=>18467, +141098=>18468, +60187=>18468, +141425=>18469, +60188=>18469, +141647=>18470, +60189=>18470, +141671=>18471, +60191=>18471, +141715=>18472, +60192=>18472, +142037=>18473, +60193=>18473, +60195=>18474, +142056=>18474, +60197=>18475, +142094=>18475, +60199=>18476, +142143=>18476, +60202=>18477, +142412=>18477, +142472=>18478, +60204=>18478, +142519=>18479, +60205=>18479, +154600=>18480, +60206=>18480, +142600=>18481, +60207=>18481, +142610=>18482, +60208=>18482, +142775=>18483, +60209=>18483, +142741=>18484, +60210=>18484, +142914=>18485, +60211=>18485, +143220=>18486, +60212=>18486, +143308=>18487, +60213=>18487, +143411=>18488, +60214=>18488, +143462=>18489, +60215=>18489, +144159=>18490, +60216=>18490, +144350=>18491, +60217=>18491, +144743=>18492, +60222=>18492, +144883=>18493, +60223=>18493, +144922=>18494, +60227=>18494, +145174=>18495, +60228=>18495, +22709=>18496, +60231=>18496, +60234=>18497, +146087=>18497, +146961=>18498, +60237=>18498, +147129=>18499, +60238=>18499, +60243=>18500, +147737=>18500, +148206=>18501, +60245=>18501, +148237=>18502, +60246=>18502, +148276=>18503, +60248=>18503, +148374=>18504, +60249=>18504, +148484=>18505, +60258=>18505, +148694=>18506, +60259=>18506, +22408=>18507, +60260=>18507, +149108=>18508, +60261=>18508, +60263=>18509, +149295=>18509, +149522=>18510, +60271=>18510, +149755=>18511, +60272=>18511, +150037=>18512, +60273=>18512, +60275=>18513, +150208=>18513, +22885=>18514, +60277=>18514, +60279=>18515, +151430=>18515, +60282=>18516, +151596=>18516, +22335=>18517, +60284=>18517, +152217=>18518, +60286=>18518, +152601=>18519, +60287=>18519, +152646=>18520, +60291=>18520, +152686=>18521, +60292=>18521, +60296=>18522, +152895=>18522, +60298=>18523, +152926=>18523, +152930=>18524, +60300=>18524, +152934=>18525, +60301=>18525, +153543=>18526, +60302=>18526, +60304=>18527, +153693=>18527, +60309=>18528, +153859=>18528, +154286=>18529, +60312=>18529, +154505=>18530, +60313=>18530, +154630=>18531, +60314=>18531, +22433=>18532, +60316=>18532, +29009=>18533, +60317=>18533, +60319=>18534, +155906=>18534, +60322=>18535, +156082=>18535, +156674=>18536, +60325=>18536, +156746=>18537, +60326=>18537, +60330=>18538, +156804=>18538, +60334=>18539, +156808=>18539, +60336=>18540, +156946=>18540, +157119=>18541, +60338=>18541, +157365=>18542, +60339=>18542, +22201=>18543, +60347=>18543, +60349=>18544, +157436=>18544, +13848=>18545, +60355=>18545, +157593=>18546, +60357=>18546, +157806=>18547, +60358=>18547, +60360=>18548, +157790=>18548, +60362=>18549, +157895=>18549, +60366=>18550, +157990=>18550, +60368=>18551, +158009=>18551, +60371=>18552, +158202=>18552, +60373=>18553, +158253=>18553, +158260=>18554, +60378=>18554, +158555=>18555, +60379=>18555, +60383=>18556, +158621=>18556, +60385=>18557, +158884=>18557, +60388=>18558, +159150=>18558, +159819=>18559, +60392=>18559, +160205=>18560, +60393=>18560, +160384=>18561, +60395=>18561, +160389=>18562, +60396=>18562, +60399=>18563, +160395=>18563, +60401=>18564, +160486=>18564, +38047=>18565, +60404=>18565, +160848=>18566, +60405=>18566, +14009=>18567, +60416=>18567, +161740=>18568, +60424=>18568, +161880=>18569, +60425=>18569, +22230=>18570, +60426=>18570, +60435=>18571, +162269=>18571, +162301=>18572, +60441=>18572, +162314=>18573, +60442=>18573, +162571=>18574, +60443=>18574, +163174=>18575, +60444=>18575, +60448=>18576, +163849=>18576, +60459=>18577, +163875=>18577, +60463=>18578, +163912=>18578, +60466=>18579, +163971=>18579, +163984=>18580, +60479=>18580, +164084=>18581, +60480=>18581, +164142=>18582, +60481=>18582, +60483=>18583, +164175=>18583, +164271=>18584, +60485=>18584, +164378=>18585, +60486=>18585, +164614=>18586, +60487=>18586, +164655=>18587, +60488=>18587, +164746=>18588, +60489=>18588, +164968=>18589, +60491=>18589, +165546=>18590, +60492=>18590, +25574=>18591, +60494=>18591, +166230=>18592, +60495=>18592, +60498=>18593, +166328=>18593, +60500=>18594, +166375=>18594, +60502=>18595, +166376=>18595, +166726=>18596, +60503=>18596, +166868=>18597, +60504=>18597, +60506=>18598, +166921=>18598, +167877=>18599, +60508=>18599, +168172=>18600, +60509=>18600, +168208=>18601, +60511=>18601, +168252=>18602, +60512=>18602, +15863=>18603, +60513=>18603, +168286=>18604, +60514=>18604, +150218=>18605, +60515=>18605, +36816=>18606, +60516=>18606, +60519=>18607, +169191=>18607, +169392=>18608, +60521=>18608, +169400=>18609, +60522=>18609, +169778=>18610, +60523=>18610, +170193=>18611, +60524=>18611, +170313=>18612, +60525=>18612, +170346=>18613, +60526=>18613, +170435=>18614, +60527=>18614, +170536=>18615, +60528=>18615, +170766=>18616, +60529=>18616, +171354=>18617, +60530=>18617, +171419=>18618, +60531=>18618, +32415=>18619, +60532=>18619, +171768=>18620, +60533=>18620, +171811=>18621, +60534=>18621, +19620=>18622, +60535=>18622, +38215=>18623, +60536=>18623, +172691=>18624, +60537=>18624, +29090=>18625, +60538=>18625, +172799=>18626, +60539=>18626, +173515=>18627, +60542=>18627, +19868=>18628, +60543=>18628, +134300=>18629, +60544=>18629, +36798=>18630, +60545=>18630, +36794=>18631, +60547=>18631, +140464=>18632, +60548=>18632, +36793=>18633, +60549=>18633, +150163=>18634, +60550=>18634, +20202=>18635, +60555=>18635, +60557=>18636, +166700=>18636, +36480=>18637, +60560=>18637, +137205=>18638, +60561=>18638, +166764=>18639, +60563=>18639, +166809=>18640, +60564=>18640, +60566=>18641, +157359=>18641, +60568=>18642, +161365=>18642, +153141=>18643, +60570=>18643, +153942=>18644, +60571=>18644, +20122=>18645, +60572=>18645, +155265=>18646, +60573=>18646, +60576=>18647, +134765=>18647, +147080=>18648, +60579=>18648, +150686=>18649, +60580=>18649, +137206=>18650, +60583=>18650, +137339=>18651, +60584=>18651, +60587=>18652, +154698=>18652, +152337=>18653, +60589=>18653, +15814=>18654, +60590=>18654, +60596=>18655, +155352=>18655, +19996=>18656, +60600=>18656, +135146=>18657, +60601=>18657, +134473=>18658, +60602=>18658, +145082=>18659, +60603=>18659, +60638=>18660, +151880=>18660, +21982=>18661, +60644=>18661, +34694=>18662, +60672=>18662, +60676=>18663, +135361=>18663, +149254=>18664, +60679=>18664, +23440=>18665, +60680=>18665, +60682=>18666, +157843=>18666, +141044=>18667, +60684=>18667, +163119=>18668, +60685=>18668, +147875=>18669, +60686=>18669, +163187=>18670, +60687=>18670, +159440=>18671, +60688=>18671, +160438=>18672, +60689=>18672, +60691=>18673, +135641=>18673, +146684=>18674, +60693=>18674, +173737=>18675, +60694=>18675, +134828=>18676, +60695=>18676, +60698=>18677, +138402=>18677, +60700=>18678, +151490=>18678, +60702=>18679, +135147=>18679, +60706=>18680, +142752=>18680, +135148=>18681, +60710=>18681, +134666=>18682, +60711=>18682, +60714=>18683, +135149=>18683, +60717=>18684, +135559=>18684, +19994=>18685, +60721=>18685, +19972=>18686, +60722=>18686, +23309=>18687, +60724=>18687, +13996=>18688, +60727=>18688, +21373=>18689, +60729=>18689, +13989=>18690, +60730=>18690, +22682=>18691, +60732=>18691, +150382=>18692, +60733=>18692, +22442=>18693, +60736=>18693, +154261=>18694, +60737=>18694, +133497=>18695, +60738=>18695, +60741=>18696, +140389=>18696, +146686=>18697, +60746=>18697, +171824=>18698, +60747=>18698, +151465=>18699, +60749=>18699, +169374=>18700, +60750=>18700, +60753=>18701, +146870=>18701, +157619=>18702, +60755=>18702, +145184=>18703, +60756=>18703, +147191=>18704, +60759=>18704, +146988=>18705, +60760=>18705, +60785=>18706, +143578=>18706, +135849=>18707, +60789=>18707, +22439=>18708, +60790=>18708, +149859=>18709, +60791=>18709, +60794=>18710, +159918=>18710, +60801=>18711, +137068=>18711, +60806=>18712, +160100=>18712, +159010=>18713, +60809=>18713, +150242=>18714, +60810=>18714, +39963=>18715, +60837=>18715, +149822=>18716, +60838=>18716, +15878=>18717, +60846=>18717, +60881=>18718, +159011=>18718, +60887=>18719, +132092=>18719, +60891=>18720, +146685=>18720, +60893=>18721, +149785=>18721, +22394=>18722, +60904=>18722, +21722=>18723, +60912=>18723, +29050=>18724, +60928=>18724, +60949=>18725, +150135=>18725, +60955=>18726, +166490=>18726, +60962=>18727, +194624=>18727, +60976=>18728, +137275=>18728, +61000=>18729, +155993=>18729, +61014=>18730, +144373=>18730, +61019=>18731, +166850=>18731, +61024=>18732, +138566=>18732, +61054=>18733, +159441=>18733, +13877=>18734, +61065=>18734, +61084=>18735, +166701=>18735, +21024=>18736, +61088=>18736, +15384=>18737, +61089=>18737, +146631=>18738, +61090=>18738, +155351=>18739, +61091=>18739, +161366=>18740, +61092=>18740, +152881=>18741, +61093=>18741, +137540=>18742, +61094=>18742, +170243=>18743, +61096=>18743, +159196=>18744, +61097=>18744, +159917=>18745, +61098=>18745, +156077=>18746, +61100=>18746, +166415=>18747, +61101=>18747, +145015=>18748, +61102=>18748, +131310=>18749, +61103=>18749, +157766=>18750, +61104=>18750, +151310=>18751, +61105=>18751, +17762=>18752, +61106=>18752, +23327=>18753, +61107=>18753, +156492=>18754, +61108=>18754, +40784=>18755, +61109=>18755, +40614=>18756, +61110=>18756, +156267=>18757, +61111=>18757, +20962=>18758, +57415=>18758, +21314=>18759, +57416=>18759, +26285=>18760, +57520=>18760, +22620=>18761, +57547=>18761, +21843=>18762, +57566=>18762, +15749=>18763, +57594=>18763, +24928=>18764, +57608=>18764, +18606=>18765, +57668=>18765, +38845=>18766, +57676=>18766, +57693=>18767, +137335=>18767, +24755=>18768, +57703=>18768, +33828=>18769, +57711=>18769, +38932=>18770, +57748=>18770, +147596=>18771, +57749=>18771, +57764=>18772, +143486=>18772, +57787=>18773, +138813=>18773, +15147=>18774, +57798=>18774, +15666=>18775, +57824=>18775, +57857=>18776, +132021=>18776, +28801=>18777, +57944=>18777, +23708=>18778, +57959=>18778, +58017=>18779, +132547=>18779, +14128=>18780, +58028=>18780, +136054=>18781, +58096=>18781, +150034=>18782, +58097=>18782, +58111=>18783, +166699=>18783, +58112=>18784, +155779=>18784, +256=>18785, +62233=>18785, +193=>18786, +62234=>18786, +461=>18787, +62235=>18787, +192=>18788, +62236=>18788, +274=>18789, +62237=>18789, +201=>18790, +62238=>18790, +282=>18791, +62239=>18791, +200=>18792, +62240=>18792, +332=>18793, +62241=>18793, +211=>18794, +62242=>18794, +465=>18795, +62243=>18795, +210=>18796, +62244=>18796, +62245=>18797, +7870=>18798, +62246=>18798, +62247=>18799, +7872=>18800, +62248=>18800, +202=>18801, +62249=>18801, +257=>18802, +62250=>18802, +225=>18803, +62251=>18803, +462=>18804, +62252=>18804, +224=>18805, +62253=>18805, +593=>18806, +62254=>18806, +275=>18807, +62255=>18807, +233=>18808, +62256=>18808, +283=>18809, +62257=>18809, +232=>18810, +62258=>18810, +299=>18811, +62259=>18811, +237=>18812, +62260=>18812, +464=>18813, +62261=>18813, +236=>18814, +62262=>18814, +333=>18815, +62263=>18815, +243=>18816, +62264=>18816, +466=>18817, +62265=>18817, +242=>18818, +62266=>18818, +363=>18819, +62267=>18819, +250=>18820, +62268=>18820, +468=>18821, +62269=>18821, +249=>18822, +62270=>18822, +470=>18823, +62271=>18823, +472=>18824, +62272=>18824, +474=>18825, +62273=>18825, +476=>18826, +62274=>18826, +252=>18827, +62275=>18827, +62276=>18828, +7871=>18829, +62277=>18829, +62278=>18830, +7873=>18831, +62279=>18831, +234=>18832, +62280=>18832, +609=>18833, +62281=>18833, +643=>18834, +63551=>18834, +592=>18835, +63552=>18835, +603=>18836, +63553=>18836, +596=>18837, +63554=>18837, +629=>18838, +63555=>18838, +339=>18839, +63556=>18839, +248=>18840, +63557=>18840, +331=>18841, +63558=>18841, +650=>18842, +63559=>18842, +618=>18843, +63560=>18843, +9178=>18844, +62282=>18844, +9179=>18845, +62283=>18845, +11933=>18846, +63530=>18846, +11974=>18847, +63539=>18847, +12003=>18848, +63547=>18848, +20539=>18849, +28158=>18850, +171123=>18851, +62841=>18851, +40870=>18852, +62842=>18852, +15817=>18853, +62843=>18853, +34959=>18854, +62845=>18855, +147790=>18855, +28791=>18856, +23797=>18857, +19232=>18858, +62848=>18858, +152013=>18859, +62849=>18859, +13657=>18860, +62850=>18860, +154928=>18861, +62851=>18861, +24866=>18862, +62853=>18863, +166450=>18863, +36775=>18864, +37366=>18865, +29073=>18866, +26393=>18867, +29626=>18868, +144001=>18869, +62859=>18869, +172295=>18870, +62860=>18870, +15499=>18871, +62861=>18871, +137600=>18872, +62862=>18872, +19216=>18873, +62863=>18873, +30948=>18874, +29698=>18875, +20910=>18876, +165647=>18877, +62867=>18877, +16393=>18878, +62868=>18878, +27235=>18879, +172730=>18880, +62870=>18880, +16931=>18881, +62871=>18881, +34319=>18882, +31274=>18883, +170311=>18884, +62875=>18884, +166634=>18885, +62876=>18885, +38741=>18886, +28749=>18887, +21284=>18888, +62880=>18889, +139390=>18889, +37876=>18890, +30425=>18891, +166371=>18892, +62883=>18892, +40871=>18893, +62884=>18893, +30685=>18894, +20131=>18895, +20464=>18896, +20668=>18897, +20015=>18898, +20247=>18899, +40872=>18900, +62891=>18900, +21556=>18901, +32139=>18902, +22674=>18903, +22736=>18904, +62896=>18905, +138678=>18905, +24210=>18906, +24217=>18907, +24514=>18908, +62900=>18909, +141074=>18909, +25995=>18910, +62902=>18911, +144377=>18911, +26905=>18912, +27203=>18913, +62905=>18914, +146531=>18914, +27903=>18915, +29184=>18916, +62909=>18917, +148741=>18917, +29580=>18918, +16091=>18919, +62911=>18919, +150035=>18920, +62912=>18920, +23317=>18921, +29881=>18922, +35715=>18923, +154788=>18924, +62916=>18924, +153237=>18925, +62917=>18925, +31379=>18926, +31724=>18927, +31939=>18928, +32364=>18929, +33528=>18930, +34199=>18931, +40873=>18932, +62924=>18932, +34960=>18933, +40874=>18934, +62926=>18934, +36537=>18935, +40875=>18936, +62928=>18936, +36815=>18937, +34143=>18938, +39392=>18939, +37409=>18940, +40876=>18941, +62933=>18941, +167353=>18942, +62934=>18942, +136255=>18943, +62935=>18943, +16497=>18944, +62936=>18944, +17058=>18945, +62937=>18945, +23066=>18946, +39016=>18947, +26475=>18948, +17014=>18949, +62944=>18949, +22333=>18950, +34262=>18951, +62948=>18952, +149883=>18952, +33471=>18953, +160013=>18954, +62950=>18954, +19585=>18955, +62951=>18955, +159092=>18956, +62952=>18956, +23931=>18957, +158485=>18958, +62954=>18958, +159678=>18959, +62955=>18959, +40877=>18960, +62956=>18960, +40878=>18961, +62957=>18961, +23446=>18962, +40879=>18963, +62959=>18963, +32347=>18964, +17392=>18965, +19506=>18966, +17923=>18967, +17830=>18968, +17784=>18969, +160359=>18970, +19831=>18971, +17843=>18972, +162993=>18973, +19682=>18974, +163013=>18975, +15253=>18976, +18230=>18977, +18244=>18978, +19527=>18979, +19520=>18980, +148159=>18981, +144919=>18982, +160594=>18983, +159371=>18984, +159954=>18985, +19543=>18986, +172881=>18987, +18255=>18988, +17882=>18989, +19589=>18990, +162924=>18991, +19719=>18992, +19108=>18993, +18081=>18994, +158499=>18995, +29221=>18996, +154196=>18997, +137827=>18998, +146950=>18999, +147297=>19000, +26189=>19001, +22267=>19002, +32149=>19003, +22813=>19004, +166841=>19005, +15860=>19006, +38708=>19007, +162799=>19008, +23515=>19009, +138590=>19010, +23204=>19011, +13861=>19012, +171696=>19013, +23249=>19014, +23479=>19015, +23804=>19016, +26478=>19017, +34195=>19018, +170309=>19019, +29793=>19020, +29853=>19021, +133743=>19022, +26343=>19023, +28247=>19024, +31178=>19025, +15752=>19026, +17603=>19027, +143958=>19028, +141206=>19029, +17306=>19030, +17718=>19031, +23765=>19032, +146202=>19033, +35577=>19034, +23672=>19035, +15634=>19036, +144721=>19037, +23928=>19038, +40882=>19039, +29015=>19040, +17752=>19041, +147692=>19042, +138787=>19043, +19575=>19044, +14712=>19045, +13386=>19046, +131492=>19047, +158785=>19048, +35532=>19049, +20404=>19050, +131641=>19051, +22975=>19052, +33132=>19053, +38998=>19054, +170234=>19055, +24379=>19056, +134047=>19057, +139713=>19058, +166253=>19059, +16642=>19060, +18107=>19061, +168057=>19062, +16135=>19063, +40883=>19064, +172469=>19065, +16632=>19066, +14294=>19067, +18167=>19068, +158790=>19069, +16764=>19070, +165554=>19071, +160767=>19072, +17773=>19073, +14548=>19074, +152730=>19075, +17761=>19076, +17691=>19077, +19849=>19078, +19579=>19079, +19830=>19080, +17898=>19081, +16328=>19082, +150287=>19083, +13921=>19084, +17630=>19085, +17597=>19086, +16877=>19087, +); +?> diff --git a/include/tcpdf/fonts/uni2cid_ag15.php b/include/tcpdf/fonts/uni2cid_ag15.php new file mode 100644 index 00000000..3c1a5141 --- /dev/null +++ b/include/tcpdf/fonts/uni2cid_ag15.php @@ -0,0 +1,30245 @@ +1, +33=>2, +34=>3, +35=>4, +36=>5, +37=>6, +38=>7, +39=>8, +40=>9, +41=>10, +42=>11, +43=>12, +44=>13, +45=>14, +46=>15, +47=>16, +48=>17, +49=>18, +50=>19, +51=>20, +52=>21, +53=>22, +54=>23, +55=>24, +56=>25, +57=>26, +58=>27, +59=>28, +60=>29, +61=>30, +62=>31, +63=>32, +64=>33, +65=>34, +66=>35, +67=>36, +68=>37, +69=>38, +70=>39, +71=>40, +72=>41, +73=>42, +74=>43, +75=>44, +76=>45, +77=>46, +78=>47, +79=>48, +80=>49, +81=>50, +82=>51, +83=>52, +84=>53, +85=>54, +86=>55, +87=>56, +88=>57, +89=>58, +90=>59, +91=>60, +92=>61, +93=>62, +94=>63, +95=>64, +96=>65, +97=>66, +98=>67, +99=>68, +100=>69, +101=>70, +102=>71, +103=>72, +104=>73, +105=>74, +106=>75, +107=>76, +108=>77, +109=>78, +110=>79, +111=>80, +112=>81, +113=>82, +114=>83, +115=>84, +116=>85, +117=>86, +118=>87, +119=>88, +120=>89, +121=>90, +122=>91, +123=>92, +124=>93, +125=>94, +126=>95, +12288=>96, +12289=>97, +12290=>98, +183=>99, +12539=>99, +713=>100, +711=>101, +168=>102, +12291=>103, +12293=>104, +8212=>105, +65374=>106, +8214=>107, +8230=>108, +8943=>108, +8216=>109, +8217=>110, +8220=>111, +8221=>112, +12308=>113, +12309=>114, +12296=>115, +12297=>116, +12298=>117, +12299=>118, +12300=>119, +12301=>120, +12302=>121, +12303=>122, +12310=>123, +12311=>124, +12304=>125, +12305=>126, +177=>127, +215=>128, +247=>129, +8758=>130, +8743=>131, +8744=>132, +8721=>133, +8719=>134, +8746=>135, +8745=>136, +8712=>137, +8759=>138, +8730=>139, +8869=>140, +8741=>141, +8736=>142, +8978=>143, +8857=>144, +8747=>145, +8750=>146, +8801=>147, +8780=>148, +8776=>149, +8765=>150, +8733=>151, +8800=>152, +8814=>153, +8815=>154, +8804=>155, +8805=>156, +8734=>157, +8757=>158, +8756=>159, +9794=>160, +9792=>161, +176=>162, +8242=>163, +8243=>164, +8451=>165, +65284=>166, +164=>167, +65504=>168, +65505=>169, +8240=>170, +167=>171, +8470=>172, +9734=>173, +9733=>174, +9675=>175, +9679=>176, +9678=>177, +9671=>178, +9670=>179, +9633=>180, +9632=>181, +9651=>182, +9650=>183, +8251=>184, +8594=>185, +8592=>186, +8593=>187, +8595=>188, +12307=>189, +9352=>190, +9353=>191, +9354=>192, +9355=>193, +9356=>194, +9357=>195, +9358=>196, +9359=>197, +9360=>198, +9361=>199, +9362=>200, +9363=>201, +9364=>202, +9365=>203, +9366=>204, +9367=>205, +9368=>206, +9369=>207, +9370=>208, +9371=>209, +9332=>210, +9333=>211, +9334=>212, +9335=>213, +9336=>214, +9337=>215, +9338=>216, +9339=>217, +9340=>218, +9341=>219, +9342=>220, +9343=>221, +9344=>222, +9345=>223, +9346=>224, +9347=>225, +9348=>226, +9349=>227, +9350=>228, +9351=>229, +9312=>230, +9313=>231, +9314=>232, +9315=>233, +9316=>234, +9317=>235, +9318=>236, +9319=>237, +9320=>238, +9321=>239, +12832=>240, +12833=>241, +12834=>242, +12835=>243, +12836=>244, +12837=>245, +12838=>246, +12839=>247, +12840=>248, +12841=>249, +8544=>250, +8545=>251, +8546=>252, +8547=>253, +8548=>254, +8549=>255, +8550=>256, +8551=>257, +8552=>258, +8553=>259, +8554=>260, +8555=>261, +65281=>262, +65282=>263, +65283=>264, +65509=>265, +65285=>266, +65286=>267, +65287=>268, +65288=>269, +65289=>270, +65290=>271, +65291=>272, +65292=>273, +65293=>274, +65294=>275, +65295=>276, +65296=>277, +65297=>278, +65298=>279, +65299=>280, +65300=>281, +65301=>282, +65302=>283, +65303=>284, +65304=>285, +65305=>286, +65306=>287, +65307=>288, +65308=>289, +65309=>290, +65310=>291, +65311=>292, +65312=>293, +65313=>294, +65314=>295, +65315=>296, +65316=>297, +65317=>298, +65318=>299, +65319=>300, +65320=>301, +65321=>302, +65322=>303, +65323=>304, +65324=>305, +65325=>306, +65326=>307, +65327=>308, +65328=>309, +65329=>310, +65330=>311, +65331=>312, +65332=>313, +65333=>314, +65334=>315, +65335=>316, +65336=>317, +65337=>318, +65338=>319, +65339=>320, +65340=>321, +65341=>322, +65342=>323, +65343=>324, +65344=>325, +65345=>326, +65346=>327, +65347=>328, +65348=>329, +65349=>330, +65350=>331, +65351=>332, +65352=>333, +65353=>334, +65354=>335, +65355=>336, +65356=>337, +65357=>338, +65358=>339, +65359=>340, +65360=>341, +65361=>342, +65362=>343, +65363=>344, +65364=>345, +65365=>346, +65366=>347, +65367=>348, +65368=>349, +65369=>350, +65370=>351, +65371=>352, +65372=>353, +65373=>354, +65507=>355, +12353=>356, +12354=>357, +12355=>358, +12356=>359, +12357=>360, +12358=>361, +12359=>362, +12360=>363, +12361=>364, +12362=>365, +12363=>366, +12364=>367, +12365=>368, +12366=>369, +12367=>370, +12368=>371, +12369=>372, +12370=>373, +12371=>374, +12372=>375, +12373=>376, +12374=>377, +12375=>378, +12376=>379, +12377=>380, +12378=>381, +12379=>382, +12380=>383, +12381=>384, +12382=>385, +12383=>386, +12384=>387, +12385=>388, +12386=>389, +12387=>390, +12388=>391, +12389=>392, +12390=>393, +12391=>394, +12392=>395, +12393=>396, +12394=>397, +12395=>398, +12396=>399, +12397=>400, +12398=>401, +12399=>402, +12400=>403, +12401=>404, +12402=>405, +12403=>406, +12404=>407, +12405=>408, +12406=>409, +12407=>410, +12408=>411, +12409=>412, +12410=>413, +12411=>414, +12412=>415, +12413=>416, +12414=>417, +12415=>418, +12416=>419, +12417=>420, +12418=>421, +12419=>422, +12420=>423, +12421=>424, +12422=>425, +12423=>426, +12424=>427, +12425=>428, +12426=>429, +12427=>430, +12428=>431, +12429=>432, +12430=>433, +12431=>434, +12432=>435, +12433=>436, +12434=>437, +12435=>438, +12449=>439, +12450=>440, +12451=>441, +12452=>442, +12453=>443, +12454=>444, +12455=>445, +12456=>446, +12457=>447, +12458=>448, +12459=>449, +12460=>450, +12461=>451, +12462=>452, +12463=>453, +12464=>454, +12465=>455, +12466=>456, +12467=>457, +12468=>458, +12469=>459, +12470=>460, +12471=>461, +12472=>462, +12473=>463, +12474=>464, +12475=>465, +12476=>466, +12477=>467, +12478=>468, +12479=>469, +12480=>470, +12481=>471, +12482=>472, +12483=>473, +12484=>474, +12485=>475, +12486=>476, +12487=>477, +12488=>478, +12489=>479, +12490=>480, +12491=>481, +12492=>482, +12493=>483, +12494=>484, +12495=>485, +12496=>486, +12497=>487, +12498=>488, +12499=>489, +12500=>490, +12501=>491, +12502=>492, +12503=>493, +12504=>494, +12505=>495, +12506=>496, +12507=>497, +12508=>498, +12509=>499, +12510=>500, +12511=>501, +12512=>502, +12513=>503, +12514=>504, +12515=>505, +12516=>506, +12517=>507, +12518=>508, +12519=>509, +12520=>510, +12521=>511, +12522=>512, +12523=>513, +12524=>514, +12525=>515, +12526=>516, +12527=>517, +12528=>518, +12529=>519, +12530=>520, +12531=>521, +12532=>522, +12533=>523, +12534=>524, +913=>525, +914=>526, +915=>527, +916=>528, +917=>529, +918=>530, +919=>531, +920=>532, +921=>533, +922=>534, +923=>535, +924=>536, +925=>537, +926=>538, +927=>539, +928=>540, +929=>541, +931=>542, +932=>543, +933=>544, +934=>545, +935=>546, +936=>547, +937=>548, +945=>549, +946=>550, +947=>551, +948=>552, +949=>553, +950=>554, +951=>555, +952=>556, +953=>557, +954=>558, +955=>559, +956=>560, +957=>561, +958=>562, +959=>563, +960=>564, +961=>565, +963=>566, +964=>567, +965=>568, +966=>569, +967=>570, +968=>571, +969=>572, +65040=>573, +59277=>573, +65042=>574, +59278=>574, +65041=>575, +59279=>575, +59280=>576, +65043=>576, +59281=>577, +65044=>577, +59282=>578, +65045=>578, +59283=>579, +65046=>579, +65077=>580, +65078=>581, +65081=>582, +65082=>583, +65087=>584, +65088=>585, +65085=>586, +65086=>587, +65089=>588, +65090=>589, +65091=>590, +65092=>591, +59284=>592, +65047=>592, +59285=>593, +65048=>593, +65083=>594, +65084=>595, +65079=>596, +65080=>597, +65073=>598, +8285=>599, +59286=>599, +65049=>599, +65075=>600, +65076=>601, +1040=>602, +1041=>603, +1042=>604, +1043=>605, +1044=>606, +1045=>607, +1025=>608, +1046=>609, +1047=>610, +1048=>611, +1049=>612, +1050=>613, +1051=>614, +1052=>615, +1053=>616, +1054=>617, +1055=>618, +1056=>619, +1057=>620, +1058=>621, +1059=>622, +1060=>623, +1061=>624, +1062=>625, +1063=>626, +1064=>627, +1065=>628, +1066=>629, +1067=>630, +1068=>631, +1069=>632, +1070=>633, +1071=>634, +1072=>635, +1073=>636, +1074=>637, +1075=>638, +1076=>639, +1077=>640, +1105=>641, +1078=>642, +1079=>643, +1080=>644, +1081=>645, +1082=>646, +1083=>647, +1084=>648, +1085=>649, +1086=>650, +1087=>651, +1088=>652, +1089=>653, +1090=>654, +1091=>655, +1092=>656, +1093=>657, +1094=>658, +1095=>659, +1096=>660, +1097=>661, +1098=>662, +1099=>663, +1100=>664, +1101=>665, +1102=>666, +1103=>667, +257=>668, +225=>669, +462=>670, +224=>671, +275=>672, +233=>673, +283=>674, +232=>675, +299=>676, +237=>677, +464=>678, +236=>679, +333=>680, +243=>681, +466=>682, +242=>683, +363=>684, +250=>685, +468=>686, +249=>687, +470=>688, +472=>689, +474=>690, +476=>691, +252=>692, +234=>693, +593=>694, +7743=>695, +59335=>695, +324=>696, +328=>697, +505=>698, +59336=>698, +609=>699, +12549=>700, +12550=>701, +12551=>702, +12552=>703, +12553=>704, +12554=>705, +12555=>706, +12556=>707, +12557=>708, +12558=>709, +12559=>710, +12560=>711, +12561=>712, +12562=>713, +12563=>714, +12564=>715, +12565=>716, +12566=>717, +12567=>718, +12568=>719, +12569=>720, +12570=>721, +12571=>722, +12572=>723, +12573=>724, +12574=>725, +12575=>726, +12576=>727, +12577=>728, +12578=>729, +12579=>730, +12580=>731, +12581=>732, +12582=>733, +12583=>734, +12584=>735, +12585=>736, +9472=>738, +9473=>739, +9474=>740, +9475=>741, +9476=>742, +9477=>743, +9478=>744, +9479=>745, +9480=>746, +9481=>747, +9482=>748, +9483=>749, +9484=>750, +9485=>751, +9486=>752, +9487=>753, +9488=>754, +9489=>755, +9490=>756, +9491=>757, +9492=>758, +9493=>759, +9494=>760, +9495=>761, +9496=>762, +9497=>763, +9498=>764, +9499=>765, +9500=>766, +9501=>767, +9502=>768, +9503=>769, +9504=>770, +9505=>771, +9506=>772, +9507=>773, +9508=>774, +9509=>775, +9510=>776, +9511=>777, +9512=>778, +9513=>779, +9514=>780, +9515=>781, +9516=>782, +9517=>783, +9518=>784, +9519=>785, +9520=>786, +9521=>787, +9522=>788, +9523=>789, +9524=>790, +9525=>791, +9526=>792, +9527=>793, +9528=>794, +9529=>795, +9530=>796, +9531=>797, +9532=>798, +9533=>799, +9534=>800, +9535=>801, +9536=>802, +9537=>803, +9538=>804, +9539=>805, +9540=>806, +9541=>807, +9542=>808, +9543=>809, +9544=>810, +9545=>811, +9546=>812, +9547=>813, +21834=>940, +38463=>941, +22467=>942, +25384=>943, +21710=>944, +21769=>945, +21696=>946, +30353=>947, +30284=>948, +34108=>949, +30702=>950, +33406=>951, +30861=>952, +29233=>953, +38552=>954, +38797=>955, +27688=>956, +23433=>957, +20474=>958, +25353=>959, +26263=>960, +23736=>961, +33018=>962, +26696=>963, +32942=>964, +26114=>965, +30414=>966, +20985=>967, +25942=>968, +29100=>969, +32753=>970, +34948=>971, +20658=>972, +22885=>973, +25034=>974, +28595=>975, +33453=>976, +25420=>977, +25170=>978, +21485=>979, +21543=>980, +31494=>981, +12043=>982, +20843=>982, +30116=>983, +24052=>984, +25300=>985, +36299=>986, +38774=>987, +25226=>988, +32793=>989, +22365=>990, +38712=>991, +32610=>992, +29240=>993, +12137=>994, +30333=>994, +26575=>995, +30334=>996, +25670=>997, +20336=>998, +36133=>999, +25308=>1000, +31255=>1001, +26001=>1002, +29677=>1003, +25644=>1004, +25203=>1005, +33324=>1006, +39041=>1007, +26495=>1008, +29256=>1009, +25198=>1010, +25292=>1011, +20276=>1012, +29923=>1013, +21322=>1014, +21150=>1015, +32458=>1016, +37030=>1017, +24110=>1018, +26758=>1019, +27036=>1020, +33152=>1021, +32465=>1022, +26834=>1023, +30917=>1024, +34444=>1025, +38225=>1026, +20621=>1027, +35876=>1028, +33502=>1029, +32990=>1030, +21253=>1031, +35090=>1032, +21093=>1033, +34180=>1034, +38649=>1035, +20445=>1036, +22561=>1037, +39281=>1038, +23453=>1039, +25265=>1040, +25253=>1041, +26292=>1042, +35961=>1043, +40077=>1044, +29190=>1045, +26479=>1046, +30865=>1047, +24754=>1048, +21329=>1049, +21271=>1050, +36744=>1051, +32972=>1052, +36125=>1053, +38049=>1054, +20493=>1055, +29384=>1056, +22791=>1057, +24811=>1058, +28953=>1059, +34987=>1060, +22868=>1061, +33519=>1062, +26412=>1063, +31528=>1064, +23849=>1065, +32503=>1066, +29997=>1067, +27893=>1068, +36454=>1069, +36856=>1070, +36924=>1071, +12240=>1072, +40763=>1072, +12112=>1073, +27604=>1073, +37145=>1074, +31508=>1075, +24444=>1076, +30887=>1077, +34006=>1078, +34109=>1079, +27605=>1080, +27609=>1081, +27606=>1082, +24065=>1083, +24199=>1084, +30201=>1085, +38381=>1086, +25949=>1087, +24330=>1088, +24517=>1089, +36767=>1090, +22721=>1091, +33218=>1092, +36991=>1093, +38491=>1094, +38829=>1095, +36793=>1096, +32534=>1097, +36140=>1098, +25153=>1099, +20415=>1100, +21464=>1101, +21342=>1102, +36776=>1103, +36777=>1104, +36779=>1105, +36941=>1106, +26631=>1107, +24426=>1108, +33176=>1109, +34920=>1110, +40150=>1111, +24971=>1112, +21035=>1113, +30250=>1114, +24428=>1115, +25996=>1116, +28626=>1117, +28392=>1118, +23486=>1119, +25672=>1120, +20853=>1121, +20912=>1122, +26564=>1123, +19993=>1124, +31177=>1125, +39292=>1126, +28851=>1127, +30149=>1128, +24182=>1129, +29627=>1130, +33760=>1131, +25773=>1132, +25320=>1133, +38069=>1134, +27874=>1135, +21338=>1136, +21187=>1137, +25615=>1138, +38082=>1139, +31636=>1140, +20271=>1141, +24091=>1142, +33334=>1143, +33046=>1144, +33162=>1145, +28196=>1146, +27850=>1147, +39539=>1148, +25429=>1149, +12056=>1150, +21340=>1150, +21754=>1151, +34917=>1152, +22496=>1153, +19981=>1154, +24067=>1155, +27493=>1156, +31807=>1157, +37096=>1158, +24598=>1159, +25830=>1160, +29468=>1161, +35009=>1162, +26448=>1163, +25165=>1164, +36130=>1165, +30572=>1166, +36393=>1167, +37319=>1168, +24425=>1169, +33756=>1170, +34081=>1171, +39184=>1172, +21442=>1173, +34453=>1174, +27531=>1175, +24813=>1176, +24808=>1177, +28799=>1178, +33485=>1179, +33329=>1180, +20179=>1181, +27815=>1182, +34255=>1183, +25805=>1184, +31961=>1185, +27133=>1186, +26361=>1187, +33609=>1188, +21397=>1189, +31574=>1190, +20391=>1191, +20876=>1192, +27979=>1193, +23618=>1194, +36461=>1195, +25554=>1196, +21449=>1197, +33580=>1198, +33590=>1199, +26597=>1200, +30900=>1201, +25661=>1202, +23519=>1203, +23700=>1204, +24046=>1205, +35815=>1206, +25286=>1207, +26612=>1208, +35962=>1209, +25600=>1210, +25530=>1211, +34633=>1212, +39307=>1213, +35863=>1214, +32544=>1215, +38130=>1216, +20135=>1217, +38416=>1218, +39076=>1219, +26124=>1220, +29462=>1221, +22330=>1222, +23581=>1223, +24120=>1224, +38271=>1225, +20607=>1226, +32928=>1227, +12058=>1228, +21378=>1228, +25950=>1229, +30021=>1230, +21809=>1231, +20513=>1232, +36229=>1233, +25220=>1234, +38046=>1235, +26397=>1236, +22066=>1237, +28526=>1238, +24034=>1239, +21557=>1240, +28818=>1241, +36710=>1242, +25199=>1243, +25764=>1244, +25507=>1245, +24443=>1246, +28552=>1247, +37108=>1248, +12162=>1249, +33251=>1249, +12192=>1250, +36784=>1250, +23576=>1251, +26216=>1252, +24561=>1253, +27785=>1254, +38472=>1255, +36225=>1256, +34924=>1257, +25745=>1258, +31216=>1259, +22478=>1260, +27225=>1261, +25104=>1262, +21576=>1263, +20056=>1264, +31243=>1265, +24809=>1266, +28548=>1267, +35802=>1268, +25215=>1269, +36894=>1270, +39563=>1271, +31204=>1272, +21507=>1273, +30196=>1274, +25345=>1275, +21273=>1276, +27744=>1277, +36831=>1278, +24347=>1279, +39536=>1280, +32827=>1281, +40831=>1282, +20360=>1283, +23610=>1284, +12186=>1285, +36196=>1285, +32709=>1286, +26021=>1287, +28861=>1288, +20805=>1289, +20914=>1290, +12173=>1291, +34411=>1291, +23815=>1292, +23456=>1293, +25277=>1294, +37228=>1295, +30068=>1296, +36364=>1297, +31264=>1298, +24833=>1299, +31609=>1300, +20167=>1301, +32504=>1302, +30597=>1303, +19985=>1304, +33261=>1305, +21021=>1306, +20986=>1307, +27249=>1308, +21416=>1309, +36487=>1310, +38148=>1311, +38607=>1312, +28353=>1313, +38500=>1314, +26970=>1315, +30784=>1316, +20648=>1317, +30679=>1318, +25616=>1319, +35302=>1320, +22788=>1321, +25571=>1322, +24029=>1323, +31359=>1324, +26941=>1325, +20256=>1326, +33337=>1327, +21912=>1328, +20018=>1329, +30126=>1330, +31383=>1331, +24162=>1332, +24202=>1333, +38383=>1334, +21019=>1335, +21561=>1336, +28810=>1337, +25462=>1338, +38180=>1339, +22402=>1340, +26149=>1341, +26943=>1342, +37255=>1343, +21767=>1344, +28147=>1345, +32431=>1346, +34850=>1347, +25139=>1348, +32496=>1349, +30133=>1350, +33576=>1351, +30913=>1352, +38604=>1353, +36766=>1354, +24904=>1355, +29943=>1356, +35789=>1357, +27492=>1358, +21050=>1359, +36176=>1360, +27425=>1361, +32874=>1362, +33905=>1363, +22257=>1364, +21254=>1365, +20174=>1366, +19995=>1367, +20945=>1368, +31895=>1369, +37259=>1370, +31751=>1371, +20419=>1372, +36479=>1373, +31713=>1374, +31388=>1375, +25703=>1376, +23828=>1377, +20652=>1378, +33030=>1379, +30209=>1380, +31929=>1381, +28140=>1382, +32736=>1383, +26449=>1384, +23384=>1385, +12072=>1386, +23544=>1386, +30923=>1387, +25774=>1388, +25619=>1389, +25514=>1390, +25387=>1391, +38169=>1392, +25645=>1393, +36798=>1394, +31572=>1395, +30249=>1396, +25171=>1397, +12068=>1398, +22823=>1398, +21574=>1399, +12109=>1400, +27513=>1400, +20643=>1401, +25140=>1402, +24102=>1403, +27526=>1404, +20195=>1405, +36151=>1406, +34955=>1407, +24453=>1408, +36910=>1409, +24608=>1410, +32829=>1411, +25285=>1412, +20025=>1413, +21333=>1414, +37112=>1415, +25528=>1416, +32966=>1417, +26086=>1418, +27694=>1419, +20294=>1420, +24814=>1421, +28129=>1422, +35806=>1423, +24377=>1424, +34507=>1425, +24403=>1426, +25377=>1427, +20826=>1428, +33633=>1429, +26723=>1430, +12049=>1431, +20992=>1431, +25443=>1432, +36424=>1433, +20498=>1434, +23707=>1435, +31095=>1436, +23548=>1437, +21040=>1438, +31291=>1439, +24764=>1440, +36947=>1441, +30423=>1442, +24503=>1443, +24471=>1444, +30340=>1445, +36460=>1446, +28783=>1447, +30331=>1448, +31561=>1449, +30634=>1450, +20979=>1451, +37011=>1452, +22564=>1453, +20302=>1454, +28404=>1455, +36842=>1456, +25932=>1457, +31515=>1458, +29380=>1459, +28068=>1460, +32735=>1461, +23265=>1462, +25269=>1463, +24213=>1464, +22320=>1465, +33922=>1466, +31532=>1467, +24093=>1468, +24351=>1469, +36882=>1470, +32532=>1471, +39072=>1472, +25474=>1473, +28359=>1474, +30872=>1475, +28857=>1476, +20856=>1477, +38747=>1478, +22443=>1479, +30005=>1480, +20291=>1481, +30008=>1482, +24215=>1483, +24806=>1484, +22880=>1485, +28096=>1486, +27583=>1487, +30857=>1488, +21500=>1489, +38613=>1490, +20939=>1491, +20993=>1492, +25481=>1493, +21514=>1494, +38035=>1495, +35843=>1496, +36300=>1497, +29241=>1498, +30879=>1499, +34678=>1500, +36845=>1501, +35853=>1502, +21472=>1503, +19969=>1504, +30447=>1505, +21486=>1506, +38025=>1507, +39030=>1508, +12237=>1509, +40718=>1509, +38189=>1510, +23450=>1511, +35746=>1512, +20002=>1513, +19996=>1514, +20908=>1515, +33891=>1516, +25026=>1517, +21160=>1518, +26635=>1519, +20375=>1520, +24683=>1521, +20923=>1522, +27934=>1523, +20828=>1524, +25238=>1525, +12099=>1526, +26007=>1526, +38497=>1527, +12182=>1528, +35910=>1528, +36887=>1529, +30168=>1530, +37117=>1531, +30563=>1532, +27602=>1533, +29322=>1534, +29420=>1535, +35835=>1536, +22581=>1537, +30585=>1538, +36172=>1539, +26460=>1540, +38208=>1541, +32922=>1542, +24230=>1543, +28193=>1544, +22930=>1545, +31471=>1546, +30701=>1547, +38203=>1548, +27573=>1549, +26029=>1550, +32526=>1551, +22534=>1552, +20817=>1553, +38431=>1554, +23545=>1555, +22697=>1556, +21544=>1557, +36466=>1558, +25958=>1559, +39039=>1560, +22244=>1561, +38045=>1562, +30462=>1563, +36929=>1564, +25479=>1565, +21702=>1566, +22810=>1567, +22842=>1568, +22427=>1569, +36530=>1570, +26421=>1571, +36346=>1572, +33333=>1573, +21057=>1574, +24816=>1575, +22549=>1576, +34558=>1577, +23784=>1578, +40517=>1579, +20420=>1580, +39069=>1581, +35769=>1582, +23077=>1583, +24694=>1584, +21380=>1585, +25212=>1586, +36943=>1587, +37122=>1588, +39295=>1589, +24681=>1590, +12157=>1591, +32780=>1591, +12041=>1592, +20799=>1592, +12159=>1593, +32819=>1593, +23572=>1594, +39285=>1595, +27953=>1596, +12038=>1597, +20108=>1597, +36144=>1598, +21457=>1599, +32602=>1600, +31567=>1601, +20240=>1602, +20047=>1603, +38400=>1604, +27861=>1605, +29648=>1606, +34281=>1607, +24070=>1608, +30058=>1609, +32763=>1610, +27146=>1611, +30718=>1612, +38034=>1613, +32321=>1614, +20961=>1615, +28902=>1616, +21453=>1617, +36820=>1618, +33539=>1619, +36137=>1620, +29359=>1621, +39277=>1622, +27867=>1623, +22346=>1624, +33459=>1625, +12101=>1626, +26041=>1626, +32938=>1627, +25151=>1628, +38450=>1629, +22952=>1630, +20223=>1631, +35775=>1632, +32442=>1633, +25918=>1634, +33778=>1635, +12206=>1636, +38750=>1636, +21857=>1637, +39134=>1638, +32933=>1639, +21290=>1640, +35837=>1641, +21536=>1642, +32954=>1643, +24223=>1644, +27832=>1645, +36153=>1646, +33452=>1647, +37210=>1648, +21545=>1649, +27675=>1650, +20998=>1651, +32439=>1652, +22367=>1653, +28954=>1654, +27774=>1655, +31881=>1656, +22859=>1657, +20221=>1658, +24575=>1659, +24868=>1660, +31914=>1661, +20016=>1662, +23553=>1663, +26539=>1664, +34562=>1665, +23792=>1666, +38155=>1667, +39118=>1668, +30127=>1669, +28925=>1670, +36898=>1671, +20911=>1672, +32541=>1673, +35773=>1674, +22857=>1675, +20964=>1676, +20315=>1677, +21542=>1678, +22827=>1679, +25975=>1680, +32932=>1681, +23413=>1682, +25206=>1683, +25282=>1684, +36752=>1685, +24133=>1686, +27679=>1687, +31526=>1688, +20239=>1689, +20440=>1690, +26381=>1691, +28014=>1692, +28074=>1693, +31119=>1694, +34993=>1695, +24343=>1696, +29995=>1697, +25242=>1698, +36741=>1699, +20463=>1700, +37340=>1701, +26023=>1702, +33071=>1703, +33105=>1704, +24220=>1705, +33104=>1706, +36212=>1707, +21103=>1708, +35206=>1709, +36171=>1710, +22797=>1711, +20613=>1712, +20184=>1713, +12201=>1714, +38428=>1714, +12119=>1715, +29238=>1715, +33145=>1716, +36127=>1717, +23500=>1718, +35747=>1719, +38468=>1720, +22919=>1721, +32538=>1722, +21648=>1723, +22134=>1724, +22030=>1725, +35813=>1726, +25913=>1727, +27010=>1728, +38041=>1729, +30422=>1730, +28297=>1731, +12082=>1732, +24178=>1732, +12130=>1733, +29976=>1733, +26438=>1734, +26577=>1735, +31487=>1736, +32925=>1737, +36214=>1738, +24863=>1739, +31174=>1740, +25954=>1741, +36195=>1742, +20872=>1743, +21018=>1744, +38050=>1745, +32568=>1746, +32923=>1747, +32434=>1748, +23703=>1749, +28207=>1750, +26464=>1751, +31705=>1752, +30347=>1753, +12220=>1754, +39640=>1754, +33167=>1755, +32660=>1756, +31957=>1757, +25630=>1758, +38224=>1759, +31295=>1760, +21578=>1761, +21733=>1762, +27468=>1763, +25601=>1764, +12093=>1765, +25096=>1765, +40509=>1766, +33011=>1767, +30105=>1768, +21106=>1769, +12208=>1770, +38761=>1770, +33883=>1771, +26684=>1772, +34532=>1773, +38401=>1774, +38548=>1775, +38124=>1776, +20010=>1777, +21508=>1778, +32473=>1779, +26681=>1780, +36319=>1781, +32789=>1782, +26356=>1783, +24218=>1784, +32697=>1785, +22466=>1786, +32831=>1787, +26775=>1788, +12079=>1789, +24037=>1789, +25915=>1790, +21151=>1791, +24685=>1792, +40858=>1793, +20379=>1794, +36524=>1795, +20844=>1796, +23467=>1797, +12088=>1798, +24339=>1798, +24041=>1799, +27742=>1800, +25329=>1801, +36129=>1802, +20849=>1803, +38057=>1804, +21246=>1805, +27807=>1806, +33503=>1807, +29399=>1808, +22434=>1809, +26500=>1810, +36141=>1811, +22815=>1812, +36764=>1813, +33735=>1814, +21653=>1815, +31629=>1816, +20272=>1817, +27837=>1818, +23396=>1819, +22993=>1820, +12238=>1821, +40723=>1821, +21476=>1822, +34506=>1823, +12219=>1824, +39592=>1824, +12181=>1825, +35895=>1825, +32929=>1826, +25925=>1827, +39038=>1828, +22266=>1829, +38599=>1830, +21038=>1831, +12128=>1832, +29916=>1832, +21072=>1833, +23521=>1834, +25346=>1835, +35074=>1836, +20054=>1837, +25296=>1838, +24618=>1839, +26874=>1840, +20851=>1841, +23448=>1842, +20896=>1843, +35266=>1844, +31649=>1845, +39302=>1846, +32592=>1847, +24815=>1848, +28748=>1849, +36143=>1850, +20809=>1851, +12084=>1852, +24191=>1852, +36891=>1853, +29808=>1854, +35268=>1855, +22317=>1856, +30789=>1857, +24402=>1858, +40863=>1859, +38394=>1860, +36712=>1861, +12225=>1862, +39740=>1862, +35809=>1863, +30328=>1864, +26690=>1865, +26588=>1866, +36330=>1867, +36149=>1868, +21053=>1869, +36746=>1870, +28378=>1871, +26829=>1872, +38149=>1873, +37101=>1874, +22269=>1875, +26524=>1876, +35065=>1877, +36807=>1878, +21704=>1879, +39608=>1880, +23401=>1881, +28023=>1882, +27686=>1883, +20133=>1884, +23475=>1885, +39559=>1886, +37219=>1887, +25000=>1888, +37039=>1889, +38889=>1890, +21547=>1891, +28085=>1892, +23506=>1893, +20989=>1894, +21898=>1895, +32597=>1896, +32752=>1897, +25788=>1898, +25421=>1899, +26097=>1900, +25022=>1901, +24717=>1902, +28938=>1903, +27735=>1904, +27721=>1905, +22831=>1906, +26477=>1907, +33322=>1908, +22741=>1909, +22158=>1910, +35946=>1911, +27627=>1912, +37085=>1913, +22909=>1914, +32791=>1915, +21495=>1916, +28009=>1917, +21621=>1918, +21917=>1919, +33655=>1920, +33743=>1921, +26680=>1922, +12146=>1923, +31166=>1923, +21644=>1924, +20309=>1925, +21512=>1926, +30418=>1927, +35977=>1928, +38402=>1929, +27827=>1930, +28088=>1931, +36203=>1932, +35088=>1933, +40548=>1934, +36154=>1935, +22079=>1936, +12234=>1937, +40657=>1937, +30165=>1938, +24456=>1939, +29408=>1940, +24680=>1941, +21756=>1942, +20136=>1943, +27178=>1944, +34913=>1945, +24658=>1946, +36720=>1947, +21700=>1948, +28888=>1949, +34425=>1950, +40511=>1951, +27946=>1952, +23439=>1953, +24344=>1954, +32418=>1955, +21897=>1956, +20399=>1957, +29492=>1958, +21564=>1959, +21402=>1960, +20505=>1961, +21518=>1962, +21628=>1963, +20046=>1964, +24573=>1965, +29786=>1966, +22774=>1967, +33899=>1968, +32993=>1969, +34676=>1970, +29392=>1971, +31946=>1972, +28246=>1973, +24359=>1974, +34382=>1975, +21804=>1976, +25252=>1977, +20114=>1978, +27818=>1979, +25143=>1980, +33457=>1981, +21719=>1982, +21326=>1983, +29502=>1984, +28369=>1985, +30011=>1986, +21010=>1987, +21270=>1988, +35805=>1989, +27088=>1990, +24458=>1991, +24576=>1992, +28142=>1993, +22351=>1994, +27426=>1995, +29615=>1996, +26707=>1997, +36824=>1998, +32531=>1999, +25442=>2000, +24739=>2001, +21796=>2002, +30186=>2003, +35938=>2004, +28949=>2005, +28067=>2006, +23462=>2007, +24187=>2008, +33618=>2009, +24908=>2010, +40644=>2011, +30970=>2012, +34647=>2013, +31783=>2014, +30343=>2015, +20976=>2016, +24822=>2017, +29004=>2018, +26179=>2019, +24140=>2020, +24653=>2021, +35854=>2022, +28784=>2023, +25381=>2024, +36745=>2025, +24509=>2026, +24674=>2027, +34516=>2028, +22238=>2029, +27585=>2030, +24724=>2031, +24935=>2032, +21321=>2033, +24800=>2034, +26214=>2035, +36159=>2036, +31229=>2037, +20250=>2038, +28905=>2039, +27719=>2040, +35763=>2041, +35826=>2042, +32472=>2043, +33636=>2044, +26127=>2045, +23130=>2046, +39746=>2047, +27985=>2048, +28151=>2049, +35905=>2050, +27963=>2051, +20249=>2052, +12117=>2053, +28779=>2053, +33719=>2054, +25110=>2055, +24785=>2056, +38669=>2057, +36135=>2058, +31096=>2059, +20987=>2060, +22334=>2061, +22522=>2062, +26426=>2063, +30072=>2064, +31293=>2065, +31215=>2066, +31637=>2067, +32908=>2068, +39269=>2069, +36857=>2070, +28608=>2071, +35749=>2072, +40481=>2073, +23020=>2074, +32489=>2075, +32521=>2076, +21513=>2077, +26497=>2078, +26840=>2079, +36753=>2080, +31821=>2081, +38598=>2082, +21450=>2083, +24613=>2084, +30142=>2085, +27762=>2086, +21363=>2087, +23241=>2088, +32423=>2089, +25380=>2090, +12047=>2091, +20960=>2091, +33034=>2092, +12080=>2093, +24049=>2093, +34015=>2094, +25216=>2095, +20864=>2096, +23395=>2097, +20238=>2098, +31085=>2099, +21058=>2100, +24760=>2101, +27982=>2102, +23492=>2103, +23490=>2104, +35745=>2105, +35760=>2106, +26082=>2107, +24524=>2108, +38469=>2109, +22931=>2110, +32487=>2111, +32426=>2112, +22025=>2113, +26551=>2114, +22841=>2115, +20339=>2116, +23478=>2117, +21152=>2118, +33626=>2119, +39050=>2120, +36158=>2121, +30002=>2122, +38078=>2123, +20551=>2124, +31292=>2125, +20215=>2126, +26550=>2127, +39550=>2128, +23233=>2129, +27516=>2130, +30417=>2131, +22362=>2132, +23574=>2133, +31546=>2134, +38388=>2135, +29006=>2136, +20860=>2137, +32937=>2138, +33392=>2139, +22904=>2140, +32516=>2141, +33575=>2142, +26816=>2143, +26604=>2144, +30897=>2145, +30839=>2146, +25315=>2147, +25441=>2148, +31616=>2149, +20461=>2150, +21098=>2151, +20943=>2152, +33616=>2153, +27099=>2154, +37492=>2155, +36341=>2156, +36145=>2157, +35265=>2158, +38190=>2159, +31661=>2160, +20214=>2161, +20581=>2162, +33328=>2163, +21073=>2164, +39279=>2165, +28176=>2166, +28293=>2167, +28071=>2168, +24314=>2169, +20725=>2170, +23004=>2171, +23558=>2172, +27974=>2173, +27743=>2174, +30086=>2175, +33931=>2176, +26728=>2177, +22870=>2178, +35762=>2179, +21280=>2180, +37233=>2181, +38477=>2182, +34121=>2183, +26898=>2184, +30977=>2185, +28966=>2186, +33014=>2187, +20132=>2188, +37066=>2189, +27975=>2190, +39556=>2191, +23047=>2192, +22204=>2193, +25605=>2194, +38128=>2195, +30699=>2196, +20389=>2197, +33050=>2198, +29409=>2199, +12179=>2200, +35282=>2200, +39290=>2201, +32564=>2202, +32478=>2203, +21119=>2204, +25945=>2205, +37237=>2206, +36735=>2207, +36739=>2208, +21483=>2209, +31382=>2210, +25581=>2211, +25509=>2212, +30342=>2213, +31224=>2214, +34903=>2215, +38454=>2216, +25130=>2217, +21163=>2218, +33410=>2219, +26708=>2220, +26480=>2221, +25463=>2222, +30571=>2223, +31469=>2224, +27905=>2225, +32467=>2226, +35299=>2227, +22992=>2228, +25106=>2229, +34249=>2230, +33445=>2231, +30028=>2232, +20511=>2233, +20171=>2234, +30117=>2235, +35819=>2236, +23626=>2237, +12081=>2238, +24062=>2238, +31563=>2239, +12100=>2240, +26020=>2240, +12198=>2241, +37329=>2241, +20170=>2242, +27941=>2243, +35167=>2244, +32039=>2245, +38182=>2246, +20165=>2247, +35880=>2248, +36827=>2249, +38771=>2250, +26187=>2251, +31105=>2252, +36817=>2253, +28908=>2254, +28024=>2255, +23613=>2256, +21170=>2257, +33606=>2258, +20834=>2259, +33550=>2260, +30555=>2261, +26230=>2262, +40120=>2263, +20140=>2264, +24778=>2265, +31934=>2266, +31923=>2267, +32463=>2268, +20117=>2269, +35686=>2270, +26223=>2271, +39048=>2272, +38745=>2273, +22659=>2274, +25964=>2275, +38236=>2276, +24452=>2277, +30153=>2278, +38742=>2279, +31455=>2280, +31454=>2281, +20928=>2282, +28847=>2283, +31384=>2284, +25578=>2285, +31350=>2286, +32416=>2287, +29590=>2288, +12210=>2289, +38893=>2289, +20037=>2290, +28792=>2291, +20061=>2292, +37202=>2293, +21417=>2294, +25937=>2295, +26087=>2296, +12165=>2297, +33276=>2297, +33285=>2298, +21646=>2299, +23601=>2300, +30106=>2301, +38816=>2302, +25304=>2303, +29401=>2304, +30141=>2305, +23621=>2306, +39545=>2307, +33738=>2308, +23616=>2309, +21632=>2310, +30697=>2311, +20030=>2312, +27822=>2313, +32858=>2314, +25298=>2315, +25454=>2316, +24040=>2317, +20855=>2318, +36317=>2319, +36382=>2320, +38191=>2321, +20465=>2322, +21477=>2323, +24807=>2324, +28844=>2325, +21095=>2326, +25424=>2327, +40515=>2328, +23071=>2329, +20518=>2330, +30519=>2331, +21367=>2332, +32482=>2333, +25733=>2334, +25899=>2335, +25225=>2336, +25496=>2337, +20500=>2338, +29237=>2339, +35273=>2340, +20915=>2341, +35776=>2342, +32477=>2343, +22343=>2344, +33740=>2345, +38055=>2346, +20891=>2347, +21531=>2348, +23803=>2349, +20426=>2350, +31459=>2351, +27994=>2352, +37089=>2353, +39567=>2354, +21888=>2355, +21654=>2356, +21345=>2357, +21679=>2358, +24320=>2359, +25577=>2360, +26999=>2361, +20975=>2362, +24936=>2363, +21002=>2364, +22570=>2365, +21208=>2366, +22350=>2367, +30733=>2368, +30475=>2369, +24247=>2370, +24951=>2371, +31968=>2372, +25179=>2373, +25239=>2374, +20130=>2375, +28821=>2376, +32771=>2377, +25335=>2378, +28900=>2379, +38752=>2380, +22391=>2381, +33499=>2382, +26607=>2383, +26869=>2384, +30933=>2385, +39063=>2386, +31185=>2387, +22771=>2388, +21683=>2389, +21487=>2390, +28212=>2391, +20811=>2392, +21051=>2393, +23458=>2394, +35838=>2395, +32943=>2396, +21827=>2397, +22438=>2398, +24691=>2399, +22353=>2400, +21549=>2401, +31354=>2402, +24656=>2403, +23380=>2404, +25511=>2405, +25248=>2406, +12061=>2407, +21475=>2407, +25187=>2408, +23495=>2409, +26543=>2410, +21741=>2411, +31391=>2412, +33510=>2413, +37239=>2414, +24211=>2415, +35044=>2416, +22840=>2417, +22446=>2418, +25358=>2419, +36328=>2420, +33007=>2421, +22359=>2422, +31607=>2423, +20393=>2424, +24555=>2425, +23485=>2426, +27454=>2427, +21281=>2428, +31568=>2429, +29378=>2430, +26694=>2431, +30719=>2432, +30518=>2433, +26103=>2434, +20917=>2435, +20111=>2436, +30420=>2437, +23743=>2438, +31397=>2439, +33909=>2440, +22862=>2441, +39745=>2442, +20608=>2443, +39304=>2444, +24871=>2445, +28291=>2446, +22372=>2447, +26118=>2448, +25414=>2449, +22256=>2450, +25324=>2451, +25193=>2452, +24275=>2453, +38420=>2454, +22403=>2455, +25289=>2456, +21895=>2457, +34593=>2458, +33098=>2459, +36771=>2460, +21862=>2461, +33713=>2462, +26469=>2463, +36182=>2464, +34013=>2465, +23146=>2466, +26639=>2467, +25318=>2468, +31726=>2469, +38417=>2470, +20848=>2471, +28572=>2472, +35888=>2473, +25597=>2474, +35272=>2475, +25042=>2476, +32518=>2477, +28866=>2478, +28389=>2479, +29701=>2480, +27028=>2481, +29436=>2482, +24266=>2483, +37070=>2484, +26391=>2485, +28010=>2486, +25438=>2487, +21171=>2488, +29282=>2489, +12156=>2490, +32769=>2490, +20332=>2491, +23013=>2492, +37226=>2493, +28889=>2494, +28061=>2495, +21202=>2496, +20048=>2497, +38647=>2498, +38253=>2499, +34174=>2500, +30922=>2501, +32047=>2502, +20769=>2503, +22418=>2504, +25794=>2505, +32907=>2506, +31867=>2507, +27882=>2508, +26865=>2509, +26974=>2510, +20919=>2511, +21400=>2512, +26792=>2513, +29313=>2514, +40654=>2515, +31729=>2516, +29432=>2517, +31163=>2518, +28435=>2519, +29702=>2520, +26446=>2521, +12197=>2522, +37324=>2522, +40100=>2523, +31036=>2524, +33673=>2525, +33620=>2526, +21519=>2527, +26647=>2528, +20029=>2529, +21385=>2530, +21169=>2531, +30782=>2532, +21382=>2533, +21033=>2534, +20616=>2535, +20363=>2536, +20432=>2537, +30178=>2538, +12148=>2539, +31435=>2539, +31890=>2540, +27813=>2541, +12202=>2542, +38582=>2542, +12050=>2543, +21147=>2543, +29827=>2544, +21737=>2545, +20457=>2546, +32852=>2547, +33714=>2548, +36830=>2549, +38256=>2550, +24265=>2551, +24604=>2552, +28063=>2553, +24088=>2554, +25947=>2555, +33080=>2556, +38142=>2557, +24651=>2558, +28860=>2559, +32451=>2560, +31918=>2561, +20937=>2562, +63865=>2562, +26753=>2563, +31921=>2564, +33391=>2565, +20004=>2566, +36742=>2567, +37327=>2568, +26238=>2569, +20142=>2570, +35845=>2571, +25769=>2572, +32842=>2573, +20698=>2574, +30103=>2575, +29134=>2576, +23525=>2577, +36797=>2578, +28518=>2579, +20102=>2580, +25730=>2581, +38243=>2582, +24278=>2583, +26009=>2584, +21015=>2585, +35010=>2586, +28872=>2587, +21155=>2588, +29454=>2589, +29747=>2590, +26519=>2591, +30967=>2592, +38678=>2593, +20020=>2594, +37051=>2595, +40158=>2596, +28107=>2597, +20955=>2598, +36161=>2599, +21533=>2600, +25294=>2601, +29618=>2602, +33777=>2603, +38646=>2604, +40836=>2605, +38083=>2606, +20278=>2607, +32666=>2608, +20940=>2609, +28789=>2610, +38517=>2611, +23725=>2612, +39046=>2613, +21478=>2614, +20196=>2615, +28316=>2616, +29705=>2617, +27060=>2618, +30827=>2619, +39311=>2620, +30041=>2621, +21016=>2622, +30244=>2623, +27969=>2624, +26611=>2625, +20845=>2626, +40857=>2627, +32843=>2628, +21657=>2629, +31548=>2630, +31423=>2631, +38534=>2632, +22404=>2633, +25314=>2634, +38471=>2635, +27004=>2636, +23044=>2637, +25602=>2638, +31699=>2639, +28431=>2640, +38475=>2641, +33446=>2642, +21346=>2643, +39045=>2644, +24208=>2645, +28809=>2646, +25523=>2647, +21348=>2648, +34383=>2649, +40065=>2650, +40595=>2651, +30860=>2652, +38706=>2653, +36335=>2654, +36162=>2655, +12229=>2656, +40575=>2656, +28510=>2657, +31108=>2658, +24405=>2659, +38470=>2660, +25134=>2661, +39540=>2662, +21525=>2663, +38109=>2664, +20387=>2665, +26053=>2666, +23653=>2667, +23649=>2668, +32533=>2669, +34385=>2670, +27695=>2671, +24459=>2672, +29575=>2673, +28388=>2674, +32511=>2675, +23782=>2676, +25371=>2677, +23402=>2678, +28390=>2679, +21365=>2680, +20081=>2681, +25504=>2682, +30053=>2683, +25249=>2684, +36718=>2685, +20262=>2686, +20177=>2687, +27814=>2688, +32438=>2689, +35770=>2690, +33821=>2691, +34746=>2692, +32599=>2693, +36923=>2694, +38179=>2695, +31657=>2696, +39585=>2697, +35064=>2698, +33853=>2699, +27931=>2700, +39558=>2701, +32476=>2702, +22920=>2703, +12231=>2704, +40635=>2704, +29595=>2705, +30721=>2706, +34434=>2707, +39532=>2708, +39554=>2709, +22043=>2710, +21527=>2711, +22475=>2712, +20080=>2713, +40614=>2714, +21334=>2715, +36808=>2716, +33033=>2717, +30610=>2718, +39314=>2719, +34542=>2720, +28385=>2721, +34067=>2722, +26364=>2723, +24930=>2724, +28459=>2725, +35881=>2726, +33426=>2727, +33579=>2728, +30450=>2729, +27667=>2730, +24537=>2731, +33725=>2732, +29483=>2733, +33541=>2734, +38170=>2735, +12113=>2736, +27611=>2736, +12141=>2737, +30683=>2737, +38086=>2738, +21359=>2739, +33538=>2740, +20882=>2741, +24125=>2742, +35980=>2743, +36152=>2744, +20040=>2745, +29611=>2746, +26522=>2747, +26757=>2748, +37238=>2749, +38665=>2750, +29028=>2751, +27809=>2752, +30473=>2753, +23186=>2754, +38209=>2755, +27599=>2756, +32654=>2757, +26151=>2758, +23504=>2759, +22969=>2760, +23194=>2761, +38376=>2762, +38391=>2763, +20204=>2764, +33804=>2765, +33945=>2766, +27308=>2767, +30431=>2768, +38192=>2769, +29467=>2770, +26790=>2771, +23391=>2772, +30511=>2773, +37274=>2774, +38753=>2775, +31964=>2776, +36855=>2777, +35868=>2778, +24357=>2779, +12150=>2780, +31859=>2780, +31192=>2781, +35269=>2782, +27852=>2783, +34588=>2784, +23494=>2785, +24130=>2786, +26825=>2787, +30496=>2788, +32501=>2789, +20885=>2790, +20813=>2791, +21193=>2792, +23081=>2793, +32517=>2794, +12207=>2795, +38754=>2795, +33495=>2796, +25551=>2797, +30596=>2798, +34256=>2799, +31186=>2800, +28218=>2801, +24217=>2802, +22937=>2803, +34065=>2804, +28781=>2805, +27665=>2806, +25279=>2807, +12139=>2808, +30399=>2808, +25935=>2809, +24751=>2810, +38397=>2811, +26126=>2812, +34719=>2813, +40483=>2814, +38125=>2815, +21517=>2816, +21629=>2817, +35884=>2818, +25720=>2819, +25721=>2820, +34321=>2821, +27169=>2822, +33180=>2823, +30952=>2824, +25705=>2825, +39764=>2826, +25273=>2827, +26411=>2828, +33707=>2829, +22696=>2830, +40664=>2831, +27819=>2832, +28448=>2833, +23518=>2834, +38476=>2835, +35851=>2836, +29279=>2837, +26576=>2838, +25287=>2839, +29281=>2840, +20137=>2841, +22982=>2842, +27597=>2843, +22675=>2844, +26286=>2845, +24149=>2846, +21215=>2847, +24917=>2848, +12106=>2849, +26408=>2849, +12140=>2850, +30446=>2850, +30566=>2851, +29287=>2852, +31302=>2853, +25343=>2854, +21738=>2855, +21584=>2856, +38048=>2857, +37027=>2858, +23068=>2859, +32435=>2860, +27670=>2861, +20035=>2862, +22902=>2863, +32784=>2864, +22856=>2865, +21335=>2866, +30007=>2867, +38590=>2868, +22218=>2869, +25376=>2870, +33041=>2871, +24700=>2872, +38393=>2873, +28118=>2874, +21602=>2875, +39297=>2876, +20869=>2877, +23273=>2878, +33021=>2879, +22958=>2880, +38675=>2881, +20522=>2882, +27877=>2883, +23612=>2884, +25311=>2885, +20320=>2886, +21311=>2887, +33147=>2888, +36870=>2889, +28346=>2890, +34091=>2891, +25288=>2892, +24180=>2893, +30910=>2894, +25781=>2895, +25467=>2896, +24565=>2897, +23064=>2898, +37247=>2899, +40479=>2900, +23615=>2901, +25423=>2902, +32834=>2903, +23421=>2904, +21870=>2905, +38218=>2906, +38221=>2907, +28037=>2908, +24744=>2909, +26592=>2910, +29406=>2911, +20957=>2912, +23425=>2913, +25319=>2914, +27870=>2915, +12124=>2916, +29275=>2916, +25197=>2917, +38062=>2918, +32445=>2919, +33043=>2920, +27987=>2921, +20892=>2922, +24324=>2923, +22900=>2924, +21162=>2925, +24594=>2926, +12069=>2927, +22899=>2927, +26262=>2928, +34384=>2929, +30111=>2930, +25386=>2931, +25062=>2932, +31983=>2933, +35834=>2934, +21734=>2935, +27431=>2936, +40485=>2937, +27572=>2938, +34261=>2939, +21589=>2940, +20598=>2941, +27812=>2942, +21866=>2943, +36276=>2944, +29228=>2945, +24085=>2946, +24597=>2947, +29750=>2948, +25293=>2949, +25490=>2950, +29260=>2951, +24472=>2952, +28227=>2953, +27966=>2954, +25856=>2955, +28504=>2956, +30424=>2957, +30928=>2958, +30460=>2959, +30036=>2960, +21028=>2961, +21467=>2962, +20051=>2963, +24222=>2964, +26049=>2965, +32810=>2966, +32982=>2967, +25243=>2968, +21638=>2969, +21032=>2970, +28846=>2971, +34957=>2972, +36305=>2973, +27873=>2974, +21624=>2975, +32986=>2976, +22521=>2977, +35060=>2978, +36180=>2979, +38506=>2980, +37197=>2981, +20329=>2982, +27803=>2983, +21943=>2984, +30406=>2985, +30768=>2986, +25256=>2987, +28921=>2988, +28558=>2989, +24429=>2990, +34028=>2991, +26842=>2992, +30844=>2993, +31735=>2994, +33192=>2995, +26379=>2996, +40527=>2997, +25447=>2998, +30896=>2999, +22383=>3000, +30738=>3001, +38713=>3002, +25209=>3003, +25259=>3004, +21128=>3005, +29749=>3006, +27607=>3007, +21860=>3008, +33086=>3009, +30130=>3010, +12138=>3011, +30382=>3011, +21305=>3012, +30174=>3013, +20731=>3014, +23617=>3015, +35692=>3016, +31687=>3017, +20559=>3018, +12122=>3019, +29255=>3019, +39575=>3020, +39128=>3021, +28418=>3022, +29922=>3023, +31080=>3024, +25735=>3025, +30629=>3026, +25340=>3027, +39057=>3028, +36139=>3029, +21697=>3030, +32856=>3031, +20050=>3032, +22378=>3033, +33529=>3034, +33805=>3035, +24179=>3036, +20973=>3037, +29942=>3038, +35780=>3039, +23631=>3040, +22369=>3041, +27900=>3042, +39047=>3043, +23110=>3044, +30772=>3045, +39748=>3046, +36843=>3047, +31893=>3048, +21078=>3049, +25169=>3050, +38138=>3051, +20166=>3052, +33670=>3053, +33889=>3054, +33769=>3055, +33970=>3056, +22484=>3057, +26420=>3058, +22275=>3059, +26222=>3060, +28006=>3061, +35889=>3062, +26333=>3063, +28689=>3064, +26399=>3065, +27450=>3066, +26646=>3067, +25114=>3068, +22971=>3069, +19971=>3070, +20932=>3071, +28422=>3072, +26578=>3073, +27791=>3074, +20854=>3075, +26827=>3076, +22855=>3077, +27495=>3078, +30054=>3079, +23822=>3080, +33040=>3081, +40784=>3082, +26071=>3083, +31048=>3084, +31041=>3085, +39569=>3086, +36215=>3087, +23682=>3088, +20062=>3089, +20225=>3090, +21551=>3091, +22865=>3092, +30732=>3093, +22120=>3094, +12115=>3095, +27668=>3095, +36804=>3096, +24323=>3097, +27773=>3098, +27875=>3099, +35755=>3100, +25488=>3101, +24688=>3102, +27965=>3103, +29301=>3104, +25190=>3105, +38030=>3106, +38085=>3107, +21315=>3108, +36801=>3109, +31614=>3110, +20191=>3111, +35878=>3112, +20094=>3113, +40660=>3114, +38065=>3115, +38067=>3116, +21069=>3117, +28508=>3118, +36963=>3119, +27973=>3120, +35892=>3121, +22545=>3122, +23884=>3123, +12107=>3124, +27424=>3124, +27465=>3125, +26538=>3126, +21595=>3127, +33108=>3128, +32652=>3129, +22681=>3130, +34103=>3131, +24378=>3132, +25250=>3133, +27207=>3134, +38201=>3135, +25970=>3136, +24708=>3137, +26725=>3138, +30631=>3139, +20052=>3140, +20392=>3141, +24039=>3142, +38808=>3143, +25772=>3144, +32728=>3145, +23789=>3146, +20431=>3147, +31373=>3148, +20999=>3149, +33540=>3150, +19988=>3151, +24623=>3152, +31363=>3153, +38054=>3154, +20405=>3155, +20146=>3156, +31206=>3157, +29748=>3158, +21220=>3159, +33465=>3160, +25810=>3161, +31165=>3162, +23517=>3163, +27777=>3164, +38738=>3165, +36731=>3166, +27682=>3167, +20542=>3168, +21375=>3169, +28165=>3170, +25806=>3171, +26228=>3172, +27696=>3173, +24773=>3174, +39031=>3175, +35831=>3176, +24198=>3177, +29756=>3178, +31351=>3179, +31179=>3180, +19992=>3181, +37041=>3182, +29699=>3183, +27714=>3184, +22234=>3185, +37195=>3186, +27845=>3187, +36235=>3188, +21306=>3189, +34502=>3190, +26354=>3191, +36527=>3192, +23624=>3193, +39537=>3194, +28192=>3195, +21462=>3196, +23094=>3197, +40843=>3198, +36259=>3199, +21435=>3200, +22280=>3201, +39079=>3202, +26435=>3203, +37275=>3204, +27849=>3205, +20840=>3206, +30154=>3207, +25331=>3208, +12125=>3209, +29356=>3209, +21048=>3210, +21149=>3211, +32570=>3212, +28820=>3213, +30264=>3214, +21364=>3215, +40522=>3216, +27063=>3217, +30830=>3218, +38592=>3219, +35033=>3220, +32676=>3221, +28982=>3222, +29123=>3223, +20873=>3224, +26579=>3225, +29924=>3226, +22756=>3227, +25880=>3228, +22199=>3229, +35753=>3230, +39286=>3231, +25200=>3232, +32469=>3233, +24825=>3234, +28909=>3235, +22764=>3236, +20161=>3237, +12040=>3238, +20154=>3238, +24525=>3239, +38887=>3240, +20219=>3241, +35748=>3242, +20995=>3243, +22922=>3244, +32427=>3245, +25172=>3246, +20173=>3247, +12103=>3248, +26085=>3248, +25102=>3249, +33592=>3250, +33993=>3251, +33635=>3252, +34701=>3253, +29076=>3254, +28342=>3255, +23481=>3256, +32466=>3257, +20887=>3258, +25545=>3259, +26580=>3260, +12161=>3261, +32905=>3261, +33593=>3262, +34837=>3263, +20754=>3264, +23418=>3265, +22914=>3266, +36785=>3267, +20083=>3268, +27741=>3269, +12042=>3270, +20837=>3270, +35109=>3271, +36719=>3272, +38446=>3273, +34122=>3274, +29790=>3275, +38160=>3276, +38384=>3277, +28070=>3278, +33509=>3279, +24369=>3280, +25746=>3281, +27922=>3282, +33832=>3283, +33134=>3284, +40131=>3285, +22622=>3286, +36187=>3287, +19977=>3288, +21441=>3289, +20254=>3290, +25955=>3291, +26705=>3292, +21971=>3293, +20007=>3294, +25620=>3295, +39578=>3296, +25195=>3297, +23234=>3298, +29791=>3299, +12170=>3300, +33394=>3300, +28073=>3301, +26862=>3302, +20711=>3303, +33678=>3304, +30722=>3305, +26432=>3306, +21049=>3307, +27801=>3308, +32433=>3309, +20667=>3310, +21861=>3311, +29022=>3312, +31579=>3313, +26194=>3314, +29642=>3315, +33515=>3316, +26441=>3317, +12077=>3318, +23665=>3318, +21024=>3319, +29053=>3320, +34923=>3321, +38378=>3322, +38485=>3323, +25797=>3324, +36193=>3325, +33203=>3326, +21892=>3327, +27733=>3328, +25159=>3329, +32558=>3330, +22674=>3331, +20260=>3332, +21830=>3333, +36175=>3334, +26188=>3335, +19978=>3336, +23578=>3337, +35059=>3338, +26786=>3339, +25422=>3340, +31245=>3341, +28903=>3342, +33421=>3343, +21242=>3344, +38902=>3345, +23569=>3346, +21736=>3347, +37045=>3348, +32461=>3349, +22882=>3350, +36170=>3351, +34503=>3352, +12166=>3353, +33292=>3353, +33293=>3354, +36198=>3355, +25668=>3356, +23556=>3357, +24913=>3358, +28041=>3359, +31038=>3360, +35774=>3361, +30775=>3362, +30003=>3363, +21627=>3364, +20280=>3365, +12189=>3366, +36523=>3366, +28145=>3367, +23072=>3368, +32453=>3369, +31070=>3370, +27784=>3371, +23457=>3372, +23158=>3373, +29978=>3374, +32958=>3375, +24910=>3376, +28183=>3377, +22768=>3378, +12131=>3379, +29983=>3379, +29989=>3380, +29298=>3381, +21319=>3382, +32499=>3383, +30465=>3384, +30427=>3385, +21097=>3386, +32988=>3387, +22307=>3388, +24072=>3389, +22833=>3390, +29422=>3391, +26045=>3392, +28287=>3393, +35799=>3394, +12075=>3395, +23608=>3395, +34417=>3396, +12055=>3397, +21313=>3397, +12143=>3398, +30707=>3398, +25342=>3399, +26102=>3400, +20160=>3401, +12215=>3402, +39135=>3402, +34432=>3403, +23454=>3404, +35782=>3405, +21490=>3406, +12142=>3407, +30690=>3407, +20351=>3408, +23630=>3409, +39542=>3410, +22987=>3411, +24335=>3412, +12144=>3413, +31034=>3413, +12064=>3414, +22763=>3414, +19990=>3415, +26623=>3416, +20107=>3417, +25325=>3418, +35475=>3419, +36893=>3420, +21183=>3421, +26159=>3422, +21980=>3423, +22124=>3424, +36866=>3425, +20181=>3426, +20365=>3427, +37322=>3428, +39280=>3429, +12114=>3430, +27663=>3430, +24066=>3431, +24643=>3432, +23460=>3433, +35270=>3434, +35797=>3435, +25910=>3436, +12095=>3437, +25163=>3437, +12216=>3438, +39318=>3438, +23432=>3439, +23551=>3440, +25480=>3441, +21806=>3442, +21463=>3443, +30246=>3444, +20861=>3445, +34092=>3446, +26530=>3447, +26803=>3448, +27530=>3449, +25234=>3450, +36755=>3451, +21460=>3452, +33298=>3453, +28113=>3454, +30095=>3455, +20070=>3456, +36174=>3457, +23408=>3458, +29087=>3459, +34223=>3460, +26257=>3461, +26329=>3462, +32626=>3463, +34560=>3464, +12233=>3465, +40653=>3465, +12239=>3466, +40736=>3466, +23646=>3467, +26415=>3468, +36848=>3469, +26641=>3470, +26463=>3471, +25101=>3472, +31446=>3473, +22661=>3474, +24246=>3475, +25968=>3476, +28465=>3477, +24661=>3478, +21047=>3479, +32781=>3480, +25684=>3481, +34928=>3482, +29993=>3483, +24069=>3484, +26643=>3485, +25332=>3486, +38684=>3487, +21452=>3488, +29245=>3489, +35841=>3490, +12116=>3491, +27700=>3491, +30561=>3492, +31246=>3493, +21550=>3494, +30636=>3495, +39034=>3496, +33308=>3497, +35828=>3498, +30805=>3499, +26388=>3500, +28865=>3501, +26031=>3502, +25749=>3503, +22070=>3504, +24605=>3505, +31169=>3506, +21496=>3507, +19997=>3508, +27515=>3509, +32902=>3510, +23546=>3511, +21987=>3512, +22235=>3513, +20282=>3514, +20284=>3515, +39282=>3516, +24051=>3517, +26494=>3518, +32824=>3519, +24578=>3520, +39042=>3521, +36865=>3522, +23435=>3523, +35772=>3524, +35829=>3525, +25628=>3526, +33368=>3527, +25822=>3528, +22013=>3529, +33487=>3530, +37221=>3531, +20439=>3532, +32032=>3533, +36895=>3534, +31903=>3535, +20723=>3536, +22609=>3537, +28335=>3538, +23487=>3539, +35785=>3540, +32899=>3541, +37240=>3542, +33948=>3543, +31639=>3544, +34429=>3545, +38539=>3546, +38543=>3547, +32485=>3548, +39635=>3549, +30862=>3550, +23681=>3551, +31319=>3552, +36930=>3553, +38567=>3554, +31071=>3555, +23385=>3556, +25439=>3557, +31499=>3558, +34001=>3559, +26797=>3560, +21766=>3561, +32553=>3562, +29712=>3563, +32034=>3564, +38145=>3565, +25152=>3566, +22604=>3567, +20182=>3568, +23427=>3569, +22905=>3570, +22612=>3571, +29549=>3572, +25374=>3573, +36427=>3574, +36367=>3575, +32974=>3576, +33492=>3577, +25260=>3578, +21488=>3579, +27888=>3580, +37214=>3581, +22826=>3582, +24577=>3583, +27760=>3584, +22349=>3585, +25674=>3586, +36138=>3587, +30251=>3588, +28393=>3589, +22363=>3590, +27264=>3591, +30192=>3592, +28525=>3593, +35885=>3594, +35848=>3595, +22374=>3596, +27631=>3597, +34962=>3598, +30899=>3599, +25506=>3600, +21497=>3601, +28845=>3602, +27748=>3603, +22616=>3604, +25642=>3605, +22530=>3606, +26848=>3607, +33179=>3608, +21776=>3609, +31958=>3610, +20504=>3611, +36538=>3612, +28108=>3613, +36255=>3614, +28907=>3615, +25487=>3616, +28059=>3617, +28372=>3618, +32486=>3619, +33796=>3620, +26691=>3621, +36867=>3622, +28120=>3623, +38518=>3624, +35752=>3625, +22871=>3626, +29305=>3627, +34276=>3628, +33150=>3629, +30140=>3630, +35466=>3631, +26799=>3632, +21076=>3633, +36386=>3634, +38161=>3635, +25552=>3636, +39064=>3637, +36420=>3638, +21884=>3639, +20307=>3640, +26367=>3641, +22159=>3642, +24789=>3643, +28053=>3644, +21059=>3645, +23625=>3646, +22825=>3647, +28155=>3648, +22635=>3649, +12133=>3650, +30000=>3650, +29980=>3651, +24684=>3652, +33300=>3653, +33094=>3654, +25361=>3655, +26465=>3656, +36834=>3657, +30522=>3658, +36339=>3659, +36148=>3660, +38081=>3661, +24086=>3662, +21381=>3663, +21548=>3664, +28867=>3665, +27712=>3666, +24311=>3667, +20572=>3668, +20141=>3669, +24237=>3670, +25402=>3671, +33351=>3672, +36890=>3673, +26704=>3674, +37230=>3675, +30643=>3676, +21516=>3677, +38108=>3678, +24420=>3679, +31461=>3680, +26742=>3681, +25413=>3682, +31570=>3683, +32479=>3684, +30171=>3685, +20599=>3686, +25237=>3687, +22836=>3688, +36879=>3689, +20984=>3690, +31171=>3691, +31361=>3692, +22270=>3693, +24466=>3694, +36884=>3695, +28034=>3696, +23648=>3697, +12063=>3698, +22303=>3698, +21520=>3699, +20820=>3700, +28237=>3701, +22242=>3702, +25512=>3703, +39059=>3704, +33151=>3705, +34581=>3706, +35114=>3707, +36864=>3708, +21534=>3709, +23663=>3710, +33216=>3711, +25302=>3712, +25176=>3713, +33073=>3714, +40501=>3715, +38464=>3716, +39534=>3717, +39548=>3718, +26925=>3719, +22949=>3720, +25299=>3721, +21822=>3722, +25366=>3723, +21703=>3724, +34521=>3725, +27964=>3726, +23043=>3727, +12129=>3728, +29926=>3728, +34972=>3729, +27498=>3730, +22806=>3731, +35916=>3732, +24367=>3733, +28286=>3734, +29609=>3735, +39037=>3736, +20024=>3737, +28919=>3738, +23436=>3739, +30871=>3740, +25405=>3741, +26202=>3742, +30358=>3743, +24779=>3744, +23451=>3745, +23113=>3746, +19975=>3747, +33109=>3748, +27754=>3749, +29579=>3750, +20129=>3751, +26505=>3752, +12153=>3753, +32593=>3753, +24448=>3754, +26106=>3755, +26395=>3756, +24536=>3757, +22916=>3758, +23041=>3759, +24013=>3760, +24494=>3761, +21361=>3762, +38886=>3763, +36829=>3764, +26693=>3765, +22260=>3766, +21807=>3767, +24799=>3768, +20026=>3769, +28493=>3770, +32500=>3771, +33479=>3772, +33806=>3773, +22996=>3774, +20255=>3775, +20266=>3776, +23614=>3777, +32428=>3778, +26410=>3779, +34074=>3780, +21619=>3781, +30031=>3782, +32963=>3783, +21890=>3784, +39759=>3785, +20301=>3786, +28205=>3787, +35859=>3788, +23561=>3789, +24944=>3790, +21355=>3791, +30239=>3792, +28201=>3793, +34442=>3794, +12098=>3795, +25991=>3795, +38395=>3796, +32441=>3797, +21563=>3798, +31283=>3799, +32010=>3800, +38382=>3801, +21985=>3802, +32705=>3803, +29934=>3804, +25373=>3805, +34583=>3806, +28065=>3807, +31389=>3808, +25105=>3809, +26017=>3810, +21351=>3811, +25569=>3812, +27779=>3813, +24043=>3814, +21596=>3815, +38056=>3816, +20044=>3817, +27745=>3818, +35820=>3819, +23627=>3820, +12102=>3821, +26080=>3821, +33436=>3822, +26791=>3823, +21566=>3824, +21556=>3825, +12111=>3826, +27595=>3826, +27494=>3827, +20116=>3828, +25410=>3829, +21320=>3830, +33310=>3831, +20237=>3832, +20398=>3833, +22366=>3834, +25098=>3835, +38654=>3836, +26212=>3837, +29289=>3838, +21247=>3839, +21153=>3840, +24735=>3841, +35823=>3842, +26132=>3843, +29081=>3844, +26512=>3845, +35199=>3846, +30802=>3847, +30717=>3848, +26224=>3849, +22075=>3850, +21560=>3851, +38177=>3852, +29306=>3853, +31232=>3854, +24687=>3855, +24076=>3856, +24713=>3857, +33181=>3858, +12067=>3859, +22805=>3859, +24796=>3860, +29060=>3861, +28911=>3862, +28330=>3863, +27728=>3864, +29312=>3865, +27268=>3866, +34989=>3867, +24109=>3868, +20064=>3869, +23219=>3870, +21916=>3871, +38115=>3872, +27927=>3873, +31995=>3874, +38553=>3875, +25103=>3876, +32454=>3877, +30606=>3878, +34430=>3879, +21283=>3880, +38686=>3881, +36758=>3882, +26247=>3883, +23777=>3884, +20384=>3885, +29421=>3886, +19979=>3887, +21414=>3888, +22799=>3889, +21523=>3890, +25472=>3891, +38184=>3892, +20808=>3893, +20185=>3894, +40092=>3895, +32420=>3896, +21688=>3897, +36132=>3898, +34900=>3899, +33335=>3900, +38386=>3901, +28046=>3902, +24358=>3903, +23244=>3904, +26174=>3905, +38505=>3906, +29616=>3907, +29486=>3908, +21439=>3909, +33146=>3910, +39301=>3911, +32673=>3912, +23466=>3913, +38519=>3914, +38480=>3915, +32447=>3916, +30456=>3917, +21410=>3918, +38262=>3919, +12217=>3920, +39321=>3920, +31665=>3921, +35140=>3922, +28248=>3923, +20065=>3924, +32724=>3925, +31077=>3926, +35814=>3927, +24819=>3928, +21709=>3929, +20139=>3930, +39033=>3931, +24055=>3932, +27233=>3933, +20687=>3934, +21521=>3935, +35937=>3936, +33831=>3937, +30813=>3938, +38660=>3939, +21066=>3940, +21742=>3941, +22179=>3942, +38144=>3943, +28040=>3944, +23477=>3945, +28102=>3946, +26195=>3947, +12073=>3948, +23567=>3948, +23389=>3949, +26657=>3950, +32918=>3951, +21880=>3952, +31505=>3953, +25928=>3954, +26964=>3955, +20123=>3956, +27463=>3957, +34638=>3958, +38795=>3959, +21327=>3960, +25375=>3961, +25658=>3962, +37034=>3963, +26012=>3964, +32961=>3965, +35856=>3966, +20889=>3967, +26800=>3968, +21368=>3969, +34809=>3970, +25032=>3971, +27844=>3972, +27899=>3973, +35874=>3974, +23633=>3975, +34218=>3976, +33455=>3977, +38156=>3978, +27427=>3979, +12191=>3980, +36763=>3980, +26032=>3981, +24571=>3982, +12092=>3983, +24515=>3983, +20449=>3984, +34885=>3985, +26143=>3986, +33125=>3987, +29481=>3988, +24826=>3989, +20852=>3990, +21009=>3991, +22411=>3992, +24418=>3993, +37026=>3994, +12175=>3995, +34892=>3995, +37266=>3996, +24184=>3997, +26447=>3998, +24615=>3999, +22995=>4000, +20804=>4001, +20982=>4002, +33016=>4003, +21256=>4004, +27769=>4005, +38596=>4006, +29066=>4007, +20241=>4008, +20462=>4009, +32670=>4010, +26429=>4011, +21957=>4012, +38152=>4013, +31168=>4014, +34966=>4015, +32483=>4016, +22687=>4017, +25100=>4018, +38656=>4019, +34394=>4020, +22040=>4021, +39035=>4022, +24464=>4023, +35768=>4024, +33988=>4025, +37207=>4026, +21465=>4027, +26093=>4028, +24207=>4029, +30044=>4030, +24676=>4031, +32110=>4032, +23167=>4033, +32490=>4034, +32493=>4035, +36713=>4036, +21927=>4037, +23459=>4038, +24748=>4039, +26059=>4040, +12126=>4041, +29572=>4041, +36873=>4042, +30307=>4043, +30505=>4044, +32474=>4045, +38772=>4046, +34203=>4047, +23398=>4048, +12147=>4049, +31348=>4049, +38634=>4050, +12174=>4051, +34880=>4051, +21195=>4052, +29071=>4053, +24490=>4054, +26092=>4055, +35810=>4056, +23547=>4057, +39535=>4058, +24033=>4059, +27529=>4060, +27739=>4061, +35757=>4062, +35759=>4063, +36874=>4064, +36805=>4065, +21387=>4066, +25276=>4067, +40486=>4068, +40493=>4069, +21568=>4070, +20011=>4071, +33469=>4072, +12123=>4073, +29273=>4073, +34460=>4074, +23830=>4075, +34905=>4076, +28079=>4077, +38597=>4078, +21713=>4079, +20122=>4080, +35766=>4081, +28937=>4082, +21693=>4083, +38409=>4084, +28895=>4085, +28153=>4086, +30416=>4087, +20005=>4088, +30740=>4089, +34578=>4090, +23721=>4091, +24310=>4092, +12180=>4093, +35328=>4093, +39068=>4094, +38414=>4095, +28814=>4096, +27839=>4097, +22852=>4098, +25513=>4099, +30524=>4100, +34893=>4101, +28436=>4102, +33395=>4103, +22576=>4104, +29141=>4105, +21388=>4106, +30746=>4107, +38593=>4108, +21761=>4109, +24422=>4110, +28976=>4111, +23476=>4112, +35866=>4113, +39564=>4114, +27523=>4115, +22830=>4116, +40495=>4117, +31207=>4118, +26472=>4119, +25196=>4120, +20335=>4121, +30113=>4122, +12154=>4123, +32650=>4123, +27915=>4124, +38451=>4125, +27687=>4126, +20208=>4127, +30162=>4128, +20859=>4129, +26679=>4130, +28478=>4131, +36992=>4132, +33136=>4133, +22934=>4134, +29814=>4135, +25671=>4136, +23591=>4137, +36965=>4138, +31377=>4139, +35875=>4140, +23002=>4141, +21676=>4142, +33280=>4143, +33647=>4144, +35201=>4145, +32768=>4146, +26928=>4147, +22094=>4148, +32822=>4149, +29239=>4150, +37326=>4151, +20918=>4152, +20063=>4153, +39029=>4154, +25494=>4155, +19994=>4156, +21494=>4157, +26355=>4158, +33099=>4159, +22812=>4160, +28082=>4161, +12032=>4162, +19968=>4162, +22777=>4163, +21307=>4164, +25558=>4165, +38129=>4166, +20381=>4167, +20234=>4168, +12176=>4169, +34915=>4169, +39056=>4170, +22839=>4171, +36951=>4172, +31227=>4173, +20202=>4174, +33008=>4175, +30097=>4176, +27778=>4177, +23452=>4178, +23016=>4179, +24413=>4180, +26885=>4181, +34433=>4182, +20506=>4183, +24050=>4184, +12036=>4185, +20057=>4185, +30691=>4186, +20197=>4187, +33402=>4188, +25233=>4189, +26131=>4190, +12194=>4191, +37009=>4191, +23673=>4192, +20159=>4193, +24441=>4194, +33222=>4195, +36920=>4196, +32900=>4197, +30123=>4198, +20134=>4199, +35028=>4200, +24847=>4201, +27589=>4202, +24518=>4203, +20041=>4204, +30410=>4205, +28322=>4206, +35811=>4207, +35758=>4208, +35850=>4209, +35793=>4210, +24322=>4211, +32764=>4212, +32716=>4213, +32462=>4214, +33589=>4215, +33643=>4216, +22240=>4217, +27575=>4218, +12211=>4219, +38899=>4219, +38452=>4220, +23035=>4221, +21535=>4222, +38134=>4223, +28139=>4224, +23493=>4225, +39278=>4226, +23609=>4227, +24341=>4228, +38544=>4229, +21360=>4230, +33521=>4231, +27185=>4232, +23156=>4233, +40560=>4234, +24212=>4235, +32552=>4236, +33721=>4237, +33828=>4238, +33829=>4239, +33639=>4240, +34631=>4241, +36814=>4242, +36194=>4243, +30408=>4244, +24433=>4245, +39062=>4246, +30828=>4247, +26144=>4248, +21727=>4249, +25317=>4250, +20323=>4251, +33219=>4252, +30152=>4253, +24248=>4254, +38605=>4255, +36362=>4256, +34553=>4257, +21647=>4258, +27891=>4259, +28044=>4260, +27704=>4261, +24703=>4262, +21191=>4263, +12132=>4264, +29992=>4264, +24189=>4265, +20248=>4266, +24736=>4267, +24551=>4268, +23588=>4269, +30001=>4270, +37038=>4271, +38080=>4272, +29369=>4273, +27833=>4274, +28216=>4275, +12195=>4276, +37193=>4276, +26377=>4277, +21451=>4278, +21491=>4279, +20305=>4280, +37321=>4281, +35825=>4282, +12060=>4283, +21448=>4283, +24188=>4284, +36802=>4285, +28132=>4286, +20110=>4287, +30402=>4288, +27014=>4289, +34398=>4290, +24858=>4291, +33286=>4292, +20313=>4293, +20446=>4294, +36926=>4295, +40060=>4296, +24841=>4297, +28189=>4298, +28180=>4299, +38533=>4300, +20104=>4301, +23089=>4302, +12204=>4303, +38632=>4303, +19982=>4304, +23679=>4305, +31161=>4306, +23431=>4307, +35821=>4308, +12155=>4309, +32701=>4309, +12127=>4310, +29577=>4310, +22495=>4311, +33419=>4312, +37057=>4313, +21505=>4314, +36935=>4315, +21947=>4316, +23786=>4317, +24481=>4318, +24840=>4319, +27442=>4320, +29425=>4321, +32946=>4322, +35465=>4323, +28020=>4324, +23507=>4325, +35029=>4326, +39044=>4327, +35947=>4328, +39533=>4329, +40499=>4330, +28170=>4331, +20900=>4332, +20803=>4333, +22435=>4334, +34945=>4335, +21407=>4336, +25588=>4337, +36757=>4338, +22253=>4339, +21592=>4340, +22278=>4341, +29503=>4342, +28304=>4343, +32536=>4344, +36828=>4345, +33489=>4346, +24895=>4347, +24616=>4348, +38498=>4349, +12104=>4350, +26352=>4350, +32422=>4351, +36234=>4352, +36291=>4353, +38053=>4354, +23731=>4355, +31908=>4356, +12105=>4357, +26376=>4357, +24742=>4358, +38405=>4359, +32792=>4360, +20113=>4361, +37095=>4362, +21248=>4363, +38504=>4364, +20801=>4365, +36816=>4366, +34164=>4367, +37213=>4368, +26197=>4369, +38901=>4370, +23381=>4371, +21277=>4372, +30776=>4373, +26434=>4374, +26685=>4375, +21705=>4376, +28798=>4377, +23472=>4378, +36733=>4379, +20877=>4380, +22312=>4381, +21681=>4382, +25874=>4383, +26242=>4384, +36190=>4385, +36163=>4386, +33039=>4387, +33900=>4388, +36973=>4389, +31967=>4390, +20991=>4391, +34299=>4392, +26531=>4393, +26089=>4394, +28577=>4395, +34468=>4396, +36481=>4397, +22122=>4398, +36896=>4399, +30338=>4400, +28790=>4401, +29157=>4402, +36131=>4403, +25321=>4404, +21017=>4405, +27901=>4406, +36156=>4407, +24590=>4408, +22686=>4409, +24974=>4410, +26366=>4411, +36192=>4412, +25166=>4413, +21939=>4414, +28195=>4415, +26413=>4416, +36711=>4417, +38113=>4418, +38392=>4419, +30504=>4420, +26629=>4421, +27048=>4422, +21643=>4423, +20045=>4424, +28856=>4425, +35784=>4426, +25688=>4427, +25995=>4428, +23429=>4429, +31364=>4430, +20538=>4431, +23528=>4432, +30651=>4433, +27617=>4434, +35449=>4435, +31896=>4436, +27838=>4437, +30415=>4438, +26025=>4439, +36759=>4440, +23853=>4441, +23637=>4442, +34360=>4443, +26632=>4444, +21344=>4445, +25112=>4446, +31449=>4447, +28251=>4448, +32509=>4449, +27167=>4450, +31456=>4451, +24432=>4452, +28467=>4453, +24352=>4454, +25484=>4455, +28072=>4456, +26454=>4457, +19976=>4458, +24080=>4459, +36134=>4460, +20183=>4461, +32960=>4462, +30260=>4463, +38556=>4464, +25307=>4465, +26157=>4466, +25214=>4467, +27836=>4468, +36213=>4469, +29031=>4470, +32617=>4471, +20806=>4472, +32903=>4473, +21484=>4474, +36974=>4475, +25240=>4476, +21746=>4477, +34544=>4478, +36761=>4479, +32773=>4480, +38167=>4481, +34071=>4482, +36825=>4483, +27993=>4484, +29645=>4485, +26015=>4486, +30495=>4487, +29956=>4488, +30759=>4489, +33275=>4490, +36126=>4491, +38024=>4492, +20390=>4493, +26517=>4494, +30137=>4495, +35786=>4496, +38663=>4497, +25391=>4498, +38215=>4499, +38453=>4500, +33976=>4501, +25379=>4502, +30529=>4503, +24449=>4504, +29424=>4505, +20105=>4506, +24596=>4507, +25972=>4508, +25327=>4509, +27491=>4510, +25919=>4511, +24103=>4512, +30151=>4513, +37073=>4514, +35777=>4515, +33437=>4516, +26525=>4517, +12096=>4518, +25903=>4518, +21553=>4519, +34584=>4520, +30693=>4521, +32930=>4522, +33026=>4523, +27713=>4524, +20043=>4525, +32455=>4526, +32844=>4527, +30452=>4528, +26893=>4529, +27542=>4530, +25191=>4531, +20540=>4532, +20356=>4533, +22336=>4534, +25351=>4535, +12108=>4536, +27490=>4536, +36286=>4537, +21482=>4538, +26088=>4539, +32440=>4540, +24535=>4541, +25370=>4542, +25527=>4543, +12164=>4544, +33267=>4544, +33268=>4545, +32622=>4546, +24092=>4547, +23769=>4548, +21046=>4549, +26234=>4550, +31209=>4551, +31258=>4552, +36136=>4553, +28825=>4554, +30164=>4555, +28382=>4556, +27835=>4557, +31378=>4558, +20013=>4559, +30405=>4560, +24544=>4561, +38047=>4562, +34935=>4563, +32456=>4564, +31181=>4565, +32959=>4566, +37325=>4567, +20210=>4568, +20247=>4569, +12168=>4570, +33311=>4570, +21608=>4571, +24030=>4572, +27954=>4573, +35788=>4574, +31909=>4575, +36724=>4576, +32920=>4577, +24090=>4578, +21650=>4579, +30385=>4580, +23449=>4581, +26172=>4582, +39588=>4583, +29664=>4584, +26666=>4585, +34523=>4586, +26417=>4587, +29482=>4588, +35832=>4589, +35803=>4590, +36880=>4591, +12149=>4592, +31481=>4592, +28891=>4593, +29038=>4594, +25284=>4595, +30633=>4596, +22065=>4597, +20027=>4598, +33879=>4599, +26609=>4600, +21161=>4601, +34496=>4602, +36142=>4603, +38136=>4604, +31569=>4605, +20303=>4606, +27880=>4607, +31069=>4608, +39547=>4609, +25235=>4610, +12118=>4611, +29226=>4611, +25341=>4612, +19987=>4613, +30742=>4614, +36716=>4615, +25776=>4616, +36186=>4617, +31686=>4618, +26729=>4619, +24196=>4620, +35013=>4621, +22918=>4622, +25758=>4623, +22766=>4624, +29366=>4625, +26894=>4626, +38181=>4627, +36861=>4628, +36184=>4629, +22368=>4630, +32512=>4631, +35846=>4632, +20934=>4633, +25417=>4634, +25305=>4635, +21331=>4636, +26700=>4637, +29730=>4638, +33537=>4639, +37196=>4640, +21828=>4641, +30528=>4642, +28796=>4643, +27978=>4644, +20857=>4645, +21672=>4646, +36164=>4647, +23039=>4648, +28363=>4649, +28100=>4650, +23388=>4651, +32043=>4652, +20180=>4653, +31869=>4654, +28371=>4655, +12070=>4656, +23376=>4656, +12163=>4657, +33258=>4657, +28173=>4658, +23383=>4659, +39683=>4660, +26837=>4661, +36394=>4662, +23447=>4663, +32508=>4664, +24635=>4665, +32437=>4666, +37049=>4667, +12187=>4668, +36208=>4668, +22863=>4669, +25549=>4670, +31199=>4671, +12188=>4672, +36275=>4672, +21330=>4673, +26063=>4674, +31062=>4675, +35781=>4676, +38459=>4677, +32452=>4678, +38075=>4679, +32386=>4680, +22068=>4681, +37257=>4682, +26368=>4683, +32618=>4684, +23562=>4685, +36981=>4686, +26152=>4687, +24038=>4688, +20304=>4689, +26590=>4690, +20570=>4691, +20316=>4692, +22352=>4693, +24231=>4694, +20109=>4695, +19980=>4696, +20800=>4697, +64012=>4697, +19984=>4698, +24319=>4699, +21317=>4700, +19989=>4701, +20120=>4702, +19998=>4703, +12224=>4704, +39730=>4704, +23404=>4705, +22121=>4706, +12033=>4707, +20008=>4707, +31162=>4708, +12035=>4709, +20031=>4709, +12052=>4710, +21269=>4710, +20039=>4711, +22829=>4712, +12120=>4713, +29243=>4713, +21358=>4714, +27664=>4715, +22239=>4716, +32996=>4717, +39319=>4718, +27603=>4719, +30590=>4720, +40727=>4721, +12034=>4722, +20022=>4722, +20127=>4723, +40720=>4724, +20060=>4725, +20073=>4726, +20115=>4727, +33416=>4728, +23387=>4729, +21868=>4730, +22031=>4731, +20164=>4732, +21389=>4733, +21405=>4734, +21411=>4735, +21413=>4736, +21422=>4737, +38757=>4738, +36189=>4739, +12053=>4740, +21274=>4740, +21493=>4741, +21286=>4742, +21294=>4743, +21310=>4744, +36188=>4745, +21350=>4746, +21347=>4747, +20994=>4748, +21000=>4749, +21006=>4750, +21037=>4751, +21043=>4752, +21055=>4753, +21056=>4754, +21068=>4755, +21086=>4756, +21089=>4757, +21084=>4758, +33967=>4759, +21117=>4760, +21122=>4761, +21121=>4762, +21136=>4763, +21139=>4764, +12044=>4765, +20866=>4765, +32596=>4766, +20155=>4767, +20163=>4768, +20169=>4769, +20162=>4770, +20200=>4771, +20193=>4772, +20203=>4773, +20190=>4774, +20251=>4775, +20211=>4776, +20258=>4777, +20324=>4778, +20213=>4779, +20261=>4780, +20263=>4781, +20233=>4782, +20267=>4783, +20318=>4784, +20327=>4785, +25912=>4786, +20314=>4787, +20317=>4788, +20319=>4789, +20311=>4790, +20274=>4791, +20285=>4792, +20342=>4793, +20340=>4794, +20369=>4795, +20361=>4796, +20355=>4797, +20367=>4798, +20350=>4799, +20347=>4800, +20394=>4801, +20348=>4802, +20396=>4803, +20372=>4804, +20454=>4805, +20456=>4806, +20458=>4807, +20421=>4808, +20442=>4809, +20451=>4810, +20444=>4811, +20433=>4812, +20447=>4813, +20472=>4814, +20521=>4815, +20556=>4816, +20467=>4817, +20524=>4818, +20495=>4819, +20526=>4820, +20525=>4821, +20478=>4822, +20508=>4823, +20492=>4824, +20517=>4825, +20520=>4826, +20606=>4827, +20547=>4828, +20565=>4829, +20552=>4830, +20558=>4831, +20588=>4832, +20603=>4833, +20645=>4834, +20647=>4835, +20649=>4836, +20666=>4837, +20694=>4838, +20742=>4839, +20717=>4840, +20716=>4841, +20710=>4842, +20718=>4843, +20743=>4844, +20747=>4845, +20189=>4846, +27709=>4847, +20312=>4848, +20325=>4849, +20430=>4850, +12245=>4851, +40864=>4851, +27718=>4852, +31860=>4853, +20846=>4854, +24061=>4855, +40649=>4856, +39320=>4857, +20865=>4858, +22804=>4859, +12051=>4860, +21241=>4860, +21261=>4861, +35335=>4862, +21264=>4863, +20971=>4864, +22809=>4865, +20821=>4866, +12039=>4867, +20128=>4867, +20822=>4868, +20147=>4869, +34926=>4870, +34980=>4871, +20149=>4872, +33044=>4873, +35026=>4874, +31104=>4875, +23348=>4876, +34819=>4877, +32696=>4878, +12046=>4879, +20907=>4879, +20913=>4880, +20925=>4881, +20924=>4882, +20935=>4883, +12045=>4884, +20886=>4884, +20898=>4885, +20901=>4886, +35744=>4887, +35750=>4888, +35751=>4889, +35754=>4890, +35764=>4891, +35765=>4892, +35767=>4893, +35778=>4894, +35779=>4895, +35787=>4896, +35791=>4897, +35790=>4898, +35794=>4899, +35795=>4900, +35796=>4901, +35798=>4902, +35800=>4903, +35801=>4904, +35804=>4905, +35807=>4906, +35808=>4907, +35812=>4908, +35816=>4909, +35817=>4910, +35822=>4911, +35824=>4912, +35827=>4913, +35830=>4914, +35833=>4915, +35836=>4916, +35839=>4917, +35840=>4918, +35842=>4919, +35844=>4920, +35847=>4921, +35852=>4922, +35855=>4923, +35857=>4924, +35858=>4925, +35860=>4926, +35861=>4927, +35862=>4928, +35865=>4929, +35867=>4930, +35864=>4931, +35869=>4932, +35871=>4933, +35872=>4934, +35873=>4935, +35877=>4936, +35879=>4937, +35882=>4938, +35883=>4939, +35886=>4940, +35887=>4941, +35890=>4942, +35891=>4943, +35893=>4944, +35894=>4945, +12057=>4946, +21353=>4946, +21370=>4947, +38429=>4948, +38434=>4949, +38433=>4950, +38449=>4951, +38442=>4952, +38461=>4953, +38460=>4954, +38466=>4955, +38473=>4956, +38484=>4957, +38495=>4958, +38503=>4959, +38508=>4960, +38514=>4961, +38516=>4962, +38536=>4963, +38541=>4964, +38551=>4965, +38576=>4966, +37015=>4967, +37019=>4968, +37021=>4969, +37017=>4970, +37036=>4971, +37025=>4972, +37044=>4973, +37043=>4974, +37046=>4975, +37050=>4976, +37048=>4977, +37040=>4978, +37071=>4979, +37061=>4980, +37054=>4981, +37072=>4982, +37060=>4983, +37063=>4984, +37075=>4985, +37094=>4986, +37090=>4987, +37084=>4988, +37079=>4989, +37083=>4990, +37099=>4991, +37103=>4992, +37118=>4993, +37124=>4994, +37154=>4995, +37150=>4996, +37155=>4997, +37169=>4998, +37167=>4999, +37177=>5000, +37187=>5001, +37190=>5002, +21005=>5003, +22850=>5004, +21154=>5005, +21164=>5006, +21165=>5007, +21182=>5008, +21759=>5009, +21200=>5010, +21206=>5011, +21232=>5012, +21471=>5013, +29166=>5014, +30669=>5015, +12085=>5016, +24308=>5016, +12048=>5017, +20981=>5017, +20988=>5018, +12223=>5019, +39727=>5019, +12059=>5020, +21430=>5020, +24321=>5021, +30042=>5022, +24047=>5023, +22348=>5024, +22441=>5025, +22433=>5026, +22654=>5027, +22716=>5028, +22725=>5029, +22737=>5030, +22313=>5031, +22316=>5032, +22314=>5033, +22323=>5034, +22329=>5035, +22318=>5036, +22319=>5037, +22364=>5038, +22331=>5039, +22338=>5040, +22377=>5041, +22405=>5042, +22379=>5043, +22406=>5044, +22396=>5045, +22395=>5046, +22376=>5047, +22381=>5048, +22390=>5049, +22387=>5050, +22445=>5051, +22436=>5052, +22412=>5053, +22450=>5054, +22479=>5055, +22439=>5056, +22452=>5057, +22419=>5058, +22432=>5059, +22485=>5060, +22488=>5061, +22490=>5062, +22489=>5063, +22482=>5064, +22456=>5065, +22516=>5066, +22511=>5067, +22520=>5068, +22500=>5069, +22493=>5070, +22539=>5071, +22541=>5072, +22525=>5073, +22509=>5074, +22528=>5075, +22558=>5076, +22553=>5077, +22596=>5078, +22560=>5079, +22629=>5080, +22636=>5081, +22657=>5082, +22665=>5083, +22682=>5084, +22656=>5085, +39336=>5086, +40729=>5087, +25087=>5088, +33401=>5089, +33405=>5090, +33407=>5091, +33423=>5092, +33418=>5093, +33448=>5094, +33412=>5095, +33422=>5096, +33425=>5097, +33431=>5098, +33433=>5099, +33451=>5100, +33464=>5101, +33470=>5102, +33456=>5103, +33480=>5104, +33482=>5105, +33507=>5106, +33432=>5107, +33463=>5108, +33454=>5109, +33483=>5110, +33484=>5111, +33473=>5112, +33449=>5113, +33460=>5114, +33441=>5115, +33450=>5116, +33439=>5117, +33476=>5118, +33486=>5119, +33444=>5120, +33505=>5121, +33545=>5122, +33527=>5123, +33508=>5124, +33551=>5125, +33543=>5126, +33500=>5127, +33524=>5128, +33490=>5129, +33496=>5130, +33548=>5131, +33531=>5132, +33491=>5133, +33553=>5134, +33562=>5135, +33542=>5136, +33556=>5137, +33557=>5138, +33504=>5139, +33493=>5140, +33564=>5141, +33617=>5142, +33627=>5143, +33628=>5144, +33544=>5145, +33682=>5146, +33596=>5147, +33588=>5148, +33585=>5149, +33691=>5150, +33630=>5151, +33583=>5152, +33615=>5153, +33607=>5154, +33603=>5155, +33631=>5156, +33600=>5157, +33559=>5158, +33632=>5159, +33581=>5160, +33594=>5161, +33587=>5162, +33638=>5163, +33637=>5164, +33640=>5165, +33563=>5166, +33641=>5167, +33644=>5168, +33642=>5169, +33645=>5170, +33646=>5171, +33712=>5172, +33656=>5173, +33715=>5174, +33716=>5175, +33696=>5176, +33706=>5177, +33683=>5178, +33692=>5179, +33669=>5180, +33660=>5181, +33718=>5182, +33705=>5183, +33661=>5184, +33720=>5185, +33659=>5186, +33688=>5187, +33694=>5188, +33704=>5189, +33722=>5190, +33724=>5191, +33729=>5192, +33793=>5193, +33765=>5194, +33752=>5195, +22535=>5196, +33816=>5197, +33803=>5198, +33757=>5199, +33789=>5200, +33750=>5201, +33820=>5202, +33848=>5203, +33809=>5204, +33798=>5205, +33748=>5206, +33759=>5207, +33807=>5208, +33795=>5209, +33784=>5210, +33785=>5211, +33770=>5212, +33733=>5213, +33728=>5214, +33830=>5215, +33776=>5216, +33761=>5217, +33884=>5218, +33873=>5219, +33882=>5220, +33881=>5221, +33907=>5222, +33927=>5223, +33928=>5224, +33914=>5225, +33929=>5226, +33912=>5227, +33852=>5228, +33862=>5229, +33897=>5230, +33910=>5231, +33932=>5232, +33934=>5233, +33841=>5234, +33901=>5235, +33985=>5236, +33997=>5237, +34000=>5238, +34022=>5239, +33981=>5240, +34003=>5241, +33994=>5242, +33983=>5243, +33978=>5244, +34016=>5245, +33953=>5246, +33977=>5247, +33972=>5248, +33943=>5249, +34021=>5250, +34019=>5251, +34060=>5252, +29965=>5253, +34104=>5254, +34032=>5255, +34105=>5256, +34079=>5257, +34106=>5258, +34134=>5259, +34107=>5260, +34047=>5261, +34044=>5262, +34137=>5263, +34120=>5264, +34152=>5265, +34148=>5266, +34142=>5267, +34170=>5268, +30626=>5269, +34115=>5270, +34162=>5271, +34171=>5272, +34212=>5273, +34216=>5274, +34183=>5275, +34191=>5276, +34169=>5277, +34222=>5278, +34204=>5279, +34181=>5280, +34233=>5281, +34231=>5282, +34224=>5283, +34259=>5284, +34241=>5285, +34268=>5286, +34303=>5287, +34343=>5288, +34309=>5289, +34345=>5290, +34326=>5291, +34364=>5292, +12086=>5293, +24318=>5293, +24328=>5294, +22844=>5295, +22849=>5296, +32823=>5297, +22869=>5298, +22874=>5299, +22872=>5300, +21263=>5301, +12074=>5302, +23586=>5302, +23589=>5303, +23596=>5304, +23604=>5305, +25164=>5306, +25194=>5307, +25247=>5308, +25275=>5309, +25290=>5310, +25306=>5311, +25303=>5312, +25326=>5313, +25378=>5314, +25334=>5315, +25401=>5316, +25419=>5317, +25411=>5318, +25517=>5319, +25590=>5320, +25457=>5321, +25466=>5322, +25486=>5323, +25524=>5324, +25453=>5325, +25516=>5326, +25482=>5327, +25449=>5328, +25518=>5329, +25532=>5330, +25586=>5331, +25592=>5332, +25568=>5333, +25599=>5334, +25540=>5335, +25566=>5336, +25550=>5337, +25682=>5338, +25542=>5339, +25534=>5340, +25669=>5341, +25665=>5342, +25611=>5343, +25627=>5344, +25632=>5345, +25612=>5346, +25638=>5347, +25633=>5348, +25694=>5349, +25732=>5350, +25709=>5351, +25750=>5352, +25722=>5353, +25783=>5354, +25784=>5355, +25753=>5356, +25786=>5357, +25792=>5358, +25808=>5359, +25815=>5360, +25828=>5361, +25826=>5362, +25865=>5363, +25893=>5364, +25902=>5365, +12087=>5366, +24331=>5366, +24530=>5367, +29977=>5368, +24337=>5369, +21343=>5370, +21489=>5371, +21501=>5372, +21481=>5373, +21480=>5374, +21499=>5375, +21522=>5376, +21526=>5377, +21510=>5378, +21579=>5379, +21586=>5380, +21587=>5381, +21588=>5382, +21590=>5383, +21571=>5384, +21537=>5385, +21591=>5386, +21593=>5387, +21539=>5388, +21554=>5389, +21634=>5390, +21652=>5391, +21623=>5392, +21617=>5393, +21604=>5394, +21658=>5395, +21659=>5396, +21636=>5397, +21622=>5398, +21606=>5399, +21661=>5400, +21712=>5401, +21677=>5402, +21698=>5403, +21684=>5404, +21714=>5405, +21671=>5406, +21670=>5407, +21715=>5408, +21716=>5409, +21618=>5410, +21667=>5411, +21717=>5412, +21691=>5413, +21695=>5414, +21708=>5415, +21721=>5416, +21722=>5417, +21724=>5418, +21673=>5419, +21674=>5420, +21668=>5421, +21725=>5422, +21711=>5423, +21726=>5424, +21787=>5425, +21735=>5426, +21792=>5427, +21757=>5428, +21780=>5429, +21747=>5430, +21794=>5431, +21795=>5432, +21775=>5433, +21777=>5434, +21799=>5435, +21802=>5436, +21863=>5437, +21903=>5438, +21941=>5439, +21833=>5440, +21869=>5441, +21825=>5442, +21845=>5443, +21823=>5444, +21840=>5445, +21820=>5446, +21815=>5447, +21846=>5448, +21877=>5449, +21878=>5450, +21879=>5451, +21811=>5452, +21808=>5453, +21852=>5454, +21899=>5455, +21970=>5456, +21891=>5457, +21937=>5458, +21945=>5459, +21896=>5460, +21889=>5461, +21919=>5462, +21886=>5463, +21974=>5464, +21905=>5465, +21883=>5466, +21983=>5467, +21949=>5468, +21950=>5469, +21908=>5470, +21913=>5471, +21994=>5472, +22007=>5473, +21961=>5474, +22047=>5475, +21969=>5476, +21995=>5477, +21996=>5478, +21972=>5479, +21990=>5480, +21981=>5481, +21956=>5482, +21999=>5483, +21989=>5484, +22002=>5485, +22003=>5486, +21964=>5487, +21965=>5488, +21992=>5489, +22005=>5490, +21988=>5491, +36756=>5492, +22046=>5493, +22024=>5494, +22028=>5495, +22017=>5496, +22052=>5497, +22051=>5498, +22014=>5499, +22016=>5500, +22055=>5501, +22061=>5502, +22104=>5503, +22073=>5504, +22103=>5505, +22060=>5506, +22093=>5507, +22114=>5508, +22105=>5509, +22108=>5510, +22092=>5511, +22100=>5512, +22150=>5513, +22116=>5514, +22129=>5515, +22123=>5516, +22139=>5517, +22140=>5518, +22149=>5519, +22163=>5520, +22191=>5521, +22228=>5522, +12062=>5523, +22231=>5523, +22237=>5524, +22241=>5525, +22261=>5526, +22251=>5527, +22265=>5528, +22271=>5529, +22276=>5530, +22282=>5531, +22281=>5532, +22300=>5533, +24079=>5534, +24089=>5535, +24084=>5536, +24081=>5537, +24113=>5538, +24123=>5539, +24124=>5540, +24119=>5541, +24132=>5542, +24148=>5543, +24155=>5544, +24158=>5545, +24161=>5546, +23692=>5547, +23674=>5548, +23693=>5549, +23696=>5550, +23702=>5551, +23688=>5552, +23704=>5553, +23705=>5554, +23697=>5555, +23706=>5556, +23708=>5557, +23733=>5558, +23714=>5559, +23741=>5560, +23724=>5561, +23723=>5562, +23729=>5563, +23715=>5564, +23745=>5565, +23735=>5566, +23748=>5567, +23762=>5568, +23780=>5569, +23755=>5570, +23781=>5571, +23810=>5572, +23811=>5573, +23847=>5574, +23846=>5575, +23854=>5576, +23844=>5577, +23838=>5578, +23814=>5579, +23835=>5580, +23896=>5581, +23870=>5582, +23860=>5583, +23869=>5584, +23916=>5585, +23899=>5586, +23919=>5587, +23901=>5588, +23915=>5589, +23883=>5590, +23882=>5591, +23913=>5592, +23924=>5593, +23938=>5594, +23961=>5595, +23965=>5596, +35955=>5597, +23991=>5598, +24005=>5599, +12091=>5600, +24435=>5600, +24439=>5601, +24450=>5602, +24455=>5603, +24457=>5604, +24460=>5605, +24469=>5606, +24473=>5607, +24476=>5608, +24488=>5609, +24493=>5610, +24501=>5611, +24508=>5612, +34914=>5613, +12090=>5614, +24417=>5614, +29357=>5615, +29360=>5616, +29364=>5617, +29367=>5618, +29368=>5619, +29379=>5620, +29377=>5621, +29390=>5622, +29389=>5623, +29394=>5624, +29416=>5625, +29423=>5626, +29417=>5627, +29426=>5628, +29428=>5629, +29431=>5630, +29441=>5631, +29427=>5632, +29443=>5633, +29434=>5634, +29435=>5635, +29463=>5636, +29459=>5637, +29473=>5638, +29450=>5639, +29470=>5640, +29469=>5641, +29461=>5642, +29474=>5643, +29497=>5644, +29477=>5645, +29484=>5646, +29496=>5647, +29489=>5648, +29520=>5649, +29517=>5650, +29527=>5651, +29536=>5652, +29548=>5653, +29551=>5654, +29566=>5655, +12167=>5656, +33307=>5656, +22821=>5657, +39143=>5658, +22820=>5659, +12065=>5660, +22786=>5660, +39267=>5661, +39271=>5662, +39272=>5663, +39273=>5664, +39274=>5665, +39275=>5666, +39276=>5667, +39284=>5668, +39287=>5669, +39293=>5670, +39296=>5671, +39300=>5672, +39303=>5673, +39306=>5674, +39309=>5675, +39312=>5676, +39313=>5677, +39315=>5678, +39316=>5679, +39317=>5680, +24192=>5681, +24209=>5682, +24203=>5683, +24214=>5684, +24229=>5685, +24224=>5686, +24249=>5687, +24245=>5688, +24254=>5689, +24243=>5690, +36179=>5691, +24274=>5692, +24273=>5693, +24283=>5694, +24296=>5695, +24298=>5696, +33210=>5697, +24516=>5698, +24521=>5699, +24534=>5700, +24527=>5701, +24579=>5702, +24558=>5703, +24580=>5704, +24545=>5705, +24548=>5706, +24574=>5707, +24581=>5708, +24582=>5709, +24554=>5710, +24557=>5711, +24568=>5712, +24601=>5713, +24629=>5714, +24614=>5715, +24603=>5716, +24591=>5717, +24589=>5718, +24617=>5719, +24619=>5720, +24586=>5721, +24639=>5722, +24609=>5723, +24696=>5724, +24697=>5725, +24699=>5726, +24698=>5727, +24642=>5728, +24682=>5729, +24701=>5730, +24726=>5731, +24730=>5732, +24749=>5733, +24733=>5734, +24707=>5735, +24722=>5736, +24716=>5737, +24731=>5738, +24812=>5739, +24763=>5740, +24753=>5741, +24797=>5742, +24792=>5743, +24774=>5744, +24794=>5745, +24756=>5746, +24864=>5747, +24870=>5748, +24853=>5749, +24867=>5750, +24820=>5751, +24832=>5752, +24846=>5753, +24875=>5754, +24906=>5755, +24949=>5756, +25004=>5757, +24980=>5758, +24999=>5759, +25015=>5760, +25044=>5761, +25077=>5762, +24541=>5763, +38579=>5764, +38377=>5765, +38379=>5766, +38385=>5767, +38387=>5768, +38389=>5769, +38390=>5770, +38396=>5771, +38398=>5772, +38403=>5773, +38404=>5774, +38406=>5775, +38408=>5776, +38410=>5777, +38411=>5778, +38412=>5779, +38413=>5780, +38415=>5781, +38418=>5782, +38421=>5783, +38422=>5784, +38423=>5785, +38425=>5786, +38426=>5787, +20012=>5788, +12121=>5789, +29247=>5789, +25109=>5790, +27701=>5791, +27732=>5792, +27740=>5793, +27722=>5794, +27811=>5795, +27781=>5796, +27792=>5797, +27796=>5798, +27788=>5799, +27752=>5800, +27753=>5801, +27764=>5802, +27766=>5803, +27782=>5804, +27817=>5805, +27856=>5806, +27860=>5807, +27821=>5808, +27895=>5809, +27896=>5810, +27889=>5811, +27863=>5812, +27826=>5813, +27872=>5814, +27862=>5815, +27898=>5816, +27883=>5817, +27886=>5818, +27825=>5819, +27859=>5820, +27887=>5821, +27902=>5822, +27961=>5823, +27943=>5824, +27916=>5825, +27971=>5826, +27976=>5827, +27911=>5828, +27908=>5829, +27929=>5830, +27918=>5831, +27947=>5832, +27981=>5833, +27950=>5834, +27957=>5835, +27930=>5836, +27983=>5837, +27986=>5838, +27988=>5839, +27955=>5840, +28049=>5841, +28015=>5842, +28062=>5843, +28064=>5844, +27998=>5845, +28051=>5846, +28052=>5847, +27996=>5848, +28000=>5849, +28028=>5850, +28003=>5851, +28186=>5852, +28103=>5853, +28101=>5854, +28126=>5855, +28174=>5856, +28095=>5857, +28128=>5858, +28177=>5859, +28134=>5860, +28125=>5861, +28121=>5862, +28182=>5863, +28075=>5864, +28172=>5865, +28078=>5866, +28203=>5867, +28270=>5868, +28238=>5869, +28267=>5870, +28338=>5871, +28255=>5872, +28294=>5873, +28243=>5874, +28244=>5875, +28210=>5876, +28197=>5877, +28228=>5878, +28383=>5879, +28337=>5880, +28312=>5881, +28384=>5882, +28461=>5883, +28386=>5884, +28325=>5885, +28327=>5886, +28349=>5887, +28347=>5888, +28343=>5889, +28375=>5890, +28340=>5891, +28367=>5892, +28303=>5893, +28354=>5894, +28319=>5895, +28514=>5896, +28486=>5897, +28487=>5898, +28452=>5899, +28437=>5900, +28409=>5901, +28463=>5902, +28470=>5903, +28491=>5904, +28532=>5905, +28458=>5906, +28425=>5907, +28457=>5908, +28553=>5909, +28557=>5910, +28556=>5911, +28536=>5912, +28530=>5913, +28540=>5914, +28538=>5915, +28625=>5916, +28617=>5917, +28583=>5918, +28601=>5919, +28598=>5920, +28610=>5921, +28641=>5922, +28654=>5923, +28638=>5924, +28640=>5925, +28655=>5926, +28698=>5927, +28707=>5928, +28699=>5929, +28729=>5930, +28725=>5931, +28751=>5932, +28766=>5933, +12071=>5934, +23424=>5934, +23428=>5935, +23445=>5936, +23443=>5937, +23461=>5938, +23480=>5939, +29999=>5940, +39582=>5941, +25652=>5942, +23524=>5943, +23534=>5944, +35120=>5945, +23536=>5946, +36423=>5947, +35591=>5948, +36790=>5949, +36819=>5950, +36821=>5951, +36837=>5952, +36846=>5953, +36836=>5954, +36841=>5955, +36838=>5956, +36851=>5957, +36840=>5958, +36869=>5959, +36868=>5960, +36875=>5961, +36902=>5962, +36881=>5963, +36877=>5964, +36886=>5965, +36897=>5966, +36917=>5967, +36918=>5968, +36909=>5969, +36911=>5970, +36932=>5971, +36945=>5972, +36946=>5973, +36944=>5974, +36968=>5975, +36952=>5976, +36962=>5977, +36955=>5978, +26297=>5979, +36980=>5980, +36989=>5981, +36994=>5982, +37000=>5983, +36995=>5984, +37003=>5985, +12089=>5986, +24400=>5986, +24407=>5987, +24406=>5988, +24408=>5989, +23611=>5990, +21675=>5991, +23632=>5992, +23641=>5993, +23409=>5994, +23651=>5995, +23654=>5996, +32700=>5997, +24362=>5998, +24361=>5999, +24365=>6000, +33396=>6001, +24380=>6002, +39739=>6003, +12076=>6004, +23662=>6004, +22913=>6005, +22915=>6006, +22925=>6007, +22953=>6008, +22954=>6009, +22947=>6010, +22935=>6011, +22986=>6012, +22955=>6013, +22942=>6014, +22948=>6015, +22994=>6016, +22962=>6017, +22959=>6018, +22999=>6019, +22974=>6020, +23045=>6021, +23046=>6022, +23005=>6023, +23048=>6024, +23011=>6025, +23000=>6026, +23033=>6027, +23052=>6028, +23049=>6029, +23090=>6030, +23092=>6031, +23057=>6032, +23075=>6033, +23059=>6034, +23104=>6035, +23143=>6036, +23114=>6037, +23125=>6038, +23100=>6039, +23138=>6040, +23157=>6041, +33004=>6042, +23210=>6043, +23195=>6044, +23159=>6045, +23162=>6046, +23230=>6047, +23275=>6048, +23218=>6049, +23250=>6050, +23252=>6051, +23224=>6052, +23264=>6053, +23267=>6054, +23281=>6055, +23254=>6056, +23270=>6057, +23256=>6058, +23260=>6059, +23305=>6060, +23319=>6061, +23318=>6062, +23346=>6063, +23351=>6064, +23360=>6065, +23573=>6066, +23580=>6067, +23386=>6068, +23397=>6069, +23411=>6070, +23377=>6071, +23379=>6072, +23394=>6073, +39541=>6074, +39543=>6075, +39544=>6076, +39546=>6077, +39551=>6078, +39549=>6079, +39552=>6080, +39553=>6081, +39557=>6082, +39560=>6083, +39562=>6084, +39568=>6085, +39570=>6086, +39571=>6087, +39574=>6088, +39576=>6089, +39579=>6090, +39580=>6091, +39581=>6092, +39583=>6093, +39584=>6094, +39586=>6095, +39587=>6096, +39589=>6097, +39591=>6098, +32415=>6099, +32417=>6100, +32419=>6101, +32421=>6102, +32424=>6103, +32425=>6104, +32429=>6105, +32432=>6106, +32446=>6107, +32448=>6108, +32449=>6109, +32450=>6110, +32457=>6111, +32459=>6112, +32460=>6113, +32464=>6114, +32468=>6115, +32471=>6116, +32475=>6117, +32480=>6118, +32481=>6119, +32488=>6120, +32491=>6121, +32494=>6122, +32495=>6123, +32497=>6124, +32498=>6125, +32525=>6126, +32502=>6127, +32506=>6128, +32507=>6129, +32510=>6130, +32513=>6131, +32514=>6132, +32515=>6133, +32519=>6134, +32520=>6135, +32523=>6136, +32524=>6137, +32527=>6138, +32529=>6139, +32530=>6140, +32535=>6141, +32537=>6142, +32540=>6143, +32539=>6144, +32543=>6145, +32545=>6146, +32546=>6147, +32547=>6148, +32548=>6149, +32549=>6150, +32550=>6151, +32551=>6152, +32554=>6153, +32555=>6154, +32556=>6155, +32557=>6156, +32559=>6157, +32560=>6158, +32561=>6159, +32562=>6160, +32563=>6161, +32565=>6162, +12083=>6163, +24186=>6163, +30079=>6164, +12078=>6165, +24027=>6165, +30014=>6166, +37013=>6167, +29582=>6168, +29585=>6169, +29614=>6170, +29602=>6171, +29599=>6172, +29647=>6173, +29634=>6174, +29649=>6175, +29623=>6176, +29619=>6177, +29632=>6178, +29641=>6179, +29640=>6180, +29669=>6181, +29657=>6182, +39036=>6183, +29706=>6184, +29673=>6185, +29671=>6186, +29662=>6187, +29626=>6188, +29682=>6189, +29711=>6190, +29738=>6191, +29787=>6192, +29734=>6193, +29733=>6194, +29736=>6195, +29744=>6196, +29742=>6197, +29740=>6198, +29723=>6199, +29722=>6200, +29761=>6201, +29788=>6202, +29783=>6203, +29781=>6204, +29785=>6205, +29815=>6206, +29805=>6207, +29822=>6208, +29852=>6209, +29838=>6210, +29824=>6211, +29825=>6212, +29831=>6213, +29835=>6214, +29854=>6215, +29864=>6216, +29865=>6217, +29840=>6218, +29863=>6219, +29906=>6220, +29882=>6221, +38890=>6222, +38891=>6223, +38892=>6224, +26444=>6225, +26451=>6226, +26462=>6227, +26440=>6228, +26473=>6229, +26533=>6230, +26503=>6231, +26474=>6232, +26483=>6233, +26520=>6234, +26535=>6235, +26485=>6236, +26536=>6237, +26526=>6238, +26541=>6239, +26507=>6240, +26487=>6241, +26492=>6242, +26608=>6243, +26633=>6244, +26584=>6245, +26634=>6246, +26601=>6247, +26544=>6248, +26636=>6249, +26585=>6250, +26549=>6251, +26586=>6252, +26547=>6253, +26589=>6254, +26624=>6255, +26563=>6256, +26552=>6257, +26594=>6258, +26638=>6259, +26561=>6260, +26621=>6261, +26674=>6262, +26675=>6263, +26720=>6264, +26721=>6265, +26702=>6266, +26722=>6267, +26692=>6268, +26724=>6269, +26755=>6270, +26653=>6271, +26709=>6272, +26726=>6273, +26689=>6274, +26727=>6275, +26688=>6276, +26686=>6277, +26698=>6278, +26697=>6279, +26665=>6280, +26805=>6281, +26767=>6282, +26740=>6283, +26743=>6284, +26771=>6285, +26731=>6286, +26818=>6287, +26990=>6288, +26876=>6289, +26911=>6290, +26912=>6291, +26873=>6292, +26916=>6293, +26864=>6294, +26891=>6295, +26881=>6296, +26967=>6297, +26851=>6298, +26896=>6299, +26993=>6300, +26937=>6301, +26976=>6302, +26946=>6303, +26973=>6304, +27012=>6305, +26987=>6306, +27008=>6307, +27032=>6308, +27000=>6309, +26932=>6310, +27084=>6311, +27015=>6312, +27016=>6313, +27086=>6314, +27017=>6315, +26982=>6316, +26979=>6317, +27001=>6318, +27035=>6319, +27047=>6320, +27067=>6321, +27051=>6322, +27053=>6323, +27092=>6324, +27057=>6325, +27073=>6326, +27082=>6327, +27103=>6328, +27029=>6329, +27104=>6330, +27021=>6331, +27135=>6332, +27183=>6333, +27117=>6334, +27159=>6335, +27160=>6336, +27237=>6337, +27122=>6338, +27204=>6339, +27198=>6340, +27296=>6341, +27216=>6342, +27227=>6343, +27189=>6344, +27278=>6345, +27257=>6346, +27197=>6347, +27176=>6348, +27224=>6349, +27260=>6350, +27281=>6351, +27280=>6352, +27305=>6353, +27287=>6354, +27307=>6355, +29495=>6356, +29522=>6357, +27521=>6358, +27522=>6359, +27527=>6360, +27524=>6361, +27538=>6362, +27539=>6363, +27533=>6364, +27546=>6365, +27547=>6366, +27553=>6367, +27562=>6368, +36715=>6369, +36717=>6370, +36721=>6371, +36722=>6372, +36723=>6373, +36725=>6374, +36726=>6375, +36728=>6376, +36727=>6377, +36729=>6378, +36730=>6379, +36732=>6380, +36734=>6381, +36737=>6382, +36738=>6383, +36740=>6384, +36743=>6385, +36747=>6386, +36749=>6387, +36750=>6388, +36751=>6389, +36760=>6390, +36762=>6391, +36558=>6392, +25099=>6393, +25111=>6394, +25115=>6395, +25119=>6396, +25122=>6397, +25121=>6398, +25125=>6399, +25124=>6400, +25132=>6401, +33255=>6402, +29935=>6403, +29940=>6404, +29951=>6405, +29967=>6406, +29969=>6407, +29971=>6408, +12097=>6409, +25908=>6409, +26094=>6410, +26095=>6411, +26096=>6412, +26122=>6413, +26137=>6414, +26482=>6415, +26115=>6416, +26133=>6417, +26112=>6418, +28805=>6419, +26359=>6420, +26141=>6421, +26164=>6422, +26161=>6423, +26166=>6424, +26165=>6425, +32774=>6426, +26207=>6427, +26196=>6428, +26177=>6429, +26191=>6430, +26198=>6431, +26209=>6432, +26199=>6433, +26231=>6434, +26244=>6435, +26252=>6436, +26279=>6437, +26269=>6438, +26302=>6439, +26331=>6440, +26332=>6441, +26342=>6442, +26345=>6443, +36146=>6444, +36147=>6445, +36150=>6446, +36155=>6447, +36157=>6448, +36160=>6449, +36165=>6450, +36166=>6451, +36168=>6452, +36169=>6453, +36167=>6454, +36173=>6455, +36181=>6456, +36185=>6457, +35271=>6458, +35274=>6459, +35275=>6460, +35276=>6461, +35278=>6462, +35279=>6463, +35280=>6464, +35281=>6465, +29294=>6466, +29343=>6467, +29277=>6468, +29286=>6469, +29295=>6470, +29310=>6471, +29311=>6472, +29316=>6473, +29323=>6474, +29325=>6475, +29327=>6476, +29330=>6477, +25352=>6478, +25394=>6479, +25520=>6480, +25663=>6481, +25816=>6482, +32772=>6483, +27626=>6484, +27635=>6485, +27645=>6486, +27637=>6487, +27641=>6488, +27653=>6489, +27655=>6490, +27654=>6491, +27661=>6492, +27669=>6493, +27672=>6494, +27673=>6495, +27674=>6496, +27681=>6497, +27689=>6498, +27684=>6499, +27690=>6500, +27698=>6501, +25909=>6502, +25941=>6503, +25963=>6504, +29261=>6505, +29266=>6506, +29270=>6507, +29232=>6508, +34402=>6509, +21014=>6510, +32927=>6511, +32924=>6512, +32915=>6513, +32956=>6514, +26378=>6515, +32957=>6516, +32945=>6517, +32939=>6518, +32941=>6519, +32948=>6520, +32951=>6521, +32999=>6522, +33000=>6523, +33001=>6524, +33002=>6525, +32987=>6526, +32962=>6527, +32964=>6528, +32985=>6529, +32973=>6530, +32983=>6531, +26384=>6532, +32989=>6533, +33003=>6534, +33009=>6535, +33012=>6536, +33005=>6537, +33037=>6538, +33038=>6539, +33010=>6540, +33020=>6541, +26389=>6542, +33042=>6543, +35930=>6544, +33078=>6545, +33054=>6546, +33068=>6547, +33048=>6548, +33074=>6549, +33096=>6550, +33100=>6551, +33107=>6552, +33140=>6553, +33113=>6554, +33114=>6555, +33137=>6556, +33120=>6557, +33129=>6558, +33148=>6559, +33149=>6560, +33133=>6561, +33127=>6562, +22605=>6563, +23221=>6564, +33160=>6565, +33154=>6566, +33169=>6567, +28373=>6568, +33187=>6569, +33194=>6570, +33228=>6571, +26406=>6572, +33226=>6573, +33211=>6574, +33217=>6575, +33190=>6576, +27428=>6577, +27447=>6578, +27449=>6579, +27459=>6580, +27462=>6581, +27481=>6582, +39121=>6583, +39122=>6584, +39123=>6585, +39125=>6586, +39129=>6587, +39130=>6588, +12110=>6589, +27571=>6589, +24384=>6590, +27586=>6591, +35315=>6592, +26000=>6593, +40785=>6594, +26003=>6595, +26044=>6596, +26054=>6597, +26052=>6598, +26051=>6599, +26060=>6600, +26062=>6601, +26066=>6602, +26070=>6603, +28800=>6604, +28828=>6605, +28822=>6606, +28829=>6607, +28859=>6608, +28864=>6609, +28855=>6610, +28843=>6611, +28849=>6612, +28904=>6613, +28874=>6614, +28944=>6615, +28947=>6616, +28950=>6617, +28975=>6618, +28977=>6619, +29043=>6620, +29020=>6621, +29032=>6622, +28997=>6623, +29042=>6624, +29002=>6625, +29048=>6626, +29050=>6627, +29080=>6628, +29107=>6629, +29109=>6630, +29096=>6631, +29088=>6632, +29152=>6633, +29140=>6634, +29159=>6635, +29177=>6636, +29213=>6637, +29224=>6638, +28780=>6639, +28952=>6640, +29030=>6641, +29113=>6642, +25150=>6643, +25149=>6644, +25155=>6645, +25160=>6646, +25161=>6647, +31035=>6648, +31040=>6649, +31046=>6650, +31049=>6651, +31067=>6652, +31068=>6653, +31059=>6654, +31066=>6655, +31074=>6656, +31063=>6657, +31072=>6658, +31087=>6659, +31079=>6660, +31098=>6661, +31109=>6662, +31114=>6663, +31130=>6664, +31143=>6665, +31155=>6666, +24529=>6667, +24528=>6668, +24636=>6669, +24669=>6670, +24666=>6671, +24679=>6672, +24641=>6673, +24665=>6674, +24675=>6675, +24747=>6676, +24838=>6677, +24845=>6678, +24925=>6679, +25001=>6680, +24989=>6681, +25035=>6682, +25041=>6683, +25094=>6684, +32896=>6685, +12160=>6686, +32895=>6686, +27795=>6687, +27894=>6688, +28156=>6689, +30710=>6690, +30712=>6691, +30720=>6692, +30729=>6693, +30743=>6694, +30744=>6695, +30737=>6696, +26027=>6697, +30765=>6698, +30748=>6699, +30749=>6700, +30777=>6701, +30778=>6702, +30779=>6703, +30751=>6704, +30780=>6705, +30757=>6706, +30764=>6707, +30755=>6708, +30761=>6709, +30798=>6710, +30829=>6711, +30806=>6712, +30807=>6713, +30758=>6714, +30800=>6715, +30791=>6716, +30796=>6717, +30826=>6718, +30875=>6719, +30867=>6720, +30874=>6721, +30855=>6722, +30876=>6723, +30881=>6724, +30883=>6725, +30898=>6726, +30905=>6727, +30885=>6728, +30932=>6729, +30937=>6730, +30921=>6731, +30956=>6732, +30962=>6733, +30981=>6734, +30964=>6735, +30995=>6736, +31012=>6737, +31006=>6738, +31028=>6739, +40859=>6740, +12235=>6741, +40697=>6741, +40699=>6742, +40700=>6743, +30449=>6744, +30468=>6745, +30477=>6746, +30457=>6747, +30471=>6748, +30472=>6749, +30490=>6750, +30498=>6751, +30489=>6752, +30509=>6753, +30502=>6754, +30517=>6755, +30520=>6756, +30544=>6757, +30545=>6758, +30535=>6759, +30531=>6760, +30554=>6761, +30568=>6762, +30562=>6763, +30565=>6764, +30591=>6765, +30605=>6766, +30589=>6767, +30592=>6768, +30604=>6769, +30609=>6770, +30623=>6771, +30624=>6772, +30640=>6773, +30645=>6774, +30653=>6775, +30010=>6776, +30016=>6777, +30030=>6778, +30027=>6779, +30024=>6780, +30043=>6781, +30066=>6782, +30073=>6783, +30083=>6784, +32600=>6785, +32609=>6786, +32607=>6787, +35400=>6788, +32616=>6789, +32628=>6790, +32625=>6791, +32633=>6792, +32641=>6793, +32638=>6794, +30413=>6795, +30437=>6796, +34866=>6797, +38021=>6798, +38022=>6799, +38023=>6800, +38027=>6801, +38026=>6802, +38028=>6803, +38029=>6804, +38031=>6805, +38032=>6806, +38036=>6807, +38039=>6808, +38037=>6809, +38042=>6810, +38043=>6811, +38044=>6812, +38051=>6813, +38052=>6814, +38059=>6815, +38058=>6816, +38061=>6817, +38060=>6818, +38063=>6819, +38064=>6820, +38066=>6821, +38068=>6822, +38070=>6823, +38071=>6824, +38072=>6825, +38073=>6826, +38074=>6827, +38076=>6828, +38077=>6829, +38079=>6830, +38084=>6831, +38088=>6832, +38089=>6833, +38090=>6834, +38091=>6835, +38092=>6836, +38093=>6837, +38094=>6838, +38096=>6839, +38097=>6840, +38098=>6841, +38101=>6842, +38102=>6843, +38103=>6844, +38105=>6845, +38104=>6846, +38107=>6847, +38110=>6848, +38111=>6849, +38112=>6850, +38114=>6851, +38116=>6852, +38117=>6853, +38119=>6854, +38120=>6855, +38122=>6856, +38121=>6857, +38123=>6858, +38126=>6859, +38127=>6860, +38131=>6861, +38132=>6862, +38133=>6863, +38135=>6864, +38137=>6865, +38140=>6866, +38141=>6867, +38143=>6868, +38147=>6869, +38146=>6870, +38150=>6871, +38151=>6872, +38153=>6873, +38154=>6874, +38157=>6875, +38158=>6876, +38159=>6877, +38162=>6878, +38163=>6879, +38164=>6880, +38165=>6881, +38166=>6882, +38168=>6883, +38171=>6884, +38173=>6885, +38174=>6886, +38175=>6887, +38178=>6888, +38186=>6889, +38187=>6890, +38185=>6891, +38188=>6892, +38193=>6893, +38194=>6894, +38196=>6895, +38198=>6896, +38199=>6897, +38200=>6898, +38204=>6899, +38206=>6900, +38207=>6901, +38210=>6902, +38197=>6903, +38212=>6904, +38213=>6905, +38214=>6906, +38217=>6907, +38220=>6908, +38222=>6909, +38223=>6910, +38226=>6911, +38227=>6912, +38228=>6913, +38230=>6914, +38231=>6915, +38232=>6916, +38233=>6917, +38235=>6918, +38238=>6919, +38239=>6920, +38237=>6921, +38241=>6922, +38242=>6923, +38244=>6924, +38245=>6925, +38246=>6926, +38247=>6927, +38248=>6928, +38249=>6929, +38250=>6930, +38251=>6931, +38252=>6932, +38255=>6933, +38257=>6934, +38258=>6935, +38259=>6936, +38202=>6937, +30695=>6938, +30700=>6939, +38601=>6940, +31189=>6941, +31213=>6942, +31203=>6943, +31211=>6944, +31238=>6945, +23879=>6946, +31235=>6947, +31234=>6948, +31262=>6949, +31252=>6950, +31289=>6951, +31287=>6952, +31313=>6953, +40655=>6954, +39333=>6955, +31344=>6956, +30344=>6957, +30350=>6958, +30355=>6959, +30361=>6960, +30372=>6961, +29918=>6962, +29920=>6963, +29996=>6964, +40480=>6965, +40482=>6966, +40488=>6967, +40489=>6968, +40490=>6969, +40491=>6970, +40492=>6971, +40498=>6972, +40497=>6973, +40502=>6974, +40504=>6975, +40503=>6976, +40505=>6977, +40506=>6978, +40510=>6979, +40513=>6980, +40514=>6981, +40516=>6982, +40518=>6983, +40519=>6984, +40520=>6985, +40521=>6986, +40523=>6987, +40524=>6988, +40526=>6989, +40529=>6990, +40533=>6991, +40535=>6992, +40538=>6993, +40539=>6994, +40540=>6995, +40542=>6996, +40547=>6997, +40550=>6998, +40551=>6999, +40552=>7000, +40553=>7001, +40554=>7002, +40555=>7003, +40556=>7004, +40561=>7005, +40557=>7006, +40563=>7007, +12135=>7008, +30098=>7008, +30100=>7009, +30102=>7010, +30112=>7011, +30109=>7012, +30124=>7013, +30115=>7014, +30131=>7015, +30132=>7016, +30136=>7017, +30148=>7018, +30129=>7019, +30128=>7020, +30147=>7021, +30146=>7022, +30166=>7023, +30157=>7024, +30179=>7025, +30184=>7026, +30182=>7027, +30180=>7028, +30187=>7029, +30183=>7030, +30211=>7031, +30193=>7032, +30204=>7033, +30207=>7034, +30224=>7035, +30208=>7036, +30213=>7037, +30220=>7038, +30231=>7039, +30218=>7040, +30245=>7041, +30232=>7042, +30229=>7043, +30233=>7044, +30235=>7045, +30268=>7046, +30242=>7047, +30240=>7048, +30272=>7049, +30253=>7050, +30256=>7051, +30271=>7052, +30261=>7053, +30275=>7054, +30270=>7055, +30259=>7056, +30285=>7057, +30302=>7058, +30292=>7059, +30300=>7060, +30294=>7061, +30315=>7062, +30319=>7063, +32714=>7064, +31462=>7065, +31352=>7066, +31353=>7067, +31360=>7068, +31366=>7069, +31368=>7070, +31381=>7071, +31398=>7072, +31392=>7073, +31404=>7074, +31400=>7075, +31405=>7076, +31411=>7077, +34916=>7078, +34921=>7079, +34930=>7080, +34941=>7081, +34943=>7082, +34946=>7083, +34978=>7084, +35014=>7085, +34999=>7086, +35004=>7087, +35017=>7088, +35042=>7089, +35022=>7090, +35043=>7091, +35045=>7092, +35057=>7093, +35098=>7094, +35068=>7095, +35048=>7096, +35070=>7097, +35056=>7098, +35105=>7099, +35097=>7100, +35091=>7101, +35099=>7102, +35082=>7103, +35124=>7104, +35115=>7105, +35126=>7106, +35137=>7107, +35174=>7108, +35195=>7109, +12134=>7110, +30091=>7110, +32997=>7111, +30386=>7112, +30388=>7113, +30684=>7114, +12158=>7115, +32786=>7115, +32788=>7116, +32790=>7117, +32796=>7118, +32800=>7119, +32802=>7120, +32805=>7121, +32806=>7122, +32807=>7123, +32809=>7124, +32808=>7125, +32817=>7126, +32779=>7127, +32821=>7128, +32835=>7129, +32838=>7130, +32845=>7131, +32850=>7132, +32873=>7133, +32881=>7134, +35203=>7135, +39032=>7136, +39040=>7137, +39043=>7138, +39049=>7139, +39052=>7140, +39053=>7141, +39055=>7142, +39060=>7143, +39066=>7144, +39067=>7145, +39070=>7146, +39071=>7147, +39073=>7148, +39074=>7149, +39077=>7150, +39078=>7151, +12172=>7152, +34381=>7152, +34388=>7153, +34412=>7154, +34414=>7155, +34431=>7156, +34426=>7157, +34428=>7158, +34427=>7159, +34472=>7160, +34445=>7161, +34443=>7162, +34476=>7163, +34461=>7164, +34471=>7165, +34467=>7166, +34474=>7167, +34451=>7168, +34473=>7169, +34486=>7170, +34500=>7171, +34485=>7172, +34510=>7173, +34480=>7174, +34490=>7175, +34481=>7176, +34479=>7177, +34505=>7178, +34511=>7179, +34484=>7180, +34537=>7181, +34545=>7182, +34546=>7183, +34541=>7184, +34547=>7185, +34512=>7186, +34579=>7187, +34526=>7188, +34548=>7189, +34527=>7190, +34520=>7191, +34513=>7192, +34563=>7193, +34567=>7194, +34552=>7195, +34568=>7196, +34570=>7197, +34573=>7198, +34569=>7199, +34595=>7200, +34619=>7201, +34590=>7202, +34597=>7203, +34606=>7204, +34586=>7205, +34622=>7206, +34632=>7207, +34612=>7208, +34609=>7209, +34601=>7210, +34615=>7211, +34623=>7212, +34690=>7213, +34594=>7214, +34685=>7215, +34686=>7216, +34683=>7217, +34656=>7218, +34672=>7219, +34636=>7220, +34670=>7221, +34699=>7222, +34643=>7223, +34659=>7224, +34684=>7225, +34660=>7226, +34649=>7227, +34661=>7228, +34707=>7229, +34735=>7230, +34728=>7231, +34770=>7232, +34758=>7233, +34696=>7234, +34693=>7235, +34733=>7236, +34711=>7237, +34691=>7238, +34731=>7239, +34789=>7240, +34732=>7241, +34741=>7242, +34739=>7243, +34763=>7244, +34771=>7245, +34749=>7246, +34769=>7247, +34752=>7248, +34762=>7249, +34779=>7250, +34794=>7251, +34784=>7252, +34798=>7253, +34838=>7254, +34835=>7255, +34814=>7256, +34826=>7257, +34843=>7258, +34849=>7259, +34873=>7260, +34876=>7261, +12152=>7262, +32566=>7262, +32578=>7263, +32580=>7264, +32581=>7265, +33296=>7266, +31482=>7267, +31485=>7268, +31496=>7269, +31491=>7270, +31492=>7271, +31509=>7272, +31498=>7273, +31531=>7274, +31503=>7275, +31559=>7276, +31544=>7277, +31530=>7278, +31513=>7279, +31534=>7280, +31537=>7281, +31520=>7282, +31525=>7283, +31524=>7284, +31539=>7285, +31550=>7286, +31518=>7287, +31576=>7288, +31578=>7289, +31557=>7290, +31605=>7291, +31564=>7292, +31581=>7293, +31584=>7294, +31598=>7295, +31611=>7296, +31586=>7297, +31602=>7298, +31601=>7299, +31632=>7300, +31654=>7301, +31655=>7302, +31672=>7303, +31660=>7304, +31645=>7305, +31656=>7306, +31621=>7307, +31658=>7308, +31644=>7309, +31650=>7310, +31659=>7311, +31668=>7312, +31697=>7313, +31681=>7314, +31692=>7315, +31709=>7316, +31706=>7317, +31717=>7318, +31718=>7319, +31722=>7320, +31756=>7321, +31742=>7322, +31740=>7323, +31759=>7324, +31766=>7325, +31755=>7326, +31775=>7327, +31786=>7328, +31782=>7329, +31800=>7330, +31809=>7331, +31808=>7332, +33278=>7333, +33281=>7334, +33282=>7335, +33284=>7336, +33260=>7337, +34884=>7338, +33313=>7339, +33314=>7340, +33315=>7341, +33325=>7342, +33327=>7343, +33320=>7344, +33323=>7345, +33336=>7346, +33339=>7347, +33331=>7348, +33332=>7349, +33342=>7350, +33348=>7351, +33353=>7352, +33355=>7353, +33359=>7354, +33370=>7355, +33375=>7356, +33384=>7357, +34942=>7358, +34949=>7359, +34952=>7360, +35032=>7361, +35039=>7362, +35166=>7363, +32669=>7364, +32671=>7365, +32679=>7366, +32687=>7367, +32688=>7368, +32690=>7369, +31868=>7370, +25929=>7371, +31889=>7372, +31901=>7373, +31900=>7374, +31902=>7375, +31906=>7376, +31922=>7377, +31932=>7378, +31933=>7379, +31937=>7380, +31943=>7381, +31948=>7382, +31949=>7383, +31944=>7384, +31941=>7385, +31959=>7386, +31976=>7387, +12169=>7388, +33390=>7388, +26280=>7389, +32703=>7390, +32718=>7391, +32725=>7392, +32741=>7393, +32737=>7394, +32742=>7395, +32745=>7396, +32750=>7397, +32755=>7398, +12151=>7399, +31992=>7399, +32119=>7400, +32166=>7401, +32174=>7402, +32327=>7403, +32411=>7404, +40632=>7405, +40628=>7406, +36211=>7407, +36228=>7408, +36244=>7409, +36241=>7410, +36273=>7411, +36199=>7412, +36205=>7413, +35911=>7414, +35913=>7415, +37194=>7416, +37200=>7417, +37198=>7418, +37199=>7419, +37220=>7420, +37218=>7421, +37217=>7422, +37232=>7423, +37225=>7424, +37231=>7425, +37245=>7426, +37246=>7427, +37234=>7428, +37236=>7429, +37241=>7430, +37260=>7431, +37253=>7432, +37264=>7433, +37261=>7434, +37265=>7435, +37282=>7436, +37283=>7437, +37290=>7438, +37293=>7439, +37294=>7440, +37295=>7441, +37301=>7442, +37300=>7443, +37306=>7444, +12183=>7445, +35925=>7445, +40574=>7446, +36280=>7447, +36331=>7448, +36357=>7449, +36441=>7450, +36457=>7451, +36277=>7452, +36287=>7453, +36284=>7454, +36282=>7455, +36292=>7456, +36310=>7457, +36311=>7458, +36314=>7459, +36318=>7460, +36302=>7461, +36303=>7462, +36315=>7463, +36294=>7464, +36332=>7465, +36343=>7466, +36344=>7467, +36323=>7468, +36345=>7469, +36347=>7470, +36324=>7471, +36361=>7472, +36349=>7473, +36372=>7474, +36381=>7475, +36383=>7476, +36396=>7477, +36398=>7478, +36387=>7479, +36399=>7480, +36410=>7481, +36416=>7482, +36409=>7483, +36405=>7484, +36413=>7485, +36401=>7486, +36425=>7487, +36417=>7488, +36418=>7489, +36433=>7490, +36434=>7491, +36426=>7492, +36464=>7493, +36470=>7494, +36476=>7495, +36463=>7496, +36468=>7497, +36485=>7498, +36495=>7499, +36500=>7500, +36496=>7501, +36508=>7502, +36510=>7503, +12184=>7504, +35960=>7504, +35970=>7505, +35978=>7506, +35973=>7507, +35992=>7508, +35988=>7509, +26011=>7510, +35286=>7511, +35294=>7512, +35290=>7513, +35292=>7514, +35301=>7515, +35307=>7516, +35311=>7517, +35390=>7518, +35622=>7519, +38739=>7520, +38633=>7521, +38643=>7522, +38639=>7523, +38662=>7524, +38657=>7525, +38664=>7526, +38671=>7527, +38670=>7528, +38698=>7529, +38701=>7530, +38704=>7531, +38718=>7532, +40832=>7533, +40835=>7534, +40837=>7535, +40838=>7536, +40839=>7537, +40840=>7538, +40841=>7539, +40842=>7540, +40844=>7541, +40702=>7542, +40715=>7543, +40717=>7544, +12203=>7545, +38585=>7545, +38588=>7546, +38589=>7547, +38606=>7548, +38610=>7549, +30655=>7550, +38624=>7551, +37518=>7552, +37550=>7553, +37576=>7554, +37694=>7555, +37738=>7556, +37834=>7557, +37775=>7558, +37950=>7559, +37995=>7560, +40063=>7561, +40066=>7562, +40069=>7563, +40070=>7564, +40071=>7565, +40072=>7566, +31267=>7567, +40075=>7568, +40078=>7569, +40080=>7570, +40081=>7571, +40082=>7572, +40084=>7573, +40085=>7574, +40090=>7575, +40091=>7576, +40094=>7577, +40095=>7578, +40096=>7579, +40097=>7580, +40098=>7581, +40099=>7582, +40101=>7583, +40102=>7584, +40103=>7585, +40104=>7586, +40105=>7587, +40107=>7588, +40109=>7589, +40110=>7590, +40112=>7591, +40113=>7592, +40114=>7593, +40115=>7594, +40116=>7595, +40117=>7596, +40118=>7597, +40119=>7598, +40122=>7599, +40123=>7600, +40124=>7601, +40125=>7602, +40132=>7603, +40133=>7604, +40134=>7605, +40135=>7606, +40138=>7607, +40139=>7608, +40140=>7609, +40141=>7610, +40142=>7611, +40143=>7612, +40144=>7613, +40147=>7614, +40148=>7615, +40149=>7616, +40151=>7617, +40152=>7618, +40153=>7619, +40156=>7620, +40157=>7621, +40159=>7622, +40162=>7623, +38780=>7624, +38789=>7625, +38801=>7626, +38802=>7627, +38804=>7628, +38831=>7629, +38827=>7630, +38819=>7631, +38834=>7632, +38836=>7633, +39601=>7634, +39600=>7635, +39607=>7636, +40536=>7637, +39606=>7638, +39610=>7639, +39612=>7640, +39617=>7641, +39616=>7642, +39621=>7643, +39618=>7644, +39627=>7645, +39628=>7646, +39633=>7647, +39749=>7648, +39747=>7649, +39751=>7650, +39753=>7651, +39752=>7652, +39757=>7653, +39761=>7654, +39144=>7655, +39181=>7656, +39214=>7657, +39253=>7658, +39252=>7659, +12221=>7660, +39647=>7660, +39649=>7661, +39654=>7662, +39663=>7663, +39659=>7664, +39675=>7665, +39661=>7666, +39673=>7667, +39688=>7668, +39695=>7669, +39699=>7670, +39711=>7671, +39715=>7672, +40637=>7673, +40638=>7674, +32315=>7675, +40578=>7676, +40583=>7677, +40584=>7678, +40587=>7679, +40594=>7680, +37846=>7681, +40605=>7682, +40607=>7683, +40667=>7684, +40668=>7685, +40669=>7686, +40672=>7687, +40671=>7688, +40674=>7689, +40681=>7690, +40679=>7691, +40677=>7692, +40682=>7693, +40687=>7694, +40738=>7695, +40748=>7696, +40751=>7697, +40761=>7698, +40759=>7699, +40765=>7700, +40766=>7701, +40772=>7702, +12295=>7703, + + + + + + + +30362=>7717, +34297=>7718, +31001=>7719, +24859=>7720, +39599=>7721, +35158=>7722, +22761=>7723, +32631=>7724, +25850=>7725, +25943=>7726, +38930=>7727, +36774=>7728, +32070=>7729, +24171=>7730, +32129=>7731, +37770=>7732, +35607=>7733, +39165=>7734, +23542=>7735, +22577=>7736, +39825=>7737, +36649=>7738, +12185=>7739, +35997=>7739, +37575=>7740, +29437=>7741, +20633=>7742, +24970=>7743, +32179=>7744, +31558=>7745, +30050=>7746, +25987=>7747, +24163=>7748, +38281=>7749, +37002=>7750, +32232=>7751, +36022=>7752, +35722=>7753, +36783=>7754, +36782=>7755, +27161=>7756, +40009=>7757, +30303=>7758, +28693=>7759, +28657=>7760, +36051=>7761, +25839=>7762, +39173=>7763, +25765=>7764, +37474=>7765, +37457=>7766, +39361=>7767, +35036=>7768, +36001=>7769, +21443=>7770, +34870=>7771, +27544=>7772, +24922=>7773, +24920=>7774, +29158=>7775, +33980=>7776, +33369=>7777, +20489=>7778, +28356=>7779, +21408=>7780, +20596=>7781, +28204=>7782, +23652=>7783, +35435=>7784, +25881=>7785, +25723=>7786, +34796=>7787, +39262=>7788, +35730=>7789, +32399=>7790, +37855=>7791, +29987=>7792, +38369=>7793, +39019=>7794, +22580=>7795, +22039=>7796, +12199=>7797, +38263=>7797, +20767=>7798, +33144=>7799, +24288=>7800, +26274=>7801, +37396=>7802, +12190=>7803, +36554=>7803, +24505=>7804, +22645=>7805, +38515=>7806, +35183=>7807, +31281=>7808, +25074=>7809, +35488=>7810, +39425=>7811, +36978=>7812, +39347=>7813, +12242=>7814, +40786=>7814, +29118=>7815, +34909=>7816, +34802=>7817, +23541=>7818, +30087=>7819, +36490=>7820, +31820=>7821, +32162=>7822, +37276=>7823, +37604=>7824, +38619=>7825, +30990=>7826, +20786=>7827, +35320=>7828, +34389=>7829, +20659=>7830, +30241=>7831, +38358=>7832, +21109=>7833, +37656=>7834, +32020=>7835, +32189=>7836, +36781=>7837, +35422=>7838, +36060=>7839, +32880=>7840, +24478=>7841, +21474=>7842, +36517=>7843, +31428=>7844, +37679=>7845, +36948=>7846, +24118=>7847, +36024=>7848, +25812=>7849, +21934=>7850, +37170=>7851, +25763=>7852, +33213=>7853, +24986=>7854, +35477=>7855, +24392=>7856, +30070=>7857, +25803=>7858, +40680=>7859, +34153=>7860, +27284=>7861, +25623=>7862, +23798=>7863, +31153=>7864, +23566=>7865, +29128=>7866, +37159=>7867, +25973=>7868, +28364=>7869, +36958=>7870, +32224=>7871, +39003=>7872, +40670=>7873, +22666=>7874, +38651=>7875, +28593=>7876, +37347=>7877, +35519=>7878, +35548=>7879, +37336=>7880, +38914=>7881, +37664=>7882, +35330=>7883, +26481=>7884, +21205=>7885, +26847=>7886, +20941=>7887, +12222=>7888, +39717=>7888, +29346=>7889, +29544=>7890, +35712=>7891, +36077=>7892, +37709=>7893, +37723=>7894, +26039=>7895, +32222=>7896, +38538=>7897, +23565=>7898, +22136=>7899, +38931=>7900, +37389=>7901, +22890=>7902, +22702=>7903, +40285=>7904, +38989=>7905, +35355=>7906, +24801=>7907, +39187=>7908, +20818=>7909, +29246=>7910, +39180=>7911, +36019=>7912, +30332=>7913, +32624=>7914, +38309=>7915, +31020=>7916, +37353=>7917, +29033=>7918, +31684=>7919, +36009=>7920, +39151=>7921, +35370=>7922, +32033=>7923, +12214=>7924, +39131=>7924, +35513=>7925, +24290=>7926, +36027=>7927, +32027=>7928, +22707=>7929, +22894=>7930, +24996=>7931, +31966=>7932, +35920=>7933, +26963=>7934, +37586=>7935, +12213=>7936, +39080=>7936, +30219=>7937, +39342=>7938, +32299=>7939, +35575=>7940, +40179=>7941, +33178=>7942, +36667=>7943, +25771=>7944, +36628=>7945, +36070=>7946, +24489=>7947, +36000=>7948, +35331=>7949, +23142=>7950, +32283=>7951, +35442=>7952, +37411=>7953, +33995=>7954, +24185=>7955, +36245=>7956, +36123=>7957, +23713=>7958, +21083=>7959, +37628=>7960, +32177=>7961, +23831=>7962, +37804=>7963, +25841=>7964, +40255=>7965, +38307=>7966, +37499=>7967, +20491=>7968, +32102=>7969, +40852=>7970, +38799=>7971, +36002=>7972, +37390=>7973, +28317=>7974, +27083=>7975, +36092=>7976, +34865=>7977, +39015=>7978, +21102=>7979, +38364=>7980, +35264=>7981, +39208=>7982, +24931=>7983, +36011=>7984, +24291=>7985, +35215=>7986, +27512=>7987, +12244=>7988, +40860=>7988, +38312=>7989, +36556=>7990, +35437=>7991, +27331=>7992, +36020=>7993, +21130=>7994, +36645=>7995, +37707=>7996, +22283=>7997, +36942=>7998, +39405=>7999, +38867=>8000, +28450=>8001, +34399=>8002, +38305=>8003, +40372=>8004, +36032=>8005, +36703=>8006, +40251=>8007, +32005=>8008, +22778=>8009, +35703=>8010, +28396=>8011, +22057=>8012, +33775=>8013, +30059=>8014, +21123=>8015, +35441=>8016, +25079=>8017, +22750=>8018, +27489=>8019, +29872=>8020, +36996=>8021, +32233=>8022, +35594=>8023, +25582=>8024, +36637=>8025, +36036=>8026, +31330=>8027, +26371=>8028, +29172=>8029, +21295=>8030, +35569=>8031, +35496=>8032, +32362=>8033, +33911=>8034, +28222=>8035, +29554=>8036, +36008=>8037, +31117=>8038, +25802=>8039, +27231=>8040, +31309=>8041, +39249=>8042, +35663=>8043, +40388=>8044, +32318=>8045, +32221=>8046, +26997=>8047, +36655=>8048, +32026=>8049, +25824=>8050, +24190=>8051, +34186=>8052, +21137=>8053, +28639=>8054, +35336=>8055, +35352=>8056, +38555=>8057, +32380=>8058, +32000=>8059, +22846=>8060, +33698=>8061, +38960=>8062, +36040=>8063, +37440=>8064, +20729=>8065, +39381=>8066, +27570=>8067, +30435=>8068, +22533=>8069, +31627=>8070, +38291=>8071, +33393=>8072, +32216=>8073, +32365=>8074, +27298=>8075, +40572=>8076, +25536=>8077, +25791=>8078, +31777=>8079, +20745=>8080, +34214=>8081, +27323=>8082, +37970=>8083, +36368=>8084, +36068=>8085, +12178=>8086, +35211=>8086, +37749=>8087, +33382=>8088, +21133=>8089, +39198=>8090, +28472=>8091, +28666=>8092, +28567=>8093, +23559=>8094, +28479=>8095, +34083=>8096, +27123=>8097, +22892=>8098, +35611=>8099, +37292=>8100, +33184=>8101, +28550=>8102, +39509=>8103, +23308=>8104, +25898=>8105, +37496=>8106, +30703=>8107, +20709=>8108, +39171=>8109, +32371=>8110, +32094=>8111, +36686=>8112, +36611=>8113, +38542=>8114, +31680=>8115, +28500=>8116, +32080=>8117, +35489=>8118, +32202=>8119, +37670=>8120, +20677=>8121, +35641=>8122, +36914=>8123, +29180=>8124, +30433=>8125, +21185=>8126, +33686=>8127, +39912=>8128, +39514=>8129, +32147=>8130, +38968=>8131, +37857=>8132, +24465=>8133, +30169=>8134, +31478=>8135, +31998=>8136, +33290=>8137, +39378=>8138, +33289=>8139, +25818=>8140, +37624=>8141, +25084=>8142, +21127=>8143, +40273=>8144, +32121=>8145, +35258=>8146, +35363=>8147, +32118=>8148, +37406=>8149, +36557=>8150, +39423=>8151, +38283=>8152, +20977=>8153, +38982=>8154, +27579=>8155, +35506=>8156, +22718=>8157, +25031=>8158, +25715=>8159, +24235=>8160, +35122=>8161, +35463=>8162, +22602=>8163, +20744=>8164, +23532=>8165, +31014=>8166, +26336=>8167, +34407=>8168, +24011=>8169, +31418=>8170, +39243=>8171, +28528=>8172, +25844=>8173, +38346=>8174, +34847=>8175, +33240=>8176, +33802=>8177, +20358=>8178, +36084=>8179, +34253=>8180, +27396=>8181, +25876=>8182, +31811=>8183, +38348=>8184, +34349=>8185, +28734=>8186, +35733=>8187, +25900=>8188, +35261=>8189, +25078=>8190, +32412=>8191, +29211=>8192, +28651=>8193, +25736=>8194, +21214=>8195, +28551=>8196, +27138=>8197, +37939=>8198, +22744=>8199, +39006=>8200, +31852=>8201, +38626=>8202, +28757=>8203, +35023=>8204, +63975=>8204, +39881=>8205, +31150=>8206, +40599=>8207, +21426=>8208, +21237=>8209, +31019=>8210, +27511=>8211, +28701=>8212, +38584=>8213, +20486=>8214, +32879=>8215, +34030=>8216, +36899=>8217, +37934=>8218, +24976=>8219, +28451=>8220, +31806=>8221, +25986=>8222, +33225=>8223, +37832=>8224, +25088=>8225, +29001=>8226, +32244=>8227, +31975=>8228, +20841=>8229, +36635=>8230, +35538=>8231, +30274=>8232, +36988=>8233, +37904=>8234, +29557=>8235, +33256=>8236, +37168=>8237, +40023=>8238, +36035=>8239, +40801=>8240, +37428=>8241, +38728=>8242, +23994=>8243, +38936=>8244, +39230=>8245, +21129=>8246, +12243=>8247, +40845=>8247, +32894=>8248, +22184=>8249, +31840=>8250, +22751=>8251, +25871=>8252, +38580=>8253, +27155=>8254, +23105=>8255, +25695=>8256, +31757=>8257, +34310=>8258, +30439=>8259, +39025=>8260, +24300=>8261, +29200=>8262, +25796=>8263, +28407=>8264, +34396=>8265, +39791=>8266, +36034=>8267, +37682=>8268, +38520=>8269, +39522=>8270, +37569=>8271, +23650=>8272, +32311=>8273, +24942=>8274, +28670=>8275, +32209=>8276, +24018=>8277, +25891=>8278, +23423=>8279, +28772=>8280, +20098=>8281, +25476=>8282, +36650=>8283, +20523=>8284, +20374=>8285, +28138=>8286, +32184=>8287, +35542=>8288, +34367=>8289, +32645=>8290, +37007=>8291, +38012=>8292, +31854=>8293, +39486=>8294, +39409=>8295, +32097=>8296, +23229=>8297, +29802=>8298, +30908=>8299, +34718=>8300, +12218=>8301, +39340=>8301, +39393=>8302, +21966=>8303, +36023=>8304, +12230=>8305, +40613=>8305, +36067=>8306, +36993=>8307, +30622=>8308, +39237=>8309, +34875=>8310, +28415=>8311, +35646=>8312, +37672=>8313, +37466=>8314, +36031=>8315, +37762=>8316, +12200=>8317, +38272=>8317, +24758=>8318, +20497=>8319, +37683=>8320, +22818=>8321, +35598=>8322, +24396=>8323, +35219=>8324, +32191=>8325, +32236=>8326, +24287=>8327, +28357=>8328, +25003=>8329, +38313=>8330, +40180=>8331, +37528=>8332, +35628=>8333, +35584=>8334, +30045=>8335, +37385=>8336, +32013=>8337, +38627=>8338, +25747=>8339, +33126=>8340, +24817=>8341, +39719=>8342, +39186=>8343, +25836=>8344, +33193=>8345, +25862=>8346, +37312=>8347, +12227=>8348, +40165=>8348, +32886=>8349, +22169=>8350, +38007=>8351, +37811=>8352, +27320=>8353, +29552=>8354, +23527=>8355, +25840=>8356, +28632=>8357, +37397=>8358, +32016=>8359, +33215=>8360, +28611=>8361, +36786=>8362, +30247=>8363, +35582=>8364, +27472=>8365, +40407=>8366, +27590=>8367, +22036=>8368, +28442=>8369, +30436=>8370, +40848=>8371, +36064=>8372, +22132=>8373, +40300=>8374, +39449=>8375, +39108=>8376, +38971=>8377, +36007=>8378, +34315=>8379, +24977=>8380, +35413=>8381, +28497=>8382, +38935=>8383, +25778=>8384, +37610=>8385, +20693=>8386, +27192=>8387, +35676=>8388, +33229=>8389, +12241=>8390, +40778=>8390, +39438=>8391, +35912=>8392, +21843=>8393, +27683=>8394, +35350=>8395, +29309=>8396, +37370=>8397, +37467=>8398, +36983=>8399, +31805=>8400, +35609=>8401, +37666=>8402, +37463=>8403, +28154=>8404, +35700=>8405, +22649=>8406, +27085=>8407, +21958=>8408, +22715=>8409, +34196=>8410, +25654=>8411, +37740=>8412, +27211=>8413, +21932=>8414, +20689=>8415, +32761=>8416, +31429=>8417, +31434=>8418, +27453=>8419, +35242=>8420, +23522=>8421, +36629=>8422, +27691=>8423, +20670=>8424, +38915=>8425, +35531=>8426, +24950=>8427, +29898=>8428, +31406=>8429, +36264=>8430, +21312=>8431, +36544=>8432, +39493=>8433, +40818=>8434, +39028=>8435, +27402=>8436, +21240=>8437, +40306=>8438, +30906=>8439, +35731=>8440, +39250=>8441, +25854=>8442, +32350=>8443, +29105=>8444, +38860=>8445, +35469=>8446, +32009=>8447, +27054=>8448, +32104=>8449, +36575=>8450, +37613=>8451, +38287=>8452, +28516=>8453, +28753=>8454, +34217=>8455, +39955=>8456, +36093=>8457, +20632=>8458, +21930=>8459, +39479=>8460, +25475=>8461, +28544=>8462, +27578=>8463, +32023=>8464, +31721=>8465, +26348=>8466, +38275=>8467, +38493=>8468, +36109=>8469, +32341=>8470, +20663=>8471, +36062=>8472, +29138=>8473, +32057=>8474, +36050=>8475, +25448=>8476, +25885=>8477, +25086=>8478, +35373=>8479, +32051=>8480, +23529=>8481, +23352=>8482, +33102=>8483, +28402=>8484, +32882=>8485, +32361=>8486, +21213=>8487, +32854=>8488, +24107=>8489, +29509=>8490, +28629=>8491, +35433=>8492, +26178=>8493, +34645=>8494, +23526=>8495, +35672=>8496, +39387=>8497, +21218=>8498, +36969=>8499, +37323=>8500, +39166=>8501, +35222=>8502, +35430=>8503, +22781=>8504, +29560=>8505, +27166=>8506, +36664=>8507, +26360=>8508, +36118=>8509, +23660=>8510, +34899=>8511, +27193=>8512, +31466=>8513, +25976=>8514, +24101=>8515, +38617=>8516, +35504=>8517, +38918=>8518, +35500=>8519, +30889=>8520, +29197=>8521, +32114=>8522, +39164=>8523, +39686=>8524, +32883=>8525, +24939=>8526, +38924=>8527, +35359=>8528, +35494=>8529, +25851=>8530, +34311=>8531, +35380=>8532, +32901=>8533, +38614=>8534, +38568=>8535, +32143=>8536, +27506=>8537, +23403=>8538, +25613=>8539, +32302=>8540, +29795=>8541, +37782=>8542, +29562=>8543, +25787=>8544, +33274=>8545, +24907=>8546, +25892=>8547, +36010=>8548, +30321=>8549, +28760=>8550, +22727=>8551, +35674=>8552, +35527=>8553, +22022=>8554, +28271=>8555, +29145=>8556, +28644=>8557, +32295=>8558, +35342=>8559, +39472=>8560, +35588=>8561, +37563=>8562, +38988=>8563, +39636=>8564, +26781=>8565, +36028=>8566, +37941=>8567, +24307=>8568, +32893=>8569, +28916=>8570, +37509=>8571, +32113=>8572, +38957=>8573, +22294=>8574, +22615=>8575, +22296=>8576, +38973=>8577, +40213=>8578, +39345=>8579, +39389=>8580, +27234=>8581, +31402=>8582, +35178=>8583, +24398=>8584, +28771=>8585, +38929=>8586, +33836=>8587, +32178=>8588, +12209=>8589, +38859=>8589, +36949=>8590, +22285=>8591, +29234=>8592, +28656=>8593, +32173=>8594, +33894=>8595, +20553=>8596, +20702=>8597, +32239=>8598, +35586=>8599, +34907=>8600, +32862=>8601, +32011=>8602, +31337=>8603, +21839=>8604, +25790=>8605, +34680=>8606, +28198=>8607, +31401=>8608, +21978=>8609, +37794=>8610, +28879=>8611, +35491=>8612, +28961=>8613, +34154=>8614, +22626=>8615, +38695=>8616, +21209=>8617, +35492=>8618, +37675=>8619, +29351=>8620, +35186=>8621, +32722=>8622, +37521=>8623, +25138=>8624, +32048=>8625, +34662=>8626, +36676=>8627, +23805=>8628, +20448=>8629, +29433=>8630, +22151=>8631, +37697=>8632, +39854=>8633, +32406=>8634, +36066=>8635, +37532=>8636, +38289=>8637, +39023=>8638, +38570=>8639, +29694=>8640, +29563=>8641, +32291=>8642, +39201=>8643, +25010=>8644, +32171=>8645, +38002=>8646, +37129=>8647, +35443=>8648, +38911=>8649, +38917=>8650, +34157=>8651, +22210=>8652, +37559=>8653, +26313=>8654, +22063=>8655, +21332=>8656, +25406=>8657, +33029=>8658, +35559=>8659, +23531=>8660, +28681=>8661, +35613=>8662, +37573=>8663, +37313=>8664, +33288=>8665, +37561=>8666, +32137=>8667, +38920=>8668, +35377=>8669, +32210=>8670, +32396=>8671, +36562=>8672, +25080=>8673, +36984=>8674, +30316=>8675, +32098=>8676, +23416=>8677, +21211=>8678, +35426=>8679, +23563=>8680, +39348=>8681, +35347=>8682, +35338=>8683, +36956=>8684, +22739=>8685, +40201=>8686, +40232=>8687, +21854=>8688, +20126=>8689, +35357=>8690, +38329=>8691, +40573=>8692, +22196=>8693, +38996=>8694, +38331=>8695, +33399=>8696, +21421=>8697, +30831=>8698, +35578=>8699, +39511=>8700, +40230=>8701, +26954=>8702, +25562=>8703, +30221=>8704, +38525=>8705, +30306=>8706, +39178=>8707, +27171=>8708, +22575=>8709, +35617=>8710, +34277=>8711, +29242=>8712, +12212=>8713, +38913=>8713, +26989=>8714, +33865=>8715, +37291=>8716, +37541=>8717, +38948=>8718, +36986=>8719, +20736=>8720, +34811=>8721, +34269=>8722, +20740=>8723, +25014=>8724, +32681=>8725, +35427=>8726, +35696=>8727, +35516=>8728, +35695=>8729, +32377=>8730, +34093=>8731, +38512=>8732, +37504=>8733, +39154=>8734, +38577=>8735, +27387=>8736, +23344=>8737, +40441=>8738, +25033=>8739, +32403=>8740, +29801=>8741, +34722=>8742, +29151=>8743, +29074=>8744, +34821=>8745, +36111=>8746, +31310=>8747, +21938=>8748, +25793=>8749, +20653=>8750, +30320=>8751, +36404=>8752, +20778=>8753, +24962=>8754, +37109=>8755, +37438=>8756, +29494=>8757, +35480=>8758, +36671=>8759, +39192=>8760, +12226=>8761, +39770=>8761, +28417=>8762, +33287=>8763, +23996=>8764, +35486=>8765, +39729=>8766, +29508=>8767, +35709=>8768, +38928=>8769, +39341=>8770, +40219=>8771, +28149=>8772, +36677=>8773, +22290=>8774, +21729=>8775, +22291=>8776, +32227=>8777, +36960=>8778, +39000=>8779, +32004=>8780, +36493=>8781, +38000=>8782, +38322=>8783, +38642=>8784, +37142=>8785, +38549=>8786, +36939=>8787, +34292=>8788, +37270=>8789, +26248=>8790, +38620=>8791, +36617=>8792, +25890=>8793, +26283=>8794, +36106=>8795, +36124=>8796, +33247=>8797, +38015=>8798, +26839=>8799, +31432=>8800, +36012=>8801, +25799=>8802, +21063=>8803, +28580=>8804, +36042=>8805, +36104=>8806, +36555=>8807, +37720=>8808, +38296=>8809, +35408=>8810, +40779=>8811, +20661=>8812, +27656=>8813, +30430=>8814, +26028=>8815, +36670=>8816, +23940=>8817, +26855=>8818, +25136=>8819, +32187=>8820, +24373=>8821, +28466=>8822, +24115=>8823, +36076=>8824, +33081=>8825, +36249=>8826, +34756=>8827, +36685=>8828, +37754=>8829, +36889=>8830, +35998=>8831, +37341=>8832, +20597=>8833, +35386=>8834, +37806=>8835, +38499=>8836, +24128=>8837, +30309=>8838, +37165=>8839, +35657=>8840, +32340=>8841, +32887=>8842, +22519=>8843, +34937=>8844, +32025=>8845, +25711=>8846, +25842=>8847, +24159=>8848, +36074=>8849, +28399=>8850, +37912=>8851, +32066=>8852, +31278=>8853, +33131=>8854, +34886=>8855, +35589=>8856, +36600=>8857, +30394=>8858, +26205=>8859, +39519=>8860, +35576=>8861, +35461=>8862, +29165=>8863, +30682=>8864, +22225=>8865, +36015=>8866, +37956=>8867, +31689=>8868, +39376=>8869, +23560=>8870, +30938=>8871, +36681=>8872, +36090=>8873, +27137=>8874, +33674=>8875, +35037=>8876, +22941=>8877, +22767=>8878, +29376=>8879, +37648=>8880, +36101=>8881, +22684=>8882, +32180=>8883, +35524=>8884, +28310=>8885, +28609=>8886, +36039=>8887, +28460=>8888, +32156=>8889, +32317=>8890, +32305=>8891, +37138=>8892, +35419=>8893, +32068=>8894, +38013=>8895, +21959=>8896, +21401=>8897, +21428=>8898, +38760=>8899, +36107=>8900, +21293=>8901, +21297=>8902, +36094=>8903, +21060=>8904, +21132=>8905, +21108=>8906, +20660=>8907, +20480=>8908, +20630=>8909, +20757=>8910, +20738=>8911, +20756=>8912, +20796=>8913, +20791=>8914, +20712=>8915, +20674=>8916, +20795=>8917, +20752=>8918, +20794=>8919, +20681=>8920, +31988=>8921, +40652=>8922, +22213=>8923, +40172=>8924, +35131=>8925, +33248=>8926, +35329=>8927, +35344=>8928, +35340=>8929, +35349=>8930, +35635=>8931, +35406=>8932, +35365=>8933, +35393=>8934, +35382=>8935, +35398=>8936, +35412=>8937, +35416=>8938, +35410=>8939, +35462=>8940, +35460=>8941, +35455=>8942, +35440=>8943, +35452=>8944, +35445=>8945, +35436=>8946, +35438=>8947, +35533=>8948, +35554=>8949, +35425=>8950, +35482=>8951, +35493=>8952, +35473=>8953, +35474=>8954, +35535=>8955, +35537=>8956, +35529=>8957, +35547=>8958, +35543=>8959, +35522=>8960, +35510=>8961, +35574=>8962, +35563=>8963, +35604=>8964, +35585=>8965, +35556=>8966, +35565=>8967, +35580=>8968, +35571=>8969, +35558=>8970, +35566=>8971, +35550=>8972, +35624=>8973, +35740=>8974, +35606=>8975, +35610=>8976, +35600=>8977, +35627=>8978, +35629=>8979, +35670=>8980, +35673=>8981, +35662=>8982, +35742=>8983, +35691=>8984, +35734=>8985, +38488=>8986, +37178=>8987, +37140=>8988, +37172=>8989, +37087=>8990, +37174=>8991, +37126=>8992, +37192=>8993, +33467=>8994, +21233=>8995, +24048=>8996, +22538=>8997, +22745=>8998, +22754=>8999, +22752=>9000, +22746=>9001, +22497=>9002, +22607=>9003, +22550=>9004, +22610=>9005, +22557=>9006, +22628=>9007, +34188=>9008, +34131=>9009, +34294=>9010, +33703=>9011, +33799=>9012, +34031=>9013, +33511=>9014, +34338=>9015, +34086=>9016, +22603=>9017, +29026=>9018, +34136=>9019, +34045=>9020, +34126=>9021, +34184=>9022, +34234=>9023, +29334=>9024, +28366=>9025, +34113=>9026, +34254=>9027, +34130=>9028, +33984=>9029, +33874=>9030, +33892=>9031, +33940=>9032, +33845=>9033, +34207=>9034, +34133=>9035, +40367=>9036, +33939=>9037, +32264=>9038, +34118=>9039, +34146=>9040, +34078=>9041, +39488=>9042, +34362=>9043, +37795=>9044, +34167=>9045, +34334=>9046, +34298=>9047, +34308=>9048, +34282=>9049, +34330=>9050, +22889=>9051, +23607=>9052, +25451=>9053, +25718=>9054, +25759=>9055, +25681=>9056, +25692=>9057, +25779=>9058, +25860=>9059, +25878=>9060, +25847=>9061, +25852=>9062, +25883=>9063, +22064=>9064, +22072=>9065, +22216=>9066, +22182=>9067, +21764=>9068, +21692=>9069, +22144=>9070, +22109=>9071, +22112=>9072, +22069=>9073, +22006=>9074, +22118=>9075, +22130=>9076, +22156=>9077, +22117=>9078, +22044=>9079, +22062=>9080, +21993=>9081, +22038=>9082, +22208=>9083, +22029=>9084, +22195=>9085, +22209=>9086, +22127=>9087, +36705=>9088, +22198=>9089, +22165=>9090, +22279=>9091, +24131=>9092, +24172=>9093, +24152=>9094, +24151=>9095, +23943=>9096, +23796=>9097, +23888=>9098, +23852=>9099, +23975=>9100, +23968=>9101, +23959=>9102, +23821=>9103, +23992=>9104, +23937=>9105, +24020=>9106, +24480=>9107, +29559=>9108, +29505=>9109, +29546=>9110, +29499=>9111, +29547=>9112, +29568=>9113, +29564=>9114, +39136=>9115, +39219=>9116, +39145=>9117, +39228=>9118, +39146=>9119, +39147=>9120, +39149=>9121, +39156=>9122, +39177=>9123, +39185=>9124, +39195=>9125, +39223=>9126, +39231=>9127, +39235=>9128, +39240=>9129, +39241=>9130, +39242=>9131, +39244=>9132, +39266=>9133, +24289=>9134, +36065=>9135, +25082=>9136, +25006=>9137, +24938=>9138, +24894=>9139, +24757=>9140, +24884=>9141, +25036=>9142, +24927=>9143, +25064=>9144, +24827=>9145, +24887=>9146, +24818=>9147, +24947=>9148, +24860=>9149, +24978=>9150, +38274=>9151, +38278=>9152, +38344=>9153, +38286=>9154, +38292=>9155, +38284=>9156, +38373=>9157, +38317=>9158, +38315=>9159, +39726=>9160, +38316=>9161, +38334=>9162, +38326=>9163, +39721=>9164, +38335=>9165, +38333=>9166, +38332=>9167, +38339=>9168, +38347=>9169, +38356=>9170, +38352=>9171, +38357=>9172, +38366=>9173, +28739=>9174, +28505=>9175, +28711=>9176, +28696=>9177, +28668=>9178, +28039=>9179, +28025=>9180, +28254=>9181, +28590=>9182, +28687=>9183, +28408=>9184, +28527=>9185, +28150=>9186, +28543=>9187, +28678=>9188, +28576=>9189, +28683=>9190, +28775=>9191, +28740=>9192, +28677=>9193, +28535=>9194, +28704=>9195, +28703=>9196, +28722=>9197, +28712=>9198, +28765=>9199, +39467=>9200, +36999=>9201, +36885=>9202, +37008=>9203, +23656=>9204, +24371=>9205, +23285=>9206, +23255=>9207, +23296=>9208, +23149=>9209, +23304=>9210, +23372=>9211, +23207=>9212, +23291=>9213, +23307=>9214, +23329=>9215, +23338=>9216, +23321=>9217, +39380=>9218, +39391=>9219, +39385=>9220, +39478=>9221, +39515=>9222, +39377=>9223, +39384=>9224, +39501=>9225, +39498=>9226, +39394=>9227, +39530=>9228, +39439=>9229, +39437=>9230, +39429=>9231, +39490=>9232, +39469=>9233, +39446=>9234, +39489=>9235, +39470=>9236, +39480=>9237, +39491=>9238, +39492=>9239, +39503=>9240, +39525=>9241, +39524=>9242, +31993=>9243, +32006=>9244, +32002=>9245, +32007=>9246, +32008=>9247, +32394=>9248, +32028=>9249, +32021=>9250, +32019=>9251, +32058=>9252, +32050=>9253, +32049=>9254, +32272=>9255, +32060=>9256, +32064=>9257, +32063=>9258, +32093=>9259, +32078=>9260, +32115=>9261, +32134=>9262, +32131=>9263, +32136=>9264, +32190=>9265, +32186=>9266, +32203=>9267, +32212=>9268, +32196=>9269, +32158=>9270, +32172=>9271, +32185=>9272, +32163=>9273, +32176=>9274, +32199=>9275, +32217=>9276, +32215=>9277, +32249=>9278, +32242=>9279, +32354=>9280, +32230=>9281, +32246=>9282, +32241=>9283, +32267=>9284, +32225=>9285, +32265=>9286, +32285=>9287, +32287=>9288, +32286=>9289, +32301=>9290, +32266=>9291, +32273=>9292, +32381=>9293, +32313=>9294, +32309=>9295, +32306=>9296, +32326=>9297, +32325=>9298, +32392=>9299, +32346=>9300, +32338=>9301, +32366=>9302, +32382=>9303, +32368=>9304, +32367=>9305, +32408=>9306, +29859=>9307, +29771=>9308, +29903=>9309, +38922=>9310, +29885=>9311, +29759=>9312, +29833=>9313, +29862=>9314, +29908=>9315, +29914=>9316, +38873=>9317, +38878=>9318, +38876=>9319, +27050=>9320, +27370=>9321, +26776=>9322, +26838=>9323, +27141=>9324, +26783=>9325, +27355=>9326, +27379=>9327, +27368=>9328, +27359=>9329, +27273=>9330, +26895=>9331, +27208=>9332, +26984=>9333, +27071=>9334, +27194=>9335, +27292=>9336, +27410=>9337, +27422=>9338, +27357=>9339, +27111=>9340, +27407=>9341, +27414=>9342, +27372=>9343, +27354=>9344, +27384=>9345, +27315=>9346, +27367=>9347, +27299=>9348, +27347=>9349, +27358=>9350, +27556=>9351, +27550=>9352, +27566=>9353, +27563=>9354, +27567=>9355, +36564=>9356, +36571=>9357, +36594=>9358, +36603=>9359, +36708=>9360, +36601=>9361, +36604=>9362, +36587=>9363, +36580=>9364, +36706=>9365, +36602=>9366, +36606=>9367, +36618=>9368, +36615=>9369, +36613=>9370, +36626=>9371, +36646=>9372, +36638=>9373, +36639=>9374, +36636=>9375, +36659=>9376, +36678=>9377, +36692=>9378, +25108=>9379, +25127=>9380, +29964=>9381, +26311=>9382, +26308=>9383, +26249=>9384, +26326=>9385, +36033=>9386, +36016=>9387, +36026=>9388, +36029=>9389, +36100=>9390, +36018=>9391, +36037=>9392, +36112=>9393, +36049=>9394, +36058=>9395, +36053=>9396, +36075=>9397, +36071=>9398, +36091=>9399, +35224=>9400, +35244=>9401, +35233=>9402, +35263=>9403, +35238=>9404, +35247=>9405, +35250=>9406, +35255=>9407, +27647=>9408, +27660=>9409, +27692=>9410, +29272=>9411, +26407=>9412, +33110=>9413, +33242=>9414, +33051=>9415, +33214=>9416, +33121=>9417, +33231=>9418, +27487=>9419, +39086=>9420, +39087=>9421, +39094=>9422, +39100=>9423, +39110=>9424, +39112=>9425, +36674=>9426, +40783=>9427, +26005=>9428, +29036=>9429, +29010=>9430, +29079=>9431, +29121=>9432, +29148=>9433, +29182=>9434, +31152=>9435, +31118=>9436, +31146=>9437, +25055=>9438, +24932=>9439, +25059=>9440, +25095=>9441, +28585=>9442, +30959=>9443, +30893=>9444, +30824=>9445, +30904=>9446, +31018=>9447, +31025=>9448, +30820=>9449, +30973=>9450, +30951=>9451, +30947=>9452, +40853=>9453, +30616=>9454, +30558=>9455, +30652=>9456, +32646=>9457, +32648=>9458, +37330=>9459, +37331=>9460, +37332=>9461, +37337=>9462, +37335=>9463, +37333=>9464, +37367=>9465, +37351=>9466, +37348=>9467, +37702=>9468, +37365=>9469, +37369=>9470, +37384=>9471, +37414=>9472, +37445=>9473, +37393=>9474, +37392=>9475, +37377=>9476, +37415=>9477, +37380=>9478, +37413=>9479, +37376=>9480, +37434=>9481, +37478=>9482, +37431=>9483, +37427=>9484, +37461=>9485, +37437=>9486, +37432=>9487, +37470=>9488, +37484=>9489, +37485=>9490, +37439=>9491, +37984=>9492, +37424=>9493, +37449=>9494, +37448=>9495, +37453=>9496, +37422=>9497, +37433=>9498, +37944=>9499, +37548=>9500, +37536=>9501, +37498=>9502, +37546=>9503, +37614=>9504, +37583=>9505, +37891=>9506, +37603=>9507, +37946=>9508, +37553=>9509, +37542=>9510, +37799=>9511, +37526=>9512, +37580=>9513, +37545=>9514, +37877=>9515, +37523=>9516, +37503=>9517, +37801=>9518, +37530=>9519, +37658=>9520, +37547=>9521, +37507=>9522, +37899=>9523, +37544=>9524, +37539=>9525, +37906=>9526, +37688=>9527, +37617=>9528, +37847=>9529, +37605=>9530, +37616=>9531, +37615=>9532, +37608=>9533, +37564=>9534, +37597=>9535, +37622=>9536, +37926=>9537, +37927=>9538, +37571=>9539, +37599=>9540, +37606=>9541, +37650=>9542, +37638=>9543, +37737=>9544, +37659=>9545, +37696=>9546, +37633=>9547, +37653=>9548, +37678=>9549, +37699=>9550, +37639=>9551, +37640=>9552, +37663=>9553, +37657=>9554, +37733=>9555, +37703=>9556, +37750=>9557, +37716=>9558, +37732=>9559, +37802=>9560, +37744=>9561, +37764=>9562, +37860=>9563, +37848=>9564, +37928=>9565, +37767=>9566, +37836=>9567, +37784=>9568, +37816=>9569, +37823=>9570, +37798=>9571, +37808=>9572, +37813=>9573, +37964=>9574, +37858=>9575, +37852=>9576, +37853=>9577, +37837=>9578, +37854=>9579, +37827=>9580, +37831=>9581, +37841=>9582, +37908=>9583, +37917=>9584, +37879=>9585, +37989=>9586, +37907=>9587, +37997=>9588, +37920=>9589, +38009=>9590, +37881=>9591, +37913=>9592, +37962=>9593, +37938=>9594, +37951=>9595, +37972=>9596, +37987=>9597, +37758=>9598, +31329=>9599, +40169=>9600, +40182=>9601, +40199=>9602, +40198=>9603, +40227=>9604, +40327=>9605, +40469=>9606, +40221=>9607, +40223=>9608, +40421=>9609, +40239=>9610, +40409=>9611, +40240=>9612, +40258=>9613, +40478=>9614, +40275=>9615, +40477=>9616, +40288=>9617, +40274=>9618, +40435=>9619, +40284=>9620, +40289=>9621, +40339=>9622, +40298=>9623, +40303=>9624, +40329=>9625, +40344=>9626, +40346=>9627, +40384=>9628, +40357=>9629, +40361=>9630, +40386=>9631, +40380=>9632, +40474=>9633, +40403=>9634, +40410=>9635, +40431=>9636, +40422=>9637, +40434=>9638, +40440=>9639, +40460=>9640, +40442=>9641, +40475=>9642, +30308=>9643, +30296=>9644, +30311=>9645, +30210=>9646, +30278=>9647, +30279=>9648, +30281=>9649, +30238=>9650, +30267=>9651, +30317=>9652, +30318=>9653, +30313=>9654, +30322=>9655, +31431=>9656, +31414=>9657, +35168=>9658, +35123=>9659, +35165=>9660, +35143=>9661, +35128=>9662, +35172=>9663, +30392=>9664, +32814=>9665, +32812=>9666, +32889=>9667, +32885=>9668, +38919=>9669, +38926=>9670, +38927=>9671, +38945=>9672, +38940=>9673, +28481=>9674, +38950=>9675, +38967=>9676, +38990=>9677, +38995=>9678, +39027=>9679, +39010=>9680, +39001=>9681, +39013=>9682, +39020=>9683, +39024=>9684, +34787=>9685, +34822=>9686, +34566=>9687, +34851=>9688, +34806=>9689, +34554=>9690, +34799=>9691, +34692=>9692, +34832=>9693, +34760=>9694, +34833=>9695, +34747=>9696, +34766=>9697, +32588=>9698, +31716=>9699, +31591=>9700, +31849=>9701, +31731=>9702, +31744=>9703, +31691=>9704, +31836=>9705, +31774=>9706, +31787=>9707, +31779=>9708, +31850=>9709, +31839=>9710, +33380=>9711, +33387=>9712, +35018=>9713, +32677=>9714, +31986=>9715, +31990=>9716, +31965=>9717, +32310=>9718, +40617=>9719, +36274=>9720, +37317=>9721, +37315=>9722, +40570=>9723, +36489=>9724, +36428=>9725, +36498=>9726, +36474=>9727, +36437=>9728, +36506=>9729, +36491=>9730, +36499=>9731, +36497=>9732, +36513=>9733, +36451=>9734, +36522=>9735, +36518=>9736, +35316=>9737, +35318=>9738, +38746=>9739, +38722=>9740, +38717=>9741, +38724=>9742, +40788=>9743, +40799=>9744, +40793=>9745, +40800=>9746, +40796=>9747, +40806=>9748, +40812=>9749, +40810=>9750, +40823=>9751, +12236=>9752, +40701=>9752, +40703=>9753, +40713=>9754, +35726=>9755, +38014=>9756, +37864=>9757, +39799=>9758, +39796=>9759, +39809=>9760, +39811=>9761, +39822=>9762, +40056=>9763, +31308=>9764, +39826=>9765, +40031=>9766, +39824=>9767, +39853=>9768, +39834=>9769, +39850=>9770, +39838=>9771, +40045=>9772, +39851=>9773, +39837=>9774, +40024=>9775, +39873=>9776, +40058=>9777, +39985=>9778, +39993=>9779, +39971=>9780, +39991=>9781, +39872=>9782, +39882=>9783, +39879=>9784, +39933=>9785, +39894=>9786, +39914=>9787, +39915=>9788, +39905=>9789, +39908=>9790, +39911=>9791, +39901=>9792, +39906=>9793, +39920=>9794, +39899=>9795, +39924=>9796, +39892=>9797, +40029=>9798, +39944=>9799, +39952=>9800, +39949=>9801, +39954=>9802, +39945=>9803, +39935=>9804, +39968=>9805, +39986=>9806, +39981=>9807, +39976=>9808, +39973=>9809, +39977=>9810, +39987=>9811, +39998=>9812, +40008=>9813, +39995=>9814, +39989=>9815, +40005=>9816, +40022=>9817, +40020=>9818, +40018=>9819, +40039=>9820, +38851=>9821, +38845=>9822, +38857=>9823, +40379=>9824, +39631=>9825, +39638=>9826, +39637=>9827, +39768=>9828, +39758=>9829, +39255=>9830, +39260=>9831, +39714=>9832, +40695=>9833, +40690=>9834, +35180=>9835, +38342=>9836, +37686=>9837, +24390=>9838, +34068=>9839, +32404=>9840, +40803=>9841, +22137=>9842, +40725=>9843, +22081=>9844, +39662=>9845, +35079=>9846, +31296=>9847, +39091=>9848, +38308=>9849, +39693=>9850, +36852=>9851, +24409=>9852, +31339=>9853, +39138=>9854, +20642=>9855, +34193=>9856, +20760=>9857, +25458=>9858, +21067=>9859, +30543=>9860, +32397=>9861, +26310=>9862, +30637=>9863, +12228=>9864, +40565=>9864, +22217=>9865, +40692=>9866, +28635=>9867, +25054=>9868, +30663=>9869, +28720=>9870, +40629=>9871, +34890=>9872, +38370=>9873, +38854=>9874, +31844=>9875, +32308=>9876, +38822=>9877, +40623=>9878, +22220=>9879, +39089=>9880, +27311=>9881, +32590=>9882, +31984=>9883, +20418=>9884, +32363=>9885, +40569=>9886, +22190=>9887, +39706=>9888, +33903=>9889, +31142=>9890, +31858=>9891, +39634=>9892, +38587=>9893, +32251=>9894, +35069=>9895, +30787=>9896, +8560=>9897, +8561=>9898, +8562=>9899, +8563=>9900, +8564=>9901, +8565=>9902, +8566=>9903, +8567=>9904, +8568=>9905, +8569=>9906, +714=>9907, +715=>9908, +729=>9909, +8211=>9910, +8213=>9911, +8229=>9912, +8245=>9913, +8453=>9914, +8457=>9915, +8598=>9916, +8599=>9917, +8600=>9918, +8601=>9919, +8725=>9920, +8735=>9921, +8739=>9922, +8786=>9923, +8806=>9924, +8807=>9925, +8895=>9926, +9552=>9927, +9553=>9928, +9554=>9929, +9555=>9930, +9556=>9931, +9557=>9932, +9558=>9933, +9559=>9934, +9560=>9935, +9561=>9936, +9562=>9937, +9563=>9938, +9564=>9939, +9565=>9940, +9566=>9941, +9567=>9942, +9568=>9943, +9569=>9944, +9570=>9945, +9571=>9946, +9572=>9947, +9573=>9948, +9574=>9949, +9575=>9950, +9576=>9951, +9577=>9952, +9578=>9953, +9579=>9954, +9580=>9955, +9581=>9956, +9582=>9957, +9583=>9958, +9584=>9959, +9585=>9960, +9586=>9961, +9587=>9962, +9601=>9963, +9602=>9964, +9603=>9965, +9604=>9966, +9605=>9967, +9606=>9968, +9607=>9969, +9608=>9970, +9609=>9971, +9610=>9972, +9611=>9973, +9612=>9974, +9613=>9975, +9614=>9976, +9615=>9977, +9619=>9978, +9620=>9979, +9621=>9980, +9660=>9981, +9661=>9982, +9698=>9983, +9699=>9984, +9700=>9985, +9701=>9986, +9737=>9987, +8853=>9988, +12306=>9989, +12317=>9990, +12318=>9991, +12321=>9992, +12322=>9993, +12323=>9994, +12324=>9995, +12325=>9996, +12326=>9997, +12327=>9998, +12328=>9999, +12329=>10000, +12963=>10001, +13198=>10002, +13199=>10003, +13212=>10004, +13213=>10005, +13214=>10006, +13217=>10007, +13252=>10008, +13262=>10009, +13265=>10010, +13266=>10011, +13269=>10012, +65072=>10013, +65506=>10014, +65508=>10015, +8481=>10016, +12849=>10017, +8208=>10018, +12540=>10019, +12443=>10020, +12444=>10021, +12541=>10022, +12542=>10023, +12294=>10024, +12445=>10025, +12446=>10026, +65097=>10027, +65098=>10028, +65099=>10029, +65100=>10030, +65101=>10031, +65102=>10032, +65103=>10033, +65104=>10034, +65105=>10035, +65106=>10036, +65108=>10037, +65109=>10038, +65110=>10039, +65111=>10040, +65113=>10041, +65114=>10042, +65115=>10043, +65116=>10044, +65117=>10045, +65118=>10046, +65119=>10047, +65120=>10048, +65121=>10049, +65122=>10050, +65123=>10051, +65124=>10052, +65125=>10053, +65126=>10054, +65128=>10055, +65129=>10056, +65130=>10057, +65131=>10058, +12350=>10059, +59367=>10059, +12272=>10060, +59368=>10060, +12273=>10061, +59369=>10061, +12274=>10062, +59370=>10062, +12275=>10063, +59371=>10063, +12276=>10064, +59372=>10064, +12277=>10065, +59373=>10065, +12278=>10066, +59374=>10066, +12279=>10067, +59375=>10067, +12280=>10068, +59376=>10068, +12281=>10069, +59377=>10069, +12282=>10070, +59378=>10070, +12283=>10071, +59379=>10071, +19970=>10072, +19972=>10073, +19973=>10074, +19974=>10075, +19983=>10076, +19986=>10077, +19991=>10078, +19999=>10079, +20000=>10080, +20001=>10081, +20003=>10082, +20006=>10083, +20009=>10084, +20014=>10085, +20015=>10086, +20017=>10087, +20019=>10088, +20021=>10089, +20023=>10090, +20028=>10091, +20032=>10092, +20033=>10093, +20034=>10094, +20036=>10095, +20038=>10096, +20042=>10097, +20049=>10098, +20053=>10099, +20055=>10100, +20058=>10101, +20059=>10102, +20066=>10103, +20067=>10104, +20068=>10105, +20069=>10106, +20071=>10107, +20072=>10108, +20074=>10109, +20075=>10110, +20076=>10111, +20077=>10112, +20078=>10113, +20079=>10114, +20082=>10115, +20084=>10116, +20085=>10117, +20086=>10118, +20087=>10119, +20088=>10120, +20089=>10121, +20090=>10122, +20091=>10123, +20092=>10124, +20093=>10125, +20095=>10126, +20096=>10127, +20097=>10128, +20099=>10129, +20100=>10130, +12037=>10131, +20101=>10131, +20103=>10132, +20106=>10133, +20112=>10134, +20118=>10135, +20119=>10136, +20121=>10137, +20124=>10138, +20125=>10139, +20131=>10140, +20138=>10141, +20143=>10142, +20144=>10143, +20145=>10144, +20148=>10145, +20150=>10146, +20151=>10147, +20152=>10148, +20153=>10149, +20156=>10150, +20157=>10151, +20158=>10152, +20168=>10153, +20172=>10154, +20175=>10155, +20176=>10156, +20178=>10157, +20186=>10158, +20187=>10159, +20188=>10160, +20192=>10161, +20194=>10162, +20198=>10163, +20199=>10164, +20201=>10165, +20205=>10166, +20206=>10167, +20207=>10168, +20209=>10169, +20212=>10170, +20216=>10171, +20217=>10172, +20218=>10173, +20220=>10174, +20222=>10175, +20224=>10176, +20226=>10177, +20227=>10178, +20228=>10179, +20229=>10180, +20230=>10181, +20231=>10182, +20232=>10183, +20235=>10184, +20236=>10185, +20242=>10186, +20243=>10187, +20244=>10188, +20245=>10189, +20246=>10190, +20252=>10191, +20253=>10192, +20257=>10193, +20259=>10194, +20264=>10195, +20265=>10196, +20268=>10197, +20269=>10198, +20270=>10199, +20273=>10200, +20275=>10201, +20277=>10202, +20279=>10203, +20281=>10204, +20283=>10205, +20286=>10206, +20287=>10207, +20288=>10208, +20289=>10209, +20290=>10210, +20292=>10211, +20293=>10212, +20295=>10213, +20296=>10214, +20297=>10215, +20298=>10216, +20299=>10217, +20300=>10218, +20306=>10219, +20308=>10220, +20310=>10221, +20321=>10222, +20322=>10223, +20326=>10224, +20328=>10225, +20330=>10226, +20331=>10227, +20333=>10228, +20334=>10229, +20337=>10230, +20338=>10231, +20341=>10232, +20343=>10233, +20344=>10234, +20345=>10235, +20346=>10236, +20349=>10237, +20352=>10238, +20353=>10239, +20354=>10240, +20357=>10241, +20359=>10242, +20362=>10243, +20364=>10244, +20366=>10245, +20368=>10246, +20370=>10247, +20371=>10248, +20373=>10249, +20376=>10250, +20377=>10251, +20378=>10252, +20380=>10253, +20382=>10254, +20383=>10255, +20385=>10256, +20386=>10257, +20388=>10258, +20395=>10259, +20397=>10260, +20400=>10261, +20401=>10262, +20402=>10263, +20403=>10264, +20404=>10265, +20406=>10266, +20407=>10267, +20408=>10268, +20409=>10269, +20410=>10270, +20411=>10271, +20412=>10272, +20413=>10273, +20414=>10274, +20416=>10275, +20417=>10276, +20422=>10277, +20423=>10278, +20424=>10279, +20425=>10280, +20427=>10281, +20428=>10282, +20429=>10283, +20434=>10284, +20435=>10285, +20436=>10286, +20437=>10287, +20438=>10288, +20441=>10289, +20443=>10290, +20450=>10291, +20452=>10292, +20453=>10293, +20455=>10294, +20459=>10295, +20460=>10296, +20464=>10297, +20466=>10298, +20468=>10299, +20469=>10300, +20470=>10301, +20471=>10302, +20473=>10303, +20475=>10304, +20476=>10305, +20477=>10306, +20479=>10307, +20481=>10308, +20482=>10309, +20483=>10310, +20484=>10311, +20485=>10312, +20487=>10313, +20488=>10314, +20490=>10315, +20494=>10316, +20496=>10317, +20499=>10318, +20501=>10319, +20502=>10320, +20503=>10321, +20507=>10322, +20509=>10323, +20510=>10324, +20512=>10325, +20514=>10326, +20515=>10327, +20516=>10328, +20519=>10329, +20527=>10330, +20528=>10331, +20529=>10332, +20530=>10333, +20531=>10334, +20532=>10335, +20533=>10336, +20534=>10337, +20535=>10338, +20536=>10339, +20537=>10340, +20539=>10341, +20541=>10342, +20543=>10343, +20544=>10344, +20545=>10345, +20546=>10346, +20548=>10347, +20549=>10348, +20550=>10349, +20554=>10350, +20555=>10351, +20557=>10352, +20560=>10353, +20561=>10354, +20562=>10355, +20563=>10356, +20564=>10357, +20566=>10358, +20567=>10359, +20568=>10360, +20569=>10361, +20571=>10362, +20573=>10363, +20574=>10364, +20575=>10365, +20576=>10366, +20577=>10367, +20578=>10368, +20579=>10369, +20580=>10370, +20582=>10371, +20583=>10372, +20584=>10373, +20585=>10374, +20586=>10375, +20587=>10376, +20589=>10377, +20590=>10378, +20591=>10379, +20592=>10380, +20593=>10381, +20594=>10382, +20595=>10383, +20600=>10384, +20601=>10385, +20602=>10386, +20604=>10387, +20605=>10388, +20609=>10389, +20610=>10390, +20611=>10391, +20612=>10392, +20614=>10393, +20615=>10394, +20617=>10395, +20618=>10396, +20619=>10397, +20620=>10398, +20622=>10399, +20623=>10400, +20624=>10401, +20625=>10402, +20626=>10403, +20627=>10404, +20628=>10405, +20629=>10406, +20631=>10407, +20634=>10408, +20635=>10409, +20636=>10410, +20637=>10411, +20638=>10412, +20639=>10413, +20640=>10414, +20641=>10415, +20644=>10416, +20646=>10417, +20650=>10418, +20651=>10419, +20654=>10420, +20655=>10421, +20656=>10422, +20657=>10423, +20662=>10424, +20664=>10425, +20665=>10426, +20668=>10427, +20669=>10428, +20671=>10429, +20672=>10430, +20673=>10431, +20675=>10432, +20676=>10433, +20678=>10434, +20679=>10435, +20680=>10436, +20682=>10437, +20683=>10438, +20684=>10439, +20685=>10440, +20686=>10441, +20688=>10442, +20690=>10443, +20691=>10444, +20692=>10445, +20695=>10446, +20696=>10447, +20697=>10448, +20699=>10449, +20700=>10450, +20701=>10451, +20703=>10452, +20704=>10453, +20705=>10454, +20706=>10455, +20707=>10456, +20708=>10457, +20713=>10458, +20714=>10459, +20715=>10460, +20719=>10461, +20720=>10462, +20721=>10463, +20722=>10464, +20724=>10465, +20726=>10466, +20727=>10467, +20728=>10468, +20730=>10469, +20732=>10470, +20733=>10471, +20734=>10472, +20735=>10473, +20737=>10474, +20739=>10475, +20741=>10476, +20746=>10477, +20748=>10478, +20749=>10479, +20750=>10480, +20751=>10481, +20753=>10482, +20755=>10483, +20758=>10484, +20759=>10485, +20761=>10486, +20762=>10487, +20763=>10488, +20764=>10489, +20765=>10490, +20766=>10491, +20768=>10492, +20770=>10493, +20771=>10494, +20772=>10495, +20773=>10496, +20774=>10497, +20775=>10498, +20776=>10499, +20777=>10500, +20779=>10501, +20780=>10502, +20781=>10503, +20782=>10504, +20783=>10505, +20784=>10506, +20785=>10507, +20787=>10508, +20788=>10509, +20789=>10510, +20790=>10511, +20792=>10512, +20793=>10513, +20797=>10514, +20798=>10515, +20802=>10516, +20807=>10517, +20810=>10518, +20812=>10519, +20814=>10520, +20815=>10521, +20816=>10522, +20819=>10523, +20823=>10524, +20824=>10525, +20825=>10526, +20827=>10527, +20829=>10528, +20830=>10529, +20831=>10530, +20832=>10531, +20833=>10532, +20835=>10533, +20836=>10534, +20838=>10535, +20839=>10536, +20842=>10537, +20847=>10538, +20850=>10539, +20858=>10540, +20862=>10541, +20863=>10542, +20867=>10543, +20868=>10544, +20870=>10545, +20871=>10546, +20874=>10547, +20875=>10548, +20878=>10549, +20879=>10550, +20880=>10551, +20881=>10552, +20883=>10553, +20884=>10554, +20888=>10555, +20890=>10556, +20893=>10557, +20894=>10558, +20895=>10559, +20897=>10560, +20899=>10561, +20902=>10562, +20903=>10563, +20904=>10564, +20905=>10565, +20906=>10566, +20909=>10567, +20910=>10568, +20916=>10569, +20920=>10570, +20921=>10571, +20922=>10572, +20926=>10573, +20927=>10574, +20929=>10575, +20930=>10576, +20931=>10577, +20933=>10578, +20936=>10579, +20938=>10580, +20942=>10581, +20944=>10582, +20946=>10583, +20947=>10584, +20948=>10585, +20949=>10586, +20950=>10587, +20951=>10588, +20952=>10589, +20953=>10590, +20954=>10591, +20956=>10592, +20958=>10593, +20959=>10594, +20962=>10595, +20963=>10596, +20965=>10597, +20966=>10598, +20967=>10599, +20968=>10600, +20969=>10601, +20970=>10602, +20972=>10603, +20974=>10604, +20978=>10605, +20980=>10606, +20983=>10607, +20990=>10608, +20996=>10609, +20997=>10610, +21001=>10611, +21003=>10612, +21004=>10613, +21007=>10614, +21008=>10615, +21011=>10616, +21012=>10617, +21013=>10618, +21020=>10619, +21022=>10620, +21023=>10621, +21025=>10622, +21026=>10623, +21027=>10624, +21029=>10625, +21030=>10626, +21031=>10627, +21034=>10628, +21036=>10629, +21039=>10630, +21041=>10631, +21042=>10632, +21044=>10633, +21045=>10634, +21052=>10635, +21054=>10636, +21061=>10637, +21062=>10638, +21064=>10639, +21065=>10640, +21070=>10641, +21071=>10642, +21074=>10643, +21075=>10644, +21077=>10645, +21079=>10646, +21080=>10647, +21081=>10648, +21082=>10649, +21085=>10650, +21087=>10651, +21088=>10652, +21090=>10653, +21091=>10654, +21092=>10655, +21094=>10656, +21096=>10657, +21099=>10658, +21100=>10659, +21101=>10660, +21104=>10661, +21105=>10662, +21107=>10663, +21110=>10664, +21111=>10665, +21112=>10666, +21113=>10667, +21114=>10668, +21115=>10669, +21116=>10670, +21118=>10671, +21120=>10672, +21124=>10673, +21125=>10674, +21126=>10675, +21131=>10676, +21134=>10677, +21135=>10678, +21138=>10679, +21140=>10680, +21141=>10681, +21142=>10682, +21143=>10683, +21144=>10684, +21145=>10685, +21146=>10686, +21148=>10687, +21156=>10688, +21157=>10689, +21158=>10690, +21159=>10691, +21166=>10692, +21167=>10693, +21168=>10694, +21172=>10695, +21173=>10696, +21174=>10697, +21175=>10698, +21176=>10699, +21177=>10700, +21178=>10701, +21179=>10702, +21180=>10703, +21181=>10704, +21184=>10705, +21186=>10706, +21188=>10707, +21189=>10708, +21190=>10709, +21192=>10710, +21194=>10711, +21196=>10712, +21197=>10713, +21198=>10714, +21199=>10715, +21201=>10716, +21203=>10717, +21204=>10718, +21207=>10719, +21210=>10720, +21212=>10721, +21216=>10722, +21217=>10723, +21219=>10724, +21221=>10725, +21222=>10726, +21223=>10727, +21224=>10728, +21225=>10729, +21226=>10730, +21227=>10731, +21228=>10732, +21229=>10733, +21230=>10734, +21231=>10735, +21234=>10736, +21235=>10737, +21236=>10738, +21238=>10739, +21239=>10740, +21243=>10741, +21244=>10742, +21245=>10743, +21249=>10744, +21250=>10745, +21251=>10746, +21252=>10747, +21255=>10748, +21257=>10749, +21258=>10750, +21259=>10751, +21260=>10752, +21262=>10753, +21265=>10754, +21266=>10755, +21267=>10756, +21268=>10757, +21272=>10758, +21275=>10759, +21276=>10760, +21278=>10761, +21279=>10762, +21282=>10763, +21284=>10764, +21285=>10765, +21287=>10766, +21288=>10767, +21289=>10768, +21291=>10769, +21292=>10770, +21296=>10771, +21298=>10772, +21299=>10773, +21300=>10774, +21301=>10775, +21302=>10776, +21303=>10777, +12054=>10778, +21304=>10778, +21308=>10779, +21309=>10780, +21314=>10781, +21316=>10782, +21318=>10783, +21323=>10784, +21324=>10785, +21325=>10786, +21328=>10787, +21336=>10788, +21337=>10789, +21339=>10790, +21341=>10791, +21349=>10792, +21352=>10793, +21354=>10794, +21356=>10795, +21357=>10796, +21362=>10797, +21366=>10798, +21369=>10799, +21371=>10800, +21372=>10801, +21373=>10802, +21374=>10803, +21376=>10804, +21377=>10805, +21379=>10806, +21383=>10807, +21384=>10808, +21386=>10809, +21390=>10810, +21391=>10811, +21392=>10812, +21393=>10813, +21394=>10814, +21395=>10815, +21396=>10816, +21398=>10817, +21399=>10818, +21403=>10819, +21404=>10820, +21406=>10821, +21409=>10822, +21412=>10823, +21415=>10824, +21418=>10825, +21419=>10826, +21420=>10827, +21423=>10828, +21424=>10829, +21425=>10830, +21427=>10831, +21429=>10832, +21431=>10833, +21432=>10834, +21433=>10835, +21434=>10836, +21436=>10837, +21437=>10838, +21438=>10839, +21440=>10840, +21444=>10841, +21445=>10842, +21446=>10843, +21447=>10844, +21454=>10845, +21455=>10846, +21456=>10847, +21458=>10848, +21459=>10849, +21461=>10850, +21466=>10851, +21468=>10852, +21469=>10853, +21470=>10854, +21473=>10855, +21479=>10856, +21492=>10857, +21498=>10858, +21502=>10859, +21503=>10860, +21504=>10861, +21506=>10862, +21509=>10863, +21511=>10864, +21515=>10865, +21524=>10866, +21528=>10867, +21529=>10868, +21530=>10869, +21532=>10870, +21538=>10871, +21540=>10872, +21541=>10873, +21546=>10874, +21552=>10875, +21555=>10876, +21558=>10877, +21559=>10878, +21562=>10879, +21565=>10880, +21567=>10881, +21569=>10882, +21570=>10883, +21572=>10884, +21573=>10885, +21575=>10886, +21577=>10887, +21580=>10888, +21581=>10889, +21582=>10890, +21583=>10891, +21585=>10892, +21594=>10893, +21597=>10894, +21598=>10895, +21599=>10896, +21600=>10897, +21601=>10898, +21603=>10899, +21605=>10900, +21607=>10901, +21609=>10902, +21610=>10903, +21611=>10904, +21612=>10905, +21613=>10906, +21614=>10907, +21615=>10908, +21616=>10909, +21620=>10910, +21625=>10911, +21626=>10912, +21630=>10913, +21631=>10914, +21633=>10915, +21635=>10916, +21637=>10917, +21639=>10918, +21640=>10919, +21641=>10920, +21642=>10921, +21645=>10922, +21649=>10923, +21651=>10924, +21655=>10925, +21656=>10926, +21660=>10927, +21662=>10928, +21663=>10929, +21664=>10930, +21665=>10931, +21666=>10932, +21669=>10933, +21678=>10934, +21680=>10935, +21682=>10936, +21685=>10937, +21686=>10938, +21687=>10939, +21689=>10940, +21690=>10941, +21694=>10942, +21699=>10943, +21701=>10944, +21706=>10945, +21707=>10946, +21718=>10947, +21720=>10948, +21723=>10949, +21728=>10950, +21730=>10951, +21731=>10952, +21732=>10953, +21739=>10954, +21740=>10955, +21743=>10956, +21744=>10957, +21745=>10958, +21748=>10959, +21749=>10960, +21750=>10961, +21751=>10962, +21752=>10963, +21753=>10964, +21755=>10965, +21758=>10966, +21760=>10967, +21762=>10968, +21763=>10969, +21765=>10970, +21768=>10971, +21770=>10972, +21771=>10973, +21772=>10974, +21773=>10975, +21774=>10976, +21778=>10977, +21779=>10978, +21781=>10979, +21782=>10980, +21783=>10981, +21784=>10982, +21785=>10983, +21786=>10984, +21788=>10985, +21789=>10986, +21790=>10987, +21791=>10988, +21793=>10989, +21797=>10990, +21798=>10991, +21800=>10992, +21801=>10993, +21803=>10994, +21805=>10995, +21810=>10996, +21812=>10997, +21813=>10998, +21814=>10999, +21816=>11000, +21817=>11001, +21818=>11002, +21819=>11003, +21821=>11004, +21824=>11005, +21826=>11006, +21829=>11007, +21831=>11008, +21832=>11009, +21835=>11010, +21836=>11011, +21837=>11012, +21838=>11013, +21841=>11014, +21842=>11015, +21844=>11016, +21847=>11017, +21848=>11018, +21849=>11019, +21850=>11020, +21851=>11021, +21853=>11022, +21855=>11023, +21856=>11024, +21858=>11025, +21859=>11026, +21864=>11027, +21865=>11028, +21867=>11029, +21871=>11030, +21872=>11031, +21873=>11032, +21874=>11033, +21875=>11034, +21876=>11035, +21881=>11036, +21882=>11037, +21885=>11038, +21887=>11039, +21893=>11040, +21894=>11041, +21900=>11042, +21901=>11043, +21902=>11044, +21904=>11045, +21906=>11046, +21907=>11047, +21909=>11048, +21910=>11049, +21911=>11050, +21914=>11051, +21915=>11052, +21918=>11053, +21920=>11054, +21921=>11055, +21922=>11056, +21923=>11057, +21924=>11058, +21925=>11059, +21926=>11060, +21928=>11061, +21929=>11062, +21931=>11063, +21933=>11064, +21935=>11065, +21936=>11066, +21940=>11067, +21942=>11068, +21944=>11069, +21946=>11070, +21948=>11071, +21951=>11072, +21952=>11073, +21953=>11074, +21954=>11075, +21955=>11076, +21960=>11077, +21962=>11078, +21963=>11079, +21967=>11080, +21968=>11081, +21973=>11082, +21975=>11083, +21976=>11084, +21977=>11085, +21979=>11086, +21982=>11087, +21984=>11088, +21986=>11089, +21991=>11090, +21997=>11091, +21998=>11092, +22000=>11093, +22001=>11094, +22004=>11095, +22008=>11096, +22009=>11097, +22010=>11098, +22011=>11099, +22012=>11100, +22015=>11101, +22018=>11102, +22019=>11103, +22020=>11104, +22021=>11105, +22023=>11106, +22026=>11107, +22027=>11108, +22032=>11109, +22033=>11110, +22034=>11111, +22035=>11112, +22037=>11113, +22041=>11114, +22042=>11115, +22045=>11116, +22048=>11117, +22049=>11118, +22050=>11119, +22053=>11120, +22054=>11121, +22056=>11122, +22058=>11123, +22059=>11124, +22067=>11125, +22071=>11126, +22074=>11127, +22076=>11128, +22077=>11129, +22078=>11130, +22080=>11131, +22082=>11132, +22083=>11133, +22084=>11134, +22085=>11135, +22086=>11136, +22087=>11137, +22088=>11138, +22089=>11139, +22090=>11140, +22091=>11141, +22095=>11142, +22096=>11143, +22097=>11144, +22098=>11145, +22099=>11146, +22101=>11147, +22102=>11148, +22106=>11149, +22107=>11150, +22110=>11151, +22111=>11152, +22113=>11153, +22115=>11154, +22119=>11155, +22125=>11156, +22126=>11157, +22128=>11158, +22131=>11159, +22133=>11160, +22135=>11161, +22138=>11162, +22141=>11163, +22142=>11164, +22143=>11165, +22145=>11166, +22146=>11167, +22147=>11168, +22148=>11169, +22152=>11170, +22153=>11171, +22154=>11172, +22155=>11173, +22157=>11174, +22160=>11175, +22161=>11176, +22162=>11177, +22164=>11178, +22166=>11179, +22167=>11180, +22168=>11181, +22170=>11182, +22171=>11183, +22172=>11184, +22173=>11185, +22174=>11186, +22175=>11187, +22176=>11188, +22177=>11189, +22178=>11190, +22180=>11191, +22181=>11192, +22183=>11193, +22185=>11194, +22186=>11195, +22187=>11196, +22188=>11197, +22189=>11198, +22192=>11199, +22193=>11200, +22194=>11201, +22197=>11202, +22200=>11203, +22201=>11204, +22202=>11205, +22203=>11206, +22205=>11207, +22206=>11208, +22207=>11209, +22211=>11210, +22212=>11211, +22214=>11212, +22215=>11213, +22219=>11214, +22221=>11215, +22222=>11216, +22223=>11217, +22224=>11218, +22226=>11219, +22227=>11220, +22229=>11221, +22230=>11222, +22232=>11223, +22233=>11224, +22236=>11225, +22243=>11226, +22245=>11227, +22246=>11228, +22247=>11229, +22248=>11230, +22249=>11231, +22250=>11232, +22252=>11233, +22254=>11234, +22255=>11235, +22258=>11236, +22259=>11237, +22262=>11238, +22263=>11239, +22264=>11240, +22267=>11241, +22268=>11242, +22272=>11243, +22273=>11244, +22274=>11245, +22277=>11246, +22284=>11247, +22286=>11248, +22287=>11249, +22288=>11250, +22289=>11251, +22292=>11252, +22293=>11253, +22295=>11254, +22297=>11255, +22298=>11256, +22299=>11257, +22301=>11258, +22302=>11259, +22304=>11260, +22305=>11261, +22306=>11262, +22308=>11263, +22309=>11264, +22310=>11265, +22311=>11266, +22315=>11267, +22321=>11268, +22322=>11269, +22324=>11270, +22325=>11271, +22326=>11272, +22327=>11273, +22328=>11274, +22332=>11275, +22333=>11276, +22335=>11277, +22337=>11278, +22339=>11279, +22340=>11280, +22341=>11281, +22342=>11282, +22344=>11283, +22345=>11284, +22347=>11285, +22354=>11286, +22355=>11287, +22356=>11288, +22357=>11289, +22358=>11290, +22360=>11291, +22361=>11292, +22370=>11293, +22371=>11294, +22373=>11295, +22375=>11296, +22380=>11297, +22382=>11298, +22384=>11299, +22385=>11300, +22386=>11301, +22388=>11302, +22389=>11303, +22392=>11304, +22393=>11305, +22394=>11306, +22397=>11307, +22398=>11308, +22399=>11309, +22400=>11310, +22401=>11311, +22407=>11312, +22408=>11313, +22409=>11314, +22410=>11315, +22413=>11316, +22414=>11317, +22415=>11318, +22416=>11319, +22417=>11320, +22420=>11321, +22421=>11322, +22422=>11323, +22423=>11324, +22424=>11325, +22425=>11326, +22426=>11327, +22428=>11328, +22429=>11329, +22430=>11330, +22431=>11331, +22437=>11332, +22440=>11333, +22442=>11334, +22444=>11335, +22447=>11336, +22448=>11337, +22449=>11338, +22451=>11339, +22453=>11340, +22454=>11341, +22455=>11342, +22457=>11343, +22458=>11344, +22459=>11345, +22460=>11346, +22461=>11347, +22462=>11348, +22463=>11349, +22464=>11350, +22465=>11351, +22468=>11352, +22469=>11353, +22470=>11354, +22471=>11355, +22472=>11356, +22473=>11357, +22474=>11358, +22476=>11359, +22477=>11360, +22480=>11361, +22481=>11362, +22483=>11363, +22486=>11364, +22487=>11365, +22491=>11366, +22492=>11367, +22494=>11368, +22498=>11369, +22499=>11370, +22501=>11371, +22502=>11372, +22503=>11373, +22504=>11374, +22505=>11375, +22506=>11376, +22507=>11377, +22508=>11378, +22510=>11379, +22512=>11380, +22513=>11381, +22514=>11382, +22515=>11383, +22517=>11384, +22518=>11385, +22523=>11386, +22524=>11387, +22526=>11388, +22527=>11389, +22529=>11390, +22531=>11391, +22532=>11392, +22536=>11393, +22537=>11394, +22540=>11395, +22542=>11396, +22543=>11397, +22544=>11398, +22546=>11399, +22547=>11400, +22548=>11401, +22551=>11402, +22552=>11403, +22554=>11404, +22555=>11405, +22556=>11406, +22559=>11407, +22562=>11408, +22563=>11409, +22565=>11410, +22566=>11411, +22567=>11412, +22568=>11413, +22569=>11414, +22571=>11415, +22572=>11416, +22573=>11417, +22574=>11418, +22578=>11419, +22579=>11420, +22582=>11421, +22583=>11422, +22584=>11423, +22585=>11424, +22586=>11425, +22587=>11426, +22588=>11427, +22589=>11428, +22590=>11429, +22591=>11430, +22592=>11431, +22593=>11432, +22594=>11433, +22595=>11434, +22597=>11435, +22598=>11436, +22599=>11437, +22600=>11438, +22601=>11439, +22606=>11440, +22608=>11441, +22611=>11442, +22613=>11443, +22614=>11444, +22617=>11445, +22618=>11446, +22619=>11447, +22620=>11448, +22621=>11449, +22623=>11450, +22624=>11451, +22625=>11452, +22627=>11453, +22630=>11454, +22631=>11455, +22632=>11456, +22633=>11457, +22634=>11458, +22637=>11459, +22638=>11460, +22639=>11461, +22640=>11462, +22641=>11463, +22642=>11464, +22643=>11465, +22644=>11466, +22646=>11467, +22647=>11468, +22648=>11469, +22650=>11470, +22651=>11471, +22652=>11472, +22653=>11473, +22655=>11474, +22658=>11475, +22660=>11476, +22662=>11477, +22663=>11478, +22664=>11479, +22667=>11480, +22668=>11481, +22669=>11482, +22670=>11483, +22671=>11484, +22672=>11485, +22673=>11486, +22676=>11487, +22677=>11488, +22678=>11489, +22679=>11490, +22680=>11491, +22683=>11492, +22685=>11493, +22688=>11494, +22689=>11495, +22690=>11496, +22691=>11497, +22692=>11498, +22693=>11499, +22694=>11500, +22695=>11501, +22698=>11502, +22699=>11503, +22700=>11504, +22701=>11505, +22703=>11506, +22704=>11507, +22705=>11508, +22706=>11509, +22708=>11510, +22709=>11511, +22710=>11512, +22711=>11513, +22712=>11514, +22713=>11515, +22714=>11516, +22717=>11517, +22719=>11518, +22720=>11519, +22722=>11520, +22723=>11521, +22724=>11522, +22726=>11523, +22728=>11524, +22729=>11525, +22730=>11526, +22731=>11527, +22732=>11528, +22733=>11529, +22734=>11530, +22735=>11531, +22736=>11532, +22738=>11533, +22740=>11534, +22742=>11535, +22743=>11536, +22747=>11537, +22748=>11538, +22749=>11539, +22753=>11540, +22755=>11541, +22757=>11542, +22758=>11543, +22759=>11544, +22760=>11545, +22762=>11546, +22765=>11547, +22769=>11548, +22770=>11549, +22772=>11550, +22773=>11551, +22775=>11552, +22776=>11553, +22779=>11554, +22780=>11555, +22782=>11556, +22783=>11557, +22784=>11558, +22785=>11559, +22787=>11560, +22789=>11561, +22790=>11562, +22792=>11563, +22793=>11564, +12066=>11565, +22794=>11565, +22795=>11566, +22796=>11567, +22798=>11568, +22800=>11569, +22801=>11570, +22802=>11571, +22803=>11572, +22807=>11573, +22808=>11574, +22811=>11575, +22813=>11576, +22814=>11577, +22816=>11578, +22817=>11579, +22819=>11580, +22822=>11581, +22824=>11582, +22828=>11583, +22832=>11584, +22834=>11585, +22835=>11586, +22837=>11587, +22838=>11588, +22843=>11589, +22845=>11590, +22847=>11591, +22848=>11592, +22851=>11593, +22853=>11594, +22854=>11595, +22858=>11596, +22860=>11597, +22861=>11598, +22864=>11599, +22866=>11600, +22867=>11601, +22873=>11602, +22875=>11603, +22876=>11604, +22877=>11605, +22878=>11606, +22879=>11607, +22881=>11608, +22883=>11609, +22884=>11610, +22886=>11611, +22887=>11612, +22888=>11613, +22891=>11614, +22893=>11615, +22895=>11616, +22896=>11617, +22897=>11618, +22898=>11619, +22901=>11620, +22903=>11621, +22906=>11622, +22907=>11623, +22908=>11624, +22910=>11625, +22911=>11626, +22912=>11627, +22917=>11628, +22921=>11629, +22923=>11630, +22924=>11631, +22926=>11632, +22927=>11633, +22928=>11634, +22929=>11635, +22932=>11636, +22933=>11637, +22936=>11638, +22938=>11639, +22939=>11640, +22940=>11641, +22943=>11642, +22944=>11643, +22945=>11644, +22946=>11645, +22950=>11646, +22951=>11647, +22956=>11648, +22957=>11649, +22960=>11650, +22961=>11651, +22963=>11652, +22964=>11653, +22965=>11654, +22966=>11655, +22967=>11656, +22968=>11657, +22970=>11658, +22972=>11659, +22973=>11660, +22975=>11661, +22976=>11662, +22977=>11663, +22978=>11664, +22979=>11665, +22980=>11666, +22981=>11667, +22983=>11668, +22984=>11669, +22985=>11670, +22988=>11671, +22989=>11672, +22990=>11673, +22991=>11674, +22997=>11675, +22998=>11676, +23001=>11677, +23003=>11678, +23006=>11679, +23007=>11680, +23008=>11681, +23009=>11682, +23010=>11683, +23012=>11684, +23014=>11685, +23015=>11686, +23017=>11687, +23018=>11688, +23019=>11689, +23021=>11690, +23022=>11691, +23023=>11692, +23024=>11693, +23025=>11694, +23026=>11695, +23027=>11696, +23028=>11697, +23029=>11698, +23030=>11699, +23031=>11700, +23032=>11701, +23034=>11702, +23036=>11703, +23037=>11704, +23038=>11705, +23040=>11706, +23042=>11707, +23050=>11708, +23051=>11709, +23053=>11710, +23054=>11711, +23055=>11712, +23056=>11713, +23058=>11714, +23060=>11715, +23061=>11716, +23062=>11717, +23063=>11718, +23065=>11719, +23066=>11720, +23067=>11721, +23069=>11722, +23070=>11723, +23073=>11724, +23074=>11725, +23076=>11726, +23078=>11727, +23079=>11728, +23080=>11729, +23082=>11730, +23083=>11731, +23084=>11732, +23085=>11733, +23086=>11734, +23087=>11735, +23088=>11736, +23091=>11737, +23093=>11738, +23095=>11739, +23096=>11740, +23097=>11741, +23098=>11742, +23099=>11743, +23101=>11744, +23102=>11745, +23103=>11746, +23106=>11747, +23107=>11748, +23108=>11749, +23109=>11750, +23111=>11751, +23112=>11752, +23115=>11753, +23116=>11754, +23117=>11755, +23118=>11756, +23119=>11757, +23120=>11758, +23121=>11759, +23122=>11760, +23123=>11761, +23124=>11762, +23126=>11763, +23127=>11764, +23128=>11765, +23129=>11766, +23131=>11767, +23132=>11768, +23133=>11769, +23134=>11770, +23135=>11771, +23136=>11772, +23137=>11773, +23139=>11774, +23140=>11775, +23141=>11776, +23144=>11777, +23145=>11778, +23147=>11779, +23148=>11780, +23150=>11781, +23151=>11782, +23152=>11783, +23153=>11784, +23154=>11785, +23155=>11786, +23160=>11787, +23161=>11788, +23163=>11789, +23164=>11790, +23165=>11791, +23166=>11792, +23168=>11793, +23169=>11794, +23170=>11795, +23171=>11796, +23172=>11797, +23173=>11798, +23174=>11799, +23175=>11800, +23176=>11801, +23177=>11802, +23178=>11803, +23179=>11804, +23180=>11805, +23181=>11806, +23182=>11807, +23183=>11808, +23184=>11809, +23185=>11810, +23187=>11811, +23188=>11812, +23189=>11813, +23190=>11814, +23191=>11815, +23192=>11816, +23193=>11817, +23196=>11818, +23197=>11819, +23198=>11820, +23199=>11821, +23200=>11822, +23201=>11823, +23202=>11824, +23203=>11825, +23204=>11826, +23205=>11827, +23206=>11828, +23208=>11829, +23209=>11830, +23211=>11831, +23212=>11832, +23213=>11833, +23214=>11834, +23215=>11835, +23216=>11836, +23217=>11837, +23220=>11838, +23222=>11839, +23223=>11840, +23225=>11841, +23226=>11842, +23227=>11843, +23228=>11844, +23231=>11845, +23232=>11846, +23235=>11847, +23236=>11848, +23237=>11849, +23238=>11850, +23239=>11851, +23240=>11852, +23242=>11853, +23243=>11854, +23245=>11855, +23246=>11856, +23247=>11857, +23248=>11858, +23249=>11859, +23251=>11860, +23253=>11861, +23257=>11862, +23258=>11863, +23259=>11864, +23261=>11865, +23262=>11866, +23263=>11867, +23266=>11868, +23268=>11869, +23269=>11870, +23271=>11871, +23272=>11872, +23274=>11873, +23276=>11874, +23277=>11875, +23278=>11876, +23279=>11877, +23280=>11878, +23282=>11879, +23283=>11880, +23284=>11881, +23286=>11882, +23287=>11883, +23288=>11884, +23289=>11885, +23290=>11886, +23292=>11887, +23293=>11888, +23294=>11889, +23295=>11890, +23297=>11891, +23298=>11892, +23299=>11893, +23300=>11894, +23301=>11895, +23302=>11896, +23303=>11897, +23306=>11898, +23309=>11899, +23310=>11900, +23311=>11901, +23312=>11902, +23313=>11903, +23314=>11904, +23315=>11905, +23316=>11906, +23317=>11907, +23320=>11908, +23322=>11909, +23323=>11910, +23324=>11911, +23325=>11912, +23326=>11913, +23327=>11914, +23328=>11915, +23330=>11916, +23331=>11917, +23332=>11918, +23333=>11919, +23334=>11920, +23335=>11921, +23336=>11922, +23337=>11923, +23339=>11924, +23340=>11925, +23341=>11926, +23342=>11927, +23343=>11928, +23345=>11929, +23347=>11930, +23349=>11931, +23350=>11932, +23353=>11933, +23354=>11934, +23355=>11935, +23356=>11936, +23357=>11937, +23358=>11938, +23359=>11939, +23361=>11940, +23362=>11941, +23363=>11942, +23364=>11943, +23365=>11944, +23366=>11945, +23367=>11946, +23368=>11947, +23369=>11948, +23370=>11949, +23371=>11950, +23373=>11951, +23374=>11952, +23375=>11953, +23378=>11954, +23382=>11955, +23390=>11956, +23392=>11957, +23393=>11958, +23399=>11959, +23400=>11960, +23405=>11961, +23406=>11962, +23407=>11963, +23410=>11964, +23412=>11965, +23414=>11966, +23415=>11967, +23417=>11968, +23419=>11969, +23420=>11970, +23422=>11971, +23426=>11972, +23430=>11973, +23434=>11974, +23437=>11975, +23438=>11976, +23440=>11977, +23441=>11978, +23442=>11979, +23444=>11980, +23446=>11981, +23455=>11982, +23463=>11983, +23464=>11984, +23465=>11985, +23468=>11986, +23469=>11987, +23470=>11988, +23471=>11989, +23473=>11990, +23474=>11991, +23479=>11992, +23482=>11993, +23483=>11994, +23484=>11995, +23488=>11996, +23489=>11997, +23491=>11998, +23496=>11999, +23497=>12000, +23498=>12001, +23499=>12002, +23501=>12003, +23502=>12004, +23503=>12005, +23505=>12006, +23508=>12007, +23509=>12008, +23510=>12009, +23511=>12010, +23512=>12011, +23513=>12012, +23514=>12013, +23515=>12014, +23516=>12015, +23520=>12016, +23523=>12017, +23530=>12018, +23533=>12019, +23535=>12020, +23537=>12021, +23538=>12022, +23539=>12023, +23540=>12024, +23543=>12025, +23549=>12026, +23550=>12027, +23552=>12028, +23554=>12029, +23555=>12030, +23557=>12031, +23564=>12032, +23568=>12033, +23570=>12034, +23571=>12035, +23575=>12036, +23577=>12037, +23579=>12038, +23582=>12039, +23583=>12040, +23584=>12041, +23585=>12042, +23587=>12043, +23590=>12044, +23592=>12045, +23593=>12046, +23594=>12047, +23595=>12048, +23597=>12049, +23598=>12050, +23599=>12051, +23600=>12052, +23602=>12053, +23603=>12054, +23605=>12055, +23606=>12056, +23619=>12057, +23620=>12058, +23622=>12059, +23623=>12060, +23628=>12061, +23629=>12062, +23634=>12063, +23635=>12064, +23636=>12065, +23638=>12066, +23639=>12067, +23640=>12068, +23642=>12069, +23643=>12070, +23644=>12071, +23645=>12072, +23647=>12073, +23655=>12074, +23657=>12075, +23658=>12076, +23659=>12077, +23661=>12078, +23664=>12079, +23666=>12080, +23667=>12081, +23668=>12082, +23669=>12083, +23670=>12084, +23671=>12085, +23672=>12086, +23675=>12087, +23676=>12088, +23677=>12089, +23678=>12090, +23680=>12091, +23683=>12092, +23684=>12093, +23685=>12094, +23686=>12095, +23687=>12096, +23689=>12097, +23690=>12098, +23691=>12099, +23694=>12100, +23695=>12101, +23698=>12102, +23699=>12103, +23701=>12104, +23709=>12105, +23710=>12106, +23711=>12107, +23712=>12108, +23716=>12109, +23717=>12110, +23718=>12111, +23719=>12112, +23720=>12113, +23722=>12114, +23726=>12115, +23727=>12116, +23728=>12117, +23730=>12118, +23732=>12119, +23734=>12120, +23737=>12121, +23738=>12122, +23739=>12123, +23740=>12124, +23742=>12125, +23744=>12126, +23746=>12127, +23747=>12128, +23749=>12129, +23750=>12130, +23751=>12131, +23752=>12132, +23753=>12133, +23754=>12134, +23756=>12135, +23757=>12136, +23758=>12137, +23759=>12138, +23760=>12139, +23761=>12140, +23763=>12141, +23764=>12142, +23765=>12143, +23766=>12144, +23767=>12145, +23768=>12146, +23770=>12147, +23771=>12148, +23772=>12149, +23773=>12150, +23774=>12151, +23775=>12152, +23776=>12153, +23778=>12154, +23779=>12155, +23783=>12156, +23785=>12157, +23787=>12158, +23788=>12159, +23790=>12160, +23791=>12161, +23793=>12162, +23794=>12163, +23795=>12164, +23797=>12165, +23799=>12166, +23800=>12167, +23801=>12168, +23802=>12169, +23804=>12170, +23806=>12171, +23807=>12172, +23808=>12173, +23809=>12174, +23812=>12175, +23813=>12176, +23816=>12177, +23817=>12178, +23818=>12179, +23819=>12180, +23820=>12181, +23823=>12182, +23824=>12183, +23825=>12184, +23826=>12185, +23827=>12186, +23829=>12187, +23832=>12188, +23833=>12189, +23834=>12190, +23836=>12191, +23837=>12192, +23839=>12193, +23840=>12194, +23841=>12195, +23842=>12196, +23843=>12197, +23845=>12198, +23848=>12199, +23850=>12200, +23851=>12201, +23855=>12202, +23856=>12203, +23857=>12204, +23858=>12205, +23859=>12206, +23861=>12207, +23862=>12208, +23863=>12209, +23864=>12210, +23865=>12211, +23866=>12212, +23867=>12213, +23868=>12214, +23871=>12215, +23872=>12216, +23873=>12217, +23874=>12218, +23875=>12219, +23876=>12220, +23877=>12221, +23878=>12222, +23880=>12223, +23881=>12224, +23885=>12225, +23886=>12226, +23887=>12227, +23889=>12228, +23890=>12229, +23891=>12230, +23892=>12231, +23893=>12232, +23894=>12233, +23895=>12234, +23897=>12235, +23898=>12236, +23900=>12237, +23902=>12238, +23903=>12239, +23904=>12240, +23905=>12241, +23906=>12242, +23907=>12243, +23908=>12244, +23909=>12245, +23910=>12246, +23911=>12247, +23912=>12248, +23914=>12249, +23917=>12250, +23918=>12251, +23920=>12252, +23921=>12253, +23922=>12254, +23923=>12255, +23925=>12256, +23926=>12257, +23927=>12258, +23928=>12259, +23929=>12260, +23930=>12261, +23931=>12262, +23932=>12263, +23933=>12264, +23934=>12265, +23935=>12266, +23936=>12267, +23939=>12268, +23941=>12269, +23942=>12270, +23944=>12271, +23945=>12272, +23946=>12273, +23947=>12274, +23948=>12275, +23949=>12276, +23950=>12277, +23951=>12278, +23952=>12279, +23953=>12280, +23954=>12281, +23955=>12282, +23956=>12283, +23957=>12284, +23958=>12285, +23960=>12286, +23962=>12287, +23963=>12288, +23964=>12289, +23966=>12290, +23967=>12291, +23969=>12292, +23970=>12293, +23971=>12294, +23972=>12295, +23973=>12296, +23974=>12297, +23976=>12298, +23977=>12299, +23978=>12300, +23979=>12301, +23980=>12302, +23981=>12303, +23982=>12304, +23983=>12305, +23984=>12306, +23985=>12307, +23986=>12308, +23987=>12309, +23988=>12310, +23989=>12311, +23990=>12312, +23993=>12313, +23995=>12314, +23997=>12315, +23998=>12316, +23999=>12317, +24000=>12318, +24001=>12319, +24002=>12320, +24003=>12321, +24004=>12322, +24006=>12323, +24007=>12324, +24008=>12325, +24009=>12326, +24010=>12327, +24012=>12328, +24014=>12329, +24015=>12330, +24016=>12331, +24017=>12332, +24019=>12333, +24021=>12334, +24022=>12335, +24023=>12336, +24024=>12337, +24025=>12338, +24026=>12339, +24028=>12340, +24031=>12341, +24032=>12342, +24035=>12343, +24036=>12344, +24042=>12345, +24044=>12346, +24045=>12347, +24053=>12348, +24054=>12349, +24056=>12350, +24057=>12351, +24058=>12352, +24059=>12353, +24060=>12354, +24063=>12355, +24064=>12356, +24068=>12357, +24071=>12358, +24073=>12359, +24074=>12360, +24075=>12361, +24077=>12362, +24078=>12363, +24082=>12364, +24083=>12365, +24087=>12366, +24094=>12367, +24095=>12368, +24096=>12369, +24097=>12370, +24098=>12371, +24099=>12372, +24100=>12373, +24104=>12374, +24105=>12375, +24106=>12376, +24108=>12377, +24111=>12378, +24112=>12379, +24114=>12380, +24116=>12381, +24117=>12382, +24121=>12383, +24122=>12384, +24126=>12385, +24127=>12386, +24129=>12387, +24134=>12388, +24135=>12389, +24136=>12390, +24137=>12391, +24138=>12392, +24139=>12393, +24141=>12394, +24142=>12395, +24143=>12396, +24144=>12397, +24145=>12398, +24146=>12399, +24147=>12400, +24150=>12401, +24153=>12402, +24154=>12403, +24156=>12404, +24157=>12405, +24160=>12406, +24164=>12407, +24165=>12408, +24166=>12409, +24167=>12410, +24168=>12411, +24169=>12412, +24170=>12413, +24173=>12414, +24174=>12415, +24175=>12416, +24176=>12417, +24177=>12418, +24181=>12419, +24183=>12420, +24193=>12421, +24194=>12422, +24195=>12423, +24197=>12424, +24200=>12425, +24201=>12426, +24204=>12427, +24205=>12428, +24206=>12429, +24210=>12430, +24216=>12431, +24219=>12432, +24221=>12433, +24225=>12434, +24226=>12435, +24227=>12436, +24228=>12437, +24232=>12438, +24233=>12439, +24234=>12440, +24236=>12441, +24238=>12442, +24239=>12443, +24240=>12444, +24241=>12445, +24242=>12446, +24244=>12447, +24250=>12448, +24251=>12449, +24252=>12450, +24253=>12451, +24255=>12452, +24256=>12453, +24257=>12454, +24258=>12455, +24259=>12456, +24260=>12457, +24261=>12458, +24262=>12459, +24263=>12460, +24264=>12461, +24267=>12462, +24268=>12463, +24269=>12464, +24270=>12465, +24271=>12466, +24272=>12467, +24276=>12468, +24277=>12469, +24279=>12470, +24280=>12471, +24281=>12472, +24282=>12473, +24284=>12474, +24285=>12475, +24286=>12476, +24292=>12477, +24293=>12478, +24294=>12479, +24295=>12480, +24297=>12481, +24299=>12482, +24301=>12483, +24302=>12484, +24303=>12485, +24304=>12486, +24305=>12487, +24306=>12488, +24309=>12489, +24312=>12490, +24313=>12491, +24315=>12492, +24316=>12493, +24317=>12494, +24325=>12495, +24326=>12496, +24327=>12497, +24329=>12498, +24332=>12499, +24333=>12500, +24334=>12501, +24336=>12502, +24338=>12503, +24340=>12504, +24342=>12505, +24345=>12506, +24346=>12507, +24348=>12508, +24349=>12509, +24350=>12510, +24353=>12511, +24354=>12512, +24355=>12513, +24356=>12514, +24360=>12515, +24363=>12516, +24364=>12517, +24366=>12518, +24368=>12519, +24370=>12520, +24372=>12521, +24374=>12522, +24375=>12523, +24376=>12524, +24379=>12525, +24381=>12526, +24382=>12527, +24383=>12528, +24385=>12529, +24386=>12530, +24387=>12531, +24388=>12532, +24389=>12533, +24391=>12534, +24393=>12535, +24394=>12536, +24395=>12537, +24397=>12538, +24399=>12539, +24401=>12540, +24404=>12541, +24410=>12542, +24411=>12543, +24412=>12544, +24414=>12545, +24415=>12546, +24416=>12547, +24419=>12548, +24421=>12549, +24423=>12550, +24424=>12551, +24427=>12552, +24430=>12553, +24431=>12554, +24434=>12555, +24436=>12556, +24437=>12557, +24438=>12558, +24440=>12559, +24442=>12560, +24445=>12561, +24446=>12562, +24447=>12563, +24451=>12564, +24454=>12565, +24461=>12566, +24462=>12567, +24463=>12568, +24467=>12569, +24468=>12570, +24470=>12571, +24474=>12572, +24475=>12573, +24477=>12574, +24479=>12575, +24482=>12576, +24483=>12577, +24484=>12578, +24485=>12579, +24486=>12580, +24487=>12581, +24491=>12582, +24492=>12583, +24495=>12584, +24496=>12585, +24497=>12586, +24498=>12587, +24499=>12588, +24500=>12589, +24502=>12590, +24504=>12591, +24506=>12592, +24507=>12593, +24510=>12594, +24511=>12595, +24512=>12596, +24513=>12597, +24514=>12598, +24519=>12599, +24520=>12600, +24522=>12601, +24523=>12602, +24526=>12603, +24531=>12604, +24532=>12605, +24533=>12606, +24538=>12607, +24539=>12608, +24540=>12609, +24542=>12610, +24543=>12611, +24546=>12612, +24547=>12613, +24549=>12614, +24550=>12615, +24552=>12616, +24553=>12617, +24556=>12618, +24559=>12619, +24560=>12620, +24562=>12621, +24563=>12622, +24564=>12623, +24566=>12624, +24567=>12625, +24569=>12626, +24570=>12627, +24572=>12628, +24583=>12629, +24584=>12630, +24585=>12631, +24587=>12632, +24588=>12633, +24592=>12634, +24593=>12635, +24595=>12636, +24599=>12637, +24600=>12638, +24602=>12639, +24606=>12640, +24607=>12641, +24610=>12642, +24611=>12643, +24612=>12644, +24620=>12645, +24621=>12646, +24622=>12647, +24624=>12648, +24625=>12649, +24626=>12650, +24627=>12651, +24628=>12652, +24630=>12653, +24631=>12654, +24632=>12655, +24633=>12656, +24634=>12657, +24637=>12658, +24638=>12659, +24640=>12660, +24644=>12661, +24645=>12662, +24646=>12663, +24647=>12664, +24648=>12665, +24649=>12666, +24650=>12667, +24652=>12668, +24654=>12669, +24655=>12670, +24657=>12671, +24659=>12672, +24660=>12673, +24662=>12674, +24663=>12675, +24664=>12676, +24667=>12677, +24668=>12678, +24670=>12679, +24671=>12680, +24672=>12681, +24673=>12682, +24677=>12683, +24678=>12684, +24686=>12685, +24689=>12686, +24690=>12687, +24692=>12688, +24693=>12689, +24695=>12690, +24702=>12691, +24704=>12692, +24705=>12693, +24706=>12694, +24709=>12695, +24710=>12696, +24711=>12697, +24712=>12698, +24714=>12699, +24715=>12700, +24718=>12701, +24719=>12702, +24720=>12703, +24721=>12704, +24723=>12705, +24725=>12706, +24727=>12707, +24728=>12708, +24729=>12709, +24732=>12710, +24734=>12711, +24737=>12712, +24738=>12713, +24740=>12714, +24741=>12715, +24743=>12716, +24745=>12717, +24746=>12718, +24750=>12719, +24752=>12720, +24755=>12721, +24759=>12722, +24761=>12723, +24762=>12724, +24765=>12725, +24766=>12726, +24767=>12727, +24768=>12728, +24769=>12729, +24770=>12730, +24771=>12731, +24772=>12732, +24775=>12733, +24776=>12734, +24777=>12735, +24780=>12736, +24781=>12737, +24782=>12738, +24783=>12739, +24784=>12740, +24786=>12741, +24787=>12742, +24788=>12743, +24790=>12744, +24791=>12745, +24793=>12746, +24795=>12747, +24798=>12748, +24802=>12749, +24803=>12750, +24804=>12751, +24805=>12752, +24810=>12753, +24821=>12754, +24823=>12755, +24824=>12756, +24828=>12757, +24829=>12758, +24830=>12759, +24831=>12760, +24834=>12761, +24835=>12762, +24836=>12763, +24837=>12764, +24839=>12765, +24842=>12766, +24843=>12767, +24844=>12768, +24848=>12769, +24849=>12770, +24850=>12771, +24851=>12772, +24852=>12773, +24854=>12774, +24855=>12775, +24856=>12776, +24857=>12777, +24861=>12778, +24862=>12779, +24865=>12780, +24866=>12781, +24869=>12782, +24872=>12783, +24873=>12784, +24874=>12785, +24876=>12786, +24877=>12787, +24878=>12788, +24879=>12789, +24880=>12790, +24881=>12791, +24882=>12792, +24883=>12793, +24885=>12794, +24886=>12795, +24888=>12796, +24889=>12797, +24890=>12798, +24891=>12799, +24892=>12800, +24893=>12801, +24896=>12802, +24897=>12803, +24898=>12804, +24899=>12805, +24900=>12806, +24901=>12807, +24902=>12808, +24903=>12809, +24905=>12810, +24909=>12811, +24911=>12812, +24912=>12813, +24914=>12814, +24915=>12815, +24916=>12816, +24918=>12817, +24919=>12818, +24921=>12819, +24923=>12820, +24924=>12821, +24926=>12822, +24928=>12823, +24929=>12824, +24933=>12825, +24934=>12826, +24937=>12827, +24940=>12828, +24941=>12829, +24943=>12830, +24945=>12831, +24946=>12832, +24948=>12833, +24952=>12834, +24953=>12835, +24954=>12836, +24955=>12837, +24956=>12838, +24957=>12839, +24958=>12840, +24959=>12841, +24960=>12842, +24961=>12843, +24963=>12844, +24964=>12845, +24965=>12846, +24966=>12847, +24967=>12848, +24968=>12849, +24969=>12850, +24972=>12851, +24973=>12852, +24975=>12853, +24979=>12854, +24981=>12855, +24982=>12856, +24983=>12857, +24984=>12858, +24985=>12859, +24987=>12860, +24988=>12861, +24990=>12862, +24991=>12863, +24992=>12864, +24993=>12865, +24994=>12866, +24995=>12867, +24997=>12868, +24998=>12869, +25002=>12870, +25005=>12871, +25007=>12872, +25008=>12873, +25009=>12874, +25011=>12875, +25012=>12876, +25013=>12877, +25016=>12878, +25017=>12879, +25018=>12880, +25019=>12881, +25020=>12882, +25021=>12883, +25023=>12884, +25024=>12885, +25025=>12886, +25027=>12887, +25028=>12888, +25029=>12889, +25030=>12890, +25037=>12891, +25038=>12892, +25039=>12893, +25040=>12894, +25043=>12895, +25045=>12896, +25046=>12897, +25047=>12898, +25048=>12899, +25049=>12900, +25050=>12901, +25051=>12902, +25052=>12903, +25053=>12904, +25056=>12905, +25057=>12906, +25058=>12907, +25060=>12908, +25061=>12909, +25063=>12910, +25065=>12911, +25066=>12912, +25067=>12913, +25068=>12914, +25069=>12915, +25070=>12916, +25071=>12917, +25072=>12918, +25073=>12919, +25075=>12920, +25076=>12921, +25081=>12922, +25083=>12923, +25085=>12924, +25089=>12925, +25090=>12926, +25091=>12927, +25092=>12928, +25093=>12929, +25097=>12930, +25107=>12931, +25113=>12932, +25116=>12933, +25117=>12934, +25118=>12935, +25120=>12936, +25123=>12937, +25126=>12938, +25128=>12939, +25129=>12940, +25131=>12941, +25133=>12942, +25135=>12943, +25137=>12944, +25141=>12945, +12094=>12946, +25142=>12946, +25144=>12947, +25145=>12948, +25146=>12949, +25147=>12950, +25148=>12951, +25154=>12952, +25156=>12953, +25157=>12954, +25158=>12955, +25162=>12956, +25167=>12957, +25168=>12958, +25173=>12959, +25174=>12960, +25175=>12961, +25177=>12962, +25178=>12963, +25180=>12964, +25181=>12965, +25182=>12966, +25183=>12967, +25184=>12968, +25185=>12969, +25186=>12970, +25188=>12971, +25189=>12972, +25192=>12973, +25201=>12974, +25202=>12975, +25204=>12976, +25205=>12977, +25207=>12978, +25208=>12979, +25210=>12980, +25211=>12981, +25213=>12982, +25217=>12983, +25218=>12984, +25219=>12985, +25221=>12986, +25222=>12987, +25223=>12988, +25224=>12989, +25227=>12990, +25228=>12991, +25229=>12992, +25230=>12993, +25231=>12994, +25232=>12995, +25236=>12996, +25241=>12997, +25244=>12998, +25245=>12999, +25246=>13000, +25251=>13001, +25254=>13002, +25255=>13003, +25257=>13004, +25258=>13005, +25261=>13006, +25262=>13007, +25263=>13008, +25264=>13009, +25266=>13010, +25267=>13011, +25268=>13012, +25270=>13013, +25271=>13014, +25272=>13015, +25274=>13016, +25278=>13017, +25280=>13018, +25281=>13019, +25283=>13020, +25291=>13021, +25295=>13022, +25297=>13023, +25301=>13024, +25309=>13025, +25310=>13026, +25312=>13027, +25313=>13028, +25316=>13029, +25322=>13030, +25323=>13031, +25328=>13032, +25330=>13033, +25333=>13034, +25336=>13035, +25337=>13036, +25338=>13037, +25339=>13038, +25344=>13039, +25347=>13040, +25348=>13041, +25349=>13042, +25350=>13043, +25354=>13044, +25355=>13045, +25356=>13046, +25357=>13047, +25359=>13048, +25360=>13049, +25362=>13050, +25363=>13051, +25364=>13052, +25365=>13053, +25367=>13054, +25368=>13055, +25369=>13056, +25372=>13057, +25382=>13058, +25383=>13059, +25385=>13060, +25388=>13061, +25389=>13062, +25390=>13063, +25392=>13064, +25393=>13065, +25395=>13066, +25396=>13067, +25397=>13068, +25398=>13069, +25399=>13070, +25400=>13071, +25403=>13072, +25404=>13073, +25407=>13074, +25408=>13075, +25409=>13076, +25412=>13077, +25415=>13078, +25416=>13079, +25418=>13080, +25425=>13081, +25426=>13082, +25427=>13083, +25428=>13084, +25430=>13085, +25431=>13086, +25432=>13087, +25433=>13088, +25434=>13089, +25435=>13090, +25436=>13091, +25437=>13092, +25440=>13093, +25444=>13094, +25445=>13095, +25446=>13096, +25450=>13097, +25452=>13098, +25455=>13099, +25456=>13100, +25459=>13101, +25460=>13102, +25461=>13103, +25464=>13104, +25465=>13105, +25468=>13106, +25469=>13107, +25470=>13108, +25471=>13109, +25473=>13110, +25477=>13111, +25478=>13112, +25483=>13113, +25485=>13114, +25489=>13115, +25491=>13116, +25492=>13117, +25493=>13118, +25495=>13119, +25497=>13120, +25498=>13121, +25499=>13122, +25500=>13123, +25501=>13124, +25502=>13125, +25503=>13126, +25505=>13127, +25508=>13128, +25510=>13129, +25515=>13130, +25519=>13131, +25521=>13132, +25522=>13133, +25525=>13134, +25526=>13135, +25529=>13136, +25531=>13137, +25533=>13138, +25535=>13139, +25537=>13140, +25538=>13141, +25539=>13142, +25541=>13143, +25543=>13144, +25544=>13145, +25546=>13146, +25547=>13147, +25548=>13148, +25553=>13149, +25555=>13150, +25556=>13151, +25557=>13152, +25559=>13153, +25560=>13154, +25561=>13155, +25563=>13156, +25564=>13157, +25565=>13158, +25567=>13159, +25570=>13160, +25572=>13161, +25573=>13162, +25574=>13163, +25575=>13164, +25576=>13165, +25579=>13166, +25580=>13167, +25583=>13168, +25584=>13169, +25585=>13170, +25587=>13171, +25589=>13172, +25591=>13173, +25593=>13174, +25594=>13175, +25595=>13176, +25596=>13177, +25598=>13178, +25603=>13179, +25604=>13180, +25606=>13181, +25607=>13182, +25608=>13183, +25609=>13184, +25610=>13185, +25614=>13186, +25617=>13187, +25618=>13188, +25621=>13189, +25622=>13190, +25624=>13191, +25625=>13192, +25626=>13193, +25629=>13194, +25631=>13195, +25634=>13196, +25635=>13197, +25636=>13198, +25637=>13199, +25639=>13200, +25640=>13201, +25641=>13202, +25643=>13203, +25646=>13204, +25647=>13205, +25648=>13206, +25649=>13207, +25650=>13208, +25651=>13209, +25653=>13210, +25655=>13211, +25656=>13212, +25657=>13213, +25659=>13214, +25660=>13215, +25662=>13216, +25664=>13217, +25666=>13218, +25667=>13219, +25673=>13220, +25675=>13221, +25676=>13222, +25677=>13223, +25678=>13224, +25679=>13225, +25680=>13226, +25683=>13227, +25685=>13228, +25686=>13229, +25687=>13230, +25689=>13231, +25690=>13232, +25691=>13233, +25693=>13234, +25696=>13235, +25697=>13236, +25698=>13237, +25699=>13238, +25700=>13239, +25701=>13240, +25702=>13241, +25704=>13242, +25706=>13243, +25707=>13244, +25708=>13245, +25710=>13246, +25712=>13247, +25713=>13248, +25714=>13249, +25716=>13250, +25717=>13251, +25719=>13252, +25724=>13253, +25725=>13254, +25726=>13255, +25727=>13256, +25728=>13257, +25729=>13258, +25731=>13259, +25734=>13260, +25737=>13261, +25738=>13262, +25739=>13263, +25740=>13264, +25741=>13265, +25742=>13266, +25743=>13267, +25744=>13268, +25748=>13269, +25751=>13270, +25752=>13271, +25754=>13272, +25755=>13273, +25756=>13274, +25757=>13275, +25760=>13276, +25761=>13277, +25762=>13278, +25766=>13279, +25767=>13280, +25768=>13281, +25770=>13282, +25775=>13283, +25777=>13284, +25780=>13285, +25782=>13286, +25785=>13287, +25789=>13288, +25795=>13289, +25798=>13290, +25800=>13291, +25801=>13292, +25804=>13293, +25807=>13294, +25809=>13295, +25811=>13296, +25813=>13297, +25814=>13298, +25817=>13299, +25819=>13300, +25820=>13301, +25821=>13302, +25823=>13303, +25825=>13304, +25827=>13305, +25829=>13306, +25831=>13307, +25832=>13308, +25833=>13309, +25834=>13310, +25835=>13311, +25837=>13312, +25838=>13313, +25843=>13314, +25845=>13315, +25846=>13316, +25848=>13317, +25849=>13318, +25853=>13319, +25855=>13320, +25857=>13321, +25858=>13322, +25859=>13323, +25861=>13324, +25863=>13325, +25864=>13326, +25866=>13327, +25867=>13328, +25868=>13329, +25869=>13330, +25870=>13331, +25872=>13332, +25873=>13333, +25875=>13334, +25877=>13335, +25879=>13336, +25882=>13337, +25884=>13338, +25886=>13339, +25887=>13340, +25888=>13341, +25889=>13342, +25894=>13343, +25895=>13344, +25896=>13345, +25897=>13346, +25901=>13347, +25904=>13348, +25905=>13349, +25906=>13350, +25907=>13351, +25911=>13352, +25914=>13353, +25916=>13354, +25917=>13355, +25920=>13356, +25921=>13357, +25922=>13358, +25923=>13359, +25924=>13360, +25926=>13361, +25927=>13362, +25930=>13363, +25931=>13364, +25933=>13365, +25934=>13366, +25936=>13367, +25938=>13368, +25939=>13369, +25940=>13370, +25944=>13371, +25946=>13372, +25948=>13373, +25951=>13374, +25952=>13375, +25953=>13376, +25956=>13377, +25957=>13378, +25959=>13379, +25960=>13380, +25961=>13381, +25962=>13382, +25965=>13383, +25966=>13384, +25967=>13385, +25969=>13386, +25971=>13387, +25974=>13388, +25977=>13389, +25978=>13390, +25979=>13391, +25980=>13392, +25981=>13393, +25982=>13394, +25983=>13395, +25984=>13396, +25985=>13397, +25988=>13398, +25989=>13399, +25990=>13400, +25992=>13401, +25993=>13402, +25994=>13403, +25997=>13404, +25998=>13405, +25999=>13406, +26002=>13407, +26004=>13408, +26006=>13409, +26008=>13410, +26010=>13411, +26013=>13412, +26014=>13413, +26016=>13414, +26018=>13415, +26019=>13416, +26022=>13417, +26024=>13418, +26026=>13419, +26030=>13420, +26033=>13421, +26034=>13422, +26035=>13423, +26036=>13424, +26037=>13425, +26038=>13426, +26040=>13427, +26042=>13428, +26043=>13429, +26046=>13430, +26047=>13431, +26048=>13432, +26050=>13433, +26055=>13434, +26056=>13435, +26057=>13436, +26058=>13437, +26061=>13438, +26064=>13439, +26065=>13440, +26067=>13441, +26068=>13442, +26069=>13443, +26072=>13444, +26073=>13445, +26074=>13446, +26075=>13447, +26076=>13448, +26077=>13449, +26078=>13450, +26079=>13451, +26081=>13452, +26083=>13453, +26084=>13454, +26090=>13455, +26091=>13456, +26098=>13457, +26099=>13458, +26100=>13459, +26101=>13460, +26104=>13461, +26105=>13462, +26107=>13463, +26108=>13464, +26109=>13465, +26110=>13466, +26111=>13467, +26113=>13468, +26116=>13469, +26117=>13470, +26119=>13471, +26120=>13472, +26121=>13473, +26123=>13474, +26125=>13475, +26128=>13476, +26129=>13477, +26130=>13478, +26134=>13479, +26135=>13480, +26136=>13481, +26138=>13482, +26139=>13483, +26140=>13484, +26142=>13485, +26145=>13486, +26146=>13487, +26147=>13488, +26148=>13489, +26150=>13490, +26153=>13491, +26154=>13492, +26155=>13493, +26156=>13494, +26158=>13495, +26160=>13496, +26162=>13497, +26163=>13498, +26167=>13499, +26168=>13500, +26169=>13501, +26170=>13502, +26171=>13503, +26173=>13504, +26175=>13505, +26176=>13506, +26180=>13507, +26181=>13508, +26182=>13509, +26183=>13510, +26184=>13511, +26185=>13512, +26186=>13513, +26189=>13514, +26190=>13515, +26192=>13516, +26193=>13517, +26200=>13518, +26201=>13519, +26203=>13520, +26204=>13521, +26206=>13522, +26208=>13523, +26210=>13524, +26211=>13525, +26213=>13526, +26215=>13527, +26217=>13528, +26218=>13529, +26219=>13530, +26220=>13531, +26221=>13532, +26225=>13533, +26226=>13534, +26227=>13535, +26229=>13536, +26232=>13537, +26233=>13538, +26235=>13539, +26236=>13540, +26237=>13541, +26239=>13542, +26240=>13543, +26241=>13544, +26243=>13545, +26245=>13546, +26246=>13547, +26250=>13548, +26251=>13549, +26253=>13550, +26254=>13551, +26255=>13552, +26256=>13553, +26258=>13554, +26259=>13555, +26260=>13556, +26261=>13557, +26264=>13558, +26265=>13559, +26266=>13560, +26267=>13561, +26268=>13562, +26270=>13563, +26271=>13564, +26272=>13565, +26273=>13566, +26275=>13567, +26276=>13568, +26277=>13569, +26278=>13570, +26281=>13571, +26282=>13572, +26284=>13573, +26285=>13574, +26287=>13575, +26288=>13576, +26289=>13577, +26290=>13578, +26291=>13579, +26293=>13580, +26294=>13581, +26295=>13582, +26296=>13583, +26298=>13584, +26299=>13585, +26300=>13586, +26301=>13587, +26303=>13588, +26304=>13589, +26305=>13590, +26306=>13591, +26307=>13592, +26309=>13593, +26312=>13594, +26314=>13595, +26315=>13596, +26316=>13597, +26317=>13598, +26318=>13599, +26319=>13600, +26320=>13601, +26321=>13602, +26322=>13603, +26323=>13604, +26324=>13605, +26325=>13606, +26327=>13607, +26328=>13608, +26330=>13609, +26334=>13610, +26335=>13611, +26337=>13612, +26338=>13613, +26339=>13614, +26340=>13615, +26341=>13616, +26343=>13617, +26344=>13618, +26346=>13619, +26347=>13620, +26349=>13621, +26350=>13622, +26351=>13623, +26353=>13624, +26357=>13625, +26358=>13626, +26362=>13627, +26363=>13628, +26365=>13629, +26369=>13630, +26370=>13631, +26372=>13632, +26373=>13633, +26374=>13634, +26375=>13635, +26380=>13636, +26382=>13637, +26383=>13638, +26385=>13639, +26386=>13640, +26387=>13641, +26390=>13642, +26392=>13643, +26393=>13644, +26394=>13645, +26396=>13646, +26398=>13647, +26400=>13648, +26401=>13649, +26402=>13650, +26403=>13651, +26404=>13652, +26405=>13653, +26409=>13654, +26414=>13655, +26416=>13656, +26418=>13657, +26419=>13658, +26422=>13659, +26423=>13660, +26424=>13661, +26425=>13662, +26427=>13663, +26428=>13664, +26430=>13665, +26431=>13666, +26433=>13667, +26436=>13668, +26437=>13669, +26439=>13670, +26442=>13671, +26443=>13672, +26445=>13673, +26450=>13674, +26452=>13675, +26453=>13676, +26455=>13677, +26456=>13678, +26457=>13679, +26458=>13680, +26459=>13681, +26461=>13682, +26466=>13683, +26467=>13684, +26468=>13685, +26470=>13686, +26471=>13687, +26475=>13688, +26476=>13689, +26478=>13690, +26484=>13691, +26486=>13692, +26488=>13693, +26489=>13694, +26490=>13695, +26491=>13696, +26493=>13697, +26496=>13698, +26498=>13699, +26499=>13700, +26501=>13701, +26502=>13702, +26504=>13703, +26506=>13704, +26508=>13705, +26509=>13706, +26510=>13707, +26511=>13708, +26513=>13709, +26514=>13710, +26515=>13711, +26516=>13712, +26518=>13713, +26521=>13714, +26523=>13715, +26527=>13716, +26528=>13717, +26529=>13718, +26532=>13719, +26534=>13720, +26537=>13721, +26540=>13722, +26542=>13723, +26545=>13724, +26546=>13725, +26548=>13726, +26553=>13727, +26554=>13728, +26555=>13729, +26556=>13730, +26557=>13731, +26558=>13732, +26559=>13733, +26560=>13734, +26562=>13735, +26565=>13736, +26566=>13737, +26567=>13738, +26568=>13739, +26569=>13740, +26570=>13741, +26571=>13742, +26572=>13743, +26573=>13744, +26574=>13745, +26581=>13746, +26582=>13747, +26583=>13748, +26587=>13749, +26591=>13750, +26593=>13751, +26595=>13752, +26596=>13753, +26598=>13754, +26599=>13755, +26600=>13756, +26602=>13757, +26603=>13758, +26605=>13759, +26606=>13760, +26610=>13761, +26613=>13762, +26614=>13763, +26615=>13764, +26616=>13765, +26617=>13766, +26618=>13767, +26619=>13768, +26620=>13769, +26622=>13770, +26625=>13771, +26626=>13772, +26627=>13773, +26628=>13774, +26630=>13775, +26637=>13776, +26640=>13777, +26642=>13778, +26644=>13779, +26645=>13780, +26648=>13781, +26649=>13782, +26650=>13783, +26651=>13784, +26652=>13785, +26654=>13786, +26655=>13787, +26656=>13788, +26658=>13789, +26659=>13790, +26660=>13791, +26661=>13792, +26662=>13793, +26663=>13794, +26664=>13795, +26667=>13796, +26668=>13797, +26669=>13798, +26670=>13799, +26671=>13800, +26672=>13801, +26673=>13802, +26676=>13803, +26677=>13804, +26678=>13805, +26682=>13806, +26683=>13807, +26687=>13808, +26695=>13809, +26699=>13810, +26701=>13811, +26703=>13812, +26706=>13813, +26710=>13814, +26711=>13815, +26712=>13816, +26713=>13817, +26714=>13818, +26715=>13819, +26716=>13820, +26717=>13821, +26718=>13822, +26719=>13823, +26730=>13824, +26732=>13825, +26733=>13826, +26734=>13827, +26735=>13828, +26736=>13829, +26737=>13830, +26738=>13831, +26739=>13832, +26741=>13833, +26744=>13834, +26745=>13835, +26746=>13836, +26747=>13837, +26748=>13838, +26749=>13839, +26750=>13840, +26751=>13841, +26752=>13842, +26754=>13843, +26756=>13844, +26759=>13845, +26760=>13846, +26761=>13847, +26762=>13848, +26763=>13849, +26764=>13850, +26765=>13851, +26766=>13852, +26768=>13853, +26769=>13854, +26770=>13855, +26772=>13856, +26773=>13857, +26774=>13858, +26777=>13859, +26778=>13860, +26779=>13861, +26780=>13862, +26782=>13863, +26784=>13864, +26785=>13865, +26787=>13866, +26788=>13867, +26789=>13868, +26793=>13869, +26794=>13870, +26795=>13871, +26796=>13872, +26798=>13873, +26801=>13874, +26802=>13875, +26804=>13876, +26806=>13877, +26807=>13878, +26808=>13879, +26809=>13880, +26810=>13881, +26811=>13882, +26812=>13883, +26813=>13884, +26814=>13885, +26815=>13886, +26817=>13887, +26819=>13888, +26820=>13889, +26821=>13890, +26822=>13891, +26823=>13892, +26824=>13893, +26826=>13894, +26828=>13895, +26830=>13896, +26831=>13897, +26832=>13898, +26833=>13899, +26835=>13900, +26836=>13901, +26841=>13902, +26843=>13903, +26844=>13904, +26845=>13905, +26846=>13906, +26849=>13907, +26850=>13908, +26852=>13909, +26853=>13910, +26854=>13911, +26856=>13912, +26857=>13913, +26858=>13914, +26859=>13915, +26860=>13916, +26861=>13917, +26863=>13918, +26866=>13919, +26867=>13920, +26868=>13921, +26870=>13922, +26871=>13923, +26872=>13924, +26875=>13925, +26877=>13926, +26878=>13927, +26879=>13928, +26880=>13929, +26882=>13930, +26883=>13931, +26884=>13932, +26886=>13933, +26887=>13934, +26888=>13935, +26889=>13936, +26890=>13937, +26892=>13938, +26897=>13939, +26899=>13940, +26900=>13941, +26901=>13942, +26902=>13943, +26903=>13944, +26904=>13945, +26905=>13946, +26906=>13947, +26907=>13948, +26908=>13949, +26909=>13950, +26910=>13951, +26913=>13952, +26914=>13953, +26915=>13954, +26917=>13955, +26918=>13956, +26919=>13957, +26920=>13958, +26921=>13959, +26922=>13960, +26923=>13961, +26924=>13962, +26926=>13963, +26927=>13964, +26929=>13965, +26930=>13966, +26931=>13967, +26933=>13968, +26934=>13969, +26935=>13970, +26936=>13971, +26938=>13972, +26939=>13973, +26940=>13974, +26942=>13975, +26944=>13976, +26945=>13977, +26947=>13978, +26948=>13979, +26949=>13980, +26950=>13981, +26951=>13982, +26952=>13983, +26953=>13984, +26955=>13985, +26956=>13986, +26957=>13987, +26958=>13988, +26959=>13989, +26960=>13990, +26961=>13991, +26962=>13992, +26965=>13993, +26966=>13994, +26968=>13995, +26969=>13996, +26971=>13997, +26972=>13998, +26975=>13999, +26977=>14000, +26978=>14001, +26980=>14002, +26981=>14003, +26983=>14004, +26985=>14005, +26986=>14006, +26988=>14007, +26991=>14008, +26992=>14009, +26994=>14010, +26995=>14011, +26996=>14012, +26998=>14013, +27002=>14014, +27003=>14015, +27005=>14016, +27006=>14017, +27007=>14018, +27009=>14019, +27011=>14020, +27013=>14021, +27018=>14022, +27019=>14023, +27020=>14024, +27022=>14025, +27023=>14026, +27024=>14027, +27025=>14028, +27026=>14029, +27027=>14030, +27030=>14031, +27031=>14032, +27033=>14033, +27034=>14034, +27037=>14035, +27038=>14036, +27039=>14037, +27040=>14038, +27041=>14039, +27042=>14040, +27043=>14041, +27044=>14042, +27045=>14043, +27046=>14044, +27049=>14045, +27052=>14046, +27055=>14047, +27056=>14048, +27058=>14049, +27059=>14050, +27061=>14051, +27062=>14052, +27064=>14053, +27065=>14054, +27066=>14055, +27068=>14056, +27069=>14057, +27070=>14058, +27072=>14059, +27074=>14060, +27075=>14061, +27076=>14062, +27077=>14063, +27078=>14064, +27079=>14065, +27080=>14066, +27081=>14067, +27087=>14068, +27089=>14069, +27090=>14070, +27091=>14071, +27093=>14072, +27094=>14073, +27095=>14074, +27096=>14075, +27097=>14076, +27098=>14077, +27100=>14078, +27101=>14079, +27102=>14080, +27105=>14081, +27106=>14082, +27107=>14083, +27108=>14084, +27109=>14085, +27110=>14086, +27112=>14087, +27113=>14088, +27114=>14089, +27115=>14090, +27116=>14091, +27118=>14092, +27119=>14093, +27120=>14094, +27121=>14095, +27124=>14096, +27125=>14097, +27126=>14098, +27127=>14099, +27128=>14100, +27129=>14101, +27130=>14102, +27131=>14103, +27132=>14104, +27134=>14105, +27136=>14106, +27139=>14107, +27140=>14108, +27142=>14109, +27143=>14110, +27144=>14111, +27145=>14112, +27147=>14113, +27148=>14114, +27149=>14115, +27150=>14116, +27151=>14117, +27152=>14118, +27153=>14119, +27154=>14120, +27156=>14121, +27157=>14122, +27158=>14123, +27162=>14124, +27163=>14125, +27164=>14126, +27165=>14127, +27168=>14128, +27170=>14129, +27172=>14130, +27173=>14131, +27174=>14132, +27175=>14133, +27177=>14134, +27179=>14135, +27180=>14136, +27181=>14137, +27182=>14138, +27184=>14139, +27186=>14140, +27187=>14141, +27188=>14142, +27190=>14143, +27191=>14144, +27195=>14145, +27196=>14146, +27199=>14147, +27200=>14148, +27201=>14149, +27202=>14150, +27203=>14151, +27205=>14152, +27206=>14153, +27209=>14154, +27210=>14155, +27212=>14156, +27213=>14157, +27214=>14158, +27215=>14159, +27217=>14160, +27218=>14161, +27219=>14162, +27220=>14163, +27221=>14164, +27222=>14165, +27223=>14166, +27226=>14167, +27228=>14168, +27229=>14169, +27230=>14170, +27232=>14171, +27235=>14172, +27236=>14173, +27238=>14174, +27239=>14175, +27240=>14176, +27241=>14177, +27242=>14178, +27243=>14179, +27244=>14180, +27245=>14181, +27246=>14182, +27247=>14183, +27248=>14184, +27250=>14185, +27251=>14186, +27252=>14187, +27253=>14188, +27254=>14189, +27255=>14190, +27256=>14191, +27258=>14192, +27259=>14193, +27261=>14194, +27262=>14195, +27263=>14196, +27265=>14197, +27266=>14198, +27267=>14199, +27269=>14200, +27270=>14201, +27271=>14202, +27272=>14203, +27274=>14204, +27275=>14205, +27276=>14206, +27277=>14207, +27279=>14208, +27282=>14209, +27283=>14210, +27285=>14211, +27286=>14212, +27288=>14213, +27289=>14214, +27290=>14215, +27291=>14216, +27293=>14217, +27294=>14218, +27295=>14219, +27297=>14220, +27300=>14221, +27301=>14222, +27302=>14223, +27303=>14224, +27304=>14225, +27306=>14226, +27309=>14227, +27310=>14228, +27312=>14229, +27313=>14230, +27314=>14231, +27316=>14232, +27317=>14233, +27318=>14234, +27319=>14235, +27321=>14236, +27322=>14237, +27324=>14238, +27325=>14239, +27326=>14240, +27327=>14241, +27328=>14242, +27329=>14243, +27330=>14244, +27332=>14245, +27333=>14246, +27334=>14247, +27335=>14248, +27336=>14249, +27337=>14250, +27338=>14251, +27339=>14252, +27340=>14253, +27341=>14254, +27342=>14255, +27343=>14256, +27344=>14257, +27345=>14258, +27346=>14259, +27348=>14260, +27349=>14261, +27350=>14262, +27351=>14263, +27352=>14264, +27353=>14265, +27356=>14266, +27360=>14267, +27361=>14268, +27362=>14269, +27363=>14270, +27364=>14271, +27365=>14272, +27366=>14273, +27369=>14274, +27371=>14275, +27373=>14276, +27374=>14277, +27375=>14278, +27376=>14279, +27377=>14280, +27378=>14281, +27380=>14282, +27381=>14283, +27382=>14284, +27383=>14285, +27385=>14286, +27386=>14287, +27388=>14288, +27389=>14289, +27390=>14290, +27391=>14291, +27392=>14292, +27393=>14293, +27394=>14294, +27395=>14295, +27397=>14296, +27398=>14297, +27399=>14298, +27400=>14299, +27401=>14300, +27403=>14301, +27404=>14302, +27405=>14303, +27406=>14304, +27408=>14305, +27409=>14306, +27411=>14307, +27412=>14308, +27413=>14309, +27415=>14310, +27416=>14311, +27417=>14312, +27418=>14313, +27419=>14314, +27420=>14315, +27421=>14316, +27423=>14317, +27429=>14318, +27430=>14319, +27432=>14320, +27433=>14321, +27434=>14322, +27435=>14323, +27436=>14324, +27437=>14325, +27438=>14326, +27439=>14327, +27440=>14328, +27441=>14329, +27443=>14330, +27444=>14331, +27445=>14332, +27446=>14333, +27448=>14334, +27451=>14335, +27452=>14336, +27455=>14337, +27456=>14338, +27457=>14339, +27458=>14340, +27460=>14341, +27461=>14342, +27464=>14343, +27466=>14344, +27467=>14345, +27469=>14346, +27470=>14347, +27471=>14348, +27473=>14349, +27474=>14350, +27475=>14351, +27476=>14352, +27477=>14353, +27478=>14354, +27479=>14355, +27480=>14356, +27482=>14357, +27483=>14358, +27484=>14359, +27485=>14360, +27486=>14361, +27488=>14362, +27496=>14363, +27497=>14364, +27499=>14365, +27500=>14366, +27501=>14367, +27502=>14368, +27503=>14369, +27504=>14370, +27505=>14371, +27507=>14372, +27508=>14373, +27509=>14374, +27510=>14375, +27514=>14376, +27517=>14377, +27518=>14378, +27519=>14379, +27520=>14380, +27525=>14381, +27528=>14382, +27532=>14383, +27534=>14384, +27535=>14385, +27536=>14386, +27537=>14387, +27540=>14388, +27541=>14389, +27543=>14390, +27545=>14391, +27548=>14392, +27549=>14393, +27551=>14394, +27552=>14395, +27554=>14396, +27555=>14397, +27557=>14398, +27558=>14399, +27559=>14400, +27560=>14401, +27561=>14402, +27564=>14403, +27565=>14404, +27568=>14405, +27569=>14406, +27574=>14407, +27576=>14408, +27577=>14409, +27580=>14410, +27581=>14411, +27582=>14412, +27584=>14413, +27587=>14414, +27588=>14415, +27591=>14416, +27592=>14417, +27593=>14418, +27594=>14419, +27596=>14420, +27598=>14421, +27600=>14422, +27601=>14423, +27608=>14424, +27610=>14425, +27612=>14426, +27613=>14427, +27614=>14428, +27615=>14429, +27616=>14430, +27618=>14431, +27619=>14432, +27620=>14433, +27621=>14434, +27622=>14435, +27623=>14436, +27624=>14437, +27625=>14438, +27628=>14439, +27629=>14440, +27630=>14441, +27632=>14442, +27633=>14443, +27634=>14444, +27636=>14445, +27638=>14446, +27639=>14447, +27640=>14448, +27642=>14449, +27643=>14450, +27644=>14451, +27646=>14452, +27648=>14453, +27649=>14454, +27650=>14455, +27651=>14456, +27652=>14457, +27657=>14458, +27658=>14459, +27659=>14460, +27662=>14461, +27666=>14462, +27671=>14463, +27676=>14464, +27677=>14465, +27678=>14466, +27680=>14467, +27685=>14468, +27693=>14469, +27697=>14470, +27699=>14471, +27702=>14472, +27703=>14473, +27705=>14474, +27706=>14475, +27707=>14476, +27708=>14477, +27710=>14478, +27711=>14479, +27715=>14480, +27716=>14481, +27717=>14482, +27720=>14483, +27723=>14484, +27724=>14485, +27725=>14486, +27726=>14487, +27727=>14488, +27729=>14489, +27730=>14490, +27731=>14491, +27734=>14492, +27736=>14493, +27737=>14494, +27738=>14495, +27746=>14496, +27747=>14497, +27749=>14498, +27750=>14499, +27751=>14500, +27755=>14501, +27756=>14502, +27757=>14503, +27758=>14504, +27759=>14505, +27761=>14506, +27763=>14507, +27765=>14508, +27767=>14509, +27768=>14510, +27770=>14511, +27771=>14512, +27772=>14513, +27775=>14514, +27776=>14515, +27780=>14516, +27783=>14517, +27786=>14518, +27787=>14519, +27789=>14520, +27790=>14521, +27793=>14522, +27794=>14523, +27797=>14524, +27798=>14525, +27799=>14526, +27800=>14527, +27802=>14528, +27804=>14529, +27805=>14530, +27806=>14531, +27808=>14532, +27810=>14533, +27816=>14534, +27820=>14535, +27823=>14536, +27824=>14537, +27828=>14538, +27829=>14539, +27830=>14540, +27831=>14541, +27834=>14542, +27840=>14543, +27841=>14544, +27842=>14545, +27843=>14546, +27846=>14547, +27847=>14548, +27848=>14549, +27851=>14550, +27853=>14551, +27854=>14552, +27855=>14553, +27857=>14554, +27858=>14555, +27864=>14556, +27865=>14557, +27866=>14558, +27868=>14559, +27869=>14560, +27871=>14561, +27876=>14562, +27878=>14563, +27879=>14564, +27881=>14565, +27884=>14566, +27885=>14567, +27890=>14568, +27892=>14569, +27897=>14570, +27903=>14571, +27904=>14572, +27906=>14573, +27907=>14574, +27909=>14575, +27910=>14576, +27912=>14577, +27913=>14578, +27914=>14579, +27917=>14580, +27919=>14581, +27920=>14582, +27921=>14583, +27923=>14584, +27924=>14585, +27925=>14586, +27926=>14587, +27928=>14588, +27932=>14589, +27933=>14590, +27935=>14591, +27936=>14592, +27937=>14593, +27938=>14594, +27939=>14595, +27940=>14596, +27942=>14597, +27944=>14598, +27945=>14599, +27948=>14600, +27949=>14601, +27951=>14602, +27952=>14603, +27956=>14604, +27958=>14605, +27959=>14606, +27960=>14607, +27962=>14608, +27967=>14609, +27968=>14610, +27970=>14611, +27972=>14612, +27977=>14613, +27980=>14614, +27984=>14615, +27989=>14616, +27990=>14617, +27991=>14618, +27992=>14619, +27995=>14620, +27997=>14621, +27999=>14622, +28001=>14623, +28002=>14624, +28004=>14625, +28005=>14626, +28007=>14627, +28008=>14628, +28011=>14629, +28012=>14630, +28013=>14631, +28016=>14632, +28017=>14633, +28018=>14634, +28019=>14635, +28021=>14636, +28022=>14637, +28026=>14638, +28027=>14639, +28029=>14640, +28030=>14641, +28031=>14642, +28032=>14643, +28033=>14644, +28035=>14645, +28036=>14646, +28038=>14647, +28042=>14648, +28043=>14649, +28045=>14650, +28047=>14651, +28048=>14652, +28050=>14653, +28054=>14654, +28055=>14655, +28056=>14656, +28057=>14657, +28058=>14658, +28060=>14659, +28066=>14660, +28069=>14661, +28076=>14662, +28077=>14663, +28080=>14664, +28081=>14665, +28083=>14666, +28084=>14667, +28086=>14668, +28087=>14669, +28089=>14670, +28090=>14671, +28091=>14672, +28092=>14673, +28093=>14674, +28094=>14675, +28097=>14676, +28098=>14677, +28099=>14678, +28104=>14679, +28105=>14680, +28106=>14681, +28109=>14682, +28110=>14683, +28111=>14684, +28112=>14685, +28114=>14686, +28115=>14687, +28116=>14688, +28117=>14689, +28119=>14690, +28122=>14691, +28123=>14692, +28124=>14693, +28127=>14694, +28130=>14695, +28131=>14696, +28133=>14697, +28135=>14698, +28136=>14699, +28137=>14700, +28141=>14701, +28143=>14702, +28144=>14703, +28146=>14704, +28148=>14705, +28152=>14706, +28157=>14707, +28158=>14708, +28159=>14709, +28160=>14710, +28161=>14711, +28162=>14712, +28163=>14713, +28164=>14714, +28166=>14715, +28167=>14716, +28168=>14717, +28169=>14718, +28171=>14719, +28175=>14720, +28178=>14721, +28179=>14722, +28181=>14723, +28184=>14724, +28185=>14725, +28187=>14726, +28188=>14727, +28190=>14728, +28191=>14729, +28194=>14730, +28199=>14731, +28200=>14732, +28202=>14733, +28206=>14734, +28208=>14735, +28209=>14736, +28211=>14737, +28213=>14738, +28214=>14739, +28215=>14740, +28217=>14741, +28219=>14742, +28220=>14743, +28221=>14744, +28223=>14745, +28224=>14746, +28225=>14747, +28226=>14748, +28229=>14749, +28230=>14750, +28231=>14751, +28232=>14752, +28233=>14753, +28234=>14754, +28235=>14755, +28236=>14756, +28239=>14757, +28240=>14758, +28241=>14759, +28242=>14760, +28245=>14761, +28247=>14762, +28249=>14763, +28250=>14764, +28252=>14765, +28253=>14766, +28256=>14767, +28257=>14768, +28258=>14769, +28259=>14770, +28260=>14771, +28261=>14772, +28262=>14773, +28263=>14774, +28264=>14775, +28265=>14776, +28266=>14777, +28268=>14778, +28269=>14779, +28272=>14780, +28273=>14781, +28274=>14782, +28275=>14783, +28276=>14784, +28277=>14785, +28278=>14786, +28279=>14787, +28280=>14788, +28281=>14789, +28282=>14790, +28283=>14791, +28284=>14792, +28285=>14793, +28288=>14794, +28289=>14795, +28290=>14796, +28292=>14797, +28295=>14798, +28296=>14799, +28298=>14800, +28299=>14801, +28300=>14802, +28301=>14803, +28302=>14804, +28305=>14805, +28306=>14806, +28307=>14807, +28308=>14808, +28309=>14809, +28311=>14810, +28313=>14811, +28314=>14812, +28315=>14813, +28318=>14814, +28320=>14815, +28321=>14816, +28323=>14817, +28324=>14818, +28326=>14819, +28328=>14820, +28329=>14821, +28331=>14822, +28332=>14823, +28333=>14824, +28334=>14825, +28336=>14826, +28339=>14827, +28341=>14828, +28344=>14829, +28345=>14830, +28348=>14831, +28350=>14832, +28351=>14833, +28352=>14834, +28355=>14835, +28358=>14836, +28360=>14837, +28361=>14838, +28362=>14839, +28365=>14840, +28368=>14841, +28370=>14842, +28374=>14843, +28376=>14844, +28377=>14845, +28379=>14846, +28380=>14847, +28381=>14848, +28387=>14849, +28391=>14850, +28394=>14851, +28395=>14852, +28397=>14853, +28398=>14854, +28400=>14855, +28401=>14856, +28403=>14857, +28405=>14858, +28406=>14859, +28410=>14860, +28411=>14861, +28412=>14862, +28413=>14863, +28414=>14864, +28416=>14865, +28419=>14866, +28420=>14867, +28421=>14868, +28423=>14869, +28424=>14870, +28426=>14871, +28427=>14872, +28428=>14873, +28429=>14874, +28430=>14875, +28432=>14876, +28433=>14877, +28434=>14878, +28438=>14879, +28439=>14880, +28440=>14881, +28441=>14882, +28443=>14883, +28444=>14884, +28445=>14885, +28446=>14886, +28447=>14887, +28449=>14888, +28453=>14889, +28454=>14890, +28455=>14891, +28456=>14892, +28462=>14893, +28464=>14894, +28468=>14895, +28469=>14896, +28471=>14897, +28473=>14898, +28474=>14899, +28475=>14900, +28476=>14901, +28477=>14902, +28480=>14903, +28482=>14904, +28483=>14905, +28484=>14906, +28485=>14907, +28488=>14908, +28489=>14909, +28490=>14910, +28492=>14911, +28494=>14912, +28495=>14913, +28496=>14914, +28498=>14915, +28499=>14916, +28501=>14917, +28502=>14918, +28503=>14919, +28506=>14920, +28507=>14921, +28509=>14922, +28511=>14923, +28512=>14924, +28513=>14925, +28515=>14926, +28517=>14927, +28519=>14928, +28520=>14929, +28521=>14930, +28522=>14931, +28523=>14932, +28524=>14933, +28529=>14934, +28531=>14935, +28533=>14936, +28534=>14937, +28537=>14938, +28539=>14939, +28541=>14940, +28542=>14941, +28545=>14942, +28546=>14943, +28547=>14944, +28549=>14945, +28554=>14946, +28555=>14947, +28559=>14948, +28560=>14949, +28561=>14950, +28562=>14951, +28563=>14952, +28564=>14953, +28565=>14954, +28566=>14955, +28568=>14956, +28569=>14957, +28570=>14958, +28571=>14959, +28573=>14960, +28574=>14961, +28575=>14962, +28578=>14963, +28579=>14964, +28581=>14965, +28582=>14966, +28584=>14967, +28586=>14968, +28587=>14969, +28588=>14970, +28589=>14971, +28591=>14972, +28592=>14973, +28594=>14974, +28596=>14975, +28597=>14976, +28599=>14977, +28600=>14978, +28602=>14979, +28603=>14980, +28604=>14981, +28605=>14982, +28606=>14983, +28607=>14984, +28612=>14985, +28613=>14986, +28614=>14987, +28615=>14988, +28616=>14989, +28618=>14990, +28619=>14991, +28620=>14992, +28621=>14993, +28622=>14994, +28623=>14995, +28624=>14996, +28627=>14997, +28628=>14998, +28630=>14999, +28631=>15000, +28633=>15001, +28634=>15002, +28636=>15003, +28637=>15004, +28642=>15005, +28643=>15006, +28645=>15007, +28646=>15008, +28647=>15009, +28648=>15010, +28649=>15011, +28650=>15012, +28652=>15013, +28653=>15014, +28658=>15015, +28659=>15016, +28660=>15017, +28661=>15018, +28662=>15019, +28663=>15020, +28664=>15021, +28665=>15022, +28667=>15023, +28669=>15024, +28671=>15025, +28672=>15026, +28673=>15027, +28674=>15028, +28675=>15029, +28676=>15030, +28679=>15031, +28680=>15032, +28682=>15033, +28684=>15034, +28685=>15035, +28686=>15036, +28688=>15037, +28690=>15038, +28691=>15039, +28692=>15040, +28694=>15041, +28695=>15042, +28697=>15043, +28700=>15044, +28702=>15045, +28705=>15046, +28706=>15047, +28708=>15048, +28709=>15049, +28710=>15050, +28713=>15051, +28714=>15052, +28715=>15053, +28716=>15054, +28717=>15055, +28718=>15056, +28719=>15057, +28721=>15058, +28723=>15059, +28724=>15060, +28726=>15061, +28727=>15062, +28728=>15063, +28730=>15064, +28731=>15065, +28732=>15066, +28733=>15067, +28735=>15068, +28736=>15069, +28737=>15070, +28738=>15071, +28741=>15072, +28742=>15073, +28743=>15074, +28744=>15075, +28745=>15076, +28746=>15077, +28747=>15078, +28749=>15079, +28750=>15080, +28752=>15081, +28754=>15082, +28755=>15083, +28756=>15084, +28758=>15085, +28759=>15086, +28761=>15087, +28762=>15088, +28763=>15089, +28764=>15090, +28767=>15091, +28768=>15092, +28769=>15093, +28770=>15094, +28773=>15095, +28774=>15096, +28776=>15097, +28777=>15098, +28778=>15099, +28782=>15100, +28785=>15101, +28786=>15102, +28787=>15103, +28788=>15104, +28791=>15105, +28793=>15106, +28794=>15107, +28795=>15108, +28797=>15109, +28801=>15110, +28802=>15111, +28803=>15112, +28804=>15113, +28806=>15114, +28807=>15115, +28808=>15116, +28811=>15117, +28812=>15118, +28813=>15119, +28815=>15120, +28816=>15121, +28817=>15122, +28819=>15123, +28823=>15124, +28824=>15125, +28826=>15126, +28827=>15127, +28830=>15128, +28831=>15129, +28832=>15130, +28833=>15131, +28834=>15132, +28835=>15133, +28836=>15134, +28837=>15135, +28838=>15136, +28839=>15137, +28840=>15138, +28841=>15139, +28842=>15140, +28848=>15141, +28850=>15142, +28852=>15143, +28853=>15144, +28854=>15145, +28858=>15146, +28862=>15147, +28863=>15148, +28868=>15149, +28869=>15150, +28870=>15151, +28871=>15152, +28873=>15153, +28875=>15154, +28876=>15155, +28877=>15156, +28878=>15157, +28880=>15158, +28881=>15159, +28882=>15160, +28883=>15161, +28884=>15162, +28885=>15163, +28886=>15164, +28887=>15165, +28890=>15166, +28892=>15167, +28893=>15168, +28894=>15169, +28896=>15170, +28897=>15171, +28898=>15172, +28899=>15173, +28901=>15174, +28906=>15175, +28910=>15176, +28912=>15177, +28913=>15178, +28914=>15179, +28915=>15180, +28917=>15181, +28918=>15182, +28920=>15183, +28922=>15184, +28923=>15185, +28924=>15186, +28926=>15187, +28927=>15188, +28928=>15189, +28929=>15190, +28930=>15191, +28931=>15192, +28932=>15193, +28933=>15194, +28934=>15195, +28935=>15196, +28936=>15197, +28939=>15198, +28940=>15199, +28941=>15200, +28942=>15201, +28943=>15202, +28945=>15203, +28946=>15204, +28948=>15205, +28951=>15206, +28955=>15207, +28956=>15208, +28957=>15209, +28958=>15210, +28959=>15211, +28960=>15212, +28962=>15213, +28963=>15214, +28964=>15215, +28965=>15216, +28967=>15217, +28968=>15218, +28969=>15219, +28970=>15220, +28971=>15221, +28972=>15222, +28973=>15223, +28974=>15224, +28978=>15225, +28979=>15226, +28980=>15227, +28981=>15228, +28983=>15229, +28984=>15230, +28985=>15231, +28986=>15232, +28987=>15233, +28988=>15234, +28989=>15235, +28990=>15236, +28991=>15237, +28992=>15238, +28993=>15239, +28994=>15240, +28995=>15241, +28996=>15242, +28998=>15243, +28999=>15244, +29000=>15245, +29003=>15246, +29005=>15247, +29007=>15248, +29008=>15249, +29009=>15250, +29011=>15251, +29012=>15252, +29013=>15253, +29014=>15254, +29015=>15255, +29016=>15256, +29017=>15257, +29018=>15258, +29019=>15259, +29021=>15260, +29023=>15261, +29024=>15262, +29025=>15263, +29027=>15264, +29029=>15265, +29034=>15266, +29035=>15267, +29037=>15268, +29039=>15269, +29040=>15270, +29041=>15271, +29044=>15272, +29045=>15273, +29046=>15274, +29047=>15275, +29049=>15276, +29051=>15277, +29052=>15278, +29054=>15279, +29055=>15280, +29056=>15281, +29057=>15282, +29058=>15283, +29059=>15284, +29061=>15285, +29062=>15286, +29063=>15287, +29064=>15288, +29065=>15289, +29067=>15290, +29068=>15291, +29069=>15292, +29070=>15293, +29072=>15294, +29073=>15295, +29075=>15296, +29077=>15297, +29078=>15298, +29082=>15299, +29083=>15300, +29084=>15301, +29085=>15302, +29086=>15303, +29089=>15304, +29090=>15305, +29091=>15306, +29092=>15307, +29093=>15308, +29094=>15309, +29095=>15310, +29097=>15311, +29098=>15312, +29099=>15313, +29101=>15314, +29102=>15315, +29103=>15316, +29104=>15317, +29106=>15318, +29108=>15319, +29110=>15320, +29111=>15321, +29112=>15322, +29114=>15323, +29115=>15324, +29116=>15325, +29117=>15326, +29119=>15327, +29120=>15328, +29122=>15329, +29124=>15330, +29125=>15331, +29126=>15332, +29127=>15333, +29129=>15334, +29130=>15335, +29131=>15336, +29132=>15337, +29133=>15338, +29135=>15339, +29136=>15340, +29137=>15341, +29139=>15342, +29142=>15343, +29143=>15344, +29144=>15345, +29146=>15346, +29147=>15347, +29149=>15348, +29150=>15349, +29153=>15350, +29154=>15351, +29155=>15352, +29156=>15353, +29160=>15354, +29161=>15355, +29162=>15356, +29163=>15357, +29164=>15358, +29167=>15359, +29168=>15360, +29169=>15361, +29170=>15362, +29171=>15363, +29173=>15364, +29174=>15365, +29175=>15366, +29176=>15367, +29178=>15368, +29179=>15369, +29181=>15370, +29183=>15371, +29184=>15372, +29185=>15373, +29186=>15374, +29187=>15375, +29188=>15376, +29189=>15377, +29191=>15378, +29192=>15379, +29193=>15380, +29194=>15381, +29195=>15382, +29196=>15383, +29198=>15384, +29199=>15385, +29201=>15386, +29202=>15387, +29203=>15388, +29204=>15389, +29205=>15390, +29206=>15391, +29207=>15392, +29208=>15393, +29209=>15394, +29210=>15395, +29212=>15396, +29214=>15397, +29215=>15398, +29216=>15399, +29217=>15400, +29218=>15401, +29219=>15402, +29220=>15403, +29221=>15404, +29222=>15405, +29223=>15406, +29225=>15407, +29227=>15408, +29229=>15409, +29230=>15410, +29231=>15411, +29235=>15412, +29236=>15413, +29244=>15414, +29248=>15415, +29249=>15416, +29250=>15417, +29251=>15418, +29252=>15419, +29253=>15420, +29254=>15421, +29257=>15422, +29258=>15423, +29259=>15424, +29262=>15425, +29263=>15426, +29264=>15427, +29265=>15428, +29267=>15429, +29268=>15430, +29269=>15431, +29271=>15432, +29274=>15433, +29276=>15434, +29278=>15435, +29280=>15436, +29283=>15437, +29284=>15438, +29285=>15439, +29288=>15440, +29290=>15441, +29291=>15442, +29292=>15443, +29293=>15444, +29296=>15445, +29297=>15446, +29299=>15447, +29300=>15448, +29302=>15449, +29303=>15450, +29304=>15451, +29307=>15452, +29308=>15453, +29314=>15454, +29315=>15455, +29317=>15456, +29318=>15457, +29319=>15458, +29320=>15459, +29321=>15460, +29324=>15461, +29326=>15462, +29328=>15463, +29329=>15464, +29331=>15465, +29332=>15466, +29333=>15467, +29335=>15468, +29336=>15469, +29337=>15470, +29338=>15471, +29339=>15472, +29340=>15473, +29341=>15474, +29342=>15475, +29344=>15476, +29345=>15477, +29347=>15478, +29348=>15479, +29349=>15480, +29350=>15481, +29352=>15482, +29353=>15483, +29354=>15484, +29355=>15485, +29358=>15486, +29361=>15487, +29362=>15488, +29363=>15489, +29365=>15490, +29370=>15491, +29371=>15492, +29372=>15493, +29373=>15494, +29374=>15495, +29375=>15496, +29381=>15497, +29382=>15498, +29383=>15499, +29385=>15500, +29386=>15501, +29387=>15502, +29388=>15503, +29391=>15504, +29393=>15505, +29395=>15506, +29396=>15507, +29397=>15508, +29398=>15509, +29400=>15510, +29402=>15511, +29403=>15512, +29404=>15513, +29405=>15514, +29407=>15515, +29410=>15516, +29411=>15517, +29412=>15518, +29413=>15519, +29414=>15520, +29415=>15521, +29418=>15522, +29419=>15523, +29429=>15524, +29430=>15525, +29438=>15526, +29439=>15527, +29440=>15528, +29442=>15529, +29444=>15530, +29445=>15531, +29446=>15532, +29447=>15533, +29448=>15534, +29449=>15535, +29451=>15536, +29452=>15537, +29453=>15538, +29455=>15539, +29456=>15540, +29457=>15541, +29458=>15542, +29460=>15543, +29464=>15544, +29465=>15545, +29466=>15546, +29471=>15547, +29472=>15548, +29475=>15549, +29476=>15550, +29478=>15551, +29479=>15552, +29480=>15553, +29485=>15554, +29487=>15555, +29488=>15556, +29490=>15557, +29491=>15558, +29493=>15559, +29498=>15560, +29500=>15561, +29501=>15562, +29504=>15563, +29506=>15564, +29507=>15565, +29510=>15566, +29511=>15567, +29512=>15568, +29513=>15569, +29514=>15570, +29515=>15571, +29516=>15572, +29518=>15573, +29519=>15574, +29521=>15575, +29523=>15576, +29524=>15577, +29525=>15578, +29526=>15579, +29528=>15580, +29529=>15581, +29530=>15582, +29531=>15583, +29532=>15584, +29533=>15585, +29534=>15586, +29535=>15587, +29537=>15588, +29538=>15589, +29539=>15590, +29540=>15591, +29541=>15592, +29542=>15593, +29543=>15594, +29545=>15595, +29550=>15596, +29553=>15597, +29555=>15598, +29556=>15599, +29558=>15600, +29561=>15601, +29565=>15602, +29567=>15603, +29569=>15604, +29570=>15605, +29571=>15606, +29573=>15607, +29574=>15608, +29576=>15609, +29578=>15610, +29580=>15611, +29581=>15612, +29583=>15613, +29584=>15614, +29586=>15615, +29587=>15616, +29588=>15617, +29589=>15618, +29591=>15619, +29592=>15620, +29593=>15621, +29594=>15622, +29596=>15623, +29597=>15624, +29598=>15625, +29600=>15626, +29601=>15627, +29603=>15628, +29604=>15629, +29605=>15630, +29606=>15631, +29607=>15632, +29608=>15633, +29610=>15634, +29612=>15635, +29613=>15636, +29617=>15637, +29620=>15638, +29621=>15639, +29622=>15640, +29624=>15641, +29625=>15642, +29628=>15643, +29629=>15644, +29630=>15645, +29631=>15646, +29633=>15647, +29635=>15648, +29636=>15649, +29637=>15650, +29638=>15651, +29639=>15652, +29643=>15653, +29644=>15654, +29646=>15655, +29650=>15656, +29651=>15657, +29652=>15658, +29653=>15659, +29654=>15660, +29655=>15661, +29656=>15662, +29658=>15663, +29659=>15664, +29660=>15665, +29661=>15666, +29663=>15667, +29665=>15668, +29666=>15669, +29667=>15670, +29668=>15671, +29670=>15672, +29672=>15673, +29674=>15674, +29675=>15675, +29676=>15676, +29678=>15677, +29679=>15678, +29680=>15679, +29681=>15680, +29683=>15681, +29684=>15682, +29685=>15683, +29686=>15684, +29687=>15685, +29688=>15686, +29689=>15687, +29690=>15688, +29691=>15689, +29692=>15690, +29693=>15691, +29695=>15692, +29696=>15693, +29697=>15694, +29698=>15695, +29700=>15696, +29703=>15697, +29704=>15698, +29707=>15699, +29708=>15700, +29709=>15701, +29710=>15702, +29713=>15703, +29714=>15704, +29715=>15705, +29716=>15706, +29717=>15707, +29718=>15708, +29719=>15709, +29720=>15710, +29721=>15711, +29724=>15712, +29725=>15713, +29726=>15714, +29727=>15715, +29728=>15716, +29729=>15717, +29731=>15718, +29732=>15719, +29735=>15720, +29737=>15721, +29739=>15722, +29741=>15723, +29743=>15724, +29745=>15725, +29746=>15726, +29751=>15727, +29752=>15728, +29753=>15729, +29754=>15730, +29755=>15731, +29757=>15732, +29758=>15733, +29760=>15734, +29762=>15735, +29763=>15736, +29764=>15737, +29765=>15738, +29766=>15739, +29767=>15740, +29768=>15741, +29769=>15742, +29770=>15743, +29772=>15744, +29773=>15745, +29774=>15746, +29775=>15747, +29776=>15748, +29777=>15749, +29778=>15750, +29779=>15751, +29780=>15752, +29782=>15753, +29784=>15754, +29789=>15755, +29792=>15756, +29793=>15757, +29794=>15758, +29796=>15759, +29797=>15760, +29798=>15761, +29799=>15762, +29800=>15763, +29803=>15764, +29804=>15765, +29806=>15766, +29807=>15767, +29809=>15768, +29810=>15769, +29811=>15770, +29812=>15771, +29813=>15772, +29816=>15773, +29817=>15774, +29818=>15775, +29819=>15776, +29820=>15777, +29821=>15778, +29823=>15779, +29826=>15780, +29828=>15781, +29829=>15782, +29830=>15783, +29832=>15784, +29834=>15785, +29836=>15786, +29837=>15787, +29839=>15788, +29841=>15789, +29842=>15790, +29843=>15791, +29844=>15792, +29845=>15793, +29846=>15794, +29847=>15795, +29848=>15796, +29849=>15797, +29850=>15798, +29851=>15799, +29853=>15800, +29855=>15801, +29856=>15802, +29857=>15803, +29858=>15804, +29860=>15805, +29861=>15806, +29866=>15807, +29867=>15808, +29868=>15809, +29869=>15810, +29870=>15811, +29871=>15812, +29873=>15813, +29874=>15814, +29875=>15815, +29876=>15816, +29877=>15817, +29878=>15818, +29879=>15819, +29880=>15820, +29881=>15821, +29883=>15822, +29884=>15823, +29886=>15824, +29887=>15825, +29888=>15826, +29889=>15827, +29890=>15828, +29891=>15829, +29892=>15830, +29893=>15831, +29894=>15832, +29895=>15833, +29896=>15834, +29897=>15835, +29899=>15836, +29900=>15837, +29901=>15838, +29902=>15839, +29904=>15840, +29905=>15841, +29907=>15842, +29909=>15843, +29910=>15844, +29911=>15845, +29912=>15846, +29913=>15847, +29915=>15848, +29917=>15849, +29919=>15850, +29921=>15851, +29925=>15852, +29927=>15853, +29928=>15854, +29929=>15855, +29930=>15856, +29931=>15857, +29932=>15858, +29933=>15859, +29936=>15860, +29937=>15861, +29938=>15862, +29939=>15863, +29941=>15864, +29944=>15865, +29945=>15866, +29946=>15867, +29947=>15868, +29948=>15869, +29949=>15870, +29950=>15871, +29952=>15872, +29953=>15873, +29954=>15874, +29955=>15875, +29957=>15876, +29958=>15877, +29959=>15878, +29960=>15879, +29961=>15880, +29962=>15881, +29963=>15882, +29966=>15883, +29968=>15884, +29970=>15885, +29972=>15886, +29973=>15887, +29974=>15888, +29975=>15889, +29979=>15890, +29981=>15891, +29982=>15892, +29984=>15893, +29985=>15894, +29986=>15895, +29988=>15896, +29990=>15897, +29991=>15898, +29994=>15899, +29998=>15900, +30004=>15901, +30006=>15902, +30009=>15903, +30012=>15904, +30013=>15905, +30015=>15906, +30017=>15907, +30018=>15908, +30019=>15909, +30020=>15910, +30022=>15911, +30023=>15912, +30025=>15913, +30026=>15914, +30029=>15915, +30032=>15916, +30033=>15917, +30034=>15918, +30035=>15919, +30037=>15920, +30038=>15921, +30039=>15922, +30040=>15923, +30046=>15924, +30047=>15925, +30048=>15926, +30049=>15927, +30051=>15928, +30052=>15929, +30055=>15930, +30056=>15931, +30057=>15932, +30060=>15933, +30061=>15934, +30062=>15935, +30063=>15936, +30064=>15937, +30065=>15938, +30067=>15939, +30069=>15940, +30071=>15941, +30074=>15942, +30075=>15943, +30076=>15944, +30077=>15945, +30078=>15946, +30080=>15947, +30081=>15948, +30082=>15949, +30084=>15950, +30085=>15951, +30088=>15952, +30089=>15953, +30090=>15954, +30092=>15955, +30093=>15956, +30094=>15957, +30096=>15958, +30099=>15959, +30101=>15960, +30104=>15961, +30107=>15962, +30108=>15963, +30110=>15964, +30114=>15965, +30118=>15966, +30119=>15967, +30120=>15968, +30121=>15969, +30122=>15970, +30125=>15971, +30134=>15972, +30135=>15973, +30138=>15974, +30139=>15975, +30143=>15976, +30144=>15977, +30145=>15978, +30150=>15979, +30155=>15980, +30156=>15981, +30158=>15982, +30159=>15983, +30160=>15984, +30161=>15985, +30163=>15986, +30167=>15987, +30170=>15988, +30172=>15989, +30173=>15990, +30175=>15991, +30176=>15992, +30177=>15993, +30181=>15994, +30185=>15995, +30188=>15996, +30189=>15997, +30190=>15998, +30191=>15999, +30194=>16000, +30195=>16001, +30197=>16002, +30198=>16003, +30199=>16004, +30200=>16005, +30202=>16006, +30203=>16007, +30205=>16008, +30206=>16009, +30212=>16010, +30214=>16011, +30215=>16012, +30216=>16013, +30217=>16014, +30222=>16015, +30223=>16016, +30225=>16017, +30226=>16018, +30227=>16019, +30228=>16020, +30230=>16021, +30234=>16022, +30236=>16023, +30237=>16024, +30243=>16025, +30248=>16026, +30252=>16027, +30254=>16028, +30255=>16029, +30257=>16030, +30258=>16031, +30262=>16032, +30263=>16033, +30265=>16034, +30266=>16035, +30269=>16036, +30273=>16037, +30276=>16038, +30277=>16039, +30280=>16040, +30282=>16041, +30283=>16042, +30286=>16043, +30287=>16044, +30288=>16045, +30289=>16046, +30290=>16047, +30291=>16048, +30293=>16049, +30295=>16050, +30297=>16051, +30298=>16052, +30299=>16053, +30301=>16054, +30304=>16055, +30305=>16056, +30310=>16057, +30312=>16058, +30314=>16059, +30323=>16060, +30324=>16061, +30325=>16062, +12136=>16063, +30326=>16063, +30327=>16064, +30329=>16065, +30330=>16066, +30335=>16067, +30336=>16068, +30337=>16069, +30339=>16070, +30341=>16071, +30345=>16072, +30346=>16073, +30348=>16074, +30349=>16075, +30351=>16076, +30352=>16077, +30354=>16078, +30356=>16079, +30357=>16080, +30359=>16081, +30360=>16082, +30363=>16083, +30364=>16084, +30365=>16085, +30366=>16086, +30367=>16087, +30368=>16088, +30369=>16089, +30370=>16090, +30371=>16091, +30373=>16092, +30374=>16093, +30375=>16094, +30376=>16095, +30377=>16096, +30378=>16097, +30379=>16098, +30380=>16099, +30381=>16100, +30383=>16101, +30384=>16102, +30387=>16103, +30389=>16104, +30390=>16105, +30391=>16106, +30393=>16107, +30395=>16108, +30396=>16109, +30397=>16110, +30398=>16111, +30400=>16112, +30401=>16113, +30403=>16114, +30404=>16115, +30407=>16116, +30409=>16117, +30411=>16118, +30412=>16119, +30419=>16120, +30421=>16121, +30425=>16122, +30426=>16123, +30428=>16124, +30429=>16125, +30432=>16126, +30434=>16127, +30438=>16128, +30440=>16129, +30441=>16130, +30442=>16131, +30443=>16132, +30444=>16133, +30445=>16134, +30448=>16135, +30451=>16136, +30453=>16137, +30454=>16138, +30455=>16139, +30458=>16140, +30459=>16141, +30461=>16142, +30463=>16143, +30464=>16144, +30466=>16145, +30467=>16146, +30469=>16147, +30470=>16148, +30474=>16149, +30476=>16150, +30478=>16151, +30479=>16152, +30480=>16153, +30481=>16154, +30482=>16155, +30483=>16156, +30484=>16157, +30485=>16158, +30486=>16159, +30487=>16160, +30488=>16161, +30491=>16162, +30492=>16163, +30493=>16164, +30494=>16165, +30497=>16166, +30499=>16167, +30500=>16168, +30501=>16169, +30503=>16170, +30506=>16171, +30507=>16172, +30508=>16173, +30510=>16174, +30512=>16175, +30513=>16176, +30514=>16177, +30515=>16178, +30516=>16179, +30521=>16180, +30523=>16181, +30525=>16182, +30526=>16183, +30527=>16184, +30530=>16185, +30532=>16186, +30533=>16187, +30534=>16188, +30536=>16189, +30537=>16190, +30538=>16191, +30539=>16192, +30540=>16193, +30541=>16194, +30542=>16195, +30546=>16196, +30547=>16197, +30548=>16198, +30549=>16199, +30550=>16200, +30551=>16201, +30552=>16202, +30553=>16203, +30556=>16204, +30557=>16205, +30559=>16206, +30560=>16207, +30564=>16208, +30567=>16209, +30569=>16210, +30570=>16211, +30573=>16212, +30574=>16213, +30575=>16214, +30576=>16215, +30577=>16216, +30578=>16217, +30579=>16218, +30580=>16219, +30581=>16220, +30582=>16221, +30583=>16222, +30584=>16223, +30586=>16224, +30587=>16225, +30588=>16226, +30593=>16227, +30594=>16228, +30595=>16229, +30598=>16230, +30599=>16231, +30600=>16232, +30601=>16233, +30602=>16234, +30603=>16235, +30607=>16236, +30608=>16237, +30611=>16238, +30612=>16239, +30613=>16240, +30614=>16241, +30615=>16242, +30617=>16243, +30618=>16244, +30619=>16245, +30620=>16246, +30621=>16247, +30625=>16248, +30627=>16249, +30628=>16250, +30630=>16251, +30632=>16252, +30635=>16253, +30638=>16254, +30639=>16255, +30641=>16256, +30642=>16257, +30644=>16258, +30646=>16259, +30647=>16260, +30648=>16261, +30649=>16262, +30650=>16263, +30654=>16264, +30656=>16265, +30657=>16266, +30658=>16267, +30659=>16268, +30660=>16269, +30661=>16270, +30662=>16271, +30664=>16272, +30665=>16273, +30666=>16274, +30667=>16275, +30668=>16276, +30670=>16277, +30671=>16278, +30672=>16279, +30673=>16280, +30674=>16281, +30675=>16282, +30676=>16283, +30677=>16284, +30678=>16285, +30680=>16286, +30681=>16287, +30685=>16288, +30686=>16289, +30687=>16290, +30688=>16291, +30689=>16292, +30692=>16293, +30694=>16294, +30696=>16295, +30698=>16296, +30704=>16297, +30705=>16298, +30706=>16299, +30708=>16300, +30709=>16301, +30711=>16302, +30713=>16303, +30714=>16304, +30715=>16305, +30716=>16306, +30723=>16307, +30724=>16308, +30725=>16309, +30726=>16310, +30727=>16311, +30728=>16312, +30730=>16313, +30731=>16314, +30734=>16315, +30735=>16316, +30736=>16317, +30739=>16318, +30741=>16319, +30745=>16320, +30747=>16321, +30750=>16322, +30752=>16323, +30753=>16324, +30754=>16325, +30756=>16326, +30760=>16327, +30762=>16328, +30763=>16329, +30766=>16330, +30767=>16331, +30769=>16332, +30770=>16333, +30771=>16334, +30773=>16335, +30774=>16336, +30781=>16337, +30783=>16338, +30785=>16339, +30786=>16340, +30788=>16341, +30790=>16342, +30792=>16343, +30793=>16344, +30794=>16345, +30795=>16346, +30797=>16347, +30799=>16348, +30801=>16349, +30803=>16350, +30804=>16351, +30808=>16352, +30809=>16353, +30810=>16354, +30811=>16355, +30812=>16356, +30814=>16357, +30815=>16358, +30816=>16359, +30817=>16360, +30818=>16361, +30819=>16362, +30821=>16363, +30822=>16364, +30823=>16365, +30825=>16366, +30832=>16367, +30833=>16368, +30834=>16369, +30835=>16370, +30836=>16371, +30837=>16372, +30838=>16373, +30840=>16374, +30841=>16375, +30842=>16376, +30843=>16377, +30845=>16378, +30846=>16379, +30847=>16380, +30848=>16381, +30849=>16382, +30850=>16383, +30851=>16384, +30852=>16385, +30853=>16386, +30854=>16387, +30856=>16388, +30858=>16389, +30859=>16390, +30863=>16391, +30864=>16392, +30866=>16393, +30868=>16394, +30869=>16395, +30870=>16396, +30873=>16397, +30877=>16398, +30878=>16399, +30880=>16400, +30882=>16401, +30884=>16402, +30886=>16403, +30888=>16404, +30890=>16405, +30891=>16406, +30892=>16407, +30894=>16408, +30895=>16409, +30901=>16410, +30902=>16411, +30903=>16412, +30907=>16413, +30909=>16414, +30911=>16415, +30912=>16416, +30914=>16417, +30915=>16418, +30916=>16419, +30918=>16420, +30919=>16421, +30920=>16422, +30924=>16423, +30925=>16424, +30926=>16425, +30927=>16426, +30929=>16427, +30930=>16428, +30931=>16429, +30934=>16430, +30935=>16431, +30936=>16432, +30939=>16433, +30940=>16434, +30941=>16435, +30942=>16436, +30943=>16437, +30944=>16438, +30945=>16439, +30946=>16440, +30948=>16441, +30949=>16442, +30950=>16443, +30953=>16444, +30954=>16445, +30955=>16446, +30957=>16447, +30958=>16448, +30960=>16449, +30961=>16450, +30963=>16451, +30965=>16452, +30966=>16453, +30968=>16454, +30969=>16455, +30971=>16456, +30972=>16457, +30974=>16458, +30975=>16459, +30976=>16460, +30978=>16461, +30979=>16462, +30980=>16463, +30982=>16464, +30983=>16465, +30984=>16466, +30985=>16467, +30986=>16468, +30987=>16469, +30988=>16470, +30989=>16471, +30991=>16472, +30992=>16473, +30993=>16474, +30994=>16475, +30996=>16476, +30997=>16477, +30998=>16478, +30999=>16479, +31000=>16480, +31002=>16481, +31003=>16482, +31004=>16483, +31005=>16484, +31007=>16485, +31008=>16486, +31009=>16487, +31010=>16488, +31011=>16489, +31013=>16490, +31015=>16491, +31016=>16492, +31017=>16493, +31021=>16494, +31022=>16495, +31023=>16496, +31024=>16497, +31026=>16498, +31027=>16499, +31029=>16500, +31030=>16501, +31031=>16502, +31032=>16503, +31033=>16504, +31037=>16505, +31039=>16506, +31042=>16507, +31043=>16508, +31044=>16509, +31045=>16510, +31047=>16511, +31050=>16512, +31051=>16513, +31052=>16514, +31053=>16515, +31054=>16516, +31055=>16517, +31056=>16518, +31057=>16519, +31058=>16520, +31060=>16521, +31061=>16522, +31064=>16523, +31065=>16524, +31073=>16525, +31075=>16526, +31076=>16527, +31078=>16528, +31081=>16529, +31082=>16530, +31083=>16531, +31084=>16532, +31086=>16533, +31088=>16534, +31089=>16535, +31090=>16536, +31091=>16537, +31092=>16538, +31093=>16539, +31094=>16540, +31097=>16541, +31099=>16542, +31100=>16543, +31101=>16544, +31102=>16545, +31103=>16546, +31106=>16547, +31107=>16548, +31110=>16549, +31111=>16550, +31112=>16551, +31113=>16552, +31115=>16553, +31116=>16554, +31120=>16555, +31121=>16556, +31122=>16557, +31123=>16558, +31124=>16559, +31125=>16560, +31126=>16561, +31127=>16562, +31128=>16563, +31129=>16564, +31131=>16565, +31132=>16566, +31133=>16567, +31134=>16568, +31135=>16569, +31136=>16570, +31137=>16571, +31138=>16572, +31139=>16573, +31140=>16574, +31141=>16575, +31144=>16576, +31145=>16577, +31147=>16578, +31148=>16579, +31149=>16580, +31151=>16581, +31154=>16582, +31156=>16583, +31157=>16584, +31158=>16585, +31159=>16586, +12145=>16587, +31160=>16587, +31164=>16588, +31167=>16589, +31170=>16590, +31172=>16591, +31173=>16592, +31175=>16593, +31176=>16594, +31178=>16595, +63893=>16595, +31180=>16596, +31182=>16597, +31183=>16598, +31184=>16599, +31187=>16600, +31188=>16601, +31190=>16602, +31191=>16603, +31193=>16604, +31194=>16605, +31195=>16606, +31196=>16607, +31197=>16608, +31198=>16609, +31200=>16610, +31201=>16611, +31202=>16612, +31205=>16613, +31208=>16614, +31210=>16615, +31212=>16616, +31214=>16617, +31217=>16618, +31218=>16619, +31219=>16620, +31220=>16621, +31221=>16622, +31222=>16623, +31223=>16624, +31225=>16625, +31226=>16626, +31228=>16627, +31230=>16628, +31231=>16629, +31233=>16630, +31236=>16631, +31237=>16632, +31239=>16633, +31240=>16634, +31241=>16635, +31242=>16636, +31244=>16637, +31247=>16638, +31248=>16639, +31249=>16640, +31250=>16641, +31251=>16642, +31253=>16643, +31254=>16644, +31256=>16645, +31257=>16646, +31259=>16647, +31260=>16648, +31261=>16649, +31263=>16650, +31265=>16651, +31266=>16652, +31268=>16653, +31269=>16654, +31270=>16655, +31271=>16656, +31272=>16657, +31273=>16658, +31274=>16659, +31275=>16660, +31276=>16661, +31277=>16662, +31279=>16663, +31280=>16664, +31282=>16665, +31284=>16666, +31285=>16667, +31286=>16668, +31288=>16669, +31290=>16670, +31294=>16671, +31297=>16672, +31298=>16673, +31299=>16674, +31300=>16675, +31301=>16676, +31303=>16677, +31304=>16678, +31305=>16679, +31306=>16680, +31307=>16681, +31311=>16682, +31312=>16683, +31314=>16684, +31315=>16685, +31316=>16686, +31317=>16687, +31318=>16688, +31320=>16689, +31321=>16690, +31322=>16691, +31323=>16692, +31324=>16693, +31325=>16694, +31326=>16695, +31327=>16696, +31328=>16697, +31331=>16698, +31332=>16699, +31333=>16700, +31334=>16701, +31335=>16702, +31336=>16703, +31338=>16704, +31340=>16705, +31341=>16706, +31342=>16707, +31343=>16708, +31345=>16709, +31346=>16710, +31347=>16711, +31349=>16712, +31355=>16713, +31356=>16714, +31357=>16715, +31358=>16716, +31362=>16717, +31365=>16718, +31367=>16719, +31369=>16720, +31370=>16721, +31371=>16722, +31372=>16723, +31374=>16724, +31375=>16725, +31376=>16726, +31379=>16727, +31380=>16728, +31385=>16729, +31386=>16730, +31387=>16731, +31390=>16732, +31393=>16733, +31394=>16734, +31395=>16735, +31396=>16736, +31399=>16737, +31403=>16738, +31407=>16739, +31408=>16740, +31409=>16741, +31410=>16742, +31412=>16743, +31413=>16744, +31415=>16745, +31416=>16746, +31417=>16747, +31419=>16748, +31420=>16749, +31421=>16750, +31422=>16751, +31424=>16752, +31425=>16753, +31426=>16754, +31427=>16755, +31430=>16756, +31433=>16757, +31436=>16758, +31437=>16759, +31438=>16760, +31439=>16761, +31440=>16762, +31441=>16763, +31442=>16764, +31443=>16765, +31444=>16766, +31445=>16767, +31447=>16768, +31448=>16769, +31450=>16770, +31451=>16771, +31452=>16772, +31453=>16773, +31457=>16774, +31458=>16775, +31460=>16776, +31463=>16777, +31464=>16778, +31465=>16779, +31467=>16780, +31468=>16781, +31470=>16782, +31472=>16783, +31473=>16784, +31474=>16785, +31475=>16786, +31476=>16787, +31477=>16788, +31479=>16789, +31480=>16790, +31483=>16791, +31484=>16792, +31486=>16793, +31488=>16794, +31489=>16795, +31490=>16796, +31493=>16797, +31495=>16798, +31497=>16799, +31500=>16800, +31501=>16801, +31502=>16802, +31504=>16803, +31506=>16804, +31507=>16805, +31510=>16806, +31511=>16807, +31512=>16808, +31514=>16809, +31516=>16810, +31517=>16811, +31519=>16812, +31521=>16813, +31522=>16814, +31523=>16815, +31527=>16816, +31529=>16817, +31533=>16818, +31535=>16819, +31536=>16820, +31538=>16821, +31540=>16822, +31541=>16823, +31542=>16824, +31543=>16825, +31545=>16826, +31547=>16827, +31549=>16828, +31551=>16829, +31552=>16830, +31553=>16831, +31554=>16832, +31555=>16833, +31556=>16834, +31560=>16835, +31562=>16836, +31565=>16837, +31566=>16838, +31571=>16839, +31573=>16840, +31575=>16841, +31577=>16842, +31580=>16843, +31582=>16844, +31583=>16845, +31585=>16846, +31587=>16847, +31588=>16848, +31589=>16849, +31590=>16850, +31592=>16851, +31593=>16852, +31594=>16853, +31595=>16854, +31596=>16855, +31597=>16856, +31599=>16857, +31600=>16858, +31603=>16859, +31604=>16860, +31606=>16861, +31608=>16862, +31610=>16863, +31612=>16864, +31613=>16865, +31615=>16866, +31617=>16867, +31618=>16868, +31619=>16869, +31620=>16870, +31622=>16871, +31623=>16872, +31624=>16873, +31625=>16874, +31626=>16875, +31628=>16876, +31630=>16877, +31631=>16878, +31633=>16879, +31634=>16880, +31635=>16881, +31638=>16882, +31640=>16883, +31641=>16884, +31642=>16885, +31643=>16886, +31646=>16887, +31647=>16888, +31648=>16889, +31651=>16890, +31652=>16891, +31653=>16892, +31662=>16893, +31663=>16894, +31664=>16895, +31666=>16896, +31667=>16897, +31669=>16898, +31670=>16899, +31671=>16900, +31673=>16901, +31674=>16902, +31675=>16903, +31676=>16904, +31677=>16905, +31678=>16906, +31679=>16907, +31682=>16908, +31683=>16909, +31685=>16910, +31688=>16911, +31690=>16912, +31693=>16913, +31694=>16914, +31695=>16915, +31696=>16916, +31698=>16917, +31700=>16918, +31701=>16919, +31702=>16920, +31703=>16921, +31704=>16922, +31707=>16923, +31708=>16924, +31710=>16925, +31711=>16926, +31712=>16927, +31714=>16928, +31715=>16929, +31719=>16930, +31720=>16931, +31723=>16932, +31724=>16933, +31725=>16934, +31727=>16935, +31728=>16936, +31730=>16937, +31732=>16938, +31733=>16939, +31734=>16940, +31736=>16941, +31737=>16942, +31738=>16943, +31739=>16944, +31741=>16945, +31743=>16946, +31745=>16947, +31746=>16948, +31747=>16949, +31748=>16950, +31749=>16951, +31750=>16952, +31752=>16953, +31753=>16954, +31754=>16955, +31758=>16956, +31760=>16957, +31761=>16958, +31762=>16959, +31763=>16960, +31764=>16961, +31765=>16962, +31767=>16963, +31768=>16964, +31769=>16965, +31770=>16966, +31771=>16967, +31772=>16968, +31773=>16969, +31776=>16970, +31778=>16971, +31780=>16972, +31781=>16973, +31784=>16974, +31785=>16975, +31788=>16976, +31789=>16977, +31790=>16978, +31791=>16979, +31792=>16980, +31793=>16981, +31794=>16982, +31795=>16983, +31796=>16984, +31797=>16985, +31798=>16986, +31799=>16987, +31801=>16988, +31802=>16989, +31803=>16990, +31804=>16991, +31810=>16992, +31812=>16993, +31813=>16994, +31814=>16995, +31815=>16996, +31816=>16997, +31817=>16998, +31818=>16999, +31819=>17000, +31822=>17001, +31823=>17002, +31824=>17003, +31825=>17004, +31826=>17005, +31827=>17006, +31828=>17007, +31829=>17008, +31830=>17009, +31831=>17010, +31832=>17011, +31833=>17012, +31834=>17013, +31835=>17014, +31837=>17015, +31838=>17016, +31841=>17017, +31842=>17018, +31843=>17019, +31845=>17020, +31846=>17021, +31847=>17022, +31848=>17023, +31851=>17024, +31853=>17025, +31855=>17026, +31856=>17027, +31857=>17028, +31861=>17029, +31862=>17030, +31863=>17031, +31864=>17032, +31865=>17033, +31866=>17034, +31870=>17035, +31871=>17036, +31872=>17037, +31873=>17038, +31874=>17039, +31875=>17040, +31876=>17041, +31877=>17042, +31878=>17043, +31879=>17044, +31880=>17045, +31882=>17046, +31883=>17047, +31884=>17048, +31885=>17049, +31886=>17050, +31887=>17051, +31888=>17052, +31891=>17053, +31892=>17054, +31894=>17055, +31897=>17056, +31898=>17057, +31899=>17058, +31904=>17059, +31905=>17060, +31907=>17061, +31910=>17062, +31911=>17063, +31912=>17064, +31913=>17065, +31915=>17066, +31916=>17067, +31917=>17068, +31919=>17069, +31920=>17070, +31924=>17071, +31925=>17072, +31926=>17073, +31927=>17074, +31928=>17075, +31930=>17076, +31931=>17077, +31935=>17078, +31936=>17079, +31938=>17080, +31939=>17081, +31940=>17082, +31942=>17083, +31945=>17084, +31947=>17085, +31950=>17086, +31951=>17087, +31952=>17088, +31953=>17089, +31954=>17090, +31955=>17091, +31956=>17092, +31960=>17093, +31962=>17094, +31963=>17095, +31969=>17096, +31970=>17097, +31971=>17098, +31972=>17099, +31973=>17100, +31974=>17101, +31977=>17102, +31978=>17103, +31979=>17104, +31980=>17105, +31981=>17106, +31982=>17107, +31985=>17108, +31987=>17109, +31989=>17110, +31991=>17111, +31994=>17112, +31996=>17113, +31997=>17114, +31999=>17115, +32001=>17116, +32003=>17117, +32012=>17118, +32014=>17119, +32015=>17120, +32017=>17121, +32018=>17122, +32022=>17123, +32024=>17124, +32029=>17125, +32030=>17126, +32031=>17127, +32035=>17128, +32036=>17129, +32037=>17130, +32038=>17131, +32040=>17132, +32041=>17133, +32042=>17134, +32044=>17135, +32045=>17136, +32046=>17137, +32052=>17138, +32053=>17139, +32054=>17140, +32055=>17141, +32056=>17142, +32059=>17143, +32061=>17144, +32062=>17145, +32065=>17146, +32067=>17147, +32069=>17148, +32071=>17149, +32072=>17150, +32073=>17151, +32074=>17152, +32075=>17153, +32076=>17154, +32077=>17155, +32079=>17156, +32081=>17157, +32082=>17158, +32083=>17159, +32084=>17160, +32085=>17161, +32086=>17162, +32087=>17163, +32088=>17164, +32089=>17165, +32090=>17166, +32091=>17167, +32092=>17168, +32095=>17169, +32096=>17170, +32099=>17171, +32100=>17172, +32101=>17173, +32103=>17174, +32105=>17175, +32106=>17176, +32107=>17177, +32108=>17178, +32109=>17179, +32111=>17180, +32112=>17181, +32116=>17182, +32117=>17183, +32120=>17184, +32122=>17185, +32123=>17186, +32124=>17187, +32125=>17188, +32126=>17189, +32127=>17190, +32128=>17191, +32130=>17192, +32132=>17193, +32133=>17194, +32135=>17195, +32138=>17196, +32139=>17197, +32140=>17198, +32141=>17199, +32142=>17200, +32144=>17201, +32145=>17202, +32146=>17203, +32148=>17204, +32149=>17205, +32150=>17206, +32151=>17207, +32152=>17208, +32153=>17209, +32154=>17210, +32155=>17211, +32157=>17212, +32159=>17213, +32160=>17214, +32161=>17215, +32164=>17216, +32165=>17217, +32167=>17218, +32168=>17219, +32169=>17220, +32170=>17221, +32175=>17222, +32181=>17223, +32182=>17224, +32183=>17225, +32188=>17226, +32192=>17227, +32193=>17228, +32194=>17229, +32195=>17230, +32197=>17231, +32198=>17232, +32200=>17233, +32201=>17234, +32204=>17235, +32205=>17236, +32206=>17237, +32207=>17238, +32208=>17239, +32211=>17240, +32213=>17241, +32214=>17242, +32218=>17243, +32219=>17244, +32220=>17245, +32223=>17246, +32226=>17247, +32228=>17248, +32229=>17249, +32231=>17250, +32234=>17251, +32235=>17252, +32237=>17253, +32238=>17254, +32240=>17255, +32243=>17256, +32245=>17257, +32247=>17258, +32248=>17259, +32250=>17260, +32252=>17261, +32253=>17262, +32254=>17263, +32255=>17264, +32256=>17265, +32257=>17266, +32258=>17267, +32259=>17268, +32260=>17269, +32261=>17270, +32262=>17271, +32263=>17272, +32268=>17273, +32269=>17274, +32270=>17275, +32271=>17276, +32274=>17277, +32275=>17278, +32276=>17279, +32277=>17280, +32278=>17281, +32279=>17282, +32280=>17283, +32281=>17284, +32282=>17285, +32284=>17286, +32288=>17287, +32289=>17288, +32290=>17289, +32292=>17290, +32293=>17291, +32294=>17292, +32296=>17293, +32297=>17294, +32298=>17295, +32300=>17296, +32303=>17297, +32304=>17298, +32307=>17299, +32312=>17300, +32314=>17301, +32316=>17302, +32319=>17303, +32320=>17304, +32322=>17305, +32323=>17306, +32324=>17307, +32328=>17308, +32329=>17309, +32330=>17310, +32331=>17311, +32332=>17312, +32333=>17313, +32334=>17314, +32335=>17315, +32336=>17316, +32337=>17317, +32339=>17318, +32342=>17319, +32343=>17320, +32344=>17321, +32345=>17322, +32347=>17323, +32348=>17324, +32349=>17325, +32351=>17326, +32352=>17327, +32353=>17328, +32355=>17329, +32356=>17330, +32357=>17331, +32358=>17332, +32359=>17333, +32360=>17334, +32364=>17335, +32369=>17336, +32370=>17337, +32372=>17338, +32373=>17339, +32374=>17340, +32375=>17341, +32376=>17342, +32378=>17343, +32379=>17344, +32383=>17345, +32384=>17346, +32385=>17347, +32387=>17348, +32388=>17349, +32389=>17350, +32390=>17351, +32391=>17352, +32393=>17353, +32395=>17354, +32398=>17355, +32400=>17356, +32401=>17357, +32402=>17358, +32405=>17359, +32407=>17360, +32409=>17361, +32410=>17362, +32413=>17363, +32414=>17364, +32430=>17365, +32436=>17366, +32443=>17367, +32444=>17368, +32470=>17369, +32484=>17370, +32492=>17371, +32505=>17372, +32522=>17373, +32528=>17374, +32542=>17375, +32567=>17376, +32569=>17377, +32571=>17378, +32572=>17379, +32573=>17380, +32574=>17381, +32575=>17382, +32576=>17383, +32577=>17384, +32579=>17385, +32582=>17386, +32583=>17387, +32584=>17388, +32585=>17389, +32586=>17390, +32587=>17391, +32589=>17392, +32591=>17393, +32594=>17394, +32595=>17395, +32598=>17396, +32601=>17397, +32603=>17398, +32604=>17399, +32605=>17400, +32606=>17401, +32608=>17402, +32611=>17403, +32612=>17404, +32613=>17405, +32614=>17406, +32615=>17407, +32619=>17408, +32620=>17409, +32621=>17410, +32623=>17411, +32627=>17412, +32629=>17413, +32630=>17414, +32632=>17415, +32634=>17416, +32635=>17417, +32636=>17418, +32637=>17419, +32639=>17420, +32640=>17421, +32642=>17422, +32643=>17423, +32644=>17424, +32647=>17425, +32649=>17426, +32651=>17427, +32653=>17428, +32655=>17429, +32656=>17430, +32657=>17431, +32658=>17432, +32659=>17433, +32661=>17434, +32662=>17435, +32663=>17436, +32664=>17437, +32665=>17438, +32667=>17439, +32668=>17440, +32672=>17441, +32674=>17442, +32675=>17443, +32678=>17444, +32680=>17445, +32682=>17446, +32683=>17447, +32684=>17448, +32685=>17449, +32686=>17450, +32689=>17451, +32691=>17452, +32692=>17453, +32693=>17454, +32694=>17455, +32695=>17456, +32698=>17457, +32699=>17458, +32702=>17459, +32704=>17460, +32706=>17461, +32707=>17462, +32708=>17463, +32710=>17464, +32711=>17465, +32712=>17466, +32713=>17467, +32715=>17468, +32717=>17469, +32719=>17470, +32720=>17471, +32721=>17472, +32723=>17473, +32726=>17474, +32727=>17475, +32729=>17476, +32730=>17477, +32731=>17478, +32732=>17479, +32733=>17480, +32734=>17481, +32738=>17482, +32739=>17483, +32740=>17484, +32743=>17485, +32744=>17486, +32746=>17487, +32747=>17488, +32748=>17489, +32749=>17490, +32751=>17491, +32754=>17492, +32756=>17493, +32757=>17494, +32758=>17495, +32759=>17496, +32760=>17497, +32762=>17498, +32765=>17499, +32766=>17500, +32767=>17501, +32770=>17502, +32775=>17503, +32776=>17504, +32777=>17505, +32778=>17506, +32782=>17507, +32783=>17508, +32785=>17509, +32787=>17510, +32794=>17511, +32795=>17512, +32797=>17513, +32798=>17514, +32799=>17515, +32801=>17516, +32803=>17517, +32804=>17518, +32811=>17519, +32813=>17520, +32815=>17521, +32816=>17522, +32818=>17523, +32820=>17524, +32825=>17525, +32826=>17526, +32828=>17527, +32830=>17528, +32832=>17529, +32833=>17530, +32836=>17531, +32837=>17532, +32839=>17533, +32840=>17534, +32841=>17535, +32846=>17536, +32847=>17537, +32848=>17538, +32849=>17539, +32851=>17540, +32853=>17541, +32855=>17542, +32857=>17543, +32859=>17544, +32860=>17545, +32861=>17546, +32863=>17547, +32864=>17548, +32865=>17549, +32866=>17550, +32867=>17551, +32868=>17552, +32869=>17553, +32870=>17554, +32871=>17555, +32872=>17556, +32875=>17557, +32876=>17558, +32877=>17559, +32878=>17560, +32884=>17561, +32888=>17562, +32890=>17563, +32891=>17564, +32892=>17565, +32897=>17566, +32898=>17567, +32904=>17568, +32906=>17569, +32909=>17570, +32910=>17571, +32911=>17572, +32912=>17573, +32913=>17574, +32914=>17575, +32916=>17576, +32917=>17577, +32919=>17578, +32921=>17579, +32926=>17580, +32931=>17581, +32934=>17582, +32935=>17583, +32936=>17584, +32940=>17585, +32944=>17586, +32947=>17587, +32949=>17588, +32950=>17589, +32952=>17590, +32953=>17591, +32955=>17592, +32965=>17593, +32967=>17594, +32968=>17595, +32969=>17596, +32970=>17597, +32971=>17598, +32975=>17599, +32976=>17600, +32977=>17601, +32978=>17602, +32979=>17603, +32980=>17604, +32981=>17605, +32984=>17606, +32991=>17607, +32992=>17608, +32994=>17609, +32995=>17610, +32998=>17611, +33006=>17612, +33013=>17613, +33015=>17614, +33017=>17615, +33019=>17616, +33022=>17617, +33023=>17618, +33024=>17619, +33025=>17620, +33027=>17621, +33028=>17622, +33031=>17623, +33032=>17624, +33035=>17625, +33036=>17626, +33045=>17627, +33047=>17628, +33049=>17629, +33052=>17630, +33053=>17631, +33055=>17632, +33056=>17633, +33057=>17634, +33058=>17635, +33059=>17636, +33060=>17637, +33061=>17638, +33062=>17639, +33063=>17640, +33064=>17641, +33065=>17642, +33066=>17643, +33067=>17644, +33069=>17645, +33070=>17646, +33072=>17647, +33075=>17648, +33076=>17649, +33077=>17650, +33079=>17651, +33082=>17652, +33083=>17653, +33084=>17654, +33085=>17655, +33087=>17656, +33088=>17657, +33089=>17658, +33090=>17659, +33091=>17660, +33092=>17661, +33093=>17662, +33095=>17663, +33097=>17664, +33101=>17665, +33103=>17666, +33106=>17667, +33111=>17668, +33112=>17669, +33115=>17670, +33116=>17671, +33117=>17672, +33118=>17673, +33119=>17674, +33122=>17675, +33123=>17676, +33124=>17677, +33128=>17678, +33130=>17679, +33132=>17680, +33135=>17681, +33138=>17682, +33139=>17683, +33141=>17684, +33142=>17685, +33143=>17686, +33153=>17687, +33155=>17688, +33156=>17689, +33157=>17690, +33158=>17691, +33159=>17692, +33161=>17693, +33163=>17694, +33164=>17695, +33165=>17696, +33166=>17697, +33168=>17698, +33170=>17699, +33171=>17700, +33172=>17701, +33173=>17702, +33174=>17703, +33175=>17704, +33177=>17705, +33182=>17706, +33183=>17707, +33185=>17708, +33186=>17709, +33188=>17710, +33189=>17711, +33191=>17712, +33195=>17713, +33196=>17714, +33197=>17715, +33198=>17716, +33199=>17717, +33200=>17718, +33201=>17719, +33202=>17720, +33204=>17721, +33205=>17722, +33206=>17723, +33207=>17724, +33208=>17725, +33209=>17726, +33212=>17727, +33220=>17728, +33221=>17729, +33223=>17730, +33224=>17731, +33227=>17732, +33230=>17733, +33232=>17734, +33233=>17735, +33234=>17736, +33235=>17737, +33236=>17738, +33237=>17739, +33238=>17740, +33239=>17741, +33241=>17742, +33243=>17743, +33244=>17744, +33245=>17745, +33246=>17746, +33249=>17747, +33250=>17748, +33252=>17749, +33253=>17750, +33254=>17751, +33257=>17752, +33259=>17753, +33262=>17754, +33263=>17755, +33264=>17756, +33265=>17757, +33266=>17758, +33269=>17759, +33270=>17760, +33271=>17761, +33272=>17762, +33273=>17763, +33277=>17764, +33279=>17765, +33283=>17766, +33291=>17767, +33294=>17768, +33295=>17769, +33297=>17770, +33299=>17771, +33301=>17772, +33302=>17773, +33303=>17774, +33304=>17775, +33305=>17776, +33306=>17777, +33309=>17778, +33312=>17779, +33316=>17780, +33317=>17781, +33318=>17782, +33319=>17783, +33321=>17784, +33326=>17785, +33330=>17786, +33338=>17787, +33340=>17788, +33341=>17789, +33343=>17790, +33344=>17791, +33345=>17792, +33346=>17793, +33347=>17794, +33349=>17795, +33350=>17796, +33352=>17797, +33354=>17798, +33356=>17799, +33357=>17800, +33358=>17801, +33360=>17802, +33361=>17803, +33362=>17804, +33363=>17805, +33364=>17806, +33365=>17807, +33366=>17808, +33367=>17809, +33371=>17810, +33372=>17811, +33373=>17812, +33374=>17813, +33376=>17814, +33377=>17815, +33378=>17816, +33379=>17817, +33381=>17818, +33383=>17819, +33385=>17820, +33386=>17821, +33388=>17822, +33389=>17823, +33397=>17824, +33398=>17825, +12171=>17826, +33400=>17826, +33403=>17827, +33404=>17828, +33408=>17829, +33409=>17830, +33411=>17831, +33413=>17832, +33414=>17833, +33415=>17834, +33417=>17835, +33420=>17836, +33424=>17837, +33427=>17838, +33428=>17839, +33429=>17840, +33430=>17841, +33434=>17842, +33435=>17843, +33438=>17844, +33440=>17845, +33442=>17846, +33443=>17847, +33447=>17848, +33458=>17849, +33461=>17850, +33462=>17851, +33466=>17852, +33468=>17853, +33471=>17854, +33472=>17855, +33474=>17856, +33475=>17857, +33477=>17858, +33478=>17859, +33481=>17860, +33488=>17861, +33494=>17862, +33497=>17863, +33498=>17864, +33501=>17865, +33506=>17866, +33512=>17867, +33513=>17868, +33514=>17869, +33516=>17870, +33517=>17871, +33518=>17872, +33520=>17873, +33522=>17874, +33523=>17875, +33525=>17876, +33526=>17877, +33528=>17878, +33530=>17879, +33532=>17880, +33533=>17881, +33534=>17882, +33535=>17883, +33536=>17884, +33546=>17885, +33547=>17886, +33549=>17887, +33552=>17888, +33554=>17889, +33555=>17890, +33558=>17891, +33560=>17892, +33561=>17893, +33565=>17894, +33566=>17895, +33567=>17896, +33568=>17897, +33569=>17898, +33570=>17899, +33571=>17900, +33572=>17901, +33573=>17902, +33574=>17903, +33577=>17904, +33578=>17905, +33582=>17906, +33584=>17907, +33586=>17908, +33591=>17909, +33595=>17910, +33597=>17911, +33598=>17912, +33599=>17913, +33601=>17914, +33602=>17915, +33604=>17916, +33605=>17917, +33608=>17918, +33610=>17919, +33611=>17920, +33612=>17921, +33613=>17922, +33614=>17923, +33619=>17924, +33621=>17925, +33622=>17926, +33623=>17927, +33624=>17928, +33625=>17929, +33629=>17930, +33634=>17931, +33648=>17932, +33649=>17933, +33650=>17934, +33651=>17935, +33652=>17936, +33653=>17937, +33654=>17938, +33657=>17939, +33658=>17940, +33662=>17941, +33663=>17942, +33664=>17943, +33665=>17944, +33666=>17945, +33667=>17946, +33668=>17947, +33671=>17948, +33672=>17949, +33675=>17950, +33676=>17951, +33677=>17952, +33679=>17953, +33680=>17954, +33681=>17955, +33684=>17956, +33685=>17957, +33687=>17958, +33689=>17959, +33690=>17960, +33693=>17961, +33695=>17962, +33697=>17963, +33699=>17964, +33700=>17965, +33701=>17966, +33702=>17967, +33708=>17968, +33709=>17969, +33710=>17970, +33711=>17971, +33717=>17972, +33723=>17973, +33726=>17974, +33727=>17975, +33730=>17976, +33731=>17977, +33732=>17978, +33734=>17979, +33736=>17980, +33737=>17981, +33739=>17982, +33741=>17983, +33742=>17984, +33744=>17985, +33745=>17986, +33746=>17987, +33747=>17988, +33749=>17989, +33751=>17990, +33753=>17991, +33754=>17992, +33755=>17993, +33758=>17994, +33762=>17995, +33763=>17996, +33764=>17997, +33766=>17998, +33767=>17999, +33768=>18000, +33771=>18001, +33772=>18002, +33773=>18003, +33774=>18004, +33779=>18005, +33780=>18006, +33781=>18007, +33782=>18008, +33783=>18009, +33786=>18010, +33787=>18011, +33788=>18012, +33790=>18013, +33791=>18014, +33792=>18015, +33794=>18016, +33797=>18017, +33800=>18018, +33801=>18019, +33808=>18020, +33810=>18021, +33811=>18022, +33812=>18023, +33813=>18024, +33814=>18025, +33815=>18026, +33817=>18027, +33818=>18028, +33819=>18029, +33822=>18030, +33823=>18031, +33824=>18032, +33825=>18033, +33826=>18034, +33827=>18035, +33833=>18036, +33834=>18037, +33835=>18038, +33837=>18039, +33838=>18040, +33839=>18041, +33840=>18042, +33842=>18043, +33843=>18044, +33844=>18045, +33846=>18046, +33847=>18047, +33849=>18048, +33850=>18049, +33851=>18050, +33854=>18051, +33855=>18052, +33856=>18053, +33857=>18054, +33858=>18055, +33859=>18056, +33860=>18057, +33861=>18058, +33863=>18059, +33864=>18060, +33866=>18061, +33867=>18062, +33868=>18063, +33869=>18064, +33870=>18065, +33871=>18066, +33872=>18067, +33875=>18068, +33876=>18069, +33877=>18070, +33878=>18071, +33880=>18072, +33885=>18073, +33886=>18074, +33887=>18075, +33888=>18076, +33890=>18077, +33893=>18078, +33895=>18079, +33896=>18080, +33898=>18081, +33902=>18082, +33904=>18083, +33906=>18084, +33908=>18085, +33913=>18086, +33915=>18087, +33916=>18088, +33917=>18089, +33918=>18090, +33919=>18091, +33920=>18092, +33921=>18093, +33923=>18094, +33924=>18095, +33925=>18096, +33926=>18097, +33930=>18098, +33933=>18099, +33935=>18100, +33936=>18101, +33937=>18102, +33938=>18103, +33941=>18104, +33942=>18105, +33944=>18106, +33946=>18107, +33947=>18108, +33949=>18109, +33950=>18110, +33951=>18111, +33952=>18112, +33954=>18113, +33955=>18114, +33956=>18115, +33957=>18116, +33958=>18117, +33959=>18118, +33960=>18119, +33961=>18120, +33962=>18121, +33963=>18122, +33964=>18123, +33965=>18124, +33966=>18125, +33968=>18126, +33969=>18127, +33971=>18128, +33973=>18129, +33974=>18130, +33975=>18131, +33979=>18132, +33982=>18133, +33986=>18134, +33987=>18135, +33989=>18136, +33990=>18137, +33991=>18138, +33992=>18139, +33996=>18140, +33998=>18141, +33999=>18142, +34002=>18143, +34004=>18144, +34005=>18145, +34007=>18146, +34008=>18147, +34009=>18148, +34010=>18149, +34011=>18150, +34012=>18151, +34014=>18152, +34017=>18153, +34018=>18154, +34020=>18155, +34023=>18156, +34024=>18157, +34025=>18158, +34026=>18159, +34027=>18160, +34029=>18161, +34033=>18162, +34034=>18163, +34035=>18164, +34036=>18165, +34037=>18166, +34038=>18167, +34039=>18168, +34040=>18169, +34041=>18170, +34042=>18171, +34043=>18172, +34046=>18173, +34048=>18174, +34049=>18175, +34050=>18176, +34051=>18177, +34052=>18178, +34053=>18179, +34054=>18180, +34055=>18181, +34056=>18182, +34057=>18183, +34058=>18184, +34059=>18185, +34061=>18186, +34062=>18187, +34063=>18188, +34064=>18189, +34066=>18190, +34069=>18191, +34070=>18192, +34072=>18193, +34073=>18194, +34075=>18195, +34076=>18196, +34077=>18197, +34080=>18198, +34082=>18199, +34084=>18200, +34085=>18201, +34087=>18202, +34088=>18203, +34089=>18204, +34090=>18205, +34094=>18206, +34095=>18207, +34096=>18208, +34097=>18209, +34098=>18210, +34099=>18211, +34100=>18212, +34101=>18213, +34102=>18214, +34110=>18215, +34111=>18216, +34112=>18217, +34114=>18218, +34116=>18219, +34117=>18220, +34119=>18221, +34123=>18222, +34124=>18223, +34125=>18224, +34127=>18225, +34128=>18226, +34129=>18227, +34132=>18228, +34135=>18229, +34138=>18230, +34139=>18231, +34140=>18232, +34141=>18233, +34143=>18234, +34144=>18235, +34145=>18236, +34147=>18237, +34149=>18238, +34150=>18239, +34151=>18240, +34155=>18241, +34156=>18242, +34158=>18243, +34159=>18244, +34160=>18245, +34161=>18246, +34163=>18247, +34165=>18248, +34166=>18249, +34168=>18250, +34172=>18251, +34173=>18252, +34175=>18253, +34176=>18254, +34177=>18255, +34178=>18256, +34179=>18257, +34182=>18258, +34185=>18259, +34187=>18260, +34189=>18261, +34190=>18262, +34192=>18263, +34194=>18264, +34195=>18265, +34197=>18266, +34198=>18267, +34199=>18268, +34200=>18269, +34201=>18270, +34202=>18271, +34205=>18272, +34206=>18273, +34208=>18274, +34209=>18275, +34210=>18276, +34211=>18277, +34213=>18278, +34215=>18279, +34219=>18280, +34220=>18281, +34221=>18282, +34225=>18283, +34226=>18284, +34227=>18285, +34228=>18286, +34229=>18287, +34230=>18288, +34232=>18289, +34235=>18290, +34236=>18291, +34237=>18292, +34238=>18293, +34239=>18294, +34240=>18295, +34242=>18296, +34243=>18297, +34244=>18298, +34245=>18299, +34246=>18300, +34247=>18301, +34248=>18302, +34250=>18303, +34251=>18304, +34252=>18305, +34257=>18306, +34258=>18307, +34260=>18308, +34262=>18309, +34263=>18310, +34264=>18311, +34265=>18312, +34266=>18313, +34267=>18314, +34270=>18315, +34271=>18316, +34272=>18317, +34273=>18318, +34274=>18319, +34275=>18320, +34278=>18321, +34279=>18322, +34280=>18323, +34283=>18324, +34284=>18325, +34285=>18326, +34286=>18327, +34287=>18328, +34288=>18329, +34289=>18330, +34290=>18331, +34291=>18332, +34293=>18333, +34295=>18334, +34296=>18335, +34300=>18336, +34301=>18337, +34302=>18338, +34304=>18339, +34305=>18340, +34306=>18341, +34307=>18342, +34312=>18343, +34313=>18344, +34314=>18345, +34316=>18346, +34317=>18347, +34318=>18348, +34319=>18349, +34320=>18350, +34322=>18351, +34323=>18352, +34324=>18353, +34325=>18354, +34327=>18355, +34328=>18356, +34329=>18357, +34331=>18358, +34332=>18359, +34333=>18360, +34335=>18361, +34336=>18362, +34337=>18363, +34339=>18364, +34340=>18365, +34341=>18366, +34342=>18367, +34344=>18368, +34346=>18369, +34347=>18370, +34348=>18371, +34350=>18372, +34351=>18373, +34352=>18374, +34353=>18375, +34354=>18376, +34355=>18377, +34356=>18378, +34357=>18379, +34358=>18380, +34359=>18381, +34361=>18382, +34363=>18383, +34365=>18384, +34366=>18385, +34368=>18386, +34369=>18387, +34370=>18388, +34371=>18389, +34372=>18390, +34373=>18391, +34374=>18392, +34375=>18393, +34376=>18394, +34377=>18395, +34378=>18396, +34379=>18397, +34380=>18398, +34386=>18399, +34387=>18400, +34390=>18401, +34391=>18402, +34392=>18403, +34393=>18404, +34395=>18405, +34397=>18406, +34400=>18407, +34401=>18408, +34403=>18409, +34404=>18410, +34405=>18411, +34406=>18412, +34408=>18413, +34409=>18414, +34410=>18415, +34413=>18416, +34415=>18417, +34416=>18418, +34418=>18419, +34419=>18420, +34420=>18421, +34421=>18422, +34422=>18423, +34423=>18424, +34424=>18425, +34435=>18426, +34436=>18427, +34437=>18428, +34438=>18429, +34439=>18430, +34440=>18431, +34441=>18432, +34446=>18433, +34447=>18434, +34448=>18435, +34449=>18436, +34450=>18437, +34452=>18438, +34454=>18439, +34455=>18440, +34456=>18441, +34457=>18442, +34458=>18443, +34459=>18444, +34462=>18445, +34463=>18446, +34464=>18447, +34465=>18448, +34466=>18449, +34469=>18450, +34470=>18451, +34475=>18452, +34477=>18453, +34478=>18454, +34482=>18455, +34483=>18456, +34487=>18457, +34488=>18458, +34489=>18459, +34491=>18460, +34492=>18461, +34493=>18462, +34494=>18463, +34495=>18464, +34497=>18465, +34498=>18466, +34499=>18467, +34501=>18468, +34504=>18469, +34508=>18470, +34509=>18471, +34514=>18472, +34515=>18473, +34517=>18474, +34518=>18475, +34519=>18476, +34522=>18477, +34524=>18478, +34525=>18479, +34528=>18480, +34529=>18481, +34530=>18482, +34531=>18483, +34533=>18484, +34534=>18485, +34535=>18486, +34536=>18487, +34538=>18488, +34539=>18489, +34540=>18490, +34543=>18491, +34549=>18492, +34550=>18493, +34551=>18494, +34555=>18495, +34556=>18496, +34557=>18497, +34559=>18498, +34561=>18499, +34564=>18500, +34565=>18501, +34571=>18502, +34572=>18503, +34574=>18504, +34575=>18505, +34576=>18506, +34577=>18507, +34580=>18508, +34582=>18509, +34585=>18510, +34587=>18511, +34589=>18512, +34591=>18513, +34592=>18514, +34596=>18515, +34598=>18516, +34599=>18517, +34600=>18518, +34602=>18519, +34603=>18520, +34604=>18521, +34605=>18522, +34607=>18523, +34608=>18524, +34610=>18525, +34611=>18526, +34613=>18527, +34614=>18528, +34616=>18529, +34617=>18530, +34618=>18531, +34620=>18532, +34621=>18533, +34624=>18534, +34625=>18535, +34626=>18536, +34627=>18537, +34628=>18538, +34629=>18539, +34630=>18540, +34634=>18541, +34635=>18542, +34637=>18543, +34639=>18544, +34640=>18545, +34641=>18546, +34642=>18547, +34644=>18548, +34646=>18549, +34648=>18550, +34650=>18551, +34651=>18552, +34652=>18553, +34653=>18554, +34654=>18555, +34655=>18556, +34657=>18557, +34658=>18558, +34663=>18559, +34664=>18560, +34665=>18561, +34666=>18562, +34667=>18563, +34668=>18564, +34669=>18565, +34671=>18566, +34673=>18567, +34674=>18568, +34675=>18569, +34677=>18570, +34679=>18571, +34681=>18572, +34682=>18573, +34687=>18574, +34688=>18575, +34689=>18576, +34694=>18577, +34695=>18578, +34697=>18579, +34698=>18580, +34700=>18581, +34702=>18582, +34703=>18583, +34704=>18584, +34705=>18585, +34706=>18586, +34708=>18587, +34709=>18588, +34710=>18589, +34712=>18590, +34713=>18591, +34714=>18592, +34715=>18593, +34716=>18594, +34717=>18595, +34720=>18596, +34721=>18597, +34723=>18598, +34724=>18599, +34725=>18600, +34726=>18601, +34727=>18602, +34729=>18603, +34730=>18604, +34734=>18605, +34736=>18606, +34737=>18607, +34738=>18608, +34740=>18609, +34742=>18610, +34743=>18611, +34744=>18612, +34745=>18613, +34748=>18614, +34750=>18615, +34751=>18616, +34753=>18617, +34754=>18618, +34755=>18619, +34757=>18620, +34759=>18621, +34761=>18622, +34764=>18623, +34765=>18624, +34767=>18625, +34768=>18626, +34772=>18627, +34773=>18628, +34774=>18629, +34775=>18630, +34776=>18631, +34777=>18632, +34778=>18633, +34780=>18634, +34781=>18635, +34782=>18636, +34783=>18637, +34785=>18638, +34786=>18639, +34788=>18640, +34790=>18641, +34791=>18642, +34792=>18643, +34793=>18644, +34795=>18645, +34797=>18646, +34800=>18647, +34801=>18648, +34803=>18649, +34804=>18650, +34805=>18651, +34807=>18652, +34808=>18653, +34810=>18654, +34812=>18655, +34813=>18656, +34815=>18657, +34816=>18658, +34817=>18659, +34818=>18660, +34820=>18661, +34823=>18662, +34824=>18663, +34825=>18664, +34827=>18665, +34828=>18666, +34829=>18667, +34830=>18668, +34831=>18669, +34834=>18670, +34836=>18671, +34839=>18672, +34840=>18673, +34841=>18674, +34842=>18675, +34844=>18676, +34845=>18677, +34846=>18678, +34848=>18679, +34852=>18680, +34853=>18681, +34854=>18682, +34855=>18683, +34856=>18684, +34857=>18685, +34858=>18686, +34859=>18687, +34860=>18688, +34861=>18689, +34862=>18690, +34863=>18691, +34864=>18692, +34867=>18693, +34868=>18694, +34869=>18695, +34871=>18696, +34872=>18697, +34874=>18698, +34877=>18699, +34878=>18700, +34879=>18701, +34881=>18702, +34882=>18703, +34883=>18704, +34887=>18705, +34888=>18706, +34889=>18707, +34891=>18708, +34894=>18709, +34895=>18710, +34896=>18711, +34897=>18712, +34898=>18713, +34901=>18714, +34902=>18715, +34904=>18716, +34906=>18717, +34908=>18718, +34910=>18719, +34911=>18720, +34912=>18721, +34918=>18722, +34919=>18723, +34922=>18724, +34925=>18725, +34927=>18726, +34929=>18727, +34931=>18728, +34932=>18729, +34933=>18730, +34934=>18731, +34936=>18732, +34938=>18733, +34939=>18734, +34940=>18735, +34944=>18736, +34947=>18737, +34950=>18738, +34951=>18739, +34953=>18740, +34954=>18741, +34956=>18742, +34958=>18743, +34959=>18744, +34960=>18745, +34961=>18746, +34963=>18747, +34964=>18748, +34965=>18749, +34967=>18750, +34968=>18751, +34969=>18752, +34970=>18753, +34971=>18754, +34973=>18755, +34974=>18756, +34975=>18757, +34976=>18758, +34977=>18759, +34979=>18760, +34981=>18761, +34982=>18762, +34983=>18763, +34984=>18764, +34985=>18765, +34986=>18766, +34988=>18767, +34990=>18768, +34991=>18769, +34992=>18770, +34994=>18771, +34995=>18772, +34996=>18773, +34997=>18774, +34998=>18775, +35000=>18776, +35001=>18777, +35002=>18778, +35003=>18779, +35005=>18780, +35006=>18781, +35007=>18782, +35008=>18783, +35011=>18784, +35012=>18785, +35015=>18786, +35016=>18787, +35019=>18788, +35020=>18789, +35021=>18790, +35024=>18791, +35025=>18792, +35027=>18793, +35030=>18794, +35031=>18795, +35034=>18796, +35035=>18797, +35038=>18798, +35040=>18799, +35041=>18800, +35046=>18801, +35047=>18802, +35049=>18803, +35050=>18804, +35051=>18805, +35052=>18806, +35053=>18807, +35054=>18808, +35055=>18809, +35058=>18810, +35061=>18811, +35062=>18812, +35063=>18813, +35066=>18814, +35067=>18815, +35071=>18816, +35072=>18817, +35073=>18818, +35075=>18819, +35076=>18820, +35077=>18821, +35078=>18822, +35080=>18823, +35081=>18824, +35083=>18825, +35084=>18826, +35085=>18827, +35086=>18828, +35087=>18829, +35089=>18830, +35092=>18831, +35093=>18832, +35094=>18833, +35095=>18834, +35096=>18835, +35100=>18836, +35101=>18837, +35102=>18838, +35103=>18839, +35104=>18840, +35106=>18841, +35107=>18842, +35108=>18843, +35110=>18844, +35111=>18845, +35112=>18846, +35113=>18847, +35116=>18848, +35117=>18849, +35118=>18850, +35119=>18851, +35121=>18852, +35125=>18853, +35127=>18854, +35129=>18855, +35130=>18856, +35132=>18857, +35133=>18858, +35134=>18859, +35135=>18860, +35136=>18861, +35138=>18862, +35139=>18863, +35141=>18864, +35142=>18865, +35144=>18866, +35145=>18867, +35146=>18868, +35147=>18869, +35148=>18870, +35149=>18871, +35150=>18872, +35151=>18873, +35152=>18874, +35153=>18875, +35154=>18876, +35155=>18877, +35156=>18878, +35157=>18879, +35159=>18880, +35160=>18881, +35161=>18882, +35162=>18883, +35163=>18884, +35164=>18885, +35169=>18886, +35170=>18887, +35171=>18888, +35173=>18889, +35175=>18890, +35176=>18891, +35177=>18892, +35179=>18893, +35181=>18894, +35182=>18895, +35184=>18896, +35185=>18897, +35187=>18898, +35188=>18899, +35189=>18900, +35190=>18901, +35191=>18902, +35192=>18903, +35193=>18904, +35194=>18905, +35196=>18906, +35197=>18907, +12177=>18908, +35198=>18908, +35200=>18909, +35202=>18910, +35204=>18911, +35205=>18912, +35207=>18913, +35208=>18914, +35209=>18915, +35210=>18916, +35212=>18917, +35213=>18918, +35214=>18919, +35216=>18920, +35217=>18921, +35218=>18922, +35220=>18923, +35221=>18924, +35223=>18925, +35225=>18926, +35226=>18927, +35227=>18928, +35228=>18929, +35229=>18930, +35230=>18931, +35231=>18932, +35232=>18933, +35234=>18934, +35235=>18935, +35236=>18936, +35237=>18937, +35239=>18938, +35240=>18939, +35241=>18940, +35243=>18941, +35245=>18942, +35246=>18943, +35248=>18944, +35249=>18945, +35251=>18946, +35252=>18947, +35253=>18948, +35254=>18949, +35256=>18950, +35257=>18951, +35259=>18952, +35260=>18953, +35262=>18954, +35267=>18955, +35277=>18956, +35283=>18957, +35284=>18958, +35285=>18959, +35287=>18960, +35288=>18961, +35289=>18962, +35291=>18963, +35293=>18964, +35295=>18965, +35296=>18966, +35297=>18967, +35298=>18968, +35300=>18969, +35303=>18970, +35304=>18971, +35305=>18972, +35306=>18973, +35308=>18974, +35309=>18975, +35310=>18976, +35312=>18977, +35313=>18978, +35314=>18979, +35317=>18980, +35319=>18981, +35321=>18982, +35322=>18983, +35323=>18984, +35324=>18985, +35325=>18986, +35326=>18987, +35327=>18988, +35332=>18989, +35333=>18990, +35334=>18991, +35337=>18992, +35339=>18993, +35341=>18994, +35343=>18995, +35345=>18996, +35346=>18997, +35348=>18998, +35351=>18999, +35353=>19000, +35354=>19001, +35356=>19002, +35358=>19003, +35360=>19004, +35361=>19005, +35362=>19006, +35364=>19007, +35366=>19008, +35367=>19009, +35368=>19010, +35369=>19011, +35371=>19012, +35372=>19013, +35374=>19014, +35375=>19015, +35376=>19016, +35378=>19017, +35379=>19018, +35381=>19019, +35383=>19020, +35384=>19021, +35385=>19022, +35387=>19023, +35388=>19024, +35389=>19025, +35391=>19026, +35392=>19027, +35394=>19028, +35395=>19029, +35396=>19030, +35397=>19031, +35399=>19032, +35401=>19033, +35402=>19034, +35403=>19035, +35404=>19036, +35405=>19037, +35407=>19038, +35409=>19039, +35411=>19040, +35414=>19041, +35415=>19042, +35417=>19043, +35418=>19044, +35420=>19045, +35421=>19046, +35423=>19047, +35424=>19048, +35428=>19049, +35429=>19050, +35431=>19051, +35432=>19052, +35434=>19053, +35439=>19054, +35444=>19055, +35446=>19056, +35447=>19057, +35448=>19058, +35450=>19059, +35451=>19060, +35453=>19061, +35454=>19062, +35456=>19063, +35457=>19064, +35458=>19065, +35459=>19066, +35464=>19067, +35467=>19068, +35468=>19069, +35470=>19070, +35471=>19071, +35472=>19072, +35476=>19073, +35478=>19074, +35479=>19075, +35481=>19076, +35483=>19077, +35484=>19078, +35485=>19079, +35487=>19080, +35490=>19081, +35495=>19082, +35497=>19083, +35498=>19084, +35499=>19085, +35501=>19086, +35502=>19087, +35503=>19088, +35505=>19089, +35507=>19090, +35508=>19091, +35509=>19092, +35511=>19093, +35512=>19094, +35514=>19095, +35515=>19096, +35517=>19097, +35518=>19098, +35520=>19099, +35521=>19100, +35523=>19101, +35525=>19102, +35526=>19103, +35528=>19104, +35530=>19105, +35532=>19106, +35534=>19107, +35536=>19108, +35539=>19109, +35540=>19110, +35541=>19111, +35544=>19112, +35545=>19113, +35546=>19114, +35549=>19115, +35551=>19116, +35552=>19117, +35553=>19118, +35555=>19119, +35557=>19120, +35560=>19121, +35561=>19122, +35562=>19123, +35564=>19124, +35567=>19125, +35568=>19126, +35570=>19127, +35572=>19128, +35573=>19129, +35577=>19130, +35579=>19131, +35581=>19132, +35583=>19133, +35587=>19134, +35590=>19135, +35592=>19136, +35593=>19137, +35595=>19138, +35596=>19139, +35597=>19140, +35599=>19141, +35601=>19142, +35602=>19143, +35603=>19144, +35605=>19145, +35608=>19146, +35612=>19147, +35614=>19148, +35615=>19149, +35616=>19150, +35618=>19151, +35619=>19152, +35620=>19153, +35621=>19154, +35623=>19155, +35625=>19156, +35626=>19157, +35630=>19158, +35631=>19159, +35632=>19160, +35633=>19161, +35634=>19162, +35636=>19163, +35637=>19164, +35638=>19165, +35639=>19166, +35640=>19167, +35642=>19168, +35643=>19169, +35644=>19170, +35645=>19171, +35647=>19172, +35648=>19173, +35649=>19174, +35650=>19175, +35651=>19176, +35652=>19177, +35653=>19178, +35654=>19179, +35655=>19180, +35656=>19181, +35658=>19182, +35659=>19183, +35660=>19184, +35661=>19185, +35664=>19186, +35665=>19187, +35666=>19188, +35667=>19189, +35668=>19190, +35669=>19191, +35671=>19192, +35675=>19193, +35677=>19194, +35678=>19195, +35679=>19196, +35680=>19197, +35681=>19198, +35682=>19199, +35683=>19200, +35684=>19201, +35685=>19202, +35687=>19203, +35688=>19204, +35689=>19205, +35690=>19206, +35693=>19207, +35694=>19208, +35697=>19209, +35698=>19210, +35699=>19211, +35701=>19212, +35702=>19213, +35704=>19214, +35705=>19215, +35706=>19216, +35707=>19217, +35708=>19218, +35710=>19219, +35711=>19220, +35713=>19221, +35714=>19222, +35715=>19223, +35716=>19224, +35717=>19225, +35718=>19226, +35719=>19227, +35720=>19228, +35721=>19229, +35723=>19230, +35724=>19231, +35725=>19232, +35727=>19233, +35728=>19234, +35729=>19235, +35732=>19236, +35735=>19237, +35736=>19238, +35737=>19239, +35738=>19240, +35739=>19241, +35741=>19242, +35743=>19243, +35756=>19244, +35761=>19245, +35771=>19246, +35783=>19247, +35792=>19248, +35818=>19249, +35849=>19250, +35870=>19251, +35896=>19252, +35897=>19253, +35898=>19254, +35899=>19255, +35900=>19256, +35901=>19257, +35902=>19258, +35903=>19259, +35904=>19260, +35906=>19261, +35907=>19262, +35908=>19263, +35909=>19264, +35914=>19265, +35915=>19266, +35917=>19267, +35918=>19268, +35919=>19269, +35921=>19270, +35922=>19271, +35923=>19272, +35924=>19273, +35926=>19274, +35927=>19275, +35928=>19276, +35929=>19277, +35931=>19278, +35932=>19279, +35933=>19280, +35934=>19281, +35935=>19282, +35936=>19283, +35939=>19284, +35940=>19285, +35941=>19286, +35942=>19287, +35943=>19288, +35944=>19289, +35945=>19290, +35948=>19291, +35949=>19292, +35950=>19293, +35951=>19294, +35952=>19295, +35953=>19296, +35954=>19297, +35956=>19298, +35957=>19299, +35958=>19300, +35959=>19301, +35963=>19302, +35964=>19303, +35965=>19304, +35966=>19305, +35967=>19306, +35968=>19307, +35969=>19308, +35971=>19309, +35972=>19310, +35974=>19311, +35975=>19312, +35976=>19313, +35979=>19314, +35981=>19315, +35982=>19316, +35983=>19317, +35984=>19318, +35985=>19319, +35986=>19320, +35987=>19321, +35989=>19322, +35990=>19323, +35991=>19324, +35993=>19325, +35994=>19326, +35995=>19327, +35996=>19328, +35999=>19329, +36003=>19330, +36004=>19331, +36005=>19332, +36006=>19333, +36013=>19334, +36014=>19335, +36017=>19336, +36021=>19337, +36025=>19338, +36030=>19339, +36038=>19340, +36041=>19341, +36043=>19342, +36044=>19343, +36045=>19344, +36046=>19345, +36047=>19346, +36048=>19347, +36052=>19348, +36054=>19349, +36055=>19350, +36056=>19351, +36057=>19352, +36059=>19353, +36061=>19354, +36063=>19355, +36069=>19356, +36072=>19357, +36073=>19358, +36078=>19359, +36079=>19360, +36080=>19361, +36081=>19362, +36082=>19363, +36083=>19364, +36085=>19365, +36086=>19366, +36087=>19367, +36088=>19368, +36089=>19369, +36095=>19370, +36096=>19371, +36097=>19372, +36098=>19373, +36099=>19374, +36102=>19375, +36103=>19376, +36105=>19377, +36108=>19378, +36110=>19379, +36113=>19380, +36114=>19381, +36115=>19382, +36116=>19383, +36117=>19384, +36119=>19385, +36120=>19386, +36121=>19387, +36122=>19388, +36128=>19389, +36177=>19390, +36178=>19391, +36183=>19392, +36191=>19393, +36197=>19394, +36200=>19395, +36201=>19396, +36202=>19397, +36204=>19398, +36206=>19399, +36207=>19400, +36209=>19401, +36210=>19402, +36216=>19403, +36217=>19404, +36218=>19405, +36219=>19406, +36220=>19407, +36221=>19408, +36222=>19409, +36223=>19410, +36224=>19411, +36226=>19412, +36227=>19413, +36230=>19414, +36231=>19415, +36232=>19416, +36233=>19417, +36236=>19418, +36237=>19419, +36238=>19420, +36239=>19421, +36240=>19422, +36242=>19423, +36243=>19424, +36246=>19425, +36247=>19426, +36248=>19427, +36250=>19428, +36251=>19429, +36252=>19430, +36253=>19431, +36254=>19432, +36256=>19433, +36257=>19434, +36258=>19435, +36260=>19436, +36261=>19437, +36262=>19438, +36263=>19439, +36265=>19440, +36266=>19441, +36267=>19442, +36268=>19443, +36269=>19444, +36270=>19445, +36271=>19446, +36272=>19447, +36278=>19448, +36279=>19449, +36281=>19450, +36283=>19451, +36285=>19452, +36288=>19453, +36289=>19454, +36290=>19455, +36293=>19456, +36295=>19457, +36296=>19458, +36297=>19459, +36298=>19460, +36301=>19461, +36304=>19462, +36306=>19463, +36307=>19464, +36308=>19465, +36309=>19466, +36312=>19467, +36313=>19468, +36316=>19469, +36320=>19470, +36321=>19471, +36322=>19472, +36325=>19473, +36326=>19474, +36327=>19475, +36329=>19476, +36333=>19477, +36334=>19478, +36336=>19479, +36337=>19480, +36338=>19481, +36340=>19482, +36342=>19483, +36348=>19484, +36350=>19485, +36351=>19486, +36352=>19487, +36353=>19488, +36354=>19489, +36355=>19490, +36356=>19491, +36358=>19492, +36359=>19493, +36360=>19494, +36363=>19495, +36365=>19496, +36366=>19497, +36369=>19498, +36370=>19499, +36371=>19500, +36373=>19501, +36374=>19502, +36375=>19503, +36376=>19504, +36377=>19505, +36378=>19506, +36379=>19507, +36380=>19508, +36384=>19509, +36385=>19510, +36388=>19511, +36389=>19512, +36390=>19513, +36391=>19514, +36392=>19515, +36395=>19516, +36397=>19517, +36400=>19518, +36402=>19519, +36403=>19520, +36406=>19521, +36407=>19522, +36408=>19523, +36411=>19524, +36412=>19525, +36414=>19526, +36415=>19527, +36419=>19528, +36421=>19529, +36422=>19530, +36429=>19531, +36430=>19532, +36431=>19533, +36432=>19534, +36435=>19535, +36436=>19536, +36438=>19537, +36439=>19538, +36440=>19539, +36442=>19540, +36443=>19541, +36444=>19542, +36445=>19543, +36446=>19544, +36447=>19545, +36448=>19546, +36449=>19547, +36450=>19548, +36452=>19549, +36453=>19550, +36455=>19551, +36456=>19552, +36458=>19553, +36459=>19554, +36462=>19555, +36465=>19556, +36467=>19557, +36469=>19558, +36471=>19559, +36472=>19560, +36473=>19561, +36475=>19562, +36477=>19563, +36478=>19564, +36480=>19565, +36482=>19566, +36483=>19567, +36484=>19568, +36486=>19569, +36488=>19570, +36492=>19571, +36494=>19572, +36501=>19573, +36502=>19574, +36503=>19575, +36504=>19576, +36505=>19577, +36507=>19578, +36509=>19579, +36511=>19580, +36512=>19581, +36514=>19582, +36515=>19583, +36516=>19584, +36519=>19585, +36520=>19586, +36521=>19587, +36525=>19588, +36526=>19589, +36528=>19590, +36529=>19591, +36531=>19592, +36532=>19593, +36533=>19594, +36534=>19595, +36535=>19596, +36536=>19597, +36537=>19598, +36539=>19599, +36540=>19600, +36541=>19601, +36542=>19602, +36543=>19603, +36545=>19604, +36546=>19605, +36547=>19606, +36548=>19607, +36549=>19608, +36550=>19609, +36551=>19610, +36552=>19611, +36553=>19612, +36559=>19613, +36560=>19614, +36561=>19615, +36563=>19616, +36565=>19617, +36566=>19618, +36567=>19619, +36568=>19620, +36569=>19621, +36570=>19622, +36572=>19623, +36573=>19624, +36574=>19625, +36576=>19626, +36577=>19627, +36578=>19628, +36579=>19629, +36581=>19630, +36582=>19631, +36583=>19632, +36584=>19633, +36585=>19634, +36586=>19635, +36588=>19636, +36589=>19637, +36590=>19638, +36591=>19639, +36592=>19640, +36593=>19641, +36595=>19642, +36596=>19643, +36597=>19644, +36598=>19645, +36599=>19646, +36605=>19647, +36607=>19648, +36608=>19649, +36609=>19650, +36610=>19651, +36612=>19652, +36614=>19653, +36616=>19654, +36619=>19655, +36620=>19656, +36621=>19657, +36622=>19658, +36623=>19659, +36624=>19660, +36625=>19661, +36627=>19662, +36630=>19663, +36631=>19664, +36632=>19665, +36633=>19666, +36634=>19667, +36640=>19668, +36641=>19669, +36642=>19670, +36643=>19671, +36644=>19672, +36647=>19673, +36648=>19674, +36651=>19675, +36652=>19676, +36653=>19677, +36654=>19678, +36656=>19679, +36657=>19680, +36658=>19681, +36660=>19682, +36661=>19683, +36662=>19684, +36663=>19685, +36665=>19686, +36666=>19687, +36668=>19688, +36669=>19689, +36672=>19690, +36673=>19691, +36675=>19692, +36679=>19693, +36680=>19694, +36682=>19695, +36683=>19696, +36684=>19697, +36687=>19698, +36688=>19699, +36689=>19700, +36690=>19701, +36691=>19702, +36693=>19703, +36694=>19704, +36695=>19705, +36696=>19706, +36697=>19707, +36698=>19708, +36699=>19709, +36700=>19710, +36701=>19711, +36702=>19712, +36704=>19713, +36707=>19714, +36709=>19715, +36714=>19716, +36736=>19717, +36748=>19718, +36754=>19719, +36765=>19720, +36768=>19721, +36769=>19722, +36770=>19723, +36772=>19724, +36773=>19725, +36775=>19726, +36778=>19727, +36780=>19728, +36787=>19729, +36788=>19730, +12193=>19731, +36789=>19731, +36791=>19732, +36792=>19733, +36794=>19734, +36795=>19735, +36796=>19736, +36799=>19737, +36800=>19738, +36803=>19739, +36806=>19740, +36809=>19741, +36810=>19742, +36811=>19743, +36812=>19744, +36813=>19745, +36815=>19746, +36818=>19747, +36822=>19748, +36823=>19749, +36826=>19750, +36832=>19751, +36833=>19752, +36835=>19753, +36839=>19754, +36844=>19755, +36847=>19756, +36849=>19757, +36850=>19758, +36853=>19759, +36854=>19760, +36858=>19761, +36859=>19762, +36860=>19763, +36862=>19764, +36863=>19765, +36871=>19766, +36872=>19767, +36876=>19768, +36878=>19769, +36883=>19770, +36888=>19771, +36892=>19772, +36900=>19773, +36901=>19774, +36903=>19775, +36904=>19776, +36905=>19777, +36906=>19778, +36907=>19779, +36908=>19780, +36912=>19781, +36913=>19782, +36915=>19783, +36916=>19784, +36919=>19785, +36921=>19786, +36922=>19787, +36925=>19788, +36927=>19789, +36928=>19790, +36931=>19791, +36933=>19792, +36934=>19793, +36936=>19794, +36937=>19795, +36938=>19796, +36940=>19797, +36950=>19798, +36953=>19799, +36954=>19800, +36957=>19801, +36959=>19802, +36961=>19803, +36964=>19804, +36966=>19805, +36967=>19806, +36970=>19807, +36971=>19808, +36972=>19809, +36975=>19810, +36976=>19811, +36977=>19812, +36979=>19813, +36982=>19814, +36985=>19815, +36987=>19816, +36990=>19817, +36997=>19818, +36998=>19819, +37001=>19820, +37004=>19821, +37005=>19822, +37006=>19823, +37010=>19824, +37012=>19825, +37014=>19826, +37016=>19827, +37018=>19828, +37020=>19829, +37022=>19830, +37023=>19831, +37024=>19832, +37028=>19833, +37029=>19834, +37031=>19835, +37032=>19836, +37033=>19837, +37035=>19838, +37037=>19839, +37042=>19840, +37047=>19841, +37052=>19842, +37053=>19843, +37055=>19844, +37056=>19845, +37058=>19846, +37059=>19847, +37062=>19848, +37064=>19849, +37065=>19850, +37067=>19851, +37068=>19852, +37069=>19853, +37074=>19854, +37076=>19855, +37077=>19856, +37078=>19857, +37080=>19858, +37081=>19859, +37082=>19860, +37086=>19861, +37088=>19862, +37091=>19863, +37092=>19864, +37093=>19865, +37097=>19866, +37098=>19867, +37100=>19868, +37102=>19869, +37104=>19870, +37105=>19871, +37106=>19872, +37107=>19873, +37110=>19874, +37111=>19875, +37113=>19876, +37114=>19877, +37115=>19878, +37116=>19879, +37119=>19880, +37120=>19881, +37121=>19882, +37123=>19883, +37125=>19884, +37127=>19885, +37128=>19886, +37130=>19887, +37131=>19888, +37132=>19889, +37133=>19890, +37134=>19891, +37135=>19892, +37136=>19893, +37137=>19894, +37139=>19895, +37141=>19896, +37143=>19897, +37144=>19898, +37146=>19899, +37147=>19900, +37148=>19901, +37149=>19902, +37151=>19903, +37152=>19904, +37153=>19905, +37156=>19906, +37157=>19907, +37158=>19908, +37160=>19909, +37161=>19910, +37162=>19911, +37163=>19912, +37164=>19913, +37166=>19914, +37171=>19915, +37173=>19916, +37175=>19917, +37176=>19918, +37179=>19919, +37180=>19920, +37181=>19921, +37182=>19922, +37183=>19923, +37184=>19924, +37185=>19925, +37186=>19926, +37188=>19927, +37189=>19928, +37191=>19929, +37201=>19930, +37203=>19931, +37204=>19932, +37205=>19933, +37206=>19934, +37208=>19935, +37209=>19936, +37211=>19937, +37212=>19938, +37215=>19939, +37216=>19940, +37222=>19941, +37223=>19942, +37224=>19943, +37227=>19944, +37229=>19945, +37235=>19946, +37242=>19947, +37243=>19948, +37244=>19949, +37248=>19950, +37249=>19951, +37250=>19952, +37251=>19953, +37252=>19954, +37254=>19955, +37256=>19956, +37258=>19957, +37262=>19958, +37263=>19959, +37267=>19960, +37268=>19961, +37269=>19962, +37271=>19963, +37272=>19964, +37273=>19965, +37277=>19966, +37278=>19967, +37279=>19968, +37280=>19969, +37281=>19970, +37284=>19971, +37285=>19972, +37286=>19973, +37287=>19974, +37288=>19975, +37289=>19976, +37296=>19977, +37297=>19978, +37298=>19979, +37299=>19980, +37302=>19981, +37303=>19982, +37304=>19983, +37305=>19984, +37307=>19985, +37308=>19986, +37309=>19987, +37310=>19988, +37311=>19989, +37314=>19990, +37316=>19991, +12196=>19992, +37318=>19992, +37320=>19993, +37328=>19994, +37334=>19995, +37338=>19996, +37339=>19997, +37342=>19998, +37343=>19999, +37344=>20000, +37345=>20001, +37346=>20002, +37349=>20003, +37350=>20004, +37352=>20005, +37354=>20006, +37355=>20007, +37356=>20008, +37357=>20009, +37358=>20010, +37359=>20011, +37360=>20012, +37361=>20013, +37362=>20014, +37363=>20015, +37364=>20016, +37366=>20017, +37368=>20018, +37371=>20019, +37372=>20020, +37373=>20021, +37374=>20022, +37375=>20023, +37378=>20024, +37379=>20025, +37381=>20026, +37382=>20027, +37383=>20028, +37386=>20029, +37387=>20030, +37388=>20031, +37391=>20032, +37394=>20033, +37395=>20034, +37398=>20035, +37399=>20036, +37400=>20037, +37401=>20038, +37402=>20039, +37403=>20040, +37404=>20041, +37405=>20042, +37407=>20043, +37408=>20044, +37409=>20045, +37410=>20046, +37412=>20047, +37416=>20048, +37417=>20049, +37418=>20050, +37419=>20051, +37420=>20052, +37421=>20053, +37423=>20054, +37425=>20055, +37426=>20056, +37429=>20057, +37430=>20058, +37435=>20059, +37436=>20060, +37441=>20061, +37442=>20062, +37443=>20063, +37444=>20064, +37446=>20065, +37447=>20066, +37450=>20067, +37451=>20068, +37452=>20069, +37454=>20070, +37455=>20071, +37456=>20072, +37458=>20073, +37459=>20074, +37460=>20075, +37462=>20076, +37464=>20077, +37465=>20078, +37468=>20079, +37469=>20080, +37471=>20081, +37472=>20082, +37473=>20083, +37475=>20084, +37476=>20085, +37477=>20086, +37479=>20087, +37480=>20088, +37481=>20089, +37482=>20090, +37483=>20091, +37486=>20092, +37487=>20093, +37488=>20094, +37489=>20095, +37490=>20096, +37491=>20097, +37493=>20098, +37494=>20099, +37495=>20100, +37497=>20101, +37500=>20102, +37501=>20103, +37502=>20104, +37505=>20105, +37506=>20106, +37508=>20107, +37510=>20108, +37511=>20109, +37512=>20110, +37513=>20111, +37514=>20112, +37515=>20113, +37516=>20114, +37517=>20115, +37519=>20116, +37520=>20117, +37522=>20118, +37524=>20119, +37525=>20120, +37527=>20121, +37529=>20122, +37531=>20123, +37533=>20124, +37534=>20125, +37535=>20126, +37537=>20127, +37538=>20128, +37540=>20129, +37543=>20130, +37549=>20131, +37551=>20132, +37552=>20133, +37554=>20134, +37555=>20135, +37556=>20136, +37557=>20137, +37558=>20138, +37560=>20139, +37562=>20140, +37565=>20141, +37566=>20142, +37567=>20143, +37568=>20144, +37570=>20145, +37572=>20146, +37574=>20147, +37577=>20148, +37578=>20149, +37579=>20150, +37581=>20151, +37582=>20152, +37584=>20153, +37585=>20154, +37587=>20155, +37588=>20156, +37589=>20157, +37590=>20158, +37591=>20159, +37592=>20160, +37593=>20161, +37594=>20162, +37595=>20163, +37596=>20164, +37598=>20165, +37600=>20166, +37601=>20167, +37602=>20168, +37607=>20169, +37609=>20170, +37611=>20171, +37612=>20172, +37618=>20173, +37619=>20174, +37620=>20175, +37621=>20176, +37623=>20177, +37625=>20178, +37626=>20179, +37627=>20180, +37629=>20181, +37630=>20182, +37631=>20183, +37632=>20184, +37634=>20185, +37635=>20186, +37636=>20187, +37637=>20188, +37641=>20189, +37642=>20190, +37643=>20191, +37644=>20192, +37645=>20193, +37646=>20194, +37647=>20195, +37649=>20196, +37651=>20197, +37652=>20198, +37654=>20199, +37655=>20200, +37660=>20201, +37661=>20202, +37662=>20203, +37665=>20204, +37667=>20205, +37668=>20206, +37669=>20207, +37671=>20208, +37673=>20209, +37674=>20210, +37676=>20211, +37677=>20212, +37680=>20213, +37681=>20214, +37684=>20215, +37685=>20216, +37687=>20217, +37689=>20218, +37690=>20219, +37691=>20220, +37692=>20221, +37693=>20222, +37695=>20223, +37698=>20224, +37700=>20225, +37701=>20226, +37704=>20227, +37705=>20228, +37706=>20229, +37708=>20230, +37710=>20231, +37711=>20232, +37712=>20233, +37713=>20234, +37714=>20235, +37715=>20236, +37717=>20237, +37718=>20238, +37719=>20239, +37721=>20240, +37722=>20241, +37724=>20242, +37725=>20243, +37726=>20244, +37727=>20245, +37728=>20246, +37729=>20247, +37730=>20248, +37731=>20249, +37734=>20250, +37735=>20251, +37736=>20252, +37739=>20253, +37741=>20254, +37742=>20255, +37743=>20256, +37745=>20257, +37746=>20258, +37747=>20259, +37748=>20260, +37751=>20261, +37752=>20262, +37753=>20263, +37755=>20264, +37756=>20265, +37757=>20266, +37759=>20267, +37760=>20268, +37761=>20269, +37763=>20270, +37765=>20271, +37766=>20272, +37768=>20273, +37769=>20274, +37771=>20275, +37772=>20276, +37773=>20277, +37774=>20278, +37776=>20279, +37777=>20280, +37778=>20281, +37779=>20282, +37780=>20283, +37781=>20284, +37783=>20285, +37785=>20286, +37786=>20287, +37787=>20288, +37788=>20289, +37789=>20290, +37790=>20291, +37791=>20292, +37792=>20293, +37793=>20294, +37796=>20295, +37797=>20296, +37800=>20297, +37803=>20298, +37805=>20299, +37807=>20300, +37809=>20301, +37810=>20302, +37812=>20303, +37814=>20304, +37815=>20305, +37817=>20306, +37818=>20307, +37819=>20308, +37820=>20309, +37821=>20310, +37822=>20311, +37824=>20312, +37825=>20313, +37826=>20314, +37828=>20315, +37829=>20316, +37830=>20317, +37833=>20318, +37835=>20319, +37838=>20320, +37839=>20321, +37840=>20322, +37842=>20323, +37843=>20324, +37844=>20325, +37845=>20326, +37849=>20327, +37850=>20328, +37851=>20329, +37856=>20330, +37859=>20331, +37861=>20332, +37862=>20333, +37863=>20334, +37865=>20335, +37866=>20336, +37867=>20337, +37868=>20338, +37869=>20339, +37870=>20340, +37871=>20341, +37872=>20342, +37873=>20343, +37874=>20344, +37875=>20345, +37876=>20346, +37878=>20347, +37880=>20348, +37882=>20349, +37883=>20350, +37884=>20351, +37885=>20352, +37886=>20353, +37887=>20354, +37888=>20355, +37889=>20356, +37890=>20357, +37892=>20358, +37893=>20359, +37894=>20360, +37895=>20361, +37896=>20362, +37897=>20363, +37898=>20364, +37900=>20365, +37901=>20366, +37902=>20367, +37903=>20368, +37905=>20369, +37909=>20370, +37910=>20371, +37911=>20372, +37914=>20373, +37915=>20374, +37916=>20375, +37918=>20376, +37919=>20377, +37921=>20378, +37922=>20379, +37923=>20380, +37924=>20381, +37925=>20382, +37929=>20383, +37930=>20384, +37931=>20385, +37932=>20386, +37933=>20387, +37935=>20388, +37936=>20389, +37937=>20390, +37940=>20391, +37942=>20392, +37943=>20393, +37945=>20394, +37947=>20395, +37948=>20396, +37949=>20397, +37952=>20398, +37953=>20399, +37954=>20400, +37955=>20401, +37957=>20402, +37958=>20403, +37959=>20404, +37960=>20405, +37961=>20406, +37963=>20407, +37965=>20408, +37966=>20409, +37967=>20410, +37968=>20411, +37969=>20412, +37971=>20413, +37973=>20414, +37974=>20415, +37975=>20416, +37976=>20417, +37977=>20418, +37978=>20419, +37979=>20420, +37980=>20421, +37981=>20422, +37982=>20423, +37983=>20424, +37985=>20425, +37986=>20426, +37988=>20427, +37990=>20428, +37991=>20429, +37992=>20430, +37993=>20431, +37994=>20432, +37996=>20433, +37998=>20434, +37999=>20435, +38001=>20436, +38003=>20437, +38004=>20438, +38005=>20439, +38006=>20440, +38008=>20441, +38010=>20442, +38011=>20443, +38016=>20444, +38017=>20445, +38018=>20446, +38019=>20447, +38020=>20448, +38033=>20449, +38038=>20450, +38040=>20451, +38087=>20452, +38095=>20453, +38099=>20454, +38100=>20455, +38106=>20456, +38118=>20457, +38139=>20458, +38172=>20459, +38176=>20460, +38183=>20461, +38195=>20462, +38205=>20463, +38211=>20464, +38216=>20465, +38219=>20466, +38229=>20467, +38234=>20468, +38240=>20469, +38254=>20470, +38260=>20471, +38261=>20472, +38264=>20473, +38265=>20474, +38266=>20475, +38267=>20476, +38268=>20477, +38269=>20478, +38270=>20479, +38273=>20480, +38276=>20481, +38277=>20482, +38279=>20483, +38280=>20484, +38282=>20485, +38285=>20486, +38288=>20487, +38290=>20488, +38293=>20489, +38294=>20490, +38295=>20491, +38297=>20492, +38298=>20493, +38299=>20494, +38300=>20495, +38301=>20496, +38302=>20497, +38303=>20498, +38304=>20499, +38306=>20500, +38310=>20501, +38311=>20502, +38314=>20503, +38318=>20504, +38319=>20505, +38320=>20506, +38321=>20507, +38323=>20508, +38324=>20509, +38325=>20510, +38327=>20511, +38328=>20512, +38330=>20513, +38336=>20514, +38337=>20515, +38338=>20516, +38340=>20517, +38341=>20518, +38343=>20519, +38345=>20520, +38349=>20521, +38350=>20522, +38351=>20523, +38353=>20524, +38354=>20525, +38355=>20526, +38359=>20527, +38360=>20528, +38361=>20529, +38362=>20530, +38363=>20531, +38365=>20532, +38367=>20533, +38368=>20534, +38371=>20535, +38372=>20536, +38374=>20537, +38375=>20538, +38380=>20539, +38399=>20540, +38407=>20541, +38419=>20542, +38424=>20543, +38427=>20544, +38430=>20545, +38432=>20546, +38435=>20547, +38436=>20548, +38437=>20549, +38438=>20550, +38439=>20551, +38440=>20552, +38441=>20553, +38443=>20554, +38444=>20555, +38445=>20556, +38447=>20557, +38448=>20558, +38455=>20559, +38456=>20560, +38457=>20561, +38458=>20562, +38462=>20563, +38465=>20564, +38467=>20565, +38474=>20566, +38478=>20567, +38479=>20568, +38481=>20569, +38482=>20570, +38483=>20571, +38486=>20572, +38487=>20573, +38489=>20574, +38490=>20575, +38492=>20576, +38494=>20577, +38496=>20578, +38501=>20579, +38502=>20580, +38507=>20581, +38509=>20582, +38510=>20583, +38511=>20584, +38513=>20585, +38521=>20586, +38522=>20587, +38523=>20588, +38524=>20589, +38526=>20590, +38527=>20591, +38528=>20592, +38529=>20593, +38530=>20594, +38531=>20595, +38532=>20596, +38535=>20597, +38537=>20598, +38540=>20599, +38545=>20600, +38546=>20601, +38547=>20602, +38550=>20603, +38554=>20604, +38557=>20605, +38558=>20606, +38559=>20607, +38560=>20608, +38561=>20609, +38562=>20610, +63985=>20611, +38563=>20611, +38564=>20612, +38565=>20613, +38566=>20614, +38569=>20615, +38571=>20616, +38572=>20617, +38573=>20618, +38574=>20619, +38575=>20620, +38578=>20621, +38581=>20622, +38583=>20623, +38586=>20624, +38591=>20625, +38594=>20626, +38595=>20627, +38600=>20628, +38602=>20629, +38603=>20630, +38608=>20631, +38609=>20632, +38611=>20633, +38612=>20634, +38615=>20635, +38616=>20636, +38618=>20637, +38621=>20638, +38622=>20639, +38623=>20640, +38625=>20641, +38628=>20642, +38629=>20643, +38630=>20644, +38631=>20645, +38635=>20646, +38636=>20647, +38637=>20648, +38638=>20649, +38640=>20650, +38641=>20651, +38644=>20652, +38645=>20653, +38648=>20654, +38650=>20655, +38652=>20656, +38653=>20657, +38655=>20658, +38658=>20659, +38659=>20660, +38661=>20661, +38666=>20662, +38667=>20663, +38668=>20664, +38672=>20665, +38673=>20666, +38674=>20667, +38676=>20668, +38677=>20669, +38679=>20670, +38680=>20671, +38681=>20672, +38682=>20673, +38683=>20674, +38685=>20675, +38687=>20676, +38688=>20677, +38689=>20678, +38690=>20679, +38691=>20680, +38692=>20681, +38693=>20682, +38694=>20683, +38696=>20684, +38697=>20685, +38699=>20686, +38700=>20687, +38702=>20688, +38703=>20689, +38705=>20690, +38707=>20691, +38708=>20692, +38709=>20693, +38710=>20694, +38711=>20695, +38714=>20696, +38715=>20697, +38716=>20698, +38719=>20699, +38720=>20700, +38721=>20701, +38723=>20702, +38725=>20703, +38726=>20704, +38727=>20705, +38729=>20706, +38730=>20707, +38731=>20708, +38732=>20709, +38733=>20710, +38734=>20711, +38735=>20712, +38736=>20713, +12205=>20714, +38737=>20714, +38740=>20715, +38741=>20716, +38743=>20717, +38744=>20718, +38748=>20719, +38749=>20720, +38751=>20721, +38755=>20722, +38756=>20723, +38758=>20724, +38759=>20725, +38762=>20726, +38763=>20727, +38764=>20728, +38765=>20729, +38766=>20730, +38767=>20731, +38768=>20732, +38769=>20733, +38770=>20734, +38773=>20735, +38775=>20736, +38776=>20737, +38777=>20738, +38778=>20739, +38779=>20740, +38781=>20741, +38782=>20742, +38783=>20743, +38784=>20744, +38785=>20745, +38786=>20746, +38787=>20747, +38788=>20748, +38790=>20749, +38791=>20750, +38792=>20751, +38793=>20752, +38794=>20753, +38796=>20754, +38798=>20755, +38800=>20756, +38803=>20757, +38805=>20758, +38806=>20759, +38807=>20760, +38809=>20761, +38810=>20762, +38811=>20763, +38812=>20764, +38813=>20765, +38814=>20766, +38815=>20767, +38817=>20768, +38818=>20769, +38820=>20770, +38821=>20771, +38823=>20772, +38824=>20773, +38825=>20774, +38826=>20775, +38828=>20776, +38830=>20777, +38832=>20778, +38833=>20779, +38835=>20780, +38837=>20781, +38838=>20782, +38839=>20783, +38840=>20784, +38841=>20785, +38842=>20786, +38843=>20787, +38844=>20788, +38846=>20789, +38847=>20790, +38848=>20791, +38849=>20792, +38850=>20793, +38852=>20794, +38853=>20795, +38855=>20796, +38856=>20797, +38858=>20798, +38861=>20799, +38862=>20800, +38863=>20801, +38864=>20802, +38865=>20803, +38866=>20804, +38868=>20805, +38869=>20806, +38870=>20807, +38871=>20808, +38872=>20809, +38874=>20810, +38875=>20811, +38877=>20812, +38879=>20813, +38880=>20814, +38881=>20815, +38882=>20816, +38883=>20817, +38884=>20818, +38885=>20819, +38888=>20820, +38894=>20821, +38895=>20822, +38896=>20823, +38897=>20824, +38898=>20825, +38900=>20826, +38903=>20827, +38904=>20828, +38905=>20829, +38906=>20830, +38907=>20831, +38908=>20832, +38909=>20833, +38910=>20834, +38912=>20835, +38916=>20836, +38921=>20837, +38923=>20838, +38925=>20839, +38932=>20840, +38933=>20841, +38934=>20842, +38937=>20843, +38938=>20844, +38939=>20845, +38941=>20846, +38942=>20847, +38943=>20848, +38944=>20849, +38946=>20850, +38947=>20851, +38949=>20852, +38951=>20853, +38952=>20854, +38953=>20855, +38954=>20856, +38955=>20857, +38956=>20858, +38958=>20859, +38959=>20860, +38961=>20861, +38962=>20862, +38963=>20863, +38964=>20864, +38965=>20865, +38966=>20866, +38969=>20867, +38970=>20868, +38972=>20869, +38974=>20870, +38975=>20871, +38976=>20872, +38977=>20873, +38978=>20874, +38979=>20875, +38980=>20876, +38981=>20877, +38983=>20878, +38984=>20879, +38985=>20880, +38986=>20881, +38987=>20882, +38991=>20883, +38992=>20884, +38993=>20885, +38994=>20886, +38997=>20887, +38998=>20888, +38999=>20889, +39002=>20890, +39004=>20891, +39005=>20892, +39007=>20893, +39008=>20894, +39009=>20895, +39011=>20896, +39012=>20897, +39014=>20898, +39016=>20899, +39017=>20900, +39018=>20901, +39021=>20902, +39022=>20903, +39026=>20904, +39051=>20905, +39054=>20906, +39058=>20907, +39061=>20908, +39065=>20909, +39075=>20910, +39081=>20911, +39082=>20912, +39083=>20913, +39084=>20914, +39085=>20915, +39088=>20916, +39090=>20917, +39092=>20918, +39093=>20919, +39095=>20920, +39096=>20921, +39097=>20922, +39098=>20923, +39099=>20924, +39101=>20925, +39102=>20926, +39103=>20927, +39104=>20928, +39105=>20929, +39106=>20930, +39107=>20931, +39109=>20932, +39111=>20933, +39113=>20934, +39114=>20935, +39115=>20936, +39116=>20937, +39117=>20938, +39119=>20939, +39120=>20940, +39124=>20941, +39126=>20942, +39127=>20943, +39132=>20944, +39133=>20945, +39137=>20946, +39139=>20947, +39140=>20948, +39141=>20949, +39142=>20950, +39148=>20951, +39150=>20952, +39152=>20953, +39153=>20954, +39155=>20955, +39157=>20956, +39158=>20957, +39159=>20958, +39160=>20959, +39161=>20960, +39162=>20961, +39163=>20962, +39167=>20963, +39168=>20964, +39169=>20965, +39170=>20966, +39172=>20967, +39174=>20968, +39175=>20969, +39176=>20970, +39179=>20971, +39182=>20972, +39183=>20973, +39188=>20974, +39189=>20975, +39190=>20976, +39191=>20977, +39193=>20978, +39194=>20979, +39196=>20980, +39197=>20981, +39199=>20982, +39200=>20983, +39202=>20984, +39203=>20985, +39204=>20986, +39205=>20987, +39206=>20988, +39207=>20989, +39209=>20990, +39210=>20991, +39211=>20992, +39212=>20993, +39213=>20994, +39215=>20995, +39216=>20996, +39217=>20997, +39218=>20998, +39220=>20999, +39221=>21000, +39222=>21001, +39224=>21002, +39225=>21003, +39226=>21004, +39227=>21005, +39229=>21006, +39232=>21007, +39233=>21008, +39234=>21009, +39236=>21010, +39238=>21011, +39239=>21012, +39245=>21013, +39246=>21014, +39247=>21015, +39248=>21016, +39251=>21017, +39254=>21018, +39256=>21019, +39257=>21020, +39258=>21021, +39259=>21022, +39261=>21023, +39263=>21024, +39264=>21025, +39265=>21026, +39268=>21027, +39270=>21028, +39283=>21029, +39288=>21030, +39289=>21031, +39291=>21032, +39294=>21033, +39298=>21034, +39299=>21035, +39305=>21036, +39308=>21037, +39310=>21038, +39322=>21039, +39323=>21040, +39324=>21041, +39325=>21042, +39326=>21043, +39327=>21044, +39328=>21045, +39329=>21046, +39330=>21047, +39331=>21048, +39332=>21049, +39334=>21050, +39335=>21051, +39337=>21052, +39338=>21053, +39339=>21054, +39343=>21055, +39344=>21056, +39346=>21057, +39349=>21058, +39350=>21059, +39351=>21060, +39352=>21061, +39353=>21062, +39354=>21063, +39355=>21064, +39356=>21065, +39357=>21066, +39358=>21067, +39359=>21068, +39360=>21069, +39362=>21070, +39363=>21071, +39364=>21072, +39365=>21073, +39366=>21074, +39367=>21075, +39368=>21076, +39369=>21077, +39370=>21078, +39371=>21079, +39372=>21080, +39373=>21081, +39374=>21082, +39375=>21083, +39379=>21084, +39382=>21085, +39383=>21086, +39386=>21087, +39388=>21088, +39390=>21089, +39392=>21090, +39395=>21091, +39396=>21092, +39397=>21093, +39398=>21094, +39399=>21095, +39400=>21096, +39401=>21097, +39402=>21098, +39403=>21099, +39404=>21100, +39406=>21101, +39407=>21102, +39408=>21103, +39410=>21104, +39411=>21105, +39412=>21106, +39413=>21107, +39414=>21108, +39415=>21109, +39416=>21110, +39417=>21111, +39418=>21112, +39419=>21113, +39420=>21114, +39421=>21115, +39422=>21116, +39424=>21117, +39426=>21118, +39427=>21119, +39428=>21120, +39430=>21121, +39431=>21122, +39432=>21123, +39433=>21124, +39434=>21125, +39435=>21126, +39436=>21127, +39440=>21128, +39441=>21129, +39442=>21130, +39443=>21131, +39444=>21132, +39445=>21133, +39447=>21134, +39448=>21135, +39450=>21136, +39451=>21137, +39452=>21138, +39453=>21139, +39454=>21140, +39455=>21141, +39456=>21142, +39457=>21143, +39458=>21144, +39459=>21145, +39460=>21146, +39461=>21147, +39462=>21148, +39463=>21149, +39464=>21150, +39465=>21151, +39466=>21152, +39468=>21153, +39471=>21154, +39473=>21155, +39474=>21156, +39475=>21157, +39476=>21158, +39477=>21159, +39481=>21160, +39482=>21161, +39483=>21162, +39484=>21163, +39485=>21164, +39487=>21165, +39494=>21166, +39495=>21167, +39496=>21168, +39497=>21169, +39499=>21170, +39500=>21171, +39502=>21172, +39504=>21173, +39505=>21174, +39506=>21175, +39507=>21176, +39508=>21177, +39510=>21178, +39512=>21179, +39513=>21180, +39516=>21181, +39517=>21182, +39518=>21183, +39520=>21184, +39521=>21185, +39523=>21186, +39526=>21187, +39527=>21188, +39528=>21189, +39529=>21190, +39531=>21191, +39538=>21192, +39555=>21193, +39561=>21194, +39565=>21195, +39566=>21196, +39572=>21197, +39573=>21198, +39577=>21199, +39590=>21200, +39593=>21201, +39594=>21202, +39595=>21203, +39596=>21204, +39597=>21205, +39598=>21206, +39602=>21207, +39603=>21208, +39604=>21209, +39605=>21210, +39609=>21211, +39611=>21212, +39613=>21213, +39614=>21214, +39615=>21215, +39619=>21216, +39620=>21217, +39622=>21218, +39623=>21219, +39624=>21220, +39625=>21221, +39626=>21222, +39629=>21223, +39630=>21224, +39632=>21225, +39639=>21226, +39641=>21227, +39642=>21228, +39643=>21229, +39644=>21230, +39645=>21231, +39646=>21232, +39648=>21233, +39650=>21234, +39651=>21235, +39652=>21236, +39653=>21237, +39655=>21238, +39656=>21239, +39657=>21240, +39658=>21241, +39660=>21242, +39664=>21243, +39665=>21244, +39666=>21245, +39667=>21246, +39668=>21247, +39669=>21248, +39670=>21249, +39671=>21250, +39672=>21251, +39674=>21252, +39676=>21253, +39677=>21254, +39678=>21255, +39679=>21256, +39680=>21257, +39681=>21258, +39682=>21259, +39684=>21260, +39685=>21261, +39687=>21262, +39689=>21263, +39690=>21264, +39691=>21265, +39692=>21266, +39694=>21267, +39696=>21268, +39697=>21269, +39698=>21270, +39700=>21271, +39701=>21272, +39702=>21273, +39703=>21274, +39704=>21275, +39705=>21276, +39707=>21277, +39708=>21278, +39709=>21279, +39710=>21280, +39712=>21281, +39713=>21282, +39716=>21283, +39718=>21284, +39720=>21285, +39722=>21286, +39723=>21287, +39724=>21288, +39725=>21289, +39728=>21290, +39731=>21291, +39732=>21292, +39733=>21293, +39734=>21294, +39735=>21295, +39736=>21296, +39737=>21297, +39738=>21298, +39741=>21299, +39742=>21300, +39743=>21301, +39744=>21302, +39750=>21303, +39754=>21304, +39755=>21305, +39756=>21306, +39760=>21307, +39762=>21308, +39763=>21309, +39765=>21310, +39766=>21311, +39767=>21312, +39769=>21313, +39771=>21314, +39772=>21315, +39773=>21316, +39774=>21317, +39775=>21318, +39776=>21319, +39777=>21320, +39778=>21321, +39779=>21322, +39780=>21323, +39781=>21324, +39782=>21325, +39783=>21326, +39784=>21327, +39785=>21328, +39786=>21329, +39787=>21330, +39788=>21331, +39789=>21332, +39790=>21333, +39792=>21334, +39793=>21335, +39794=>21336, +39795=>21337, +39797=>21338, +39798=>21339, +39800=>21340, +39801=>21341, +39802=>21342, +39803=>21343, +39804=>21344, +39805=>21345, +39806=>21346, +39807=>21347, +39808=>21348, +39810=>21349, +39812=>21350, +39813=>21351, +39814=>21352, +39815=>21353, +39816=>21354, +39817=>21355, +39818=>21356, +39819=>21357, +39820=>21358, +39821=>21359, +39823=>21360, +39827=>21361, +39828=>21362, +39829=>21363, +39830=>21364, +39831=>21365, +39832=>21366, +39833=>21367, +39835=>21368, +39836=>21369, +39839=>21370, +39840=>21371, +39841=>21372, +39842=>21373, +39843=>21374, +39844=>21375, +39845=>21376, +39846=>21377, +39847=>21378, +39848=>21379, +39849=>21380, +39852=>21381, +39855=>21382, +39856=>21383, +39857=>21384, +39858=>21385, +39859=>21386, +39860=>21387, +39861=>21388, +39862=>21389, +39863=>21390, +39864=>21391, +39865=>21392, +39866=>21393, +39867=>21394, +39868=>21395, +39869=>21396, +39870=>21397, +39871=>21398, +39874=>21399, +39875=>21400, +39876=>21401, +39877=>21402, +39878=>21403, +39880=>21404, +39883=>21405, +39884=>21406, +39885=>21407, +39886=>21408, +39887=>21409, +39888=>21410, +39889=>21411, +39890=>21412, +39891=>21413, +39893=>21414, +39895=>21415, +39896=>21416, +39897=>21417, +39898=>21418, +39900=>21419, +39902=>21420, +39903=>21421, +39904=>21422, +39907=>21423, +39909=>21424, +39910=>21425, +39913=>21426, +39916=>21427, +39917=>21428, +39918=>21429, +39919=>21430, +39921=>21431, +39922=>21432, +39923=>21433, +39925=>21434, +39926=>21435, +39927=>21436, +39928=>21437, +39929=>21438, +39930=>21439, +39931=>21440, +39932=>21441, +39934=>21442, +39936=>21443, +39937=>21444, +39938=>21445, +39939=>21446, +39940=>21447, +39941=>21448, +39942=>21449, +39943=>21450, +39946=>21451, +39947=>21452, +39948=>21453, +39950=>21454, +39951=>21455, +39953=>21456, +39956=>21457, +39957=>21458, +39958=>21459, +39959=>21460, +39960=>21461, +39961=>21462, +39962=>21463, +39963=>21464, +39964=>21465, +39965=>21466, +39966=>21467, +39967=>21468, +39969=>21469, +39970=>21470, +39972=>21471, +39974=>21472, +39975=>21473, +39978=>21474, +39979=>21475, +39980=>21476, +39982=>21477, +39983=>21478, +39984=>21479, +39988=>21480, +39990=>21481, +39992=>21482, +39994=>21483, +39996=>21484, +39997=>21485, +39999=>21486, +40000=>21487, +40001=>21488, +40002=>21489, +40003=>21490, +40004=>21491, +40006=>21492, +40007=>21493, +40010=>21494, +40011=>21495, +40012=>21496, +40013=>21497, +40014=>21498, +40015=>21499, +40016=>21500, +40017=>21501, +40019=>21502, +40021=>21503, +40025=>21504, +40026=>21505, +40027=>21506, +40028=>21507, +40030=>21508, +40032=>21509, +40033=>21510, +40034=>21511, +40035=>21512, +40036=>21513, +40037=>21514, +40038=>21515, +40040=>21516, +40041=>21517, +40042=>21518, +40043=>21519, +40044=>21520, +40046=>21521, +40047=>21522, +40048=>21523, +40049=>21524, +40050=>21525, +40051=>21526, +40052=>21527, +40053=>21528, +40054=>21529, +40055=>21530, +40057=>21531, +40059=>21532, +40061=>21533, +40062=>21534, +40064=>21535, +40067=>21536, +40068=>21537, +40073=>21538, +40074=>21539, +40076=>21540, +40079=>21541, +40083=>21542, +40086=>21543, +40087=>21544, +40088=>21545, +40089=>21546, +40093=>21547, +40106=>21548, +40108=>21549, +40111=>21550, +40121=>21551, +40126=>21552, +40127=>21553, +40128=>21554, +40129=>21555, +40130=>21556, +40136=>21557, +40137=>21558, +40145=>21559, +40146=>21560, +40154=>21561, +40155=>21562, +40160=>21563, +40161=>21564, +40163=>21565, +40164=>21566, +40166=>21567, +40167=>21568, +40168=>21569, +40170=>21570, +40171=>21571, +40173=>21572, +40174=>21573, +40175=>21574, +40176=>21575, +40177=>21576, +40178=>21577, +40181=>21578, +40183=>21579, +40184=>21580, +40185=>21581, +40186=>21582, +40187=>21583, +40188=>21584, +40189=>21585, +40190=>21586, +40191=>21587, +40192=>21588, +40193=>21589, +40194=>21590, +40195=>21591, +40196=>21592, +40197=>21593, +40200=>21594, +40202=>21595, +40203=>21596, +40204=>21597, +40205=>21598, +40206=>21599, +40207=>21600, +40208=>21601, +40209=>21602, +40210=>21603, +40211=>21604, +40212=>21605, +40214=>21606, +40215=>21607, +40216=>21608, +40217=>21609, +40218=>21610, +40220=>21611, +40222=>21612, +40224=>21613, +40225=>21614, +40226=>21615, +40228=>21616, +40229=>21617, +40231=>21618, +40233=>21619, +40234=>21620, +40235=>21621, +40236=>21622, +40237=>21623, +40238=>21624, +40241=>21625, +40242=>21626, +40243=>21627, +40244=>21628, +40245=>21629, +40246=>21630, +40247=>21631, +40248=>21632, +40249=>21633, +40250=>21634, +40252=>21635, +40253=>21636, +40254=>21637, +40256=>21638, +40257=>21639, +40259=>21640, +40260=>21641, +40261=>21642, +40262=>21643, +40263=>21644, +40264=>21645, +40265=>21646, +40266=>21647, +40267=>21648, +40268=>21649, +40269=>21650, +40270=>21651, +40271=>21652, +40272=>21653, +40276=>21654, +40277=>21655, +40278=>21656, +40279=>21657, +40280=>21658, +40281=>21659, +40282=>21660, +40283=>21661, +40286=>21662, +40287=>21663, +40290=>21664, +40291=>21665, +40292=>21666, +40293=>21667, +40294=>21668, +40295=>21669, +40296=>21670, +40297=>21671, +40299=>21672, +40301=>21673, +40302=>21674, +40304=>21675, +40305=>21676, +40307=>21677, +40308=>21678, +40309=>21679, +40310=>21680, +40311=>21681, +40312=>21682, +40313=>21683, +40314=>21684, +40315=>21685, +40316=>21686, +40317=>21687, +40318=>21688, +40319=>21689, +40320=>21690, +40321=>21691, +40322=>21692, +40323=>21693, +40324=>21694, +40325=>21695, +40326=>21696, +40328=>21697, +40330=>21698, +40331=>21699, +40332=>21700, +40333=>21701, +40334=>21702, +40335=>21703, +40336=>21704, +40337=>21705, +40338=>21706, +40340=>21707, +40341=>21708, +40342=>21709, +40343=>21710, +40345=>21711, +40347=>21712, +40348=>21713, +40349=>21714, +40350=>21715, +40351=>21716, +40352=>21717, +40353=>21718, +40354=>21719, +40355=>21720, +40356=>21721, +40358=>21722, +40359=>21723, +40360=>21724, +40362=>21725, +40363=>21726, +40364=>21727, +40365=>21728, +40366=>21729, +40368=>21730, +40369=>21731, +40370=>21732, +40371=>21733, +40373=>21734, +40374=>21735, +40375=>21736, +40376=>21737, +40377=>21738, +40378=>21739, +40381=>21740, +40382=>21741, +40383=>21742, +40385=>21743, +40387=>21744, +40389=>21745, +40390=>21746, +40391=>21747, +40392=>21748, +40393=>21749, +40394=>21750, +40395=>21751, +40396=>21752, +40397=>21753, +40398=>21754, +40399=>21755, +40400=>21756, +40401=>21757, +40402=>21758, +40404=>21759, +40405=>21760, +40406=>21761, +40408=>21762, +40411=>21763, +40412=>21764, +40413=>21765, +40414=>21766, +40415=>21767, +40416=>21768, +40417=>21769, +40418=>21770, +40419=>21771, +40420=>21772, +40423=>21773, +40424=>21774, +40425=>21775, +40426=>21776, +40427=>21777, +40428=>21778, +40429=>21779, +40430=>21780, +40432=>21781, +40433=>21782, +40436=>21783, +40437=>21784, +40438=>21785, +40439=>21786, +40443=>21787, +40444=>21788, +40445=>21789, +40446=>21790, +40447=>21791, +40448=>21792, +40449=>21793, +40450=>21794, +40451=>21795, +40452=>21796, +40453=>21797, +40454=>21798, +40455=>21799, +40456=>21800, +40457=>21801, +40458=>21802, +40459=>21803, +40461=>21804, +40462=>21805, +40463=>21806, +40464=>21807, +40465=>21808, +40466=>21809, +40467=>21810, +40468=>21811, +40470=>21812, +40471=>21813, +40472=>21814, +40473=>21815, +40476=>21816, +40484=>21817, +40487=>21818, +40494=>21819, +40496=>21820, +40500=>21821, +40507=>21822, +40508=>21823, +40512=>21824, +40525=>21825, +40528=>21826, +40530=>21827, +40531=>21828, +40532=>21829, +40534=>21830, +40537=>21831, +40541=>21832, +40543=>21833, +40544=>21834, +40545=>21835, +40546=>21836, +40549=>21837, +40558=>21838, +40559=>21839, +40562=>21840, +40564=>21841, +40566=>21842, +40567=>21843, +40568=>21844, +40571=>21845, +40576=>21846, +40577=>21847, +40579=>21848, +40580=>21849, +40581=>21850, +40582=>21851, +40585=>21852, +40586=>21853, +40588=>21854, +40589=>21855, +40590=>21856, +40591=>21857, +40592=>21858, +40593=>21859, +40596=>21860, +40597=>21861, +40598=>21862, +40600=>21863, +40601=>21864, +40602=>21865, +40603=>21866, +40604=>21867, +40606=>21868, +40608=>21869, +40609=>21870, +40610=>21871, +40611=>21872, +40612=>21873, +40615=>21874, +40616=>21875, +40618=>21876, +40619=>21877, +40620=>21878, +40621=>21879, +40622=>21880, +40624=>21881, +40625=>21882, +40626=>21883, +40627=>21884, +40630=>21885, +40631=>21886, +40633=>21887, +40634=>21888, +40636=>21889, +40639=>21890, +40640=>21891, +40641=>21892, +40642=>21893, +12232=>21894, +40643=>21894, +40645=>21895, +40646=>21896, +40647=>21897, +40648=>21898, +40650=>21899, +40651=>21900, +40656=>21901, +40658=>21902, +40659=>21903, +40661=>21904, +40662=>21905, +40663=>21906, +40665=>21907, +40666=>21908, +40673=>21909, +40675=>21910, +40676=>21911, +40678=>21912, +40683=>21913, +40684=>21914, +40685=>21915, +40686=>21916, +40688=>21917, +40689=>21918, +40691=>21919, +40693=>21920, +40694=>21921, +40696=>21922, +40698=>21923, +40704=>21924, +40705=>21925, +40706=>21926, +40707=>21927, +40708=>21928, +40709=>21929, +40710=>21930, +40711=>21931, +40712=>21932, +40714=>21933, +40716=>21934, +40719=>21935, +40721=>21936, +40722=>21937, +40724=>21938, +40726=>21939, +40728=>21940, +40730=>21941, +40731=>21942, +40732=>21943, +40733=>21944, +40734=>21945, +40735=>21946, +40737=>21947, +40739=>21948, +40740=>21949, +40741=>21950, +40742=>21951, +40743=>21952, +40744=>21953, +40745=>21954, +40746=>21955, +40747=>21956, +40749=>21957, +40750=>21958, +40752=>21959, +40753=>21960, +40754=>21961, +40755=>21962, +40756=>21963, +40757=>21964, +40758=>21965, +40760=>21966, +40762=>21967, +40764=>21968, +40767=>21969, +40768=>21970, +40769=>21971, +40770=>21972, +40771=>21973, +40773=>21974, +40774=>21975, +40775=>21976, +40776=>21977, +40777=>21978, +40780=>21979, +40781=>21980, +40782=>21981, +40787=>21982, +40789=>21983, +40790=>21984, +40791=>21985, +40792=>21986, +40794=>21987, +40795=>21988, +40797=>21989, +40798=>21990, +40802=>21991, +40804=>21992, +40805=>21993, +40807=>21994, +40808=>21995, +40809=>21996, +40811=>21997, +40813=>21998, +40814=>21999, +40815=>22000, +40816=>22001, +40817=>22002, +40819=>22003, +40820=>22004, +40821=>22005, +40822=>22006, +40824=>22007, +40825=>22008, +40826=>22009, +40827=>22010, +40828=>22011, +40829=>22012, +40830=>22013, +40833=>22014, +40834=>22015, +40846=>22016, +40847=>22017, +40849=>22018, +40850=>22019, +40851=>22020, +40854=>22021, +40855=>22022, +40856=>22023, +40861=>22024, +40862=>22025, +40865=>22026, +40866=>22027, +40867=>22028, +40868=>22029, +40869=>22030, +63788=>22031, +64013=>22032, +64014=>22033, +64015=>22034, +64017=>22035, +64019=>22036, +64020=>22037, +64024=>22038, +64031=>22039, +64032=>22040, +64033=>22041, +64035=>22042, +64036=>22043, +64039=>22044, +64040=>22045, +64041=>22046, +11905=>22047, +59413=>22047, +131207=>22048, +59414=>22048, +131209=>22049, +59415=>22049, +131276=>22050, +59416=>22050, +11908=>22051, +59417=>22051, +13427=>22052, +59418=>22052, +13383=>22053, +59419=>22053, +11912=>22054, +59420=>22054, +11915=>22055, +59421=>22055, +40884=>22056, +59422=>22056, +13726=>22057, +59423=>22057, +13850=>22058, +59424=>22058, +13838=>22059, +59425=>22059, +11916=>22060, +59426=>22060, +11927=>22061, +59427=>22061, +14702=>22062, +59428=>22062, +14616=>22063, +59429=>22063, +40885=>22064, +59430=>22064, +14799=>22065, +59431=>22065, +14815=>22066, +59432=>22066, +14963=>22067, +59433=>22067, +14800=>22068, +59434=>22068, +40886=>22069, +59435=>22069, +40887=>22070, +59436=>22070, +15182=>22071, +59437=>22071, +15470=>22072, +59438=>22072, +15584=>22073, +59439=>22073, +11943=>22074, +59440=>22074, +136663=>22075, +59441=>22075, +40888=>22076, +59442=>22076, +11946=>22077, +59443=>22077, +16470=>22078, +59444=>22078, +16735=>22079, +59445=>22079, +11950=>22080, +59446=>22080, +17207=>22081, +59447=>22081, +11955=>22082, +59448=>22082, +11958=>22083, +59449=>22083, +11959=>22084, +59450=>22084, +141711=>22085, +59451=>22085, +17329=>22086, +59452=>22086, +17324=>22087, +59453=>22087, +11963=>22088, +59454=>22088, +17373=>22089, +59455=>22089, +17622=>22090, +59456=>22090, +18017=>22091, +59457=>22091, +17996=>22092, +59458=>22092, +40889=>22093, +132361=>22093, +59459=>22093, +18211=>22094, +59460=>22094, +18217=>22095, +59461=>22095, +18300=>22096, +59462=>22096, +18317=>22097, +59463=>22097, +11978=>22098, +59464=>22098, +18759=>22099, +59465=>22099, +18810=>22100, +59466=>22100, +18813=>22101, +59467=>22101, +18818=>22102, +59468=>22102, +18819=>22103, +59469=>22103, +18821=>22104, +59470=>22104, +18822=>22105, +59471=>22105, +18847=>22106, +59472=>22106, +18843=>22107, +59473=>22107, +18871=>22108, +59474=>22108, +18870=>22109, +59475=>22109, +40890=>22110, +133533=>22110, +59476=>22110, +147966=>22111, +59477=>22111, +19619=>22112, +59478=>22112, +19615=>22113, +59479=>22113, +19616=>22114, +59480=>22114, +19617=>22115, +59481=>22115, +19575=>22116, +59482=>22116, +19618=>22117, +59483=>22117, +19731=>22118, +59484=>22118, +19732=>22119, +59485=>22119, +19733=>22120, +59486=>22120, +19734=>22121, +59487=>22121, +19735=>22122, +59488=>22122, +19736=>22123, +59489=>22123, +19737=>22124, +59490=>22124, +19886=>22125, +59491=>22125, +40891=>22126, +59492=>22126, +8364=>22353, +59244=>22353, +165=>22354, +12351=>22357, +12436=>22375, +12535=>22390, +12537=>22391, +12536=>22392, +12538=>22393, +12339=>22395, +12340=>22396, +12341=>22397, +12344=>22398, +12345=>22399, +12346=>22400, +12586=>22401, +12587=>22402, +12588=>22403, +12704=>22404, +12705=>22405, +12706=>22406, +12707=>22407, +12708=>22408, +12709=>22409, +12710=>22410, +12711=>22411, +12712=>22412, +12713=>22413, +12714=>22414, +12715=>22415, +12716=>22416, +12717=>22417, +12718=>22418, +12719=>22419, +12720=>22420, +12721=>22421, +12722=>22422, +12723=>22423, +12724=>22424, +12725=>22425, +12726=>22426, +12727=>22427, +11904=>22428, +11906=>22429, +11907=>22430, +11909=>22431, +11910=>22432, +11911=>22433, +11913=>22434, +11914=>22435, +11917=>22436, +11918=>22437, +11919=>22438, +11920=>22439, +11921=>22440, +11922=>22441, +11923=>22442, +11924=>22443, +11925=>22444, +11926=>22445, +11928=>22446, +11929=>22447, +11931=>22448, +11932=>22449, +11933=>22450, +11934=>22451, +11935=>22452, +11936=>22453, +11937=>22454, +11938=>22455, +11939=>22456, +11940=>22457, +11941=>22458, +11942=>22459, +11944=>22460, +11945=>22461, +11947=>22462, +11948=>22463, +11949=>22464, +11951=>22465, +11952=>22466, +11953=>22467, +11954=>22468, +11956=>22469, +11957=>22470, +11960=>22471, +11961=>22472, +11962=>22473, +11964=>22474, +11965=>22475, +11966=>22476, +11967=>22477, +11968=>22478, +11969=>22479, +11970=>22480, +11971=>22481, +11972=>22482, +11973=>22483, +11974=>22484, +11975=>22485, +11976=>22486, +11977=>22487, +11979=>22488, +11980=>22489, +11981=>22490, +11982=>22491, +11983=>22492, +11984=>22493, +11985=>22494, +11986=>22495, +11987=>22496, +11988=>22497, +11989=>22498, +11990=>22499, +11991=>22500, +11992=>22501, +11993=>22502, +11994=>22503, +11995=>22504, +11996=>22505, +11997=>22506, +11998=>22507, +11999=>22508, +12000=>22509, +12001=>22510, +12002=>22511, +12003=>22512, +12004=>22513, +12005=>22514, +12006=>22515, +12007=>22516, +12008=>22517, +12009=>22518, +12010=>22519, +12011=>22520, +12012=>22521, +12013=>22522, +12014=>22523, +12015=>22524, +12016=>22525, +12017=>22526, +12018=>22527, +12019=>22528, +13312=>22529, +13313=>22530, +13314=>22531, +13315=>22532, +13316=>22533, +13317=>22534, +13318=>22535, +13319=>22536, +13320=>22537, +13321=>22538, +13322=>22539, +13323=>22540, +13324=>22541, +13325=>22542, +13326=>22543, +13327=>22544, +13328=>22545, +13329=>22546, +13330=>22547, +13331=>22548, +13332=>22549, +13333=>22550, +13334=>22551, +13335=>22552, +13336=>22553, +13337=>22554, +13338=>22555, +13339=>22556, +13340=>22557, +13341=>22558, +13342=>22559, +13343=>22560, +13344=>22561, +13345=>22562, +13346=>22563, +13347=>22564, +13348=>22565, +13349=>22566, +13350=>22567, +13351=>22568, +13352=>22569, +13353=>22570, +13354=>22571, +13355=>22572, +13356=>22573, +13357=>22574, +13358=>22575, +13359=>22576, +13360=>22577, +13361=>22578, +13362=>22579, +13363=>22580, +13364=>22581, +13365=>22582, +13366=>22583, +13367=>22584, +13368=>22585, +13369=>22586, +13370=>22587, +13371=>22588, +13372=>22589, +13373=>22590, +13374=>22591, +13375=>22592, +13376=>22593, +13377=>22594, +13378=>22595, +13379=>22596, +13380=>22597, +13381=>22598, +13382=>22599, +13384=>22600, +13385=>22601, +13386=>22602, +13387=>22603, +13388=>22604, +13389=>22605, +13390=>22606, +13391=>22607, +13392=>22608, +13393=>22609, +13394=>22610, +13395=>22611, +13396=>22612, +13397=>22613, +13398=>22614, +13399=>22615, +13400=>22616, +13401=>22617, +13402=>22618, +13403=>22619, +13404=>22620, +13405=>22621, +13406=>22622, +13407=>22623, +13408=>22624, +13409=>22625, +13410=>22626, +13411=>22627, +13412=>22628, +13413=>22629, +13414=>22630, +13415=>22631, +13416=>22632, +13417=>22633, +13418=>22634, +13419=>22635, +13420=>22636, +13421=>22637, +13422=>22638, +13423=>22639, +13424=>22640, +13425=>22641, +13426=>22642, +13428=>22643, +13429=>22644, +13430=>22645, +13431=>22646, +13432=>22647, +13433=>22648, +13434=>22649, +13435=>22650, +13436=>22651, +13437=>22652, +13438=>22653, +13439=>22654, +13440=>22655, +13441=>22656, +13442=>22657, +13443=>22658, +13444=>22659, +13445=>22660, +13446=>22661, +13447=>22662, +13448=>22663, +13449=>22664, +13450=>22665, +13451=>22666, +13452=>22667, +13453=>22668, +13454=>22669, +13455=>22670, +13456=>22671, +13457=>22672, +13458=>22673, +13459=>22674, +13460=>22675, +13461=>22676, +13462=>22677, +13463=>22678, +13464=>22679, +13465=>22680, +13466=>22681, +13467=>22682, +13468=>22683, +13469=>22684, +13470=>22685, +13471=>22686, +13472=>22687, +13473=>22688, +13474=>22689, +13475=>22690, +13476=>22691, +13477=>22692, +13478=>22693, +13479=>22694, +13480=>22695, +13481=>22696, +13482=>22697, +13483=>22698, +13484=>22699, +13485=>22700, +13486=>22701, +13487=>22702, +13488=>22703, +13489=>22704, +13490=>22705, +13491=>22706, +13492=>22707, +13493=>22708, +13494=>22709, +13495=>22710, +13496=>22711, +13497=>22712, +13498=>22713, +13499=>22714, +13500=>22715, +13501=>22716, +13502=>22717, +13503=>22718, +13504=>22719, +13505=>22720, +13506=>22721, +13507=>22722, +13508=>22723, +13509=>22724, +13510=>22725, +13511=>22726, +13512=>22727, +13513=>22728, +13514=>22729, +13515=>22730, +13516=>22731, +13517=>22732, +13518=>22733, +13519=>22734, +13520=>22735, +13521=>22736, +13522=>22737, +13523=>22738, +13524=>22739, +13525=>22740, +13526=>22741, +13527=>22742, +13528=>22743, +13529=>22744, +13530=>22745, +13531=>22746, +13532=>22747, +13533=>22748, +13534=>22749, +13535=>22750, +13536=>22751, +13537=>22752, +13538=>22753, +13539=>22754, +13540=>22755, +13541=>22756, +13542=>22757, +13543=>22758, +13544=>22759, +13545=>22760, +13546=>22761, +13547=>22762, +13548=>22763, +13549=>22764, +13550=>22765, +13551=>22766, +13552=>22767, +13553=>22768, +13554=>22769, +13555=>22770, +13556=>22771, +13557=>22772, +13558=>22773, +13559=>22774, +13560=>22775, +13561=>22776, +13562=>22777, +13563=>22778, +13564=>22779, +13565=>22780, +13566=>22781, +13567=>22782, +13568=>22783, +13569=>22784, +13570=>22785, +13571=>22786, +13572=>22787, +13573=>22788, +13574=>22789, +13575=>22790, +13576=>22791, +13577=>22792, +13578=>22793, +13579=>22794, +13580=>22795, +13581=>22796, +13582=>22797, +13583=>22798, +13584=>22799, +13585=>22800, +13586=>22801, +13587=>22802, +13588=>22803, +13589=>22804, +13590=>22805, +13591=>22806, +13592=>22807, +13593=>22808, +13594=>22809, +13595=>22810, +13596=>22811, +13597=>22812, +13598=>22813, +13599=>22814, +13600=>22815, +13601=>22816, +13602=>22817, +13603=>22818, +13604=>22819, +13605=>22820, +13606=>22821, +13607=>22822, +13608=>22823, +13609=>22824, +13610=>22825, +13611=>22826, +13612=>22827, +13613=>22828, +13614=>22829, +13615=>22830, +13616=>22831, +13617=>22832, +13618=>22833, +13619=>22834, +13620=>22835, +13621=>22836, +13622=>22837, +13623=>22838, +13624=>22839, +13625=>22840, +13626=>22841, +13627=>22842, +13628=>22843, +13629=>22844, +13630=>22845, +13631=>22846, +13632=>22847, +13633=>22848, +13634=>22849, +13635=>22850, +13636=>22851, +13637=>22852, +13638=>22853, +13639=>22854, +13640=>22855, +13641=>22856, +13642=>22857, +13643=>22858, +13644=>22859, +13645=>22860, +13646=>22861, +13647=>22862, +13648=>22863, +13649=>22864, +13650=>22865, +13651=>22866, +13652=>22867, +13653=>22868, +13654=>22869, +13655=>22870, +13656=>22871, +13657=>22872, +13658=>22873, +13659=>22874, +13660=>22875, +13661=>22876, +13662=>22877, +13663=>22878, +13664=>22879, +13665=>22880, +13666=>22881, +13667=>22882, +13668=>22883, +13669=>22884, +13670=>22885, +13671=>22886, +13672=>22887, +13673=>22888, +13674=>22889, +13675=>22890, +13676=>22891, +13677=>22892, +13678=>22893, +13679=>22894, +13680=>22895, +13681=>22896, +13682=>22897, +13683=>22898, +13684=>22899, +13685=>22900, +13686=>22901, +13687=>22902, +13688=>22903, +13689=>22904, +13690=>22905, +13691=>22906, +13692=>22907, +13693=>22908, +13694=>22909, +13695=>22910, +13696=>22911, +13697=>22912, +13698=>22913, +13699=>22914, +13700=>22915, +13701=>22916, +13702=>22917, +13703=>22918, +13704=>22919, +13705=>22920, +13706=>22921, +13707=>22922, +13708=>22923, +13709=>22924, +13710=>22925, +13711=>22926, +13712=>22927, +13713=>22928, +13714=>22929, +13715=>22930, +13716=>22931, +13717=>22932, +13718=>22933, +13719=>22934, +13720=>22935, +13721=>22936, +13722=>22937, +13723=>22938, +13724=>22939, +13725=>22940, +13727=>22941, +13728=>22942, +13729=>22943, +13730=>22944, +13731=>22945, +13732=>22946, +13733=>22947, +13734=>22948, +13735=>22949, +13736=>22950, +13737=>22951, +13738=>22952, +13739=>22953, +13740=>22954, +13741=>22955, +13742=>22956, +13743=>22957, +13744=>22958, +13745=>22959, +13746=>22960, +13747=>22961, +13748=>22962, +13749=>22963, +13750=>22964, +13751=>22965, +13752=>22966, +13753=>22967, +13754=>22968, +13755=>22969, +13756=>22970, +13757=>22971, +13758=>22972, +13759=>22973, +13760=>22974, +13761=>22975, +13762=>22976, +13763=>22977, +13764=>22978, +13765=>22979, +13766=>22980, +13767=>22981, +13768=>22982, +13769=>22983, +13770=>22984, +13771=>22985, +13772=>22986, +13773=>22987, +13774=>22988, +13775=>22989, +13776=>22990, +13777=>22991, +13778=>22992, +13779=>22993, +13780=>22994, +13781=>22995, +13782=>22996, +13783=>22997, +13784=>22998, +13785=>22999, +13786=>23000, +13787=>23001, +13788=>23002, +13789=>23003, +13790=>23004, +13791=>23005, +13792=>23006, +13793=>23007, +13794=>23008, +13795=>23009, +13796=>23010, +13797=>23011, +13798=>23012, +13799=>23013, +13800=>23014, +13801=>23015, +13802=>23016, +13803=>23017, +13804=>23018, +13805=>23019, +13806=>23020, +13807=>23021, +13808=>23022, +13809=>23023, +13810=>23024, +13811=>23025, +13812=>23026, +13813=>23027, +13814=>23028, +13815=>23029, +13816=>23030, +13817=>23031, +13818=>23032, +13819=>23033, +13820=>23034, +13821=>23035, +13822=>23036, +13823=>23037, +13824=>23038, +13825=>23039, +13826=>23040, +13827=>23041, +13828=>23042, +13829=>23043, +13830=>23044, +13831=>23045, +13832=>23046, +13833=>23047, +13834=>23048, +13835=>23049, +13836=>23050, +13837=>23051, +13839=>23052, +13840=>23053, +13841=>23054, +13842=>23055, +13843=>23056, +13844=>23057, +13845=>23058, +13846=>23059, +13847=>23060, +13848=>23061, +13849=>23062, +13851=>23063, +13852=>23064, +13853=>23065, +13854=>23066, +13855=>23067, +13856=>23068, +13857=>23069, +13858=>23070, +13859=>23071, +13860=>23072, +13861=>23073, +13862=>23074, +13863=>23075, +13864=>23076, +13865=>23077, +13866=>23078, +13867=>23079, +13868=>23080, +13869=>23081, +13870=>23082, +13871=>23083, +13872=>23084, +13873=>23085, +13874=>23086, +13875=>23087, +13876=>23088, +13877=>23089, +13878=>23090, +13879=>23091, +13880=>23092, +13881=>23093, +13882=>23094, +13883=>23095, +13884=>23096, +13885=>23097, +13886=>23098, +13887=>23099, +13888=>23100, +13889=>23101, +13890=>23102, +13891=>23103, +13892=>23104, +13893=>23105, +13894=>23106, +13895=>23107, +13896=>23108, +13897=>23109, +13898=>23110, +13899=>23111, +13900=>23112, +13901=>23113, +13902=>23114, +13903=>23115, +13904=>23116, +13905=>23117, +13906=>23118, +13907=>23119, +13908=>23120, +13909=>23121, +13910=>23122, +13911=>23123, +13912=>23124, +13913=>23125, +13914=>23126, +13915=>23127, +13916=>23128, +13917=>23129, +13918=>23130, +13919=>23131, +13920=>23132, +13921=>23133, +13922=>23134, +13923=>23135, +13924=>23136, +13925=>23137, +13926=>23138, +13927=>23139, +13928=>23140, +13929=>23141, +13930=>23142, +13931=>23143, +13932=>23144, +13933=>23145, +13934=>23146, +13935=>23147, +13936=>23148, +13937=>23149, +13938=>23150, +13939=>23151, +13940=>23152, +13941=>23153, +13942=>23154, +13943=>23155, +13944=>23156, +13945=>23157, +13946=>23158, +13947=>23159, +13948=>23160, +13949=>23161, +13950=>23162, +13951=>23163, +13952=>23164, +13953=>23165, +13954=>23166, +13955=>23167, +13956=>23168, +13957=>23169, +13958=>23170, +13959=>23171, +13960=>23172, +13961=>23173, +13962=>23174, +13963=>23175, +13964=>23176, +13965=>23177, +13966=>23178, +13967=>23179, +13968=>23180, +13969=>23181, +13970=>23182, +13971=>23183, +13972=>23184, +13973=>23185, +13974=>23186, +13975=>23187, +13976=>23188, +13977=>23189, +13978=>23190, +13979=>23191, +13980=>23192, +13981=>23193, +13982=>23194, +13983=>23195, +13984=>23196, +13985=>23197, +13986=>23198, +13987=>23199, +13988=>23200, +13989=>23201, +13990=>23202, +13991=>23203, +13992=>23204, +13993=>23205, +13994=>23206, +13995=>23207, +13996=>23208, +13997=>23209, +13998=>23210, +13999=>23211, +14000=>23212, +14001=>23213, +14002=>23214, +14003=>23215, +14004=>23216, +14005=>23217, +14006=>23218, +14007=>23219, +14008=>23220, +14009=>23221, +14010=>23222, +14011=>23223, +14012=>23224, +14013=>23225, +14014=>23226, +14015=>23227, +14016=>23228, +14017=>23229, +14018=>23230, +14019=>23231, +14020=>23232, +14021=>23233, +14022=>23234, +14023=>23235, +14024=>23236, +14025=>23237, +14026=>23238, +14027=>23239, +14028=>23240, +14029=>23241, +14030=>23242, +14031=>23243, +14032=>23244, +14033=>23245, +14034=>23246, +14035=>23247, +14036=>23248, +14037=>23249, +14038=>23250, +14039=>23251, +14040=>23252, +14041=>23253, +14042=>23254, +14043=>23255, +14044=>23256, +14045=>23257, +14046=>23258, +14047=>23259, +14048=>23260, +14049=>23261, +14050=>23262, +14051=>23263, +14052=>23264, +14053=>23265, +14054=>23266, +14055=>23267, +14056=>23268, +14057=>23269, +14058=>23270, +14059=>23271, +14060=>23272, +14061=>23273, +14062=>23274, +14063=>23275, +14064=>23276, +14065=>23277, +14066=>23278, +14067=>23279, +14068=>23280, +14069=>23281, +14070=>23282, +14071=>23283, +14072=>23284, +14073=>23285, +14074=>23286, +14075=>23287, +14076=>23288, +14077=>23289, +14078=>23290, +14079=>23291, +14080=>23292, +14081=>23293, +14082=>23294, +14083=>23295, +14084=>23296, +14085=>23297, +14086=>23298, +14087=>23299, +14088=>23300, +14089=>23301, +14090=>23302, +14091=>23303, +14092=>23304, +14093=>23305, +14094=>23306, +14095=>23307, +14096=>23308, +14097=>23309, +14098=>23310, +14099=>23311, +14100=>23312, +14101=>23313, +14102=>23314, +14103=>23315, +14104=>23316, +14105=>23317, +14106=>23318, +14107=>23319, +14108=>23320, +14109=>23321, +14110=>23322, +14111=>23323, +14112=>23324, +14113=>23325, +14114=>23326, +14115=>23327, +14116=>23328, +14117=>23329, +14118=>23330, +14119=>23331, +14120=>23332, +14121=>23333, +14122=>23334, +14123=>23335, +14124=>23336, +14125=>23337, +14126=>23338, +14127=>23339, +14128=>23340, +14129=>23341, +14130=>23342, +14131=>23343, +14132=>23344, +14133=>23345, +14134=>23346, +14135=>23347, +14136=>23348, +14137=>23349, +14138=>23350, +14139=>23351, +14140=>23352, +14141=>23353, +14142=>23354, +14143=>23355, +14144=>23356, +14145=>23357, +14146=>23358, +14147=>23359, +14148=>23360, +14149=>23361, +14150=>23362, +14151=>23363, +14152=>23364, +14153=>23365, +14154=>23366, +14155=>23367, +14156=>23368, +14157=>23369, +14158=>23370, +14159=>23371, +14160=>23372, +14161=>23373, +14162=>23374, +14163=>23375, +14164=>23376, +14165=>23377, +14166=>23378, +14167=>23379, +14168=>23380, +14169=>23381, +14170=>23382, +14171=>23383, +14172=>23384, +14173=>23385, +14174=>23386, +14175=>23387, +14176=>23388, +14177=>23389, +14178=>23390, +14179=>23391, +14180=>23392, +14181=>23393, +14182=>23394, +14183=>23395, +14184=>23396, +14185=>23397, +14186=>23398, +14187=>23399, +14188=>23400, +14189=>23401, +14190=>23402, +14191=>23403, +14192=>23404, +14193=>23405, +14194=>23406, +14195=>23407, +14196=>23408, +14197=>23409, +14198=>23410, +14199=>23411, +14200=>23412, +14201=>23413, +14202=>23414, +14203=>23415, +14204=>23416, +14205=>23417, +14206=>23418, +14207=>23419, +14208=>23420, +14209=>23421, +14210=>23422, +14211=>23423, +14212=>23424, +14213=>23425, +14214=>23426, +14215=>23427, +14216=>23428, +14217=>23429, +14218=>23430, +14219=>23431, +14220=>23432, +14221=>23433, +14222=>23434, +14223=>23435, +14224=>23436, +14225=>23437, +14226=>23438, +14227=>23439, +14228=>23440, +14229=>23441, +14230=>23442, +14231=>23443, +14232=>23444, +14233=>23445, +14234=>23446, +14235=>23447, +14236=>23448, +14237=>23449, +14238=>23450, +14239=>23451, +14240=>23452, +14241=>23453, +14242=>23454, +14243=>23455, +14244=>23456, +14245=>23457, +14246=>23458, +14247=>23459, +14248=>23460, +14249=>23461, +14250=>23462, +14251=>23463, +14252=>23464, +14253=>23465, +14254=>23466, +14255=>23467, +14256=>23468, +14257=>23469, +14258=>23470, +14259=>23471, +14260=>23472, +14261=>23473, +14262=>23474, +14263=>23475, +14264=>23476, +14265=>23477, +14266=>23478, +14267=>23479, +14268=>23480, +14269=>23481, +14270=>23482, +14271=>23483, +14272=>23484, +14273=>23485, +14274=>23486, +14275=>23487, +14276=>23488, +14277=>23489, +14278=>23490, +14279=>23491, +14280=>23492, +14281=>23493, +14282=>23494, +14283=>23495, +14284=>23496, +14285=>23497, +14286=>23498, +14287=>23499, +14288=>23500, +14289=>23501, +14290=>23502, +14291=>23503, +14292=>23504, +14293=>23505, +14294=>23506, +14295=>23507, +14296=>23508, +14297=>23509, +14298=>23510, +14299=>23511, +14300=>23512, +14301=>23513, +14302=>23514, +14303=>23515, +14304=>23516, +14305=>23517, +14306=>23518, +14307=>23519, +14308=>23520, +14309=>23521, +14310=>23522, +14311=>23523, +14312=>23524, +14313=>23525, +14314=>23526, +14315=>23527, +14316=>23528, +14317=>23529, +14318=>23530, +14319=>23531, +14320=>23532, +14321=>23533, +14322=>23534, +14323=>23535, +14324=>23536, +14325=>23537, +14326=>23538, +14327=>23539, +14328=>23540, +14329=>23541, +14330=>23542, +14331=>23543, +14332=>23544, +14333=>23545, +14334=>23546, +14335=>23547, +14336=>23548, +14337=>23549, +14338=>23550, +14339=>23551, +14340=>23552, +14341=>23553, +14342=>23554, +14343=>23555, +14344=>23556, +14345=>23557, +14346=>23558, +14347=>23559, +14348=>23560, +14349=>23561, +14350=>23562, +14351=>23563, +14352=>23564, +14353=>23565, +14354=>23566, +14355=>23567, +14356=>23568, +14357=>23569, +14358=>23570, +14359=>23571, +14360=>23572, +14361=>23573, +14362=>23574, +14363=>23575, +14364=>23576, +14365=>23577, +14366=>23578, +14367=>23579, +14368=>23580, +14369=>23581, +14370=>23582, +14371=>23583, +14372=>23584, +14373=>23585, +14374=>23586, +14375=>23587, +14376=>23588, +14377=>23589, +14378=>23590, +14379=>23591, +14380=>23592, +14381=>23593, +14382=>23594, +14383=>23595, +14384=>23596, +14385=>23597, +14386=>23598, +14387=>23599, +14388=>23600, +14389=>23601, +14390=>23602, +14391=>23603, +14392=>23604, +14393=>23605, +14394=>23606, +14395=>23607, +14396=>23608, +14397=>23609, +14398=>23610, +14399=>23611, +14400=>23612, +14401=>23613, +14402=>23614, +14403=>23615, +14404=>23616, +14405=>23617, +14406=>23618, +14407=>23619, +14408=>23620, +14409=>23621, +14410=>23622, +14411=>23623, +14412=>23624, +14413=>23625, +14414=>23626, +14415=>23627, +14416=>23628, +14417=>23629, +14418=>23630, +14419=>23631, +14420=>23632, +14421=>23633, +14422=>23634, +14423=>23635, +14424=>23636, +14425=>23637, +14426=>23638, +14427=>23639, +14428=>23640, +14429=>23641, +14430=>23642, +14431=>23643, +14432=>23644, +14433=>23645, +14434=>23646, +14435=>23647, +14436=>23648, +14437=>23649, +14438=>23650, +14439=>23651, +14440=>23652, +14441=>23653, +14442=>23654, +14443=>23655, +14444=>23656, +14445=>23657, +14446=>23658, +14447=>23659, +14448=>23660, +14449=>23661, +14450=>23662, +14451=>23663, +14452=>23664, +14453=>23665, +14454=>23666, +14455=>23667, +14456=>23668, +14457=>23669, +14458=>23670, +14459=>23671, +14460=>23672, +14461=>23673, +14462=>23674, +14463=>23675, +14464=>23676, +14465=>23677, +14466=>23678, +14467=>23679, +14468=>23680, +14469=>23681, +14470=>23682, +14471=>23683, +14472=>23684, +14473=>23685, +14474=>23686, +14475=>23687, +14476=>23688, +14477=>23689, +14478=>23690, +14479=>23691, +14480=>23692, +14481=>23693, +14482=>23694, +14483=>23695, +14484=>23696, +14485=>23697, +14486=>23698, +14487=>23699, +14488=>23700, +14489=>23701, +14490=>23702, +14491=>23703, +14492=>23704, +14493=>23705, +14494=>23706, +14495=>23707, +14496=>23708, +14497=>23709, +14498=>23710, +14499=>23711, +14500=>23712, +14501=>23713, +14502=>23714, +14503=>23715, +14504=>23716, +14505=>23717, +14506=>23718, +14507=>23719, +14508=>23720, +14509=>23721, +14510=>23722, +14511=>23723, +14512=>23724, +14513=>23725, +14514=>23726, +14515=>23727, +14516=>23728, +14517=>23729, +14518=>23730, +14519=>23731, +14520=>23732, +14521=>23733, +14522=>23734, +14523=>23735, +14524=>23736, +14525=>23737, +14526=>23738, +14527=>23739, +14528=>23740, +14529=>23741, +14530=>23742, +14531=>23743, +14532=>23744, +14533=>23745, +14534=>23746, +14535=>23747, +14536=>23748, +14537=>23749, +14538=>23750, +14539=>23751, +14540=>23752, +14541=>23753, +14542=>23754, +14543=>23755, +14544=>23756, +14545=>23757, +14546=>23758, +14547=>23759, +14548=>23760, +14549=>23761, +14550=>23762, +14551=>23763, +14552=>23764, +14553=>23765, +14554=>23766, +14555=>23767, +14556=>23768, +14557=>23769, +14558=>23770, +14559=>23771, +14560=>23772, +14561=>23773, +14562=>23774, +14563=>23775, +14564=>23776, +14565=>23777, +14566=>23778, +14567=>23779, +14568=>23780, +14569=>23781, +14570=>23782, +14571=>23783, +14572=>23784, +14573=>23785, +14574=>23786, +14575=>23787, +14576=>23788, +14577=>23789, +14578=>23790, +14579=>23791, +14580=>23792, +14581=>23793, +14582=>23794, +14583=>23795, +14584=>23796, +14585=>23797, +14586=>23798, +14587=>23799, +14588=>23800, +14589=>23801, +14590=>23802, +14591=>23803, +14592=>23804, +14593=>23805, +14594=>23806, +14595=>23807, +14596=>23808, +14597=>23809, +14598=>23810, +14599=>23811, +14600=>23812, +14601=>23813, +14602=>23814, +14603=>23815, +14604=>23816, +14605=>23817, +14606=>23818, +14607=>23819, +14608=>23820, +14609=>23821, +14610=>23822, +14611=>23823, +14612=>23824, +14613=>23825, +14614=>23826, +14615=>23827, +14617=>23828, +14618=>23829, +14619=>23830, +14620=>23831, +14621=>23832, +14622=>23833, +14623=>23834, +14624=>23835, +14625=>23836, +14626=>23837, +14627=>23838, +14628=>23839, +14629=>23840, +14630=>23841, +14631=>23842, +14632=>23843, +14633=>23844, +14634=>23845, +14635=>23846, +14636=>23847, +14637=>23848, +14638=>23849, +14639=>23850, +14640=>23851, +14641=>23852, +14642=>23853, +14643=>23854, +14644=>23855, +14645=>23856, +14646=>23857, +14647=>23858, +14648=>23859, +14649=>23860, +14650=>23861, +14651=>23862, +14652=>23863, +14653=>23864, +14654=>23865, +14655=>23866, +14656=>23867, +14657=>23868, +14658=>23869, +14659=>23870, +14660=>23871, +14661=>23872, +14662=>23873, +14663=>23874, +14664=>23875, +14665=>23876, +14666=>23877, +14667=>23878, +14668=>23879, +14669=>23880, +14670=>23881, +14671=>23882, +14672=>23883, +14673=>23884, +14674=>23885, +14675=>23886, +14676=>23887, +14677=>23888, +14678=>23889, +14679=>23890, +14680=>23891, +14681=>23892, +14682=>23893, +14683=>23894, +14684=>23895, +14685=>23896, +14686=>23897, +14687=>23898, +14688=>23899, +14689=>23900, +14690=>23901, +14691=>23902, +14692=>23903, +14693=>23904, +14694=>23905, +14695=>23906, +14696=>23907, +14697=>23908, +14698=>23909, +14699=>23910, +14700=>23911, +14701=>23912, +14703=>23913, +14704=>23914, +14705=>23915, +14706=>23916, +14707=>23917, +14708=>23918, +14709=>23919, +14710=>23920, +14711=>23921, +14712=>23922, +14713=>23923, +14714=>23924, +14715=>23925, +14716=>23926, +14717=>23927, +14718=>23928, +14719=>23929, +14720=>23930, +14721=>23931, +14722=>23932, +14723=>23933, +14724=>23934, +14725=>23935, +14726=>23936, +14727=>23937, +14728=>23938, +14729=>23939, +14730=>23940, +14731=>23941, +14732=>23942, +14733=>23943, +14734=>23944, +14735=>23945, +14736=>23946, +14737=>23947, +14738=>23948, +14739=>23949, +14740=>23950, +14741=>23951, +14742=>23952, +14743=>23953, +14744=>23954, +14745=>23955, +14746=>23956, +14747=>23957, +14748=>23958, +14749=>23959, +14750=>23960, +14751=>23961, +14752=>23962, +14753=>23963, +14754=>23964, +14755=>23965, +14756=>23966, +14757=>23967, +14758=>23968, +14759=>23969, +14760=>23970, +14761=>23971, +14762=>23972, +14763=>23973, +14764=>23974, +14765=>23975, +14766=>23976, +14767=>23977, +14768=>23978, +14769=>23979, +14770=>23980, +14771=>23981, +14772=>23982, +14773=>23983, +14774=>23984, +14775=>23985, +14776=>23986, +14777=>23987, +14778=>23988, +14779=>23989, +14780=>23990, +14781=>23991, +14782=>23992, +14783=>23993, +14784=>23994, +14785=>23995, +14786=>23996, +14787=>23997, +14788=>23998, +14789=>23999, +14790=>24000, +14791=>24001, +14792=>24002, +14793=>24003, +14794=>24004, +14795=>24005, +14796=>24006, +14797=>24007, +14798=>24008, +14801=>24009, +14802=>24010, +14803=>24011, +14804=>24012, +14805=>24013, +14806=>24014, +14807=>24015, +14808=>24016, +14809=>24017, +14810=>24018, +14811=>24019, +14812=>24020, +14813=>24021, +14814=>24022, +14816=>24023, +14817=>24024, +14818=>24025, +14819=>24026, +14820=>24027, +14821=>24028, +14822=>24029, +14823=>24030, +14824=>24031, +14825=>24032, +14826=>24033, +14827=>24034, +14828=>24035, +14829=>24036, +14830=>24037, +14831=>24038, +14832=>24039, +14833=>24040, +14834=>24041, +14835=>24042, +14836=>24043, +14837=>24044, +14838=>24045, +14839=>24046, +14840=>24047, +14841=>24048, +14842=>24049, +14843=>24050, +14844=>24051, +14845=>24052, +14846=>24053, +14847=>24054, +14848=>24055, +14849=>24056, +14850=>24057, +14851=>24058, +14852=>24059, +14853=>24060, +14854=>24061, +14855=>24062, +14856=>24063, +14857=>24064, +14858=>24065, +14859=>24066, +14860=>24067, +14861=>24068, +14862=>24069, +14863=>24070, +14864=>24071, +14865=>24072, +14866=>24073, +14867=>24074, +14868=>24075, +14869=>24076, +14870=>24077, +14871=>24078, +14872=>24079, +14873=>24080, +14874=>24081, +14875=>24082, +14876=>24083, +14877=>24084, +14878=>24085, +14879=>24086, +14880=>24087, +14881=>24088, +14882=>24089, +14883=>24090, +14884=>24091, +14885=>24092, +14886=>24093, +14887=>24094, +14888=>24095, +14889=>24096, +14890=>24097, +14891=>24098, +14892=>24099, +14893=>24100, +14894=>24101, +14895=>24102, +14896=>24103, +14897=>24104, +14898=>24105, +14899=>24106, +14900=>24107, +14901=>24108, +14902=>24109, +14903=>24110, +14904=>24111, +14905=>24112, +14906=>24113, +14907=>24114, +14908=>24115, +14909=>24116, +14910=>24117, +14911=>24118, +14912=>24119, +14913=>24120, +14914=>24121, +14915=>24122, +14916=>24123, +14917=>24124, +14918=>24125, +14919=>24126, +14920=>24127, +14921=>24128, +14922=>24129, +14923=>24130, +14924=>24131, +14925=>24132, +14926=>24133, +14927=>24134, +14928=>24135, +14929=>24136, +14930=>24137, +14931=>24138, +14932=>24139, +14933=>24140, +14934=>24141, +14935=>24142, +14936=>24143, +14937=>24144, +14938=>24145, +14939=>24146, +14940=>24147, +14941=>24148, +14942=>24149, +14943=>24150, +14944=>24151, +14945=>24152, +14946=>24153, +14947=>24154, +14948=>24155, +14949=>24156, +14950=>24157, +14951=>24158, +14952=>24159, +14953=>24160, +14954=>24161, +14955=>24162, +14956=>24163, +14957=>24164, +14958=>24165, +14959=>24166, +14960=>24167, +14961=>24168, +14962=>24169, +14964=>24170, +14965=>24171, +14966=>24172, +14967=>24173, +14968=>24174, +14969=>24175, +14970=>24176, +14971=>24177, +14972=>24178, +14973=>24179, +14974=>24180, +14975=>24181, +14976=>24182, +14977=>24183, +14978=>24184, +14979=>24185, +14980=>24186, +14981=>24187, +14982=>24188, +14983=>24189, +14984=>24190, +14985=>24191, +14986=>24192, +14987=>24193, +14988=>24194, +14989=>24195, +14990=>24196, +14991=>24197, +14992=>24198, +14993=>24199, +14994=>24200, +14995=>24201, +14996=>24202, +14997=>24203, +14998=>24204, +14999=>24205, +15000=>24206, +15001=>24207, +15002=>24208, +15003=>24209, +15004=>24210, +15005=>24211, +15006=>24212, +15007=>24213, +15008=>24214, +15009=>24215, +15010=>24216, +15011=>24217, +15012=>24218, +15013=>24219, +15014=>24220, +15015=>24221, +15016=>24222, +15017=>24223, +15018=>24224, +15019=>24225, +15020=>24226, +15021=>24227, +15022=>24228, +15023=>24229, +15024=>24230, +15025=>24231, +15026=>24232, +15027=>24233, +15028=>24234, +15029=>24235, +15030=>24236, +15031=>24237, +15032=>24238, +15033=>24239, +15034=>24240, +15035=>24241, +15036=>24242, +15037=>24243, +15038=>24244, +15039=>24245, +15040=>24246, +15041=>24247, +15042=>24248, +15043=>24249, +15044=>24250, +15045=>24251, +15046=>24252, +15047=>24253, +15048=>24254, +15049=>24255, +15050=>24256, +15051=>24257, +15052=>24258, +15053=>24259, +15054=>24260, +15055=>24261, +15056=>24262, +15057=>24263, +15058=>24264, +15059=>24265, +15060=>24266, +15061=>24267, +15062=>24268, +15063=>24269, +15064=>24270, +15065=>24271, +15066=>24272, +15067=>24273, +15068=>24274, +15069=>24275, +15070=>24276, +15071=>24277, +15072=>24278, +15073=>24279, +15074=>24280, +15075=>24281, +15076=>24282, +15077=>24283, +15078=>24284, +15079=>24285, +15080=>24286, +15081=>24287, +15082=>24288, +15083=>24289, +15084=>24290, +15085=>24291, +15086=>24292, +15087=>24293, +15088=>24294, +15089=>24295, +15090=>24296, +15091=>24297, +15092=>24298, +15093=>24299, +15094=>24300, +15095=>24301, +15096=>24302, +15097=>24303, +15098=>24304, +15099=>24305, +15100=>24306, +15101=>24307, +15102=>24308, +15103=>24309, +15104=>24310, +15105=>24311, +15106=>24312, +15107=>24313, +15108=>24314, +15109=>24315, +15110=>24316, +15111=>24317, +15112=>24318, +15113=>24319, +15114=>24320, +15115=>24321, +15116=>24322, +15117=>24323, +15118=>24324, +15119=>24325, +15120=>24326, +15121=>24327, +15122=>24328, +15123=>24329, +15124=>24330, +15125=>24331, +15126=>24332, +15127=>24333, +15128=>24334, +15129=>24335, +15130=>24336, +15131=>24337, +15132=>24338, +15133=>24339, +15134=>24340, +15135=>24341, +15136=>24342, +15137=>24343, +15138=>24344, +15139=>24345, +15140=>24346, +15141=>24347, +15142=>24348, +15143=>24349, +15144=>24350, +15145=>24351, +15146=>24352, +15147=>24353, +15148=>24354, +15149=>24355, +15150=>24356, +15151=>24357, +15152=>24358, +15153=>24359, +15154=>24360, +15155=>24361, +15156=>24362, +15157=>24363, +15158=>24364, +15159=>24365, +15160=>24366, +15161=>24367, +15162=>24368, +15163=>24369, +15164=>24370, +15165=>24371, +15166=>24372, +15167=>24373, +15168=>24374, +15169=>24375, +15170=>24376, +15171=>24377, +15172=>24378, +15173=>24379, +15174=>24380, +15175=>24381, +15176=>24382, +15177=>24383, +15178=>24384, +15179=>24385, +15180=>24386, +15181=>24387, +15183=>24388, +15184=>24389, +15185=>24390, +15186=>24391, +15187=>24392, +15188=>24393, +15189=>24394, +15190=>24395, +15191=>24396, +15192=>24397, +15193=>24398, +15194=>24399, +15195=>24400, +15196=>24401, +15197=>24402, +15198=>24403, +15199=>24404, +15200=>24405, +15201=>24406, +15202=>24407, +15203=>24408, +15204=>24409, +15205=>24410, +15206=>24411, +15207=>24412, +15208=>24413, +15209=>24414, +15210=>24415, +15211=>24416, +15212=>24417, +15213=>24418, +15214=>24419, +15215=>24420, +15216=>24421, +15217=>24422, +15218=>24423, +15219=>24424, +15220=>24425, +15221=>24426, +15222=>24427, +15223=>24428, +15224=>24429, +15225=>24430, +15226=>24431, +15227=>24432, +15228=>24433, +15229=>24434, +15230=>24435, +15231=>24436, +15232=>24437, +15233=>24438, +15234=>24439, +15235=>24440, +15236=>24441, +15237=>24442, +15238=>24443, +15239=>24444, +15240=>24445, +15241=>24446, +15242=>24447, +15243=>24448, +15244=>24449, +15245=>24450, +15246=>24451, +15247=>24452, +15248=>24453, +15249=>24454, +15250=>24455, +15251=>24456, +15252=>24457, +15253=>24458, +15254=>24459, +15255=>24460, +15256=>24461, +15257=>24462, +15258=>24463, +15259=>24464, +15260=>24465, +15261=>24466, +15262=>24467, +15263=>24468, +15264=>24469, +15265=>24470, +15266=>24471, +15267=>24472, +15268=>24473, +15269=>24474, +15270=>24475, +15271=>24476, +15272=>24477, +15273=>24478, +15274=>24479, +15275=>24480, +15276=>24481, +15277=>24482, +15278=>24483, +15279=>24484, +15280=>24485, +15281=>24486, +15282=>24487, +15283=>24488, +15284=>24489, +15285=>24490, +15286=>24491, +15287=>24492, +15288=>24493, +15289=>24494, +15290=>24495, +15291=>24496, +15292=>24497, +15293=>24498, +15294=>24499, +15295=>24500, +15296=>24501, +15297=>24502, +15298=>24503, +15299=>24504, +15300=>24505, +15301=>24506, +15302=>24507, +15303=>24508, +15304=>24509, +15305=>24510, +15306=>24511, +15307=>24512, +15308=>24513, +15309=>24514, +15310=>24515, +15311=>24516, +15312=>24517, +15313=>24518, +15314=>24519, +15315=>24520, +15316=>24521, +15317=>24522, +15318=>24523, +15319=>24524, +15320=>24525, +15321=>24526, +15322=>24527, +15323=>24528, +15324=>24529, +15325=>24530, +15326=>24531, +15327=>24532, +15328=>24533, +15329=>24534, +15330=>24535, +15331=>24536, +15332=>24537, +15333=>24538, +15334=>24539, +15335=>24540, +15336=>24541, +15337=>24542, +15338=>24543, +15339=>24544, +15340=>24545, +15341=>24546, +15342=>24547, +15343=>24548, +15344=>24549, +15345=>24550, +15346=>24551, +15347=>24552, +15348=>24553, +15349=>24554, +15350=>24555, +15351=>24556, +15352=>24557, +15353=>24558, +15354=>24559, +15355=>24560, +15356=>24561, +15357=>24562, +15358=>24563, +15359=>24564, +15360=>24565, +15361=>24566, +15362=>24567, +15363=>24568, +15364=>24569, +15365=>24570, +15366=>24571, +15367=>24572, +15368=>24573, +15369=>24574, +15370=>24575, +15371=>24576, +15372=>24577, +15373=>24578, +15374=>24579, +15375=>24580, +15376=>24581, +15377=>24582, +15378=>24583, +15379=>24584, +15380=>24585, +15381=>24586, +15382=>24587, +15383=>24588, +15384=>24589, +15385=>24590, +15386=>24591, +15387=>24592, +15388=>24593, +15389=>24594, +15390=>24595, +15391=>24596, +15392=>24597, +15393=>24598, +15394=>24599, +15395=>24600, +15396=>24601, +15397=>24602, +15398=>24603, +15399=>24604, +15400=>24605, +15401=>24606, +15402=>24607, +15403=>24608, +15404=>24609, +15405=>24610, +15406=>24611, +15407=>24612, +15408=>24613, +15409=>24614, +15410=>24615, +15411=>24616, +15412=>24617, +15413=>24618, +15414=>24619, +15415=>24620, +15416=>24621, +15417=>24622, +15418=>24623, +15419=>24624, +15420=>24625, +15421=>24626, +15422=>24627, +15423=>24628, +15424=>24629, +15425=>24630, +15426=>24631, +15427=>24632, +15428=>24633, +15429=>24634, +15430=>24635, +15431=>24636, +15432=>24637, +15433=>24638, +15434=>24639, +15435=>24640, +15436=>24641, +15437=>24642, +15438=>24643, +15439=>24644, +15440=>24645, +15441=>24646, +15442=>24647, +15443=>24648, +15444=>24649, +15445=>24650, +15446=>24651, +15447=>24652, +15448=>24653, +15449=>24654, +15450=>24655, +15451=>24656, +15452=>24657, +15453=>24658, +15454=>24659, +15455=>24660, +15456=>24661, +15457=>24662, +15458=>24663, +15459=>24664, +15460=>24665, +15461=>24666, +15462=>24667, +15463=>24668, +15464=>24669, +15465=>24670, +15466=>24671, +15467=>24672, +15468=>24673, +15469=>24674, +15471=>24675, +15472=>24676, +15473=>24677, +15474=>24678, +15475=>24679, +15476=>24680, +15477=>24681, +15478=>24682, +15479=>24683, +15480=>24684, +15481=>24685, +15482=>24686, +15483=>24687, +15484=>24688, +15485=>24689, +15486=>24690, +15487=>24691, +15488=>24692, +15489=>24693, +15490=>24694, +15491=>24695, +15492=>24696, +15493=>24697, +15494=>24698, +15495=>24699, +15496=>24700, +15497=>24701, +15498=>24702, +15499=>24703, +15500=>24704, +15501=>24705, +15502=>24706, +15503=>24707, +15504=>24708, +15505=>24709, +15506=>24710, +15507=>24711, +15508=>24712, +15509=>24713, +15510=>24714, +15511=>24715, +15512=>24716, +15513=>24717, +15514=>24718, +15515=>24719, +15516=>24720, +15517=>24721, +15518=>24722, +15519=>24723, +15520=>24724, +15521=>24725, +15522=>24726, +15523=>24727, +15524=>24728, +15525=>24729, +15526=>24730, +15527=>24731, +15528=>24732, +15529=>24733, +15530=>24734, +15531=>24735, +15532=>24736, +15533=>24737, +15534=>24738, +15535=>24739, +15536=>24740, +15537=>24741, +15538=>24742, +15539=>24743, +15540=>24744, +15541=>24745, +15542=>24746, +15543=>24747, +15544=>24748, +15545=>24749, +15546=>24750, +15547=>24751, +15548=>24752, +15549=>24753, +15550=>24754, +15551=>24755, +15552=>24756, +15553=>24757, +15554=>24758, +15555=>24759, +15556=>24760, +15557=>24761, +15558=>24762, +15559=>24763, +15560=>24764, +15561=>24765, +15562=>24766, +15563=>24767, +15564=>24768, +15565=>24769, +15566=>24770, +15567=>24771, +15568=>24772, +15569=>24773, +15570=>24774, +15571=>24775, +15572=>24776, +15573=>24777, +15574=>24778, +15575=>24779, +15576=>24780, +15577=>24781, +15578=>24782, +15579=>24783, +15580=>24784, +15581=>24785, +15582=>24786, +15583=>24787, +15585=>24788, +15586=>24789, +15587=>24790, +15588=>24791, +15589=>24792, +15590=>24793, +15591=>24794, +15592=>24795, +15593=>24796, +15594=>24797, +15595=>24798, +15596=>24799, +15597=>24800, +15598=>24801, +15599=>24802, +15600=>24803, +15601=>24804, +15602=>24805, +15603=>24806, +15604=>24807, +15605=>24808, +15606=>24809, +15607=>24810, +15608=>24811, +15609=>24812, +15610=>24813, +15611=>24814, +15612=>24815, +15613=>24816, +15614=>24817, +15615=>24818, +15616=>24819, +15617=>24820, +15618=>24821, +15619=>24822, +15620=>24823, +15621=>24824, +15622=>24825, +15623=>24826, +15624=>24827, +15625=>24828, +15626=>24829, +15627=>24830, +15628=>24831, +15629=>24832, +15630=>24833, +15631=>24834, +15632=>24835, +15633=>24836, +15634=>24837, +15635=>24838, +15636=>24839, +15637=>24840, +15638=>24841, +15639=>24842, +15640=>24843, +15641=>24844, +15642=>24845, +15643=>24846, +15644=>24847, +15645=>24848, +15646=>24849, +15647=>24850, +15648=>24851, +15649=>24852, +15650=>24853, +15651=>24854, +15652=>24855, +15653=>24856, +15654=>24857, +15655=>24858, +15656=>24859, +15657=>24860, +15658=>24861, +15659=>24862, +15660=>24863, +15661=>24864, +15662=>24865, +15663=>24866, +15664=>24867, +15665=>24868, +15666=>24869, +15667=>24870, +15668=>24871, +15669=>24872, +15670=>24873, +15671=>24874, +15672=>24875, +15673=>24876, +15674=>24877, +15675=>24878, +15676=>24879, +15677=>24880, +15678=>24881, +15679=>24882, +15680=>24883, +15681=>24884, +15682=>24885, +15683=>24886, +15684=>24887, +15685=>24888, +15686=>24889, +15687=>24890, +15688=>24891, +15689=>24892, +15690=>24893, +15691=>24894, +15692=>24895, +15693=>24896, +15694=>24897, +15695=>24898, +15696=>24899, +15697=>24900, +15698=>24901, +15699=>24902, +15700=>24903, +15701=>24904, +15702=>24905, +15703=>24906, +15704=>24907, +15705=>24908, +15706=>24909, +15707=>24910, +15708=>24911, +15709=>24912, +15710=>24913, +15711=>24914, +15712=>24915, +15713=>24916, +15714=>24917, +15715=>24918, +15716=>24919, +15717=>24920, +15718=>24921, +15719=>24922, +15720=>24923, +15721=>24924, +15722=>24925, +15723=>24926, +15724=>24927, +15725=>24928, +15726=>24929, +15727=>24930, +15728=>24931, +15729=>24932, +15730=>24933, +15731=>24934, +15732=>24935, +15733=>24936, +15734=>24937, +15735=>24938, +15736=>24939, +15737=>24940, +15738=>24941, +15739=>24942, +15740=>24943, +15741=>24944, +15742=>24945, +15743=>24946, +15744=>24947, +15745=>24948, +15746=>24949, +15747=>24950, +15748=>24951, +15749=>24952, +15750=>24953, +15751=>24954, +15752=>24955, +15753=>24956, +15754=>24957, +15755=>24958, +15756=>24959, +15757=>24960, +15758=>24961, +15759=>24962, +15760=>24963, +15761=>24964, +15762=>24965, +15763=>24966, +15764=>24967, +15765=>24968, +15766=>24969, +15767=>24970, +15768=>24971, +15769=>24972, +15770=>24973, +15771=>24974, +15772=>24975, +15773=>24976, +15774=>24977, +15775=>24978, +15776=>24979, +15777=>24980, +15778=>24981, +15779=>24982, +15780=>24983, +15781=>24984, +15782=>24985, +15783=>24986, +15784=>24987, +15785=>24988, +15786=>24989, +15787=>24990, +15788=>24991, +15789=>24992, +15790=>24993, +15791=>24994, +15792=>24995, +15793=>24996, +15794=>24997, +15795=>24998, +15796=>24999, +15797=>25000, +15798=>25001, +15799=>25002, +15800=>25003, +15801=>25004, +15802=>25005, +15803=>25006, +15804=>25007, +15805=>25008, +15806=>25009, +15807=>25010, +15808=>25011, +15809=>25012, +15810=>25013, +15811=>25014, +15812=>25015, +15813=>25016, +15814=>25017, +15815=>25018, +15816=>25019, +15817=>25020, +15818=>25021, +15819=>25022, +15820=>25023, +15821=>25024, +15822=>25025, +15823=>25026, +15824=>25027, +15825=>25028, +15826=>25029, +15827=>25030, +15828=>25031, +15829=>25032, +15830=>25033, +15831=>25034, +15832=>25035, +15833=>25036, +15834=>25037, +15835=>25038, +15836=>25039, +15837=>25040, +15838=>25041, +15839=>25042, +15840=>25043, +15841=>25044, +15842=>25045, +15843=>25046, +15844=>25047, +15845=>25048, +15846=>25049, +15847=>25050, +15848=>25051, +15849=>25052, +15850=>25053, +15851=>25054, +15852=>25055, +15853=>25056, +15854=>25057, +15855=>25058, +15856=>25059, +15857=>25060, +15858=>25061, +15859=>25062, +15860=>25063, +15861=>25064, +15862=>25065, +15863=>25066, +15864=>25067, +15865=>25068, +15866=>25069, +15867=>25070, +15868=>25071, +15869=>25072, +15870=>25073, +15871=>25074, +15872=>25075, +15873=>25076, +15874=>25077, +15875=>25078, +15876=>25079, +15877=>25080, +15878=>25081, +15879=>25082, +15880=>25083, +15881=>25084, +15882=>25085, +15883=>25086, +15884=>25087, +15885=>25088, +15886=>25089, +15887=>25090, +15888=>25091, +15889=>25092, +15890=>25093, +15891=>25094, +15892=>25095, +15893=>25096, +15894=>25097, +15895=>25098, +15896=>25099, +15897=>25100, +15898=>25101, +15899=>25102, +15900=>25103, +15901=>25104, +15902=>25105, +15903=>25106, +15904=>25107, +15905=>25108, +15906=>25109, +15907=>25110, +15908=>25111, +15909=>25112, +15910=>25113, +15911=>25114, +15912=>25115, +15913=>25116, +15914=>25117, +15915=>25118, +15916=>25119, +15917=>25120, +15918=>25121, +15919=>25122, +15920=>25123, +15921=>25124, +15922=>25125, +15923=>25126, +15924=>25127, +15925=>25128, +15926=>25129, +15927=>25130, +15928=>25131, +15929=>25132, +15930=>25133, +15931=>25134, +15932=>25135, +15933=>25136, +15934=>25137, +15935=>25138, +15936=>25139, +15937=>25140, +15938=>25141, +15939=>25142, +15940=>25143, +15941=>25144, +15942=>25145, +15943=>25146, +15944=>25147, +15945=>25148, +15946=>25149, +15947=>25150, +15948=>25151, +15949=>25152, +15950=>25153, +15951=>25154, +15952=>25155, +15953=>25156, +15954=>25157, +15955=>25158, +15956=>25159, +15957=>25160, +15958=>25161, +15959=>25162, +15960=>25163, +15961=>25164, +15962=>25165, +15963=>25166, +15964=>25167, +15965=>25168, +15966=>25169, +15967=>25170, +15968=>25171, +15969=>25172, +15970=>25173, +15971=>25174, +15972=>25175, +15973=>25176, +15974=>25177, +15975=>25178, +15976=>25179, +15977=>25180, +15978=>25181, +15979=>25182, +15980=>25183, +15981=>25184, +15982=>25185, +15983=>25186, +15984=>25187, +15985=>25188, +15986=>25189, +15987=>25190, +15988=>25191, +15989=>25192, +15990=>25193, +15991=>25194, +15992=>25195, +15993=>25196, +15994=>25197, +15995=>25198, +15996=>25199, +15997=>25200, +15998=>25201, +15999=>25202, +16000=>25203, +16001=>25204, +16002=>25205, +16003=>25206, +16004=>25207, +16005=>25208, +16006=>25209, +16007=>25210, +16008=>25211, +16009=>25212, +16010=>25213, +16011=>25214, +16012=>25215, +16013=>25216, +16014=>25217, +16015=>25218, +16016=>25219, +16017=>25220, +16018=>25221, +16019=>25222, +16020=>25223, +16021=>25224, +16022=>25225, +16023=>25226, +16024=>25227, +16025=>25228, +16026=>25229, +16027=>25230, +16028=>25231, +16029=>25232, +16030=>25233, +16031=>25234, +16032=>25235, +16033=>25236, +16034=>25237, +16035=>25238, +16036=>25239, +16037=>25240, +16038=>25241, +16039=>25242, +16040=>25243, +16041=>25244, +16042=>25245, +16043=>25246, +16044=>25247, +16045=>25248, +16046=>25249, +16047=>25250, +16048=>25251, +16049=>25252, +16050=>25253, +16051=>25254, +16052=>25255, +16053=>25256, +16054=>25257, +16055=>25258, +16056=>25259, +16057=>25260, +16058=>25261, +16059=>25262, +16060=>25263, +16061=>25264, +16062=>25265, +16063=>25266, +16064=>25267, +16065=>25268, +16066=>25269, +16067=>25270, +16068=>25271, +16069=>25272, +16070=>25273, +16071=>25274, +16072=>25275, +16073=>25276, +16074=>25277, +16075=>25278, +16076=>25279, +16077=>25280, +16078=>25281, +16079=>25282, +16080=>25283, +16081=>25284, +16082=>25285, +16083=>25286, +16084=>25287, +16085=>25288, +16086=>25289, +16087=>25290, +16088=>25291, +16089=>25292, +16090=>25293, +16091=>25294, +16092=>25295, +16093=>25296, +16094=>25297, +16095=>25298, +16096=>25299, +16097=>25300, +16098=>25301, +16099=>25302, +16100=>25303, +16101=>25304, +16102=>25305, +16103=>25306, +16104=>25307, +16105=>25308, +16106=>25309, +16107=>25310, +16108=>25311, +16109=>25312, +16110=>25313, +16111=>25314, +16112=>25315, +16113=>25316, +16114=>25317, +16115=>25318, +16116=>25319, +16117=>25320, +16118=>25321, +16119=>25322, +16120=>25323, +16121=>25324, +16122=>25325, +16123=>25326, +16124=>25327, +16125=>25328, +16126=>25329, +16127=>25330, +16128=>25331, +16129=>25332, +16130=>25333, +16131=>25334, +16132=>25335, +16133=>25336, +16134=>25337, +16135=>25338, +16136=>25339, +16137=>25340, +16138=>25341, +16139=>25342, +16140=>25343, +16141=>25344, +16142=>25345, +16143=>25346, +16144=>25347, +16145=>25348, +16146=>25349, +16147=>25350, +16148=>25351, +16149=>25352, +16150=>25353, +16151=>25354, +16152=>25355, +16153=>25356, +16154=>25357, +16155=>25358, +16156=>25359, +16157=>25360, +16158=>25361, +16159=>25362, +16160=>25363, +16161=>25364, +16162=>25365, +16163=>25366, +16164=>25367, +16165=>25368, +16166=>25369, +16167=>25370, +16168=>25371, +16169=>25372, +16170=>25373, +16171=>25374, +16172=>25375, +16173=>25376, +16174=>25377, +16175=>25378, +16176=>25379, +16177=>25380, +16178=>25381, +16179=>25382, +16180=>25383, +16181=>25384, +16182=>25385, +16183=>25386, +16184=>25387, +16185=>25388, +16186=>25389, +16187=>25390, +16188=>25391, +16189=>25392, +16190=>25393, +16191=>25394, +16192=>25395, +16193=>25396, +16194=>25397, +16195=>25398, +16196=>25399, +16197=>25400, +16198=>25401, +16199=>25402, +16200=>25403, +16201=>25404, +16202=>25405, +16203=>25406, +16204=>25407, +16205=>25408, +16206=>25409, +16207=>25410, +16208=>25411, +16209=>25412, +16210=>25413, +16211=>25414, +16212=>25415, +16213=>25416, +16214=>25417, +16215=>25418, +16216=>25419, +16217=>25420, +16218=>25421, +16219=>25422, +16220=>25423, +16221=>25424, +16222=>25425, +16223=>25426, +16224=>25427, +16225=>25428, +16226=>25429, +16227=>25430, +16228=>25431, +16229=>25432, +16230=>25433, +16231=>25434, +16232=>25435, +16233=>25436, +16234=>25437, +16235=>25438, +16236=>25439, +16237=>25440, +16238=>25441, +16239=>25442, +16240=>25443, +16241=>25444, +16242=>25445, +16243=>25446, +16244=>25447, +16245=>25448, +16246=>25449, +16247=>25450, +16248=>25451, +16249=>25452, +16250=>25453, +16251=>25454, +16252=>25455, +16253=>25456, +16254=>25457, +16255=>25458, +16256=>25459, +16257=>25460, +16258=>25461, +16259=>25462, +16260=>25463, +16261=>25464, +16262=>25465, +16263=>25466, +16264=>25467, +16265=>25468, +16266=>25469, +16267=>25470, +16268=>25471, +16269=>25472, +16270=>25473, +16271=>25474, +16272=>25475, +16273=>25476, +16274=>25477, +16275=>25478, +16276=>25479, +16277=>25480, +16278=>25481, +16279=>25482, +16280=>25483, +16281=>25484, +16282=>25485, +16283=>25486, +16284=>25487, +16285=>25488, +16286=>25489, +16287=>25490, +16288=>25491, +16289=>25492, +16290=>25493, +16291=>25494, +16292=>25495, +16293=>25496, +16294=>25497, +16295=>25498, +16296=>25499, +16297=>25500, +16298=>25501, +16299=>25502, +16300=>25503, +16301=>25504, +16302=>25505, +16303=>25506, +16304=>25507, +16305=>25508, +16306=>25509, +16307=>25510, +16308=>25511, +16309=>25512, +16310=>25513, +16311=>25514, +16312=>25515, +16313=>25516, +16314=>25517, +16315=>25518, +16316=>25519, +16317=>25520, +16318=>25521, +16319=>25522, +16320=>25523, +16321=>25524, +16322=>25525, +16323=>25526, +16324=>25527, +16325=>25528, +16326=>25529, +16327=>25530, +16328=>25531, +16329=>25532, +16330=>25533, +16331=>25534, +16332=>25535, +16333=>25536, +16334=>25537, +16335=>25538, +16336=>25539, +16337=>25540, +16338=>25541, +16339=>25542, +16340=>25543, +16341=>25544, +16342=>25545, +16343=>25546, +16344=>25547, +16345=>25548, +16346=>25549, +16347=>25550, +16348=>25551, +16349=>25552, +16350=>25553, +16351=>25554, +16352=>25555, +16353=>25556, +16354=>25557, +16355=>25558, +16356=>25559, +16357=>25560, +16358=>25561, +16359=>25562, +16360=>25563, +16361=>25564, +16362=>25565, +16363=>25566, +16364=>25567, +16365=>25568, +16366=>25569, +16367=>25570, +16368=>25571, +16369=>25572, +16370=>25573, +16371=>25574, +16372=>25575, +16373=>25576, +16374=>25577, +16375=>25578, +16376=>25579, +16377=>25580, +16378=>25581, +16379=>25582, +16380=>25583, +16381=>25584, +16382=>25585, +16383=>25586, +16384=>25587, +16385=>25588, +16386=>25589, +16387=>25590, +16388=>25591, +16389=>25592, +16390=>25593, +16391=>25594, +16392=>25595, +16393=>25596, +16394=>25597, +16395=>25598, +16396=>25599, +16397=>25600, +16398=>25601, +16399=>25602, +16400=>25603, +16401=>25604, +16402=>25605, +16403=>25606, +16404=>25607, +16405=>25608, +16406=>25609, +16407=>25610, +16408=>25611, +16409=>25612, +16410=>25613, +16411=>25614, +16412=>25615, +16413=>25616, +16414=>25617, +16415=>25618, +16416=>25619, +16417=>25620, +16418=>25621, +16419=>25622, +16420=>25623, +16421=>25624, +16422=>25625, +16423=>25626, +16424=>25627, +16425=>25628, +16426=>25629, +16427=>25630, +16428=>25631, +16429=>25632, +16430=>25633, +16431=>25634, +16432=>25635, +16433=>25636, +16434=>25637, +16435=>25638, +16436=>25639, +16437=>25640, +16438=>25641, +16439=>25642, +16440=>25643, +16441=>25644, +16442=>25645, +16443=>25646, +16444=>25647, +16445=>25648, +16446=>25649, +16447=>25650, +16448=>25651, +16449=>25652, +16450=>25653, +16451=>25654, +16452=>25655, +16453=>25656, +16454=>25657, +16455=>25658, +16456=>25659, +16457=>25660, +16458=>25661, +16459=>25662, +16460=>25663, +16461=>25664, +16462=>25665, +16463=>25666, +16464=>25667, +16465=>25668, +16466=>25669, +16467=>25670, +16468=>25671, +16469=>25672, +16471=>25673, +16472=>25674, +16473=>25675, +16474=>25676, +16475=>25677, +16476=>25678, +16477=>25679, +16478=>25680, +16479=>25681, +16480=>25682, +16481=>25683, +16482=>25684, +16483=>25685, +16484=>25686, +16485=>25687, +16486=>25688, +16487=>25689, +16488=>25690, +16489=>25691, +16490=>25692, +16491=>25693, +16492=>25694, +16493=>25695, +16494=>25696, +16495=>25697, +16496=>25698, +16497=>25699, +16498=>25700, +16499=>25701, +16500=>25702, +16501=>25703, +16502=>25704, +16503=>25705, +16504=>25706, +16505=>25707, +16506=>25708, +16507=>25709, +16508=>25710, +16509=>25711, +16510=>25712, +16511=>25713, +16512=>25714, +16513=>25715, +16514=>25716, +16515=>25717, +16516=>25718, +16517=>25719, +16518=>25720, +16519=>25721, +16520=>25722, +16521=>25723, +16522=>25724, +16523=>25725, +16524=>25726, +16525=>25727, +16526=>25728, +16527=>25729, +16528=>25730, +16529=>25731, +16530=>25732, +16531=>25733, +16532=>25734, +16533=>25735, +16534=>25736, +16535=>25737, +16536=>25738, +16537=>25739, +16538=>25740, +16539=>25741, +16540=>25742, +16541=>25743, +16542=>25744, +16543=>25745, +16544=>25746, +16545=>25747, +16546=>25748, +16547=>25749, +16548=>25750, +16549=>25751, +16550=>25752, +16551=>25753, +16552=>25754, +16553=>25755, +16554=>25756, +16555=>25757, +16556=>25758, +16557=>25759, +16558=>25760, +16559=>25761, +16560=>25762, +16561=>25763, +16562=>25764, +16563=>25765, +16564=>25766, +16565=>25767, +16566=>25768, +16567=>25769, +16568=>25770, +16569=>25771, +16570=>25772, +16571=>25773, +16572=>25774, +16573=>25775, +16574=>25776, +16575=>25777, +16576=>25778, +16577=>25779, +16578=>25780, +16579=>25781, +16580=>25782, +16581=>25783, +16582=>25784, +16583=>25785, +16584=>25786, +16585=>25787, +16586=>25788, +16587=>25789, +16588=>25790, +16589=>25791, +16590=>25792, +16591=>25793, +16592=>25794, +16593=>25795, +16594=>25796, +16595=>25797, +16596=>25798, +16597=>25799, +16598=>25800, +16599=>25801, +16600=>25802, +16601=>25803, +16602=>25804, +16603=>25805, +16604=>25806, +16605=>25807, +16606=>25808, +16607=>25809, +16608=>25810, +16609=>25811, +16610=>25812, +16611=>25813, +16612=>25814, +16613=>25815, +16614=>25816, +16615=>25817, +16616=>25818, +16617=>25819, +16618=>25820, +16619=>25821, +16620=>25822, +16621=>25823, +16622=>25824, +16623=>25825, +16624=>25826, +16625=>25827, +16626=>25828, +16627=>25829, +16628=>25830, +16629=>25831, +16630=>25832, +16631=>25833, +16632=>25834, +16633=>25835, +16634=>25836, +16635=>25837, +16636=>25838, +16637=>25839, +16638=>25840, +16639=>25841, +16640=>25842, +16641=>25843, +16642=>25844, +16643=>25845, +16644=>25846, +16645=>25847, +16646=>25848, +16647=>25849, +16648=>25850, +16649=>25851, +16650=>25852, +16651=>25853, +16652=>25854, +16653=>25855, +16654=>25856, +16655=>25857, +16656=>25858, +16657=>25859, +16658=>25860, +16659=>25861, +16660=>25862, +16661=>25863, +16662=>25864, +16663=>25865, +16664=>25866, +16665=>25867, +16666=>25868, +16667=>25869, +16668=>25870, +16669=>25871, +16670=>25872, +16671=>25873, +16672=>25874, +16673=>25875, +16674=>25876, +16675=>25877, +16676=>25878, +16677=>25879, +16678=>25880, +16679=>25881, +16680=>25882, +16681=>25883, +16682=>25884, +16683=>25885, +16684=>25886, +16685=>25887, +16686=>25888, +16687=>25889, +16688=>25890, +16689=>25891, +16690=>25892, +16691=>25893, +16692=>25894, +16693=>25895, +16694=>25896, +16695=>25897, +16696=>25898, +16697=>25899, +16698=>25900, +16699=>25901, +16700=>25902, +16701=>25903, +16702=>25904, +16703=>25905, +16704=>25906, +16705=>25907, +16706=>25908, +16707=>25909, +16708=>25910, +16709=>25911, +16710=>25912, +16711=>25913, +16712=>25914, +16713=>25915, +16714=>25916, +16715=>25917, +16716=>25918, +16717=>25919, +16718=>25920, +16719=>25921, +16720=>25922, +16721=>25923, +16722=>25924, +16723=>25925, +16724=>25926, +16725=>25927, +16726=>25928, +16727=>25929, +16728=>25930, +16729=>25931, +16730=>25932, +16731=>25933, +16732=>25934, +16733=>25935, +16734=>25936, +16736=>25937, +16737=>25938, +16738=>25939, +16739=>25940, +16740=>25941, +16741=>25942, +16742=>25943, +16743=>25944, +16744=>25945, +16745=>25946, +16746=>25947, +16747=>25948, +16748=>25949, +16749=>25950, +16750=>25951, +16751=>25952, +16752=>25953, +16753=>25954, +16754=>25955, +16755=>25956, +16756=>25957, +16757=>25958, +16758=>25959, +16759=>25960, +16760=>25961, +16761=>25962, +16762=>25963, +16763=>25964, +16764=>25965, +16765=>25966, +16766=>25967, +16767=>25968, +16768=>25969, +16769=>25970, +16770=>25971, +16771=>25972, +16772=>25973, +16773=>25974, +16774=>25975, +16775=>25976, +16776=>25977, +16777=>25978, +16778=>25979, +16779=>25980, +16780=>25981, +16781=>25982, +16782=>25983, +16783=>25984, +16784=>25985, +16785=>25986, +16786=>25987, +16787=>25988, +16788=>25989, +16789=>25990, +16790=>25991, +16791=>25992, +16792=>25993, +16793=>25994, +16794=>25995, +16795=>25996, +16796=>25997, +16797=>25998, +16798=>25999, +16799=>26000, +16800=>26001, +16801=>26002, +16802=>26003, +16803=>26004, +16804=>26005, +16805=>26006, +16806=>26007, +16807=>26008, +16808=>26009, +16809=>26010, +16810=>26011, +16811=>26012, +16812=>26013, +16813=>26014, +16814=>26015, +16815=>26016, +16816=>26017, +16817=>26018, +16818=>26019, +16819=>26020, +16820=>26021, +16821=>26022, +16822=>26023, +16823=>26024, +16824=>26025, +16825=>26026, +16826=>26027, +16827=>26028, +16828=>26029, +16829=>26030, +16830=>26031, +16831=>26032, +16832=>26033, +16833=>26034, +16834=>26035, +16835=>26036, +16836=>26037, +16837=>26038, +16838=>26039, +16839=>26040, +16840=>26041, +16841=>26042, +16842=>26043, +16843=>26044, +16844=>26045, +16845=>26046, +16846=>26047, +16847=>26048, +16848=>26049, +16849=>26050, +16850=>26051, +16851=>26052, +16852=>26053, +16853=>26054, +16854=>26055, +16855=>26056, +16856=>26057, +16857=>26058, +16858=>26059, +16859=>26060, +16860=>26061, +16861=>26062, +16862=>26063, +16863=>26064, +16864=>26065, +16865=>26066, +16866=>26067, +16867=>26068, +16868=>26069, +16869=>26070, +16870=>26071, +16871=>26072, +16872=>26073, +16873=>26074, +16874=>26075, +16875=>26076, +16876=>26077, +16877=>26078, +16878=>26079, +16879=>26080, +16880=>26081, +16881=>26082, +16882=>26083, +16883=>26084, +16884=>26085, +16885=>26086, +16886=>26087, +16887=>26088, +16888=>26089, +16889=>26090, +16890=>26091, +16891=>26092, +16892=>26093, +16893=>26094, +16894=>26095, +16895=>26096, +16896=>26097, +16897=>26098, +16898=>26099, +16899=>26100, +16900=>26101, +16901=>26102, +16902=>26103, +16903=>26104, +16904=>26105, +16905=>26106, +16906=>26107, +16907=>26108, +16908=>26109, +16909=>26110, +16910=>26111, +16911=>26112, +16912=>26113, +16913=>26114, +16914=>26115, +16915=>26116, +16916=>26117, +16917=>26118, +16918=>26119, +16919=>26120, +16920=>26121, +16921=>26122, +16922=>26123, +16923=>26124, +16924=>26125, +16925=>26126, +16926=>26127, +16927=>26128, +16928=>26129, +16929=>26130, +16930=>26131, +16931=>26132, +16932=>26133, +16933=>26134, +16934=>26135, +16935=>26136, +16936=>26137, +16937=>26138, +16938=>26139, +16939=>26140, +16940=>26141, +16941=>26142, +16942=>26143, +16943=>26144, +16944=>26145, +16945=>26146, +16946=>26147, +16947=>26148, +16948=>26149, +16949=>26150, +16950=>26151, +16951=>26152, +16952=>26153, +16953=>26154, +16954=>26155, +16955=>26156, +16956=>26157, +16957=>26158, +16958=>26159, +16959=>26160, +16960=>26161, +16961=>26162, +16962=>26163, +16963=>26164, +16964=>26165, +16965=>26166, +16966=>26167, +16967=>26168, +16968=>26169, +16969=>26170, +16970=>26171, +16971=>26172, +16972=>26173, +16973=>26174, +16974=>26175, +16975=>26176, +16976=>26177, +16977=>26178, +16978=>26179, +16979=>26180, +16980=>26181, +16981=>26182, +16982=>26183, +16983=>26184, +16984=>26185, +16985=>26186, +16986=>26187, +16987=>26188, +16988=>26189, +16989=>26190, +16990=>26191, +16991=>26192, +16992=>26193, +16993=>26194, +16994=>26195, +16995=>26196, +16996=>26197, +16997=>26198, +16998=>26199, +16999=>26200, +17000=>26201, +17001=>26202, +17002=>26203, +17003=>26204, +17004=>26205, +17005=>26206, +17006=>26207, +17007=>26208, +17008=>26209, +17009=>26210, +17010=>26211, +17011=>26212, +17012=>26213, +17013=>26214, +17014=>26215, +17015=>26216, +17016=>26217, +17017=>26218, +17018=>26219, +17019=>26220, +17020=>26221, +17021=>26222, +17022=>26223, +17023=>26224, +17024=>26225, +17025=>26226, +17026=>26227, +17027=>26228, +17028=>26229, +17029=>26230, +17030=>26231, +17031=>26232, +17032=>26233, +17033=>26234, +17034=>26235, +17035=>26236, +17036=>26237, +17037=>26238, +17038=>26239, +17039=>26240, +17040=>26241, +17041=>26242, +17042=>26243, +17043=>26244, +17044=>26245, +17045=>26246, +17046=>26247, +17047=>26248, +17048=>26249, +17049=>26250, +17050=>26251, +17051=>26252, +17052=>26253, +17053=>26254, +17054=>26255, +17055=>26256, +17056=>26257, +17057=>26258, +17058=>26259, +17059=>26260, +17060=>26261, +17061=>26262, +17062=>26263, +17063=>26264, +17064=>26265, +17065=>26266, +17066=>26267, +17067=>26268, +17068=>26269, +17069=>26270, +17070=>26271, +17071=>26272, +17072=>26273, +17073=>26274, +17074=>26275, +17075=>26276, +17076=>26277, +17077=>26278, +17078=>26279, +17079=>26280, +17080=>26281, +17081=>26282, +17082=>26283, +17083=>26284, +17084=>26285, +17085=>26286, +17086=>26287, +17087=>26288, +17088=>26289, +17089=>26290, +17090=>26291, +17091=>26292, +17092=>26293, +17093=>26294, +17094=>26295, +17095=>26296, +17096=>26297, +17097=>26298, +17098=>26299, +17099=>26300, +17100=>26301, +17101=>26302, +17102=>26303, +17103=>26304, +17104=>26305, +17105=>26306, +17106=>26307, +17107=>26308, +17108=>26309, +17109=>26310, +17110=>26311, +17111=>26312, +17112=>26313, +17113=>26314, +17114=>26315, +17115=>26316, +17116=>26317, +17117=>26318, +17118=>26319, +17119=>26320, +17120=>26321, +17121=>26322, +17122=>26323, +17123=>26324, +17124=>26325, +17125=>26326, +17126=>26327, +17127=>26328, +17128=>26329, +17129=>26330, +17130=>26331, +17131=>26332, +17132=>26333, +17133=>26334, +17134=>26335, +17135=>26336, +17136=>26337, +17137=>26338, +17138=>26339, +17139=>26340, +17140=>26341, +17141=>26342, +17142=>26343, +17143=>26344, +17144=>26345, +17145=>26346, +17146=>26347, +17147=>26348, +17148=>26349, +17149=>26350, +17150=>26351, +17151=>26352, +17152=>26353, +17153=>26354, +17154=>26355, +17155=>26356, +17156=>26357, +17157=>26358, +17158=>26359, +17159=>26360, +17160=>26361, +17161=>26362, +17162=>26363, +17163=>26364, +17164=>26365, +17165=>26366, +17166=>26367, +17167=>26368, +17168=>26369, +17169=>26370, +17170=>26371, +17171=>26372, +17172=>26373, +17173=>26374, +17174=>26375, +17175=>26376, +17176=>26377, +17177=>26378, +17178=>26379, +17179=>26380, +17180=>26381, +17181=>26382, +17182=>26383, +17183=>26384, +17184=>26385, +17185=>26386, +17186=>26387, +17187=>26388, +17188=>26389, +17189=>26390, +17190=>26391, +17191=>26392, +17192=>26393, +17193=>26394, +17194=>26395, +17195=>26396, +17196=>26397, +17197=>26398, +17198=>26399, +17199=>26400, +17200=>26401, +17201=>26402, +17202=>26403, +17203=>26404, +17204=>26405, +17205=>26406, +17206=>26407, +17208=>26408, +17209=>26409, +17210=>26410, +17211=>26411, +17212=>26412, +17213=>26413, +17214=>26414, +17215=>26415, +17216=>26416, +17217=>26417, +17218=>26418, +17219=>26419, +17220=>26420, +17221=>26421, +17222=>26422, +17223=>26423, +17224=>26424, +17225=>26425, +17226=>26426, +17227=>26427, +17228=>26428, +17229=>26429, +17230=>26430, +17231=>26431, +17232=>26432, +17233=>26433, +17234=>26434, +17235=>26435, +17236=>26436, +17237=>26437, +17238=>26438, +17239=>26439, +17240=>26440, +17241=>26441, +17242=>26442, +17243=>26443, +17244=>26444, +17245=>26445, +17246=>26446, +17247=>26447, +17248=>26448, +17249=>26449, +17250=>26450, +17251=>26451, +17252=>26452, +17253=>26453, +17254=>26454, +17255=>26455, +17256=>26456, +17257=>26457, +17258=>26458, +17259=>26459, +17260=>26460, +17261=>26461, +17262=>26462, +17263=>26463, +17264=>26464, +17265=>26465, +17266=>26466, +17267=>26467, +17268=>26468, +17269=>26469, +17270=>26470, +17271=>26471, +17272=>26472, +17273=>26473, +17274=>26474, +17275=>26475, +17276=>26476, +17277=>26477, +17278=>26478, +17279=>26479, +17280=>26480, +17281=>26481, +17282=>26482, +17283=>26483, +17284=>26484, +17285=>26485, +17286=>26486, +17287=>26487, +17288=>26488, +17289=>26489, +17290=>26490, +17291=>26491, +17292=>26492, +17293=>26493, +17294=>26494, +17295=>26495, +17296=>26496, +17297=>26497, +17298=>26498, +17299=>26499, +17300=>26500, +17301=>26501, +17302=>26502, +17303=>26503, +17304=>26504, +17305=>26505, +17306=>26506, +17307=>26507, +17308=>26508, +17309=>26509, +17310=>26510, +17311=>26511, +17312=>26512, +17313=>26513, +17314=>26514, +17315=>26515, +17316=>26516, +17317=>26517, +17318=>26518, +17319=>26519, +17320=>26520, +17321=>26521, +17322=>26522, +17323=>26523, +17325=>26524, +17326=>26525, +17327=>26526, +17328=>26527, +17330=>26528, +17331=>26529, +17332=>26530, +17333=>26531, +17334=>26532, +17335=>26533, +17336=>26534, +17337=>26535, +17338=>26536, +17339=>26537, +17340=>26538, +17341=>26539, +17342=>26540, +17343=>26541, +17344=>26542, +17345=>26543, +17346=>26544, +17347=>26545, +17348=>26546, +17349=>26547, +17350=>26548, +17351=>26549, +17352=>26550, +17353=>26551, +17354=>26552, +17355=>26553, +17356=>26554, +17357=>26555, +17358=>26556, +17359=>26557, +17360=>26558, +17361=>26559, +17362=>26560, +17363=>26561, +17364=>26562, +17365=>26563, +17366=>26564, +17367=>26565, +17368=>26566, +17369=>26567, +17370=>26568, +17371=>26569, +17372=>26570, +17374=>26571, +17375=>26572, +17376=>26573, +17377=>26574, +17378=>26575, +17379=>26576, +17380=>26577, +17381=>26578, +17382=>26579, +17383=>26580, +17384=>26581, +17385=>26582, +17386=>26583, +17387=>26584, +17388=>26585, +17389=>26586, +17390=>26587, +17391=>26588, +17392=>26589, +17393=>26590, +17394=>26591, +17395=>26592, +17396=>26593, +17397=>26594, +17398=>26595, +17399=>26596, +17400=>26597, +17401=>26598, +17402=>26599, +17403=>26600, +17404=>26601, +17405=>26602, +17406=>26603, +17407=>26604, +17408=>26605, +17409=>26606, +17410=>26607, +17411=>26608, +17412=>26609, +17413=>26610, +17414=>26611, +17415=>26612, +17416=>26613, +17417=>26614, +17418=>26615, +17419=>26616, +17420=>26617, +17421=>26618, +17422=>26619, +17423=>26620, +17424=>26621, +17425=>26622, +17426=>26623, +17427=>26624, +17428=>26625, +17429=>26626, +17430=>26627, +17431=>26628, +17432=>26629, +17433=>26630, +17434=>26631, +17435=>26632, +17436=>26633, +17437=>26634, +17438=>26635, +17439=>26636, +17440=>26637, +17441=>26638, +17442=>26639, +17443=>26640, +17444=>26641, +17445=>26642, +17446=>26643, +17447=>26644, +17448=>26645, +17449=>26646, +17450=>26647, +17451=>26648, +17452=>26649, +17453=>26650, +17454=>26651, +17455=>26652, +17456=>26653, +17457=>26654, +17458=>26655, +17459=>26656, +17460=>26657, +17461=>26658, +17462=>26659, +17463=>26660, +17464=>26661, +17465=>26662, +17466=>26663, +17467=>26664, +17468=>26665, +17469=>26666, +17470=>26667, +17471=>26668, +17472=>26669, +17473=>26670, +17474=>26671, +17475=>26672, +17476=>26673, +17477=>26674, +17478=>26675, +17479=>26676, +17480=>26677, +17481=>26678, +17482=>26679, +17483=>26680, +17484=>26681, +17485=>26682, +17486=>26683, +17487=>26684, +17488=>26685, +17489=>26686, +17490=>26687, +17491=>26688, +17492=>26689, +17493=>26690, +17494=>26691, +17495=>26692, +17496=>26693, +17497=>26694, +17498=>26695, +17499=>26696, +17500=>26697, +17501=>26698, +17502=>26699, +17503=>26700, +17504=>26701, +17505=>26702, +17506=>26703, +17507=>26704, +17508=>26705, +17509=>26706, +17510=>26707, +17511=>26708, +17512=>26709, +17513=>26710, +17514=>26711, +17515=>26712, +17516=>26713, +17517=>26714, +17518=>26715, +17519=>26716, +17520=>26717, +17521=>26718, +17522=>26719, +17523=>26720, +17524=>26721, +17525=>26722, +17526=>26723, +17527=>26724, +17528=>26725, +17529=>26726, +17530=>26727, +17531=>26728, +17532=>26729, +17533=>26730, +17534=>26731, +17535=>26732, +17536=>26733, +17537=>26734, +17538=>26735, +17539=>26736, +17540=>26737, +17541=>26738, +17542=>26739, +17543=>26740, +17544=>26741, +17545=>26742, +17546=>26743, +17547=>26744, +17548=>26745, +17549=>26746, +17550=>26747, +17551=>26748, +17552=>26749, +17553=>26750, +17554=>26751, +17555=>26752, +17556=>26753, +17557=>26754, +17558=>26755, +17559=>26756, +17560=>26757, +17561=>26758, +17562=>26759, +17563=>26760, +17564=>26761, +17565=>26762, +17566=>26763, +17567=>26764, +17568=>26765, +17569=>26766, +17570=>26767, +17571=>26768, +17572=>26769, +17573=>26770, +17574=>26771, +17575=>26772, +17576=>26773, +17577=>26774, +17578=>26775, +17579=>26776, +17580=>26777, +17581=>26778, +17582=>26779, +17583=>26780, +17584=>26781, +17585=>26782, +17586=>26783, +17587=>26784, +17588=>26785, +17589=>26786, +17590=>26787, +17591=>26788, +17592=>26789, +17593=>26790, +17594=>26791, +17595=>26792, +17596=>26793, +17597=>26794, +17598=>26795, +17599=>26796, +17600=>26797, +17601=>26798, +17602=>26799, +17603=>26800, +17604=>26801, +17605=>26802, +17606=>26803, +17607=>26804, +17608=>26805, +17609=>26806, +17610=>26807, +17611=>26808, +17612=>26809, +17613=>26810, +17614=>26811, +17615=>26812, +17616=>26813, +17617=>26814, +17618=>26815, +17619=>26816, +17620=>26817, +17621=>26818, +17623=>26819, +17624=>26820, +17625=>26821, +17626=>26822, +17627=>26823, +17628=>26824, +17629=>26825, +17630=>26826, +17631=>26827, +17632=>26828, +17633=>26829, +17634=>26830, +17635=>26831, +17636=>26832, +17637=>26833, +17638=>26834, +17639=>26835, +17640=>26836, +17641=>26837, +17642=>26838, +17643=>26839, +17644=>26840, +17645=>26841, +17646=>26842, +17647=>26843, +17648=>26844, +17649=>26845, +17650=>26846, +17651=>26847, +17652=>26848, +17653=>26849, +17654=>26850, +17655=>26851, +17656=>26852, +17657=>26853, +17658=>26854, +17659=>26855, +17660=>26856, +17661=>26857, +17662=>26858, +17663=>26859, +17664=>26860, +17665=>26861, +17666=>26862, +17667=>26863, +17668=>26864, +17669=>26865, +17670=>26866, +17671=>26867, +17672=>26868, +17673=>26869, +17674=>26870, +17675=>26871, +17676=>26872, +17677=>26873, +17678=>26874, +17679=>26875, +17680=>26876, +17681=>26877, +17682=>26878, +17683=>26879, +17684=>26880, +17685=>26881, +17686=>26882, +17687=>26883, +17688=>26884, +17689=>26885, +17690=>26886, +17691=>26887, +17692=>26888, +17693=>26889, +17694=>26890, +17695=>26891, +17696=>26892, +17697=>26893, +17698=>26894, +17699=>26895, +17700=>26896, +17701=>26897, +17702=>26898, +17703=>26899, +17704=>26900, +17705=>26901, +17706=>26902, +17707=>26903, +17708=>26904, +17709=>26905, +17710=>26906, +17711=>26907, +17712=>26908, +17713=>26909, +17714=>26910, +17715=>26911, +17716=>26912, +17717=>26913, +17718=>26914, +17719=>26915, +17720=>26916, +17721=>26917, +17722=>26918, +17723=>26919, +17724=>26920, +17725=>26921, +17726=>26922, +17727=>26923, +17728=>26924, +17729=>26925, +17730=>26926, +17731=>26927, +17732=>26928, +17733=>26929, +17734=>26930, +17735=>26931, +17736=>26932, +17737=>26933, +17738=>26934, +17739=>26935, +17740=>26936, +17741=>26937, +17742=>26938, +17743=>26939, +17744=>26940, +17745=>26941, +17746=>26942, +17747=>26943, +17748=>26944, +17749=>26945, +17750=>26946, +17751=>26947, +17752=>26948, +17753=>26949, +17754=>26950, +17755=>26951, +17756=>26952, +17757=>26953, +17758=>26954, +17759=>26955, +17760=>26956, +17761=>26957, +17762=>26958, +17763=>26959, +17764=>26960, +17765=>26961, +17766=>26962, +17767=>26963, +17768=>26964, +17769=>26965, +17770=>26966, +17771=>26967, +17772=>26968, +17773=>26969, +17774=>26970, +17775=>26971, +17776=>26972, +17777=>26973, +17778=>26974, +17779=>26975, +17780=>26976, +17781=>26977, +17782=>26978, +17783=>26979, +17784=>26980, +17785=>26981, +17786=>26982, +17787=>26983, +17788=>26984, +17789=>26985, +17790=>26986, +17791=>26987, +17792=>26988, +17793=>26989, +17794=>26990, +17795=>26991, +17796=>26992, +17797=>26993, +17798=>26994, +17799=>26995, +17800=>26996, +17801=>26997, +17802=>26998, +17803=>26999, +17804=>27000, +17805=>27001, +17806=>27002, +17807=>27003, +17808=>27004, +17809=>27005, +17810=>27006, +17811=>27007, +17812=>27008, +17813=>27009, +17814=>27010, +17815=>27011, +17816=>27012, +17817=>27013, +17818=>27014, +17819=>27015, +17820=>27016, +17821=>27017, +17822=>27018, +17823=>27019, +17824=>27020, +17825=>27021, +17826=>27022, +17827=>27023, +17828=>27024, +17829=>27025, +17830=>27026, +17831=>27027, +17832=>27028, +17833=>27029, +17834=>27030, +17835=>27031, +17836=>27032, +17837=>27033, +17838=>27034, +17839=>27035, +17840=>27036, +17841=>27037, +17842=>27038, +17843=>27039, +17844=>27040, +17845=>27041, +17846=>27042, +17847=>27043, +17848=>27044, +17849=>27045, +17850=>27046, +17851=>27047, +17852=>27048, +17853=>27049, +17854=>27050, +17855=>27051, +17856=>27052, +17857=>27053, +17858=>27054, +17859=>27055, +17860=>27056, +17861=>27057, +17862=>27058, +17863=>27059, +17864=>27060, +17865=>27061, +17866=>27062, +17867=>27063, +17868=>27064, +17869=>27065, +17870=>27066, +17871=>27067, +17872=>27068, +17873=>27069, +17874=>27070, +17875=>27071, +17876=>27072, +17877=>27073, +17878=>27074, +17879=>27075, +17880=>27076, +17881=>27077, +17882=>27078, +17883=>27079, +17884=>27080, +17885=>27081, +17886=>27082, +17887=>27083, +17888=>27084, +17889=>27085, +17890=>27086, +17891=>27087, +17892=>27088, +17893=>27089, +17894=>27090, +17895=>27091, +17896=>27092, +17897=>27093, +17898=>27094, +17899=>27095, +17900=>27096, +17901=>27097, +17902=>27098, +17903=>27099, +17904=>27100, +17905=>27101, +17906=>27102, +17907=>27103, +17908=>27104, +17909=>27105, +17910=>27106, +17911=>27107, +17912=>27108, +17913=>27109, +17914=>27110, +17915=>27111, +17916=>27112, +17917=>27113, +17918=>27114, +17919=>27115, +17920=>27116, +17921=>27117, +17922=>27118, +17923=>27119, +17924=>27120, +17925=>27121, +17926=>27122, +17927=>27123, +17928=>27124, +17929=>27125, +17930=>27126, +17931=>27127, +17932=>27128, +17933=>27129, +17934=>27130, +17935=>27131, +17936=>27132, +17937=>27133, +17938=>27134, +17939=>27135, +17940=>27136, +17941=>27137, +17942=>27138, +17943=>27139, +17944=>27140, +17945=>27141, +17946=>27142, +17947=>27143, +17948=>27144, +17949=>27145, +17950=>27146, +17951=>27147, +17952=>27148, +17953=>27149, +17954=>27150, +17955=>27151, +17956=>27152, +17957=>27153, +17958=>27154, +17959=>27155, +17960=>27156, +17961=>27157, +17962=>27158, +17963=>27159, +17964=>27160, +17965=>27161, +17966=>27162, +17967=>27163, +17968=>27164, +17969=>27165, +17970=>27166, +17971=>27167, +17972=>27168, +17973=>27169, +17974=>27170, +17975=>27171, +17976=>27172, +17977=>27173, +17978=>27174, +17979=>27175, +17980=>27176, +17981=>27177, +17982=>27178, +17983=>27179, +17984=>27180, +17985=>27181, +17986=>27182, +17987=>27183, +17988=>27184, +17989=>27185, +17990=>27186, +17991=>27187, +17992=>27188, +17993=>27189, +17994=>27190, +17995=>27191, +17997=>27192, +17998=>27193, +17999=>27194, +18000=>27195, +18001=>27196, +18002=>27197, +18003=>27198, +18004=>27199, +18005=>27200, +18006=>27201, +18007=>27202, +18008=>27203, +18009=>27204, +18010=>27205, +18011=>27206, +18012=>27207, +18013=>27208, +18014=>27209, +18015=>27210, +18016=>27211, +18018=>27212, +18019=>27213, +18020=>27214, +18021=>27215, +18022=>27216, +18023=>27217, +18024=>27218, +18025=>27219, +18026=>27220, +18027=>27221, +18028=>27222, +18029=>27223, +18030=>27224, +18031=>27225, +18032=>27226, +18033=>27227, +18034=>27228, +18035=>27229, +18036=>27230, +18037=>27231, +18038=>27232, +18039=>27233, +18040=>27234, +18041=>27235, +18042=>27236, +18043=>27237, +18044=>27238, +18045=>27239, +18046=>27240, +18047=>27241, +18048=>27242, +18049=>27243, +18050=>27244, +18051=>27245, +18052=>27246, +18053=>27247, +18054=>27248, +18055=>27249, +18056=>27250, +18057=>27251, +18058=>27252, +18059=>27253, +18060=>27254, +18061=>27255, +18062=>27256, +18063=>27257, +18064=>27258, +18065=>27259, +18066=>27260, +18067=>27261, +18068=>27262, +18069=>27263, +18070=>27264, +18071=>27265, +18072=>27266, +18073=>27267, +18074=>27268, +18075=>27269, +18076=>27270, +18077=>27271, +18078=>27272, +18079=>27273, +18080=>27274, +18081=>27275, +18082=>27276, +18083=>27277, +18084=>27278, +18085=>27279, +18086=>27280, +18087=>27281, +18088=>27282, +18089=>27283, +18090=>27284, +18091=>27285, +18092=>27286, +18093=>27287, +18094=>27288, +18095=>27289, +18096=>27290, +18097=>27291, +18098=>27292, +18099=>27293, +18100=>27294, +18101=>27295, +18102=>27296, +18103=>27297, +18104=>27298, +18105=>27299, +18106=>27300, +18107=>27301, +18108=>27302, +18109=>27303, +18110=>27304, +18111=>27305, +18112=>27306, +18113=>27307, +18114=>27308, +18115=>27309, +18116=>27310, +18117=>27311, +18118=>27312, +18119=>27313, +18120=>27314, +18121=>27315, +18122=>27316, +18123=>27317, +18124=>27318, +18125=>27319, +18126=>27320, +18127=>27321, +18128=>27322, +18129=>27323, +18130=>27324, +18131=>27325, +18132=>27326, +18133=>27327, +18134=>27328, +18135=>27329, +18136=>27330, +18137=>27331, +18138=>27332, +18139=>27333, +18140=>27334, +18141=>27335, +18142=>27336, +18143=>27337, +18144=>27338, +18145=>27339, +18146=>27340, +18147=>27341, +18148=>27342, +18149=>27343, +18150=>27344, +18151=>27345, +18152=>27346, +18153=>27347, +18154=>27348, +18155=>27349, +18156=>27350, +18157=>27351, +18158=>27352, +18159=>27353, +18160=>27354, +18161=>27355, +18162=>27356, +18163=>27357, +18164=>27358, +18165=>27359, +18166=>27360, +18167=>27361, +18168=>27362, +18169=>27363, +18170=>27364, +18171=>27365, +18172=>27366, +18173=>27367, +18174=>27368, +18175=>27369, +18176=>27370, +18177=>27371, +18178=>27372, +18179=>27373, +18180=>27374, +18181=>27375, +18182=>27376, +18183=>27377, +18184=>27378, +18185=>27379, +18186=>27380, +18187=>27381, +18188=>27382, +18189=>27383, +18190=>27384, +18191=>27385, +18192=>27386, +18193=>27387, +18194=>27388, +18195=>27389, +18196=>27390, +18197=>27391, +18198=>27392, +18199=>27393, +18200=>27394, +18201=>27395, +18202=>27396, +18203=>27397, +18204=>27398, +18205=>27399, +18206=>27400, +18207=>27401, +18208=>27402, +18209=>27403, +18210=>27404, +18212=>27405, +18213=>27406, +18214=>27407, +18215=>27408, +18216=>27409, +18218=>27410, +18219=>27411, +18220=>27412, +18221=>27413, +18222=>27414, +18223=>27415, +18224=>27416, +18225=>27417, +18226=>27418, +18227=>27419, +18228=>27420, +18229=>27421, +18230=>27422, +18231=>27423, +18232=>27424, +18233=>27425, +18234=>27426, +18235=>27427, +18236=>27428, +18237=>27429, +18238=>27430, +18239=>27431, +18240=>27432, +18241=>27433, +18242=>27434, +18243=>27435, +18244=>27436, +18245=>27437, +18246=>27438, +18247=>27439, +18248=>27440, +18249=>27441, +18250=>27442, +18251=>27443, +18252=>27444, +18253=>27445, +18254=>27446, +18255=>27447, +18256=>27448, +18257=>27449, +18258=>27450, +18259=>27451, +18260=>27452, +18261=>27453, +18262=>27454, +18263=>27455, +18264=>27456, +18265=>27457, +18266=>27458, +18267=>27459, +18268=>27460, +18269=>27461, +18270=>27462, +18271=>27463, +18272=>27464, +18273=>27465, +18274=>27466, +18275=>27467, +18276=>27468, +18277=>27469, +18278=>27470, +18279=>27471, +18280=>27472, +18281=>27473, +18282=>27474, +18283=>27475, +18284=>27476, +18285=>27477, +18286=>27478, +18287=>27479, +18288=>27480, +18289=>27481, +18290=>27482, +18291=>27483, +18292=>27484, +18293=>27485, +18294=>27486, +18295=>27487, +18296=>27488, +18297=>27489, +18298=>27490, +18299=>27491, +18301=>27492, +18302=>27493, +18303=>27494, +18304=>27495, +18305=>27496, +18306=>27497, +18307=>27498, +18308=>27499, +18309=>27500, +18310=>27501, +18311=>27502, +18312=>27503, +18313=>27504, +18314=>27505, +18315=>27506, +18316=>27507, +18318=>27508, +18319=>27509, +18320=>27510, +18321=>27511, +18322=>27512, +18323=>27513, +18324=>27514, +18325=>27515, +18326=>27516, +18327=>27517, +18328=>27518, +18329=>27519, +18330=>27520, +18331=>27521, +18332=>27522, +18333=>27523, +18334=>27524, +18335=>27525, +18336=>27526, +18337=>27527, +18338=>27528, +18339=>27529, +18340=>27530, +18341=>27531, +18342=>27532, +18343=>27533, +18344=>27534, +18345=>27535, +18346=>27536, +18347=>27537, +18348=>27538, +18349=>27539, +18350=>27540, +18351=>27541, +18352=>27542, +18353=>27543, +18354=>27544, +18355=>27545, +18356=>27546, +18357=>27547, +18358=>27548, +18359=>27549, +18360=>27550, +18361=>27551, +18362=>27552, +18363=>27553, +18364=>27554, +18365=>27555, +18366=>27556, +18367=>27557, +18368=>27558, +18369=>27559, +18370=>27560, +18371=>27561, +18372=>27562, +18373=>27563, +18374=>27564, +18375=>27565, +18376=>27566, +18377=>27567, +18378=>27568, +18379=>27569, +18380=>27570, +18381=>27571, +18382=>27572, +18383=>27573, +18384=>27574, +18385=>27575, +18386=>27576, +18387=>27577, +18388=>27578, +18389=>27579, +18390=>27580, +18391=>27581, +18392=>27582, +18393=>27583, +18394=>27584, +18395=>27585, +18396=>27586, +18397=>27587, +18398=>27588, +18399=>27589, +18400=>27590, +18401=>27591, +18402=>27592, +18403=>27593, +18404=>27594, +18405=>27595, +18406=>27596, +18407=>27597, +18408=>27598, +18409=>27599, +18410=>27600, +18411=>27601, +18412=>27602, +18413=>27603, +18414=>27604, +18415=>27605, +18416=>27606, +18417=>27607, +18418=>27608, +18419=>27609, +18420=>27610, +18421=>27611, +18422=>27612, +18423=>27613, +18424=>27614, +18425=>27615, +18426=>27616, +18427=>27617, +18428=>27618, +18429=>27619, +18430=>27620, +18431=>27621, +18432=>27622, +18433=>27623, +18434=>27624, +18435=>27625, +18436=>27626, +18437=>27627, +18438=>27628, +18439=>27629, +18440=>27630, +18441=>27631, +18442=>27632, +18443=>27633, +18444=>27634, +18445=>27635, +18446=>27636, +18447=>27637, +18448=>27638, +18449=>27639, +18450=>27640, +18451=>27641, +18452=>27642, +18453=>27643, +18454=>27644, +18455=>27645, +18456=>27646, +18457=>27647, +18458=>27648, +18459=>27649, +18460=>27650, +18461=>27651, +18462=>27652, +18463=>27653, +18464=>27654, +18465=>27655, +18466=>27656, +18467=>27657, +18468=>27658, +18469=>27659, +18470=>27660, +18471=>27661, +18472=>27662, +18473=>27663, +18474=>27664, +18475=>27665, +18476=>27666, +18477=>27667, +18478=>27668, +18479=>27669, +18480=>27670, +18481=>27671, +18482=>27672, +18483=>27673, +18484=>27674, +18485=>27675, +18486=>27676, +18487=>27677, +18488=>27678, +18489=>27679, +18490=>27680, +18491=>27681, +18492=>27682, +18493=>27683, +18494=>27684, +18495=>27685, +18496=>27686, +18497=>27687, +18498=>27688, +18499=>27689, +18500=>27690, +18501=>27691, +18502=>27692, +18503=>27693, +18504=>27694, +18505=>27695, +18506=>27696, +18507=>27697, +18508=>27698, +18509=>27699, +18510=>27700, +18511=>27701, +18512=>27702, +18513=>27703, +18514=>27704, +18515=>27705, +18516=>27706, +18517=>27707, +18518=>27708, +18519=>27709, +18520=>27710, +18521=>27711, +18522=>27712, +18523=>27713, +18524=>27714, +18525=>27715, +18526=>27716, +18527=>27717, +18528=>27718, +18529=>27719, +18530=>27720, +18531=>27721, +18532=>27722, +18533=>27723, +18534=>27724, +18535=>27725, +18536=>27726, +18537=>27727, +18538=>27728, +18539=>27729, +18540=>27730, +18541=>27731, +18542=>27732, +18543=>27733, +18544=>27734, +18545=>27735, +18546=>27736, +18547=>27737, +18548=>27738, +18549=>27739, +18550=>27740, +18551=>27741, +18552=>27742, +18553=>27743, +18554=>27744, +18555=>27745, +18556=>27746, +18557=>27747, +18558=>27748, +18559=>27749, +18560=>27750, +18561=>27751, +18562=>27752, +18563=>27753, +18564=>27754, +18565=>27755, +18566=>27756, +18567=>27757, +18568=>27758, +18569=>27759, +18570=>27760, +18571=>27761, +18572=>27762, +18573=>27763, +18574=>27764, +18575=>27765, +18576=>27766, +18577=>27767, +18578=>27768, +18579=>27769, +18580=>27770, +18581=>27771, +18582=>27772, +18583=>27773, +18584=>27774, +18585=>27775, +18586=>27776, +18587=>27777, +18588=>27778, +18589=>27779, +18590=>27780, +18591=>27781, +18592=>27782, +18593=>27783, +18594=>27784, +18595=>27785, +18596=>27786, +18597=>27787, +18598=>27788, +18599=>27789, +18600=>27790, +18601=>27791, +18602=>27792, +18603=>27793, +18604=>27794, +18605=>27795, +18606=>27796, +18607=>27797, +18608=>27798, +18609=>27799, +18610=>27800, +18611=>27801, +18612=>27802, +18613=>27803, +18614=>27804, +18615=>27805, +18616=>27806, +18617=>27807, +18618=>27808, +18619=>27809, +18620=>27810, +18621=>27811, +18622=>27812, +18623=>27813, +18624=>27814, +18625=>27815, +18626=>27816, +18627=>27817, +18628=>27818, +18629=>27819, +18630=>27820, +18631=>27821, +18632=>27822, +18633=>27823, +18634=>27824, +18635=>27825, +18636=>27826, +18637=>27827, +18638=>27828, +18639=>27829, +18640=>27830, +18641=>27831, +18642=>27832, +18643=>27833, +18644=>27834, +18645=>27835, +18646=>27836, +18647=>27837, +18648=>27838, +18649=>27839, +18650=>27840, +18651=>27841, +18652=>27842, +18653=>27843, +18654=>27844, +18655=>27845, +18656=>27846, +18657=>27847, +18658=>27848, +18659=>27849, +18660=>27850, +18661=>27851, +18662=>27852, +18663=>27853, +18664=>27854, +18665=>27855, +18666=>27856, +18667=>27857, +18668=>27858, +18669=>27859, +18670=>27860, +18671=>27861, +18672=>27862, +18673=>27863, +18674=>27864, +18675=>27865, +18676=>27866, +18677=>27867, +18678=>27868, +18679=>27869, +18680=>27870, +18681=>27871, +18682=>27872, +18683=>27873, +18684=>27874, +18685=>27875, +18686=>27876, +18687=>27877, +18688=>27878, +18689=>27879, +18690=>27880, +18691=>27881, +18692=>27882, +18693=>27883, +18694=>27884, +18695=>27885, +18696=>27886, +18697=>27887, +18698=>27888, +18699=>27889, +18700=>27890, +18701=>27891, +18702=>27892, +18703=>27893, +18704=>27894, +18705=>27895, +18706=>27896, +18707=>27897, +18708=>27898, +18709=>27899, +18710=>27900, +18711=>27901, +18712=>27902, +18713=>27903, +18714=>27904, +18715=>27905, +18716=>27906, +18717=>27907, +18718=>27908, +18719=>27909, +18720=>27910, +18721=>27911, +18722=>27912, +18723=>27913, +18724=>27914, +18725=>27915, +18726=>27916, +18727=>27917, +18728=>27918, +18729=>27919, +18730=>27920, +18731=>27921, +18732=>27922, +18733=>27923, +18734=>27924, +18735=>27925, +18736=>27926, +18737=>27927, +18738=>27928, +18739=>27929, +18740=>27930, +18741=>27931, +18742=>27932, +18743=>27933, +18744=>27934, +18745=>27935, +18746=>27936, +18747=>27937, +18748=>27938, +18749=>27939, +18750=>27940, +18751=>27941, +18752=>27942, +18753=>27943, +18754=>27944, +18755=>27945, +18756=>27946, +18757=>27947, +18758=>27948, +18760=>27949, +18761=>27950, +18762=>27951, +18763=>27952, +18764=>27953, +18765=>27954, +18766=>27955, +18767=>27956, +18768=>27957, +18769=>27958, +18770=>27959, +18771=>27960, +18772=>27961, +18773=>27962, +18774=>27963, +18775=>27964, +18776=>27965, +18777=>27966, +18778=>27967, +18779=>27968, +18780=>27969, +18781=>27970, +18782=>27971, +18783=>27972, +18784=>27973, +18785=>27974, +18786=>27975, +18787=>27976, +18788=>27977, +18789=>27978, +18790=>27979, +18791=>27980, +18792=>27981, +18793=>27982, +18794=>27983, +18795=>27984, +18796=>27985, +18797=>27986, +18798=>27987, +18799=>27988, +18800=>27989, +18801=>27990, +18802=>27991, +18803=>27992, +18804=>27993, +18805=>27994, +18806=>27995, +18807=>27996, +18808=>27997, +18809=>27998, +18811=>27999, +18812=>28000, +18814=>28001, +18815=>28002, +18816=>28003, +18817=>28004, +18820=>28005, +18823=>28006, +18824=>28007, +18825=>28008, +18826=>28009, +18827=>28010, +18828=>28011, +18829=>28012, +18830=>28013, +18831=>28014, +18832=>28015, +18833=>28016, +18834=>28017, +18835=>28018, +18836=>28019, +18837=>28020, +18838=>28021, +18839=>28022, +18840=>28023, +18841=>28024, +18842=>28025, +18844=>28026, +18845=>28027, +18846=>28028, +18848=>28029, +18849=>28030, +18850=>28031, +18851=>28032, +18852=>28033, +18853=>28034, +18854=>28035, +18855=>28036, +18856=>28037, +18857=>28038, +18858=>28039, +18859=>28040, +18860=>28041, +18861=>28042, +18862=>28043, +18863=>28044, +18864=>28045, +18865=>28046, +18866=>28047, +18867=>28048, +18868=>28049, +18869=>28050, +18872=>28051, +18873=>28052, +18874=>28053, +18875=>28054, +18876=>28055, +18877=>28056, +18878=>28057, +18879=>28058, +18880=>28059, +18881=>28060, +18882=>28061, +18883=>28062, +18884=>28063, +18885=>28064, +18886=>28065, +18887=>28066, +18888=>28067, +18889=>28068, +18890=>28069, +18891=>28070, +18892=>28071, +18893=>28072, +18894=>28073, +18895=>28074, +18896=>28075, +18897=>28076, +18898=>28077, +18899=>28078, +18900=>28079, +18901=>28080, +18902=>28081, +18903=>28082, +18904=>28083, +18905=>28084, +18906=>28085, +18907=>28086, +18908=>28087, +18909=>28088, +18910=>28089, +18911=>28090, +18912=>28091, +18913=>28092, +18914=>28093, +18915=>28094, +18916=>28095, +18917=>28096, +18918=>28097, +18919=>28098, +18920=>28099, +18921=>28100, +18922=>28101, +18923=>28102, +18924=>28103, +18925=>28104, +18926=>28105, +18927=>28106, +18928=>28107, +18929=>28108, +18930=>28109, +18931=>28110, +18932=>28111, +18933=>28112, +18934=>28113, +18935=>28114, +18936=>28115, +18937=>28116, +18938=>28117, +18939=>28118, +18940=>28119, +18941=>28120, +18942=>28121, +18943=>28122, +18944=>28123, +18945=>28124, +18946=>28125, +18947=>28126, +18948=>28127, +18949=>28128, +18950=>28129, +18951=>28130, +18952=>28131, +18953=>28132, +18954=>28133, +18955=>28134, +18956=>28135, +18957=>28136, +18958=>28137, +18959=>28138, +18960=>28139, +18961=>28140, +18962=>28141, +18963=>28142, +18964=>28143, +18965=>28144, +18966=>28145, +18967=>28146, +18968=>28147, +18969=>28148, +18970=>28149, +18971=>28150, +18972=>28151, +18973=>28152, +18974=>28153, +18975=>28154, +18976=>28155, +18977=>28156, +18978=>28157, +18979=>28158, +18980=>28159, +18981=>28160, +18982=>28161, +18983=>28162, +18984=>28163, +18985=>28164, +18986=>28165, +18987=>28166, +18988=>28167, +18989=>28168, +18990=>28169, +18991=>28170, +18992=>28171, +18993=>28172, +18994=>28173, +18995=>28174, +18996=>28175, +18997=>28176, +18998=>28177, +18999=>28178, +19000=>28179, +19001=>28180, +19002=>28181, +19003=>28182, +19004=>28183, +19005=>28184, +19006=>28185, +19007=>28186, +19008=>28187, +19009=>28188, +19010=>28189, +19011=>28190, +19012=>28191, +19013=>28192, +19014=>28193, +19015=>28194, +19016=>28195, +19017=>28196, +19018=>28197, +19019=>28198, +19020=>28199, +19021=>28200, +19022=>28201, +19023=>28202, +19024=>28203, +19025=>28204, +19026=>28205, +19027=>28206, +19028=>28207, +19029=>28208, +19030=>28209, +19031=>28210, +19032=>28211, +19033=>28212, +19034=>28213, +19035=>28214, +19036=>28215, +19037=>28216, +19038=>28217, +19039=>28218, +19040=>28219, +19041=>28220, +19042=>28221, +19043=>28222, +19044=>28223, +19045=>28224, +19046=>28225, +19047=>28226, +19048=>28227, +19049=>28228, +19050=>28229, +19051=>28230, +19052=>28231, +19053=>28232, +19054=>28233, +19055=>28234, +19056=>28235, +19057=>28236, +19058=>28237, +19059=>28238, +19060=>28239, +19061=>28240, +19062=>28241, +19063=>28242, +19064=>28243, +19065=>28244, +19066=>28245, +19067=>28246, +19068=>28247, +19069=>28248, +19070=>28249, +19071=>28250, +19072=>28251, +19073=>28252, +19074=>28253, +19075=>28254, +19076=>28255, +19077=>28256, +19078=>28257, +19079=>28258, +19080=>28259, +19081=>28260, +19082=>28261, +19083=>28262, +19084=>28263, +19085=>28264, +19086=>28265, +19087=>28266, +19088=>28267, +19089=>28268, +19090=>28269, +19091=>28270, +19092=>28271, +19093=>28272, +19094=>28273, +19095=>28274, +19096=>28275, +19097=>28276, +19098=>28277, +19099=>28278, +19100=>28279, +19101=>28280, +19102=>28281, +19103=>28282, +19104=>28283, +19105=>28284, +19106=>28285, +19107=>28286, +19108=>28287, +19109=>28288, +19110=>28289, +19111=>28290, +19112=>28291, +19113=>28292, +19114=>28293, +19115=>28294, +19116=>28295, +19117=>28296, +19118=>28297, +19119=>28298, +19120=>28299, +19121=>28300, +19122=>28301, +19123=>28302, +19124=>28303, +19125=>28304, +19126=>28305, +19127=>28306, +19128=>28307, +19129=>28308, +19130=>28309, +19131=>28310, +19132=>28311, +19133=>28312, +19134=>28313, +19135=>28314, +19136=>28315, +19137=>28316, +19138=>28317, +19139=>28318, +19140=>28319, +19141=>28320, +19142=>28321, +19143=>28322, +19144=>28323, +19145=>28324, +19146=>28325, +19147=>28326, +19148=>28327, +19149=>28328, +19150=>28329, +19151=>28330, +19152=>28331, +19153=>28332, +19154=>28333, +19155=>28334, +19156=>28335, +19157=>28336, +19158=>28337, +19159=>28338, +19160=>28339, +19161=>28340, +19162=>28341, +19163=>28342, +19164=>28343, +19165=>28344, +19166=>28345, +19167=>28346, +19168=>28347, +19169=>28348, +19170=>28349, +19171=>28350, +19172=>28351, +19173=>28352, +19174=>28353, +19175=>28354, +19176=>28355, +19177=>28356, +19178=>28357, +19179=>28358, +19180=>28359, +19181=>28360, +19182=>28361, +19183=>28362, +19184=>28363, +19185=>28364, +19186=>28365, +19187=>28366, +19188=>28367, +19189=>28368, +19190=>28369, +19191=>28370, +19192=>28371, +19193=>28372, +19194=>28373, +19195=>28374, +19196=>28375, +19197=>28376, +19198=>28377, +19199=>28378, +19200=>28379, +19201=>28380, +19202=>28381, +19203=>28382, +19204=>28383, +19205=>28384, +19206=>28385, +19207=>28386, +19208=>28387, +19209=>28388, +19210=>28389, +19211=>28390, +19212=>28391, +19213=>28392, +19214=>28393, +19215=>28394, +19216=>28395, +19217=>28396, +19218=>28397, +19219=>28398, +19220=>28399, +19221=>28400, +19222=>28401, +19223=>28402, +19224=>28403, +19225=>28404, +19226=>28405, +19227=>28406, +19228=>28407, +19229=>28408, +19230=>28409, +19231=>28410, +19232=>28411, +19233=>28412, +19234=>28413, +19235=>28414, +19236=>28415, +19237=>28416, +19238=>28417, +19239=>28418, +19240=>28419, +19241=>28420, +19242=>28421, +19243=>28422, +19244=>28423, +19245=>28424, +19246=>28425, +19247=>28426, +19248=>28427, +19249=>28428, +19250=>28429, +19251=>28430, +19252=>28431, +19253=>28432, +19254=>28433, +19255=>28434, +19256=>28435, +19257=>28436, +19258=>28437, +19259=>28438, +19260=>28439, +19261=>28440, +19262=>28441, +19263=>28442, +19264=>28443, +19265=>28444, +19266=>28445, +19267=>28446, +19268=>28447, +19269=>28448, +19270=>28449, +19271=>28450, +19272=>28451, +19273=>28452, +19274=>28453, +19275=>28454, +19276=>28455, +19277=>28456, +19278=>28457, +19279=>28458, +19280=>28459, +19281=>28460, +19282=>28461, +19283=>28462, +19284=>28463, +19285=>28464, +19286=>28465, +19287=>28466, +19288=>28467, +19289=>28468, +19290=>28469, +19291=>28470, +19292=>28471, +19293=>28472, +19294=>28473, +19295=>28474, +19296=>28475, +19297=>28476, +19298=>28477, +19299=>28478, +19300=>28479, +19301=>28480, +19302=>28481, +19303=>28482, +19304=>28483, +19305=>28484, +19306=>28485, +19307=>28486, +19308=>28487, +19309=>28488, +19310=>28489, +19311=>28490, +19312=>28491, +19313=>28492, +19314=>28493, +19315=>28494, +19316=>28495, +19317=>28496, +19318=>28497, +19319=>28498, +19320=>28499, +19321=>28500, +19322=>28501, +19323=>28502, +19324=>28503, +19325=>28504, +19326=>28505, +19327=>28506, +19328=>28507, +19329=>28508, +19330=>28509, +19331=>28510, +19332=>28511, +19333=>28512, +19334=>28513, +19335=>28514, +19336=>28515, +19337=>28516, +19338=>28517, +19339=>28518, +19340=>28519, +19341=>28520, +19342=>28521, +19343=>28522, +19344=>28523, +19345=>28524, +19346=>28525, +19347=>28526, +19348=>28527, +19349=>28528, +19350=>28529, +19351=>28530, +19352=>28531, +19353=>28532, +19354=>28533, +19355=>28534, +19356=>28535, +19357=>28536, +19358=>28537, +19359=>28538, +19360=>28539, +19361=>28540, +19362=>28541, +19363=>28542, +19364=>28543, +19365=>28544, +19366=>28545, +19367=>28546, +19368=>28547, +19369=>28548, +19370=>28549, +19371=>28550, +19372=>28551, +19373=>28552, +19374=>28553, +19375=>28554, +19376=>28555, +19377=>28556, +19378=>28557, +19379=>28558, +19380=>28559, +19381=>28560, +19382=>28561, +19383=>28562, +19384=>28563, +19385=>28564, +19386=>28565, +19387=>28566, +19388=>28567, +19389=>28568, +19390=>28569, +19391=>28570, +19392=>28571, +19393=>28572, +19394=>28573, +19395=>28574, +19396=>28575, +19397=>28576, +19398=>28577, +19399=>28578, +19400=>28579, +19401=>28580, +19402=>28581, +19403=>28582, +19404=>28583, +19405=>28584, +19406=>28585, +19407=>28586, +19408=>28587, +19409=>28588, +19410=>28589, +19411=>28590, +19412=>28591, +19413=>28592, +19414=>28593, +19415=>28594, +19416=>28595, +19417=>28596, +19418=>28597, +19419=>28598, +19420=>28599, +19421=>28600, +19422=>28601, +19423=>28602, +19424=>28603, +19425=>28604, +19426=>28605, +19427=>28606, +19428=>28607, +19429=>28608, +19430=>28609, +19431=>28610, +19432=>28611, +19433=>28612, +19434=>28613, +19435=>28614, +19436=>28615, +19437=>28616, +19438=>28617, +19439=>28618, +19440=>28619, +19441=>28620, +19442=>28621, +19443=>28622, +19444=>28623, +19445=>28624, +19446=>28625, +19447=>28626, +19448=>28627, +19449=>28628, +19450=>28629, +19451=>28630, +19452=>28631, +19453=>28632, +19454=>28633, +19455=>28634, +19456=>28635, +19457=>28636, +19458=>28637, +19459=>28638, +19460=>28639, +19461=>28640, +19462=>28641, +19463=>28642, +19464=>28643, +19465=>28644, +19466=>28645, +19467=>28646, +19468=>28647, +19469=>28648, +19470=>28649, +19471=>28650, +19472=>28651, +19473=>28652, +19474=>28653, +19475=>28654, +19476=>28655, +19477=>28656, +19478=>28657, +19479=>28658, +19480=>28659, +19481=>28660, +19482=>28661, +19483=>28662, +19484=>28663, +19485=>28664, +19486=>28665, +19487=>28666, +19488=>28667, +19489=>28668, +19490=>28669, +19491=>28670, +19492=>28671, +19493=>28672, +19494=>28673, +19495=>28674, +19496=>28675, +19497=>28676, +19498=>28677, +19499=>28678, +19500=>28679, +19501=>28680, +19502=>28681, +19503=>28682, +19504=>28683, +19505=>28684, +19506=>28685, +19507=>28686, +19508=>28687, +19509=>28688, +19510=>28689, +19511=>28690, +19512=>28691, +19513=>28692, +19514=>28693, +19515=>28694, +19516=>28695, +19517=>28696, +19518=>28697, +19519=>28698, +19520=>28699, +19521=>28700, +19522=>28701, +19523=>28702, +19524=>28703, +19525=>28704, +19526=>28705, +19527=>28706, +19528=>28707, +19529=>28708, +19530=>28709, +19531=>28710, +19532=>28711, +19533=>28712, +19534=>28713, +19535=>28714, +19536=>28715, +19537=>28716, +19538=>28717, +19539=>28718, +19540=>28719, +19541=>28720, +19542=>28721, +19543=>28722, +19544=>28723, +19545=>28724, +19546=>28725, +19547=>28726, +19548=>28727, +19549=>28728, +19550=>28729, +19551=>28730, +19552=>28731, +19553=>28732, +19554=>28733, +19555=>28734, +19556=>28735, +19557=>28736, +19558=>28737, +19559=>28738, +19560=>28739, +19561=>28740, +19562=>28741, +19563=>28742, +19564=>28743, +19565=>28744, +19566=>28745, +19567=>28746, +19568=>28747, +19569=>28748, +19570=>28749, +19571=>28750, +19572=>28751, +19573=>28752, +19574=>28753, +19576=>28754, +19577=>28755, +19578=>28756, +19579=>28757, +19580=>28758, +19581=>28759, +19582=>28760, +19583=>28761, +19584=>28762, +19585=>28763, +19586=>28764, +19587=>28765, +19588=>28766, +19589=>28767, +19590=>28768, +19591=>28769, +19592=>28770, +19593=>28771, +19594=>28772, +19595=>28773, +19596=>28774, +19597=>28775, +19598=>28776, +19599=>28777, +19600=>28778, +19601=>28779, +19602=>28780, +19603=>28781, +19604=>28782, +19605=>28783, +19606=>28784, +19607=>28785, +19608=>28786, +19609=>28787, +19610=>28788, +19611=>28789, +19612=>28790, +19613=>28791, +19614=>28792, +19620=>28793, +19621=>28794, +19622=>28795, +19623=>28796, +19624=>28797, +19625=>28798, +19626=>28799, +19627=>28800, +19628=>28801, +19629=>28802, +19630=>28803, +19631=>28804, +19632=>28805, +19633=>28806, +19634=>28807, +19635=>28808, +19636=>28809, +19637=>28810, +19638=>28811, +19639=>28812, +19640=>28813, +19641=>28814, +19642=>28815, +19643=>28816, +19644=>28817, +19645=>28818, +19646=>28819, +19647=>28820, +19648=>28821, +19649=>28822, +19650=>28823, +19651=>28824, +19652=>28825, +19653=>28826, +19654=>28827, +19655=>28828, +19656=>28829, +19657=>28830, +19658=>28831, +19659=>28832, +19660=>28833, +19661=>28834, +19662=>28835, +19663=>28836, +19664=>28837, +19665=>28838, +19666=>28839, +19667=>28840, +19668=>28841, +19669=>28842, +19670=>28843, +19671=>28844, +19672=>28845, +19673=>28846, +19674=>28847, +19675=>28848, +19676=>28849, +19677=>28850, +19678=>28851, +19679=>28852, +19680=>28853, +19681=>28854, +19682=>28855, +19683=>28856, +19684=>28857, +19685=>28858, +19686=>28859, +19687=>28860, +19688=>28861, +19689=>28862, +19690=>28863, +19691=>28864, +19692=>28865, +19693=>28866, +19694=>28867, +19695=>28868, +19696=>28869, +19697=>28870, +19698=>28871, +19699=>28872, +19700=>28873, +19701=>28874, +19702=>28875, +19703=>28876, +19704=>28877, +19705=>28878, +19706=>28879, +19707=>28880, +19708=>28881, +19709=>28882, +19710=>28883, +19711=>28884, +19712=>28885, +19713=>28886, +19714=>28887, +19715=>28888, +19716=>28889, +19717=>28890, +19718=>28891, +19719=>28892, +19720=>28893, +19721=>28894, +19722=>28895, +19723=>28896, +19724=>28897, +19725=>28898, +19726=>28899, +19727=>28900, +19728=>28901, +19729=>28902, +19730=>28903, +19738=>28904, +19739=>28905, +19740=>28906, +19741=>28907, +19742=>28908, +19743=>28909, +19744=>28910, +19745=>28911, +19746=>28912, +19747=>28913, +19748=>28914, +19749=>28915, +19750=>28916, +19751=>28917, +19752=>28918, +19753=>28919, +19754=>28920, +19755=>28921, +19756=>28922, +19757=>28923, +19758=>28924, +19759=>28925, +19760=>28926, +19761=>28927, +19762=>28928, +19763=>28929, +19764=>28930, +19765=>28931, +19766=>28932, +19767=>28933, +19768=>28934, +19769=>28935, +19770=>28936, +19771=>28937, +19772=>28938, +19773=>28939, +19774=>28940, +19775=>28941, +19776=>28942, +19777=>28943, +19778=>28944, +19779=>28945, +19780=>28946, +19781=>28947, +19782=>28948, +19783=>28949, +19784=>28950, +19785=>28951, +19786=>28952, +19787=>28953, +19788=>28954, +19789=>28955, +19790=>28956, +19791=>28957, +19792=>28958, +19793=>28959, +19794=>28960, +19795=>28961, +19796=>28962, +19797=>28963, +19798=>28964, +19799=>28965, +19800=>28966, +19801=>28967, +19802=>28968, +19803=>28969, +19804=>28970, +19805=>28971, +19806=>28972, +19807=>28973, +19808=>28974, +19809=>28975, +19810=>28976, +19811=>28977, +19812=>28978, +19813=>28979, +19814=>28980, +19815=>28981, +19816=>28982, +19817=>28983, +19818=>28984, +19819=>28985, +19820=>28986, +19821=>28987, +19822=>28988, +19823=>28989, +19824=>28990, +19825=>28991, +19826=>28992, +19827=>28993, +19828=>28994, +19829=>28995, +19830=>28996, +19831=>28997, +19832=>28998, +19833=>28999, +19834=>29000, +19835=>29001, +19836=>29002, +19837=>29003, +19838=>29004, +19839=>29005, +19840=>29006, +19841=>29007, +19842=>29008, +19843=>29009, +19844=>29010, +19845=>29011, +19846=>29012, +19847=>29013, +19848=>29014, +19849=>29015, +19850=>29016, +19851=>29017, +19852=>29018, +19853=>29019, +19854=>29020, +19855=>29021, +19856=>29022, +19857=>29023, +19858=>29024, +19859=>29025, +19860=>29026, +19861=>29027, +19862=>29028, +19863=>29029, +19864=>29030, +19865=>29031, +19866=>29032, +19867=>29033, +19868=>29034, +19869=>29035, +19870=>29036, +19871=>29037, +19872=>29038, +19873=>29039, +19874=>29040, +19875=>29041, +19876=>29042, +19877=>29043, +19878=>29044, +19879=>29045, +19880=>29046, +19881=>29047, +19882=>29048, +19883=>29049, +19884=>29050, +19885=>29051, +19887=>29052, +19888=>29053, +19889=>29054, +19890=>29055, +19891=>29056, +19892=>29057, +19893=>29058, +40960=>29064, +40961=>29065, +40962=>29066, +40963=>29067, +40964=>29068, +40965=>29069, +40966=>29070, +40967=>29071, +40968=>29072, +40969=>29073, +40970=>29074, +40971=>29075, +40972=>29076, +40973=>29077, +40974=>29078, +40975=>29079, +40976=>29080, +40977=>29081, +40978=>29082, +40979=>29083, +40980=>29084, +40981=>29085, +40982=>29086, +40983=>29087, +40984=>29088, +40985=>29089, +40986=>29090, +40987=>29091, +40988=>29092, +40989=>29093, +40990=>29094, +40991=>29095, +40992=>29096, +40993=>29097, +40994=>29098, +40995=>29099, +40996=>29100, +40997=>29101, +40998=>29102, +40999=>29103, +41000=>29104, +41001=>29105, +41002=>29106, +41003=>29107, +41004=>29108, +41005=>29109, +41006=>29110, +41007=>29111, +41008=>29112, +41009=>29113, +41010=>29114, +41011=>29115, +41012=>29116, +41013=>29117, +41014=>29118, +41015=>29119, +41016=>29120, +41017=>29121, +41018=>29122, +41019=>29123, +41020=>29124, +41021=>29125, +41022=>29126, +41023=>29127, +41024=>29128, +41025=>29129, +41026=>29130, +41027=>29131, +41028=>29132, +41029=>29133, +41030=>29134, +41031=>29135, +41032=>29136, +41033=>29137, +41034=>29138, +41035=>29139, +41036=>29140, +41037=>29141, +41038=>29142, +41039=>29143, +41040=>29144, +41041=>29145, +41042=>29146, +41043=>29147, +41044=>29148, +41045=>29149, +41046=>29150, +41047=>29151, +41048=>29152, +41049=>29153, +41050=>29154, +41051=>29155, +41052=>29156, +41053=>29157, +41054=>29158, +41055=>29159, +41056=>29160, +41057=>29161, +41058=>29162, +41059=>29163, +41060=>29164, +41061=>29165, +41062=>29166, +41063=>29167, +41064=>29168, +41065=>29169, +41066=>29170, +41067=>29171, +41068=>29172, +41069=>29173, +41070=>29174, +41071=>29175, +41072=>29176, +41073=>29177, +41074=>29178, +41075=>29179, +41076=>29180, +41077=>29181, +41078=>29182, +41079=>29183, +41080=>29184, +41081=>29185, +41082=>29186, +41083=>29187, +41084=>29188, +41085=>29189, +41086=>29190, +41087=>29191, +41088=>29192, +41089=>29193, +41090=>29194, +41091=>29195, +41092=>29196, +41093=>29197, +41094=>29198, +41095=>29199, +41096=>29200, +41097=>29201, +41098=>29202, +41099=>29203, +41100=>29204, +41101=>29205, +41102=>29206, +41103=>29207, +41104=>29208, +41105=>29209, +41106=>29210, +41107=>29211, +41108=>29212, +41109=>29213, +41110=>29214, +41111=>29215, +41112=>29216, +41113=>29217, +41114=>29218, +41115=>29219, +41116=>29220, +41117=>29221, +41118=>29222, +41119=>29223, +41120=>29224, +41121=>29225, +41122=>29226, +41123=>29227, +41124=>29228, +41125=>29229, +41126=>29230, +41127=>29231, +41128=>29232, +41129=>29233, +41130=>29234, +41131=>29235, +41132=>29236, +41133=>29237, +41134=>29238, +41135=>29239, +41136=>29240, +41137=>29241, +41138=>29242, +41139=>29243, +41140=>29244, +41141=>29245, +41142=>29246, +41143=>29247, +41144=>29248, +41145=>29249, +41146=>29250, +41147=>29251, +41148=>29252, +41149=>29253, +41150=>29254, +41151=>29255, +41152=>29256, +41153=>29257, +41154=>29258, +41155=>29259, +41156=>29260, +41157=>29261, +41158=>29262, +41159=>29263, +41160=>29264, +41161=>29265, +41162=>29266, +41163=>29267, +41164=>29268, +41165=>29269, +41166=>29270, +41167=>29271, +41168=>29272, +41169=>29273, +41170=>29274, +41171=>29275, +41172=>29276, +41173=>29277, +41174=>29278, +41175=>29279, +41176=>29280, +41177=>29281, +41178=>29282, +41179=>29283, +41180=>29284, +41181=>29285, +41182=>29286, +41183=>29287, +41184=>29288, +41185=>29289, +41186=>29290, +41187=>29291, +41188=>29292, +41189=>29293, +41190=>29294, +41191=>29295, +41192=>29296, +41193=>29297, +41194=>29298, +41195=>29299, +41196=>29300, +41197=>29301, +41198=>29302, +41199=>29303, +41200=>29304, +41201=>29305, +41202=>29306, +41203=>29307, +41204=>29308, +41205=>29309, +41206=>29310, +41207=>29311, +41208=>29312, +41209=>29313, +41210=>29314, +41211=>29315, +41212=>29316, +41213=>29317, +41214=>29318, +41215=>29319, +41216=>29320, +41217=>29321, +41218=>29322, +41219=>29323, +41220=>29324, +41221=>29325, +41222=>29326, +41223=>29327, +41224=>29328, +41225=>29329, +41226=>29330, +41227=>29331, +41228=>29332, +41229=>29333, +41230=>29334, +41231=>29335, +41232=>29336, +41233=>29337, +41234=>29338, +41235=>29339, +41236=>29340, +41237=>29341, +41238=>29342, +41239=>29343, +41240=>29344, +41241=>29345, +41242=>29346, +41243=>29347, +41244=>29348, +41245=>29349, +41246=>29350, +41247=>29351, +41248=>29352, +41249=>29353, +41250=>29354, +41251=>29355, +41252=>29356, +41253=>29357, +41254=>29358, +41255=>29359, +41256=>29360, +41257=>29361, +41258=>29362, +41259=>29363, +41260=>29364, +41261=>29365, +41262=>29366, +41263=>29367, +41264=>29368, +41265=>29369, +41266=>29370, +41267=>29371, +41268=>29372, +41269=>29373, +41270=>29374, +41271=>29375, +41272=>29376, +41273=>29377, +41274=>29378, +41275=>29379, +41276=>29380, +41277=>29381, +41278=>29382, +41279=>29383, +41280=>29384, +41281=>29385, +41282=>29386, +41283=>29387, +41284=>29388, +41285=>29389, +41286=>29390, +41287=>29391, +41288=>29392, +41289=>29393, +41290=>29394, +41291=>29395, +41292=>29396, +41293=>29397, +41294=>29398, +41295=>29399, +41296=>29400, +41297=>29401, +41298=>29402, +41299=>29403, +41300=>29404, +41301=>29405, +41302=>29406, +41303=>29407, +41304=>29408, +41305=>29409, +41306=>29410, +41307=>29411, +41308=>29412, +41309=>29413, +41310=>29414, +41311=>29415, +41312=>29416, +41313=>29417, +41314=>29418, +41315=>29419, +41316=>29420, +41317=>29421, +41318=>29422, +41319=>29423, +41320=>29424, +41321=>29425, +41322=>29426, +41323=>29427, +41324=>29428, +41325=>29429, +41326=>29430, +41327=>29431, +41328=>29432, +41329=>29433, +41330=>29434, +41331=>29435, +41332=>29436, +41333=>29437, +41334=>29438, +41335=>29439, +41336=>29440, +41337=>29441, +41338=>29442, +41339=>29443, +41340=>29444, +41341=>29445, +41342=>29446, +41343=>29447, +41344=>29448, +41345=>29449, +41346=>29450, +41347=>29451, +41348=>29452, +41349=>29453, +41350=>29454, +41351=>29455, +41352=>29456, +41353=>29457, +41354=>29458, +41355=>29459, +41356=>29460, +41357=>29461, +41358=>29462, +41359=>29463, +41360=>29464, +41361=>29465, +41362=>29466, +41363=>29467, +41364=>29468, +41365=>29469, +41366=>29470, +41367=>29471, +41368=>29472, +41369=>29473, +41370=>29474, +41371=>29475, +41372=>29476, +41373=>29477, +41374=>29478, +41375=>29479, +41376=>29480, +41377=>29481, +41378=>29482, +41379=>29483, +41380=>29484, +41381=>29485, +41382=>29486, +41383=>29487, +41384=>29488, +41385=>29489, +41386=>29490, +41387=>29491, +41388=>29492, +41389=>29493, +41390=>29494, +41391=>29495, +41392=>29496, +41393=>29497, +41394=>29498, +41395=>29499, +41396=>29500, +41397=>29501, +41398=>29502, +41399=>29503, +41400=>29504, +41401=>29505, +41402=>29506, +41403=>29507, +41404=>29508, +41405=>29509, +41406=>29510, +41407=>29511, +41408=>29512, +41409=>29513, +41410=>29514, +41411=>29515, +41412=>29516, +41413=>29517, +41414=>29518, +41415=>29519, +41416=>29520, +41417=>29521, +41418=>29522, +41419=>29523, +41420=>29524, +41421=>29525, +41422=>29526, +41423=>29527, +41424=>29528, +41425=>29529, +41426=>29530, +41427=>29531, +41428=>29532, +41429=>29533, +41430=>29534, +41431=>29535, +41432=>29536, +41433=>29537, +41434=>29538, +41435=>29539, +41436=>29540, +41437=>29541, +41438=>29542, +41439=>29543, +41440=>29544, +41441=>29545, +41442=>29546, +41443=>29547, +41444=>29548, +41445=>29549, +41446=>29550, +41447=>29551, +41448=>29552, +41449=>29553, +41450=>29554, +41451=>29555, +41452=>29556, +41453=>29557, +41454=>29558, +41455=>29559, +41456=>29560, +41457=>29561, +41458=>29562, +41459=>29563, +41460=>29564, +41461=>29565, +41462=>29566, +41463=>29567, +41464=>29568, +41465=>29569, +41466=>29570, +41467=>29571, +41468=>29572, +41469=>29573, +41470=>29574, +41471=>29575, +41472=>29576, +41473=>29577, +41474=>29578, +41475=>29579, +41476=>29580, +41477=>29581, +41478=>29582, +41479=>29583, +41480=>29584, +41481=>29585, +41482=>29586, +41483=>29587, +41484=>29588, +41485=>29589, +41486=>29590, +41487=>29591, +41488=>29592, +41489=>29593, +41490=>29594, +41491=>29595, +41492=>29596, +41493=>29597, +41494=>29598, +41495=>29599, +41496=>29600, +41497=>29601, +41498=>29602, +41499=>29603, +41500=>29604, +41501=>29605, +41502=>29606, +41503=>29607, +41504=>29608, +41505=>29609, +41506=>29610, +41507=>29611, +41508=>29612, +41509=>29613, +41510=>29614, +41511=>29615, +41512=>29616, +41513=>29617, +41514=>29618, +41515=>29619, +41516=>29620, +41517=>29621, +41518=>29622, +41519=>29623, +41520=>29624, +41521=>29625, +41522=>29626, +41523=>29627, +41524=>29628, +41525=>29629, +41526=>29630, +41527=>29631, +41528=>29632, +41529=>29633, +41530=>29634, +41531=>29635, +41532=>29636, +41533=>29637, +41534=>29638, +41535=>29639, +41536=>29640, +41537=>29641, +41538=>29642, +41539=>29643, +41540=>29644, +41541=>29645, +41542=>29646, +41543=>29647, +41544=>29648, +41545=>29649, +41546=>29650, +41547=>29651, +41548=>29652, +41549=>29653, +41550=>29654, +41551=>29655, +41552=>29656, +41553=>29657, +41554=>29658, +41555=>29659, +41556=>29660, +41557=>29661, +41558=>29662, +41559=>29663, +41560=>29664, +41561=>29665, +41562=>29666, +41563=>29667, +41564=>29668, +41565=>29669, +41566=>29670, +41567=>29671, +41568=>29672, +41569=>29673, +41570=>29674, +41571=>29675, +41572=>29676, +41573=>29677, +41574=>29678, +41575=>29679, +41576=>29680, +41577=>29681, +41578=>29682, +41579=>29683, +41580=>29684, +41581=>29685, +41582=>29686, +41583=>29687, +41584=>29688, +41585=>29689, +41586=>29690, +41587=>29691, +41588=>29692, +41589=>29693, +41590=>29694, +41591=>29695, +41592=>29696, +41593=>29697, +41594=>29698, +41595=>29699, +41596=>29700, +41597=>29701, +41598=>29702, +41599=>29703, +41600=>29704, +41601=>29705, +41602=>29706, +41603=>29707, +41604=>29708, +41605=>29709, +41606=>29710, +41607=>29711, +41608=>29712, +41609=>29713, +41610=>29714, +41611=>29715, +41612=>29716, +41613=>29717, +41614=>29718, +41615=>29719, +41616=>29720, +41617=>29721, +41618=>29722, +41619=>29723, +41620=>29724, +41621=>29725, +41622=>29726, +41623=>29727, +41624=>29728, +41625=>29729, +41626=>29730, +41627=>29731, +41628=>29732, +41629=>29733, +41630=>29734, +41631=>29735, +41632=>29736, +41633=>29737, +41634=>29738, +41635=>29739, +41636=>29740, +41637=>29741, +41638=>29742, +41639=>29743, +41640=>29744, +41641=>29745, +41642=>29746, +41643=>29747, +41644=>29748, +41645=>29749, +41646=>29750, +41647=>29751, +41648=>29752, +41649=>29753, +41650=>29754, +41651=>29755, +41652=>29756, +41653=>29757, +41654=>29758, +41655=>29759, +41656=>29760, +41657=>29761, +41658=>29762, +41659=>29763, +41660=>29764, +41661=>29765, +41662=>29766, +41663=>29767, +41664=>29768, +41665=>29769, +41666=>29770, +41667=>29771, +41668=>29772, +41669=>29773, +41670=>29774, +41671=>29775, +41672=>29776, +41673=>29777, +41674=>29778, +41675=>29779, +41676=>29780, +41677=>29781, +41678=>29782, +41679=>29783, +41680=>29784, +41681=>29785, +41682=>29786, +41683=>29787, +41684=>29788, +41685=>29789, +41686=>29790, +41687=>29791, +41688=>29792, +41689=>29793, +41690=>29794, +41691=>29795, +41692=>29796, +41693=>29797, +41694=>29798, +41695=>29799, +41696=>29800, +41697=>29801, +41698=>29802, +41699=>29803, +41700=>29804, +41701=>29805, +41702=>29806, +41703=>29807, +41704=>29808, +41705=>29809, +41706=>29810, +41707=>29811, +41708=>29812, +41709=>29813, +41710=>29814, +41711=>29815, +41712=>29816, +41713=>29817, +41714=>29818, +41715=>29819, +41716=>29820, +41717=>29821, +41718=>29822, +41719=>29823, +41720=>29824, +41721=>29825, +41722=>29826, +41723=>29827, +41724=>29828, +41725=>29829, +41726=>29830, +41727=>29831, +41728=>29832, +41729=>29833, +41730=>29834, +41731=>29835, +41732=>29836, +41733=>29837, +41734=>29838, +41735=>29839, +41736=>29840, +41737=>29841, +41738=>29842, +41739=>29843, +41740=>29844, +41741=>29845, +41742=>29846, +41743=>29847, +41744=>29848, +41745=>29849, +41746=>29850, +41747=>29851, +41748=>29852, +41749=>29853, +41750=>29854, +41751=>29855, +41752=>29856, +41753=>29857, +41754=>29858, +41755=>29859, +41756=>29860, +41757=>29861, +41758=>29862, +41759=>29863, +41760=>29864, +41761=>29865, +41762=>29866, +41763=>29867, +41764=>29868, +41765=>29869, +41766=>29870, +41767=>29871, +41768=>29872, +41769=>29873, +41770=>29874, +41771=>29875, +41772=>29876, +41773=>29877, +41774=>29878, +41775=>29879, +41776=>29880, +41777=>29881, +41778=>29882, +41779=>29883, +41780=>29884, +41781=>29885, +41782=>29886, +41783=>29887, +41784=>29888, +41785=>29889, +41786=>29890, +41787=>29891, +41788=>29892, +41789=>29893, +41790=>29894, +41791=>29895, +41792=>29896, +41793=>29897, +41794=>29898, +41795=>29899, +41796=>29900, +41797=>29901, +41798=>29902, +41799=>29903, +41800=>29904, +41801=>29905, +41802=>29906, +41803=>29907, +41804=>29908, +41805=>29909, +41806=>29910, +41807=>29911, +41808=>29912, +41809=>29913, +41810=>29914, +41811=>29915, +41812=>29916, +41813=>29917, +41814=>29918, +41815=>29919, +41816=>29920, +41817=>29921, +41818=>29922, +41819=>29923, +41820=>29924, +41821=>29925, +41822=>29926, +41823=>29927, +41824=>29928, +41825=>29929, +41826=>29930, +41827=>29931, +41828=>29932, +41829=>29933, +41830=>29934, +41831=>29935, +41832=>29936, +41833=>29937, +41834=>29938, +41835=>29939, +41836=>29940, +41837=>29941, +41838=>29942, +41839=>29943, +41840=>29944, +41841=>29945, +41842=>29946, +41843=>29947, +41844=>29948, +41845=>29949, +41846=>29950, +41847=>29951, +41848=>29952, +41849=>29953, +41850=>29954, +41851=>29955, +41852=>29956, +41853=>29957, +41854=>29958, +41855=>29959, +41856=>29960, +41857=>29961, +41858=>29962, +41859=>29963, +41860=>29964, +41861=>29965, +41862=>29966, +41863=>29967, +41864=>29968, +41865=>29969, +41866=>29970, +41867=>29971, +41868=>29972, +41869=>29973, +41870=>29974, +41871=>29975, +41872=>29976, +41873=>29977, +41874=>29978, +41875=>29979, +41876=>29980, +41877=>29981, +41878=>29982, +41879=>29983, +41880=>29984, +41881=>29985, +41882=>29986, +41883=>29987, +41884=>29988, +41885=>29989, +41886=>29990, +41887=>29991, +41888=>29992, +41889=>29993, +41890=>29994, +41891=>29995, +41892=>29996, +41893=>29997, +41894=>29998, +41895=>29999, +41896=>30000, +41897=>30001, +41898=>30002, +41899=>30003, +41900=>30004, +41901=>30005, +41902=>30006, +41903=>30007, +41904=>30008, +41905=>30009, +41906=>30010, +41907=>30011, +41908=>30012, +41909=>30013, +41910=>30014, +41911=>30015, +41912=>30016, +41913=>30017, +41914=>30018, +41915=>30019, +41916=>30020, +41917=>30021, +41918=>30022, +41919=>30023, +41920=>30024, +41921=>30025, +41922=>30026, +41923=>30027, +41924=>30028, +41925=>30029, +41926=>30030, +41927=>30031, +41928=>30032, +41929=>30033, +41930=>30034, +41931=>30035, +41932=>30036, +41933=>30037, +41934=>30038, +41935=>30039, +41936=>30040, +41937=>30041, +41938=>30042, +41939=>30043, +41940=>30044, +41941=>30045, +41942=>30046, +41943=>30047, +41944=>30048, +41945=>30049, +41946=>30050, +41947=>30051, +41948=>30052, +41949=>30053, +41950=>30054, +41951=>30055, +41952=>30056, +41953=>30057, +41954=>30058, +41955=>30059, +41956=>30060, +41957=>30061, +41958=>30062, +41959=>30063, +41960=>30064, +41961=>30065, +41962=>30066, +41963=>30067, +41964=>30068, +41965=>30069, +41966=>30070, +41967=>30071, +41968=>30072, +41969=>30073, +41970=>30074, +41971=>30075, +41972=>30076, +41973=>30077, +41974=>30078, +41975=>30079, +41976=>30080, +41977=>30081, +41978=>30082, +41979=>30083, +41980=>30084, +41981=>30085, +41982=>30086, +41983=>30087, +41984=>30088, +41985=>30089, +41986=>30090, +41987=>30091, +41988=>30092, +41989=>30093, +41990=>30094, +41991=>30095, +41992=>30096, +41993=>30097, +41994=>30098, +41995=>30099, +41996=>30100, +41997=>30101, +41998=>30102, +41999=>30103, +42000=>30104, +42001=>30105, +42002=>30106, +42003=>30107, +42004=>30108, +42005=>30109, +42006=>30110, +42007=>30111, +42008=>30112, +42009=>30113, +42010=>30114, +42011=>30115, +42012=>30116, +42013=>30117, +42014=>30118, +42015=>30119, +42016=>30120, +42017=>30121, +42018=>30122, +42019=>30123, +42020=>30124, +42021=>30125, +42022=>30126, +42023=>30127, +42024=>30128, +42025=>30129, +42026=>30130, +42027=>30131, +42028=>30132, +42029=>30133, +42030=>30134, +42031=>30135, +42032=>30136, +42033=>30137, +42034=>30138, +42035=>30139, +42036=>30140, +42037=>30141, +42038=>30142, +42039=>30143, +42040=>30144, +42041=>30145, +42042=>30146, +42043=>30147, +42044=>30148, +42045=>30149, +42046=>30150, +42047=>30151, +42048=>30152, +42049=>30153, +42050=>30154, +42051=>30155, +42052=>30156, +42053=>30157, +42054=>30158, +42055=>30159, +42056=>30160, +42057=>30161, +42058=>30162, +42059=>30163, +42060=>30164, +42061=>30165, +42062=>30166, +42063=>30167, +42064=>30168, +42065=>30169, +42066=>30170, +42067=>30171, +42068=>30172, +42069=>30173, +42070=>30174, +42071=>30175, +42072=>30176, +42073=>30177, +42074=>30178, +42075=>30179, +42076=>30180, +42077=>30181, +42078=>30182, +42079=>30183, +42080=>30184, +42081=>30185, +42082=>30186, +42083=>30187, +42084=>30188, +42085=>30189, +42086=>30190, +42087=>30191, +42088=>30192, +42089=>30193, +42090=>30194, +42091=>30195, +42092=>30196, +42093=>30197, +42094=>30198, +42095=>30199, +42096=>30200, +42097=>30201, +42098=>30202, +42099=>30203, +42100=>30204, +42101=>30205, +42102=>30206, +42103=>30207, +42104=>30208, +42105=>30209, +42106=>30210, +42107=>30211, +42108=>30212, +42109=>30213, +42110=>30214, +42111=>30215, +42112=>30216, +42113=>30217, +42114=>30218, +42115=>30219, +42116=>30220, +42117=>30221, +42118=>30222, +42119=>30223, +42120=>30224, +42121=>30225, +42122=>30226, +42123=>30227, +42124=>30228, +42128=>30229, +42129=>30230, +42130=>30231, +42131=>30232, +42132=>30233, +42133=>30234, +42134=>30235, +42135=>30236, +42136=>30237, +42137=>30238, +42138=>30239, +42139=>30240, +42140=>30241, +42141=>30242, +42142=>30243, +42143=>30244, +42144=>30245, +42145=>30246, +42146=>30247, +42147=>30248, +42148=>30249, +42149=>30250, +42150=>30251, +42151=>30252, +42152=>30253, +42153=>30254, +42154=>30255, +42155=>30256, +42156=>30257, +42157=>30258, +42158=>30259, +42159=>30260, +42160=>30261, +42161=>30262, +42162=>30263, +42163=>30264, +42164=>30265, +42165=>30266, +42166=>30267, +42167=>30268, +42168=>30269, +42169=>30270, +42170=>30271, +42171=>30272, +42172=>30273, +42173=>30274, +42174=>30275, +42175=>30276, +42176=>30277, +42177=>30278, +42178=>30279, +42179=>30280, +42180=>30281, +42181=>30282, +42182=>30283, +); +?> diff --git a/include/tcpdf/fonts/uni2cid_aj16.php b/include/tcpdf/fonts/uni2cid_aj16.php new file mode 100644 index 00000000..24e2a06e --- /dev/null +++ b/include/tcpdf/fonts/uni2cid_aj16.php @@ -0,0 +1,15728 @@ +1, +32=>1, +33=>2, +34=>3, +35=>4, +36=>5, +37=>6, +38=>7, +39=>8, +40=>9, +41=>10, +42=>11, +43=>12, +44=>13, +8209=>14, +45=>14, +46=>15, +47=>16, +48=>17, +49=>18, +50=>19, +51=>20, +52=>21, +53=>22, +54=>23, +55=>24, +56=>25, +57=>26, +58=>27, +59=>28, +60=>29, +61=>30, +62=>31, +63=>32, +64=>33, +65=>34, +66=>35, +67=>36, +68=>37, +69=>38, +70=>39, +71=>40, +72=>41, +73=>42, +74=>43, +75=>44, +76=>45, +77=>46, +78=>47, +79=>48, +80=>49, +81=>50, +82=>51, +83=>52, +84=>53, +85=>54, +86=>55, +87=>56, +88=>57, +89=>58, +90=>59, +91=>60, +165=>61, +93=>62, +94=>63, +818=>64, +95=>64, +768=>65, +96=>65, +97=>66, +98=>67, +99=>68, +100=>69, +101=>70, +102=>71, +103=>72, +104=>73, +105=>74, +106=>75, +107=>76, +108=>77, +109=>78, +110=>79, +111=>80, +112=>81, +113=>82, +114=>83, +115=>84, +116=>85, +117=>86, +118=>87, +119=>88, +120=>89, +121=>90, +122=>91, +123=>92, +166=>93, +125=>94, +732=>95, +771=>95, +700=>96, +8217=>96, +92=>97, +699=>98, +8216=>98, +124=>99, +126=>100, +8764=>100, +161=>101, +162=>102, +163=>103, +8260=>104, +402=>105, +164=>107, +8220=>108, +171=>109, +8249=>110, +8250=>111, +64257=>112, +64258=>113, +8210=>114, +8211=>114, +183=>117, +8729=>117, +8226=>119, +8218=>120, +8222=>121, +8221=>122, +187=>123, +191=>126, +769=>127, +710=>128, +770=>128, +175=>129, +772=>129, +774=>130, +775=>131, +776=>132, +730=>133, +778=>133, +184=>134, +807=>134, +779=>135, +808=>136, +780=>137, +822=>138, +8212=>138, +198=>139, +170=>140, +321=>141, +216=>142, +338=>143, +186=>144, +230=>145, +305=>146, +322=>147, +248=>148, +339=>149, +223=>150, +173=>151, +169=>152, +172=>153, +174=>154, +178=>157, +179=>158, +181=>159, +185=>160, +188=>161, +189=>162, +190=>163, +192=>164, +193=>165, +194=>166, +195=>167, +196=>168, +197=>169, +199=>170, +200=>171, +201=>172, +202=>173, +203=>174, +204=>175, +205=>176, +206=>177, +207=>178, +208=>179, +209=>180, +210=>181, +211=>182, +212=>183, +213=>184, +214=>185, +217=>187, +218=>188, +219=>189, +220=>190, +221=>191, +222=>192, +224=>193, +225=>194, +226=>195, +227=>196, +228=>197, +229=>198, +231=>199, +232=>200, +233=>201, +234=>202, +235=>203, +236=>204, +237=>205, +238=>206, +239=>207, +240=>208, +241=>209, +242=>210, +243=>211, +244=>212, +245=>213, +246=>214, +249=>216, +250=>217, +251=>218, +252=>219, +253=>220, +254=>221, +255=>222, +352=>223, +376=>224, +381=>225, +773=>226, +8254=>226, +353=>227, +8482=>228, +382=>229, +8194=>231, +65512=>323, +65377=>327, +65378=>328, +65379=>329, +65380=>330, +65381=>331, +65382=>332, +65383=>333, +65384=>334, +65385=>335, +65386=>336, +65387=>337, +65388=>338, +65389=>339, +65390=>340, +65391=>341, +65392=>342, +65393=>343, +65394=>344, +65395=>345, +65396=>346, +65397=>347, +65398=>348, +65399=>349, +65400=>350, +65401=>351, +65402=>352, +65403=>353, +65404=>354, +65405=>355, +65406=>356, +65407=>357, +65408=>358, +65409=>359, +65410=>360, +65411=>361, +65412=>362, +65413=>363, +65414=>364, +65415=>365, +65416=>366, +65417=>367, +65418=>368, +65419=>369, +65420=>370, +65421=>371, +65422=>372, +65423=>373, +65424=>374, +65425=>375, +65426=>376, +65427=>377, +65428=>378, +65429=>379, +65430=>380, +65431=>381, +65432=>382, +65433=>383, +65434=>384, +65435=>385, +65436=>386, +65437=>387, +65438=>388, +65439=>389, +8195=>633, +12288=>633, +12289=>634, +12290=>635, +65292=>636, +65294=>637, +12539=>638, +65306=>639, +65307=>640, +65311=>641, +65281=>642, +12443=>643, +12444=>644, +180=>645, +65344=>646, +168=>647, +65342=>648, +65507=>649, +65343=>650, +12541=>651, +12542=>652, +12445=>653, +12446=>654, +12291=>655, +20189=>656, +12293=>657, +12294=>658, +12295=>659, +12540=>660, +8213=>661, +8208=>662, +65295=>663, +65340=>664, +12316=>665, +65374=>665, +8214=>666, +65372=>667, +8230=>668, +8229=>669, +65288=>674, +65289=>675, +12308=>676, +12309=>677, +65339=>678, +65341=>679, +65371=>680, +65373=>681, +12296=>682, +12297=>683, +12298=>684, +12299=>685, +12300=>686, +12301=>687, +12302=>688, +12303=>689, +12304=>690, +12305=>691, +65291=>692, +8722=>693, +65293=>693, +177=>694, +215=>695, +247=>696, +65309=>697, +8800=>698, +65308=>699, +65310=>700, +8806=>701, +8807=>702, +8734=>703, +8756=>704, +9794=>705, +9792=>706, +176=>707, +8242=>708, +8243=>709, +8451=>710, +65509=>711, +65284=>712, +65504=>713, +65505=>714, +65285=>715, +65283=>716, +65286=>717, +65290=>718, +65312=>719, +167=>720, +9734=>721, +9733=>722, +9675=>723, +9679=>724, +9678=>725, +9671=>726, +9670=>727, +9633=>728, +9632=>729, +9651=>730, +9650=>731, +9661=>732, +9660=>733, +8251=>734, +12306=>735, +8594=>736, +8592=>737, +8593=>738, +8595=>739, +12307=>740, +8712=>741, +8715=>742, +8838=>743, +8839=>744, +8834=>745, +8835=>746, +8746=>747, +8745=>748, +8743=>749, +8744=>750, +65506=>751, +8658=>752, +8660=>753, +8704=>754, +8707=>755, +8736=>756, +8869=>757, +8978=>758, +8706=>759, +8711=>760, +8801=>761, +8786=>762, +8810=>763, +8811=>764, +8730=>765, +8765=>766, +8733=>767, +8757=>768, +8747=>769, +8748=>770, +8491=>771, +8240=>772, +9839=>773, +9837=>774, +9834=>775, +8224=>776, +8225=>777, +182=>778, +9711=>779, +65296=>780, +65297=>781, +65298=>782, +65299=>783, +65300=>784, +65301=>785, +65302=>786, +65303=>787, +65304=>788, +65305=>789, +65313=>790, +65314=>791, +65315=>792, +65316=>793, +65317=>794, +65318=>795, +65319=>796, +65320=>797, +65321=>798, +65322=>799, +65323=>800, +65324=>801, +65325=>802, +65326=>803, +65327=>804, +65328=>805, +65329=>806, +65330=>807, +65331=>808, +65332=>809, +65333=>810, +65334=>811, +65335=>812, +65336=>813, +65337=>814, +65338=>815, +65345=>816, +65346=>817, +65347=>818, +65348=>819, +65349=>820, +65350=>821, +65351=>822, +65352=>823, +65353=>824, +65354=>825, +65355=>826, +65356=>827, +65357=>828, +65358=>829, +65359=>830, +65360=>831, +65361=>832, +65362=>833, +65363=>834, +65364=>835, +65365=>836, +65366=>837, +65367=>838, +65368=>839, +65369=>840, +65370=>841, +12353=>842, +12354=>843, +12355=>844, +12356=>845, +12357=>846, +12358=>847, +12359=>848, +12360=>849, +12361=>850, +12362=>851, +12363=>852, +12364=>853, +12365=>854, +12366=>855, +12367=>856, +12368=>857, +12369=>858, +12370=>859, +12371=>860, +12372=>861, +12373=>862, +12374=>863, +12375=>864, +12376=>865, +12377=>866, +12378=>867, +12379=>868, +12380=>869, +12381=>870, +12382=>871, +12383=>872, +12384=>873, +12385=>874, +12386=>875, +12387=>876, +12388=>877, +12389=>878, +12390=>879, +12391=>880, +12392=>881, +12393=>882, +12394=>883, +12395=>884, +12396=>885, +12397=>886, +12398=>887, +12399=>888, +12400=>889, +12401=>890, +12402=>891, +12403=>892, +12404=>893, +12405=>894, +12406=>895, +12407=>896, +12408=>897, +12409=>898, +12410=>899, +12411=>900, +12412=>901, +12413=>902, +12414=>903, +12415=>904, +12416=>905, +12417=>906, +12418=>907, +12419=>908, +12420=>909, +12421=>910, +12422=>911, +12423=>912, +12424=>913, +12425=>914, +12426=>915, +12427=>916, +12428=>917, +12429=>918, +12430=>919, +12431=>920, +12432=>921, +12433=>922, +12434=>923, +12435=>924, +12449=>925, +12450=>926, +12451=>927, +12452=>928, +12453=>929, +12454=>930, +12455=>931, +12456=>932, +12457=>933, +12458=>934, +12459=>935, +12460=>936, +12461=>937, +12462=>938, +12463=>939, +12464=>940, +12465=>941, +12466=>942, +12467=>943, +12468=>944, +12469=>945, +12470=>946, +12471=>947, +12472=>948, +12473=>949, +12474=>950, +12475=>951, +12476=>952, +12477=>953, +12478=>954, +12479=>955, +12480=>956, +12481=>957, +12482=>958, +12483=>959, +12484=>960, +12485=>961, +12486=>962, +12487=>963, +12488=>964, +12489=>965, +12490=>966, +12491=>967, +12492=>968, +12493=>969, +12494=>970, +12495=>971, +12496=>972, +12497=>973, +12498=>974, +12499=>975, +12500=>976, +12501=>977, +12502=>978, +12503=>979, +12504=>980, +12505=>981, +12506=>982, +12507=>983, +12508=>984, +12509=>985, +12510=>986, +12511=>987, +12512=>988, +12513=>989, +12514=>990, +12515=>991, +12516=>992, +12517=>993, +12518=>994, +12519=>995, +12520=>996, +12521=>997, +12522=>998, +12523=>999, +12524=>1000, +12525=>1001, +12526=>1002, +12527=>1003, +12528=>1004, +12529=>1005, +12530=>1006, +12531=>1007, +12532=>1008, +12533=>1009, +12534=>1010, +913=>1011, +914=>1012, +915=>1013, +916=>1014, +917=>1015, +918=>1016, +919=>1017, +920=>1018, +921=>1019, +922=>1020, +923=>1021, +924=>1022, +925=>1023, +926=>1024, +927=>1025, +928=>1026, +929=>1027, +931=>1028, +932=>1029, +933=>1030, +934=>1031, +935=>1032, +936=>1033, +937=>1034, +945=>1035, +946=>1036, +947=>1037, +948=>1038, +949=>1039, +950=>1040, +951=>1041, +952=>1042, +953=>1043, +954=>1044, +955=>1045, +956=>1046, +957=>1047, +958=>1048, +959=>1049, +960=>1050, +961=>1051, +963=>1052, +964=>1053, +965=>1054, +966=>1055, +967=>1056, +968=>1057, +969=>1058, +1040=>1059, +1041=>1060, +1042=>1061, +1043=>1062, +1044=>1063, +1045=>1064, +1025=>1065, +1046=>1066, +1047=>1067, +1048=>1068, +1049=>1069, +1050=>1070, +1051=>1071, +1052=>1072, +1053=>1073, +1054=>1074, +1055=>1075, +1056=>1076, +1057=>1077, +1058=>1078, +1059=>1079, +1060=>1080, +1061=>1081, +1062=>1082, +1063=>1083, +1064=>1084, +1065=>1085, +1066=>1086, +1067=>1087, +1068=>1088, +1069=>1089, +1070=>1090, +1071=>1091, +1072=>1092, +1073=>1093, +1074=>1094, +1075=>1095, +1076=>1096, +1077=>1097, +1105=>1098, +1078=>1099, +1079=>1100, +1080=>1101, +1081=>1102, +1082=>1103, +1083=>1104, +1084=>1105, +1085=>1106, +1086=>1107, +1087=>1108, +1088=>1109, +1089=>1110, +1090=>1111, +1091=>1112, +1092=>1113, +1093=>1114, +1094=>1115, +1095=>1116, +1096=>1117, +1097=>1118, +1098=>1119, +1099=>1120, +1100=>1121, +1101=>1122, +1102=>1123, +1103=>1124, +20124=>1125, +21782=>1126, +23043=>1127, +38463=>1128, +21696=>1129, +24859=>1130, +25384=>1131, +23030=>1132, +36898=>1133, +33909=>1134, +33564=>1135, +31312=>1136, +24746=>1137, +25569=>1138, +28197=>1139, +26093=>1140, +33894=>1141, +33446=>1142, +39925=>1143, +26771=>1144, +22311=>1145, +26017=>1146, +25201=>1147, +23451=>1148, +22992=>1149, +34427=>1150, +39156=>1151, +32098=>1152, +32190=>1153, +39822=>1154, +25110=>1155, +31903=>1156, +34999=>1157, +23433=>1158, +24245=>1159, +25353=>1160, +26263=>1161, +26696=>1162, +38343=>1163, +38797=>1164, +26447=>1165, +20197=>1166, +20234=>1167, +20301=>1168, +20381=>1169, +20553=>1170, +22258=>1171, +22839=>1172, +22996=>1173, +23041=>1174, +23561=>1175, +24799=>1176, +24847=>1177, +24944=>1178, +26131=>1179, +26885=>1180, +28858=>1181, +30031=>1182, +30064=>1183, +31227=>1184, +32173=>1185, +32239=>1186, +32963=>1187, +33806=>1188, +12176=>1189, +34915=>1189, +35586=>1190, +36949=>1191, +36986=>1192, +21307=>1193, +20117=>1194, +20133=>1195, +22495=>1196, +32946=>1197, +37057=>1198, +30959=>1199, +12032=>1200, +19968=>1200, +22769=>1201, +28322=>1202, +36920=>1203, +31282=>1204, +33576=>1205, +33419=>1206, +39983=>1207, +20801=>1208, +21360=>1209, +21693=>1210, +21729=>1211, +22240=>1212, +23035=>1213, +24341=>1214, +39154=>1215, +28139=>1216, +32996=>1217, +34093=>1218, +38498=>1219, +38512=>1220, +38560=>1221, +38907=>1222, +21515=>1223, +21491=>1224, +23431=>1225, +28879=>1226, +12155=>1227, +32701=>1227, +36802=>1228, +12204=>1229, +38632=>1229, +21359=>1230, +40284=>1231, +31418=>1232, +19985=>1233, +30867=>1234, +12165=>1235, +33276=>1235, +28198=>1236, +22040=>1237, +21764=>1238, +27421=>1239, +34074=>1240, +39995=>1241, +23013=>1242, +21417=>1243, +28006=>1244, +12128=>1245, +29916=>1245, +38287=>1246, +22082=>1247, +20113=>1248, +36939=>1249, +38642=>1250, +33615=>1251, +39180=>1252, +21473=>1253, +21942=>1254, +23344=>1255, +24433=>1256, +26144=>1257, +26355=>1258, +26628=>1259, +27704=>1260, +27891=>1261, +27945=>1262, +29787=>1263, +30408=>1264, +31310=>1265, +38964=>1266, +33521=>1267, +34907=>1268, +35424=>1269, +37613=>1270, +28082=>1271, +30123=>1272, +30410=>1273, +39365=>1274, +24742=>1275, +35585=>1276, +36234=>1277, +38322=>1278, +27022=>1279, +21421=>1280, +20870=>1281, +22290=>1282, +22576=>1283, +22852=>1284, +23476=>1285, +24310=>1286, +24616=>1287, +25513=>1288, +25588=>1289, +27839=>1290, +28436=>1291, +28814=>1292, +28948=>1293, +29017=>1294, +29141=>1295, +29503=>1296, +32257=>1297, +33398=>1298, +33489=>1299, +34199=>1300, +36960=>1301, +37467=>1302, +40219=>1303, +22633=>1304, +26044=>1305, +27738=>1306, +29989=>1307, +20985=>1308, +22830=>1309, +22885=>1310, +24448=>1311, +24540=>1312, +25276=>1313, +26106=>1314, +27178=>1315, +27431=>1316, +27572=>1317, +29579=>1318, +32705=>1319, +35158=>1320, +40236=>1321, +40206=>1322, +12009=>1323, +40644=>1323, +23713=>1324, +27798=>1325, +33659=>1326, +20740=>1327, +23627=>1328, +25014=>1329, +33222=>1330, +26742=>1331, +29281=>1332, +12036=>1333, +20057=>1333, +20474=>1334, +21368=>1335, +24681=>1336, +28201=>1337, +31311=>1338, +12211=>1339, +38899=>1339, +19979=>1340, +21270=>1341, +20206=>1342, +20309=>1343, +20285=>1344, +20385=>1345, +20339=>1346, +21152=>1347, +21487=>1348, +22025=>1349, +22799=>1350, +23233=>1351, +23478=>1352, +23521=>1353, +31185=>1354, +26247=>1355, +26524=>1356, +26550=>1357, +27468=>1358, +27827=>1359, +12117=>1360, +28779=>1360, +29634=>1361, +31117=>1362, +12146=>1363, +31166=>1363, +31292=>1364, +31623=>1365, +33457=>1366, +33499=>1367, +33540=>1368, +33655=>1369, +33775=>1370, +33747=>1371, +34662=>1372, +35506=>1373, +22057=>1374, +36008=>1375, +36838=>1376, +36942=>1377, +38686=>1378, +34442=>1379, +20420=>1380, +23784=>1381, +25105=>1382, +12123=>1383, +29273=>1383, +30011=>1384, +33253=>1385, +33469=>1386, +34558=>1387, +36032=>1388, +38597=>1389, +39187=>1390, +39381=>1391, +20171=>1392, +20250=>1393, +35299=>1394, +22238=>1395, +22602=>1396, +22730=>1397, +24315=>1398, +24555=>1399, +24618=>1400, +24724=>1401, +24674=>1402, +25040=>1403, +25106=>1404, +25296=>1405, +25913=>1406, +39745=>1407, +26214=>1408, +26800=>1409, +28023=>1410, +28784=>1411, +30028=>1412, +30342=>1413, +32117=>1414, +33445=>1415, +34809=>1416, +38283=>1417, +38542=>1418, +12185=>1419, +35997=>1419, +20977=>1420, +21182=>1421, +22806=>1422, +21683=>1423, +23475=>1424, +23830=>1425, +24936=>1426, +27010=>1427, +28079=>1428, +30861=>1429, +33995=>1430, +34903=>1431, +35442=>1432, +37799=>1433, +39608=>1434, +28012=>1435, +39336=>1436, +34521=>1437, +22435=>1438, +26623=>1439, +34510=>1440, +37390=>1441, +21123=>1442, +22151=>1443, +21508=>1444, +24275=>1445, +25313=>1446, +25785=>1447, +26684=>1448, +26680=>1449, +27579=>1450, +29554=>1451, +30906=>1452, +31339=>1453, +35226=>1454, +12179=>1455, +35282=>1455, +36203=>1456, +36611=>1457, +37101=>1458, +38307=>1459, +38548=>1460, +12208=>1461, +38761=>1461, +23398=>1462, +23731=>1463, +27005=>1464, +38989=>1465, +38990=>1466, +25499=>1467, +31520=>1468, +27179=>1469, +27263=>1470, +26806=>1471, +39949=>1472, +28511=>1473, +21106=>1474, +21917=>1475, +24688=>1476, +25324=>1477, +27963=>1478, +28167=>1479, +28369=>1480, +33883=>1481, +35088=>1482, +36676=>1483, +19988=>1484, +39993=>1485, +21494=>1486, +26907=>1487, +27194=>1488, +38788=>1489, +26666=>1490, +20828=>1491, +31427=>1492, +33970=>1493, +37340=>1494, +37772=>1495, +22107=>1496, +40232=>1497, +26658=>1498, +33541=>1499, +33841=>1500, +31909=>1501, +21000=>1502, +33477=>1503, +12129=>1504, +29926=>1504, +20094=>1505, +20355=>1506, +20896=>1507, +23506=>1508, +21002=>1509, +21208=>1510, +21223=>1511, +24059=>1512, +21914=>1513, +22570=>1514, +23014=>1515, +23436=>1516, +23448=>1517, +23515=>1518, +12082=>1519, +24178=>1519, +24185=>1520, +24739=>1521, +24863=>1522, +24931=>1523, +25022=>1524, +25563=>1525, +25954=>1526, +26577=>1527, +26707=>1528, +26874=>1529, +27454=>1530, +27475=>1531, +27735=>1532, +28450=>1533, +28567=>1534, +28485=>1535, +29872=>1536, +12130=>1537, +29976=>1537, +30435=>1538, +30475=>1539, +31487=>1540, +31649=>1541, +31777=>1542, +32233=>1543, +12152=>1544, +32566=>1544, +32752=>1545, +32925=>1546, +33382=>1547, +33694=>1548, +35251=>1549, +35532=>1550, +36011=>1551, +36996=>1552, +37969=>1553, +38291=>1554, +38289=>1555, +38306=>1556, +38501=>1557, +38867=>1558, +39208=>1559, +33304=>1560, +20024=>1561, +21547=>1562, +23736=>1563, +24012=>1564, +29609=>1565, +30284=>1566, +30524=>1567, +23721=>1568, +32747=>1569, +36107=>1570, +38593=>1571, +38929=>1572, +38996=>1573, +39000=>1574, +20225=>1575, +20238=>1576, +21361=>1577, +21916=>1578, +22120=>1579, +22522=>1580, +22855=>1581, +23305=>1582, +23492=>1583, +23696=>1584, +24076=>1585, +24190=>1586, +24524=>1587, +25582=>1588, +26426=>1589, +26071=>1590, +26082=>1591, +26399=>1592, +26827=>1593, +26820=>1594, +27231=>1595, +24112=>1596, +27589=>1597, +27671=>1598, +27773=>1599, +30079=>1600, +31048=>1601, +23395=>1602, +31232=>1603, +32000=>1604, +24509=>1605, +35215=>1606, +35352=>1607, +36020=>1608, +36215=>1609, +36556=>1610, +36637=>1611, +39138=>1612, +39438=>1613, +12004=>1614, +12225=>1614, +39740=>1614, +12018=>1615, +20096=>1615, +20605=>1616, +20736=>1617, +22931=>1618, +23452=>1619, +25135=>1620, +25216=>1621, +25836=>1622, +27450=>1623, +29344=>1624, +30097=>1625, +31047=>1626, +32681=>1627, +34811=>1628, +35516=>1629, +35696=>1630, +25516=>1631, +33738=>1632, +38816=>1633, +21513=>1634, +21507=>1635, +21931=>1636, +26708=>1637, +27224=>1638, +35440=>1639, +30759=>1640, +26485=>1641, +12233=>1642, +40653=>1642, +21364=>1643, +23458=>1644, +33050=>1645, +34384=>1646, +36870=>1647, +19992=>1648, +20037=>1649, +20167=>1650, +20241=>1651, +21450=>1652, +21560=>1653, +23470=>1654, +12088=>1655, +24339=>1655, +24613=>1656, +25937=>1657, +26429=>1658, +27714=>1659, +27762=>1660, +27875=>1661, +28792=>1662, +29699=>1663, +31350=>1664, +31406=>1665, +31496=>1666, +32026=>1667, +31998=>1668, +32102=>1669, +26087=>1670, +12124=>1671, +29275=>1671, +21435=>1672, +23621=>1673, +24040=>1674, +25298=>1675, +25312=>1676, +25369=>1677, +28192=>1678, +34394=>1679, +35377=>1680, +36317=>1681, +37624=>1682, +28417=>1683, +31142=>1684, +12226=>1685, +39770=>1685, +20136=>1686, +20139=>1687, +20140=>1688, +20379=>1689, +20384=>1690, +20689=>1691, +20807=>1692, +31478=>1693, +20849=>1694, +20982=>1695, +21332=>1696, +21281=>1697, +21375=>1698, +21483=>1699, +21932=>1700, +22659=>1701, +23777=>1702, +24375=>1703, +24394=>1704, +24623=>1705, +24656=>1706, +24685=>1707, +25375=>1708, +25945=>1709, +27211=>1710, +27841=>1711, +29378=>1712, +29421=>1713, +30703=>1714, +33016=>1715, +33029=>1716, +33288=>1717, +34126=>1718, +37111=>1719, +37857=>1720, +38911=>1721, +39255=>1722, +39514=>1723, +20208=>1724, +20957=>1725, +23597=>1726, +26241=>1727, +26989=>1728, +23616=>1729, +26354=>1730, +26997=>1731, +12127=>1732, +29577=>1732, +26704=>1733, +31873=>1734, +20677=>1735, +21220=>1736, +22343=>1737, +12081=>1738, +24062=>1738, +37670=>1739, +12100=>1740, +26020=>1740, +27427=>1741, +27453=>1742, +29748=>1743, +31105=>1744, +31165=>1745, +31563=>1746, +32202=>1747, +33465=>1748, +33740=>1749, +34943=>1750, +35167=>1751, +35641=>1752, +36817=>1753, +12198=>1754, +37329=>1754, +21535=>1755, +37504=>1756, +20061=>1757, +20534=>1758, +21477=>1759, +21306=>1760, +29399=>1761, +29590=>1762, +30697=>1763, +33510=>1764, +36527=>1765, +39366=>1766, +39368=>1767, +39378=>1768, +20855=>1769, +24858=>1770, +34398=>1771, +21936=>1772, +31354=>1773, +20598=>1774, +23507=>1775, +36935=>1776, +38533=>1777, +20018=>1778, +27355=>1779, +37351=>1780, +23633=>1781, +23624=>1782, +25496=>1783, +31391=>1784, +27795=>1785, +38772=>1786, +36705=>1787, +31402=>1788, +29066=>1789, +38536=>1790, +31874=>1791, +26647=>1792, +32368=>1793, +26705=>1794, +37740=>1795, +21234=>1796, +21531=>1797, +34219=>1798, +35347=>1799, +32676=>1800, +36557=>1801, +37089=>1802, +21350=>1803, +34952=>1804, +31041=>1805, +20418=>1806, +20670=>1807, +21009=>1808, +20804=>1809, +21843=>1810, +22317=>1811, +29674=>1812, +22411=>1813, +22865=>1814, +24418=>1815, +24452=>1816, +24693=>1817, +24950=>1818, +24935=>1819, +25001=>1820, +25522=>1821, +25658=>1822, +25964=>1823, +26223=>1824, +26690=>1825, +28179=>1826, +30054=>1827, +31293=>1828, +31995=>1829, +32076=>1830, +32153=>1831, +32331=>1832, +32619=>1833, +33550=>1834, +33610=>1835, +34509=>1836, +35336=>1837, +35427=>1838, +35686=>1839, +36605=>1840, +38938=>1841, +40335=>1842, +33464=>1843, +36814=>1844, +39912=>1845, +21127=>1846, +25119=>1847, +25731=>1848, +28608=>1849, +38553=>1850, +26689=>1851, +20625=>1852, +12107=>1853, +27424=>1853, +27770=>1854, +28500=>1855, +12147=>1856, +31348=>1856, +32080=>1857, +12174=>1858, +34880=>1858, +35363=>1859, +12105=>1860, +26376=>1860, +20214=>1861, +20537=>1862, +20518=>1863, +20581=>1864, +20860=>1865, +21048=>1866, +21091=>1867, +21927=>1868, +22287=>1869, +22533=>1870, +23244=>1871, +24314=>1872, +25010=>1873, +25080=>1874, +25331=>1875, +25458=>1876, +26908=>1877, +27177=>1878, +29309=>1879, +12125=>1880, +29356=>1880, +29486=>1881, +30740=>1882, +30831=>1883, +32121=>1884, +30476=>1885, +32937=>1886, +12178=>1887, +35211=>1887, +35609=>1888, +36066=>1889, +36562=>1890, +36963=>1891, +37749=>1892, +38522=>1893, +38997=>1894, +39443=>1895, +40568=>1896, +20803=>1897, +21407=>1898, +21427=>1899, +24187=>1900, +24358=>1901, +28187=>1902, +28304=>1903, +12126=>1904, +29572=>1904, +29694=>1905, +32067=>1906, +33335=>1907, +12180=>1908, +35328=>1908, +35578=>1909, +38480=>1910, +20046=>1911, +20491=>1912, +21476=>1913, +21628=>1914, +22266=>1915, +22993=>1916, +23396=>1917, +12080=>1918, +24049=>1918, +24235=>1919, +24359=>1920, +12094=>1921, +25144=>1921, +25925=>1922, +26543=>1923, +28246=>1924, +29392=>1925, +31946=>1926, +34996=>1927, +32929=>1928, +32993=>1929, +33776=>1930, +11969=>1931, +34382=>1931, +35463=>1932, +36328=>1933, +37431=>1934, +38599=>1935, +39015=>1936, +12238=>1937, +40723=>1937, +20116=>1938, +20114=>1939, +20237=>1940, +21320=>1941, +21577=>1942, +21566=>1943, +23087=>1944, +24460=>1945, +24481=>1946, +24735=>1947, +26791=>1948, +27278=>1949, +29786=>1950, +30849=>1951, +35486=>1952, +35492=>1953, +35703=>1954, +37264=>1955, +20062=>1956, +39881=>1957, +20132=>1958, +20348=>1959, +20399=>1960, +20505=>1961, +20502=>1962, +20809=>1963, +20844=>1964, +21151=>1965, +21177=>1966, +21246=>1967, +21402=>1968, +12061=>1969, +21475=>1969, +21521=>1970, +21518=>1971, +21897=>1972, +22353=>1973, +22434=>1974, +22909=>1975, +23380=>1976, +23389=>1977, +23439=>1978, +12079=>1979, +24037=>1979, +24039=>1980, +24055=>1981, +24184=>1982, +24195=>1983, +24218=>1984, +24247=>1985, +24344=>1986, +24658=>1987, +24908=>1988, +25239=>1989, +25304=>1990, +25511=>1991, +25915=>1992, +26114=>1993, +26179=>1994, +26356=>1995, +26477=>1996, +26657=>1997, +26775=>1998, +27083=>1999, +27743=>2000, +27946=>2001, +28009=>2002, +28207=>2003, +28317=>2004, +30002=>2005, +30343=>2006, +30828=>2007, +31295=>2008, +31968=>2009, +32005=>2010, +32024=>2011, +32094=>2012, +32177=>2013, +32789=>2014, +32771=>2015, +32943=>2016, +32945=>2017, +33108=>2018, +33167=>2019, +33322=>2020, +33618=>2021, +12175=>2022, +34892=>2022, +34913=>2023, +35611=>2024, +36002=>2025, +36092=>2026, +37066=>2027, +37237=>2028, +37489=>2029, +30783=>2030, +37628=>2031, +38308=>2032, +38477=>2033, +38917=>2034, +12217=>2035, +39321=>2035, +12220=>2036, +39640=>2036, +40251=>2037, +21083=>2038, +21163=>2039, +21495=>2040, +21512=>2041, +22741=>2042, +25335=>2043, +28640=>2044, +35946=>2045, +36703=>2046, +40633=>2047, +20811=>2048, +21051=>2049, +21578=>2050, +22269=>2051, +31296=>2052, +37239=>2053, +40288=>2054, +12234=>2055, +40658=>2055, +29508=>2056, +28425=>2057, +33136=>2058, +29969=>2059, +24573=>2060, +24794=>2061, +12219=>2062, +39592=>2062, +29403=>2063, +36796=>2064, +27492=>2065, +38915=>2066, +20170=>2067, +22256=>2068, +22372=>2069, +22718=>2070, +23130=>2071, +24680=>2072, +25031=>2073, +26127=>2074, +26118=>2075, +26681=>2076, +26801=>2077, +28151=>2078, +30165=>2079, +32058=>2080, +12169=>2081, +33390=>2081, +39746=>2082, +20123=>2083, +20304=>2084, +21449=>2085, +21766=>2086, +23919=>2087, +24038=>2088, +24046=>2089, +26619=>2090, +27801=>2091, +29811=>2092, +30722=>2093, +35408=>2094, +37782=>2095, +35039=>2096, +22352=>2097, +24231=>2098, +25387=>2099, +20661=>2100, +20652=>2101, +20877=>2102, +26368=>2103, +21705=>2104, +22622=>2105, +22971=>2106, +23472=>2107, +24425=>2108, +25165=>2109, +25505=>2110, +26685=>2111, +27507=>2112, +28168=>2113, +28797=>2114, +37319=>2115, +29312=>2116, +30741=>2117, +30758=>2118, +31085=>2119, +25998=>2120, +32048=>2121, +33756=>2122, +35009=>2123, +36617=>2124, +38555=>2125, +21092=>2126, +22312=>2127, +26448=>2128, +32618=>2129, +36001=>2130, +20916=>2131, +22338=>2132, +38442=>2133, +22586=>2134, +27018=>2135, +32948=>2136, +21682=>2137, +23822=>2138, +22524=>2139, +30869=>2140, +40442=>2141, +20316=>2142, +21066=>2143, +21643=>2144, +25662=>2145, +26152=>2146, +26388=>2147, +26613=>2148, +31364=>2149, +31574=>2150, +32034=>2151, +37679=>2152, +26716=>2153, +39853=>2154, +31545=>2155, +21273=>2156, +20874=>2157, +21047=>2158, +23519=>2159, +25334=>2160, +25774=>2161, +25830=>2162, +26413=>2163, +27578=>2164, +34217=>2165, +38609=>2166, +30352=>2167, +39894=>2168, +25420=>2169, +37638=>2170, +39851=>2171, +12139=>2172, +30399=>2172, +26194=>2173, +19977=>2174, +20632=>2175, +21442=>2176, +12077=>2177, +23665=>2177, +24808=>2178, +25746=>2179, +25955=>2180, +26719=>2181, +29158=>2182, +29642=>2183, +29987=>2184, +31639=>2185, +32386=>2186, +34453=>2187, +35715=>2188, +36059=>2189, +37240=>2190, +39184=>2191, +26028=>2192, +26283=>2193, +27531=>2194, +20181=>2195, +20180=>2196, +20282=>2197, +20351=>2198, +21050=>2199, +21496=>2200, +21490=>2201, +21987=>2202, +22235=>2203, +12064=>2204, +22763=>2204, +22987=>2205, +22985=>2206, +23039=>2207, +12070=>2208, +23376=>2208, +23629=>2209, +24066=>2210, +24107=>2211, +24535=>2212, +24605=>2213, +25351=>2214, +12096=>2215, +25903=>2215, +23388=>2216, +26031=>2217, +26045=>2218, +26088=>2219, +26525=>2220, +12108=>2221, +27490=>2221, +27515=>2222, +12114=>2223, +27663=>2223, +29509=>2224, +31049=>2225, +31169=>2226, +12151=>2227, +31992=>2227, +32025=>2228, +32043=>2229, +32930=>2230, +33026=>2231, +12164=>2232, +33267=>2232, +35222=>2233, +35422=>2234, +35433=>2235, +35430=>2236, +35468=>2237, +35566=>2238, +36039=>2239, +36060=>2240, +38604=>2241, +39164=>2242, +12013=>2243, +27503=>2243, +20107=>2244, +20284=>2245, +20365=>2246, +20816=>2247, +23383=>2248, +23546=>2249, +24904=>2250, +25345=>2251, +26178=>2252, +27425=>2253, +28363=>2254, +27835=>2255, +29246=>2256, +29885=>2257, +30164=>2258, +30913=>2259, +12144=>2260, +31034=>2260, +12157=>2261, +32780=>2261, +12159=>2262, +32819=>2262, +12163=>2263, +33258=>2263, +33940=>2264, +36766=>2265, +27728=>2266, +12229=>2267, +40575=>2267, +24335=>2268, +35672=>2269, +40235=>2270, +31482=>2271, +36600=>2272, +23437=>2273, +38635=>2274, +19971=>2275, +21489=>2276, +22519=>2277, +22833=>2278, +23241=>2279, +23460=>2280, +24713=>2281, +28287=>2282, +28422=>2283, +30142=>2284, +36074=>2285, +23455=>2286, +34048=>2287, +31712=>2288, +20594=>2289, +26612=>2290, +33437=>2291, +23649=>2292, +34122=>2293, +32286=>2294, +33294=>2295, +20889=>2296, +23556=>2297, +25448=>2298, +36198=>2299, +26012=>2300, +29038=>2301, +31038=>2302, +32023=>2303, +32773=>2304, +35613=>2305, +12190=>2306, +36554=>2306, +36974=>2307, +34503=>2308, +37034=>2309, +20511=>2310, +21242=>2311, +23610=>2312, +26451=>2313, +28796=>2314, +29237=>2315, +37196=>2316, +37320=>2317, +37675=>2318, +33509=>2319, +23490=>2320, +24369=>2321, +24825=>2322, +20027=>2323, +21462=>2324, +23432=>2325, +12095=>2326, +25163=>2326, +26417=>2327, +27530=>2328, +29417=>2329, +29664=>2330, +31278=>2331, +33131=>2332, +36259=>2333, +37202=>2334, +12216=>2335, +39318=>2335, +20754=>2336, +21463=>2337, +21610=>2338, +23551=>2339, +25480=>2340, +27193=>2341, +32172=>2342, +38656=>2343, +22234=>2344, +21454=>2345, +21608=>2346, +23447=>2347, +23601=>2348, +24030=>2349, +20462=>2350, +24833=>2351, +25342=>2352, +27954=>2353, +31168=>2354, +31179=>2355, +32066=>2356, +32333=>2357, +32722=>2358, +33261=>2359, +12168=>2360, +33311=>2360, +33936=>2361, +34886=>2362, +35186=>2363, +35728=>2364, +36468=>2365, +36655=>2366, +36913=>2367, +37195=>2368, +37228=>2369, +38598=>2370, +37276=>2371, +20160=>2372, +20303=>2373, +20805=>2374, +12055=>2375, +21313=>2375, +24467=>2376, +25102=>2377, +26580=>2378, +27713=>2379, +28171=>2380, +29539=>2381, +32294=>2382, +37325=>2383, +37507=>2384, +21460=>2385, +22809=>2386, +23487=>2387, +28113=>2388, +31069=>2389, +32302=>2390, +31899=>2391, +22654=>2392, +29087=>2393, +20986=>2394, +34899=>2395, +36848=>2396, +20426=>2397, +23803=>2398, +26149=>2399, +30636=>2400, +31459=>2401, +33308=>2402, +39423=>2403, +20934=>2404, +24490=>2405, +26092=>2406, +26991=>2407, +27529=>2408, +28147=>2409, +28310=>2410, +28516=>2411, +30462=>2412, +32020=>2413, +24033=>2414, +36981=>2415, +37255=>2416, +38918=>2417, +20966=>2418, +21021=>2419, +25152=>2420, +26257=>2421, +26329=>2422, +28186=>2423, +24246=>2424, +32210=>2425, +32626=>2426, +26360=>2427, +34223=>2428, +34295=>2429, +35576=>2430, +21161=>2431, +21465=>2432, +12069=>2433, +22899=>2433, +24207=>2434, +24464=>2435, +24661=>2436, +37604=>2437, +38500=>2438, +20663=>2439, +20767=>2440, +21213=>2441, +21280=>2442, +21319=>2443, +21484=>2444, +21736=>2445, +21830=>2446, +21809=>2447, +22039=>2448, +22888=>2449, +22974=>2450, +23100=>2451, +23477=>2452, +23558=>2453, +12073=>2454, +23567=>2454, +23569=>2455, +23578=>2456, +24196=>2457, +24202=>2458, +24288=>2459, +24432=>2460, +25215=>2461, +25220=>2462, +25307=>2463, +25484=>2464, +25463=>2465, +26119=>2466, +26124=>2467, +26157=>2468, +26230=>2469, +26494=>2470, +26786=>2471, +27167=>2472, +27189=>2473, +27836=>2474, +28040=>2475, +28169=>2476, +28248=>2477, +28988=>2478, +28966=>2479, +29031=>2480, +30151=>2481, +30465=>2482, +30813=>2483, +30977=>2484, +31077=>2485, +31216=>2486, +31456=>2487, +31505=>2488, +31911=>2489, +32057=>2490, +32918=>2491, +33750=>2492, +33931=>2493, +34121=>2494, +34909=>2495, +35059=>2496, +35359=>2497, +35388=>2498, +35412=>2499, +35443=>2500, +35937=>2501, +36062=>2502, +37284=>2503, +37478=>2504, +37758=>2505, +37912=>2506, +38556=>2507, +38808=>2508, +19978=>2509, +19976=>2510, +19998=>2511, +20055=>2512, +20887=>2513, +21104=>2514, +22478=>2515, +22580=>2516, +22732=>2517, +23330=>2518, +24120=>2519, +24773=>2520, +25854=>2521, +26465=>2522, +26454=>2523, +27972=>2524, +29366=>2525, +30067=>2526, +31331=>2527, +33976=>2528, +35698=>2529, +37304=>2530, +37664=>2531, +22065=>2532, +22516=>2533, +39166=>2534, +25325=>2535, +26893=>2536, +27542=>2537, +29165=>2538, +32340=>2539, +32887=>2540, +12170=>2541, +33394=>2541, +35302=>2542, +12215=>2543, +39135=>2543, +34645=>2544, +36785=>2545, +23611=>2546, +20280=>2547, +20449=>2548, +20405=>2549, +21767=>2550, +23072=>2551, +23517=>2552, +23529=>2553, +12092=>2554, +24515=>2554, +24910=>2555, +25391=>2556, +26032=>2557, +26187=>2558, +26862=>2559, +27035=>2560, +28024=>2561, +28145=>2562, +30003=>2563, +30137=>2564, +30495=>2565, +31070=>2566, +31206=>2567, +32051=>2568, +12162=>2569, +33251=>2569, +33455=>2570, +34218=>2571, +35242=>2572, +35386=>2573, +12189=>2574, +36523=>2574, +12191=>2575, +36763=>2575, +36914=>2576, +37341=>2577, +38663=>2578, +12040=>2579, +20154=>2579, +20161=>2580, +20995=>2581, +22645=>2582, +22764=>2583, +23563=>2584, +29978=>2585, +23613=>2586, +33102=>2587, +35338=>2588, +36805=>2589, +38499=>2590, +38765=>2591, +31525=>2592, +35535=>2593, +38920=>2594, +37218=>2595, +22259=>2596, +21416=>2597, +36887=>2598, +21561=>2599, +22402=>2600, +24101=>2601, +25512=>2602, +12116=>2603, +27700=>2603, +28810=>2604, +30561=>2605, +31883=>2606, +32736=>2607, +34928=>2608, +36930=>2609, +37204=>2610, +37648=>2611, +37656=>2612, +38543=>2613, +29790=>2614, +39620=>2615, +23815=>2616, +23913=>2617, +25968=>2618, +26530=>2619, +36264=>2620, +38619=>2621, +25454=>2622, +26441=>2623, +26905=>2624, +33733=>2625, +38935=>2626, +38592=>2627, +35070=>2628, +28548=>2629, +25722=>2630, +12072=>2631, +23544=>2631, +19990=>2632, +28716=>2633, +30045=>2634, +26159=>2635, +20932=>2636, +21046=>2637, +21218=>2638, +22995=>2639, +24449=>2640, +24615=>2641, +25104=>2642, +25919=>2643, +25972=>2644, +26143=>2645, +26228=>2646, +26866=>2647, +26646=>2648, +27491=>2649, +28165=>2650, +29298=>2651, +12131=>2652, +29983=>2652, +30427=>2653, +31934=>2654, +32854=>2655, +22768=>2656, +35069=>2657, +11972=>2658, +35199=>2658, +35488=>2659, +35475=>2660, +35531=>2661, +36893=>2662, +37266=>2663, +11992=>2664, +38738=>2664, +38745=>2665, +12011=>2666, +25993=>2666, +31246=>2667, +33030=>2668, +38587=>2669, +24109=>2670, +24796=>2671, +25114=>2672, +26021=>2673, +26132=>2674, +26512=>2675, +12143=>2676, +30707=>2676, +31309=>2677, +31821=>2678, +32318=>2679, +33034=>2680, +36012=>2681, +12186=>2682, +36196=>2682, +36321=>2683, +36447=>2684, +30889=>2685, +20999=>2686, +25305=>2687, +25509=>2688, +25666=>2689, +25240=>2690, +35373=>2691, +31363=>2692, +31680=>2693, +35500=>2694, +38634=>2695, +32118=>2696, +12166=>2697, +33292=>2697, +34633=>2698, +20185=>2699, +20808=>2700, +21315=>2701, +21344=>2702, +23459=>2703, +23554=>2704, +23574=>2705, +24029=>2706, +25126=>2707, +25159=>2708, +25776=>2709, +26643=>2710, +26676=>2711, +27849=>2712, +27973=>2713, +27927=>2714, +26579=>2715, +28508=>2716, +29006=>2717, +29053=>2718, +26059=>2719, +31359=>2720, +31661=>2721, +32218=>2722, +32330=>2723, +32680=>2724, +33146=>2725, +12167=>2726, +33307=>2726, +33337=>2727, +34214=>2728, +35438=>2729, +36046=>2730, +36341=>2731, +36984=>2732, +36983=>2733, +37549=>2734, +37521=>2735, +38275=>2736, +39854=>2737, +21069=>2738, +21892=>2739, +28472=>2740, +28982=>2741, +20840=>2742, +31109=>2743, +32341=>2744, +33203=>2745, +31950=>2746, +22092=>2747, +22609=>2748, +23720=>2749, +25514=>2750, +26366=>2751, +26365=>2752, +26970=>2753, +29401=>2754, +30095=>2755, +30094=>2756, +30990=>2757, +31062=>2758, +31199=>2759, +31895=>2760, +32032=>2761, +32068=>2762, +34311=>2763, +35380=>2764, +38459=>2765, +36961=>2766, +12239=>2767, +40736=>2767, +20711=>2768, +21109=>2769, +21452=>2770, +21474=>2771, +20489=>2772, +21930=>2773, +22766=>2774, +22863=>2775, +29245=>2776, +23435=>2777, +23652=>2778, +21277=>2779, +24803=>2780, +24819=>2781, +25436=>2782, +25475=>2783, +25407=>2784, +25531=>2785, +25805=>2786, +26089=>2787, +26361=>2788, +24035=>2789, +27085=>2790, +27133=>2791, +28437=>2792, +29157=>2793, +20105=>2794, +30185=>2795, +30456=>2796, +31379=>2797, +31967=>2798, +32207=>2799, +32156=>2800, +32865=>2801, +33609=>2802, +33624=>2803, +33900=>2804, +33980=>2805, +34299=>2806, +35013=>2807, +12187=>2808, +36208=>2808, +36865=>2809, +36973=>2810, +37783=>2811, +38684=>2812, +39442=>2813, +20687=>2814, +22679=>2815, +24974=>2816, +33235=>2817, +34101=>2818, +36104=>2819, +36896=>2820, +20419=>2821, +20596=>2822, +21063=>2823, +21363=>2824, +24687=>2825, +25417=>2826, +26463=>2827, +28204=>2828, +12188=>2829, +36275=>2829, +36895=>2830, +20439=>2831, +23646=>2832, +36042=>2833, +26063=>2834, +32154=>2835, +21330=>2836, +34966=>2837, +20854=>2838, +25539=>2839, +23384=>2840, +23403=>2841, +23562=>2842, +25613=>2843, +26449=>2844, +36956=>2845, +20182=>2846, +22810=>2847, +22826=>2848, +27760=>2849, +35409=>2850, +21822=>2851, +22549=>2852, +22949=>2853, +24816=>2854, +25171=>2855, +26561=>2856, +33333=>2857, +26965=>2858, +38464=>2859, +39364=>2860, +39464=>2861, +20307=>2862, +22534=>2863, +23550=>2864, +32784=>2865, +23729=>2866, +24111=>2867, +24453=>2868, +24608=>2869, +24907=>2870, +25140=>2871, +26367=>2872, +27888=>2873, +28382=>2874, +32974=>2875, +33151=>2876, +33492=>2877, +34955=>2878, +36024=>2879, +36864=>2880, +36910=>2881, +38538=>2882, +40667=>2883, +39899=>2884, +20195=>2885, +21488=>2886, +12068=>2887, +22823=>2887, +31532=>2888, +37261=>2889, +38988=>2890, +40441=>2891, +28381=>2892, +28711=>2893, +21331=>2894, +21828=>2895, +23429=>2896, +25176=>2897, +25246=>2898, +25299=>2899, +27810=>2900, +28655=>2901, +29730=>2902, +35351=>2903, +37944=>2904, +28609=>2905, +35582=>2906, +33592=>2907, +20967=>2908, +34552=>2909, +21482=>2910, +21481=>2911, +20294=>2912, +36948=>2913, +12192=>2914, +36784=>2914, +22890=>2915, +33073=>2916, +24061=>2917, +31466=>2918, +36799=>2919, +26842=>2920, +12181=>2921, +35895=>2921, +29432=>2922, +40008=>2923, +27197=>2924, +35504=>2925, +20025=>2926, +21336=>2927, +22022=>2928, +22374=>2929, +25285=>2930, +25506=>2931, +26086=>2932, +27470=>2933, +28129=>2934, +28251=>2935, +28845=>2936, +30701=>2937, +31471=>2938, +31658=>2939, +32187=>2940, +32829=>2941, +32966=>2942, +34507=>2943, +35477=>2944, +37723=>2945, +22243=>2946, +22727=>2947, +24382=>2948, +26029=>2949, +26262=>2950, +27264=>2951, +27573=>2952, +30007=>2953, +35527=>2954, +20516=>2955, +30693=>2956, +22320=>2957, +24347=>2958, +24677=>2959, +26234=>2960, +27744=>2961, +30196=>2962, +31258=>2963, +32622=>2964, +33268=>2965, +34584=>2966, +36933=>2967, +39347=>2968, +31689=>2969, +30044=>2970, +12149=>2971, +31481=>2971, +31569=>2972, +33988=>2973, +36880=>2974, +31209=>2975, +31378=>2976, +33590=>2977, +23265=>2978, +30528=>2979, +20013=>2980, +20210=>2981, +23449=>2982, +24544=>2983, +25277=>2984, +26172=>2985, +26609=>2986, +27880=>2987, +12173=>2988, +34411=>2988, +34935=>2989, +35387=>2990, +37198=>2991, +37619=>2992, +39376=>2993, +27159=>2994, +28710=>2995, +29482=>2996, +33511=>2997, +33879=>2998, +36015=>2999, +19969=>3000, +20806=>3001, +20939=>3002, +21899=>3003, +23541=>3004, +24086=>3005, +24115=>3006, +24193=>3007, +24340=>3008, +24373=>3009, +24427=>3010, +24500=>3011, +25074=>3012, +25361=>3013, +26274=>3014, +26397=>3015, +28526=>3016, +29266=>3017, +30010=>3018, +30522=>3019, +32884=>3020, +33081=>3021, +33144=>3022, +34678=>3023, +35519=>3024, +35548=>3025, +36229=>3026, +36339=>3027, +37530=>3028, +11985=>3029, +12199=>3029, +38263=>3029, +38914=>3030, +12227=>3031, +40165=>3031, +21189=>3032, +25431=>3033, +30452=>3034, +26389=>3035, +27784=>3036, +29645=>3037, +36035=>3038, +37806=>3039, +38515=>3040, +27941=>3041, +22684=>3042, +26894=>3043, +27084=>3044, +36861=>3045, +37786=>3046, +30171=>3047, +36890=>3048, +22618=>3049, +26626=>3050, +25524=>3051, +27131=>3052, +20291=>3053, +28460=>3054, +26584=>3055, +36795=>3056, +34086=>3057, +32180=>3058, +37716=>3059, +26943=>3060, +28528=>3061, +22378=>3062, +22775=>3063, +23340=>3064, +32044=>3065, +12118=>3066, +29226=>3066, +21514=>3067, +37347=>3068, +40372=>3069, +20141=>3070, +20302=>3071, +20572=>3072, +20597=>3073, +21059=>3074, +35998=>3075, +21576=>3076, +22564=>3077, +23450=>3078, +24093=>3079, +24213=>3080, +24237=>3081, +24311=>3082, +24351=>3083, +24716=>3084, +25269=>3085, +25402=>3086, +25552=>3087, +26799=>3088, +27712=>3089, +30855=>3090, +31118=>3091, +31243=>3092, +32224=>3093, +33351=>3094, +35330=>3095, +35558=>3096, +36420=>3097, +36883=>3098, +37048=>3099, +37165=>3100, +37336=>3101, +12237=>3102, +40718=>3102, +27877=>3103, +25688=>3104, +25826=>3105, +25973=>3106, +28404=>3107, +30340=>3108, +31515=>3109, +36969=>3110, +37841=>3111, +28346=>3112, +21746=>3113, +24505=>3114, +25764=>3115, +36685=>3116, +36845=>3117, +37444=>3118, +20856=>3119, +22635=>3120, +22825=>3121, +23637=>3122, +24215=>3123, +28155=>3124, +32399=>3125, +29980=>3126, +36028=>3127, +36578=>3128, +39003=>3129, +28857=>3130, +20253=>3131, +27583=>3132, +28593=>3133, +12133=>3134, +30000=>3134, +38651=>3135, +20814=>3136, +21520=>3137, +22581=>3138, +22615=>3139, +22956=>3140, +23648=>3141, +24466=>3142, +12099=>3143, +26007=>3143, +26460=>3144, +28193=>3145, +30331=>3146, +33759=>3147, +36077=>3148, +36884=>3149, +37117=>3150, +37709=>3151, +30757=>3152, +30778=>3153, +21162=>3154, +24230=>3155, +12063=>3156, +22303=>3156, +22900=>3157, +24594=>3158, +20498=>3159, +20826=>3160, +20908=>3161, +20941=>3162, +12049=>3163, +20992=>3163, +21776=>3164, +22612=>3165, +22616=>3166, +22871=>3167, +23445=>3168, +23798=>3169, +23947=>3170, +24764=>3171, +25237=>3172, +25645=>3173, +26481=>3174, +26691=>3175, +26812=>3176, +26847=>3177, +30423=>3178, +28120=>3179, +28271=>3180, +28059=>3181, +28783=>3182, +29128=>3183, +24403=>3184, +30168=>3185, +31095=>3186, +31561=>3187, +31572=>3188, +31570=>3189, +31958=>3190, +32113=>3191, +21040=>3192, +33891=>3193, +34153=>3194, +34276=>3195, +35342=>3196, +35588=>3197, +12182=>3198, +35910=>3198, +36367=>3199, +36867=>3200, +36879=>3201, +37913=>3202, +38518=>3203, +38957=>3204, +39472=>3205, +38360=>3206, +20685=>3207, +21205=>3208, +21516=>3209, +22530=>3210, +23566=>3211, +24999=>3212, +25758=>3213, +27934=>3214, +30643=>3215, +31461=>3216, +33012=>3217, +33796=>3218, +36947=>3219, +37509=>3220, +23776=>3221, +40199=>3222, +21311=>3223, +24471=>3224, +24499=>3225, +28060=>3226, +29305=>3227, +30563=>3228, +31167=>3229, +31716=>3230, +27602=>3231, +29420=>3232, +35501=>3233, +26627=>3234, +27233=>3235, +20984=>3236, +31361=>3237, +26932=>3238, +23626=>3239, +40182=>3240, +33515=>3241, +23493=>3242, +12195=>3243, +37193=>3243, +28702=>3244, +22136=>3245, +23663=>3246, +24775=>3247, +25958=>3248, +27788=>3249, +35930=>3250, +36929=>3251, +38931=>3252, +21585=>3253, +26311=>3254, +37389=>3255, +22856=>3256, +37027=>3257, +20869=>3258, +20045=>3259, +20970=>3260, +34201=>3261, +35598=>3262, +28760=>3263, +25466=>3264, +37707=>3265, +26978=>3266, +39348=>3267, +32260=>3268, +30071=>3269, +21335=>3270, +26976=>3271, +36575=>3272, +38627=>3273, +27741=>3274, +12038=>3275, +20108=>3275, +23612=>3276, +24336=>3277, +36841=>3278, +21250=>3279, +36049=>3280, +12161=>3281, +32905=>3281, +34425=>3282, +24319=>3283, +12103=>3284, +26085=>3284, +20083=>3285, +12042=>3286, +20837=>3286, +22914=>3287, +23615=>3288, +38894=>3289, +20219=>3290, +22922=>3291, +24525=>3292, +35469=>3293, +28641=>3294, +31152=>3295, +31074=>3296, +23527=>3297, +33905=>3298, +29483=>3299, +29105=>3300, +24180=>3301, +24565=>3302, +25467=>3303, +25754=>3304, +29123=>3305, +31896=>3306, +20035=>3307, +24316=>3308, +20043=>3309, +22492=>3310, +22178=>3311, +24745=>3312, +28611=>3313, +32013=>3314, +33021=>3315, +33075=>3316, +33215=>3317, +36786=>3318, +35223=>3319, +34468=>3320, +24052=>3321, +25226=>3322, +25773=>3323, +35207=>3324, +26487=>3325, +27874=>3326, +27966=>3327, +29750=>3328, +30772=>3329, +23110=>3330, +32629=>3331, +33453=>3332, +12218=>3333, +39340=>3333, +20467=>3334, +24259=>3335, +25309=>3336, +25490=>3337, +25943=>3338, +26479=>3339, +30403=>3340, +29260=>3341, +32972=>3342, +32954=>3343, +36649=>3344, +37197=>3345, +20493=>3346, +22521=>3347, +23186=>3348, +26757=>3349, +26995=>3350, +29028=>3351, +29437=>3352, +36023=>3353, +22770=>3354, +36064=>3355, +38506=>3356, +36889=>3357, +34687=>3358, +31204=>3359, +30695=>3360, +33833=>3361, +20271=>3362, +21093=>3363, +21338=>3364, +25293=>3365, +26575=>3366, +27850=>3367, +12137=>3368, +30333=>3368, +31636=>3369, +31893=>3370, +33334=>3371, +34180=>3372, +36843=>3373, +26333=>3374, +28448=>3375, +29190=>3376, +32283=>3377, +33707=>3378, +39361=>3379, +12008=>3380, +40614=>3380, +20989=>3381, +31665=>3382, +30834=>3383, +31672=>3384, +32903=>3385, +31560=>3386, +27368=>3387, +24161=>3388, +32908=>3389, +30033=>3390, +30048=>3391, +12043=>3392, +20843=>3392, +37474=>3393, +28300=>3394, +30330=>3395, +37271=>3396, +39658=>3397, +20240=>3398, +32624=>3399, +25244=>3400, +31567=>3401, +38309=>3402, +40169=>3403, +22138=>3404, +22617=>3405, +34532=>3406, +38588=>3407, +20276=>3408, +21028=>3409, +21322=>3410, +21453=>3411, +21467=>3412, +24070=>3413, +25644=>3414, +26001=>3415, +26495=>3416, +27710=>3417, +27726=>3418, +29256=>3419, +29359=>3420, +29677=>3421, +30036=>3422, +32321=>3423, +33324=>3424, +34281=>3425, +36009=>3426, +31684=>3427, +12196=>3428, +37318=>3428, +29033=>3429, +38930=>3430, +39151=>3431, +25405=>3432, +26217=>3433, +30058=>3434, +30436=>3435, +30928=>3436, +34115=>3437, +34542=>3438, +21290=>3439, +21329=>3440, +21542=>3441, +22915=>3442, +24199=>3443, +24444=>3444, +24754=>3445, +25161=>3446, +25209=>3447, +25259=>3448, +26000=>3449, +12112=>3450, +27604=>3450, +27852=>3451, +30130=>3452, +12138=>3453, +30382=>3453, +30865=>3454, +31192=>3455, +32203=>3456, +32631=>3457, +32933=>3458, +34987=>3459, +35513=>3460, +36027=>3461, +36991=>3462, +12206=>3463, +38750=>3463, +12214=>3464, +39131=>3464, +27147=>3465, +31800=>3466, +20633=>3467, +23614=>3468, +24494=>3469, +26503=>3470, +27608=>3471, +29749=>3472, +30473=>3473, +32654=>3474, +12240=>3475, +40763=>3475, +26570=>3476, +31255=>3477, +21305=>3478, +12134=>3479, +30091=>3479, +39661=>3480, +24422=>3481, +33181=>3482, +33777=>3483, +32920=>3484, +24380=>3485, +24517=>3486, +30050=>3487, +31558=>3488, +36924=>3489, +26727=>3490, +23019=>3491, +23195=>3492, +32016=>3493, +30334=>3494, +35628=>3495, +20469=>3496, +24426=>3497, +27161=>3498, +27703=>3499, +28418=>3500, +29922=>3501, +31080=>3502, +34920=>3503, +35413=>3504, +35961=>3505, +24287=>3506, +25551=>3507, +30149=>3508, +31186=>3509, +33495=>3510, +37672=>3511, +37618=>3512, +33948=>3513, +34541=>3514, +39981=>3515, +21697=>3516, +24428=>3517, +25996=>3518, +27996=>3519, +28693=>3520, +36007=>3521, +36051=>3522, +38971=>3523, +25935=>3524, +29942=>3525, +19981=>3526, +20184=>3527, +22496=>3528, +22827=>3529, +23142=>3530, +23500=>3531, +20904=>3532, +24067=>3533, +24220=>3534, +24598=>3535, +25206=>3536, +25975=>3537, +26023=>3538, +26222=>3539, +28014=>3540, +12119=>3541, +29238=>3541, +31526=>3542, +33104=>3543, +33178=>3544, +33433=>3545, +35676=>3546, +36000=>3547, +36070=>3548, +36212=>3549, +12201=>3550, +38428=>3550, +38468=>3551, +20398=>3552, +25771=>3553, +27494=>3554, +33310=>3555, +33889=>3556, +34154=>3557, +37096=>3558, +23553=>3559, +26963=>3560, +12213=>3561, +39080=>3561, +33914=>3562, +34135=>3563, +20239=>3564, +21103=>3565, +24489=>3566, +24133=>3567, +26381=>3568, +31119=>3569, +33145=>3570, +35079=>3571, +35206=>3572, +28149=>3573, +24343=>3574, +25173=>3575, +27832=>3576, +20175=>3577, +29289=>3578, +39826=>3579, +20998=>3580, +21563=>3581, +22132=>3582, +22707=>3583, +24996=>3584, +25198=>3585, +28954=>3586, +22894=>3587, +31881=>3588, +31966=>3589, +32027=>3590, +38640=>3591, +12098=>3592, +25991=>3592, +32862=>3593, +19993=>3594, +20341=>3595, +20853=>3596, +22592=>3597, +24163=>3598, +24179=>3599, +24330=>3600, +26564=>3601, +20006=>3602, +34109=>3603, +38281=>3604, +38491=>3605, +12150=>3606, +31859=>3606, +12212=>3607, +38913=>3607, +20731=>3608, +22721=>3609, +30294=>3610, +30887=>3611, +21029=>3612, +30629=>3613, +34065=>3614, +31622=>3615, +20559=>3616, +22793=>3617, +12122=>3618, +29255=>3618, +31687=>3619, +32232=>3620, +36794=>3621, +36820=>3622, +36941=>3623, +20415=>3624, +21193=>3625, +23081=>3626, +24321=>3627, +38829=>3628, +20445=>3629, +33303=>3630, +37610=>3631, +22275=>3632, +25429=>3633, +27497=>3634, +29995=>3635, +35036=>3636, +36628=>3637, +31298=>3638, +21215=>3639, +22675=>3640, +24917=>3641, +25098=>3642, +26286=>3643, +11935=>3644, +27597=>3644, +31807=>3645, +33769=>3646, +20515=>3647, +20472=>3648, +21253=>3649, +21574=>3650, +22577=>3651, +22857=>3652, +23453=>3653, +23792=>3654, +23791=>3655, +23849=>3656, +24214=>3657, +25265=>3658, +25447=>3659, +25918=>3660, +12101=>3661, +26041=>3661, +26379=>3662, +27861=>3663, +27873=>3664, +28921=>3665, +30770=>3666, +32299=>3667, +32990=>3668, +33459=>3669, +33804=>3670, +34028=>3671, +34562=>3672, +35090=>3673, +35370=>3674, +35914=>3675, +37030=>3676, +37586=>3677, +39165=>3678, +40179=>3679, +40300=>3680, +20047=>3681, +20129=>3682, +20621=>3683, +21078=>3684, +22346=>3685, +22952=>3686, +24125=>3687, +24536=>3688, +24537=>3689, +25151=>3690, +26292=>3691, +26395=>3692, +26576=>3693, +26834=>3694, +20882=>3695, +32033=>3696, +32938=>3697, +33192=>3698, +35584=>3699, +35980=>3700, +36031=>3701, +37502=>3702, +38450=>3703, +21536=>3704, +38956=>3705, +21271=>3706, +20693=>3707, +12056=>3708, +21340=>3708, +22696=>3709, +25778=>3710, +26420=>3711, +29287=>3712, +30566=>3713, +31302=>3714, +37350=>3715, +21187=>3716, +27809=>3717, +27526=>3718, +22528=>3719, +24140=>3720, +22868=>3721, +26412=>3722, +32763=>3723, +20961=>3724, +30406=>3725, +25705=>3726, +30952=>3727, +39764=>3728, +12231=>3729, +40635=>3729, +22475=>3730, +22969=>3731, +26151=>3732, +26522=>3733, +27598=>3734, +21737=>3735, +27097=>3736, +24149=>3737, +33180=>3738, +26517=>3739, +39850=>3740, +26622=>3741, +40018=>3742, +26717=>3743, +20134=>3744, +20451=>3745, +12060=>3746, +21448=>3746, +25273=>3747, +26411=>3748, +27819=>3749, +36804=>3750, +20397=>3751, +32365=>3752, +40639=>3753, +19975=>3754, +24930=>3755, +28288=>3756, +28459=>3757, +34067=>3758, +21619=>3759, +26410=>3760, +39749=>3761, +11922=>3762, +24051=>3762, +31637=>3763, +23724=>3764, +23494=>3765, +34588=>3766, +28234=>3767, +34001=>3768, +31252=>3769, +33032=>3770, +22937=>3771, +31885=>3772, +11936=>3773, +27665=>3773, +30496=>3774, +21209=>3775, +22818=>3776, +28961=>3777, +29279=>3778, +12141=>3779, +30683=>3779, +38695=>3780, +40289=>3781, +26891=>3782, +23167=>3783, +23064=>3784, +20901=>3785, +21517=>3786, +21629=>3787, +26126=>3788, +30431=>3789, +36855=>3790, +37528=>3791, +40180=>3792, +23018=>3793, +29277=>3794, +28357=>3795, +20813=>3796, +26825=>3797, +32191=>3798, +32236=>3799, +12207=>3800, +38754=>3800, +40634=>3801, +25720=>3802, +27169=>3803, +33538=>3804, +22916=>3805, +23391=>3806, +12113=>3807, +27611=>3807, +29467=>3808, +30450=>3809, +32178=>3810, +32791=>3811, +33945=>3812, +20786=>3813, +12106=>3814, +26408=>3814, +40665=>3815, +12140=>3816, +30446=>3816, +26466=>3817, +21247=>3818, +39173=>3819, +23588=>3820, +25147=>3821, +31870=>3822, +36016=>3823, +21839=>3824, +24758=>3825, +32011=>3826, +12200=>3827, +38272=>3827, +21249=>3828, +20063=>3829, +20918=>3830, +22812=>3831, +29242=>3832, +32822=>3833, +37326=>3834, +24357=>3835, +12142=>3836, +30690=>3836, +21380=>3837, +24441=>3838, +32004=>3839, +34220=>3840, +35379=>3841, +36493=>3842, +38742=>3843, +26611=>3844, +34222=>3845, +37971=>3846, +24841=>3847, +24840=>3848, +27833=>3849, +30290=>3850, +35565=>3851, +36664=>3852, +21807=>3853, +20305=>3854, +20778=>3855, +21191=>3856, +21451=>3857, +23461=>3858, +24189=>3859, +24736=>3860, +24962=>3861, +25558=>3862, +26377=>3863, +26586=>3864, +28263=>3865, +28044=>3866, +29494=>3867, +29495=>3868, +30001=>3869, +31056=>3870, +35029=>3871, +35480=>3872, +36938=>3873, +12194=>3874, +37009=>3874, +37109=>3875, +38596=>3876, +34701=>3877, +12067=>3878, +22805=>3878, +20104=>3879, +20313=>3880, +19982=>3881, +35465=>3882, +36671=>3883, +38928=>3884, +20653=>3885, +24188=>3886, +22934=>3887, +23481=>3888, +24248=>3889, +25562=>3890, +25594=>3891, +25793=>3892, +26332=>3893, +26954=>3894, +27096=>3895, +27915=>3896, +28342=>3897, +29076=>3898, +12132=>3899, +29992=>3899, +31407=>3900, +12154=>3901, +32650=>3901, +32768=>3902, +33865=>3903, +33993=>3904, +35201=>3905, +35617=>3906, +36362=>3907, +36965=>3908, +38525=>3909, +39178=>3910, +24958=>3911, +25233=>3912, +27442=>3913, +27779=>3914, +28020=>3915, +32716=>3916, +32764=>3917, +28096=>3918, +32645=>3919, +34746=>3920, +35064=>3921, +26469=>3922, +33713=>3923, +38972=>3924, +38647=>3925, +27931=>3926, +32097=>3927, +33853=>3928, +37226=>3929, +20081=>3930, +21365=>3931, +23888=>3932, +27396=>3933, +28651=>3934, +34253=>3935, +34349=>3936, +35239=>3937, +21033=>3938, +21519=>3939, +23653=>3940, +26446=>3941, +26792=>3942, +29702=>3943, +29827=>3944, +30178=>3945, +35023=>3946, +35041=>3947, +12197=>3948, +37324=>3948, +38626=>3949, +38520=>3950, +24459=>3951, +29575=>3952, +12148=>3953, +31435=>3953, +33870=>3954, +25504=>3955, +30053=>3956, +21129=>3957, +27969=>3958, +28316=>3959, +29705=>3960, +30041=>3961, +30827=>3962, +31890=>3963, +38534=>3964, +12015=>3965, +31452=>3965, +12243=>3966, +40845=>3966, +20406=>3967, +24942=>3968, +26053=>3969, +34396=>3970, +20102=>3971, +20142=>3972, +20698=>3973, +20001=>3974, +20940=>3975, +23534=>3976, +26009=>3977, +26753=>3978, +28092=>3979, +29471=>3980, +30274=>3981, +30637=>3982, +31260=>3983, +31975=>3984, +33391=>3985, +35538=>3986, +36988=>3987, +37327=>3988, +38517=>3989, +38936=>3990, +12050=>3991, +21147=>3991, +32209=>3992, +20523=>3993, +21400=>3994, +26519=>3995, +28107=>3996, +29136=>3997, +29747=>3998, +33256=>3999, +36650=>4000, +38563=>4001, +40023=>4002, +40607=>4003, +29792=>4004, +22593=>4005, +28057=>4006, +32047=>4007, +39006=>4008, +20196=>4009, +20278=>4010, +20363=>4011, +20919=>4012, +21169=>4013, +23994=>4014, +24604=>4015, +29618=>4016, +31036=>4017, +33491=>4018, +37428=>4019, +38583=>4020, +38646=>4021, +38666=>4022, +40599=>4023, +40802=>4024, +26278=>4025, +27508=>4026, +21015=>4027, +21155=>4028, +28872=>4029, +35010=>4030, +24265=>4031, +24651=>4032, +24976=>4033, +28451=>4034, +29001=>4035, +31806=>4036, +32244=>4037, +32879=>4038, +34030=>4039, +36899=>4040, +37676=>4041, +21570=>4042, +39791=>4043, +27347=>4044, +28809=>4045, +36034=>4046, +36335=>4047, +38706=>4048, +21172=>4049, +23105=>4050, +24266=>4051, +24324=>4052, +26391=>4053, +27004=>4054, +27028=>4055, +28010=>4056, +28431=>4057, +29282=>4058, +29436=>4059, +31725=>4060, +12156=>4061, +32769=>4061, +32894=>4062, +34635=>4063, +37070=>4064, +20845=>4065, +40595=>4066, +31108=>4067, +32907=>4068, +37682=>4069, +35542=>4070, +20525=>4071, +21644=>4072, +35441=>4073, +27498=>4074, +36036=>4075, +33031=>4076, +24785=>4077, +26528=>4078, +40434=>4079, +20121=>4080, +20120=>4081, +39952=>4082, +35435=>4083, +34241=>4084, +34152=>4085, +26880=>4086, +28286=>4087, +30871=>4088, +33109=>4089, +24332=>4090, +19984=>4091, +19989=>4092, +20010=>4093, +20017=>4094, +12034=>4095, +20022=>4095, +20028=>4096, +12035=>4097, +20031=>4097, +20034=>4098, +20054=>4099, +20056=>4100, +20098=>4101, +12037=>4102, +20101=>4102, +35947=>4103, +20106=>4104, +33298=>4105, +24333=>4106, +20110=>4107, +20126=>4108, +20127=>4109, +12039=>4110, +20128=>4110, +20130=>4111, +20144=>4112, +20147=>4113, +20150=>4114, +20174=>4115, +20173=>4116, +20164=>4117, +20166=>4118, +20162=>4119, +20183=>4120, +20190=>4121, +20205=>4122, +20191=>4123, +20215=>4124, +20233=>4125, +20314=>4126, +20272=>4127, +20315=>4128, +20317=>4129, +20311=>4130, +20295=>4131, +20342=>4132, +20360=>4133, +20367=>4134, +20376=>4135, +20347=>4136, +20329=>4137, +20336=>4138, +20369=>4139, +20335=>4140, +20358=>4141, +20374=>4142, +20760=>4143, +20436=>4144, +20447=>4145, +20430=>4146, +20440=>4147, +20443=>4148, +20433=>4149, +20442=>4150, +20432=>4151, +20452=>4152, +20453=>4153, +20506=>4154, +20520=>4155, +20500=>4156, +20522=>4157, +20517=>4158, +20485=>4159, +20252=>4160, +20470=>4161, +20513=>4162, +20521=>4163, +20524=>4164, +20478=>4165, +20463=>4166, +20497=>4167, +20486=>4168, +20547=>4169, +20551=>4170, +26371=>4171, +20565=>4172, +20560=>4173, +20552=>4174, +20570=>4175, +20566=>4176, +20588=>4177, +20600=>4178, +20608=>4179, +20634=>4180, +20613=>4181, +20660=>4182, +20658=>4183, +20681=>4184, +20682=>4185, +20659=>4186, +20674=>4187, +20694=>4188, +20702=>4189, +20709=>4190, +20717=>4191, +20707=>4192, +20718=>4193, +20729=>4194, +20725=>4195, +20745=>4196, +20737=>4197, +20738=>4198, +20758=>4199, +20757=>4200, +20756=>4201, +20762=>4202, +20769=>4203, +20794=>4204, +20791=>4205, +20796=>4206, +20795=>4207, +12041=>4208, +20799=>4208, +11918=>4209, +20800=>4209, +20818=>4210, +20812=>4211, +20820=>4212, +20834=>4213, +31480=>4214, +20841=>4215, +20842=>4216, +20846=>4217, +20864=>4218, +12044=>4219, +20866=>4219, +22232=>4220, +20876=>4221, +20873=>4222, +20879=>4223, +20881=>4224, +20883=>4225, +20885=>4226, +12045=>4227, +20886=>4227, +20900=>4228, +20902=>4229, +20898=>4230, +20905=>4231, +20906=>4232, +12046=>4233, +20907=>4233, +20915=>4234, +20913=>4235, +20914=>4236, +20912=>4237, +20917=>4238, +20925=>4239, +20933=>4240, +20937=>4241, +20955=>4242, +12047=>4243, +20960=>4243, +34389=>4244, +20969=>4245, +20973=>4246, +20976=>4247, +12048=>4248, +20981=>4248, +20990=>4249, +20996=>4250, +21003=>4251, +21012=>4252, +21006=>4253, +21031=>4254, +21034=>4255, +21038=>4256, +21043=>4257, +21049=>4258, +21071=>4259, +21060=>4260, +21067=>4261, +21068=>4262, +21086=>4263, +21076=>4264, +21098=>4265, +21108=>4266, +21097=>4267, +21107=>4268, +21119=>4269, +21117=>4270, +21133=>4271, +21140=>4272, +21138=>4273, +21105=>4274, +21128=>4275, +21137=>4276, +36776=>4277, +36775=>4278, +21164=>4279, +21165=>4280, +21180=>4281, +21173=>4282, +21185=>4283, +21197=>4284, +21207=>4285, +21214=>4286, +21219=>4287, +21222=>4288, +39149=>4289, +21216=>4290, +21235=>4291, +21237=>4292, +21240=>4293, +12051=>4294, +21241=>4294, +21254=>4295, +21256=>4296, +30008=>4297, +21261=>4298, +21264=>4299, +21263=>4300, +21269=>4301, +12052=>4301, +21274=>4302, +12053=>4302, +21283=>4303, +21295=>4304, +21297=>4305, +21299=>4306, +12054=>4307, +21304=>4307, +21312=>4308, +21318=>4309, +21317=>4310, +19991=>4311, +21321=>4312, +21325=>4313, +20950=>4314, +21342=>4315, +12057=>4316, +21353=>4316, +21358=>4317, +22808=>4318, +21371=>4319, +21367=>4320, +12058=>4321, +21378=>4321, +21398=>4322, +21408=>4323, +21414=>4324, +21413=>4325, +21422=>4326, +21424=>4327, +12059=>4328, +21430=>4328, +21443=>4329, +31762=>4330, +38617=>4331, +21471=>4332, +26364=>4333, +29166=>4334, +21486=>4335, +21480=>4336, +21485=>4337, +21498=>4338, +21505=>4339, +21565=>4340, +21568=>4341, +21548=>4342, +21549=>4343, +21564=>4344, +21550=>4345, +21558=>4346, +21545=>4347, +21533=>4348, +21582=>4349, +21647=>4350, +21621=>4351, +21646=>4352, +21599=>4353, +21617=>4354, +21623=>4355, +21616=>4356, +21650=>4357, +21627=>4358, +21632=>4359, +21622=>4360, +21636=>4361, +21648=>4362, +21638=>4363, +21703=>4364, +21666=>4365, +21688=>4366, +21669=>4367, +21676=>4368, +21700=>4369, +21704=>4370, +21672=>4371, +21675=>4372, +21698=>4373, +21668=>4374, +21694=>4375, +21692=>4376, +21720=>4377, +21733=>4378, +21734=>4379, +21775=>4380, +21780=>4381, +21757=>4382, +21742=>4383, +21741=>4384, +21754=>4385, +21730=>4386, +21817=>4387, +21824=>4388, +21859=>4389, +21836=>4390, +21806=>4391, +21852=>4392, +21829=>4393, +21846=>4394, +21847=>4395, +21816=>4396, +21811=>4397, +21853=>4398, +21913=>4399, +21888=>4400, +21679=>4401, +21898=>4402, +21919=>4403, +21883=>4404, +21886=>4405, +21912=>4406, +21918=>4407, +21934=>4408, +21884=>4409, +21891=>4410, +21929=>4411, +21895=>4412, +21928=>4413, +21978=>4414, +21957=>4415, +21983=>4416, +21956=>4417, +21980=>4418, +21988=>4419, +21972=>4420, +22036=>4421, +22007=>4422, +22038=>4423, +22014=>4424, +22013=>4425, +22043=>4426, +22009=>4427, +22094=>4428, +22096=>4429, +29151=>4430, +22068=>4431, +22070=>4432, +22066=>4433, +22072=>4434, +22123=>4435, +22116=>4436, +22063=>4437, +22124=>4438, +22122=>4439, +22150=>4440, +22144=>4441, +22154=>4442, +22176=>4443, +22164=>4444, +22159=>4445, +22181=>4446, +22190=>4447, +22198=>4448, +22196=>4449, +22210=>4450, +22204=>4451, +22209=>4452, +22211=>4453, +22208=>4454, +22216=>4455, +22222=>4456, +22225=>4457, +22227=>4458, +12062=>4459, +22231=>4459, +22254=>4460, +22265=>4461, +22272=>4462, +22271=>4463, +22276=>4464, +22281=>4465, +22280=>4466, +22283=>4467, +22285=>4468, +22291=>4469, +22296=>4470, +22294=>4471, +21959=>4472, +22300=>4473, +22310=>4474, +22327=>4475, +22328=>4476, +22350=>4477, +22331=>4478, +22336=>4479, +22351=>4480, +22377=>4481, +22464=>4482, +22408=>4483, +22369=>4484, +22399=>4485, +22409=>4486, +22419=>4487, +22432=>4488, +22451=>4489, +22436=>4490, +22442=>4491, +22448=>4492, +22467=>4493, +22470=>4494, +22484=>4495, +22482=>4496, +22483=>4497, +22538=>4498, +22486=>4499, +22499=>4500, +22539=>4501, +22553=>4502, +22557=>4503, +22642=>4504, +22561=>4505, +22626=>4506, +22603=>4507, +22640=>4508, +27584=>4509, +22610=>4510, +22589=>4511, +22649=>4512, +22661=>4513, +22713=>4514, +22687=>4515, +22699=>4516, +22714=>4517, +22750=>4518, +22715=>4519, +22712=>4520, +22702=>4521, +22725=>4522, +22739=>4523, +22737=>4524, +22743=>4525, +22745=>4526, +22744=>4527, +22757=>4528, +22748=>4529, +22756=>4530, +22751=>4531, +22767=>4532, +22778=>4533, +22777=>4534, +22779=>4535, +22780=>4536, +22781=>4537, +22786=>4538, +12065=>4538, +22794=>4539, +12066=>4539, +22800=>4540, +22811=>4541, +26790=>4542, +22821=>4543, +22828=>4544, +22829=>4545, +22834=>4546, +22840=>4547, +22846=>4548, +31442=>4549, +22869=>4550, +22864=>4551, +22862=>4552, +22874=>4553, +22872=>4554, +22882=>4555, +22880=>4556, +22887=>4557, +22892=>4558, +22889=>4559, +22904=>4560, +22913=>4561, +22941=>4562, +20318=>4563, +20395=>4564, +22947=>4565, +22962=>4566, +22982=>4567, +23016=>4568, +23004=>4569, +22925=>4570, +23001=>4571, +23002=>4572, +23077=>4573, +23071=>4574, +23057=>4575, +23068=>4576, +23049=>4577, +23066=>4578, +23104=>4579, +23148=>4580, +23113=>4581, +23093=>4582, +23094=>4583, +23138=>4584, +23146=>4585, +23194=>4586, +23228=>4587, +23230=>4588, +23243=>4589, +23234=>4590, +23229=>4591, +23267=>4592, +23255=>4593, +23270=>4594, +23273=>4595, +23254=>4596, +23290=>4597, +23291=>4598, +23308=>4599, +23307=>4600, +23318=>4601, +23346=>4602, +23248=>4603, +23338=>4604, +23350=>4605, +23358=>4606, +23363=>4607, +23365=>4608, +23360=>4609, +23377=>4610, +23381=>4611, +23386=>4612, +23387=>4613, +23397=>4614, +23401=>4615, +23408=>4616, +23411=>4617, +23413=>4618, +23416=>4619, +25992=>4620, +23418=>4621, +12071=>4622, +23424=>4622, +23427=>4623, +23462=>4624, +23480=>4625, +23491=>4626, +23495=>4627, +23497=>4628, +23508=>4629, +23504=>4630, +23524=>4631, +23526=>4632, +23522=>4633, +23518=>4634, +23525=>4635, +23531=>4636, +23536=>4637, +23542=>4638, +23539=>4639, +23557=>4640, +23559=>4641, +23560=>4642, +23565=>4643, +23571=>4644, +23584=>4645, +11920=>4646, +12074=>4646, +23586=>4646, +23592=>4647, +12075=>4648, +23608=>4648, +23609=>4649, +23617=>4650, +23622=>4651, +23630=>4652, +23635=>4653, +23632=>4654, +23631=>4655, +23409=>4656, +23660=>4657, +12076=>4658, +23662=>4658, +20066=>4659, +23670=>4660, +23673=>4661, +23692=>4662, +23697=>4663, +23700=>4664, +22939=>4665, +23723=>4666, +23739=>4667, +23734=>4668, +23740=>4669, +23735=>4670, +23749=>4671, +23742=>4672, +23751=>4673, +23769=>4674, +23785=>4675, +23805=>4676, +23802=>4677, +23789=>4678, +23948=>4679, +23786=>4680, +23819=>4681, +23829=>4682, +23831=>4683, +23900=>4684, +23839=>4685, +23835=>4686, +23825=>4687, +23828=>4688, +23842=>4689, +23834=>4690, +23833=>4691, +23832=>4692, +23884=>4693, +23890=>4694, +23886=>4695, +23883=>4696, +23916=>4697, +23923=>4698, +23926=>4699, +23943=>4700, +23940=>4701, +23938=>4702, +23970=>4703, +23965=>4704, +23980=>4705, +23982=>4706, +23997=>4707, +23952=>4708, +23991=>4709, +23996=>4710, +24009=>4711, +24013=>4712, +24019=>4713, +24018=>4714, +24022=>4715, +12078=>4716, +24027=>4716, +24043=>4717, +24050=>4718, +24053=>4719, +24075=>4720, +24090=>4721, +24089=>4722, +24081=>4723, +24091=>4724, +24118=>4725, +24119=>4726, +24132=>4727, +24131=>4728, +24128=>4729, +24142=>4730, +24151=>4731, +24148=>4732, +24159=>4733, +24162=>4734, +24164=>4735, +24135=>4736, +24181=>4737, +24182=>4738, +11923=>4739, +12083=>4739, +24186=>4739, +40636=>4740, +12084=>4741, +24191=>4741, +24224=>4742, +24257=>4743, +24258=>4744, +24264=>4745, +24272=>4746, +24271=>4747, +24278=>4748, +24291=>4749, +24285=>4750, +24282=>4751, +24283=>4752, +24290=>4753, +24289=>4754, +24296=>4755, +24297=>4756, +24300=>4757, +24305=>4758, +24307=>4759, +24304=>4760, +12085=>4761, +24308=>4761, +24312=>4762, +12086=>4763, +24318=>4763, +24323=>4764, +24329=>4765, +24413=>4766, +24412=>4767, +12087=>4768, +24331=>4768, +24337=>4769, +24342=>4770, +24361=>4771, +24365=>4772, +24376=>4773, +24385=>4774, +24392=>4775, +24396=>4776, +24398=>4777, +24367=>4778, +11924=>4779, +24401=>4779, +24406=>4780, +24407=>4781, +24409=>4782, +12090=>4783, +24417=>4783, +24429=>4784, +12091=>4785, +24435=>4785, +24439=>4786, +24451=>4787, +24450=>4788, +24447=>4789, +24458=>4790, +24456=>4791, +24465=>4792, +24455=>4793, +24478=>4794, +24473=>4795, +24472=>4796, +24480=>4797, +24488=>4798, +24493=>4799, +24508=>4800, +24534=>4801, +24571=>4802, +24548=>4803, +24568=>4804, +24561=>4805, +24541=>4806, +24755=>4807, +24575=>4808, +24609=>4809, +24672=>4810, +24601=>4811, +24592=>4812, +24617=>4813, +24590=>4814, +24625=>4815, +24603=>4816, +24597=>4817, +24619=>4818, +24614=>4819, +24591=>4820, +24634=>4821, +24666=>4822, +24641=>4823, +24682=>4824, +24695=>4825, +24671=>4826, +24650=>4827, +24646=>4828, +24653=>4829, +24675=>4830, +24643=>4831, +24676=>4832, +24642=>4833, +24684=>4834, +24683=>4835, +24665=>4836, +24705=>4837, +24717=>4838, +24807=>4839, +24707=>4840, +24730=>4841, +24708=>4842, +24731=>4843, +24726=>4844, +24727=>4845, +24722=>4846, +24743=>4847, +24715=>4848, +24801=>4849, +24760=>4850, +24800=>4851, +24787=>4852, +24756=>4853, +24560=>4854, +24765=>4855, +24774=>4856, +24757=>4857, +24792=>4858, +24909=>4859, +24853=>4860, +24838=>4861, +24822=>4862, +24823=>4863, +24832=>4864, +24820=>4865, +24826=>4866, +24835=>4867, +24865=>4868, +24827=>4869, +24817=>4870, +24845=>4871, +24846=>4872, +24903=>4873, +24894=>4874, +24872=>4875, +24871=>4876, +24906=>4877, +24895=>4878, +24892=>4879, +24876=>4880, +24884=>4881, +24893=>4882, +24898=>4883, +24900=>4884, +24947=>4885, +24951=>4886, +24920=>4887, +24921=>4888, +24922=>4889, +24939=>4890, +24948=>4891, +24943=>4892, +24933=>4893, +24945=>4894, +24927=>4895, +24925=>4896, +24915=>4897, +24949=>4898, +24985=>4899, +24982=>4900, +24967=>4901, +25004=>4902, +24980=>4903, +24986=>4904, +24970=>4905, +24977=>4906, +25003=>4907, +25006=>4908, +25036=>4909, +25034=>4910, +25033=>4911, +25079=>4912, +25032=>4913, +25027=>4914, +25030=>4915, +25018=>4916, +25035=>4917, +32633=>4918, +25037=>4919, +25062=>4920, +25059=>4921, +25078=>4922, +25082=>4923, +25076=>4924, +25087=>4925, +25085=>4926, +25084=>4927, +25086=>4928, +25088=>4929, +12093=>4930, +25096=>4930, +25097=>4931, +25101=>4932, +25100=>4933, +25108=>4934, +25115=>4935, +25118=>4936, +25121=>4937, +25130=>4938, +25134=>4939, +25136=>4940, +25138=>4941, +25139=>4942, +25153=>4943, +25166=>4944, +25182=>4945, +25187=>4946, +25179=>4947, +25184=>4948, +25192=>4949, +25212=>4950, +25218=>4951, +25225=>4952, +25214=>4953, +25234=>4954, +25235=>4955, +25238=>4956, +25300=>4957, +25219=>4958, +25236=>4959, +25303=>4960, +25297=>4961, +25275=>4962, +25295=>4963, +25343=>4964, +25286=>4965, +25812=>4966, +25288=>4967, +25308=>4968, +25292=>4969, +25290=>4970, +25282=>4971, +25287=>4972, +25243=>4973, +25289=>4974, +25356=>4975, +25326=>4976, +25329=>4977, +25383=>4978, +25346=>4979, +25352=>4980, +25327=>4981, +25333=>4982, +25424=>4983, +25406=>4984, +25421=>4985, +25628=>4986, +25423=>4987, +25494=>4988, +25486=>4989, +25472=>4990, +25515=>4991, +25462=>4992, +25507=>4993, +25487=>4994, +25481=>4995, +25503=>4996, +25525=>4997, +25451=>4998, +25449=>4999, +25534=>5000, +25577=>5001, +25536=>5002, +25542=>5003, +25571=>5004, +25545=>5005, +25554=>5006, +25590=>5007, +25540=>5008, +25622=>5009, +25652=>5010, +25606=>5011, +25619=>5012, +25638=>5013, +25654=>5014, +25885=>5015, +25623=>5016, +25640=>5017, +25615=>5018, +25703=>5019, +25711=>5020, +25718=>5021, +25678=>5022, +25898=>5023, +25749=>5024, +25747=>5025, +25765=>5026, +25769=>5027, +25736=>5028, +25788=>5029, +25818=>5030, +25810=>5031, +25797=>5032, +25799=>5033, +25787=>5034, +25816=>5035, +25794=>5036, +25841=>5037, +25831=>5038, +33289=>5039, +25824=>5040, +25825=>5041, +25260=>5042, +25827=>5043, +25839=>5044, +25900=>5045, +25846=>5046, +25844=>5047, +25842=>5048, +25850=>5049, +25856=>5050, +25853=>5051, +25880=>5052, +25884=>5053, +25861=>5054, +25892=>5055, +25891=>5056, +25899=>5057, +12097=>5058, +25908=>5058, +11929=>5059, +25909=>5059, +25911=>5060, +25910=>5061, +25912=>5062, +30027=>5063, +25928=>5064, +25942=>5065, +25941=>5066, +25933=>5067, +25944=>5068, +25950=>5069, +25949=>5070, +25970=>5071, +25976=>5072, +25986=>5073, +25987=>5074, +35722=>5075, +26011=>5076, +26015=>5077, +26027=>5078, +26039=>5079, +26051=>5080, +26054=>5081, +26049=>5082, +26052=>5083, +26060=>5084, +26066=>5085, +26075=>5086, +26073=>5087, +12102=>5088, +26080=>5088, +11931=>5089, +26081=>5089, +26097=>5090, +26482=>5091, +26122=>5092, +26115=>5093, +26107=>5094, +26483=>5095, +26165=>5096, +26166=>5097, +26164=>5098, +26140=>5099, +26191=>5100, +26180=>5101, +26185=>5102, +26177=>5103, +26206=>5104, +26205=>5105, +26212=>5106, +26215=>5107, +26216=>5108, +26207=>5109, +26210=>5110, +26224=>5111, +26243=>5112, +26248=>5113, +26254=>5114, +26249=>5115, +26244=>5116, +26264=>5117, +26269=>5118, +26305=>5119, +26297=>5120, +26313=>5121, +26302=>5122, +26300=>5123, +26308=>5124, +26296=>5125, +26326=>5126, +26330=>5127, +26336=>5128, +26175=>5129, +26342=>5130, +26345=>5131, +12104=>5132, +26352=>5132, +26357=>5133, +26359=>5134, +26383=>5135, +26390=>5136, +26398=>5137, +26406=>5138, +26407=>5139, +38712=>5140, +26414=>5141, +26431=>5142, +26422=>5143, +26433=>5144, +26424=>5145, +26423=>5146, +26438=>5147, +26462=>5148, +26464=>5149, +26457=>5150, +26467=>5151, +26468=>5152, +26505=>5153, +26480=>5154, +26537=>5155, +26492=>5156, +26474=>5157, +26508=>5158, +26507=>5159, +26534=>5160, +26529=>5161, +26501=>5162, +26551=>5163, +26607=>5164, +26548=>5165, +26604=>5166, +26547=>5167, +26601=>5168, +26552=>5169, +26596=>5170, +26590=>5171, +26589=>5172, +26594=>5173, +26606=>5174, +26553=>5175, +26574=>5176, +26566=>5177, +26599=>5178, +27292=>5179, +26654=>5180, +26694=>5181, +26665=>5182, +26688=>5183, +26701=>5184, +26674=>5185, +26702=>5186, +26803=>5187, +26667=>5188, +26713=>5189, +26723=>5190, +26743=>5191, +26751=>5192, +26783=>5193, +26767=>5194, +26797=>5195, +26772=>5196, +26781=>5197, +26779=>5198, +26755=>5199, +27310=>5200, +26809=>5201, +26740=>5202, +26805=>5203, +26784=>5204, +26810=>5205, +26895=>5206, +26765=>5207, +26750=>5208, +26881=>5209, +26826=>5210, +26888=>5211, +26840=>5212, +26914=>5213, +26918=>5214, +26849=>5215, +26892=>5216, +26829=>5217, +26836=>5218, +26855=>5219, +26837=>5220, +26934=>5221, +26898=>5222, +26884=>5223, +26839=>5224, +26851=>5225, +26917=>5226, +26873=>5227, +26848=>5228, +26863=>5229, +26920=>5230, +26922=>5231, +26906=>5232, +26915=>5233, +26913=>5234, +26822=>5235, +27001=>5236, +26999=>5237, +26972=>5238, +27000=>5239, +26987=>5240, +26964=>5241, +27006=>5242, +26990=>5243, +26937=>5244, +26996=>5245, +26941=>5246, +26969=>5247, +26928=>5248, +26977=>5249, +26974=>5250, +26973=>5251, +27009=>5252, +26986=>5253, +27058=>5254, +27054=>5255, +27088=>5256, +27071=>5257, +27073=>5258, +27091=>5259, +27070=>5260, +27086=>5261, +23528=>5262, +27082=>5263, +27101=>5264, +27067=>5265, +27075=>5266, +27047=>5267, +27182=>5268, +27025=>5269, +27040=>5270, +27036=>5271, +27029=>5272, +27060=>5273, +27102=>5274, +27112=>5275, +27138=>5276, +27163=>5277, +27135=>5278, +27402=>5279, +27129=>5280, +27122=>5281, +27111=>5282, +27141=>5283, +27057=>5284, +27166=>5285, +27117=>5286, +27156=>5287, +27115=>5288, +27146=>5289, +27154=>5290, +27329=>5291, +27171=>5292, +27155=>5293, +27204=>5294, +27148=>5295, +27250=>5296, +27190=>5297, +27256=>5298, +27207=>5299, +27234=>5300, +27225=>5301, +27238=>5302, +27208=>5303, +27192=>5304, +27170=>5305, +27280=>5306, +27277=>5307, +27296=>5308, +27268=>5309, +27298=>5310, +27299=>5311, +27287=>5312, +34327=>5313, +27323=>5314, +27331=>5315, +27330=>5316, +27320=>5317, +27315=>5318, +27308=>5319, +27358=>5320, +27345=>5321, +27359=>5322, +27306=>5323, +27354=>5324, +27370=>5325, +27387=>5326, +27397=>5327, +34326=>5328, +27386=>5329, +27410=>5330, +27414=>5331, +39729=>5332, +27423=>5333, +27448=>5334, +27447=>5335, +30428=>5336, +27449=>5337, +39150=>5338, +27463=>5339, +27459=>5340, +27465=>5341, +27472=>5342, +27481=>5343, +27476=>5344, +27483=>5345, +27487=>5346, +27489=>5347, +27512=>5348, +12109=>5349, +27513=>5349, +27519=>5350, +27520=>5351, +27524=>5352, +27523=>5353, +27533=>5354, +27544=>5355, +27541=>5356, +27550=>5357, +27556=>5358, +27562=>5359, +27563=>5360, +27567=>5361, +27570=>5362, +27569=>5363, +12110=>5364, +27571=>5364, +27575=>5365, +27580=>5366, +27590=>5367, +12111=>5368, +27595=>5368, +27603=>5369, +27615=>5370, +27628=>5371, +27627=>5372, +27635=>5373, +27631=>5374, +40638=>5375, +27656=>5376, +27667=>5377, +12115=>5378, +27668=>5378, +27675=>5379, +27684=>5380, +27683=>5381, +27742=>5382, +27733=>5383, +27746=>5384, +27754=>5385, +27778=>5386, +27789=>5387, +27802=>5388, +27777=>5389, +27803=>5390, +27774=>5391, +27752=>5392, +27763=>5393, +27794=>5394, +27792=>5395, +27844=>5396, +27889=>5397, +27859=>5398, +27837=>5399, +27863=>5400, +27845=>5401, +27869=>5402, +27822=>5403, +27825=>5404, +27838=>5405, +27834=>5406, +27867=>5407, +27887=>5408, +27865=>5409, +27882=>5410, +27935=>5411, +34893=>5412, +27958=>5413, +27947=>5414, +27965=>5415, +27960=>5416, +27929=>5417, +27957=>5418, +27955=>5419, +27922=>5420, +27916=>5421, +28003=>5422, +28051=>5423, +28004=>5424, +27994=>5425, +28025=>5426, +27993=>5427, +28046=>5428, +28053=>5429, +28644=>5430, +28037=>5431, +28153=>5432, +28181=>5433, +28170=>5434, +28085=>5435, +28103=>5436, +28134=>5437, +28088=>5438, +28102=>5439, +28140=>5440, +28126=>5441, +28108=>5442, +28136=>5443, +28114=>5444, +28101=>5445, +28154=>5446, +28121=>5447, +28132=>5448, +28117=>5449, +28138=>5450, +28142=>5451, +28205=>5452, +28270=>5453, +28206=>5454, +28185=>5455, +28274=>5456, +28255=>5457, +28222=>5458, +28195=>5459, +28267=>5460, +28203=>5461, +28278=>5462, +28237=>5463, +28191=>5464, +28227=>5465, +28218=>5466, +28238=>5467, +28196=>5468, +28415=>5469, +28189=>5470, +28216=>5471, +28290=>5472, +28330=>5473, +28312=>5474, +28361=>5475, +28343=>5476, +28371=>5477, +28349=>5478, +28335=>5479, +28356=>5480, +28338=>5481, +28372=>5482, +28373=>5483, +28303=>5484, +28325=>5485, +28354=>5486, +28319=>5487, +28481=>5488, +28433=>5489, +28748=>5490, +28396=>5491, +28408=>5492, +28414=>5493, +28479=>5494, +28402=>5495, +28465=>5496, +28399=>5497, +28466=>5498, +28364=>5499, +28478=>5500, +28435=>5501, +28407=>5502, +28550=>5503, +28538=>5504, +28536=>5505, +28545=>5506, +28544=>5507, +28527=>5508, +28507=>5509, +28659=>5510, +28525=>5511, +28546=>5512, +28540=>5513, +28504=>5514, +28558=>5515, +28561=>5516, +28610=>5517, +28518=>5518, +28595=>5519, +28579=>5520, +28577=>5521, +28580=>5522, +28601=>5523, +28614=>5524, +28586=>5525, +28639=>5526, +28629=>5527, +28652=>5528, +28628=>5529, +28632=>5530, +28657=>5531, +28654=>5532, +28635=>5533, +28681=>5534, +28683=>5535, +28666=>5536, +28689=>5537, +28673=>5538, +28687=>5539, +28670=>5540, +28699=>5541, +28698=>5542, +28532=>5543, +28701=>5544, +28696=>5545, +28703=>5546, +28720=>5547, +28734=>5548, +28722=>5549, +28753=>5550, +28771=>5551, +28825=>5552, +28818=>5553, +28847=>5554, +28913=>5555, +28844=>5556, +28856=>5557, +28851=>5558, +28846=>5559, +28895=>5560, +28875=>5561, +28893=>5562, +28889=>5563, +28937=>5564, +28925=>5565, +28956=>5566, +28953=>5567, +29029=>5568, +29013=>5569, +29064=>5570, +29030=>5571, +29026=>5572, +29004=>5573, +29014=>5574, +29036=>5575, +29071=>5576, +29179=>5577, +29060=>5578, +29077=>5579, +29096=>5580, +29100=>5581, +29143=>5582, +29113=>5583, +29118=>5584, +29138=>5585, +29129=>5586, +29140=>5587, +29134=>5588, +29152=>5589, +29164=>5590, +29159=>5591, +29173=>5592, +29180=>5593, +29177=>5594, +29183=>5595, +29197=>5596, +29200=>5597, +29211=>5598, +29224=>5599, +29229=>5600, +29228=>5601, +29232=>5602, +29234=>5603, +12120=>5604, +29243=>5604, +29244=>5605, +12121=>5606, +29247=>5606, +29248=>5607, +29254=>5608, +29259=>5609, +29272=>5610, +29300=>5611, +29310=>5612, +29314=>5613, +29313=>5614, +29319=>5615, +29330=>5616, +29334=>5617, +29346=>5618, +29351=>5619, +29369=>5620, +29362=>5621, +29379=>5622, +29382=>5623, +29380=>5624, +29390=>5625, +29394=>5626, +29410=>5627, +29408=>5628, +29409=>5629, +29433=>5630, +29431=>5631, +20495=>5632, +29463=>5633, +29450=>5634, +29468=>5635, +29462=>5636, +29469=>5637, +29492=>5638, +29487=>5639, +29481=>5640, +29477=>5641, +29502=>5642, +29518=>5643, +29519=>5644, +40664=>5645, +29527=>5646, +29546=>5647, +29544=>5648, +29552=>5649, +29560=>5650, +29557=>5651, +29563=>5652, +29562=>5653, +29640=>5654, +29619=>5655, +29646=>5656, +29627=>5657, +29632=>5658, +29669=>5659, +29678=>5660, +29662=>5661, +29858=>5662, +29701=>5663, +29807=>5664, +29733=>5665, +29688=>5666, +29746=>5667, +29754=>5668, +29781=>5669, +29759=>5670, +29791=>5671, +29785=>5672, +29761=>5673, +29788=>5674, +29801=>5675, +29808=>5676, +29795=>5677, +29802=>5678, +29814=>5679, +29822=>5680, +29835=>5681, +29854=>5682, +29863=>5683, +29898=>5684, +29903=>5685, +29908=>5686, +29681=>5687, +29920=>5688, +29923=>5689, +29927=>5690, +29929=>5691, +29934=>5692, +29938=>5693, +29936=>5694, +29937=>5695, +29944=>5696, +29943=>5697, +29956=>5698, +29955=>5699, +29957=>5700, +29964=>5701, +29966=>5702, +29965=>5703, +29973=>5704, +29971=>5705, +29982=>5706, +29990=>5707, +29996=>5708, +30012=>5709, +30020=>5710, +30029=>5711, +30026=>5712, +30025=>5713, +30043=>5714, +30022=>5715, +30042=>5716, +30057=>5717, +30052=>5718, +30055=>5719, +30059=>5720, +30061=>5721, +30072=>5722, +30070=>5723, +30086=>5724, +30087=>5725, +30068=>5726, +30090=>5727, +30089=>5728, +30082=>5729, +30100=>5730, +30106=>5731, +30109=>5732, +30117=>5733, +30115=>5734, +30146=>5735, +30131=>5736, +30147=>5737, +30133=>5738, +30141=>5739, +30136=>5740, +30140=>5741, +30129=>5742, +30157=>5743, +30154=>5744, +30162=>5745, +30169=>5746, +30179=>5747, +30174=>5748, +30206=>5749, +30207=>5750, +30204=>5751, +30209=>5752, +30192=>5753, +30202=>5754, +30194=>5755, +30195=>5756, +30219=>5757, +30221=>5758, +30217=>5759, +30239=>5760, +30247=>5761, +30240=>5762, +30241=>5763, +30242=>5764, +30244=>5765, +30260=>5766, +30256=>5767, +30267=>5768, +30279=>5769, +30280=>5770, +30278=>5771, +30300=>5772, +30296=>5773, +30305=>5774, +30306=>5775, +30312=>5776, +30313=>5777, +30314=>5778, +30311=>5779, +30316=>5780, +30320=>5781, +30322=>5782, +12136=>5783, +30326=>5783, +30328=>5784, +30332=>5785, +30336=>5786, +30339=>5787, +30344=>5788, +30347=>5789, +30350=>5790, +30358=>5791, +30355=>5792, +30361=>5793, +30362=>5794, +30384=>5795, +30388=>5796, +30392=>5797, +30393=>5798, +30394=>5799, +30402=>5800, +30413=>5801, +30422=>5802, +30418=>5803, +30430=>5804, +30433=>5805, +30437=>5806, +30439=>5807, +30442=>5808, +34351=>5809, +30459=>5810, +30472=>5811, +30471=>5812, +30468=>5813, +30505=>5814, +30500=>5815, +30494=>5816, +30501=>5817, +30502=>5818, +30491=>5819, +30519=>5820, +30520=>5821, +30535=>5822, +30554=>5823, +30568=>5824, +30571=>5825, +30555=>5826, +30565=>5827, +30591=>5828, +30590=>5829, +30585=>5830, +30606=>5831, +30603=>5832, +30609=>5833, +30624=>5834, +30622=>5835, +30640=>5836, +30646=>5837, +30649=>5838, +30655=>5839, +30652=>5840, +30653=>5841, +30651=>5842, +30663=>5843, +30669=>5844, +30679=>5845, +30682=>5846, +30684=>5847, +30691=>5848, +30702=>5849, +30716=>5850, +30732=>5851, +30738=>5852, +31014=>5853, +30752=>5854, +31018=>5855, +30789=>5856, +30862=>5857, +30836=>5858, +30854=>5859, +30844=>5860, +30874=>5861, +30860=>5862, +30883=>5863, +30901=>5864, +30890=>5865, +30895=>5866, +30929=>5867, +30918=>5868, +30923=>5869, +30932=>5870, +30910=>5871, +30908=>5872, +30917=>5873, +30922=>5874, +30956=>5875, +30951=>5876, +30938=>5877, +30973=>5878, +30964=>5879, +30983=>5880, +30994=>5881, +30993=>5882, +31001=>5883, +31020=>5884, +31019=>5885, +31040=>5886, +31072=>5887, +31063=>5888, +31071=>5889, +31066=>5890, +31061=>5891, +31059=>5892, +31098=>5893, +31103=>5894, +31114=>5895, +31133=>5896, +31143=>5897, +40779=>5898, +31146=>5899, +31150=>5900, +31155=>5901, +31161=>5902, +31162=>5903, +31177=>5904, +31189=>5905, +31207=>5906, +31212=>5907, +31201=>5908, +31203=>5909, +31240=>5910, +31245=>5911, +31256=>5912, +31257=>5913, +31264=>5914, +31263=>5915, +31104=>5916, +31281=>5917, +31291=>5918, +31294=>5919, +31287=>5920, +31299=>5921, +31319=>5922, +31305=>5923, +31329=>5924, +31330=>5925, +31337=>5926, +40861=>5927, +31344=>5928, +31353=>5929, +31357=>5930, +31368=>5931, +31383=>5932, +31381=>5933, +31384=>5934, +31382=>5935, +31401=>5936, +31432=>5937, +31408=>5938, +31414=>5939, +31429=>5940, +31428=>5941, +31423=>5942, +36995=>5943, +31431=>5944, +31434=>5945, +31437=>5946, +31439=>5947, +31445=>5948, +31443=>5949, +31449=>5950, +31450=>5951, +31453=>5952, +31457=>5953, +31458=>5954, +31462=>5955, +31469=>5956, +31472=>5957, +31490=>5958, +31503=>5959, +31498=>5960, +31494=>5961, +31539=>5962, +31512=>5963, +31513=>5964, +31518=>5965, +31541=>5966, +31528=>5967, +31542=>5968, +31568=>5969, +31610=>5970, +31492=>5971, +31565=>5972, +31499=>5973, +31564=>5974, +31557=>5975, +31605=>5976, +31589=>5977, +31604=>5978, +31591=>5979, +31600=>5980, +31601=>5981, +31596=>5982, +31598=>5983, +31645=>5984, +31640=>5985, +31647=>5986, +31629=>5987, +31644=>5988, +31642=>5989, +31627=>5990, +31634=>5991, +31631=>5992, +31581=>5993, +31641=>5994, +31691=>5995, +31681=>5996, +31692=>5997, +31695=>5998, +31668=>5999, +31686=>6000, +31709=>6001, +31721=>6002, +31761=>6003, +31764=>6004, +31718=>6005, +31717=>6006, +31840=>6007, +31744=>6008, +31751=>6009, +31763=>6010, +31731=>6011, +31735=>6012, +31767=>6013, +31757=>6014, +31734=>6015, +31779=>6016, +31783=>6017, +31786=>6018, +31775=>6019, +31799=>6020, +31787=>6021, +31805=>6022, +31820=>6023, +31811=>6024, +31828=>6025, +31823=>6026, +31808=>6027, +31824=>6028, +31832=>6029, +31839=>6030, +31844=>6031, +31830=>6032, +31845=>6033, +31852=>6034, +31861=>6035, +31875=>6036, +31888=>6037, +31908=>6038, +31917=>6039, +31906=>6040, +31915=>6041, +31905=>6042, +31912=>6043, +31923=>6044, +31922=>6045, +31921=>6046, +31918=>6047, +31929=>6048, +31933=>6049, +31936=>6050, +31941=>6051, +31938=>6052, +31960=>6053, +31954=>6054, +31964=>6055, +31970=>6056, +39739=>6057, +31983=>6058, +31986=>6059, +31988=>6060, +31990=>6061, +31994=>6062, +32006=>6063, +32002=>6064, +32028=>6065, +32021=>6066, +32010=>6067, +32069=>6068, +32075=>6069, +32046=>6070, +32050=>6071, +32063=>6072, +32053=>6073, +32070=>6074, +32115=>6075, +32086=>6076, +32078=>6077, +32114=>6078, +32104=>6079, +32110=>6080, +32079=>6081, +32099=>6082, +32147=>6083, +32137=>6084, +32091=>6085, +32143=>6086, +32125=>6087, +32155=>6088, +32186=>6089, +32174=>6090, +32163=>6091, +32181=>6092, +32199=>6093, +32189=>6094, +32171=>6095, +32317=>6096, +32162=>6097, +32175=>6098, +32220=>6099, +32184=>6100, +32159=>6101, +32176=>6102, +32216=>6103, +32221=>6104, +32228=>6105, +32222=>6106, +32251=>6107, +32242=>6108, +32225=>6109, +32261=>6110, +32266=>6111, +32291=>6112, +32289=>6113, +32274=>6114, +32305=>6115, +32287=>6116, +32265=>6117, +32267=>6118, +32290=>6119, +32326=>6120, +32358=>6121, +32315=>6122, +32309=>6123, +32313=>6124, +32323=>6125, +32311=>6126, +32306=>6127, +32314=>6128, +32359=>6129, +32349=>6130, +32342=>6131, +32350=>6132, +32345=>6133, +32346=>6134, +32377=>6135, +32362=>6136, +32361=>6137, +32380=>6138, +32379=>6139, +32387=>6140, +32213=>6141, +32381=>6142, +36782=>6143, +32383=>6144, +32392=>6145, +32393=>6146, +32396=>6147, +32402=>6148, +32400=>6149, +32403=>6150, +32404=>6151, +32406=>6152, +32398=>6153, +32411=>6154, +32412=>6155, +32568=>6156, +32570=>6157, +32581=>6158, +32588=>6159, +32589=>6160, +32590=>6161, +32592=>6162, +12153=>6163, +32593=>6163, +32597=>6164, +32596=>6165, +32600=>6166, +32607=>6167, +32608=>6168, +32616=>6169, +32617=>6170, +32615=>6171, +32632=>6172, +32642=>6173, +32646=>6174, +32643=>6175, +32648=>6176, +32647=>6177, +32652=>6178, +32660=>6179, +32670=>6180, +32669=>6181, +32666=>6182, +32675=>6183, +32687=>6184, +32690=>6185, +32697=>6186, +32686=>6187, +32694=>6188, +32696=>6189, +35697=>6190, +32709=>6191, +32710=>6192, +32714=>6193, +32725=>6194, +32724=>6195, +32737=>6196, +32742=>6197, +32745=>6198, +32755=>6199, +32761=>6200, +39132=>6201, +32774=>6202, +32772=>6203, +32779=>6204, +12158=>6205, +32786=>6205, +32792=>6206, +32793=>6207, +32796=>6208, +32801=>6209, +32808=>6210, +32831=>6211, +32827=>6212, +32842=>6213, +32838=>6214, +32850=>6215, +32856=>6216, +32858=>6217, +32863=>6218, +32866=>6219, +32872=>6220, +32883=>6221, +32882=>6222, +32880=>6223, +32886=>6224, +32889=>6225, +32893=>6226, +12160=>6227, +32895=>6227, +32900=>6228, +32902=>6229, +32901=>6230, +32923=>6231, +32915=>6232, +32922=>6233, +32941=>6234, +20880=>6235, +32940=>6236, +32987=>6237, +32997=>6238, +32985=>6239, +32989=>6240, +32964=>6241, +32986=>6242, +32982=>6243, +33033=>6244, +33007=>6245, +33009=>6246, +33051=>6247, +33065=>6248, +33059=>6249, +33071=>6250, +33099=>6251, +38539=>6252, +33094=>6253, +33086=>6254, +33107=>6255, +33105=>6256, +33020=>6257, +33137=>6258, +33134=>6259, +33125=>6260, +33126=>6261, +33140=>6262, +33155=>6263, +33160=>6264, +33162=>6265, +33152=>6266, +33154=>6267, +33184=>6268, +33173=>6269, +33188=>6270, +33187=>6271, +33119=>6272, +33171=>6273, +33193=>6274, +33200=>6275, +33205=>6276, +33214=>6277, +33208=>6278, +33213=>6279, +33216=>6280, +33218=>6281, +33210=>6282, +33225=>6283, +33229=>6284, +33233=>6285, +33241=>6286, +33240=>6287, +33224=>6288, +33242=>6289, +33247=>6290, +33248=>6291, +33255=>6292, +33274=>6293, +33275=>6294, +33278=>6295, +33281=>6296, +33282=>6297, +33285=>6298, +33287=>6299, +33290=>6300, +33293=>6301, +33296=>6302, +33302=>6303, +33321=>6304, +33323=>6305, +33336=>6306, +33331=>6307, +33344=>6308, +33369=>6309, +33368=>6310, +33373=>6311, +33370=>6312, +33375=>6313, +33380=>6314, +33378=>6315, +33384=>6316, +33386=>6317, +33387=>6318, +33326=>6319, +33393=>6320, +33399=>6321, +12171=>6322, +33400=>6322, +33406=>6323, +33421=>6324, +33426=>6325, +33451=>6326, +33439=>6327, +33467=>6328, +33452=>6329, +33505=>6330, +33507=>6331, +33503=>6332, +33490=>6333, +33524=>6334, +33523=>6335, +33530=>6336, +33683=>6337, +33539=>6338, +33531=>6339, +33529=>6340, +33502=>6341, +33542=>6342, +33500=>6343, +33545=>6344, +33497=>6345, +33589=>6346, +33588=>6347, +33558=>6348, +33586=>6349, +33585=>6350, +33600=>6351, +33593=>6352, +33616=>6353, +33605=>6354, +33583=>6355, +33579=>6356, +33559=>6357, +33560=>6358, +33669=>6359, +33690=>6360, +33706=>6361, +33695=>6362, +33698=>6363, +33686=>6364, +33571=>6365, +33678=>6366, +33671=>6367, +33674=>6368, +33660=>6369, +33717=>6370, +33651=>6371, +33653=>6372, +33696=>6373, +33673=>6374, +33704=>6375, +33780=>6376, +33811=>6377, +33771=>6378, +33742=>6379, +33789=>6380, +33795=>6381, +33752=>6382, +33803=>6383, +33729=>6384, +33783=>6385, +33799=>6386, +33760=>6387, +33778=>6388, +33805=>6389, +33826=>6390, +33824=>6391, +33725=>6392, +33848=>6393, +34054=>6394, +33787=>6395, +33901=>6396, +33834=>6397, +33852=>6398, +34138=>6399, +33924=>6400, +33911=>6401, +33899=>6402, +33965=>6403, +33902=>6404, +33922=>6405, +33897=>6406, +33862=>6407, +33836=>6408, +33903=>6409, +33913=>6410, +33845=>6411, +33994=>6412, +33890=>6413, +33977=>6414, +33983=>6415, +33951=>6416, +34009=>6417, +33997=>6418, +33979=>6419, +34010=>6420, +34000=>6421, +33985=>6422, +33990=>6423, +34006=>6424, +33953=>6425, +34081=>6426, +34047=>6427, +34036=>6428, +34071=>6429, +34072=>6430, +34092=>6431, +34079=>6432, +34069=>6433, +34068=>6434, +34044=>6435, +34112=>6436, +34147=>6437, +34136=>6438, +34120=>6439, +34113=>6440, +34306=>6441, +34123=>6442, +34133=>6443, +34176=>6444, +34212=>6445, +34184=>6446, +34193=>6447, +34186=>6448, +34216=>6449, +34157=>6450, +34196=>6451, +34203=>6452, +34282=>6453, +34183=>6454, +34204=>6455, +34167=>6456, +34174=>6457, +34192=>6458, +34249=>6459, +34234=>6460, +34255=>6461, +34233=>6462, +34256=>6463, +34261=>6464, +34269=>6465, +34277=>6466, +34268=>6467, +34297=>6468, +34314=>6469, +34323=>6470, +34315=>6471, +34302=>6472, +34298=>6473, +34310=>6474, +34338=>6475, +34330=>6476, +34352=>6477, +34367=>6478, +12172=>6479, +34381=>6479, +20053=>6480, +34388=>6481, +34399=>6482, +34407=>6483, +34417=>6484, +34451=>6485, +34467=>6486, +34473=>6487, +34474=>6488, +34443=>6489, +34444=>6490, +34486=>6491, +34479=>6492, +34500=>6493, +34502=>6494, +34480=>6495, +34505=>6496, +34851=>6497, +34475=>6498, +34516=>6499, +34526=>6500, +34537=>6501, +34540=>6502, +34527=>6503, +34523=>6504, +34543=>6505, +34578=>6506, +34566=>6507, +34568=>6508, +34560=>6509, +34563=>6510, +34555=>6511, +34577=>6512, +34569=>6513, +34573=>6514, +34553=>6515, +34570=>6516, +34612=>6517, +34623=>6518, +34615=>6519, +34619=>6520, +34597=>6521, +34601=>6522, +34586=>6523, +34656=>6524, +34655=>6525, +34680=>6526, +34636=>6527, +34638=>6528, +34676=>6529, +34647=>6530, +34664=>6531, +34670=>6532, +34649=>6533, +34643=>6534, +34659=>6535, +34666=>6536, +34821=>6537, +34722=>6538, +34719=>6539, +34690=>6540, +34735=>6541, +34763=>6542, +34749=>6543, +34752=>6544, +34768=>6545, +38614=>6546, +34731=>6547, +34756=>6548, +34739=>6549, +34759=>6550, +34758=>6551, +34747=>6552, +34799=>6553, +34802=>6554, +34784=>6555, +34831=>6556, +34829=>6557, +34814=>6558, +34806=>6559, +34807=>6560, +34830=>6561, +34770=>6562, +34833=>6563, +34838=>6564, +34837=>6565, +34850=>6566, +34849=>6567, +34865=>6568, +34870=>6569, +34873=>6570, +34855=>6571, +34875=>6572, +34884=>6573, +34882=>6574, +34898=>6575, +34905=>6576, +34910=>6577, +34914=>6578, +34923=>6579, +34945=>6580, +34942=>6581, +34974=>6582, +34933=>6583, +34941=>6584, +34997=>6585, +34930=>6586, +34946=>6587, +34967=>6588, +34962=>6589, +34990=>6590, +34969=>6591, +34978=>6592, +34957=>6593, +34980=>6594, +34992=>6595, +35007=>6596, +34993=>6597, +35011=>6598, +35012=>6599, +35028=>6600, +35032=>6601, +35033=>6602, +35037=>6603, +35065=>6604, +35074=>6605, +35068=>6606, +35060=>6607, +35048=>6608, +35058=>6609, +35076=>6610, +35084=>6611, +35082=>6612, +35091=>6613, +35139=>6614, +35102=>6615, +35109=>6616, +35114=>6617, +35115=>6618, +35137=>6619, +35140=>6620, +35131=>6621, +35126=>6622, +35128=>6623, +35148=>6624, +35101=>6625, +35168=>6626, +35166=>6627, +35174=>6628, +35172=>6629, +35181=>6630, +35178=>6631, +35183=>6632, +35188=>6633, +35191=>6634, +12177=>6635, +35198=>6635, +35203=>6636, +35208=>6637, +35210=>6638, +35219=>6639, +35224=>6640, +35233=>6641, +35241=>6642, +35238=>6643, +35244=>6644, +35247=>6645, +35250=>6646, +35258=>6647, +35261=>6648, +35263=>6649, +35264=>6650, +35290=>6651, +35292=>6652, +35293=>6653, +35303=>6654, +35316=>6655, +35320=>6656, +35331=>6657, +35350=>6658, +35344=>6659, +35340=>6660, +35355=>6661, +35357=>6662, +35365=>6663, +35382=>6664, +35393=>6665, +35419=>6666, +35410=>6667, +35398=>6668, +35400=>6669, +35452=>6670, +35437=>6671, +35436=>6672, +35426=>6673, +35461=>6674, +35458=>6675, +35460=>6676, +35496=>6677, +35489=>6678, +35473=>6679, +35493=>6680, +35494=>6681, +35482=>6682, +35491=>6683, +35524=>6684, +35533=>6685, +35522=>6686, +35546=>6687, +35563=>6688, +35571=>6689, +35559=>6690, +35556=>6691, +35569=>6692, +35604=>6693, +35552=>6694, +35554=>6695, +35575=>6696, +35550=>6697, +35547=>6698, +35596=>6699, +35591=>6700, +35610=>6701, +35553=>6702, +35606=>6703, +35600=>6704, +35607=>6705, +35616=>6706, +35635=>6707, +38827=>6708, +35622=>6709, +35627=>6710, +35646=>6711, +35624=>6712, +35649=>6713, +35660=>6714, +35663=>6715, +35662=>6716, +35657=>6717, +35670=>6718, +35675=>6719, +35674=>6720, +35691=>6721, +35679=>6722, +35692=>6723, +35695=>6724, +35700=>6725, +35709=>6726, +35712=>6727, +35724=>6728, +35726=>6729, +35730=>6730, +35731=>6731, +35734=>6732, +35737=>6733, +35738=>6734, +35898=>6735, +35905=>6736, +35903=>6737, +35912=>6738, +35916=>6739, +35918=>6740, +35920=>6741, +12183=>6742, +35925=>6742, +35938=>6743, +35948=>6744, +12184=>6745, +35960=>6745, +35962=>6746, +35970=>6747, +35977=>6748, +35973=>6749, +35978=>6750, +35981=>6751, +35982=>6752, +35988=>6753, +35964=>6754, +35992=>6755, +25117=>6756, +36013=>6757, +36010=>6758, +36029=>6759, +36018=>6760, +36019=>6761, +36014=>6762, +36022=>6763, +36040=>6764, +36033=>6765, +36068=>6766, +36067=>6767, +36058=>6768, +36093=>6769, +36090=>6770, +36091=>6771, +36100=>6772, +36101=>6773, +36106=>6774, +36103=>6775, +36111=>6776, +36109=>6777, +36112=>6778, +40782=>6779, +36115=>6780, +36045=>6781, +36116=>6782, +36118=>6783, +36199=>6784, +36205=>6785, +36209=>6786, +36211=>6787, +36225=>6788, +36249=>6789, +36290=>6790, +36286=>6791, +36282=>6792, +36303=>6793, +36314=>6794, +36310=>6795, +36300=>6796, +36315=>6797, +36299=>6798, +36330=>6799, +36331=>6800, +36319=>6801, +36323=>6802, +36348=>6803, +36360=>6804, +36361=>6805, +36351=>6806, +36381=>6807, +36382=>6808, +36368=>6809, +36383=>6810, +36418=>6811, +36405=>6812, +36400=>6813, +36404=>6814, +36426=>6815, +36423=>6816, +36425=>6817, +36428=>6818, +36432=>6819, +36424=>6820, +36441=>6821, +36452=>6822, +36448=>6823, +36394=>6824, +36451=>6825, +36437=>6826, +36470=>6827, +36466=>6828, +36476=>6829, +36481=>6830, +36487=>6831, +36485=>6832, +36484=>6833, +36491=>6834, +36490=>6835, +36499=>6836, +36497=>6837, +36500=>6838, +36505=>6839, +36522=>6840, +36513=>6841, +36524=>6842, +36528=>6843, +36550=>6844, +36529=>6845, +36542=>6846, +36549=>6847, +36552=>6848, +36555=>6849, +36571=>6850, +36579=>6851, +36604=>6852, +36603=>6853, +36587=>6854, +36606=>6855, +36618=>6856, +36613=>6857, +36629=>6858, +36626=>6859, +36633=>6860, +36627=>6861, +36636=>6862, +36639=>6863, +36635=>6864, +36620=>6865, +36646=>6866, +36659=>6867, +36667=>6868, +36665=>6869, +36677=>6870, +36674=>6871, +36670=>6872, +36684=>6873, +36681=>6874, +36678=>6875, +36686=>6876, +36695=>6877, +36700=>6878, +36706=>6879, +36707=>6880, +36708=>6881, +36764=>6882, +36767=>6883, +36771=>6884, +36781=>6885, +36783=>6886, +36791=>6887, +36826=>6888, +36837=>6889, +36834=>6890, +36842=>6891, +36847=>6892, +36999=>6893, +36852=>6894, +36869=>6895, +36857=>6896, +36858=>6897, +36881=>6898, +36885=>6899, +36897=>6900, +36877=>6901, +36894=>6902, +36886=>6903, +36875=>6904, +36903=>6905, +36918=>6906, +36917=>6907, +36921=>6908, +36856=>6909, +36943=>6910, +36944=>6911, +36945=>6912, +36946=>6913, +36878=>6914, +36937=>6915, +36926=>6916, +36950=>6917, +36952=>6918, +36958=>6919, +36968=>6920, +36975=>6921, +36982=>6922, +38568=>6923, +36978=>6924, +36994=>6925, +36989=>6926, +36993=>6927, +36992=>6928, +37002=>6929, +37001=>6930, +37007=>6931, +37032=>6932, +37039=>6933, +37041=>6934, +37045=>6935, +37090=>6936, +37092=>6937, +25160=>6938, +37083=>6939, +37122=>6940, +37138=>6941, +37145=>6942, +37170=>6943, +37168=>6944, +37194=>6945, +37206=>6946, +37208=>6947, +37219=>6948, +37221=>6949, +37225=>6950, +37235=>6951, +37234=>6952, +37259=>6953, +37257=>6954, +37250=>6955, +37282=>6956, +37291=>6957, +37295=>6958, +37290=>6959, +37301=>6960, +37300=>6961, +37306=>6962, +37312=>6963, +37313=>6964, +37321=>6965, +37323=>6966, +37328=>6967, +37334=>6968, +37343=>6969, +37345=>6970, +37339=>6971, +37372=>6972, +37365=>6973, +37366=>6974, +37406=>6975, +37375=>6976, +37396=>6977, +37420=>6978, +37397=>6979, +37393=>6980, +37470=>6981, +37463=>6982, +37445=>6983, +37449=>6984, +37476=>6985, +37448=>6986, +37525=>6987, +37439=>6988, +37451=>6989, +37456=>6990, +37532=>6991, +37526=>6992, +37523=>6993, +37531=>6994, +37466=>6995, +37583=>6996, +37561=>6997, +37559=>6998, +37609=>6999, +37647=>7000, +37626=>7001, +37700=>7002, +37678=>7003, +37657=>7004, +37666=>7005, +37658=>7006, +37667=>7007, +37690=>7008, +37685=>7009, +37691=>7010, +37724=>7011, +37728=>7012, +37756=>7013, +37742=>7014, +37718=>7015, +37808=>7016, +37804=>7017, +37805=>7018, +37780=>7019, +37817=>7020, +37846=>7021, +37847=>7022, +37864=>7023, +37861=>7024, +37848=>7025, +37827=>7026, +37853=>7027, +37840=>7028, +37832=>7029, +37860=>7030, +37914=>7031, +37908=>7032, +37907=>7033, +37891=>7034, +37895=>7035, +37904=>7036, +37942=>7037, +37931=>7038, +37941=>7039, +37921=>7040, +37946=>7041, +37953=>7042, +37970=>7043, +37956=>7044, +37979=>7045, +37984=>7046, +37986=>7047, +37982=>7048, +37994=>7049, +37417=>7050, +38000=>7051, +38005=>7052, +38007=>7053, +38013=>7054, +37978=>7055, +38012=>7056, +38014=>7057, +38017=>7058, +38015=>7059, +38274=>7060, +38279=>7061, +38282=>7062, +38292=>7063, +38294=>7064, +38296=>7065, +38297=>7066, +38304=>7067, +38312=>7068, +38311=>7069, +38317=>7070, +38332=>7071, +38331=>7072, +38329=>7073, +38334=>7074, +38346=>7075, +28662=>7076, +38339=>7077, +38349=>7078, +38348=>7079, +38357=>7080, +38356=>7081, +38358=>7082, +38364=>7083, +38369=>7084, +38373=>7085, +38370=>7086, +38433=>7087, +38440=>7088, +38446=>7089, +38447=>7090, +38466=>7091, +38476=>7092, +38479=>7093, +38475=>7094, +38519=>7095, +38492=>7096, +38494=>7097, +38493=>7098, +38495=>7099, +38502=>7100, +38514=>7101, +38508=>7102, +38541=>7103, +38552=>7104, +38549=>7105, +38551=>7106, +38570=>7107, +38567=>7108, +38577=>7109, +38578=>7110, +38576=>7111, +38580=>7112, +12202=>7113, +38582=>7113, +38584=>7114, +12203=>7115, +38585=>7115, +38606=>7116, +38603=>7117, +38601=>7118, +38605=>7119, +35149=>7120, +38620=>7121, +38669=>7122, +38613=>7123, +38649=>7124, +38660=>7125, +38662=>7126, +38664=>7127, +38675=>7128, +38670=>7129, +38673=>7130, +38671=>7131, +38678=>7132, +38681=>7133, +38692=>7134, +38698=>7135, +38704=>7136, +38713=>7137, +38717=>7138, +38718=>7139, +38724=>7140, +38726=>7141, +38728=>7142, +38722=>7143, +38729=>7144, +38748=>7145, +38752=>7146, +38756=>7147, +38758=>7148, +38760=>7149, +21202=>7150, +38763=>7151, +38769=>7152, +38777=>7153, +38789=>7154, +38780=>7155, +38785=>7156, +38778=>7157, +38790=>7158, +38795=>7159, +38799=>7160, +38800=>7161, +38812=>7162, +38824=>7163, +38822=>7164, +38819=>7165, +38835=>7166, +38836=>7167, +38851=>7168, +38854=>7169, +38856=>7170, +12209=>7171, +38859=>7171, +38876=>7172, +12210=>7173, +38893=>7173, +40783=>7174, +38898=>7175, +31455=>7176, +38902=>7177, +38901=>7178, +38927=>7179, +38924=>7180, +38968=>7181, +38948=>7182, +38945=>7183, +38967=>7184, +38973=>7185, +38982=>7186, +38991=>7187, +38987=>7188, +39019=>7189, +39023=>7190, +39024=>7191, +39025=>7192, +39028=>7193, +39027=>7194, +39082=>7195, +39087=>7196, +39089=>7197, +39094=>7198, +39108=>7199, +39107=>7200, +39110=>7201, +39145=>7202, +39147=>7203, +39171=>7204, +39177=>7205, +39186=>7206, +39188=>7207, +39192=>7208, +39201=>7209, +39197=>7210, +39198=>7211, +39204=>7212, +39200=>7213, +39212=>7214, +39214=>7215, +39229=>7216, +39230=>7217, +39234=>7218, +39241=>7219, +39237=>7220, +39248=>7221, +39243=>7222, +39249=>7223, +39250=>7224, +39244=>7225, +39253=>7226, +39319=>7227, +39320=>7228, +39333=>7229, +39341=>7230, +39342=>7231, +39356=>7232, +39391=>7233, +39387=>7234, +39389=>7235, +39384=>7236, +39377=>7237, +39405=>7238, +39406=>7239, +39409=>7240, +39410=>7241, +39419=>7242, +39416=>7243, +39425=>7244, +39439=>7245, +39429=>7246, +39394=>7247, +39449=>7248, +39467=>7249, +39479=>7250, +39493=>7251, +39490=>7252, +39488=>7253, +39491=>7254, +39486=>7255, +39509=>7256, +39501=>7257, +39515=>7258, +39511=>7259, +39519=>7260, +39522=>7261, +39525=>7262, +39524=>7263, +39529=>7264, +39531=>7265, +39530=>7266, +39597=>7267, +39600=>7268, +39612=>7269, +39616=>7270, +39631=>7271, +39633=>7272, +39635=>7273, +39636=>7274, +39646=>7275, +12221=>7276, +39647=>7276, +39650=>7277, +39651=>7278, +39654=>7279, +39663=>7280, +39659=>7281, +39662=>7282, +39668=>7283, +39665=>7284, +39671=>7285, +39675=>7286, +39686=>7287, +39704=>7288, +39706=>7289, +39711=>7290, +39714=>7291, +39715=>7292, +12222=>7293, +39717=>7293, +39719=>7294, +39720=>7295, +39721=>7296, +39722=>7297, +39726=>7298, +12223=>7299, +39727=>7299, +39730=>7300, +12224=>7300, +39748=>7301, +39747=>7302, +39759=>7303, +39757=>7304, +39758=>7305, +39761=>7306, +39768=>7307, +39796=>7308, +39827=>7309, +39811=>7310, +39825=>7311, +39830=>7312, +39831=>7313, +39839=>7314, +39840=>7315, +39848=>7316, +39860=>7317, +39872=>7318, +39882=>7319, +39865=>7320, +39878=>7321, +39887=>7322, +39889=>7323, +39890=>7324, +39907=>7325, +39906=>7326, +39908=>7327, +39892=>7328, +39905=>7329, +39994=>7330, +39922=>7331, +39921=>7332, +39920=>7333, +39957=>7334, +39956=>7335, +39945=>7336, +39955=>7337, +39948=>7338, +39942=>7339, +39944=>7340, +39954=>7341, +39946=>7342, +39940=>7343, +39982=>7344, +39963=>7345, +39973=>7346, +39972=>7347, +39969=>7348, +39984=>7349, +40007=>7350, +39986=>7351, +40006=>7352, +39998=>7353, +40026=>7354, +40032=>7355, +40039=>7356, +40054=>7357, +40056=>7358, +40167=>7359, +40172=>7360, +40176=>7361, +40201=>7362, +40200=>7363, +40171=>7364, +40195=>7365, +40198=>7366, +40234=>7367, +40230=>7368, +40367=>7369, +40227=>7370, +40223=>7371, +40260=>7372, +40213=>7373, +40210=>7374, +40257=>7375, +40255=>7376, +40254=>7377, +40262=>7378, +40264=>7379, +40285=>7380, +40286=>7381, +40292=>7382, +40273=>7383, +40272=>7384, +40281=>7385, +40306=>7386, +40329=>7387, +40327=>7388, +40363=>7389, +40303=>7390, +40314=>7391, +40346=>7392, +40356=>7393, +40361=>7394, +40370=>7395, +40388=>7396, +40385=>7397, +40379=>7398, +40376=>7399, +40378=>7400, +40390=>7401, +40399=>7402, +40386=>7403, +40409=>7404, +40403=>7405, +40440=>7406, +40422=>7407, +40429=>7408, +40431=>7409, +40445=>7410, +40474=>7411, +40475=>7412, +40478=>7413, +12228=>7414, +40565=>7414, +40569=>7415, +40573=>7416, +40577=>7417, +40584=>7418, +40587=>7419, +40588=>7420, +40594=>7421, +40597=>7422, +40593=>7423, +40605=>7424, +12230=>7425, +40613=>7425, +40617=>7426, +40632=>7427, +40618=>7428, +40621=>7429, +38753=>7430, +40652=>7431, +40654=>7432, +40655=>7433, +40656=>7434, +40660=>7435, +40668=>7436, +40670=>7437, +40669=>7438, +40672=>7439, +40677=>7440, +40680=>7441, +40687=>7442, +40692=>7443, +40694=>7444, +40695=>7445, +12235=>7446, +40697=>7446, +40699=>7447, +40700=>7448, +12236=>7449, +40701=>7449, +40711=>7450, +40712=>7451, +30391=>7452, +40725=>7453, +40737=>7454, +40748=>7455, +40766=>7456, +40778=>7457, +12241=>7457, +40786=>7458, +12242=>7458, +40788=>7459, +40803=>7460, +40799=>7461, +40800=>7462, +40801=>7463, +40806=>7464, +40807=>7465, +40812=>7466, +40810=>7467, +40823=>7468, +40818=>7469, +40822=>7470, +40853=>7471, +40860=>7472, +12244=>7472, +40864=>7473, +12245=>7473, +22575=>7474, +27079=>7475, +36953=>7476, +29796=>7477, +9472=>7479, +9473=>7480, +9474=>7481, +9475=>7482, +9476=>7483, +9477=>7484, +9478=>7485, +9479=>7486, +9480=>7487, +9481=>7488, +9482=>7489, +9483=>7490, +9484=>7491, +9485=>7492, +9486=>7493, +9487=>7494, +9488=>7495, +9489=>7496, +9490=>7497, +9491=>7498, +9492=>7499, +9493=>7500, +9494=>7501, +9495=>7502, +9496=>7503, +9497=>7504, +9498=>7505, +9499=>7506, +9500=>7507, +9501=>7508, +9502=>7509, +9503=>7510, +9504=>7511, +9505=>7512, +9506=>7513, +9507=>7514, +9508=>7515, +9509=>7516, +9510=>7517, +9511=>7518, +9512=>7519, +9513=>7520, +9514=>7521, +9515=>7522, +9516=>7523, +9517=>7524, +9518=>7525, +9519=>7526, +9520=>7527, +9521=>7528, +9522=>7529, +9523=>7530, +9524=>7531, +9525=>7532, +9526=>7533, +9527=>7534, +9528=>7535, +9529=>7536, +9530=>7537, +9531=>7538, +9532=>7539, +9533=>7540, +9534=>7541, +9535=>7542, +9536=>7543, +9537=>7544, +9538=>7545, +9539=>7546, +9540=>7547, +9541=>7548, +9542=>7549, +9543=>7550, +9544=>7551, +9545=>7552, +9546=>7553, +9547=>7554, +9312=>7555, +9313=>7556, +9314=>7557, +9315=>7558, +9316=>7559, +9317=>7560, +9318=>7561, +9319=>7562, +9320=>7563, +9321=>7564, +9322=>7565, +9323=>7566, +9324=>7567, +9325=>7568, +9326=>7569, +9327=>7570, +9328=>7571, +9329=>7572, +9330=>7573, +9331=>7574, +8544=>7575, +8545=>7576, +8546=>7577, +8547=>7578, +8548=>7579, +8549=>7580, +8550=>7581, +8551=>7582, +8552=>7583, +8553=>7584, +13129=>7585, +13076=>7586, +13133=>7588, +13095=>7590, +13110=>7592, +13137=>7593, +13069=>7595, +13094=>7596, +13099=>7598, +13130=>7599, +13212=>7601, +13213=>7602, +13214=>7603, +13198=>7604, +13199=>7605, +13252=>7606, +13217=>7607, +12317=>7608, +12319=>7609, +8470=>7610, +13261=>7611, +12964=>7613, +12965=>7614, +12966=>7615, +12967=>7616, +12968=>7617, +12849=>7618, +12850=>7619, +12857=>7620, +13182=>7621, +13181=>7622, +13180=>7623, +8750=>7624, +8721=>7625, +8735=>7629, +8895=>7630, +21854=>7633, +167133=>7641, +28976=>7644, +40407=>7646, +64054=>7651, +22169=>7654, +15694=>7655, +20448=>7660, +36544=>7663, +194797=>7665, +153716=>7670, +32363=>7671, +33606=>7672, +167670=>7673, +40572=>7677, +26171=>7680, +40628=>7682, +26629=>7687, +23650=>7693, +194780=>7695, +32353=>7697, +64070=>7700, +34083=>7706, +37292=>7707, +34796=>7715, +25620=>7724, +39506=>7727, +64074=>7732, +194692=>7734, +31774=>7739, +64016=>7746, +25681=>7747, +63980=>7750, +22625=>7751, +39002=>7752, +194679=>7754, +31153=>7758, +28678=>7760, +22218=>7770, +21085=>7774, +28497=>7776, +37297=>7777, +64106=>7788, +38960=>7795, +40629=>7797, +33802=>7807, +63939=>7808, +63890=>7809, +63891=>7810, +63897=>7811, +34847=>7813, +194575=>7814, +194771=>7816, +194584=>7817, +137754=>7825, +23643=>7826, +25890=>7831, +26618=>7834, +26766=>7836, +148432=>7838, +194848=>7839, +34110=>7861, +30562=>7877, +65041=>7887, +65042=>7888, +65075=>7890, +65073=>7892, +65074=>7893, +8285=>7897, +65049=>7897, +8282=>7898, +65072=>7898, +65077=>7899, +65078=>7900, +65081=>7901, +65082=>7902, +65095=>7903, +65096=>7904, +65079=>7905, +65080=>7906, +65087=>7907, +65088=>7908, +65085=>7909, +65086=>7910, +65089=>7911, +65090=>7912, +65091=>7913, +65092=>7914, +65083=>7915, +65084=>7916, +12436=>7958, +12437=>7959, +12438=>7960, +22099=>7963, +65508=>8005, +65287=>8006, +65282=>8007, +9665=>8009, +9655=>8010, +8681=>8011, +8679=>8012, +8678=>8013, +8680=>8014, +9634=>8015, +9831=>8016, +9825=>8017, +9828=>8018, +9826=>8019, +13216=>8020, +13218=>8021, +13220=>8022, +13221=>8023, +13207=>8024, +8467=>8025, +13208=>8026, +13235=>8027, +13234=>8028, +13233=>8029, +13232=>8030, +13189=>8031, +13190=>8032, +13191=>8033, +13259=>8034, +13200=>8035, +13268=>8036, +13206=>8037, +13090=>8038, +13078=>8039, +13080=>8040, +13077=>8041, +13059=>8042, +13091=>8043, +13143=>8044, +13122=>8045, +13113=>8046, +13115=>8047, +13056=>8048, +13105=>8049, +13127=>8050, +13086=>8051, +13098=>8052, +13183=>8054, +8481=>8055, +9742=>8056, +12342=>8057, +12320=>8058, +9352=>8062, +9353=>8063, +9354=>8064, +9355=>8065, +9356=>8066, +9357=>8067, +9358=>8068, +9359=>8069, +9360=>8070, +9332=>8071, +9333=>8072, +9334=>8073, +9335=>8074, +9336=>8075, +9337=>8076, +9338=>8077, +9339=>8078, +9340=>8079, +9341=>8080, +9342=>8081, +9343=>8082, +9344=>8083, +9345=>8084, +9346=>8085, +9347=>8086, +9348=>8087, +9349=>8088, +9350=>8089, +9351=>8090, +12881=>8091, +8560=>8092, +8561=>8093, +8562=>8094, +8563=>8095, +8564=>8096, +8565=>8097, +8566=>8098, +8567=>8099, +8568=>8100, +8569=>8101, +12882=>8102, +12883=>8103, +12884=>8104, +12885=>8105, +12886=>8106, +12887=>8107, +12888=>8108, +12889=>8109, +12890=>8110, +12891=>8111, +9372=>8112, +9373=>8113, +9374=>8114, +9375=>8115, +9376=>8116, +9377=>8117, +9378=>8118, +9379=>8119, +9380=>8120, +9381=>8121, +9382=>8122, +9383=>8123, +9384=>8124, +9385=>8125, +9386=>8126, +9387=>8127, +9388=>8128, +9389=>8129, +9390=>8130, +9391=>8131, +9392=>8132, +9393=>8133, +9394=>8134, +9395=>8135, +9396=>8136, +9397=>8137, +12867=>8138, +12861=>8139, +12863=>8140, +12852=>8141, +12856=>8142, +12851=>8143, +12860=>8144, +12866=>8145, +12862=>8146, +12854=>8147, +12853=>8148, +12859=>8149, +12864=>8150, +12858=>8151, +12976=>8152, +12973=>8153, +12969=>8154, +12975=>8155, +12948=>8156, +12970=>8157, +12952=>8158, +12971=>8159, +12946=>8160, +12945=>8161, +12947=>8162, +12972=>8163, +12974=>8164, +12950=>8165, +9131=>8174, +9132=>8175, +9133=>8176, +9127=>8178, +9128=>8179, +9129=>8180, +13260=>8182, +13061=>8183, +13215=>8186, +13219=>8187, +13222=>8188, +12958=>8191, +13192=>8192, +13193=>8193, +13256=>8194, +8749=>8195, +12848=>8197, +12842=>8198, +12843=>8199, +12844=>8200, +12845=>8201, +12846=>8202, +12847=>8203, +12855=>8204, +12865=>8205, +10145=>8206, +11013=>8207, +11014=>8208, +11015=>8209, +9673=>8210, +9824=>8211, +9829=>8212, +9827=>8213, +9830=>8214, +9728=>8215, +9729=>8216, +9730=>8217, +9731=>8218, +9758=>8219, +9756=>8220, +9757=>8221, +9759=>8222, +12953=>8223, +9450=>8224, +8554=>8225, +8555=>8226, +9601=>8230, +9602=>8231, +9603=>8232, +9604=>8233, +9605=>8234, +9606=>8235, +9607=>8236, +9608=>8237, +9615=>8238, +9614=>8239, +9613=>8240, +9612=>8241, +9611=>8242, +9610=>8243, +9609=>8244, +9620=>8245, +9621=>8246, +9581=>8247, +9582=>8248, +9584=>8249, +9583=>8250, +9552=>8251, +9566=>8252, +9578=>8253, +9569=>8254, +9698=>8255, +9699=>8256, +9701=>8257, +9700=>8258, +9585=>8261, +9586=>8262, +9587=>8263, +65040=>8268, +20956=>8284, +29081=>8285, +10102=>8286, +10103=>8287, +10104=>8288, +10105=>8289, +10106=>8290, +10107=>8291, +10108=>8292, +10109=>8293, +10110=>8294, +8570=>8298, +8571=>8299, +8575=>8303, +8458=>8304, +8457=>8305, +8507=>8307, +12292=>8308, +8646=>8309, +8644=>8310, +8645=>8311, +12535=>8313, +12536=>8314, +12537=>8315, +12538=>8316, +12957=>8319, +13179=>8323, +13107=>8327, +13134=>8328, +32394=>8359, +35100=>8360, +37704=>8361, +37512=>8362, +34012=>8363, +20425=>8364, +28859=>8365, +26161=>8366, +26824=>8367, +37625=>8368, +26363=>8369, +24389=>8370, +12033=>8371, +20008=>8371, +20193=>8372, +20220=>8373, +20224=>8374, +20227=>8375, +20281=>8376, +20310=>8377, +20370=>8378, +20362=>8379, +20378=>8380, +20372=>8381, +20429=>8382, +20544=>8383, +20514=>8384, +20479=>8385, +20510=>8386, +20550=>8387, +20592=>8388, +20546=>8389, +20628=>8390, +20724=>8391, +20696=>8392, +20810=>8393, +20836=>8394, +20893=>8395, +20926=>8396, +20972=>8397, +21013=>8398, +21148=>8399, +21158=>8400, +21184=>8401, +21211=>8402, +21248=>8403, +21284=>8405, +21362=>8406, +21395=>8407, +21426=>8408, +21469=>8409, +64014=>8410, +21660=>8411, +21642=>8412, +21673=>8413, +21759=>8414, +21894=>8415, +22361=>8416, +22373=>8417, +22444=>8418, +22472=>8419, +22471=>8420, +64015=>8421, +22686=>8423, +22706=>8424, +22795=>8425, +22867=>8426, +22875=>8427, +22877=>8428, +22883=>8429, +22948=>8430, +22970=>8431, +23382=>8432, +23488=>8433, +29999=>8434, +23512=>8435, +23582=>8437, +23718=>8438, +23738=>8439, +23797=>8440, +23847=>8441, +23891=>8442, +23874=>8444, +23917=>8445, +23992=>8446, +23993=>8447, +24016=>8448, +24353=>8449, +24372=>8450, +24423=>8451, +24503=>8452, +24542=>8453, +24669=>8454, +24709=>8455, +24714=>8456, +24798=>8457, +24789=>8458, +24864=>8459, +24818=>8460, +24849=>8461, +24887=>8462, +24880=>8463, +24984=>8464, +25107=>8465, +25254=>8466, +25589=>8467, +25696=>8468, +25757=>8469, +25806=>8470, +25934=>8471, +26112=>8472, +26133=>8473, +26121=>8474, +26158=>8475, +26148=>8477, +26213=>8478, +26199=>8479, +26201=>8480, +64018=>8481, +26227=>8482, +26265=>8483, +26272=>8484, +26290=>8485, +26303=>8486, +26362=>8487, +26382=>8488, +26470=>8490, +26555=>8491, +26706=>8492, +26560=>8493, +26692=>8495, +26831=>8496, +64019=>8497, +26984=>8498, +64020=>8499, +27032=>8500, +27106=>8501, +27184=>8502, +27243=>8503, +27206=>8504, +27251=>8505, +27262=>8506, +27362=>8507, +27364=>8508, +27606=>8509, +27711=>8510, +27740=>8511, +27782=>8512, +27759=>8513, +27866=>8514, +27908=>8515, +28039=>8516, +28015=>8517, +28054=>8518, +28076=>8519, +28111=>8520, +28152=>8521, +28146=>8522, +28156=>8523, +28217=>8524, +28252=>8525, +28199=>8526, +28220=>8527, +28351=>8528, +28552=>8529, +28597=>8530, +28661=>8531, +28677=>8532, +28679=>8533, +28712=>8534, +28805=>8535, +28843=>8536, +28943=>8537, +28932=>8538, +29020=>8539, +28998=>8540, +28999=>8541, +29121=>8543, +29182=>8544, +29361=>8545, +29374=>8546, +29476=>8547, +64022=>8548, +29559=>8549, +29629=>8550, +29641=>8551, +29654=>8552, +29667=>8553, +29650=>8554, +29703=>8555, +29685=>8556, +29734=>8557, +29738=>8558, +29737=>8559, +29742=>8560, +29833=>8562, +29855=>8563, +29953=>8564, +30063=>8565, +30338=>8566, +30364=>8567, +30366=>8568, +30363=>8569, +30374=>8570, +64023=>8571, +30534=>8572, +21167=>8573, +30753=>8574, +30798=>8575, +30820=>8576, +30842=>8577, +31024=>8578, +64024=>8579, +64025=>8580, +64026=>8581, +31124=>8582, +64027=>8583, +31131=>8584, +31441=>8585, +31463=>8586, +64028=>8587, +31467=>8588, +31646=>8589, +64029=>8590, +32072=>8591, +32183=>8593, +32160=>8594, +32214=>8595, +32338=>8596, +32583=>8597, +32673=>8598, +64030=>8599, +33537=>8600, +33634=>8601, +33663=>8602, +33735=>8603, +33782=>8604, +33864=>8605, +33972=>8606, +34131=>8607, +34137=>8608, +34155=>8609, +64031=>8610, +34224=>8611, +64032=>8612, +64033=>8613, +34823=>8614, +35061=>8615, +35346=>8616, +35383=>8617, +35449=>8618, +35495=>8619, +35518=>8620, +35551=>8621, +64034=>8622, +35574=>8623, +35667=>8624, +35711=>8625, +36080=>8626, +36084=>8627, +36114=>8628, +36214=>8629, +64035=>8630, +36559=>8631, +64037=>8633, +36967=>8634, +37086=>8635, +64038=>8636, +37141=>8637, +37159=>8638, +37338=>8639, +37335=>8640, +37342=>8641, +37357=>8642, +37358=>8643, +37348=>8644, +37349=>8645, +37382=>8646, +37392=>8647, +37386=>8648, +37434=>8649, +37440=>8650, +37436=>8651, +37454=>8652, +37465=>8653, +37457=>8654, +37433=>8655, +37479=>8656, +37543=>8657, +37495=>8658, +37496=>8659, +37607=>8660, +37591=>8661, +37593=>8662, +37584=>8663, +64039=>8664, +37589=>8665, +37600=>8666, +37587=>8667, +37669=>8668, +37665=>8669, +37627=>8670, +64040=>8671, +37662=>8672, +37631=>8673, +37661=>8674, +37634=>8675, +37744=>8676, +37719=>8677, +37796=>8678, +37830=>8679, +37854=>8680, +37880=>8681, +37937=>8682, +37957=>8683, +37960=>8684, +38290=>8685, +64041=>8687, +38557=>8688, +38575=>8689, +38707=>8690, +38715=>8691, +38723=>8692, +38733=>8693, +38735=>8694, +12205=>8695, +38737=>8695, +38999=>8697, +39013=>8698, +64042=>8699, +64043=>8700, +39207=>8701, +64044=>8702, +39326=>8703, +39502=>8704, +39641=>8705, +39644=>8706, +39797=>8707, +39794=>8708, +39823=>8709, +39857=>8710, +39867=>8711, +39936=>8712, +40304=>8713, +40299=>8714, +64045=>8715, +40473=>8716, +40657=>8717, +8364=>9354, +8486=>9355, +64256=>9358, +64259=>9359, +64260=>9360, +257=>9361, +299=>9362, +363=>9363, +275=>9364, +333=>9365, +256=>9366, +298=>9367, +362=>9368, +274=>9369, +332=>9370, +8539=>9371, +8540=>9372, +8541=>9373, +8542=>9374, +8531=>9375, +8532=>9376, +8304=>9377, +8308=>9378, +8309=>9379, +8310=>9380, +8311=>9381, +8312=>9382, +8313=>9383, +8320=>9384, +8321=>9385, +8322=>9386, +8323=>9387, +8324=>9388, +8325=>9389, +8326=>9390, +8327=>9391, +8328=>9392, +8329=>9393, +461=>9394, +282=>9395, +7868=>9397, +463=>9398, +296=>9400, +465=>9401, +467=>9403, +366=>9404, +360=>9405, +462=>9406, +283=>9407, +7869=>9409, +464=>9410, +297=>9412, +466=>9413, +468=>9415, +367=>9416, +361=>9417, +593=>9418, +8049=>9419, +8048=>9420, +509=>9421, +596=>9423, +601=>9426, +602=>9429, +603=>9432, +8051=>9433, +8050=>9434, +567=>9435, +331=>9436, +629=>9437, +652=>9438, +658=>9441, +643=>9442, +720=>9443, +8534=>9785, +8535=>9786, +8536=>9787, +8537=>9788, +8538=>9789, +12832=>10126, +12833=>10127, +12834=>10128, +12835=>10129, +12836=>10130, +12837=>10131, +12838=>10132, +12839=>10133, +12840=>10134, +12841=>10135, +12892=>10244, +12893=>10245, +12894=>10246, +12895=>10247, +12977=>10248, +12978=>10249, +12979=>10250, +12980=>10251, +12981=>10252, +12982=>10253, +12983=>10254, +12984=>10255, +12985=>10256, +12986=>10257, +12987=>10258, +12988=>10259, +12989=>10260, +12990=>10261, +12991=>10262, +9424=>10313, +9425=>10314, +9426=>10315, +9427=>10316, +9428=>10317, +9429=>10318, +9430=>10319, +9431=>10320, +9432=>10321, +9433=>10322, +9434=>10323, +9435=>10324, +9436=>10325, +9437=>10326, +9438=>10327, +9439=>10328, +9440=>10329, +9441=>10330, +9442=>10331, +9443=>10332, +9444=>10333, +9445=>10334, +9446=>10335, +9447=>10336, +9448=>10337, +9449=>10338, +9398=>10339, +9399=>10340, +9400=>10341, +9401=>10342, +9402=>10343, +9403=>10344, +9404=>10345, +9405=>10346, +9406=>10347, +9407=>10348, +9408=>10349, +9409=>10350, +9410=>10351, +9411=>10352, +9412=>10353, +9413=>10354, +9414=>10355, +9415=>10356, +9416=>10357, +9417=>10358, +9418=>10359, +9419=>10360, +9420=>10361, +9421=>10362, +9422=>10363, +9423=>10364, +13008=>10413, +13009=>10414, +13010=>10415, +13011=>10416, +13012=>10417, +13013=>10418, +13014=>10419, +13015=>10420, +13016=>10421, +13017=>10422, +13018=>10423, +13019=>10424, +13020=>10425, +13021=>10426, +13022=>10427, +13023=>10428, +13024=>10429, +13025=>10430, +13026=>10431, +13027=>10432, +13028=>10433, +13029=>10434, +13030=>10435, +13031=>10436, +13032=>10437, +13033=>10438, +13034=>10439, +13035=>10440, +13036=>10441, +13037=>10442, +13038=>10443, +13039=>10444, +13040=>10445, +13041=>10446, +13042=>10447, +13043=>10448, +13044=>10449, +13045=>10450, +13046=>10451, +13047=>10452, +13048=>10453, +13049=>10454, +13050=>10455, +13051=>10456, +13052=>10457, +13053=>10458, +13054=>10459, +12928=>10461, +12929=>10462, +12930=>10463, +12931=>10464, +12932=>10465, +12933=>10466, +12934=>10467, +12935=>10468, +12936=>10469, +12937=>10470, +12944=>10471, +12938=>10472, +12939=>10473, +12940=>10474, +12941=>10475, +12942=>10476, +12943=>10477, +12959=>10479, +12960=>10486, +12961=>10487, +12955=>10488, +12954=>10489, +12963=>10490, +12962=>10491, +12951=>10492, +12956=>10494, +12949=>10495, +9676=>10502, +9471=>10503, +10111=>10514, +9451=>10515, +9452=>10516, +9453=>10517, +9454=>10518, +9455=>10519, +9456=>10520, +9457=>10521, +9458=>10522, +9459=>10523, +9460=>10524, +8414=>11035, +13274=>11851, +8448=>11855, +13250=>11856, +8453=>11859, +13169=>11861, +13197=>11864, +13211=>11865, +13271=>11869, +13272=>11870, +13057=>11874, +13058=>11875, +13060=>11876, +13062=>11877, +13064=>11879, +13063=>11881, +13066=>11882, +13065=>11884, +13067=>11886, +13068=>11888, +13070=>11889, +13071=>11890, +13072=>11891, +13073=>11892, +13074=>11893, +13075=>11894, +13079=>11896, +13081=>11898, +13082=>11900, +13083=>11901, +13084=>11902, +13085=>11903, +13087=>11904, +13088=>11905, +13089=>11906, +13092=>11907, +13093=>11909, +13096=>11912, +13097=>11913, +13101=>11915, +13102=>11918, +13103=>11919, +13104=>11920, +13106=>11921, +13108=>11924, +13109=>11925, +13116=>11926, +13111=>11930, +13112=>11932, +13114=>11933, +13117=>11934, +13121=>11935, +13118=>11936, +13119=>11937, +13120=>11938, +13123=>11939, +13124=>11940, +13125=>11941, +13126=>11942, +13128=>11943, +13131=>11944, +13132=>11945, +13135=>11946, +13136=>11947, +13138=>11950, +13140=>11951, +13139=>11954, +13141=>11955, +13142=>11956, +8501=>12089, +976=>12090, +8714=>12091, +8463=>12092, +981=>12094, +987=>12095, +977=>12096, +9832=>12098, +9833=>12099, +9836=>12100, +12347=>12106, +12339=>12108, +12340=>12109, +12341=>12110, +8252=>12111, +8265=>12112, +8723=>12118, +8771=>12120, +8818=>12121, +8819=>12122, +12312=>12129, +12313=>12130, +65375=>12131, +65376=>12132, +9115=>12143, +9117=>12144, +9118=>12145, +9120=>12146, +9121=>12151, +9123=>12152, +9124=>12153, +9126=>12154, +9116=>12167, +9119=>12167, +9122=>12167, +9125=>12167, +9130=>12167, +9986=>12176, +12349=>12179, +12447=>12181, +8709=>12184, +8864=>12185, +8854=>12186, +8856=>12187, +8853=>12188, +8855=>12189, +9888=>12192, +9664=>12194, +9654=>12195, +8656=>12200, +8596=>12201, +8600=>12202, +8601=>12203, +8598=>12204, +8599=>12205, +8652=>12206, +8651=>12207, +12336=>12218, +8967=>12219, +10048=>12228, +10047=>12229, +9643=>12237, +9642=>12239, +10010=>12241, +9702=>12254, +10070=>12259, +65093=>12639, +65094=>12640, +64103=>13320, +64098=>13321, +32227=>13322, +12232=>13323, +40643=>13323, +28331=>13324, +64082=>13325, +64061=>13326, +64069=>13327, +64062=>13328, +27114=>13329, +28212=>13330, +64096=>13331, +64071=>13332, +64056=>13333, +64066=>13334, +64078=>13335, +34395=>13336, +64105=>13337, +64052=>13338, +64099=>13339, +25581=>13340, +25802=>13341, +30799=>13342, +64084=>13343, +63856=>13344, +64077=>13345, +64097=>13346, +64072=>13347, +64076=>13348, +64091=>13349, +64092=>13350, +64081=>13351, +64067=>13352, +64090=>13353, +28041=>13354, +29376=>13355, +194885=>13357, +64086=>13358, +64080=>13359, +64049=>13360, +64059=>13361, +24034=>13362, +64063=>13363, +64101=>13364, +21373=>13365, +64055=>13366, +64095=>13367, +24501=>13368, +64064=>13369, +64083=>13371, +64085=>13373, +64104=>13374, +64068=>13375, +64089=>13376, +26202=>13377, +64053=>13378, +64075=>13379, +64100=>13380, +64065=>13381, +64048=>13382, +64057=>13384, +64051=>13385, +27493=>13386, +64058=>13387, +27599=>13388, +64050=>13389, +25150=>13390, +64079=>13391, +63773=>13392, +63964=>13393, +63798=>13394, +28122=>13395, +63952=>13396, +26310=>13397, +27511=>13398, +64087=>13399, +37706=>13400, +37636=>13402, +133390=>13523, +35999=>13644, +11991=>13645, +11965=>13646, +158033=>13646, +37555=>13652, +38321=>13653, +194812=>13656, +194965=>13670, +194794=>13679, +26478=>13681, +11974=>13682, +194594=>13684, +156194=>13691, +13314=>13698, +26083=>13701, +134071=>13706, +171339=>13717, +194611=>13719, +24378=>13720, +11945=>13729, +20465=>13731, +63753=>13739, +11964=>13747, +194732=>13750, +26435=>13751, +133732=>13755, +35329=>13756, +25142=>13757, +21555=>13760, +23067=>13761, +25221=>13765, +194819=>13768, +21567=>13775, +27506=>13785, +29986=>13790, +19256=>13791, +24063=>13794, +194827=>13801, +29626=>13802, +134047=>13803, +194600=>13807, +194849=>13809, +194623=>13815, +194675=>13832, +11916=>13833, +11917=>13834, +23577=>13835, +131083=>13839, +23426=>13840, +194642=>13841, +11997=>13847, +11999=>13848, +39136=>13848, +11998=>13849, +169599=>13849, +14221=>13850, +11927=>13852, +14586=>13852, +194887=>13854, +11909=>13856, +20155=>13856, +131490=>13857, +13599=>13865, +194738=>13867, +11971=>13870, +35200=>13870, +31237=>13875, +35498=>13880, +32085=>13882, +28568=>13884, +25591=>13892, +30246=>13893, +11978=>13898, +163767=>13898, +146686=>13904, +13351=>13910, +33067=>13913, +194842=>13916, +11950=>13922, +154327=>13922, +194714=>13928, +194831=>13932, +22305=>13952, +135741=>13953, +194586=>13954, +64003=>13956, +21534=>13964, +15240=>13965, +20839=>13966, +63839=>13971, +20023=>13981, +11946=>13995, +150804=>13995, +24421=>13996, +23020=>13997, +194658=>13998, +24217=>14000, +13416=>14047, +40884=>14048, +21200=>14056, +38376=>14061, +26625=>14066, +195024=>14068, +195039=>14069, +153215=>14075, +11959=>14078, +36534=>14083, +63775=>14084, +63875=>14088, +31867=>14094, +63906=>14095, +63898=>14097, +11961=>14099, +32770=>14099, +157360=>14100, +11911=>14105, +132648=>14105, +131210=>14108, +133508=>14109, +194604=>14109, +11915=>14110, +13630=>14110, +21589=>14115, +22841=>14117, +23414=>14120, +194669=>14121, +23572=>14122, +14306=>14123, +23782=>14124, +20040=>14126, +194742=>14129, +158105=>14134, +25371=>14135, +26211=>14138, +194779=>14140, +27126=>14143, +27014=>14144, +27596=>14148, +28183=>14150, +27818=>14153, +11942=>14157, +20012=>14157, +29935=>14160, +30069=>14161, +30188=>14162, +30286=>14163, +16305=>14164, +30570=>14165, +30633=>14166, +31571=>14173, +16996=>14176, +194924=>14180, +32328=>14183, +132415=>14188, +11955=>14189, +156266=>14189, +33089=>14194, +17491=>14195, +33401=>14197, +11966=>14197, +64094=>14198, +11967=>14198, +64093=>14199, +11968=>14199, +20857=>14201, +33626=>14202, +17701=>14206, +34292=>14208, +131248=>14209, +34429=>14214, +13358=>14216, +35014=>14217, +18406=>14224, +36808=>14233, +166279=>14253, +167447=>14256, +38969=>14259, +39432=>14266, +39903=>14271, +148206=>14282, +21385=>14288, +64017=>14290, +194785=>14291, +146622=>14293, +132625=>14294, +19972=>14296, +19973=>14297, +19999=>14298, +20011=>14299, +20015=>14300, +20016=>14301, +20032=>14302, +20033=>14303, +20036=>14304, +11907=>14305, +20058=>14305, +20095=>14306, +20109=>14307, +20118=>14308, +20153=>14309, +20176=>14310, +20192=>14311, +20221=>14312, +20223=>14313, +20235=>14314, +20245=>14315, +20320=>14316, +20283=>14317, +20297=>14318, +20308=>14319, +20346=>14320, +20349=>14321, +20350=>14322, +20375=>14323, +20414=>14324, +20431=>14325, +20477=>14326, +20480=>14327, +20481=>14328, +20496=>14329, +20507=>14330, +20519=>14331, +20526=>14332, +20567=>14333, +20582=>14334, +20586=>14335, +20539=>14336, +20623=>14337, +20630=>14338, +20636=>14339, +20684=>14340, +20710=>14341, +20713=>14342, +20719=>14343, +20744=>14344, +20747=>14345, +20752=>14346, +20763=>14347, +20766=>14348, +20831=>14349, +20897=>14350, +20924=>14351, +20974=>14353, +20980=>14354, +20993=>14355, +11913=>14356, +20994=>14356, +21011=>14357, +21065=>14358, +21089=>14359, +21094=>14360, +21139=>14361, +21192=>14362, +21232=>14363, +21258=>14364, +21259=>14365, +21310=>14366, +21324=>14367, +21323=>14368, +21345=>14369, +21356=>14370, +21419=>14371, +21466=>14372, +21478=>14373, +21493=>14374, +21543=>14375, +21581=>14376, +21606=>14377, +21611=>14378, +21620=>14379, +21645=>14380, +21654=>14381, +21665=>14382, +21677=>14383, +21689=>14384, +21695=>14385, +21702=>14386, +21709=>14387, +21774=>14388, +21803=>14389, +21813=>14390, +21834=>14391, +21856=>14392, +21896=>14394, +21902=>14395, +22024=>14396, +22030=>14397, +22031=>14398, +22071=>14399, +22079=>14400, +22089=>14401, +22091=>14402, +22095=>14403, +22118=>14404, +22121=>14405, +22127=>14406, +22129=>14407, +22130=>14408, +22165=>14409, +22170=>14410, +22188=>14411, +22189=>14412, +22193=>14413, +22217=>14414, +22237=>14415, +22244=>14416, +22282=>14417, +22293=>14418, +22307=>14419, +22319=>14420, +22323=>14421, +22324=>14422, +22348=>14423, +22384=>14424, +22412=>14425, +22428=>14426, +22456=>14427, +22502=>14428, +22509=>14429, +22517=>14430, +22518=>14431, +22527=>14432, +22537=>14433, +22560=>14434, +22578=>14435, +22652=>14436, +22656=>14437, +22697=>14438, +22734=>14439, +22736=>14440, +22740=>14441, +22746=>14442, +22761=>14443, +22796=>14444, +22820=>14445, +22831=>14446, +22881=>14447, +22893=>14448, +22986=>14449, +22994=>14450, +23005=>14451, +23011=>14452, +23012=>14453, +23044=>14454, +23052=>14455, +23075=>14456, +23111=>14457, +23125=>14458, +23139=>14459, +23149=>14460, +23166=>14461, +23198=>14462, +23207=>14463, +23212=>14464, +23219=>14465, +23264=>14466, +23296=>14467, +23321=>14468, +23333=>14469, +23341=>14470, +23361=>14471, +23420=>14472, +23422=>14473, +23423=>14474, +23434=>14475, +11919=>14476, +23587=>14476, +23595=>14477, +23600=>14478, +23651=>14479, +23657=>14480, +23676=>14481, +23755=>14482, +23762=>14483, +23796=>14484, +23844=>14485, +23846=>14486, +23875=>14487, +23878=>14488, +23882=>14489, +23954=>14490, +23956=>14491, +23961=>14492, +23968=>14493, +24024=>14494, +24032=>14495, +24056=>14496, +24064=>14497, +24082=>14498, +24084=>14499, +24085=>14500, +24088=>14501, +24110=>14502, +24152=>14503, +24171=>14504, +24172=>14505, +24232=>14506, +24234=>14507, +24254=>14508, +24255=>14509, +24274=>14511, +24327=>14512, +24334=>14513, +24348=>14514, +24349=>14515, +24354=>14516, +24360=>14517, +24374=>14518, +24379=>14519, +24384=>14520, +12089=>14521, +24400=>14521, +24408=>14522, +24420=>14523, +24457=>14524, +24476=>14525, +24487=>14526, +24484=>14527, +24495=>14528, +24504=>14529, +11926=>14530, +24516=>14530, +24521=>14531, +24545=>14532, +24553=>14533, +24557=>14534, +24572=>14535, +24599=>14536, +24602=>14537, +24627=>14538, +24673=>14539, +24703=>14540, +24734=>14541, +24740=>14542, +24752=>14543, +24779=>14544, +24795=>14545, +24824=>14546, +24850=>14547, +24851=>14548, +24852=>14549, +24860=>14550, +24956=>14551, +24973=>14552, +24991=>14553, +25000=>14554, +25026=>14555, +25055=>14556, +25109=>14557, +25129=>14558, +25155=>14559, +25158=>14560, +11928=>14561, +25164=>14561, +25169=>14562, +25174=>14563, +25284=>14564, +25340=>14565, +25354=>14566, +25357=>14567, +25368=>14568, +25401=>14569, +25410=>14570, +25411=>14571, +25445=>14572, +25460=>14573, +25469=>14574, +25476=>14575, +25479=>14576, +25488=>14577, +25502=>14578, +25553=>14579, +25564=>14580, +25609=>14581, +25616=>14582, +25634=>14583, +25684=>14584, +25691=>14585, +25709=>14586, +25723=>14587, +25790=>14588, +25791=>14589, +25829=>14590, +25847=>14591, +25851=>14592, +25860=>14593, +25878=>14594, +25881=>14595, +25927=>14596, +25959=>14597, +25985=>14598, +25989=>14599, +26050=>14600, +26096=>14601, +26098=>14602, +26156=>14603, +26188=>14604, +26203=>14605, +26204=>14606, +26209=>14607, +26219=>14608, +26276=>14610, +26312=>14611, +26348=>14612, +26373=>14613, +26387=>14614, +26419=>14615, +26440=>14616, +26444=>14617, +26486=>14618, +26491=>14619, +26544=>14620, +26546=>14621, +26617=>14622, +26583=>14623, +26585=>14624, +26608=>14625, +26668=>14626, +26672=>14627, +26673=>14628, +26715=>14629, +26738=>14630, +26741=>14631, +26746=>14632, +26756=>14633, +26789=>14634, +26802=>14635, +26832=>14636, +26838=>14637, +26856=>14638, +26861=>14639, +26864=>14640, +26865=>14641, +26876=>14642, +26897=>14643, +26899=>14644, +26933=>14645, +26939=>14646, +26967=>14647, +26979=>14648, +26994=>14649, +27007=>14650, +27008=>14651, +27046=>14652, +27053=>14653, +27063=>14654, +27094=>14655, +27095=>14656, +27137=>14657, +27151=>14658, +27157=>14659, +27176=>14660, +27188=>14661, +27198=>14662, +27205=>14663, +27216=>14664, +27217=>14665, +27222=>14666, +27227=>14667, +27267=>14668, +27273=>14669, +27281=>14670, +27293=>14671, +27294=>14672, +27295=>14673, +27356=>14674, +27367=>14675, +27372=>14676, +27422=>14677, +27428=>14678, +27445=>14679, +27462=>14680, +27478=>14681, +27488=>14682, +27522=>14683, +27582=>14684, +27617=>14685, +27633=>14686, +27664=>14687, +27699=>14688, +27701=>14689, +11937=>14689, +11938=>14690, +27737=>14691, +27766=>14692, +27771=>14693, +27781=>14694, +27797=>14695, +27804=>14696, +27856=>14697, +27860=>14698, +27862=>14699, +27872=>14700, +27883=>14701, +27884=>14702, +27886=>14703, +27914=>14704, +27918=>14705, +27921=>14706, +27950=>14707, +27991=>14708, +27998=>14709, +28005=>14710, +28034=>14711, +28095=>14712, +28100=>14713, +28106=>14714, +28118=>14715, +28137=>14716, +28194=>14717, +28241=>14718, +28359=>14719, +28362=>14720, +28366=>14721, +28413=>14722, +28442=>14723, +28458=>14724, +28463=>14725, +28467=>14726, +28506=>14727, +28510=>14728, +28514=>14729, +28541=>14730, +28555=>14731, +28557=>14732, +28562=>14733, +28564=>14734, +28570=>14735, +28583=>14736, +28584=>14737, +28598=>14738, +28634=>14739, +28638=>14740, +28729=>14742, +28732=>14743, +28756=>14745, +28765=>14746, +28766=>14747, +28772=>14748, +11939=>14749, +28780=>14749, +28798=>14750, +28801=>14751, +28821=>14752, +28855=>14753, +28883=>14754, +28884=>14755, +28888=>14756, +28892=>14757, +28935=>14758, +28960=>14759, +28977=>14760, +29002=>14761, +29010=>14762, +29024=>14763, +29049=>14764, +29074=>14765, +29131=>14767, +29139=>14768, +29142=>14769, +29184=>14770, +29213=>14771, +29227=>14772, +29240=>14773, +29249=>14774, +29267=>14775, +29269=>14776, +29270=>14777, +29276=>14778, +29325=>14779, +11944=>14780, +29357=>14780, +29364=>14781, +29383=>14782, +29435=>14783, +29444=>14784, +29445=>14785, +29480=>14786, +29489=>14787, +29507=>14788, +29548=>14789, +29564=>14790, +29571=>14791, +29573=>14792, +29574=>14793, +29589=>14794, +29598=>14795, +29599=>14796, +29600=>14797, +29606=>14798, +29611=>14799, +29621=>14800, +29623=>14801, +29628=>14802, +29647=>14803, +29657=>14804, +29673=>14805, +29684=>14806, +29693=>14807, +29700=>14808, +29706=>14809, +29722=>14810, +29723=>14811, +29732=>14812, +29736=>14813, +29740=>14814, +29743=>14815, +29744=>14816, +29745=>14817, +29753=>14818, +29764=>14819, +29767=>14820, +29771=>14821, +29773=>14822, +29777=>14823, +29783=>14824, +29798=>14825, +29803=>14826, +29809=>14827, +29824=>14828, +29829=>14829, +29830=>14830, +29831=>14831, +29840=>14832, +29848=>14833, +29852=>14834, +29856=>14835, +29859=>14836, +29864=>14837, +29867=>14838, +29877=>14839, +29887=>14840, +29896=>14841, +29914=>14842, +29918=>14843, +30030=>14844, +30073=>14845, +30081=>14846, +30096=>14847, +12135=>14848, +30098=>14848, +30099=>14849, +30132=>14850, +30180=>14851, +30201=>14852, +30208=>14853, +30218=>14854, +30229=>14855, +30230=>14856, +30233=>14857, +30238=>14858, +30253=>14859, +30261=>14860, +30275=>14861, +30283=>14862, +30309=>14863, +30317=>14864, +30319=>14865, +30321=>14866, +30324=>14867, +30372=>14868, +30373=>14869, +30405=>14870, +30412=>14871, +30444=>14872, +30460=>14873, +30516=>14874, +30518=>14875, +30556=>14876, +30559=>14877, +30560=>14878, +30578=>14879, +30589=>14880, +30613=>14881, +30634=>14882, +30694=>14883, +30704=>14884, +30708=>14885, +30726=>14886, +30754=>14887, +30765=>14888, +30766=>14889, +30768=>14890, +30773=>14891, +30824=>14892, +30878=>14893, +30920=>14894, +30924=>14895, +30926=>14896, +30948=>14897, +30944=>14898, +30945=>14899, +30962=>14900, +30967=>14901, +30971=>14902, +31025=>14903, +11949=>14905, +31035=>14905, +31037=>14906, +31045=>14907, +31067=>14908, +31068=>14909, +31115=>14910, +31126=>14911, +31128=>14912, +12145=>14913, +31160=>14913, +31163=>14914, +31178=>14915, +31194=>14916, +31235=>14917, +31241=>14918, +31249=>14919, +31262=>14920, +31277=>14921, +31289=>14922, +31301=>14923, +31308=>14924, +31325=>14925, +31341=>14927, +31352=>14928, +31392=>14929, +31395=>14930, +31411=>14931, +31419=>14932, +31420=>14933, +31430=>14934, +31495=>14935, +31508=>14936, +31527=>14937, +31537=>14938, +31559=>14939, +31566=>14940, +31584=>14941, +31593=>14942, +31597=>14943, +31602=>14944, +31633=>14945, +31663=>14946, +31703=>14947, +31705=>14948, +31755=>14949, +31759=>14950, +31776=>14951, +31782=>14952, +31793=>14953, +31798=>14954, +31825=>14955, +31833=>14956, +31847=>14957, +31854=>14958, +31856=>14959, +31932=>14960, +31935=>14961, +31944=>14962, +31945=>14963, +31959=>14964, +31961=>14965, +31965=>14966, +31979=>14967, +32007=>14968, +32008=>14969, +32009=>14970, +32019=>14971, +32029=>14972, +32035=>14973, +32065=>14974, +32083=>14975, +32089=>14976, +32093=>14977, +32122=>14978, +32134=>14979, +32139=>14980, +32140=>14981, +32204=>14982, +32235=>14983, +32241=>14984, +32249=>14985, +32264=>14986, +32273=>14987, +32277=>14988, +32288=>14989, +32327=>14990, +32354=>14991, +32366=>14992, +32371=>14993, +32397=>14994, +32401=>14995, +32408=>14996, +32580=>14997, +32591=>14998, +11947=>14999, +11954=>14999, +32594=>14999, +11953=>15000, +32595=>15000, +32609=>15001, +32657=>15002, +32703=>15003, +32718=>15004, +32735=>15005, +32741=>15006, +32748=>15007, +32750=>15008, +32751=>15009, +32762=>15010, +32782=>15011, +32785=>15012, +32788=>15013, +32804=>15014, +32806=>15015, +32826=>15016, +32828=>15017, +32864=>15018, +32881=>15019, +32885=>15020, +32926=>15021, +32934=>15022, +32939=>15023, +32983=>15024, +32984=>15025, +33046=>15026, +33048=>15027, +33082=>15028, +33098=>15029, +33100=>15030, +33153=>15031, +33156=>15032, +33204=>15033, +33231=>15034, +33273=>15035, +33283=>15036, +33313=>15037, +33330=>15038, +33332=>15039, +33350=>15040, +33355=>15041, +33359=>15042, +33422=>15043, +33454=>15044, +33463=>15045, +33470=>15046, +33478=>15047, +33534=>15048, +33603=>15049, +33617=>15050, +33621=>15051, +33670=>15052, +33677=>15053, +33682=>15054, +33688=>15055, +33705=>15056, +33727=>15057, +33728=>15058, +33770=>15059, +33807=>15060, +33809=>15061, +33866=>15062, +33910=>15063, +33960=>15064, +33967=>15065, +33984=>15066, +33986=>15067, +34032=>15068, +34045=>15069, +34060=>15070, +34100=>15071, +34142=>15072, +34191=>15073, +34231=>15074, +34254=>15075, +34221=>15076, +34322=>15077, +34345=>15078, +34386=>15079, +34403=>15080, +34412=>15081, +34415=>15082, +34426=>15083, +34445=>15084, +34449=>15085, +34456=>15086, +34471=>15087, +34472=>15088, +34554=>15089, +34557=>15090, +34571=>15091, +34579=>15092, +34585=>15093, +34590=>15094, +34600=>15095, +34622=>15096, +34673=>15097, +34696=>15098, +34713=>15099, +34732=>15100, +34733=>15101, +34741=>15102, +34774=>15103, +34795=>15104, +34797=>15105, +34817=>15106, +34822=>15108, +34827=>15109, +34836=>15110, +34844=>15111, +34902=>15112, +34911=>15113, +11970=>15114, +34916=>15114, +34968=>15115, +34986=>15116, +35005=>15117, +35006=>15118, +35018=>15119, +35026=>15120, +35035=>15121, +35056=>15122, +35057=>15123, +35078=>15124, +35096=>15125, +35097=>15126, +35098=>15127, +35111=>15128, +35120=>15129, +35134=>15130, +35195=>15131, +35284=>15132, +35286=>15133, +35301=>15134, +35313=>15135, +35335=>15136, +35343=>15137, +35349=>15138, +35362=>15139, +35406=>15140, +35455=>15141, +35572=>15142, +35615=>15143, +35639=>15144, +35651=>15145, +35652=>15146, +35668=>15147, +35740=>15148, +35742=>15149, +35911=>15150, +35924=>15151, +35955=>15152, +36004=>15153, +36057=>15154, +36065=>15155, +36088=>15156, +36094=>15157, +36123=>15158, +36201=>15159, +36204=>15160, +36228=>15161, +36237=>15162, +36245=>15163, +36262=>15164, +36294=>15165, +36302=>15166, +36324=>15167, +36332=>15168, +36384=>15169, +36427=>15170, +36460=>15171, +36464=>15172, +36474=>15173, +36498=>15174, +36526=>15175, +36531=>15176, +36561=>15177, +36564=>15178, +36601=>15179, +36631=>15180, +36662=>15181, +36774=>15182, +12193=>15183, +36789=>15183, +11981=>15184, +36790=>15184, +36832=>15186, +36836=>15187, +36854=>15188, +36866=>15189, +36908=>15190, +36932=>15191, +37000=>15192, +37013=>15193, +37017=>15194, +37019=>15195, +37026=>15196, +37044=>15197, +37079=>15198, +37085=>15199, +37108=>15200, +37143=>15201, +37148=>15202, +37169=>15203, +37178=>15204, +37181=>15205, +37192=>15206, +37211=>15207, +37217=>15208, +37220=>15209, +37262=>15210, +37278=>15211, +37288=>15212, +37293=>15213, +37294=>15214, +37298=>15215, +37308=>15216, +37360=>15217, +37367=>15218, +37371=>15219, +37383=>15220, +37416=>15221, +37427=>15222, +37432=>15223, +37443=>15224, +37447=>15225, +37455=>15226, +37472=>15227, +37570=>15228, +37579=>15229, +37580=>15230, +37599=>15231, +37645=>15232, +37653=>15233, +37663=>15234, +37671=>15235, +37703=>15236, +37714=>15237, +37738=>15239, +37741=>15240, +37787=>15241, +37818=>15242, +37801=>15243, +37825=>15244, +37834=>15245, +37858=>15246, +37882=>15247, +37885=>15248, +37903=>15249, +37940=>15250, +37951=>15251, +37973=>15252, +37995=>15253, +38002=>15254, +11986=>15255, +38264=>15255, +38310=>15256, +38313=>15257, +38324=>15259, +38333=>15260, +38362=>15261, +11983=>15262, +11990=>15262, +38429=>15262, +38465=>15263, +38488=>15264, +38532=>15265, +38564=>15266, +38569=>15267, +38610=>15268, +195060=>15269, +38622=>15270, +38633=>15271, +38641=>15272, +38658=>15273, +38665=>15274, +38746=>15275, +38755=>15276, +38766=>15277, +38771=>15278, +38810=>15279, +38818=>15280, +38837=>15281, +38838=>15282, +38873=>15283, +38878=>15284, +38900=>15285, +38922=>15286, +38926=>15287, +38942=>15288, +38947=>15289, +38955=>15290, +38974=>15291, +38994=>15292, +38995=>15293, +39001=>15294, +39020=>15295, +39096=>15296, +39098=>15297, +39103=>15298, +39112=>15299, +39141=>15300, +39218=>15301, +39219=>15302, +39232=>15303, +39245=>15304, +39260=>15305, +39263=>15306, +39345=>15307, +39353=>15308, +39354=>15309, +39369=>15310, +39426=>15311, +39446=>15312, +39460=>15313, +39463=>15314, +39469=>15315, +39470=>15316, +39478=>15317, +39480=>15318, +39498=>15319, +39510=>15320, +39605=>15321, +39606=>15322, +39673=>15323, +39683=>15324, +39712=>15325, +39731=>15326, +39732=>15327, +39795=>15328, +39801=>15329, +39847=>15330, +39873=>15331, +39879=>15332, +39895=>15333, +39911=>15334, +39915=>15335, +39927=>15336, +39930=>15337, +39933=>15338, +39947=>15339, +39975=>15340, +39978=>15341, +39990=>15342, +40001=>15343, +40019=>15344, +40035=>15345, +40048=>15346, +40055=>15347, +40194=>15348, +40258=>15349, +40263=>15350, +40291=>15351, +40297=>15352, +40316=>15353, +40318=>15354, +40333=>15355, +40369=>15356, +40387=>15357, +40391=>15358, +40406=>15359, +40415=>15360, +40427=>15361, +40436=>15362, +40469=>15363, +40477=>15364, +40612=>15365, +40616=>15366, +40620=>15367, +40679=>15368, +40686=>15369, +40720=>15370, +40722=>15371, +40727=>15372, +40729=>15373, +40751=>15374, +40759=>15375, +40761=>15376, +40769=>15377, +40773=>15378, +40791=>15379, +40808=>15380, +40817=>15381, +40821=>15382, +40848=>15383, +40852=>15384, +40866=>15385, +13317=>15387, +194564=>15388, +22048=>15389, +24267=>15390, +11925=>15391, +144954=>15393, +28665=>15395, +28390=>15396, +29107=>15397, +11940=>15398, +64073=>15398, +11980=>15403, +64102=>15403, +23986=>15405, +20435=>15407, +20697=>15408, +20720=>15409, +20931=>15410, +22134=>15411, +27220=>15412, +27905=>15413, +28112=>15414, +28226=>15415, +28377=>15416, +29668=>15417, +29729=>15418, +30060=>15419, +30801=>15420, +34805=>15421, +144382=>15422, +29608=>15423, +15091=>15424, +13531=>15425, +17420=>15426, +16010=>15427, +40893=>15429, +19432=>15430, +40892=>15431, +16090=>15432, +15138=>15433, +40894=>15434, +17786=>15435, +16531=>15436, +18021=>15438, +16643=>15439, +17043=>15440, +18094=>15441, +13448=>15442, +140809=>15443, +63584=>15444, +63585=>15445, +63586=>15446, +63610=>15447, +63615=>15448, +8836=>15472, +8837=>15473, +8842=>15474, +8843=>15475, +8713=>15476, +8965=>15478, +8966=>15479, +8741=>15489, +8742=>15490, +8802=>15505, +8773=>15507, +8776=>15508, +8822=>15509, +8823=>15510, +8487=>15515, +8922=>15725, +8923=>15726, +8533=>15727, +8984=>15728, +7742=>15729, +7743=>15730, +504=>15731, +505=>15732, +470=>15733, +472=>15734, +474=>15735, +476=>15736, +260=>15737, +728=>15738, +317=>15739, +346=>15740, +350=>15741, +356=>15742, +377=>15743, +379=>15744, +261=>15745, +731=>15746, +318=>15747, +347=>15748, +711=>15749, +351=>15750, +357=>15751, +378=>15752, +733=>15753, +380=>15754, +340=>15755, +258=>15756, +313=>15757, +262=>15758, +268=>15759, +280=>15760, +270=>15761, +323=>15762, +327=>15763, +336=>15764, +344=>15765, +368=>15766, +354=>15767, +341=>15768, +259=>15769, +314=>15770, +263=>15771, +269=>15772, +281=>15773, +271=>15774, +273=>15775, +324=>15776, +328=>15777, +337=>15778, +345=>15779, +369=>15780, +355=>15781, +729=>15782, +264=>15783, +284=>15784, +292=>15785, +308=>15786, +348=>15787, +364=>15788, +265=>15789, +285=>15790, +293=>15791, +309=>15792, +349=>15793, +365=>15794, +625=>15795, +651=>15796, +638=>15797, +620=>15798, +622=>15799, +633=>15800, +648=>15801, +598=>15802, +627=>15803, +637=>15804, +642=>15805, +656=>15806, +635=>15807, +621=>15808, +607=>15809, +626=>15810, +669=>15811, +654=>15812, +609=>15813, +624=>15814, +641=>15815, +295=>15816, +661=>15817, +660=>15818, +614=>15819, +664=>15820, +450=>15821, +595=>15822, +599=>15823, +644=>15824, +608=>15825, +403=>15826, +616=>15827, +649=>15828, +600=>15829, +604=>15830, +606=>15831, +592=>15832, +623=>15833, +650=>15834, +612=>15835, +594=>15836, +653=>15837, +613=>15838, +674=>15839, +673=>15840, +597=>15841, +657=>15842, +634=>15843, +615=>15844, +865=>15845, +712=>15846, +716=>15847, +721=>15848, +8255=>15849, +783=>15850, +741=>15851, +742=>15852, +743=>15853, +744=>15854, +745=>15855, +805=>15858, +812=>15859, +825=>15860, +796=>15861, +799=>15862, +800=>15863, +829=>15864, +809=>15865, +815=>15866, +734=>15867, +804=>15868, +816=>15869, +828=>15870, +820=>15871, +797=>15872, +798=>15873, +792=>15874, +793=>15875, +810=>15876, +826=>15877, +827=>15878, +794=>15879, +610=>15883, +611=>15884, +618=>15885, +628=>15886, +630=>15887, +632=>15888, +640=>15889, +655=>15890, +665=>15891, +668=>15892, +671=>15893, +688=>15894, +690=>15895, +695=>15896, +705=>15897, +736=>15898, +737=>15899, +8862=>15906, +12348=>16194, +12543=>16195, +12310=>16197, +12311=>16198, +9838=>16199, +9835=>16200, +10548=>16201, +10549=>16202, +10687=>16203, +12448=>16205, +10746=>16207, +10747=>16208, +962=>16222, +9461=>16223, +9462=>16224, +9463=>16225, +9464=>16226, +9465=>16227, +9466=>16228, +9467=>16229, +9468=>16230, +9469=>16231, +9470=>16232, +9750=>16233, +9751=>16234, +9649=>16235, +12784=>16236, +12785=>16237, +12786=>16238, +12787=>16239, +12788=>16240, +12789=>16241, +12790=>16242, +12791=>16243, +12792=>16244, +12793=>16245, +12794=>16247, +12795=>16248, +12796=>16249, +12797=>16250, +12798=>16251, +12799=>16252, +9150=>16253, +9151=>16254, +9152=>16255, +9153=>16256, +9154=>16257, +9155=>16258, +9156=>16259, +9157=>16260, +9158=>16261, +9159=>16262, +9160=>16263, +9161=>16264, +9162=>16265, +9163=>16266, +9164=>16267, +10003=>16270, +9251=>16272, +9166=>16273, +9680=>16274, +9681=>16275, +9682=>16276, +9683=>16277, +8263=>16278, +8264=>16279, +8273=>16281, +8258=>16282, +12688=>16283, +12689=>16284, +12690=>16285, +12691=>16286, +12692=>16287, +12693=>16288, +12694=>16289, +12695=>16290, +12696=>16291, +12697=>16292, +12698=>16293, +12699=>16294, +12700=>16295, +12701=>16296, +12702=>16297, +12703=>16298, +9136=>16312, +9137=>16313, +9842=>16314, +9843=>16315, +9844=>16316, +9845=>16317, +9846=>16318, +9847=>16319, +9848=>16320, +9849=>16321, +9850=>16322, +9851=>16323, +9852=>16324, +9853=>16325, +12441=>16326, +12442=>16327, +8413=>16328, +20296=>16779, +20319=>16780, +20330=>16781, +20332=>16782, +20494=>16783, +20504=>16784, +20545=>16785, +20722=>16786, +20688=>16787, +20742=>16788, +20739=>16789, +20789=>16790, +20821=>16791, +20823=>16792, +13493=>16793, +20938=>16794, +20962=>16795, +21079=>16796, +21196=>16797, +21206=>16798, +21243=>16799, +21276=>16800, +21347=>16801, +21405=>16802, +21522=>16803, +21631=>16804, +21640=>16805, +21840=>16806, +21889=>16807, +21933=>16808, +21966=>16809, +22075=>16810, +22174=>16811, +22185=>16812, +22195=>16813, +22391=>16814, +22396=>16815, +135963=>16816, +22479=>16817, +22500=>16818, +22628=>16819, +22665=>16820, +136302=>16821, +22738=>16822, +22752=>16823, +34369=>16824, +22923=>16825, +22930=>16826, +22979=>16827, +23059=>16828, +23143=>16829, +23159=>16830, +23172=>16831, +23236=>16832, +137405=>16833, +23421=>16834, +23443=>16835, +23570=>16836, +64060=>16837, +136884=>16838, +23674=>16839, +23695=>16840, +23711=>16841, +23715=>16842, +23722=>16843, +23760=>16844, +138804=>16845, +23821=>16846, +23879=>16847, +23937=>16848, +23972=>16849, +23975=>16850, +24011=>16851, +24158=>16852, +24313=>16853, +24320=>16854, +24322=>16855, +24355=>16856, +24381=>16857, +24404=>16858, +24445=>16859, +24589=>16860, +24596=>16861, +24600=>16862, +24629=>16863, +24647=>16864, +24733=>16865, +24788=>16866, +24797=>16867, +24875=>16868, +25020=>16869, +25017=>16870, +25122=>16871, +25178=>16872, +25199=>16873, +25302=>16874, +25468=>16875, +25573=>16876, +25721=>16877, +25796=>16878, +25808=>16879, +25897=>16880, +26013=>16881, +26170=>16882, +26146=>16883, +26155=>16884, +26160=>16885, +26163=>16886, +26184=>16887, +143812=>16888, +26231=>16889, +26232=>16890, +26253=>16891, +26299=>16892, +26331=>16893, +26344=>16894, +26439=>16895, +26497=>16896, +26515=>16897, +26520=>16898, +26523=>16899, +26620=>16900, +26653=>16901, +26787=>16902, +26890=>16903, +26953=>16904, +144836=>16905, +26946=>16906, +26980=>16907, +27045=>16908, +27087=>16909, +15286=>16910, +15299=>16911, +27113=>16912, +27125=>16913, +145215=>16914, +27195=>16915, +145251=>16916, +27284=>16917, +27301=>16918, +15375=>16919, +27419=>16920, +27436=>16921, +27495=>16922, +27561=>16923, +27565=>16924, +27607=>16925, +27647=>16926, +27653=>16927, +27764=>16928, +27800=>16929, +27899=>16930, +27846=>16931, +27953=>16932, +27961=>16933, +27967=>16934, +27992=>16935, +28052=>16936, +28074=>16937, +28123=>16938, +28125=>16939, +28228=>16940, +28254=>16941, +28337=>16942, +28353=>16943, +28432=>16944, +28505=>16945, +28513=>16946, +28542=>16947, +28556=>16948, +28576=>16949, +28604=>16950, +28615=>16951, +28618=>16952, +28656=>16953, +28750=>16954, +28789=>16955, +28836=>16956, +28900=>16957, +28971=>16958, +28958=>16959, +28974=>16960, +29009=>16961, +29032=>16962, +29061=>16963, +29063=>16964, +29114=>16965, +29124=>16966, +29205=>16967, +15935=>16968, +29339=>16969, +149489=>16970, +29479=>16971, +29520=>16972, +29542=>16973, +29602=>16974, +29739=>16975, +29766=>16976, +29794=>16977, +29805=>16978, +29862=>16979, +29865=>16980, +29897=>16981, +29951=>16982, +29975=>16983, +16242=>16984, +30158=>16985, +30210=>16986, +30216=>16987, +30308=>16988, +30337=>16989, +30365=>16990, +30378=>16991, +30390=>16992, +30414=>16993, +30420=>16994, +30438=>16995, +30449=>16996, +30474=>16997, +30489=>16998, +30541=>16999, +30542=>17000, +30586=>17001, +30592=>17002, +30612=>17003, +30688=>17004, +152718=>17005, +30787=>17006, +30830=>17007, +30896=>17008, +152846=>17009, +30893=>17010, +30976=>17011, +31004=>17012, +31022=>17013, +31028=>17014, +31046=>17015, +31097=>17016, +31176=>17017, +153457=>17018, +31188=>17019, +31198=>17020, +31211=>17021, +31213=>17022, +31365=>17023, +154052=>17024, +31438=>17025, +31485=>17026, +31506=>17027, +31533=>17028, +31547=>17029, +31599=>17030, +31745=>17031, +31795=>17032, +155041=>17033, +31853=>17034, +31865=>17035, +31887=>17036, +31892=>17037, +31904=>17038, +31957=>17039, +32049=>17040, +32092=>17041, +32131=>17042, +32166=>17043, +32194=>17044, +32296=>17045, +32663=>17046, +32731=>17047, +32821=>17048, +32823=>17049, +32970=>17050, +32992=>17051, +33011=>17052, +33120=>17053, +33127=>17054, +33128=>17055, +33133=>17056, +33211=>17057, +33226=>17058, +33239=>17059, +17499=>17060, +33376=>17061, +33396=>17062, +158463=>17063, +33441=>17064, +33443=>17065, +33444=>17066, +33449=>17067, +33471=>17068, +33493=>17069, +33533=>17070, +33536=>17071, +33570=>17072, +33581=>17073, +33594=>17074, +33607=>17075, +33661=>17076, +33703=>17077, +33743=>17078, +33745=>17079, +33761=>17080, +33793=>17081, +33798=>17082, +33887=>17083, +33904=>17084, +33907=>17085, +33925=>17086, +33950=>17087, +33978=>17088, +159296=>17089, +34098=>17090, +34078=>17091, +34095=>17092, +34148=>17093, +34170=>17094, +34188=>17095, +34210=>17096, +34251=>17097, +34285=>17098, +34303=>17099, +34308=>17100, +34309=>17101, +34320=>17102, +159988=>17103, +34328=>17104, +34360=>17105, +34391=>17106, +34402=>17107, +17821=>17108, +34421=>17109, +34488=>17110, +34556=>17111, +34695=>17112, +17898=>17113, +34826=>17114, +34832=>17115, +35022=>17116, +161412=>17117, +35122=>17118, +35129=>17119, +35136=>17120, +35220=>17121, +35318=>17122, +35399=>17123, +35421=>17124, +35425=>17125, +35445=>17126, +35536=>17127, +35654=>17128, +35673=>17129, +35689=>17130, +35741=>17131, +35913=>17132, +35944=>17133, +36271=>17134, +36305=>17135, +36311=>17136, +36387=>17137, +36413=>17138, +36475=>17139, +164471=>17140, +18500=>17141, +36602=>17142, +36638=>17143, +36653=>17144, +36692=>17145, +164813=>17146, +36840=>17147, +36846=>17148, +36872=>17149, +36909=>17150, +37015=>17151, +37043=>17152, +37054=>17153, +37060=>17154, +37061=>17155, +37063=>17156, +37103=>17157, +37140=>17158, +37142=>17159, +37154=>17160, +37155=>17161, +37167=>17162, +37172=>17163, +37251=>17164, +37361=>17165, +37705=>17166, +37732=>17167, +37733=>17168, +37795=>17169, +37855=>17170, +37892=>17171, +37939=>17172, +37962=>17173, +37987=>17174, +38001=>17175, +38286=>17176, +38303=>17177, +38316=>17178, +38326=>17179, +38347=>17180, +38352=>17181, +38355=>17182, +18864=>17183, +38366=>17184, +38565=>17185, +38639=>17186, +38734=>17187, +38805=>17188, +38830=>17189, +38842=>17190, +38849=>17191, +38857=>17192, +38875=>17193, +38998=>17194, +39143=>17195, +39256=>17196, +39427=>17197, +39617=>17198, +39619=>17199, +39630=>17200, +39638=>17201, +39682=>17202, +39688=>17203, +19479=>17204, +39725=>17205, +39774=>17206, +39782=>17207, +39812=>17208, +39818=>17209, +39838=>17210, +39886=>17211, +39909=>17212, +39928=>17213, +39971=>17214, +40015=>17215, +40016=>17216, +40037=>17217, +40221=>17218, +40222=>17219, +40259=>17220, +40274=>17221, +40330=>17222, +40342=>17223, +40384=>17224, +40364=>17225, +40380=>17226, +172432=>17227, +40423=>17228, +40455=>17229, +40606=>17230, +40623=>17231, +40855=>17232, +131209=>17233, +19970=>17234, +19983=>17235, +19986=>17236, +20009=>17237, +20014=>17238, +20039=>17239, +131234=>17240, +20049=>17241, +13318=>17242, +131236=>17243, +20073=>17244, +20125=>17245, +13356=>17246, +20156=>17247, +20163=>17248, +20168=>17249, +20203=>17250, +20186=>17251, +20209=>17252, +20213=>17253, +20246=>17254, +20324=>17255, +20279=>17256, +20286=>17257, +20312=>17258, +131603=>17259, +20343=>17260, +20344=>17261, +20354=>17262, +20357=>17263, +20454=>17264, +20402=>17265, +20421=>17266, +20427=>17267, +20434=>17268, +13418=>17269, +20466=>17270, +20499=>17271, +20508=>17272, +20558=>17273, +20563=>17274, +20579=>17275, +20643=>17276, +20616=>17277, +20626=>17278, +20627=>17279, +20629=>17280, +20650=>17281, +131883=>17282, +20657=>17283, +20666=>17284, +20667=>17285, +20676=>17286, +20679=>17287, +20723=>17288, +131969=>17289, +20686=>17290, +131953=>17291, +20692=>17292, +20705=>17293, +13458=>17294, +132089=>17295, +20759=>17296, +132170=>17297, +20832=>17298, +132361=>17299, +20851=>17300, +20867=>17301, +20875=>17302, +13500=>17303, +20888=>17304, +20899=>17305, +20909=>17306, +13511=>17307, +132566=>17308, +20979=>17309, +21010=>17310, +21014=>17311, +132943=>17312, +21077=>17313, +21084=>17314, +21100=>17315, +21111=>17316, +21124=>17317, +21122=>17318, +133127=>17319, +21144=>17320, +133178=>17321, +21156=>17322, +21178=>17323, +21179=>17324, +21194=>17325, +21201=>17326, +133305=>17327, +21239=>17328, +21301=>17329, +21314=>17330, +133500=>17331, +133533=>17332, +21351=>17333, +21370=>17334, +21412=>17335, +21428=>17336, +133843=>17337, +21431=>17338, +21440=>17339, +133917=>17340, +13661=>17341, +13662=>17342, +21461=>17343, +13667=>17344, +21492=>17345, +21540=>17346, +21544=>17347, +13678=>17348, +21571=>17349, +21602=>17350, +21612=>17351, +21653=>17352, +21664=>17353, +21670=>17354, +21678=>17355, +21687=>17356, +21690=>17357, +21699=>17358, +134469=>17359, +21740=>17360, +21743=>17361, +21745=>17362, +21747=>17363, +21760=>17364, +21761=>17365, +21769=>17366, +21820=>17367, +21825=>17368, +13734=>17369, +21831=>17370, +13736=>17371, +21860=>17372, +134625=>17373, +21885=>17374, +21890=>17375, +21905=>17376, +13765=>17377, +21970=>17378, +134805=>17379, +134765=>17380, +21951=>17381, +21961=>17382, +21964=>17383, +21969=>17384, +21981=>17385, +13786=>17386, +21986=>17387, +134756=>17388, +21993=>17389, +22056=>17390, +135007=>17391, +22023=>17392, +22032=>17393, +22064=>17394, +13812=>17395, +22077=>17396, +22080=>17397, +22087=>17398, +22110=>17399, +22112=>17400, +22125=>17401, +13829=>17402, +22152=>17403, +22156=>17404, +22173=>17405, +22184=>17406, +22194=>17407, +22213=>17408, +22221=>17409, +22239=>17410, +22248=>17411, +22262=>17412, +22263=>17413, +135681=>17414, +135765=>17415, +22313=>17416, +135803=>17417, +22341=>17418, +22342=>17419, +22349=>17420, +135796=>17421, +22376=>17422, +22383=>17423, +22387=>17424, +22388=>17425, +22389=>17426, +22395=>17427, +135908=>17428, +135895=>17429, +22426=>17430, +22429=>17431, +22430=>17432, +22440=>17433, +22487=>17434, +135933=>17435, +22476=>17436, +135990=>17437, +136004=>17438, +22494=>17439, +22512=>17440, +13898=>17441, +22520=>17442, +22523=>17443, +22525=>17444, +22532=>17445, +22558=>17446, +22567=>17447, +22585=>17448, +136132=>17449, +22601=>17450, +22604=>17451, +22631=>17452, +22666=>17453, +22667=>17454, +22669=>17455, +22671=>17456, +22672=>17457, +22676=>17458, +22685=>17459, +22698=>17460, +22705=>17461, +136301=>17462, +22723=>17463, +22733=>17464, +22754=>17465, +22771=>17466, +22772=>17467, +22789=>17468, +22790=>17469, +22797=>17470, +22804=>17471, +136663=>17472, +13969=>17473, +22845=>17474, +13977=>17475, +22854=>17476, +13974=>17477, +158761=>17478, +22879=>17479, +136775=>17480, +22901=>17481, +22902=>17482, +22908=>17483, +22943=>17484, +22958=>17485, +22972=>17486, +22984=>17487, +22989=>17488, +23006=>17489, +23015=>17490, +23022=>17491, +136966=>17492, +137026=>17493, +14031=>17494, +23053=>17495, +23063=>17496, +23079=>17497, +23085=>17498, +23141=>17499, +23162=>17500, +23179=>17501, +23196=>17502, +23199=>17503, +23200=>17504, +23202=>17505, +23217=>17506, +23221=>17507, +23226=>17508, +23231=>17509, +23258=>17510, +23260=>17511, +23269=>17512, +23280=>17513, +23278=>17514, +23285=>17515, +23304=>17516, +23319=>17517, +23348=>17518, +23372=>17519, +23378=>17520, +23400=>17521, +23407=>17522, +23425=>17523, +23428=>17524, +137667=>17525, +23446=>17526, +23468=>17527, +14177=>17528, +14178=>17529, +23502=>17530, +23510=>17531, +14188=>17532, +14187=>17533, +23537=>17534, +23549=>17535, +14197=>17536, +23555=>17537, +23593=>17538, +138326=>17539, +23647=>17540, +23655=>17541, +23656=>17542, +23664=>17543, +138541=>17544, +138565=>17545, +138616=>17546, +138594=>17547, +23688=>17548, +23690=>17549, +14273=>17550, +138657=>17551, +138652=>17552, +23712=>17553, +23714=>17554, +23719=>17555, +138642=>17556, +23725=>17557, +23733=>17558, +138679=>17559, +23753=>17560, +138720=>17561, +138803=>17562, +23814=>17563, +23824=>17564, +23851=>17565, +23837=>17566, +23840=>17567, +23857=>17568, +23865=>17569, +14312=>17570, +23905=>17571, +23914=>17572, +14324=>17573, +23920=>17574, +139038=>17575, +14333=>17576, +23944=>17577, +14336=>17578, +23959=>17579, +23984=>17580, +23988=>17581, +139126=>17582, +24017=>17583, +24023=>17584, +139258=>17585, +24036=>17586, +24041=>17587, +14383=>17588, +14390=>17589, +14400=>17590, +24095=>17591, +24126=>17592, +24137=>17593, +14428=>17594, +24150=>17595, +14433=>17596, +24173=>17597, +24174=>17598, +139643=>17599, +24229=>17600, +24236=>17601, +24249=>17602, +24262=>17603, +24281=>17604, +140062=>17605, +24317=>17606, +24328=>17607, +140205=>17608, +24350=>17609, +24391=>17610, +24419=>17611, +24434=>17612, +24446=>17613, +24463=>17614, +24482=>17615, +24519=>17616, +24523=>17617, +24530=>17618, +24531=>17619, +24532=>17620, +24546=>17621, +24558=>17622, +24559=>17623, +24563=>17624, +14615=>17625, +24610=>17626, +24612=>17627, +14618=>17628, +24652=>17629, +24725=>17630, +24744=>17631, +141043=>17632, +24753=>17633, +24766=>17634, +24776=>17635, +24793=>17636, +24814=>17637, +24821=>17638, +24848=>17639, +24857=>17640, +24862=>17641, +24890=>17642, +14703=>17643, +24897=>17644, +24902=>17645, +24928=>17646, +141403=>17647, +24978=>17648, +24979=>17649, +24983=>17650, +24997=>17651, +25005=>17652, +141483=>17653, +25045=>17654, +25053=>17655, +25077=>17656, +141711=>17657, +25123=>17658, +25170=>17659, +25185=>17660, +25188=>17661, +25211=>17662, +25197=>17663, +25203=>17664, +25241=>17665, +25301=>17666, +142008=>17667, +25341=>17668, +25347=>17669, +25360=>17670, +142159=>17671, +142160=>17672, +25394=>17673, +25397=>17674, +25403=>17675, +25404=>17676, +25409=>17677, +25412=>17678, +25422=>17679, +142150=>17680, +25433=>17681, +142365=>17682, +142246=>17683, +25452=>17684, +25497=>17685, +142372=>17686, +25492=>17687, +25533=>17688, +25556=>17689, +25557=>17690, +25568=>17691, +25579=>17692, +25580=>17693, +25586=>17694, +25630=>17695, +25637=>17696, +25641=>17697, +25647=>17698, +25690=>17699, +25693=>17700, +25715=>17701, +25725=>17702, +25735=>17703, +25745=>17704, +25759=>17705, +25803=>17706, +25804=>17707, +25813=>17708, +25815=>17709, +142817=>17710, +25828=>17711, +25855=>17712, +14958=>17713, +25871=>17714, +25876=>17715, +14963=>17716, +25886=>17717, +25906=>17718, +25924=>17719, +25940=>17720, +25963=>17721, +25978=>17722, +25988=>17723, +25994=>17724, +26034=>17725, +26037=>17726, +26040=>17727, +26047=>17728, +26057=>17729, +26068=>17730, +15062=>17731, +26105=>17732, +26108=>17733, +26116=>17734, +26120=>17735, +26145=>17736, +26154=>17737, +26181=>17738, +26193=>17739, +26190=>17740, +15082=>17741, +143811=>17742, +143861=>17743, +143798=>17744, +26218=>17745, +26220=>17746, +26221=>17747, +26235=>17748, +26240=>17749, +26256=>17750, +26258=>17751, +15118=>17752, +26285=>17753, +26289=>17754, +26293=>17755, +15130=>17756, +15132=>17757, +15063=>17758, +26369=>17759, +26386=>17760, +144242=>17761, +26393=>17762, +144339=>17763, +144338=>17764, +26445=>17765, +26452=>17766, +26461=>17767, +144336=>17768, +144356=>17769, +144341=>17770, +26484=>17771, +144346=>17772, +26514=>17773, +144351=>17774, +33635=>17775, +26640=>17776, +26563=>17777, +26568=>17778, +26578=>17779, +26587=>17780, +26615=>17781, +144458=>17782, +144465=>17783, +144459=>17784, +26648=>17785, +26655=>17786, +26669=>17787, +144485=>17788, +26675=>17789, +26683=>17790, +26686=>17791, +26693=>17792, +26697=>17793, +26700=>17794, +26709=>17795, +26711=>17796, +15223=>17797, +26731=>17798, +26734=>17799, +26748=>17800, +26754=>17801, +26768=>17802, +26774=>17803, +15213=>17804, +26776=>17805, +26777=>17806, +26778=>17807, +26780=>17808, +26794=>17809, +26795=>17810, +26804=>17811, +26811=>17812, +26875=>17813, +144612=>17814, +144730=>17815, +26819=>17816, +26821=>17817, +26828=>17818, +26841=>17819, +26852=>17820, +26853=>17821, +26860=>17822, +26871=>17823, +26883=>17824, +26887=>17825, +15239=>17826, +144788=>17827, +15245=>17828, +26950=>17829, +26985=>17830, +26988=>17831, +27002=>17832, +27026=>17833, +15268=>17834, +27030=>17835, +27056=>17836, +27066=>17837, +27068=>17838, +27072=>17839, +27089=>17840, +144953=>17841, +144967=>17842, +144952=>17843, +27107=>17844, +27118=>17845, +27119=>17846, +27123=>17847, +15309=>17848, +27124=>17849, +27134=>17850, +27153=>17851, +27162=>17852, +27165=>17853, +145180=>17854, +27186=>17855, +27187=>17856, +27199=>17857, +27209=>17858, +27258=>17859, +27214=>17860, +27218=>17861, +27236=>17862, +145164=>17863, +27275=>17864, +15344=>17865, +27297=>17866, +145252=>17867, +27307=>17868, +27325=>17869, +27334=>17870, +27348=>17871, +27344=>17872, +27357=>17873, +145407=>17874, +145383=>17875, +27377=>17876, +27378=>17877, +27379=>17878, +27389=>17879, +145444=>17880, +27403=>17881, +27407=>17882, +27408=>17883, +27409=>17884, +145469=>17885, +27415=>17886, +15398=>17887, +27439=>17888, +27466=>17889, +27480=>17890, +27500=>17891, +27509=>17892, +11934=>17893, +27514=>17893, +27521=>17894, +27547=>17895, +27566=>17896, +146072=>17897, +27581=>17898, +27591=>17899, +27592=>17900, +27593=>17901, +27610=>17902, +27622=>17903, +27623=>17904, +27630=>17905, +27650=>17906, +27658=>17907, +27662=>17908, +27702=>17909, +146559=>17910, +27725=>17911, +27739=>17912, +27757=>17913, +27780=>17914, +27785=>17915, +15555=>17916, +27796=>17917, +27799=>17918, +27821=>17919, +27842=>17920, +15570=>17921, +27868=>17922, +27881=>17923, +27885=>17924, +146688=>17925, +27904=>17926, +27940=>17927, +27942=>17928, +27943=>17929, +27751=>17930, +27951=>17931, +27964=>17932, +27995=>17933, +28000=>17934, +28016=>17935, +28032=>17936, +28033=>17937, +28042=>17938, +28045=>17939, +28049=>17940, +28056=>17941, +146752=>17942, +146938=>17943, +146937=>17944, +146899=>17945, +28075=>17946, +28078=>17947, +28084=>17948, +28098=>17949, +27956=>17950, +28104=>17951, +28110=>17952, +28127=>17953, +28150=>17954, +28214=>17955, +28190=>17956, +15633=>17957, +28210=>17958, +28232=>17959, +28233=>17960, +28235=>17961, +28236=>17962, +28239=>17963, +28243=>17964, +28244=>17965, +28247=>17966, +28259=>17967, +15646=>17968, +28307=>17969, +28327=>17970, +28340=>17971, +28355=>17972, +28469=>17973, +28395=>17974, +28409=>17975, +28411=>17976, +28426=>17977, +28428=>17978, +28440=>17979, +28453=>17980, +28470=>17981, +28476=>17982, +147326=>17983, +28498=>17984, +28503=>17985, +28512=>17986, +28520=>17987, +28560=>17988, +28566=>17989, +28606=>17990, +28575=>17991, +28581=>17992, +28591=>17993, +15716=>17994, +28616=>17995, +28617=>17996, +28649=>17997, +147606=>17998, +28668=>17999, +28672=>18000, +28682=>18001, +28707=>18002, +147715=>18003, +28730=>18004, +28739=>18005, +28743=>18006, +28747=>18007, +15770=>18008, +28773=>18009, +28777=>18010, +28782=>18011, +28790=>18012, +28806=>18013, +28823=>18014, +147910=>18015, +28831=>18016, +28849=>18017, +147966=>18018, +28908=>18019, +28874=>18020, +28881=>18021, +28931=>18022, +28934=>18023, +28936=>18024, +28940=>18025, +15808=>18026, +28975=>18027, +29008=>18028, +29011=>18029, +29022=>18030, +15828=>18031, +29078=>18032, +29056=>18033, +29083=>18034, +29088=>18035, +29090=>18036, +29102=>18037, +29103=>18038, +148412=>18039, +29145=>18040, +29148=>18041, +29191=>18042, +15877=>18043, +29236=>18044, +29241=>18045, +29250=>18046, +29271=>18047, +29283=>18048, +149033=>18049, +29294=>18050, +29295=>18051, +29304=>18052, +29311=>18053, +29326=>18054, +149157=>18055, +29358=>18056, +29360=>18057, +29377=>18058, +15968=>18059, +29388=>18060, +15974=>18061, +15976=>18062, +29427=>18063, +29434=>18064, +29447=>18065, +29458=>18066, +29464=>18067, +29465=>18068, +16003=>18069, +29497=>18070, +29484=>18071, +29491=>18072, +29501=>18073, +29522=>18074, +16020=>18075, +29547=>18076, +149654=>18077, +29550=>18078, +29551=>18079, +29553=>18080, +29569=>18081, +29578=>18082, +29588=>18083, +29592=>18084, +29596=>18085, +29605=>18086, +29625=>18087, +29631=>18088, +29637=>18089, +29643=>18090, +29665=>18091, +29671=>18092, +29689=>18093, +29715=>18094, +29690=>18095, +29697=>18096, +29779=>18097, +29760=>18098, +29763=>18099, +29778=>18100, +29789=>18101, +29825=>18102, +29832=>18103, +150093=>18104, +29842=>18105, +29847=>18106, +29849=>18107, +29857=>18108, +29861=>18109, +29866=>18110, +29881=>18111, +29883=>18112, +29882=>18113, +29910=>18114, +29912=>18115, +29931=>18116, +150358=>18117, +29946=>18118, +150383=>18119, +29984=>18120, +29988=>18121, +29994=>18122, +16215=>18123, +150550=>18124, +30013=>18125, +30014=>18126, +30016=>18127, +30024=>18128, +30032=>18129, +30034=>18130, +30066=>18131, +30065=>18132, +30074=>18133, +30077=>18134, +30078=>18135, +30092=>18136, +16245=>18137, +30114=>18138, +16247=>18139, +30128=>18140, +30135=>18141, +30143=>18142, +30144=>18143, +30150=>18144, +30159=>18145, +30163=>18146, +30173=>18147, +30175=>18148, +30176=>18149, +30183=>18150, +30190=>18151, +30193=>18152, +30211=>18153, +30232=>18154, +30215=>18155, +30223=>18156, +16302=>18157, +151054=>18158, +30227=>18159, +30235=>18160, +30236=>18161, +151095=>18162, +30245=>18163, +30248=>18164, +30268=>18165, +30259=>18166, +151146=>18167, +16329=>18168, +30273=>18169, +151179=>18170, +30281=>18171, +30293=>18172, +16343=>18173, +30318=>18174, +30357=>18175, +30369=>18176, +30368=>18177, +30375=>18178, +30376=>18179, +30383=>18180, +151626=>18181, +30409=>18182, +151637=>18183, +30440=>18184, +151842=>18185, +30487=>18186, +30490=>18187, +30509=>18188, +30517=>18189, +151977=>18190, +16441=>18191, +152037=>18192, +152013=>18193, +30552=>18194, +152094=>18195, +30588=>18196, +152140=>18197, +16472=>18198, +30618=>18199, +30623=>18200, +30626=>18201, +30628=>18202, +30686=>18203, +30687=>18204, +30692=>18205, +30698=>18206, +30700=>18207, +30715=>18208, +152622=>18209, +30725=>18210, +30729=>18211, +30733=>18212, +30745=>18213, +30764=>18214, +30791=>18215, +30826=>18216, +152793=>18217, +30858=>18218, +30868=>18219, +30884=>18220, +30877=>18221, +30879=>18222, +30907=>18223, +30933=>18224, +30950=>18225, +30969=>18226, +30970=>18227, +30974=>18228, +152999=>18229, +30992=>18230, +31003=>18231, +31013=>18232, +31050=>18233, +31064=>18234, +16645=>18235, +31079=>18236, +31090=>18237, +31125=>18238, +31137=>18239, +31145=>18240, +31156=>18241, +31170=>18242, +31175=>18243, +31180=>18244, +31181=>18245, +31190=>18246, +16712=>18247, +153513=>18248, +153524=>18249, +16719=>18250, +31242=>18251, +31253=>18252, +31259=>18253, +16739=>18254, +31288=>18255, +31303=>18256, +31318=>18257, +31321=>18258, +31324=>18259, +31327=>18260, +31335=>18261, +31338=>18262, +31349=>18263, +31362=>18264, +31370=>18265, +31376=>18266, +31404=>18267, +154068=>18268, +16820=>18269, +31417=>18270, +31422=>18271, +16831=>18272, +31436=>18273, +31464=>18274, +31476=>18275, +154340=>18276, +154339=>18277, +154353=>18278, +31549=>18279, +31530=>18280, +31534=>18281, +31535=>18282, +16870=>18283, +16883=>18284, +31615=>18285, +31553=>18286, +16878=>18287, +31573=>18288, +31609=>18289, +31588=>18290, +31590=>18291, +31603=>18292, +154546=>18293, +16903=>18294, +31632=>18295, +31643=>18296, +16910=>18297, +31669=>18298, +31676=>18299, +31685=>18300, +31690=>18301, +154699=>18302, +154724=>18303, +31700=>18304, +31702=>18305, +31706=>18306, +31722=>18307, +31728=>18308, +31747=>18309, +31758=>18310, +31813=>18311, +31818=>18312, +31831=>18313, +31838=>18314, +31841=>18315, +31849=>18316, +31855=>18317, +155182=>18318, +155222=>18319, +155237=>18320, +31910=>18321, +155234=>18322, +31926=>18323, +31927=>18324, +155352=>18325, +31940=>18326, +155330=>18327, +31949=>18328, +155368=>18329, +155427=>18330, +31974=>18331, +155484=>18332, +31989=>18333, +32003=>18334, +17094=>18335, +32018=>18336, +32030=>18337, +155616=>18338, +155604=>18339, +32061=>18340, +32062=>18341, +32064=>18342, +32071=>18343, +155660=>18344, +155643=>18345, +17110=>18346, +32090=>18347, +32106=>18348, +32112=>18349, +17117=>18350, +32127=>18351, +155671=>18352, +32136=>18353, +32151=>18354, +155744=>18355, +32157=>18356, +32167=>18357, +32170=>18358, +32182=>18359, +32192=>18360, +32215=>18361, +32217=>18362, +32230=>18363, +17154=>18364, +155885=>18365, +64088=>18366, +32272=>18367, +32279=>18368, +32285=>18369, +32295=>18370, +32300=>18371, +32325=>18372, +32373=>18373, +32382=>18374, +32390=>18375, +32391=>18376, +17195=>18377, +32410=>18378, +17219=>18379, +32572=>18380, +32571=>18381, +32574=>18382, +32579=>18383, +13505=>18384, +156272=>18385, +156294=>18386, +32611=>18387, +32612=>18388, +32621=>18389, +32637=>18390, +32638=>18391, +32656=>18392, +20859=>18393, +146702=>18394, +32662=>18395, +32668=>18396, +32685=>18397, +156674=>18398, +32707=>18399, +32719=>18400, +32739=>18401, +32754=>18402, +32778=>18403, +32776=>18404, +32790=>18405, +32812=>18406, +32816=>18407, +32835=>18408, +32870=>18409, +32891=>18410, +32921=>18411, +32924=>18412, +32932=>18413, +32935=>18414, +32952=>18415, +157310=>18416, +32965=>18417, +32981=>18418, +32998=>18419, +33037=>18420, +33013=>18421, +33019=>18422, +17390=>18423, +33077=>18424, +33054=>18425, +17392=>18426, +33060=>18427, +33063=>18428, +33068=>18429, +157469=>18430, +33085=>18431, +17416=>18432, +33129=>18433, +17431=>18434, +17436=>18435, +33157=>18436, +17442=>18437, +33176=>18438, +33202=>18439, +33217=>18440, +33219=>18441, +33238=>18442, +33243=>18443, +157917=>18444, +33252=>18445, +157930=>18446, +33260=>18447, +33277=>18448, +33279=>18449, +158063=>18450, +33284=>18451, +158173=>18452, +33305=>18453, +33314=>18454, +158238=>18455, +33340=>18456, +33353=>18457, +33349=>18458, +158296=>18459, +17526=>18460, +17530=>18461, +33367=>18462, +158348=>18463, +33372=>18464, +33379=>18465, +158391=>18466, +17553=>18467, +33405=>18468, +33407=>18469, +33411=>18470, +33418=>18471, +33427=>18472, +33447=>18473, +33448=>18474, +33458=>18475, +33460=>18476, +33466=>18477, +33468=>18478, +33506=>18479, +33512=>18480, +33527=>18481, +33543=>18482, +33544=>18483, +33548=>18484, +33620=>18485, +33563=>18486, +33565=>18487, +33584=>18488, +33596=>18489, +33604=>18490, +33623=>18491, +17598=>18492, +17620=>18493, +17587=>18494, +33684=>18495, +33685=>18496, +33691=>18497, +33693=>18498, +33737=>18499, +33744=>18500, +33748=>18501, +33757=>18502, +33765=>18503, +33785=>18504, +33813=>18505, +158835=>18506, +33815=>18507, +33849=>18508, +33871=>18509, +33873=>18510, +33874=>18511, +33881=>18512, +33882=>18513, +33884=>18514, +158941=>18515, +33893=>18516, +33912=>18517, +33916=>18518, +33921=>18519, +17677=>18520, +33943=>18521, +33958=>18522, +33982=>18523, +17672=>18524, +33998=>18525, +33999=>18526, +34003=>18527, +159333=>18528, +34023=>18529, +34026=>18530, +34031=>18531, +34033=>18532, +34042=>18533, +34075=>18534, +34084=>18535, +34085=>18536, +34091=>18537, +34127=>18538, +34159=>18539, +17731=>18540, +34129=>18541, +34145=>18542, +34146=>18543, +159636=>18544, +34171=>18545, +34173=>18546, +34175=>18547, +34177=>18548, +34182=>18549, +34195=>18550, +34205=>18551, +34207=>18552, +159736=>18553, +159734=>18554, +159735=>18555, +34236=>18556, +34247=>18557, +34250=>18558, +34264=>18559, +34265=>18560, +34271=>18561, +34273=>18562, +34278=>18563, +34294=>18564, +34304=>18565, +34321=>18566, +34334=>18567, +34337=>18568, +34340=>18569, +34343=>18570, +160013=>18571, +34361=>18572, +34364=>18573, +160057=>18574, +34368=>18575, +34387=>18576, +34390=>18577, +34423=>18578, +34439=>18579, +34441=>18580, +34460=>18581, +34461=>18582, +34481=>18583, +34483=>18584, +34497=>18585, +34499=>18586, +34513=>18587, +34517=>18588, +34519=>18589, +34531=>18590, +34534=>18591, +17848=>18592, +34565=>18593, +34567=>18594, +34574=>18595, +34576=>18596, +34591=>18597, +34593=>18598, +34595=>18599, +34609=>18600, +34618=>18601, +34624=>18602, +34627=>18603, +34641=>18604, +34648=>18605, +34660=>18606, +34661=>18607, +34674=>18608, +34684=>18609, +160731=>18610, +160730=>18611, +34727=>18612, +34697=>18613, +34699=>18614, +34707=>18615, +34720=>18616, +160766=>18617, +17893=>18618, +34750=>18619, +160784=>18620, +34753=>18621, +34766=>18622, +34783=>18623, +160841=>18624, +34787=>18625, +34789=>18626, +34790=>18627, +34794=>18628, +34835=>18629, +34856=>18630, +34862=>18631, +34866=>18632, +34876=>18633, +17935=>18634, +34890=>18635, +34904=>18636, +161301=>18637, +161300=>18638, +34921=>18639, +161329=>18640, +34927=>18641, +34976=>18642, +35004=>18643, +35008=>18644, +161427=>18645, +35025=>18646, +35027=>18647, +17985=>18648, +35073=>18649, +161550=>18650, +35127=>18651, +161571=>18652, +35138=>18653, +35141=>18654, +35145=>18655, +161618=>18656, +35170=>18657, +35209=>18658, +35216=>18659, +35231=>18660, +35248=>18661, +35255=>18662, +35288=>18663, +35307=>18664, +18081=>18665, +35315=>18666, +35325=>18667, +35327=>18668, +18095=>18669, +35345=>18670, +35348=>18671, +162181=>18672, +35361=>18673, +35381=>18674, +35390=>18675, +35397=>18676, +35405=>18677, +35416=>18678, +35502=>18679, +35472=>18680, +35511=>18681, +35543=>18682, +35580=>18683, +162436=>18684, +35594=>18685, +35589=>18686, +35597=>18687, +35612=>18688, +35629=>18689, +18188=>18690, +35665=>18691, +35678=>18692, +35702=>18693, +35713=>18694, +35723=>18695, +35732=>18696, +35733=>18697, +35897=>18698, +162739=>18699, +35901=>18700, +162750=>18701, +162759=>18702, +35909=>18703, +35919=>18704, +35927=>18705, +35945=>18706, +35949=>18707, +163000=>18708, +35987=>18709, +35986=>18710, +35993=>18711, +18276=>18712, +35995=>18713, +36054=>18714, +36053=>18715, +163232=>18716, +36081=>18717, +163344=>18718, +36105=>18719, +36110=>18720, +36296=>18721, +36313=>18722, +36364=>18723, +18429=>18724, +36349=>18725, +36358=>18726, +163978=>18727, +36372=>18728, +36374=>18729, +36385=>18730, +36386=>18731, +36391=>18732, +164027=>18733, +18454=>18734, +36406=>18735, +36409=>18736, +36436=>18737, +36450=>18738, +36461=>18739, +36463=>18740, +36504=>18741, +36510=>18742, +36533=>18743, +36539=>18744, +164482=>18745, +18510=>18746, +164595=>18747, +36608=>18748, +36616=>18749, +36651=>18750, +36672=>18751, +36682=>18752, +36696=>18753, +164876=>18754, +36772=>18755, +36788=>18756, +164949=>18757, +36801=>18758, +36806=>18759, +64036=>18760, +36810=>18761, +36813=>18762, +36819=>18763, +36821=>18764, +36849=>18765, +36853=>18766, +36859=>18767, +36876=>18768, +36919=>18769, +165227=>18770, +36931=>18771, +36957=>18772, +165320=>18773, +165321=>18774, +36997=>18775, +37004=>18776, +37008=>18777, +37025=>18778, +18613=>18779, +37040=>18780, +37046=>18781, +37059=>18782, +37064=>18783, +165591=>18784, +37084=>18785, +37087=>18786, +165626=>18787, +37110=>18788, +37106=>18789, +37120=>18790, +37099=>18791, +37118=>18792, +37119=>18793, +37124=>18794, +37126=>18795, +37144=>18796, +37150=>18797, +37175=>18798, +37177=>18799, +37190=>18800, +37191=>18801, +37207=>18802, +37209=>18803, +37236=>18804, +37241=>18805, +37253=>18806, +37299=>18807, +37302=>18808, +37315=>18809, +37316=>18810, +166217=>18811, +166214=>18812, +37356=>18813, +37377=>18814, +37398=>18815, +37399=>18816, +166251=>18817, +37442=>18818, +37450=>18819, +37462=>18820, +37473=>18821, +37477=>18822, +37480=>18823, +166280=>18824, +37500=>18825, +37501=>18826, +37503=>18827, +37513=>18828, +37517=>18829, +37527=>18830, +37529=>18831, +37535=>18832, +37547=>18833, +166330=>18834, +166331=>18835, +37554=>18836, +37567=>18837, +37568=>18838, +37574=>18839, +37582=>18840, +37605=>18841, +37649=>18842, +166430=>18843, +166441=>18844, +37623=>18845, +37673=>18846, +166513=>18847, +166467=>18848, +37713=>18849, +37722=>18850, +37739=>18851, +37745=>18852, +37747=>18853, +37793=>18854, +166553=>18855, +166605=>18856, +37768=>18857, +37771=>18858, +37775=>18859, +37790=>18860, +37877=>18861, +166628=>18862, +166621=>18863, +37873=>18864, +37831=>18865, +37852=>18866, +37863=>18867, +37897=>18868, +37910=>18869, +37911=>18870, +37883=>18871, +37938=>18872, +37947=>18873, +166849=>18874, +166895=>18875, +37997=>18876, +37999=>18877, +38265=>18878, +38278=>18879, +38284=>18880, +38285=>18881, +167184=>18882, +167281=>18883, +38344=>18884, +167419=>18885, +167455=>18886, +38444=>18887, +38451=>18888, +38452=>18889, +167478=>18890, +38460=>18891, +38497=>18892, +167561=>18893, +38530=>18894, +167659=>18895, +38554=>18896, +167730=>18897, +18919=>18898, +38579=>18899, +38586=>18900, +38589=>18901, +18938=>18902, +167928=>18903, +38616=>18904, +38618=>18905, +38621=>18906, +18948=>18907, +38676=>18908, +38691=>18909, +18985=>18910, +38710=>18911, +38721=>18912, +38727=>18913, +38743=>18914, +38747=>18915, +38762=>18916, +168608=>18917, +168625=>18918, +38806=>18919, +38814=>18920, +38833=>18921, +38834=>18922, +38846=>18923, +38860=>18924, +38865=>18925, +38868=>18926, +38872=>18927, +38881=>18928, +38897=>18929, +38916=>18930, +38925=>18931, +38932=>18932, +38934=>18933, +19132=>18934, +169104=>18935, +38962=>18936, +38963=>18937, +38949=>18938, +38983=>18939, +39014=>18940, +39083=>18941, +39085=>18942, +39088=>18943, +169423=>18944, +39095=>18945, +39099=>18946, +39100=>18947, +39106=>18948, +39111=>18949, +39115=>18950, +39137=>18951, +39139=>18952, +39146=>18953, +39152=>18954, +39153=>18955, +39155=>18956, +39176=>18957, +19259=>18958, +169712=>18959, +39190=>18960, +39191=>18961, +169753=>18962, +39194=>18963, +39195=>18964, +39196=>18965, +169808=>18966, +39217=>18967, +39226=>18968, +39227=>18969, +39228=>18970, +39233=>18971, +39238=>18972, +39246=>18973, +39264=>18974, +39331=>18975, +39334=>18976, +39357=>18977, +39359=>18978, +39363=>18979, +39380=>18980, +39385=>18981, +39390=>18982, +170182=>18983, +39408=>18984, +39417=>18985, +39420=>18986, +39434=>18987, +39441=>18988, +39450=>18989, +39456=>18990, +39473=>18991, +39492=>18992, +39500=>18993, +39512=>18994, +19394=>18995, +39599=>18996, +19402=>18997, +39607=>18998, +19410=>18999, +39609=>19000, +170610=>19001, +39622=>19002, +39632=>19003, +39634=>19004, +39637=>19005, +39648=>19006, +39653=>19007, +39657=>19008, +39692=>19009, +39696=>19010, +39698=>19011, +39702=>19012, +39708=>19013, +39723=>19014, +39741=>19015, +19488=>19016, +39755=>19017, +39779=>19018, +39781=>19019, +39787=>19020, +39788=>19021, +39798=>19022, +39799=>19023, +39846=>19024, +39852=>19025, +171483=>19026, +39858=>19027, +39864=>19028, +39870=>19029, +39923=>19030, +39896=>19031, +39901=>19032, +39914=>19033, +39919=>19034, +39918=>19035, +171541=>19036, +171658=>19037, +171593=>19038, +39958=>19039, +39960=>19040, +39961=>19041, +39962=>19042, +39965=>19043, +39970=>19044, +39977=>19045, +171716=>19046, +39985=>19047, +39991=>19048, +40005=>19049, +40028=>19050, +171753=>19051, +40009=>19052, +40010=>19053, +171739=>19054, +40020=>19055, +40024=>19056, +40027=>19057, +40029=>19058, +40031=>19059, +40041=>19060, +40042=>19061, +40043=>19062, +40045=>19063, +40046=>19064, +40050=>19065, +40053=>19066, +40058=>19067, +40166=>19068, +40178=>19069, +40203=>19070, +171982=>19071, +171991=>19071, +40209=>19072, +40215=>19073, +40216=>19074, +172079=>19075, +19652=>19076, +172058=>19077, +40242=>19078, +19665=>19079, +40266=>19080, +40287=>19081, +40290=>19082, +172281=>19083, +172162=>19084, +40307=>19085, +40310=>19086, +40311=>19087, +40324=>19088, +40345=>19089, +40353=>19090, +40383=>19091, +40373=>19092, +40377=>19093, +40381=>19094, +40393=>19095, +40410=>19096, +40416=>19097, +40419=>19098, +19719=>19099, +40458=>19100, +40450=>19101, +40461=>19102, +40476=>19103, +40571=>19104, +139800=>19105, +40576=>19106, +40581=>19107, +40603=>19108, +172940=>19109, +40637=>19110, +173111=>19111, +40671=>19112, +40703=>19113, +40706=>19114, +19831=>19115, +40707=>19116, +40762=>19117, +40765=>19118, +40774=>19119, +40787=>19120, +40789=>19121, +40792=>19122, +173553=>19123, +40797=>19124, +173570=>19125, +40809=>19126, +40813=>19127, +40816=>19128, +173746=>19129, +11948=>19130, +13844=>19131, +14509=>19132, +15820=>19133, +16348=>19134, +17854=>19135, +17936=>19136, +19326=>19137, +19512=>19138, +19681=>19139, +19980=>19140, +20003=>19141, +20004=>19142, +20089=>19143, +20211=>19144, +20236=>19145, +20249=>19146, +20267=>19147, +20270=>19148, +20273=>19149, +20356=>19150, +20382=>19151, +20407=>19152, +20484=>19153, +20492=>19154, +20556=>19155, +20575=>19156, +20578=>19157, +20599=>19158, +20622=>19159, +20638=>19160, +20642=>19161, +20675=>19162, +20712=>19163, +20721=>19164, +20734=>19165, +20743=>19166, +20748=>19167, +20749=>19168, +20750=>19169, +20787=>19170, +20792=>19171, +20852=>19172, +20868=>19173, +20920=>19174, +20922=>19175, +20936=>19176, +20943=>19177, +20945=>19178, +20947=>19179, +20948=>19180, +20952=>19181, +20959=>19182, +20997=>19183, +21030=>19184, +21032=>19185, +21035=>19186, +21041=>19187, +21042=>19188, +21045=>19189, +21052=>19190, +21082=>19191, +21088=>19192, +21102=>19193, +21112=>19194, +21113=>19195, +21130=>19196, +21132=>19197, +21217=>19198, +21225=>19199, +21233=>19200, +21251=>19201, +21265=>19202, +21279=>19203, +21293=>19204, +21298=>19205, +21309=>19206, +21349=>19207, +21357=>19208, +21369=>19209, +21374=>19210, +21396=>19211, +21401=>19212, +21418=>19213, +21423=>19214, +21434=>19215, +21441=>19216, +21444=>19217, +21445=>19218, +21472=>19219, +21523=>19220, +21546=>19221, +21553=>19222, +21556=>19223, +21557=>19224, +21580=>19225, +21671=>19226, +21674=>19227, +21681=>19228, +21691=>19229, +21710=>19230, +21738=>19231, +21756=>19232, +21765=>19233, +21768=>19234, +21781=>19235, +21799=>19236, +21802=>19237, +21814=>19238, +21841=>19239, +21862=>19240, +21903=>19241, +21906=>19242, +21908=>19243, +21924=>19244, +21938=>19245, +21955=>19246, +21958=>19247, +21971=>19248, +21979=>19249, +21996=>19250, +21998=>19251, +22001=>19252, +22006=>19253, +22008=>19254, +22021=>19255, +22029=>19256, +22033=>19257, +22034=>19258, +22060=>19259, +22069=>19260, +22073=>19261, +22093=>19262, +22100=>19263, +22149=>19264, +22175=>19265, +22182=>19266, +22199=>19267, +22220=>19268, +22223=>19269, +22233=>19270, +22241=>19271, +22251=>19272, +22253=>19273, +22257=>19274, +22279=>19275, +22284=>19276, +22298=>19277, +22299=>19278, +22301=>19279, +22316=>19280, +22318=>19281, +22333=>19282, +22334=>19283, +22367=>19284, +22379=>19285, +22381=>19286, +22394=>19287, +22403=>19288, +22423=>19289, +22446=>19290, +22485=>19291, +22503=>19292, +22541=>19293, +22566=>19294, +22605=>19295, +22607=>19296, +22623=>19297, +22637=>19298, +22655=>19299, +22657=>19300, +22680=>19301, +22716=>19302, +22815=>19303, +22819=>19304, +22873=>19305, +22905=>19306, +22935=>19307, +22959=>19308, +22963=>19309, +23007=>19310, +23025=>19311, +23032=>19312, +23218=>19313, +23224=>19314, +23274=>19315, +23286=>19316, +23323=>19317, +23325=>19318, +23329=>19319, +23352=>19320, +23479=>19321, +23511=>19322, +23520=>19323, +23583=>19324, +23594=>19325, +23596=>19326, +23606=>19327, +23641=>19328, +23644=>19329, +23661=>19330, +23773=>19331, +23809=>19332, +23860=>19333, +23869=>19334, +23897=>19335, +23934=>19336, +23939=>19337, +24007=>19338, +24057=>19339, +24104=>19340, +24114=>19341, +24117=>19342, +24155=>19343, +24168=>19344, +24170=>19345, +24183=>19346, +24192=>19347, +24203=>19348, +24243=>19349, +24253=>19350, +24273=>19351, +24276=>19352, +24277=>19353, +24397=>19354, +24492=>19355, +24554=>19356, +24583=>19357, +24649=>19358, +24660=>19359, +24679=>19360, +24763=>19361, +24772=>19362, +24829=>19363, +24842=>19364, +24854=>19365, +24874=>19366, +24886=>19367, +24926=>19368, +24932=>19369, +24955=>19370, +24957=>19371, +24959=>19372, +24989=>19373, +25016=>19374, +25052=>19375, +25058=>19376, +25061=>19377, +25064=>19378, +25092=>19379, +25095=>19380, +25137=>19381, +25145=>19382, +25149=>19383, +25210=>19384, +25232=>19385, +25256=>19386, +25306=>19387, +25332=>19388, +25366=>19389, +25386=>19390, +25398=>19391, +25414=>19392, +25419=>19393, +25427=>19394, +25457=>19395, +25461=>19396, +25471=>19397, +25474=>19398, +25482=>19399, +25518=>19400, +25519=>19401, +25578=>19402, +25592=>19403, +25593=>19404, +25618=>19405, +25624=>19406, +25632=>19407, +25636=>19408, +25642=>19409, +25653=>19410, +25661=>19411, +25663=>19412, +25682=>19413, +25695=>19414, +25716=>19415, +25744=>19416, +25752=>19417, +25753=>19418, +25772=>19419, +25779=>19420, +25837=>19421, +25840=>19422, +25883=>19423, +25887=>19424, +25902=>19425, +25929=>19426, +25952=>19427, +26002=>19428, +26005=>19429, +26036=>19430, +26046=>19431, +26056=>19432, +26062=>19433, +26064=>19434, +26079=>19435, +26238=>19436, +26251=>19437, +26252=>19438, +26291=>19439, +26304=>19440, +26319=>19441, +26405=>19442, +26421=>19443, +26453=>19444, +26496=>19445, +26511=>19446, +26513=>19447, +26532=>19448, +26545=>19449, +26549=>19450, +26558=>19451, +26664=>19452, +26758=>19453, +26859=>19454, +26869=>19455, +26903=>19456, +26931=>19457, +26936=>19458, +26971=>19459, +26981=>19460, +27048=>19461, +27051=>19462, +27055=>19463, +27109=>19464, +27121=>19465, +27210=>19466, +27221=>19467, +27239=>19468, +27249=>19469, +27311=>19470, +27336=>19471, +27337=>19472, +27395=>19473, +27451=>19474, +27455=>19475, +27517=>19476, +27518=>19477, +27568=>19478, +27639=>19479, +27641=>19480, +27652=>19481, +27657=>19482, +27661=>19483, +27692=>19484, +27722=>19485, +27730=>19486, +27732=>19487, +27769=>19488, +27820=>19489, +27828=>19490, +27858=>19491, +28001=>19492, +28028=>19493, +28089=>19494, +28144=>19495, +28229=>19496, +28275=>19497, +28283=>19498, +28285=>19499, +28297=>19500, +28348=>19501, +28378=>19502, +28379=>19503, +28454=>19504, +28457=>19505, +28464=>19506, +28551=>19507, +28573=>19508, +28590=>19509, +28599=>19510, +28685=>19511, +28704=>19512, +28745=>19513, +28824=>19514, +28848=>19515, +28885=>19516, +28886=>19517, +28997=>19518, +29106=>19519, +29172=>19520, +29207=>19521, +29215=>19522, +29251=>19523, +29263=>19524, +29264=>19525, +29274=>19526, +29280=>19527, +29288=>19528, +29303=>19529, +29316=>19530, +29385=>19531, +29413=>19532, +29428=>19533, +29442=>19534, +29451=>19535, +29470=>19536, +29474=>19537, +29498=>19538, +29499=>19539, +29517=>19540, +29528=>19541, +29543=>19542, +29810=>19543, +29871=>19544, +29919=>19545, +29924=>19546, +29940=>19547, +29947=>19548, +29974=>19549, +29985=>19550, +30015=>19551, +30046=>19552, +30105=>19553, +30116=>19554, +30145=>19555, +30148=>19556, +30156=>19557, +30167=>19558, +30172=>19559, +30177=>19560, +30191=>19561, +30212=>19562, +30220=>19563, +30237=>19564, +30258=>19565, +30264=>19566, +30277=>19567, +30282=>19568, +30303=>19569, +30381=>19570, +30397=>19571, +30425=>19572, +30443=>19573, +30448=>19574, +30457=>19575, +30464=>19576, +30478=>19577, +30498=>19578, +30504=>19579, +30511=>19580, +30521=>19581, +30526=>19582, +30533=>19583, +30538=>19584, +30543=>19585, +30558=>19586, +30564=>19587, +30567=>19588, +30572=>19589, +30596=>19590, +30604=>19591, +30605=>19592, +30614=>19593, +30631=>19594, +30639=>19595, +30647=>19596, +30654=>19597, +30665=>19598, +30673=>19599, +30681=>19600, +30705=>19601, +30775=>19602, +30812=>19603, +30846=>19604, +30872=>19605, +30881=>19606, +30897=>19607, +30899=>19608, +30921=>19609, +30931=>19610, +30988=>19611, +31007=>19612, +31015=>19613, +31016=>19614, +31039=>19615, +31042=>19616, +31060=>19617, +31083=>19618, +31100=>19619, +31147=>19620, +31172=>19621, +31210=>19622, +31234=>19623, +31244=>19624, +31280=>19625, +31290=>19626, +31300=>19627, +31360=>19628, +31366=>19629, +31380=>19630, +31413=>19631, +31421=>19632, +31486=>19633, +31531=>19634, +31607=>19635, +31648=>19636, +31660=>19637, +31664=>19638, +31720=>19639, +31730=>19640, +31736=>19641, +31740=>19642, +31742=>19643, +31753=>19644, +31784=>19645, +31791=>19646, +31810=>19647, +31826=>19648, +31827=>19649, +31835=>19650, +31836=>19651, +31837=>19652, +31858=>19653, +31869=>19654, +31879=>19655, +31902=>19656, +31930=>19657, +31943=>19658, +31955=>19659, +31962=>19660, +32060=>19661, +32077=>19662, +32130=>19663, +32133=>19664, +32141=>19665, +32145=>19666, +32158=>19667, +32179=>19668, +32185=>19669, +32208=>19670, +32229=>19671, +32245=>19672, +32246=>19673, +32303=>19674, +32310=>19675, +32324=>19676, +32367=>19677, +32376=>19678, +32385=>19679, +32573=>19680, +32603=>19681, +32605=>19682, +32613=>19683, +32625=>19684, +32639=>19685, +32640=>19686, +32651=>19687, +32674=>19688, +32765=>19689, +32766=>19690, +32767=>19691, +32775=>19692, +32781=>19693, +32798=>19694, +32825=>19695, +32904=>19696, +32910=>19697, +32975=>19698, +32980=>19699, +33005=>19700, +33008=>19701, +33015=>19702, +33018=>19703, +33022=>19704, +33027=>19705, +33047=>19706, +33072=>19707, +33111=>19708, +33135=>19709, +33139=>19710, +33163=>19711, +33168=>19712, +33179=>19713, +33182=>19714, +33227=>19715, +33237=>19716, +33245=>19717, +33246=>19718, +33249=>19719, +33263=>19720, +33270=>19721, +33280=>19722, +33291=>19723, +33299=>19724, +33300=>19725, +33306=>19726, +33338=>19727, +33348=>19728, +33389=>19729, +33412=>19730, +33417=>19731, +33425=>19732, +33450=>19733, +33456=>19734, +33488=>19735, +33514=>19736, +33519=>19737, +33526=>19738, +33622=>19739, +33656=>19740, +33784=>19741, +33788=>19742, +33880=>19743, +33939=>19744, +33969=>19745, +33981=>19746, +34043=>19747, +34118=>19748, +34134=>19749, +34141=>19750, +34181=>19751, +34200=>19752, +34370=>19753, +34374=>19754, +34496=>19755, +34580=>19756, +34594=>19757, +34606=>19758, +34617=>19759, +34653=>19760, +34683=>19761, +34700=>19762, +34702=>19763, +34711=>19764, +34712=>19765, +34718=>19766, +34723=>19767, +34734=>19768, +34751=>19769, +34761=>19770, +34778=>19771, +34840=>19772, +34843=>19773, +34861=>19774, +34874=>19775, +34885=>19776, +34891=>19777, +34894=>19778, +34901=>19779, +34906=>19780, +34926=>19781, +34970=>19782, +34971=>19783, +34972=>19784, +35021=>19785, +35040=>19786, +35055=>19787, +35086=>19788, +35087=>19789, +35110=>19790, +35125=>19791, +35162=>19792, +35164=>19793, +35179=>19794, +35184=>19795, +35196=>19796, +35237=>19797, +35253=>19798, +35260=>19799, +35285=>19800, +35401=>19801, +35415=>19802, +35431=>19803, +35454=>19804, +35462=>19805, +35478=>19806, +35510=>19807, +35529=>19808, +35537=>19809, +35549=>19810, +35564=>19811, +35573=>19812, +35590=>19813, +35599=>19814, +35601=>19815, +35653=>19816, +35666=>19817, +35693=>19818, +35704=>19819, +35708=>19820, +35710=>19821, +35717=>19822, +35743=>19823, +35915=>19824, +35923=>19825, +35963=>19826, +36026=>19827, +36037=>19828, +36041=>19829, +36050=>19830, +36076=>19831, +36085=>19832, +36087=>19833, +36097=>19834, +36099=>19835, +36119=>19836, +36124=>19837, +36206=>19838, +36241=>19839, +36255=>19840, +36267=>19841, +36274=>19842, +36309=>19843, +36327=>19844, +36337=>19845, +36338=>19846, +36340=>19847, +36353=>19848, +36363=>19849, +36390=>19850, +36401=>19851, +36416=>19852, +36417=>19853, +36429=>19854, +36431=>19855, +36444=>19856, +36449=>19857, +36457=>19858, +36465=>19859, +36469=>19860, +36471=>19861, +36489=>19862, +36496=>19863, +36501=>19864, +36506=>19865, +36519=>19866, +36521=>19867, +36525=>19868, +36584=>19869, +36592=>19870, +36615=>19871, +36632=>19872, +36645=>19873, +36647=>19874, +36652=>19875, +36661=>19876, +36666=>19877, +36675=>19878, +36679=>19879, +36689=>19880, +36693=>19881, +36768=>19882, +36769=>19883, +36770=>19884, +36773=>19885, +36868=>19886, +36891=>19887, +36911=>19888, +36940=>19889, +36955=>19890, +36976=>19891, +36980=>19892, +36985=>19893, +37003=>19894, +37016=>19895, +37024=>19896, +37042=>19897, +37053=>19898, +37065=>19899, +37104=>19900, +37125=>19901, +37157=>19902, +37210=>19903, +37223=>19904, +37242=>19905, +37258=>19906, +37265=>19907, +37269=>19908, +37296=>19909, +37307=>19910, +37309=>19911, +37314=>19912, +37317=>19913, +37376=>19914, +37385=>19915, +37411=>19916, +37494=>19917, +37518=>19918, +37551=>19919, +37563=>19920, +37564=>19921, +37569=>19922, +37571=>19923, +37573=>19924, +37576=>19925, +37652=>19926, +37683=>19927, +37686=>19928, +37720=>19929, +37759=>19930, +37762=>19931, +37770=>19932, +37819=>19933, +37836=>19934, +37862=>19935, +37881=>19936, +37890=>19937, +37901=>19938, +37902=>19939, +37934=>19940, +37964=>19941, +38280=>19942, +38305=>19943, +38335=>19944, +38342=>19945, +38345=>19946, +38353=>19947, +38354=>19948, +38368=>19949, +38372=>19950, +38374=>19951, +38436=>19952, +38449=>19953, +38456=>19954, +38461=>19955, +38484=>19956, +38516=>19957, +38523=>19958, +38527=>19959, +38529=>19960, +38531=>19961, +38537=>19962, +38550=>19963, +38574=>19964, +38659=>19965, +38683=>19966, +38689=>19967, +38690=>19968, +38696=>19969, +38705=>19970, +38759=>19971, +38774=>19972, +38781=>19973, +38783=>19974, +38809=>19975, +38815=>19976, +38828=>19977, +38841=>19978, +38861=>19979, +38880=>19980, +38895=>19981, +38919=>19982, +38950=>19983, +38958=>19984, +39010=>19985, +39011=>19986, +39092=>19987, +39109=>19988, +39170=>19989, +39185=>19990, +39189=>19991, +39221=>19992, +39240=>19993, +39252=>19994, +39262=>19995, +39393=>19996, +39436=>19997, +39440=>19998, +39459=>19999, +39489=>20000, +39505=>20001, +39613=>20002, +39614=>20003, +39681=>20004, +39689=>20005, +39691=>20006, +39693=>20007, +39694=>20008, +39705=>20009, +39733=>20010, +39752=>20011, +39765=>20012, +39784=>20013, +39808=>20014, +39814=>20015, +39824=>20016, +39837=>20017, +39856=>20018, +39871=>20019, +39880=>20020, +39935=>20021, +39938=>20022, +39964=>20023, +39989=>20024, +40004=>20025, +40022=>20026, +40033=>20027, +40040=>20028, +40240=>20029, +40253=>20030, +40298=>20031, +40315=>20032, +40421=>20033, +40425=>20034, +40435=>20035, +40570=>20036, +40578=>20037, +40579=>20038, +40580=>20039, +40624=>20040, +40676=>20041, +40688=>20042, +40690=>20043, +40713=>20044, +40719=>20045, +40724=>20046, +40731=>20047, +40738=>20048, +40742=>20049, +40746=>20050, +40747=>20051, +40756=>20052, +40794=>20053, +40815=>20054, +40862=>20055, +40869=>20056, +131317=>20057, +151044=>20058, +151538=>20059, +163187=>20060, +194581=>20061, +194630=>20062, +194713=>20063, +194726=>20064, +194789=>20065, +195038=>20066, +13790=>20067, +40895=>20068, +40896=>20069, +40897=>20070, +40898=>20071, +172722=>20072, +131416=>20075, +132529=>20080, +132844=>20083, +134488=>20090, +154060=>20112, +14756=>20122, +14776=>20123, +142914=>20124, +14940=>20127, +133064=>20128, +143339=>20130, +162228=>20133, +15044=>20135, +15051=>20136, +14981=>20142, +15347=>20151, +27384=>20152, +15665=>20158, +147531=>20168, +15936=>20170, +14497=>20171, +158878=>20206, +18207=>20219, +162876=>20220, +18462=>20225, +39709=>20297, +39724=>20298, +20482=>20299, +20958=>20300, +21255=>20301, +23532=>20302, +63784=>20303, +26142=>20304, +63785=>20305, +28746=>20306, +64021=>20307, +21857=>20308, +27706=>20309, +31328=>20310, +156492=>20311, +34819=>20312, +38315=>20313, +38741=>20314, +171581=>20315, +173594=>20316, +900=>20317, +901=>20318, +272=>20322, +294=>20323, +306=>20324, +319=>20325, +330=>20326, +358=>20327, +307=>20328, +312=>20329, +320=>20330, +329=>20331, +359=>20332, +266=>20333, +278=>20334, +286=>20335, +290=>20336, +288=>20337, +304=>20338, +302=>20339, +310=>20340, +315=>20342, +325=>20343, +342=>20344, +370=>20345, +471=>20346, +475=>20347, +473=>20348, +469=>20349, +372=>20350, +374=>20351, +267=>20352, +279=>20353, +501=>20354, +287=>20355, +289=>20356, +303=>20357, +311=>20358, +316=>20360, +326=>20361, +343=>20362, +371=>20363, +373=>20364, +375=>20365, +8494=>20366, +8710=>20367, +8719=>20368, +8804=>20369, +8805=>20370, +9674=>20371, +902=>20427, +904=>20428, +905=>20429, +906=>20430, +938=>20431, +908=>20432, +910=>20433, +939=>20434, +911=>20435, +940=>20436, +941=>20437, +942=>20438, +943=>20439, +970=>20440, +912=>20441, +972=>20442, +973=>20443, +971=>20444, +944=>20445, +974=>20446, +1026=>20447, +1027=>20448, +1028=>20449, +1029=>20450, +1030=>20451, +1031=>20452, +1032=>20453, +1033=>20454, +1034=>20455, +1035=>20456, +1036=>20457, +1038=>20458, +1039=>20459, +1106=>20460, +1107=>20461, +1108=>20462, +1109=>20463, +1110=>20464, +1111=>20465, +1112=>20466, +1113=>20467, +1114=>20468, +1115=>20469, +1116=>20470, +1118=>20471, +1119=>20472, +9361=>20587, +9362=>20588, +20021=>21075, +20060=>21076, +20067=>21077, +20072=>21078, +20084=>21079, +20085=>21080, +20119=>21081, +20143=>21082, +20187=>21083, +20194=>21084, +20200=>21085, +20207=>21086, +20222=>21087, +20226=>21088, +20232=>21089, +20242=>21090, +20247=>21091, +20275=>21092, +20277=>21093, +20288=>21094, +20290=>21095, +20299=>21096, +20300=>21097, +20306=>21098, +20323=>21099, +20334=>21100, +20337=>21101, +20345=>21102, +20353=>21103, +20361=>21104, +20364=>21105, +20366=>21106, +20368=>21107, +20371=>21108, +20377=>21109, +20383=>21110, +20409=>21111, +20411=>21112, +20412=>21113, +20413=>21114, +20416=>21115, +20417=>21116, +20422=>21117, +20424=>21118, +20428=>21119, +20444=>21120, +20450=>21121, +20464=>21122, +20476=>21123, +20487=>21124, +20490=>21125, +20503=>21126, +20509=>21127, +20528=>21128, +20530=>21129, +20531=>21130, +20533=>21131, +20549=>21132, +20554=>21133, +20561=>21134, +20562=>21135, +20569=>21136, +20576=>21137, +20583=>21138, +20589=>21139, +20593=>21140, +20609=>21141, +20611=>21142, +20612=>21143, +20614=>21144, +20618=>21145, +20624=>21146, +20635=>21147, +20639=>21148, +20640=>21149, +20641=>21150, +20655=>21151, +20656=>21152, +20665=>21153, +20669=>21154, +20672=>21155, +20691=>21156, +20700=>21157, +20701=>21158, +20703=>21159, +20706=>21160, +20708=>21161, +20726=>21162, +20730=>21163, +20761=>21165, +20764=>21166, +20765=>21167, +20771=>21168, +20775=>21169, +20776=>21170, +20780=>21171, +20781=>21172, +20783=>21173, +20785=>21174, +20788=>21175, +20793=>21176, +20802=>21177, +20815=>21178, +20819=>21179, +20824=>21180, +20838=>21181, +20862=>21182, +20878=>21183, +20927=>21184, +20930=>21185, +20946=>21186, +20949=>21187, +20965=>21188, +20978=>21189, +20983=>21190, +21016=>21191, +21026=>21192, +21061=>21193, +21080=>21194, +21087=>21195, +21120=>21196, +21125=>21197, +21141=>21198, +21142=>21199, +21143=>21200, +21146=>21201, +21157=>21202, +21159=>21203, +21168=>21204, +21174=>21205, +21175=>21206, +21176=>21207, +21181=>21208, +21188=>21209, +21190=>21210, +21199=>21211, +21204=>21212, +21212=>21213, +21221=>21214, +21224=>21215, +21226=>21216, +21228=>21217, +21236=>21218, +21238=>21219, +21260=>21220, +21267=>21221, +21272=>21222, +21275=>21223, +21278=>21224, +21285=>21225, +21287=>21226, +21288=>21227, +21289=>21228, +21291=>21229, +21292=>21230, +21296=>21231, +21308=>21232, +21337=>21233, +21339=>21234, +21379=>21236, +21383=>21237, +21384=>21238, +21390=>21239, +21409=>21240, +21429=>21241, +21432=>21242, +21437=>21243, +21455=>21244, +21458=>21245, +21459=>21246, +21470=>21247, +21479=>21249, +21506=>21250, +21530=>21251, +21537=>21252, +21551=>21253, +21572=>21254, +21575=>21255, +21583=>21256, +21598=>21257, +21604=>21258, +21607=>21259, +21609=>21260, +21613=>21261, +21614=>21262, +21633=>21263, +21635=>21264, +21637=>21265, +21641=>21266, +21649=>21267, +21663=>21268, +21706=>21269, +21728=>21270, +21750=>21271, +21758=>21272, +21772=>21273, +21773=>21274, +21810=>21275, +21819=>21276, +21821=>21277, +21833=>21278, +21837=>21279, +21848=>21280, +21850=>21281, +21851=>21282, +21887=>21283, +21907=>21284, +21911=>21285, +21923=>21286, +21953=>21287, +21963=>21288, +21975=>21289, +21976=>21290, +21982=>21291, +22015=>21292, +22026=>21294, +22041=>21295, +22067=>21296, +22076=>21297, +22081=>21298, +22083=>21299, +22084=>21300, +22086=>21301, +22113=>21302, +22114=>21303, +22115=>21304, +22133=>21305, +22148=>21306, +22155=>21307, +22183=>21308, +22187=>21309, +22206=>21310, +22219=>21311, +22224=>21312, +22236=>21313, +22245=>21314, +22246=>21315, +22247=>21316, +22273=>21317, +22274=>21318, +22289=>21319, +22304=>21320, +22306=>21321, +22308=>21322, +22309=>21323, +22314=>21324, +22335=>21325, +22354=>21326, +22370=>21327, +22375=>21328, +22382=>21329, +22385=>21330, +22393=>21331, +22398=>21332, +22401=>21333, +22420=>21334, +22425=>21335, +22431=>21336, +22433=>21337, +22421=>21338, +22439=>21339, +22441=>21340, +22461=>21341, +22493=>21342, +22505=>21343, +22526=>21344, +22531=>21345, +22536=>21346, +22497=>21347, +22540=>21348, +22555=>21349, +22559=>21350, +22573=>21351, +22591=>21352, +22608=>21353, +22613=>21354, +22632=>21355, +22648=>21356, +22663=>21357, +22664=>21358, +22668=>21359, +22678=>21360, +22688=>21361, +22689=>21362, +22690=>21363, +22694=>21364, +22724=>21365, +22722=>21366, +22728=>21367, +22742=>21368, +22749=>21369, +22753=>21370, +22802=>21372, +22803=>21373, +22813=>21374, +22817=>21375, +22824=>21376, +22832=>21377, +22835=>21378, +22837=>21379, +22838=>21380, +22847=>21381, +22851=>21382, +22866=>21383, +22878=>21384, +22891=>21385, +22895=>21386, +22898=>21387, +22907=>21388, +22924=>21389, +22926=>21390, +22933=>21391, +22951=>21392, +22957=>21393, +22960=>21394, +22967=>21395, +22977=>21396, +22980=>21397, +23023=>21398, +23026=>21399, +23028=>21400, +23031=>21401, +23040=>21402, +23054=>21403, +23058=>21404, +23070=>21405, +23076=>21406, +23080=>21407, +23082=>21408, +23088=>21409, +23108=>21410, +23109=>21411, +23112=>21412, +23116=>21413, +23120=>21414, +23134=>21415, +23163=>21416, +23184=>21417, +23187=>21418, +23190=>21419, +23193=>21420, +23227=>21421, +23238=>21422, +23240=>21423, +23247=>21424, +23293=>21425, +23297=>21426, +23371=>21427, +23390=>21428, +23406=>21429, +23430=>21430, +23438=>21431, +23440=>21432, +23441=>21433, +23444=>21434, +23464=>21435, +23465=>21436, +23469=>21437, +23471=>21438, +23473=>21439, +23474=>21440, +23482=>21441, +23484=>21442, +23489=>21443, +23501=>21444, +23503=>21445, +23513=>21446, +23514=>21447, +23535=>21448, +23540=>21449, +23564=>21450, +23575=>21451, +23590=>21452, +23598=>21453, +23602=>21454, +23605=>21455, +23642=>21456, +23668=>21457, +23669=>21458, +23675=>21459, +23677=>21460, +23687=>21461, +23698=>21462, +23709=>21463, +23730=>21464, +23732=>21465, +23767=>21466, +23790=>21467, +23793=>21468, +23794=>21469, +23826=>21470, +23843=>21471, +23871=>21472, +23880=>21473, +23893=>21474, +23889=>21475, +23903=>21476, +23904=>21477, +23906=>21478, +23908=>21479, +23929=>21480, +23930=>21481, +23935=>21482, +23946=>21483, +23955=>21484, +23957=>21485, +23963=>21486, +23967=>21487, +23979=>21488, +24003=>21489, +24014=>21490, +24025=>21491, +24071=>21492, +24077=>21493, +24096=>21494, +24139=>21495, +24144=>21496, +24145=>21497, +24156=>21498, +24176=>21499, +24206=>21500, +24226=>21501, +24228=>21502, +24241=>21503, +24268=>21504, +24270=>21505, +24284=>21506, +24286=>21507, +24293=>21508, +24299=>21509, +24326=>21510, +24345=>21511, +24356=>21512, +24363=>21513, +24364=>21514, +24366=>21515, +24368=>21516, +24383=>21517, +24388=>21518, +24411=>21519, +24416=>21520, +24431=>21521, +24436=>21522, +24437=>21523, +24440=>21524, +24442=>21525, +24461=>21526, +24470=>21527, +24477=>21528, +24491=>21529, +24496=>21530, +24497=>21531, +24520=>21532, +24528=>21533, +24529=>21534, +24552=>21535, +24556=>21536, +24562=>21537, +24566=>21538, +24570=>21539, +24586=>21540, +24595=>21541, +24607=>21542, +24621=>21543, +24640=>21544, +24648=>21545, +24657=>21546, +24662=>21547, +24663=>21548, +24689=>21549, +24702=>21550, +24706=>21551, +24710=>21552, +24712=>21553, +24718=>21554, +24721=>21555, +24723=>21556, +24728=>21557, +24738=>21559, +24741=>21560, +24759=>21561, +24770=>21562, +24777=>21563, +24778=>21564, +24782=>21565, +24783=>21566, +24802=>21567, +24805=>21568, +24828=>21569, +24834=>21570, +24839=>21571, +24844=>21572, +24855=>21573, +24866=>21574, +24881=>21575, +24885=>21576, +24889=>21577, +24901=>21578, +24905=>21579, +24940=>21580, +24946=>21581, +24952=>21582, +24960=>21583, +24961=>21584, +24963=>21585, +24964=>21586, +24971=>21587, +24988=>21588, +24992=>21589, +25002=>21590, +25024=>21591, +25025=>21592, +25038=>21593, +25039=>21594, +25054=>21595, +25057=>21596, +25063=>21597, +25065=>21598, +25068=>21599, +25069=>21600, +25071=>21601, +25089=>21602, +25091=>21603, +25116=>21604, +25120=>21605, +25127=>21606, +25131=>21607, +25154=>21608, +25156=>21609, +25168=>21610, +25172=>21611, +25180=>21612, +25213=>21613, +25229=>21614, +25230=>21615, +25231=>21616, +25267=>21617, +25270=>21618, +25271=>21619, +25274=>21620, +25278=>21621, +25279=>21622, +25294=>21623, +25322=>21624, +25330=>21625, +25348=>21626, +25355=>21627, +25363=>21628, +25385=>21629, +25389=>21630, +25418=>21631, +25426=>21632, +25428=>21633, +25432=>21634, +25435=>21635, +25446=>21636, +25453=>21637, +25464=>21638, +25493=>21639, +25498=>21640, +25508=>21641, +25510=>21642, +25517=>21643, +25537=>21644, +25541=>21645, +25544=>21646, +25550=>21647, +25555=>21648, +25587=>21649, +25610=>21650, +25648=>21651, +25675=>21652, +25679=>21653, +25683=>21654, +25692=>21655, +25697=>21656, +25699=>21657, +25733=>21658, +25743=>21659, +25755=>21660, +25761=>21661, +25763=>21662, +25766=>21663, +25768=>21664, +25789=>21665, +25801=>21666, +25809=>21667, +25833=>21668, +25834=>21669, +25845=>21670, +25857=>21671, +25864=>21672, +25865=>21673, +25866=>21674, +25875=>21675, +25894=>21676, +25905=>21677, +25914=>21678, +25916=>21679, +25917=>21680, +25923=>21681, +25936=>21682, +25938=>21683, +25951=>21684, +25981=>21685, +26008=>21686, +26016=>21687, +26019=>21688, +26022=>21689, +26030=>21690, +26035=>21691, +26070=>21692, +26072=>21693, +26100=>21695, +26101=>21696, +26110=>21697, +26111=>21698, +26125=>21699, +26129=>21700, +26130=>21701, +26134=>21702, +26141=>21703, +26147=>21704, +26150=>21705, +26153=>21706, +26169=>21707, +26167=>21708, +26176=>21709, +26182=>21710, +26186=>21711, +26200=>21712, +26208=>21713, +26229=>21714, +26239=>21715, +26233=>21716, +26236=>21717, +26266=>21718, +26267=>21719, +26268=>21720, +26271=>21721, +26306=>21723, +26307=>21724, +26316=>21725, +26318=>21726, +26324=>21727, +26335=>21728, +26347=>21729, +26350=>21730, +26375=>21731, +26396=>21732, +26400=>21733, +26402=>21734, +26430=>21735, +26437=>21736, +26476=>21737, +26500=>21738, +26510=>21739, +26518=>21740, +26521=>21741, +26556=>21742, +26557=>21743, +26562=>21744, +26565=>21745, +26569=>21746, +26588=>21747, +26593=>21748, +26598=>21749, +26610=>21750, +26614=>21751, +26644=>21752, +26649=>21753, +26663=>21754, +26671=>21755, +26687=>21756, +26698=>21757, +26712=>21758, +26735=>21759, +26736=>21760, +26737=>21761, +26745=>21762, +26747=>21763, +26760=>21764, +26785=>21765, +26793=>21766, +26798=>21767, +26833=>21768, +26835=>21769, +26844=>21770, +26845=>21771, +26858=>21772, +26870=>21773, +26877=>21774, +26886=>21775, +26889=>21776, +26896=>21777, +26902=>21778, +26929=>21779, +26949=>21780, +26958=>21781, +26982=>21782, +26992=>21783, +26993=>21784, +27003=>21785, +27021=>21786, +27041=>21787, +27064=>21788, +27077=>21789, +27080=>21790, +27136=>21792, +27139=>21793, +27168=>21794, +27172=>21795, +27191=>21796, +27242=>21798, +27265=>21799, +27270=>21800, +27271=>21801, +27291=>21802, +27312=>21803, +27313=>21804, +27316=>21805, +27326=>21806, +27327=>21807, +27340=>21808, +27349=>21809, +27350=>21810, +27376=>21811, +27388=>21812, +27394=>21813, +27398=>21814, +27399=>21815, +27401=>21816, +27432=>21817, +27435=>21818, +27446=>21819, +27469=>21820, +27474=>21821, +27485=>21822, +27499=>21823, +27502=>21824, +27504=>21825, +27525=>21826, +27543=>21827, +27551=>21828, +27552=>21829, +27554=>21830, +27555=>21831, +27560=>21832, +27564=>21833, +27576=>21834, +27577=>21835, +27587=>21836, +27588=>21837, +27619=>21838, +27666=>21839, +27673=>21840, +27679=>21841, +27686=>21842, +27687=>21843, +27688=>21844, +27694=>21845, +27707=>21846, +27723=>21847, +27727=>21848, +27755=>21849, +27768=>21850, +27783=>21851, +27807=>21852, +27824=>21853, +27826=>21854, +27853=>21855, +27855=>21856, +27857=>21857, +27879=>21858, +27890=>21859, +27892=>21860, +27911=>21861, +27919=>21862, +27923=>21863, +27930=>21864, +27944=>21865, +27999=>21866, +28007=>21867, +28050=>21868, +28055=>21869, +28087=>21870, +28093=>21871, +28128=>21872, +28130=>21873, +28133=>21874, +28143=>21875, +28148=>21876, +28160=>21877, +28164=>21878, +28219=>21879, +28242=>21880, +28253=>21881, +28258=>21882, +28264=>21883, +28301=>21884, +28313=>21885, +28320=>21886, +28333=>21887, +28334=>21888, +28339=>21889, +28347=>21890, +28352=>21891, +28360=>21892, +28365=>21893, +28367=>21894, +28397=>21895, +28398=>21896, +28420=>21897, +28424=>21898, +28429=>21899, +28438=>21900, +28443=>21901, +28475=>21902, +28461=>21903, +28495=>21904, +28499=>21905, +28509=>21906, +28524=>21907, +28547=>21908, +28563=>21909, +28582=>21910, +28592=>21911, +28613=>21912, +28648=>21913, +28669=>21914, +28695=>21915, +28719=>21916, +28724=>21917, +28727=>21918, +28740=>21919, +28744=>21920, +28757=>21921, +28820=>21922, +28822=>21923, +28827=>21924, +28852=>21925, +28922=>21926, +28933=>21927, +28939=>21928, +28973=>21929, +28984=>21930, +28993=>21931, +29003=>21932, +29015=>21934, +29018=>21935, +29068=>21936, +29082=>21937, +29104=>21938, +29119=>21939, +29120=>21940, +29132=>21941, +29146=>21942, +29176=>21943, +29192=>21944, +29193=>21945, +29203=>21946, +29210=>21947, +29220=>21948, +29231=>21949, +29253=>21950, +29262=>21951, +29278=>21952, +29291=>21953, +29297=>21954, +29307=>21955, +29308=>21956, +29321=>21957, +29331=>21958, +29352=>21959, +29397=>21960, +29398=>21961, +29400=>21962, +29407=>21963, +29438=>21964, +29453=>21965, +29459=>21966, +29490=>21967, +29493=>21968, +29526=>21969, +29533=>21970, +29534=>21971, +29535=>21972, +29536=>21973, +29545=>21974, +29561=>21975, +29568=>21976, +29582=>21977, +29584=>21978, +29587=>21979, +29591=>21980, +29610=>21981, +29613=>21982, +29638=>21983, +29644=>21984, +29651=>21985, +29661=>21986, +29670=>21987, +29687=>21988, +29691=>21989, +29695=>21990, +29696=>21991, +29713=>21992, +29741=>21993, +29799=>21994, +29800=>21995, +29806=>21996, +29839=>21997, +29841=>21998, +29850=>21999, +29870=>22000, +29873=>22001, +29874=>22002, +29900=>22003, +29904=>22004, +29907=>22005, +29915=>22007, +29928=>22008, +29930=>22009, +29948=>22011, +29958=>22012, +29970=>22013, +29991=>22014, +29993=>22015, +30006=>22016, +30009=>22017, +30019=>22018, +30023=>22019, +30039=>22020, +30047=>22021, +30049=>22022, +30075=>22023, +30076=>22024, +30085=>22025, +30101=>22026, +30108=>22027, +30138=>22028, +30226=>22029, +30243=>22030, +30249=>22031, +30265=>22032, +30266=>22033, +30272=>22034, +30276=>22035, +30297=>22036, +30341=>22037, +30348=>22038, +30349=>22039, +30367=>22040, +30370=>22041, +30371=>22042, +30401=>22043, +30411=>22044, +30432=>22046, +30454=>22047, +30470=>22048, +30482=>22049, +30484=>22050, +30485=>22051, +30492=>22052, +30510=>22053, +30525=>22054, +30530=>22055, +30546=>22056, +30550=>22057, +30551=>22058, +30576=>22059, +30579=>22060, +30580=>22061, +30638=>22064, +30641=>22065, +30645=>22066, +30659=>22067, +30674=>22068, +30677=>22069, +30712=>22070, +30734=>22071, +30737=>22072, +30749=>22073, +30755=>22074, +30788=>22075, +30792=>22076, +30796=>22077, +30802=>22078, +30814=>22079, +30816=>22080, +30817=>22081, +30819=>22082, +30863=>22083, +30888=>22084, +30892=>22085, +30898=>22086, +30909=>22087, +30911=>22088, +30919=>22089, +30930=>22090, +30934=>22091, +30939=>22092, +30943=>22093, +30954=>22094, +30963=>22095, +30966=>22096, +30975=>22097, +30982=>22098, +31002=>22099, +31006=>22100, +31008=>22101, +31017=>22102, +31021=>22103, +31029=>22104, +31044=>22105, +31051=>22106, +31055=>22107, +31057=>22108, +31081=>22109, +31099=>22110, +31102=>22111, +31116=>22112, +31121=>22113, +31123=>22114, +31132=>22115, +31144=>22116, +31151=>22117, +31183=>22118, +31197=>22119, +31200=>22120, +31202=>22121, +31205=>22122, +31217=>22123, +31224=>22124, +31228=>22125, +31239=>22126, +31265=>22127, +31271=>22128, +31275=>22129, +31279=>22130, +31284=>22131, +31285=>22132, +31304=>22133, +31317=>22134, +31333=>22135, +31358=>22136, +31371=>22137, +31377=>22138, +31390=>22139, +31433=>22140, +31451=>22141, +31465=>22142, +31468=>22143, +31473=>22144, +31483=>22145, +31519=>22146, +31523=>22147, +31529=>22148, +31536=>22149, +31540=>22150, +31551=>22151, +31552=>22152, +31594=>22153, +31620=>22154, +31625=>22155, +31630=>22156, +31638=>22157, +31653=>22158, +31666=>22159, +31670=>22160, +31674=>22161, +31675=>22162, +31677=>22163, +31682=>22164, +31688=>22165, +31707=>22166, +31732=>22167, +31733=>22168, +31737=>22169, +31738=>22170, +31746=>22171, +31748=>22172, +31750=>22173, +31756=>22174, +31769=>22175, +31771=>22176, +31781=>22177, +31788=>22178, +31796=>22179, +31801=>22180, +31802=>22181, +31814=>22182, +31829=>22183, +31834=>22184, +31843=>22185, +31868=>22187, +31878=>22188, +31920=>22189, +31931=>22190, +31951=>22191, +31956=>22192, +31977=>22193, +32015=>22194, +32017=>22195, +32022=>22196, +32038=>22197, +32042=>22198, +32045=>22199, +32081=>22200, +32087=>22201, +32101=>22202, +32103=>22203, +32120=>22204, +32123=>22205, +32129=>22206, +32150=>22207, +32195=>22208, +32196=>22209, +32197=>22210, +32198=>22211, +32205=>22212, +32206=>22213, +32256=>22214, +32226=>22215, +32234=>22216, +32237=>22217, +32250=>22218, +32284=>22219, +32301=>22220, +32307=>22221, +32319=>22222, +32334=>22223, +32336=>22224, +32344=>22225, +32351=>22226, +32357=>22227, +32405=>22228, +32413=>22229, +32414=>22230, +32575=>22231, +32604=>22232, +32614=>22233, +32653=>22235, +32655=>22236, +32678=>22237, +32682=>22238, +32692=>22239, +32700=>22240, +32704=>22241, +32712=>22242, +32744=>22243, +32783=>22244, +32787=>22245, +32797=>22246, +32799=>22247, +32800=>22248, +32814=>22249, +32820=>22250, +32830=>22251, +32832=>22252, +32836=>22253, +32868=>22254, +32877=>22255, +32897=>22256, +32953=>22257, +32968=>22258, +32973=>22259, +32978=>22260, +33006=>22261, +33010=>22262, +33014=>22263, +33017=>22264, +33035=>22265, +33052=>22266, +33056=>22267, +33084=>22268, +33093=>22269, +33095=>22270, +33106=>22271, +33121=>22272, +33143=>22273, +33158=>22274, +33166=>22275, +33174=>22276, +33186=>22277, +33198=>22278, +33221=>22279, +33230=>22280, +33259=>22281, +33264=>22282, +33265=>22283, +33266=>22284, +33269=>22285, +33272=>22286, +33295=>22288, +33309=>22289, +33320=>22290, +33347=>22291, +33358=>22292, +33361=>22293, +33366=>22294, +33383=>22295, +33403=>22296, +33408=>22297, +33409=>22298, +33415=>22299, +33428=>22300, +33430=>22301, +33432=>22302, +33434=>22303, +33435=>22304, +33440=>22305, +33498=>22306, +33504=>22307, +33508=>22308, +33517=>22309, +33546=>22310, +33547=>22311, +33566=>22312, +33567=>22313, +33569=>22314, +33580=>22315, +33582=>22316, +33587=>22317, +33591=>22318, +33597=>22319, +33602=>22320, +33613=>22321, +33614=>22322, +33648=>22323, +33664=>22324, +33666=>22325, +33668=>22326, +33689=>22327, +33692=>22328, +33702=>22329, +33708=>22330, +33726=>22331, +33619=>22332, +33768=>22333, +33817=>22334, +33709=>22335, +33839=>22336, +33861=>22337, +33863=>22338, +33869=>22339, +33878=>22340, +33888=>22342, +33892=>22343, +33895=>22344, +33898=>22345, +33908=>22346, +33917=>22347, +33938=>22348, +33941=>22349, +33961=>22350, +33962=>22351, +33991=>22352, +33992=>22353, +33996=>22354, +34034=>22355, +34039=>22356, +34050=>22357, +34051=>22358, +34055=>22359, +34062=>22360, +34064=>22361, +34076=>22362, +34082=>22363, +34087=>22364, +34090=>22365, +34099=>22366, +34102=>22367, +34111=>22368, +34128=>22369, +34130=>22370, +34140=>22371, +34143=>22373, +34144=>22374, +34169=>22375, +34185=>22376, +34187=>22377, +34208=>22378, +34213=>22379, +34215=>22380, +34228=>22381, +34230=>22382, +34232=>22383, +34237=>22384, +34238=>22385, +34239=>22386, +34242=>22387, +34266=>22388, +34272=>22389, +34280=>22390, +34291=>22391, +34300=>22392, +34317=>22393, +34318=>22394, +34329=>22395, +34331=>22396, +34358=>22397, +34362=>22398, +34365=>22399, +34392=>22400, +34393=>22401, +34397=>22402, +34400=>22403, +34401=>22404, +34404=>22405, +34409=>22406, +34422=>22407, +34454=>22408, +34458=>22409, +34465=>22410, +34470=>22411, +34477=>22412, +34484=>22413, +34485=>22414, +34487=>22415, +34489=>22416, +34495=>22417, +34501=>22418, +34514=>22419, +34522=>22420, +34524=>22421, +34528=>22422, +34533=>22423, +34535=>22424, +34440=>22425, +34564=>22426, +34575=>22427, +34607=>22428, +34610=>22429, +34620=>22430, +34621=>22431, +34629=>22432, +34637=>22433, +34657=>22434, +34671=>22435, +34691=>22436, +34692=>22437, +34693=>22438, +34694=>22439, +34704=>22440, +34709=>22441, +34737=>22443, +34760=>22444, +34762=>22445, +34773=>22446, +34777=>22447, +34780=>22448, +34786=>22449, +34788=>22450, +34801=>22451, +34803=>22452, +34808=>22453, +34810=>22454, +34815=>22455, +34825=>22456, +34841=>22457, +34834=>22458, +34842=>22459, +34846=>22460, +34864=>22461, +34869=>22462, +34881=>22463, +34883=>22464, +34888=>22465, +34889=>22466, +34897=>22468, +34908=>22469, +34912=>22470, +34929=>22471, +34937=>22472, +34939=>22473, +34944=>22474, +34975=>22475, +34984=>22476, +35002=>22477, +35019=>22478, +35020=>22479, +35038=>22480, +35047=>22481, +35063=>22482, +35085=>22483, +35093=>22484, +35094=>22485, +35104=>22486, +35112=>22487, +35121=>22488, +35130=>22489, +35142=>22490, +35151=>22491, +35154=>22492, +35159=>22493, +35163=>22494, +35169=>22495, +35171=>22496, +35182=>22497, +35187=>22498, +35189=>22499, +35194=>22500, +35197=>22501, +35213=>22502, +35221=>22503, +35227=>22504, +35228=>22505, +35232=>22506, +35252=>22507, +35254=>22508, +35287=>22509, +35305=>22510, +35309=>22511, +35321=>22512, +35332=>22513, +35333=>22514, +35358=>22515, +35360=>22516, +35364=>22517, +35366=>22518, +35371=>22519, +35372=>22520, +35375=>22521, +35389=>22522, +35392=>22523, +35395=>22524, +35411=>22525, +35414=>22526, +35420=>22527, +35429=>22528, +35446=>22529, +35447=>22530, +35450=>22531, +35451=>22532, +35456=>22533, +35459=>22534, +35467=>22535, +35471=>22536, +35474=>22537, +35479=>22538, +35481=>22539, +35487=>22540, +35497=>22541, +35503=>22542, +35507=>22543, +35515=>22544, +35523=>22545, +35526=>22546, +35528=>22547, +35530=>22548, +35539=>22549, +35540=>22550, +35541=>22551, +35568=>22552, +35583=>22553, +35595=>22554, +35614=>22555, +35632=>22556, +35644=>22557, +35650=>22558, +35656=>22559, +35661=>22560, +35683=>22561, +35705=>22562, +35716=>22563, +35725=>22564, +35727=>22565, +35896=>22566, +35902=>22567, +35921=>22568, +35928=>22569, +35931=>22570, +35933=>22571, +35929=>22572, +35939=>22573, +35940=>22574, +35942=>22575, +35957=>22576, +35958=>22577, +35966=>22578, +35974=>22579, +35975=>22580, +35979=>22581, +35984=>22582, +35996=>22584, +36025=>22585, +36038=>22586, +36043=>22587, +36047=>22588, +36061=>22589, +36072=>22590, +36079=>22591, +36082=>22592, +36095=>22593, +36197=>22594, +36223=>22595, +36226=>22596, +36232=>22597, +36240=>22598, +36254=>22599, +36256=>22600, +36268=>22601, +36277=>22602, +36279=>22603, +36281=>22604, +36283=>22605, +36288=>22606, +36293=>22607, +36295=>22608, +36298=>22609, +36308=>22610, +36325=>22611, +36336=>22612, +36284=>22613, +36356=>22614, +36357=>22615, +36369=>22616, +36403=>22617, +36407=>22618, +36408=>22619, +36430=>22620, +36443=>22621, +36445=>22622, +36446=>22623, +36473=>22624, +36482=>22625, +36483=>22626, +36507=>22627, +36509=>22628, +36514=>22629, +36538=>22630, +36545=>22631, +36547=>22632, +36548=>22633, +36551=>22634, +36572=>22635, +36590=>22636, +36593=>22637, +36599=>22638, +36589=>22639, +36610=>22640, +36623=>22641, +36624=>22642, +36630=>22643, +36640=>22644, +36641=>22645, +36643=>22646, +36648=>22647, +36654=>22648, +36660=>22649, +36663=>22650, +36673=>22651, +36687=>22652, +36690=>22653, +36691=>22654, +36701=>22655, +36702=>22656, +36709=>22657, +36765=>22658, +36792=>22659, +36798=>22660, +36800=>22661, +36811=>22662, +36816=>22663, +36818=>22664, +36835=>22665, +36862=>22666, +36888=>22667, +36904=>22668, +36905=>22669, +36906=>22670, +36915=>22671, +36916=>22672, +36927=>22673, +36962=>22674, +36966=>22675, +36972=>22676, +37006=>22677, +37029=>22678, +37068=>22679, +37077=>22680, +37080=>22681, +37081=>22682, +37093=>22683, +37074=>22684, +37128=>22685, +37133=>22686, +37136=>22687, +37146=>22688, +37152=>22689, +37161=>22690, +37166=>22691, +37174=>22692, +37180=>22693, +37187=>22694, +37199=>22695, +37203=>22696, +37229=>22697, +37243=>22698, +37249=>22699, +37254=>22700, +37267=>22701, +37268=>22702, +37272=>22703, +37281=>22704, +37286=>22705, +37311=>22706, +37331=>22707, +37332=>22708, +37337=>22709, +37353=>22710, +37354=>22711, +37359=>22712, +37369=>22713, +37373=>22714, +37380=>22715, +37381=>22716, +37388=>22717, +37394=>22718, +37395=>22719, +37400=>22720, +37404=>22721, +37405=>22722, +37412=>22723, +37413=>22724, +37414=>22725, +37422=>22726, +37423=>22727, +37424=>22728, +37429=>22729, +37430=>22730, +37438=>22731, +37446=>22732, +37453=>22733, +37464=>22734, +37468=>22735, +37469=>22736, +37481=>22737, +37486=>22738, +37487=>22739, +37488=>22740, +37493=>22741, +37497=>22742, +37499=>22743, +37514=>22744, +37522=>22745, +37536=>22746, +37540=>22747, +37541=>22748, +37544=>22749, +37558=>22750, +37560=>22751, +37562=>22752, +37565=>22753, +37575=>22754, +37581=>22755, +37592=>22756, +37596=>22757, +37597=>22758, +37601=>22759, +37603=>22760, +37608=>22761, +37612=>22762, +37614=>22763, +37616=>22764, +37632=>22765, +37640=>22766, +37660=>22767, +37668=>22768, +37674=>22769, +37684=>22770, +37687=>22771, +37712=>22772, +37717=>22773, +37726=>22774, +37735=>22775, +37737=>22776, +37743=>22777, +37748=>22778, +37750=>22779, +37754=>22780, +37757=>22781, +37760=>22782, +37761=>22783, +37773=>22784, +37778=>22785, +37781=>22786, +37784=>22787, +37798=>22789, +37800=>22790, +37803=>22791, +37812=>22792, +37813=>22793, +37814=>22794, +37828=>22795, +37829=>22796, +37833=>22797, +37835=>22798, +37837=>22799, +37843=>22800, +37849=>22801, +37879=>22802, +37889=>22803, +37896=>22804, +37909=>22805, +37919=>22806, +37935=>22807, +37949=>22808, +37955=>22809, +37977=>22810, +37980=>22811, +37983=>22812, +37985=>22813, +37992=>22814, +37998=>22815, +38020=>22816, +38019=>22817, +38270=>22818, +38276=>22819, +38301=>22820, +38302=>22821, +38330=>22822, +38361=>22823, +38365=>22824, +38367=>22825, +38430=>22826, +38434=>22827, +38437=>22828, +38438=>22829, +38455=>22830, +38457=>22831, +38458=>22832, +38482=>22833, +38486=>22834, +38487=>22835, +38510=>22836, +38524=>22837, +38526=>22838, +38545=>22839, +38559=>22840, +38566=>22841, +38602=>22842, +38623=>22844, +38650=>22845, +38661=>22846, +38682=>22847, +38685=>22848, +38730=>22850, +38744=>22851, +38775=>22852, +38776=>22853, +38779=>22854, +38784=>22855, +38793=>22856, +38807=>22857, +38840=>22858, +38844=>22859, +38847=>22860, +38852=>22861, +38853=>22862, +38855=>22863, +38858=>22864, +38862=>22865, +38864=>22866, +38871=>22867, +38877=>22868, +38884=>22869, +38903=>22870, +38904=>22871, +38906=>22872, +38937=>22873, +38940=>22874, +38944=>22875, +38959=>22876, +38965=>22877, +38980=>22878, +38986=>22879, +38993=>22880, +39018=>22881, +39086=>22882, +39116=>22883, +39142=>22884, +39158=>22885, +39175=>22886, +39199=>22887, +39202=>22888, +39206=>22889, +39211=>22890, +39220=>22891, +39225=>22892, +39239=>22893, +39257=>22894, +39259=>22895, +39323=>22896, +39325=>22897, +39327=>22898, +39344=>22899, +39346=>22900, +39349=>22901, +39379=>22902, +39386=>22903, +39388=>22904, +39399=>22905, +39402=>22906, +39403=>22907, +39404=>22908, +39412=>22909, +39413=>22910, +39421=>22911, +39422=>22912, +39428=>22913, +39435=>22914, +39454=>22915, +39458=>22916, +39475=>22917, +39477=>22918, +39495=>22919, +39499=>22921, +39508=>22922, +39517=>22923, +39594=>22924, +39596=>22925, +39598=>22926, +39602=>22927, +39604=>22928, +39611=>22929, +39615=>22930, +39624=>22931, +39639=>22932, +39643=>22933, +39652=>22934, +39655=>22935, +39660=>22936, +39666=>22937, +39667=>22938, +39669=>22939, +39674=>22940, +39677=>22941, +39679=>22942, +39680=>22943, +39684=>22944, +39685=>22945, +39707=>22946, +39718=>22947, +39735=>22949, +39737=>22950, +39738=>22951, +39756=>22952, +39766=>22953, +39767=>22954, +39771=>22955, +39777=>22956, +39786=>22957, +39789=>22958, +39790=>22959, +39800=>22960, +39807=>22961, +39813=>22962, +39815=>22963, +39817=>22964, +39819=>22965, +39821=>22966, +39828=>22967, +39834=>22968, +39849=>22969, +39863=>22970, +39868=>22971, +39888=>22972, +39929=>22973, +39951=>22974, +39953=>22975, +39966=>22976, +39974=>22977, +39976=>22978, +39997=>22979, +40003=>22980, +40014=>22981, +40030=>22982, +40059=>22983, +40183=>22984, +40185=>22985, +40220=>22986, +40239=>22987, +40243=>22988, +40244=>22989, +40250=>22990, +40252=>22991, +40261=>22992, +40275=>22993, +40276=>22994, +40293=>22995, +40323=>22996, +40326=>22997, +40334=>22998, +40338=>22999, +40339=>23000, +40341=>23001, +40343=>23002, +40344=>23003, +40362=>23004, +40366=>23005, +40394=>23007, +40404=>23008, +40405=>23009, +40414=>23010, +40430=>23011, +40432=>23012, +40446=>23013, +40462=>23014, +40464=>23015, +40465=>23016, +40466=>23017, +40470=>23018, +40583=>23019, +40590=>23020, +40591=>23021, +40598=>23022, +40600=>23023, +40622=>23024, +40627=>23025, +40646=>23026, +40648=>23027, +40651=>23028, +40661=>23029, +40684=>23030, +40685=>23031, +40689=>23032, +40693=>23033, +40696=>23034, +40721=>23035, +40726=>23036, +40730=>23037, +40735=>23038, +40753=>23039, +40754=>23040, +40764=>23041, +40767=>23042, +40771=>23043, +40772=>23044, +40775=>23045, +40790=>23046, +40798=>23047, +40814=>23048, +40819=>23049, +40826=>23050, +40829=>23051, +40847=>23052, +40849=>23053, +40850=>23054, +40854=>23055, +40865=>23056, +40867=>23057, +); +?> diff --git a/include/tcpdf/fonts/uni2cid_ak12.php b/include/tcpdf/fonts/uni2cid_ak12.php new file mode 100644 index 00000000..e938203c --- /dev/null +++ b/include/tcpdf/fonts/uni2cid_ak12.php @@ -0,0 +1,17553 @@ +1, +33=>2, +34=>3, +35=>4, +36=>5, +37=>6, +38=>7, +39=>8, +40=>9, +41=>10, +42=>11, +43=>12, +44=>13, +45=>14, +46=>15, +47=>16, +48=>17, +49=>18, +50=>19, +51=>20, +52=>21, +53=>22, +54=>23, +55=>24, +56=>25, +57=>26, +58=>27, +59=>28, +60=>29, +61=>30, +62=>31, +63=>32, +64=>33, +65=>34, +66=>35, +67=>36, +68=>37, +69=>38, +70=>39, +71=>40, +72=>41, +73=>42, +74=>43, +75=>44, +76=>45, +77=>46, +78=>47, +79=>48, +80=>49, +81=>50, +82=>51, +83=>52, +84=>53, +85=>54, +86=>55, +87=>56, +88=>57, +89=>58, +90=>59, +91=>60, +92=>61, +93=>62, +94=>63, +95=>64, +96=>65, +97=>66, +98=>67, +99=>68, +100=>69, +101=>70, +102=>71, +103=>72, +104=>73, +105=>74, +106=>75, +107=>76, +108=>77, +109=>78, +110=>79, +111=>80, +112=>81, +113=>82, +114=>83, +115=>84, +116=>85, +117=>86, +118=>87, +119=>88, +120=>89, +121=>90, +122=>91, +123=>92, +124=>93, +125=>94, +126=>95, +8361=>96, +8208=>97, +169=>98, +12644=>101, +12288=>101, +12289=>102, +12290=>103, +183=>104, +12539=>104, +8229=>105, +8943=>106, +8230=>106, +168=>107, +12291=>108, +8211=>109, +8212=>110, +8214=>111, +65340=>112, +65374=>113, +8216=>114, +8217=>115, +8220=>116, +8221=>117, +12308=>118, +12309=>119, +12296=>120, +12297=>121, +12298=>122, +12299=>123, +12300=>124, +12301=>125, +12302=>126, +12303=>127, +12304=>128, +12305=>129, +177=>130, +215=>131, +247=>132, +8800=>133, +8804=>134, +8805=>135, +8734=>136, +8756=>137, +176=>138, +8242=>139, +8243=>140, +8451=>141, +8491=>142, +65504=>143, +65505=>144, +65509=>145, +9794=>146, +9792=>147, +8736=>148, +8869=>149, +8978=>150, +8706=>151, +8711=>152, +8801=>153, +8786=>154, +167=>155, +8251=>156, +9734=>157, +9733=>158, +9675=>159, +9679=>160, +9678=>161, +9671=>162, +9670=>163, +9633=>164, +9632=>165, +9651=>166, +9650=>167, +9661=>168, +9660=>169, +8594=>170, +8592=>171, +8593=>172, +8595=>173, +8596=>174, +12307=>175, +171=>176, +187=>177, +8730=>178, +8765=>179, +8733=>180, +8757=>181, +8747=>182, +8748=>183, +8712=>184, +8715=>185, +8838=>186, +8839=>187, +8834=>188, +8835=>189, +8746=>190, +8745=>191, +8743=>192, +8744=>193, +65506=>194, +8658=>195, +8660=>196, +8704=>197, +8707=>198, +180=>199, +732=>200, +711=>201, +728=>202, +733=>203, +730=>204, +729=>205, +184=>206, +731=>207, +161=>208, +191=>209, +8758=>210, +8750=>211, +8721=>212, +8719=>213, +164=>214, +8457=>215, +8240=>216, +9665=>217, +9664=>218, +9655=>219, +9654=>220, +9828=>221, +9824=>222, +9825=>223, +9829=>224, +9831=>225, +9827=>226, +9673=>227, +9672=>228, +9635=>229, +9680=>230, +9681=>231, +9618=>232, +9636=>233, +9637=>234, +9640=>235, +9639=>236, +9638=>237, +9641=>238, +9832=>239, +9743=>240, +9742=>241, +9756=>242, +9758=>243, +182=>244, +8224=>245, +8225=>246, +8597=>247, +8599=>248, +8601=>249, +8598=>250, +8600=>251, +9837=>252, +9833=>253, +9834=>254, +9836=>255, +12927=>256, +12828=>257, +8470=>258, +13255=>259, +8482=>260, +13250=>261, +13272=>262, +8481=>263, +65281=>264, +65282=>265, +65283=>266, +65284=>267, +65285=>268, +65286=>269, +65287=>270, +65288=>271, +65289=>272, +65290=>273, +65291=>274, +65292=>275, +65293=>276, +65294=>277, +65295=>278, +65296=>279, +65297=>280, +65298=>281, +65299=>282, +65300=>283, +65301=>284, +65302=>285, +65303=>286, +65304=>287, +65305=>288, +65306=>289, +65307=>290, +65308=>291, +65309=>292, +65310=>293, +65311=>294, +65312=>295, +65313=>296, +65314=>297, +65315=>298, +65316=>299, +65317=>300, +65318=>301, +65319=>302, +65320=>303, +65321=>304, +65322=>305, +65323=>306, +65324=>307, +65325=>308, +65326=>309, +65327=>310, +65328=>311, +65329=>312, +65330=>313, +65331=>314, +65332=>315, +65333=>316, +65334=>317, +65335=>318, +65336=>319, +65337=>320, +65338=>321, +65339=>322, +65510=>323, +65341=>324, +65342=>325, +65343=>326, +65344=>327, +65345=>328, +65346=>329, +65347=>330, +65348=>331, +65349=>332, +65350=>333, +65351=>334, +65352=>335, +65353=>336, +65354=>337, +65355=>338, +65356=>339, +65357=>340, +65358=>341, +65359=>342, +65360=>343, +65361=>344, +65362=>345, +65363=>346, +65364=>347, +65365=>348, +65366=>349, +65367=>350, +65368=>351, +65369=>352, +65370=>353, +65371=>354, +65372=>355, +65373=>356, +65507=>357, +12593=>358, +12594=>359, +12595=>360, +12596=>361, +12597=>362, +12598=>363, +12599=>364, +12600=>365, +12601=>366, +12602=>367, +12603=>368, +12604=>369, +12605=>370, +12606=>371, +12607=>372, +12608=>373, +12609=>374, +12610=>375, +12611=>376, +12612=>377, +12613=>378, +12614=>379, +12615=>380, +12616=>381, +12617=>382, +12618=>383, +12619=>384, +12620=>385, +12621=>386, +12622=>387, +12623=>388, +12624=>389, +12625=>390, +12626=>391, +12627=>392, +12628=>393, +12629=>394, +12630=>395, +12631=>396, +12632=>397, +12633=>398, +12634=>399, +12635=>400, +12636=>401, +12637=>402, +12638=>403, +12639=>404, +12640=>405, +12641=>406, +12642=>407, +12643=>408, +12645=>409, +12646=>410, +12647=>411, +12648=>412, +12649=>413, +12650=>414, +12651=>415, +12652=>416, +12653=>417, +12654=>418, +12655=>419, +12656=>420, +12657=>421, +12658=>422, +12659=>423, +12660=>424, +12661=>425, +12662=>426, +12663=>427, +12664=>428, +12665=>429, +12666=>430, +12667=>431, +12668=>432, +12669=>433, +12670=>434, +12671=>435, +12672=>436, +12673=>437, +12674=>438, +12675=>439, +12676=>440, +12677=>441, +12678=>442, +12679=>443, +12680=>444, +12681=>445, +12682=>446, +12683=>447, +12684=>448, +12685=>449, +12686=>450, +8560=>451, +8561=>452, +8562=>453, +8563=>454, +8564=>455, +8565=>456, +8566=>457, +8567=>458, +8568=>459, +8569=>460, +8544=>461, +8545=>462, +8546=>463, +8547=>464, +8548=>465, +8549=>466, +8550=>467, +8551=>468, +8552=>469, +8553=>470, +913=>471, +914=>472, +915=>473, +916=>474, +917=>475, +918=>476, +919=>477, +920=>478, +921=>479, +922=>480, +923=>481, +924=>482, +925=>483, +926=>484, +927=>485, +928=>486, +929=>487, +931=>488, +932=>489, +933=>490, +934=>491, +935=>492, +936=>493, +937=>494, +945=>495, +946=>496, +947=>497, +948=>498, +949=>499, +950=>500, +951=>501, +952=>502, +953=>503, +954=>504, +955=>505, +956=>506, +957=>507, +958=>508, +959=>509, +960=>510, +961=>511, +963=>512, +964=>513, +965=>514, +966=>515, +967=>516, +968=>517, +969=>518, +9472=>519, +9474=>520, +9484=>521, +9488=>522, +9496=>523, +9492=>524, +9500=>525, +9516=>526, +9508=>527, +9524=>528, +9532=>529, +9473=>530, +9475=>531, +9487=>532, +9491=>533, +9499=>534, +9495=>535, +9507=>536, +9523=>537, +9515=>538, +9531=>539, +9547=>540, +9504=>541, +9519=>542, +9512=>543, +9527=>544, +9535=>545, +9501=>546, +9520=>547, +9509=>548, +9528=>549, +9538=>550, +9490=>551, +9489=>552, +9498=>553, +9497=>554, +9494=>555, +9493=>556, +9486=>557, +9485=>558, +9502=>559, +9503=>560, +9505=>561, +9506=>562, +9510=>563, +9511=>564, +9513=>565, +9514=>566, +9517=>567, +9518=>568, +9521=>569, +9522=>570, +9525=>571, +9526=>572, +9529=>573, +9530=>574, +9533=>575, +9534=>576, +9536=>577, +9537=>578, +9539=>579, +9540=>580, +9541=>581, +9542=>582, +9543=>583, +9544=>584, +9545=>585, +9546=>586, +13205=>587, +13206=>588, +13207=>589, +8467=>590, +13208=>591, +13252=>592, +13219=>593, +13220=>594, +13221=>595, +13222=>596, +13209=>597, +13210=>598, +13211=>599, +13212=>600, +13213=>601, +13214=>602, +13215=>603, +13216=>604, +13217=>605, +13218=>606, +13258=>607, +13197=>608, +13198=>609, +13199=>610, +13263=>611, +13192=>612, +13193=>613, +13256=>614, +13223=>615, +13224=>616, +13232=>617, +13233=>618, +13234=>619, +13235=>620, +13236=>621, +13237=>622, +13238=>623, +13239=>624, +13240=>625, +13241=>626, +13184=>627, +13185=>628, +13186=>629, +13187=>630, +13188=>631, +13242=>632, +13243=>633, +13244=>634, +13245=>635, +13246=>636, +13247=>637, +13200=>638, +13201=>639, +13202=>640, +13203=>641, +13204=>642, +8486=>643, +13248=>644, +13249=>645, +13194=>646, +13195=>647, +13196=>648, +13270=>649, +13253=>650, +13229=>651, +13230=>652, +13231=>653, +13275=>654, +13225=>655, +13226=>656, +13227=>657, +13228=>658, +13277=>659, +13264=>660, +13267=>661, +13251=>662, +13257=>663, +13276=>664, +13254=>665, +198=>666, +208=>667, +170=>668, +294=>669, +306=>670, +319=>671, +321=>672, +216=>673, +338=>674, +186=>675, +222=>676, +358=>677, +330=>678, +12896=>679, +12897=>680, +12898=>681, +12899=>682, +12900=>683, +12901=>684, +12902=>685, +12903=>686, +12904=>687, +12905=>688, +12906=>689, +12907=>690, +12908=>691, +12909=>692, +12910=>693, +12911=>694, +12912=>695, +12913=>696, +12914=>697, +12915=>698, +12916=>699, +12917=>700, +12918=>701, +12919=>702, +12920=>703, +12921=>704, +12922=>705, +12923=>706, +9424=>707, +9425=>708, +9426=>709, +9427=>710, +9428=>711, +9429=>712, +9430=>713, +9431=>714, +9432=>715, +9433=>716, +9434=>717, +9435=>718, +9436=>719, +9437=>720, +9438=>721, +9439=>722, +9440=>723, +9441=>724, +9442=>725, +9443=>726, +9444=>727, +9445=>728, +9446=>729, +9447=>730, +9448=>731, +9449=>732, +9312=>733, +9313=>734, +9314=>735, +9315=>736, +9316=>737, +9317=>738, +9318=>739, +9319=>740, +9320=>741, +9321=>742, +9322=>743, +9323=>744, +9324=>745, +9325=>746, +9326=>747, +189=>748, +8531=>749, +8532=>750, +188=>751, +190=>752, +8539=>753, +8540=>754, +8541=>755, +8542=>756, +230=>757, +273=>758, +240=>759, +295=>760, +305=>761, +307=>762, +312=>763, +320=>764, +322=>765, +248=>766, +339=>767, +223=>768, +254=>769, +359=>770, +331=>771, +329=>772, +12800=>773, +12801=>774, +12802=>775, +12803=>776, +12804=>777, +12805=>778, +12806=>779, +12807=>780, +12808=>781, +12809=>782, +12810=>783, +12811=>784, +12812=>785, +12813=>786, +12814=>787, +12815=>788, +12816=>789, +12817=>790, +12818=>791, +12819=>792, +12820=>793, +12821=>794, +12822=>795, +12823=>796, +12824=>797, +12825=>798, +12826=>799, +12827=>800, +9372=>801, +9373=>802, +9374=>803, +9375=>804, +9376=>805, +9377=>806, +9378=>807, +9379=>808, +9380=>809, +9381=>810, +9382=>811, +9383=>812, +9384=>813, +9385=>814, +9386=>815, +9387=>816, +9388=>817, +9389=>818, +9390=>819, +9391=>820, +9392=>821, +9393=>822, +9394=>823, +9395=>824, +9396=>825, +9397=>826, +9332=>827, +9333=>828, +9334=>829, +9335=>830, +9336=>831, +9337=>832, +9338=>833, +9339=>834, +9340=>835, +9341=>836, +9342=>837, +9343=>838, +9344=>839, +9345=>840, +9346=>841, +185=>842, +178=>843, +179=>844, +8308=>845, +8319=>846, +8321=>847, +8322=>848, +8323=>849, +8324=>850, +12353=>851, +12354=>852, +12355=>853, +12356=>854, +12357=>855, +12358=>856, +12359=>857, +12360=>858, +12361=>859, +12362=>860, +12363=>861, +12364=>862, +12365=>863, +12366=>864, +12367=>865, +12368=>866, +12369=>867, +12370=>868, +12371=>869, +12372=>870, +12373=>871, +12374=>872, +12375=>873, +12376=>874, +12377=>875, +12378=>876, +12379=>877, +12380=>878, +12381=>879, +12382=>880, +12383=>881, +12384=>882, +12385=>883, +12386=>884, +12387=>885, +12388=>886, +12389=>887, +12390=>888, +12391=>889, +12392=>890, +12393=>891, +12394=>892, +12395=>893, +12396=>894, +12397=>895, +12398=>896, +12399=>897, +12400=>898, +12401=>899, +12402=>900, +12403=>901, +12404=>902, +12405=>903, +12406=>904, +12407=>905, +12408=>906, +12409=>907, +12410=>908, +12411=>909, +12412=>910, +12413=>911, +12414=>912, +12415=>913, +12416=>914, +12417=>915, +12418=>916, +12419=>917, +12420=>918, +12421=>919, +12422=>920, +12423=>921, +12424=>922, +12425=>923, +12426=>924, +12427=>925, +12428=>926, +12429=>927, +12430=>928, +12431=>929, +12432=>930, +12433=>931, +12434=>932, +12435=>933, +12449=>934, +12450=>935, +12451=>936, +12452=>937, +12453=>938, +12454=>939, +12455=>940, +12456=>941, +12457=>942, +12458=>943, +12459=>944, +12460=>945, +12461=>946, +12462=>947, +12463=>948, +12464=>949, +12465=>950, +12466=>951, +12467=>952, +12468=>953, +12469=>954, +12470=>955, +12471=>956, +12472=>957, +12473=>958, +12474=>959, +12475=>960, +12476=>961, +12477=>962, +12478=>963, +12479=>964, +12480=>965, +12481=>966, +12482=>967, +12483=>968, +12484=>969, +12485=>970, +12486=>971, +12487=>972, +12488=>973, +12489=>974, +12490=>975, +12491=>976, +12492=>977, +12493=>978, +12494=>979, +12495=>980, +12496=>981, +12497=>982, +12498=>983, +12499=>984, +12500=>985, +12501=>986, +12502=>987, +12503=>988, +12504=>989, +12505=>990, +12506=>991, +12507=>992, +12508=>993, +12509=>994, +12510=>995, +12511=>996, +12512=>997, +12513=>998, +12514=>999, +12515=>1000, +12516=>1001, +12517=>1002, +12518=>1003, +12519=>1004, +12520=>1005, +12521=>1006, +12522=>1007, +12523=>1008, +12524=>1009, +12525=>1010, +12526=>1011, +12527=>1012, +12528=>1013, +12529=>1014, +12530=>1015, +12531=>1016, +12532=>1017, +12533=>1018, +12534=>1019, +1040=>1020, +1041=>1021, +1042=>1022, +1043=>1023, +1044=>1024, +1045=>1025, +1025=>1026, +1046=>1027, +1047=>1028, +1048=>1029, +1049=>1030, +1050=>1031, +1051=>1032, +1052=>1033, +1053=>1034, +1054=>1035, +1055=>1036, +1056=>1037, +1057=>1038, +1058=>1039, +1059=>1040, +1060=>1041, +1061=>1042, +1062=>1043, +1063=>1044, +1064=>1045, +1065=>1046, +1066=>1047, +1067=>1048, +1068=>1049, +1069=>1050, +1070=>1051, +1071=>1052, +1072=>1053, +1073=>1054, +1074=>1055, +1075=>1056, +1076=>1057, +1077=>1058, +1105=>1059, +1078=>1060, +1079=>1061, +1080=>1062, +1081=>1063, +1082=>1064, +1083=>1065, +1084=>1066, +1085=>1067, +1086=>1068, +1087=>1069, +1088=>1070, +1089=>1071, +1090=>1072, +1091=>1073, +1092=>1074, +1093=>1075, +1094=>1076, +1095=>1077, +1096=>1078, +1097=>1079, +1098=>1080, +1099=>1081, +1100=>1082, +1101=>1083, +1102=>1084, +1103=>1085, +44032=>1086, +44033=>1087, +44036=>1088, +44039=>1089, +44040=>1090, +44041=>1091, +44042=>1092, +44048=>1093, +44049=>1094, +44050=>1095, +44051=>1096, +44052=>1097, +44053=>1098, +44054=>1099, +44055=>1100, +44057=>1101, +44058=>1102, +44059=>1103, +44060=>1104, +44061=>1105, +44064=>1106, +44068=>1107, +44076=>1108, +44077=>1109, +44079=>1110, +44080=>1111, +44081=>1112, +44088=>1113, +44089=>1114, +44092=>1115, +44096=>1116, +44107=>1117, +44109=>1118, +44116=>1119, +44120=>1120, +44124=>1121, +44144=>1122, +44145=>1123, +44148=>1124, +44151=>1125, +44152=>1126, +44154=>1127, +44160=>1128, +44161=>1129, +44163=>1130, +44164=>1131, +44165=>1132, +44166=>1133, +44169=>1134, +44170=>1135, +44171=>1136, +44172=>1137, +44176=>1138, +44180=>1139, +44188=>1140, +44189=>1141, +44191=>1142, +44192=>1143, +44193=>1144, +44200=>1145, +44201=>1146, +44202=>1147, +44204=>1148, +44207=>1149, +44208=>1150, +44216=>1151, +44217=>1152, +44219=>1153, +44220=>1154, +44221=>1155, +44225=>1156, +44228=>1157, +44232=>1158, +44236=>1159, +44245=>1160, +44247=>1161, +44256=>1162, +44257=>1163, +44260=>1164, +44263=>1165, +44264=>1166, +44266=>1167, +44268=>1168, +44271=>1169, +44272=>1170, +44273=>1171, +44275=>1172, +44277=>1173, +44278=>1174, +44284=>1175, +44285=>1176, +44288=>1177, +44292=>1178, +44294=>1179, +44300=>1180, +44301=>1181, +44303=>1182, +44305=>1183, +44312=>1184, +44316=>1185, +44320=>1186, +44329=>1187, +44332=>1188, +44333=>1189, +44340=>1190, +44341=>1191, +44344=>1192, +44348=>1193, +44356=>1194, +44357=>1195, +44359=>1196, +44361=>1197, +44368=>1198, +44372=>1199, +44376=>1200, +44385=>1201, +44387=>1202, +44396=>1203, +44397=>1204, +44400=>1205, +44403=>1206, +44404=>1207, +44405=>1208, +44406=>1209, +44411=>1210, +44412=>1211, +44413=>1212, +44415=>1213, +44417=>1214, +44418=>1215, +44424=>1216, +44425=>1217, +44428=>1218, +44432=>1219, +44444=>1220, +44445=>1221, +44452=>1222, +44471=>1223, +44480=>1224, +44481=>1225, +44484=>1226, +44488=>1227, +44496=>1228, +44497=>1229, +44499=>1230, +44508=>1231, +44512=>1232, +44516=>1233, +44536=>1234, +44537=>1235, +44540=>1236, +44543=>1237, +44544=>1238, +44545=>1239, +44552=>1240, +44553=>1241, +44555=>1242, +44557=>1243, +44564=>1244, +44592=>1245, +44593=>1246, +44596=>1247, +44599=>1248, +44600=>1249, +44602=>1250, +44608=>1251, +44609=>1252, +44611=>1253, +44613=>1254, +44614=>1255, +44618=>1256, +44620=>1257, +44621=>1258, +44622=>1259, +44624=>1260, +44628=>1261, +44630=>1262, +44636=>1263, +44637=>1264, +44639=>1265, +44640=>1266, +44641=>1267, +44645=>1268, +44648=>1269, +44649=>1270, +44652=>1271, +44656=>1272, +44664=>1273, +44665=>1274, +44667=>1275, +44668=>1276, +44669=>1277, +44676=>1278, +44677=>1279, +44684=>1280, +44732=>1281, +44733=>1282, +44734=>1283, +44736=>1284, +44740=>1285, +44748=>1286, +44749=>1287, +44751=>1288, +44752=>1289, +44753=>1290, +44760=>1291, +44761=>1292, +44764=>1293, +44776=>1294, +44779=>1295, +44781=>1296, +44788=>1297, +44792=>1298, +44796=>1299, +44807=>1300, +44808=>1301, +44813=>1302, +44816=>1303, +44844=>1304, +44845=>1305, +44848=>1306, +44850=>1307, +44852=>1308, +44860=>1309, +44861=>1310, +44863=>1311, +44865=>1312, +44866=>1313, +44867=>1314, +44872=>1315, +44873=>1316, +44880=>1317, +44892=>1318, +44893=>1319, +44900=>1320, +44901=>1321, +44921=>1322, +44928=>1323, +44932=>1324, +44936=>1325, +44944=>1326, +44945=>1327, +44949=>1328, +44956=>1329, +44984=>1330, +44985=>1331, +44988=>1332, +44992=>1333, +44999=>1334, +45000=>1335, +45001=>1336, +45003=>1337, +45005=>1338, +45006=>1339, +45012=>1340, +45020=>1341, +45032=>1342, +45033=>1343, +45040=>1344, +45041=>1345, +45044=>1346, +45048=>1347, +45056=>1348, +45057=>1349, +45060=>1350, +45068=>1351, +45072=>1352, +45076=>1353, +45084=>1354, +45085=>1355, +45096=>1356, +45124=>1357, +45125=>1358, +45128=>1359, +45130=>1360, +45132=>1361, +45134=>1362, +45139=>1363, +45140=>1364, +45141=>1365, +45143=>1366, +45145=>1367, +45149=>1368, +45180=>1369, +45181=>1370, +45184=>1371, +45188=>1372, +45196=>1373, +45197=>1374, +45199=>1375, +45201=>1376, +45208=>1377, +45209=>1378, +45210=>1379, +45212=>1380, +45215=>1381, +45216=>1382, +45217=>1383, +45218=>1384, +45224=>1385, +45225=>1386, +45227=>1387, +45228=>1388, +45229=>1389, +45230=>1390, +45231=>1391, +45233=>1392, +45235=>1393, +45236=>1394, +45237=>1395, +45240=>1396, +45244=>1397, +45252=>1398, +45253=>1399, +45255=>1400, +45256=>1401, +45257=>1402, +45264=>1403, +45265=>1404, +45268=>1405, +45272=>1406, +45280=>1407, +45285=>1408, +45320=>1409, +45321=>1410, +45323=>1411, +45324=>1412, +45328=>1413, +45330=>1414, +45331=>1415, +45336=>1416, +45337=>1417, +45339=>1418, +45340=>1419, +45341=>1420, +45347=>1421, +45348=>1422, +45349=>1423, +45352=>1424, +45356=>1425, +45364=>1426, +45365=>1427, +45367=>1428, +45368=>1429, +45369=>1430, +45376=>1431, +45377=>1432, +45380=>1433, +45384=>1434, +45392=>1435, +45393=>1436, +45396=>1437, +45397=>1438, +45400=>1439, +45404=>1440, +45408=>1441, +45432=>1442, +45433=>1443, +45436=>1444, +45440=>1445, +45442=>1446, +45448=>1447, +45449=>1448, +45451=>1449, +45453=>1450, +45458=>1451, +45459=>1452, +45460=>1453, +45464=>1454, +45468=>1455, +45480=>1456, +45516=>1457, +45520=>1458, +45524=>1459, +45532=>1460, +45533=>1461, +45535=>1462, +45544=>1463, +45545=>1464, +45548=>1465, +45552=>1466, +45561=>1467, +45563=>1468, +45565=>1469, +45572=>1470, +45573=>1471, +45576=>1472, +45579=>1473, +45580=>1474, +45588=>1475, +45589=>1476, +45591=>1477, +45593=>1478, +45600=>1479, +45620=>1480, +45628=>1481, +45656=>1482, +45660=>1483, +45664=>1484, +45672=>1485, +45673=>1486, +45684=>1487, +45685=>1488, +45692=>1489, +45700=>1490, +45701=>1491, +45705=>1492, +45712=>1493, +45713=>1494, +45716=>1495, +45720=>1496, +45721=>1497, +45722=>1498, +45728=>1499, +45729=>1500, +45731=>1501, +45733=>1502, +45734=>1503, +45738=>1504, +45740=>1505, +45744=>1506, +45748=>1507, +45768=>1508, +45769=>1509, +45772=>1510, +45776=>1511, +45778=>1512, +45784=>1513, +45785=>1514, +45787=>1515, +45789=>1516, +45794=>1517, +45796=>1518, +45797=>1519, +45798=>1520, +45800=>1521, +45803=>1522, +45804=>1523, +45805=>1524, +45806=>1525, +45807=>1526, +45811=>1527, +45812=>1528, +45813=>1529, +45815=>1530, +45816=>1531, +45817=>1532, +45818=>1533, +45819=>1534, +45823=>1535, +45824=>1536, +45825=>1537, +45828=>1538, +45832=>1539, +45840=>1540, +45841=>1541, +45843=>1542, +45844=>1543, +45845=>1544, +45852=>1545, +45908=>1546, +45909=>1547, +45910=>1548, +45912=>1549, +45915=>1550, +45916=>1551, +45918=>1552, +45919=>1553, +45924=>1554, +45925=>1555, +45927=>1556, +45929=>1557, +45931=>1558, +45934=>1559, +45936=>1560, +45937=>1561, +45940=>1562, +45944=>1563, +45952=>1564, +45953=>1565, +45955=>1566, +45956=>1567, +45957=>1568, +45964=>1569, +45968=>1570, +45972=>1571, +45984=>1572, +45985=>1573, +45992=>1574, +45996=>1575, +46020=>1576, +46021=>1577, +46024=>1578, +46027=>1579, +46028=>1580, +46030=>1581, +46032=>1582, +46036=>1583, +46037=>1584, +46039=>1585, +46041=>1586, +46043=>1587, +46045=>1588, +46048=>1589, +46052=>1590, +46056=>1591, +46076=>1592, +46096=>1593, +46104=>1594, +46108=>1595, +46112=>1596, +46120=>1597, +46121=>1598, +46123=>1599, +46132=>1600, +46160=>1601, +46161=>1602, +46164=>1603, +46168=>1604, +46176=>1605, +46177=>1606, +46179=>1607, +46181=>1608, +46188=>1609, +46208=>1610, +46216=>1611, +46237=>1612, +46244=>1613, +46248=>1614, +46252=>1615, +46261=>1616, +46263=>1617, +46265=>1618, +46272=>1619, +46276=>1620, +46280=>1621, +46288=>1622, +46293=>1623, +46300=>1624, +46301=>1625, +46304=>1626, +46307=>1627, +46308=>1628, +46310=>1629, +46316=>1630, +46317=>1631, +46319=>1632, +46321=>1633, +46328=>1634, +46356=>1635, +46357=>1636, +46360=>1637, +46363=>1638, +46364=>1639, +46372=>1640, +46373=>1641, +46375=>1642, +46376=>1643, +46377=>1644, +46378=>1645, +46384=>1646, +46385=>1647, +46388=>1648, +46392=>1649, +46400=>1650, +46401=>1651, +46403=>1652, +46404=>1653, +46405=>1654, +46411=>1655, +46412=>1656, +46413=>1657, +46416=>1658, +46420=>1659, +46428=>1660, +46429=>1661, +46431=>1662, +46432=>1663, +46433=>1664, +46496=>1665, +46497=>1666, +46500=>1667, +46504=>1668, +46506=>1669, +46507=>1670, +46512=>1671, +46513=>1672, +46515=>1673, +46516=>1674, +46517=>1675, +46523=>1676, +46524=>1677, +46525=>1678, +46528=>1679, +46532=>1680, +46540=>1681, +46541=>1682, +46543=>1683, +46544=>1684, +46545=>1685, +46552=>1686, +46572=>1687, +46608=>1688, +46609=>1689, +46612=>1690, +46616=>1691, +46629=>1692, +46636=>1693, +46644=>1694, +46664=>1695, +46692=>1696, +46696=>1697, +46748=>1698, +46749=>1699, +46752=>1700, +46756=>1701, +46763=>1702, +46764=>1703, +46769=>1704, +46804=>1705, +46832=>1706, +46836=>1707, +46840=>1708, +46848=>1709, +46849=>1710, +46853=>1711, +46888=>1712, +46889=>1713, +46892=>1714, +46895=>1715, +46896=>1716, +46904=>1717, +46905=>1718, +46907=>1719, +46916=>1720, +46920=>1721, +46924=>1722, +46932=>1723, +46933=>1724, +46944=>1725, +46948=>1726, +46952=>1727, +46960=>1728, +46961=>1729, +46963=>1730, +46965=>1731, +46972=>1732, +46973=>1733, +46976=>1734, +46980=>1735, +46988=>1736, +46989=>1737, +46991=>1738, +46992=>1739, +46993=>1740, +46994=>1741, +46998=>1742, +46999=>1743, +47000=>1744, +47001=>1745, +47004=>1746, +47008=>1747, +47016=>1748, +47017=>1749, +47019=>1750, +47020=>1751, +47021=>1752, +47028=>1753, +47029=>1754, +47032=>1755, +47047=>1756, +47049=>1757, +47084=>1758, +47085=>1759, +47088=>1760, +47092=>1761, +47100=>1762, +47101=>1763, +47103=>1764, +47104=>1765, +47105=>1766, +47111=>1767, +47112=>1768, +47113=>1769, +47116=>1770, +47120=>1771, +47128=>1772, +47129=>1773, +47131=>1774, +47133=>1775, +47140=>1776, +47141=>1777, +47144=>1778, +47148=>1779, +47156=>1780, +47157=>1781, +47159=>1782, +47160=>1783, +47161=>1784, +47168=>1785, +47172=>1786, +47185=>1787, +47187=>1788, +47196=>1789, +47197=>1790, +47200=>1791, +47204=>1792, +47212=>1793, +47213=>1794, +47215=>1795, +47217=>1796, +47224=>1797, +47228=>1798, +47245=>1799, +47272=>1800, +47280=>1801, +47284=>1802, +47288=>1803, +47296=>1804, +47297=>1805, +47299=>1806, +47301=>1807, +47308=>1808, +47312=>1809, +47316=>1810, +47325=>1811, +47327=>1812, +47329=>1813, +47336=>1814, +47337=>1815, +47340=>1816, +47344=>1817, +47352=>1818, +47353=>1819, +47355=>1820, +47357=>1821, +47364=>1822, +47384=>1823, +47392=>1824, +47420=>1825, +47421=>1826, +47424=>1827, +47428=>1828, +47436=>1829, +47439=>1830, +47441=>1831, +47448=>1832, +47449=>1833, +47452=>1834, +47456=>1835, +47464=>1836, +47465=>1837, +47467=>1838, +47469=>1839, +47476=>1840, +47477=>1841, +47480=>1842, +47484=>1843, +47492=>1844, +47493=>1845, +47495=>1846, +47497=>1847, +47498=>1848, +47501=>1849, +47502=>1850, +47532=>1851, +47533=>1852, +47536=>1853, +47540=>1854, +47548=>1855, +47549=>1856, +47551=>1857, +47553=>1858, +47560=>1859, +47561=>1860, +47564=>1861, +47566=>1862, +47567=>1863, +47568=>1864, +47569=>1865, +47570=>1866, +47576=>1867, +47577=>1868, +47579=>1869, +47581=>1870, +47582=>1871, +47585=>1872, +47587=>1873, +47588=>1874, +47589=>1875, +47592=>1876, +47596=>1877, +47604=>1878, +47605=>1879, +47607=>1880, +47608=>1881, +47609=>1882, +47610=>1883, +47616=>1884, +47617=>1885, +47624=>1886, +47637=>1887, +47672=>1888, +47673=>1889, +47676=>1890, +47680=>1891, +47682=>1892, +47688=>1893, +47689=>1894, +47691=>1895, +47693=>1896, +47694=>1897, +47699=>1898, +47700=>1899, +47701=>1900, +47704=>1901, +47708=>1902, +47716=>1903, +47717=>1904, +47719=>1905, +47720=>1906, +47721=>1907, +47728=>1908, +47729=>1909, +47732=>1910, +47736=>1911, +47747=>1912, +47748=>1913, +47749=>1914, +47751=>1915, +47756=>1916, +47784=>1917, +47785=>1918, +47787=>1919, +47788=>1920, +47792=>1921, +47794=>1922, +47800=>1923, +47801=>1924, +47803=>1925, +47805=>1926, +47812=>1927, +47816=>1928, +47832=>1929, +47833=>1930, +47868=>1931, +47872=>1932, +47876=>1933, +47885=>1934, +47887=>1935, +47889=>1936, +47896=>1937, +47900=>1938, +47904=>1939, +47913=>1940, +47915=>1941, +47924=>1942, +47925=>1943, +47926=>1944, +47928=>1945, +47931=>1946, +47932=>1947, +47933=>1948, +47934=>1949, +47940=>1950, +47941=>1951, +47943=>1952, +47945=>1953, +47949=>1954, +47951=>1955, +47952=>1956, +47956=>1957, +47960=>1958, +47969=>1959, +47971=>1960, +47980=>1961, +48008=>1962, +48012=>1963, +48016=>1964, +48036=>1965, +48040=>1966, +48044=>1967, +48052=>1968, +48055=>1969, +48064=>1970, +48068=>1971, +48072=>1972, +48080=>1973, +48083=>1974, +48120=>1975, +48121=>1976, +48124=>1977, +48127=>1978, +48128=>1979, +48130=>1980, +48136=>1981, +48137=>1982, +48139=>1983, +48140=>1984, +48141=>1985, +48143=>1986, +48145=>1987, +48148=>1988, +48149=>1989, +48150=>1990, +48151=>1991, +48152=>1992, +48155=>1993, +48156=>1994, +48157=>1995, +48158=>1996, +48159=>1997, +48164=>1998, +48165=>1999, +48167=>2000, +48169=>2001, +48173=>2002, +48176=>2003, +48177=>2004, +48180=>2005, +48184=>2006, +48192=>2007, +48193=>2008, +48195=>2009, +48196=>2010, +48197=>2011, +48201=>2012, +48204=>2013, +48205=>2014, +48208=>2015, +48221=>2016, +48260=>2017, +48261=>2018, +48264=>2019, +48267=>2020, +48268=>2021, +48270=>2022, +48276=>2023, +48277=>2024, +48279=>2025, +48281=>2026, +48282=>2027, +48288=>2028, +48289=>2029, +48292=>2030, +48295=>2031, +48296=>2032, +48304=>2033, +48305=>2034, +48307=>2035, +48308=>2036, +48309=>2037, +48316=>2038, +48317=>2039, +48320=>2040, +48324=>2041, +48333=>2042, +48335=>2043, +48336=>2044, +48337=>2045, +48341=>2046, +48344=>2047, +48348=>2048, +48372=>2049, +48373=>2050, +48374=>2051, +48376=>2052, +48380=>2053, +48388=>2054, +48389=>2055, +48391=>2056, +48393=>2057, +48400=>2058, +48404=>2059, +48420=>2060, +48428=>2061, +48448=>2062, +48456=>2063, +48457=>2064, +48460=>2065, +48464=>2066, +48472=>2067, +48473=>2068, +48484=>2069, +48488=>2070, +48512=>2071, +48513=>2072, +48516=>2073, +48519=>2074, +48520=>2075, +48521=>2076, +48522=>2077, +48528=>2078, +48529=>2079, +48531=>2080, +48533=>2081, +48537=>2082, +48538=>2083, +48540=>2084, +48548=>2085, +48560=>2086, +48568=>2087, +48596=>2088, +48597=>2089, +48600=>2090, +48604=>2091, +48617=>2092, +48624=>2093, +48628=>2094, +48632=>2095, +48640=>2096, +48643=>2097, +48645=>2098, +48652=>2099, +48653=>2100, +48656=>2101, +48660=>2102, +48668=>2103, +48669=>2104, +48671=>2105, +48708=>2106, +48709=>2107, +48712=>2108, +48716=>2109, +48718=>2110, +48724=>2111, +48725=>2112, +48727=>2113, +48729=>2114, +48730=>2115, +48731=>2116, +48736=>2117, +48737=>2118, +48740=>2119, +48744=>2120, +48746=>2121, +48752=>2122, +48753=>2123, +48755=>2124, +48756=>2125, +48757=>2126, +48763=>2127, +48764=>2128, +48765=>2129, +48768=>2130, +48772=>2131, +48780=>2132, +48781=>2133, +48783=>2134, +48784=>2135, +48785=>2136, +48792=>2137, +48793=>2138, +48808=>2139, +48848=>2140, +48849=>2141, +48852=>2142, +48855=>2143, +48856=>2144, +48864=>2145, +48867=>2146, +48868=>2147, +48869=>2148, +48876=>2149, +48897=>2150, +48904=>2151, +48905=>2152, +48920=>2153, +48921=>2154, +48923=>2155, +48924=>2156, +48925=>2157, +48960=>2158, +48961=>2159, +48964=>2160, +48968=>2161, +48976=>2162, +48977=>2163, +48981=>2164, +49044=>2165, +49072=>2166, +49093=>2167, +49100=>2168, +49101=>2169, +49104=>2170, +49108=>2171, +49116=>2172, +49119=>2173, +49121=>2174, +49212=>2175, +49233=>2176, +49240=>2177, +49244=>2178, +49248=>2179, +49256=>2180, +49257=>2181, +49296=>2182, +49297=>2183, +49300=>2184, +49304=>2185, +49312=>2186, +49313=>2187, +49315=>2188, +49317=>2189, +49324=>2190, +49325=>2191, +49327=>2192, +49328=>2193, +49331=>2194, +49332=>2195, +49333=>2196, +49334=>2197, +49340=>2198, +49341=>2199, +49343=>2200, +49344=>2201, +49345=>2202, +49349=>2203, +49352=>2204, +49353=>2205, +49356=>2206, +49360=>2207, +49368=>2208, +49369=>2209, +49371=>2210, +49372=>2211, +49373=>2212, +49380=>2213, +49381=>2214, +49384=>2215, +49388=>2216, +49396=>2217, +49397=>2218, +49399=>2219, +49401=>2220, +49408=>2221, +49412=>2222, +49416=>2223, +49424=>2224, +49429=>2225, +49436=>2226, +49437=>2227, +49438=>2228, +49439=>2229, +49440=>2230, +49443=>2231, +49444=>2232, +49446=>2233, +49447=>2234, +49452=>2235, +49453=>2236, +49455=>2237, +49456=>2238, +49457=>2239, +49462=>2240, +49464=>2241, +49465=>2242, +49468=>2243, +49472=>2244, +49480=>2245, +49481=>2246, +49483=>2247, +49484=>2248, +49485=>2249, +49492=>2250, +49493=>2251, +49496=>2252, +49500=>2253, +49508=>2254, +49509=>2255, +49511=>2256, +49512=>2257, +49513=>2258, +49520=>2259, +49524=>2260, +49528=>2261, +49541=>2262, +49548=>2263, +49549=>2264, +49550=>2265, +49552=>2266, +49556=>2267, +49558=>2268, +49564=>2269, +49565=>2270, +49567=>2271, +49569=>2272, +49573=>2273, +49576=>2274, +49577=>2275, +49580=>2276, +49584=>2277, +49597=>2278, +49604=>2279, +49608=>2280, +49612=>2281, +49620=>2282, +49623=>2283, +49624=>2284, +49632=>2285, +49636=>2286, +49640=>2287, +49648=>2288, +49649=>2289, +49651=>2290, +49660=>2291, +49661=>2292, +49664=>2293, +49668=>2294, +49676=>2295, +49677=>2296, +49679=>2297, +49681=>2298, +49688=>2299, +49689=>2300, +49692=>2301, +49695=>2302, +49696=>2303, +49704=>2304, +49705=>2305, +49707=>2306, +49709=>2307, +49711=>2308, +49713=>2309, +49714=>2310, +49716=>2311, +49736=>2312, +49744=>2313, +49745=>2314, +49748=>2315, +49752=>2316, +49760=>2317, +49765=>2318, +49772=>2319, +49773=>2320, +49776=>2321, +49780=>2322, +49788=>2323, +49789=>2324, +49791=>2325, +49793=>2326, +49800=>2327, +49801=>2328, +49808=>2329, +49816=>2330, +49819=>2331, +49821=>2332, +49828=>2333, +49829=>2334, +49832=>2335, +49836=>2336, +49837=>2337, +49844=>2338, +49845=>2339, +49847=>2340, +49849=>2341, +49884=>2342, +49885=>2343, +49888=>2344, +49891=>2345, +49892=>2346, +49899=>2347, +49900=>2348, +49901=>2349, +49903=>2350, +49905=>2351, +49910=>2352, +49912=>2353, +49913=>2354, +49915=>2355, +49916=>2356, +49920=>2357, +49928=>2358, +49929=>2359, +49932=>2360, +49933=>2361, +49939=>2362, +49940=>2363, +49941=>2364, +49944=>2365, +49948=>2366, +49956=>2367, +49957=>2368, +49960=>2369, +49961=>2370, +49989=>2371, +50024=>2372, +50025=>2373, +50028=>2374, +50032=>2375, +50034=>2376, +50040=>2377, +50041=>2378, +50044=>2379, +50045=>2380, +50052=>2381, +50056=>2382, +50060=>2383, +50112=>2384, +50136=>2385, +50137=>2386, +50140=>2387, +50143=>2388, +50144=>2389, +50146=>2390, +50152=>2391, +50153=>2392, +50157=>2393, +50164=>2394, +50165=>2395, +50168=>2396, +50184=>2397, +50192=>2398, +50212=>2399, +50220=>2400, +50224=>2401, +50228=>2402, +50236=>2403, +50237=>2404, +50248=>2405, +50276=>2406, +50277=>2407, +50280=>2408, +50284=>2409, +50292=>2410, +50293=>2411, +50297=>2412, +50304=>2413, +50324=>2414, +50332=>2415, +50360=>2416, +50364=>2417, +50409=>2418, +50416=>2419, +50417=>2420, +50420=>2421, +50424=>2422, +50426=>2423, +50431=>2424, +50432=>2425, +50433=>2426, +50444=>2427, +50448=>2428, +50452=>2429, +50460=>2430, +50472=>2431, +50473=>2432, +50476=>2433, +50480=>2434, +50488=>2435, +50489=>2436, +50491=>2437, +50493=>2438, +50500=>2439, +50501=>2440, +50504=>2441, +50505=>2442, +50506=>2443, +50508=>2444, +50509=>2445, +50510=>2446, +50515=>2447, +50516=>2448, +50517=>2449, +50519=>2450, +50520=>2451, +50521=>2452, +50525=>2453, +50526=>2454, +50528=>2455, +50529=>2456, +50532=>2457, +50536=>2458, +50544=>2459, +50545=>2460, +50547=>2461, +50548=>2462, +50549=>2463, +50556=>2464, +50557=>2465, +50560=>2466, +50564=>2467, +50567=>2468, +50572=>2469, +50573=>2470, +50575=>2471, +50577=>2472, +50581=>2473, +50583=>2474, +50584=>2475, +50588=>2476, +50592=>2477, +50601=>2478, +50612=>2479, +50613=>2480, +50616=>2481, +50617=>2482, +50619=>2483, +50620=>2484, +50621=>2485, +50622=>2486, +50628=>2487, +50629=>2488, +50630=>2489, +50631=>2490, +50632=>2491, +50633=>2492, +50634=>2493, +50636=>2494, +50638=>2495, +50640=>2496, +50641=>2497, +50644=>2498, +50648=>2499, +50656=>2500, +50657=>2501, +50659=>2502, +50661=>2503, +50668=>2504, +50669=>2505, +50670=>2506, +50672=>2507, +50676=>2508, +50678=>2509, +50679=>2510, +50684=>2511, +50685=>2512, +50686=>2513, +50687=>2514, +50688=>2515, +50689=>2516, +50693=>2517, +50694=>2518, +50695=>2519, +50696=>2520, +50700=>2521, +50704=>2522, +50712=>2523, +50713=>2524, +50715=>2525, +50716=>2526, +50724=>2527, +50725=>2528, +50728=>2529, +50732=>2530, +50733=>2531, +50734=>2532, +50736=>2533, +50739=>2534, +50740=>2535, +50741=>2536, +50743=>2537, +50745=>2538, +50747=>2539, +50752=>2540, +50753=>2541, +50756=>2542, +50760=>2543, +50768=>2544, +50769=>2545, +50771=>2546, +50772=>2547, +50773=>2548, +50780=>2549, +50781=>2550, +50784=>2551, +50796=>2552, +50799=>2553, +50801=>2554, +50808=>2555, +50809=>2556, +50812=>2557, +50816=>2558, +50824=>2559, +50825=>2560, +50827=>2561, +50829=>2562, +50836=>2563, +50837=>2564, +50840=>2565, +50844=>2566, +50852=>2567, +50853=>2568, +50855=>2569, +50857=>2570, +50864=>2571, +50865=>2572, +50868=>2573, +50872=>2574, +50873=>2575, +50874=>2576, +50880=>2577, +50881=>2578, +50883=>2579, +50885=>2580, +50892=>2581, +50893=>2582, +50896=>2583, +50900=>2584, +50908=>2585, +50909=>2586, +50912=>2587, +50913=>2588, +50920=>2589, +50921=>2590, +50924=>2591, +50928=>2592, +50936=>2593, +50937=>2594, +50941=>2595, +50948=>2596, +50949=>2597, +50952=>2598, +50956=>2599, +50964=>2600, +50965=>2601, +50967=>2602, +50969=>2603, +50976=>2604, +50977=>2605, +50980=>2606, +50984=>2607, +50992=>2608, +50993=>2609, +50995=>2610, +50997=>2611, +50999=>2612, +51004=>2613, +51005=>2614, +51008=>2615, +51012=>2616, +51018=>2617, +51020=>2618, +51021=>2619, +51023=>2620, +51025=>2621, +51026=>2622, +51027=>2623, +51028=>2624, +51029=>2625, +51030=>2626, +51031=>2627, +51032=>2628, +51036=>2629, +51040=>2630, +51048=>2631, +51051=>2632, +51060=>2633, +51061=>2634, +51064=>2635, +51068=>2636, +51069=>2637, +51070=>2638, +51075=>2639, +51076=>2640, +51077=>2641, +51079=>2642, +51080=>2643, +51081=>2644, +51082=>2645, +51086=>2646, +51088=>2647, +51089=>2648, +51092=>2649, +51094=>2650, +51095=>2651, +51096=>2652, +51098=>2653, +51104=>2654, +51105=>2655, +51107=>2656, +51108=>2657, +51109=>2658, +51110=>2659, +51116=>2660, +51117=>2661, +51120=>2662, +51124=>2663, +51132=>2664, +51133=>2665, +51135=>2666, +51136=>2667, +51137=>2668, +51144=>2669, +51145=>2670, +51148=>2671, +51150=>2672, +51152=>2673, +51160=>2674, +51165=>2675, +51172=>2676, +51176=>2677, +51180=>2678, +51200=>2679, +51201=>2680, +51204=>2681, +51208=>2682, +51210=>2683, +51216=>2684, +51217=>2685, +51219=>2686, +51221=>2687, +51222=>2688, +51228=>2689, +51229=>2690, +51232=>2691, +51236=>2692, +51244=>2693, +51245=>2694, +51247=>2695, +51249=>2696, +51256=>2697, +51260=>2698, +51264=>2699, +51272=>2700, +51273=>2701, +51276=>2702, +51277=>2703, +51284=>2704, +51312=>2705, +51313=>2706, +51316=>2707, +51320=>2708, +51322=>2709, +51328=>2710, +51329=>2711, +51331=>2712, +51333=>2713, +51334=>2714, +51335=>2715, +51339=>2716, +51340=>2717, +51341=>2718, +51348=>2719, +51357=>2720, +51359=>2721, +51361=>2722, +51368=>2723, +51388=>2724, +51389=>2725, +51396=>2726, +51400=>2727, +51404=>2728, +51412=>2729, +51413=>2730, +51415=>2731, +51417=>2732, +51424=>2733, +51425=>2734, +51428=>2735, +51445=>2736, +51452=>2737, +51453=>2738, +51456=>2739, +51460=>2740, +51461=>2741, +51462=>2742, +51468=>2743, +51469=>2744, +51471=>2745, +51473=>2746, +51480=>2747, +51500=>2748, +51508=>2749, +51536=>2750, +51537=>2751, +51540=>2752, +51544=>2753, +51552=>2754, +51553=>2755, +51555=>2756, +51564=>2757, +51568=>2758, +51572=>2759, +51580=>2760, +51592=>2761, +51593=>2762, +51596=>2763, +51600=>2764, +51608=>2765, +51609=>2766, +51611=>2767, +51613=>2768, +51648=>2769, +51649=>2770, +51652=>2771, +51655=>2772, +51656=>2773, +51658=>2774, +51664=>2775, +51665=>2776, +51667=>2777, +51669=>2778, +51670=>2779, +51673=>2780, +51674=>2781, +51676=>2782, +51677=>2783, +51680=>2784, +51682=>2785, +51684=>2786, +51687=>2787, +51692=>2788, +51693=>2789, +51695=>2790, +51696=>2791, +51697=>2792, +51704=>2793, +51705=>2794, +51708=>2795, +51712=>2796, +51720=>2797, +51721=>2798, +51723=>2799, +51724=>2800, +51725=>2801, +51732=>2802, +51736=>2803, +51753=>2804, +51788=>2805, +51789=>2806, +51792=>2807, +51796=>2808, +51804=>2809, +51805=>2810, +51807=>2811, +51808=>2812, +51809=>2813, +51816=>2814, +51837=>2815, +51844=>2816, +51864=>2817, +51900=>2818, +51901=>2819, +51904=>2820, +51908=>2821, +51916=>2822, +51917=>2823, +51919=>2824, +51921=>2825, +51923=>2826, +51928=>2827, +51929=>2828, +51936=>2829, +51948=>2830, +51956=>2831, +51976=>2832, +51984=>2833, +51988=>2834, +51992=>2835, +52000=>2836, +52001=>2837, +52033=>2838, +52040=>2839, +52041=>2840, +52044=>2841, +52048=>2842, +52056=>2843, +52057=>2844, +52061=>2845, +52068=>2846, +52088=>2847, +52089=>2848, +52124=>2849, +52152=>2850, +52180=>2851, +52196=>2852, +52199=>2853, +52201=>2854, +52236=>2855, +52237=>2856, +52240=>2857, +52244=>2858, +52252=>2859, +52253=>2860, +52257=>2861, +52258=>2862, +52263=>2863, +52264=>2864, +52265=>2865, +52268=>2866, +52270=>2867, +52272=>2868, +52280=>2869, +52281=>2870, +52283=>2871, +52284=>2872, +52285=>2873, +52286=>2874, +52292=>2875, +52293=>2876, +52296=>2877, +52300=>2878, +52308=>2879, +52309=>2880, +52311=>2881, +52312=>2882, +52313=>2883, +52320=>2884, +52324=>2885, +52326=>2886, +52328=>2887, +52336=>2888, +52341=>2889, +52376=>2890, +52377=>2891, +52380=>2892, +52384=>2893, +52392=>2894, +52393=>2895, +52395=>2896, +52396=>2897, +52397=>2898, +52404=>2899, +52405=>2900, +52408=>2901, +52412=>2902, +52420=>2903, +52421=>2904, +52423=>2905, +52425=>2906, +52432=>2907, +52436=>2908, +52452=>2909, +52460=>2910, +52464=>2911, +52481=>2912, +52488=>2913, +52489=>2914, +52492=>2915, +52496=>2916, +52504=>2917, +52505=>2918, +52507=>2919, +52509=>2920, +52516=>2921, +52520=>2922, +52524=>2923, +52537=>2924, +52572=>2925, +52576=>2926, +52580=>2927, +52588=>2928, +52589=>2929, +52591=>2930, +52593=>2931, +52600=>2932, +52616=>2933, +52628=>2934, +52629=>2935, +52632=>2936, +52636=>2937, +52644=>2938, +52645=>2939, +52647=>2940, +52649=>2941, +52656=>2942, +52676=>2943, +52684=>2944, +52688=>2945, +52712=>2946, +52716=>2947, +52720=>2948, +52728=>2949, +52729=>2950, +52731=>2951, +52733=>2952, +52740=>2953, +52744=>2954, +52748=>2955, +52756=>2956, +52761=>2957, +52768=>2958, +52769=>2959, +52772=>2960, +52776=>2961, +52784=>2962, +52785=>2963, +52787=>2964, +52789=>2965, +52824=>2966, +52825=>2967, +52828=>2968, +52831=>2969, +52832=>2970, +52833=>2971, +52840=>2972, +52841=>2973, +52843=>2974, +52845=>2975, +52852=>2976, +52853=>2977, +52856=>2978, +52860=>2979, +52868=>2980, +52869=>2981, +52871=>2982, +52873=>2983, +52880=>2984, +52881=>2985, +52884=>2986, +52888=>2987, +52896=>2988, +52897=>2989, +52899=>2990, +52900=>2991, +52901=>2992, +52908=>2993, +52909=>2994, +52929=>2995, +52964=>2996, +52965=>2997, +52968=>2998, +52971=>2999, +52972=>3000, +52980=>3001, +52981=>3002, +52983=>3003, +52984=>3004, +52985=>3005, +52992=>3006, +52993=>3007, +52996=>3008, +53000=>3009, +53008=>3010, +53009=>3011, +53011=>3012, +53013=>3013, +53020=>3014, +53024=>3015, +53028=>3016, +53036=>3017, +53037=>3018, +53039=>3019, +53040=>3020, +53041=>3021, +53048=>3022, +53076=>3023, +53077=>3024, +53080=>3025, +53084=>3026, +53092=>3027, +53093=>3028, +53095=>3029, +53097=>3030, +53104=>3031, +53105=>3032, +53108=>3033, +53112=>3034, +53120=>3035, +53125=>3036, +53132=>3037, +53153=>3038, +53160=>3039, +53168=>3040, +53188=>3041, +53216=>3042, +53217=>3043, +53220=>3044, +53224=>3045, +53232=>3046, +53233=>3047, +53235=>3048, +53237=>3049, +53244=>3050, +53248=>3051, +53252=>3052, +53265=>3053, +53272=>3054, +53293=>3055, +53300=>3056, +53301=>3057, +53304=>3058, +53308=>3059, +53316=>3060, +53317=>3061, +53319=>3062, +53321=>3063, +53328=>3064, +53332=>3065, +53336=>3066, +53344=>3067, +53356=>3068, +53357=>3069, +53360=>3070, +53364=>3071, +53372=>3072, +53373=>3073, +53377=>3074, +53412=>3075, +53413=>3076, +53416=>3077, +53420=>3078, +53428=>3079, +53429=>3080, +53431=>3081, +53433=>3082, +53440=>3083, +53441=>3084, +53444=>3085, +53448=>3086, +53449=>3087, +53456=>3088, +53457=>3089, +53459=>3090, +53460=>3091, +53461=>3092, +53468=>3093, +53469=>3094, +53472=>3095, +53476=>3096, +53484=>3097, +53485=>3098, +53487=>3099, +53488=>3100, +53489=>3101, +53496=>3102, +53517=>3103, +53552=>3104, +53553=>3105, +53556=>3106, +53560=>3107, +53562=>3108, +53568=>3109, +53569=>3110, +53571=>3111, +53572=>3112, +53573=>3113, +53580=>3114, +53581=>3115, +53584=>3116, +53588=>3117, +53596=>3118, +53597=>3119, +53599=>3120, +53601=>3121, +53608=>3122, +53612=>3123, +53628=>3124, +53636=>3125, +53640=>3126, +53664=>3127, +53665=>3128, +53668=>3129, +53672=>3130, +53680=>3131, +53681=>3132, +53683=>3133, +53685=>3134, +53690=>3135, +53692=>3136, +53696=>3137, +53720=>3138, +53748=>3139, +53752=>3140, +53767=>3141, +53769=>3142, +53776=>3143, +53804=>3144, +53805=>3145, +53808=>3146, +53812=>3147, +53820=>3148, +53821=>3149, +53823=>3150, +53825=>3151, +53832=>3152, +53852=>3153, +53860=>3154, +53888=>3155, +53889=>3156, +53892=>3157, +53896=>3158, +53904=>3159, +53905=>3160, +53909=>3161, +53916=>3162, +53920=>3163, +53924=>3164, +53932=>3165, +53937=>3166, +53944=>3167, +53945=>3168, +53948=>3169, +53951=>3170, +53952=>3171, +53954=>3172, +53960=>3173, +53961=>3174, +53963=>3175, +53972=>3176, +53976=>3177, +53980=>3178, +53988=>3179, +53989=>3180, +54000=>3181, +54001=>3182, +54004=>3183, +54008=>3184, +54016=>3185, +54017=>3186, +54019=>3187, +54021=>3188, +54028=>3189, +54029=>3190, +54030=>3191, +54032=>3192, +54036=>3193, +54038=>3194, +54044=>3195, +54045=>3196, +54047=>3197, +54048=>3198, +54049=>3199, +54053=>3200, +54056=>3201, +54057=>3202, +54060=>3203, +54064=>3204, +54072=>3205, +54073=>3206, +54075=>3207, +54076=>3208, +54077=>3209, +54084=>3210, +54085=>3211, +54140=>3212, +54141=>3213, +54144=>3214, +54148=>3215, +54156=>3216, +54157=>3217, +54159=>3218, +54160=>3219, +54161=>3220, +54168=>3221, +54169=>3222, +54172=>3223, +54176=>3224, +54184=>3225, +54185=>3226, +54187=>3227, +54189=>3228, +54196=>3229, +54200=>3230, +54204=>3231, +54212=>3232, +54213=>3233, +54216=>3234, +54217=>3235, +54224=>3236, +54232=>3237, +54241=>3238, +54243=>3239, +54252=>3240, +54253=>3241, +54256=>3242, +54260=>3243, +54268=>3244, +54269=>3245, +54271=>3246, +54273=>3247, +54280=>3248, +54301=>3249, +54336=>3250, +54340=>3251, +54364=>3252, +54368=>3253, +54372=>3254, +54381=>3255, +54383=>3256, +54392=>3257, +54393=>3258, +54396=>3259, +54399=>3260, +54400=>3261, +54402=>3262, +54408=>3263, +54409=>3264, +54411=>3265, +54413=>3266, +54420=>3267, +54441=>3268, +54476=>3269, +54480=>3270, +54484=>3271, +54492=>3272, +54495=>3273, +54504=>3274, +54508=>3275, +54512=>3276, +54520=>3277, +54523=>3278, +54525=>3279, +54532=>3280, +54536=>3281, +54540=>3282, +54548=>3283, +54549=>3284, +54551=>3285, +54588=>3286, +54589=>3287, +54592=>3288, +54596=>3289, +54604=>3290, +54605=>3291, +54607=>3292, +54609=>3293, +54616=>3294, +54617=>3295, +54620=>3296, +54624=>3297, +54629=>3298, +54632=>3299, +54633=>3300, +54635=>3301, +54637=>3302, +54644=>3303, +54645=>3304, +54648=>3305, +54652=>3306, +54660=>3307, +54661=>3308, +54663=>3309, +54664=>3310, +54665=>3311, +54672=>3312, +54693=>3313, +54728=>3314, +54729=>3315, +54732=>3316, +54736=>3317, +54738=>3318, +54744=>3319, +54745=>3320, +54747=>3321, +54749=>3322, +54756=>3323, +54757=>3324, +54760=>3325, +54764=>3326, +54772=>3327, +54773=>3328, +54775=>3329, +54777=>3330, +54784=>3331, +54785=>3332, +54788=>3333, +54792=>3334, +54800=>3335, +54801=>3336, +54803=>3337, +54804=>3338, +54805=>3339, +54812=>3340, +54816=>3341, +54820=>3342, +54829=>3343, +54840=>3344, +54841=>3345, +54844=>3346, +54848=>3347, +54853=>3348, +54856=>3349, +54857=>3350, +54859=>3351, +54861=>3352, +54865=>3353, +54868=>3354, +54869=>3355, +54872=>3356, +54876=>3357, +54887=>3358, +54889=>3359, +54896=>3360, +54897=>3361, +54900=>3362, +54915=>3363, +54917=>3364, +54924=>3365, +54925=>3366, +54928=>3367, +54932=>3368, +54941=>3369, +54943=>3370, +54945=>3371, +54952=>3372, +54956=>3373, +54960=>3374, +54969=>3375, +54971=>3376, +54980=>3377, +54981=>3378, +54984=>3379, +54988=>3380, +54993=>3381, +54996=>3382, +54999=>3383, +55001=>3384, +55008=>3385, +55012=>3386, +55016=>3387, +55024=>3388, +55029=>3389, +55036=>3390, +55037=>3391, +55040=>3392, +55044=>3393, +55057=>3394, +55064=>3395, +55065=>3396, +55068=>3397, +55072=>3398, +55080=>3399, +55081=>3400, +55083=>3401, +55085=>3402, +55092=>3403, +55093=>3404, +55096=>3405, +55100=>3406, +55108=>3407, +55111=>3408, +55113=>3409, +55120=>3410, +55121=>3411, +55124=>3412, +55126=>3413, +55127=>3414, +55128=>3415, +55129=>3416, +55136=>3417, +55137=>3418, +55139=>3419, +55141=>3420, +55145=>3421, +55148=>3422, +55152=>3423, +55156=>3424, +55164=>3425, +55165=>3426, +55169=>3427, +55176=>3428, +55177=>3429, +55180=>3430, +55184=>3431, +55192=>3432, +55193=>3433, +55195=>3434, +55197=>3435, +20285=>3436, +20339=>3437, +20551=>3438, +20729=>3439, +21152=>3440, +21487=>3441, +21621=>3442, +21733=>3443, +22025=>3444, +23233=>3445, +23478=>3446, +26247=>3447, +26550=>3448, +26551=>3449, +26607=>3450, +27468=>3451, +29634=>3452, +30146=>3453, +31292=>3454, +33499=>3455, +33540=>3456, +34903=>3457, +34952=>3458, +35382=>3459, +36040=>3460, +63747=>3460, +36303=>3461, +36603=>3462, +36838=>3463, +39381=>3464, +21051=>3465, +21364=>3466, +21508=>3467, +24682=>3468, +24932=>3469, +27580=>3470, +29647=>3471, +33050=>3472, +35258=>3473, +12179=>3474, +35282=>3474, +38307=>3475, +20355=>3476, +21002=>3477, +22718=>3478, +22904=>3479, +23014=>3480, +12082=>3481, +24178=>3481, +24185=>3482, +25031=>3483, +25536=>3484, +26438=>3485, +26604=>3486, +26751=>3487, +28567=>3488, +30286=>3489, +30475=>3490, +30965=>3491, +31240=>3492, +31487=>3493, +31777=>3494, +32925=>3495, +12169=>3496, +33390=>3496, +33393=>3497, +35563=>3498, +38291=>3499, +20075=>3500, +21917=>3501, +26359=>3502, +28212=>3503, +30883=>3504, +31469=>3505, +33883=>3506, +35088=>3507, +34638=>3508, +38824=>3509, +21208=>3510, +22350=>3511, +22570=>3512, +23884=>3513, +24863=>3514, +25022=>3515, +25121=>3516, +25954=>3517, +26577=>3518, +27204=>3519, +28187=>3520, +12130=>3521, +29976=>3521, +30131=>3522, +30435=>3523, +30640=>3524, +32058=>3525, +37039=>3526, +37969=>3527, +37970=>3528, +40853=>3529, +21283=>3530, +23724=>3531, +30002=>3532, +32987=>3533, +37440=>3534, +38296=>3535, +21083=>3536, +22536=>3537, +23004=>3538, +23713=>3539, +23831=>3540, +24247=>3541, +24378=>3542, +24394=>3543, +24951=>3544, +27743=>3545, +30074=>3546, +30086=>3547, +31968=>3548, +32115=>3549, +32177=>3550, +32652=>3551, +33108=>3552, +33313=>3553, +34193=>3554, +35137=>3555, +35611=>3556, +37628=>3557, +38477=>3558, +64009=>3558, +40007=>3559, +20171=>3560, +20215=>3561, +20491=>3562, +20977=>3563, +22607=>3564, +24887=>3565, +24894=>3566, +24936=>3567, +25913=>3568, +27114=>3569, +28433=>3570, +30117=>3571, +30342=>3572, +30422=>3573, +31623=>3574, +33445=>3575, +33995=>3576, +37799=>3577, +38283=>3578, +21888=>3579, +23458=>3580, +22353=>3581, +31923=>3582, +32697=>3583, +37301=>3584, +20520=>3585, +21435=>3586, +23621=>3587, +24040=>3588, +25298=>3589, +25454=>3590, +25818=>3591, +25831=>3592, +28192=>3593, +28844=>3594, +31067=>3595, +36317=>3596, +36382=>3597, +36989=>3598, +37445=>3599, +37624=>3600, +20094=>3601, +20214=>3602, +20581=>3603, +12081=>3604, +24062=>3604, +24314=>3605, +24838=>3606, +26967=>3607, +33137=>3608, +34388=>3609, +36423=>3610, +37749=>3611, +39467=>3612, +20062=>3613, +20625=>3614, +26480=>3615, +26688=>3616, +20745=>3617, +21133=>3618, +21138=>3619, +27298=>3620, +30652=>3621, +37392=>3622, +40660=>3623, +21163=>3624, +24623=>3625, +36850=>3626, +20552=>3627, +25001=>3628, +25581=>3629, +25802=>3630, +26684=>3631, +27268=>3632, +28608=>3633, +33160=>3634, +35233=>3635, +38548=>3636, +22533=>3637, +29309=>3638, +12125=>3639, +29356=>3639, +29956=>3640, +32121=>3641, +32365=>3642, +32937=>3643, +12178=>3644, +35211=>3644, +64010=>3644, +35700=>3645, +36963=>3646, +40273=>3647, +25225=>3648, +27770=>3649, +28500=>3650, +32080=>3651, +32570=>3652, +35363=>3653, +20860=>3654, +24906=>3655, +31645=>3656, +35609=>3657, +37463=>3658, +37772=>3659, +20140=>3660, +20435=>3661, +20510=>3662, +20670=>3663, +20742=>3664, +21185=>3665, +21197=>3666, +21375=>3667, +22384=>3668, +22659=>3669, +24218=>3670, +24465=>3671, +24950=>3672, +25004=>3673, +25806=>3674, +25964=>3675, +26223=>3676, +26299=>3677, +26356=>3678, +63745=>3678, +26775=>3679, +28039=>3680, +28805=>3681, +28913=>3682, +29855=>3683, +29861=>3684, +29898=>3685, +30169=>3686, +30828=>3687, +30956=>3688, +31455=>3689, +31478=>3690, +32069=>3691, +32147=>3692, +32789=>3693, +32831=>3694, +33051=>3695, +33686=>3696, +35686=>3697, +36629=>3698, +36885=>3699, +37857=>3700, +38915=>3701, +38968=>3702, +39514=>3703, +39912=>3704, +20418=>3705, +21843=>3706, +22586=>3707, +22865=>3708, +63753=>3708, +23395=>3709, +23622=>3710, +24760=>3711, +25106=>3712, +26690=>3713, +26800=>3714, +26856=>3715, +28330=>3716, +30028=>3717, +30328=>3718, +30926=>3719, +31293=>3720, +31995=>3721, +32363=>3722, +32380=>3723, +35336=>3724, +35489=>3725, +35903=>3726, +38542=>3727, +40388=>3728, +21476=>3729, +21481=>3730, +21578=>3731, +21617=>3732, +22266=>3733, +22993=>3734, +23396=>3735, +23611=>3736, +24235=>3737, +25335=>3738, +25911=>3739, +25925=>3740, +25970=>3741, +26272=>3742, +26543=>3743, +27073=>3744, +27837=>3745, +30204=>3746, +30352=>3747, +30590=>3748, +31295=>3749, +32660=>3750, +32771=>3751, +32929=>3752, +33167=>3753, +33510=>3754, +33533=>3755, +33776=>3756, +34241=>3757, +34865=>3758, +34996=>3759, +35493=>3760, +36764=>3761, +37678=>3762, +38599=>3763, +39015=>3764, +12220=>3765, +39640=>3765, +12238=>3766, +40723=>3766, +21741=>3767, +26011=>3768, +26354=>3769, +26767=>3770, +31296=>3771, +12181=>3772, +35895=>3772, +40288=>3773, +22256=>3774, +22372=>3775, +23825=>3776, +26118=>3777, +26801=>3778, +26829=>3779, +28414=>3780, +29736=>3781, +34974=>3782, +39908=>3783, +27752=>3784, +12219=>3785, +39592=>3785, +20379=>3786, +20844=>3787, +20849=>3788, +21151=>3789, +23380=>3790, +12079=>3791, +24037=>3791, +24656=>3792, +24685=>3793, +25329=>3794, +25511=>3795, +25915=>3796, +29657=>3797, +31354=>3798, +34467=>3799, +36002=>3800, +38799=>3801, +20018=>3802, +63749=>3802, +23521=>3803, +12093=>3804, +25096=>3804, +26524=>3805, +12128=>3806, +29916=>3806, +31185=>3807, +33747=>3808, +35463=>3809, +35506=>3810, +36328=>3811, +36942=>3812, +37707=>3813, +38982=>3814, +24275=>3815, +64011=>3815, +27112=>3816, +34303=>3817, +37101=>3818, +20896=>3819, +23448=>3820, +23532=>3821, +24931=>3822, +26874=>3823, +27454=>3824, +28748=>3825, +29743=>3826, +29912=>3827, +31649=>3828, +32592=>3829, +33733=>3830, +35264=>3831, +36011=>3832, +38364=>3833, +39208=>3834, +21038=>3835, +24669=>3836, +25324=>3837, +36866=>3838, +20362=>3839, +20809=>3840, +21281=>3841, +22745=>3842, +24291=>3843, +26336=>3844, +27960=>3845, +28826=>3846, +29378=>3847, +29654=>3848, +31568=>3849, +33009=>3850, +37979=>3851, +21350=>3852, +25499=>3853, +32619=>3854, +20054=>3855, +20608=>3856, +22602=>3857, +22750=>3858, +24618=>3859, +24871=>3860, +25296=>3861, +27088=>3862, +39745=>3863, +23439=>3864, +32024=>3865, +32945=>3866, +36703=>3867, +20132=>3868, +20689=>3869, +21676=>3870, +21932=>3871, +23308=>3872, +23968=>3873, +24039=>3874, +25898=>3875, +25934=>3876, +26657=>3877, +27211=>3878, +29409=>3879, +30350=>3880, +30703=>3881, +32094=>3882, +32761=>3883, +33184=>3884, +34126=>3885, +34527=>3886, +36611=>3887, +36686=>3888, +37066=>3889, +39171=>3890, +39509=>3891, +39851=>3892, +19992=>3893, +20037=>3894, +20061=>3895, +20167=>3896, +20465=>3897, +20855=>3898, +21246=>3899, +21312=>3900, +12061=>3901, +21475=>3901, +21477=>3902, +63750=>3902, +21646=>3903, +22036=>3904, +22389=>3905, +22434=>3906, +23495=>3907, +23943=>3908, +24272=>3909, +25084=>3910, +25304=>3911, +25937=>3912, +26552=>3913, +26601=>3914, +27083=>3915, +27472=>3916, +27590=>3917, +27628=>3918, +27714=>3919, +28317=>3920, +28792=>3921, +29399=>3922, +29590=>3923, +29699=>3924, +30655=>3925, +30697=>3926, +31350=>3927, +32127=>3928, +32777=>3929, +12165=>3930, +33276=>3930, +33285=>3931, +33290=>3932, +33503=>3933, +34914=>3934, +35635=>3935, +36092=>3936, +36544=>3937, +36881=>3938, +37041=>3939, +37476=>3940, +37558=>3941, +39378=>3942, +39493=>3943, +40169=>3944, +40407=>3945, +12244=>3946, +40860=>3946, +63751=>3946, +63752=>3946, +22283=>3947, +23616=>3948, +33738=>3949, +38816=>3950, +38827=>3951, +40628=>3952, +21531=>3953, +31384=>3954, +32676=>3955, +35033=>3956, +36557=>3957, +37089=>3958, +22528=>3959, +23624=>3960, +25496=>3961, +31391=>3962, +23470=>3963, +12088=>3964, +24339=>3964, +31353=>3965, +31406=>3966, +33422=>3967, +36524=>3968, +20518=>3969, +21048=>3970, +21240=>3971, +21367=>3972, +22280=>3973, +25331=>3974, +25458=>3975, +27402=>3976, +28099=>3977, +30519=>3978, +21413=>3979, +29527=>3980, +34152=>3981, +36470=>3982, +38357=>3983, +26426=>3984, +27331=>3985, +28528=>3986, +35437=>3987, +36556=>3988, +39243=>3989, +26231=>3990, +27512=>3991, +36020=>3992, +12225=>3993, +39740=>3993, +21483=>3994, +22317=>3995, +22862=>3996, +25542=>3997, +27131=>3998, +29674=>3999, +30789=>4000, +31418=>4001, +31429=>4002, +31998=>4003, +33909=>4004, +35215=>4005, +36211=>4006, +36917=>4007, +38312=>4008, +21243=>4009, +22343=>4010, +30023=>4011, +31584=>4012, +33740=>4013, +37406=>4014, +27224=>4015, +20811=>4016, +21067=>4017, +21127=>4018, +25119=>4019, +26840=>4020, +26997=>4021, +38553=>4022, +20677=>4023, +21156=>4024, +21220=>4025, +25027=>4026, +12100=>4027, +26020=>4027, +26681=>4028, +27135=>4029, +29822=>4030, +31563=>4031, +33465=>4032, +33771=>4033, +35250=>4034, +35641=>4035, +36817=>4036, +39241=>4037, +20170=>4038, +22935=>4039, +25810=>4040, +26129=>4041, +27278=>4042, +29748=>4043, +31105=>4044, +31165=>4045, +33449=>4046, +34942=>4047, +34943=>4048, +35167=>4049, +37670=>4050, +20235=>4051, +21450=>4052, +24613=>4053, +25201=>4054, +27762=>4055, +32026=>4056, +32102=>4057, +20120=>4058, +20834=>4059, +30684=>4060, +32943=>4061, +20225=>4062, +20238=>4063, +20854=>4064, +20864=>4065, +21980=>4066, +22120=>4067, +22331=>4068, +22522=>4069, +22524=>4070, +22804=>4071, +22855=>4072, +22931=>4073, +23492=>4074, +23696=>4075, +23822=>4076, +12080=>4077, +24049=>4077, +24190=>4078, +24524=>4079, +25216=>4080, +26071=>4081, +26083=>4082, +26398=>4083, +26399=>4084, +26462=>4085, +26827=>4086, +26820=>4087, +27231=>4088, +27450=>4089, +27683=>4090, +27773=>4091, +27778=>4092, +28103=>4093, +29592=>4094, +29734=>4095, +29738=>4096, +29826=>4097, +29859=>4098, +30072=>4099, +30079=>4100, +30849=>4101, +30959=>4102, +31041=>4103, +31047=>4104, +31048=>4105, +31098=>4106, +31637=>4107, +32000=>4108, +32186=>4109, +32648=>4110, +32774=>4111, +32813=>4112, +32908=>4113, +35352=>4114, +35663=>4115, +35912=>4116, +63744=>4116, +36215=>4117, +37665=>4118, +37668=>4119, +39138=>4120, +39249=>4121, +39438=>4122, +39439=>4123, +39525=>4124, +40594=>4125, +32202=>4126, +20342=>4127, +21513=>4128, +25326=>4129, +26708=>4130, +12198=>4131, +37329=>4131, +63754=>4131, +21931=>4132, +20794=>4133, +23068=>4134, +25062=>4135, +25295=>4136, +63835=>4136, +25343=>4137, +37027=>4138, +35582=>4139, +63837=>4139, +26262=>4140, +29014=>4141, +38627=>4142, +25423=>4143, +25466=>4144, +21335=>4145, +26511=>4146, +26976=>4147, +28275=>4148, +30007=>4149, +32013=>4150, +34930=>4151, +22218=>4152, +23064=>4153, +20035=>4154, +20839=>4155, +22856=>4156, +63756=>4156, +26608=>4157, +32784=>4158, +12069=>4159, +22899=>4159, +63873=>4159, +24180=>4160, +63886=>4160, +25754=>4161, +63889=>4161, +31178=>4162, +63893=>4162, +24565=>4163, +63907=>4163, +24684=>4164, +25288=>4165, +25467=>4166, +63908=>4166, +23527=>4167, +63839=>4167, +63914=>4167, +23511=>4168, +21162=>4169, +22900=>4170, +24361=>4171, +24594=>4172, +63840=>4172, +29785=>4173, +39377=>4174, +28611=>4175, +33215=>4176, +36786=>4177, +24817=>4178, +33126=>4179, +23615=>4180, +63933=>4180, +23273=>4181, +35365=>4182, +26491=>4183, +63944=>4183, +32016=>4184, +63951=>4184, +33021=>4185, +23612=>4186, +27877=>4187, +63971=>4187, +21311=>4188, +63979=>4188, +28346=>4189, +63980=>4189, +22810=>4190, +33590=>4191, +63998=>4191, +20025=>4192, +63838=>4192, +20150=>4193, +20294=>4194, +21934=>4195, +22296=>4196, +22727=>4197, +24406=>4198, +26039=>4199, +26086=>4200, +27264=>4201, +27573=>4202, +28237=>4203, +30701=>4204, +31471=>4205, +31774=>4206, +32222=>4207, +34507=>4208, +34962=>4209, +37170=>4210, +37723=>4211, +25787=>4212, +28606=>4213, +29562=>4214, +30136=>4215, +36948=>4216, +21846=>4217, +22349=>4218, +25018=>4219, +25812=>4220, +26311=>4221, +28129=>4222, +28251=>4223, +28525=>4224, +28601=>4225, +30192=>4226, +32835=>4227, +33213=>4228, +34113=>4229, +35203=>4230, +35527=>4231, +35674=>4232, +37663=>4233, +27795=>4234, +30035=>4235, +31572=>4236, +36367=>4237, +36957=>4238, +21776=>4239, +22530=>4240, +22616=>4241, +24162=>4242, +25095=>4243, +25758=>4244, +26848=>4245, +30070=>4246, +31958=>4247, +64003=>4247, +34739=>4248, +40680=>4249, +20195=>4250, +22408=>4251, +22382=>4252, +12068=>4253, +22823=>4253, +23565=>4254, +23729=>4255, +24118=>4256, +24453=>4257, +25140=>4258, +25825=>4259, +29619=>4260, +33274=>4261, +34955=>4262, +36024=>4263, +38538=>4264, +40667=>4265, +23429=>4266, +64004=>4266, +24503=>4267, +24755=>4268, +20498=>4269, +12049=>4270, +20992=>4270, +21040=>4271, +22294=>4272, +22581=>4273, +22615=>4274, +23566=>4275, +23648=>4276, +23798=>4277, +23947=>4278, +24230=>4279, +64001=>4279, +24466=>4280, +24764=>4281, +25361=>4282, +25481=>4283, +25623=>4284, +26691=>4285, +26873=>4286, +27330=>4287, +28120=>4288, +28193=>4289, +28372=>4290, +28644=>4291, +29182=>4292, +30428=>4293, +30585=>4294, +31153=>4295, +31291=>4296, +33796=>4297, +35241=>4298, +36077=>4299, +36339=>4300, +36424=>4301, +36867=>4302, +36884=>4303, +36947=>4304, +37117=>4305, +37709=>4306, +38518=>4307, +38876=>4308, +27602=>4309, +28678=>4310, +29272=>4311, +29346=>4312, +29544=>4313, +30563=>4314, +31167=>4315, +31716=>4316, +32411=>4317, +35712=>4318, +63834=>4318, +22697=>4319, +24775=>4320, +25958=>4321, +26109=>4322, +26302=>4323, +27788=>4324, +28958=>4325, +29129=>4326, +35930=>4327, +38931=>4328, +20077=>4329, +31361=>4330, +20189=>4331, +20908=>4332, +20941=>4333, +21205=>4334, +21516=>4335, +24999=>4336, +26481=>4337, +26704=>4338, +26847=>4339, +27934=>4340, +64005=>4340, +28540=>4341, +30140=>4342, +30643=>4343, +31461=>4344, +33012=>4345, +33891=>4346, +37509=>4347, +20828=>4348, +12099=>4349, +26007=>4349, +26460=>4350, +26515=>4351, +30168=>4352, +31431=>4353, +33651=>4354, +12182=>4355, +35910=>4355, +36887=>4356, +38957=>4357, +23663=>4358, +33216=>4359, +33434=>4360, +36929=>4361, +36975=>4362, +37389=>4363, +24471=>4364, +23965=>4365, +27225=>4366, +29128=>4367, +30331=>4368, +31561=>4369, +34276=>4370, +35588=>4371, +37159=>4372, +39472=>4373, +21895=>4374, +63755=>4374, +25078=>4375, +63757=>4375, +30313=>4376, +63758=>4376, +32645=>4377, +63759=>4377, +34367=>4378, +63760=>4378, +34746=>4379, +63761=>4379, +35064=>4380, +63762=>4380, +37007=>4381, +63763=>4381, +27931=>4382, +63765=>4382, +28889=>4383, +63766=>4383, +29662=>4384, +63767=>4384, +32097=>4385, +33853=>4386, +63768=>4386, +37226=>4387, +63769=>4387, +39409=>4388, +63770=>4388, +20098=>4389, +63771=>4389, +21365=>4390, +63772=>4390, +27396=>4391, +63773=>4391, +27410=>4392, +28734=>4393, +29211=>4394, +63774=>4394, +34349=>4395, +63775=>4395, +40478=>4396, +63776=>4396, +21068=>4397, +36771=>4398, +23888=>4399, +63777=>4399, +25829=>4400, +25900=>4401, +27414=>4402, +28651=>4403, +63778=>4403, +31811=>4404, +32412=>4405, +34253=>4406, +63779=>4406, +35172=>4407, +63780=>4407, +35261=>4408, +25289=>4409, +63781=>4409, +33240=>4410, +63782=>4410, +34847=>4411, +63783=>4411, +24266=>4412, +63784=>4412, +26391=>4413, +63785=>4413, +28010=>4414, +63786=>4414, +29436=>4415, +63787=>4415, +29701=>4416, +29807=>4417, +34690=>4418, +37086=>4419, +63788=>4419, +20358=>4420, +63789=>4420, +23821=>4421, +24480=>4422, +33802=>4423, +20919=>4424, +63790=>4424, +25504=>4425, +63861=>4425, +30053=>4426, +63862=>4426, +20142=>4427, +63863=>4427, +20486=>4428, +20841=>4429, +63864=>4429, +20937=>4430, +63865=>4430, +26753=>4431, +63866=>4431, +27153=>4432, +31918=>4433, +31921=>4434, +31975=>4435, +63867=>4435, +33391=>4436, +63868=>4436, +35538=>4437, +63869=>4437, +36635=>4438, +37327=>4439, +63870=>4439, +20406=>4440, +20791=>4441, +21237=>4442, +63871=>4442, +21570=>4443, +63872=>4443, +24300=>4444, +63874=>4444, +24942=>4445, +25150=>4446, +26053=>4447, +63875=>4447, +27354=>4448, +28670=>4449, +63876=>4449, +31018=>4450, +63877=>4450, +34268=>4451, +34851=>4452, +38317=>4453, +63878=>4453, +39522=>4454, +39530=>4455, +63879=>4455, +40599=>4456, +63880=>4456, +40654=>4457, +63881=>4457, +12050=>4458, +21147=>4458, +63882=>4458, +26310=>4459, +63883=>4459, +27511=>4460, +63884=>4460, +28701=>4461, +31019=>4462, +36706=>4463, +63885=>4463, +38722=>4464, +24976=>4465, +63887=>4465, +25088=>4466, +63888=>4466, +25891=>4467, +28451=>4468, +63890=>4468, +29001=>4469, +63891=>4469, +29833=>4470, +63892=>4470, +32244=>4471, +63894=>4471, +32879=>4472, +63895=>4472, +34030=>4473, +63897=>4473, +36646=>4474, +63896=>4474, +36899=>4475, +63898=>4475, +37706=>4476, +63899=>4476, +20925=>4477, +21015=>4478, +63900=>4478, +21155=>4479, +63901=>4479, +27916=>4480, +28872=>4481, +63903=>4481, +35010=>4482, +63904=>4482, +24265=>4483, +63906=>4483, +25986=>4484, +27566=>4485, +63909=>4485, +28610=>4486, +31806=>4487, +63910=>4487, +29557=>4488, +63911=>4488, +20196=>4489, +63912=>4489, +20278=>4490, +22265=>4491, +63913=>4491, +23738=>4492, +23994=>4493, +63915=>4493, +24604=>4494, +63916=>4494, +29618=>4495, +63917=>4495, +31533=>4496, +32666=>4497, +63919=>4497, +32718=>4498, +32838=>4499, +63920=>4499, +36894=>4500, +37428=>4501, +63921=>4501, +38646=>4502, +63922=>4502, +38728=>4503, +63923=>4503, +38936=>4504, +63924=>4504, +40801=>4505, +20363=>4506, +63925=>4506, +28583=>4507, +31150=>4508, +63926=>4508, +37300=>4509, +63927=>4509, +38583=>4510, +63928=>4510, +21214=>4511, +63791=>4511, +25736=>4512, +25796=>4513, +63792=>4513, +27347=>4514, +63793=>4514, +28510=>4515, +28696=>4516, +29200=>4517, +63794=>4517, +30439=>4518, +63795=>4518, +12156=>4519, +32769=>4519, +63796=>4519, +34310=>4520, +63797=>4520, +34396=>4521, +63798=>4521, +36335=>4522, +63799=>4522, +36613=>4523, +38706=>4524, +63800=>4524, +39791=>4525, +63801=>4525, +40442=>4526, +63802=>4526, +12228=>4527, +40565=>4527, +30860=>4528, +63803=>4528, +31103=>4529, +63804=>4529, +32160=>4530, +63805=>4530, +33737=>4531, +63806=>4531, +37636=>4532, +63807=>4532, +12229=>4533, +40575=>4533, +63808=>4533, +40595=>4534, +35542=>4535, +63809=>4535, +22751=>4536, +63810=>4536, +24324=>4537, +63811=>4537, +26407=>4538, +28711=>4539, +29903=>4540, +31840=>4541, +63812=>4541, +32894=>4542, +63813=>4542, +20769=>4543, +28712=>4544, +29282=>4545, +63814=>4545, +30922=>4546, +63815=>4546, +36034=>4547, +63816=>4547, +36058=>4548, +36084=>4549, +38647=>4550, +63817=>4550, +20102=>4551, +63930=>4551, +20698=>4552, +63931=>4552, +23534=>4553, +63932=>4553, +24278=>4554, +26009=>4555, +63934=>4555, +29134=>4556, +63936=>4556, +30274=>4557, +63937=>4557, +30637=>4558, +32842=>4559, +34044=>4560, +63938=>4560, +36988=>4561, +63939=>4561, +39719=>4562, +12243=>4563, +40845=>4563, +63940=>4563, +22744=>4564, +63818=>4564, +23105=>4565, +23650=>4566, +63819=>4566, +27155=>4567, +63820=>4567, +28122=>4568, +63821=>4568, +28431=>4569, +63822=>4569, +30267=>4570, +32047=>4571, +63823=>4571, +32311=>4572, +63824=>4572, +34078=>4573, +35128=>4574, +37860=>4575, +38475=>4576, +63825=>4576, +21129=>4577, +63943=>4577, +26066=>4578, +26611=>4579, +63945=>4579, +27060=>4580, +27969=>4581, +63946=>4581, +28316=>4582, +63947=>4582, +28687=>4583, +29705=>4584, +63948=>4584, +29792=>4585, +30041=>4586, +63949=>4586, +30244=>4587, +30827=>4588, +63950=>4588, +35628=>4589, +39006=>4590, +63952=>4590, +20845=>4591, +63953=>4591, +25134=>4592, +63954=>4592, +38520=>4593, +63955=>4593, +20374=>4594, +20523=>4595, +63956=>4595, +23833=>4596, +63957=>4596, +28138=>4597, +63958=>4597, +32184=>4598, +36650=>4599, +63959=>4599, +24459=>4600, +63960=>4600, +24900=>4601, +63961=>4601, +26647=>4602, +63962=>4602, +38534=>4603, +63964=>4603, +21202=>4604, +63826=>4604, +32907=>4605, +63827=>4605, +20956=>4606, +63828=>4606, +20940=>4607, +63829=>4607, +26974=>4608, +31260=>4609, +63830=>4609, +32190=>4610, +63831=>4610, +33777=>4611, +63832=>4611, +38517=>4612, +63833=>4612, +20442=>4613, +21033=>4614, +63965=>4614, +21400=>4615, +21519=>4616, +63966=>4616, +21774=>4617, +23653=>4618, +63967=>4618, +24743=>4619, +26446=>4620, +63969=>4620, +26792=>4621, +63970=>4621, +28012=>4622, +29313=>4623, +29432=>4624, +29702=>4625, +63972=>4625, +29827=>4626, +30178=>4627, +63973=>4627, +31852=>4628, +32633=>4629, +63974=>4629, +32696=>4630, +33673=>4631, +35023=>4632, +63975=>4632, +35041=>4633, +63976=>4633, +12197=>4634, +37324=>4634, +63977=>4634, +37328=>4635, +38626=>4636, +63978=>4636, +39881=>4637, +21533=>4638, +63981=>4638, +28542=>4639, +29136=>4640, +63982=>4640, +29848=>4641, +63983=>4641, +34298=>4642, +63984=>4642, +36522=>4643, +38563=>4644, +63985=>4644, +40023=>4645, +63986=>4645, +40607=>4646, +63987=>4646, +26519=>4647, +63988=>4647, +28107=>4648, +63989=>4648, +29747=>4649, +33256=>4650, +63990=>4650, +38678=>4651, +30764=>4652, +12148=>4653, +31435=>4653, +63991=>4653, +31520=>4654, +63992=>4654, +31890=>4655, +63993=>4655, +25705=>4656, +29802=>4657, +30194=>4658, +30908=>4659, +30952=>4660, +12218=>4661, +39340=>4661, +39764=>4662, +12231=>4663, +40635=>4663, +23518=>4664, +24149=>4665, +28448=>4666, +33180=>4667, +33707=>4668, +37000=>4669, +19975=>4670, +21325=>4671, +23081=>4672, +24018=>4673, +24398=>4674, +24930=>4675, +25405=>4676, +26217=>4677, +26364=>4678, +28415=>4679, +28459=>4680, +28771=>4681, +30622=>4682, +33836=>4683, +34067=>4684, +34875=>4685, +36627=>4686, +39237=>4687, +39995=>4688, +21788=>4689, +25273=>4690, +26411=>4691, +27819=>4692, +33545=>4693, +35178=>4694, +38778=>4695, +20129=>4696, +22916=>4697, +24536=>4698, +24537=>4699, +26395=>4700, +32178=>4701, +32596=>4702, +33426=>4703, +33579=>4704, +33725=>4705, +36638=>4706, +37017=>4707, +22475=>4708, +22969=>4709, +23186=>4710, +23504=>4711, +26151=>4712, +26522=>4713, +26757=>4714, +27599=>4715, +29028=>4716, +32629=>4717, +36023=>4718, +36067=>4719, +36993=>4720, +39749=>4721, +33032=>4722, +35978=>4723, +38476=>4724, +39488=>4725, +12230=>4726, +40613=>4726, +23391=>4727, +27667=>4728, +29467=>4729, +30450=>4730, +30431=>4731, +33804=>4732, +20906=>4733, +35219=>4734, +20813=>4735, +20885=>4736, +21193=>4737, +26825=>4738, +27796=>4739, +30468=>4740, +30496=>4741, +32191=>4742, +32236=>4743, +12207=>4744, +38754=>4744, +40629=>4745, +28357=>4746, +34065=>4747, +20901=>4748, +21517=>4749, +21629=>4750, +26126=>4751, +26269=>4752, +26919=>4753, +28319=>4754, +12139=>4755, +30399=>4755, +30609=>4756, +33559=>4757, +33986=>4758, +34719=>4759, +37225=>4760, +37528=>4761, +40180=>4762, +34946=>4763, +20398=>4764, +20882=>4765, +21215=>4766, +22982=>4767, +24125=>4768, +24917=>4769, +25720=>4770, +25721=>4771, +26286=>4772, +26576=>4773, +27169=>4774, +27597=>4775, +12113=>4776, +27611=>4776, +29279=>4777, +29281=>4778, +29761=>4779, +30520=>4780, +12141=>4781, +30683=>4781, +32791=>4782, +33468=>4783, +33541=>4784, +35584=>4785, +35624=>4786, +35980=>4787, +12106=>4788, +26408=>4788, +27792=>4789, +29287=>4790, +12140=>4791, +30446=>4791, +30566=>4792, +31302=>4793, +40361=>4794, +27519=>4795, +27794=>4796, +22818=>4797, +26406=>4798, +33945=>4799, +21359=>4800, +22675=>4801, +22937=>4802, +24287=>4803, +25551=>4804, +26164=>4805, +26483=>4806, +28218=>4807, +29483=>4808, +31447=>4809, +33495=>4810, +37672=>4811, +21209=>4812, +24043=>4813, +25006=>4814, +25035=>4815, +25098=>4816, +25287=>4817, +25771=>4818, +12102=>4819, +26080=>4819, +26969=>4820, +27494=>4821, +12111=>4822, +27595=>4822, +28961=>4823, +29687=>4824, +30045=>4825, +32326=>4826, +33310=>4827, +33538=>4828, +34154=>4829, +35491=>4830, +36031=>4831, +38695=>4832, +40289=>4833, +22696=>4834, +40664=>4835, +20497=>4836, +21006=>4837, +21563=>4838, +21839=>4839, +12098=>4840, +25991=>4840, +27766=>4841, +32010=>4842, +32011=>4843, +32862=>4844, +34442=>4845, +12200=>4846, +38272=>4846, +38639=>4847, +21247=>4848, +27797=>4849, +29289=>4850, +21619=>4851, +23194=>4852, +23614=>4853, +23883=>4854, +24396=>4855, +24494=>4856, +26410=>4857, +26806=>4858, +26979=>4859, +28220=>4860, +28228=>4861, +30473=>4862, +12150=>4863, +31859=>4863, +32654=>4864, +34183=>4865, +35598=>4866, +36855=>4867, +38753=>4868, +40692=>4869, +23735=>4870, +24758=>4871, +24845=>4872, +25003=>4873, +25935=>4874, +26107=>4875, +26108=>4876, +27665=>4877, +27887=>4878, +29599=>4879, +29641=>4880, +32225=>4881, +38292=>4882, +23494=>4883, +34588=>4884, +35600=>4885, +21085=>4886, +21338=>4887, +25293=>4888, +25615=>4889, +25778=>4890, +26420=>4891, +27192=>4892, +27850=>4893, +29632=>4894, +29854=>4895, +31636=>4896, +31893=>4897, +32283=>4898, +33162=>4899, +33334=>4900, +34180=>4901, +36843=>4902, +38649=>4903, +39361=>4904, +20276=>4905, +21322=>4906, +21453=>4907, +21467=>4908, +25292=>4909, +25644=>4910, +25856=>4911, +26001=>4912, +27075=>4913, +27886=>4914, +28504=>4915, +29677=>4916, +30036=>4917, +30242=>4918, +30436=>4919, +30460=>4920, +30928=>4921, +30971=>4922, +63844=>4922, +31020=>4923, +32070=>4924, +33324=>4925, +34784=>4926, +36820=>4927, +38930=>4928, +39151=>4929, +21187=>4930, +25300=>4931, +25765=>4932, +28196=>4933, +28497=>4934, +30332=>4935, +36299=>4936, +37297=>4937, +37474=>4938, +39662=>4939, +39747=>4940, +20515=>4941, +20621=>4942, +22346=>4943, +22952=>4944, +23592=>4945, +24135=>4946, +24439=>4947, +25151=>4948, +25918=>4949, +12101=>4950, +26041=>4950, +26049=>4951, +26121=>4952, +26507=>4953, +27036=>4954, +28354=>4955, +30917=>4956, +32033=>4957, +32938=>4958, +33152=>4959, +33323=>4960, +33459=>4961, +33953=>4962, +34444=>4963, +35370=>4964, +35607=>4965, +37030=>4966, +38450=>4967, +40848=>4968, +20493=>4969, +20467=>4970, +22521=>4971, +24472=>4972, +25308=>4973, +25490=>4974, +26479=>4975, +28227=>4976, +28953=>4977, +30403=>4978, +32972=>4979, +32986=>4980, +35060=>4981, +35061=>4982, +35097=>4983, +36064=>4984, +36649=>4985, +37197=>4986, +38506=>4987, +20271=>4988, +20336=>4989, +24091=>4990, +26575=>4991, +26658=>4992, +12137=>4993, +30333=>4993, +30334=>4994, +39748=>4995, +24161=>4996, +27146=>4997, +29033=>4998, +29140=>4999, +30058=>5000, +32321=>5001, +34115=>5002, +34281=>5003, +39132=>5004, +20240=>5005, +31567=>5006, +32624=>5007, +38309=>5008, +20961=>5009, +24070=>5010, +26805=>5011, +27710=>5012, +27726=>5013, +27867=>5014, +29359=>5015, +31684=>5016, +33539=>5017, +27861=>5018, +29754=>5019, +20731=>5020, +21128=>5021, +22721=>5022, +25816=>5023, +27287=>5024, +29863=>5025, +30294=>5026, +30887=>5027, +34327=>5028, +38370=>5029, +38713=>5030, +21342=>5031, +24321=>5032, +35722=>5033, +36776=>5034, +36783=>5035, +37002=>5036, +21029=>5037, +30629=>5038, +40009=>5039, +40712=>5040, +19993=>5041, +20482=>5042, +20853=>5043, +23643=>5044, +24183=>5045, +26142=>5046, +26170=>5047, +26564=>5048, +26821=>5049, +28851=>5050, +29953=>5051, +30149=>5052, +31177=>5053, +31453=>5054, +36647=>5055, +39200=>5056, +39432=>5057, +20445=>5058, +22561=>5059, +22577=>5060, +23542=>5061, +26222=>5062, +27493=>5063, +27921=>5064, +28282=>5065, +28541=>5066, +29668=>5067, +29995=>5068, +33769=>5069, +35036=>5070, +35091=>5071, +35676=>5072, +36628=>5073, +20239=>5074, +20693=>5075, +21264=>5076, +12056=>5077, +21340=>5077, +23443=>5078, +24489=>5079, +63846=>5079, +26381=>5080, +31119=>5081, +33145=>5082, +33583=>5083, +34068=>5084, +35079=>5085, +35206=>5086, +36665=>5087, +36667=>5088, +64007=>5088, +39333=>5089, +39954=>5090, +26412=>5091, +20086=>5092, +20472=>5093, +22857=>5094, +23553=>5095, +23791=>5096, +23792=>5097, +25447=>5098, +26834=>5099, +28925=>5100, +29090=>5101, +29739=>5102, +32299=>5103, +34028=>5104, +34562=>5105, +36898=>5106, +37586=>5107, +40179=>5108, +19981=>5109, +63847=>5109, +20184=>5110, +20463=>5111, +20613=>5112, +21078=>5113, +21103=>5114, +21542=>5115, +21648=>5116, +22496=>5117, +22827=>5118, +23142=>5119, +23386=>5120, +23413=>5121, +23500=>5122, +24220=>5123, +25206=>5124, +25975=>5125, +26023=>5126, +28014=>5127, +28325=>5128, +12119=>5129, +29238=>5129, +31526=>5130, +31807=>5131, +12152=>5132, +32566=>5132, +33104=>5133, +33105=>5134, +33178=>5135, +33344=>5136, +33433=>5137, +33705=>5138, +35331=>5139, +36000=>5140, +36070=>5141, +36091=>5142, +36212=>5143, +36282=>5144, +37096=>5145, +37340=>5146, +12201=>5147, +38428=>5147, +38468=>5148, +39385=>5149, +40167=>5150, +21271=>5151, +63843=>5151, +20998=>5152, +21545=>5153, +22132=>5154, +22707=>5155, +22868=>5156, +22894=>5157, +24575=>5158, +24996=>5159, +25198=>5160, +26128=>5161, +27774=>5162, +28954=>5163, +30406=>5164, +31881=>5165, +31966=>5166, +32027=>5167, +33452=>5168, +36033=>5169, +38640=>5170, +20315=>5171, +24343=>5172, +24447=>5173, +25282=>5174, +23849=>5175, +26379=>5176, +26842=>5177, +30844=>5178, +32323=>5179, +40300=>5180, +19989=>5181, +20633=>5182, +12052=>5183, +21269=>5183, +21290=>5184, +21329=>5185, +22915=>5186, +23138=>5187, +24199=>5188, +24754=>5189, +24970=>5190, +25161=>5191, +25209=>5192, +26000=>5193, +26503=>5194, +27047=>5195, +12112=>5196, +27604=>5196, +27606=>5197, +27607=>5198, +27608=>5199, +27832=>5200, +29749=>5201, +30202=>5202, +30738=>5203, +30865=>5204, +31189=>5205, +31192=>5206, +31875=>5207, +32203=>5208, +32737=>5209, +32933=>5210, +33086=>5211, +33218=>5212, +33778=>5213, +34586=>5214, +35048=>5215, +35513=>5216, +35692=>5217, +36027=>5218, +37145=>5219, +12206=>5220, +38750=>5220, +12214=>5221, +39131=>5221, +12240=>5222, +40763=>5222, +22188=>5223, +23338=>5224, +24428=>5225, +25996=>5226, +27315=>5227, +27567=>5228, +27996=>5229, +28657=>5230, +28693=>5231, +29277=>5232, +29613=>5233, +36007=>5234, +36051=>5235, +38971=>5236, +24977=>5237, +27703=>5238, +32856=>5239, +39425=>5240, +20045=>5241, +20107=>5242, +20123=>5243, +20181=>5244, +20282=>5245, +20284=>5246, +20351=>5247, +20447=>5248, +20735=>5249, +21490=>5250, +21496=>5251, +21766=>5252, +21987=>5253, +22235=>5254, +12064=>5255, +22763=>5255, +22882=>5256, +23057=>5257, +23531=>5258, +23546=>5259, +23556=>5260, +24051=>5261, +24107=>5262, +24473=>5263, +24605=>5264, +25448=>5265, +26012=>5266, +26031=>5267, +26614=>5268, +26619=>5269, +26797=>5270, +27515=>5271, +27801=>5272, +27863=>5273, +28195=>5274, +28681=>5275, +29509=>5276, +30722=>5277, +31038=>5278, +31040=>5279, +31072=>5280, +31169=>5281, +31721=>5282, +32023=>5283, +32114=>5284, +32902=>5285, +33293=>5286, +33678=>5287, +34001=>5288, +34503=>5289, +35039=>5290, +35408=>5291, +35422=>5292, +35613=>5293, +36060=>5294, +36198=>5295, +36781=>5296, +37034=>5297, +39164=>5298, +39391=>5299, +40605=>5300, +21066=>5301, +26388=>5302, +20632=>5303, +21034=>5304, +12077=>5305, +23665=>5305, +25955=>5306, +27733=>5307, +29642=>5308, +29987=>5309, +30109=>5310, +31639=>5311, +33948=>5312, +37240=>5313, +38704=>5314, +20087=>5315, +25746=>5316, +27578=>5317, +63856=>5317, +29022=>5318, +34217=>5319, +19977=>5320, +26441=>5321, +26862=>5322, +28183=>5323, +33439=>5324, +34072=>5325, +34923=>5326, +25591=>5327, +28545=>5328, +37394=>5329, +39087=>5330, +19978=>5331, +20663=>5332, +20687=>5333, +20767=>5334, +21830=>5335, +21930=>5336, +22039=>5337, +23360=>5338, +23577=>5339, +23776=>5340, +24120=>5341, +24202=>5342, +24224=>5343, +24258=>5344, +24819=>5345, +26705=>5346, +27233=>5347, +28248=>5348, +29245=>5349, +29248=>5350, +29376=>5351, +63994=>5351, +30456=>5352, +31077=>5353, +31665=>5354, +32724=>5355, +35059=>5356, +35316=>5357, +35443=>5358, +35937=>5359, +36062=>5360, +38684=>5361, +22622=>5362, +63852=>5362, +29885=>5363, +36093=>5364, +21959=>5365, +31329=>5366, +32034=>5367, +63850=>5367, +12170=>5368, +33394=>5368, +29298=>5369, +12131=>5370, +29983=>5370, +29989=>5371, +31513=>5372, +22661=>5373, +22779=>5374, +23996=>5375, +24207=>5376, +24246=>5377, +24464=>5378, +24661=>5379, +25234=>5380, +25471=>5381, +25933=>5382, +26257=>5383, +26329=>5384, +26360=>5385, +26646=>5386, +26866=>5387, +29312=>5388, +29790=>5389, +31598=>5390, +32110=>5391, +32214=>5392, +32626=>5393, +32997=>5394, +33298=>5395, +34223=>5396, +35199=>5397, +35475=>5398, +36893=>5399, +37604=>5400, +12233=>5401, +40653=>5401, +12239=>5402, +40736=>5402, +12067=>5403, +22805=>5403, +22893=>5404, +24109=>5405, +24796=>5406, +26132=>5407, +26227=>5408, +26512=>5409, +27728=>5410, +28101=>5411, +28511=>5412, +12143=>5413, +30707=>5413, +30889=>5414, +33990=>5415, +37323=>5416, +37675=>5417, +20185=>5418, +20682=>5419, +20808=>5420, +21892=>5421, +23307=>5422, +23459=>5423, +25159=>5424, +25982=>5425, +26059=>5426, +28210=>5427, +29053=>5428, +29697=>5429, +29764=>5430, +29831=>5431, +29887=>5432, +30316=>5433, +31146=>5434, +32218=>5435, +32341=>5436, +32680=>5437, +33146=>5438, +33203=>5439, +33337=>5440, +34330=>5441, +34796=>5442, +35445=>5443, +36323=>5444, +36984=>5445, +37521=>5446, +37925=>5447, +39245=>5448, +39854=>5449, +21352=>5450, +23633=>5451, +26964=>5452, +27844=>5453, +27945=>5454, +28203=>5455, +12166=>5456, +33292=>5456, +34203=>5457, +35131=>5458, +35373=>5459, +35498=>5460, +63855=>5460, +63905=>5460, +38634=>5461, +40807=>5462, +21089=>5463, +26297=>5464, +27570=>5465, +32406=>5466, +34814=>5467, +36109=>5468, +38275=>5469, +38493=>5470, +25885=>5471, +28041=>5472, +29166=>5473, +22478=>5474, +22995=>5475, +23468=>5476, +24615=>5477, +24826=>5478, +25104=>5479, +26143=>5480, +26207=>5481, +29481=>5482, +29689=>5483, +30427=>5484, +30465=>5485, +63853=>5485, +31596=>5486, +32854=>5487, +32882=>5488, +33125=>5489, +35488=>5490, +37266=>5491, +19990=>5492, +21218=>5493, +27506=>5494, +27927=>5495, +31237=>5496, +31545=>5497, +32048=>5498, +36016=>5499, +21484=>5500, +22063=>5501, +22609=>5502, +23477=>5503, +12073=>5504, +23567=>5504, +23569=>5505, +24034=>5506, +25152=>5507, +25475=>5508, +25620=>5509, +26157=>5510, +26803=>5511, +27836=>5512, +28040=>5513, +28335=>5514, +28703=>5515, +28836=>5516, +29138=>5517, +29990=>5518, +30095=>5519, +30094=>5520, +30233=>5521, +31505=>5522, +31712=>5523, +31787=>5524, +32032=>5525, +32057=>5526, +34092=>5527, +34157=>5528, +34311=>5529, +35380=>5530, +36877=>5531, +36961=>5532, +37045=>5533, +37559=>5534, +38902=>5535, +39479=>5536, +20439=>5537, +23660=>5538, +26463=>5539, +28049=>5540, +31903=>5541, +32396=>5542, +35606=>5543, +36118=>5544, +36895=>5545, +23403=>5546, +24061=>5547, +25613=>5548, +33984=>5549, +36956=>5550, +39137=>5551, +29575=>5552, +63841=>5552, +63963=>5552, +23435=>5553, +24730=>5554, +26494=>5555, +28126=>5556, +35359=>5557, +35494=>5558, +36865=>5559, +38924=>5560, +21047=>5561, +28753=>5562, +30862=>5563, +37782=>5564, +34928=>5565, +37335=>5566, +20462=>5567, +21463=>5568, +22013=>5569, +22234=>5570, +22402=>5571, +22781=>5572, +23234=>5573, +23432=>5574, +23723=>5575, +23744=>5576, +24101=>5577, +24833=>5578, +25101=>5579, +12095=>5580, +25163=>5580, +25480=>5581, +25628=>5582, +25910=>5583, +25976=>5584, +63849=>5584, +27193=>5585, +27530=>5586, +12116=>5587, +27700=>5587, +27929=>5588, +28465=>5589, +29159=>5590, +29417=>5591, +29560=>5592, +29703=>5593, +29874=>5594, +30246=>5595, +30561=>5596, +31168=>5597, +31319=>5598, +31466=>5599, +31929=>5600, +32143=>5601, +32172=>5602, +32353=>5603, +32670=>5604, +33065=>5605, +33585=>5606, +33936=>5607, +34010=>5608, +34282=>5609, +34966=>5610, +35504=>5611, +35728=>5612, +36664=>5613, +36930=>5614, +36995=>5615, +37228=>5616, +37526=>5617, +37561=>5618, +38539=>5619, +38567=>5620, +38568=>5621, +38614=>5622, +38656=>5623, +38920=>5624, +12216=>5625, +39318=>5625, +39635=>5626, +39706=>5627, +21460=>5628, +22654=>5629, +22809=>5630, +23408=>5631, +23487=>5632, +28113=>5633, +28506=>5634, +29087=>5635, +29729=>5636, +29881=>5637, +32901=>5638, +33789=>5639, +24033=>5640, +24455=>5641, +24490=>5642, +24642=>5643, +26092=>5644, +26642=>5645, +26991=>5646, +27219=>5647, +27529=>5648, +27957=>5649, +28147=>5650, +29667=>5651, +30462=>5652, +30636=>5653, +31565=>5654, +32020=>5655, +33059=>5656, +33308=>5657, +33600=>5658, +34036=>5659, +34147=>5660, +35426=>5661, +35524=>5662, +37255=>5663, +37662=>5664, +38918=>5665, +39348=>5666, +25100=>5667, +34899=>5668, +36848=>5669, +37477=>5670, +23815=>5671, +23847=>5672, +23913=>5673, +29791=>5674, +33181=>5675, +34664=>5676, +28629=>5677, +25342=>5678, +63859=>5678, +32722=>5679, +35126=>5680, +35186=>5681, +19998=>5682, +20056=>5683, +20711=>5684, +21213=>5685, +21319=>5686, +25215=>5687, +26119=>5688, +32361=>5689, +34821=>5690, +38494=>5691, +20365=>5692, +21273=>5693, +22070=>5694, +22987=>5695, +23204=>5696, +12075=>5697, +23608=>5697, +23630=>5698, +23629=>5699, +24066=>5700, +24337=>5701, +24643=>5702, +26045=>5703, +26159=>5704, +26178=>5705, +26558=>5706, +26612=>5707, +29468=>5708, +12142=>5709, +30690=>5709, +12144=>5710, +31034=>5710, +32709=>5711, +33940=>5712, +33997=>5713, +35222=>5714, +35430=>5715, +35433=>5716, +35553=>5717, +12183=>5718, +35925=>5718, +35962=>5719, +22516=>5720, +23508=>5721, +24335=>5722, +24687=>5723, +25325=>5724, +26893=>5725, +27542=>5726, +28252=>5727, +29060=>5728, +31698=>5729, +34645=>5730, +35672=>5731, +63996=>5731, +36606=>5732, +12215=>5733, +39135=>5733, +39166=>5734, +20280=>5735, +20353=>5736, +20449=>5737, +21627=>5738, +23072=>5739, +23480=>5740, +24892=>5741, +26032=>5742, +26216=>5743, +29180=>5744, +30003=>5745, +31070=>5746, +32051=>5747, +33102=>5748, +12162=>5749, +33251=>5749, +33688=>5750, +34218=>5751, +34254=>5752, +34563=>5753, +35338=>5754, +12189=>5755, +36523=>5755, +12191=>5756, +36763=>5756, +36805=>5757, +22833=>5758, +23460=>5759, +23526=>5760, +24713=>5761, +23529=>5762, +23563=>5763, +12092=>5764, +24515=>5764, +27777=>5765, +28145=>5766, +28683=>5767, +29978=>5768, +33455=>5769, +35574=>5770, +20160=>5771, +63997=>5771, +12055=>5772, +21313=>5772, +38617=>5773, +12114=>5774, +27663=>5774, +20126=>5775, +20420=>5776, +20818=>5777, +21854=>5778, +23077=>5779, +23784=>5780, +25105=>5781, +12123=>5782, +29273=>5782, +33469=>5783, +33706=>5784, +34558=>5785, +34905=>5786, +35357=>5787, +38463=>5788, +38597=>5789, +39187=>5790, +40201=>5791, +40285=>5792, +22538=>5793, +23731=>5794, +23997=>5795, +24132=>5796, +24801=>5797, +63929=>5797, +24853=>5798, +25569=>5799, +27138=>5800, +63764=>5800, +63836=>5800, +63935=>5800, +28197=>5801, +37122=>5802, +37716=>5803, +38990=>5804, +39952=>5805, +40823=>5806, +23433=>5807, +23736=>5808, +25353=>5809, +26191=>5810, +26696=>5811, +30524=>5812, +38593=>5813, +38797=>5814, +38996=>5815, +39839=>5816, +26017=>5817, +35585=>5818, +36555=>5819, +38332=>5820, +21813=>5821, +23721=>5822, +24022=>5823, +24245=>5824, +26263=>5825, +30284=>5826, +33780=>5827, +38343=>5828, +22739=>5829, +25276=>5830, +29390=>5831, +40232=>5832, +20208=>5833, +22830=>5834, +24591=>5835, +26171=>5836, +27523=>5837, +31207=>5838, +40230=>5839, +21395=>5840, +21696=>5841, +22467=>5842, +23830=>5843, +24859=>5844, +26326=>5845, +28079=>5846, +30861=>5847, +33406=>5848, +38552=>5849, +38724=>5850, +21380=>5851, +25212=>5852, +25494=>5853, +28082=>5854, +32266=>5855, +33099=>5856, +38989=>5857, +27387=>5858, +32588=>5859, +40367=>5860, +40474=>5861, +20063=>5862, +20539=>5863, +20918=>5864, +22812=>5865, +24825=>5866, +25590=>5867, +26928=>5868, +29242=>5869, +32822=>5870, +37326=>5871, +24369=>5872, +32004=>5873, +33509=>5874, +63860=>5874, +33903=>5875, +33979=>5876, +34277=>5877, +36493=>5878, +20335=>5879, +22756=>5880, +23363=>5881, +24665=>5882, +25562=>5883, +25880=>5884, +25965=>5885, +26264=>5886, +26954=>5887, +27171=>5888, +27915=>5889, +28673=>5890, +29036=>5891, +30162=>5892, +30221=>5893, +31155=>5894, +31344=>5895, +12154=>5896, +32650=>5896, +35140=>5897, +35731=>5898, +37312=>5899, +38525=>5900, +39178=>5901, +22276=>5902, +24481=>5903, +26044=>5904, +28417=>5905, +30208=>5906, +31142=>5907, +35486=>5908, +39341=>5909, +12226=>5910, +39770=>5910, +40812=>5911, +20740=>5912, +25014=>5913, +25233=>5914, +27277=>5915, +33222=>5916, +20547=>5917, +22576=>5918, +24422=>5919, +28937=>5920, +12180=>5921, +35328=>5921, +35578=>5922, +23420=>5923, +34326=>5924, +20474=>5925, +20796=>5926, +22196=>5927, +22852=>5928, +25513=>5929, +28153=>5930, +23978=>5931, +26989=>5932, +20870=>5933, +20104=>5934, +20313=>5935, +22914=>5936, +27487=>5937, +27741=>5938, +29877=>5939, +30998=>5940, +33287=>5941, +33349=>5942, +33593=>5943, +36671=>5944, +36701=>5945, +39192=>5946, +20134=>5947, +22495=>5948, +24441=>5949, +26131=>5950, +63968=>5950, +30123=>5951, +32377=>5952, +35695=>5953, +36870=>5954, +39515=>5955, +22181=>5956, +22567=>5957, +23032=>5958, +23071=>5959, +23476=>5960, +24310=>5961, +25424=>5962, +25403=>5963, +26941=>5964, +27783=>5965, +27839=>5966, +28046=>5967, +28051=>5968, +28149=>5969, +28436=>5970, +28895=>5971, +28982=>5972, +29017=>5973, +29123=>5974, +29141=>5975, +30799=>5976, +30831=>5977, +31605=>5978, +32227=>5979, +32303=>5980, +34893=>5981, +36575=>5982, +37467=>5983, +40182=>5984, +24709=>5985, +28037=>5986, +29105=>5987, +38321=>5988, +21421=>5989, +26579=>5990, +28814=>5991, +28976=>5992, +29744=>5993, +33398=>5994, +33490=>5995, +38331=>5996, +39653=>5997, +40573=>5998, +26308=>5999, +29121=>6000, +33865=>6001, +63854=>6001, +22603=>6002, +23992=>6003, +24433=>6004, +26144=>6005, +26254=>6006, +27001=>6007, +27054=>6008, +27704=>6009, +27891=>6010, +28214=>6011, +28481=>6012, +28634=>6013, +28699=>6014, +28719=>6015, +29008=>6016, +29151=>6017, +29552=>6018, +29787=>6019, +29908=>6020, +30408=>6021, +31310=>6022, +32403=>6023, +33521=>6024, +35424=>6025, +36814=>6026, +37704=>6027, +38681=>6028, +20034=>6029, +20522=>6030, +21000=>6031, +21473=>6032, +26355=>6033, +27757=>6034, +28618=>6035, +29450=>6036, +30591=>6037, +31330=>6038, +33454=>6039, +34269=>6040, +34306=>6041, +35028=>6042, +35427=>6043, +35709=>6044, +35947=>6045, +37555=>6046, +38675=>6047, +38928=>6048, +20116=>6049, +20237=>6050, +20425=>6051, +20658=>6052, +21320=>6053, +21566=>6054, +21555=>6055, +21978=>6056, +22626=>6057, +22714=>6058, +22887=>6059, +23067=>6060, +23524=>6061, +24735=>6062, +25034=>6063, +25942=>6064, +26111=>6065, +26212=>6066, +26791=>6067, +27738=>6068, +28595=>6069, +28879=>6070, +29100=>6071, +29522=>6072, +31613=>6073, +34568=>6074, +35492=>6075, +39986=>6076, +40711=>6077, +23627=>6078, +27779=>6079, +29508=>6080, +12127=>6081, +29577=>6081, +37434=>6082, +28331=>6083, +29797=>6084, +30239=>6085, +31337=>6086, +32277=>6087, +34314=>6088, +20800=>6089, +22725=>6090, +25793=>6091, +29934=>6092, +29973=>6093, +30320=>6094, +32705=>6095, +37013=>6096, +38605=>6097, +39252=>6098, +28198=>6099, +12129=>6100, +29926=>6100, +31401=>6101, +31402=>6102, +33253=>6103, +34521=>6104, +34680=>6105, +35355=>6106, +23113=>6107, +23436=>6108, +23451=>6109, +26785=>6110, +26880=>6111, +28003=>6112, +29609=>6113, +29715=>6114, +29740=>6115, +30871=>6116, +32233=>6117, +32747=>6118, +33048=>6119, +33109=>6120, +33694=>6121, +35916=>6122, +38446=>6123, +63942=>6123, +38929=>6124, +12104=>6125, +26352=>6125, +24448=>6126, +26106=>6127, +26505=>6128, +27754=>6129, +29579=>6130, +20525=>6131, +23043=>6132, +27498=>6133, +30702=>6134, +22806=>6135, +23916=>6136, +24013=>6137, +29477=>6138, +30031=>6139, +20709=>6140, +20985=>6141, +22575=>6142, +22829=>6143, +22934=>6144, +23002=>6145, +23525=>6146, +23970=>6147, +25303=>6148, +25622=>6149, +25747=>6150, +25854=>6151, +26332=>6152, +27208=>6153, +29183=>6154, +29796=>6155, +31368=>6156, +31407=>6157, +32327=>6158, +32350=>6159, +32768=>6160, +33136=>6161, +34799=>6162, +35201=>6163, +35616=>6164, +36953=>6165, +36992=>6166, +39250=>6167, +24958=>6168, +27442=>6169, +28020=>6170, +32287=>6171, +35109=>6172, +36785=>6173, +20433=>6174, +20653=>6175, +20887=>6176, +21191=>6177, +22471=>6178, +22665=>6179, +23481=>6180, +24248=>6181, +24898=>6182, +27029=>6183, +28044=>6184, +28263=>6185, +28342=>6186, +29076=>6187, +29794=>6188, +12132=>6189, +29992=>6189, +29996=>6190, +32883=>6191, +33592=>6192, +33993=>6193, +36362=>6194, +37780=>6195, +37854=>6196, +20110=>6197, +20305=>6198, +20598=>6199, +20778=>6200, +12060=>6201, +21448=>6201, +21451=>6202, +21491=>6203, +23431=>6204, +23507=>6205, +23588=>6206, +24858=>6207, +24962=>6208, +26100=>6209, +12124=>6210, +29275=>6210, +29591=>6211, +29760=>6212, +30402=>6213, +31056=>6214, +31121=>6215, +31161=>6216, +32006=>6217, +12155=>6218, +32701=>6218, +33419=>6219, +34261=>6220, +34398=>6221, +36802=>6222, +36935=>6223, +37109=>6224, +37354=>6225, +38533=>6226, +12204=>6227, +38632=>6227, +38633=>6228, +21206=>6229, +24423=>6230, +26093=>6231, +26161=>6232, +26671=>6233, +29020=>6234, +31286=>6235, +37057=>6236, +38922=>6237, +20113=>6238, +27218=>6239, +27550=>6240, +28560=>6241, +29065=>6242, +32792=>6243, +33464=>6244, +34131=>6245, +36939=>6246, +38549=>6247, +38642=>6248, +38907=>6249, +34074=>6250, +39729=>6251, +20112=>6252, +29066=>6253, +38596=>6254, +20803=>6255, +21407=>6256, +21729=>6257, +22291=>6258, +22290=>6259, +22435=>6260, +23195=>6261, +23236=>6262, +23491=>6263, +24616=>6264, +24895=>6265, +25588=>6266, +27781=>6267, +27961=>6268, +28274=>6269, +28304=>6270, +29232=>6271, +29503=>6272, +29783=>6273, +33489=>6274, +34945=>6275, +36677=>6276, +36960=>6277, +38498=>6278, +39000=>6279, +40219=>6280, +12105=>6281, +26376=>6281, +36234=>6282, +37470=>6283, +20301=>6284, +20553=>6285, +20702=>6286, +21361=>6287, +22285=>6288, +22996=>6289, +23041=>6290, +23561=>6291, +24944=>6292, +26256=>6293, +28205=>6294, +29234=>6295, +29771=>6296, +32239=>6297, +32963=>6298, +33806=>6299, +33894=>6300, +34111=>6301, +34655=>6302, +34907=>6303, +35096=>6304, +35586=>6305, +36949=>6306, +12209=>6307, +38859=>6307, +39759=>6308, +20083=>6309, +20369=>6310, +20754=>6311, +20842=>6312, +21807=>6313, +21929=>6314, +23418=>6315, +23461=>6316, +24188=>6317, +24189=>6318, +24254=>6319, +24736=>6320, +24799=>6321, +24840=>6322, +24841=>6323, +25540=>6324, +25912=>6325, +26377=>6326, +26580=>6327, +26586=>6328, +26977=>6329, +26978=>6330, +27833=>6331, +27943=>6332, +28216=>6333, +28641=>6334, +29494=>6335, +29495=>6336, +29788=>6337, +30001=>6338, +30290=>6339, +32173=>6340, +33278=>6341, +33848=>6342, +35029=>6343, +35480=>6344, +35547=>6345, +35565=>6346, +36400=>6347, +36418=>6348, +36938=>6349, +36926=>6350, +36986=>6351, +12195=>6352, +37193=>6352, +37321=>6353, +37742=>6354, +22537=>6355, +27603=>6356, +12161=>6357, +32905=>6357, +32946=>6358, +20801=>6359, +22891=>6360, +23609=>6361, +28516=>6362, +29607=>6363, +32996=>6364, +36103=>6365, +37399=>6366, +38287=>6367, +12160=>6368, +32895=>6368, +25102=>6369, +28700=>6370, +32104=>6371, +34701=>6372, +22432=>6373, +24681=>6374, +24903=>6375, +27575=>6376, +35518=>6377, +37504=>6378, +38577=>6379, +12036=>6380, +20057=>6380, +21535=>6381, +28139=>6382, +34093=>6383, +38512=>6384, +12211=>6385, +38899=>6385, +39150=>6386, +25558=>6387, +27875=>6388, +12194=>6389, +37009=>6389, +20957=>6390, +25033=>6391, +33210=>6392, +40441=>6393, +20381=>6394, +20506=>6395, +20736=>6396, +23452=>6397, +24847=>6398, +25087=>6399, +25836=>6400, +26885=>6401, +27589=>6402, +30097=>6403, +30691=>6404, +32681=>6405, +33380=>6406, +34191=>6407, +34811=>6408, +12176=>6409, +34915=>6409, +35516=>6410, +35696=>6411, +37291=>6412, +12038=>6413, +20108=>6413, +20197=>6414, +20234=>6415, +22839=>6416, +23016=>6417, +24050=>6418, +24347=>6419, +24411=>6420, +24609=>6421, +29246=>6422, +29669=>6423, +30064=>6424, +63842=>6424, +30157=>6425, +31227=>6426, +12157=>6427, +32780=>6427, +12159=>6428, +32819=>6428, +32900=>6429, +33505=>6430, +33617=>6431, +36029=>6432, +36019=>6433, +36999=>6434, +39156=>6435, +39180=>6436, +28727=>6437, +30410=>6438, +32714=>6439, +32716=>6440, +32764=>6441, +35610=>6442, +12040=>6443, +20154=>6443, +20161=>6444, +20995=>6445, +21360=>6446, +21693=>6447, +63902=>6447, +22240=>6448, +23035=>6449, +23493=>6450, +24341=>6451, +24525=>6452, +28270=>6453, +32106=>6454, +33589=>6455, +34451=>6456, +35469=>6457, +38765=>6458, +38775=>6459, +12032=>6460, +19968=>6460, +20314=>6461, +20350=>6462, +22777=>6463, +12103=>6464, +26085=>6464, +28322=>6465, +36920=>6466, +37808=>6467, +39353=>6468, +20219=>6469, +22764=>6470, +22922=>6471, +23001=>6472, +24641=>6473, +31252=>6474, +33615=>6475, +36035=>6476, +12042=>6477, +20837=>6477, +21316=>6478, +20173=>6479, +21097=>6480, +23381=>6481, +33471=>6482, +20180=>6483, +21050=>6484, +63999=>6484, +21672=>6485, +22985=>6486, +23039=>6487, +12070=>6488, +23376=>6488, +23383=>6489, +23388=>6490, +24675=>6491, +24904=>6492, +28363=>6493, +28825=>6494, +63995=>6494, +29038=>6495, +29574=>6496, +29943=>6497, +30133=>6498, +30913=>6499, +32043=>6500, +32773=>6501, +12163=>6502, +33258=>6502, +33576=>6503, +34071=>6504, +34249=>6505, +35566=>6506, +36039=>6507, +38604=>6508, +20316=>6509, +21242=>6510, +22204=>6511, +26027=>6512, +26152=>6513, +28796=>6514, +28856=>6515, +29237=>6516, +32189=>6517, +33421=>6518, +37196=>6519, +38592=>6520, +40306=>6521, +23409=>6522, +26855=>6523, +27544=>6524, +28538=>6525, +30430=>6526, +23697=>6527, +26283=>6528, +28507=>6529, +31668=>6530, +31786=>6531, +34870=>6532, +38620=>6533, +19976=>6534, +20183=>6535, +21280=>6536, +22580=>6537, +22715=>6538, +22767=>6539, +22892=>6540, +23559=>6541, +24115=>6542, +24196=>6543, +24373=>6544, +25484=>6545, +26290=>6546, +26454=>6547, +27167=>6548, +27299=>6549, +27404=>6550, +28479=>6551, +29254=>6552, +29520=>6553, +29835=>6554, +31456=>6555, +31911=>6556, +33144=>6557, +33247=>6558, +33255=>6559, +33674=>6560, +33900=>6561, +34083=>6562, +34196=>6563, +34255=>6564, +35037=>6565, +36115=>6566, +37292=>6567, +12199=>6568, +38263=>6568, +38556=>6569, +20877=>6570, +21705=>6571, +22312=>6572, +23472=>6573, +25165=>6574, +26448=>6575, +26685=>6576, +26771=>6577, +28221=>6578, +28371=>6579, +28797=>6580, +32289=>6581, +35009=>6582, +36001=>6583, +36617=>6584, +40779=>6585, +40782=>6586, +29229=>6587, +31631=>6588, +35533=>6589, +37658=>6590, +20295=>6591, +20302=>6592, +20786=>6593, +21632=>6594, +22992=>6595, +24213=>6596, +25269=>6597, +26485=>6598, +26990=>6599, +27159=>6600, +27822=>6601, +28186=>6602, +29401=>6603, +29482=>6604, +30141=>6605, +31672=>6606, +32053=>6607, +33511=>6608, +33785=>6609, +33879=>6610, +34295=>6611, +35419=>6612, +36015=>6613, +36487=>6614, +36889=>6615, +37048=>6616, +38606=>6617, +40799=>6618, +21219=>6619, +21514=>6620, +23265=>6621, +23490=>6622, +25688=>6623, +25973=>6624, +28404=>6625, +29380=>6626, +30340=>6627, +31309=>6628, +31515=>6629, +31821=>6630, +32318=>6631, +32735=>6632, +33659=>6633, +35627=>6634, +36042=>6635, +12186=>6636, +36196=>6636, +36321=>6637, +36447=>6638, +36842=>6639, +36857=>6640, +36969=>6641, +37841=>6642, +20291=>6643, +20346=>6644, +20659=>6645, +20840=>6646, +20856=>6647, +21069=>6648, +21098=>6649, +22625=>6650, +22652=>6651, +22880=>6652, +23560=>6653, +23637=>6654, +24283=>6655, +24731=>6656, +25136=>6657, +26643=>6658, +27583=>6659, +27656=>6660, +28593=>6661, +29006=>6662, +29728=>6663, +12133=>6664, +30000=>6664, +30008=>6665, +30033=>6666, +30322=>6667, +31564=>6668, +31627=>6669, +31661=>6670, +31686=>6671, +32399=>6672, +35438=>6673, +36670=>6674, +36681=>6675, +37439=>6676, +37523=>6677, +37666=>6678, +37931=>6679, +38651=>6680, +39002=>6681, +39019=>6682, +39198=>6683, +20999=>6684, +64000=>6684, +25130=>6685, +25240=>6686, +27993=>6687, +30308=>6688, +31434=>6689, +31680=>6690, +32118=>6691, +21344=>6692, +23742=>6693, +24215=>6694, +28472=>6695, +28857=>6696, +31896=>6697, +38673=>6698, +39822=>6699, +40670=>6700, +25509=>6701, +25722=>6702, +34678=>6703, +19969=>6704, +20117=>6705, +20141=>6706, +20572=>6707, +20597=>6708, +21576=>6709, +22979=>6710, +23450=>6711, +24128=>6712, +24237=>6713, +24311=>6714, +24449=>6715, +24773=>6716, +25402=>6717, +25919=>6718, +25972=>6719, +26060=>6720, +26230=>6721, +26232=>6722, +26622=>6723, +26984=>6724, +27273=>6725, +27491=>6726, +27712=>6727, +28096=>6728, +28136=>6729, +28191=>6730, +28254=>6731, +28702=>6732, +28833=>6733, +29582=>6734, +29693=>6735, +30010=>6736, +30555=>6737, +30855=>6738, +31118=>6739, +31243=>6740, +31357=>6741, +31934=>6742, +32142=>6743, +33351=>6744, +35330=>6745, +35562=>6746, +35998=>6747, +37165=>6748, +37194=>6749, +37336=>6750, +37478=>6751, +37580=>6752, +37664=>6753, +38662=>6754, +38742=>6755, +38748=>6756, +38914=>6757, +12237=>6758, +40718=>6758, +21046=>6759, +21137=>6760, +21884=>6761, +22564=>6762, +24093=>6763, +24351=>6764, +24716=>6765, +25552=>6766, +26799=>6767, +28639=>6768, +31085=>6769, +31532=>6770, +33229=>6771, +34234=>6772, +35069=>6773, +35576=>6774, +36420=>6775, +37261=>6776, +38500=>6777, +38555=>6778, +38717=>6779, +38988=>6780, +12241=>6781, +40778=>6781, +20430=>6782, +20806=>6783, +20939=>6784, +21161=>6785, +22066=>6786, +24340=>6787, +24427=>6788, +25514=>6789, +25805=>6790, +26089=>6791, +26177=>6792, +26362=>6793, +26361=>6794, +26397=>6795, +26781=>6796, +26839=>6797, +27133=>6798, +28437=>6799, +28526=>6800, +29031=>6801, +29157=>6802, +12118=>6803, +29226=>6803, +29866=>6804, +30522=>6805, +31062=>6806, +31066=>6807, +31199=>6808, +31264=>6809, +31381=>6810, +31895=>6811, +31967=>6812, +32068=>6813, +32368=>6814, +32903=>6815, +34299=>6816, +34468=>6817, +35412=>6818, +35519=>6819, +36249=>6820, +36481=>6821, +36896=>6822, +36973=>6823, +37347=>6824, +38459=>6825, +38613=>6826, +12227=>6827, +40165=>6827, +26063=>6828, +31751=>6829, +12188=>6830, +36275=>6830, +37827=>6831, +23384=>6832, +23562=>6833, +21330=>6834, +25305=>6835, +29469=>6836, +20519=>6837, +23447=>6838, +24478=>6839, +24752=>6840, +24939=>6841, +26837=>6842, +28121=>6843, +29742=>6844, +31278=>6845, +32066=>6846, +32156=>6847, +32305=>6848, +33131=>6849, +36394=>6850, +36405=>6851, +37758=>6852, +37912=>6853, +20304=>6854, +22352=>6855, +24038=>6856, +24231=>6857, +25387=>6858, +32618=>6859, +20027=>6860, +20303=>6861, +20367=>6862, +20570=>6863, +23005=>6864, +32964=>6865, +21610=>6866, +21608=>6867, +22014=>6868, +22863=>6869, +23449=>6870, +24030=>6871, +24282=>6872, +26205=>6873, +26417=>6874, +26609=>6875, +26666=>6876, +27880=>6877, +27954=>6878, +28234=>6879, +28557=>6880, +28855=>6881, +29664=>6882, +30087=>6883, +31820=>6884, +32002=>6885, +32044=>6886, +32162=>6887, +12168=>6888, +33311=>6888, +34523=>6889, +35387=>6890, +35461=>6891, +12187=>6892, +36208=>6892, +36490=>6893, +36659=>6894, +36913=>6895, +37198=>6896, +37202=>6897, +37956=>6898, +39376=>6899, +12149=>6900, +31481=>6900, +31909=>6901, +20426=>6902, +20737=>6903, +20934=>6904, +22472=>6905, +23535=>6906, +23803=>6907, +26201=>6908, +27197=>6909, +27994=>6910, +28310=>6911, +28652=>6912, +28940=>6913, +30063=>6914, +31459=>6915, +34850=>6916, +36897=>6917, +36981=>6918, +38603=>6919, +39423=>6920, +33537=>6921, +20013=>6922, +20210=>6923, +34886=>6924, +37325=>6925, +21373=>6926, +27355=>6927, +26987=>6928, +27713=>6929, +33914=>6930, +22686=>6931, +24974=>6932, +26366=>6933, +25327=>6934, +28893=>6935, +29969=>6936, +30151=>6937, +32338=>6938, +33976=>6939, +35657=>6940, +36104=>6941, +20043=>6942, +21482=>6943, +21675=>6944, +22320=>6945, +22336=>6946, +24535=>6947, +25345=>6948, +25351=>6949, +25711=>6950, +12096=>6951, +25903=>6951, +26088=>6952, +26234=>6953, +26525=>6954, +26547=>6955, +12108=>6956, +27490=>6956, +27744=>6957, +27802=>6958, +28460=>6959, +30693=>6960, +30757=>6961, +31049=>6962, +31063=>6963, +32025=>6964, +32930=>6965, +33026=>6966, +12164=>6967, +33267=>6967, +33437=>6968, +33463=>6969, +34584=>6970, +35468=>6971, +36100=>6972, +36286=>6973, +36978=>6974, +30452=>6975, +31257=>6976, +31287=>6977, +32340=>6978, +32887=>6979, +21767=>6980, +21972=>6981, +22645=>6982, +25391=>6983, +25634=>6984, +26185=>6985, +26187=>6986, +26733=>6987, +27035=>6988, +27524=>6989, +27941=>6990, +28337=>6991, +29645=>6992, +29800=>6993, +29857=>6994, +30043=>6995, +30137=>6996, +30433=>6997, +30494=>6998, +30603=>6999, +31206=>7000, +32265=>7001, +32285=>7002, +33275=>7003, +34095=>7004, +34967=>7005, +35386=>7006, +36049=>7007, +36587=>7008, +12192=>7009, +36784=>7009, +63857=>7009, +36914=>7010, +37805=>7011, +38499=>7012, +38515=>7013, +38663=>7014, +20356=>7015, +21489=>7016, +23018=>7017, +23241=>7018, +24089=>7019, +26702=>7020, +29894=>7021, +30142=>7022, +31209=>7023, +31378=>7024, +33187=>7025, +34541=>7026, +36074=>7027, +36300=>7028, +36845=>7029, +26015=>7030, +26389=>7031, +22519=>7032, +28503=>7033, +32221=>7034, +36655=>7035, +37878=>7036, +38598=>7037, +24501=>7038, +25074=>7039, +28548=>7040, +19988=>7041, +20376=>7042, +20511=>7043, +21449=>7044, +21983=>7045, +23919=>7046, +24046=>7047, +27425=>7048, +27492=>7049, +30923=>7050, +31642=>7051, +36425=>7052, +12190=>7053, +36554=>7053, +63746=>7053, +36974=>7054, +25417=>7055, +25662=>7056, +30528=>7057, +31364=>7058, +37679=>7059, +38015=>7060, +40810=>7061, +25776=>7062, +28591=>7063, +29158=>7064, +29864=>7065, +29914=>7066, +31428=>7067, +31762=>7068, +32386=>7069, +31922=>7070, +32408=>7071, +35738=>7072, +36106=>7073, +38013=>7074, +39184=>7075, +39244=>7076, +21049=>7077, +23519=>7078, +25830=>7079, +26413=>7080, +32046=>7081, +20717=>7082, +21443=>7083, +63851=>7083, +22649=>7084, +24920=>7085, +24921=>7086, +25082=>7087, +26028=>7088, +31449=>7089, +35730=>7090, +35734=>7091, +20489=>7092, +20513=>7093, +21109=>7094, +21809=>7095, +23100=>7096, +24288=>7097, +24432=>7098, +24884=>7099, +25950=>7100, +26124=>7101, +26166=>7102, +26274=>7103, +27085=>7104, +28356=>7105, +28466=>7106, +29462=>7107, +30241=>7108, +31379=>7109, +33081=>7110, +33369=>7111, +33750=>7112, +33980=>7113, +20661=>7114, +22512=>7115, +23488=>7116, +23528=>7117, +24425=>7118, +25505=>7119, +30758=>7120, +32181=>7121, +33756=>7122, +34081=>7123, +37319=>7124, +37365=>7125, +20874=>7126, +26613=>7127, +31574=>7128, +36012=>7129, +20932=>7130, +22971=>7131, +24765=>7132, +34389=>7133, +20508=>7134, +21076=>7135, +23610=>7136, +24957=>7137, +25114=>7138, +25299=>7139, +64002=>7139, +25842=>7140, +26021=>7141, +28364=>7142, +30240=>7143, +33034=>7144, +36448=>7145, +38495=>7146, +38587=>7147, +20191=>7148, +21315=>7149, +21912=>7150, +22825=>7151, +24029=>7152, +25797=>7153, +27849=>7154, +28154=>7155, +29588=>7156, +31359=>7157, +12167=>7158, +33307=>7158, +34214=>7159, +36068=>7160, +36368=>7161, +36983=>7162, +37351=>7163, +38369=>7164, +38433=>7165, +38854=>7166, +20984=>7167, +21746=>7168, +21894=>7169, +24505=>7170, +25764=>7171, +28552=>7172, +32180=>7173, +36639=>7174, +36685=>7175, +37941=>7176, +20681=>7177, +23574=>7178, +27838=>7179, +28155=>7180, +29979=>7181, +30651=>7182, +31805=>7183, +31844=>7184, +35449=>7185, +35522=>7186, +22558=>7187, +22974=>7188, +24086=>7189, +25463=>7190, +29266=>7191, +30090=>7192, +30571=>7193, +35548=>7194, +36028=>7195, +36626=>7196, +24307=>7197, +26228=>7198, +28152=>7199, +32893=>7200, +33729=>7201, +35531=>7202, +12205=>7203, +38737=>7203, +39894=>7204, +21059=>7205, +26367=>7206, +28053=>7207, +28399=>7208, +32224=>7209, +35558=>7210, +36910=>7211, +36958=>7212, +39636=>7213, +21021=>7214, +21119=>7215, +21736=>7216, +24980=>7217, +25220=>7218, +25307=>7219, +26786=>7220, +26898=>7221, +26970=>7222, +27189=>7223, +28818=>7224, +28966=>7225, +30813=>7226, +30977=>7227, +30990=>7228, +31186=>7229, +31245=>7230, +32918=>7231, +12171=>7232, +33400=>7232, +33493=>7233, +33609=>7234, +34121=>7235, +35970=>7236, +36229=>7237, +37218=>7238, +37259=>7239, +37294=>7240, +20419=>7241, +22225=>7242, +29165=>7243, +30679=>7244, +34560=>7245, +35320=>7246, +12072=>7247, +23544=>7247, +24534=>7248, +26449=>7249, +37032=>7250, +21474=>7251, +22618=>7252, +23541=>7253, +24740=>7254, +24961=>7255, +25696=>7256, +32317=>7257, +32880=>7258, +34085=>7259, +37507=>7260, +25774=>7261, +20652=>7262, +23828=>7263, +26368=>7264, +22684=>7265, +25277=>7266, +25512=>7267, +26894=>7268, +27000=>7269, +27166=>7270, +28267=>7271, +30394=>7272, +31179=>7273, +33467=>7274, +33833=>7275, +35535=>7276, +36264=>7277, +36861=>7278, +37138=>7279, +37195=>7280, +37276=>7281, +37648=>7282, +37656=>7283, +37786=>7284, +38619=>7285, +39478=>7286, +39949=>7287, +19985=>7288, +30044=>7289, +31069=>7290, +31482=>7291, +31569=>7292, +31689=>7293, +32302=>7294, +33988=>7295, +36441=>7296, +36468=>7297, +36600=>7298, +36880=>7299, +26149=>7300, +26943=>7301, +29763=>7302, +20986=>7303, +26414=>7304, +40668=>7305, +20805=>7306, +24544=>7307, +27798=>7308, +34802=>7309, +34909=>7310, +34935=>7311, +24756=>7312, +33205=>7313, +33795=>7314, +36101=>7315, +21462=>7316, +21561=>7317, +22068=>7318, +23094=>7319, +23601=>7320, +28810=>7321, +32736=>7322, +32858=>7323, +33030=>7324, +33261=>7325, +36259=>7326, +37257=>7327, +39519=>7328, +40434=>7329, +20596=>7330, +20164=>7331, +21408=>7332, +24827=>7333, +28204=>7334, +23652=>7335, +20360=>7336, +20516=>7337, +21988=>7338, +23769=>7339, +24159=>7340, +24677=>7341, +26772=>7342, +27835=>7343, +28100=>7344, +29118=>7345, +30164=>7346, +30196=>7347, +30305=>7348, +31258=>7349, +31305=>7350, +32199=>7351, +32251=>7352, +32622=>7353, +33268=>7354, +34473=>7355, +36636=>7356, +38601=>7357, +39347=>7358, +12242=>7359, +40786=>7359, +21063=>7360, +21189=>7361, +39149=>7362, +35242=>7363, +19971=>7364, +26578=>7365, +28422=>7366, +20405=>7367, +23522=>7368, +26517=>7369, +27784=>7370, +63858=>7370, +28024=>7371, +29723=>7372, +30759=>7373, +37341=>7374, +37756=>7375, +34756=>7376, +31204=>7377, +31281=>7378, +24555=>7379, +20182=>7380, +21668=>7381, +21822=>7382, +22702=>7383, +22949=>7384, +24816=>7385, +25171=>7386, +25302=>7387, +26422=>7388, +26965=>7389, +33333=>7390, +38464=>7391, +39345=>7392, +39389=>7393, +20524=>7394, +21331=>7395, +21828=>7396, +22396=>7397, +25176=>7398, +25826=>7399, +26219=>7400, +26589=>7401, +28609=>7402, +28655=>7403, +29730=>7404, +29752=>7405, +35351=>7406, +37944=>7407, +21585=>7408, +22022=>7409, +22374=>7410, +24392=>7411, +24986=>7412, +27470=>7413, +28760=>7414, +28845=>7415, +32187=>7416, +35477=>7417, +22890=>7418, +33067=>7419, +25506=>7420, +30472=>7421, +32829=>7422, +36010=>7423, +22612=>7424, +25645=>7425, +27067=>7426, +23445=>7427, +24081=>7428, +28271=>7429, +34153=>7430, +20812=>7431, +21488=>7432, +22826=>7433, +24608=>7434, +24907=>7435, +27526=>7436, +27760=>7437, +27888=>7438, +31518=>7439, +32974=>7440, +33492=>7441, +36294=>7442, +37040=>7443, +39089=>7444, +25799=>7445, +28580=>7446, +25745=>7447, +25860=>7448, +20814=>7449, +21520=>7450, +12063=>7451, +22303=>7451, +35342=>7452, +24927=>7453, +26742=>7454, +30171=>7455, +31570=>7456, +32113=>7457, +36890=>7458, +22534=>7459, +27084=>7460, +33151=>7461, +35114=>7462, +36864=>7463, +38969=>7464, +20600=>7465, +22871=>7466, +22956=>7467, +25237=>7468, +36879=>7469, +39722=>7470, +24925=>7471, +29305=>7472, +38358=>7473, +22369=>7474, +23110=>7475, +24052=>7476, +25226=>7477, +25773=>7478, +25850=>7479, +26487=>7480, +27874=>7481, +27966=>7482, +29228=>7483, +29750=>7484, +30772=>7485, +32631=>7486, +33453=>7487, +36315=>7488, +38935=>7489, +21028=>7490, +22338=>7491, +26495=>7492, +29256=>7493, +29923=>7494, +36009=>7495, +36774=>7496, +37393=>7497, +38442=>7498, +12043=>7499, +20843=>7499, +21485=>7500, +25420=>7501, +20329=>7502, +21764=>7503, +24726=>7504, +25943=>7505, +27803=>7506, +28031=>7507, +29260=>7508, +29437=>7509, +31255=>7510, +35207=>7511, +12185=>7512, +35997=>7512, +24429=>7513, +28558=>7514, +28921=>7515, +33192=>7516, +24846=>7517, +20415=>7518, +63845=>7518, +20559=>7519, +25153=>7520, +12122=>7521, +29255=>7521, +31687=>7522, +32232=>7523, +32745=>7524, +36941=>7525, +38829=>7526, +39449=>7527, +36022=>7528, +22378=>7529, +24179=>7530, +26544=>7531, +33805=>7532, +35413=>7533, +21536=>7534, +23318=>7535, +24163=>7536, +24290=>7537, +24330=>7538, +25987=>7539, +32954=>7540, +34109=>7541, +38281=>7542, +38491=>7543, +20296=>7544, +21253=>7545, +21261=>7546, +21263=>7547, +21638=>7548, +21754=>7549, +22275=>7550, +24067=>7551, +24598=>7552, +25243=>7553, +25265=>7554, +25429=>7555, +27873=>7556, +28006=>7557, +30129=>7558, +30770=>7559, +32990=>7560, +33071=>7561, +33502=>7562, +33889=>7563, +33970=>7564, +34957=>7565, +35090=>7566, +36875=>7567, +37610=>7568, +39165=>7569, +39825=>7570, +24133=>7571, +26292=>7572, +64006=>7572, +26333=>7573, +28689=>7574, +29190=>7575, +20469=>7576, +21117=>7577, +24426=>7578, +24915=>7579, +26451=>7580, +27161=>7581, +28418=>7582, +29922=>7583, +31080=>7584, +34920=>7585, +35961=>7586, +39111=>7587, +39108=>7588, +39491=>7589, +21697=>7590, +31263=>7591, +26963=>7592, +35575=>7593, +35914=>7594, +12213=>7595, +39080=>7595, +39342=>7596, +24444=>7597, +25259=>7598, +30130=>7599, +12138=>7600, +30382=>7600, +34987=>7601, +36991=>7602, +38466=>7603, +21305=>7604, +24380=>7605, +24517=>7606, +27852=>7607, +63848=>7607, +29644=>7608, +30050=>7609, +12134=>7610, +30091=>7610, +31558=>7611, +33534=>7612, +39325=>7613, +20047=>7614, +36924=>7615, +19979=>7616, +20309=>7617, +21414=>7618, +22799=>7619, +24264=>7620, +26160=>7621, +27827=>7622, +29781=>7623, +33655=>7624, +34662=>7625, +36032=>7626, +36944=>7627, +38686=>7628, +39957=>7629, +22737=>7630, +23416=>7631, +34384=>7632, +35604=>7633, +40372=>7634, +23506=>7635, +24680=>7636, +24717=>7637, +26097=>7638, +27735=>7639, +28450=>7640, +28579=>7641, +28698=>7642, +32597=>7643, +32752=>7644, +38289=>7645, +38290=>7646, +38480=>7647, +38867=>7648, +21106=>7649, +36676=>7650, +20989=>7651, +21547=>7652, +21688=>7653, +21859=>7654, +21898=>7655, +27323=>7656, +28085=>7657, +32216=>7658, +33382=>7659, +37532=>7660, +38519=>7661, +40569=>7662, +21512=>7663, +21704=>7664, +30418=>7665, +34532=>7666, +38308=>7667, +38356=>7668, +38492=>7669, +20130=>7670, +20233=>7671, +23022=>7672, +23270=>7673, +24055=>7674, +24658=>7675, +25239=>7676, +26477=>7677, +26689=>7678, +27782=>7679, +28207=>7680, +32568=>7681, +32923=>7682, +33322=>7683, +38917=>7684, +20133=>7685, +20565=>7686, +21683=>7687, +22419=>7688, +22874=>7689, +23401=>7690, +23475=>7691, +25032=>7692, +26999=>7693, +28023=>7694, +28707=>7695, +34809=>7696, +35299=>7697, +35442=>7698, +35559=>7699, +36994=>7700, +39405=>7701, +39608=>7702, +21182=>7703, +26680=>7704, +20502=>7705, +24184=>7706, +26447=>7707, +33607=>7708, +12175=>7709, +34892=>7709, +64008=>7709, +20139=>7710, +21521=>7711, +22190=>7712, +29670=>7713, +37141=>7714, +38911=>7715, +39177=>7716, +39255=>7717, +12217=>7718, +39321=>7718, +22099=>7719, +22687=>7720, +34395=>7721, +35377=>7722, +25010=>7723, +27382=>7724, +29563=>7725, +36562=>7726, +27463=>7727, +38570=>7728, +39511=>7729, +22869=>7730, +29184=>7731, +36203=>7732, +12208=>7733, +38761=>7733, +20436=>7734, +23796=>7735, +24358=>7736, +25080=>7737, +26203=>7738, +27883=>7739, +28843=>7740, +12126=>7741, +29572=>7741, +29625=>7742, +29694=>7743, +30505=>7744, +30541=>7745, +32067=>7746, +32098=>7747, +32291=>7748, +33335=>7749, +34898=>7750, +36066=>7751, +37449=>7752, +39023=>7753, +23377=>7754, +12147=>7755, +31348=>7755, +12174=>7756, +34880=>7756, +12212=>7757, +38913=>7757, +23244=>7758, +20448=>7759, +21332=>7760, +22846=>7761, +23805=>7762, +25406=>7763, +28025=>7764, +29433=>7765, +33029=>7766, +33031=>7767, +33698=>7768, +37583=>7769, +38960=>7770, +20136=>7771, +20804=>7772, +21009=>7773, +22411=>7774, +24418=>7775, +27842=>7776, +28366=>7777, +28677=>7778, +28752=>7779, +28847=>7780, +29074=>7781, +29673=>7782, +29801=>7783, +63918=>7783, +33610=>7784, +34722=>7785, +34913=>7786, +36872=>7787, +37026=>7788, +37795=>7789, +39336=>7790, +20846=>7791, +24407=>7792, +24800=>7793, +24935=>7794, +26291=>7795, +34137=>7796, +36426=>7797, +37295=>7798, +38795=>7799, +20046=>7800, +20114=>7801, +21628=>7802, +22741=>7803, +22778=>7804, +22909=>7805, +23733=>7806, +24359=>7807, +12094=>7808, +25142=>7808, +25160=>7809, +26122=>7810, +26215=>7811, +27627=>7812, +28009=>7813, +28111=>7814, +28246=>7815, +28408=>7816, +28564=>7817, +28640=>7818, +28649=>7819, +28765=>7820, +29392=>7821, +29733=>7822, +29786=>7823, +29920=>7824, +30355=>7825, +31068=>7826, +31946=>7827, +32286=>7828, +32993=>7829, +33446=>7830, +33899=>7831, +33983=>7832, +34382=>7833, +34399=>7834, +34676=>7835, +35703=>7836, +35946=>7837, +37804=>7838, +38912=>7839, +39013=>7840, +24785=>7841, +25110=>7842, +37239=>7843, +23130=>7844, +26127=>7845, +28151=>7846, +28222=>7847, +29759=>7848, +39746=>7849, +24573=>7850, +24794=>7851, +31503=>7852, +21700=>7853, +24344=>7854, +27742=>7855, +27859=>7856, +27946=>7857, +28888=>7858, +32005=>7859, +34425=>7860, +35340=>7861, +40251=>7862, +21270=>7863, +21644=>7864, +23301=>7865, +27194=>7866, +12117=>7867, +28779=>7867, +30069=>7868, +31117=>7869, +12146=>7870, +31166=>7870, +33457=>7871, +33775=>7872, +35441=>7873, +35649=>7874, +36008=>7875, +38772=>7876, +25844=>7877, +25899=>7878, +30906=>7879, +30907=>7880, +31339=>7881, +20024=>7882, +21914=>7883, +22864=>7884, +23462=>7885, +24187=>7886, +24739=>7887, +25563=>7888, +27489=>7889, +26213=>7890, +26707=>7891, +28185=>7892, +29029=>7893, +29872=>7894, +32008=>7895, +36996=>7896, +39529=>7897, +39973=>7898, +27963=>7899, +28369=>7900, +63748=>7900, +29502=>7901, +35905=>7902, +38346=>7903, +20976=>7904, +24140=>7905, +24488=>7906, +24653=>7907, +24822=>7908, +24880=>7909, +24908=>7910, +26179=>7911, +26180=>7912, +27045=>7913, +27841=>7914, +28255=>7915, +28361=>7916, +28514=>7917, +29004=>7918, +29852=>7919, +30343=>7920, +31681=>7921, +31783=>7922, +33618=>7923, +34647=>7924, +36945=>7925, +38541=>7926, +12232=>7927, +40643=>7927, +21295=>7928, +22238=>7929, +24315=>7930, +24458=>7931, +24674=>7932, +24724=>7933, +25079=>7934, +26214=>7935, +26371=>7936, +27292=>7937, +28142=>7938, +28590=>7939, +28784=>7940, +29546=>7941, +32362=>7942, +33214=>7943, +33588=>7944, +34516=>7945, +35496=>7946, +36036=>7947, +21123=>7948, +29554=>7949, +23446=>7950, +27243=>7951, +37892=>7952, +21742=>7953, +22150=>7954, +23389=>7955, +25928=>7956, +25989=>7957, +26313=>7958, +26783=>7959, +28045=>7960, +28102=>7961, +12120=>7962, +29243=>7962, +32948=>7963, +37237=>7964, +39501=>7965, +20399=>7966, +20505=>7967, +21402=>7968, +21518=>7969, +21564=>7970, +21897=>7971, +21957=>7972, +24127=>7973, +24460=>7974, +26429=>7975, +29030=>7976, +29661=>7977, +36869=>7978, +21211=>7979, +21235=>7980, +22628=>7981, +22734=>7982, +28932=>7983, +29071=>7984, +29179=>7985, +34224=>7986, +35347=>7987, +26248=>7988, +63941=>7988, +34216=>7989, +21927=>7990, +26244=>7991, +29002=>7992, +33841=>7993, +21321=>7994, +21913=>7995, +27585=>7996, +24409=>7997, +24509=>7998, +25582=>7999, +26249=>8000, +28999=>8001, +35569=>8002, +36637=>8003, +40638=>8004, +20241=>8005, +25658=>8006, +28875=>8007, +30054=>8008, +34407=>8009, +24676=>8010, +35662=>8011, +40440=>8012, +20807=>8013, +20982=>8014, +21256=>8015, +27958=>8016, +33016=>8017, +12234=>8018, +40657=>8018, +26133=>8019, +27427=>8020, +28824=>8021, +30165=>8022, +21507=>8023, +23673=>8024, +32007=>8025, +35350=>8026, +12107=>8027, +27424=>8027, +27453=>8028, +27462=>8029, +21560=>8030, +24688=>8031, +27965=>8032, +32725=>8033, +33288=>8034, +20694=>8035, +20958=>8036, +21916=>8037, +22123=>8038, +22221=>8039, +23020=>8040, +23305=>8041, +24076=>8042, +24985=>8043, +24984=>8044, +25137=>8045, +26206=>8046, +26342=>8047, +29081=>8048, +29113=>8049, +29114=>8050, +29351=>8051, +31143=>8052, +31232=>8053, +32690=>8054, +35440=>8055, + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +12310=>8219, +12311=>8220, +12312=>8221, +12313=>8222, +8223=>8237, +8219=>8238, +8314=>8239, +8315=>8240, +8316=>8248, +8317=>8250, +8318=>8251, +700=>8275, +8942=>8320, +8759=>8321, +10122=>8342, +10123=>8343, +10124=>8344, +10125=>8345, +10126=>8346, +10127=>8347, +10128=>8348, +10129=>8349, +10130=>8350, +10131=>8351, +9398=>8388, +9399=>8389, +9400=>8390, +9401=>8391, +9402=>8392, +9403=>8393, +9404=>8394, +9405=>8395, +9406=>8396, +9407=>8397, +9408=>8398, +9409=>8399, +9410=>8400, +9411=>8401, +9412=>8402, +9413=>8403, +9414=>8404, +9415=>8405, +9416=>8406, +9417=>8407, +9418=>8408, +9419=>8409, +9420=>8410, +9421=>8411, +9422=>8412, +9423=>8413, +8826=>8475, +8827=>8476, +8910=>8477, +8911=>8478, +8832=>8479, +8833=>8480, +8816=>8481, +8817=>8482, +8818=>8483, +8819=>8484, +8842=>8486, +8843=>8488, +8822=>8489, +8823=>8490, +8825=>8491, +8922=>8492, +8923=>8493, +8773=>8499, +8771=>8500, +8776=>8501, +8868=>8503, +8244=>8582, +9839=>8594, +8258=>8599, +10045=>8604, +8226=>8607, +8249=>8612, +8250=>8613, +10010=>8630, +10006=>8631, +9711=>8633, +10070=>8637, +9676=>8639, +9775=>8664, +12320=>8671, +10102=>8673, +10103=>8674, +10104=>8675, +10105=>8676, +10106=>8677, +10107=>8678, +10108=>8679, +10109=>8680, +10110=>8681, +10111=>8682, +12306=>8700, +12342=>8701, +8710=>8715, +8735=>8717, +8741=>8719, +8742=>8720, +8787=>8722, +8785=>8723, +8806=>8724, +8807=>8725, +8723=>8726, +8853=>8727, +8854=>8728, +8855=>8729, +8980=>8731, +8802=>8734, +9649=>8736, +8738=>8738, +8784=>8739, +8867=>8742, +8814=>8745, +8815=>8746, +8837=>8747, +8836=>8748, +8713=>8749, +8716=>8750, +8891=>8751, +8892=>8752, +8794=>8753, +8966=>8754, +12958=>8761, +8252=>8763, +9702=>8775, +9663=>8779, +9653=>8780, +9657=>8781, +9667=>8782, +9674=>8787, +12849=>8788, +12857=>8789, +13259=>8790, +9327=>8791, +9328=>8792, +9329=>8793, +9330=>8794, +9331=>8795, +8656=>8814, +8655=>8815, +8653=>8816, +8657=>8854, +8659=>8855, +8626=>8864, +8625=>8865, +8628=>8867, +8624=>8868, +8627=>8869, +8636=>8884, +8640=>8885, +8644=>8896, +8645=>8897, +9347=>9042, +9348=>9043, +9349=>9044, +9350=>9045, +9351=>9046, +12948=>9080, +12965=>9096, +8672=>9190, +8674=>9191, +8673=>9192, +8675=>9193, +8678=>9198, +8680=>9199, +8679=>9200, +8681=>9201, +9757=>9222, +9759=>9223, +12944=>9300, +12938=>9301, +12939=>9302, +12940=>9303, +12941=>9304, +12942=>9305, +12943=>9306, +12318=>9322, +12319=>9323, +8246=>9324, +8245=>9326, +12540=>9330, +44034=>9333, +44035=>9334, +44037=>9335, +44038=>9336, +44043=>9337, +44044=>9338, +44045=>9339, +44046=>9340, +44047=>9341, +44056=>9342, +44062=>9343, +44063=>9344, +44065=>9345, +44066=>9346, +44067=>9347, +44069=>9348, +44070=>9349, +44071=>9350, +44072=>9351, +44073=>9352, +44074=>9353, +44075=>9354, +44078=>9355, +44082=>9356, +44083=>9357, +44084=>9358, +44085=>9359, +44086=>9360, +44087=>9361, +44090=>9362, +44091=>9363, +44093=>9364, +44094=>9365, +44095=>9366, +44097=>9367, +44098=>9368, +44099=>9369, +44100=>9370, +44101=>9371, +44102=>9372, +44103=>9373, +44104=>9374, +44105=>9375, +44106=>9376, +44108=>9377, +44110=>9378, +44111=>9379, +44112=>9380, +44113=>9381, +44114=>9382, +44115=>9383, +44117=>9384, +44118=>9385, +44119=>9386, +44121=>9387, +44122=>9388, +44123=>9389, +44125=>9390, +44126=>9391, +44127=>9392, +44128=>9393, +44129=>9394, +44130=>9395, +44131=>9396, +44132=>9397, +44133=>9398, +44134=>9399, +44135=>9400, +44136=>9401, +44137=>9402, +44138=>9403, +44139=>9404, +44140=>9405, +44141=>9406, +44142=>9407, +44143=>9408, +44146=>9409, +44147=>9410, +44149=>9411, +44150=>9412, +44153=>9413, +44155=>9414, +44156=>9415, +44157=>9416, +44158=>9417, +44159=>9418, +44162=>9419, +44167=>9420, +44168=>9421, +44173=>9422, +44174=>9423, +44175=>9424, +44177=>9425, +44178=>9426, +44179=>9427, +44181=>9428, +44182=>9429, +44183=>9430, +44184=>9431, +44185=>9432, +44186=>9433, +44187=>9434, +44190=>9435, +44194=>9436, +44195=>9437, +44196=>9438, +44197=>9439, +44198=>9440, +44199=>9441, +44203=>9442, +44205=>9443, +44206=>9444, +44209=>9445, +44210=>9446, +44211=>9447, +44212=>9448, +44213=>9449, +44214=>9450, +44215=>9451, +44218=>9452, +44222=>9453, +44223=>9454, +44224=>9455, +44226=>9456, +44227=>9457, +44229=>9458, +44230=>9459, +44231=>9460, +44233=>9461, +44234=>9462, +44235=>9463, +44237=>9464, +44238=>9465, +44239=>9466, +44240=>9467, +44241=>9468, +44242=>9469, +44243=>9470, +44244=>9471, +44246=>9472, +44248=>9473, +44249=>9474, +44250=>9475, +44251=>9476, +44252=>9477, +44253=>9478, +44254=>9479, +44255=>9480, +44258=>9481, +44259=>9482, +44261=>9483, +44262=>9484, +44265=>9485, +44267=>9486, +44269=>9487, +44270=>9488, +44274=>9489, +44276=>9490, +44279=>9491, +44280=>9492, +44281=>9493, +44282=>9494, +44283=>9495, +44286=>9496, +44287=>9497, +44289=>9498, +44290=>9499, +44291=>9500, +44293=>9501, +44295=>9502, +44296=>9503, +44297=>9504, +44298=>9505, +44299=>9506, +44302=>9507, +44304=>9508, +44306=>9509, +44307=>9510, +44308=>9511, +44309=>9512, +44310=>9513, +44311=>9514, +44313=>9515, +44314=>9516, +44315=>9517, +44317=>9518, +44318=>9519, +44319=>9520, +44321=>9521, +44322=>9522, +44323=>9523, +44324=>9524, +44325=>9525, +44326=>9526, +44327=>9527, +44328=>9528, +44330=>9529, +44331=>9530, +44334=>9531, +44335=>9532, +44336=>9533, +44337=>9534, +44338=>9535, +44339=>9536, +44342=>9537, +44343=>9538, +44345=>9539, +44346=>9540, +44347=>9541, +44349=>9542, +44350=>9543, +44351=>9544, +44352=>9545, +44353=>9546, +44354=>9547, +44355=>9548, +44358=>9549, +44360=>9550, +44362=>9551, +44363=>9552, +44364=>9553, +44365=>9554, +44366=>9555, +44367=>9556, +44369=>9557, +44370=>9558, +44371=>9559, +44373=>9560, +44374=>9561, +44375=>9562, +44377=>9563, +44378=>9564, +44379=>9565, +44380=>9566, +44381=>9567, +44382=>9568, +44383=>9569, +44384=>9570, +44386=>9571, +44388=>9572, +44389=>9573, +44390=>9574, +44391=>9575, +44392=>9576, +44393=>9577, +44394=>9578, +44395=>9579, +44398=>9580, +44399=>9581, +44401=>9582, +44402=>9583, +44407=>9584, +44408=>9585, +44409=>9586, +44410=>9587, +44414=>9588, +44416=>9589, +44419=>9590, +44420=>9591, +44421=>9592, +44422=>9593, +44423=>9594, +44426=>9595, +44427=>9596, +44429=>9597, +44430=>9598, +44431=>9599, +44433=>9600, +44434=>9601, +44435=>9602, +44436=>9603, +44437=>9604, +44438=>9605, +44439=>9606, +44440=>9607, +44441=>9608, +44442=>9609, +44443=>9610, +44446=>9611, +44447=>9612, +44448=>9613, +44449=>9614, +44450=>9615, +44451=>9616, +44453=>9617, +44454=>9618, +44455=>9619, +44456=>9620, +44457=>9621, +44458=>9622, +44459=>9623, +44460=>9624, +44461=>9625, +44462=>9626, +44463=>9627, +44464=>9628, +44465=>9629, +44466=>9630, +44467=>9631, +44468=>9632, +44469=>9633, +44470=>9634, +44472=>9635, +44473=>9636, +44474=>9637, +44475=>9638, +44476=>9639, +44477=>9640, +44478=>9641, +44479=>9642, +44482=>9643, +44483=>9644, +44485=>9645, +44486=>9646, +44487=>9647, +44489=>9648, +44490=>9649, +44491=>9650, +44492=>9651, +44493=>9652, +44494=>9653, +44495=>9654, +44498=>9655, +44500=>9656, +44501=>9657, +44502=>9658, +44503=>9659, +44504=>9660, +44505=>9661, +44506=>9662, +44507=>9663, +44509=>9664, +44510=>9665, +44511=>9666, +44513=>9667, +44514=>9668, +44515=>9669, +44517=>9670, +44518=>9671, +44519=>9672, +44520=>9673, +44521=>9674, +44522=>9675, +44523=>9676, +44524=>9677, +44525=>9678, +44526=>9679, +44527=>9680, +44528=>9681, +44529=>9682, +44530=>9683, +44531=>9684, +44532=>9685, +44533=>9686, +44534=>9687, +44535=>9688, +44538=>9689, +44539=>9690, +44541=>9691, +44542=>9692, +44546=>9693, +44547=>9694, +44548=>9695, +44549=>9696, +44550=>9697, +44551=>9698, +44554=>9699, +44556=>9700, +44558=>9701, +44559=>9702, +44560=>9703, +44561=>9704, +44562=>9705, +44563=>9706, +44565=>9707, +44566=>9708, +44567=>9709, +44568=>9710, +44569=>9711, +44570=>9712, +44571=>9713, +44572=>9714, +44573=>9715, +44574=>9716, +44575=>9717, +44576=>9718, +44577=>9719, +44578=>9720, +44579=>9721, +44580=>9722, +44581=>9723, +44582=>9724, +44583=>9725, +44584=>9726, +44585=>9727, +44586=>9728, +44587=>9729, +44588=>9730, +44589=>9731, +44590=>9732, +44591=>9733, +44594=>9734, +44595=>9735, +44597=>9736, +44598=>9737, +44601=>9738, +44603=>9739, +44604=>9740, +44605=>9741, +44606=>9742, +44607=>9743, +44610=>9744, +44612=>9745, +44615=>9746, +44616=>9747, +44617=>9748, +44619=>9749, +44623=>9750, +44625=>9751, +44626=>9752, +44627=>9753, +44629=>9754, +44631=>9755, +44632=>9756, +44633=>9757, +44634=>9758, +44635=>9759, +44638=>9760, +44642=>9761, +44643=>9762, +44644=>9763, +44646=>9764, +44647=>9765, +44650=>9766, +44651=>9767, +44653=>9768, +44654=>9769, +44655=>9770, +44657=>9771, +44658=>9772, +44659=>9773, +44660=>9774, +44661=>9775, +44662=>9776, +44663=>9777, +44666=>9778, +44670=>9779, +44671=>9780, +44672=>9781, +44673=>9782, +44674=>9783, +44675=>9784, +44678=>9785, +44679=>9786, +44680=>9787, +44681=>9788, +44682=>9789, +44683=>9790, +44685=>9791, +44686=>9792, +44687=>9793, +44688=>9794, +44689=>9795, +44690=>9796, +44691=>9797, +44692=>9798, +44693=>9799, +44694=>9800, +44695=>9801, +44696=>9802, +44697=>9803, +44698=>9804, +44699=>9805, +44700=>9806, +44701=>9807, +44702=>9808, +44703=>9809, +44704=>9810, +44705=>9811, +44706=>9812, +44707=>9813, +44708=>9814, +44709=>9815, +44710=>9816, +44711=>9817, +44712=>9818, +44713=>9819, +44714=>9820, +44715=>9821, +44716=>9822, +44717=>9823, +44718=>9824, +44719=>9825, +44720=>9826, +44721=>9827, +44722=>9828, +44723=>9829, +44724=>9830, +44725=>9831, +44726=>9832, +44727=>9833, +44728=>9834, +44729=>9835, +44730=>9836, +44731=>9837, +44735=>9838, +44737=>9839, +44738=>9840, +44739=>9841, +44741=>9842, +44742=>9843, +44743=>9844, +44744=>9845, +44745=>9846, +44746=>9847, +44747=>9848, +44750=>9849, +44754=>9850, +44755=>9851, +44756=>9852, +44757=>9853, +44758=>9854, +44759=>9855, +44762=>9856, +44763=>9857, +44765=>9858, +44766=>9859, +44767=>9860, +44768=>9861, +44769=>9862, +44770=>9863, +44771=>9864, +44772=>9865, +44773=>9866, +44774=>9867, +44775=>9868, +44777=>9869, +44778=>9870, +44780=>9871, +44782=>9872, +44783=>9873, +44784=>9874, +44785=>9875, +44786=>9876, +44787=>9877, +44789=>9878, +44790=>9879, +44791=>9880, +44793=>9881, +44794=>9882, +44795=>9883, +44797=>9884, +44798=>9885, +44799=>9886, +44800=>9887, +44801=>9888, +44802=>9889, +44803=>9890, +44804=>9891, +44805=>9892, +44806=>9893, +44809=>9894, +44810=>9895, +44811=>9896, +44812=>9897, +44814=>9898, +44815=>9899, +44817=>9900, +44818=>9901, +44819=>9902, +44820=>9903, +44821=>9904, +44822=>9905, +44823=>9906, +44824=>9907, +44825=>9908, +44826=>9909, +44827=>9910, +44828=>9911, +44829=>9912, +44830=>9913, +44831=>9914, +44832=>9915, +44833=>9916, +44834=>9917, +44835=>9918, +44836=>9919, +44837=>9920, +44838=>9921, +44839=>9922, +44840=>9923, +44841=>9924, +44842=>9925, +44843=>9926, +44846=>9927, +44847=>9928, +44849=>9929, +44851=>9930, +44853=>9931, +44854=>9932, +44855=>9933, +44856=>9934, +44857=>9935, +44858=>9936, +44859=>9937, +44862=>9938, +44864=>9939, +44868=>9940, +44869=>9941, +44870=>9942, +44871=>9943, +44874=>9944, +44875=>9945, +44876=>9946, +44877=>9947, +44878=>9948, +44879=>9949, +44881=>9950, +44882=>9951, +44883=>9952, +44884=>9953, +44885=>9954, +44886=>9955, +44887=>9956, +44888=>9957, +44889=>9958, +44890=>9959, +44891=>9960, +44894=>9961, +44895=>9962, +44896=>9963, +44897=>9964, +44898=>9965, +44899=>9966, +44902=>9967, +44903=>9968, +44904=>9969, +44905=>9970, +44906=>9971, +44907=>9972, +44908=>9973, +44909=>9974, +44910=>9975, +44911=>9976, +44912=>9977, +44913=>9978, +44914=>9979, +44915=>9980, +44916=>9981, +44917=>9982, +44918=>9983, +44919=>9984, +44920=>9985, +44922=>9986, +44923=>9987, +44924=>9988, +44925=>9989, +44926=>9990, +44927=>9991, +44929=>9992, +44930=>9993, +44931=>9994, +44933=>9995, +44934=>9996, +44935=>9997, +44937=>9998, +44938=>9999, +44939=>10000, +44940=>10001, +44941=>10002, +44942=>10003, +44943=>10004, +44946=>10005, +44947=>10006, +44948=>10007, +44950=>10008, +44951=>10009, +44952=>10010, +44953=>10011, +44954=>10012, +44955=>10013, +44957=>10014, +44958=>10015, +44959=>10016, +44960=>10017, +44961=>10018, +44962=>10019, +44963=>10020, +44964=>10021, +44965=>10022, +44966=>10023, +44967=>10024, +44968=>10025, +44969=>10026, +44970=>10027, +44971=>10028, +44972=>10029, +44973=>10030, +44974=>10031, +44975=>10032, +44976=>10033, +44977=>10034, +44978=>10035, +44979=>10036, +44980=>10037, +44981=>10038, +44982=>10039, +44983=>10040, +44986=>10041, +44987=>10042, +44989=>10043, +44990=>10044, +44991=>10045, +44993=>10046, +44994=>10047, +44995=>10048, +44996=>10049, +44997=>10050, +44998=>10051, +45002=>10052, +45004=>10053, +45007=>10054, +45008=>10055, +45009=>10056, +45010=>10057, +45011=>10058, +45013=>10059, +45014=>10060, +45015=>10061, +45016=>10062, +45017=>10063, +45018=>10064, +45019=>10065, +45021=>10066, +45022=>10067, +45023=>10068, +45024=>10069, +45025=>10070, +45026=>10071, +45027=>10072, +45028=>10073, +45029=>10074, +45030=>10075, +45031=>10076, +45034=>10077, +45035=>10078, +45036=>10079, +45037=>10080, +45038=>10081, +45039=>10082, +45042=>10083, +45043=>10084, +45045=>10085, +45046=>10086, +45047=>10087, +45049=>10088, +45050=>10089, +45051=>10090, +45052=>10091, +45053=>10092, +45054=>10093, +45055=>10094, +45058=>10095, +45059=>10096, +45061=>10097, +45062=>10098, +45063=>10099, +45064=>10100, +45065=>10101, +45066=>10102, +45067=>10103, +45069=>10104, +45070=>10105, +45071=>10106, +45073=>10107, +45074=>10108, +45075=>10109, +45077=>10110, +45078=>10111, +45079=>10112, +45080=>10113, +45081=>10114, +45082=>10115, +45083=>10116, +45086=>10117, +45087=>10118, +45088=>10119, +45089=>10120, +45090=>10121, +45091=>10122, +45092=>10123, +45093=>10124, +45094=>10125, +45095=>10126, +45097=>10127, +45098=>10128, +45099=>10129, +45100=>10130, +45101=>10131, +45102=>10132, +45103=>10133, +45104=>10134, +45105=>10135, +45106=>10136, +45107=>10137, +45108=>10138, +45109=>10139, +45110=>10140, +45111=>10141, +45112=>10142, +45113=>10143, +45114=>10144, +45115=>10145, +45116=>10146, +45117=>10147, +45118=>10148, +45119=>10149, +45120=>10150, +45121=>10151, +45122=>10152, +45123=>10153, +45126=>10154, +45127=>10155, +45129=>10156, +45131=>10157, +45133=>10158, +45135=>10159, +45136=>10160, +45137=>10161, +45138=>10162, +45142=>10163, +45144=>10164, +45146=>10165, +45147=>10166, +45148=>10167, +45150=>10168, +45151=>10169, +45152=>10170, +45153=>10171, +45154=>10172, +45155=>10173, +45156=>10174, +45157=>10175, +45158=>10176, +45159=>10177, +45160=>10178, +45161=>10179, +45162=>10180, +45163=>10181, +45164=>10182, +45165=>10183, +45166=>10184, +45167=>10185, +45168=>10186, +45169=>10187, +45170=>10188, +45171=>10189, +45172=>10190, +45173=>10191, +45174=>10192, +45175=>10193, +45176=>10194, +45177=>10195, +45178=>10196, +45179=>10197, +45182=>10198, +45183=>10199, +45185=>10200, +45186=>10201, +45187=>10202, +45189=>10203, +45190=>10204, +45191=>10205, +45192=>10206, +45193=>10207, +45194=>10208, +45195=>10209, +45198=>10210, +45200=>10211, +45202=>10212, +45203=>10213, +45204=>10214, +45205=>10215, +45206=>10216, +45207=>10217, +45211=>10218, +45213=>10219, +45214=>10220, +45219=>10221, +45220=>10222, +45221=>10223, +45222=>10224, +45223=>10225, +45226=>10226, +45232=>10227, +45234=>10228, +45238=>10229, +45239=>10230, +45241=>10231, +45242=>10232, +45243=>10233, +45245=>10234, +45246=>10235, +45247=>10236, +45248=>10237, +45249=>10238, +45250=>10239, +45251=>10240, +45254=>10241, +45258=>10242, +45259=>10243, +45260=>10244, +45261=>10245, +45262=>10246, +45263=>10247, +45266=>10248, +45267=>10249, +45269=>10250, +45270=>10251, +45271=>10252, +45273=>10253, +45274=>10254, +45275=>10255, +45276=>10256, +45277=>10257, +45278=>10258, +45279=>10259, +45281=>10260, +45282=>10261, +45283=>10262, +45284=>10263, +45286=>10264, +45287=>10265, +45288=>10266, +45289=>10267, +45290=>10268, +45291=>10269, +45292=>10270, +45293=>10271, +45294=>10272, +45295=>10273, +45296=>10274, +45297=>10275, +45298=>10276, +45299=>10277, +45300=>10278, +45301=>10279, +45302=>10280, +45303=>10281, +45304=>10282, +45305=>10283, +45306=>10284, +45307=>10285, +45308=>10286, +45309=>10287, +45310=>10288, +45311=>10289, +45312=>10290, +45313=>10291, +45314=>10292, +45315=>10293, +45316=>10294, +45317=>10295, +45318=>10296, +45319=>10297, +45322=>10298, +45325=>10299, +45326=>10300, +45327=>10301, +45329=>10302, +45332=>10303, +45333=>10304, +45334=>10305, +45335=>10306, +45338=>10307, +45342=>10308, +45343=>10309, +45344=>10310, +45345=>10311, +45346=>10312, +45350=>10313, +45351=>10314, +45353=>10315, +45354=>10316, +45355=>10317, +45357=>10318, +45358=>10319, +45359=>10320, +45360=>10321, +45361=>10322, +45362=>10323, +45363=>10324, +45366=>10325, +45370=>10326, +45371=>10327, +45372=>10328, +45373=>10329, +45374=>10330, +45375=>10331, +45378=>10332, +45379=>10333, +45381=>10334, +45382=>10335, +45383=>10336, +45385=>10337, +45386=>10338, +45387=>10339, +45388=>10340, +45389=>10341, +45390=>10342, +45391=>10343, +45394=>10344, +45395=>10345, +45398=>10346, +45399=>10347, +45401=>10348, +45402=>10349, +45403=>10350, +45405=>10351, +45406=>10352, +45407=>10353, +45409=>10354, +45410=>10355, +45411=>10356, +45412=>10357, +45413=>10358, +45414=>10359, +45415=>10360, +45416=>10361, +45417=>10362, +45418=>10363, +45419=>10364, +45420=>10365, +45421=>10366, +45422=>10367, +45423=>10368, +45424=>10369, +45425=>10370, +45426=>10371, +45427=>10372, +45428=>10373, +45429=>10374, +45430=>10375, +45431=>10376, +45434=>10377, +45435=>10378, +45437=>10379, +45438=>10380, +45439=>10381, +45441=>10382, +45443=>10383, +45444=>10384, +45445=>10385, +45446=>10386, +45447=>10387, +45450=>10388, +45452=>10389, +45454=>10390, +45455=>10391, +45456=>10392, +45457=>10393, +45461=>10394, +45462=>10395, +45463=>10396, +45465=>10397, +45466=>10398, +45467=>10399, +45469=>10400, +45470=>10401, +45471=>10402, +45472=>10403, +45473=>10404, +45474=>10405, +45475=>10406, +45476=>10407, +45477=>10408, +45478=>10409, +45479=>10410, +45481=>10411, +45482=>10412, +45483=>10413, +45484=>10414, +45485=>10415, +45486=>10416, +45487=>10417, +45488=>10418, +45489=>10419, +45490=>10420, +45491=>10421, +45492=>10422, +45493=>10423, +45494=>10424, +45495=>10425, +45496=>10426, +45497=>10427, +45498=>10428, +45499=>10429, +45500=>10430, +45501=>10431, +45502=>10432, +45503=>10433, +45504=>10434, +45505=>10435, +45506=>10436, +45507=>10437, +45508=>10438, +45509=>10439, +45510=>10440, +45511=>10441, +45512=>10442, +45513=>10443, +45514=>10444, +45515=>10445, +45517=>10446, +45518=>10447, +45519=>10448, +45521=>10449, +45522=>10450, +45523=>10451, +45525=>10452, +45526=>10453, +45527=>10454, +45528=>10455, +45529=>10456, +45530=>10457, +45531=>10458, +45534=>10459, +45536=>10460, +45537=>10461, +45538=>10462, +45539=>10463, +45540=>10464, +45541=>10465, +45542=>10466, +45543=>10467, +45546=>10468, +45547=>10469, +45549=>10470, +45550=>10471, +45551=>10472, +45553=>10473, +45554=>10474, +45555=>10475, +45556=>10476, +45557=>10477, +45558=>10478, +45559=>10479, +45560=>10480, +45562=>10481, +45564=>10482, +45566=>10483, +45567=>10484, +45568=>10485, +45569=>10486, +45570=>10487, +45571=>10488, +45574=>10489, +45575=>10490, +45577=>10491, +45578=>10492, +45581=>10493, +45582=>10494, +45583=>10495, +45584=>10496, +45585=>10497, +45586=>10498, +45587=>10499, +45590=>10500, +45592=>10501, +45594=>10502, +45595=>10503, +45596=>10504, +45597=>10505, +45598=>10506, +45599=>10507, +45601=>10508, +45602=>10509, +45603=>10510, +45604=>10511, +45605=>10512, +45606=>10513, +45607=>10514, +45608=>10515, +45609=>10516, +45610=>10517, +45611=>10518, +45612=>10519, +45613=>10520, +45614=>10521, +45615=>10522, +45616=>10523, +45617=>10524, +45618=>10525, +45619=>10526, +45621=>10527, +45622=>10528, +45623=>10529, +45624=>10530, +45625=>10531, +45626=>10532, +45627=>10533, +45629=>10534, +45630=>10535, +45631=>10536, +45632=>10537, +45633=>10538, +45634=>10539, +45635=>10540, +45636=>10541, +45637=>10542, +45638=>10543, +45639=>10544, +45640=>10545, +45641=>10546, +45642=>10547, +45643=>10548, +45644=>10549, +45645=>10550, +45646=>10551, +45647=>10552, +45648=>10553, +45649=>10554, +45650=>10555, +45651=>10556, +45652=>10557, +45653=>10558, +45654=>10559, +45655=>10560, +45657=>10561, +45658=>10562, +45659=>10563, +45661=>10564, +45662=>10565, +45663=>10566, +45665=>10567, +45666=>10568, +45667=>10569, +45668=>10570, +45669=>10571, +45670=>10572, +45671=>10573, +45674=>10574, +45675=>10575, +45676=>10576, +45677=>10577, +45678=>10578, +45679=>10579, +45680=>10580, +45681=>10581, +45682=>10582, +45683=>10583, +45686=>10584, +45687=>10585, +45688=>10586, +45689=>10587, +45690=>10588, +45691=>10589, +45693=>10590, +45694=>10591, +45695=>10592, +45696=>10593, +45697=>10594, +45698=>10595, +45699=>10596, +45702=>10597, +45703=>10598, +45704=>10599, +45706=>10600, +45707=>10601, +45708=>10602, +45709=>10603, +45710=>10604, +45711=>10605, +45714=>10606, +45715=>10607, +45717=>10608, +45718=>10609, +45719=>10610, +45723=>10611, +45724=>10612, +45725=>10613, +45726=>10614, +45727=>10615, +45730=>10616, +45732=>10617, +45735=>10618, +45736=>10619, +45737=>10620, +45739=>10621, +45741=>10622, +45742=>10623, +45743=>10624, +45745=>10625, +45746=>10626, +45747=>10627, +45749=>10628, +45750=>10629, +45751=>10630, +45752=>10631, +45753=>10632, +45754=>10633, +45755=>10634, +45756=>10635, +45757=>10636, +45758=>10637, +45759=>10638, +45760=>10639, +45761=>10640, +45762=>10641, +45763=>10642, +45764=>10643, +45765=>10644, +45766=>10645, +45767=>10646, +45770=>10647, +45771=>10648, +45773=>10649, +45774=>10650, +45775=>10651, +45777=>10652, +45779=>10653, +45780=>10654, +45781=>10655, +45782=>10656, +45783=>10657, +45786=>10658, +45788=>10659, +45790=>10660, +45791=>10661, +45792=>10662, +45793=>10663, +45795=>10664, +45799=>10665, +45801=>10666, +45802=>10667, +45808=>10668, +45809=>10669, +45810=>10670, +45814=>10671, +45820=>10672, +45821=>10673, +45822=>10674, +45826=>10675, +45827=>10676, +45829=>10677, +45830=>10678, +45831=>10679, +45833=>10680, +45834=>10681, +45835=>10682, +45836=>10683, +45837=>10684, +45838=>10685, +45839=>10686, +45842=>10687, +45846=>10688, +45847=>10689, +45848=>10690, +45849=>10691, +45850=>10692, +45851=>10693, +45853=>10694, +45854=>10695, +45855=>10696, +45856=>10697, +45857=>10698, +45858=>10699, +45859=>10700, +45860=>10701, +45861=>10702, +45862=>10703, +45863=>10704, +45864=>10705, +45865=>10706, +45866=>10707, +45867=>10708, +45868=>10709, +45869=>10710, +45870=>10711, +45871=>10712, +45872=>10713, +45873=>10714, +45874=>10715, +45875=>10716, +45876=>10717, +45877=>10718, +45878=>10719, +45879=>10720, +45880=>10721, +45881=>10722, +45882=>10723, +45883=>10724, +45884=>10725, +45885=>10726, +45886=>10727, +45887=>10728, +45888=>10729, +45889=>10730, +45890=>10731, +45891=>10732, +45892=>10733, +45893=>10734, +45894=>10735, +45895=>10736, +45896=>10737, +45897=>10738, +45898=>10739, +45899=>10740, +45900=>10741, +45901=>10742, +45902=>10743, +45903=>10744, +45904=>10745, +45905=>10746, +45906=>10747, +45907=>10748, +45911=>10749, +45913=>10750, +45914=>10751, +45917=>10752, +45920=>10753, +45921=>10754, +45922=>10755, +45923=>10756, +45926=>10757, +45928=>10758, +45930=>10759, +45932=>10760, +45933=>10761, +45935=>10762, +45938=>10763, +45939=>10764, +45941=>10765, +45942=>10766, +45943=>10767, +45945=>10768, +45946=>10769, +45947=>10770, +45948=>10771, +45949=>10772, +45950=>10773, +45951=>10774, +45954=>10775, +45958=>10776, +45959=>10777, +45960=>10778, +45961=>10779, +45962=>10780, +45963=>10781, +45965=>10782, +45966=>10783, +45967=>10784, +45969=>10785, +45970=>10786, +45971=>10787, +45973=>10788, +45974=>10789, +45975=>10790, +45976=>10791, +45977=>10792, +45978=>10793, +45979=>10794, +45980=>10795, +45981=>10796, +45982=>10797, +45983=>10798, +45986=>10799, +45987=>10800, +45988=>10801, +45989=>10802, +45990=>10803, +45991=>10804, +45993=>10805, +45994=>10806, +45995=>10807, +45997=>10808, +45998=>10809, +45999=>10810, +46000=>10811, +46001=>10812, +46002=>10813, +46003=>10814, +46004=>10815, +46005=>10816, +46006=>10817, +46007=>10818, +46008=>10819, +46009=>10820, +46010=>10821, +46011=>10822, +46012=>10823, +46013=>10824, +46014=>10825, +46015=>10826, +46016=>10827, +46017=>10828, +46018=>10829, +46019=>10830, +46022=>10831, +46023=>10832, +46025=>10833, +46026=>10834, +46029=>10835, +46031=>10836, +46033=>10837, +46034=>10838, +46035=>10839, +46038=>10840, +46040=>10841, +46042=>10842, +46044=>10843, +46046=>10844, +46047=>10845, +46049=>10846, +46050=>10847, +46051=>10848, +46053=>10849, +46054=>10850, +46055=>10851, +46057=>10852, +46058=>10853, +46059=>10854, +46060=>10855, +46061=>10856, +46062=>10857, +46063=>10858, +46064=>10859, +46065=>10860, +46066=>10861, +46067=>10862, +46068=>10863, +46069=>10864, +46070=>10865, +46071=>10866, +46072=>10867, +46073=>10868, +46074=>10869, +46075=>10870, +46077=>10871, +46078=>10872, +46079=>10873, +46080=>10874, +46081=>10875, +46082=>10876, +46083=>10877, +46084=>10878, +46085=>10879, +46086=>10880, +46087=>10881, +46088=>10882, +46089=>10883, +46090=>10884, +46091=>10885, +46092=>10886, +46093=>10887, +46094=>10888, +46095=>10889, +46097=>10890, +46098=>10891, +46099=>10892, +46100=>10893, +46101=>10894, +46102=>10895, +46103=>10896, +46105=>10897, +46106=>10898, +46107=>10899, +46109=>10900, +46110=>10901, +46111=>10902, +46113=>10903, +46114=>10904, +46115=>10905, +46116=>10906, +46117=>10907, +46118=>10908, +46119=>10909, +46122=>10910, +46124=>10911, +46125=>10912, +46126=>10913, +46127=>10914, +46128=>10915, +46129=>10916, +46130=>10917, +46131=>10918, +46133=>10919, +46134=>10920, +46135=>10921, +46136=>10922, +46137=>10923, +46138=>10924, +46139=>10925, +46140=>10926, +46141=>10927, +46142=>10928, +46143=>10929, +46144=>10930, +46145=>10931, +46146=>10932, +46147=>10933, +46148=>10934, +46149=>10935, +46150=>10936, +46151=>10937, +46152=>10938, +46153=>10939, +46154=>10940, +46155=>10941, +46156=>10942, +46157=>10943, +46158=>10944, +46159=>10945, +46162=>10946, +46163=>10947, +46165=>10948, +46166=>10949, +46167=>10950, +46169=>10951, +46170=>10952, +46171=>10953, +46172=>10954, +46173=>10955, +46174=>10956, +46175=>10957, +46178=>10958, +46180=>10959, +46182=>10960, +46183=>10961, +46184=>10962, +46185=>10963, +46186=>10964, +46187=>10965, +46189=>10966, +46190=>10967, +46191=>10968, +46192=>10969, +46193=>10970, +46194=>10971, +46195=>10972, +46196=>10973, +46197=>10974, +46198=>10975, +46199=>10976, +46200=>10977, +46201=>10978, +46202=>10979, +46203=>10980, +46204=>10981, +46205=>10982, +46206=>10983, +46207=>10984, +46209=>10985, +46210=>10986, +46211=>10987, +46212=>10988, +46213=>10989, +46214=>10990, +46215=>10991, +46217=>10992, +46218=>10993, +46219=>10994, +46220=>10995, +46221=>10996, +46222=>10997, +46223=>10998, +46224=>10999, +46225=>11000, +46226=>11001, +46227=>11002, +46228=>11003, +46229=>11004, +46230=>11005, +46231=>11006, +46232=>11007, +46233=>11008, +46234=>11009, +46235=>11010, +46236=>11011, +46238=>11012, +46239=>11013, +46240=>11014, +46241=>11015, +46242=>11016, +46243=>11017, +46245=>11018, +46246=>11019, +46247=>11020, +46249=>11021, +46250=>11022, +46251=>11023, +46253=>11024, +46254=>11025, +46255=>11026, +46256=>11027, +46257=>11028, +46258=>11029, +46259=>11030, +46260=>11031, +46262=>11032, +46264=>11033, +46266=>11034, +46267=>11035, +46268=>11036, +46269=>11037, +46270=>11038, +46271=>11039, +46273=>11040, +46274=>11041, +46275=>11042, +46277=>11043, +46278=>11044, +46279=>11045, +46281=>11046, +46282=>11047, +46283=>11048, +46284=>11049, +46285=>11050, +46286=>11051, +46287=>11052, +46289=>11053, +46290=>11054, +46291=>11055, +46292=>11056, +46294=>11057, +46295=>11058, +46296=>11059, +46297=>11060, +46298=>11061, +46299=>11062, +46302=>11063, +46303=>11064, +46305=>11065, +46306=>11066, +46309=>11067, +46311=>11068, +46312=>11069, +46313=>11070, +46314=>11071, +46315=>11072, +46318=>11073, +46320=>11074, +46322=>11075, +46323=>11076, +46324=>11077, +46325=>11078, +46326=>11079, +46327=>11080, +46329=>11081, +46330=>11082, +46331=>11083, +46332=>11084, +46333=>11085, +46334=>11086, +46335=>11087, +46336=>11088, +46337=>11089, +46338=>11090, +46339=>11091, +46340=>11092, +46341=>11093, +46342=>11094, +46343=>11095, +46344=>11096, +46345=>11097, +46346=>11098, +46347=>11099, +46348=>11100, +46349=>11101, +46350=>11102, +46351=>11103, +46352=>11104, +46353=>11105, +46354=>11106, +46355=>11107, +46358=>11108, +46359=>11109, +46361=>11110, +46362=>11111, +46365=>11112, +46366=>11113, +46367=>11114, +46368=>11115, +46369=>11116, +46370=>11117, +46371=>11118, +46374=>11119, +46379=>11120, +46380=>11121, +46381=>11122, +46382=>11123, +46383=>11124, +46386=>11125, +46387=>11126, +46389=>11127, +46390=>11128, +46391=>11129, +46393=>11130, +46394=>11131, +46395=>11132, +46396=>11133, +46397=>11134, +46398=>11135, +46399=>11136, +46402=>11137, +46406=>11138, +46407=>11139, +46408=>11140, +46409=>11141, +46410=>11142, +46414=>11143, +46415=>11144, +46417=>11145, +46418=>11146, +46419=>11147, +46421=>11148, +46422=>11149, +46423=>11150, +46424=>11151, +46425=>11152, +46426=>11153, +46427=>11154, +46430=>11155, +46434=>11156, +46435=>11157, +46436=>11158, +46437=>11159, +46438=>11160, +46439=>11161, +46440=>11162, +46441=>11163, +46442=>11164, +46443=>11165, +46444=>11166, +46445=>11167, +46446=>11168, +46447=>11169, +46448=>11170, +46449=>11171, +46450=>11172, +46451=>11173, +46452=>11174, +46453=>11175, +46454=>11176, +46455=>11177, +46456=>11178, +46457=>11179, +46458=>11180, +46459=>11181, +46460=>11182, +46461=>11183, +46462=>11184, +46463=>11185, +46464=>11186, +46465=>11187, +46466=>11188, +46467=>11189, +46468=>11190, +46469=>11191, +46470=>11192, +46471=>11193, +46472=>11194, +46473=>11195, +46474=>11196, +46475=>11197, +46476=>11198, +46477=>11199, +46478=>11200, +46479=>11201, +46480=>11202, +46481=>11203, +46482=>11204, +46483=>11205, +46484=>11206, +46485=>11207, +46486=>11208, +46487=>11209, +46488=>11210, +46489=>11211, +46490=>11212, +46491=>11213, +46492=>11214, +46493=>11215, +46494=>11216, +46495=>11217, +46498=>11218, +46499=>11219, +46501=>11220, +46502=>11221, +46503=>11222, +46505=>11223, +46508=>11224, +46509=>11225, +46510=>11226, +46511=>11227, +46514=>11228, +46518=>11229, +46519=>11230, +46520=>11231, +46521=>11232, +46522=>11233, +46526=>11234, +46527=>11235, +46529=>11236, +46530=>11237, +46531=>11238, +46533=>11239, +46534=>11240, +46535=>11241, +46536=>11242, +46537=>11243, +46538=>11244, +46539=>11245, +46542=>11246, +46546=>11247, +46547=>11248, +46548=>11249, +46549=>11250, +46550=>11251, +46551=>11252, +46553=>11253, +46554=>11254, +46555=>11255, +46556=>11256, +46557=>11257, +46558=>11258, +46559=>11259, +46560=>11260, +46561=>11261, +46562=>11262, +46563=>11263, +46564=>11264, +46565=>11265, +46566=>11266, +46567=>11267, +46568=>11268, +46569=>11269, +46570=>11270, +46571=>11271, +46573=>11272, +46574=>11273, +46575=>11274, +46576=>11275, +46577=>11276, +46578=>11277, +46579=>11278, +46580=>11279, +46581=>11280, +46582=>11281, +46583=>11282, +46584=>11283, +46585=>11284, +46586=>11285, +46587=>11286, +46588=>11287, +46589=>11288, +46590=>11289, +46591=>11290, +46592=>11291, +46593=>11292, +46594=>11293, +46595=>11294, +46596=>11295, +46597=>11296, +46598=>11297, +46599=>11298, +46600=>11299, +46601=>11300, +46602=>11301, +46603=>11302, +46604=>11303, +46605=>11304, +46606=>11305, +46607=>11306, +46610=>11307, +46611=>11308, +46613=>11309, +46614=>11310, +46615=>11311, +46617=>11312, +46618=>11313, +46619=>11314, +46620=>11315, +46621=>11316, +46622=>11317, +46623=>11318, +46624=>11319, +46625=>11320, +46626=>11321, +46627=>11322, +46628=>11323, +46630=>11324, +46631=>11325, +46632=>11326, +46633=>11327, +46634=>11328, +46635=>11329, +46637=>11330, +46638=>11331, +46639=>11332, +46640=>11333, +46641=>11334, +46642=>11335, +46643=>11336, +46645=>11337, +46646=>11338, +46647=>11339, +46648=>11340, +46649=>11341, +46650=>11342, +46651=>11343, +46652=>11344, +46653=>11345, +46654=>11346, +46655=>11347, +46656=>11348, +46657=>11349, +46658=>11350, +46659=>11351, +46660=>11352, +46661=>11353, +46662=>11354, +46663=>11355, +46665=>11356, +46666=>11357, +46667=>11358, +46668=>11359, +46669=>11360, +46670=>11361, +46671=>11362, +46672=>11363, +46673=>11364, +46674=>11365, +46675=>11366, +46676=>11367, +46677=>11368, +46678=>11369, +46679=>11370, +46680=>11371, +46681=>11372, +46682=>11373, +46683=>11374, +46684=>11375, +46685=>11376, +46686=>11377, +46687=>11378, +46688=>11379, +46689=>11380, +46690=>11381, +46691=>11382, +46693=>11383, +46694=>11384, +46695=>11385, +46697=>11386, +46698=>11387, +46699=>11388, +46700=>11389, +46701=>11390, +46702=>11391, +46703=>11392, +46704=>11393, +46705=>11394, +46706=>11395, +46707=>11396, +46708=>11397, +46709=>11398, +46710=>11399, +46711=>11400, +46712=>11401, +46713=>11402, +46714=>11403, +46715=>11404, +46716=>11405, +46717=>11406, +46718=>11407, +46719=>11408, +46720=>11409, +46721=>11410, +46722=>11411, +46723=>11412, +46724=>11413, +46725=>11414, +46726=>11415, +46727=>11416, +46728=>11417, +46729=>11418, +46730=>11419, +46731=>11420, +46732=>11421, +46733=>11422, +46734=>11423, +46735=>11424, +46736=>11425, +46737=>11426, +46738=>11427, +46739=>11428, +46740=>11429, +46741=>11430, +46742=>11431, +46743=>11432, +46744=>11433, +46745=>11434, +46746=>11435, +46747=>11436, +46750=>11437, +46751=>11438, +46753=>11439, +46754=>11440, +46755=>11441, +46757=>11442, +46758=>11443, +46759=>11444, +46760=>11445, +46761=>11446, +46762=>11447, +46765=>11448, +46766=>11449, +46767=>11450, +46768=>11451, +46770=>11452, +46771=>11453, +46772=>11454, +46773=>11455, +46774=>11456, +46775=>11457, +46776=>11458, +46777=>11459, +46778=>11460, +46779=>11461, +46780=>11462, +46781=>11463, +46782=>11464, +46783=>11465, +46784=>11466, +46785=>11467, +46786=>11468, +46787=>11469, +46788=>11470, +46789=>11471, +46790=>11472, +46791=>11473, +46792=>11474, +46793=>11475, +46794=>11476, +46795=>11477, +46796=>11478, +46797=>11479, +46798=>11480, +46799=>11481, +46800=>11482, +46801=>11483, +46802=>11484, +46803=>11485, +46805=>11486, +46806=>11487, +46807=>11488, +46808=>11489, +46809=>11490, +46810=>11491, +46811=>11492, +46812=>11493, +46813=>11494, +46814=>11495, +46815=>11496, +46816=>11497, +46817=>11498, +46818=>11499, +46819=>11500, +46820=>11501, +46821=>11502, +46822=>11503, +46823=>11504, +46824=>11505, +46825=>11506, +46826=>11507, +46827=>11508, +46828=>11509, +46829=>11510, +46830=>11511, +46831=>11512, +46833=>11513, +46834=>11514, +46835=>11515, +46837=>11516, +46838=>11517, +46839=>11518, +46841=>11519, +46842=>11520, +46843=>11521, +46844=>11522, +46845=>11523, +46846=>11524, +46847=>11525, +46850=>11526, +46851=>11527, +46852=>11528, +46854=>11529, +46855=>11530, +46856=>11531, +46857=>11532, +46858=>11533, +46859=>11534, +46860=>11535, +46861=>11536, +46862=>11537, +46863=>11538, +46864=>11539, +46865=>11540, +46866=>11541, +46867=>11542, +46868=>11543, +46869=>11544, +46870=>11545, +46871=>11546, +46872=>11547, +46873=>11548, +46874=>11549, +46875=>11550, +46876=>11551, +46877=>11552, +46878=>11553, +46879=>11554, +46880=>11555, +46881=>11556, +46882=>11557, +46883=>11558, +46884=>11559, +46885=>11560, +46886=>11561, +46887=>11562, +46890=>11563, +46891=>11564, +46893=>11565, +46894=>11566, +46897=>11567, +46898=>11568, +46899=>11569, +46900=>11570, +46901=>11571, +46902=>11572, +46903=>11573, +46906=>11574, +46908=>11575, +46909=>11576, +46910=>11577, +46911=>11578, +46912=>11579, +46913=>11580, +46914=>11581, +46915=>11582, +46917=>11583, +46918=>11584, +46919=>11585, +46921=>11586, +46922=>11587, +46923=>11588, +46925=>11589, +46926=>11590, +46927=>11591, +46928=>11592, +46929=>11593, +46930=>11594, +46931=>11595, +46934=>11596, +46935=>11597, +46936=>11598, +46937=>11599, +46938=>11600, +46939=>11601, +46940=>11602, +46941=>11603, +46942=>11604, +46943=>11605, +46945=>11606, +46946=>11607, +46947=>11608, +46949=>11609, +46950=>11610, +46951=>11611, +46953=>11612, +46954=>11613, +46955=>11614, +46956=>11615, +46957=>11616, +46958=>11617, +46959=>11618, +46962=>11619, +46964=>11620, +46966=>11621, +46967=>11622, +46968=>11623, +46969=>11624, +46970=>11625, +46971=>11626, +46974=>11627, +46975=>11628, +46977=>11629, +46978=>11630, +46979=>11631, +46981=>11632, +46982=>11633, +46983=>11634, +46984=>11635, +46985=>11636, +46986=>11637, +46987=>11638, +46990=>11639, +46995=>11640, +46996=>11641, +46997=>11642, +47002=>11643, +47003=>11644, +47005=>11645, +47006=>11646, +47007=>11647, +47009=>11648, +47010=>11649, +47011=>11650, +47012=>11651, +47013=>11652, +47014=>11653, +47015=>11654, +47018=>11655, +47022=>11656, +47023=>11657, +47024=>11658, +47025=>11659, +47026=>11660, +47027=>11661, +47030=>11662, +47031=>11663, +47033=>11664, +47034=>11665, +47035=>11666, +47036=>11667, +47037=>11668, +47038=>11669, +47039=>11670, +47040=>11671, +47041=>11672, +47042=>11673, +47043=>11674, +47044=>11675, +47045=>11676, +47046=>11677, +47048=>11678, +47050=>11679, +47051=>11680, +47052=>11681, +47053=>11682, +47054=>11683, +47055=>11684, +47056=>11685, +47057=>11686, +47058=>11687, +47059=>11688, +47060=>11689, +47061=>11690, +47062=>11691, +47063=>11692, +47064=>11693, +47065=>11694, +47066=>11695, +47067=>11696, +47068=>11697, +47069=>11698, +47070=>11699, +47071=>11700, +47072=>11701, +47073=>11702, +47074=>11703, +47075=>11704, +47076=>11705, +47077=>11706, +47078=>11707, +47079=>11708, +47080=>11709, +47081=>11710, +47082=>11711, +47083=>11712, +47086=>11713, +47087=>11714, +47089=>11715, +47090=>11716, +47091=>11717, +47093=>11718, +47094=>11719, +47095=>11720, +47096=>11721, +47097=>11722, +47098=>11723, +47099=>11724, +47102=>11725, +47106=>11726, +47107=>11727, +47108=>11728, +47109=>11729, +47110=>11730, +47114=>11731, +47115=>11732, +47117=>11733, +47118=>11734, +47119=>11735, +47121=>11736, +47122=>11737, +47123=>11738, +47124=>11739, +47125=>11740, +47126=>11741, +47127=>11742, +47130=>11743, +47132=>11744, +47134=>11745, +47135=>11746, +47136=>11747, +47137=>11748, +47138=>11749, +47139=>11750, +47142=>11751, +47143=>11752, +47145=>11753, +47146=>11754, +47147=>11755, +47149=>11756, +47150=>11757, +47151=>11758, +47152=>11759, +47153=>11760, +47154=>11761, +47155=>11762, +47158=>11763, +47162=>11764, +47163=>11765, +47164=>11766, +47165=>11767, +47166=>11768, +47167=>11769, +47169=>11770, +47170=>11771, +47171=>11772, +47173=>11773, +47174=>11774, +47175=>11775, +47176=>11776, +47177=>11777, +47178=>11778, +47179=>11779, +47180=>11780, +47181=>11781, +47182=>11782, +47183=>11783, +47184=>11784, +47186=>11785, +47188=>11786, +47189=>11787, +47190=>11788, +47191=>11789, +47192=>11790, +47193=>11791, +47194=>11792, +47195=>11793, +47198=>11794, +47199=>11795, +47201=>11796, +47202=>11797, +47203=>11798, +47205=>11799, +47206=>11800, +47207=>11801, +47208=>11802, +47209=>11803, +47210=>11804, +47211=>11805, +47214=>11806, +47216=>11807, +47218=>11808, +47219=>11809, +47220=>11810, +47221=>11811, +47222=>11812, +47223=>11813, +47225=>11814, +47226=>11815, +47227=>11816, +47229=>11817, +47230=>11818, +47231=>11819, +47232=>11820, +47233=>11821, +47234=>11822, +47235=>11823, +47236=>11824, +47237=>11825, +47238=>11826, +47239=>11827, +47240=>11828, +47241=>11829, +47242=>11830, +47243=>11831, +47244=>11832, +47246=>11833, +47247=>11834, +47248=>11835, +47249=>11836, +47250=>11837, +47251=>11838, +47252=>11839, +47253=>11840, +47254=>11841, +47255=>11842, +47256=>11843, +47257=>11844, +47258=>11845, +47259=>11846, +47260=>11847, +47261=>11848, +47262=>11849, +47263=>11850, +47264=>11851, +47265=>11852, +47266=>11853, +47267=>11854, +47268=>11855, +47269=>11856, +47270=>11857, +47271=>11858, +47273=>11859, +47274=>11860, +47275=>11861, +47276=>11862, +47277=>11863, +47278=>11864, +47279=>11865, +47281=>11866, +47282=>11867, +47283=>11868, +47285=>11869, +47286=>11870, +47287=>11871, +47289=>11872, +47290=>11873, +47291=>11874, +47292=>11875, +47293=>11876, +47294=>11877, +47295=>11878, +47298=>11879, +47300=>11880, +47302=>11881, +47303=>11882, +47304=>11883, +47305=>11884, +47306=>11885, +47307=>11886, +47309=>11887, +47310=>11888, +47311=>11889, +47313=>11890, +47314=>11891, +47315=>11892, +47317=>11893, +47318=>11894, +47319=>11895, +47320=>11896, +47321=>11897, +47322=>11898, +47323=>11899, +47324=>11900, +47326=>11901, +47328=>11902, +47330=>11903, +47331=>11904, +47332=>11905, +47333=>11906, +47334=>11907, +47335=>11908, +47338=>11909, +47339=>11910, +47341=>11911, +47342=>11912, +47343=>11913, +47345=>11914, +47346=>11915, +47347=>11916, +47348=>11917, +47349=>11918, +47350=>11919, +47351=>11920, +47354=>11921, +47356=>11922, +47358=>11923, +47359=>11924, +47360=>11925, +47361=>11926, +47362=>11927, +47363=>11928, +47365=>11929, +47366=>11930, +47367=>11931, +47368=>11932, +47369=>11933, +47370=>11934, +47371=>11935, +47372=>11936, +47373=>11937, +47374=>11938, +47375=>11939, +47376=>11940, +47377=>11941, +47378=>11942, +47379=>11943, +47380=>11944, +47381=>11945, +47382=>11946, +47383=>11947, +47385=>11948, +47386=>11949, +47387=>11950, +47388=>11951, +47389=>11952, +47390=>11953, +47391=>11954, +47393=>11955, +47394=>11956, +47395=>11957, +47396=>11958, +47397=>11959, +47398=>11960, +47399=>11961, +47400=>11962, +47401=>11963, +47402=>11964, +47403=>11965, +47404=>11966, +47405=>11967, +47406=>11968, +47407=>11969, +47408=>11970, +47409=>11971, +47410=>11972, +47411=>11973, +47412=>11974, +47413=>11975, +47414=>11976, +47415=>11977, +47416=>11978, +47417=>11979, +47418=>11980, +47419=>11981, +47422=>11982, +47423=>11983, +47425=>11984, +47426=>11985, +47427=>11986, +47429=>11987, +47430=>11988, +47431=>11989, +47432=>11990, +47433=>11991, +47434=>11992, +47435=>11993, +47437=>11994, +47438=>11995, +47440=>11996, +47442=>11997, +47443=>11998, +47444=>11999, +47445=>12000, +47446=>12001, +47447=>12002, +47450=>12003, +47451=>12004, +47453=>12005, +47454=>12006, +47455=>12007, +47457=>12008, +47458=>12009, +47459=>12010, +47460=>12011, +47461=>12012, +47462=>12013, +47463=>12014, +47466=>12015, +47468=>12016, +47470=>12017, +47471=>12018, +47472=>12019, +47473=>12020, +47474=>12021, +47475=>12022, +47478=>12023, +47479=>12024, +47481=>12025, +47482=>12026, +47483=>12027, +47485=>12028, +47486=>12029, +47487=>12030, +47488=>12031, +47489=>12032, +47490=>12033, +47491=>12034, +47494=>12035, +47496=>12036, +47499=>12037, +47500=>12038, +47503=>12039, +47504=>12040, +47505=>12041, +47506=>12042, +47507=>12043, +47508=>12044, +47509=>12045, +47510=>12046, +47511=>12047, +47512=>12048, +47513=>12049, +47514=>12050, +47515=>12051, +47516=>12052, +47517=>12053, +47518=>12054, +47519=>12055, +47520=>12056, +47521=>12057, +47522=>12058, +47523=>12059, +47524=>12060, +47525=>12061, +47526=>12062, +47527=>12063, +47528=>12064, +47529=>12065, +47530=>12066, +47531=>12067, +47534=>12068, +47535=>12069, +47537=>12070, +47538=>12071, +47539=>12072, +47541=>12073, +47542=>12074, +47543=>12075, +47544=>12076, +47545=>12077, +47546=>12078, +47547=>12079, +47550=>12080, +47552=>12081, +47554=>12082, +47555=>12083, +47556=>12084, +47557=>12085, +47558=>12086, +47559=>12087, +47562=>12088, +47563=>12089, +47565=>12090, +47571=>12091, +47572=>12092, +47573=>12093, +47574=>12094, +47575=>12095, +47578=>12096, +47580=>12097, +47583=>12098, +47584=>12099, +47586=>12100, +47590=>12101, +47591=>12102, +47593=>12103, +47594=>12104, +47595=>12105, +47597=>12106, +47598=>12107, +47599=>12108, +47600=>12109, +47601=>12110, +47602=>12111, +47603=>12112, +47606=>12113, +47611=>12114, +47612=>12115, +47613=>12116, +47614=>12117, +47615=>12118, +47618=>12119, +47619=>12120, +47620=>12121, +47621=>12122, +47622=>12123, +47623=>12124, +47625=>12125, +47626=>12126, +47627=>12127, +47628=>12128, +47629=>12129, +47630=>12130, +47631=>12131, +47632=>12132, +47633=>12133, +47634=>12134, +47635=>12135, +47636=>12136, +47638=>12137, +47639=>12138, +47640=>12139, +47641=>12140, +47642=>12141, +47643=>12142, +47644=>12143, +47645=>12144, +47646=>12145, +47647=>12146, +47648=>12147, +47649=>12148, +47650=>12149, +47651=>12150, +47652=>12151, +47653=>12152, +47654=>12153, +47655=>12154, +47656=>12155, +47657=>12156, +47658=>12157, +47659=>12158, +47660=>12159, +47661=>12160, +47662=>12161, +47663=>12162, +47664=>12163, +47665=>12164, +47666=>12165, +47667=>12166, +47668=>12167, +47669=>12168, +47670=>12169, +47671=>12170, +47674=>12171, +47675=>12172, +47677=>12173, +47678=>12174, +47679=>12175, +47681=>12176, +47683=>12177, +47684=>12178, +47685=>12179, +47686=>12180, +47687=>12181, +47690=>12182, +47692=>12183, +47695=>12184, +47696=>12185, +47697=>12186, +47698=>12187, +47702=>12188, +47703=>12189, +47705=>12190, +47706=>12191, +47707=>12192, +47709=>12193, +47710=>12194, +47711=>12195, +47712=>12196, +47713=>12197, +47714=>12198, +47715=>12199, +47718=>12200, +47722=>12201, +47723=>12202, +47724=>12203, +47725=>12204, +47726=>12205, +47727=>12206, +47730=>12207, +47731=>12208, +47733=>12209, +47734=>12210, +47735=>12211, +47737=>12212, +47738=>12213, +47739=>12214, +47740=>12215, +47741=>12216, +47742=>12217, +47743=>12218, +47744=>12219, +47745=>12220, +47746=>12221, +47750=>12222, +47752=>12223, +47753=>12224, +47754=>12225, +47755=>12226, +47757=>12227, +47758=>12228, +47759=>12229, +47760=>12230, +47761=>12231, +47762=>12232, +47763=>12233, +47764=>12234, +47765=>12235, +47766=>12236, +47767=>12237, +47768=>12238, +47769=>12239, +47770=>12240, +47771=>12241, +47772=>12242, +47773=>12243, +47774=>12244, +47775=>12245, +47776=>12246, +47777=>12247, +47778=>12248, +47779=>12249, +47780=>12250, +47781=>12251, +47782=>12252, +47783=>12253, +47786=>12254, +47789=>12255, +47790=>12256, +47791=>12257, +47793=>12258, +47795=>12259, +47796=>12260, +47797=>12261, +47798=>12262, +47799=>12263, +47802=>12264, +47804=>12265, +47806=>12266, +47807=>12267, +47808=>12268, +47809=>12269, +47810=>12270, +47811=>12271, +47813=>12272, +47814=>12273, +47815=>12274, +47817=>12275, +47818=>12276, +47819=>12277, +47820=>12278, +47821=>12279, +47822=>12280, +47823=>12281, +47824=>12282, +47825=>12283, +47826=>12284, +47827=>12285, +47828=>12286, +47829=>12287, +47830=>12288, +47831=>12289, +47834=>12290, +47835=>12291, +47836=>12292, +47837=>12293, +47838=>12294, +47839=>12295, +47840=>12296, +47841=>12297, +47842=>12298, +47843=>12299, +47844=>12300, +47845=>12301, +47846=>12302, +47847=>12303, +47848=>12304, +47849=>12305, +47850=>12306, +47851=>12307, +47852=>12308, +47853=>12309, +47854=>12310, +47855=>12311, +47856=>12312, +47857=>12313, +47858=>12314, +47859=>12315, +47860=>12316, +47861=>12317, +47862=>12318, +47863=>12319, +47864=>12320, +47865=>12321, +47866=>12322, +47867=>12323, +47869=>12324, +47870=>12325, +47871=>12326, +47873=>12327, +47874=>12328, +47875=>12329, +47877=>12330, +47878=>12331, +47879=>12332, +47880=>12333, +47881=>12334, +47882=>12335, +47883=>12336, +47884=>12337, +47886=>12338, +47888=>12339, +47890=>12340, +47891=>12341, +47892=>12342, +47893=>12343, +47894=>12344, +47895=>12345, +47897=>12346, +47898=>12347, +47899=>12348, +47901=>12349, +47902=>12350, +47903=>12351, +47905=>12352, +47906=>12353, +47907=>12354, +47908=>12355, +47909=>12356, +47910=>12357, +47911=>12358, +47912=>12359, +47914=>12360, +47916=>12361, +47917=>12362, +47918=>12363, +47919=>12364, +47920=>12365, +47921=>12366, +47922=>12367, +47923=>12368, +47927=>12369, +47929=>12370, +47930=>12371, +47935=>12372, +47936=>12373, +47937=>12374, +47938=>12375, +47939=>12376, +47942=>12377, +47944=>12378, +47946=>12379, +47947=>12380, +47948=>12381, +47950=>12382, +47953=>12383, +47954=>12384, +47955=>12385, +47957=>12386, +47958=>12387, +47959=>12388, +47961=>12389, +47962=>12390, +47963=>12391, +47964=>12392, +47965=>12393, +47966=>12394, +47967=>12395, +47968=>12396, +47970=>12397, +47972=>12398, +47973=>12399, +47974=>12400, +47975=>12401, +47976=>12402, +47977=>12403, +47978=>12404, +47979=>12405, +47981=>12406, +47982=>12407, +47983=>12408, +47984=>12409, +47985=>12410, +47986=>12411, +47987=>12412, +47988=>12413, +47989=>12414, +47990=>12415, +47991=>12416, +47992=>12417, +47993=>12418, +47994=>12419, +47995=>12420, +47996=>12421, +47997=>12422, +47998=>12423, +47999=>12424, +48000=>12425, +48001=>12426, +48002=>12427, +48003=>12428, +48004=>12429, +48005=>12430, +48006=>12431, +48007=>12432, +48009=>12433, +48010=>12434, +48011=>12435, +48013=>12436, +48014=>12437, +48015=>12438, +48017=>12439, +48018=>12440, +48019=>12441, +48020=>12442, +48021=>12443, +48022=>12444, +48023=>12445, +48024=>12446, +48025=>12447, +48026=>12448, +48027=>12449, +48028=>12450, +48029=>12451, +48030=>12452, +48031=>12453, +48032=>12454, +48033=>12455, +48034=>12456, +48035=>12457, +48037=>12458, +48038=>12459, +48039=>12460, +48041=>12461, +48042=>12462, +48043=>12463, +48045=>12464, +48046=>12465, +48047=>12466, +48048=>12467, +48049=>12468, +48050=>12469, +48051=>12470, +48053=>12471, +48054=>12472, +48056=>12473, +48057=>12474, +48058=>12475, +48059=>12476, +48060=>12477, +48061=>12478, +48062=>12479, +48063=>12480, +48065=>12481, +48066=>12482, +48067=>12483, +48069=>12484, +48070=>12485, +48071=>12486, +48073=>12487, +48074=>12488, +48075=>12489, +48076=>12490, +48077=>12491, +48078=>12492, +48079=>12493, +48081=>12494, +48082=>12495, +48084=>12496, +48085=>12497, +48086=>12498, +48087=>12499, +48088=>12500, +48089=>12501, +48090=>12502, +48091=>12503, +48092=>12504, +48093=>12505, +48094=>12506, +48095=>12507, +48096=>12508, +48097=>12509, +48098=>12510, +48099=>12511, +48100=>12512, +48101=>12513, +48102=>12514, +48103=>12515, +48104=>12516, +48105=>12517, +48106=>12518, +48107=>12519, +48108=>12520, +48109=>12521, +48110=>12522, +48111=>12523, +48112=>12524, +48113=>12525, +48114=>12526, +48115=>12527, +48116=>12528, +48117=>12529, +48118=>12530, +48119=>12531, +48122=>12532, +48123=>12533, +48125=>12534, +48126=>12535, +48129=>12536, +48131=>12537, +48132=>12538, +48133=>12539, +48134=>12540, +48135=>12541, +48138=>12542, +48142=>12543, +48144=>12544, +48146=>12545, +48147=>12546, +48153=>12547, +48154=>12548, +48160=>12549, +48161=>12550, +48162=>12551, +48163=>12552, +48166=>12553, +48168=>12554, +48170=>12555, +48171=>12556, +48172=>12557, +48174=>12558, +48175=>12559, +48178=>12560, +48179=>12561, +48181=>12562, +48182=>12563, +48183=>12564, +48185=>12565, +48186=>12566, +48187=>12567, +48188=>12568, +48189=>12569, +48190=>12570, +48191=>12571, +48194=>12572, +48198=>12573, +48199=>12574, +48200=>12575, +48202=>12576, +48203=>12577, +48206=>12578, +48207=>12579, +48209=>12580, +48210=>12581, +48211=>12582, +48212=>12583, +48213=>12584, +48214=>12585, +48215=>12586, +48216=>12587, +48217=>12588, +48218=>12589, +48219=>12590, +48220=>12591, +48222=>12592, +48223=>12593, +48224=>12594, +48225=>12595, +48226=>12596, +48227=>12597, +48228=>12598, +48229=>12599, +48230=>12600, +48231=>12601, +48232=>12602, +48233=>12603, +48234=>12604, +48235=>12605, +48236=>12606, +48237=>12607, +48238=>12608, +48239=>12609, +48240=>12610, +48241=>12611, +48242=>12612, +48243=>12613, +48244=>12614, +48245=>12615, +48246=>12616, +48247=>12617, +48248=>12618, +48249=>12619, +48250=>12620, +48251=>12621, +48252=>12622, +48253=>12623, +48254=>12624, +48255=>12625, +48256=>12626, +48257=>12627, +48258=>12628, +48259=>12629, +48262=>12630, +48263=>12631, +48265=>12632, +48266=>12633, +48269=>12634, +48271=>12635, +48272=>12636, +48273=>12637, +48274=>12638, +48275=>12639, +48278=>12640, +48280=>12641, +48283=>12642, +48284=>12643, +48285=>12644, +48286=>12645, +48287=>12646, +48290=>12647, +48291=>12648, +48293=>12649, +48294=>12650, +48297=>12651, +48298=>12652, +48299=>12653, +48300=>12654, +48301=>12655, +48302=>12656, +48303=>12657, +48306=>12658, +48310=>12659, +48311=>12660, +48312=>12661, +48313=>12662, +48314=>12663, +48315=>12664, +48318=>12665, +48319=>12666, +48321=>12667, +48322=>12668, +48323=>12669, +48325=>12670, +48326=>12671, +48327=>12672, +48328=>12673, +48329=>12674, +48330=>12675, +48331=>12676, +48332=>12677, +48334=>12678, +48338=>12679, +48339=>12680, +48340=>12681, +48342=>12682, +48343=>12683, +48345=>12684, +48346=>12685, +48347=>12686, +48349=>12687, +48350=>12688, +48351=>12689, +48352=>12690, +48353=>12691, +48354=>12692, +48355=>12693, +48356=>12694, +48357=>12695, +48358=>12696, +48359=>12697, +48360=>12698, +48361=>12699, +48362=>12700, +48363=>12701, +48364=>12702, +48365=>12703, +48366=>12704, +48367=>12705, +48368=>12706, +48369=>12707, +48370=>12708, +48371=>12709, +48375=>12710, +48377=>12711, +48378=>12712, +48379=>12713, +48381=>12714, +48382=>12715, +48383=>12716, +48384=>12717, +48385=>12718, +48386=>12719, +48387=>12720, +48390=>12721, +48392=>12722, +48394=>12723, +48395=>12724, +48396=>12725, +48397=>12726, +48398=>12727, +48399=>12728, +48401=>12729, +48402=>12730, +48403=>12731, +48405=>12732, +48406=>12733, +48407=>12734, +48408=>12735, +48409=>12736, +48410=>12737, +48411=>12738, +48412=>12739, +48413=>12740, +48414=>12741, +48415=>12742, +48416=>12743, +48417=>12744, +48418=>12745, +48419=>12746, +48421=>12747, +48422=>12748, +48423=>12749, +48424=>12750, +48425=>12751, +48426=>12752, +48427=>12753, +48429=>12754, +48430=>12755, +48431=>12756, +48432=>12757, +48433=>12758, +48434=>12759, +48435=>12760, +48436=>12761, +48437=>12762, +48438=>12763, +48439=>12764, +48440=>12765, +48441=>12766, +48442=>12767, +48443=>12768, +48444=>12769, +48445=>12770, +48446=>12771, +48447=>12772, +48449=>12773, +48450=>12774, +48451=>12775, +48452=>12776, +48453=>12777, +48454=>12778, +48455=>12779, +48458=>12780, +48459=>12781, +48461=>12782, +48462=>12783, +48463=>12784, +48465=>12785, +48466=>12786, +48467=>12787, +48468=>12788, +48469=>12789, +48470=>12790, +48471=>12791, +48474=>12792, +48475=>12793, +48476=>12794, +48477=>12795, +48478=>12796, +48479=>12797, +48480=>12798, +48481=>12799, +48482=>12800, +48483=>12801, +48485=>12802, +48486=>12803, +48487=>12804, +48489=>12805, +48490=>12806, +48491=>12807, +48492=>12808, +48493=>12809, +48494=>12810, +48495=>12811, +48496=>12812, +48497=>12813, +48498=>12814, +48499=>12815, +48500=>12816, +48501=>12817, +48502=>12818, +48503=>12819, +48504=>12820, +48505=>12821, +48506=>12822, +48507=>12823, +48508=>12824, +48509=>12825, +48510=>12826, +48511=>12827, +48514=>12828, +48515=>12829, +48517=>12830, +48518=>12831, +48523=>12832, +48524=>12833, +48525=>12834, +48526=>12835, +48527=>12836, +48530=>12837, +48532=>12838, +48534=>12839, +48535=>12840, +48536=>12841, +48539=>12842, +48541=>12843, +48542=>12844, +48543=>12845, +48544=>12846, +48545=>12847, +48546=>12848, +48547=>12849, +48549=>12850, +48550=>12851, +48551=>12852, +48552=>12853, +48553=>12854, +48554=>12855, +48555=>12856, +48556=>12857, +48557=>12858, +48558=>12859, +48559=>12860, +48561=>12861, +48562=>12862, +48563=>12863, +48564=>12864, +48565=>12865, +48566=>12866, +48567=>12867, +48569=>12868, +48570=>12869, +48571=>12870, +48572=>12871, +48573=>12872, +48574=>12873, +48575=>12874, +48576=>12875, +48577=>12876, +48578=>12877, +48579=>12878, +48580=>12879, +48581=>12880, +48582=>12881, +48583=>12882, +48584=>12883, +48585=>12884, +48586=>12885, +48587=>12886, +48588=>12887, +48589=>12888, +48590=>12889, +48591=>12890, +48592=>12891, +48593=>12892, +48594=>12893, +48595=>12894, +48598=>12895, +48599=>12896, +48601=>12897, +48602=>12898, +48603=>12899, +48605=>12900, +48606=>12901, +48607=>12902, +48608=>12903, +48609=>12904, +48610=>12905, +48611=>12906, +48612=>12907, +48613=>12908, +48614=>12909, +48615=>12910, +48616=>12911, +48618=>12912, +48619=>12913, +48620=>12914, +48621=>12915, +48622=>12916, +48623=>12917, +48625=>12918, +48626=>12919, +48627=>12920, +48629=>12921, +48630=>12922, +48631=>12923, +48633=>12924, +48634=>12925, +48635=>12926, +48636=>12927, +48637=>12928, +48638=>12929, +48639=>12930, +48641=>12931, +48642=>12932, +48644=>12933, +48646=>12934, +48647=>12935, +48648=>12936, +48649=>12937, +48650=>12938, +48651=>12939, +48654=>12940, +48655=>12941, +48657=>12942, +48658=>12943, +48659=>12944, +48661=>12945, +48662=>12946, +48663=>12947, +48664=>12948, +48665=>12949, +48666=>12950, +48667=>12951, +48670=>12952, +48672=>12953, +48673=>12954, +48674=>12955, +48675=>12956, +48676=>12957, +48677=>12958, +48678=>12959, +48679=>12960, +48680=>12961, +48681=>12962, +48682=>12963, +48683=>12964, +48684=>12965, +48685=>12966, +48686=>12967, +48687=>12968, +48688=>12969, +48689=>12970, +48690=>12971, +48691=>12972, +48692=>12973, +48693=>12974, +48694=>12975, +48695=>12976, +48696=>12977, +48697=>12978, +48698=>12979, +48699=>12980, +48700=>12981, +48701=>12982, +48702=>12983, +48703=>12984, +48704=>12985, +48705=>12986, +48706=>12987, +48707=>12988, +48710=>12989, +48711=>12990, +48713=>12991, +48714=>12992, +48715=>12993, +48717=>12994, +48719=>12995, +48720=>12996, +48721=>12997, +48722=>12998, +48723=>12999, +48726=>13000, +48728=>13001, +48732=>13002, +48733=>13003, +48734=>13004, +48735=>13005, +48738=>13006, +48739=>13007, +48741=>13008, +48742=>13009, +48743=>13010, +48745=>13011, +48747=>13012, +48748=>13013, +48749=>13014, +48750=>13015, +48751=>13016, +48754=>13017, +48758=>13018, +48759=>13019, +48760=>13020, +48761=>13021, +48762=>13022, +48766=>13023, +48767=>13024, +48769=>13025, +48770=>13026, +48771=>13027, +48773=>13028, +48774=>13029, +48775=>13030, +48776=>13031, +48777=>13032, +48778=>13033, +48779=>13034, +48782=>13035, +48786=>13036, +48787=>13037, +48788=>13038, +48789=>13039, +48790=>13040, +48791=>13041, +48794=>13042, +48795=>13043, +48796=>13044, +48797=>13045, +48798=>13046, +48799=>13047, +48800=>13048, +48801=>13049, +48802=>13050, +48803=>13051, +48804=>13052, +48805=>13053, +48806=>13054, +48807=>13055, +48809=>13056, +48810=>13057, +48811=>13058, +48812=>13059, +48813=>13060, +48814=>13061, +48815=>13062, +48816=>13063, +48817=>13064, +48818=>13065, +48819=>13066, +48820=>13067, +48821=>13068, +48822=>13069, +48823=>13070, +48824=>13071, +48825=>13072, +48826=>13073, +48827=>13074, +48828=>13075, +48829=>13076, +48830=>13077, +48831=>13078, +48832=>13079, +48833=>13080, +48834=>13081, +48835=>13082, +48836=>13083, +48837=>13084, +48838=>13085, +48839=>13086, +48840=>13087, +48841=>13088, +48842=>13089, +48843=>13090, +48844=>13091, +48845=>13092, +48846=>13093, +48847=>13094, +48850=>13095, +48851=>13096, +48853=>13097, +48854=>13098, +48857=>13099, +48858=>13100, +48859=>13101, +48860=>13102, +48861=>13103, +48862=>13104, +48863=>13105, +48865=>13106, +48866=>13107, +48870=>13108, +48871=>13109, +48872=>13110, +48873=>13111, +48874=>13112, +48875=>13113, +48877=>13114, +48878=>13115, +48879=>13116, +48880=>13117, +48881=>13118, +48882=>13119, +48883=>13120, +48884=>13121, +48885=>13122, +48886=>13123, +48887=>13124, +48888=>13125, +48889=>13126, +48890=>13127, +48891=>13128, +48892=>13129, +48893=>13130, +48894=>13131, +48895=>13132, +48896=>13133, +48898=>13134, +48899=>13135, +48900=>13136, +48901=>13137, +48902=>13138, +48903=>13139, +48906=>13140, +48907=>13141, +48908=>13142, +48909=>13143, +48910=>13144, +48911=>13145, +48912=>13146, +48913=>13147, +48914=>13148, +48915=>13149, +48916=>13150, +48917=>13151, +48918=>13152, +48919=>13153, +48922=>13154, +48926=>13155, +48927=>13156, +48928=>13157, +48929=>13158, +48930=>13159, +48931=>13160, +48932=>13161, +48933=>13162, +48934=>13163, +48935=>13164, +48936=>13165, +48937=>13166, +48938=>13167, +48939=>13168, +48940=>13169, +48941=>13170, +48942=>13171, +48943=>13172, +48944=>13173, +48945=>13174, +48946=>13175, +48947=>13176, +48948=>13177, +48949=>13178, +48950=>13179, +48951=>13180, +48952=>13181, +48953=>13182, +48954=>13183, +48955=>13184, +48956=>13185, +48957=>13186, +48958=>13187, +48959=>13188, +48962=>13189, +48963=>13190, +48965=>13191, +48966=>13192, +48967=>13193, +48969=>13194, +48970=>13195, +48971=>13196, +48972=>13197, +48973=>13198, +48974=>13199, +48975=>13200, +48978=>13201, +48979=>13202, +48980=>13203, +48982=>13204, +48983=>13205, +48984=>13206, +48985=>13207, +48986=>13208, +48987=>13209, +48988=>13210, +48989=>13211, +48990=>13212, +48991=>13213, +48992=>13214, +48993=>13215, +48994=>13216, +48995=>13217, +48996=>13218, +48997=>13219, +48998=>13220, +48999=>13221, +49000=>13222, +49001=>13223, +49002=>13224, +49003=>13225, +49004=>13226, +49005=>13227, +49006=>13228, +49007=>13229, +49008=>13230, +49009=>13231, +49010=>13232, +49011=>13233, +49012=>13234, +49013=>13235, +49014=>13236, +49015=>13237, +49016=>13238, +49017=>13239, +49018=>13240, +49019=>13241, +49020=>13242, +49021=>13243, +49022=>13244, +49023=>13245, +49024=>13246, +49025=>13247, +49026=>13248, +49027=>13249, +49028=>13250, +49029=>13251, +49030=>13252, +49031=>13253, +49032=>13254, +49033=>13255, +49034=>13256, +49035=>13257, +49036=>13258, +49037=>13259, +49038=>13260, +49039=>13261, +49040=>13262, +49041=>13263, +49042=>13264, +49043=>13265, +49045=>13266, +49046=>13267, +49047=>13268, +49048=>13269, +49049=>13270, +49050=>13271, +49051=>13272, +49052=>13273, +49053=>13274, +49054=>13275, +49055=>13276, +49056=>13277, +49057=>13278, +49058=>13279, +49059=>13280, +49060=>13281, +49061=>13282, +49062=>13283, +49063=>13284, +49064=>13285, +49065=>13286, +49066=>13287, +49067=>13288, +49068=>13289, +49069=>13290, +49070=>13291, +49071=>13292, +49073=>13293, +49074=>13294, +49075=>13295, +49076=>13296, +49077=>13297, +49078=>13298, +49079=>13299, +49080=>13300, +49081=>13301, +49082=>13302, +49083=>13303, +49084=>13304, +49085=>13305, +49086=>13306, +49087=>13307, +49088=>13308, +49089=>13309, +49090=>13310, +49091=>13311, +49092=>13312, +49094=>13313, +49095=>13314, +49096=>13315, +49097=>13316, +49098=>13317, +49099=>13318, +49102=>13319, +49103=>13320, +49105=>13321, +49106=>13322, +49107=>13323, +49109=>13324, +49110=>13325, +49111=>13326, +49112=>13327, +49113=>13328, +49114=>13329, +49115=>13330, +49117=>13331, +49118=>13332, +49120=>13333, +49122=>13334, +49123=>13335, +49124=>13336, +49125=>13337, +49126=>13338, +49127=>13339, +49128=>13340, +49129=>13341, +49130=>13342, +49131=>13343, +49132=>13344, +49133=>13345, +49134=>13346, +49135=>13347, +49136=>13348, +49137=>13349, +49138=>13350, +49139=>13351, +49140=>13352, +49141=>13353, +49142=>13354, +49143=>13355, +49144=>13356, +49145=>13357, +49146=>13358, +49147=>13359, +49148=>13360, +49149=>13361, +49150=>13362, +49151=>13363, +49152=>13364, +49153=>13365, +49154=>13366, +49155=>13367, +49156=>13368, +49157=>13369, +49158=>13370, +49159=>13371, +49160=>13372, +49161=>13373, +49162=>13374, +49163=>13375, +49164=>13376, +49165=>13377, +49166=>13378, +49167=>13379, +49168=>13380, +49169=>13381, +49170=>13382, +49171=>13383, +49172=>13384, +49173=>13385, +49174=>13386, +49175=>13387, +49176=>13388, +49177=>13389, +49178=>13390, +49179=>13391, +49180=>13392, +49181=>13393, +49182=>13394, +49183=>13395, +49184=>13396, +49185=>13397, +49186=>13398, +49187=>13399, +49188=>13400, +49189=>13401, +49190=>13402, +49191=>13403, +49192=>13404, +49193=>13405, +49194=>13406, +49195=>13407, +49196=>13408, +49197=>13409, +49198=>13410, +49199=>13411, +49200=>13412, +49201=>13413, +49202=>13414, +49203=>13415, +49204=>13416, +49205=>13417, +49206=>13418, +49207=>13419, +49208=>13420, +49209=>13421, +49210=>13422, +49211=>13423, +49213=>13424, +49214=>13425, +49215=>13426, +49216=>13427, +49217=>13428, +49218=>13429, +49219=>13430, +49220=>13431, +49221=>13432, +49222=>13433, +49223=>13434, +49224=>13435, +49225=>13436, +49226=>13437, +49227=>13438, +49228=>13439, +49229=>13440, +49230=>13441, +49231=>13442, +49232=>13443, +49234=>13444, +49235=>13445, +49236=>13446, +49237=>13447, +49238=>13448, +49239=>13449, +49241=>13450, +49242=>13451, +49243=>13452, +49245=>13453, +49246=>13454, +49247=>13455, +49249=>13456, +49250=>13457, +49251=>13458, +49252=>13459, +49253=>13460, +49254=>13461, +49255=>13462, +49258=>13463, +49259=>13464, +49260=>13465, +49261=>13466, +49262=>13467, +49263=>13468, +49264=>13469, +49265=>13470, +49266=>13471, +49267=>13472, +49268=>13473, +49269=>13474, +49270=>13475, +49271=>13476, +49272=>13477, +49273=>13478, +49274=>13479, +49275=>13480, +49276=>13481, +49277=>13482, +49278=>13483, +49279=>13484, +49280=>13485, +49281=>13486, +49282=>13487, +49283=>13488, +49284=>13489, +49285=>13490, +49286=>13491, +49287=>13492, +49288=>13493, +49289=>13494, +49290=>13495, +49291=>13496, +49292=>13497, +49293=>13498, +49294=>13499, +49295=>13500, +49298=>13501, +49299=>13502, +49301=>13503, +49302=>13504, +49303=>13505, +49305=>13506, +49306=>13507, +49307=>13508, +49308=>13509, +49309=>13510, +49310=>13511, +49311=>13512, +49314=>13513, +49316=>13514, +49318=>13515, +49319=>13516, +49320=>13517, +49321=>13518, +49322=>13519, +49323=>13520, +49326=>13521, +49329=>13522, +49330=>13523, +49335=>13524, +49336=>13525, +49337=>13526, +49338=>13527, +49339=>13528, +49342=>13529, +49346=>13530, +49347=>13531, +49348=>13532, +49350=>13533, +49351=>13534, +49354=>13535, +49355=>13536, +49357=>13537, +49358=>13538, +49359=>13539, +49361=>13540, +49362=>13541, +49363=>13542, +49364=>13543, +49365=>13544, +49366=>13545, +49367=>13546, +49370=>13547, +49374=>13548, +49375=>13549, +49376=>13550, +49377=>13551, +49378=>13552, +49379=>13553, +49382=>13554, +49383=>13555, +49385=>13556, +49386=>13557, +49387=>13558, +49389=>13559, +49390=>13560, +49391=>13561, +49392=>13562, +49393=>13563, +49394=>13564, +49395=>13565, +49398=>13566, +49400=>13567, +49402=>13568, +49403=>13569, +49404=>13570, +49405=>13571, +49406=>13572, +49407=>13573, +49409=>13574, +49410=>13575, +49411=>13576, +49413=>13577, +49414=>13578, +49415=>13579, +49417=>13580, +49418=>13581, +49419=>13582, +49420=>13583, +49421=>13584, +49422=>13585, +49423=>13586, +49425=>13587, +49426=>13588, +49427=>13589, +49428=>13590, +49430=>13591, +49431=>13592, +49432=>13593, +49433=>13594, +49434=>13595, +49435=>13596, +49441=>13597, +49442=>13598, +49445=>13599, +49448=>13600, +49449=>13601, +49450=>13602, +49451=>13603, +49454=>13604, +49458=>13605, +49459=>13606, +49460=>13607, +49461=>13608, +49463=>13609, +49466=>13610, +49467=>13611, +49469=>13612, +49470=>13613, +49471=>13614, +49473=>13615, +49474=>13616, +49475=>13617, +49476=>13618, +49477=>13619, +49478=>13620, +49479=>13621, +49482=>13622, +49486=>13623, +49487=>13624, +49488=>13625, +49489=>13626, +49490=>13627, +49491=>13628, +49494=>13629, +49495=>13630, +49497=>13631, +49498=>13632, +49499=>13633, +49501=>13634, +49502=>13635, +49503=>13636, +49504=>13637, +49505=>13638, +49506=>13639, +49507=>13640, +49510=>13641, +49514=>13642, +49515=>13643, +49516=>13644, +49517=>13645, +49518=>13646, +49519=>13647, +49521=>13648, +49522=>13649, +49523=>13650, +49525=>13651, +49526=>13652, +49527=>13653, +49529=>13654, +49530=>13655, +49531=>13656, +49532=>13657, +49533=>13658, +49534=>13659, +49535=>13660, +49536=>13661, +49537=>13662, +49538=>13663, +49539=>13664, +49540=>13665, +49542=>13666, +49543=>13667, +49544=>13668, +49545=>13669, +49546=>13670, +49547=>13671, +49551=>13672, +49553=>13673, +49554=>13674, +49555=>13675, +49557=>13676, +49559=>13677, +49560=>13678, +49561=>13679, +49562=>13680, +49563=>13681, +49566=>13682, +49568=>13683, +49570=>13684, +49571=>13685, +49572=>13686, +49574=>13687, +49575=>13688, +49578=>13689, +49579=>13690, +49581=>13691, +49582=>13692, +49583=>13693, +49585=>13694, +49586=>13695, +49587=>13696, +49588=>13697, +49589=>13698, +49590=>13699, +49591=>13700, +49592=>13701, +49593=>13702, +49594=>13703, +49595=>13704, +49596=>13705, +49598=>13706, +49599=>13707, +49600=>13708, +49601=>13709, +49602=>13710, +49603=>13711, +49605=>13712, +49606=>13713, +49607=>13714, +49609=>13715, +49610=>13716, +49611=>13717, +49613=>13718, +49614=>13719, +49615=>13720, +49616=>13721, +49617=>13722, +49618=>13723, +49619=>13724, +49621=>13725, +49622=>13726, +49625=>13727, +49626=>13728, +49627=>13729, +49628=>13730, +49629=>13731, +49630=>13732, +49631=>13733, +49633=>13734, +49634=>13735, +49635=>13736, +49637=>13737, +49638=>13738, +49639=>13739, +49641=>13740, +49642=>13741, +49643=>13742, +49644=>13743, +49645=>13744, +49646=>13745, +49647=>13746, +49650=>13747, +49652=>13748, +49653=>13749, +49654=>13750, +49655=>13751, +49656=>13752, +49657=>13753, +49658=>13754, +49659=>13755, +49662=>13756, +49663=>13757, +49665=>13758, +49666=>13759, +49667=>13760, +49669=>13761, +49670=>13762, +49671=>13763, +49672=>13764, +49673=>13765, +49674=>13766, +49675=>13767, +49678=>13768, +49680=>13769, +49682=>13770, +49683=>13771, +49684=>13772, +49685=>13773, +49686=>13774, +49687=>13775, +49690=>13776, +49691=>13777, +49693=>13778, +49694=>13779, +49697=>13780, +49698=>13781, +49699=>13782, +49700=>13783, +49701=>13784, +49702=>13785, +49703=>13786, +49706=>13787, +49708=>13788, +49710=>13789, +49712=>13790, +49715=>13791, +49717=>13792, +49718=>13793, +49719=>13794, +49720=>13795, +49721=>13796, +49722=>13797, +49723=>13798, +49724=>13799, +49725=>13800, +49726=>13801, +49727=>13802, +49728=>13803, +49729=>13804, +49730=>13805, +49731=>13806, +49732=>13807, +49733=>13808, +49734=>13809, +49735=>13810, +49737=>13811, +49738=>13812, +49739=>13813, +49740=>13814, +49741=>13815, +49742=>13816, +49743=>13817, +49746=>13818, +49747=>13819, +49749=>13820, +49750=>13821, +49751=>13822, +49753=>13823, +49754=>13824, +49755=>13825, +49756=>13826, +49757=>13827, +49758=>13828, +49759=>13829, +49761=>13830, +49762=>13831, +49763=>13832, +49764=>13833, +49766=>13834, +49767=>13835, +49768=>13836, +49769=>13837, +49770=>13838, +49771=>13839, +49774=>13840, +49775=>13841, +49777=>13842, +49778=>13843, +49779=>13844, +49781=>13845, +49782=>13846, +49783=>13847, +49784=>13848, +49785=>13849, +49786=>13850, +49787=>13851, +49790=>13852, +49792=>13853, +49794=>13854, +49795=>13855, +49796=>13856, +49797=>13857, +49798=>13858, +49799=>13859, +49802=>13860, +49803=>13861, +49804=>13862, +49805=>13863, +49806=>13864, +49807=>13865, +49809=>13866, +49810=>13867, +49811=>13868, +49812=>13869, +49813=>13870, +49814=>13871, +49815=>13872, +49817=>13873, +49818=>13874, +49820=>13875, +49822=>13876, +49823=>13877, +49824=>13878, +49825=>13879, +49826=>13880, +49827=>13881, +49830=>13882, +49831=>13883, +49833=>13884, +49834=>13885, +49835=>13886, +49838=>13887, +49839=>13888, +49840=>13889, +49841=>13890, +49842=>13891, +49843=>13892, +49846=>13893, +49848=>13894, +49850=>13895, +49851=>13896, +49852=>13897, +49853=>13898, +49854=>13899, +49855=>13900, +49856=>13901, +49857=>13902, +49858=>13903, +49859=>13904, +49860=>13905, +49861=>13906, +49862=>13907, +49863=>13908, +49864=>13909, +49865=>13910, +49866=>13911, +49867=>13912, +49868=>13913, +49869=>13914, +49870=>13915, +49871=>13916, +49872=>13917, +49873=>13918, +49874=>13919, +49875=>13920, +49876=>13921, +49877=>13922, +49878=>13923, +49879=>13924, +49880=>13925, +49881=>13926, +49882=>13927, +49883=>13928, +49886=>13929, +49887=>13930, +49889=>13931, +49890=>13932, +49893=>13933, +49894=>13934, +49895=>13935, +49896=>13936, +49897=>13937, +49898=>13938, +49902=>13939, +49904=>13940, +49906=>13941, +49907=>13942, +49908=>13943, +49909=>13944, +49911=>13945, +49914=>13946, +49917=>13947, +49918=>13948, +49919=>13949, +49921=>13950, +49922=>13951, +49923=>13952, +49924=>13953, +49925=>13954, +49926=>13955, +49927=>13956, +49930=>13957, +49931=>13958, +49934=>13959, +49935=>13960, +49936=>13961, +49937=>13962, +49938=>13963, +49942=>13964, +49943=>13965, +49945=>13966, +49946=>13967, +49947=>13968, +49949=>13969, +49950=>13970, +49951=>13971, +49952=>13972, +49953=>13973, +49954=>13974, +49955=>13975, +49958=>13976, +49959=>13977, +49962=>13978, +49963=>13979, +49964=>13980, +49965=>13981, +49966=>13982, +49967=>13983, +49968=>13984, +49969=>13985, +49970=>13986, +49971=>13987, +49972=>13988, +49973=>13989, +49974=>13990, +49975=>13991, +49976=>13992, +49977=>13993, +49978=>13994, +49979=>13995, +49980=>13996, +49981=>13997, +49982=>13998, +49983=>13999, +49984=>14000, +49985=>14001, +49986=>14002, +49987=>14003, +49988=>14004, +49990=>14005, +49991=>14006, +49992=>14007, +49993=>14008, +49994=>14009, +49995=>14010, +49996=>14011, +49997=>14012, +49998=>14013, +49999=>14014, +50000=>14015, +50001=>14016, +50002=>14017, +50003=>14018, +50004=>14019, +50005=>14020, +50006=>14021, +50007=>14022, +50008=>14023, +50009=>14024, +50010=>14025, +50011=>14026, +50012=>14027, +50013=>14028, +50014=>14029, +50015=>14030, +50016=>14031, +50017=>14032, +50018=>14033, +50019=>14034, +50020=>14035, +50021=>14036, +50022=>14037, +50023=>14038, +50026=>14039, +50027=>14040, +50029=>14041, +50030=>14042, +50031=>14043, +50033=>14044, +50035=>14045, +50036=>14046, +50037=>14047, +50038=>14048, +50039=>14049, +50042=>14050, +50043=>14051, +50046=>14052, +50047=>14053, +50048=>14054, +50049=>14055, +50050=>14056, +50051=>14057, +50053=>14058, +50054=>14059, +50055=>14060, +50057=>14061, +50058=>14062, +50059=>14063, +50061=>14064, +50062=>14065, +50063=>14066, +50064=>14067, +50065=>14068, +50066=>14069, +50067=>14070, +50068=>14071, +50069=>14072, +50070=>14073, +50071=>14074, +50072=>14075, +50073=>14076, +50074=>14077, +50075=>14078, +50076=>14079, +50077=>14080, +50078=>14081, +50079=>14082, +50080=>14083, +50081=>14084, +50082=>14085, +50083=>14086, +50084=>14087, +50085=>14088, +50086=>14089, +50087=>14090, +50088=>14091, +50089=>14092, +50090=>14093, +50091=>14094, +50092=>14095, +50093=>14096, +50094=>14097, +50095=>14098, +50096=>14099, +50097=>14100, +50098=>14101, +50099=>14102, +50100=>14103, +50101=>14104, +50102=>14105, +50103=>14106, +50104=>14107, +50105=>14108, +50106=>14109, +50107=>14110, +50108=>14111, +50109=>14112, +50110=>14113, +50111=>14114, +50113=>14115, +50114=>14116, +50115=>14117, +50116=>14118, +50117=>14119, +50118=>14120, +50119=>14121, +50120=>14122, +50121=>14123, +50122=>14124, +50123=>14125, +50124=>14126, +50125=>14127, +50126=>14128, +50127=>14129, +50128=>14130, +50129=>14131, +50130=>14132, +50131=>14133, +50132=>14134, +50133=>14135, +50134=>14136, +50135=>14137, +50138=>14138, +50139=>14139, +50141=>14140, +50142=>14141, +50145=>14142, +50147=>14143, +50148=>14144, +50149=>14145, +50150=>14146, +50151=>14147, +50154=>14148, +50155=>14149, +50156=>14150, +50158=>14151, +50159=>14152, +50160=>14153, +50161=>14154, +50162=>14155, +50163=>14156, +50166=>14157, +50167=>14158, +50169=>14159, +50170=>14160, +50171=>14161, +50172=>14162, +50173=>14163, +50174=>14164, +50175=>14165, +50176=>14166, +50177=>14167, +50178=>14168, +50179=>14169, +50180=>14170, +50181=>14171, +50182=>14172, +50183=>14173, +50185=>14174, +50186=>14175, +50187=>14176, +50188=>14177, +50189=>14178, +50190=>14179, +50191=>14180, +50193=>14181, +50194=>14182, +50195=>14183, +50196=>14184, +50197=>14185, +50198=>14186, +50199=>14187, +50200=>14188, +50201=>14189, +50202=>14190, +50203=>14191, +50204=>14192, +50205=>14193, +50206=>14194, +50207=>14195, +50208=>14196, +50209=>14197, +50210=>14198, +50211=>14199, +50213=>14200, +50214=>14201, +50215=>14202, +50216=>14203, +50217=>14204, +50218=>14205, +50219=>14206, +50221=>14207, +50222=>14208, +50223=>14209, +50225=>14210, +50226=>14211, +50227=>14212, +50229=>14213, +50230=>14214, +50231=>14215, +50232=>14216, +50233=>14217, +50234=>14218, +50235=>14219, +50238=>14220, +50239=>14221, +50240=>14222, +50241=>14223, +50242=>14224, +50243=>14225, +50244=>14226, +50245=>14227, +50246=>14228, +50247=>14229, +50249=>14230, +50250=>14231, +50251=>14232, +50252=>14233, +50253=>14234, +50254=>14235, +50255=>14236, +50256=>14237, +50257=>14238, +50258=>14239, +50259=>14240, +50260=>14241, +50261=>14242, +50262=>14243, +50263=>14244, +50264=>14245, +50265=>14246, +50266=>14247, +50267=>14248, +50268=>14249, +50269=>14250, +50270=>14251, +50271=>14252, +50272=>14253, +50273=>14254, +50274=>14255, +50275=>14256, +50278=>14257, +50279=>14258, +50281=>14259, +50282=>14260, +50283=>14261, +50285=>14262, +50286=>14263, +50287=>14264, +50288=>14265, +50289=>14266, +50290=>14267, +50291=>14268, +50294=>14269, +50295=>14270, +50296=>14271, +50298=>14272, +50299=>14273, +50300=>14274, +50301=>14275, +50302=>14276, +50303=>14277, +50305=>14278, +50306=>14279, +50307=>14280, +50308=>14281, +50309=>14282, +50310=>14283, +50311=>14284, +50312=>14285, +50313=>14286, +50314=>14287, +50315=>14288, +50316=>14289, +50317=>14290, +50318=>14291, +50319=>14292, +50320=>14293, +50321=>14294, +50322=>14295, +50323=>14296, +50325=>14297, +50326=>14298, +50327=>14299, +50328=>14300, +50329=>14301, +50330=>14302, +50331=>14303, +50333=>14304, +50334=>14305, +50335=>14306, +50336=>14307, +50337=>14308, +50338=>14309, +50339=>14310, +50340=>14311, +50341=>14312, +50342=>14313, +50343=>14314, +50344=>14315, +50345=>14316, +50346=>14317, +50347=>14318, +50348=>14319, +50349=>14320, +50350=>14321, +50351=>14322, +50352=>14323, +50353=>14324, +50354=>14325, +50355=>14326, +50356=>14327, +50357=>14328, +50358=>14329, +50359=>14330, +50361=>14331, +50362=>14332, +50363=>14333, +50365=>14334, +50366=>14335, +50367=>14336, +50368=>14337, +50369=>14338, +50370=>14339, +50371=>14340, +50372=>14341, +50373=>14342, +50374=>14343, +50375=>14344, +50376=>14345, +50377=>14346, +50378=>14347, +50379=>14348, +50380=>14349, +50381=>14350, +50382=>14351, +50383=>14352, +50384=>14353, +50385=>14354, +50386=>14355, +50387=>14356, +50388=>14357, +50389=>14358, +50390=>14359, +50391=>14360, +50392=>14361, +50393=>14362, +50394=>14363, +50395=>14364, +50396=>14365, +50397=>14366, +50398=>14367, +50399=>14368, +50400=>14369, +50401=>14370, +50402=>14371, +50403=>14372, +50404=>14373, +50405=>14374, +50406=>14375, +50407=>14376, +50408=>14377, +50410=>14378, +50411=>14379, +50412=>14380, +50413=>14381, +50414=>14382, +50415=>14383, +50418=>14384, +50419=>14385, +50421=>14386, +50422=>14387, +50423=>14388, +50425=>14389, +50427=>14390, +50428=>14391, +50429=>14392, +50430=>14393, +50434=>14394, +50435=>14395, +50436=>14396, +50437=>14397, +50438=>14398, +50439=>14399, +50440=>14400, +50441=>14401, +50442=>14402, +50443=>14403, +50445=>14404, +50446=>14405, +50447=>14406, +50449=>14407, +50450=>14408, +50451=>14409, +50453=>14410, +50454=>14411, +50455=>14412, +50456=>14413, +50457=>14414, +50458=>14415, +50459=>14416, +50461=>14417, +50462=>14418, +50463=>14419, +50464=>14420, +50465=>14421, +50466=>14422, +50467=>14423, +50468=>14424, +50469=>14425, +50470=>14426, +50471=>14427, +50474=>14428, +50475=>14429, +50477=>14430, +50478=>14431, +50479=>14432, +50481=>14433, +50482=>14434, +50483=>14435, +50484=>14436, +50485=>14437, +50486=>14438, +50487=>14439, +50490=>14440, +50492=>14441, +50494=>14442, +50495=>14443, +50496=>14444, +50497=>14445, +50498=>14446, +50499=>14447, +50502=>14448, +50503=>14449, +50507=>14450, +50511=>14451, +50512=>14452, +50513=>14453, +50514=>14454, +50518=>14455, +50522=>14456, +50523=>14457, +50524=>14458, +50527=>14459, +50530=>14460, +50531=>14461, +50533=>14462, +50534=>14463, +50535=>14464, +50537=>14465, +50538=>14466, +50539=>14467, +50540=>14468, +50541=>14469, +50542=>14470, +50543=>14471, +50546=>14472, +50550=>14473, +50551=>14474, +50552=>14475, +50553=>14476, +50554=>14477, +50555=>14478, +50558=>14479, +50559=>14480, +50561=>14481, +50562=>14482, +50563=>14483, +50565=>14484, +50566=>14485, +50568=>14486, +50569=>14487, +50570=>14488, +50571=>14489, +50574=>14490, +50576=>14491, +50578=>14492, +50579=>14493, +50580=>14494, +50582=>14495, +50585=>14496, +50586=>14497, +50587=>14498, +50589=>14499, +50590=>14500, +50591=>14501, +50593=>14502, +50594=>14503, +50595=>14504, +50596=>14505, +50597=>14506, +50598=>14507, +50599=>14508, +50600=>14509, +50602=>14510, +50603=>14511, +50604=>14512, +50605=>14513, +50606=>14514, +50607=>14515, +50608=>14516, +50609=>14517, +50610=>14518, +50611=>14519, +50614=>14520, +50615=>14521, +50618=>14522, +50623=>14523, +50624=>14524, +50625=>14525, +50626=>14526, +50627=>14527, +50635=>14528, +50637=>14529, +50639=>14530, +50642=>14531, +50643=>14532, +50645=>14533, +50646=>14534, +50647=>14535, +50649=>14536, +50650=>14537, +50651=>14538, +50652=>14539, +50653=>14540, +50654=>14541, +50655=>14542, +50658=>14543, +50660=>14544, +50662=>14545, +50663=>14546, +50664=>14547, +50665=>14548, +50666=>14549, +50667=>14550, +50671=>14551, +50673=>14552, +50674=>14553, +50675=>14554, +50677=>14555, +50680=>14556, +50681=>14557, +50682=>14558, +50683=>14559, +50690=>14560, +50691=>14561, +50692=>14562, +50697=>14563, +50698=>14564, +50699=>14565, +50701=>14566, +50702=>14567, +50703=>14568, +50705=>14569, +50706=>14570, +50707=>14571, +50708=>14572, +50709=>14573, +50710=>14574, +50711=>14575, +50714=>14576, +50717=>14577, +50718=>14578, +50719=>14579, +50720=>14580, +50721=>14581, +50722=>14582, +50723=>14583, +50726=>14584, +50727=>14585, +50729=>14586, +50730=>14587, +50731=>14588, +50735=>14589, +50737=>14590, +50738=>14591, +50742=>14592, +50744=>14593, +50746=>14594, +50748=>14595, +50749=>14596, +50750=>14597, +50751=>14598, +50754=>14599, +50755=>14600, +50757=>14601, +50758=>14602, +50759=>14603, +50761=>14604, +50762=>14605, +50763=>14606, +50764=>14607, +50765=>14608, +50766=>14609, +50767=>14610, +50770=>14611, +50774=>14612, +50775=>14613, +50776=>14614, +50777=>14615, +50778=>14616, +50779=>14617, +50782=>14618, +50783=>14619, +50785=>14620, +50786=>14621, +50787=>14622, +50788=>14623, +50789=>14624, +50790=>14625, +50791=>14626, +50792=>14627, +50793=>14628, +50794=>14629, +50795=>14630, +50797=>14631, +50798=>14632, +50800=>14633, +50802=>14634, +50803=>14635, +50804=>14636, +50805=>14637, +50806=>14638, +50807=>14639, +50810=>14640, +50811=>14641, +50813=>14642, +50814=>14643, +50815=>14644, +50817=>14645, +50818=>14646, +50819=>14647, +50820=>14648, +50821=>14649, +50822=>14650, +50823=>14651, +50826=>14652, +50828=>14653, +50830=>14654, +50831=>14655, +50832=>14656, +50833=>14657, +50834=>14658, +50835=>14659, +50838=>14660, +50839=>14661, +50841=>14662, +50842=>14663, +50843=>14664, +50845=>14665, +50846=>14666, +50847=>14667, +50848=>14668, +50849=>14669, +50850=>14670, +50851=>14671, +50854=>14672, +50856=>14673, +50858=>14674, +50859=>14675, +50860=>14676, +50861=>14677, +50862=>14678, +50863=>14679, +50866=>14680, +50867=>14681, +50869=>14682, +50870=>14683, +50871=>14684, +50875=>14685, +50876=>14686, +50877=>14687, +50878=>14688, +50879=>14689, +50882=>14690, +50884=>14691, +50886=>14692, +50887=>14693, +50888=>14694, +50889=>14695, +50890=>14696, +50891=>14697, +50894=>14698, +50895=>14699, +50897=>14700, +50898=>14701, +50899=>14702, +50901=>14703, +50902=>14704, +50903=>14705, +50904=>14706, +50905=>14707, +50906=>14708, +50907=>14709, +50910=>14710, +50911=>14711, +50914=>14712, +50915=>14713, +50916=>14714, +50917=>14715, +50918=>14716, +50919=>14717, +50922=>14718, +50923=>14719, +50925=>14720, +50926=>14721, +50927=>14722, +50929=>14723, +50930=>14724, +50931=>14725, +50932=>14726, +50933=>14727, +50934=>14728, +50935=>14729, +50938=>14730, +50939=>14731, +50940=>14732, +50942=>14733, +50943=>14734, +50944=>14735, +50945=>14736, +50946=>14737, +50947=>14738, +50950=>14739, +50951=>14740, +50953=>14741, +50954=>14742, +50955=>14743, +50957=>14744, +50958=>14745, +50959=>14746, +50960=>14747, +50961=>14748, +50962=>14749, +50963=>14750, +50966=>14751, +50968=>14752, +50970=>14753, +50971=>14754, +50972=>14755, +50973=>14756, +50974=>14757, +50975=>14758, +50978=>14759, +50979=>14760, +50981=>14761, +50982=>14762, +50983=>14763, +50985=>14764, +50986=>14765, +50987=>14766, +50988=>14767, +50989=>14768, +50990=>14769, +50991=>14770, +50994=>14771, +50996=>14772, +50998=>14773, +51000=>14774, +51001=>14775, +51002=>14776, +51003=>14777, +51006=>14778, +51007=>14779, +51009=>14780, +51010=>14781, +51011=>14782, +51013=>14783, +51014=>14784, +51015=>14785, +51016=>14786, +51017=>14787, +51019=>14788, +51022=>14789, +51024=>14790, +51033=>14791, +51034=>14792, +51035=>14793, +51037=>14794, +51038=>14795, +51039=>14796, +51041=>14797, +51042=>14798, +51043=>14799, +51044=>14800, +51045=>14801, +51046=>14802, +51047=>14803, +51049=>14804, +51050=>14805, +51052=>14806, +51053=>14807, +51054=>14808, +51055=>14809, +51056=>14810, +51057=>14811, +51058=>14812, +51059=>14813, +51062=>14814, +51063=>14815, +51065=>14816, +51066=>14817, +51067=>14818, +51071=>14819, +51072=>14820, +51073=>14821, +51074=>14822, +51078=>14823, +51083=>14824, +51084=>14825, +51085=>14826, +51087=>14827, +51090=>14828, +51091=>14829, +51093=>14830, +51097=>14831, +51099=>14832, +51100=>14833, +51101=>14834, +51102=>14835, +51103=>14836, +51106=>14837, +51111=>14838, +51112=>14839, +51113=>14840, +51114=>14841, +51115=>14842, +51118=>14843, +51119=>14844, +51121=>14845, +51122=>14846, +51123=>14847, +51125=>14848, +51126=>14849, +51127=>14850, +51128=>14851, +51129=>14852, +51130=>14853, +51131=>14854, +51134=>14855, +51138=>14856, +51139=>14857, +51140=>14858, +51141=>14859, +51142=>14860, +51143=>14861, +51146=>14862, +51147=>14863, +51149=>14864, +51151=>14865, +51153=>14866, +51154=>14867, +51155=>14868, +51156=>14869, +51157=>14870, +51158=>14871, +51159=>14872, +51161=>14873, +51162=>14874, +51163=>14875, +51164=>14876, +51166=>14877, +51167=>14878, +51168=>14879, +51169=>14880, +51170=>14881, +51171=>14882, +51173=>14883, +51174=>14884, +51175=>14885, +51177=>14886, +51178=>14887, +51179=>14888, +51181=>14889, +51182=>14890, +51183=>14891, +51184=>14892, +51185=>14893, +51186=>14894, +51187=>14895, +51188=>14896, +51189=>14897, +51190=>14898, +51191=>14899, +51192=>14900, +51193=>14901, +51194=>14902, +51195=>14903, +51196=>14904, +51197=>14905, +51198=>14906, +51199=>14907, +51202=>14908, +51203=>14909, +51205=>14910, +51206=>14911, +51207=>14912, +51209=>14913, +51211=>14914, +51212=>14915, +51213=>14916, +51214=>14917, +51215=>14918, +51218=>14919, +51220=>14920, +51223=>14921, +51224=>14922, +51225=>14923, +51226=>14924, +51227=>14925, +51230=>14926, +51231=>14927, +51233=>14928, +51234=>14929, +51235=>14930, +51237=>14931, +51238=>14932, +51239=>14933, +51240=>14934, +51241=>14935, +51242=>14936, +51243=>14937, +51246=>14938, +51248=>14939, +51250=>14940, +51251=>14941, +51252=>14942, +51253=>14943, +51254=>14944, +51255=>14945, +51257=>14946, +51258=>14947, +51259=>14948, +51261=>14949, +51262=>14950, +51263=>14951, +51265=>14952, +51266=>14953, +51267=>14954, +51268=>14955, +51269=>14956, +51270=>14957, +51271=>14958, +51274=>14959, +51275=>14960, +51278=>14961, +51279=>14962, +51280=>14963, +51281=>14964, +51282=>14965, +51283=>14966, +51285=>14967, +51286=>14968, +51287=>14969, +51288=>14970, +51289=>14971, +51290=>14972, +51291=>14973, +51292=>14974, +51293=>14975, +51294=>14976, +51295=>14977, +51296=>14978, +51297=>14979, +51298=>14980, +51299=>14981, +51300=>14982, +51301=>14983, +51302=>14984, +51303=>14985, +51304=>14986, +51305=>14987, +51306=>14988, +51307=>14989, +51308=>14990, +51309=>14991, +51310=>14992, +51311=>14993, +51314=>14994, +51315=>14995, +51317=>14996, +51318=>14997, +51319=>14998, +51321=>14999, +51323=>15000, +51324=>15001, +51325=>15002, +51326=>15003, +51327=>15004, +51330=>15005, +51332=>15006, +51336=>15007, +51337=>15008, +51338=>15009, +51342=>15010, +51343=>15011, +51344=>15012, +51345=>15013, +51346=>15014, +51347=>15015, +51349=>15016, +51350=>15017, +51351=>15018, +51352=>15019, +51353=>15020, +51354=>15021, +51355=>15022, +51356=>15023, +51358=>15024, +51360=>15025, +51362=>15026, +51363=>15027, +51364=>15028, +51365=>15029, +51366=>15030, +51367=>15031, +51369=>15032, +51370=>15033, +51371=>15034, +51372=>15035, +51373=>15036, +51374=>15037, +51375=>15038, +51376=>15039, +51377=>15040, +51378=>15041, +51379=>15042, +51380=>15043, +51381=>15044, +51382=>15045, +51383=>15046, +51384=>15047, +51385=>15048, +51386=>15049, +51387=>15050, +51390=>15051, +51391=>15052, +51392=>15053, +51393=>15054, +51394=>15055, +51395=>15056, +51397=>15057, +51398=>15058, +51399=>15059, +51401=>15060, +51402=>15061, +51403=>15062, +51405=>15063, +51406=>15064, +51407=>15065, +51408=>15066, +51409=>15067, +51410=>15068, +51411=>15069, +51414=>15070, +51416=>15071, +51418=>15072, +51419=>15073, +51420=>15074, +51421=>15075, +51422=>15076, +51423=>15077, +51426=>15078, +51427=>15079, +51429=>15080, +51430=>15081, +51431=>15082, +51432=>15083, +51433=>15084, +51434=>15085, +51435=>15086, +51436=>15087, +51437=>15088, +51438=>15089, +51439=>15090, +51440=>15091, +51441=>15092, +51442=>15093, +51443=>15094, +51444=>15095, +51446=>15096, +51447=>15097, +51448=>15098, +51449=>15099, +51450=>15100, +51451=>15101, +51454=>15102, +51455=>15103, +51457=>15104, +51458=>15105, +51459=>15106, +51463=>15107, +51464=>15108, +51465=>15109, +51466=>15110, +51467=>15111, +51470=>15112, +51472=>15113, +51474=>15114, +51475=>15115, +51476=>15116, +51477=>15117, +51478=>15118, +51479=>15119, +51481=>15120, +51482=>15121, +51483=>15122, +51484=>15123, +51485=>15124, +51486=>15125, +51487=>15126, +51488=>15127, +51489=>15128, +51490=>15129, +51491=>15130, +51492=>15131, +51493=>15132, +51494=>15133, +51495=>15134, +51496=>15135, +51497=>15136, +51498=>15137, +51499=>15138, +51501=>15139, +51502=>15140, +51503=>15141, +51504=>15142, +51505=>15143, +51506=>15144, +51507=>15145, +51509=>15146, +51510=>15147, +51511=>15148, +51512=>15149, +51513=>15150, +51514=>15151, +51515=>15152, +51516=>15153, +51517=>15154, +51518=>15155, +51519=>15156, +51520=>15157, +51521=>15158, +51522=>15159, +51523=>15160, +51524=>15161, +51525=>15162, +51526=>15163, +51527=>15164, +51528=>15165, +51529=>15166, +51530=>15167, +51531=>15168, +51532=>15169, +51533=>15170, +51534=>15171, +51535=>15172, +51538=>15173, +51539=>15174, +51541=>15175, +51542=>15176, +51543=>15177, +51545=>15178, +51546=>15179, +51547=>15180, +51548=>15181, +51549=>15182, +51550=>15183, +51551=>15184, +51554=>15185, +51556=>15186, +51557=>15187, +51558=>15188, +51559=>15189, +51560=>15190, +51561=>15191, +51562=>15192, +51563=>15193, +51565=>15194, +51566=>15195, +51567=>15196, +51569=>15197, +51570=>15198, +51571=>15199, +51573=>15200, +51574=>15201, +51575=>15202, +51576=>15203, +51577=>15204, +51578=>15205, +51579=>15206, +51581=>15207, +51582=>15208, +51583=>15209, +51584=>15210, +51585=>15211, +51586=>15212, +51587=>15213, +51588=>15214, +51589=>15215, +51590=>15216, +51591=>15217, +51594=>15218, +51595=>15219, +51597=>15220, +51598=>15221, +51599=>15222, +51601=>15223, +51602=>15224, +51603=>15225, +51604=>15226, +51605=>15227, +51606=>15228, +51607=>15229, +51610=>15230, +51612=>15231, +51614=>15232, +51615=>15233, +51616=>15234, +51617=>15235, +51618=>15236, +51619=>15237, +51620=>15238, +51621=>15239, +51622=>15240, +51623=>15241, +51624=>15242, +51625=>15243, +51626=>15244, +51627=>15245, +51628=>15246, +51629=>15247, +51630=>15248, +51631=>15249, +51632=>15250, +51633=>15251, +51634=>15252, +51635=>15253, +51636=>15254, +51637=>15255, +51638=>15256, +51639=>15257, +51640=>15258, +51641=>15259, +51642=>15260, +51643=>15261, +51644=>15262, +51645=>15263, +51646=>15264, +51647=>15265, +51650=>15266, +51651=>15267, +51653=>15268, +51654=>15269, +51657=>15270, +51659=>15271, +51660=>15272, +51661=>15273, +51662=>15274, +51663=>15275, +51666=>15276, +51668=>15277, +51671=>15278, +51672=>15279, +51675=>15280, +51678=>15281, +51679=>15282, +51681=>15283, +51683=>15284, +51685=>15285, +51686=>15286, +51688=>15287, +51689=>15288, +51690=>15289, +51691=>15290, +51694=>15291, +51698=>15292, +51699=>15293, +51700=>15294, +51701=>15295, +51702=>15296, +51703=>15297, +51706=>15298, +51707=>15299, +51709=>15300, +51710=>15301, +51711=>15302, +51713=>15303, +51714=>15304, +51715=>15305, +51716=>15306, +51717=>15307, +51718=>15308, +51719=>15309, +51722=>15310, +51726=>15311, +51727=>15312, +51728=>15313, +51729=>15314, +51730=>15315, +51731=>15316, +51733=>15317, +51734=>15318, +51735=>15319, +51737=>15320, +51738=>15321, +51739=>15322, +51740=>15323, +51741=>15324, +51742=>15325, +51743=>15326, +51744=>15327, +51745=>15328, +51746=>15329, +51747=>15330, +51748=>15331, +51749=>15332, +51750=>15333, +51751=>15334, +51752=>15335, +51754=>15336, +51755=>15337, +51756=>15338, +51757=>15339, +51758=>15340, +51759=>15341, +51760=>15342, +51761=>15343, +51762=>15344, +51763=>15345, +51764=>15346, +51765=>15347, +51766=>15348, +51767=>15349, +51768=>15350, +51769=>15351, +51770=>15352, +51771=>15353, +51772=>15354, +51773=>15355, +51774=>15356, +51775=>15357, +51776=>15358, +51777=>15359, +51778=>15360, +51779=>15361, +51780=>15362, +51781=>15363, +51782=>15364, +51783=>15365, +51784=>15366, +51785=>15367, +51786=>15368, +51787=>15369, +51790=>15370, +51791=>15371, +51793=>15372, +51794=>15373, +51795=>15374, +51797=>15375, +51798=>15376, +51799=>15377, +51800=>15378, +51801=>15379, +51802=>15380, +51803=>15381, +51806=>15382, +51810=>15383, +51811=>15384, +51812=>15385, +51813=>15386, +51814=>15387, +51815=>15388, +51817=>15389, +51818=>15390, +51819=>15391, +51820=>15392, +51821=>15393, +51822=>15394, +51823=>15395, +51824=>15396, +51825=>15397, +51826=>15398, +51827=>15399, +51828=>15400, +51829=>15401, +51830=>15402, +51831=>15403, +51832=>15404, +51833=>15405, +51834=>15406, +51835=>15407, +51836=>15408, +51838=>15409, +51839=>15410, +51840=>15411, +51841=>15412, +51842=>15413, +51843=>15414, +51845=>15415, +51846=>15416, +51847=>15417, +51848=>15418, +51849=>15419, +51850=>15420, +51851=>15421, +51852=>15422, +51853=>15423, +51854=>15424, +51855=>15425, +51856=>15426, +51857=>15427, +51858=>15428, +51859=>15429, +51860=>15430, +51861=>15431, +51862=>15432, +51863=>15433, +51865=>15434, +51866=>15435, +51867=>15436, +51868=>15437, +51869=>15438, +51870=>15439, +51871=>15440, +51872=>15441, +51873=>15442, +51874=>15443, +51875=>15444, +51876=>15445, +51877=>15446, +51878=>15447, +51879=>15448, +51880=>15449, +51881=>15450, +51882=>15451, +51883=>15452, +51884=>15453, +51885=>15454, +51886=>15455, +51887=>15456, +51888=>15457, +51889=>15458, +51890=>15459, +51891=>15460, +51892=>15461, +51893=>15462, +51894=>15463, +51895=>15464, +51896=>15465, +51897=>15466, +51898=>15467, +51899=>15468, +51902=>15469, +51903=>15470, +51905=>15471, +51906=>15472, +51907=>15473, +51909=>15474, +51910=>15475, +51911=>15476, +51912=>15477, +51913=>15478, +51914=>15479, +51915=>15480, +51918=>15481, +51920=>15482, +51922=>15483, +51924=>15484, +51925=>15485, +51926=>15486, +51927=>15487, +51930=>15488, +51931=>15489, +51932=>15490, +51933=>15491, +51934=>15492, +51935=>15493, +51937=>15494, +51938=>15495, +51939=>15496, +51940=>15497, +51941=>15498, +51942=>15499, +51943=>15500, +51944=>15501, +51945=>15502, +51946=>15503, +51947=>15504, +51949=>15505, +51950=>15506, +51951=>15507, +51952=>15508, +51953=>15509, +51954=>15510, +51955=>15511, +51957=>15512, +51958=>15513, +51959=>15514, +51960=>15515, +51961=>15516, +51962=>15517, +51963=>15518, +51964=>15519, +51965=>15520, +51966=>15521, +51967=>15522, +51968=>15523, +51969=>15524, +51970=>15525, +51971=>15526, +51972=>15527, +51973=>15528, +51974=>15529, +51975=>15530, +51977=>15531, +51978=>15532, +51979=>15533, +51980=>15534, +51981=>15535, +51982=>15536, +51983=>15537, +51985=>15538, +51986=>15539, +51987=>15540, +51989=>15541, +51990=>15542, +51991=>15543, +51993=>15544, +51994=>15545, +51995=>15546, +51996=>15547, +51997=>15548, +51998=>15549, +51999=>15550, +52002=>15551, +52003=>15552, +52004=>15553, +52005=>15554, +52006=>15555, +52007=>15556, +52008=>15557, +52009=>15558, +52010=>15559, +52011=>15560, +52012=>15561, +52013=>15562, +52014=>15563, +52015=>15564, +52016=>15565, +52017=>15566, +52018=>15567, +52019=>15568, +52020=>15569, +52021=>15570, +52022=>15571, +52023=>15572, +52024=>15573, +52025=>15574, +52026=>15575, +52027=>15576, +52028=>15577, +52029=>15578, +52030=>15579, +52031=>15580, +52032=>15581, +52034=>15582, +52035=>15583, +52036=>15584, +52037=>15585, +52038=>15586, +52039=>15587, +52042=>15588, +52043=>15589, +52045=>15590, +52046=>15591, +52047=>15592, +52049=>15593, +52050=>15594, +52051=>15595, +52052=>15596, +52053=>15597, +52054=>15598, +52055=>15599, +52058=>15600, +52059=>15601, +52060=>15602, +52062=>15603, +52063=>15604, +52064=>15605, +52065=>15606, +52066=>15607, +52067=>15608, +52069=>15609, +52070=>15610, +52071=>15611, +52072=>15612, +52073=>15613, +52074=>15614, +52075=>15615, +52076=>15616, +52077=>15617, +52078=>15618, +52079=>15619, +52080=>15620, +52081=>15621, +52082=>15622, +52083=>15623, +52084=>15624, +52085=>15625, +52086=>15626, +52087=>15627, +52090=>15628, +52091=>15629, +52092=>15630, +52093=>15631, +52094=>15632, +52095=>15633, +52096=>15634, +52097=>15635, +52098=>15636, +52099=>15637, +52100=>15638, +52101=>15639, +52102=>15640, +52103=>15641, +52104=>15642, +52105=>15643, +52106=>15644, +52107=>15645, +52108=>15646, +52109=>15647, +52110=>15648, +52111=>15649, +52112=>15650, +52113=>15651, +52114=>15652, +52115=>15653, +52116=>15654, +52117=>15655, +52118=>15656, +52119=>15657, +52120=>15658, +52121=>15659, +52122=>15660, +52123=>15661, +52125=>15662, +52126=>15663, +52127=>15664, +52128=>15665, +52129=>15666, +52130=>15667, +52131=>15668, +52132=>15669, +52133=>15670, +52134=>15671, +52135=>15672, +52136=>15673, +52137=>15674, +52138=>15675, +52139=>15676, +52140=>15677, +52141=>15678, +52142=>15679, +52143=>15680, +52144=>15681, +52145=>15682, +52146=>15683, +52147=>15684, +52148=>15685, +52149=>15686, +52150=>15687, +52151=>15688, +52153=>15689, +52154=>15690, +52155=>15691, +52156=>15692, +52157=>15693, +52158=>15694, +52159=>15695, +52160=>15696, +52161=>15697, +52162=>15698, +52163=>15699, +52164=>15700, +52165=>15701, +52166=>15702, +52167=>15703, +52168=>15704, +52169=>15705, +52170=>15706, +52171=>15707, +52172=>15708, +52173=>15709, +52174=>15710, +52175=>15711, +52176=>15712, +52177=>15713, +52178=>15714, +52179=>15715, +52181=>15716, +52182=>15717, +52183=>15718, +52184=>15719, +52185=>15720, +52186=>15721, +52187=>15722, +52188=>15723, +52189=>15724, +52190=>15725, +52191=>15726, +52192=>15727, +52193=>15728, +52194=>15729, +52195=>15730, +52197=>15731, +52198=>15732, +52200=>15733, +52202=>15734, +52203=>15735, +52204=>15736, +52205=>15737, +52206=>15738, +52207=>15739, +52208=>15740, +52209=>15741, +52210=>15742, +52211=>15743, +52212=>15744, +52213=>15745, +52214=>15746, +52215=>15747, +52216=>15748, +52217=>15749, +52218=>15750, +52219=>15751, +52220=>15752, +52221=>15753, +52222=>15754, +52223=>15755, +52224=>15756, +52225=>15757, +52226=>15758, +52227=>15759, +52228=>15760, +52229=>15761, +52230=>15762, +52231=>15763, +52232=>15764, +52233=>15765, +52234=>15766, +52235=>15767, +52238=>15768, +52239=>15769, +52241=>15770, +52242=>15771, +52243=>15772, +52245=>15773, +52246=>15774, +52247=>15775, +52248=>15776, +52249=>15777, +52250=>15778, +52251=>15779, +52254=>15780, +52255=>15781, +52256=>15782, +52259=>15783, +52260=>15784, +52261=>15785, +52262=>15786, +52266=>15787, +52267=>15788, +52269=>15789, +52271=>15790, +52273=>15791, +52274=>15792, +52275=>15793, +52276=>15794, +52277=>15795, +52278=>15796, +52279=>15797, +52282=>15798, +52287=>15799, +52288=>15800, +52289=>15801, +52290=>15802, +52291=>15803, +52294=>15804, +52295=>15805, +52297=>15806, +52298=>15807, +52299=>15808, +52301=>15809, +52302=>15810, +52303=>15811, +52304=>15812, +52305=>15813, +52306=>15814, +52307=>15815, +52310=>15816, +52314=>15817, +52315=>15818, +52316=>15819, +52317=>15820, +52318=>15821, +52319=>15822, +52321=>15823, +52322=>15824, +52323=>15825, +52325=>15826, +52327=>15827, +52329=>15828, +52330=>15829, +52331=>15830, +52332=>15831, +52333=>15832, +52334=>15833, +52335=>15834, +52337=>15835, +52338=>15836, +52339=>15837, +52340=>15838, +52342=>15839, +52343=>15840, +52344=>15841, +52345=>15842, +52346=>15843, +52347=>15844, +52348=>15845, +52349=>15846, +52350=>15847, +52351=>15848, +52352=>15849, +52353=>15850, +52354=>15851, +52355=>15852, +52356=>15853, +52357=>15854, +52358=>15855, +52359=>15856, +52360=>15857, +52361=>15858, +52362=>15859, +52363=>15860, +52364=>15861, +52365=>15862, +52366=>15863, +52367=>15864, +52368=>15865, +52369=>15866, +52370=>15867, +52371=>15868, +52372=>15869, +52373=>15870, +52374=>15871, +52375=>15872, +52378=>15873, +52379=>15874, +52381=>15875, +52382=>15876, +52383=>15877, +52385=>15878, +52386=>15879, +52387=>15880, +52388=>15881, +52389=>15882, +52390=>15883, +52391=>15884, +52394=>15885, +52398=>15886, +52399=>15887, +52400=>15888, +52401=>15889, +52402=>15890, +52403=>15891, +52406=>15892, +52407=>15893, +52409=>15894, +52410=>15895, +52411=>15896, +52413=>15897, +52414=>15898, +52415=>15899, +52416=>15900, +52417=>15901, +52418=>15902, +52419=>15903, +52422=>15904, +52424=>15905, +52426=>15906, +52427=>15907, +52428=>15908, +52429=>15909, +52430=>15910, +52431=>15911, +52433=>15912, +52434=>15913, +52435=>15914, +52437=>15915, +52438=>15916, +52439=>15917, +52440=>15918, +52441=>15919, +52442=>15920, +52443=>15921, +52444=>15922, +52445=>15923, +52446=>15924, +52447=>15925, +52448=>15926, +52449=>15927, +52450=>15928, +52451=>15929, +52453=>15930, +52454=>15931, +52455=>15932, +52456=>15933, +52457=>15934, +52458=>15935, +52459=>15936, +52461=>15937, +52462=>15938, +52463=>15939, +52465=>15940, +52466=>15941, +52467=>15942, +52468=>15943, +52469=>15944, +52470=>15945, +52471=>15946, +52472=>15947, +52473=>15948, +52474=>15949, +52475=>15950, +52476=>15951, +52477=>15952, +52478=>15953, +52479=>15954, +52480=>15955, +52482=>15956, +52483=>15957, +52484=>15958, +52485=>15959, +52486=>15960, +52487=>15961, +52490=>15962, +52491=>15963, +52493=>15964, +52494=>15965, +52495=>15966, +52497=>15967, +52498=>15968, +52499=>15969, +52500=>15970, +52501=>15971, +52502=>15972, +52503=>15973, +52506=>15974, +52508=>15975, +52510=>15976, +52511=>15977, +52512=>15978, +52513=>15979, +52514=>15980, +52515=>15981, +52517=>15982, +52518=>15983, +52519=>15984, +52521=>15985, +52522=>15986, +52523=>15987, +52525=>15988, +52526=>15989, +52527=>15990, +52528=>15991, +52529=>15992, +52530=>15993, +52531=>15994, +52532=>15995, +52533=>15996, +52534=>15997, +52535=>15998, +52536=>15999, +52538=>16000, +52539=>16001, +52540=>16002, +52541=>16003, +52542=>16004, +52543=>16005, +52544=>16006, +52545=>16007, +52546=>16008, +52547=>16009, +52548=>16010, +52549=>16011, +52550=>16012, +52551=>16013, +52552=>16014, +52553=>16015, +52554=>16016, +52555=>16017, +52556=>16018, +52557=>16019, +52558=>16020, +52559=>16021, +52560=>16022, +52561=>16023, +52562=>16024, +52563=>16025, +52564=>16026, +52565=>16027, +52566=>16028, +52567=>16029, +52568=>16030, +52569=>16031, +52570=>16032, +52571=>16033, +52573=>16034, +52574=>16035, +52575=>16036, +52577=>16037, +52578=>16038, +52579=>16039, +52581=>16040, +52582=>16041, +52583=>16042, +52584=>16043, +52585=>16044, +52586=>16045, +52587=>16046, +52590=>16047, +52592=>16048, +52594=>16049, +52595=>16050, +52596=>16051, +52597=>16052, +52598=>16053, +52599=>16054, +52601=>16055, +52602=>16056, +52603=>16057, +52604=>16058, +52605=>16059, +52606=>16060, +52607=>16061, +52608=>16062, +52609=>16063, +52610=>16064, +52611=>16065, +52612=>16066, +52613=>16067, +52614=>16068, +52615=>16069, +52617=>16070, +52618=>16071, +52619=>16072, +52620=>16073, +52621=>16074, +52622=>16075, +52623=>16076, +52624=>16077, +52625=>16078, +52626=>16079, +52627=>16080, +52630=>16081, +52631=>16082, +52633=>16083, +52634=>16084, +52635=>16085, +52637=>16086, +52638=>16087, +52639=>16088, +52640=>16089, +52641=>16090, +52642=>16091, +52643=>16092, +52646=>16093, +52648=>16094, +52650=>16095, +52651=>16096, +52652=>16097, +52653=>16098, +52654=>16099, +52655=>16100, +52657=>16101, +52658=>16102, +52659=>16103, +52660=>16104, +52661=>16105, +52662=>16106, +52663=>16107, +52664=>16108, +52665=>16109, +52666=>16110, +52667=>16111, +52668=>16112, +52669=>16113, +52670=>16114, +52671=>16115, +52672=>16116, +52673=>16117, +52674=>16118, +52675=>16119, +52677=>16120, +52678=>16121, +52679=>16122, +52680=>16123, +52681=>16124, +52682=>16125, +52683=>16126, +52685=>16127, +52686=>16128, +52687=>16129, +52689=>16130, +52690=>16131, +52691=>16132, +52692=>16133, +52693=>16134, +52694=>16135, +52695=>16136, +52696=>16137, +52697=>16138, +52698=>16139, +52699=>16140, +52700=>16141, +52701=>16142, +52702=>16143, +52703=>16144, +52704=>16145, +52705=>16146, +52706=>16147, +52707=>16148, +52708=>16149, +52709=>16150, +52710=>16151, +52711=>16152, +52713=>16153, +52714=>16154, +52715=>16155, +52717=>16156, +52718=>16157, +52719=>16158, +52721=>16159, +52722=>16160, +52723=>16161, +52724=>16162, +52725=>16163, +52726=>16164, +52727=>16165, +52730=>16166, +52732=>16167, +52734=>16168, +52735=>16169, +52736=>16170, +52737=>16171, +52738=>16172, +52739=>16173, +52741=>16174, +52742=>16175, +52743=>16176, +52745=>16177, +52746=>16178, +52747=>16179, +52749=>16180, +52750=>16181, +52751=>16182, +52752=>16183, +52753=>16184, +52754=>16185, +52755=>16186, +52757=>16187, +52758=>16188, +52759=>16189, +52760=>16190, +52762=>16191, +52763=>16192, +52764=>16193, +52765=>16194, +52766=>16195, +52767=>16196, +52770=>16197, +52771=>16198, +52773=>16199, +52774=>16200, +52775=>16201, +52777=>16202, +52778=>16203, +52779=>16204, +52780=>16205, +52781=>16206, +52782=>16207, +52783=>16208, +52786=>16209, +52788=>16210, +52790=>16211, +52791=>16212, +52792=>16213, +52793=>16214, +52794=>16215, +52795=>16216, +52796=>16217, +52797=>16218, +52798=>16219, +52799=>16220, +52800=>16221, +52801=>16222, +52802=>16223, +52803=>16224, +52804=>16225, +52805=>16226, +52806=>16227, +52807=>16228, +52808=>16229, +52809=>16230, +52810=>16231, +52811=>16232, +52812=>16233, +52813=>16234, +52814=>16235, +52815=>16236, +52816=>16237, +52817=>16238, +52818=>16239, +52819=>16240, +52820=>16241, +52821=>16242, +52822=>16243, +52823=>16244, +52826=>16245, +52827=>16246, +52829=>16247, +52830=>16248, +52834=>16249, +52835=>16250, +52836=>16251, +52837=>16252, +52838=>16253, +52839=>16254, +52842=>16255, +52844=>16256, +52846=>16257, +52847=>16258, +52848=>16259, +52849=>16260, +52850=>16261, +52851=>16262, +52854=>16263, +52855=>16264, +52857=>16265, +52858=>16266, +52859=>16267, +52861=>16268, +52862=>16269, +52863=>16270, +52864=>16271, +52865=>16272, +52866=>16273, +52867=>16274, +52870=>16275, +52872=>16276, +52874=>16277, +52875=>16278, +52876=>16279, +52877=>16280, +52878=>16281, +52879=>16282, +52882=>16283, +52883=>16284, +52885=>16285, +52886=>16286, +52887=>16287, +52889=>16288, +52890=>16289, +52891=>16290, +52892=>16291, +52893=>16292, +52894=>16293, +52895=>16294, +52898=>16295, +52902=>16296, +52903=>16297, +52904=>16298, +52905=>16299, +52906=>16300, +52907=>16301, +52910=>16302, +52911=>16303, +52912=>16304, +52913=>16305, +52914=>16306, +52915=>16307, +52916=>16308, +52917=>16309, +52918=>16310, +52919=>16311, +52920=>16312, +52921=>16313, +52922=>16314, +52923=>16315, +52924=>16316, +52925=>16317, +52926=>16318, +52927=>16319, +52928=>16320, +52930=>16321, +52931=>16322, +52932=>16323, +52933=>16324, +52934=>16325, +52935=>16326, +52936=>16327, +52937=>16328, +52938=>16329, +52939=>16330, +52940=>16331, +52941=>16332, +52942=>16333, +52943=>16334, +52944=>16335, +52945=>16336, +52946=>16337, +52947=>16338, +52948=>16339, +52949=>16340, +52950=>16341, +52951=>16342, +52952=>16343, +52953=>16344, +52954=>16345, +52955=>16346, +52956=>16347, +52957=>16348, +52958=>16349, +52959=>16350, +52960=>16351, +52961=>16352, +52962=>16353, +52963=>16354, +52966=>16355, +52967=>16356, +52969=>16357, +52970=>16358, +52973=>16359, +52974=>16360, +52975=>16361, +52976=>16362, +52977=>16363, +52978=>16364, +52979=>16365, +52982=>16366, +52986=>16367, +52987=>16368, +52988=>16369, +52989=>16370, +52990=>16371, +52991=>16372, +52994=>16373, +52995=>16374, +52997=>16375, +52998=>16376, +52999=>16377, +53001=>16378, +53002=>16379, +53003=>16380, +53004=>16381, +53005=>16382, +53006=>16383, +53007=>16384, +53010=>16385, +53012=>16386, +53014=>16387, +53015=>16388, +53016=>16389, +53017=>16390, +53018=>16391, +53019=>16392, +53021=>16393, +53022=>16394, +53023=>16395, +53025=>16396, +53026=>16397, +53027=>16398, +53029=>16399, +53030=>16400, +53031=>16401, +53032=>16402, +53033=>16403, +53034=>16404, +53035=>16405, +53038=>16406, +53042=>16407, +53043=>16408, +53044=>16409, +53045=>16410, +53046=>16411, +53047=>16412, +53049=>16413, +53050=>16414, +53051=>16415, +53052=>16416, +53053=>16417, +53054=>16418, +53055=>16419, +53056=>16420, +53057=>16421, +53058=>16422, +53059=>16423, +53060=>16424, +53061=>16425, +53062=>16426, +53063=>16427, +53064=>16428, +53065=>16429, +53066=>16430, +53067=>16431, +53068=>16432, +53069=>16433, +53070=>16434, +53071=>16435, +53072=>16436, +53073=>16437, +53074=>16438, +53075=>16439, +53078=>16440, +53079=>16441, +53081=>16442, +53082=>16443, +53083=>16444, +53085=>16445, +53086=>16446, +53087=>16447, +53088=>16448, +53089=>16449, +53090=>16450, +53091=>16451, +53094=>16452, +53096=>16453, +53098=>16454, +53099=>16455, +53100=>16456, +53101=>16457, +53102=>16458, +53103=>16459, +53106=>16460, +53107=>16461, +53109=>16462, +53110=>16463, +53111=>16464, +53113=>16465, +53114=>16466, +53115=>16467, +53116=>16468, +53117=>16469, +53118=>16470, +53119=>16471, +53121=>16472, +53122=>16473, +53123=>16474, +53124=>16475, +53126=>16476, +53127=>16477, +53128=>16478, +53129=>16479, +53130=>16480, +53131=>16481, +53133=>16482, +53134=>16483, +53135=>16484, +53136=>16485, +53137=>16486, +53138=>16487, +53139=>16488, +53140=>16489, +53141=>16490, +53142=>16491, +53143=>16492, +53144=>16493, +53145=>16494, +53146=>16495, +53147=>16496, +53148=>16497, +53149=>16498, +53150=>16499, +53151=>16500, +53152=>16501, +53154=>16502, +53155=>16503, +53156=>16504, +53157=>16505, +53158=>16506, +53159=>16507, +53161=>16508, +53162=>16509, +53163=>16510, +53164=>16511, +53165=>16512, +53166=>16513, +53167=>16514, +53169=>16515, +53170=>16516, +53171=>16517, +53172=>16518, +53173=>16519, +53174=>16520, +53175=>16521, +53176=>16522, +53177=>16523, +53178=>16524, +53179=>16525, +53180=>16526, +53181=>16527, +53182=>16528, +53183=>16529, +53184=>16530, +53185=>16531, +53186=>16532, +53187=>16533, +53189=>16534, +53190=>16535, +53191=>16536, +53192=>16537, +53193=>16538, +53194=>16539, +53195=>16540, +53196=>16541, +53197=>16542, +53198=>16543, +53199=>16544, +53200=>16545, +53201=>16546, +53202=>16547, +53203=>16548, +53204=>16549, +53205=>16550, +53206=>16551, +53207=>16552, +53208=>16553, +53209=>16554, +53210=>16555, +53211=>16556, +53212=>16557, +53213=>16558, +53214=>16559, +53215=>16560, +53218=>16561, +53219=>16562, +53221=>16563, +53222=>16564, +53223=>16565, +53225=>16566, +53226=>16567, +53227=>16568, +53228=>16569, +53229=>16570, +53230=>16571, +53231=>16572, +53234=>16573, +53236=>16574, +53238=>16575, +53239=>16576, +53240=>16577, +53241=>16578, +53242=>16579, +53243=>16580, +53245=>16581, +53246=>16582, +53247=>16583, +53249=>16584, +53250=>16585, +53251=>16586, +53253=>16587, +53254=>16588, +53255=>16589, +53256=>16590, +53257=>16591, +53258=>16592, +53259=>16593, +53260=>16594, +53261=>16595, +53262=>16596, +53263=>16597, +53264=>16598, +53266=>16599, +53267=>16600, +53268=>16601, +53269=>16602, +53270=>16603, +53271=>16604, +53273=>16605, +53274=>16606, +53275=>16607, +53276=>16608, +53277=>16609, +53278=>16610, +53279=>16611, +53280=>16612, +53281=>16613, +53282=>16614, +53283=>16615, +53284=>16616, +53285=>16617, +53286=>16618, +53287=>16619, +53288=>16620, +53289=>16621, +53290=>16622, +53291=>16623, +53292=>16624, +53294=>16625, +53295=>16626, +53296=>16627, +53297=>16628, +53298=>16629, +53299=>16630, +53302=>16631, +53303=>16632, +53305=>16633, +53306=>16634, +53307=>16635, +53309=>16636, +53310=>16637, +53311=>16638, +53312=>16639, +53313=>16640, +53314=>16641, +53315=>16642, +53318=>16643, +53320=>16644, +53322=>16645, +53323=>16646, +53324=>16647, +53325=>16648, +53326=>16649, +53327=>16650, +53329=>16651, +53330=>16652, +53331=>16653, +53333=>16654, +53334=>16655, +53335=>16656, +53337=>16657, +53338=>16658, +53339=>16659, +53340=>16660, +53341=>16661, +53342=>16662, +53343=>16663, +53345=>16664, +53346=>16665, +53347=>16666, +53348=>16667, +53349=>16668, +53350=>16669, +53351=>16670, +53352=>16671, +53353=>16672, +53354=>16673, +53355=>16674, +53358=>16675, +53359=>16676, +53361=>16677, +53362=>16678, +53363=>16679, +53365=>16680, +53366=>16681, +53367=>16682, +53368=>16683, +53369=>16684, +53370=>16685, +53371=>16686, +53374=>16687, +53375=>16688, +53376=>16689, +53378=>16690, +53379=>16691, +53380=>16692, +53381=>16693, +53382=>16694, +53383=>16695, +53384=>16696, +53385=>16697, +53386=>16698, +53387=>16699, +53388=>16700, +53389=>16701, +53390=>16702, +53391=>16703, +53392=>16704, +53393=>16705, +53394=>16706, +53395=>16707, +53396=>16708, +53397=>16709, +53398=>16710, +53399=>16711, +53400=>16712, +53401=>16713, +53402=>16714, +53403=>16715, +53404=>16716, +53405=>16717, +53406=>16718, +53407=>16719, +53408=>16720, +53409=>16721, +53410=>16722, +53411=>16723, +53414=>16724, +53415=>16725, +53417=>16726, +53418=>16727, +53419=>16728, +53421=>16729, +53422=>16730, +53423=>16731, +53424=>16732, +53425=>16733, +53426=>16734, +53427=>16735, +53430=>16736, +53432=>16737, +53434=>16738, +53435=>16739, +53436=>16740, +53437=>16741, +53438=>16742, +53439=>16743, +53442=>16744, +53443=>16745, +53445=>16746, +53446=>16747, +53447=>16748, +53450=>16749, +53451=>16750, +53452=>16751, +53453=>16752, +53454=>16753, +53455=>16754, +53458=>16755, +53462=>16756, +53463=>16757, +53464=>16758, +53465=>16759, +53466=>16760, +53467=>16761, +53470=>16762, +53471=>16763, +53473=>16764, +53474=>16765, +53475=>16766, +53477=>16767, +53478=>16768, +53479=>16769, +53480=>16770, +53481=>16771, +53482=>16772, +53483=>16773, +53486=>16774, +53490=>16775, +53491=>16776, +53492=>16777, +53493=>16778, +53494=>16779, +53495=>16780, +53497=>16781, +53498=>16782, +53499=>16783, +53500=>16784, +53501=>16785, +53502=>16786, +53503=>16787, +53504=>16788, +53505=>16789, +53506=>16790, +53507=>16791, +53508=>16792, +53509=>16793, +53510=>16794, +53511=>16795, +53512=>16796, +53513=>16797, +53514=>16798, +53515=>16799, +53516=>16800, +53518=>16801, +53519=>16802, +53520=>16803, +53521=>16804, +53522=>16805, +53523=>16806, +53524=>16807, +53525=>16808, +53526=>16809, +53527=>16810, +53528=>16811, +53529=>16812, +53530=>16813, +53531=>16814, +53532=>16815, +53533=>16816, +53534=>16817, +53535=>16818, +53536=>16819, +53537=>16820, +53538=>16821, +53539=>16822, +53540=>16823, +53541=>16824, +53542=>16825, +53543=>16826, +53544=>16827, +53545=>16828, +53546=>16829, +53547=>16830, +53548=>16831, +53549=>16832, +53550=>16833, +53551=>16834, +53554=>16835, +53555=>16836, +53557=>16837, +53558=>16838, +53559=>16839, +53561=>16840, +53563=>16841, +53564=>16842, +53565=>16843, +53566=>16844, +53567=>16845, +53570=>16846, +53574=>16847, +53575=>16848, +53576=>16849, +53577=>16850, +53578=>16851, +53579=>16852, +53582=>16853, +53583=>16854, +53585=>16855, +53586=>16856, +53587=>16857, +53589=>16858, +53590=>16859, +53591=>16860, +53592=>16861, +53593=>16862, +53594=>16863, +53595=>16864, +53598=>16865, +53600=>16866, +53602=>16867, +53603=>16868, +53604=>16869, +53605=>16870, +53606=>16871, +53607=>16872, +53609=>16873, +53610=>16874, +53611=>16875, +53613=>16876, +53614=>16877, +53615=>16878, +53616=>16879, +53617=>16880, +53618=>16881, +53619=>16882, +53620=>16883, +53621=>16884, +53622=>16885, +53623=>16886, +53624=>16887, +53625=>16888, +53626=>16889, +53627=>16890, +53629=>16891, +53630=>16892, +53631=>16893, +53632=>16894, +53633=>16895, +53634=>16896, +53635=>16897, +53637=>16898, +53638=>16899, +53639=>16900, +53641=>16901, +53642=>16902, +53643=>16903, +53644=>16904, +53645=>16905, +53646=>16906, +53647=>16907, +53648=>16908, +53649=>16909, +53650=>16910, +53651=>16911, +53652=>16912, +53653=>16913, +53654=>16914, +53655=>16915, +53656=>16916, +53657=>16917, +53658=>16918, +53659=>16919, +53660=>16920, +53661=>16921, +53662=>16922, +53663=>16923, +53666=>16924, +53667=>16925, +53669=>16926, +53670=>16927, +53671=>16928, +53673=>16929, +53674=>16930, +53675=>16931, +53676=>16932, +53677=>16933, +53678=>16934, +53679=>16935, +53682=>16936, +53684=>16937, +53686=>16938, +53687=>16939, +53688=>16940, +53689=>16941, +53691=>16942, +53693=>16943, +53694=>16944, +53695=>16945, +53697=>16946, +53698=>16947, +53699=>16948, +53700=>16949, +53701=>16950, +53702=>16951, +53703=>16952, +53704=>16953, +53705=>16954, +53706=>16955, +53707=>16956, +53708=>16957, +53709=>16958, +53710=>16959, +53711=>16960, +53712=>16961, +53713=>16962, +53714=>16963, +53715=>16964, +53716=>16965, +53717=>16966, +53718=>16967, +53719=>16968, +53721=>16969, +53722=>16970, +53723=>16971, +53724=>16972, +53725=>16973, +53726=>16974, +53727=>16975, +53728=>16976, +53729=>16977, +53730=>16978, +53731=>16979, +53732=>16980, +53733=>16981, +53734=>16982, +53735=>16983, +53736=>16984, +53737=>16985, +53738=>16986, +53739=>16987, +53740=>16988, +53741=>16989, +53742=>16990, +53743=>16991, +53744=>16992, +53745=>16993, +53746=>16994, +53747=>16995, +53749=>16996, +53750=>16997, +53751=>16998, +53753=>16999, +53754=>17000, +53755=>17001, +53756=>17002, +53757=>17003, +53758=>17004, +53759=>17005, +53760=>17006, +53761=>17007, +53762=>17008, +53763=>17009, +53764=>17010, +53765=>17011, +53766=>17012, +53768=>17013, +53770=>17014, +53771=>17015, +53772=>17016, +53773=>17017, +53774=>17018, +53775=>17019, +53777=>17020, +53778=>17021, +53779=>17022, +53780=>17023, +53781=>17024, +53782=>17025, +53783=>17026, +53784=>17027, +53785=>17028, +53786=>17029, +53787=>17030, +53788=>17031, +53789=>17032, +53790=>17033, +53791=>17034, +53792=>17035, +53793=>17036, +53794=>17037, +53795=>17038, +53796=>17039, +53797=>17040, +53798=>17041, +53799=>17042, +53800=>17043, +53801=>17044, +53802=>17045, +53803=>17046, +53806=>17047, +53807=>17048, +53809=>17049, +53810=>17050, +53811=>17051, +53813=>17052, +53814=>17053, +53815=>17054, +53816=>17055, +53817=>17056, +53818=>17057, +53819=>17058, +53822=>17059, +53824=>17060, +53826=>17061, +53827=>17062, +53828=>17063, +53829=>17064, +53830=>17065, +53831=>17066, +53833=>17067, +53834=>17068, +53835=>17069, +53836=>17070, +53837=>17071, +53838=>17072, +53839=>17073, +53840=>17074, +53841=>17075, +53842=>17076, +53843=>17077, +53844=>17078, +53845=>17079, +53846=>17080, +53847=>17081, +53848=>17082, +53849=>17083, +53850=>17084, +53851=>17085, +53853=>17086, +53854=>17087, +53855=>17088, +53856=>17089, +53857=>17090, +53858=>17091, +53859=>17092, +53861=>17093, +53862=>17094, +53863=>17095, +53864=>17096, +53865=>17097, +53866=>17098, +53867=>17099, +53868=>17100, +53869=>17101, +53870=>17102, +53871=>17103, +53872=>17104, +53873=>17105, +53874=>17106, +53875=>17107, +53876=>17108, +53877=>17109, +53878=>17110, +53879=>17111, +53880=>17112, +53881=>17113, +53882=>17114, +53883=>17115, +53884=>17116, +53885=>17117, +53886=>17118, +53887=>17119, +53890=>17120, +53891=>17121, +53893=>17122, +53894=>17123, +53895=>17124, +53897=>17125, +53898=>17126, +53899=>17127, +53900=>17128, +53901=>17129, +53902=>17130, +53903=>17131, +53906=>17132, +53907=>17133, +53908=>17134, +53910=>17135, +53911=>17136, +53912=>17137, +53913=>17138, +53914=>17139, +53915=>17140, +53917=>17141, +53918=>17142, +53919=>17143, +53921=>17144, +53922=>17145, +53923=>17146, +53925=>17147, +53926=>17148, +53927=>17149, +53928=>17150, +53929=>17151, +53930=>17152, +53931=>17153, +53933=>17154, +53934=>17155, +53935=>17156, +53936=>17157, +53938=>17158, +53939=>17159, +53940=>17160, +53941=>17161, +53942=>17162, +53943=>17163, +53946=>17164, +53947=>17165, +53949=>17166, +53950=>17167, +53953=>17168, +53955=>17169, +53956=>17170, +53957=>17171, +53958=>17172, +53959=>17173, +53962=>17174, +53964=>17175, +53965=>17176, +53966=>17177, +53967=>17178, +53968=>17179, +53969=>17180, +53970=>17181, +53971=>17182, +53973=>17183, +53974=>17184, +53975=>17185, +53977=>17186, +53978=>17187, +53979=>17188, +53981=>17189, +53982=>17190, +53983=>17191, +53984=>17192, +53985=>17193, +53986=>17194, +53987=>17195, +53990=>17196, +53991=>17197, +53992=>17198, +53993=>17199, +53994=>17200, +53995=>17201, +53996=>17202, +53997=>17203, +53998=>17204, +53999=>17205, +54002=>17206, +54003=>17207, +54005=>17208, +54006=>17209, +54007=>17210, +54009=>17211, +54010=>17212, +54011=>17213, +54012=>17214, +54013=>17215, +54014=>17216, +54015=>17217, +54018=>17218, +54020=>17219, +54022=>17220, +54023=>17221, +54024=>17222, +54025=>17223, +54026=>17224, +54027=>17225, +54031=>17226, +54033=>17227, +54034=>17228, +54035=>17229, +54037=>17230, +54039=>17231, +54040=>17232, +54041=>17233, +54042=>17234, +54043=>17235, +54046=>17236, +54050=>17237, +54051=>17238, +54052=>17239, +54054=>17240, +54055=>17241, +54058=>17242, +54059=>17243, +54061=>17244, +54062=>17245, +54063=>17246, +54065=>17247, +54066=>17248, +54067=>17249, +54068=>17250, +54069=>17251, +54070=>17252, +54071=>17253, +54074=>17254, +54078=>17255, +54079=>17256, +54080=>17257, +54081=>17258, +54082=>17259, +54083=>17260, +54086=>17261, +54087=>17262, +54088=>17263, +54089=>17264, +54090=>17265, +54091=>17266, +54092=>17267, +54093=>17268, +54094=>17269, +54095=>17270, +54096=>17271, +54097=>17272, +54098=>17273, +54099=>17274, +54100=>17275, +54101=>17276, +54102=>17277, +54103=>17278, +54104=>17279, +54105=>17280, +54106=>17281, +54107=>17282, +54108=>17283, +54109=>17284, +54110=>17285, +54111=>17286, +54112=>17287, +54113=>17288, +54114=>17289, +54115=>17290, +54116=>17291, +54117=>17292, +54118=>17293, +54119=>17294, +54120=>17295, +54121=>17296, +54122=>17297, +54123=>17298, +54124=>17299, +54125=>17300, +54126=>17301, +54127=>17302, +54128=>17303, +54129=>17304, +54130=>17305, +54131=>17306, +54132=>17307, +54133=>17308, +54134=>17309, +54135=>17310, +54136=>17311, +54137=>17312, +54138=>17313, +54139=>17314, +54142=>17315, +54143=>17316, +54145=>17317, +54146=>17318, +54147=>17319, +54149=>17320, +54150=>17321, +54151=>17322, +54152=>17323, +54153=>17324, +54154=>17325, +54155=>17326, +54158=>17327, +54162=>17328, +54163=>17329, +54164=>17330, +54165=>17331, +54166=>17332, +54167=>17333, +54170=>17334, +54171=>17335, +54173=>17336, +54174=>17337, +54175=>17338, +54177=>17339, +54178=>17340, +54179=>17341, +54180=>17342, +54181=>17343, +54182=>17344, +54183=>17345, +54186=>17346, +54188=>17347, +54190=>17348, +54191=>17349, +54192=>17350, +54193=>17351, +54194=>17352, +54195=>17353, +54197=>17354, +54198=>17355, +54199=>17356, +54201=>17357, +54202=>17358, +54203=>17359, +54205=>17360, +54206=>17361, +54207=>17362, +54208=>17363, +54209=>17364, +54210=>17365, +54211=>17366, +54214=>17367, +54215=>17368, +54218=>17369, +54219=>17370, +54220=>17371, +54221=>17372, +54222=>17373, +54223=>17374, +54225=>17375, +54226=>17376, +54227=>17377, +54228=>17378, +54229=>17379, +54230=>17380, +54231=>17381, +54233=>17382, +54234=>17383, +54235=>17384, +54236=>17385, +54237=>17386, +54238=>17387, +54239=>17388, +54240=>17389, +54242=>17390, +54244=>17391, +54245=>17392, +54246=>17393, +54247=>17394, +54248=>17395, +54249=>17396, +54250=>17397, +54251=>17398, +54254=>17399, +54255=>17400, +54257=>17401, +54258=>17402, +54259=>17403, +54261=>17404, +54262=>17405, +54263=>17406, +54264=>17407, +54265=>17408, +54266=>17409, +54267=>17410, +54270=>17411, +54272=>17412, +54274=>17413, +54275=>17414, +54276=>17415, +54277=>17416, +54278=>17417, +54279=>17418, +54281=>17419, +54282=>17420, +54283=>17421, +54284=>17422, +54285=>17423, +54286=>17424, +54287=>17425, +54288=>17426, +54289=>17427, +54290=>17428, +54291=>17429, +54292=>17430, +54293=>17431, +54294=>17432, +54295=>17433, +54296=>17434, +54297=>17435, +54298=>17436, +54299=>17437, +54300=>17438, +54302=>17439, +54303=>17440, +54304=>17441, +54305=>17442, +54306=>17443, +54307=>17444, +54308=>17445, +54309=>17446, +54310=>17447, +54311=>17448, +54312=>17449, +54313=>17450, +54314=>17451, +54315=>17452, +54316=>17453, +54317=>17454, +54318=>17455, +54319=>17456, +54320=>17457, +54321=>17458, +54322=>17459, +54323=>17460, +54324=>17461, +54325=>17462, +54326=>17463, +54327=>17464, +54328=>17465, +54329=>17466, +54330=>17467, +54331=>17468, +54332=>17469, +54333=>17470, +54334=>17471, +54335=>17472, +54337=>17473, +54338=>17474, +54339=>17475, +54341=>17476, +54342=>17477, +54343=>17478, +54344=>17479, +54345=>17480, +54346=>17481, +54347=>17482, +54348=>17483, +54349=>17484, +54350=>17485, +54351=>17486, +54352=>17487, +54353=>17488, +54354=>17489, +54355=>17490, +54356=>17491, +54357=>17492, +54358=>17493, +54359=>17494, +54360=>17495, +54361=>17496, +54362=>17497, +54363=>17498, +54365=>17499, +54366=>17500, +54367=>17501, +54369=>17502, +54370=>17503, +54371=>17504, +54373=>17505, +54374=>17506, +54375=>17507, +54376=>17508, +54377=>17509, +54378=>17510, +54379=>17511, +54380=>17512, +54382=>17513, +54384=>17514, +54385=>17515, +54386=>17516, +54387=>17517, +54388=>17518, +54389=>17519, +54390=>17520, +54391=>17521, +54394=>17522, +54395=>17523, +54397=>17524, +54398=>17525, +54401=>17526, +54403=>17527, +54404=>17528, +54405=>17529, +54406=>17530, +54407=>17531, +54410=>17532, +54412=>17533, +54414=>17534, +54415=>17535, +54416=>17536, +54417=>17537, +54418=>17538, +54419=>17539, +54421=>17540, +54422=>17541, +54423=>17542, +54424=>17543, +54425=>17544, +54426=>17545, +54427=>17546, +54428=>17547, +54429=>17548, +54430=>17549, +54431=>17550, +54432=>17551, +54433=>17552, +54434=>17553, +54435=>17554, +54436=>17555, +54437=>17556, +54438=>17557, +54439=>17558, +54440=>17559, +54442=>17560, +54443=>17561, +54444=>17562, +54445=>17563, +54446=>17564, +54447=>17565, +54448=>17566, +54449=>17567, +54450=>17568, +54451=>17569, +54452=>17570, +54453=>17571, +54454=>17572, +54455=>17573, +54456=>17574, +54457=>17575, +54458=>17576, +54459=>17577, +54460=>17578, +54461=>17579, +54462=>17580, +54463=>17581, +54464=>17582, +54465=>17583, +54466=>17584, +54467=>17585, +54468=>17586, +54469=>17587, +54470=>17588, +54471=>17589, +54472=>17590, +54473=>17591, +54474=>17592, +54475=>17593, +54477=>17594, +54478=>17595, +54479=>17596, +54481=>17597, +54482=>17598, +54483=>17599, +54485=>17600, +54486=>17601, +54487=>17602, +54488=>17603, +54489=>17604, +54490=>17605, +54491=>17606, +54493=>17607, +54494=>17608, +54496=>17609, +54497=>17610, +54498=>17611, +54499=>17612, +54500=>17613, +54501=>17614, +54502=>17615, +54503=>17616, +54505=>17617, +54506=>17618, +54507=>17619, +54509=>17620, +54510=>17621, +54511=>17622, +54513=>17623, +54514=>17624, +54515=>17625, +54516=>17626, +54517=>17627, +54518=>17628, +54519=>17629, +54521=>17630, +54522=>17631, +54524=>17632, +54526=>17633, +54527=>17634, +54528=>17635, +54529=>17636, +54530=>17637, +54531=>17638, +54533=>17639, +54534=>17640, +54535=>17641, +54537=>17642, +54538=>17643, +54539=>17644, +54541=>17645, +54542=>17646, +54543=>17647, +54544=>17648, +54545=>17649, +54546=>17650, +54547=>17651, +54550=>17652, +54552=>17653, +54553=>17654, +54554=>17655, +54555=>17656, +54556=>17657, +54557=>17658, +54558=>17659, +54559=>17660, +54560=>17661, +54561=>17662, +54562=>17663, +54563=>17664, +54564=>17665, +54565=>17666, +54566=>17667, +54567=>17668, +54568=>17669, +54569=>17670, +54570=>17671, +54571=>17672, +54572=>17673, +54573=>17674, +54574=>17675, +54575=>17676, +54576=>17677, +54577=>17678, +54578=>17679, +54579=>17680, +54580=>17681, +54581=>17682, +54582=>17683, +54583=>17684, +54584=>17685, +54585=>17686, +54586=>17687, +54587=>17688, +54590=>17689, +54591=>17690, +54593=>17691, +54594=>17692, +54595=>17693, +54597=>17694, +54598=>17695, +54599=>17696, +54600=>17697, +54601=>17698, +54602=>17699, +54603=>17700, +54606=>17701, +54608=>17702, +54610=>17703, +54611=>17704, +54612=>17705, +54613=>17706, +54614=>17707, +54615=>17708, +54618=>17709, +54619=>17710, +54621=>17711, +54622=>17712, +54623=>17713, +54625=>17714, +54626=>17715, +54627=>17716, +54628=>17717, +54630=>17718, +54631=>17719, +54634=>17720, +54636=>17721, +54638=>17722, +54639=>17723, +54640=>17724, +54641=>17725, +54642=>17726, +54643=>17727, +54646=>17728, +54647=>17729, +54649=>17730, +54650=>17731, +54651=>17732, +54653=>17733, +54654=>17734, +54655=>17735, +54656=>17736, +54657=>17737, +54658=>17738, +54659=>17739, +54662=>17740, +54666=>17741, +54667=>17742, +54668=>17743, +54669=>17744, +54670=>17745, +54671=>17746, +54673=>17747, +54674=>17748, +54675=>17749, +54676=>17750, +54677=>17751, +54678=>17752, +54679=>17753, +54680=>17754, +54681=>17755, +54682=>17756, +54683=>17757, +54684=>17758, +54685=>17759, +54686=>17760, +54687=>17761, +54688=>17762, +54689=>17763, +54690=>17764, +54691=>17765, +54692=>17766, +54694=>17767, +54695=>17768, +54696=>17769, +54697=>17770, +54698=>17771, +54699=>17772, +54700=>17773, +54701=>17774, +54702=>17775, +54703=>17776, +54704=>17777, +54705=>17778, +54706=>17779, +54707=>17780, +54708=>17781, +54709=>17782, +54710=>17783, +54711=>17784, +54712=>17785, +54713=>17786, +54714=>17787, +54715=>17788, +54716=>17789, +54717=>17790, +54718=>17791, +54719=>17792, +54720=>17793, +54721=>17794, +54722=>17795, +54723=>17796, +54724=>17797, +54725=>17798, +54726=>17799, +54727=>17800, +54730=>17801, +54731=>17802, +54733=>17803, +54734=>17804, +54735=>17805, +54737=>17806, +54739=>17807, +54740=>17808, +54741=>17809, +54742=>17810, +54743=>17811, +54746=>17812, +54748=>17813, +54750=>17814, +54751=>17815, +54752=>17816, +54753=>17817, +54754=>17818, +54755=>17819, +54758=>17820, +54759=>17821, +54761=>17822, +54762=>17823, +54763=>17824, +54765=>17825, +54766=>17826, +54767=>17827, +54768=>17828, +54769=>17829, +54770=>17830, +54771=>17831, +54774=>17832, +54776=>17833, +54778=>17834, +54779=>17835, +54780=>17836, +54781=>17837, +54782=>17838, +54783=>17839, +54786=>17840, +54787=>17841, +54789=>17842, +54790=>17843, +54791=>17844, +54793=>17845, +54794=>17846, +54795=>17847, +54796=>17848, +54797=>17849, +54798=>17850, +54799=>17851, +54802=>17852, +54806=>17853, +54807=>17854, +54808=>17855, +54809=>17856, +54810=>17857, +54811=>17858, +54813=>17859, +54814=>17860, +54815=>17861, +54817=>17862, +54818=>17863, +54819=>17864, +54821=>17865, +54822=>17866, +54823=>17867, +54824=>17868, +54825=>17869, +54826=>17870, +54827=>17871, +54828=>17872, +54830=>17873, +54831=>17874, +54832=>17875, +54833=>17876, +54834=>17877, +54835=>17878, +54836=>17879, +54837=>17880, +54838=>17881, +54839=>17882, +54842=>17883, +54843=>17884, +54845=>17885, +54846=>17886, +54847=>17887, +54849=>17888, +54850=>17889, +54851=>17890, +54852=>17891, +54854=>17892, +54855=>17893, +54858=>17894, +54860=>17895, +54862=>17896, +54863=>17897, +54864=>17898, +54866=>17899, +54867=>17900, +54870=>17901, +54871=>17902, +54873=>17903, +54874=>17904, +54875=>17905, +54877=>17906, +54878=>17907, +54879=>17908, +54880=>17909, +54881=>17910, +54882=>17911, +54883=>17912, +54884=>17913, +54885=>17914, +54886=>17915, +54888=>17916, +54890=>17917, +54891=>17918, +54892=>17919, +54893=>17920, +54894=>17921, +54895=>17922, +54898=>17923, +54899=>17924, +54901=>17925, +54902=>17926, +54903=>17927, +54904=>17928, +54905=>17929, +54906=>17930, +54907=>17931, +54908=>17932, +54909=>17933, +54910=>17934, +54911=>17935, +54912=>17936, +54913=>17937, +54914=>17938, +54916=>17939, +54918=>17940, +54919=>17941, +54920=>17942, +54921=>17943, +54922=>17944, +54923=>17945, +54926=>17946, +54927=>17947, +54929=>17948, +54930=>17949, +54931=>17950, +54933=>17951, +54934=>17952, +54935=>17953, +54936=>17954, +54937=>17955, +54938=>17956, +54939=>17957, +54940=>17958, +54942=>17959, +54944=>17960, +54946=>17961, +54947=>17962, +54948=>17963, +54949=>17964, +54950=>17965, +54951=>17966, +54953=>17967, +54954=>17968, +54955=>17969, +54957=>17970, +54958=>17971, +54959=>17972, +54961=>17973, +54962=>17974, +54963=>17975, +54964=>17976, +54965=>17977, +54966=>17978, +54967=>17979, +54968=>17980, +54970=>17981, +54972=>17982, +54973=>17983, +54974=>17984, +54975=>17985, +54976=>17986, +54977=>17987, +54978=>17988, +54979=>17989, +54982=>17990, +54983=>17991, +54985=>17992, +54986=>17993, +54987=>17994, +54989=>17995, +54990=>17996, +54991=>17997, +54992=>17998, +54994=>17999, +54995=>18000, +54997=>18001, +54998=>18002, +55000=>18003, +55002=>18004, +55003=>18005, +55004=>18006, +55005=>18007, +55006=>18008, +55007=>18009, +55009=>18010, +55010=>18011, +55011=>18012, +55013=>18013, +55014=>18014, +55015=>18015, +55017=>18016, +55018=>18017, +55019=>18018, +55020=>18019, +55021=>18020, +55022=>18021, +55023=>18022, +55025=>18023, +55026=>18024, +55027=>18025, +55028=>18026, +55030=>18027, +55031=>18028, +55032=>18029, +55033=>18030, +55034=>18031, +55035=>18032, +55038=>18033, +55039=>18034, +55041=>18035, +55042=>18036, +55043=>18037, +55045=>18038, +55046=>18039, +55047=>18040, +55048=>18041, +55049=>18042, +55050=>18043, +55051=>18044, +55052=>18045, +55053=>18046, +55054=>18047, +55055=>18048, +55056=>18049, +55058=>18050, +55059=>18051, +55060=>18052, +55061=>18053, +55062=>18054, +55063=>18055, +55066=>18056, +55067=>18057, +55069=>18058, +55070=>18059, +55071=>18060, +55073=>18061, +55074=>18062, +55075=>18063, +55076=>18064, +55077=>18065, +55078=>18066, +55079=>18067, +55082=>18068, +55084=>18069, +55086=>18070, +55087=>18071, +55088=>18072, +55089=>18073, +55090=>18074, +55091=>18075, +55094=>18076, +55095=>18077, +55097=>18078, +55098=>18079, +55099=>18080, +55101=>18081, +55102=>18082, +55103=>18083, +55104=>18084, +55105=>18085, +55106=>18086, +55107=>18087, +55109=>18088, +55110=>18089, +55112=>18090, +55114=>18091, +55115=>18092, +55116=>18093, +55117=>18094, +55118=>18095, +55119=>18096, +55122=>18097, +55123=>18098, +55125=>18099, +55130=>18100, +55131=>18101, +55132=>18102, +55133=>18103, +55134=>18104, +55135=>18105, +55138=>18106, +55140=>18107, +55142=>18108, +55143=>18109, +55144=>18110, +55146=>18111, +55147=>18112, +55149=>18113, +55150=>18114, +55151=>18115, +55153=>18116, +55154=>18117, +55155=>18118, +55157=>18119, +55158=>18120, +55159=>18121, +55160=>18122, +55161=>18123, +55162=>18124, +55163=>18125, +55166=>18126, +55167=>18127, +55168=>18128, +55170=>18129, +55171=>18130, +55172=>18131, +55173=>18132, +55174=>18133, +55175=>18134, +55178=>18135, +55179=>18136, +55181=>18137, +55182=>18138, +55183=>18139, +55185=>18140, +55186=>18141, +55187=>18142, +55188=>18143, +55189=>18144, +55190=>18145, +55191=>18146, +55194=>18147, +55196=>18148, +55198=>18149, +55199=>18150, +55200=>18151, +55201=>18152, +55202=>18153, +55203=>18154, +); +?> diff --git a/include/tcpdf/fonts/utils/enc/cp1250.map b/include/tcpdf/fonts/utils/enc/cp1250.map new file mode 100644 index 00000000..ec110af0 --- /dev/null +++ b/include/tcpdf/fonts/utils/enc/cp1250.map @@ -0,0 +1,251 @@ +!00 U+0000 .notdef +!01 U+0001 .notdef +!02 U+0002 .notdef +!03 U+0003 .notdef +!04 U+0004 .notdef +!05 U+0005 .notdef +!06 U+0006 .notdef +!07 U+0007 .notdef +!08 U+0008 .notdef +!09 U+0009 .notdef +!0A U+000A .notdef +!0B U+000B .notdef +!0C U+000C .notdef +!0D U+000D .notdef +!0E U+000E .notdef +!0F U+000F .notdef +!10 U+0010 .notdef +!11 U+0011 .notdef +!12 U+0012 .notdef +!13 U+0013 .notdef +!14 U+0014 .notdef +!15 U+0015 .notdef +!16 U+0016 .notdef +!17 U+0017 .notdef +!18 U+0018 .notdef +!19 U+0019 .notdef +!1A U+001A .notdef +!1B U+001B .notdef +!1C U+001C .notdef +!1D U+001D .notdef +!1E U+001E .notdef +!1F U+001F .notdef +!20 U+0020 space +!21 U+0021 exclam +!22 U+0022 quotedbl +!23 U+0023 numbersign +!24 U+0024 dollar +!25 U+0025 percent +!26 U+0026 ampersand +!27 U+0027 quotesingle +!28 U+0028 parenleft +!29 U+0029 parenright +!2A U+002A asterisk +!2B U+002B plus +!2C U+002C comma +!2D U+002D hyphen +!2E U+002E period +!2F U+002F slash +!30 U+0030 zero +!31 U+0031 one +!32 U+0032 two +!33 U+0033 three +!34 U+0034 four +!35 U+0035 five +!36 U+0036 six +!37 U+0037 seven +!38 U+0038 eight +!39 U+0039 nine +!3A U+003A colon +!3B U+003B semicolon +!3C U+003C less +!3D U+003D equal +!3E U+003E greater +!3F U+003F question +!40 U+0040 at +!41 U+0041 A +!42 U+0042 B +!43 U+0043 C +!44 U+0044 D +!45 U+0045 E +!46 U+0046 F +!47 U+0047 G +!48 U+0048 H +!49 U+0049 I +!4A U+004A J +!4B U+004B K +!4C U+004C L +!4D U+004D M +!4E U+004E N +!4F U+004F O +!50 U+0050 P +!51 U+0051 Q +!52 U+0052 R +!53 U+0053 S +!54 U+0054 T +!55 U+0055 U +!56 U+0056 V +!57 U+0057 W +!58 U+0058 X +!59 U+0059 Y +!5A U+005A Z +!5B U+005B bracketleft +!5C U+005C backslash +!5D U+005D bracketright +!5E U+005E asciicircum +!5F U+005F underscore +!60 U+0060 grave +!61 U+0061 a +!62 U+0062 b +!63 U+0063 c +!64 U+0064 d +!65 U+0065 e +!66 U+0066 f +!67 U+0067 g +!68 U+0068 h +!69 U+0069 i +!6A U+006A j +!6B U+006B k +!6C U+006C l +!6D U+006D m +!6E U+006E n +!6F U+006F o +!70 U+0070 p +!71 U+0071 q +!72 U+0072 r +!73 U+0073 s +!74 U+0074 t +!75 U+0075 u +!76 U+0076 v +!77 U+0077 w +!78 U+0078 x +!79 U+0079 y +!7A U+007A z +!7B U+007B braceleft +!7C U+007C bar +!7D U+007D braceright +!7E U+007E asciitilde +!7F U+007F .notdef +!80 U+20AC Euro +!82 U+201A quotesinglbase +!84 U+201E quotedblbase +!85 U+2026 ellipsis +!86 U+2020 dagger +!87 U+2021 daggerdbl +!89 U+2030 perthousand +!8A U+0160 Scaron +!8B U+2039 guilsinglleft +!8C U+015A Sacute +!8D U+0164 Tcaron +!8E U+017D Zcaron +!8F U+0179 Zacute +!91 U+2018 quoteleft +!92 U+2019 quoteright +!93 U+201C quotedblleft +!94 U+201D quotedblright +!95 U+2022 bullet +!96 U+2013 endash +!97 U+2014 emdash +!99 U+2122 trademark +!9A U+0161 scaron +!9B U+203A guilsinglright +!9C U+015B sacute +!9D U+0165 tcaron +!9E U+017E zcaron +!9F U+017A zacute +!A0 U+00A0 space +!A1 U+02C7 caron +!A2 U+02D8 breve +!A3 U+0141 Lslash +!A4 U+00A4 currency +!A5 U+0104 Aogonek +!A6 U+00A6 brokenbar +!A7 U+00A7 section +!A8 U+00A8 dieresis +!A9 U+00A9 copyright +!AA U+015E Scedilla +!AB U+00AB guillemotleft +!AC U+00AC logicalnot +!AD U+00AD hyphen +!AE U+00AE registered +!AF U+017B Zdotaccent +!B0 U+00B0 degree +!B1 U+00B1 plusminus +!B2 U+02DB ogonek +!B3 U+0142 lslash +!B4 U+00B4 acute +!B5 U+00B5 mu +!B6 U+00B6 paragraph +!B7 U+00B7 periodcentered +!B8 U+00B8 cedilla +!B9 U+0105 aogonek +!BA U+015F scedilla +!BB U+00BB guillemotright +!BC U+013D Lcaron +!BD U+02DD hungarumlaut +!BE U+013E lcaron +!BF U+017C zdotaccent +!C0 U+0154 Racute +!C1 U+00C1 Aacute +!C2 U+00C2 Acircumflex +!C3 U+0102 Abreve +!C4 U+00C4 Adieresis +!C5 U+0139 Lacute +!C6 U+0106 Cacute +!C7 U+00C7 Ccedilla +!C8 U+010C Ccaron +!C9 U+00C9 Eacute +!CA U+0118 Eogonek +!CB U+00CB Edieresis +!CC U+011A Ecaron +!CD U+00CD Iacute +!CE U+00CE Icircumflex +!CF U+010E Dcaron +!D0 U+0110 Dcroat +!D1 U+0143 Nacute +!D2 U+0147 Ncaron +!D3 U+00D3 Oacute +!D4 U+00D4 Ocircumflex +!D5 U+0150 Ohungarumlaut +!D6 U+00D6 Odieresis +!D7 U+00D7 multiply +!D8 U+0158 Rcaron +!D9 U+016E Uring +!DA U+00DA Uacute +!DB U+0170 Uhungarumlaut +!DC U+00DC Udieresis +!DD U+00DD Yacute +!DE U+0162 Tcommaaccent +!DF U+00DF germandbls +!E0 U+0155 racute +!E1 U+00E1 aacute +!E2 U+00E2 acircumflex +!E3 U+0103 abreve +!E4 U+00E4 adieresis +!E5 U+013A lacute +!E6 U+0107 cacute +!E7 U+00E7 ccedilla +!E8 U+010D ccaron +!E9 U+00E9 eacute +!EA U+0119 eogonek +!EB U+00EB edieresis +!EC U+011B ecaron +!ED U+00ED iacute +!EE U+00EE icircumflex +!EF U+010F dcaron +!F0 U+0111 dcroat +!F1 U+0144 nacute +!F2 U+0148 ncaron +!F3 U+00F3 oacute +!F4 U+00F4 ocircumflex +!F5 U+0151 ohungarumlaut +!F6 U+00F6 odieresis +!F7 U+00F7 divide +!F8 U+0159 rcaron +!F9 U+016F uring +!FA U+00FA uacute +!FB U+0171 uhungarumlaut +!FC U+00FC udieresis +!FD U+00FD yacute +!FE U+0163 tcommaaccent +!FF U+02D9 dotaccent diff --git a/include/tcpdf/fonts/utils/enc/cp1251.map b/include/tcpdf/fonts/utils/enc/cp1251.map new file mode 100644 index 00000000..de6a198d --- /dev/null +++ b/include/tcpdf/fonts/utils/enc/cp1251.map @@ -0,0 +1,255 @@ +!00 U+0000 .notdef +!01 U+0001 .notdef +!02 U+0002 .notdef +!03 U+0003 .notdef +!04 U+0004 .notdef +!05 U+0005 .notdef +!06 U+0006 .notdef +!07 U+0007 .notdef +!08 U+0008 .notdef +!09 U+0009 .notdef +!0A U+000A .notdef +!0B U+000B .notdef +!0C U+000C .notdef +!0D U+000D .notdef +!0E U+000E .notdef +!0F U+000F .notdef +!10 U+0010 .notdef +!11 U+0011 .notdef +!12 U+0012 .notdef +!13 U+0013 .notdef +!14 U+0014 .notdef +!15 U+0015 .notdef +!16 U+0016 .notdef +!17 U+0017 .notdef +!18 U+0018 .notdef +!19 U+0019 .notdef +!1A U+001A .notdef +!1B U+001B .notdef +!1C U+001C .notdef +!1D U+001D .notdef +!1E U+001E .notdef +!1F U+001F .notdef +!20 U+0020 space +!21 U+0021 exclam +!22 U+0022 quotedbl +!23 U+0023 numbersign +!24 U+0024 dollar +!25 U+0025 percent +!26 U+0026 ampersand +!27 U+0027 quotesingle +!28 U+0028 parenleft +!29 U+0029 parenright +!2A U+002A asterisk +!2B U+002B plus +!2C U+002C comma +!2D U+002D hyphen +!2E U+002E period +!2F U+002F slash +!30 U+0030 zero +!31 U+0031 one +!32 U+0032 two +!33 U+0033 three +!34 U+0034 four +!35 U+0035 five +!36 U+0036 six +!37 U+0037 seven +!38 U+0038 eight +!39 U+0039 nine +!3A U+003A colon +!3B U+003B semicolon +!3C U+003C less +!3D U+003D equal +!3E U+003E greater +!3F U+003F question +!40 U+0040 at +!41 U+0041 A +!42 U+0042 B +!43 U+0043 C +!44 U+0044 D +!45 U+0045 E +!46 U+0046 F +!47 U+0047 G +!48 U+0048 H +!49 U+0049 I +!4A U+004A J +!4B U+004B K +!4C U+004C L +!4D U+004D M +!4E U+004E N +!4F U+004F O +!50 U+0050 P +!51 U+0051 Q +!52 U+0052 R +!53 U+0053 S +!54 U+0054 T +!55 U+0055 U +!56 U+0056 V +!57 U+0057 W +!58 U+0058 X +!59 U+0059 Y +!5A U+005A Z +!5B U+005B bracketleft +!5C U+005C backslash +!5D U+005D bracketright +!5E U+005E asciicircum +!5F U+005F underscore +!60 U+0060 grave +!61 U+0061 a +!62 U+0062 b +!63 U+0063 c +!64 U+0064 d +!65 U+0065 e +!66 U+0066 f +!67 U+0067 g +!68 U+0068 h +!69 U+0069 i +!6A U+006A j +!6B U+006B k +!6C U+006C l +!6D U+006D m +!6E U+006E n +!6F U+006F o +!70 U+0070 p +!71 U+0071 q +!72 U+0072 r +!73 U+0073 s +!74 U+0074 t +!75 U+0075 u +!76 U+0076 v +!77 U+0077 w +!78 U+0078 x +!79 U+0079 y +!7A U+007A z +!7B U+007B braceleft +!7C U+007C bar +!7D U+007D braceright +!7E U+007E asciitilde +!7F U+007F .notdef +!80 U+0402 afii10051 +!81 U+0403 afii10052 +!82 U+201A quotesinglbase +!83 U+0453 afii10100 +!84 U+201E quotedblbase +!85 U+2026 ellipsis +!86 U+2020 dagger +!87 U+2021 daggerdbl +!88 U+20AC Euro +!89 U+2030 perthousand +!8A U+0409 afii10058 +!8B U+2039 guilsinglleft +!8C U+040A afii10059 +!8D U+040C afii10061 +!8E U+040B afii10060 +!8F U+040F afii10145 +!90 U+0452 afii10099 +!91 U+2018 quoteleft +!92 U+2019 quoteright +!93 U+201C quotedblleft +!94 U+201D quotedblright +!95 U+2022 bullet +!96 U+2013 endash +!97 U+2014 emdash +!99 U+2122 trademark +!9A U+0459 afii10106 +!9B U+203A guilsinglright +!9C U+045A afii10107 +!9D U+045C afii10109 +!9E U+045B afii10108 +!9F U+045F afii10193 +!A0 U+00A0 space +!A1 U+040E afii10062 +!A2 U+045E afii10110 +!A3 U+0408 afii10057 +!A4 U+00A4 currency +!A5 U+0490 afii10050 +!A6 U+00A6 brokenbar +!A7 U+00A7 section +!A8 U+0401 afii10023 +!A9 U+00A9 copyright +!AA U+0404 afii10053 +!AB U+00AB guillemotleft +!AC U+00AC logicalnot +!AD U+00AD hyphen +!AE U+00AE registered +!AF U+0407 afii10056 +!B0 U+00B0 degree +!B1 U+00B1 plusminus +!B2 U+0406 afii10055 +!B3 U+0456 afii10103 +!B4 U+0491 afii10098 +!B5 U+00B5 mu +!B6 U+00B6 paragraph +!B7 U+00B7 periodcentered +!B8 U+0451 afii10071 +!B9 U+2116 afii61352 +!BA U+0454 afii10101 +!BB U+00BB guillemotright +!BC U+0458 afii10105 +!BD U+0405 afii10054 +!BE U+0455 afii10102 +!BF U+0457 afii10104 +!C0 U+0410 afii10017 +!C1 U+0411 afii10018 +!C2 U+0412 afii10019 +!C3 U+0413 afii10020 +!C4 U+0414 afii10021 +!C5 U+0415 afii10022 +!C6 U+0416 afii10024 +!C7 U+0417 afii10025 +!C8 U+0418 afii10026 +!C9 U+0419 afii10027 +!CA U+041A afii10028 +!CB U+041B afii10029 +!CC U+041C afii10030 +!CD U+041D afii10031 +!CE U+041E afii10032 +!CF U+041F afii10033 +!D0 U+0420 afii10034 +!D1 U+0421 afii10035 +!D2 U+0422 afii10036 +!D3 U+0423 afii10037 +!D4 U+0424 afii10038 +!D5 U+0425 afii10039 +!D6 U+0426 afii10040 +!D7 U+0427 afii10041 +!D8 U+0428 afii10042 +!D9 U+0429 afii10043 +!DA U+042A afii10044 +!DB U+042B afii10045 +!DC U+042C afii10046 +!DD U+042D afii10047 +!DE U+042E afii10048 +!DF U+042F afii10049 +!E0 U+0430 afii10065 +!E1 U+0431 afii10066 +!E2 U+0432 afii10067 +!E3 U+0433 afii10068 +!E4 U+0434 afii10069 +!E5 U+0435 afii10070 +!E6 U+0436 afii10072 +!E7 U+0437 afii10073 +!E8 U+0438 afii10074 +!E9 U+0439 afii10075 +!EA U+043A afii10076 +!EB U+043B afii10077 +!EC U+043C afii10078 +!ED U+043D afii10079 +!EE U+043E afii10080 +!EF U+043F afii10081 +!F0 U+0440 afii10082 +!F1 U+0441 afii10083 +!F2 U+0442 afii10084 +!F3 U+0443 afii10085 +!F4 U+0444 afii10086 +!F5 U+0445 afii10087 +!F6 U+0446 afii10088 +!F7 U+0447 afii10089 +!F8 U+0448 afii10090 +!F9 U+0449 afii10091 +!FA U+044A afii10092 +!FB U+044B afii10093 +!FC U+044C afii10094 +!FD U+044D afii10095 +!FE U+044E afii10096 +!FF U+044F afii10097 diff --git a/include/tcpdf/fonts/utils/enc/cp1252.map b/include/tcpdf/fonts/utils/enc/cp1252.map new file mode 100644 index 00000000..dd490e59 --- /dev/null +++ b/include/tcpdf/fonts/utils/enc/cp1252.map @@ -0,0 +1,251 @@ +!00 U+0000 .notdef +!01 U+0001 .notdef +!02 U+0002 .notdef +!03 U+0003 .notdef +!04 U+0004 .notdef +!05 U+0005 .notdef +!06 U+0006 .notdef +!07 U+0007 .notdef +!08 U+0008 .notdef +!09 U+0009 .notdef +!0A U+000A .notdef +!0B U+000B .notdef +!0C U+000C .notdef +!0D U+000D .notdef +!0E U+000E .notdef +!0F U+000F .notdef +!10 U+0010 .notdef +!11 U+0011 .notdef +!12 U+0012 .notdef +!13 U+0013 .notdef +!14 U+0014 .notdef +!15 U+0015 .notdef +!16 U+0016 .notdef +!17 U+0017 .notdef +!18 U+0018 .notdef +!19 U+0019 .notdef +!1A U+001A .notdef +!1B U+001B .notdef +!1C U+001C .notdef +!1D U+001D .notdef +!1E U+001E .notdef +!1F U+001F .notdef +!20 U+0020 space +!21 U+0021 exclam +!22 U+0022 quotedbl +!23 U+0023 numbersign +!24 U+0024 dollar +!25 U+0025 percent +!26 U+0026 ampersand +!27 U+0027 quotesingle +!28 U+0028 parenleft +!29 U+0029 parenright +!2A U+002A asterisk +!2B U+002B plus +!2C U+002C comma +!2D U+002D hyphen +!2E U+002E period +!2F U+002F slash +!30 U+0030 zero +!31 U+0031 one +!32 U+0032 two +!33 U+0033 three +!34 U+0034 four +!35 U+0035 five +!36 U+0036 six +!37 U+0037 seven +!38 U+0038 eight +!39 U+0039 nine +!3A U+003A colon +!3B U+003B semicolon +!3C U+003C less +!3D U+003D equal +!3E U+003E greater +!3F U+003F question +!40 U+0040 at +!41 U+0041 A +!42 U+0042 B +!43 U+0043 C +!44 U+0044 D +!45 U+0045 E +!46 U+0046 F +!47 U+0047 G +!48 U+0048 H +!49 U+0049 I +!4A U+004A J +!4B U+004B K +!4C U+004C L +!4D U+004D M +!4E U+004E N +!4F U+004F O +!50 U+0050 P +!51 U+0051 Q +!52 U+0052 R +!53 U+0053 S +!54 U+0054 T +!55 U+0055 U +!56 U+0056 V +!57 U+0057 W +!58 U+0058 X +!59 U+0059 Y +!5A U+005A Z +!5B U+005B bracketleft +!5C U+005C backslash +!5D U+005D bracketright +!5E U+005E asciicircum +!5F U+005F underscore +!60 U+0060 grave +!61 U+0061 a +!62 U+0062 b +!63 U+0063 c +!64 U+0064 d +!65 U+0065 e +!66 U+0066 f +!67 U+0067 g +!68 U+0068 h +!69 U+0069 i +!6A U+006A j +!6B U+006B k +!6C U+006C l +!6D U+006D m +!6E U+006E n +!6F U+006F o +!70 U+0070 p +!71 U+0071 q +!72 U+0072 r +!73 U+0073 s +!74 U+0074 t +!75 U+0075 u +!76 U+0076 v +!77 U+0077 w +!78 U+0078 x +!79 U+0079 y +!7A U+007A z +!7B U+007B braceleft +!7C U+007C bar +!7D U+007D braceright +!7E U+007E asciitilde +!7F U+007F .notdef +!80 U+20AC Euro +!82 U+201A quotesinglbase +!83 U+0192 florin +!84 U+201E quotedblbase +!85 U+2026 ellipsis +!86 U+2020 dagger +!87 U+2021 daggerdbl +!88 U+02C6 circumflex +!89 U+2030 perthousand +!8A U+0160 Scaron +!8B U+2039 guilsinglleft +!8C U+0152 OE +!8E U+017D Zcaron +!91 U+2018 quoteleft +!92 U+2019 quoteright +!93 U+201C quotedblleft +!94 U+201D quotedblright +!95 U+2022 bullet +!96 U+2013 endash +!97 U+2014 emdash +!98 U+02DC tilde +!99 U+2122 trademark +!9A U+0161 scaron +!9B U+203A guilsinglright +!9C U+0153 oe +!9E U+017E zcaron +!9F U+0178 Ydieresis +!A0 U+00A0 space +!A1 U+00A1 exclamdown +!A2 U+00A2 cent +!A3 U+00A3 sterling +!A4 U+00A4 currency +!A5 U+00A5 yen +!A6 U+00A6 brokenbar +!A7 U+00A7 section +!A8 U+00A8 dieresis +!A9 U+00A9 copyright +!AA U+00AA ordfeminine +!AB U+00AB guillemotleft +!AC U+00AC logicalnot +!AD U+00AD hyphen +!AE U+00AE registered +!AF U+00AF macron +!B0 U+00B0 degree +!B1 U+00B1 plusminus +!B2 U+00B2 twosuperior +!B3 U+00B3 threesuperior +!B4 U+00B4 acute +!B5 U+00B5 mu +!B6 U+00B6 paragraph +!B7 U+00B7 periodcentered +!B8 U+00B8 cedilla +!B9 U+00B9 onesuperior +!BA U+00BA ordmasculine +!BB U+00BB guillemotright +!BC U+00BC onequarter +!BD U+00BD onehalf +!BE U+00BE threequarters +!BF U+00BF questiondown +!C0 U+00C0 Agrave +!C1 U+00C1 Aacute +!C2 U+00C2 Acircumflex +!C3 U+00C3 Atilde +!C4 U+00C4 Adieresis +!C5 U+00C5 Aring +!C6 U+00C6 AE +!C7 U+00C7 Ccedilla +!C8 U+00C8 Egrave +!C9 U+00C9 Eacute +!CA U+00CA Ecircumflex +!CB U+00CB Edieresis +!CC U+00CC Igrave +!CD U+00CD Iacute +!CE U+00CE Icircumflex +!CF U+00CF Idieresis +!D0 U+00D0 Eth +!D1 U+00D1 Ntilde +!D2 U+00D2 Ograve +!D3 U+00D3 Oacute +!D4 U+00D4 Ocircumflex +!D5 U+00D5 Otilde +!D6 U+00D6 Odieresis +!D7 U+00D7 multiply +!D8 U+00D8 Oslash +!D9 U+00D9 Ugrave +!DA U+00DA Uacute +!DB U+00DB Ucircumflex +!DC U+00DC Udieresis +!DD U+00DD Yacute +!DE U+00DE Thorn +!DF U+00DF germandbls +!E0 U+00E0 agrave +!E1 U+00E1 aacute +!E2 U+00E2 acircumflex +!E3 U+00E3 atilde +!E4 U+00E4 adieresis +!E5 U+00E5 aring +!E6 U+00E6 ae +!E7 U+00E7 ccedilla +!E8 U+00E8 egrave +!E9 U+00E9 eacute +!EA U+00EA ecircumflex +!EB U+00EB edieresis +!EC U+00EC igrave +!ED U+00ED iacute +!EE U+00EE icircumflex +!EF U+00EF idieresis +!F0 U+00F0 eth +!F1 U+00F1 ntilde +!F2 U+00F2 ograve +!F3 U+00F3 oacute +!F4 U+00F4 ocircumflex +!F5 U+00F5 otilde +!F6 U+00F6 odieresis +!F7 U+00F7 divide +!F8 U+00F8 oslash +!F9 U+00F9 ugrave +!FA U+00FA uacute +!FB U+00FB ucircumflex +!FC U+00FC udieresis +!FD U+00FD yacute +!FE U+00FE thorn +!FF U+00FF ydieresis diff --git a/include/tcpdf/fonts/utils/enc/cp1253.map b/include/tcpdf/fonts/utils/enc/cp1253.map new file mode 100644 index 00000000..4bd826fb --- /dev/null +++ b/include/tcpdf/fonts/utils/enc/cp1253.map @@ -0,0 +1,239 @@ +!00 U+0000 .notdef +!01 U+0001 .notdef +!02 U+0002 .notdef +!03 U+0003 .notdef +!04 U+0004 .notdef +!05 U+0005 .notdef +!06 U+0006 .notdef +!07 U+0007 .notdef +!08 U+0008 .notdef +!09 U+0009 .notdef +!0A U+000A .notdef +!0B U+000B .notdef +!0C U+000C .notdef +!0D U+000D .notdef +!0E U+000E .notdef +!0F U+000F .notdef +!10 U+0010 .notdef +!11 U+0011 .notdef +!12 U+0012 .notdef +!13 U+0013 .notdef +!14 U+0014 .notdef +!15 U+0015 .notdef +!16 U+0016 .notdef +!17 U+0017 .notdef +!18 U+0018 .notdef +!19 U+0019 .notdef +!1A U+001A .notdef +!1B U+001B .notdef +!1C U+001C .notdef +!1D U+001D .notdef +!1E U+001E .notdef +!1F U+001F .notdef +!20 U+0020 space +!21 U+0021 exclam +!22 U+0022 quotedbl +!23 U+0023 numbersign +!24 U+0024 dollar +!25 U+0025 percent +!26 U+0026 ampersand +!27 U+0027 quotesingle +!28 U+0028 parenleft +!29 U+0029 parenright +!2A U+002A asterisk +!2B U+002B plus +!2C U+002C comma +!2D U+002D hyphen +!2E U+002E period +!2F U+002F slash +!30 U+0030 zero +!31 U+0031 one +!32 U+0032 two +!33 U+0033 three +!34 U+0034 four +!35 U+0035 five +!36 U+0036 six +!37 U+0037 seven +!38 U+0038 eight +!39 U+0039 nine +!3A U+003A colon +!3B U+003B semicolon +!3C U+003C less +!3D U+003D equal +!3E U+003E greater +!3F U+003F question +!40 U+0040 at +!41 U+0041 A +!42 U+0042 B +!43 U+0043 C +!44 U+0044 D +!45 U+0045 E +!46 U+0046 F +!47 U+0047 G +!48 U+0048 H +!49 U+0049 I +!4A U+004A J +!4B U+004B K +!4C U+004C L +!4D U+004D M +!4E U+004E N +!4F U+004F O +!50 U+0050 P +!51 U+0051 Q +!52 U+0052 R +!53 U+0053 S +!54 U+0054 T +!55 U+0055 U +!56 U+0056 V +!57 U+0057 W +!58 U+0058 X +!59 U+0059 Y +!5A U+005A Z +!5B U+005B bracketleft +!5C U+005C backslash +!5D U+005D bracketright +!5E U+005E asciicircum +!5F U+005F underscore +!60 U+0060 grave +!61 U+0061 a +!62 U+0062 b +!63 U+0063 c +!64 U+0064 d +!65 U+0065 e +!66 U+0066 f +!67 U+0067 g +!68 U+0068 h +!69 U+0069 i +!6A U+006A j +!6B U+006B k +!6C U+006C l +!6D U+006D m +!6E U+006E n +!6F U+006F o +!70 U+0070 p +!71 U+0071 q +!72 U+0072 r +!73 U+0073 s +!74 U+0074 t +!75 U+0075 u +!76 U+0076 v +!77 U+0077 w +!78 U+0078 x +!79 U+0079 y +!7A U+007A z +!7B U+007B braceleft +!7C U+007C bar +!7D U+007D braceright +!7E U+007E asciitilde +!7F U+007F .notdef +!80 U+20AC Euro +!82 U+201A quotesinglbase +!83 U+0192 florin +!84 U+201E quotedblbase +!85 U+2026 ellipsis +!86 U+2020 dagger +!87 U+2021 daggerdbl +!89 U+2030 perthousand +!8B U+2039 guilsinglleft +!91 U+2018 quoteleft +!92 U+2019 quoteright +!93 U+201C quotedblleft +!94 U+201D quotedblright +!95 U+2022 bullet +!96 U+2013 endash +!97 U+2014 emdash +!99 U+2122 trademark +!9B U+203A guilsinglright +!A0 U+00A0 space +!A1 U+0385 dieresistonos +!A2 U+0386 Alphatonos +!A3 U+00A3 sterling +!A4 U+00A4 currency +!A5 U+00A5 yen +!A6 U+00A6 brokenbar +!A7 U+00A7 section +!A8 U+00A8 dieresis +!A9 U+00A9 copyright +!AB U+00AB guillemotleft +!AC U+00AC logicalnot +!AD U+00AD hyphen +!AE U+00AE registered +!AF U+2015 afii00208 +!B0 U+00B0 degree +!B1 U+00B1 plusminus +!B2 U+00B2 twosuperior +!B3 U+00B3 threesuperior +!B4 U+0384 tonos +!B5 U+00B5 mu +!B6 U+00B6 paragraph +!B7 U+00B7 periodcentered +!B8 U+0388 Epsilontonos +!B9 U+0389 Etatonos +!BA U+038A Iotatonos +!BB U+00BB guillemotright +!BC U+038C Omicrontonos +!BD U+00BD onehalf +!BE U+038E Upsilontonos +!BF U+038F Omegatonos +!C0 U+0390 iotadieresistonos +!C1 U+0391 Alpha +!C2 U+0392 Beta +!C3 U+0393 Gamma +!C4 U+0394 Delta +!C5 U+0395 Epsilon +!C6 U+0396 Zeta +!C7 U+0397 Eta +!C8 U+0398 Theta +!C9 U+0399 Iota +!CA U+039A Kappa +!CB U+039B Lambda +!CC U+039C Mu +!CD U+039D Nu +!CE U+039E Xi +!CF U+039F Omicron +!D0 U+03A0 Pi +!D1 U+03A1 Rho +!D3 U+03A3 Sigma +!D4 U+03A4 Tau +!D5 U+03A5 Upsilon +!D6 U+03A6 Phi +!D7 U+03A7 Chi +!D8 U+03A8 Psi +!D9 U+03A9 Omega +!DA U+03AA Iotadieresis +!DB U+03AB Upsilondieresis +!DC U+03AC alphatonos +!DD U+03AD epsilontonos +!DE U+03AE etatonos +!DF U+03AF iotatonos +!E0 U+03B0 upsilondieresistonos +!E1 U+03B1 alpha +!E2 U+03B2 beta +!E3 U+03B3 gamma +!E4 U+03B4 delta +!E5 U+03B5 epsilon +!E6 U+03B6 zeta +!E7 U+03B7 eta +!E8 U+03B8 theta +!E9 U+03B9 iota +!EA U+03BA kappa +!EB U+03BB lambda +!EC U+03BC mu +!ED U+03BD nu +!EE U+03BE xi +!EF U+03BF omicron +!F0 U+03C0 pi +!F1 U+03C1 rho +!F2 U+03C2 sigma1 +!F3 U+03C3 sigma +!F4 U+03C4 tau +!F5 U+03C5 upsilon +!F6 U+03C6 phi +!F7 U+03C7 chi +!F8 U+03C8 psi +!F9 U+03C9 omega +!FA U+03CA iotadieresis +!FB U+03CB upsilondieresis +!FC U+03CC omicrontonos +!FD U+03CD upsilontonos +!FE U+03CE omegatonos diff --git a/include/tcpdf/fonts/utils/enc/cp1254.map b/include/tcpdf/fonts/utils/enc/cp1254.map new file mode 100644 index 00000000..829473b2 --- /dev/null +++ b/include/tcpdf/fonts/utils/enc/cp1254.map @@ -0,0 +1,249 @@ +!00 U+0000 .notdef +!01 U+0001 .notdef +!02 U+0002 .notdef +!03 U+0003 .notdef +!04 U+0004 .notdef +!05 U+0005 .notdef +!06 U+0006 .notdef +!07 U+0007 .notdef +!08 U+0008 .notdef +!09 U+0009 .notdef +!0A U+000A .notdef +!0B U+000B .notdef +!0C U+000C .notdef +!0D U+000D .notdef +!0E U+000E .notdef +!0F U+000F .notdef +!10 U+0010 .notdef +!11 U+0011 .notdef +!12 U+0012 .notdef +!13 U+0013 .notdef +!14 U+0014 .notdef +!15 U+0015 .notdef +!16 U+0016 .notdef +!17 U+0017 .notdef +!18 U+0018 .notdef +!19 U+0019 .notdef +!1A U+001A .notdef +!1B U+001B .notdef +!1C U+001C .notdef +!1D U+001D .notdef +!1E U+001E .notdef +!1F U+001F .notdef +!20 U+0020 space +!21 U+0021 exclam +!22 U+0022 quotedbl +!23 U+0023 numbersign +!24 U+0024 dollar +!25 U+0025 percent +!26 U+0026 ampersand +!27 U+0027 quotesingle +!28 U+0028 parenleft +!29 U+0029 parenright +!2A U+002A asterisk +!2B U+002B plus +!2C U+002C comma +!2D U+002D hyphen +!2E U+002E period +!2F U+002F slash +!30 U+0030 zero +!31 U+0031 one +!32 U+0032 two +!33 U+0033 three +!34 U+0034 four +!35 U+0035 five +!36 U+0036 six +!37 U+0037 seven +!38 U+0038 eight +!39 U+0039 nine +!3A U+003A colon +!3B U+003B semicolon +!3C U+003C less +!3D U+003D equal +!3E U+003E greater +!3F U+003F question +!40 U+0040 at +!41 U+0041 A +!42 U+0042 B +!43 U+0043 C +!44 U+0044 D +!45 U+0045 E +!46 U+0046 F +!47 U+0047 G +!48 U+0048 H +!49 U+0049 I +!4A U+004A J +!4B U+004B K +!4C U+004C L +!4D U+004D M +!4E U+004E N +!4F U+004F O +!50 U+0050 P +!51 U+0051 Q +!52 U+0052 R +!53 U+0053 S +!54 U+0054 T +!55 U+0055 U +!56 U+0056 V +!57 U+0057 W +!58 U+0058 X +!59 U+0059 Y +!5A U+005A Z +!5B U+005B bracketleft +!5C U+005C backslash +!5D U+005D bracketright +!5E U+005E asciicircum +!5F U+005F underscore +!60 U+0060 grave +!61 U+0061 a +!62 U+0062 b +!63 U+0063 c +!64 U+0064 d +!65 U+0065 e +!66 U+0066 f +!67 U+0067 g +!68 U+0068 h +!69 U+0069 i +!6A U+006A j +!6B U+006B k +!6C U+006C l +!6D U+006D m +!6E U+006E n +!6F U+006F o +!70 U+0070 p +!71 U+0071 q +!72 U+0072 r +!73 U+0073 s +!74 U+0074 t +!75 U+0075 u +!76 U+0076 v +!77 U+0077 w +!78 U+0078 x +!79 U+0079 y +!7A U+007A z +!7B U+007B braceleft +!7C U+007C bar +!7D U+007D braceright +!7E U+007E asciitilde +!7F U+007F .notdef +!80 U+20AC Euro +!82 U+201A quotesinglbase +!83 U+0192 florin +!84 U+201E quotedblbase +!85 U+2026 ellipsis +!86 U+2020 dagger +!87 U+2021 daggerdbl +!88 U+02C6 circumflex +!89 U+2030 perthousand +!8A U+0160 Scaron +!8B U+2039 guilsinglleft +!8C U+0152 OE +!91 U+2018 quoteleft +!92 U+2019 quoteright +!93 U+201C quotedblleft +!94 U+201D quotedblright +!95 U+2022 bullet +!96 U+2013 endash +!97 U+2014 emdash +!98 U+02DC tilde +!99 U+2122 trademark +!9A U+0161 scaron +!9B U+203A guilsinglright +!9C U+0153 oe +!9F U+0178 Ydieresis +!A0 U+00A0 space +!A1 U+00A1 exclamdown +!A2 U+00A2 cent +!A3 U+00A3 sterling +!A4 U+00A4 currency +!A5 U+00A5 yen +!A6 U+00A6 brokenbar +!A7 U+00A7 section +!A8 U+00A8 dieresis +!A9 U+00A9 copyright +!AA U+00AA ordfeminine +!AB U+00AB guillemotleft +!AC U+00AC logicalnot +!AD U+00AD hyphen +!AE U+00AE registered +!AF U+00AF macron +!B0 U+00B0 degree +!B1 U+00B1 plusminus +!B2 U+00B2 twosuperior +!B3 U+00B3 threesuperior +!B4 U+00B4 acute +!B5 U+00B5 mu +!B6 U+00B6 paragraph +!B7 U+00B7 periodcentered +!B8 U+00B8 cedilla +!B9 U+00B9 onesuperior +!BA U+00BA ordmasculine +!BB U+00BB guillemotright +!BC U+00BC onequarter +!BD U+00BD onehalf +!BE U+00BE threequarters +!BF U+00BF questiondown +!C0 U+00C0 Agrave +!C1 U+00C1 Aacute +!C2 U+00C2 Acircumflex +!C3 U+00C3 Atilde +!C4 U+00C4 Adieresis +!C5 U+00C5 Aring +!C6 U+00C6 AE +!C7 U+00C7 Ccedilla +!C8 U+00C8 Egrave +!C9 U+00C9 Eacute +!CA U+00CA Ecircumflex +!CB U+00CB Edieresis +!CC U+00CC Igrave +!CD U+00CD Iacute +!CE U+00CE Icircumflex +!CF U+00CF Idieresis +!D0 U+011E Gbreve +!D1 U+00D1 Ntilde +!D2 U+00D2 Ograve +!D3 U+00D3 Oacute +!D4 U+00D4 Ocircumflex +!D5 U+00D5 Otilde +!D6 U+00D6 Odieresis +!D7 U+00D7 multiply +!D8 U+00D8 Oslash +!D9 U+00D9 Ugrave +!DA U+00DA Uacute +!DB U+00DB Ucircumflex +!DC U+00DC Udieresis +!DD U+0130 Idotaccent +!DE U+015E Scedilla +!DF U+00DF germandbls +!E0 U+00E0 agrave +!E1 U+00E1 aacute +!E2 U+00E2 acircumflex +!E3 U+00E3 atilde +!E4 U+00E4 adieresis +!E5 U+00E5 aring +!E6 U+00E6 ae +!E7 U+00E7 ccedilla +!E8 U+00E8 egrave +!E9 U+00E9 eacute +!EA U+00EA ecircumflex +!EB U+00EB edieresis +!EC U+00EC igrave +!ED U+00ED iacute +!EE U+00EE icircumflex +!EF U+00EF idieresis +!F0 U+011F gbreve +!F1 U+00F1 ntilde +!F2 U+00F2 ograve +!F3 U+00F3 oacute +!F4 U+00F4 ocircumflex +!F5 U+00F5 otilde +!F6 U+00F6 odieresis +!F7 U+00F7 divide +!F8 U+00F8 oslash +!F9 U+00F9 ugrave +!FA U+00FA uacute +!FB U+00FB ucircumflex +!FC U+00FC udieresis +!FD U+0131 dotlessi +!FE U+015F scedilla +!FF U+00FF ydieresis diff --git a/include/tcpdf/fonts/utils/enc/cp1255.map b/include/tcpdf/fonts/utils/enc/cp1255.map new file mode 100644 index 00000000..079e10c6 --- /dev/null +++ b/include/tcpdf/fonts/utils/enc/cp1255.map @@ -0,0 +1,233 @@ +!00 U+0000 .notdef +!01 U+0001 .notdef +!02 U+0002 .notdef +!03 U+0003 .notdef +!04 U+0004 .notdef +!05 U+0005 .notdef +!06 U+0006 .notdef +!07 U+0007 .notdef +!08 U+0008 .notdef +!09 U+0009 .notdef +!0A U+000A .notdef +!0B U+000B .notdef +!0C U+000C .notdef +!0D U+000D .notdef +!0E U+000E .notdef +!0F U+000F .notdef +!10 U+0010 .notdef +!11 U+0011 .notdef +!12 U+0012 .notdef +!13 U+0013 .notdef +!14 U+0014 .notdef +!15 U+0015 .notdef +!16 U+0016 .notdef +!17 U+0017 .notdef +!18 U+0018 .notdef +!19 U+0019 .notdef +!1A U+001A .notdef +!1B U+001B .notdef +!1C U+001C .notdef +!1D U+001D .notdef +!1E U+001E .notdef +!1F U+001F .notdef +!20 U+0020 space +!21 U+0021 exclam +!22 U+0022 quotedbl +!23 U+0023 numbersign +!24 U+0024 dollar +!25 U+0025 percent +!26 U+0026 ampersand +!27 U+0027 quotesingle +!28 U+0028 parenleft +!29 U+0029 parenright +!2A U+002A asterisk +!2B U+002B plus +!2C U+002C comma +!2D U+002D hyphen +!2E U+002E period +!2F U+002F slash +!30 U+0030 zero +!31 U+0031 one +!32 U+0032 two +!33 U+0033 three +!34 U+0034 four +!35 U+0035 five +!36 U+0036 six +!37 U+0037 seven +!38 U+0038 eight +!39 U+0039 nine +!3A U+003A colon +!3B U+003B semicolon +!3C U+003C less +!3D U+003D equal +!3E U+003E greater +!3F U+003F question +!40 U+0040 at +!41 U+0041 A +!42 U+0042 B +!43 U+0043 C +!44 U+0044 D +!45 U+0045 E +!46 U+0046 F +!47 U+0047 G +!48 U+0048 H +!49 U+0049 I +!4A U+004A J +!4B U+004B K +!4C U+004C L +!4D U+004D M +!4E U+004E N +!4F U+004F O +!50 U+0050 P +!51 U+0051 Q +!52 U+0052 R +!53 U+0053 S +!54 U+0054 T +!55 U+0055 U +!56 U+0056 V +!57 U+0057 W +!58 U+0058 X +!59 U+0059 Y +!5A U+005A Z +!5B U+005B bracketleft +!5C U+005C backslash +!5D U+005D bracketright +!5E U+005E asciicircum +!5F U+005F underscore +!60 U+0060 grave +!61 U+0061 a +!62 U+0062 b +!63 U+0063 c +!64 U+0064 d +!65 U+0065 e +!66 U+0066 f +!67 U+0067 g +!68 U+0068 h +!69 U+0069 i +!6A U+006A j +!6B U+006B k +!6C U+006C l +!6D U+006D m +!6E U+006E n +!6F U+006F o +!70 U+0070 p +!71 U+0071 q +!72 U+0072 r +!73 U+0073 s +!74 U+0074 t +!75 U+0075 u +!76 U+0076 v +!77 U+0077 w +!78 U+0078 x +!79 U+0079 y +!7A U+007A z +!7B U+007B braceleft +!7C U+007C bar +!7D U+007D braceright +!7E U+007E asciitilde +!7F U+007F .notdef +!80 U+20AC Euro +!82 U+201A quotesinglbase +!83 U+0192 florin +!84 U+201E quotedblbase +!85 U+2026 ellipsis +!86 U+2020 dagger +!87 U+2021 daggerdbl +!88 U+02C6 circumflex +!89 U+2030 perthousand +!8B U+2039 guilsinglleft +!91 U+2018 quoteleft +!92 U+2019 quoteright +!93 U+201C quotedblleft +!94 U+201D quotedblright +!95 U+2022 bullet +!96 U+2013 endash +!97 U+2014 emdash +!98 U+02DC tilde +!99 U+2122 trademark +!9B U+203A guilsinglright +!A0 U+00A0 space +!A1 U+00A1 exclamdown +!A2 U+00A2 cent +!A3 U+00A3 sterling +!A4 U+20AA afii57636 +!A5 U+00A5 yen +!A6 U+00A6 brokenbar +!A7 U+00A7 section +!A8 U+00A8 dieresis +!A9 U+00A9 copyright +!AA U+00D7 multiply +!AB U+00AB guillemotleft +!AC U+00AC logicalnot +!AD U+00AD sfthyphen +!AE U+00AE registered +!AF U+00AF macron +!B0 U+00B0 degree +!B1 U+00B1 plusminus +!B2 U+00B2 twosuperior +!B3 U+00B3 threesuperior +!B4 U+00B4 acute +!B5 U+00B5 mu +!B6 U+00B6 paragraph +!B7 U+00B7 middot +!B8 U+00B8 cedilla +!B9 U+00B9 onesuperior +!BA U+00F7 divide +!BB U+00BB guillemotright +!BC U+00BC onequarter +!BD U+00BD onehalf +!BE U+00BE threequarters +!BF U+00BF questiondown +!C0 U+05B0 afii57799 +!C1 U+05B1 afii57801 +!C2 U+05B2 afii57800 +!C3 U+05B3 afii57802 +!C4 U+05B4 afii57793 +!C5 U+05B5 afii57794 +!C6 U+05B6 afii57795 +!C7 U+05B7 afii57798 +!C8 U+05B8 afii57797 +!C9 U+05B9 afii57806 +!CB U+05BB afii57796 +!CC U+05BC afii57807 +!CD U+05BD afii57839 +!CE U+05BE afii57645 +!CF U+05BF afii57841 +!D0 U+05C0 afii57842 +!D1 U+05C1 afii57804 +!D2 U+05C2 afii57803 +!D3 U+05C3 afii57658 +!D4 U+05F0 afii57716 +!D5 U+05F1 afii57717 +!D6 U+05F2 afii57718 +!D7 U+05F3 gereshhebrew +!D8 U+05F4 gershayimhebrew +!E0 U+05D0 afii57664 +!E1 U+05D1 afii57665 +!E2 U+05D2 afii57666 +!E3 U+05D3 afii57667 +!E4 U+05D4 afii57668 +!E5 U+05D5 afii57669 +!E6 U+05D6 afii57670 +!E7 U+05D7 afii57671 +!E8 U+05D8 afii57672 +!E9 U+05D9 afii57673 +!EA U+05DA afii57674 +!EB U+05DB afii57675 +!EC U+05DC afii57676 +!ED U+05DD afii57677 +!EE U+05DE afii57678 +!EF U+05DF afii57679 +!F0 U+05E0 afii57680 +!F1 U+05E1 afii57681 +!F2 U+05E2 afii57682 +!F3 U+05E3 afii57683 +!F4 U+05E4 afii57684 +!F5 U+05E5 afii57685 +!F6 U+05E6 afii57686 +!F7 U+05E7 afii57687 +!F8 U+05E8 afii57688 +!F9 U+05E9 afii57689 +!FA U+05EA afii57690 +!FD U+200E afii299 +!FE U+200F afii300 diff --git a/include/tcpdf/fonts/utils/enc/cp1257.map b/include/tcpdf/fonts/utils/enc/cp1257.map new file mode 100644 index 00000000..2f2ecfa2 --- /dev/null +++ b/include/tcpdf/fonts/utils/enc/cp1257.map @@ -0,0 +1,244 @@ +!00 U+0000 .notdef +!01 U+0001 .notdef +!02 U+0002 .notdef +!03 U+0003 .notdef +!04 U+0004 .notdef +!05 U+0005 .notdef +!06 U+0006 .notdef +!07 U+0007 .notdef +!08 U+0008 .notdef +!09 U+0009 .notdef +!0A U+000A .notdef +!0B U+000B .notdef +!0C U+000C .notdef +!0D U+000D .notdef +!0E U+000E .notdef +!0F U+000F .notdef +!10 U+0010 .notdef +!11 U+0011 .notdef +!12 U+0012 .notdef +!13 U+0013 .notdef +!14 U+0014 .notdef +!15 U+0015 .notdef +!16 U+0016 .notdef +!17 U+0017 .notdef +!18 U+0018 .notdef +!19 U+0019 .notdef +!1A U+001A .notdef +!1B U+001B .notdef +!1C U+001C .notdef +!1D U+001D .notdef +!1E U+001E .notdef +!1F U+001F .notdef +!20 U+0020 space +!21 U+0021 exclam +!22 U+0022 quotedbl +!23 U+0023 numbersign +!24 U+0024 dollar +!25 U+0025 percent +!26 U+0026 ampersand +!27 U+0027 quotesingle +!28 U+0028 parenleft +!29 U+0029 parenright +!2A U+002A asterisk +!2B U+002B plus +!2C U+002C comma +!2D U+002D hyphen +!2E U+002E period +!2F U+002F slash +!30 U+0030 zero +!31 U+0031 one +!32 U+0032 two +!33 U+0033 three +!34 U+0034 four +!35 U+0035 five +!36 U+0036 six +!37 U+0037 seven +!38 U+0038 eight +!39 U+0039 nine +!3A U+003A colon +!3B U+003B semicolon +!3C U+003C less +!3D U+003D equal +!3E U+003E greater +!3F U+003F question +!40 U+0040 at +!41 U+0041 A +!42 U+0042 B +!43 U+0043 C +!44 U+0044 D +!45 U+0045 E +!46 U+0046 F +!47 U+0047 G +!48 U+0048 H +!49 U+0049 I +!4A U+004A J +!4B U+004B K +!4C U+004C L +!4D U+004D M +!4E U+004E N +!4F U+004F O +!50 U+0050 P +!51 U+0051 Q +!52 U+0052 R +!53 U+0053 S +!54 U+0054 T +!55 U+0055 U +!56 U+0056 V +!57 U+0057 W +!58 U+0058 X +!59 U+0059 Y +!5A U+005A Z +!5B U+005B bracketleft +!5C U+005C backslash +!5D U+005D bracketright +!5E U+005E asciicircum +!5F U+005F underscore +!60 U+0060 grave +!61 U+0061 a +!62 U+0062 b +!63 U+0063 c +!64 U+0064 d +!65 U+0065 e +!66 U+0066 f +!67 U+0067 g +!68 U+0068 h +!69 U+0069 i +!6A U+006A j +!6B U+006B k +!6C U+006C l +!6D U+006D m +!6E U+006E n +!6F U+006F o +!70 U+0070 p +!71 U+0071 q +!72 U+0072 r +!73 U+0073 s +!74 U+0074 t +!75 U+0075 u +!76 U+0076 v +!77 U+0077 w +!78 U+0078 x +!79 U+0079 y +!7A U+007A z +!7B U+007B braceleft +!7C U+007C bar +!7D U+007D braceright +!7E U+007E asciitilde +!7F U+007F .notdef +!80 U+20AC Euro +!82 U+201A quotesinglbase +!84 U+201E quotedblbase +!85 U+2026 ellipsis +!86 U+2020 dagger +!87 U+2021 daggerdbl +!89 U+2030 perthousand +!8B U+2039 guilsinglleft +!8D U+00A8 dieresis +!8E U+02C7 caron +!8F U+00B8 cedilla +!91 U+2018 quoteleft +!92 U+2019 quoteright +!93 U+201C quotedblleft +!94 U+201D quotedblright +!95 U+2022 bullet +!96 U+2013 endash +!97 U+2014 emdash +!99 U+2122 trademark +!9B U+203A guilsinglright +!9D U+00AF macron +!9E U+02DB ogonek +!A0 U+00A0 space +!A2 U+00A2 cent +!A3 U+00A3 sterling +!A4 U+00A4 currency +!A6 U+00A6 brokenbar +!A7 U+00A7 section +!A8 U+00D8 Oslash +!A9 U+00A9 copyright +!AA U+0156 Rcommaaccent +!AB U+00AB guillemotleft +!AC U+00AC logicalnot +!AD U+00AD hyphen +!AE U+00AE registered +!AF U+00C6 AE +!B0 U+00B0 degree +!B1 U+00B1 plusminus +!B2 U+00B2 twosuperior +!B3 U+00B3 threesuperior +!B4 U+00B4 acute +!B5 U+00B5 mu +!B6 U+00B6 paragraph +!B7 U+00B7 periodcentered +!B8 U+00F8 oslash +!B9 U+00B9 onesuperior +!BA U+0157 rcommaaccent +!BB U+00BB guillemotright +!BC U+00BC onequarter +!BD U+00BD onehalf +!BE U+00BE threequarters +!BF U+00E6 ae +!C0 U+0104 Aogonek +!C1 U+012E Iogonek +!C2 U+0100 Amacron +!C3 U+0106 Cacute +!C4 U+00C4 Adieresis +!C5 U+00C5 Aring +!C6 U+0118 Eogonek +!C7 U+0112 Emacron +!C8 U+010C Ccaron +!C9 U+00C9 Eacute +!CA U+0179 Zacute +!CB U+0116 Edotaccent +!CC U+0122 Gcommaaccent +!CD U+0136 Kcommaaccent +!CE U+012A Imacron +!CF U+013B Lcommaaccent +!D0 U+0160 Scaron +!D1 U+0143 Nacute +!D2 U+0145 Ncommaaccent +!D3 U+00D3 Oacute +!D4 U+014C Omacron +!D5 U+00D5 Otilde +!D6 U+00D6 Odieresis +!D7 U+00D7 multiply +!D8 U+0172 Uogonek +!D9 U+0141 Lslash +!DA U+015A Sacute +!DB U+016A Umacron +!DC U+00DC Udieresis +!DD U+017B Zdotaccent +!DE U+017D Zcaron +!DF U+00DF germandbls +!E0 U+0105 aogonek +!E1 U+012F iogonek +!E2 U+0101 amacron +!E3 U+0107 cacute +!E4 U+00E4 adieresis +!E5 U+00E5 aring +!E6 U+0119 eogonek +!E7 U+0113 emacron +!E8 U+010D ccaron +!E9 U+00E9 eacute +!EA U+017A zacute +!EB U+0117 edotaccent +!EC U+0123 gcommaaccent +!ED U+0137 kcommaaccent +!EE U+012B imacron +!EF U+013C lcommaaccent +!F0 U+0161 scaron +!F1 U+0144 nacute +!F2 U+0146 ncommaaccent +!F3 U+00F3 oacute +!F4 U+014D omacron +!F5 U+00F5 otilde +!F6 U+00F6 odieresis +!F7 U+00F7 divide +!F8 U+0173 uogonek +!F9 U+0142 lslash +!FA U+015B sacute +!FB U+016B umacron +!FC U+00FC udieresis +!FD U+017C zdotaccent +!FE U+017E zcaron +!FF U+02D9 dotaccent diff --git a/include/tcpdf/fonts/utils/enc/cp1258.map b/include/tcpdf/fonts/utils/enc/cp1258.map new file mode 100644 index 00000000..fed915f7 --- /dev/null +++ b/include/tcpdf/fonts/utils/enc/cp1258.map @@ -0,0 +1,247 @@ +!00 U+0000 .notdef +!01 U+0001 .notdef +!02 U+0002 .notdef +!03 U+0003 .notdef +!04 U+0004 .notdef +!05 U+0005 .notdef +!06 U+0006 .notdef +!07 U+0007 .notdef +!08 U+0008 .notdef +!09 U+0009 .notdef +!0A U+000A .notdef +!0B U+000B .notdef +!0C U+000C .notdef +!0D U+000D .notdef +!0E U+000E .notdef +!0F U+000F .notdef +!10 U+0010 .notdef +!11 U+0011 .notdef +!12 U+0012 .notdef +!13 U+0013 .notdef +!14 U+0014 .notdef +!15 U+0015 .notdef +!16 U+0016 .notdef +!17 U+0017 .notdef +!18 U+0018 .notdef +!19 U+0019 .notdef +!1A U+001A .notdef +!1B U+001B .notdef +!1C U+001C .notdef +!1D U+001D .notdef +!1E U+001E .notdef +!1F U+001F .notdef +!20 U+0020 space +!21 U+0021 exclam +!22 U+0022 quotedbl +!23 U+0023 numbersign +!24 U+0024 dollar +!25 U+0025 percent +!26 U+0026 ampersand +!27 U+0027 quotesingle +!28 U+0028 parenleft +!29 U+0029 parenright +!2A U+002A asterisk +!2B U+002B plus +!2C U+002C comma +!2D U+002D hyphen +!2E U+002E period +!2F U+002F slash +!30 U+0030 zero +!31 U+0031 one +!32 U+0032 two +!33 U+0033 three +!34 U+0034 four +!35 U+0035 five +!36 U+0036 six +!37 U+0037 seven +!38 U+0038 eight +!39 U+0039 nine +!3A U+003A colon +!3B U+003B semicolon +!3C U+003C less +!3D U+003D equal +!3E U+003E greater +!3F U+003F question +!40 U+0040 at +!41 U+0041 A +!42 U+0042 B +!43 U+0043 C +!44 U+0044 D +!45 U+0045 E +!46 U+0046 F +!47 U+0047 G +!48 U+0048 H +!49 U+0049 I +!4A U+004A J +!4B U+004B K +!4C U+004C L +!4D U+004D M +!4E U+004E N +!4F U+004F O +!50 U+0050 P +!51 U+0051 Q +!52 U+0052 R +!53 U+0053 S +!54 U+0054 T +!55 U+0055 U +!56 U+0056 V +!57 U+0057 W +!58 U+0058 X +!59 U+0059 Y +!5A U+005A Z +!5B U+005B bracketleft +!5C U+005C backslash +!5D U+005D bracketright +!5E U+005E asciicircum +!5F U+005F underscore +!60 U+0060 grave +!61 U+0061 a +!62 U+0062 b +!63 U+0063 c +!64 U+0064 d +!65 U+0065 e +!66 U+0066 f +!67 U+0067 g +!68 U+0068 h +!69 U+0069 i +!6A U+006A j +!6B U+006B k +!6C U+006C l +!6D U+006D m +!6E U+006E n +!6F U+006F o +!70 U+0070 p +!71 U+0071 q +!72 U+0072 r +!73 U+0073 s +!74 U+0074 t +!75 U+0075 u +!76 U+0076 v +!77 U+0077 w +!78 U+0078 x +!79 U+0079 y +!7A U+007A z +!7B U+007B braceleft +!7C U+007C bar +!7D U+007D braceright +!7E U+007E asciitilde +!7F U+007F .notdef +!80 U+20AC Euro +!82 U+201A quotesinglbase +!83 U+0192 florin +!84 U+201E quotedblbase +!85 U+2026 ellipsis +!86 U+2020 dagger +!87 U+2021 daggerdbl +!88 U+02C6 circumflex +!89 U+2030 perthousand +!8B U+2039 guilsinglleft +!8C U+0152 OE +!91 U+2018 quoteleft +!92 U+2019 quoteright +!93 U+201C quotedblleft +!94 U+201D quotedblright +!95 U+2022 bullet +!96 U+2013 endash +!97 U+2014 emdash +!98 U+02DC tilde +!99 U+2122 trademark +!9B U+203A guilsinglright +!9C U+0153 oe +!9F U+0178 Ydieresis +!A0 U+00A0 space +!A1 U+00A1 exclamdown +!A2 U+00A2 cent +!A3 U+00A3 sterling +!A4 U+00A4 currency +!A5 U+00A5 yen +!A6 U+00A6 brokenbar +!A7 U+00A7 section +!A8 U+00A8 dieresis +!A9 U+00A9 copyright +!AA U+00AA ordfeminine +!AB U+00AB guillemotleft +!AC U+00AC logicalnot +!AD U+00AD hyphen +!AE U+00AE registered +!AF U+00AF macron +!B0 U+00B0 degree +!B1 U+00B1 plusminus +!B2 U+00B2 twosuperior +!B3 U+00B3 threesuperior +!B4 U+00B4 acute +!B5 U+00B5 mu +!B6 U+00B6 paragraph +!B7 U+00B7 periodcentered +!B8 U+00B8 cedilla +!B9 U+00B9 onesuperior +!BA U+00BA ordmasculine +!BB U+00BB guillemotright +!BC U+00BC onequarter +!BD U+00BD onehalf +!BE U+00BE threequarters +!BF U+00BF questiondown +!C0 U+00C0 Agrave +!C1 U+00C1 Aacute +!C2 U+00C2 Acircumflex +!C3 U+0102 Abreve +!C4 U+00C4 Adieresis +!C5 U+00C5 Aring +!C6 U+00C6 AE +!C7 U+00C7 Ccedilla +!C8 U+00C8 Egrave +!C9 U+00C9 Eacute +!CA U+00CA Ecircumflex +!CB U+00CB Edieresis +!CC U+0300 gravecomb +!CD U+00CD Iacute +!CE U+00CE Icircumflex +!CF U+00CF Idieresis +!D0 U+0110 Dcroat +!D1 U+00D1 Ntilde +!D2 U+0309 hookabovecomb +!D3 U+00D3 Oacute +!D4 U+00D4 Ocircumflex +!D5 U+01A0 Ohorn +!D6 U+00D6 Odieresis +!D7 U+00D7 multiply +!D8 U+00D8 Oslash +!D9 U+00D9 Ugrave +!DA U+00DA Uacute +!DB U+00DB Ucircumflex +!DC U+00DC Udieresis +!DD U+01AF Uhorn +!DE U+0303 tildecomb +!DF U+00DF germandbls +!E0 U+00E0 agrave +!E1 U+00E1 aacute +!E2 U+00E2 acircumflex +!E3 U+0103 abreve +!E4 U+00E4 adieresis +!E5 U+00E5 aring +!E6 U+00E6 ae +!E7 U+00E7 ccedilla +!E8 U+00E8 egrave +!E9 U+00E9 eacute +!EA U+00EA ecircumflex +!EB U+00EB edieresis +!EC U+0301 acutecomb +!ED U+00ED iacute +!EE U+00EE icircumflex +!EF U+00EF idieresis +!F0 U+0111 dcroat +!F1 U+00F1 ntilde +!F2 U+0323 dotbelowcomb +!F3 U+00F3 oacute +!F4 U+00F4 ocircumflex +!F5 U+01A1 ohorn +!F6 U+00F6 odieresis +!F7 U+00F7 divide +!F8 U+00F8 oslash +!F9 U+00F9 ugrave +!FA U+00FA uacute +!FB U+00FB ucircumflex +!FC U+00FC udieresis +!FD U+01B0 uhorn +!FE U+20AB dong +!FF U+00FF ydieresis diff --git a/include/tcpdf/fonts/utils/enc/cp874.map b/include/tcpdf/fonts/utils/enc/cp874.map new file mode 100644 index 00000000..1006e6b1 --- /dev/null +++ b/include/tcpdf/fonts/utils/enc/cp874.map @@ -0,0 +1,225 @@ +!00 U+0000 .notdef +!01 U+0001 .notdef +!02 U+0002 .notdef +!03 U+0003 .notdef +!04 U+0004 .notdef +!05 U+0005 .notdef +!06 U+0006 .notdef +!07 U+0007 .notdef +!08 U+0008 .notdef +!09 U+0009 .notdef +!0A U+000A .notdef +!0B U+000B .notdef +!0C U+000C .notdef +!0D U+000D .notdef +!0E U+000E .notdef +!0F U+000F .notdef +!10 U+0010 .notdef +!11 U+0011 .notdef +!12 U+0012 .notdef +!13 U+0013 .notdef +!14 U+0014 .notdef +!15 U+0015 .notdef +!16 U+0016 .notdef +!17 U+0017 .notdef +!18 U+0018 .notdef +!19 U+0019 .notdef +!1A U+001A .notdef +!1B U+001B .notdef +!1C U+001C .notdef +!1D U+001D .notdef +!1E U+001E .notdef +!1F U+001F .notdef +!20 U+0020 space +!21 U+0021 exclam +!22 U+0022 quotedbl +!23 U+0023 numbersign +!24 U+0024 dollar +!25 U+0025 percent +!26 U+0026 ampersand +!27 U+0027 quotesingle +!28 U+0028 parenleft +!29 U+0029 parenright +!2A U+002A asterisk +!2B U+002B plus +!2C U+002C comma +!2D U+002D hyphen +!2E U+002E period +!2F U+002F slash +!30 U+0030 zero +!31 U+0031 one +!32 U+0032 two +!33 U+0033 three +!34 U+0034 four +!35 U+0035 five +!36 U+0036 six +!37 U+0037 seven +!38 U+0038 eight +!39 U+0039 nine +!3A U+003A colon +!3B U+003B semicolon +!3C U+003C less +!3D U+003D equal +!3E U+003E greater +!3F U+003F question +!40 U+0040 at +!41 U+0041 A +!42 U+0042 B +!43 U+0043 C +!44 U+0044 D +!45 U+0045 E +!46 U+0046 F +!47 U+0047 G +!48 U+0048 H +!49 U+0049 I +!4A U+004A J +!4B U+004B K +!4C U+004C L +!4D U+004D M +!4E U+004E N +!4F U+004F O +!50 U+0050 P +!51 U+0051 Q +!52 U+0052 R +!53 U+0053 S +!54 U+0054 T +!55 U+0055 U +!56 U+0056 V +!57 U+0057 W +!58 U+0058 X +!59 U+0059 Y +!5A U+005A Z +!5B U+005B bracketleft +!5C U+005C backslash +!5D U+005D bracketright +!5E U+005E asciicircum +!5F U+005F underscore +!60 U+0060 grave +!61 U+0061 a +!62 U+0062 b +!63 U+0063 c +!64 U+0064 d +!65 U+0065 e +!66 U+0066 f +!67 U+0067 g +!68 U+0068 h +!69 U+0069 i +!6A U+006A j +!6B U+006B k +!6C U+006C l +!6D U+006D m +!6E U+006E n +!6F U+006F o +!70 U+0070 p +!71 U+0071 q +!72 U+0072 r +!73 U+0073 s +!74 U+0074 t +!75 U+0075 u +!76 U+0076 v +!77 U+0077 w +!78 U+0078 x +!79 U+0079 y +!7A U+007A z +!7B U+007B braceleft +!7C U+007C bar +!7D U+007D braceright +!7E U+007E asciitilde +!7F U+007F .notdef +!80 U+20AC Euro +!85 U+2026 ellipsis +!91 U+2018 quoteleft +!92 U+2019 quoteright +!93 U+201C quotedblleft +!94 U+201D quotedblright +!95 U+2022 bullet +!96 U+2013 endash +!97 U+2014 emdash +!A0 U+00A0 space +!A1 U+0E01 kokaithai +!A2 U+0E02 khokhaithai +!A3 U+0E03 khokhuatthai +!A4 U+0E04 khokhwaithai +!A5 U+0E05 khokhonthai +!A6 U+0E06 khorakhangthai +!A7 U+0E07 ngonguthai +!A8 U+0E08 chochanthai +!A9 U+0E09 chochingthai +!AA U+0E0A chochangthai +!AB U+0E0B sosothai +!AC U+0E0C chochoethai +!AD U+0E0D yoyingthai +!AE U+0E0E dochadathai +!AF U+0E0F topatakthai +!B0 U+0E10 thothanthai +!B1 U+0E11 thonangmonthothai +!B2 U+0E12 thophuthaothai +!B3 U+0E13 nonenthai +!B4 U+0E14 dodekthai +!B5 U+0E15 totaothai +!B6 U+0E16 thothungthai +!B7 U+0E17 thothahanthai +!B8 U+0E18 thothongthai +!B9 U+0E19 nonuthai +!BA U+0E1A bobaimaithai +!BB U+0E1B poplathai +!BC U+0E1C phophungthai +!BD U+0E1D fofathai +!BE U+0E1E phophanthai +!BF U+0E1F fofanthai +!C0 U+0E20 phosamphaothai +!C1 U+0E21 momathai +!C2 U+0E22 yoyakthai +!C3 U+0E23 roruathai +!C4 U+0E24 ruthai +!C5 U+0E25 lolingthai +!C6 U+0E26 luthai +!C7 U+0E27 wowaenthai +!C8 U+0E28 sosalathai +!C9 U+0E29 sorusithai +!CA U+0E2A sosuathai +!CB U+0E2B hohipthai +!CC U+0E2C lochulathai +!CD U+0E2D oangthai +!CE U+0E2E honokhukthai +!CF U+0E2F paiyannoithai +!D0 U+0E30 saraathai +!D1 U+0E31 maihanakatthai +!D2 U+0E32 saraaathai +!D3 U+0E33 saraamthai +!D4 U+0E34 saraithai +!D5 U+0E35 saraiithai +!D6 U+0E36 sarauethai +!D7 U+0E37 saraueethai +!D8 U+0E38 sarauthai +!D9 U+0E39 sarauuthai +!DA U+0E3A phinthuthai +!DF U+0E3F bahtthai +!E0 U+0E40 saraethai +!E1 U+0E41 saraaethai +!E2 U+0E42 saraothai +!E3 U+0E43 saraaimaimuanthai +!E4 U+0E44 saraaimaimalaithai +!E5 U+0E45 lakkhangyaothai +!E6 U+0E46 maiyamokthai +!E7 U+0E47 maitaikhuthai +!E8 U+0E48 maiekthai +!E9 U+0E49 maithothai +!EA U+0E4A maitrithai +!EB U+0E4B maichattawathai +!EC U+0E4C thanthakhatthai +!ED U+0E4D nikhahitthai +!EE U+0E4E yamakkanthai +!EF U+0E4F fongmanthai +!F0 U+0E50 zerothai +!F1 U+0E51 onethai +!F2 U+0E52 twothai +!F3 U+0E53 threethai +!F4 U+0E54 fourthai +!F5 U+0E55 fivethai +!F6 U+0E56 sixthai +!F7 U+0E57 seventhai +!F8 U+0E58 eightthai +!F9 U+0E59 ninethai +!FA U+0E5A angkhankhuthai +!FB U+0E5B khomutthai diff --git a/include/tcpdf/fonts/utils/enc/iso-8859-1.map b/include/tcpdf/fonts/utils/enc/iso-8859-1.map new file mode 100644 index 00000000..61740a38 --- /dev/null +++ b/include/tcpdf/fonts/utils/enc/iso-8859-1.map @@ -0,0 +1,256 @@ +!00 U+0000 .notdef +!01 U+0001 .notdef +!02 U+0002 .notdef +!03 U+0003 .notdef +!04 U+0004 .notdef +!05 U+0005 .notdef +!06 U+0006 .notdef +!07 U+0007 .notdef +!08 U+0008 .notdef +!09 U+0009 .notdef +!0A U+000A .notdef +!0B U+000B .notdef +!0C U+000C .notdef +!0D U+000D .notdef +!0E U+000E .notdef +!0F U+000F .notdef +!10 U+0010 .notdef +!11 U+0011 .notdef +!12 U+0012 .notdef +!13 U+0013 .notdef +!14 U+0014 .notdef +!15 U+0015 .notdef +!16 U+0016 .notdef +!17 U+0017 .notdef +!18 U+0018 .notdef +!19 U+0019 .notdef +!1A U+001A .notdef +!1B U+001B .notdef +!1C U+001C .notdef +!1D U+001D .notdef +!1E U+001E .notdef +!1F U+001F .notdef +!20 U+0020 space +!21 U+0021 exclam +!22 U+0022 quotedbl +!23 U+0023 numbersign +!24 U+0024 dollar +!25 U+0025 percent +!26 U+0026 ampersand +!27 U+0027 quotesingle +!28 U+0028 parenleft +!29 U+0029 parenright +!2A U+002A asterisk +!2B U+002B plus +!2C U+002C comma +!2D U+002D hyphen +!2E U+002E period +!2F U+002F slash +!30 U+0030 zero +!31 U+0031 one +!32 U+0032 two +!33 U+0033 three +!34 U+0034 four +!35 U+0035 five +!36 U+0036 six +!37 U+0037 seven +!38 U+0038 eight +!39 U+0039 nine +!3A U+003A colon +!3B U+003B semicolon +!3C U+003C less +!3D U+003D equal +!3E U+003E greater +!3F U+003F question +!40 U+0040 at +!41 U+0041 A +!42 U+0042 B +!43 U+0043 C +!44 U+0044 D +!45 U+0045 E +!46 U+0046 F +!47 U+0047 G +!48 U+0048 H +!49 U+0049 I +!4A U+004A J +!4B U+004B K +!4C U+004C L +!4D U+004D M +!4E U+004E N +!4F U+004F O +!50 U+0050 P +!51 U+0051 Q +!52 U+0052 R +!53 U+0053 S +!54 U+0054 T +!55 U+0055 U +!56 U+0056 V +!57 U+0057 W +!58 U+0058 X +!59 U+0059 Y +!5A U+005A Z +!5B U+005B bracketleft +!5C U+005C backslash +!5D U+005D bracketright +!5E U+005E asciicircum +!5F U+005F underscore +!60 U+0060 grave +!61 U+0061 a +!62 U+0062 b +!63 U+0063 c +!64 U+0064 d +!65 U+0065 e +!66 U+0066 f +!67 U+0067 g +!68 U+0068 h +!69 U+0069 i +!6A U+006A j +!6B U+006B k +!6C U+006C l +!6D U+006D m +!6E U+006E n +!6F U+006F o +!70 U+0070 p +!71 U+0071 q +!72 U+0072 r +!73 U+0073 s +!74 U+0074 t +!75 U+0075 u +!76 U+0076 v +!77 U+0077 w +!78 U+0078 x +!79 U+0079 y +!7A U+007A z +!7B U+007B braceleft +!7C U+007C bar +!7D U+007D braceright +!7E U+007E asciitilde +!7F U+007F .notdef +!80 U+0080 .notdef +!81 U+0081 .notdef +!82 U+0082 .notdef +!83 U+0083 .notdef +!84 U+0084 .notdef +!85 U+0085 .notdef +!86 U+0086 .notdef +!87 U+0087 .notdef +!88 U+0088 .notdef +!89 U+0089 .notdef +!8A U+008A .notdef +!8B U+008B .notdef +!8C U+008C .notdef +!8D U+008D .notdef +!8E U+008E .notdef +!8F U+008F .notdef +!90 U+0090 .notdef +!91 U+0091 .notdef +!92 U+0092 .notdef +!93 U+0093 .notdef +!94 U+0094 .notdef +!95 U+0095 .notdef +!96 U+0096 .notdef +!97 U+0097 .notdef +!98 U+0098 .notdef +!99 U+0099 .notdef +!9A U+009A .notdef +!9B U+009B .notdef +!9C U+009C .notdef +!9D U+009D .notdef +!9E U+009E .notdef +!9F U+009F .notdef +!A0 U+00A0 space +!A1 U+00A1 exclamdown +!A2 U+00A2 cent +!A3 U+00A3 sterling +!A4 U+00A4 currency +!A5 U+00A5 yen +!A6 U+00A6 brokenbar +!A7 U+00A7 section +!A8 U+00A8 dieresis +!A9 U+00A9 copyright +!AA U+00AA ordfeminine +!AB U+00AB guillemotleft +!AC U+00AC logicalnot +!AD U+00AD hyphen +!AE U+00AE registered +!AF U+00AF macron +!B0 U+00B0 degree +!B1 U+00B1 plusminus +!B2 U+00B2 twosuperior +!B3 U+00B3 threesuperior +!B4 U+00B4 acute +!B5 U+00B5 mu +!B6 U+00B6 paragraph +!B7 U+00B7 periodcentered +!B8 U+00B8 cedilla +!B9 U+00B9 onesuperior +!BA U+00BA ordmasculine +!BB U+00BB guillemotright +!BC U+00BC onequarter +!BD U+00BD onehalf +!BE U+00BE threequarters +!BF U+00BF questiondown +!C0 U+00C0 Agrave +!C1 U+00C1 Aacute +!C2 U+00C2 Acircumflex +!C3 U+00C3 Atilde +!C4 U+00C4 Adieresis +!C5 U+00C5 Aring +!C6 U+00C6 AE +!C7 U+00C7 Ccedilla +!C8 U+00C8 Egrave +!C9 U+00C9 Eacute +!CA U+00CA Ecircumflex +!CB U+00CB Edieresis +!CC U+00CC Igrave +!CD U+00CD Iacute +!CE U+00CE Icircumflex +!CF U+00CF Idieresis +!D0 U+00D0 Eth +!D1 U+00D1 Ntilde +!D2 U+00D2 Ograve +!D3 U+00D3 Oacute +!D4 U+00D4 Ocircumflex +!D5 U+00D5 Otilde +!D6 U+00D6 Odieresis +!D7 U+00D7 multiply +!D8 U+00D8 Oslash +!D9 U+00D9 Ugrave +!DA U+00DA Uacute +!DB U+00DB Ucircumflex +!DC U+00DC Udieresis +!DD U+00DD Yacute +!DE U+00DE Thorn +!DF U+00DF germandbls +!E0 U+00E0 agrave +!E1 U+00E1 aacute +!E2 U+00E2 acircumflex +!E3 U+00E3 atilde +!E4 U+00E4 adieresis +!E5 U+00E5 aring +!E6 U+00E6 ae +!E7 U+00E7 ccedilla +!E8 U+00E8 egrave +!E9 U+00E9 eacute +!EA U+00EA ecircumflex +!EB U+00EB edieresis +!EC U+00EC igrave +!ED U+00ED iacute +!EE U+00EE icircumflex +!EF U+00EF idieresis +!F0 U+00F0 eth +!F1 U+00F1 ntilde +!F2 U+00F2 ograve +!F3 U+00F3 oacute +!F4 U+00F4 ocircumflex +!F5 U+00F5 otilde +!F6 U+00F6 odieresis +!F7 U+00F7 divide +!F8 U+00F8 oslash +!F9 U+00F9 ugrave +!FA U+00FA uacute +!FB U+00FB ucircumflex +!FC U+00FC udieresis +!FD U+00FD yacute +!FE U+00FE thorn +!FF U+00FF ydieresis diff --git a/include/tcpdf/fonts/utils/enc/iso-8859-11.map b/include/tcpdf/fonts/utils/enc/iso-8859-11.map new file mode 100644 index 00000000..91688120 --- /dev/null +++ b/include/tcpdf/fonts/utils/enc/iso-8859-11.map @@ -0,0 +1,248 @@ +!00 U+0000 .notdef +!01 U+0001 .notdef +!02 U+0002 .notdef +!03 U+0003 .notdef +!04 U+0004 .notdef +!05 U+0005 .notdef +!06 U+0006 .notdef +!07 U+0007 .notdef +!08 U+0008 .notdef +!09 U+0009 .notdef +!0A U+000A .notdef +!0B U+000B .notdef +!0C U+000C .notdef +!0D U+000D .notdef +!0E U+000E .notdef +!0F U+000F .notdef +!10 U+0010 .notdef +!11 U+0011 .notdef +!12 U+0012 .notdef +!13 U+0013 .notdef +!14 U+0014 .notdef +!15 U+0015 .notdef +!16 U+0016 .notdef +!17 U+0017 .notdef +!18 U+0018 .notdef +!19 U+0019 .notdef +!1A U+001A .notdef +!1B U+001B .notdef +!1C U+001C .notdef +!1D U+001D .notdef +!1E U+001E .notdef +!1F U+001F .notdef +!20 U+0020 space +!21 U+0021 exclam +!22 U+0022 quotedbl +!23 U+0023 numbersign +!24 U+0024 dollar +!25 U+0025 percent +!26 U+0026 ampersand +!27 U+0027 quotesingle +!28 U+0028 parenleft +!29 U+0029 parenright +!2A U+002A asterisk +!2B U+002B plus +!2C U+002C comma +!2D U+002D hyphen +!2E U+002E period +!2F U+002F slash +!30 U+0030 zero +!31 U+0031 one +!32 U+0032 two +!33 U+0033 three +!34 U+0034 four +!35 U+0035 five +!36 U+0036 six +!37 U+0037 seven +!38 U+0038 eight +!39 U+0039 nine +!3A U+003A colon +!3B U+003B semicolon +!3C U+003C less +!3D U+003D equal +!3E U+003E greater +!3F U+003F question +!40 U+0040 at +!41 U+0041 A +!42 U+0042 B +!43 U+0043 C +!44 U+0044 D +!45 U+0045 E +!46 U+0046 F +!47 U+0047 G +!48 U+0048 H +!49 U+0049 I +!4A U+004A J +!4B U+004B K +!4C U+004C L +!4D U+004D M +!4E U+004E N +!4F U+004F O +!50 U+0050 P +!51 U+0051 Q +!52 U+0052 R +!53 U+0053 S +!54 U+0054 T +!55 U+0055 U +!56 U+0056 V +!57 U+0057 W +!58 U+0058 X +!59 U+0059 Y +!5A U+005A Z +!5B U+005B bracketleft +!5C U+005C backslash +!5D U+005D bracketright +!5E U+005E asciicircum +!5F U+005F underscore +!60 U+0060 grave +!61 U+0061 a +!62 U+0062 b +!63 U+0063 c +!64 U+0064 d +!65 U+0065 e +!66 U+0066 f +!67 U+0067 g +!68 U+0068 h +!69 U+0069 i +!6A U+006A j +!6B U+006B k +!6C U+006C l +!6D U+006D m +!6E U+006E n +!6F U+006F o +!70 U+0070 p +!71 U+0071 q +!72 U+0072 r +!73 U+0073 s +!74 U+0074 t +!75 U+0075 u +!76 U+0076 v +!77 U+0077 w +!78 U+0078 x +!79 U+0079 y +!7A U+007A z +!7B U+007B braceleft +!7C U+007C bar +!7D U+007D braceright +!7E U+007E asciitilde +!7F U+007F .notdef +!80 U+0080 .notdef +!81 U+0081 .notdef +!82 U+0082 .notdef +!83 U+0083 .notdef +!84 U+0084 .notdef +!85 U+0085 .notdef +!86 U+0086 .notdef +!87 U+0087 .notdef +!88 U+0088 .notdef +!89 U+0089 .notdef +!8A U+008A .notdef +!8B U+008B .notdef +!8C U+008C .notdef +!8D U+008D .notdef +!8E U+008E .notdef +!8F U+008F .notdef +!90 U+0090 .notdef +!91 U+0091 .notdef +!92 U+0092 .notdef +!93 U+0093 .notdef +!94 U+0094 .notdef +!95 U+0095 .notdef +!96 U+0096 .notdef +!97 U+0097 .notdef +!98 U+0098 .notdef +!99 U+0099 .notdef +!9A U+009A .notdef +!9B U+009B .notdef +!9C U+009C .notdef +!9D U+009D .notdef +!9E U+009E .notdef +!9F U+009F .notdef +!A0 U+00A0 space +!A1 U+0E01 kokaithai +!A2 U+0E02 khokhaithai +!A3 U+0E03 khokhuatthai +!A4 U+0E04 khokhwaithai +!A5 U+0E05 khokhonthai +!A6 U+0E06 khorakhangthai +!A7 U+0E07 ngonguthai +!A8 U+0E08 chochanthai +!A9 U+0E09 chochingthai +!AA U+0E0A chochangthai +!AB U+0E0B sosothai +!AC U+0E0C chochoethai +!AD U+0E0D yoyingthai +!AE U+0E0E dochadathai +!AF U+0E0F topatakthai +!B0 U+0E10 thothanthai +!B1 U+0E11 thonangmonthothai +!B2 U+0E12 thophuthaothai +!B3 U+0E13 nonenthai +!B4 U+0E14 dodekthai +!B5 U+0E15 totaothai +!B6 U+0E16 thothungthai +!B7 U+0E17 thothahanthai +!B8 U+0E18 thothongthai +!B9 U+0E19 nonuthai +!BA U+0E1A bobaimaithai +!BB U+0E1B poplathai +!BC U+0E1C phophungthai +!BD U+0E1D fofathai +!BE U+0E1E phophanthai +!BF U+0E1F fofanthai +!C0 U+0E20 phosamphaothai +!C1 U+0E21 momathai +!C2 U+0E22 yoyakthai +!C3 U+0E23 roruathai +!C4 U+0E24 ruthai +!C5 U+0E25 lolingthai +!C6 U+0E26 luthai +!C7 U+0E27 wowaenthai +!C8 U+0E28 sosalathai +!C9 U+0E29 sorusithai +!CA U+0E2A sosuathai +!CB U+0E2B hohipthai +!CC U+0E2C lochulathai +!CD U+0E2D oangthai +!CE U+0E2E honokhukthai +!CF U+0E2F paiyannoithai +!D0 U+0E30 saraathai +!D1 U+0E31 maihanakatthai +!D2 U+0E32 saraaathai +!D3 U+0E33 saraamthai +!D4 U+0E34 saraithai +!D5 U+0E35 saraiithai +!D6 U+0E36 sarauethai +!D7 U+0E37 saraueethai +!D8 U+0E38 sarauthai +!D9 U+0E39 sarauuthai +!DA U+0E3A phinthuthai +!DF U+0E3F bahtthai +!E0 U+0E40 saraethai +!E1 U+0E41 saraaethai +!E2 U+0E42 saraothai +!E3 U+0E43 saraaimaimuanthai +!E4 U+0E44 saraaimaimalaithai +!E5 U+0E45 lakkhangyaothai +!E6 U+0E46 maiyamokthai +!E7 U+0E47 maitaikhuthai +!E8 U+0E48 maiekthai +!E9 U+0E49 maithothai +!EA U+0E4A maitrithai +!EB U+0E4B maichattawathai +!EC U+0E4C thanthakhatthai +!ED U+0E4D nikhahitthai +!EE U+0E4E yamakkanthai +!EF U+0E4F fongmanthai +!F0 U+0E50 zerothai +!F1 U+0E51 onethai +!F2 U+0E52 twothai +!F3 U+0E53 threethai +!F4 U+0E54 fourthai +!F5 U+0E55 fivethai +!F6 U+0E56 sixthai +!F7 U+0E57 seventhai +!F8 U+0E58 eightthai +!F9 U+0E59 ninethai +!FA U+0E5A angkhankhuthai +!FB U+0E5B khomutthai diff --git a/include/tcpdf/fonts/utils/enc/iso-8859-15.map b/include/tcpdf/fonts/utils/enc/iso-8859-15.map new file mode 100644 index 00000000..6c2b5712 --- /dev/null +++ b/include/tcpdf/fonts/utils/enc/iso-8859-15.map @@ -0,0 +1,256 @@ +!00 U+0000 .notdef +!01 U+0001 .notdef +!02 U+0002 .notdef +!03 U+0003 .notdef +!04 U+0004 .notdef +!05 U+0005 .notdef +!06 U+0006 .notdef +!07 U+0007 .notdef +!08 U+0008 .notdef +!09 U+0009 .notdef +!0A U+000A .notdef +!0B U+000B .notdef +!0C U+000C .notdef +!0D U+000D .notdef +!0E U+000E .notdef +!0F U+000F .notdef +!10 U+0010 .notdef +!11 U+0011 .notdef +!12 U+0012 .notdef +!13 U+0013 .notdef +!14 U+0014 .notdef +!15 U+0015 .notdef +!16 U+0016 .notdef +!17 U+0017 .notdef +!18 U+0018 .notdef +!19 U+0019 .notdef +!1A U+001A .notdef +!1B U+001B .notdef +!1C U+001C .notdef +!1D U+001D .notdef +!1E U+001E .notdef +!1F U+001F .notdef +!20 U+0020 space +!21 U+0021 exclam +!22 U+0022 quotedbl +!23 U+0023 numbersign +!24 U+0024 dollar +!25 U+0025 percent +!26 U+0026 ampersand +!27 U+0027 quotesingle +!28 U+0028 parenleft +!29 U+0029 parenright +!2A U+002A asterisk +!2B U+002B plus +!2C U+002C comma +!2D U+002D hyphen +!2E U+002E period +!2F U+002F slash +!30 U+0030 zero +!31 U+0031 one +!32 U+0032 two +!33 U+0033 three +!34 U+0034 four +!35 U+0035 five +!36 U+0036 six +!37 U+0037 seven +!38 U+0038 eight +!39 U+0039 nine +!3A U+003A colon +!3B U+003B semicolon +!3C U+003C less +!3D U+003D equal +!3E U+003E greater +!3F U+003F question +!40 U+0040 at +!41 U+0041 A +!42 U+0042 B +!43 U+0043 C +!44 U+0044 D +!45 U+0045 E +!46 U+0046 F +!47 U+0047 G +!48 U+0048 H +!49 U+0049 I +!4A U+004A J +!4B U+004B K +!4C U+004C L +!4D U+004D M +!4E U+004E N +!4F U+004F O +!50 U+0050 P +!51 U+0051 Q +!52 U+0052 R +!53 U+0053 S +!54 U+0054 T +!55 U+0055 U +!56 U+0056 V +!57 U+0057 W +!58 U+0058 X +!59 U+0059 Y +!5A U+005A Z +!5B U+005B bracketleft +!5C U+005C backslash +!5D U+005D bracketright +!5E U+005E asciicircum +!5F U+005F underscore +!60 U+0060 grave +!61 U+0061 a +!62 U+0062 b +!63 U+0063 c +!64 U+0064 d +!65 U+0065 e +!66 U+0066 f +!67 U+0067 g +!68 U+0068 h +!69 U+0069 i +!6A U+006A j +!6B U+006B k +!6C U+006C l +!6D U+006D m +!6E U+006E n +!6F U+006F o +!70 U+0070 p +!71 U+0071 q +!72 U+0072 r +!73 U+0073 s +!74 U+0074 t +!75 U+0075 u +!76 U+0076 v +!77 U+0077 w +!78 U+0078 x +!79 U+0079 y +!7A U+007A z +!7B U+007B braceleft +!7C U+007C bar +!7D U+007D braceright +!7E U+007E asciitilde +!7F U+007F .notdef +!80 U+0080 .notdef +!81 U+0081 .notdef +!82 U+0082 .notdef +!83 U+0083 .notdef +!84 U+0084 .notdef +!85 U+0085 .notdef +!86 U+0086 .notdef +!87 U+0087 .notdef +!88 U+0088 .notdef +!89 U+0089 .notdef +!8A U+008A .notdef +!8B U+008B .notdef +!8C U+008C .notdef +!8D U+008D .notdef +!8E U+008E .notdef +!8F U+008F .notdef +!90 U+0090 .notdef +!91 U+0091 .notdef +!92 U+0092 .notdef +!93 U+0093 .notdef +!94 U+0094 .notdef +!95 U+0095 .notdef +!96 U+0096 .notdef +!97 U+0097 .notdef +!98 U+0098 .notdef +!99 U+0099 .notdef +!9A U+009A .notdef +!9B U+009B .notdef +!9C U+009C .notdef +!9D U+009D .notdef +!9E U+009E .notdef +!9F U+009F .notdef +!A0 U+00A0 space +!A1 U+00A1 exclamdown +!A2 U+00A2 cent +!A3 U+00A3 sterling +!A4 U+20AC Euro +!A5 U+00A5 yen +!A6 U+0160 Scaron +!A7 U+00A7 section +!A8 U+0161 scaron +!A9 U+00A9 copyright +!AA U+00AA ordfeminine +!AB U+00AB guillemotleft +!AC U+00AC logicalnot +!AD U+00AD hyphen +!AE U+00AE registered +!AF U+00AF macron +!B0 U+00B0 degree +!B1 U+00B1 plusminus +!B2 U+00B2 twosuperior +!B3 U+00B3 threesuperior +!B4 U+017D Zcaron +!B5 U+00B5 mu +!B6 U+00B6 paragraph +!B7 U+00B7 periodcentered +!B8 U+017E zcaron +!B9 U+00B9 onesuperior +!BA U+00BA ordmasculine +!BB U+00BB guillemotright +!BC U+0152 OE +!BD U+0153 oe +!BE U+0178 Ydieresis +!BF U+00BF questiondown +!C0 U+00C0 Agrave +!C1 U+00C1 Aacute +!C2 U+00C2 Acircumflex +!C3 U+00C3 Atilde +!C4 U+00C4 Adieresis +!C5 U+00C5 Aring +!C6 U+00C6 AE +!C7 U+00C7 Ccedilla +!C8 U+00C8 Egrave +!C9 U+00C9 Eacute +!CA U+00CA Ecircumflex +!CB U+00CB Edieresis +!CC U+00CC Igrave +!CD U+00CD Iacute +!CE U+00CE Icircumflex +!CF U+00CF Idieresis +!D0 U+00D0 Eth +!D1 U+00D1 Ntilde +!D2 U+00D2 Ograve +!D3 U+00D3 Oacute +!D4 U+00D4 Ocircumflex +!D5 U+00D5 Otilde +!D6 U+00D6 Odieresis +!D7 U+00D7 multiply +!D8 U+00D8 Oslash +!D9 U+00D9 Ugrave +!DA U+00DA Uacute +!DB U+00DB Ucircumflex +!DC U+00DC Udieresis +!DD U+00DD Yacute +!DE U+00DE Thorn +!DF U+00DF germandbls +!E0 U+00E0 agrave +!E1 U+00E1 aacute +!E2 U+00E2 acircumflex +!E3 U+00E3 atilde +!E4 U+00E4 adieresis +!E5 U+00E5 aring +!E6 U+00E6 ae +!E7 U+00E7 ccedilla +!E8 U+00E8 egrave +!E9 U+00E9 eacute +!EA U+00EA ecircumflex +!EB U+00EB edieresis +!EC U+00EC igrave +!ED U+00ED iacute +!EE U+00EE icircumflex +!EF U+00EF idieresis +!F0 U+00F0 eth +!F1 U+00F1 ntilde +!F2 U+00F2 ograve +!F3 U+00F3 oacute +!F4 U+00F4 ocircumflex +!F5 U+00F5 otilde +!F6 U+00F6 odieresis +!F7 U+00F7 divide +!F8 U+00F8 oslash +!F9 U+00F9 ugrave +!FA U+00FA uacute +!FB U+00FB ucircumflex +!FC U+00FC udieresis +!FD U+00FD yacute +!FE U+00FE thorn +!FF U+00FF ydieresis diff --git a/include/tcpdf/fonts/utils/enc/iso-8859-16.map b/include/tcpdf/fonts/utils/enc/iso-8859-16.map new file mode 100644 index 00000000..202c8fe5 --- /dev/null +++ b/include/tcpdf/fonts/utils/enc/iso-8859-16.map @@ -0,0 +1,256 @@ +!00 U+0000 .notdef +!01 U+0001 .notdef +!02 U+0002 .notdef +!03 U+0003 .notdef +!04 U+0004 .notdef +!05 U+0005 .notdef +!06 U+0006 .notdef +!07 U+0007 .notdef +!08 U+0008 .notdef +!09 U+0009 .notdef +!0A U+000A .notdef +!0B U+000B .notdef +!0C U+000C .notdef +!0D U+000D .notdef +!0E U+000E .notdef +!0F U+000F .notdef +!10 U+0010 .notdef +!11 U+0011 .notdef +!12 U+0012 .notdef +!13 U+0013 .notdef +!14 U+0014 .notdef +!15 U+0015 .notdef +!16 U+0016 .notdef +!17 U+0017 .notdef +!18 U+0018 .notdef +!19 U+0019 .notdef +!1A U+001A .notdef +!1B U+001B .notdef +!1C U+001C .notdef +!1D U+001D .notdef +!1E U+001E .notdef +!1F U+001F .notdef +!20 U+0020 space +!21 U+0021 exclam +!22 U+0022 quotedbl +!23 U+0023 numbersign +!24 U+0024 dollar +!25 U+0025 percent +!26 U+0026 ampersand +!27 U+0027 quotesingle +!28 U+0028 parenleft +!29 U+0029 parenright +!2A U+002A asterisk +!2B U+002B plus +!2C U+002C comma +!2D U+002D hyphen +!2E U+002E period +!2F U+002F slash +!30 U+0030 zero +!31 U+0031 one +!32 U+0032 two +!33 U+0033 three +!34 U+0034 four +!35 U+0035 five +!36 U+0036 six +!37 U+0037 seven +!38 U+0038 eight +!39 U+0039 nine +!3A U+003A colon +!3B U+003B semicolon +!3C U+003C less +!3D U+003D equal +!3E U+003E greater +!3F U+003F question +!40 U+0040 at +!41 U+0041 A +!42 U+0042 B +!43 U+0043 C +!44 U+0044 D +!45 U+0045 E +!46 U+0046 F +!47 U+0047 G +!48 U+0048 H +!49 U+0049 I +!4A U+004A J +!4B U+004B K +!4C U+004C L +!4D U+004D M +!4E U+004E N +!4F U+004F O +!50 U+0050 P +!51 U+0051 Q +!52 U+0052 R +!53 U+0053 S +!54 U+0054 T +!55 U+0055 U +!56 U+0056 V +!57 U+0057 W +!58 U+0058 X +!59 U+0059 Y +!5A U+005A Z +!5B U+005B bracketleft +!5C U+005C backslash +!5D U+005D bracketright +!5E U+005E asciicircum +!5F U+005F underscore +!60 U+0060 grave +!61 U+0061 a +!62 U+0062 b +!63 U+0063 c +!64 U+0064 d +!65 U+0065 e +!66 U+0066 f +!67 U+0067 g +!68 U+0068 h +!69 U+0069 i +!6A U+006A j +!6B U+006B k +!6C U+006C l +!6D U+006D m +!6E U+006E n +!6F U+006F o +!70 U+0070 p +!71 U+0071 q +!72 U+0072 r +!73 U+0073 s +!74 U+0074 t +!75 U+0075 u +!76 U+0076 v +!77 U+0077 w +!78 U+0078 x +!79 U+0079 y +!7A U+007A z +!7B U+007B braceleft +!7C U+007C bar +!7D U+007D braceright +!7E U+007E asciitilde +!7F U+007F .notdef +!80 U+0080 .notdef +!81 U+0081 .notdef +!82 U+0082 .notdef +!83 U+0083 .notdef +!84 U+0084 .notdef +!85 U+0085 .notdef +!86 U+0086 .notdef +!87 U+0087 .notdef +!88 U+0088 .notdef +!89 U+0089 .notdef +!8A U+008A .notdef +!8B U+008B .notdef +!8C U+008C .notdef +!8D U+008D .notdef +!8E U+008E .notdef +!8F U+008F .notdef +!90 U+0090 .notdef +!91 U+0091 .notdef +!92 U+0092 .notdef +!93 U+0093 .notdef +!94 U+0094 .notdef +!95 U+0095 .notdef +!96 U+0096 .notdef +!97 U+0097 .notdef +!98 U+0098 .notdef +!99 U+0099 .notdef +!9A U+009A .notdef +!9B U+009B .notdef +!9C U+009C .notdef +!9D U+009D .notdef +!9E U+009E .notdef +!9F U+009F .notdef +!A0 U+00A0 space +!A1 U+0104 Aogonek +!A2 U+0105 aogonek +!A3 U+0141 Lslash +!A4 U+20AC Euro +!A5 U+201E quotedblbase +!A6 U+0160 Scaron +!A7 U+00A7 section +!A8 U+0161 scaron +!A9 U+00A9 copyright +!AA U+0218 Scommaaccent +!AB U+00AB guillemotleft +!AC U+0179 Zacute +!AD U+00AD hyphen +!AE U+017A zacute +!AF U+017B Zdotaccent +!B0 U+00B0 degree +!B1 U+00B1 plusminus +!B2 U+010C Ccaron +!B3 U+0142 lslash +!B4 U+017D Zcaron +!B5 U+201D quotedblright +!B6 U+00B6 paragraph +!B7 U+00B7 periodcentered +!B8 U+017E zcaron +!B9 U+010D ccaron +!BA U+0219 scommaaccent +!BB U+00BB guillemotright +!BC U+0152 OE +!BD U+0153 oe +!BE U+0178 Ydieresis +!BF U+017C zdotaccent +!C0 U+00C0 Agrave +!C1 U+00C1 Aacute +!C2 U+00C2 Acircumflex +!C3 U+0102 Abreve +!C4 U+00C4 Adieresis +!C5 U+0106 Cacute +!C6 U+00C6 AE +!C7 U+00C7 Ccedilla +!C8 U+00C8 Egrave +!C9 U+00C9 Eacute +!CA U+00CA Ecircumflex +!CB U+00CB Edieresis +!CC U+00CC Igrave +!CD U+00CD Iacute +!CE U+00CE Icircumflex +!CF U+00CF Idieresis +!D0 U+0110 Dcroat +!D1 U+0143 Nacute +!D2 U+00D2 Ograve +!D3 U+00D3 Oacute +!D4 U+00D4 Ocircumflex +!D5 U+0150 Ohungarumlaut +!D6 U+00D6 Odieresis +!D7 U+015A Sacute +!D8 U+0170 Uhungarumlaut +!D9 U+00D9 Ugrave +!DA U+00DA Uacute +!DB U+00DB Ucircumflex +!DC U+00DC Udieresis +!DD U+0118 Eogonek +!DE U+021A Tcommaaccent +!DF U+00DF germandbls +!E0 U+00E0 agrave +!E1 U+00E1 aacute +!E2 U+00E2 acircumflex +!E3 U+0103 abreve +!E4 U+00E4 adieresis +!E5 U+0107 cacute +!E6 U+00E6 ae +!E7 U+00E7 ccedilla +!E8 U+00E8 egrave +!E9 U+00E9 eacute +!EA U+00EA ecircumflex +!EB U+00EB edieresis +!EC U+00EC igrave +!ED U+00ED iacute +!EE U+00EE icircumflex +!EF U+00EF idieresis +!F0 U+0111 dcroat +!F1 U+0144 nacute +!F2 U+00F2 ograve +!F3 U+00F3 oacute +!F4 U+00F4 ocircumflex +!F5 U+0151 ohungarumlaut +!F6 U+00F6 odieresis +!F7 U+015B sacute +!F8 U+0171 uhungarumlaut +!F9 U+00F9 ugrave +!FA U+00FA uacute +!FB U+00FB ucircumflex +!FC U+00FC udieresis +!FD U+0119 eogonek +!FE U+021B tcommaaccent +!FF U+00FF ydieresis diff --git a/include/tcpdf/fonts/utils/enc/iso-8859-2.map b/include/tcpdf/fonts/utils/enc/iso-8859-2.map new file mode 100644 index 00000000..65ae09f9 --- /dev/null +++ b/include/tcpdf/fonts/utils/enc/iso-8859-2.map @@ -0,0 +1,256 @@ +!00 U+0000 .notdef +!01 U+0001 .notdef +!02 U+0002 .notdef +!03 U+0003 .notdef +!04 U+0004 .notdef +!05 U+0005 .notdef +!06 U+0006 .notdef +!07 U+0007 .notdef +!08 U+0008 .notdef +!09 U+0009 .notdef +!0A U+000A .notdef +!0B U+000B .notdef +!0C U+000C .notdef +!0D U+000D .notdef +!0E U+000E .notdef +!0F U+000F .notdef +!10 U+0010 .notdef +!11 U+0011 .notdef +!12 U+0012 .notdef +!13 U+0013 .notdef +!14 U+0014 .notdef +!15 U+0015 .notdef +!16 U+0016 .notdef +!17 U+0017 .notdef +!18 U+0018 .notdef +!19 U+0019 .notdef +!1A U+001A .notdef +!1B U+001B .notdef +!1C U+001C .notdef +!1D U+001D .notdef +!1E U+001E .notdef +!1F U+001F .notdef +!20 U+0020 space +!21 U+0021 exclam +!22 U+0022 quotedbl +!23 U+0023 numbersign +!24 U+0024 dollar +!25 U+0025 percent +!26 U+0026 ampersand +!27 U+0027 quotesingle +!28 U+0028 parenleft +!29 U+0029 parenright +!2A U+002A asterisk +!2B U+002B plus +!2C U+002C comma +!2D U+002D hyphen +!2E U+002E period +!2F U+002F slash +!30 U+0030 zero +!31 U+0031 one +!32 U+0032 two +!33 U+0033 three +!34 U+0034 four +!35 U+0035 five +!36 U+0036 six +!37 U+0037 seven +!38 U+0038 eight +!39 U+0039 nine +!3A U+003A colon +!3B U+003B semicolon +!3C U+003C less +!3D U+003D equal +!3E U+003E greater +!3F U+003F question +!40 U+0040 at +!41 U+0041 A +!42 U+0042 B +!43 U+0043 C +!44 U+0044 D +!45 U+0045 E +!46 U+0046 F +!47 U+0047 G +!48 U+0048 H +!49 U+0049 I +!4A U+004A J +!4B U+004B K +!4C U+004C L +!4D U+004D M +!4E U+004E N +!4F U+004F O +!50 U+0050 P +!51 U+0051 Q +!52 U+0052 R +!53 U+0053 S +!54 U+0054 T +!55 U+0055 U +!56 U+0056 V +!57 U+0057 W +!58 U+0058 X +!59 U+0059 Y +!5A U+005A Z +!5B U+005B bracketleft +!5C U+005C backslash +!5D U+005D bracketright +!5E U+005E asciicircum +!5F U+005F underscore +!60 U+0060 grave +!61 U+0061 a +!62 U+0062 b +!63 U+0063 c +!64 U+0064 d +!65 U+0065 e +!66 U+0066 f +!67 U+0067 g +!68 U+0068 h +!69 U+0069 i +!6A U+006A j +!6B U+006B k +!6C U+006C l +!6D U+006D m +!6E U+006E n +!6F U+006F o +!70 U+0070 p +!71 U+0071 q +!72 U+0072 r +!73 U+0073 s +!74 U+0074 t +!75 U+0075 u +!76 U+0076 v +!77 U+0077 w +!78 U+0078 x +!79 U+0079 y +!7A U+007A z +!7B U+007B braceleft +!7C U+007C bar +!7D U+007D braceright +!7E U+007E asciitilde +!7F U+007F .notdef +!80 U+0080 .notdef +!81 U+0081 .notdef +!82 U+0082 .notdef +!83 U+0083 .notdef +!84 U+0084 .notdef +!85 U+0085 .notdef +!86 U+0086 .notdef +!87 U+0087 .notdef +!88 U+0088 .notdef +!89 U+0089 .notdef +!8A U+008A .notdef +!8B U+008B .notdef +!8C U+008C .notdef +!8D U+008D .notdef +!8E U+008E .notdef +!8F U+008F .notdef +!90 U+0090 .notdef +!91 U+0091 .notdef +!92 U+0092 .notdef +!93 U+0093 .notdef +!94 U+0094 .notdef +!95 U+0095 .notdef +!96 U+0096 .notdef +!97 U+0097 .notdef +!98 U+0098 .notdef +!99 U+0099 .notdef +!9A U+009A .notdef +!9B U+009B .notdef +!9C U+009C .notdef +!9D U+009D .notdef +!9E U+009E .notdef +!9F U+009F .notdef +!A0 U+00A0 space +!A1 U+0104 Aogonek +!A2 U+02D8 breve +!A3 U+0141 Lslash +!A4 U+00A4 currency +!A5 U+013D Lcaron +!A6 U+015A Sacute +!A7 U+00A7 section +!A8 U+00A8 dieresis +!A9 U+0160 Scaron +!AA U+015E Scedilla +!AB U+0164 Tcaron +!AC U+0179 Zacute +!AD U+00AD hyphen +!AE U+017D Zcaron +!AF U+017B Zdotaccent +!B0 U+00B0 degree +!B1 U+0105 aogonek +!B2 U+02DB ogonek +!B3 U+0142 lslash +!B4 U+00B4 acute +!B5 U+013E lcaron +!B6 U+015B sacute +!B7 U+02C7 caron +!B8 U+00B8 cedilla +!B9 U+0161 scaron +!BA U+015F scedilla +!BB U+0165 tcaron +!BC U+017A zacute +!BD U+02DD hungarumlaut +!BE U+017E zcaron +!BF U+017C zdotaccent +!C0 U+0154 Racute +!C1 U+00C1 Aacute +!C2 U+00C2 Acircumflex +!C3 U+0102 Abreve +!C4 U+00C4 Adieresis +!C5 U+0139 Lacute +!C6 U+0106 Cacute +!C7 U+00C7 Ccedilla +!C8 U+010C Ccaron +!C9 U+00C9 Eacute +!CA U+0118 Eogonek +!CB U+00CB Edieresis +!CC U+011A Ecaron +!CD U+00CD Iacute +!CE U+00CE Icircumflex +!CF U+010E Dcaron +!D0 U+0110 Dcroat +!D1 U+0143 Nacute +!D2 U+0147 Ncaron +!D3 U+00D3 Oacute +!D4 U+00D4 Ocircumflex +!D5 U+0150 Ohungarumlaut +!D6 U+00D6 Odieresis +!D7 U+00D7 multiply +!D8 U+0158 Rcaron +!D9 U+016E Uring +!DA U+00DA Uacute +!DB U+0170 Uhungarumlaut +!DC U+00DC Udieresis +!DD U+00DD Yacute +!DE U+0162 Tcommaaccent +!DF U+00DF germandbls +!E0 U+0155 racute +!E1 U+00E1 aacute +!E2 U+00E2 acircumflex +!E3 U+0103 abreve +!E4 U+00E4 adieresis +!E5 U+013A lacute +!E6 U+0107 cacute +!E7 U+00E7 ccedilla +!E8 U+010D ccaron +!E9 U+00E9 eacute +!EA U+0119 eogonek +!EB U+00EB edieresis +!EC U+011B ecaron +!ED U+00ED iacute +!EE U+00EE icircumflex +!EF U+010F dcaron +!F0 U+0111 dcroat +!F1 U+0144 nacute +!F2 U+0148 ncaron +!F3 U+00F3 oacute +!F4 U+00F4 ocircumflex +!F5 U+0151 ohungarumlaut +!F6 U+00F6 odieresis +!F7 U+00F7 divide +!F8 U+0159 rcaron +!F9 U+016F uring +!FA U+00FA uacute +!FB U+0171 uhungarumlaut +!FC U+00FC udieresis +!FD U+00FD yacute +!FE U+0163 tcommaaccent +!FF U+02D9 dotaccent diff --git a/include/tcpdf/fonts/utils/enc/iso-8859-4.map b/include/tcpdf/fonts/utils/enc/iso-8859-4.map new file mode 100644 index 00000000..a7d87bf3 --- /dev/null +++ b/include/tcpdf/fonts/utils/enc/iso-8859-4.map @@ -0,0 +1,256 @@ +!00 U+0000 .notdef +!01 U+0001 .notdef +!02 U+0002 .notdef +!03 U+0003 .notdef +!04 U+0004 .notdef +!05 U+0005 .notdef +!06 U+0006 .notdef +!07 U+0007 .notdef +!08 U+0008 .notdef +!09 U+0009 .notdef +!0A U+000A .notdef +!0B U+000B .notdef +!0C U+000C .notdef +!0D U+000D .notdef +!0E U+000E .notdef +!0F U+000F .notdef +!10 U+0010 .notdef +!11 U+0011 .notdef +!12 U+0012 .notdef +!13 U+0013 .notdef +!14 U+0014 .notdef +!15 U+0015 .notdef +!16 U+0016 .notdef +!17 U+0017 .notdef +!18 U+0018 .notdef +!19 U+0019 .notdef +!1A U+001A .notdef +!1B U+001B .notdef +!1C U+001C .notdef +!1D U+001D .notdef +!1E U+001E .notdef +!1F U+001F .notdef +!20 U+0020 space +!21 U+0021 exclam +!22 U+0022 quotedbl +!23 U+0023 numbersign +!24 U+0024 dollar +!25 U+0025 percent +!26 U+0026 ampersand +!27 U+0027 quotesingle +!28 U+0028 parenleft +!29 U+0029 parenright +!2A U+002A asterisk +!2B U+002B plus +!2C U+002C comma +!2D U+002D hyphen +!2E U+002E period +!2F U+002F slash +!30 U+0030 zero +!31 U+0031 one +!32 U+0032 two +!33 U+0033 three +!34 U+0034 four +!35 U+0035 five +!36 U+0036 six +!37 U+0037 seven +!38 U+0038 eight +!39 U+0039 nine +!3A U+003A colon +!3B U+003B semicolon +!3C U+003C less +!3D U+003D equal +!3E U+003E greater +!3F U+003F question +!40 U+0040 at +!41 U+0041 A +!42 U+0042 B +!43 U+0043 C +!44 U+0044 D +!45 U+0045 E +!46 U+0046 F +!47 U+0047 G +!48 U+0048 H +!49 U+0049 I +!4A U+004A J +!4B U+004B K +!4C U+004C L +!4D U+004D M +!4E U+004E N +!4F U+004F O +!50 U+0050 P +!51 U+0051 Q +!52 U+0052 R +!53 U+0053 S +!54 U+0054 T +!55 U+0055 U +!56 U+0056 V +!57 U+0057 W +!58 U+0058 X +!59 U+0059 Y +!5A U+005A Z +!5B U+005B bracketleft +!5C U+005C backslash +!5D U+005D bracketright +!5E U+005E asciicircum +!5F U+005F underscore +!60 U+0060 grave +!61 U+0061 a +!62 U+0062 b +!63 U+0063 c +!64 U+0064 d +!65 U+0065 e +!66 U+0066 f +!67 U+0067 g +!68 U+0068 h +!69 U+0069 i +!6A U+006A j +!6B U+006B k +!6C U+006C l +!6D U+006D m +!6E U+006E n +!6F U+006F o +!70 U+0070 p +!71 U+0071 q +!72 U+0072 r +!73 U+0073 s +!74 U+0074 t +!75 U+0075 u +!76 U+0076 v +!77 U+0077 w +!78 U+0078 x +!79 U+0079 y +!7A U+007A z +!7B U+007B braceleft +!7C U+007C bar +!7D U+007D braceright +!7E U+007E asciitilde +!7F U+007F .notdef +!80 U+0080 .notdef +!81 U+0081 .notdef +!82 U+0082 .notdef +!83 U+0083 .notdef +!84 U+0084 .notdef +!85 U+0085 .notdef +!86 U+0086 .notdef +!87 U+0087 .notdef +!88 U+0088 .notdef +!89 U+0089 .notdef +!8A U+008A .notdef +!8B U+008B .notdef +!8C U+008C .notdef +!8D U+008D .notdef +!8E U+008E .notdef +!8F U+008F .notdef +!90 U+0090 .notdef +!91 U+0091 .notdef +!92 U+0092 .notdef +!93 U+0093 .notdef +!94 U+0094 .notdef +!95 U+0095 .notdef +!96 U+0096 .notdef +!97 U+0097 .notdef +!98 U+0098 .notdef +!99 U+0099 .notdef +!9A U+009A .notdef +!9B U+009B .notdef +!9C U+009C .notdef +!9D U+009D .notdef +!9E U+009E .notdef +!9F U+009F .notdef +!A0 U+00A0 space +!A1 U+0104 Aogonek +!A2 U+0138 kgreenlandic +!A3 U+0156 Rcommaaccent +!A4 U+00A4 currency +!A5 U+0128 Itilde +!A6 U+013B Lcommaaccent +!A7 U+00A7 section +!A8 U+00A8 dieresis +!A9 U+0160 Scaron +!AA U+0112 Emacron +!AB U+0122 Gcommaaccent +!AC U+0166 Tbar +!AD U+00AD hyphen +!AE U+017D Zcaron +!AF U+00AF macron +!B0 U+00B0 degree +!B1 U+0105 aogonek +!B2 U+02DB ogonek +!B3 U+0157 rcommaaccent +!B4 U+00B4 acute +!B5 U+0129 itilde +!B6 U+013C lcommaaccent +!B7 U+02C7 caron +!B8 U+00B8 cedilla +!B9 U+0161 scaron +!BA U+0113 emacron +!BB U+0123 gcommaaccent +!BC U+0167 tbar +!BD U+014A Eng +!BE U+017E zcaron +!BF U+014B eng +!C0 U+0100 Amacron +!C1 U+00C1 Aacute +!C2 U+00C2 Acircumflex +!C3 U+00C3 Atilde +!C4 U+00C4 Adieresis +!C5 U+00C5 Aring +!C6 U+00C6 AE +!C7 U+012E Iogonek +!C8 U+010C Ccaron +!C9 U+00C9 Eacute +!CA U+0118 Eogonek +!CB U+00CB Edieresis +!CC U+0116 Edotaccent +!CD U+00CD Iacute +!CE U+00CE Icircumflex +!CF U+012A Imacron +!D0 U+0110 Dcroat +!D1 U+0145 Ncommaaccent +!D2 U+014C Omacron +!D3 U+0136 Kcommaaccent +!D4 U+00D4 Ocircumflex +!D5 U+00D5 Otilde +!D6 U+00D6 Odieresis +!D7 U+00D7 multiply +!D8 U+00D8 Oslash +!D9 U+0172 Uogonek +!DA U+00DA Uacute +!DB U+00DB Ucircumflex +!DC U+00DC Udieresis +!DD U+0168 Utilde +!DE U+016A Umacron +!DF U+00DF germandbls +!E0 U+0101 amacron +!E1 U+00E1 aacute +!E2 U+00E2 acircumflex +!E3 U+00E3 atilde +!E4 U+00E4 adieresis +!E5 U+00E5 aring +!E6 U+00E6 ae +!E7 U+012F iogonek +!E8 U+010D ccaron +!E9 U+00E9 eacute +!EA U+0119 eogonek +!EB U+00EB edieresis +!EC U+0117 edotaccent +!ED U+00ED iacute +!EE U+00EE icircumflex +!EF U+012B imacron +!F0 U+0111 dcroat +!F1 U+0146 ncommaaccent +!F2 U+014D omacron +!F3 U+0137 kcommaaccent +!F4 U+00F4 ocircumflex +!F5 U+00F5 otilde +!F6 U+00F6 odieresis +!F7 U+00F7 divide +!F8 U+00F8 oslash +!F9 U+0173 uogonek +!FA U+00FA uacute +!FB U+00FB ucircumflex +!FC U+00FC udieresis +!FD U+0169 utilde +!FE U+016B umacron +!FF U+02D9 dotaccent diff --git a/include/tcpdf/fonts/utils/enc/iso-8859-5.map b/include/tcpdf/fonts/utils/enc/iso-8859-5.map new file mode 100644 index 00000000..f9cd4edc --- /dev/null +++ b/include/tcpdf/fonts/utils/enc/iso-8859-5.map @@ -0,0 +1,256 @@ +!00 U+0000 .notdef +!01 U+0001 .notdef +!02 U+0002 .notdef +!03 U+0003 .notdef +!04 U+0004 .notdef +!05 U+0005 .notdef +!06 U+0006 .notdef +!07 U+0007 .notdef +!08 U+0008 .notdef +!09 U+0009 .notdef +!0A U+000A .notdef +!0B U+000B .notdef +!0C U+000C .notdef +!0D U+000D .notdef +!0E U+000E .notdef +!0F U+000F .notdef +!10 U+0010 .notdef +!11 U+0011 .notdef +!12 U+0012 .notdef +!13 U+0013 .notdef +!14 U+0014 .notdef +!15 U+0015 .notdef +!16 U+0016 .notdef +!17 U+0017 .notdef +!18 U+0018 .notdef +!19 U+0019 .notdef +!1A U+001A .notdef +!1B U+001B .notdef +!1C U+001C .notdef +!1D U+001D .notdef +!1E U+001E .notdef +!1F U+001F .notdef +!20 U+0020 space +!21 U+0021 exclam +!22 U+0022 quotedbl +!23 U+0023 numbersign +!24 U+0024 dollar +!25 U+0025 percent +!26 U+0026 ampersand +!27 U+0027 quotesingle +!28 U+0028 parenleft +!29 U+0029 parenright +!2A U+002A asterisk +!2B U+002B plus +!2C U+002C comma +!2D U+002D hyphen +!2E U+002E period +!2F U+002F slash +!30 U+0030 zero +!31 U+0031 one +!32 U+0032 two +!33 U+0033 three +!34 U+0034 four +!35 U+0035 five +!36 U+0036 six +!37 U+0037 seven +!38 U+0038 eight +!39 U+0039 nine +!3A U+003A colon +!3B U+003B semicolon +!3C U+003C less +!3D U+003D equal +!3E U+003E greater +!3F U+003F question +!40 U+0040 at +!41 U+0041 A +!42 U+0042 B +!43 U+0043 C +!44 U+0044 D +!45 U+0045 E +!46 U+0046 F +!47 U+0047 G +!48 U+0048 H +!49 U+0049 I +!4A U+004A J +!4B U+004B K +!4C U+004C L +!4D U+004D M +!4E U+004E N +!4F U+004F O +!50 U+0050 P +!51 U+0051 Q +!52 U+0052 R +!53 U+0053 S +!54 U+0054 T +!55 U+0055 U +!56 U+0056 V +!57 U+0057 W +!58 U+0058 X +!59 U+0059 Y +!5A U+005A Z +!5B U+005B bracketleft +!5C U+005C backslash +!5D U+005D bracketright +!5E U+005E asciicircum +!5F U+005F underscore +!60 U+0060 grave +!61 U+0061 a +!62 U+0062 b +!63 U+0063 c +!64 U+0064 d +!65 U+0065 e +!66 U+0066 f +!67 U+0067 g +!68 U+0068 h +!69 U+0069 i +!6A U+006A j +!6B U+006B k +!6C U+006C l +!6D U+006D m +!6E U+006E n +!6F U+006F o +!70 U+0070 p +!71 U+0071 q +!72 U+0072 r +!73 U+0073 s +!74 U+0074 t +!75 U+0075 u +!76 U+0076 v +!77 U+0077 w +!78 U+0078 x +!79 U+0079 y +!7A U+007A z +!7B U+007B braceleft +!7C U+007C bar +!7D U+007D braceright +!7E U+007E asciitilde +!7F U+007F .notdef +!80 U+0080 .notdef +!81 U+0081 .notdef +!82 U+0082 .notdef +!83 U+0083 .notdef +!84 U+0084 .notdef +!85 U+0085 .notdef +!86 U+0086 .notdef +!87 U+0087 .notdef +!88 U+0088 .notdef +!89 U+0089 .notdef +!8A U+008A .notdef +!8B U+008B .notdef +!8C U+008C .notdef +!8D U+008D .notdef +!8E U+008E .notdef +!8F U+008F .notdef +!90 U+0090 .notdef +!91 U+0091 .notdef +!92 U+0092 .notdef +!93 U+0093 .notdef +!94 U+0094 .notdef +!95 U+0095 .notdef +!96 U+0096 .notdef +!97 U+0097 .notdef +!98 U+0098 .notdef +!99 U+0099 .notdef +!9A U+009A .notdef +!9B U+009B .notdef +!9C U+009C .notdef +!9D U+009D .notdef +!9E U+009E .notdef +!9F U+009F .notdef +!A0 U+00A0 space +!A1 U+0401 afii10023 +!A2 U+0402 afii10051 +!A3 U+0403 afii10052 +!A4 U+0404 afii10053 +!A5 U+0405 afii10054 +!A6 U+0406 afii10055 +!A7 U+0407 afii10056 +!A8 U+0408 afii10057 +!A9 U+0409 afii10058 +!AA U+040A afii10059 +!AB U+040B afii10060 +!AC U+040C afii10061 +!AD U+00AD hyphen +!AE U+040E afii10062 +!AF U+040F afii10145 +!B0 U+0410 afii10017 +!B1 U+0411 afii10018 +!B2 U+0412 afii10019 +!B3 U+0413 afii10020 +!B4 U+0414 afii10021 +!B5 U+0415 afii10022 +!B6 U+0416 afii10024 +!B7 U+0417 afii10025 +!B8 U+0418 afii10026 +!B9 U+0419 afii10027 +!BA U+041A afii10028 +!BB U+041B afii10029 +!BC U+041C afii10030 +!BD U+041D afii10031 +!BE U+041E afii10032 +!BF U+041F afii10033 +!C0 U+0420 afii10034 +!C1 U+0421 afii10035 +!C2 U+0422 afii10036 +!C3 U+0423 afii10037 +!C4 U+0424 afii10038 +!C5 U+0425 afii10039 +!C6 U+0426 afii10040 +!C7 U+0427 afii10041 +!C8 U+0428 afii10042 +!C9 U+0429 afii10043 +!CA U+042A afii10044 +!CB U+042B afii10045 +!CC U+042C afii10046 +!CD U+042D afii10047 +!CE U+042E afii10048 +!CF U+042F afii10049 +!D0 U+0430 afii10065 +!D1 U+0431 afii10066 +!D2 U+0432 afii10067 +!D3 U+0433 afii10068 +!D4 U+0434 afii10069 +!D5 U+0435 afii10070 +!D6 U+0436 afii10072 +!D7 U+0437 afii10073 +!D8 U+0438 afii10074 +!D9 U+0439 afii10075 +!DA U+043A afii10076 +!DB U+043B afii10077 +!DC U+043C afii10078 +!DD U+043D afii10079 +!DE U+043E afii10080 +!DF U+043F afii10081 +!E0 U+0440 afii10082 +!E1 U+0441 afii10083 +!E2 U+0442 afii10084 +!E3 U+0443 afii10085 +!E4 U+0444 afii10086 +!E5 U+0445 afii10087 +!E6 U+0446 afii10088 +!E7 U+0447 afii10089 +!E8 U+0448 afii10090 +!E9 U+0449 afii10091 +!EA U+044A afii10092 +!EB U+044B afii10093 +!EC U+044C afii10094 +!ED U+044D afii10095 +!EE U+044E afii10096 +!EF U+044F afii10097 +!F0 U+2116 afii61352 +!F1 U+0451 afii10071 +!F2 U+0452 afii10099 +!F3 U+0453 afii10100 +!F4 U+0454 afii10101 +!F5 U+0455 afii10102 +!F6 U+0456 afii10103 +!F7 U+0457 afii10104 +!F8 U+0458 afii10105 +!F9 U+0459 afii10106 +!FA U+045A afii10107 +!FB U+045B afii10108 +!FC U+045C afii10109 +!FD U+00A7 section +!FE U+045E afii10110 +!FF U+045F afii10193 diff --git a/include/tcpdf/fonts/utils/enc/iso-8859-7.map b/include/tcpdf/fonts/utils/enc/iso-8859-7.map new file mode 100644 index 00000000..e163796b --- /dev/null +++ b/include/tcpdf/fonts/utils/enc/iso-8859-7.map @@ -0,0 +1,250 @@ +!00 U+0000 .notdef +!01 U+0001 .notdef +!02 U+0002 .notdef +!03 U+0003 .notdef +!04 U+0004 .notdef +!05 U+0005 .notdef +!06 U+0006 .notdef +!07 U+0007 .notdef +!08 U+0008 .notdef +!09 U+0009 .notdef +!0A U+000A .notdef +!0B U+000B .notdef +!0C U+000C .notdef +!0D U+000D .notdef +!0E U+000E .notdef +!0F U+000F .notdef +!10 U+0010 .notdef +!11 U+0011 .notdef +!12 U+0012 .notdef +!13 U+0013 .notdef +!14 U+0014 .notdef +!15 U+0015 .notdef +!16 U+0016 .notdef +!17 U+0017 .notdef +!18 U+0018 .notdef +!19 U+0019 .notdef +!1A U+001A .notdef +!1B U+001B .notdef +!1C U+001C .notdef +!1D U+001D .notdef +!1E U+001E .notdef +!1F U+001F .notdef +!20 U+0020 space +!21 U+0021 exclam +!22 U+0022 quotedbl +!23 U+0023 numbersign +!24 U+0024 dollar +!25 U+0025 percent +!26 U+0026 ampersand +!27 U+0027 quotesingle +!28 U+0028 parenleft +!29 U+0029 parenright +!2A U+002A asterisk +!2B U+002B plus +!2C U+002C comma +!2D U+002D hyphen +!2E U+002E period +!2F U+002F slash +!30 U+0030 zero +!31 U+0031 one +!32 U+0032 two +!33 U+0033 three +!34 U+0034 four +!35 U+0035 five +!36 U+0036 six +!37 U+0037 seven +!38 U+0038 eight +!39 U+0039 nine +!3A U+003A colon +!3B U+003B semicolon +!3C U+003C less +!3D U+003D equal +!3E U+003E greater +!3F U+003F question +!40 U+0040 at +!41 U+0041 A +!42 U+0042 B +!43 U+0043 C +!44 U+0044 D +!45 U+0045 E +!46 U+0046 F +!47 U+0047 G +!48 U+0048 H +!49 U+0049 I +!4A U+004A J +!4B U+004B K +!4C U+004C L +!4D U+004D M +!4E U+004E N +!4F U+004F O +!50 U+0050 P +!51 U+0051 Q +!52 U+0052 R +!53 U+0053 S +!54 U+0054 T +!55 U+0055 U +!56 U+0056 V +!57 U+0057 W +!58 U+0058 X +!59 U+0059 Y +!5A U+005A Z +!5B U+005B bracketleft +!5C U+005C backslash +!5D U+005D bracketright +!5E U+005E asciicircum +!5F U+005F underscore +!60 U+0060 grave +!61 U+0061 a +!62 U+0062 b +!63 U+0063 c +!64 U+0064 d +!65 U+0065 e +!66 U+0066 f +!67 U+0067 g +!68 U+0068 h +!69 U+0069 i +!6A U+006A j +!6B U+006B k +!6C U+006C l +!6D U+006D m +!6E U+006E n +!6F U+006F o +!70 U+0070 p +!71 U+0071 q +!72 U+0072 r +!73 U+0073 s +!74 U+0074 t +!75 U+0075 u +!76 U+0076 v +!77 U+0077 w +!78 U+0078 x +!79 U+0079 y +!7A U+007A z +!7B U+007B braceleft +!7C U+007C bar +!7D U+007D braceright +!7E U+007E asciitilde +!7F U+007F .notdef +!80 U+0080 .notdef +!81 U+0081 .notdef +!82 U+0082 .notdef +!83 U+0083 .notdef +!84 U+0084 .notdef +!85 U+0085 .notdef +!86 U+0086 .notdef +!87 U+0087 .notdef +!88 U+0088 .notdef +!89 U+0089 .notdef +!8A U+008A .notdef +!8B U+008B .notdef +!8C U+008C .notdef +!8D U+008D .notdef +!8E U+008E .notdef +!8F U+008F .notdef +!90 U+0090 .notdef +!91 U+0091 .notdef +!92 U+0092 .notdef +!93 U+0093 .notdef +!94 U+0094 .notdef +!95 U+0095 .notdef +!96 U+0096 .notdef +!97 U+0097 .notdef +!98 U+0098 .notdef +!99 U+0099 .notdef +!9A U+009A .notdef +!9B U+009B .notdef +!9C U+009C .notdef +!9D U+009D .notdef +!9E U+009E .notdef +!9F U+009F .notdef +!A0 U+00A0 space +!A1 U+2018 quoteleft +!A2 U+2019 quoteright +!A3 U+00A3 sterling +!A6 U+00A6 brokenbar +!A7 U+00A7 section +!A8 U+00A8 dieresis +!A9 U+00A9 copyright +!AB U+00AB guillemotleft +!AC U+00AC logicalnot +!AD U+00AD hyphen +!AF U+2015 afii00208 +!B0 U+00B0 degree +!B1 U+00B1 plusminus +!B2 U+00B2 twosuperior +!B3 U+00B3 threesuperior +!B4 U+0384 tonos +!B5 U+0385 dieresistonos +!B6 U+0386 Alphatonos +!B7 U+00B7 periodcentered +!B8 U+0388 Epsilontonos +!B9 U+0389 Etatonos +!BA U+038A Iotatonos +!BB U+00BB guillemotright +!BC U+038C Omicrontonos +!BD U+00BD onehalf +!BE U+038E Upsilontonos +!BF U+038F Omegatonos +!C0 U+0390 iotadieresistonos +!C1 U+0391 Alpha +!C2 U+0392 Beta +!C3 U+0393 Gamma +!C4 U+0394 Delta +!C5 U+0395 Epsilon +!C6 U+0396 Zeta +!C7 U+0397 Eta +!C8 U+0398 Theta +!C9 U+0399 Iota +!CA U+039A Kappa +!CB U+039B Lambda +!CC U+039C Mu +!CD U+039D Nu +!CE U+039E Xi +!CF U+039F Omicron +!D0 U+03A0 Pi +!D1 U+03A1 Rho +!D3 U+03A3 Sigma +!D4 U+03A4 Tau +!D5 U+03A5 Upsilon +!D6 U+03A6 Phi +!D7 U+03A7 Chi +!D8 U+03A8 Psi +!D9 U+03A9 Omega +!DA U+03AA Iotadieresis +!DB U+03AB Upsilondieresis +!DC U+03AC alphatonos +!DD U+03AD epsilontonos +!DE U+03AE etatonos +!DF U+03AF iotatonos +!E0 U+03B0 upsilondieresistonos +!E1 U+03B1 alpha +!E2 U+03B2 beta +!E3 U+03B3 gamma +!E4 U+03B4 delta +!E5 U+03B5 epsilon +!E6 U+03B6 zeta +!E7 U+03B7 eta +!E8 U+03B8 theta +!E9 U+03B9 iota +!EA U+03BA kappa +!EB U+03BB lambda +!EC U+03BC mu +!ED U+03BD nu +!EE U+03BE xi +!EF U+03BF omicron +!F0 U+03C0 pi +!F1 U+03C1 rho +!F2 U+03C2 sigma1 +!F3 U+03C3 sigma +!F4 U+03C4 tau +!F5 U+03C5 upsilon +!F6 U+03C6 phi +!F7 U+03C7 chi +!F8 U+03C8 psi +!F9 U+03C9 omega +!FA U+03CA iotadieresis +!FB U+03CB upsilondieresis +!FC U+03CC omicrontonos +!FD U+03CD upsilontonos +!FE U+03CE omegatonos diff --git a/include/tcpdf/fonts/utils/enc/iso-8859-9.map b/include/tcpdf/fonts/utils/enc/iso-8859-9.map new file mode 100644 index 00000000..48c123ae --- /dev/null +++ b/include/tcpdf/fonts/utils/enc/iso-8859-9.map @@ -0,0 +1,256 @@ +!00 U+0000 .notdef +!01 U+0001 .notdef +!02 U+0002 .notdef +!03 U+0003 .notdef +!04 U+0004 .notdef +!05 U+0005 .notdef +!06 U+0006 .notdef +!07 U+0007 .notdef +!08 U+0008 .notdef +!09 U+0009 .notdef +!0A U+000A .notdef +!0B U+000B .notdef +!0C U+000C .notdef +!0D U+000D .notdef +!0E U+000E .notdef +!0F U+000F .notdef +!10 U+0010 .notdef +!11 U+0011 .notdef +!12 U+0012 .notdef +!13 U+0013 .notdef +!14 U+0014 .notdef +!15 U+0015 .notdef +!16 U+0016 .notdef +!17 U+0017 .notdef +!18 U+0018 .notdef +!19 U+0019 .notdef +!1A U+001A .notdef +!1B U+001B .notdef +!1C U+001C .notdef +!1D U+001D .notdef +!1E U+001E .notdef +!1F U+001F .notdef +!20 U+0020 space +!21 U+0021 exclam +!22 U+0022 quotedbl +!23 U+0023 numbersign +!24 U+0024 dollar +!25 U+0025 percent +!26 U+0026 ampersand +!27 U+0027 quotesingle +!28 U+0028 parenleft +!29 U+0029 parenright +!2A U+002A asterisk +!2B U+002B plus +!2C U+002C comma +!2D U+002D hyphen +!2E U+002E period +!2F U+002F slash +!30 U+0030 zero +!31 U+0031 one +!32 U+0032 two +!33 U+0033 three +!34 U+0034 four +!35 U+0035 five +!36 U+0036 six +!37 U+0037 seven +!38 U+0038 eight +!39 U+0039 nine +!3A U+003A colon +!3B U+003B semicolon +!3C U+003C less +!3D U+003D equal +!3E U+003E greater +!3F U+003F question +!40 U+0040 at +!41 U+0041 A +!42 U+0042 B +!43 U+0043 C +!44 U+0044 D +!45 U+0045 E +!46 U+0046 F +!47 U+0047 G +!48 U+0048 H +!49 U+0049 I +!4A U+004A J +!4B U+004B K +!4C U+004C L +!4D U+004D M +!4E U+004E N +!4F U+004F O +!50 U+0050 P +!51 U+0051 Q +!52 U+0052 R +!53 U+0053 S +!54 U+0054 T +!55 U+0055 U +!56 U+0056 V +!57 U+0057 W +!58 U+0058 X +!59 U+0059 Y +!5A U+005A Z +!5B U+005B bracketleft +!5C U+005C backslash +!5D U+005D bracketright +!5E U+005E asciicircum +!5F U+005F underscore +!60 U+0060 grave +!61 U+0061 a +!62 U+0062 b +!63 U+0063 c +!64 U+0064 d +!65 U+0065 e +!66 U+0066 f +!67 U+0067 g +!68 U+0068 h +!69 U+0069 i +!6A U+006A j +!6B U+006B k +!6C U+006C l +!6D U+006D m +!6E U+006E n +!6F U+006F o +!70 U+0070 p +!71 U+0071 q +!72 U+0072 r +!73 U+0073 s +!74 U+0074 t +!75 U+0075 u +!76 U+0076 v +!77 U+0077 w +!78 U+0078 x +!79 U+0079 y +!7A U+007A z +!7B U+007B braceleft +!7C U+007C bar +!7D U+007D braceright +!7E U+007E asciitilde +!7F U+007F .notdef +!80 U+0080 .notdef +!81 U+0081 .notdef +!82 U+0082 .notdef +!83 U+0083 .notdef +!84 U+0084 .notdef +!85 U+0085 .notdef +!86 U+0086 .notdef +!87 U+0087 .notdef +!88 U+0088 .notdef +!89 U+0089 .notdef +!8A U+008A .notdef +!8B U+008B .notdef +!8C U+008C .notdef +!8D U+008D .notdef +!8E U+008E .notdef +!8F U+008F .notdef +!90 U+0090 .notdef +!91 U+0091 .notdef +!92 U+0092 .notdef +!93 U+0093 .notdef +!94 U+0094 .notdef +!95 U+0095 .notdef +!96 U+0096 .notdef +!97 U+0097 .notdef +!98 U+0098 .notdef +!99 U+0099 .notdef +!9A U+009A .notdef +!9B U+009B .notdef +!9C U+009C .notdef +!9D U+009D .notdef +!9E U+009E .notdef +!9F U+009F .notdef +!A0 U+00A0 space +!A1 U+00A1 exclamdown +!A2 U+00A2 cent +!A3 U+00A3 sterling +!A4 U+00A4 currency +!A5 U+00A5 yen +!A6 U+00A6 brokenbar +!A7 U+00A7 section +!A8 U+00A8 dieresis +!A9 U+00A9 copyright +!AA U+00AA ordfeminine +!AB U+00AB guillemotleft +!AC U+00AC logicalnot +!AD U+00AD hyphen +!AE U+00AE registered +!AF U+00AF macron +!B0 U+00B0 degree +!B1 U+00B1 plusminus +!B2 U+00B2 twosuperior +!B3 U+00B3 threesuperior +!B4 U+00B4 acute +!B5 U+00B5 mu +!B6 U+00B6 paragraph +!B7 U+00B7 periodcentered +!B8 U+00B8 cedilla +!B9 U+00B9 onesuperior +!BA U+00BA ordmasculine +!BB U+00BB guillemotright +!BC U+00BC onequarter +!BD U+00BD onehalf +!BE U+00BE threequarters +!BF U+00BF questiondown +!C0 U+00C0 Agrave +!C1 U+00C1 Aacute +!C2 U+00C2 Acircumflex +!C3 U+00C3 Atilde +!C4 U+00C4 Adieresis +!C5 U+00C5 Aring +!C6 U+00C6 AE +!C7 U+00C7 Ccedilla +!C8 U+00C8 Egrave +!C9 U+00C9 Eacute +!CA U+00CA Ecircumflex +!CB U+00CB Edieresis +!CC U+00CC Igrave +!CD U+00CD Iacute +!CE U+00CE Icircumflex +!CF U+00CF Idieresis +!D0 U+011E Gbreve +!D1 U+00D1 Ntilde +!D2 U+00D2 Ograve +!D3 U+00D3 Oacute +!D4 U+00D4 Ocircumflex +!D5 U+00D5 Otilde +!D6 U+00D6 Odieresis +!D7 U+00D7 multiply +!D8 U+00D8 Oslash +!D9 U+00D9 Ugrave +!DA U+00DA Uacute +!DB U+00DB Ucircumflex +!DC U+00DC Udieresis +!DD U+0130 Idotaccent +!DE U+015E Scedilla +!DF U+00DF germandbls +!E0 U+00E0 agrave +!E1 U+00E1 aacute +!E2 U+00E2 acircumflex +!E3 U+00E3 atilde +!E4 U+00E4 adieresis +!E5 U+00E5 aring +!E6 U+00E6 ae +!E7 U+00E7 ccedilla +!E8 U+00E8 egrave +!E9 U+00E9 eacute +!EA U+00EA ecircumflex +!EB U+00EB edieresis +!EC U+00EC igrave +!ED U+00ED iacute +!EE U+00EE icircumflex +!EF U+00EF idieresis +!F0 U+011F gbreve +!F1 U+00F1 ntilde +!F2 U+00F2 ograve +!F3 U+00F3 oacute +!F4 U+00F4 ocircumflex +!F5 U+00F5 otilde +!F6 U+00F6 odieresis +!F7 U+00F7 divide +!F8 U+00F8 oslash +!F9 U+00F9 ugrave +!FA U+00FA uacute +!FB U+00FB ucircumflex +!FC U+00FC udieresis +!FD U+0131 dotlessi +!FE U+015F scedilla +!FF U+00FF ydieresis diff --git a/include/tcpdf/fonts/utils/enc/koi8-r.map b/include/tcpdf/fonts/utils/enc/koi8-r.map new file mode 100644 index 00000000..6ad5d05d --- /dev/null +++ b/include/tcpdf/fonts/utils/enc/koi8-r.map @@ -0,0 +1,256 @@ +!00 U+0000 .notdef +!01 U+0001 .notdef +!02 U+0002 .notdef +!03 U+0003 .notdef +!04 U+0004 .notdef +!05 U+0005 .notdef +!06 U+0006 .notdef +!07 U+0007 .notdef +!08 U+0008 .notdef +!09 U+0009 .notdef +!0A U+000A .notdef +!0B U+000B .notdef +!0C U+000C .notdef +!0D U+000D .notdef +!0E U+000E .notdef +!0F U+000F .notdef +!10 U+0010 .notdef +!11 U+0011 .notdef +!12 U+0012 .notdef +!13 U+0013 .notdef +!14 U+0014 .notdef +!15 U+0015 .notdef +!16 U+0016 .notdef +!17 U+0017 .notdef +!18 U+0018 .notdef +!19 U+0019 .notdef +!1A U+001A .notdef +!1B U+001B .notdef +!1C U+001C .notdef +!1D U+001D .notdef +!1E U+001E .notdef +!1F U+001F .notdef +!20 U+0020 space +!21 U+0021 exclam +!22 U+0022 quotedbl +!23 U+0023 numbersign +!24 U+0024 dollar +!25 U+0025 percent +!26 U+0026 ampersand +!27 U+0027 quotesingle +!28 U+0028 parenleft +!29 U+0029 parenright +!2A U+002A asterisk +!2B U+002B plus +!2C U+002C comma +!2D U+002D hyphen +!2E U+002E period +!2F U+002F slash +!30 U+0030 zero +!31 U+0031 one +!32 U+0032 two +!33 U+0033 three +!34 U+0034 four +!35 U+0035 five +!36 U+0036 six +!37 U+0037 seven +!38 U+0038 eight +!39 U+0039 nine +!3A U+003A colon +!3B U+003B semicolon +!3C U+003C less +!3D U+003D equal +!3E U+003E greater +!3F U+003F question +!40 U+0040 at +!41 U+0041 A +!42 U+0042 B +!43 U+0043 C +!44 U+0044 D +!45 U+0045 E +!46 U+0046 F +!47 U+0047 G +!48 U+0048 H +!49 U+0049 I +!4A U+004A J +!4B U+004B K +!4C U+004C L +!4D U+004D M +!4E U+004E N +!4F U+004F O +!50 U+0050 P +!51 U+0051 Q +!52 U+0052 R +!53 U+0053 S +!54 U+0054 T +!55 U+0055 U +!56 U+0056 V +!57 U+0057 W +!58 U+0058 X +!59 U+0059 Y +!5A U+005A Z +!5B U+005B bracketleft +!5C U+005C backslash +!5D U+005D bracketright +!5E U+005E asciicircum +!5F U+005F underscore +!60 U+0060 grave +!61 U+0061 a +!62 U+0062 b +!63 U+0063 c +!64 U+0064 d +!65 U+0065 e +!66 U+0066 f +!67 U+0067 g +!68 U+0068 h +!69 U+0069 i +!6A U+006A j +!6B U+006B k +!6C U+006C l +!6D U+006D m +!6E U+006E n +!6F U+006F o +!70 U+0070 p +!71 U+0071 q +!72 U+0072 r +!73 U+0073 s +!74 U+0074 t +!75 U+0075 u +!76 U+0076 v +!77 U+0077 w +!78 U+0078 x +!79 U+0079 y +!7A U+007A z +!7B U+007B braceleft +!7C U+007C bar +!7D U+007D braceright +!7E U+007E asciitilde +!7F U+007F .notdef +!80 U+2500 SF100000 +!81 U+2502 SF110000 +!82 U+250C SF010000 +!83 U+2510 SF030000 +!84 U+2514 SF020000 +!85 U+2518 SF040000 +!86 U+251C SF080000 +!87 U+2524 SF090000 +!88 U+252C SF060000 +!89 U+2534 SF070000 +!8A U+253C SF050000 +!8B U+2580 upblock +!8C U+2584 dnblock +!8D U+2588 block +!8E U+258C lfblock +!8F U+2590 rtblock +!90 U+2591 ltshade +!91 U+2592 shade +!92 U+2593 dkshade +!93 U+2320 integraltp +!94 U+25A0 filledbox +!95 U+2219 periodcentered +!96 U+221A radical +!97 U+2248 approxequal +!98 U+2264 lessequal +!99 U+2265 greaterequal +!9A U+00A0 space +!9B U+2321 integralbt +!9C U+00B0 degree +!9D U+00B2 twosuperior +!9E U+00B7 periodcentered +!9F U+00F7 divide +!A0 U+2550 SF430000 +!A1 U+2551 SF240000 +!A2 U+2552 SF510000 +!A3 U+0451 afii10071 +!A4 U+2553 SF520000 +!A5 U+2554 SF390000 +!A6 U+2555 SF220000 +!A7 U+2556 SF210000 +!A8 U+2557 SF250000 +!A9 U+2558 SF500000 +!AA U+2559 SF490000 +!AB U+255A SF380000 +!AC U+255B SF280000 +!AD U+255C SF270000 +!AE U+255D SF260000 +!AF U+255E SF360000 +!B0 U+255F SF370000 +!B1 U+2560 SF420000 +!B2 U+2561 SF190000 +!B3 U+0401 afii10023 +!B4 U+2562 SF200000 +!B5 U+2563 SF230000 +!B6 U+2564 SF470000 +!B7 U+2565 SF480000 +!B8 U+2566 SF410000 +!B9 U+2567 SF450000 +!BA U+2568 SF460000 +!BB U+2569 SF400000 +!BC U+256A SF540000 +!BD U+256B SF530000 +!BE U+256C SF440000 +!BF U+00A9 copyright +!C0 U+044E afii10096 +!C1 U+0430 afii10065 +!C2 U+0431 afii10066 +!C3 U+0446 afii10088 +!C4 U+0434 afii10069 +!C5 U+0435 afii10070 +!C6 U+0444 afii10086 +!C7 U+0433 afii10068 +!C8 U+0445 afii10087 +!C9 U+0438 afii10074 +!CA U+0439 afii10075 +!CB U+043A afii10076 +!CC U+043B afii10077 +!CD U+043C afii10078 +!CE U+043D afii10079 +!CF U+043E afii10080 +!D0 U+043F afii10081 +!D1 U+044F afii10097 +!D2 U+0440 afii10082 +!D3 U+0441 afii10083 +!D4 U+0442 afii10084 +!D5 U+0443 afii10085 +!D6 U+0436 afii10072 +!D7 U+0432 afii10067 +!D8 U+044C afii10094 +!D9 U+044B afii10093 +!DA U+0437 afii10073 +!DB U+0448 afii10090 +!DC U+044D afii10095 +!DD U+0449 afii10091 +!DE U+0447 afii10089 +!DF U+044A afii10092 +!E0 U+042E afii10048 +!E1 U+0410 afii10017 +!E2 U+0411 afii10018 +!E3 U+0426 afii10040 +!E4 U+0414 afii10021 +!E5 U+0415 afii10022 +!E6 U+0424 afii10038 +!E7 U+0413 afii10020 +!E8 U+0425 afii10039 +!E9 U+0418 afii10026 +!EA U+0419 afii10027 +!EB U+041A afii10028 +!EC U+041B afii10029 +!ED U+041C afii10030 +!EE U+041D afii10031 +!EF U+041E afii10032 +!F0 U+041F afii10033 +!F1 U+042F afii10049 +!F2 U+0420 afii10034 +!F3 U+0421 afii10035 +!F4 U+0422 afii10036 +!F5 U+0423 afii10037 +!F6 U+0416 afii10024 +!F7 U+0412 afii10019 +!F8 U+042C afii10046 +!F9 U+042B afii10045 +!FA U+0417 afii10025 +!FB U+0428 afii10042 +!FC U+042D afii10047 +!FD U+0429 afii10043 +!FE U+0427 afii10041 +!FF U+042A afii10044 diff --git a/include/tcpdf/fonts/utils/enc/koi8-u.map b/include/tcpdf/fonts/utils/enc/koi8-u.map new file mode 100644 index 00000000..40a7e4fd --- /dev/null +++ b/include/tcpdf/fonts/utils/enc/koi8-u.map @@ -0,0 +1,256 @@ +!00 U+0000 .notdef +!01 U+0001 .notdef +!02 U+0002 .notdef +!03 U+0003 .notdef +!04 U+0004 .notdef +!05 U+0005 .notdef +!06 U+0006 .notdef +!07 U+0007 .notdef +!08 U+0008 .notdef +!09 U+0009 .notdef +!0A U+000A .notdef +!0B U+000B .notdef +!0C U+000C .notdef +!0D U+000D .notdef +!0E U+000E .notdef +!0F U+000F .notdef +!10 U+0010 .notdef +!11 U+0011 .notdef +!12 U+0012 .notdef +!13 U+0013 .notdef +!14 U+0014 .notdef +!15 U+0015 .notdef +!16 U+0016 .notdef +!17 U+0017 .notdef +!18 U+0018 .notdef +!19 U+0019 .notdef +!1A U+001A .notdef +!1B U+001B .notdef +!1C U+001C .notdef +!1D U+001D .notdef +!1E U+001E .notdef +!1F U+001F .notdef +!20 U+0020 space +!21 U+0021 exclam +!22 U+0022 quotedbl +!23 U+0023 numbersign +!24 U+0024 dollar +!25 U+0025 percent +!26 U+0026 ampersand +!27 U+0027 quotesingle +!28 U+0028 parenleft +!29 U+0029 parenright +!2A U+002A asterisk +!2B U+002B plus +!2C U+002C comma +!2D U+002D hyphen +!2E U+002E period +!2F U+002F slash +!30 U+0030 zero +!31 U+0031 one +!32 U+0032 two +!33 U+0033 three +!34 U+0034 four +!35 U+0035 five +!36 U+0036 six +!37 U+0037 seven +!38 U+0038 eight +!39 U+0039 nine +!3A U+003A colon +!3B U+003B semicolon +!3C U+003C less +!3D U+003D equal +!3E U+003E greater +!3F U+003F question +!40 U+0040 at +!41 U+0041 A +!42 U+0042 B +!43 U+0043 C +!44 U+0044 D +!45 U+0045 E +!46 U+0046 F +!47 U+0047 G +!48 U+0048 H +!49 U+0049 I +!4A U+004A J +!4B U+004B K +!4C U+004C L +!4D U+004D M +!4E U+004E N +!4F U+004F O +!50 U+0050 P +!51 U+0051 Q +!52 U+0052 R +!53 U+0053 S +!54 U+0054 T +!55 U+0055 U +!56 U+0056 V +!57 U+0057 W +!58 U+0058 X +!59 U+0059 Y +!5A U+005A Z +!5B U+005B bracketleft +!5C U+005C backslash +!5D U+005D bracketright +!5E U+005E asciicircum +!5F U+005F underscore +!60 U+0060 grave +!61 U+0061 a +!62 U+0062 b +!63 U+0063 c +!64 U+0064 d +!65 U+0065 e +!66 U+0066 f +!67 U+0067 g +!68 U+0068 h +!69 U+0069 i +!6A U+006A j +!6B U+006B k +!6C U+006C l +!6D U+006D m +!6E U+006E n +!6F U+006F o +!70 U+0070 p +!71 U+0071 q +!72 U+0072 r +!73 U+0073 s +!74 U+0074 t +!75 U+0075 u +!76 U+0076 v +!77 U+0077 w +!78 U+0078 x +!79 U+0079 y +!7A U+007A z +!7B U+007B braceleft +!7C U+007C bar +!7D U+007D braceright +!7E U+007E asciitilde +!7F U+007F .notdef +!80 U+2500 SF100000 +!81 U+2502 SF110000 +!82 U+250C SF010000 +!83 U+2510 SF030000 +!84 U+2514 SF020000 +!85 U+2518 SF040000 +!86 U+251C SF080000 +!87 U+2524 SF090000 +!88 U+252C SF060000 +!89 U+2534 SF070000 +!8A U+253C SF050000 +!8B U+2580 upblock +!8C U+2584 dnblock +!8D U+2588 block +!8E U+258C lfblock +!8F U+2590 rtblock +!90 U+2591 ltshade +!91 U+2592 shade +!92 U+2593 dkshade +!93 U+2320 integraltp +!94 U+25A0 filledbox +!95 U+2022 bullet +!96 U+221A radical +!97 U+2248 approxequal +!98 U+2264 lessequal +!99 U+2265 greaterequal +!9A U+00A0 space +!9B U+2321 integralbt +!9C U+00B0 degree +!9D U+00B2 twosuperior +!9E U+00B7 periodcentered +!9F U+00F7 divide +!A0 U+2550 SF430000 +!A1 U+2551 SF240000 +!A2 U+2552 SF510000 +!A3 U+0451 afii10071 +!A4 U+0454 afii10101 +!A5 U+2554 SF390000 +!A6 U+0456 afii10103 +!A7 U+0457 afii10104 +!A8 U+2557 SF250000 +!A9 U+2558 SF500000 +!AA U+2559 SF490000 +!AB U+255A SF380000 +!AC U+255B SF280000 +!AD U+0491 afii10098 +!AE U+255D SF260000 +!AF U+255E SF360000 +!B0 U+255F SF370000 +!B1 U+2560 SF420000 +!B2 U+2561 SF190000 +!B3 U+0401 afii10023 +!B4 U+0404 afii10053 +!B5 U+2563 SF230000 +!B6 U+0406 afii10055 +!B7 U+0407 afii10056 +!B8 U+2566 SF410000 +!B9 U+2567 SF450000 +!BA U+2568 SF460000 +!BB U+2569 SF400000 +!BC U+256A SF540000 +!BD U+0490 afii10050 +!BE U+256C SF440000 +!BF U+00A9 copyright +!C0 U+044E afii10096 +!C1 U+0430 afii10065 +!C2 U+0431 afii10066 +!C3 U+0446 afii10088 +!C4 U+0434 afii10069 +!C5 U+0435 afii10070 +!C6 U+0444 afii10086 +!C7 U+0433 afii10068 +!C8 U+0445 afii10087 +!C9 U+0438 afii10074 +!CA U+0439 afii10075 +!CB U+043A afii10076 +!CC U+043B afii10077 +!CD U+043C afii10078 +!CE U+043D afii10079 +!CF U+043E afii10080 +!D0 U+043F afii10081 +!D1 U+044F afii10097 +!D2 U+0440 afii10082 +!D3 U+0441 afii10083 +!D4 U+0442 afii10084 +!D5 U+0443 afii10085 +!D6 U+0436 afii10072 +!D7 U+0432 afii10067 +!D8 U+044C afii10094 +!D9 U+044B afii10093 +!DA U+0437 afii10073 +!DB U+0448 afii10090 +!DC U+044D afii10095 +!DD U+0449 afii10091 +!DE U+0447 afii10089 +!DF U+044A afii10092 +!E0 U+042E afii10048 +!E1 U+0410 afii10017 +!E2 U+0411 afii10018 +!E3 U+0426 afii10040 +!E4 U+0414 afii10021 +!E5 U+0415 afii10022 +!E6 U+0424 afii10038 +!E7 U+0413 afii10020 +!E8 U+0425 afii10039 +!E9 U+0418 afii10026 +!EA U+0419 afii10027 +!EB U+041A afii10028 +!EC U+041B afii10029 +!ED U+041C afii10030 +!EE U+041D afii10031 +!EF U+041E afii10032 +!F0 U+041F afii10033 +!F1 U+042F afii10049 +!F2 U+0420 afii10034 +!F3 U+0421 afii10035 +!F4 U+0422 afii10036 +!F5 U+0423 afii10037 +!F6 U+0416 afii10024 +!F7 U+0412 afii10019 +!F8 U+042C afii10046 +!F9 U+042B afii10045 +!FA U+0417 afii10025 +!FB U+0428 afii10042 +!FC U+042D afii10047 +!FD U+0429 afii10043 +!FE U+0427 afii10041 +!FF U+042A afii10044 diff --git a/include/tcpdf/fonts/utils/makefont.php b/include/tcpdf/fonts/utils/makefont.php new file mode 100644 index 00000000..24173441 --- /dev/null +++ b/include/tcpdf/fonts/utils/makefont.php @@ -0,0 +1,730 @@ +. +// +// See LICENSE.TXT file for more information. +// ---------------------------------------------------------------------------- +// +// Description : Utility to generate font definition files fot TCPDF +// +// Authors: Nicola Asuni, Olivier Plathey, Steven Wittens +// +// (c) Copyright: +// Nicola Asuni +// Tecnick.com S.r.l. +// Via della Pace, 11 +// 09044 Quartucciu (CA) +// ITALY +// www.tecnick.com +// info@tecnick.com +//============================================================+ + +/** + * Utility to generate font definition files fot TCPDF. + * @author Nicola Asuni, Olivier Plathey, Steven Wittens + * @copyright 2004-2009 Nicola Asuni - Tecnick.com S.r.l (www.tecnick.com) Via Della Pace, 11 - 09044 - Quartucciu (CA) - ITALY - www.tecnick.com - info@tecnick.com + * @package com.tecnick.tcpdf + * @link http://www.tcpdf.org + * @license http://www.gnu.org/copyleft/lesser.html LGPL +*/ + +/** + * + * @param string $fontfile path to font file (TTF, OTF or PFB). + * @param string $fmfile font metrics file (UFM or AFM). + * @param boolean $embedded Set to false to not embed the font, true otherwise (default). + * @param string $enc Name of the encoding table to use. Omit this parameter for TrueType Unicode, OpenType Unicode and symbolic fonts like Symbol or ZapfDingBats. + * @param array $patch Optional modification of the encoding + */ +function MakeFont($fontfile, $fmfile, $embedded=true, $enc='cp1252', $patch=array()/* BEGIN SUGARCRM SPECIFIC */, $cidInfo=""/* END SUGARCRM SPECIFIC */) { + //Generate a font definition file + set_magic_quotes_runtime(0); + ini_set('auto_detect_line_endings', '1'); + if (!file_exists($fontfile)) { + die('Error: file not found: '.$fontfile); + } + if (!file_exists($fmfile)) { + die('Error: file not found: '.$fmfile); + } + $cidtogidmap = ''; + $map = array(); + $diff = ''; + $dw = 0; // default width + $ffext = strtolower(substr($fontfile, -3)); + $fmext = strtolower(substr($fmfile, -3)); + if ($fmext == 'afm') { + if (($ffext == 'ttf') OR ($ffext == 'otf')) { + $type = 'TrueType'; + } elseif ($ffext == 'pfb') { + $type = 'Type1'; + } else { + die('Error: unrecognized font file extension: '.$ffext); + } + if ($enc) { + $map = ReadMap($enc); + foreach ($patch as $cc => $gn) { + $map[$cc] = $gn; + } + } + $fm = ReadAFM($fmfile, $map); + if (isset($widths['.notdef'])) { + $dw = $widths['.notdef']; + } + if ($enc) { + $diff = MakeFontEncoding($map); + } + $fd = MakeFontDescriptor($fm, empty($map)); + } elseif ($fmext == 'ufm') { + $enc = ''; + if (($ffext == 'ttf') OR ($ffext == 'otf')) { + $type = 'TrueTypeUnicode'; + } else { + die('Error: not a TrueType font: '.$ffext); + } + $fm = ReadUFM($fmfile, $cidtogidmap); + $dw = $fm['MissingWidth']; + $fd = MakeFontDescriptor($fm, false); + } + //Start generation + $s = ' 0)) { + // assign default space width + $dw = $fm['Widths'][32]; + } else { + $dw = 600; + } + } + // BEGIN SUGARCRM SPECIFIC + if($embedded){ + // END SUGARCRM SPECIFIC + $s .= '$dw='.$dw.";\n"; + // BEGIN SUGARCRM SPECIFIC + }else{ + $s .= '$dw='."1000;\n"; + } + // END SUGARCRM SPECIFIC + $w = MakeWidthArray($fm); + $s .= '$cw='.$w.";\n"; + // BEGIN SUGARCRM SPECIFIC + if($embedded){ + // END SUGARCRM SPECIFIC + $s .= '$enc=\''.$enc."';\n"; + // BEGIN SUGARCRM SPECIFIC + } + // END SUGARCRM SPECIFIC + $s .= '$diff=\''.$diff."';\n"; + $basename = substr(basename($fmfile), 0, -4); + // BEGIN SUGARCRM SPECIFIC + $dirname = dirname($fmfile); + // END SUGARCRM SPECIFIC + if ($embedded) { + //Embedded font + if (($type == 'TrueType') OR ($type == 'TrueTypeUnicode')) { + CheckTTF($fontfile); + } + $f = fopen($fontfile,'rb'); + if (!$f) { + die('Error: Unable to open '.$fontfile); + } + $file = stream_get_contents($f); + fclose($f); + if ($type == 'Type1') { + //Find first two sections and discard third one + $header = (ord($file{0}) == 128); + if ($header) { + //Strip first binary header + $file = substr($file, 6); + } + $pos = strpos($file, 'eexec'); + if (!$pos) { + die('Error: font file does not seem to be valid Type1'); + } + $size1 = $pos + 6; + if ($header AND (ord($file{$size1}) == 128)) { + //Strip second binary header + $file = substr($file, 0, $size1).substr($file, $size1+6); + } + $pos = strpos($file, '00000000'); + if (!$pos) { + die('Error: font file does not seem to be valid Type1'); + } + $size2 = $pos - $size1; + $file = substr($file, 0, ($size1 + $size2)); + } + $basename = strtolower($basename); + if (function_exists('gzcompress')) { + $cmp = $basename.'.z'; + // BEGIN SUGARCRM SPECIFIC + /* + // END SUGARCRM SPECIFIC + SaveToFile($cmp, gzcompress($file, 9), 'b'); + // BEGIN SUGARCRM SPECIFIC + */ + SaveToFile($dirname."/".$cmp, gzcompress($file, 9), 'b'); + // END SUGARCRM SPECIFIC + $s .= '$file=\''.$cmp."';\n"; + print "Font file compressed (".$cmp.")\n"; + if (!empty($cidtogidmap)) { + $cmp = $basename.'.ctg.z'; + // BEGIN SUGARCRM SPECIFIC + /* + // END SUGARCRM SPECIFIC + SaveToFile($cmp, gzcompress($cidtogidmap, 9), 'b'); + // BEGIN SUGARCRM SPECIFIC + */ + SaveToFile($dirname."/".$cmp, gzcompress($cidtogidmap, 9), 'b'); + // END SUGARCRM SPECIFIC + print "CIDToGIDMap created and compressed (".$cmp.")\n"; + $s .= '$ctg=\''.$cmp."';\n"; + } + } else { + $s .= '$file=\''.basename($fontfile)."';\n"; + print "Notice: font file could not be compressed (zlib extension not available)\n"; + if (!empty($cidtogidmap)) { + $cmp = $basename.'.ctg'; + // BEGIN SUGARCRM SPECIFIC + /* + // END SUGARCRM SPECIFIC + $f = fopen($cmp, 'wb'); + // BEGIN SUGARCRM SPECIFIC + */ + $f = fopen($dirname."/".$cmp, 'wb'); + // END SUGARCRM SPECIFIC + fwrite($f, $cidtogidmap); + fclose($f); + print "CIDToGIDMap created (".$cmp.")\n"; + $s .= '$ctg=\''.$cmp."';\n"; + } + } + if($type == 'Type1') { + $s .= '$size1='.$size1.";\n"; + $s .= '$size2='.$size2.";\n"; + } else { + $s.='$originalsize='.filesize($fontfile).";\n"; + } + } else { + //Not embedded font + // BEGIN SUGARCRM SPECIFIC + /* + // END SUGARCRM SPECIFIC + $s .= '$file='."'';\n"; + // BEGIN SUGARCRM SPECIFIC + */ + $s .= $cidInfo; + // END SUGARCRM SPECIFIC + } + $s .= "?>"; + // BEGIN SUGARCRM SPECIFIC + /* + // END SUGARCRM SPECIFIC + SaveToFile($basename.'.php',$s); + // BEGIN SUGARCRM SPECIFIC + */ + SaveToFile($dirname."/".$basename.'.php',$s); + // END SUGARCRM SPECIFIC + print "Font definition file generated (".$basename.".php)\n"; + // BEGIN SUGARCRM SPECIFIC + return $dirname."/".$basename; + // END SUGARCRM SPECIFIC +} + +/** + * Read the specified encoding map. + * @param string $enc map name (see /enc/ folder for valid names). + */ +function ReadMap($enc) { + //Read a map file + $file = dirname(__FILE__).'/enc/'.strtolower($enc).'.map'; + $a = file($file); + if (empty($a)) { + die('Error: encoding not found: '.$enc); + } + $cc2gn = array(); + foreach ($a as $l) { + if ($l{0} == '!') { + $e = preg_split('/[ \\t]+/',rtrim($l)); + $cc = hexdec(substr($e[0],1)); + $gn = $e[2]; + $cc2gn[$cc] = $gn; + } + } + for($i = 0; $i <= 255; $i++) { + if(!isset($cc2gn[$i])) { + $cc2gn[$i] = '.notdef'; + } + } + return $cc2gn; +} + +/** + * Read UFM file + */ +function ReadUFM($file, &$cidtogidmap) { + //Prepare empty CIDToGIDMap + $cidtogidmap = str_pad('', (256 * 256 * 2), "\x00"); + //Read a font metric file + $a = file($file); + if (empty($a)) { + die('File not found'); + } + $widths = array(); + $fm = array(); + foreach($a as $l) { + $e = explode(' ',chop($l)); + if(count($e) < 2) { + continue; + } + $code = $e[0]; + $param = $e[1]; + if($code == 'U') { + // U 827 ; WX 0 ; N squaresubnosp ; G 675 ; + //Character metrics + $cc = (int)$e[1]; + if ($cc != -1) { + $gn = $e[7]; + $w = $e[4]; + $glyph = $e[10]; + $widths[$cc] = $w; + if($cc == ord('X')) { + $fm['CapXHeight'] = $e[13]; + } + // Set GID + if (($cc >= 0) AND ($cc < 0xFFFF) AND $glyph) { + $cidtogidmap{($cc * 2)} = chr($glyph >> 8); + $cidtogidmap{(($cc * 2) + 1)} = chr($glyph & 0xFF); + } + } + if(($gn == '.notdef') AND (!isset($fm['MissingWidth']))) { + $fm['MissingWidth'] = $w; + } + } elseif($code == 'FontName') { + $fm['FontName'] = $param; + } elseif($code == 'Weight') { + $fm['Weight'] = $param; + } elseif($code == 'ItalicAngle') { + $fm['ItalicAngle'] = (double)$param; + } elseif($code == 'Ascender') { + $fm['Ascender'] = (int)$param; + } elseif($code == 'Descender') { + $fm['Descender'] = (int)$param; + } elseif($code == 'UnderlineThickness') { + $fm['UnderlineThickness'] = (int)$param; + } elseif($code == 'UnderlinePosition') { + $fm['UnderlinePosition'] = (int)$param; + } elseif($code == 'IsFixedPitch') { + $fm['IsFixedPitch'] = ($param == 'true'); + } elseif($code == 'FontBBox') { + $fm['FontBBox'] = array($e[1], $e[2], $e[3], $e[4]); + } elseif($code == 'CapHeight') { + $fm['CapHeight'] = (int)$param; + } elseif($code == 'StdVW') { + $fm['StdVW'] = (int)$param; + } + } + if(!isset($fm['MissingWidth'])) { + $fm['MissingWidth'] = 600; + } + if(!isset($fm['FontName'])) { + die('FontName not found'); + } + $fm['Widths'] = $widths; + return $fm; +} + +/** + * Read AFM file + */ +function ReadAFM($file,&$map) { + //Read a font metric file + $a = file($file); + if(empty($a)) { + die('File not found'); + } + $widths = array(); + $fm = array(); + $fix = array( + 'Edot'=>'Edotaccent', + 'edot'=>'edotaccent', + 'Idot'=>'Idotaccent', + 'Zdot'=>'Zdotaccent', + 'zdot'=>'zdotaccent', + 'Odblacute' => 'Ohungarumlaut', + 'odblacute' => 'ohungarumlaut', + 'Udblacute'=>'Uhungarumlaut', + 'udblacute'=>'uhungarumlaut', + 'Gcedilla'=>'Gcommaaccent' + ,'gcedilla'=>'gcommaaccent', + 'Kcedilla'=>'Kcommaaccent', + 'kcedilla'=>'kcommaaccent', + 'Lcedilla'=>'Lcommaaccent', + 'lcedilla'=>'lcommaaccent', + 'Ncedilla'=>'Ncommaaccent', + 'ncedilla'=>'ncommaaccent', + 'Rcedilla'=>'Rcommaaccent', + 'rcedilla'=>'rcommaaccent', + 'Scedilla'=>'Scommaaccent', + 'scedilla'=>'scommaaccent', + 'Tcedilla'=>'Tcommaaccent', + 'tcedilla'=>'tcommaaccent', + 'Dslash'=>'Dcroat', + 'dslash'=>'dcroat', + 'Dmacron'=>'Dcroat', + 'dmacron'=>'dcroat', + 'combininggraveaccent'=>'gravecomb', + 'combininghookabove'=>'hookabovecomb', + 'combiningtildeaccent'=>'tildecomb', + 'combiningacuteaccent'=>'acutecomb', + 'combiningdotbelow'=>'dotbelowcomb', + 'dongsign'=>'dong' + ); + foreach($a as $l) { + $e = explode(' ', rtrim($l)); + if (count($e) < 2) { + continue; + } + $code = $e[0]; + $param = $e[1]; + if ($code == 'C') { + //Character metrics + $cc = (int)$e[1]; + $w = $e[4]; + $gn = $e[7]; + if (substr($gn, -4) == '20AC') { + $gn = 'Euro'; + } + if (isset($fix[$gn])) { + //Fix incorrect glyph name + foreach ($map as $c => $n) { + if ($n == $fix[$gn]) { + $map[$c] = $gn; + } + } + } + if (empty($map)) { + //Symbolic font: use built-in encoding + $widths[$cc] = $w; + } else { + $widths[$gn] = $w; + if($gn == 'X') { + $fm['CapXHeight'] = $e[13]; + } + } + if($gn == '.notdef') { + $fm['MissingWidth'] = $w; + } + } elseif($code == 'FontName') { + $fm['FontName'] = $param; + } elseif($code == 'Weight') { + $fm['Weight'] = $param; + } elseif($code == 'ItalicAngle') { + $fm['ItalicAngle'] = (double)$param; + } elseif($code == 'Ascender') { + $fm['Ascender'] = (int)$param; + } elseif($code == 'Descender') { + $fm['Descender'] = (int)$param; + } elseif($code == 'UnderlineThickness') { + $fm['UnderlineThickness'] = (int)$param; + } elseif($code == 'UnderlinePosition') { + $fm['UnderlinePosition'] = (int)$param; + } elseif($code == 'IsFixedPitch') { + $fm['IsFixedPitch'] = ($param == 'true'); + } elseif($code == 'FontBBox') { + $fm['FontBBox'] = array($e[1], $e[2], $e[3], $e[4]); + } elseif($code == 'CapHeight') { + $fm['CapHeight'] = (int)$param; + } elseif($code == 'StdVW') { + $fm['StdVW'] = (int)$param; + } + } + if (!isset($fm['FontName'])) { + die('FontName not found'); + } + if (!empty($map)) { + if (!isset($widths['.notdef'])) { + $widths['.notdef'] = 600; + } + if (!isset($widths['Delta']) AND isset($widths['increment'])) { + $widths['Delta'] = $widths['increment']; + } + //Order widths according to map + for ($i = 0; $i <= 255; $i++) { + if (!isset($widths[$map[$i]])) { + print "Warning: character ".$map[$i]." is missing\n"; + $widths[$i] = $widths['.notdef']; + } else { + $widths[$i] = $widths[$map[$i]]; + } + } + } + $fm['Widths'] = $widths; + return $fm; +} + +function MakeFontDescriptor($fm, $symbolic=false) { + //Ascent + $asc = (isset($fm['Ascender']) ? $fm['Ascender'] : 1000); + $fd = "array('Ascent'=>".$asc; + //Descent + $desc = (isset($fm['Descender']) ? $fm['Descender'] : -200); + $fd .= ",'Descent'=>".$desc; + //CapHeight + if (isset($fm['CapHeight'])) { + $ch = $fm['CapHeight']; + } elseif (isset($fm['CapXHeight'])) { + $ch = $fm['CapXHeight']; + } else { + $ch = $asc; + } + $fd .= ",'CapHeight'=>".$ch; + //Flags + $flags = 0; + if (isset($fm['IsFixedPitch']) AND $fm['IsFixedPitch']) { + $flags += 1<<0; + } + if ($symbolic) { + $flags += 1<<2; + } else { + $flags += 1<<5; + } + if (isset($fm['ItalicAngle']) AND ($fm['ItalicAngle'] != 0)) { + $flags += 1<<6; + } + $fd .= ",'Flags'=>".$flags; + //FontBBox + if (isset($fm['FontBBox'])) { + $fbb = $fm['FontBBox']; + } else { + $fbb = array(0, ($desc - 100), 1000, ($asc + 100)); + } + $fd .= ",'FontBBox'=>'[".$fbb[0].' '.$fbb[1].' '.$fbb[2].' '.$fbb[3]."]'"; + //ItalicAngle + $ia = (isset($fm['ItalicAngle']) ? $fm['ItalicAngle'] : 0); + $fd .= ",'ItalicAngle'=>".$ia; + //StemV + if (isset($fm['StdVW'])) { + $stemv = $fm['StdVW']; + } elseif (isset($fm['Weight']) and eregi('(bold|black)', $fm['Weight'])) { + $stemv = 120; + } else { + $stemv = 70; + } + $fd .= ",'StemV'=>".$stemv; + //MissingWidth + if(isset($fm['MissingWidth'])) { + $fd .= ",'MissingWidth'=>".$fm['MissingWidth']; + } + $fd .= ')'; + return $fd; +} + +function MakeWidthArray($fm) { + //Make character width array + $s = 'array('; + $cw = $fm['Widths']; + $els = array(); + $c = 0; + foreach ($cw as $i => $w) { + if (is_numeric($i)) { + $els[] = (((($c++)%10) == 0) ? "\n" : '').$i.'=>'.$w; + } + } + $s .= implode(',', $els); + $s .= ')'; + return $s; +} + +function MakeFontEncoding($map) { + //Build differences from reference encoding + $ref = ReadMap('cp1252'); + $s = ''; + $last = 0; + for ($i = 32; $i <= 255; $i++) { + if ($map[$i] != $ref[$i]) { + if ($i != $last+1) { + $s .= $i.' '; + } + $last = $i; + $s .= '/'.$map[$i].' '; + } + } + return rtrim($s); +} + +function SaveToFile($file, $s, $mode='t') { + $f = fopen($file, 'w'.$mode); + if(!$f) { + die('Can\'t write to file '.$file); + } + fwrite($f, $s, strlen($s)); + fclose($f); +} + +function ReadShort($f) { + $a = unpack('n1n', fread($f, 2)); + return $a['n']; +} + +function ReadLong($f) { + $a = unpack('N1N', fread($f, 4)); + return $a['N']; +} + +function CheckTTF($file) { + //Check if font license allows embedding + $f = fopen($file, 'rb'); + if (!$f) { + die('Error: unable to open '.$file); + } + //Extract number of tables + fseek($f, 4, SEEK_CUR); + $nb = ReadShort($f); + fseek($f, 6, SEEK_CUR); + //Seek OS/2 table + $found = false; + for ($i = 0; $i < $nb; $i++) { + if (fread($f, 4) == 'OS/2') { + $found = true; + break; + } + fseek($f, 12, SEEK_CUR); + } + if (!$found) { + fclose($f); + return; + } + fseek($f, 4, SEEK_CUR); + $offset = ReadLong($f); + fseek($f, $offset, SEEK_SET); + //Extract fsType flags + fseek($f, 8, SEEK_CUR); + $fsType = ReadShort($f); + $rl = ($fsType & 0x02) != 0; + $pp = ($fsType & 0x04) != 0; + $e = ($fsType & 0x08) != 0; + fclose($f); + if($rl AND (!$pp) AND (!$e)) { + print "Warning: font license does not allow embedding\n"; + } +} +// BEGIN SUGARCRM SPECIFIC +/* +// END SUGARCRM SPECIFIC + +$arg = $GLOBALS['argv']; +if (count($arg) >= 3) { + ob_start(); + array_shift($arg); + if (sizeof($arg) == 3) { + $arg[3] = $arg[2]; + $arg[2] = true; + } else { + if (!isset($arg[2])) { + $arg[2] = true; + } + if (!isset($arg[3])) { + $arg[3] = 'cp1252'; + } + } + if (!isset($arg[4])) { + $arg[4] = array(); + } + MakeFont($arg[0], $arg[1], $arg[2], $arg[3], $arg[4]); + $t = ob_get_clean(); + print preg_replace('!!i', "\n", $t); +} else { + print "Usage: makefont.php \n"; +} + +// BEGIN SUGARCRM SPECIFIC +*/ +// END SUGARCRM SPECIFIC +?> diff --git a/include/tcpdf/htmlcolors.php b/include/tcpdf/htmlcolors.php new file mode 100644 index 00000000..1502879a --- /dev/null +++ b/include/tcpdf/htmlcolors.php @@ -0,0 +1,231 @@ +. +// +// See LICENSE.TXT file for more information. +// ---------------------------------------------------------------------------- +// +// Description : Array of WEB safe colors +// +// Author: Nicola Asuni +// +// (c) Copyright: +// Nicola Asuni +// Tecnick.com S.r.l. +// Via della Pace, 11 +// 09044 Quartucciu (CA) +// ITALY +// www.tecnick.com +// info@tecnick.com +//============================================================+ + +/** + * Array of WEB safe colors. + * @author Nicola Asuni + * @copyright 2004-2009 Nicola Asuni - Tecnick.com S.r.l (www.tecnick.com) Via Della Pace, 11 - 09044 - Quartucciu (CA) - ITALY - www.tecnick.com - info@tecnick.com + * @package com.tecnick.tcpdf + * @link http://www.tcpdf.org + * @license http://www.gnu.org/copyleft/lesser.html LGPL + * @since 2.9.000 (2008-03-26) +*/ + +/** + * Array of WEB safe colors + */ +global $webcolor; +$webcolor = array ( +'aliceblue' => 'f0f8ff', +'antiquewhite' => 'faebd7', +'aqua' => '00ffff', +'aquamarine' => '7fffd4', +'azure' => 'f0ffff', +'beige' => 'f5f5dc', +'bisque' => 'ffe4c4', +'black' => '000000', +'blanchedalmond' => 'ffebcd', +'blue' => '0000ff', +'blueviolet' => '8a2be2', +'brown' => 'a52a2a', +'burlywood' => 'deb887', +'cadetblue' => '5f9ea0', +'chartreuse' => '7fff00', +'chocolate' => 'd2691e', +'coral' => 'ff7f50', +'cornflowerblue' => '6495ed', +'cornsilk' => 'fff8dc', +'crimson' => 'dc143c', +'cyan' => '00ffff', +'darkblue' => '00008b', +'darkcyan' => '008b8b', +'darkgoldenrod' => 'b8860b', +'darkgray' => 'a9a9a9', +'darkgrey' => 'a9a9a9', +'darkgreen' => '006400', +'darkkhaki' => 'bdb76b', +'darkmagenta' => '8b008b', +'darkolivegreen' => '556b2f', +'darkorange' => 'ff8c00', +'darkorchid' => '9932cc', +'darkred' => '8b0000', +'darksalmon' => 'e9967a', +'darkseagreen' => '8fbc8f', +'darkslateblue' => '483d8b', +'darkslategray' => '2f4f4f', +'darkslategrey' => '2f4f4f', +'darkturquoise' => '00ced1', +'darkviolet' => '9400d3', +'deeppink' => 'ff1493', +'deepskyblue' => '00bfff', +'dimgray' => '696969', +'dimgrey' => '696969', +'dodgerblue' => '1e90ff', +'firebrick' => 'b22222', +'floralwhite' => 'fffaf0', +'forestgreen' => '228b22', +'fuchsia' => 'ff00ff', +'gainsboro' => 'dcdcdc', +'ghostwhite' => 'f8f8ff', +'gold' => 'ffd700', +'goldenrod' => 'daa520', +'gray' => '808080', +'grey' => '808080', +'green' => '008000', +'greenyellow' => 'adff2f', +'honeydew' => 'f0fff0', +'hotpink' => 'ff69b4', +'indianred ' => 'cd5c5c', +'indigo ' => '4b0082', +'ivory' => 'fffff0', +'khaki' => 'f0e68c', +'lavender' => 'e6e6fa', +'lavenderblush' => 'fff0f5', +'lawngreen' => '7cfc00', +'lemonchiffon' => 'fffacd', +'lightblue' => 'add8e6', +'lightcoral' => 'f08080', +'lightcyan' => 'e0ffff', +'lightgoldenrodyellow' => 'fafad2', +'lightgray' => 'd3d3d3', +'lightgrey' => 'd3d3d3', +'lightgreen' => '90ee90', +'lightpink' => 'ffb6c1', +'lightsalmon' => 'ffa07a', +'lightseagreen' => '20b2aa', +'lightskyblue' => '87cefa', +'lightslategray' => '778899', +'lightslategrey' => '778899', +'lightsteelblue' => 'b0c4de', +'lightyellow' => 'ffffe0', +'lime' => '00ff00', +'limegreen' => '32cd32', +'linen' => 'faf0e6', +'magenta' => 'ff00ff', +'maroon' => '800000', +'mediumaquamarine' => '66cdaa', +'mediumblue' => '0000cd', +'mediumorchid' => 'ba55d3', +'mediumpurple' => '9370d8', +'mediumseagreen' => '3cb371', +'mediumslateblue' => '7b68ee', +'mediumspringgreen' => '00fa9a', +'mediumturquoise' => '48d1cc', +'mediumvioletred' => 'c71585', +'midnightblue' => '191970', +'mintcream' => 'f5fffa', +'mistyrose' => 'ffe4e1', +'moccasin' => 'ffe4b5', +'navajowhite' => 'ffdead', +'navy' => '000080', +'oldlace' => 'fdf5e6', +'olive' => '808000', +'olivedrab' => '6b8e23', +'orange' => 'ffa500', +'orangered' => 'ff4500', +'orchid' => 'da70d6', +'palegoldenrod' => 'eee8aa', +'palegreen' => '98fb98', +'paleturquoise' => 'afeeee', +'palevioletred' => 'd87093', +'papayawhip' => 'ffefd5', +'peachpuff' => 'ffdab9', +'peru' => 'cd853f', +'pink' => 'ffc0cb', +'plum' => 'dda0dd', +'powderblue' => 'b0e0e6', +'purple' => '800080', +'red' => 'ff0000', +'rosybrown' => 'bc8f8f', +'royalblue' => '4169e1', +'saddlebrown' => '8b4513', +'salmon' => 'fa8072', +'sandybrown' => 'f4a460', +'seagreen' => '2e8b57', +'seashell' => 'fff5ee', +'sienna' => 'a0522d', +'silver' => 'c0c0c0', +'skyblue' => '87ceeb', +'slateblue' => '6a5acd', +'slategray' => '708090', +'slategrey' => '708090', +'snow' => 'fffafa', +'springgreen' => '00ff7f', +'steelblue' => '4682b4', +'tan' => 'd2b48c', +'teal' => '008080', +'thistle' => 'd8bfd8', +'tomato' => 'ff6347', +'turquoise' => '40e0d0', +'violet' => 'ee82ee', +'wheat' => 'f5deb3', +'white' => 'ffffff', +'whitesmoke' => 'f5f5f5', +'yellow' => 'ffff00', +'yellowgreen' => '9acd32' +); + +//============================================================+ +// END OF FILE +//============================================================+ +?> diff --git a/include/tcpdf/tcpdf.php b/include/tcpdf/tcpdf.php new file mode 100644 index 00000000..43cad714 --- /dev/null +++ b/include/tcpdf/tcpdf.php @@ -0,0 +1,13979 @@ + + Bug 39085 - When loading the opposite search panel via ajax on the ListViews, call the index action instead of the ListView action to avoid touching pre-MVC code by accident. + +r56990 - 2010-06-16 13:05:36 -0700 (Wed, 16 Jun 2010) - kjing - snapshot "Mango" svn branch to a new one for GitHub sync + +r56989 - 2010-06-16 13:01:33 -0700 (Wed, 16 Jun 2010) - kjing - defunt "Mango" svn dev branch before github cutover + +r55980 - 2010-04-19 13:31:28 -0700 (Mon, 19 Apr 2010) - kjing - create Mango (6.1) based on windex + +r53409 - 2010-01-03 19:31:15 -0800 (Sun, 03 Jan 2010) - roger - merge -r50376:HEAD from fuji_newtag_tmp + +r51719 - 2009-10-22 10:18:00 -0700 (Thu, 22 Oct 2009) - mitani - Converted to Build 3 tags and updated the build system + +r51634 - 2009-10-19 13:32:22 -0700 (Mon, 19 Oct 2009) - mitani - Windex is the branch for Sugar Sales 1.0 development + +r51443 - 2009-10-12 13:34:36 -0700 (Mon, 12 Oct 2009) - jmertic - Bug 33332 - Made application PHP 5.3 compliant with E_DEPRECATED warnings on by: +- Changing all ereg function to either preg or simple string based ones +- No more references to magic quotes. +- Change all the session_unregister() functions to just unset() the correct session variable instead. + +r50375 - 2009-08-24 18:07:43 -0700 (Mon, 24 Aug 2009) - dwong - branch kobe2 from tokyo r50372 + +r47904 - 2009-06-02 11:54:10 -0700 (Tue, 02 Jun 2009) - jenny - Adding changes that were made to the earlier version of this file to support jpg images. + +r47900 - 2009-06-02 11:26:55 -0700 (Tue, 02 Jun 2009) - jenny - Updating with changes from bsoufflet. + +r46662 - 2009-04-29 10:48:07 -0700 (Wed, 29 Apr 2009) - jenny - Invoking native jpg image support which isnt' automatically there. + +r46617 - 2009-04-28 16:08:45 -0700 (Tue, 28 Apr 2009) - jenny - Fixing a bug in TCPDF that checks to see if the GD library is installed. + +r46451 - 2009-04-23 16:57:40 -0700 (Thu, 23 Apr 2009) - jenny - tcpdf initial checkin. + + +*/ + + +//============================================================+ +// File name : tcpdf.php +// Begin : 2002-08-03 +// Last Update : 2009-05-28 +// Author : Nicola Asuni - info@tecnick.com - http://www.tcpdf.org +// Version : 4.6.013 +// License : GNU LGPL (http://www.gnu.org/copyleft/lesser.html) +// ---------------------------------------------------------------------------- +// Copyright (C) 2002-2009 Nicola Asuni - Tecnick.com S.r.l. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see . +// +// See LICENSE.TXT file for more information. +// ---------------------------------------------------------------------------- +// +// Description : This is a PHP class for generating PDF documents without +// requiring external extensions. +// +// NOTE: +// This class was originally derived in 2002 from the Public +// Domain FPDF class by Olivier Plathey (http://www.fpdf.org), +// but now is almost entirely rewritten. +// +// Main features: +// * no external libraries are required for the basic functions; +// * supports all ISO page formats; +// * supports custom page formats, margins and units of measure; +// * supports UTF-8 Unicode and Right-To-Left languages; +// * supports TrueTypeUnicode, OpenTypeUnicode, TrueType, OpenType, Type1 and CID-0 fonts; +// * supports document encryption; +// * includes methods to publish some XHTML code; +// * includes graphic (geometric) and transformation methods; +// * includes Javascript and forms support; +// * includes a method to print various barcode formats: CODE 39, ANSI MH10.8M-1983, USD-3, 3 of 9, CODE 93, USS-93, Standard 2 of 5, Interleaved 2 of 5, CODE 128 A/B/C, 2 and 5 Digits UPC-Based Extention, EAN 8, EAN 13, UPC-A, UPC-E, MSI, POSTNET, PLANET, RMS4CC (Royal Mail 4-state Customer Code), CBC (Customer Bar Code), KIX (Klant index - Customer index), Intelligent Mail Barcode, Onecode, USPS-B-3200, CODABAR, CODE 11, PHARMACODE, PHARMACODE TWO-TRACKS; +// * includes methods to set Bookmarks and print a Table of Content; +// * includes methods to move and delete pages; +// * includes methods for automatic page header and footer management; +// * supports automatic page break; +// * supports automatic page numbering and page groups; +// * supports automatic line break and text justification; +// * supports JPEG and PNG images natively, all images supported by GD (GD, GD2, GD2PART, GIF, JPEG, PNG, BMP, XBM, XPM) and all images supported via ImagMagick (http://www.imagemagick.org/www/formats.html) +// * supports stroke and clipping mode for text; +// * supports clipping masks; +// * supports Grayscale, RGB, CMYK, Spot Colors and Transparencies; +// * supports several annotations, including links, text and file attachments; +// * supports page compression (requires zlib extension); +// * supports text hyphenation. +// * supports transactions to UNDO commands. +// +// ----------------------------------------------------------- +// THANKS TO: +// +// Olivier Plathey (http://www.fpdf.org) for original FPDF. +// Efthimios Mavrogeorgiadis (emavro@yahoo.com) for suggestions on RTL language support. +// Klemen Vodopivec (http://www.fpdf.de/downloads/addons/37/) for Encryption algorithm. +// Warren Sherliker (wsherliker@gmail.com) for better image handling. +// dullus for text Justification. +// Bob Vincent (pillarsdotnet@users.sourceforge.net) for
  • value attribute. +// Patrick Benny for text stretch suggestion on Cell(). +// Johannes Güntert for JavaScript support. +// Denis Van Nuffelen for Dynamic Form. +// Jacek Czekaj for multibyte justification +// Anthony Ferrara for the reintroduction of legacy image methods. +// Sourceforge user 1707880 (hucste) for line-trough mode. +// Larry Stanbery for page groups. +// Martin Hall-May for transparency. +// Aaron C. Spike for Polycurve method. +// Mohamad Ali Golkar, Saleh AlMatrafe, Charles Abbott for Arabic and Persian support. +// Moritz Wagner and Andreas Wurmser for graphic functions. +// Andrew Whitehead for core fonts support. +// Esteban Joël Marín for OpenType font conversion. +// Teus Hagen for several suggestions and fixes. +// Yukihiro Nakadaira for CID-0 CJK fonts fixes. +// Kosmas Papachristos for some CSS improvements. +// Marcel Partap for some fixes. +// Won Kyu Park for several suggestions, fixes and patches. +// Anyone that has reported a bug or sent a suggestion. +//============================================================+ + +/** + * This is a PHP class for generating PDF documents without requiring external extensions.
    + * TCPDF project (http://www.tcpdf.org) was originally derived in 2002 from the Public Domain FPDF class by Olivier Plathey (http://www.fpdf.org), but now is almost entirely rewritten.
    + *

    TCPDF main features are:

    + *
      +*
    • no external libraries are required for the basic functions;
    • +*
    • supports all ISO page formats;
    • +*
    • supports custom page formats, margins and units of measure;
    • +*
    • supports UTF-8 Unicode and Right-To-Left languages;
    • +*
    • supports TrueTypeUnicode, OpenTypeUnicode, TrueType, OpenType, Type1 and CID-0 fonts;
    • +*
    • supports document encryption;
    • +*
    • includes methods to publish some XHTML code;
    • +*
    • includes graphic (geometric) and transformation methods;
    • +*
    • includes Javascript and forms support;
    • +*
    • includes a method to print various barcode formats: CODE 39, ANSI MH10.8M-1983, USD-3, 3 of 9, CODE 93, USS-93, Standard 2 of 5, Interleaved 2 of 5, CODE 128 A/B/C, 2 and 5 Digits UPC-Based Extention, EAN 8, EAN 13, UPC-A, UPC-E, MSI, POSTNET, PLANET, RMS4CC (Royal Mail 4-state Customer Code), CBC (Customer Bar Code), KIX (Klant index - Customer index), Intelligent Mail Barcode, Onecode, USPS-B-3200, CODABAR, CODE 11, PHARMACODE, PHARMACODE TWO-TRACKS;
    • +*
    • includes methods to set Bookmarks and print a Table of Content;
    • +*
    • includes methods to move and delete pages;
    • +*
    • includes methods for automatic page header and footer management;
    • +*
    • supports automatic page break;
    • +*
    • supports automatic page numbering and page groups;
    • +*
    • supports automatic line break and text justification;
    • +*
    • supports JPEG and PNG images natively, all images supported by GD (GD, GD2, GD2PART, GIF, JPEG, PNG, BMP, XBM, XPM) and all images supported via ImagMagick (http://www.imagemagick.org/www/formats.html)
    • +*
    • supports stroke and clipping mode for text;
    • +*
    • supports clipping masks;
    • +*
    • supports Grayscale, RGB, CMYK, Spot Colors and Transparencies;
    • +*
    • supports several annotations, including links, text and file attachments;
    • +*
    • supports page compression (requires zlib extension);
    • +*
    • supports text hyphenation.
    • +*
    • supports transactions to UNDO commands.
    • + *
    + * Tools to encode your unicode fonts are on fonts/utils directory.

    + * @package com.tecnick.tcpdf + * @abstract Class for generating PDF files on-the-fly without requiring external extensions. + * @author Nicola Asuni + * @copyright 2002-2009 Nicola Asuni - Tecnick.com S.r.l (www.tecnick.com) Via Della Pace, 11 - 09044 - Quartucciu (CA) - ITALY - www.tecnick.com - info@tecnick.com + * @link http://www.tcpdf.org + * @license http://www.gnu.org/copyleft/lesser.html LGPL + * @version 4.6.013 + */ + +/** + * main configuration file + */ +require_once(dirname(__FILE__).'/config/tcpdf_config.php'); + +// includes some support files + +/** + * unicode data + */ +require_once(dirname(__FILE__).'/unicode_data.php'); + +/** + * html colors table + */ +require_once(dirname(__FILE__).'/htmlcolors.php'); + +if (!class_exists('TCPDF', false)) { + /** + * define default PDF document producer + */ + define('PDF_PRODUCER', 'TCPDF 4.6.013 (http://www.tcpdf.org)'); + + /** + * This is a PHP class for generating PDF documents without requiring external extensions.
    + * TCPDF project (http://www.tcpdf.org) has been originally derived in 2002 from the Public Domain FPDF class by Olivier Plathey (http://www.fpdf.org), but now is almost entirely rewritten.
    + * @name TCPDF + * @package com.tecnick.tcpdf + * @version 4.6.013 + * @author Nicola Asuni - info@tecnick.com + * @link http://www.tcpdf.org + * @license http://www.gnu.org/copyleft/lesser.html LGPL + */ + class TCPDF { + + // protected or Protected properties + + /** + * @var current page number + * @access protected + */ + protected $page; + + /** + * @var current object number + * @access protected + */ + protected $n; + + /** + * @var array of object offsets + * @access protected + */ + protected $offsets; + + /** + * @var buffer holding in-memory PDF + * @access protected + */ + protected $buffer; + + /** + * @var array containing pages + * @access protected + */ + protected $pages = array(); + + /** + * @var current document state + * @access protected + */ + protected $state; + + /** + * @var compression flag + * @access protected + */ + protected $compress; + + /** + * @var current page orientation (P = Portrait, L = Landscape) + * @access protected + */ + protected $CurOrientation; + + /** + * @var array that stores page dimensions and graphic status.
    • $this->pagedim[$this->page]['w'] => page_width_in_points
    • $this->pagedim[$this->page]['h'] => height in points
    • $this->pagedim[$this->page]['wk'] => page_width_in_points
    • $this->pagedim[$this->page]['hk'] => height
    • $this->pagedim[$this->page]['tm'] => top_margin
    • $this->pagedim[$this->page]['bm'] => bottom_margin
    • $this->pagedim[$this->page]['lm'] => left_margin
    • $this->pagedim[$this->page]['rm'] => right_margin
    • $this->pagedim[$this->page]['pb'] => auto_page_break
    • $this->pagedim[$this->page]['or'] => page_orientation
    • $this->pagedim[$this->page]['olm'] => original_left_margin
    • $this->pagedim[$this->page]['orm'] => original_right_margin
    + * @access protected + */ + protected $pagedim = array(); + + /** + * @var scale factor (number of points in user unit) + * @access protected + */ + protected $k; + + /** + * @var width of page format in points + * @access protected + */ + protected $fwPt; + + /** + * @var height of page format in points + * @access protected + */ + protected $fhPt; + + /** + * @var current width of page in points + * @access protected + */ + protected $wPt; + + /** + * @var current height of page in points + * @access protected + */ + protected $hPt; + + /** + * @var current width of page in user unit + * @access protected + */ + protected $w; + + /** + * @var current height of page in user unit + * @access protected + */ + protected $h; + + /** + * @var left margin + * @access protected + */ + protected $lMargin; + + /** + * @var top margin + * @access protected + */ + protected $tMargin; + + /** + * @var right margin + * @access protected + */ + protected $rMargin; + + /** + * @var page break margin + * @access protected + */ + protected $bMargin; + + /** + * @var cell internal padding + * @access protected + */ + //protected + public $cMargin; + + /** + * @var cell internal padding (previous value) + * @access protected + */ + protected $oldcMargin; + + /** + * @var current horizontal position in user unit for cell positioning + * @access protected + */ + protected $x; + + /** + * @var current vertical position in user unit for cell positioning + * @access protected + */ + protected $y; + + /** + * @var height of last cell printed + * @access protected + */ + protected $lasth; + + /** + * @var line width in user unit + * @access protected + */ + protected $LineWidth; + + /** + * @var array of standard font names + * @access protected + */ + protected $CoreFonts; + + /** + * @var array of used fonts + * @access protected + */ + protected $fonts = array(); + + /** + * @var array of font files + * @access protected + */ + protected $FontFiles = array(); + + /** + * @var array of encoding differences + * @access protected + */ + protected $diffs = array(); + + /** + * @var array of used images + * @access protected + */ + protected $images = array(); + + /** + * @var array of Annotations in pages + * @access protected + */ + protected $PageAnnots = array(); + + /** + * @var array of internal links + * @access protected + */ + protected $links = array(); + + /** + * @var current font family + * @access protected + */ + protected $FontFamily; + + /** + * @var current font style + * @access protected + */ + protected $FontStyle; + + /** + * @var current font ascent (distance between font top and baseline) + * @access protected + * @since 2.8.000 (2007-03-29) + */ + protected $FontAscent; + + /** + * @var current font descent (distance between font bottom and baseline) + * @access protected + * @since 2.8.000 (2007-03-29) + */ + protected $FontDescent; + + /** + * @var underlining flag + * @access protected + */ + protected $underline; + + /** + * @var current font info + * @access protected + */ + protected $CurrentFont; + + /** + * @var current font size in points + * @access protected + */ + protected $FontSizePt; + + /** + * @var current font size in user unit + * @access protected + */ + protected $FontSize; + + /** + * @var commands for drawing color + * @access protected + */ + protected $DrawColor; + + /** + * @var commands for filling color + * @access protected + */ + protected $FillColor; + + /** + * @var commands for text color + * @access protected + */ + protected $TextColor; + + /** + * @var indicates whether fill and text colors are different + * @access protected + */ + protected $ColorFlag; + + /** + * @var automatic page breaking + * @access protected + */ + protected $AutoPageBreak; + + /** + * @var threshold used to trigger page breaks + * @access protected + */ + protected $PageBreakTrigger; + + /** + * @var flag set when processing footer + * @access protected + */ + protected $InFooter = false; + + /** + * @var zoom display mode + * @access protected + */ + protected $ZoomMode; + + /** + * @var layout display mode + * @access protected + */ + protected $LayoutMode; + + /** + * @var title + * @access protected + */ + protected $title = ''; + + /** + * @var subject + * @access protected + */ + protected $subject = ''; + + /** + * @var author + * @access protected + */ + protected $author = ''; + + /** + * @var keywords + * @access protected + */ + protected $keywords = ''; + + /** + * @var creator + * @access protected + */ + protected $creator = ''; + + /** + * @var alias for total number of pages + * @access protected + */ + protected $AliasNbPages = '{nb}'; + + /** + * @var alias for page number + * @access protected + */ + protected $AliasNumPage = '{pnb}'; + + /** + * @var right-bottom corner X coordinate of inserted image + * @since 2002-07-31 + * @author Nicola Asuni + * @access protected + */ + protected $img_rb_x; + + /** + * @var right-bottom corner Y coordinate of inserted image + * @since 2002-07-31 + * @author Nicola Asuni + * @access protected + */ + protected $img_rb_y; + + /** + * @var adjusting factor to convert pixels to user units. + * @since 2004-06-14 + * @author Nicola Asuni + * @access protected + */ + protected $imgscale = 1; + + /** + * @var boolean set to true when the input text is unicode (require unicode fonts) + * @since 2005-01-02 + * @author Nicola Asuni + * @access protected + */ + protected $isunicode = false; + + /** + * @var PDF version + * @since 1.5.3 + * @access protected + */ + protected $PDFVersion = '1.7'; + + + // ---------------------- + + /** + * @var Minimum distance between header and top page margin. + * @access protected + */ + protected $header_margin; + + /** + * @var Minimum distance between footer and bottom page margin. + * @access protected + */ + protected $footer_margin; + + /** + * @var original left margin value + * @access protected + * @since 1.53.0.TC013 + */ + protected $original_lMargin; + + /** + * @var original right margin value + * @access protected + * @since 1.53.0.TC013 + */ + protected $original_rMargin; + + /** + * @var Header font. + * @access protected + */ + protected $header_font; + + /** + * @var Footer font. + * @access protected + */ + protected $footer_font; + + /** + * @var Language templates. + * @access protected + */ + protected $l; + + /** + * @var Barcode to print on page footer (only if set). + * @access protected + */ + protected $barcode = false; + + /** + * @var If true prints header + * @access protected + */ + protected $print_header = true; + + /** + * @var If true prints footer. + * @access protected + */ + protected $print_footer = true; + + /** + * @var Header image logo. + * @access protected + */ + protected $header_logo = ''; + + /** + * @var Header image logo width in mm. + * @access protected + */ + protected $header_logo_width = 30; + + /** + * @var String to print as title on document header. + * @access protected + */ + protected $header_title = ''; + + /** + * @var String to print on document header. + * @access protected + */ + protected $header_string = ''; + + /** + * @var Default number of columns for html table. + * @access protected + */ + protected $default_table_columns = 4; + + + // variables for html parser + + /** + * @var HTML PARSER: array to store current link and rendering styles. + * @access protected + */ + protected $HREF = array(); + + /** + * @var store a list of available fonts on filesystem. + * @access protected + */ + protected $fontlist = array(); + + /** + * @var current foreground color + * @access protected + */ + protected $fgcolor; + + /** + * @var HTML PARSER: array of boolean values, true in case of ordered list (OL), false otherwise. + * @access protected + */ + protected $listordered = array(); + + /** + * @var HTML PARSER: array count list items on nested lists. + * @access protected + */ + protected $listcount = array(); + + /** + * @var HTML PARSER: current list nesting level. + * @access protected + */ + protected $listnum = 0; + + /** + * @var HTML PARSER: indent amount for lists. + * @access protected + */ + protected $listindent; + + /** + * @var current background color + * @access protected + */ + protected $bgcolor; + + /** + * @var Store temporary font size in points. + * @access protected + */ + protected $tempfontsize = 10; + + /** + * @var spacer for LI tags. + * @access protected + */ + protected $lispacer = ''; + + /** + * @var default encoding + * @access protected + * @since 1.53.0.TC010 + */ + protected $encoding = 'UTF-8'; + + /** + * @var PHP internal encoding + * @access protected + * @since 1.53.0.TC016 + */ + protected $internal_encoding; + + /** + * @var indicates if the document language is Right-To-Left + * @access protected + * @since 2.0.000 + */ + protected $rtl = false; + + /** + * @var used to force RTL or LTR string inversion + * @access protected + * @since 2.0.000 + */ + protected $tmprtl = false; + + // --- Variables used for document encryption: + + /** + * Indicates whether document is protected + * @access protected + * @since 2.0.000 (2008-01-02) + */ + protected $encrypted; + + /** + * U entry in pdf document + * @access protected + * @since 2.0.000 (2008-01-02) + */ + protected $Uvalue; + + /** + * O entry in pdf document + * @access protected + * @since 2.0.000 (2008-01-02) + */ + protected $Ovalue; + + /** + * P entry in pdf document + * @access protected + * @since 2.0.000 (2008-01-02) + */ + protected $Pvalue; + + /** + * encryption object id + * @access protected + * @since 2.0.000 (2008-01-02) + */ + protected $enc_obj_id; + + /** + * last RC4 key encrypted (cached for optimisation) + * @access protected + * @since 2.0.000 (2008-01-02) + */ + protected $last_rc4_key; + + /** + * last RC4 computed key + * @access protected + * @since 2.0.000 (2008-01-02) + */ + protected $last_rc4_key_c; + + /** + * RC4 padding + * @access protected + */ + protected $padding = "\x28\xBF\x4E\x5E\x4E\x75\x8A\x41\x64\x00\x4E\x56\xFF\xFA\x01\x08\x2E\x2E\x00\xB6\xD0\x68\x3E\x80\x2F\x0C\xA9\xFE\x64\x53\x69\x7A"; + + /** + * RC4 encryption key + * @access protected + */ + protected $encryption_key; + + // --- bookmark --- + + /** + * Outlines for bookmark + * @access protected + * @since 2.1.002 (2008-02-12) + */ + protected $outlines = array(); + + /** + * Outline root for bookmark + * @access protected + * @since 2.1.002 (2008-02-12) + */ + protected $OutlineRoot; + + + // --- javascript and form --- + + /** + * javascript code + * @access protected + * @since 2.1.002 (2008-02-12) + */ + protected $javascript = ''; + + /** + * javascript counter + * @access protected + * @since 2.1.002 (2008-02-12) + */ + protected $n_js; + + /** + * line trough state + * @access protected + * @since 2.8.000 (2008-03-19) + */ + protected $linethrough; + + // --- Variables used for User's Rights --- + // See PDF reference chapter 8.7 Digital Signatures + + /** + * If true enables user's rights on PDF reader + * @access protected + * @since 2.9.000 (2008-03-26) + */ + protected $ur; + + /** + * Names specifying additional document-wide usage rights for the document. + * @access protected + * @since 2.9.000 (2008-03-26) + */ + protected $ur_document; + + /** + * Names specifying additional annotation-related usage rights for the document. + * @access protected + * @since 2.9.000 (2008-03-26) + */ + protected $ur_annots; + + /** + * Names specifying additional form-field-related usage rights for the document. + * @access protected + * @since 2.9.000 (2008-03-26) + */ + protected $ur_form; + + /** + * Names specifying additional signature-related usage rights for the document. + * @access protected + * @since 2.9.000 (2008-03-26) + */ + protected $ur_signature; + + /** + * Dot Per Inch Document Resolution (do not change) + * @access protected + * @since 3.0.000 (2008-03-27) + */ + protected $dpi = 72; + + /** + * Array of page numbers were a new page group was started + * @access protected + * @since 3.0.000 (2008-03-27) + */ + protected $newpagegroup = array(); + + /** + * Contains the number of pages of the groups + * @access protected + * @since 3.0.000 (2008-03-27) + */ + protected $pagegroups; + + /** + * Contains the alias of the current page group + * @access protected + * @since 3.0.000 (2008-03-27) + */ + protected $currpagegroup; + + /** + * Restrict the rendering of some elements to screen or printout. + * @access protected + * @since 3.0.000 (2008-03-27) + */ + protected $visibility = 'all'; + + /** + * Print visibility. + * @access protected + * @since 3.0.000 (2008-03-27) + */ + protected $n_ocg_print; + + /** + * View visibility. + * @access protected + * @since 3.0.000 (2008-03-27) + */ + protected $n_ocg_view; + + /** + * Array of transparency objects and parameters. + * @access protected + * @since 3.0.000 (2008-03-27) + */ + protected $extgstates; + + /** + * Set the default JPEG compression quality (1-100) + * @access protected + * @since 3.0.000 (2008-03-27) + */ + protected $jpeg_quality; + + /** + * Default cell height ratio. + * @access protected + * @since 3.0.014 (2008-05-23) + */ + protected $cell_height_ratio = K_CELL_HEIGHT_RATIO; + + /** + * PDF viewer preferences. + * @access protected + * @since 3.1.000 (2008-06-09) + */ + protected $viewer_preferences; + + /** + * A name object specifying how the document should be displayed when opened. + * @access protected + * @since 3.1.000 (2008-06-09) + */ + protected $PageMode; + + /** + * Array for storing gradient information. + * @access protected + * @since 3.1.000 (2008-06-09) + */ + protected $gradients = array(); + + /** + * Array used to store positions inside the pages buffer. + * keys are the page numbers + * @access protected + * @since 3.2.000 (2008-06-26) + */ + protected $intmrk = array(); + + /** + * Array used to store footer positions of each page. + * @access protected + * @since 3.2.000 (2008-07-01) + */ + protected $footerpos = array(); + + + /** + * Array used to store footer lenght of each page. + * @access protected + * @since 4.0.014 (2008-07-29) + */ + protected $footerlen = array(); + + /** + * True if a newline is created. + * @access protected + * @since 3.2.000 (2008-07-01) + */ + protected $newline = true; + + /** + * End position of the latest inserted line + * @access protected + * @since 3.2.000 (2008-07-01) + */ + protected $endlinex = 0; + + /** + * PDF string for last line width + * @access protected + * @since 4.0.006 (2008-07-16) + */ + protected $linestyleWidth = ''; + + /** + * PDF string for last line width + * @access protected + * @since 4.0.006 (2008-07-16) + */ + protected $linestyleCap = '0 J'; + + /** + * PDF string for last line width + * @access protected + * @since 4.0.006 (2008-07-16) + */ + protected $linestyleJoin = '0 j'; + + /** + * PDF string for last line width + * @access protected + * @since 4.0.006 (2008-07-16) + */ + protected $linestyleDash = '[] 0 d'; + + /** + * True if marked-content sequence is open + * @access protected + * @since 4.0.013 (2008-07-28) + */ + protected $openMarkedContent = false; + + /** + * Count the latest inserted vertical spaces on HTML + * @access protected + * @since 4.0.021 (2008-08-24) + */ + protected $htmlvspace = 0; + + /** + * Array of Spot colors + * @access protected + * @since 4.0.024 (2008-09-12) + */ + protected $spot_colors = array(); + + /** + * Symbol used for HTML unordered list items + * @access protected + * @since 4.0.028 (2008-09-26) + */ + protected $lisymbol = ''; + + /** + * String used to mark the beginning and end of EPS image blocks + * @access protected + * @since 4.1.000 (2008-10-18) + */ + protected $epsmarker = 'x#!#EPS#!#x'; + + /** + * Array of transformation matrix + * @access protected + * @since 4.2.000 (2008-10-29) + */ + protected $transfmatrix = array(); + + /** + * Booklet mode for double-sided pages + * @access protected + * @since 4.2.000 (2008-10-29) + */ + protected $booklet = false; + + /** + * Epsilon value used for float calculations + * @access protected + * @since 4.2.000 (2008-10-29) + */ + protected $feps = 0.001; + + /** + * Array used for custom vertical spaces for HTML tags + * @access protected + * @since 4.2.001 (2008-10-30) + */ + protected $tagvspaces = array(); + + /** + * @var HTML PARSER: custom indent amount for lists. + * Negative value means disabled. + * @access protected + * @since 4.2.007 (2008-11-12) + */ + protected $customlistindent = -1; + + /** + * @var if true keeps the border open for the cell sides that cross the page. + * @access protected + * @since 4.2.010 (2008-11-14) + */ + protected $opencell = true; + + /** + * @var array of files to embedd + * @access protected + * @since 4.4.000 (2008-12-07) + */ + protected $embeddedfiles = array(); + + /** + * @var boolean true when inside html pre tag + * @access protected + * @since 4.4.001 (2008-12-08) + */ + protected $premode = false; + + /** + * Array used to store positions of graphics transformation blocks inside the page buffer. + * keys are the page numbers + * @access protected + * @since 4.4.002 (2008-12-09) + */ + protected $transfmrk = array(); + + /** + * Default color for html links + * @access protected + * @since 4.4.003 (2008-12-09) + */ + protected $htmlLinkColorArray = array(0, 0, 255); + + /** + * Default font style to add to html links + * @access protected + * @since 4.4.003 (2008-12-09) + */ + protected $htmlLinkFontStyle = 'U'; + + /** + * Counts the number of pages. + * @access protected + * @since 4.5.000 (2008-12-31) + */ + protected $numpages = 0; + + /** + * Array containing page lenghts in bytes. + * @access protected + * @since 4.5.000 (2008-12-31) + */ + protected $pagelen = array(); + + /** + * Counts the number of pages. + * @access protected + * @since 4.5.000 (2008-12-31) + */ + protected $numimages = 0; + + /** + * Store the image keys. + * @access protected + * @since 4.5.000 (2008-12-31) + */ + protected $imagekeys = array(); + + /** + * Lenght of the buffer in bytes. + * @access protected + * @since 4.5.000 (2008-12-31) + */ + protected $bufferlen = 0; + + /** + * If true enables disk caching. + * @access protected + * @since 4.5.000 (2008-12-31) + */ + protected $diskcache = false; + + /** + * Counts the number of fonts. + * @access protected + * @since 4.5.000 (2009-01-02) + */ + protected $numfonts = 0; + + /** + * Store the font keys. + * @access protected + * @since 4.5.000 (2009-01-02) + */ + protected $fontkeys = array(); + + /** + * Store the fage status (true when opened, false when closed). + * @access protected + * @since 4.5.000 (2009-01-02) + */ + protected $pageopen = array(); + + /** + * Default monospaced font + * @access protected + * @since 4.5.025 (2009-03-10) + */ + protected $default_monospaced_font = 'courier'; + + /** + * Used to store a cloned copy of the current class object + * @access protected + * @since 4.5.029 (2009-03-19) + */ + protected $objcopy; + + /** + * Array used to store the lenghts of cache files + * @access protected + * @since 4.5.029 (2009-03-19) + */ + protected $cache_file_lenght = array(); + + /** + * Table header content to be repeated on each new page + * @access protected + * @since 4.5.030 (2009-03-20) + */ + protected $thead = ''; + + /** + * Distance between the top of page and end of table headers on a new page. + * @access protected + * @since 4.5.030 (2009-03-20) + */ + protected $theadMargin = ''; + + /** + * Cache array for UTF8StringToArray() method. + * @access protected + * @since 4.5.037 (2009-04-07) + */ + protected $cache_UTF8StringToArray = array(); + + /** + * Maximum size of cache array used for UTF8StringToArray() method. + * @access protected + * @since 4.5.037 (2009-04-07) + */ + protected $cache_maxsize_UTF8StringToArray = 8; + + /** + * Current size of cache array used for UTF8StringToArray() method. + * @access protected + * @since 4.5.037 (2009-04-07) + */ + protected $cache_size_UTF8StringToArray = 0; + + /** + * If true enables document signing + * @access protected + * @since 4.6.005 (2009-04-24) + */ + protected $sign = false; + + /** + * Signature data + * @access protected + * @since 4.6.005 (2009-04-24) + */ + protected $signature_data = array(); + + /** + * Signature max lenght + * @access protected + * @since 4.6.005 (2009-04-24) + */ + protected $signature_max_lenght = 5120; + + /** + * Regular expression used to find blank characters used for word-wrapping. + * @access protected + * @since 4.6.006 (2009-04-28) + */ + protected $re_spaces = '/[\s\p{Z}\p{Lo}]/'; + + //------------------------------------------------------------ + // METHODS + //------------------------------------------------------------ + + /** + * This is the class constructor. + * It allows to set up the page format, the orientation and + * the measure unit used in all the methods (except for the font sizes). + * @since 1.0 + * @param string $orientation page orientation. Possible values are (case insensitive):
    • P or Portrait (default)
    • L or Landscape
    + * @param string $unit User measure unit. Possible values are:
    • pt: point
    • mm: millimeter (default)
    • cm: centimeter
    • in: inch

    A point equals 1/72 of inch, that is to say about 0.35 mm (an inch being 2.54 cm). This is a very common unit in typography; font sizes are expressed in that unit. + * @param mixed $format The format used for pages. It can be either one of the following values (case insensitive) or a custom format in the form of a two-element array containing the width and the height (expressed in the unit given by unit).
    • 4A0
    • 2A0
    • A0
    • A1
    • A2
    • A3
    • A4 (default)
    • A5
    • A6
    • A7
    • A8
    • A9
    • A10
    • B0
    • B1
    • B2
    • B3
    • B4
    • B5
    • B6
    • B7
    • B8
    • B9
    • B10
    • C0
    • C1
    • C2
    • C3
    • C4
    • C5
    • C6
    • C7
    • C8
    • C9
    • C10
    • RA0
    • RA1
    • RA2
    • RA3
    • RA4
    • SRA0
    • SRA1
    • SRA2
    • SRA3
    • SRA4
    • LETTER
    • LEGAL
    • EXECUTIVE
    • FOLIO
    + * @param boolean $unicode TRUE means that the input text is unicode (default = true) + * @param boolean $diskcache if TRUE reduce the RAM memory usage by caching temporary data on filesystem (slower). + * @param String $encoding charset encoding; default is UTF-8 + * @access public + */ + public function __construct($orientation='P', $unit='mm', $format='A4', $unicode=true, $encoding='UTF-8', $diskcache=false) { + /* Set internal character encoding to ASCII */ + if (function_exists('mb_internal_encoding') AND mb_internal_encoding()) { + $this->internal_encoding = mb_internal_encoding(); + mb_internal_encoding('ASCII'); + } + // set disk caching + $this->diskcache = $diskcache ? true : false; + // set language direction + $this->rtl = $this->l['a_meta_dir']=='rtl' ? true : false; + $this->tmprtl = false; + //Some checks + $this->_dochecks(); + //Initialization of properties + $this->isunicode = $unicode; + $this->page = 0; + $this->transfmrk[0] = array(); + $this->pagedim = array(); + $this->n = 2; + $this->buffer = ''; + $this->pages = array(); + $this->state = 0; + $this->fonts = array(); + $this->FontFiles = array(); + $this->diffs = array(); + $this->images = array(); + $this->links = array(); + $this->gradients = array(); + $this->InFooter = false; + $this->lasth = 0; + $this->FontFamily = 'helvetica'; + $this->FontStyle = ''; + $this->FontSizePt = 12; + $this->underline = false; + $this->linethrough = false; + $this->DrawColor = '0 G'; + $this->FillColor = '0 g'; + $this->TextColor = '0 g'; + $this->ColorFlag = false; + // encryption values + $this->encrypted = false; + $this->last_rc4_key = ''; + $this->padding = "\x28\xBF\x4E\x5E\x4E\x75\x8A\x41\x64\x00\x4E\x56\xFF\xFA\x01\x08\x2E\x2E\x00\xB6\xD0\x68\x3E\x80\x2F\x0C\xA9\xFE\x64\x53\x69\x7A"; + //Standard Unicode fonts + $this->CoreFonts = array( + 'courier'=>'Courier', + 'courierB'=>'Courier-Bold', + 'courierI'=>'Courier-Oblique', + 'courierBI'=>'Courier-BoldOblique', + 'helvetica'=>'Helvetica', + 'helveticaB'=>'Helvetica-Bold', + 'helveticaI'=>'Helvetica-Oblique', + 'helveticaBI'=>'Helvetica-BoldOblique', + 'times'=>'Times-Roman', + 'timesB'=>'Times-Bold', + 'timesI'=>'Times-Italic', + 'timesBI'=>'Times-BoldItalic', + 'symbol'=>'Symbol', + 'zapfdingbats'=>'ZapfDingbats' + ); + //Set scale factor + $this->setPageUnit($unit); + // set page format and orientation + $this->setPageFormat($format, $orientation); + //Page margins (1 cm) + $margin = 28.35 / $this->k; + $this->SetMargins($margin, $margin); + //Interior cell margin + $this->cMargin = $margin / 10; + //Line width (0.2 mm) + $this->LineWidth = 0.57 / $this->k; + $this->linestyleWidth = sprintf('%.2F w', ($this->LineWidth * $this->k)); + $this->linestyleCap = '0 J'; + $this->linestyleJoin = '0 j'; + $this->linestyleDash = '[] 0 d'; + //Automatic page break + $this->SetAutoPageBreak(true, (2 * $margin)); + //Full width display mode + $this->SetDisplayMode('fullwidth'); + //Compression + $this->SetCompression(true); + //Set default PDF version number + $this->PDFVersion = '1.7'; + $this->encoding = $encoding; + $this->HREF = array(); + $this->getFontsList(); + $this->fgcolor = array('R' => 0, 'G' => 0, 'B' => 0); + $this->bgcolor = array('R' => 255, 'G' => 255, 'B' => 255); + $this->extgstates = array(); + // user's rights + $this->sign = false; + $this->ur = false; + $this->ur_document = '/FullSave'; + $this->ur_annots = '/Create/Delete/Modify/Copy/Import/Export'; + $this->ur_form = '/Add/Delete/FillIn/Import/Export/SubmitStandalone/SpawnTemplate'; + $this->ur_signature = '/Modify'; + // set default JPEG quality + $this->jpeg_quality = 75; + // initialize some settings + $this->utf8Bidi(array(''), ''); + // set default font + $this->SetFont($this->FontFamily, $this->FontStyle, $this->FontSizePt); + // check if PCRE Unicode support is enabled + if (@preg_match('/\pL/u', 'a') == 1) { + // PCRE unicode support is turned ON + // \p{Z} or \p{Separator}: any kind of Unicode whitespace or invisible separator. + // \p{Lo} or \p{Other_Letter}: a Unicode letter or ideograph that does not have lowercase and uppercase variants. + // \p{Lo} is needed because Chinese characters are packed next to each other without spaces in between. + $this->re_spaces = '/[\s\p{Z}\p{Lo}]/'; + } else { + // PCRE unicode support is turned OFF + $this->re_spaces = '/[\s]/'; + } + } + + /** + * Default destructor. + * @access public + * @since 1.53.0.TC016 + */ + public function __destruct() { + // restore internal encoding + if (isset($this->internal_encoding) AND !empty($this->internal_encoding)) { + mb_internal_encoding($this->internal_encoding); + } + // unset all class variables + $this->_destroy(true); + } + + /** + * Set the units of measure for the document. + * @param string $unit User measure unit. Possible values are:
    • pt: point
    • mm: millimeter (default)
    • cm: centimeter
    • in: inch

    A point equals 1/72 of inch, that is to say about 0.35 mm (an inch being 2.54 cm). This is a very common unit in typography; font sizes are expressed in that unit. + * @access public + * @since 3.0.015 (2008-06-06) + */ + public function setPageUnit($unit) { + //Set scale factor + switch (strtolower($unit)) { + // points + case 'px': + case 'pt': { + $this->k = 1; + break; + } + // millimeters + case 'mm': { + $this->k = $this->dpi / 25.4; + break; + } + // centimeters + case 'cm': { + $this->k = $this->dpi / 2.54; + break; + } + // inches + case 'in': { + $this->k = $this->dpi; + break; + } + // unsupported unit + default : { + $this->Error('Incorrect unit: '.$unit); + break; + } + } + if (isset($this->CurOrientation)) { + $this->setPageOrientation($this->CurOrientation); + } + } + + /** + * Set the page format + * @param mixed $format The format used for pages. It can be either one of the following values (case insensitive) or a custom format in the form of a two-element array containing the width and the height (expressed in the unit given by unit).
    • 4A0
    • 2A0
    • A0
    • A1
    • A2
    • A3
    • A4 (default)
    • A5
    • A6
    • A7
    • A8
    • A9
    • A10
    • B0
    • B1
    • B2
    • B3
    • B4
    • B5
    • B6
    • B7
    • B8
    • B9
    • B10
    • C0
    • C1
    • C2
    • C3
    • C4
    • C5
    • C6
    • C7
    • C8
    • C9
    • C10
    • RA0
    • RA1
    • RA2
    • RA3
    • RA4
    • SRA0
    • SRA1
    • SRA2
    • SRA3
    • SRA4
    • LETTER
    • LEGAL
    • EXECUTIVE
    • FOLIO
    + * @param string $orientation page orientation. Possible values are (case insensitive):
    • P or PORTRAIT (default)
    • L or LANDSCAPE
    + * @access public + * @since 3.0.015 (2008-06-06) + */ + public function setPageFormat($format, $orientation='P') { + //Page format + if (is_string($format)) { + // Page formats (45 standard ISO paper formats and 4 american common formats). + // Paper cordinates are calculated in this way: (inches * 72) where (1 inch = 2.54 cm) + switch (strtoupper($format)) { + case '4A0': {$format = array(4767.87,6740.79); break;} + case '2A0': {$format = array(3370.39,4767.87); break;} + case 'A0': {$format = array(2383.94,3370.39); break;} + case 'A1': {$format = array(1683.78,2383.94); break;} + case 'A2': {$format = array(1190.55,1683.78); break;} + case 'A3': {$format = array(841.89,1190.55); break;} + case 'A4': default: {$format = array(595.28,841.89); break;} + case 'A5': {$format = array(419.53,595.28); break;} + case 'A6': {$format = array(297.64,419.53); break;} + case 'A7': {$format = array(209.76,297.64); break;} + case 'A8': {$format = array(147.40,209.76); break;} + case 'A9': {$format = array(104.88,147.40); break;} + case 'A10': {$format = array(73.70,104.88); break;} + case 'B0': {$format = array(2834.65,4008.19); break;} + case 'B1': {$format = array(2004.09,2834.65); break;} + case 'B2': {$format = array(1417.32,2004.09); break;} + case 'B3': {$format = array(1000.63,1417.32); break;} + case 'B4': {$format = array(708.66,1000.63); break;} + case 'B5': {$format = array(498.90,708.66); break;} + case 'B6': {$format = array(354.33,498.90); break;} + case 'B7': {$format = array(249.45,354.33); break;} + case 'B8': {$format = array(175.75,249.45); break;} + case 'B9': {$format = array(124.72,175.75); break;} + case 'B10': {$format = array(87.87,124.72); break;} + case 'C0': {$format = array(2599.37,3676.54); break;} + case 'C1': {$format = array(1836.85,2599.37); break;} + case 'C2': {$format = array(1298.27,1836.85); break;} + case 'C3': {$format = array(918.43,1298.27); break;} + case 'C4': {$format = array(649.13,918.43); break;} + case 'C5': {$format = array(459.21,649.13); break;} + case 'C6': {$format = array(323.15,459.21); break;} + case 'C7': {$format = array(229.61,323.15); break;} + case 'C8': {$format = array(161.57,229.61); break;} + case 'C9': {$format = array(113.39,161.57); break;} + case 'C10': {$format = array(79.37,113.39); break;} + case 'RA0': {$format = array(2437.80,3458.27); break;} + case 'RA1': {$format = array(1729.13,2437.80); break;} + case 'RA2': {$format = array(1218.90,1729.13); break;} + case 'RA3': {$format = array(864.57,1218.90); break;} + case 'RA4': {$format = array(609.45,864.57); break;} + case 'SRA0': {$format = array(2551.18,3628.35); break;} + case 'SRA1': {$format = array(1814.17,2551.18); break;} + case 'SRA2': {$format = array(1275.59,1814.17); break;} + case 'SRA3': {$format = array(907.09,1275.59); break;} + case 'SRA4': {$format = array(637.80,907.09); break;} + case 'LETTER': {$format = array(612.00,792.00); break;} + case 'LEGAL': {$format = array(612.00,1008.00); break;} + case 'EXECUTIVE': {$format = array(521.86,756.00); break;} + case 'FOLIO': {$format = array(612.00,936.00); break;} + } + $this->fwPt = $format[0]; + $this->fhPt = $format[1]; + } else { + $this->fwPt = $format[0] * $this->k; + $this->fhPt = $format[1] * $this->k; + } + $this->setPageOrientation($orientation); + } + + /** + * Set page orientation. + * @param string $orientation page orientation. Possible values are (case insensitive):
    • P or PORTRAIT (default)
    • L or LANDSCAPE
    + * @param boolean $autopagebreak Boolean indicating if auto-page-break mode should be on or off. + * @param float $bottommargin bottom margin of the page. + * @access public + * @since 3.0.015 (2008-06-06) + */ + public function setPageOrientation($orientation, $autopagebreak='', $bottommargin='') { + $orientation = strtoupper($orientation); + if (($orientation == 'P') OR ($orientation == 'PORTRAIT')) { + $this->CurOrientation = 'P'; + $this->wPt = $this->fwPt; + $this->hPt = $this->fhPt; + } elseif (($orientation == 'L') OR ($orientation == 'LANDSCAPE')) { + $this->CurOrientation = 'L'; + $this->wPt = $this->fhPt; + $this->hPt = $this->fwPt; + } else { + $this->Error('Incorrect orientation: '.$orientation); + } + $this->w = $this->wPt / $this->k; + $this->h = $this->hPt / $this->k; + if ($this->empty_string($autopagebreak)) { + if (isset($this->AutoPageBreak)) { + $autopagebreak = $this->AutoPageBreak; + } else { + $autopagebreak = true; + } + } + if ($this->empty_string($bottommargin)) { + if (isset($this->bMargin)) { + $bottommargin = $this->bMargin; + } else { + // default value = 2 cm + $bottommargin = 2 * 28.35 / $this->k; + } + } + $this->SetAutoPageBreak($autopagebreak, $bottommargin); + // store page dimensions + $this->pagedim[$this->page] = array('w' => $this->wPt, 'h' => $this->hPt, 'wk' => $this->w, 'hk' => $this->h, 'tm' => $this->tMargin, 'bm' => $bottommargin, 'lm' => $this->lMargin, 'rm' => $this->rMargin, 'pb' => $autopagebreak, 'or' => $this->CurOrientation, 'olm' => $this->original_lMargin, 'orm' => $this->original_rMargin); + } + + /** + * Enable or disable Right-To-Left language mode + * @param Boolean $enable if true enable Right-To-Left language mode. + * @access public + * @since 2.0.000 (2008-01-03) + */ + public function setRTL($enable) { + $this->rtl = $enable ? true : false; + $this->tmprtl = false; + } + + /** + * Return the RTL status + * @return boolean + * @access public + * @since 4.0.012 (2008-07-24) + */ + public function getRTL() { + return $this->rtl; + } + + /** + * Force temporary RTL language direction + * @param mixed $mode can be false, 'L' for LTR or 'R' for RTL + * @access public + * @since 2.1.000 (2008-01-09) + */ + public function setTempRTL($mode) { + switch ($mode) { + case false: + case 'L': + case 'R': { + $this->tmprtl = $mode; + } + } + } + + /** + * Set the last cell height. + * @param float $h cell height. + * @author Nicola Asuni + * @access public + * @since 1.53.0.TC034 + */ + public function setLastH($h) { + $this->lasth = $h; + } + + /** + * Get the last cell height. + * @return last cell height + * @access public + * @since 4.0.017 (2008-08-05) + */ + public function getLastH() { + return $this->lasth; + } + + /** + * Set the adjusting factor to convert pixels to user units. + * @param float $scale adjusting factor to convert pixels to user units. + * @author Nicola Asuni + * @access public + * @since 1.5.2 + */ + public function setImageScale($scale) { + $this->imgscale = $scale; + } + + /** + * Returns the adjusting factor to convert pixels to user units. + * @return float adjusting factor to convert pixels to user units. + * @author Nicola Asuni + * @access public + * @since 1.5.2 + */ + public function getImageScale() { + return $this->imgscale; + } + + /** + * Returns an array of page dimensions: + *
    • $this->pagedim[$this->page]['w'] => page_width_in_points
    • $this->pagedim[$this->page]['h'] => height in points
    • $this->pagedim[$this->page]['wk'] => page_width_in_points
    • $this->pagedim[$this->page]['hk'] => height
    • $this->pagedim[$this->page]['tm'] => top_margin
    • $this->pagedim[$this->page]['bm'] => bottom_margin
    • $this->pagedim[$this->page]['lm'] => left_margin
    • $this->pagedim[$this->page]['rm'] => right_margin
    • $this->pagedim[$this->page]['pb'] => auto_page_break
    • $this->pagedim[$this->page]['or'] => page_orientation
    • $this->pagedim[$this->page]['olm'] => original_left_margin
    • $this->pagedim[$this->page]['orm'] => original_right_margin
    + * @param int $pagenum page number (empty = current page) + * @return array of page dimensions. + * @author Nicola Asuni + * @access public + * @since 4.5.027 (2009-03-16) + */ + public function getPageDimensions($pagenum='') { + if (empty($pagenum)) { + $pagenum = $this->page; + } + return $this->pagedim[$pagenum]; + } + + /** + * Returns the page width in units. + * @param int $pagenum page number (empty = current page) + * @return int page width. + * @author Nicola Asuni + * @access public + * @since 1.5.2 + * @see getPageDimensions() + */ + public function getPageWidth($pagenum='') { + if (empty($pagenum)) { + return $this->w; + } + return $this->pagedim[$pagenum]['w']; + } + + /** + * Returns the page height in units. + * @param int $pagenum page number (empty = current page) + * @return int page height. + * @author Nicola Asuni + * @access public + * @since 1.5.2 + * @see getPageDimensions() + */ + public function getPageHeight($pagenum='') { + if (empty($pagenum)) { + return $this->h; + } + return $this->pagedim[$pagenum]['h']; + } + + /** + * Returns the page break margin. + * @param int $pagenum page number (empty = current page) + * @return int page break margin. + * @author Nicola Asuni + * @access public + * @since 1.5.2 + * @see getPageDimensions() + */ + public function getBreakMargin($pagenum='') { + if (empty($pagenum)) { + return $this->bMargin; + } + return $this->pagedim[$pagenum]['bm']; + } + + /** + * Returns the scale factor (number of points in user unit). + * @return int scale factor. + * @author Nicola Asuni + * @access public + * @since 1.5.2 + */ + public function getScaleFactor() { + return $this->k; + } + + /** + * Defines the left, top and right margins. By default, they equal 1 cm. Call this method to change them. + * @param float $left Left margin. + * @param float $top Top margin. + * @param float $right Right margin. Default value is the left one. + * @access public + * @since 1.0 + * @see SetLeftMargin(), SetTopMargin(), SetRightMargin(), SetAutoPageBreak() + */ + public function SetMargins($left, $top, $right=-1) { + //Set left, top and right margins + $this->lMargin = $left; + $this->tMargin = $top; + if ($right == -1) { + $right = $left; + } + $this->rMargin = $right; + } + + /** + * Defines the left margin. The method can be called before creating the first page. If the current abscissa gets out of page, it is brought back to the margin. + * @param float $margin The margin. + * @access public + * @since 1.4 + * @see SetTopMargin(), SetRightMargin(), SetAutoPageBreak(), SetMargins() + */ + public function SetLeftMargin($margin) { + //Set left margin + $this->lMargin=$margin; + if (($this->page > 0) AND ($this->x < $margin)) { + $this->x = $margin; + } + } + + /** + * Defines the top margin. The method can be called before creating the first page. + * @param float $margin The margin. + * @access public + * @since 1.5 + * @see SetLeftMargin(), SetRightMargin(), SetAutoPageBreak(), SetMargins() + */ + public function SetTopMargin($margin) { + //Set top margin + $this->tMargin=$margin; + if (($this->page > 0) AND ($this->y < $margin)) { + $this->y = $margin; + } + } + + /** + * Defines the right margin. The method can be called before creating the first page. + * @param float $margin The margin. + * @access public + * @since 1.5 + * @see SetLeftMargin(), SetTopMargin(), SetAutoPageBreak(), SetMargins() + */ + public function SetRightMargin($margin) { + $this->rMargin=$margin; + if (($this->page > 0) AND ($this->x > ($this->w - $margin))) { + $this->x = $this->w - $margin; + } + } + + /** + * Set the internal Cell padding. + * @param float $pad internal padding. + * @access public + * @since 2.1.000 (2008-01-09) + * @see Cell(), SetLeftMargin(), SetTopMargin(), SetAutoPageBreak(), SetMargins() + */ + public function SetCellPadding($pad) { + $this->cMargin = $pad; + } + + /** + * Enables or disables the automatic page breaking mode. When enabling, the second parameter is the distance from the bottom of the page that defines the triggering limit. By default, the mode is on and the margin is 2 cm. + * @param boolean $auto Boolean indicating if mode should be on or off. + * @param float $margin Distance from the bottom of the page. + * @access public + * @since 1.0 + * @see Cell(), MultiCell(), AcceptPageBreak() + */ + public function SetAutoPageBreak($auto, $margin=0) { + //Set auto page break mode and triggering margin + $this->AutoPageBreak = $auto; + $this->bMargin = $margin; + $this->PageBreakTrigger = $this->h - $margin; + } + + /** + * Defines the way the document is to be displayed by the viewer. + * @param mixed $zoom The zoom to use. It can be one of the following string values or a number indicating the zooming factor to use.
    • fullpage: displays the entire page on screen
    • fullwidth: uses maximum width of window
    • real: uses real size (equivalent to 100% zoom)
    • default: uses viewer default mode
    + * @param string $layout The page layout. Possible values are:
    • SinglePage Display one page at a time
    • OneColumn Display the pages in one column
    • TwoColumnLeft Display the pages in two columns, with odd-numbered pages on the left
    • TwoColumnRight Display the pages in two columns, with odd-numbered pages on the right
    • TwoPageLeft (PDF 1.5) Display the pages two at a time, with odd-numbered pages on the left
    • TwoPageRight (PDF 1.5) Display the pages two at a time, with odd-numbered pages on the right
    + * @param string $mode A name object specifying how the document should be displayed when opened:
    • UseNone Neither document outline nor thumbnail images visible
    • UseOutlines Document outline visible
    • UseThumbs Thumbnail images visible
    • FullScreen Full-screen mode, with no menu bar, window controls, or any other window visible
    • UseOC (PDF 1.5) Optional content group panel visible
    • UseAttachments (PDF 1.6) Attachments panel visible
    + * @access public + * @since 1.2 + */ + public function SetDisplayMode($zoom, $layout='SinglePage', $mode='UseNone') { + //Set display mode in viewer + if (($zoom == 'fullpage') OR ($zoom == 'fullwidth') OR ($zoom == 'real') OR ($zoom == 'default') OR (!is_string($zoom))) { + $this->ZoomMode = $zoom; + } else { + $this->Error('Incorrect zoom display mode: '.$zoom); + } + switch ($layout) { + case 'default': + case 'single': + case 'SinglePage': { + $this->LayoutMode = 'SinglePage'; + break; + } + case 'continuous': + case 'OneColumn': { + $this->LayoutMode = 'OneColumn'; + break; + } + case 'two': + case 'TwoColumnLeft': { + $this->LayoutMode = 'TwoColumnLeft'; + break; + } + case 'TwoColumnRight': { + $this->LayoutMode = 'TwoColumnRight'; + break; + } + case 'TwoPageLeft': { + $this->LayoutMode = 'TwoPageLeft'; + break; + } + case 'TwoPageRight': { + $this->LayoutMode = 'TwoPageRight'; + break; + } + default: { + $this->LayoutMode = 'SinglePage'; + } + } + switch ($mode) { + case 'UseNone': { + $this->PageMode = 'UseNone'; + break; + } + case 'UseOutlines': { + $this->PageMode = 'UseOutlines'; + break; + } + case 'UseThumbs': { + $this->PageMode = 'UseThumbs'; + break; + } + case 'FullScreen': { + $this->PageMode = 'FullScreen'; + break; + } + case 'UseOC': { + $this->PageMode = 'UseOC'; + break; + } + case '': { + $this->PageMode = 'UseAttachments'; + break; + } + default: { + $this->PageMode = 'UseNone'; + } + } + } + + /** + * Activates or deactivates page compression. When activated, the internal representation of each page is compressed, which leads to a compression ratio of about 2 for the resulting document. Compression is on by default. + * Note: the Zlib extension is required for this feature. If not present, compression will be turned off. + * @param boolean $compress Boolean indicating if compression must be enabled. + * @access public + * @since 1.4 + */ + public function SetCompression($compress) { + //Set page compression + if (function_exists('gzcompress')) { + $this->compress = $compress; + } else { + $this->compress = false; + } + } + + /** + * Defines the title of the document. + * @param string $title The title. + * @access public + * @since 1.2 + * @see SetAuthor(), SetCreator(), SetKeywords(), SetSubject() + */ + public function SetTitle($title) { + //Title of document + $this->title = $title; + } + + /** + * Defines the subject of the document. + * @param string $subject The subject. + * @access public + * @since 1.2 + * @see SetAuthor(), SetCreator(), SetKeywords(), SetTitle() + */ + public function SetSubject($subject) { + //Subject of document + $this->subject = $subject; + } + + /** + * Defines the author of the document. + * @param string $author The name of the author. + * @access public + * @since 1.2 + * @see SetCreator(), SetKeywords(), SetSubject(), SetTitle() + */ + public function SetAuthor($author) { + //Author of document + $this->author = $author; + } + + /** + * Associates keywords with the document, generally in the form 'keyword1 keyword2 ...'. + * @param string $keywords The list of keywords. + * @access public + * @since 1.2 + * @see SetAuthor(), SetCreator(), SetSubject(), SetTitle() + */ + public function SetKeywords($keywords) { + //Keywords of document + $this->keywords = $keywords; + } + + /** + * Defines the creator of the document. This is typically the name of the application that generates the PDF. + * @param string $creator The name of the creator. + * @access public + * @since 1.2 + * @see SetAuthor(), SetKeywords(), SetSubject(), SetTitle() + */ + public function SetCreator($creator) { + //Creator of document + $this->creator = $creator; + } + + /** + * This method is automatically called in case of fatal error; it simply outputs the message and halts the execution. An inherited class may override it to customize the error handling but should always halt the script, or the resulting document would probably be invalid. + * 2004-06-11 :: Nicola Asuni : changed bold tag with strong + * @param string $msg The error message + * @access public + * @since 1.0 + */ + public function Error($msg) { + // unset all class variables + $this->_destroy(true); + // exit program and print error + die('TCPDF ERROR: '.$msg); + } + + /** + * This method begins the generation of the PDF document. + * It is not necessary to call it explicitly because AddPage() does it automatically. + * Note: no page is created by this method + * @access public + * @since 1.0 + * @see AddPage(), Close() + */ + public function Open() { + //Begin document + $this->state = 1; + } + + /** + * Terminates the PDF document. + * It is not necessary to call this method explicitly because Output() does it automatically. + * If the document contains no page, AddPage() is called to prevent from getting an invalid document. + * @access public + * @since 1.0 + * @see Open(), Output() + */ + public function Close() { + if ($this->state == 3) { + return; + } + if ($this->page == 0) { + $this->AddPage(); + } + // close page + $this->endPage(); + // close document + $this->_enddoc(); + // unset all class variables (except critical ones) + $this->_destroy(false); + } + + /** + * Move pointer at the specified document page and update page dimensions. + * @param int $pnum page number + * @param boolean $resetmargins if true reset left, right, top margins and Y position. + * @access public + * @since 2.1.000 (2008-01-07) + * @see getPage(), lastpage(), getNumPages() + */ + public function setPage($pnum, $resetmargins=false) { + if ($pnum == $this->page) { + return; + } + if (($pnum > 0) AND ($pnum <= $this->numpages)) { + $this->state = 2; + // save current graphic settings + //$gvars = $this->getGraphicVars(); + $oldpage = $this->page; + $this->page = $pnum; + $this->wPt = $this->pagedim[$this->page]['w']; + $this->hPt = $this->pagedim[$this->page]['h']; + $this->w = $this->wPt / $this->k; + $this->h = $this->hPt / $this->k; + $this->tMargin = $this->pagedim[$this->page]['tm']; + $this->bMargin = $this->pagedim[$this->page]['bm']; + $this->original_lMargin = $this->pagedim[$this->page]['olm']; + $this->original_rMargin = $this->pagedim[$this->page]['orm']; + $this->AutoPageBreak = $this->pagedim[$this->page]['pb']; + $this->CurOrientation = $this->pagedim[$this->page]['or']; + $this->SetAutoPageBreak($this->AutoPageBreak, $this->bMargin); + // restore graphic settings + //$this->setGraphicVars($gvars); + if ($resetmargins) { + $this->lMargin = $this->pagedim[$this->page]['olm']; + $this->rMargin = $this->pagedim[$this->page]['orm']; + $this->SetY($this->tMargin); + } else { + // account for booklet mode + if ($this->pagedim[$this->page]['olm'] != $this->pagedim[$oldpage]['olm']) { + $deltam = $this->pagedim[$this->page]['olm'] - $this->pagedim[$this->page]['orm']; + $this->lMargin += $deltam; + $this->rMargin -= $deltam; + } + } + } else { + $this->Error('Wrong page number on setPage() function.'); + } + } + + /** + * Reset pointer to the last document page. + * @param boolean $resetmargins if true reset left, right, top margins and Y position. + * @access public + * @since 2.0.000 (2008-01-04) + * @see setPage(), getPage(), getNumPages() + */ + public function lastPage($resetmargins=false) { + $this->setPage($this->getNumPages(), $resetmargins); + } + + /** + * Get current document page number. + * @return int page number + * @access public + * @since 2.1.000 (2008-01-07) + * @see setPage(), lastpage(), getNumPages() + */ + public function getPage() { + return $this->page; + } + + + /** + * Get the total number of insered pages. + * @return int number of pages + * @access public + * @since 2.1.000 (2008-01-07) + * @see setPage(), getPage(), lastpage() + */ + public function getNumPages() { + return $this->numpages; + } + + /** + * Adds a new page to the document. If a page is already present, the Footer() method is called first to output the footer (if enabled). Then the page is added, the current position set to the top-left corner according to the left and top margins (or top-right if in RTL mode), and Header() is called to display the header (if enabled). + * The origin of the coordinate system is at the top-left corner (or top-right for RTL) and increasing ordinates go downwards. + * @param string $orientation page orientation. Possible values are (case insensitive):
    • P or PORTRAIT (default)
    • L or LANDSCAPE
    + * @param mixed $format The format used for pages. It can be either one of the following values (case insensitive) or a custom format in the form of a two-element array containing the width and the height (expressed in the unit given by unit).
    • 4A0
    • 2A0
    • A0
    • A1
    • A2
    • A3
    • A4 (default)
    • A5
    • A6
    • A7
    • A8
    • A9
    • A10
    • B0
    • B1
    • B2
    • B3
    • B4
    • B5
    • B6
    • B7
    • B8
    • B9
    • B10
    • C0
    • C1
    • C2
    • C3
    • C4
    • C5
    • C6
    • C7
    • C8
    • C9
    • C10
    • RA0
    • RA1
    • RA2
    • RA3
    • RA4
    • SRA0
    • SRA1
    • SRA2
    • SRA3
    • SRA4
    • LETTER
    • LEGAL
    • EXECUTIVE
    • FOLIO
    + * @access public + * @since 1.0 + * @see startPage(), endPage() + */ + public function AddPage($orientation='', $format='') { + if (!isset($this->original_lMargin)) { + $this->original_lMargin = $this->lMargin; + } + if (!isset($this->original_rMargin)) { + $this->original_rMargin = $this->rMargin; + } + // terminate previous page + $this->endPage(); + // start new page + $this->startPage($orientation, $format); + } + + /** + * Terminate the current page + * @access protected + * @since 4.2.010 (2008-11-14) + * @see startPage(), AddPage() + */ + protected function endPage() { + // check if page is already closed + if (($this->page == 0) OR ($this->numpages > $this->page) OR (!$this->pageopen[$this->page])) { + return; + } + $this->InFooter = true; + // print page footer + $this->setFooter(); + // close page + $this->_endpage(); + // mark page as closed + $this->pageopen[$this->page] = false; + $this->InFooter = false; + } + + /** + * Starts a new page to the document. The page must be closed using the endPage() function. + * The origin of the coordinate system is at the top-left corner and increasing ordinates go downwards. + * @param string $orientation page orientation. Possible values are (case insensitive):
    • P or PORTRAIT (default)
    • L or LANDSCAPE
    + * @param mixed $format The format used for pages. It can be either one of the following values (case insensitive) or a custom format in the form of a two-element array containing the width and the height (expressed in the unit given by unit).
    • 4A0
    • 2A0
    • A0
    • A1
    • A2
    • A3
    • A4 (default)
    • A5
    • A6
    • A7
    • A8
    • A9
    • A10
    • B0
    • B1
    • B2
    • B3
    • B4
    • B5
    • B6
    • B7
    • B8
    • B9
    • B10
    • C0
    • C1
    • C2
    • C3
    • C4
    • C5
    • C6
    • C7
    • C8
    • C9
    • C10
    • RA0
    • RA1
    • RA2
    • RA3
    • RA4
    • SRA0
    • SRA1
    • SRA2
    • SRA3
    • SRA4
    • LETTER
    • LEGAL
    • EXECUTIVE
    • FOLIO
    + * @access protected + * @since 4.2.010 (2008-11-14) + * @see endPage(), AddPage() + */ + protected function startPage($orientation='', $format='') { + if ($this->numpages > $this->page) { + // this page has been already added + $this->setPage($this->page + 1); + $this->SetY($this->tMargin); + return; + } + // start a new page + if ($this->state == 0) { + $this->Open(); + } + ++$this->numpages; + $this->swapMargins($this->booklet); + // save current graphic settings + $gvars = $this->getGraphicVars(); + // start new page + $this->_beginpage($orientation, $format); + // mark page as open + $this->pageopen[$this->page] = true; + // restore graphic settings + $this->setGraphicVars($gvars); + // mark this point + $this->setPageMark(); + // print page header + $this->setHeader(); + // restore graphic settings + $this->setGraphicVars($gvars); + // mark this point + $this->setPageMark(); + // print table header (if any) + $this->setTableHeader(); + } + + /** + * Set start-writing mark on current page for multicell borders and fills. + * This function must be called after calling Image() function for a background image. + * Background images must be always inserted before calling Multicell() or WriteHTMLCell() or WriteHTML() functions. + * @access public + * @since 4.0.016 (2008-07-30) + */ + public function setPageMark() { + $this->intmrk[$this->page] = $this->pagelen[$this->page]; + } + + /** + * Set header data. + * @param string $ln header image logo + * @param string $lw header image logo width in mm + * @param string $ht string to print as title on document header + * @param string $hs string to print on document header + * @access public + */ + public function setHeaderData($ln='', $lw=0, $ht='', $hs='') { + $this->header_logo = $ln; + $this->header_logo_width = $lw; + $this->header_title = $ht; + $this->header_string = $hs; + } + + /** + * Returns header data: + *
    • $ret['logo'] = logo image
    • $ret['logo_width'] = width of the image logo in user units
    • $ret['title'] = header title
    • $ret['string'] = header description string
    + * @return array() + * @access public + * @since 4.0.012 (2008-07-24) + */ + public function getHeaderData() { + $ret = array(); + $ret['logo'] = $this->header_logo; + $ret['logo_width'] = $this->header_logo_width; + $ret['title'] = $this->header_title; + $ret['string'] = $this->header_string; + return $ret; + } + + /** + * Set header margin. + * (minimum distance between header and top page margin) + * @param int $hm distance in user units + * @access public + */ + public function setHeaderMargin($hm=10) { + $this->header_margin = $hm; + } + + /** + * Returns header margin in user units. + * @return float + * @since 4.0.012 (2008-07-24) + * @access public + */ + public function getHeaderMargin() { + return $this->header_margin; + } + + /** + * Set footer margin. + * (minimum distance between footer and bottom page margin) + * @param int $fm distance in user units + * @access public + */ + public function setFooterMargin($fm=10) { + $this->footer_margin = $fm; + } + + /** + * Returns footer margin in user units. + * @return float + * @since 4.0.012 (2008-07-24) + * @access public + */ + public function getFooterMargin() { + return $this->footer_margin; + } + /** + * Set a flag to print page header. + * @param boolean $val set to true to print the page header (default), false otherwise. + * @access public + */ + public function setPrintHeader($val=true) { + $this->print_header = $val; + } + + /** + * Set a flag to print page footer. + * @param boolean $value set to true to print the page footer (default), false otherwise. + * @access public + */ + public function setPrintFooter($val=true) { + $this->print_footer = $val; + } + + /** + * Return the right-bottom (or left-bottom for RTL) corner X coordinate of last inserted image + * @return float + * @access public + */ + public function getImageRBX() { + return $this->img_rb_x; + } + + /** + * Return the right-bottom (or left-bottom for RTL) corner Y coordinate of last inserted image + * @return float + * @access public + */ + public function getImageRBY() { + return $this->img_rb_y; + } + + /** + * This method is used to render the page header. + * It is automatically called by AddPage() and could be overwritten in your own inherited class. + * @access public + */ + public function Header() { + $ormargins = $this->getOriginalMargins(); + $headerfont = $this->getHeaderFont(); + $headerdata = $this->getHeaderData(); + if (($headerdata['logo']) AND ($headerdata['logo'] != K_BLANK_IMAGE)) { + $this->Image(K_PATH_IMAGES.$headerdata['logo'], $this->GetX(), $this->getHeaderMargin(), $headerdata['logo_width']); + $imgy = $this->getImageRBY(); + } else { + $imgy = $this->GetY(); + } + $cell_height = round(($this->getCellHeightRatio() * $headerfont[2]) / $this->getScaleFactor(), 2); + // set starting margin for text data cell + if ($this->getRTL()) { + $header_x = $ormargins['right'] + ($headerdata['logo_width'] * 1.1); + } else { + $header_x = $ormargins['left'] + ($headerdata['logo_width'] * 1.1); + } + $this->SetTextColor(0, 0, 0); + // header title + $this->SetFont($headerfont[0], 'B', $headerfont[2] + 1); + $this->SetX($header_x); + $this->Cell(0, $cell_height, $headerdata['title'], 0, 1, '', 0, '', 0); + // header string + $this->SetFont($headerfont[0], $headerfont[1], $headerfont[2]); + $this->SetX($header_x); + $this->MultiCell(0, $cell_height, $headerdata['string'], 0, '', 0, 1, '', '', true, 0, false); + // print an ending header line + $this->SetLineStyle(array('width' => 0.85 / $this->getScaleFactor(), 'cap' => 'butt', 'join' => 'miter', 'dash' => 0, 'color' => array(0, 0, 0))); + $this->SetY((2.835 / $this->getScaleFactor()) + max($imgy, $this->GetY())); + if ($this->getRTL()) { + $this->SetX($ormargins['right']); + } else { + $this->SetX($ormargins['left']); + } + $this->Cell(0, 0, '', 'T', 0, 'C'); + } + + /** + * This method is used to render the page footer. + * It is automatically called by AddPage() and could be overwritten in your own inherited class. + * @access public + */ + public function Footer() { + $cur_y = $this->GetY(); + $ormargins = $this->getOriginalMargins(); + $this->SetTextColor(0, 0, 0); + //set style for cell border + $line_width = 0.85 / $this->getScaleFactor(); + $this->SetLineStyle(array('width' => $line_width, 'cap' => 'butt', 'join' => 'miter', 'dash' => 0, 'color' => array(0, 0, 0))); + //print document barcode + $barcode = $this->getBarcode(); + if (!empty($barcode)) { + $this->Ln($line_width); + $barcode_width = round(($this->getPageWidth() - $ormargins['left'] - $ormargins['right'])/3); + $this->write1DBarcode($barcode, 'C128B', $this->GetX(), $cur_y + $line_width, $barcode_width, (($this->getFooterMargin() / 3) - $line_width), 0.3, '', ''); + } + if (empty($this->pagegroups)) { + $pagenumtxt = $this->l['w_page'].' '.$this->getAliasNumPage().' / '.$this->getAliasNbPages(); + } else { + $pagenumtxt = $this->l['w_page'].' '.$this->getPageNumGroupAlias().' / '.$this->getPageGroupAlias(); + } + $this->SetY($cur_y); + //Print page number + if ($this->getRTL()) { + $this->SetX($ormargins['right']); + $this->Cell(0, 0, $pagenumtxt, 'T', 0, 'L'); + } else { + $this->SetX($ormargins['left']); + $this->Cell(0, 0, $pagenumtxt, 'T', 0, 'R'); + } + } + + /** + * This method is used to render the page header. + * @access protected + * @since 4.0.012 (2008-07-24) + */ + protected function setHeader() { + if ($this->print_header) { + $lasth = $this->lasth; + $this->_out('q'); + $this->rMargin = $this->original_rMargin; + $this->lMargin = $this->original_lMargin; + $this->cMargin = 0; + //set current position + if ($this->rtl) { + $this->SetXY($this->original_rMargin, $this->header_margin); + } else { + $this->SetXY($this->original_lMargin, $this->header_margin); + } + $this->SetFont($this->header_font[0], $this->header_font[1], $this->header_font[2]); + $this->Header(); + //restore position + if ($this->rtl) { + $this->SetXY($this->original_rMargin, $this->tMargin); + } else { + $this->SetXY($this->original_lMargin, $this->tMargin); + } + $this->_out('Q'); + $this->lasth = $lasth; + } + } + + /** + * This method is used to render the page footer. + * @access protected + * @since 4.0.012 (2008-07-24) + */ + protected function setFooter() { + //Page footer + // save current graphic settings + $gvars = $this->getGraphicVars(); + // mark this point + $this->footerpos[$this->page] = $this->pagelen[$this->page]; + $this->_out("\n"); + if ($this->print_footer) { + $lasth = $this->lasth; + $this->_out('q'); + $this->rMargin = $this->original_rMargin; + $this->lMargin = $this->original_lMargin; + $this->cMargin = 0; + //set current position + $footer_y = $this->h - $this->footer_margin; + if ($this->rtl) { + $this->SetXY($this->original_rMargin, $footer_y); + } else { + $this->SetXY($this->original_lMargin, $footer_y); + } + $this->SetFont($this->footer_font[0], $this->footer_font[1], $this->footer_font[2]); + $this->Footer(); + //restore position + if ($this->rtl) { + $this->SetXY($this->original_rMargin, $this->tMargin); + } else { + $this->SetXY($this->original_lMargin, $this->tMargin); + } + $this->_out('Q'); + $this->lasth = $lasth; + } + // restore graphic settings + $this->setGraphicVars($gvars); + // calculate footer lenght + $this->footerlen[$this->page] = $this->pagelen[$this->page] - $this->footerpos[$this->page] + 1; + } + + /** + * This method is used to render the table header on new page (if any). + * @access protected + * @since 4.5.030 (2009-03-25) + */ + protected function setTableHeader() { + if (!$this->empty_string($this->theadMargin)) { + // restore the original top-margin + $this->tMargin = $this->theadMargin; + $this->pagedim[$this->page]['tm'] = $this->theadMargin; + $this->y = $this->theadMargin; + } + if (!$this->empty_string($this->thead)) { + // print table header + $this->writeHTML($this->thead, false, false, false, false, ''); + // set new top margin to skip the table headers + if (!isset($this->theadMargin) OR ($this->empty_string($this->theadMargin))) { + $this->theadMargin = $this->tMargin; + } + $this->tMargin = $this->y; + $this->pagedim[$this->page]['tm'] = $this->tMargin; + } + } + + /** + * Returns the current page number. + * @return int page number + * @access public + * @since 1.0 + * @see AliasNbPages(), getAliasNbPages() + */ + public function PageNo() { + return $this->page; + } + + /** + * Defines a new spot color. + * It can be expressed in RGB components or gray scale. + * The method can be called before the first page is created and the value is retained from page to page. + * @param int $c Cyan color for CMYK. Value between 0 and 255 + * @param int $m Magenta color for CMYK. Value between 0 and 255 + * @param int $y Yellow color for CMYK. Value between 0 and 255 + * @param int $k Key (Black) color for CMYK. Value between 0 and 255 + * @access public + * @since 4.0.024 (2008-09-12) + * @see SetDrawSpotColor(), SetFillSpotColor(), SetTextSpotColor() + */ + public function AddSpotColor($name, $c, $m, $y, $k) { + if (!isset($this->spot_colors[$name])) { + $i = 1 + count($this->spot_colors); + $this->spot_colors[$name] = array('i' => $i, 'c' => $c, 'm' => $m, 'y' => $y, 'k' => $k); + } + } + + /** + * Defines the color used for all drawing operations (lines, rectangles and cell borders). + * It can be expressed in RGB components or gray scale. + * The method can be called before the first page is created and the value is retained from page to page. + * @param array $color array of colors + * @access public + * @since 3.1.000 (2008-06-11) + * @see SetDrawColor() + */ + public function SetDrawColorArray($color) { + if (isset($color)) { + $color = array_values($color); + $r = isset($color[0]) ? $color[0] : -1; + $g = isset($color[1]) ? $color[1] : -1; + $b = isset($color[2]) ? $color[2] : -1; + $k = isset($color[3]) ? $color[3] : -1; + if ($r >= 0) { + $this->SetDrawColor($r, $g, $b, $k); + } + } + } + + /** + * Defines the color used for all drawing operations (lines, rectangles and cell borders). It can be expressed in RGB components or gray scale. The method can be called before the first page is created and the value is retained from page to page. + * @param int $col1 Gray level for single color, or Red color for RGB, or Cyan color for CMYK. Value between 0 and 255 + * @param int $col2 Green color for RGB, or Magenta color for CMYK. Value between 0 and 255 + * @param int $col3 Blue color for RGB, or Yellow color for CMYK. Value between 0 and 255 + * @param int $col4 Key (Black) color for CMYK. Value between 0 and 255 + * @access public + * @since 1.3 + * @see SetDrawColorArray(), SetFillColor(), SetTextColor(), Line(), Rect(), Cell(), MultiCell() + */ + public function SetDrawColor($col1=0, $col2=-1, $col3=-1, $col4=-1) { + // set default values + if (!is_numeric($col1)) { + $col1 = 0; + } + if (!is_numeric($col2)) { + $col2 = -1; + } + if (!is_numeric($col3)) { + $col3 = -1; + } + if (!is_numeric($col4)) { + $col4 = -1; + } + //Set color for all stroking operations + if (($col2 == -1) AND ($col3 == -1) AND ($col4 == -1)) { + // Grey scale + $this->DrawColor = sprintf('%.3F G', $col1/255); + } elseif ($col4 == -1) { + // RGB + $this->DrawColor = sprintf('%.3F %.3F %.3F RG', $col1/255, $col2/255, $col3/255); + } else { + // CMYK + $this->DrawColor = sprintf('%.3F %.3F %.3F %.3F K', $col1/100, $col2/100, $col3/100, $col4/100); + } + if ($this->page > 0) { + $this->_out($this->DrawColor); + } + } + + /** + * Defines the spot color used for all drawing operations (lines, rectangles and cell borders). + * @param string $name name of the spot color + * @param int $tint the intensity of the color (from 0 to 100 ; 100 = full intensity by default). + * @access public + * @since 4.0.024 (2008-09-12) + * @see AddSpotColor(), SetFillSpotColor(), SetTextSpotColor() + */ + public function SetDrawSpotColor($name, $tint=100) { + if (!isset($this->spot_colors[$name])) { + $this->Error('Undefined spot color: '.$name); + } + $this->DrawColor = sprintf('/CS%d CS %.3F SCN', $this->spot_colors[$name]['i'], $tint/100); + if ($this->page > 0) { + $this->_out($this->DrawColor); + } + } + + /** + * Defines the color used for all filling operations (filled rectangles and cell backgrounds). + * It can be expressed in RGB components or gray scale. + * The method can be called before the first page is created and the value is retained from page to page. + * @param array $color array of colors + * @access public + * @since 3.1.000 (2008-6-11) + * @see SetFillColor() + */ + public function SetFillColorArray($color) { + if (isset($color)) { + $color = array_values($color); + $r = isset($color[0]) ? $color[0] : -1; + $g = isset($color[1]) ? $color[1] : -1; + $b = isset($color[2]) ? $color[2] : -1; + $k = isset($color[3]) ? $color[3] : -1; + if ($r >= 0) { + $this->SetFillColor($r, $g, $b, $k); + } + } + } + + /** + * Defines the color used for all filling operations (filled rectangles and cell backgrounds). It can be expressed in RGB components or gray scale. The method can be called before the first page is created and the value is retained from page to page. + * @param int $col1 Gray level for single color, or Red color for RGB, or Cyan color for CMYK. Value between 0 and 255 + * @param int $col2 Green color for RGB, or Magenta color for CMYK. Value between 0 and 255 + * @param int $col3 Blue color for RGB, or Yellow color for CMYK. Value between 0 and 255 + * @param int $col4 Key (Black) color for CMYK. Value between 0 and 255 + * @access public + * @since 1.3 + * @see SetFillColorArray(), SetDrawColor(), SetTextColor(), Rect(), Cell(), MultiCell() + */ + public function SetFillColor($col1=0, $col2=-1, $col3=-1, $col4=-1) { + // set default values + if (!is_numeric($col1)) { + $col1 = 0; + } + if (!is_numeric($col2)) { + $col2 = -1; + } + if (!is_numeric($col3)) { + $col3 = -1; + } + if (!is_numeric($col4)) { + $col4 = -1; + } + //Set color for all filling operations + if (($col2 == -1) AND ($col3 == -1) AND ($col4 == -1)) { + // Grey scale + $this->FillColor = sprintf('%.3F g', $col1/255); + $this->bgcolor = array('G' => $col1); + } elseif ($col4 == -1) { + // RGB + $this->FillColor = sprintf('%.3F %.3F %.3F rg', $col1/255, $col2/255, $col3/255); + $this->bgcolor = array('R' => $col1, 'G' => $col2, 'B' => $col3); + } else { + // CMYK + $this->FillColor = sprintf('%.3F %.3F %.3F %.3F k', $col1/100, $col2/100, $col3/100, $col4/100); + $this->bgcolor = array('C' => $col1, 'M' => $col2, 'Y' => $col3, 'K' => $col4); + } + $this->ColorFlag = ($this->FillColor != $this->TextColor); + if ($this->page > 0) { + $this->_out($this->FillColor); + } + } + + /** + * Defines the spot color used for all filling operations (filled rectangles and cell backgrounds). + * @param string $name name of the spot color + * @param int $tint the intensity of the color (from 0 to 100 ; 100 = full intensity by default). + * @access public + * @since 4.0.024 (2008-09-12) + * @see AddSpotColor(), SetDrawSpotColor(), SetTextSpotColor() + */ + public function SetFillSpotColor($name, $tint=100) { + if (!isset($this->spot_colors[$name])) { + $this->Error('Undefined spot color: '.$name); + } + $this->FillColor = sprintf('/CS%d cs %.3F scn', $this->spot_colors[$name]['i'], $tint/100); + $this->ColorFlag = ($this->FillColor != $this->TextColor); + if ($this->page > 0) { + $this->_out($this->FillColor); + } + } + + /** + * Defines the color used for text. It can be expressed in RGB components or gray scale. + * The method can be called before the first page is created and the value is retained from page to page. + * @param array $color array of colors + * @access public + * @since 3.1.000 (2008-6-11) + * @see SetFillColor() + */ + public function SetTextColorArray($color) { + if (isset($color)) { + $color = array_values($color); + $r = isset($color[0]) ? $color[0] : -1; + $g = isset($color[1]) ? $color[1] : -1; + $b = isset($color[2]) ? $color[2] : -1; + $k = isset($color[3]) ? $color[3] : -1; + if ($r >= 0) { + $this->SetTextColor($r, $g, $b, $k); + } + } + } + + /** + * Defines the color used for text. It can be expressed in RGB components or gray scale. The method can be called before the first page is created and the value is retained from page to page. + * @param int $col1 Gray level for single color, or Red color for RGB, or Cyan color for CMYK. Value between 0 and 255 + * @param int $col2 Green color for RGB, or Magenta color for CMYK. Value between 0 and 255 + * @param int $col3 Blue color for RGB, or Yellow color for CMYK. Value between 0 and 255 + * @param int $col4 Key (Black) color for CMYK. Value between 0 and 255 + * @access public + * @since 1.3 + * @see SetTextColorArray(), SetDrawColor(), SetFillColor(), Text(), Cell(), MultiCell() + */ + public function SetTextColor($col1=0, $col2=-1, $col3=-1, $col4=-1) { + // set default values + if (!is_numeric($col1)) { + $col1 = 0; + } + if (!is_numeric($col2)) { + $col2 = -1; + } + if (!is_numeric($col3)) { + $col3 = -1; + } + if (!is_numeric($col4)) { + $col4 = -1; + } + //Set color for text + if (($col2 == -1) AND ($col3 == -1) AND ($col4 == -1)) { + // Grey scale + $this->TextColor = sprintf('%.3F g', $col1/255); + $this->fgcolor = array('G' => $col1); + } elseif ($col4 == -1) { + // RGB + $this->TextColor = sprintf('%.3F %.3F %.3F rg', $col1/255, $col2/255, $col3/255); + $this->fgcolor = array('R' => $col1, 'G' => $col2, 'B' => $col3); + } else { + // CMYK + $this->TextColor = sprintf('%.3F %.3F %.3F %.3F k', $col1/100, $col2/100, $col3/100, $col4/100); + $this->fgcolor = array('C' => $col1, 'M' => $col2, 'Y' => $col3, 'K' => $col4); + } + $this->ColorFlag = ($this->FillColor != $this->TextColor); + } + + /** + * Defines the spot color used for text. + * @param string $name name of the spot color + * @param int $tint the intensity of the color (from 0 to 100 ; 100 = full intensity by default). + * @access public + * @since 4.0.024 (2008-09-12) + * @see AddSpotColor(), SetDrawSpotColor(), SetFillSpotColor() + */ + public function SetTextSpotColor($name, $tint=100) { + if (!isset($this->spot_colors[$name])) { + $this->Error('Undefined spot color: '.$name); + } + $this->TextColor = sprintf('/CS%d cs %.3F scn', $this->spot_colors[$name]['i'], $tint/100); + $this->ColorFlag = ($this->FillColor != $this->TextColor); + if ($this->page > 0) { + $this->_out($this->TextColor); + } + } + + /** + * Returns the length of a string in user unit. A font must be selected.
    + * @param string $s The string whose length is to be computed + * @param string $fontname Family font. It can be either a name defined by AddFont() or one of the standard families. It is also possible to pass an empty string, in that case, the current family is retained. + * @param string $fontstyle Font style. Possible values are (case insensitive):
    • empty string: regular
    • B: bold
    • I: italic
    • U: underline
    • D: line trough
    or any combination. The default value is regular. + * @param float $fontsize Font size in points. The default value is the current size. + * @return int string length + * @author Nicola Asuni + * @access public + * @since 1.2 + */ + public function GetStringWidth($s, $fontname='', $fontstyle='', $fontsize=0) { + return $this->GetArrStringWidth($this->utf8Bidi($this->UTF8StringToArray($s), $s, $this->tmprtl), $fontname, $fontstyle, $fontsize); + } + + /** + * Returns the string length of an array of chars in user unit. A font must be selected.
    + * @param string $arr The array of chars whose total length is to be computed + * @param string $fontname Family font. It can be either a name defined by AddFont() or one of the standard families. It is also possible to pass an empty string, in that case, the current family is retained. + * @param string $fontstyle Font style. Possible values are (case insensitive):
    • empty string: regular
    • B: bold
    • I: italic
    • U: underline
    • D: line trough
    or any combination. The default value is regular. + * @param float $fontsize Font size in points. The default value is the current size. + * @return int string length + * @author Nicola Asuni + * @access public + * @since 2.4.000 (2008-03-06) + */ + public function GetArrStringWidth($sa, $fontname='', $fontstyle='', $fontsize=0) { + // store current values + if (!$this->empty_string($fontname)) { + $prev_FontFamily = $this->FontFamily; + $prev_FontStyle = $this->FontStyle; + $prev_FontSizePt = $this->FontSizePt; + $this->SetFont($fontname, $fontstyle, $fontsize); + } + $w = 0; + foreach ($sa as $char) { + $w += $this->GetCharWidth($char); + } + // restore previous values + if (!$this->empty_string($fontname)) { + $this->SetFont($prev_FontFamily, $prev_FontStyle, $prev_FontSizePt); + } + return $w; + } + + /** + * Returns the length of the char in user unit for the current font.
    + * @param int $char The char code whose length is to be returned + * @return int char width + * @author Nicola Asuni + * @access public + * @since 2.4.000 (2008-03-06) + */ + public function GetCharWidth($char) { + if ($char == 173) { + // SHY character will not be printed + return (0); + } + $cw = &$this->CurrentFont['cw']; + if (isset($cw[$char])) { + $w = $cw[$char]; + } elseif (isset($this->CurrentFont['dw'])) { + // default width + $w = $this->CurrentFont['dw']; + } elseif (isset($cw[32])) { + // default width + $dw = $cw[32]; + } else { + $w = 600; + } + return ($w * $this->FontSize / 1000); + } + + /** + * Returns the numbero of characters in a string. + * @param string $s The input string. + * @return int number of characters + * @access public + * @since 2.0.0001 (2008-01-07) + */ + public function GetNumChars($s) { + if (($this->CurrentFont['type'] == 'TrueTypeUnicode') OR ($this->CurrentFont['type'] == 'cidfont0')) { + return count($this->UTF8StringToArray($s)); + } + return strlen($s); + } + + /** + * Fill the list of available fonts ($this->fontlist). + * @access protected + * @since 4.0.013 (2008-07-28) + */ + protected function getFontsList() { + $fontsdir = opendir($this->_getfontpath()); + while (($file = readdir($fontsdir)) !== false) { + if (substr($file, -4) == '.php') { + array_push($this->fontlist, strtolower(basename($file, '.php'))); + } + } + closedir($fontsdir); + } + + /** + * Imports a TrueType, Type1, core, or CID0 font and makes it available. + * It is necessary to generate a font definition file first (read /fonts/utils/README.TXT). + * The definition file (and the font file itself when embedding) must be present either in the current directory or in the one indicated by K_PATH_FONTS if the constant is defined. If it could not be found, the error "Could not include font definition file" is generated. + * @param string $family Font family. The name can be chosen arbitrarily. If it is a standard family name, it will override the corresponding font. + * @param string $style Font style. Possible values are (case insensitive):
    • empty string: regular (default)
    • B: bold
    • I: italic
    • BI or IB: bold italic
    + * @param string $fontfile The font definition file. By default, the name is built from the family and style, in lower case with no spaces. + * @return array containing the font data, or false in case of error. + * @access public + * @since 1.5 + * @see SetFont() + */ + public function AddFont($family, $style='', $fontfile='') { + if ($this->empty_string($family)) { + if (!$this->empty_string($this->FontFamily)) { + $family = $this->FontFamily; + } else { + $this->Error('Empty font family'); + } + } + $family = strtolower($family); + if ((!$this->isunicode) AND ($family == 'arial')) { + $family = 'helvetica'; + } + if (($family == 'symbol') OR ($family == 'zapfdingbats')) { + $style = ''; + } + $tempstyle = strtoupper($style); + $style = ''; + // underline + if (strpos($tempstyle, 'U') !== false) { + $this->underline = true; + } else { + $this->underline = false; + } + // line through (deleted) + if (strpos($tempstyle, 'D') !== false) { + $this->linethrough = true; + } else { + $this->linethrough = false; + } + // bold + if (strpos($tempstyle, 'B') !== false) { + $style .= 'B'; + } + // oblique + if (strpos($tempstyle, 'I') !== false) { + $style .= 'I'; + } + $bistyle = $style; + $fontkey = $family.$style; + $font_style = $style.($this->underline ? 'U' : '').($this->linethrough ? 'D' : ''); + $fontdata = array('fontkey' => $fontkey, 'family' => $family, 'style' => $font_style); + // check if the font has been already added + if ($this->getFontBuffer($fontkey) !== false) { + return $fontdata; + } + if (isset($type)) { + unset($type); + } + if (isset($cw)) { + unset($cw); + } + // get specified font directory (if any) + $fontdir = ''; + if (!$this->empty_string($fontfile)) { + $fontdir = dirname($fontfile); + if ($this->empty_string($fontdir) OR ($fontdir == '.')) { + $fontdir = ''; + } else { + $fontdir .= '/'; + } + } + // search and include font file + if ($this->empty_string($fontfile) OR (!file_exists($fontfile))) { + // build a standard filenames for specified font + $fontfile1 = str_replace(' ', '', $family).strtolower($style).'.php'; + $fontfile2 = str_replace(' ', '', $family).'.php'; + // search files on various directories + if (file_exists($fontdir.$fontfile1)) { + $fontfile = $fontdir.$fontfile1; + } elseif (file_exists($this->_getfontpath().$fontfile1)) { + $fontfile = $this->_getfontpath().$fontfile1; + } elseif (file_exists($fontfile1)) { + $fontfile = $fontfile1; + } elseif (file_exists($fontdir.$fontfile2)) { + $fontfile = $fontdir.$fontfile2; + } elseif (file_exists($this->_getfontpath().$fontfile2)) { + $fontfile = $this->_getfontpath().$fontfile2; + } else { + $fontfile = $fontfile2; + } + } + // include font file + if (file_exists($fontfile)) { + include($fontfile); + } else { + $this->Error('Could not include font definition file: '.$family.''); + } + // check font parameters + if ((!isset($type)) OR (!isset($cw))) { + $this->Error('The font definition file has a bad format: '.$fontfile.''); + } + if (!isset($file)) { + $file = ''; + } + if (!isset($enc)) { + $enc = ''; + } + if (!isset($dw) OR $this->empty_string($dw)) { + // set default width + if (isset($desc['MissingWidth']) AND ($desc['MissingWidth'] > 0)) { + $dw = $desc['MissingWidth']; + } elseif (isset($cw[32])) { + $dw = $cw[32]; + } else { + $dw = 600; + } + } + ++$this->numfonts; + // register CID font (all styles at once) + if ($type == 'cidfont0') { + $file = ''; // not embedded + $styles = array('' => '', 'B' => ',Bold', 'I' => ',Italic', 'BI' => ',BoldItalic'); + $sname = $name.$styles[$bistyle]; + if ((strpos($bistyle, 'B') !== false) AND (isset($desc['StemV'])) AND ($desc['StemV'] == 70)) { + $desc['StemV'] = 120; + } + $this->setFontBuffer($fontkey, array('i' => $this->numfonts, 'type' => $type, 'name' => $sname, 'desc' => $desc, 'cidinfo' => $cidinfo, 'up' => $up, 'ut' => $ut, 'cw' => $cw, 'dw' => $dw, 'enc' => $enc)); + } elseif ($type == 'core') { + $this->setFontBuffer($fontkey, array('i' => $this->numfonts, 'type' => 'core', 'name' => $this->CoreFonts[$fontkey], 'up' => -100, 'ut' => 50, 'cw' => $cw, 'dw' => $dw)); + } elseif (($type == 'TrueType') OR ($type == 'Type1')) { + $this->setFontBuffer($fontkey, array('i' => $this->numfonts, 'type' => $type, 'name' => $name, 'up' => $up, 'ut' => $ut, 'cw' => $cw, 'dw' => $dw, 'file' => $file, 'enc' => $enc, 'desc' => $desc)); + } elseif ($type == 'TrueTypeUnicode') { + $this->setFontBuffer($fontkey, array('i' => $this->numfonts, 'type' => $type, 'name' => $name, 'desc' => $desc, 'up' => $up, 'ut' => $ut, 'cw' => $cw, 'dw' => $dw, 'enc' => $enc, 'file' => $file, 'ctg' => $ctg)); + } else { + $this->Error('Unknow font type: '.$type.''); + } + if (isset($diff) AND (!empty($diff))) { + //Search existing encodings + $d = 0; + $nb = count($this->diffs); + for ($i=1; $i <= $nb; ++$i) { + if ($this->diffs[$i] == $diff) { + $d = $i; + break; + } + } + if ($d == 0) { + $d = $nb + 1; + $this->diffs[$d] = $diff; + } + $this->setFontSubBuffer($fontkey, 'diff', $d); + } + if (!$this->empty_string($file)) { + if ((strcasecmp($type,'TrueType') == 0) OR (strcasecmp($type, 'TrueTypeUnicode') == 0)) { + $this->FontFiles[$file] = array('length1' => $originalsize, 'fontdir' => $fontdir); + } elseif ($type != 'core') { + $this->FontFiles[$file] = array('length1' => $size1, 'length2' => $size2, 'fontdir' => $fontdir); + } + } + return $fontdata; + } + + /** + * Sets the font used to print character strings. + * The font can be either a standard one or a font added via the AddFont() method. Standard fonts use Windows encoding cp1252 (Western Europe). + * The method can be called before the first page is created and the font is retained from page to page. + * If you just wish to change the current font size, it is simpler to call SetFontSize(). + * Note: for the standard fonts, the font metric files must be accessible. There are three possibilities for this:
    • They are in the current directory (the one where the running script lies)
    • They are in one of the directories defined by the include_path parameter
    • They are in the directory defined by the K_PATH_FONTS constant

    + * @param string $family Family font. It can be either a name defined by AddFont() or one of the standard Type1 families (case insensitive):
    • times (Times-Roman)
    • timesb (Times-Bold)
    • timesi (Times-Italic)
    • timesbi (Times-BoldItalic)
    • helvetica (Helvetica)
    • helveticab (Helvetica-Bold)
    • helveticai (Helvetica-Oblique)
    • helveticabi (Helvetica-BoldOblique)
    • courier (Courier)
    • courierb (Courier-Bold)
    • courieri (Courier-Oblique)
    • courierbi (Courier-BoldOblique)
    • symbol (Symbol)
    • zapfdingbats (ZapfDingbats)
    It is also possible to pass an empty string. In that case, the current family is retained. + * @param string $style Font style. Possible values are (case insensitive):
    • empty string: regular
    • B: bold
    • I: italic
    • U: underline
    • D: line trough
    or any combination. The default value is regular. Bold and italic styles do not apply to Symbol and ZapfDingbats basic fonts or other fonts when not defined. + * @param float $size Font size in points. The default value is the current size. If no size has been specified since the beginning of the document, the value taken is 12 + * @param string $fontfile The font definition file. By default, the name is built from the family and style, in lower case with no spaces. + * @access public + * @since 1.0 + * @see AddFont(), SetFontSize() + */ + public function SetFont($family, $style='', $size=0, $fontfile='') { + //Select a font; size given in points + if ($size == 0) { + $size = $this->FontSizePt; + } + // try to add font (if not already added) + $fontdata = $this->AddFont($family, $style, $fontfile); + $this->FontFamily = $fontdata['family']; + $this->FontStyle = $fontdata['style']; + $this->CurrentFont = $this->getFontBuffer($fontdata['fontkey']); + $this->SetFontSize($size); + } + + /** + * Defines the size of the current font. + * @param float $size The size (in points) + * @access public + * @since 1.0 + * @see SetFont() + */ + public function SetFontSize($size) { + //Set font size in points + $this->FontSizePt = $size; + $this->FontSize = $size / $this->k; + if (isset($this->CurrentFont['desc']['Ascent']) AND ($this->CurrentFont['desc']['Ascent'] > 0)) { + $this->FontAscent = $this->CurrentFont['desc']['Ascent'] * $this->FontSize / 1000; + } else { + $this->FontAscent = 0.8 * $this->FontSize; + } + if (isset($this->CurrentFont['desc']['Descent']) AND ($this->CurrentFont['desc']['Descent'] > 0)) { + $this->FontDescent = - $this->CurrentFont['desc']['Descent'] * $this->FontSize / 1000; + } else { + $this->FontDescent = 0.2 * $this->FontSize; + } + if (($this->page > 0) AND (isset($this->CurrentFont['i']))) { + $this->_out(sprintf('BT /F%d %.2F Tf ET', $this->CurrentFont['i'], $this->FontSizePt)); + } + } + + /** + * Defines the default monospaced font. + * @param string $font Font name. + * @access public + * @since 4.5.025 + */ + public function SetDefaultMonospacedFont($font) { + $this->default_monospaced_font = $font; + } + + /** + * Creates a new internal link and returns its identifier. An internal link is a clickable area which directs to another place within the document.
    + * The identifier can then be passed to Cell(), Write(), Image() or Link(). The destination is defined with SetLink(). + * @access public + * @since 1.5 + * @see Cell(), Write(), Image(), Link(), SetLink() + */ + public function AddLink() { + //Create a new internal link + $n = count($this->links) + 1; + $this->links[$n] = array(0, 0); + return $n; + } + + /** + * Defines the page and position a link points to. + * @param int $link The link identifier returned by AddLink() + * @param float $y Ordinate of target position; -1 indicates the current position. The default value is 0 (top of page) + * @param int $page Number of target page; -1 indicates the current page. This is the default value + * @access public + * @since 1.5 + * @see AddLink() + */ + public function SetLink($link, $y=0, $page=-1) { + if ($y == -1) { + $y = $this->y; + } + if ($page == -1) { + $page = $this->page; + } + $this->links[$link] = array($page, $y); + } + + /** + * Puts a link on a rectangular area of the page. + * Text or image links are generally put via Cell(), Write() or Image(), but this method can be useful for instance to define a clickable area inside an image. + * @param float $x Abscissa of the upper-left corner of the rectangle + * @param float $y Ordinate of the upper-left corner of the rectangle + * @param float $w Width of the rectangle + * @param float $h Height of the rectangle + * @param mixed $link URL or identifier returned by AddLink() + * @param int $spaces number of spaces on the text to link + * @access public + * @since 1.5 + * @see AddLink(), Annotation(), Cell(), Write(), Image() + */ + public function Link($x, $y, $w, $h, $link, $spaces=0) { + $this->Annotation($x, $y, $w, $h, $link, array('Subtype'=>'Link'), $spaces); + } + + /** + * Puts a markup annotation on a rectangular area of the page. + * !!!!THE ANNOTATION SUPPORT IS NOT YET FULLY IMPLEMENTED !!!! + * @param float $x Abscissa of the upper-left corner of the rectangle + * @param float $y Ordinate of the upper-left corner of the rectangle + * @param float $w Width of the rectangle + * @param float $h Height of the rectangle + * @param string $text annotation text or alternate content + * @param array $opt array of options (see section 8.4 of PDF reference 1.7). + * @param int $spaces number of spaces on the text to link + * @access public + * @since 4.0.018 (2008-08-06) + */ + public function Annotation($x, $y, $w, $h, $text, $opt=array('Subtype'=>'Text'), $spaces=0) { + // recalculate coordinates to account for graphic transformations + if (isset($this->transfmatrix)) { + $maxid = count($this->transfmatrix) - 1; + for ($i=$maxid; $i >= 0; $i--) { + $ctm = $this->transfmatrix[$i]; + if (isset($ctm['a'])) { + $x = $x * $this->k; + $y = ($this->h - $y) * $this->k; + $w = $w * $this->k; + $h = $h * $this->k; + // top left + $xt = $x; + $yt = $y; + $x1 = ($ctm['a'] * $xt) + ($ctm['c'] * $yt) + $ctm['e']; + $y1 = ($ctm['b'] * $xt) + ($ctm['d'] * $yt) + $ctm['f']; + // top right + $xt = $x + $w; + $yt = $y; + $x2 = ($ctm['a'] * $xt) + ($ctm['c'] * $yt) + $ctm['e']; + $y2 = ($ctm['b'] * $xt) + ($ctm['d'] * $yt) + $ctm['f']; + // bottom left + $xt = $x; + $yt = $y - $h; + $x3 = ($ctm['a'] * $xt) + ($ctm['c'] * $yt) + $ctm['e']; + $y3 = ($ctm['b'] * $xt) + ($ctm['d'] * $yt) + $ctm['f']; + // bottom right + $xt = $x + $w; + $yt = $y - $h; + $x4 = ($ctm['a'] * $xt) + ($ctm['c'] * $yt) + $ctm['e']; + $y4 = ($ctm['b'] * $xt) + ($ctm['d'] * $yt) + $ctm['f']; + // new coordinates (rectangle area) + $x = min($x1, $x2, $x3, $x4); + $y = max($y1, $y2, $y3, $y4); + $w = (max($x1, $x2, $x3, $x4) - $x) / $this->k; + $h = ($y - min($y1, $y2, $y3, $y4)) / $this->k; + $x = $x / $this->k; + $y = $this->h - ($y / $this->k); + } + } + } + $this->PageAnnots[$this->page][] = array('x' => $x, 'y' => $y, 'w' => $w, 'h' => $h, 'txt' => $text, 'opt' => $opt, 'numspaces' => $spaces); + if (($opt['Subtype'] == 'FileAttachment') AND (!$this->empty_string($opt['FS'])) AND file_exists($opt['FS']) AND (!isset($this->embeddedfiles[basename($opt['FS'])]))) { + $this->embeddedfiles[basename($opt['FS'])] = array('file' => $opt['FS'], 'n' => (count($this->embeddedfiles) + 100000)); + } + } + + /** + * Embedd the attached files. + * @since 4.4.000 (2008-12-07) + * @access protected + * @see Annotation() + */ + protected function _putEmbeddedFiles() { + reset($this->embeddedfiles); + foreach ($this->embeddedfiles as $filename => $filedata) { + $data = file_get_contents($filedata['file']); + $filter = ''; + if ($this->compress) { + $data = gzcompress($data); + $filter = ' /Filter /FlateDecode'; + } + $this->offsets[$filedata['n']] = $this->bufferlen; + $this->_out($filedata['n'].' 0 obj'); + $this->_out('<>'); + $this->_putstream($data); + $this->_out('endobj'); + } + } + + /** + * Prints a character string. + * The origin is on the left of the first charcter, on the baseline. + * This method allows to place a string precisely on the page. + * @param float $x Abscissa of the origin + * @param float $y Ordinate of the origin + * @param string $txt String to print + * @param int $stroke outline size in points (0 = disable) + * @param boolean $clip if true activate clipping mode (you must call StartTransform() before this function and StopTransform() to stop the clipping tranformation). + * @access public + * @since 1.0 + * @deprecated deprecated since version 4.3.005 (2008-11-25) + * @see Cell(), Write(), MultiCell(), WriteHTML(), WriteHTMLCell() + */ + public function Text($x, $y, $txt, $stroke=0, $clip=false) { + //Output a string + if ($this->rtl) { + // bidirectional algorithm (some chars may be changed affecting the line length) + $s = $this->utf8Bidi($this->UTF8StringToArray($txt), $txt, $this->tmprtl); + $l = $this->GetArrStringWidth($s); + $xr = $this->w - $x - $this->GetArrStringWidth($s); + } else { + $xr = $x; + } + $opt = ''; + if (($stroke > 0) AND (!$clip)) { + $opt .= '1 Tr '.intval($stroke).' w '; + } elseif (($stroke > 0) AND $clip) { + $opt .= '5 Tr '.intval($stroke).' w '; + } elseif ($clip) { + $opt .= '7 Tr '; + } + $s = sprintf('BT %.2F %.2F Td %s(%s) Tj ET 0 Tr', $xr * $this->k, ($this->h-$y) * $this->k, $opt, $this->_escapetext($txt)); + if ($this->underline AND ($txt!='')) { + $s .= ' '.$this->_dounderline($xr, $y, $txt); + } + if ($this->linethrough AND ($txt!='')) { + $s .= ' '.$this->_dolinethrough($xr, $y, $txt); + } + if ($this->ColorFlag AND (!$clip)) { + $s='q '.$this->TextColor.' '.$s.' Q'; + } + $this->_out($s); + } + + /** + * Whenever a page break condition is met, the method is called, and the break is issued or not depending on the returned value. + * The default implementation returns a value according to the mode selected by SetAutoPageBreak().
    + * This method is called automatically and should not be called directly by the application. + * @return boolean + * @access public + * @since 1.4 + * @see SetAutoPageBreak() + */ + public function AcceptPageBreak() { + return $this->AutoPageBreak; + } + + /** + * Add page if needed. + * @param float $h Cell height. Default value: 0. + * @param mixed $y starting y position, leave empty for current position. + * @return boolean true in case of page break, false otherwise. + * @since 3.2.000 (2008-07-01) + * @access protected + */ + protected function checkPageBreak($h=0, $y='') { + if ($this->empty_string($y)) { + $y = $this->y; + } + if ((($y + $h) > $this->PageBreakTrigger) AND (!$this->InFooter) AND ($this->AcceptPageBreak())) { + //Automatic page break + $x = $this->x; + $this->AddPage($this->CurOrientation); + $this->y = $this->tMargin; + $oldpage = $this->page - 1; + if ($this->rtl) { + if ($this->pagedim[$this->page]['orm'] != $this->pagedim[$oldpage]['orm']) { + $this->x = $x - ($this->pagedim[$this->page]['orm'] - $this->pagedim[$oldpage]['orm']); + } else { + $this->x = $x; + } + } else { + if ($this->pagedim[$this->page]['olm'] != $this->pagedim[$oldpage]['olm']) { + $this->x = $x + ($this->pagedim[$this->page]['olm'] - $this->pagedim[$oldpage]['olm']); + } else { + $this->x = $x; + } + } + return true; + } + return false; + } + + /** + * Prints a cell (rectangular area) with optional borders, background color and character string. The upper-left corner of the cell corresponds to the current position. The text can be aligned or centered. After the call, the current position moves to the right or to the next line. It is possible to put a link on the text.
    + * If automatic page breaking is enabled and the cell goes beyond the limit, a page break is done before outputting. + * @param float $w Cell width. If 0, the cell extends up to the right margin. + * @param float $h Cell height. Default value: 0. + * @param string $txt String to print. Default value: empty string. + * @param mixed $border Indicates if borders must be drawn around the cell. The value can be either a number:
    • 0: no border (default)
    • 1: frame
    or a string containing some or all of the following characters (in any order):
    • L: left
    • T: top
    • R: right
    • B: bottom
    + * @param int $ln Indicates where the current position should go after the call. Possible values are:
    • 0: to the right (or left for RTL languages)
    • 1: to the beginning of the next line
    • 2: below
    + Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: 0. + * @param string $align Allows to center or align the text. Possible values are:
    • L or empty string: left align (default value)
    • C: center
    • R: right align
    • J: justify
    + * @param int $fill Indicates if the cell background must be painted (1) or transparent (0). Default value: 0. + * @param mixed $link URL or identifier returned by AddLink(). + * @param int $stretch stretch carachter mode:
    • 0 = disabled
    • 1 = horizontal scaling only if necessary
    • 2 = forced horizontal scaling
    • 3 = character spacing only if necessary
    • 4 = forced character spacing
    + * @param boolean $ignore_min_height if true ignore automatic minimum height value. + * @access public + * @since 1.0 + * @see SetFont(), SetDrawColor(), SetFillColor(), SetTextColor(), SetLineWidth(), AddLink(), Ln(), MultiCell(), Write(), SetAutoPageBreak() + */ + public function Cell($w, $h=0, $txt='', $border=0, $ln=0, $align='', $fill=0, $link='', $stretch=0, $ignore_min_height=false) { + //$min_cell_height = $this->FontAscent + $this->FontDescent; + $min_cell_height = $this->FontSize * $this->cell_height_ratio; + if ($h < $min_cell_height) { + $h = $min_cell_height; + } + $this->checkPageBreak($h); + $this->_out($this->getCellCode($w, $h, $txt, $border, $ln, $align, $fill, $link, $stretch, $ignore_min_height)); + } + + /** + * Removes SHY characters from text. + * @param string $txt input string + * @return string without SHY characters. + * @access public + * @since (4.5.019) 2009-02-28 + */ + public function removeSHY($txt='') { + /* + * Unicode Data + * Name : SOFT HYPHEN, commonly abbreviated as SHY + * HTML Entity (decimal): ­ + * HTML Entity (hex): ­ + * HTML Entity (named): ­ + * How to type in Microsoft Windows: [Alt +00AD] or [Alt 0173] + * UTF-8 (hex): 0xC2 0xAD (c2ad) + * UTF-8 character: chr(194).chr(173) + */ + $txt = preg_replace('/([\\xc2]{1}[\\xad]{1})/', '', $txt); + if (!$this->isunicode) { + $txt = preg_replace('/([\\xad]{1})/', '', $txt); + } + return $txt; + } + + /** + * Returns the PDF string code to print a cell (rectangular area) with optional borders, background color and character string. The upper-left corner of the cell corresponds to the current position. The text can be aligned or centered. After the call, the current position moves to the right or to the next line. It is possible to put a link on the text.
    + * If automatic page breaking is enabled and the cell goes beyond the limit, a page break is done before outputting. + * @param float $w Cell width. If 0, the cell extends up to the right margin. + * @param float $h Cell height. Default value: 0. + * @param string $txt String to print. Default value: empty string. + * @param mixed $border Indicates if borders must be drawn around the cell. The value can be either a number:
    • 0: no border (default)
    • 1: frame
    or a string containing some or all of the following characters (in any order):
    • L: left
    • T: top
    • R: right
    • B: bottom
    + * @param int $ln Indicates where the current position should go after the call. Possible values are:
    • 0: to the right (or left for RTL languages)
    • 1: to the beginning of the next line
    • 2: below
    Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: 0. + * @param string $align Allows to center or align the text. Possible values are:
    • L or empty string: left align (default value)
    • C: center
    • R: right align
    • J: justify
    + * @param int $fill Indicates if the cell background must be painted (1) or transparent (0). Default value: 0. + * @param mixed $link URL or identifier returned by AddLink(). + * @param int $stretch stretch carachter mode:
    • 0 = disabled
    • 1 = horizontal scaling only if necessary
    • 2 = forced horizontal scaling
    • 3 = character spacing only if necessary
    • 4 = forced character spacing
    + * @param boolean $ignore_min_height if true ignore automatic minimum height value. + * @access protected + * @since 1.0 + * @see Cell() + */ + protected function getCellCode($w, $h=0, $txt='', $border=0, $ln=0, $align='', $fill=0, $link='', $stretch=0, $ignore_min_height=false) { + $txt = $this->removeSHY($txt); + $rs = ''; //string to be returned + if (!$ignore_min_height) { + $min_cell_height = $this->FontSize * $this->cell_height_ratio; + if ($h < $min_cell_height) { + $h = $min_cell_height; + } + } + $k = $this->k; + if ($this->empty_string($w) OR ($w <= 0)) { + if ($this->rtl) { + $w = $this->x - $this->lMargin; + } else { + $w = $this->w - $this->rMargin - $this->x; + } + } + $s = ''; + if (($fill == 1) OR ($border == 1)) { + if ($fill == 1) { + $op = ($border == 1) ? 'B' : 'f'; + } else { + $op = 'S'; + } + if ($this->rtl) { + $xk = (($this->x - $w) * $k); + } else { + $xk = ($this->x * $k); + } + $s .= sprintf('%.2F %.2F %.2F %.2F re %s ', $xk, (($this->h - $this->y) * $k), ($w * $k), (-$h * $k), $op); + } + if (is_string($border)) { + $lm = ($this->LineWidth / 2); + $x = $this->x; + $y = $this->y; + if (strpos($border,'L') !== false) { + if ($this->rtl) { + $xk = ($x - $w) * $k; + } else { + $xk = $x * $k; + } + $s .= sprintf('%.2F %.2F m %.2F %.2F l S ', $xk, (($this->h - $y + $lm) * $k), $xk, (($this->h - ($y + $h + $lm)) * $k)); + } + if (strpos($border,'T') !== false) { + if ($this->rtl) { + $xk = ($x - $w + $lm) * $k; + $xwk = ($x - $lm) * $k; + } else { + $xk = ($x - $lm) * $k; + $xwk = ($x + $w + $lm) * $k; + } + $s .= sprintf('%.2F %.2F m %.2F %.2F l S ', $xk, (($this->h - $y) * $k), $xwk, (($this->h - $y) * $k)); + } + if (strpos($border,'R') !== false) { + if ($this->rtl) { + $xk = $x * $k; + } else { + $xk = ($x + $w) * $k; + } + $s .= sprintf('%.2F %.2F m %.2F %.2F l S ', $xk, (($this->h - $y + $lm) * $k), $xk, (($this->h - ($y + $h + $lm))* $k)); + } + if (strpos($border,'B') !== false) { + if ($this->rtl) { + $xk = ($x - $w + $lm) * $k; + $xwk = ($x - $lm) * $k; + } else { + $xk = ($x - $lm) * $k; + $xwk = ($x + $w + $lm) * $k; + } + $s .= sprintf('%.2F %.2F m %.2F %.2F l S ', $xk, (($this->h - ($y + $h)) * $k), $xwk, (($this->h - ($y + $h)) * $k)); + } + } + if ($txt != '') { + // text lenght + $width = $this->GetStringWidth($txt); + // ratio between cell lenght and text lenght + $ratio = ($w - (2 * $this->cMargin)) / $width; + + // stretch text if required + if (($stretch > 0) AND (($ratio < 1) OR (($ratio > 1) AND (($stretch % 2) == 0)))) { + if ($stretch > 2) { + // spacing + //Calculate character spacing in points + $char_space = (($w - $width - (2 * $this->cMargin)) * $this->k) / max($this->GetNumChars($txt)-1,1); + //Set character spacing + $rs .= sprintf('BT %.2F Tc ET ', $char_space); + } else { + // scaling + //Calculate horizontal scaling + $horiz_scale = $ratio * 100.0; + //Set horizontal scaling + $rs .= sprintf('BT %.2F Tz ET ', $horiz_scale); + } + $align = ''; + $width = $w - (2 * $this->cMargin); + } else { + $stretch == 0; + } + if ($align == 'L') { + if ($this->rtl) { + $dx = $w - $width - $this->cMargin; + } else { + $dx = $this->cMargin; + } + } elseif ($align == 'R') { + if ($this->rtl) { + $dx = $this->cMargin; + } else { + $dx = $w - $width - $this->cMargin; + } + } elseif ($align == 'C') { + $dx = ($w - $width) / 2; + } elseif ($align == 'J') { + if ($this->rtl) { + $dx = $w - $width - $this->cMargin; + } else { + $dx = $this->cMargin; + } + } else { + $dx = $this->cMargin; + } + if ($this->ColorFlag) { + $s .= 'q '.$this->TextColor.' '; + } + $txt2 = $this->_escapetext($txt); + if ($this->rtl) { + $xdk = ($this->x - $dx - $width) * $k; + } else { + $xdk = ($this->x + $dx) * $k; + } + // Justification + if ($align == 'J') { + // count number of spaces + $ns = substr_count($txt, ' '); + if (($this->CurrentFont['type'] == 'TrueTypeUnicode') OR ($this->CurrentFont['type'] == 'cidfont0')) { + // get string width without spaces + $width = $this->GetStringWidth(str_replace(' ', '', $txt)); + // calculate average space width + $spacewidth = ($w - $width - (2 * $this->cMargin)) / ($ns?$ns:1) / $this->FontSize / $this->k; + // set word position to be used with TJ operator + $txt2 = str_replace(chr(0).' ', ') '.(-2830 * $spacewidth).' (', $txt2); + } else { + // get string width + $width = $this->GetStringWidth($txt); + $spacewidth = (($w - $width - (2 * $this->cMargin)) / ($ns?$ns:1)) * $this->k; + $rs .= sprintf('BT %.3F Tw ET ', $spacewidth); + } + } + // calculate approximate position of the font base line + //$basefonty = $this->y + (($h + $this->FontAscent - $this->FontDescent)/2); + $basefonty = $this->y + ($h/2) + ($this->FontSize/3); + // print text + $s .= sprintf('BT %.2F %.2F Td [(%s)] TJ ET', $xdk, (($this->h - $basefonty) * $k), $txt2); + if ($this->rtl) { + $xdx = $this->x - $dx - $width; + } else { + $xdx = $this->x + $dx; + } + if ($this->underline) { + $s .= ' '.$this->_dounderline($xdx, $basefonty, $txt); + } + if ($this->linethrough) { + $s .= ' '.$this->_dolinethrough($xdx, $basefonty, $txt); + } + if ($this->ColorFlag) { + $s .= ' Q'; + } + if ($link) { + $this->Link($xdx, $this->y + (($h - $this->FontSize)/2), $width, $this->FontSize, $link, substr_count($txt, chr(32))); + } + } + // output cell + if ($s) { + // output cell + $rs .= $s; + // reset text stretching + if ($stretch > 2) { + //Reset character horizontal spacing + $rs .= ' BT 0 Tc ET'; + } elseif ($stretch > 0) { + //Reset character horizontal scaling + $rs .= ' BT 100 Tz ET'; + } + } + // reset word spacing + if (!(($this->CurrentFont['type'] == 'TrueTypeUnicode') OR ($this->CurrentFont['type'] == 'cidfont0')) AND ($align == 'J')) { + $rs .= ' BT 0 Tw ET'; + } + $this->lasth = $h; + if ($ln > 0) { + //Go to the beginning of the next line + $this->y += $h; + if ($ln == 1) { + if ($this->rtl) { + $this->x = $this->w - $this->rMargin; + } else { + $this->x = $this->lMargin; + } + } + } else { + // go left or right by case + if ($this->rtl) { + $this->x -= $w; + } else { + $this->x += $w; + } + } + $gstyles = ''.$this->linestyleWidth.' '.$this->linestyleCap.' '.$this->linestyleJoin.' '.$this->linestyleDash.' '.$this->DrawColor.' '.$this->FillColor."\n"; + $rs = $gstyles.$rs; + return $rs; + } + + /** + * This method allows printing text with line breaks. + * They can be automatic (as soon as the text reaches the right border of the cell) or explicit (via the \n character). As many cells as necessary are output, one below the other.
    + * Text can be aligned, centered or justified. The cell block can be framed and the background painted. + * @param float $w Width of cells. If 0, they extend up to the right margin of the page. + * @param float $h Cell minimum height. The cell extends automatically if needed. + * @param string $txt String to print + * @param mixed $border Indicates if borders must be drawn around the cell block. The value can be either a number:
    • 0: no border (default)
    • 1: frame
    or a string containing some or all of the following characters (in any order):
    • L: left
    • T: top
    • R: right
    • B: bottom
    + * @param string $align Allows to center or align the text. Possible values are:
    • L or empty string: left align
    • C: center
    • R: right align
    • J: justification (default value when $ishtml=false)
    + * @param int $fill Indicates if the cell background must be painted (1) or transparent (0). Default value: 0. + * @param int $ln Indicates where the current position should go after the call. Possible values are:
    • 0: to the right
    • 1: to the beginning of the next line [DEFAULT]
    • 2: below
    + * @param int $x x position in user units + * @param int $y y position in user units + * @param boolean $reseth if true reset the last cell height (default true). + * @param int $stretch stretch carachter mode:
    • 0 = disabled
    • 1 = horizontal scaling only if necessary
    • 2 = forced horizontal scaling
    • 3 = character spacing only if necessary
    • 4 = forced character spacing
    + * @param boolean $ishtml set to true if $txt is HTML content (default = false). + * @param boolean $autopadding if true, uses internal padding and automatically adjust it to account for line width. + * @param float $maxh maximum height. It should be >= $h and less then remaining space to the bottom of the page, or 0 for disable this feature. This feature works only when $ishtml=false. + * @return int Return the number of cells or 1 for html mode. + * @access public + * @since 1.3 + * @see SetFont(), SetDrawColor(), SetFillColor(), SetTextColor(), SetLineWidth(), Cell(), Write(), SetAutoPageBreak() + */ + public function MultiCell($w, $h, $txt, $border=0, $align='J', $fill=0, $ln=1, $x='', $y='', $reseth=true, $stretch=0, $ishtml=false, $autopadding=true, $maxh=0) { + if ($this->empty_string($this->lasth) OR $reseth) { + //set row height + $this->lasth = $this->FontSize * $this->cell_height_ratio; + } + if (!$this->empty_string($y)) { + $this->SetY($y); + } else { + $y = $this->GetY(); + } + // check for page break + $this->checkPageBreak($h); + $y = $this->GetY(); + // get current page number + $startpage = $this->page; + if (!$this->empty_string($x)) { + $this->SetX($x); + } else { + $x = $this->GetX(); + } + if ($this->empty_string($w) OR ($w <= 0)) { + if ($this->rtl) { + $w = $this->x - $this->lMargin; + } else { + $w = $this->w - $this->rMargin - $this->x; + } + } + // store original margin values + $lMargin = $this->lMargin; + $rMargin = $this->rMargin; + if ($this->rtl) { + $this->SetRightMargin($this->w - $this->x); + $this->SetLeftMargin($this->x - $w); + } else { + $this->SetLeftMargin($this->x); + $this->SetRightMargin($this->w - $this->x - $w); + } + $starty = $this->y; + if ($autopadding) { + // Adjust internal padding + if ($this->cMargin < ($this->LineWidth / 2)) { + $this->cMargin = ($this->LineWidth / 2); + } + // Add top space if needed + if (($this->lasth - $this->FontSize) < $this->LineWidth) { + $this->y += $this->LineWidth / 2; + } + // add top padding + $this->y += $this->cMargin; + } + if ($ishtml) { + // ******* Write HTML text + $this->writeHTML($txt, true, 0, $reseth, true, $align); + $nl = 1; + } else { + // ******* Write text + $nl = $this->Write($this->lasth, $txt, '', 0, $align, true, $stretch, false, false, $maxh); + } + if ($autopadding) { + // add bottom padding + $this->y += $this->cMargin; + // Add bottom space if needed + if (($this->lasth - $this->FontSize) < $this->LineWidth) { + $this->y += $this->LineWidth / 2; + } + } + // Get end-of-text Y position + $currentY = $this->y; + // get latest page number + $endpage = $this->page; + // check if a new page has been created + if ($endpage > $startpage) { + // design borders around HTML cells. + for ($page=$startpage; $page <= $endpage; ++$page) { + $this->setPage($page); + if ($page == $startpage) { + $this->y = $starty; // put cursor at the beginning of cell on the first page + $h = $this->getPageHeight() - $starty - $this->getBreakMargin(); + $cborder = $this->getBorderMode($border, $position='start'); + } elseif ($page == $endpage) { + $this->y = $this->tMargin; // put cursor at the beginning of last page + $h = $currentY - $this->tMargin; + $cborder = $this->getBorderMode($border, $position='end'); + } else { + $this->y = $this->tMargin; // put cursor at the beginning of the current page + $h = $this->getPageHeight() - $this->tMargin - $this->getBreakMargin(); + $cborder = $this->getBorderMode($border, $position='middle'); + } + $nx = $x; + // account for margin changes + if ($page > $startpage) { + if (($this->rtl) AND ($this->pagedim[$page]['orm'] != $this->pagedim[$startpage]['orm'])) { + $nx = $x + ($this->pagedim[$page]['orm'] - $this->pagedim[$startpage]['orm']); + } elseif ((!$this->rtl) AND ($this->pagedim[$page]['olm'] != $this->pagedim[$startpage]['olm'])) { + $nx = $x + ($this->pagedim[$page]['olm'] - $this->pagedim[$startpage]['olm']); + } + } + $this->SetX($nx); + $ccode = $this->getCellCode($w, $h, '', $cborder, 1, '', $fill, '', 0, false); + if ($cborder OR $fill) { + $pagebuff = $this->getPageBuffer($this->page); + $pstart = substr($pagebuff, 0, $this->intmrk[$this->page]); + $pend = substr($pagebuff, $this->intmrk[$this->page]); + $this->setPageBuffer($this->page, $pstart.$ccode."\n".$pend); + $this->intmrk[$this->page] += strlen($ccode."\n"); + } + } + } else { + $h = max($h, ($currentY - $y)); + // put cursor at the beginning of text + $this->SetY($y); + $this->SetX($x); + // design a cell around the text + $ccode = $this->getCellCode($w, $h, '', $border, 1, '', $fill, '', 0, true); + if ($border OR $fill) { + if (end($this->transfmrk[$this->page]) !== false) { + $pagemarkkey = key($this->transfmrk[$this->page]); + $pagemark = &$this->transfmrk[$this->page][$pagemarkkey]; + } elseif ($this->InFooter) { + $pagemark = &$this->footerpos[$this->page]; + } else { + $pagemark = &$this->intmrk[$this->page]; + } + $pagebuff = $this->getPageBuffer($this->page); + $pstart = substr($pagebuff, 0, $pagemark); + $pend = substr($pagebuff, $pagemark); + $this->setPageBuffer($this->page, $pstart.$ccode."\n".$pend); + $pagemark += strlen($ccode."\n"); + } + } + // Get end-of-cell Y position + $currentY = $this->GetY(); + // restore original margin values + $this->SetLeftMargin($lMargin); + $this->SetRightMargin($rMargin); + if ($ln > 0) { + //Go to the beginning of the next line + $this->SetY($currentY); + if ($ln == 2) { + $this->SetX($x + $w); + } + } else { + // go left or right by case + $this->setPage($startpage); + $this->y = $y; + $this->SetX($x + $w); + } + return $nl; + } + + /** + * Get the border mode accounting for multicell position (opens bottom side of multicell crossing pages) + * @param mixed $border Indicates if borders must be drawn around the cell block. The value can be either a number:
    • 0: no border (default)
    • 1: frame
    or a string containing some or all of the following characters (in any order):
    • L: left
    • T: top
    • R: right
    • B: bottom
    + * @param string multicell position: 'start', 'middle', 'end' + * @return border mode + * @access protected + * @since 4.4.002 (2008-12-09) + */ + protected function getBorderMode($border, $position='start') { + if ((!$this->opencell) AND ($border == 1)) { + return 1; + } + $cborder = ''; + switch ($position) { + case 'start': { + if ($border == 1) { + $cborder = 'LTR'; + } else { + if (!(false === strpos($border, 'L'))) { + $cborder .= 'L'; + } + if (!(false === strpos($border, 'T'))) { + $cborder .= 'T'; + } + if (!(false === strpos($border, 'R'))) { + $cborder .= 'R'; + } + if ((!$this->opencell) AND (!(false === strpos($border, 'B')))) { + $cborder .= 'B'; + } + } + break; + } + case 'middle': { + if ($border == 1) { + $cborder = 'LR'; + } else { + if (!(false === strpos($border, 'L'))) { + $cborder .= 'L'; + } + if ((!$this->opencell) AND (!(false === strpos($border, 'T')))) { + $cborder .= 'T'; + } + if (!(false === strpos($border, 'R'))) { + $cborder .= 'R'; + } + if ((!$this->opencell) AND (!(false === strpos($border, 'B')))) { + $cborder .= 'B'; + } + } + break; + } + case 'end': { + if ($border == 1) { + $cborder = 'LRB'; + } else { + if (!(false === strpos($border, 'L'))) { + $cborder .= 'L'; + } + if ((!$this->opencell) AND (!(false === strpos($border, 'T')))) { + $cborder .= 'T'; + } + if (!(false === strpos($border, 'R'))) { + $cborder .= 'R'; + } + if (!(false === strpos($border, 'B'))) { + $cborder .= 'B'; + } + } + break; + } + default: { + $cborder = $border; + break; + } + } + return $cborder; + } + + /** + * This method returns the estimated number of lines required to print the text. + * @param string $txt text to print + * @param float $w width of cell. If 0, they extend up to the right margin of the page. + * @return int Return the estimated number of lines. + * @access public + * @since 4.5.011 + */ + public function getNumLines($txt, $w=0) { + $lines = 0; + if ($this->empty_string($w) OR ($w <= 0)) { + if ($this->rtl) { + $w = $this->x - $this->lMargin; + } else { + $w = $this->w - $this->rMargin - $this->x; + } + } + // max column width + $wmax = $w - (2 * $this->cMargin); + // remove carriage returns + $txt = str_replace("\r", '', $txt); + // remove last newline (if any) + if (substr($txt,-1) == "\n") { + $txt = substr($txt, 0, -1); + } + // divide text in blocks + $txtblocks = explode("\n", $txt); + // for each block; + foreach ($txtblocks as $block) { + // estimate the number of lines + $lines += $this->empty_string($block) ? 1 : (ceil($this->GetStringWidth($block) / $wmax)); + } + return $lines; + } + + /** + * This method prints text from the current position.
    + * @param float $h Line height + * @param string $txt String to print + * @param mixed $link URL or identifier returned by AddLink() + * @param int $fill Indicates if the background must be painted (1) or transparent (0). Default value: 0. + * @param string $align Allows to center or align the text. Possible values are:
    • L or empty string: left align (default value)
    • C: center
    • R: right align
    • J: justify
    + * @param boolean $ln if true set cursor at the bottom of the line, otherwise set cursor at the top of the line. + * @param int $stretch stretch carachter mode:
    • 0 = disabled
    • 1 = horizontal scaling only if necessary
    • 2 = forced horizontal scaling
    • 3 = character spacing only if necessary
    • 4 = forced character spacing
    + * @param boolean $firstline if true prints only the first line and return the remaining string. + * @param boolean $firstblock if true the string is the starting of a line. + * @param float $maxh maximum height. The remaining unprinted text will be returned. It should be >= $h and less then remaining space to the bottom of the page, or 0 for disable this feature. + * @return mixed Return the number of cells or the remaining string if $firstline = true. + * @access public + * @since 1.5 + */ + public function Write($h, $txt, $link='', $fill=0, $align='', $ln=false, $stretch=0, $firstline=false, $firstblock=false, $maxh=0) { + if (strlen($txt) == 0) { + $txt = ' '; + } + // remove carriage returns + $s = str_replace("\r", '', $txt); + // check if string contains arabic text + if (preg_match(K_RE_PATTERN_ARABIC, $s)) { + $arabic = true; + } else { + $arabic = false; + } + // check if string contains RTL text + if ($arabic OR $this->tmprtl OR preg_match(K_RE_PATTERN_RTL, $txt)) { + $rtlmode = true; + } else { + $rtlmode = false; + } + // get a char width + $chrwidth = $this->GetCharWidth('.'); + // get array of unicode values + $chars = $this->UTF8StringToArray($s); + // get array of chars + $uchars = $this->UTF8ArrayToUniArray($chars); + // get the number of characters + $nb = count($chars); + // replacement for SHY character (minus symbol) + $shy_replacement = 45; + $shy_replacement_char = $this->unichr($shy_replacement); + // widht for SHY replacement + $shy_replacement_width = $this->GetCharWidth($shy_replacement); + // store current position + $prevx = $this->x; + $prevy = $this->y; + // max Y + $maxy = $this->y + $maxh - $h - (2 * $this->cMargin); + // calculate remaining line width ($w) + if ($this->rtl) { + $w = $this->x - $this->lMargin; + } else { + $w = $this->w - $this->rMargin - $this->x; + } + // max column width + $wmax = $w - (2 * $this->cMargin); + if ($chrwidth > $wmax) { + // a single character do not fit on column + return ''; + } + $i = 0; // character position + $j = 0; // current starting position + $sep = -1; // position of the last blank space + $shy = false; // true if the last blank is a soft hypen (SHY) + $l = 0; // current string lenght + $nl = 0; //number of lines + $linebreak = false; + // for each character + while ($i < $nb) { + if (($maxh > 0) AND ($this->y >= $maxy) ) { + $firstline = true; + } + //Get the current character + $c = $chars[$i]; + if ($c == 10) { // 10 = "\n" = new line + //Explicit line break + if ($align == 'J') { + if ($this->rtl) { + $talign = 'R'; + } else { + $talign = 'L'; + } + } else { + $talign = $align; + } + $tmpstr = $this->UniArrSubString($uchars, $j, $i); + if ($firstline) { + $startx = $this->x; + $tmparr = array_slice($chars, $j, $i); + if ($rtlmode) { + $tmparr = $this->utf8Bidi($tmparr, $tmpstr, $this->tmprtl); + } + $linew = $this->GetArrStringWidth($tmparr); + unset($tmparr); + if ($this->rtl) { + $this->endlinex = $startx - $linew; + } else { + $this->endlinex = $startx + $linew; + } + $w = $linew; + $tmpcmargin = $this->cMargin; + if ($maxh == 0) { + $this->cMargin = 0; + } + } + $this->Cell($w, $h, $tmpstr, 0, 1, $talign, $fill, $link, $stretch); + unset($tmpstr); + if ($firstline) { + $this->cMargin = $tmpcmargin; + return ($this->UniArrSubString($uchars, $i)); + } + ++$nl; + $j = $i + 1; + $l = 0; + $sep = -1; + $shy = false; + // account for margin changes + if ((($this->y + $this->lasth) > $this->PageBreakTrigger) AND (!$this->InFooter)) { + // AcceptPageBreak() may be overriden on extended classed to include margin changes + $this->AcceptPageBreak(); + } + $w = $this->getRemainingWidth(); + $wmax = $w - (2 * $this->cMargin); + } else { + // 160 is the non-breaking space. + // 173 is SHY (Soft Hypen). + // \p{Z} or \p{Separator}: any kind of Unicode whitespace or invisible separator. + // \p{Lo} or \p{Other_Letter}: a Unicode letter or ideograph that does not have lowercase and uppercase variants. + // \p{Lo} is needed because Chinese characters are packed next to each other without spaces in between. + if (($c != 160) AND (($c == 173) OR preg_match($this->re_spaces, $this->unichr($c)))) { + // update last blank space position + $sep = $i; + // check if is a SHY + if ($c == 173) { + $shy = true; + } else { + $shy = false; + } + } + // update string length + if ((($this->CurrentFont['type'] == 'TrueTypeUnicode') OR ($this->CurrentFont['type'] == 'cidfont0')) AND ($arabic)) { + // with bidirectional algorithm some chars may be changed affecting the line length + // *** very slow *** + $l = $this->GetArrStringWidth($this->utf8Bidi(array_slice($chars, $j, $i-$j+1), '', $this->tmprtl)); + } else { + $l += $this->GetCharWidth($c); + } + if (($l > $wmax) OR ($shy AND (($l + $shy_replacement_width) > $wmax)) ) { + // we have reached the end of column + if ($sep == -1) { + // check if the line was already started + if (($this->rtl AND ($this->x <= ($this->w - $this->rMargin - $chrwidth))) + OR ((!$this->rtl) AND ($this->x >= ($this->lMargin + $chrwidth)))) { + // print a void cell and go to next line + $this->Cell($w, $h, '', 0, 1); + $linebreak = true; + if ($firstline) { + return ($this->UniArrSubString($uchars, $j)); + } + } else { + // truncate the word because do not fit on column + $tmpstr = $this->UniArrSubString($uchars, $j, $i); + if ($firstline) { + $startx = $this->x; + $tmparr = array_slice($chars, $j, $i); + if ($rtlmode) { + $tmparr = $this->utf8Bidi($tmparr, $tmpstr, $this->tmprtl); + } + $linew = $this->GetArrStringWidth($tmparr); + unset($tmparr); + if ($this->rtl) { + $this->endlinex = $startx - $linew; + } else { + $this->endlinex = $startx + $linew; + } + $w = $linew; + $tmpcmargin = $this->cMargin; + if ($maxh == 0) { + $this->cMargin = 0; + } + } + $this->Cell($w, $h, $tmpstr, 0, 1, $align, $fill, $link, $stretch); + unset($tmpstr); + if ($firstline) { + $this->cMargin = $tmpcmargin; + return ($this->UniArrSubString($uchars, $i)); + } + $j = $i; + --$i; + } + } else { + // word wrapping + if ($this->rtl AND (!$firstblock)) { + $endspace = 1; + } else { + $endspace = 0; + } + if ($shy) { + // add hypen (minus symbol) at the end of the line + $shy_width = $shy_replacement_width; + if ($this->rtl) { + $shy_char_left = $shy_replacement_char; + $shy_char_right = ''; + } else { + $shy_char_left = ''; + $shy_char_right = $shy_replacement_char; + } + } else { + $shy_width = 0; + $shy_char_left = ''; + $shy_char_right = ''; + } + $tmpstr = $this->UniArrSubString($uchars, $j, ($sep + $endspace)); + if ($firstline) { + $startx = $this->x; + $tmparr = array_slice($chars, $j, ($sep + $endspace)); + if ($rtlmode) { + $tmparr = $this->utf8Bidi($tmparr, $tmpstr, $this->tmprtl); + } + $linew = $this->GetArrStringWidth($tmparr); + unset($tmparr); + if ($this->rtl) { + $this->endlinex = $startx - $linew - $shy_width; + } else { + $this->endlinex = $startx + $linew + $shy_width; + } + $w = $linew; + $tmpcmargin = $this->cMargin; + if ($maxh == 0) { + $this->cMargin = 0; + } + } + // print the line + $this->Cell($w, $h, $shy_char_left.$tmpstr.$shy_char_right, 0, 1, $align, $fill, $link, $stretch); + unset($tmpstr); + if ($firstline) { + // return the remaining text + $this->cMargin = $tmpcmargin; + return ($this->UniArrSubString($uchars, ($sep + $endspace))); + } + $i = $sep; + $sep = -1; + $shy = false; + $j = ($i+1); + } + // account for margin changes + if ((($this->y + $this->lasth) > $this->PageBreakTrigger) AND (!$this->InFooter)) { + // AcceptPageBreak() may be overriden on extended classed to include margin changes + $this->AcceptPageBreak(); + } + $w = $this->getRemainingWidth(); + $wmax = $w - (2 * $this->cMargin); + if ($linebreak) { + $linebreak = false; + } else { + ++$nl; + $l = 0; + } + } + } + ++$i; + } // end while i < nb + // print last substring (if any) + if ($l > 0) { + switch ($align) { + case 'J': + case 'C': { + $w = $w; + break; + } + case 'L': { + if ($this->rtl) { + $w = $w; + } else { + $w = $l; + } + break; + } + case 'R': { + if ($this->rtl) { + $w = $l; + } else { + $w = $w; + } + break; + } + default: { + $w = $l; + break; + } + } + $tmpstr = $this->UniArrSubString($uchars, $j, $nb); + if ($firstline) { + $startx = $this->x; + $tmparr = array_slice($chars, $j, $nb); + if ($rtlmode) { + $tmparr = $this->utf8Bidi($tmparr, $tmpstr, $this->tmprtl); + } + $linew = $this->GetArrStringWidth($tmparr); + unset($tmparr); + if ($this->rtl) { + $this->endlinex = $startx - $linew; + } else { + $this->endlinex = $startx + $linew; + } + $w = $linew; + $tmpcmargin = $this->cMargin; + if ($maxh == 0) { + $this->cMargin = 0; + } + } + $this->Cell($w, $h, $tmpstr, 0, $ln, $align, $fill, $link, $stretch); + unset($tmpstr); + if ($firstline) { + $this->cMargin = $tmpcmargin; + return ($this->UniArrSubString($uchars, $nb)); + } + ++$nl; + } + if ($firstline) { + return ''; + } + return $nl; + } + + /** + * Returns the remaining width between the current position and margins. + * @return int Return the remaining width + * @access protected + */ + protected function getRemainingWidth() { + if ($this->rtl) { + return ($this->x - $this->lMargin); + } else { + return ($this->w - $this->rMargin - $this->x); + } + } + + /** + * Extract a slice of the $strarr array and return it as string. + * @param string $strarr The input array of characters. + * @param int $start the starting element of $strarr. + * @param int $end first element that will not be returned. + * @return Return part of a string + * @access public + */ + public function UTF8ArrSubString($strarr, $start='', $end='') { + if (strlen($start) == 0) { + $start = 0; + } + if (strlen($end) == 0) { + $end = count($strarr); + } + $string = ''; + for ($i=$start; $i < $end; ++$i) { + $string .= $this->unichr($strarr[$i]); + } + return $string; + } + + /** + * Extract a slice of the $uniarr array and return it as string. + * @param string $uniarr The input array of characters. + * @param int $start the starting element of $strarr. + * @param int $end first element that will not be returned. + * @return Return part of a string + * @access public + * @since 4.5.037 (2009-04-07) + */ + public function UniArrSubString($uniarr, $start='', $end='') { + if (strlen($start) == 0) { + $start = 0; + } + if (strlen($end) == 0) { + $end = count($uniarr); + } + $string = ''; + for ($i=$start; $i < $end; ++$i) { + $string .= $uniarr[$i]; + } + return $string; + } + + /** + * Convert an array of UTF8 values to array of unicode characters + * @param string $ta The input array of UTF8 values. + * @return Return array of unicode characters + * @access public + * @since 4.5.037 (2009-04-07) + */ + public function UTF8ArrayToUniArray($ta) { + return array_map(array($this, 'unichr'), $ta); + } + + /** + * Returns the unicode caracter specified by UTF-8 code + * @param int $c UTF-8 code + * @return Returns the specified character. + * @author Miguel Perez, Nicola Asuni + * @access public + * @since 2.3.000 (2008-03-05) + */ + public function unichr($c) { + if (!$this->isunicode) { + return chr($c); + } elseif ($c <= 0x7F) { + // one byte + return chr($c); + } elseif ($c <= 0x7FF) { + // two bytes + return chr(0xC0 | $c >> 6).chr(0x80 | $c & 0x3F); + } elseif ($c <= 0xFFFF) { + // three bytes + return chr(0xE0 | $c >> 12).chr(0x80 | $c >> 6 & 0x3F).chr(0x80 | $c & 0x3F); + } elseif ($c <= 0x10FFFF) { + // four bytes + return chr(0xF0 | $c >> 18).chr(0x80 | $c >> 12 & 0x3F).chr(0x80 | $c >> 6 & 0x3F).chr(0x80 | $c & 0x3F); + } else { + return ''; + } + } + + /** + * Puts an image in the page. + * The upper-left corner must be given. + * The dimensions can be specified in different ways:
      + *
    • explicit width and height (expressed in user unit)
    • + *
    • one explicit dimension, the other being calculated automatically in order to keep the original proportions
    • + *
    • no explicit dimension, in which case the image is put at 72 dpi
    + * Supported formats are JPEG and PNG images whitout GD library and all images supported by GD: GD, GD2, GD2PART, GIF, JPEG, PNG, BMP, XBM, XPM; + * The format can be specified explicitly or inferred from the file extension.
    + * It is possible to put a link on the image.
    + * Remark: if an image is used several times, only one copy will be embedded in the file.
    + * @param string $file Name of the file containing the image. + * @param float $x Abscissa of the upper-left corner. + * @param float $y Ordinate of the upper-left corner. + * @param float $w Width of the image in the page. If not specified or equal to zero, it is automatically calculated. + * @param float $h Height of the image in the page. If not specified or equal to zero, it is automatically calculated. + * @param string $type Image format. Possible values are (case insensitive): JPEG and PNG (whitout GD library) and all images supported by GD: GD, GD2, GD2PART, GIF, JPEG, PNG, BMP, XBM, XPM;. If not specified, the type is inferred from the file extension. + * @param mixed $link URL or identifier returned by AddLink(). + * @param string $align Indicates the alignment of the pointer next to image insertion relative to image height. The value can be:
    • T: top-right for LTR or top-left for RTL
    • M: middle-right for LTR or middle-left for RTL
    • B: bottom-right for LTR or bottom-left for RTL
    • N: next line
    + * @param boolean $resize If true resize (reduce) the image to fit $w and $h (requires GD library). + * @param int $dpi dot-per-inch resolution used on resize + * @param string $palign Allows to center or align the image on the current line. Possible values are:
    • L : left align
    • C : center
    • R : right align
    • '' : empty string : left for LTR or right for RTL
    + * @param boolean $ismask true if this image is a mask, false otherwise + * @param mixed $imgmask image object returned by this function or false + * @param mixed $border Indicates if borders must be drawn around the image. The value can be either a number:
    • 0: no border (default)
    • 1: frame
    or a string containing some or all of the following characters (in any order):
    • L: left
    • T: top
    • R: right
    • B: bottom
    + * @param boolean $fitbox If true scale image dimensions proportionally to fit within the ($w, $h) box. + * @return image information + * @access public + * @since 1.1 + */ + public function Image($file, $x='', $y='', $w=0, $h=0, $type='', $link='', $align='', $resize=false, $dpi=300, $palign='', $ismask=false, $imgmask=false, $border=0, $fitbox=false) { + if ($x === '') { + $x = $this->x; + } + if ($y === '') { + $y = $this->y; + } + // get image dimensions + $imsize = @getimagesize($file); + if ($imsize === FALSE) { + // encode spaces on filename + $file = str_replace(' ', '%20', $file); + $imsize = @getimagesize($file); + if ($imsize === FALSE) { + $this->Error('[Image] No such file or directory in '.$file); + } + } + // get original image width and height in pixels + list($pixw, $pixh) = $imsize; + // calculate image width and height on document + if (($w <= 0) AND ($h <= 0)) { + // convert image size to document unit + $w = $this->pixelsToUnits($pixw); + $h = $this->pixelsToUnits($pixh); + } elseif ($w <= 0) { + $w = $h * $pixw / $pixh; + } elseif ($h <= 0) { + $h = $w * $pixh / $pixw; + } elseif ($fitbox AND ($w > 0) AND ($h > 0)) { + // scale image dimensions proportionally to fit within the ($w, $h) box + if ((($w * $pixh) / ($h * $pixw)) < 1) { + $h = $w * $pixh / $pixw; + } else { + $w = $h * $pixw / $pixh; + } + } + // calculate new minimum dimensions in pixels + $neww = round($w * $this->k * $dpi / $this->dpi); + $newh = round($h * $this->k * $dpi / $this->dpi); + // check if resize is necessary (resize is used only to reduce the image) + if (($neww * $newh) >= ($pixw * $pixh)) { + $resize = false; + } + // check if image has been already added on document + if (!in_array($file, $this->imagekeys)) { + //First use of image, get info + if ($type == '') { + $fileinfo = pathinfo($file); + if (isset($fileinfo['extension']) AND (!$this->empty_string($fileinfo['extension']))) { + $type = $fileinfo['extension']; + } else { + $this->Error('Image file has no extension and no type was specified: '.$file); + } + } + $type = strtolower($type); + if ($type == 'jpg') { + $type = 'jpeg'; + } + $mqr = get_magic_quotes_runtime(); + //set_magic_quotes_runtime(0); + // Specific image handlers + $mtd = '_parse'.$type; + // GD image handler function + $gdfunction = 'imagecreatefrom'.$type; + $info = false; + if ((method_exists($this, $mtd)) AND (!($resize AND function_exists($gdfunction)))) { + // TCPDF image functions + $info = $this->$mtd($file); + if ($info == 'pngalpha') { + return $this->ImagePngAlpha($file, $x, $y, $w, $h, 'PNG', $link, $align, $resize, $dpi, $palign); + } + } + if (!$info) { + if (function_exists($gdfunction)) { + // GD library + $img = $gdfunction($file); + if ($resize) { + $imgr = imagecreatetruecolor($neww, $newh); + imagecopyresampled($imgr, $img, 0, 0, 0, 0, $neww, $newh, $pixw, $pixh); + $info = $this->_toJPEG($imgr); + } else { + $info = $this->_toJPEG($img); + } + } elseif (extension_loaded('imagick')) { + // ImageMagick library + $img = new Imagick(); + $img->readImage($file); + if ($resize) { + $img->resizeImage($neww, $newh, 10, 1, false); + } + $img->setCompressionQuality($this->jpeg_quality); + $img->setImageFormat('jpeg'); + $tempname = tempnam(K_PATH_CACHE, 'jpg_'); + $img->writeImage($tempname); + $info = $this->_parsejpeg($tempname); + unlink($tempname); + $img->destroy(); + } + else if ($type == 'jpeg') { + $info = $this->_parsejpeg($file); + } + else { + return; + } + } + if ($info === false) { + //If false, we cannot process image + return; + } + //set_magic_quotes_runtime($mqr); + if ($ismask) { + // force grayscale + $info['cs'] = 'DeviceGray'; + } + $info['i'] = $this->numimages + 1; + if ($imgmask !== false) { + $info['masked'] = $imgmask; + } + // add image to document + $this->setImageBuffer($file, $info); + } else { + $info = $this->getImageBuffer($file); + } + // Check whether we need a new page first as this does not fit + if ($this->checkPageBreak($h, $y)) { + $y = $this->GetY() + $this->cMargin; + } + // set bottomcoordinates + $this->img_rb_y = $y + $h; + // set alignment + if ($this->rtl) { + if ($palign == 'L') { + $ximg = $this->lMargin; + // set right side coordinate + $this->img_rb_x = $ximg + $w; + } elseif ($palign == 'C') { + $ximg = ($this->w - $x - $w) / 2; + // set right side coordinate + $this->img_rb_x = $ximg + $w; + } else { + $ximg = $this->w - $x - $w; + // set left side coordinate + $this->img_rb_x = $ximg; + } + } else { + if ($palign == 'R') { + $ximg = $this->w - $this->rMargin - $w; + // set left side coordinate + $this->img_rb_x = $ximg; + } elseif ($palign == 'C') { + $ximg = ($this->w - $x - $w) / 2; + // set right side coordinate + $this->img_rb_x = $ximg + $w; + } else { + $ximg = $x; + // set right side coordinate + $this->img_rb_x = $ximg + $w; + } + } + if ($ismask) { + // embed hidden, ouside the canvas + $xkimg = ($this->pagedim[$this->page]['w'] + 10); + } else { + $xkimg = $ximg * $this->k; + } + $this->_out(sprintf('q %.2F 0 0 %.2F %.2F %.2F cm /I%d Do Q', ($w * $this->k), ($h * $this->k), $xkimg, (($this->h - ($y + $h)) * $this->k), $info['i'])); + if (!empty($border)) { + $bx = $x; + $by = $y; + $this->x = $ximg; + $this->y = $y; + $this->Cell($w, $h, '', $border, 0, '', 0, '', 0); + $this->x = $bx; + $this->y = $by; + } + if ($link) { + $this->Link($ximg, $y, $w, $h, $link, 0); + } + // set pointer to align the successive text/objects + switch($align) { + case 'T': { + $this->y = $y; + $this->x = $this->img_rb_x; + break; + } + case 'M': { + $this->y = $y + round($h/2); + $this->x = $this->img_rb_x; + break; + } + case 'B': { + $this->y = $this->img_rb_y; + $this->x = $this->img_rb_x; + break; + } + case 'N': { + $this->SetY($this->img_rb_y); + break; + } + default:{ + break; + } + } + $this->endlinex = $this->img_rb_x; + return $info['i']; + } + + /** + * Convert the loaded php image to a JPEG and then return a structure for the PDF creator. + * This function requires GD library and write access to the directory defined on K_PATH_CACHE constant. + * @param string $file Image file name. + * @param image $image Image object. + * return image JPEG image object. + * @access protected + */ + protected function _toJPEG($image) { + $tempname = tempnam(K_PATH_CACHE, 'jpg_'); + imagejpeg($image, $tempname, $this->jpeg_quality); + imagedestroy($image); + $retvars = $this->_parsejpeg($tempname); + // tidy up by removing temporary image + unlink($tempname); + return $retvars; + } + + /** + * Extract info from a JPEG file without using the GD library. + * @param string $file image file to parse + * @return array structure containing the image data + * @access protected + */ + protected function _parsejpeg($file) { + $a = getimagesize($file); + if (empty($a)) { + $this->Error('Missing or incorrect image file: '.$file); + } + if ($a[2] != 2) { + $this->Error('Not a JPEG file: '.$file); + } + if ((!isset($a['channels'])) OR ($a['channels'] == 3)) { + $colspace = 'DeviceRGB'; + } elseif ($a['channels'] == 4) { + $colspace = 'DeviceCMYK'; + } else { + $colspace = 'DeviceGray'; + } + $bpc = isset($a['bits']) ? $a['bits'] : 8; + $data = file_get_contents($file); + return array('w' => $a[0], 'h' => $a[1], 'cs' => $colspace, 'bpc' => $bpc, 'f' => 'DCTDecode', 'data' => $data); + } + + /** + * Extract info from a PNG file without using the GD library. + * @param string $file image file to parse + * @return array structure containing the image data + * @access protected + */ + protected function _parsepng($file) { + $f = fopen($file, 'rb'); + if ($f === false) { + $this->Error('Can\'t open image file: '.$file); + } + //Check signature + if (fread($f, 8) != chr(137).'PNG'.chr(13).chr(10).chr(26).chr(10)) { + $this->Error('Not a PNG file: '.$file); + } + //Read header chunk + fread($f, 4); + if (fread($f, 4) != 'IHDR') { + $this->Error('Incorrect PNG file: '.$file); + } + $w = $this->_freadint($f); + $h = $this->_freadint($f); + $bpc = ord(fread($f, 1)); + if ($bpc > 8) { + //$this->Error('16-bit depth not supported: '.$file); + fclose($f); + return false; + } + $ct = ord(fread($f, 1)); + if ($ct == 0) { + $colspace = 'DeviceGray'; + } elseif ($ct == 2) { + $colspace = 'DeviceRGB'; + } elseif ($ct == 3) { + $colspace = 'Indexed'; + } else { + // alpha channel + fclose($f); + return 'pngalpha'; + } + if (ord(fread($f, 1)) != 0) { + //$this->Error('Unknown compression method: '.$file); + fclose($f); + return false; + } + if (ord(fread($f, 1)) != 0) { + //$this->Error('Unknown filter method: '.$file); + fclose($f); + return false; + } + if (ord(fread($f, 1)) != 0) { + //$this->Error('Interlacing not supported: '.$file); + fclose($f); + return false; + } + fread($f, 4); + $parms = '/DecodeParms <>'; + //Scan chunks looking for palette, transparency and image data + $pal = ''; + $trns = ''; + $data = ''; + do { + $n = $this->_freadint($f); + $type = fread($f, 4); + if ($type == 'PLTE') { + //Read palette + $pal = $this->rfread($f, $n); + fread($f, 4); + } elseif ($type == 'tRNS') { + //Read transparency info + $t = $this->rfread($f, $n); + if ($ct == 0) { + $trns = array(ord(substr($t, 1, 1))); + } elseif ($ct == 2) { + $trns = array(ord(substr($t, 1, 1)), ord(substr($t, 3, 1)), ord(substr($t, 5, 1))); + } else { + $pos = strpos($t, chr(0)); + if ($pos !== false) { + $trns = array($pos); + } + } + fread($f, 4); + } elseif ($type == 'IDAT') { + //Read image data block + $data .= $this->rfread($f, $n); + fread($f, 4); + } elseif ($type == 'IEND') { + break; + } else { + $this->rfread($f, $n + 4); + } + } while ($n); + if (($colspace == 'Indexed') AND (empty($pal))) { + //$this->Error('Missing palette in '.$file); + fclose($f); + return false; + } + fclose($f); + return array('w' => $w, 'h' => $h, 'cs' => $colspace, 'bpc' => $bpc, 'f' => 'FlateDecode', 'parms' => $parms, 'pal' => $pal, 'trns' => $trns, 'data' => $data); + } + + /** + * Binary-safe and URL-safe file read. + * Reads up to length bytes from the file pointer referenced by handle. Reading stops as soon as one of the following conditions is met: length bytes have been read; EOF (end of file) is reached. + * @param resource $handle + * @param int $length + * @return Returns the read string or FALSE in case of error. + * @author Nicola Asuni + * @access protected + * @since 4.5.027 (2009-03-16) + */ + protected function rfread($handle, $length) { + $data = fread($handle, $length); + if ($data === false) { + return false; + } + $rest = $length - strlen($data); + if ($rest > 0) { + $data .= $this->rfread($handle, $rest); + } + return $data; + } + + /** + * Extract info from a PNG image with alpha channel using the GD library. + * @param string $file Name of the file containing the image. + * @param float $x Abscissa of the upper-left corner. + * @param float $y Ordinate of the upper-left corner. + * @param float $w Width of the image in the page. If not specified or equal to zero, it is automatically calculated. + * @param float $h Height of the image in the page. If not specified or equal to zero, it is automatically calculated. + * @param string $type Image format. Possible values are (case insensitive): JPEG and PNG (whitout GD library) and all images supported by GD: GD, GD2, GD2PART, GIF, JPEG, PNG, BMP, XBM, XPM;. If not specified, the type is inferred from the file extension. + * @param mixed $link URL or identifier returned by AddLink(). + * @param string $align Indicates the alignment of the pointer next to image insertion relative to image height. The value can be:
    • T: top-right for LTR or top-left for RTL
    • M: middle-right for LTR or middle-left for RTL
    • B: bottom-right for LTR or bottom-left for RTL
    • N: next line
    + * @param boolean $resize If true resize (reduce) the image to fit $w and $h (requires GD library). + * @param int $dpi dot-per-inch resolution used on resize + * @param string $palign Allows to center or align the image on the current line. Possible values are:
    • L : left align
    • C : center
    • R : right align
    • '' : empty string : left for LTR or right for RTL
    + * @author Valentin Schmidt, Nicola Asuni + * @access protected + * @since 4.3.007 (2008-12-04) + * @see Image() + */ + protected function ImagePngAlpha($file, $x='', $y='', $w=0, $h=0, $type='', $link='', $align='', $resize=false, $dpi=300, $palign='') { + // get image size + list($wpx, $hpx) = getimagesize($file); + // generate images + $img = imagecreatefrompng($file); + $imgalpha = imagecreate($wpx, $hpx); + // generate gray scale pallete + for ($c = 0; $c < 256; ++$c) { + ImageColorAllocate($imgalpha, $c, $c, $c); + } + // extract alpha channel + for ($xpx = 0; $xpx < $wpx; ++$xpx) { + for ($ypx = 0; $ypx < $hpx; ++$ypx) { + $colorindex = imagecolorat($img, $xpx, $ypx); + $col = imagecolorsforindex($img, $colorindex); + imagesetpixel($imgalpha, $xpx, $ypx, $this->getGDgamma((127 - $col['alpha']) * 255 / 127)); + } + } + // create temp alpha file + $tempfile_alpha = tempnam(K_PATH_CACHE, 'mska_'); + imagepng($imgalpha, $tempfile_alpha); + imagedestroy($imgalpha); + // extract image without alpha channel + $imgplain = imagecreatetruecolor($wpx, $hpx); + imagecopy($imgplain, $img, 0, 0, 0, 0, $wpx, $hpx); + // create temp image file + $tempfile_plain = tempnam(K_PATH_CACHE, 'mskp_'); + imagepng($imgplain, $tempfile_plain); + imagedestroy($imgplain); + // embed mask image + $imgmask = $this->Image($tempfile_alpha, $x, $y, $w, $h, 'PNG', '', '', $resize, $dpi, '', true, false); + // embed image, masked with previously embedded mask + $this->Image($tempfile_plain, $x, $y, $w, $h, $type, $link, $align, $resize, $dpi, $palign, false, $imgmask); + // remove temp files + unlink($tempfile_alpha); + unlink($tempfile_plain); + } + + /** + * Correct the gamma value to be used with GD library + * @param float $v the gamma value to be corrected + * @access protected + * @since 4.3.007 (2008-12-04) + */ + protected function getGDgamma($v) { + return (pow(($v / 255), 2.2) * 255); + } + + /** + * Performs a line break. + * The current abscissa goes back to the left margin and the ordinate increases by the amount passed in parameter. + * @param float $h The height of the break. By default, the value equals the height of the last printed cell. + * @param boolean $cell if true add a cMargin to the x coordinate + * @access public + * @since 1.0 + * @see Cell() + */ + public function Ln($h='', $cell=false) { + //Line feed; default value is last cell height + if ($cell) { + $cellmargin = $this->cMargin; + } else { + $cellmargin = 0; + } + if ($this->rtl) { + $this->x = $this->w - $this->rMargin - $cellmargin; + } else { + $this->x = $this->lMargin + $cellmargin; + } + if (is_string($h)) { + $this->y += $this->lasth; + } else { + $this->y += $h; + } + $this->newline = true; + } + + /** + * Returns the relative X value of current position. + * The value is relative to the left border for LTR languages and to the right border for RTL languages. + * @return float + * @access public + * @since 1.2 + * @see SetX(), GetY(), SetY() + */ + public function GetX() { + //Get x position + if ($this->rtl) { + return ($this->w - $this->x); + } else { + return $this->x; + } + } + + /** + * Returns the absolute X value of current position. + * @return float + * @access public + * @since 1.2 + * @see SetX(), GetY(), SetY() + */ + public function GetAbsX() { + return $this->x; + } + + /** + * Returns the ordinate of the current position. + * @return float + * @access public + * @since 1.0 + * @see SetY(), GetX(), SetX() + */ + public function GetY() { + //Get y position + return $this->y; + } + + /** + * Defines the abscissa of the current position. + * If the passed value is negative, it is relative to the right of the page (or left if language is RTL). + * @param float $x The value of the abscissa. + * @access public + * @since 1.2 + * @see GetX(), GetY(), SetY(), SetXY() + */ + public function SetX($x) { + //Set x position + if ($this->rtl) { + if ($x >= 0) { + $this->x = $this->w - $x; + } else { + $this->x = abs($x); + } + } else { + if ($x >= 0) { + $this->x = $x; + } else { + $this->x = $this->w + $x; + } + } + if ($this->x < 0) { + $this->x = 0; + } + if ($this->x > $this->w) { + $this->x = $this->w; + } + } + + /** + * Moves the current abscissa back to the left margin and sets the ordinate. + * If the passed value is negative, it is relative to the bottom of the page. + * @param float $y The value of the ordinate. + * @param bool $resetx if true (default) reset the X position. + * @access public + * @since 1.0 + * @see GetX(), GetY(), SetY(), SetXY() + */ + public function SetY($y, $resetx=true) { + if ($resetx) { + //reset x + if ($this->rtl) { + $this->x = $this->w - $this->rMargin; + } else { + $this->x = $this->lMargin; + } + } + if ($y >= 0) { + $this->y = $y; + } else { + $this->y = $this->h + $y; + } + if ($this->y < 0) { + $this->y = 0; + } + if ($this->y > $this->h) { + $this->y = $this->h; + } + } + + /** + * Defines the abscissa and ordinate of the current position. + * If the passed values are negative, they are relative respectively to the right and bottom of the page. + * @param float $x The value of the abscissa + * @param float $y The value of the ordinate + * @access public + * @since 1.2 + * @see SetX(), SetY() + */ + public function SetXY($x, $y) { + //Set x and y positions + $this->SetY($y); + $this->SetX($x); + } + + /** + * Send the document to a given destination: string, local file or browser. + * In the last case, the plug-in may be used (if present) or a download ("Save as" dialog box) may be forced.
    + * The method first calls Close() if necessary to terminate the document. + * @param string $name The name of the file when saved. Note that special characters are removed and blanks characters are replaced with the underscore character. + * @param string $dest Destination where to send the document. It can take one of the following values:
    • I: send the file inline to the browser (default). The plug-in is used if available. The name given by name is used when one selects the "Save as" option on the link generating the PDF.
    • D: send to the browser and force a file download with the name given by name.
    • F: save to a local file with the name given by name.
    • S: return the document as a string. name is ignored.
    + * @access public + * @since 1.0 + * @see Close() + */ + public function Output($name='doc.pdf', $dest='I') { + //Output PDF to some destination + //Finish document if necessary + if ($this->state < 3) { + $this->Close(); + } + //Normalize parameters + if (is_bool($dest)) { + $dest = $dest ? 'D' : 'F'; + } + $dest = strtoupper($dest); + if ($dest != 'F') { + $name = preg_replace('/[\s]+/', '_', $name); + $name = preg_replace('/[^a-zA-Z0-9\._-\x{4e00}-\x{9fa5}]/u', '', $name); + } + if ($this->sign) { + // *** apply digital signature to the document *** + // get the document content + $pdfdoc = $this->getBuffer(); + // remove last newline + $pdfdoc = substr($pdfdoc, 0, -1); + // Remove the original buffer + if (isset($this->diskcache) AND $this->diskcache) { + // remove buffer file from cache + unlink($this->buffer); + } + unset($this->buffer); + // remove filler space + $tmppos = strpos($pdfdoc, '/ByteRange[0 ********** ********** **********]') + 58; + $pdfdoc = substr($pdfdoc, 0, $tmppos).substr($pdfdoc, $tmppos + $this->signature_max_lenght); + // define the ByteRange + $byte_range = array(); + $byte_range[0] = 0; + $byte_range[1] = $tmppos - 1; + $byte_range[2] = $byte_range[1] + $this->signature_max_lenght; + $byte_range[3] = strlen($pdfdoc) - $byte_range[1]; + // replace the ByteRange + $byterange = sprintf('/ByteRange[0 %010u %010u %010u]', $byte_range[1], $byte_range[2], $byte_range[3]); + $pdfdoc = str_replace('/ByteRange[0 ********** ********** **********]', $byterange, $pdfdoc); + // write the document to a temporary folder + $tempdoc = tempnam(K_PATH_CACHE, 'tmppdf_'); + $f = fopen($tempdoc, 'wb'); + if (!$f) { + $this->Error('Unable to create temporary file: '.$tempdoc); + } + $pdfdoc_lenght = strlen($pdfdoc); + fwrite($f, $pdfdoc, $pdfdoc_lenght); + fclose($f); + // get digital signature. + // IS THE FOLLOWING PROCEDURE CORRECT? THE SIGNED DOCUMENTS ARE NOT VALID! + $tempsign = tempnam(K_PATH_CACHE, 'tmpsig_'); + if (empty($this->signature_data['extracerts'])) { + openssl_pkcs7_sign($tempdoc, $tempsign, $this->signature_data['signcert'], array($this->signature_data['privkey'], $this->signature_data['password']), array(), PKCS7_BINARY | PKCS7_DETACHED); + } else { + openssl_pkcs7_sign($tempdoc, $tempsign, $this->signature_data['signcert'], array($this->signature_data['privkey'], $this->signature_data['password']), array(), PKCS7_BINARY | PKCS7_DETACHED, $this->signature_data['extracerts']); + } + unlink($tempdoc); + // read signature + $signature = file_get_contents($tempsign, false, null, $pdfdoc_lenght); + unlink($tempsign); + // extract signature + $signature = substr($signature, (strpos($signature, "%%EOF\n\n------") + 13)); + $tmparr = explode("\n\n", $signature); + $signature = $tmparr[1]; + unset($tmparr); + // decode signature + $signature = base64_decode(trim($signature)); + // convert signature to hex + $signature = current(unpack('H*', $signature)); + $signature = str_pad($signature, $this->signature_max_lenght, '0'); + // Add signature to the document + $pdfdoc = substr($pdfdoc, 0, $byte_range[1]).$signature.substr($pdfdoc, (0 - $byte_range[3])); + $this->diskcache = false; + $this->buffer = &$pdfdoc; + $this->bufferlen = strlen($pdfdoc); + } + switch($dest) { + case 'I': { + // Send PDF to the standard output + if (ob_get_contents()) { + $this->Error('Some data has already been output, can\'t send PDF file'); + } + if (php_sapi_name() != 'cli') { + //We send to a browser + header('Content-Type: application/pdf'); + if (headers_sent()) { + $this->Error('Some data has already been output to browser, can\'t send PDF file'); + } + header('Cache-Control: public, must-revalidate, max-age=0'); // HTTP/1.1 + header('Pragma: public'); + header('Expires: Sat, 26 Jul 1997 05:00:00 GMT'); // Date in the past + header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT'); + header('Content-Length: '.$this->bufferlen); + header('Content-Disposition: inline; filename="'.basename($name).'";'); + } + echo $this->getBuffer(); + break; + } + case 'D': { + // Download PDF as file + if (ob_get_contents()) { + $this->Error('Some data has already been output, can\'t send PDF file'); + } + header('Content-Description: File Transfer'); + if (headers_sent()) { + $this->Error('Some data has already been output to browser, can\'t send PDF file'); + } + header('Cache-Control: public, must-revalidate, max-age=0'); // HTTP/1.1 + header('Pragma: public'); + header('Expires: Sat, 26 Jul 1997 05:00:00 GMT'); // Date in the past + header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT'); + // force download dialog + header('Content-Type: application/force-download'); + header('Content-Type: application/octet-stream', false); + header('Content-Type: application/download', false); + header('Content-Type: application/pdf', false); + // use the Content-Disposition header to supply a recommended filename + header('Content-Disposition: attachment; filename="'.basename($name).'";'); + header('Content-Transfer-Encoding: binary'); + header('Content-Length: '.$this->bufferlen); + echo $this->getBuffer(); + break; + } + case 'F': { + // Save PDF to a local file + if ($this->diskcache) { + copy($this->buffer, $name); + } else { + $f = fopen($name, 'wb'); + if (!$f) { + $this->Error('Unable to create output file: '.$name); + } + fwrite($f, $this->getBuffer(), $this->bufferlen); + fclose($f); + } + break; + } + case 'S': { + // Returns PDF as a string + return $this->getBuffer(); + } + default: { + $this->Error('Incorrect output destination: '.$dest); + } + } + return ''; + } + + /** + * Unset all class variables except the following critical variables: internal_encoding, state, bufferlen, buffer and diskcache. + * @param boolean $destroyall if true destroys all class variables, otherwise preserves critical variables. + * @param boolean $preserve_objcopy if true preserves the objcopy variable + * @access public + * @since 4.5.016 (2009-02-24) + */ + public function _destroy($destroyall=false, $preserve_objcopy=false) { + if ($destroyall AND isset($this->diskcache) AND $this->diskcache AND (!$preserve_objcopy) AND (!$this->empty_string($this->buffer))) { + // remove buffer file from cache + unlink($this->buffer); + } + foreach (array_keys(get_object_vars($this)) as $val) { + if ($destroyall OR ( + ($val != 'internal_encoding') + AND ($val != 'state') + AND ($val != 'bufferlen') + AND ($val != 'buffer') + AND ($val != 'diskcache') + AND ($val != 'sign') + AND ($val != 'signature_data') + AND ($val != 'signature_max_lenght') + )) { + if (!$preserve_objcopy OR ($val != 'objcopy')) { + unset($this->$val); + } + } + } + } + + /** + * Check for locale-related bug + * @access protected + */ + protected function _dochecks() { + //Check for locale-related bug + if (1.1 == 1) { + $this->Error('Don\'t alter the locale before including class file'); + } + //Check for decimal separator + if (sprintf('%.1F', 1.0) != '1.0') { + setlocale(LC_NUMERIC, 'C'); + } + } + + /** + * Return fonts path + * @return string + * @access protected + */ + protected function _getfontpath() { + if (!defined('K_PATH_FONTS') AND is_dir(dirname(__FILE__).'/fonts')) { + define('K_PATH_FONTS', dirname(__FILE__).'/fonts/'); + } + return defined('K_PATH_FONTS') ? K_PATH_FONTS : ''; + } + + /** + * Output pages. + * @access protected + */ + protected function _putpages() { + $nb = $this->numpages; + if (!empty($this->AliasNbPages)) { + $nbs = $this->formatPageNumber($nb); + $nbu = $this->UTF8ToUTF16BE($nbs, false); // replacement for unicode font + $alias_a = $this->_escape($this->AliasNbPages); + $alias_au = $this->_escape('{'.$this->AliasNbPages.'}'); + if ($this->isunicode) { + $alias_b = $this->_escape($this->UTF8ToLatin1($this->AliasNbPages)); + $alias_bu = $this->_escape($this->UTF8ToLatin1('{'.$this->AliasNbPages.'}')); + $alias_c = $this->_escape($this->utf8StrRev($this->AliasNbPages, false, $this->tmprtl)); + $alias_cu = $this->_escape($this->utf8StrRev('{'.$this->AliasNbPages.'}', false, $this->tmprtl)); + } + } + if (!empty($this->AliasNumPage)) { + $alias_pa = $this->_escape($this->AliasNumPage); + $alias_pau = $this->_escape('{'.$this->AliasNumPage.'}'); + if ($this->isunicode) { + $alias_pb = $this->_escape($this->UTF8ToLatin1($this->AliasNumPage)); + $alias_pbu = $this->_escape($this->UTF8ToLatin1('{'.$this->AliasNumPage.'}')); + $alias_pc = $this->_escape($this->utf8StrRev($this->AliasNumPage, false, $this->tmprtl)); + $alias_pcu = $this->_escape($this->utf8StrRev('{'.$this->AliasNumPage.'}', false, $this->tmprtl)); + } + } + $pagegroupnum = 0; + $filter = ($this->compress) ? '/Filter /FlateDecode ' : ''; + for ($n=1; $n <= $nb; ++$n) { + $temppage = $this->getPageBuffer($n); + if (!empty($this->pagegroups)) { + if(isset($this->newpagegroup[$n])) { + $pagegroupnum = 0; + } + ++$pagegroupnum; + foreach ($this->pagegroups as $k => $v) { + // replace total pages group numbers + $vs = $this->formatPageNumber($v); + $vu = $this->UTF8ToUTF16BE($vs, false); + $alias_ga = $this->_escape($k); + $alias_gau = $this->_escape('{'.$k.'}'); + if ($this->isunicode) { + $alias_gb = $this->_escape($this->UTF8ToLatin1($k)); + $alias_gbu = $this->_escape($this->UTF8ToLatin1('{'.$k.'}')); + $alias_gc = $this->_escape($this->utf8StrRev($k, false, $this->tmprtl)); + $alias_gcu = $this->_escape($this->utf8StrRev('{'.$k.'}', false, $this->tmprtl)); + } + $temppage = str_replace($alias_gau, $vu, $temppage); + if ($this->isunicode) { + $temppage = str_replace($alias_gbu, $vu, $temppage); + $temppage = str_replace($alias_gcu, $vu, $temppage); + $temppage = str_replace($alias_gb, $vs, $temppage); + $temppage = str_replace($alias_gc, $vs, $temppage); + } + $temppage = str_replace($alias_ga, $vs, $temppage); + // replace page group numbers + $pvs = $this->formatPageNumber($pagegroupnum); + $pvu = $this->UTF8ToUTF16BE($pvs, false); + $pk = str_replace('{nb', '{pnb', $k); + $alias_pga = $this->_escape($pk); + $alias_pgau = $this->_escape('{'.$pk.'}'); + if ($this->isunicode) { + $alias_pgb = $this->_escape($this->UTF8ToLatin1($pk)); + $alias_pgbu = $this->_escape($this->UTF8ToLatin1('{'.$pk.'}')); + $alias_pgc = $this->_escape($this->utf8StrRev($pk, false, $this->tmprtl)); + $alias_pgcu = $this->_escape($this->utf8StrRev('{'.$pk.'}', false, $this->tmprtl)); + } + $temppage = str_replace($alias_pgau, $pvu, $temppage); + if ($this->isunicode) { + $temppage = str_replace($alias_pgbu, $pvu, $temppage); + $temppage = str_replace($alias_pgcu, $pvu, $temppage); + $temppage = str_replace($alias_pgb, $pvs, $temppage); + $temppage = str_replace($alias_pgc, $pvs, $temppage); + } + $temppage = str_replace($alias_pga, $pvs, $temppage); + } + } + if (!empty($this->AliasNbPages)) { + // replace total pages number + $temppage = str_replace($alias_au, $nbu, $temppage); + if ($this->isunicode) { + $temppage = str_replace($alias_bu, $nbu, $temppage); + $temppage = str_replace($alias_cu, $nbu, $temppage); + $temppage = str_replace($alias_b, $nbs, $temppage); + $temppage = str_replace($alias_c, $nbs, $temppage); + } + $temppage = str_replace($alias_a, $nbs, $temppage); + } + if (!empty($this->AliasNumPage)) { + // replace page number + $pnbs = $this->formatPageNumber($n); + $pnbu = $this->UTF8ToUTF16BE($pnbs, false); // replacement for unicode font + $temppage = str_replace($alias_pau, $pnbu, $temppage); + if ($this->isunicode) { + $temppage = str_replace($alias_pbu, $pnbu, $temppage); + $temppage = str_replace($alias_pcu, $pnbu, $temppage); + $temppage = str_replace($alias_pb, $pnbs, $temppage); + $temppage = str_replace($alias_pc, $pnbs, $temppage); + } + $temppage = str_replace($alias_pa, $pnbs, $temppage); + } + $temppage = str_replace($this->epsmarker, '', $temppage); + //$this->setPageBuffer($n, $temppage); + //Page + $this->_newobj(); + $this->_out('<_out('/Parent 1 0 R'); + $this->_out(sprintf('/MediaBox [0 0 %.2F %.2F]', $this->pagedim[$n]['w'], $this->pagedim[$n]['h'])); + $this->_out('/Resources 2 0 R'); + $this->_putannots($n); + $this->_out('/Contents '.($this->n + 1).' 0 R>>'); + $this->_out('endobj'); + //Page content + $p = ($this->compress) ? gzcompress($temppage) : $temppage; + $this->_newobj(); + $this->_out('<<'.$filter.'/Length '.strlen($p).'>>'); + $this->_putstream($p); + $this->_out('endobj'); + if ($this->diskcache) { + // remove temporary files + unlink($this->pages[$n]); + } + } + //Pages root + $this->offsets[1] = $this->bufferlen; + $this->_out('1 0 obj'); + $this->_out('<_out($kids.']'); + $this->_out('/Count '.$nb); + //$this->_out(sprintf('/MediaBox [0 0 %.2F %.2F]',$this->pagedim[0]['w'],$this->pagedim[0]['h'])); + $this->_out('>>'); + $this->_out('endobj'); + } + + /** + * Output Page Annotations. + * !!! THIS FUNCTION IS NOT YET COMPLETED !!! + * See section 8.4 of PDF reference. + * @param int $n page number + * @access protected + * @author Nicola Asuni + * @since 4.0.018 (2008-08-06) + */ + protected function _putannots($n) { + if (isset($this->PageAnnots[$n])) { + $annots = '/Annots ['; + foreach ($this->PageAnnots[$n] as $key => $pl) { + $pl['opt'] = array_change_key_case($pl['opt'], CASE_LOWER); + $a = $pl['x'] * $this->k; + $b = $this->pagedim[$n]['h'] - ($pl['y'] * $this->k); + $c = $pl['w'] * $this->k; + $d = $pl['h'] * $this->k; + $rect = sprintf('%.2F %.2F %.2F %.2F', $a, $b, $a+$c, $b-$d); + $annots .= "\n"; + $annots .= '<_textstring($pl['txt']); + //$annots .= ' /P '; + $annots .= ' /NM '.$this->_textstring(sprintf('%04u-%04u', $n, $key)); + $annots .= ' /M '.$this->_datastring('D:'.date('YmdHis')); + if (isset($pl['opt']['f'])) { + $val = 0; + if (is_array($pl['opt']['f'])) { + foreach ($pl['opt']['f'] as $f) { + switch (strtolower($f)) { + case 'invisible': { + $val += 1 << 0; + break; + } + case 'hidden': { + $val += 1 << 1; + break; + } + case 'print': { + $val += 1 << 2; + break; + } + case 'nozoom': { + $val += 1 << 3; + break; + } + case 'norotate': { + $val += 1 << 4; + break; + } + case 'noview': { + $val += 1 << 5; + break; + } + case 'readonly': { + $val += 1 << 6; + break; + } + case 'locked': { + $val += 1 << 8; + break; + } + case 'togglenoview': { + $val += 1 << 9; + break; + } + case 'lockedcontents': { + $val += 1 << 10; + break; + } + default: { + break; + } + } + } + } + $annots .= ' /F '.intval($val); + } + //$annots .= ' /AP '; + //$annots .= ' /AS '; + $annots .= ' /Border ['; + if (isset($pl['opt']['border']) AND (count($pl['opt']['border']) >= 3)) { + $annots .= intval($pl['opt']['border'][0]).' '; + $annots .= intval($pl['opt']['border'][1]).' '; + $annots .= intval($pl['opt']['border'][2]); + if (isset($pl['opt']['border'][3]) AND is_array($pl['opt']['border'][3])) { + $annots .= ' ['; + foreach ($pl['opt']['border'][3] as $dash) { + $annots .= intval($dash).' '; + } + $annots .= ']'; + } + } else { + $annots .= '0 0 0'; + } + $annots .= ']'; + if (isset($pl['opt']['bs']) AND (is_array($pl['opt']['bs']))) { + $annots .= ' /BS <= 0) AND ($pl['opt']['be']['i'] <= 2)) { + $annots .= ' /I '.sprintf(" %.4F", $pl['opt']['be']['i']); + } + $annots .= '>>'; + } + $annots .= ' /C ['; + if (isset($pl['opt']['c']) AND (is_array($pl['opt']['c']))) { + foreach ($pl['opt']['c'] as $col) { + $col = intval($col); + $color = $col <= 0 ? 0 : ($col >= 255 ? 1 : $col / 255); + $annots .= sprintf(" %.4F", $color); + } + } + $annots .= ']'; + //$annots .= ' /StructParent '; + //$annots .= ' /OC '; + $markups = array('text', 'freetext', 'line', 'square', 'circle', 'polygon', 'polyline', 'highlight', 'underline', 'squiggly', 'strikeout', 'stamp', 'caret', 'ink', 'fileattachment', 'sound'); + if (in_array(strtolower($pl['opt']['subtype']), $markups)) { + // this is a markup type + if (isset($pl['opt']['t']) AND is_string($pl['opt']['t'])) { + $annots .= ' /T '.$this->_textstring($pl['opt']['t']); + } + //$annots .= ' /Popup '; + if (isset($pl['opt']['ca'])) { + $annots .= ' /CA '.sprintf("%.4F", floatval($pl['opt']['ca'])); + } + if (isset($pl['opt']['rc'])) { + $annots .= ' /RC '.$this->_textstring($pl['opt']['rc']); + } + $annots .= ' /CreationDate '.$this->_datastring('D:'.date('YmdHis')); + //$annots .= ' /IRT '; + if (isset($pl['opt']['subj'])) { + $annots .= ' /Subj '.$this->_textstring($pl['opt']['subj']); + } + //$annots .= ' /RT '; + //$annots .= ' /IT '; + //$annots .= ' /ExData '; + } + switch (strtolower($pl['opt']['subtype'])) { + case 'text': { + if (isset($pl['opt']['open'])) { + $annots .= ' /Open '. (strtolower($pl['opt']['open']) == 'true' ? 'true' : 'false'); + } + $iconsapp = array('Comment', 'Help', 'Insert', 'Key', 'NewParagraph', 'Note', 'Paragraph'); + if (isset($pl['opt']['name']) AND in_array($pl['opt']['name'], $iconsapp)) { + $annots .= ' /Name /'.$pl['opt']['name']; + } else { + $annots .= ' /Name /Note'; + } + $statemodels = array('Marked', 'Review'); + if (isset($pl['opt']['statemodel']) AND in_array($pl['opt']['statemodel'], $statemodels)) { + $annots .= ' /StateModel /'.$pl['opt']['statemodel']; + } else { + $pl['opt']['statemodel'] = 'Marked'; + $annots .= ' /StateModel /'.$pl['opt']['statemodel']; + } + if ($pl['opt']['statemodel'] == 'Marked') { + $states = array('Accepted', 'Unmarked'); + } else { + $states = array('Accepted', 'Rejected', 'Cancelled', 'Completed', 'None'); + } + if (isset($pl['opt']['state']) AND in_array($pl['opt']['state'], $states)) { + $annots .= ' /State /'.$pl['opt']['state']; + } else { + if ($pl['opt']['statemodel'] == 'Marked') { + $annots .= ' /State /Unmarked'; + } else { + $annots .= ' /State /None'; + } + } + break; + } + case 'link': { + if(is_string($pl['txt'])) { + // external URI link + $annots .= ' /A <_datastring($pl['txt']).'>>'; + } else { + // internal link + $l = $this->links[$pl['txt']]; + $annots .= sprintf(' /Dest [%d 0 R /XYZ 0 %.2F null]', (1 + (2 * $l[0])), ($this->pagedim[$l[0]]['h'] - ($l[1] * $this->k))); + } + $hmodes = array('N', 'I', 'O', 'P'); + if (isset($pl['opt']['h']) AND in_array($pl['opt']['h'], $hmodes)) { + $annots .= ' /H /'.$pl['opt']['h']; + } else { + $annots .= ' /H /I'; + } + //$annots .= ' /PA '; + //$annots .= ' /Quadpoints '; + break; + } + case 'freetext': { + $annots .= ' /DA '.$this->_textstring($pl['txt']); + if (isset($pl['opt']['q']) AND ($pl['opt']['q'] >= 0) AND ($pl['opt']['q'] <= 2)) { + $annots .= ' /Q '.intval($pl['opt']['q']); + } + if (isset($pl['opt']['rc'])) { + $annots .= ' /RC '.$this->_textstring($pl['opt']['rc']); + } + if (isset($pl['opt']['ds'])) { + $annots .= ' /DS '.$this->_textstring($pl['opt']['ds']); + } + if (isset($pl['opt']['cl']) AND is_array($pl['opt']['cl'])) { + $annots .= ' /CL ['; + foreach ($pl['opt']['cl'] as $cl) { + $annots .= sprintf("%.4F ", $cl * $this->k); + } + $annots .= ']'; + } + $tfit = array('FreeTextCallout', 'FreeTextTypeWriter'); + if (isset($pl['opt']['it']) AND in_array($pl['opt']['it'], $tfit)) { + $annots .= ' /IT '.$pl['opt']['it']; + } + if (isset($pl['opt']['rd']) AND is_array($pl['opt']['rd'])) { + $l = $pl['opt']['rd'][0] * $this->k; + $r = $pl['opt']['rd'][1] * $this->k; + $t = $pl['opt']['rd'][2] * $this->k; + $b = $pl['opt']['rd'][3] * $this->k; + $annots .= ' /RD ['.sprintf('%.2F %.2F %.2F %.2F', $l, $r, $t, $b).']'; + } + //$annots .= ' /LE '; + break; + } + // ... to be completed ... + case 'line': { + break; + } + case 'square': { + break; + } + case 'circle': { + break; + } + case 'polygon': { + break; + } + case 'polyline': { + break; + } + case 'highlight': { + break; + } + case 'underline': { + break; + } + case 'squiggly': { + break; + } + case 'strikeout': { + break; + } + case 'stamp': { + break; + } + case 'caret': { + break; + } + case 'ink': { + break; + } + case 'popup': { + break; + } + case 'fileattachment': { + if (!isset($pl['opt']['fs'])) { + break; + } + $filename = basename($pl['opt']['fs']); + if (isset($this->embeddedfiles[$filename]['n'])) { + $annots .= ' /FS <_datastring($filename).' /EF <embeddedfiles[$filename]['n'].' 0 R>> >>'; + $iconsapp = array('Graph', 'Paperclip', 'PushPin', 'Tag'); + if (isset($pl['opt']['name']) AND in_array($pl['opt']['name'], $iconsapp)) { + $annots .= ' /Name /'.$pl['opt']['name']; + } else { + $annots .= ' /Name /PushPin'; + } + } + break; + } + case 'sound': { + if (!isset($pl['opt']['sound'])) { + break; + } + $filename = basename($pl['opt']['sound']); + if (isset($this->embeddedfiles[$filename]['n'])) { + // ... TO BE COMPLETED ... + $iconsapp = array('Speaker', 'Mic'); + if (isset($pl['opt']['name']) AND in_array($pl['opt']['name'], $iconsapp)) { + $annots .= ' /Name /'.$pl['opt']['name']; + } else { + $annots .= ' /Name /Speaker'; + } + } + break; + } + case 'movie': { + break; + } + case 'widget': { + if (isset($pl['opt']['h'])) { + $annots .= ' /H '.intval($pl['opt']['h']); + } + if (isset($pl['opt']['mk']) AND (is_array($pl['opt']['mk']))) { + $annots .= ' /MK <<'; + // ... TO BE COMPLETED ... + $annots .= '>>'; + } + break; + } + case 'screen': { + break; + } + case 'printermark': { + break; + } + case 'trapnet': { + break; + } + case 'watermark': { + break; + } + case '3d': { + break; + } + default: { + break; + } + } + + $annots .= '>>'; + } + $annots .= "\n]"; + $this->_out($annots); + } + } + + /** + * Output fonts. + * @access protected + */ + protected function _putfonts() { + $nf = $this->n; + foreach ($this->diffs as $diff) { + //Encodings + $this->_newobj(); + $this->_out('<>'); + $this->_out('endobj'); + } + $mqr = get_magic_quotes_runtime(); + //set_magic_quotes_runtime(0); + foreach ($this->FontFiles as $file => $info) { + // search and get font file to embedd + $fontdir = $info['fontdir']; + $file = strtolower($file); + $fontfile = ''; + // search files on various directories + if (file_exists($fontdir.$file)) { + $fontfile = $fontdir.$file; + } elseif (file_exists($this->_getfontpath().$file)) { + $fontfile = $this->_getfontpath().$file; + } elseif (file_exists($file)) { + $fontfile = $file; + } + if (!$this->empty_string($fontfile)) { + $font = file_get_contents($fontfile); + $compressed = (substr($file, -2) == '.z'); + if ((!$compressed) AND (isset($info['length2']))) { + $header = (ord($font{0}) == 128); + if ($header) { + //Strip first binary header + $font = substr($font, 6); + } + if ($header AND (ord($font{$info['length1']}) == 128)) { + //Strip second binary header + $font = substr($font, 0, $info['length1']).substr($font, ($info['length1'] + 6)); + } + } + $this->_newobj(); + $this->FontFiles[$file]['n'] = $this->n; + $this->_out('<_out('/Filter /FlateDecode'); + } + $this->_out('/Length1 '.$info['length1']); + if (isset($info['length2'])) { + $this->_out('/Length2 '.$info['length2'].' /Length3 0'); + } + $this->_out('>>'); + $this->_putstream($font); + $this->_out('endobj'); + } + } + //set_magic_quotes_runtime($mqr); + foreach ($this->fontkeys as $k) { + //Font objects + $this->setFontSubBuffer($k, 'n', $this->n + 1); + $font = $this->getFontBuffer($k); + $type = $font['type']; + $name = $font['name']; + if ($type == 'core') { + //Standard font + $this->_newobj(); + $this->_out('<_out('/BaseFont /'.$name); + $this->_out('/Subtype /Type1'); + if (($name != 'symbol') AND ($name != 'zapfdingbats')) { + $this->_out('/Encoding /WinAnsiEncoding'); + } + $this->_out('>>'); + $this->_out('endobj'); + } elseif (($type == 'Type1') OR ($type == 'TrueType')) { + //Additional Type1 or TrueType font + $this->_newobj(); + $this->_out('<_out('/BaseFont /'.$name); + $this->_out('/Subtype /'.$type); + $this->_out('/FirstChar 32 /LastChar 255'); + $this->_out('/Widths '.($this->n + 1).' 0 R'); + $this->_out('/FontDescriptor '.($this->n + 2).' 0 R'); + if ($font['enc']) { + if (isset($font['diff'])) { + $this->_out('/Encoding '.($nf + $font['diff']).' 0 R'); + } else { + $this->_out('/Encoding /WinAnsiEncoding'); + } + } + $this->_out('>>'); + $this->_out('endobj'); + // Widths + $this->_newobj(); + $cw = &$font['cw']; + $s = '['; + for ($i = 32; $i < 256; ++$i) { + $s .= $cw[$i].' '; + } + $this->_out($s.']'); + $this->_out('endobj'); + //Descriptor + $this->_newobj(); + $s = '< $v) { + $s .= ' /'.$k.' '.$v.''; + } + if (!$this->empty_string($font['file'])) { + $s .= ' /FontFile'.($type == 'Type1' ? '' : '2').' '.$this->FontFiles[$font['file']]['n'].' 0 R'; + } + $this->_out($s.'>>'); + $this->_out('endobj'); + } else { + //Allow for additional types + $mtd = '_put'.strtolower($type); + if (!method_exists($this, $mtd)) { + $this->Error('Unsupported font type: '.$type); + } + $this->$mtd($font); + } + } + } + + /** + * Outputs font widths + * @parameter array $font font data + * @parameter int $cidoffset offset for CID values + * @author Nicola Asuni + * @access protected + * @since 4.4.000 (2008-12-07) + */ + protected function _putfontwidths($font, $cidoffset=0) { + ksort($font['cw']); + $rangeid = 0; + $range = array(); + $prevcid = -2; + $prevwidth = -1; + $interval = false; + // for each character + foreach ($font['cw'] as $cid => $width) { + $cid -= $cidoffset; + if ($width != $font['dw']) { + if ($cid == ($prevcid + 1)) { + // consecutive CID + if ($width == $prevwidth) { + if ($width == $range[$rangeid][0]) { + $range[$rangeid][] = $width; + } else { + array_pop($range[$rangeid]); + // new range + $rangeid = $prevcid; + $range[$rangeid] = array(); + $range[$rangeid][] = $prevwidth; + $range[$rangeid][] = $width; + } + $interval = true; + $range[$rangeid]['interval'] = true; + } else { + if ($interval) { + // new range + $rangeid = $cid; + $range[$rangeid] = array(); + $range[$rangeid][] = $width; + } else { + $range[$rangeid][] = $width; + } + $interval = false; + } + } else { + // new range + $rangeid = $cid; + $range[$rangeid] = array(); + $range[$rangeid][] = $width; + $interval = false; + } + $prevcid = $cid; + $prevwidth = $width; + } + } + // optimize ranges + $prevk = -1; + $nextk = -1; + $prevint = false; + foreach ($range as $k => $ws) { + $cws = count($ws); + if (($k == $nextk) AND (!$prevint) AND ((!isset($ws['interval'])) OR ($cws < 4))) { + if (isset($range[$k]['interval'])) { + unset($range[$k]['interval']); + } + $range[$prevk] = array_merge($range[$prevk], $range[$k]); + unset($range[$k]); + } else { + $prevk = $k; + } + $nextk = $k + $cws; + if (isset($ws['interval'])) { + if ($cws > 3) { + $prevint = true; + } else { + $prevint = false; + } + unset($range[$k]['interval']); + --$nextk; + } else { + $prevint = false; + } + } + // output data + $w = ''; + foreach ($range as $k => $ws) { + if (count(array_count_values($ws)) == 1) { + // interval mode is more compact + $w .= ' '.$k.' '.($k + count($ws) - 1).' '.$ws[0]; + } else { + // range mode + $w .= ' '.$k.' [ '.implode(' ', $ws).' ]'; + } + } + $this->_out('/W ['.$w.' ]'); + } + + /** + * Adds unicode fonts.
    + * Based on PDF Reference 1.3 (section 5) + * @parameter array $font font data + * @access protected + * @author Nicola Asuni + * @since 1.52.0.TC005 (2005-01-05) + */ + protected function _puttruetypeunicode($font) { + // Type0 Font + // A composite font composed of other fonts, organized hierarchically + $this->_newobj(); + $this->_out('<_out('/Subtype /Type0'); + $this->_out('/BaseFont /'.$font['name'].''); + $this->_out('/Encoding /Identity-H'); //The horizontal identity mapping for 2-byte CIDs; may be used with CIDFonts using any Registry, Ordering, and Supplement values. + $this->_out('/ToUnicode /Identity-H'); + $this->_out('/DescendantFonts ['.($this->n + 1).' 0 R]'); + $this->_out('>>'); + $this->_out('endobj'); + // CIDFontType2 + // A CIDFont whose glyph descriptions are based on TrueType font technology + $this->_newobj(); + $this->_out('<_out('/Subtype /CIDFontType2'); + $this->_out('/BaseFont /'.$font['name'].''); + // A dictionary containing entries that define the character collection of the CIDFont. + $cidinfo = '/Registry '.$this->_datastring('Adobe'); + $cidinfo .= ' /Ordering '.$this->_datastring('Identity'); + $cidinfo .= ' /Supplement 0'; + $this->_out('/CIDSystemInfo <<'.$cidinfo.'>>'); + $this->_out('/FontDescriptor '.($this->n + 1).' 0 R'); + $this->_out('/DW '.$font['dw'].''); // default width + $this->_putfontwidths($font, 0); + $this->_out('/CIDToGIDMap '.($this->n + 2).' 0 R'); + $this->_out('>>'); + $this->_out('endobj'); + // Font descriptor + // A font descriptor describing the CIDFont default metrics other than its glyph widths + $this->_newobj(); + $this->_out('<_out('/FontName /'.$font['name']); + foreach ($font['desc'] as $key => $value) { + $this->_out('/'.$key.' '.$value); + } + $fontdir = ''; + if (!$this->empty_string($font['file'])) { + // A stream containing a TrueType font + $this->_out('/FontFile2 '.$this->FontFiles[$font['file']]['n'].' 0 R'); + $fontdir = $this->FontFiles[$font['file']]['fontdir']; + } + $this->_out('>>'); + $this->_out('endobj'); + $this->_newobj(); + if (isset($font['ctg']) AND (!$this->empty_string($font['ctg']))) { + // Embed CIDToGIDMap + // A specification of the mapping from CIDs to glyph indices + // search and get CTG font file to embedd + $ctgfile = strtolower($font['ctg']); + // search and get ctg font file to embedd + $fontfile = ''; + // search files on various directories + if (file_exists($fontdir.$ctgfile)) { + $fontfile = $fontdir.$ctgfile; + } elseif (file_exists($this->_getfontpath().$ctgfile)) { + $fontfile = $this->_getfontpath().$ctgfile; + } elseif (file_exists($ctgfile)) { + $fontfile = $ctgfile; + } + if ($this->empty_string($fontfile)) { + $this->Error('Font file not found: '.$ctgfile); + } + $size = filesize($fontfile); + $this->_out('<_out('/Filter /FlateDecode'); + } + $this->_out('>>'); + $this->_putstream(file_get_contents($fontfile)); + } + $this->_out('endobj'); + } + + /** + * Output CID-0 fonts. + * @param array $font font data + * @access protected + * @author Andrew Whitehead, Nicola Asuni, Yukihiro Nakadaira + * @since 3.2.000 (2008-06-23) + */ + protected function _putcidfont0($font) { + $cidoffset = 31; + if (isset($font['cidinfo']['uni2cid'])) { + // convert unicode to cid. + $uni2cid = $font['cidinfo']['uni2cid']; + $cw = array(); + foreach ($font['cw'] as $uni => $width) { + if (isset($uni2cid[$uni])) { + $cw[($uni2cid[$uni] + $cidoffset)] = $width; + } elseif ($uni < 256) { + $cw[$uni] = $width; + } // else unknown character + } + $font = array_merge($font, array('cw' => $cw)); + } + $name = $font['name']; + $enc = $font['enc']; + if ($enc) { + $longname = $name.'-'.$enc; + } else { + $longname = $name; + } + $this->_newobj(); + $this->_out('<_out('/BaseFont /'.$longname); + $this->_out('/Subtype /Type0'); + if ($enc) { + $this->_out('/Encoding /'.$enc); + } + $this->_out('/DescendantFonts ['.($this->n + 1).' 0 R]'); + $this->_out('>>'); + $this->_out('endobj'); + $this->_newobj(); + $this->_out('<_out('/BaseFont /'.$name); + $this->_out('/Subtype /CIDFontType0'); + $cidinfo = '/Registry '.$this->_datastring($font['cidinfo']['Registry']); + $cidinfo .= ' /Ordering '.$this->_datastring($font['cidinfo']['Ordering']); + $cidinfo .= ' /Supplement '.$font['cidinfo']['Supplement']; + $this->_out('/CIDSystemInfo <<'.$cidinfo.'>>'); + $this->_out('/FontDescriptor '.($this->n + 1).' 0 R'); + $this->_out('/DW '.$font['dw']); + $this->_putfontwidths($font, $cidoffset); + $this->_out('>>'); + $this->_out('endobj'); + $this->_newobj(); + $s = '< $v) { + if ($k != 'Style') { + $s .= ' /'.$k.' '.$v.''; + } + } + $this->_out($s.'>>'); + $this->_out('endobj'); + } + + /** + * Output images. + * @access protected + */ + protected function _putimages() { + $filter = ($this->compress) ? '/Filter /FlateDecode ' : ''; + foreach ($this->imagekeys as $file) { + $info = $this->getImageBuffer($file); + $this->_newobj(); + $this->setImageSubBuffer($file, 'n', $this->n); + $this->_out('<_out('/Subtype /Image'); + $this->_out('/Width '.$info['w']); + $this->_out('/Height '.$info['h']); + if (isset($info['masked'])) { + $this->_out('/SMask '.($this->n - 1).' 0 R'); + } + if ($info['cs'] == 'Indexed') { + $this->_out('/ColorSpace [/Indexed /DeviceRGB '.((strlen($info['pal']) / 3) - 1).' '.($this->n + 1).' 0 R]'); + } else { + $this->_out('/ColorSpace /'.$info['cs']); + if ($info['cs'] == 'DeviceCMYK') { + $this->_out('/Decode [1 0 1 0 1 0 1 0]'); + } + } + $this->_out('/BitsPerComponent '.$info['bpc']); + if (isset($info['f'])) { + $this->_out('/Filter /'.$info['f']); + } + if (isset($info['parms'])) { + $this->_out($info['parms']); + } + if (isset($info['trns']) AND is_array($info['trns'])) { + $trns=''; + $count_info = count($info['trns']); + for ($i=0; $i < $count_info; ++$i) { + $trns .= $info['trns'][$i].' '.$info['trns'][$i].' '; + } + $this->_out('/Mask ['.$trns.']'); + } + $this->_out('/Length '.strlen($info['data']).'>>'); + $this->_putstream($info['data']); + $this->_out('endobj'); + //Palette + if ($info['cs'] == 'Indexed') { + $this->_newobj(); + $pal = ($this->compress) ? gzcompress($info['pal']) : $info['pal']; + $this->_out('<<'.$filter.'/Length '.strlen($pal).'>>'); + $this->_putstream($pal); + $this->_out('endobj'); + } + } + } + + /** + * Output Spot Colors Resources. + * @access protected + * @since 4.0.024 (2008-09-12) + */ + protected function _putspotcolors() { + foreach ($this->spot_colors as $name => $color) { + $this->_newobj(); + $this->spot_colors[$name]['n'] = $this->n; + $this->_out('[/Separation /'.str_replace(' ', '#20', $name)); + $this->_out('/DeviceCMYK <<'); + $this->_out('/Range [0 1 0 1 0 1 0 1] /C0 [0 0 0 0] '); + $this->_out(sprintf('/C1 [%.4F %.4F %.4F %.4F] ', $color['c']/100, $color['m']/100, $color['y']/100, $color['k']/100)); + $this->_out('/FunctionType 2 /Domain [0 1] /N 1>>]'); + $this->_out('endobj'); + } + } + + /** + * Output object dictionary for images. + * @access protected + */ + protected function _putxobjectdict() { + foreach ($this->imagekeys as $file) { + $info = $this->getImageBuffer($file); + $this->_out('/I'.$info['i'].' '.$info['n'].' 0 R'); + } + } + + /** + * Output Resources Dictionary. + * @access protected + */ + protected function _putresourcedict() { + $this->_out('/ProcSet [/PDF /Text /ImageB /ImageC /ImageI]'); + $this->_out('/Font <<'); + foreach ($this->fontkeys as $fontkey) { + $font = $this->getFontBuffer($fontkey); + $this->_out('/F'.$font['i'].' '.$font['n'].' 0 R'); + } + $this->_out('>>'); + $this->_out('/XObject <<'); + $this->_putxobjectdict(); + $this->_out('>>'); + // visibility + $this->_out('/Properties <n_ocg_print.' 0 R /OC2 '.$this->n_ocg_view.' 0 R>>'); + // transparency + $this->_out('/ExtGState <<'); + foreach ($this->extgstates as $k => $extgstate) { + $this->_out('/GS'.$k.' '.$extgstate['n'].' 0 R'); + } + $this->_out('>>'); + // gradients + if (isset($this->gradients) AND (count($this->gradients) > 0)) { + $this->_out('/Shading <<'); + foreach ($this->gradients as $id => $grad) { + $this->_out('/Sh'.$id.' '.$grad['id'].' 0 R'); + } + $this->_out('>>'); + } + // spot colors + if (isset($this->spot_colors) AND (count($this->spot_colors) > 0)) { + $this->_out('/ColorSpace <<'); + foreach ($this->spot_colors as $color) { + $this->_out('/CS'.$color['i'].' '.$color['n'].' 0 R'); + } + $this->_out('>>'); + } + } + + /** + * Output Resources. + * @access protected + */ + protected function _putresources() { + $this->_putextgstates(); + $this->_putocg(); + $this->_putfonts(); + $this->_putimages(); + $this->_putspotcolors(); + $this->_putshaders(); + //Resource dictionary + $this->offsets[2] = $this->bufferlen; + $this->_out('2 0 obj'); + $this->_out('<<'); + $this->_putresourcedict(); + $this->_out('>>'); + $this->_out('endobj'); + $this->_putjavascript(); + $this->_putbookmarks(); + $this->_putEmbeddedFiles(); + // encryption + if ($this->encrypted) { + $this->_newobj(); + $this->enc_obj_id = $this->n; + $this->_out('<<'); + $this->_putencryption(); + $this->_out('>>'); + $this->_out('endobj'); + } + } + + /** + * Adds some Metadata information + * (see Chapter 10.2 of PDF Reference) + * @access protected + */ + protected function _putinfo() { + if (!$this->empty_string($this->title)) { + $this->_out('/Title '.$this->_textstring($this->title)); + } + if (!$this->empty_string($this->author)) { + $this->_out('/Author '.$this->_textstring($this->author)); + } + if (!$this->empty_string($this->subject)) { + $this->_out('/Subject '.$this->_textstring($this->subject)); + } + if (!$this->empty_string($this->keywords)) { + $this->_out('/Keywords '.$this->_textstring($this->keywords)); + } + if (!$this->empty_string($this->creator)) { + $this->_out('/Creator '.$this->_textstring($this->creator)); + } + if (defined('PDF_PRODUCER')) { + $this->_out('/Producer '.$this->_textstring(PDF_PRODUCER)); + } + $this->_out('/CreationDate '.$this->_datastring('D:'.date('YmdHis'))); + $this->_out('/ModDate '.$this->_datastring('D:'.date('YmdHis'))); + } + + /** + * Output Catalog. + * @access protected + */ + protected function _putcatalog() { + $this->_out('/Type /Catalog'); + $this->_out('/Pages 1 0 R'); + if ($this->ZoomMode == 'fullpage') { + $this->_out('/OpenAction [3 0 R /Fit]'); + } elseif ($this->ZoomMode == 'fullwidth') { + $this->_out('/OpenAction [3 0 R /FitH null]'); + } elseif ($this->ZoomMode == 'real') { + $this->_out('/OpenAction [3 0 R /XYZ null null 1]'); + } elseif (!is_string($this->ZoomMode)) { + $this->_out('/OpenAction [3 0 R /XYZ null null '.($this->ZoomMode / 100).']'); + } + if (isset($this->LayoutMode) AND (!$this->empty_string($this->LayoutMode))) { + $this->_out('/PageLayout /'.$this->LayoutMode.''); + } + if (isset($this->PageMode) AND (!$this->empty_string($this->PageMode))) { + $this->_out('/PageMode /'.$this->PageMode); + } + if (isset($this->l['a_meta_language'])) { + $this->_out('/Lang /'.$this->l['a_meta_language']); + } + $this->_out('/Names <<'); + if (!$this->empty_string($this->javascript)) { + $this->_out('/JavaScript '.($this->n_js).' 0 R'); + } + $this->_out('>>'); + if (count($this->outlines) > 0) { + $this->_out('/Outlines '.$this->OutlineRoot.' 0 R'); + $this->_out('/PageMode /UseOutlines'); + } + $this->_putviewerpreferences(); + $p = $this->n_ocg_print.' 0 R'; + $v = $this->n_ocg_view.' 0 R'; + $as = '<> <>'; + $this->_out('/OCProperties <>>>'); + } + + /** + * Output viewer preferences. + * @author Nicola asuni + * @since 3.1.000 (2008-06-09) + * @access protected + */ + protected function _putviewerpreferences() { + $this->_out('/ViewerPreferences<<'); + if ($this->rtl) { + $this->_out('/Direction /R2L'); + } else { + $this->_out('/Direction /L2R'); + } + if (isset($this->viewer_preferences['HideToolbar']) AND ($this->viewer_preferences['HideToolbar'])) { + $this->_out('/HideToolbar true'); + } + if (isset($this->viewer_preferences['HideMenubar']) AND ($this->viewer_preferences['HideMenubar'])) { + $this->_out('/HideMenubar true'); + } + if (isset($this->viewer_preferences['HideWindowUI']) AND ($this->viewer_preferences['HideWindowUI'])) { + $this->_out('/HideWindowUI true'); + } + if (isset($this->viewer_preferences['FitWindow']) AND ($this->viewer_preferences['FitWindow'])) { + $this->_out('/FitWindow true'); + } + if (isset($this->viewer_preferences['CenterWindow']) AND ($this->viewer_preferences['CenterWindow'])) { + $this->_out('/CenterWindow true'); + } + if (isset($this->viewer_preferences['DisplayDocTitle']) AND ($this->viewer_preferences['DisplayDocTitle'])) { + $this->_out('/DisplayDocTitle true'); + } + if (isset($this->viewer_preferences['NonFullScreenPageMode'])) { + $this->_out('/NonFullScreenPageMode /'.$this->viewer_preferences['NonFullScreenPageMode'].''); + } + if (isset($this->viewer_preferences['ViewArea'])) { + $this->_out('/ViewArea /'.$this->viewer_preferences['ViewArea']); + } + if (isset($this->viewer_preferences['ViewClip'])) { + $this->_out('/ViewClip /'.$this->viewer_preferences['ViewClip']); + } + if (isset($this->viewer_preferences['PrintArea'])) { + $this->_out('/PrintArea /'.$this->viewer_preferences['PrintArea']); + } + if (isset($this->viewer_preferences['PrintClip'])) { + $this->_out('/PrintClip /'.$this->viewer_preferences['PrintClip']); + } + if (isset($this->viewer_preferences['PrintScaling'])) { + $this->_out('/PrintScaling /'.$this->viewer_preferences['PrintScaling']); + } + if (isset($this->viewer_preferences['Duplex']) AND (!$this->empty_string($this->viewer_preferences['Duplex']))) { + $this->_out('/Duplex /'.$this->viewer_preferences['Duplex']); + } + if (isset($this->viewer_preferences['PickTrayByPDFSize'])) { + if ($this->viewer_preferences['PickTrayByPDFSize']) { + $this->_out('/PickTrayByPDFSize true'); + } else { + $this->_out('/PickTrayByPDFSize false'); + } + } + if (isset($this->viewer_preferences['PrintPageRange'])) { + $PrintPageRangeNum = ''; + foreach ($this->viewer_preferences['PrintPageRange'] as $k => $v) { + $PrintPageRangeNum .= ' '.($v - 1).''; + } + $this->_out('/PrintPageRange ['.substr($PrintPageRangeNum,1).']'); + } + if (isset($this->viewer_preferences['NumCopies'])) { + $this->_out('/NumCopies '.intval($this->viewer_preferences['NumCopies'])); + } + $this->_out('>>'); + } + + /** + * Output trailer. + * @access protected + */ + protected function _puttrailer() { + $this->_out('/Size '.($this->n + 1)); + $this->_out('/Root '.$this->n.' 0 R'); + $this->_out('/Info '.($this->n - 1).' 0 R'); + if ($this->encrypted) { + $this->_out('/Encrypt '.$this->enc_obj_id.' 0 R'); + $this->_out('/ID [()()]'); + } + } + + /** + * Output PDF header. + * @access protected + */ + protected function _putheader() { + $this->_out('%PDF-'.$this->PDFVersion); + } + + /** + * Output end of document (EOF). + * @access protected + */ + protected function _enddoc() { + $this->state = 1; + $this->_putheader(); + $this->_putpages(); + $this->_putresources(); + //Info + $this->_newobj(); + $this->_out('<<'); + $this->_putinfo(); + $this->_out('>>'); + $this->_out('endobj'); + //Catalog + $this->_newobj(); + $this->_out('<<'); + $this->_putcatalog(); + $this->_putcertification(); + $this->_putuserrights(); + $this->_out('>>'); + $this->_out('endobj'); + //Cross-ref + $o = $this->bufferlen; + $this->_out('xref'); + $this->_out('0 '.($this->n + 1)); + $this->_out('0000000000 65535 f '); + for ($i=1; $i <= $this->n; ++$i) { + $this->_out(sprintf('%010d 00000 n ', $this->offsets[$i])); + } + if (isset($this->embeddedfiles) AND count($this->embeddedfiles) > 0) { + $this->_out('100000 '.count($this->embeddedfiles)); + foreach ($this->embeddedfiles as $filename => $filedata) { + $this->_out(sprintf('%010d 00000 n ', $this->offsets[$filedata['n']])); + } + } + //Trailer + $this->_out('trailer'); + $this->_out('<<'); + $this->_puttrailer(); + $this->_out('>>'); + $this->_out('startxref'); + $this->_out($o); + $this->_out('%%EOF'); + $this->state = 3; // end-of-doc + if ($this->diskcache) { + // remove temporary files used for images + foreach ($this->imagekeys as $key) { + // remove temporary files + unlink($this->images[$key]); + } + foreach ($this->fontkeys as $key) { + // remove temporary files + unlink($this->fonts[$key]); + } + } + } + + /** + * Initialize a new page. + * @param string $orientation page orientation. Possible values are (case insensitive):
    • P or PORTRAIT (default)
    • L or LANDSCAPE
    + * @param mixed $format The format used for pages. It can be either one of the following values (case insensitive) or a custom format in the form of a two-element array containing the width and the height (expressed in the unit given by unit).
    • 4A0
    • 2A0
    • A0
    • A1
    • A2
    • A3
    • A4 (default)
    • A5
    • A6
    • A7
    • A8
    • A9
    • A10
    • B0
    • B1
    • B2
    • B3
    • B4
    • B5
    • B6
    • B7
    • B8
    • B9
    • B10
    • C0
    • C1
    • C2
    • C3
    • C4
    • C5
    • C6
    • C7
    • C8
    • C9
    • C10
    • RA0
    • RA1
    • RA2
    • RA3
    • RA4
    • SRA0
    • SRA1
    • SRA2
    • SRA3
    • SRA4
    • LETTER
    • LEGAL
    • EXECUTIVE
    • FOLIO
    + * @access protected + */ + protected function _beginpage($orientation='', $format='') { + ++$this->page; + $this->setPageBuffer($this->page, ''); + // initialize array for graphics tranformation positions inside a page buffer + $this->transfmrk[$this->page] = array(); + $this->state = 2; + if ($this->empty_string($orientation)) { + if (isset($this->CurOrientation)) { + $orientation = $this->CurOrientation; + } else { + $orientation = 'P'; + } + } + if ($this->empty_string($format)) { + $this->setPageOrientation($orientation); + } else { + $this->setPageFormat($format, $orientation); + } + if ($this->rtl) { + $this->x = $this->w - $this->rMargin; + } else { + $this->x = $this->lMargin; + } + $this->y = $this->tMargin; + if (isset($this->newpagegroup[$this->page])) { + // start a new group + $n = sizeof($this->pagegroups) + 1; + $alias = '{nb'.$n.'}'; + $this->pagegroups[$alias] = 1; + $this->currpagegroup = $alias; + } elseif ($this->currpagegroup) { + ++$this->pagegroups[$this->currpagegroup]; + } + } + + /** + * Mark end of page. + * @access protected + */ + protected function _endpage() { + $this->setVisibility('all'); + $this->state = 1; + } + + /** + * Begin a new object. + * @access protected + */ + protected function _newobj() { + ++$this->n; + $this->offsets[$this->n] = $this->bufferlen; + $this->_out($this->n.' 0 obj'); + } + + /** + * Underline text. + * @param int $x X coordinate + * @param int $y Y coordinate + * @param string $txt text to underline + * @access protected + */ + protected function _dounderline($x, $y, $txt) { + $up = $this->CurrentFont['up']; + $ut = $this->CurrentFont['ut']; + $w = $this->GetStringWidth($txt); + return sprintf('%.2F %.2F %.2F %.2F re f', $x * $this->k, ($this->h - ($y - $up / 1000 * $this->FontSize)) * $this->k, $w * $this->k, -$ut / 1000 * $this->FontSizePt); + } + + /** + * Line through text. + * @param int $x X coordinate + * @param int $y Y coordinate + * @param string $txt text to linethrough + * @access protected + */ + protected function _dolinethrough($x, $y, $txt) { + $up = $this->CurrentFont['up']; + $ut = $this->CurrentFont['ut']; + $w = $this->GetStringWidth($txt); + return sprintf('%.2F %.2F %.2F %.2F re f', $x * $this->k, ($this->h - ($y - ($this->FontSize/2) - $up / 1000 * $this->FontSize)) * $this->k, $w * $this->k, -$ut / 1000 * $this->FontSizePt); + } + + /** + * Read a 4-byte integer from file. + * @param string $f file name. + * @return 4-byte integer + * @access protected + */ + protected function _freadint($f) { + $a = unpack('Ni', fread($f, 4)); + return $a['i']; + } + + /** + * Add "\" before "\", "(" and ")" + * @param string $s string to escape. + * @return string escaped string. + * @access protected + */ + protected function _escape($s) { + // the chr(13) substitution fixes the Bugs item #1421290. + return strtr($s, array(')' => '\\)', '(' => '\\(', '\\' => '\\\\', chr(13) => '\r')); + } + + /** + * Format a date string for meta information + * @param string $s date string to escape. + * @return string escaped string. + * @access protected + */ + protected function _datastring($s) { + if ($this->encrypted) { + $s = $this->_RC4($this->_objectkey($this->n), $s); + } + return '('. $this->_escape($s).')'; + } + + /** + * Format a text string for meta information + * @param string $s string to escape. + * @return string escaped string. + * @access protected + */ + protected function _textstring($s) { + if ($this->isunicode) { + //Convert string to UTF-16BE + $s = $this->UTF8ToUTF16BE($s, true); + } + return $this->_datastring($s); + } + + /** + * Format a text string + * @param string $s string to escape. + * @return string escaped string. + * @access protected + */ + protected function _escapetext($s) { + if ($this->isunicode) { + if (($this->CurrentFont['type'] == 'core') OR ($this->CurrentFont['type'] == 'TrueType') OR ($this->CurrentFont['type'] == 'Type1')) { + $s = $this->UTF8ToLatin1($s); + } else { + //Convert string to UTF-16BE and reverse RTL language + $s = $this->utf8StrRev($s, false, $this->tmprtl); + } + } + return $this->_escape($s); + } + + /** + * Output a stream. + * @param string $s string to output. + * @access protected + */ + protected function _putstream($s) { + if ($this->encrypted) { + $s = $this->_RC4($this->_objectkey($this->n), $s); + } + $this->_out('stream'); + $this->_out($s); + $this->_out('endstream'); + } + + /** + * Output a string to the document. + * @param string $s string to output. + * @access protected + */ + protected function _out($s) { + if ($this->state == 2) { + if ((!$this->InFooter) AND isset($this->footerlen[$this->page]) AND ($this->footerlen[$this->page] > 0)) { + // puts data before page footer + $pagebuff = $this->getPageBuffer($this->page); + $page = substr($pagebuff, 0, -$this->footerlen[$this->page]); + $footer = substr($pagebuff, -$this->footerlen[$this->page]); + $this->setPageBuffer($this->page, $page.$s."\n".$footer); + // update footer position + $this->footerpos[$this->page] += strlen($s."\n"); + } else { + $this->setPageBuffer($this->page, $s."\n", true); + } + } else { + $this->setBuffer($s."\n"); + } + } + + /** + * Converts UTF-8 strings to codepoints array.
    + * Invalid byte sequences will be replaced with 0xFFFD (replacement character)
    + * Based on: http://www.faqs.org/rfcs/rfc3629.html + *
    +		 * 	  Char. number range  |        UTF-8 octet sequence
    +		 *       (hexadecimal)    |              (binary)
    +		 *    --------------------+-----------------------------------------------
    +		 *    0000 0000-0000 007F | 0xxxxxxx
    +		 *    0000 0080-0000 07FF | 110xxxxx 10xxxxxx
    +		 *    0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
    +		 *    0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
    +		 *    ---------------------------------------------------------------------
    +		 *
    +		 *   ABFN notation:
    +		 *   ---------------------------------------------------------------------
    +		 *   UTF8-octets = *( UTF8-char )
    +		 *   UTF8-char   = UTF8-1 / UTF8-2 / UTF8-3 / UTF8-4
    +		 *   UTF8-1      = %x00-7F
    +		 *   UTF8-2      = %xC2-DF UTF8-tail
    +		 *
    +		 *   UTF8-3      = %xE0 %xA0-BF UTF8-tail / %xE1-EC 2( UTF8-tail ) /
    +		 *                 %xED %x80-9F UTF8-tail / %xEE-EF 2( UTF8-tail )
    +		 *   UTF8-4      = %xF0 %x90-BF 2( UTF8-tail ) / %xF1-F3 3( UTF8-tail ) /
    +		 *                 %xF4 %x80-8F 2( UTF8-tail )
    +		 *   UTF8-tail   = %x80-BF
    +		 *   ---------------------------------------------------------------------
    +		 * 
    + * @param string $str string to process. + * @return array containing codepoints (UTF-8 characters values) + * @access protected + * @author Nicola Asuni + * @since 1.53.0.TC005 (2005-01-05) + */ + protected function UTF8StringToArray($str) { + if (isset($this->cache_UTF8StringToArray['_'.$str])) { + // return cached value + return($this->cache_UTF8StringToArray['_'.$str]); + } + // check cache size + if ($this->cache_size_UTF8StringToArray >= $this->cache_maxsize_UTF8StringToArray) { + // remove first element + array_shift($this->cache_UTF8StringToArray); + } + ++$this->cache_size_UTF8StringToArray; + if (!$this->isunicode) { + // split string into array of equivalent codes + $strarr = array(); + $strlen = strlen($str); + for ($i=0; $i < $strlen; ++$i) { + $strarr[] = ord($str{$i}); + } + // insert new value on cache + $this->cache_UTF8StringToArray['_'.$str] = $strarr; + return $strarr; + } + $unicode = array(); // array containing unicode values + $bytes = array(); // array containing single character byte sequences + $numbytes = 1; // number of octetc needed to represent the UTF-8 character + $str .= ''; // force $str to be a string + $length = strlen($str); + for ($i = 0; $i < $length; ++$i) { + $char = ord($str{$i}); // get one string character at time + if (count($bytes) == 0) { // get starting octect + if ($char <= 0x7F) { + $unicode[] = $char; // use the character "as is" because is ASCII + $numbytes = 1; + } elseif (($char >> 0x05) == 0x06) { // 2 bytes character (0x06 = 110 BIN) + $bytes[] = ($char - 0xC0) << 0x06; + $numbytes = 2; + } elseif (($char >> 0x04) == 0x0E) { // 3 bytes character (0x0E = 1110 BIN) + $bytes[] = ($char - 0xE0) << 0x0C; + $numbytes = 3; + } elseif (($char >> 0x03) == 0x1E) { // 4 bytes character (0x1E = 11110 BIN) + $bytes[] = ($char - 0xF0) << 0x12; + $numbytes = 4; + } else { + // use replacement character for other invalid sequences + $unicode[] = 0xFFFD; + $bytes = array(); + $numbytes = 1; + } + } elseif (($char >> 0x06) == 0x02) { // bytes 2, 3 and 4 must start with 0x02 = 10 BIN + $bytes[] = $char - 0x80; + if (count($bytes) == $numbytes) { + // compose UTF-8 bytes to a single unicode value + $char = $bytes[0]; + for ($j = 1; $j < $numbytes; ++$j) { + $char += ($bytes[$j] << (($numbytes - $j - 1) * 0x06)); + } + if ((($char >= 0xD800) AND ($char <= 0xDFFF)) OR ($char >= 0x10FFFF)) { + /* The definition of UTF-8 prohibits encoding character numbers between + U+D800 and U+DFFF, which are reserved for use with the UTF-16 + encoding form (as surrogate pairs) and do not directly represent + characters. */ + $unicode[] = 0xFFFD; // use replacement character + } else { + $unicode[] = $char; // add char to array + } + // reset data for next char + $bytes = array(); + $numbytes = 1; + } + } else { + // use replacement character for other invalid sequences + $unicode[] = 0xFFFD; + $bytes = array(); + $numbytes = 1; + } + } + // insert new value on cache + $this->cache_UTF8StringToArray['_'.$str] = $unicode; + return $unicode; + } + + /** + * Converts UTF-8 strings to UTF16-BE.
    + * @param string $str string to process. + * @param boolean $setbom if true set the Byte Order Mark (BOM = 0xFEFF) + * @return string + * @access protected + * @author Nicola Asuni + * @since 1.53.0.TC005 (2005-01-05) + * @uses UTF8StringToArray(), arrUTF8ToUTF16BE() + */ + protected function UTF8ToUTF16BE($str, $setbom=true) { + if (!$this->isunicode) { + return $str; // string is not in unicode + } + $unicode = $this->UTF8StringToArray($str); // array containing UTF-8 unicode values + return $this->arrUTF8ToUTF16BE($unicode, $setbom); + } + + /** + * Converts UTF-8 strings to Latin1 when using the standard 14 core fonts.
    + * @param string $str string to process. + * @return string + * @author Andrew Whitehead, Nicola Asuni + * @access protected + * @since 3.2.000 (2008-06-23) + */ + protected function UTF8ToLatin1($str) { + global $utf8tolatin; + if (!$this->isunicode) { + return $str; // string is not in unicode + } + $outstr = ''; // string to be returned + $unicode = $this->UTF8StringToArray($str); // array containing UTF-8 unicode values + foreach ($unicode as $char) { + if ($char < 256) { + $outstr .= chr($char); + } elseif (array_key_exists($char, $utf8tolatin)) { + // map from UTF-8 + $outstr .= chr($utf8tolatin[$char]); + } elseif ($char == 0xFFFD) { + // skip + } else { + $outstr .= '?'; + } + } + return $outstr; + } + + /** + * Converts array of UTF-8 characters to UTF16-BE string.
    + * Based on: http://www.faqs.org/rfcs/rfc2781.html + *
    +		 *   Encoding UTF-16:
    +		 * 
    + 		 *   Encoding of a single character from an ISO 10646 character value to
    +		 *    UTF-16 proceeds as follows. Let U be the character number, no greater
    +		 *    than 0x10FFFF.
    +		 * 
    +		 *    1) If U < 0x10000, encode U as a 16-bit unsigned integer and
    +		 *       terminate.
    +		 * 
    +		 *    2) Let U' = U - 0x10000. Because U is less than or equal to 0x10FFFF,
    +		 *       U' must be less than or equal to 0xFFFFF. That is, U' can be
    +		 *       represented in 20 bits.
    +		 * 
    +		 *    3) Initialize two 16-bit unsigned integers, W1 and W2, to 0xD800 and
    +		 *       0xDC00, respectively. These integers each have 10 bits free to
    +		 *       encode the character value, for a total of 20 bits.
    +		 * 
    +		 *    4) Assign the 10 high-order bits of the 20-bit U' to the 10 low-order
    +		 *       bits of W1 and the 10 low-order bits of U' to the 10 low-order
    +		 *       bits of W2. Terminate.
    +		 * 
    +		 *    Graphically, steps 2 through 4 look like:
    +		 *    U' = yyyyyyyyyyxxxxxxxxxx
    +		 *    W1 = 110110yyyyyyyyyy
    +		 *    W2 = 110111xxxxxxxxxx
    +		 * 
    + * @param array $unicode array containing UTF-8 unicode values + * @param boolean $setbom if true set the Byte Order Mark (BOM = 0xFEFF) + * @return string + * @access protected + * @author Nicola Asuni + * @since 2.1.000 (2008-01-08) + * @see UTF8ToUTF16BE() + */ + protected function arrUTF8ToUTF16BE($unicode, $setbom=true) { + $outstr = ''; // string to be returned + if ($setbom) { + $outstr .= "\xFE\xFF"; // Byte Order Mark (BOM) + } + foreach ($unicode as $char) { + if ($char == 0xFFFD) { + $outstr .= "\xFF\xFD"; // replacement character + } elseif ($char < 0x10000) { + $outstr .= chr($char >> 0x08); + $outstr .= chr($char & 0xFF); + } else { + $char -= 0x10000; + $w1 = 0xD800 | ($char >> 0x10); + $w2 = 0xDC00 | ($char & 0x3FF); + $outstr .= chr($w1 >> 0x08); + $outstr .= chr($w1 & 0xFF); + $outstr .= chr($w2 >> 0x08); + $outstr .= chr($w2 & 0xFF); + } + } + return $outstr; + } + // ==================================================== + + /** + * Set header font. + * @param array $font font + * @access public + * @since 1.1 + */ + public function setHeaderFont($font) { + $this->header_font = $font; + } + + /** + * Get header font. + * @return array() + * @access public + * @since 4.0.012 (2008-07-24) + */ + public function getHeaderFont() { + return $this->header_font; + } + + /** + * Set footer font. + * @param array $font font + * @access public + * @since 1.1 + */ + public function setFooterFont($font) { + $this->footer_font = $font; + } + + /** + * Get Footer font. + * @return array() + * @access public + * @since 4.0.012 (2008-07-24) + */ + public function getFooterFont() { + return $this->footer_font; + } + + /** + * Set language array. + * @param array $language + * @access public + * @since 1.1 + */ + public function setLanguageArray($language) { + $this->l = $language; + $this->rtl = $this->l['a_meta_dir']=='rtl' ? true : false; + } + + /** + * Returns the PDF data. + * @access public + */ + public function getPDFData() { + if ($this->state < 3) { + $this->Close(); + } + return $this->buffer; + } + + /** + * Output anchor link. + * @param string $url link URL or internal link (i.e.: <a href="#23">link to page 23</a>) + * @param string $name link name + * @param int $fill Indicates if the cell background must be painted (1) or transparent (0). Default value: 0. + * @param boolean $firstline if true prints only the first line and return the remaining string. + * @param array $color array of RGB text color + * @param string $style font style (U, D, B, I) + * @return the number of cells used or the remaining text if $firstline = true; + * @access public + */ + public function addHtmlLink($url, $name, $fill=0, $firstline=false, $color='', $style=-1) { + if (!$this->empty_string($url) AND ($url{0} == '#')) { + // convert url to internal link + $page = intval(substr($url, 1)); + $url = $this->AddLink(); + $this->SetLink($url, 0, $page); + } + // store current settings + $prevcolor = $this->fgcolor; + $prevstyle = $this->FontStyle; + if (empty($color)) { + $this->SetTextColorArray($this->htmlLinkColorArray); + } else { + $this->SetTextColorArray($color); + } + if ($style == -1) { + $this->SetFont('', $this->FontStyle.$this->htmlLinkFontStyle); + } else { + $this->SetFont('', $this->FontStyle.$style); + } + $ret = $this->Write($this->lasth, $name, $url, $fill, '', false, 0, $firstline); + // restore settings + $this->SetFont('', $prevstyle); + $this->SetTextColorArray($prevcolor); + return $ret; + } + + /** + * Returns an associative array (keys: R,G,B) from an html color name or a six-digit or three-digit hexadecimal color representation (i.e. #3FE5AA or #7FF). + * @param string $color html color + * @return array RGB color or false in case of error. + * @access public + */ + public function convertHTMLColorToDec($color='#FFFFFF') { + global $webcolor; + $returncolor = false; + $color = preg_replace('/[\s]*/', '', $color); // remove extra spaces + $color = strtolower($color); + if (strlen($color) == 0) { + return false; + } + if (substr($color, 0, 3) == 'rgb') { + $codes = substr($color, 4); + $codes = str_replace(')', '', $codes); + $returncolor = explode(',', $codes, 3); + return $returncolor; + } + if (substr($color, 0, 1) != '#') { + // decode color name + if (isset($webcolor[$color])) { + $color_code = $webcolor[$color]; + } else { + return false; + } + } else { + $color_code = substr($color, 1); + } + switch (strlen($color_code)) { + case 3: { + // three-digit hexadecimal representation + $r = substr($color_code, 0, 1); + $g = substr($color_code, 1, 1); + $b = substr($color_code, 2, 1); + $returncolor['R'] = hexdec($r.$r); + $returncolor['G'] = hexdec($g.$g); + $returncolor['B'] = hexdec($b.$b); + break; + } + case 6: { + // six-digit hexadecimal representation + $returncolor['R'] = hexdec(substr($color_code, 0, 2)); + $returncolor['G'] = hexdec(substr($color_code, 2, 2)); + $returncolor['B'] = hexdec(substr($color_code, 4, 2)); + break; + } + } + return $returncolor; + } + + /** + * Converts pixels to User's Units. + * @param int $px pixels + * @return float value in user's unit + * @access public + * @see setImageScale(), getImageScale() + */ + public function pixelsToUnits($px) { + return ($px / ($this->imgscale * $this->k)); + } + + /** + * Reverse function for htmlentities. + * Convert entities in UTF-8. + * @param $text_to_convert Text to convert. + * @return string converted + * @access public + */ + public function unhtmlentities($text_to_convert) { + return html_entity_decode($text_to_convert, ENT_QUOTES, $this->encoding); + } + + // ENCRYPTION METHODS ---------------------------------- + // SINCE 2.0.000 (2008-01-02) + + /** + * Compute encryption key depending on object number where the encrypted data is stored + * @param int $n object number + * @access protected + * @since 2.0.000 (2008-01-02) + */ + protected function _objectkey($n) { + return substr($this->_md5_16($this->encryption_key.pack('VXxx', $n)), 0, 10); + } + + /** + * Put encryption on PDF document. + * @access protected + * @since 2.0.000 (2008-01-02) + */ + protected function _putencryption() { + $this->_out('/Filter /Standard'); + $this->_out('/V 1'); + $this->_out('/R 2'); + $this->_out('/O ('.$this->_escape($this->Ovalue).')'); + $this->_out('/U ('.$this->_escape($this->Uvalue).')'); + $this->_out('/P '.$this->Pvalue); + } + + /** + * Returns the input text exrypted using RC4 algorithm and the specified key. + * RC4 is the standard encryption algorithm used in PDF format + * @param string $key encryption key + * @param String $text input text to be encrypted + * @return String encrypted text + * @access protected + * @since 2.0.000 (2008-01-02) + * @author Klemen Vodopivec + */ + protected function _RC4($key, $text) { + if ($this->last_rc4_key != $key) { + $k = str_repeat($key, ((256 / strlen($key)) + 1)); + $rc4 = range(0, 255); + $j = 0; + for ($i = 0; $i < 256; ++$i) { + $t = $rc4[$i]; + $j = ($j + $t + ord($k{$i})) % 256; + $rc4[$i] = $rc4[$j]; + $rc4[$j] = $t; + } + $this->last_rc4_key = $key; + $this->last_rc4_key_c = $rc4; + } else { + $rc4 = $this->last_rc4_key_c; + } + $len = strlen($text); + $a = 0; + $b = 0; + $out = ''; + for ($i = 0; $i < $len; ++$i) { + $a = ($a + 1) % 256; + $t = $rc4[$a]; + $b = ($b + $t) % 256; + $rc4[$a] = $rc4[$b]; + $rc4[$b] = $t; + $k = $rc4[($rc4[$a] + $rc4[$b]) % 256]; + $out .= chr(ord($text{$i}) ^ $k); + } + return $out; + } + + /** + * Encrypts a string using MD5 and returns it's value as a binary string. + * @param string $str input string + * @return String MD5 encrypted binary string + * @access protected + * @since 2.0.000 (2008-01-02) + * @author Klemen Vodopivec + */ + protected function _md5_16($str) { + return pack('H*', md5($str)); + } + + /** + * Compute O value (used for RC4 encryption) + * @param String $user_pass user password + * @param String $owner_pass user password + * @return String O value + * @access protected + * @since 2.0.000 (2008-01-02) + * @author Klemen Vodopivec + */ + protected function _Ovalue($user_pass, $owner_pass) { + $tmp = $this->_md5_16($owner_pass); + $owner_RC4_key = substr($tmp, 0, 5); + return $this->_RC4($owner_RC4_key, $user_pass); + } + + /** + * Compute U value (used for RC4 encryption) + * @return String U value + * @access protected + * @since 2.0.000 (2008-01-02) + * @author Klemen Vodopivec + */ + protected function _Uvalue() { + return $this->_RC4($this->encryption_key, $this->padding); + } + + /** + * Compute encryption key + * @param String $user_pass user password + * @param String $owner_pass user password + * @param String $protection protection type + * @access protected + * @since 2.0.000 (2008-01-02) + * @author Klemen Vodopivec + */ + protected function _generateencryptionkey($user_pass, $owner_pass, $protection) { + // Pad passwords + $user_pass = substr($user_pass.$this->padding, 0, 32); + $owner_pass = substr($owner_pass.$this->padding, 0, 32); + // Compute O value + $this->Ovalue = $this->_Ovalue($user_pass, $owner_pass); + // Compute encyption key + $tmp = $this->_md5_16($user_pass.$this->Ovalue.chr($protection)."\xFF\xFF\xFF"); + $this->encryption_key = substr($tmp, 0, 5); + // Compute U value + $this->Uvalue = $this->_Uvalue(); + // Compute P value + $this->Pvalue = -(($protection^255) + 1); + } + + /** + * Set document protection + * The permission array is composed of values taken from the following ones: + * - copy: copy text and images to the clipboard + * - print: print the document + * - modify: modify it (except for annotations and forms) + * - annot-forms: add annotations and forms + * Remark: the protection against modification is for people who have the full Acrobat product. + * If you don't set any password, the document will open as usual. If you set a user password, the PDF viewer will ask for it before displaying the document. The master password, if different from the user one, can be used to get full access. + * Note: protecting a document requires to encrypt it, which increases the processing time a lot. This can cause a PHP time-out in some cases, especially if the document contains images or fonts. + * @param Array $permissions the set of permissions. Empty by default (only viewing is allowed). (print, modify, copy, annot-forms) + * @param String $user_pass user password. Empty by default. + * @param String $owner_pass owner password. If not specified, a random value is used. + * @access public + * @since 2.0.000 (2008-01-02) + * @author Klemen Vodopivec + */ + public function SetProtection($permissions=array(), $user_pass='', $owner_pass=null) { + $options = array('print' => 4, 'modify' => 8, 'copy' => 16, 'annot-forms' => 32); + $protection = 192; + foreach ($permissions as $permission) { + if (!isset($options[$permission])) { + $this->Error('Incorrect permission: '.$permission); + } + $protection += $options[$permission]; + } + if ($owner_pass === null) { + $owner_pass = uniqid(rand()); + } + $this->encrypted = true; + $this->_generateencryptionkey($user_pass, $owner_pass, $protection); + } + + // END OF ENCRYPTION FUNCTIONS ------------------------- + + // START TRANSFORMATIONS SECTION ----------------------- + + /** + * Starts a 2D tranformation saving current graphic state. + * This function must be called before scaling, mirroring, translation, rotation and skewing. + * Use StartTransform() before, and StopTransform() after the transformations to restore the normal behavior. + * @access public + * @since 2.1.000 (2008-01-07) + * @see StartTransform(), StopTransform() + */ + public function StartTransform() { + $this->_out('q'); + $this->transfmrk[$this->page][] = $this->pagelen[$this->page]; + } + + /** + * Stops a 2D tranformation restoring previous graphic state. + * This function must be called after scaling, mirroring, translation, rotation and skewing. + * Use StartTransform() before, and StopTransform() after the transformations to restore the normal behavior. + * @access public + * @since 2.1.000 (2008-01-07) + * @see StartTransform(), StopTransform() + */ + public function StopTransform() { + $this->_out('Q'); + if (isset($this->transfmatrix)) { + array_pop($this->transfmatrix); + } + array_pop($this->transfmrk[$this->page]); + } + /** + * Horizontal Scaling. + * @param float $s_x scaling factor for width as percent. 0 is not allowed. + * @param int $x abscissa of the scaling center. Default is current x position + * @param int $y ordinate of the scaling center. Default is current y position + * @access public + * @since 2.1.000 (2008-01-07) + * @see StartTransform(), StopTransform() + */ + public function ScaleX($s_x, $x='', $y='') { + $this->Scale($s_x, 100, $x, $y); + } + + /** + * Vertical Scaling. + * @param float $s_y scaling factor for height as percent. 0 is not allowed. + * @param int $x abscissa of the scaling center. Default is current x position + * @param int $y ordinate of the scaling center. Default is current y position + * @access public + * @since 2.1.000 (2008-01-07) + * @see StartTransform(), StopTransform() + */ + public function ScaleY($s_y, $x='', $y='') { + $this->Scale(100, $s_y, $x, $y); + } + + /** + * Vertical and horizontal proportional Scaling. + * @param float $s scaling factor for width and height as percent. 0 is not allowed. + * @param int $x abscissa of the scaling center. Default is current x position + * @param int $y ordinate of the scaling center. Default is current y position + * @access public + * @since 2.1.000 (2008-01-07) + * @see StartTransform(), StopTransform() + */ + public function ScaleXY($s, $x='', $y='') { + $this->Scale($s, $s, $x, $y); + } + + /** + * Vertical and horizontal non-proportional Scaling. + * @param float $s_x scaling factor for width as percent. 0 is not allowed. + * @param float $s_y scaling factor for height as percent. 0 is not allowed. + * @param int $x abscissa of the scaling center. Default is current x position + * @param int $y ordinate of the scaling center. Default is current y position + * @access public + * @since 2.1.000 (2008-01-07) + * @see StartTransform(), StopTransform() + */ + public function Scale($s_x, $s_y, $x='', $y='') { + if ($x === '') { + $x = $this->x; + } + if ($y === '') { + $y = $this->y; + } + if ($this->rtl) { + $x = $this->w - $x; + } + if (($s_x == 0) OR ($s_y == 0)) { + $this->Error('Please do not use values equal to zero for scaling'); + } + $y = ($this->h - $y) * $this->k; + $x *= $this->k; + //calculate elements of transformation matrix + $s_x /= 100; + $s_y /= 100; + $tm[0] = $s_x; + $tm[1] = 0; + $tm[2] = 0; + $tm[3] = $s_y; + $tm[4] = $x * (1 - $s_x); + $tm[5] = $y * (1 - $s_y); + //scale the coordinate system + $this->Transform($tm); + } + + /** + * Horizontal Mirroring. + * @param int $x abscissa of the point. Default is current x position + * @access public + * @since 2.1.000 (2008-01-07) + * @see StartTransform(), StopTransform() + */ + public function MirrorH($x='') { + $this->Scale(-100, 100, $x); + } + + /** + * Verical Mirroring. + * @param int $y ordinate of the point. Default is current y position + * @access public + * @since 2.1.000 (2008-01-07) + * @see StartTransform(), StopTransform() + */ + public function MirrorV($y='') { + $this->Scale(100, -100, '', $y); + } + + /** + * Point reflection mirroring. + * @param int $x abscissa of the point. Default is current x position + * @param int $y ordinate of the point. Default is current y position + * @access public + * @since 2.1.000 (2008-01-07) + * @see StartTransform(), StopTransform() + */ + public function MirrorP($x='',$y='') { + $this->Scale(-100, -100, $x, $y); + } + + /** + * Reflection against a straight line through point (x, y) with the gradient angle (angle). + * @param float $angle gradient angle of the straight line. Default is 0 (horizontal line). + * @param int $x abscissa of the point. Default is current x position + * @param int $y ordinate of the point. Default is current y position + * @access public + * @since 2.1.000 (2008-01-07) + * @see StartTransform(), StopTransform() + */ + public function MirrorL($angle=0, $x='',$y='') { + $this->Scale(-100, 100, $x, $y); + $this->Rotate(-2*($angle-90), $x, $y); + } + + /** + * Translate graphic object horizontally. + * @param int $t_x movement to the right (or left for RTL) + * @access public + * @since 2.1.000 (2008-01-07) + * @see StartTransform(), StopTransform() + */ + public function TranslateX($t_x) { + $this->Translate($t_x, 0); + } + + /** + * Translate graphic object vertically. + * @param int $t_y movement to the bottom + * @access public + * @since 2.1.000 (2008-01-07) + * @see StartTransform(), StopTransform() + */ + public function TranslateY($t_y) { + $this->Translate(0, $t_y); + } + + /** + * Translate graphic object horizontally and vertically. + * @param int $t_x movement to the right + * @param int $t_y movement to the bottom + * @access public + * @since 2.1.000 (2008-01-07) + * @see StartTransform(), StopTransform() + */ + public function Translate($t_x, $t_y) { + if ($this->rtl) { + $t_x = -$t_x; + } + //calculate elements of transformation matrix + $tm[0] = 1; + $tm[1] = 0; + $tm[2] = 0; + $tm[3] = 1; + $tm[4] = $t_x * $this->k; + $tm[5] = -$t_y * $this->k; + //translate the coordinate system + $this->Transform($tm); + } + + /** + * Rotate object. + * @param float $angle angle in degrees for counter-clockwise rotation + * @param int $x abscissa of the rotation center. Default is current x position + * @param int $y ordinate of the rotation center. Default is current y position + * @access public + * @since 2.1.000 (2008-01-07) + * @see StartTransform(), StopTransform() + */ + public function Rotate($angle, $x='', $y='') { + if ($x === '') { + $x = $this->x; + } + if ($y === '') { + $y = $this->y; + } + if ($this->rtl) { + $x = $this->w - $x; + $angle = -$angle; + } + $y = ($this->h - $y) * $this->k; + $x *= $this->k; + //calculate elements of transformation matrix + $tm[0] = cos(deg2rad($angle)); + $tm[1] = sin(deg2rad($angle)); + $tm[2] = -$tm[1]; + $tm[3] = $tm[0]; + $tm[4] = $x + ($tm[1] * $y) - ($tm[0] * $x); + $tm[5] = $y - ($tm[0] * $y) - ($tm[1] * $x); + //rotate the coordinate system around ($x,$y) + $this->Transform($tm); + } + + /** + * Skew horizontally. + * @param float $angle_x angle in degrees between -90 (skew to the left) and 90 (skew to the right) + * @param int $x abscissa of the skewing center. default is current x position + * @param int $y ordinate of the skewing center. default is current y position + * @access public + * @since 2.1.000 (2008-01-07) + * @see StartTransform(), StopTransform() + */ + public function SkewX($angle_x, $x='', $y='') { + $this->Skew($angle_x, 0, $x, $y); + } + + /** + * Skew vertically. + * @param float $angle_y angle in degrees between -90 (skew to the bottom) and 90 (skew to the top) + * @param int $x abscissa of the skewing center. default is current x position + * @param int $y ordinate of the skewing center. default is current y position + * @access public + * @since 2.1.000 (2008-01-07) + * @see StartTransform(), StopTransform() + */ + public function SkewY($angle_y, $x='', $y='') { + $this->Skew(0, $angle_y, $x, $y); + } + + /** + * Skew. + * @param float $angle_x angle in degrees between -90 (skew to the left) and 90 (skew to the right) + * @param float $angle_y angle in degrees between -90 (skew to the bottom) and 90 (skew to the top) + * @param int $x abscissa of the skewing center. default is current x position + * @param int $y ordinate of the skewing center. default is current y position + * @access public + * @since 2.1.000 (2008-01-07) + * @see StartTransform(), StopTransform() + */ + public function Skew($angle_x, $angle_y, $x='', $y='') { + if ($x === '') { + $x = $this->x; + } + if ($y === '') { + $y = $this->y; + } + if ($this->rtl) { + $x = $this->w - $x; + $angle_x = -$angle_x; + } + if (($angle_x <= -90) OR ($angle_x >= 90) OR ($angle_y <= -90) OR ($angle_y >= 90)) { + $this->Error('Please use values between -90 and +90 degrees for Skewing.'); + } + $x *= $this->k; + $y = ($this->h - $y) * $this->k; + //calculate elements of transformation matrix + $tm[0] = 1; + $tm[1] = tan(deg2rad($angle_y)); + $tm[2] = tan(deg2rad($angle_x)); + $tm[3] = 1; + $tm[4] = -$tm[2] * $y; + $tm[5] = -$tm[1] * $x; + //skew the coordinate system + $this->Transform($tm); + } + + /** + * Apply graphic transformations. + * @access protected + * @since 2.1.000 (2008-01-07) + * @see StartTransform(), StopTransform() + */ + protected function Transform($tm) { + $this->_out(sprintf('%.3F %.3F %.3F %.3F %.3F %.3F cm', $tm[0], $tm[1], $tm[2], $tm[3], $tm[4], $tm[5])); + // store transformation matrix + $this->transfmatrix[] = array('a' => $tm[0], 'b' => $tm[1], 'c' => $tm[2], 'd' => $tm[3], 'e' => $tm[4], 'f' => $tm[5]); + // update tranformation mark + if (end($this->transfmrk[$this->page]) !== false) { + $key = key($this->transfmrk[$this->page]); + $this->transfmrk[$this->page][$key] = $this->pagelen[$this->page]; + } + } + + // END TRANSFORMATIONS SECTION ------------------------- + + + // START GRAPHIC FUNCTIONS SECTION --------------------- + // The following section is based on the code provided by David Hernandez Sanz + + /** + * Defines the line width. By default, the value equals 0.2 mm. The method can be called before the first page is created and the value is retained from page to page. + * @param float $width The width. + * @access public + * @since 1.0 + * @see Line(), Rect(), Cell(), MultiCell() + */ + public function SetLineWidth($width) { + //Set line width + $this->LineWidth = $width; + $this->linestyleWidth = sprintf('%.2F w', ($width * $this->k)); + $this->_out($this->linestyleWidth); + } + + /** + * Returns the current the line width. + * @return int Line width + * @access public + * @since 2.1.000 (2008-01-07) + * @see Line(), SetLineWidth() + */ + public function GetLineWidth() { + return $this->LineWidth; + } + + /** + * Set line style. + * @param array $style Line style. Array with keys among the following: + *
      + *
    • width (float): Width of the line in user units.
    • + *
    • cap (string): Type of cap to put on the line. Possible values are: + * butt, round, square. The difference between "square" and "butt" is that + * "square" projects a flat end past the end of the line.
    • + *
    • join (string): Type of join. Possible values are: miter, round, + * bevel.
    • + *
    • dash (mixed): Dash pattern. Is 0 (without dash) or string with + * series of length values, which are the lengths of the on and off dashes. + * For example: "2" represents 2 on, 2 off, 2 on, 2 off, ...; "2,1" is 2 on, + * 1 off, 2 on, 1 off, ...
    • + *
    • phase (integer): Modifier on the dash pattern which is used to shift + * the point at which the pattern starts.
    • + *
    • color (array): Draw color. Format: array(GREY) or array(R,G,B) or array(C,M,Y,K).
    • + *
    + * @access public + * @since 2.1.000 (2008-01-08) + */ + public function SetLineStyle($style) { + extract($style); + if (isset($width)) { + $width_prev = $this->LineWidth; + $this->SetLineWidth($width); + $this->LineWidth = $width_prev; + } + if (isset($cap)) { + $ca = array('butt' => 0, 'round'=> 1, 'square' => 2); + if (isset($ca[$cap])) { + $this->linestyleCap = $ca[$cap].' J'; + $this->_out($this->linestyleCap); + } + } + if (isset($join)) { + $ja = array('miter' => 0, 'round' => 1, 'bevel' => 2); + if (isset($ja[$join])) { + $this->linestyleJoin = $ja[$join].' j'; + $this->_out($this->linestyleJoin); + } + } + if (isset($dash)) { + $dash_string = ''; + if ($dash) { + if (preg_match('/^.+,/', $dash)) { + $tab = explode(',', $dash); + } else { + $tab = array($dash); + } + $dash_string = ''; + foreach ($tab as $i => $v) { + if ($i) { + $dash_string .= ' '; + } + $dash_string .= sprintf("%.2F", $v); + } + } + if (!isset($phase) OR !$dash) { + $phase = 0; + } + $this->linestyleDash = sprintf("[%s] %.2F d", $dash_string, $phase); + $this->_out($this->linestyleDash); + } + if (isset($color)) { + $this->SetDrawColorArray($color); + } + } + + /* + * Set a draw point. + * @param float $x Abscissa of point. + * @param float $y Ordinate of point. + * @access protected + * @since 2.1.000 (2008-01-08) + */ + protected function _outPoint($x, $y) { + if ($this->rtl) { + $x = $this->w - $x; + } + $this->_out(sprintf("%.2F %.2F m", $x * $this->k, ($this->h - $y) * $this->k)); + } + + /* + * Draws a line from last draw point. + * @param float $x Abscissa of end point. + * @param float $y Ordinate of end point. + * @access protected + * @since 2.1.000 (2008-01-08) + */ + protected function _outLine($x, $y) { + if ($this->rtl) { + $x = $this->w - $x; + } + $this->_out(sprintf("%.2F %.2F l", $x * $this->k, ($this->h - $y) * $this->k)); + } + + /** + * Draws a rectangle. + * @param float $x Abscissa of upper-left corner (or upper-right corner for RTL language). + * @param float $y Ordinate of upper-left corner (or upper-right corner for RTL language). + * @param float $w Width. + * @param float $h Height. + * @param string $op options + * @access protected + * @since 2.1.000 (2008-01-08) + */ + protected function _outRect($x, $y, $w, $h, $op) { + if ($this->rtl) { + $x = $this->w - $x - $w; + } + $this->_out(sprintf('%.2F %.2F %.2F %.2F re %s', $x*$this->k, ($this->h-$y)*$this->k, $w*$this->k, -$h*$this->k, $op)); + } + + /* + * Draws a Bezier curve from last draw point. + * The Bezier curve is a tangent to the line between the control points at either end of the curve. + * @param float $x1 Abscissa of control point 1. + * @param float $y1 Ordinate of control point 1. + * @param float $x2 Abscissa of control point 2. + * @param float $y2 Ordinate of control point 2. + * @param float $x3 Abscissa of end point. + * @param float $y3 Ordinate of end point. + * @access protected + * @since 2.1.000 (2008-01-08) + */ + protected function _outCurve($x1, $y1, $x2, $y2, $x3, $y3) { + if ($this->rtl) { + $x1 = $this->w - $x1; + $x2 = $this->w - $x2; + $x3 = $this->w - $x3; + } + $this->_out(sprintf("%.2F %.2F %.2F %.2F %.2F %.2F c", $x1 * $this->k, ($this->h - $y1) * $this->k, $x2 * $this->k, ($this->h - $y2) * $this->k, $x3 * $this->k, ($this->h - $y3) * $this->k)); + } + + /** + * Draws a line between two points. + * @param float $x1 Abscissa of first point. + * @param float $y1 Ordinate of first point. + * @param float $x2 Abscissa of second point. + * @param float $y2 Ordinate of second point. + * @param array $style Line style. Array like for {@link SetLineStyle SetLineStyle}. Default value: default line style (empty array). + * @access public + * @since 1.0 + * @see SetLineWidth(), SetDrawColor(), SetLineStyle() + */ + public function Line($x1, $y1, $x2, $y2, $style=array()) { + if ($style) { + $this->SetLineStyle($style); + } + $this->_outPoint($x1, $y1); + $this->_outLine($x2, $y2); + $this->_out(' S'); + } + + /** + * Draws a rectangle. + * @param float $x Abscissa of upper-left corner (or upper-right corner for RTL language). + * @param float $y Ordinate of upper-left corner (or upper-right corner for RTL language). + * @param float $w Width. + * @param float $h Height. + * @param string $style Style of rendering. Possible values are: + *
      + *
    • D or empty string: Draw (default).
    • + *
    • F: Fill.
    • + *
    • DF or FD: Draw and fill.
    • + *
    • CNZ: Clipping mode (using the even-odd rule to determine which regions lie inside the clipping path).
    • + *
    • CEO: Clipping mode (using the nonzero winding number rule to determine which regions lie inside the clipping path).
    • + *
    + * @param array $border_style Border style of rectangle. Array with keys among the following: + *
      + *
    • all: Line style of all borders. Array like for {@link SetLineStyle SetLineStyle}.
    • + *
    • L, T, R, B or combinations: Line style of left, top, right or bottom border. Array like for {@link SetLineStyle SetLineStyle}.
    • + *
    + * If a key is not present or is null, not draws the border. Default value: default line style (empty array). + * @param array $border_style Border style of rectangle. Array like for {@link SetLineStyle SetLineStyle}. Default value: default line style (empty array). + * @param array $fill_color Fill color. Format: array(GREY) or array(R,G,B) or array(C,M,Y,K). Default value: default color (empty array). + * @access public + * @since 1.0 + * @see SetLineStyle() + */ + public function Rect($x, $y, $w, $h, $style='', $border_style=array(), $fill_color=array()) { + if (!(false === strpos($style, 'F')) AND isset($fill_color)) { + $this->SetFillColorArray($fill_color); + } + switch ($style) { + case 'F': { + $op = 'f'; + $border_style = array(); + $this->_outRect($x, $y, $w, $h, $op); + break; + } + case 'DF': + case 'FD': { + if ((!$border_style) OR (isset($border_style['all']))) { + $op = 'B'; + if (isset($border_style['all'])) { + $this->SetLineStyle($border_style['all']); + $border_style = array(); + } + } else { + $op = 'f'; + } + $this->_outRect($x, $y, $w, $h, $op); + break; + } + case 'CNZ': { + $op = 'W n'; + $this->_outRect($x, $y, $w, $h, $op); + break; + } + case 'CEO': { + $op = 'W* n'; + $this->_outRect($x, $y, $w, $h, $op); + break; + } + default: { + $op = 'S'; + if ((!$border_style) OR (isset($border_style['all']))) { + if (isset($border_style['all']) AND $border_style['all']) { + $this->SetLineStyle($border_style['all']); + $border_style = array(); + } + $this->_outRect($x, $y, $w, $h, $op); + } + break; + } + } + if ($border_style) { + $border_style2 = array(); + foreach ($border_style as $line => $value) { + $lenght = strlen($line); + for ($i = 0; $i < $lenght; ++$i) { + $border_style2[$line[$i]] = $value; + } + } + $border_style = $border_style2; + if (isset($border_style['L']) AND $border_style['L']) { + $this->Line($x, $y, $x, $y + $h, $border_style['L']); + } + if (isset($border_style['T']) AND $border_style['T']) { + $this->Line($x, $y, $x + $w, $y, $border_style['T']); + } + if (isset($border_style['R']) AND $border_style['R']) { + $this->Line($x + $w, $y, $x + $w, $y + $h, $border_style['R']); + } + if (isset($border_style['B']) AND $border_style['B']) { + $this->Line($x, $y + $h, $x + $w, $y + $h, $border_style['B']); + } + } + } + + + /** + * Draws a Bezier curve. + * The Bezier curve is a tangent to the line between the control points at + * either end of the curve. + * @param float $x0 Abscissa of start point. + * @param float $y0 Ordinate of start point. + * @param float $x1 Abscissa of control point 1. + * @param float $y1 Ordinate of control point 1. + * @param float $x2 Abscissa of control point 2. + * @param float $y2 Ordinate of control point 2. + * @param float $x3 Abscissa of end point. + * @param float $y3 Ordinate of end point. + * @param string $style Style of rendering. Possible values are: + *
      + *
    • D or empty string: Draw (default).
    • + *
    • F: Fill.
    • + *
    • DF or FD: Draw and fill.
    • + *
    • CNZ: Clipping mode (using the even-odd rule to determine which regions lie inside the clipping path).
    • + *
    • CEO: Clipping mode (using the nonzero winding number rule to determine which regions lie inside the clipping path).
    • + *
    + * @param array $line_style Line style of curve. Array like for {@link SetLineStyle SetLineStyle}. Default value: default line style (empty array). + * @param array $fill_color Fill color. Format: array(GREY) or array(R,G,B) or array(C,M,Y,K). Default value: default color (empty array). + * @access public + * @see SetLineStyle() + * @since 2.1.000 (2008-01-08) + */ + public function Curve($x0, $y0, $x1, $y1, $x2, $y2, $x3, $y3, $style='', $line_style=array(), $fill_color=array()) { + if (!(false === strpos($style, 'F')) AND isset($fill_color)) { + $this->SetFillColorArray($fill_color); + } + switch ($style) { + case 'F': { + $op = 'f'; + $line_style = array(); + break; + } + case 'FD': + case 'DF': { + $op = 'B'; + break; + } + case 'CNZ': { + $op = 'W n'; + break; + } + case 'CEO': { + $op = 'W* n'; + break; + } + default: { + $op = 'S'; + break; + } + } + if ($line_style) { + $this->SetLineStyle($line_style); + } + $this->_outPoint($x0, $y0); + $this->_outCurve($x1, $y1, $x2, $y2, $x3, $y3); + $this->_out($op); + } + + /** + * Draws a poly-Bezier curve. + * Each Bezier curve segment is a tangent to the line between the control points at + * either end of the curve. + * @param float $x0 Abscissa of start point. + * @param float $y0 Ordinate of start point. + * @param float $segments An array of bezier descriptions. Format: array(x1, y1, x2, y2, x3, y3). + * @param string $style Style of rendering. Possible values are: + *
      + *
    • D or empty string: Draw (default).
    • + *
    • F: Fill.
    • + *
    • DF or FD: Draw and fill.
    • + *
    • CNZ: Clipping mode (using the even-odd rule to determine which regions lie inside the clipping path).
    • + *
    • CEO: Clipping mode (using the nonzero winding number rule to determine which regions lie inside the clipping path).
    • + *
    + * @param array $line_style Line style of curve. Array like for {@link SetLineStyle SetLineStyle}. Default value: default line style (empty array). + * @param array $fill_color Fill color. Format: array(GREY) or array(R,G,B) or array(C,M,Y,K). Default value: default color (empty array). + * @access public + * @see SetLineStyle() + * @since 3.0008 (2008-05-12) + */ + public function Polycurve($x0, $y0, $segments, $style='', $line_style=array(), $fill_color=array()) { + if (!(false === strpos($style, 'F')) AND isset($fill_color)) { + $this->SetFillColorArray($fill_color); + } + switch ($style) { + case 'F': { + $op = 'f'; + $line_style = array(); + break; + } + case 'FD': + case 'DF': { + $op = 'B'; + break; + } + case 'CNZ': { + $op = 'W n'; + break; + } + case 'CEO': { + $op = 'W* n'; + break; + } + default: { + $op = 'S'; + break; + } + } + if ($line_style) { + $this->SetLineStyle($line_style); + } + $this->_outPoint($x0, $y0); + foreach ($segments as $segment) { + list($x1, $y1, $x2, $y2, $x3, $y3) = $segment; + $this->_outCurve($x1, $y1, $x2, $y2, $x3, $y3); + } + $this->_out($op); + } + + /** + * Draws an ellipse. + * An ellipse is formed from n Bezier curves. + * @param float $x0 Abscissa of center point. + * @param float $y0 Ordinate of center point. + * @param float $rx Horizontal radius. + * @param float $ry Vertical radius (if ry = 0 then is a circle, see {@link Circle Circle}). Default value: 0. + * @param float $angle: Angle oriented (anti-clockwise). Default value: 0. + * @param float $astart: Angle start of draw line. Default value: 0. + * @param float $afinish: Angle finish of draw line. Default value: 360. + * @param string $style Style of rendering. Possible values are: + *
      + *
    • D or empty string: Draw (default).
    • + *
    • F: Fill.
    • + *
    • DF or FD: Draw and fill.
    • + *
    • C: Draw close.
    • + *
    • CNZ: Clipping mode (using the even-odd rule to determine which regions lie inside the clipping path).
    • + *
    • CEO: Clipping mode (using the nonzero winding number rule to determine which regions lie inside the clipping path).
    • + *
    + * @param array $line_style Line style of ellipse. Array like for {@link SetLineStyle SetLineStyle}. Default value: default line style (empty array). + * @param array $fill_color Fill color. Format: array(GREY) or array(R,G,B) or array(C,M,Y,K). Default value: default color (empty array). + * @param integer $nc Number of curves used in ellipse. Default value: 8. + * @access public + * @since 2.1.000 (2008-01-08) + */ + public function Ellipse($x0, $y0, $rx, $ry=0, $angle=0, $astart=0, $afinish=360, $style='', $line_style=array(), $fill_color=array(), $nc=8) { + if ($angle) { + $this->StartTransform(); + $this->Rotate($angle, $x0, $y0); + $this->Ellipse($x0, $y0, $rx, $ry, 0, $astart, $afinish, $style, $line_style, $fill_color, $nc); + $this->StopTransform(); + return; + } + if ($rx) { + if (!(false === strpos($style, 'F')) AND isset($fill_color)) { + $this->SetFillColorArray($fill_color); + } + switch ($style) { + case 'F': { + $op = 'f'; + $line_style = array(); + break; + } + case 'FD': + case 'DF': { + $op = 'B'; + break; + } + case 'C': { + $op = 's'; // Small 's' signifies closing the path as well + break; + } + case 'CNZ': { + $op = 'W n'; + break; + } + case 'CEO': { + $op = 'W* n'; + break; + } + default: { + $op = 'S'; + break; + } + } + if ($line_style) { + $this->SetLineStyle($line_style); + } + if (!$ry) { + $ry = $rx; + } + $rx *= $this->k; + $ry *= $this->k; + if ($nc < 2) { + $nc = 2; + } + $astart = deg2rad((float) $astart); + $afinish = deg2rad((float) $afinish); + $total_angle = $afinish - $astart; + $dt = $total_angle / $nc; + $dtm = $dt / 3; + $x0 *= $this->k; + $y0 = ($this->h - $y0) * $this->k; + $t1 = $astart; + $a0 = $x0 + ($rx * cos($t1)); + $b0 = $y0 + ($ry * sin($t1)); + $c0 = -$rx * sin($t1); + $d0 = $ry * cos($t1); + $this->_outPoint($a0 / $this->k, $this->h - ($b0 / $this->k)); + for ($i = 1; $i <= $nc; ++$i) { + // Draw this bit of the total curve + $t1 = ($i * $dt) + $astart; + $a1 = $x0 + ($rx * cos($t1)); + $b1 = $y0 + ($ry * sin($t1)); + $c1 = -$rx * sin($t1); + $d1 = $ry * cos($t1); + $this->_outCurve(($a0 + ($c0 * $dtm)) / $this->k, $this->h - (($b0 + ($d0 * $dtm)) / $this->k), ($a1 - ($c1 * $dtm)) / $this->k, $this->h - (($b1 - ($d1 * $dtm)) / $this->k), $a1 / $this->k, $this->h - ($b1 / $this->k)); + $a0 = $a1; + $b0 = $b1; + $c0 = $c1; + $d0 = $d1; + } + $this->_out($op); + } + } + + /** + * Draws a circle. + * A circle is formed from n Bezier curves. + * @param float $x0 Abscissa of center point. + * @param float $y0 Ordinate of center point. + * @param float $r Radius. + * @param float $astart: Angle start of draw line. Default value: 0. + * @param float $afinish: Angle finish of draw line. Default value: 360. + * @param string $style Style of rendering. Possible values are: + *
      + *
    • D or empty string: Draw (default).
    • + *
    • F: Fill.
    • + *
    • DF or FD: Draw and fill.
    • + *
    • C: Draw close.
    • + *
    • CNZ: Clipping mode (using the even-odd rule to determine which regions lie inside the clipping path).
    • + *
    • CEO: Clipping mode (using the nonzero winding number rule to determine which regions lie inside the clipping path).
    • + *
    + * @param array $line_style Line style of circle. Array like for {@link SetLineStyle SetLineStyle}. Default value: default line style (empty array). + * @param array $fill_color Fill color. Format: array(red, green, blue). Default value: default color (empty array). + * @param integer $nc Number of curves used in circle. Default value: 8. + * @access public + * @since 2.1.000 (2008-01-08) + */ + public function Circle($x0, $y0, $r, $astart=0, $afinish=360, $style='', $line_style=array(), $fill_color=array(), $nc=8) { + $this->Ellipse($x0, $y0, $r, 0, 0, $astart, $afinish, $style, $line_style, $fill_color, $nc); + } + + /** + * Draws a polygon. + * @param array $p Points 0 to ($np - 1). Array with values (x0, y0, x1, y1,..., x(np-1), y(np - 1)) + * @param string $style Style of rendering. Possible values are: + *
      + *
    • D or empty string: Draw (default).
    • + *
    • F: Fill.
    • + *
    • DF or FD: Draw and fill.
    • + *
    • CNZ: Clipping mode (using the even-odd rule to determine which regions lie inside the clipping path).
    • + *
    • CEO: Clipping mode (using the nonzero winding number rule to determine which regions lie inside the clipping path).
    • + *
    + * @param array $line_style Line style of polygon. Array with keys among the following: + *
      + *
    • all: Line style of all lines. Array like for {@link SetLineStyle SetLineStyle}.
    • + *
    • 0 to ($np - 1): Line style of each line. Array like for {@link SetLineStyle SetLineStyle}.
    • + *
    + * If a key is not present or is null, not draws the line. Default value is default line style (empty array). + * @param array $fill_color Fill color. Format: array(GREY) or array(R,G,B) or array(C,M,Y,K). Default value: default color (empty array). + * @access public + * @since 2.1.000 (2008-01-08) + */ + public function Polygon($p, $style='', $line_style=array(), $fill_color=array()) { + $np = count($p) / 2; + if (!(false === strpos($style, 'F')) AND isset($fill_color)) { + $this->SetFillColorArray($fill_color); + } + switch ($style) { + case 'F': { + $line_style = array(); + $op = 'f'; + break; + } + case 'FD': + case 'DF': { + $op = 'B'; + break; + } + case 'CNZ': { + $op = 'W n'; + break; + } + case 'CEO': { + $op = 'W* n'; + break; + } + default: { + $op = 'S'; + break; + } + } + $draw = true; + if ($line_style) { + if (isset($line_style['all'])) { + $this->SetLineStyle($line_style['all']); + } else { // 0 .. (np - 1), op = {B, S} + $draw = false; + if ('B' == $op) { + $op = 'f'; + $this->_outPoint($p[0], $p[1]); + for ($i = 2; $i < ($np * 2); $i = $i + 2) { + $this->_outLine($p[$i], $p[$i + 1]); + } + $this->_outLine($p[0], $p[1]); + $this->_out($op); + } + $p[($np * 2)] = $p[0]; + $p[(($np * 2) + 1)] = $p[1]; + for ($i = 0; $i < $np; ++$i) { + if (isset($line_style[$i]) AND ($line_style[$i] != 0)) { + $this->Line($p[($i * 2)], $p[(($i * 2) + 1)], $p[(($i * 2) + 2)], $p[(($i * 2) + 3)], $line_style[$i]); + } + } + } + } + if ($draw) { + $this->_outPoint($p[0], $p[1]); + for ($i = 2; $i < ($np * 2); $i = $i + 2) { + $this->_outLine($p[$i], $p[$i + 1]); + } + $this->_outLine($p[0], $p[1]); + $this->_out($op); + } + } + + /** + * Draws a regular polygon. + * @param float $x0 Abscissa of center point. + * @param float $y0 Ordinate of center point. + * @param float $r: Radius of inscribed circle. + * @param integer $ns Number of sides. + * @param float $angle Angle oriented (anti-clockwise). Default value: 0. + * @param boolean $draw_circle Draw inscribed circle or not. Default value: false. + * @param string $style Style of rendering. Possible values are: + *
      + *
    • D or empty string: Draw (default).
    • + *
    • F: Fill.
    • + *
    • DF or FD: Draw and fill.
    • + *
    • CNZ: Clipping mode (using the even-odd rule to determine which regions lie inside the clipping path).
    • + *
    • CEO: Clipping mode (using the nonzero winding number rule to determine which regions lie inside the clipping path).
    • + *
    + * @param array $line_style Line style of polygon sides. Array with keys among the following: + *
      + *
    • all: Line style of all sides. Array like for {@link SetLineStyle SetLineStyle}.
    • + *
    • 0 to ($ns - 1): Line style of each side. Array like for {@link SetLineStyle SetLineStyle}.
    • + *
    + * If a key is not present or is null, not draws the side. Default value is default line style (empty array). + * @param array $fill_color Fill color. Format: array(red, green, blue). Default value: default color (empty array). + * @param string $circle_style Style of rendering of inscribed circle (if draws). Possible values are: + *
      + *
    • D or empty string: Draw (default).
    • + *
    • F: Fill.
    • + *
    • DF or FD: Draw and fill.
    • + *
    • CNZ: Clipping mode (using the even-odd rule to determine which regions lie inside the clipping path).
    • + *
    • CEO: Clipping mode (using the nonzero winding number rule to determine which regions lie inside the clipping path).
    • + *
    + * @param array $circle_outLine_style Line style of inscribed circle (if draws). Array like for {@link SetLineStyle SetLineStyle}. Default value: default line style (empty array). + * @param array $circle_fill_color Fill color of inscribed circle (if draws). Format: array(red, green, blue). Default value: default color (empty array). + * @access public + * @since 2.1.000 (2008-01-08) + */ + public function RegularPolygon($x0, $y0, $r, $ns, $angle=0, $draw_circle=false, $style='', $line_style=array(), $fill_color=array(), $circle_style='', $circle_outLine_style=array(), $circle_fill_color=array()) { + if (3 > $ns) { + $ns = 3; + } + if ($draw_circle) { + $this->Circle($x0, $y0, $r, 0, 360, $circle_style, $circle_outLine_style, $circle_fill_color); + } + $p = array(); + for ($i = 0; $i < $ns; ++$i) { + $a = $angle + ($i * 360 / $ns); + $a_rad = deg2rad((float) $a); + $p[] = $x0 + ($r * sin($a_rad)); + $p[] = $y0 + ($r * cos($a_rad)); + } + $this->Polygon($p, $style, $line_style, $fill_color); + } + + /** + * Draws a star polygon + * @param float $x0 Abscissa of center point. + * @param float $y0 Ordinate of center point. + * @param float $r Radius of inscribed circle. + * @param integer $nv Number of vertices. + * @param integer $ng Number of gap (if ($ng % $nv = 1) then is a regular polygon). + * @param float $angle: Angle oriented (anti-clockwise). Default value: 0. + * @param boolean $draw_circle: Draw inscribed circle or not. Default value is false. + * @param string $style Style of rendering. Possible values are: + *
      + *
    • D or empty string: Draw (default).
    • + *
    • F: Fill.
    • + *
    • DF or FD: Draw and fill.
    • + *
    • CNZ: Clipping mode (using the even-odd rule to determine which regions lie inside the clipping path).
    • + *
    • CEO: Clipping mode (using the nonzero winding number rule to determine which regions lie inside the clipping path).
    • + *
    + * @param array $line_style Line style of polygon sides. Array with keys among the following: + *
      + *
    • all: Line style of all sides. Array like for + * {@link SetLineStyle SetLineStyle}.
    • + *
    • 0 to (n - 1): Line style of each side. Array like for {@link SetLineStyle SetLineStyle}.
    • + *
    + * If a key is not present or is null, not draws the side. Default value is default line style (empty array). + * @param array $fill_color Fill color. Format: array(red, green, blue). Default value: default color (empty array). + * @param string $circle_style Style of rendering of inscribed circle (if draws). Possible values are: + *
      + *
    • D or empty string: Draw (default).
    • + *
    • F: Fill.
    • + *
    • DF or FD: Draw and fill.
    • + *
    • CNZ: Clipping mode (using the even-odd rule to determine which regions lie inside the clipping path).
    • + *
    • CEO: Clipping mode (using the nonzero winding number rule to determine which regions lie inside the clipping path).
    • + *
    + * @param array $circle_outLine_style Line style of inscribed circle (if draws). Array like for {@link SetLineStyle SetLineStyle}. Default value: default line style (empty array). + * @param array $circle_fill_color Fill color of inscribed circle (if draws). Format: array(red, green, blue). Default value: default color (empty array). + * @access public + * @since 2.1.000 (2008-01-08) + */ + public function StarPolygon($x0, $y0, $r, $nv, $ng, $angle=0, $draw_circle=false, $style='', $line_style=array(), $fill_color=array(), $circle_style='', $circle_outLine_style=array(), $circle_fill_color=array()) { + if (2 > $nv) { + $nv = 2; + } + if ($draw_circle) { + $this->Circle($x0, $y0, $r, 0, 360, $circle_style, $circle_outLine_style, $circle_fill_color); + } + $p2 = array(); + $visited = array(); + for ($i = 0; $i < $nv; ++$i) { + $a = $angle + ($i * 360 / $nv); + $a_rad = deg2rad((float) $a); + $p2[] = $x0 + ($r * sin($a_rad)); + $p2[] = $y0 + ($r * cos($a_rad)); + $visited[] = false; + } + $p = array(); + $i = 0; + do { + $p[] = $p2[$i * 2]; + $p[] = $p2[($i * 2) + 1]; + $visited[$i] = true; + $i += $ng; + $i %= $nv; + } while (!$visited[$i]); + $this->Polygon($p, $style, $line_style, $fill_color); + } + + /** + * Draws a rounded rectangle. + * @param float $x Abscissa of upper-left corner. + * @param float $y Ordinate of upper-left corner. + * @param float $w Width. + * @param float $h Height. + * @param float $r Radius of the rounded corners. + * @param string $round_corner Draws rounded corner or not. String with a 0 (not rounded i-corner) or 1 (rounded i-corner) in i-position. Positions are, in order and begin to 0: top left, top right, bottom right and bottom left. Default value: all rounded corner ("1111"). + * @param string $style Style of rendering. Possible values are: + *
      + *
    • D or empty string: Draw (default).
    • + *
    • F: Fill.
    • + *
    • DF or FD: Draw and fill.
    • + *
    • CNZ: Clipping mode (using the even-odd rule to determine which regions lie inside the clipping path).
    • + *
    • CEO: Clipping mode (using the nonzero winding number rule to determine which regions lie inside the clipping path).
    • + *
    + * @param array $border_style Border style of rectangle. Array like for {@link SetLineStyle SetLineStyle}. Default value: default line style (empty array). + * @param array $fill_color Fill color. Format: array(GREY) or array(R,G,B) or array(C,M,Y,K). Default value: default color (empty array). + * @access public + * @since 2.1.000 (2008-01-08) + */ + public function RoundedRect($x, $y, $w, $h, $r, $round_corner='1111', $style='', $border_style=array(), $fill_color=array()) { + if ('0000' == $round_corner) { // Not rounded + $this->Rect($x, $y, $w, $h, $style, $border_style, $fill_color); + } else { // Rounded + if (!(false === strpos($style, 'F')) AND isset($fill_color)) { + $this->SetFillColorArray($fill_color); + } + switch ($style) { + case 'F': { + $border_style = array(); + $op = 'f'; + break; + } + case 'FD': + case 'DF': { + $op = 'B'; + break; + } + case 'CNZ': { + $op = 'W n'; + break; + } + case 'CEO': { + $op = 'W* n'; + break; + } + default: { + $op = 'S'; + break; + } + } + if ($border_style) { + $this->SetLineStyle($border_style); + } + $MyArc = 4 / 3 * (sqrt(2) - 1); + $this->_outPoint($x + $r, $y); + $xc = $x + $w - $r; + $yc = $y + $r; + $this->_outLine($xc, $y); + if ($round_corner[0]) { + $this->_outCurve($xc + ($r * $MyArc), $yc - $r, $xc + $r, $yc - ($r * $MyArc), $xc + $r, $yc); + } else { + $this->_outLine($x + $w, $y); + } + $xc = $x + $w - $r; + $yc = $y + $h - $r; + $this->_outLine($x + $w, $yc); + if ($round_corner[1]) { + $this->_outCurve($xc + $r, $yc + ($r * $MyArc), $xc + ($r * $MyArc), $yc + $r, $xc, $yc + $r); + } else { + $this->_outLine($x + $w, $y + $h); + } + $xc = $x + $r; + $yc = $y + $h - $r; + $this->_outLine($xc, $y + $h); + if ($round_corner[2]) { + $this->_outCurve($xc - ($r * $MyArc), $yc + $r, $xc - $r, $yc + ($r * $MyArc), $xc - $r, $yc); + } else { + $this->_outLine($x, $y + $h); + } + $xc = $x + $r; + $yc = $y + $r; + $this->_outLine($x, $yc); + if ($round_corner[3]) { + $this->_outCurve($xc - $r, $yc - ($r * $MyArc), $xc - ($r * $MyArc), $yc - $r, $xc, $yc - $r); + } else { + $this->_outLine($x, $y); + $this->_outLine($x + $r, $y); + } + $this->_out($op); + } + } + + // END GRAPHIC FUNCTIONS SECTION ----------------------- + + // BIDIRECTIONAL TEXT SECTION -------------------------- + /** + * Reverse the RLT substrings using the Bidirectional Algorithm (http://unicode.org/reports/tr9/). + * @param string $str string to manipulate. + * @param bool $forcertl if 'R' forces RTL, if 'L' forces LTR + * @return string + * @access protected + * @author Nicola Asuni + * @since 2.1.000 (2008-01-08) + */ + protected function utf8StrRev($str, $setbom=false, $forcertl=false) { + return $this->arrUTF8ToUTF16BE($this->utf8Bidi($this->UTF8StringToArray($str), $str, $forcertl), $setbom); + } + + /** + * Reverse the RLT substrings using the Bidirectional Algorithm (http://unicode.org/reports/tr9/). + * @param array $ta array of characters composing the string. + * @param string $str string to process + * @param bool $forcertl if 'R' forces RTL, if 'L' forces LTR + * @return string + * @author Nicola Asuni + * @access protected + * @since 2.4.000 (2008-03-06) + */ + protected function utf8Bidi($ta, $str='', $forcertl=false) { + global $unicode, $unicode_mirror, $unicode_arlet, $laa_array, $diacritics; + // paragraph embedding level + $pel = 0; + // max level + $maxlevel = 0; + if ($this->empty_string($str)) { + // create string from array + $str = $this->UTF8ArrSubString($ta); + } + // check if string contains arabic text + if (preg_match(K_RE_PATTERN_ARABIC, $str)) { + $arabic = true; + } else { + $arabic = false; + } + // check if string contains RTL text + if (!($forcertl OR $arabic OR preg_match(K_RE_PATTERN_RTL, $str))) { + return $ta; + } + + // get number of chars + $numchars = count($ta); + + if ($forcertl == 'R') { + $pel = 1; + } elseif ($forcertl == 'L') { + $pel = 0; + } else { + // P2. In each paragraph, find the first character of type L, AL, or R. + // P3. If a character is found in P2 and it is of type AL or R, then set the paragraph embedding level to one; otherwise, set it to zero. + for ($i=0; $i < $numchars; ++$i) { + $type = $unicode[$ta[$i]]; + if ($type == 'L') { + $pel = 0; + break; + } elseif (($type == 'AL') OR ($type == 'R')) { + $pel = 1; + break; + } + } + } + + // Current Embedding Level + $cel = $pel; + // directional override status + $dos = 'N'; + $remember = array(); + // start-of-level-run + $sor = $pel % 2 ? 'R' : 'L'; + $eor = $sor; + + // Array of characters data + $chardata = Array(); + + // X1. Begin by setting the current embedding level to the paragraph embedding level. Set the directional override status to neutral. Process each character iteratively, applying rules X2 through X9. Only embedding levels from 0 to 61 are valid in this phase. + // In the resolution of levels in rules I1 and I2, the maximum embedding level of 62 can be reached. + for ($i=0; $i < $numchars; ++$i) { + if ($ta[$i] == K_RLE) { + // X2. With each RLE, compute the least greater odd embedding level. + // a. If this new level would be valid, then this embedding code is valid. Remember (push) the current embedding level and override status. Reset the current level to this new level, and reset the override status to neutral. + // b. If the new level would not be valid, then this code is invalid. Do not change the current level or override status. + $next_level = $cel + ($cel % 2) + 1; + if ($next_level < 62) { + $remember[] = array('num' => K_RLE, 'cel' => $cel, 'dos' => $dos); + $cel = $next_level; + $dos = 'N'; + $sor = $eor; + $eor = $cel % 2 ? 'R' : 'L'; + } + } elseif ($ta[$i] == K_LRE) { + // X3. With each LRE, compute the least greater even embedding level. + // a. If this new level would be valid, then this embedding code is valid. Remember (push) the current embedding level and override status. Reset the current level to this new level, and reset the override status to neutral. + // b. If the new level would not be valid, then this code is invalid. Do not change the current level or override status. + $next_level = $cel + 2 - ($cel % 2); + if ( $next_level < 62 ) { + $remember[] = array('num' => K_LRE, 'cel' => $cel, 'dos' => $dos); + $cel = $next_level; + $dos = 'N'; + $sor = $eor; + $eor = $cel % 2 ? 'R' : 'L'; + } + } elseif ($ta[$i] == K_RLO) { + // X4. With each RLO, compute the least greater odd embedding level. + // a. If this new level would be valid, then this embedding code is valid. Remember (push) the current embedding level and override status. Reset the current level to this new level, and reset the override status to right-to-left. + // b. If the new level would not be valid, then this code is invalid. Do not change the current level or override status. + $next_level = $cel + ($cel % 2) + 1; + if ($next_level < 62) { + $remember[] = array('num' => K_RLO, 'cel' => $cel, 'dos' => $dos); + $cel = $next_level; + $dos = 'R'; + $sor = $eor; + $eor = $cel % 2 ? 'R' : 'L'; + } + } elseif ($ta[$i] == K_LRO) { + // X5. With each LRO, compute the least greater even embedding level. + // a. If this new level would be valid, then this embedding code is valid. Remember (push) the current embedding level and override status. Reset the current level to this new level, and reset the override status to left-to-right. + // b. If the new level would not be valid, then this code is invalid. Do not change the current level or override status. + $next_level = $cel + 2 - ($cel % 2); + if ( $next_level < 62 ) { + $remember[] = array('num' => K_LRO, 'cel' => $cel, 'dos' => $dos); + $cel = $next_level; + $dos = 'L'; + $sor = $eor; + $eor = $cel % 2 ? 'R' : 'L'; + } + } elseif ($ta[$i] == K_PDF) { + // X7. With each PDF, determine the matching embedding or override code. If there was a valid matching code, restore (pop) the last remembered (pushed) embedding level and directional override. + if (count($remember)) { + $last = count($remember ) - 1; + if (($remember[$last]['num'] == K_RLE) OR + ($remember[$last]['num'] == K_LRE) OR + ($remember[$last]['num'] == K_RLO) OR + ($remember[$last]['num'] == K_LRO)) { + $match = array_pop($remember); + $cel = $match['cel']; + $dos = $match['dos']; + $sor = $eor; + $eor = ($cel > $match['cel'] ? $cel : $match['cel']) % 2 ? 'R' : 'L'; + } + } + } elseif (($ta[$i] != K_RLE) AND + ($ta[$i] != K_LRE) AND + ($ta[$i] != K_RLO) AND + ($ta[$i] != K_LRO) AND + ($ta[$i] != K_PDF)) { + // X6. For all types besides RLE, LRE, RLO, LRO, and PDF: + // a. Set the level of the current character to the current embedding level. + // b. Whenever the directional override status is not neutral, reset the current character type to the directional override status. + if ($dos != 'N') { + $chardir = $dos; + } else { + $chardir = $unicode[$ta[$i]]; + } + // stores string characters and other information + $chardata[] = array('char' => $ta[$i], 'level' => $cel, 'type' => $chardir, 'sor' => $sor, 'eor' => $eor); + } + } // end for each char + + // X8. All explicit directional embeddings and overrides are completely terminated at the end of each paragraph. Paragraph separators are not included in the embedding. + // X9. Remove all RLE, LRE, RLO, LRO, PDF, and BN codes. + // X10. The remaining rules are applied to each run of characters at the same level. For each run, determine the start-of-level-run (sor) and end-of-level-run (eor) type, either L or R. This depends on the higher of the two levels on either side of the boundary (at the start or end of the paragraph, the level of the 'other' run is the base embedding level). If the higher level is odd, the type is R; otherwise, it is L. + + // 3.3.3 Resolving Weak Types + // Weak types are now resolved one level run at a time. At level run boundaries where the type of the character on the other side of the boundary is required, the type assigned to sor or eor is used. + // Nonspacing marks are now resolved based on the previous characters. + $numchars = count($chardata); + + // W1. Examine each nonspacing mark (NSM) in the level run, and change the type of the NSM to the type of the previous character. If the NSM is at the start of the level run, it will get the type of sor. + $prevlevel = -1; // track level changes + $levcount = 0; // counts consecutive chars at the same level + for ($i=0; $i < $numchars; ++$i) { + if ($chardata[$i]['type'] == 'NSM') { + if ($levcount) { + $chardata[$i]['type'] = $chardata[$i]['sor']; + } elseif ($i > 0) { + $chardata[$i]['type'] = $chardata[($i-1)]['type']; + } + } + if ($chardata[$i]['level'] != $prevlevel) { + $levcount = 0; + } else { + ++$levcount; + } + $prevlevel = $chardata[$i]['level']; + } + + // W2. Search backward from each instance of a European number until the first strong type (R, L, AL, or sor) is found. If an AL is found, change the type of the European number to Arabic number. + $prevlevel = -1; + $levcount = 0; + for ($i=0; $i < $numchars; ++$i) { + if ($chardata[$i]['char'] == 'EN') { + for ($j=$levcount; $j >= 0; $j--) { + if ($chardata[$j]['type'] == 'AL') { + $chardata[$i]['type'] = 'AN'; + } elseif (($chardata[$j]['type'] == 'L') OR ($chardata[$j]['type'] == 'R')) { + break; + } + } + } + if ($chardata[$i]['level'] != $prevlevel) { + $levcount = 0; + } else { + ++$levcount; + } + $prevlevel = $chardata[$i]['level']; + } + + // W3. Change all ALs to R. + for ($i=0; $i < $numchars; ++$i) { + if ($chardata[$i]['type'] == 'AL') { + $chardata[$i]['type'] = 'R'; + } + } + + // W4. A single European separator between two European numbers changes to a European number. A single common separator between two numbers of the same type changes to that type. + $prevlevel = -1; + $levcount = 0; + for ($i=0; $i < $numchars; ++$i) { + if (($levcount > 0) AND (($i+1) < $numchars) AND ($chardata[($i+1)]['level'] == $prevlevel)) { + if (($chardata[$i]['type'] == 'ES') AND ($chardata[($i-1)]['type'] == 'EN') AND ($chardata[($i+1)]['type'] == 'EN')) { + $chardata[$i]['type'] = 'EN'; + } elseif (($chardata[$i]['type'] == 'CS') AND ($chardata[($i-1)]['type'] == 'EN') AND ($chardata[($i+1)]['type'] == 'EN')) { + $chardata[$i]['type'] = 'EN'; + } elseif (($chardata[$i]['type'] == 'CS') AND ($chardata[($i-1)]['type'] == 'AN') AND ($chardata[($i+1)]['type'] == 'AN')) { + $chardata[$i]['type'] = 'AN'; + } + } + if ($chardata[$i]['level'] != $prevlevel) { + $levcount = 0; + } else { + ++$levcount; + } + $prevlevel = $chardata[$i]['level']; + } + + // W5. A sequence of European terminators adjacent to European numbers changes to all European numbers. + $prevlevel = -1; + $levcount = 0; + for ($i=0; $i < $numchars; ++$i) { + if ($chardata[$i]['type'] == 'ET') { + if (($levcount > 0) AND ($chardata[($i-1)]['type'] == 'EN')) { + $chardata[$i]['type'] = 'EN'; + } else { + $j = $i+1; + while (($j < $numchars) AND ($chardata[$j]['level'] == $prevlevel)) { + if ($chardata[$j]['type'] == 'EN') { + $chardata[$i]['type'] = 'EN'; + break; + } elseif ($chardata[$j]['type'] != 'ET') { + break; + } + ++$j; + } + } + } + if ($chardata[$i]['level'] != $prevlevel) { + $levcount = 0; + } else { + ++$levcount; + } + $prevlevel = $chardata[$i]['level']; + } + + // W6. Otherwise, separators and terminators change to Other Neutral. + $prevlevel = -1; + $levcount = 0; + for ($i=0; $i < $numchars; ++$i) { + if (($chardata[$i]['type'] == 'ET') OR ($chardata[$i]['type'] == 'ES') OR ($chardata[$i]['type'] == 'CS')) { + $chardata[$i]['type'] = 'ON'; + } + if ($chardata[$i]['level'] != $prevlevel) { + $levcount = 0; + } else { + ++$levcount; + } + $prevlevel = $chardata[$i]['level']; + } + + //W7. Search backward from each instance of a European number until the first strong type (R, L, or sor) is found. If an L is found, then change the type of the European number to L. + $prevlevel = -1; + $levcount = 0; + for ($i=0; $i < $numchars; ++$i) { + if ($chardata[$i]['char'] == 'EN') { + for ($j=$levcount; $j >= 0; $j--) { + if ($chardata[$j]['type'] == 'L') { + $chardata[$i]['type'] = 'L'; + } elseif ($chardata[$j]['type'] == 'R') { + break; + } + } + } + if ($chardata[$i]['level'] != $prevlevel) { + $levcount = 0; + } else { + ++$levcount; + } + $prevlevel = $chardata[$i]['level']; + } + + // N1. A sequence of neutrals takes the direction of the surrounding strong text if the text on both sides has the same direction. European and Arabic numbers act as if they were R in terms of their influence on neutrals. Start-of-level-run (sor) and end-of-level-run (eor) are used at level run boundaries. + $prevlevel = -1; + $levcount = 0; + for ($i=0; $i < $numchars; ++$i) { + if (($levcount > 0) AND (($i+1) < $numchars) AND ($chardata[($i+1)]['level'] == $prevlevel)) { + if (($chardata[$i]['type'] == 'N') AND ($chardata[($i-1)]['type'] == 'L') AND ($chardata[($i+1)]['type'] == 'L')) { + $chardata[$i]['type'] = 'L'; + } elseif (($chardata[$i]['type'] == 'N') AND + (($chardata[($i-1)]['type'] == 'R') OR ($chardata[($i-1)]['type'] == 'EN') OR ($chardata[($i-1)]['type'] == 'AN')) AND + (($chardata[($i+1)]['type'] == 'R') OR ($chardata[($i+1)]['type'] == 'EN') OR ($chardata[($i+1)]['type'] == 'AN'))) { + $chardata[$i]['type'] = 'R'; + } elseif ($chardata[$i]['type'] == 'N') { + // N2. Any remaining neutrals take the embedding direction + $chardata[$i]['type'] = $chardata[$i]['sor']; + } + } elseif (($levcount == 0) AND (($i+1) < $numchars) AND ($chardata[($i+1)]['level'] == $prevlevel)) { + // first char + if (($chardata[$i]['type'] == 'N') AND ($chardata[$i]['sor'] == 'L') AND ($chardata[($i+1)]['type'] == 'L')) { + $chardata[$i]['type'] = 'L'; + } elseif (($chardata[$i]['type'] == 'N') AND + (($chardata[$i]['sor'] == 'R') OR ($chardata[$i]['sor'] == 'EN') OR ($chardata[$i]['sor'] == 'AN')) AND + (($chardata[($i+1)]['type'] == 'R') OR ($chardata[($i+1)]['type'] == 'EN') OR ($chardata[($i+1)]['type'] == 'AN'))) { + $chardata[$i]['type'] = 'R'; + } elseif ($chardata[$i]['type'] == 'N') { + // N2. Any remaining neutrals take the embedding direction + $chardata[$i]['type'] = $chardata[$i]['sor']; + } + } elseif (($levcount > 0) AND ((($i+1) == $numchars) OR (($i+1) < $numchars) AND ($chardata[($i+1)]['level'] != $prevlevel))) { + //last char + if (($chardata[$i]['type'] == 'N') AND ($chardata[($i-1)]['type'] == 'L') AND ($chardata[$i]['eor'] == 'L')) { + $chardata[$i]['type'] = 'L'; + } elseif (($chardata[$i]['type'] == 'N') AND + (($chardata[($i-1)]['type'] == 'R') OR ($chardata[($i-1)]['type'] == 'EN') OR ($chardata[($i-1)]['type'] == 'AN')) AND + (($chardata[$i]['eor'] == 'R') OR ($chardata[$i]['eor'] == 'EN') OR ($chardata[$i]['eor'] == 'AN'))) { + $chardata[$i]['type'] = 'R'; + } elseif ($chardata[$i]['type'] == 'N') { + // N2. Any remaining neutrals take the embedding direction + $chardata[$i]['type'] = $chardata[$i]['sor']; + } + } elseif ($chardata[$i]['type'] == 'N') { + // N2. Any remaining neutrals take the embedding direction + $chardata[$i]['type'] = $chardata[$i]['sor']; + } + if ($chardata[$i]['level'] != $prevlevel) { + $levcount = 0; + } else { + ++$levcount; + } + $prevlevel = $chardata[$i]['level']; + } + + // I1. For all characters with an even (left-to-right) embedding direction, those of type R go up one level and those of type AN or EN go up two levels. + // I2. For all characters with an odd (right-to-left) embedding direction, those of type L, EN or AN go up one level. + for ($i=0; $i < $numchars; ++$i) { + $odd = $chardata[$i]['level'] % 2; + if ($odd) { + if (($chardata[$i]['type'] == 'L') OR ($chardata[$i]['type'] == 'AN') OR ($chardata[$i]['type'] == 'EN')) { + $chardata[$i]['level'] += 1; + } + } else { + if ($chardata[$i]['type'] == 'R') { + $chardata[$i]['level'] += 1; + } elseif (($chardata[$i]['type'] == 'AN') OR ($chardata[$i]['type'] == 'EN')) { + $chardata[$i]['level'] += 2; + } + } + $maxlevel = max($chardata[$i]['level'],$maxlevel); + } + + // L1. On each line, reset the embedding level of the following characters to the paragraph embedding level: + // 1. Segment separators, + // 2. Paragraph separators, + // 3. Any sequence of whitespace characters preceding a segment separator or paragraph separator, and + // 4. Any sequence of white space characters at the end of the line. + for ($i=0; $i < $numchars; ++$i) { + if (($chardata[$i]['type'] == 'B') OR ($chardata[$i]['type'] == 'S')) { + $chardata[$i]['level'] = $pel; + } elseif ($chardata[$i]['type'] == 'WS') { + $j = $i+1; + while ($j < $numchars) { + if ((($chardata[$j]['type'] == 'B') OR ($chardata[$j]['type'] == 'S')) OR + (($j == ($numchars-1)) AND ($chardata[$j]['type'] == 'WS'))) { + $chardata[$i]['level'] = $pel; + break; + } elseif ($chardata[$j]['type'] != 'WS') { + break; + } + ++$j; + } + } + } + + // Arabic Shaping + // Cursively connected scripts, such as Arabic or Syriac, require the selection of positional character shapes that depend on adjacent characters. Shaping is logically applied after the Bidirectional Algorithm is used and is limited to characters within the same directional run. + if ($arabic) { + $endedletter = array(1569,1570,1571,1572,1573,1575,1577,1583,1584,1585,1586,1608,1688); + $alfletter = array(1570,1571,1573,1575); + $chardata2 = $chardata; + $laaletter = false; + $charAL = array(); + $x = 0; + for ($i=0; $i < $numchars; ++$i) { + if (($unicode[$chardata[$i]['char']] == 'AL') OR ($chardata[$i]['char'] == 32) OR ($chardata[$i]['char'] == 8204)) { + $charAL[$x] = $chardata[$i]; + $charAL[$x]['i'] = $i; + $chardata[$i]['x'] = $x; + ++$x; + } + } + $numAL = $x; + for ($i=0; $i < $numchars; ++$i) { + $thischar = $chardata[$i]; + if ($i > 0) { + $prevchar = $chardata[($i-1)]; + } else { + $prevchar = false; + } + if (($i+1) < $numchars) { + $nextchar = $chardata[($i+1)]; + } else { + $nextchar = false; + } + if ($unicode[$thischar['char']] == 'AL') { + $x = $thischar['x']; + if ($x > 0) { + $prevchar = $charAL[($x-1)]; + } else { + $prevchar = false; + } + if (($x+1) < $numAL) { + $nextchar = $charAL[($x+1)]; + } else { + $nextchar = false; + } + // if laa letter + if (($prevchar !== false) AND ($prevchar['char'] == 1604) AND (in_array($thischar['char'], $alfletter))) { + $arabicarr = $laa_array; + $laaletter = true; + if ($x > 1) { + $prevchar = $charAL[($x-2)]; + } else { + $prevchar = false; + } + } else { + $arabicarr = $unicode_arlet; + $laaletter = false; + } + if (($prevchar !== false) AND ($nextchar !== false) AND + (($unicode[$prevchar['char']] == 'AL') OR ($unicode[$prevchar['char']] == 'NSM')) AND + (($unicode[$nextchar['char']] == 'AL') OR ($unicode[$nextchar['char']] == 'NSM')) AND + ($prevchar['type'] == $thischar['type']) AND + ($nextchar['type'] == $thischar['type']) AND + ($nextchar['char'] != 1567)) { + if (in_array($prevchar['char'], $endedletter)) { + if (isset($arabicarr[$thischar['char']][2])) { + // initial + $chardata2[$i]['char'] = $arabicarr[$thischar['char']][2]; + } + } else { + if (isset($arabicarr[$thischar['char']][3])) { + // medial + $chardata2[$i]['char'] = $arabicarr[$thischar['char']][3]; + } + } + } elseif (($nextchar !== false) AND + (($unicode[$nextchar['char']] == 'AL') OR ($unicode[$nextchar['char']] == 'NSM')) AND + ($nextchar['type'] == $thischar['type']) AND + ($nextchar['char'] != 1567)) { + if (isset($arabicarr[$chardata[$i]['char']][2])) { + // initial + $chardata2[$i]['char'] = $arabicarr[$thischar['char']][2]; + } + } elseif ((($prevchar !== false) AND + (($unicode[$prevchar['char']] == 'AL') OR ($unicode[$prevchar['char']] == 'NSM')) AND + ($prevchar['type'] == $thischar['type'])) OR + (($nextchar !== false) AND ($nextchar['char'] == 1567))) { + // final + if (($i > 1) AND ($thischar['char'] == 1607) AND + ($chardata[$i-1]['char'] == 1604) AND + ($chardata[$i-2]['char'] == 1604)) { + //Allah Word + // mark characters to delete with false + $chardata2[$i-2]['char'] = false; + $chardata2[$i-1]['char'] = false; + $chardata2[$i]['char'] = 65010; + } else { + if (($prevchar !== false) AND in_array($prevchar['char'], $endedletter)) { + if (isset($arabicarr[$thischar['char']][0])) { + // isolated + $chardata2[$i]['char'] = $arabicarr[$thischar['char']][0]; + } + } else { + if (isset($arabicarr[$thischar['char']][1])) { + // final + $chardata2[$i]['char'] = $arabicarr[$thischar['char']][1]; + } + } + } + } elseif (isset($arabicarr[$thischar['char']][0])) { + // isolated + $chardata2[$i]['char'] = $arabicarr[$thischar['char']][0]; + } + // if laa letter + if ($laaletter) { + // mark characters to delete with false + $chardata2[($charAL[($x-1)]['i'])]['char'] = false; + } + } // end if AL (Arabic Letter) + } // end for each char + /* + * Combining characters that can occur with Shadda (0651 HEX, 1617 DEC) are placed in UE586-UE594. + * Putting the combining mark and shadda in the same glyph allows us to avoid the two marks overlapping each other in an illegible manner. + */ + $cw = &$this->CurrentFont['cw']; + for ($i = 0; $i < ($numchars-1); ++$i) { + if (($chardata2[$i]['char'] == 1617) AND (isset($diacritics[($chardata2[$i+1]['char'])]))) { + // check if the subtitution font is defined on current font + if (isset($cw[($diacritics[($chardata2[$i+1]['char'])])])) { + $chardata2[$i]['char'] = false; + $chardata2[$i+1]['char'] = $diacritics[($chardata2[$i+1]['char'])]; + } + } + } + // remove marked characters + foreach ($chardata2 as $key => $value) { + if ($value['char'] === false) { + unset($chardata2[$key]); + } + } + $chardata = array_values($chardata2); + $numchars = count($chardata); + unset($chardata2); + unset($arabicarr); + unset($laaletter); + unset($charAL); + } + + // L2. From the highest level found in the text to the lowest odd level on each line, including intermediate levels not actually present in the text, reverse any contiguous sequence of characters that are at that level or higher. + for ($j=$maxlevel; $j > 0; $j--) { + $ordarray = Array(); + $revarr = Array(); + $onlevel = false; + for ($i=0; $i < $numchars; ++$i) { + if ($chardata[$i]['level'] >= $j) { + $onlevel = true; + if (isset($unicode_mirror[$chardata[$i]['char']])) { + // L4. A character is depicted by a mirrored glyph if and only if (a) the resolved directionality of that character is R, and (b) the Bidi_Mirrored property value of that character is true. + $chardata[$i]['char'] = $unicode_mirror[$chardata[$i]['char']]; + } + $revarr[] = $chardata[$i]; + } else { + if ($onlevel) { + $revarr = array_reverse($revarr); + $ordarray = array_merge($ordarray, $revarr); + $revarr = Array(); + $onlevel = false; + } + $ordarray[] = $chardata[$i]; + } + } + if ($onlevel) { + $revarr = array_reverse($revarr); + $ordarray = array_merge($ordarray, $revarr); + } + $chardata = $ordarray; + } + + $ordarray = array(); + for ($i=0; $i < $numchars; ++$i) { + $ordarray[] = $chardata[$i]['char']; + } + + return $ordarray; + } + + // END OF BIDIRECTIONAL TEXT SECTION ------------------- + + /* + * Adds a bookmark. + * @param string $txt bookmark description. + * @param int $level bookmark level (minimum value is 0). + * @param float $y Ordinate of the boorkmark position (default = -1 = current position). + * @param int $page target page number (leave empty for current page). + * @access public + * @author Olivier Plathey, Nicola Asuni + * @since 2.1.002 (2008-02-12) + */ + public function Bookmark($txt, $level=0, $y=-1, $page='') { + if ($level < 0) { + $level = 0; + } + if (isset($this->outlines[0])) { + $lastoutline = end($this->outlines); + $maxlevel = $lastoutline['l'] + 1; + } else { + $maxlevel = 0; + } + if ($level > $maxlevel) { + $level = $maxlevel; + } + if ($y == -1) { + $y = $this->GetY(); + } + if (empty($page)) { + $page = $this->PageNo(); + } + $this->outlines[] = array('t' => $txt, 'l' => $level, 'y' => $y, 'p' => $page); + } + + /* + * Create a bookmark PDF string. + * @access protected + * @author Olivier Plathey, Nicola Asuni + * @since 2.1.002 (2008-02-12) + */ + protected function _putbookmarks() { + $nb = count($this->outlines); + if ($nb == 0) { + return; + } + $lru = array(); + $level = 0; + foreach ($this->outlines as $i => $o) { + if ($o['l'] > 0) { + $parent = $lru[($o['l'] - 1)]; + //Set parent and last pointers + $this->outlines[$i]['parent'] = $parent; + $this->outlines[$parent]['last'] = $i; + if ($o['l'] > $level) { + //Level increasing: set first pointer + $this->outlines[$parent]['first'] = $i; + } + } else { + $this->outlines[$i]['parent'] = $nb; + } + if (($o['l'] <= $level) AND ($i > 0)) { + //Set prev and next pointers + $prev = $lru[$o['l']]; + $this->outlines[$prev]['next'] = $i; + $this->outlines[$i]['prev'] = $prev; + } + $lru[$o['l']] = $i; + $level = $o['l']; + } + //Outline items + $n = $this->n + 1; + foreach ($this->outlines as $i => $o) { + $this->_newobj(); + $this->_out('<_textstring($o['t'])); + $this->_out('/Parent '.($n + $o['parent']).' 0 R'); + if (isset($o['prev'])) + $this->_out('/Prev '.($n + $o['prev']).' 0 R'); + if (isset($o['next'])) + $this->_out('/Next '.($n + $o['next']).' 0 R'); + if (isset($o['first'])) + $this->_out('/First '.($n + $o['first']).' 0 R'); + if (isset($o['last'])) + $this->_out('/Last '.($n + $o['last']).' 0 R'); + $this->_out(sprintf('/Dest [%d 0 R /XYZ 0 %.2F null]', (1 + (2 * $o['p'])), ($this->pagedim[$o['p']]['h'] - ($o['y'] * $this->k)))); + $this->_out('/Count 0>>'); + $this->_out('endobj'); + } + //Outline root + $this->_newobj(); + $this->OutlineRoot = $this->n; + $this->_out('<_out('/Last '.($n + $lru[0]).' 0 R>>'); + $this->_out('endobj'); + } + + + // --- JAVASCRIPT - FORMS ------------------------------ + + /* + * Adds a javascript + * @access public + * @author Johannes Güntert, Nicola Asuni + * @since 2.1.002 (2008-02-12) + */ + public function IncludeJS($script) { + $this->javascript .= $script; + } + + /* + * Create a javascript PDF string. + * @access protected + * @author Johannes Güntert, Nicola Asuni + * @since 2.1.002 (2008-02-12) + */ + protected function _putjavascript() { + if (empty($this->javascript)) { + return; + } + // the following two lines are uded to avoid form fields duplication after saving + $js1 = sprintf("ftcpdfdocsaved=this.addField('%s','%s',%d,[%.2F,%.2F,%.2F,%.2F]);", 'tcpdfdocsaved', 'text', 0, 0, 1, 0, 1); + $js2 = "getField('tcpdfdocsaved').value = 'saved';"; + $this->_newobj(); + $this->n_js = $this->n; + $this->_out('<<'); + $this->_out('/Names [(EmbeddedJS) '.($this->n + 1).' 0 R ]'); + $this->_out('>>'); + $this->_out('endobj'); + $this->_newobj(); + $this->_out('<<'); + $this->_out('/S /JavaScript'); + $this->_out('/JS '.$this->_textstring($js1."\n".$this->javascript."\n".$js2)); + $this->_out('>>'); + $this->_out('endobj'); + } + + /* + * Convert color to javascript color. + * @param string $color color name or #RRGGBB + * @access protected + * @author Denis Van Nuffelen, Nicola Asuni + * @since 2.1.002 (2008-02-12) + */ + protected function _JScolor($color) { + static $aColors = array('transparent', 'black', 'white', 'red', 'green', 'blue', 'cyan', 'magenta', 'yellow', 'dkGray', 'gray', 'ltGray'); + if (substr($color,0,1) == '#') { + return sprintf("['RGB',%.3F,%.3F,%.3F]", hexdec(substr($color,1,2))/255, hexdec(substr($color,3,2))/255, hexdec(substr($color,5,2))/255); + } + if (!in_array($color,$aColors)) { + $this->Error('Invalid color: '.$color); + } + return 'color.'.$color; + } + + /* + * Adds a javascript form field. + * @param string $type field type + * @param string $name field name + * @param int $x horizontal position + * @param int $y vertical position + * @param int $w width + * @param int $h height + * @param array $prop array of properties. Possible values are (http://www.adobe.com/devnet/acrobat/pdfs/js_developer_guide.pdf):
    • rect: Position and size of field on page.
    • borderStyle: Rectangle border appearance.
    • strokeColor: Color of bounding rectangle.
    • lineWidth: Width of the edge of the surrounding rectangle.
    • rotation: Rotation of field in 90-degree increments.
    • fillColor: Background color of field (gray, transparent, RGB, or CMYK).
    • userName: Short description of field that appears on mouse-over.
    • readonly: Whether the user may change the field contents.
    • doNotScroll: Whether text fields may scroll.
    • display: Whether visible or hidden on screen or in print.
    • textFont: Text font.
    • textColor: Text color.
    • textSize: Text size.
    • richText: Rich text.
    • richValue: Text.
    • comb: Text comb format.
    • multiline: Text multiline.
    • charLimit: Text limit to number of characters.
    • fileSelect: Text file selection format.
    • password: Text password format.
    • alignment: Text layout in text fields.
    • buttonAlignX: X alignment of icon on button face.
    • buttonAlignY: Y alignment of icon on button face.
    • buttonFitBounds: Relative scaling of an icon to fit inside a button face.
    • buttonScaleHow: Relative scaling of an icon to fit inside a button face.
    • buttonScaleWhen: Relative scaling of an icon to fit inside a button face.
    • highlight: Appearance of a button when pushed.
    • style: Glyph style for checkbox and radio buttons.
    • numItems: Number of items in a combo box or list box.
    • editable: Whether the user can type in a combo box.
    • multipleSelection: Whether multiple list box items may be selected.
    + * @access protected + * @author Denis Van Nuffelen, Nicola Asuni + * @since 2.1.002 (2008-02-12) + */ + protected function _addfield($type, $name, $x, $y, $w, $h, $prop) { + if ($this->rtl) { + $x = $x - $w; + } + // the followind avoid fields duplication after saving the document + $this->javascript .= "if(getField('tcpdfdocsaved').value != 'saved') {"; + $k = $this->k; + $this->javascript .= sprintf("f".$name."=this.addField('%s','%s',%d,[%.2F,%.2F,%.2F,%.2F]);", $name, $type, $this->PageNo()-1, $x*$k, ($this->h-$y)*$k+1, ($x+$w)*$k, ($this->h-$y-$h)*$k+1)."\n"; + $this->javascript .= 'f'.$name.'.textSize='.$this->FontSizePt.";\n"; + while (list($key, $val) = each($prop)) { + if (strcmp(substr($key, -5), 'Color') == 0) { + $val = $this->_JScolor($val); + } else { + $val = "'".$val."'"; + } + $this->javascript .= 'f'.$name.'.'.$key.'='.$val.";\n"; + } + if ($this->rtl) { + $this->x -= $w; + } else { + $this->x += $w; + } + $this->javascript .= '}'; + } + + /* + * Creates a text field + * @param string $name field name + * @param int $w width + * @param int $h height + * @param string $prop properties. The value property allows to set the initial value. The multiline property allows to define the field as multiline. Possible values are (http://www.adobe.com/devnet/acrobat/pdfs/js_developer_guide.pdf):
    • rect: Position and size of field on page.
    • borderStyle: Rectangle border appearance.
    • strokeColor: Color of bounding rectangle.
    • lineWidth: Width of the edge of the surrounding rectangle.
    • rotation: Rotation of field in 90-degree increments.
    • fillColor: Background color of field (gray, transparent, RGB, or CMYK).
    • userName: Short description of field that appears on mouse-over.
    • readonly: Whether the user may change the field contents.
    • doNotScroll: Whether text fields may scroll.
    • display: Whether visible or hidden on screen or in print.
    • textFont: Text font.
    • textColor: Text color.
    • textSize: Text size.
    • richText: Rich text.
    • richValue: Text.
    • comb: Text comb format.
    • multiline: Text multiline.
    • charLimit: Text limit to number of characters.
    • fileSelect: Text file selection format.
    • password: Text password format.
    • alignment: Text layout in text fields.
    • buttonAlignX: X alignment of icon on button face.
    • buttonAlignY: Y alignment of icon on button face.
    • buttonFitBounds: Relative scaling of an icon to fit inside a button face.
    • buttonScaleHow: Relative scaling of an icon to fit inside a button face.
    • buttonScaleWhen: Relative scaling of an icon to fit inside a button face.
    • highlight: Appearance of a button when pushed.
    • style: Glyph style for checkbox and radio buttons.
    • numItems: Number of items in a combo box or list box.
    • editable: Whether the user can type in a combo box.
    • multipleSelection: Whether multiple list box items may be selected.
    + * @access public + * @author Denis Van Nuffelen, Nicola Asuni + * @since 2.1.002 (2008-02-12) + */ + public function TextField($name, $w, $h, $prop=array()) { + $this->_addfield('text', $name, $this->x, $this->y, $w, $h, $prop); + } + + /* + * Creates a RadioButton field + * @param string $name field name + * @param int $w width + * @param string $prop properties. Possible values are (http://www.adobe.com/devnet/acrobat/pdfs/js_developer_guide.pdf):
    • rect: Position and size of field on page.
    • borderStyle: Rectangle border appearance.
    • strokeColor: Color of bounding rectangle.
    • lineWidth: Width of the edge of the surrounding rectangle.
    • rotation: Rotation of field in 90-degree increments.
    • fillColor: Background color of field (gray, transparent, RGB, or CMYK).
    • userName: Short description of field that appears on mouse-over.
    • readonly: Whether the user may change the field contents.
    • doNotScroll: Whether text fields may scroll.
    • display: Whether visible or hidden on screen or in print.
    • textFont: Text font.
    • textColor: Text color.
    • textSize: Text size.
    • richText: Rich text.
    • richValue: Text.
    • comb: Text comb format.
    • multiline: Text multiline.
    • charLimit: Text limit to number of characters.
    • fileSelect: Text file selection format.
    • password: Text password format.
    • alignment: Text layout in text fields.
    • buttonAlignX: X alignment of icon on button face.
    • buttonAlignY: Y alignment of icon on button face.
    • buttonFitBounds: Relative scaling of an icon to fit inside a button face.
    • buttonScaleHow: Relative scaling of an icon to fit inside a button face.
    • buttonScaleWhen: Relative scaling of an icon to fit inside a button face.
    • highlight: Appearance of a button when pushed.
    • style: Glyph style for checkbox and radio buttons.
    • numItems: Number of items in a combo box or list box.
    • editable: Whether the user can type in a combo box.
    • multipleSelection: Whether multiple list box items may be selected.
    + * @access public + * @author Nicola Asuni + * @since 2.2.003 (2008-03-03) + */ + public function RadioButton($name, $w, $prop=array()) { + if (!isset($prop['strokeColor'])) { + $prop['strokeColor']='black'; + } + $this->_addfield('radiobutton', $name, $this->x, $this->y, $w, $w, $prop); + } + + /* + * Creates a List-box field + * @param string $name field name + * @param int $w width + * @param int $h height + * @param array $values array containing the list of values. + * @param string $prop properties. Possible values are (http://www.adobe.com/devnet/acrobat/pdfs/js_developer_guide.pdf):
    • rect: Position and size of field on page.
    • borderStyle: Rectangle border appearance.
    • strokeColor: Color of bounding rectangle.
    • lineWidth: Width of the edge of the surrounding rectangle.
    • rotation: Rotation of field in 90-degree increments.
    • fillColor: Background color of field (gray, transparent, RGB, or CMYK).
    • userName: Short description of field that appears on mouse-over.
    • readonly: Whether the user may change the field contents.
    • doNotScroll: Whether text fields may scroll.
    • display: Whether visible or hidden on screen or in print.
    • textFont: Text font.
    • textColor: Text color.
    • textSize: Text size.
    • richText: Rich text.
    • richValue: Text.
    • comb: Text comb format.
    • multiline: Text multiline.
    • charLimit: Text limit to number of characters.
    • fileSelect: Text file selection format.
    • password: Text password format.
    • alignment: Text layout in text fields.
    • buttonAlignX: X alignment of icon on button face.
    • buttonAlignY: Y alignment of icon on button face.
    • buttonFitBounds: Relative scaling of an icon to fit inside a button face.
    • buttonScaleHow: Relative scaling of an icon to fit inside a button face.
    • buttonScaleWhen: Relative scaling of an icon to fit inside a button face.
    • highlight: Appearance of a button when pushed.
    • style: Glyph style for checkbox and radio buttons.
    • numItems: Number of items in a combo box or list box.
    • editable: Whether the user can type in a combo box.
    • multipleSelection: Whether multiple list box items may be selected.
    + * @access public + * @author Nicola Asuni + * @since 2.2.003 (2008-03-03) + */ + public function ListBox($name, $w, $h, $values, $prop=array()) { + if (!isset($prop['strokeColor'])) { + $prop['strokeColor'] = 'ltGray'; + } + $this->_addfield('listbox', $name, $this->x, $this->y, $w, $h, $prop); + $s = ''; + foreach ($values as $value) { + $s .= "'".addslashes($value)."',"; + } + $this->javascript .= 'f'.$name.'.setItems(['.substr($s, 0, -1)."]);\n"; + } + + /* + * Creates a Combo-box field + * @param string $name field name + * @param int $w width + * @param int $h height + * @param array $values array containing the list of values. + * @param string $prop properties. Possible values are (http://www.adobe.com/devnet/acrobat/pdfs/js_developer_guide.pdf):
    • rect: Position and size of field on page.
    • borderStyle: Rectangle border appearance.
    • strokeColor: Color of bounding rectangle.
    • lineWidth: Width of the edge of the surrounding rectangle.
    • rotation: Rotation of field in 90-degree increments.
    • fillColor: Background color of field (gray, transparent, RGB, or CMYK).
    • userName: Short description of field that appears on mouse-over.
    • readonly: Whether the user may change the field contents.
    • doNotScroll: Whether text fields may scroll.
    • display: Whether visible or hidden on screen or in print.
    • textFont: Text font.
    • textColor: Text color.
    • textSize: Text size.
    • richText: Rich text.
    • richValue: Text.
    • comb: Text comb format.
    • multiline: Text multiline.
    • charLimit: Text limit to number of characters.
    • fileSelect: Text file selection format.
    • password: Text password format.
    • alignment: Text layout in text fields.
    • buttonAlignX: X alignment of icon on button face.
    • buttonAlignY: Y alignment of icon on button face.
    • buttonFitBounds: Relative scaling of an icon to fit inside a button face.
    • buttonScaleHow: Relative scaling of an icon to fit inside a button face.
    • buttonScaleWhen: Relative scaling of an icon to fit inside a button face.
    • highlight: Appearance of a button when pushed.
    • style: Glyph style for checkbox and radio buttons.
    • numItems: Number of items in a combo box or list box.
    • editable: Whether the user can type in a combo box.
    • multipleSelection: Whether multiple list box items may be selected.
    + * @access public + * @author Denis Van Nuffelen, Nicola Asuni + * @since 2.1.002 (2008-02-12) + */ + public function ComboBox($name, $w, $h, $values, $prop=array()) { + $this->_addfield('combobox', $name, $this->x, $this->y, $w, $h, $prop); + $s = ''; + foreach ($values as $value) { + $s .= "'".addslashes($value)."',"; + } + $this->javascript .= 'f'.$name.'.setItems(['.substr($s, 0, -1)."]);\n"; + } + + /* + * Creates a CheckBox field + * @param string $name field name + * @param int $w width + * @param boolean $checked define the initial state (default = false). + * @param string $prop properties. Possible values are (http://www.adobe.com/devnet/acrobat/pdfs/js_developer_guide.pdf):
    • rect: Position and size of field on page.
    • borderStyle: Rectangle border appearance.
    • strokeColor: Color of bounding rectangle.
    • lineWidth: Width of the edge of the surrounding rectangle.
    • rotation: Rotation of field in 90-degree increments.
    • fillColor: Background color of field (gray, transparent, RGB, or CMYK).
    • userName: Short description of field that appears on mouse-over.
    • readonly: Whether the user may change the field contents.
    • doNotScroll: Whether text fields may scroll.
    • display: Whether visible or hidden on screen or in print.
    • textFont: Text font.
    • textColor: Text color.
    • textSize: Text size.
    • richText: Rich text.
    • richValue: Text.
    • comb: Text comb format.
    • multiline: Text multiline.
    • charLimit: Text limit to number of characters.
    • fileSelect: Text file selection format.
    • password: Text password format.
    • alignment: Text layout in text fields.
    • buttonAlignX: X alignment of icon on button face.
    • buttonAlignY: Y alignment of icon on button face.
    • buttonFitBounds: Relative scaling of an icon to fit inside a button face.
    • buttonScaleHow: Relative scaling of an icon to fit inside a button face.
    • buttonScaleWhen: Relative scaling of an icon to fit inside a button face.
    • highlight: Appearance of a button when pushed.
    • style: Glyph style for checkbox and radio buttons.
    • numItems: Number of items in a combo box or list box.
    • editable: Whether the user can type in a combo box.
    • multipleSelection: Whether multiple list box items may be selected.
    + * @access public + * @author Denis Van Nuffelen, Nicola Asuni + * @since 2.1.002 (2008-02-12) + */ + public function CheckBox($name, $w, $checked=false, $prop=array()) { + $prop['value'] = ($checked ? 'Yes' : 'Off'); + if (!isset($prop['strokeColor'])) { + $prop['strokeColor'] = 'black'; + } + $this->_addfield('checkbox', $name, $this->x, $this->y, $w, $w, $prop); + } + + /* + * Creates a button field + * @param string $name field name + * @param int $w width + * @param int $h height + * @param string $caption caption. + * @param string $action action triggered by the button (JavaScript code). + * @param string $prop properties. Possible values are (http://www.adobe.com/devnet/acrobat/pdfs/js_developer_guide.pdf):
    • rect: Position and size of field on page.
    • borderStyle: Rectangle border appearance.
    • strokeColor: Color of bounding rectangle.
    • lineWidth: Width of the edge of the surrounding rectangle.
    • rotation: Rotation of field in 90-degree increments.
    • fillColor: Background color of field (gray, transparent, RGB, or CMYK).
    • userName: Short description of field that appears on mouse-over.
    • readonly: Whether the user may change the field contents.
    • doNotScroll: Whether text fields may scroll.
    • display: Whether visible or hidden on screen or in print.
    • textFont: Text font.
    • textColor: Text color.
    • textSize: Text size.
    • richText: Rich text.
    • richValue: Text.
    • comb: Text comb format.
    • multiline: Text multiline.
    • charLimit: Text limit to number of characters.
    • fileSelect: Text file selection format.
    • password: Text password format.
    • alignment: Text layout in text fields.
    • buttonAlignX: X alignment of icon on button face.
    • buttonAlignY: Y alignment of icon on button face.
    • buttonFitBounds: Relative scaling of an icon to fit inside a button face.
    • buttonScaleHow: Relative scaling of an icon to fit inside a button face.
    • buttonScaleWhen: Relative scaling of an icon to fit inside a button face.
    • highlight: Appearance of a button when pushed.
    • style: Glyph style for checkbox and radio buttons.
    • numItems: Number of items in a combo box or list box.
    • editable: Whether the user can type in a combo box.
    • multipleSelection: Whether multiple list box items may be selected.
    + * @access public + * @author Denis Van Nuffelen, Nicola Asuni + * @since 2.1.002 (2008-02-12) + */ + public function Button($name, $w, $h, $caption, $action, $prop=array()) { + if (!isset($prop['strokeColor'])) { + $prop['strokeColor'] = 'black'; + } + if (!isset($prop['borderStyle'])) { + $prop['borderStyle'] = 'beveled'; + } + $this->_addfield('button', $name, $this->x, $this->y, $w, $h, $prop); + $this->javascript .= 'f'.$name.".buttonSetCaption('".addslashes($caption)."');\n"; + $this->javascript .= 'f'.$name.".setAction('MouseUp','".addslashes($action)."');\n"; + $this->javascript .= 'f'.$name.".highlight='push';\n"; + $this->javascript .= 'f'.$name.".print=false;\n"; + } + + // END JAVASCRIPT - FORMS ------------------------------ + + /* + * Enable Write permissions for PDF Reader. + * WARNING: This works only using the Adobe private key with the setSignature() method. + * @access protected + * @author Nicola Asuni + * @since 2.9.000 (2008-03-26) + */ + protected function _putuserrights() { + if ((!$this->sign) OR (isset($this->signature_data['cert_type']) AND ($this->signature_data['cert_type'] > 0))) { + return; + } + $this->_out('/Perms'); + $this->_out('<<'); + $this->_out('/UR3'); + $this->_out('<<'); + $this->_out('/Type/Sig'); + $this->_out('/Filter/Adobe.PPKLite'); + $this->_out('/SubFilter/adbe.pkcs7.detached'); + $this->_out('/ByteRange[0 ********** ********** **********]'); + $this->_out('/Contents<>'.str_repeat(' ', $this->signature_max_lenght)); + if ($this->ur) { + $this->_out('/Reference'); + $this->_out('['); + $this->_out('<<'); + $this->_out('/Type/SigRef'); + $this->_out('/TransformMethod/UR3'); + $this->_out('/TransformParams'); + $this->_out('<<'); + $this->_out('/Type/TransformParams'); + $this->_out('/V/2.2'); + if (!$this->empty_string($this->ur_document)) { + $this->_out('/Document['.$this->ur_document.']'); + } + if (!$this->empty_string($this->ur_annots)) { + $this->_out('/Annots['.$this->ur_annots.']'); + } + if (!$this->empty_string($this->ur_form)) { + $this->_out('/Form['.$this->ur_form.']'); + } + if (!$this->empty_string($this->ur_signature)) { + $this->_out('/Signature['.$this->ur_signature.']'); + } + $this->_out('>>'); + $this->_out('>>'); + $this->_out(']'); + } + $this->_out('/M '.$this->_datastring('D:'.date('YmdHisO'))); + $this->_out('>>'); + $this->_out('>>'); + } + + /* + * Add certification signature (DocMDP) + * @access protected + * @author Nicola Asuni + * @since 4.6.008 (2009-05-07) + */ + protected function _putcertification() { + if ((!$this->sign) OR (isset($this->signature_data['cert_type']) AND ($this->signature_data['cert_type'] <= 0))) { + return; + } + $this->_out('/Perms'); + $this->_out('<<'); + $this->_out('/DocMDP'); + $this->_out('<<'); + $this->_out('/Type/Sig'); + $this->_out('/Filter/Adobe.PPKLite'); + $this->_out('/SubFilter/adbe.pkcs7.detached'); + $this->_out('/ByteRange[0 ********** ********** **********]'); + $this->_out('/Contents<>'.str_repeat(' ', $this->signature_max_lenght)); + $this->_out('/Reference'); + $this->_out('['); + $this->_out('<<'); + $this->_out('/Type/SigRef'); + $this->_out('/TransformMethod/DocMDP'); + $this->_out('/TransformParams'); + $this->_out('<<'); + $this->_out('/Type/TransformParams'); + $this->_out('/V/1.2'); + $this->_out('/P '.$this->signature_data['cert_type'].''); + $this->_out('>>'); + $this->_out('>>'); + $this->_out(']'); + $this->_out('/M '.$this->_datastring('D:'.date('YmdHisO'))); + if (isset($this->signature_data['info']['Name']) AND !$this->empty_string($this->signature_data['info']['Name'])) { + $this->_out('/Name '.$this->_textstring($this->signature_data['info']['Name']).''); + } + if (isset($this->signature_data['info']['Location']) AND !$this->empty_string($this->signature_data['info']['Location'])) { + $this->_out('/Location '.$this->_textstring($this->signature_data['info']['Location']).''); + } + if (isset($this->signature_data['info']['Reason']) AND !$this->empty_string($this->signature_data['info']['Reason'])) { + $this->_out('/Reason '.$this->_textstring($this->signature_data['info']['Reason']).''); + } + if (isset($this->signature_data['info']['ContactInfo']) AND !$this->empty_string($this->signature_data['info']['ContactInfo'])) { + $this->_out('/ContactInfo '.$this->_textstring($this->signature_data['info']['ContactInfo']).''); + } + $this->_out('>>'); + $this->_out('>>'); + } + + /* + * Set User's Rights for PDF Reader + * WARNING: This works only using the Adobe private key with the setSignature() method!. + * Check the PDF Reference 8.7.1 Transform Methods, + * Table 8.105 Entries in the UR transform parameters dictionary + * @param boolean $enable if true enable user's rights on PDF reader + * @param string $document Names specifying additional document-wide usage rights for the document. The only defined value is "/FullSave", which permits a user to save the document along with modified form and/or annotation data. + * @param string $annots Names specifying additional annotation-related usage rights for the document. Valid names in PDF 1.5 and later are /Create/Delete/Modify/Copy/Import/Export, which permit the user to perform the named operation on annotations. + * @param string $form Names specifying additional form-field-related usage rights for the document. Valid names are: /Add/Delete/FillIn/Import/Export/SubmitStandalone/SpawnTemplate + * @param string $signature Names specifying additional signature-related usage rights for the document. The only defined value is /Modify, which permits a user to apply a digital signature to an existing signature form field or clear a signed signature form field. + * @access public + * @author Nicola Asuni + * @since 2.9.000 (2008-03-26) + */ + public function setUserRights( + $enable=true, + $document='/FullSave', + $annots='/Create/Delete/Modify/Copy/Import/Export', + $form='/Add/Delete/FillIn/Import/Export/SubmitStandalone/SpawnTemplate', + $signature='/Modify') { + $this->ur = $enable; + $this->ur_document = $document; + $this->ur_annots = $annots; + $this->ur_form = $form; + $this->ur_signature = $signature; + } + + /* + * Enable document signature (requires the OpenSSL Library). + * The digital signature improve document authenticity and integrity and allows o enable extra features on Acrobat Reader. + * @param mixed $signing_cert signing certificate (string or filename prefixed with 'file://') + * @param mixed $private_key private key (string or filename prefixed with 'file://') + * @param string $private_key_password password + * @param string $extracerts specifies the name of a file containing a bunch of extra certificates to include in the signature which can for example be used to help the recipient to verify the certificate that you used. + * @param int $cert_type The access permissions granted for this document. Valid values shall be: 1 = No changes to the document shall be permitted; any change to the document shall invalidate the signature; 2 = Permitted changes shall be filling in forms, instantiating page templates, and signing; other changes shall invalidate the signature; 3 = Permitted changes shall be the same as for 2, as well as annotation creation, deletion, and modification; other changes shall invalidate the signature. + * @parm array $info array of option information: Name, Location, Reason, ContactInfo. + * @access public + * @author Nicola Asuni + * @since 4.6.005 (2009-04-24) + */ + public function setSignature($signing_cert='', $private_key='', $private_key_password='', $extracerts='', $cert_type=2, $info=array()) { + // to create self-signed signature: openssl req -x509 -nodes -days 365000 -newkey rsa:1024 -keyout tcpdf.pem -out tcpdf.pem + $this->sign = true; + $this->signature_data = array(); + if (strlen($signing_cert) == 0) { + $signing_cert = 'file://'.dirname(__FILE__).'/tcpdf.pem'; + } + if (strlen($private_key) == 0) { + $private_key = $signing_cert; + } + $this->signature_data['signcert'] = $signing_cert; + $this->signature_data['privkey'] = $private_key; + $this->signature_data['password'] = $private_key_password; + $this->signature_data['extracerts'] = $extracerts; + $this->signature_data['cert_type'] = $cert_type; + $this->signature_data['info'] = array(); + } + + /* + * Create a new page group. + * NOTE: call this function before calling AddPage() + * @param int $page starting group page (leave empty for next page). + * @access public + * @since 3.0.000 (2008-03-27) + */ + public function startPageGroup($page='') { + if (empty($page)) { + $page = $this->page + 1; + } + $this->newpagegroup[$page] = true; + } + + /** + * Defines an alias for the total number of pages. + * It will be substituted as the document is closed. + * @param string $alias The alias. + * @access public + * @since 1.4 + * @see getAliasNbPages(), PageNo(), Footer() + */ + public function AliasNbPages($alias='{nb}') { + $this->AliasNbPages = $alias; + } + + /** + * Returns the string alias used for the total number of pages. + * If the current font is unicode type, the returned string is surrounded by additional curly braces. + * @return string + * @access public + * @since 4.0.018 (2008-08-08) + * @see AliasNbPages(), PageNo(), Footer() + */ + public function getAliasNbPages() { + if (($this->CurrentFont['type'] == 'TrueTypeUnicode') OR ($this->CurrentFont['type'] == 'cidfont0')) { + return '{'.$this->AliasNbPages.'}'; + } + return $this->AliasNbPages; + } + + /** + * Defines an alias for the page number. + * It will be substituted as the document is closed. + * @param string $alias The alias. + * @access public + * @since 4.5.000 (2009-01-02) + * @see getAliasNbPages(), PageNo(), Footer() + */ + public function AliasNumPage($alias='{pnb}') { + //Define an alias for total number of pages + $this->AliasNumPage = $alias; + } + + /** + * Returns the string alias used for the page number. + * If the current font is unicode type, the returned string is surrounded by additional curly braces. + * @return string + * @access public + * @since 4.5.000 (2009-01-02) + * @see AliasNbPages(), PageNo(), Footer() + */ + public function getAliasNumPage() { + if (($this->CurrentFont['type'] == 'TrueTypeUnicode') OR ($this->CurrentFont['type'] == 'cidfont0')) { + return '{'.$this->AliasNumPage.'}'; + } + return $this->AliasNumPage; + } + + /* + * Return the current page in the group. + * @return current page in the group + * @access public + * @since 3.0.000 (2008-03-27) + */ + public function getGroupPageNo() { + return $this->pagegroups[$this->currpagegroup]; + } + + /** + * Returns the current group page number formatted as a string. + * @access public + * @since 4.3.003 (2008-11-18) + * @see PaneNo(), formatPageNumber() + */ + public function getGroupPageNoFormatted() { + return $this->formatPageNumber($this->getGroupPageNo()); + } + + /* + * Return the alias of the current page group + * If the current font is unicode type, the returned string is surrounded by additional curly braces. + * (will be replaced by the total number of pages in this group). + * @return alias of the current page group + * @access public + * @since 3.0.000 (2008-03-27) + */ + public function getPageGroupAlias() { + if (($this->CurrentFont['type'] == 'TrueTypeUnicode') OR ($this->CurrentFont['type'] == 'cidfont0')) { + return '{'.$this->currpagegroup.'}'; + } + return $this->currpagegroup; + } + + /* + * Return the alias for the page number on the current page group + * If the current font is unicode type, the returned string is surrounded by additional curly braces. + * (will be replaced by the total number of pages in this group). + * @return alias of the current page group + * @access public + * @since 4.5.000 (2009-01-02) + */ + public function getPageNumGroupAlias() { + if (($this->CurrentFont['type'] == 'TrueTypeUnicode') OR ($this->CurrentFont['type'] == 'cidfont0')) { + return '{'.str_replace('{nb', '{pnb', $this->currpagegroup).'}'; + } + return str_replace('{nb', '{pnb', $this->currpagegroup); + } + + /** + * Format the page numbers. + * This method can be overriden for custom formats. + * @param int $num page number + * @access protected + * @since 4.2.005 (2008-11-06) + */ + protected function formatPageNumber($num) { + return number_format((float)$num, 0, '', '.'); + } + + /** + * Format the page numbers on the Table Of Content. + * This method can be overriden for custom formats. + * @param int $num page number + * @access protected + * @since 4.5.001 (2009-01-04) + * @see addTOC() + */ + protected function formatTOCPageNumber($num) { + return number_format((float)$num, 0, '', '.'); + } + + /** + * Returns the current page number formatted as a string. + * @access public + * @since 4.2.005 (2008-11-06) + * @see PaneNo(), formatPageNumber() + */ + public function PageNoFormatted() { + return $this->formatPageNumber($this->PageNo()); + } + + /* + * Put visibility settings. + * @access protected + * @since 3.0.000 (2008-03-27) + */ + protected function _putocg() { + $this->_newobj(); + $this->n_ocg_print = $this->n; + $this->_out('<_textstring('print')); + $this->_out('/Usage <> /View <>>>>>'); + $this->_out('endobj'); + $this->_newobj(); + $this->n_ocg_view=$this->n; + $this->_out('<_textstring('view')); + $this->_out('/Usage <> /View <>>>>>'); + $this->_out('endobj'); + } + + /* + * Set the visibility of the successive elements. + * This can be useful, for instance, to put a background + * image or color that will show on screen but won't print. + * @param string $v visibility mode. Legal values are: all, print, screen. + * @access public + * @since 3.0.000 (2008-03-27) + */ + public function setVisibility($v) { + if ($this->openMarkedContent) { + // close existing open marked-content + $this->_out('EMC'); + $this->openMarkedContent = false; + } + switch($v) { + case 'print': { + $this->_out('/OC /OC1 BDC'); + $this->openMarkedContent = true; + break; + } + case 'screen': { + $this->_out('/OC /OC2 BDC'); + $this->openMarkedContent = true; + break; + } + case 'all': { + $this->_out(''); + break; + } + default: { + $this->Error('Incorrect visibility: '.$v); + break; + } + } + $this->visibility = $v; + } + + /* + * Add transparency parameters to the current extgstate + * @param array $params parameters + * @return the number of extgstates + * @access protected + * @since 3.0.000 (2008-03-27) + */ + protected function addExtGState($parms) { + $n = count($this->extgstates) + 1; + $this->extgstates[$n]['parms'] = $parms; + return $n; + } + + /* + * Add an extgstate + * @param array $gs extgstate + * @access protected + * @since 3.0.000 (2008-03-27) + */ + protected function setExtGState($gs) { + $this->_out(sprintf('/GS%d gs', $gs)); + } + + /* + * Put extgstates for object transparency + * @param array $gs extgstate + * @access protected + * @since 3.0.000 (2008-03-27) + */ + protected function _putextgstates() { + $ne = count($this->extgstates); + for ($i = 1; $i <= $ne; ++$i) { + $this->_newobj(); + $this->extgstates[$i]['n'] = $this->n; + $this->_out('<extgstates[$i]['parms'] as $k => $v) { + $this->_out('/'.$k.' '.$v); + } + $this->_out('>>'); + $this->_out('endobj'); + } + } + + /* + * Set alpha for stroking (CA) and non-stroking (ca) operations. + * @param float $alpha real value from 0 (transparent) to 1 (opaque) + * @param string $bm blend mode, one of the following: Normal, Multiply, Screen, Overlay, Darken, Lighten, ColorDodge, ColorBurn, HardLight, SoftLight, Difference, Exclusion, Hue, Saturation, Color, Luminosity + * @access public + * @since 3.0.000 (2008-03-27) + */ + public function setAlpha($alpha, $bm='Normal') { + $gs = $this->addExtGState(array('ca' => $alpha, 'CA' => $alpha, 'BM' => '/'.$bm)); + $this->setExtGState($gs); + } + + /* + * Set the default JPEG compression quality (1-100) + * @param int $quality JPEG quality, integer between 1 and 100 + * @access public + * @since 3.0.000 (2008-03-27) + */ + public function setJPEGQuality($quality) { + if (($quality < 1) OR ($quality > 100)) { + $quality = 75; + } + $this->jpeg_quality = intval($quality); + } + + /* + * Set the default number of columns in a row for HTML tables. + * @param int $cols number of columns + * @access public + * @since 3.0.014 (2008-06-04) + */ + public function setDefaultTableColumns($cols=4) { + $this->default_table_columns = intval($cols); + } + + /* + * Set the height of cell repect font height. + * @param int $h cell proportion respect font height (typical value = 1.25). + * @access public + * @since 3.0.014 (2008-06-04) + */ + public function setCellHeightRatio($h) { + $this->cell_height_ratio = $h; + } + + /* + * return the height of cell repect font height. + * @access public + * @since 4.0.012 (2008-07-24) + */ + public function getCellHeightRatio() { + return $this->cell_height_ratio; + } + + /* + * Set the PDF version (check PDF reference for valid values). + * Default value is 1.t + * @access public + * @since 3.1.000 (2008-06-09) + */ + public function setPDFVersion($version='1.7') { + $this->PDFVersion = $version; + } + + /* + * Set the viewer preferences dictionary controlling the way the document is to be presented on the screen or in print. + * (see Section 8.1 of PDF reference, "Viewer Preferences"). + *
      + *
    • HideToolbar boolean (Optional) A flag specifying whether to hide the viewer application's tool bars when the document is active. Default value: false.
    • + *
    • HideMenubar boolean (Optional) A flag specifying whether to hide the viewer application's menu bar when the document is active. Default value: false.
    • + *
    • HideWindowUI boolean (Optional) A flag specifying whether to hide user interface elements in the document's window (such as scroll bars and navigation controls), leaving only the document's contents displayed. Default value: false.
    • + *
    • FitWindow boolean (Optional) A flag specifying whether to resize the document's window to fit the size of the first displayed page. Default value: false.
    • + *
    • CenterWindow boolean (Optional) A flag specifying whether to position the document's window in the center of the screen. Default value: false.
    • + *
    • DisplayDocTitle boolean (Optional; PDF 1.4) A flag specifying whether the window's title bar should display the document title taken from the Title entry of the document information dictionary (see Section 10.2.1, "Document Information Dictionary"). If false, the title bar should instead display the name of the PDF file containing the document. Default value: false.
    • + *
    • NonFullScreenPageMode name (Optional) The document's page mode, specifying how to display the document on exiting full-screen mode:
      • UseNone Neither document outline nor thumbnail images visible
      • UseOutlines Document outline visible
      • UseThumbs Thumbnail images visible
      • UseOC Optional content group panel visible
        • This entry is meaningful only if the value of the PageMode entry in the catalog dictionary (see Section 3.6.1, "Document Catalog") is FullScreen; it is ignored otherwise. Default value: UseNone. + *
        • ViewArea name (Optional; PDF 1.4) The name of the page boundary representing the area of a page to be displayed when viewing the document on the screen. Valid values are (see Section 10.10.1, "Page Boundaries").:
          • MediaBox
          • CropBox (default)
          • BleedBox
          • TrimBox
          • ArtBox
        • + *
        • ViewClip name (Optional; PDF 1.4) The name of the page boundary to which the contents of a page are to be clipped when viewing the document on the screen. Valid values are (see Section 10.10.1, "Page Boundaries").:
          • MediaBox
          • CropBox (default)
          • BleedBox
          • TrimBox
          • ArtBox
        • + *
        • PrintArea name (Optional; PDF 1.4) The name of the page boundary representing the area of a page to be rendered when printing the document. Valid values are (see Section 10.10.1, "Page Boundaries").:
          • MediaBox
          • CropBox (default)
          • BleedBox
          • TrimBox
          • ArtBox
        • + *
        • PrintClip name (Optional; PDF 1.4) The name of the page boundary to which the contents of a page are to be clipped when printing the document. Valid values are (see Section 10.10.1, "Page Boundaries").:
          • MediaBox
          • CropBox (default)
          • BleedBox
          • TrimBox
          • ArtBox
        • + *
        • PrintScaling name (Optional; PDF 1.6) The page scaling option to be selected when a print dialog is displayed for this document. Valid values are:
          • None, which indicates that the print dialog should reflect no page scaling
          • AppDefault (default), which indicates that applications should use the current print scaling
            • + *
            • Duplex name (Optional; PDF 1.7) The paper handling option to use when printing the file from the print dialog. The following values are valid:
              • Simplex - Print single-sided
              • DuplexFlipShortEdge - Duplex and flip on the short edge of the sheet
              • DuplexFlipLongEdge - Duplex and flip on the long edge of the sheet
              Default value: none
            • + *
            • PickTrayByPDFSize boolean (Optional; PDF 1.7) A flag specifying whether the PDF page size is used to select the input paper tray. This setting influences only the preset values used to populate the print dialog presented by a PDF viewer application. If PickTrayByPDFSize is true, the check box in the print dialog associated with input paper tray is checked. Note: This setting has no effect on Mac OS systems, which do not provide the ability to pick the input tray by size.
            • + *
            • PrintPageRange array (Optional; PDF 1.7) The page numbers used to initialize the print dialog box when the file is printed. The first page of the PDF file is denoted by 1. Each pair consists of the first and last pages in the sub-range. An odd number of integers causes this entry to be ignored. Negative numbers cause the entire array to be ignored. Default value: as defined by PDF viewer application
            • + *
            • NumCopies integer (Optional; PDF 1.7) The number of copies to be printed when the print dialog is opened for this file. Supported values are the integers 2 through 5. Values outside this range are ignored. Default value: as defined by PDF viewer application, but typically 1
            • + *
            + * @param array $preferences array of options. + * @author Nicola Asuni + * @access public + * @since 3.1.000 (2008-06-09) + */ + public function setViewerPreferences($preferences) { + $this->viewer_preferences = $preferences; + } + + /** + * Paints a linear colour gradient. + * @param float $x abscissa of the top left corner of the rectangle. + * @param float $y ordinate of the top left corner of the rectangle. + * @param float $w width of the rectangle. + * @param float $h height of the rectangle. + * @param array $col1 first color (RGB components). + * @param array $col2 second color (RGB components). + * @param array $coords array of the form (x1, y1, x2, y2) which defines the gradient vector (see linear_gradient_coords.jpg). The default value is from left to right (x1=0, y1=0, x2=1, y2=0). + * @author Andreas Würmser, Nicola Asuni + * @since 3.1.000 (2008-06-09) + * @access public + */ + public function LinearGradient($x, $y, $w, $h, $col1=array(), $col2=array(), $coords=array(0,0,1,0)) { + $this->Clip($x, $y, $w, $h); + $this->Gradient(2, $col1, $col2, $coords); + } + + /** + * Paints a radial colour gradient. + * @param float $x abscissa of the top left corner of the rectangle. + * @param float $y ordinate of the top left corner of the rectangle. + * @param float $w width of the rectangle. + * @param float $h height of the rectangle. + * @param array $col1 first color (RGB components). + * @param array $col2 second color (RGB components). + * @param array $coords array of the form (fx, fy, cx, cy, r) where (fx, fy) is the starting point of the gradient with color1, (cx, cy) is the center of the circle with color2, and r is the radius of the circle (see radial_gradient_coords.jpg). (fx, fy) should be inside the circle, otherwise some areas will not be defined. + * @author Andreas Würmser, Nicola Asuni + * @since 3.1.000 (2008-06-09) + * @access public + */ + public function RadialGradient($x, $y, $w, $h, $col1=array(), $col2=array(), $coords=array(0.5,0.5,0.5,0.5,1)) { + $this->Clip($x, $y, $w, $h); + $this->Gradient(3, $col1, $col2, $coords); + } + + /** + * Paints a coons patch mesh. + * @param float $x abscissa of the top left corner of the rectangle. + * @param float $y ordinate of the top left corner of the rectangle. + * @param float $w width of the rectangle. + * @param float $h height of the rectangle. + * @param array $col1 first color (lower left corner) (RGB components). + * @param array $col2 second color (lower right corner) (RGB components). + * @param array $col3 third color (upper right corner) (RGB components). + * @param array $col4 fourth color (upper left corner) (RGB components). + * @param array $coords
            • for one patch mesh: array(float x1, float y1, .... float x12, float y12): 12 pairs of coordinates (normally from 0 to 1) which specify the Bezier control points that define the patch. First pair is the lower left edge point, next is its right control point (control point 2). Then the other points are defined in the order: control point 1, edge point, control point 2 going counter-clockwise around the patch. Last (x12, y12) is the first edge point's left control point (control point 1).
            • for two or more patch meshes: array[number of patches]: arrays with the following keys for each patch: f: where to put that patch (0 = first patch, 1, 2, 3 = right, top and left of precedent patch - I didn't figure this out completely - just try and error ;-) points: 12 pairs of coordinates of the Bezier control points as above for the first patch, 8 pairs of coordinates for the following patches, ignoring the coordinates already defined by the precedent patch (I also didn't figure out the order of these - also: try and see what's happening) colors: must be 4 colors for the first patch, 2 colors for the following patches
            + * @param array $coords_min minimum value used by the coordinates. If a coordinate's value is smaller than this it will be cut to coords_min. default: 0 + * @param array $coords_max maximum value used by the coordinates. If a coordinate's value is greater than this it will be cut to coords_max. default: 1 + * @author Andreas Würmser, Nicola Asuni + * @since 3.1.000 (2008-06-09) + * @access public + */ + public function CoonsPatchMesh($x, $y, $w, $h, $col1=array(), $col2=array(), $col3=array(), $col4=array(), $coords=array(0.00,0.0,0.33,0.00,0.67,0.00,1.00,0.00,1.00,0.33,1.00,0.67,1.00,1.00,0.67,1.00,0.33,1.00,0.00,1.00,0.00,0.67,0.00,0.33), $coords_min=0, $coords_max=1) { + $this->Clip($x, $y, $w, $h); + $n = count($this->gradients) + 1; + $this->gradients[$n]['type'] = 6; //coons patch mesh + //check the coords array if it is the simple array or the multi patch array + if (!isset($coords[0]['f'])) { + //simple array -> convert to multi patch array + if (!isset($col1[1])) { + $col1[1] = $col1[2] = $col1[0]; + } + if (!isset($col2[1])) { + $col2[1] = $col2[2] = $col2[0]; + } + if (!isset($col3[1])) { + $col3[1] = $col3[2] = $col3[0]; + } + if (!isset($col4[1])) { + $col4[1] = $col4[2] = $col4[0]; + } + $patch_array[0]['f'] = 0; + $patch_array[0]['points'] = $coords; + $patch_array[0]['colors'][0]['r'] = $col1[0]; + $patch_array[0]['colors'][0]['g'] = $col1[1]; + $patch_array[0]['colors'][0]['b'] = $col1[2]; + $patch_array[0]['colors'][1]['r'] = $col2[0]; + $patch_array[0]['colors'][1]['g'] = $col2[1]; + $patch_array[0]['colors'][1]['b'] = $col2[2]; + $patch_array[0]['colors'][2]['r'] = $col3[0]; + $patch_array[0]['colors'][2]['g'] = $col3[1]; + $patch_array[0]['colors'][2]['b'] = $col3[2]; + $patch_array[0]['colors'][3]['r'] = $col4[0]; + $patch_array[0]['colors'][3]['g'] = $col4[1]; + $patch_array[0]['colors'][3]['b'] = $col4[2]; + } else { + //multi patch array + $patch_array = $coords; + } + $bpcd = 65535; //16 BitsPerCoordinate + //build the data stream + $this->gradients[$n]['stream'] = ''; + $count_patch = count($patch_array); + for ($i=0; $i < $count_patch; ++$i) { + $this->gradients[$n]['stream'] .= chr($patch_array[$i]['f']); //start with the edge flag as 8 bit + $count_points = count($patch_array[$i]['points']); + for ($j=0; $j < $count_points; ++$j) { + //each point as 16 bit + $patch_array[$i]['points'][$j] = (($patch_array[$i]['points'][$j] - $coords_min) / ($coords_max - $coords_min)) * $bpcd; + if ($patch_array[$i]['points'][$j] < 0) { + $patch_array[$i]['points'][$j] = 0; + } + if ($patch_array[$i]['points'][$j] > $bpcd) { + $patch_array[$i]['points'][$j] = $bpcd; + } + $this->gradients[$n]['stream'] .= chr(floor($patch_array[$i]['points'][$j] / 256)); + $this->gradients[$n]['stream'] .= chr(floor($patch_array[$i]['points'][$j] % 256)); + } + $count_cols = count($patch_array[$i]['colors']); + for ($j=0; $j < $count_cols; ++$j) { + //each color component as 8 bit + $this->gradients[$n]['stream'] .= chr($patch_array[$i]['colors'][$j]['r']); + $this->gradients[$n]['stream'] .= chr($patch_array[$i]['colors'][$j]['g']); + $this->gradients[$n]['stream'] .= chr($patch_array[$i]['colors'][$j]['b']); + } + } + //paint the gradient + $this->_out('/Sh'.$n.' sh'); + //restore previous Graphic State + $this->_out('Q'); + } + + /** + * Set a rectangular clipping area. + * @param float $x abscissa of the top left corner of the rectangle (or top right corner for RTL mode). + * @param float $y ordinate of the top left corner of the rectangle. + * @param float $w width of the rectangle. + * @param float $h height of the rectangle. + * @author Andreas Würmser, Nicola Asuni + * @since 3.1.000 (2008-06-09) + * @access protected + */ + protected function Clip($x, $y, $w, $h) { + if ($this->rtl) { + $x = $this->w - $x - $w; + } + //save current Graphic State + $s = 'q'; + //set clipping area + $s .= sprintf(' %.2F %.2F %.2F %.2F re W n', $x*$this->k, ($this->h-$y)*$this->k, $w*$this->k, -$h*$this->k); + //set up transformation matrix for gradient + $s .= sprintf(' %.3F 0 0 %.3F %.3F %.3F cm', $w*$this->k, $h*$this->k, $x*$this->k, ($this->h-($y+$h))*$this->k); + $this->_out($s); + } + + /** + * Output gradient. + * @param int $type type of gradient. + * @param array $col1 first color (RGB components). + * @param array $col2 second color (RGB components). + * @param array $coords array of coordinates. + * @author Andreas Würmser, Nicola Asuni + * @since 3.1.000 (2008-06-09) + * @access protected + */ + protected function Gradient($type, $col1, $col2, $coords) { + $n = count($this->gradients) + 1; + $this->gradients[$n]['type'] = $type; + if (!isset($col1[1])) { + $col1[1]=$col1[2]=$col1[0]; + } + $this->gradients[$n]['col1'] = sprintf('%.3F %.3F %.3F', ($col1[0]/255), ($col1[1]/255), ($col1[2]/255)); + if (!isset($col2[1])) { + $col2[1] = $col2[2] = $col2[0]; + } + $this->gradients[$n]['col2'] = sprintf('%.3F %.3F %.3F', ($col2[0]/255), ($col2[1]/255), ($col2[2]/255)); + $this->gradients[$n]['coords'] = $coords; + //paint the gradient + $this->_out('/Sh'.$n.' sh'); + //restore previous Graphic State + $this->_out('Q'); + } + + /** + * Output shaders. + * @author Andreas Würmser, Nicola Asuni + * @since 3.1.000 (2008-06-09) + * @access protected + */ + function _putshaders() { + foreach ($this->gradients as $id => $grad) { + if (($grad['type'] == 2) OR ($grad['type'] == 3)) { + $this->_newobj(); + $this->_out('<<'); + $this->_out('/FunctionType 2'); + $this->_out('/Domain [0.0 1.0]'); + $this->_out('/C0 ['.$grad['col1'].']'); + $this->_out('/C1 ['.$grad['col2'].']'); + $this->_out('/N 1'); + $this->_out('>>'); + $this->_out('endobj'); + $f1 = $this->n; + } + $this->_newobj(); + $this->_out('<<'); + $this->_out('/ShadingType '.$grad['type']); + $this->_out('/ColorSpace /DeviceRGB'); + if ($grad['type'] == 2) { + $this->_out(sprintf('/Coords [%.3F %.3F %.3F %.3F]', $grad['coords'][0], $grad['coords'][1], $grad['coords'][2], $grad['coords'][3])); + $this->_out('/Function '.$f1.' 0 R'); + $this->_out('/Extend [true true] '); + $this->_out('>>'); + } elseif ($grad['type'] == 3) { + //x0, y0, r0, x1, y1, r1 + //at this this time radius of inner circle is 0 + $this->_out(sprintf('/Coords [%.3F %.3F 0 %.3F %.3F %.3F]', $grad['coords'][0], $grad['coords'][1], $grad['coords'][2], $grad['coords'][3], $grad['coords'][4])); + $this->_out('/Function '.$f1.' 0 R'); + $this->_out('/Extend [true true] '); + $this->_out('>>'); + } elseif ($grad['type'] == 6) { + $this->_out('/BitsPerCoordinate 16'); + $this->_out('/BitsPerComponent 8'); + $this->_out('/Decode[0 1 0 1 0 1 0 1 0 1]'); + $this->_out('/BitsPerFlag 8'); + $this->_out('/Length '.strlen($grad['stream'])); + $this->_out('>>'); + $this->_putstream($grad['stream']); + } + $this->_out('endobj'); + $this->gradients[$id]['id'] = $this->n; + } + } + + /** + * Output an arc + * @author Maxime Delorme, Nicola Asuni + * @since 3.1.000 (2008-06-09) + * @access protected + */ + protected function _outarc($x1, $y1, $x2, $y2, $x3, $y3 ) { + $h = $this->h; + $this->_out(sprintf('%.2F %.2F %.2F %.2F %.2F %.2F c', $x1*$this->k, ($h-$y1)*$this->k, $x2*$this->k, ($h-$y2)*$this->k, $x3*$this->k, ($h-$y3)*$this->k)); + } + + /** + * Draw the sector of a circle. + * It can be used for instance to render pie charts. + * @param float $xc abscissa of the center. + * @param float $yc ordinate of the center. + * @param float $r radius. + * @param float $a start angle (in degrees). + * @param float $b end angle (in degrees). + * @param string $style: D, F, FD or DF (draw, fill, fill and draw). Default: FD. + * @param float $cw: indicates whether to go clockwise (default: true). + * @param float $o: origin of angles (0 for 3 o'clock, 90 for noon, 180 for 9 o'clock, 270 for 6 o'clock). Default: 90. + * @author Maxime Delorme, Nicola Asuni + * @since 3.1.000 (2008-06-09) + * @access public + */ + public function PieSector($xc, $yc, $r, $a, $b, $style='FD', $cw=true, $o=90) { + if ($this->rtl) { + $xc = $this->w - $xc; + } + if ($cw) { + $d = $b; + $b = $o - $a; + $a = $o - $d; + } else { + $b += $o; + $a += $o; + } + $a = ($a % 360) + 360; + $b = ($b % 360) + 360; + if ($a > $b) { + $b +=360; + } + $b = $b / 360 * 2 * M_PI; + $a = $a / 360 * 2 * M_PI; + $d = $b - $a; + if ($d == 0 ) { + $d = 2 * M_PI; + } + $k = $this->k; + $hp = $this->h; + if ($style=='F') { + $op = 'f'; + } elseif ($style=='FD' or $style=='DF') { + $op = 'b'; + } else { + $op = 's'; + } + if (sin($d/2)) { + $MyArc = 4/3 * (1 - cos($d/2)) / sin($d/2) * $r; + } + //first put the center + $this->_out(sprintf('%.2F %.2F m', ($xc)*$k, ($hp-$yc)*$k)); + //put the first point + $this->_out(sprintf('%.2F %.2F l', ($xc+$r*cos($a))*$k, (($hp-($yc-$r*sin($a)))*$k))); + //draw the arc + if ($d < (M_PI/2)) { + $this->_outarc($xc+$r*cos($a)+$MyArc*cos(M_PI/2+$a), $yc-$r*sin($a)-$MyArc*sin(M_PI/2+$a), $xc+$r*cos($b)+$MyArc*cos($b-M_PI/2), $yc-$r*sin($b)-$MyArc*sin($b-M_PI/2), $xc+$r*cos($b), $yc-$r*sin($b)); + } else { + $b = $a + $d/4; + $MyArc = 4/3*(1-cos($d/8))/sin($d/8)*$r; + $this->_outarc($xc+$r*cos($a)+$MyArc*cos(M_PI/2+$a), $yc-$r*sin($a)-$MyArc*sin(M_PI/2+$a), $xc+$r*cos($b)+$MyArc*cos($b-M_PI/2), $yc-$r*sin($b)-$MyArc*sin($b-M_PI/2), $xc+$r*cos($b), $yc-$r*sin($b)); + $a = $b; + $b = $a + $d/4; + $this->_outarc($xc+$r*cos($a)+$MyArc*cos(M_PI/2+$a), $yc-$r*sin($a)-$MyArc*sin(M_PI/2+$a), $xc+$r*cos($b)+$MyArc*cos($b-M_PI/2), $yc-$r*sin($b)-$MyArc*sin($b-M_PI/2), $xc+$r*cos($b), $yc-$r*sin($b)); + $a = $b; + $b = $a + $d/4; + $this->_outarc($xc+$r*cos($a)+$MyArc*cos(M_PI/2+$a), $yc-$r*sin($a)-$MyArc*sin(M_PI/2+$a), $xc+$r*cos($b)+$MyArc*cos($b-M_PI/2), $yc-$r*sin($b)-$MyArc*sin($b-M_PI/2), $xc+$r*cos($b), $yc-$r*sin($b) ); + $a = $b; + $b = $a + $d/4; + $this->_outarc($xc+$r*cos($a)+$MyArc*cos(M_PI/2+$a), $yc-$r*sin($a)-$MyArc*sin(M_PI/2+$a), $xc+$r*cos($b)+$MyArc*cos($b-M_PI/2), $yc-$r*sin($b)-$MyArc*sin($b-M_PI/2), $xc+$r*cos($b), $yc-$r*sin($b)); + } + //terminate drawing + $this->_out($op); + } + + /** + * Embed vector-based Adobe Illustrator (AI) or AI-compatible EPS files. + * Only vector drawing is supported, not text or bitmap. + * Although the script was successfully tested with various AI format versions, best results are probably achieved with files that were exported in the AI3 format (tested with Illustrator CS2, Freehand MX and Photoshop CS2). + * @param string $file Name of the file containing the image. + * @param float $x Abscissa of the upper-left corner. + * @param float $y Ordinate of the upper-left corner. + * @param float $w Width of the image in the page. If not specified or equal to zero, it is automatically calculated. + * @param float $h Height of the image in the page. If not specified or equal to zero, it is automatically calculated. + * @param mixed $link URL or identifier returned by AddLink(). + * @param boolean useBoundingBox specifies whether to position the bounding box (true) or the complete canvas (false) at location (x,y). Default value is true. + * @param string $align Indicates the alignment of the pointer next to image insertion relative to image height. The value can be:
            • T: top-right for LTR or top-left for RTL
            • M: middle-right for LTR or middle-left for RTL
            • B: bottom-right for LTR or bottom-left for RTL
            • N: next line
            + * @param string $palign Allows to center or align the image on the current line. Possible values are:
            • L : left align
            • C : center
            • R : right align
            • '' : empty string : left for LTR or right for RTL
            + * @param mixed $border Indicates if borders must be drawn around the image. The value can be either a number:
            • 0: no border (default)
            • 1: frame
            or a string containing some or all of the following characters (in any order):
            • L: left
            • T: top
            • R: right
            • B: bottom
            + * @author Valentin Schmidt, Nicola Asuni + * @since 3.1.000 (2008-06-09) + * @access public + */ + public function ImageEps($file, $x='', $y='', $w=0, $h=0, $link='', $useBoundingBox=true, $align='', $palign='', $border=0) { + if ($x === '') { + $x = $this->x; + } + if ($y === '') { + $y = $this->y; + } + $k = $this->k; + $data = file_get_contents($file); + if ($data === false) { + $this->Error('EPS file not found: '.$file); + } + $regs = array(); + // EPS/AI compatibility check (only checks files created by Adobe Illustrator!) + preg_match("/%%Creator:([^\r\n]+)/", $data, $regs); # find Creator + if (count($regs) > 1) { + $version_str = trim($regs[1]); # e.g. "Adobe Illustrator(R) 8.0" + if (strpos($version_str, 'Adobe Illustrator') !== false) { + $versexp = explode(' ', $version_str); + $version = (float)array_pop($versexp); + if ($version >= 9) { + $this->Error('This version of Adobe Illustrator file is not supported: '.$file); + } + } + } + // strip binary bytes in front of PS-header + $start = strpos($data, '%!PS-Adobe'); + if ($start > 0) { + $data = substr($data, $start); + } + // find BoundingBox params + preg_match("/%%BoundingBox:([^\r\n]+)/", $data, $regs); + if (count($regs) > 1) { + list($x1, $y1, $x2, $y2) = explode(' ', trim($regs[1])); + } else { + $this->Error('No BoundingBox found in EPS file: '.$file); + } + $start = strpos($data, '%%EndSetup'); + if ($start === false) { + $start = strpos($data, '%%EndProlog'); + } + if ($start === false) { + $start = strpos($data, '%%BoundingBox'); + } + $data = substr($data, $start); + $end = strpos($data, '%%PageTrailer'); + if ($end===false) { + $end = strpos($data, 'showpage'); + } + if ($end) { + $data = substr($data, 0, $end); + } + if ($w > 0) { + $scale_x = $w / (($x2 - $x1) / $k); + if ($h > 0) { + $scale_y = $h / (($y2 - $y1) / $k); + } else { + $scale_y = $scale_x; + $h = ($y2 - $y1) / $k * $scale_y; + } + } else { + if ($h > 0) { + $scale_y = $h / (($y2 - $y1) / $k); + $scale_x = $scale_y; + $w = ($x2-$x1) / $k * $scale_x; + } else { + $w = ($x2 - $x1) / $k; + $h = ($y2 - $y1) / $k; + } + } + // Check whether we need a new page first as this does not fit + if ($this->checkPageBreak($h, $y)) { + $y = $this->GetY() + $this->cMargin; + } + // set bottomcoordinates + $this->img_rb_y = $y + $h; + // set alignment + if ($this->rtl) { + if ($palign == 'L') { + $ximg = $this->lMargin; + // set right side coordinate + $this->img_rb_x = $ximg + $w; + } elseif ($palign == 'C') { + $ximg = ($this->w - $x - $w) / 2; + // set right side coordinate + $this->img_rb_x = $ximg + $w; + } else { + $ximg = $this->w - $x - $w; + // set left side coordinate + $this->img_rb_x = $ximg; + } + } else { + if ($palign == 'R') { + $ximg = $this->w - $this->rMargin - $w; + // set left side coordinate + $this->img_rb_x = $ximg; + } elseif ($palign == 'C') { + $ximg = ($this->w - $x - $w) / 2; + // set right side coordinate + $this->img_rb_x = $ximg + $w; + } else { + $ximg = $x; + // set right side coordinate + $this->img_rb_x = $ximg + $w; + } + } + if ($useBoundingBox) { + $dx = $ximg * $k - $x1; + $dy = $y * $k - $y1; + } else { + $dx = $ximg * $k; + $dy = $y * $k; + } + // save the current graphic state + $this->_out('q'.$this->epsmarker); + // translate + $this->_out(sprintf('%.3F %.3F %.3F %.3F %.3F %.3F cm', 1, 0, 0, 1, $dx, $dy + ($this->hPt - (2 * $y * $k) - ($y2 - $y1)))); + // scale + if (isset($scale_x)) { + $this->_out(sprintf('%.3F %.3F %.3F %.3F %.3F %.3F cm', $scale_x, 0, 0, $scale_y, $x1 * (1 - $scale_x), $y2 * (1 - $scale_y))); + } + // handle pc/unix/mac line endings + preg_match('/[\r\n]+/s', $data, $regs); + $lines = explode($regs[0], $data); + $u=0; + $cnt = count($lines); + for ($i=0; $i < $cnt; ++$i) { + $line = $lines[$i]; + if (($line == '') OR ($line{0} == '%')) { + continue; + } + $len = strlen($line); + $chunks = explode(' ', $line); + $cmd = array_pop($chunks); + // RGB + if (($cmd == 'Xa') OR ($cmd == 'XA')) { + $b = array_pop($chunks); + $g = array_pop($chunks); + $r = array_pop($chunks); + $this->_out(''.$r.' '.$g.' '.$b.' '.($cmd=='Xa'?'rg':'RG')); //substr($line, 0, -2).'rg' -> in EPS (AI8): c m y k r g b rg! + continue; + } + switch ($cmd) { + case 'm': + case 'l': + case 'v': + case 'y': + case 'c': + case 'k': + case 'K': + case 'g': + case 'G': + case 's': + case 'S': + case 'J': + case 'j': + case 'w': + case 'M': + case 'd': + case 'n': + case 'v': { + $this->_out($line); + break; + } + case 'x': {// custom fill color + list($c,$m,$y,$k) = $chunks; + $this->_out(''.$c.' '.$m.' '.$y.' '.$k.' k'); + break; + } + case 'X': { // custom stroke color + list($c,$m,$y,$k) = $chunks; + $this->_out(''.$c.' '.$m.' '.$y.' '.$k.' K'); + break; + } + case 'Y': + case 'N': + case 'V': + case 'L': + case 'C': { + $line{$len-1} = strtolower($cmd); + $this->_out($line); + break; + } + case 'b': + case 'B': { + $this->_out($cmd . '*'); + break; + } + case 'f': + case 'F': { + if ($u > 0) { + $isU = false; + $max = min($i+5, $cnt); + for ($j=$i+1; $j < $max; ++$j) + $isU = ($isU OR (($lines[$j] == 'U') OR ($lines[$j] == '*U'))); + if ($isU) { + $this->_out('f*'); + } + } else { + $this->_out('f*'); + } + break; + } + case '*u': { + ++$u; + break; + } + case '*U': { + --$u; + break; + } + } + } + // restore previous graphic state + $this->_out($this->epsmarker.'Q'); + if (!empty($border)) { + $bx = $x; + $by = $y; + $this->x = $x; + $this->y = $y; + $this->Cell($w, $h, '', $border, 0, '', 0, '', 0); + $this->x = $bx; + $this->y = $by; + } + if ($link) { + $this->Link($ximg, $y, $w, $h, $link, 0); + } + // set pointer to align the successive text/objects + switch($align) { + case 'T':{ + $this->y = $y; + $this->x = $this->img_rb_x; + break; + } + case 'M':{ + $this->y = $y + round($h/2); + $this->x = $this->img_rb_x; + break; + } + case 'B':{ + $this->y = $this->img_rb_y; + $this->x = $this->img_rb_x; + break; + } + case 'N':{ + $this->SetY($this->img_rb_y); + break; + } + default:{ + break; + } + } + $this->endlinex = $this->img_rb_x; + } + + /** + * Set document barcode. + * @param string $bc barcode + * @access public + */ + public function setBarcode($bc='') { + $this->barcode = $bc; + } + + /** + * Get current barcode. + * @return string + * @access public + * @since 4.0.012 (2008-07-24) + */ + public function getBarcode() { + return $this->barcode; + } + + /** + * Print a Linear Barcode. + * @param string $code code to print + * @param string $type type of barcode. + * @param int $x x position in user units + * @param int $y y position in user units + * @param int $w width in user units + * @param int $h height in user units + * @param float $xres width of the smallest bar in user units + * @param array $style array of options:
            • string $style['position'] barcode position inside the specified width: L = left (default for LTR); C = center; R = right (default for RTL); S = stretch
            • boolean $style['border'] if true prints a border around the barcode
            • int $style['padding'] padding to leave around the barcode in user units
            • array $style['fgcolor'] color array for bars and text
            • mixed $style['bgcolor'] color array for background or false for transparent
            • boolean $style["text"] boolean if true prints text below the barcode
            • string $style['font'] font name for text
            • int $style['fontsize'] font size for text
            • int $style['stretchtext']: 0 = disabled; 1 = horizontal scaling only if necessary; 2 = forced horizontal scaling; 3 = character spacing only if necessary; 4 = forced character spacing
            + * @param string $align Indicates the alignment of the pointer next to barcode insertion relative to barcode height. The value can be:
            • T: top-right for LTR or top-left for RTL
            • M: middle-right for LTR or middle-left for RTL
            • B: bottom-right for LTR or bottom-left for RTL
            • N: next line
            + * @author Nicola Asuni + * @since 3.1.000 (2008-06-09) + * @access public + */ + public function write1DBarcode($code, $type, $x='', $y='', $w='', $h='', $xres=0.4, $style='', $align='') { + if ($this->empty_string($code)) { + return; + } + require_once(dirname(__FILE__).'/barcodes.php'); + // save current graphic settings + $gvars = $this->getGraphicVars(); + // create new barcode object + $barcodeobj = new TCPDFBarcode($code, $type); + $arrcode = $barcodeobj->getBarcodeArray(); + if ($arrcode === false) { + $this->Error('Error in 1D barcode string'); + } + // set default values + if (!isset($style['position'])) { + if ($this->rtl) { + $style['position'] = 'R'; + } else { + $style['position'] = 'L'; + } + } + if (!isset($style['padding'])) { + $style['padding'] = 0; + } + if (!isset($style['fgcolor'])) { + $style['fgcolor'] = array(0,0,0); // default black + } + if (!isset($style['bgcolor'])) { + $style['bgcolor'] = false; // default transparent + } + if (!isset($style['border'])) { + $style['border'] = false; + } + if (!isset($style['text'])) { + $style['text'] = false; + $fontsize = 0; + } + if ($style['text'] AND isset($style['font'])) { + if (isset($style['fontsize'])) { + $fontsize = $style['fontsize']; + } else { + $fontsize = 0; + } + $this->SetFont($style['font'], '', $fontsize); + } + if (!isset($style['stretchtext'])) { + $style['stretchtext'] = 4; + } + // set foreground color + $this->SetDrawColorArray($style['fgcolor']); + $this->SetTextColorArray($style['fgcolor']); + if ($this->empty_string($w) OR ($w <= 0)) { + if ($this->rtl) { + $w = $this->x - $this->lMargin; + } else { + $w = $this->w - $this->rMargin - $this->x; + } + } + if ($this->empty_string($x)) { + $x = $this->GetX(); + } + if ($this->rtl) { + $x = $this->w - $x; + } + if ($this->empty_string($y)) { + $y = $this->GetY(); + } + if ($this->empty_string($xres)) { + $xres = 0.4; + } + $fbw = ($arrcode['maxw'] * $xres) + (2 * $style['padding']); + $extraspace = ($this->cell_height_ratio * $fontsize / $this->k) + (2 * $style['padding']); + if ($this->empty_string($h) OR ($h <= 0)) { + $h = 10 + $extraspace; + } + if ($this->checkPageBreak($h)) { + $y = $this->y; + } + // maximum bar heigth + $barh = $h - $extraspace; + switch ($style['position']) { + case 'L': { // left + if ($this->rtl) { + $xpos = $x - $w; + } else { + $xpos = $x; + } + break; + } + case 'C': { // center + $xdiff = (($w - $fbw) / 2); + if ($this->rtl) { + $xpos = $x - $w + $xdiff; + } else { + $xpos = $x + $xdiff; + } + break; + } + case 'R': { // right + if ($this->rtl) { + $xpos = $x - $fbw; + } else { + $xpos = $x + $w - $fbw; + } + break; + } + case 'S': { // stretch + $fbw = $w; + $xres = ($w - (2 * $style['padding'])) / $arrcode['maxw']; + if ($this->rtl) { + $xpos = $x - $w; + } else { + $xpos = $x; + } + break; + } + } + $xpos_rect = $xpos; + $xpos = $xpos_rect + $style['padding']; + $xpos_text = $xpos; + // barcode is always printed in LTR direction + $tempRTL = $this->rtl; + $this->rtl = false; + // print background color + if ($style['bgcolor']) { + $this->Rect($xpos_rect, $y, $fbw, $h, 'DF', '', $style['bgcolor']); + } elseif ($style['border']) { + $this->Rect($xpos_rect, $y, $fbw, $h, 'D'); + } + // print bars + if ($arrcode !== false) { + foreach ($arrcode['bcode'] as $k => $v) { + $bw = ($v['w'] * $xres); + if ($v['t']) { + // draw a vertical bar + $ypos = $y + $style['padding'] + ($v['p'] * $barh / $arrcode['maxh']); + $this->Rect($xpos, $ypos, $bw, ($v['h'] * $barh / $arrcode['maxh']), 'F', array(), $style['fgcolor']); + } + $xpos += $bw; + } + } + // print text + if ($style['text']) { + // print text + $this->x = $xpos_text; + $this->y = $y + $style['padding'] + $barh; + $this->Cell(($arrcode['maxw'] * $xres), ($this->cell_height_ratio * $fontsize / $this->k), $code, 0, 0, 'C', 0, '', $style['stretchtext']); + } + // restore original direction + $this->rtl = $tempRTL; + // restore previous settings + $this->setGraphicVars($gvars); + // set bottomcoordinates + $this->img_rb_y = $y + $h; + if ($this->rtl) { + // set left side coordinate + $this->img_rb_x = ($this->w - $x - $w); + } else { + // set right side coordinate + $this->img_rb_x = $x + $w; + } + // set pointer to align the successive text/objects + switch($align) { + case 'T':{ + $this->y = $y; + $this->x = $this->img_rb_x; + break; + } + case 'M':{ + $this->y = $y + round($h/2); + $this->x = $this->img_rb_x; + break; + } + case 'B':{ + $this->y = $this->img_rb_y; + $this->x = $this->img_rb_x; + break; + } + case 'N':{ + $this->SetY($this->img_rb_y); + break; + } + default:{ + break; + } + } + } + + /** + * This function is DEPRECATED, please use the new write1DBarcode() function. + * @param int $x x position in user units + * @param int $y y position in user units + * @param int $w width in user units + * @param int $h height position in user units + * @param string $type type of barcode (I25, C128A, C128B, C128C, C39) + * @param string $style barcode style + * @param string $font font for text + * @param int $xres x resolution + * @param string $code code to print + * @deprecated deprecated since version 3.1.000 (2008-06-10) + * @access public + * @see write1DBarcode() + */ + public function writeBarcode($x, $y, $w, $h, $type, $style, $font, $xres, $code) { + // convert old settings for the new write1DBarcode() function. + $xres = 1 / $xres; + $newstyle = array( + 'position' => 'L', + 'border' => false, + 'padding' => 0, + 'fgcolor' => array(0,0,0), + 'bgcolor' => false, + 'text' => true, + 'font' => $font, + 'fontsize' => 8, + 'stretchtext' => 4 + ); + if ($style & 1) { + $newstyle['border'] = true; + } + if ($style & 2) { + $newstyle['bgcolor'] = false; + } + if ($style & 4) { + $newstyle['position'] = 'C'; + } elseif ($style & 8) { + $newstyle['position'] = 'L'; + } elseif ($style & 16) { + $newstyle['position'] = 'R'; + } + if ($style & 128) { + $newstyle['text'] = true; + } + if ($style & 256) { + $newstyle['stretchtext'] = 4; + } + $this->write1DBarcode($code, $type, $x, $y, $w, $h, $xres, $newstyle, ''); + } + + /** + * Print 2D Barcode. + * @param string $code code to print + * @param string $type type of barcode. + * @param int $x x position in user units + * @param int $y y position in user units + * @param int $w width in user units + * @param int $h height in user units + * @param array $style array of options:
            • boolean $style['border'] if true prints a border around the barcode
            • int $style['padding'] padding to leave around the barcode in user units
            • array $style['fgcolor'] color array for bars and text
            • mixed $style['bgcolor'] color array for background or false for transparent
            + * @param string $align Indicates the alignment of the pointer next to barcode insertion relative to barcode height. The value can be:
            • T: top-right for LTR or top-left for RTL
            • M: middle-right for LTR or middle-left for RTL
            • B: bottom-right for LTR or bottom-left for RTL
            • N: next line
            + * @author Nicola Asuni + * @since 4.5.037 (2009-04-07) + * @access public + */ + public function write2DBarcode($code, $type, $x='', $y='', $w='', $h='', $style='', $align='') { + if ($this->empty_string($code)) { + return; + } + require_once(dirname(__FILE__).'/2dbarcodes.php'); + // save current graphic settings + $gvars = $this->getGraphicVars(); + // create new barcode object + $barcodeobj = new TCPDF2DBarcode($code, $type); + $arrcode = $barcodeobj->getBarcodeArray(); + if ($arrcode === false) { + $this->Error('Error in 2D barcode string'); + } + // set default values + if (!isset($style['padding'])) { + $style['padding'] = 0; + } + if (!isset($style['fgcolor'])) { + $style['fgcolor'] = array(0,0,0); // default black + } + if (!isset($style['bgcolor'])) { + $style['bgcolor'] = false; // default transparent + } + if (!isset($style['border'])) { + $style['border'] = false; + } + // set foreground color + $this->SetDrawColorArray($style['fgcolor']); + if ($this->empty_string($x)) { + $x = $this->GetX(); + } + if ($this->rtl) { + $x = $this->w - $x; + } + if ($this->empty_string($y)) { + $y = $this->GetY(); + } + if ($this->empty_string($w) OR ($w <= 0)) { + if ($this->rtl) { + $w = $x - $this->lMargin; + } else { + $w = $this->w - $this->rMargin - $x; + } + } + if ($this->empty_string($h) OR ($h <= 0)) { + // 2d barcodes are square by default + $h = $w; + } + if ($this->checkPageBreak($h)) { + $y = $this->y; + } + // calculate barcode size (excluding padding) + $bw = $w - (2 * $style['padding']); + $bh = $h - (2 * $style['padding']); + // calculate starting coordinates + if ($this->rtl) { + $xpos = $x - $w; + } else { + $xpos = $x; + } + $xpos += $style['padding']; + $ypos = $y + $style['padding']; + // barcode is always printed in LTR direction + $tempRTL = $this->rtl; + $this->rtl = false; + // print background color + if ($style['bgcolor']) { + $this->Rect($x, $y, $w, $h, 'DF', '', $style['bgcolor']); + } elseif ($style['border']) { + $this->Rect($x, $y, $w, $h, 'D'); + } + // print barcode cells + if ($arrcode !== false) { + $rows = $arrcode['num_rows']; + $cols = $arrcode['num_cols']; + // calculate dimension of single barcode cell + $cw = $bw / $cols; + $ch = $bh / $rows; + // for each row + for ($r = 0; $r < $rows; ++$r) { + $xr = $xpos; + // for each column + for ($c = 0; $c < $cols; ++$c) { + if ($arrcode['bcode'][$r][$c] == 1) { + // draw a single barcode cell + $this->Rect($xr, $ypos, $cw, $ch, 'F', array(), $style['fgcolor']); + } + $xr += $cw; + } + $ypos += $ch; + } + } + // restore original direction + $this->rtl = $tempRTL; + // restore previous settings + $this->setGraphicVars($gvars); + // set bottomcoordinates + $this->img_rb_y = $y + $h; + if ($this->rtl) { + // set left side coordinate + $this->img_rb_x = ($this->w - $x - $w); + } else { + // set right side coordinate + $this->img_rb_x = $x + $w; + } + // set pointer to align the successive text/objects + switch($align) { + case 'T':{ + $this->y = $y; + $this->x = $this->img_rb_x; + break; + } + case 'M':{ + $this->y = $y + round($h/2); + $this->x = $this->img_rb_x; + break; + } + case 'B':{ + $this->y = $this->img_rb_y; + $this->x = $this->img_rb_x; + break; + } + case 'N':{ + $this->SetY($this->img_rb_y); + break; + } + default:{ + break; + } + } + } + + /** + * Returns an array containing current margins: + *
              +
            • $ret['left'] = left margin
            • +
            • $ret['right'] = right margin
            • +
            • $ret['top'] = top margin
            • +
            • $ret['bottom'] = bottom margin
            • +
            • $ret['header'] = header margin
            • +
            • $ret['footer'] = footer margin
            • +
            • $ret['cell'] = cell margin
            • + *
            + * @return array containing all margins measures + * @access public + * @since 3.2.000 (2008-06-23) + */ + public function getMargins() { + $ret = array( + 'left' => $this->lMargin, + 'right' => $this->rMargin, + 'top' => $this->tMargin, + 'bottom' => $this->bMargin, + 'header' => $this->header_margin, + 'footer' => $this->footer_margin, + 'cell' => $this->cMargin, + ); + return $ret; + } + + /** + * Returns an array containing original margins: + *
              +
            • $ret['left'] = left margin
            • +
            • $ret['right'] = right margin
            • + *
            + * @return array containing all margins measures + * @access public + * @since 4.0.012 (2008-07-24) + */ + public function getOriginalMargins() { + $ret = array( + 'left' => $this->original_lMargin, + 'right' => $this->original_rMargin + ); + return $ret; + } + + /** + * Returns the current font size. + * @return current font size + * @access public + * @since 3.2.000 (2008-06-23) + */ + public function getFontSize() { + return $this->FontSize; + } + + /** + * Returns the current font size in points unit. + * @return current font size in points unit + * @access public + * @since 3.2.000 (2008-06-23) + */ + public function getFontSizePt() { + return $this->FontSizePt; + } + + /** + * Returns the current font family name. + * @return string current font family name + * @access public + * @since 4.3.008 (2008-12-05) + */ + public function getFontFamily() { + return $this->FontFamily; + } + + /** + * Returns the current font style. + * @return string current font style + * @access public + * @since 4.3.008 (2008-12-05) + */ + public function getFontStyle() { + return $this->FontStyle; + } + + /** + * Prints a cell (rectangular area) with optional borders, background color and html text string. + * The upper-left corner of the cell corresponds to the current position. After the call, the current position moves to the right or to the next line.
            + * If automatic page breaking is enabled and the cell goes beyond the limit, a page break is done before outputting. + * @param float $w Cell width. If 0, the cell extends up to the right margin. + * @param float $h Cell minimum height. The cell extends automatically if needed. + * @param float $x upper-left corner X coordinate + * @param float $y upper-left corner Y coordinate + * @param string $html html text to print. Default value: empty string. + * @param mixed $border Indicates if borders must be drawn around the cell. The value can be either a number:
            • 0: no border (default)
            • 1: frame
            or a string containing some or all of the following characters (in any order):
            • L: left
            • T: top
            • R: right
            • B: bottom
            + * @param int $ln Indicates where the current position should go after the call. Possible values are:
            • 0: to the right (or left for RTL language)
            • 1: to the beginning of the next line
            • 2: below
            + Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: 0. + * @param int $fill Indicates if the cell background must be painted (1) or transparent (0). Default value: 0. + * @param boolean $reseth if true reset the last cell height (default true). + * @param string $align Allows to center or align the text. Possible values are:
            • L : left align
            • C : center
            • R : right align
            • '' : empty string : left for LTR or right for RTL
            + * @param boolean $autopadding if true, uses internal padding and automatically adjust it to account for line width. + * @access public + * @uses MultiCell() + * @see Multicell(), writeHTML() + */ + public function writeHTMLCell($w, $h, $x, $y, $html='', $border=0, $ln=0, $fill=0, $reseth=true, $align='', $autopadding=true) { + return $this->MultiCell($w, $h, $html, $border, $align, $fill, $ln, $x, $y, $reseth, 0, true, $autopadding, 0); + } + + /** + * Returns the HTML DOM array. + *
            • $dom[$key]['tag'] = true if tag, false otherwise;
            • $dom[$key]['value'] = tag name or text;
            • $dom[$key]['opening'] = true if opening tag, false otherwise;
            • $dom[$key]['attribute'] = array of attributes (attribute name is the key);
            • $dom[$key]['style'] = array of style attributes (attribute name is the key);
            • $dom[$key]['parent'] = id of parent element;
            • $dom[$key]['fontname'] = font family name;
            • $dom[$key]['fontstyle'] = font style;
            • $dom[$key]['fontsize'] = font size in points;
            • $dom[$key]['bgcolor'] = RGB array of background color;
            • $dom[$key]['fgcolor'] = RGB array of foreground color;
            • $dom[$key]['width'] = width in pixels;
            • $dom[$key]['height'] = height in pixels;
            • $dom[$key]['align'] = text alignment;
            • $dom[$key]['cols'] = number of colums in table;
            • $dom[$key]['rows'] = number of rows in table;
            + * @param string $html html code + * @return array + * @access protected + * @since 3.2.000 (2008-06-20) + */ + protected function getHtmlDomArray($html) { + // remove all unsupported tags (the line below lists all supported tags) + $html = strip_tags($html, '



              • '); + //replace some blank characters + $html = preg_replace('/
                ]*)>[\n\r\t]+/', '<\\1\\2>', $html);
                +			$html = preg_replace('@(\r\n|\r)@', "\n", $html);
                +			$repTable = array("\t" => ' ', "\0" => ' ', "\x0B" => ' ', "\\" => "\\\\");
                +			$html = strtr($html, $repTable);
                +			while (preg_match("']*)>(.*?)\n(.*?)
                'si", $html)) { + // preserve newlines on
                 tag
                +				$html = preg_replace("']*)>(.*?)\n(.*?)
                'si", "\\2
                \\3", $html); + } + $html = str_replace("\n", ' ', $html); + // remove extra spaces from code + $html = preg_replace('/[\s]+<\/(table|tr|td|th|ul|ol|li)>/', '', $html); + $html = preg_replace('/[\s]+<(tr|td|th|ul|ol|li|br)/', '<\\1', $html); + $html = preg_replace('/<\/(table|tr|td|th|blockquote|dd|div|dt|h1|h2|h3|h4|h5|h6|hr|li|ol|ul|p)>[\s]+<', $html); + $html = preg_replace('/<\/(td|th)>/', '', $html); + $html = preg_replace('/<\/table>([\s]*)/', '
              ', $html); + $html = preg_replace('/]*)>/xi', '', $html); + $html = preg_replace('/FontFamily; + $dom[$key]['fontstyle'] = $this->FontStyle; + $dom[$key]['fontsize'] = $this->FontSizePt; + $dom[$key]['bgcolor'] = false; + $dom[$key]['fgcolor'] = $this->fgcolor; + $dom[$key]['align'] = ''; + $dom[$key]['listtype'] = ''; + $thead = false; // true when we are inside the THEAD tag + ++$key; + $level = array(); + array_push($level, 0); // root + while ($elkey < $maxel) { + $dom[$key] = array(); + $element = $a[$elkey]; + $dom[$key]['elkey'] = $elkey; + if (preg_match($tagpattern, $element)) { + // html tag + $element = substr($element, 1, -1); + // get tag name + preg_match('/[\/]?([a-zA-Z0-9]*)/', $element, $tag); + $tagname = strtolower($tag[1]); + // check if we are inside a table header + if ($tagname == 'thead') { + if ($element{0} == '/') { + $thead = false; + } else { + $thead = true; + } + ++$elkey; + continue; + } + $dom[$key]['tag'] = true; + $dom[$key]['value'] = $tagname; + if ($element{0} == '/') { + // closing html tag + $dom[$key]['opening'] = false; + $dom[$key]['parent'] = end($level); + array_pop($level); + $dom[$key]['fontname'] = $dom[($dom[($dom[$key]['parent'])]['parent'])]['fontname']; + $dom[$key]['fontstyle'] = $dom[($dom[($dom[$key]['parent'])]['parent'])]['fontstyle']; + $dom[$key]['fontsize'] = $dom[($dom[($dom[$key]['parent'])]['parent'])]['fontsize']; + $dom[$key]['bgcolor'] = $dom[($dom[($dom[$key]['parent'])]['parent'])]['bgcolor']; + $dom[$key]['fgcolor'] = $dom[($dom[($dom[$key]['parent'])]['parent'])]['fgcolor']; + $dom[$key]['align'] = $dom[($dom[($dom[$key]['parent'])]['parent'])]['align']; + if (isset($dom[($dom[($dom[$key]['parent'])]['parent'])]['listtype'])) { + $dom[$key]['listtype'] = $dom[($dom[($dom[$key]['parent'])]['parent'])]['listtype']; + } + // set the number of columns in table tag + if (($dom[$key]['value'] == 'tr') AND (!isset($dom[($dom[($dom[$key]['parent'])]['parent'])]['cols']))) { + $dom[($dom[($dom[$key]['parent'])]['parent'])]['cols'] = $dom[($dom[$key]['parent'])]['cols']; + } + if (($dom[$key]['value'] == 'td') OR ($dom[$key]['value'] == 'th')) { + $dom[($dom[$key]['parent'])]['content'] = ''; + for ($i = ($dom[$key]['parent'] + 1); $i < $key; ++$i) { + $dom[($dom[$key]['parent'])]['content'] .= $a[$dom[$i]['elkey']]; + } + $key = $i; + } + // store header rows on a new table + if (($dom[$key]['value'] == 'tr') AND ($dom[($dom[$key]['parent'])]['thead'] == true)) { + if ($this->empty_string($dom[($dom[($dom[$key]['parent'])]['parent'])]['thead'])) { + $dom[($dom[($dom[$key]['parent'])]['parent'])]['thead'] = $a[$dom[($dom[($dom[$key]['parent'])]['parent'])]['elkey']]; + } + for ($i = $dom[$key]['parent']; $i <= $key; ++$i) { + $dom[($dom[($dom[$key]['parent'])]['parent'])]['thead'] .= $a[$dom[$i]['elkey']]; + } + } + if (($dom[$key]['value'] == 'table') AND (!$this->empty_string($dom[($dom[$key]['parent'])]['thead']))) { + $dom[($dom[$key]['parent'])]['thead'] .= ''; + } + } else { + // opening html tag + $dom[$key]['opening'] = true; + $dom[$key]['parent'] = end($level); + if (substr($element, -1, 1) != '/') { + // not self-closing tag + array_push($level, $key); + $dom[$key]['self'] = false; + } else { + $dom[$key]['self'] = true; + } + // copy some values from parent + $parentkey = 0; + if ($key > 0) { + $parentkey = $dom[$key]['parent']; + $dom[$key]['fontname'] = $dom[$parentkey]['fontname']; + $dom[$key]['fontstyle'] = $dom[$parentkey]['fontstyle']; + $dom[$key]['fontsize'] = $dom[$parentkey]['fontsize']; + $dom[$key]['bgcolor'] = $dom[$parentkey]['bgcolor']; + $dom[$key]['fgcolor'] = $dom[$parentkey]['fgcolor']; + $dom[$key]['align'] = $dom[$parentkey]['align']; + $dom[$key]['listtype'] = $dom[$parentkey]['listtype']; + } + // get attributes + preg_match_all('/([^=\s]*)=["]?([^"]*)["]?/', $element, $attr_array, PREG_PATTERN_ORDER); + $dom[$key]['attribute'] = array(); // reset attribute array + while (list($id, $name) = each($attr_array[1])) { + $dom[$key]['attribute'][strtolower($name)] = $attr_array[2][$id]; + } + // split style attributes + if (isset($dom[$key]['attribute']['style'])) { + // get style attributes + preg_match_all('/([^;:\s]*):([^;]*)/', $dom[$key]['attribute']['style'], $style_array, PREG_PATTERN_ORDER); + $dom[$key]['style'] = array(); // reset style attribute array + while (list($id, $name) = each($style_array[1])) { + $dom[$key]['style'][strtolower($name)] = trim($style_array[2][$id]); + } + // --- get some style attributes --- + if (isset($dom[$key]['style']['font-family'])) { + // font family + if (isset($dom[$key]['style']['font-family'])) { + $fontslist = explode(',', strtolower($dom[$key]['style']['font-family'])); + foreach ($fontslist as $font) { + $font = trim(strtolower($font)); + if (in_array($font, $this->fontlist) OR in_array($font, $this->fontkeys)) { + $dom[$key]['fontname'] = $font; + break; + } + } + } + } + // list-style-type + if (isset($dom[$key]['style']['list-style-type'])) { + $dom[$key]['listtype'] = trim(strtolower($dom[$key]['style']['list-style-type'])); + if ($dom[$key]['listtype'] == 'inherit') { + $dom[$key]['listtype'] = $dom[$parentkey]['listtype']; + } + } + // font size + if (isset($dom[$key]['style']['font-size'])) { + $fsize = trim($dom[$key]['style']['font-size']); + switch ($fsize) { + // absolute-size + case 'xx-small': { + $dom[$key]['fontsize'] = $dom[0]['fontsize'] - 4; + break; + } + case 'x-small': { + $dom[$key]['fontsize'] = $dom[0]['fontsize'] - 3; + break; + } + case 'small': { + $dom[$key]['fontsize'] = $dom[0]['fontsize'] - 2; + break; + } + case 'medium': { + $dom[$key]['fontsize'] = $dom[0]['fontsize']; + break; + } + case 'large': { + $dom[$key]['fontsize'] = $dom[0]['fontsize'] + 2; + break; + } + case 'x-large': { + $dom[$key]['fontsize'] = $dom[0]['fontsize'] + 4; + break; + } + case 'xx-large': { + $dom[$key]['fontsize'] = $dom[0]['fontsize'] + 6; + break; + } + // relative-size + case 'smaller': { + $dom[$key]['fontsize'] = $dom[$parentkey]['fontsize'] - 3; + break; + } + case 'larger': { + $dom[$key]['fontsize'] = $dom[$parentkey]['fontsize'] + 3; + break; + } + default: { + $dom[$key]['fontsize'] = $this->getHTMLUnitToUnits($fsize, $dom[$parentkey]['fontsize'], 'pt', true); + } + } + } + // font style + if (isset($dom[$key]['style']['font-weight']) AND (strtolower($dom[$key]['style']['font-weight']{0}) == 'b')) { + $dom[$key]['fontstyle'] .= 'B'; + } + if (isset($dom[$key]['style']['font-style']) AND (strtolower($dom[$key]['style']['font-style']{0}) == 'i')) { + $dom[$key]['fontstyle'] .= '"I'; + } + // font color + if (isset($dom[$key]['style']['color']) AND (!$this->empty_string($dom[$key]['style']['color']))) { + $dom[$key]['fgcolor'] = $this->convertHTMLColorToDec($dom[$key]['style']['color']); + } + // background color + if (isset($dom[$key]['style']['background-color']) AND (!$this->empty_string($dom[$key]['style']['background-color']))) { + $dom[$key]['bgcolor'] = $this->convertHTMLColorToDec($dom[$key]['style']['background-color']); + } + // text-decoration + if (isset($dom[$key]['style']['text-decoration'])) { + $decors = explode(' ', strtolower($dom[$key]['style']['text-decoration'])); + foreach ($decors as $dec) { + $dec = trim($dec); + if (!$this->empty_string($dec)) { + if ($dec{0} == 'u') { + $dom[$key]['fontstyle'] .= 'U'; + } elseif ($dec{0} == 'l') { + $dom[$key]['fontstyle'] .= 'D'; + } + } + } + } + // check for width attribute + if (isset($dom[$key]['style']['width'])) { + $dom[$key]['width'] = $dom[$key]['style']['width']; + } + // check for height attribute + if (isset($dom[$key]['style']['height'])) { + $dom[$key]['height'] = $dom[$key]['style']['height']; + } + // check for text alignment + if (isset($dom[$key]['style']['text-align'])) { + $dom[$key]['align'] = strtoupper($dom[$key]['style']['text-align']{0}); + } + // check for border attribute + if (isset($dom[$key]['style']['border'])) { + $dom[$key]['attribute']['border'] = $dom[$key]['style']['border']; + } + } + // check for font tag + if ($dom[$key]['value'] == 'font') { + // font family + if (isset($dom[$key]['attribute']['face'])) { + $fontslist = explode(',', strtolower($dom[$key]['attribute']['face'])); + foreach ($fontslist as $font) { + $font = trim(strtolower($font)); + if (in_array($font, $this->fontlist) OR in_array($font, $this->fontkeys)) { + $dom[$key]['fontname'] = $font; + break; + } + } + } + // font size + if (isset($dom[$key]['attribute']['size'])) { + if ($key > 0) { + if ($dom[$key]['attribute']['size']{0} == '+') { + $dom[$key]['fontsize'] = $dom[($dom[$key]['parent'])]['fontsize'] + intval(substr($dom[$key]['attribute']['size'], 1)); + } elseif ($dom[$key]['attribute']['size']{0} == '-') { + $dom[$key]['fontsize'] = $dom[($dom[$key]['parent'])]['fontsize'] - intval(substr($dom[$key]['attribute']['size'], 1)); + } else { + $dom[$key]['fontsize'] = intval($dom[$key]['attribute']['size']); + } + } else { + $dom[$key]['fontsize'] = intval($dom[$key]['attribute']['size']); + } + } + } + // force natural alignment for lists + if ((($dom[$key]['value'] == 'ul') OR ($dom[$key]['value'] == 'ol') OR ($dom[$key]['value'] == 'dl')) + AND (!isset($dom[$key]['align']) OR $this->empty_string($dom[$key]['align']) OR ($dom[$key]['align'] != 'J'))) { + if ($this->rtl) { + $dom[$key]['align'] = 'R'; + } else { + $dom[$key]['align'] = 'L'; + } + } + if (($dom[$key]['value'] == 'small') OR ($dom[$key]['value'] == 'sup') OR ($dom[$key]['value'] == 'sub')) { + $dom[$key]['fontsize'] = $dom[$key]['fontsize'] * K_SMALL_RATIO; + } + if (($dom[$key]['value'] == 'strong') OR ($dom[$key]['value'] == 'b')) { + $dom[$key]['fontstyle'] .= 'B'; + } + if (($dom[$key]['value'] == 'em') OR ($dom[$key]['value'] == 'i')) { + $dom[$key]['fontstyle'] .= 'I'; + } + if ($dom[$key]['value'] == 'u') { + $dom[$key]['fontstyle'] .= 'U'; + } + if ($dom[$key]['value'] == 'del') { + $dom[$key]['fontstyle'] .= 'D'; + } + if (($dom[$key]['value'] == 'pre') OR ($dom[$key]['value'] == 'tt')) { + $dom[$key]['fontname'] = $this->default_monospaced_font; + } + if (($dom[$key]['value']{0} == 'h') AND (intval($dom[$key]['value']{1}) > 0) AND (intval($dom[$key]['value']{1}) < 7)) { + $headsize = (4 - intval($dom[$key]['value']{1})) * 2; + $dom[$key]['fontsize'] = $dom[0]['fontsize'] + $headsize; + $dom[$key]['fontstyle'] .= 'B'; + } + if (($dom[$key]['value'] == 'table')) { + $dom[$key]['rows'] = 0; // number of rows + $dom[$key]['trids'] = array(); // IDs of TR elements + $dom[$key]['thead'] = ''; // table header rows + } + if (($dom[$key]['value'] == 'tr')) { + $dom[$key]['cols'] = 0; + // store the number of rows on table element + ++$dom[($dom[$key]['parent'])]['rows']; + // store the TR elements IDs on table element + array_push($dom[($dom[$key]['parent'])]['trids'], $key); + if ($thead) { + $dom[$key]['thead'] = true; + } else { + $dom[$key]['thead'] = false; + } + } + if (($dom[$key]['value'] == 'th') OR ($dom[$key]['value'] == 'td')) { + if (isset($dom[$key]['attribute']['colspan'])) { + $colspan = intval($dom[$key]['attribute']['colspan']); + } else { + $colspan = 1; + } + $dom[$key]['attribute']['colspan'] = $colspan; + $dom[($dom[$key]['parent'])]['cols'] += $colspan; + } + // set foreground color attribute + if (isset($dom[$key]['attribute']['color']) AND (!$this->empty_string($dom[$key]['attribute']['color']))) { + $dom[$key]['fgcolor'] = $this->convertHTMLColorToDec($dom[$key]['attribute']['color']); + } + // set background color attribute + if (isset($dom[$key]['attribute']['bgcolor']) AND (!$this->empty_string($dom[$key]['attribute']['bgcolor']))) { + $dom[$key]['bgcolor'] = $this->convertHTMLColorToDec($dom[$key]['attribute']['bgcolor']); + } + // check for width attribute + if (isset($dom[$key]['attribute']['width'])) { + $dom[$key]['width'] = $dom[$key]['attribute']['width']; + } + // check for height attribute + if (isset($dom[$key]['attribute']['height'])) { + $dom[$key]['height'] = $dom[$key]['attribute']['height']; + } + // check for text alignment + if (isset($dom[$key]['attribute']['align']) AND (!$this->empty_string($dom[$key]['attribute']['align'])) AND ($dom[$key]['value'] !== 'img')) { + $dom[$key]['align'] = strtoupper($dom[$key]['attribute']['align']{0}); + } + } // end opening tag + } else { + // text + $dom[$key]['tag'] = false; + $dom[$key]['value'] = stripslashes($this->unhtmlentities($element)); + $dom[$key]['parent'] = end($level); + } + ++$elkey; + ++$key; + } + return $dom; + } + + /** + * Allows to preserve some HTML formatting (limited support).
              + * IMPORTANT: The HTML must be well formatted - try to clean-up it using an application like HTML-Tidy before submitting. + * Supported tags are: a, b, blockquote, br, dd, del, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, img, li, ol, p, pre, small, span, strong, sub, sup, table, tcpdf, td, th, thead, tr, tt, u, ul + * @param string $html text to display + * @param boolean $ln if true add a new line after text (default = true) + * @param int $fill Indicates if the background must be painted (true) or transparent (false). + * @param boolean $reseth if true reset the last cell height (default false). + * @param boolean $cell if true add the default cMargin space to each Write (default false). + * @param string $align Allows to center or align the text. Possible values are:
              • L : left align
              • C : center
              • R : right align
              • '' : empty string : left for LTR or right for RTL
              + * @access public + */ + public function writeHTML($html, $ln=true, $fill=false, $reseth=false, $cell=false, $align='') { + $gvars = $this->getGraphicVars(); + // store current values + $prevPage = $this->page; + $prevlMargin = $this->lMargin; + $prevrMargin = $this->rMargin; + $curfontname = $this->FontFamily; + $curfontstyle = $this->FontStyle; + $curfontsize = $this->FontSizePt; + $this->newline = true; + $minstartliney = $this->y; + $yshift = 0; + $startlinepage = $this->page; + $newline = true; + $loop = 0; + $curpos = 0; + $blocktags = array('blockquote','br','dd','div','dt','h1','h2','h3','h4','h5','h6','hr','li','ol','p','ul','tcpdf'); + $this->premode = false; + if (isset($this->PageAnnots[$this->page])) { + $pask = count($this->PageAnnots[$this->page]); + } else { + $pask = 0; + } + if (isset($this->footerlen[$this->page])) { + $this->footerpos[$this->page] = $this->pagelen[$this->page] - $this->footerlen[$this->page]; + } else { + $this->footerpos[$this->page] = $this->pagelen[$this->page]; + } + $startlinepos = $this->footerpos[$this->page]; + $lalign = $align; + $plalign = $align; + if ($this->rtl) { + $w = $this->x - $this->lMargin; + } else { + $w = $this->w - $this->rMargin - $this->x; + } + $w -= (2 * $this->cMargin); + if ($cell) { + if ($this->rtl) { + $this->x -= $this->cMargin; + } else { + $this->x += $this->cMargin; + } + } + if ($this->customlistindent >= 0) { + $this->listindent = $this->customlistindent; + } else { + $this->listindent = $this->GetStringWidth('0000'); + } + $this->listnum = 0; + if (($this->empty_string($this->lasth)) OR ($reseth)) { + //set row height + $this->lasth = $this->FontSize * $this->cell_height_ratio; + } + $dom = $this->getHtmlDomArray($html); + $maxel = count($dom); + $key = 0; + while ($key < $maxel) { + if ($dom[$key]['tag'] OR ($key == 0)) { + if ((($dom[$key]['value'] == 'table') OR ($dom[$key]['value'] == 'tr')) AND (isset($dom[$key]['align']))) { + $dom[$key]['align'] = ($this->rtl) ? 'R' : 'L'; + } + // vertically align image in line + if ((!$this->newline) + AND ($dom[$key]['value'] == 'img') + AND (isset($dom[$key]['attribute']['height'])) + AND ($dom[$key]['attribute']['height'] > 0)) { + // get image height + $imgh = $this->getHTMLUnitToUnits($dom[$key]['attribute']['height'], $this->lasth, 'px'); + if (!$this->InFooter) { + // check for page break + $this->checkPageBreak($imgh); + } + if ($this->page > $startlinepage) { + // fix lines splitted over two pages + if (isset($this->footerlen[$startlinepage])) { + $curpos = $this->pagelen[$startlinepage] - $this->footerlen[$startlinepage]; + } + // line to be moved one page forward + $pagebuff = $this->getPageBuffer($startlinepage); + $linebeg = substr($pagebuff, $startlinepos, ($curpos - $startlinepos)); + $tstart = substr($pagebuff, 0, $startlinepos); + $tend = substr($this->getPageBuffer($startlinepage), $curpos); + // remove line start from previous page + $this->setPageBuffer($startlinepage, $tstart.''.$tend); + $pagebuff = $this->getPageBuffer($this->page); + $tstart = substr($pagebuff, 0, $this->intmrk[$this->page]); + $tend = substr($pagebuff, $this->intmrk[$this->page]); + // add line start to current page + $yshift = $minstartliney - $this->y; + $try = sprintf('1 0 0 1 0 %.3F cm', ($yshift * $this->k)); + $this->setPageBuffer($this->page, $tstart."\nq\n".$try."\n".$linebeg."\nQ\n".$tend); + // shift the annotations and links + if (isset($this->PageAnnots[$startlinepage])) { + foreach ($this->PageAnnots[$startlinepage] as $pak => $pac) { + if ($pak >= $pask) { + $this->PageAnnots[$this->page][] = $pac; + unset($this->PageAnnots[$startlinepage][$pak]); + $npak = count($this->PageAnnots[$this->page]) - 1; + $this->PageAnnots[$this->page][$npak]['y'] -= $yshift; + } + } + } + $startlinepos = $this->intmrk[$this->page]; + $startlinepage = $this->page; + $startliney = $this->y; + } + + $this->y += (($curfontsize / $this->k) - $imgh); + $minstartliney = min($this->y, $minstartliney); + + } elseif (isset($dom[$key]['fontname']) OR isset($dom[$key]['fontstyle']) OR isset($dom[$key]['fontsize'])) { + // account for different font size + $pfontname = $curfontname; + $pfontstyle = $curfontstyle; + $pfontsize = $curfontsize; + $fontname = isset($dom[$key]['fontname']) ? $dom[$key]['fontname'] : $curfontname; + $fontstyle = isset($dom[$key]['fontstyle']) ? $dom[$key]['fontstyle'] : $curfontstyle; + $fontsize = isset($dom[$key]['fontsize']) ? $dom[$key]['fontsize'] : $curfontsize; + if (($fontname != $curfontname) OR ($fontstyle != $curfontstyle) OR ($fontsize != $curfontsize)) { + $this->SetFont($fontname, $fontstyle, $fontsize); + $this->lasth = $this->FontSize * $this->cell_height_ratio; + if (is_numeric($fontsize) AND ($fontsize > 0) + AND is_numeric($curfontsize) AND ($curfontsize > 0) + AND ($fontsize != $curfontsize) AND (!$this->newline) + AND ($key < ($maxel - 1)) + ) { + if ((!$this->newline) AND ($this->page > $startlinepage)) { + // fix lines splitted over two pages + if (isset($this->footerlen[$startlinepage])) { + $curpos = $this->pagelen[$startlinepage] - $this->footerlen[$startlinepage]; + } + // line to be moved one page forward + $pagebuff = $this->getPageBuffer($startlinepage); + $linebeg = substr($pagebuff, $startlinepos, ($curpos - $startlinepos)); + $tstart = substr($pagebuff, 0, $startlinepos); + $tend = substr($this->getPageBuffer($startlinepage), $curpos); + // remove line start from previous page + $this->setPageBuffer($startlinepage, $tstart.''.$tend); + $pagebuff = $this->getPageBuffer($this->page); + $tstart = substr($pagebuff, 0, $this->intmrk[$this->page]); + $tend = substr($pagebuff, $this->intmrk[$this->page]); + // add line start to current page + $yshift = $minstartliney - $this->y; + $try = sprintf('1 0 0 1 0 %.3F cm', ($yshift * $this->k)); + $this->setPageBuffer($this->page, $tstart."\nq\n".$try."\n".$linebeg."\nQ\n".$tend); + // shift the annotations and links + if (isset($this->PageAnnots[$startlinepage])) { + foreach ($this->PageAnnots[$startlinepage] as $pak => $pac) { + if ($pak >= $pask) { + $this->PageAnnots[$this->page][] = $pac; + unset($this->PageAnnots[$startlinepage][$pak]); + $npak = count($this->PageAnnots[$this->page]) - 1; + $this->PageAnnots[$this->page][$npak]['y'] -= $yshift; + } + } + } + } + $this->y += (($curfontsize - $fontsize) / $this->k); + $minstartliney = min($this->y, $minstartliney); + } + $curfontname = $fontname; + $curfontstyle = $fontstyle; + $curfontsize = $fontsize; + } + } + if (($plalign == 'J') AND (in_array($dom[$key]['value'], $blocktags))) { + $plalign = ''; + } + // get current position on page buffer + $curpos = $this->pagelen[$startlinepage]; + if (isset($dom[$key]['bgcolor']) AND ($dom[$key]['bgcolor'] !== false)) { + $this->SetFillColorArray($dom[$key]['bgcolor']); + $wfill = true; + } else { + $wfill = $fill | false; + } + if (isset($dom[$key]['fgcolor']) AND ($dom[$key]['fgcolor'] !== false)) { + $this->SetTextColorArray($dom[$key]['fgcolor']); + } + if (isset($dom[$key]['align'])) { + $lalign = $dom[$key]['align']; + } + if ($this->empty_string($lalign)) { + $lalign = $align; + } + } + // align lines + if ($this->newline AND (strlen($dom[$key]['value']) > 0) AND ($dom[$key]['value'] != 'td') AND ($dom[$key]['value'] != 'th')) { + $newline = true; + // we are at the beginning of a new line + if (isset($startlinex)) { + $yshift = $minstartliney - $startliney; + if (($yshift > 0) OR ($this->page > $startlinepage)) { + $yshift = 0; + } + if ((isset($plalign) AND ((($plalign == 'C') OR ($plalign == 'J') OR (($plalign == 'R') AND (!$this->rtl)) OR (($plalign == 'L') AND ($this->rtl))))) OR ($yshift < 0)) { + // the last line must be shifted to be aligned as requested + $linew = abs($this->endlinex - $startlinex); + $pstart = substr($this->getPageBuffer($startlinepage), 0, $startlinepos); + if (isset($opentagpos) AND isset($this->footerlen[$startlinepage]) AND (!$this->InFooter)) { + $this->footerpos[$startlinepage] = $this->pagelen[$startlinepage] - $this->footerlen[$startlinepage]; + $midpos = min($opentagpos, $this->footerpos[$startlinepage]); + } elseif (isset($opentagpos)) { + $midpos = $opentagpos; + } elseif (isset($this->footerlen[$startlinepage]) AND (!$this->InFooter)) { + $this->footerpos[$startlinepage] = $this->pagelen[$startlinepage] - $this->footerlen[$startlinepage]; + $midpos = $this->footerpos[$startlinepage]; + } else { + $midpos = 0; + } + if ($midpos > 0) { + $pmid = substr($this->getPageBuffer($startlinepage), $startlinepos, ($midpos - $startlinepos)); + $pend = substr($this->getPageBuffer($startlinepage), $midpos); + } else { + $pmid = substr($this->getPageBuffer($startlinepage), $startlinepos); + $pend = ''; + } + // calculate shifting amount + $tw = $w; + if ($this->lMargin != $prevlMargin) { + $tw += ($prevlMargin - $this->lMargin); + } + if ($this->rMargin != $prevrMargin) { + $tw += ($prevrMargin - $this->rMargin); + } + $mdiff = abs($tw - $linew); + $t_x = 0; + if ($plalign == 'C') { + if ($this->rtl) { + $t_x = -($mdiff / 2); + } else { + $t_x = ($mdiff / 2); + } + } elseif (($plalign == 'R') AND (!$this->rtl)) { + // right alignment on LTR document + $t_x = $mdiff; + } elseif (($plalign == 'L') AND ($this->rtl)) { + // left alignment on RTL document + $t_x = -$mdiff; + } elseif (($plalign == 'J') AND ($plalign == $lalign)) { + // Justification + if ($this->rtl OR $this->tmprtl) { + $t_x = $this->lMargin - $this->endlinex; + } + $no = 0; + $ns = 0; + $pmidtemp = $pmid; + // escape special characters + $pmidtemp = preg_replace('/[\\\][\(]/x', '\\#!#OP#!#', $pmidtemp); + $pmidtemp = preg_replace('/[\\\][\)]/x', '\\#!#CP#!#', $pmidtemp); + // search spaces + if (preg_match_all('/\[\(([^\)]*)\)\]/x', $pmidtemp, $lnstring, PREG_PATTERN_ORDER)) { + $maxkk = count($lnstring[1]) - 1; + for ($kk=0; $kk <= $maxkk; ++$kk) { + // restore special characters + $lnstring[1][$kk] = str_replace('#!#OP#!#', '(', $lnstring[1][$kk]); + $lnstring[1][$kk] = str_replace('#!#CP#!#', ')', $lnstring[1][$kk]); + if ($kk == $maxkk) { + if ($this->rtl OR $this->tmprtl) { + $tvalue = ltrim($lnstring[1][$kk]); + } else { + $tvalue = rtrim($lnstring[1][$kk]); + } + } else { + $tvalue = $lnstring[1][$kk]; + } + // count spaces on line + $no += substr_count($lnstring[1][$kk], chr(32)); + $ns += substr_count($tvalue, chr(32)); + } + if ($this->rtl OR $this->tmprtl) { + $t_x = $this->lMargin - $this->endlinex - (($no - $ns - 1) * $this->GetStringWidth(chr(32))); + } + // calculate additional space to add to each space + $spacewidth = (($tw - $linew + (($no - $ns) * $this->GetStringWidth(chr(32)))) / ($ns?$ns:1)) * $this->k; + $spacewidthu = ($tw - $linew + ($no * $this->GetStringWidth(chr(32)))) / ($ns?$ns:1) / $this->FontSize / $this->k; + $nsmax = $ns; + $ns = 0; + reset($lnstring); + $offset = 0; + $strcount = 0; + $prev_epsposbeg = 0; + global $spacew; + while (preg_match('/([0-9\.\+\-]*)[\s](Td|cm|m|l|c|re)[\s]/x', $pmid, $strpiece, PREG_OFFSET_CAPTURE, $offset) == 1) { + if ($this->rtl OR $this->tmprtl) { + $spacew = ($spacewidth * ($nsmax - $ns)); + } else { + $spacew = ($spacewidth * $ns); + } + $offset = $strpiece[2][1] + strlen($strpiece[2][0]); + $epsposbeg = strpos($pmid, 'q'.$this->epsmarker, $offset); + $epsposend = strpos($pmid, $this->epsmarker.'Q', $offset) + strlen($this->epsmarker.'Q'); + if ((($epsposbeg > 0) AND ($epsposend > 0) AND ($offset > $epsposbeg) AND ($offset < $epsposend)) + OR (($epsposbeg === false) AND ($epsposend > 0) AND ($offset < $epsposend))) { + // shift EPS images + $trx = sprintf('1 0 0 1 %.3F 0 cm', $spacew); + $epsposbeg = strpos($pmid, 'q'.$this->epsmarker, ($prev_epsposbeg - 6)); + $pmid_b = substr($pmid, 0, $epsposbeg); + $pmid_m = substr($pmid, $epsposbeg, ($epsposend - $epsposbeg)); + $pmid_e = substr($pmid, $epsposend); + $pmid = $pmid_b."\nq\n".$trx."\n".$pmid_m."\nQ\n".$pmid_e; + $offset = $epsposend; + continue; + } + $prev_epsposbeg = $epsposbeg; + $currentxpos = 0; + // shift blocks of code + switch ($strpiece[2][0]) { + case 'Td': + case 'cm': + case 'm': + case 'l': { + // get current X position + preg_match('/([0-9\.\+\-]*)[\s]('.$strpiece[1][0].')[\s]('.$strpiece[2][0].')([\s]*)/x', $pmid, $xmatches); + $currentxpos = $xmatches[1]; + if (($strcount <= $maxkk) AND ($strpiece[2][0] == 'Td')) { + if ($strcount == $maxkk) { + if ($this->rtl OR $this->tmprtl) { + $tvalue = $lnstring[1][$strcount]; + } else { + $tvalue = rtrim($lnstring[1][$strcount]); + } + } else { + $tvalue = $lnstring[1][$strcount]; + } + $ns += substr_count($tvalue, chr(32)); + ++$strcount; + } + if ($this->rtl OR $this->tmprtl) { + $spacew = ($spacewidth * ($nsmax - $ns)); + } + // justify block + $pmid = preg_replace_callback('/([0-9\.\+\-]*)[\s]('.$strpiece[1][0].')[\s]('.$strpiece[2][0].')([\s]*)/x', + create_function('$matches', 'global $spacew; + $newx = sprintf("%.2F",(floatval($matches[1]) + $spacew)); + return "".$newx." ".$matches[2]." x*#!#*x".$matches[3].$matches[4];'), $pmid, 1); + break; + } + case 're': { + // get current X position + preg_match('/([0-9\.\+\-]*)[\s]([0-9\.\+\-]*)[\s]([0-9\.\+\-]*)[\s]('.$strpiece[1][0].')[\s]('.$strpiece[2][0].')([\s]*)/x', $pmid, $xmatches); + $currentxpos = $xmatches[1]; + // justify block + $pmid = preg_replace_callback('/([0-9\.\+\-]*)[\s]([0-9\.\+\-]*)[\s]([0-9\.\+\-]*)[\s]('.$strpiece[1][0].')[\s]('.$strpiece[2][0].')([\s]*)/x', + create_function('$matches', 'global $spacew; + $newx = sprintf("%.2F",(floatval($matches[1]) + $spacew)); + return "".$newx." ".$matches[2]." ".$matches[3]." ".$matches[4]." x*#!#*x".$matches[5].$matches[6];'), $pmid, 1); + break; + } + case 'c': { + // get current X position + preg_match('/([0-9\.\+\-]*)[\s]([0-9\.\+\-]*)[\s]([0-9\.\+\-]*)[\s]([0-9\.\+\-]*)[\s]([0-9\.\+\-]*)[\s]('.$strpiece[1][0].')[\s]('.$strpiece[2][0].')([\s]*)/x', $pmid, $xmatches); + $currentxpos = $xmatches[1]; + // justify block + $pmid = preg_replace_callback('/([0-9\.\+\-]*)[\s]([0-9\.\+\-]*)[\s]([0-9\.\+\-]*)[\s]([0-9\.\+\-]*)[\s]([0-9\.\+\-]*)[\s]('.$strpiece[1][0].')[\s]('.$strpiece[2][0].')([\s]*)/x', + create_function('$matches', 'global $spacew; + $newx1 = sprintf("%.3F",(floatval($matches[1]) + $spacew)); + $newx2 = sprintf("%.3F",(floatval($matches[3]) + $spacew)); + $newx3 = sprintf("%.3F",(floatval($matches[5]) + $spacew)); + return "".$newx1." ".$matches[2]." ".$newx2." ".$matches[4]." ".$newx3." ".$matches[6]." x*#!#*x".$matches[7].$matches[8];'), $pmid, 1); + break; + } + } + // shift the annotations and links + if (isset($this->PageAnnots[$this->page])) { + foreach ($this->PageAnnots[$this->page] as $pak => $pac) { + if (($pac['y'] >= $minstartliney) AND (($pac['x'] * $this->k) >= ($currentxpos - $this->feps)) AND (($pac['x'] * $this->k) <= ($currentxpos + $this->feps))) { + $this->PageAnnots[$this->page][$pak]['x'] += ($spacew / $this->k); + $this->PageAnnots[$this->page][$pak]['w'] += (($spacewidth * $pac['numspaces']) / $this->k); + break; + } + } + } + } // end of while + // remove markers + $pmid = str_replace('x*#!#*x', '', $pmid); + if (($this->CurrentFont['type'] == 'TrueTypeUnicode') OR ($this->CurrentFont['type'] == 'cidfont0')) { + // multibyte characters + $spacew = $spacewidthu; + $pmidtemp = $pmid; + // escape special characters + $pmidtemp = preg_replace('/[\\\][\(]/x', '\\#!#OP#!#', $pmidtemp); + $pmidtemp = preg_replace('/[\\\][\)]/x', '\\#!#CP#!#', $pmidtemp); + $pmid = preg_replace_callback("/\[\(([^\)]*)\)\]/x", + create_function('$matches', 'global $spacew; + $matches[1] = str_replace("#!#OP#!#", "(", $matches[1]); + $matches[1] = str_replace("#!#CP#!#", ")", $matches[1]); + return "[(".str_replace(chr(0).chr(32), ") ".(-2830 * $spacew)." (", $matches[1]).")]";'), $pmidtemp); + $this->setPageBuffer($startlinepage, $pstart."\n".$pmid."\n".$pend); + $endlinepos = strlen($pstart."\n".$pmid."\n"); + } else { + // non-unicode (single-byte characters) + $rs = sprintf("%.3F Tw", $spacewidth); + $pmid = preg_replace("/\[\(/x", $rs.' [(', $pmid); + $this->setPageBuffer($startlinepage, $pstart."\n".$pmid."\nBT 0 Tw ET\n".$pend); + $endlinepos = strlen($pstart."\n".$pmid."\nBT 0 Tw ET\n"); + } + } + } // end of J + if (($t_x != 0) OR ($yshift < 0)) { + // shift the line + $trx = sprintf('1 0 0 1 %.3F %.3F cm', ($t_x * $this->k), ($yshift * $this->k)); + $this->setPageBuffer($startlinepage, $pstart."\nq\n".$trx."\n".$pmid."\nQ\n".$pend); + $endlinepos = strlen($pstart."\nq\n".$trx."\n".$pmid."\nQ\n"); + // shift the annotations and links + if (isset($this->PageAnnots[$this->page])) { + foreach ($this->PageAnnots[$this->page] as $pak => $pac) { + if ($pak >= $pask) { + $this->PageAnnots[$this->page][$pak]['x'] += $t_x; + $this->PageAnnots[$this->page][$pak]['y'] -= $yshift; + } + } + } + $this->y -= $yshift; + } + } + } + $this->newline = false; + $pbrk = $this->checkPageBreak($this->lasth); + $this->SetFont($fontname, $fontstyle, $fontsize); + if ($wfill) { + $this->SetFillColorArray($this->bgcolor); + } + $startlinex = $this->x; + $startliney = $this->y; + $minstartliney = $this->y; + $startlinepage = $this->page; + if (isset($endlinepos) AND (!$pbrk)) { + $startlinepos = $endlinepos; + unset($endlinepos); + } else { + if (isset($this->footerlen[$this->page])) { + $this->footerpos[$this->page] = $this->pagelen[$this->page] - $this->footerlen[$this->page]; + } else { + $this->footerpos[$this->page] = $this->pagelen[$this->page]; + } + $startlinepos = $this->footerpos[$this->page]; + } + $plalign = $lalign; + if (isset($this->PageAnnots[$this->page])) { + $pask = count($this->PageAnnots[$this->page]); + } else { + $pask = 0; + } + } + if (isset($opentagpos)) { + unset($opentagpos); + } + if ($dom[$key]['tag']) { + if ($dom[$key]['opening']) { + if ($dom[$key]['value'] == 'table') { + if ($this->rtl) { + $wtmp = $this->x - $this->lMargin; + } else { + $wtmp = $this->w - $this->rMargin - $this->x; + } + $wtmp -= (2 * $this->cMargin); + // calculate cell width + if (isset($dom[$key]['width'])) { + $table_width = $this->getHTMLUnitToUnits($dom[$key]['width'], $wtmp, 'px'); + } else { + $table_width = $wtmp; + } + } + // table content is handled in a special way + if (($dom[$key]['value'] == 'td') OR ($dom[$key]['value'] == 'th')) { + $trid = $dom[$key]['parent']; + $table_el = $dom[$trid]['parent']; + if (!isset($dom[$table_el]['cols'])) { + $dom[$table_el]['cols'] = $trid['cols']; + } + $oldmargin = $this->cMargin; + if (isset($dom[($dom[$trid]['parent'])]['attribute']['cellpadding'])) { + $currentcmargin = $this->getHTMLUnitToUnits($dom[($dom[$trid]['parent'])]['attribute']['cellpadding'], 1, 'px'); + } else { + $currentcmargin = 0; + } + $this->cMargin = $currentcmargin; + if (isset($dom[($dom[$trid]['parent'])]['attribute']['cellspacing'])) { + $cellspacing = $this->getHTMLUnitToUnits($dom[($dom[$trid]['parent'])]['attribute']['cellspacing'], 1, 'px'); + } else { + $cellspacing = 0; + } + if ($this->rtl) { + $cellspacingx = -$cellspacing; + } else { + $cellspacingx = $cellspacing; + } + $colspan = $dom[$key]['attribute']['colspan']; + $wtmp = ($colspan * ($table_width / $dom[$table_el]['cols'])); + if (isset($dom[$key]['width'])) { + $cellw = $this->getHTMLUnitToUnits($dom[$key]['width'], $wtmp, 'px'); + } else { + $cellw = $wtmp; + } + if (isset($dom[$key]['height'])) { + // minimum cell height + $cellh = $this->getHTMLUnitToUnits($dom[$key]['height'], 0, 'px'); + } else { + $cellh = 0; + } + $cellw -= $cellspacing; + if (isset($dom[$key]['content'])) { + $cell_content = $dom[$key]['content']; + } else { + $cell_content = ' '; + } + $tagtype = $dom[$key]['value']; + $parentid = $key; + while (($key < $maxel) AND (!(($dom[$key]['tag']) AND (!$dom[$key]['opening']) AND ($dom[$key]['value'] == $tagtype) AND ($dom[$key]['parent'] == $parentid)))) { + // move $key index forward + ++$key; + } + if (!isset($dom[$trid]['startpage'])) { + $dom[$trid]['startpage'] = $this->page; + } else { + $this->setPage($dom[$trid]['startpage']); + } + if (!isset($dom[$trid]['starty'])) { + $dom[$trid]['starty'] = $this->y; + } else { + $this->y = $dom[$trid]['starty']; + } + if (!isset($dom[$trid]['startx'])) { + $dom[$trid]['startx'] = $this->x; + } + $this->x += ($cellspacingx / 2); + if (isset($dom[$parentid]['attribute']['rowspan'])) { + $rowspan = intval($dom[$parentid]['attribute']['rowspan']); + } else { + $rowspan = 1; + } + // skip row-spanned cells started on the previous rows + if (isset($dom[$table_el]['rowspans'])) { + $rsk = 0; + $rskmax = count($dom[$table_el]['rowspans']); + while ($rsk < $rskmax) { + $trwsp = $dom[$table_el]['rowspans'][$rsk]; + $rsstartx = $trwsp['startx']; + $rsendx = $trwsp['endx']; + // account for margin changes + if ($trwsp['startpage'] < $this->page) { + if (($this->rtl) AND ($this->pagedim[$this->page]['orm'] != $this->pagedim[$trwsp['startpage']]['orm'])) { + $dl = ($this->pagedim[$this->page]['orm'] - $this->pagedim[$trwsp['startpage']]['orm']); + $rsstartx -= $dl; + $rsendx -= $dl; + } elseif ((!$this->rtl) AND ($this->pagedim[$this->page]['olm'] != $this->pagedim[$trwsp['startpage']]['olm'])) { + $dl = ($this->pagedim[$this->page]['olm'] - $this->pagedim[$trwsp['startpage']]['olm']); + $rsstartx += $dl; + $rsendx += $dl; + } + } + if (($trwsp['rowspan'] > 0) + AND ($rsstartx > ($this->x - $cellspacing - $currentcmargin - $this->feps)) + AND ($rsstartx < ($this->x + $cellspacing + $currentcmargin + $this->feps)) + AND (($trwsp['starty'] < ($this->y - $this->feps)) OR ($trwsp['startpage'] < $this->page))) { + // set the starting X position of the current cell + $this->x = $rsendx + $cellspacingx; + if (($trwsp['rowspan'] == 1) + AND (isset($dom[$trid]['endy'])) + AND (isset($dom[$trid]['endpage'])) + AND ($trwsp['endpage'] == $dom[$trid]['endpage'])) { + // set ending Y position for row + $dom[$table_el]['rowspans'][$rsk]['endy'] = max($dom[$trid]['endy'], $trwsp['endy']); + $dom[$trid]['endy'] = $dom[$table_el]['rowspans'][$rsk]['endy']; + } + $rsk = 0; + } else { + ++$rsk; + } + } + } + // add rowspan information to table element + if ($rowspan > 1) { + if (isset($this->footerlen[$this->page])) { + $this->footerpos[$this->page] = $this->pagelen[$this->page] - $this->footerlen[$this->page]; + } else { + $this->footerpos[$this->page] = $this->pagelen[$this->page]; + } + $trintmrkpos = $this->footerpos[$this->page]; + $trsid = array_push($dom[$table_el]['rowspans'], array('trid' => $trid, 'rowspan' => $rowspan, 'mrowspan' => $rowspan, 'colspan' => $colspan, 'startpage' => $this->page, 'startx' => $this->x, 'starty' => $this->y, 'intmrkpos' => $trintmrkpos)); + } + $cellid = array_push($dom[$trid]['cellpos'], array('startx' => $this->x)); + if ($rowspan > 1) { + $dom[$trid]['cellpos'][($cellid - 1)]['rowspanid'] = ($trsid - 1); + } + // push background colors + if (isset($dom[$parentid]['bgcolor']) AND ($dom[$parentid]['bgcolor'] !== false)) { + $dom[$trid]['cellpos'][($cellid - 1)]['bgcolor'] = $dom[$parentid]['bgcolor']; + } + $prevLastH = $this->lasth; + // ****** write the cell content ****** + $this->MultiCell($cellw, $cellh, $cell_content, false, $lalign, false, 2, '', '', true, 0, true); + $this->lasth = $prevLastH; + $this->cMargin = $oldmargin; + $dom[$trid]['cellpos'][($cellid - 1)]['endx'] = $this->x; + // update the end of row position + if ($rowspan <= 1) { + if (isset($dom[$trid]['endy'])) { + if ($this->page == $dom[$trid]['endpage']) { + $dom[$trid]['endy'] = max($this->y, $dom[$trid]['endy']); + } elseif ($this->page > $dom[$trid]['endpage']) { + $dom[$trid]['endy'] = $this->y; + } + } else { + $dom[$trid]['endy'] = $this->y; + } + if (isset($dom[$trid]['endpage'])) { + $dom[$trid]['endpage'] = max($this->page, $dom[$trid]['endpage']); + } else { + $dom[$trid]['endpage'] = $this->page; + } + } else { + // account for row-spanned cells + $dom[$table_el]['rowspans'][($trsid - 1)]['endx'] = $this->x; + $dom[$table_el]['rowspans'][($trsid - 1)]['endy'] = $this->y; + $dom[$table_el]['rowspans'][($trsid - 1)]['endpage'] = $this->page; + } + if (isset($dom[$table_el]['rowspans'])) { + // update endy and endpage on rowspanned cells + foreach ($dom[$table_el]['rowspans'] as $k => $trwsp) { + if ($trwsp['rowspan'] > 0) { + if (isset($dom[$trid]['endpage'])) { + if ($trwsp['endpage'] == $dom[$trid]['endpage']) { + $dom[$table_el]['rowspans'][$k]['endy'] = max($dom[$trid]['endy'], $trwsp['endy']); + } elseif ($trwsp['endpage'] < $dom[$trid]['endpage']) { + $dom[$table_el]['rowspans'][$k]['endy'] = $dom[$trid]['endy']; + $dom[$table_el]['rowspans'][$k]['endpage'] = $dom[$trid]['endpage']; + } else { + $dom[$trid]['endy'] = $this->pagedim[$dom[$trid]['endpage']]['hk'] - $this->pagedim[$dom[$trid]['endpage']]['bm']; + } + } + } + } + } + $this->x += ($cellspacingx / 2); + } else { + // opening tag (or self-closing tag) + if (!isset($opentagpos)) { + if (!$this->InFooter) { + if (isset($this->footerlen[$this->page])) { + $this->footerpos[$this->page] = $this->pagelen[$this->page] - $this->footerlen[$this->page]; + } else { + $this->footerpos[$this->page] = $this->pagelen[$this->page]; + } + $opentagpos = $this->footerpos[$this->page]; + } + } + $this->openHTMLTagHandler($dom, $key, $cell); + } + } else { + // closing tag + $this->closeHTMLTagHandler($dom, $key, $cell); + } + } elseif (strlen($dom[$key]['value']) > 0) { + // print list-item + if (!$this->empty_string($this->lispacer)) { + $this->SetFont($pfontname, $pfontstyle, $pfontsize); + $this->lasth = $this->FontSize * $this->cell_height_ratio; + $minstartliney = $this->y; + $this->putHtmlListBullet($this->listnum, $this->lispacer, $pfontsize); + $this->SetFont($curfontname, $curfontstyle, $curfontsize); + $this->lasth = $this->FontSize * $this->cell_height_ratio; + if (is_numeric($pfontsize) AND ($pfontsize > 0) AND is_numeric($curfontsize) AND ($curfontsize > 0) AND ($pfontsize != $curfontsize)) { + $this->y += (($pfontsize - $curfontsize) / $this->k); + $minstartliney = min($this->y, $minstartliney); + } + } + // text + $this->htmlvspace = 0; + if ((!$this->premode) AND ($this->rtl OR $this->tmprtl)) { + // reverse spaces order + $len1 = strlen($dom[$key]['value']); + $lsp = $len1 - strlen(ltrim($dom[$key]['value'])); + $rsp = $len1 - strlen(rtrim($dom[$key]['value'])); + $tmpstr = ''; + if ($rsp > 0) { + $tmpstr .= substr($dom[$key]['value'], -$rsp); + } + $tmpstr .= trim($dom[$key]['value']); + if ($lsp > 0) { + $tmpstr .= substr($dom[$key]['value'], 0, $lsp); + } + $dom[$key]['value'] = $tmpstr; + } + if ($newline) { + if (!$this->premode) { + if (($this->rtl OR $this->tmprtl)) { + $dom[$key]['value'] = rtrim($dom[$key]['value']); + } else { + $dom[$key]['value'] = ltrim($dom[$key]['value']); + } + } + $newline = false; + $firstblock = true; + } else { + $firstblock = false; + } + $strrest = ''; + if (!empty($this->HREF) AND (isset($this->HREF['url']))) { + // HTML Link + $strrest = $this->addHtmlLink($this->HREF['url'], $dom[$key]['value'], $wfill, true, $this->HREF['color'], $this->HREF['style']); + } else { + $ctmpmargin = $this->cMargin; + $this->cMargin = 0; + // ****** write only until the end of the line and get the rest ****** + $strrest = $this->Write($this->lasth, $dom[$key]['value'], '', $wfill, '', false, 0, true, $firstblock); + $this->cMargin = $ctmpmargin; + } + if (strlen($strrest) > 0) { + // store the remaining string on the previous $key position + $this->newline = true; + if ($cell) { + if ($this->rtl) { + $this->x -= $this->cMargin; + } else { + $this->x += $this->cMargin; + } + } + if ($strrest == $dom[$key]['value']) { + // used to avoid infinite loop + ++$loop; + } else { + $loop = 0; + } + $dom[$key]['value'] = ltrim($strrest); + if ($loop < 3) { + --$key; + } + } else { + $loop = 0; + } + } + ++$key; + } // end for each $key + // align the last line + if (isset($startlinex)) { + $yshift = $minstartliney - $startliney; + if (($yshift > 0) OR ($this->page > $startlinepage)) { + $yshift = 0; + } + if ((isset($plalign) AND ((($plalign == 'C') OR ($plalign == 'J') OR (($plalign == 'R') AND (!$this->rtl)) OR (($plalign == 'L') AND ($this->rtl))))) OR ($yshift < 0)) { + // the last line must be shifted to be aligned as requested + $linew = abs($this->endlinex - $startlinex); + $pstart = substr($this->getPageBuffer($startlinepage), 0, $startlinepos); + if (isset($opentagpos) AND isset($this->footerlen[$startlinepage]) AND (!$this->InFooter)) { + $this->footerpos[$startlinepage] = $this->pagelen[$startlinepage] - $this->footerlen[$startlinepage]; + $midpos = min($opentagpos, $this->footerpos[$startlinepage]); + } elseif (isset($opentagpos)) { + $midpos = $opentagpos; + } elseif (isset($this->footerlen[$startlinepage]) AND (!$this->InFooter)) { + $this->footerpos[$startlinepage] = $this->pagelen[$startlinepage] - $this->footerlen[$startlinepage]; + $midpos = $this->footerpos[$startlinepage]; + } else { + $midpos = 0; + } + if ($midpos > 0) { + $pmid = substr($this->getPageBuffer($startlinepage), $startlinepos, ($midpos - $startlinepos)); + $pend = substr($this->getPageBuffer($startlinepage), $midpos); + } else { + $pmid = substr($this->getPageBuffer($startlinepage), $startlinepos); + $pend = ''; + } + // calculate shifting amount + $tw = $w; + if ($this->lMargin != $prevlMargin) { + $tw += ($prevlMargin - $this->lMargin); + } + if ($this->rMargin != $prevrMargin) { + $tw += ($prevrMargin - $this->rMargin); + } + $mdiff = abs($tw - $linew); + if ($plalign == 'C') { + if ($this->rtl) { + $t_x = -($mdiff / 2); + } else { + $t_x = ($mdiff / 2); + } + } elseif (($plalign == 'R') AND (!$this->rtl)) { + // right alignment on LTR document + $t_x = $mdiff; + } elseif (($plalign == 'L') AND ($this->rtl)) { + // left alignment on RTL document + $t_x = -$mdiff; + } else { + $t_x = 0; + } + if (($t_x != 0) OR ($yshift < 0)) { + // shift the line + $trx = sprintf('1 0 0 1 %.3F %.3F cm', ($t_x * $this->k), ($yshift * $this->k)); + $this->setPageBuffer($startlinepage, $pstart."\nq\n".$trx."\n".$pmid."\nQ\n".$pend); + $endlinepos = strlen($pstart."\nq\n".$trx."\n".$pmid."\nQ\n"); + // shift the annotations and links + if (isset($this->PageAnnots[$this->page])) { + foreach ($this->PageAnnots[$this->page] as $pak => $pac) { + if ($pak >= $pask) { + $this->PageAnnots[$this->page][$pak]['x'] += $t_x; + $this->PageAnnots[$this->page][$pak]['y'] -= $yshift; + } + } + } + $this->y -= $yshift; + } + } + } + if ($ln AND (!($cell AND ($dom[$key-1]['value'] == 'table')))) { + $this->Ln($this->lasth); + } + // restore previous values + $this->setGraphicVars($gvars); + if ($this->page > $prevPage) { + $this->lMargin = $this->pagedim[$this->page]['olm']; + $this->rMargin = $this->pagedim[$this->page]['orm']; + } + unset($dom); + } + + /** + * Process opening tags. + * @param array $dom html dom array + * @param int $key current element id + * @param boolean $cell if true add the default cMargin space to each new line (default false). + * @access protected + */ + protected function openHTMLTagHandler(&$dom, $key, $cell=false) { + $tag = $dom[$key]; + $parent = $dom[($dom[$key]['parent'])]; + $firstorlast = ($key == 1); + // check for text direction attribute + if (isset($tag['attribute']['dir'])) { + $this->tmprtl = $tag['attribute']['dir'] == 'rtl' ? 'R' : 'L'; + } else { + $this->tmprtl = false; + } + //Opening tag + switch($tag['value']) { + case 'table': { + $cp = 0; + $cs = 0; + $dom[$key]['rowspans'] = array(); + if (!$this->empty_string($dom[$key]['thead'])) { + // set table header + $this->thead = $dom[$key]['thead']; + } + if (isset($tag['attribute']['cellpadding'])) { + $cp = $this->getHTMLUnitToUnits($tag['attribute']['cellpadding'], 1, 'px'); + $this->oldcMargin = $this->cMargin; + $this->cMargin = $cp; + } + if (isset($tag['attribute']['cellspacing'])) { + $cs = $this->getHTMLUnitToUnits($tag['attribute']['cellspacing'], 1, 'px'); + } + $this->checkPageBreak((2 * $cp) + (2 * $cs) + $this->lasth); + break; + } + case 'tr': { + // array of columns positions + $dom[$key]['cellpos'] = array(); + break; + } + case 'hr': { + $this->addHTMLVertSpace(1, $cell, '', $firstorlast, $tag['value'], false); + $this->htmlvspace = 0; + $wtmp = $this->w - $this->lMargin - $this->rMargin; + if ((isset($tag['attribute']['width'])) AND ($tag['attribute']['width'] != '')) { + $hrWidth = $this->getHTMLUnitToUnits($tag['attribute']['width'], $wtmp, 'px'); + } else { + $hrWidth = $wtmp; + } + $x = $this->GetX(); + $y = $this->GetY(); + $prevlinewidth = $this->GetLineWidth(); + $this->Line($x, $y, $x + $hrWidth, $y); + $this->SetLineWidth($prevlinewidth); + $this->addHTMLVertSpace(1, $cell, '', !isset($dom[($key + 1)]), $tag['value'], false); + break; + } + case 'a': { + if (array_key_exists('href', $tag['attribute'])) { + $this->HREF['url'] = $tag['attribute']['href']; + } + $this->HREF['color'] = $this->htmlLinkColorArray; + $this->HREF['style'] = $this->htmlLinkFontStyle; + if (array_key_exists('style', $tag['attribute'])) { + // get style attributes + preg_match_all('/([^;:\s]*):([^;]*)/', $tag['attribute']['style'], $style_array, PREG_PATTERN_ORDER); + $astyle = array(); + while (list($id, $name) = each($style_array[1])) { + $name = strtolower($name); + $astyle[$name] = trim($style_array[2][$id]); + } + if (isset($astyle['color'])) { + $this->HREF['color'] = $this->convertHTMLColorToDec($astyle['color']); + } + if (isset($astyle['text-decoration'])) { + $this->HREF['style'] = ''; + $decors = explode(' ', strtolower($astyle['text-decoration'])); + foreach ($decors as $dec) { + $dec = trim($dec); + if (!$this->empty_string($dec)) { + if ($dec{0} == 'u') { + $this->HREF['style'] .= 'U'; + } elseif ($dec{0} == 'l') { + $this->HREF['style'] .= 'D'; + } + } + } + } + } + break; + } + case 'img': { + if (isset($tag['attribute']['src'])) { + // replace relative path with real server path + if ($tag['attribute']['src'][0] == '/') { + $tag['attribute']['src'] = $_SERVER['DOCUMENT_ROOT'].$tag['attribute']['src']; + } + $tag['attribute']['src'] = urldecode($tag['attribute']['src']); + $tag['attribute']['src'] = str_replace(K_PATH_URL, K_PATH_MAIN, $tag['attribute']['src']); + if (!isset($tag['attribute']['width'])) { + $tag['attribute']['width'] = 0; + } + if (!isset($tag['attribute']['height'])) { + $tag['attribute']['height'] = 0; + } + //if (!isset($tag['attribute']['align'])) { + // the only alignment supported is "bottom" + // further development is required for other modes. + $tag['attribute']['align'] = 'bottom'; + //} + switch($tag['attribute']['align']) { + case 'top': { + $align = 'T'; + break; + } + case 'middle': { + $align = 'M'; + break; + } + case 'bottom': { + $align = 'B'; + break; + } + default: { + $align = 'B'; + break; + } + } + $fileinfo = pathinfo($tag['attribute']['src']); + if (isset($fileinfo['extension']) AND (!$this->empty_string($fileinfo['extension']))) { + $type = strtolower($fileinfo['extension']); + } + $prevy = $this->y; + $xpos = $this->GetX(); + if (isset($dom[($key - 1)]) AND ($dom[($key - 1)]['value'] == ' ')) { + if ($this->rtl) { + $xpos += $this->GetStringWidth(' '); + } else { + $xpos -= $this->GetStringWidth(' '); + } + } + $imglink = ''; + if (isset($this->HREF['url']) AND !$this->empty_string($this->HREF['url'])) { + $imglink = $this->HREF['url']; + if ($imglink{0} == '#') { + // convert url to internal link + $page = intval(substr($imglink, 1)); + $imglink = $this->AddLink(); + $this->SetLink($imglink, 0, $page); + } + } + $border = 0; + if (isset($tag['attribute']['border']) AND !empty($tag['attribute']['border'])) { + // currently only support 1 (frame) or a combination of 'LTRB' + $border = $tag['attribute']['border']; + } + $iw = ''; + if (isset($tag['attribute']['width'])) { + $iw = $this->getHTMLUnitToUnits($tag['attribute']['width'], 1, 'px', false); + } + $ih = ''; + if (isset($tag['attribute']['height'])) { + $ih = $this->getHTMLUnitToUnits($tag['attribute']['height'], 1, 'px', false); + } + if (($type == 'eps') OR ($type == 'ai')) { + $this->ImageEps($tag['attribute']['src'], $xpos, $this->GetY(), $iw, $ih, $imglink, true, $align, '', $border); + } else { + $this->Image($tag['attribute']['src'], $xpos, $this->GetY(), $iw, $ih, '', $imglink, $align, false, 300, '', false, false, $border); + } + switch($align) { + case 'T': { + $this->y = $prevy; + break; + } + case 'M': { + $this->y = (($this->img_rb_y + $prevy - ($tag['fontsize'] / $this->k)) / 2) ; + break; + } + case 'B': { + $this->y = $this->img_rb_y - ($tag['fontsize'] / $this->k); + break; + } + } + } + break; + } + case 'dl': { + ++$this->listnum; + $this->addHTMLVertSpace(0, $cell, '', $firstorlast, $tag['value'], false); + break; + } + case 'dt': { + $this->addHTMLVertSpace(1, $cell, '', $firstorlast, $tag['value'], false); + break; + } + case 'dd': { + if ($this->rtl) { + $this->rMargin += $this->listindent; + } else { + $this->lMargin += $this->listindent; + } + $this->addHTMLVertSpace(1, $cell, '', $firstorlast, $tag['value'], false); + break; + } + case 'ul': + case 'ol': { + $this->addHTMLVertSpace(0, $cell, '', $firstorlast, $tag['value'], false); + $this->htmlvspace = 0; + ++$this->listnum; + if ($tag['value'] == 'ol') { + $this->listordered[$this->listnum] = true; + } else { + $this->listordered[$this->listnum] = false; + } + if (isset($tag['attribute']['start'])) { + $this->listcount[$this->listnum] = intval($tag['attribute']['start']) - 1; + } else { + $this->listcount[$this->listnum] = 0; + } + if ($this->rtl) { + $this->rMargin += $this->listindent; + } else { + $this->lMargin += $this->listindent; + } + $this->addHTMLVertSpace(0, $cell, '', $firstorlast, $tag['value'], false); + $this->htmlvspace = 0; + break; + } + case 'li': { + $this->addHTMLVertSpace(1, $cell, '', $firstorlast, $tag['value'], false); + if ($this->listordered[$this->listnum]) { + // ordered item + if (isset($parent['attribute']['type']) AND !$this->empty_string($parent['attribute']['type'])) { + $this->lispacer = $parent['attribute']['type']; + } elseif (isset($parent['listtype']) AND !$this->empty_string($parent['listtype'])) { + $this->lispacer = $parent['listtype']; + } elseif (isset($this->lisymbol) AND !$this->empty_string($this->lisymbol)) { + $this->lispacer = $this->lisymbol; + } else { + $this->lispacer = '#'; + } + ++$this->listcount[$this->listnum]; + if (isset($tag['attribute']['value'])) { + $this->listcount[$this->listnum] = intval($tag['attribute']['value']); + } + } else { + // unordered item + if (isset($parent['attribute']['type']) AND !$this->empty_string($parent['attribute']['type'])) { + $this->lispacer = $parent['attribute']['type']; + } elseif (isset($parent['listtype']) AND !$this->empty_string($parent['listtype'])) { + $this->lispacer = $parent['listtype']; + } elseif (isset($this->lisymbol) AND !$this->empty_string($this->lisymbol)) { + $this->lispacer = $this->lisymbol; + } else { + $this->lispacer = '!'; + } + } + break; + } + case 'blockquote': { + if ($this->rtl) { + $this->rMargin += $this->listindent; + } else { + $this->lMargin += $this->listindent; + } + $this->addHTMLVertSpace(2, $cell, '', $firstorlast, $tag['value'], false); + break; + } + case 'br': { + $this->Ln('', $cell); + break; + } + case 'div': { + $this->addHTMLVertSpace(1, $cell, '', $firstorlast, $tag['value'], false); + break; + } + case 'p': { + $this->addHTMLVertSpace(2, $cell, '', $firstorlast, $tag['value'], false); + break; + } + case 'pre': { + $this->addHTMLVertSpace(1, $cell, '', $firstorlast, $tag['value'], false); + $this->premode = true; + break; + } + case 'sup': { + $this->SetXY($this->GetX(), $this->GetY() - ((0.7 * $this->FontSizePt) / $this->k)); + break; + } + case 'sub': { + $this->SetXY($this->GetX(), $this->GetY() + ((0.3 * $this->FontSizePt) / $this->k)); + break; + } + case 'h1': + case 'h2': + case 'h3': + case 'h4': + case 'h5': + case 'h6': { + $this->addHTMLVertSpace(1, $cell, ($tag['fontsize'] * 1.5) / $this->k, $firstorlast, $tag['value'], false); + break; + } + case 'tcpdf': { + if (defined('K_TCPDF_CALLS_IN_HTML') AND (K_TCPDF_CALLS_IN_HTML === true)) { + // Special tag used to call TCPDF methods + if (isset($tag['attribute']['method'])) { + $tcpdf_method = $tag['attribute']['method']; + if (method_exists($this, $tcpdf_method)) { + if (isset($tag['attribute']['params']) AND (!empty($tag['attribute']['params']))) { + $params = unserialize(urldecode($tag['attribute']['params'])); + call_user_func_array(array($this, $tcpdf_method), $params); + } else { + $this->$tcpdf_method(); + } + $this->newline = true; + } + } + } + } + default: { + break; + } + } + } + + /** + * Process closing tags. + * @param array $dom html dom array + * @param int $key current element id + * @param boolean $cell if true add the default cMargin space to each new line (default false). + * @access protected + */ + protected function closeHTMLTagHandler(&$dom, $key, $cell=false) { + $tag = $dom[$key]; + $parent = $dom[($dom[$key]['parent'])]; + $firstorlast = ((!isset($dom[($key + 1)])) OR ((!isset($dom[($key + 2)])) AND ($dom[($key + 1)]['value'] == 'marker'))); + //Closing tag + switch($tag['value']) { + case 'tr': { + $table_el = $dom[($dom[$key]['parent'])]['parent']; + if(!isset($parent['endy'])) { + $dom[($dom[$key]['parent'])]['endy'] = $this->y; + $parent['endy'] = $this->y; + } + if(!isset($parent['endpage'])) { + $dom[($dom[$key]['parent'])]['endpage'] = $this->page; + $parent['endpage'] = $this->page; + } + // update row-spanned cells + if (isset($dom[$table_el]['rowspans'])) { + foreach ($dom[$table_el]['rowspans'] as $k => $trwsp) { + $dom[$table_el]['rowspans'][$k]['rowspan'] -= 1; + if ($dom[$table_el]['rowspans'][$k]['rowspan'] == 0) { + if ($dom[$table_el]['rowspans'][$k]['endpage'] == $parent['endpage']) { + $dom[($dom[$key]['parent'])]['endy'] = max($dom[$table_el]['rowspans'][$k]['endy'], $parent['endy']); + } elseif ($dom[$table_el]['rowspans'][$k]['endpage'] > $parent['endpage']) { + $dom[($dom[$key]['parent'])]['endy'] = $dom[$table_el]['rowspans'][$k]['endy']; + $dom[($dom[$key]['parent'])]['endpage'] = $dom[$table_el]['rowspans'][$k]['endpage']; + } + } + } + // report new endy and endpage to the rowspanned cells + foreach ($dom[$table_el]['rowspans'] as $k => $trwsp) { + if ($dom[$table_el]['rowspans'][$k]['rowspan'] == 0) { + $dom[$table_el]['rowspans'][$k]['endpage'] = max($dom[$table_el]['rowspans'][$k]['endpage'], $dom[($dom[$key]['parent'])]['endpage']); + $dom[($dom[$key]['parent'])]['endpage'] = $dom[$table_el]['rowspans'][$k]['endpage']; + $dom[$table_el]['rowspans'][$k]['endy'] = max($dom[$table_el]['rowspans'][$k]['endy'], $dom[($dom[$key]['parent'])]['endy']); + $dom[($dom[$key]['parent'])]['endy'] = $dom[$table_el]['rowspans'][$k]['endy']; + } + } + // update remaining rowspanned cells + foreach ($dom[$table_el]['rowspans'] as $k => $trwsp) { + if ($dom[$table_el]['rowspans'][$k]['rowspan'] == 0) { + $dom[$table_el]['rowspans'][$k]['endpage'] = $dom[($dom[$key]['parent'])]['endpage']; + $dom[$table_el]['rowspans'][$k]['endy'] = $dom[($dom[$key]['parent'])]['endy']; + } + } + } + $this->setPage($dom[($dom[$key]['parent'])]['endpage']); + $this->y = $dom[($dom[$key]['parent'])]['endy']; + if (isset($dom[$table_el]['attribute']['cellspacing'])) { + $cellspacing = $this->getHTMLUnitToUnits($dom[$table_el]['attribute']['cellspacing'], 1, 'px'); + $this->y += $cellspacing; + } + $this->Ln(0, $cell); + $this->x = $parent['startx']; + // account for booklet mode + if ($this->page > $parent['startpage']) { + if (($this->rtl) AND ($this->pagedim[$this->page]['orm'] != $this->pagedim[$parent['startpage']]['orm'])) { + $this->x += ($this->pagedim[$this->page]['orm'] - $this->pagedim[$parent['startpage']]['orm']); + } elseif ((!$this->rtl) AND ($this->pagedim[$this->page]['olm'] != $this->pagedim[$parent['startpage']]['olm'])) { + $this->x += ($this->pagedim[$this->page]['olm'] - $this->pagedim[$parent['startpage']]['olm']); + } + } + break; + } + case 'table': { + // draw borders + $table_el = $parent; + if ((isset($table_el['attribute']['border']) AND ($table_el['attribute']['border'] > 0)) + OR (isset($table_el['style']['border']) AND ($table_el['style']['border'] > 0))) { + $border = 1; + } else { + $border = 0; + } + // fix bottom line alignment of last line before page break + foreach ($dom[($dom[$key]['parent'])]['trids'] as $j => $trkey) { + // update row-spanned cells + if (isset($dom[($dom[$key]['parent'])]['rowspans'])) { + foreach ($dom[($dom[$key]['parent'])]['rowspans'] as $k => $trwsp) { + if ($trwsp['trid'] == $trkey) { + $dom[($dom[$key]['parent'])]['rowspans'][$k]['mrowspan'] -= 1; + } + if (isset($prevtrkey) AND ($trwsp['trid'] == $prevtrkey) AND ($trwsp['mrowspan'] >= 0)) { + $dom[($dom[$key]['parent'])]['rowspans'][$k]['trid'] = $trkey; + } + } + } + if (isset($prevtrkey) AND ($dom[$trkey]['startpage'] > $dom[$prevtrkey]['endpage'])) { + $pgendy = $this->pagedim[$dom[$prevtrkey]['endpage']]['hk'] - $this->pagedim[$dom[$prevtrkey]['endpage']]['bm']; + $dom[$prevtrkey]['endy'] = $pgendy; + // update row-spanned cells + if (isset($dom[($dom[$key]['parent'])]['rowspans'])) { + foreach ($dom[($dom[$key]['parent'])]['rowspans'] as $k => $trwsp) { + if (($trwsp['trid'] == $trkey) AND ($trwsp['mrowspan'] == 1) AND ($trwsp['endpage'] == $dom[$prevtrkey]['endpage'])) { + $dom[($dom[$key]['parent'])]['rowspans'][$k]['endy'] = $pgendy; + $dom[($dom[$key]['parent'])]['rowspans'][$k]['mrowspan'] = -1; + } + } + } + } + $prevtrkey = $trkey; + $table_el = $dom[($dom[$key]['parent'])]; + } + // for each row + foreach ($table_el['trids'] as $j => $trkey) { + $parent = $dom[$trkey]; + // for each cell on the row + foreach ($parent['cellpos'] as $k => $cellpos) { + if (isset($cellpos['rowspanid']) AND ($cellpos['rowspanid'] >= 0)) { + $cellpos['startx'] = $table_el['rowspans'][($cellpos['rowspanid'])]['startx']; + $cellpos['endx'] = $table_el['rowspans'][($cellpos['rowspanid'])]['endx']; + $endy = $table_el['rowspans'][($cellpos['rowspanid'])]['endy']; + $startpage = $table_el['rowspans'][($cellpos['rowspanid'])]['startpage']; + $endpage = $table_el['rowspans'][($cellpos['rowspanid'])]['endpage']; + } else { + $endy = $parent['endy']; + $startpage = $parent['startpage']; + $endpage = $parent['endpage']; + } + if ($endpage > $startpage) { + // design borders around HTML cells. + for ($page=$startpage; $page <= $endpage; ++$page) { + $this->setPage($page); + if ($page == $startpage) { + $this->y = $parent['starty']; // put cursor at the beginning of row on the first page + $ch = $this->getPageHeight() - $parent['starty'] - $this->getBreakMargin(); + $cborder = $this->getBorderMode($border, $position='start'); + } elseif ($page == $endpage) { + $this->y = $this->tMargin; // put cursor at the beginning of last page + $ch = $endy - $this->tMargin; + $cborder = $this->getBorderMode($border, $position='end'); + } else { + $this->y = $this->tMargin; // put cursor at the beginning of the current page + $ch = $this->getPageHeight() - $this->tMargin - $this->getBreakMargin(); + $cborder = $this->getBorderMode($border, $position='middle'); + } + if (isset($cellpos['bgcolor']) AND ($cellpos['bgcolor']) !== false) { + $this->SetFillColorArray($cellpos['bgcolor']); + $fill = true; + } else { + $fill = false; + } + $cw = abs($cellpos['endx'] - $cellpos['startx']); + $this->x = $cellpos['startx']; + // account for margin changes + if ($page > $startpage) { + if (($this->rtl) AND ($this->pagedim[$page]['orm'] != $this->pagedim[$startpage]['orm'])) { + $this->x -= ($this->pagedim[$page]['orm'] - $this->pagedim[$startpage]['orm']); + } elseif ((!$this->rtl) AND ($this->pagedim[$page]['lm'] != $this->pagedim[$startpage]['olm'])) { + $this->x += ($this->pagedim[$page]['olm'] - $this->pagedim[$startpage]['olm']); + } + } + // design a cell around the text + $ccode = $this->FillColor."\n".$this->getCellCode($cw, $ch, '', $cborder, 1, '', $fill, '', 0, true); + if ($cborder OR $fill) { + $pagebuff = $this->getPageBuffer($this->page); + $pstart = substr($pagebuff, 0, $this->intmrk[$this->page]); + $pend = substr($pagebuff, $this->intmrk[$this->page]); + $this->setPageBuffer($this->page, $pstart.$ccode."\n".$pend); + $this->intmrk[$this->page] += strlen($ccode."\n"); + } + } + } else { + $this->setPage($startpage); + if (isset($cellpos['bgcolor']) AND ($cellpos['bgcolor']) !== false) { + $this->SetFillColorArray($cellpos['bgcolor']); + $fill = true; + } else { + $fill = false; + } + $this->x = $cellpos['startx']; + $this->y = $parent['starty']; + $cw = abs($cellpos['endx'] - $cellpos['startx']); + $ch = $endy - $parent['starty']; + // design a cell around the text + $ccode = $this->FillColor."\n".$this->getCellCode($cw, $ch, '', $border, 1, '', $fill, '', 0, true); + if ($border OR $fill) { + if (end($this->transfmrk[$this->page]) !== false) { + $pagemarkkey = key($this->transfmrk[$this->page]); + $pagemark = &$this->transfmrk[$this->page][$pagemarkkey]; + } elseif ($this->InFooter) { + $pagemark = &$this->footerpos[$this->page]; + } else { + $pagemark = &$this->intmrk[$this->page]; + } + $pagebuff = $this->getPageBuffer($this->page); + $pstart = substr($pagebuff, 0, $pagemark); + $pend = substr($pagebuff, $pagemark); + $this->setPageBuffer($this->page, $pstart.$ccode."\n".$pend); + $pagemark += strlen($ccode."\n"); + } + } + } + if (isset($table_el['attribute']['cellspacing'])) { + $cellspacing = $this->getHTMLUnitToUnits($table_el['attribute']['cellspacing'], 1, 'px'); + $this->y += $cellspacing; + } + $this->Ln(0, $cell); + $this->x = $parent['startx']; + if ($endpage > $startpage) { + if (($this->rtl) AND ($this->pagedim[$endpage]['orm'] != $this->pagedim[$startpage]['orm'])) { + $this->x += ($this->pagedim[$endpage]['orm'] - $this->pagedim[$startpage]['orm']); + } elseif ((!$this->rtl) AND ($this->pagedim[$endpage]['olm'] != $this->pagedim[$startpage]['olm'])) { + $this->x += ($this->pagedim[$endpage]['olm'] - $this->pagedim[$startpage]['olm']); + } + } + } + if (isset($parent['cellpadding'])) { + $this->cMargin = $this->oldcMargin; + } + $this->lasth = $this->FontSize * $this->cell_height_ratio; + if (!$this->empty_string($this->theadMargin)) { + // restore top margin + $this->tMargin = $this->theadMargin; + $this->pagedim[$this->page]['tm'] = $this->theadMargin; + } + // reset table header + $this->thead = ''; + $this->theadMargin = ''; + break; + } + case 'a': { + $this->HREF = ''; + break; + } + case 'sup': { + $this->SetXY($this->GetX(), $this->GetY() + ((0.7 * $parent['fontsize']) / $this->k)); + break; + } + case 'sub': { + $this->SetXY($this->GetX(), $this->GetY() - ((0.3 * $parent['fontsize'])/$this->k)); + break; + } + case 'div': { + $this->addHTMLVertSpace(1, $cell, '', $firstorlast, $tag['value'], true); + break; + } + case 'blockquote': { + if ($this->rtl) { + $this->rMargin -= $this->listindent; + } else { + $this->lMargin -= $this->listindent; + } + $this->addHTMLVertSpace(2, $cell, '', $firstorlast, $tag['value'], true); + break; + } + case 'p': { + $this->addHTMLVertSpace(2, $cell, '', $firstorlast, $tag['value'], true); + break; + } + case 'pre': { + $this->addHTMLVertSpace(1, $cell, '', $firstorlast, $tag['value'], true); + $this->premode = false; + break; + } + case 'dl': { + --$this->listnum; + if ($this->listnum <= 0) { + $this->listnum = 0; + $this->addHTMLVertSpace(2, $cell, '', $firstorlast, $tag['value'], true); + } + break; + } + case 'dt': { + $this->lispacer = ''; + $this->addHTMLVertSpace(0, $cell, '', $firstorlast, $tag['value'], true); + break; + } + case 'dd': { + $this->lispacer = ''; + if ($this->rtl) { + $this->rMargin -= $this->listindent; + } else { + $this->lMargin -= $this->listindent; + } + $this->addHTMLVertSpace(0, $cell, '', $firstorlast, $tag['value'], true); + break; + } + case 'ul': + case 'ol': { + --$this->listnum; + $this->lispacer = ''; + if ($this->rtl) { + $this->rMargin -= $this->listindent; + } else { + $this->lMargin -= $this->listindent; + } + if ($this->listnum <= 0) { + $this->listnum = 0; + $this->addHTMLVertSpace(2, $cell, '', $firstorlast, $tag['value'], true); + } + $this->lasth = $this->FontSize * $this->cell_height_ratio; + break; + } + case 'li': { + $this->lispacer = ''; + $this->addHTMLVertSpace(0, $cell, '', $firstorlast, $tag['value'], true); + break; + } + case 'h1': + case 'h2': + case 'h3': + case 'h4': + case 'h5': + case 'h6': { + $this->addHTMLVertSpace(1, $cell, ($parent['fontsize'] * 1.5) / $this->k, $firstorlast, $tag['value'], true); + break; + } + default : { + break; + } + } + $this->tmprtl = false; + } + + /** + * Add vertical spaces if needed. + * @param int $n number of spaces to add + * @param boolean $cell if true add the default cMargin space to each new line (default false). + * @param string $h The height of the break. By default, the value equals the height of the last printed cell. + * @param boolean $firstorlast if true do not print additional empty lines. + * @param string $tag HTML tag to which this space will be applied + * @param boolean $closing true if this space will be applied to a closing tag, false otherwise + * @access protected + */ + protected function addHTMLVertSpace($n, $cell=false, $h='', $firstorlast=false, $tag='', $closing=false) { + if ($firstorlast) { + $this->Ln(0, $cell); + $this->htmlvspace = 0; + return; + } + if (isset($this->tagvspaces[$tag][intval($closing)]['n'])) { + $n = $this->tagvspaces[$tag][intval($closing)]['n']; + } + if (isset($this->tagvspaces[$tag][intval($closing)]['h'])) { + $h = $this->tagvspaces[$tag][intval($closing)]['h']; + } + if (is_string($h)) { + $vsize = $n * $this->lasth; + } else { + $vsize = $n * $h; + } + if ($vsize > $this->htmlvspace) { + $this->Ln(($vsize - $this->htmlvspace), $cell); + $this->htmlvspace = $vsize; + } + } + + /** + * Set the default bullet to be used as LI bullet symbol + * @param string $symbol character or string to be used (legal values are: '' = automatic, '!' = auto bullet, '#' = auto numbering, 'disc', 'disc', 'circle', 'square', '1', 'decimal', 'decimal-leading-zero', 'i', 'lower-roman', 'I', 'upper-roman', 'a', 'lower-alpha', 'lower-latin', 'A', 'upper-alpha', 'upper-latin', 'lower-greek') + * @access public + * @since 4.0.028 (2008-09-26) + */ + public function setLIsymbol($symbol='!') { + $symbol = strtolower($symbol); + switch ($symbol) { + case '!' : + case '#' : + case 'disc' : + case 'disc' : + case 'circle' : + case 'square' : + case '1': + case 'decimal': + case 'decimal-leading-zero': + case 'i': + case 'lower-roman': + case 'I': + case 'upper-roman': + case 'a': + case 'lower-alpha': + case 'lower-latin': + case 'A': + case 'upper-alpha': + case 'upper-latin': + case 'lower-greek': { + $this->lisymbol = $symbol; + break; + } + default : { + $this->lisymbol = ''; + } + } + } + + /** + * Set the booklet mode for double-sided pages. + * @param boolean $booklet true set the booklet mode on, fals eotherwise. + * @param float $inner Inner page margin. + * @param float $outer Outer page margin. + * @access public + * @since 4.2.000 (2008-10-29) + */ + public function SetBooklet($booklet=true, $inner=-1, $outer=-1) { + $this->booklet = $booklet; + if ($inner >= 0) { + $this->lMargin = $inner; + } + if ($outer >= 0) { + $this->rMargin = $outer; + } + } + + /** + * Swap the left and right margins. + * @param boolean $reverse if true swap left and right margins. + * @access protected + * @since 4.2.000 (2008-10-29) + */ + protected function swapMargins($reverse=true) { + if ($reverse) { + // swap left and right margins + $mtemp = $this->original_lMargin; + $this->original_lMargin = $this->original_rMargin; + $this->original_rMargin = $mtemp; + $deltam = $this->original_lMargin - $this->original_rMargin; + $this->lMargin += $deltam; + $this->rMargin -= $deltam; + } + } + + /** + * Set the vertical spaces for HTML tags. + * The array must have the following structure (example): + * $tagvs = array('h1' => array(0 => array('h' => '', 'n' => 2), 1 => array('h' => 1.3, 'n' => 1))); + * The first array level contains the tag names, + * the second level contains 0 for opening tags or 1 for closing tags, + * the third level contains the vertical space unit (h) and the number spaces to add (n). + * If the h parameter is not specified, default values are used. + * @param array $tagvs array of tags and relative vertical spaces. + * @access public + * @since 4.2.001 (2008-10-30) + */ + public function setHtmlVSpace($tagvs) { + $this->tagvspaces = $tagvs; + } + + /** + * Set custom width for list indentation. + * @param float $width width of the indentation. Use negative value to disable it. + * @access public + * @since 4.2.007 (2008-11-12) + */ + public function setListIndentWidth($width) { + return $this->customlistindent = floatval($width); + } + + /** + * Set the top/bottom cell sides to be open or closed when the cell cross the page. + * @param boolean $isopen if true keeps the top/bottom border open for the cell sides that cross the page. + * @access public + * @since 4.2.010 (2008-11-14) + */ + public function setOpenCell($isopen) { + $this->opencell = $isopen; + } + + /** + * Set the color and font style for HTML links. + * @param array $color RGB array of colors + * @param string $fontstyle additional font styles to add + * @access public + * @since 4.4.003 (2008-12-09) + */ + public function setHtmlLinksStyle($color=array(0,0,255), $fontstyle='U') { + $this->htmlLinkColorArray = $color; + $this->htmlLinkFontStyle = $fontstyle; + } + + /** + * convert html string containing value and unit of measure to user's units or points. + * @param string $htmlval string containing values and unit + * @param string $refsize reference value in points + * @param string $defaultunit default unit (can be one of the following: %, em, ex, px, in, mm, pc, pt). + * @param boolean $point if true returns points, otherwise returns value in user's units + * @return float value in user's unit or point if $points=true + * @access public + * @since 4.4.004 (2008-12-10) + */ + public function getHTMLUnitToUnits($htmlval, $refsize=1, $defaultunit='px', $points=false) { + $supportedunits = array('%', 'em', 'ex', 'px', 'in', 'cm', 'mm', 'pc', 'pt'); + $retval = 0; + $value = 0; + $unit = 'px'; + $k = $this->k; + if ($points) { + $k = 1; + } + if (in_array($defaultunit, $supportedunits)) { + $unit = $defaultunit; + } + if (is_numeric($htmlval)) { + $value = floatval($htmlval); + } elseif (preg_match('/([0-9\.]+)/', $htmlval, $mnum)) { + $value = floatval($mnum[1]); + if (preg_match('/([a-z%]+)/', $htmlval, $munit)) { + if (in_array($munit[1], $supportedunits)) { + $unit = $munit[1]; + } + } + } + switch ($unit) { + // percentage + case '%': { + $retval = (($value * $refsize) / 100); + break; + } + // relative-size + case 'em': { + $retval = ($value * $refsize); + break; + } + case 'ex': { + $retval = $value * ($refsize / 2); + break; + } + // absolute-size + case 'in': { + $retval = ($value * $this->dpi) / $k; + break; + } + case 'cm': { + $retval = ($value / 2.54 * $this->dpi) / $k; + break; + } + case 'mm': { + $retval = ($value / 25.4 * $this->dpi) / $k; + break; + } + case 'pc': { + // one pica is 12 points + $retval = ($value * 12) / $k; + break; + } + case 'pt': { + $retval = $value / $k; + break; + } + case 'px': { + $retval = $this->pixelsToUnits($value); + break; + } + } + return $retval; + } + + /** + * Returns the Roman representation of an integer number + * @param int number to convert + * @return string roman representation of the specified number + * @access public + * @since 4.4.004 (2008-12-10) + */ + public function intToRoman($number) { + $roman = ''; + while ($number >= 1000) { + $roman .= 'M'; + $number -= 1000; + } + while ($number >= 900) { + $roman .= 'CM'; + $number -= 900; + } + while ($number >= 500) { + $roman .= 'D'; + $number -= 500; + } + while ($number >= 400) { + $roman .= 'CD'; + $number -= 400; + } + while ($number >= 100) { + $roman .= 'C'; + $number -= 100; + } + while ($number >= 90) { + $roman .= 'XC'; + $number -= 90; + } + while ($number >= 50) { + $roman .= 'L'; + $number -= 50; + } + while ($number >= 40) { + $roman .= 'XL'; + $number -= 40; + } + while ($number >= 10) { + $roman .= 'X'; + $number -= 10; + } + while ($number >= 9) { + $roman .= 'IX'; + $number -= 9; + } + while ($number >= 5) { + $roman .= 'V'; + $number -= 5; + } + while ($number >= 4) { + $roman .= 'IV'; + $number -= 4; + } + while ($number >= 1) { + $roman .= 'I'; + --$number; + } + return $roman; + } + + /** + * Output an HTML list bullet or ordered item symbol + * @param int $listdepth list nesting level + * @param string $listtype type of list + * @param float $size current font size + * @access protected + * @since 4.4.004 (2008-12-10) + */ + protected function putHtmlListBullet($listdepth, $listtype='', $size=10) { + $size /= $this->k; + $fill = ''; + $color = $this->fgcolor; + $width = 0; + $textitem = ''; + $tmpx = $this->x; + $lspace = $this->GetStringWidth(' '); + if ($listtype == '!') { + // set default list type for unordered list + $deftypes = array('disc', 'circle', 'square'); + $listtype = $deftypes[($listdepth - 1) % 3]; + } elseif ($listtype == '#') { + // set default list type for ordered list + $listtype = 'decimal'; + } + switch ($listtype) { + // unordered types + case 'none': { + break; + } + case 'disc': { + $fill = 'F'; + } + case 'circle': { + $fill .= 'D'; + $r = $size / 6; + $lspace += (2 * $r); + if ($this->rtl) { + $this->x = $this->w - $this->x - $lspace; + } else { + $this->x -= $lspace; + } + $this->Circle(($this->x + $r), ($this->y + ($this->lasth / 2)), $r, 0, 360, $fill, array('color'=>$color), $color, 8); + break; + } + case 'square': { + $l = $size / 3; + $lspace += $l; + if ($this->rtl) { + $this->x = $this->w - $this->x - $lspace; + } else { + $this->x -= $lspace; + } + $this->Rect($this->x, ($this->y + (($this->lasth - $l)/ 2)), $l, $l, 'F', array(), $color); + break; + } + // ordered types + + // $this->listcount[$this->listnum]; + // $textitem + case '1': + case 'decimal': { + $textitem = $this->listcount[$this->listnum]; + break; + } + case 'decimal-leading-zero': { + $textitem = sprintf("%02d", $this->listcount[$this->listnum]); + break; + } + case 'i': + case 'lower-roman': { + $textitem = strtolower($this->intToRoman($this->listcount[$this->listnum])); + break; + } + case 'I': + case 'upper-roman': { + $textitem = $this->intToRoman($this->listcount[$this->listnum]); + break; + } + case 'a': + case 'lower-alpha': + case 'lower-latin': { + $textitem = chr(97 + $this->listcount[$this->listnum] - 1); + break; + } + case 'A': + case 'upper-alpha': + case 'upper-latin': { + $textitem = chr(65 + $this->listcount[$this->listnum] - 1); + break; + } + case 'lower-greek': { + $textitem = $this->unichr(945 + $this->listcount[$this->listnum] - 1); + break; + } + /* + // Types to be implemented (special handling) + case 'hebrew': { + break; + } + case 'armenian': { + break; + } + case 'georgian': { + break; + } + case 'cjk-ideographic': { + break; + } + case 'hiragana': { + break; + } + case 'katakana': { + break; + } + case 'hiragana-iroha': { + break; + } + case 'katakana-iroha': { + break; + } + */ + default: { + $textitem = $this->listcount[$this->listnum]; + } + } + if (!$this->empty_string($textitem)) { + // print ordered item + if ($this->rtl) { + $textitem = '.'.$textitem; + } else { + $textitem = $textitem.'.'; + } + $lspace += $this->GetStringWidth($textitem); + if ($this->rtl) { + $this->x += $lspace; + } else { + $this->x -= $lspace; + } + $this->Write($this->lasth, $textitem, '', false, '', false, 0, false); + } + $this->x = $tmpx; + $this->lispacer = ''; + } + + /** + * Returns current graphic variables as array. + * @return array graphic variables + * @access protected + * @since 4.2.010 (2008-11-14) + */ + protected function getGraphicVars() { + $grapvars = array( + 'FontFamily' => $this->FontFamily, + 'FontStyle' => $this->FontStyle, + 'FontSizePt' => $this->FontSizePt, + 'rMargin' => $this->rMargin, + 'lMargin' => $this->lMargin, + 'cMargin' => $this->cMargin, + 'LineWidth' => $this->LineWidth, + 'linestyleWidth' => $this->linestyleWidth, + 'linestyleCap' => $this->linestyleCap, + 'linestyleJoin' => $this->linestyleJoin, + 'linestyleDash' => $this->linestyleDash, + 'DrawColor' => $this->DrawColor, + 'FillColor' => $this->FillColor, + 'TextColor' => $this->TextColor, + 'ColorFlag' => $this->ColorFlag, + 'bgcolor' => $this->bgcolor, + 'fgcolor' => $this->fgcolor, + 'htmlvspace' => $this->htmlvspace, + 'lasth' => $this->lasth + ); + return $grapvars; + } + + /** + * Set graphic variables. + * @param $gvars array graphic variables + * @access protected + * @since 4.2.010 (2008-11-14) + */ + protected function setGraphicVars($gvars) { + $this->FontFamily = $gvars['FontFamily']; + $this->FontStyle = $gvars['FontStyle']; + $this->FontSizePt = $gvars['FontSizePt']; + $this->rMargin = $gvars['rMargin']; + $this->lMargin = $gvars['lMargin']; + $this->cMargin = $gvars['cMargin']; + $this->LineWidth = $gvars['LineWidth']; + $this->linestyleWidth = $gvars['linestyleWidth']; + $this->linestyleCap = $gvars['linestyleCap']; + $this->linestyleJoin = $gvars['linestyleJoin']; + $this->linestyleDash = $gvars['linestyleDash']; + $this->DrawColor = $gvars['DrawColor']; + $this->FillColor = $gvars['FillColor']; + $this->TextColor = $gvars['TextColor']; + $this->ColorFlag = $gvars['ColorFlag']; + $this->bgcolor = $gvars['bgcolor']; + $this->fgcolor = $gvars['fgcolor']; + $this->htmlvspace = $gvars['htmlvspace']; + //$this->lasth = $gvars['lasth']; + $this->_out(''.$this->linestyleWidth.' '.$this->linestyleCap.' '.$this->linestyleJoin.' '.$this->linestyleDash.' '.$this->DrawColor.' '.$this->FillColor.''); + if (!$this->empty_string($this->FontFamily)) { + $this->SetFont($this->FontFamily, $this->FontStyle, $this->FontSizePt); + } + } + + /** + * Returns a temporary filename for caching object on filesystem. + * @param string $prefix prefix to add to filename + * return string filename. + * @access protected + * @since 4.5.000 (2008-12-31) + */ + protected function getObjFilename($name) { + return tempnam(K_PATH_CACHE, $name.'_'); + } + + /** + * Writes data to a temporary file on filesystem. + * @param string $file file name + * @param mixed $data data to write on file + * @param boolean $append if true append data, false replace. + * @access protected + * @since 4.5.000 (2008-12-31) + */ + protected function writeDiskCache($filename, $data, $append=false) { + if ($append) { + $fmode = 'ab+'; + } else { + $fmode = 'wb+'; + } + $f = @fopen($filename, $fmode); + if (!$f) { + $this->Error('Unable to write cache file: '.$filename); + } else { + fwrite($f, $data); + fclose($f); + } + // update file lenght (needed for transactions) + if (!isset($this->cache_file_lenght['_'.$filename])) { + $this->cache_file_lenght['_'.$filename] = strlen($data); + } else { + $this->cache_file_lenght['_'.$filename] += strlen($data); + } + } + + /** + * Read data from a temporary file on filesystem. + * @param string $file file name + * @return mixed retrieved data + * @access protected + * @since 4.5.000 (2008-12-31) + */ + protected function readDiskCache($filename) { + return file_get_contents($filename); + } + + /** + * Set buffer content (always append data). + * @param string $data data + * @access protected + * @since 4.5.000 (2009-01-02) + */ + protected function setBuffer($data) { + $this->bufferlen += strlen($data); + if ($this->diskcache) { + if (!isset($this->buffer) OR $this->empty_string($this->buffer)) { + $this->buffer = $this->getObjFilename('buffer'); + } + $this->writeDiskCache($this->buffer, $data, true); + } else { + $this->buffer .= $data; + } + } + + /** + * Get buffer content. + * @return string buffer content + * @access protected + * @since 4.5.000 (2009-01-02) + */ + protected function getBuffer() { + if ($this->diskcache) { + return $this->readDiskCache($this->buffer); + } else { + return $this->buffer; + } + } + + /** + * Set page buffer content. + * @param int $page page number + * @param string $data page data + * @param boolean $append if true append data, false replace. + * @access protected + * @since 4.5.000 (2008-12-31) + */ + protected function setPageBuffer($page, $data, $append=false) { + if ($this->diskcache) { + if (!isset($this->pages[$page])) { + $this->pages[$page] = $this->getObjFilename('page'.$page); + } + $this->writeDiskCache($this->pages[$page], $data, $append); + } else { + if ($append) { + $this->pages[$page] .= $data; + } else { + $this->pages[$page] = $data; + } + } + if ($append AND isset($this->pagelen[$page])) { + $this->pagelen[$page] += strlen($data); + } else { + $this->pagelen[$page] = strlen($data); + } + } + + /** + * Get page buffer content. + * @param int $page page number + * @return string page buffer content or false in case of error + * @access protected + * @since 4.5.000 (2008-12-31) + */ + protected function getPageBuffer($page) { + if ($this->diskcache) { + return $this->readDiskCache($this->pages[$page]); + } elseif (isset($this->pages[$page])) { + return $this->pages[$page]; + } + return false; + } + + /** + * Set image buffer content. + * @param string $image image key + * @param array $data image data + * @access protected + * @since 4.5.000 (2008-12-31) + */ + protected function setImageBuffer($image, $data) { + if ($this->diskcache) { + if (!isset($this->images[$image])) { + $this->images[$image] = $this->getObjFilename('image'.$image); + } + $this->writeDiskCache($this->images[$image], serialize($data)); + } else { + $this->images[$image] = $data; + } + if (!in_array($image, $this->imagekeys)) { + $this->imagekeys[] = $image; + } + ++$this->numimages; + } + + /** + * Set image buffer content. + * @param string $image image key + * @param string $key image sub-key + * @param array $data image data + * @access protected + * @since 4.5.000 (2008-12-31) + */ + protected function setImageSubBuffer($image, $key, $data) { + if (!isset($this->images[$image])) { + $this->setImageBuffer($image, array()); + } + if ($this->diskcache) { + $tmpimg = $this->getImageBuffer($image); + $tmpimg[$key] = $data; + $this->writeDiskCache($this->images[$image], serialize($tmpimg)); + } else { + $this->images[$image][$key] = $data; + } + } + + /** + * Get page buffer content. + * @param string $image image key + * @return string image buffer content or false in case of error + * @access protected + * @since 4.5.000 (2008-12-31) + */ + protected function getImageBuffer($image) { + if ($this->diskcache AND isset($this->images[$image])) { + return unserialize($this->readDiskCache($this->images[$image])); + } elseif (isset($this->images[$image])) { + return $this->images[$image]; + } + return false; + } + + /** + * Set font buffer content. + * @param string $font font key + * @param array $data font data + * @access protected + * @since 4.5.000 (2009-01-02) + */ + protected function setFontBuffer($font, $data) { + if ($this->diskcache) { + if (!isset($this->fonts[$font])) { + $this->fonts[$font] = $this->getObjFilename('font'); + } + $this->writeDiskCache($this->fonts[$font], serialize($data)); + } else { + $this->fonts[$font] = $data; + } + if (!in_array($font, $this->fontkeys)) { + $this->fontkeys[] = $font; + } + } + + /** + * Set font buffer content. + * @param string $font font key + * @param string $key font sub-key + * @param array $data font data + * @access protected + * @since 4.5.000 (2009-01-02) + */ + protected function setFontSubBuffer($font, $key, $data) { + if (!isset($this->fonts[$font])) { + $this->setFontBuffer($font, array()); + } + if ($this->diskcache) { + $tmpfont = $this->getFontBuffer($font); + $tmpfont[$key] = $data; + $this->writeDiskCache($this->fonts[$font], serialize($tmpfont)); + } else { + $this->fonts[$font][$key] = $data; + } + } + + /** + * Get font buffer content. + * @param string $font font key + * @return string font buffer content or false in case of error + * @access protected + * @since 4.5.000 (2009-01-02) + */ + protected function getFontBuffer($font) { + if ($this->diskcache AND isset($this->fonts[$font])) { + return unserialize($this->readDiskCache($this->fonts[$font])); + } elseif (isset($this->fonts[$font])) { + return $this->fonts[$font]; + } + return false; + } + + /** + * Move a page to a previous position. + * @param int $frompage number of the source page + * @param int $topage number of the destination page (must be less than $frompage) + * @return true in case of success, false in case of error. + * @access public + * @since 4.5.000 (2009-01-02) + */ + public function movePage($frompage, $topage) { + if (($frompage > $this->numpages) OR ($frompage <= $topage)) { + return false; + } + if ($frompage == $this->page) { + // close the page before moving it + $this->endPage(); + } + // move all page-related states + $tmppage = $this->pages[$frompage]; + $tmppagedim = $this->pagedim[$frompage]; + $tmppagelen = $this->pagelen[$frompage]; + $tmpintmrk = $this->intmrk[$frompage]; + if (isset($this->footerpos[$frompage])) { + $tmpfooterpos = $this->footerpos[$frompage]; + } + if (isset($this->footerlen[$frompage])) { + $tmpfooterlen = $this->footerlen[$frompage]; + } + if (isset($this->transfmrk[$frompage])) { + $tmptransfmrk = $this->transfmrk[$frompage]; + } + if (isset($this->PageAnnots[$frompage])) { + $tmpannots = $this->PageAnnots[$frompage]; + } + if (isset($this->newpagegroup[$frompage])) { + $tmpnewpagegroup = $this->newpagegroup[$frompage]; + } + for ($i = $frompage; $i > $topage; --$i) { + $j = $i - 1; + // shift pages down + $this->pages[$i] = $this->pages[$j]; + $this->pagedim[$i] = $this->pagedim[$j]; + $this->pagelen[$i] = $this->pagelen[$j]; + $this->intmrk[$i] = $this->intmrk[$j]; + if (isset($this->footerpos[$j])) { + $this->footerpos[$i] = $this->footerpos[$j]; + } elseif (isset($this->footerpos[$i])) { + unset($this->footerpos[$i]); + } + if (isset($this->footerlen[$j])) { + $this->footerlen[$i] = $this->footerlen[$j]; + } elseif (isset($this->footerlen[$i])) { + unset($this->footerlen[$i]); + } + if (isset($this->transfmrk[$j])) { + $this->transfmrk[$i] = $this->transfmrk[$j]; + } elseif (isset($this->transfmrk[$i])) { + unset($this->transfmrk[$i]); + } + if (isset($this->PageAnnots[$j])) { + $this->PageAnnots[$i] = $this->PageAnnots[$j]; + } elseif (isset($this->PageAnnots[$i])) { + unset($this->PageAnnots[$i]); + } + if (isset($this->newpagegroup[$j])) { + $this->newpagegroup[$i] = $this->newpagegroup[$j]; + } elseif (isset($this->newpagegroup[$i])) { + unset($this->newpagegroup[$i]); + } + } + $this->pages[$topage] = $tmppage; + $this->pagedim[$topage] = $tmppagedim; + $this->pagelen[$topage] = $tmppagelen; + $this->intmrk[$topage] = $tmpintmrk; + if (isset($tmpfooterpos)) { + $this->footerpos[$topage] = $tmpfooterpos; + } elseif (isset($this->footerpos[$topage])) { + unset($this->footerpos[$topage]); + } + if (isset($tmpfooterlen)) { + $this->footerlen[$topage] = $tmpfooterlen; + } elseif (isset($this->footerlen[$topage])) { + unset($this->footerlen[$topage]); + } + if (isset($tmptransfmrk)) { + $this->transfmrk[$topage] = $tmptransfmrk; + } elseif (isset($this->transfmrk[$topage])) { + unset($this->transfmrk[$topage]); + } + if (isset($tmpannots)) { + $this->PageAnnots[$topage] = $tmpannots; + } elseif (isset($this->PageAnnots[$topage])) { + unset($this->PageAnnots[$topage]); + } + if (isset($tmpnewpagegroup)) { + $this->newpagegroup[$topage] = $tmpnewpagegroup; + } elseif (isset($this->newpagegroup[$topage])) { + unset($this->newpagegroup[$topage]); + } + // adjust outlines + $tmpoutlines = $this->outlines; + foreach ($tmpoutlines as $key => $outline) { + if (($outline['p'] >= $topage) AND ($outline['p'] < $frompage)) { + $this->outlines[$key]['p'] = $outline['p'] + 1; + } elseif ($outline['p'] == $frompage) { + $this->outlines[$key]['p'] = $topage; + } + } + // adjust links + $tmplinks = $this->links; + foreach ($tmplinks as $key => $link) { + if (($link[0] >= $topage) AND ($link[0] < $frompage)) { + $this->links[$key][0] = $link[0] + 1; + } elseif ($link[0] == $frompage) { + $this->links[$key][0] = $topage; + } + } + // adjust javascript + $tmpjavascript = $this->javascript; + global $jfrompage, $jtopage; + $jfrompage = $frompage; + $jtopage = $topage; + $this->javascript = preg_replace_callback('/this\.addField\(\'([^\']*)\',\'([^\']*)\',([0-9]+)/', + create_function('$matches', 'global $jfrompage, $jtopage; + $pagenum = intval($matches[3]) + 1; + if (($pagenum >= $jtopage) AND ($pagenum < $jfrompage)) { + $newpage = ($pagenum + 1); + } elseif ($pagenum == $jfrompage) { + $newpage = $jtopage; + } else { + $newpage = $pagenum; + } + --$newpage; + return "this.addField(\'".$matches[1]."\',\'".$matches[2]."\',".$newpage."";'), $tmpjavascript); + // return to last page + $this->lastPage(true); + return true; + } + + /** + * Remove the specified page. + * @param int $page page to remove + * @return true in case of success, false in case of error. + * @access public + * @since 4.6.004 (2009-04-23) + */ + public function deletePage($page) { + if ($page > $this->numpages) { + return false; + } + // delete current page + unset($this->pages[$page]); + unset($this->pagedim[$page]); + unset($this->pagelen[$page]); + unset($this->intmrk[$page]); + if (isset($this->footerpos[$page])) { + unset($this->footerpos[$page]); + } + if (isset($this->footerlen[$page])) { + unset($this->footerlen[$page]); + } + if (isset($this->transfmrk[$page])) { + unset($this->transfmrk[$page]); + } + if (isset($this->PageAnnots[$page])) { + unset($this->PageAnnots[$page]); + } + if (isset($this->newpagegroup[$page])) { + unset($this->newpagegroup[$page]); + } + if (isset($this->pageopen[$page])) { + unset($this->pageopen[$page]); + } + // update remaining pages + for ($i = $page; $i < $this->numpages; ++$i) { + $j = $i + 1; + // shift pages + $this->pages[$i] = $this->pages[$j]; + $this->pagedim[$i] = $this->pagedim[$j]; + $this->pagelen[$i] = $this->pagelen[$j]; + $this->intmrk[$i] = $this->intmrk[$j]; + if (isset($this->footerpos[$j])) { + $this->footerpos[$i] = $this->footerpos[$j]; + } elseif (isset($this->footerpos[$i])) { + unset($this->footerpos[$i]); + } + if (isset($this->footerlen[$j])) { + $this->footerlen[$i] = $this->footerlen[$j]; + } elseif (isset($this->footerlen[$i])) { + unset($this->footerlen[$i]); + } + if (isset($this->transfmrk[$j])) { + $this->transfmrk[$i] = $this->transfmrk[$j]; + } elseif (isset($this->transfmrk[$i])) { + unset($this->transfmrk[$i]); + } + if (isset($this->PageAnnots[$j])) { + $this->PageAnnots[$i] = $this->PageAnnots[$j]; + } elseif (isset($this->PageAnnots[$i])) { + unset($this->PageAnnots[$i]); + } + if (isset($this->newpagegroup[$j])) { + $this->newpagegroup[$i] = $this->newpagegroup[$j]; + } elseif (isset($this->newpagegroup[$i])) { + unset($this->newpagegroup[$i]); + } + if (isset($this->pageopen[$j])) { + $this->pageopen[$i] = $this->pageopen[$j]; + } elseif (isset($this->pageopen[$i])) { + unset($this->pageopen[$i]); + } + } + // remove last page + unset($this->pages[$this->numpages]); + unset($this->pagedim[$this->numpages]); + unset($this->pagelen[$this->numpages]); + unset($this->intmrk[$this->numpages]); + if (isset($this->footerpos[$this->numpages])) { + unset($this->footerpos[$this->numpages]); + } + if (isset($this->footerlen[$this->numpages])) { + unset($this->footerlen[$this->numpages]); + } + if (isset($this->transfmrk[$this->numpages])) { + unset($this->transfmrk[$this->numpages]); + } + if (isset($this->PageAnnots[$this->numpages])) { + unset($this->PageAnnots[$this->numpages]); + } + if (isset($this->newpagegroup[$this->numpages])) { + unset($this->newpagegroup[$this->numpages]); + } + if (isset($this->pageopen[$this->numpages])) { + unset($this->pageopen[$this->numpages]); + } + --$this->numpages; + $this->page = $this->numpages; + // adjust outlines + $tmpoutlines = $this->outlines; + foreach ($tmpoutlines as $key => $outline) { + if ($outline['p'] > $page) { + $this->outlines[$key]['p'] = $outline['p'] - 1; + } elseif ($outline['p'] == $page) { + unset($this->outlines[$key]); + } + } + // adjust links + $tmplinks = $this->links; + foreach ($tmplinks as $key => $link) { + if ($link[0] > $page) { + $this->links[$key][0] = $link[0] - 1; + } elseif ($link[0] == $page) { + unset($this->links[$key]); + } + } + // adjust javascript + $tmpjavascript = $this->javascript; + global $jpage; + $jpage = $page; + $this->javascript = preg_replace_callback('/this\.addField\(\'([^\']*)\',\'([^\']*)\',([0-9]+)/', + create_function('$matches', 'global $jpage; + $pagenum = intval($matches[3]) + 1; + if ($pagenum >= $jpage) { + $newpage = ($pagenum - 1); + } elseif ($pagenum == $jpage) { + $newpage = 1; + } else { + $newpage = $pagenum; + } + --$newpage; + return "this.addField(\'".$matches[1]."\',\'".$matches[2]."\',".$newpage."";'), $tmpjavascript); + // return to last page + $this->lastPage(true); + return true; + } + + /** + * Output a Table of Content Index (TOC). + * You can override this method to achieve different styles. + * @param int $page page number where this TOC should be inserted (leave empty for current page). + * @param string $numbersfont set the font for page numbers (please use monospaced font for better alignment). + * @param string $filler string used to fill the space between text and page number. + * @access public + * @author Nicola Asuni + * @since 4.5.000 (2009-01-02) + */ + public function addTOC($page='', $numbersfont='', $filler='.') { + $fontsize = $this->FontSizePt; + $fontfamily = $this->FontFamily; + $fontstyle = $this->FontStyle; + $w = $this->w - $this->lMargin - $this->rMargin; + $spacer = $this->GetStringWidth(' ') * 4; + $page_first = $this->getPage(); + $lmargin = $this->lMargin; + $rmargin = $this->rMargin; + $x_start = $this->GetX(); + if ($this->empty_string($numbersfont)) { + $numbersfont = $this->default_monospaced_font; + } + if ($this->empty_string($filler)) { + $filler = ' '; + } + if ($this->empty_string($page)) { + $gap = ' '; + } else { + $gap = ''; + } + foreach ($this->outlines as $key => $outline) { + if ($this->rtl) { + $aligntext = 'R'; + $alignnum = 'L'; + } else { + $aligntext = 'L'; + $alignnum = 'R'; + } + if ($outline['l'] == 0) { + $this->SetFont($fontfamily, $fontstyle.'B', $fontsize); + } else { + $this->SetFont($fontfamily, $fontstyle, $fontsize - $outline['l']); + } + $indent = ($spacer * $outline['l']); + if ($this->rtl) { + $this->rMargin += $indent; + $this->x -= $indent; + } else { + $this->lMargin += $indent; + $this->x += $indent; + } + $link = $this->AddLink(); + $this->SetLink($link, 0, $outline['p']); + // write the text + $this->Write(0, $outline['t'], $link, 0, $aligntext, false, 0, false, false, 0); + $this->SetFont($numbersfont, $fontstyle, $fontsize); + if ($this->empty_string($page)) { + $pagenum = $outline['p']; + } else { + // placemark to be replaced with the correct number + $pagenum = '{#'.($outline['p']).'}'; + if (($this->CurrentFont['type'] == 'TrueTypeUnicode') OR ($this->CurrentFont['type'] == 'cidfont0')) { + $pagenum = '{'.$pagenum.'}'; + } + } + $numwidth = $this->GetStringWidth($pagenum); + if ($this->rtl) { + $tw = $this->x - $this->lMargin; + } else { + $tw = $this->w - $this->rMargin - $this->x; + } + $fw = $tw - $numwidth - $this->GetStringWidth(' '); + $numfills = floor($fw / $this->GetStringWidth($filler)); + if ($numfills > 0) { + $rowfill = str_repeat($filler, $numfills); + } else { + $rowfill = ''; + } + if ($this->rtl) { + $pagenum = $pagenum.$gap.$rowfill.' '; + } else { + $pagenum = ' '.$rowfill.$gap.$pagenum; + } + // write the number + //$this->SetX($x_start); + $this->Cell($tw, 0, $pagenum, 0, 1, $alignnum, 0, $link, 0); + $this->SetX($x_start); + $this->lMargin = $lmargin; + $this->rMargin = $rmargin; + } + $page_last = $this->getPage(); + $numpages = $page_last - $page_first + 1; + if (!$this->empty_string($page)) { + for ($p = $page_first; $p <= $page_last; ++$p) { + // get page data + $temppage = $this->getPageBuffer($p); + for ($n = 1; $n <= $this->numpages; ++$n) { + // update page numbers + $k = '{#'.$n.'}'; + $ku = '{'.$k.'}'; + $alias_a = $this->_escape($k); + $alias_au = $this->_escape('{'.$k.'}'); + if ($this->isunicode) { + $alias_b = $this->_escape($this->UTF8ToLatin1($k)); + $alias_bu = $this->_escape($this->UTF8ToLatin1($ku)); + $alias_c = $this->_escape($this->utf8StrRev($k, false, $this->tmprtl)); + $alias_cu = $this->_escape($this->utf8StrRev($ku, false, $this->tmprtl)); + } + if ($n >= $page) { + $np = $n + $numpages; + } else { + $np = $n; + } + $ns = $this->formatTOCPageNumber($np); + $nu = $ns; + $sdiff = strlen($k) - strlen($ns) - 1; + $sdiffu = strlen($ku) - strlen($ns) - 1; + $sfill = str_repeat($filler, $sdiff); + $sfillu = str_repeat($filler, $sdiffu); + if ($this->rtl) { + $ns = $ns.' '.$sfill; + $nu = $nu.' '.$sfillu; + } else { + $ns = $sfill.' '.$ns; + $nu = $sfillu.' '.$nu; + } + $nu = $this->UTF8ToUTF16BE($nu, false); + $temppage = str_replace($alias_au, $nu, $temppage); + if ($this->isunicode) { + $temppage = str_replace($alias_bu, $nu, $temppage); + $temppage = str_replace($alias_cu, $nu, $temppage); + $temppage = str_replace($alias_b, $ns, $temppage); + $temppage = str_replace($alias_c, $ns, $temppage); + } + $temppage = str_replace($alias_a, $ns, $temppage); + } + // save changes + $this->setPageBuffer($p, $temppage); + } + // move pages + for ($i = 0; $i < $numpages; ++$i) { + $this->movePage($page_last, $page); + } + } + $this->SetFont($fontfamily, $fontstyle, $fontsize); + } + + /** + * Stores a copy of the current TCPDF object used for undo operation. + * @access public + * @since 4.5.029 (2009-03-19) + */ + public function startTransaction() { + if (isset($this->objcopy)) { + // remove previous copy + $this->commitTransaction(); + } + // clone current object + $this->objcopy = $this->objclone($this); + } + + /** + * Delete the copy of the current TCPDF object used for undo operation. + * @access public + * @since 4.5.029 (2009-03-19) + */ + public function commitTransaction() { + if (isset($this->objcopy)) { + $this->objcopy->_destroy(true, true); + unset($this->objcopy); + } + } + + /** + * This method allows to undo the latest transaction by returning the latest saved TCPDF object with startTransaction(). + * @return TCPDF object. + * @access public + * @since 4.5.029 (2009-03-19) + */ + public function rollbackTransaction() { + if (isset($this->objcopy)) { + if (isset($this->objcopy->diskcache) AND $this->objcopy->diskcache) { + // truncate files to previous values + foreach ($this->objcopy->cache_file_lenght as $file => $lenght) { + $file = substr($file, 1); + $handle = fopen($file, 'r+'); + ftruncate($handle, $lenght); + } + } + $this->_destroy(true, true); + return $this->objcopy; + } + return $this; + } + + /** + * Creates a copy of a class object + * @param object $object class object to be cloned + * @return cloned object + * @access public + * @since 4.5.029 (2009-03-19) + */ + public function objclone($object) { + return @clone($object); + } + + /** + * Determine whether a string is empty. + * @param srting $str string to be checked + * @return boolean true if string is empty + * @access public + * @since 4.5.044 (2009-04-16) + */ + public function empty_string($str) { + return (is_null($str) OR (is_string($str) AND (strlen($str) == 0))); + } + + } // END OF TCPDF CLASS +} +//============================================================+ +// END OF FILE +//============================================================+ +?> diff --git a/include/tcpdf/unicode_data.php b/include/tcpdf/unicode_data.php new file mode 100644 index 00000000..c149cef3 --- /dev/null +++ b/include/tcpdf/unicode_data.php @@ -0,0 +1,18383 @@ +. +// +// See LICENSE.TXT file for more information. +// ---------------------------------------------------------------------------- +// +// Description : Unicode Include file for TCPDF. +// +// Author: Nicola Asuni +// +// (c) Copyright: +// Nicola Asuni +// Tecnick.com s.r.l. +// Via Della Pace, 11 +// 09044 Quartucciu (CA) +// ITALY +// www.tecnick.com +// info@tecnick.com +//============================================================+ +// THANKS TO +// Efthimios Mavrogeorgiadis +// Saleh AlMatrafe + +/** + * Unicode Include file for TCPDF. + * @author Nicola Asuni + * @copyright 2004-2009 Nicola Asuni - Tecnick.com S.r.l (www.tecnick.com) Via Della Pace, 11 - 09044 - Quartucciu (CA) - ITALY - www.tecnick.com - info@tecnick.com + * @package com.tecnick.tcpdf + * @link http://www.tcpdf.org + * @license http://www.gnu.org/copyleft/lesser.html LGPL + * @since 2.1.000 (2008-01-08) +*/ + +/** +* Left-to-Right Mark +*/ +define('K_LRM', 8206); +/** +* Right-to-Left Mark +*/ +define('K_RLM', 8207); +/** +* Left-to-Right Embedding +*/ +define('K_LRE', 8234); +/** +* Right-to-Left Embedding +*/ +define('K_RLE', 8235); +/** +* Pop Directional Format +*/ +define('K_PDF', 8236); +/** +* Left-to-Right Override +*/ +define('K_LRO', 8237); +/** +* Right-to-Left Override +*/ +define('K_RLO', 8238); + +/* + * Pattern to test RTL (Righ-To-Left) strings using regular expressions. + */ +define('K_RE_PATTERN_RTL', "/( + \xD6\xBE # R + | \xD7[\x80\x83\x86\x90-\xAA\xB0-\xB4] # R + | \xDF[\x80-\xAA\xB4\xB5\xBA] # R + | \xE2\x80\x8F # R + | \xEF\xAC[\x9D\x9F\xA0-\xA8\xAA-\xB6\xB8-\xBC\xBE] # R + | \xEF\xAD[\x80\x81\x83\x84\x86-\x8F] # R + | \xF0\x90\xA0[\x80-\x85\x88\x8A-\xB5\xB7\xB8\xBC\xBF] # R + | \xF0\x90\xA4[\x80-\x99] # R + | \xF0\x90\xA8[\x80\x90-\x93\x95-\x97\x99-\xB3] # R + | \xF0\x90\xA9[\x80-\x87\x90-\x98] # R + | \xE2\x80[\xAB\xAE] # RLE & RLO + )/x"); + +/* + * Pattern to test Arabic strings using regular expressions. + * source: http://www.w3.org/International/questions/qa-forms-utf-8 + */ +define("K_RE_PATTERN_ARABIC", "/( + \xD8[\x80-\x83\x8B\x8D\x9B\x9E\x9F\xA1-\xBA] # AL + | \xD9[\x80-\x8A\xAD-\xAF\xB1-\xBF] # AL + | \xDA[\x80-\xBF] # AL + | \xDB[\x80-\x95\x9D\xA5\xA6\xAE\xAF\xBA-\xBF] # AL + | \xDC[\x80-\x8D\x90\x92-\xAF] # AL + | \xDD[\x8D-\xAD] # AL + | \xDE[\x80-\xA5\xB1] # AL + | \xEF\xAD[\x90-\xBF] # AL + | \xEF\xAE[\x80-\xB1] # AL + | \xEF\xAF[\x93-\xBF] # AL + | \xEF[\xB0-\xB3][\x80-\xBF] # AL + | \xEF\xB4[\x80-\xBD] # AL + | \xEF\xB5[\x90-\xBF] # AL + | \xEF\xB6[\x80-\x8F\x92-\xBF] # AL + | \xEF\xB7[\x80-\x87\xB0-\xBC] # AL + | \xEF\xB9[\xB0-\xB4\xB6-\xBF] # AL + | \xEF\xBA[\x80-\xBF] # AL + | \xEF\xBB[\x80-\xBC] # AL + | \xD9[\xA0-\xA9\xAB\xAC] # AN + )/x"); + +/** + * Array of unicode types + */ +global $unicode; +$unicode = array( +0=>'BN', +1=>'BN', +2=>'BN', +3=>'BN', +4=>'BN', +5=>'BN', +6=>'BN', +7=>'BN', +8=>'BN', +9=>'S', +10=>'B', +11=>'S', +12=>'WS', +13=>'B', +14=>'BN', +15=>'BN', +16=>'BN', +17=>'BN', +18=>'BN', +19=>'BN', +20=>'BN', +21=>'BN', +22=>'BN', +23=>'BN', +24=>'BN', +25=>'BN', +26=>'BN', +27=>'BN', +28=>'B', +29=>'B', +30=>'B', +31=>'S', +32=>'WS', +33=>'ON', +34=>'ON', +35=>'ET', +36=>'ET', +37=>'ET', +38=>'ON', +39=>'ON', +40=>'ON', +41=>'ON', +42=>'ON', +43=>'ES', +44=>'CS', +45=>'ES', +46=>'CS', +47=>'CS', +48=>'EN', +49=>'EN', +50=>'EN', +51=>'EN', +52=>'EN', +53=>'EN', +54=>'EN', +55=>'EN', +56=>'EN', +57=>'EN', +58=>'CS', +59=>'ON', +60=>'ON', +61=>'ON', +62=>'ON', +63=>'ON', +64=>'ON', +65=>'L', +66=>'L', +67=>'L', +68=>'L', +69=>'L', +70=>'L', +71=>'L', +72=>'L', +73=>'L', +74=>'L', +75=>'L', +76=>'L', +77=>'L', +78=>'L', +79=>'L', +80=>'L', +81=>'L', +82=>'L', +83=>'L', +84=>'L', +85=>'L', +86=>'L', +87=>'L', +88=>'L', +89=>'L', +90=>'L', +91=>'ON', +92=>'ON', +93=>'ON', +94=>'ON', +95=>'ON', +96=>'ON', +97=>'L', +98=>'L', +99=>'L', +100=>'L', +101=>'L', +102=>'L', +103=>'L', +104=>'L', +105=>'L', +106=>'L', +107=>'L', +108=>'L', +109=>'L', +110=>'L', +111=>'L', +112=>'L', +113=>'L', +114=>'L', +115=>'L', +116=>'L', +117=>'L', +118=>'L', +119=>'L', +120=>'L', +121=>'L', +122=>'L', +123=>'ON', +124=>'ON', +125=>'ON', +126=>'ON', +127=>'BN', +128=>'BN', +129=>'BN', +130=>'BN', +131=>'BN', +132=>'BN', +133=>'B', +134=>'BN', +135=>'BN', +136=>'BN', +137=>'BN', +138=>'BN', +139=>'BN', +140=>'BN', +141=>'BN', +142=>'BN', +143=>'BN', +144=>'BN', +145=>'BN', +146=>'BN', +147=>'BN', +148=>'BN', +149=>'BN', +150=>'BN', +151=>'BN', +152=>'BN', +153=>'BN', +154=>'BN', +155=>'BN', +156=>'BN', +157=>'BN', +158=>'BN', +159=>'BN', +160=>'CS', +161=>'ON', +162=>'ET', +163=>'ET', +164=>'ET', +165=>'ET', +166=>'ON', +167=>'ON', +168=>'ON', +169=>'ON', +170=>'L', +171=>'ON', +172=>'ON', +173=>'BN', +174=>'ON', +175=>'ON', +176=>'ET', +177=>'ET', +178=>'EN', +179=>'EN', +180=>'ON', +181=>'L', +182=>'ON', +183=>'ON', +184=>'ON', +185=>'EN', +186=>'L', +187=>'ON', +188=>'ON', +189=>'ON', +190=>'ON', +191=>'ON', +192=>'L', +193=>'L', +194=>'L', +195=>'L', +196=>'L', +197=>'L', +198=>'L', +199=>'L', +200=>'L', +201=>'L', +202=>'L', +203=>'L', +204=>'L', +205=>'L', +206=>'L', +207=>'L', +208=>'L', +209=>'L', +210=>'L', +211=>'L', +212=>'L', +213=>'L', +214=>'L', +215=>'ON', +216=>'L', +217=>'L', +218=>'L', +219=>'L', +220=>'L', +221=>'L', +222=>'L', +223=>'L', +224=>'L', +225=>'L', +226=>'L', +227=>'L', +228=>'L', +229=>'L', +230=>'L', +231=>'L', +232=>'L', +233=>'L', +234=>'L', +235=>'L', +236=>'L', +237=>'L', +238=>'L', +239=>'L', +240=>'L', +241=>'L', +242=>'L', +243=>'L', +244=>'L', +245=>'L', +246=>'L', +247=>'ON', +248=>'L', +249=>'L', +250=>'L', +251=>'L', +252=>'L', +253=>'L', +254=>'L', +255=>'L', +256=>'L', +257=>'L', +258=>'L', +259=>'L', +260=>'L', +261=>'L', +262=>'L', +263=>'L', +264=>'L', +265=>'L', +266=>'L', +267=>'L', +268=>'L', +269=>'L', +270=>'L', +271=>'L', +272=>'L', +273=>'L', +274=>'L', +275=>'L', +276=>'L', +277=>'L', +278=>'L', +279=>'L', +280=>'L', +281=>'L', +282=>'L', +283=>'L', +284=>'L', +285=>'L', +286=>'L', +287=>'L', +288=>'L', +289=>'L', +290=>'L', +291=>'L', +292=>'L', +293=>'L', +294=>'L', +295=>'L', +296=>'L', +297=>'L', +298=>'L', +299=>'L', +300=>'L', +301=>'L', +302=>'L', +303=>'L', +304=>'L', +305=>'L', +306=>'L', +307=>'L', +308=>'L', +309=>'L', +310=>'L', +311=>'L', +312=>'L', +313=>'L', +314=>'L', +315=>'L', +316=>'L', +317=>'L', +318=>'L', +319=>'L', +320=>'L', +321=>'L', +322=>'L', +323=>'L', +324=>'L', +325=>'L', +326=>'L', +327=>'L', +328=>'L', +329=>'L', +330=>'L', +331=>'L', +332=>'L', +333=>'L', +334=>'L', +335=>'L', +336=>'L', +337=>'L', +338=>'L', +339=>'L', +340=>'L', +341=>'L', +342=>'L', +343=>'L', +344=>'L', +345=>'L', +346=>'L', +347=>'L', +348=>'L', +349=>'L', +350=>'L', +351=>'L', +352=>'L', +353=>'L', +354=>'L', +355=>'L', +356=>'L', +357=>'L', +358=>'L', +359=>'L', +360=>'L', +361=>'L', +362=>'L', +363=>'L', +364=>'L', +365=>'L', +366=>'L', +367=>'L', +368=>'L', +369=>'L', +370=>'L', +371=>'L', +372=>'L', +373=>'L', +374=>'L', +375=>'L', +376=>'L', +377=>'L', +378=>'L', +379=>'L', +380=>'L', +381=>'L', +382=>'L', +383=>'L', +384=>'L', +385=>'L', +386=>'L', +387=>'L', +388=>'L', +389=>'L', +390=>'L', +391=>'L', +392=>'L', +393=>'L', +394=>'L', +395=>'L', +396=>'L', +397=>'L', +398=>'L', +399=>'L', +400=>'L', +401=>'L', +402=>'L', +403=>'L', +404=>'L', +405=>'L', +406=>'L', +407=>'L', +408=>'L', +409=>'L', +410=>'L', +411=>'L', +412=>'L', +413=>'L', +414=>'L', +415=>'L', +416=>'L', +417=>'L', +418=>'L', +419=>'L', +420=>'L', +421=>'L', +422=>'L', +423=>'L', +424=>'L', +425=>'L', +426=>'L', +427=>'L', +428=>'L', +429=>'L', +430=>'L', +431=>'L', +432=>'L', +433=>'L', +434=>'L', +435=>'L', +436=>'L', +437=>'L', +438=>'L', +439=>'L', +440=>'L', +441=>'L', +442=>'L', +443=>'L', +444=>'L', +445=>'L', +446=>'L', +447=>'L', +448=>'L', +449=>'L', +450=>'L', +451=>'L', +452=>'L', +453=>'L', +454=>'L', +455=>'L', +456=>'L', +457=>'L', +458=>'L', +459=>'L', +460=>'L', +461=>'L', +462=>'L', +463=>'L', +464=>'L', +465=>'L', +466=>'L', +467=>'L', +468=>'L', +469=>'L', +470=>'L', +471=>'L', +472=>'L', +473=>'L', +474=>'L', +475=>'L', +476=>'L', +477=>'L', +478=>'L', +479=>'L', +480=>'L', +481=>'L', +482=>'L', +483=>'L', +484=>'L', +485=>'L', +486=>'L', +487=>'L', +488=>'L', +489=>'L', +490=>'L', +491=>'L', +492=>'L', +493=>'L', +494=>'L', +495=>'L', +496=>'L', +497=>'L', +498=>'L', +499=>'L', +500=>'L', +501=>'L', +502=>'L', +503=>'L', +504=>'L', +505=>'L', +506=>'L', +507=>'L', +508=>'L', +509=>'L', +510=>'L', +511=>'L', +512=>'L', +513=>'L', +514=>'L', +515=>'L', +516=>'L', +517=>'L', +518=>'L', +519=>'L', +520=>'L', +521=>'L', +522=>'L', +523=>'L', +524=>'L', +525=>'L', +526=>'L', +527=>'L', +528=>'L', +529=>'L', +530=>'L', +531=>'L', +532=>'L', +533=>'L', +534=>'L', +535=>'L', +536=>'L', +537=>'L', +538=>'L', +539=>'L', +540=>'L', +541=>'L', +542=>'L', +543=>'L', +544=>'L', +545=>'L', +546=>'L', +547=>'L', +548=>'L', +549=>'L', +550=>'L', +551=>'L', +552=>'L', +553=>'L', +554=>'L', +555=>'L', +556=>'L', +557=>'L', +558=>'L', +559=>'L', +560=>'L', +561=>'L', +562=>'L', +563=>'L', +564=>'L', +565=>'L', +566=>'L', +567=>'L', +568=>'L', +569=>'L', +570=>'L', +571=>'L', +572=>'L', +573=>'L', +574=>'L', +575=>'L', +576=>'L', +577=>'L', +578=>'L', +579=>'L', +580=>'L', +581=>'L', +582=>'L', +583=>'L', +584=>'L', +585=>'L', +586=>'L', +587=>'L', +588=>'L', +589=>'L', +590=>'L', +591=>'L', +592=>'L', +593=>'L', +594=>'L', +595=>'L', +596=>'L', +597=>'L', +598=>'L', +599=>'L', +600=>'L', +601=>'L', +602=>'L', +603=>'L', +604=>'L', +605=>'L', +606=>'L', +607=>'L', +608=>'L', +609=>'L', +610=>'L', +611=>'L', +612=>'L', +613=>'L', +614=>'L', +615=>'L', +616=>'L', +617=>'L', +618=>'L', +619=>'L', +620=>'L', +621=>'L', +622=>'L', +623=>'L', +624=>'L', +625=>'L', +626=>'L', +627=>'L', +628=>'L', +629=>'L', +630=>'L', +631=>'L', +632=>'L', +633=>'L', +634=>'L', +635=>'L', +636=>'L', +637=>'L', +638=>'L', +639=>'L', +640=>'L', +641=>'L', +642=>'L', +643=>'L', +644=>'L', +645=>'L', +646=>'L', +647=>'L', +648=>'L', +649=>'L', +650=>'L', +651=>'L', +652=>'L', +653=>'L', +654=>'L', +655=>'L', +656=>'L', +657=>'L', +658=>'L', +659=>'L', +660=>'L', +661=>'L', +662=>'L', +663=>'L', +664=>'L', +665=>'L', +666=>'L', +667=>'L', +668=>'L', +669=>'L', +670=>'L', +671=>'L', +672=>'L', +673=>'L', +674=>'L', +675=>'L', +676=>'L', +677=>'L', +678=>'L', +679=>'L', +680=>'L', +681=>'L', +682=>'L', +683=>'L', +684=>'L', +685=>'L', +686=>'L', +687=>'L', +688=>'L', +689=>'L', +690=>'L', +691=>'L', +692=>'L', +693=>'L', +694=>'L', +695=>'L', +696=>'L', +697=>'ON', +698=>'ON', +699=>'L', +700=>'L', +701=>'L', +702=>'L', +703=>'L', +704=>'L', +705=>'L', +706=>'ON', +707=>'ON', +708=>'ON', +709=>'ON', +710=>'ON', +711=>'ON', +712=>'ON', +713=>'ON', +714=>'ON', +715=>'ON', +716=>'ON', +717=>'ON', +718=>'ON', +719=>'ON', +720=>'L', +721=>'L', +722=>'ON', +723=>'ON', +724=>'ON', +725=>'ON', +726=>'ON', +727=>'ON', +728=>'ON', +729=>'ON', +730=>'ON', +731=>'ON', +732=>'ON', +733=>'ON', +734=>'ON', +735=>'ON', +736=>'L', +737=>'L', +738=>'L', +739=>'L', +740=>'L', +741=>'ON', +742=>'ON', +743=>'ON', +744=>'ON', +745=>'ON', +746=>'ON', +747=>'ON', +748=>'ON', +749=>'ON', +750=>'L', +751=>'ON', +752=>'ON', +753=>'ON', +754=>'ON', +755=>'ON', +756=>'ON', +757=>'ON', +758=>'ON', +759=>'ON', +760=>'ON', +761=>'ON', +762=>'ON', +763=>'ON', +764=>'ON', +765=>'ON', +766=>'ON', +767=>'ON', +768=>'NSM', +769=>'NSM', +770=>'NSM', +771=>'NSM', +772=>'NSM', +773=>'NSM', +774=>'NSM', +775=>'NSM', +776=>'NSM', +777=>'NSM', +778=>'NSM', +779=>'NSM', +780=>'NSM', +781=>'NSM', +782=>'NSM', +783=>'NSM', +784=>'NSM', +785=>'NSM', +786=>'NSM', +787=>'NSM', +788=>'NSM', +789=>'NSM', +790=>'NSM', +791=>'NSM', +792=>'NSM', +793=>'NSM', +794=>'NSM', +795=>'NSM', +796=>'NSM', +797=>'NSM', +798=>'NSM', +799=>'NSM', +800=>'NSM', +801=>'NSM', +802=>'NSM', +803=>'NSM', +804=>'NSM', +805=>'NSM', +806=>'NSM', +807=>'NSM', +808=>'NSM', +809=>'NSM', +810=>'NSM', +811=>'NSM', +812=>'NSM', +813=>'NSM', +814=>'NSM', +815=>'NSM', +816=>'NSM', +817=>'NSM', +818=>'NSM', +819=>'NSM', +820=>'NSM', +821=>'NSM', +822=>'NSM', +823=>'NSM', +824=>'NSM', +825=>'NSM', +826=>'NSM', +827=>'NSM', +828=>'NSM', +829=>'NSM', +830=>'NSM', +831=>'NSM', +832=>'NSM', +833=>'NSM', +834=>'NSM', +835=>'NSM', +836=>'NSM', +837=>'NSM', +838=>'NSM', +839=>'NSM', +840=>'NSM', +841=>'NSM', +842=>'NSM', +843=>'NSM', +844=>'NSM', +845=>'NSM', +846=>'NSM', +847=>'NSM', +848=>'NSM', +849=>'NSM', +850=>'NSM', +851=>'NSM', +852=>'NSM', +853=>'NSM', +854=>'NSM', +855=>'NSM', +856=>'NSM', +857=>'NSM', +858=>'NSM', +859=>'NSM', +860=>'NSM', +861=>'NSM', +862=>'NSM', +863=>'NSM', +864=>'NSM', +865=>'NSM', +866=>'NSM', +867=>'NSM', +868=>'NSM', +869=>'NSM', +870=>'NSM', +871=>'NSM', +872=>'NSM', +873=>'NSM', +874=>'NSM', +875=>'NSM', +876=>'NSM', +877=>'NSM', +878=>'NSM', +879=>'NSM', +884=>'ON', +885=>'ON', +890=>'L', +891=>'L', +892=>'L', +893=>'L', +894=>'ON', +900=>'ON', +901=>'ON', +902=>'L', +903=>'ON', +904=>'L', +905=>'L', +906=>'L', +908=>'L', +910=>'L', +911=>'L', +912=>'L', +913=>'L', +914=>'L', +915=>'L', +916=>'L', +917=>'L', +918=>'L', +919=>'L', +920=>'L', +921=>'L', +922=>'L', +923=>'L', +924=>'L', +925=>'L', +926=>'L', +927=>'L', +928=>'L', +929=>'L', +931=>'L', +932=>'L', +933=>'L', +934=>'L', +935=>'L', +936=>'L', +937=>'L', +938=>'L', +939=>'L', +940=>'L', +941=>'L', +942=>'L', +943=>'L', +944=>'L', +945=>'L', +946=>'L', +947=>'L', +948=>'L', +949=>'L', +950=>'L', +951=>'L', +952=>'L', +953=>'L', +954=>'L', +955=>'L', +956=>'L', +957=>'L', +958=>'L', +959=>'L', +960=>'L', +961=>'L', +962=>'L', +963=>'L', +964=>'L', +965=>'L', +966=>'L', +967=>'L', +968=>'L', +969=>'L', +970=>'L', +971=>'L', +972=>'L', +973=>'L', +974=>'L', +976=>'L', +977=>'L', +978=>'L', +979=>'L', +980=>'L', +981=>'L', +982=>'L', +983=>'L', +984=>'L', +985=>'L', +986=>'L', +987=>'L', +988=>'L', +989=>'L', +990=>'L', +991=>'L', +992=>'L', +993=>'L', +994=>'L', +995=>'L', +996=>'L', +997=>'L', +998=>'L', +999=>'L', +1000=>'L', +1001=>'L', +1002=>'L', +1003=>'L', +1004=>'L', +1005=>'L', +1006=>'L', +1007=>'L', +1008=>'L', +1009=>'L', +1010=>'L', +1011=>'L', +1012=>'L', +1013=>'L', +1014=>'ON', +1015=>'L', +1016=>'L', +1017=>'L', +1018=>'L', +1019=>'L', +1020=>'L', +1021=>'L', +1022=>'L', +1023=>'L', +1024=>'L', +1025=>'L', +1026=>'L', +1027=>'L', +1028=>'L', +1029=>'L', +1030=>'L', +1031=>'L', +1032=>'L', +1033=>'L', +1034=>'L', +1035=>'L', +1036=>'L', +1037=>'L', +1038=>'L', +1039=>'L', +1040=>'L', +1041=>'L', +1042=>'L', +1043=>'L', +1044=>'L', +1045=>'L', +1046=>'L', +1047=>'L', +1048=>'L', +1049=>'L', +1050=>'L', +1051=>'L', +1052=>'L', +1053=>'L', +1054=>'L', +1055=>'L', +1056=>'L', +1057=>'L', +1058=>'L', +1059=>'L', +1060=>'L', +1061=>'L', +1062=>'L', +1063=>'L', +1064=>'L', +1065=>'L', +1066=>'L', +1067=>'L', +1068=>'L', +1069=>'L', +1070=>'L', +1071=>'L', +1072=>'L', +1073=>'L', +1074=>'L', +1075=>'L', +1076=>'L', +1077=>'L', +1078=>'L', +1079=>'L', +1080=>'L', +1081=>'L', +1082=>'L', +1083=>'L', +1084=>'L', +1085=>'L', +1086=>'L', +1087=>'L', +1088=>'L', +1089=>'L', +1090=>'L', +1091=>'L', +1092=>'L', +1093=>'L', +1094=>'L', +1095=>'L', +1096=>'L', +1097=>'L', +1098=>'L', +1099=>'L', +1100=>'L', +1101=>'L', +1102=>'L', +1103=>'L', +1104=>'L', +1105=>'L', +1106=>'L', +1107=>'L', +1108=>'L', +1109=>'L', +1110=>'L', +1111=>'L', +1112=>'L', +1113=>'L', +1114=>'L', +1115=>'L', +1116=>'L', +1117=>'L', +1118=>'L', +1119=>'L', +1120=>'L', +1121=>'L', +1122=>'L', +1123=>'L', +1124=>'L', +1125=>'L', +1126=>'L', +1127=>'L', +1128=>'L', +1129=>'L', +1130=>'L', +1131=>'L', +1132=>'L', +1133=>'L', +1134=>'L', +1135=>'L', +1136=>'L', +1137=>'L', +1138=>'L', +1139=>'L', +1140=>'L', +1141=>'L', +1142=>'L', +1143=>'L', +1144=>'L', +1145=>'L', +1146=>'L', +1147=>'L', +1148=>'L', +1149=>'L', +1150=>'L', +1151=>'L', +1152=>'L', +1153=>'L', +1154=>'L', +1155=>'NSM', +1156=>'NSM', +1157=>'NSM', +1158=>'NSM', +1160=>'NSM', +1161=>'NSM', +1162=>'L', +1163=>'L', +1164=>'L', +1165=>'L', +1166=>'L', +1167=>'L', +1168=>'L', +1169=>'L', +1170=>'L', +1171=>'L', +1172=>'L', +1173=>'L', +1174=>'L', +1175=>'L', +1176=>'L', +1177=>'L', +1178=>'L', +1179=>'L', +1180=>'L', +1181=>'L', +1182=>'L', +1183=>'L', +1184=>'L', +1185=>'L', +1186=>'L', +1187=>'L', +1188=>'L', +1189=>'L', +1190=>'L', +1191=>'L', +1192=>'L', +1193=>'L', +1194=>'L', +1195=>'L', +1196=>'L', +1197=>'L', +1198=>'L', +1199=>'L', +1200=>'L', +1201=>'L', +1202=>'L', +1203=>'L', +1204=>'L', +1205=>'L', +1206=>'L', +1207=>'L', +1208=>'L', +1209=>'L', +1210=>'L', +1211=>'L', +1212=>'L', +1213=>'L', +1214=>'L', +1215=>'L', +1216=>'L', +1217=>'L', +1218=>'L', +1219=>'L', +1220=>'L', +1221=>'L', +1222=>'L', +1223=>'L', +1224=>'L', +1225=>'L', +1226=>'L', +1227=>'L', +1228=>'L', +1229=>'L', +1230=>'L', +1231=>'L', +1232=>'L', +1233=>'L', +1234=>'L', +1235=>'L', +1236=>'L', +1237=>'L', +1238=>'L', +1239=>'L', +1240=>'L', +1241=>'L', +1242=>'L', +1243=>'L', +1244=>'L', +1245=>'L', +1246=>'L', +1247=>'L', +1248=>'L', +1249=>'L', +1250=>'L', +1251=>'L', +1252=>'L', +1253=>'L', +1254=>'L', +1255=>'L', +1256=>'L', +1257=>'L', +1258=>'L', +1259=>'L', +1260=>'L', +1261=>'L', +1262=>'L', +1263=>'L', +1264=>'L', +1265=>'L', +1266=>'L', +1267=>'L', +1268=>'L', +1269=>'L', +1270=>'L', +1271=>'L', +1272=>'L', +1273=>'L', +1274=>'L', +1275=>'L', +1276=>'L', +1277=>'L', +1278=>'L', +1279=>'L', +1280=>'L', +1281=>'L', +1282=>'L', +1283=>'L', +1284=>'L', +1285=>'L', +1286=>'L', +1287=>'L', +1288=>'L', +1289=>'L', +1290=>'L', +1291=>'L', +1292=>'L', +1293=>'L', +1294=>'L', +1295=>'L', +1296=>'L', +1297=>'L', +1298=>'L', +1299=>'L', +1329=>'L', +1330=>'L', +1331=>'L', +1332=>'L', +1333=>'L', +1334=>'L', +1335=>'L', +1336=>'L', +1337=>'L', +1338=>'L', +1339=>'L', +1340=>'L', +1341=>'L', +1342=>'L', +1343=>'L', +1344=>'L', +1345=>'L', +1346=>'L', +1347=>'L', +1348=>'L', +1349=>'L', +1350=>'L', +1351=>'L', +1352=>'L', +1353=>'L', +1354=>'L', +1355=>'L', +1356=>'L', +1357=>'L', +1358=>'L', +1359=>'L', +1360=>'L', +1361=>'L', +1362=>'L', +1363=>'L', +1364=>'L', +1365=>'L', +1366=>'L', +1369=>'L', +1370=>'L', +1371=>'L', +1372=>'L', +1373=>'L', +1374=>'L', +1375=>'L', +1377=>'L', +1378=>'L', +1379=>'L', +1380=>'L', +1381=>'L', +1382=>'L', +1383=>'L', +1384=>'L', +1385=>'L', +1386=>'L', +1387=>'L', +1388=>'L', +1389=>'L', +1390=>'L', +1391=>'L', +1392=>'L', +1393=>'L', +1394=>'L', +1395=>'L', +1396=>'L', +1397=>'L', +1398=>'L', +1399=>'L', +1400=>'L', +1401=>'L', +1402=>'L', +1403=>'L', +1404=>'L', +1405=>'L', +1406=>'L', +1407=>'L', +1408=>'L', +1409=>'L', +1410=>'L', +1411=>'L', +1412=>'L', +1413=>'L', +1414=>'L', +1415=>'L', +1417=>'L', +1418=>'ON', +1425=>'NSM', +1426=>'NSM', +1427=>'NSM', +1428=>'NSM', +1429=>'NSM', +1430=>'NSM', +1431=>'NSM', +1432=>'NSM', +1433=>'NSM', +1434=>'NSM', +1435=>'NSM', +1436=>'NSM', +1437=>'NSM', +1438=>'NSM', +1439=>'NSM', +1440=>'NSM', +1441=>'NSM', +1442=>'NSM', +1443=>'NSM', +1444=>'NSM', +1445=>'NSM', +1446=>'NSM', +1447=>'NSM', +1448=>'NSM', +1449=>'NSM', +1450=>'NSM', +1451=>'NSM', +1452=>'NSM', +1453=>'NSM', +1454=>'NSM', +1455=>'NSM', +1456=>'NSM', +1457=>'NSM', +1458=>'NSM', +1459=>'NSM', +1460=>'NSM', +1461=>'NSM', +1462=>'NSM', +1463=>'NSM', +1464=>'NSM', +1465=>'NSM', +1466=>'NSM', +1467=>'NSM', +1468=>'NSM', +1469=>'NSM', +1470=>'R', +1471=>'NSM', +1472=>'R', +1473=>'NSM', +1474=>'NSM', +1475=>'R', +1476=>'NSM', +1477=>'NSM', +1478=>'R', +1479=>'NSM', +1488=>'R', +1489=>'R', +1490=>'R', +1491=>'R', +1492=>'R', +1493=>'R', +1494=>'R', +1495=>'R', +1496=>'R', +1497=>'R', +1498=>'R', +1499=>'R', +1500=>'R', +1501=>'R', +1502=>'R', +1503=>'R', +1504=>'R', +1505=>'R', +1506=>'R', +1507=>'R', +1508=>'R', +1509=>'R', +1510=>'R', +1511=>'R', +1512=>'R', +1513=>'R', +1514=>'R', +1520=>'R', +1521=>'R', +1522=>'R', +1523=>'R', +1524=>'R', +1536=>'AL', +1537=>'AL', +1538=>'AL', +1539=>'AL', +1547=>'AL', +1548=>'CS', +1549=>'AL', +1550=>'ON', +1551=>'ON', +1552=>'NSM', +1553=>'NSM', +1554=>'NSM', +1555=>'NSM', +1556=>'NSM', +1557=>'NSM', +1563=>'AL', +1566=>'AL', +1567=>'AL', +1569=>'AL', +1570=>'AL', +1571=>'AL', +1572=>'AL', +1573=>'AL', +1574=>'AL', +1575=>'AL', +1576=>'AL', +1577=>'AL', +1578=>'AL', +1579=>'AL', +1580=>'AL', +1581=>'AL', +1582=>'AL', +1583=>'AL', +1584=>'AL', +1585=>'AL', +1586=>'AL', +1587=>'AL', +1588=>'AL', +1589=>'AL', +1590=>'AL', +1591=>'AL', +1592=>'AL', +1593=>'AL', +1594=>'AL', +1600=>'AL', +1601=>'AL', +1602=>'AL', +1603=>'AL', +1604=>'AL', +1605=>'AL', +1606=>'AL', +1607=>'AL', +1608=>'AL', +1609=>'AL', +1610=>'AL', +1611=>'NSM', +1612=>'NSM', +1613=>'NSM', +1614=>'NSM', +1615=>'NSM', +1616=>'NSM', +1617=>'NSM', +1618=>'NSM', +1619=>'NSM', +1620=>'NSM', +1621=>'NSM', +1622=>'NSM', +1623=>'NSM', +1624=>'NSM', +1625=>'NSM', +1626=>'NSM', +1627=>'NSM', +1628=>'NSM', +1629=>'NSM', +1630=>'NSM', +1632=>'AN', +1633=>'AN', +1634=>'AN', +1635=>'AN', +1636=>'AN', +1637=>'AN', +1638=>'AN', +1639=>'AN', +1640=>'AN', +1641=>'AN', +1642=>'ET', +1643=>'AN', +1644=>'AN', +1645=>'AL', +1646=>'AL', +1647=>'AL', +1648=>'NSM', +1649=>'AL', +1650=>'AL', +1651=>'AL', +1652=>'AL', +1653=>'AL', +1654=>'AL', +1655=>'AL', +1656=>'AL', +1657=>'AL', +1658=>'AL', +1659=>'AL', +1660=>'AL', +1661=>'AL', +1662=>'AL', +1663=>'AL', +1664=>'AL', +1665=>'AL', +1666=>'AL', +1667=>'AL', +1668=>'AL', +1669=>'AL', +1670=>'AL', +1671=>'AL', +1672=>'AL', +1673=>'AL', +1674=>'AL', +1675=>'AL', +1676=>'AL', +1677=>'AL', +1678=>'AL', +1679=>'AL', +1680=>'AL', +1681=>'AL', +1682=>'AL', +1683=>'AL', +1684=>'AL', +1685=>'AL', +1686=>'AL', +1687=>'AL', +1688=>'AL', +1689=>'AL', +1690=>'AL', +1691=>'AL', +1692=>'AL', +1693=>'AL', +1694=>'AL', +1695=>'AL', +1696=>'AL', +1697=>'AL', +1698=>'AL', +1699=>'AL', +1700=>'AL', +1701=>'AL', +1702=>'AL', +1703=>'AL', +1704=>'AL', +1705=>'AL', +1706=>'AL', +1707=>'AL', +1708=>'AL', +1709=>'AL', +1710=>'AL', +1711=>'AL', +1712=>'AL', +1713=>'AL', +1714=>'AL', +1715=>'AL', +1716=>'AL', +1717=>'AL', +1718=>'AL', +1719=>'AL', +1720=>'AL', +1721=>'AL', +1722=>'AL', +1723=>'AL', +1724=>'AL', +1725=>'AL', +1726=>'AL', +1727=>'AL', +1728=>'AL', +1729=>'AL', +1730=>'AL', +1731=>'AL', +1732=>'AL', +1733=>'AL', +1734=>'AL', +1735=>'AL', +1736=>'AL', +1737=>'AL', +1738=>'AL', +1739=>'AL', +1740=>'AL', +1741=>'AL', +1742=>'AL', +1743=>'AL', +1744=>'AL', +1745=>'AL', +1746=>'AL', +1747=>'AL', +1748=>'AL', +1749=>'AL', +1750=>'NSM', +1751=>'NSM', +1752=>'NSM', +1753=>'NSM', +1754=>'NSM', +1755=>'NSM', +1756=>'NSM', +1757=>'AL', +1758=>'NSM', +1759=>'NSM', +1760=>'NSM', +1761=>'NSM', +1762=>'NSM', +1763=>'NSM', +1764=>'NSM', +1765=>'AL', +1766=>'AL', +1767=>'NSM', +1768=>'NSM', +1769=>'ON', +1770=>'NSM', +1771=>'NSM', +1772=>'NSM', +1773=>'NSM', +1774=>'AL', +1775=>'AL', +1776=>'EN', +1777=>'EN', +1778=>'EN', +1779=>'EN', +1780=>'EN', +1781=>'EN', +1782=>'EN', +1783=>'EN', +1784=>'EN', +1785=>'EN', +1786=>'AL', +1787=>'AL', +1788=>'AL', +1789=>'AL', +1790=>'AL', +1791=>'AL', +1792=>'AL', +1793=>'AL', +1794=>'AL', +1795=>'AL', +1796=>'AL', +1797=>'AL', +1798=>'AL', +1799=>'AL', +1800=>'AL', +1801=>'AL', +1802=>'AL', +1803=>'AL', +1804=>'AL', +1805=>'AL', +1807=>'BN', +1808=>'AL', +1809=>'NSM', +1810=>'AL', +1811=>'AL', +1812=>'AL', +1813=>'AL', +1814=>'AL', +1815=>'AL', +1816=>'AL', +1817=>'AL', +1818=>'AL', +1819=>'AL', +1820=>'AL', +1821=>'AL', +1822=>'AL', +1823=>'AL', +1824=>'AL', +1825=>'AL', +1826=>'AL', +1827=>'AL', +1828=>'AL', +1829=>'AL', +1830=>'AL', +1831=>'AL', +1832=>'AL', +1833=>'AL', +1834=>'AL', +1835=>'AL', +1836=>'AL', +1837=>'AL', +1838=>'AL', +1839=>'AL', +1840=>'NSM', +1841=>'NSM', +1842=>'NSM', +1843=>'NSM', +1844=>'NSM', +1845=>'NSM', +1846=>'NSM', +1847=>'NSM', +1848=>'NSM', +1849=>'NSM', +1850=>'NSM', +1851=>'NSM', +1852=>'NSM', +1853=>'NSM', +1854=>'NSM', +1855=>'NSM', +1856=>'NSM', +1857=>'NSM', +1858=>'NSM', +1859=>'NSM', +1860=>'NSM', +1861=>'NSM', +1862=>'NSM', +1863=>'NSM', +1864=>'NSM', +1865=>'NSM', +1866=>'NSM', +1869=>'AL', +1870=>'AL', +1871=>'AL', +1872=>'AL', +1873=>'AL', +1874=>'AL', +1875=>'AL', +1876=>'AL', +1877=>'AL', +1878=>'AL', +1879=>'AL', +1880=>'AL', +1881=>'AL', +1882=>'AL', +1883=>'AL', +1884=>'AL', +1885=>'AL', +1886=>'AL', +1887=>'AL', +1888=>'AL', +1889=>'AL', +1890=>'AL', +1891=>'AL', +1892=>'AL', +1893=>'AL', +1894=>'AL', +1895=>'AL', +1896=>'AL', +1897=>'AL', +1898=>'AL', +1899=>'AL', +1900=>'AL', +1901=>'AL', +1920=>'AL', +1921=>'AL', +1922=>'AL', +1923=>'AL', +1924=>'AL', +1925=>'AL', +1926=>'AL', +1927=>'AL', +1928=>'AL', +1929=>'AL', +1930=>'AL', +1931=>'AL', +1932=>'AL', +1933=>'AL', +1934=>'AL', +1935=>'AL', +1936=>'AL', +1937=>'AL', +1938=>'AL', +1939=>'AL', +1940=>'AL', +1941=>'AL', +1942=>'AL', +1943=>'AL', +1944=>'AL', +1945=>'AL', +1946=>'AL', +1947=>'AL', +1948=>'AL', +1949=>'AL', +1950=>'AL', +1951=>'AL', +1952=>'AL', +1953=>'AL', +1954=>'AL', +1955=>'AL', +1956=>'AL', +1957=>'AL', +1958=>'NSM', +1959=>'NSM', +1960=>'NSM', +1961=>'NSM', +1962=>'NSM', +1963=>'NSM', +1964=>'NSM', +1965=>'NSM', +1966=>'NSM', +1967=>'NSM', +1968=>'NSM', +1969=>'AL', +1984=>'R', +1985=>'R', +1986=>'R', +1987=>'R', +1988=>'R', +1989=>'R', +1990=>'R', +1991=>'R', +1992=>'R', +1993=>'R', +1994=>'R', +1995=>'R', +1996=>'R', +1997=>'R', +1998=>'R', +1999=>'R', +2000=>'R', +2001=>'R', +2002=>'R', +2003=>'R', +2004=>'R', +2005=>'R', +2006=>'R', +2007=>'R', +2008=>'R', +2009=>'R', +2010=>'R', +2011=>'R', +2012=>'R', +2013=>'R', +2014=>'R', +2015=>'R', +2016=>'R', +2017=>'R', +2018=>'R', +2019=>'R', +2020=>'R', +2021=>'R', +2022=>'R', +2023=>'R', +2024=>'R', +2025=>'R', +2026=>'R', +2027=>'NSM', +2028=>'NSM', +2029=>'NSM', +2030=>'NSM', +2031=>'NSM', +2032=>'NSM', +2033=>'NSM', +2034=>'NSM', +2035=>'NSM', +2036=>'R', +2037=>'R', +2038=>'ON', +2039=>'ON', +2040=>'ON', +2041=>'ON', +2042=>'R', +2305=>'NSM', +2306=>'NSM', +2307=>'L', +2308=>'L', +2309=>'L', +2310=>'L', +2311=>'L', +2312=>'L', +2313=>'L', +2314=>'L', +2315=>'L', +2316=>'L', +2317=>'L', +2318=>'L', +2319=>'L', +2320=>'L', +2321=>'L', +2322=>'L', +2323=>'L', +2324=>'L', +2325=>'L', +2326=>'L', +2327=>'L', +2328=>'L', +2329=>'L', +2330=>'L', +2331=>'L', +2332=>'L', +2333=>'L', +2334=>'L', +2335=>'L', +2336=>'L', +2337=>'L', +2338=>'L', +2339=>'L', +2340=>'L', +2341=>'L', +2342=>'L', +2343=>'L', +2344=>'L', +2345=>'L', +2346=>'L', +2347=>'L', +2348=>'L', +2349=>'L', +2350=>'L', +2351=>'L', +2352=>'L', +2353=>'L', +2354=>'L', +2355=>'L', +2356=>'L', +2357=>'L', +2358=>'L', +2359=>'L', +2360=>'L', +2361=>'L', +2364=>'NSM', +2365=>'L', +2366=>'L', +2367=>'L', +2368=>'L', +2369=>'NSM', +2370=>'NSM', +2371=>'NSM', +2372=>'NSM', +2373=>'NSM', +2374=>'NSM', +2375=>'NSM', +2376=>'NSM', +2377=>'L', +2378=>'L', +2379=>'L', +2380=>'L', +2381=>'NSM', +2384=>'L', +2385=>'NSM', +2386=>'NSM', +2387=>'NSM', +2388=>'NSM', +2392=>'L', +2393=>'L', +2394=>'L', +2395=>'L', +2396=>'L', +2397=>'L', +2398=>'L', +2399=>'L', +2400=>'L', +2401=>'L', +2402=>'NSM', +2403=>'NSM', +2404=>'L', +2405=>'L', +2406=>'L', +2407=>'L', +2408=>'L', +2409=>'L', +2410=>'L', +2411=>'L', +2412=>'L', +2413=>'L', +2414=>'L', +2415=>'L', +2416=>'L', +2427=>'L', +2428=>'L', +2429=>'L', +2430=>'L', +2431=>'L', +2433=>'NSM', +2434=>'L', +2435=>'L', +2437=>'L', +2438=>'L', +2439=>'L', +2440=>'L', +2441=>'L', +2442=>'L', +2443=>'L', +2444=>'L', +2447=>'L', +2448=>'L', +2451=>'L', +2452=>'L', +2453=>'L', +2454=>'L', +2455=>'L', +2456=>'L', +2457=>'L', +2458=>'L', +2459=>'L', +2460=>'L', +2461=>'L', +2462=>'L', +2463=>'L', +2464=>'L', +2465=>'L', +2466=>'L', +2467=>'L', +2468=>'L', +2469=>'L', +2470=>'L', +2471=>'L', +2472=>'L', +2474=>'L', +2475=>'L', +2476=>'L', +2477=>'L', +2478=>'L', +2479=>'L', +2480=>'L', +2482=>'L', +2486=>'L', +2487=>'L', +2488=>'L', +2489=>'L', +2492=>'NSM', +2493=>'L', +2494=>'L', +2495=>'L', +2496=>'L', +2497=>'NSM', +2498=>'NSM', +2499=>'NSM', +2500=>'NSM', +2503=>'L', +2504=>'L', +2507=>'L', +2508=>'L', +2509=>'NSM', +2510=>'L', +2519=>'L', +2524=>'L', +2525=>'L', +2527=>'L', +2528=>'L', +2529=>'L', +2530=>'NSM', +2531=>'NSM', +2534=>'L', +2535=>'L', +2536=>'L', +2537=>'L', +2538=>'L', +2539=>'L', +2540=>'L', +2541=>'L', +2542=>'L', +2543=>'L', +2544=>'L', +2545=>'L', +2546=>'ET', +2547=>'ET', +2548=>'L', +2549=>'L', +2550=>'L', +2551=>'L', +2552=>'L', +2553=>'L', +2554=>'L', +2561=>'NSM', +2562=>'NSM', +2563=>'L', +2565=>'L', +2566=>'L', +2567=>'L', +2568=>'L', +2569=>'L', +2570=>'L', +2575=>'L', +2576=>'L', +2579=>'L', +2580=>'L', +2581=>'L', +2582=>'L', +2583=>'L', +2584=>'L', +2585=>'L', +2586=>'L', +2587=>'L', +2588=>'L', +2589=>'L', +2590=>'L', +2591=>'L', +2592=>'L', +2593=>'L', +2594=>'L', +2595=>'L', +2596=>'L', +2597=>'L', +2598=>'L', +2599=>'L', +2600=>'L', +2602=>'L', +2603=>'L', +2604=>'L', +2605=>'L', +2606=>'L', +2607=>'L', +2608=>'L', +2610=>'L', +2611=>'L', +2613=>'L', +2614=>'L', +2616=>'L', +2617=>'L', +2620=>'NSM', +2622=>'L', +2623=>'L', +2624=>'L', +2625=>'NSM', +2626=>'NSM', +2631=>'NSM', +2632=>'NSM', +2635=>'NSM', +2636=>'NSM', +2637=>'NSM', +2649=>'L', +2650=>'L', +2651=>'L', +2652=>'L', +2654=>'L', +2662=>'L', +2663=>'L', +2664=>'L', +2665=>'L', +2666=>'L', +2667=>'L', +2668=>'L', +2669=>'L', +2670=>'L', +2671=>'L', +2672=>'NSM', +2673=>'NSM', +2674=>'L', +2675=>'L', +2676=>'L', +2689=>'NSM', +2690=>'NSM', +2691=>'L', +2693=>'L', +2694=>'L', +2695=>'L', +2696=>'L', +2697=>'L', +2698=>'L', +2699=>'L', +2700=>'L', +2701=>'L', +2703=>'L', +2704=>'L', +2705=>'L', +2707=>'L', +2708=>'L', +2709=>'L', +2710=>'L', +2711=>'L', +2712=>'L', +2713=>'L', +2714=>'L', +2715=>'L', +2716=>'L', +2717=>'L', +2718=>'L', +2719=>'L', +2720=>'L', +2721=>'L', +2722=>'L', +2723=>'L', +2724=>'L', +2725=>'L', +2726=>'L', +2727=>'L', +2728=>'L', +2730=>'L', +2731=>'L', +2732=>'L', +2733=>'L', +2734=>'L', +2735=>'L', +2736=>'L', +2738=>'L', +2739=>'L', +2741=>'L', +2742=>'L', +2743=>'L', +2744=>'L', +2745=>'L', +2748=>'NSM', +2749=>'L', +2750=>'L', +2751=>'L', +2752=>'L', +2753=>'NSM', +2754=>'NSM', +2755=>'NSM', +2756=>'NSM', +2757=>'NSM', +2759=>'NSM', +2760=>'NSM', +2761=>'L', +2763=>'L', +2764=>'L', +2765=>'NSM', +2768=>'L', +2784=>'L', +2785=>'L', +2786=>'NSM', +2787=>'NSM', +2790=>'L', +2791=>'L', +2792=>'L', +2793=>'L', +2794=>'L', +2795=>'L', +2796=>'L', +2797=>'L', +2798=>'L', +2799=>'L', +2801=>'ET', +2817=>'NSM', +2818=>'L', +2819=>'L', +2821=>'L', +2822=>'L', +2823=>'L', +2824=>'L', +2825=>'L', +2826=>'L', +2827=>'L', +2828=>'L', +2831=>'L', +2832=>'L', +2835=>'L', +2836=>'L', +2837=>'L', +2838=>'L', +2839=>'L', +2840=>'L', +2841=>'L', +2842=>'L', +2843=>'L', +2844=>'L', +2845=>'L', +2846=>'L', +2847=>'L', +2848=>'L', +2849=>'L', +2850=>'L', +2851=>'L', +2852=>'L', +2853=>'L', +2854=>'L', +2855=>'L', +2856=>'L', +2858=>'L', +2859=>'L', +2860=>'L', +2861=>'L', +2862=>'L', +2863=>'L', +2864=>'L', +2866=>'L', +2867=>'L', +2869=>'L', +2870=>'L', +2871=>'L', +2872=>'L', +2873=>'L', +2876=>'NSM', +2877=>'L', +2878=>'L', +2879=>'NSM', +2880=>'L', +2881=>'NSM', +2882=>'NSM', +2883=>'NSM', +2887=>'L', +2888=>'L', +2891=>'L', +2892=>'L', +2893=>'NSM', +2902=>'NSM', +2903=>'L', +2908=>'L', +2909=>'L', +2911=>'L', +2912=>'L', +2913=>'L', +2918=>'L', +2919=>'L', +2920=>'L', +2921=>'L', +2922=>'L', +2923=>'L', +2924=>'L', +2925=>'L', +2926=>'L', +2927=>'L', +2928=>'L', +2929=>'L', +2946=>'NSM', +2947=>'L', +2949=>'L', +2950=>'L', +2951=>'L', +2952=>'L', +2953=>'L', +2954=>'L', +2958=>'L', +2959=>'L', +2960=>'L', +2962=>'L', +2963=>'L', +2964=>'L', +2965=>'L', +2969=>'L', +2970=>'L', +2972=>'L', +2974=>'L', +2975=>'L', +2979=>'L', +2980=>'L', +2984=>'L', +2985=>'L', +2986=>'L', +2990=>'L', +2991=>'L', +2992=>'L', +2993=>'L', +2994=>'L', +2995=>'L', +2996=>'L', +2997=>'L', +2998=>'L', +2999=>'L', +3000=>'L', +3001=>'L', +3006=>'L', +3007=>'L', +3008=>'NSM', +3009=>'L', +3010=>'L', +3014=>'L', +3015=>'L', +3016=>'L', +3018=>'L', +3019=>'L', +3020=>'L', +3021=>'NSM', +3031=>'L', +3046=>'L', +3047=>'L', +3048=>'L', +3049=>'L', +3050=>'L', +3051=>'L', +3052=>'L', +3053=>'L', +3054=>'L', +3055=>'L', +3056=>'L', +3057=>'L', +3058=>'L', +3059=>'ON', +3060=>'ON', +3061=>'ON', +3062=>'ON', +3063=>'ON', +3064=>'ON', +3065=>'ET', +3066=>'ON', +3073=>'L', +3074=>'L', +3075=>'L', +3077=>'L', +3078=>'L', +3079=>'L', +3080=>'L', +3081=>'L', +3082=>'L', +3083=>'L', +3084=>'L', +3086=>'L', +3087=>'L', +3088=>'L', +3090=>'L', +3091=>'L', +3092=>'L', +3093=>'L', +3094=>'L', +3095=>'L', +3096=>'L', +3097=>'L', +3098=>'L', +3099=>'L', +3100=>'L', +3101=>'L', +3102=>'L', +3103=>'L', +3104=>'L', +3105=>'L', +3106=>'L', +3107=>'L', +3108=>'L', +3109=>'L', +3110=>'L', +3111=>'L', +3112=>'L', +3114=>'L', +3115=>'L', +3116=>'L', +3117=>'L', +3118=>'L', +3119=>'L', +3120=>'L', +3121=>'L', +3122=>'L', +3123=>'L', +3125=>'L', +3126=>'L', +3127=>'L', +3128=>'L', +3129=>'L', +3134=>'NSM', +3135=>'NSM', +3136=>'NSM', +3137=>'L', +3138=>'L', +3139=>'L', +3140=>'L', +3142=>'NSM', +3143=>'NSM', +3144=>'NSM', +3146=>'NSM', +3147=>'NSM', +3148=>'NSM', +3149=>'NSM', +3157=>'NSM', +3158=>'NSM', +3168=>'L', +3169=>'L', +3174=>'L', +3175=>'L', +3176=>'L', +3177=>'L', +3178=>'L', +3179=>'L', +3180=>'L', +3181=>'L', +3182=>'L', +3183=>'L', +3202=>'L', +3203=>'L', +3205=>'L', +3206=>'L', +3207=>'L', +3208=>'L', +3209=>'L', +3210=>'L', +3211=>'L', +3212=>'L', +3214=>'L', +3215=>'L', +3216=>'L', +3218=>'L', +3219=>'L', +3220=>'L', +3221=>'L', +3222=>'L', +3223=>'L', +3224=>'L', +3225=>'L', +3226=>'L', +3227=>'L', +3228=>'L', +3229=>'L', +3230=>'L', +3231=>'L', +3232=>'L', +3233=>'L', +3234=>'L', +3235=>'L', +3236=>'L', +3237=>'L', +3238=>'L', +3239=>'L', +3240=>'L', +3242=>'L', +3243=>'L', +3244=>'L', +3245=>'L', +3246=>'L', +3247=>'L', +3248=>'L', +3249=>'L', +3250=>'L', +3251=>'L', +3253=>'L', +3254=>'L', +3255=>'L', +3256=>'L', +3257=>'L', +3260=>'NSM', +3261=>'L', +3262=>'L', +3263=>'L', +3264=>'L', +3265=>'L', +3266=>'L', +3267=>'L', +3268=>'L', +3270=>'L', +3271=>'L', +3272=>'L', +3274=>'L', +3275=>'L', +3276=>'NSM', +3277=>'NSM', +3285=>'L', +3286=>'L', +3294=>'L', +3296=>'L', +3297=>'L', +3298=>'NSM', +3299=>'NSM', +3302=>'L', +3303=>'L', +3304=>'L', +3305=>'L', +3306=>'L', +3307=>'L', +3308=>'L', +3309=>'L', +3310=>'L', +3311=>'L', +3313=>'ON', +3314=>'ON', +3330=>'L', +3331=>'L', +3333=>'L', +3334=>'L', +3335=>'L', +3336=>'L', +3337=>'L', +3338=>'L', +3339=>'L', +3340=>'L', +3342=>'L', +3343=>'L', +3344=>'L', +3346=>'L', +3347=>'L', +3348=>'L', +3349=>'L', +3350=>'L', +3351=>'L', +3352=>'L', +3353=>'L', +3354=>'L', +3355=>'L', +3356=>'L', +3357=>'L', +3358=>'L', +3359=>'L', +3360=>'L', +3361=>'L', +3362=>'L', +3363=>'L', +3364=>'L', +3365=>'L', +3366=>'L', +3367=>'L', +3368=>'L', +3370=>'L', +3371=>'L', +3372=>'L', +3373=>'L', +3374=>'L', +3375=>'L', +3376=>'L', +3377=>'L', +3378=>'L', +3379=>'L', +3380=>'L', +3381=>'L', +3382=>'L', +3383=>'L', +3384=>'L', +3385=>'L', +3390=>'L', +3391=>'L', +3392=>'L', +3393=>'NSM', +3394=>'NSM', +3395=>'NSM', +3398=>'L', +3399=>'L', +3400=>'L', +3402=>'L', +3403=>'L', +3404=>'L', +3405=>'NSM', +3415=>'L', +3424=>'L', +3425=>'L', +3430=>'L', +3431=>'L', +3432=>'L', +3433=>'L', +3434=>'L', +3435=>'L', +3436=>'L', +3437=>'L', +3438=>'L', +3439=>'L', +3458=>'L', +3459=>'L', +3461=>'L', +3462=>'L', +3463=>'L', +3464=>'L', +3465=>'L', +3466=>'L', +3467=>'L', +3468=>'L', +3469=>'L', +3470=>'L', +3471=>'L', +3472=>'L', +3473=>'L', +3474=>'L', +3475=>'L', +3476=>'L', +3477=>'L', +3478=>'L', +3482=>'L', +3483=>'L', +3484=>'L', +3485=>'L', +3486=>'L', +3487=>'L', +3488=>'L', +3489=>'L', +3490=>'L', +3491=>'L', +3492=>'L', +3493=>'L', +3494=>'L', +3495=>'L', +3496=>'L', +3497=>'L', +3498=>'L', +3499=>'L', +3500=>'L', +3501=>'L', +3502=>'L', +3503=>'L', +3504=>'L', +3505=>'L', +3507=>'L', +3508=>'L', +3509=>'L', +3510=>'L', +3511=>'L', +3512=>'L', +3513=>'L', +3514=>'L', +3515=>'L', +3517=>'L', +3520=>'L', +3521=>'L', +3522=>'L', +3523=>'L', +3524=>'L', +3525=>'L', +3526=>'L', +3530=>'NSM', +3535=>'L', +3536=>'L', +3537=>'L', +3538=>'NSM', +3539=>'NSM', +3540=>'NSM', +3542=>'NSM', +3544=>'L', +3545=>'L', +3546=>'L', +3547=>'L', +3548=>'L', +3549=>'L', +3550=>'L', +3551=>'L', +3570=>'L', +3571=>'L', +3572=>'L', +3585=>'L', +3586=>'L', +3587=>'L', +3588=>'L', +3589=>'L', +3590=>'L', +3591=>'L', +3592=>'L', +3593=>'L', +3594=>'L', +3595=>'L', +3596=>'L', +3597=>'L', +3598=>'L', +3599=>'L', +3600=>'L', +3601=>'L', +3602=>'L', +3603=>'L', +3604=>'L', +3605=>'L', +3606=>'L', +3607=>'L', +3608=>'L', +3609=>'L', +3610=>'L', +3611=>'L', +3612=>'L', +3613=>'L', +3614=>'L', +3615=>'L', +3616=>'L', +3617=>'L', +3618=>'L', +3619=>'L', +3620=>'L', +3621=>'L', +3622=>'L', +3623=>'L', +3624=>'L', +3625=>'L', +3626=>'L', +3627=>'L', +3628=>'L', +3629=>'L', +3630=>'L', +3631=>'L', +3632=>'L', +3633=>'NSM', +3634=>'L', +3635=>'L', +3636=>'NSM', +3637=>'NSM', +3638=>'NSM', +3639=>'NSM', +3640=>'NSM', +3641=>'NSM', +3642=>'NSM', +3647=>'ET', +3648=>'L', +3649=>'L', +3650=>'L', +3651=>'L', +3652=>'L', +3653=>'L', +3654=>'L', +3655=>'NSM', +3656=>'NSM', +3657=>'NSM', +3658=>'NSM', +3659=>'NSM', +3660=>'NSM', +3661=>'NSM', +3662=>'NSM', +3663=>'L', +3664=>'L', +3665=>'L', +3666=>'L', +3667=>'L', +3668=>'L', +3669=>'L', +3670=>'L', +3671=>'L', +3672=>'L', +3673=>'L', +3674=>'L', +3675=>'L', +3713=>'L', +3714=>'L', +3716=>'L', +3719=>'L', +3720=>'L', +3722=>'L', +3725=>'L', +3732=>'L', +3733=>'L', +3734=>'L', +3735=>'L', +3737=>'L', +3738=>'L', +3739=>'L', +3740=>'L', +3741=>'L', +3742=>'L', +3743=>'L', +3745=>'L', +3746=>'L', +3747=>'L', +3749=>'L', +3751=>'L', +3754=>'L', +3755=>'L', +3757=>'L', +3758=>'L', +3759=>'L', +3760=>'L', +3761=>'NSM', +3762=>'L', +3763=>'L', +3764=>'NSM', +3765=>'NSM', +3766=>'NSM', +3767=>'NSM', +3768=>'NSM', +3769=>'NSM', +3771=>'NSM', +3772=>'NSM', +3773=>'L', +3776=>'L', +3777=>'L', +3778=>'L', +3779=>'L', +3780=>'L', +3782=>'L', +3784=>'NSM', +3785=>'NSM', +3786=>'NSM', +3787=>'NSM', +3788=>'NSM', +3789=>'NSM', +3792=>'L', +3793=>'L', +3794=>'L', +3795=>'L', +3796=>'L', +3797=>'L', +3798=>'L', +3799=>'L', +3800=>'L', +3801=>'L', +3804=>'L', +3805=>'L', +3840=>'L', +3841=>'L', +3842=>'L', +3843=>'L', +3844=>'L', +3845=>'L', +3846=>'L', +3847=>'L', +3848=>'L', +3849=>'L', +3850=>'L', +3851=>'L', +3852=>'L', +3853=>'L', +3854=>'L', +3855=>'L', +3856=>'L', +3857=>'L', +3858=>'L', +3859=>'L', +3860=>'L', +3861=>'L', +3862=>'L', +3863=>'L', +3864=>'NSM', +3865=>'NSM', +3866=>'L', +3867=>'L', +3868=>'L', +3869=>'L', +3870=>'L', +3871=>'L', +3872=>'L', +3873=>'L', +3874=>'L', +3875=>'L', +3876=>'L', +3877=>'L', +3878=>'L', +3879=>'L', +3880=>'L', +3881=>'L', +3882=>'L', +3883=>'L', +3884=>'L', +3885=>'L', +3886=>'L', +3887=>'L', +3888=>'L', +3889=>'L', +3890=>'L', +3891=>'L', +3892=>'L', +3893=>'NSM', +3894=>'L', +3895=>'NSM', +3896=>'L', +3897=>'NSM', +3898=>'ON', +3899=>'ON', +3900=>'ON', +3901=>'ON', +3902=>'L', +3903=>'L', +3904=>'L', +3905=>'L', +3906=>'L', +3907=>'L', +3908=>'L', +3909=>'L', +3910=>'L', +3911=>'L', +3913=>'L', +3914=>'L', +3915=>'L', +3916=>'L', +3917=>'L', +3918=>'L', +3919=>'L', +3920=>'L', +3921=>'L', +3922=>'L', +3923=>'L', +3924=>'L', +3925=>'L', +3926=>'L', +3927=>'L', +3928=>'L', +3929=>'L', +3930=>'L', +3931=>'L', +3932=>'L', +3933=>'L', +3934=>'L', +3935=>'L', +3936=>'L', +3937=>'L', +3938=>'L', +3939=>'L', +3940=>'L', +3941=>'L', +3942=>'L', +3943=>'L', +3944=>'L', +3945=>'L', +3946=>'L', +3953=>'NSM', +3954=>'NSM', +3955=>'NSM', +3956=>'NSM', +3957=>'NSM', +3958=>'NSM', +3959=>'NSM', +3960=>'NSM', +3961=>'NSM', +3962=>'NSM', +3963=>'NSM', +3964=>'NSM', +3965=>'NSM', +3966=>'NSM', +3967=>'L', +3968=>'NSM', +3969=>'NSM', +3970=>'NSM', +3971=>'NSM', +3972=>'NSM', +3973=>'L', +3974=>'NSM', +3975=>'NSM', +3976=>'L', +3977=>'L', +3978=>'L', +3979=>'L', +3984=>'NSM', +3985=>'NSM', +3986=>'NSM', +3987=>'NSM', +3988=>'NSM', +3989=>'NSM', +3990=>'NSM', +3991=>'NSM', +3993=>'NSM', +3994=>'NSM', +3995=>'NSM', +3996=>'NSM', +3997=>'NSM', +3998=>'NSM', +3999=>'NSM', +4000=>'NSM', +4001=>'NSM', +4002=>'NSM', +4003=>'NSM', +4004=>'NSM', +4005=>'NSM', +4006=>'NSM', +4007=>'NSM', +4008=>'NSM', +4009=>'NSM', +4010=>'NSM', +4011=>'NSM', +4012=>'NSM', +4013=>'NSM', +4014=>'NSM', +4015=>'NSM', +4016=>'NSM', +4017=>'NSM', +4018=>'NSM', +4019=>'NSM', +4020=>'NSM', +4021=>'NSM', +4022=>'NSM', +4023=>'NSM', +4024=>'NSM', +4025=>'NSM', +4026=>'NSM', +4027=>'NSM', +4028=>'NSM', +4030=>'L', +4031=>'L', +4032=>'L', +4033=>'L', +4034=>'L', +4035=>'L', +4036=>'L', +4037=>'L', +4038=>'NSM', +4039=>'L', +4040=>'L', +4041=>'L', +4042=>'L', +4043=>'L', +4044=>'L', +4047=>'L', +4048=>'L', +4049=>'L', +4096=>'L', +4097=>'L', +4098=>'L', +4099=>'L', +4100=>'L', +4101=>'L', +4102=>'L', +4103=>'L', +4104=>'L', +4105=>'L', +4106=>'L', +4107=>'L', +4108=>'L', +4109=>'L', +4110=>'L', +4111=>'L', +4112=>'L', +4113=>'L', +4114=>'L', +4115=>'L', +4116=>'L', +4117=>'L', +4118=>'L', +4119=>'L', +4120=>'L', +4121=>'L', +4122=>'L', +4123=>'L', +4124=>'L', +4125=>'L', +4126=>'L', +4127=>'L', +4128=>'L', +4129=>'L', +4131=>'L', +4132=>'L', +4133=>'L', +4134=>'L', +4135=>'L', +4137=>'L', +4138=>'L', +4140=>'L', +4141=>'NSM', +4142=>'NSM', +4143=>'NSM', +4144=>'NSM', +4145=>'L', +4146=>'NSM', +4150=>'NSM', +4151=>'NSM', +4152=>'L', +4153=>'NSM', +4160=>'L', +4161=>'L', +4162=>'L', +4163=>'L', +4164=>'L', +4165=>'L', +4166=>'L', +4167=>'L', +4168=>'L', +4169=>'L', +4170=>'L', +4171=>'L', +4172=>'L', +4173=>'L', +4174=>'L', +4175=>'L', +4176=>'L', +4177=>'L', +4178=>'L', +4179=>'L', +4180=>'L', +4181=>'L', +4182=>'L', +4183=>'L', +4184=>'NSM', +4185=>'NSM', +4256=>'L', +4257=>'L', +4258=>'L', +4259=>'L', +4260=>'L', +4261=>'L', +4262=>'L', +4263=>'L', +4264=>'L', +4265=>'L', +4266=>'L', +4267=>'L', +4268=>'L', +4269=>'L', +4270=>'L', +4271=>'L', +4272=>'L', +4273=>'L', +4274=>'L', +4275=>'L', +4276=>'L', +4277=>'L', +4278=>'L', +4279=>'L', +4280=>'L', +4281=>'L', +4282=>'L', +4283=>'L', +4284=>'L', +4285=>'L', +4286=>'L', +4287=>'L', +4288=>'L', +4289=>'L', +4290=>'L', +4291=>'L', +4292=>'L', +4293=>'L', +4304=>'L', +4305=>'L', +4306=>'L', +4307=>'L', +4308=>'L', +4309=>'L', +4310=>'L', +4311=>'L', +4312=>'L', +4313=>'L', +4314=>'L', +4315=>'L', +4316=>'L', +4317=>'L', +4318=>'L', +4319=>'L', +4320=>'L', +4321=>'L', +4322=>'L', +4323=>'L', +4324=>'L', +4325=>'L', +4326=>'L', +4327=>'L', +4328=>'L', +4329=>'L', +4330=>'L', +4331=>'L', +4332=>'L', +4333=>'L', +4334=>'L', +4335=>'L', +4336=>'L', +4337=>'L', +4338=>'L', +4339=>'L', +4340=>'L', +4341=>'L', +4342=>'L', +4343=>'L', +4344=>'L', +4345=>'L', +4346=>'L', +4347=>'L', +4348=>'L', +4352=>'L', +4353=>'L', +4354=>'L', +4355=>'L', +4356=>'L', +4357=>'L', +4358=>'L', +4359=>'L', +4360=>'L', +4361=>'L', +4362=>'L', +4363=>'L', +4364=>'L', +4365=>'L', +4366=>'L', +4367=>'L', +4368=>'L', +4369=>'L', +4370=>'L', +4371=>'L', +4372=>'L', +4373=>'L', +4374=>'L', +4375=>'L', +4376=>'L', +4377=>'L', +4378=>'L', +4379=>'L', +4380=>'L', +4381=>'L', +4382=>'L', +4383=>'L', +4384=>'L', +4385=>'L', +4386=>'L', +4387=>'L', +4388=>'L', +4389=>'L', +4390=>'L', +4391=>'L', +4392=>'L', +4393=>'L', +4394=>'L', +4395=>'L', +4396=>'L', +4397=>'L', +4398=>'L', +4399=>'L', +4400=>'L', +4401=>'L', +4402=>'L', +4403=>'L', +4404=>'L', +4405=>'L', +4406=>'L', +4407=>'L', +4408=>'L', +4409=>'L', +4410=>'L', +4411=>'L', +4412=>'L', +4413=>'L', +4414=>'L', +4415=>'L', +4416=>'L', +4417=>'L', +4418=>'L', +4419=>'L', +4420=>'L', +4421=>'L', +4422=>'L', +4423=>'L', +4424=>'L', +4425=>'L', +4426=>'L', +4427=>'L', +4428=>'L', +4429=>'L', +4430=>'L', +4431=>'L', +4432=>'L', +4433=>'L', +4434=>'L', +4435=>'L', +4436=>'L', +4437=>'L', +4438=>'L', +4439=>'L', +4440=>'L', +4441=>'L', +4447=>'L', +4448=>'L', +4449=>'L', +4450=>'L', +4451=>'L', +4452=>'L', +4453=>'L', +4454=>'L', +4455=>'L', +4456=>'L', +4457=>'L', +4458=>'L', +4459=>'L', +4460=>'L', +4461=>'L', +4462=>'L', +4463=>'L', +4464=>'L', +4465=>'L', +4466=>'L', +4467=>'L', +4468=>'L', +4469=>'L', +4470=>'L', +4471=>'L', +4472=>'L', +4473=>'L', +4474=>'L', +4475=>'L', +4476=>'L', +4477=>'L', +4478=>'L', +4479=>'L', +4480=>'L', +4481=>'L', +4482=>'L', +4483=>'L', +4484=>'L', +4485=>'L', +4486=>'L', +4487=>'L', +4488=>'L', +4489=>'L', +4490=>'L', +4491=>'L', +4492=>'L', +4493=>'L', +4494=>'L', +4495=>'L', +4496=>'L', +4497=>'L', +4498=>'L', +4499=>'L', +4500=>'L', +4501=>'L', +4502=>'L', +4503=>'L', +4504=>'L', +4505=>'L', +4506=>'L', +4507=>'L', +4508=>'L', +4509=>'L', +4510=>'L', +4511=>'L', +4512=>'L', +4513=>'L', +4514=>'L', +4520=>'L', +4521=>'L', +4522=>'L', +4523=>'L', +4524=>'L', +4525=>'L', +4526=>'L', +4527=>'L', +4528=>'L', +4529=>'L', +4530=>'L', +4531=>'L', +4532=>'L', +4533=>'L', +4534=>'L', +4535=>'L', +4536=>'L', +4537=>'L', +4538=>'L', +4539=>'L', +4540=>'L', +4541=>'L', +4542=>'L', +4543=>'L', +4544=>'L', +4545=>'L', +4546=>'L', +4547=>'L', +4548=>'L', +4549=>'L', +4550=>'L', +4551=>'L', +4552=>'L', +4553=>'L', +4554=>'L', +4555=>'L', +4556=>'L', +4557=>'L', +4558=>'L', +4559=>'L', +4560=>'L', +4561=>'L', +4562=>'L', +4563=>'L', +4564=>'L', +4565=>'L', +4566=>'L', +4567=>'L', +4568=>'L', +4569=>'L', +4570=>'L', +4571=>'L', +4572=>'L', +4573=>'L', +4574=>'L', +4575=>'L', +4576=>'L', +4577=>'L', +4578=>'L', +4579=>'L', +4580=>'L', +4581=>'L', +4582=>'L', +4583=>'L', +4584=>'L', +4585=>'L', +4586=>'L', +4587=>'L', +4588=>'L', +4589=>'L', +4590=>'L', +4591=>'L', +4592=>'L', +4593=>'L', +4594=>'L', +4595=>'L', +4596=>'L', +4597=>'L', +4598=>'L', +4599=>'L', +4600=>'L', +4601=>'L', +4608=>'L', +4609=>'L', +4610=>'L', +4611=>'L', +4612=>'L', +4613=>'L', +4614=>'L', +4615=>'L', +4616=>'L', +4617=>'L', +4618=>'L', +4619=>'L', +4620=>'L', +4621=>'L', +4622=>'L', +4623=>'L', +4624=>'L', +4625=>'L', +4626=>'L', +4627=>'L', +4628=>'L', +4629=>'L', +4630=>'L', +4631=>'L', +4632=>'L', +4633=>'L', +4634=>'L', +4635=>'L', +4636=>'L', +4637=>'L', +4638=>'L', +4639=>'L', +4640=>'L', +4641=>'L', +4642=>'L', +4643=>'L', +4644=>'L', +4645=>'L', +4646=>'L', +4647=>'L', +4648=>'L', +4649=>'L', +4650=>'L', +4651=>'L', +4652=>'L', +4653=>'L', +4654=>'L', +4655=>'L', +4656=>'L', +4657=>'L', +4658=>'L', +4659=>'L', +4660=>'L', +4661=>'L', +4662=>'L', +4663=>'L', +4664=>'L', +4665=>'L', +4666=>'L', +4667=>'L', +4668=>'L', +4669=>'L', +4670=>'L', +4671=>'L', +4672=>'L', +4673=>'L', +4674=>'L', +4675=>'L', +4676=>'L', +4677=>'L', +4678=>'L', +4679=>'L', +4680=>'L', +4682=>'L', +4683=>'L', +4684=>'L', +4685=>'L', +4688=>'L', +4689=>'L', +4690=>'L', +4691=>'L', +4692=>'L', +4693=>'L', +4694=>'L', +4696=>'L', +4698=>'L', +4699=>'L', +4700=>'L', +4701=>'L', +4704=>'L', +4705=>'L', +4706=>'L', +4707=>'L', +4708=>'L', +4709=>'L', +4710=>'L', +4711=>'L', +4712=>'L', +4713=>'L', +4714=>'L', +4715=>'L', +4716=>'L', +4717=>'L', +4718=>'L', +4719=>'L', +4720=>'L', +4721=>'L', +4722=>'L', +4723=>'L', +4724=>'L', +4725=>'L', +4726=>'L', +4727=>'L', +4728=>'L', +4729=>'L', +4730=>'L', +4731=>'L', +4732=>'L', +4733=>'L', +4734=>'L', +4735=>'L', +4736=>'L', +4737=>'L', +4738=>'L', +4739=>'L', +4740=>'L', +4741=>'L', +4742=>'L', +4743=>'L', +4744=>'L', +4746=>'L', +4747=>'L', +4748=>'L', +4749=>'L', +4752=>'L', +4753=>'L', +4754=>'L', +4755=>'L', +4756=>'L', +4757=>'L', +4758=>'L', +4759=>'L', +4760=>'L', +4761=>'L', +4762=>'L', +4763=>'L', +4764=>'L', +4765=>'L', +4766=>'L', +4767=>'L', +4768=>'L', +4769=>'L', +4770=>'L', +4771=>'L', +4772=>'L', +4773=>'L', +4774=>'L', +4775=>'L', +4776=>'L', +4777=>'L', +4778=>'L', +4779=>'L', +4780=>'L', +4781=>'L', +4782=>'L', +4783=>'L', +4784=>'L', +4786=>'L', +4787=>'L', +4788=>'L', +4789=>'L', +4792=>'L', +4793=>'L', +4794=>'L', +4795=>'L', +4796=>'L', +4797=>'L', +4798=>'L', +4800=>'L', +4802=>'L', +4803=>'L', +4804=>'L', +4805=>'L', +4808=>'L', +4809=>'L', +4810=>'L', +4811=>'L', +4812=>'L', +4813=>'L', +4814=>'L', +4815=>'L', +4816=>'L', +4817=>'L', +4818=>'L', +4819=>'L', +4820=>'L', +4821=>'L', +4822=>'L', +4824=>'L', +4825=>'L', +4826=>'L', +4827=>'L', +4828=>'L', +4829=>'L', +4830=>'L', +4831=>'L', +4832=>'L', +4833=>'L', +4834=>'L', +4835=>'L', +4836=>'L', +4837=>'L', +4838=>'L', +4839=>'L', +4840=>'L', +4841=>'L', +4842=>'L', +4843=>'L', +4844=>'L', +4845=>'L', +4846=>'L', +4847=>'L', +4848=>'L', +4849=>'L', +4850=>'L', +4851=>'L', +4852=>'L', +4853=>'L', +4854=>'L', +4855=>'L', +4856=>'L', +4857=>'L', +4858=>'L', +4859=>'L', +4860=>'L', +4861=>'L', +4862=>'L', +4863=>'L', +4864=>'L', +4865=>'L', +4866=>'L', +4867=>'L', +4868=>'L', +4869=>'L', +4870=>'L', +4871=>'L', +4872=>'L', +4873=>'L', +4874=>'L', +4875=>'L', +4876=>'L', +4877=>'L', +4878=>'L', +4879=>'L', +4880=>'L', +4882=>'L', +4883=>'L', +4884=>'L', +4885=>'L', +4888=>'L', +4889=>'L', +4890=>'L', +4891=>'L', +4892=>'L', +4893=>'L', +4894=>'L', +4895=>'L', +4896=>'L', +4897=>'L', +4898=>'L', +4899=>'L', +4900=>'L', +4901=>'L', +4902=>'L', +4903=>'L', +4904=>'L', +4905=>'L', +4906=>'L', +4907=>'L', +4908=>'L', +4909=>'L', +4910=>'L', +4911=>'L', +4912=>'L', +4913=>'L', +4914=>'L', +4915=>'L', +4916=>'L', +4917=>'L', +4918=>'L', +4919=>'L', +4920=>'L', +4921=>'L', +4922=>'L', +4923=>'L', +4924=>'L', +4925=>'L', +4926=>'L', +4927=>'L', +4928=>'L', +4929=>'L', +4930=>'L', +4931=>'L', +4932=>'L', +4933=>'L', +4934=>'L', +4935=>'L', +4936=>'L', +4937=>'L', +4938=>'L', +4939=>'L', +4940=>'L', +4941=>'L', +4942=>'L', +4943=>'L', +4944=>'L', +4945=>'L', +4946=>'L', +4947=>'L', +4948=>'L', +4949=>'L', +4950=>'L', +4951=>'L', +4952=>'L', +4953=>'L', +4954=>'L', +4959=>'NSM', +4960=>'L', +4961=>'L', +4962=>'L', +4963=>'L', +4964=>'L', +4965=>'L', +4966=>'L', +4967=>'L', +4968=>'L', +4969=>'L', +4970=>'L', +4971=>'L', +4972=>'L', +4973=>'L', +4974=>'L', +4975=>'L', +4976=>'L', +4977=>'L', +4978=>'L', +4979=>'L', +4980=>'L', +4981=>'L', +4982=>'L', +4983=>'L', +4984=>'L', +4985=>'L', +4986=>'L', +4987=>'L', +4988=>'L', +4992=>'L', +4993=>'L', +4994=>'L', +4995=>'L', +4996=>'L', +4997=>'L', +4998=>'L', +4999=>'L', +5000=>'L', +5001=>'L', +5002=>'L', +5003=>'L', +5004=>'L', +5005=>'L', +5006=>'L', +5007=>'L', +5008=>'ON', +5009=>'ON', +5010=>'ON', +5011=>'ON', +5012=>'ON', +5013=>'ON', +5014=>'ON', +5015=>'ON', +5016=>'ON', +5017=>'ON', +5024=>'L', +5025=>'L', +5026=>'L', +5027=>'L', +5028=>'L', +5029=>'L', +5030=>'L', +5031=>'L', +5032=>'L', +5033=>'L', +5034=>'L', +5035=>'L', +5036=>'L', +5037=>'L', +5038=>'L', +5039=>'L', +5040=>'L', +5041=>'L', +5042=>'L', +5043=>'L', +5044=>'L', +5045=>'L', +5046=>'L', +5047=>'L', +5048=>'L', +5049=>'L', +5050=>'L', +5051=>'L', +5052=>'L', +5053=>'L', +5054=>'L', +5055=>'L', +5056=>'L', +5057=>'L', +5058=>'L', +5059=>'L', +5060=>'L', +5061=>'L', +5062=>'L', +5063=>'L', +5064=>'L', +5065=>'L', +5066=>'L', +5067=>'L', +5068=>'L', +5069=>'L', +5070=>'L', +5071=>'L', +5072=>'L', +5073=>'L', +5074=>'L', +5075=>'L', +5076=>'L', +5077=>'L', +5078=>'L', +5079=>'L', +5080=>'L', +5081=>'L', +5082=>'L', +5083=>'L', +5084=>'L', +5085=>'L', +5086=>'L', +5087=>'L', +5088=>'L', +5089=>'L', +5090=>'L', +5091=>'L', +5092=>'L', +5093=>'L', +5094=>'L', +5095=>'L', +5096=>'L', +5097=>'L', +5098=>'L', +5099=>'L', +5100=>'L', +5101=>'L', +5102=>'L', +5103=>'L', +5104=>'L', +5105=>'L', +5106=>'L', +5107=>'L', +5108=>'L', +5121=>'L', +5122=>'L', +5123=>'L', +5124=>'L', +5125=>'L', +5126=>'L', +5127=>'L', +5128=>'L', +5129=>'L', +5130=>'L', +5131=>'L', +5132=>'L', +5133=>'L', +5134=>'L', +5135=>'L', +5136=>'L', +5137=>'L', +5138=>'L', +5139=>'L', +5140=>'L', +5141=>'L', +5142=>'L', +5143=>'L', +5144=>'L', +5145=>'L', +5146=>'L', +5147=>'L', +5148=>'L', +5149=>'L', +5150=>'L', +5151=>'L', +5152=>'L', +5153=>'L', +5154=>'L', +5155=>'L', +5156=>'L', +5157=>'L', +5158=>'L', +5159=>'L', +5160=>'L', +5161=>'L', +5162=>'L', +5163=>'L', +5164=>'L', +5165=>'L', +5166=>'L', +5167=>'L', +5168=>'L', +5169=>'L', +5170=>'L', +5171=>'L', +5172=>'L', +5173=>'L', +5174=>'L', +5175=>'L', +5176=>'L', +5177=>'L', +5178=>'L', +5179=>'L', +5180=>'L', +5181=>'L', +5182=>'L', +5183=>'L', +5184=>'L', +5185=>'L', +5186=>'L', +5187=>'L', +5188=>'L', +5189=>'L', +5190=>'L', +5191=>'L', +5192=>'L', +5193=>'L', +5194=>'L', +5195=>'L', +5196=>'L', +5197=>'L', +5198=>'L', +5199=>'L', +5200=>'L', +5201=>'L', +5202=>'L', +5203=>'L', +5204=>'L', +5205=>'L', +5206=>'L', +5207=>'L', +5208=>'L', +5209=>'L', +5210=>'L', +5211=>'L', +5212=>'L', +5213=>'L', +5214=>'L', +5215=>'L', +5216=>'L', +5217=>'L', +5218=>'L', +5219=>'L', +5220=>'L', +5221=>'L', +5222=>'L', +5223=>'L', +5224=>'L', +5225=>'L', +5226=>'L', +5227=>'L', +5228=>'L', +5229=>'L', +5230=>'L', +5231=>'L', +5232=>'L', +5233=>'L', +5234=>'L', +5235=>'L', +5236=>'L', +5237=>'L', +5238=>'L', +5239=>'L', +5240=>'L', +5241=>'L', +5242=>'L', +5243=>'L', +5244=>'L', +5245=>'L', +5246=>'L', +5247=>'L', +5248=>'L', +5249=>'L', +5250=>'L', +5251=>'L', +5252=>'L', +5253=>'L', +5254=>'L', +5255=>'L', +5256=>'L', +5257=>'L', +5258=>'L', +5259=>'L', +5260=>'L', +5261=>'L', +5262=>'L', +5263=>'L', +5264=>'L', +5265=>'L', +5266=>'L', +5267=>'L', +5268=>'L', +5269=>'L', +5270=>'L', +5271=>'L', +5272=>'L', +5273=>'L', +5274=>'L', +5275=>'L', +5276=>'L', +5277=>'L', +5278=>'L', +5279=>'L', +5280=>'L', +5281=>'L', +5282=>'L', +5283=>'L', +5284=>'L', +5285=>'L', +5286=>'L', +5287=>'L', +5288=>'L', +5289=>'L', +5290=>'L', +5291=>'L', +5292=>'L', +5293=>'L', +5294=>'L', +5295=>'L', +5296=>'L', +5297=>'L', +5298=>'L', +5299=>'L', +5300=>'L', +5301=>'L', +5302=>'L', +5303=>'L', +5304=>'L', +5305=>'L', +5306=>'L', +5307=>'L', +5308=>'L', +5309=>'L', +5310=>'L', +5311=>'L', +5312=>'L', +5313=>'L', +5314=>'L', +5315=>'L', +5316=>'L', +5317=>'L', +5318=>'L', +5319=>'L', +5320=>'L', +5321=>'L', +5322=>'L', +5323=>'L', +5324=>'L', +5325=>'L', +5326=>'L', +5327=>'L', +5328=>'L', +5329=>'L', +5330=>'L', +5331=>'L', +5332=>'L', +5333=>'L', +5334=>'L', +5335=>'L', +5336=>'L', +5337=>'L', +5338=>'L', +5339=>'L', +5340=>'L', +5341=>'L', +5342=>'L', +5343=>'L', +5344=>'L', +5345=>'L', +5346=>'L', +5347=>'L', +5348=>'L', +5349=>'L', +5350=>'L', +5351=>'L', +5352=>'L', +5353=>'L', +5354=>'L', +5355=>'L', +5356=>'L', +5357=>'L', +5358=>'L', +5359=>'L', +5360=>'L', +5361=>'L', +5362=>'L', +5363=>'L', +5364=>'L', +5365=>'L', +5366=>'L', +5367=>'L', +5368=>'L', +5369=>'L', +5370=>'L', +5371=>'L', +5372=>'L', +5373=>'L', +5374=>'L', +5375=>'L', +5376=>'L', +5377=>'L', +5378=>'L', +5379=>'L', +5380=>'L', +5381=>'L', +5382=>'L', +5383=>'L', +5384=>'L', +5385=>'L', +5386=>'L', +5387=>'L', +5388=>'L', +5389=>'L', +5390=>'L', +5391=>'L', +5392=>'L', +5393=>'L', +5394=>'L', +5395=>'L', +5396=>'L', +5397=>'L', +5398=>'L', +5399=>'L', +5400=>'L', +5401=>'L', +5402=>'L', +5403=>'L', +5404=>'L', +5405=>'L', +5406=>'L', +5407=>'L', +5408=>'L', +5409=>'L', +5410=>'L', +5411=>'L', +5412=>'L', +5413=>'L', +5414=>'L', +5415=>'L', +5416=>'L', +5417=>'L', +5418=>'L', +5419=>'L', +5420=>'L', +5421=>'L', +5422=>'L', +5423=>'L', +5424=>'L', +5425=>'L', +5426=>'L', +5427=>'L', +5428=>'L', +5429=>'L', +5430=>'L', +5431=>'L', +5432=>'L', +5433=>'L', +5434=>'L', +5435=>'L', +5436=>'L', +5437=>'L', +5438=>'L', +5439=>'L', +5440=>'L', +5441=>'L', +5442=>'L', +5443=>'L', +5444=>'L', +5445=>'L', +5446=>'L', +5447=>'L', +5448=>'L', +5449=>'L', +5450=>'L', +5451=>'L', +5452=>'L', +5453=>'L', +5454=>'L', +5455=>'L', +5456=>'L', +5457=>'L', +5458=>'L', +5459=>'L', +5460=>'L', +5461=>'L', +5462=>'L', +5463=>'L', +5464=>'L', +5465=>'L', +5466=>'L', +5467=>'L', +5468=>'L', +5469=>'L', +5470=>'L', +5471=>'L', +5472=>'L', +5473=>'L', +5474=>'L', +5475=>'L', +5476=>'L', +5477=>'L', +5478=>'L', +5479=>'L', +5480=>'L', +5481=>'L', +5482=>'L', +5483=>'L', +5484=>'L', +5485=>'L', +5486=>'L', +5487=>'L', +5488=>'L', +5489=>'L', +5490=>'L', +5491=>'L', +5492=>'L', +5493=>'L', +5494=>'L', +5495=>'L', +5496=>'L', +5497=>'L', +5498=>'L', +5499=>'L', +5500=>'L', +5501=>'L', +5502=>'L', +5503=>'L', +5504=>'L', +5505=>'L', +5506=>'L', +5507=>'L', +5508=>'L', +5509=>'L', +5510=>'L', +5511=>'L', +5512=>'L', +5513=>'L', +5514=>'L', +5515=>'L', +5516=>'L', +5517=>'L', +5518=>'L', +5519=>'L', +5520=>'L', +5521=>'L', +5522=>'L', +5523=>'L', +5524=>'L', +5525=>'L', +5526=>'L', +5527=>'L', +5528=>'L', +5529=>'L', +5530=>'L', +5531=>'L', +5532=>'L', +5533=>'L', +5534=>'L', +5535=>'L', +5536=>'L', +5537=>'L', +5538=>'L', +5539=>'L', +5540=>'L', +5541=>'L', +5542=>'L', +5543=>'L', +5544=>'L', +5545=>'L', +5546=>'L', +5547=>'L', +5548=>'L', +5549=>'L', +5550=>'L', +5551=>'L', +5552=>'L', +5553=>'L', +5554=>'L', +5555=>'L', +5556=>'L', +5557=>'L', +5558=>'L', +5559=>'L', +5560=>'L', +5561=>'L', +5562=>'L', +5563=>'L', +5564=>'L', +5565=>'L', +5566=>'L', +5567=>'L', +5568=>'L', +5569=>'L', +5570=>'L', +5571=>'L', +5572=>'L', +5573=>'L', +5574=>'L', +5575=>'L', +5576=>'L', +5577=>'L', +5578=>'L', +5579=>'L', +5580=>'L', +5581=>'L', +5582=>'L', +5583=>'L', +5584=>'L', +5585=>'L', +5586=>'L', +5587=>'L', +5588=>'L', +5589=>'L', +5590=>'L', +5591=>'L', +5592=>'L', +5593=>'L', +5594=>'L', +5595=>'L', +5596=>'L', +5597=>'L', +5598=>'L', +5599=>'L', +5600=>'L', +5601=>'L', +5602=>'L', +5603=>'L', +5604=>'L', +5605=>'L', +5606=>'L', +5607=>'L', +5608=>'L', +5609=>'L', +5610=>'L', +5611=>'L', +5612=>'L', +5613=>'L', +5614=>'L', +5615=>'L', +5616=>'L', +5617=>'L', +5618=>'L', +5619=>'L', +5620=>'L', +5621=>'L', +5622=>'L', +5623=>'L', +5624=>'L', +5625=>'L', +5626=>'L', +5627=>'L', +5628=>'L', +5629=>'L', +5630=>'L', +5631=>'L', +5632=>'L', +5633=>'L', +5634=>'L', +5635=>'L', +5636=>'L', +5637=>'L', +5638=>'L', +5639=>'L', +5640=>'L', +5641=>'L', +5642=>'L', +5643=>'L', +5644=>'L', +5645=>'L', +5646=>'L', +5647=>'L', +5648=>'L', +5649=>'L', +5650=>'L', +5651=>'L', +5652=>'L', +5653=>'L', +5654=>'L', +5655=>'L', +5656=>'L', +5657=>'L', +5658=>'L', +5659=>'L', +5660=>'L', +5661=>'L', +5662=>'L', +5663=>'L', +5664=>'L', +5665=>'L', +5666=>'L', +5667=>'L', +5668=>'L', +5669=>'L', +5670=>'L', +5671=>'L', +5672=>'L', +5673=>'L', +5674=>'L', +5675=>'L', +5676=>'L', +5677=>'L', +5678=>'L', +5679=>'L', +5680=>'L', +5681=>'L', +5682=>'L', +5683=>'L', +5684=>'L', +5685=>'L', +5686=>'L', +5687=>'L', +5688=>'L', +5689=>'L', +5690=>'L', +5691=>'L', +5692=>'L', +5693=>'L', +5694=>'L', +5695=>'L', +5696=>'L', +5697=>'L', +5698=>'L', +5699=>'L', +5700=>'L', +5701=>'L', +5702=>'L', +5703=>'L', +5704=>'L', +5705=>'L', +5706=>'L', +5707=>'L', +5708=>'L', +5709=>'L', +5710=>'L', +5711=>'L', +5712=>'L', +5713=>'L', +5714=>'L', +5715=>'L', +5716=>'L', +5717=>'L', +5718=>'L', +5719=>'L', +5720=>'L', +5721=>'L', +5722=>'L', +5723=>'L', +5724=>'L', +5725=>'L', +5726=>'L', +5727=>'L', +5728=>'L', +5729=>'L', +5730=>'L', +5731=>'L', +5732=>'L', +5733=>'L', +5734=>'L', +5735=>'L', +5736=>'L', +5737=>'L', +5738=>'L', +5739=>'L', +5740=>'L', +5741=>'L', +5742=>'L', +5743=>'L', +5744=>'L', +5745=>'L', +5746=>'L', +5747=>'L', +5748=>'L', +5749=>'L', +5750=>'L', +5760=>'WS', +5761=>'L', +5762=>'L', +5763=>'L', +5764=>'L', +5765=>'L', +5766=>'L', +5767=>'L', +5768=>'L', +5769=>'L', +5770=>'L', +5771=>'L', +5772=>'L', +5773=>'L', +5774=>'L', +5775=>'L', +5776=>'L', +5777=>'L', +5778=>'L', +5779=>'L', +5780=>'L', +5781=>'L', +5782=>'L', +5783=>'L', +5784=>'L', +5785=>'L', +5786=>'L', +5787=>'ON', +5788=>'ON', +5792=>'L', +5793=>'L', +5794=>'L', +5795=>'L', +5796=>'L', +5797=>'L', +5798=>'L', +5799=>'L', +5800=>'L', +5801=>'L', +5802=>'L', +5803=>'L', +5804=>'L', +5805=>'L', +5806=>'L', +5807=>'L', +5808=>'L', +5809=>'L', +5810=>'L', +5811=>'L', +5812=>'L', +5813=>'L', +5814=>'L', +5815=>'L', +5816=>'L', +5817=>'L', +5818=>'L', +5819=>'L', +5820=>'L', +5821=>'L', +5822=>'L', +5823=>'L', +5824=>'L', +5825=>'L', +5826=>'L', +5827=>'L', +5828=>'L', +5829=>'L', +5830=>'L', +5831=>'L', +5832=>'L', +5833=>'L', +5834=>'L', +5835=>'L', +5836=>'L', +5837=>'L', +5838=>'L', +5839=>'L', +5840=>'L', +5841=>'L', +5842=>'L', +5843=>'L', +5844=>'L', +5845=>'L', +5846=>'L', +5847=>'L', +5848=>'L', +5849=>'L', +5850=>'L', +5851=>'L', +5852=>'L', +5853=>'L', +5854=>'L', +5855=>'L', +5856=>'L', +5857=>'L', +5858=>'L', +5859=>'L', +5860=>'L', +5861=>'L', +5862=>'L', +5863=>'L', +5864=>'L', +5865=>'L', +5866=>'L', +5867=>'L', +5868=>'L', +5869=>'L', +5870=>'L', +5871=>'L', +5872=>'L', +5888=>'L', +5889=>'L', +5890=>'L', +5891=>'L', +5892=>'L', +5893=>'L', +5894=>'L', +5895=>'L', +5896=>'L', +5897=>'L', +5898=>'L', +5899=>'L', +5900=>'L', +5902=>'L', +5903=>'L', +5904=>'L', +5905=>'L', +5906=>'NSM', +5907=>'NSM', +5908=>'NSM', +5920=>'L', +5921=>'L', +5922=>'L', +5923=>'L', +5924=>'L', +5925=>'L', +5926=>'L', +5927=>'L', +5928=>'L', +5929=>'L', +5930=>'L', +5931=>'L', +5932=>'L', +5933=>'L', +5934=>'L', +5935=>'L', +5936=>'L', +5937=>'L', +5938=>'NSM', +5939=>'NSM', +5940=>'NSM', +5941=>'L', +5942=>'L', +5952=>'L', +5953=>'L', +5954=>'L', +5955=>'L', +5956=>'L', +5957=>'L', +5958=>'L', +5959=>'L', +5960=>'L', +5961=>'L', +5962=>'L', +5963=>'L', +5964=>'L', +5965=>'L', +5966=>'L', +5967=>'L', +5968=>'L', +5969=>'L', +5970=>'NSM', +5971=>'NSM', +5984=>'L', +5985=>'L', +5986=>'L', +5987=>'L', +5988=>'L', +5989=>'L', +5990=>'L', +5991=>'L', +5992=>'L', +5993=>'L', +5994=>'L', +5995=>'L', +5996=>'L', +5998=>'L', +5999=>'L', +6000=>'L', +6002=>'NSM', +6003=>'NSM', +6016=>'L', +6017=>'L', +6018=>'L', +6019=>'L', +6020=>'L', +6021=>'L', +6022=>'L', +6023=>'L', +6024=>'L', +6025=>'L', +6026=>'L', +6027=>'L', +6028=>'L', +6029=>'L', +6030=>'L', +6031=>'L', +6032=>'L', +6033=>'L', +6034=>'L', +6035=>'L', +6036=>'L', +6037=>'L', +6038=>'L', +6039=>'L', +6040=>'L', +6041=>'L', +6042=>'L', +6043=>'L', +6044=>'L', +6045=>'L', +6046=>'L', +6047=>'L', +6048=>'L', +6049=>'L', +6050=>'L', +6051=>'L', +6052=>'L', +6053=>'L', +6054=>'L', +6055=>'L', +6056=>'L', +6057=>'L', +6058=>'L', +6059=>'L', +6060=>'L', +6061=>'L', +6062=>'L', +6063=>'L', +6064=>'L', +6065=>'L', +6066=>'L', +6067=>'L', +6068=>'L', +6069=>'L', +6070=>'L', +6071=>'NSM', +6072=>'NSM', +6073=>'NSM', +6074=>'NSM', +6075=>'NSM', +6076=>'NSM', +6077=>'NSM', +6078=>'L', +6079=>'L', +6080=>'L', +6081=>'L', +6082=>'L', +6083=>'L', +6084=>'L', +6085=>'L', +6086=>'NSM', +6087=>'L', +6088=>'L', +6089=>'NSM', +6090=>'NSM', +6091=>'NSM', +6092=>'NSM', +6093=>'NSM', +6094=>'NSM', +6095=>'NSM', +6096=>'NSM', +6097=>'NSM', +6098=>'NSM', +6099=>'NSM', +6100=>'L', +6101=>'L', +6102=>'L', +6103=>'L', +6104=>'L', +6105=>'L', +6106=>'L', +6107=>'ET', +6108=>'L', +6109=>'NSM', +6112=>'L', +6113=>'L', +6114=>'L', +6115=>'L', +6116=>'L', +6117=>'L', +6118=>'L', +6119=>'L', +6120=>'L', +6121=>'L', +6128=>'ON', +6129=>'ON', +6130=>'ON', +6131=>'ON', +6132=>'ON', +6133=>'ON', +6134=>'ON', +6135=>'ON', +6136=>'ON', +6137=>'ON', +6144=>'ON', +6145=>'ON', +6146=>'ON', +6147=>'ON', +6148=>'ON', +6149=>'ON', +6150=>'ON', +6151=>'ON', +6152=>'ON', +6153=>'ON', +6154=>'ON', +6155=>'NSM', +6156=>'NSM', +6157=>'NSM', +6158=>'WS', +6160=>'L', +6161=>'L', +6162=>'L', +6163=>'L', +6164=>'L', +6165=>'L', +6166=>'L', +6167=>'L', +6168=>'L', +6169=>'L', +6176=>'L', +6177=>'L', +6178=>'L', +6179=>'L', +6180=>'L', +6181=>'L', +6182=>'L', +6183=>'L', +6184=>'L', +6185=>'L', +6186=>'L', +6187=>'L', +6188=>'L', +6189=>'L', +6190=>'L', +6191=>'L', +6192=>'L', +6193=>'L', +6194=>'L', +6195=>'L', +6196=>'L', +6197=>'L', +6198=>'L', +6199=>'L', +6200=>'L', +6201=>'L', +6202=>'L', +6203=>'L', +6204=>'L', +6205=>'L', +6206=>'L', +6207=>'L', +6208=>'L', +6209=>'L', +6210=>'L', +6211=>'L', +6212=>'L', +6213=>'L', +6214=>'L', +6215=>'L', +6216=>'L', +6217=>'L', +6218=>'L', +6219=>'L', +6220=>'L', +6221=>'L', +6222=>'L', +6223=>'L', +6224=>'L', +6225=>'L', +6226=>'L', +6227=>'L', +6228=>'L', +6229=>'L', +6230=>'L', +6231=>'L', +6232=>'L', +6233=>'L', +6234=>'L', +6235=>'L', +6236=>'L', +6237=>'L', +6238=>'L', +6239=>'L', +6240=>'L', +6241=>'L', +6242=>'L', +6243=>'L', +6244=>'L', +6245=>'L', +6246=>'L', +6247=>'L', +6248=>'L', +6249=>'L', +6250=>'L', +6251=>'L', +6252=>'L', +6253=>'L', +6254=>'L', +6255=>'L', +6256=>'L', +6257=>'L', +6258=>'L', +6259=>'L', +6260=>'L', +6261=>'L', +6262=>'L', +6263=>'L', +6272=>'L', +6273=>'L', +6274=>'L', +6275=>'L', +6276=>'L', +6277=>'L', +6278=>'L', +6279=>'L', +6280=>'L', +6281=>'L', +6282=>'L', +6283=>'L', +6284=>'L', +6285=>'L', +6286=>'L', +6287=>'L', +6288=>'L', +6289=>'L', +6290=>'L', +6291=>'L', +6292=>'L', +6293=>'L', +6294=>'L', +6295=>'L', +6296=>'L', +6297=>'L', +6298=>'L', +6299=>'L', +6300=>'L', +6301=>'L', +6302=>'L', +6303=>'L', +6304=>'L', +6305=>'L', +6306=>'L', +6307=>'L', +6308=>'L', +6309=>'L', +6310=>'L', +6311=>'L', +6312=>'L', +6313=>'NSM', +6400=>'L', +6401=>'L', +6402=>'L', +6403=>'L', +6404=>'L', +6405=>'L', +6406=>'L', +6407=>'L', +6408=>'L', +6409=>'L', +6410=>'L', +6411=>'L', +6412=>'L', +6413=>'L', +6414=>'L', +6415=>'L', +6416=>'L', +6417=>'L', +6418=>'L', +6419=>'L', +6420=>'L', +6421=>'L', +6422=>'L', +6423=>'L', +6424=>'L', +6425=>'L', +6426=>'L', +6427=>'L', +6428=>'L', +6432=>'NSM', +6433=>'NSM', +6434=>'NSM', +6435=>'L', +6436=>'L', +6437=>'L', +6438=>'L', +6439=>'NSM', +6440=>'NSM', +6441=>'NSM', +6442=>'NSM', +6443=>'NSM', +6448=>'L', +6449=>'L', +6450=>'NSM', +6451=>'L', +6452=>'L', +6453=>'L', +6454=>'L', +6455=>'L', +6456=>'L', +6457=>'NSM', +6458=>'NSM', +6459=>'NSM', +6464=>'ON', +6468=>'ON', +6469=>'ON', +6470=>'L', +6471=>'L', +6472=>'L', +6473=>'L', +6474=>'L', +6475=>'L', +6476=>'L', +6477=>'L', +6478=>'L', +6479=>'L', +6480=>'L', +6481=>'L', +6482=>'L', +6483=>'L', +6484=>'L', +6485=>'L', +6486=>'L', +6487=>'L', +6488=>'L', +6489=>'L', +6490=>'L', +6491=>'L', +6492=>'L', +6493=>'L', +6494=>'L', +6495=>'L', +6496=>'L', +6497=>'L', +6498=>'L', +6499=>'L', +6500=>'L', +6501=>'L', +6502=>'L', +6503=>'L', +6504=>'L', +6505=>'L', +6506=>'L', +6507=>'L', +6508=>'L', +6509=>'L', +6512=>'L', +6513=>'L', +6514=>'L', +6515=>'L', +6516=>'L', +6528=>'L', +6529=>'L', +6530=>'L', +6531=>'L', +6532=>'L', +6533=>'L', +6534=>'L', +6535=>'L', +6536=>'L', +6537=>'L', +6538=>'L', +6539=>'L', +6540=>'L', +6541=>'L', +6542=>'L', +6543=>'L', +6544=>'L', +6545=>'L', +6546=>'L', +6547=>'L', +6548=>'L', +6549=>'L', +6550=>'L', +6551=>'L', +6552=>'L', +6553=>'L', +6554=>'L', +6555=>'L', +6556=>'L', +6557=>'L', +6558=>'L', +6559=>'L', +6560=>'L', +6561=>'L', +6562=>'L', +6563=>'L', +6564=>'L', +6565=>'L', +6566=>'L', +6567=>'L', +6568=>'L', +6569=>'L', +6576=>'L', +6577=>'L', +6578=>'L', +6579=>'L', +6580=>'L', +6581=>'L', +6582=>'L', +6583=>'L', +6584=>'L', +6585=>'L', +6586=>'L', +6587=>'L', +6588=>'L', +6589=>'L', +6590=>'L', +6591=>'L', +6592=>'L', +6593=>'L', +6594=>'L', +6595=>'L', +6596=>'L', +6597=>'L', +6598=>'L', +6599=>'L', +6600=>'L', +6601=>'L', +6608=>'L', +6609=>'L', +6610=>'L', +6611=>'L', +6612=>'L', +6613=>'L', +6614=>'L', +6615=>'L', +6616=>'L', +6617=>'L', +6622=>'ON', +6623=>'ON', +6624=>'ON', +6625=>'ON', +6626=>'ON', +6627=>'ON', +6628=>'ON', +6629=>'ON', +6630=>'ON', +6631=>'ON', +6632=>'ON', +6633=>'ON', +6634=>'ON', +6635=>'ON', +6636=>'ON', +6637=>'ON', +6638=>'ON', +6639=>'ON', +6640=>'ON', +6641=>'ON', +6642=>'ON', +6643=>'ON', +6644=>'ON', +6645=>'ON', +6646=>'ON', +6647=>'ON', +6648=>'ON', +6649=>'ON', +6650=>'ON', +6651=>'ON', +6652=>'ON', +6653=>'ON', +6654=>'ON', +6655=>'ON', +6656=>'L', +6657=>'L', +6658=>'L', +6659=>'L', +6660=>'L', +6661=>'L', +6662=>'L', +6663=>'L', +6664=>'L', +6665=>'L', +6666=>'L', +6667=>'L', +6668=>'L', +6669=>'L', +6670=>'L', +6671=>'L', +6672=>'L', +6673=>'L', +6674=>'L', +6675=>'L', +6676=>'L', +6677=>'L', +6678=>'L', +6679=>'NSM', +6680=>'NSM', +6681=>'L', +6682=>'L', +6683=>'L', +6686=>'L', +6687=>'L', +6912=>'NSM', +6913=>'NSM', +6914=>'NSM', +6915=>'NSM', +6916=>'L', +6917=>'L', +6918=>'L', +6919=>'L', +6920=>'L', +6921=>'L', +6922=>'L', +6923=>'L', +6924=>'L', +6925=>'L', +6926=>'L', +6927=>'L', +6928=>'L', +6929=>'L', +6930=>'L', +6931=>'L', +6932=>'L', +6933=>'L', +6934=>'L', +6935=>'L', +6936=>'L', +6937=>'L', +6938=>'L', +6939=>'L', +6940=>'L', +6941=>'L', +6942=>'L', +6943=>'L', +6944=>'L', +6945=>'L', +6946=>'L', +6947=>'L', +6948=>'L', +6949=>'L', +6950=>'L', +6951=>'L', +6952=>'L', +6953=>'L', +6954=>'L', +6955=>'L', +6956=>'L', +6957=>'L', +6958=>'L', +6959=>'L', +6960=>'L', +6961=>'L', +6962=>'L', +6963=>'L', +6964=>'NSM', +6965=>'L', +6966=>'NSM', +6967=>'NSM', +6968=>'NSM', +6969=>'NSM', +6970=>'NSM', +6971=>'L', +6972=>'NSM', +6973=>'L', +6974=>'L', +6975=>'L', +6976=>'L', +6977=>'L', +6978=>'NSM', +6979=>'L', +6980=>'L', +6981=>'L', +6982=>'L', +6983=>'L', +6984=>'L', +6985=>'L', +6986=>'L', +6987=>'L', +6992=>'L', +6993=>'L', +6994=>'L', +6995=>'L', +6996=>'L', +6997=>'L', +6998=>'L', +6999=>'L', +7000=>'L', +7001=>'L', +7002=>'L', +7003=>'L', +7004=>'L', +7005=>'L', +7006=>'L', +7007=>'L', +7008=>'L', +7009=>'L', +7010=>'L', +7011=>'L', +7012=>'L', +7013=>'L', +7014=>'L', +7015=>'L', +7016=>'L', +7017=>'L', +7018=>'L', +7019=>'NSM', +7020=>'NSM', +7021=>'NSM', +7022=>'NSM', +7023=>'NSM', +7024=>'NSM', +7025=>'NSM', +7026=>'NSM', +7027=>'NSM', +7028=>'L', +7029=>'L', +7030=>'L', +7031=>'L', +7032=>'L', +7033=>'L', +7034=>'L', +7035=>'L', +7036=>'L', +7424=>'L', +7425=>'L', +7426=>'L', +7427=>'L', +7428=>'L', +7429=>'L', +7430=>'L', +7431=>'L', +7432=>'L', +7433=>'L', +7434=>'L', +7435=>'L', +7436=>'L', +7437=>'L', +7438=>'L', +7439=>'L', +7440=>'L', +7441=>'L', +7442=>'L', +7443=>'L', +7444=>'L', +7445=>'L', +7446=>'L', +7447=>'L', +7448=>'L', +7449=>'L', +7450=>'L', +7451=>'L', +7452=>'L', +7453=>'L', +7454=>'L', +7455=>'L', +7456=>'L', +7457=>'L', +7458=>'L', +7459=>'L', +7460=>'L', +7461=>'L', +7462=>'L', +7463=>'L', +7464=>'L', +7465=>'L', +7466=>'L', +7467=>'L', +7468=>'L', +7469=>'L', +7470=>'L', +7471=>'L', +7472=>'L', +7473=>'L', +7474=>'L', +7475=>'L', +7476=>'L', +7477=>'L', +7478=>'L', +7479=>'L', +7480=>'L', +7481=>'L', +7482=>'L', +7483=>'L', +7484=>'L', +7485=>'L', +7486=>'L', +7487=>'L', +7488=>'L', +7489=>'L', +7490=>'L', +7491=>'L', +7492=>'L', +7493=>'L', +7494=>'L', +7495=>'L', +7496=>'L', +7497=>'L', +7498=>'L', +7499=>'L', +7500=>'L', +7501=>'L', +7502=>'L', +7503=>'L', +7504=>'L', +7505=>'L', +7506=>'L', +7507=>'L', +7508=>'L', +7509=>'L', +7510=>'L', +7511=>'L', +7512=>'L', +7513=>'L', +7514=>'L', +7515=>'L', +7516=>'L', +7517=>'L', +7518=>'L', +7519=>'L', +7520=>'L', +7521=>'L', +7522=>'L', +7523=>'L', +7524=>'L', +7525=>'L', +7526=>'L', +7527=>'L', +7528=>'L', +7529=>'L', +7530=>'L', +7531=>'L', +7532=>'L', +7533=>'L', +7534=>'L', +7535=>'L', +7536=>'L', +7537=>'L', +7538=>'L', +7539=>'L', +7540=>'L', +7541=>'L', +7542=>'L', +7543=>'L', +7544=>'L', +7545=>'L', +7546=>'L', +7547=>'L', +7548=>'L', +7549=>'L', +7550=>'L', +7551=>'L', +7552=>'L', +7553=>'L', +7554=>'L', +7555=>'L', +7556=>'L', +7557=>'L', +7558=>'L', +7559=>'L', +7560=>'L', +7561=>'L', +7562=>'L', +7563=>'L', +7564=>'L', +7565=>'L', +7566=>'L', +7567=>'L', +7568=>'L', +7569=>'L', +7570=>'L', +7571=>'L', +7572=>'L', +7573=>'L', +7574=>'L', +7575=>'L', +7576=>'L', +7577=>'L', +7578=>'L', +7579=>'L', +7580=>'L', +7581=>'L', +7582=>'L', +7583=>'L', +7584=>'L', +7585=>'L', +7586=>'L', +7587=>'L', +7588=>'L', +7589=>'L', +7590=>'L', +7591=>'L', +7592=>'L', +7593=>'L', +7594=>'L', +7595=>'L', +7596=>'L', +7597=>'L', +7598=>'L', +7599=>'L', +7600=>'L', +7601=>'L', +7602=>'L', +7603=>'L', +7604=>'L', +7605=>'L', +7606=>'L', +7607=>'L', +7608=>'L', +7609=>'L', +7610=>'L', +7611=>'L', +7612=>'L', +7613=>'L', +7614=>'L', +7615=>'L', +7616=>'NSM', +7617=>'NSM', +7618=>'NSM', +7619=>'NSM', +7620=>'NSM', +7621=>'NSM', +7622=>'NSM', +7623=>'NSM', +7624=>'NSM', +7625=>'NSM', +7626=>'NSM', +7678=>'NSM', +7679=>'NSM', +7680=>'L', +7681=>'L', +7682=>'L', +7683=>'L', +7684=>'L', +7685=>'L', +7686=>'L', +7687=>'L', +7688=>'L', +7689=>'L', +7690=>'L', +7691=>'L', +7692=>'L', +7693=>'L', +7694=>'L', +7695=>'L', +7696=>'L', +7697=>'L', +7698=>'L', +7699=>'L', +7700=>'L', +7701=>'L', +7702=>'L', +7703=>'L', +7704=>'L', +7705=>'L', +7706=>'L', +7707=>'L', +7708=>'L', +7709=>'L', +7710=>'L', +7711=>'L', +7712=>'L', +7713=>'L', +7714=>'L', +7715=>'L', +7716=>'L', +7717=>'L', +7718=>'L', +7719=>'L', +7720=>'L', +7721=>'L', +7722=>'L', +7723=>'L', +7724=>'L', +7725=>'L', +7726=>'L', +7727=>'L', +7728=>'L', +7729=>'L', +7730=>'L', +7731=>'L', +7732=>'L', +7733=>'L', +7734=>'L', +7735=>'L', +7736=>'L', +7737=>'L', +7738=>'L', +7739=>'L', +7740=>'L', +7741=>'L', +7742=>'L', +7743=>'L', +7744=>'L', +7745=>'L', +7746=>'L', +7747=>'L', +7748=>'L', +7749=>'L', +7750=>'L', +7751=>'L', +7752=>'L', +7753=>'L', +7754=>'L', +7755=>'L', +7756=>'L', +7757=>'L', +7758=>'L', +7759=>'L', +7760=>'L', +7761=>'L', +7762=>'L', +7763=>'L', +7764=>'L', +7765=>'L', +7766=>'L', +7767=>'L', +7768=>'L', +7769=>'L', +7770=>'L', +7771=>'L', +7772=>'L', +7773=>'L', +7774=>'L', +7775=>'L', +7776=>'L', +7777=>'L', +7778=>'L', +7779=>'L', +7780=>'L', +7781=>'L', +7782=>'L', +7783=>'L', +7784=>'L', +7785=>'L', +7786=>'L', +7787=>'L', +7788=>'L', +7789=>'L', +7790=>'L', +7791=>'L', +7792=>'L', +7793=>'L', +7794=>'L', +7795=>'L', +7796=>'L', +7797=>'L', +7798=>'L', +7799=>'L', +7800=>'L', +7801=>'L', +7802=>'L', +7803=>'L', +7804=>'L', +7805=>'L', +7806=>'L', +7807=>'L', +7808=>'L', +7809=>'L', +7810=>'L', +7811=>'L', +7812=>'L', +7813=>'L', +7814=>'L', +7815=>'L', +7816=>'L', +7817=>'L', +7818=>'L', +7819=>'L', +7820=>'L', +7821=>'L', +7822=>'L', +7823=>'L', +7824=>'L', +7825=>'L', +7826=>'L', +7827=>'L', +7828=>'L', +7829=>'L', +7830=>'L', +7831=>'L', +7832=>'L', +7833=>'L', +7834=>'L', +7835=>'L', +7840=>'L', +7841=>'L', +7842=>'L', +7843=>'L', +7844=>'L', +7845=>'L', +7846=>'L', +7847=>'L', +7848=>'L', +7849=>'L', +7850=>'L', +7851=>'L', +7852=>'L', +7853=>'L', +7854=>'L', +7855=>'L', +7856=>'L', +7857=>'L', +7858=>'L', +7859=>'L', +7860=>'L', +7861=>'L', +7862=>'L', +7863=>'L', +7864=>'L', +7865=>'L', +7866=>'L', +7867=>'L', +7868=>'L', +7869=>'L', +7870=>'L', +7871=>'L', +7872=>'L', +7873=>'L', +7874=>'L', +7875=>'L', +7876=>'L', +7877=>'L', +7878=>'L', +7879=>'L', +7880=>'L', +7881=>'L', +7882=>'L', +7883=>'L', +7884=>'L', +7885=>'L', +7886=>'L', +7887=>'L', +7888=>'L', +7889=>'L', +7890=>'L', +7891=>'L', +7892=>'L', +7893=>'L', +7894=>'L', +7895=>'L', +7896=>'L', +7897=>'L', +7898=>'L', +7899=>'L', +7900=>'L', +7901=>'L', +7902=>'L', +7903=>'L', +7904=>'L', +7905=>'L', +7906=>'L', +7907=>'L', +7908=>'L', +7909=>'L', +7910=>'L', +7911=>'L', +7912=>'L', +7913=>'L', +7914=>'L', +7915=>'L', +7916=>'L', +7917=>'L', +7918=>'L', +7919=>'L', +7920=>'L', +7921=>'L', +7922=>'L', +7923=>'L', +7924=>'L', +7925=>'L', +7926=>'L', +7927=>'L', +7928=>'L', +7929=>'L', +7936=>'L', +7937=>'L', +7938=>'L', +7939=>'L', +7940=>'L', +7941=>'L', +7942=>'L', +7943=>'L', +7944=>'L', +7945=>'L', +7946=>'L', +7947=>'L', +7948=>'L', +7949=>'L', +7950=>'L', +7951=>'L', +7952=>'L', +7953=>'L', +7954=>'L', +7955=>'L', +7956=>'L', +7957=>'L', +7960=>'L', +7961=>'L', +7962=>'L', +7963=>'L', +7964=>'L', +7965=>'L', +7968=>'L', +7969=>'L', +7970=>'L', +7971=>'L', +7972=>'L', +7973=>'L', +7974=>'L', +7975=>'L', +7976=>'L', +7977=>'L', +7978=>'L', +7979=>'L', +7980=>'L', +7981=>'L', +7982=>'L', +7983=>'L', +7984=>'L', +7985=>'L', +7986=>'L', +7987=>'L', +7988=>'L', +7989=>'L', +7990=>'L', +7991=>'L', +7992=>'L', +7993=>'L', +7994=>'L', +7995=>'L', +7996=>'L', +7997=>'L', +7998=>'L', +7999=>'L', +8000=>'L', +8001=>'L', +8002=>'L', +8003=>'L', +8004=>'L', +8005=>'L', +8008=>'L', +8009=>'L', +8010=>'L', +8011=>'L', +8012=>'L', +8013=>'L', +8016=>'L', +8017=>'L', +8018=>'L', +8019=>'L', +8020=>'L', +8021=>'L', +8022=>'L', +8023=>'L', +8025=>'L', +8027=>'L', +8029=>'L', +8031=>'L', +8032=>'L', +8033=>'L', +8034=>'L', +8035=>'L', +8036=>'L', +8037=>'L', +8038=>'L', +8039=>'L', +8040=>'L', +8041=>'L', +8042=>'L', +8043=>'L', +8044=>'L', +8045=>'L', +8046=>'L', +8047=>'L', +8048=>'L', +8049=>'L', +8050=>'L', +8051=>'L', +8052=>'L', +8053=>'L', +8054=>'L', +8055=>'L', +8056=>'L', +8057=>'L', +8058=>'L', +8059=>'L', +8060=>'L', +8061=>'L', +8064=>'L', +8065=>'L', +8066=>'L', +8067=>'L', +8068=>'L', +8069=>'L', +8070=>'L', +8071=>'L', +8072=>'L', +8073=>'L', +8074=>'L', +8075=>'L', +8076=>'L', +8077=>'L', +8078=>'L', +8079=>'L', +8080=>'L', +8081=>'L', +8082=>'L', +8083=>'L', +8084=>'L', +8085=>'L', +8086=>'L', +8087=>'L', +8088=>'L', +8089=>'L', +8090=>'L', +8091=>'L', +8092=>'L', +8093=>'L', +8094=>'L', +8095=>'L', +8096=>'L', +8097=>'L', +8098=>'L', +8099=>'L', +8100=>'L', +8101=>'L', +8102=>'L', +8103=>'L', +8104=>'L', +8105=>'L', +8106=>'L', +8107=>'L', +8108=>'L', +8109=>'L', +8110=>'L', +8111=>'L', +8112=>'L', +8113=>'L', +8114=>'L', +8115=>'L', +8116=>'L', +8118=>'L', +8119=>'L', +8120=>'L', +8121=>'L', +8122=>'L', +8123=>'L', +8124=>'L', +8125=>'ON', +8126=>'L', +8127=>'ON', +8128=>'ON', +8129=>'ON', +8130=>'L', +8131=>'L', +8132=>'L', +8134=>'L', +8135=>'L', +8136=>'L', +8137=>'L', +8138=>'L', +8139=>'L', +8140=>'L', +8141=>'ON', +8142=>'ON', +8143=>'ON', +8144=>'L', +8145=>'L', +8146=>'L', +8147=>'L', +8150=>'L', +8151=>'L', +8152=>'L', +8153=>'L', +8154=>'L', +8155=>'L', +8157=>'ON', +8158=>'ON', +8159=>'ON', +8160=>'L', +8161=>'L', +8162=>'L', +8163=>'L', +8164=>'L', +8165=>'L', +8166=>'L', +8167=>'L', +8168=>'L', +8169=>'L', +8170=>'L', +8171=>'L', +8172=>'L', +8173=>'ON', +8174=>'ON', +8175=>'ON', +8178=>'L', +8179=>'L', +8180=>'L', +8182=>'L', +8183=>'L', +8184=>'L', +8185=>'L', +8186=>'L', +8187=>'L', +8188=>'L', +8189=>'ON', +8190=>'ON', +8192=>'WS', +8193=>'WS', +8194=>'WS', +8195=>'WS', +8196=>'WS', +8197=>'WS', +8198=>'WS', +8199=>'WS', +8200=>'WS', +8201=>'WS', +8202=>'WS', +8203=>'BN', +8204=>'BN', +8205=>'BN', +8206=>'L', +8207=>'R', +8208=>'ON', +8209=>'ON', +8210=>'ON', +8211=>'ON', +8212=>'ON', +8213=>'ON', +8214=>'ON', +8215=>'ON', +8216=>'ON', +8217=>'ON', +8218=>'ON', +8219=>'ON', +8220=>'ON', +8221=>'ON', +8222=>'ON', +8223=>'ON', +8224=>'ON', +8225=>'ON', +8226=>'ON', +8227=>'ON', +8228=>'ON', +8229=>'ON', +8230=>'ON', +8231=>'ON', +8232=>'WS', +8233=>'B', +8234=>'LRE', +8235=>'RLE', +8236=>'PDF', +8237=>'LRO', +8238=>'RLO', +8239=>'CS', +8240=>'ET', +8241=>'ET', +8242=>'ET', +8243=>'ET', +8244=>'ET', +8245=>'ON', +8246=>'ON', +8247=>'ON', +8248=>'ON', +8249=>'ON', +8250=>'ON', +8251=>'ON', +8252=>'ON', +8253=>'ON', +8254=>'ON', +8255=>'ON', +8256=>'ON', +8257=>'ON', +8258=>'ON', +8259=>'ON', +8260=>'CS', +8261=>'ON', +8262=>'ON', +8263=>'ON', +8264=>'ON', +8265=>'ON', +8266=>'ON', +8267=>'ON', +8268=>'ON', +8269=>'ON', +8270=>'ON', +8271=>'ON', +8272=>'ON', +8273=>'ON', +8274=>'ON', +8275=>'ON', +8276=>'ON', +8277=>'ON', +8278=>'ON', +8279=>'ON', +8280=>'ON', +8281=>'ON', +8282=>'ON', +8283=>'ON', +8284=>'ON', +8285=>'ON', +8286=>'ON', +8287=>'WS', +8288=>'BN', +8289=>'BN', +8290=>'BN', +8291=>'BN', +8298=>'BN', +8299=>'BN', +8300=>'BN', +8301=>'BN', +8302=>'BN', +8303=>'BN', +8304=>'EN', +8305=>'L', +8308=>'EN', +8309=>'EN', +8310=>'EN', +8311=>'EN', +8312=>'EN', +8313=>'EN', +8314=>'ES', +8315=>'ES', +8316=>'ON', +8317=>'ON', +8318=>'ON', +8319=>'L', +8320=>'EN', +8321=>'EN', +8322=>'EN', +8323=>'EN', +8324=>'EN', +8325=>'EN', +8326=>'EN', +8327=>'EN', +8328=>'EN', +8329=>'EN', +8330=>'ES', +8331=>'ES', +8332=>'ON', +8333=>'ON', +8334=>'ON', +8336=>'L', +8337=>'L', +8338=>'L', +8339=>'L', +8340=>'L', +8352=>'ET', +8353=>'ET', +8354=>'ET', +8355=>'ET', +8356=>'ET', +8357=>'ET', +8358=>'ET', +8359=>'ET', +8360=>'ET', +8361=>'ET', +8362=>'ET', +8363=>'ET', +8364=>'ET', +8365=>'ET', +8366=>'ET', +8367=>'ET', +8368=>'ET', +8369=>'ET', +8370=>'ET', +8371=>'ET', +8372=>'ET', +8373=>'ET', +8400=>'NSM', +8401=>'NSM', +8402=>'NSM', +8403=>'NSM', +8404=>'NSM', +8405=>'NSM', +8406=>'NSM', +8407=>'NSM', +8408=>'NSM', +8409=>'NSM', +8410=>'NSM', +8411=>'NSM', +8412=>'NSM', +8413=>'NSM', +8414=>'NSM', +8415=>'NSM', +8416=>'NSM', +8417=>'NSM', +8418=>'NSM', +8419=>'NSM', +8420=>'NSM', +8421=>'NSM', +8422=>'NSM', +8423=>'NSM', +8424=>'NSM', +8425=>'NSM', +8426=>'NSM', +8427=>'NSM', +8428=>'NSM', +8429=>'NSM', +8430=>'NSM', +8431=>'NSM', +8448=>'ON', +8449=>'ON', +8450=>'L', +8451=>'ON', +8452=>'ON', +8453=>'ON', +8454=>'ON', +8455=>'L', +8456=>'ON', +8457=>'ON', +8458=>'L', +8459=>'L', +8460=>'L', +8461=>'L', +8462=>'L', +8463=>'L', +8464=>'L', +8465=>'L', +8466=>'L', +8467=>'L', +8468=>'ON', +8469=>'L', +8470=>'ON', +8471=>'ON', +8472=>'ON', +8473=>'L', +8474=>'L', +8475=>'L', +8476=>'L', +8477=>'L', +8478=>'ON', +8479=>'ON', +8480=>'ON', +8481=>'ON', +8482=>'ON', +8483=>'ON', +8484=>'L', +8485=>'ON', +8486=>'L', +8487=>'ON', +8488=>'L', +8489=>'ON', +8490=>'L', +8491=>'L', +8492=>'L', +8493=>'L', +8494=>'ET', +8495=>'L', +8496=>'L', +8497=>'L', +8498=>'L', +8499=>'L', +8500=>'L', +8501=>'L', +8502=>'L', +8503=>'L', +8504=>'L', +8505=>'L', +8506=>'ON', +8507=>'ON', +8508=>'L', +8509=>'L', +8510=>'L', +8511=>'L', +8512=>'ON', +8513=>'ON', +8514=>'ON', +8515=>'ON', +8516=>'ON', +8517=>'L', +8518=>'L', +8519=>'L', +8520=>'L', +8521=>'L', +8522=>'ON', +8523=>'ON', +8524=>'ON', +8525=>'ON', +8526=>'L', +8531=>'ON', +8532=>'ON', +8533=>'ON', +8534=>'ON', +8535=>'ON', +8536=>'ON', +8537=>'ON', +8538=>'ON', +8539=>'ON', +8540=>'ON', +8541=>'ON', +8542=>'ON', +8543=>'ON', +8544=>'L', +8545=>'L', +8546=>'L', +8547=>'L', +8548=>'L', +8549=>'L', +8550=>'L', +8551=>'L', +8552=>'L', +8553=>'L', +8554=>'L', +8555=>'L', +8556=>'L', +8557=>'L', +8558=>'L', +8559=>'L', +8560=>'L', +8561=>'L', +8562=>'L', +8563=>'L', +8564=>'L', +8565=>'L', +8566=>'L', +8567=>'L', +8568=>'L', +8569=>'L', +8570=>'L', +8571=>'L', +8572=>'L', +8573=>'L', +8574=>'L', +8575=>'L', +8576=>'L', +8577=>'L', +8578=>'L', +8579=>'L', +8580=>'L', +8592=>'ON', +8593=>'ON', +8594=>'ON', +8595=>'ON', +8596=>'ON', +8597=>'ON', +8598=>'ON', +8599=>'ON', +8600=>'ON', +8601=>'ON', +8602=>'ON', +8603=>'ON', +8604=>'ON', +8605=>'ON', +8606=>'ON', +8607=>'ON', +8608=>'ON', +8609=>'ON', +8610=>'ON', +8611=>'ON', +8612=>'ON', +8613=>'ON', +8614=>'ON', +8615=>'ON', +8616=>'ON', +8617=>'ON', +8618=>'ON', +8619=>'ON', +8620=>'ON', +8621=>'ON', +8622=>'ON', +8623=>'ON', +8624=>'ON', +8625=>'ON', +8626=>'ON', +8627=>'ON', +8628=>'ON', +8629=>'ON', +8630=>'ON', +8631=>'ON', +8632=>'ON', +8633=>'ON', +8634=>'ON', +8635=>'ON', +8636=>'ON', +8637=>'ON', +8638=>'ON', +8639=>'ON', +8640=>'ON', +8641=>'ON', +8642=>'ON', +8643=>'ON', +8644=>'ON', +8645=>'ON', +8646=>'ON', +8647=>'ON', +8648=>'ON', +8649=>'ON', +8650=>'ON', +8651=>'ON', +8652=>'ON', +8653=>'ON', +8654=>'ON', +8655=>'ON', +8656=>'ON', +8657=>'ON', +8658=>'ON', +8659=>'ON', +8660=>'ON', +8661=>'ON', +8662=>'ON', +8663=>'ON', +8664=>'ON', +8665=>'ON', +8666=>'ON', +8667=>'ON', +8668=>'ON', +8669=>'ON', +8670=>'ON', +8671=>'ON', +8672=>'ON', +8673=>'ON', +8674=>'ON', +8675=>'ON', +8676=>'ON', +8677=>'ON', +8678=>'ON', +8679=>'ON', +8680=>'ON', +8681=>'ON', +8682=>'ON', +8683=>'ON', +8684=>'ON', +8685=>'ON', +8686=>'ON', +8687=>'ON', +8688=>'ON', +8689=>'ON', +8690=>'ON', +8691=>'ON', +8692=>'ON', +8693=>'ON', +8694=>'ON', +8695=>'ON', +8696=>'ON', +8697=>'ON', +8698=>'ON', +8699=>'ON', +8700=>'ON', +8701=>'ON', +8702=>'ON', +8703=>'ON', +8704=>'ON', +8705=>'ON', +8706=>'ON', +8707=>'ON', +8708=>'ON', +8709=>'ON', +8710=>'ON', +8711=>'ON', +8712=>'ON', +8713=>'ON', +8714=>'ON', +8715=>'ON', +8716=>'ON', +8717=>'ON', +8718=>'ON', +8719=>'ON', +8720=>'ON', +8721=>'ON', +8722=>'ES', +8723=>'ET', +8724=>'ON', +8725=>'ON', +8726=>'ON', +8727=>'ON', +8728=>'ON', +8729=>'ON', +8730=>'ON', +8731=>'ON', +8732=>'ON', +8733=>'ON', +8734=>'ON', +8735=>'ON', +8736=>'ON', +8737=>'ON', +8738=>'ON', +8739=>'ON', +8740=>'ON', +8741=>'ON', +8742=>'ON', +8743=>'ON', +8744=>'ON', +8745=>'ON', +8746=>'ON', +8747=>'ON', +8748=>'ON', +8749=>'ON', +8750=>'ON', +8751=>'ON', +8752=>'ON', +8753=>'ON', +8754=>'ON', +8755=>'ON', +8756=>'ON', +8757=>'ON', +8758=>'ON', +8759=>'ON', +8760=>'ON', +8761=>'ON', +8762=>'ON', +8763=>'ON', +8764=>'ON', +8765=>'ON', +8766=>'ON', +8767=>'ON', +8768=>'ON', +8769=>'ON', +8770=>'ON', +8771=>'ON', +8772=>'ON', +8773=>'ON', +8774=>'ON', +8775=>'ON', +8776=>'ON', +8777=>'ON', +8778=>'ON', +8779=>'ON', +8780=>'ON', +8781=>'ON', +8782=>'ON', +8783=>'ON', +8784=>'ON', +8785=>'ON', +8786=>'ON', +8787=>'ON', +8788=>'ON', +8789=>'ON', +8790=>'ON', +8791=>'ON', +8792=>'ON', +8793=>'ON', +8794=>'ON', +8795=>'ON', +8796=>'ON', +8797=>'ON', +8798=>'ON', +8799=>'ON', +8800=>'ON', +8801=>'ON', +8802=>'ON', +8803=>'ON', +8804=>'ON', +8805=>'ON', +8806=>'ON', +8807=>'ON', +8808=>'ON', +8809=>'ON', +8810=>'ON', +8811=>'ON', +8812=>'ON', +8813=>'ON', +8814=>'ON', +8815=>'ON', +8816=>'ON', +8817=>'ON', +8818=>'ON', +8819=>'ON', +8820=>'ON', +8821=>'ON', +8822=>'ON', +8823=>'ON', +8824=>'ON', +8825=>'ON', +8826=>'ON', +8827=>'ON', +8828=>'ON', +8829=>'ON', +8830=>'ON', +8831=>'ON', +8832=>'ON', +8833=>'ON', +8834=>'ON', +8835=>'ON', +8836=>'ON', +8837=>'ON', +8838=>'ON', +8839=>'ON', +8840=>'ON', +8841=>'ON', +8842=>'ON', +8843=>'ON', +8844=>'ON', +8845=>'ON', +8846=>'ON', +8847=>'ON', +8848=>'ON', +8849=>'ON', +8850=>'ON', +8851=>'ON', +8852=>'ON', +8853=>'ON', +8854=>'ON', +8855=>'ON', +8856=>'ON', +8857=>'ON', +8858=>'ON', +8859=>'ON', +8860=>'ON', +8861=>'ON', +8862=>'ON', +8863=>'ON', +8864=>'ON', +8865=>'ON', +8866=>'ON', +8867=>'ON', +8868=>'ON', +8869=>'ON', +8870=>'ON', +8871=>'ON', +8872=>'ON', +8873=>'ON', +8874=>'ON', +8875=>'ON', +8876=>'ON', +8877=>'ON', +8878=>'ON', +8879=>'ON', +8880=>'ON', +8881=>'ON', +8882=>'ON', +8883=>'ON', +8884=>'ON', +8885=>'ON', +8886=>'ON', +8887=>'ON', +8888=>'ON', +8889=>'ON', +8890=>'ON', +8891=>'ON', +8892=>'ON', +8893=>'ON', +8894=>'ON', +8895=>'ON', +8896=>'ON', +8897=>'ON', +8898=>'ON', +8899=>'ON', +8900=>'ON', +8901=>'ON', +8902=>'ON', +8903=>'ON', +8904=>'ON', +8905=>'ON', +8906=>'ON', +8907=>'ON', +8908=>'ON', +8909=>'ON', +8910=>'ON', +8911=>'ON', +8912=>'ON', +8913=>'ON', +8914=>'ON', +8915=>'ON', +8916=>'ON', +8917=>'ON', +8918=>'ON', +8919=>'ON', +8920=>'ON', +8921=>'ON', +8922=>'ON', +8923=>'ON', +8924=>'ON', +8925=>'ON', +8926=>'ON', +8927=>'ON', +8928=>'ON', +8929=>'ON', +8930=>'ON', +8931=>'ON', +8932=>'ON', +8933=>'ON', +8934=>'ON', +8935=>'ON', +8936=>'ON', +8937=>'ON', +8938=>'ON', +8939=>'ON', +8940=>'ON', +8941=>'ON', +8942=>'ON', +8943=>'ON', +8944=>'ON', +8945=>'ON', +8946=>'ON', +8947=>'ON', +8948=>'ON', +8949=>'ON', +8950=>'ON', +8951=>'ON', +8952=>'ON', +8953=>'ON', +8954=>'ON', +8955=>'ON', +8956=>'ON', +8957=>'ON', +8958=>'ON', +8959=>'ON', +8960=>'ON', +8961=>'ON', +8962=>'ON', +8963=>'ON', +8964=>'ON', +8965=>'ON', +8966=>'ON', +8967=>'ON', +8968=>'ON', +8969=>'ON', +8970=>'ON', +8971=>'ON', +8972=>'ON', +8973=>'ON', +8974=>'ON', +8975=>'ON', +8976=>'ON', +8977=>'ON', +8978=>'ON', +8979=>'ON', +8980=>'ON', +8981=>'ON', +8982=>'ON', +8983=>'ON', +8984=>'ON', +8985=>'ON', +8986=>'ON', +8987=>'ON', +8988=>'ON', +8989=>'ON', +8990=>'ON', +8991=>'ON', +8992=>'ON', +8993=>'ON', +8994=>'ON', +8995=>'ON', +8996=>'ON', +8997=>'ON', +8998=>'ON', +8999=>'ON', +9000=>'ON', +9001=>'ON', +9002=>'ON', +9003=>'ON', +9004=>'ON', +9005=>'ON', +9006=>'ON', +9007=>'ON', +9008=>'ON', +9009=>'ON', +9010=>'ON', +9011=>'ON', +9012=>'ON', +9013=>'ON', +9014=>'L', +9015=>'L', +9016=>'L', +9017=>'L', +9018=>'L', +9019=>'L', +9020=>'L', +9021=>'L', +9022=>'L', +9023=>'L', +9024=>'L', +9025=>'L', +9026=>'L', +9027=>'L', +9028=>'L', +9029=>'L', +9030=>'L', +9031=>'L', +9032=>'L', +9033=>'L', +9034=>'L', +9035=>'L', +9036=>'L', +9037=>'L', +9038=>'L', +9039=>'L', +9040=>'L', +9041=>'L', +9042=>'L', +9043=>'L', +9044=>'L', +9045=>'L', +9046=>'L', +9047=>'L', +9048=>'L', +9049=>'L', +9050=>'L', +9051=>'L', +9052=>'L', +9053=>'L', +9054=>'L', +9055=>'L', +9056=>'L', +9057=>'L', +9058=>'L', +9059=>'L', +9060=>'L', +9061=>'L', +9062=>'L', +9063=>'L', +9064=>'L', +9065=>'L', +9066=>'L', +9067=>'L', +9068=>'L', +9069=>'L', +9070=>'L', +9071=>'L', +9072=>'L', +9073=>'L', +9074=>'L', +9075=>'L', +9076=>'L', +9077=>'L', +9078=>'L', +9079=>'L', +9080=>'L', +9081=>'L', +9082=>'L', +9083=>'ON', +9084=>'ON', +9085=>'ON', +9086=>'ON', +9087=>'ON', +9088=>'ON', +9089=>'ON', +9090=>'ON', +9091=>'ON', +9092=>'ON', +9093=>'ON', +9094=>'ON', +9095=>'ON', +9096=>'ON', +9097=>'ON', +9098=>'ON', +9099=>'ON', +9100=>'ON', +9101=>'ON', +9102=>'ON', +9103=>'ON', +9104=>'ON', +9105=>'ON', +9106=>'ON', +9107=>'ON', +9108=>'ON', +9109=>'L', +9110=>'ON', +9111=>'ON', +9112=>'ON', +9113=>'ON', +9114=>'ON', +9115=>'ON', +9116=>'ON', +9117=>'ON', +9118=>'ON', +9119=>'ON', +9120=>'ON', +9121=>'ON', +9122=>'ON', +9123=>'ON', +9124=>'ON', +9125=>'ON', +9126=>'ON', +9127=>'ON', +9128=>'ON', +9129=>'ON', +9130=>'ON', +9131=>'ON', +9132=>'ON', +9133=>'ON', +9134=>'ON', +9135=>'ON', +9136=>'ON', +9137=>'ON', +9138=>'ON', +9139=>'ON', +9140=>'ON', +9141=>'ON', +9142=>'ON', +9143=>'ON', +9144=>'ON', +9145=>'ON', +9146=>'ON', +9147=>'ON', +9148=>'ON', +9149=>'ON', +9150=>'ON', +9151=>'ON', +9152=>'ON', +9153=>'ON', +9154=>'ON', +9155=>'ON', +9156=>'ON', +9157=>'ON', +9158=>'ON', +9159=>'ON', +9160=>'ON', +9161=>'ON', +9162=>'ON', +9163=>'ON', +9164=>'ON', +9165=>'ON', +9166=>'ON', +9167=>'ON', +9168=>'ON', +9169=>'ON', +9170=>'ON', +9171=>'ON', +9172=>'ON', +9173=>'ON', +9174=>'ON', +9175=>'ON', +9176=>'ON', +9177=>'ON', +9178=>'ON', +9179=>'ON', +9180=>'ON', +9181=>'ON', +9182=>'ON', +9183=>'ON', +9184=>'ON', +9185=>'ON', +9186=>'ON', +9187=>'ON', +9188=>'ON', +9189=>'ON', +9190=>'ON', +9191=>'ON', +9216=>'ON', +9217=>'ON', +9218=>'ON', +9219=>'ON', +9220=>'ON', +9221=>'ON', +9222=>'ON', +9223=>'ON', +9224=>'ON', +9225=>'ON', +9226=>'ON', +9227=>'ON', +9228=>'ON', +9229=>'ON', +9230=>'ON', +9231=>'ON', +9232=>'ON', +9233=>'ON', +9234=>'ON', +9235=>'ON', +9236=>'ON', +9237=>'ON', +9238=>'ON', +9239=>'ON', +9240=>'ON', +9241=>'ON', +9242=>'ON', +9243=>'ON', +9244=>'ON', +9245=>'ON', +9246=>'ON', +9247=>'ON', +9248=>'ON', +9249=>'ON', +9250=>'ON', +9251=>'ON', +9252=>'ON', +9253=>'ON', +9254=>'ON', +9280=>'ON', +9281=>'ON', +9282=>'ON', +9283=>'ON', +9284=>'ON', +9285=>'ON', +9286=>'ON', +9287=>'ON', +9288=>'ON', +9289=>'ON', +9290=>'ON', +9312=>'ON', +9313=>'ON', +9314=>'ON', +9315=>'ON', +9316=>'ON', +9317=>'ON', +9318=>'ON', +9319=>'ON', +9320=>'ON', +9321=>'ON', +9322=>'ON', +9323=>'ON', +9324=>'ON', +9325=>'ON', +9326=>'ON', +9327=>'ON', +9328=>'ON', +9329=>'ON', +9330=>'ON', +9331=>'ON', +9332=>'ON', +9333=>'ON', +9334=>'ON', +9335=>'ON', +9336=>'ON', +9337=>'ON', +9338=>'ON', +9339=>'ON', +9340=>'ON', +9341=>'ON', +9342=>'ON', +9343=>'ON', +9344=>'ON', +9345=>'ON', +9346=>'ON', +9347=>'ON', +9348=>'ON', +9349=>'ON', +9350=>'ON', +9351=>'ON', +9352=>'EN', +9353=>'EN', +9354=>'EN', +9355=>'EN', +9356=>'EN', +9357=>'EN', +9358=>'EN', +9359=>'EN', +9360=>'EN', +9361=>'EN', +9362=>'EN', +9363=>'EN', +9364=>'EN', +9365=>'EN', +9366=>'EN', +9367=>'EN', +9368=>'EN', +9369=>'EN', +9370=>'EN', +9371=>'EN', +9372=>'L', +9373=>'L', +9374=>'L', +9375=>'L', +9376=>'L', +9377=>'L', +9378=>'L', +9379=>'L', +9380=>'L', +9381=>'L', +9382=>'L', +9383=>'L', +9384=>'L', +9385=>'L', +9386=>'L', +9387=>'L', +9388=>'L', +9389=>'L', +9390=>'L', +9391=>'L', +9392=>'L', +9393=>'L', +9394=>'L', +9395=>'L', +9396=>'L', +9397=>'L', +9398=>'L', +9399=>'L', +9400=>'L', +9401=>'L', +9402=>'L', +9403=>'L', +9404=>'L', +9405=>'L', +9406=>'L', +9407=>'L', +9408=>'L', +9409=>'L', +9410=>'L', +9411=>'L', +9412=>'L', +9413=>'L', +9414=>'L', +9415=>'L', +9416=>'L', +9417=>'L', +9418=>'L', +9419=>'L', +9420=>'L', +9421=>'L', +9422=>'L', +9423=>'L', +9424=>'L', +9425=>'L', +9426=>'L', +9427=>'L', +9428=>'L', +9429=>'L', +9430=>'L', +9431=>'L', +9432=>'L', +9433=>'L', +9434=>'L', +9435=>'L', +9436=>'L', +9437=>'L', +9438=>'L', +9439=>'L', +9440=>'L', +9441=>'L', +9442=>'L', +9443=>'L', +9444=>'L', +9445=>'L', +9446=>'L', +9447=>'L', +9448=>'L', +9449=>'L', +9450=>'ON', +9451=>'ON', +9452=>'ON', +9453=>'ON', +9454=>'ON', +9455=>'ON', +9456=>'ON', +9457=>'ON', +9458=>'ON', +9459=>'ON', +9460=>'ON', +9461=>'ON', +9462=>'ON', +9463=>'ON', +9464=>'ON', +9465=>'ON', +9466=>'ON', +9467=>'ON', +9468=>'ON', +9469=>'ON', +9470=>'ON', +9471=>'ON', +9472=>'ON', +9473=>'ON', +9474=>'ON', +9475=>'ON', +9476=>'ON', +9477=>'ON', +9478=>'ON', +9479=>'ON', +9480=>'ON', +9481=>'ON', +9482=>'ON', +9483=>'ON', +9484=>'ON', +9485=>'ON', +9486=>'ON', +9487=>'ON', +9488=>'ON', +9489=>'ON', +9490=>'ON', +9491=>'ON', +9492=>'ON', +9493=>'ON', +9494=>'ON', +9495=>'ON', +9496=>'ON', +9497=>'ON', +9498=>'ON', +9499=>'ON', +9500=>'ON', +9501=>'ON', +9502=>'ON', +9503=>'ON', +9504=>'ON', +9505=>'ON', +9506=>'ON', +9507=>'ON', +9508=>'ON', +9509=>'ON', +9510=>'ON', +9511=>'ON', +9512=>'ON', +9513=>'ON', +9514=>'ON', +9515=>'ON', +9516=>'ON', +9517=>'ON', +9518=>'ON', +9519=>'ON', +9520=>'ON', +9521=>'ON', +9522=>'ON', +9523=>'ON', +9524=>'ON', +9525=>'ON', +9526=>'ON', +9527=>'ON', +9528=>'ON', +9529=>'ON', +9530=>'ON', +9531=>'ON', +9532=>'ON', +9533=>'ON', +9534=>'ON', +9535=>'ON', +9536=>'ON', +9537=>'ON', +9538=>'ON', +9539=>'ON', +9540=>'ON', +9541=>'ON', +9542=>'ON', +9543=>'ON', +9544=>'ON', +9545=>'ON', +9546=>'ON', +9547=>'ON', +9548=>'ON', +9549=>'ON', +9550=>'ON', +9551=>'ON', +9552=>'ON', +9553=>'ON', +9554=>'ON', +9555=>'ON', +9556=>'ON', +9557=>'ON', +9558=>'ON', +9559=>'ON', +9560=>'ON', +9561=>'ON', +9562=>'ON', +9563=>'ON', +9564=>'ON', +9565=>'ON', +9566=>'ON', +9567=>'ON', +9568=>'ON', +9569=>'ON', +9570=>'ON', +9571=>'ON', +9572=>'ON', +9573=>'ON', +9574=>'ON', +9575=>'ON', +9576=>'ON', +9577=>'ON', +9578=>'ON', +9579=>'ON', +9580=>'ON', +9581=>'ON', +9582=>'ON', +9583=>'ON', +9584=>'ON', +9585=>'ON', +9586=>'ON', +9587=>'ON', +9588=>'ON', +9589=>'ON', +9590=>'ON', +9591=>'ON', +9592=>'ON', +9593=>'ON', +9594=>'ON', +9595=>'ON', +9596=>'ON', +9597=>'ON', +9598=>'ON', +9599=>'ON', +9600=>'ON', +9601=>'ON', +9602=>'ON', +9603=>'ON', +9604=>'ON', +9605=>'ON', +9606=>'ON', +9607=>'ON', +9608=>'ON', +9609=>'ON', +9610=>'ON', +9611=>'ON', +9612=>'ON', +9613=>'ON', +9614=>'ON', +9615=>'ON', +9616=>'ON', +9617=>'ON', +9618=>'ON', +9619=>'ON', +9620=>'ON', +9621=>'ON', +9622=>'ON', +9623=>'ON', +9624=>'ON', +9625=>'ON', +9626=>'ON', +9627=>'ON', +9628=>'ON', +9629=>'ON', +9630=>'ON', +9631=>'ON', +9632=>'ON', +9633=>'ON', +9634=>'ON', +9635=>'ON', +9636=>'ON', +9637=>'ON', +9638=>'ON', +9639=>'ON', +9640=>'ON', +9641=>'ON', +9642=>'ON', +9643=>'ON', +9644=>'ON', +9645=>'ON', +9646=>'ON', +9647=>'ON', +9648=>'ON', +9649=>'ON', +9650=>'ON', +9651=>'ON', +9652=>'ON', +9653=>'ON', +9654=>'ON', +9655=>'ON', +9656=>'ON', +9657=>'ON', +9658=>'ON', +9659=>'ON', +9660=>'ON', +9661=>'ON', +9662=>'ON', +9663=>'ON', +9664=>'ON', +9665=>'ON', +9666=>'ON', +9667=>'ON', +9668=>'ON', +9669=>'ON', +9670=>'ON', +9671=>'ON', +9672=>'ON', +9673=>'ON', +9674=>'ON', +9675=>'ON', +9676=>'ON', +9677=>'ON', +9678=>'ON', +9679=>'ON', +9680=>'ON', +9681=>'ON', +9682=>'ON', +9683=>'ON', +9684=>'ON', +9685=>'ON', +9686=>'ON', +9687=>'ON', +9688=>'ON', +9689=>'ON', +9690=>'ON', +9691=>'ON', +9692=>'ON', +9693=>'ON', +9694=>'ON', +9695=>'ON', +9696=>'ON', +9697=>'ON', +9698=>'ON', +9699=>'ON', +9700=>'ON', +9701=>'ON', +9702=>'ON', +9703=>'ON', +9704=>'ON', +9705=>'ON', +9706=>'ON', +9707=>'ON', +9708=>'ON', +9709=>'ON', +9710=>'ON', +9711=>'ON', +9712=>'ON', +9713=>'ON', +9714=>'ON', +9715=>'ON', +9716=>'ON', +9717=>'ON', +9718=>'ON', +9719=>'ON', +9720=>'ON', +9721=>'ON', +9722=>'ON', +9723=>'ON', +9724=>'ON', +9725=>'ON', +9726=>'ON', +9727=>'ON', +9728=>'ON', +9729=>'ON', +9730=>'ON', +9731=>'ON', +9732=>'ON', +9733=>'ON', +9734=>'ON', +9735=>'ON', +9736=>'ON', +9737=>'ON', +9738=>'ON', +9739=>'ON', +9740=>'ON', +9741=>'ON', +9742=>'ON', +9743=>'ON', +9744=>'ON', +9745=>'ON', +9746=>'ON', +9747=>'ON', +9748=>'ON', +9749=>'ON', +9750=>'ON', +9751=>'ON', +9752=>'ON', +9753=>'ON', +9754=>'ON', +9755=>'ON', +9756=>'ON', +9757=>'ON', +9758=>'ON', +9759=>'ON', +9760=>'ON', +9761=>'ON', +9762=>'ON', +9763=>'ON', +9764=>'ON', +9765=>'ON', +9766=>'ON', +9767=>'ON', +9768=>'ON', +9769=>'ON', +9770=>'ON', +9771=>'ON', +9772=>'ON', +9773=>'ON', +9774=>'ON', +9775=>'ON', +9776=>'ON', +9777=>'ON', +9778=>'ON', +9779=>'ON', +9780=>'ON', +9781=>'ON', +9782=>'ON', +9783=>'ON', +9784=>'ON', +9785=>'ON', +9786=>'ON', +9787=>'ON', +9788=>'ON', +9789=>'ON', +9790=>'ON', +9791=>'ON', +9792=>'ON', +9793=>'ON', +9794=>'ON', +9795=>'ON', +9796=>'ON', +9797=>'ON', +9798=>'ON', +9799=>'ON', +9800=>'ON', +9801=>'ON', +9802=>'ON', +9803=>'ON', +9804=>'ON', +9805=>'ON', +9806=>'ON', +9807=>'ON', +9808=>'ON', +9809=>'ON', +9810=>'ON', +9811=>'ON', +9812=>'ON', +9813=>'ON', +9814=>'ON', +9815=>'ON', +9816=>'ON', +9817=>'ON', +9818=>'ON', +9819=>'ON', +9820=>'ON', +9821=>'ON', +9822=>'ON', +9823=>'ON', +9824=>'ON', +9825=>'ON', +9826=>'ON', +9827=>'ON', +9828=>'ON', +9829=>'ON', +9830=>'ON', +9831=>'ON', +9832=>'ON', +9833=>'ON', +9834=>'ON', +9835=>'ON', +9836=>'ON', +9837=>'ON', +9838=>'ON', +9839=>'ON', +9840=>'ON', +9841=>'ON', +9842=>'ON', +9843=>'ON', +9844=>'ON', +9845=>'ON', +9846=>'ON', +9847=>'ON', +9848=>'ON', +9849=>'ON', +9850=>'ON', +9851=>'ON', +9852=>'ON', +9853=>'ON', +9854=>'ON', +9855=>'ON', +9856=>'ON', +9857=>'ON', +9858=>'ON', +9859=>'ON', +9860=>'ON', +9861=>'ON', +9862=>'ON', +9863=>'ON', +9864=>'ON', +9865=>'ON', +9866=>'ON', +9867=>'ON', +9868=>'ON', +9869=>'ON', +9870=>'ON', +9871=>'ON', +9872=>'ON', +9873=>'ON', +9874=>'ON', +9875=>'ON', +9876=>'ON', +9877=>'ON', +9878=>'ON', +9879=>'ON', +9880=>'ON', +9881=>'ON', +9882=>'ON', +9883=>'ON', +9884=>'ON', +9888=>'ON', +9889=>'ON', +9890=>'ON', +9891=>'ON', +9892=>'ON', +9893=>'ON', +9894=>'ON', +9895=>'ON', +9896=>'ON', +9897=>'ON', +9898=>'ON', +9899=>'ON', +9900=>'L', +9901=>'ON', +9902=>'ON', +9903=>'ON', +9904=>'ON', +9905=>'ON', +9906=>'ON', +9985=>'ON', +9986=>'ON', +9987=>'ON', +9988=>'ON', +9990=>'ON', +9991=>'ON', +9992=>'ON', +9993=>'ON', +9996=>'ON', +9997=>'ON', +9998=>'ON', +9999=>'ON', +10000=>'ON', +10001=>'ON', +10002=>'ON', +10003=>'ON', +10004=>'ON', +10005=>'ON', +10006=>'ON', +10007=>'ON', +10008=>'ON', +10009=>'ON', +10010=>'ON', +10011=>'ON', +10012=>'ON', +10013=>'ON', +10014=>'ON', +10015=>'ON', +10016=>'ON', +10017=>'ON', +10018=>'ON', +10019=>'ON', +10020=>'ON', +10021=>'ON', +10022=>'ON', +10023=>'ON', +10025=>'ON', +10026=>'ON', +10027=>'ON', +10028=>'ON', +10029=>'ON', +10030=>'ON', +10031=>'ON', +10032=>'ON', +10033=>'ON', +10034=>'ON', +10035=>'ON', +10036=>'ON', +10037=>'ON', +10038=>'ON', +10039=>'ON', +10040=>'ON', +10041=>'ON', +10042=>'ON', +10043=>'ON', +10044=>'ON', +10045=>'ON', +10046=>'ON', +10047=>'ON', +10048=>'ON', +10049=>'ON', +10050=>'ON', +10051=>'ON', +10052=>'ON', +10053=>'ON', +10054=>'ON', +10055=>'ON', +10056=>'ON', +10057=>'ON', +10058=>'ON', +10059=>'ON', +10061=>'ON', +10063=>'ON', +10064=>'ON', +10065=>'ON', +10066=>'ON', +10070=>'ON', +10072=>'ON', +10073=>'ON', +10074=>'ON', +10075=>'ON', +10076=>'ON', +10077=>'ON', +10078=>'ON', +10081=>'ON', +10082=>'ON', +10083=>'ON', +10084=>'ON', +10085=>'ON', +10086=>'ON', +10087=>'ON', +10088=>'ON', +10089=>'ON', +10090=>'ON', +10091=>'ON', +10092=>'ON', +10093=>'ON', +10094=>'ON', +10095=>'ON', +10096=>'ON', +10097=>'ON', +10098=>'ON', +10099=>'ON', +10100=>'ON', +10101=>'ON', +10102=>'ON', +10103=>'ON', +10104=>'ON', +10105=>'ON', +10106=>'ON', +10107=>'ON', +10108=>'ON', +10109=>'ON', +10110=>'ON', +10111=>'ON', +10112=>'ON', +10113=>'ON', +10114=>'ON', +10115=>'ON', +10116=>'ON', +10117=>'ON', +10118=>'ON', +10119=>'ON', +10120=>'ON', +10121=>'ON', +10122=>'ON', +10123=>'ON', +10124=>'ON', +10125=>'ON', +10126=>'ON', +10127=>'ON', +10128=>'ON', +10129=>'ON', +10130=>'ON', +10131=>'ON', +10132=>'ON', +10136=>'ON', +10137=>'ON', +10138=>'ON', +10139=>'ON', +10140=>'ON', +10141=>'ON', +10142=>'ON', +10143=>'ON', +10144=>'ON', +10145=>'ON', +10146=>'ON', +10147=>'ON', +10148=>'ON', +10149=>'ON', +10150=>'ON', +10151=>'ON', +10152=>'ON', +10153=>'ON', +10154=>'ON', +10155=>'ON', +10156=>'ON', +10157=>'ON', +10158=>'ON', +10159=>'ON', +10161=>'ON', +10162=>'ON', +10163=>'ON', +10164=>'ON', +10165=>'ON', +10166=>'ON', +10167=>'ON', +10168=>'ON', +10169=>'ON', +10170=>'ON', +10171=>'ON', +10172=>'ON', +10173=>'ON', +10174=>'ON', +10176=>'ON', +10177=>'ON', +10178=>'ON', +10179=>'ON', +10180=>'ON', +10181=>'ON', +10182=>'ON', +10183=>'ON', +10184=>'ON', +10185=>'ON', +10186=>'ON', +10192=>'ON', +10193=>'ON', +10194=>'ON', +10195=>'ON', +10196=>'ON', +10197=>'ON', +10198=>'ON', +10199=>'ON', +10200=>'ON', +10201=>'ON', +10202=>'ON', +10203=>'ON', +10204=>'ON', +10205=>'ON', +10206=>'ON', +10207=>'ON', +10208=>'ON', +10209=>'ON', +10210=>'ON', +10211=>'ON', +10212=>'ON', +10213=>'ON', +10214=>'ON', +10215=>'ON', +10216=>'ON', +10217=>'ON', +10218=>'ON', +10219=>'ON', +10224=>'ON', +10225=>'ON', +10226=>'ON', +10227=>'ON', +10228=>'ON', +10229=>'ON', +10230=>'ON', +10231=>'ON', +10232=>'ON', +10233=>'ON', +10234=>'ON', +10235=>'ON', +10236=>'ON', +10237=>'ON', +10238=>'ON', +10239=>'ON', +10240=>'L', +10241=>'L', +10242=>'L', +10243=>'L', +10244=>'L', +10245=>'L', +10246=>'L', +10247=>'L', +10248=>'L', +10249=>'L', +10250=>'L', +10251=>'L', +10252=>'L', +10253=>'L', +10254=>'L', +10255=>'L', +10256=>'L', +10257=>'L', +10258=>'L', +10259=>'L', +10260=>'L', +10261=>'L', +10262=>'L', +10263=>'L', +10264=>'L', +10265=>'L', +10266=>'L', +10267=>'L', +10268=>'L', +10269=>'L', +10270=>'L', +10271=>'L', +10272=>'L', +10273=>'L', +10274=>'L', +10275=>'L', +10276=>'L', +10277=>'L', +10278=>'L', +10279=>'L', +10280=>'L', +10281=>'L', +10282=>'L', +10283=>'L', +10284=>'L', +10285=>'L', +10286=>'L', +10287=>'L', +10288=>'L', +10289=>'L', +10290=>'L', +10291=>'L', +10292=>'L', +10293=>'L', +10294=>'L', +10295=>'L', +10296=>'L', +10297=>'L', +10298=>'L', +10299=>'L', +10300=>'L', +10301=>'L', +10302=>'L', +10303=>'L', +10304=>'L', +10305=>'L', +10306=>'L', +10307=>'L', +10308=>'L', +10309=>'L', +10310=>'L', +10311=>'L', +10312=>'L', +10313=>'L', +10314=>'L', +10315=>'L', +10316=>'L', +10317=>'L', +10318=>'L', +10319=>'L', +10320=>'L', +10321=>'L', +10322=>'L', +10323=>'L', +10324=>'L', +10325=>'L', +10326=>'L', +10327=>'L', +10328=>'L', +10329=>'L', +10330=>'L', +10331=>'L', +10332=>'L', +10333=>'L', +10334=>'L', +10335=>'L', +10336=>'L', +10337=>'L', +10338=>'L', +10339=>'L', +10340=>'L', +10341=>'L', +10342=>'L', +10343=>'L', +10344=>'L', +10345=>'L', +10346=>'L', +10347=>'L', +10348=>'L', +10349=>'L', +10350=>'L', +10351=>'L', +10352=>'L', +10353=>'L', +10354=>'L', +10355=>'L', +10356=>'L', +10357=>'L', +10358=>'L', +10359=>'L', +10360=>'L', +10361=>'L', +10362=>'L', +10363=>'L', +10364=>'L', +10365=>'L', +10366=>'L', +10367=>'L', +10368=>'L', +10369=>'L', +10370=>'L', +10371=>'L', +10372=>'L', +10373=>'L', +10374=>'L', +10375=>'L', +10376=>'L', +10377=>'L', +10378=>'L', +10379=>'L', +10380=>'L', +10381=>'L', +10382=>'L', +10383=>'L', +10384=>'L', +10385=>'L', +10386=>'L', +10387=>'L', +10388=>'L', +10389=>'L', +10390=>'L', +10391=>'L', +10392=>'L', +10393=>'L', +10394=>'L', +10395=>'L', +10396=>'L', +10397=>'L', +10398=>'L', +10399=>'L', +10400=>'L', +10401=>'L', +10402=>'L', +10403=>'L', +10404=>'L', +10405=>'L', +10406=>'L', +10407=>'L', +10408=>'L', +10409=>'L', +10410=>'L', +10411=>'L', +10412=>'L', +10413=>'L', +10414=>'L', +10415=>'L', +10416=>'L', +10417=>'L', +10418=>'L', +10419=>'L', +10420=>'L', +10421=>'L', +10422=>'L', +10423=>'L', +10424=>'L', +10425=>'L', +10426=>'L', +10427=>'L', +10428=>'L', +10429=>'L', +10430=>'L', +10431=>'L', +10432=>'L', +10433=>'L', +10434=>'L', +10435=>'L', +10436=>'L', +10437=>'L', +10438=>'L', +10439=>'L', +10440=>'L', +10441=>'L', +10442=>'L', +10443=>'L', +10444=>'L', +10445=>'L', +10446=>'L', +10447=>'L', +10448=>'L', +10449=>'L', +10450=>'L', +10451=>'L', +10452=>'L', +10453=>'L', +10454=>'L', +10455=>'L', +10456=>'L', +10457=>'L', +10458=>'L', +10459=>'L', +10460=>'L', +10461=>'L', +10462=>'L', +10463=>'L', +10464=>'L', +10465=>'L', +10466=>'L', +10467=>'L', +10468=>'L', +10469=>'L', +10470=>'L', +10471=>'L', +10472=>'L', +10473=>'L', +10474=>'L', +10475=>'L', +10476=>'L', +10477=>'L', +10478=>'L', +10479=>'L', +10480=>'L', +10481=>'L', +10482=>'L', +10483=>'L', +10484=>'L', +10485=>'L', +10486=>'L', +10487=>'L', +10488=>'L', +10489=>'L', +10490=>'L', +10491=>'L', +10492=>'L', +10493=>'L', +10494=>'L', +10495=>'L', +10496=>'ON', +10497=>'ON', +10498=>'ON', +10499=>'ON', +10500=>'ON', +10501=>'ON', +10502=>'ON', +10503=>'ON', +10504=>'ON', +10505=>'ON', +10506=>'ON', +10507=>'ON', +10508=>'ON', +10509=>'ON', +10510=>'ON', +10511=>'ON', +10512=>'ON', +10513=>'ON', +10514=>'ON', +10515=>'ON', +10516=>'ON', +10517=>'ON', +10518=>'ON', +10519=>'ON', +10520=>'ON', +10521=>'ON', +10522=>'ON', +10523=>'ON', +10524=>'ON', +10525=>'ON', +10526=>'ON', +10527=>'ON', +10528=>'ON', +10529=>'ON', +10530=>'ON', +10531=>'ON', +10532=>'ON', +10533=>'ON', +10534=>'ON', +10535=>'ON', +10536=>'ON', +10537=>'ON', +10538=>'ON', +10539=>'ON', +10540=>'ON', +10541=>'ON', +10542=>'ON', +10543=>'ON', +10544=>'ON', +10545=>'ON', +10546=>'ON', +10547=>'ON', +10548=>'ON', +10549=>'ON', +10550=>'ON', +10551=>'ON', +10552=>'ON', +10553=>'ON', +10554=>'ON', +10555=>'ON', +10556=>'ON', +10557=>'ON', +10558=>'ON', +10559=>'ON', +10560=>'ON', +10561=>'ON', +10562=>'ON', +10563=>'ON', +10564=>'ON', +10565=>'ON', +10566=>'ON', +10567=>'ON', +10568=>'ON', +10569=>'ON', +10570=>'ON', +10571=>'ON', +10572=>'ON', +10573=>'ON', +10574=>'ON', +10575=>'ON', +10576=>'ON', +10577=>'ON', +10578=>'ON', +10579=>'ON', +10580=>'ON', +10581=>'ON', +10582=>'ON', +10583=>'ON', +10584=>'ON', +10585=>'ON', +10586=>'ON', +10587=>'ON', +10588=>'ON', +10589=>'ON', +10590=>'ON', +10591=>'ON', +10592=>'ON', +10593=>'ON', +10594=>'ON', +10595=>'ON', +10596=>'ON', +10597=>'ON', +10598=>'ON', +10599=>'ON', +10600=>'ON', +10601=>'ON', +10602=>'ON', +10603=>'ON', +10604=>'ON', +10605=>'ON', +10606=>'ON', +10607=>'ON', +10608=>'ON', +10609=>'ON', +10610=>'ON', +10611=>'ON', +10612=>'ON', +10613=>'ON', +10614=>'ON', +10615=>'ON', +10616=>'ON', +10617=>'ON', +10618=>'ON', +10619=>'ON', +10620=>'ON', +10621=>'ON', +10622=>'ON', +10623=>'ON', +10624=>'ON', +10625=>'ON', +10626=>'ON', +10627=>'ON', +10628=>'ON', +10629=>'ON', +10630=>'ON', +10631=>'ON', +10632=>'ON', +10633=>'ON', +10634=>'ON', +10635=>'ON', +10636=>'ON', +10637=>'ON', +10638=>'ON', +10639=>'ON', +10640=>'ON', +10641=>'ON', +10642=>'ON', +10643=>'ON', +10644=>'ON', +10645=>'ON', +10646=>'ON', +10647=>'ON', +10648=>'ON', +10649=>'ON', +10650=>'ON', +10651=>'ON', +10652=>'ON', +10653=>'ON', +10654=>'ON', +10655=>'ON', +10656=>'ON', +10657=>'ON', +10658=>'ON', +10659=>'ON', +10660=>'ON', +10661=>'ON', +10662=>'ON', +10663=>'ON', +10664=>'ON', +10665=>'ON', +10666=>'ON', +10667=>'ON', +10668=>'ON', +10669=>'ON', +10670=>'ON', +10671=>'ON', +10672=>'ON', +10673=>'ON', +10674=>'ON', +10675=>'ON', +10676=>'ON', +10677=>'ON', +10678=>'ON', +10679=>'ON', +10680=>'ON', +10681=>'ON', +10682=>'ON', +10683=>'ON', +10684=>'ON', +10685=>'ON', +10686=>'ON', +10687=>'ON', +10688=>'ON', +10689=>'ON', +10690=>'ON', +10691=>'ON', +10692=>'ON', +10693=>'ON', +10694=>'ON', +10695=>'ON', +10696=>'ON', +10697=>'ON', +10698=>'ON', +10699=>'ON', +10700=>'ON', +10701=>'ON', +10702=>'ON', +10703=>'ON', +10704=>'ON', +10705=>'ON', +10706=>'ON', +10707=>'ON', +10708=>'ON', +10709=>'ON', +10710=>'ON', +10711=>'ON', +10712=>'ON', +10713=>'ON', +10714=>'ON', +10715=>'ON', +10716=>'ON', +10717=>'ON', +10718=>'ON', +10719=>'ON', +10720=>'ON', +10721=>'ON', +10722=>'ON', +10723=>'ON', +10724=>'ON', +10725=>'ON', +10726=>'ON', +10727=>'ON', +10728=>'ON', +10729=>'ON', +10730=>'ON', +10731=>'ON', +10732=>'ON', +10733=>'ON', +10734=>'ON', +10735=>'ON', +10736=>'ON', +10737=>'ON', +10738=>'ON', +10739=>'ON', +10740=>'ON', +10741=>'ON', +10742=>'ON', +10743=>'ON', +10744=>'ON', +10745=>'ON', +10746=>'ON', +10747=>'ON', +10748=>'ON', +10749=>'ON', +10750=>'ON', +10751=>'ON', +10752=>'ON', +10753=>'ON', +10754=>'ON', +10755=>'ON', +10756=>'ON', +10757=>'ON', +10758=>'ON', +10759=>'ON', +10760=>'ON', +10761=>'ON', +10762=>'ON', +10763=>'ON', +10764=>'ON', +10765=>'ON', +10766=>'ON', +10767=>'ON', +10768=>'ON', +10769=>'ON', +10770=>'ON', +10771=>'ON', +10772=>'ON', +10773=>'ON', +10774=>'ON', +10775=>'ON', +10776=>'ON', +10777=>'ON', +10778=>'ON', +10779=>'ON', +10780=>'ON', +10781=>'ON', +10782=>'ON', +10783=>'ON', +10784=>'ON', +10785=>'ON', +10786=>'ON', +10787=>'ON', +10788=>'ON', +10789=>'ON', +10790=>'ON', +10791=>'ON', +10792=>'ON', +10793=>'ON', +10794=>'ON', +10795=>'ON', +10796=>'ON', +10797=>'ON', +10798=>'ON', +10799=>'ON', +10800=>'ON', +10801=>'ON', +10802=>'ON', +10803=>'ON', +10804=>'ON', +10805=>'ON', +10806=>'ON', +10807=>'ON', +10808=>'ON', +10809=>'ON', +10810=>'ON', +10811=>'ON', +10812=>'ON', +10813=>'ON', +10814=>'ON', +10815=>'ON', +10816=>'ON', +10817=>'ON', +10818=>'ON', +10819=>'ON', +10820=>'ON', +10821=>'ON', +10822=>'ON', +10823=>'ON', +10824=>'ON', +10825=>'ON', +10826=>'ON', +10827=>'ON', +10828=>'ON', +10829=>'ON', +10830=>'ON', +10831=>'ON', +10832=>'ON', +10833=>'ON', +10834=>'ON', +10835=>'ON', +10836=>'ON', +10837=>'ON', +10838=>'ON', +10839=>'ON', +10840=>'ON', +10841=>'ON', +10842=>'ON', +10843=>'ON', +10844=>'ON', +10845=>'ON', +10846=>'ON', +10847=>'ON', +10848=>'ON', +10849=>'ON', +10850=>'ON', +10851=>'ON', +10852=>'ON', +10853=>'ON', +10854=>'ON', +10855=>'ON', +10856=>'ON', +10857=>'ON', +10858=>'ON', +10859=>'ON', +10860=>'ON', +10861=>'ON', +10862=>'ON', +10863=>'ON', +10864=>'ON', +10865=>'ON', +10866=>'ON', +10867=>'ON', +10868=>'ON', +10869=>'ON', +10870=>'ON', +10871=>'ON', +10872=>'ON', +10873=>'ON', +10874=>'ON', +10875=>'ON', +10876=>'ON', +10877=>'ON', +10878=>'ON', +10879=>'ON', +10880=>'ON', +10881=>'ON', +10882=>'ON', +10883=>'ON', +10884=>'ON', +10885=>'ON', +10886=>'ON', +10887=>'ON', +10888=>'ON', +10889=>'ON', +10890=>'ON', +10891=>'ON', +10892=>'ON', +10893=>'ON', +10894=>'ON', +10895=>'ON', +10896=>'ON', +10897=>'ON', +10898=>'ON', +10899=>'ON', +10900=>'ON', +10901=>'ON', +10902=>'ON', +10903=>'ON', +10904=>'ON', +10905=>'ON', +10906=>'ON', +10907=>'ON', +10908=>'ON', +10909=>'ON', +10910=>'ON', +10911=>'ON', +10912=>'ON', +10913=>'ON', +10914=>'ON', +10915=>'ON', +10916=>'ON', +10917=>'ON', +10918=>'ON', +10919=>'ON', +10920=>'ON', +10921=>'ON', +10922=>'ON', +10923=>'ON', +10924=>'ON', +10925=>'ON', +10926=>'ON', +10927=>'ON', +10928=>'ON', +10929=>'ON', +10930=>'ON', +10931=>'ON', +10932=>'ON', +10933=>'ON', +10934=>'ON', +10935=>'ON', +10936=>'ON', +10937=>'ON', +10938=>'ON', +10939=>'ON', +10940=>'ON', +10941=>'ON', +10942=>'ON', +10943=>'ON', +10944=>'ON', +10945=>'ON', +10946=>'ON', +10947=>'ON', +10948=>'ON', +10949=>'ON', +10950=>'ON', +10951=>'ON', +10952=>'ON', +10953=>'ON', +10954=>'ON', +10955=>'ON', +10956=>'ON', +10957=>'ON', +10958=>'ON', +10959=>'ON', +10960=>'ON', +10961=>'ON', +10962=>'ON', +10963=>'ON', +10964=>'ON', +10965=>'ON', +10966=>'ON', +10967=>'ON', +10968=>'ON', +10969=>'ON', +10970=>'ON', +10971=>'ON', +10972=>'ON', +10973=>'ON', +10974=>'ON', +10975=>'ON', +10976=>'ON', +10977=>'ON', +10978=>'ON', +10979=>'ON', +10980=>'ON', +10981=>'ON', +10982=>'ON', +10983=>'ON', +10984=>'ON', +10985=>'ON', +10986=>'ON', +10987=>'ON', +10988=>'ON', +10989=>'ON', +10990=>'ON', +10991=>'ON', +10992=>'ON', +10993=>'ON', +10994=>'ON', +10995=>'ON', +10996=>'ON', +10997=>'ON', +10998=>'ON', +10999=>'ON', +11000=>'ON', +11001=>'ON', +11002=>'ON', +11003=>'ON', +11004=>'ON', +11005=>'ON', +11006=>'ON', +11007=>'ON', +11008=>'ON', +11009=>'ON', +11010=>'ON', +11011=>'ON', +11012=>'ON', +11013=>'ON', +11014=>'ON', +11015=>'ON', +11016=>'ON', +11017=>'ON', +11018=>'ON', +11019=>'ON', +11020=>'ON', +11021=>'ON', +11022=>'ON', +11023=>'ON', +11024=>'ON', +11025=>'ON', +11026=>'ON', +11027=>'ON', +11028=>'ON', +11029=>'ON', +11030=>'ON', +11031=>'ON', +11032=>'ON', +11033=>'ON', +11034=>'ON', +11040=>'ON', +11041=>'ON', +11042=>'ON', +11043=>'ON', +11264=>'L', +11265=>'L', +11266=>'L', +11267=>'L', +11268=>'L', +11269=>'L', +11270=>'L', +11271=>'L', +11272=>'L', +11273=>'L', +11274=>'L', +11275=>'L', +11276=>'L', +11277=>'L', +11278=>'L', +11279=>'L', +11280=>'L', +11281=>'L', +11282=>'L', +11283=>'L', +11284=>'L', +11285=>'L', +11286=>'L', +11287=>'L', +11288=>'L', +11289=>'L', +11290=>'L', +11291=>'L', +11292=>'L', +11293=>'L', +11294=>'L', +11295=>'L', +11296=>'L', +11297=>'L', +11298=>'L', +11299=>'L', +11300=>'L', +11301=>'L', +11302=>'L', +11303=>'L', +11304=>'L', +11305=>'L', +11306=>'L', +11307=>'L', +11308=>'L', +11309=>'L', +11310=>'L', +11312=>'L', +11313=>'L', +11314=>'L', +11315=>'L', +11316=>'L', +11317=>'L', +11318=>'L', +11319=>'L', +11320=>'L', +11321=>'L', +11322=>'L', +11323=>'L', +11324=>'L', +11325=>'L', +11326=>'L', +11327=>'L', +11328=>'L', +11329=>'L', +11330=>'L', +11331=>'L', +11332=>'L', +11333=>'L', +11334=>'L', +11335=>'L', +11336=>'L', +11337=>'L', +11338=>'L', +11339=>'L', +11340=>'L', +11341=>'L', +11342=>'L', +11343=>'L', +11344=>'L', +11345=>'L', +11346=>'L', +11347=>'L', +11348=>'L', +11349=>'L', +11350=>'L', +11351=>'L', +11352=>'L', +11353=>'L', +11354=>'L', +11355=>'L', +11356=>'L', +11357=>'L', +11358=>'L', +11360=>'L', +11361=>'L', +11362=>'L', +11363=>'L', +11364=>'L', +11365=>'L', +11366=>'L', +11367=>'L', +11368=>'L', +11369=>'L', +11370=>'L', +11371=>'L', +11372=>'L', +11380=>'L', +11381=>'L', +11382=>'L', +11383=>'L', +11392=>'L', +11393=>'L', +11394=>'L', +11395=>'L', +11396=>'L', +11397=>'L', +11398=>'L', +11399=>'L', +11400=>'L', +11401=>'L', +11402=>'L', +11403=>'L', +11404=>'L', +11405=>'L', +11406=>'L', +11407=>'L', +11408=>'L', +11409=>'L', +11410=>'L', +11411=>'L', +11412=>'L', +11413=>'L', +11414=>'L', +11415=>'L', +11416=>'L', +11417=>'L', +11418=>'L', +11419=>'L', +11420=>'L', +11421=>'L', +11422=>'L', +11423=>'L', +11424=>'L', +11425=>'L', +11426=>'L', +11427=>'L', +11428=>'L', +11429=>'L', +11430=>'L', +11431=>'L', +11432=>'L', +11433=>'L', +11434=>'L', +11435=>'L', +11436=>'L', +11437=>'L', +11438=>'L', +11439=>'L', +11440=>'L', +11441=>'L', +11442=>'L', +11443=>'L', +11444=>'L', +11445=>'L', +11446=>'L', +11447=>'L', +11448=>'L', +11449=>'L', +11450=>'L', +11451=>'L', +11452=>'L', +11453=>'L', +11454=>'L', +11455=>'L', +11456=>'L', +11457=>'L', +11458=>'L', +11459=>'L', +11460=>'L', +11461=>'L', +11462=>'L', +11463=>'L', +11464=>'L', +11465=>'L', +11466=>'L', +11467=>'L', +11468=>'L', +11469=>'L', +11470=>'L', +11471=>'L', +11472=>'L', +11473=>'L', +11474=>'L', +11475=>'L', +11476=>'L', +11477=>'L', +11478=>'L', +11479=>'L', +11480=>'L', +11481=>'L', +11482=>'L', +11483=>'L', +11484=>'L', +11485=>'L', +11486=>'L', +11487=>'L', +11488=>'L', +11489=>'L', +11490=>'L', +11491=>'L', +11492=>'L', +11493=>'ON', +11494=>'ON', +11495=>'ON', +11496=>'ON', +11497=>'ON', +11498=>'ON', +11513=>'ON', +11514=>'ON', +11515=>'ON', +11516=>'ON', +11517=>'ON', +11518=>'ON', +11519=>'ON', +11520=>'L', +11521=>'L', +11522=>'L', +11523=>'L', +11524=>'L', +11525=>'L', +11526=>'L', +11527=>'L', +11528=>'L', +11529=>'L', +11530=>'L', +11531=>'L', +11532=>'L', +11533=>'L', +11534=>'L', +11535=>'L', +11536=>'L', +11537=>'L', +11538=>'L', +11539=>'L', +11540=>'L', +11541=>'L', +11542=>'L', +11543=>'L', +11544=>'L', +11545=>'L', +11546=>'L', +11547=>'L', +11548=>'L', +11549=>'L', +11550=>'L', +11551=>'L', +11552=>'L', +11553=>'L', +11554=>'L', +11555=>'L', +11556=>'L', +11557=>'L', +11568=>'L', +11569=>'L', +11570=>'L', +11571=>'L', +11572=>'L', +11573=>'L', +11574=>'L', +11575=>'L', +11576=>'L', +11577=>'L', +11578=>'L', +11579=>'L', +11580=>'L', +11581=>'L', +11582=>'L', +11583=>'L', +11584=>'L', +11585=>'L', +11586=>'L', +11587=>'L', +11588=>'L', +11589=>'L', +11590=>'L', +11591=>'L', +11592=>'L', +11593=>'L', +11594=>'L', +11595=>'L', +11596=>'L', +11597=>'L', +11598=>'L', +11599=>'L', +11600=>'L', +11601=>'L', +11602=>'L', +11603=>'L', +11604=>'L', +11605=>'L', +11606=>'L', +11607=>'L', +11608=>'L', +11609=>'L', +11610=>'L', +11611=>'L', +11612=>'L', +11613=>'L', +11614=>'L', +11615=>'L', +11616=>'L', +11617=>'L', +11618=>'L', +11619=>'L', +11620=>'L', +11621=>'L', +11631=>'L', +11648=>'L', +11649=>'L', +11650=>'L', +11651=>'L', +11652=>'L', +11653=>'L', +11654=>'L', +11655=>'L', +11656=>'L', +11657=>'L', +11658=>'L', +11659=>'L', +11660=>'L', +11661=>'L', +11662=>'L', +11663=>'L', +11664=>'L', +11665=>'L', +11666=>'L', +11667=>'L', +11668=>'L', +11669=>'L', +11670=>'L', +11680=>'L', +11681=>'L', +11682=>'L', +11683=>'L', +11684=>'L', +11685=>'L', +11686=>'L', +11688=>'L', +11689=>'L', +11690=>'L', +11691=>'L', +11692=>'L', +11693=>'L', +11694=>'L', +11696=>'L', +11697=>'L', +11698=>'L', +11699=>'L', +11700=>'L', +11701=>'L', +11702=>'L', +11704=>'L', +11705=>'L', +11706=>'L', +11707=>'L', +11708=>'L', +11709=>'L', +11710=>'L', +11712=>'L', +11713=>'L', +11714=>'L', +11715=>'L', +11716=>'L', +11717=>'L', +11718=>'L', +11720=>'L', +11721=>'L', +11722=>'L', +11723=>'L', +11724=>'L', +11725=>'L', +11726=>'L', +11728=>'L', +11729=>'L', +11730=>'L', +11731=>'L', +11732=>'L', +11733=>'L', +11734=>'L', +11736=>'L', +11737=>'L', +11738=>'L', +11739=>'L', +11740=>'L', +11741=>'L', +11742=>'L', +11776=>'ON', +11777=>'ON', +11778=>'ON', +11779=>'ON', +11780=>'ON', +11781=>'ON', +11782=>'ON', +11783=>'ON', +11784=>'ON', +11785=>'ON', +11786=>'ON', +11787=>'ON', +11788=>'ON', +11789=>'ON', +11790=>'ON', +11791=>'ON', +11792=>'ON', +11793=>'ON', +11794=>'ON', +11795=>'ON', +11796=>'ON', +11797=>'ON', +11798=>'ON', +11799=>'ON', +11804=>'ON', +11805=>'ON', +11904=>'ON', +11905=>'ON', +11906=>'ON', +11907=>'ON', +11908=>'ON', +11909=>'ON', +11910=>'ON', +11911=>'ON', +11912=>'ON', +11913=>'ON', +11914=>'ON', +11915=>'ON', +11916=>'ON', +11917=>'ON', +11918=>'ON', +11919=>'ON', +11920=>'ON', +11921=>'ON', +11922=>'ON', +11923=>'ON', +11924=>'ON', +11925=>'ON', +11926=>'ON', +11927=>'ON', +11928=>'ON', +11929=>'ON', +11931=>'ON', +11932=>'ON', +11933=>'ON', +11934=>'ON', +11935=>'ON', +11936=>'ON', +11937=>'ON', +11938=>'ON', +11939=>'ON', +11940=>'ON', +11941=>'ON', +11942=>'ON', +11943=>'ON', +11944=>'ON', +11945=>'ON', +11946=>'ON', +11947=>'ON', +11948=>'ON', +11949=>'ON', +11950=>'ON', +11951=>'ON', +11952=>'ON', +11953=>'ON', +11954=>'ON', +11955=>'ON', +11956=>'ON', +11957=>'ON', +11958=>'ON', +11959=>'ON', +11960=>'ON', +11961=>'ON', +11962=>'ON', +11963=>'ON', +11964=>'ON', +11965=>'ON', +11966=>'ON', +11967=>'ON', +11968=>'ON', +11969=>'ON', +11970=>'ON', +11971=>'ON', +11972=>'ON', +11973=>'ON', +11974=>'ON', +11975=>'ON', +11976=>'ON', +11977=>'ON', +11978=>'ON', +11979=>'ON', +11980=>'ON', +11981=>'ON', +11982=>'ON', +11983=>'ON', +11984=>'ON', +11985=>'ON', +11986=>'ON', +11987=>'ON', +11988=>'ON', +11989=>'ON', +11990=>'ON', +11991=>'ON', +11992=>'ON', +11993=>'ON', +11994=>'ON', +11995=>'ON', +11996=>'ON', +11997=>'ON', +11998=>'ON', +11999=>'ON', +12000=>'ON', +12001=>'ON', +12002=>'ON', +12003=>'ON', +12004=>'ON', +12005=>'ON', +12006=>'ON', +12007=>'ON', +12008=>'ON', +12009=>'ON', +12010=>'ON', +12011=>'ON', +12012=>'ON', +12013=>'ON', +12014=>'ON', +12015=>'ON', +12016=>'ON', +12017=>'ON', +12018=>'ON', +12019=>'ON', +12032=>'ON', +12033=>'ON', +12034=>'ON', +12035=>'ON', +12036=>'ON', +12037=>'ON', +12038=>'ON', +12039=>'ON', +12040=>'ON', +12041=>'ON', +12042=>'ON', +12043=>'ON', +12044=>'ON', +12045=>'ON', +12046=>'ON', +12047=>'ON', +12048=>'ON', +12049=>'ON', +12050=>'ON', +12051=>'ON', +12052=>'ON', +12053=>'ON', +12054=>'ON', +12055=>'ON', +12056=>'ON', +12057=>'ON', +12058=>'ON', +12059=>'ON', +12060=>'ON', +12061=>'ON', +12062=>'ON', +12063=>'ON', +12064=>'ON', +12065=>'ON', +12066=>'ON', +12067=>'ON', +12068=>'ON', +12069=>'ON', +12070=>'ON', +12071=>'ON', +12072=>'ON', +12073=>'ON', +12074=>'ON', +12075=>'ON', +12076=>'ON', +12077=>'ON', +12078=>'ON', +12079=>'ON', +12080=>'ON', +12081=>'ON', +12082=>'ON', +12083=>'ON', +12084=>'ON', +12085=>'ON', +12086=>'ON', +12087=>'ON', +12088=>'ON', +12089=>'ON', +12090=>'ON', +12091=>'ON', +12092=>'ON', +12093=>'ON', +12094=>'ON', +12095=>'ON', +12096=>'ON', +12097=>'ON', +12098=>'ON', +12099=>'ON', +12100=>'ON', +12101=>'ON', +12102=>'ON', +12103=>'ON', +12104=>'ON', +12105=>'ON', +12106=>'ON', +12107=>'ON', +12108=>'ON', +12109=>'ON', +12110=>'ON', +12111=>'ON', +12112=>'ON', +12113=>'ON', +12114=>'ON', +12115=>'ON', +12116=>'ON', +12117=>'ON', +12118=>'ON', +12119=>'ON', +12120=>'ON', +12121=>'ON', +12122=>'ON', +12123=>'ON', +12124=>'ON', +12125=>'ON', +12126=>'ON', +12127=>'ON', +12128=>'ON', +12129=>'ON', +12130=>'ON', +12131=>'ON', +12132=>'ON', +12133=>'ON', +12134=>'ON', +12135=>'ON', +12136=>'ON', +12137=>'ON', +12138=>'ON', +12139=>'ON', +12140=>'ON', +12141=>'ON', +12142=>'ON', +12143=>'ON', +12144=>'ON', +12145=>'ON', +12146=>'ON', +12147=>'ON', +12148=>'ON', +12149=>'ON', +12150=>'ON', +12151=>'ON', +12152=>'ON', +12153=>'ON', +12154=>'ON', +12155=>'ON', +12156=>'ON', +12157=>'ON', +12158=>'ON', +12159=>'ON', +12160=>'ON', +12161=>'ON', +12162=>'ON', +12163=>'ON', +12164=>'ON', +12165=>'ON', +12166=>'ON', +12167=>'ON', +12168=>'ON', +12169=>'ON', +12170=>'ON', +12171=>'ON', +12172=>'ON', +12173=>'ON', +12174=>'ON', +12175=>'ON', +12176=>'ON', +12177=>'ON', +12178=>'ON', +12179=>'ON', +12180=>'ON', +12181=>'ON', +12182=>'ON', +12183=>'ON', +12184=>'ON', +12185=>'ON', +12186=>'ON', +12187=>'ON', +12188=>'ON', +12189=>'ON', +12190=>'ON', +12191=>'ON', +12192=>'ON', +12193=>'ON', +12194=>'ON', +12195=>'ON', +12196=>'ON', +12197=>'ON', +12198=>'ON', +12199=>'ON', +12200=>'ON', +12201=>'ON', +12202=>'ON', +12203=>'ON', +12204=>'ON', +12205=>'ON', +12206=>'ON', +12207=>'ON', +12208=>'ON', +12209=>'ON', +12210=>'ON', +12211=>'ON', +12212=>'ON', +12213=>'ON', +12214=>'ON', +12215=>'ON', +12216=>'ON', +12217=>'ON', +12218=>'ON', +12219=>'ON', +12220=>'ON', +12221=>'ON', +12222=>'ON', +12223=>'ON', +12224=>'ON', +12225=>'ON', +12226=>'ON', +12227=>'ON', +12228=>'ON', +12229=>'ON', +12230=>'ON', +12231=>'ON', +12232=>'ON', +12233=>'ON', +12234=>'ON', +12235=>'ON', +12236=>'ON', +12237=>'ON', +12238=>'ON', +12239=>'ON', +12240=>'ON', +12241=>'ON', +12242=>'ON', +12243=>'ON', +12244=>'ON', +12245=>'ON', +12272=>'ON', +12273=>'ON', +12274=>'ON', +12275=>'ON', +12276=>'ON', +12277=>'ON', +12278=>'ON', +12279=>'ON', +12280=>'ON', +12281=>'ON', +12282=>'ON', +12283=>'ON', +12288=>'WS', +12289=>'ON', +12290=>'ON', +12291=>'ON', +12292=>'ON', +12293=>'L', +12294=>'L', +12295=>'L', +12296=>'ON', +12297=>'ON', +12298=>'ON', +12299=>'ON', +12300=>'ON', +12301=>'ON', +12302=>'ON', +12303=>'ON', +12304=>'ON', +12305=>'ON', +12306=>'ON', +12307=>'ON', +12308=>'ON', +12309=>'ON', +12310=>'ON', +12311=>'ON', +12312=>'ON', +12313=>'ON', +12314=>'ON', +12315=>'ON', +12316=>'ON', +12317=>'ON', +12318=>'ON', +12319=>'ON', +12320=>'ON', +12321=>'L', +12322=>'L', +12323=>'L', +12324=>'L', +12325=>'L', +12326=>'L', +12327=>'L', +12328=>'L', +12329=>'L', +12330=>'NSM', +12331=>'NSM', +12332=>'NSM', +12333=>'NSM', +12334=>'NSM', +12335=>'NSM', +12336=>'ON', +12337=>'L', +12338=>'L', +12339=>'L', +12340=>'L', +12341=>'L', +12342=>'ON', +12343=>'ON', +12344=>'L', +12345=>'L', +12346=>'L', +12347=>'L', +12348=>'L', +12349=>'ON', +12350=>'ON', +12351=>'ON', +12353=>'L', +12354=>'L', +12355=>'L', +12356=>'L', +12357=>'L', +12358=>'L', +12359=>'L', +12360=>'L', +12361=>'L', +12362=>'L', +12363=>'L', +12364=>'L', +12365=>'L', +12366=>'L', +12367=>'L', +12368=>'L', +12369=>'L', +12370=>'L', +12371=>'L', +12372=>'L', +12373=>'L', +12374=>'L', +12375=>'L', +12376=>'L', +12377=>'L', +12378=>'L', +12379=>'L', +12380=>'L', +12381=>'L', +12382=>'L', +12383=>'L', +12384=>'L', +12385=>'L', +12386=>'L', +12387=>'L', +12388=>'L', +12389=>'L', +12390=>'L', +12391=>'L', +12392=>'L', +12393=>'L', +12394=>'L', +12395=>'L', +12396=>'L', +12397=>'L', +12398=>'L', +12399=>'L', +12400=>'L', +12401=>'L', +12402=>'L', +12403=>'L', +12404=>'L', +12405=>'L', +12406=>'L', +12407=>'L', +12408=>'L', +12409=>'L', +12410=>'L', +12411=>'L', +12412=>'L', +12413=>'L', +12414=>'L', +12415=>'L', +12416=>'L', +12417=>'L', +12418=>'L', +12419=>'L', +12420=>'L', +12421=>'L', +12422=>'L', +12423=>'L', +12424=>'L', +12425=>'L', +12426=>'L', +12427=>'L', +12428=>'L', +12429=>'L', +12430=>'L', +12431=>'L', +12432=>'L', +12433=>'L', +12434=>'L', +12435=>'L', +12436=>'L', +12437=>'L', +12438=>'L', +12441=>'NSM', +12442=>'NSM', +12443=>'ON', +12444=>'ON', +12445=>'L', +12446=>'L', +12447=>'L', +12448=>'ON', +12449=>'L', +12450=>'L', +12451=>'L', +12452=>'L', +12453=>'L', +12454=>'L', +12455=>'L', +12456=>'L', +12457=>'L', +12458=>'L', +12459=>'L', +12460=>'L', +12461=>'L', +12462=>'L', +12463=>'L', +12464=>'L', +12465=>'L', +12466=>'L', +12467=>'L', +12468=>'L', +12469=>'L', +12470=>'L', +12471=>'L', +12472=>'L', +12473=>'L', +12474=>'L', +12475=>'L', +12476=>'L', +12477=>'L', +12478=>'L', +12479=>'L', +12480=>'L', +12481=>'L', +12482=>'L', +12483=>'L', +12484=>'L', +12485=>'L', +12486=>'L', +12487=>'L', +12488=>'L', +12489=>'L', +12490=>'L', +12491=>'L', +12492=>'L', +12493=>'L', +12494=>'L', +12495=>'L', +12496=>'L', +12497=>'L', +12498=>'L', +12499=>'L', +12500=>'L', +12501=>'L', +12502=>'L', +12503=>'L', +12504=>'L', +12505=>'L', +12506=>'L', +12507=>'L', +12508=>'L', +12509=>'L', +12510=>'L', +12511=>'L', +12512=>'L', +12513=>'L', +12514=>'L', +12515=>'L', +12516=>'L', +12517=>'L', +12518=>'L', +12519=>'L', +12520=>'L', +12521=>'L', +12522=>'L', +12523=>'L', +12524=>'L', +12525=>'L', +12526=>'L', +12527=>'L', +12528=>'L', +12529=>'L', +12530=>'L', +12531=>'L', +12532=>'L', +12533=>'L', +12534=>'L', +12535=>'L', +12536=>'L', +12537=>'L', +12538=>'L', +12539=>'ON', +12540=>'L', +12541=>'L', +12542=>'L', +12543=>'L', +12549=>'L', +12550=>'L', +12551=>'L', +12552=>'L', +12553=>'L', +12554=>'L', +12555=>'L', +12556=>'L', +12557=>'L', +12558=>'L', +12559=>'L', +12560=>'L', +12561=>'L', +12562=>'L', +12563=>'L', +12564=>'L', +12565=>'L', +12566=>'L', +12567=>'L', +12568=>'L', +12569=>'L', +12570=>'L', +12571=>'L', +12572=>'L', +12573=>'L', +12574=>'L', +12575=>'L', +12576=>'L', +12577=>'L', +12578=>'L', +12579=>'L', +12580=>'L', +12581=>'L', +12582=>'L', +12583=>'L', +12584=>'L', +12585=>'L', +12586=>'L', +12587=>'L', +12588=>'L', +12593=>'L', +12594=>'L', +12595=>'L', +12596=>'L', +12597=>'L', +12598=>'L', +12599=>'L', +12600=>'L', +12601=>'L', +12602=>'L', +12603=>'L', +12604=>'L', +12605=>'L', +12606=>'L', +12607=>'L', +12608=>'L', +12609=>'L', +12610=>'L', +12611=>'L', +12612=>'L', +12613=>'L', +12614=>'L', +12615=>'L', +12616=>'L', +12617=>'L', +12618=>'L', +12619=>'L', +12620=>'L', +12621=>'L', +12622=>'L', +12623=>'L', +12624=>'L', +12625=>'L', +12626=>'L', +12627=>'L', +12628=>'L', +12629=>'L', +12630=>'L', +12631=>'L', +12632=>'L', +12633=>'L', +12634=>'L', +12635=>'L', +12636=>'L', +12637=>'L', +12638=>'L', +12639=>'L', +12640=>'L', +12641=>'L', +12642=>'L', +12643=>'L', +12644=>'L', +12645=>'L', +12646=>'L', +12647=>'L', +12648=>'L', +12649=>'L', +12650=>'L', +12651=>'L', +12652=>'L', +12653=>'L', +12654=>'L', +12655=>'L', +12656=>'L', +12657=>'L', +12658=>'L', +12659=>'L', +12660=>'L', +12661=>'L', +12662=>'L', +12663=>'L', +12664=>'L', +12665=>'L', +12666=>'L', +12667=>'L', +12668=>'L', +12669=>'L', +12670=>'L', +12671=>'L', +12672=>'L', +12673=>'L', +12674=>'L', +12675=>'L', +12676=>'L', +12677=>'L', +12678=>'L', +12679=>'L', +12680=>'L', +12681=>'L', +12682=>'L', +12683=>'L', +12684=>'L', +12685=>'L', +12686=>'L', +12688=>'L', +12689=>'L', +12690=>'L', +12691=>'L', +12692=>'L', +12693=>'L', +12694=>'L', +12695=>'L', +12696=>'L', +12697=>'L', +12698=>'L', +12699=>'L', +12700=>'L', +12701=>'L', +12702=>'L', +12703=>'L', +12704=>'L', +12705=>'L', +12706=>'L', +12707=>'L', +12708=>'L', +12709=>'L', +12710=>'L', +12711=>'L', +12712=>'L', +12713=>'L', +12714=>'L', +12715=>'L', +12716=>'L', +12717=>'L', +12718=>'L', +12719=>'L', +12720=>'L', +12721=>'L', +12722=>'L', +12723=>'L', +12724=>'L', +12725=>'L', +12726=>'L', +12727=>'L', +12736=>'ON', +12737=>'ON', +12738=>'ON', +12739=>'ON', +12740=>'ON', +12741=>'ON', +12742=>'ON', +12743=>'ON', +12744=>'ON', +12745=>'ON', +12746=>'ON', +12747=>'ON', +12748=>'ON', +12749=>'ON', +12750=>'ON', +12751=>'ON', +12784=>'L', +12785=>'L', +12786=>'L', +12787=>'L', +12788=>'L', +12789=>'L', +12790=>'L', +12791=>'L', +12792=>'L', +12793=>'L', +12794=>'L', +12795=>'L', +12796=>'L', +12797=>'L', +12798=>'L', +12799=>'L', +12800=>'L', +12801=>'L', +12802=>'L', +12803=>'L', +12804=>'L', +12805=>'L', +12806=>'L', +12807=>'L', +12808=>'L', +12809=>'L', +12810=>'L', +12811=>'L', +12812=>'L', +12813=>'L', +12814=>'L', +12815=>'L', +12816=>'L', +12817=>'L', +12818=>'L', +12819=>'L', +12820=>'L', +12821=>'L', +12822=>'L', +12823=>'L', +12824=>'L', +12825=>'L', +12826=>'L', +12827=>'L', +12828=>'L', +12829=>'ON', +12830=>'ON', +12832=>'L', +12833=>'L', +12834=>'L', +12835=>'L', +12836=>'L', +12837=>'L', +12838=>'L', +12839=>'L', +12840=>'L', +12841=>'L', +12842=>'L', +12843=>'L', +12844=>'L', +12845=>'L', +12846=>'L', +12847=>'L', +12848=>'L', +12849=>'L', +12850=>'L', +12851=>'L', +12852=>'L', +12853=>'L', +12854=>'L', +12855=>'L', +12856=>'L', +12857=>'L', +12858=>'L', +12859=>'L', +12860=>'L', +12861=>'L', +12862=>'L', +12863=>'L', +12864=>'L', +12865=>'L', +12866=>'L', +12867=>'L', +12880=>'ON', +12881=>'ON', +12882=>'ON', +12883=>'ON', +12884=>'ON', +12885=>'ON', +12886=>'ON', +12887=>'ON', +12888=>'ON', +12889=>'ON', +12890=>'ON', +12891=>'ON', +12892=>'ON', +12893=>'ON', +12894=>'ON', +12895=>'ON', +12896=>'L', +12897=>'L', +12898=>'L', +12899=>'L', +12900=>'L', +12901=>'L', +12902=>'L', +12903=>'L', +12904=>'L', +12905=>'L', +12906=>'L', +12907=>'L', +12908=>'L', +12909=>'L', +12910=>'L', +12911=>'L', +12912=>'L', +12913=>'L', +12914=>'L', +12915=>'L', +12916=>'L', +12917=>'L', +12918=>'L', +12919=>'L', +12920=>'L', +12921=>'L', +12922=>'L', +12923=>'L', +12924=>'ON', +12925=>'ON', +12926=>'ON', +12927=>'L', +12928=>'L', +12929=>'L', +12930=>'L', +12931=>'L', +12932=>'L', +12933=>'L', +12934=>'L', +12935=>'L', +12936=>'L', +12937=>'L', +12938=>'L', +12939=>'L', +12940=>'L', +12941=>'L', +12942=>'L', +12943=>'L', +12944=>'L', +12945=>'L', +12946=>'L', +12947=>'L', +12948=>'L', +12949=>'L', +12950=>'L', +12951=>'L', +12952=>'L', +12953=>'L', +12954=>'L', +12955=>'L', +12956=>'L', +12957=>'L', +12958=>'L', +12959=>'L', +12960=>'L', +12961=>'L', +12962=>'L', +12963=>'L', +12964=>'L', +12965=>'L', +12966=>'L', +12967=>'L', +12968=>'L', +12969=>'L', +12970=>'L', +12971=>'L', +12972=>'L', +12973=>'L', +12974=>'L', +12975=>'L', +12976=>'L', +12977=>'ON', +12978=>'ON', +12979=>'ON', +12980=>'ON', +12981=>'ON', +12982=>'ON', +12983=>'ON', +12984=>'ON', +12985=>'ON', +12986=>'ON', +12987=>'ON', +12988=>'ON', +12989=>'ON', +12990=>'ON', +12991=>'ON', +12992=>'L', +12993=>'L', +12994=>'L', +12995=>'L', +12996=>'L', +12997=>'L', +12998=>'L', +12999=>'L', +13000=>'L', +13001=>'L', +13002=>'L', +13003=>'L', +13004=>'ON', +13005=>'ON', +13006=>'ON', +13007=>'ON', +13008=>'L', +13009=>'L', +13010=>'L', +13011=>'L', +13012=>'L', +13013=>'L', +13014=>'L', +13015=>'L', +13016=>'L', +13017=>'L', +13018=>'L', +13019=>'L', +13020=>'L', +13021=>'L', +13022=>'L', +13023=>'L', +13024=>'L', +13025=>'L', +13026=>'L', +13027=>'L', +13028=>'L', +13029=>'L', +13030=>'L', +13031=>'L', +13032=>'L', +13033=>'L', +13034=>'L', +13035=>'L', +13036=>'L', +13037=>'L', +13038=>'L', +13039=>'L', +13040=>'L', +13041=>'L', +13042=>'L', +13043=>'L', +13044=>'L', +13045=>'L', +13046=>'L', +13047=>'L', +13048=>'L', +13049=>'L', +13050=>'L', +13051=>'L', +13052=>'L', +13053=>'L', +13054=>'L', +13056=>'L', +13057=>'L', +13058=>'L', +13059=>'L', +13060=>'L', +13061=>'L', +13062=>'L', +13063=>'L', +13064=>'L', +13065=>'L', +13066=>'L', +13067=>'L', +13068=>'L', +13069=>'L', +13070=>'L', +13071=>'L', +13072=>'L', +13073=>'L', +13074=>'L', +13075=>'L', +13076=>'L', +13077=>'L', +13078=>'L', +13079=>'L', +13080=>'L', +13081=>'L', +13082=>'L', +13083=>'L', +13084=>'L', +13085=>'L', +13086=>'L', +13087=>'L', +13088=>'L', +13089=>'L', +13090=>'L', +13091=>'L', +13092=>'L', +13093=>'L', +13094=>'L', +13095=>'L', +13096=>'L', +13097=>'L', +13098=>'L', +13099=>'L', +13100=>'L', +13101=>'L', +13102=>'L', +13103=>'L', +13104=>'L', +13105=>'L', +13106=>'L', +13107=>'L', +13108=>'L', +13109=>'L', +13110=>'L', +13111=>'L', +13112=>'L', +13113=>'L', +13114=>'L', +13115=>'L', +13116=>'L', +13117=>'L', +13118=>'L', +13119=>'L', +13120=>'L', +13121=>'L', +13122=>'L', +13123=>'L', +13124=>'L', +13125=>'L', +13126=>'L', +13127=>'L', +13128=>'L', +13129=>'L', +13130=>'L', +13131=>'L', +13132=>'L', +13133=>'L', +13134=>'L', +13135=>'L', +13136=>'L', +13137=>'L', +13138=>'L', +13139=>'L', +13140=>'L', +13141=>'L', +13142=>'L', +13143=>'L', +13144=>'L', +13145=>'L', +13146=>'L', +13147=>'L', +13148=>'L', +13149=>'L', +13150=>'L', +13151=>'L', +13152=>'L', +13153=>'L', +13154=>'L', +13155=>'L', +13156=>'L', +13157=>'L', +13158=>'L', +13159=>'L', +13160=>'L', +13161=>'L', +13162=>'L', +13163=>'L', +13164=>'L', +13165=>'L', +13166=>'L', +13167=>'L', +13168=>'L', +13169=>'L', +13170=>'L', +13171=>'L', +13172=>'L', +13173=>'L', +13174=>'L', +13175=>'ON', +13176=>'ON', +13177=>'ON', +13178=>'ON', +13179=>'L', +13180=>'L', +13181=>'L', +13182=>'L', +13183=>'L', +13184=>'L', +13185=>'L', +13186=>'L', +13187=>'L', +13188=>'L', +13189=>'L', +13190=>'L', +13191=>'L', +13192=>'L', +13193=>'L', +13194=>'L', +13195=>'L', +13196=>'L', +13197=>'L', +13198=>'L', +13199=>'L', +13200=>'L', +13201=>'L', +13202=>'L', +13203=>'L', +13204=>'L', +13205=>'L', +13206=>'L', +13207=>'L', +13208=>'L', +13209=>'L', +13210=>'L', +13211=>'L', +13212=>'L', +13213=>'L', +13214=>'L', +13215=>'L', +13216=>'L', +13217=>'L', +13218=>'L', +13219=>'L', +13220=>'L', +13221=>'L', +13222=>'L', +13223=>'L', +13224=>'L', +13225=>'L', +13226=>'L', +13227=>'L', +13228=>'L', +13229=>'L', +13230=>'L', +13231=>'L', +13232=>'L', +13233=>'L', +13234=>'L', +13235=>'L', +13236=>'L', +13237=>'L', +13238=>'L', +13239=>'L', +13240=>'L', +13241=>'L', +13242=>'L', +13243=>'L', +13244=>'L', +13245=>'L', +13246=>'L', +13247=>'L', +13248=>'L', +13249=>'L', +13250=>'L', +13251=>'L', +13252=>'L', +13253=>'L', +13254=>'L', +13255=>'L', +13256=>'L', +13257=>'L', +13258=>'L', +13259=>'L', +13260=>'L', +13261=>'L', +13262=>'L', +13263=>'L', +13264=>'L', +13265=>'L', +13266=>'L', +13267=>'L', +13268=>'L', +13269=>'L', +13270=>'L', +13271=>'L', +13272=>'L', +13273=>'L', +13274=>'L', +13275=>'L', +13276=>'L', +13277=>'L', +13278=>'ON', +13279=>'ON', +13280=>'L', +13281=>'L', +13282=>'L', +13283=>'L', +13284=>'L', +13285=>'L', +13286=>'L', +13287=>'L', +13288=>'L', +13289=>'L', +13290=>'L', +13291=>'L', +13292=>'L', +13293=>'L', +13294=>'L', +13295=>'L', +13296=>'L', +13297=>'L', +13298=>'L', +13299=>'L', +13300=>'L', +13301=>'L', +13302=>'L', +13303=>'L', +13304=>'L', +13305=>'L', +13306=>'L', +13307=>'L', +13308=>'L', +13309=>'L', +13310=>'L', +13311=>'ON', +13312=>'L', +19893=>'L', +19904=>'ON', +19905=>'ON', +19906=>'ON', +19907=>'ON', +19908=>'ON', +19909=>'ON', +19910=>'ON', +19911=>'ON', +19912=>'ON', +19913=>'ON', +19914=>'ON', +19915=>'ON', +19916=>'ON', +19917=>'ON', +19918=>'ON', +19919=>'ON', +19920=>'ON', +19921=>'ON', +19922=>'ON', +19923=>'ON', +19924=>'ON', +19925=>'ON', +19926=>'ON', +19927=>'ON', +19928=>'ON', +19929=>'ON', +19930=>'ON', +19931=>'ON', +19932=>'ON', +19933=>'ON', +19934=>'ON', +19935=>'ON', +19936=>'ON', +19937=>'ON', +19938=>'ON', +19939=>'ON', +19940=>'ON', +19941=>'ON', +19942=>'ON', +19943=>'ON', +19944=>'ON', +19945=>'ON', +19946=>'ON', +19947=>'ON', +19948=>'ON', +19949=>'ON', +19950=>'ON', +19951=>'ON', +19952=>'ON', +19953=>'ON', +19954=>'ON', +19955=>'ON', +19956=>'ON', +19957=>'ON', +19958=>'ON', +19959=>'ON', +19960=>'ON', +19961=>'ON', +19962=>'ON', +19963=>'ON', +19964=>'ON', +19965=>'ON', +19966=>'ON', +19967=>'ON', +19968=>'L', +40891=>'L', +40960=>'L', +40961=>'L', +40962=>'L', +40963=>'L', +40964=>'L', +40965=>'L', +40966=>'L', +40967=>'L', +40968=>'L', +40969=>'L', +40970=>'L', +40971=>'L', +40972=>'L', +40973=>'L', +40974=>'L', +40975=>'L', +40976=>'L', +40977=>'L', +40978=>'L', +40979=>'L', +40980=>'L', +40981=>'L', +40982=>'L', +40983=>'L', +40984=>'L', +40985=>'L', +40986=>'L', +40987=>'L', +40988=>'L', +40989=>'L', +40990=>'L', +40991=>'L', +40992=>'L', +40993=>'L', +40994=>'L', +40995=>'L', +40996=>'L', +40997=>'L', +40998=>'L', +40999=>'L', +41000=>'L', +41001=>'L', +41002=>'L', +41003=>'L', +41004=>'L', +41005=>'L', +41006=>'L', +41007=>'L', +41008=>'L', +41009=>'L', +41010=>'L', +41011=>'L', +41012=>'L', +41013=>'L', +41014=>'L', +41015=>'L', +41016=>'L', +41017=>'L', +41018=>'L', +41019=>'L', +41020=>'L', +41021=>'L', +41022=>'L', +41023=>'L', +41024=>'L', +41025=>'L', +41026=>'L', +41027=>'L', +41028=>'L', +41029=>'L', +41030=>'L', +41031=>'L', +41032=>'L', +41033=>'L', +41034=>'L', +41035=>'L', +41036=>'L', +41037=>'L', +41038=>'L', +41039=>'L', +41040=>'L', +41041=>'L', +41042=>'L', +41043=>'L', +41044=>'L', +41045=>'L', +41046=>'L', +41047=>'L', +41048=>'L', +41049=>'L', +41050=>'L', +41051=>'L', +41052=>'L', +41053=>'L', +41054=>'L', +41055=>'L', +41056=>'L', +41057=>'L', +41058=>'L', +41059=>'L', +41060=>'L', +41061=>'L', +41062=>'L', +41063=>'L', +41064=>'L', +41065=>'L', +41066=>'L', +41067=>'L', +41068=>'L', +41069=>'L', +41070=>'L', +41071=>'L', +41072=>'L', +41073=>'L', +41074=>'L', +41075=>'L', +41076=>'L', +41077=>'L', +41078=>'L', +41079=>'L', +41080=>'L', +41081=>'L', +41082=>'L', +41083=>'L', +41084=>'L', +41085=>'L', +41086=>'L', +41087=>'L', +41088=>'L', +41089=>'L', +41090=>'L', +41091=>'L', +41092=>'L', +41093=>'L', +41094=>'L', +41095=>'L', +41096=>'L', +41097=>'L', +41098=>'L', +41099=>'L', +41100=>'L', +41101=>'L', +41102=>'L', +41103=>'L', +41104=>'L', +41105=>'L', +41106=>'L', +41107=>'L', +41108=>'L', +41109=>'L', +41110=>'L', +41111=>'L', +41112=>'L', +41113=>'L', +41114=>'L', +41115=>'L', +41116=>'L', +41117=>'L', +41118=>'L', +41119=>'L', +41120=>'L', +41121=>'L', +41122=>'L', +41123=>'L', +41124=>'L', +41125=>'L', +41126=>'L', +41127=>'L', +41128=>'L', +41129=>'L', +41130=>'L', +41131=>'L', +41132=>'L', +41133=>'L', +41134=>'L', +41135=>'L', +41136=>'L', +41137=>'L', +41138=>'L', +41139=>'L', +41140=>'L', +41141=>'L', +41142=>'L', +41143=>'L', +41144=>'L', +41145=>'L', +41146=>'L', +41147=>'L', +41148=>'L', +41149=>'L', +41150=>'L', +41151=>'L', +41152=>'L', +41153=>'L', +41154=>'L', +41155=>'L', +41156=>'L', +41157=>'L', +41158=>'L', +41159=>'L', +41160=>'L', +41161=>'L', +41162=>'L', +41163=>'L', +41164=>'L', +41165=>'L', +41166=>'L', +41167=>'L', +41168=>'L', +41169=>'L', +41170=>'L', +41171=>'L', +41172=>'L', +41173=>'L', +41174=>'L', +41175=>'L', +41176=>'L', +41177=>'L', +41178=>'L', +41179=>'L', +41180=>'L', +41181=>'L', +41182=>'L', +41183=>'L', +41184=>'L', +41185=>'L', +41186=>'L', +41187=>'L', +41188=>'L', +41189=>'L', +41190=>'L', +41191=>'L', +41192=>'L', +41193=>'L', +41194=>'L', +41195=>'L', +41196=>'L', +41197=>'L', +41198=>'L', +41199=>'L', +41200=>'L', +41201=>'L', +41202=>'L', +41203=>'L', +41204=>'L', +41205=>'L', +41206=>'L', +41207=>'L', +41208=>'L', +41209=>'L', +41210=>'L', +41211=>'L', +41212=>'L', +41213=>'L', +41214=>'L', +41215=>'L', +41216=>'L', +41217=>'L', +41218=>'L', +41219=>'L', +41220=>'L', +41221=>'L', +41222=>'L', +41223=>'L', +41224=>'L', +41225=>'L', +41226=>'L', +41227=>'L', +41228=>'L', +41229=>'L', +41230=>'L', +41231=>'L', +41232=>'L', +41233=>'L', +41234=>'L', +41235=>'L', +41236=>'L', +41237=>'L', +41238=>'L', +41239=>'L', +41240=>'L', +41241=>'L', +41242=>'L', +41243=>'L', +41244=>'L', +41245=>'L', +41246=>'L', +41247=>'L', +41248=>'L', +41249=>'L', +41250=>'L', +41251=>'L', +41252=>'L', +41253=>'L', +41254=>'L', +41255=>'L', +41256=>'L', +41257=>'L', +41258=>'L', +41259=>'L', +41260=>'L', +41261=>'L', +41262=>'L', +41263=>'L', +41264=>'L', +41265=>'L', +41266=>'L', +41267=>'L', +41268=>'L', +41269=>'L', +41270=>'L', +41271=>'L', +41272=>'L', +41273=>'L', +41274=>'L', +41275=>'L', +41276=>'L', +41277=>'L', +41278=>'L', +41279=>'L', +41280=>'L', +41281=>'L', +41282=>'L', +41283=>'L', +41284=>'L', +41285=>'L', +41286=>'L', +41287=>'L', +41288=>'L', +41289=>'L', +41290=>'L', +41291=>'L', +41292=>'L', +41293=>'L', +41294=>'L', +41295=>'L', +41296=>'L', +41297=>'L', +41298=>'L', +41299=>'L', +41300=>'L', +41301=>'L', +41302=>'L', +41303=>'L', +41304=>'L', +41305=>'L', +41306=>'L', +41307=>'L', +41308=>'L', +41309=>'L', +41310=>'L', +41311=>'L', +41312=>'L', +41313=>'L', +41314=>'L', +41315=>'L', +41316=>'L', +41317=>'L', +41318=>'L', +41319=>'L', +41320=>'L', +41321=>'L', +41322=>'L', +41323=>'L', +41324=>'L', +41325=>'L', +41326=>'L', +41327=>'L', +41328=>'L', +41329=>'L', +41330=>'L', +41331=>'L', +41332=>'L', +41333=>'L', +41334=>'L', +41335=>'L', +41336=>'L', +41337=>'L', +41338=>'L', +41339=>'L', +41340=>'L', +41341=>'L', +41342=>'L', +41343=>'L', +41344=>'L', +41345=>'L', +41346=>'L', +41347=>'L', +41348=>'L', +41349=>'L', +41350=>'L', +41351=>'L', +41352=>'L', +41353=>'L', +41354=>'L', +41355=>'L', +41356=>'L', +41357=>'L', +41358=>'L', +41359=>'L', +41360=>'L', +41361=>'L', +41362=>'L', +41363=>'L', +41364=>'L', +41365=>'L', +41366=>'L', +41367=>'L', +41368=>'L', +41369=>'L', +41370=>'L', +41371=>'L', +41372=>'L', +41373=>'L', +41374=>'L', +41375=>'L', +41376=>'L', +41377=>'L', +41378=>'L', +41379=>'L', +41380=>'L', +41381=>'L', +41382=>'L', +41383=>'L', +41384=>'L', +41385=>'L', +41386=>'L', +41387=>'L', +41388=>'L', +41389=>'L', +41390=>'L', +41391=>'L', +41392=>'L', +41393=>'L', +41394=>'L', +41395=>'L', +41396=>'L', +41397=>'L', +41398=>'L', +41399=>'L', +41400=>'L', +41401=>'L', +41402=>'L', +41403=>'L', +41404=>'L', +41405=>'L', +41406=>'L', +41407=>'L', +41408=>'L', +41409=>'L', +41410=>'L', +41411=>'L', +41412=>'L', +41413=>'L', +41414=>'L', +41415=>'L', +41416=>'L', +41417=>'L', +41418=>'L', +41419=>'L', +41420=>'L', +41421=>'L', +41422=>'L', +41423=>'L', +41424=>'L', +41425=>'L', +41426=>'L', +41427=>'L', +41428=>'L', +41429=>'L', +41430=>'L', +41431=>'L', +41432=>'L', +41433=>'L', +41434=>'L', +41435=>'L', +41436=>'L', +41437=>'L', +41438=>'L', +41439=>'L', +41440=>'L', +41441=>'L', +41442=>'L', +41443=>'L', +41444=>'L', +41445=>'L', +41446=>'L', +41447=>'L', +41448=>'L', +41449=>'L', +41450=>'L', +41451=>'L', +41452=>'L', +41453=>'L', +41454=>'L', +41455=>'L', +41456=>'L', +41457=>'L', +41458=>'L', +41459=>'L', +41460=>'L', +41461=>'L', +41462=>'L', +41463=>'L', +41464=>'L', +41465=>'L', +41466=>'L', +41467=>'L', +41468=>'L', +41469=>'L', +41470=>'L', +41471=>'L', +41472=>'L', +41473=>'L', +41474=>'L', +41475=>'L', +41476=>'L', +41477=>'L', +41478=>'L', +41479=>'L', +41480=>'L', +41481=>'L', +41482=>'L', +41483=>'L', +41484=>'L', +41485=>'L', +41486=>'L', +41487=>'L', +41488=>'L', +41489=>'L', +41490=>'L', +41491=>'L', +41492=>'L', +41493=>'L', +41494=>'L', +41495=>'L', +41496=>'L', +41497=>'L', +41498=>'L', +41499=>'L', +41500=>'L', +41501=>'L', +41502=>'L', +41503=>'L', +41504=>'L', +41505=>'L', +41506=>'L', +41507=>'L', +41508=>'L', +41509=>'L', +41510=>'L', +41511=>'L', +41512=>'L', +41513=>'L', +41514=>'L', +41515=>'L', +41516=>'L', +41517=>'L', +41518=>'L', +41519=>'L', +41520=>'L', +41521=>'L', +41522=>'L', +41523=>'L', +41524=>'L', +41525=>'L', +41526=>'L', +41527=>'L', +41528=>'L', +41529=>'L', +41530=>'L', +41531=>'L', +41532=>'L', +41533=>'L', +41534=>'L', +41535=>'L', +41536=>'L', +41537=>'L', +41538=>'L', +41539=>'L', +41540=>'L', +41541=>'L', +41542=>'L', +41543=>'L', +41544=>'L', +41545=>'L', +41546=>'L', +41547=>'L', +41548=>'L', +41549=>'L', +41550=>'L', +41551=>'L', +41552=>'L', +41553=>'L', +41554=>'L', +41555=>'L', +41556=>'L', +41557=>'L', +41558=>'L', +41559=>'L', +41560=>'L', +41561=>'L', +41562=>'L', +41563=>'L', +41564=>'L', +41565=>'L', +41566=>'L', +41567=>'L', +41568=>'L', +41569=>'L', +41570=>'L', +41571=>'L', +41572=>'L', +41573=>'L', +41574=>'L', +41575=>'L', +41576=>'L', +41577=>'L', +41578=>'L', +41579=>'L', +41580=>'L', +41581=>'L', +41582=>'L', +41583=>'L', +41584=>'L', +41585=>'L', +41586=>'L', +41587=>'L', +41588=>'L', +41589=>'L', +41590=>'L', +41591=>'L', +41592=>'L', +41593=>'L', +41594=>'L', +41595=>'L', +41596=>'L', +41597=>'L', +41598=>'L', +41599=>'L', +41600=>'L', +41601=>'L', +41602=>'L', +41603=>'L', +41604=>'L', +41605=>'L', +41606=>'L', +41607=>'L', +41608=>'L', +41609=>'L', +41610=>'L', +41611=>'L', +41612=>'L', +41613=>'L', +41614=>'L', +41615=>'L', +41616=>'L', +41617=>'L', +41618=>'L', +41619=>'L', +41620=>'L', +41621=>'L', +41622=>'L', +41623=>'L', +41624=>'L', +41625=>'L', +41626=>'L', +41627=>'L', +41628=>'L', +41629=>'L', +41630=>'L', +41631=>'L', +41632=>'L', +41633=>'L', +41634=>'L', +41635=>'L', +41636=>'L', +41637=>'L', +41638=>'L', +41639=>'L', +41640=>'L', +41641=>'L', +41642=>'L', +41643=>'L', +41644=>'L', +41645=>'L', +41646=>'L', +41647=>'L', +41648=>'L', +41649=>'L', +41650=>'L', +41651=>'L', +41652=>'L', +41653=>'L', +41654=>'L', +41655=>'L', +41656=>'L', +41657=>'L', +41658=>'L', +41659=>'L', +41660=>'L', +41661=>'L', +41662=>'L', +41663=>'L', +41664=>'L', +41665=>'L', +41666=>'L', +41667=>'L', +41668=>'L', +41669=>'L', +41670=>'L', +41671=>'L', +41672=>'L', +41673=>'L', +41674=>'L', +41675=>'L', +41676=>'L', +41677=>'L', +41678=>'L', +41679=>'L', +41680=>'L', +41681=>'L', +41682=>'L', +41683=>'L', +41684=>'L', +41685=>'L', +41686=>'L', +41687=>'L', +41688=>'L', +41689=>'L', +41690=>'L', +41691=>'L', +41692=>'L', +41693=>'L', +41694=>'L', +41695=>'L', +41696=>'L', +41697=>'L', +41698=>'L', +41699=>'L', +41700=>'L', +41701=>'L', +41702=>'L', +41703=>'L', +41704=>'L', +41705=>'L', +41706=>'L', +41707=>'L', +41708=>'L', +41709=>'L', +41710=>'L', +41711=>'L', +41712=>'L', +41713=>'L', +41714=>'L', +41715=>'L', +41716=>'L', +41717=>'L', +41718=>'L', +41719=>'L', +41720=>'L', +41721=>'L', +41722=>'L', +41723=>'L', +41724=>'L', +41725=>'L', +41726=>'L', +41727=>'L', +41728=>'L', +41729=>'L', +41730=>'L', +41731=>'L', +41732=>'L', +41733=>'L', +41734=>'L', +41735=>'L', +41736=>'L', +41737=>'L', +41738=>'L', +41739=>'L', +41740=>'L', +41741=>'L', +41742=>'L', +41743=>'L', +41744=>'L', +41745=>'L', +41746=>'L', +41747=>'L', +41748=>'L', +41749=>'L', +41750=>'L', +41751=>'L', +41752=>'L', +41753=>'L', +41754=>'L', +41755=>'L', +41756=>'L', +41757=>'L', +41758=>'L', +41759=>'L', +41760=>'L', +41761=>'L', +41762=>'L', +41763=>'L', +41764=>'L', +41765=>'L', +41766=>'L', +41767=>'L', +41768=>'L', +41769=>'L', +41770=>'L', +41771=>'L', +41772=>'L', +41773=>'L', +41774=>'L', +41775=>'L', +41776=>'L', +41777=>'L', +41778=>'L', +41779=>'L', +41780=>'L', +41781=>'L', +41782=>'L', +41783=>'L', +41784=>'L', +41785=>'L', +41786=>'L', +41787=>'L', +41788=>'L', +41789=>'L', +41790=>'L', +41791=>'L', +41792=>'L', +41793=>'L', +41794=>'L', +41795=>'L', +41796=>'L', +41797=>'L', +41798=>'L', +41799=>'L', +41800=>'L', +41801=>'L', +41802=>'L', +41803=>'L', +41804=>'L', +41805=>'L', +41806=>'L', +41807=>'L', +41808=>'L', +41809=>'L', +41810=>'L', +41811=>'L', +41812=>'L', +41813=>'L', +41814=>'L', +41815=>'L', +41816=>'L', +41817=>'L', +41818=>'L', +41819=>'L', +41820=>'L', +41821=>'L', +41822=>'L', +41823=>'L', +41824=>'L', +41825=>'L', +41826=>'L', +41827=>'L', +41828=>'L', +41829=>'L', +41830=>'L', +41831=>'L', +41832=>'L', +41833=>'L', +41834=>'L', +41835=>'L', +41836=>'L', +41837=>'L', +41838=>'L', +41839=>'L', +41840=>'L', +41841=>'L', +41842=>'L', +41843=>'L', +41844=>'L', +41845=>'L', +41846=>'L', +41847=>'L', +41848=>'L', +41849=>'L', +41850=>'L', +41851=>'L', +41852=>'L', +41853=>'L', +41854=>'L', +41855=>'L', +41856=>'L', +41857=>'L', +41858=>'L', +41859=>'L', +41860=>'L', +41861=>'L', +41862=>'L', +41863=>'L', +41864=>'L', +41865=>'L', +41866=>'L', +41867=>'L', +41868=>'L', +41869=>'L', +41870=>'L', +41871=>'L', +41872=>'L', +41873=>'L', +41874=>'L', +41875=>'L', +41876=>'L', +41877=>'L', +41878=>'L', +41879=>'L', +41880=>'L', +41881=>'L', +41882=>'L', +41883=>'L', +41884=>'L', +41885=>'L', +41886=>'L', +41887=>'L', +41888=>'L', +41889=>'L', +41890=>'L', +41891=>'L', +41892=>'L', +41893=>'L', +41894=>'L', +41895=>'L', +41896=>'L', +41897=>'L', +41898=>'L', +41899=>'L', +41900=>'L', +41901=>'L', +41902=>'L', +41903=>'L', +41904=>'L', +41905=>'L', +41906=>'L', +41907=>'L', +41908=>'L', +41909=>'L', +41910=>'L', +41911=>'L', +41912=>'L', +41913=>'L', +41914=>'L', +41915=>'L', +41916=>'L', +41917=>'L', +41918=>'L', +41919=>'L', +41920=>'L', +41921=>'L', +41922=>'L', +41923=>'L', +41924=>'L', +41925=>'L', +41926=>'L', +41927=>'L', +41928=>'L', +41929=>'L', +41930=>'L', +41931=>'L', +41932=>'L', +41933=>'L', +41934=>'L', +41935=>'L', +41936=>'L', +41937=>'L', +41938=>'L', +41939=>'L', +41940=>'L', +41941=>'L', +41942=>'L', +41943=>'L', +41944=>'L', +41945=>'L', +41946=>'L', +41947=>'L', +41948=>'L', +41949=>'L', +41950=>'L', +41951=>'L', +41952=>'L', +41953=>'L', +41954=>'L', +41955=>'L', +41956=>'L', +41957=>'L', +41958=>'L', +41959=>'L', +41960=>'L', +41961=>'L', +41962=>'L', +41963=>'L', +41964=>'L', +41965=>'L', +41966=>'L', +41967=>'L', +41968=>'L', +41969=>'L', +41970=>'L', +41971=>'L', +41972=>'L', +41973=>'L', +41974=>'L', +41975=>'L', +41976=>'L', +41977=>'L', +41978=>'L', +41979=>'L', +41980=>'L', +41981=>'L', +41982=>'L', +41983=>'L', +41984=>'L', +41985=>'L', +41986=>'L', +41987=>'L', +41988=>'L', +41989=>'L', +41990=>'L', +41991=>'L', +41992=>'L', +41993=>'L', +41994=>'L', +41995=>'L', +41996=>'L', +41997=>'L', +41998=>'L', +41999=>'L', +42000=>'L', +42001=>'L', +42002=>'L', +42003=>'L', +42004=>'L', +42005=>'L', +42006=>'L', +42007=>'L', +42008=>'L', +42009=>'L', +42010=>'L', +42011=>'L', +42012=>'L', +42013=>'L', +42014=>'L', +42015=>'L', +42016=>'L', +42017=>'L', +42018=>'L', +42019=>'L', +42020=>'L', +42021=>'L', +42022=>'L', +42023=>'L', +42024=>'L', +42025=>'L', +42026=>'L', +42027=>'L', +42028=>'L', +42029=>'L', +42030=>'L', +42031=>'L', +42032=>'L', +42033=>'L', +42034=>'L', +42035=>'L', +42036=>'L', +42037=>'L', +42038=>'L', +42039=>'L', +42040=>'L', +42041=>'L', +42042=>'L', +42043=>'L', +42044=>'L', +42045=>'L', +42046=>'L', +42047=>'L', +42048=>'L', +42049=>'L', +42050=>'L', +42051=>'L', +42052=>'L', +42053=>'L', +42054=>'L', +42055=>'L', +42056=>'L', +42057=>'L', +42058=>'L', +42059=>'L', +42060=>'L', +42061=>'L', +42062=>'L', +42063=>'L', +42064=>'L', +42065=>'L', +42066=>'L', +42067=>'L', +42068=>'L', +42069=>'L', +42070=>'L', +42071=>'L', +42072=>'L', +42073=>'L', +42074=>'L', +42075=>'L', +42076=>'L', +42077=>'L', +42078=>'L', +42079=>'L', +42080=>'L', +42081=>'L', +42082=>'L', +42083=>'L', +42084=>'L', +42085=>'L', +42086=>'L', +42087=>'L', +42088=>'L', +42089=>'L', +42090=>'L', +42091=>'L', +42092=>'L', +42093=>'L', +42094=>'L', +42095=>'L', +42096=>'L', +42097=>'L', +42098=>'L', +42099=>'L', +42100=>'L', +42101=>'L', +42102=>'L', +42103=>'L', +42104=>'L', +42105=>'L', +42106=>'L', +42107=>'L', +42108=>'L', +42109=>'L', +42110=>'L', +42111=>'L', +42112=>'L', +42113=>'L', +42114=>'L', +42115=>'L', +42116=>'L', +42117=>'L', +42118=>'L', +42119=>'L', +42120=>'L', +42121=>'L', +42122=>'L', +42123=>'L', +42124=>'L', +42128=>'ON', +42129=>'ON', +42130=>'ON', +42131=>'ON', +42132=>'ON', +42133=>'ON', +42134=>'ON', +42135=>'ON', +42136=>'ON', +42137=>'ON', +42138=>'ON', +42139=>'ON', +42140=>'ON', +42141=>'ON', +42142=>'ON', +42143=>'ON', +42144=>'ON', +42145=>'ON', +42146=>'ON', +42147=>'ON', +42148=>'ON', +42149=>'ON', +42150=>'ON', +42151=>'ON', +42152=>'ON', +42153=>'ON', +42154=>'ON', +42155=>'ON', +42156=>'ON', +42157=>'ON', +42158=>'ON', +42159=>'ON', +42160=>'ON', +42161=>'ON', +42162=>'ON', +42163=>'ON', +42164=>'ON', +42165=>'ON', +42166=>'ON', +42167=>'ON', +42168=>'ON', +42169=>'ON', +42170=>'ON', +42171=>'ON', +42172=>'ON', +42173=>'ON', +42174=>'ON', +42175=>'ON', +42176=>'ON', +42177=>'ON', +42178=>'ON', +42179=>'ON', +42180=>'ON', +42181=>'ON', +42182=>'ON', +42752=>'ON', +42753=>'ON', +42754=>'ON', +42755=>'ON', +42756=>'ON', +42757=>'ON', +42758=>'ON', +42759=>'ON', +42760=>'ON', +42761=>'ON', +42762=>'ON', +42763=>'ON', +42764=>'ON', +42765=>'ON', +42766=>'ON', +42767=>'ON', +42768=>'ON', +42769=>'ON', +42770=>'ON', +42771=>'ON', +42772=>'ON', +42773=>'ON', +42774=>'ON', +42775=>'ON', +42776=>'ON', +42777=>'ON', +42778=>'ON', +42784=>'ON', +42785=>'ON', +43008=>'L', +43009=>'L', +43010=>'NSM', +43011=>'L', +43012=>'L', +43013=>'L', +43014=>'NSM', +43015=>'L', +43016=>'L', +43017=>'L', +43018=>'L', +43019=>'NSM', +43020=>'L', +43021=>'L', +43022=>'L', +43023=>'L', +43024=>'L', +43025=>'L', +43026=>'L', +43027=>'L', +43028=>'L', +43029=>'L', +43030=>'L', +43031=>'L', +43032=>'L', +43033=>'L', +43034=>'L', +43035=>'L', +43036=>'L', +43037=>'L', +43038=>'L', +43039=>'L', +43040=>'L', +43041=>'L', +43042=>'L', +43043=>'L', +43044=>'L', +43045=>'NSM', +43046=>'NSM', +43047=>'L', +43048=>'ON', +43049=>'ON', +43050=>'ON', +43051=>'ON', +43072=>'L', +43073=>'L', +43074=>'L', +43075=>'L', +43076=>'L', +43077=>'L', +43078=>'L', +43079=>'L', +43080=>'L', +43081=>'L', +43082=>'L', +43083=>'L', +43084=>'L', +43085=>'L', +43086=>'L', +43087=>'L', +43088=>'L', +43089=>'L', +43090=>'L', +43091=>'L', +43092=>'L', +43093=>'L', +43094=>'L', +43095=>'L', +43096=>'L', +43097=>'L', +43098=>'L', +43099=>'L', +43100=>'L', +43101=>'L', +43102=>'L', +43103=>'L', +43104=>'L', +43105=>'L', +43106=>'L', +43107=>'L', +43108=>'L', +43109=>'L', +43110=>'L', +43111=>'L', +43112=>'L', +43113=>'L', +43114=>'L', +43115=>'L', +43116=>'L', +43117=>'L', +43118=>'L', +43119=>'L', +43120=>'L', +43121=>'L', +43122=>'L', +43123=>'L', +43124=>'ON', +43125=>'ON', +43126=>'ON', +43127=>'ON', +44032=>'L', +55203=>'L', +55296=>'L', +56191=>'L', +56192=>'L', +56319=>'L', +56320=>'L', +57343=>'L', +57344=>'L', +63743=>'L', +63744=>'L', +63745=>'L', +63746=>'L', +63747=>'L', +63748=>'L', +63749=>'L', +63750=>'L', +63751=>'L', +63752=>'L', +63753=>'L', +63754=>'L', +63755=>'L', +63756=>'L', +63757=>'L', +63758=>'L', +63759=>'L', +63760=>'L', +63761=>'L', +63762=>'L', +63763=>'L', +63764=>'L', +63765=>'L', +63766=>'L', +63767=>'L', +63768=>'L', +63769=>'L', +63770=>'L', +63771=>'L', +63772=>'L', +63773=>'L', +63774=>'L', +63775=>'L', +63776=>'L', +63777=>'L', +63778=>'L', +63779=>'L', +63780=>'L', +63781=>'L', +63782=>'L', +63783=>'L', +63784=>'L', +63785=>'L', +63786=>'L', +63787=>'L', +63788=>'L', +63789=>'L', +63790=>'L', +63791=>'L', +63792=>'L', +63793=>'L', +63794=>'L', +63795=>'L', +63796=>'L', +63797=>'L', +63798=>'L', +63799=>'L', +63800=>'L', +63801=>'L', +63802=>'L', +63803=>'L', +63804=>'L', +63805=>'L', +63806=>'L', +63807=>'L', +63808=>'L', +63809=>'L', +63810=>'L', +63811=>'L', +63812=>'L', +63813=>'L', +63814=>'L', +63815=>'L', +63816=>'L', +63817=>'L', +63818=>'L', +63819=>'L', +63820=>'L', +63821=>'L', +63822=>'L', +63823=>'L', +63824=>'L', +63825=>'L', +63826=>'L', +63827=>'L', +63828=>'L', +63829=>'L', +63830=>'L', +63831=>'L', +63832=>'L', +63833=>'L', +63834=>'L', +63835=>'L', +63836=>'L', +63837=>'L', +63838=>'L', +63839=>'L', +63840=>'L', +63841=>'L', +63842=>'L', +63843=>'L', +63844=>'L', +63845=>'L', +63846=>'L', +63847=>'L', +63848=>'L', +63849=>'L', +63850=>'L', +63851=>'L', +63852=>'L', +63853=>'L', +63854=>'L', +63855=>'L', +63856=>'L', +63857=>'L', +63858=>'L', +63859=>'L', +63860=>'L', +63861=>'L', +63862=>'L', +63863=>'L', +63864=>'L', +63865=>'L', +63866=>'L', +63867=>'L', +63868=>'L', +63869=>'L', +63870=>'L', +63871=>'L', +63872=>'L', +63873=>'L', +63874=>'L', +63875=>'L', +63876=>'L', +63877=>'L', +63878=>'L', +63879=>'L', +63880=>'L', +63881=>'L', +63882=>'L', +63883=>'L', +63884=>'L', +63885=>'L', +63886=>'L', +63887=>'L', +63888=>'L', +63889=>'L', +63890=>'L', +63891=>'L', +63892=>'L', +63893=>'L', +63894=>'L', +63895=>'L', +63896=>'L', +63897=>'L', +63898=>'L', +63899=>'L', +63900=>'L', +63901=>'L', +63902=>'L', +63903=>'L', +63904=>'L', +63905=>'L', +63906=>'L', +63907=>'L', +63908=>'L', +63909=>'L', +63910=>'L', +63911=>'L', +63912=>'L', +63913=>'L', +63914=>'L', +63915=>'L', +63916=>'L', +63917=>'L', +63918=>'L', +63919=>'L', +63920=>'L', +63921=>'L', +63922=>'L', +63923=>'L', +63924=>'L', +63925=>'L', +63926=>'L', +63927=>'L', +63928=>'L', +63929=>'L', +63930=>'L', +63931=>'L', +63932=>'L', +63933=>'L', +63934=>'L', +63935=>'L', +63936=>'L', +63937=>'L', +63938=>'L', +63939=>'L', +63940=>'L', +63941=>'L', +63942=>'L', +63943=>'L', +63944=>'L', +63945=>'L', +63946=>'L', +63947=>'L', +63948=>'L', +63949=>'L', +63950=>'L', +63951=>'L', +63952=>'L', +63953=>'L', +63954=>'L', +63955=>'L', +63956=>'L', +63957=>'L', +63958=>'L', +63959=>'L', +63960=>'L', +63961=>'L', +63962=>'L', +63963=>'L', +63964=>'L', +63965=>'L', +63966=>'L', +63967=>'L', +63968=>'L', +63969=>'L', +63970=>'L', +63971=>'L', +63972=>'L', +63973=>'L', +63974=>'L', +63975=>'L', +63976=>'L', +63977=>'L', +63978=>'L', +63979=>'L', +63980=>'L', +63981=>'L', +63982=>'L', +63983=>'L', +63984=>'L', +63985=>'L', +63986=>'L', +63987=>'L', +63988=>'L', +63989=>'L', +63990=>'L', +63991=>'L', +63992=>'L', +63993=>'L', +63994=>'L', +63995=>'L', +63996=>'L', +63997=>'L', +63998=>'L', +63999=>'L', +64000=>'L', +64001=>'L', +64002=>'L', +64003=>'L', +64004=>'L', +64005=>'L', +64006=>'L', +64007=>'L', +64008=>'L', +64009=>'L', +64010=>'L', +64011=>'L', +64012=>'L', +64013=>'L', +64014=>'L', +64015=>'L', +64016=>'L', +64017=>'L', +64018=>'L', +64019=>'L', +64020=>'L', +64021=>'L', +64022=>'L', +64023=>'L', +64024=>'L', +64025=>'L', +64026=>'L', +64027=>'L', +64028=>'L', +64029=>'L', +64030=>'L', +64031=>'L', +64032=>'L', +64033=>'L', +64034=>'L', +64035=>'L', +64036=>'L', +64037=>'L', +64038=>'L', +64039=>'L', +64040=>'L', +64041=>'L', +64042=>'L', +64043=>'L', +64044=>'L', +64045=>'L', +64048=>'L', +64049=>'L', +64050=>'L', +64051=>'L', +64052=>'L', +64053=>'L', +64054=>'L', +64055=>'L', +64056=>'L', +64057=>'L', +64058=>'L', +64059=>'L', +64060=>'L', +64061=>'L', +64062=>'L', +64063=>'L', +64064=>'L', +64065=>'L', +64066=>'L', +64067=>'L', +64068=>'L', +64069=>'L', +64070=>'L', +64071=>'L', +64072=>'L', +64073=>'L', +64074=>'L', +64075=>'L', +64076=>'L', +64077=>'L', +64078=>'L', +64079=>'L', +64080=>'L', +64081=>'L', +64082=>'L', +64083=>'L', +64084=>'L', +64085=>'L', +64086=>'L', +64087=>'L', +64088=>'L', +64089=>'L', +64090=>'L', +64091=>'L', +64092=>'L', +64093=>'L', +64094=>'L', +64095=>'L', +64096=>'L', +64097=>'L', +64098=>'L', +64099=>'L', +64100=>'L', +64101=>'L', +64102=>'L', +64103=>'L', +64104=>'L', +64105=>'L', +64106=>'L', +64112=>'L', +64113=>'L', +64114=>'L', +64115=>'L', +64116=>'L', +64117=>'L', +64118=>'L', +64119=>'L', +64120=>'L', +64121=>'L', +64122=>'L', +64123=>'L', +64124=>'L', +64125=>'L', +64126=>'L', +64127=>'L', +64128=>'L', +64129=>'L', +64130=>'L', +64131=>'L', +64132=>'L', +64133=>'L', +64134=>'L', +64135=>'L', +64136=>'L', +64137=>'L', +64138=>'L', +64139=>'L', +64140=>'L', +64141=>'L', +64142=>'L', +64143=>'L', +64144=>'L', +64145=>'L', +64146=>'L', +64147=>'L', +64148=>'L', +64149=>'L', +64150=>'L', +64151=>'L', +64152=>'L', +64153=>'L', +64154=>'L', +64155=>'L', +64156=>'L', +64157=>'L', +64158=>'L', +64159=>'L', +64160=>'L', +64161=>'L', +64162=>'L', +64163=>'L', +64164=>'L', +64165=>'L', +64166=>'L', +64167=>'L', +64168=>'L', +64169=>'L', +64170=>'L', +64171=>'L', +64172=>'L', +64173=>'L', +64174=>'L', +64175=>'L', +64176=>'L', +64177=>'L', +64178=>'L', +64179=>'L', +64180=>'L', +64181=>'L', +64182=>'L', +64183=>'L', +64184=>'L', +64185=>'L', +64186=>'L', +64187=>'L', +64188=>'L', +64189=>'L', +64190=>'L', +64191=>'L', +64192=>'L', +64193=>'L', +64194=>'L', +64195=>'L', +64196=>'L', +64197=>'L', +64198=>'L', +64199=>'L', +64200=>'L', +64201=>'L', +64202=>'L', +64203=>'L', +64204=>'L', +64205=>'L', +64206=>'L', +64207=>'L', +64208=>'L', +64209=>'L', +64210=>'L', +64211=>'L', +64212=>'L', +64213=>'L', +64214=>'L', +64215=>'L', +64216=>'L', +64217=>'L', +64256=>'L', +64257=>'L', +64258=>'L', +64259=>'L', +64260=>'L', +64261=>'L', +64262=>'L', +64275=>'L', +64276=>'L', +64277=>'L', +64278=>'L', +64279=>'L', +64285=>'R', +64286=>'NSM', +64287=>'R', +64288=>'R', +64289=>'R', +64290=>'R', +64291=>'R', +64292=>'R', +64293=>'R', +64294=>'R', +64295=>'R', +64296=>'R', +64297=>'ES', +64298=>'R', +64299=>'R', +64300=>'R', +64301=>'R', +64302=>'R', +64303=>'R', +64304=>'R', +64305=>'R', +64306=>'R', +64307=>'R', +64308=>'R', +64309=>'R', +64310=>'R', +64312=>'R', +64313=>'R', +64314=>'R', +64315=>'R', +64316=>'R', +64318=>'R', +64320=>'R', +64321=>'R', +64323=>'R', +64324=>'R', +64326=>'R', +64327=>'R', +64328=>'R', +64329=>'R', +64330=>'R', +64331=>'R', +64332=>'R', +64333=>'R', +64334=>'R', +64335=>'R', +64336=>'AL', +64337=>'AL', +64338=>'AL', +64339=>'AL', +64340=>'AL', +64341=>'AL', +64342=>'AL', +64343=>'AL', +64344=>'AL', +64345=>'AL', +64346=>'AL', +64347=>'AL', +64348=>'AL', +64349=>'AL', +64350=>'AL', +64351=>'AL', +64352=>'AL', +64353=>'AL', +64354=>'AL', +64355=>'AL', +64356=>'AL', +64357=>'AL', +64358=>'AL', +64359=>'AL', +64360=>'AL', +64361=>'AL', +64362=>'AL', +64363=>'AL', +64364=>'AL', +64365=>'AL', +64366=>'AL', +64367=>'AL', +64368=>'AL', +64369=>'AL', +64370=>'AL', +64371=>'AL', +64372=>'AL', +64373=>'AL', +64374=>'AL', +64375=>'AL', +64376=>'AL', +64377=>'AL', +64378=>'AL', +64379=>'AL', +64380=>'AL', +64381=>'AL', +64382=>'AL', +64383=>'AL', +64384=>'AL', +64385=>'AL', +64386=>'AL', +64387=>'AL', +64388=>'AL', +64389=>'AL', +64390=>'AL', +64391=>'AL', +64392=>'AL', +64393=>'AL', +64394=>'AL', +64395=>'AL', +64396=>'AL', +64397=>'AL', +64398=>'AL', +64399=>'AL', +64400=>'AL', +64401=>'AL', +64402=>'AL', +64403=>'AL', +64404=>'AL', +64405=>'AL', +64406=>'AL', +64407=>'AL', +64408=>'AL', +64409=>'AL', +64410=>'AL', +64411=>'AL', +64412=>'AL', +64413=>'AL', +64414=>'AL', +64415=>'AL', +64416=>'AL', +64417=>'AL', +64418=>'AL', +64419=>'AL', +64420=>'AL', +64421=>'AL', +64422=>'AL', +64423=>'AL', +64424=>'AL', +64425=>'AL', +64426=>'AL', +64427=>'AL', +64428=>'AL', +64429=>'AL', +64430=>'AL', +64431=>'AL', +64432=>'AL', +64433=>'AL', +64467=>'AL', +64468=>'AL', +64469=>'AL', +64470=>'AL', +64471=>'AL', +64472=>'AL', +64473=>'AL', +64474=>'AL', +64475=>'AL', +64476=>'AL', +64477=>'AL', +64478=>'AL', +64479=>'AL', +64480=>'AL', +64481=>'AL', +64482=>'AL', +64483=>'AL', +64484=>'AL', +64485=>'AL', +64486=>'AL', +64487=>'AL', +64488=>'AL', +64489=>'AL', +64490=>'AL', +64491=>'AL', +64492=>'AL', +64493=>'AL', +64494=>'AL', +64495=>'AL', +64496=>'AL', +64497=>'AL', +64498=>'AL', +64499=>'AL', +64500=>'AL', +64501=>'AL', +64502=>'AL', +64503=>'AL', +64504=>'AL', +64505=>'AL', +64506=>'AL', +64507=>'AL', +64508=>'AL', +64509=>'AL', +64510=>'AL', +64511=>'AL', +64512=>'AL', +64513=>'AL', +64514=>'AL', +64515=>'AL', +64516=>'AL', +64517=>'AL', +64518=>'AL', +64519=>'AL', +64520=>'AL', +64521=>'AL', +64522=>'AL', +64523=>'AL', +64524=>'AL', +64525=>'AL', +64526=>'AL', +64527=>'AL', +64528=>'AL', +64529=>'AL', +64530=>'AL', +64531=>'AL', +64532=>'AL', +64533=>'AL', +64534=>'AL', +64535=>'AL', +64536=>'AL', +64537=>'AL', +64538=>'AL', +64539=>'AL', +64540=>'AL', +64541=>'AL', +64542=>'AL', +64543=>'AL', +64544=>'AL', +64545=>'AL', +64546=>'AL', +64547=>'AL', +64548=>'AL', +64549=>'AL', +64550=>'AL', +64551=>'AL', +64552=>'AL', +64553=>'AL', +64554=>'AL', +64555=>'AL', +64556=>'AL', +64557=>'AL', +64558=>'AL', +64559=>'AL', +64560=>'AL', +64561=>'AL', +64562=>'AL', +64563=>'AL', +64564=>'AL', +64565=>'AL', +64566=>'AL', +64567=>'AL', +64568=>'AL', +64569=>'AL', +64570=>'AL', +64571=>'AL', +64572=>'AL', +64573=>'AL', +64574=>'AL', +64575=>'AL', +64576=>'AL', +64577=>'AL', +64578=>'AL', +64579=>'AL', +64580=>'AL', +64581=>'AL', +64582=>'AL', +64583=>'AL', +64584=>'AL', +64585=>'AL', +64586=>'AL', +64587=>'AL', +64588=>'AL', +64589=>'AL', +64590=>'AL', +64591=>'AL', +64592=>'AL', +64593=>'AL', +64594=>'AL', +64595=>'AL', +64596=>'AL', +64597=>'AL', +64598=>'AL', +64599=>'AL', +64600=>'AL', +64601=>'AL', +64602=>'AL', +64603=>'AL', +64604=>'AL', +64605=>'AL', +64606=>'AL', +64607=>'AL', +64608=>'AL', +64609=>'AL', +64610=>'AL', +64611=>'AL', +64612=>'AL', +64613=>'AL', +64614=>'AL', +64615=>'AL', +64616=>'AL', +64617=>'AL', +64618=>'AL', +64619=>'AL', +64620=>'AL', +64621=>'AL', +64622=>'AL', +64623=>'AL', +64624=>'AL', +64625=>'AL', +64626=>'AL', +64627=>'AL', +64628=>'AL', +64629=>'AL', +64630=>'AL', +64631=>'AL', +64632=>'AL', +64633=>'AL', +64634=>'AL', +64635=>'AL', +64636=>'AL', +64637=>'AL', +64638=>'AL', +64639=>'AL', +64640=>'AL', +64641=>'AL', +64642=>'AL', +64643=>'AL', +64644=>'AL', +64645=>'AL', +64646=>'AL', +64647=>'AL', +64648=>'AL', +64649=>'AL', +64650=>'AL', +64651=>'AL', +64652=>'AL', +64653=>'AL', +64654=>'AL', +64655=>'AL', +64656=>'AL', +64657=>'AL', +64658=>'AL', +64659=>'AL', +64660=>'AL', +64661=>'AL', +64662=>'AL', +64663=>'AL', +64664=>'AL', +64665=>'AL', +64666=>'AL', +64667=>'AL', +64668=>'AL', +64669=>'AL', +64670=>'AL', +64671=>'AL', +64672=>'AL', +64673=>'AL', +64674=>'AL', +64675=>'AL', +64676=>'AL', +64677=>'AL', +64678=>'AL', +64679=>'AL', +64680=>'AL', +64681=>'AL', +64682=>'AL', +64683=>'AL', +64684=>'AL', +64685=>'AL', +64686=>'AL', +64687=>'AL', +64688=>'AL', +64689=>'AL', +64690=>'AL', +64691=>'AL', +64692=>'AL', +64693=>'AL', +64694=>'AL', +64695=>'AL', +64696=>'AL', +64697=>'AL', +64698=>'AL', +64699=>'AL', +64700=>'AL', +64701=>'AL', +64702=>'AL', +64703=>'AL', +64704=>'AL', +64705=>'AL', +64706=>'AL', +64707=>'AL', +64708=>'AL', +64709=>'AL', +64710=>'AL', +64711=>'AL', +64712=>'AL', +64713=>'AL', +64714=>'AL', +64715=>'AL', +64716=>'AL', +64717=>'AL', +64718=>'AL', +64719=>'AL', +64720=>'AL', +64721=>'AL', +64722=>'AL', +64723=>'AL', +64724=>'AL', +64725=>'AL', +64726=>'AL', +64727=>'AL', +64728=>'AL', +64729=>'AL', +64730=>'AL', +64731=>'AL', +64732=>'AL', +64733=>'AL', +64734=>'AL', +64735=>'AL', +64736=>'AL', +64737=>'AL', +64738=>'AL', +64739=>'AL', +64740=>'AL', +64741=>'AL', +64742=>'AL', +64743=>'AL', +64744=>'AL', +64745=>'AL', +64746=>'AL', +64747=>'AL', +64748=>'AL', +64749=>'AL', +64750=>'AL', +64751=>'AL', +64752=>'AL', +64753=>'AL', +64754=>'AL', +64755=>'AL', +64756=>'AL', +64757=>'AL', +64758=>'AL', +64759=>'AL', +64760=>'AL', +64761=>'AL', +64762=>'AL', +64763=>'AL', +64764=>'AL', +64765=>'AL', +64766=>'AL', +64767=>'AL', +64768=>'AL', +64769=>'AL', +64770=>'AL', +64771=>'AL', +64772=>'AL', +64773=>'AL', +64774=>'AL', +64775=>'AL', +64776=>'AL', +64777=>'AL', +64778=>'AL', +64779=>'AL', +64780=>'AL', +64781=>'AL', +64782=>'AL', +64783=>'AL', +64784=>'AL', +64785=>'AL', +64786=>'AL', +64787=>'AL', +64788=>'AL', +64789=>'AL', +64790=>'AL', +64791=>'AL', +64792=>'AL', +64793=>'AL', +64794=>'AL', +64795=>'AL', +64796=>'AL', +64797=>'AL', +64798=>'AL', +64799=>'AL', +64800=>'AL', +64801=>'AL', +64802=>'AL', +64803=>'AL', +64804=>'AL', +64805=>'AL', +64806=>'AL', +64807=>'AL', +64808=>'AL', +64809=>'AL', +64810=>'AL', +64811=>'AL', +64812=>'AL', +64813=>'AL', +64814=>'AL', +64815=>'AL', +64816=>'AL', +64817=>'AL', +64818=>'AL', +64819=>'AL', +64820=>'AL', +64821=>'AL', +64822=>'AL', +64823=>'AL', +64824=>'AL', +64825=>'AL', +64826=>'AL', +64827=>'AL', +64828=>'AL', +64829=>'AL', +64830=>'ON', +64831=>'ON', +64848=>'AL', +64849=>'AL', +64850=>'AL', +64851=>'AL', +64852=>'AL', +64853=>'AL', +64854=>'AL', +64855=>'AL', +64856=>'AL', +64857=>'AL', +64858=>'AL', +64859=>'AL', +64860=>'AL', +64861=>'AL', +64862=>'AL', +64863=>'AL', +64864=>'AL', +64865=>'AL', +64866=>'AL', +64867=>'AL', +64868=>'AL', +64869=>'AL', +64870=>'AL', +64871=>'AL', +64872=>'AL', +64873=>'AL', +64874=>'AL', +64875=>'AL', +64876=>'AL', +64877=>'AL', +64878=>'AL', +64879=>'AL', +64880=>'AL', +64881=>'AL', +64882=>'AL', +64883=>'AL', +64884=>'AL', +64885=>'AL', +64886=>'AL', +64887=>'AL', +64888=>'AL', +64889=>'AL', +64890=>'AL', +64891=>'AL', +64892=>'AL', +64893=>'AL', +64894=>'AL', +64895=>'AL', +64896=>'AL', +64897=>'AL', +64898=>'AL', +64899=>'AL', +64900=>'AL', +64901=>'AL', +64902=>'AL', +64903=>'AL', +64904=>'AL', +64905=>'AL', +64906=>'AL', +64907=>'AL', +64908=>'AL', +64909=>'AL', +64910=>'AL', +64911=>'AL', +64914=>'AL', +64915=>'AL', +64916=>'AL', +64917=>'AL', +64918=>'AL', +64919=>'AL', +64920=>'AL', +64921=>'AL', +64922=>'AL', +64923=>'AL', +64924=>'AL', +64925=>'AL', +64926=>'AL', +64927=>'AL', +64928=>'AL', +64929=>'AL', +64930=>'AL', +64931=>'AL', +64932=>'AL', +64933=>'AL', +64934=>'AL', +64935=>'AL', +64936=>'AL', +64937=>'AL', +64938=>'AL', +64939=>'AL', +64940=>'AL', +64941=>'AL', +64942=>'AL', +64943=>'AL', +64944=>'AL', +64945=>'AL', +64946=>'AL', +64947=>'AL', +64948=>'AL', +64949=>'AL', +64950=>'AL', +64951=>'AL', +64952=>'AL', +64953=>'AL', +64954=>'AL', +64955=>'AL', +64956=>'AL', +64957=>'AL', +64958=>'AL', +64959=>'AL', +64960=>'AL', +64961=>'AL', +64962=>'AL', +64963=>'AL', +64964=>'AL', +64965=>'AL', +64966=>'AL', +64967=>'AL', +65008=>'AL', +65009=>'AL', +65010=>'AL', +65011=>'AL', +65012=>'AL', +65013=>'AL', +65014=>'AL', +65015=>'AL', +65016=>'AL', +65017=>'AL', +65018=>'AL', +65019=>'AL', +65020=>'AL', +65021=>'ON', +65024=>'NSM', +65025=>'NSM', +65026=>'NSM', +65027=>'NSM', +65028=>'NSM', +65029=>'NSM', +65030=>'NSM', +65031=>'NSM', +65032=>'NSM', +65033=>'NSM', +65034=>'NSM', +65035=>'NSM', +65036=>'NSM', +65037=>'NSM', +65038=>'NSM', +65039=>'NSM', +65040=>'ON', +65041=>'ON', +65042=>'ON', +65043=>'ON', +65044=>'ON', +65045=>'ON', +65046=>'ON', +65047=>'ON', +65048=>'ON', +65049=>'ON', +65056=>'NSM', +65057=>'NSM', +65058=>'NSM', +65059=>'NSM', +65072=>'ON', +65073=>'ON', +65074=>'ON', +65075=>'ON', +65076=>'ON', +65077=>'ON', +65078=>'ON', +65079=>'ON', +65080=>'ON', +65081=>'ON', +65082=>'ON', +65083=>'ON', +65084=>'ON', +65085=>'ON', +65086=>'ON', +65087=>'ON', +65088=>'ON', +65089=>'ON', +65090=>'ON', +65091=>'ON', +65092=>'ON', +65093=>'ON', +65094=>'ON', +65095=>'ON', +65096=>'ON', +65097=>'ON', +65098=>'ON', +65099=>'ON', +65100=>'ON', +65101=>'ON', +65102=>'ON', +65103=>'ON', +65104=>'CS', +65105=>'ON', +65106=>'CS', +65108=>'ON', +65109=>'CS', +65110=>'ON', +65111=>'ON', +65112=>'ON', +65113=>'ON', +65114=>'ON', +65115=>'ON', +65116=>'ON', +65117=>'ON', +65118=>'ON', +65119=>'ET', +65120=>'ON', +65121=>'ON', +65122=>'ES', +65123=>'ES', +65124=>'ON', +65125=>'ON', +65126=>'ON', +65128=>'ON', +65129=>'ET', +65130=>'ET', +65131=>'ON', +65136=>'AL', +65137=>'AL', +65138=>'AL', +65139=>'AL', +65140=>'AL', +65142=>'AL', +65143=>'AL', +65144=>'AL', +65145=>'AL', +65146=>'AL', +65147=>'AL', +65148=>'AL', +65149=>'AL', +65150=>'AL', +65151=>'AL', +65152=>'AL', +65153=>'AL', +65154=>'AL', +65155=>'AL', +65156=>'AL', +65157=>'AL', +65158=>'AL', +65159=>'AL', +65160=>'AL', +65161=>'AL', +65162=>'AL', +65163=>'AL', +65164=>'AL', +65165=>'AL', +65166=>'AL', +65167=>'AL', +65168=>'AL', +65169=>'AL', +65170=>'AL', +65171=>'AL', +65172=>'AL', +65173=>'AL', +65174=>'AL', +65175=>'AL', +65176=>'AL', +65177=>'AL', +65178=>'AL', +65179=>'AL', +65180=>'AL', +65181=>'AL', +65182=>'AL', +65183=>'AL', +65184=>'AL', +65185=>'AL', +65186=>'AL', +65187=>'AL', +65188=>'AL', +65189=>'AL', +65190=>'AL', +65191=>'AL', +65192=>'AL', +65193=>'AL', +65194=>'AL', +65195=>'AL', +65196=>'AL', +65197=>'AL', +65198=>'AL', +65199=>'AL', +65200=>'AL', +65201=>'AL', +65202=>'AL', +65203=>'AL', +65204=>'AL', +65205=>'AL', +65206=>'AL', +65207=>'AL', +65208=>'AL', +65209=>'AL', +65210=>'AL', +65211=>'AL', +65212=>'AL', +65213=>'AL', +65214=>'AL', +65215=>'AL', +65216=>'AL', +65217=>'AL', +65218=>'AL', +65219=>'AL', +65220=>'AL', +65221=>'AL', +65222=>'AL', +65223=>'AL', +65224=>'AL', +65225=>'AL', +65226=>'AL', +65227=>'AL', +65228=>'AL', +65229=>'AL', +65230=>'AL', +65231=>'AL', +65232=>'AL', +65233=>'AL', +65234=>'AL', +65235=>'AL', +65236=>'AL', +65237=>'AL', +65238=>'AL', +65239=>'AL', +65240=>'AL', +65241=>'AL', +65242=>'AL', +65243=>'AL', +65244=>'AL', +65245=>'AL', +65246=>'AL', +65247=>'AL', +65248=>'AL', +65249=>'AL', +65250=>'AL', +65251=>'AL', +65252=>'AL', +65253=>'AL', +65254=>'AL', +65255=>'AL', +65256=>'AL', +65257=>'AL', +65258=>'AL', +65259=>'AL', +65260=>'AL', +65261=>'AL', +65262=>'AL', +65263=>'AL', +65264=>'AL', +65265=>'AL', +65266=>'AL', +65267=>'AL', +65268=>'AL', +65269=>'AL', +65270=>'AL', +65271=>'AL', +65272=>'AL', +65273=>'AL', +65274=>'AL', +65275=>'AL', +65276=>'AL', +65279=>'BN', +65281=>'ON', +65282=>'ON', +65283=>'ET', +65284=>'ET', +65285=>'ET', +65286=>'ON', +65287=>'ON', +65288=>'ON', +65289=>'ON', +65290=>'ON', +65291=>'ES', +65292=>'CS', +65293=>'ES', +65294=>'CS', +65295=>'CS', +65296=>'EN', +65297=>'EN', +65298=>'EN', +65299=>'EN', +65300=>'EN', +65301=>'EN', +65302=>'EN', +65303=>'EN', +65304=>'EN', +65305=>'EN', +65306=>'CS', +65307=>'ON', +65308=>'ON', +65309=>'ON', +65310=>'ON', +65311=>'ON', +65312=>'ON', +65313=>'L', +65314=>'L', +65315=>'L', +65316=>'L', +65317=>'L', +65318=>'L', +65319=>'L', +65320=>'L', +65321=>'L', +65322=>'L', +65323=>'L', +65324=>'L', +65325=>'L', +65326=>'L', +65327=>'L', +65328=>'L', +65329=>'L', +65330=>'L', +65331=>'L', +65332=>'L', +65333=>'L', +65334=>'L', +65335=>'L', +65336=>'L', +65337=>'L', +65338=>'L', +65339=>'ON', +65340=>'ON', +65341=>'ON', +65342=>'ON', +65343=>'ON', +65344=>'ON', +65345=>'L', +65346=>'L', +65347=>'L', +65348=>'L', +65349=>'L', +65350=>'L', +65351=>'L', +65352=>'L', +65353=>'L', +65354=>'L', +65355=>'L', +65356=>'L', +65357=>'L', +65358=>'L', +65359=>'L', +65360=>'L', +65361=>'L', +65362=>'L', +65363=>'L', +65364=>'L', +65365=>'L', +65366=>'L', +65367=>'L', +65368=>'L', +65369=>'L', +65370=>'L', +65371=>'ON', +65372=>'ON', +65373=>'ON', +65374=>'ON', +65375=>'ON', +65376=>'ON', +65377=>'ON', +65378=>'ON', +65379=>'ON', +65380=>'ON', +65381=>'ON', +65382=>'L', +65383=>'L', +65384=>'L', +65385=>'L', +65386=>'L', +65387=>'L', +65388=>'L', +65389=>'L', +65390=>'L', +65391=>'L', +65392=>'L', +65393=>'L', +65394=>'L', +65395=>'L', +65396=>'L', +65397=>'L', +65398=>'L', +65399=>'L', +65400=>'L', +65401=>'L', +65402=>'L', +65403=>'L', +65404=>'L', +65405=>'L', +65406=>'L', +65407=>'L', +65408=>'L', +65409=>'L', +65410=>'L', +65411=>'L', +65412=>'L', +65413=>'L', +65414=>'L', +65415=>'L', +65416=>'L', +65417=>'L', +65418=>'L', +65419=>'L', +65420=>'L', +65421=>'L', +65422=>'L', +65423=>'L', +65424=>'L', +65425=>'L', +65426=>'L', +65427=>'L', +65428=>'L', +65429=>'L', +65430=>'L', +65431=>'L', +65432=>'L', +65433=>'L', +65434=>'L', +65435=>'L', +65436=>'L', +65437=>'L', +65438=>'L', +65439=>'L', +65440=>'L', +65441=>'L', +65442=>'L', +65443=>'L', +65444=>'L', +65445=>'L', +65446=>'L', +65447=>'L', +65448=>'L', +65449=>'L', +65450=>'L', +65451=>'L', +65452=>'L', +65453=>'L', +65454=>'L', +65455=>'L', +65456=>'L', +65457=>'L', +65458=>'L', +65459=>'L', +65460=>'L', +65461=>'L', +65462=>'L', +65463=>'L', +65464=>'L', +65465=>'L', +65466=>'L', +65467=>'L', +65468=>'L', +65469=>'L', +65470=>'L', +65474=>'L', +65475=>'L', +65476=>'L', +65477=>'L', +65478=>'L', +65479=>'L', +65482=>'L', +65483=>'L', +65484=>'L', +65485=>'L', +65486=>'L', +65487=>'L', +65490=>'L', +65491=>'L', +65492=>'L', +65493=>'L', +65494=>'L', +65495=>'L', +65498=>'L', +65499=>'L', +65500=>'L', +65504=>'ET', +65505=>'ET', +65506=>'ON', +65507=>'ON', +65508=>'ON', +65509=>'ET', +65510=>'ET', +65512=>'ON', +65513=>'ON', +65514=>'ON', +65515=>'ON', +65516=>'ON', +65517=>'ON', +65518=>'ON', +65529=>'ON', +65530=>'ON', +65531=>'ON', +65532=>'ON', +65533=>'ON', +65536=>'L', +65537=>'L', +65538=>'L', +65539=>'L', +65540=>'L', +65541=>'L', +65542=>'L', +65543=>'L', +65544=>'L', +65545=>'L', +65546=>'L', +65547=>'L', +65549=>'L', +65550=>'L', +65551=>'L', +65552=>'L', +65553=>'L', +65554=>'L', +65555=>'L', +65556=>'L', +65557=>'L', +65558=>'L', +65559=>'L', +65560=>'L', +65561=>'L', +65562=>'L', +65563=>'L', +65564=>'L', +65565=>'L', +65566=>'L', +65567=>'L', +65568=>'L', +65569=>'L', +65570=>'L', +65571=>'L', +65572=>'L', +65573=>'L', +65574=>'L', +65576=>'L', +65577=>'L', +65578=>'L', +65579=>'L', +65580=>'L', +65581=>'L', +65582=>'L', +65583=>'L', +65584=>'L', +65585=>'L', +65586=>'L', +65587=>'L', +65588=>'L', +65589=>'L', +65590=>'L', +65591=>'L', +65592=>'L', +65593=>'L', +65594=>'L', +65596=>'L', +65597=>'L', +65599=>'L', +65600=>'L', +65601=>'L', +65602=>'L', +65603=>'L', +65604=>'L', +65605=>'L', +65606=>'L', +65607=>'L', +65608=>'L', +65609=>'L', +65610=>'L', +65611=>'L', +65612=>'L', +65613=>'L', +65616=>'L', +65617=>'L', +65618=>'L', +65619=>'L', +65620=>'L', +65621=>'L', +65622=>'L', +65623=>'L', +65624=>'L', +65625=>'L', +65626=>'L', +65627=>'L', +65628=>'L', +65629=>'L', +65664=>'L', +65665=>'L', +65666=>'L', +65667=>'L', +65668=>'L', +65669=>'L', +65670=>'L', +65671=>'L', +65672=>'L', +65673=>'L', +65674=>'L', +65675=>'L', +65676=>'L', +65677=>'L', +65678=>'L', +65679=>'L', +65680=>'L', +65681=>'L', +65682=>'L', +65683=>'L', +65684=>'L', +65685=>'L', +65686=>'L', +65687=>'L', +65688=>'L', +65689=>'L', +65690=>'L', +65691=>'L', +65692=>'L', +65693=>'L', +65694=>'L', +65695=>'L', +65696=>'L', +65697=>'L', +65698=>'L', +65699=>'L', +65700=>'L', +65701=>'L', +65702=>'L', +65703=>'L', +65704=>'L', +65705=>'L', +65706=>'L', +65707=>'L', +65708=>'L', +65709=>'L', +65710=>'L', +65711=>'L', +65712=>'L', +65713=>'L', +65714=>'L', +65715=>'L', +65716=>'L', +65717=>'L', +65718=>'L', +65719=>'L', +65720=>'L', +65721=>'L', +65722=>'L', +65723=>'L', +65724=>'L', +65725=>'L', +65726=>'L', +65727=>'L', +65728=>'L', +65729=>'L', +65730=>'L', +65731=>'L', +65732=>'L', +65733=>'L', +65734=>'L', +65735=>'L', +65736=>'L', +65737=>'L', +65738=>'L', +65739=>'L', +65740=>'L', +65741=>'L', +65742=>'L', +65743=>'L', +65744=>'L', +65745=>'L', +65746=>'L', +65747=>'L', +65748=>'L', +65749=>'L', +65750=>'L', +65751=>'L', +65752=>'L', +65753=>'L', +65754=>'L', +65755=>'L', +65756=>'L', +65757=>'L', +65758=>'L', +65759=>'L', +65760=>'L', +65761=>'L', +65762=>'L', +65763=>'L', +65764=>'L', +65765=>'L', +65766=>'L', +65767=>'L', +65768=>'L', +65769=>'L', +65770=>'L', +65771=>'L', +65772=>'L', +65773=>'L', +65774=>'L', +65775=>'L', +65776=>'L', +65777=>'L', +65778=>'L', +65779=>'L', +65780=>'L', +65781=>'L', +65782=>'L', +65783=>'L', +65784=>'L', +65785=>'L', +65786=>'L', +65792=>'L', +65793=>'ON', +65794=>'L', +65799=>'L', +65800=>'L', +65801=>'L', +65802=>'L', +65803=>'L', +65804=>'L', +65805=>'L', +65806=>'L', +65807=>'L', +65808=>'L', +65809=>'L', +65810=>'L', +65811=>'L', +65812=>'L', +65813=>'L', +65814=>'L', +65815=>'L', +65816=>'L', +65817=>'L', +65818=>'L', +65819=>'L', +65820=>'L', +65821=>'L', +65822=>'L', +65823=>'L', +65824=>'L', +65825=>'L', +65826=>'L', +65827=>'L', +65828=>'L', +65829=>'L', +65830=>'L', +65831=>'L', +65832=>'L', +65833=>'L', +65834=>'L', +65835=>'L', +65836=>'L', +65837=>'L', +65838=>'L', +65839=>'L', +65840=>'L', +65841=>'L', +65842=>'L', +65843=>'L', +65847=>'L', +65848=>'L', +65849=>'L', +65850=>'L', +65851=>'L', +65852=>'L', +65853=>'L', +65854=>'L', +65855=>'L', +65856=>'ON', +65857=>'ON', +65858=>'ON', +65859=>'ON', +65860=>'ON', +65861=>'ON', +65862=>'ON', +65863=>'ON', +65864=>'ON', +65865=>'ON', +65866=>'ON', +65867=>'ON', +65868=>'ON', +65869=>'ON', +65870=>'ON', +65871=>'ON', +65872=>'ON', +65873=>'ON', +65874=>'ON', +65875=>'ON', +65876=>'ON', +65877=>'ON', +65878=>'ON', +65879=>'ON', +65880=>'ON', +65881=>'ON', +65882=>'ON', +65883=>'ON', +65884=>'ON', +65885=>'ON', +65886=>'ON', +65887=>'ON', +65888=>'ON', +65889=>'ON', +65890=>'ON', +65891=>'ON', +65892=>'ON', +65893=>'ON', +65894=>'ON', +65895=>'ON', +65896=>'ON', +65897=>'ON', +65898=>'ON', +65899=>'ON', +65900=>'ON', +65901=>'ON', +65902=>'ON', +65903=>'ON', +65904=>'ON', +65905=>'ON', +65906=>'ON', +65907=>'ON', +65908=>'ON', +65909=>'ON', +65910=>'ON', +65911=>'ON', +65912=>'ON', +65913=>'ON', +65914=>'ON', +65915=>'ON', +65916=>'ON', +65917=>'ON', +65918=>'ON', +65919=>'ON', +65920=>'ON', +65921=>'ON', +65922=>'ON', +65923=>'ON', +65924=>'ON', +65925=>'ON', +65926=>'ON', +65927=>'ON', +65928=>'ON', +65929=>'ON', +65930=>'ON', +66304=>'L', +66305=>'L', +66306=>'L', +66307=>'L', +66308=>'L', +66309=>'L', +66310=>'L', +66311=>'L', +66312=>'L', +66313=>'L', +66314=>'L', +66315=>'L', +66316=>'L', +66317=>'L', +66318=>'L', +66319=>'L', +66320=>'L', +66321=>'L', +66322=>'L', +66323=>'L', +66324=>'L', +66325=>'L', +66326=>'L', +66327=>'L', +66328=>'L', +66329=>'L', +66330=>'L', +66331=>'L', +66332=>'L', +66333=>'L', +66334=>'L', +66336=>'L', +66337=>'L', +66338=>'L', +66339=>'L', +66352=>'L', +66353=>'L', +66354=>'L', +66355=>'L', +66356=>'L', +66357=>'L', +66358=>'L', +66359=>'L', +66360=>'L', +66361=>'L', +66362=>'L', +66363=>'L', +66364=>'L', +66365=>'L', +66366=>'L', +66367=>'L', +66368=>'L', +66369=>'L', +66370=>'L', +66371=>'L', +66372=>'L', +66373=>'L', +66374=>'L', +66375=>'L', +66376=>'L', +66377=>'L', +66378=>'L', +66432=>'L', +66433=>'L', +66434=>'L', +66435=>'L', +66436=>'L', +66437=>'L', +66438=>'L', +66439=>'L', +66440=>'L', +66441=>'L', +66442=>'L', +66443=>'L', +66444=>'L', +66445=>'L', +66446=>'L', +66447=>'L', +66448=>'L', +66449=>'L', +66450=>'L', +66451=>'L', +66452=>'L', +66453=>'L', +66454=>'L', +66455=>'L', +66456=>'L', +66457=>'L', +66458=>'L', +66459=>'L', +66460=>'L', +66461=>'L', +66463=>'L', +66464=>'L', +66465=>'L', +66466=>'L', +66467=>'L', +66468=>'L', +66469=>'L', +66470=>'L', +66471=>'L', +66472=>'L', +66473=>'L', +66474=>'L', +66475=>'L', +66476=>'L', +66477=>'L', +66478=>'L', +66479=>'L', +66480=>'L', +66481=>'L', +66482=>'L', +66483=>'L', +66484=>'L', +66485=>'L', +66486=>'L', +66487=>'L', +66488=>'L', +66489=>'L', +66490=>'L', +66491=>'L', +66492=>'L', +66493=>'L', +66494=>'L', +66495=>'L', +66496=>'L', +66497=>'L', +66498=>'L', +66499=>'L', +66504=>'L', +66505=>'L', +66506=>'L', +66507=>'L', +66508=>'L', +66509=>'L', +66510=>'L', +66511=>'L', +66512=>'L', +66513=>'L', +66514=>'L', +66515=>'L', +66516=>'L', +66517=>'L', +66560=>'L', +66561=>'L', +66562=>'L', +66563=>'L', +66564=>'L', +66565=>'L', +66566=>'L', +66567=>'L', +66568=>'L', +66569=>'L', +66570=>'L', +66571=>'L', +66572=>'L', +66573=>'L', +66574=>'L', +66575=>'L', +66576=>'L', +66577=>'L', +66578=>'L', +66579=>'L', +66580=>'L', +66581=>'L', +66582=>'L', +66583=>'L', +66584=>'L', +66585=>'L', +66586=>'L', +66587=>'L', +66588=>'L', +66589=>'L', +66590=>'L', +66591=>'L', +66592=>'L', +66593=>'L', +66594=>'L', +66595=>'L', +66596=>'L', +66597=>'L', +66598=>'L', +66599=>'L', +66600=>'L', +66601=>'L', +66602=>'L', +66603=>'L', +66604=>'L', +66605=>'L', +66606=>'L', +66607=>'L', +66608=>'L', +66609=>'L', +66610=>'L', +66611=>'L', +66612=>'L', +66613=>'L', +66614=>'L', +66615=>'L', +66616=>'L', +66617=>'L', +66618=>'L', +66619=>'L', +66620=>'L', +66621=>'L', +66622=>'L', +66623=>'L', +66624=>'L', +66625=>'L', +66626=>'L', +66627=>'L', +66628=>'L', +66629=>'L', +66630=>'L', +66631=>'L', +66632=>'L', +66633=>'L', +66634=>'L', +66635=>'L', +66636=>'L', +66637=>'L', +66638=>'L', +66639=>'L', +66640=>'L', +66641=>'L', +66642=>'L', +66643=>'L', +66644=>'L', +66645=>'L', +66646=>'L', +66647=>'L', +66648=>'L', +66649=>'L', +66650=>'L', +66651=>'L', +66652=>'L', +66653=>'L', +66654=>'L', +66655=>'L', +66656=>'L', +66657=>'L', +66658=>'L', +66659=>'L', +66660=>'L', +66661=>'L', +66662=>'L', +66663=>'L', +66664=>'L', +66665=>'L', +66666=>'L', +66667=>'L', +66668=>'L', +66669=>'L', +66670=>'L', +66671=>'L', +66672=>'L', +66673=>'L', +66674=>'L', +66675=>'L', +66676=>'L', +66677=>'L', +66678=>'L', +66679=>'L', +66680=>'L', +66681=>'L', +66682=>'L', +66683=>'L', +66684=>'L', +66685=>'L', +66686=>'L', +66687=>'L', +66688=>'L', +66689=>'L', +66690=>'L', +66691=>'L', +66692=>'L', +66693=>'L', +66694=>'L', +66695=>'L', +66696=>'L', +66697=>'L', +66698=>'L', +66699=>'L', +66700=>'L', +66701=>'L', +66702=>'L', +66703=>'L', +66704=>'L', +66705=>'L', +66706=>'L', +66707=>'L', +66708=>'L', +66709=>'L', +66710=>'L', +66711=>'L', +66712=>'L', +66713=>'L', +66714=>'L', +66715=>'L', +66716=>'L', +66717=>'L', +66720=>'L', +66721=>'L', +66722=>'L', +66723=>'L', +66724=>'L', +66725=>'L', +66726=>'L', +66727=>'L', +66728=>'L', +66729=>'L', +67584=>'R', +67585=>'R', +67586=>'R', +67587=>'R', +67588=>'R', +67589=>'R', +67592=>'R', +67594=>'R', +67595=>'R', +67596=>'R', +67597=>'R', +67598=>'R', +67599=>'R', +67600=>'R', +67601=>'R', +67602=>'R', +67603=>'R', +67604=>'R', +67605=>'R', +67606=>'R', +67607=>'R', +67608=>'R', +67609=>'R', +67610=>'R', +67611=>'R', +67612=>'R', +67613=>'R', +67614=>'R', +67615=>'R', +67616=>'R', +67617=>'R', +67618=>'R', +67619=>'R', +67620=>'R', +67621=>'R', +67622=>'R', +67623=>'R', +67624=>'R', +67625=>'R', +67626=>'R', +67627=>'R', +67628=>'R', +67629=>'R', +67630=>'R', +67631=>'R', +67632=>'R', +67633=>'R', +67634=>'R', +67635=>'R', +67636=>'R', +67637=>'R', +67639=>'R', +67640=>'R', +67644=>'R', +67647=>'R', +67840=>'R', +67841=>'R', +67842=>'R', +67843=>'R', +67844=>'R', +67845=>'R', +67846=>'R', +67847=>'R', +67848=>'R', +67849=>'R', +67850=>'R', +67851=>'R', +67852=>'R', +67853=>'R', +67854=>'R', +67855=>'R', +67856=>'R', +67857=>'R', +67858=>'R', +67859=>'R', +67860=>'R', +67861=>'R', +67862=>'R', +67863=>'R', +67864=>'R', +67865=>'R', +67871=>'ON', +68096=>'R', +68097=>'NSM', +68098=>'NSM', +68099=>'NSM', +68101=>'NSM', +68102=>'NSM', +68108=>'NSM', +68109=>'NSM', +68110=>'NSM', +68111=>'NSM', +68112=>'R', +68113=>'R', +68114=>'R', +68115=>'R', +68117=>'R', +68118=>'R', +68119=>'R', +68121=>'R', +68122=>'R', +68123=>'R', +68124=>'R', +68125=>'R', +68126=>'R', +68127=>'R', +68128=>'R', +68129=>'R', +68130=>'R', +68131=>'R', +68132=>'R', +68133=>'R', +68134=>'R', +68135=>'R', +68136=>'R', +68137=>'R', +68138=>'R', +68139=>'R', +68140=>'R', +68141=>'R', +68142=>'R', +68143=>'R', +68144=>'R', +68145=>'R', +68146=>'R', +68147=>'R', +68152=>'NSM', +68153=>'NSM', +68154=>'NSM', +68159=>'NSM', +68160=>'R', +68161=>'R', +68162=>'R', +68163=>'R', +68164=>'R', +68165=>'R', +68166=>'R', +68167=>'R', +68176=>'R', +68177=>'R', +68178=>'R', +68179=>'R', +68180=>'R', +68181=>'R', +68182=>'R', +68183=>'R', +68184=>'R', +73728=>'L', +73729=>'L', +73730=>'L', +73731=>'L', +73732=>'L', +73733=>'L', +73734=>'L', +73735=>'L', +73736=>'L', +73737=>'L', +73738=>'L', +73739=>'L', +73740=>'L', +73741=>'L', +73742=>'L', +73743=>'L', +73744=>'L', +73745=>'L', +73746=>'L', +73747=>'L', +73748=>'L', +73749=>'L', +73750=>'L', +73751=>'L', +73752=>'L', +73753=>'L', +73754=>'L', +73755=>'L', +73756=>'L', +73757=>'L', +73758=>'L', +73759=>'L', +73760=>'L', +73761=>'L', +73762=>'L', +73763=>'L', +73764=>'L', +73765=>'L', +73766=>'L', +73767=>'L', +73768=>'L', +73769=>'L', +73770=>'L', +73771=>'L', +73772=>'L', +73773=>'L', +73774=>'L', +73775=>'L', +73776=>'L', +73777=>'L', +73778=>'L', +73779=>'L', +73780=>'L', +73781=>'L', +73782=>'L', +73783=>'L', +73784=>'L', +73785=>'L', +73786=>'L', +73787=>'L', +73788=>'L', +73789=>'L', +73790=>'L', +73791=>'L', +73792=>'L', +73793=>'L', +73794=>'L', +73795=>'L', +73796=>'L', +73797=>'L', +73798=>'L', +73799=>'L', +73800=>'L', +73801=>'L', +73802=>'L', +73803=>'L', +73804=>'L', +73805=>'L', +73806=>'L', +73807=>'L', +73808=>'L', +73809=>'L', +73810=>'L', +73811=>'L', +73812=>'L', +73813=>'L', +73814=>'L', +73815=>'L', +73816=>'L', +73817=>'L', +73818=>'L', +73819=>'L', +73820=>'L', +73821=>'L', +73822=>'L', +73823=>'L', +73824=>'L', +73825=>'L', +73826=>'L', +73827=>'L', +73828=>'L', +73829=>'L', +73830=>'L', +73831=>'L', +73832=>'L', +73833=>'L', +73834=>'L', +73835=>'L', +73836=>'L', +73837=>'L', +73838=>'L', +73839=>'L', +73840=>'L', +73841=>'L', +73842=>'L', +73843=>'L', +73844=>'L', +73845=>'L', +73846=>'L', +73847=>'L', +73848=>'L', +73849=>'L', +73850=>'L', +73851=>'L', +73852=>'L', +73853=>'L', +73854=>'L', +73855=>'L', +73856=>'L', +73857=>'L', +73858=>'L', +73859=>'L', +73860=>'L', +73861=>'L', +73862=>'L', +73863=>'L', +73864=>'L', +73865=>'L', +73866=>'L', +73867=>'L', +73868=>'L', +73869=>'L', +73870=>'L', +73871=>'L', +73872=>'L', +73873=>'L', +73874=>'L', +73875=>'L', +73876=>'L', +73877=>'L', +73878=>'L', +73879=>'L', +73880=>'L', +73881=>'L', +73882=>'L', +73883=>'L', +73884=>'L', +73885=>'L', +73886=>'L', +73887=>'L', +73888=>'L', +73889=>'L', +73890=>'L', +73891=>'L', +73892=>'L', +73893=>'L', +73894=>'L', +73895=>'L', +73896=>'L', +73897=>'L', +73898=>'L', +73899=>'L', +73900=>'L', +73901=>'L', +73902=>'L', +73903=>'L', +73904=>'L', +73905=>'L', +73906=>'L', +73907=>'L', +73908=>'L', +73909=>'L', +73910=>'L', +73911=>'L', +73912=>'L', +73913=>'L', +73914=>'L', +73915=>'L', +73916=>'L', +73917=>'L', +73918=>'L', +73919=>'L', +73920=>'L', +73921=>'L', +73922=>'L', +73923=>'L', +73924=>'L', +73925=>'L', +73926=>'L', +73927=>'L', +73928=>'L', +73929=>'L', +73930=>'L', +73931=>'L', +73932=>'L', +73933=>'L', +73934=>'L', +73935=>'L', +73936=>'L', +73937=>'L', +73938=>'L', +73939=>'L', +73940=>'L', +73941=>'L', +73942=>'L', +73943=>'L', +73944=>'L', +73945=>'L', +73946=>'L', +73947=>'L', +73948=>'L', +73949=>'L', +73950=>'L', +73951=>'L', +73952=>'L', +73953=>'L', +73954=>'L', +73955=>'L', +73956=>'L', +73957=>'L', +73958=>'L', +73959=>'L', +73960=>'L', +73961=>'L', +73962=>'L', +73963=>'L', +73964=>'L', +73965=>'L', +73966=>'L', +73967=>'L', +73968=>'L', +73969=>'L', +73970=>'L', +73971=>'L', +73972=>'L', +73973=>'L', +73974=>'L', +73975=>'L', +73976=>'L', +73977=>'L', +73978=>'L', +73979=>'L', +73980=>'L', +73981=>'L', +73982=>'L', +73983=>'L', +73984=>'L', +73985=>'L', +73986=>'L', +73987=>'L', +73988=>'L', +73989=>'L', +73990=>'L', +73991=>'L', +73992=>'L', +73993=>'L', +73994=>'L', +73995=>'L', +73996=>'L', +73997=>'L', +73998=>'L', +73999=>'L', +74000=>'L', +74001=>'L', +74002=>'L', +74003=>'L', +74004=>'L', +74005=>'L', +74006=>'L', +74007=>'L', +74008=>'L', +74009=>'L', +74010=>'L', +74011=>'L', +74012=>'L', +74013=>'L', +74014=>'L', +74015=>'L', +74016=>'L', +74017=>'L', +74018=>'L', +74019=>'L', +74020=>'L', +74021=>'L', +74022=>'L', +74023=>'L', +74024=>'L', +74025=>'L', +74026=>'L', +74027=>'L', +74028=>'L', +74029=>'L', +74030=>'L', +74031=>'L', +74032=>'L', +74033=>'L', +74034=>'L', +74035=>'L', +74036=>'L', +74037=>'L', +74038=>'L', +74039=>'L', +74040=>'L', +74041=>'L', +74042=>'L', +74043=>'L', +74044=>'L', +74045=>'L', +74046=>'L', +74047=>'L', +74048=>'L', +74049=>'L', +74050=>'L', +74051=>'L', +74052=>'L', +74053=>'L', +74054=>'L', +74055=>'L', +74056=>'L', +74057=>'L', +74058=>'L', +74059=>'L', +74060=>'L', +74061=>'L', +74062=>'L', +74063=>'L', +74064=>'L', +74065=>'L', +74066=>'L', +74067=>'L', +74068=>'L', +74069=>'L', +74070=>'L', +74071=>'L', +74072=>'L', +74073=>'L', +74074=>'L', +74075=>'L', +74076=>'L', +74077=>'L', +74078=>'L', +74079=>'L', +74080=>'L', +74081=>'L', +74082=>'L', +74083=>'L', +74084=>'L', +74085=>'L', +74086=>'L', +74087=>'L', +74088=>'L', +74089=>'L', +74090=>'L', +74091=>'L', +74092=>'L', +74093=>'L', +74094=>'L', +74095=>'L', +74096=>'L', +74097=>'L', +74098=>'L', +74099=>'L', +74100=>'L', +74101=>'L', +74102=>'L', +74103=>'L', +74104=>'L', +74105=>'L', +74106=>'L', +74107=>'L', +74108=>'L', +74109=>'L', +74110=>'L', +74111=>'L', +74112=>'L', +74113=>'L', +74114=>'L', +74115=>'L', +74116=>'L', +74117=>'L', +74118=>'L', +74119=>'L', +74120=>'L', +74121=>'L', +74122=>'L', +74123=>'L', +74124=>'L', +74125=>'L', +74126=>'L', +74127=>'L', +74128=>'L', +74129=>'L', +74130=>'L', +74131=>'L', +74132=>'L', +74133=>'L', +74134=>'L', +74135=>'L', +74136=>'L', +74137=>'L', +74138=>'L', +74139=>'L', +74140=>'L', +74141=>'L', +74142=>'L', +74143=>'L', +74144=>'L', +74145=>'L', +74146=>'L', +74147=>'L', +74148=>'L', +74149=>'L', +74150=>'L', +74151=>'L', +74152=>'L', +74153=>'L', +74154=>'L', +74155=>'L', +74156=>'L', +74157=>'L', +74158=>'L', +74159=>'L', +74160=>'L', +74161=>'L', +74162=>'L', +74163=>'L', +74164=>'L', +74165=>'L', +74166=>'L', +74167=>'L', +74168=>'L', +74169=>'L', +74170=>'L', +74171=>'L', +74172=>'L', +74173=>'L', +74174=>'L', +74175=>'L', +74176=>'L', +74177=>'L', +74178=>'L', +74179=>'L', +74180=>'L', +74181=>'L', +74182=>'L', +74183=>'L', +74184=>'L', +74185=>'L', +74186=>'L', +74187=>'L', +74188=>'L', +74189=>'L', +74190=>'L', +74191=>'L', +74192=>'L', +74193=>'L', +74194=>'L', +74195=>'L', +74196=>'L', +74197=>'L', +74198=>'L', +74199=>'L', +74200=>'L', +74201=>'L', +74202=>'L', +74203=>'L', +74204=>'L', +74205=>'L', +74206=>'L', +74207=>'L', +74208=>'L', +74209=>'L', +74210=>'L', +74211=>'L', +74212=>'L', +74213=>'L', +74214=>'L', +74215=>'L', +74216=>'L', +74217=>'L', +74218=>'L', +74219=>'L', +74220=>'L', +74221=>'L', +74222=>'L', +74223=>'L', +74224=>'L', +74225=>'L', +74226=>'L', +74227=>'L', +74228=>'L', +74229=>'L', +74230=>'L', +74231=>'L', +74232=>'L', +74233=>'L', +74234=>'L', +74235=>'L', +74236=>'L', +74237=>'L', +74238=>'L', +74239=>'L', +74240=>'L', +74241=>'L', +74242=>'L', +74243=>'L', +74244=>'L', +74245=>'L', +74246=>'L', +74247=>'L', +74248=>'L', +74249=>'L', +74250=>'L', +74251=>'L', +74252=>'L', +74253=>'L', +74254=>'L', +74255=>'L', +74256=>'L', +74257=>'L', +74258=>'L', +74259=>'L', +74260=>'L', +74261=>'L', +74262=>'L', +74263=>'L', +74264=>'L', +74265=>'L', +74266=>'L', +74267=>'L', +74268=>'L', +74269=>'L', +74270=>'L', +74271=>'L', +74272=>'L', +74273=>'L', +74274=>'L', +74275=>'L', +74276=>'L', +74277=>'L', +74278=>'L', +74279=>'L', +74280=>'L', +74281=>'L', +74282=>'L', +74283=>'L', +74284=>'L', +74285=>'L', +74286=>'L', +74287=>'L', +74288=>'L', +74289=>'L', +74290=>'L', +74291=>'L', +74292=>'L', +74293=>'L', +74294=>'L', +74295=>'L', +74296=>'L', +74297=>'L', +74298=>'L', +74299=>'L', +74300=>'L', +74301=>'L', +74302=>'L', +74303=>'L', +74304=>'L', +74305=>'L', +74306=>'L', +74307=>'L', +74308=>'L', +74309=>'L', +74310=>'L', +74311=>'L', +74312=>'L', +74313=>'L', +74314=>'L', +74315=>'L', +74316=>'L', +74317=>'L', +74318=>'L', +74319=>'L', +74320=>'L', +74321=>'L', +74322=>'L', +74323=>'L', +74324=>'L', +74325=>'L', +74326=>'L', +74327=>'L', +74328=>'L', +74329=>'L', +74330=>'L', +74331=>'L', +74332=>'L', +74333=>'L', +74334=>'L', +74335=>'L', +74336=>'L', +74337=>'L', +74338=>'L', +74339=>'L', +74340=>'L', +74341=>'L', +74342=>'L', +74343=>'L', +74344=>'L', +74345=>'L', +74346=>'L', +74347=>'L', +74348=>'L', +74349=>'L', +74350=>'L', +74351=>'L', +74352=>'L', +74353=>'L', +74354=>'L', +74355=>'L', +74356=>'L', +74357=>'L', +74358=>'L', +74359=>'L', +74360=>'L', +74361=>'L', +74362=>'L', +74363=>'L', +74364=>'L', +74365=>'L', +74366=>'L', +74367=>'L', +74368=>'L', +74369=>'L', +74370=>'L', +74371=>'L', +74372=>'L', +74373=>'L', +74374=>'L', +74375=>'L', +74376=>'L', +74377=>'L', +74378=>'L', +74379=>'L', +74380=>'L', +74381=>'L', +74382=>'L', +74383=>'L', +74384=>'L', +74385=>'L', +74386=>'L', +74387=>'L', +74388=>'L', +74389=>'L', +74390=>'L', +74391=>'L', +74392=>'L', +74393=>'L', +74394=>'L', +74395=>'L', +74396=>'L', +74397=>'L', +74398=>'L', +74399=>'L', +74400=>'L', +74401=>'L', +74402=>'L', +74403=>'L', +74404=>'L', +74405=>'L', +74406=>'L', +74407=>'L', +74408=>'L', +74409=>'L', +74410=>'L', +74411=>'L', +74412=>'L', +74413=>'L', +74414=>'L', +74415=>'L', +74416=>'L', +74417=>'L', +74418=>'L', +74419=>'L', +74420=>'L', +74421=>'L', +74422=>'L', +74423=>'L', +74424=>'L', +74425=>'L', +74426=>'L', +74427=>'L', +74428=>'L', +74429=>'L', +74430=>'L', +74431=>'L', +74432=>'L', +74433=>'L', +74434=>'L', +74435=>'L', +74436=>'L', +74437=>'L', +74438=>'L', +74439=>'L', +74440=>'L', +74441=>'L', +74442=>'L', +74443=>'L', +74444=>'L', +74445=>'L', +74446=>'L', +74447=>'L', +74448=>'L', +74449=>'L', +74450=>'L', +74451=>'L', +74452=>'L', +74453=>'L', +74454=>'L', +74455=>'L', +74456=>'L', +74457=>'L', +74458=>'L', +74459=>'L', +74460=>'L', +74461=>'L', +74462=>'L', +74463=>'L', +74464=>'L', +74465=>'L', +74466=>'L', +74467=>'L', +74468=>'L', +74469=>'L', +74470=>'L', +74471=>'L', +74472=>'L', +74473=>'L', +74474=>'L', +74475=>'L', +74476=>'L', +74477=>'L', +74478=>'L', +74479=>'L', +74480=>'L', +74481=>'L', +74482=>'L', +74483=>'L', +74484=>'L', +74485=>'L', +74486=>'L', +74487=>'L', +74488=>'L', +74489=>'L', +74490=>'L', +74491=>'L', +74492=>'L', +74493=>'L', +74494=>'L', +74495=>'L', +74496=>'L', +74497=>'L', +74498=>'L', +74499=>'L', +74500=>'L', +74501=>'L', +74502=>'L', +74503=>'L', +74504=>'L', +74505=>'L', +74506=>'L', +74507=>'L', +74508=>'L', +74509=>'L', +74510=>'L', +74511=>'L', +74512=>'L', +74513=>'L', +74514=>'L', +74515=>'L', +74516=>'L', +74517=>'L', +74518=>'L', +74519=>'L', +74520=>'L', +74521=>'L', +74522=>'L', +74523=>'L', +74524=>'L', +74525=>'L', +74526=>'L', +74527=>'L', +74528=>'L', +74529=>'L', +74530=>'L', +74531=>'L', +74532=>'L', +74533=>'L', +74534=>'L', +74535=>'L', +74536=>'L', +74537=>'L', +74538=>'L', +74539=>'L', +74540=>'L', +74541=>'L', +74542=>'L', +74543=>'L', +74544=>'L', +74545=>'L', +74546=>'L', +74547=>'L', +74548=>'L', +74549=>'L', +74550=>'L', +74551=>'L', +74552=>'L', +74553=>'L', +74554=>'L', +74555=>'L', +74556=>'L', +74557=>'L', +74558=>'L', +74559=>'L', +74560=>'L', +74561=>'L', +74562=>'L', +74563=>'L', +74564=>'L', +74565=>'L', +74566=>'L', +74567=>'L', +74568=>'L', +74569=>'L', +74570=>'L', +74571=>'L', +74572=>'L', +74573=>'L', +74574=>'L', +74575=>'L', +74576=>'L', +74577=>'L', +74578=>'L', +74579=>'L', +74580=>'L', +74581=>'L', +74582=>'L', +74583=>'L', +74584=>'L', +74585=>'L', +74586=>'L', +74587=>'L', +74588=>'L', +74589=>'L', +74590=>'L', +74591=>'L', +74592=>'L', +74593=>'L', +74594=>'L', +74595=>'L', +74596=>'L', +74597=>'L', +74598=>'L', +74599=>'L', +74600=>'L', +74601=>'L', +74602=>'L', +74603=>'L', +74604=>'L', +74605=>'L', +74606=>'L', +74752=>'L', +74753=>'L', +74754=>'L', +74755=>'L', +74756=>'L', +74757=>'L', +74758=>'L', +74759=>'L', +74760=>'L', +74761=>'L', +74762=>'L', +74763=>'L', +74764=>'L', +74765=>'L', +74766=>'L', +74767=>'L', +74768=>'L', +74769=>'L', +74770=>'L', +74771=>'L', +74772=>'L', +74773=>'L', +74774=>'L', +74775=>'L', +74776=>'L', +74777=>'L', +74778=>'L', +74779=>'L', +74780=>'L', +74781=>'L', +74782=>'L', +74783=>'L', +74784=>'L', +74785=>'L', +74786=>'L', +74787=>'L', +74788=>'L', +74789=>'L', +74790=>'L', +74791=>'L', +74792=>'L', +74793=>'L', +74794=>'L', +74795=>'L', +74796=>'L', +74797=>'L', +74798=>'L', +74799=>'L', +74800=>'L', +74801=>'L', +74802=>'L', +74803=>'L', +74804=>'L', +74805=>'L', +74806=>'L', +74807=>'L', +74808=>'L', +74809=>'L', +74810=>'L', +74811=>'L', +74812=>'L', +74813=>'L', +74814=>'L', +74815=>'L', +74816=>'L', +74817=>'L', +74818=>'L', +74819=>'L', +74820=>'L', +74821=>'L', +74822=>'L', +74823=>'L', +74824=>'L', +74825=>'L', +74826=>'L', +74827=>'L', +74828=>'L', +74829=>'L', +74830=>'L', +74831=>'L', +74832=>'L', +74833=>'L', +74834=>'L', +74835=>'L', +74836=>'L', +74837=>'L', +74838=>'L', +74839=>'L', +74840=>'L', +74841=>'L', +74842=>'L', +74843=>'L', +74844=>'L', +74845=>'L', +74846=>'L', +74847=>'L', +74848=>'L', +74849=>'L', +74850=>'L', +74864=>'L', +74865=>'L', +74866=>'L', +74867=>'L', +118784=>'L', +118785=>'L', +118786=>'L', +118787=>'L', +118788=>'L', +118789=>'L', +118790=>'L', +118791=>'L', +118792=>'L', +118793=>'L', +118794=>'L', +118795=>'L', +118796=>'L', +118797=>'L', +118798=>'L', +118799=>'L', +118800=>'L', +118801=>'L', +118802=>'L', +118803=>'L', +118804=>'L', +118805=>'L', +118806=>'L', +118807=>'L', +118808=>'L', +118809=>'L', +118810=>'L', +118811=>'L', +118812=>'L', +118813=>'L', +118814=>'L', +118815=>'L', +118816=>'L', +118817=>'L', +118818=>'L', +118819=>'L', +118820=>'L', +118821=>'L', +118822=>'L', +118823=>'L', +118824=>'L', +118825=>'L', +118826=>'L', +118827=>'L', +118828=>'L', +118829=>'L', +118830=>'L', +118831=>'L', +118832=>'L', +118833=>'L', +118834=>'L', +118835=>'L', +118836=>'L', +118837=>'L', +118838=>'L', +118839=>'L', +118840=>'L', +118841=>'L', +118842=>'L', +118843=>'L', +118844=>'L', +118845=>'L', +118846=>'L', +118847=>'L', +118848=>'L', +118849=>'L', +118850=>'L', +118851=>'L', +118852=>'L', +118853=>'L', +118854=>'L', +118855=>'L', +118856=>'L', +118857=>'L', +118858=>'L', +118859=>'L', +118860=>'L', +118861=>'L', +118862=>'L', +118863=>'L', +118864=>'L', +118865=>'L', +118866=>'L', +118867=>'L', +118868=>'L', +118869=>'L', +118870=>'L', +118871=>'L', +118872=>'L', +118873=>'L', +118874=>'L', +118875=>'L', +118876=>'L', +118877=>'L', +118878=>'L', +118879=>'L', +118880=>'L', +118881=>'L', +118882=>'L', +118883=>'L', +118884=>'L', +118885=>'L', +118886=>'L', +118887=>'L', +118888=>'L', +118889=>'L', +118890=>'L', +118891=>'L', +118892=>'L', +118893=>'L', +118894=>'L', +118895=>'L', +118896=>'L', +118897=>'L', +118898=>'L', +118899=>'L', +118900=>'L', +118901=>'L', +118902=>'L', +118903=>'L', +118904=>'L', +118905=>'L', +118906=>'L', +118907=>'L', +118908=>'L', +118909=>'L', +118910=>'L', +118911=>'L', +118912=>'L', +118913=>'L', +118914=>'L', +118915=>'L', +118916=>'L', +118917=>'L', +118918=>'L', +118919=>'L', +118920=>'L', +118921=>'L', +118922=>'L', +118923=>'L', +118924=>'L', +118925=>'L', +118926=>'L', +118927=>'L', +118928=>'L', +118929=>'L', +118930=>'L', +118931=>'L', +118932=>'L', +118933=>'L', +118934=>'L', +118935=>'L', +118936=>'L', +118937=>'L', +118938=>'L', +118939=>'L', +118940=>'L', +118941=>'L', +118942=>'L', +118943=>'L', +118944=>'L', +118945=>'L', +118946=>'L', +118947=>'L', +118948=>'L', +118949=>'L', +118950=>'L', +118951=>'L', +118952=>'L', +118953=>'L', +118954=>'L', +118955=>'L', +118956=>'L', +118957=>'L', +118958=>'L', +118959=>'L', +118960=>'L', +118961=>'L', +118962=>'L', +118963=>'L', +118964=>'L', +118965=>'L', +118966=>'L', +118967=>'L', +118968=>'L', +118969=>'L', +118970=>'L', +118971=>'L', +118972=>'L', +118973=>'L', +118974=>'L', +118975=>'L', +118976=>'L', +118977=>'L', +118978=>'L', +118979=>'L', +118980=>'L', +118981=>'L', +118982=>'L', +118983=>'L', +118984=>'L', +118985=>'L', +118986=>'L', +118987=>'L', +118988=>'L', +118989=>'L', +118990=>'L', +118991=>'L', +118992=>'L', +118993=>'L', +118994=>'L', +118995=>'L', +118996=>'L', +118997=>'L', +118998=>'L', +118999=>'L', +119000=>'L', +119001=>'L', +119002=>'L', +119003=>'L', +119004=>'L', +119005=>'L', +119006=>'L', +119007=>'L', +119008=>'L', +119009=>'L', +119010=>'L', +119011=>'L', +119012=>'L', +119013=>'L', +119014=>'L', +119015=>'L', +119016=>'L', +119017=>'L', +119018=>'L', +119019=>'L', +119020=>'L', +119021=>'L', +119022=>'L', +119023=>'L', +119024=>'L', +119025=>'L', +119026=>'L', +119027=>'L', +119028=>'L', +119029=>'L', +119040=>'L', +119041=>'L', +119042=>'L', +119043=>'L', +119044=>'L', +119045=>'L', +119046=>'L', +119047=>'L', +119048=>'L', +119049=>'L', +119050=>'L', +119051=>'L', +119052=>'L', +119053=>'L', +119054=>'L', +119055=>'L', +119056=>'L', +119057=>'L', +119058=>'L', +119059=>'L', +119060=>'L', +119061=>'L', +119062=>'L', +119063=>'L', +119064=>'L', +119065=>'L', +119066=>'L', +119067=>'L', +119068=>'L', +119069=>'L', +119070=>'L', +119071=>'L', +119072=>'L', +119073=>'L', +119074=>'L', +119075=>'L', +119076=>'L', +119077=>'L', +119078=>'L', +119082=>'L', +119083=>'L', +119084=>'L', +119085=>'L', +119086=>'L', +119087=>'L', +119088=>'L', +119089=>'L', +119090=>'L', +119091=>'L', +119092=>'L', +119093=>'L', +119094=>'L', +119095=>'L', +119096=>'L', +119097=>'L', +119098=>'L', +119099=>'L', +119100=>'L', +119101=>'L', +119102=>'L', +119103=>'L', +119104=>'L', +119105=>'L', +119106=>'L', +119107=>'L', +119108=>'L', +119109=>'L', +119110=>'L', +119111=>'L', +119112=>'L', +119113=>'L', +119114=>'L', +119115=>'L', +119116=>'L', +119117=>'L', +119118=>'L', +119119=>'L', +119120=>'L', +119121=>'L', +119122=>'L', +119123=>'L', +119124=>'L', +119125=>'L', +119126=>'L', +119127=>'L', +119128=>'L', +119129=>'L', +119130=>'L', +119131=>'L', +119132=>'L', +119133=>'L', +119134=>'L', +119135=>'L', +119136=>'L', +119137=>'L', +119138=>'L', +119139=>'L', +119140=>'L', +119141=>'L', +119142=>'L', +119143=>'NSM', +119144=>'NSM', +119145=>'NSM', +119146=>'L', +119147=>'L', +119148=>'L', +119149=>'L', +119150=>'L', +119151=>'L', +119152=>'L', +119153=>'L', +119154=>'L', +119155=>'BN', +119156=>'BN', +119157=>'BN', +119158=>'BN', +119159=>'BN', +119160=>'BN', +119161=>'BN', +119162=>'BN', +119163=>'NSM', +119164=>'NSM', +119165=>'NSM', +119166=>'NSM', +119167=>'NSM', +119168=>'NSM', +119169=>'NSM', +119170=>'NSM', +119171=>'L', +119172=>'L', +119173=>'NSM', +119174=>'NSM', +119175=>'NSM', +119176=>'NSM', +119177=>'NSM', +119178=>'NSM', +119179=>'NSM', +119180=>'L', +119181=>'L', +119182=>'L', +119183=>'L', +119184=>'L', +119185=>'L', +119186=>'L', +119187=>'L', +119188=>'L', +119189=>'L', +119190=>'L', +119191=>'L', +119192=>'L', +119193=>'L', +119194=>'L', +119195=>'L', +119196=>'L', +119197=>'L', +119198=>'L', +119199=>'L', +119200=>'L', +119201=>'L', +119202=>'L', +119203=>'L', +119204=>'L', +119205=>'L', +119206=>'L', +119207=>'L', +119208=>'L', +119209=>'L', +119210=>'NSM', +119211=>'NSM', +119212=>'NSM', +119213=>'NSM', +119214=>'L', +119215=>'L', +119216=>'L', +119217=>'L', +119218=>'L', +119219=>'L', +119220=>'L', +119221=>'L', +119222=>'L', +119223=>'L', +119224=>'L', +119225=>'L', +119226=>'L', +119227=>'L', +119228=>'L', +119229=>'L', +119230=>'L', +119231=>'L', +119232=>'L', +119233=>'L', +119234=>'L', +119235=>'L', +119236=>'L', +119237=>'L', +119238=>'L', +119239=>'L', +119240=>'L', +119241=>'L', +119242=>'L', +119243=>'L', +119244=>'L', +119245=>'L', +119246=>'L', +119247=>'L', +119248=>'L', +119249=>'L', +119250=>'L', +119251=>'L', +119252=>'L', +119253=>'L', +119254=>'L', +119255=>'L', +119256=>'L', +119257=>'L', +119258=>'L', +119259=>'L', +119260=>'L', +119261=>'L', +119296=>'ON', +119297=>'ON', +119298=>'ON', +119299=>'ON', +119300=>'ON', +119301=>'ON', +119302=>'ON', +119303=>'ON', +119304=>'ON', +119305=>'ON', +119306=>'ON', +119307=>'ON', +119308=>'ON', +119309=>'ON', +119310=>'ON', +119311=>'ON', +119312=>'ON', +119313=>'ON', +119314=>'ON', +119315=>'ON', +119316=>'ON', +119317=>'ON', +119318=>'ON', +119319=>'ON', +119320=>'ON', +119321=>'ON', +119322=>'ON', +119323=>'ON', +119324=>'ON', +119325=>'ON', +119326=>'ON', +119327=>'ON', +119328=>'ON', +119329=>'ON', +119330=>'ON', +119331=>'ON', +119332=>'ON', +119333=>'ON', +119334=>'ON', +119335=>'ON', +119336=>'ON', +119337=>'ON', +119338=>'ON', +119339=>'ON', +119340=>'ON', +119341=>'ON', +119342=>'ON', +119343=>'ON', +119344=>'ON', +119345=>'ON', +119346=>'ON', +119347=>'ON', +119348=>'ON', +119349=>'ON', +119350=>'ON', +119351=>'ON', +119352=>'ON', +119353=>'ON', +119354=>'ON', +119355=>'ON', +119356=>'ON', +119357=>'ON', +119358=>'ON', +119359=>'ON', +119360=>'ON', +119361=>'ON', +119362=>'NSM', +119363=>'NSM', +119364=>'NSM', +119365=>'ON', +119552=>'ON', +119553=>'ON', +119554=>'ON', +119555=>'ON', +119556=>'ON', +119557=>'ON', +119558=>'ON', +119559=>'ON', +119560=>'ON', +119561=>'ON', +119562=>'ON', +119563=>'ON', +119564=>'ON', +119565=>'ON', +119566=>'ON', +119567=>'ON', +119568=>'ON', +119569=>'ON', +119570=>'ON', +119571=>'ON', +119572=>'ON', +119573=>'ON', +119574=>'ON', +119575=>'ON', +119576=>'ON', +119577=>'ON', +119578=>'ON', +119579=>'ON', +119580=>'ON', +119581=>'ON', +119582=>'ON', +119583=>'ON', +119584=>'ON', +119585=>'ON', +119586=>'ON', +119587=>'ON', +119588=>'ON', +119589=>'ON', +119590=>'ON', +119591=>'ON', +119592=>'ON', +119593=>'ON', +119594=>'ON', +119595=>'ON', +119596=>'ON', +119597=>'ON', +119598=>'ON', +119599=>'ON', +119600=>'ON', +119601=>'ON', +119602=>'ON', +119603=>'ON', +119604=>'ON', +119605=>'ON', +119606=>'ON', +119607=>'ON', +119608=>'ON', +119609=>'ON', +119610=>'ON', +119611=>'ON', +119612=>'ON', +119613=>'ON', +119614=>'ON', +119615=>'ON', +119616=>'ON', +119617=>'ON', +119618=>'ON', +119619=>'ON', +119620=>'ON', +119621=>'ON', +119622=>'ON', +119623=>'ON', +119624=>'ON', +119625=>'ON', +119626=>'ON', +119627=>'ON', +119628=>'ON', +119629=>'ON', +119630=>'ON', +119631=>'ON', +119632=>'ON', +119633=>'ON', +119634=>'ON', +119635=>'ON', +119636=>'ON', +119637=>'ON', +119638=>'ON', +119648=>'L', +119649=>'L', +119650=>'L', +119651=>'L', +119652=>'L', +119653=>'L', +119654=>'L', +119655=>'L', +119656=>'L', +119657=>'L', +119658=>'L', +119659=>'L', +119660=>'L', +119661=>'L', +119662=>'L', +119663=>'L', +119664=>'L', +119665=>'L', +119808=>'L', +119809=>'L', +119810=>'L', +119811=>'L', +119812=>'L', +119813=>'L', +119814=>'L', +119815=>'L', +119816=>'L', +119817=>'L', +119818=>'L', +119819=>'L', +119820=>'L', +119821=>'L', +119822=>'L', +119823=>'L', +119824=>'L', +119825=>'L', +119826=>'L', +119827=>'L', +119828=>'L', +119829=>'L', +119830=>'L', +119831=>'L', +119832=>'L', +119833=>'L', +119834=>'L', +119835=>'L', +119836=>'L', +119837=>'L', +119838=>'L', +119839=>'L', +119840=>'L', +119841=>'L', +119842=>'L', +119843=>'L', +119844=>'L', +119845=>'L', +119846=>'L', +119847=>'L', +119848=>'L', +119849=>'L', +119850=>'L', +119851=>'L', +119852=>'L', +119853=>'L', +119854=>'L', +119855=>'L', +119856=>'L', +119857=>'L', +119858=>'L', +119859=>'L', +119860=>'L', +119861=>'L', +119862=>'L', +119863=>'L', +119864=>'L', +119865=>'L', +119866=>'L', +119867=>'L', +119868=>'L', +119869=>'L', +119870=>'L', +119871=>'L', +119872=>'L', +119873=>'L', +119874=>'L', +119875=>'L', +119876=>'L', +119877=>'L', +119878=>'L', +119879=>'L', +119880=>'L', +119881=>'L', +119882=>'L', +119883=>'L', +119884=>'L', +119885=>'L', +119886=>'L', +119887=>'L', +119888=>'L', +119889=>'L', +119890=>'L', +119891=>'L', +119892=>'L', +119894=>'L', +119895=>'L', +119896=>'L', +119897=>'L', +119898=>'L', +119899=>'L', +119900=>'L', +119901=>'L', +119902=>'L', +119903=>'L', +119904=>'L', +119905=>'L', +119906=>'L', +119907=>'L', +119908=>'L', +119909=>'L', +119910=>'L', +119911=>'L', +119912=>'L', +119913=>'L', +119914=>'L', +119915=>'L', +119916=>'L', +119917=>'L', +119918=>'L', +119919=>'L', +119920=>'L', +119921=>'L', +119922=>'L', +119923=>'L', +119924=>'L', +119925=>'L', +119926=>'L', +119927=>'L', +119928=>'L', +119929=>'L', +119930=>'L', +119931=>'L', +119932=>'L', +119933=>'L', +119934=>'L', +119935=>'L', +119936=>'L', +119937=>'L', +119938=>'L', +119939=>'L', +119940=>'L', +119941=>'L', +119942=>'L', +119943=>'L', +119944=>'L', +119945=>'L', +119946=>'L', +119947=>'L', +119948=>'L', +119949=>'L', +119950=>'L', +119951=>'L', +119952=>'L', +119953=>'L', +119954=>'L', +119955=>'L', +119956=>'L', +119957=>'L', +119958=>'L', +119959=>'L', +119960=>'L', +119961=>'L', +119962=>'L', +119963=>'L', +119964=>'L', +119966=>'L', +119967=>'L', +119970=>'L', +119973=>'L', +119974=>'L', +119977=>'L', +119978=>'L', +119979=>'L', +119980=>'L', +119982=>'L', +119983=>'L', +119984=>'L', +119985=>'L', +119986=>'L', +119987=>'L', +119988=>'L', +119989=>'L', +119990=>'L', +119991=>'L', +119992=>'L', +119993=>'L', +119995=>'L', +119997=>'L', +119998=>'L', +119999=>'L', +120000=>'L', +120001=>'L', +120002=>'L', +120003=>'L', +120005=>'L', +120006=>'L', +120007=>'L', +120008=>'L', +120009=>'L', +120010=>'L', +120011=>'L', +120012=>'L', +120013=>'L', +120014=>'L', +120015=>'L', +120016=>'L', +120017=>'L', +120018=>'L', +120019=>'L', +120020=>'L', +120021=>'L', +120022=>'L', +120023=>'L', +120024=>'L', +120025=>'L', +120026=>'L', +120027=>'L', +120028=>'L', +120029=>'L', +120030=>'L', +120031=>'L', +120032=>'L', +120033=>'L', +120034=>'L', +120035=>'L', +120036=>'L', +120037=>'L', +120038=>'L', +120039=>'L', +120040=>'L', +120041=>'L', +120042=>'L', +120043=>'L', +120044=>'L', +120045=>'L', +120046=>'L', +120047=>'L', +120048=>'L', +120049=>'L', +120050=>'L', +120051=>'L', +120052=>'L', +120053=>'L', +120054=>'L', +120055=>'L', +120056=>'L', +120057=>'L', +120058=>'L', +120059=>'L', +120060=>'L', +120061=>'L', +120062=>'L', +120063=>'L', +120064=>'L', +120065=>'L', +120066=>'L', +120067=>'L', +120068=>'L', +120069=>'L', +120071=>'L', +120072=>'L', +120073=>'L', +120074=>'L', +120077=>'L', +120078=>'L', +120079=>'L', +120080=>'L', +120081=>'L', +120082=>'L', +120083=>'L', +120084=>'L', +120086=>'L', +120087=>'L', +120088=>'L', +120089=>'L', +120090=>'L', +120091=>'L', +120092=>'L', +120094=>'L', +120095=>'L', +120096=>'L', +120097=>'L', +120098=>'L', +120099=>'L', +120100=>'L', +120101=>'L', +120102=>'L', +120103=>'L', +120104=>'L', +120105=>'L', +120106=>'L', +120107=>'L', +120108=>'L', +120109=>'L', +120110=>'L', +120111=>'L', +120112=>'L', +120113=>'L', +120114=>'L', +120115=>'L', +120116=>'L', +120117=>'L', +120118=>'L', +120119=>'L', +120120=>'L', +120121=>'L', +120123=>'L', +120124=>'L', +120125=>'L', +120126=>'L', +120128=>'L', +120129=>'L', +120130=>'L', +120131=>'L', +120132=>'L', +120134=>'L', +120138=>'L', +120139=>'L', +120140=>'L', +120141=>'L', +120142=>'L', +120143=>'L', +120144=>'L', +120146=>'L', +120147=>'L', +120148=>'L', +120149=>'L', +120150=>'L', +120151=>'L', +120152=>'L', +120153=>'L', +120154=>'L', +120155=>'L', +120156=>'L', +120157=>'L', +120158=>'L', +120159=>'L', +120160=>'L', +120161=>'L', +120162=>'L', +120163=>'L', +120164=>'L', +120165=>'L', +120166=>'L', +120167=>'L', +120168=>'L', +120169=>'L', +120170=>'L', +120171=>'L', +120172=>'L', +120173=>'L', +120174=>'L', +120175=>'L', +120176=>'L', +120177=>'L', +120178=>'L', +120179=>'L', +120180=>'L', +120181=>'L', +120182=>'L', +120183=>'L', +120184=>'L', +120185=>'L', +120186=>'L', +120187=>'L', +120188=>'L', +120189=>'L', +120190=>'L', +120191=>'L', +120192=>'L', +120193=>'L', +120194=>'L', +120195=>'L', +120196=>'L', +120197=>'L', +120198=>'L', +120199=>'L', +120200=>'L', +120201=>'L', +120202=>'L', +120203=>'L', +120204=>'L', +120205=>'L', +120206=>'L', +120207=>'L', +120208=>'L', +120209=>'L', +120210=>'L', +120211=>'L', +120212=>'L', +120213=>'L', +120214=>'L', +120215=>'L', +120216=>'L', +120217=>'L', +120218=>'L', +120219=>'L', +120220=>'L', +120221=>'L', +120222=>'L', +120223=>'L', +120224=>'L', +120225=>'L', +120226=>'L', +120227=>'L', +120228=>'L', +120229=>'L', +120230=>'L', +120231=>'L', +120232=>'L', +120233=>'L', +120234=>'L', +120235=>'L', +120236=>'L', +120237=>'L', +120238=>'L', +120239=>'L', +120240=>'L', +120241=>'L', +120242=>'L', +120243=>'L', +120244=>'L', +120245=>'L', +120246=>'L', +120247=>'L', +120248=>'L', +120249=>'L', +120250=>'L', +120251=>'L', +120252=>'L', +120253=>'L', +120254=>'L', +120255=>'L', +120256=>'L', +120257=>'L', +120258=>'L', +120259=>'L', +120260=>'L', +120261=>'L', +120262=>'L', +120263=>'L', +120264=>'L', +120265=>'L', +120266=>'L', +120267=>'L', +120268=>'L', +120269=>'L', +120270=>'L', +120271=>'L', +120272=>'L', +120273=>'L', +120274=>'L', +120275=>'L', +120276=>'L', +120277=>'L', +120278=>'L', +120279=>'L', +120280=>'L', +120281=>'L', +120282=>'L', +120283=>'L', +120284=>'L', +120285=>'L', +120286=>'L', +120287=>'L', +120288=>'L', +120289=>'L', +120290=>'L', +120291=>'L', +120292=>'L', +120293=>'L', +120294=>'L', +120295=>'L', +120296=>'L', +120297=>'L', +120298=>'L', +120299=>'L', +120300=>'L', +120301=>'L', +120302=>'L', +120303=>'L', +120304=>'L', +120305=>'L', +120306=>'L', +120307=>'L', +120308=>'L', +120309=>'L', +120310=>'L', +120311=>'L', +120312=>'L', +120313=>'L', +120314=>'L', +120315=>'L', +120316=>'L', +120317=>'L', +120318=>'L', +120319=>'L', +120320=>'L', +120321=>'L', +120322=>'L', +120323=>'L', +120324=>'L', +120325=>'L', +120326=>'L', +120327=>'L', +120328=>'L', +120329=>'L', +120330=>'L', +120331=>'L', +120332=>'L', +120333=>'L', +120334=>'L', +120335=>'L', +120336=>'L', +120337=>'L', +120338=>'L', +120339=>'L', +120340=>'L', +120341=>'L', +120342=>'L', +120343=>'L', +120344=>'L', +120345=>'L', +120346=>'L', +120347=>'L', +120348=>'L', +120349=>'L', +120350=>'L', +120351=>'L', +120352=>'L', +120353=>'L', +120354=>'L', +120355=>'L', +120356=>'L', +120357=>'L', +120358=>'L', +120359=>'L', +120360=>'L', +120361=>'L', +120362=>'L', +120363=>'L', +120364=>'L', +120365=>'L', +120366=>'L', +120367=>'L', +120368=>'L', +120369=>'L', +120370=>'L', +120371=>'L', +120372=>'L', +120373=>'L', +120374=>'L', +120375=>'L', +120376=>'L', +120377=>'L', +120378=>'L', +120379=>'L', +120380=>'L', +120381=>'L', +120382=>'L', +120383=>'L', +120384=>'L', +120385=>'L', +120386=>'L', +120387=>'L', +120388=>'L', +120389=>'L', +120390=>'L', +120391=>'L', +120392=>'L', +120393=>'L', +120394=>'L', +120395=>'L', +120396=>'L', +120397=>'L', +120398=>'L', +120399=>'L', +120400=>'L', +120401=>'L', +120402=>'L', +120403=>'L', +120404=>'L', +120405=>'L', +120406=>'L', +120407=>'L', +120408=>'L', +120409=>'L', +120410=>'L', +120411=>'L', +120412=>'L', +120413=>'L', +120414=>'L', +120415=>'L', +120416=>'L', +120417=>'L', +120418=>'L', +120419=>'L', +120420=>'L', +120421=>'L', +120422=>'L', +120423=>'L', +120424=>'L', +120425=>'L', +120426=>'L', +120427=>'L', +120428=>'L', +120429=>'L', +120430=>'L', +120431=>'L', +120432=>'L', +120433=>'L', +120434=>'L', +120435=>'L', +120436=>'L', +120437=>'L', +120438=>'L', +120439=>'L', +120440=>'L', +120441=>'L', +120442=>'L', +120443=>'L', +120444=>'L', +120445=>'L', +120446=>'L', +120447=>'L', +120448=>'L', +120449=>'L', +120450=>'L', +120451=>'L', +120452=>'L', +120453=>'L', +120454=>'L', +120455=>'L', +120456=>'L', +120457=>'L', +120458=>'L', +120459=>'L', +120460=>'L', +120461=>'L', +120462=>'L', +120463=>'L', +120464=>'L', +120465=>'L', +120466=>'L', +120467=>'L', +120468=>'L', +120469=>'L', +120470=>'L', +120471=>'L', +120472=>'L', +120473=>'L', +120474=>'L', +120475=>'L', +120476=>'L', +120477=>'L', +120478=>'L', +120479=>'L', +120480=>'L', +120481=>'L', +120482=>'L', +120483=>'L', +120484=>'L', +120485=>'L', +120488=>'L', +120489=>'L', +120490=>'L', +120491=>'L', +120492=>'L', +120493=>'L', +120494=>'L', +120495=>'L', +120496=>'L', +120497=>'L', +120498=>'L', +120499=>'L', +120500=>'L', +120501=>'L', +120502=>'L', +120503=>'L', +120504=>'L', +120505=>'L', +120506=>'L', +120507=>'L', +120508=>'L', +120509=>'L', +120510=>'L', +120511=>'L', +120512=>'L', +120513=>'L', +120514=>'L', +120515=>'L', +120516=>'L', +120517=>'L', +120518=>'L', +120519=>'L', +120520=>'L', +120521=>'L', +120522=>'L', +120523=>'L', +120524=>'L', +120525=>'L', +120526=>'L', +120527=>'L', +120528=>'L', +120529=>'L', +120530=>'L', +120531=>'L', +120532=>'L', +120533=>'L', +120534=>'L', +120535=>'L', +120536=>'L', +120537=>'L', +120538=>'L', +120539=>'L', +120540=>'L', +120541=>'L', +120542=>'L', +120543=>'L', +120544=>'L', +120545=>'L', +120546=>'L', +120547=>'L', +120548=>'L', +120549=>'L', +120550=>'L', +120551=>'L', +120552=>'L', +120553=>'L', +120554=>'L', +120555=>'L', +120556=>'L', +120557=>'L', +120558=>'L', +120559=>'L', +120560=>'L', +120561=>'L', +120562=>'L', +120563=>'L', +120564=>'L', +120565=>'L', +120566=>'L', +120567=>'L', +120568=>'L', +120569=>'L', +120570=>'L', +120571=>'L', +120572=>'L', +120573=>'L', +120574=>'L', +120575=>'L', +120576=>'L', +120577=>'L', +120578=>'L', +120579=>'L', +120580=>'L', +120581=>'L', +120582=>'L', +120583=>'L', +120584=>'L', +120585=>'L', +120586=>'L', +120587=>'L', +120588=>'L', +120589=>'L', +120590=>'L', +120591=>'L', +120592=>'L', +120593=>'L', +120594=>'L', +120595=>'L', +120596=>'L', +120597=>'L', +120598=>'L', +120599=>'L', +120600=>'L', +120601=>'L', +120602=>'L', +120603=>'L', +120604=>'L', +120605=>'L', +120606=>'L', +120607=>'L', +120608=>'L', +120609=>'L', +120610=>'L', +120611=>'L', +120612=>'L', +120613=>'L', +120614=>'L', +120615=>'L', +120616=>'L', +120617=>'L', +120618=>'L', +120619=>'L', +120620=>'L', +120621=>'L', +120622=>'L', +120623=>'L', +120624=>'L', +120625=>'L', +120626=>'L', +120627=>'L', +120628=>'L', +120629=>'L', +120630=>'L', +120631=>'L', +120632=>'L', +120633=>'L', +120634=>'L', +120635=>'L', +120636=>'L', +120637=>'L', +120638=>'L', +120639=>'L', +120640=>'L', +120641=>'L', +120642=>'L', +120643=>'L', +120644=>'L', +120645=>'L', +120646=>'L', +120647=>'L', +120648=>'L', +120649=>'L', +120650=>'L', +120651=>'L', +120652=>'L', +120653=>'L', +120654=>'L', +120655=>'L', +120656=>'L', +120657=>'L', +120658=>'L', +120659=>'L', +120660=>'L', +120661=>'L', +120662=>'L', +120663=>'L', +120664=>'L', +120665=>'L', +120666=>'L', +120667=>'L', +120668=>'L', +120669=>'L', +120670=>'L', +120671=>'L', +120672=>'L', +120673=>'L', +120674=>'L', +120675=>'L', +120676=>'L', +120677=>'L', +120678=>'L', +120679=>'L', +120680=>'L', +120681=>'L', +120682=>'L', +120683=>'L', +120684=>'L', +120685=>'L', +120686=>'L', +120687=>'L', +120688=>'L', +120689=>'L', +120690=>'L', +120691=>'L', +120692=>'L', +120693=>'L', +120694=>'L', +120695=>'L', +120696=>'L', +120697=>'L', +120698=>'L', +120699=>'L', +120700=>'L', +120701=>'L', +120702=>'L', +120703=>'L', +120704=>'L', +120705=>'L', +120706=>'L', +120707=>'L', +120708=>'L', +120709=>'L', +120710=>'L', +120711=>'L', +120712=>'L', +120713=>'L', +120714=>'L', +120715=>'L', +120716=>'L', +120717=>'L', +120718=>'L', +120719=>'L', +120720=>'L', +120721=>'L', +120722=>'L', +120723=>'L', +120724=>'L', +120725=>'L', +120726=>'L', +120727=>'L', +120728=>'L', +120729=>'L', +120730=>'L', +120731=>'L', +120732=>'L', +120733=>'L', +120734=>'L', +120735=>'L', +120736=>'L', +120737=>'L', +120738=>'L', +120739=>'L', +120740=>'L', +120741=>'L', +120742=>'L', +120743=>'L', +120744=>'L', +120745=>'L', +120746=>'L', +120747=>'L', +120748=>'L', +120749=>'L', +120750=>'L', +120751=>'L', +120752=>'L', +120753=>'L', +120754=>'L', +120755=>'L', +120756=>'L', +120757=>'L', +120758=>'L', +120759=>'L', +120760=>'L', +120761=>'L', +120762=>'L', +120763=>'L', +120764=>'L', +120765=>'L', +120766=>'L', +120767=>'L', +120768=>'L', +120769=>'L', +120770=>'L', +120771=>'L', +120772=>'L', +120773=>'L', +120774=>'L', +120775=>'L', +120776=>'L', +120777=>'L', +120778=>'L', +120779=>'L', +120782=>'EN', +120783=>'EN', +120784=>'EN', +120785=>'EN', +120786=>'EN', +120787=>'EN', +120788=>'EN', +120789=>'EN', +120790=>'EN', +120791=>'EN', +120792=>'EN', +120793=>'EN', +120794=>'EN', +120795=>'EN', +120796=>'EN', +120797=>'EN', +120798=>'EN', +120799=>'EN', +120800=>'EN', +120801=>'EN', +120802=>'EN', +120803=>'EN', +120804=>'EN', +120805=>'EN', +120806=>'EN', +120807=>'EN', +120808=>'EN', +120809=>'EN', +120810=>'EN', +120811=>'EN', +120812=>'EN', +120813=>'EN', +120814=>'EN', +120815=>'EN', +120816=>'EN', +120817=>'EN', +120818=>'EN', +120819=>'EN', +120820=>'EN', +120821=>'EN', +120822=>'EN', +120823=>'EN', +120824=>'EN', +120825=>'EN', +120826=>'EN', +120827=>'EN', +120828=>'EN', +120829=>'EN', +120830=>'EN', +120831=>'EN', +131072=>'L', +173782=>'L', +194560=>'L', +194561=>'L', +194562=>'L', +194563=>'L', +194564=>'L', +194565=>'L', +194566=>'L', +194567=>'L', +194568=>'L', +194569=>'L', +194570=>'L', +194571=>'L', +194572=>'L', +194573=>'L', +194574=>'L', +194575=>'L', +194576=>'L', +194577=>'L', +194578=>'L', +194579=>'L', +194580=>'L', +194581=>'L', +194582=>'L', +194583=>'L', +194584=>'L', +194585=>'L', +194586=>'L', +194587=>'L', +194588=>'L', +194589=>'L', +194590=>'L', +194591=>'L', +194592=>'L', +194593=>'L', +194594=>'L', +194595=>'L', +194596=>'L', +194597=>'L', +194598=>'L', +194599=>'L', +194600=>'L', +194601=>'L', +194602=>'L', +194603=>'L', +194604=>'L', +194605=>'L', +194606=>'L', +194607=>'L', +194608=>'L', +194609=>'L', +194610=>'L', +194611=>'L', +194612=>'L', +194613=>'L', +194614=>'L', +194615=>'L', +194616=>'L', +194617=>'L', +194618=>'L', +194619=>'L', +194620=>'L', +194621=>'L', +194622=>'L', +194623=>'L', +194624=>'L', +194625=>'L', +194626=>'L', +194627=>'L', +194628=>'L', +194629=>'L', +194630=>'L', +194631=>'L', +194632=>'L', +194633=>'L', +194634=>'L', +194635=>'L', +194636=>'L', +194637=>'L', +194638=>'L', +194639=>'L', +194640=>'L', +194641=>'L', +194642=>'L', +194643=>'L', +194644=>'L', +194645=>'L', +194646=>'L', +194647=>'L', +194648=>'L', +194649=>'L', +194650=>'L', +194651=>'L', +194652=>'L', +194653=>'L', +194654=>'L', +194655=>'L', +194656=>'L', +194657=>'L', +194658=>'L', +194659=>'L', +194660=>'L', +194661=>'L', +194662=>'L', +194663=>'L', +194664=>'L', +194665=>'L', +194666=>'L', +194667=>'L', +194668=>'L', +194669=>'L', +194670=>'L', +194671=>'L', +194672=>'L', +194673=>'L', +194674=>'L', +194675=>'L', +194676=>'L', +194677=>'L', +194678=>'L', +194679=>'L', +194680=>'L', +194681=>'L', +194682=>'L', +194683=>'L', +194684=>'L', +194685=>'L', +194686=>'L', +194687=>'L', +194688=>'L', +194689=>'L', +194690=>'L', +194691=>'L', +194692=>'L', +194693=>'L', +194694=>'L', +194695=>'L', +194696=>'L', +194697=>'L', +194698=>'L', +194699=>'L', +194700=>'L', +194701=>'L', +194702=>'L', +194703=>'L', +194704=>'L', +194705=>'L', +194706=>'L', +194707=>'L', +194708=>'L', +194709=>'L', +194710=>'L', +194711=>'L', +194712=>'L', +194713=>'L', +194714=>'L', +194715=>'L', +194716=>'L', +194717=>'L', +194718=>'L', +194719=>'L', +194720=>'L', +194721=>'L', +194722=>'L', +194723=>'L', +194724=>'L', +194725=>'L', +194726=>'L', +194727=>'L', +194728=>'L', +194729=>'L', +194730=>'L', +194731=>'L', +194732=>'L', +194733=>'L', +194734=>'L', +194735=>'L', +194736=>'L', +194737=>'L', +194738=>'L', +194739=>'L', +194740=>'L', +194741=>'L', +194742=>'L', +194743=>'L', +194744=>'L', +194745=>'L', +194746=>'L', +194747=>'L', +194748=>'L', +194749=>'L', +194750=>'L', +194751=>'L', +194752=>'L', +194753=>'L', +194754=>'L', +194755=>'L', +194756=>'L', +194757=>'L', +194758=>'L', +194759=>'L', +194760=>'L', +194761=>'L', +194762=>'L', +194763=>'L', +194764=>'L', +194765=>'L', +194766=>'L', +194767=>'L', +194768=>'L', +194769=>'L', +194770=>'L', +194771=>'L', +194772=>'L', +194773=>'L', +194774=>'L', +194775=>'L', +194776=>'L', +194777=>'L', +194778=>'L', +194779=>'L', +194780=>'L', +194781=>'L', +194782=>'L', +194783=>'L', +194784=>'L', +194785=>'L', +194786=>'L', +194787=>'L', +194788=>'L', +194789=>'L', +194790=>'L', +194791=>'L', +194792=>'L', +194793=>'L', +194794=>'L', +194795=>'L', +194796=>'L', +194797=>'L', +194798=>'L', +194799=>'L', +194800=>'L', +194801=>'L', +194802=>'L', +194803=>'L', +194804=>'L', +194805=>'L', +194806=>'L', +194807=>'L', +194808=>'L', +194809=>'L', +194810=>'L', +194811=>'L', +194812=>'L', +194813=>'L', +194814=>'L', +194815=>'L', +194816=>'L', +194817=>'L', +194818=>'L', +194819=>'L', +194820=>'L', +194821=>'L', +194822=>'L', +194823=>'L', +194824=>'L', +194825=>'L', +194826=>'L', +194827=>'L', +194828=>'L', +194829=>'L', +194830=>'L', +194831=>'L', +194832=>'L', +194833=>'L', +194834=>'L', +194835=>'L', +194836=>'L', +194837=>'L', +194838=>'L', +194839=>'L', +194840=>'L', +194841=>'L', +194842=>'L', +194843=>'L', +194844=>'L', +194845=>'L', +194846=>'L', +194847=>'L', +194848=>'L', +194849=>'L', +194850=>'L', +194851=>'L', +194852=>'L', +194853=>'L', +194854=>'L', +194855=>'L', +194856=>'L', +194857=>'L', +194858=>'L', +194859=>'L', +194860=>'L', +194861=>'L', +194862=>'L', +194863=>'L', +194864=>'L', +194865=>'L', +194866=>'L', +194867=>'L', +194868=>'L', +194869=>'L', +194870=>'L', +194871=>'L', +194872=>'L', +194873=>'L', +194874=>'L', +194875=>'L', +194876=>'L', +194877=>'L', +194878=>'L', +194879=>'L', +194880=>'L', +194881=>'L', +194882=>'L', +194883=>'L', +194884=>'L', +194885=>'L', +194886=>'L', +194887=>'L', +194888=>'L', +194889=>'L', +194890=>'L', +194891=>'L', +194892=>'L', +194893=>'L', +194894=>'L', +194895=>'L', +194896=>'L', +194897=>'L', +194898=>'L', +194899=>'L', +194900=>'L', +194901=>'L', +194902=>'L', +194903=>'L', +194904=>'L', +194905=>'L', +194906=>'L', +194907=>'L', +194908=>'L', +194909=>'L', +194910=>'L', +194911=>'L', +194912=>'L', +194913=>'L', +194914=>'L', +194915=>'L', +194916=>'L', +194917=>'L', +194918=>'L', +194919=>'L', +194920=>'L', +194921=>'L', +194922=>'L', +194923=>'L', +194924=>'L', +194925=>'L', +194926=>'L', +194927=>'L', +194928=>'L', +194929=>'L', +194930=>'L', +194931=>'L', +194932=>'L', +194933=>'L', +194934=>'L', +194935=>'L', +194936=>'L', +194937=>'L', +194938=>'L', +194939=>'L', +194940=>'L', +194941=>'L', +194942=>'L', +194943=>'L', +194944=>'L', +194945=>'L', +194946=>'L', +194947=>'L', +194948=>'L', +194949=>'L', +194950=>'L', +194951=>'L', +194952=>'L', +194953=>'L', +194954=>'L', +194955=>'L', +194956=>'L', +194957=>'L', +194958=>'L', +194959=>'L', +194960=>'L', +194961=>'L', +194962=>'L', +194963=>'L', +194964=>'L', +194965=>'L', +194966=>'L', +194967=>'L', +194968=>'L', +194969=>'L', +194970=>'L', +194971=>'L', +194972=>'L', +194973=>'L', +194974=>'L', +194975=>'L', +194976=>'L', +194977=>'L', +194978=>'L', +194979=>'L', +194980=>'L', +194981=>'L', +194982=>'L', +194983=>'L', +194984=>'L', +194985=>'L', +194986=>'L', +194987=>'L', +194988=>'L', +194989=>'L', +194990=>'L', +194991=>'L', +194992=>'L', +194993=>'L', +194994=>'L', +194995=>'L', +194996=>'L', +194997=>'L', +194998=>'L', +194999=>'L', +195000=>'L', +195001=>'L', +195002=>'L', +195003=>'L', +195004=>'L', +195005=>'L', +195006=>'L', +195007=>'L', +195008=>'L', +195009=>'L', +195010=>'L', +195011=>'L', +195012=>'L', +195013=>'L', +195014=>'L', +195015=>'L', +195016=>'L', +195017=>'L', +195018=>'L', +195019=>'L', +195020=>'L', +195021=>'L', +195022=>'L', +195023=>'L', +195024=>'L', +195025=>'L', +195026=>'L', +195027=>'L', +195028=>'L', +195029=>'L', +195030=>'L', +195031=>'L', +195032=>'L', +195033=>'L', +195034=>'L', +195035=>'L', +195036=>'L', +195037=>'L', +195038=>'L', +195039=>'L', +195040=>'L', +195041=>'L', +195042=>'L', +195043=>'L', +195044=>'L', +195045=>'L', +195046=>'L', +195047=>'L', +195048=>'L', +195049=>'L', +195050=>'L', +195051=>'L', +195052=>'L', +195053=>'L', +195054=>'L', +195055=>'L', +195056=>'L', +195057=>'L', +195058=>'L', +195059=>'L', +195060=>'L', +195061=>'L', +195062=>'L', +195063=>'L', +195064=>'L', +195065=>'L', +195066=>'L', +195067=>'L', +195068=>'L', +195069=>'L', +195070=>'L', +195071=>'L', +195072=>'L', +195073=>'L', +195074=>'L', +195075=>'L', +195076=>'L', +195077=>'L', +195078=>'L', +195079=>'L', +195080=>'L', +195081=>'L', +195082=>'L', +195083=>'L', +195084=>'L', +195085=>'L', +195086=>'L', +195087=>'L', +195088=>'L', +195089=>'L', +195090=>'L', +195091=>'L', +195092=>'L', +195093=>'L', +195094=>'L', +195095=>'L', +195096=>'L', +195097=>'L', +195098=>'L', +195099=>'L', +195100=>'L', +195101=>'L', +917505=>'BN', +917536=>'BN', +917537=>'BN', +917538=>'BN', +917539=>'BN', +917540=>'BN', +917541=>'BN', +917542=>'BN', +917543=>'BN', +917544=>'BN', +917545=>'BN', +917546=>'BN', +917547=>'BN', +917548=>'BN', +917549=>'BN', +917550=>'BN', +917551=>'BN', +917552=>'BN', +917553=>'BN', +917554=>'BN', +917555=>'BN', +917556=>'BN', +917557=>'BN', +917558=>'BN', +917559=>'BN', +917560=>'BN', +917561=>'BN', +917562=>'BN', +917563=>'BN', +917564=>'BN', +917565=>'BN', +917566=>'BN', +917567=>'BN', +917568=>'BN', +917569=>'BN', +917570=>'BN', +917571=>'BN', +917572=>'BN', +917573=>'BN', +917574=>'BN', +917575=>'BN', +917576=>'BN', +917577=>'BN', +917578=>'BN', +917579=>'BN', +917580=>'BN', +917581=>'BN', +917582=>'BN', +917583=>'BN', +917584=>'BN', +917585=>'BN', +917586=>'BN', +917587=>'BN', +917588=>'BN', +917589=>'BN', +917590=>'BN', +917591=>'BN', +917592=>'BN', +917593=>'BN', +917594=>'BN', +917595=>'BN', +917596=>'BN', +917597=>'BN', +917598=>'BN', +917599=>'BN', +917600=>'BN', +917601=>'BN', +917602=>'BN', +917603=>'BN', +917604=>'BN', +917605=>'BN', +917606=>'BN', +917607=>'BN', +917608=>'BN', +917609=>'BN', +917610=>'BN', +917611=>'BN', +917612=>'BN', +917613=>'BN', +917614=>'BN', +917615=>'BN', +917616=>'BN', +917617=>'BN', +917618=>'BN', +917619=>'BN', +917620=>'BN', +917621=>'BN', +917622=>'BN', +917623=>'BN', +917624=>'BN', +917625=>'BN', +917626=>'BN', +917627=>'BN', +917628=>'BN', +917629=>'BN', +917630=>'BN', +917631=>'BN', +917760=>'NSM', +917761=>'NSM', +917762=>'NSM', +917763=>'NSM', +917764=>'NSM', +917765=>'NSM', +917766=>'NSM', +917767=>'NSM', +917768=>'NSM', +917769=>'NSM', +917770=>'NSM', +917771=>'NSM', +917772=>'NSM', +917773=>'NSM', +917774=>'NSM', +917775=>'NSM', +917776=>'NSM', +917777=>'NSM', +917778=>'NSM', +917779=>'NSM', +917780=>'NSM', +917781=>'NSM', +917782=>'NSM', +917783=>'NSM', +917784=>'NSM', +917785=>'NSM', +917786=>'NSM', +917787=>'NSM', +917788=>'NSM', +917789=>'NSM', +917790=>'NSM', +917791=>'NSM', +917792=>'NSM', +917793=>'NSM', +917794=>'NSM', +917795=>'NSM', +917796=>'NSM', +917797=>'NSM', +917798=>'NSM', +917799=>'NSM', +917800=>'NSM', +917801=>'NSM', +917802=>'NSM', +917803=>'NSM', +917804=>'NSM', +917805=>'NSM', +917806=>'NSM', +917807=>'NSM', +917808=>'NSM', +917809=>'NSM', +917810=>'NSM', +917811=>'NSM', +917812=>'NSM', +917813=>'NSM', +917814=>'NSM', +917815=>'NSM', +917816=>'NSM', +917817=>'NSM', +917818=>'NSM', +917819=>'NSM', +917820=>'NSM', +917821=>'NSM', +917822=>'NSM', +917823=>'NSM', +917824=>'NSM', +917825=>'NSM', +917826=>'NSM', +917827=>'NSM', +917828=>'NSM', +917829=>'NSM', +917830=>'NSM', +917831=>'NSM', +917832=>'NSM', +917833=>'NSM', +917834=>'NSM', +917835=>'NSM', +917836=>'NSM', +917837=>'NSM', +917838=>'NSM', +917839=>'NSM', +917840=>'NSM', +917841=>'NSM', +917842=>'NSM', +917843=>'NSM', +917844=>'NSM', +917845=>'NSM', +917846=>'NSM', +917847=>'NSM', +917848=>'NSM', +917849=>'NSM', +917850=>'NSM', +917851=>'NSM', +917852=>'NSM', +917853=>'NSM', +917854=>'NSM', +917855=>'NSM', +917856=>'NSM', +917857=>'NSM', +917858=>'NSM', +917859=>'NSM', +917860=>'NSM', +917861=>'NSM', +917862=>'NSM', +917863=>'NSM', +917864=>'NSM', +917865=>'NSM', +917866=>'NSM', +917867=>'NSM', +917868=>'NSM', +917869=>'NSM', +917870=>'NSM', +917871=>'NSM', +917872=>'NSM', +917873=>'NSM', +917874=>'NSM', +917875=>'NSM', +917876=>'NSM', +917877=>'NSM', +917878=>'NSM', +917879=>'NSM', +917880=>'NSM', +917881=>'NSM', +917882=>'NSM', +917883=>'NSM', +917884=>'NSM', +917885=>'NSM', +917886=>'NSM', +917887=>'NSM', +917888=>'NSM', +917889=>'NSM', +917890=>'NSM', +917891=>'NSM', +917892=>'NSM', +917893=>'NSM', +917894=>'NSM', +917895=>'NSM', +917896=>'NSM', +917897=>'NSM', +917898=>'NSM', +917899=>'NSM', +917900=>'NSM', +917901=>'NSM', +917902=>'NSM', +917903=>'NSM', +917904=>'NSM', +917905=>'NSM', +917906=>'NSM', +917907=>'NSM', +917908=>'NSM', +917909=>'NSM', +917910=>'NSM', +917911=>'NSM', +917912=>'NSM', +917913=>'NSM', +917914=>'NSM', +917915=>'NSM', +917916=>'NSM', +917917=>'NSM', +917918=>'NSM', +917919=>'NSM', +917920=>'NSM', +917921=>'NSM', +917922=>'NSM', +917923=>'NSM', +917924=>'NSM', +917925=>'NSM', +917926=>'NSM', +917927=>'NSM', +917928=>'NSM', +917929=>'NSM', +917930=>'NSM', +917931=>'NSM', +917932=>'NSM', +917933=>'NSM', +917934=>'NSM', +917935=>'NSM', +917936=>'NSM', +917937=>'NSM', +917938=>'NSM', +917939=>'NSM', +917940=>'NSM', +917941=>'NSM', +917942=>'NSM', +917943=>'NSM', +917944=>'NSM', +917945=>'NSM', +917946=>'NSM', +917947=>'NSM', +917948=>'NSM', +917949=>'NSM', +917950=>'NSM', +917951=>'NSM', +917952=>'NSM', +917953=>'NSM', +917954=>'NSM', +917955=>'NSM', +917956=>'NSM', +917957=>'NSM', +917958=>'NSM', +917959=>'NSM', +917960=>'NSM', +917961=>'NSM', +917962=>'NSM', +917963=>'NSM', +917964=>'NSM', +917965=>'NSM', +917966=>'NSM', +917967=>'NSM', +917968=>'NSM', +917969=>'NSM', +917970=>'NSM', +917971=>'NSM', +917972=>'NSM', +917973=>'NSM', +917974=>'NSM', +917975=>'NSM', +917976=>'NSM', +917977=>'NSM', +917978=>'NSM', +917979=>'NSM', +917980=>'NSM', +917981=>'NSM', +917982=>'NSM', +917983=>'NSM', +917984=>'NSM', +917985=>'NSM', +917986=>'NSM', +917987=>'NSM', +917988=>'NSM', +917989=>'NSM', +917990=>'NSM', +917991=>'NSM', +917992=>'NSM', +917993=>'NSM', +917994=>'NSM', +917995=>'NSM', +917996=>'NSM', +917997=>'NSM', +917998=>'NSM', +917999=>'NSM', +983040=>'L', +1048573=>'L', +1048576=>'L', +1114109=>'L' +); + +/** + * Mirror unicode characters. + * For information on bidi mirroring, see UAX #9: Bidirectional Algorithm, + * at http://www.unicode.org/unicode/reports/tr9/ + */ +global $unicode_mirror; +$unicode_mirror = array ( +0x0028=>0x0029, +0x0029=>0x0028, +0x003C=>0x003E, +0x003E=>0x003C, +0x005B=>0x005D, +0x005D=>0x005B, +0x007B=>0x007D, +0x007D=>0x007B, +0x00AB=>0x00BB, +0x00BB=>0x00AB, +0x0F3A=>0x0F3B, +0x0F3B=>0x0F3A, +0x0F3C=>0x0F3D, +0x0F3D=>0x0F3C, +0x169B=>0x169C, +0x169C=>0x169B, +0x2018=>0x2019, +0x2019=>0x2018, +0x201C=>0x201D, +0x201D=>0x201C, +0x2039=>0x203A, +0x203A=>0x2039, +0x2045=>0x2046, +0x2046=>0x2045, +0x207D=>0x207E, +0x207E=>0x207D, +0x208D=>0x208E, +0x208E=>0x208D, +0x2208=>0x220B, +0x2209=>0x220C, +0x220A=>0x220D, +0x220B=>0x2208, +0x220C=>0x2209, +0x220D=>0x220A, +0x2215=>0x29F5, +0x223C=>0x223D, +0x223D=>0x223C, +0x2243=>0x22CD, +0x2252=>0x2253, +0x2253=>0x2252, +0x2254=>0x2255, +0x2255=>0x2254, +0x2264=>0x2265, +0x2265=>0x2264, +0x2266=>0x2267, +0x2267=>0x2266, +0x2268=>0x2269, +0x2269=>0x2268, +0x226A=>0x226B, +0x226B=>0x226A, +0x226E=>0x226F, +0x226F=>0x226E, +0x2270=>0x2271, +0x2271=>0x2270, +0x2272=>0x2273, +0x2273=>0x2272, +0x2274=>0x2275, +0x2275=>0x2274, +0x2276=>0x2277, +0x2277=>0x2276, +0x2278=>0x2279, +0x2279=>0x2278, +0x227A=>0x227B, +0x227B=>0x227A, +0x227C=>0x227D, +0x227D=>0x227C, +0x227E=>0x227F, +0x227F=>0x227E, +0x2280=>0x2281, +0x2281=>0x2280, +0x2282=>0x2283, +0x2283=>0x2282, +0x2284=>0x2285, +0x2285=>0x2284, +0x2286=>0x2287, +0x2287=>0x2286, +0x2288=>0x2289, +0x2289=>0x2288, +0x228A=>0x228B, +0x228B=>0x228A, +0x228F=>0x2290, +0x2290=>0x228F, +0x2291=>0x2292, +0x2292=>0x2291, +0x2298=>0x29B8, +0x22A2=>0x22A3, +0x22A3=>0x22A2, +0x22A6=>0x2ADE, +0x22A8=>0x2AE4, +0x22A9=>0x2AE3, +0x22AB=>0x2AE5, +0x22B0=>0x22B1, +0x22B1=>0x22B0, +0x22B2=>0x22B3, +0x22B3=>0x22B2, +0x22B4=>0x22B5, +0x22B5=>0x22B4, +0x22B6=>0x22B7, +0x22B7=>0x22B6, +0x22C9=>0x22CA, +0x22CA=>0x22C9, +0x22CB=>0x22CC, +0x22CC=>0x22CB, +0x22CD=>0x2243, +0x22D0=>0x22D1, +0x22D1=>0x22D0, +0x22D6=>0x22D7, +0x22D7=>0x22D6, +0x22D8=>0x22D9, +0x22D9=>0x22D8, +0x22DA=>0x22DB, +0x22DB=>0x22DA, +0x22DC=>0x22DD, +0x22DD=>0x22DC, +0x22DE=>0x22DF, +0x22DF=>0x22DE, +0x22E0=>0x22E1, +0x22E1=>0x22E0, +0x22E2=>0x22E3, +0x22E3=>0x22E2, +0x22E4=>0x22E5, +0x22E5=>0x22E4, +0x22E6=>0x22E7, +0x22E7=>0x22E6, +0x22E8=>0x22E9, +0x22E9=>0x22E8, +0x22EA=>0x22EB, +0x22EB=>0x22EA, +0x22EC=>0x22ED, +0x22ED=>0x22EC, +0x22F0=>0x22F1, +0x22F1=>0x22F0, +0x22F2=>0x22FA, +0x22F3=>0x22FB, +0x22F4=>0x22FC, +0x22F6=>0x22FD, +0x22F7=>0x22FE, +0x22FA=>0x22F2, +0x22FB=>0x22F3, +0x22FC=>0x22F4, +0x22FD=>0x22F6, +0x22FE=>0x22F7, +0x2308=>0x2309, +0x2309=>0x2308, +0x230A=>0x230B, +0x230B=>0x230A, +0x2329=>0x232A, +0x232A=>0x2329, +0x2768=>0x2769, +0x2769=>0x2768, +0x276A=>0x276B, +0x276B=>0x276A, +0x276C=>0x276D, +0x276D=>0x276C, +0x276E=>0x276F, +0x276F=>0x276E, +0x2770=>0x2771, +0x2771=>0x2770, +0x2772=>0x2773, +0x2773=>0x2772, +0x2774=>0x2775, +0x2775=>0x2774, +0x27C3=>0x27C4, +0x27C4=>0x27C3, +0x27C5=>0x27C6, +0x27C6=>0x27C5, +0x27D5=>0x27D6, +0x27D6=>0x27D5, +0x27DD=>0x27DE, +0x27DE=>0x27DD, +0x27E2=>0x27E3, +0x27E3=>0x27E2, +0x27E4=>0x27E5, +0x27E5=>0x27E4, +0x27E6=>0x27E7, +0x27E7=>0x27E6, +0x27E8=>0x27E9, +0x27E9=>0x27E8, +0x27EA=>0x27EB, +0x27EB=>0x27EA, +0x2983=>0x2984, +0x2984=>0x2983, +0x2985=>0x2986, +0x2986=>0x2985, +0x2987=>0x2988, +0x2988=>0x2987, +0x2989=>0x298A, +0x298A=>0x2989, +0x298B=>0x298C, +0x298C=>0x298B, +0x298D=>0x2990, +0x298E=>0x298F, +0x298F=>0x298E, +0x2990=>0x298D, +0x2991=>0x2992, +0x2992=>0x2991, +0x2993=>0x2994, +0x2994=>0x2993, +0x2995=>0x2996, +0x2996=>0x2995, +0x2997=>0x2998, +0x2998=>0x2997, +0x29B8=>0x2298, +0x29C0=>0x29C1, +0x29C1=>0x29C0, +0x29C4=>0x29C5, +0x29C5=>0x29C4, +0x29CF=>0x29D0, +0x29D0=>0x29CF, +0x29D1=>0x29D2, +0x29D2=>0x29D1, +0x29D4=>0x29D5, +0x29D5=>0x29D4, +0x29D8=>0x29D9, +0x29D9=>0x29D8, +0x29DA=>0x29DB, +0x29DB=>0x29DA, +0x29F5=>0x2215, +0x29F8=>0x29F9, +0x29F9=>0x29F8, +0x29FC=>0x29FD, +0x29FD=>0x29FC, +0x2A2B=>0x2A2C, +0x2A2C=>0x2A2B, +0x2A2D=>0x2A2E, +0x2A2E=>0x2A2D, +0x2A34=>0x2A35, +0x2A35=>0x2A34, +0x2A3C=>0x2A3D, +0x2A3D=>0x2A3C, +0x2A64=>0x2A65, +0x2A65=>0x2A64, +0x2A79=>0x2A7A, +0x2A7A=>0x2A79, +0x2A7D=>0x2A7E, +0x2A7E=>0x2A7D, +0x2A7F=>0x2A80, +0x2A80=>0x2A7F, +0x2A81=>0x2A82, +0x2A82=>0x2A81, +0x2A83=>0x2A84, +0x2A84=>0x2A83, +0x2A8B=>0x2A8C, +0x2A8C=>0x2A8B, +0x2A91=>0x2A92, +0x2A92=>0x2A91, +0x2A93=>0x2A94, +0x2A94=>0x2A93, +0x2A95=>0x2A96, +0x2A96=>0x2A95, +0x2A97=>0x2A98, +0x2A98=>0x2A97, +0x2A99=>0x2A9A, +0x2A9A=>0x2A99, +0x2A9B=>0x2A9C, +0x2A9C=>0x2A9B, +0x2AA1=>0x2AA2, +0x2AA2=>0x2AA1, +0x2AA6=>0x2AA7, +0x2AA7=>0x2AA6, +0x2AA8=>0x2AA9, +0x2AA9=>0x2AA8, +0x2AAA=>0x2AAB, +0x2AAB=>0x2AAA, +0x2AAC=>0x2AAD, +0x2AAD=>0x2AAC, +0x2AAF=>0x2AB0, +0x2AB0=>0x2AAF, +0x2AB3=>0x2AB4, +0x2AB4=>0x2AB3, +0x2ABB=>0x2ABC, +0x2ABC=>0x2ABB, +0x2ABD=>0x2ABE, +0x2ABE=>0x2ABD, +0x2ABF=>0x2AC0, +0x2AC0=>0x2ABF, +0x2AC1=>0x2AC2, +0x2AC2=>0x2AC1, +0x2AC3=>0x2AC4, +0x2AC4=>0x2AC3, +0x2AC5=>0x2AC6, +0x2AC6=>0x2AC5, +0x2ACD=>0x2ACE, +0x2ACE=>0x2ACD, +0x2ACF=>0x2AD0, +0x2AD0=>0x2ACF, +0x2AD1=>0x2AD2, +0x2AD2=>0x2AD1, +0x2AD3=>0x2AD4, +0x2AD4=>0x2AD3, +0x2AD5=>0x2AD6, +0x2AD6=>0x2AD5, +0x2ADE=>0x22A6, +0x2AE3=>0x22A9, +0x2AE4=>0x22A8, +0x2AE5=>0x22AB, +0x2AEC=>0x2AED, +0x2AED=>0x2AEC, +0x2AF7=>0x2AF8, +0x2AF8=>0x2AF7, +0x2AF9=>0x2AFA, +0x2AFA=>0x2AF9, +0x2E02=>0x2E03, +0x2E03=>0x2E02, +0x2E04=>0x2E05, +0x2E05=>0x2E04, +0x2E09=>0x2E0A, +0x2E0A=>0x2E09, +0x2E0C=>0x2E0D, +0x2E0D=>0x2E0C, +0x2E1C=>0x2E1D, +0x2E1D=>0x2E1C, +0x3008=>0x3009, +0x3009=>0x3008, +0x300A=>0x300B, +0x300B=>0x300A, +0x300C=>0x300D, +0x300D=>0x300C, +0x300E=>0x300F, +0x300F=>0x300E, +0x3010=>0x3011, +0x3011=>0x3010, +0x3014=>0x3015, +0x3015=>0x3014, +0x3016=>0x3017, +0x3017=>0x3016, +0x3018=>0x3019, +0x3019=>0x3018, +0x301A=>0x301B, +0x301B=>0x301A, +0x301D=>0x301E, +0x301E=>0x301D, +0xFE59=>0xFE5A, +0xFE5A=>0xFE59, +0xFE5B=>0xFE5C, +0xFE5C=>0xFE5B, +0xFE5D=>0xFE5E, +0xFE5E=>0xFE5D, +0xFE64=>0xFE65, +0xFE65=>0xFE64, +0xFF08=>0xFF09, +0xFF09=>0xFF08, +0xFF1C=>0xFF1E, +0xFF1E=>0xFF1C, +0xFF3B=>0xFF3D, +0xFF3D=>0xFF3B, +0xFF5B=>0xFF5D, +0xFF5D=>0xFF5B, +0xFF5F=>0xFF60, +0xFF60=>0xFF5F, +0xFF62=>0xFF63, +0xFF63=>0xFF62); + +/** + * Arabic shape subtitutions + * char code=>isolated, final, initial, medial + */ +global $unicode_arlet; +$unicode_arlet = array( +1569=>array(65152), +1570=>array(65153, 65154, 65153, 65154), +1571=>array(65155, 65156, 65155, 65156), +1572=>array(65157, 65158), +1573=>array(65159, 65160, 65159, 65160), +1574=>array(65161, 65162, 65163, 65164), +1575=>array(65165, 65166, 65165, 65166), +1576=>array(65167, 65168, 65169, 65170), +1577=>array(65171, 65172), +1578=>array(65173, 65174, 65175, 65176), +1579=>array(65177, 65178, 65179, 65180), +1580=>array(65181, 65182, 65183, 65184), +1581=>array(65185, 65186, 65187, 65188), +1582=>array(65189, 65190, 65191, 65192), +1583=>array(65193, 65194, 65193, 65194), +1584=>array(65195, 65196, 65195, 65196), +1585=>array(65197, 65198, 65197, 65198), +1586=>array(65199, 65200, 65199, 65200), +1587=>array(65201, 65202, 65203, 65204), +1588=>array(65205, 65206, 65207, 65208), +1589=>array(65209, 65210, 65211, 65212), +1590=>array(65213, 65214, 65215, 65216), +1591=>array(65217, 65218, 65219, 65220), +1592=>array(65221, 65222, 65223, 65224), +1593=>array(65225, 65226, 65227, 65228), +1594=>array(65229, 65230, 65231, 65232), +1601=>array(65233, 65234, 65235, 65236), +1602=>array(65237, 65238, 65239, 65240), +1603=>array(65241, 65242, 65243, 65244), +1604=>array(65245, 65246, 65247, 65248), +1605=>array(65249, 65250, 65251, 65252), +1606=>array(65253, 65254, 65255, 65256), +1607=>array(65257, 65258, 65259, 65260), +1608=>array(65261, 65262, 65261, 65262), +1609=>array(65263, 65264, 64488, 64489), +1610=>array(65265, 65266, 65267, 65268), +1649=>array(64336, 64337), +1655=>array(64477), +1657=>array(64358, 64359, 64360, 64361), +1658=>array(64350, 64351, 64352, 64353), +1659=>array(64338, 64339, 64340, 64341), +1662=>array(64342, 64343, 64344, 64345), +1663=>array(64354, 64355, 64356, 64357), +1664=>array(64346, 64347, 64348, 64349), +1667=>array(64374, 64375, 64376, 64377), +1668=>array(64370, 64371, 64372, 64373), +1670=>array(64378, 64379, 64380, 64381), +1671=>array(64382, 64383, 64384, 64385), +1672=>array(64392, 64393), +1676=>array(64388, 64389), +1677=>array(64386, 64387), +1678=>array(64390, 64391), +1681=>array(64396, 64397), +1688=>array(64394, 64395, 64394, 64395), +1700=>array(64362, 64363, 64364, 64365), +1702=>array(64366, 64367, 64368, 64369), +1705=>array(64398, 64399, 64400, 64401), +1709=>array(64467, 64468, 64469, 64470), +1711=>array(64402, 64403, 64404, 64405), +1713=>array(64410, 64411, 64412, 64413), +1715=>array(64406, 64407, 64408, 64409), +1722=>array(64414, 64415), +1723=>array(64416, 64417, 64418, 64419), +1726=>array(64426, 64427, 64428, 64429), +1728=>array(64420, 64421), +1729=>array(64422, 64423, 64424, 64425), +1733=>array(64480, 64481), +1734=>array(64473, 64474), +1735=>array(64471, 64472), +1736=>array(64475, 64476), +1737=>array(64482, 64483), +1739=>array(64478, 64479), +1740=>array(64508, 64509, 64510, 64511), +1744=>array(64484, 64485, 64486, 64487), +1746=>array(64430, 64431), +1747=>array(64432, 64433) +); + +/** + * Arabic laa letter + * char code=>isolated, final, initial, medial + */ +global $laa_array; +$laa_array = array ( +1570 =>array(65269, 65270, 65269, 65270), +1571 =>array(65271, 65272, 65271, 65272), +1573 =>array(65273, 65274, 65273, 65274), +1575 =>array(65275, 65276, 65275, 65276) +); + +/** + * Array of character substitutions for sequences of two diacritics symbols starting with SHADDA (0651 HEX, 1617 DEC). + * Combining characters that can occur with Shadda (U0651) are placed in UE586-UE594. + * Putting the combining mark and shadda in the same glyph allows us to avoid the two marks overlapping each other in an illegible manner. + * second NSM char code=>substitution char + */ +global $diacritics; +$diacritics = array ( +1612=>64606, # Shadda + Dammatan +1613=>64607, # Shadda + Kasratan +1614=>64608, # Shadda + Fatha +1615=>64609, # Shadda + Damma +1616=>64610 # Shadda + Kasra +); + +/** + * Array of character substitutions from UTF-8 unicode to latin1 + */ +global $utf8tolatin; +$utf8tolatin = array ( +8364=>128, # Euro1 +338=>140, # OE +352=>138, # Scaron +376=>159, # Ydieresis +381=>142, # Zcaron2 +8226=>149, # bullet3 +710=>136, # circumflex +8224=>134, # dagger +8225=>135, # daggerdbl +8230=>133, # ellipsis +8212=>151, # emdash +8211=>150, # endash +402=>131, # florin +8249=>139, # guilsinglleft +8250=>155, # guilsinglright +339=>156, # oe +8240=>137, # perthousand +8222=>132, # quotedblbase +8220=>147, # quotedblleft +8221=>148, # quotedblright +8216=>145, # quoteleft +8217=>146, # quoteright +8218=>130, # quotesinglbase +353=>154, # scaron +732=>152, # tilde +8482=>153, # trademark +382=>158 # zcaron2 +); + +//============================================================+ +// END OF FILE +//============================================================+ +?> diff --git a/include/templates/Template.php b/include/templates/Template.php new file mode 100644 index 00000000..f7885ea4 --- /dev/null +++ b/include/templates/Template.php @@ -0,0 +1,51 @@ +args['return_array']= if this is set to true, then 'display()' function returns html and javascript + * in array format. This will allow granular control of html so that you can + * seperate the tables and customize the grid + */ + + + //convert values for gridcount in case they are in string form + if($this->args['gridcount'] == 'one'){ + $this->args['gridcount'] = 0; + }elseif($this->args['gridcount'] == 'two'){ + $this->args['gridcount'] = 1; + }elseif( + $this->args['gridcount'] == 'three'){$this->args['gridcount'] = 2; + } + + if(!isset($this->args['classname']) || empty($this->args['classname'])){ + $this->args['classname'] = 'DragDropGrid'; + } + $json = getJSONobj(); + //use Json to encode the arrays of data, for passing to javascript. + //we will always display at least one column, so set left column + $this->args['left_data'][] = array(' ', ' '); + $data0_enc = $json->encode($this->args['left_data']); + $left_div_name = $this->args['left_div_name']; + + //if count is set to 1, then we are displaying two columns, set the 2 column variables + if($this->args['gridcount']==1){ + $this->args['right_data'][] = array(' ', ' '); + $data1_enc = $json->encode($this->args['right_data']); + $right_div_name = $this->args['right_div_name']; + } + + //if count is set to 2, then we are displaying three columns, set the 3 column variables + if($this->args['gridcount']==2){ + $this->args['mid_data'][] = array(' ', ' '); + $data1_enc = $json->encode($this->args['mid_data']); + $mid_div_name = $this->args['mid_div_name']; + $this->args['right_data'][] = array(' ', ' '); + $data2_enc = $json->encode($this->args['right_data']); + $right_div_name = $this->args['right_div_name']; + } + $html_str_arr = array(); + //create the table, with the divs that will get populated. Populate both the string and array version + $html_str = "
              "; + $html_str_arr['begin'] = $html_str; + $html_str .= ""; + $html_str_arr['left'] = ""; + //set the middle column only if we are displaying 3 columns + if($this->args['gridcount']==2){ + $html_str .= ""; + $html_str_arr['middle'] = ""; + } + //set the right column if we are not in 1 column only mode + if($this->args['gridcount']>0){ + $html_str .= ""; + $html_str_arr['right'] = ""; + } + $html_str .= "
              "; + $html_str_arr['end'] = "
          • "; + + //create the needed javascript to set the values and invoke listener + $j_str = " "; + //return display string + $str = $j_str . ' ' . $html_str; + $html_str_arr['script'] = $j_str; + + if(isset($this->args['return_array']) && $this->args['return_array']){ + return $html_str_arr; + }else{ + return $str; + } + } + + /* + * This script is the javascript class definition for the template drag drop object. This + * makes use of the args['classname'] parameter to name the class and to prefix variables with. This is done + * dynamically so that multiple template dragdrop objects can be defined on the same page if needed + * without having the variables mix up as you drag rows around. + */ + function displayDefinitionScript() { + //create some defaults in case arguments are missing + + //convert values for gridcount in case they are in string form + if(!isset($this->args['gridcount']) || empty($this->args['gridcount']) || $this->args['gridcount'] == 'one'){ + $this->args['gridcount'] = 0; + }elseif($this->args['gridcount'] == 'two'){ + $this->args['gridcount'] = 1; + }elseif( + $this->args['gridcount'] == 'three'){$this->args['gridcount'] = 2; + } + + + + //default class name + if(!isset($this->args['classname']) || empty($this->args['classname'])){ + $this->args['classname'] = 'DragDropGrid'; + } + //default columns to one if the value is set to anything other than the expected 0,1 or 2 + if(($this->args['gridcount'] != 0) && ($this->args['gridcount'] != 1) && ($this->args['gridcount'] != 2)){ + $this->args['gridcount'] = 0; + } + + //default div names + if(!isset($this->args['left_div_name']) || empty($this->args['left_div_name'])){ + $this->args['left_div_name'] = 'left'; + } + if(!isset($this->args['mid_div_name']) || empty($this->args['mid_div_name'])){ + $this->args['mid_div_name'] = 'mid'; + } + if(!isset($this->args['right_div_name']) || empty($this->args['right_div_name'])){ + $this->args['right_div_name'] = 'right'; + } + + + + //create javascript that defines the javascript class for this instance + //start by defining the variables that the grids will be referenced by + $j_str = " + + "; + //all done, return final script + return $j_str; + } + + +/* + * this function returns the src style sheet and script tags that need to be included + * for the template chooser to work + */ + + function displayScriptTags() { + global $sugar_version, $sugar_config; + $j_str = " + + "; + + return $j_str; + } + +} + +?> diff --git a/include/templates/TemplateGroupChooser.php b/include/templates/TemplateGroupChooser.php new file mode 100644 index 00000000..686a5e3e --- /dev/null +++ b/include/templates/TemplateGroupChooser.php @@ -0,0 +1,175 @@ +args['left_size']) ? '10' : $this->args['left_size']); + $right_size = (empty($this->args['right_size']) ? '10' : $this->args['right_size']); + $third_size = (empty($this->args['third_size']) ? '10' : $this->args['third_size']); + $max_left = (empty($this->args['max_left']) ? '' : $this->args['max_left']); + $alt_tip = (empty($this->args['alt_tip']) ? '' : $this->args['alt_tip']); + + $str = ''; + if($js_loaded == false) { +// $this->template_groups_chooser_js(); + $js_loaded = true; + } + if(!isset($this->args['display'])) { + $table_style = ""; + } + else { + $table_style = "display: ".$this->args['display']; + } + + $str .= "
            args['id']}\" style=\"{$table_style}\">"; + if(!empty($this->args['title'])) $str .= "

            {$this->args['title']}

            "; + $str .= << + + +   + {$this->args['left_label']} +EOQ; + + if($this->display_hide_tabs == true) { + $str .= <<  + {$this->args['right_label']} +EOQ; + } + + if($this->display_third_tabs == true) { + $str .= <<  +   + {$this->args['third_label']} +EOQ; + } + + $str .= ' '; + if(!isset($this->args['disable'])) { + $str .= "
            args['left_name']}','{$this->args['left_name']}','{$this->args['right_name']}');\">" . SugarThemeRegistry::current()->getImage('uparrow_big','border="0" style="margin-bottom: 1px;" alt="'.$alt_tip.'"') . "
            +
            args['left_name']}','{$this->args['left_name']}','{$this->args['right_name']}');\">" . SugarThemeRegistry::current()->getImage('downarrow_big','border="0" style="margin-top: 1px;" alt="'.$alt_tip.'"') . ""; + } + + $str .= << + + + + + +
            +
            + "; + if ($this->display_hide_tabs == true) { + $str .= ''; + if(!isset($this->args['disable'])) { + $str .= "args['left_name']}','{$this->args['right_name']}', '{$left_size}', '{$right_size}', '{$max_left}');\">" . SugarThemeRegistry::current()->getImage('leftarrow_big','border="0" style="margin-right: 1px;" alt="'.$alt_tip.'"') . "args['left_name']}','{$this->args['right_name']}', '{$left_size}', '{$right_size}');\">" . SugarThemeRegistry::current()->getImage('rightarrow_big','border="0" style="margin-left: 1px;" alt="'.$alt_tip.'"') . ""; + } + $str .= " + args['right_name']}_td\" align=\"center\"> + " + . ""; + } + + if ($this->display_third_tabs == true) { + $str .= ''; + if(!isset($this->args['disable'])) { + $str .= "args['right_name']}','{$this->args['third_name']}', '{$right_size}', '{$third_size}');\">" . SugarThemeRegistry::current()->getImage('leftarrow_big','border="0" style="margin-right: 1px;" alt="'.$alt_tip.'"') . "args['right_name']}','{$this->args['third_name']}', '{$right_size}', '{$third_size}');\">" . SugarThemeRegistry::current()->getImage('rightarrow_big','border="0" style="margin-left: 1px;" alt="'.$alt_tip.'"') . ""; + } + $str .= " + args['third_name']}_td\" align=\"center\"> + + + + "; + } + $str .= " + "; + + + return $str; +} + + + + /* + * All Moved to sugar_3.js in class tabChooser; + * Please follow style that Dashlet configuration is done. + */ + function template_groups_chooser_js() { + //return ''; + } + +} + +?> diff --git a/include/timezone/timezones.php b/include/timezone/timezones.php new file mode 100644 index 00000000..44e09a29 --- /dev/null +++ b/include/timezone/timezones.php @@ -0,0 +1,2920 @@ + + array ( + 'gmtOffset' => 60, + ), + 'Africa/Luanda' => + array ( + 'gmtOffset' => 60, + ), + 'Africa/Porto-Novo' => + array ( + 'gmtOffset' => 60, + ), + 'Africa/Gaborone' => + array ( + 'gmtOffset' => 120, + ), + 'Africa/Ouagadougou' => + array ( + 'gmtOffset' => 0, + ), + 'Africa/Bujumbura' => + array ( + 'gmtOffset' => 120, + ), + 'Africa/Douala' => + array ( + 'gmtOffset' => 60, + ), + 'Atlantic/Cape_Verde' => + array ( + 'gmtOffset' => -60, + ), + 'Africa/Bangui' => + array ( + 'gmtOffset' => 60, + ), + 'Africa/Ndjamena' => + array ( + 'gmtOffset' => 60, + ), + 'Indian/Comoro' => + array ( + 'gmtOffset' => 180, + ), + 'Africa/Kinshasa' => + array ( + 'gmtOffset' => 60, + ), + 'Africa/Lubumbashi' => + array ( + 'gmtOffset' => 120, + ), + 'Africa/Brazzaville' => + array ( + 'gmtOffset' => 60, + ), + 'Africa/Abidjan' => + array ( + 'gmtOffset' => 0, + ), + 'Africa/Djibouti' => + array ( + 'gmtOffset' => 180, + ), + 'Africa/Cairo' => + array ( + 'gmtOffset' => 120, + 'dstOffset' => 60, + 'dstMonth' => 4, + 'dstStartday' => -1, + 'dstWeekday' => 5, + 'stdMonth' => 9, + 'stdStartday' => -1, + 'stdWeekday' => 4, + 'dstStartTimeSec' => 0, + 'stdStartTimeSec' => 82800, + ), + 'Africa/Malabo' => + array ( + 'gmtOffset' => 60, + ), + 'Africa/Asmera' => + array ( + 'gmtOffset' => 180, + ), + 'Africa/Addis_Ababa' => + array ( + 'gmtOffset' => 180, + ), + 'Africa/Libreville' => + array ( + 'gmtOffset' => 60, + ), + 'Africa/Banjul' => + array ( + 'gmtOffset' => 0, + ), + 'Africa/Accra' => + array ( + 'gmtOffset' => 0, + ), + 'Africa/Conakry' => + array ( + 'gmtOffset' => 0, + ), + 'Africa/Bissau' => + array ( + 'gmtOffset' => 0, + ), + 'Africa/Nairobi' => + array ( + 'gmtOffset' => 180, + ), + 'Africa/Maseru' => + array ( + 'gmtOffset' => 120, + ), + 'Africa/Monrovia' => + array ( + 'gmtOffset' => 0, + ), + 'Africa/Tripoli' => + array ( + 'gmtOffset' => 120, + ), + 'Indian/Antananarivo' => + array ( + 'gmtOffset' => 180, + ), + 'Africa/Blantyre' => + array ( + 'gmtOffset' => 120, + ), + 'Africa/Bamako' => + array ( + 'gmtOffset' => 0, + ), + 'Africa/Nouakchott' => + array ( + 'gmtOffset' => 0, + ), + 'Indian/Mauritius' => + array ( + 'gmtOffset' => 240, + ), + 'Indian/Mayotte' => + array ( + 'gmtOffset' => 180, + ), + 'Africa/Casablanca' => + array ( + 'gmtOffset' => 0, + ), + 'Africa/El_Aaiun' => + array ( + 'gmtOffset' => 0, + ), + 'Africa/Maputo' => + array ( + 'gmtOffset' => 120, + ), + 'Africa/Windhoek' => + array ( + 'gmtOffset' => 60, + 'dstOffset' => 60, + 'dstMonth' => 9, + 'dstStartday' => 1, + 'dstWeekday' => 0, + 'stdMonth' => 4, + 'stdStartday' => 1, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 7200, + 'stdStartTimeSec' => 3600, + ), + 'Africa/Niamey' => + array ( + 'gmtOffset' => 60, + ), + 'Africa/Lagos' => + array ( + 'gmtOffset' => 60, + ), + 'Indian/Reunion' => + array ( + 'gmtOffset' => 240, + ), + 'Africa/Kigali' => + array ( + 'gmtOffset' => 120, + ), + 'Atlantic/St_Helena' => + array ( + 'gmtOffset' => 0, + ), + 'Africa/Sao_Tome' => + array ( + 'gmtOffset' => 0, + ), + 'Africa/Dakar' => + array ( + 'gmtOffset' => 0, + ), + 'Indian/Mahe' => + array ( + 'gmtOffset' => 240, + ), + 'Africa/Freetown' => + array ( + 'gmtOffset' => 0, + ), + 'Africa/Mogadishu' => + array ( + 'gmtOffset' => 180, + ), + 'Africa/Johannesburg' => + array ( + 'gmtOffset' => 120, + ), + 'Africa/Khartoum' => + array ( + 'gmtOffset' => 180, + ), + 'Africa/Mbabane' => + array ( + 'gmtOffset' => 120, + ), + 'Africa/Dar_es_Salaam' => + array ( + 'gmtOffset' => 180, + ), + 'Africa/Lome' => + array ( + 'gmtOffset' => 0, + ), + 'Africa/Tunis' => + array ( + 'gmtOffset' => 60, + 'dstOffset' => 60, + 'dstMonth' => 5, + 'dstStartday' => 1, + 'dstWeekday' => -1, + 'stdMonth' => 9, + 'stdStartday' => 30, + 'stdWeekday' => -1, + 'dstStartTimeSec' => 0, + 'stdStartTimeSec' => 3600, + ), + 'Africa/Kampala' => + array ( + 'gmtOffset' => 180, + ), + 'Africa/Lusaka' => + array ( + 'gmtOffset' => 120, + ), + 'Africa/Harare' => + array ( + 'gmtOffset' => 120, + ), + 'Antarctica/Casey' => + array ( + 'gmtOffset' => 480, + ), + 'Antarctica/Davis' => + array ( + 'gmtOffset' => 420, + ), + 'Antarctica/Mawson' => + array ( + 'gmtOffset' => 360, + ), + 'Indian/Kerguelen' => + array ( + 'gmtOffset' => 300, + ), + 'Antarctica/DumontDUrville' => + array ( + 'gmtOffset' => 600, + ), + 'Antarctica/Syowa' => + array ( + 'gmtOffset' => 180, + ), + 'Antarctica/Vostok' => + array ( + 'gmtOffset' => 360, + ), + 'Antarctica/Rothera' => + array ( + 'gmtOffset' => -180, + ), + 'Antarctica/Palmer' => + array ( + 'gmtOffset' => -240, + 'dstOffset' => 60, + 'dstMonth' => 10, + 'dstStartday' => 9, + 'dstWeekday' => 0, + 'stdMonth' => 3, + 'stdStartday' => 9, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 0, + 'stdStartTimeSec' => -3600, + ), + 'Antarctica/McMurdo' => + array ( + 'gmtOffset' => 720, + 'dstOffset' => 60, + 'dstMonth' => 10, + 'dstStartday' => 1, + 'dstWeekday' => 0, + 'stdMonth' => 3, + 'stdStartday' => 15, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 7200, + 'stdStartTimeSec' => 7200, + ), + 'Asia/Kabul' => + array ( + 'gmtOffset' => 270, + ), + 'Asia/Yerevan' => + array ( + 'gmtOffset' => 240, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => -1, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => -1, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 7200, + 'stdStartTimeSec' => 7200, + ), + 'Asia/Baku' => + array ( + 'gmtOffset' => 240, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => -1, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => -1, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 3600, + 'stdStartTimeSec' => 0, + ), + 'Asia/Bahrain' => + array ( + 'gmtOffset' => 180, + ), + 'Asia/Dhaka' => + array ( + 'gmtOffset' => 360, + ), + 'Asia/Thimphu' => + array ( + 'gmtOffset' => 360, + ), + 'Indian/Chagos' => + array ( + 'gmtOffset' => 360, + ), + 'Asia/Brunei' => + array ( + 'gmtOffset' => 480, + ), + 'Asia/Rangoon' => + array ( + 'gmtOffset' => 390, + ), + 'Asia/Phnom_Penh' => + array ( + 'gmtOffset' => 420, + ), + 'Asia/Beijing' => + array ( + 'gmtOffset' => 480, + ), + 'Asia/Harbin' => + array ( + 'gmtOffset' => 480, + ), + 'Asia/Shanghai' => + array ( + 'gmtOffset' => 480, + ), + 'Asia/Chongqing' => + array ( + 'gmtOffset' => 480, + ), + 'Asia/Urumqi' => + array ( + 'gmtOffset' => 480, + ), + 'Asia/Kashgar' => + array ( + 'gmtOffset' => 480, + ), + 'Asia/Hong_Kong' => + array ( + 'gmtOffset' => 480, + ), + 'Asia/Taipei' => + array ( + 'gmtOffset' => 480, + ), + 'Asia/Macau' => + array ( + 'gmtOffset' => 480, + ), + 'Asia/Nicosia' => + array ( + 'gmtOffset' => 120, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => -1, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => -1, + 'stdWeekday' => 0, + 'dstStartTimeSec' => -3600, + 'stdStartTimeSec' => -3600, + ), + 'Asia/Tbilisi' => + array ( + 'gmtOffset' => 180, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => -1, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => -1, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 7200, + 'stdStartTimeSec' => 7200, + ), + 'Asia/Dili' => + array ( + 'gmtOffset' => 540, + ), + 'Asia/Calcutta' => + array ( + 'gmtOffset' => 330, + ), + 'Asia/Jakarta' => + array ( + 'gmtOffset' => 420, + ), + 'Asia/Pontianak' => + array ( + 'gmtOffset' => 420, + ), + 'Asia/Makassar' => + array ( + 'gmtOffset' => 480, + ), + 'Asia/Jayapura' => + array ( + 'gmtOffset' => 540, + ), + 'Asia/Tehran' => + array ( + 'gmtOffset' => 210, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => 22, + 'dstWeekday' => -1, + 'stdMonth' => 9, + 'stdStartday' => 22, + 'stdWeekday' => -1, + 'dstStartTimeSec' => 0, + 'stdStartTimeSec' => -3600, + ), + 'Asia/Baghdad' => + array ( + 'gmtOffset' => 180, + 'dstOffset' => 60, + 'dstMonth' => 4, + 'dstStartday' => 1, + 'dstWeekday' => -1, + 'stdMonth' => 10, + 'stdStartday' => 1, + 'stdWeekday' => -1, + 'dstStartTimeSec' => 10800, + 'stdStartTimeSec' => 10800, + ), + 'Asia/Jerusalem' => + array ( + 'gmtOffset' => 120, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => 24, + 'dstWeekday' => 5, + 'stdMonth' => 9, + 'stdStartday' => 12, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 7200, + 'stdStartTimeSec' => 3600, + ), + 'Asia/Tokyo' => + array ( + 'gmtOffset' => 540, + ), + 'Asia/Amman' => + array ( + 'gmtOffset' => 120, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => -1, + 'dstWeekday' => 4, + 'stdMonth' => 9, + 'stdStartday' => -1, + 'stdWeekday' => 4, + 'dstStartTimeSec' => 0, + 'stdStartTimeSec' => 0, + ), + 'Asia/Almaty' => + array ( + 'gmtOffset' => 360, + ), + 'Asia/Qyzylorda' => + array ( + 'gmtOffset' => 360, + ), + 'Asia/Aqtobe' => + array ( + 'gmtOffset' => 300, + ), + 'Asia/Aqtau' => + array ( + 'gmtOffset' => 300, + ), + 'Asia/Oral' => + array ( + 'gmtOffset' => 300, + ), + 'Asia/Bishkek' => + array ( + 'gmtOffset' => 360, + ), + 'Asia/Seoul' => + array ( + 'gmtOffset' => 540, + ), + 'Asia/Pyongyang' => + array ( + 'gmtOffset' => 540, + ), + 'Asia/Kuwait' => + array ( + 'gmtOffset' => 180, + ), + 'Asia/Vientiane' => + array ( + 'gmtOffset' => 420, + ), + 'Asia/Beirut' => + array ( + 'gmtOffset' => 120, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => -1, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => -1, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 0, + 'stdStartTimeSec' => -3600, + ), + 'Asia/Kuala_Lumpur' => + array ( + 'gmtOffset' => 480, + ), + 'Asia/Kuching' => + array ( + 'gmtOffset' => 480, + ), + 'Indian/Maldives' => + array ( + 'gmtOffset' => 300, + ), + 'Asia/Hovd' => + array ( + 'gmtOffset' => 420, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => -1, + 'dstWeekday' => 6, + 'stdMonth' => 9, + 'stdStartday' => -1, + 'stdWeekday' => 6, + 'dstStartTimeSec' => 7200, + 'stdStartTimeSec' => 3600, + ), + 'Asia/Ulaanbaatar' => + array ( + 'gmtOffset' => 480, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => -1, + 'dstWeekday' => 6, + 'stdMonth' => 9, + 'stdStartday' => -1, + 'stdWeekday' => 6, + 'dstStartTimeSec' => 7200, + 'stdStartTimeSec' => 3600, + ), + 'Asia/Choibalsan' => + array ( + 'gmtOffset' => 540, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => -1, + 'dstWeekday' => 6, + 'stdMonth' => 9, + 'stdStartday' => -1, + 'stdWeekday' => 6, + 'dstStartTimeSec' => 7200, + 'stdStartTimeSec' => 3600, + ), + 'Asia/Katmandu' => + array ( + 'gmtOffset' => 345, + ), + 'Asia/Muscat' => + array ( + 'gmtOffset' => 240, + ), + 'Asia/Karachi' => + array ( + 'gmtOffset' => 300, + ), + 'Asia/Gaza' => + array ( + 'gmtOffset' => 120, + 'dstOffset' => 60, + 'dstMonth' => 4, + 'dstStartday' => 15, + 'dstWeekday' => 5, + 'stdMonth' => 10, + 'stdStartday' => 15, + 'stdWeekday' => 5, + 'dstStartTimeSec' => 0, + 'stdStartTimeSec' => -3600, + ), + 'Asia/Manila' => + array ( + 'gmtOffset' => 480, + ), + 'Asia/Qatar' => + array ( + 'gmtOffset' => 180, + ), + 'Asia/Riyadh' => + array ( + 'gmtOffset' => 180, + ), + 'Asia/Singapore' => + array ( + 'gmtOffset' => 480, + ), + 'Asia/Colombo' => + array ( + 'gmtOffset' => 360, + ), + 'Asia/Damascus' => + array ( + 'gmtOffset' => 120, + 'dstOffset' => 60, + 'dstMonth' => 4, + 'dstStartday' => 1, + 'dstWeekday' => -1, + 'stdMonth' => 10, + 'stdStartday' => 1, + 'stdWeekday' => -1, + 'dstStartTimeSec' => 0, + 'stdStartTimeSec' => -3600, + ), + 'Asia/Dushanbe' => + array ( + 'gmtOffset' => 300, + ), + 'Asia/Bangkok' => + array ( + 'gmtOffset' => 420, + ), + 'Asia/Ashgabat' => + array ( + 'gmtOffset' => 300, + ), + 'Asia/Dubai' => + array ( + 'gmtOffset' => 240, + ), + 'Asia/Samarkand' => + array ( + 'gmtOffset' => 300, + ), + 'Asia/Tashkent' => + array ( + 'gmtOffset' => 300, + ), + 'Asia/Saigon' => + array ( + 'gmtOffset' => 420, + ), + 'Asia/Aden' => + array ( + 'gmtOffset' => 180, + ), + 'Australia/Darwin' => + array ( + 'gmtOffset' => 570, + ), + 'Australia/Perth' => + array ( + 'gmtOffset' => 480, + ), + 'Australia/Brisbane' => + array ( + 'gmtOffset' => 600, + ), + 'Australia/Lindeman' => + array ( + 'gmtOffset' => 600, + ), + 'Australia/Adelaide' => + array ( + 'gmtOffset' => 570, + 'dstOffset' => 60, + 'dstMonth' => 10, + 'dstStartday' => 1, + 'dstWeekday' => 0, + 'stdMonth' => 4, + 'stdStartday' => 1, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 7200, + 'stdStartTimeSec' => 7200, + ), + 'Australia/Hobart' => + array ( + 'gmtOffset' => 600, + 'dstOffset' => 60, + 'dstMonth' => 10, + 'dstStartday' => 1, + 'dstWeekday' => 0, + 'stdMonth' => 4, + 'stdStartday' => 1, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 7200, + 'stdStartTimeSec' => 7200, + ), + 'Australia/Currie' => + array ( + 'gmtOffset' => 600, + 'dstOffset' => 60, + 'dstMonth' => 10, + 'dstStartday' => 1, + 'dstWeekday' => 0, + 'stdMonth' => 4, + 'stdStartday' => 1, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 7200, + 'stdStartTimeSec' => 7200, + ), + 'Australia/Melbourne' => + array ( + 'gmtOffset' => 600, + 'dstOffset' => 60, + 'dstMonth' => 10, + 'dstStartday' => 1, + 'dstWeekday' => 0, + 'stdMonth' => 4, + 'stdStartday' => 1, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 7200, + 'stdStartTimeSec' => 7200, + ), + 'Australia/Sydney' => + array ( + 'gmtOffset' => 600, + 'dstOffset' => 60, + 'dstMonth' => 10, + 'dstStartday' => 1, + 'dstWeekday' => 0, + 'stdMonth' => 4, + 'stdStartday' => 1, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 7200, + 'stdStartTimeSec' => 7200, + ), + 'Australia/Broken_Hill' => + array ( + 'gmtOffset' => 570, + 'dstOffset' => 60, + 'dstMonth' => 10, + 'dstStartday' => 1, + 'dstWeekday' => 0, + 'stdMonth' => 4, + 'stdStartday' => 1, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 7200, + 'stdStartTimeSec' => 7200, + ), + 'Indian/Christmas' => + array ( + 'gmtOffset' => 420, + ), + 'Pacific/Rarotonga' => + array ( + 'gmtOffset' => -600, + ), + 'Indian/Cocos' => + array ( + 'gmtOffset' => 390, + ), + 'Pacific/Fiji' => + array ( + 'gmtOffset' => 720, + ), + 'Pacific/Gambier' => + array ( + 'gmtOffset' => -540, + ), + 'Pacific/Marquesas' => + array ( + 'gmtOffset' => -570, + ), + 'Pacific/Tahiti' => + array ( + 'gmtOffset' => -600, + ), + 'Pacific/Guam' => + array ( + 'gmtOffset' => 600, + ), + 'Pacific/Tarawa' => + array ( + 'gmtOffset' => 720, + ), + 'Pacific/Enderbury' => + array ( + 'gmtOffset' => 780, + ), + 'Pacific/Kiritimati' => + array ( + 'gmtOffset' => 840, + ), + 'Pacific/Saipan' => + array ( + 'gmtOffset' => 600, + ), + 'Pacific/Majuro' => + array ( + 'gmtOffset' => 720, + ), + 'Pacific/Kwajalein' => + array ( + 'gmtOffset' => 720, + ), + 'Pacific/Truk' => + array ( + 'gmtOffset' => 600, + ), + 'Pacific/Ponape' => + array ( + 'gmtOffset' => 660, + ), + 'Pacific/Kosrae' => + array ( + 'gmtOffset' => 660, + ), + 'Pacific/Nauru' => + array ( + 'gmtOffset' => 720, + ), + 'Pacific/Noumea' => + array ( + 'gmtOffset' => 660, + ), + 'Pacific/Auckland' => + array ( + 'gmtOffset' => 720, + 'dstOffset' => 60, + 'dstMonth' => 10, + 'dstStartday' => 1, + 'dstWeekday' => 0, + 'stdMonth' => 3, + 'stdStartday' => 15, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 7200, + 'stdStartTimeSec' => 7200, + ), + 'Pacific/Chatham' => + array ( + 'gmtOffset' => 765, + 'dstOffset' => 60, + 'dstMonth' => 10, + 'dstStartday' => 1, + 'dstWeekday' => 0, + 'stdMonth' => 3, + 'stdStartday' => 15, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 9900, + 'stdStartTimeSec' => 9900, + ), + 'Pacific/Niue' => + array ( + 'gmtOffset' => -660, + ), + 'Pacific/Norfolk' => + array ( + 'gmtOffset' => 690, + ), + 'Pacific/Palau' => + array ( + 'gmtOffset' => 540, + ), + 'Pacific/Port_Moresby' => + array ( + 'gmtOffset' => 600, + ), + 'Pacific/Pitcairn' => + array ( + 'gmtOffset' => -480, + ), + 'Pacific/Pago_Pago' => + array ( + 'gmtOffset' => -660, + ), + 'Pacific/Apia' => + array ( + 'gmtOffset' => -660, + ), + 'Pacific/Guadalcanal' => + array ( + 'gmtOffset' => 660, + ), + 'Pacific/Fakaofo' => + array ( + 'gmtOffset' => -600, + ), + 'Pacific/Tongatapu' => + array ( + 'gmtOffset' => 780, + ), + 'Pacific/Funafuti' => + array ( + 'gmtOffset' => 720, + ), + 'Pacific/Johnston' => + array ( + 'gmtOffset' => -600, + ), + 'Pacific/Midway' => + array ( + 'gmtOffset' => -660, + ), + 'Pacific/Wake' => + array ( + 'gmtOffset' => 720, + ), + 'Pacific/Efate' => + array ( + 'gmtOffset' => 660, + ), + 'Pacific/Wallis' => + array ( + 'gmtOffset' => 720, + ), + 'Europe/London' => + array ( + 'gmtOffset' => 0, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => -1, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => -1, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 3600, + 'stdStartTimeSec' => 3600, + ), + 'Europe/Dublin' => + array ( + 'gmtOffset' => 0, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => -1, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => -1, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 3600, + 'stdStartTimeSec' => 3600, + ), + 'WET' => + array ( + 'gmtOffset' => 0, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => -1, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => -1, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 3600, + 'stdStartTimeSec' => 3600, + ), + 'CET' => + array ( + 'gmtOffset' => 60, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => -1, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => -1, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 7200, + 'stdStartTimeSec' => 7200, + ), + 'MET' => + array ( + 'gmtOffset' => 60, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => -1, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => -1, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 7200, + 'stdStartTimeSec' => 7200, + ), + 'EET' => + array ( + 'gmtOffset' => 120, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => -1, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => -1, + 'stdWeekday' => 0, + 'dstStartTimeSec' => -3600, + 'stdStartTimeSec' => -3600, + ), + 'Europe/Tirane' => + array ( + 'gmtOffset' => 60, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => -1, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => -1, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 0, + 'stdStartTimeSec' => 0, + ), + 'Europe/Andorra' => + array ( + 'gmtOffset' => 60, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => -1, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => -1, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 0, + 'stdStartTimeSec' => 0, + ), + 'Europe/Vienna' => + array ( + 'gmtOffset' => 60, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => -1, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => -1, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 0, + 'stdStartTimeSec' => 0, + ), + 'Europe/Minsk' => + array ( + 'gmtOffset' => 120, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => -1, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => -1, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 7200, + 'stdStartTimeSec' => 7200, + ), + 'Europe/Brussels' => + array ( + 'gmtOffset' => 60, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => -1, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => -1, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 0, + 'stdStartTimeSec' => 0, + ), + 'Europe/Sofia' => + array ( + 'gmtOffset' => 120, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => -1, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => -1, + 'stdWeekday' => 0, + 'dstStartTimeSec' => -3600, + 'stdStartTimeSec' => -3600, + ), + 'Europe/Prague' => + array ( + 'gmtOffset' => 60, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => -1, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => -1, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 0, + 'stdStartTimeSec' => 0, + ), + 'Europe/Copenhagen' => + array ( + 'gmtOffset' => 60, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => -1, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => -1, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 0, + 'stdStartTimeSec' => 0, + ), + 'Atlantic/Faeroe' => + array ( + 'gmtOffset' => 0, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => -1, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => -1, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 3600, + 'stdStartTimeSec' => 3600, + ), + 'America/Danmarkshavn' => + array ( + 'gmtOffset' => 0, + ), + 'America/Scoresbysund' => + array ( + 'gmtOffset' => -60, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => -1, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => -1, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 7200, + 'stdStartTimeSec' => 7200, + ), + 'America/Godthab' => + array ( + 'gmtOffset' => -180, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => -1, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => -1, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 14400, + 'stdStartTimeSec' => 14400, + ), + 'America/Thule' => + array ( + 'gmtOffset' => -240, + 'dstOffset' => 60, + 'dstMonth' => 4, + 'dstStartday' => 1, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => -1, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 7200, + 'stdStartTimeSec' => 3600, + ), + 'Europe/Tallinn' => + array ( + 'gmtOffset' => 120, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => -1, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => -1, + 'stdWeekday' => 0, + 'dstStartTimeSec' => -3600, + 'stdStartTimeSec' => -3600, + ), + 'Europe/Helsinki' => + array ( + 'gmtOffset' => 120, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => -1, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => -1, + 'stdWeekday' => 0, + 'dstStartTimeSec' => -3600, + 'stdStartTimeSec' => -3600, + ), + 'Europe/Paris' => + array ( + 'gmtOffset' => 60, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => -1, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => -1, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 0, + 'stdStartTimeSec' => 0, + ), + 'Europe/Berlin' => + array ( + 'gmtOffset' => 60, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => -1, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => -1, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 0, + 'stdStartTimeSec' => 0, + ), + 'Europe/Gibraltar' => + array ( + 'gmtOffset' => 60, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => -1, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => -1, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 0, + 'stdStartTimeSec' => 0, + ), + 'Europe/Athens' => + array ( + 'gmtOffset' => 120, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => -1, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => -1, + 'stdWeekday' => 0, + 'dstStartTimeSec' => -3600, + 'stdStartTimeSec' => -3600, + ), + 'Europe/Budapest' => + array ( + 'gmtOffset' => 60, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => -1, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => -1, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 0, + 'stdStartTimeSec' => 0, + ), + 'Atlantic/Reykjavik' => + array ( + 'gmtOffset' => 0, + ), + 'Europe/Rome' => + array ( + 'gmtOffset' => 60, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => -1, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => -1, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 0, + 'stdStartTimeSec' => 0, + ), + 'Europe/Riga' => + array ( + 'gmtOffset' => 120, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => -1, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => -1, + 'stdWeekday' => 0, + 'dstStartTimeSec' => -3600, + 'stdStartTimeSec' => -3600, + ), + 'Europe/Vaduz' => + array ( + 'gmtOffset' => 60, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => -1, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => -1, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 0, + 'stdStartTimeSec' => 0, + ), + 'Europe/Vilnius' => + array ( + 'gmtOffset' => 120, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => -1, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => -1, + 'stdWeekday' => 0, + 'dstStartTimeSec' => -3600, + 'stdStartTimeSec' => -3600, + ), + 'Europe/Luxembourg' => + array ( + 'gmtOffset' => 60, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => -1, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => -1, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 0, + 'stdStartTimeSec' => 0, + ), + 'Europe/Malta' => + array ( + 'gmtOffset' => 60, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => -1, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => -1, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 0, + 'stdStartTimeSec' => 0, + ), + 'Europe/Chisinau' => + array ( + 'gmtOffset' => 120, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => -1, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => -1, + 'stdWeekday' => 0, + 'dstStartTimeSec' => -3600, + 'stdStartTimeSec' => -3600, + ), + 'Europe/Monaco' => + array ( + 'gmtOffset' => 60, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => -1, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => -1, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 0, + 'stdStartTimeSec' => 0, + ), + 'Europe/Amsterdam' => + array ( + 'gmtOffset' => 60, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => -1, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => -1, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 0, + 'stdStartTimeSec' => 0, + ), + 'Europe/Oslo' => + array ( + 'gmtOffset' => 60, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => -1, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => -1, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 0, + 'stdStartTimeSec' => 0, + ), + 'Europe/Warsaw' => + array ( + 'gmtOffset' => 60, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => -1, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => -1, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 0, + 'stdStartTimeSec' => 0, + ), + 'Europe/Lisbon' => + array ( + 'gmtOffset' => 0, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => -1, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => -1, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 3600, + 'stdStartTimeSec' => 3600, + ), + 'Atlantic/Azores' => + array ( + 'gmtOffset' => -60, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => -1, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => -1, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 7200, + 'stdStartTimeSec' => 7200, + ), + 'Atlantic/Madeira' => + array ( + 'gmtOffset' => 0, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => -1, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => -1, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 3600, + 'stdStartTimeSec' => 3600, + ), + 'Europe/Bucharest' => + array ( + 'gmtOffset' => 120, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => -1, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => -1, + 'stdWeekday' => 0, + 'dstStartTimeSec' => -3600, + 'stdStartTimeSec' => -3600, + ), + 'Europe/Kaliningrad' => + array ( + 'gmtOffset' => 120, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => -1, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => -1, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 7200, + 'stdStartTimeSec' => 7200, + ), + 'Europe/Moscow' => + array ( + 'gmtOffset' => 180, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => -1, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => -1, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 7200, + 'stdStartTimeSec' => 7200, + ), + 'Europe/Samara' => + array ( + 'gmtOffset' => 240, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => -1, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => -1, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 7200, + 'stdStartTimeSec' => 7200, + ), + 'Asia/Yekaterinburg' => + array ( + 'gmtOffset' => 300, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => -1, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => -1, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 7200, + 'stdStartTimeSec' => 7200, + ), + 'Asia/Omsk' => + array ( + 'gmtOffset' => 360, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => -1, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => -1, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 7200, + 'stdStartTimeSec' => 7200, + ), + 'Asia/Novosibirsk' => + array ( + 'gmtOffset' => 360, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => -1, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => -1, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 7200, + 'stdStartTimeSec' => 7200, + ), + 'Asia/Krasnoyarsk' => + array ( + 'gmtOffset' => 420, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => -1, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => -1, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 7200, + 'stdStartTimeSec' => 7200, + ), + 'Asia/Irkutsk' => + array ( + 'gmtOffset' => 480, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => -1, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => -1, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 7200, + 'stdStartTimeSec' => 7200, + ), + 'Asia/Yakutsk' => + array ( + 'gmtOffset' => 540, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => -1, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => -1, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 7200, + 'stdStartTimeSec' => 7200, + ), + 'Asia/Vladivostok' => + array ( + 'gmtOffset' => 600, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => -1, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => -1, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 7200, + 'stdStartTimeSec' => 7200, + ), + 'Asia/Sakhalin' => + array ( + 'gmtOffset' => 600, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => -1, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => -1, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 7200, + 'stdStartTimeSec' => 7200, + ), + 'Asia/Magadan' => + array ( + 'gmtOffset' => 660, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => -1, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => -1, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 7200, + 'stdStartTimeSec' => 7200, + ), + 'Asia/Kamchatka' => + array ( + 'gmtOffset' => 720, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => -1, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => -1, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 7200, + 'stdStartTimeSec' => 7200, + ), + 'Asia/Anadyr' => + array ( + 'gmtOffset' => 720, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => -1, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => -1, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 7200, + 'stdStartTimeSec' => 7200, + ), + 'Europe/Belgrade' => + array ( + 'gmtOffset' => 60, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => -1, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => -1, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 0, + 'stdStartTimeSec' => 0, + ), + 'Europe/Madrid' => + array ( + 'gmtOffset' => 60, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => -1, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => -1, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 0, + 'stdStartTimeSec' => 0, + ), + 'Africa/Ceuta' => + array ( + 'gmtOffset' => 60, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => -1, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => -1, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 0, + 'stdStartTimeSec' => 0, + ), + 'Atlantic/Canary' => + array ( + 'gmtOffset' => 0, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => -1, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => -1, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 3600, + 'stdStartTimeSec' => 3600, + ), + 'Europe/Stockholm' => + array ( + 'gmtOffset' => 60, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => -1, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => -1, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 0, + 'stdStartTimeSec' => 0, + ), + 'Europe/Zurich' => + array ( + 'gmtOffset' => 60, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => -1, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => -1, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 0, + 'stdStartTimeSec' => 0, + ), + 'Europe/Istanbul' => + array ( + 'gmtOffset' => 120, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => -1, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => -1, + 'stdWeekday' => 0, + 'dstStartTimeSec' => -3600, + 'stdStartTimeSec' => -3600, + ), + 'Europe/Kiev' => + array ( + 'gmtOffset' => 120, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => -1, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => -1, + 'stdWeekday' => 0, + 'dstStartTimeSec' => -3600, + 'stdStartTimeSec' => -3600, + ), + 'Europe/Uzhgorod' => + array ( + 'gmtOffset' => 120, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => -1, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => -1, + 'stdWeekday' => 0, + 'dstStartTimeSec' => -3600, + 'stdStartTimeSec' => -3600, + ), + 'Europe/Zaporozhye' => + array ( + 'gmtOffset' => 120, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => -1, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => -1, + 'stdWeekday' => 0, + 'dstStartTimeSec' => -3600, + 'stdStartTimeSec' => -3600, + ), + 'Europe/Simferopol' => + array ( + 'gmtOffset' => 120, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => -1, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => -1, + 'stdWeekday' => 0, + 'dstStartTimeSec' => -3600, + 'stdStartTimeSec' => -3600, + ), + 'America/New_York' => + array ( + 'gmtOffset' => -300, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => 7, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => 0, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 7200, + 'stdStartTimeSec' => 3600, + ), + 'America/Chicago' => + array ( + 'gmtOffset' => -360, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => 7, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => 0, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 7200, + 'stdStartTimeSec' => 3600, + ), + 'America/North_Dakota/Center' => + array ( + 'gmtOffset' => -360, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => 7, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => 0, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 7200, + 'stdStartTimeSec' => 3600, + ), + 'America/Denver' => + array ( + 'gmtOffset' => -420, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => 7, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => 0, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 7200, + 'stdStartTimeSec' => 3600, + ), + 'America/Los_Angeles' => + array ( + 'gmtOffset' => -480, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => 7, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => 0, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 7200, + 'stdStartTimeSec' => 3600, + ), + 'America/Juneau' => + array ( + 'gmtOffset' => -540, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => 7, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => 0, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 7200, + 'stdStartTimeSec' => 3600, + ), + 'America/Yakutat' => + array ( + 'gmtOffset' => -540, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => 7, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => 0, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 7200, + 'stdStartTimeSec' => 3600, + ), + 'America/Anchorage' => + array ( + 'gmtOffset' => -540, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => 7, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => 0, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 7200, + 'stdStartTimeSec' => 3600, + ), + 'America/Nome' => + array ( + 'gmtOffset' => -540, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => 7, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => 0, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 7200, + 'stdStartTimeSec' => 3600, + ), + 'America/Adak' => + array ( + 'gmtOffset' => -600, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => 7, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => 0, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 7200, + 'stdStartTimeSec' => 3600, + ), + 'Pacific/Honolulu' => + array ( + 'gmtOffset' => -600, + ), + 'America/Phoenix' => + array ( + 'gmtOffset' => -420, + ), + 'America/Boise' => + array ( + 'gmtOffset' => -420, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => 7, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => 0, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 7200, + 'stdStartTimeSec' => 3600, + ), + 'America/Indiana/Indianapolis' => + array ( + 'gmtOffset' => -300, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => 7, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => 0, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 7200, + 'stdStartTimeSec' => 3600, + ), + 'America/Indiana/Marengo' => + array ( + 'gmtOffset' => -300, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => 7, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => 0, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 7200, + 'stdStartTimeSec' => 3600, + ), + 'America/Indiana/Knox' => + array ( + 'gmtOffset' => -300, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => 7, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => 0, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 7200, + 'stdStartTimeSec' => 3600, + ), + 'America/Indiana/Vevay' => + array ( + 'gmtOffset' => -300, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => 7, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => 0, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 7200, + 'stdStartTimeSec' => 3600, + ), + 'America/Kentucky/Louisville' => + array ( + 'gmtOffset' => -300, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => 7, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => 0, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 7200, + 'stdStartTimeSec' => 3600, + ), + 'America/Kentucky/Monticello' => + array ( + 'gmtOffset' => -300, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => 7, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => 0, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 7200, + 'stdStartTimeSec' => 3600, + ), + 'America/Detroit' => + array ( + 'gmtOffset' => -300, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => 7, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => 0, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 7200, + 'stdStartTimeSec' => 3600, + ), + 'America/Menominee' => + array ( + 'gmtOffset' => -360, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => 7, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => 0, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 7200, + 'stdStartTimeSec' => 3600, + ), + 'America/St_Johns' => + array ( + 'gmtOffset' => -210, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => 7, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => 0, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 60, + 'stdStartTimeSec' => -3540, + ), + 'America/Goose_Bay' => + array ( + 'gmtOffset' => -240, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => 7, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => 0, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 60, + 'stdStartTimeSec' => -3540, + ), + 'America/Halifax' => + array ( + 'gmtOffset' => -240, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => 7, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => 0, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 7200, + 'stdStartTimeSec' => 3600, + ), + 'America/Glace_Bay' => + array ( + 'gmtOffset' => -240, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => 7, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => 0, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 7200, + 'stdStartTimeSec' => 3600, + ), + 'America/Montreal' => + array ( + 'gmtOffset' => -300, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => 7, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => 0, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 7200, + 'stdStartTimeSec' => 3600, + ), + 'America/Toronto' => + array ( + 'gmtOffset' => -300, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => 7, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => 0, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 7200, + 'stdStartTimeSec' => 3600, + ), + 'America/Thunder_Bay' => + array ( + 'gmtOffset' => -300, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => 7, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => 0, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 7200, + 'stdStartTimeSec' => 3600, + ), + 'America/Nipigon' => + array ( + 'gmtOffset' => -300, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => 7, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => 0, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 7200, + 'stdStartTimeSec' => 3600, + ), + 'America/Rainy_River' => + array ( + 'gmtOffset' => -360, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => 7, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => 0, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 7200, + 'stdStartTimeSec' => 3600, + ), + 'America/Winnipeg' => + array ( + 'gmtOffset' => -360, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => 7, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => 0, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 7200, + 'stdStartTimeSec' => 7200, + ), + 'America/Regina' => + array ( + 'gmtOffset' => -360, + ), + 'America/Swift_Current' => + array ( + 'gmtOffset' => -360, + ), + 'America/Edmonton' => + array ( + 'gmtOffset' => -420, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => 7, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => 0, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 7200, + 'stdStartTimeSec' => 3600, + ), + 'America/Vancouver' => + array ( + 'gmtOffset' => -480, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => 7, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => 0, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 7200, + 'stdStartTimeSec' => 3600, + ), + 'America/Dawson_Creek' => + array ( + 'gmtOffset' => -420, + ), + 'America/Pangnirtung' => + array ( + 'gmtOffset' => -300, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => 7, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => 0, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 7200, + 'stdStartTimeSec' => 3600, + ), + 'America/Iqaluit' => + array ( + 'gmtOffset' => -300, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => 7, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => 0, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 7200, + 'stdStartTimeSec' => 3600, + ), + 'America/Coral_Harbour' => + array ( + 'gmtOffset' => -300, + ), + 'America/Rankin_Inlet' => + array ( + 'gmtOffset' => -360, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => 7, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => 0, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 7200, + 'stdStartTimeSec' => 3600, + ), + 'America/Cambridge_Bay' => + array ( + 'gmtOffset' => -420, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => 7, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => 0, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 7200, + 'stdStartTimeSec' => 3600, + ), + 'America/Yellowknife' => + array ( + 'gmtOffset' => -420, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => 7, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => 0, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 7200, + 'stdStartTimeSec' => 3600, + ), + 'America/Inuvik' => + array ( + 'gmtOffset' => -420, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => 7, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => 0, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 7200, + 'stdStartTimeSec' => 3600, + ), + 'America/Whitehorse' => + array ( + 'gmtOffset' => -480, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => 7, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => 0, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 7200, + 'stdStartTimeSec' => 3600, + ), + 'America/Dawson' => + array ( + 'gmtOffset' => -480, + 'dstOffset' => 60, + 'dstMonth' => 3, + 'dstStartday' => 7, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => 0, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 7200, + 'stdStartTimeSec' => 3600, + ), + 'America/Cancun' => + array ( + 'gmtOffset' => -360, + 'dstOffset' => 60, + 'dstMonth' => 4, + 'dstStartday' => 1, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => -1, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 7200, + 'stdStartTimeSec' => 3600, + ), + 'America/Merida' => + array ( + 'gmtOffset' => -360, + 'dstOffset' => 60, + 'dstMonth' => 4, + 'dstStartday' => 1, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => -1, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 7200, + 'stdStartTimeSec' => 3600, + ), + 'America/Monterrey' => + array ( + 'gmtOffset' => -360, + 'dstOffset' => 60, + 'dstMonth' => 4, + 'dstStartday' => 1, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => -1, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 7200, + 'stdStartTimeSec' => 3600, + ), + 'America/Mexico_City' => + array ( + 'gmtOffset' => -360, + 'dstOffset' => 60, + 'dstMonth' => 4, + 'dstStartday' => 1, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => -1, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 7200, + 'stdStartTimeSec' => 3600, + ), + 'America/Chihuahua' => + array ( + 'gmtOffset' => -420, + 'dstOffset' => 60, + 'dstMonth' => 4, + 'dstStartday' => 1, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => -1, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 7200, + 'stdStartTimeSec' => 3600, + ), + 'America/Hermosillo' => + array ( + 'gmtOffset' => -420, + ), + 'America/Mazatlan' => + array ( + 'gmtOffset' => -420, + 'dstOffset' => 60, + 'dstMonth' => 4, + 'dstStartday' => 1, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => -1, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 7200, + 'stdStartTimeSec' => 3600, + ), + 'America/Tijuana' => + array ( + 'gmtOffset' => -480, + 'dstOffset' => 60, + 'dstMonth' => 4, + 'dstStartday' => 1, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => -1, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 7200, + 'stdStartTimeSec' => 3600, + ), + 'America/Anguilla' => + array ( + 'gmtOffset' => -240, + ), + 'America/Antigua' => + array ( + 'gmtOffset' => -240, + ), + 'America/Nassau' => + array ( + 'gmtOffset' => -300, + 'dstOffset' => 60, + 'dstMonth' => 4, + 'dstStartday' => 1, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => -1, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 7200, + 'stdStartTimeSec' => 3600, + ), + 'America/Barbados' => + array ( + 'gmtOffset' => -240, + ), + 'America/Belize' => + array ( + 'gmtOffset' => -360, + ), + 'Atlantic/Bermuda' => + array ( + 'gmtOffset' => -240, + 'dstOffset' => 60, + 'dstMonth' => 4, + 'dstStartday' => 1, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => -1, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 7200, + 'stdStartTimeSec' => 3600, + ), + 'America/Cayman' => + array ( + 'gmtOffset' => -300, + ), + 'America/Costa_Rica' => + array ( + 'gmtOffset' => -360, + ), + 'America/Havana' => + array ( + 'gmtOffset' => -300, + 'dstOffset' => 60, + 'dstMonth' => 4, + 'dstStartday' => 1, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => -1, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 0, + 'stdStartTimeSec' => 0, + ), + 'America/Dominica' => + array ( + 'gmtOffset' => -240, + ), + 'America/Santo_Domingo' => + array ( + 'gmtOffset' => -240, + ), + 'America/El_Salvador' => + array ( + 'gmtOffset' => -360, + ), + 'America/Grenada' => + array ( + 'gmtOffset' => -240, + ), + 'America/Guadeloupe' => + array ( + 'gmtOffset' => -240, + ), + 'America/Guatemala' => + array ( + 'gmtOffset' => -360, + ), + 'America/Port-au-Prince' => + array ( + 'gmtOffset' => -300, + 'dstOffset' => 60, + 'dstMonth' => 4, + 'dstStartday' => 1, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => -1, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 0, + 'stdStartTimeSec' => -3600, + ), + 'America/Tegucigalpa' => + array ( + 'gmtOffset' => -360, + ), + 'America/Jamaica' => + array ( + 'gmtOffset' => -300, + ), + 'America/Martinique' => + array ( + 'gmtOffset' => -240, + ), + 'America/Montserrat' => + array ( + 'gmtOffset' => -240, + ), + 'America/Managua' => + array ( + 'gmtOffset' => -360, + 'dstOffset' => 60, + 'dstMonth' => 4, + 'dstStartday' => 10, + 'dstWeekday' => -1, + 'stdMonth' => 9, + 'stdStartday' => 18, + 'stdWeekday' => -1, + 'dstStartTimeSec' => 0, + 'stdStartTimeSec' => -3600, + ), + 'America/Panama' => + array ( + 'gmtOffset' => -300, + ), + 'America/Puerto_Rico' => + array ( + 'gmtOffset' => -240, + ), + 'America/St_Kitts' => + array ( + 'gmtOffset' => -240, + ), + 'America/St_Lucia' => + array ( + 'gmtOffset' => -240, + ), + 'America/Miquelon' => + array ( + 'gmtOffset' => -180, + 'dstOffset' => 60, + 'dstMonth' => 4, + 'dstStartday' => 1, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => -1, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 7200, + 'stdStartTimeSec' => 3600, + ), + 'America/St_Vincent' => + array ( + 'gmtOffset' => -240, + ), + 'America/Grand_Turk' => + array ( + 'gmtOffset' => -300, + 'dstOffset' => 60, + 'dstMonth' => 4, + 'dstStartday' => 1, + 'dstWeekday' => 0, + 'stdMonth' => 10, + 'stdStartday' => -1, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 0, + 'stdStartTimeSec' => -3600, + ), + 'America/Tortola' => + array ( + 'gmtOffset' => -240, + ), + 'America/St_Thomas' => + array ( + 'gmtOffset' => -240, + ), + 'America/Argentina/Buenos_Aires' => + array ( + 'gmtOffset' => -180, + ), + 'America/Argentina/Cordoba' => + array ( + 'gmtOffset' => -180, + ), + 'America/Argentina/Tucuman' => + array ( + 'gmtOffset' => -180, + ), + 'America/Argentina/La_Rioja' => + array ( + 'gmtOffset' => -180, + ), + 'America/Argentina/San_Juan' => + array ( + 'gmtOffset' => -180, + ), + 'America/Argentina/Jujuy' => + array ( + 'gmtOffset' => -180, + ), + 'America/Argentina/Catamarca' => + array ( + 'gmtOffset' => -180, + ), + 'America/Argentina/Mendoza' => + array ( + 'gmtOffset' => -180, + ), + 'America/Argentina/Rio_Gallegos' => + array ( + 'gmtOffset' => -180, + ), + 'America/Argentina/Ushuaia' => + array ( + 'gmtOffset' => -180, + ), + 'America/Aruba' => + array ( + 'gmtOffset' => -240, + ), + 'America/La_Paz' => + array ( + 'gmtOffset' => -240, + ), + 'America/Noronha' => + array ( + 'gmtOffset' => -120, + ), + 'America/Belem' => + array ( + 'gmtOffset' => -180, + ), + 'America/Fortaleza' => + array ( + 'gmtOffset' => -180, + ), + 'America/Recife' => + array ( + 'gmtOffset' => -180, + ), + 'America/Araguaina' => + array ( + 'gmtOffset' => -180, + ), + 'America/Maceio' => + array ( + 'gmtOffset' => -180, + ), + 'America/Bahia' => + array ( + 'gmtOffset' => -180, + ), + 'America/Sao_Paulo' => + array ( + 'gmtOffset' => -180, + 'dstOffset' => 60, + 'dstMonth' => 10, + 'dstStartday' => 15, + 'dstWeekday' => 0, + 'stdMonth' => 2, + 'stdStartday' => 15, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 0, + 'stdStartTimeSec' => -3600, + ), + 'America/Campo_Grande' => + array ( + 'gmtOffset' => -240, + 'dstOffset' => 60, + 'dstMonth' => 10, + 'dstStartday' => 15, + 'dstWeekday' => 0, + 'stdMonth' => 2, + 'stdStartday' => 15, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 0, + 'stdStartTimeSec' => -3600, + ), + 'America/Cuiaba' => + array ( + 'gmtOffset' => -240, + 'dstOffset' => 60, + 'dstMonth' => 10, + 'dstStartday' => 15, + 'dstWeekday' => 0, + 'stdMonth' => 2, + 'stdStartday' => 15, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 0, + 'stdStartTimeSec' => -3600, + ), + 'America/Porto_Velho' => + array ( + 'gmtOffset' => -240, + ), + 'America/Boa_Vista' => + array ( + 'gmtOffset' => -240, + ), + 'America/Manaus' => + array ( + 'gmtOffset' => -240, + ), + 'America/Eirunepe' => + array ( + 'gmtOffset' => -300, + ), + 'America/Rio_Branco' => + array ( + 'gmtOffset' => -300, + ), + 'America/Santiago' => + array ( + 'gmtOffset' => -240, + 'dstOffset' => 60, + 'dstMonth' => 10, + 'dstStartday' => 9, + 'dstWeekday' => 0, + 'stdMonth' => 3, + 'stdStartday' => 9, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 28800, + 'stdStartTimeSec' => 25200, + ), + 'Pacific/Easter' => + array ( + 'gmtOffset' => -360, + 'dstOffset' => 60, + 'dstMonth' => 10, + 'dstStartday' => 9, + 'dstWeekday' => 0, + 'stdMonth' => 3, + 'stdStartday' => 9, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 36000, + 'stdStartTimeSec' => 32400, + ), + 'America/Bogota' => + array ( + 'gmtOffset' => -300, + ), + 'America/Curacao' => + array ( + 'gmtOffset' => -240, + ), + 'America/Guayaquil' => + array ( + 'gmtOffset' => -300, + ), + 'Pacific/Galapagos' => + array ( + 'gmtOffset' => -360, + ), + 'Atlantic/Stanley' => + array ( + 'gmtOffset' => -240, + 'dstOffset' => 60, + 'dstMonth' => 9, + 'dstStartday' => 1, + 'dstWeekday' => 0, + 'stdMonth' => 4, + 'stdStartday' => 15, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 7200, + 'stdStartTimeSec' => 3600, + ), + 'America/Cayenne' => + array ( + 'gmtOffset' => -180, + ), + 'America/Guyana' => + array ( + 'gmtOffset' => -240, + ), + 'America/Asuncion' => + array ( + 'gmtOffset' => -240, + 'dstOffset' => 60, + 'dstMonth' => 10, + 'dstStartday' => 15, + 'dstWeekday' => 0, + 'stdMonth' => 3, + 'stdStartday' => 8, + 'stdWeekday' => 0, + 'dstStartTimeSec' => 0, + 'stdStartTimeSec' => -3600, + ), + 'America/Lima' => + array ( + 'gmtOffset' => -300, + ), + 'Atlantic/South_Georgia' => + array ( + 'gmtOffset' => -120, + ), + 'America/Paramaribo' => + array ( + 'gmtOffset' => -180, + ), + 'America/Port_of_Spain' => + array ( + 'gmtOffset' => -240, + ), + 'America/Montevideo' => + array ( + 'gmtOffset' => -180, + 'dstOffset' => 60, + 'dstMonth' => 10, + 'dstStartday' => 9, + 'dstWeekday' => -1, + 'stdMonth' => 3, + 'stdStartday' => 27, + 'stdWeekday' => -1, + 'dstStartTimeSec' => 7200, + 'stdStartTimeSec' => 3600, + ), + 'America/Caracas' => + array ( + 'gmtOffset' => -270, + ), +) +?> diff --git a/include/upload_file.php b/include/upload_file.php new file mode 100644 index 00000000..b6a9b1c1 --- /dev/null +++ b/include/upload_file.php @@ -0,0 +1,359 @@ +field_name = $field_name; + // Bug 28408 - Add automatic creation of upload cache directory if it doesn't exist + if ( !is_dir($GLOBALS['sugar_config']['upload_dir']) ) + create_cache_directory(str_replace($GLOBALS['sugar_config']['cache_dir'],'',$GLOBALS['sugar_config']['upload_dir'])); + } + + function set_for_soap($filename, $file) { + $this->stored_file_name = $filename; + $this->use_soap = true; + $this->file = $file; + } + + /** + * wrapper for this::get_file_path() + * @param string stored_file_name File name in filesystem + * @param string bean_id note bean ID + * @return string path with file name + */ + function get_url($stored_file_name,$bean_id) { + global $sugar_config; + return UploadFile::get_file_path($stored_file_name,$bean_id); + } + + /** + * builds a URL path for an anchor tag + * @param string stored_file_name File name in filesystem + * @param string bean_id note bean ID + * @return string path with file name + */ + function get_file_path($stored_file_name,$bean_id) { + global $sugar_config; + global $locale; + + // if the parameters are empty strings, just return back the upload_dir + if ( empty($bean_id) && empty($stored_file_name) ) + return $sugar_config['upload_dir']; + + if (file_exists($sugar_config['upload_dir'] . $bean_id . rawurlencode($stored_file_name))){ + if (!rename($sugar_config['upload_dir'] . $bean_id . rawurlencode($stored_file_name), + $sugar_config['upload_dir'] . $bean_id)){ + $GLOBALS['log']->fatal("unable to rename file in {$sugar_config['upload_dir']}"); + } + } + else if (file_exists($sugar_config['upload_dir'] . $bean_id . urlencode($stored_file_name))){ + if (!rename($sugar_config['upload_dir'] . $bean_id . urlencode($stored_file_name), + $sugar_config['upload_dir'] . $bean_id)){ + $GLOBALS['log']->fatal("unable to rename file in {$sugar_config['upload_dir']}"); + } + } + else if (file_exists($sugar_config['upload_dir'] . $bean_id . $stored_file_name)){ + if (!rename($sugar_config['upload_dir'] . $bean_id . $stored_file_name, + $sugar_config['upload_dir'] . $bean_id)){ + $GLOBALS['log']->fatal("unable to rename file in {$sugar_config['upload_dir']}"); + } + } + else if (file_exists($sugar_config['upload_dir'] . $bean_id . $locale->translateCharset( $stored_file_name, 'UTF-8', $locale->getExportCharset() ))){ + if (!rename($sugar_config['upload_dir'] . $bean_id . $locale->translateCharset( $stored_file_name, 'UTF-8', $locale->getExportCharset() ), + $sugar_config['upload_dir'] . $bean_id)){ + $GLOBALS['log']->fatal("unable to rename file in {$sugar_config['upload_dir']}"); + } + } + + return $sugar_config['upload_dir'] . $bean_id; + } + + /** + * duplicates an already uploaded file in the filesystem. + * @param string old_id ID of original note + * @param string new_id ID of new (copied) note + * @param string filename Filename of file (deprecated) + */ + function duplicate_file($old_id, $new_id, $file_name) { + global $sugar_config; + + // current file system (GUID) + $source = $sugar_config['upload_dir'] . $old_id; + + if(!file_exists($source)) { + // old-style file system (GUID.filename.extension) + $oldStyleSource = $source.$file_name; + if(file_exists($oldStyleSource)) { + // change to new style + if(copy($oldStyleSource, $source)) { + // delete the old + if(!unlink($oldStyleSource)) { + $GLOBALS['log']->warn("upload_file could not unlink [ {$oldStyleSource} ]"); + } + } else { + $GLOBALS['log']->warn("upload_file could not copy [ {$oldStyleSource} ] to [ {$source} ]"); + } + } + } + + $destination = $sugar_config['upload_dir'] . $new_id; + if(!copy($source, $destination)) { + $GLOBALS['log']->warn("upload_file could not copy [ {$source} ] to [ {$destination} ]"); + } + } + + /** + * standard PHP file-upload security measures. all variables accessed in a global context + * @return bool True on success + */ + function confirm_upload() { + global $sugar_config; + + if(!is_uploaded_file($_FILES[$this->field_name]['tmp_name'])) { + return false; + } elseif($_FILES[$this->field_name]['size'] > $sugar_config['upload_maxsize']) { + die("ERROR: uploaded file was too big: max filesize: {$sugar_config['upload_maxsize']}"); + } + + if(!is_writable($sugar_config['upload_dir'])) { + die("ERROR: cannot write to directory: {$sugar_config['upload_dir']} for uploads"); + } + + $this->mime_type =$this->getMime($_FILES[$this->field_name]); + $this->stored_file_name = $this->create_stored_filename(); + $this->temp_file_location = $_FILES[$this->field_name]['tmp_name']; + + return true; + } + + function getMimeSoap($filename){ + + if( function_exists( 'ext2mime' ) ) + { + $mime = ext2mime($filename); + } + else + { + $mime = ' application/octet-stream'; + } + return $mime; + + } + function getMime(&$_FILES_element) + { + + $filename = $_FILES_element['name']; + + if( $_FILES_element['type'] ) + { + $mime = $_FILES_element['type']; + } + elseif( function_exists( 'mime_content_type' ) ) + { + $mime = mime_content_type( $_FILES_element['tmp_name'] ); + } + elseif( function_exists( 'ext2mime' ) ) + { + $mime = ext2mime( $_FILES_element['name'] ); + } + else + { + $mime = ' application/octet-stream'; + } + return $mime; + } + + /** + * gets note's filename + * @return string + */ + function get_stored_file_name() { + return $this->stored_file_name; + } + + /** + * creates a file's name for preparation for saving + * @return string + */ + function create_stored_filename() { + global $sugar_config; + + if(!$this->use_soap) { + $stored_file_name = $_FILES[$this->field_name]['name']; + $this->original_file_name = $stored_file_name; + + /** + * cn: bug 8056 - windows filesystems and IIS do not like utf8. we are forced to urlencode() to ensure that + * the file is linkable from the browser. this will stay broken until we move to a db-storage system + */ + if(is_windows()) { + // create a non UTF-8 name encoding + // 176 + 36 char guid = windows' maximum filename length + $end = (strlen($stored_file_name) > 176) ? 176 : strlen($stored_file_name); + $stored_file_name = substr($stored_file_name, 0, $end); + $this->original_file_name = $_FILES[$this->field_name]['name']; + } + } else { + $stored_file_name = $this->stored_file_name; + $this->original_file_name = $stored_file_name; + } + + $ext_pos = strrpos($stored_file_name, "."); + if($ext_pos !== false) + $this->file_ext = substr($stored_file_name, $ext_pos + 1); + // cn: bug 6347 - fix file extension detection + foreach($sugar_config['upload_badext'] as $badExt) { + if(strtolower($this->file_ext) == strtolower($badExt)) { + $stored_file_name .= ".txt"; + $this->file_ext="txt"; + break; // no need to look for more + } + } + return $stored_file_name; + } + + /** + * moves uploaded temp file to permanent save location + * @param string bean_id ID of parent bean + * @return bool True on success + */ + function final_move($bean_id) { + global $sugar_config; + + $destination = clean_path($this->get_upload_path($bean_id)); + if($this->use_soap) { + $fp = sugar_fopen($destination, 'wb'); + if(!fwrite($fp, $this->file)){ + die("ERROR: can't save file to $destination"); + } + fclose($fp); + } else { + if(!move_uploaded_file($_FILES[$this->field_name]['tmp_name'], $destination)) { + die("ERROR: can't move_uploaded_file to $destination. You should try making the directory writable by the webserver"); + } + } + return true; + } + + function upload_doc(&$bean, $bean_id, $doc_type, $file_name, $mime_type){ + + if(!empty($doc_type)&&$doc_type!='Sugar') { + global $sugar_config; + $destination = clean_path($this->get_upload_path($bean_id)); + sugar_rename($destination, str_replace($bean_id, $bean_id.'_'.$file_name, $destination)); + $new_destination = clean_path($this->get_upload_path($bean_id.'_'.$file_name)); + + try{ + $this->api = ExternalAPIFactory::loadAPI($doc_type); + + if ( isset($this->api) && $this->api !== false ) { + $result = $this->api->uploadDoc( + $bean, + $new_destination, + $file_name, + $mime_type + ); + } else { + $result['success'] = FALSE; + // FIXME: Translate + $GLOBALS['log']->error("Could not load the requested API (".$doc_type.")"); + $result['errorMessage'] = 'Could not find a proper API'; + } + unlink($new_destination); + }catch(Exception $e){ + $result['success'] = FALSE; + $result['errorMessage'] = $e->getMessage(); + $GLOBALS['log']->error("Caught exception: (".$e->getMessage().") "); + } + if ( !$result['success'] ) { + sugar_rename($new_destination, str_replace($bean_id.'_'.$file_name, $bean_id, $new_destination)); + $bean->doc_type = 'Sugar'; + // FIXME: Translate + if ( ! is_array($_SESSION['user_error_message']) ) + $_SESSION['user_error_message'] = array(); + + $error_message = isset($result['errorMessage']) ? $result['errorMessage'] : $GLOBALS['app_strings']['ERR_EXTERNAL_API_SAVE_FAIL']; + $_SESSION['user_error_message'][] = $error_message; + + } + } + } + + /** + * returns the path with file name to save an uploaded file + * @param string bean_id ID of the parent bean + * @return string + */ + function get_upload_path($bean_id) { + global $sugar_config; + $file_name = $bean_id; + + // cn: bug 8056 - mbcs filename in urlencoding > 212 chars in Windows fails + $end = (strlen($file_name) > 212) ? 212 : strlen($file_name); + $ret_file_name = substr($file_name, 0, $end); + + return $sugar_config['upload_dir'].$ret_file_name; + } + + /** + * deletes a file + * @param string bean_id ID of the parent bean + * @param string file_name File's name + */ + function unlink_file($bean_id,$file_name) { + global $sugar_config; + return unlink($sugar_config['upload_dir'].$bean_id.$file_name); + } +} +?> diff --git a/include/utils.php b/include/utils.php new file mode 100644 index 00000000..ecd3599c --- /dev/null +++ b/include/utils.php @@ -0,0 +1,4192 @@ + empty($admin_export_only) ? false : $admin_export_only, + 'export_delimiter' => empty($export_delimiter) ? ',' : $export_delimiter, + 'cache_dir' => empty($cache_dir) ? 'cache/' : $cache_dir, + 'calculate_response_time' => empty($calculate_response_time) ? true : $calculate_response_time, + 'create_default_user' => empty($create_default_user) ? false : $create_default_user, + 'chartEngine' => 'Jit', + 'date_formats' => empty($dateFormats) ? array( + 'Y-m-d'=>'2010-12-23', + 'd-m-Y' => '23-12-2010', + 'm-d-Y'=>'12-23-2010', + 'Y/m/d'=>'2010/12/23', + 'd/m/Y' => '23/12/2010', + 'm/d/Y'=>'12/23/2010', + 'Y.m.d' => '2010.12.23', + 'd.m.Y' => '23.12.2010', + 'm.d.Y' => '12.23.2010' + ) : $dateFormats, + 'dbconfig' => $dbconfig, // this must be set!! + 'dbconfigoption' => $dbconfigoption, // this must be set!! + 'default_action' => empty($default_action) ? 'index' : $default_action, + 'default_charset' => empty($default_charset) ? 'UTF-8' : $default_charset, + 'default_currency_name' => empty($default_currency_name) ? 'US Dollar' : $default_currency_name, + 'default_currency_symbol' => empty($default_currency_symbol) ? '$' : $default_currency_symbol, + 'default_currency_iso4217' => empty($default_currency_iso4217) ? '$' : $default_currency_iso4217, + 'default_date_format' => empty($defaultDateFormat) ? 'm/d/Y' : $defaultDateFormat, + 'default_export_charset' => 'UTF-8', + 'default_language' => empty($default_language) ? 'en_us' : $default_language, + 'default_module' => empty($default_module) ? 'Home' : $default_module, + 'default_password' => empty($default_password) ? '' : $default_password, + 'default_permissions' => array ( + 'dir_mode' => 02770, + 'file_mode' => 0660, + 'chown' => '', + 'chgrp' => '', + ), + 'default_theme' => empty($default_theme) ? 'Sugar5' : $default_theme, + 'default_time_format' => empty($defaultTimeFormat) ? 'h:ia' : $defaultTimeFormat, + 'default_user_is_admin' => empty($default_user_is_admin) ? false : $default_user_is_admin, + 'default_user_name' => empty($default_user_name) ? '' : $default_user_name, + 'disable_export' => empty($disable_export) ? false : $disable_export, + 'disable_persistent_connections' => empty($disable_persistent_connections) ? false : $disable_persistent_connections, + 'display_email_template_variable_chooser' => empty($display_email_template_variable_chooser) ? false : $display_email_template_variable_chooser, + 'display_inbound_email_buttons' => empty($display_inbound_email_buttons) ? false : $display_inbound_email_buttons, + 'history_max_viewed' => empty($history_max_viewed) ? 50 : $history_max_viewed, + 'host_name' => empty($host_name) ? 'localhost' : $host_name, + 'import_dir' => $import_dir, // this must be set!! + 'import_max_records_per_file' => 100, + 'languages' => empty($languages) ? array('en_us' => 'English (US)') : $languages, + 'list_max_entries_per_page' => empty($list_max_entries_per_page) ? 20 : $list_max_entries_per_page, + 'list_max_entries_per_subpanel' => empty($list_max_entries_per_subpanel) ? 10 : $list_max_entries_per_subpanel, + 'lock_default_user_name' => empty($lock_default_user_name) ? false : $lock_default_user_name, + 'log_memory_usage' => empty($log_memory_usage) ? false : $log_memory_usage, + 'portal_view' => 'single_user', + 'resource_management' => array ( + 'special_query_limit' => 50000, + 'special_query_modules' => array('Reports', 'Export', 'Import', 'Administration', 'Sync'), + 'default_limit' => 1000, + ), + 'require_accounts' => empty($requireAccounts) ? true : $requireAccounts, + 'rss_cache_time' => empty($RSS_CACHE_TIME) ? '10800' : $RSS_CACHE_TIME, + 'session_dir' => $session_dir, // this must be set!! + 'site_url' => empty($site_URL) ? $site_url : $site_URL, // this must be set!! + 'showDetailData' => true, // if true, read-only ACL fields will still appear on EditViews as non-editable + 'showThemePicker' => true, + 'sugar_version' => empty($sugar_version) ? 'unknown' : $sugar_version, + 'time_formats' => empty($timeFormats) ? array ( + 'H:i'=>'23:00', 'h:ia'=>'11:00 pm', 'h:iA'=>'11:00PM', + 'H.i'=>'23.00', 'h.ia'=>'11.00 pm', 'h.iA'=>'11.00PM' ) : $timeFormats, + 'tmp_dir' => $tmp_dir, // this must be set!! + 'translation_string_prefix' => empty($translation_string_prefix) ? false : $translation_string_prefix, + 'unique_key' => empty($unique_key) ? md5(create_guid()) : $unique_key, + 'upload_badext' => empty($upload_badext) ? array ( + 'php', 'php3', 'php4', 'php5', 'pl', 'cgi', 'py', + 'asp', 'cfm', 'js', 'vbs', 'html', 'htm' ) : $upload_badext, + 'upload_dir' => $upload_dir, // this must be set!! + 'upload_maxsize' => empty($upload_maxsize) ? 3000000 : $upload_maxsize, + 'import_max_execution_time' => empty($import_max_execution_time) ? 3600 : $import_max_execution_time, + 'lock_homepage' => false, + 'lock_subpanels' => false, + 'max_dashlets_homepage' => 15, + 'dashlet_display_row_options' => array('1','3','5','10'), + 'default_max_tabs' => empty($max_tabs) ? '7' : $max_tabs, + 'default_subpanel_tabs' => empty($subpanel_tabs) ? true : $subpanel_tabs, + 'default_subpanel_links' => empty($subpanel_links) ? false : $subpanel_links, + 'default_swap_last_viewed' => empty($swap_last_viewed) ? false : $swap_last_viewed, + 'default_swap_shortcuts' => empty($swap_shortcuts) ? false : $swap_shortcuts, + 'default_navigation_paradigm' => empty($navigation_paradigm) ? 'gm' : $navigation_paradigm, + 'default_call_status' => 'Planned', + 'js_lang_version' => 1, + 'passwordsetting' => empty($passwordsetting) ? array ( + 'SystemGeneratedPasswordON' => '', + 'generatepasswordtmpl' => '', + 'lostpasswordtmpl' => '', + 'forgotpasswordON' => true, + 'linkexpiration' => '1', + 'linkexpirationtime' => '30', + 'linkexpirationtype' => '1', + 'systexpiration' => '0', + 'systexpirationtime' => '', + 'systexpirationtype' => '0', + 'systexpirationlogin' => '', + ) : $passwordsetting, + ); +} + +function get_sugar_config_defaults() { + global $locale; + /** + * used for getting base values for array style config.php. used by the + * installer and to fill in new entries on upgrades. see also: + * sugar_config_union + */ + + $sugar_config_defaults = array ( + 'admin_export_only' => false, + 'export_delimiter' => ',', + 'cache_dir' => 'cache/', + 'calculate_response_time' => true, + 'create_default_user' => false, + 'chartEngine' => 'Jit', + 'date_formats' => array ( + 'Y-m-d' => '2010-12-23', 'm-d-Y' => '12-23-2010', 'd-m-Y' => '23-12-2010', + 'Y/m/d' => '2010/12/23', 'm/d/Y' => '12/23/2010', 'd/m/Y' => '23/12/2010', + 'Y.m.d' => '2010.12.23', 'd.m.Y' => '23.12.2010', 'm.d.Y' => '12.23.2010',), + 'dbconfigoption' => array ( + 'persistent' => true, + 'autofree' => false, + 'debug' => 0, + 'seqname_format' => '%s_seq', + 'portability' => 0, + 'ssl' => false ), + 'default_action' => 'index', + 'default_charset' => return_session_value_or_default('default_charset', + 'UTF-8'), + 'default_currency_name' => return_session_value_or_default('default_currency_name', 'US Dollar'), + 'default_currency_symbol' => return_session_value_or_default('default_currency_symbol', '$'), + 'default_currency_iso4217' => return_session_value_or_default('default_currency_iso4217', 'USD'), + 'default_currency_significant_digits' => return_session_value_or_default('default_currency_significant_digits', 2), + 'default_number_grouping_seperator' => return_session_value_or_default('default_number_grouping_seperator', ','), + 'default_decimal_seperator' => return_session_value_or_default('default_decimal_seperator', '.'), + 'default_date_format' => 'm/d/Y', + 'default_export_charset' => 'UTF-8', + 'default_language' => return_session_value_or_default('default_language', + 'en_us'), + 'default_module' => 'Home', + 'default_password' => '', + 'default_permissions' => array ( + 'dir_mode' => 02770, + 'file_mode' => 0660, + 'user' => '', + 'group' => '', + ), + 'default_theme' => return_session_value_or_default('site_default_theme', 'Sugar5'), + 'default_time_format' => 'h:ia', + 'default_user_is_admin' => false, + 'default_user_name' => '', + 'disable_export' => false, + 'disable_persistent_connections' => + return_session_value_or_default('disable_persistent_connections', + 'false'), + 'display_email_template_variable_chooser' => false, + 'display_inbound_email_buttons' => false, + 'dump_slow_queries' => false, + 'email_default_editor' => 'html', + 'email_default_client' => 'sugar', + 'email_default_delete_attachments' => true, + 'history_max_viewed' => 50, + 'installer_locked' => true, + 'import_max_records_per_file' => 100, + 'languages' => array('en_us' => 'English (US)'), + 'large_scale_test' => false, + 'list_max_entries_per_page' => 20, + 'list_max_entries_per_subpanel' => 10, + 'lock_default_user_name' => false, + 'log_memory_usage' => false, + 'portal_view' => 'single_user', + 'resource_management' => array ( + 'special_query_limit' => 50000, + 'special_query_modules' => array('Reports', 'Export', 'Import', 'Administration', 'Sync'), + 'default_limit' => 1000, + ), + 'require_accounts' => true, + 'rss_cache_time' => return_session_value_or_default('rss_cache_time', + '10800'), + 'save_query' => 'all', + 'showDetailData' => true, // if true, read-only ACL fields will still appear on EditViews as non-editable + 'showThemePicker' => true, + 'slow_query_time_msec' => '100', + 'sugarbeet' => true, + 'time_formats' => array ( + 'H:i'=>'23:00', 'h:ia'=>'11:00pm', 'h:iA'=>'11:00PM', + 'H.i'=>'23.00', 'h.ia'=>'11.00pm', 'h.iA'=>'11.00PM' ), + 'tracker_max_display_length' => 15, + 'translation_string_prefix' => + return_session_value_or_default('translation_string_prefix', false), + 'upload_badext' => array ( + 'php', 'php3', 'php4', 'php5', 'pl', 'cgi', 'py', + 'asp', 'cfm', 'js', 'vbs', 'html', 'htm' ), + 'upload_maxsize' => 3000000, + 'import_max_execution_time' => 3600, +// 'use_php_code_json' => returnPhpJsonStatus(), + 'verify_client_ip' => true, + 'js_custom_version' => '', + 'js_lang_version' => 1, + 'default_number_grouping_seperator' => ',', + 'default_decimal_seperator' => '.', + 'lock_homepage' => false, + 'lock_subpanels' => false, + 'max_dashlets_homepage' => '15', + 'default_max_tabs' => '7', + 'dashlet_display_row_options' => array('1','3','5','10'), + 'default_subpanel_tabs' => true, + 'default_subpanel_links' => false, + 'default_swap_last_viewed' => false, + 'default_swap_shortcuts' => false, + 'default_navigation_paradigm' => 'gm', + 'admin_access_control' => false, + 'use_common_ml_dir' => false, + 'common_ml_dir' => '', + 'vcal_time' => '2', + 'passwordsetting' => empty($passwordsetting) ? array ( + 'SystemGeneratedPasswordON' => '', + 'generatepasswordtmpl' => '', + 'lostpasswordtmpl' => '', + 'forgotpasswordON' => false, + 'linkexpiration' => '1', + 'linkexpirationtime' => '30', + 'linkexpirationtype' => '1', + 'systexpiration' => '0', + 'systexpirationtime' => '', + 'systexpirationtype' => '0', + 'systexpirationlogin' => '', + ) : $passwordsetting, + 'use_real_names' => true, + ); + + if(!is_object($locale)) { + $locale = new Localization(); + } + + $sugar_config_defaults['default_currencies'] = $locale->getDefaultCurrencies(); + + $sugar_config_defaults = sugarArrayMerge($locale->getLocaleConfigDefaults(), $sugar_config_defaults); + return( $sugar_config_defaults ); +} + +/** + * @deprecated use SugarView::getMenu() instead + */ +function load_menu($path){ + global $module_menu; + + if(file_exists($path . 'Menu.php')) + { + require($path . 'Menu.php'); + } + if(file_exists('custom/' . $path . 'Ext/Menus/menu.ext.php')) + { + require('custom/' . $path . 'Ext/Menus/menu.ext.php'); + } + if(file_exists('custom/application/Ext/Menus/menu.ext.php')) + { + require('custom/application/Ext/Menus/menu.ext.php'); + } + return $module_menu; +} + +/** + * get_notify_template_file + * This function will return the location of the email notifications template to use + * + * @return string relative file path to email notifications template file + */ +function get_notify_template_file($language){ + /* + * Order of operation: + * 1) custom version of specified language + * 2) stock version of specified language + * 3) custom version of en_us template + * 4) stock en_us template + */ + + // set $file to the base code template so it's set if none of the conditions pass + $file = "include/language/en_us.notify_template.html"; + + if(file_exists("custom/include/language/{$language}.notify_template.html")){ + $file = "custom/include/language/{$language}.notify_template.html"; + } + else if(file_exists("include/language/{$language}.notify_template.html")){ + $file = "include/language/{$language}.notify_template.html"; + } + else if(file_exists("custom/include/language/en_us.notify_template.html")){ + $file = "custom/include/language/en_us.notify_template.html"; + } + + return $file; +} + +function sugar_config_union( $default, $override ){ + // a little different then array_merge and array_merge_recursive. we want + // the second array to override the first array if the same value exists, + // otherwise merge the unique keys. it handles arrays of arrays recursively + // might be suitable for a generic array_union + if( !is_array( $override ) ){ + $override = array(); + } + foreach( $default as $key => $value ){ + if( !array_key_exists($key, $override) ){ + $override[$key] = $value; + } + else if( is_array( $key ) ){ + $override[$key] = sugar_config_union( $value, $override[$key] ); + } + } + return( $override ); +} + +function make_not_writable( $file ){ + // Returns true if the given file/dir has been made not writable + $ret_val = false; + if( is_file($file) || is_dir($file) ){ + if( !is_writable($file) ){ + $ret_val = true; + } + else { + $original_fileperms = fileperms($file); + + // take away writable permissions + $new_fileperms = $original_fileperms & ~0x0092; + @sugar_chmod($file, $new_fileperms); + + if( !is_writable($file) ){ + $ret_val = true; + } + } + } + return $ret_val; +} + + +/** This function returns the name of the person. + * It currently returns "first last". It should not put the space if either name is not available. + * It should not return errors if either name is not available. + * If no names are present, it will return "" + * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc. + * All Rights Reserved. + * Contributor(s): ______________________________________.. + */ +function return_name($row, $first_column, $last_column) +{ + $first_name = ""; + $last_name = ""; + $full_name = ""; + + if(isset($row[$first_column])) + { + $first_name = stripslashes($row[$first_column]); + } + + if(isset($row[$last_column])) + { + $last_name = stripslashes($row[$last_column]); + } + + $full_name = $first_name; + + // If we have a first name and we have a last name + if($full_name != "" && $last_name != "") + { + // append a space, then the last name + $full_name .= " ".$last_name; + } + // If we have no first name, but we have a last name + else if($last_name != "") + { + // append the last name without the space. + $full_name .= $last_name; + } + + return $full_name; +} + + +function get_languages() +{ + global $sugar_config; + $lang = $sugar_config['languages']; + if(!empty($sugar_config['disabled_languages'])){ + foreach(explode(',', $sugar_config['disabled_languages']) as $disable) { + unset($lang[$disable]); + } + } + return $lang; +} + +function get_all_languages() +{ + global $sugar_config; + return $sugar_config['languages']; +} + + +function get_language_display($key) +{ + global $sugar_config; + return $sugar_config['languages'][$key]; +} + +function get_assigned_user_name($assigned_user_id, $is_group = '') { + static $saved_user_list = null; + + if(empty($saved_user_list)) { + $saved_user_list = get_user_array(false, '', '', false, null, $is_group); + } + + if(isset($saved_user_list[$assigned_user_id])) { + return $saved_user_list[$assigned_user_id]; + } + + return ''; +} + +/** + * retrieves the user_name column value (login) + * @param string id GUID of user + * @return string + */ +function get_user_name($id) { + global $db; + + if(empty($db)) + $db = DBManagerFactory::getInstance(); + + $q = "SELECT user_name FROM users WHERE id='{$id}'"; + $r = $db->query($q); + $a = $db->fetchByAssoc($r); + + return (empty($a)) ? '' : $a['user_name']; +} + + +//TODO Update to use global cache +function get_user_array($add_blank=true, $status="Active", $assigned_user="", $use_real_name=false, $user_name_begins = null, $is_group=' AND portal_only=0 ', $from_cache = true) { + global $locale; + global $sugar_config; + + if(empty($locale)) { + + $locale = new Localization(); + } + if($from_cache) + $user_array = get_register_value('user_array', $add_blank. $status . $assigned_user); + + if(!isset($user_array)) { + $db = DBManagerFactory::getInstance(); + $temp_result = Array(); + // Including deleted users for now. + if (empty($status)) { + $query = "SELECT id, first_name, last_name, user_name from users WHERE 1=1".$is_group; + } + else { + $query = "SELECT id, first_name, last_name, user_name from users WHERE status='$status'".$is_group; + } + + if (!empty($user_name_begins)) { + $query .= " AND user_name LIKE '$user_name_begins%' "; + } + if (!empty($assigned_user)) { + $query .= " OR id='$assigned_user'"; + } + $query = $query.' ORDER BY user_name ASC'; + $GLOBALS['log']->debug("get_user_array query: $query"); + $result = $db->query($query, true, "Error filling in user array: "); + + if ($add_blank==true) { + // Add in a blank row + $temp_result[''] = ''; + } + + // Get the id and the name. + while($row = $db->fetchByAssoc($result)) { + if($use_real_name == true || showFullName()) { + if(isset($row['last_name'])) { // cn: we will ALWAYS have both first_name and last_name (empty value if blank in db) + $temp_result[$row['id']] = $locale->getLocaleFormattedName($row['first_name'],$row['last_name']); + } else { + $temp_result[$row['id']] = $row['user_name']; + } + } else { + $temp_result[$row['id']] = $row['user_name']; + } + } + + $user_array = $temp_result; + if($from_cache) + set_register_value('user_array', $add_blank. $status . $assigned_user, $temp_result); + } + + + return $user_array; +} + + +/** + * uses a different query to return a list of users than get_user_array() + * @param args string where clause entry + * @return array Array of Users' details that match passed criteria + */ +function getUserArrayFromFullName($args, $hide_portal_users = false) { + global $locale; + $db = DBManagerFactory::getInstance(); + + $argArray = array(); + if(strpos($args, " ")) { + $argArray = explode(" ", $args); + } else { + $argArray[] = $args; + } + + $inClause = ''; + foreach($argArray as $arg) { + if(!empty($inClause)) { + $inClause .= ' OR '; + } + if(empty($arg)) + continue; + + $inClause .= "(first_name LIKE '{$arg}%' OR last_name LIKE '{$arg}%')"; + } + + $query = "SELECT id, first_name, last_name, user_name FROM users WHERE status='Active' AND deleted=0 AND "; + if ( $hide_portal_users ) { + $query .= " portal_only=0 AND "; + } + $query .= $inClause; + $query .= " ORDER BY last_name ASC"; + + $r = $db->query($query); + $ret = array(); + while($a = $db->fetchByAssoc($r)) { + $ret[$a['id']] = $locale->getLocaleFormattedName($a['first_name'], $a['last_name']); + } + + return $ret; +} + +/** + * + * based on user pref then system pref + */ +function showFullName() { + global $sugar_config; + global $current_user; + static $showFullName = null; + + if (is_null($showFullName)) { + $sysPref = (isset($sugar_config['use_real_names']) && $sugar_config['use_real_names'] == true) ? true : false; + $userPref = (is_object($current_user)) ? $current_user->getPreference('use_real_names') : null; + + if($userPref != null) { + $bool = ($userPref == 'on') ? true : false; + $showFullName = $bool; + } else { + $showFullName = $sysPref; + } + } + + return $showFullName; +} + +function clean($string, $maxLength) +{ + $string = substr($string, 0, $maxLength); + return escapeshellcmd($string); +} + +/** + * Copy the specified request variable to the member variable of the specified object. + * Do no copy if the member variable is already set. + * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc. + * All Rights Reserved. + * Contributor(s): ______________________________________.. + */ +function safe_map($request_var, & $focus, $always_copy = false) +{ + safe_map_named($request_var, $focus, $request_var, $always_copy); +} + +/** + * Copy the specified request variable to the member variable of the specified object. + * Do no copy if the member variable is already set. + * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc. + * All Rights Reserved. + * Contributor(s): ______________________________________.. + */ +function safe_map_named($request_var, & $focus, $member_var, $always_copy) +{ + if (isset($_REQUEST[$request_var]) && ($always_copy || is_null($focus->$member_var))) { + $GLOBALS['log']->debug("safe map named called assigning '{$_REQUEST[$request_var]}' to $member_var"); + $focus->$member_var = $_REQUEST[$request_var]; + } +} + +/** + * This function retrieves an application language file and returns the array of strings included in the $app_list_strings var. + * + * @param string $language specific language to load + * @return array lang strings + */ +function return_app_list_strings_language($language) +{ + global $app_list_strings; + global $sugar_config; + + $cache_key = 'app_list_strings.'.$language; + + // Check for cached value + $cache_entry = sugar_cache_retrieve($cache_key); + if(!empty($cache_entry)) + { + return $cache_entry; + } + + $default_language = $sugar_config['default_language']; + $temp_app_list_strings = $app_list_strings; + + $langs = array(); + if ($language != 'en_us') { + $langs[] = 'en_us'; + } + if ($default_language != 'en_us' && $language != $default_language) { + $langs[] = $default_language; + } + $langs[] = $language; + + $app_list_strings_array = array(); + + foreach ( $langs as $lang ) { + $app_list_strings = array(); + if(file_exists("include/language/$lang.lang.php")) { + include("include/language/$lang.lang.php"); + $GLOBALS['log']->info("Found language file: $lang.lang.php"); + } + if(file_exists("include/language/$lang.lang.override.php")) { + include("include/language/$lang.lang.override.php"); + $GLOBALS['log']->info("Found override language file: $lang.lang.override.php"); + } + if(file_exists("include/language/$lang.lang.php.override")) { + include("include/language/$lang.lang.php.override"); + $GLOBALS['log']->info("Found override language file: $lang.lang.php.override"); + } + + $app_list_strings_array[] = $app_list_strings; + } + + $app_list_strings = array(); + foreach ( $app_list_strings_array as $app_list_strings_item ) { + $app_list_strings = sugarArrayMerge($app_list_strings, $app_list_strings_item); + } + + foreach ( $langs as $lang ) { + if(file_exists("custom/application/Ext/Language/$lang.lang.ext.php")) { + $app_list_strings = _mergeCustomAppListStrings("custom/application/Ext/Language/$lang.lang.ext.php" , $app_list_strings); + $GLOBALS['log']->info("Found extended language file: $lang.lang.ext.php"); + } + if(file_exists("custom/include/language/$lang.lang.php")) { + include("custom/include/language/$lang.lang.php"); + $GLOBALS['log']->info("Found custom language file: $lang.lang.php"); + } + } + + if(!isset($app_list_strings)) { + $GLOBALS['log']->fatal("Unable to load the application language file for the selected language ($language) or the default language ($default_language) or the en_us language"); + return null; + } + + $return_value = $app_list_strings; + $app_list_strings = $temp_app_list_strings; + + sugar_cache_put($cache_key, $return_value); + + return $return_value; +} + +/** +* The dropdown items in custom language files is $app_list_strings['$key']['$second_key'] = $value not +* $GLOBALS['app_list_strings']['$key'] = $value, so we have to delete the original ones in app_list_strings and relace it with the custom ones. + * @param file string the language that you want include, + * @param app_list_strings array the golbal strings + * @return array + */ + //jchi 25347 +function _mergeCustomAppListStrings($file , $app_list_strings){ + $app_list_strings_original = $app_list_strings; + unset($app_list_strings); + include($file); + if(!isset($app_list_strings) || !is_array($app_list_strings)){ + return $app_list_strings_original; + } + //Bug 25347: We should not merge custom dropdown fields unless they relate to parent fields or the module list. + foreach($app_list_strings as $key=>$value) + { + $exemptDropdowns = array("moduleList", "parent_type_display", "record_type_display", "record_type_display_notes"); + if (!in_array($key, $exemptDropdowns) && array_key_exists($key, $app_list_strings_original)) + { + unset($app_list_strings_original["$key"]); + } + } + $app_list_strings = sugarArrayMergeRecursive($app_list_strings_original , $app_list_strings); + return $app_list_strings; +} + +/** + * This function retrieves an application language file and returns the array of strings included. + * + * @param string $language specific language to load + * @return array lang strings + */ +function return_application_language($language) +{ + global $app_strings, $sugar_config; + + $cache_key = 'app_strings.'.$language; + + // Check for cached value + $cache_entry = sugar_cache_retrieve($cache_key); + if(!empty($cache_entry)) + { + return $cache_entry; + } + + $temp_app_strings = $app_strings; + $default_language = $sugar_config['default_language']; + + $langs = array(); + if ($language != 'en_us') { + $langs[] = 'en_us'; + } + if ($default_language != 'en_us' && $language != $default_language) { + $langs[] = $default_language; + } + + $langs[] = $language; + + $app_strings_array = array(); + + foreach ( $langs as $lang ) { + $app_strings = array(); + if(file_exists("include/language/$lang.lang.php")) { + include("include/language/$lang.lang.php"); + $GLOBALS['log']->info("Found language file: $lang.lang.php"); + } + if(file_exists("include/language/$lang.lang.override.php")) { + include("include/language/$lang.lang.override.php"); + $GLOBALS['log']->info("Found override language file: $lang.lang.override.php"); + } + if(file_exists("include/language/$lang.lang.php.override")) { + include("include/language/$lang.lang.php.override"); + $GLOBALS['log']->info("Found override language file: $lang.lang.php.override"); + } + if(file_exists("custom/application/Ext/Language/$lang.lang.ext.php")) { + include("custom/application/Ext/Language/$lang.lang.ext.php"); + $GLOBALS['log']->info("Found extended language file: $lang.lang.ext.php"); + } + if(file_exists("custom/include/language/$lang.lang.php")) { + include("custom/include/language/$lang.lang.php"); + $GLOBALS['log']->info("Found custom language file: $lang.lang.php"); + } + $app_strings_array[] = $app_strings; + } + + $app_strings = array(); + foreach ( $app_strings_array as $app_strings_item ) { + $app_strings = sugarArrayMerge($app_strings, $app_strings_item); + } + + if(!isset($app_strings)) { + $GLOBALS['log']->fatal("Unable to load the application language strings"); + return null; + } + + // If we are in debug mode for translating, turn on the prefix now! + if($sugar_config['translation_string_prefix']) { + foreach($app_strings as $entry_key=>$entry_value) { + $app_strings[$entry_key] = $language.' '.$entry_value; + } + } + if(isset($_SESSION['show_deleted'])) { + $app_strings['LBL_DELETE_BUTTON'] = $app_strings['LBL_UNDELETE_BUTTON']; + $app_strings['LBL_DELETE_BUTTON_LABEL'] = $app_strings['LBL_UNDELETE_BUTTON_LABEL']; + $app_strings['LBL_DELETE_BUTTON_TITLE'] = $app_strings['LBL_UNDELETE_BUTTON_TITLE']; + $app_strings['LBL_DELETE'] = $app_strings['LBL_UNDELETE']; + } + + $app_strings['LBL_ALT_HOT_KEY'] = get_alt_hot_key(); + + $return_value = $app_strings; + $app_strings = $temp_app_strings; + + sugar_cache_put($cache_key, $return_value); + + return $return_value; +} + +/** + * This function retrieves a module's language file and returns the array of strings included. + * + * @param string $language specific language to load + * @param string $module module name to load strings for + * @param bool $refresh optional, true if you want to rebuild the language strings + * @return array lang strings + */ +function return_module_language($language, $module, $refresh=false) +{ + global $mod_strings; + global $sugar_config; + global $currentModule; + + // Jenny - Bug 8119: Need to check if $module is not empty + if (empty($module)) { + $stack = debug_backtrace(); + $GLOBALS['log']->warn("Variable module is not in return_module_language ". var_export($stack, true)); + return array(); + } + + $cache_key = "mod_strings_lang.".$language.$module; + // Check for cached value + $cache_entry = sugar_cache_retrieve($cache_key); + if(!empty($cache_entry)) + { + return $cache_entry; + } + + // Store the current mod strings for later + $temp_mod_strings = $mod_strings; + $loaded_mod_strings = array(); + $language_used = $language; + $default_language = $sugar_config['default_language']; + + if(empty($language)) { + $language = $default_language; + } + + // Bug 21559 - So we can get all the strings defined in the template, refresh + // the vardefs file if the cached language file doesn't exist. + if(!file_exists($GLOBALS['sugar_config']['cache_dir'].'modules/'. $module . '/language/'.$language.'.lang.php') + && !empty($GLOBALS['beanList'][$module])){ + $object = $GLOBALS['beanList'][$module]; + if ($object == 'aCase') { + $object = 'Case'; + } + VardefManager::refreshVardefs($module,$object); + } + + $loaded_mod_strings = LanguageManager::loadModuleLanguage($module, $language,$refresh); + + // cn: bug 6048 - merge en_us with requested language + if($language != $sugar_config['default_language']) + $loaded_mod_strings = sugarArrayMerge( + LanguageManager::loadModuleLanguage($module, $sugar_config['default_language'],$refresh), + $loaded_mod_strings + ); + + // Load in en_us strings by default + if($language != 'en_us' && $sugar_config['default_language'] != 'en_us') + $loaded_mod_strings = sugarArrayMerge( + LanguageManager::loadModuleLanguage($module, 'en_us', $refresh), + $loaded_mod_strings + ); + + // If we are in debug mode for translating, turn on the prefix now! + if($sugar_config['translation_string_prefix']) { + foreach($loaded_mod_strings as $entry_key=>$entry_value) { + $loaded_mod_strings[$entry_key] = $language_used.' '.$entry_value; + } + } + + $return_value = $loaded_mod_strings; + if(!isset($mod_strings)){ + $mod_strings = $return_value; + } + else + $mod_strings = $temp_mod_strings; + + sugar_cache_put($cache_key, $return_value); + return $return_value; +} + + +/** This function retrieves an application language file and returns the array of strings included in the $mod_list_strings var. + * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc. + * All Rights Reserved. + * Contributor(s): ______________________________________.. + * If you are using the current language, do not call this function unless you are loading it for the first time */ +function return_mod_list_strings_language($language,$module) { + global $mod_list_strings; + global $sugar_config; + global $currentModule; + + $cache_key = "mod_list_str_lang.".$language.$module; + + // Check for cached value + $cache_entry = sugar_cache_retrieve($cache_key); + if(!empty($cache_entry)) + { + return $cache_entry; + } + + $language_used = $language; + $temp_mod_list_strings = $mod_list_strings; + $default_language = $sugar_config['default_language']; + + if($currentModule == $module && isset($mod_list_strings) && $mod_list_strings != null) { + return $mod_list_strings; + } + + // cn: bug 6351 - include en_us if file langpack not available + // cn: bug 6048 - merge en_us with requested language + include("modules/$module/language/en_us.lang.php"); + $en_mod_list_strings = array(); + if($language_used != $default_language) + $en_mod_list_strings = $mod_list_strings; + + if(file_exists("modules/$module/language/$language.lang.php")) { + include("modules/$module/language/$language.lang.php"); + } + + if(file_exists("modules/$module/language/$language.lang.override.php")){ + include("modules/$module/language/$language.lang.override.php"); + } + + if(file_exists("modules/$module/language/$language.lang.php.override")){ + echo 'Please Change:
            ' . "modules/$module/language/$language.lang.php.override" . '
            to
            ' . 'Please Change:
            ' . "modules/$module/language/$language.lang.override.php"; + include("modules/$module/language/$language.lang.php.override"); + } + + // cn: bug 6048 - merge en_us with requested language + $mod_list_strings = sugarArrayMerge($en_mod_list_strings, $mod_list_strings); + + // if we still don't have a language pack, then log an error + if(!isset($mod_list_strings)) { + $GLOBALS['log']->fatal("Unable to load the application list language file for the selected language($language) or the default language($default_language) for module({$module})"); + return null; + } + + $return_value = $mod_list_strings; + $mod_list_strings = $temp_mod_list_strings; + + sugar_cache_put($cache_key, $return_value); + return $return_value; +} + + +/** This function retrieves a theme's language file and returns the array of strings included. + * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc. + * All Rights Reserved. + * Contributor(s): ______________________________________.. + */ +function return_theme_language($language, $theme) +{ + global $mod_strings, $sugar_config, $currentModule; + + $language_used = $language; + $default_language = $sugar_config['default_language']; + + include(SugarThemeRegistry::get($theme)->getFilePath()."/language/$current_language.lang.php"); + if(file_exists(SugarThemeRegistry::get($theme)->getFilePath()."/language/$current_language.lang.override.php")){ + include(SugarThemeRegistry::get($theme)->getFilePath()."/language/$current_language.lang.override.php"); + } + if(file_exists(SugarThemeRegistry::get($theme)->getFilePath()."/language/$current_language.lang.php.override")){ + echo 'Please Change:
            ' . SugarThemeRegistry::get($theme)->getFilePath()."/language/$current_language.lang.php.override" . '
            to
            ' . 'Please Change:
            ' . SugarThemeRegistry::get($theme)->getFilePath()."/language/$current_language.lang.override.php"; + include(SugarThemeRegistry::get($theme)->getFilePath()."/language/$current_language.lang.php.override"); + } + if(!isset($theme_strings)) + { + $GLOBALS['log']->warn("Unable to find the theme file for language: ".$language." and theme: ".$theme); + require(SugarThemeRegistry::get($theme)->getFilePath()."/language/$default_language.lang.php"); + $language_used = $default_language; + } + + if(!isset($theme_strings)) + { + $GLOBALS['log']->fatal("Unable to load the theme($theme) language file for the selected language($language) or the default language($default_language)"); + return null; + } + + // If we are in debug mode for translating, turn on the prefix now! + if($sugar_config['translation_string_prefix']) + { + foreach($theme_strings as $entry_key=>$entry_value) + { + $theme_strings[$entry_key] = $language_used.' '.$entry_value; + } + } + + return $theme_strings; +} + + + +/** If the session variable is defined and is not equal to "" then return it. Otherwise, return the default value. + * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc. + * All Rights Reserved. + * Contributor(s): ______________________________________.. + */ +function return_session_value_or_default($varname, $default) +{ + if(isset($_SESSION[$varname]) && $_SESSION[$varname] != "") + { + return $_SESSION[$varname]; + } + + return $default; +} + +/** + * Creates an array of where restrictions. These are used to construct a where SQL statement on the query + * It looks for the variable in the $_REQUEST array. If it is set and is not "" it will create a where clause out of it. + * @param &$where_clauses - The array to append the clause to + * @param $variable_name - The name of the variable to look for an add to the where clause if found + * @param $SQL_name - [Optional] If specified, this is the SQL column name that is used. If not specified, the $variable_name is used as the SQL_name. + * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc. + * All Rights Reserved. + * Contributor(s): ______________________________________.. + */ +function append_where_clause(&$where_clauses, $variable_name, $SQL_name = null) +{ + if($SQL_name == null) + { + $SQL_name = $variable_name; + } + + if(isset($_REQUEST[$variable_name]) && $_REQUEST[$variable_name] != "") + { + array_push($where_clauses, "$SQL_name like '".$GLOBALS['db']->quote($_REQUEST[$variable_name])."%'"); + } +} + +/** + * Generate the appropriate SQL based on the where clauses. + * @param $where_clauses - An Array of individual where clauses stored as strings + * @returns string where_clause - The final SQL where clause to be executed. + * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc. + * All Rights Reserved. + * Contributor(s): ______________________________________.. + */ +function generate_where_statement($where_clauses) +{ + $where = ""; + foreach($where_clauses as $clause) + { + if($where != "") + $where .= " and "; + $where .= $clause; + } + + $GLOBALS['log']->info("Here is the where clause for the list view: $where"); + return $where; +} + +/** + * determines if a passed string matches the criteria for a Sugar GUID + * @param string $guid + * @return bool False on failure + */ +function is_guid($guid) { + if(strlen($guid) != 36) { + return false; + } + + if(preg_match("/\w{8}-\w{4}-\w{4}-\w{4}-\w{12}/i", $guid)) { + return true; + } + + return true;; +} + + +/** + * A temporary method of generating GUIDs of the correct format for our DB. + * @return String contianing a GUID in the format: aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee + * + * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc. + * All Rights Reserved. + * Contributor(s): ______________________________________.. + */ +function create_guid() +{ + $microTime = microtime(); + list($a_dec, $a_sec) = explode(" ", $microTime); + + $dec_hex = dechex($a_dec* 1000000); + $sec_hex = dechex($a_sec); + + ensure_length($dec_hex, 5); + ensure_length($sec_hex, 6); + + $guid = ""; + $guid .= $dec_hex; + $guid .= create_guid_section(3); + $guid .= '-'; + $guid .= create_guid_section(4); + $guid .= '-'; + $guid .= create_guid_section(4); + $guid .= '-'; + $guid .= create_guid_section(4); + $guid .= '-'; + $guid .= $sec_hex; + $guid .= create_guid_section(6); + + return $guid; + +} + +function create_guid_section($characters) +{ + $return = ""; + for($i=0; $i<$characters; $i++) + { + $return .= dechex(mt_rand(0,15)); + } + return $return; +} + +function ensure_length(&$string, $length) +{ + $strlen = strlen($string); + if($strlen < $length) + { + $string = str_pad($string,$length,"0"); + } + else if($strlen > $length) + { + $string = substr($string, 0, $length); + } +} + +function microtime_diff($a, $b) { + list($a_dec, $a_sec) = explode(" ", $a); + list($b_dec, $b_sec) = explode(" ", $b); + return $b_sec - $a_sec + $b_dec - $a_dec; +} + +// check if Studio is displayed. +function displayStudioForCurrentUser() +{ + if ( is_admin($GLOBALS['current_user']) ) { + return true; + } + + + + return true; + +} + +function displayWorkflowForCurrentUser() +{ + $_SESSION['display_workflow_for_user'] = false; + return false; +} + +// return an array with all modules where the user is an admin. +function get_admin_modules_for_user($user) { + global $beanList; + $admin_modules = array(); + + return ($admin_modules); +} + + function get_workflow_admin_modules_for_user($user){ + if (isset($_SESSION['get_workflow_admin_modules_for_user'])) { + return $_SESSION['get_workflow_admin_modules_for_user']; + } + + global $moduleList; + $workflow_mod_list = array(); + foreach($moduleList as $module){ + $workflow_mod_list[$module] = $module; + } + + // This list is taken from teh previous version of workflow_utils.php + $workflow_mod_list['Tasks'] = "Tasks"; + $workflow_mod_list['Calls'] = "Calls"; + $workflow_mod_list['Meetings'] = "Meetings"; + $workflow_mod_list['Notes'] = "Notes"; + $workflow_mod_list['ProjectTask'] = "Project Tasks"; + $workflow_mod_list['Leads'] = "Leads"; + $workflow_mod_list['Opportunities'] = "Opportunities"; + // End of list + + $workflow_admin_modules = array(); + if(empty($user)) { + return $workflow_admin_modules; + } + $actions = ACLAction::getUserActions($user->id); + //check for ForecastSchedule because it doesn't exist in $workflow_mod_list + if (isset($actions['ForecastSchedule']['module']['admin']['aclaccess']) && ($actions['ForecastSchedule']['module']['admin']['aclaccess']==ACL_ALLOW_DEV || + $actions['ForecastSchedule']['module']['admin']['aclaccess']==ACL_ALLOW_ADMIN_DEV)) { + $workflow_admin_modules['Forecasts'] = 'Forecasts'; + } + foreach ($workflow_mod_list as $key=>$val) { + if(!in_array($val, $workflow_admin_modules) && ($val!='iFrames' && $val!='Feeds' && $val!='Home' && $val!='Dashboard' + && $val!='Calendar' && $val!='Activities' && $val!='Reports') && + (is_admin_for_module($user,$key))) { + $workflow_admin_modules[$key] = $val; + } + } + $_SESSION['get_workflow_admin_modules_for_user'] = $workflow_admin_modules; + return ($workflow_admin_modules); +} + +// Check if user is admin for at least one module. +function is_admin_for_any_module($user) { + return false; +} + + +// Check if user is admin for a specific module. +function is_admin_for_module($user,$module) { + return false; +} + + +/** + * Check if user id belongs to a system admin. + * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc. + * All Rights Reserved. + * Contributor(s): ______________________________________.. + */ +function is_admin($user) { + if(!empty($user) && ($user->is_admin == '1' || $user->is_admin === 'on')){ + return true; + } + + return false; +} + +/** + * Return the display name for a theme if it exists. + * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc. + * All Rights Reserved. + * Contributor(s): ______________________________________.. + * + * @deprecated use SugarThemeRegistry::get($theme)->name instead + */ +function get_theme_display($theme) +{ + return SugarThemeRegistry::get($theme)->name; +} + +/** + * Return an array of directory names. + * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc. + * All Rights Reserved. + * Contributor(s): ______________________________________.. + * + * @deprecated use SugarThemeRegistry::availableThemes() instead. + */ +function get_themes() +{ + return SugarThemeRegistry::availableThemes(); +} + +/** + * THIS FUNCTION IS DEPRECATED AND SHOULD NOT BE USED; USE get_select_options_with_id() + * Create HTML to display select options in a dropdown list. To be used inside + * of a select statement in a form. + * param $option_list - the array of strings to that contains the option list + * param $selected - the string which contains the default value + * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc. + * All Rights Reserved. + * Contributor(s): ______________________________________.. + */ +function get_select_options ($option_list, $selected) { + return get_select_options_with_id($option_list, $selected); +} + +/** + * Create HTML to display select options in a dropdown list. To be used inside + * of a select statement in a form. This method expects the option list to have keys and values. The keys are the ids. The values are the display strings. + * param $option_list - the array of strings to that contains the option list + * param $selected - the string which contains the default value + * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc. + * All Rights Reserved. + * Contributor(s): ______________________________________.. + */ +function get_select_options_with_id ($option_list, $selected_key) { + return get_select_options_with_id_separate_key($option_list, $option_list, $selected_key); +} + + +/** + * Create HTML to display select options in a dropdown list. To be used inside + * of a select statement in a form. This method expects the option list to have keys and values. The keys are the ids. The values are the display strings. + * param $label_list - the array of strings to that contains the option list + * param $key_list - the array of strings to that contains the values list + * param $selected - the string which contains the default value + * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc. + * All Rights Reserved. + * Contributor(s): ______________________________________.. + */ +function get_select_options_with_id_separate_key ($label_list, $key_list, $selected_key, $massupdate=false) { + global $app_strings; + $select_options = ""; + + //for setting null selection values to human readable --None-- + $pattern = "/'0?'>".$app_strings['LBL_NONE']."<"; + + if (empty($key_list)) $key_list = array(); + //create the type dropdown domain and set the selected value if $opp value already exists + foreach ($key_list as $option_key=>$option_value) { + + $selected_string = ''; + // the system is evaluating $selected_key == 0 || '' to true. Be very careful when changing this. Test all cases. + // The bug was only happening with one of the users in the drop down. It was being replaced by none. + if (($option_key != '' && $selected_key == $option_key) || ($selected_key == '' && $option_key == '' && !$massupdate) || (is_array($selected_key) && in_array($option_key, $selected_key))) + { + $selected_string = 'selected '; + } + + $html_value = $option_key; + + $select_options .= "\n"; + } + $select_options = preg_replace($pattern, $replacement, $select_options); + return $select_options; +} + + +/** + * Call this method instead of die(). + * Then we call the die method with the error message that is passed in. + */ +function sugar_die($error_message) +{ + global $focus; + sugar_cleanup(); + die($error_message); +} + + +/** + * Create javascript to clear values of all elements in a form. + * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc. + * All Rights Reserved. + * Contributor(s): ______________________________________.. + */ +function get_clear_form_js () { + $the_script = << +function clear_form(form) { + var newLoc = 'index.php?action=' + form.action.value + '&module=' + form.module.value + '&query=true&clear_query=true'; + if(typeof(form.advanced) != 'undefined'){ + newLoc += '&advanced=' + form.advanced.value; + } + document.location.href= newLoc; +} + +EOQ; + + return $the_script; +} + +/** + * Create javascript to set the cursor focus to specific field in a form + * when the screen is rendered. The field name is currently hardcoded into the + * the function. + * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc. + * All Rights Reserved. + * Contributor(s): ______________________________________.. + */ +function get_set_focus_js () { + //TODO Clint 5/20 - Make this function more generic so that it can take in the target form and field names as variables + $the_script = << + + +EOQ; + + return $the_script; +} + +/** + * Very cool algorithm for sorting multi-dimensional arrays. Found at http://us2.php.net/manual/en/function.array-multisort.php + * Syntax: $new_array = array_csort($array [, 'col1' [, SORT_FLAG [, SORT_FLAG]]]...); + * Explanation: $array is the array you want to sort, 'col1' is the name of the column + * you want to sort, SORT_FLAGS are : SORT_ASC, SORT_DESC, SORT_REGULAR, SORT_NUMERIC, SORT_STRING + * you can repeat the 'col',FLAG,FLAG, as often you want, the highest prioritiy is given to + * the first - so the array is sorted by the last given column first, then the one before ... + * Example: $array = array_csort($array,'town','age',SORT_DESC,'name'); + * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc. + * All Rights Reserved. + * Contributor(s): ______________________________________.. + */ +function array_csort() { + $args = func_get_args(); + $marray = array_shift($args); + $i = 0; + + $msortline = "return(array_multisort("; + foreach ($args as $arg) { + $i++; + if (is_string($arg)) { + foreach ($marray as $row) { + $sortarr[$i][] = $row[$arg]; + } + } else { + $sortarr[$i] = $arg; + } + $msortline .= "\$sortarr[".$i."],"; + } + $msortline .= "\$marray));"; + + eval($msortline); + return $marray; +} + +/** + * Converts localized date format string to jscalendar format + * Example: $array = array_csort($array,'town','age',SORT_DESC,'name'); + * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc. + * All Rights Reserved. + * Contributor(s): ______________________________________.. + */ +function parse_calendardate($local_format) { + preg_match('/\(?([^-]{1})[^-]*-([^-]{1})[^-]*-([^-]{1})[^-]*\)/', $local_format, $matches); + $calendar_format = "%" . $matches[1] . "-%" . $matches[2] . "-%" . $matches[3]; + return str_replace(array("y", "ᅣ1�7", "a", "j"), array("Y", "Y", "Y", "d"), $calendar_format); +} + + + + + +function translate($string, $mod='', $selectedValue=''){ + //$test_start = microtime(); + //static $mod_strings_results = array(); + if(!empty($mod)){ + global $current_language; + //Bug 31275 + if(isset($_REQUEST['login_language'])){ + $current_language = ($_REQUEST['login_language'] == $current_language)? $current_language : $_REQUEST['login_language']; + } + $mod_strings = return_module_language($current_language, $mod); + + }else{ + global $mod_strings; + } + + $returnValue = ''; + global $app_strings, $app_list_strings; + + if(isset($mod_strings[$string])) + $returnValue = $mod_strings[$string]; + else if(isset($app_strings[$string])) + $returnValue = $app_strings[$string]; + else if(isset($app_list_strings[$string])) + $returnValue = $app_list_strings[$string]; + else if(isset($app_list_strings['moduleList']) && isset($app_list_strings['moduleList'][$string])) + $returnValue = $app_list_strings['moduleList'][$string]; + + + //$test_end = microtime(); + // + // $mod_strings_results[$mod] = microtime_diff($test_start,$test_end); + // + // echo("translate results:"); + // $total_time = 0; + // $total_strings = 0; + // foreach($mod_strings_results as $key=>$value) + // { + // echo("Module $key \t\t time $value \t\t
            "); + // $total_time += $value; + // } + // + // echo("Total time: $total_time
            "); + + + + if(empty($returnValue)){ + return $string; + } + + if(is_array($returnValue) && ! empty($selectedValue) && isset($returnValue[$selectedValue]) ){ + return $returnValue[$selectedValue]; + } + + return $returnValue; +} + +function unTranslateNum($num) { + static $dec_sep; + static $num_grp_sep; + global $current_user, $sugar_config; + + if($dec_sep == null) { + $user_dec_sep = $current_user->getPreference('dec_sep'); + $dec_sep = (empty($user_dec_sep) ? $sugar_config['default_decimal_seperator'] : $user_dec_sep); + } + if($num_grp_sep == null) { + $user_num_grp_sep = $current_user->getPreference('num_grp_sep'); + $num_grp_sep = (empty($user_num_grp_sep) ? $sugar_config['default_number_grouping_seperator'] : $user_num_grp_sep); + } + + $num = preg_replace("'" . preg_quote($num_grp_sep) . "'", '', $num); + $num = preg_replace("'" . preg_quote($dec_sep) . "'", '.', $num); + return $num; + +} + +function add_http($url) { + if(!preg_match("@://@i", $url)) { + $scheme = "http"; + if(!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on') { + $scheme = 'https'; + } + + return "{$scheme}://{$url}"; + } + + return $url; +} + +/** + * returns a default array of XSS tags to clean + * @return array + */ +function getDefaultXssTags() { + $tmp = array( + "applet" => "applet", + "base" => "base", + "embed" => "embed", + "form" => "form", + "frame" => "frame", + "frameset" => "frameset", + "iframe" => "iframe", + "import" => "\?import", + "layer" => "layer", + "link" => "link", + "object" => "object", + "script" => "script", + "xmp" => "xmp", + ); + + $ret = base64_encode(serialize($tmp)); + + return $ret; +} + +/** + * Remove potential xss vectors from strings + * @param string str String to search for XSS attack vectors + * @param bool cleanImg Flag to allow tags to survive - only used by InboundEmail for inline images. + * @return string + */ +function remove_xss($str, $cleanImg=true) +{ + $potentials = clean_xss($str, $cleanImg); + if(is_array($potentials) && !empty($potentials)) { + foreach($potentials as $bad) { + $str = str_replace($bad, "", $str); + } + } + return $str; +} + +/** + * Detects typical XSS attack patterns + * @param string str String to search for XSS attack vectors + * @param bool cleanImg Flag to allow tags to survive - only used by InboundEmail for inline images. + * @return array Array of matches, empty on clean string + */ +function clean_xss($str, $cleanImg=true) { + global $sugar_config; + + if(empty($sugar_config['email_xss'])) + $sugar_config['email_xss'] = getDefaultXssTags(); + + $arr = unserialize(base64_decode($sugar_config['email_xss'])); + + $regex = ''; + foreach($arr as $v) { + if(!empty($regex)) { + $regex .= "|"; + } + $regex .= $v; + } + + $tag_regex = "#<({$regex})[^>]*>?#sim"; + + // cn: bug 13079 - "on\w" matched too many non-events (cONTact, strONG, etc.) + $jsEvents = "onblur|onfocus|oncontextmenu|onresize|onscroll|onunload|ondblclick|onclick|"; + $jsEvents .= "onmouseup|onmouseover|onmousedown|onmouseenter|onmouseleave|onmousemove|onload|onchange|"; + $jsEvents .= "onreset|onselect|onsubmit|onkeydown|onkeypress|onkeyup|onabort|onerror|ondragdrop"; + + $attribute_regex = "#<[^/>][^>]+({$jsEvents})[^=>]*=[^>]*>#sim"; + $javascript_regex = '@<[^/>][^>]+(expression\(|j\W*a\W*v\W*a|v\W*b\W*s\W*c\W*r|&#|/\*|\*/)[^>]*>@sim'; + $imgsrc_regex = '#<[^>]+src[^=]*=([^>]*?http://[^>]*)>#sim'; + $css_url = '#url\(.*\.\w+\)#'; + + + $str = str_replace("\t", "", $str); + + $matches = array_merge( + xss_check_pattern($tag_regex, $str), + xss_check_pattern($javascript_regex, $str), + xss_check_pattern($attribute_regex, $str) + ); + + if($cleanImg) { + $matches = array_merge($matches, + xss_check_pattern($imgsrc_regex, $str) + ); + } + + // cn: bug 13498 - custom white-list of allowed domains that vet remote images + preg_match_all($css_url, $str, $cssUrlMatches, PREG_PATTERN_ORDER); + + if(isset($sugar_config['security_trusted_domains']) && !empty($sugar_config['security_trusted_domains']) && is_array($sugar_config['security_trusted_domains'])) { + if(is_array($cssUrlMatches) && count($cssUrlMatches) > 0) { + // normalize whitelist + foreach($sugar_config['security_trusted_domains'] as $k => $v) { + $sugar_config['security_trusted_domains'][$k] = strtolower($v); + } + + foreach($cssUrlMatches[0] as $match) { + $domain = strtolower(substr(strstr($match, "://"), 3)); + $baseUrl = substr($domain, 0, strpos($domain, "/")); + + if(!in_array($baseUrl, $sugar_config['security_trusted_domains'])) { + $matches[] = $match; + } + } + } + } else { + $matches = array_merge($matches, $cssUrlMatches[0]); + } + + return $matches; +} + +/** + * Helper function used by clean_xss() to parse for known-bad vectors + * @param string pattern Regex pattern to use + * @param string str String to parse for badness + * @return array + */ +function xss_check_pattern($pattern, $str) { + preg_match_all($pattern, $str, $matches, PREG_PATTERN_ORDER); + return $matches[1]; +} + +// Designed to take a string passed in the URL as a parameter and clean all "bad" data from it +// The second argument is a string, "filter," which corresponds to a regular expression +function clean_string($str, $filter = "STANDARD") { + global $sugar_config; + + $filters = Array( + "STANDARD" => '#[^A-Z0-9\-_\.\@]#i', + "STANDARDSPACE" => '#[^A-Z0-9\-_\.\@\ ]#i', + "FILE" => '#[^A-Z0-9\-_\.]#i', + "NUMBER" => '#[^0-9\-]#i', + "SQL_COLUMN_LIST" => '#[^A-Z0-9,_\.]#i', + "PATH_NO_URL" => '#://#i', + "SAFED_GET" => '#[^A-Z0-9\@\=\&\?\.\/\-_~]#i', /* range of allowed characters in a GET string */ + "UNIFIED_SEARCH" => "#[\\x00]#", /* cn: bug 3356 & 9236 - MBCS search strings */ + "AUTO_INCREMENT" => '#[^0-9\-,\ ]#i', + "ALPHANUM" => '#[^A-Z0-9\-]#i', + ); + + if (preg_match($filters[$filter], $str)) { + if (isset($GLOBALS['log']) && is_object($GLOBALS['log'])) { + $GLOBALS['log']->fatal("SECURITY: bad data passed in; string: {$str}"); + } + die("Bad data passed in; Return to Home"); + } + else { + return $str; + } +} + +function clean_special_arguments() { + if(isset($_SERVER['PHP_SELF'])) { + if (!empty($_SERVER['PHP_SELF'])) clean_string($_SERVER['PHP_SELF'], 'SAFED_GET'); + } + if (!empty($_REQUEST) && !empty($_REQUEST['login_theme'])) clean_string($_REQUEST['login_theme'], "STANDARD"); + if (!empty($_REQUEST) && !empty($_REQUEST['login_module'])) clean_string($_REQUEST['login_module'], "STANDARD"); + if (!empty($_REQUEST) && !empty($_REQUEST['login_action'])) clean_string($_REQUEST['login_action'], "STANDARD"); + if (!empty($_REQUEST) && !empty($_REQUEST['ck_login_theme_20'])) clean_string($_REQUEST['ck_login_theme_20'], "STANDARD"); + if (!empty($_SESSION) && !empty($_SESSION['authenticated_user_theme'])) clean_string($_SESSION['authenticated_user_theme'], "STANDARD"); + if (!empty($_REQUEST) && !empty($_REQUEST['module_name'])) clean_string($_REQUEST['module_name'], "STANDARD"); + if (!empty($_REQUEST) && !empty($_REQUEST['module'])) clean_string($_REQUEST['module'], "STANDARD"); + if (!empty($_POST) && !empty($_POST['parent_type'])) clean_string($_POST['parent_type'], "STANDARD"); + if (!empty($_REQUEST) && !empty($_REQUEST['mod_lang'])) clean_string($_REQUEST['mod_lang'], "STANDARD"); + if (!empty($_SESSION) && !empty($_SESSION['authenticated_user_language'])) clean_string($_SESSION['authenticated_user_language'], "STANDARD"); + if (!empty($_SESSION) && !empty($_SESSION['dyn_layout_file'])) clean_string($_SESSION['dyn_layout_file'], "PATH_NO_URL"); + if (!empty($_GET) && !empty($_GET['from'])) clean_string($_GET['from']); + if (!empty($_GET) && !empty($_GET['gmto'])) clean_string($_GET['gmto'], "NUMBER"); + if (!empty($_GET) && !empty($_GET['case_number'])) clean_string($_GET['case_number'], "AUTO_INCREMENT"); + if (!empty($_GET) && !empty($_GET['bug_number'])) clean_string($_GET['bug_number'], "AUTO_INCREMENT"); + if (!empty($_GET) && !empty($_GET['quote_num'])) clean_string($_GET['quote_num'], "AUTO_INCREMENT"); + clean_superglobals('stamp', 'ALPHANUM'); // for vcr controls + clean_superglobals('offset', 'ALPHANUM'); + clean_superglobals('return_action'); + clean_superglobals('return_module'); + return TRUE; +} + +/** + * cleans the given key in superglobals $_GET, $_POST, $_REQUEST + */ +function clean_superglobals($key, $filter = 'STANDARD') { + if(isset($_GET[$key])) clean_string($_GET[$key], $filter); + if(isset($_POST[$key])) clean_string($_POST[$key], $filter); + if(isset($_REQUEST[$key])) clean_string($_REQUEST[$key], $filter); +} + +function set_superglobals($key, $val){ + $_GET[$key] = $val; + $_POST[$key] = $val; + $_REQUEST[$key] = $val; +} + +// Works in conjunction with clean_string() to defeat SQL injection, file inclusion attacks, and XSS +function clean_incoming_data() { + global $sugar_config; + + if (get_magic_quotes_gpc() == 1) { + $req = array_map("preprocess_param", $_REQUEST); + $post = array_map("preprocess_param", $_POST); + $get = array_map("preprocess_param", $_GET); + } else { + + $req = array_map("securexss", $_REQUEST); + $post = array_map("securexss", $_POST); + $get = array_map("securexss", $_GET); + } + + // PHP cannot stomp out superglobals reliably + foreach($post as $k => $v) { $_POST[$k] = $v; } + foreach($get as $k => $v) { $_GET[$k] = $v; } + foreach($req as $k => $v) { + $_REQUEST[$k] = $v; + //ensure the keys are safe as well + securexsskey($k); + } + // Any additional variables that need to be cleaned should be added here + if (isset($_REQUEST['login_theme'])) clean_string($_REQUEST['login_theme']); + if (isset($_REQUEST['login_module'])) clean_string($_REQUEST['login_module']); + if (isset($_REQUEST['login_action'])) clean_string($_REQUEST['login_action']); + if (isset($_REQUEST['login_language'])) clean_string($_REQUEST['login_language']); + if (isset($_REQUEST['action'])) clean_string($_REQUEST['action']); + if (isset($_REQUEST['module'])) clean_string($_REQUEST['module']); + if (isset($_REQUEST['record'])) clean_string($_REQUEST['record'], 'STANDARDSPACE'); + if (isset($_SESSION['authenticated_user_theme'])) clean_string($_SESSION['authenticated_user_theme']); + if (isset($_SESSION['authenticated_user_language'])) clean_string($_SESSION['authenticated_user_language']); + if (isset($_REQUEST['language'])) clean_string($_REQUEST['language']); + if (isset($sugar_config['default_theme'])) clean_string($sugar_config['default_theme']); + if (isset($_REQUEST['offset'])) clean_string($_REQUEST['offset']); + if (isset($_REQUEST['stamp'])) clean_string($_REQUEST['stamp']); + + if(isset($_REQUEST['lvso'])){ + set_superglobals('lvso', (strtolower($_REQUEST['lvso']) === 'desc')?'desc':'asc'); + } + // Clean "offset" and "order_by" parameters in URL + foreach ($_REQUEST as $key => $val) { + if (str_end($key, "_offset")) { + clean_string($_REQUEST[$key], "ALPHANUM"); // keep this ALPHANUM for disable_count_query + set_superglobals($key, $_REQUEST[$key]); + } + elseif (str_end($key, "_ORDER_BY")) { + clean_string($_REQUEST[$key], "SQL_COLUMN_LIST"); + set_superglobals($key, $_REQUEST[$key]); + } + } + + + return 0; +} + +// Returns TRUE if $str begins with $begin +function str_begin($str, $begin) { + return (substr($str, 0, strlen($begin)) == $begin); +} + +// Returns TRUE if $str ends with $end +function str_end($str, $end) { + return (substr($str, strlen($str) - strlen($end)) == $end); +} + +function securexss($value) { + if(is_array($value)){ + $new = array(); + foreach($value as $key=>$val){ + $new[$key] = securexss($val); + } + return $new; + } + static $xss_cleanup= array('"' =>'"', "'" => ''' , '<' =>'<' , '>'=>'>'); + $value = preg_replace(array('/javascript:/i', '/\0/'), array('java script:', ''), $value); + $value = preg_replace('/javascript:/i', 'java script:', $value); + return str_replace(array_keys($xss_cleanup), array_values($xss_cleanup), $value); +} + +function securexsskey($value, $die=true){ + global $sugar_config; + $matches = array(); + preg_match("/[\'\"\<\>]/", $value, $matches); + if(!empty($matches)){ + if($die){ + die("Bad data passed in; Return to Home"); + }else{ + unset($_REQUEST[$value]); + unset($_POST[$value]); + unset($_GET[$value]); + } + } +} + +function preprocess_param($value){ + if(is_string($value)){ + if(get_magic_quotes_gpc() == 1){ + $value = stripslashes($value); + } + + $value = securexss($value); + } + + + return $value; + + +} + +function set_register_value($category, $name, $value){ + return sugar_cache_put("{$category}:{$name}", $value); +} + +function get_register_value($category,$name){ + return sugar_cache_retrieve("{$category}:{$name}"); +} + +// this function cleans id's when being imported +function convert_id($string) +{ + return preg_replace_callback( '|[^A-Za-z0-9\-]|', + create_function( + // single quotes are essential here, + // or alternative escape all $ as \$ + '$matches', + 'return ord($matches[0]);' + ) ,$string); +} + +/** + * @deprecated use SugarTheme::getImage() + */ +function get_image($image,$other_attributes,$width="",$height="") +{ + return SugarThemeRegistry::current()->getImage(basename($image), + $other_attributes, + empty($width) ? null : $width, + empty($height) ? null : $height + ); +} +/** + * @deprecated use SugarTheme::getImageURL() + */ +function getImagePath($image_name) +{ + return SugarThemeRegistry::current()->getImageURL($image_name); +} + +function getWebPath($relative_path){ + //if it has a :// then it isn't a relative path + if(substr_count($relative_path, '://') > 0) return $relative_path; + if(defined('TEMPLATE_URL'))$relative_path = SugarTemplateUtilities::getWebPath($relative_path); + return $relative_path; +} + +function getJSPath($relative_path, $additional_attrs=''){ + if(defined('TEMPLATE_URL'))$relative_path = SugarTemplateUtilities::getWebPath($relative_path); + if(empty($GLOBALS['sugar_config']['js_custom_version']))$GLOBALS['sugar_config']['js_custom_version'] = 1; + $js_version_key = isset($GLOBALS['js_version_key'])?$GLOBALS['js_version_key']:''; + $path = $relative_path . '?s=' . $js_version_key . '&c=' . $GLOBALS['sugar_config']['js_custom_version'] ; + if ( inDeveloperMode() ) $path .= '&developerMode='.mt_rand(); + if(!empty($additonal_attrs)) $path .= '&' . $additional_attrs; + return $path; +} + +function getSWFPath($relative_path, $additional_params=''){ + $path = $relative_path; + if (!empty($additional_params)){ + $path .= '?' . $additional_params; + } + if (defined('TEMPLATE_URL')){ + $path = TEMPLATE_URL . '/' . $path; + } + return $path; +} + + + + + +function getSQLDate($date_str) +{ + if (preg_match('/^(\d{1,2})-(\d{1,2})-(\d{4})$/',$date_str,$match)) + { + if ( strlen($match[2]) == 1) + { + $match[2] = "0".$match[2]; + } + if ( strlen($match[1]) == 1) + { + $match[1] = "0".$match[1]; + } + return "{$match[3]}-{$match[1]}-{$match[2]}"; + } + else if (preg_match('/^(\d{1,2})\/(\d{1,2})\/(\d{4})$/',$date_str,$match)) + { + if ( strlen($match[2]) == 1) + { + $match[2] = "0".$match[2]; + } + if ( strlen($match[1]) == 1) + { + $match[1] = "0".$match[1]; + } + return "{$match[3]}-{$match[1]}-{$match[2]}"; + } + else + { + return ""; + } +} + +function clone_history(&$db, $from_id,$to_id, $to_type) +{ + global $timedate; + $old_note_id=null; + $old_filename=null; + require_once('include/upload_file.php'); + $tables = array('calls'=>'Call', 'meetings'=>'Meeting', 'notes'=>'Note', 'tasks'=>'Task'); + + $location=array('Email'=>"modules/Emails/Email.php", + 'Call'=>"modules/Calls/Call.php", + 'Meeting'=>"modules/Meetings/Meeting.php", + 'Note'=>"modules/Notes/Note.php", + 'Tasks'=>"modules/Tasks/Task.php", + ); + + + foreach($tables as $table=>$bean_class) + { + + if (!class_exists($bean_class)) + { + require_once($location[$bean_class]); + } + + $bProcessingNotes=false; + if ($table=='notes') + { + $bProcessingNotes=true; + } + $query = "SELECT id FROM $table WHERE parent_id='$from_id'"; + $results = $db->query($query); + while($row = $db->fetchByAssoc($results)) + { + //retrieve existing record. + $bean= new $bean_class(); + $bean->retrieve($row['id']); + //process for new instance. + if ($bProcessingNotes) + { + $old_note_id=$row['id']; + $old_filename=$bean->filename; + } + $bean->id=null; + $bean->parent_id=$to_id; + $bean->parent_type=$to_type; + if ($to_type=='Contacts' and in_array('contact_id',$bean->column_fields)) + { + $bean->contact_id=$to_id; + } + $bean->update_date_modified = false; + $bean->update_modified_by = false; + if(isset($bean->date_modified)) + $bean->date_modified = $timedate->to_db($bean->date_modified); + if(isset($bean->date_entered)) + $bean->date_entered = $timedate->to_db($bean->date_entered); + //save + $new_id=$bean->save(); + + //duplicate the file now. for notes. + if ($bProcessingNotes && !empty($old_filename)) + { + UploadFile::duplicate_file($old_note_id,$new_id,$old_filename); + } + //reset the values needed for attachment duplication. + $old_note_id=null; + $old_filename=null; + } + } +} + +function values_to_keys($array) +{ + $new_array = array(); + if(!is_array($array)) + { + return $new_array; + } + foreach($array as $arr){ + $new_array[$arr] = $arr; + } + return $new_array; +} + +function clone_relationship(&$db, $tables = array(), $from_column, $from_id, $to_id) +{ + foreach($tables as $table) + { + + if ($table == 'emails_beans') { + $query = "SELECT * FROM $table WHERE $from_column='$from_id' and bean_module='Leads'"; + } else { + $query = "SELECT * FROM $table WHERE $from_column='$from_id'"; + } + $results = $db->query($query); + while($row = $db->fetchByAssoc($results)) + { + $query = "INSERT INTO $table "; + $names = ''; + $values = ''; + $row[$from_column] = $to_id; + $row['id'] = create_guid(); + if ($table=='emails_beans') { + $row['bean_module'] =='Contacts'; + } + + foreach($row as $name=>$value) + { + + if(empty($names)) + { + $names .= $name; + $values .= "'$value'"; + } else + { + $names .= ', '. $name; + $values .= ", '$value'"; + } + } + $query .= "($names) VALUES ($values)"; + $db->query($query); + } + } +} + +function get_unlinked_email_query($type, $bean) { + global $current_user; + + $return_array['select']='SELECT emails.id '; + $return_array['from']='FROM emails '; + $return_array['where']=""; + $return_array['join'] = " JOIN (select distinct email_id from emails_email_addr_rel eear + + join email_addr_bean_rel eabr on eabr.bean_id ='$bean->id' and eabr.bean_module = '$bean->module_dir' and + eabr.email_address_id = eear.email_address_id and eabr.deleted=0 + where eear.deleted=0 and eear.email_id not in + (select eb.email_id from emails_beans eb where eb.bean_module ='$bean->module_dir' and eb.bean_id = '$bean->id') + ) derivedemails on derivedemails.email_id = emails.id"; + $return_array['join_tables'][0] = ''; + + if (isset($type) and isset($type['return_as_array']) and $type['return_as_array']==true) { + return $return_array; + } + + return $return_array['select'] . $return_array['from'] . $return_array['where']; +} // fn + +/** + * Check to see if the number is empty or non-zero + * @param $value + * @return boolean + **/ +function number_empty($value) +{ + return empty($value) && $value != '0'; +} + +function get_bean_select_array($add_blank=true, $bean_name, $display_columns, $where='', $order_by='', $blank_is_none=false) +{ + global $beanFiles; + require_once($beanFiles[$bean_name]); + $focus = new $bean_name(); + $user_array = array(); + $user_array = get_register_value('select_array',$bean_name. $display_columns. $where . $order_by); + if(!$user_array) + { + + $db = DBManagerFactory::getInstance(); + $temp_result = Array(); + $query = "SELECT id, {$display_columns} as display from {$focus->table_name} "; + $query .= "where "; + if ( $where != '') + { + $query .= $where." AND "; + } + + $query .= " deleted=0"; + + if ( $order_by != '') + { + $query .= ' order by '.$order_by; + } + + $GLOBALS['log']->debug("get_user_array query: $query"); + $result = $db->query($query, true, "Error filling in user array: "); + + if ($add_blank==true){ + // Add in a blank row + if($blank_is_none == true) { // set 'blank row' to "--None--" + global $app_strings; + $temp_result[''] = $app_strings['LBL_NONE']; + } else { + $temp_result[''] = ''; + } + } + + // Get the id and the name. + while($row = $db->fetchByAssoc($result)) + { + $temp_result[$row['id']] = $row['display']; + } + + $user_array = $temp_result; + set_register_value('select_array',$bean_name. $display_columns. $where . $order_by,$temp_result); + } + + return $user_array; + +} +/** + * + * + * @param unknown_type $listArray + */ +// function parse_list_modules +// searches a list for items in a user's allowed tabs and returns an array that removes unallowed tabs from list +function parse_list_modules(&$listArray) +{ + global $modListHeader; + $returnArray = array(); + + foreach($listArray as $optionName => $optionVal) + { + if(array_key_exists($optionName, $modListHeader)) + { + $returnArray[$optionName] = $optionVal; + } + + // special case for projects + if(array_key_exists('Project', $modListHeader)) + { + $returnArray['ProjectTask'] = $listArray['ProjectTask']; + } + } + $acldenied = ACLController::disabledModuleList($listArray,false); + foreach($acldenied as $denied){ + unset($returnArray[$denied]); + } + asort($returnArray); + + return $returnArray; +} + +function display_notice($msg = false){ + global $error_notice; + //no error notice - lets just display the error to the user + if(!isset($error_notice)){ + echo '
            '.$msg . '
            '; + }else{ + $error_notice .= $msg . '
            '; + } +} + +/* checks if it is a number that atleast has the plus at the beggining + */ +function skype_formatted($number){ + //kbrill - BUG #15375 + if(isset($_REQUEST['action']) && $_REQUEST['action']=="Popup") { + return false; + } else { + return substr($number, 0, 1) == '+' || substr($number, 0, 2) == '00' || substr($number, 0, 3) == '011'; + } +// return substr($number, 0, 1) == '+' || substr($number, 0, 2) == '00' || substr($number, 0, 2) == '011'; +} + +function format_skype($number) { + return preg_replace('/[^\+0-9]/','',$number); +} + +function insert_charset_header() { + header('Content-Type: text/html; charset=UTF-8'); +} + +function getCurrentURL() +{ + $href = "http:"; + if(!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on') + { + $href = 'https:'; + } + + $href.= "//".$_SERVER['HTTP_HOST'].$_SERVER['SCRIPT_NAME'].'?'.$_SERVER['QUERY_STRING']; + return $href; +} + +function javascript_escape($str) { + $new_str = ''; + + for($i = 0; $i < strlen($str); $i++) { + + if(ord(substr($str, $i, 1))==10){ + $new_str .= '\n'; + }elseif(ord(substr($str, $i, 1))==13){ + $new_str .= '\r'; + } + else { + $new_str .= $str{$i}; + } + } + + $new_str = str_replace("'", "\\'", $new_str); + + return $new_str; +} + +function js_escape($str, $keep=true){ + $str = html_entity_decode(str_replace("\\", "", $str), ENT_QUOTES); + + if($keep){ + $str = javascript_escape($str); + } + else { + $str = str_replace("'", " ", $str); + $str = str_replace('"', " ", $str); + } + + return $str; + + //end function js_escape +} + +function br2nl($str) { + $regex = "#<[^>]+br.+?>#i"; + preg_match_all($regex, $str, $matches); + + foreach($matches[0] as $match) { + $str = str_replace($match, "
            ", $str); + } + + $brs = array('
            ','
            ', '
            '); + $str = str_replace("\r\n", "\n", $str); // make from windows-returns, *nix-returns + $str = str_replace("\n\r", "\n", $str); // make from windows-returns, *nix-returns + $str = str_replace("\r", "\n", $str); // make from windows-returns, *nix-returns + $str = str_ireplace($brs, "\n", $str); // to retrieve it + + return $str; +} + +/** + * Private helper function for displaying the contents of a given variable. + * This function is only intended to be used for SugarCRM internal development. + * The ppd stands for Pre Print Die. + */ +function _ppd($mixed) +{ +} + + +/** + * Private helper function for displaying the contents of a given variable in + * the Logger. This function is only intended to be used for SugarCRM internal + * development. The pp stands for Pre Print. + * @param $mixed var to print_r() + * @param $die boolean end script flow + * @param $displayStackTrace also show stack trace + */ +function _ppl($mixed, $die=false, $displayStackTrace=false, $loglevel="fatal") { +} + +/** + * private helper function to quickly show the major, direct, field attributes of a given bean. + * The ppf stands for Pre[formatted] Print Focus [object] + * @param object bean The focus bean + */ +function _ppf($bean, $die=false) { +} + + + +/** + * Private helper function for displaying the contents of a given variable. + * This function is only intended to be used for SugarCRM internal development. + * The pp stands for Pre Print. + */ +function _pp($mixed) +{ +} + +/** + * Private helper function for displaying the contents of a given variable. + * This function is only intended to be used for SugarCRM internal development. + * The pp stands for Pre Print. + */ +function _pstack_trace($mixed=NULL) +{ +} + +/** + * Private helper function for displaying the contents of a given variable. + * This function is only intended to be used for SugarCRM internal development. + * The pp stands for Pre Print Trace. + */ +function _ppt($mixed, $textOnly=false) +{ +} + +/** + * Private helper function for displaying the contents of a given variable. + * This function is only intended to be used for SugarCRM internal development. + * The pp stands for Pre Print Trace Die. + */ +function _pptd($mixed) +{ +} + +/** + * Private helper function for decoding javascript UTF8 + * This function is only intended to be used for SugarCRM internal development. + */ +function decodeJavascriptUTF8($str) { +} + +/** + * Will check if a given PHP version string is supported (tested on this ver), + * unsupported (results unknown), or invalid (something will break on this + * ver). Do not pass in any pararameter to default to a check against the + * current environment's PHP version. + * + * @return 1 implies supported, 0 implies unsupported, -1 implies invalid + */ +function check_php_version($sys_php_version = '') { + $sys_php_version = empty($sys_php_version) ? constant('PHP_VERSION') : $sys_php_version; + // versions below $min_considered_php_version considered invalid by default, + // versions equal to or above this ver will be considered depending + // on the rules that follow + $min_considered_php_version = '5.2.1'; + + // only the supported versions, + // should be mutually exclusive with $invalid_php_versions + $supported_php_versions = array ( + '5.2.1', '5.2.2', '5.2.3', '5.2.4', '5.2.5', '5.2.6', '5.2.8', '5.3.0' + ); + //Find out what Database the system is using. + global $sugar_config; + $dbType = ''; + if (isset($_REQUEST['setup_db_type'])) { + $dbType = $_REQUEST['setup_db_type']; + } else if (isset ($sugar_config['dbconfig']) && isset ($sugar_config['dbconfig']['db_type'])) { + $dbType = $sugar_config['dbconfig']['db_type']; + } + + // invalid versions above the $min_considered_php_version, + // should be mutually exclusive with $supported_php_versions + + // SugarCRM prohibits install on PHP 5.2.7 on all platforms + $invalid_php_versions = array('5.2.7'); + + // default unsupported + $retval = 0; + + // versions below $min_considered_php_version are invalid + if(1 == version_compare($sys_php_version, $min_considered_php_version, '<')) { + $retval = -1; + } + + // supported version check overrides default unsupported + foreach($supported_php_versions as $ver) { + if(1 == version_compare($sys_php_version, $ver, 'eq') || strpos($sys_php_version,$ver) !== false) { + $retval = 1; + break; + } + } + + // invalid version check overrides default unsupported + foreach($invalid_php_versions as $ver) { + if(1 == version_compare($sys_php_version, $ver, 'eq') && strpos($sys_php_version,$ver) !== false) { + $retval = -1; + break; + } + } + + //allow a redhat distro to install, regardless of version. We are assuming the redhat naming convention is followed + //and the php version contains 'rh' characters + if(strpos($sys_php_version, 'rh') !== false) { + $retval = 1; + } + + return $retval; +} + +/** + * Will check if a given IIS version string is supported (tested on this ver), + * unsupported (results unknown), or invalid (something will break on this + * ver). + * + * @return 1 implies supported, 0 implies unsupported, -1 implies invalid + */ +function check_iis_version($sys_iis_version = '') { + + $server_software = $_SERVER["SERVER_SOFTWARE"]; + $iis_version = ''; + if(strpos($server_software,'Microsoft-IIS') !== false && preg_match_all("/^.*\/(\d+\.?\d*)$/", $server_software, $out)) + $iis_version = $out[1][0]; + + $sys_iis_version = empty($sys_iis_version) ? $iis_version : $sys_iis_version; + + // versions below $min_considered_iis_version considered invalid by default, + // versions equal to or above this ver will be considered depending + // on the rules that follow + $min_considered_iis_version = '6.0'; + + // only the supported versions, + // should be mutually exclusive with $invalid_iis_versions + $supported_iis_versions = array ('6.0', '7.0',); + $unsupported_iis_versions = array(); + $invalid_iis_versions = array('5.0',); + + // default unsupported + $retval = 0; + + // versions below $min_considered_iis_version are invalid + if(1 == version_compare($sys_iis_version, $min_considered_iis_version, '<')) { + $retval = -1; + } + + // supported version check overrides default unsupported + foreach($supported_iis_versions as $ver) { + if(1 == version_compare($sys_iis_version, $ver, 'eq') || strpos($sys_iis_version,$ver) !== false) { + $retval = 1; + break; + } + } + + // unsupported version check overrides default unsupported + foreach($unsupported_iis_versions as $ver) { + if(1 == version_compare($sys_iis_version, $ver, 'eq') && strpos($sys_iis_version,$ver) !== false) { + $retval = 0; + break; + } + } + + // invalid version check overrides default unsupported + foreach($invalid_iis_versions as $ver) { + if(1 == version_compare($sys_iis_version, $ver, 'eq') && strpos($sys_iis_version,$ver) !== false) { + $retval = -1; + break; + } + } + + return $retval; +} + +function pre_login_check(){ + global $action, $login_error; + if(!empty($action)&& $action == 'Login'){ + + if(!empty($login_error)){ + $login_error = htmlentities($login_error); + $login_error = str_replace(array("<pre>","</pre>","\r\n", "\n"), "
            ", $login_error); + $_SESSION['login_error'] = $login_error; + echo ''; + } + } +} + + + +function sugar_cleanup($exit = false) { + static $called = false; + if($called)return; + $called = true; + set_include_path(realpath(dirname(__FILE__) . '/..') . PATH_SEPARATOR . get_include_path()); + chdir(realpath(dirname(__FILE__) . '/..')); + global $sugar_config; + require_once('include/utils/LogicHook.php'); + LogicHook::initialize(); + $GLOBALS['logic_hook']->call_custom_logic('', 'server_round_trip'); + + //added this check to avoid errors during install. + if (empty($sugar_config['dbconfig'])) { + if ($exit) exit; else return; + } + + if (!class_exists('Tracker', true)) { + require_once 'modules/Trackers/Tracker.php'; + } + Tracker::logPage(); + // Now write the cached tracker_queries + if(!empty($GLOBALS['savePreferencesToDB']) && $GLOBALS['savePreferencesToDB']) { + if ( isset($GLOBALS['current_user']) && $GLOBALS['current_user'] instanceOf User ) + $GLOBALS['current_user']->savePreferencesToDB(); + } + + //check to see if this is not an ajax call AND the user preference error flag is set + if( + (isset($_SESSION['USER_PREFRENCE_ERRORS']) && $_SESSION['USER_PREFRENCE_ERRORS']) + && ($_REQUEST['action']!='modulelistmenu' && $_REQUEST['action']!='DynamicAction') + && (empty($_REQUEST['to_pdf']) || !$_REQUEST['to_pdf'] ) + && (empty($_REQUEST['sugar_body_only']) || !$_REQUEST['sugar_body_only'] ) + + ){ + global $app_strings; + //this is not an ajax call and the user preference error flag is set, so reset the flag and print js to flash message + $err_mess = $app_strings['ERROR_USER_PREFS']; + $_SESSION['USER_PREFRENCE_ERRORS'] = false; + echo " + "; + + } + + pre_login_check(); + if(class_exists('DBManagerFactory')) { + $db = DBManagerFactory::getInstance(); + $db->disconnect(); + if($exit) { + exit; + } + } +} + +register_shutdown_function('sugar_cleanup'); + + +/* + check_logic_hook - checks to see if your custom logic is in the logic file + if not, it will add it. If the file isn't built yet, it will create the file + + */ +function check_logic_hook_file($module_name, $event, $action_array){ + require_once('include/utils/logic_utils.php'); + $add_logic = false; + + if(file_exists("custom/modules/$module_name/logic_hooks.php")){ + + $hook_array = get_hook_array($module_name); + + if(check_existing_element($hook_array, $event, $action_array)==true){ + //the hook at hand is present, so do nothing + } else { + $add_logic = true; + + $logic_count = count($hook_array[$event]); + if($action_array[0]==""){ + $action_array[0] = $logic_count + 1; + } + $hook_array[$event][] = $action_array; + + } + //end if the file exists already + } else { + $add_logic = true; + if($action_array[0]==""){ + $action_array[0] = 1; + } + $hook_array = array(); + $hook_array[$event][] = $action_array; + //end if else file exists already + } + if($add_logic == true){ + + //reorder array by element[0] + //$hook_array = reorder_array($hook_array, $event); + //!!!Finish this above TODO + + $new_contents = replace_or_add_logic_type($hook_array); + write_logic_file($module_name, $new_contents); + + //end if add_element is true + } + + //end function check_logic_hook_file +} + +function remove_logic_hook($module_name, $event, $action_array) { + require_once('include/utils/logic_utils.php'); + $add_logic = false; + + if(file_exists("custom/modules/".$module_name."/logic_hooks.php")){ + // The file exists, let's make sure the hook is there + $hook_array = get_hook_array($module_name); + + if(check_existing_element($hook_array, $event, $action_array)==true){ + // The hook is there, time to take it out. + + foreach ( $hook_array[$event] as $i => $hook ) { + // We don't do a full comparison below just in case the filename changes + if ( $hook[0] == $action_array[0] + && $hook[1] == $action_array[1] + && $hook[3] == $action_array[3] + && $hook[4] == $action_array[4] ) { + unset($hook_array[$event][$i]); + } + } + + $new_contents = replace_or_add_logic_type($hook_array); + write_logic_file($module_name, $new_contents); + + } + } +} + +function display_stack_trace($textOnly=false){ + + $stack = debug_backtrace(); + + echo "\n\n display_stack_trace caller, file: " . $stack[0]['file']. ' line#: ' .$stack[0]['line']; + + if(!$textOnly) + echo '
            '; + + $first = true; + $out = ''; + + foreach($stack as $item) { + $file = ''; + $class = ''; + $line = ''; + $function = ''; + + if(isset($item['file'])) + $file = $item['file']; + if(isset($item['class'])) + $class = $item['class']; + if(isset($item['line'])) + $line = $item['line']; + if(isset($item['function'])) + $function = $item['function']; + + if(!$first) { + if(!$textOnly) { + $out .= ''; + } + + $out .= $file; + + if(!$textOnly) { + $out .= ''; + } + + $out .= "[L:{$line}]"; + + if(!$textOnly) { + $out .= ''; + } + + $out .= "({$class}:{$function})"; + + if(!$textOnly) { + $out .= '
            '; + } else { + $out .= "\n"; + } + } else { + $first = false; + } + } + + echo $out; +} + +function StackTraceErrorHandler($errno, $errstr, $errfile,$errline, $errcontext) { + $error_msg = " $errstr occured in $errfile on line $errline [" . date("Y-m-d H:i:s") . ']'; + $halt_script = true; + switch($errno){ + case 2048: return; //depricated we have lots of these ignore them + case E_USER_NOTICE: + case E_NOTICE: + if ( error_reporting() & E_NOTICE ) { + $halt_script = false; + $type = 'Notice'; + } + else + return; + break; + case E_USER_WARNING: + case E_COMPILE_WARNING: + case E_CORE_WARNING: + case E_WARNING: + + $halt_script = false; + $type = "Warning"; + break; + + case E_USER_ERROR: + case E_COMPILE_ERROR: + case E_CORE_ERROR: + case E_ERROR: + + $type = "Fatal Error"; + break; + + case E_PARSE: + + $type = "Parse Error"; + break; + + default: + //don't know what it is might not be so bad + $halt_script = false; + $type = "Unknown Error ($errno)"; + break; + } + $error_msg = ''.$type.':' . $error_msg; + echo $error_msg; + display_stack_trace(); + if($halt_script){ + exit -1; + } + + + +} + + +if(isset($sugar_config['stack_trace_errors']) && $sugar_config['stack_trace_errors']){ + + set_error_handler('StackTraceErrorHandler'); +} +function get_sub_cookies($name){ + $cookies = array(); + if(isset($_COOKIE[$name])){ + $subs = explode('#', $_COOKIE[$name]); + foreach($subs as $cookie){ + if(!empty($cookie)){ + $cookie = explode('=', $cookie); + + $cookies[$cookie[0]] = $cookie[1]; + } + } + } + return $cookies; + +} + + +function mark_delete_components($sub_object_array, $run_second_level=false, $sub_sub_array=""){ + + if(!empty($sub_object_array)){ + + foreach($sub_object_array as $sub_object){ + + //run_second level is set to true if you need to remove sub-sub components + if($run_second_level==true){ + + mark_delete_components($sub_object->get_linked_beans($sub_sub_array['rel_field'],$sub_sub_array['rel_module'])); + + //end if run_second_level is true + } + $sub_object->mark_deleted($sub_object->id); + //end foreach sub component + } + //end if this is not empty + } + + //end function mark_delete_components +} + +/** + * For translating the php.ini memory values into bytes. e.g. input value of '8M' will return 8388608. + */ +function return_bytes($val) +{ + $val = trim($val); + $last = strtolower($val{strlen($val)-1}); + + switch($last) + { + // The 'G' modifier is available since PHP 5.1.0 + case 'g': + $val *= 1024; + case 'm': + $val *= 1024; + case 'k': + $val *= 1024; + } + + return $val; +} + +/** + * Adds the href HTML tags around any URL in the $string + */ +function url2html($string) { + // + $return_string = preg_replace('/(\w+:\/\/)(\S+)/', ' \\1\\2', $string); + return $return_string; +} +// End customization by Julian + +/** + * tries to determine whether the Host machine is a Windows machine + */ +function is_windows() { + static $is_windows = null; + if (!isset($is_windows)) { + $is_windows = strtoupper(substr(PHP_OS, 0, 3)) == 'WIN'; + } + return $is_windows; +} + +/** + * equivalent for windows filesystem for PHP's is_writable() + * @param string file Full path to the file/dir + * @return bool true if writable + */ +function is_writable_windows($file) { + if($file{strlen($file)-1}=='/') { + return is_writable_windows($file.uniqid(mt_rand()).'.tmp'); + } + + // the assumption here is that Windows has an inherited permissions scheme + // any file that is a descendant of an unwritable directory will inherit + // that property and will trigger a failure below. + if(is_dir($file)) { + return true; + } + + $file = str_replace("/", '\\', $file); + + if(file_exists($file)) { + if (!($f = @sugar_fopen($file, 'r+'))) + return false; + fclose($f); + return true; + } + + if(!($f = @sugar_fopen($file, 'w'))) + return false; + fclose($f); + unlink($file); + return true; +} + + +/** + * best guesses Timezone based on webserver's TZ settings + */ +function lookupTimezone($userOffset = 0) +{ + return TimeDate::guessTimezone($userOffset); +} + +function convert_module_to_singular($module_array){ + global $beanList; + + foreach($module_array as $key => $value){ + if(!empty($beanList[$value])) $module_array[$key] = $beanList[$value]; + + if($value=="Cases") { + $module_array[$key] = "Case"; + } + if($key=="projecttask"){ + $module_array['ProjectTask'] = "Project Task"; + unset($module_array[$key]); + } + } + + return $module_array; + + //end function convert_module_to_singular +} + +/* + * Given the bean_name which may be plural or singular return the singular + * bean_name. This is important when you need to include files. + */ +function get_singular_bean_name($bean_name){ + global $beanFiles, $beanList; + if(array_key_exists($bean_name, $beanList)){ + return $beanList[$bean_name]; + } + else{ + return $bean_name; + } +} + +function get_label($label_tag, $temp_module_strings){ + global $app_strings; + if(!empty($temp_module_strings[$label_tag])){ + + $label_name = $temp_module_strings[$label_tag]; + } else { + if(!empty($app_strings[$label_tag])){ + $label_name = $app_strings[$label_tag]; + } else { + $label_name = $label_tag; + } + } + return $label_name; + + //end function get_label +} + + +function search_filter_rel_info(& $focus, $tar_rel_module, $relationship_name){ + + $rel_list = array(); + + foreach($focus->relationship_fields as $rel_key => $rel_value){ + if($rel_value == $relationship_name){ + $temp_bean = get_module_info($tar_rel_module); + // echo $focus->$rel_key; + $temp_bean->retrieve($focus->$rel_key); + if($temp_bean->id!=""){ + + $rel_list[] = $temp_bean; + return $rel_list; + } + } + } + + foreach($focus->field_defs as $field_name => $field_def){ + //Check if the relationship_name matches a "relate" field + if(!empty($field_def['type']) && $field_def['type'] == 'relate' + && !empty($field_def['id_name']) && !empty($focus->field_defs[$field_def['id_name']]) + && !empty($focus->field_defs[$field_def['id_name']]['relationship']) + && $focus->field_defs[$field_def['id_name']]['relationship'] == $relationship_name) + { + $temp_bean = get_module_info($tar_rel_module); + // echo $focus->$field_def['id_name']; + $temp_bean->retrieve($focus->$field_def['id_name']); + if($temp_bean->id!=""){ + + $rel_list[] = $temp_bean; + return $rel_list; + } + //Check if the relationship_name matches a "link" in a relate field + } else if(!empty($rel_value['link']) && !empty($rel_value['id_name']) && $rel_value['link'] == $relationship_name){ + $temp_bean = get_module_info($tar_rel_module); + // echo $focus->$rel_value['id_name']; + $temp_bean->retrieve($focus->$rel_value['id_name']); + if($temp_bean->id!=""){ + + $rel_list[] = $temp_bean; + return $rel_list; + } + } + } + + // special case for unlisted parent-type relationships + if($focus->parent_type == $tar_rel_module && !empty($focus->parent_id)) { + $temp_bean = get_module_info($tar_rel_module); + $temp_bean->retrieve($focus->parent_id); + if($temp_bean->id!=""){ + $rel_list[] = $temp_bean; + return $rel_list; + } + } + + return $rel_list; + + //end function search_filter_rel_info +} + +function get_module_info($module_name){ + global $beanList; + global $dictionary; + + //Get dictionary and focus data for module + $vardef_name = $beanList[$module_name]; + + if($vardef_name=="aCase"){ + $class_name = "Case"; + } else { + $class_name = $vardef_name; + } + + if(!file_exists('modules/'. $module_name . '/'.$class_name.'.php')){ + return; + } + + include_once('modules/'. $module_name . '/'.$class_name.'.php'); + + $module_bean = new $vardef_name(); + return $module_bean; + //end function get_module_table +} + +/** + * In order to have one place to obtain the proper object name. aCase for example causes issues throughout the application. + * + * @param string $moduleName + */ +function get_valid_bean_name($module_name){ + global $beanList; + + $vardef_name = $beanList[$module_name]; + if($vardef_name=="aCase"){ + $bean_name = "Case"; + } else { + $bean_name = $vardef_name; + } + return $bean_name; +} + + + +function checkAuthUserStatus(){ + + //authUserStatus(); +} + + +/** + * This function returns an array of phpinfo() results that can be parsed and + * used to figure out what version we run, what modules are compiled in, etc. + * @param $level int info level constant (1,2,4,8...64); + * @return $returnInfo array array of info about the PHP environment + * @author original by "code at adspeed dot com" Fron php.net + * @author customized for Sugar by Chris N. + */ +function getPhpInfo($level=-1) { + /** Name (constant) Value Description + INFO_GENERAL 1 The configuration line, php.ini location, build date, Web Server, System and more. + INFO_CREDITS 2 PHP Credits. See also phpcredits(). + INFO_CONFIGURATION 4 Current Local and Master values for PHP directives. See also ini_get(). + INFO_MODULES 8 Loaded modules and their respective settings. See also get_loaded_extensions(). + INFO_ENVIRONMENT 16 Environment Variable information that's also available in $_ENV. + INFO_VARIABLES 32 Shows all predefined variables from EGPCS (Environment, GET, POST, Cookie, Server). + INFO_LICENSE 64 PHP License information. See also the license FAQ. + INFO_ALL -1 Shows all of the above. This is the default value. + */ + ob_start(); + phpinfo($level); + $phpinfo = ob_get_contents(); + ob_end_clean(); + + $phpinfo = strip_tags($phpinfo,'

            '); + $phpinfo = preg_replace('/]*>([^<]+)<\/th>/',"\\1",$phpinfo); + $phpinfo = preg_replace('/]*>([^<]+)<\/td>/',"\\1",$phpinfo); + $parsedInfo = preg_split('/([^<]+<\/h.>)/', $phpinfo, -1, PREG_SPLIT_DELIM_CAPTURE); + $match = ''; + $version = ''; + $returnInfo = array(); + + if(preg_match('/

            PHP Version ([^<]+)<\/h1>/', $phpinfo, $version)) { + $returnInfo['PHP Version'] = $version[1]; + } + + + for ($i=1; $i([^<]+)<\/h.>/', $parsedInfo[$i], $match)) { + $vName = trim($match[1]); + $parsedInfo2 = explode("\n",$parsedInfo[$i+1]); + + foreach ($parsedInfo2 AS $vOne) { + $vPat = '([^<]+)<\/info>'; + $vPat3 = "/$vPat\s*$vPat\s*$vPat/"; + $vPat2 = "/$vPat\s*$vPat/"; + + if (preg_match($vPat3,$vOne,$match)) { // 3cols + $returnInfo[$vName][trim($match[1])] = array(trim($match[2]),trim($match[3])); + } elseif (preg_match($vPat2,$vOne,$match)) { // 2cols + $returnInfo[$vName][trim($match[1])] = trim($match[2]); + } + } + } elseif(true) { + + } + } + + return $returnInfo; +} + +/** + * This function will take a string that has tokens like {0}, {1} and will replace + * those tokens with the args provided + * @param $format string to format + * @param $args args to replace + * @return $result a formatted string + */ +function string_format($format, $args){ + $result = $format; + for($i = 0; $i < count($args); $i++){ + $result = str_replace('{'.$i.'}', $args[$i], $result); + } + return $result; +} + +/** + * Generate a string for displaying a unique identifier that is composed + * of a system_id and number. This is use to allow us to generate quote + * numbers using a DB auto-increment key from offline clients and still + * have the number be unique (since it is modified by the system_id. + * + * @param $num of bean + * @param $system_id from system + * @return $result a formatted string + */ +function format_number_display($num, $system_id){ + global $sugar_config; + if(isset($num) && !empty($num)){ + $num=unformat_number($num); + if(isset($system_id) && $system_id == 1){ + return sprintf("%d", $num); + } + else{ + return sprintf("%d-%d", $num, $system_id); + } + } +} +function checkLoginUserStatus(){ +} + +/** + * This function will take a number and system_id and format + * @param $url URL containing host to append port + * @param $port the port number - if '' is passed, no change to url + * @return $resulturl the new URL with the port appended to the host + */ +function appendPortToHost($url, $port) +{ + $resulturl = $url; + + // if no port, don't change the url + if($port != '') + { + $split = explode("/", $url); + //check if it starts with http, in case they didn't include that in url + if(str_begin($url, 'http')) + { + //third index ($split[2]) will be the host + $split[2] .= ":".$port; + } + else // otherwise assumed to start with host name + { + //first index ($split[0]) will be the host + $split[0] .= ":".$port; + } + + $resulturl = implode("/", $split); + } + + return $resulturl; +} + +/** + * Singleton to return JSON object + * @return JSON object + */ +function getJSONobj() { + static $json = null; + if(!isset($json)) { + require_once('include/JSON.php'); + $json = new JSON(JSON_LOOSE_TYPE); + } + return $json; +} + +require_once('include/utils/db_utils.php'); +//check to see if custom utils exists +if(file_exists('custom/include/custom_utils.php')){ + include_once('custom/include/custom_utils.php'); +} + + +/** + * Set default php.ini settings for entry points + */ +function setPhpIniSettings() { + // zlib module + // Bug 37579 - Comment out force enabling zlib.output_compression, since it can cause problems on certain hosts + /* + if(function_exists('gzclose') && headers_sent() == false) { + ini_set('zlib.output_compression', 1); + } + */ + // mbstring module + //nsingh: breaks zip/unzip functionality. Commenting out 4/23/08 + + /*if(function_exists('mb_strlen')) { + ini_set('mbstring.func_overload', 7); + ini_set('mbstring.internal_encoding', 'UTF-8'); + }*/ + + + // http://us3.php.net/manual/en/ref.pcre.php#ini.pcre.backtrack-limit + // starting with 5.2.0, backtrack_limit breaks JSON decoding + $backtrack_limit = ini_get('pcre.backtrack_limit'); + if(!empty($backtrack_limit)) { + ini_set('pcre.backtrack_limit', '-1'); + } + + // mssql only + if(ini_get("mssql.charset")) { + ini_set('mssql.charset', "UTF-8"); + } +} + +/** + * like array_merge() but will handle array elements that are themselves arrays; + * PHP's version just overwrites the element with the new one. + * + * @internal Note that this function deviates from the internal array_merge() + * functions in that it does does not treat numeric keys differently + * than string keys. Additionally, it deviates from + * array_merge_recursive() by not creating an array when like values + * found. + * + * @param array gimp the array whose values will be overloaded + * @param array dom the array whose values will pwn the gimp's + * @return array beaten gimp + */ +function sugarArrayMerge($gimp, $dom) { + if(is_array($gimp) && is_array($dom)) { + foreach($dom as $domKey => $domVal) { + if(array_key_exists($domKey, $gimp)) { + if(is_array($domVal)) { + $tempArr = array(); + foreach ( $domVal as $domArrKey => $domArrVal ) + $tempArr[$domArrKey] = $domArrVal; + foreach ( $gimp[$domKey] as $gimpArrKey => $gimpArrVal ) + if ( !array_key_exists($gimpArrKey, $tempArr) ) + $tempArr[$gimpArrKey] = $gimpArrVal; + $gimp[$domKey] = $tempArr; + } else { + $gimp[$domKey] = $domVal; + } + } else { + $gimp[$domKey] = $domVal; + } + } + } + // if the passed value for gimp isn't an array, then return the $dom + elseif(is_array($dom)) + return $dom; + + return $gimp; +} + +/** + * Similiar to sugarArrayMerge except arrays of N depth are merged. + * + * @param array gimp the array whose values will be overloaded + * @param array dom the array whose values will pwn the gimp's + * @return array beaten gimp + */ +function sugarArrayMergeRecursive($gimp, $dom) { + if(is_array($gimp) && is_array($dom)) { + foreach($dom as $domKey => $domVal) { + if(array_key_exists($domKey, $gimp)) { + if(is_array($domVal) && is_array($gimp[$domKey])) { + $gimp[$domKey] = sugarArrayMergeRecursive($gimp[$domKey], $domVal); + } else { + $gimp[$domKey] = $domVal; + } + } else { + $gimp[$domKey] = $domVal; + } + } + } + // if the passed value for gimp isn't an array, then return the $dom + elseif(is_array($dom)) + return $dom; + + return $gimp; +} + +/** + * finds the correctly working versions of PHP-JSON + * @return bool True if NOT found or WRONG version + */ +function returnPhpJsonStatus() { + if(function_exists('json_encode')) { + $phpInfo = getPhpInfo(8); + return version_compare($phpInfo['json']['json version'], '1.1.1', '<'); + } + return true; // not found +} + + +/** + * getTrackerSubstring + * + * Returns a [number]-char or less string for the Tracker to display in the header + * based on the tracker_max_display_length setting in config.php. If not set, + * or invalid length, then defaults to 15 for COM editions, 30 for others. + * + * @param string name field for a given Object + * @return string [number]-char formatted string if length of string exceeds the max allowed + */ +function getTrackerSubstring($name) { + static $max_tracker_item_length; + + //Trim the name + $name = html_entity_decode($name, ENT_QUOTES, 'UTF-8'); + $strlen = function_exists('mb_strlen') ? mb_strlen($name) : strlen($name); + + global $sugar_config; + + if(!isset($max_tracker_item_length)) { + if(isset($sugar_config['tracker_max_display_length'])) { + $max_tracker_item_length = (is_int($sugar_config['tracker_max_display_length']) && $sugar_config['tracker_max_display_length'] > 0 && $sugar_config['tracker_max_display_length'] < 50) ? $sugar_config['tracker_max_display_length'] : 15; + } else { + $max_tracker_item_length = 15; + } + } + + if($strlen > $max_tracker_item_length) { + $chopped = function_exists('mb_substr') ? mb_substr($name, 0, $max_tracker_item_length, "UTF-8") : substr($name, 0, $max_tracker_item_length, "UTF-8"); + } else { + $chopped = $name; + } + + return $chopped; +} +function generate_search_where ($field_list=array(),$values=array(),&$bean,$add_custom_fields=false,$module='') { + $where_clauses= array(); + $like_char='%'; + $table_name=$bean->object_name; + foreach ($field_list[$module] as $field=>$parms) { + if(isset($values[$field]) && $values[$field] != "") { + $operator='like'; + if (!empty($parms['operator'])) { + $operator=$parms['operator']; + } + if (is_array($values[$field])) { + $operator='in'; + $field_value=''; + foreach ($values[$field] as $key => $val) { + if ($val != ' ' and $val != '') { + if (!empty($field_value)) { + $field_value.=','; + } + $field_value .= "'".$GLOBALS['db']->quote($val)."'"; + } + } + } else { + $field_value=$GLOBALS['db']->quote($values[$field]); + } + //set db_fields array. + if (!isset($parms['db_field']) ) { + $parms['db_field'] = array($field); + } + if (isset($parms['my_items']) and $parms['my_items'] == true) { + global $current_user; + $field_value = $GLOBALS['db']->quote($current_user->id); + $operator='='; + } + + $where=''; + $itr=0; + if ($field_value != '') { + + foreach ($parms['db_field'] as $db_field) { + if (strstr($db_field,'.')===false) { + $db_field=$bean->table_name.".".$db_field; + } + if ($GLOBALS['db']->dbType=='oci8' && isset($parms['query_type']) && $parms['query_type']=='case_insensitive') { + $db_field='upper('.$db_field.")"; + $field_value=strtoupper($field_value); + } + + $itr++; + if (!empty($where)) { + $where .= " OR "; + } + switch (strtolower($operator)) { + case 'like' : + $where .= $db_field . " like '".$field_value.$like_char."'"; + break; + case 'in': + $where .= $db_field . " in (".$field_value.')'; + break; + case '=': + $where .= $db_field . " = '".$field_value ."'"; + break; + } + } + } + if (!empty($where)) { + if ($itr>1) { + array_push($where_clauses, '( '.$where.' )'); + } else { + array_push($where_clauses, $where); + } + } + } + } + if ($add_custom_fields) { + require_once('modules/DynamicFields/DynamicField.php'); + $bean->setupCustomFields($module); + $bean->custom_fields->setWhereClauses($where_clauses); + } + return $where_clauses; +} + +function add_quotes($str) { + return "'{$str}'"; +} + +/** + * This function will rebuild the config file + * @param $sugar_config + * @param $sugar_version + * @return bool true if successful + */ +function rebuildConfigFile($sugar_config, $sugar_version) { + // add defaults to missing values of in-memory sugar_config + $sugar_config = sugarArrayMerge(get_sugar_config_defaults(), $sugar_config ); + // need to override version with default no matter what + $sugar_config['sugar_version'] = $sugar_version; + + ksort( $sugar_config ); + + if( write_array_to_file( "sugar_config", $sugar_config, "config.php" ) ){ + return true; + } + else { + return false; + } +} + +/** + * getJavascriptSiteURL + * This function returns a URL for the client javascript calls to access + * the site. It uses $_SERVER['HTTP_REFERER'] in the event that Proxy servers + * are used to access the site. Thus, the hostname in the URL returned may + * not always match that of $sugar_config['site_url']. Basically, the + * assumption is that however the user accessed the website is how they + * will continue to with subsequent javascript requests. If the variable + * $_SERVER['HTTP_REFERER'] is not found then we default to old algorithm. + * @return $site_url The url used to refer to the website + */ +function getJavascriptSiteURL() { + global $sugar_config; + if(!empty($_SERVER['HTTP_REFERER'])) { + $url = parse_url($_SERVER['HTTP_REFERER']); + $replacement_url = $url['scheme']."://".$url['host']; + if(!empty($url['port'])) + $replacement_url .= ':'.$url['port']; + $site_url = preg_replace('/^http[s]?\:\/\/[^\/]+/',$replacement_url,$sugar_config['site_url']); + } else { + $site_url = preg_replace('/^http(s)?\:\/\/[^\/]+/',"http$1://".$_SERVER['HTTP_HOST'],$sugar_config['site_url']); + if(!empty($_SERVER['SERVER_PORT']) &&$_SERVER['SERVER_PORT'] == '443') { + $site_url = preg_replace('/^http\:/','https:',$site_url); + } + } + $GLOBALS['log']->debug("getJavascriptSiteURL(), site_url=". $site_url); + return $site_url; +} + +// works nicely with array_map() -- can be used to wrap single quotes around each element in an array +function add_squotes($str) { + return "'" . $str . "'"; +} + + +// recursive function to count the number of levels within an array +function array_depth($array, $depth_count=-1, $depth_array=array()){ + $depth_count++; + if (is_array($array)){ + foreach ($array as $key => $value){ + $depth_array[] = array_depth($value, $depth_count); + } + } + else{ + return $depth_count; + } + foreach ($depth_array as $value){ + $depth_count = $value > $depth_count ? $value : $depth_count; + } + return $depth_count; +} + +/** + * Creates a new Group User + * @param string $name Name of Group User + * @return string GUID of new Group User + */ +function createGroupUser($name) { + + + $group = new User(); + $group->user_name = $name; + $group->last_name = $name; + $group->is_group = 1; + $group->deleted = 0; + $group->status = 'Active'; // cn: bug 6711 + $group->setPreference('timezone', TimeDate::userTimezone()); + $group->save(); + + return $group->id; +} + +/* + * Helper function to locate an icon file given only a name + * Searches through the various paths for the file + * @param string iconFileName The filename of the icon + * @return string Relative pathname of the located icon, or '' if not found + */ + +function _getIcon($iconFileName) +{ + $iconPath = SugarThemeRegistry::current()->getImageURL("icon_{$iconFileName}.gif"); + //First try un-ucfirst-ing the icon name + if ( empty($iconPath) ) + $iconPath = SugarThemeRegistry::current()->getImageURL( + "icon_" . strtolower(substr($iconFileName,0,1)).substr($iconFileName,1) . ".gif"); + //Next try removing the icon prefix + if ( empty($iconPath) ) + $iconPath = SugarThemeRegistry::current()->getImageURL("{$iconFileName}.gif"); + + return $iconPath; +} +/** + * Function to grab the correct icon image for Studio + * @param string $iconFileName Name of the icon file + * @param string $altfilename Name of a fallback icon file (displayed if the imagefilename doesn't exist) + * @param string $width Width of image + * @param string $height Height of image + * @param string $align Alignment of image + * @return string $string tag with corresponding image + */ + +function getStudioIcon($iconFileName='', $altFileName='', $width='48', $height='48', $align='baseline' ) +{ + global $app_strings, $theme; + + $iconPath = _getIcon($iconFileName); + if(empty($iconPath)){ + $iconPath = _getIcon($altFileName); + if (empty($iconPath)) + { + return $app_strings['LBL_NO_IMAGE']; + } + } + return ''; +} + +/** + * Function to grab the correct icon image for Dashlets Dialog + * @param string $filename Location of the icon file + * @param string $module Name of the module to fall back onto if file does not exist + * @param string $width Width of image + * @param string $height Height of image + * @param string $align Alignment of image + * @return string $string tag with corresponding image + */ + +function get_dashlets_dialog_icon($module='', $width='32', $height='32', $align='absmiddle'){ + global $app_strings, $theme; + $icon_path = _getIcon($module . "_32"); + if (empty($icon_path)) + { + $icon_path = _getIcon($module); + } + if(empty($icon_path)){ + $icon = $app_strings['LBL_NO_IMAGE']; + } + else{ + $icon = ''; + } + return $icon; +} + +// works nicely to change UTF8 strings that are html entities - good for PDF conversions +function html_entity_decode_utf8($string) +{ + static $trans_tbl; + // replace numeric entities + //php will have issues with numbers with leading zeros, so do not include them in what we send to code2utf. + $string = preg_replace('~�*([0-9a-f]+);~ei', 'code2utf(hexdec("\\1"))', $string); + $string = preg_replace('~�*([0-9]+);~e', 'code2utf(\\1)', $string); + // replace literal entities + if (!isset($trans_tbl)) + { + $trans_tbl = array(); + foreach (get_html_translation_table(HTML_ENTITIES) as $val=>$key) + $trans_tbl[$key] = utf8_encode($val); + } + return strtr($string, $trans_tbl); +} + +// Returns the utf string corresponding to the unicode value +function code2utf($num) +{ + if ($num < 128) return chr($num); + if ($num < 2048) return chr(($num >> 6) + 192) . chr(($num & 63) + 128); + if ($num < 65536) return chr(($num >> 12) + 224) . chr((($num >> 6) & 63) + 128) . chr(($num & 63) + 128); + if ($num < 2097152) return chr(($num >> 18) + 240) . chr((($num >> 12) & 63) + 128) . chr((($num >> 6) & 63) + 128) . chr(($num & 63) + 128); + return ''; +} + +function str_split_php4($string, $length = 1) { + $string_length = strlen($string); + $return = array(); + $cursor = 0; + if ($length > $string_length) { + // use the string_length as the string is shorter than the length + $length = $string_length; + } + for ($cursor = 0; $cursor < $string_length; $cursor = $cursor + $length) { + $return[] = substr($string, $cursor, $length); + } + return $return; +} + +if (version_compare(phpversion(), '5.0.0', '<')) { + function str_split($string, $length = 1) { + return str_split_php4($string, $length); + } +} + +/* + * Invoked when connected to mssql. checks if we have freetds version of mssql library. + * the response is put into a global variable. + */ +function is_freetds() { + + $ret=false; + if (isset($GLOBALS['mssql_library_version'])) { + if ($GLOBALS['mssql_library_version']=='freetds') { + $ret=true; + } else { + $ret=false; + } + } else { + ob_start(); + phpinfo(); + $info=ob_get_contents(); + ob_end_clean(); + + if (strpos($info,'FreeTDS') !== false) { + $GLOBALS['mssql_library_version']='freetds'; + $ret=true; + } else { + $GLOBALS['mssql_library_version']='regular'; + $ret=false; + } + } + return $ret; +} + +/* + * stripos - Find position of first occurrence of a case-insensitive string + * + * The function is being defined for systems with PHP version < 5. + * + */ +if (!function_exists("stripos")){ + function stripos($haystack,$needle,$offset=0){ + return strpos(strtolower($haystack),strtolower($needle),$offset); + } +} + +/** + * Chart dashlet helper function that returns the correct CSS file, dependent on the current theme. + * + * @todo this won't work completely right until we impliment css compression and combination + * for now, we'll just include the last css file found. + * + * @return chart.css file to use + */ +function chartStyle() +{ + return SugarThemeRegistry::current()->getCSSURL('chart.css'); +} + +/** + * Chart dashlet helper functions that returns the correct XML color file for charts, + * dependent on the current theme. + * + * @return sugarColors.xml to use + */ +function chartColors() +{ + if (SugarThemeRegistry::current()->getCSSURL('sugarColors.xml')=='') + return SugarThemeRegistry::current()->getImageURL('sugarColors.xml'); + return SugarThemeRegistry::current()->getCSSURL('sugarColors.xml'); +} +/* End Chart Dashlet helper functions */ + +/** + * This function is designed to set up the php enviroment + * for AJAX requests. + */ + +function ajaxInit() { + ini_set('display_errors', 'false'); +} + +/** + * Returns an absolute path from the given path, determining if it is relative or absolute + * + * @param string $path + * @return string + */ +function getAbsolutePath( + $path, + $currentServer = false + ) +{ + $path = trim($path); + + // try to match absolute paths like \\server\share, /directory or c:\ + if ( ( substr($path,0,2) == '\\\\' ) + || ( $path[0] == '/' ) + || preg_match('/^[A-z]:/i',$path) + || $currentServer ) + return $path; + + return getcwd().'/'.$path; +} + +/** + * Returns the bean object of the given module + * + * @deprecated use SugarModule::loadBean() instead + * @param string $module + * @return object + */ +function loadBean( + $module + ) +{ + return SugarModule::get($module)->loadBean(); +} + + +/** + * Returns true if the application is being accessed on a touch screen interface ( like an iPad ) + */ +function isTouchScreen() +{ + $ua = empty($_SERVER['HTTP_USER_AGENT']) ? "undefined" : strtolower($_SERVER['HTTP_USER_AGENT']); + + // first check if we have forced use of the touch enhanced interface + if ( isset($_COOKIE['touchscreen']) && $_COOKIE['touchscreen'] == '1' ) { + return true; + } + + // next check if we should use the touch interface with our device + if ( strpos($ua, 'ipad') !== false ) { + return true; + } + + return false; +} + +/** + * Returns the shortcut keys to access the shortcut links. Shortcut + * keys vary depending on browser versions and operating systems. + * @return String value of the shortcut keys + */ +function get_alt_hot_key() { + $ua = ''; + if ( isset($_SERVER['HTTP_USER_AGENT']) ) + $ua = strtolower($_SERVER['HTTP_USER_AGENT']); + $isMac = strpos($ua, 'mac') !== false; + $isLinux = strpos($ua, 'linux') !== false; + + if(!$isMac && !$isLinux && strpos($ua, 'mozilla') !== false) { + if(preg_match('/firefox\/(\d)?\./', $ua, $matches)) { + return $matches[1] < 2 ? 'Alt+' : 'Alt+Shift+'; + } + } + return $isMac ? 'Ctrl+' : 'Alt+'; +} + +function can_start_session(){ + if(!empty($_GET['PHPSESSID'])) { + return true; + } + $session_id = session_id(); + return empty($session_id) ? true : false; +} + +function load_link_class($properties){ + $class = 'Link'; + if(!empty($properties['link_class']) && !empty($properties['link_file'])){ + require_once($properties['link_file']); + $class = $properties['link_class']; + } + return $class; +} + + +function inDeveloperMode() +{ + return isset($GLOBALS['sugar_config']['developerMode']) && $GLOBALS['sugar_config']['developerMode']; +} + +/** + * Filter the protocol list for inbound email accounts. + * + * @param array $protocol + */ +function filterInboundEmailPopSelection($protocol) +{ + if ( !isset($GLOBALS['sugar_config']['allow_pop_inbound']) || ! $GLOBALS['sugar_config']['allow_pop_inbound'] ) + { + if( isset($protocol['pop3']) ) + unset($protocol['pop3']); + } + else + $protocol['pop3'] = 'POP3'; + + return $protocol; +} + +/** + * The function is used because currently we are not supporting mbstring.func_overload + * For some user using mssql without FreeTDS, they may store multibyte charaters in varchar using latin_general collation. It cannot store so many mutilbyte characters, so we need to use strlen. + * The varchar in MySQL, Orcale, and nvarchar in FreeTDS, we can store $length mutilbyte charaters in it. we need mb_substr to keep more info. +* @returns the substred strings. + */ +function sugar_substr($string, $length, $charset='UTF-8') { + if($GLOBALS['db']->dbType == 'mssql' && empty($GLOBALS['db']->isFreeTDS)) { + if(strlen($string) > $length) { + $string = trim(substr(trim($string),0,$length)); + } + } + else { + if(mb_strlen($string,$charset) > $length) { + $string = trim(mb_substr(trim($string),0,$length,$charset)); + } + } + return $string; +} + +/** + * The function is used because on FastCGI enviroment, the ucfirst(Chinese Characters) will produce bad charcters. + * This will work even without setting the mbstring.*encoding + */ +function sugar_ucfirst($string, $charset='UTF-8') { + return mb_strtoupper(mb_substr($string, 0, 1, $charset), $charset) . mb_substr($string, 1, mb_strlen($string), $charset); +} + + +/** + * + */ +function unencodeMultienum($string) { + if (is_array($string)) + { + return $string; + } + if (substr($string, 0 ,1) == "^" && substr($string, -1) == "^") { + $string = substr(substr($string, 1), 0, strlen($string) -2); + } + + return explode('^,^', $string); +} + +function encodeMultienumValue($arr) { + if (!is_array($arr)) + return $arr; + + if (empty($arr)) + return ""; + + $string = "^" . implode('^,^', $arr) . "^"; + + return $string; +} + +/** + * create_export_query is used for export and massupdate + * We haven't handle the these fields: $field['type'] == 'relate' && isset($field['link'] + * This function will correct the where clause and output necessary join condition for them + * @param $module: the module name + * @param $searchFields: searchFields which is got after $searchForm->populateFromArray() + * @param $where: where clauses + * @return $ret_array['where']: corrected where clause + * @return $ret_array['join']: extra join condition + */ +function create_export_query_relate_link_patch($module, $searchFields, $where){ + if(file_exists('modules/'.$module.'/SearchForm.html')){ + $ret_array['where'] = $where; + return $ret_array; + } + $seed = loadBean($module); + foreach($seed->field_defs as $name=>$field) + { + + if( $field['type'] == 'relate' && isset($field['link']) && !empty($searchFields[$name]['value']) ){ + $seed->load_relationship($field['link']); + $params = array(); + if(empty($join_type)) + { + $params['join_type'] = ' LEFT JOIN '; + } + else + { + $params['join_type'] = $join_type; + } + if(isset($data['join_name'])) + { + $params['join_table_alias'] = $field['join_name']; + } + else + { + $params['join_table_alias'] = 'join_'.$field['name']; + + } + if(isset($data['join_link_name'])) + { + $params['join_table_link_alias'] = $field['join_link_name']; + } + else + { + $params['join_table_link_alias'] = 'join_link_'.$field['name']; + } + $join = $seed->$field['link']->getJoin($params, true); + $join_table_alias = 'join_'.$field['name']; + if(isset($field['db_concat_fields'])){ + $db_field = db_concat($join_table_alias, $field['db_concat_fields']); + $where = preg_replace('/'.$field['name'].'/', $db_field, $where); + }else{ + $where = preg_replace('/(^|[\s(])' . $field['name'] . '/', '${1}' . $join_table_alias . '.'.$field['rname'], $where); + } + } + } + $ret_array = array('where'=>$where, 'join'=>$join['join']); + return $ret_array; +} + +/** + * We need to clear all the js cache files, including the js language files in serval places in MB. So I extract them into a util function here. + * @Depends on QuickRepairAndRebuild.php + * @Relate bug 30642 ,23177 + */ +function clearAllJsAndJsLangFilesWithoutOutput(){ + global $current_language , $mod_strings; + $MBmodStrings = $mod_strings; + $mod_strings = return_module_language ( $current_language, 'Administration' ) ; + include_once ('modules/Administration/QuickRepairAndRebuild.php') ; + $repair = new RepairAndClear(); + $repair->module_list = array(); + $repair->show_output = false; + $repair->clearJsLangFiles(); + $repair->clearJsFiles(); + $mod_strings = $MBmodStrings; +} + +/** + * This function will allow you to get a variable value from query string + */ +function getVariableFromQueryString($variable, $string){ + $matches = array(); + $number = preg_match("/{$variable}=([a-zA-Z0-9_-]+)[&]?/", $string, $matches); + if($number){ + return $matches[1]; + } + else{ + return false; + } +} + +/** + * should_hide_iframes + * This is a helper method to determine whether or not to show iframes (My Sites) related + * information in the application. + * + * @return boolean flag indicating whether or not iframes module should be hidden + */ +function should_hide_iframes() { + //Remove the MySites module + if(file_exists('modules/iFrames/iFrame.php')) { + if(!class_exists("iFrame")) { + require_once('modules/iFrames/iFrame.php'); + } + return false; + } + return true; +} + +/** + * Given a version such as 5.5.0RC1 return RC. If we have a version such as: 5.5 then return GA + * + * @param string $version + * @return string RC, BETA, GA + */ +function getVersionStatus($version){ + if(preg_match('/^[\d\.]+?([a-zA-Z]+?)[\d]*?$/si', $version, $matches)) { + return strtoupper($matches[1]); + }else{ + return 'GA'; + } +} + +/** + * Return the numeric portion of a version. For example if passed 5.5.0RC1 then return 5.5. If given + * 5.5.1RC1 then return 5.5.1 + * + * @param string $version + * @return version + */ +function getMajorMinorVersion($version){ + if(preg_match('/^([\d\.]+).*$/si', $version, $matches2)){ + $version = $matches2[1]; + $arr = explode('.', $version); + if(count($arr) > 2){ + if($arr[2] == '0'){ + $version = substr($version, 0, 3); + } + } + } + return $version; +} + +/** + * Return string composed of seconds & microseconds of current time, without dots + * @return string + */ +function sugar_microtime() +{ + $now = explode(' ', microtime()); + $unique_id = $now[1].str_replace('.', '', $now[0]); + return $unique_id; +} + +/** + * Extract urls from a piece of text + * @param $string + * @return array of urls found in $string + */ +function getUrls($string) +{ + $lines = explode("
            ", trim($string)); + $urls = array(); + foreach($lines as $line){ + $regex = '/http?\:\/\/[^\" ]+/i'; + preg_match_all($regex, $line, $matches); + foreach($matches[0] as $match){ + $urls[] = $match; + } + } + return $urls; +} +?> diff --git a/include/utils/LogicHook.php b/include/utils/LogicHook.php new file mode 100644 index 00000000..99f3711b --- /dev/null +++ b/include/utils/LogicHook.php @@ -0,0 +1,168 @@ +bean =& $bean; + return $this; + } + + /** + * Provide a means for developers to create upgrade safe business logic hooks. + * If the bean is null, then we assume this call was not made from a SugarBean Object and + * therefore we do not pass it to the method call. + * + * @param string $module_dir + * @param string $event + * @param array $arguments + * @param SugarBean $bean + */ + function call_custom_logic($module_dir, $event, $arguments = null){ + // declare the hook array variable, it will be defined in the included file. + $hook_array = null; + if(isset($GLOBALS['log'])){ + $GLOBALS['log']->debug("Hook called: $module_dir::$event"); + } + if(!empty($module_dir)){ + // This will load an array of the hooks to process + if(file_exists("custom/modules/$module_dir/logic_hooks.php")){ + if(isset($GLOBALS['log'])){ + $GLOBALS['log']->debug('Including module specific hook file for '.$module_dir); + } + include("custom/modules/$module_dir/logic_hooks.php"); + $this->process_hooks($hook_array, $event, $arguments); + $hook_array = null; + } + } + // Now load the generic array if it exists. + if(file_exists('custom/modules/logic_hooks.php')){ + if(isset($GLOBALS['log'])){ + $GLOBALS['log']->debug('Including generic hook file'); + } + include('custom/modules/logic_hooks.php'); + $this->process_hooks($hook_array, $event, $arguments); + } + } + + /** + * This is called from call_custom_logic and actually performs the action as defined in the + * logic hook. If the bean is null, then we assume this call was not made from a SugarBean Object and + * therefore we do not pass it to the method call. + * + * @param array $hook_array + * @param string $event + * @param array $arguments + * @param SugarBean $bean + */ + function process_hooks($hook_array, $event, $arguments){ + // Now iterate through the array for the appropriate hook + if(!empty($hook_array[$event])){ + foreach($hook_array[$event] as $hook_details){ + if(!file_exists($hook_details[2])){ + if(isset($GLOBALS['log'])){ + $GLOBALS['log']->error('Unable to load custom logic file: '.$hook_details[2]); + } + continue; + } + include_once($hook_details[2]); + $hook_class = $hook_details[3]; + $hook_function = $hook_details[4]; + + // Make a static call to the function of the specified class + //TODO Make a factory for these classes. Cache instances accross uses + if($hook_class == $hook_function){ + if(isset($GLOBALS['log'])){ + $GLOBALS['log']->debug('Creating new instance of hook class '.$hook_class.' with parameters'); + } + if(!is_null($this->bean)) + $class = new $hook_class($this->bean, $event, $arguments); + else + $class = new $hook_class($event, $arguments); + }else{ + if(isset($GLOBALS['log'])){ + $GLOBALS['log']->debug('Creating new instance of hook class '.$hook_class.' without parameters'); + } + $class = new $hook_class(); + if(!is_null($this->bean)) + $class->$hook_function($this->bean, $event, $arguments); + else + $class->$hook_function($event, $arguments); + } + } + } + } +} +?> \ No newline at end of file diff --git a/include/utils/activity_utils.php b/include/utils/activity_utils.php new file mode 100644 index 00000000..2267346b --- /dev/null +++ b/include/utils/activity_utils.php @@ -0,0 +1,86 @@ +object_name).'_id'; + + $select = "SELECT {$bean->table_name}.* from {$bean->rel_users_table},{$bean->table_name} "; + + $auto_where = ' WHERE '; + if(!empty($where)) { + $auto_where .= $where. ' AND '; + } + + $auto_where .= " {$bean->rel_users_table}.{$bean_id_name}={$bean->table_name}.id AND {$bean->rel_users_table}.user_id='{$user_id}' AND {$bean->table_name}.deleted=0 AND {$bean->rel_users_table}.deleted=0"; + + + $query = $select.$auto_where; + + $result = $bean->db->query($query, true); + + $list = array(); + + while($row = $bean->db->fetchByAssoc($result)) { + foreach($bean->column_fields as $field) { + if(isset($row[$field])) { + $bean->$field = $row[$field]; + } else { + $bean->$field = ''; + } + } + + $bean->processed_dates_times = array(); + $bean->check_date_relationships_load(); + $bean->fill_in_additional_detail_fields(); + + /** + * PHP 5+ always treats objects as passed by reference + * Need to clone it if we're using 5.0+ + * clone() not supported by 4.x + */ + if(version_compare(phpversion(), "5.0", ">=")) { + $newBean = clone($bean); + } else { + $newBean = $bean; + } + $list[] = $newBean; + } + + return $list; +} +?> diff --git a/include/utils/array_utils.php b/include/utils/array_utils.php new file mode 100644 index 00000000..3d142d79 --- /dev/null +++ b/include/utils/array_utils.php @@ -0,0 +1,293 @@ +''), $options); + } + } else { + $options = array(''=>''); + } + return $options; +} + +/* + * Given an array and key names, return a string in the form of $array_name[$key_name[0]][$key_name[1]]... = $value recursively. + * @params : $key_names - array of keys + * $array_name- name of the array + * $value -value of the array + * $eval - evals the generated string if true, note that the array name must be in the global space! + * @return : example - string $array_name['a']['b']['c'][.] = 'hello' + */ +function override_value_to_string_recursive($key_names, $array_name, $value, $eval=false){ + if ($eval) return eval( "\${$array_name}". override_recursive_helper($key_names, $array_name, $value)); + else return "\${$array_name}". override_recursive_helper($key_names, $array_name, $value); +} + +function override_recursive_helper($key_names, $array_name, $value){ + if( empty( $key_names ) ) + return "=".var_export_helper($value,true).";"; + else{ + $key = array_shift($key_names); + return "[".var_export($key,true)."]". override_recursive_helper($key_names, $array_name,$value); + } +} + +function override_value_to_string_recursive2($array_name, $value_name, $value, $save_empty = true) { + if (is_array($value)) { + $str = ''; + $newArrayName = $array_name . "['$value_name']"; + foreach($value as $key=>$val) { + $str.= override_value_to_string_recursive2($newArrayName, $key, $val, $save_empty); + } + return $str; + } else { + if(!$save_empty && empty($value)){ + return; + }else{ + return "\$$array_name" . "['$value_name'] = " . var_export($value, true) . ";\n"; + } + } +} + +/** + * This function will attempt to convert an object to an array. + * Loops are not checked for so this function should be used with caution. + * + * @param $obj + * @return array representation of $obj + */ +function object_to_array_recursive($obj) +{ + if (!is_object($obj)) + return $obj; + + $ret = get_object_vars($obj); + foreach($ret as $key => $val) + { + if (is_object($val)) { + $ret[$key] = object_to_array_recursive($val); + } + + } + return $ret; +} +/** + * This function returns an array of all the key=>value pairs in $array1 + * that are wither not present, or different in $array2. + * If a key exists in $array2 but not $array1, it will not be reported. + * Values which are arrays are traced further and reported only if thier is a difference + * in one or more of thier children. + * + * @param array $array1, the array which contains all the key=>values you wish to check againts + * @param array $array2, the array which + * @param array $allowEmpty, will return the value if it is empty in $array1 and not in $array2, + * otherwise empty values in $array1 are ignored. + * @return array containing the differences between the two arrays + */ + function deepArrayDiff($array1, $array2, $allowEmpty = false) { + $diff = array(); + foreach($array1 as $key=>$value) { + if (is_array($value)) { + if ((!isset($array2[$key]) || !is_array($array2[$key])) && (isset($value) || $allowEmpty)) { + $diff[$key] = $value; + } else { + $value = deepArrayDiff($array1[$key], $array2[$key], $allowEmpty); + if (!empty($value) || $allowEmpty) + $diff[$key] = $value; + } + } else if ((!isset($array2[$key]) || $value != $array2[$key]) && (isset($value) || $allowEmpty)){ + $diff[$key] = $value; + } + } + return $diff; + } + + /** + * Recursivly set a value in an array, creating sub arrays as necessary + * + * @param unknown_type $array + * @param unknown_type $key + */ + function setDeepArrayValue(&$array, $key, $value) { + //if _ is at position zero, that is invalid. + if (strrpos($key, "_")) { + list ($key, $remkey) = explode('_', $key, 2); + if (!isset($array[$key]) || !is_array($array[$key])) { + $array[$key] = array(); + } + setDeepArrayValue($array[$key], $remkey, $value); + } + else { + $array[$key] = $value; + } + } + + +// This function iterates through the given arrays and combines the values of each key, to form one array +// Returns FALSE if number of elements in the arrays do not match; otherwise, returns merged array +// Example: array("a", "b", "c") and array("x", "y", "z") are passed in; array("ax", "by", "cz") is returned +function array_merge_values($arr1, $arr2) { + if (count($arr1) != count($arr2)) { + return FALSE; + } + + for ($i = 0; $i < count($arr1); $i++) { + $arr1[$i] .= $arr2[$i]; + } + + return $arr1; +} + +/** + * Search an array for a given value ignorning case sensitivity + * + * @param unknown_type $key + * @param unknown_type $haystack + */ +function array_search_insensitive($key, $haystack) +{ + if(!is_array($haystack)) + return FALSE; + + $found = FALSE; + foreach($haystack as $k => $v) + { + if(strtolower($v) == strtolower($key)) + { + $found = TRUE; + break; + } + } + + return $found; +} + +/** + * Wrapper around PHP's ArrayObject class that provides dot-notation recursive searching + * for multi-dimensional arrays + */ +class SugarArray extends ArrayObject +{ + /** + * Return the value matching $key if exists, otherwise $default value + * + * This method uses dot notation to look through multi-dimensional arrays + * + * @param string $key key to look up + * @param mixed $default value to return if $key does not exist + * @return mixed + */ + public function get($key, $default = null) { + return $this->_getFromSource($key, $default); + } + + /** + * Provided as a convinience method for fetching a value within an existing + * array without instantiating a SugarArray + * + * NOTE: This should only used where refactoring an array into a SugarArray + * is unfeasible. This operation is more expensive than a direct + * SugarArray as each time it creates and throws away a new instance + * + * @param array $haystack haystack + * @param string $needle needle + * @param mixed $default default value to return + * @return mixed + */ + static public function staticGet($haystack, $needle, $default = null) { + if (empty($haystack)) { + return $default; + } + $array = new self($haystack); + return $array->get($needle, $default); + } + + private function _getFromSource($key, $default) { + if (strpos($key, '.') === false) { + return isset($this[$key]) ? $this[$key] : $default; + } + + $exploded = explode('.', $key); + $current_key = array_shift($exploded); + return $this->_getRecursive($this->_getFromSource($current_key, $default), $exploded, $default); + } + + private function _getRecursive($raw_config, $children, $default) { + if ($raw_config === $default) { + return $default; + } elseif (count($children) == 0) { + return $raw_config; + } else { + $next_key = array_shift($children); + return isset($raw_config[$next_key]) ? + $this->_getRecursive($raw_config[$next_key], $children, $default) : + $default; + } + } +} + +?> diff --git a/include/utils/autoloader.php b/include/utils/autoloader.php new file mode 100644 index 00000000..0b041cb7 --- /dev/null +++ b/include/utils/autoloader.php @@ -0,0 +1,97 @@ +'XTemplate/xtpl.php', + 'ListView'=>'include/ListView/ListView.php', + 'Sugar_Smarty'=>'include/Sugar_Smarty.php', + 'Javascript'=>'include/javascript/javascript.php', + + ); + + public static $noAutoLoad = array( + 'Tracker'=>true, + ); + + public static $moduleMap = array(); + + public static function autoload($class) + { + $uclass = ucfirst($class); + if(!empty(SugarAutoLoader::$noAutoLoad[$class])){ + return false; + } + if(!empty(SugarAutoLoader::$map[$uclass])){ + require_once(SugarAutoLoader::$map[$uclass]); + return true; + } + + if(empty(SugarAutoLoader::$moduleMap)){ + if(isset($GLOBALS['beanFiles'])){ + SugarAutoLoader::$moduleMap = $GLOBALS['beanFiles']; + }else{ + include('include/modules.php'); + SugarAutoLoader::$moduleMap = $beanFiles; + } + } + if(!empty(SugarAutoLoader::$moduleMap[$class])){ + require_once(SugarAutoLoader::$moduleMap[$class]); + return true; + } + + return false; + } + + public static function loadAll(){ + foreach(SugarAutoLoader::$map as $class=>$file){ + require_once($file); + } + + if(isset($GLOBALS['beanFiles'])){ + $files = $GLOBALS['beanFiles']; + }else{ + include('include/modules.php'); + $files = $beanList; + } + foreach(SugarAutoLoader::$map as $class=>$file){ + require_once($file); + } + + } +} +?> diff --git a/include/utils/db_utils.php b/include/utils/db_utils.php new file mode 100644 index 00000000..f9581766 --- /dev/null +++ b/include/utils/db_utils.php @@ -0,0 +1,202 @@ +convert($string, $type, $additional_parameters, $additional_parameters_oracle_only); + } + +/** + * @deprecated use DBManager::concat() instead. + */ +function db_concat($table, $fields) + { + return $GLOBALS['db']->concat($table, $fields); +} + +/** + * @deprecated use DBManager::fromConvert() instead. + */ +function from_db_convert($string, $type) + { + return $GLOBALS['db']->fromConvert($string, $type); + } + +$toHTML = array( + '"' => '"', + '<' => '<', + '>' => '>', + "'" => ''', +); +$GLOBALS['toHTML_keys'] = array_keys($toHTML); +$GLOBALS['toHTML_values'] = array_values($toHTML); + +/** + * Replaces specific characters with their HTML entity values + * @param string $string String to check/replace + * @param bool $encode Default true + * @return string + * + * @todo Make this utilize the external caching mechanism after re-testing (see + * log on r25320). + */ +function to_html($string, $encode=true){ + if (empty($string)) { + return $string; + } + static $cache = array(); + global $toHTML; + if (isset($cache['c'.$string])) { + return $cache['c'.$string]; + } + + $cache_key = 'c'.$string; + + if($encode && is_string($string)){//$string = htmlentities($string, ENT_QUOTES); + /* + * cn: bug 13376 - handle ampersands separately + * credit: ashimamura via bug portal + */ + //$string = str_replace("&", "&", $string); + + if(is_array($toHTML)) { // cn: causing errors in i18n test suite ($toHTML is non-array) + $string = str_replace( + $GLOBALS['toHTML_keys'], + $GLOBALS['toHTML_values'], + $string + ); + } + } + $cache[$cache_key] = $string; + return $cache[$cache_key]; +} + +/** + * Replaces specific HTML entity values with the true characters + * @param string $string String to check/replace + * @param bool $encode Default true + * @return string + */ +function from_html($string, $encode=true) { + if (!is_string($string) || !$encode) { + return $string; + } + + global $toHTML; + static $toHTML_values = null; + static $toHTML_keys = null; + static $cache = array(); + if (!isset($toHTML_values) || !empty($GLOBALS['from_html_cache_clear'])) { + $toHTML_values = array_values($toHTML); + $toHTML_keys = array_keys($toHTML); + } + + // Bug 36261 - Decode & so we can handle double encoded entities + $string = str_replace("&", "&", $string); + + if (!isset($cache[$string])) { + $cache[$string] = str_replace($toHTML_values, $toHTML_keys, $string); + } + return $cache[$string]; +} + +/** + * @deprecated + * @todo this function is only used by one function ( run_upgrade_wizard_sql() ), which isn't + * used either; trying kill this off + */ +function run_sql_file( $filename ) +{ + if( !is_file( $filename ) ){ + print( "Could not find file: $filename
            " ); + return( false ); + } + + + $contents = sugar_file_get_contents($filename); + + $lastsemi = strrpos( $contents, ';') ; + $contents = substr( $contents, 0, $lastsemi ); + $queries = explode( ';', $contents ); + $db = DBManagerFactory::getInstance(); + + foreach( $queries as $query ){ + if( !empty($query) ){ + if($db->dbType == 'oci8') + { + } + else + { + $db->query( $query.';', true, "An error has occured while running.
            " ); + } + } + } + return( true ); +} + +/* + * Return a version of $proposed that can be used as a column name in any of our supported databases + * Practically this means no longer than 25 characters as the smallest identifier length for our supported DBs is 30 chars for Oracle plus we add on at least four characters in some places (for indicies for example) + * @param string $name Proposed name for the column + * @param string $ensureUnique + * @return string Valid column name trimmed to right length and with invalid characters removed + */ + function getValidDBName ($name, $ensureUnique = false, $maxLen = 30) +{ + // first strip any invalid characters - all but alphanumerics and - + $name = preg_replace ( '/[^\w-]+/i', '', $name ) ; + $len = strlen ( $name ) ; + $result = $name; + if ($ensureUnique) + { + $md5str = md5($name); + $tail = substr ( $name, -11) ; + $temp = substr($md5str , strlen($md5str)-4 ); + $result = substr ( $name, 0, 10) . $temp . $tail ; + }else if ($len > ($maxLen - 5)) + { + $result = substr ( $name, 0, 11) . substr ( $name, 11 - $maxLen + 5); + } + return strtolower ( $result ) ; +} + +?> diff --git a/include/utils/encryption_utils.php b/include/utils/encryption_utils.php new file mode 100644 index 00000000..0ff191c8 --- /dev/null +++ b/include/utils/encryption_utils.php @@ -0,0 +1,104 @@ +encrypt($data); + return base64_encode($encrypted); +} + +/** + * Uses blowfish to decode data assumes data has been base64 encoded with the iv stored as part of the data + * @param STRING key - key to base decoding off of + * @param STRING encoded base64 encoded blowfish encrypted data + * @return string + */ +function blowfishDecode($key, $encoded){ + $data = base64_decode($encoded); + $bf = new Crypt_Blowfish($key); + return trim($bf->decrypt($data)); +} + +?> \ No newline at end of file diff --git a/include/utils/external_cache.php b/include/utils/external_cache.php new file mode 100644 index 00000000..b6e7a692 --- /dev/null +++ b/include/utils/external_cache.php @@ -0,0 +1,40 @@ += 2 && $path[0].$path[1] == "\\\\" ) { + $path = substr($path,2); + $appendpath = "\\\\"; + } + $path = str_replace( "\\", "/", $path ); + $path = str_replace( "//", "/", $path ); + $path = str_replace( "/./", "/", $path ); + return( $appendpath.$path ); +} + +function create_cache_directory($file) +{ + $paths = explode('/',$file); + $dir = str_replace('/','',$GLOBALS['sugar_config']['cache_dir']); + if(!file_exists($dir)) + { + sugar_mkdir($dir, 0775); + } + for($i = 0; $i < sizeof($paths) - 1; $i++) + { + $dir .= '/' . $paths[$i]; + if(!file_exists($dir)) + { + sugar_mkdir($dir, 0775); + } + } + return $dir . '/'. $paths[sizeof($paths) - 1]; +} + +function get_module_dir_list() +{ + $modules = array(); + $path = 'modules'; + $d = dir($path); + while($entry = $d->read()) + { + if($entry != '..' && $entry != '.') + { + if(is_dir($path. '/'. $entry)) + { + $modules[$entry] = $entry; + } + } + } + return $modules; +} + +function mk_temp_dir( $base_dir, $prefix="" ) +{ + $temp_dir = tempnam( getcwd() .'/'. $base_dir, $prefix ); + if( !$temp_dir || !unlink( $temp_dir ) ) + { + return( false ); + } + + if( sugar_mkdir( $temp_dir ) ){ + return( $temp_dir ); + } + + return( false ); +} + +function remove_file_extension( $filename ) +{ + return( substr( $filename, 0, strrpos($filename, ".") ) ); +} + +function write_array_to_file( $the_name, $the_array, $the_file, $mode="w", $header='' ) +{ + if(!empty($header) && ($mode != 'a' || !file_exists($the_file))){ + $the_string = $header; + }else{ + $the_string = "\n"; + + if( $fh = @sugar_fopen( $the_file, $mode ) ) + { + fputs( $fh, $the_string); + fclose( $fh ); + return( true ); + } + else + { + return( false ); + } + +} + +function write_encoded_file( $soap_result, $write_to_dir, $write_to_file="" ) +{ + // this function dies when encountering an error -- use with caution! + // the path/file is returned upon success + + + + if( $write_to_file == "" ) + { + $write_to_file = $write_to_dir . "/" . $soap_result['filename']; + } + + $file = $soap_result['data']; + $write_to_file = str_replace( "\\", "/", $write_to_file ); + + $dir_to_make = dirname( $write_to_file ); + if( !is_dir( $dir_to_make ) ) + { + mkdir_recursive( $dir_to_make ); + } + $fh = sugar_fopen( $write_to_file, "wb" ); + fwrite( $fh, base64_decode( $file ) ); + fclose( $fh ); + + if( md5_file( $write_to_file ) != $soap_result['md5'] ) + { + die( "MD5 error after writing file $write_to_file" ); + } + return( $write_to_file ); +} + +function create_custom_directory($file) +{ + $paths = explode('/',$file); + $dir = 'custom'; + if(!file_exists($dir)) + { + sugar_mkdir($dir, 0755); + } + for($i = 0; $i < sizeof($paths) - 1; $i++) + { + $dir .= '/' . $paths[$i]; + if(!file_exists($dir)) + { + sugar_mkdir($dir, 0755); + } + } + return $dir . '/'. $paths[sizeof($paths) - 1]; +} + +/** + * This function will recursively generates md5s of files and returns an array of all md5s. + * + * @param $path The path of the root directory to scan - must end with '/' + * @param $ignore_dirs array of filenames/directory names to ignore running md5 on - default 'cache' and 'upload' + * @result $md5_array an array containing path as key and md5 as value + */ +function generateMD5array($path, $ignore_dirs = array('cache', 'upload')) +{ + $dh = opendir($path); + while (false !== ($filename = readdir($dh))) + { + $current_dir_content[] = $filename; + } + + // removes the ignored directories + $current_dir_content = array_diff($current_dir_content, $ignore_dirs); + + sort($current_dir_content); + $md5_array = array(); + + foreach($current_dir_content as $file) + { + // make sure that it's not dir '.' or '..' + if(strcmp($file, ".") && strcmp($file, "..")) + { + if(is_dir($path.$file)) + { + // For testing purposes - uncomment to see all files and md5s + //echo "
            Dir: ".$path.$file."
            "; + //generateMD5array($path.$file."/"); + + $md5_array += generateMD5array($path.$file."/", $ignore_dirs); + } + else + { + // For testing purposes - uncomment to see all files and md5s + //echo " File: ".$path.$file."
            "; + //echo md5_file($path.$file)."
            "; + + $md5_array[$path.$file] = md5_file($path.$file); + } + } + } + + return $md5_array; + +} + +/** + * Function to compare two directory structures and return the items in path_a that didn't match in path_b + * + * @param $path_a The path of the first root directory to scan - must end with '/' + * @param $path_b The path of the second root directory to scan - must end with '/' + * @param $ignore_dirs array of filenames/directory names to ignore running md5 on - default 'cache' and 'upload' + * @result array containing all the md5s of everything in $path_a that didn't have a match in $path_b + */ +function md5DirCompare($path_a, $path_b, $ignore_dirs = array('cache', 'upload')) +{ + $md5array_a = generateMD5array($path_a, $ignore_dirs); + $md5array_b = generateMD5array($path_b, $ignore_dirs); + + $result = array_diff($md5array_a, $md5array_b); + + return $result; +} + +/** + * Function to retrieve all file names of matching pattern in a directory (and it's subdirectories) + * example: getFiles($arr, './modules', '.+/EditView.php/'); // grabs all EditView.phps + * @param array $arr return array to populate matches + * @param string $dir directory to look in [ USE ./ in front of the $dir! ] + * @param regex $pattern optional pattern to match against + */ +function getFiles(&$arr, $dir, $pattern = null) { + if(!is_dir($dir))return; + $d = dir($dir); + while($e =$d->read()){ + if(substr($e, 0, 1) == '.')continue; + $file = $dir . '/' . $e; + if(is_dir($file)){ + getFiles($arr, $file, $pattern); + }else{ + if(empty($pattern)) $arr[] = $file; + else if(preg_match($pattern, $file)) + $arr[] = $file; + } + } +} + +/** + * Function to split up large files for download + * used in download.php + * @param string $filename + * @param int $retbytes + */ +function readfile_chunked($filename,$retbytes=true) +{ + $chunksize = 1*(1024*1024); // how many bytes per chunk + $buffer = ''; + $cnt = 0; + $handle = sugar_fopen($filename, 'rb'); + if ($handle === false) + { + return false; + } + while (!feof($handle)) + { + $buffer = fread($handle, $chunksize); + echo $buffer; + flush(); + if ($retbytes) + { + $cnt += strlen($buffer); + } + } + $status = fclose($handle); + if ($retbytes && $status) + { + return $cnt; // return num. bytes delivered like readfile() does. + } + return $status; +} +/** + * Renames a file. If $new_file already exists, it will first unlink it and then rename it. + * used in SugarLogger.php + * @param string $old_filename + * @param string $new_filename + */ +function sugar_rename( $old_filename, $new_filename){ + if (empty($old_filename) || empty($new_filename)) return false; + $success = false; + if(file_exists($new_filename)) { + unlink($new_filename); + $success = rename($old_filename, $new_filename); + } + else { + $success = rename($old_filename, $new_filename); + } + + return $success; +} + +function fileToHash($file){ + $hash = md5($file); + $_SESSION['file2Hash'][$hash] = $file; + return $hash; + } + +function hashToFile($hash){ + if(!empty($_SESSION['file2Hash'][$hash])){ + return $_SESSION['file2Hash'][$hash]; + } + return false; +} + + + +/** + * get_file_extension + * This function returns the file extension portion of a given filename + * + * @param $filename String of filename to return extension + * @param $string_to_lower boolean value indicating whether or not to return value as lowercase, true by default + * + * @return extension String value, blank if no extension found + */ +function get_file_extension($filename, $string_to_lower=true) +{ + if(strpos($filename, '.') !== false) + { + return $string_to_lower ? strtolower(array_pop(explode('.',$filename))) : array_pop(explode('.',$filename)); + } + + return ''; +} + + +/** + * get_mime_content_type_from_filename + * This function is similar to mime_content_type, but does not require a real + * file or path location. Instead, the function merely checks the filename + * extension and returns a best guess mime content type. + * + * @param $filename String of filename to return mime content type + * @return mime content type as String value (defaults to 'application/octet-stream' for filenames with extension, empty otherwise) + * + */ +function get_mime_content_type_from_filename($filename) +{ + if(strpos($filename, '.') !== false) + { + $mime_types = array( + 'txt' => 'text/plain', + 'htm' => 'text/html', + 'html' => 'text/html', + 'php' => 'text/html', + 'css' => 'text/css', + 'js' => 'application/javascript', + 'json' => 'application/json', + 'xml' => 'application/xml', + 'swf' => 'application/x-shockwave-flash', + 'flv' => 'video/x-flv', + + // images + 'png' => 'image/png', + 'jpe' => 'image/jpeg', + 'jpeg' => 'image/jpeg', + 'jpg' => 'image/jpeg', + 'gif' => 'image/gif', + 'bmp' => 'image/bmp', + 'ico' => 'image/vnd.microsoft.icon', + 'tiff' => 'image/tiff', + 'tif' => 'image/tiff', + 'svg' => 'image/svg+xml', + 'svgz' => 'image/svg+xml', + + // archives + 'zip' => 'application/zip', + 'rar' => 'application/x-rar-compressed', + 'exe' => 'application/x-msdownload', + 'msi' => 'application/x-msdownload', + 'cab' => 'application/vnd.ms-cab-compressed', + + // audio/video + 'mp3' => 'audio/mpeg', + 'qt' => 'video/quicktime', + 'mov' => 'video/quicktime', + + // adobe + 'pdf' => 'application/pdf', + 'psd' => 'image/vnd.adobe.photoshop', + 'ai' => 'application/postscript', + 'eps' => 'application/postscript', + 'ps' => 'application/postscript', + + // ms office + 'doc' => 'application/msword', + 'rtf' => 'application/rtf', + 'xls' => 'application/vnd.ms-excel', + 'ppt' => 'application/vnd.ms-powerpoint', + + // open office + 'odt' => 'application/vnd.oasis.opendocument.text', + 'ods' => 'application/vnd.oasis.opendocument.spreadsheet', + ); + + $ext = strtolower(array_pop(explode('.',$filename))); + if (array_key_exists($ext, $mime_types)) { + return $mime_types[$ext]; + } + + return 'application/octet-stream'; + } + + return ''; +} + +function cleanFileName($name) +{ + return preg_replace('/[^\w-._]+/i', '', $name); +} + +?> \ No newline at end of file diff --git a/include/utils/layout_utils.php b/include/utils/layout_utils.php new file mode 100644 index 00000000..46a37fcc --- /dev/null +++ b/include/utils/layout_utils.php @@ -0,0 +1,367 @@ +getImageURL('blank.gif'); + $printImageURL = SugarThemeRegistry::current()->getImageURL("print.gif"); + $helpImageURL = SugarThemeRegistry::current()->getImageURL("help.gif"); + + $is_min_max = strpos($other_text,"_search.gif"); + if($is_min_max !== false) + $form_title = "{$other_text} {$form_title}"; + + $the_form = << + +

            {$form_title}

            +EOHTML; + + $keywords = array("/class=\"button\"/","/class='button'/","/class=button/","/<\/form>/"); + $match=""; + foreach ($keywords as $left) + if (preg_match($left,$other_text)) + $match = true; + + if ($other_text && $match) { + $the_form .= << + + +$other_text + +EOHTML; + if ($show_help) { + $the_form .= ""; + if ($_REQUEST['action'] != "EditView") { + $the_form .= << + Print +   + + {$app_strings['LNK_PRINT']} + +EOHTML; + } + $the_form .= << + Help +   + + {$app_strings['LNK_HELP']} + + +EOHTML; + } + } + else { + if ($other_text && $is_min_max === false) { + $the_form .= << +$other_text +EOHTML; + } + else { + $the_form .= << +EOHTML; + } + + if ($show_help) { + $the_form .= ""; + if ($_REQUEST['action'] != "EditView") { + $the_form .= << + Print +   + + {$app_strings['LNK_PRINT']} +EOHTML; + } + $the_form .= << + Help +   + {$app_strings['LNK_HELP']} + +EOHTML; + } + } + + $the_form .= << + +EOHTML; + + return $the_form; +} + +/** + * Wrapper function for the get_module_title function, which is mostly used for pre-MVC modules. + * + * @deprecated use SugarView::getModuleTitle() for MVC modules, or getClassicModuleTitle() for non-MVC modules + * + * @param $module string to next to the title. Typically used for form buttons. + * @param $module_title string to display as the module title + * @param $show_help boolean which determines if the print and help links are shown. + * @return string HTML + */ +function get_module_title( + $module, + $module_title, + $show_create, + $count=0 + ) +{ + global $sugar_version, $sugar_flavor, $server_unique_key, $current_language, $action; + global $app_strings; + + $the_title = "
            \n

            "; + $module = preg_replace("/ /","",$module); + $iconPath = ""; + if(is_file(SugarThemeRegistry::current()->getImageURL('icon_'.$module.'_32.png',false))) + { + $iconPath = SugarThemeRegistry::current()->getImageURL('icon_'.$module.'_32.png'); + } else if (is_file(SugarThemeRegistry::current()->getImageURL('icon_'.ucfirst($module).'_32.png',false))) + { + $iconPath = SugarThemeRegistry::current()->getImageURL('icon_'.ucfirst($module).'_32.png'); + } + if (!empty($iconPath)) { + if (SugarThemeRegistry::current()->directionality == "ltr") { + $the_title .= ""; + $the_title .= ($count >= 1) ? SugarView::getBreadCrumbSymbol() : ""; + $the_title .= $module_title; + } else { + $the_title .= $module_title; + $the_title .= ($count > 1) ? SugarView::getBreadCrumbSymbol() : ""; + $the_title .= ""; + } + } else { + $the_title .= $module_title; + } + $the_title .= "

            \n"; + + if ($show_create) { + $the_title .= ""; + $createRecordURL = SugarThemeRegistry::current()->getImageURL('create-record.gif'); + $the_title .= << +{$GLOBALS[ + +{$GLOBALS['app_strings']['LNK_CREATE']} + +EOHTML; + + $the_title .= ''; + } + + $the_title .= "
            \n"; + return $the_title; +} + +/** + * Handles displaying the header for classic view modules + * + * @param $module string to next to the title. Typically used for form buttons. + * @param array $params optional, params to display in the breadcrumb, overriding SugarView::_getModuleTitleParams() + * These should be in the form of array('label' => '', 'link' => ''); + * the first breadcrumb should be index at 0, and built from there e.g. + * + * array( + * 'Contacts', + * 'John Smith', + * 'Edit', + * ); + * + * would display as: + * Contacts >> John Smith >> Edit + * @param $show_help boolean which determines if the print and help links are shown. + * @return string HTML + */ +function getClassicModuleTitle( + $module, + $params, + $show_create, + $index_url_override="") +{ + global $sugar_version, $sugar_flavor, $server_unique_key, $current_language, $action; + global $app_strings; + + $module_title = ''; + $count = count($params); + $index = 0; + + + + $module = preg_replace("/ /","",$module); + $iconPath = ""; + $the_title = "
            \n

            "; + + + if(is_file(SugarThemeRegistry::current()->getImageURL('icon_'.$module.'_32.png',false))) + { + $iconPath = SugarThemeRegistry::current()->getImageURL('icon_'.$module.'_32.png'); + } else if (is_file(SugarThemeRegistry::current()->getImageURL('icon_'.ucfirst($module).'_32.png',false))) + { + $iconPath = SugarThemeRegistry::current()->getImageURL('icon_'.ucfirst($module).'_32.png'); + } + if (!empty($iconPath)) { + $url = (!empty($index_url_override)) ? $index_url_override : "index.php?module={$module}&action=index"; + array_unshift ($params,""); + } + + $new_params = array(); + $i = 0; + foreach ($params as $value) { + if ((!is_null($value)) && ($value !== "")) { + $new_params[$i] = $value; + $i++; + } + } + + + if(SugarThemeRegistry::current()->directionality == "rtl") { + $new_params = array_reverse($new_params); + } + + $module_title = join(SugarView::getBreadCrumbSymbol(),$new_params); + + + + $the_title .= $module_title."

            \n"; + + if ($show_create) { + $the_title .= ""; + $createRecordURL = SugarThemeRegistry::current()->getImageURL('create-record.gif'); + $the_title .= << +{$GLOBALS[ + +{$GLOBALS['app_strings']['LNK_CREATE']} + +EOHTML; + + $the_title .= ''; + } + + $the_title .= "
            \n"; + return $the_title; + +} + +/** + * Create a header for a popup. + * + * @todo refactor this into the base Popup_Picker class + * + * @param $theme string the name of the current theme, ignorred to use SugarThemeRegistry::current() instead. + * @return string HTML + */ +function insert_popup_header( + $theme = null + ) +{ + global $app_strings, $sugar_config; + + $charset = isset($app_strings['LBL_CHARSET']) + ? $app_strings['LBL_CHARSET'] : $sugar_config['default_charset']; + + $themeCSS = SugarThemeRegistry::current()->getCSS(); + + echo << + + + +{$app_strings['LBL_BROWSER_TITLE']} +{$themeCSS} +EOHTML; + echo ''; + echo ''; + echo << + +EOHTML; +} + +/** + * Create a footer for a popup. + * + * @todo refactor this into the base Popup_Picker class + * + * @return string HTML + */ +function insert_popup_footer() +{ + echo << + +EOQ; +} diff --git a/include/utils/logic_utils.php b/include/utils/logic_utils.php new file mode 100644 index 00000000..4a420fe0 --- /dev/null +++ b/include/utils/logic_utils.php @@ -0,0 +1,123 @@ +"; + + return $new_contents; +} + + + +function write_logic_file($module_name, $contents){ + + $file = "modules/".$module_name . '/logic_hooks.php'; + $file = create_custom_directory($file); + $fp = sugar_fopen($file, 'wb'); + fwrite($fp,$contents); + fclose($fp); + +//end function write_logic_file +} + +function build_logic_file($hook_array){ + + $hook_contents = ""; + + $hook_contents .= "// Do not store anything in this file that is not part of the array or the hook version. This file will \n"; + $hook_contents .= "// be automatically rebuilt in the future. \n "; + $hook_contents .= "\$hook_version = 1; \n"; + $hook_contents .= "\$hook_array = Array(); \n"; + $hook_contents .= "// position, file, function \n"; + + foreach($hook_array as $event_array => $event){ + + $hook_contents .= "\$hook_array['".$event_array."'] = Array(); \n"; + + foreach($event as $second_key => $elements){ + + $hook_contents .= "\$hook_array['".$event_array."'][] = "; + $hook_contents .= "Array(".$elements[0].", '".$elements[1]."', '".$elements[2]."','".$elements[3]."', '".$elements[4]."'); \n"; + + } + + //end foreach hook_array as event => action_array + } + + $hook_contents .= "\n\n"; + + return $hook_contents; + +//end function build_logic_file +} + +?> diff --git a/include/utils/mvc_utils.php b/include/utils/mvc_utils.php new file mode 100644 index 00000000..f5ff7091 --- /dev/null +++ b/include/utils/mvc_utils.php @@ -0,0 +1,51 @@ + diff --git a/include/utils/php_zip_utils.php b/include/utils/php_zip_utils.php new file mode 100644 index 00000000..75da555f --- /dev/null +++ b/include/utils/php_zip_utils.php @@ -0,0 +1,121 @@ +open($zip_archive); + if($res !== true) { + if (!defined('SUGAR_PHPUNIT_RUNNER')) + die(sprintf("ZIP Error(%d): %s", $res, $zip->status)); + return false; + } + + if($archive_file !== null) { + $res = $zip->extractTo($zip_dir, $archive_file); + } else { + $res = $zip->extractTo($zip_dir); + } + if($res !== true) { + if (!defined('SUGAR_PHPUNIT_RUNNER')) + die(sprintf("ZIP Error(%d): %s", $res, $zip->status)); + return false; + } + return true; +} + +function zip_dir( $zip_dir, $zip_archive ) +{ + if( !is_dir( $zip_dir ) ){ + if (!defined('SUGAR_PHPUNIT_RUNNER')) + die( "Specified directory '$zip_dir' for zip file '$zip_archive' extraction does not exist." ); + return false; + } + $zip = new ZipArchive(); + $zip->open($zip_archive, ZIPARCHIVE::CREATE|ZIPARCHIVE::OVERWRITE); + $path = realpath($zip_dir); + $chop = strlen($path)+1; + $dir = new RecursiveDirectoryIterator($path); + $it = new RecursiveIteratorIterator($dir, RecursiveIteratorIterator::SELF_FIRST); + foreach ($it as $k => $fileinfo) { + $localname = substr($fileinfo->getPathname(), $chop); + if($fileinfo->isDir()) { + $zip->addEmptyDir($localname); + } else { + $zip->addFile($fileinfo->getPathname(), $localname); + } + } +} + +/** + * Zip list of files, optionally stripping prefix + * @param string $zip_file + * @param array $file_list + * @param string $prefix Regular expression for the prefix to strip + */ +function zip_files_list($zip_file, $file_list, $prefix = '') +{ + $archive = new ZipArchive(); + $res = $archive->open($zip_file, ZipArchive::CREATE|ZipArchive::OVERWRITE); + if($res !== TRUE) + { + $GLOBALS['log']->fatal("Unable to open zip file, check directory permissions: $zip_file"); + return FALSE; + } + foreach($file_list as $file) { + if(!empty($prefix) && preg_match($prefix, $file, $matches) > 0) { + $zipname = substr($file, strlen($matches[0])); + } else { + $zipname = $file; + } + $archive->addFile($file, $zipname); + } + return TRUE; +} diff --git a/include/utils/progress_bar_utils.php b/include/utils/progress_bar_utils.php new file mode 100644 index 00000000..718f0a34 --- /dev/null +++ b/include/utils/progress_bar_utils.php @@ -0,0 +1,148 @@ +
                 


            "; + + echo str_repeat(' ',256); + + progress_bar_flush(); + start_flow_bar($name, $delay); +} + +function start_flow_bar($name, $delay) +{ + $delay *= 1000; + $timer_id = $name . '_id'; + echo " +"; + echo str_repeat(' ',256); + + progress_bar_flush(); +} + +function destroy_flow_bar($name) +{ + $timer_id = $name . '_id'; + echo ""; + echo str_repeat(' ',256); + + progress_bar_flush(); +} + +function display_progress_bar($name,$current, $total) +{ + $percent = $current/$total * 100; + $remain = 100 - $percent; + $status = floor($percent); + //scale to a larger size + $percent *= 2; + $remain *= 2; + if($remain == 0){ + $remain = 1; + } + if($percent == 0){ + $percent = 1; + } + echo "
            $status%  

            "; + if($status == 0){ + echo ""; + } + echo str_repeat(' ',256); + + progress_bar_flush(); +} + +function update_progress_bar($name,$current, $total) +{ + $percent = $current/$total * 100; + $remain = 100 - $percent; + $status = floor($percent); + //scale to a larger size + $percent *= 2; + $remain *= 2; + if($remain == 0){ + $remain = 1; + } + if($status == 100){ + echo ""; + } + if($status == 0){ + echo ""; + echo ""; + } + if($status > 0){ + echo ""; + } + + + if($percent == 0){ + $percent = 1; + } + + echo ""; + progress_bar_flush(); +} diff --git a/include/utils/security_utils.php b/include/utils/security_utils.php new file mode 100644 index 00000000..2ecfbacb --- /dev/null +++ b/include/utils/security_utils.php @@ -0,0 +1,146 @@ +get_tabs($user); + + return $tabArray[0]; + +} + +function query_user_has_roles($user_id) +{ + + + $role = new Role(); + + return $role->check_user_role_count($user_id); +} + +function get_user_allowed_modules($user_id) +{ + + + $role = new Role(); + + $allowed = $role->query_user_allowed_modules($user_id); + return $allowed; +} + +function get_user_disallowed_modules($user_id, &$allowed) +{ + + + $role = new Role(); + $disallowed = $role->query_user_disallowed_modules($user_id, $allowed); + return $disallowed; +} +// grabs client ip address and returns its value +function query_client_ip() +{ + global $_SERVER; + $clientIP = false; + if(!empty($GLOBALS['sugar_config']['ip_variable']) && !empty($_SERVER[$GLOBALS['sugar_config']['ip_variable']])){ + $clientIP = $_SERVER[$GLOBALS['sugar_config']['ip_variable']]; + }else if(isset($_SERVER['HTTP_CLIENT_IP'])) + { + $clientIP = $_SERVER['HTTP_CLIENT_IP']; + } + elseif(isset($_SERVER['HTTP_X_FORWARDED_FOR']) AND preg_match_all('#\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}#s', $_SERVER['HTTP_X_FORWARDED_FOR'], $matches)) + { + // check for internal ips by looking at the first octet + foreach($matches[0] AS $ip) + { + if(!preg_match("#^(10|172\.16|192\.168)\.#", $ip)) + { + $clientIP = $ip; + break; + } + } + + } + elseif(isset($_SERVER['HTTP_FROM'])) + { + $clientIP = $_SERVER['HTTP_FROM']; + } + else + { + $clientIP = $_SERVER['REMOTE_ADDR']; + } + return $clientIP; +} + +// sets value to key value +function get_val_array($arr){ + $new = array(); + if(!empty($arr)){ + foreach($arr as $key=>$val){ + $new[$key] = $key; + } + } + return $new; +} + diff --git a/include/utils/sugar_file_utils.php b/include/utils/sugar_file_utils.php new file mode 100644 index 00000000..d6f7fa84 --- /dev/null +++ b/include/utils/sugar_file_utils.php @@ -0,0 +1,328 @@ +error("Cannot create directory $pathname cannot be touched"); + } + + return $result; +} + +/** + * sugar_fopen + * Call this function instead of fopen to apply preconfigured permission + * settings when creating the the file. This method is basically + * a wrapper to the PHP fopen function except that it supports setting + * the mode value by using the configuration file (if set). The mode is + * 0777 by default. + * + * @param $filename - String value of the file to create + * @param $mode - The integer value of the permissions mode to set the created file to + * @param $$use_include_path - boolean value indicating whether or not to search the the included_path + * @param $context + * @return boolean - Returns a file pointer on success, false otherwise + */ +function sugar_fopen($filename, $mode, $use_include_path=false, $context=null){ + //check to see if the file exists, if not then use touch to create it. + if(!file_exists($filename)){ + sugar_touch($filename); + } + + if(empty($context)) { + return fopen($filename, $mode, $use_include_path); + } else { + return fopen($filename, $mode, $use_include_path, $context); + } +} + +/** + * sugar_file_put_contents + * Call this function instead of file_put_contents to apply preconfigured permission + * settings when creating the the file. This method is basically + * a wrapper to the PHP file_put_contents function except that it supports setting + * the mode value by using the configuration file (if set). The mode is + * 0777 by default. + * + * @param $filename - String value of the file to create + * @param $data - The data to be written to the file + * @param $flags - int as specifed by file_put_contents parameters + * @param $context + * @return int - Returns the number of bytes written to the file, false otherwise. + */ +function sugar_file_put_contents($filename, $data, $flags=null, $context=null){ + //check to see if the file exists, if not then use touch to create it. + if(!file_exists($filename)){ + sugar_touch($filename); + } + + if ( !is_writable($filename) ) { + $GLOBALS['log']->error("File $filename cannot be written to"); + return false; + } + + if(empty($flags)) { + return file_put_contents($filename, $data); + } elseif(empty($context)) { + return file_put_contents($filename, $data, $flags); + } else{ + return file_put_contents($filename, $data, $flags, $context); + } +} + +/** + * sugar_file_get_contents + * + * @param $filename - String value of the file to create + * @param $use_include_path - boolean value indicating whether or not to search the the included_path + * @param $context + * @return string|boolean - Returns a file data on success, false otherwise + */ +function sugar_file_get_contents($filename, $use_include_path=false, $context=null){ + //check to see if the file exists, if not then use touch to create it. + if(!file_exists($filename)){ + sugar_touch($filename); + } + + if ( !is_readable($filename) ) { + $GLOBALS['log']->error("File $filename cannot be read"); + return false; + } + + if(empty($context)) { + return file_get_contents($filename, $use_include_path); + } else { + return file_get_contents($filename, $use_include_path, $context); + } +} + +/** + * sugar_touch + * Attempts to set the access and modification times of the file named in the filename + * parameter to the value given in time . Note that the access time is always modified, + * regardless of the number of parameters. If the file does not exist it will be created. + * This method is basically a wrapper to the PHP touch method except that created files + * may be set with the permissions specified in the configuration file (if set). + * + * @param $filename - The name of the file being touched. + * @param $time - The touch time. If time is not supplied, the current system time is used. + * @param $atime - If present, the access time of the given filename is set to the value of atime + * @return boolean - Returns TRUE on success or FALSE on failure. + * + */ +function sugar_touch($filename, $time=null, $atime=null) { + + $result = false; + + if(!empty($atime) && !empty($time)) { + $result = @touch($filename, $time, $atime); + } else if(!empty($time)) { + $result = @touch($filename, $time); + } else { + $result = @touch($filename); + } + + if(!$result) { + $GLOBALS['log']->error("File $filename cannot be touched"); + return $result; + } + if(!empty($GLOBALS['sugar_config']['default_permissions']['file_mode'])){ + sugar_chmod($filename, $GLOBALS['sugar_config']['default_permissions']['file_mode']); + } + if(!empty($GLOBALS['sugar_config']['default_permissions']['user'])){ + sugar_chown($filename); + } + if(!empty($GLOBALS['sugar_config']['default_permissions']['group'])){ + sugar_chgrp($filename); + } + + return true; +} + +/** + * sugar_chmod + * Attempts to change the permission of the specified filename to the mode value specified in the + * default_permissions configuration; otherwise, it will use the mode value. + * + * @param string filename - Path to the file + * @param int $mode The integer value of the permissions mode to set the created directory to + * @return boolean Returns TRUE on success or FALSE on failure. + */ +function sugar_chmod($filename, $mode=null) { + if ( !is_int($mode) ) + $mode = (int) $mode; + if(!is_windows()){ + if(!isset($mode)){ + $mode = get_mode('file_mode', $mode); + } + if(isset($mode) && $mode > 0){ + return @chmod($filename, $mode); + }else{ + return false; + } + } + return true; +} + +/** + * sugar_chown + * Attempts to change the owner of the file filename to the user specified in the + * default_permissions configuration; otherwise, it will use the user value. + * + * @param filename - Path to the file + * @param user - A user name or number + * @return boolean - Returns TRUE on success or FALSE on failure. + */ +function sugar_chown($filename, $user='') { + if(!is_windows()){ + if(strlen($user)){ + return chown($filename, $user); + }else{ + if(strlen($GLOBALS['sugar_config']['default_permissions']['user'])){ + $user = $GLOBALS['sugar_config']['default_permissions']['user']; + return chown($filename, $user); + }else{ + return false; + } + } + } + return true; +} + +/** + * sugar_chgrp + * Attempts to change the group of the file filename to the group specified in the + * default_permissions configuration; otherwise it will use the group value. + * + * @param filename - Path to the file + * @param group - A group name or number + * @return boolean - Returns TRUE on success or FALSE on failure. + */ +function sugar_chgrp($filename, $group='') { + if(!is_windows()){ + if(!empty($group)){ + return chgrp($filename, $group); + }else{ + if(!empty($GLOBALS['sugar_config']['default_permissions']['group'])){ + $group = $GLOBALS['sugar_config']['default_permissions']['group']; + return chgrp($filename, $group); + }else{ + return false; + } + } + } + return true; +} + +/** + * get_mode + * + * Will check to see if there is a default mode defined in the config file, otherwise return the + * $mode given as input + * + * @param int $mode - the mode being passed by the calling function. This value will be overridden by a value + * defined in the config file. + * @return int - the mode either found in the config file or passed in via the input parameter + */ +function get_mode($key = 'dir_mode', $mode=null) { + if ( !is_int($mode) ) + $mode = (int) $mode; + if(!class_exists('SugarConfig', true)) { + require 'include/SugarObjects/SugarConfig.php'; + } + if(!is_windows()){ + $conf_inst=SugarConfig::getInstance(); + $mode = $conf_inst->get('default_permissions.'.$key, $mode); + } + return $mode; +} + +function sugar_is_dir($path, $mode='r'){ + if(defined('TEMPLATE_URL'))return is_dir($path, $mode); + return is_dir($path); +} + +function sugar_is_file($path, $mode='r'){ + if(defined('TEMPLATE_URL'))return is_file($path, $mode); + return is_file($path); +} + +?> diff --git a/include/utils/zip_utils.php b/include/utils/zip_utils.php new file mode 100644 index 00000000..74809042 --- /dev/null +++ b/include/utils/zip_utils.php @@ -0,0 +1,130 @@ +deprecated('Use of PCLZip has been deprecated. Please enable the zip extension in your PHP install ( see http://www.php.net/manual/en/zip.installation.php for more details ).'); +} +function unzip( $zip_archive, $zip_dir, $forceOverwrite = false ){ + if( !is_dir( $zip_dir ) ){ + if (!defined('SUGAR_PHPUNIT_RUNNER')) + die( "Specified directory '$zip_dir' for zip file '$zip_archive' extraction does not exist." ); + return false; + } + + $archive = new PclZip( $zip_archive ); + + if ( $forceOverwrite ) { + if( $archive->extract( PCLZIP_OPT_PATH, $zip_dir, PCLZIP_OPT_REPLACE_NEWER ) == 0 ){ + if (!defined('SUGAR_PHPUNIT_RUNNER')) + die( "Error: " . $archive->errorInfo(true) ); + return false; + } + } + else { + if( $archive->extract( PCLZIP_OPT_PATH, $zip_dir ) == 0 ){ + if (!defined('SUGAR_PHPUNIT_RUNNER')) + die( "Error: " . $archive->errorInfo(true) ); + return false; + } + } +} + +function unzip_file( $zip_archive, $archive_file, $to_dir, $forceOverwrite = false ){ + if( !is_dir( $to_dir ) ){ + if (!defined('SUGAR_PHPUNIT_RUNNER')) + die( "Specified directory '$to_dir' for zip file '$zip_archive' extraction does not exist." ); + return false; + } + + $archive = new PclZip($zip_archive); + if ( $forceOverwrite ) { + if( $archive->extract( PCLZIP_OPT_BY_NAME, $archive_file, + PCLZIP_OPT_PATH, $to_dir, + PCLZIP_OPT_REPLACE_NEWER ) == 0 ){ + if (!defined('SUGAR_PHPUNIT_RUNNER')) + die( "Error: " . $archive->errorInfo(true) ); + return false; + } + } + else { + if( $archive->extract( PCLZIP_OPT_BY_NAME, $archive_file, + PCLZIP_OPT_PATH, $to_dir ) == 0 ){ + if (!defined('SUGAR_PHPUNIT_RUNNER')) + die( "Error: " . $archive->errorInfo(true) ); + return false; + } + } +} + +function zip_dir( $zip_dir, $zip_archive ){ + $archive = new PclZip( $zip_archive ); + $v_list = $archive->create( $zip_dir ); + if( $v_list == 0 ){ + if (!defined('SUGAR_PHPUNIT_RUNNER')) + die( "Error: " . $archive->errorInfo(true) ); + return false; + } +} + +/** + * Zip list of files, optionally stripping prefix + * @param string $zip_file + * @param array $file_list + * @param string $prefix Regular expression for the prefix to strip + */ +function zip_files_list($zip_file, $file_list, $prefix = '') +{ + $archive = new PclZip( $zip_file ); + foreach($file_list as $file) { + if(!empty($prefix) && preg_match($prefix, $file, $matches) > 0) { + $remove_path = $matches[0]; + $archive->add($file, PCLZIP_OPT_REMOVE_PATH, $prefix); + } else { + $archive->add($file); + } + } + return true; +} + +} // if (ZipArchive exists) \ No newline at end of file diff --git a/include/vCard.php b/include/vCard.php new file mode 100644 index 00000000..d432cf20 --- /dev/null +++ b/include/vCard.php @@ -0,0 +1,385 @@ +properties = array(); + } + + function loadContact($contactid, $module='Contacts') { + global $app_list_strings; + + require_once($GLOBALS['beanFiles'][$GLOBALS['beanList'][$module]]); + $contact = new $GLOBALS['beanList'][$module](); + $contact->retrieve($contactid); + // cn: bug 8504 - CF/LB break Outlook's vCard import + $bad = array("\n", "\r"); + $good = array("=0A", "=0D"); + $encoding = ''; + if(strpos($contact->primary_address_street, "\n") || strpos($contact->primary_address_street, "\r")) { + $contact->primary_address_street = str_replace($bad, $good, $contact->primary_address_street); + $encoding = 'QUOTED-PRINTABLE'; + } + + $this->setName(from_html($contact->first_name), from_html($contact->last_name), $app_list_strings['salutation_dom'][from_html($contact->salutation)]); + if ( isset($contact->birthdate) ) + $this->setBirthDate(from_html($contact->birthdate)); + $this->setPhoneNumber(from_html($contact->phone_fax), 'FAX'); + $this->setPhoneNumber(from_html($contact->phone_home), 'HOME'); + $this->setPhoneNumber(from_html($contact->phone_mobile), 'CELL'); + $this->setPhoneNumber(from_html($contact->phone_work), 'WORK'); + $this->setEmail(from_html($contact->email1)); + $this->setAddress(from_html($contact->primary_address_street), from_html($contact->primary_address_city), from_html($contact->primary_address_state), from_html($contact->primary_address_postalcode), from_html($contact->primary_address_country), 'WORK', $encoding); + if ( isset($contact->account_name) ) + $this->setORG(from_html($contact->account_name), from_html($contact->department)); + else + $this->setORG('', from_html($contact->department)); + $this->setTitle($contact->title); + } + + function setTitle($title){ + $this->setProperty("TITLE",$title ); + } + function setORG($org, $dep){ + $this->setProperty("ORG","$org;$dep" ); + } + function setAddress($address, $city, $state,$postal, $country, $type, $encoding=''){ + if(!empty($encoding)) { + $encoding = ";ENCODING={$encoding}"; + } + $this->setProperty("ADR;$type$encoding",";;$address;$city;$state;$postal;$country" ); + } + + function setName($first_name, $last_name, $prefix){ + $this->name = strtr($first_name.'_'.$last_name, ' ' , '_'); + $this->setProperty('N',$last_name.';'.$first_name.';;'.$prefix ); + $this->setProperty('FN',"$prefix $first_name $last_name"); + } + + function setEmail($address){ + $this->setProperty('EMAIL;INTERNET', $address); + } + + function setPhoneNumber( $number, $type) + { + if($type != 'FAX') { + $this->setProperty("TEL;$type", $number); + } + else { + $this->setProperty("TEL;WORK;$type", $number); + } + } + function setBirthDate($date){ + $this->setProperty('BDAY',$date); + } + function getProperty($name){ + if(isset($this->properties[$name])) + return $this->properties[$name]; + return null; + } + + function setProperty($name, $value){ + $this->properties[$name] = $value; + } + + function toString(){ + global $locale; + $temp = "BEGIN:VCARD\n"; + foreach($this->properties as $key=>$value){ + if(!empty($value)) { + $temp .= $key. ';CHARSET='.strtolower($locale->getExportCharset()).':'.$value."\n"; + } else { + $temp .= $key. ':'.$value."\n"; + } + } + $temp.= "END:VCARD\n"; + + + return $temp; + } + + function saveVCard(){ + global $locale; + $content = $this->toString(); + if ( !defined('SUGAR_PHPUNIT_RUNNER') ) { + header("Content-Disposition: attachment; filename={$this->name}.vcf"); + header("Content-Type: text/x-vcard; charset=".$locale->getExportCharset()); + header("Expires: Mon, 26 Jul 1997 05:00:00 GMT" ); + header("Last-Modified: " . TimeDate::httpTime() ); + header("Cache-Control: max-age=0"); + header("Pragma: public"); + header("Content-Length: ".strlen($content)); + } + + print $locale->translateCharset($content, 'UTF-8', $locale->getExportCharset()); + } + + function importVCard($filename, $module='Contacts'){ + global $current_user; + $lines = file($filename); + $start = false; + $contact = loadBean($module); + + $contact->title = 'imported'; + $contact->assigned_user_id = $current_user->id; + $fullname = ''; + $email_suffix = 1; + + for($index = 0; $index < sizeof($lines); $index++){ + $line = $lines[$index]; + + // check the encoding and change it if needed + $locale = new Localization(); + $encoding = $locale->detectCharset($line); + if ( $encoding != $GLOBALS['sugar_config']['default_charset'] ) { + $line = $locale->translateCharset($line,$encoding); + } + $line = trim($line); + if($start){ + //VCARD is done + if(substr_count(strtoupper($line), 'END:VCARD')){ + if(!isset($contact->last_name)){ + $contact->last_name = $fullname; + } + break; + } + $keyvalue = explode(':',$line); + if(sizeof($keyvalue)==2){ + $value = $keyvalue[1]; + for($newindex= $index + 1; $newindex < sizeof($lines), substr_count($lines[$newindex], ':') == 0; $newindex++){ + $value .= $lines[$newindex]; + $index = $newindex; + } + $values = explode(';',$value ); + $key = strtoupper($keyvalue[0]); + $key = strtr($key, '=', ''); + $key = strtr($key, ',',';'); + $keys = explode(';' ,$key); + + if($keys[0] == 'TEL'){ + if(substr_count($key, 'WORK') > 0){ + if(substr_count($key, 'FAX') > 0){ + if(!isset($contact->phone_fax)){ + $contact->phone_fax = $value; + } + }else{ + if(!isset($contact->phone_work)){ + $contact->phone_work = $value; + } + } + } + if(substr_count($key, 'HOME') > 0){ + if(substr_count($key, 'FAX') > 0){ + if(!isset($contact->phone_fax)){ + $contact->phone_fax = $value; + } + }else{ + if(!isset($contact->phone_home)){ + $contact->phone_home = $value; + } + } + } + if(substr_count($key, 'CELL') > 0){ + if(!isset($contact->phone_mobile)){ + $contact->phone_mobile = $value; + } + + } + if(substr_count($key, 'FAX') > 0){ + if(!isset($contact->phone_fax)){ + $contact->phone_fax = $value; + } + + } + + } + if($keys[0] == 'N'){ + if(sizeof($values) > 0) + $contact->last_name = $values[0]; + if(sizeof($values) > 1) + $contact->first_name = $values[1]; + if(sizeof($values) > 2) + $contact->salutation = $values[2]; + + + + } + if($keys[0] == 'FN'){ + $fullname = $value; + + + } + + } + if($keys[0] == 'ADR'){ + if(substr_count($key, 'WORK') > 0 && (substr_count($key, 'POSTAL') > 0|| substr_count($key, 'PARCEL') == 0)){ + + if(!isset($contact->primary_address_street) && sizeof($values) > 2){ + $textBreaks = array("\n", "\r"); + $vcardBreaks = array("=0A", "=0D"); + $contact->primary_address_street = str_replace($vcardBreaks, $textBreaks, $values[2]); + } + if(!isset($contact->primary_address_city) && sizeof($values) > 3){ + $contact->primary_address_city = $values[3]; + } + if(!isset($contact->primary_address_state) && sizeof($values) > 4){ + $contact->primary_address_state = $values[4]; + } + if(!isset($contact->primary_address_postalcode) && sizeof($values) > 5){ + $contact->primary_address_postalcode = $values[5]; + } + if(!isset($contact->primary_address_country) && sizeof($values) > 6){ + $contact->primary_address_country = $values[6]; + } + } + } + + if($keys[0] == 'TITLE'){ + $contact->title = $value; + + } + if($keys[0] == 'EMAIL'){ + $field = 'email' . $email_suffix; + if(!isset($contact->$field)) { + $contact->$field = $value; + } + + if($email_suffix == 1) { + $_REQUEST['email1'] = $value; + } + + $email_suffix++; + } + + if($keys[0] == 'ORG'){ + $GLOBALS['log']->debug('I found a company name'); + if(!empty($value)){ + $GLOBALS['log']->debug('I found a company name (fer real)'); + if ( is_a($contact,"Contact") || is_a($contact,"Lead") ) { + $GLOBALS['log']->debug('And Im dealing with a person!'); + $accountBean = loadBean('Accounts'); + // It's a contact, we better try and match up an account + $full_company_name = trim($values[0]); + // Do we have a full company name match? + $result = $accountBean->retrieve_by_string_fields(array('name' => $full_company_name, 'deleted' => 0)); + if ( ! isset($result->id) ) { + // Try to trim the full company name down, see if we get some other matches + $vCardTrimStrings = array('/ltd\.*/i'=>'', + '/llc\.*/i'=>'', + '/gmbh\.*/i'=>'', + '/inc\.*/i'=>'', + '/\.com/i'=>'', + ); + // Allow users to override the trimming strings + if ( file_exists('custom/include/vCardTrimStrings.php') ) { + require_once('custom/include/vCardTrimStrings.php'); + } + $short_company_name = trim(preg_replace(array_keys($vCardTrimStrings),$vCardTrimStrings,$full_company_name)," ,."); + + $GLOBALS['log']->debug('Trying an extended search for: '.$short_company_name); + $result = $accountBean->retrieve_by_string_fields(array('name' => $short_company_name, 'deleted' => 0)); + } + + if ( is_a($contact,"Lead") || ! isset($result->id) ) { + // We could not find a parent account, or this is a lead so only copy the name, no linking + $GLOBALS['log']->debug("Did not find a matching company ($full_company_name)"); + $contact->account_id = ''; + $contact->account_name = $full_company_name; + } else { + $GLOBALS['log']->debug("Found a matching company: ".$result->name); + $contact->account_id = $result->id; + $contact->account_name = $result->name; + } + $contact->department = $values[1]; + } else{ + $contact->department = $value; + } + } + + } + + } + + + + + //FOUND THE BEGINING OF THE VCARD + if(!$start && substr_count(strtoupper($line), 'BEGIN:VCARD')){ + $start = true; + } + + } + + if ( is_a($contact, "Contact") && empty($contact->account_id) && !empty($contact->account_name) ) { + $GLOBALS['log']->debug("Look ma! I'm creating a new account: ".$contact->account_name); + // We need to create a new account + $accountBean = loadBean('Accounts'); + // Populate the newly created account with all of the contact information + foreach ( $contact->field_defs as $field_name => $field_def ) { + if ( !empty($contact->$field_name) ) { + $accountBean->$field_name = $contact->$field_name; + } + } + $accountBean->name = $contact->account_name; + $accountBean->save(); + $contact->account_id = $accountBean->id; + } + + $contactId = $contact->save(); + return $contactId; + } + } + + + + + + + + +?> diff --git a/include/ytree/ExtNode.php b/include/ytree/ExtNode.php new file mode 100644 index 00000000..da9f4807 --- /dev/null +++ b/include/ytree/ExtNode.php @@ -0,0 +1,114 @@ +_label=$label; + $this->id = $id; + $this->_properties['text']=$label; + $this->uid=microtime(); + $this->set_property('id',$id); + $this->expanded = $show_expanded; + } + + //properties set here will be accessible via + //node.data object in javascript. + //users can add a collection of paramaters that will + //be passed to objects responding to tree events + function set_property($name, $value, $is_param=false) { + if(!empty($name) && ($value === 0 || !empty($value))) { + if ($is_param==false) { + $this->_properties[$name]=$value; + } else { + $this->_params[$name]=$value; + } + } + } + + //add a child node. + function add_node($node) { + $this->nodes[$node->uid]=$node; + } + + //return definition of the node. the definition is a multi-dimension array and has 3 parts. + // data-> definition of the current node. + // attributes=> collection of additional attributes such as style class etc.. + // nodes: definition of children nodes. + function get_definition() { + $ret=array(); + + $ret = $this->_properties; + if (!empty($this->_params)) { + $ret[] = $this->_params; + } + + $ret['dynamicload']=$this->dynamic_load; + $ret['dynamicloadfunction']=$this->dynamicloadfunction; + $ret['expanded']=$this->expanded; + $ret['children'] = array(); + $ret['type'] = 1; + + foreach ($this->nodes as $node) { + $ret['children'][]=$node->get_definition(); + } + //$ret['leaf'] = empty($ret['children']); + return $ret; + } +} +?> \ No newline at end of file diff --git a/include/ytree/Node.php b/include/ytree/Node.php new file mode 100644 index 00000000..1738b096 --- /dev/null +++ b/include/ytree/Node.php @@ -0,0 +1,110 @@ +_label=$label; + $this->_properties['label']=$label; + $this->uid = create_guid(); + $this->set_property('id',$id); + $this->expanded = $show_expanded; + } + + //properties set here will be accessible via + //node.data object in javascript. + //users can add a collection of paramaters that will + //be passed to objects responding to tree events + function set_property($name, $value, $is_param=false) { + if(!empty($name) && ($value === 0 || !empty($value))) { + if ($is_param==false) { + $this->_properties[$name]=$value; + } else { + $this->_params[$name]=$value; + } + } + } + + //add a child node. + function add_node($node) { + $this->nodes[$node->uid]=$node; + } + + //return definition of the node. the definition is a multi-dimension array and has 3 parts. + // data-> definition of the current node. + // attributes=> collection of additional attributes such as style class etc.. + // nodes: definition of children nodes. + function get_definition() { + $ret=array(); + + $ret['data']=$this->_properties; + if (count($this->_params) > 0) { + $ret['data']['param']=$this->_params; + } + + $ret['custom']['dynamicload']=$this->dynamic_load; + $ret['custom']['dynamicloadfunction']=$this->dynamicloadfunction; + $ret['custom']['expanded']=$this->expanded; + + foreach ($this->nodes as $node) { + $ret['nodes'][]=$node->get_definition(); + } + return $ret; + } +} +?> \ No newline at end of file diff --git a/include/ytree/Tree.php b/include/ytree/Tree.php new file mode 100644 index 00000000..7de067f4 --- /dev/null +++ b/include/ytree/Tree.php @@ -0,0 +1,169 @@ +_name=$name; + $this->json=new JSON(JSON_LOOSE_TYPE); + } + + //optionally add json.js, required for making AJAX Calls. + function include_json_reference($reference=null) { + if (empty($reference)) { + $this->_header_files[]='include/JSON.js'; + } else { + $this->_header_files[]=$reference; + } + } + + function add_node($node) { + $this->_nodes[$node->uid]=$node; + } + +// returns html for including necessary javascript files. + function generate_header() { + $ret="\n"; + foreach ($this->_header_files as $filename) { + $ret.="\n"; + } + return $ret; + } + +//properties set here will be accessible from +//the tree's name space.. + function set_param($name, $value) { + if (!empty($name) && !empty($value)) { + $this->_params[$name]=$value; + } + } + + function generate_nodes_array($scriptTags = true) { + global $sugar_config; + $node=null; + $ret=array(); + foreach ($this->_nodes as $node ) { + $ret['nodes'][]=$node->get_definition(); + } + + //todo removed site_url setting from here. + //todo make these variables unique. + $tree_data="var TREE_DATA= " . $this->json->encode($ret) . ";\n"; + $tree_data.="var param= " . $this->json->encode($this->_params) . ";\n"; + + $tree_data.="var mytree;\n"; + $tree_data.="treeinit(mytree,TREE_DATA,'{$this->_name}',param);\n"; + if($scriptTags) return ''; + else return $tree_data; + } + + + /** + * Generates the javascript node arrays without calling treeinit(). Also generates a callback function that can be + * easily called to instatiate the treeview object onload(). + * + * IE6/7 will throw an "Operation Aborted" error when calling certain types of scripts before the page is fully + * loaded. The workaround is to move the init() call to the onload handler. See: http://www.viavirtualearth. + * com/wiki/DeferScript.ashx + * + * @param bool insertScriptTags Flag to add "; + } + + return $treeData; + } + + function generateNodesRaw() { + $node = null; + $ret = array(); + $return = array(); + + foreach($this->_nodes as $node) { + $ret['nodes'][] = $node->get_definition(); + } + + $return['tree_data'] = $ret; + $return['param'] = $this->_params; + + return $return; + } +} +?> diff --git a/include/ytree/TreeView/HTMLNode.js b/include/ytree/TreeView/HTMLNode.js new file mode 100644 index 00000000..e7904ec5 --- /dev/null +++ b/include/ytree/TreeView/HTMLNode.js @@ -0,0 +1,6 @@ +/* Copyright (c) 2006 Yahoo! Inc. All rights reserved. */ +YAHOO.widget.HTMLNode=function(oData,oParent,expanded,hasIcon){if(oParent){this.init(oData,oParent,expanded);this.initContent(oData,hasIcon);}};YAHOO.widget.HTMLNode.prototype=new YAHOO.widget.Node();YAHOO.widget.HTMLNode.prototype.contentStyle="ygtvhtml";YAHOO.widget.HTMLNode.prototype.contentElId=null;YAHOO.widget.HTMLNode.prototype.content=null;YAHOO.widget.HTMLNode.prototype.initContent=function(oData,hasIcon){if(typeof oData=="string"){oData={html:oData};} +this.html=oData.html;this.contentElId="ygtvcontentel"+this.index;this.hasIcon=hasIcon;};YAHOO.widget.HTMLNode.prototype.getContentEl=function(){return document.getElementById(this.contentElId);};YAHOO.widget.HTMLNode.prototype.getNodeHtml=function(){var sb=new Array();sb[sb.length]='';sb[sb.length]='';for(i=0;i ';} +if(this.hasIcon){sb[sb.length]=' ';if(this.hasChildren(true)){sb[sb.length]=' onmouseover="this.className=';sb[sb.length]='YAHOO.widget.TreeView.getNode(\'';sb[sb.length]=this.tree.id+'\','+this.index+').getHoverStyle()"';sb[sb.length]=' onmouseout="this.className=';sb[sb.length]='YAHOO.widget.TreeView.getNode(\'';sb[sb.length]=this.tree.id+'\','+this.index+').getStyle()"';} +sb[sb.length]='';} +sb[sb.length]='';sb[sb.length]='';sb[sb.length]='
            ';return sb.join("");}; \ No newline at end of file diff --git a/include/ytree/TreeView/MenuNode.js b/include/ytree/TreeView/MenuNode.js new file mode 100644 index 00000000..30a50591 --- /dev/null +++ b/include/ytree/TreeView/MenuNode.js @@ -0,0 +1,3 @@ +/* Copyright (c) 2006 Yahoo! Inc. All rights reserved. */ +YAHOO.widget.MenuNode=function(oData,oParent,expanded){if(oParent){this.init(oData,oParent,expanded);this.setUpLabel(oData);} +this.multiExpand=false;};YAHOO.widget.MenuNode.prototype=new YAHOO.widget.TextNode(); \ No newline at end of file diff --git a/include/ytree/TreeView/Node.js b/include/ytree/TreeView/Node.js new file mode 100644 index 00000000..40c8c1b9 --- /dev/null +++ b/include/ytree/TreeView/Node.js @@ -0,0 +1,21 @@ +/* Copyright (c) 2006 Yahoo! Inc. All rights reserved. */ +YAHOO.widget.Node=function(oData,oParent,expanded){if(oParent){this.init(oData,oParent,expanded);}};YAHOO.widget.Node.prototype={index:0,children:null,tree:null,data:null,parent:null,depth:-1,href:null,target:"_self",expanded:false,multiExpand:true,renderHidden:false,childrenRendered:false,previousSibling:null,nextSibling:null,_dynLoad:false,dataLoader:null,isLoading:false,hasIcon:true,init:function(oData,oParent,expanded){this.data=oData;this.children=[];this.index=YAHOO.widget.TreeView.nodeCount;++YAHOO.widget.TreeView.nodeCount;this.logger=new ygLogger("Node");this.expanded=expanded;if(oParent){this.tree=oParent.tree;this.parent=oParent;this.href="javascript:"+this.getToggleLink();this.depth=oParent.depth+1;this.multiExpand=oParent.multiExpand;oParent.appendChild(this);}},appendChild:function(node){if(this.hasChildren()){var sib=this.children[this.children.length-1];sib.nextSibling=node;node.previousSibling=sib;} +this.tree.regNode(node);this.children[this.children.length]=node;return node;},getSiblings:function(){return this.parent.children;},showChildren:function(){if(!this.tree.animateExpand(this.getChildrenEl())){if(this.hasChildren()){this.getChildrenEl().style.display="";}}},hideChildren:function(){this.logger.debug("hiding "+this.index);if(!this.tree.animateCollapse(this.getChildrenEl())){this.getChildrenEl().style.display="none";}},getElId:function(){return"ygtv"+this.index;},getChildrenElId:function(){return"ygtvc"+this.index;},getToggleElId:function(){return"ygtvt"+this.index;},getEl:function(){return document.getElementById(this.getElId());},getChildrenEl:function(){return document.getElementById(this.getChildrenElId());},getToggleEl:function(){return document.getElementById(this.getToggleElId());},getToggleLink:function(){return"YAHOO.widget.TreeView.getNode(\'"+this.tree.id+"\',"+ +this.index+").toggle()";},collapse:function(){if(!this.expanded){return;} +if(!this.getEl()){this.expanded=false;return;} +this.hideChildren();this.expanded=false;if(this.hasIcon){this.getToggleEl().className=this.getStyle();} +this.tree.onCollapse(this);},expand:function(){if(this.expanded){return;} +if(!this.getEl()){this.expanded=true;return;} +if(!this.childrenRendered){this.getChildrenEl().innerHTML=this.renderChildren();} +this.expanded=true;if(this.hasIcon){this.getToggleEl().className=this.getStyle();} +if(this.isLoading){this.expanded=false;return;} +if(!this.multiExpand){var sibs=this.getSiblings();for(var i=0;i0||(checkForLazyLoad&&this.isDynamic()&&!this.childrenRendered));},toggle:function(){if(!this.tree.locked&&(this.hasChildren(true)||this.isDynamic())){if(this.expanded){this.collapse();}else{this.expand();}}},getHtml:function(){var sb=[];sb[sb.length]='
            ';sb[sb.length]=this.getNodeHtml();sb[sb.length]=this.getChildrenHtml();sb[sb.length]='
            ';return sb.join("");},getChildrenHtml:function(){var sb=[];sb[sb.length]='
            =this.depth||depth<0){this.logger.debug("illegal getAncestor depth: "+depth);return null;} +var p=this.parent;while(p.depth>depth){p=p.parent;} +return p;},getDepthStyle:function(depth){return(this.getAncestor(depth).nextSibling)?"ygtvdepthcell":"ygtvblankdepthcell";},getNodeHtml:function(){return"";}}; \ No newline at end of file diff --git a/include/ytree/TreeView/RootNode.js b/include/ytree/TreeView/RootNode.js new file mode 100644 index 00000000..f022360e --- /dev/null +++ b/include/ytree/TreeView/RootNode.js @@ -0,0 +1,2 @@ +/* Copyright (c) 2006 Yahoo! Inc. All rights reserved. */ +YAHOO.widget.RootNode=function(oTree){this.init(null,null,true);this.tree=oTree;};YAHOO.widget.RootNode.prototype=new YAHOO.widget.Node();YAHOO.widget.RootNode.prototype.getNodeHtml=function(){return"";}; \ No newline at end of file diff --git a/include/ytree/TreeView/TaskNode.js b/include/ytree/TreeView/TaskNode.js new file mode 100644 index 00000000..2997293c --- /dev/null +++ b/include/ytree/TreeView/TaskNode.js @@ -0,0 +1,28 @@ +/** + * The check box marks a task complete. It is a simulated form field + * with three states ... + * 0=unchecked, 1=some children checked, 2=all children checked + * When a task is clicked, the state of the nodes and parent and children + * are updated, and this behavior cascades. + * + * @extends YAHOO.widget.TextNode + * @constructor + * @param oData {object} A string or object containing the data that will + * be used to render this node. + * @param oParent {Node} This node's parent node + * @param expanded {boolean} The initial expanded/collapsed state + * @param checked {boolean} The initial checked/unchecked state + */ +YAHOO.widget.TaskNode=function(oData,oParent,expanded,checked){if(oData){this.init(oData,oParent,expanded);this.setUpLabel(oData);this.setUpCheck(checked);}};YAHOO.widget.TaskNode.prototype=new YAHOO.widget.TextNode();YAHOO.widget.TaskNode.prototype.checked=false;YAHOO.widget.TaskNode.prototype.checkState=0;YAHOO.widget.TaskNode.prototype.cascadeUp=false;YAHOO.widget.TaskNode.prototype.taskNodeParentChange=function(){if(this.tree&&!this.tree.hasEvent("checkClick")){this.tree.createEvent("checkClick",this.tree);}};YAHOO.widget.TaskNode.prototype.setUpCheck=function(checked){if(checked&&checked===true){this.check();} +this.taskNodeParentChange();this.subscribe("parentChange",this.taskNodeParentChange);};YAHOO.widget.TaskNode.prototype.getCheckElId=function(){return"ygtvcheck"+this.index;};YAHOO.widget.TaskNode.prototype.getCheckEl=function(){return document.getElementById(this.getCheckElId());};YAHOO.widget.TaskNode.prototype.getCheckStyle=function(){return"ygtvcheck"+this.checkState;};YAHOO.widget.TaskNode.prototype.getCheckLink=function(){return"YAHOO.widget.TreeView.getNode(\'"+this.tree.id+"\',"+ +this.index+").checkClick()";};YAHOO.widget.TaskNode.prototype.checkClick=function(){if(this.checkState===0){this.check();}else{this.uncheck();} +this.onCheckClick();this.tree.fireEvent("checkClick",this);};YAHOO.widget.TaskNode.prototype.onCheckClick=function(){};YAHOO.widget.TaskNode.prototype.updateParent=function(){var p=this.parent;if(!p||!p.updateParent){return;} +var somethingChecked=false;var somethingNotChecked=false;for(var i=0;i0);};YAHOO.widget.TaskNode.prototype.check=function(){this.setCheckState(2);for(var i=0;i ';} +sb[sb.length]=' ';sb[sb.length]='';sb[sb.length]='';sb[sb.length]=' ';sb[sb.length]='';sb[sb.length]='';sb[sb.length]='';sb[sb.length]='';sb[sb.length]='';return sb.join("");};YAHOO.widget.TaskNode.prototype.toString=function(){return"TaskNode ("+this.index+") "+this.label;}; \ No newline at end of file diff --git a/include/ytree/TreeView/TextNode.js b/include/ytree/TreeView/TextNode.js new file mode 100644 index 00000000..d63c1029 --- /dev/null +++ b/include/ytree/TreeView/TextNode.js @@ -0,0 +1,9 @@ +/* Copyright (c) 2006 Yahoo! Inc. All rights reserved. */ +YAHOO.widget.TextNode=function(oData,oParent,expanded){if(oParent){this.init(oData,oParent,expanded);this.setUpLabel(oData);}};YAHOO.widget.TextNode.prototype=new YAHOO.widget.Node();YAHOO.widget.TextNode.prototype.labelStyle="ygtvlabel";YAHOO.widget.TextNode.prototype.labelElId=null;YAHOO.widget.TextNode.prototype.label=null;YAHOO.widget.TextNode.prototype.setUpLabel=function(oData){if(typeof oData=="string"){oData={label:oData};} +this.label=oData.label;if(oData.href){this.href=oData.href;} +if(oData.target){this.target=oData.target;} +this.labelElId="ygtvlabelel"+this.index;};YAHOO.widget.TextNode.prototype.getLabelEl=function(){return document.getElementById(this.labelElId);};YAHOO.widget.TextNode.prototype.getNodeHtml=function(){var sb=new Array();sb[sb.length]='';sb[sb.length]='';for(i=0;i ';} +var getNode='YAHOO.widget.TreeView.getNode(\''+ +this.tree.id+'\','+this.index+')';sb[sb.length]=' ';sb[sb.length]='';sb[sb.length]='';sb[sb.length]='';sb[sb.length]='
            ';sb[sb.length]='';sb[sb.length]='
            ';return sb.join("");}; \ No newline at end of file diff --git a/include/ytree/TreeView/TreeView.js b/include/ytree/TreeView/TreeView.js new file mode 100644 index 00000000..ce4ad535 --- /dev/null +++ b/include/ytree/TreeView/TreeView.js @@ -0,0 +1,79 @@ +/* + Copyright (c) 2006, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + version: 0.12.0 + + 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. + */ +YAHOO.widget.TreeView=function(id){if(id){this.init(id);}};YAHOO.widget.TreeView.prototype={id:null,_el:null,_nodes:null,locked:false,_expandAnim:null,_collapseAnim:null,_animCount:0,maxAnim:2,setExpandAnim:function(type){if(YAHOO.widget.TVAnim.isValid(type)){this._expandAnim=type;}},setCollapseAnim:function(type){if(YAHOO.widget.TVAnim.isValid(type)){this._collapseAnim=type;}},animateExpand:function(el,node){if(this._expandAnim&&this._animCount ';} +var f=document.createElement("div");var s=f.style;s.position="absolute";s.top="-1000px";s.left="-1000px";f.innerHTML=sb.join("");document.body.appendChild(f);YAHOO.widget.TreeView.removeHandler(window,"load",YAHOO.widget.TreeView.preload);};YAHOO.widget.TreeView.addHandler(window,"load",YAHOO.widget.TreeView.preload);YAHOO.widget.Node=function(oData,oParent,expanded){if(oData){this.init(oData,oParent,expanded);}};YAHOO.widget.Node.prototype={index:0,children:null,tree:null,data:null,parent:null,depth:-1,href:null,target:"_self",expanded:false,multiExpand:true,renderHidden:false,childrenRendered:false,dynamicLoadComplete:false,previousSibling:null,nextSibling:null,_dynLoad:false,dataLoader:null,isLoading:false,hasIcon:true,iconMode:0,_type:"Node",init:function(oData,oParent,expanded){this.data=oData;this.children=[];this.index=YAHOO.widget.TreeView.nodeCount;++YAHOO.widget.TreeView.nodeCount;this.expanded=expanded;this.createEvent("parentChange",this);if(oParent){oParent.appendChild(this);}},applyParent:function(parentNode){if(!parentNode){return false;} +this.tree=parentNode.tree;this.parent=parentNode;this.depth=parentNode.depth+1;if(!this.href){this.href="javascript:"+this.getToggleLink();} +if(!this.multiExpand){this.multiExpand=parentNode.multiExpand;} +this.tree.regNode(this);parentNode.childrenRendered=false;for(var i=0,len=this.children.length;i0||(checkForLazyLoad&&this.isDynamic()&&!this.dynamicLoadComplete));},toggle:function(){if(!this.tree.locked&&(this.hasChildren(true)||this.isDynamic())){if(this.expanded){this.collapse();}else{this.expand();}}},getHtml:function(){this.childrenRendered=false;var sb=[];sb[sb.length]='
            ';sb[sb.length]=this.getNodeHtml();sb[sb.length]=this.getChildrenHtml();sb[sb.length]='
            ';return sb.join("");},getChildrenHtml:function(){var sb=[];sb[sb.length]='
            =this.depth||depth<0){return null;} +var p=this.parent;while(p.depth>depth){p=p.parent;} +return p;},getDepthStyle:function(depth){return(this.getAncestor(depth).nextSibling)?"ygtvdepthcell":"ygtvblankdepthcell";},getNodeHtml:function(){return"";},refresh:function(){this.getChildrenEl().innerHTML=this.completeRender();if(this.hasIcon){var el=this.getToggleEl();if(el){el.className=this.getStyle();}}},toString:function(){return"Node ("+this.index+")";}};YAHOO.augment(YAHOO.widget.Node,YAHOO.util.EventProvider);YAHOO.widget.RootNode=function(oTree){this.init(null,null,true);this.tree=oTree;};YAHOO.extend(YAHOO.widget.RootNode,YAHOO.widget.Node,{getNodeHtml:function(){return"";},toString:function(){return"RootNode";},loadComplete:function(){this.tree.draw();}});YAHOO.widget.TextNode=function(oData,oParent,expanded){if(oData){this.init(oData,oParent,expanded);this.setUpLabel(oData);}};YAHOO.extend(YAHOO.widget.TextNode,YAHOO.widget.Node,{labelStyle:"ygtvlabel",labelElId:null,label:null,textNodeParentChange:function(){if(this.tree&&!this.tree.hasEvent("labelClick")){this.tree.createEvent("labelClick",this.tree);}},setUpLabel:function(oData){this.textNodeParentChange();this.subscribe("parentChange",this.textNodeParentChange);if(typeof oData=="string"){oData={label:oData};} +this.label=oData.label;if(oData.href){this.href=oData.href;} +if(oData.target){this.target=oData.target;} +if(oData.style){this.labelStyle=oData.style;} +this.labelElId="ygtvlabelel"+this.index;},getLabelEl:function(){return document.getElementById(this.labelElId);},getNodeHtml:function(){var sb=[];sb[sb.length]='';sb[sb.length]='';for(var i=0;i ';} +var getNode='YAHOO.widget.TreeView.getNode(\''+ +this.tree.id+'\','+this.index+')';sb[sb.length]='';sb[sb.length]=' ';sb[sb.length]='';sb[sb.length]='';sb[sb.length]='';sb[sb.length]='
            ';sb[sb.length]='';sb[sb.length]='
            ';return sb.join("");},onLabelClick:function(me){return me.tree.fireEvent("labelClick",me);},toString:function(){return"TextNode ("+this.index+") "+this.label;}});YAHOO.widget.MenuNode=function(oData,oParent,expanded){if(oData){this.init(oData,oParent,expanded);this.setUpLabel(oData);} +this.multiExpand=false;};YAHOO.extend(YAHOO.widget.MenuNode,YAHOO.widget.TextNode,{toString:function(){return"MenuNode ("+this.index+") "+this.label;}});YAHOO.widget.HTMLNode=function(oData,oParent,expanded,hasIcon){if(oData){this.init(oData,oParent,expanded);this.initContent(oData,hasIcon);}};YAHOO.extend(YAHOO.widget.HTMLNode,YAHOO.widget.Node,{contentStyle:"ygtvhtml",contentElId:null,content:null,initContent:function(oData,hasIcon){if(typeof oData=="string"){oData={html:oData};} +this.html=oData.html;this.contentElId="ygtvcontentel"+this.index;this.hasIcon=hasIcon;},getContentEl:function(){return document.getElementById(this.contentElId);},getNodeHtml:function(){var sb=[];sb[sb.length]='';sb[sb.length]='';for(var i=0;i ';} +if(this.hasIcon){sb[sb.length]='';sb[sb.length]='';sb[sb.length]='
            ';return sb.join("");},toString:function(){return"HTMLNode ("+this.index+")";}});YAHOO.widget.TVAnim=function(){return{FADE_IN:"TVFadeIn",FADE_OUT:"TVFadeOut",getAnim:function(type,el,callback){if(YAHOO.widget[type]){return new YAHOO.widget[type](el,callback);}else{return null;}},isValid:function(type){return(YAHOO.widget[type]);}};}();YAHOO.widget.TVFadeIn=function(el,callback){this.el=el;this.callback=callback;};YAHOO.widget.TVFadeIn.prototype={animate:function(){var tvanim=this;var s=this.el.style;s.opacity=0.1;s.filter="alpha(opacity=10)";s.display="";var dur=0.4;var a=new YAHOO.util.Anim(this.el,{opacity:{from:0.1,to:1,unit:""}},dur);a.onComplete.subscribe(function(){tvanim.onComplete();});a.animate();},onComplete:function(){this.callback();},toString:function(){return"TVFadeIn";}};YAHOO.widget.TVFadeOut=function(el,callback){this.el=el;this.callback=callback;};YAHOO.widget.TVFadeOut.prototype={animate:function(){var tvanim=this;var dur=0.4;var a=new YAHOO.util.Anim(this.el,{opacity:{from:1,to:0.1,unit:""}},dur);a.onComplete.subscribe(function(){tvanim.onComplete();});a.animate();},onComplete:function(){var s=this.el.style;s.display="none";s.filter="alpha(opacity=100)";this.callback();},toString:function(){return"TVFadeOut";}}; \ No newline at end of file diff --git a/include/ytree/TreeView/anim/TVAnim.js b/include/ytree/TreeView/anim/TVAnim.js new file mode 100644 index 00000000..4d95d697 --- /dev/null +++ b/include/ytree/TreeView/anim/TVAnim.js @@ -0,0 +1,2 @@ +/* Copyright (c) 2006 Yahoo! Inc. All rights reserved. */ +YAHOO.widget.TVAnim=new function(){this.FADE_IN="YAHOO.widget.TVFadeIn";this.FADE_OUT="YAHOO.widget.TVFadeOut";this.getAnim=function(type,el,callback){switch(type){case this.FADE_IN:return new YAHOO.widget.TVFadeIn(el,callback);case this.FADE_OUT:return new YAHOO.widget.TVFadeOut(el,callback);default:return null;}};this.isValid=function(type){return("undefined"!=eval("typeof "+type));};}; \ No newline at end of file diff --git a/include/ytree/TreeView/anim/TVFadeIn.js b/include/ytree/TreeView/anim/TVFadeIn.js new file mode 100644 index 00000000..dd067fd9 --- /dev/null +++ b/include/ytree/TreeView/anim/TVFadeIn.js @@ -0,0 +1,2 @@ +/* Copyright (c) 2006 Yahoo! Inc. All rights reserved. */ +YAHOO.widget.TVFadeIn=function(el,callback){this.el=el;this.callback=callback;this.logger=new ygLogger("TVFadeIn");};YAHOO.widget.TVFadeIn.prototype={animate:function(){var tvanim=this;var s=this.el.style;s.opacity=0.1;s.filter="alpha(opacity=10)";s.display="";var dur=0.4;var a=new YAHOO.util.Anim(this.el,{opacity:{from:0.1,to:1,unit:""}},dur);a.onComplete.subscribe(function(){tvanim.onComplete();});a.animate();},onComplete:function(){this.callback();}}; \ No newline at end of file diff --git a/include/ytree/TreeView/anim/TVFadeOut.js b/include/ytree/TreeView/anim/TVFadeOut.js new file mode 100644 index 00000000..8ff5e524 --- /dev/null +++ b/include/ytree/TreeView/anim/TVFadeOut.js @@ -0,0 +1,2 @@ +/* Copyright (c) 2006 Yahoo! Inc. All rights reserved. */ +YAHOO.widget.TVFadeOut=function(el,callback){this.el=el;this.callback=callback;this.logger=new ygLogger("TVFadeOut");};YAHOO.widget.TVFadeOut.prototype={animate:function(){var tvanim=this;var dur=0.4;var a=new YAHOO.util.Anim(this.el,{opacity:{from:1,to:0.1,unit:""}},dur);a.onComplete.subscribe(function(){tvanim.onComplete();});a.animate();},onComplete:function(){var s=this.el.style;s.display="none";s.filter="alpha(opacity=100)";this.callback();}}; \ No newline at end of file diff --git a/include/ytree/TreeView/css/check/tree.css b/include/ytree/TreeView/css/check/tree.css new file mode 100644 index 00000000..26cb743a --- /dev/null +++ b/include/ytree/TreeView/css/check/tree.css @@ -0,0 +1 @@ +/* Copyright (c) 2006 Yahoo! Inc. All rights reserved. */ /* first or middle sibling, no children */ .ygtvtn {background: url(../../img/folders/tn.gif) 0 0 no-repeat; width:16px; height:22px; } /* first or middle sibling, collapsable */ .ygtvtm {background: url(../../img/folders/tm.gif) 0 0 no-repeat; width:16px; height:22px; cursor:pointer } /* first or middle sibling, collapsable, hover */ .ygtvtmh {background: url(../../img/folders/tmh.gif) 0 0 no-repeat; width:16px; height:22px; cursor:pointer } /* first or middle sibling, expandable */ .ygtvtp {background: url(../../img/folders/tp.gif) 0 0 no-repeat; width:16px; height:22px; cursor:pointer } /* first or middle sibling, expandable, hover */ .ygtvtph {background: url(../../img/folders/tph.gif) 0 0 no-repeat; width:16px; height:22px; cursor:pointer } /* last sibling, no children */ .ygtvln {background: url(../../img/folders/ln.gif) 0 0 no-repeat; width:16px; height:22px; } /* Last sibling, collapsable */ .ygtvlm {background: url(../../img/folders/lm.gif) 0 0 no-repeat; width:16px; height:22px; cursor:pointer } /* Last sibling, collapsable, hover */ .ygtvlmh {background: url(../../img/folders/lmh.gif) 0 0 no-repeat; width:16px; height:22px; cursor:pointer } /* Last sibling, expandable */ .ygtvlp { background: url(../../img/folders/lp.gif) 0 0 no-repeat; width:16px; height:22px; cursor:pointer } /* Last sibling, expandable, hover */ .ygtvlph { background: url(../../img/folders/lph.gif) 0 0 no-repeat; width:16px; height:22px; cursor:pointer } /* Loading icon */ .ygtvloading { background: url(../../img/check/loading.gif) 0 0 no-repeat; width:16px; height:22px; } /* the style for the empty cells that are used for rendering the depth * of the node */ .ygtvdepthcell { background: url(../../img/check/vline.gif) 0 0 no-repeat; width:16px; height:22px; } .ygtvblankdepthcell { width:16px; height:22px; } /* the style of the div around each node */ .ygtvitem { } /* the style of the div around each node's collection of children */ .ygtvchildren { } * html .ygtvchildren { height:1%; } /* the style of the text label in ygTextNode */ .ygtvlabel, .ygtvlabel:link, .ygtvlabel:visited, .ygtvlabel:hover { text-decoration: none; } .ygtvcheck0 { background: url(../../img/check/check0.gif) 0 0 no-repeat; width:16px; height:22px; cursor:pointer } .ygtvcheck1 { background: url(../../img/check/check1.gif) 0 0 no-repeat; width:16px; height:22px; cursor:pointer } .ygtvcheck2 { background: url(../../img/check/check2.gif) 0 0 no-repeat; width:16px; height:22px; cursor:pointer } \ No newline at end of file diff --git a/include/ytree/TreeView/css/default/tree.css b/include/ytree/TreeView/css/default/tree.css new file mode 100644 index 00000000..effce510 --- /dev/null +++ b/include/ytree/TreeView/css/default/tree.css @@ -0,0 +1,97 @@ +/* Copyright (c) 2006 Yahoo! Inc. All rights reserved. */ + +/* first or middle sibling, no children */ +.ygtvtn { + width:16px; height:22px; + background: url(../../img/default/tn.gif) 0 0 no-repeat; +} + +/* first or middle sibling, collapsable */ +.ygtvtm { + width:16px; height:22px; + cursor:pointer ; + background: url(../../img/default/tm.gif) 0 0 no-repeat; +} + +/* first or middle sibling, collapsable, hover */ +.ygtvtmh { + width:16px; height:22px; + cursor:pointer ; + background: url(../../img/default/tmh.gif) 0 0 no-repeat; +} + +/* first or middle sibling, expandable */ +.ygtvtp { + width:16px; height:22px; + cursor:pointer ; + background: url(../../img/default/tp.gif) 0 0 no-repeat; +} + +/* first or middle sibling, expandable, hover */ +.ygtvtph { + width:16px; height:22px; + cursor:pointer ; + background: url(../../img/default/tph.gif) 0 0 no-repeat; +} + +/* last sibling, no children */ +.ygtvln { + width:16px; height:22px; + background: url(../../img/default/ln.gif) 0 0 no-repeat; +} + +/* Last sibling, collapsable */ +.ygtvlm { + width:16px; height:22px; + cursor:pointer ; + background: url(../../img/default/lm.gif) 0 0 no-repeat; +} + +/* Last sibling, collapsable, hover */ +.ygtvlmh { + width:16px; height:22px; + cursor:pointer ; + background: url(../../img/default/lmh.gif) 0 0 no-repeat; +} + +/* Last sibling, expandable */ +.ygtvlp { + width:16px; height:22px; + cursor:pointer ; + background: url(../../img/default/lp.gif) 0 0 no-repeat; +} + +/* Last sibling, expandable, hover */ +.ygtvlph { + width:17px; height:22px; cursor:pointer ; + background: url(../../img/default/lph.gif) 0 0 no-repeat; +} + +/* Loading icon */ +.ygtvloading { + width:16px; height:22px; + background: url(../../img/default/loading.gif) 0 0 no-repeat; +} + +/* the style for the empty cells that are used for rendering the depth + * of the node */ +.ygtvdepthcell { + width:16px; height:22px; + background: url(../../img/default/vline.gif) 0 0 no-repeat; +} + +.ygtvblankdepthcell { width:16px; height:22px; } + +/* the style of the div around each node */ +.ygtvitem { } + +/* the style of the div around each node's collection of children */ +.ygtvchildren { } +* html .ygtvchildren { height:2%; } + +/* the style of the text label in ygTextNode */ +.ygtvlabel, .ygtvlabel:link, .ygtvlabel:visited, .ygtvlabel:hover { + margin-left:2px; + text-decoration: none; +} + diff --git a/include/ytree/TreeView/css/folders/tree.css b/include/ytree/TreeView/css/folders/tree.css new file mode 100644 index 00000000..5f3b26ff --- /dev/null +++ b/include/ytree/TreeView/css/folders/tree.css @@ -0,0 +1,55 @@ +/* Copyright (c) 2006 Yahoo! Inc. All rights reserved. */ + +/* first or middle sibling, no children */ +.ygtvtn { background: url(../../img/folders/tn.gif) 0 0 no-repeat; width:17px; height:22px; } + +/* first or middle sibling, collapsable */ +.ygtvtm { background: url(../../img/folders/tm.gif) 0 0 no-repeat; width:34px; height:22px; cursor:pointer } + +/* first or middle sibling, collapsable, hover */ +.ygtvtmh { background: url(../../img/folders/tmh.gif) 0 0 no-repeat; width:34px; height:22px; cursor:pointer } + +/* first or middle sibling, expandable */ +.ygtvtp { background: url(../../img/folders/tp.gif) 0 0 no-repeat; width:34px; height:22px; cursor:pointer } + +/* first or middle sibling, expandable, hover */ +.ygtvtph { background: url(../../img/folders/tph.gif) 0 0 no-repeat; width:34px; height:22px; cursor:pointer } + +/* last sibling, no children */ +.ygtvln { background: url(../../img/folders/ln.gif) 0 0 no-repeat; width:17px; height:22px; } + +/* Last sibling, collapsable */ +.ygtvlm { background: url(../../img/folders/lm.gif) 0 0 no-repeat; width:34px; height:22px; cursor:pointer } + +/* Last sibling, collapsable, hover */ +.ygtvlmh { background: url(../../img/folders/lmh.gif) 0 0 no-repeat; width:34px; height:22px; cursor:pointer } + +/* Last sibling, expandable */ +.ygtvlp { background: url(../../img/folders/lp.gif) 0 0 no-repeat; width:34px; height:22px; cursor:pointer } + +/* Last sibling, expandable, hover */ +.ygtvlph { background: url(../../img/folders/lph.gif) 0 0 no-repeat; width:34px; height:22px; cursor:pointer } + +/* Loading icon */ +.ygtvloading { background: url(../../img/folders/loading.gif) 0 0 no-repeat; width:16px; height:22px; } + +/* the style for the empty cells that are used for rendering the depth + * of the node */ +.ygtvdepthcell { background: url(../../img/folders/vline.gif) 0 0 no-repeat; width:17px; height:22px; } + +.ygtvblankdepthcell { width:17px; height:22px; } + +/* the style of the div around each node */ +.ygtvitem { } + +/* the style of the div around each node's collection of children */ +.ygtvchildren { } +* html .ygtvchildren { height:1%; } + +/* the style of the text label in ygTextNode */ +.ygtvlabel, .ygtvlabel:link, .ygtvlabel:visited, .ygtvlabel:hover { + margin-left:2px; + text-decoration: none; +} + + diff --git a/include/ytree/TreeView/css/forecasts/tree.css b/include/ytree/TreeView/css/forecasts/tree.css new file mode 100644 index 00000000..5f3b26ff --- /dev/null +++ b/include/ytree/TreeView/css/forecasts/tree.css @@ -0,0 +1,55 @@ +/* Copyright (c) 2006 Yahoo! Inc. All rights reserved. */ + +/* first or middle sibling, no children */ +.ygtvtn { background: url(../../img/folders/tn.gif) 0 0 no-repeat; width:17px; height:22px; } + +/* first or middle sibling, collapsable */ +.ygtvtm { background: url(../../img/folders/tm.gif) 0 0 no-repeat; width:34px; height:22px; cursor:pointer } + +/* first or middle sibling, collapsable, hover */ +.ygtvtmh { background: url(../../img/folders/tmh.gif) 0 0 no-repeat; width:34px; height:22px; cursor:pointer } + +/* first or middle sibling, expandable */ +.ygtvtp { background: url(../../img/folders/tp.gif) 0 0 no-repeat; width:34px; height:22px; cursor:pointer } + +/* first or middle sibling, expandable, hover */ +.ygtvtph { background: url(../../img/folders/tph.gif) 0 0 no-repeat; width:34px; height:22px; cursor:pointer } + +/* last sibling, no children */ +.ygtvln { background: url(../../img/folders/ln.gif) 0 0 no-repeat; width:17px; height:22px; } + +/* Last sibling, collapsable */ +.ygtvlm { background: url(../../img/folders/lm.gif) 0 0 no-repeat; width:34px; height:22px; cursor:pointer } + +/* Last sibling, collapsable, hover */ +.ygtvlmh { background: url(../../img/folders/lmh.gif) 0 0 no-repeat; width:34px; height:22px; cursor:pointer } + +/* Last sibling, expandable */ +.ygtvlp { background: url(../../img/folders/lp.gif) 0 0 no-repeat; width:34px; height:22px; cursor:pointer } + +/* Last sibling, expandable, hover */ +.ygtvlph { background: url(../../img/folders/lph.gif) 0 0 no-repeat; width:34px; height:22px; cursor:pointer } + +/* Loading icon */ +.ygtvloading { background: url(../../img/folders/loading.gif) 0 0 no-repeat; width:16px; height:22px; } + +/* the style for the empty cells that are used for rendering the depth + * of the node */ +.ygtvdepthcell { background: url(../../img/folders/vline.gif) 0 0 no-repeat; width:17px; height:22px; } + +.ygtvblankdepthcell { width:17px; height:22px; } + +/* the style of the div around each node */ +.ygtvitem { } + +/* the style of the div around each node's collection of children */ +.ygtvchildren { } +* html .ygtvchildren { height:1%; } + +/* the style of the text label in ygTextNode */ +.ygtvlabel, .ygtvlabel:link, .ygtvlabel:visited, .ygtvlabel:hover { + margin-left:2px; + text-decoration: none; +} + + diff --git a/include/ytree/TreeView/img/bullet.gif b/include/ytree/TreeView/img/bullet.gif new file mode 100644 index 0000000000000000000000000000000000000000..9d28c2f6aa75cfb4dbdff60fbac60130fe88a5d3 GIT binary patch literal 172 zcmZ?wbhEHbiA_^35yCG=nM*V^-Y&L?h$mWymZSRuEmL)9C;?rN?A}amE~Lz2ZJ>L D!_Y=` literal 0 HcmV?d00001 diff --git a/include/ytree/TreeView/img/check/Thumbs.db b/include/ytree/TreeView/img/check/Thumbs.db new file mode 100644 index 0000000000000000000000000000000000000000..b5281bfef0bfd33064dab822333a3f838a2cf9eb GIT binary patch literal 18432 zcmeI32_RM5`oOn2L!rzKDx`@F2Pt)mkR+ifLy|dDqRfs)t|5t1R3}43;busKAqizj z=A<%}q727)qI35D+c@3o-rMcgd-uKG-{NPTv)8xwTHo61`_{0R$CcbIG1rA!kuSnp zgaM(VtO)Zb*XiIh#(3aD5PJB4K}At?;v#~;$EolWwEzX`$_5XQ7hnXK0PLBw0Mh_g zfE}0#Z~)VR82~2$T>#+*W&v{m9)J(P`U5}20)QYO1k48J0$AESh=qaqzye?)fL)&o z|9lJRB2Mt*3eQ3nafEn3;sHR0|?!fpOBRPT83{( zV?^lbXys$^H)I(X5ym<_1Qo;#v^GQRp%ttrF8!^)T;Ku!Zuv`~gq4`%gdj5!efM8X zf6OOiw)?I6F9X?C*h7GT<;ALkef=~0$C?WB0e@!ym~X&*0A~M~AHjUUAK5?VBQPKE zNA@oQ*F^y_U=bh=ECw*YuoU7mz;ZwWkOWo$QUKO}ur`zhaDW_ubu9$|%c}_SDquCB z1grtp0(f8@upUqbRDcZtmPZX@bzmc)0c-*^fz5yxum#WtwgNhUE`a6R2Jv=4A20xR z06PIgzz8q~On_a0DX<&B^6i1x9IyZ^0V@FOi#C8Quotic>;VS=%i{#`KEN5+54ZrX zzyaVO;0Cw@m^FI>UI3QQ2V!4<0QdpeGsXJAEO^N16SM{4+N7qThR{K$+Kp8ZZGxs@ zpr^-vAuz%((=;X~Mn)z!78d4d9BdpM>}>4p(`U@&nm&Vj20J?!9~bv59$sEv4o-dn zJ|2OYJiI*EP3RaP4>!W@7D~s!K+nj4)f%LIARS@kW}3M`dOhfQL%CHmlG1NBqgV3WMg=|xBH1~70lGA)p1p1EF!#msruLYYI;c$C9pt{1S1$m;g-?%7|(#wUtv z6(eD)jcfL8iXHwg%|0sjn_f>54hA}ScnsWNfD~a;WvIm9nqjFf`P;7T^ghbnk)>JB zWRe-U=IPHl_K3&3qKxK<=!liH@3 z^h{CCbsHJmQ<*(ETzA=`$in=&X zyY?1Y>1tgw&K&BA9Pl`DVHt{W_M^zlEj-@(HLi-($4W+t$vfI|x%o?#YP#PWm~gbq#>`L+$iJpX@CxI6 zqG_N_%6=JEgd&B??gXk&Jc<+~oI{a^u7ocx9C+%H*wlY{K>Nyvt8rsqP-o&>6dcTl zlehMv$Ura2nioZ;v$mqh`{8gDVUDs!5wWV@Uuv++4Uh=)a}L(&AnLr|o--g9sMTPI zBF>%!g_9}J97ICU%Cs*uxUJ3Rty%58bGgo4p{E)_%NJ_2oVK(Sv@|%b!M{&fzIy$9 zY2=u_4OYWcJEN?l%>AG(1rJ2qbqfe}gYGx%`;dfpZI?WTe zL``CUQ=6?LQS(Tmvh!Z4j0~@4%l!@uuD1~cQRIp43d(}4l#@e85^gl}kRK3gCoT|V zayZOU#4e4hh$5Yv>x#S92K8?k>+Hvu36JI1)|tx0pQdiie~u!JA=VmWr`Oob)~cQjBNO+UDxNcFkeIQNn&-;Eg^ zUbPwco|e~SPU_LUq386p#d}in-$HMA9F-AIDZNM>bJf^aM=)XO9f>34>JKa)SQhna zKcCxJRsM^s9uXc9#)|BvDDozK4vGk&$f7Gbm7aSZQvH{pNWw24qGAS?C0rd@GD_$! zKU-)(ab5oY;!wDEBPsH531x#7RAgDyoeq7=vK~_6VHA0{K!F-&TyqaUd|P;^p9rd* zcM$Z{>^EoVCiw^B--+>4!wl;xgTrSl$y%ExYc92z`6qGk#N=H;^0N=T>cp<>rL{CmQAXR%DHa~)3Id^&WG9(q(;G?-Z74D}O%*zW zel3MMv~q;nH2EZJ)D$jr_LcOjhRR%foW0XS}wBsCYBMh3?ZzJB) zt3eURUvy7gAEF2}Lr1*oG!p0IVq6oE(V^3^-GMrIXW&Ip(8;P06lvRuryLALk@cP_ z9eQyD^66)U2Aljr!KJCAofBHR1_U37OnVbF&r(0z=f&zi8_*IO610r;7`kF_v~~^X zM$m@py7BH1r#6C(r$s>e&A@98n-a;E@1<|Yh?LBegv(^YVBph`judiSp|40L>0p+d zc}&?=!@aZAUFO_q;969^o<~(cW8vJ!fQxhjW{>tWyA4|h5#DI$p~&4kcq-n+<2a|_ z(9`a%(OX<>uV^HkkJiFnQ(CikZ83imZ*13{6*3ORsk^R^$wQkPb5esnE2!lpCkpFG zGnpU!RY{j^w~`S~A8J3%vj4qwL}k*FgI7fq;gceK!ogK3 zNR@!^3LuH4${;J@2m3A!S2m1)SB6j6%ynYV09&sh23-UFj>UAe`Ku(u&oO`HL%62q zujBLbpMU-;Kt9&~CUdrl@BJq)1m0za6Fib7igI(af+ZKx?-V`N!MrtZbMU70ZuSdh zwGL#jqLkFV*`p4{Ay;e~ZtN@ES7nNuo~LNIT{l6{Vy>C@;q{$wcWob2`5=0moN?K` zvaouGyI-T-3*k`h?Apw^8;yJ}wn+5PQrgq=?AZpUYUx8|s*9uw51oj-JC8};@OT_g zl+!P`3u3r2J58(l1Mi(ySUQWn-DKEeqP5IV@_4h1c0_kmsKh?HE*>3Kgg`TGY~B1L z;d}O9RziV_V6Rxf*6cqLu=256Vf&P@yoHJHUk6nXahNP0+b{T$@ICtLL4gM*%g6RA zek5S!WBaw(UhTK)Zw9imljYO=rv!Ze8P@+({*$(^@$>sn@f;F4bVq*8AcaM*epf;L zvUAs7)QM;aGQ6V$OeFs~j%_^^*&Hh_|AY zS-0hF=VHjb=$9%o#9^Tv_GL88`T z&Y@=yzSZm-QEq^ZCSfw`5JkD3IwYq^@UXM5uevT@)4o^s7UL4d_o2$}o$KbcxA!*Q zX|*m|V?Ab6^aANak$^0%n6-^pc8H!j32zES#Qj)W)&1~Ry~l`bL!sSH)7%*fsdMY( zBgU+Vd%{ZT1m;T#&Y6i9T6~G~qs@IfUed-d+bR2-vcLaU`(t(|w5R%~lFyW=c+FMO z%FR99;`iKRM#$3pmi?8dmz_2j%9wtao@JMsuPu2b-dj1kh>FW4J3C)qo5GhiyV5LK z#Qvsf`dxWeI!crI^iwnTu?SWeP%h+gX!nH|?V1rdW^k*1C`83LTDMMacD7h*uSG_f zMVLWsY8|rpP4cRK8-~tiVc&{o_O(mi;-9{d>|^o&pqlK!I$WV#AR6I^AlC(z5Ima_ z-I#*+a!f+}f?6S|_)x_ubIBp5+&LHZm4(3qI8#mFF^x7Ibg;F5`Y2!G z)w@*DTw6_J_N2@Em>xHEX!KvWz_Sf(e@874^-~T)7Z%*hTT@+!51Ajb zl2sQJ>)Gwy!H-|Sh)CT%AEM3Zz0tq;c0y7jVNaK*LE7VWiJD0kyP2xH2ZUd(KGDjsnMk z2nIrc6F?{c3pgYUI0b|Q5x{8x%NGgpS>PNH1rz}1feXMzfCyXy zVt`m64u}UX0|`JPa0S5bl??G!;2MwuqylNcufTO69moJO0Zje|#M!`2;1+NjxC7(> zxj-I}58MSX`9}~J0{4L;pcp6t9sm!4QlJbd2Pyz855{BoTm@7EH9##;2h;-%z!RVm zcnVfBBG+XzjW~_*Q`7ZrjPNi&F<5BU|IS+>08_G8md^|%8 zkM}gLaInfg`QUna$ZP=%n`iV=2XCJ&^_e#R#HBjc964Kj^lgWA9?=6Cx;Kp-2V8gu=Gt<__%7OrGEDT6m1ks#tA{)MBzFsiAx_pN8fKb!k!`!o9QCgcG zn1u&w9~~ib=1KWhuWGozg3V_1Op=S)<%A33!JAW~9Lh3W7^Q!m-N?J&!c=$lW0o3z z{gbA5`-}_c-j|fBDm`>M?-EJF*4)XAai3uUZzgxJ=+;ZBrkCch{eE!=e*dq6J)Gi| zgwwvZCXmM_w6K9iUasn}acT1ocs{{)}jVJReGZ)tx^cY<^G7NEH! z=>MrCRubK^fkJS)8)deR&Hoysx7LH!M2haP|?+19>CGU-L8I;4JDH+4yMi z+~sXc&CaZ^XL%qx?_yTFX%>HhiFw<*i%Y6^S088`q}Uby+WEL^)uQ+_&DJ-C9ra$T zId+$m4!H)K?WxMcj)27d=hjd(`)i{AIpz<$5&Eg~SD&1}lKvO$KYhBc!JP76g(MJo z4gCcRGCyAa_&az`xEEHB@tgj|pDajkn=D`UUr_$v)&Cxp|8lZ?+>e(}Hv{g6-R@iU zuLRlWljZ-+|39)OsPN1@UEdzl+xS;)+SH|iHU1P`!tKS$9X>@CTqu&PJ)+8^N=?E) z=h+s#07bSDdjc0vh+LvyF{D9#6B|IN6CZhtR*}qi@QqPiJux!yj{HqKU3E@3B(QEytO?2volRX}p=<>0&)co--PwVlt)Cqf_ z<)x)Ee5LDy7eSDTQ`oMsTKIg1J|EIB+n~+%F^NxS@L2kEfM!2WrtD{G{{9co-c7;>mzyob0p(XQACgVR(o)~C;%RQO= z@uW3$_CE?oXAfcPeAh4b0p^1&Hm)Nd(?4HLV@X(`*-zD!{Y=@L<>7{JuuA8LXB0|b_vzyJUM literal 0 HcmV?d00001 diff --git a/include/ytree/TreeView/img/check/check0.gif b/include/ytree/TreeView/img/check/check0.gif new file mode 100644 index 0000000000000000000000000000000000000000..193028b99361c6527f17a9056037f3d8729fada7 GIT binary patch literal 608 zcmZ?wbhEHb6krfzc;>|L^y$-=FJFHD{{8v$=l}lwYiw-%_U+rNSFb*Q{ycHwL|t9o z4nyho27-Mo48_U+qq=FHi!VMBd=eR6X0+O=zU@7{g=`t?<-R$aV!QBO~=si|q# zu3gWbJ!@`mzI^%e$A3uKV-Me@C^y%BTZ(p%u#nr1TIw0qR;)H>HZ-Y})b4zPm zdq-zicTcmUtRf$uChJr_107k%CMHe`N0x;P`5omrrJC4T89CNEtasp8#oolg$!xcC z*G^_mh9((lImRPL*@bMRWts#ebZswOyr3>2&}6S{Yk&KWy@0BkeG`wFo;Jga7tBID z3Or5XCSs!Nxxa8b*r|v&i3p1^@tiSGSg@dh)kuRwD&VlggmwY>tRDsr6B@;pN)`kN kI5!@bwak+c_`=}P#wi$N7O_%^c>;TH(y2L>8UhT~0GYwkU;qFB literal 0 HcmV?d00001 diff --git a/include/ytree/TreeView/img/check/check1.gif b/include/ytree/TreeView/img/check/check1.gif new file mode 100644 index 0000000000000000000000000000000000000000..181317599bfd45f03a7a69784b232509171d98e9 GIT binary patch literal 609 zcmZ?wbhEHb6krfzc;?HnW5@{Q2|Z;^P1R|37;4=+mc9 z2M!#ludjdl^y!^DcW&Oi`QX8Wd-v|GTD9u_{rlg(eY<=2?(*f!7cE+}Zr!@3rlz#C zw93lLty{Ntbad?6wX3|me9f9QU0q#_jEvpg-8D5erKP3o*RL-ssmjjIK6B=bk&#hr zYwM9CN4|dj+Sb-)XlVHT`}dxnp5w=lFIlo=!GZ+|z~IZE19BTEP8ittHTX6)x3spkcXW1j_cTk$%W!aLa!=*3 zc9)lEa$s@xW?Hz=(p!newn>g(hVaPYrXndu(oIuG-2?s&?!;%&%Yb2pGtyHpw{(Nw4Sq&g@>2*tTt3LPEl(O`BR;T8=%(xpqq#l;5>99Xq#)&2YTYiepbIy&0g+AOW@ zckS9Guc-F@`}d~imPLyeZQs6~fsu`YfvK{pX2F65U0q$Rt*sL$O-@Ws1A@}h((LT) z?(XjO>(?(?vSiJgH4`UJK6B=bk&)5y`M-)|l9Y<;$0E z*|Mdlr)S-|b(NKs3l=PFZf@Sadv|qB-H{_lmMvRWUS2+J+H@9n9wt`q{DLAwL&J0D z&M`1B06hgHX$=&AvM@3*#4+fAECR&|1N-TQIAB<`wzYS3c6IkOiz~=+aJchM|1mCdzDLXw4hE#vxNR(VN@CJ{DPhF!b7VuM)OM4A+ZRauU+7{|s2 zcnd2w$tde{Md^hbMtE?UD9bddsdKr+>S#rp``L#2t2OayvU`dd#ftf`8raM6HSzlj zc(5=uIVZF*Fl5;XgfOzUFmkr3NH`Qau*iwBl%AN_(0#mLZsnU73LZ^-il>A0j5i(a fVsVr<>G*MA!L!EM+AbM4F05F7ettU>BZD;n{1fhr literal 0 HcmV?d00001 diff --git a/include/ytree/TreeView/img/check/lm.gif b/include/ytree/TreeView/img/check/lm.gif new file mode 100644 index 0000000000000000000000000000000000000000..e7d0a3ce92eb825a95ca188133567cd4f8f31499 GIT binary patch literal 94 zcmZ?wbhEHb6krfzn8?8J|NsAnh6V;OL-8jIs|W)#gAS0(0Fq~5(x216Qtb79sX3ZA us+DiZoVZmeFVu3oV#=XiRnDKMs-2p#PO1G%cj6U(9b}?;FOZ literal 0 HcmV?d00001 diff --git a/include/ytree/TreeView/img/check/ln.gif b/include/ytree/TreeView/img/check/ln.gif new file mode 100644 index 0000000000000000000000000000000000000000..b7b3e55cd044af047e571b8e46d99dd4b801ee60 GIT binary patch literal 142 zcmZ?wbhEHb6krfz*v!Dt(9rPz|9=MJ08pjkPZmZ727U&`e=?ytsfj5H?w)Q6!MTY= zCBcbhsYME5Ky0LEz@P&%5oCu0i}Z(+o~!p-ygs}8e}YEQf$*yI>683lZcElVAIHLA F4FFl;B{Tp4 literal 0 HcmV?d00001 diff --git a/include/ytree/TreeView/img/check/loading.gif b/include/ytree/TreeView/img/check/loading.gif new file mode 100644 index 0000000000000000000000000000000000000000..0bbf3bc0c0e5e635553e8d1bf9ceddefbc402396 GIT binary patch literal 2673 zcmchY_gj;P7RTSb83YJ1>=8y5ONL=ZcEgk+C?FydumNNz8c=c6`n&|fmMu_HHG%^w zNLVjHyfy)hAgHK_Kxkz+0Ktm5M|X*?y?g!o_3yv`{_^F^wY9YuFJ3GxEUd1s-nnz<)vH(c?%i8n zUVirM+2rIT007UQKY#e};oRKZty{MqJa}MhYina;bNBAu-+udTYHDhBcJ|n@WA*j* z-+lL;iHS*OX6D|#dm|zu!o$ON?b=mbT)bh!26uP&kdP1u2Zx!N8486$B9X?&$DclZ zdgI28>FMdk#l`#g@Bj4EPc=0)2M!!4EG!%z9?s6rzI5r**|TSdhK8)HtXf)HHgDc+ zZEek9Fk)k4xm@nHZQC3j9o^jACMG6~jg9m3^EYnX2*Yq^XJ>6~?X_#y4jnqQbLUQp zM6z$+zMp^o*}}p?p-?n8H=jOzx~Zv&N~Km+RkgLX9X@>c=FOXxm6dsUd1NvZ zX=yul?BMZua=F~p)O7py?EwJ+w{PD*dGh2hzx?v((WCP6au$mb!vmnqSpF6-9Ona(JQT#e>!KODwxYzG5#S|?M#v6eD#mgO^`=~9EL;yL&>*dd5*+XG=_`^3=CG25PbLa+LJ%N(PW_s z=_-TaM{SB!w(n7k+dMDN2G6VPqUA$u7F4m@ABAZ1D`*UMfe}E6csJU}J1Trmp#~7hZ5QSGpNvd1Uz$!Rf3q28pgSj9o zx?zwoWa8GYK@TOz^)mp#V2_VR5WfJ0W9BSSbn+cKb z7B9l9)K#s!?PSt;g%c8u;y7rd?hkP%>vq5BY=N>c=98V=+T&RSPgSu|E(FAK>B?vNN1 zPszwcbxJ?Oh|1pGd!9?gxzSWOR8o=x5!rGh+6r3hBL-14aTaAQxvJ|Y-S_m4niV2S zK@?}-9Dkhg<+w{Ny!vjyp-QmjyGmIW1DFB{k>P2=8cm~9M^_P#8?JFDumGEPaqJvf zZ{f;B#CG;H7q8a_hQ$pR6%%6So8vKM+W+cNPE_TI46^dn9q@qBr@1bUgxcPGB*b-i z3Hx_0(Esy5KKx^Y0yfgB6~}t>@!ctk>J|!vgVRhE2CPQ;AOKY2y%5nM@YF^ZMS~q}%L-n>Lpor#4w48UHYViOt={{43LMRvkIp+rkbs*s; z14}4q0y6`s8DL?uo-~*R@5tnFsC1DR#BGxT8fA20u_o?`0iDNI6lf;^$@AkR1dPTz z>XF1ZAqNjU95c@Vn59Wo;Z6b(YG+L$xy3(?j2I*vQ>PmzMEdh`yw3=)E}JYMDG|*x mDkGVJ;D)fXhxDI?kcM(ish)oPv+$)O9m7&lFF%`-bKA@>z>*#XDKFr20=RDO%adz+epk!mc6H literal 0 HcmV?d00001 diff --git a/include/ytree/TreeView/img/check/lph.gif b/include/ytree/TreeView/img/check/lph.gif new file mode 100644 index 0000000000000000000000000000000000000000..e3478d8e37dadeba8c9d68c84ad29c3b2843a69b GIT binary patch literal 111 zcmZ?wbhEHb6krfzSj586(9qzWyyp6yrwj}X|Ns97k`SQylZBCifrUW_#09BkU^emC zb!Xj!lRuUA>b}?;FOZcNk%w1VGsZy1Cav&|Ns90004l1fdBvhA^8LW00093EC2ui01yBm0{{a5 zoR6s{>%SVDN!WWM*c`~(aUUXt+jx}0x_U$Nl_tuVt|Eu@i(%By01AUc;I0@!{*Fpg zbHaSSq>t#++QcfgNN&+P1PjGRs)M{VC)E{p+ns{PY55GCCfKT zdutnudlj5Dyj9$F{FNNGJl0(HoBNy=EnH1}ZJdp~t=!H0?Hmr>3p`F;E`5$S&AzVp z{?`tlZe5Rkubt1m@7)jnPh3E9yb6{Yh|XXugzgy9Q&`KPym)~q60+C`qA!W^6**q? znDL-Sb09BaG+A=fNOdVgwOqB*UQB#5_0{Be(_c=2I|cS6C^G26p9zIVB-#+^L!%p& zPJB7bX-BCasfHZNl%!RZTUBOd+0|uOm|tamHq3)NWI} zN%=0-tJUw*u~7w2HCz?()w_VfD(3pwYh$yM(N< zs&K4`v9z;VwY#}pyCWrW*|_c0@z(R$uJ^F-()E4(hW?AL_0z|Vpf`iy5Q;dvYwa^J{*Cj$a(RI*^pgD(@tTsX5~&4)K5=A5{*V$X{pgJ%4> zk!VMwABPGRiIn70lTA@ZRhg3IQW>=eEafa17mSEp06Pc% BB!B<_ literal 0 HcmV?d00001 diff --git a/include/ytree/TreeView/img/check/tn.gif b/include/ytree/TreeView/img/check/tn.gif new file mode 100644 index 0000000000000000000000000000000000000000..4a280397de0ae7564f625d9356204a1cb6a1f399 GIT binary patch literal 504 zcmVi2fsz(rj1Z(I%uk_Z1$dUHLJCFC+@t*{rh7DQ$tg6bPOd)Ib9R>WJIOY zC1?7iG(~*cW?M%k^nH`*-V=i`xtK z>l-Y#TUe}i?3nDfEc#3uZ90uwt$NLx?Ya%yEz9_=8%|Cu4t!3WF5E0v&bw~>jvTK% z&s^_(54|tlPyNqYKx_lG736l%TS9Q=7LIEO5uQVI6V+8@m(N{9de0Z-ZN%5n-ba2T z{gniGQeaAgD-E_p_)=j^h7xB!tcjDOO^Q1$_QV)c-%pP@K@JsJlw?wqOHnpe`IKc; zms4R@m3ft>&a5}LdNsJN672wB*X9FPF}IdUNW|t3S66 u{d%%SVDDcF0XR#Je|A>GGlz1le|i8=~as(Px~3Y#jsDi#ZROFE0Y zt6NK!%i1gaYZh!fj9iR%44mw|tk!J&OdZWO&0MX0?UpUQ4c-m+jU8@2E_d#|PTsDb zepk*OpEvJbzjqJ+%A4QU&sRWV1CsGaU6>nC( zTlseN`xS6l!D9)RHGCFv+PjSNHs1TVZ{)v|16Lk=xp3ygn-h0l>^L-J(UM71HfVqJ9X~WyIc2u{X2H>*|v-0Hm(~vZ{@z319vVQI`QMwlUHAU dy?OTM+oN}%ZaqA9@!H9AH}4%ic+3R=06S)30ObGx literal 0 HcmV?d00001 diff --git a/include/ytree/TreeView/img/check/tph.gif b/include/ytree/TreeView/img/check/tph.gif new file mode 100644 index 0000000000000000000000000000000000000000..e4d7d991e44f0ebbe5f05ec261eb831d96332a4e GIT binary patch literal 568 zcmV-80>}MFNk%w1VGsZy1EK@~*WBexW2^uG0Dypi|Ns900000000000A^8LW000C4 zEC2ui01yBm0{{d6NV?pvH@CVug*84wib4m7AKKl%9&5pQE9md6;~nrKG2-t)^qB zU9PdTVX}#@thKPWwqLl8yS}}^zh=j1$!g1N&2GDcSq!^Z7?+4Av#^Y-0ZW&C?{%!M{?3ielPvS1UOS*O@cQK=0vztVNZrX9j4qE zv|`bVM^CC8$};Ikrz4@36gjo!C6iB?!qh60D^0I9!QvFFlPpiOKG6bID|D$_qHK-E zMLJh0+_z2ZX2rXeZ&$xx0f!YlmT+0aXA!4Wyq0m>yO8rbmOGhlWxJ9i_tpHDb70Sd zK^GQ%m~>*(i%~aL{W!Dh&96Jh{yaN$?a{YO=RUnVb??=`Tf-hMn>cObwvppjuA4b; z=f0r>moB`x_2bu*XJ5X(dH3hvqlce9zB=~v+R<}Y@0~q(_u}D`mv273{q^_T=YMZI G0RTJi9wSr$ literal 0 HcmV?d00001 diff --git a/include/ytree/TreeView/img/check/vline.gif b/include/ytree/TreeView/img/check/vline.gif new file mode 100644 index 0000000000000000000000000000000000000000..1fb0de8bb2911a51ff29f91fe7d231c0a5529091 GIT binary patch literal 503 zcmV^fYPpKps`<(p>p2TrD|$=1D3^=ctGbK# zdo|2eJQh57td{J!4A)HgY!_`h&36sRSk21q>J1AnD^5#pYmSSqyUot4?)whhE*wu> zZ+wqDubj`k@7xdCKWPD}4YXDeTS9H_4t8_+4PrQn<0zK1cn)Jajn3;DdZfn@UPyT# z`Hi%95?@MvB>}GV*OK5%fiV%zG+6Ut&WJlF_N@5xV$h63Hx}&(@~B9qB$GNd$rNQ& zl~Y+hby*eWRhe07ZnfDJ=U1I$d6xBg7HC?bYl*fs`W7kFxJ&6aor@Q%U8#Gi_O+Uq z>tC&b!4CFXm~3LRi_tb#`$+IcfwtO2i=-iumcis&gwQteGNf$RAoON>7%V9T{{hW3I06UMq^ke`4 literal 0 HcmV?d00001 diff --git a/include/ytree/TreeView/img/default/lm.gif b/include/ytree/TreeView/img/default/lm.gif new file mode 100644 index 0000000000000000000000000000000000000000..e7d0a3ce92eb825a95ca188133567cd4f8f31499 GIT binary patch literal 94 zcmZ?wbhEHb6krfzn8?8J|NsAnh6V;OL-8jIs|W)#gAS0(0Fq~5(x216Qtb79sX3ZA us+DiZoVZmeFVu3oV#=XiRnDKMs-2p#PO1G%cj6U(9b}?;FOZ literal 0 HcmV?d00001 diff --git a/include/ytree/TreeView/img/default/ln.gif b/include/ytree/TreeView/img/default/ln.gif new file mode 100644 index 0000000000000000000000000000000000000000..b7b3e55cd044af047e571b8e46d99dd4b801ee60 GIT binary patch literal 142 zcmZ?wbhEHb6krfz*v!Dt(9rPz|9=MJ08pjkPZmZ727U&`e=?ytsfj5H?w)Q6!MTY= zCBcbhsYME5Ky0LEz@P&%5oCu0i}Z(+o~!p-ygs}8e}YEQf$*yI>683lZcElVAIHLA F4FFl;B{Tp4 literal 0 HcmV?d00001 diff --git a/include/ytree/TreeView/img/default/loading.gif b/include/ytree/TreeView/img/default/loading.gif new file mode 100644 index 0000000000000000000000000000000000000000..0bbf3bc0c0e5e635553e8d1bf9ceddefbc402396 GIT binary patch literal 2673 zcmchY_gj;P7RTSb83YJ1>=8y5ONL=ZcEgk+C?FydumNNz8c=c6`n&|fmMu_HHG%^w zNLVjHyfy)hAgHK_Kxkz+0Ktm5M|X*?y?g!o_3yv`{_^F^wY9YuFJ3GxEUd1s-nnz<)vH(c?%i8n zUVirM+2rIT007UQKY#e};oRKZty{MqJa}MhYina;bNBAu-+udTYHDhBcJ|n@WA*j* z-+lL;iHS*OX6D|#dm|zu!o$ON?b=mbT)bh!26uP&kdP1u2Zx!N8486$B9X?&$DclZ zdgI28>FMdk#l`#g@Bj4EPc=0)2M!!4EG!%z9?s6rzI5r**|TSdhK8)HtXf)HHgDc+ zZEek9Fk)k4xm@nHZQC3j9o^jACMG6~jg9m3^EYnX2*Yq^XJ>6~?X_#y4jnqQbLUQp zM6z$+zMp^o*}}p?p-?n8H=jOzx~Zv&N~Km+RkgLX9X@>c=FOXxm6dsUd1NvZ zX=yul?BMZua=F~p)O7py?EwJ+w{PD*dGh2hzx?v((WCP6au$mb!vmnqSpF6-9Ona(JQT#e>!KODwxYzG5#S|?M#v6eD#mgO^`=~9EL;yL&>*dd5*+XG=_`^3=CG25PbLa+LJ%N(PW_s z=_-TaM{SB!w(n7k+dMDN2G6VPqUA$u7F4m@ABAZ1D`*UMfe}E6csJU}J1Trmp#~7hZ5QSGpNvd1Uz$!Rf3q28pgSj9o zx?zwoWa8GYK@TOz^)mp#V2_VR5WfJ0W9BSSbn+cKb z7B9l9)K#s!?PSt;g%c8u;y7rd?hkP%>vq5BY=N>c=98V=+T&RSPgSu|E(FAK>B?vNN1 zPszwcbxJ?Oh|1pGd!9?gxzSWOR8o=x5!rGh+6r3hBL-14aTaAQxvJ|Y-S_m4niV2S zK@?}-9Dkhg<+w{Ny!vjyp-QmjyGmIW1DFB{k>P2=8cm~9M^_P#8?JFDumGEPaqJvf zZ{f;B#CG;H7q8a_hQ$pR6%%6So8vKM+W+cNPE_TI46^dn9q@qBr@1bUgxcPGB*b-i z3Hx_0(Esy5KKx^Y0yfgB6~}t>@!ctk>J|!vgVRhE2CPQ;AOKY2y%5nM@YF^ZMS~q}%L-n>Lpor#4w48UHYViOt={{43LMRvkIp+rkbs*s; z14}4q0y6`s8DL?uo-~*R@5tnFsC1DR#BGxT8fA20u_o?`0iDNI6lf;^$@AkR1dPTz z>XF1ZAqNjU95c@Vn59Wo;Z6b(YG+L$xy3(?j2I*vQ>PmzMEdh`yw3=)E}JYMDG|*x mDkGVJ;D)fXhxDI?kcM(ish)oPv+$)O9m7&lFF%`-bKA@>z>*#XDKFr20=RDO%adz+epk!mc6H literal 0 HcmV?d00001 diff --git a/include/ytree/TreeView/img/default/lph.gif b/include/ytree/TreeView/img/default/lph.gif new file mode 100644 index 0000000000000000000000000000000000000000..e3478d8e37dadeba8c9d68c84ad29c3b2843a69b GIT binary patch literal 111 zcmZ?wbhEHb6krfzSj586(9qzWyyp6yrwj}X|Ns97k`SQylZBCifrUW_#09BkU^emC zb!Xj!lRuUA>b}?;FOZcNk%w1VGsZy1Cav&|Ns90004l1fdBvhA^8LW00093EC2ui01yBm0{{a5 zoR6s{>%SVDN!WWM*c`~(aUUXt+jx}0x_U$Nl_tuVt|Eu@i(%By01AUc;I0@!{*Fpg zbHaSSq>t#++QcfgNN&+P1PjGRs)M{VC)E{p+ns{PY55GCCfKT zdutnudlj5Dyj9$F{FNNGJl0(HoBNy=EnH1}ZJdp~t=!H0?Hmr>3p`F;E`5$S&AzVp z{?`tlZe5Rkubt1m@7)jnPh3E9yb6{Yh|XXugzgy9Q&`KPym)~q60+C`qA!W^6**q? znDL-Sb09BaG+A=fNOdVgwOqB*UQB#5_0{Be(_c=2I|cS6C^G26p9zIVB-#+^L!%p& zPJB7bX-BCasfHZNl%!RZTUBOd+0|uOm|tamHq3)NWI} zN%=0-tJUw*u~7w2HCz?()w_VfD(3pwYh$yM(N< zs&K4`v9z;VwY#}pyCWrW*|_c0@z(R$uJ^F-()E4(hW?AL_0z|Vpf`iy5Q;dvYwa^J{*Cj$a(RI*^pgD(@tTsX5~&4)K5=A5{*V$X{pgJ%4> zk!VMwABPGRiIn70lTA@ZRhg3IQW>=eEafa17mSEp06Pc% BB!B<_ literal 0 HcmV?d00001 diff --git a/include/ytree/TreeView/img/default/tn.gif b/include/ytree/TreeView/img/default/tn.gif new file mode 100644 index 0000000000000000000000000000000000000000..4a280397de0ae7564f625d9356204a1cb6a1f399 GIT binary patch literal 504 zcmVi2fsz(rj1Z(I%uk_Z1$dUHLJCFC+@t*{rh7DQ$tg6bPOd)Ib9R>WJIOY zC1?7iG(~*cW?M%k^nH`*-V=i`xtK z>l-Y#TUe}i?3nDfEc#3uZ90uwt$NLx?Ya%yEz9_=8%|Cu4t!3WF5E0v&bw~>jvTK% z&s^_(54|tlPyNqYKx_lG736l%TS9Q=7LIEO5uQVI6V+8@m(N{9de0Z-ZN%5n-ba2T z{gniGQeaAgD-E_p_)=j^h7xB!tcjDOO^Q1$_QV)c-%pP@K@JsJlw?wqOHnpe`IKc; zms4R@m3ft>&a5}LdNsJN672wB*X9FPF}IdUNW|t3S66 u{d%%SVDDcF0XR#Je|A>GGlz1le|i8=~as(Px~3Y#jsDi#ZROFE0Y zt6NK!%i1gaYZh!fj9iR%44mw|tk!J&OdZWO&0MX0?UpUQ4c-m+jU8@2E_d#|PTsDb zepk*OpEvJbzjqJ+%A4QU&sRWV1CsGaU6>nC( zTlseN`xS6l!D9)RHGCFv+PjSNHs1TVZ{)v|16Lk=xp3ygn-h0l>^L-J(UM71HfVqJ9X~WyIc2u{X2H>*|v-0Hm(~vZ{@z319vVQI`QMwlUHAU dy?OTM+oN}%ZaqA9@!H9AH}4%ic+3R=06S)30ObGx literal 0 HcmV?d00001 diff --git a/include/ytree/TreeView/img/default/tph.gif b/include/ytree/TreeView/img/default/tph.gif new file mode 100644 index 0000000000000000000000000000000000000000..e4d7d991e44f0ebbe5f05ec261eb831d96332a4e GIT binary patch literal 568 zcmV-80>}MFNk%w1VGsZy1EK@~*WBexW2^uG0Dypi|Ns900000000000A^8LW000C4 zEC2ui01yBm0{{d6NV?pvH@CVug*84wib4m7AKKl%9&5pQE9md6;~nrKG2-t)^qB zU9PdTVX}#@thKPWwqLl8yS}}^zh=j1$!g1N&2GDcSq!^Z7?+4Av#^Y-0ZW&C?{%!M{?3ielPvS1UOS*O@cQK=0vztVNZrX9j4qE zv|`bVM^CC8$};Ikrz4@36gjo!C6iB?!qh60D^0I9!QvFFlPpiOKG6bID|D$_qHK-E zMLJh0+_z2ZX2rXeZ&$xx0f!YlmT+0aXA!4Wyq0m>yO8rbmOGhlWxJ9i_tpHDb70Sd zK^GQ%m~>*(i%~aL{W!Dh&96Jh{yaN$?a{YO=RUnVb??=`Tf-hMn>cObwvppjuA4b; z=f0r>moB`x_2bu*XJ5X(dH3hvqlce9zB=~v+R<}Y@0~q(_u}D`mv273{q^_T=YMZI G0RTJi9wSr$ literal 0 HcmV?d00001 diff --git a/include/ytree/TreeView/img/default/vline.gif b/include/ytree/TreeView/img/default/vline.gif new file mode 100644 index 0000000000000000000000000000000000000000..1fb0de8bb2911a51ff29f91fe7d231c0a5529091 GIT binary patch literal 503 zcmV^fYPpKps`<(p>p2TrD|$=1D3^=ctGbK# zdo|2eJQh57td{J!4A)HgY!_`h&36sRSk21q>J1AnD^5#pYmSSqyUot4?)whhE*wu> zZ+wqDubj`k@7xdCKWPD}4YXDeTS9H_4t8_+4PrQn<0zK1cn)Jajn3;DdZfn@UPyT# z`Hi%95?@MvB>}GV*OK5%fiV%zG+6Ut&WJlF_N@5xV$h63Hx}&(@~B9qB$GNd$rNQ& zl~Y+hby*eWRhe07ZnfDJ=U1I$d6xBg7HC?bYl*fs`W7kFxJ&6aor@Q%U8#Gi_O+Uq z>tC&b!4CFXm~3LRi_tb#`$+IcfwtO2i=-iumcis&gwQteGNf$RAoON>7%V9T{{hW3I06UMq^ke`4 literal 0 HcmV?d00001 diff --git a/include/ytree/TreeView/img/folders/lm.gif b/include/ytree/TreeView/img/folders/lm.gif new file mode 100644 index 0000000000000000000000000000000000000000..b5623002a654745049da926cd3c0f8f1cded2a43 GIT binary patch literal 666 zcmdUs&1(}u0L90+Npyp<*4FQ|(*)B>s*aFDr9G?=@`0B<8U@)>u!$CZK>4{;Dd1Yu45FZ>;TyyJVkcrw;|av%Wq zfG+?z4H#w2V2nDOlx z;NPf*{|h>QbM96U2R+TU%};>$7mkmlRc$n*YmwV`#_z_#MDG41(8u(AF?UY`K}z>d zJxE8Mmr7btaJjZ{p|&YCQhb;WZGFvge0TUm7(IG6r-j@Gx83(?ZE@nwvfAx_4#>auF!nVb-p1_?dcQL-&j)(e^W~9mo}iy!^R*{xVj!d4ocu98Xw}8^Pz$=k zXfSr<)GTW|`&o{9+`9q^icY9}$Dw2G$&WLZZ$~{E`zbtDd4K=YYX`W>Vy0C*S0xs6;fB3g&~9pLX!Z?#N%XSx-#onl$*-={{EYn;!?ZF9iqq*9Y$)O zL^O2v!n4m`zwv*pfBDbZ{abJW5C{7=JU5yEAII@TGL_C`^=$p^{GGc=d9*NgU(V|9rG+*(e{gU0+I6d|Gx1!`9TJ*==jShv&v)>c{bf0^;&mA-U=kdF zlDu{*bz%^V`S*5R1NB$@hb0x?ing7c`V(qWJW|H9xdqi;ttGsT9i74MGp}Jf{G)g1 zqSlr1Zt8q-V_z?Nm#>qrztQ1683lZcElVAIHLA F4FFl;B{Tp4 literal 0 HcmV?d00001 diff --git a/include/ytree/TreeView/img/folders/loading.gif b/include/ytree/TreeView/img/folders/loading.gif new file mode 100644 index 0000000000000000000000000000000000000000..2c8472eaa82f95d8239b6a0918adf4ad8abd6f90 GIT binary patch literal 516 zcmZ?wbhEHb6krfzxXQqA^ytxp2M_MuyLac#om;nV-MDe%j2SbgOqnua!i1ilo{o-= zmX?-=hKBO;^8Eb#^z`)Pgx2go9$HSv)e_evvfWEwU+^yIOhs`0|ea~8WqOXLey&1-o+ j40=l<_MLxt=&%5njl2*W!~+7NzT%-BPOL0xjttfSIRuCI literal 0 HcmV?d00001 diff --git a/include/ytree/TreeView/img/folders/lp.gif b/include/ytree/TreeView/img/folders/lp.gif new file mode 100644 index 0000000000000000000000000000000000000000..b9f54856706fe8de0c858b4bb4e46b27a8b4719a GIT binary patch literal 641 zcmZ?wbhEHbRALZgc*Xz%4`wJdG&D>oQ276#A;7`m!-0gEGiQEyv0*|-fq{m?^~?J| z>~JV3NKgVJ6fewKQ9S#346#RcN;lm1p|3K9N0UsVr*w7&G;Y7jz4;vmVFt{*5 zV8en54|W7NSQs=^6#RcMK|w*_!v=>BI|2$40{-7<*wCPGV1~l~7YjaINZ7Dq!UdoM zfD!=?2?+rYHW)0J(D30vz=sbT{@(x^xL`qr!nco4KAcGSaG~JA3Im|q9xPC}dgy&i(lS!fIo{IEaOaL=_X9`6^9K}JOtdUitn5@zIG(!S`qsa)!YWd0 zRwy&DOLJ-PdVNrCXP2;QSm03jh=om>*=2>u6b6@OaXmW?frkrL1hQLC)`~r~W##4N K0fMYd4AuY$xzKt5 literal 0 HcmV?d00001 diff --git a/include/ytree/TreeView/img/folders/lph.gif b/include/ytree/TreeView/img/folders/lph.gif new file mode 100644 index 0000000000000000000000000000000000000000..f663714f4944a2b046d7c413e0aea5240132ec0e GIT binary patch literal 651 zcmZ?wbhEHbRACTfc;>{gVZnq26B_=1*q|UF@c+Ys4J#)6f6(yZM8f|U3;w?VvM2n% zQSjkFKtn^rhYJM{Rv3KP5%2*>e%SEgLc)dyfe$Y>I9M1MXej)@P@tdyG-1Jm8443R z3N|z-eAwX7P>^t7hQfy(4ht$2J{(ARu)yH;%f}5B1s4`5Bm@Lpzr6p!0)@R(1TIVv zn9$KMbLPws4;FlQFyY(BCkY7w1qBHK4h|1C7(Cb!Frh%VVPuHSjez`*eT|9>Dk6oKMT7DfgJCk7pm<3Vx4!2Y7asj0c8wXMCQowu{6 zx37OfQ}@Iv{f4YFW~ffIpF3|}E2}6IlaK*}<^+3(HESL0TNyTO-o&_VyJh?8HI8dH zv@oz7Vp+n$$z?5Jr!2o~?cO!}oAr(?l{(HQABQLewYZ?6v7JLpU-pHOgN z5t7!3xbXF5@IoD z|nT}F@V%exs}cFYl$ z!a-W3=O&BC0551>2d;#9XkyjTzpGcIeLb4Ddj1pIIhJ>CpS*ta@Y%J4yEiYs9=>>g n!(ZNBeEa8k*pO`;+wFGveKhOAlWzpS z{l5q)rIOm4$RZS}C`BvA#SCRCOWDeCZ-pvVrE1l9v_qZhQn%VnHK9pOX&TxFHZ)ia z(>>nf$cT#Qi1Avo%*cxD$T16wl~EPdQDai{c1BlpM-Lnsjmemb=@_=c8Zb!15?a() z3^veUF+3LJoT$vs9P48(SyfhNjpf3EVpn!&59%RBZ%*ZO4)X8=noMH{`XPZrSOW%W zSkej)7K05mSYzj0CMUXTY$WkJXj1i(Bl)in=&~uTnr=8$6B&pFPVK^_jYle&^E8DxOW+C*Ozx5U3T~g zOQDe#Y2Re=Fz|xrb>K>vhbC6-|GjWdx~kiLtNowQr8}C-Hy$57yY*n_+QHtB4>upa tK7V}W>F=X=pHKIWUw%7#`~Bma>pQQ0o&9|A<@Dm=!AX66|7oN9{{Yy;b6Wra literal 0 HcmV?d00001 diff --git a/include/ytree/TreeView/img/folders/tm.gif b/include/ytree/TreeView/img/folders/tm.gif new file mode 100644 index 0000000000000000000000000000000000000000..56622cc305a9a8432d94c733c6a8dfe76119230c GIT binary patch literal 1281 zcmdUsjWbjU0Knh+SeAwrHG6IHmLiE+)g5M)J&Z+X+Uic6x$L^GNM*yyN9DyX>!W%; zlC?_@VeQ5~>tomYT9kDdw%lEN+|?d~PSbg*$r#hUt3Ts@f5GoJKUPGTe*kwc0Gcne z00@F`97km^ZsZ^^gqtAz6#@VNEaKrt9zM=S5g4C3kD+uNL#D(4reR_jikVvf*clfhnErG!nT%wDCIg}$)zax8#A8F591}vvFoefp z_i9EBC{L$>$3`b`1G`+1Tmu(_WHJnKJ{5gR_+LQVv>*Tg3pn`M_VW|K3Wr#E`2t}< zp{NijD!qLtpHNm_QAsE*5#6gPzgtK!Ll8enl@Mr=$%JNKIXKu6ZTCwGfST%j+dw6e zNTON{TUbk*)k51{DACn?dggIiw_ZTqHQ?fcI5~}2?6#h@T3jTQtgtM$6L*+du3?rW zl5gnjJx$)Kj~SCRV=mYap&?;#PUU(N^=Ug)e8I+@nP}pMdj|JlJ6zFVpul1qWk2Za zJ1Vq0=3^K6L`AmR`A=xrC7AZa(w_E^e?Y()zH7yd>Owj7M3EgO-St$s^(_bIfNWi+ zuQ{v8@kp`LJgMm0rsGBZH(dieF5Kx$_dB^WJiq+tBigoC&nPDqN87S_ zug8^>s_3Is{+nlN)(UZ8J}qT>=&+SK@OtXiaXr-|zJK@CcOx^FEc?KZDg2@5&idy5 z+T;%dFW(jD8G~1{v@1c^)+&#^&;GFXrQVM*l=d<7jpIxGQ10d20i3YY6lvZZjewit z3^31D+r!B#J!%96im1eT0cB4(_j~F{75A3&L`HpqTVBipL`&VE6?+h?8?Jf(yRq<- z?*~7(>t5QJ#hZQ;_Zv$YFP^*I2%4juyAd+SO2Eqk_XNb3-|+TqD*DFe?{nAL>u2_r zpBcR0lzUpGS*rMAhw^zCys_1j$MS{k~(z9@O9IVqPk^>bGx&AO`xq%DtcU6jhk%jDA5srpr^+|Y5L zR`JX5#o9;4r}ElH;harf`@-AEI^{BwewzZPHUI=R9|a% zZNgS-Pkkywu5QZ9k!xDZ`{ccC4O?<;hl-)->mJEbbVN_|DFy}>wiJWI>x@T3PhNPU z)$dbDn98yu3%zOUW#kD+icOx-F->;x?5M+JY)9c2YrP#J7lrXHLK}@ablYRmKefSg zOS9hS?YNoR?&}pmmmcAP|K U-ZKv*d~KX^p5GT`Wd<<*0~01CaR2}S literal 0 HcmV?d00001 diff --git a/include/ytree/TreeView/img/folders/tmh.gif b/include/ytree/TreeView/img/folders/tmh.gif new file mode 100644 index 0000000000000000000000000000000000000000..e42349e406a7e23e8d6620821680628d6e0712e4 GIT binary patch literal 1295 zcmd6ki&s(y0Ee#-N}7}Oq@*pckJ2{Vm>nOB7NkAIc21m~j<41Z*~FG&=t^9gUEYvo zS5gsZbyHJTazQ&2vvQ<`<;YSK`I5euyH$t z*&qi(gUUD%pN-qtG!X3X>$d6H>@+4)2Eq`BLZPT61@F4vCH&79;aTDZ04yNxz32N+ z03RG;iNq4AOsC^6M)# z8}r;X?ex)}272zi{APjmH%-N!za$SfBnD`|$X*aWWt1|sl`$Uu3*9I~ef&7Cbi}NL zyaJOOgfeo2T2vR&fQXe_(#YZtR)bC&lA9L63oeRP%RBce)UrrX)@o&JY1Y(d5@&Yo~oz+sqlX=!2EAGu`)e5@RGve~z z@tE@C+o`eV#M(@!M5!`6!PDI2nOgbcxU)$8s($v6&UPPqkU*dTjOo3daj~>V|QWYz1&bk%cGJU zL+hAGYtTPdO&ET9(in3CZ{+(kqz9!IT)ti2fsz(rj1Z(I%uk_Z1$dUHLJCFC+@t*{rh7DQ$tg6bPOd)Ib9R>WJIOY zC1?7iG(~*cW?M%k^nH`*-V=i`xtK z>l-Y#TUe}i?3nDfEc#3uZ90uwt$NLx?Ya%yEz9_=8%|Cu4t!3WF5E0v&bw~>jvTK% z&s^_(54|tlPyNqYKx_lG736l%TS9Q=7LIEO5uQVI6V+8@m(N{9de0Z-ZN%5n-ba2T z{gniGQeaAgD-E_p_)=j^h7xB!tcjDOO^Q1$_QV)c-%pP@K@JsJlw?wqOHnpe`IKc; zms4R@m3ft>&a5}LdNsJN672wB*X9FPF}IdUNW|t3S66 u{d%M&G=7-+nXi%{%_#v9SGo zZvZ4cg8&3UbV`)Kw*mnG0Hja|+(2N6PK^?aN@5WuFqD{r@drHIz`>0$re@+>Uew`z z930o-MxG9#5Jni+K_IxrDiN56N?=R|>JSj`gP40j2Zs5T@j!_08mtYv? zVSOB83c-|2ObJf@^3Wim)YjJCt)lQa98`iBQ3?lwR+j$2AHX=KG%7(%$K>%iIEI=g zhEW*gaG;H~d4eFeYX5&ldue3>01)8!cEa0F05X9<0^v1Lkys)IuHPvArVJI7lvkA< zw2{d|%7ME2dXbHTrKJz>R`MK$x*u7u=n$-pr3>a3*k!b8E%5%Mnngqg#R_NWf|)YQfwuZ-YsoPE&i zv5+{(&R888wj)!+KY-VUMmK#%2L>->^^eaSOJ^s1mEF~qIx=)d%8p-!JB9Y_H>r7T z3%xCyjG>4>U&PJY=cFs%iqF0*!^*rBLmTivrz|0*@Ui*qdo5Ue0 z(l3(P@+q&xgFaF7$rS6>IRce>^t*{2e0=GmkE2?>Z=8&Jb}l96a9(q1{D~eqgFhGB zav^D5+LE4XX=;Jf9jK~|EYCPqW^Pc8D(muLlj>qY6jhxqJZqv~7wctvN=w$K)M#0N ztFN?D5Z_uR%Bfk(RTSm=me*BKHF-^qahiNp$7XV6>wVMm6>ZAP<*V(*`&SBjt;3pY z20UNUTe{`0e)17byq{uJU+een*rUgOb>q{n{`C{f@%}eWuWJ33=55pd4Kr@980y)S z(*df5`~v~nrQ+#;)>XM%pys(of9KWoZ#k0L8C}7*aOORERAXp(@d;M@y64rfH{IcG_rnP;5nYc8JnjcG0T#E+QU5 zs*iZ2#G_3_kWz#owBBWKhJWhppTDHXvOs!~Zs003ZUKS&~}ed}3sHF?YR>HR z7{ukEh}00l=3&S%D)quJ%z*uWl+!3yo)oEzQ3mZ?m!XWd7XK$6wn{ zCI0pY`la=WzvW~gB7kjN@IJdA#F?7!c0<6`pbDvxt*|}T_7I*AQruwO`?b?GWLwIG z3#%bn1Y5@g-#S06F~#o)psL(MoR8$0IdX(?zH2%Hg>`-ccp8Jxl5wmiB;#`T*~W0< znaT0nzdmc`x@1}eckrIK6%W^bmr&dk$>w3NON(e^`pfR9b^VYcttCtww}oq_rmMmq zr&tL*m1S{@%|b_)0{U~((m1p?x>wnixKb|h6AUxEljFx^j;*9pB6C?#lY>gXQER~sqEX35bbegB4}YF^IdrZK;M znl`#LDXZ=|8q)iiRsK;<(pLKZud5_)mN!+nha$ zWNrBQ-{wyo4|n3P$E-?ncO=hO33T~thkU_L{i%-0sZ zd2{S+4(o(`QOHbPsXKG{Rrp&hHBccwUlM$Fj+$|jVz-oXx;xDEX4pQl>($7h=S#`a z<7BrxvDZS~G7lxC-xtTHb}WM_`nm7(E|%KK;xbB~$>Oiq+Q@m?t)cP+!J|9!3x(6q z1~avUd~h#e#S9o_7?V7N4yM rAJu+hrOyL~{R^MggEV{Jw!@4_--m(0mA>u4kuQ8ZP9_jTL4ffes3;L^ literal 0 HcmV?d00001 diff --git a/include/ytree/TreeView/img/folders/vline.gif b/include/ytree/TreeView/img/folders/vline.gif new file mode 100644 index 0000000000000000000000000000000000000000..1fb0de8bb2911a51ff29f91fe7d231c0a5529091 GIT binary patch literal 503 zcmV^fYPpKps`<(p>p2TrD|$=1D3^=ctGbK# zdo|2eJQh57td{J!4A)HgY!_`h&36sRSk21q>J1AnD^5#pYmSSqyUot4?)whhE*wu> zZ+wqDubj`k@7xdCKWPD}4YXDeTS9H_4t8_+4PrQn<0zK1cn)Jajn3;DdZfn@UPyT# z`Hi%95?@MvB>}GV*OK5%fiV%zG+6Ut&WJlF_N@5xV$h63Hx}&(@~B9qB$GNd$rNQ& zl~Y+hby*eWRhe07ZnfDJ=U1I$d6xBg7HC?bYl*fs`W7kFxJ&6aor@Q%U8#Gi_O+Uq z>tC&b!4CFXm~3LRi_tb#`$+IcfwtO2i=-iumcis&gwQteGNf$RAoON>7%V9T{{hW3I06UMq^ke`4 literal 0 HcmV?d00001 diff --git a/include/ytree/TreeView/img/greybg.png b/include/ytree/TreeView/img/greybg.png new file mode 100644 index 0000000000000000000000000000000000000000..1ff7817010b1327f9174c53743480dbec6e5831a GIT binary patch literal 197 zcmeAS@N?(olHy`uVBq!ia0vp^8Vn39J{-(I)*UWIAj!az?&#~tz;Nxx75@k$AYZb? zHKHUqKdq!Zu_%?nF(p4KRlzeiF+DXXH8G{K@MNkDP!U^zPl&6ru`!UTJT3AnkaG2O zaSW-r_2wWWFOYX=!FT^$es&QclUPtQlYyCGgAN1Z%=cyQK$<*V{an^LB{Ts5arr3K literal 0 HcmV?d00001 diff --git a/include/ytree/TreeView/img/header.gif b/include/ytree/TreeView/img/header.gif new file mode 100644 index 0000000000000000000000000000000000000000..6bb816ce2139fd04128976d48d6b49ea67b86049 GIT binary patch literal 203 zcmV;+05tzcNk%w1VJra~0Du4hYItf(TudSP1ONa4001li0000i0UH1S0-}tMsmtvT zqnxzbi?iMw_z#BSNS5Y_rs~SJ?hD8AOmp^)=lag~{tpZahs2_BLQ5)_%%<}RjjoQ= zs`ZM^YPa03cP9;t$KBRxX9S( z_z2mUI7wM)nG~6+xyjk-d2<;mI!gL!dWxE=`bXO8`ii$IJ4;(@>jRssyX$o8`+HCT F06P{RX6^t0 literal 0 HcmV?d00001 diff --git a/include/ytree/TreeView/img/logo.gif b/include/ytree/TreeView/img/logo.gif new file mode 100644 index 0000000000000000000000000000000000000000..7b00575606c147b260183f61ea2a0f6820080512 GIT binary patch literal 705 zcmZ?wbhEHbbYxItxXQrr|NsALhM6HDA?w$#Z)$2fbLPyKFJIEq(&jj9ZWfroxBkrC zyLWqgduPs^d2j#IXXoF1fB*B|{%0>zWB4lqc;vu{%4AE36$3h2gnFF zbT^ho)=T(HarR726mH3=^mUV)Ha|gfj$dW9oAiQ}NsC=8+g-Uhi`Yxpz!{JSzGw`Hzb@lnymz~yy=V$(Jbi4P|)svVy>p|IO1BbX!Y@C3g5|86Ya z+#k4J@!+8d7KVfT%B*iMJvfwnl6fM#q%}w9ghD~DX$cXG9;{6#wmxGiTUWblr*6;T zMf0BsemrpU{)H(CyB=(L(QdY1o%v~kEVXP$|Bp!t}=Q?gniQ2jUa@0nhF(gIs#AC;FYT$;Gw zf?)znxghVFUiJ?Q)^aZf)|n?}?}2T*_HEsXA3JsS$cZzDj-5Pw{Ph0A#}6DivFE_yeFu;3+Iw*O?tQ!WAKtNN|CSxQx9!}! zY1_^Xo4236c$I6dc_YwvwUQve;Qzz`hUHa_dl(p)d_7$pLn>}dH37%)R*4g_P%98 zYUZp`(_;!twyw)wD$-IgZ#6puLvl@R9^(-O58(w&g=RM%p5kc#+$3|3xya(i(@h4` z9~W40UwNsdu$k0x9^s|`tX5*`wkhY7Xiz=7hB89y_u26&Y{3o zH;W;4#bU>GZ5Gn+@=DsB56e6(YVvE}DXY*R@gsvtM08;v+fJz`IVR;*jP2tn@mUVmYreK&jn0{)3hK>wdfsHUY+m@zt=wYL>4%McWmbpYGB6%F z;Hs>k-~T9S!|X(m3!de;R5ah|eO7SA!M%8wmIH%f!3BX62kvke8Xh`p;J(;G`dOYx z`{La)Ctt1t>GqUX;A9R8DqwGp?I|$6aj_s=c}{PE`J}^!vFlcG2{`b)F=2URaNrnQ zxxtl_0_M%Ky-%__Hc!06TWVo8ef27k_oUA@u<&#oWZ>qW)UD{(W+`>^YC!s7kcwTW zLqi#vIvQJ_If(Ghm>GDNyV&py&=tyac#F-K9d2X*hQN$WUY7s{VI~gl#k(a=p5+Kn zE;r|302(VS+hCxT;KItI(I6_h;t?yzwI2Ql8hAG>Vh&Ye1p4d(-v%MZ5KTs)%mS+t dMu!GQhAjIt#@`Md_Xj3L22WQ%mvv4FO#qGPmRGfL4E1TigwMT;QC5+R@{MKBIv)!3>< zu{xrnQfWD3AV3Zv;YdP&0D*7?a*>dbgDVM;aD*Ihj<>O&`UmvG?*8_}KF^2U*@vfM zqP)HQyZ`|3MxKa>1AtACi(@?9UHMMHL#?Z9&Imgh1^}W-L2N>htN#cSnSeQ+osP*v z<)VSGwCoG$y~r$7209LnN-M}2M2EUmd{0H6iF7y|RuD99m^xU!gCpbW+4))`b!pik zmdKnCbT}l$X1CAGEyxvWu~gpEKeV7-T+$m>R@cmC%ayAb0*S^Qo!|+?O|48it8d-7 z@i(q9KEa0Znqb| zF6RvKY&LsW?;wdvzhCsUjzoL-q(pC6?ds#c__HcLF^NEKrO~@{t{0TQZRCq2p`l0c zjV%-!V_G>gzn}#{TPJ&9!(`%%r3)I}&0l}7sv|2@Gs}jR8Ukf%T1loce!6=PCtSC|L`H<2$(Jtig}J9uK%^>R|GrC753gRnZ>(SaDV<)gKi~?z{>#F% zY06FMDKUC0y)$aEnHCOa^%1BAiQul1xYgahPvSGUBk%?|G0}=IK!!mTSa6GjkIwFo)N8~5ID3|RQU5qOdq*jOu@-X~@; zuTe7Lm)7}+&6sLt>Xd5CeT+4*QLedhogvDqFBb=Wc(3|UZosYraf15!B8vlqp)U>{ z)UF){BC5SZMh=4wjCNG16Sw;Iu{-5N0&ZI_;2F<~uY?uIsos&_+deCG?(D2Pcrd3m zFRne<{|un^)JYddGCo=GdMrG`404o5=X1YE1#8a!u+n453n{tdSr)@m2vA!y%J=Yx ztpTslpn+-;+(PfTk#|UZ83xsCa$aMF()p^7g#cc~^=`HRQR{AEAk?N6d~IQq$+@`Tnd@j|Ugvw`;e2jkcG}|8 zE6~KAM{*qeToT^&Sa>hU?c;ly1V66Vo50=61bRL*>6rnm;pXT36?Kbbzg;XOxb>za z2Y}MG;2TG88G348RAG^RyIacS)H*QUSj?{Uh)`a|=uK@mw>w_aZ8(ABJO0;!461P_ zmKr8{)30m_*Y=>INiW4{{dgNkDCX8uOY&3UYt7W`h);7 LGA4o;p7Ps2i5x4* literal 0 HcmV?d00001 diff --git a/include/ytree/TreeView/img/qmiddle.png b/include/ytree/TreeView/img/qmiddle.png new file mode 100644 index 0000000000000000000000000000000000000000..331fc6b2d6de89d2ac89128f698ad23732f72e90 GIT binary patch literal 385 zcmeAS@N?(olHy`uVBq!ia0y~yVEPYa`*1J=$+J&19swzqbVpxD28L@luJ}h70r`?8 zt`Q}{`DrEPiAAXljw$&`sS2LCiRr09sfj6-g(p*OfQp;~d_r9R{r|sv|IsgBza2Vu z`ueTAcke&?{{6?BckdrReV$WLVrgZyY5U#_SFWErcj@P^U(a8@{_yeBs`cA`|M~Ox z?_XnMJN@8N2@_WwWL+yDFB|Nq}(`yc%On*To_lY$$wpL`QP{QR$bfT8(Y WivQ20^LGF}#Ng@b=d#Wzp$P!YPS(Z% literal 0 HcmV?d00001 diff --git a/include/ytree/TreeView/img/qtop.png b/include/ytree/TreeView/img/qtop.png new file mode 100644 index 0000000000000000000000000000000000000000..07e845ed1554f058d9d04ed0bce74b66b4359329 GIT binary patch literal 2030 zcmZ`)c~Daa8jqq|r7GRFtE*iFwC)zyT34=7gm4N$Q3pg0MUjF)0wjcl1c*FVEMT<= zB90&sP!J&`$Pump;Rr{n?VZBn3KqL1D(X=X8iNlF!-wKY;bd$G7KgicF3S!eGY6C&I%?nHibIOjdhm@6@!khRsnbRZ5jA2uoPs*zE2b%*vz7SJq}` z=d0_R!^6q!=5_*s7>dJp^zd=m(2kCda3YDv<&sGeDwS$>ZlSYxU|~rX9~Z~%>f2E$ zFlh9$eC1;?6NI43+9o0~oJ@|0jEE|!tm_{d+1lQzZEUS?YRmapEEo|^OXoDSw!RUH z3zg2!#{j@b26I$2(ZcP@&S&Hml{L3@_V9;f%ktH=bw*i@8U(}eVHyh^i0C`TnM(Vscm>{yr8&(UPND#$%W!cQq({5>E*qA!JuHw z)YO#4V$nWTs?};nc@49sp|OS6H!xgQRbO0QL!nS2NaXtF_Kftmfx)3{4!5?UwQq1Z z{Y{$P75iLT>4;FAo>O3CWJHOgOiE@#L-CyUu2x=8KBN3YQJIysO;Kr;cyjut^DVw$ z)WpO@)BjHuwet&0ufBrIUVrr(cwsCt$u_#-v zs%vs~bsH6mQ#0OgZfzMF8p1G4p+wVOrkQD`zXD}zb&EW@Byx3o>+$EfNz1sy+D{Ce zdA$W3bNz33{mf$Nw9v^SktleWY34fw7AgRX(sBFeOX-Gn_gK*E;z9)(8)W zt7EPf&4$9Ei4%_SoHhu+4^&Xx=UGWd%!VKfq`toXU%nV8x0^|kwaT(*3a#yyOb1v9 zz{N7r8{@mt__p=&?#|9}Z_C4xQHEykbzgXy^ZDU{0ixRg$X*W>Ej9=8EB)%#9Rac_ zZp^i_4A9rpF3mKjg})HJUd4uHD}dw_@oI4AoI9FBeOPw!>!jG#*QZX_7@m3e)wx4P z1Lk<%4VbzG*A&hCQaU=|G05c_7^EN~98jpl(U23gl@n)r_K&F^Qz6(LcOJgE(KjGV z{@itQ(<P<1#b#T%=U1<#3yawYR?umbKm)vq6CZb&V zb^Md>=5+B(Nc_DkBPGdBm7=M9xLE?)^O3$vL}CUBb8Shs8m*#c8pT3ZuuvPn1Pqa3 zLy3ez2L}5&j(K*HTf2R5=(9W?C$A7A1G@KsB)VYux%s7FJw0tYqb-16B!4*$&ujf5 zv!E|e2f@i98K)ECwDR+|0FIB5pV`vwy?S5LM9IMyJQE!j*`GdmyQ0cGK~ufM%$jOn zS1YHSSI||t(VO(I2Xyq0WCvV0YVyi)j_qDBc!#U|_)tTk;LNkr8`OYyViNMn@t9MB zr0;TIiyxCSA^jkD>!jrPm&*IEW}R_%`>rN~Pn@jb!{|gon2vg7T!aOdXZy7;MMgf{qLA{?Zbb| zfo<6kiSkpQTM~zr)C8=F7!oI;&Eb~qu{>5c~LSsS6 y*#e69I$%~m4(;;D{+%)jwSRj{Vj=jC-iVSxl;tzlvFnF5w`Ev+KmHe5@TeRB literal 0 HcmV?d00001 diff --git a/include/ytree/TreeView/license.txt b/include/ytree/TreeView/license.txt new file mode 100644 index 00000000..be1b84e4 --- /dev/null +++ b/include/ytree/TreeView/license.txt @@ -0,0 +1,35 @@ +Software License Agreement (BSD License) + +Copyright (c) 2006, Yahoo! Inc. +All rights reserved. + +Redistribution and use of this software 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 Yahoo! Inc. nor the names of its + contributors may be used to endorse or promote products + derived from this software without specific prior + written permission of Yahoo! Inc. + +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/include/ytree/treeutil.js b/include/ytree/treeutil.js new file mode 100644 index 00000000..ab21b5bf --- /dev/null +++ b/include/ytree/treeutil.js @@ -0,0 +1,50 @@ +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ +function treeinit(tree,treedata,treediv,params){tree=new YAHOO.widget.TreeView(treediv);YAHOO.namespace(treediv).param=params;var root=tree.getRoot();var tmpNode;var data=treedata;for(nodedata in data){for(node in data[nodedata]){addNode(root,data[nodedata][node]);}} +tree.subscribe("clickEvent",function(o){set_selected_node(this.id,null,o.node);});tree.draw();} +function set_selected_node(treeid,nodeid,node){if(typeof(node)=='undefined') +node=YAHOO.widget.TreeView.getNode(treeid,nodeid);if(typeof(node)!='undefined'){YAHOO.namespace(treeid).selectednode=node;}else{YAHOO.namespace(treeid).selectednode=null;}} +function addNode(parentnode,nodedef){var dynamicload=false;var dynamicloadfunction;var childnodes;var expanded=false;if(nodedef['data']!='undefined'){if(typeof(nodedef['custom'])!='undefined'){dynamicload=nodedef['custom']['dynamicload'];dynamicloadfunction=nodedef['custom']['dynamicloadfunction'];expanded=nodedef['custom']['expanded'];} +var tmpNode=new YAHOO.widget.TextNode(nodedef['data'],parentnode,expanded);if(dynamicload){tmpNode.setDynamicLoad(eval(dynamicloadfunction));} +if(typeof(nodedef['nodes'])!='undefined'){for(childnodes in nodedef['nodes']){addNode(tmpNode,nodedef['nodes'][childnodes]);}}}} +function node_click(treeid,target,targettype,functioname){node=YAHOO.namespace(treeid).selectednode;var url=site_url.site_url+"/index.php?entryPoint=TreeData&function="+functioname+construct_url_from_tree_param(node);var callback={success:function(o){var targetdiv=document.getElementById(o.argument[0]);targetdiv.innerHTML=o.responseText;SUGAR.util.evalScript(o.responseText);},failure:function(o){},argument:[target,targettype]} +var trobj=YAHOO.util.Connect.asyncRequest('GET',url,callback,null);} +function construct_url_from_tree_param(node){var treespace=YAHOO.namespace(node.tree.id);url="&PARAMT_depth="+node.depth;if(treespace!='undefined'){for(tparam in treespace.param){url=url+"&PARAMT_"+tparam+'='+treespace.param[tparam];}} +for(i=node.depth;i>=0;i--){var currentnode;if(i==node.depth){currentnode=node;}else{currentnode=node.getAncestor(i);} +url=url+"&PARAMN_id"+'_'+currentnode.depth+'='+currentnode.data.id;if(currentnode.data.param!='undefined'){for(nparam in currentnode.data.param){url=url+"&PARAMN_"+nparam+'_'+currentnode.depth+'='+currentnode.data.param[nparam];}}} +return url;} +function loadDataForNode(node,onCompleteCallback){var id=node.data.id;var params="entryPoint=TreeData&function=get_node_data"+construct_url_from_tree_param(node);var callback={success:function(o){node=o.argument[0];var nodes=JSON.parse(o.responseText);var tmpNode;for(nodedata in nodes){for(node1 in nodes[nodedata]){addNode(node,nodes[nodedata][node1]);}} +o.argument[1]();},failure:function(o){},argument:[node,onCompleteCallback]} +var trobj=YAHOO.util.Connect.asyncRequest('POST','index.php',callback,params);} \ No newline at end of file diff --git a/index.php b/index.php new file mode 100644 index 00000000..c75bcdb6 --- /dev/null +++ b/index.php @@ -0,0 +1,46 @@ +startSession(); +$app->execute(); + +?> diff --git a/install.php b/install.php new file mode 100644 index 00000000..21cb9e69 --- /dev/null +++ b/install.php @@ -0,0 +1,586 @@ + 'English (US)', + ); + if(file_exists('install/lang.config.php')){ + include('install/lang.config.php'); + if(!empty($config['languages'])){ + + foreach($config['languages'] as $k=>$v){ + if(file_exists('install/language/' . $k . '.lang.php')){ + $supportedLanguages[$k] = $v; + } + } + } + } + return $supportedLanguages; +} +$supportedLanguages = getSupportedInstallLanguages(); + + + + + + + +// after install language is selected, use that pack +$default_lang = 'en_us'; +if(!isset($_POST['language']) && (!isset($_SESSION['language']) && empty($_SESSION['language']))) { + if(isset($_SERVER['HTTP_ACCEPT_LANGUAGE']) && !empty($_SERVER['HTTP_ACCEPT_LANGUAGE'])) { + $lang = parseAcceptLanguage(); + if(isset($supportedLanguages[$lang])) { + $_POST['language'] = $lang; + } else { + $_POST['language'] = $default_lang; + } + } +} + +if(isset($_POST['language'])) { + $_SESSION['language'] = str_replace('-','_',$_POST['language']); +} + +$current_language = isset($_SESSION['language']) ? $_SESSION['language'] : $default_lang; + +if(file_exists("install/language/{$current_language}.lang.php")) { + require_once("install/language/{$current_language}.lang.php"); +} else { + require_once("install/language/{$default_lang}.lang.php"); +} + +if($current_language != 'en_us') { + $my_mod_strings = $mod_strings; + include('install/language/en_us.lang.php'); + $mod_strings = sugarArrayMerge($mod_strings, $my_mod_strings); +} +//// END INSTALLER LANGUAGE +/////////////////////////////////////////////////////////////////////////////// + +//get the url for the helper link +$help_url = get_help_button_url(); + + + +//if this license print, then redirect and exit, +if(isset($_REQUEST['page']) && $_REQUEST['page'] == 'licensePrint') +{ + include('install/licensePrint.php'); + exit (); +} + +//check to see if mysqli is enabled +if(function_exists('mysqli_connect')){ + $_SESSION['mysql_type'] = 'mysqli'; +} + +//if this is a system check, then just run the check and return, +//this is an ajax call and there is no need for further processing +if(isset($_REQUEST['checkInstallSystem']) && ($_REQUEST['checkInstallSystem'])){ + require_once('install/installSystemCheck.php'); + echo runCheck($install_script, $mod_strings); + return; +} + +//if this is a DB Settings check, then just run the check and return, +//this is an ajax call and there is no need for further processing +if(isset($_REQUEST['checkDBSettings']) && ($_REQUEST['checkDBSettings'])){ + require_once('install/checkDBSettings.php'); + echo checkDBSettings(); + return; +} + +//maintaining the install_type if earlier set to custom +if(isset($_REQUEST['install_type']) && $_REQUEST['install_type'] == 'custom'){ + $_SESSION['install_type'] = $_REQUEST['install_type']; +} + +//set the default settings into session +foreach($installer_defaults as $key =>$val){ + if(!isset($_SESSION[$key])){ + $_SESSION[$key] = $val; + } +} + +// always perform +clean_special_arguments(); +print_debug_comment(); +$next_clicked = false; +$next_step = 0; + +// use a simple array to map out the steps of the installer page flow +$workflow = array( 'welcome.php', + 'ready.php', + 'license.php', + 'installType.php', +); +$workflow[] = 'systemOptions.php'; +$workflow[] = 'dbConfig_a.php'; +//$workflow[] = 'dbConfig_b.php'; + +//define web root, which will be used as default for site_url +if($_SERVER['SERVER_PORT']=='80'){ + $web_root = $_SERVER['SERVER_NAME'].$_SERVER['PHP_SELF']; +}else{ + $web_root = $_SERVER['SERVER_NAME'].':'.$_SERVER['SERVER_PORT'].$_SERVER['PHP_SELF']; +} +$web_root = str_replace("/install.php", "", $web_root); +$web_root = "http://$web_root"; + + if(!isset($_SESSION['oc_install']) || $_SESSION['oc_install'] == false) { + $workflow[] = 'siteConfig_a.php'; + if(isset($_SESSION['install_type']) && !empty($_SESSION['install_type']) && $_SESSION['install_type']=='custom'){ + $workflow[] = 'siteConfig_b.php'; + } + } else { + if(is_readable('config.php')) { + require_once('config.php'); + } + } + + // set the form's php var to the loaded config's var else default to sane settings + if(!isset($_SESSION['setup_site_url']) || empty($_SESSION['setup_site_url'])){ + if(isset($sugar_config['site_url']) && !empty($sugar_config['site_url'])){ + $_SESSION['setup_site_url']= $sugar_config['site_url']; + }else{ + $_SESSION['setup_site_url']= $web_root; + } + } + if(!isset($_SESSION['setup_system_name']) || empty($_SESSION['setup_system_name'])){$_SESSION['setup_system_name'] = 'SugarCRM';} + if(!isset($_SESSION['setup_site_session_path']) || empty($_SESSION['setup_site_session_path'])){$_SESSION['setup_site_session_path'] = (isset($sugar_config['session_dir'])) ? $sugar_config['session_dir'] : '';} + if(!isset($_SESSION['setup_site_log_dir']) || empty($_SESSION['setup_site_log_dir'])){$_SESSION['setup_site_log_dir'] = (isset($sugar_config['log_dir'])) ? $sugar_config['log_dir'] : '.';} + if(!isset($_SESSION['setup_site_guid']) || empty($_SESSION['setup_site_guid'])){$_SESSION['setup_site_guid'] = (isset($sugar_config['unique_key'])) ? $sugar_config['unique_key'] : '';} + + + + $workflow[] = 'confirmSettings.php'; + $workflow[] = 'performSetup.php'; + + if(!isset($_SESSION['oc_install']) || $_SESSION['oc_install'] == false){ + if(isset($_SESSION['install_type']) && !empty($_SESSION['install_type']) && $_SESSION['install_type']=='custom'){ + //$workflow[] = 'download_patches.php'; + $workflow[] = 'download_modules.php'; + } + } + + $workflow[] = 'register.php'; + + +// increment/decrement the workflow pointer +if(!empty($_REQUEST['goto'])) { + switch($_REQUEST['goto']) { + case $mod_strings['LBL_CHECKSYS_RECHECK']: + $next_step = $_REQUEST['current_step']; + break; + case $mod_strings['LBL_BACK']: + $next_step = $_REQUEST['current_step'] - 1; + break; + case $mod_strings['LBL_NEXT']: + case $mod_strings['LBL_START']: + $next_step = $_REQUEST['current_step'] + 1; + $next_clicked = true; + break; + case 'SilentInstall': + $next_step = 9999; + break; + case 'oc_convert': + $next_step = 9191; + break; + } +} +// Add check here to see if a silent install config file exists; if so then launch silent installer +elseif ( is_file('config_si.php') && empty($sugar_config['installer_locked'])) { + echo << + + + + + + {$mod_strings['LBL_WIZARD_TITLE']} {$mod_strings['LBL_TITLE_WELCOME']} {$setup_sugar_version} {$mod_strings['LBL_WELCOME_SETUP_WIZARD']} + + + + + + + + + + + + + + + + + + + +
            {$mod_strings['LBL_HELP']}
            +

            + SugarCRM +

            + {$mod_strings['LBL_TITLE_WELCOME']} {$setup_sugar_version} {$mod_strings['LBL_WELCOME_SETUP_WIZARD']}
            SugarCRM +
            Sugar Themes
            {$mod_strings['LBL_LAUNCHING_SILENT_INSTALL']}
            + + +EOHTML; + die(); +} + + + +$exclude_files = array('register.php','download_modules.php'); +if(isset($next_step) && isset($workflow[$next_step]) && !in_array($workflow[$next_step],$exclude_files) && isset($sugar_config['installer_locked']) && $sugar_config['installer_locked'] == true) { + $the_file = 'installDisabled.php'; + $disabled_title = $mod_strings['LBL_DISABLED_DESCRIPTION']; + $disabled_title_2 = $mod_strings['LBL_DISABLED_TITLE_2']; + $disabled_text =<<{$mod_strings['LBL_DISABLED_DESCRIPTION']}

            +
            +			'installer_locked' => false,
            +		
            +

            {$mod_strings['LBL_DISABLED_DESCRIPTION_2']}

            + +

            {$mod_strings['LBL_DISABLED_HELP_1']} {$mod_strings['LBL_DISABLED_HELP_2']}.

            +EOQ; +} +else{ +$validation_errors = array(); +// process the data posted +if($next_clicked) { + // store the submitted data because the 'Next' button was clicked + switch($workflow[trim($_REQUEST['current_step'])]) { + case 'welcome.php': + $_SESSION['language'] = $_REQUEST['language']; + $_SESSION['setup_site_admin_user_name'] = 'admin'; + break; + case 'license.php': + $_SESSION['setup_license_accept'] = get_boolean_from_request('setup_license_accept'); + $_SESSION['license_submitted'] = true; + + + // eventually default all vars here, with overrides from config.php + if(is_readable('config.php')) { + global $sugar_config; + include_once('config.php'); + } + + $default_db_type = 'mysql'; + + if(!isset($_SESSION['setup_db_type'])) { + $_SESSION['setup_db_type'] = empty($sugar_config['dbconfig']['db_type']) ? $default_db_type : $sugar_config['dbconfig']['db_type']; + } + + break; + case 'installType.php': + $_SESSION['install_type'] = $_REQUEST['install_type']; + if(isset($_REQUEST['setup_license_key']) && !empty($_REQUEST['setup_license_key'])){ + $_SESSION['setup_license_key'] = $_REQUEST['setup_license_key']; + } + $_SESSION['licenseKey_submitted'] = true; + + + + break; + + case 'systemOptions.php': + $_SESSION['setup_db_type'] = $_REQUEST['setup_db_type']; + $validation_errors = validate_systemOptions(); + if(count($validation_errors) > 0) { + $next_step--; + } + break; + + case 'dbConfig_a.php': + //validation is now done through ajax call to checkDBSettings.php + if(isset($_REQUEST['setup_db_drop_tables'])){ + $_SESSION['setup_db_drop_tables'] = $_REQUEST['setup_db_drop_tables']; + if($_SESSION['setup_db_drop_tables']=== true || $_SESSION['setup_db_drop_tables'] == 'true'){ + $_SESSION['setup_db_create_database'] = false; + } + } + break; + + case 'siteConfig_a.php': + if(isset($_REQUEST['setup_site_url'])){$_SESSION['setup_site_url'] = $_REQUEST['setup_site_url'];} + if(isset($_REQUEST['setup_system_name'])){$_SESSION['setup_system_name'] = $_REQUEST['setup_system_name'];} + $_SESSION['setup_site_admin_user_name'] = $_REQUEST['setup_site_admin_user_name']; + $_SESSION['setup_site_admin_password'] = $_REQUEST['setup_site_admin_password']; + $_SESSION['setup_site_admin_password_retype'] = $_REQUEST['setup_site_admin_password_retype']; + $_SESSION['siteConfig_submitted'] = true; + + $validation_errors = array(); + $validation_errors = validate_siteConfig('a'); + if(count($validation_errors) > 0) { + $next_step--; + } + break; + case 'siteConfig_b.php': + $_SESSION['setup_site_sugarbeet_automatic_checks'] = get_boolean_from_request('setup_site_sugarbeet_automatic_checks'); + + $_SESSION['setup_site_custom_session_path'] = get_boolean_from_request('setup_site_custom_session_path'); + if($_SESSION['setup_site_custom_session_path']){ + $_SESSION['setup_site_session_path'] = $_REQUEST['setup_site_session_path']; + }else{ + $_SESSION['setup_site_session_path'] = ''; + } + + $_SESSION['setup_site_custom_log_dir'] = get_boolean_from_request('setup_site_custom_log_dir'); + if($_SESSION['setup_site_custom_log_dir']){ + $_SESSION['setup_site_log_dir'] = $_REQUEST['setup_site_log_dir']; + }else{ + $_SESSION['setup_site_log_dir'] = '.'; + } + + $_SESSION['setup_site_specify_guid'] = get_boolean_from_request('setup_site_specify_guid'); + if($_SESSION['setup_site_specify_guid']){ + $_SESSION['setup_site_guid'] = $_REQUEST['setup_site_guid']; + }else{ + $_SESSION['setup_site_guid'] = ''; + } + $_SESSION['siteConfig_submitted'] = true; + if(isset($_REQUEST['setup_site_sugarbeet_anonymous_stats'])){ + $_SESSION['setup_site_sugarbeet_anonymous_stats'] = get_boolean_from_request('setup_site_sugarbeet_anonymous_stats'); + }else{ + $_SESSION['setup_site_sugarbeet_anonymous_stats'] = 0; + } + + $validation_errors = array(); + $validation_errors = validate_siteConfig('b'); + if(count($validation_errors) > 0) { + $next_step--; + } + break; +} + } + +if($next_step == 9999) { + $the_file = 'SilentInstall'; +}else if($next_step == 9191) { + $_SESSION['oc_server_url'] = $_REQUEST['oc_server_url']; + $_SESSION['oc_username'] = $_REQUEST['oc_username']; + $_SESSION['oc_password'] = $_REQUEST['oc_password']; + $the_file = 'oc_convert.php'; +} +else{ + $the_file = $workflow[$next_step]; + +} + +switch($the_file) { + case 'welcome.php': + case 'license.php': + // + // Check to see if session variables are working properly + // + $_SESSION['test_session'] = 'sessions are available'; + @session_write_close(); + unset($_SESSION['test_session']); + @session_start(); + + if(!isset($_SESSION['test_session'])) + { + $the_file = 'installDisabled.php'; + // PHP.ini location - + $phpIniLocation = get_cfg_var("cfg_file_path"); + $disabled_title = $mod_strings['LBL_SESSION_ERR_TITLE']; + $disabled_title_2 = $mod_strings['LBL_SESSION_ERR_TITLE']; + $disabled_text = $mod_strings['LBL_SESSION_ERR_DESCRIPTION']."
            {$phpIniLocation}
            "; + break; + } + // check to see if installer has been disabled + if(is_readable('config.php') && (filesize('config.php') > 0)) { + include_once('config.php'); + + if(!isset($sugar_config['installer_locked']) || $sugar_config['installer_locked'] == true) { + $the_file = 'installDisabled.php'; + $disabled_title = $mod_strings['LBL_DISABLED_DESCRIPTION']; + $disabled_title_2 = $mod_strings['LBL_DISABLED_TITLE_2']; + $disabled_text =<<{$mod_strings['LBL_DISABLED_DESCRIPTION']}

            +
            +						'installer_locked' => false,
            +					
            +

            {$mod_strings['LBL_DISABLED_DESCRIPTION_2']}

            + +

            {$mod_strings['LBL_DISABLED_HELP_1']} {$mod_strings['LBL_DISABLED_HELP_2']}.

            +EOQ; + //if this is an offline client installation but the conversion did not succeed, + //then try to convert again + if(isset($sugar_config['disc_client']) && $sugar_config['disc_client'] == true && isset($sugar_config['oc_converted']) && $sugar_config['oc_converted'] == false) { + header('Location: index.php?entryPoint=oc_convert&first_time=true'); + exit (); + } + } + } + break; + case 'register.php': + session_unset(); + break; + case 'SilentInstall': + $si_errors = false; + pullSilentInstallVarsIntoSession(); + $validation_errors = validate_dbConfig('a'); + if(count($validation_errors) > 0) { + $the_file = 'dbConfig_a.php'; + $si_errors = true; + } + $validation_errors = validate_siteConfig('a'); + if(count($validation_errors) > 0) { + $the_file = 'siteConfig_a.php'; + $si_errors = true; + } + $validation_errors = validate_siteConfig('b'); + if(count($validation_errors) > 0) { + $the_file = 'siteConfig_b.php'; + $si_errors = true; + } + + if(!$si_errors){ + $the_file = 'performSetup.php'; + } + //since this is a SilentInstall we still need to make sure that + //the appropriate files are writable + // config.php + make_writable('./config.php'); + + // custom dir + make_writable('./custom'); + + // modules dir + recursive_make_writable('./modules'); + + // data dir + make_writable('./data'); + make_writable('./data/upload'); + + // cache dir + make_writable('./cache/custom_fields'); + make_writable('./cache/dyn_lay'); + make_writable('./cache/images'); + make_writable('./cache/import'); + make_writable('./cache/layout'); + make_writable('./cache/pdf'); + make_writable('./cache/upload'); + make_writable('./cache/xml'); + + // check whether we're getting this request from a command line tool + // we want to output brief messages if we're outputting to a command line tool + $cli_mode = false; + if(isset($_REQUEST['cli']) && ($_REQUEST['cli'] == 'true')) { + $_SESSION['cli'] = true; + // if we have errors, just shoot them back now + if(count($validation_errors) > 0) { + foreach($validation_errors as $error) { + print($mod_strings['ERR_ERROR_GENERAL']."\n"); + print(" " . $error . "\n"); + print("Exit 1\n"); + exit(1); + } + } + } + break; + } +} + + +$the_file = clean_string($the_file, 'FILE'); +// change to require to get a good file load error message if the file is not available. +require('install/' . $the_file); + +?> \ No newline at end of file diff --git a/install/TeamDemoData.php b/install/TeamDemoData.php new file mode 100644 index 00000000..f41f8db6 --- /dev/null +++ b/install/TeamDemoData.php @@ -0,0 +1,191 @@ + 'seed_jim_id', + 'sarah' => 'seed_sarah_id', + 'sally' => 'seed_sally_id', + 'max' => 'seed_max_id', + 'will' => 'seed_will_id', + 'chris' => 'seed_chris_id', + /* + * Pending fix of demo data mechanism + 'jim' => 'jim00000-0000-0000-0000-000000000000', + 'sarah' => 'sarah000-0000-0000-0000-000000000000', + 'sally' => 'sally000-0000-0000-0000-000000000000', + 'max' => 'max00000-0000-0000-0000-000000000000', + 'will' => 'will0000-0000-0000-0000-000000000000', + 'chris' => 'chris000-0000-0000-0000-000000000000', + */ + ); + + /** + * Constructor for creating demo data for teams + */ + function TeamDemoData($seed_team, $large_scale_test = false) + { + $this->_team = $seed_team; + $this->_large_scale_test = $large_scale_test; + } + + /** + * + */ + function create_demo_data() { + global $current_language; + global $sugar_demodata; + foreach($sugar_demodata['teams'] as $v) + { + if (!$this->_team->retrieve($v['team_id'])) + $this->_team->create_team($v['name'], $v['description'], $v['team_id']); + } + + if($this->_large_scale_test) + { + $team_list = $this->_seed_data_get_team_list(); + foreach($team_list as $team_name) + { + $this->_quick_create($team_name); + } + } + + $this->add_users_to_team(); + } + + function add_users_to_team() { + // Create the west team memberships + $this->_team->retrieve("West"); + $this->_team->add_user_to_team($this->guids['sarah']); + $this->_team->add_user_to_team($this->guids['sally']); + $this->_team->add_user_to_team($this->guids["max"]); + + // Create the east team memberships + $this->_team->retrieve("East"); + $this->_team->add_user_to_team($this->guids["will"]); + $this->_team->add_user_to_team($this->guids['chris']); + } + + /** + * + */ + function get_random_team() + { + $team_list = $this->_seed_data_get_team_list(); + $team_list_size = count($team_list); + $random_index = mt_rand(0,$team_list_size-1); + + return $team_list[$random_index]; + } + + /** + * + */ + function get_random_teamset() + { + $team_list = $this->_seed_data_get_teamset_list(); + $team_list_size = count($team_list); + $random_index = mt_rand(0,$team_list_size-1); + + return $team_list[$random_index]; + } + + + /** + * + */ + function _seed_data_get_teamset_list() + { + $teamsets = Array(); + $teamsets[] = array("East", "West"); + $teamsets[] = array("East", "West", "1"); + $teamsets[] = array("West", "East"); + $teamsets[] = array("West", "East", "1"); + $teamsets[] = array("1", "East"); + $teamsets[] = array("1", "West"); + return $teamsets; + } + + + /** + * + */ + function _seed_data_get_team_list() + { + $teams = Array(); +//bug 28138 todo + $teams[] = "north"; + $teams[] = "south"; + $teams[] = "left"; + $teams[] = "right"; + $teams[] = "in"; + $teams[] = "out"; + $teams[] = "fly"; + $teams[] = "walk"; + $teams[] = "crawl"; + $teams[] = "pivot"; + $teams[] = "money"; + $teams[] = "dinero"; + $teams[] = "shadow"; + $teams[] = "roof"; + $teams[] = "sales"; + $teams[] = "pillow"; + $teams[] = "feather"; + + return $teams; + } + + /** + * + */ + function _quick_create($name) + { + if (!$this->_team->retrieve($name)) + { + $this->_team->create_team($name, $name, $name); + } + } + + +} +?> diff --git a/install/UploadLangFileCheck.php b/install/UploadLangFileCheck.php new file mode 100644 index 00000000..8a289998 --- /dev/null +++ b/install/UploadLangFileCheck.php @@ -0,0 +1,87 @@ +decode(html_entity_decode($_REQUEST['file_name'])); + + if(isset($file_name['jsonObject']) && $file_name['jsonObject'] != null){ + $file_name = $file_name['jsonObject']; + } +*/ + +$file_name = $_REQUEST['file_name']; +$filesize = ''; +if(file_exists($file_name)){ + $filesize =filesize($file_name); +} + +//$GLOBALS['log']->fatal($file_name); +$response = ''; + +//$GLOBALS['log']->fatal('file name '.$file_name); +//$GLOBALS['log']->fatal('file size loaded '.filesize($file_name)); + + +//if($filesize > ini_get("upload_max_filesize")) + +//$GLOBALS['log']->fatal(substr(ini_get("upload_max_filesize"), 0, strlen( ini_get("upload_max_filesize")) - 1)); +//get the file size defined in php.ini +//$uploadSizeIni = substr(ini_get("upload_max_filesize"), 0, strlen( ini_get("upload_max_filesize")) - 1); +//$GLOBALS['log']->fatal('Upload php setting Size '.return_bytes(ini_get("upload_max_filesize"))); +if($filesize != null){ + if(($filesize > return_bytes(ini_get("upload_max_filesize"))) || ($filesize > return_bytes(ini_get("post_max_size")))){ + $response=$filesize; + //$response= ""; + } +} + +if (!empty($response)) { + echo $response; +} +sugar_cleanup(); +exit(); diff --git a/install/UserDemoData.php b/install/UserDemoData.php new file mode 100644 index 00000000..0ca7be32 --- /dev/null +++ b/install/UserDemoData.php @@ -0,0 +1,188 @@ + 'seed_jim_id', + 'sarah' => 'seed_sarah_id', + 'sally' => 'seed_sally_id', + 'max' => 'seed_max_id', + 'will' => 'seed_will_id', + 'chris' => 'seed_chris_id', + /* + * Pending fix of demo data mechanism + 'jim' => 'jim00000-0000-0000-0000-000000000000', + 'sarah' => 'sarah000-0000-0000-0000-000000000000', + 'sally' => 'sally000-0000-0000-0000-000000000000', + 'max' => 'max00000-0000-0000-0000-000000000000', + 'will' => 'will0000-0000-0000-0000-000000000000', + 'chris' => 'chris000-0000-0000-0000-000000000000', + */ + ); + + /** + * Constructor for creating user demo data + */ + function UserDemoData($seed_user, $large_scale_test = false) + { + // use a seed user so it does not have to be known which file to + // include the User class from + $this->_user = $seed_user; + $this->_large_scale_test = $large_scale_test; + } + + /** + * + */ + function create_demo_data() + { + global $current_language; + global $sugar_demodata; + foreach($sugar_demodata['users'] as $v) + { + $this->_create_seed_user($v['id'], $v['last_name'], $v['first_name'], $v['user_name'], $v['title'], $v['is_admin'], $v['reports_to'], $v['reports_to_name'], $v['email']); + + } + if($this->_large_scale_test) { + $user_list = $this->_seed_data_get_user_list(); + foreach($user_list as $user_name) + { + $this->_quick_create_user($user_name); + } + } + } + + + /** + * Create a user in the seed data. + */ + function _create_seed_user($id, $last_name, $first_name, $user_name, + $title, $is_admin, $reports_to, $reports_to_name, $email) + { + $u = new User(); + + $u->id=$id; + $u->new_with_id = true; + $u->last_name = $last_name; + $u->first_name = $first_name; + $u->user_name = $user_name; + $u->title = $title; + $u->status = 'Active'; + $u->employee_status = 'Active'; + $u->is_admin = $is_admin; + //$u->user_password = $u->encrypt_password($user_name); + $u->user_hash = strtolower(md5($user_name)); + $u->reports_to_id = $reports_to; + $u->reports_to_name = $reports_to_name; + //$u->email1 = $email; + $u->emailAddress->addAddress($email, true); + $u->emailAddress->addAddress("reply.".$email, false, true); + $u->emailAddress->addAddress("alias.".$email); + + // bug 15371 tyoung set a user preference so that Users/DetailView.php can find something without repeatedly querying the db in vain + $u->setPreference('max_tabs','7'); + $u->savePreferencesToDB(); + + + $u->picture = $this->_copy_user_image($id); + + $u->save(); + } + + /** + * + */ + function _seed_data_get_user_list() + { + $users = Array(); +//bug 28138 todo + $users[] = "north"; + $users[] = "south"; + $users[] = "east"; + $users[] = "west"; + $users[] = "left"; + $users[] = "right"; + $users[] = "in"; + $users[] = "out"; + $users[] = "fly"; + $users[] = "walk"; + $users[] = "crawl"; + $users[] = "pivot"; + $users[] = "money"; + $users[] = "dinero"; + $users[] = "shadow"; + $users[] = "roof"; + $users[] = "sales"; + $users[] = "pillow"; + $users[] = "feather"; + + return $users; + } + + /** + * + */ + function _quick_create_user($name) + { + global $sugar_demodata; + if (!$this->_user->retrieve($name.'_id')) + { + $this->_create_seed_user("{$name}_id", $name, $name, $name, + $sugar_demodata['users'][0]['title'], $sugar_demodata['users'][0]['is_admin'], "seed_jim_id", $sugar_demodata['users'][0]['last_name'].", ".$sugar_demodata['users'][0]['first_name'], $sugar_demodata['users'][0]['email']); + } + } + + function _copy_user_image($id) { + global $sugar_config; + $picture_file = create_guid(); + $file = "include/images/".$id.".gif"; + $newfile = $sugar_config['upload_dir'].$picture_file; + if (!copy($file, $newfile)) { + global $app_strings; + $GLOBALS['log']->fatal(string_format($app_strings['ERR_FILE_NOT_FOUND'], array($file))); + + } + return $picture_file; + } + +} +?> diff --git a/install/checkDBSettings.php b/install/checkDBSettings.php new file mode 100644 index 00000000..b347334c --- /dev/null +++ b/install/checkDBSettings.php @@ -0,0 +1,571 @@ + 0 ){ + installLog("Basic form info is INVALID, exit Process."); + return printErrors($errors); + }else{ + installLog("Basic form info is valid, continuing Process."); + } + + // test the account that will talk to the db if we're not creating it + if( $_SESSION['setup_db_sugarsales_user'] != '' && !$_SESSION['setup_db_create_sugarsales_user'] ){ + if( $_SESSION['setup_db_type'] == 'mysql' ){ + installLog("testing with mysql"); + if(isset($_SESSION['mysql_type']) && $_SESSION['mysql_type'] == 'mysqli'){ + installLog("MySQLI library detected"); + } + + if(isset($_SESSION['mysql_type'])){ + $host_name = getHostPortFromString($_SESSION['setup_db_host_name']); + if(empty($host_name)){ + $link = @mysqli_connect( $_SESSION['setup_db_host_name'], $_SESSION['setup_db_sugarsales_user'], $_SESSION['setup_db_sugarsales_password']); + }else{ + $link = @mysqli_connect( $host_name[0], $_SESSION['setup_db_sugarsales_user'], $_SESSION['setup_db_sugarsales_password'], null, $host_name[1]); + } + }else{ + $link = @mysql_connect( $_SESSION['setup_db_host_name'], + $_SESSION['setup_db_sugarsales_user'], + $_SESSION['setup_db_sugarsales_password'] ); + } + + if( !$link ){ + installLog("Could not make Connection using host: {$_SESSION['setup_db_host_name']}, usr: {$_SESSION['setup_db_sugarsales_user']}"); + if(isset($_SESSION['mysql_type'])){ + $errno = mysqli_connect_errno(); + $error = mysqli_connect_error(); + }else{ + $errno = mysql_errno(); + $error = mysql_error(); + } + + $errors['ERR_DB_LOGIN_FAILURE'] = $mod_strings['ERR_DB_LOGIN_FAILURE_MYSQL']." $errno: $error)."; + installLog("ERROR:: {$errors['ERR_DB_LOGIN_FAILURE']}"); + } + else{ + installLog("Connection made using host: {$_SESSION['setup_db_host_name']}, usr: {$_SESSION['setup_db_sugarsales_user']}"); + if(isset($_SESSION['mysql_type'])){ + mysqli_close($link ); + }else{ + mysql_close($link ); + } + } + } elseif( $_SESSION['setup_db_type'] == 'mssql' ) { + installLog("testing with mssql"); + $connect_host = ""; + $_SESSION['setup_db_host_instance'] = trim($_SESSION['setup_db_host_instance']); + + if (empty($_SESSION['setup_db_host_instance'])){ + $connect_host = $_SESSION['setup_db_host_name']; + }else{ + $connect_host = $_SESSION['setup_db_host_name']. "\\" . $_SESSION['setup_db_host_instance']; + } + if(isset($_SESSION['mssql_type'])){ + $connect_params = array( + "UID"=>$_SESSION['setup_db_sugarsales_user'], + "PWD"=>$_SESSION['setup_db_sugarsales_password'], + "MultipleActiveResultSets"=>false, + ); + $link = sqlsrv_connect( $connect_host , $connect_params); + } + else { + $link = @mssql_connect( $connect_host , + $_SESSION['setup_db_sugarsales_user'], + $_SESSION['setup_db_sugarsales_password'] ); + } + if( !$link ) { + $errors['ERR_DB_LOGIN_FAILURE'] = $mod_strings['ERR_DB_LOGIN_FAILURE_MSSQL']; + installLog("ERROR:: {$errors['ERR_DB_LOGIN_FAILURE']}"); + } else { + installLog("Connection made using host: {$_SESSION['setup_db_host_name']}, usr: {$_SESSION['setup_db_sugarsales_user']}"); + if(isset($_SESSION['mssql_type'])){ + sqlsrv_close($link ); + } + else { + mssql_close($link ); + } + } + // Bug 29855 - Check to see if given db name is valid + if (preg_match("/[\"\'\*\/\\?\:\\<\>\-]+/i", $_SESSION['setup_db_database_name']) ) { + $errors['ERR_DB_MSSQL_DB_NAME'] = $mod_strings['ERR_DB_MSSQL_DB_NAME_INVALID']; + installLog("ERROR:: {$errors['ERR_DB_MSSQL_DB_NAME']}"); + } + + } elseif( $_SESSION['setup_db_type'] == 'oci8' ){ + } + } + + // privileged account tests + if( $_SESSION['setup_db_admin_user_name'] == '' ){ + $errors['ERR_DB_PRIV_USER'] = $mod_strings['ERR_DB_PRIV_USER']; + installLog("ERROR:: {$errors['ERR_DB_PRIV_USER']}"); + } + else { + installLog("Testing priviliged account..."); + if( $_SESSION['setup_db_type'] == 'mysql' ){ + if(isset($_SESSION['mysql_type'])){ + $host_name = getHostPortFromString($_SESSION['setup_db_host_name']); + if(empty($host_name)){ + $link = @mysqli_connect( $_SESSION['setup_db_host_name'], $_SESSION['setup_db_admin_user_name'], $_SESSION['setup_db_admin_password']); + }else{ + $link = @mysqli_connect( $host_name[0], $_SESSION['setup_db_admin_user_name'], $_SESSION['setup_db_admin_password'], null, $host_name[1]); + } + }else{ + $link = @mysql_connect( $_SESSION['setup_db_host_name'], + $_SESSION['setup_db_admin_user_name'], + $_SESSION['setup_db_admin_password'] ); + + } + if( $link ){ + installLog("Connection made for Privileged admin account using host: {$_SESSION['setup_db_host_name']}, usr: {$_SESSION['setup_db_admin_user_name']}"); + // database admin credentials are valid--can continue check on stuff + if(isset($_SESSION['mysql_type'])){ + $db_selected = @mysqli_select_db($link, $_SESSION['setup_db_database_name']); + }else{ + $db_selected = @mysql_select_db($_SESSION['setup_db_database_name'], $link); + } + if($silent==false && $db_selected && $_SESSION['setup_db_create_database'] && (!isset($_SESSION['setup_db_drop_tables']) || !$_SESSION['setup_db_drop_tables'])){ + $errStr = $mod_strings['ERR_DB_EXISTS_PROCEED']; + $errors['ERR_DB_EXISTS_PROCEED'] = $errStr; + installLog("ERROR:: {$errors['ERR_DB_EXISTS_PROCEED']}"); + } + else if( !$db_selected && !$_SESSION['setup_db_create_database'] ){ + $errors['ERR_DB_EXISTS_NOT'] = $mod_strings['ERR_DB_EXISTS_NOT']; + installLog("ERROR:: {$errors['ERR_DB_EXISTS_NOT']}"); + } + + // test for upgrade and inform user about the upgrade wizard + if( $db_selected ){ + installLog("DB Selected, will reuse {$_SESSION['setup_db_database_name']}"); + if(isset($_SESSION['mysql_type'])){ + $config_query = "SHOW TABLES LIKE 'config'"; + $config_result = mysqli_query($link , $config_query); + $config_table_exists = (mysqli_num_rows( $config_result ) == 1); + mysqli_free_result( $config_result ); + include('sugar_version.php'); + if( !$_SESSION['setup_db_drop_tables'] && $config_table_exists ){ + $query = "SELECT COUNT(*) FROM config WHERE category='info' AND name='sugar_version' AND VALUE LIKE '$sugar_db_version'"; + $result = mysqli_query( $link , $query ); + $row = mysqli_fetch_row( $result ); + if($row[0] != 1 && $silent==false) { + $errors['ERR_DB_EXISTS_WITH_CONFIG'] = $mod_strings['ERR_DB_EXISTS_WITH_CONFIG']; + installLog("ERROR:: {$errors['ERR_DB_EXISTS_WITH_CONFIG']}"); + } + mysqli_free_result($result); + } + }else{ + $config_query = "SHOW TABLES LIKE 'config'"; + $config_result = mysql_query( $config_query, $link ); + $config_table_exists = (mysql_num_rows( $config_result ) == 1); + mysql_free_result( $config_result ); + include('sugar_version.php'); + if( !$_SESSION['setup_db_drop_tables'] && $config_table_exists ){ + $query = "SELECT COUNT(*) FROM config WHERE category='info' AND name='sugar_version' AND VALUE LIKE '$sugar_db_version'"; + $result = mysql_query( $query, $link ); + $row = mysql_fetch_row( $result ); + if($row[0] != 1 && $silent==false) { + $errors['ERR_DB_EXISTS_WITH_CONFIG'] = $mod_strings['ERR_DB_EXISTS_WITH_CONFIG']; + installLog("ERROR:: {$errors['ERR_DB_EXISTS_WITH_CONFIG']}"); + } + mysql_free_result($result); + } + } + + }else{ + installLog("DB not selected, will create {$_SESSION['setup_db_database_name']}"); + } + + + // check for existing SugarCRM database user if create flag is set, + //user name has been given, and database has been selected (reusing db, not creating new one) + if($_SESSION['setup_db_create_sugarsales_user'] && $_SESSION['setup_db_sugarsales_user'] != '' && $db_selected){ + if(isset($_SESSION['mysql_type'])){ + $mysqli_db_selected = mysqli_select_db($link, 'mysql'); + $user = $_SESSION['setup_db_sugarsales_user']; + $query = "select count(*) from user where User ='$user'"; + $result = mysqli_query($link, $query); + if(!$result){ + $errno = mysqli_connect_errno(); + $error = mysqli_connect_error(); + $errors['ERR_DB_ADMIN'] = $mod_strings['ERR_DB_ADMIN'].$errno. ": {$error})."; + installLog("ERROR:: {$errors['ERR_DB_ADMIN']}"); + }else{ + $row = mysqli_fetch_row($result); + if($row[0] == 1){ + $errors['ERR_DB_USER_EXISTS'] = $mod_strings['ERR_DB_USER_EXISTS']; + installLog("ERROR:: {$errors['ERR_DB_USER_EXISTS']}"); + } + mysqli_free_result($result); + } + }else{ + $mysql_db_selected = mysql_select_db('mysql', $link); + $user = $_SESSION['setup_db_sugarsales_user']; + $query = "select count(*) from user where User ='$user'"; + $result = mysql_query($query, $link); + if(!$result){ + $errno = mysql_errno(); + $error = mysql_error(); + $errors['ERR_DB_ADMIN'] = $mod_strings['ERR_DB_ADMIN'].$errno. ": {$error})."; + installLog("ERROR:: {$errors['ERR_DB_ADMIN']}"); + }else{ + $row = mysql_fetch_row($result); + if($row[0] == 1){ + $errors['ERR_DB_USER_EXISTS'] = $mod_strings['ERR_DB_USER_EXISTS']; + installLog("ERROR:: {$errors['ERR_DB_USER_EXISTS']}"); + //do not throw errors, reuse existing user + //$_SESSION['setup_db_create_sugarsales_user'] = 0; + } + mysql_free_result($result); + } + } + + } + + // check mysql minimum version requirement + $db_version = getMysqlVersion($link); + if(version_compare($db_version, '4.1.2') < 0) { + $errors['ERR_DB_MYSQL_VERSION1'] = $mod_strings['ERR_DB_MYSQL_VERSION1'].$db_version.$mod_strings['ERR_DB_MYSQL_VERSION2']; + installLog("ERROR:: {$errors['ERR_DB_MYSQL_VERSION1']}"); + }else{ + installLog("Passed DB Version check, version is {$db_version}"); + } + + if(isset($_SESSION['mysql_type'])){ + mysqli_close($link); + }else{ + mysql_close($link); + } + } + else { // dblink was bad + if(isset($_SESSION['mysql_type'])){ + $errno = mysqli_connect_errno(); + $error = mysqli_connect_error(); + }else{ + $errno = mysql_errno(); + $error = mysql_error(); + } + $errors['ERR_DB_ADMIN'] = $mod_strings['ERR_DB_ADMIN'].$errno. ": {$error})."; + installLog("ERROR:: {$errors['ERR_DB_ADMIN']}"); + } + + }else if( $_SESSION['setup_db_type'] == 'mssql' ){ + installLog("Testing priviliged account..."); + $connect_host = ""; + $_SESSION['setup_db_host_instance'] = trim($_SESSION['setup_db_host_instance']); + + if (empty($_SESSION['setup_db_host_instance'])){ + $connect_host = $_SESSION['setup_db_host_name']; + }else{ + $connect_host = $_SESSION['setup_db_host_name']. "\\" . $_SESSION['setup_db_host_instance']; + } + if(isset($_SESSION['mssql_type'])){ + $connect_params = array( + "UID"=>$_SESSION['setup_db_sugarsales_user'], + "PWD"=>$_SESSION['setup_db_sugarsales_password'], + "MultipleActiveResultSets"=>false, + ); + $link = sqlsrv_connect( $connect_host , $connect_params); + } + else { + $link = @mssql_connect( $connect_host , + $_SESSION['setup_db_admin_user_name'], + $_SESSION['setup_db_admin_password'] ); + } + if( $link ){ + installLog("Connection made for Privileged admin account using host: {$_SESSION['setup_db_host_name']}, usr: {$_SESSION['setup_db_admin_user_name']}"); + // database admin credentials are valid--can continue check on stuff + $tbl_exists_qry = "SELECT name FROM master..sysdatabases WHERE name = N'{$_SESSION['setup_db_database_name']}'"; + if(isset($_SESSION['mssql_type'])) + $res = sqlsrv_query($link,$tbl_exists_qry); + else + $res = mssql_query($tbl_exists_qry); + $db_exists = false; + if ( isset($_SESSION['mssql_type']) && sqlsrv_fetch( $res) == 1){$db_exists = true; + installLog("DB Exists and selected, will reuse {$_SESSION['setup_db_database_name']}"); + }elseif ( !isset($_SESSION['mssql_type']) && mssql_num_rows( $res) == 1){$db_exists = true; + installLog("DB Exists and selected, will reuse {$_SESSION['setup_db_database_name']}"); + }else{ + installLog("No DB Selected, will create {$_SESSION['setup_db_database_name']}"); + } + if($silent==false && $db_exists && $_SESSION['setup_db_create_database'] && (!isset($_SESSION['setup_db_drop_tables']) || !$_SESSION['setup_db_drop_tables'])){ + $errStr = $mod_strings['ERR_DB_EXISTS_PROCEED']; + $errors['ERR_DB_EXISTS_PROCEED'] = $errStr; + installLog("ERROR:: {$errors['ERR_DB_EXISTS_PROCEED']}"); + } + else if( !$db_exists && !$_SESSION['setup_db_create_database'] ){ + $errors['ERR_DB_EXISTS_NOT'] = $mod_strings['ERR_DB_EXISTS_NOT']; + installLog("ERROR:: {$errors['ERR_DB_EXISTS_NOT']}"); + } + + // check for existing SugarCRM database user if create flag is set, + //user name has been given, and database has been selected (reusing db, not creating new one) + if($_SESSION['setup_db_create_sugarsales_user'] && $_SESSION['setup_db_sugarsales_user'] != ''){ + if(isset($_SESSION['mssql_type'])) { + $mssql_db_selected = (bool) sqlsrv_query($link,'USE master'); + $user = $_SESSION['setup_db_sugarsales_user']; + $query = "select count(*) from sys.sql_logins where name ='$user'"; + $result = sqlsrv_query($link, $query); + if(!$result){ + $errors['ERR_DB_ADMIN'] = $mod_strings['ERR_DB_ADMIN']; + installLog("ERROR:: {$errors['ERR_DB_ADMIN']}"); + }else{ + $row = sqlsrv_fetch_array($result); + if($row[0] == 1){ + $errors['ERR_DB_USER_EXISTS'] = $mod_strings['ERR_DB_USER_EXISTS']; + installLog("ERROR:: {$errors['ERR_DB_USER_EXISTS']}"); + } + sqlsrv_free_stmt($result); + } + } + else { + $mssql_db_selected = mssql_select_db('master', $link); + $user = $_SESSION['setup_db_sugarsales_user']; + $query = "select count(*) from sys.sql_logins where name ='$user'"; + $result = mssql_query($query, $link); + if(!$result){ + $errors['ERR_DB_ADMIN'] = $mod_strings['ERR_DB_ADMIN']; + installLog("ERROR:: {$errors['ERR_DB_ADMIN']}"); + }else{ + $row = mssql_fetch_row($result); + if($row[0] == 1){ + $errors['ERR_DB_USER_EXISTS'] = $mod_strings['ERR_DB_USER_EXISTS']; + installLog("ERROR:: {$errors['ERR_DB_USER_EXISTS']}"); + } + mssql_free_result($result); + } + } + } + + if(isset($_SESSION['mssql_type'])) + sqlsrv_close($link); + else + mssql_close($link); + + } + else { // dblink was bad + $errors['ERR_DB_ADMIN_MSSQL'] = $mod_strings['ERR_DB_ADMIN_MSSQL'].$connect_host; + installLog("ERROR:: {$errors['ERR_DB_ADMIN_MSSQL']}"); + } + + }else if( $_SESSION['setup_db_type'] == 'oci8' ){ + } + } // end of privileged user tests + if($silent){ + return $errors; + }else{ + printErrors($errors); + } + installLog("End DB Check Process *************"); +} + +function printErrors($errors ){ + +global $mod_strings; + if(count($errors) == 0){ + echo 'dbCheckPassed'; + installLog("SUCCESS:: no errors detected!"); + }else if((count($errors) == 1 && isset($errors["ERR_DB_EXISTS_PROCEED"])) || + (count($errors) == 2 && isset($errors["ERR_DB_EXISTS_PROCEED"]) && isset($errors["ERR_DB_EXISTS_WITH_CONFIG"])) ){ + ///throw alert asking to overwwrite db + echo 'preexeest'; + installLog("WARNING:: no errors detected, but DB tables will be dropped!, issuing warning to user"); + }else{ + installLog("FATAL:: errors have been detected! User will not be allowed to continue. Errors are as follow:"); + //print out errors + $validationErr = "

            {$mod_strings['ERR_DBCONF_VALIDATION']}

            "; + $validationErr .= '
              '; + + foreach($errors as $key =>$erMsg){ + if($key != "ERR_DB_EXISTS_PROCEED" && $key != "ERR_DB_EXISTS_WITH_CONFIG"){ + if($_SESSION['dbUSRData'] == 'same' && $key == 'ERR_DB_ADMIN'){ + installLog(".. {$erMsg}"); + break; + } + $validationErr .= '
            • ' . $erMsg . '
            • '; + installLog(".. {$erMsg}"); + } + } + $validationErr .= '
            '; + $validationErr .= '
            '; + + echo $validationErr; + } + +} + + +function copyInputsIntoSession(){ + if(isset($_REQUEST['setup_db_type'])){$_SESSION['setup_db_type'] = $_REQUEST['setup_db_type'];} + if(isset($_REQUEST['setup_db_admin_user_name'])){$_SESSION['setup_db_admin_user_name'] = $_REQUEST['setup_db_admin_user_name'];} + if(isset($_REQUEST['setup_db_admin_password'])){$_SESSION['setup_db_admin_password'] = $_REQUEST['setup_db_admin_password'];} + if(isset($_REQUEST['setup_db_database_name'])){$_SESSION['setup_db_database_name'] = $_REQUEST['setup_db_database_name'];} + if(isset($_REQUEST['setup_db_host_name'])){$_SESSION['setup_db_host_name'] = $_REQUEST['setup_db_host_name'];} + + if(isset($_REQUEST['setup_db_host_instance'])){ + $_SESSION['setup_db_host_instance'] = $_REQUEST['setup_db_host_instance']; + } + + + // on a silent install, copy values from $_SESSION into $_REQUEST + if (isset($_REQUEST['goto']) && $_REQUEST['goto'] == 'SilentInstall') { + if (isset($_SESSION['dbUSRData']) && !empty($_SESSION['dbUSRData'])) + $_REQUEST['dbUSRData'] = $_SESSION['dbUSRData']; + else $_REQUEST['dbUSRData'] = 'same'; + + if (isset($_SESSION['setup_db_sugarsales_user']) && !empty($_SESSION['setup_db_sugarsales_user'])) + $_REQUEST['setup_db_sugarsales_user'] = $_SESSION['setup_db_sugarsales_user']; + else $_REQUEST['dbUSRData'] = 'same'; + + $_REQUEST['setup_db_sugarsales_password'] = $_SESSION['setup_db_sugarsales_password']; + $_REQUEST['setup_db_sugarsales_password_retype'] = $_SESSION['setup_db_sugarsales_password']; + } + + //make sure we are creating or using provided user for app db connections + $_SESSION['setup_db_create_sugarsales_user'] = true;//get_boolean_from_request('setup_db_create_sugarsales_user'); + if( $_SESSION['setup_db_type'] == 'oci8' ){ + //if we are in Oracle Mode, make the admin user/password same as connecting user/password + $_SESSION['setup_db_sugarsales_user'] = $_SESSION['setup_db_admin_user_name']; + $_SESSION['setup_db_sugarsales_password'] = $_SESSION['setup_db_admin_password']; + $_SESSION['setup_db_sugarsales_password_retype'] = $_SESSION['setup_db_sugarsales_password']; + $_SESSION['setup_db_create_sugarsales_user'] = false; + $_SESSION['setup_db_create_database'] = false; + + }//elseif(isset($_SESSION['install_type']) && !empty($_SESSION['install_type']) && strtolower($_SESSION['install_type'])=='typical'){ + else{ + + + //retrieve the value from dropdown in order to know what settings the user + //wants to use for the sugar db user. + + //use provided db admin by default + $_SESSION['dbUSRData'] = 'same'; + + if(isset($_REQUEST['dbUSRData']) && !empty($_REQUEST['dbUSRData'])){ + $_SESSION['dbUSRData'] = $_REQUEST['dbUSRData']; + } + + + if($_SESSION['dbUSRData'] == 'auto'){ + //create user automatically + $_SESSION['setup_db_create_sugarsales_user'] = true; + $_SESSION['setup_db_sugarsales_user'] = "sugar".create_db_user_creds(5); + $_SESSION['setup_db_sugarsales_password'] = create_db_user_creds(10); + $_SESSION['setup_db_sugarsales_password_retype'] = $_SESSION['setup_db_sugarsales_password']; + }elseif($_SESSION['dbUSRData'] == 'provide'){ + //use provided user info + $_SESSION['setup_db_create_sugarsales_user'] = false; + $_SESSION['setup_db_sugarsales_user'] = $_REQUEST['setup_db_sugarsales_user']; + $_SESSION['setup_db_sugarsales_password'] = $_REQUEST['setup_db_sugarsales_password']; + $_SESSION['setup_db_sugarsales_password_retype'] = $_REQUEST['setup_db_sugarsales_password_retype']; + }elseif($_SESSION['dbUSRData'] == 'create'){ + // create user with provided info + $_SESSION['setup_db_create_sugarsales_user'] = true; + $_SESSION['setup_db_sugarsales_user'] = $_REQUEST['setup_db_sugarsales_user']; + $_SESSION['setup_db_sugarsales_password'] = $_REQUEST['setup_db_sugarsales_password']; + $_SESSION['setup_db_sugarsales_password_retype'] = $_REQUEST['setup_db_sugarsales_password_retype']; + }else{ + //Use the same login as provided admin user + $_SESSION['setup_db_create_sugarsales_user'] = false; + $_SESSION['setup_db_sugarsales_user'] = $_SESSION['setup_db_admin_user_name']; + $_SESSION['setup_db_sugarsales_password'] = $_SESSION['setup_db_admin_password']; + $_SESSION['setup_db_sugarsales_retype'] = $_SESSION['setup_db_admin_password']; + } + } + + if(!isset($_SESSION['demoData']) || empty($_SESSION['demoData'])){ + $_SESSION['demoData'] = 'no'; + } + if(isset($_REQUEST['demoData'])){$_SESSION['demoData'] = $_REQUEST['demoData'] ;} + if (isset($_REQUEST['goto']) && $_REQUEST['goto'] == 'SilentInstall' && isset($SESSION['setup_db_drop_tables'])) { + //set up for Oracle Silent Installer + $_REQUEST['setup_db_drop_tables'] = $_SESSION['setup_db_drop_tables'] ; + } + if (isset($_REQUEST['setup_db_drop_tables']) + || ((isset($_REQUEST['goto']) && $_REQUEST['goto'] == 'SilentInstall' && isset($SESSION['setup_db_drop_tables']))) + ){ + $_SESSION['setup_db_drop_tables'] = true; + $_SESSION['setup_db_create_database'] = false; + + }else{ + $_SESSION['setup_db_drop_tables'] = false; + $_SESSION['setup_db_create_database'] = true; + } +} + +//// END PAGEOUTPUT +/////////////////////////////////////////////////////////////////////////////// +?> diff --git a/install/confirmSettings.php b/install/confirmSettings.php new file mode 100644 index 00000000..0b08dd05 --- /dev/null +++ b/install/confirmSettings.php @@ -0,0 +1,591 @@ + + + + + + + {$mod_strings['LBL_WIZARD_TITLE']} {$mod_strings['LBL_CONFIRM_TITLE']} + + + + +
            + + + + + + + + + + + + + + +
            {$mod_strings['LBL_HELP']}
            +

            + SugarCRM +

            + {$mod_strings['LBL_CONFIRM_TITLE']}
            SugarCRM +
            + + + + {$dbType} + {$oci8} + + + + + +EOQ; + +$out .=<< + + + + + + + + + +EOQ; +if($yesNoDropCreate){ + +$out .=<< + + + + +EOQ; + +} + + +if(isset($_SESSION['install_type']) && !empty($_SESSION['install_type']) && $_SESSION['install_type']=='custom'){ +$out .=<< + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +EOQ; +} +/* +if(isset($_SESSION['licenseKey_submitted']) && ($_SESSION['licenseKey_submitted']) + && (isset($GLOBALS['db']) && !empty($GLOBALS['db']))){ +$out .=<< +EOQ; +} +*/ + + +$out .=<< + + + + + + + + + + + + + + + + + + + + + + +EOQ; + + + + + + +$envString = ' + '; + + // PHP VERSION + $envString .=' + + + + + '; + + +//Begin List of already known good variables. These were checked during the initial sys check +// XML Parsing + $envString .=' + + + + + '; + + + +// mbstrings + + $envString .=' + + + + + '; + +// config.php + $envString .=' + + + + + '; + +// custom dir + + + $envString .=' + + + + + '; + + +// modules dir + $envString .=' + + + + + '; + +// data dir + + $envString .=' + + + + + '; + +// cache dir + $error_found = true; + $envString .=' + + + + + '; +// End already known to be good + +// memory limit +$memory_msg = ""; +// CL - fix for 9183 (if memory_limit is enabled we will honor it and check it; otherwise use unlimited) +$memory_limit = ini_get('memory_limit'); +if(empty($memory_limit)){ + $memory_limit = "-1"; +} +if(!defined('SUGARCRM_MIN_MEM')) { + define('SUGARCRM_MIN_MEM', 40); +} +$sugarMinMem = constant('SUGARCRM_MIN_MEM'); +// logic based on: http://us2.php.net/manual/en/ini.core.php#ini.memory-limit +if( $memory_limit == "" ){ // memory_limit disabled at compile time, no memory limit + $memory_msg = "{$mod_strings['LBL_CHECKSYS_MEM_OK']}"; +} elseif( $memory_limit == "-1" ){ // memory_limit enabled, but set to unlimited + $memory_msg = "{$mod_strings['LBL_CHECKSYS_MEM_UNLIMITED']}"; +} else { + $mem_display = $memory_limit; + rtrim($memory_limit, 'M'); + $memory_limit_int = (int) $memory_limit; + $SUGARCRM_MIN_MEM = (int) constant('SUGARCRM_MIN_MEM'); + if( $memory_limit_int < constant('SUGARCRM_MIN_MEM') ){ + $memory_msg = "$memory_limit{$mod_strings['ERR_CHECKSYS_MEM_LIMIT_1']}" . constant('SUGARCRM_MIN_MEM') . "{$mod_strings['ERR_CHECKSYS_MEM_LIMIT_2']}"; + $memory_msg = str_replace('$memory_limit', $mem_display, $memory_msg); + } else { + $memory_msg = "{$mod_strings['LBL_CHECKSYS_OK']} ({$memory_limit})"; + } +} + + $envString .=' + + + + + '; + + // zlib + if(function_exists('gzclose')) { + $zlibStatus = "{$mod_strings['LBL_CHECKSYS_OK']}"; + } else { + $zlibStatus = "{$mod_strings['ERR_CHECKSYS_ZLIB']}"; + } + $envString .=' + + + + + '; + + // zip + if(class_exists("ZipArchive")) { + $zipStatus = "{$mod_strings['LBL_CHECKSYS_OK']}"; + } else { + $zipStatus = "{$mod_strings['ERR_CHECKSYS_ZIP']}"; + } + $envString .=' + + + + + '; + + + + // imap + if(function_exists('imap_open')) { + $imapStatus = "{$mod_strings['LBL_CHECKSYS_OK']}"; + } else { + $imapStatus = "{$mod_strings['ERR_CHECKSYS_IMAP']}"; + } + + $envString .=' + + + + + '; + + + // cURL + if(function_exists('curl_init')) { + $curlStatus = "{$mod_strings['LBL_CHECKSYS_OK']}"; + } else { + $curlStatus = "{$mod_strings['ERR_CHECKSYS_CURL']}"; + } + + $envString .=' + + + + + '; + + + //CHECK UPLOAD FILE SIZE + $upload_max_filesize = ini_get('upload_max_filesize'); + $upload_max_filesize_bytes = return_bytes($upload_max_filesize); + if(!defined('SUGARCRM_MIN_UPLOAD_MAX_FILESIZE_BYTES')){ + define('SUGARCRM_MIN_UPLOAD_MAX_FILESIZE_BYTES', 6 * 1024 * 1024); + } + + if($upload_max_filesize_bytes > constant('SUGARCRM_MIN_UPLOAD_MAX_FILESIZE_BYTES')) { + $fileMaxStatus = "{$mod_strings['LBL_CHECKSYS_OK']}"; + } else { + $fileMaxStatus = "{$mod_strings['ERR_UPLOAD_MAX_FILESIZE']}"; + } + + $envString .=' + + + + + '; + + + + + +// PHP.ini +$phpIniLocation = get_cfg_var("cfg_file_path"); + $envString .=' + + + + + '; + +$out .= $envString; + +$out .=<< + + + + + + + + + '; + + +} + + + + +/////////////////////////////////////////////////////////////////////////////// +//// BEGIN PAGE OUTPUT + +$out =<< + + + + + + {$mod_strings['LBL_WIZARD_TITLE']} {$mod_strings['LBL_DBCONF_TITLE']} + + + + + + + + + +EOQ; +$out .= ''; + +$out2 =<< + + +
            {$mod_strings['LBL_DBCONF_TITLE']}
            {$mod_strings['LBL_DBCONF_DB_NAME']} + {$_SESSION['setup_db_database_name']} {$dbCreate} +
            {$mod_strings['LBL_DBCONF_DB_ADMIN_USER']}{$_SESSION['setup_db_admin_user_name']}
            {$mod_strings['LBL_DBCONF_DEMO_DATA']}{$demoData}
            {$mod_strings['LBL_DBCONF_DB_DROP']}{$yesNoDropCreate}
            {$mod_strings['LBL_SITECFG_TITLE']}
            {$mod_strings['LBL_SITECFG_URL']}{$_SESSION['setup_site_url']}
            {$mod_strings['LBL_SITECFG_SUGAR_UPDATES']}
            {$mod_strings['LBL_SITECFG_SUGAR_UP']}{$yesNoSugarUpdates}
            {$mod_strings['LBL_SITECFG_SITE_SECURITY']}
            {$mod_strings['LBL_SITECFG_CUSTOM_SESSION']}?{$yesNoCustomSession}
            {$mod_strings['LBL_SITECFG_CUSTOM_LOG']}?{$yesNoCustomLog}
            {$mod_strings['LBL_SITECFG_CUSTOM_ID']}?{$yesNoCustomId}
            {$mod_strings['LBL_SYSTEM_CREDS']}
            {$mod_strings['LBL_DBCONF_DB_USER']} + {$_SESSION['setup_db_sugarsales_user']} +
            {$mod_strings['LBL_DBCONF_DB_PASSWORD']} + {$mod_strings['LBL_HIDDEN']} + +
            {$mod_strings['LBL_SITECFG_ADMIN_Name']} + Admin +
            {$mod_strings['LBL_SITECFG_ADMIN_PASS']} + {$mod_strings['LBL_HIDDEN']} + +
            '.$mod_strings['LBL_SYSTEM_ENV'].'
            '.$mod_strings['LBL_CHECKSYS_PHPVER'].''.constant('PHP_VERSION').'
            '.$mod_strings['LBL_CHECKSYS_XML'].''.$mod_strings['LBL_CHECKSYS_OK'].'
            '.$mod_strings['LBL_CHECKSYS_MBSTRING'].''.$mod_strings['LBL_CHECKSYS_OK'].'
            '.$mod_strings['LBL_CHECKSYS_CONFIG'].''.$mod_strings['LBL_CHECKSYS_OK'].'
            '.$mod_strings['LBL_CHECKSYS_CUSTOM'].''.$mod_strings['LBL_CHECKSYS_OK'].'
            '.$mod_strings['LBL_CHECKSYS_MODULE'].''.$mod_strings['LBL_CHECKSYS_OK'].'
            '.$mod_strings['LBL_CHECKSYS_DATA'].''.$mod_strings['LBL_CHECKSYS_OK'].'
            '.$mod_strings['LBL_CHECKSYS_CACHE'].''.$mod_strings['LBL_CHECKSYS_OK'].'
            '.$mod_strings['LBL_CHECKSYS_MEM'].''.$memory_msg.'
            '.$mod_strings['LBL_CHECKSYS_ZLIB'].''.$zlibStatus.'
            '.$mod_strings['LBL_CHECKSYS_ZIP'].''.$zipStatus.'
            '.$mod_strings['LBL_CHECKSYS_IMAP'].''.$imapStatus.'
            '.$mod_strings['LBL_CHECKSYS_CURL'].''.$curlStatus.'
            '.$mod_strings['LBL_UPLOAD_MAX_FILESIZE_TITLE'].''.$fileMaxStatus.'
            '.$mod_strings['LBL_CHECKSYS_PHP_INI'].''.$phpIniLocation.'
            + + +EOQ; + +// CRON Settings +if ( !isset($sugar_config['default_language']) ) + $sugar_config['default_language'] = $_SESSION['default_language']; +if ( !isset($sugar_config['cache_dir']) ) + $sugar_config['cache_dir'] = $sugar_config_defaults['cache_dir']; +if ( !isset($sugar_config['site_url']) ) + $sugar_config['site_url'] = $_SESSION['setup_site_url']; +if ( !isset($sugar_config['translation_string_prefix']) ) + $sugar_config['translation_string_prefix'] = $sugar_config_defaults['translation_string_prefix']; +$mod_strings_scheduler = return_module_language($GLOBALS['current_language'], 'Schedulers'); +$error = ''; + +if (!isset($_SERVER['Path'])) { + $_SERVER['Path'] = getenv('Path'); +} +if(is_windows()) { +if(isset($_SERVER['Path']) && !empty($_SERVER['Path'])) { // IIS IUSR_xxx may not have access to Path or it is not set + if(!strpos($_SERVER['Path'], 'php')) { + $error = ''.$mod_strings_scheduler['LBL_NO_PHP_CLI'].''; + } +} +$cronString = ' + + + +'; +} else { +if(isset($_SERVER['Path']) && !empty($_SERVER['Path'])) { // some Linux servers do not make this available + if(!strpos($_SERVER['PATH'], 'php')) { + $error = ''.$mod_strings_scheduler['LBL_NO_PHP_CLI'].''; + } +} +$cronString = ' + + + +'; +} + +$out .= $cronString; + +$out .=<< + + + + + + + + +
             
            + + '.$mod_strings_scheduler['LBL_CRON_WINDOWS_DESC'].'
            +
            + cd '.realpath('./').'
            + php.exe -f cron.php +
            '.$error.' +
            + + '.$mod_strings_scheduler['LBL_CRON_INSTRUCTIONS_LINUX'].' + + '.$mod_strings_scheduler['LBL_CRON_LINUX_DESC'].'
            + *    *    *    *    *     + cd '.realpath('./').'; php -f cron.php > /dev/null 2>&1 +
            '.$error.' +
            +   +
            +
            + + + + + + +
            + + + + + + +
            +
            + +
            + + + + + +EOQ; +echo $out; + +?> + + + + + + + + + diff --git a/install/data/disc_client.php b/install/data/disc_client.php new file mode 100644 index 00000000..0b514cab --- /dev/null +++ b/install/data/disc_client.php @@ -0,0 +1,57 @@ + diff --git a/install/dbConfig.js b/install/dbConfig.js new file mode 100644 index 00000000..b9084958 --- /dev/null +++ b/install/dbConfig.js @@ -0,0 +1,40 @@ +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ +function togglePasswordRetypeRequired(){var theForm=document.forms[0];var elem=document.getElementById('password_retype_required');if(theForm.setup_db_create_sugarsales_user.checked){elem.style.display='';theForm.setup_db_username_is_privileged.checked="";theForm.setup_db_username_is_privileged.disabled="disabled";toggleUsernameIsPrivileged();} +else{elem.style.display='none';theForm.setup_db_username_is_privileged.disabled="";}} +function toggleDropTables(){var theForm=document.forms[0];if(theForm.setup_db_create_database.checked){theForm.setup_db_drop_tables.checked='';theForm.setup_db_drop_tables.disabled="disabled";} +else{theForm.setup_db_drop_tables.disabled='';}} +function toggleUsernameIsPrivileged(){var theForm=document.forms[0];var elem=document.getElementById('privileged_user_info');if(theForm.setup_db_username_is_privileged.checked){elem.style.display='none';} +else{elem.style.display='';}} \ No newline at end of file diff --git a/install/dbConfig_a.php b/install/dbConfig_a.php new file mode 100644 index 00000000..eb62a20d --- /dev/null +++ b/install/dbConfig_a.php @@ -0,0 +1,465 @@ +
            '.$mod_strings['LBL_DBCONFIG_MSG2'].'
            *'.$host_lbl.' + '; + if (isset($_SESSION['setup_db_type']) && $_SESSION['setup_db_type'] =='mssql'){ + $dbSplit1 .= ' \ '; + } + $dbSplit1 .= '
            + + + + + + + + + +
            {$mod_strings['LBL_HELP']}
            +

            + SugarCRM +

            + {$mod_strings['LBL_DBCONF_TITLE']} +
            + SugarCRM +
            + +
            {$mod_strings['LBL_REQUIRED']}
            + + + + + + + + + + + +{$dbSplit1} + + + + + + + + + + + + + +
            {$mod_strings['LBL_DBCONF_TITLE_NAME']}
             {$mod_strings['LBL_DBCONFIG_MSG3']}
            *{$mod_strings['LBL_DBCONF_DB_NAME']} {$oci8sid} +
              +
            {$mod_strings['LBL_DBCONF_TITLE_USER_INFO']}
            {$mod_strings['LBL_DBCONFIG_B_MSG1']}
            *{$mod_strings['LBL_DBCONF_DB_ADMIN_USER']} + +
            {$mod_strings['LBL_DBCONF_DB_ADMIN_PASSWORD']}
            +EOQ2; + +//if we are installing in custom mode, include the following html +if($_SESSION['setup_db_type'] != 'oci8' ){ + +// create / set db user dropdown +$auto_select = '';$provide_select ='';$create_select = '';$same_select = ''; +if(isset($_SESSION['dbUSRData'])){ +// if($_SESSION['dbUSRData']=='auto') {$auto_select ='selected';} + if($_SESSION['dbUSRData']=='provide') {$provide_select ='selected';} +if(isset($_SESSION['install_type']) && !empty($_SESSION['install_type']) && strtolower($_SESSION['install_type'])=='custom'){ + if($_SESSION['dbUSRData']=='create') {$create_select ='selected';} +} + if($_SESSION['dbUSRData']=='same') {$same_select ='selected';} +}else{ + $same_select ='selected'; +} +$dbUSRDD = "
             "; + + + + +$out2 .=<< +

            {$mod_strings['LBL_DBCONFIG_SECURITY']}
             
            {$mod_strings['LBL_DBCONF_SUGAR_DB_USER']}
             
            $dbUSRDD
            + + + +EOQ2; +} + +//set demo dropdown +//$supported_demodata = array( +// 'en_us' => 'English (US)', +// 'zh_cn' => '简体中文', +// 'ja_jp' => 'Japanese - 日本語', +//); +$demoDD = "
             "; + + +$out3 =<< +
            {$mod_strings['LBL_DBCONF_DEMO_DATA_TITLE']}
             {$mod_strings['LBL_DBCONF_DEMO_DATA']} + {$demoDD} +
            +EOQ3; + + +$out4 =<< + + + +
            + + + + + + +
            + + + +
            + + + + +
            + + + + + + + +
            ', + 'txt_body' => +' +Here is your account username and temporary password: +Username : $contact_user_user_name +Password : $contact_user_user_hash + +$config_site_url + +After you log in using the above password, you may be required to reset the password to one of your own choice.', + 'name' => 'System-generated password email', + ), + 'advanced_password_forgot_password_email' => array( + 'subject' => 'Reset your account password', + 'description' => "This template is used to send a user a link to click to reset the user's account password.", + 'body' => '

            You recently requested on $contact_user_pwd_last_changed to be able to reset your account password.

            Click on the link below to reset your password:

            $contact_user_link_guid

            ', + 'txt_body' => +' +You recently requested on $contact_user_pwd_last_changed to be able to reset your account password. + +Click on the link below to reset your password: + +$contact_user_link_guid', + 'name' => 'Forgot Password email', + ), +); + +?> diff --git a/install/license.js b/install/license.js new file mode 100644 index 00000000..f83e7701 --- /dev/null +++ b/install/license.js @@ -0,0 +1,39 @@ +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ +function toggleLicenseAccept(){var theForm=document.forms[0];if(theForm.setup_license_accept.checked){theForm.setup_license_accept.checked="";} +else{theForm.setup_license_accept.checked="yes";} +toggleNextButton();} +function toggleNextButton(){var theForm=document.forms[0];var nextButton=document.getElementById("button_next");if(theForm.setup_license_accept.checked){nextButton.disabled='';nextButton.focus();} +else{nextButton.disabled="disabled";}} \ No newline at end of file diff --git a/install/license.php b/install/license.php new file mode 100644 index 00000000..be34e64e --- /dev/null +++ b/install/license.php @@ -0,0 +1,237 @@ + + + + + + {$mod_strings['LBL_WIZARD_TITLE']} {$mod_strings['LBL_LICENSE_ACCEPTANCE']} + + + + + + + + + +
            +
            + + + + + + + + + + + + + + + + + + + +
            {$mod_strings['LBL_HELP']}
            +

            + SugarCRM +

            + {$mod_strings['LBL_LICENSE_ACCEPTANCE']}
            + SugarCRM +
            + +
            + + {$mod_strings['LBL_LICENSE_I_ACCEPT']} + + +
            +
            + + + + + +
            + + + +
            +
            +
            +
            + + + + + +
            + + + + +EOQ; + +echo $out; +?> \ No newline at end of file diff --git a/install/licensePrint.php b/install/licensePrint.php new file mode 100644 index 00000000..de86c697 --- /dev/null +++ b/install/licensePrint.php @@ -0,0 +1,90 @@ + + + + + + + {$mod_strings['LBL_LICENSE_TITLE_2']} + + + + + + + + + + + + + + + + + +
            + + +
              +
            +            {$license_file}
            +        
            +
             
            + + +
            + + +EOQ; +echo $out; +?> \ No newline at end of file diff --git a/install/oc_convert.js b/install/oc_convert.js new file mode 100644 index 00000000..0f7eacb8 --- /dev/null +++ b/install/oc_convert.js @@ -0,0 +1,35 @@ +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ +function toggleIsFirstTime(){var theForm=document.forms[0];theForm.first_time.value="false";} \ No newline at end of file diff --git a/install/oc_install.js b/install/oc_install.js new file mode 100644 index 00000000..93c169a2 --- /dev/null +++ b/install/oc_install.js @@ -0,0 +1,36 @@ +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ +function toggleOfflineClientInstallation(){var theForm=document.forms[0];if(!theForm.oc_install.checked){theForm.oc_server_url.disabled="disabled";theForm.oc_username.disabled="disabled";theForm.oc_password.disabled="disabled";} +else{theForm.oc_server_url.disabled='';theForm.oc_username.disabled='';theForm.oc_password.disabled='';}} \ No newline at end of file diff --git a/install/performSetup.php b/install/performSetup.php new file mode 100644 index 00000000..8228424e --- /dev/null +++ b/install/performSetup.php @@ -0,0 +1,565 @@ +pause(); + + +$cache_dir = 'cache/'; +$line_entry_format = "     "; +$line_exit_format = "...   "; +$rel_dictionary = $dictionary; // sourced by modules/TableDictionary.php +$render_table_close = ""; +$render_table_open = ""; +$setup_db_admin_password = $_SESSION['setup_db_admin_password']; +$setup_db_admin_user_name = $_SESSION['setup_db_admin_user_name']; +$setup_db_create_database = $_SESSION['setup_db_create_database']; +$setup_db_create_sugarsales_user = $_SESSION['setup_db_create_sugarsales_user']; +$setup_db_database_name = $_SESSION['setup_db_database_name']; +$setup_db_drop_tables = $_SESSION['setup_db_drop_tables']; +$setup_db_host_instance = $_SESSION['setup_db_host_instance']; +$setup_db_host_name = $_SESSION['setup_db_host_name']; +$demoData = $_SESSION['demoData']; +$setup_db_sugarsales_password = $_SESSION['setup_db_sugarsales_password']; +$setup_db_sugarsales_user = $_SESSION['setup_db_sugarsales_user']; +$setup_site_admin_user_name = $_SESSION['setup_site_admin_user_name']; +$setup_site_admin_password = $_SESSION['setup_site_admin_password']; +$setup_site_guid = (isset($_SESSION['setup_site_specify_guid']) && $_SESSION['setup_site_specify_guid'] != '') ? $_SESSION['setup_site_guid'] : ''; +$setup_site_url = $_SESSION['setup_site_url']; +$parsed_url = parse_url($setup_site_url); +$setup_site_host_name = $parsed_url['host']; +$setup_site_log_dir = isset($_SESSION['setup_site_custom_log_dir']) ? $_SESSION['setup_site_log_dir'] : '.'; +$setup_site_log_file = 'sugarcrm.log'; // may be an option later +$setup_site_session_path = isset($_SESSION['setup_site_custom_session_path']) ? $_SESSION['setup_site_session_path'] : ''; +$setup_site_log_level ='fatal'; + +sugar_cache_clear('TeamSetsCache'); +if ( file_exists($cache_dir .'modules/Teams/TeamSetCache.php') ) { + unlink($cache_dir.'modules/Teams/TeamSetCache.php'); +} + +sugar_cache_clear('TeamSetsMD5Cache'); +if ( file_exists($cache_dir.'modules/Teams/TeamSetMD5Cache.php') ) { + unlink($cache_dir.'modules/Teams/TeamSetMD5Cache.php'); +} + +$out =<< + + + + + + {$mod_strings['LBL_WIZARD_TITLE']} {$mod_strings['LBL_PERFORM_TITLE']} + + + + + + + + + + + + + + + + +
            {$mod_strings['LBL_HELP']}
            +

            + SugarCRM +

            + {$mod_strings['LBL_PERFORM_TITLE']}
            + SugarCRM
            +EOQ; +echo $out; +installLog("calling handleSugarConfig()"); +$bottle = handleSugarConfig(); +installLog("calling handleLog4Php()"); +handleLog4Php(); + +$server_software = $_SERVER["SERVER_SOFTWARE"]; +if(strpos($server_software,'Microsoft-IIS') !== false) +{ + installLog("calling handleWebConfig()"); + handleWebConfig(); +} else { + installLog("calling handleHtaccess()"); + handleHtaccess(); +} + +/////////////////////////////////////////////////////////////////////////////// +//// START TABLE STUFF +echo "
            "; +echo "{$mod_strings['LBL_PERFORM_TABLES']}"; +echo "
            "; + +// create the SugarCRM database +if($setup_db_create_database) { +installLog("calling handleDbCreateDatabase()"); + handleDbCreateDatabase(); +} else { + +// ensure the charset and collation are utf8 + installLog("calling handleDbCharsetCollation()"); + handleDbCharsetCollation(); +} + +// create the SugarCRM database user +if($setup_db_create_sugarsales_user) + handleDbCreateSugarUser(); + + +foreach( $beanFiles as $bean => $file ){ + require_once( $file ); +} + +// load up the config_override.php file. +// This is used to provide default user settings +if( is_file("config_override.php") ){ + require_once("config_override.php"); +} + +$db = &DBManagerFactory::getInstance(); +$startTime = microtime(true); +$focus = 0; +$processed_tables = array(); // for keeping track of the tables we have worked on +$empty = ''; +$new_tables = 1; // is there ever a scenario where we DON'T create the admin user? +$new_config = 1; +$new_report = 1; + +// add non-module Beans to this array to keep the installer from erroring. +$nonStandardModules = array ( + //'Tracker', +); + +//if working with sql-server create a catalog for full-text indexes. +if ($GLOBALS['db']->dbType=='mssql') { + $GLOBALS['db']->helper->create_default_full_text_catalog(); +} +/** + * loop through all the Beans and create their tables + */ + installLog("looping through all the Beans and create their tables"); + //start by clearing out the vardefs + VardefManager::clearVardef(); +foreach( $beanFiles as $bean => $file ) { + $doNotInit = array('Scheduler', 'SchedulersJob', 'ProjectTask'); + + if(in_array($bean, $doNotInit)) { + $focus = new $bean(false); + } else { + $focus = new $bean(); + } + + if ( $bean == 'Configurator' ) + continue; + + $table_name = $focus->table_name; + installLog("processing table ".$focus->table_name); + // check to see if we have already setup this table + if(!in_array($table_name, $processed_tables)) { + if(!file_exists("modules/".$focus->module_dir."/vardefs.php")){ + continue; + } + if(!in_array($bean, $nonStandardModules)) { + require_once("modules/".$focus->module_dir."/vardefs.php"); // load up $dictionary + if($dictionary[$focus->object_name]['table'] == 'does_not_exist') { + continue; // support new vardef definitions + } + } else { + continue; //no further processing needed for ignored beans. + } + + // table has not been setup...we will do it now and remember that + $processed_tables[] = $table_name; + + $focus->db->database = $db->database; // set db connection so we do not need to reconnect + + if($setup_db_drop_tables) { + drop_table_install($focus); + installLog("dropping table ".$focus->table_name); + } + + if(create_table_if_not_exist($focus)) { + installLog("creating table ".$focus->table_name); + if( $bean == "User" ){ + $new_tables = 1; + } + if($bean == "Administration") + $new_config = 1; + + + } + + installLog("creating Relationship Meta for ".$focus->getObjectName()); + SugarBean::createRelationshipMeta($focus->getObjectName(), $db, $table_name, $empty, $focus->module_dir); + echo "."; + + } // end if() +} + +echo "
            "; +//// END TABLE STUFF + +/////////////////////////////////////////////////////////////////////////////// +//// START RELATIONSHIP CREATION + + ksort($rel_dictionary); + foreach( $rel_dictionary as $rel_name => $rel_data ){ + $table = $rel_data['table']; + + if( $setup_db_drop_tables ){ + if( $db->tableExists($table) ){ + $db->dropTableName($table); + } + } + + if( !$db->tableExists($table) ){ + $db->createTableParams($table, $rel_data['fields'], $rel_data['indices']); + } + + SugarBean::createRelationshipMeta($rel_name,$db,$table,$rel_dictionary,''); + } + +/////////////////////////////////////////////////////////////////////////////// +//// START CREATE DEFAULTS + echo "
            "; + echo "{$mod_strings['LBL_PERFORM_CREATE_DEFAULT']}
            "; + echo "
            "; + installLog("Begin creating Defaults"); + if ($new_config) { + installLog("insert defaults into config table"); + insert_default_settings(); + } + + + + + + if ($new_tables) { + echo $line_entry_format.$mod_strings['LBL_PERFORM_DEFAULT_USERS'].$line_exit_format; + installLog($mod_strings['LBL_PERFORM_DEFAULT_USERS']); + create_default_users(); + echo $mod_strings['LBL_PERFORM_DONE']; + } else { + echo $line_entry_format.$mod_strings['LBL_PERFORM_ADMIN_PASSWORD'].$line_exit_format; + installLog($mod_strings['LBL_PERFORM_ADMIN_PASSWORD']); + $db->setUserName($setup_db_sugarsales_user); + $db->setUserPassword($setup_db_sugarsales_password); + set_admin_password($setup_site_admin_password); + echo $mod_strings['LBL_PERFORM_DONE']; + } + + + + + // default OOB schedulers + + echo $line_entry_format.$mod_strings['LBL_PERFORM_DEFAULT_SCHEDULER'].$line_exit_format; + installLog($mod_strings['LBL_PERFORM_DEFAULT_SCHEDULER']); + $scheduler = new Scheduler(); + if(isset($sugar_config['demoData']) && $sugar_config['demoData'] != 'no' && $_SESSION['setup_db_type'] == 'mssql') { + $db->query('DELETE FROM schedulers'); + $db->query('DELETE FROM schedulers_times'); + + + $sched3 = new Scheduler(); + $sched3->name = 'Prune the User History Table'; + $sched3->job = 'function::trimTracker'; + $sched3->date_time_start = create_date(2005,1,1) . ' ' . create_time(0,0,1); + $sched3->date_time_end = create_date(2020,12,31) . ' ' . create_time(23,59,59); + $sched3->job_interval = '*::*::*::*::*'; + $sched3->status = 'Active'; + $sched3->created_by = '1'; + $sched3->modified_user_id = '1'; + $sched3->catch_up = '1'; + $sched3->save(); + $sched4 = new Scheduler(); + $sched4->name = 'Check Inbound Mailboxes'; + $sched4->job = 'function::pollMonitoredInboxes'; + $sched4->date_time_start = create_date(2005,1,1) . ' ' . create_time(0,0,1); + $sched4->date_time_end = create_date(2020,12,31) . ' ' . create_time(23,59,59); + $sched4->job_interval = '*::*::*::*::*'; + $sched4->status = 'Active'; + $sched4->created_by = '1'; + $sched4->modified_user_id = '1'; + $sched4->catch_up = '0'; + $sched4->save(); + $sched5 = new Scheduler(); + $sched5->name = 'Run Nightly Process Bounced Campaign Emails'; + $sched5->job = 'function::pollMonitoredInboxesForBouncedCampaignEmails'; + $sched5->date_time_start = create_date(2005,1,1) . ' ' . create_time(0,0,1); + $sched5->date_time_end = create_date(2020,12,31) . ' ' . create_time(23,59,59); + $sched5->job_interval = '0::2-6::*::*::*'; + $sched5->status = 'Active'; + $sched5->created_by = '1'; + $sched5->modified_user_id = '1'; + $sched5->catch_up = '1'; + $sched5->save(); + + $sched6 = new Scheduler(); + $sched6->name = 'Run Nightly Mass Email Campaigns'; + $sched6->job = 'function::runMassEmailCampaign'; + $sched6->date_time_start = create_date(2005,1,1) . ' ' . create_time(0,0,1); + $sched6->date_time_end = create_date(2020,12,31) . ' ' . create_time(23,59,59); + $sched6->job_interval = '0::2-6::*::*::*'; + $sched6->status = 'Active'; + $sched6->created_by = '1'; + $sched6->modified_user_id = '1'; + $sched6->catch_up = '1'; + $sched6->save(); + + + $sched7 = new Scheduler(); + $sched7->name = 'Prune Database on 1st of Month'; + $sched7->job = 'function::pruneDatabase'; + $sched7->date_time_start = create_date(2005,1,1) . ' ' . create_time(0,0,1); + $sched7->date_time_end = create_date(2020,12,31) . ' ' . create_time(23,59,59); + $sched7->job_interval = '0::4::1::*::*'; + $sched7->status = 'Inactive'; + $sched7->created_by = '1'; + $sched7->modified_user_id = '1'; + $sched7->catch_up = '0'; + $sched7->save(); + + + + } else { + $scheduler->rebuildDefaultSchedulers(); + } + + + echo $mod_strings['LBL_PERFORM_DONE']; + + + +// Enable Sugar Feeds and add all feeds by default +installLog("Enable SugarFeeds"); +enableSugarFeeds(); + +/////////////////////////////////////////////////////////////////////////////// +//// START DEMO DATA + + // populating the db with seed data + installLog("populating the db with seed data"); + if( $_SESSION['demoData'] != 'no' ){ + set_time_limit( 301 ); + + echo "
            "; + echo "{$mod_strings['LBL_PERFORM_DEMO_DATA']}"; + echo "

            "; + + print( $render_table_close ); + print( $render_table_open ); + + $current_user = new User(); + $current_user->retrieve(1); + include("install/populateSeedData.php"); + } + + $endTime = microtime(true); + $deltaTime = $endTime - $startTime; + + + +/////////////////////////////////////////////////////////////////////////// +//// FINALIZE LANG PACK INSTALL + if(isset($_SESSION['INSTALLED_LANG_PACKS']) && is_array($_SESSION['INSTALLED_LANG_PACKS']) && !empty($_SESSION['INSTALLED_LANG_PACKS'])) { + updateUpgradeHistory(); + } + + /////////////////////////////////////////////////////////////////////////// + //// HANDLE SUGAR VERSIONS + require_once('modules/Versions/InstallDefaultVersions.php'); + + + + require_once('modules/Connectors/InstallDefaultConnectors.php'); + + + /////////////////////////////////////////////////////////////////////////////// + //// INSTALL PASSWORD TEMPLATES + include('install/seed_data/Advanced_Password_SeedData.php'); + +/////////////////////////////////////////////////////////////////////////////// +//// SETUP DONE +installLog("Installation has completed *********"); +$memoryUsed = ''; + if(function_exists('memory_get_usage')) { + $memoryUsed = $mod_strings['LBL_PERFORM_OUTRO_5'].memory_get_usage().$mod_strings['LBL_PERFORM_OUTRO_6']; + } + + +$errTcpip = ''; + $fp = @fsockopen("www.sugarcrm.com", 80, $errno, $errstr, 3); + if (!$fp) { + $errTcpip = "

            {$mod_strings['ERR_PERFORM_NO_TCPIP']}

            "; + } + if ($fp && (!isset( $_SESSION['oc_install']) || $_SESSION['oc_install'] == false)) { + @fclose($fp); + if ( $next_step == 9999 ) + $next_step = 8; + $fpResult =<< + + + + + + +
            +   +
            + +FP; + } else { + $fpResult =<< +
              +
            + + +
            +
            +FP; + } + + if( isset($_SESSION['setup_site_sugarbeet_automatic_checks']) && $_SESSION['setup_site_sugarbeet_automatic_checks'] == true){ + set_CheckUpdates_config_setting('automatic'); + }else{ + set_CheckUpdates_config_setting('manual'); + } + if(!empty($_SESSION['setup_system_name'])){ + $admin=new Administration(); + $admin->saveSetting('system','name',$_SESSION['setup_system_name']); + } + + + // Bug 28601 - Set the default list of tabs to show + $enabled_tabs = array(); + $enabled_tabs[] = 'Home'; + + $enabled_tabs[] = 'Accounts'; + $enabled_tabs[] = 'Contacts'; + $enabled_tabs[] = 'Opportunities'; + $enabled_tabs[] = 'Leads'; + $enabled_tabs[] = 'Calendar'; + $enabled_tabs[] = 'Documents'; + $enabled_tabs[] = 'Emails'; + $enabled_tabs[] = 'Campaigns'; + $enabled_tabs[] = 'Calls'; + $enabled_tabs[] = 'Meetings'; + $enabled_tabs[] = 'Tasks'; + $enabled_tabs[] = 'Notes'; + $enabled_tabs[] = 'Cases'; + $enabled_tabs[] = 'Prospects'; + $enabled_tabs[] = 'ProspectLists'; + + + require_once('modules/MySettings/TabController.php'); + $tabs = new TabController(); + $tabs->set_system_tabs($enabled_tabs); + +post_install_modules(); +if( count( $bottle ) > 0 ){ + foreach( $bottle as $bottle_message ){ + $bottleMsg .= "{$bottle_message}\n"; + } +} else { + $bottleMsg = $mod_strings['LBL_PERFORM_SUCCESS']; +} + + + +$out =<<

            {$mod_strings['LBL_PERFORM_OUTRO_1']} {$setup_sugar_version} {$mod_strings['LBL_PERFORM_OUTRO_2']}

            + +{$mod_strings['LBL_PERFORM_OUTRO_3']} {$deltaTime} {$mod_strings['LBL_PERFORM_OUTRO_4']}
            +{$memoryUsed} +{$errTcpip} + + + + +
            + + + + +
            +{$fpResult} +
            + + + + + + +EOQ; + +echo $out; + + +?> diff --git a/install/populateSeedData.php b/install/populateSeedData.php new file mode 100644 index 00000000..fa3fd741 --- /dev/null +++ b/install/populateSeedData.php @@ -0,0 +1,503 @@ +create_demo_data(); +$number_contacts = 200; +$number_companies = 50; +$number_leads = 200; +$large_scale_test = empty($sugar_config['large_scale_test']) ? false : $sugar_config['large_scale_test']; +// If large scale test is set to true, increase the seed data. +if($large_scale_test) { + // increase the cuttoff time to 1 hour + ini_set("max_execution_time", "3600"); + $number_contacts = 100000; + $number_companies = 15000; + $number_leads = 100000; +} + + +$possible_duration_hours_arr = array( 0, 1, 2, 3); +$possible_duration_minutes_arr = array('00' => '00','15' => '15', '30' => '30', '45' => '45'); +$account_ids = Array(); +$accounts = Array(); +$opportunity_ids = Array(); + +// Determine the assigned user for all demo data. This is the default user if set, or admin +$assigned_user_name = "admin"; +if(!empty($sugar_config['default_user_name']) && + !empty($sugar_config['create_default_user']) && + $sugar_config['create_default_user']) +{ + $assigned_user_name = $sugar_config['default_user_name']; +} + +// Look up the user id for the assigned user +$seed_user = new User(); +$assigned_user_id = $seed_user->retrieve_user_id($assigned_user_name); +$patterns[] = '/ /'; +$patterns[] = '/\./'; +$patterns[] = '/&/'; +$patterns[] = '/\//'; +$replacements[] = ''; +$replacements[] = ''; +$replacements[] = ''; +$replacements[] = ''; + +/////////////////////////////////////////////////////////////////////////////// +//// ACCOUNTS + +for($i = 0; $i < $number_companies; $i++) { + $account_name = $sugar_demodata['company_name_array'][mt_rand(0,$company_name_count-1)]; + // Create new accounts. + $account = new Account(); + $account->name = $account_name; + $account->phone_office = create_phone_number(); + $account->assigned_user_id = $assigned_user_id; + $account->emailAddress->addAddress(createEmailAddress(), true); + $account->emailAddress->addAddress(createEmailAddress()); + $account->website = createWebAddress(); + $account->billing_address_street = $sugar_demodata['street_address_array'][mt_rand(0,$street_address_count-1)]; + $account->billing_address_city = $sugar_demodata['city_array'][mt_rand(0,$city_array_count-1)]; + if($i % 3 == 1) { + $account->billing_address_state = "NY"; + $assigned_user_id = mt_rand(9,10); + if($assigned_user_id == 9) { + $account->assigned_user_name = "seed_will"; + $account->assigned_user_id = $account->assigned_user_name."_id"; + } else { + $account->assigned_user_name = "seed_chris"; + $account->assigned_user_id = $account->assigned_user_name."_id"; + } + + $account->assigned_user_id = $account->assigned_user_name."_id"; + } else { + $account->billing_address_state = "CA"; + $assigned_user_id = mt_rand(6,8); + if($assigned_user_id == 6) { + $account->assigned_user_name = "seed_sarah"; + } elseif($assigned_user_id == 7) { + $account->assigned_user_name = "seed_sally"; + } else { + $account->assigned_user_name = "seed_max"; + } + + $account->assigned_user_id = $account->assigned_user_name."_id"; + } + + $account->billing_address_postalcode = mt_rand(10000, 99999); + $account->billing_address_country = 'USA'; + $account->shipping_address_street = $account->billing_address_street; + $account->shipping_address_city = $account->billing_address_city; + $account->shipping_address_state = $account->billing_address_state; + $account->shipping_address_postalcode = $account->billing_address_postalcode; + $account->shipping_address_country = $account->billing_address_country; + $account->industry = array_rand($app_list_strings['industry_dom']); + $account->account_type = "Customer"; + $account->save(); + $account_ids[] = $account->id; + $accounts[] = $account; + + // Create a case for the account + $case = new aCase(); + $case->account_id = $account->id; + $case->priority = array_rand($app_list_strings['case_priority_dom']); + $case->status = array_rand($app_list_strings['case_status_dom']); + $case->name = $sugar_demodata['case_seed_names'][mt_rand(0,4)]; + $case->assigned_user_id = $account->assigned_user_id; + $case->assigned_user_name = $account->assigned_user_name; + $case->save(); + + // Create a bug for the account + $bug = new Bug(); + $bug->account_id = $account->id; + $bug->priority = array_rand($app_list_strings['bug_priority_dom']); + $bug->status = array_rand($app_list_strings['bug_status_dom']); + $bug->name = $sugar_demodata['bug_seed_names'][mt_rand(0,4)]; + $bug->assigned_user_id = $account->assigned_user_id; + $bug->assigned_user_name = $account->assigned_user_name; + $bug->save(); + + $note = new Note(); + $note->parent_type = 'Accounts'; + $note->parent_id = $account->id; + $seed_data_index = mt_rand(0,3); + $note->name = $sugar_demodata['note_seed_names_and_Descriptions'][$seed_data_index][0]; + $note->description = $sugar_demodata['note_seed_names_and_Descriptions'][$seed_data_index][1]; + $note->assigned_user_id = $account->assigned_user_id; + $note->assigned_user_name = $account->assigned_user_name; + $note->save(); + + $call = new Call(); + $call->parent_type = 'Accounts'; + $call->parent_id = $account->id; + $call->name = $sugar_demodata['call_seed_data_names'][mt_rand(0,3)]; + $call->assigned_user_id = $account->assigned_user_id; + $call->assigned_user_name = $account->assigned_user_name; + $call->direction='Outbound'; + $call->date_start = create_date(). ' ' . create_time(); + $call->duration_hours='0'; + $call->duration_minutes='30'; + $call->account_id =$account->id; + $call->status='Planned'; + $call->save(); + + //Create new opportunities + $opp = new Opportunity(); + $opp->assigned_user_id = $account->assigned_user_id; + $opp->assigned_user_name = $account->assigned_user_name; + $opp->name = substr($account_name." - 1000 units", 0, 50); + $opp->date_closed = create_date(); + $opp->lead_source = array_rand($app_list_strings['lead_source_dom']); + $opp->sales_stage = array_rand($app_list_strings['sales_stage_dom']); + // If the deal is already one, make the date closed occur in the past. + if($opp->sales_stage == "Closed Won" || $opp->sales_stage == "Closed Lost") + { + $opp->date_closed = create_past_date(); + } + $opp->opportunity_type = array_rand($app_list_strings['opportunity_type_dom']); + $amount = array("10000", "25000", "50000", "75000"); + $key = array_rand($amount); + $opp->amount = $amount[$key]; + $probability = array("10", "70", "40", "60"); + $key = array_rand($probability); + $opp->probability = $probability[$key]; + $opp->save(); + $opportunity_ids[] = $opp->id; + // Create a linking table entry to assign an account to the opportunity. + $opp->set_relationship('accounts_opportunities', array('opportunity_id'=>$opp->id ,'account_id'=> $account->id), false); + +} + +$titles = $sugar_demodata['titles']; +$account_max = count($account_ids) - 1; +$first_name_max = $first_name_count - 1; +$last_name_max = $last_name_count - 1; +$street_address_max = $street_address_count - 1; +$city_array_max = $city_array_count - 1; +$lead_source_max = count($app_list_strings['lead_source_dom']) - 1; +$lead_status_max = count($app_list_strings['lead_status_dom']) - 1; +$title_max = count($titles) - 1; +/////////////////////////////////////////////////////////////////////////////// +//// DEMO CONTACTS +for($i=0; $i<$number_contacts; $i++) { + $contact = new Contact(); + $contact->first_name = $sugar_demodata['first_name_array'][mt_rand(0,$first_name_max)]; + $contact->last_name = $sugar_demodata['last_name_array'][mt_rand(0,$last_name_max)]; + $contact->assigned_user_id = $account->assigned_user_id; + $contact->primary_address_street = $sugar_demodata['street_address_array'][mt_rand(0,$street_address_max)]; + $contact->primary_address_city = $sugar_demodata['city_array'][mt_rand(0,$city_array_max)]; + $contact->lead_source = array_rand($app_list_strings['lead_source_dom']); + $contact->title = $titles[mt_rand(0,$title_max)]; + $contact->emailAddress->addAddress(createEmailAddress(), true, true); + $contact->emailAddress->addAddress(createEmailAddress(), false, false, false, true); + $assignedUser = new User(); + $assignedUser->retrieve($contact->assigned_user_id); + $contact->assigned_user_id = $assigned_user_id; + $contact->email1 = createEmailAddress(); + $key = array_rand($sugar_demodata['street_address_array']); + $contact->primary_address_street = $sugar_demodata['street_address_array'][$key]; + $key = array_rand($sugar_demodata['city_array']); + $contact->primary_address_city = $sugar_demodata['city_array'][$key]; + $contact->lead_source = array_rand($app_list_strings['lead_source_dom']); + $contact->title = $titles[array_rand($titles)]; + $contact->phone_work = create_phone_number(); + $contact->phone_home = create_phone_number(); + $contact->phone_mobile = create_phone_number(); + $account_number = mt_rand(0,$account_max); + $account_id = $account_ids[$account_number]; + // Fill in a bogus address + $contacts_account = $accounts[$account_number]; + $contact->primary_address_state = $contacts_account->billing_address_state; + $contact->assigned_user_id = $contacts_account->assigned_user_id; + $contact->assigned_user_name = $contacts_account->assigned_user_name; + $contact->primary_address_postalcode = mt_rand(10000,99999); + $contact->primary_address_country = 'USA'; + $contact->save(); + // Create a linking table entry to assign an account to the contact. + $contact->set_relationship('accounts_contacts', array('contact_id'=>$contact->id ,'account_id'=> $account_id), false); + // This assumes that there will be one opportunity per company in the seed data. + $opportunity_key = array_rand($opportunity_ids); + $contact->set_relationship('opportunities_contacts', array('contact_id'=>$contact->id ,'opportunity_id'=> $opportunity_ids[$opportunity_key], 'contact_role'=>$app_list_strings['opportunity_relationship_type_default_key']), false); + + //Create new tasks + $task = new Task(); + $key = array_rand($sugar_demodata['task_seed_data_names']); + $task->name = $sugar_demodata['task_seed_data_names'][$key]; + //separate date and time field have been merged into one. + $task->date_due = create_date() . ' ' . create_time(); + $task->date_due_flag = 0; + $task->assigned_user_id = $contacts_account->assigned_user_id; + $task->assigned_user_name = $contacts_account->assigned_user_name; + $task->priority = array_rand($app_list_strings['task_priority_dom']); + $task->status = array_rand($app_list_strings['task_status_dom']); + $task->contact_id = $contact->id; + if ($contact->primary_address_city == "San Mateo") { + $task->parent_id = $account_id; + $task->parent_type = 'Accounts'; + } + $task->save(); + + //Create new meetings + $meeting = new Meeting(); + $key = array_rand($sugar_demodata['meeting_seed_data_names']); + $meeting->name = $sugar_demodata['meeting_seed_data_names'][$key]; + $meeting->date_start = create_date(). ' ' . create_time(); + //$meeting->time_start = date("H:i",time()); + $meeting->duration_hours = array_rand($possible_duration_hours_arr); + $meeting->duration_minutes = array_rand($possible_duration_minutes_arr); + $meeting->assigned_user_id = $assigned_user_id; + $meeting->assigned_user_id = $contacts_account->assigned_user_id; + $meeting->assigned_user_name = $contacts_account->assigned_user_name; + $meeting->description = $sugar_demodata['meeting_seed_data_descriptions']; + $meeting->status = array_rand($app_list_strings['meeting_status_dom']); + $meeting->contact_id = $contact->id; + $meeting->parent_id = $account_id; + $meeting->parent_type = 'Accounts'; + // dont update vcal + $meeting->update_vcal = false; + $meeting->save(); + // leverage the seed user to set the acceptance status on the meeting. + $seed_user->id = $meeting->assigned_user_id; + $meeting->set_accept_status($seed_user,'accept'); + + //Create new emails + $email = new Email(); + $key = array_rand($sugar_demodata['email_seed_data_subjects']); + $email->name = $sugar_demodata['email_seed_data_subjects'][$key]; + $email->date_start = create_date(); + $email->time_start = create_time(); + $email->duration_hours = array_rand($possible_duration_hours_arr); + $email->duration_minutes = array_rand($possible_duration_minutes_arr); + $email->assigned_user_id = $assigned_user_id; + $email->assigned_user_id = $contacts_account->assigned_user_id; + $email->assigned_user_name = $contacts_account->assigned_user_name; + $email->description = $sugar_demodata['email_seed_data_descriptions']; + $email->status = 'sent'; + $email->parent_id = $account_id; + $email->parent_type = 'Accounts'; + $email->to_addrs = $contact->emailAddress->getPrimaryAddress($contact); + $email->from_addr = $assignedUser->emailAddress->getPrimaryAddress($assignedUser); + $email->from_addr_name = $email->from_addr; + $email->to_addrs_names = $email->to_addrs; + $email->type = 'out'; + $email->save(); + $email->load_relationship('contacts'); + $email->contacts->add($contact->id); + $email->load_relationship('accounts'); + $email->contacts->add($account_id); +} + +for($i=0; $i<$number_leads; $i++) +{ + $lead = new Lead(); + $lead->account_name = $sugar_demodata['company_name_array'][mt_rand(0,$company_name_count-1)]; + $lead->first_name = $sugar_demodata['first_name_array'][mt_rand(0,$first_name_max)]; + $lead->last_name = $sugar_demodata['last_name_array'][mt_rand(0,$last_name_max)]; + $lead->primary_address_street = $sugar_demodata['street_address_array'][mt_rand(0,$street_address_max)]; + $lead->primary_address_city = $sugar_demodata['city_array'][mt_rand(0,$city_array_max)]; + $lead->lead_source = array_rand($app_list_strings['lead_source_dom']); + $lead->title = $sugar_demodata['titles'][mt_rand(0,$title_max)]; + $lead->phone_work = create_phone_number(); + $lead->phone_home = create_phone_number(); + $lead->phone_mobile = create_phone_number(); + $lead->emailAddress->addAddress(createEmailAddress(), true); + // Fill in a bogus address + $lead->primary_address_state = $sugar_demodata['primary_address_state']; + $leads_account = $accounts[$account_number]; + $lead->primary_address_state = $leads_account->billing_address_state; + $lead->status = array_rand($app_list_strings['lead_status_dom']); + $lead->lead_source = array_rand($app_list_strings['lead_source_dom']); + if($i % 3 == 1) + { + $lead->billing_address_state = $sugar_demodata['billing_address_state']['east']; + $assigned_user_id = mt_rand(9,10); + if($assigned_user_id == 9) + { + $lead->assigned_user_name = "seed_will"; + $lead->assigned_user_id = $lead->assigned_user_name."_id"; + } + else + { + $lead->assigned_user_name = "seed_chris"; + $lead->assigned_user_id = $lead->assigned_user_name."_id"; + } + + $lead->assigned_user_id = $lead->assigned_user_name."_id"; + } + else + { + $lead->billing_address_state = $sugar_demodata['billing_address_state']['west']; + $assigned_user_id = mt_rand(6,8); + if($assigned_user_id == 6) + { + $lead->assigned_user_name = "seed_sarah"; + } + else if($assigned_user_id == 7) + { + $lead->assigned_user_name = "seed_sally"; + } + else + { + $lead->assigned_user_name = "seed_max"; + } + + $lead->assigned_user_id = $lead->assigned_user_name."_id"; + } + + + // If this is a large scale test, switch to the bulk teams 90% of the time. + if ($large_scale_test) + { + if(mt_rand(0,100) < 90) { + $assigned_team = $team_demo_data->get_random_team(); + $lead->assigned_user_name = $assigned_team; + } else { + } + } + $lead->primary_address_postalcode = mt_rand(10000,99999); + $lead->primary_address_country = $sugar_demodata['primary_address_country']; + $lead->save(); +} + + +/// +/// SEED DATA FOR EMAIL TEMPLATES +/// +if(!empty($sugar_demodata['emailtemplates_seed_data'])) { + foreach($sugar_demodata['emailtemplates_seed_data'] as $v){ + $EmailTemp = new EmailTemplate(); + $EmailTemp->name = $v['name']; + $EmailTemp->description = $v['description']; + $EmailTemp->subject = $v['subject']; + $EmailTemp->body = $v['text_body']; + $EmailTemp->body_html = $v['body']; + $EmailTemp->deleted = 0; + $EmailTemp->published = 'off'; + $EmailTemp->text_only = 0; + $id =$EmailTemp->save(); + } +} +/// +/// SEED DATA FOR PROJECT AND PROJECT TASK +/// +include_once('modules/Project/Project.php'); +include_once('modules/ProjectTask/ProjectTask.php'); +// Project: Audit Plan +$project = new Project(); +$project->name = $sugar_demodata['project_seed_data']['audit']['name']; +$project->description = $sugar_demodata['project_seed_data']['audit']['description']; +$project->assigned_user_id = 1; +$project->estimated_start_date = $sugar_demodata['project_seed_data']['audit']['estimated_start_date']; +$project->estimated_end_date = $sugar_demodata['project_seed_data']['audit']['estimated_end_date']; +$project->status = $sugar_demodata['project_seed_data']['audit']['status']; +$project->priority = $sugar_demodata['project_seed_data']['audit']['priority']; +$audit_plan_id = $project->save(); + +foreach($sugar_demodata['project_seed_data']['audit']['project_tasks'] as $v){ + $project_task = new ProjectTask(); + $project_task->assigned_user_id = 1; + $project_task->name = $v['name']; + $project_task->date_start = $v['date_start']; + $project_task->date_finish = $v['date_finish']; + $project_task->project_id = $audit_plan_id; + $project_task->project_task_id = '1'; + $project_task->description = $v['description']; + $project_task->duration = $v['duration']; + $project_task->duration_unit = $v['duration_unit']; + $project_task->percent_complete = $v['percent_complete']; + $communicate_stakeholders_id = $project_task->save(); +} + + +?> diff --git a/install/processing.gif b/install/processing.gif new file mode 100644 index 0000000000000000000000000000000000000000..bf6cbee5814f51f0ddc9384a2f607117a735950b GIT binary patch literal 10847 zcmb`NXHZjX->;L91QJksO+b()O%YU3Q9(BXipaJg-OxJ;J@hm}@4Z*)U8E`okQM=v z8hYqeKtu&B9Nf?QyywjMyw^--)`vA&lQrwUa{Ye)TSM!v@>R2G04HD{060EA1^@u9 zt*wQHg&7$cjg5`9wY5DxJv18a-Me=qBO}w(({wt0X=$mty889&*K2EQTU%RHDs^vf zZ-0M(U|`_ew{KltU4w&z+uPe?V`J^@?WLuq2L}f^IXOv5Ng~J0I_ggz-%-<5S2!=v z06e*w$Zx^h9(IoI!d`anw!#`(cZDCIJ?*T7HLT2Bg)g0#Ke>SWftjV1u(`Len!OoT z8*OHJ-p<(?4G=j5!{8_1Abauw{P_U@$g!|+l%-vkZE2OGj@PmWi{0;47*^5BJ+HCVfg!|>-E&07j2fTmnZ~*9{j^`2v>ikfcE@({ zldYd`K%ftSge5zKc!d!?0=?a$V-a`)Gy)fu8WR-nj?jB{;$J*=tu^_vC?rv1&^<`&kDSH0Bk*3Rbschs7`{ts;v9aCL1J;T-Qd?ic_ zvS26-&dhR(jTypN@{NO+^)uVgpI^Ry-(BAvkH#0_7+}=v*b5?RL;(A?Z_i*>2Z0-+ z^Nw$D;cg)R7k^{Ent9C-LC#}iQZOEO4YxuTyl4Y2X`T(_6IYZ22gOvN@ z?F3JZO>f2Z@6M)gxDUQ{rh8p@{xg{Sd%g@3JCCN-JJ<+_+ap04rmH39!WMEdnOTpx~El`X6`&%sE;<~UVUbJlrR8CT^fWZ zGKSn;BKY6@CP~8UblKRGlS0;Pg5i_4c{1mlCvpxnuhH@&q&JEmyr74^PFBjl^}cs^e?G^2WewPEhN+$*f_$=8>SoA( zDs2yQIFSxc-af2;h=3405q+A092{yN;pOY^79SbppAn8GC58Cov5~$ZfjEMrcN8Qe z&XZUXot*EGje-8N5QLC_RzjBm0t#UT+1S1pU>X|kwH*j(8J>he-E3&Alf%>Q1Me4x zMhDzh*On0Dz4L3M?g5_`mNq|pIh+|Q-nA=Z#1JVi$8?A+4$vVFX3%G2(lY}Rp==80 z&tXt0r06qeP<@)NZA1oc)nf^!t8rprC|QN@T6oCnZi>u}m2x}ImF@&#@m+Vj+Qko< za#{;4N3qtAA|=&8+(-LX+KC()lXcQh+wWD}$X9^)vIBvkLRVykuja~Sn|BtNu~p|( zm^5%itS2VrY?D~L4%aSAL~hTu@Pk?J=1}D66mMQpdA~-dg&tqTj|vsDWfa6u>6T6g z-EF=whaa&*la_1PN@;#JaLj}hl~SEYfqxg z^BC2G-37ipnQRpP=*uen=DqAJiudQm#nfc4(>MITe|qqWm5TlW}s2CQh4v8!(?3YIh>TWD+@&< z1tcStY+iDkV4dM9;HfJe{=KAh!IucRngb~lU^2v3d&VF=WCgzb9VSxilWE$0R>r|D z?$e}0<>1vHTgNtC_fQVxm*>f);GWYzO8zptxh7iI?WegMS$Op-Fyf|y)_lUwr1FA| zfTrpTG7ME+9{TmXfwuJ}sNZJvr=gI%H+O~HA^^9lk2vw;41dr!FvSYC&&QVxIRF{ev<6!=t19 z2%D*)*-;qOcF@*pd4%rnzco9)IvIjk`ogptW_P%}vqs<4i^^`ivQBNiT;Ok&#Uw7gbssrr!mi&v$c0`s0IYRe(COH0{v zMLn&oQ02Qn&^?!(>$M}!Df!Af>E~t8-|uluD>!~nlLuU86SD`+Z zL$|>qf4KgO`x;jz^Etr3@}PnI(wQHB6&}=i8!1)@mFPY<)NhYzHF!lWk&r9M(rzHv zjs5-dzGne%1)xiV)3y=N%l1%TngQq4TLyN9Zq0Q3vQEYl+7yK3)I*i-A6)DZ+FmJ# zsW@Usqwn)xRd4CR-K2ZRO$js;5ZKulTIpz|=9#GMR^=$F-mWs~gCG7K4~6l<&)s*t zXq7)A@^i0GY3JvcL5&N)_D7zfe|`N|MI_ipewPcJ?tawc!iU71WQ0oAN%HHdiw_Gp zaWEv(JILGLBf!Zw$d45fU{AohpczJl(WD^?p>6E8Fb-hBd=6SCNbo`7YT2|nB(7-RQwWTxLXAa;6Y9E$i5xVS`% zn;IG!W7?YEp7{)0nY4%QEFF0KIP&OV)QM}xuMEDJ*QhjByTv;FL{%OK!9QlD$m1wA ziv$p(SP0U4UX2(f#C#m0EsVD!#7X{rTYnc-@E}FO=4SC=Z4o#_!EVwR#wAWn<2DYH z-Kbd^OqOsHN~E}njij6l`eu2kSlXAb(scf7+E=xnM2`B4wm2M4{WOF_lPI6-Ji{Wp z*x4bB!ke^U#gXYeXyV*kk1t*MN%Y-03bDdKF+#b9-Z^@tN0yyPBe(KP%hWRpT(k)c zxN|HR$%3~Y4oiIcV~cOs7F{CJXrd;ZOQLcvi44-K2oUBFUNQZc%ZhlDDW_hu4~L`6O}3+2yC z)>aTT4MDmJ>*YU-;1f!2gHoR)_k{^<7w4L)-t4ltgRI4lhfdFEng@G*?h#bsKI@fB zklNS7LAmI`$onF*9TYE5e5jBGbBrCon-n$P+WTW@U0=p~NBKfOo}Tpu1=w_GN@{UQ zY7rQ+_kAU>XWigb8piybO>`}P;R@L2h$fjD%CV7``&;~AjDg)<%7l?6gEnzV#UsZ) zbY8BA*G0C(e!ldDUUHsht)Z$+yujI<*-{1j)zZk(f=RXfDM3YA6~%PTL4hhnba+{i zW*>cAQ#&y3aQO)^J-dW>YW!0vpEU18Ue{5uI2?@0Q7z6NYZQs0!HZn z*$Mn1ogNX1h)LND{<&SG+9pmF$h9PW{%Yy@jRPvz;kka!%JSAtJ27b05pzL=;1lG- zZrLGQCmW9EJqyi}Eb{CowDqtypyMQMyg+GH<$=YVx|dsHtdQXs@Qq;Q=>b*=ry7v9 zXxKjRjv=QjYDf{28Tvw=?>GoV{?;B#FN01w~h@RRTV^u zAd$ymmJ@s8_Yx#Ijrk@{0#FRj)4be{L$ZhQl9s{&jANCW#Fhm5^-|HUH(k|R`trmR z$w$TaZ{+QZ=B7eH?7mOSg;8y!28`s-5~WjjrW!GS>y%l4kTY$9{hsMeH*>z+3WqLc zIy}HzbYhqpJtI&C=5NEr-51jVZkBJ>g;z(n^gB#Ha>DPc-j$nJep@;`p$-6kf`c}n z=p8r!+sJ`1&tns|l=BogkLlQ9WtVi(%5dbh{gv9F3*Dv<+qz+ca|#zs`}aS; zAE|y!y`LOMP+9)pEuk3@CSHGn$DA9vSw8cw2BnhLmh(>1i#T-(fn&P zvr3pQ9sfcqU)YgRuS)=QVkmgmd94t-f!8`BW}K3=n6zftkC!Ivw&M9uid z)@aZ`4_!XO7=_jr$j*-e8ZkFAnlPUEo0#IoGN>eQwO3Qu3X4_`)%Jc;skxwWE~yE~ zz^21yWo7LH&4M@>zSIU8g((3O(mr*rq%Ih&zQ~YjR?ov)N>~V~K5&&v2EX4`dSIi| z{>oaxaR|nXlcJAl_&)R;1Tw@wIE*b?@P==g22)q1O0wfLq(VMa9PzlE;V}S~%xihk z@<;JrHf5aGluOGC75K_6Iw}pftVc94o3UR?x_O}=T5ZaY^SkGdHcMLe?wu(-XKM%m zKO9h=AxTfBPD1(C>=r{>2SR|c!rS`i?_73Ta9@Z>#|wPiwu{ zx?U1mp#>9*V$V+pz8w@$uF40NwQP5FZ~ICyGiai4ApgA|k_0CM*lc#>tBmPBj1aCg z!SI`wZ5HZLs1WqZg$(gDbUS3`SgQq2wMe!3}(|-#mCpRPC8aKNyuLqJ$U0J2R;8t15bO0kN5)Q+GT!5XSdO6 z%){F#f1lI4GMnQSK6Pjpy{V5`HFhInlrlZK8 zkmLO0Q{$iX^ZNVtkDdQo%L!W~|5c7eop9v(yP!y)HzL<(F$2PHbZA%6#5>0;DqA>v zODM?~?S_DbhQWw_KG2ZR_(*IFDVEhEA}Pp^AuT;I#qV^Er+q|JflXjUDKaZ14(Ay~ z_H_$$)WH4+C2mC4%0DRS>tjOnCWJz$Ok?ANx#6(h@!5%z_?g+U!TFMrrR9&|_Py|p z!4{8^-KFW=V#NAqX!`6 z7o<`o2J*Gk4Sz{_tPWQEeMe&Q5J&k7#doooyBbB9YT(=|?x65&PbGePJ^Bivgr~g0 zDE7Q6%8^Gky0UYb7SgMY+FJ)?a~VnZrpAW`rOckk=OzHiJwO{Ix$PYt(dQ&~n(De$S~Na{CU=;$qp= z8P%`W(Z07XRJKjIjEplIUB5MrHXUw}d-DB8jH^4O{nPF2jF~Ms2r8xvw1eeHr1*r% zNdS(Y^B^@-Z}2&)n%E@N=%tYStg740`}wTtMCFXef#pgTqwwA_ZB z4~xcQA9#yivpMS-?i8a&MwovWBs+WP=3C#erf0(ert-o8EHOQKM%Yk&9ovymcTxP` zd*X3+3JUQQ&|c{3SaSa*MTtnBoYWOnlOu_&q_Lbvyww~2R73Z3wc>MOS#3RO;J@{h zR&6iBn$#I?f<8e}ebEA;S8k%`H3s*AAbHsmAtysj=ZMx{OAx=7_ z_9>;*BcMMhqhOl5Xu{ijLo354d|py5Jc}S;P(6`)WLKOTnU;<2x{^+RIr2$z=C~s3 zsLRo`KnEuU2k_*KM*9dI(qk^QTIYwr4?;GhjOx?XJnmj;#2b=Kl&c``Cd1qO*OE5V z$;S#wOGZ9$GCK2!s!`q?G~bgJtr`b)Y#AhL$VZf2?nAV-NodwI$g&9I0gMN|RS6u( zn4A!j#Q2&`^F`g2Y)%vg*BMcwo#`icUyp{Xe85&`$HNikmXv?PHjOIy^Qv1pJiyU|m~~oc*)+Lnfha9+rxZ{iZycbs#>DVm15-HFTrgvyr2r8pI%h0YE^?==I3!wHmhMem#V*8tkgHaiWxu0;(C@r{ zL)tG+DU0%UsSkPp2C;m(!eO*j`D6PZjy!Sy``w@P^M@l<|4l#HY@mOwP6-0Fbx2(w zIQ`J9!x;@l)`?~XRC8igW`vbkguD^nR(^gq0iIX_4DEZG92gNtu!bhZgvR+GgKR^* zykRa$uBQXN!ts{Q?ay{=PbR^lhb8EnO^ft^u=2 z`|5@&!U16??W?@i)@>me?Ee7@S1O&*6(s~bjuf+V6}@)?6qIr3=cV^4e4OQdG`e`7 z#WkC>t;0Rh2bpsIT`cz=wd-b|xe&Dkd%B{d!WxoisVlrnEmC4e4yFd<-T|Sq=KA4( z$`j57Y9?+q9n^qX)#=e4-!^*V;*r(CoKi`0fO9nbV&;2j4iVts9DA?SrT}3QQykk= zHd^X;JruedVF0vkA}DI;`1w=~jM7dLR%GsN2+aB!8(+0rfw?>Pf?u*KU1LuBD+Mk+S zc5cWr@bLV;U{IfC*;Jx>@?@R>CXTH@TwUWP(Q4KL9xgWyjI239No`OziF!k#fJ8MN z$Nxy;tS^Ui44#ZUPs|H*@fcJKLYmY22ylv~LF9n)m%gz1Pn{xU_6_B6@(U533Ft+k z-uz$zlr9R+XqrPOAmj%NjC;*&v!Mo$Y-y4GJw@Uule=9kDJ-gz#;y(u@v7-Zoe)XI zn-YLzNayF&6`%KOSEnP;LMscA980e1ir)^N`D;=_fuTE0SVqVOQ%ZG2>3#rC*z$ND2fHx7_ z7Sd4;?EnrYj4A}XY_!&zdJ$?;n6KUfC~UX#0gxFa4BZMi%00ycY#yyn;bPZ~CHs^e z>Qx#2d}Qp5o~2!RX)15wxozP#)TbC4x~}!Af1Jiw|K82tXU1Gntr;-)6ueWK1Fo9N$4 zp$E&Z&u<7{TqavIm(KB-|Ahy%l}Eng`JeXH`TC#gI z%{nqZ+MeKa;w2M_PD|tM@y?5^vvY$lKkV#oE+njveGexbecl57zO$=6m5%p;^TqsW zOw2gQ^RcRbxBr>p*c08hFLbizmEx8zwwaO({2cz`t}Qp+S^LbWEFg~ zZ+>cfxI?nP<*KV=p%f19B+VvFxm_UDk$nuvwW?Obz0bHS=$N0_JqPU>wVL$jaQ!As zs>>te|f3DECu;&J8 zq2OSy$H34%aSATn!9bNA4YwCwCfS?t=MszttX^1($0bof>jv`Hq5X~&KytDaanalc zZX>C_m$)X8_@Tle(mKke$Qpyaz0Sfg3e#YZ3QRjFOe02JE%GaV5p0t$AR7t-dKgcn zILeXJc)Wq_Pw~amCab54Km6TI@o|=-XBo=1N@vCh(%`IRbt`EFMqEMCTV;hcl4am_ z^1ZF-Zo`=Js;o{%4v&uZjc3P~`$yb9ZwIf#x%hX=i#AmhE)^}uZ z_(#-QA>GWfPlO^9TGgXdmLNvmU7?=7l&+dNHz`R>56AwDJ%+^*(@5uF`;D#?t>^WA zAIYd$nH0+^kO84FAyL;C;>xVBu@i}v*0VR#HlLE5oBi&Fu7U4_s55yB#$q@k-o?hWFa(nUO<)B)xSb?*J zuf9>LXHPMS84VBeRnvRMuWcsgG**E=VkFh0iut~Rn>e-zI;g{nX=ZL|O|}*S1rPD! zE-RC7yZw2Ar}oYJyDC)>W@ZlAhpN-q*|p)aGfGjJ&Tm$_=k8wkCAj-#yPaEeFu=rT zr5S#y+>2$#|L0y*epM9GyVawS);Z1#`f^pN4IB6Q&rF!Zwi*Z>m=0D0MZHM^IJ~c} zSHt=w@;tXh2%LNN*U!<*X3(g}ka-2kFsw*u|6g2ZQKCNG5g>%8s)hNPy~~ScybAGV z)`;IW#!!{^Vm;8g)=_+vrumvh(BA>YID(XXN^sm569wnZgR0{XoM`;|9CgZ?$0Bv* z0WMb2a%d&P1>MfiZ)!tMwI*ex+D*GTH{00Q1a34<;9SpoWoXJ@A>xv!|9LdEn{g6js$V* zGVxZm?s0EbUi&6(Y~5GUyaA@B@x-bRaQrAeHXnKV!?Mm@?v9DefY6#u`BVkf>3Lq3 zDnN(>HOL$CKqx82OP~uePTYls8Z(BcIjCkQ^ZaDCXZ3$2a0C@;ApYWeaac4M((4~JSJdBJS z#(niQqTSIPe;pUrVb$`rqF7YTU$5Fz22+y*iaOJkr{46YkS@L9Lyg%p|1etS~ zabH|=N$!3%TkoPoC-qJ}tu_!m+Fj(Vep{AVeeK)9%eUDMH?AxnO?9r0{m~R41G{Q9 z{@CKvD{+dOzm;AVk&QaeqsY~+F-176c|n2l>vxGL3K5D$o->>0usE<9TIX7e-)=a-cTsTYSzGqdyo)(Vm&b&$9Dp8& zHM{TclHnK8*>(mGKt7>LYK#Vz#eGlXj0mV2Mtt8M&UgEIWjZmC| z=aE#hdYTh?EeCr(+3Ipgm(;UV0hLe!o|!2r)eiPVRm@LNemC#(*+b2Ol7U!5dv~FL z;MwBOGs`^K{7Se(WJ8y_jC+E=BrvwAmFi%`!){biSr)`oTKle+sz+=;w<&X6mMbEo zh8Z-UiYSy^lF)~QIF0E=SGw?RHYrr{AX+4aLIq#nq+WN5IBTk$8|lE)WaeG;`NwAL z%9W7HDtE1F^GL+O#!fV^!fS~rB*nayU@v^}33R$HECM=;PrCTV2fz0|ACU@Sgzr7XyD zh}s*}2Gm1$4Z=|*aIFRXRFTZkgwu87w=8{pg_>Li$;0;TUHvoD?xJ3}nGpkCzL^b8 zw(nH|RSjA4E@g+(P(0pqbJn5z`**({*!hOAeKnn8NFg-I@-~-lgR#u&rpPYf0!p-| h^S@h7bkup(NB*?1|D!4Y!3s + + + + +{$mod_strings['LBL_WIZARD_TITLE']} {$mod_strings['LBL_TITLE_ARE_YOU_READY']} + + + + + +
            + + + + + + + + + + + + + + + + +
            {$mod_strings['LBL_HELP']}
            +

            + SugarCRM +

            +
            SugarCRM +
            {$mod_strings['LBL_TITLE_ARE_YOU_READY']}
            +

            {$mod_strings['LBL_WELCOME_PLEASE_READ_BELOW']}

            + + + + + + +
            + + + +  {$mod_strings['REQUIRED_SYS_COMP']} + +
            +
            {$mod_strings['REQUIRED_SYS_COMP_MSG']}
            +
            + + + + + + +
            + + + +  {$mod_strings['REQUIRED_SYS_CHK']} + +
            +
            {$mod_strings['REQUIRED_SYS_CHK_MSG']}
            +
            + + + + + + +
            + + + +  {$mod_strings['REQUIRED_INSTALLTYPE']} + +
            +
            {$mod_strings['REQUIRED_INSTALLTYPE_MSG']}
            +
            +
            +
            + + + + + +
            + + + + +
            +
            +
            + + + +EOQ; +echo $out; +?> \ No newline at end of file diff --git a/install/register.js b/install/register.js new file mode 100644 index 00000000..82eb7906 --- /dev/null +++ b/install/register.js @@ -0,0 +1,44 @@ +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ +function submitbutton() +{var form=document.mosForm;var r=new RegExp("[^0-9A-Za-z]","i");if(form.email1.value!="") +{var myString=form.email1.value;var pattern=/(\W)|(_)/g;var adate=new Date();var ms=adate.getMilliseconds();var sec=adate.getSeconds();var mins=adate.getMinutes();ms=ms.toString();sec=sec.toString();mins=mins.toString();newdate=ms+sec+mins;var newString=myString.replace(pattern,"");newString=newString+newdate;} +if(form.name.value=="") +{form.name.focus();alert("Please provide your name");return false;} +else if(form.email1.value=="") +{form.email1.focus();alert("Please provide your email address");return false;} +else +{form.submit();} +document.appform.submit();window.focus();} \ No newline at end of file diff --git a/install/register.php b/install/register.php new file mode 100644 index 00000000..d8ac99cf --- /dev/null +++ b/install/register.php @@ -0,0 +1,139 @@ +"; + */ + $regPhp=""; + + + $notConfirmed =<<{$mod_strings['LBL_REG_CONF_1']}

            --> + + {$regPhp} + +CONF; + +} else { + $notConfirmed = $mod_strings['LBL_REG_CONF_3']; +} + + +/////////////////////////////////////////////////////////////////////////////// +//// START OUTPUT + +$out =<< + + + + + + {$mod_strings['LBL_WIZARD_TITLE']} {$mod_strings['LBL_REG_TITLE']} + + + + + + + + + + + + + + + + + +
             
            +

            + SugarCRM +

            + {$mod_strings['LBL_REG_TITLE']} (Optional)
            SugarCRM
            {$notConfirmed}
            +
            + + + + + +
              +
            + + +
            +
            +
            +
            + + +EOQ; + +echo $out; + +?> \ No newline at end of file diff --git a/install/seed_data/Advanced_Password_SeedData.php b/install/seed_data/Advanced_Password_SeedData.php new file mode 100644 index 00000000..089e800c --- /dev/null +++ b/install/seed_data/Advanced_Password_SeedData.php @@ -0,0 +1,83 @@ +name = $mod_strings['advanced_password_new_account_email']['name']; +$EmailTemp->description = $mod_strings['advanced_password_new_account_email']['description']; +$EmailTemp->subject = $mod_strings['advanced_password_new_account_email']['subject']; +$EmailTemp->body = $mod_strings['advanced_password_new_account_email']['txt_body']; +$EmailTemp->body_html = $mod_strings['advanced_password_new_account_email']['body']; +$EmailTemp->deleted = 0; +$EmailTemp->published = 'off'; +$EmailTemp->text_only = 0; +$id =$EmailTemp->save(); +$sugar_config['passwordsetting']['generatepasswordtmpl'] = $id; + +//User generate a link to set a new password +$EmailTemp = new EmailTemplate(); +$EmailTemp->name = $mod_strings['advanced_password_forgot_password_email']['name']; +$EmailTemp->description = $mod_strings['advanced_password_forgot_password_email']['description']; +$EmailTemp->subject = $mod_strings['advanced_password_forgot_password_email']['subject']; +$EmailTemp->body = $mod_strings['advanced_password_forgot_password_email']['txt_body']; +$EmailTemp->body_html = $mod_strings['advanced_password_forgot_password_email']['body']; +$EmailTemp->deleted = 0; +$EmailTemp->published = 'off'; +$EmailTemp->text_only = 0; +$id =$EmailTemp->save(); +$sugar_config['passwordsetting']['lostpasswordtmpl'] = $id; + +// set all other default settings +$sugar_config['passwordsetting']['forgotpasswordON'] = true; +$sugar_config['passwordsetting']['SystemGeneratedPasswordON'] = true; +$sugar_config['passwordsetting']['systexpirationtime'] = 7; +$sugar_config['passwordsetting']['systexpiration'] = 1; +$sugar_config['passwordsetting']['linkexpiration'] = true; +$sugar_config['passwordsetting']['linkexpirationtime'] = 24; +$sugar_config['passwordsetting']['linkexpirationtype'] = 60; +$sugar_config['passwordsetting']['minpwdlength'] = 6; +$sugar_config['passwordsetting']['oneupper'] = true; +$sugar_config['passwordsetting']['onelower'] = true; +$sugar_config['passwordsetting']['onenumber'] = true; + +write_array_to_file( "sugar_config", $sugar_config, "config.php"); \ No newline at end of file diff --git a/install/seed_data/quotes_SeedData.php b/install/seed_data/quotes_SeedData.php new file mode 100644 index 00000000..137af11c --- /dev/null +++ b/install/seed_data/quotes_SeedData.php @@ -0,0 +1,174 @@ +$quote) { + + $focus = new Quote(); + $focus->id = create_guid(); + $focus->new_with_id = true; + $focus->name = $quote['name']; + $focus->description = !empty($quote['description']) ? $quote['description'] : ''; + $focus->quote_stage = !empty($quote['quote_stage']) ? $quote['quote_stage'] : ''; + $focus->date_quote_expected_closed = $quote['date_quote_expected_closed']; + if(!empty($quote['purcahse_order_num'])) { + $focus->purchase_order_num = $quote['purcahse_order_num']; + } + + if(!empty($quote['original_po_date'])) { + $focus->original_po_date = $quote['original_po_date']; + } + + if(!empty($quote['payment_terms'])) { + $focus->payment_terms = $quote['payment_terms']; + } + + $focus->quote_type = 'Quotes'; + $focus->calc_grand_total = 1; + $focus->show_line_nums = 1; + $focus->team_id = $current_user->team_id; + $focus->team_set_id = $current_user->team_set_id; + + //Set random account and contact ids + $sql = 'SELECT * FROM accounts WHERE deleted = 0'; + $result = $GLOBALS['db']->limitQuery($sql,0,10,true,"Error retrieving Accounts"); + while ($row = $GLOBALS['db']->fetchByAssoc($result)) { + $focus->billing_account_id = $row['id']; + $focus->name = str_replace('[account name]', $row['name'], $focus->name); + $focus->billing_address_street = $row['billing_address_street']; + $focus->billing_address_city = $row['billing_address_city']; + $focus->billing_address_state = $row['billing_address_state']; + $focus->billing_address_country = $row['billing_address_country']; + $focus->billing_address_postalcode = $row['billing_address_postalcode']; + $focus->shipping_address_street = $row['shipping_address_street']; + $focus->shipping_address_city = $row['shipping_address_city']; + $focus->shipping_address_state = $row['shipping_address_state']; + $focus->shipping_address_country = $row['shipping_address_country']; + $focus->shipping_address_postalcode = $row['shipping_address_postalcode']; + break; + } + + foreach($quote['bundle_data'] as $bundle_key=>$bundle) { + $pb = new ProductBundle(); + $pb->team_id = $focus->team_set_id; + $pb->team_set_id = $focus->team_set_id; + $pb->currency_id = $focus->currency_id; + $pb->bundle_stage = $bundle['bundle_stage']; + $pb->name = $bundle['bundle_name']; + + $product_bundle_id = $pb->save(); + + //Save the products + foreach($bundle['products'] as $product_key=>$products) { + $sql = 'SELECT * FROM product_templates WHERE name = \'' . $products['name'] . '\''; + $result = $GLOBALS['db']->query($sql); + while ($row = $GLOBALS['db']->fetchByAssoc($result)) { + $product = new Product(); + + foreach($product->column_fields as $field) { + if(isset($row[$field])) { + $product->$field = $row[$field]; + } + } + + $product->name = $products['name']; + $product->id = create_guid(); + $product->new_with_id = true; + $product->quantity = $products['quantity']; + $product->currency_id = $focus->currency_id; + $product->team_id = $focus->team_id; + $product->team_set_id = $focus->team_set_id; + $product->quote_id = $focus->id; + $product->account_id = $focus->billing_account_id; + $product->status = 'Quotes'; + + if ($focus->quote_stage == 'Closed Accepted') { + $product->status='Orders'; + } + + $pb->subtotal += ($product->list_price * $product->quantity); + $pb->deal_tot += ($product->list_price * $product->quantity); + $pb->new_sub += ($product->list_price * $product->quantity); + $pb->total += ($product->list_price * $product->quantity); + + $product_id = $product->save(); + $pb->set_productbundle_product_relationship($product_id, $product_key, $product_bundle_id); + break; + } //while + + } //foreach + + $pb->tax = 0; + $pb->shipping = 0; + $pb->save(); + + //Save any product bundle comment + if(isset($bundle['comment'])) { + $product_bundle_note = new ProductBundleNote(); + $product_bundle_note->description = $bundle['comment']; + $product_bundle_note->save(); + $pb->set_product_bundle_note_relationship($bundle_key, $product_bundle_note->id, $product_bundle_id); + } + + $pb->set_productbundle_quote_relationship($focus->id, $product_bundle_id, $bundle_key); + + $focus->tax += $pb->tax; + $focus->shipping += $pb->shipping; + $focus->subtotal += $pb->subtotal; + $focus->deal_tot += $pb->deal_tot; + $focus->new_sub += $pb->new_sub; + $focus->total += $pb->total; + + } //foreach + + //Save the quote + $focus->save(); + } //foreach +} + + +?> \ No newline at end of file diff --git a/install/siteConfig.js b/install/siteConfig.js new file mode 100644 index 00000000..224d2e66 --- /dev/null +++ b/install/siteConfig.js @@ -0,0 +1,42 @@ +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ +function toggleSiteDefaults(){var theForm=document.forms[0];var elem=document.getElementById('setup_site_session');if(theForm.setup_site_defaults.checked){document.getElementById('setup_site_session_section_pre').style.display='none';document.getElementById('setup_site_session_section').style.display='none';document.getElementById('setup_site_log_dir_pre').style.display='none';document.getElementById('setup_site_log_dir').style.display='none';document.getElementById('setup_site_guid_section_pre').style.display='none';document.getElementById('setup_site_guid_section').style.display='none';} +else{document.getElementById('setup_site_session_section_pre').style.display='';document.getElementById('setup_site_log_dir_pre').style.display='';document.getElementById('setup_site_guid_section_pre').style.display='';toggleSession();toggleGUID();}} +function toggleSession(){var theForm=document.forms[0];var elem=document.getElementById('setup_site_session_section');if(theForm.setup_site_custom_session_path.checked){elem.style.display='';} +else{elem.style.display='none';}} +function toggleLogDir(){var theForm=document.forms[0];var elem=document.getElementById('setup_site_log_dir');if(theForm.setup_site_custom_log_dir.checked){elem.style.display='';} +else{elem.style.display='none';}} +function toggleGUID(){var theForm=document.forms[0];var elem=document.getElementById('setup_site_guid_section');if(theForm.setup_site_specify_guid.checked){elem.style.display='';} +else{elem.style.display='none';}} \ No newline at end of file diff --git a/install/siteConfig_a.php b/install/siteConfig_a.php new file mode 100644 index 00000000..5c63cbba --- /dev/null +++ b/install/siteConfig_a.php @@ -0,0 +1,210 @@ +$value) + { + $language_keys[] = $key; + $language_values[] = $value; + } + + $_SESSION['language_keys'] = urlencode(implode(",",$language_keys)); + $_SESSION['language_values'] = urlencode(implode(",",$language_values)); + } +} + +//// errors +$errors = ''; +if( isset($validation_errors) && is_array($validation_errors)){ + if( count($validation_errors) > 0 ){ + $errors = '
            '; + $errors .= '

            '.$mod_strings['LBL_SITECFG_FIX_ERRORS'].'

              '; + foreach( $validation_errors as $error ){ + $errors .= '
            • ' . $error . '
            • '; + } + $errors .= '
            '; + } +} + + +//// ternaries +$sugarUpdates = (isset($_SESSION['setup_site_sugarbeet']) && !empty($_SESSION['setup_site_sugarbeet'])) ? 'checked="checked"' : ''; +$siteSecurity = (isset($_SESSION['setup_site_defaults']) && !empty($_SESSION['setup_site_defaults'])) ? 'checked="checked"' : ''; +$customSession = (isset($_SESSION['setup_site_custom_session_path']) && !empty($_SESSION['setup_site_custom_session_path'])) ? 'checked="checked"' : ''; +$customLog = (isset($_SESSION['setup_site_custom_log_dir']) && !empty($_SESSION['setup_site_custom_log_dir'])) ? 'checked="checked"' : ''; +$customId = (isset($_SESSION['setup_site_specify_guid']) && !empty($_SESSION['setup_site_specify_guid'])) ? 'checked="checked"' : ''; + +/////////////////////////////////////////////////////////////////////////////// +//// START OUTPUT +$out =<< + + + + + + {$mod_strings['LBL_WIZARD_TITLE']} {$mod_strings['LBL_SITECFG_TITLE']} + + + + + + +
            + + + + + + + + + + + + + + + +
            {$mod_strings['LBL_HELP']}
            +

            + SugarCRM +

            + {$mod_strings['LBL_SITECFG_TITLE']}
            + SugarCRM +
            + {$errors} +
            {$mod_strings['LBL_REQUIRED']}
            + + +EOQ; + + + +//hide this in typical mode +if(isset($_SESSION['install_type']) && !empty($_SESSION['install_type']) && strtolower($_SESSION['install_type'])=='custom'){ +$out .=<< + + + + + + + +EOQ; +} + +$out .=<< + + + + + + + + + + +EOQ; + +$out .= << + + + + + +
            {$mod_strings['LBL_SITECFG_TITLE2']}
            {$mod_strings['LBL_SITECFG_URL_MSG']} +
            *{$mod_strings['LBL_SITECFG_URL']}

            {$mod_strings['LBL_SITECFG_SYS_NAME_MSG']}
            *{$mod_strings['LBL_SYSTEM_NAME']}
             
            {$mod_strings['LBL_SITECFG_PASSWORD_MSG']}
            *{$mod_strings['LBL_SITECFG_ADMIN_Name']}
            +
            *{$mod_strings['LBL_SITECFG_ADMIN_PASS']}
            +
            *{$mod_strings['LBL_SITECFG_ADMIN_PASS_2']}
            +
            + + + + + +
            + + +
            +
            + +
            + + + +EOQ; + +echo $out; +?> diff --git a/install/siteConfig_b.php b/install/siteConfig_b.php new file mode 100644 index 00000000..1377be0e --- /dev/null +++ b/install/siteConfig_b.php @@ -0,0 +1,235 @@ +$value) + { + $language_keys[] = $key; + $language_values[] = $value; + } + + $_SESSION['language_keys'] = urlencode(implode(",",$language_keys)); + $_SESSION['language_values'] = urlencode(implode(",",$language_values)); + } +} + +//// errors +$errors = ''; +if( isset($validation_errors) ){ + if( count($validation_errors) > 0 ){ + $errors = '
            '; + $errors .= '

            '.$mod_strings['LBL_SITECFG_FIX_ERRORS'].'

              '; + foreach( $validation_errors as $error ){ + $errors .= '
            • ' . $error . '
            • '; + } + $errors .= '
            '; + } +} + + +//// ternaries +$sugarUpdates = (isset($_SESSION['setup_site_sugarbeet']) && !empty($_SESSION['setup_site_sugarbeet'])) ? 'checked="checked"' : ''; +$siteSecurity = (isset($_SESSION['setup_site_defaults']) && !empty($_SESSION['setup_site_defaults'])) ? 'checked="checked"' : ''; +$customSession = (isset($_SESSION['setup_site_custom_session_path']) && !empty($_SESSION['setup_site_custom_session_path'])) ? 'checked="checked"' : ''; +$customLog = (isset($_SESSION['setup_site_custom_log_dir']) && !empty($_SESSION['setup_site_custom_log_dir'])) ? 'checked="checked"' : ''; +$customId = (isset($_SESSION['setup_site_specify_guid']) && !empty($_SESSION['setup_site_specify_guid'])) ? 'checked="checked"' : ''; + +/////////////////////////////////////////////////////////////////////////////// +//// START OUTPUT +$out =<< + + + + + + {$mod_strings['LBL_WIZARD_TITLE']} {$mod_strings['LBL_SITECFG_SECURITY_TITLE']} + + + + + + +
            + + + + + + + + + + + + + +
            {$mod_strings['LBL_HELP']}
            +

            + SugarCRM +

            + {$mod_strings['LBL_SITECFG_SECURITY_TITLE']}
            SugarCRM
            + {$errors} +
            {$mod_strings['LBL_REQUIRED']}
            + + + +EOQ; +$checked = ''; +if(!empty($_SESSION['setup_site_sugarbeet_anonymous_stats'])) $checked = 'checked="checked"'; +$out .= " + + + + +"; +$checked = ''; +if(!empty($_SESSION['setup_site_sugarbeet_automatic_checks'])) $checked = 'checked="checked"'; +$out .= << + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
            {$mod_strings['LBL_SITECFG_SITE_SECURITY']}
            {$mod_strings['LBL_SITECFG_ANONSTATS']}
            {$mod_strings['LBL_SITECFG_ANONSTATS_DIRECTIONS']}
            {$mod_strings['LBL_SITECFG_SUGAR_UP']}
            {$mod_strings['LBL_SITECFG_SUGAR_UP_DIRECTIONS']}
             
            {$mod_strings['LBL_SITECFG_CUSTOM_SESSION']}
            + {$mod_strings['LBL_SITECFG_CUSTOM_SESSION_DIRECTIONS']}
             
            * +
            {$mod_strings['LBL_SITECFG_SESSION_PATH']}
            +
            {$mod_strings['LBL_SITECFG_CUSTOM_LOG']}
            + {$mod_strings['LBL_SITECFG_CUSTOM_LOG_DIRECTIONS']}
             
            * +
            {$mod_strings['LBL_SITECFG_LOG_DIR']}
            + +
            +
            {$mod_strings['LBL_SITECFG_CUSTOM_ID']}
            + {$mod_strings['LBL_SITECFG_CUSTOM_ID_DIRECTIONS']}
             
            * +
            {$mod_strings['LBL_SITECFG_APP_ID']}
            + +
            +
            +
            +
            + + + + + +
            + + +
            +
            +
            +
            + + + +EOQ; + +echo $out; +?> diff --git a/install/systemOptions.php b/install/systemOptions.php new file mode 100644 index 00000000..7d170276 --- /dev/null +++ b/install/systemOptions.php @@ -0,0 +1,174 @@ + 0) { + $errs = '
            '; + $errs .= "

            {$mod_strings['LBL_SYSOPTS_ERRS_TITLE']}

            "; + $errs .= '
              '; + + foreach($validation_errors as $error) { + $errs .= '
            • ' . $error . '
            • '; + } + + $errs .= '
            '; + $errs .= '
            '; + } +} + +$mysql = ''; +$oci8 = ''; +$mssql = ''; +if($setup_db_type == "mysql") + $mysql = 'checked="checked"'; +else if ($setup_db_type == "mssql") + $mssql = 'checked="checked"'; + + +$out=<< + + + + + + {$mod_strings['LBL_WIZARD_TITLE']} {$mod_strings['LBL_SYSOPTS_DB_TITLE']} + + + + + +
            + + + + + + + + + + + + + +
            {$mod_strings['LBL_HELP']}
            +

            + SugarCRM +

            + {$mod_strings['LBL_SYSOPTS_DB_TITLE']}
            + SugarCRM +
            + {$errs} + + + + + + + + +
            {$mod_strings['LBL_SYSOPTS_DB']}
            {$mod_strings['LBL_SYSOPTS_2']}
              +EOQ; +if(function_exists('mysql_connect') || function_exists('mysqli_connect')){ +$out.=<<{$mod_strings['LBL_MYSQL']} +EOQ; +//check to see if mysqli is enabled +if(function_exists('mysqli_connect')){ + $_SESSION['mysql_type'] = 'mysqli'; + $out.='  (MySQLi detected)
            '; +}else{ + $out.= '
            '; +} +} +if(function_exists('mssql_connect') || function_exists('sqlsrv_connect')){ +$out.=<<{$mod_strings['LBL_MSSQL']} +EOQ; +} +//check to see if sqlsrv is enabled +if(function_exists('sqlsrv_connect')){ + $_SESSION['mssql_type'] = 'sqlsrv'; + $out.='  (Microsoft SQL Server Driver for PHP detected)
            '; +}else{ + $out.= '
            '; +} + + + + +$out.=<< +
              + +EOQ; + +$out.=<< + +
            +
            +
            + + + + + + +
            + + +
            +
            +
            + + +EOQ; +echo $out; +?> diff --git a/install/welcome.php b/install/welcome.php new file mode 100644 index 00000000..2adbac0b --- /dev/null +++ b/install/welcome.php @@ -0,0 +1,145 @@ + + + + + + {$mod_strings['LBL_WIZARD_TITLE']} {$mod_strings['LBL_TITLE_WELCOME']} {$setup_sugar_version} {$mod_strings['LBL_WELCOME_SETUP_WIZARD']} + + + + + +
            + + + + + + + + + + + + + + + + + +
            {$mod_strings['LBL_HELP']}
            +

            + SugarCRM +

            + {$mod_strings['LBL_TITLE_WELCOME']} {$setup_sugar_version} {$mod_strings['LBL_WELCOME_SETUP_WIZARD']}
            SugarCRM +
            Sugar Themes
            + {$mod_strings['LBL_WELCOME_CHOOSE_LANGUAGE']}: + +   +
            +
            + + + + + +
            + + + +
            +
            +
            + + + +EOQ; +if (version_compare(phpversion(),'5.2.0') < 0) { + if(empty($mod_strings['LBL_MINIMUM_PHP_VERSION'])){ + $mod_strings['LBL_MINIMUM_PHP_VERSION'] = 'Minimum Php version required is 5.2.1.'; + } + +$php_verison_warning =<< +
            Sugar Themes
            +

            {$mod_strings['LBL_MINIMUM_PHP_VERSION']}

            +
            Sugar Themes
            +eoq; + $out = $php_verison_warning; +} +echo $out; +?> diff --git a/json.php b/json.php new file mode 100644 index 00000000..b6e4d41c --- /dev/null +++ b/json.php @@ -0,0 +1,112 @@ +retrieve($_REQUEST['record']); + + $all_fields = array_merge($focus->column_fields,$focus->additional_column_fields); + + $obj = array(); + $ret = array(); + + foreach($all_fields as $field) { + if(isset($focus->$field)) { + $obj[$field] = $focus->$field; + } + } + + // cn: bug 12274 - defend against CSRF + $ret['fields'] = $obj; + print $json->encode($ret, true); +} + +function json_get_full_list() { + global $beanFiles; + global $beanList; + + require_once('include/utils.php'); + require_once($beanFiles[$beanList[$_REQUEST['module']]]); + + $json = getJSONobj(); + + $where = str_replace('\\','', rawurldecode($_REQUEST['where'])); + $order = str_replace('\\','', rawurldecode($_REQUEST['order'])); + $focus = new $beanList[$_REQUEST['module']]; + $fullList = $focus->get_full_list($order, $where, ''); + $all_fields = array_merge($focus->column_fields,$focus->additional_column_fields); + + $js_fields_arr = array(); + + $i=1; // js doesn't like 0 index? + foreach($fullList as $note) { + $js_fields_arr[$i] = array(); + + foreach($all_fields as $field) { + if(isset($note->$field)) { + $note->$field = from_html($note->$field); + $note->$field = preg_replace('/\r\n/','
            ',$note->$field); + $note->$field = preg_replace('/\n/','
            ',$note->$field); + $js_fields_arr[$i][$field] = addslashes($note->$field); + } + } + $i++; + } + + $out = $json->encode($js_fields_arr, true); + print($out); +} +//// END HELPER FUNCTIONS +/////////////////////////////////////////////////////////////////////////////// + +// called from another file +$GLOBALS['log'] = LoggerManager::getLogger('json.php'); + +$supported_functions = array('retrieve','get_full_list'); +if(in_array($_REQUEST['action'],$supported_functions)) { + call_user_func('json_'.$_REQUEST['action']); +} + +?> diff --git a/json_server.php b/json_server.php new file mode 100644 index 00000000..f97ede8d --- /dev/null +++ b/json_server.php @@ -0,0 +1,765 @@ +debug("JSON_SERVER:"); +$global_registry_var_name = 'GLOBAL_REGISTRY'; + +/////////////////////////////////////////////////////////////////////////////// +//// SUPPORTED METHODS +/* + * ADD NEW METHODS TO THIS ARRAY: + * then create a function called "function json_$method($request_id, &$params)" + * where $method is the method name + */ +$SUPPORTED_METHODS = array( + 'retrieve', + 'query', + 'set_accept_status', + 'get_user_array', + 'get_objects_from_module', + 'email', + 'get_full_list' +); + +/** + * Generic retrieve for getting data from a sugarbean + */ +function json_retrieve($request_id, $params) { + global $current_user; + global $beanFiles,$beanList; + $json = getJSONobj(); + + $record = $params[0]['record']; + + require_once($beanFiles[$beanList[$params[0]['module']]]); + $focus = new $beanList[$params[0]['module']]; + $focus->retrieve($record); + + // to get a simplified version of the sugarbean + $module_arr = populateBean($focus); + + $response = array(); + $response['id'] = $request_id; + $response['result'] = array("status"=>"success","record"=>$module_arr); + $json_response = $json->encode($response, true); + print $json_response; +} + +function json_query($request_id, $params) { + global $response, $sugar_config; + global $beanFiles, $beanList; + $json = getJSONobj(); + + if($sugar_config['list_max_entries_per_page'] < 31) // override query limits + $sugar_config['list_max_entries_per_page'] = 31; + + $args = $params[0]; + + //decode condition parameter values.. + if(is_array($args['conditions'])) { + foreach($args['conditions'] as $key=>$condition) { + if(!empty($condition['value'])) { + $where = $json->decode(utf8_encode($condition['value'])); + // cn: bug 12693 - API change due to CSRF security changes. + $where = empty($where) ? $condition['value'] : $where; + $args['conditions'][$key]['value'] = $where; + } + } + } + + $list_return = array(); + + if(! empty($args['module'])) { + $args['modules'] = array($args['module']); + } + + foreach($args['modules'] as $module) { + require_once($beanFiles[$beanList[$module]]); + $focus = new $beanList[$module]; + + $query_orderby = ''; + if(!empty($args['order'])) { + $query_orderby = $args['order']; + } + $query_limit = ''; + if(!empty($args['limit'])) { + $query_limit = $args['limit']; + } + $query_where = construct_where($args, $focus->table_name,$module); + $list_arr = array(); + if($focus->ACLAccess('ListView', true)) { + $focus->ungreedy_count=false; + $curlist = $focus->get_list($query_orderby, $query_where, 0, $query_limit, -1, 0); + $list_return = array_merge($list_return,$curlist['list']); + } + } + + $app_list_strings = null; + + for($i = 0;$i < count($list_return);$i++) { + if(isset($list_return[$i]->emailAddress) && is_object($list_return[$i]->emailAddress)) { + $list_return[$i]->emailAddress->handleLegacyRetrieve($list_return[$i]); + } + + $list_arr[$i]= array(); + $list_arr[$i]['fields']= array(); + $list_arr[$i]['module']= $list_return[$i]->object_name; + + foreach($args['field_list'] as $field) { + // handle enums + if( (isset($list_return[$i]->field_name_map[$field]['type']) && $list_return[$i]->field_name_map[$field]['type'] == 'enum') || + (isset($list_return[$i]->field_name_map[$field]['custom_type']) && $list_return[$i]->field_name_map[$field]['custom_type'] == 'enum')) { + + // get fields to match enum vals + if(empty($app_list_strings)) { + if(isset($_SESSION['authenticated_user_language']) && $_SESSION['authenticated_user_language'] != '') $current_language = $_SESSION['authenticated_user_language']; + else $current_language = $sugar_config['default_language']; + $app_list_strings = return_app_list_strings_language($current_language); + } + + // match enum vals to text vals in language pack for return + if(!empty($app_list_strings[$list_return[$i]->field_name_map[$field]['options']])) { + $list_return[$i]->$field = $app_list_strings[$list_return[$i]->field_name_map[$field]['options']][$list_return[$i]->$field]; + } + } + + $list_arr[$i]['fields'][$field] = $list_return[$i]->$field; + } + } + + + $response['id'] = $request_id; + $response['result'] = array("list"=>$list_arr); + $json_response = $json->encode($response, true); + echo $json_response; +} + + +function json_set_accept_status($request_id, $params) { + global $current_user; + global $beanFiles,$beanList; + $json = getJSONobj(); + require_once($beanFiles[$beanList[$params[0]['module']]]); + + $focus = new $beanList[$params[0]['module']]; + $focus->id = $params[0]['record']; + + $test = $focus->set_accept_status($current_user,$params[0]['accept_status']); + + $response = array(); + $response['id'] = $request_id; + $response['result'] = array("status"=>"success","record"=>$params[0]['record'],'accept_status'=>$params[0]['accept_status']); + $json_response = $json->encode($response, true); + print $json_response; +} + + +/** + * retrieves Users matching passed criteria + */ +function json_get_user_array($request_id, $params) { + $json = getJSONobj(); + $args = $params[0]; + + //decode condition parameter values.. + if(is_array($args['conditions'])) { + foreach($args['conditions'] as $key=>$condition) { + if(!empty($condition['value'])) { + $args['conditions'][$key]['value']=$json->decode($condition['value']); + } + } + } + + $response = array(); + $response['id'] = $request_id; + $response['result'] = array(); + $response['result']['list'] = array(); + + if(showFullName()) { + $user_array = getUserArrayFromFullName($args['conditions'][0]['value']); + } else { + $user_array = get_user_array(false, "Active", $focus->assigned_user_id, false, $args['conditions'][0]['value']); + } + + foreach($user_array as $id=>$name) { + array_push($response['result']['list'], array('fields' => array('id' => $id, 'user_name' => $name), 'module' => 'Users')); + } + + print $json->encode($response, true); +} + +function json_get_objects_from_module($request_id, $params) { + global $beanList, $beanFiles, $current_user; + $json = getJSONobj(); + + $module_name = $params[0]['module']; + $offset = intval($params[0]['offset']); + $where = $params[0]['where']; + $max = $params[0]['max']; + $order_by = $params[0]['order_by']; + $using_cp = false; + + if($module_name == 'CampaignProspects'){ + $module_name = 'Prospects'; + $using_cp = true; + } + + $class_name = $beanList[$module_name]; + require_once($beanFiles[$class_name]); + $seed = new $class_name(); + if($where == ''){ + $where = ''; + } + if($offset == '' || $offset == -1){ + $offset = 0; + } + if($max == ''){ + $max = 10; + } + + $deleted = '0'; + if($using_cp){ + $fields = array('id', 'first_name', 'last_name'); + $response = $seed->retrieveTargetList($where, $fields, $offset,-1,$max,$deleted); + }else{ + $response = $seed->get_list($order_by, $where, $offset,-1,$max,$deleted); + } + + $list = $response['list']; + $row_count = $response['row_count']; + + $output_list = array(); + foreach($list as $value) + { + $output_list[] = get_return_value($value, $module_name); + } + $response = array(); + $response['id'] = $request_id; + + $response['result'] = array('result_count'=>$row_count,'entry_list'=>$output_list); + $json_response = $json->encode($response, true); + print $json_response; +} + + + + +function json_email($request_id, $params) { + global $response, $sugar_config; + global $beanFiles,$beanList; + $json = getJSONobj(); + + $args = $params[0]; + + if($sugar_config['list_max_entries_per_page'] < 50) // override query limits + $sugar_config['list_max_entries_per_page'] = 50; + + $list_return = array(); + + if(! empty($args['module'])) { + $args['modules'] = array($args['module']); + } + + foreach($args['modules'] as $module) { + require_once($beanFiles[$beanList[$module]]); + $focus = new $beanList[$module]; + + $query_orderby = ''; + if(!empty($args['order'])) { + $query_orderby = $args['order']; + } + $query_limit = ''; + if(!empty($args['limit'])) { + $query_limit = $args['limit']; + } + $query_where = construct_where($args,$focus->table_name); + $list_arr = array(); + + $curlist = $focus->get_list($query_orderby, $query_where, 0, $query_limit, -1, 0); + $list_return = array_merge($list_return,$curlist['list']); + } + + for($i = 0;$i < count($list_return);$i++) { + $list_arr[$i]= array(); + $list_arr[$i]['fields']= array(); + $list_arr[$i]['module']= $list_return[$i]->object_name; + + foreach($args['field_list'] as $field) { + $list_arr[$i]['fields'][$field] = $list_return[$i]->$field; + } + } + + $response['id'] = $request_id; + $response['result'] = array("list"=>$list_arr); + $json_response = $json->encode($response, true); + echo $json_response; +} + + +function json_get_full_list($request_id, $params) { + global $beanFiles; + global $beanList; + $json = getJSONobj(); + require_once($beanFiles[$beanList[$params[0]['module']]]); + + $where = str_replace('\\','', rawurldecode($params[0]['where'])); + $order = str_replace('\\','', rawurldecode($params[0]['order'])); + $focus = new $beanList[$params[0]['module']]; + + $fullList = $focus->get_full_list($order, $where, ''); + $all_fields = array_merge($focus->column_fields,$focus->additional_column_fields); + + $js_fields_arr = array(); + + if(isset($fullList) && !empty($fullList)) { // json error if this isn't defensive + $i=0; + foreach($fullList as $note) { + $js_fields_arr[$i] = array(); + + foreach($all_fields as $field) { + if(isset($note->$field)) { + $note->$field = from_html($note->$field); + $note->$field = preg_replace('/\r\n/','
            ',$note->$field); + $note->$field = preg_replace('/\n/','
            ',$note->$field); + $js_fields_arr[$i][$field] = addslashes($note->$field); + } + } + $i++; + } + } + + $fin['id'] = $request_id; + $fin['result'] = $js_fields_arr; + $out = $json->encode($fin, true); + + print($out); +} +//// END SUPPORTED METHODS +/////////////////////////////////////////////////////////////////////////////// + + + + + + + + + + + +// ONLY USED FOR MEETINGS +function meeting_retrieve($module,$record) { + global $response; + global $beanFiles,$beanList; + //header('Content-type: text/xml'); + require_once($beanFiles[$beanList[$module]]); + $focus = new $beanList[$module]; + $json = getJSONobj(); + + if(empty($module) || empty($record)) + { + $response['error'] = array("error_msg"=>"method: retrieve: missing module or record as parameters"); + print $json->encode($response, true); + + } + + $focus->retrieve($record); + + $GLOBALS['log']->debug("JSON_SERVER:retrieved meeting:"); + + $module_arr = populateBean($focus); + + if($module == 'Meetings') + { + $users = $focus->get_meeting_users(); + } else if($module == 'Calls') + { + $users = $focus->get_call_users(); + } + + $module_arr['users_arr'] = array(); + + foreach($users as $user) + { + array_push($module_arr['users_arr'], populateBean($user)); + } + $module_arr['orig_users_arr_hash'] = array(); + foreach($users as $user) + { + $module_arr['orig_users_arr_hash'][$user->id] = '1'; + } + + $module_arr['contacts_arr'] = array(); + + $focus->load_relationships('contacts'); + $contacts=$focus->get_linked_beans('contacts','Contact'); + foreach($contacts as $contact) + { + array_push($module_arr['users_arr'], populateBean($contact)); + } + + return $module_arr; +} + +// HAS MEETING SPECIFIC CODE: +function populateBean(&$focus) { + $all_fields = $focus->column_fields; + // MEETING SPECIFIC + $all_fields = array_merge($all_fields,array('required','accept_status','name')); // need name field for contacts and users + //$all_fields = array_merge($focus->column_fields,$focus->additional_column_fields); + + $module_arr = array(); + + $module_arr['module'] = $focus->object_name; + + $module_arr['fields'] = array(); + + foreach($all_fields as $field) + { + if(isset($focus->$field)) + { + $focus->$field = from_html($focus->$field); + $focus->$field = preg_replace("/\r\n/","
            ",$focus->$field); + $focus->$field = preg_replace("/\n/","
            ",$focus->$field); + $module_arr['fields'][$field] = $focus->$field; + } + } +$GLOBALS['log']->debug("JSON_SERVER:populate bean:"); + return $module_arr; +} + + + + + + + + + + + + +function getUserJSON() { +} + + +function getUserConfigJSON() { + require_once('include/TimeDate.php'); + $timedate = TimeDate::getInstance(); + global $current_user,$global_registry_var_name,$json,$sugar_config; + + if(isset($_SESSION['authenticated_user_theme']) && $_SESSION['authenticated_user_theme'] != '') + { + $theme = $_SESSION['authenticated_user_theme']; + } + else + { + $theme = $sugar_config['default_theme']; + } + $user_arr = array(); + $user_arr['theme'] = $theme; + $user_arr['fields'] = array(); + $user_arr['module'] = 'User'; + $user_arr['fields']['id'] = $current_user->id; + $user_arr['fields']['user_name'] = $current_user->user_name; + $user_arr['fields']['first_name'] = $current_user->first_name; + $user_arr['fields']['last_name'] = $current_user->last_name; + $user_arr['fields']['email'] = $current_user->email1; + $user_arr['fields']['gmt_offset'] = $timedate->getUserUTCOffset(); + $str = "\n".$global_registry_var_name.".current_user = ".$json->encode($user_arr, true).";\n"; +return $str; + +} + + + + + + +/////////////////////////////////////////////////////////////////////////////// +//// UTILS +function authenticate() { + global $sugar_config; + + $user_unique_key =(isset($_SESSION['unique_key'])) ? $_SESSION['unique_key'] : ""; + $server_unique_key =(isset($sugar_config['unique_key'])) ? $sugar_config['unique_key'] : ""; + + if($user_unique_key != $server_unique_key) { + $GLOBALS['log']->debug("JSON_SERVER: user_unique_key:".$user_unique_key."!=".$server_unique_key); + session_destroy(); + return null; + } + + if(!isset($_SESSION['authenticated_user_id'])) { + $GLOBALS['log']->debug("JSON_SERVER: authenticated_user_id NOT SET. DESTROY"); + session_destroy(); + return null; + } + + $current_user = new User(); + + $result = $current_user->retrieve($_SESSION['authenticated_user_id']); + $GLOBALS['log']->debug("JSON_SERVER: retrieved user from SESSION"); + + + if($result == null) { + $GLOBALS['log']->debug("JSON_SERVER: could get a user from SESSION. DESTROY"); + session_destroy(); + return null; + } + + return $result; +} + +function construct_where(&$query_obj, $table='',$module=null) { + if(! empty($table)) { + $table .= "."; + } + $cond_arr = array(); + + if(! is_array($query_obj['conditions'])) { + $query_obj['conditions'] = array(); + } + + foreach($query_obj['conditions'] as $condition) { + + if ($condition['name']=='email1' or $condition['name']=='email2') { + + $email1_value=strtoupper($condition['value']); + $email1_condition = " {$table}id in ( SELECT er.bean_id AS id FROM email_addr_bean_rel er, " . + "email_addresses ea WHERE ea.id = er.email_address_id " . + "AND ea.deleted = 0 AND er.deleted = 0 AND er.bean_module = '{$module}' AND email_address_caps LIKE '%{$email1_value}%' )"; + + array_push($cond_arr,$email1_condition); + } + else { + if($condition['op'] == 'contains') { + $cond_arr[] = $GLOBALS['db']->quote($table.$condition['name'])." like '%".$GLOBALS['db']->quote($condition['value'])."%'"; + } + if($condition['op'] == 'like_custom') { + $like = ''; + if(!empty($condition['begin'])) $like .= $GLOBALS['db']->quote($condition['begin']); + $like .= $GLOBALS['db']->quote($condition['value']); + if(!empty($condition['end'])) $like .= $GLOBALS['db']->quote($condition['end']); + $cond_arr[] = $GLOBALS['db']->quote($table.$condition['name'])." like '$like'"; + } else { // starts_with + $cond_arr[] = $GLOBALS['db']->quote($table.$condition['name'])." like '".$GLOBALS['db']->quote($condition['value'])."%'"; + } + } + } + + if($table == 'users.') { + $cond_arr[] = $table."status='Active'"; + } + + return implode(" {$query_obj['group']} ",$cond_arr); +} + +function getAppMetaJSON() { + global $global_registry_var_name, $sugar_config; + $json = getJSONobj(); + + $str = "\nvar ".$global_registry_var_name." = new Object();\n"; + $str .= "\n".$global_registry_var_name.".config = {\"site_url\":\"".getJavascriptSiteURL()."\"};\n"; + + $str .= $global_registry_var_name.".meta = new Object();\n"; + $str .= $global_registry_var_name.".meta.modules = new Object();\n"; + $modules_arr = array('Meetings','Calls'); + $meta_modules = array(); + + global $beanFiles,$beanList; + //header('Content-type: text/xml'); + foreach($modules_arr as $module) { + require_once($beanFiles[$beanList[$module]]); + $focus = new $beanList[$module]; + $meta_modules[$module] = array(); + $meta_modules[$module]['field_defs'] = $focus->field_defs; + } + + $str .= $global_registry_var_name.".meta.modules.Meetings = ". $json->encode($meta_modules['Meetings'], true)."\n"; + $str .= $global_registry_var_name.".meta.modules.Calls = ". $json->encode($meta_modules['Calls'], true)."\n"; + return $str; +} + +function getFocusData() { + global $global_registry_var_name; + $json = getJSONobj(); + + if(empty($_REQUEST['module']) ) + return ''; + elseif(empty($_REQUEST['record'] ) ) + return "\n".$global_registry_var_name.'["focus"] = {"module":"'.$_REQUEST['module'].'",users_arr:[],fields:{"id":"-1"}}'."\n"; + + $module_arr = meeting_retrieve($_REQUEST['module'], $_REQUEST['record']); + return "\n".$global_registry_var_name."['focus'] = ". $json->encode($module_arr, true).";\n"; +} + +function getStringsJSON() { + //set module and application string arrays based upon selected language + global $current_language; + global $global_registry_var_name; + $json = getJSONobj(); + + $currentModule = 'Calendar'; + $mod_list_strings = return_mod_list_strings_language($current_language,$currentModule); + $str = "\n".$global_registry_var_name."['calendar_strings'] = {\"dom_cal_month_long\":". $json->encode($mod_list_strings['dom_cal_month_long']).",\"dom_cal_weekdays_long\":". $json->encode($mod_list_strings['dom_cal_weekdays_long'])."}\n"; + + if(empty($_REQUEST['module'])) + $_REQUEST['module'] = 'Home'; + + $currentModule = $_REQUEST['module']; + $mod_strings = return_module_language($current_language,$currentModule); + return $str . "\n".$global_registry_var_name."['meeting_strings'] = ". $json->encode($mod_strings, true)."\n"; +} +//// END UTILS +/////////////////////////////////////////////////////////////////////////////// + + + +/////////////////////////////////////////////////////////////////////////////// +//// JSON SERVER HANDLER LOGIC +//ignore notices +error_reporting(E_ALL ^ E_NOTICE); +ob_start(); +insert_charset_header(); + +if(!empty($sugar_config['session_dir'])) { + session_save_path($sugar_config['session_dir']); + $GLOBALS['log']->debug("JSON_SERVER:session_save_path:".$sugar_config['session_dir']); +} + +session_start(); +$GLOBALS['log']->debug("JSON_SERVER:session started"); + +$current_language = 'en_us'; // defaulting - will be set by user, then sys prefs + +// create json parser +$json = getJSONobj(); + +// if the language is not set yet, then set it to the default language. +if(isset($_SESSION['authenticated_user_language']) && $_SESSION['authenticated_user_language'] != '') { + $current_language = $_SESSION['authenticated_user_language']; +} else { + $current_language = $sugar_config['default_language']; +} + +$locale = new Localization(); + +$GLOBALS['log']->debug("JSON_SERVER: current_language:".$current_language); + +// if this is a get, than this is spitting out static javascript as if it was a file +// wp: DO NOT USE THIS. Include the javascript inline using include/json_config.php +// using does not cache properly on some browsers +// resulting in 2 or more server hits per page load. Very bad for SSL. +if(strtolower($_SERVER['REQUEST_METHOD'])== 'get') { + echo "alert('DEPRECATED API\nPlease report as a bug.');"; + /** + * Deprecated for security reasons. + * + * DO NOT USE. + * + * + $current_user = authenticate(); + if(empty($current_user)) { + $GLOBALS['log']->debug("JSON_SERVER: current_user isn't set"); + print ""; + } + + $str = ''; + $str .= getAppMetaJSON(); + $GLOBALS['log']->debug("JSON_SERVER:getAppMetaJSON"); + + if($_GET['module'] != '_configonly') { + $str .= getFocusData(); + $GLOBALS['log']->debug("JSON_SERVER: getFocusData"); + $str .= getStringsJSON(); + $GLOBALS['log']->debug("JSON_SERVER:getStringsJSON"); + } + + $str .= getUserConfigJSON(); + $GLOBALS['log']->debug("JSON_SERVER:getUserConfigJSON"); + print $str; + */ +} else { + // else act as a JSON-RPC server for SugarCRM + // create result array + $response = array(); + $response['result'] = null; + $response['id'] = "-1"; + + // authenticate user + $current_user = authenticate(); + + if(empty($current_user)) { + $response['error'] = array("error_msg"=>"not logged in"); + print $json->encode($response, true); + print "not logged in"; + } + + // extract request + if(isset($GLOBALS['HTTP_RAW_POST_DATA'])) + $request = $json->decode($GLOBALS['HTTP_RAW_POST_DATA'], true); + else + $request = $json->decode(file_get_contents("php://input"), true); + + + if(!is_array($request)) { + $response['error'] = array("error_msg"=>"malformed request"); + print $json->encode($response, true); + } + + // make sure required RPC fields are set + if(empty($request['method']) || empty($request['id'])) { + $response['error'] = array("error_msg"=>"missing parameters"); + print $json->encode($response, true); + } + + $response['id'] = $request['id']; + + if(in_array($request['method'], $SUPPORTED_METHODS)) { + call_user_func('json_'.$request['method'],$request['id'],$request['params']); + } else { + $response['error'] = array("error_msg"=>"method:".$request["method"]." not supported"); + print $json->encode($response, true); + } +} + +ob_end_flush(); +sugar_cleanup(); +exit(); +?> \ No newline at end of file diff --git a/jssource/JSGroupings.php b/jssource/JSGroupings.php new file mode 100644 index 00000000..d2fef50b --- /dev/null +++ b/jssource/JSGroupings.php @@ -0,0 +1,156 @@ + $Concatenated_file_location + * + * If you wish to add a grouping that contains a file that is part of another group already, + * add a '.' after the .js in order to make the element key unique. Make sure you pare the extension out + * + */ + + $js_groupings = array( + $sugar_grp1 = array( + //scripts loaded on first page + 'include/javascript/sugar_3.js' => 'include/javascript/sugar_grp1.js', + 'include/javascript/cookie.js' => 'include/javascript/sugar_grp1.js', + 'include/javascript/menu.js' => 'include/javascript/sugar_grp1.js', + 'include/javascript/calendar.js' => 'include/javascript/sugar_grp1.js', + 'include/javascript/quickCompose.js' => 'include/javascript/sugar_grp1.js', + 'include/javascript/yui/build/yuiloader/yuiloader-min.js' => 'include/javascript/sugar_grp1.js', + ), + + $sugar_grp1_yui = array( + //YUI scripts loaded on first page + 'include/javascript/yui/build/yahoo/yahoo-min.js' => 'include/javascript/sugar_grp1_yui.js', + 'include/javascript/yui/build/dom/dom-min.js' => 'include/javascript/sugar_grp1_yui.js', + 'include/javascript/yui/build/yahoo-dom-event/yahoo-dom-event-min.js' + => 'include/javascript/sugar_grp1_yui.js', + 'include/javascript/yui/build/event/event-min.js' => 'include/javascript/sugar_grp1_yui.js', + 'include/javascript/yui/build/logger/logger-min.js' => 'include/javascript/sugar_grp1_yui.js', + 'include/javascript/yui/build/animation/animation-min.js' => 'include/javascript/sugar_grp1_yui.js', + 'include/javascript/yui/build/connection/connection-min.js' => 'include/javascript/sugar_grp1_yui.js', + 'include/javascript/yui/build/dragdrop/dragdrop-min.js' => 'include/javascript/sugar_grp1_yui.js', + //Ensure we grad the SLIDETOP custom container animation + 'include/javascript/yui/build/container/container-min.js' => 'include/javascript/sugar_grp1_yui.js', + 'include/javascript/yui/build/selector/selector-min.js'=> 'include/javascript/sugar_grp1_yui.js', + //This should probably be removed as it is not often used with the rest of YUI + 'include/javascript/yui/ygDDList.js' => 'include/javascript/sugar_grp1_yui.js', + //YUI based quicksearch + 'include/javascript/yui/build/datasource/datasource-min.js' => 'include/javascript/sugar_grp1_yui.js', + 'include/javascript/yui/build/json/json-min.js' => 'include/javascript/sugar_grp1_yui.js', + 'include/javascript/yui/build/autocomplete/autocomplete-min.js'=> 'include/javascript/sugar_grp1_yui.js', + 'include/javascript/quicksearch.js' => 'include/javascript/sugar_grp1_yui.js', + 'include/javascript/yui/build/menu/menu-min.js' => 'include/javascript/sugar_grp1_yui.js', + 'include/javascript/sugar_connection_event_listener.js' => 'include/javascript/sugar_grp1_yui.js', + 'include/javascript/yui/build/calendar/calendar.js' => 'include/javascript/sugar_grp1_yui.js', + + ), + + $sugar_grp_yui_widgets = array( + //sugar_grp1_yui must be laoded before sugar_grp_yui_widgets + 'include/javascript/yui/build/element/element-min.js' => 'include/javascript/sugar_grp_yui_widgets.js', + 'include/javascript/yui/build/datatable/datatable-min.js' => 'include/javascript/sugar_grp_yui_widgets.js', + 'include/javascript/yui/build/tabview/tabview-min.js' => 'include/javascript/sugar_grp_yui_widgets.js', + 'include/javascript/yui/build/treeview/treeview-min.js' => 'include/javascript/sugar_grp_yui_widgets.js', + 'include/javascript/yui/build/button/button-min.js' => 'include/javascript/sugar_grp_yui_widgets.js', + 'include/javascript/yui/build/calendar/calendar-min.js' => 'include/javascript/sugar_grp_yui_widgets.js', + 'include/javascript/sugarwidgets/SugarYUIWidgets.js' => 'include/javascript/sugar_grp_yui_widgets.js', + ), + + $sugar_grp_yui_widgets_css = array( + "include/javascript/yui/build/fonts/fonts-min.css" => 'include/javascript/sugar_grp_yui_widgets.css', + "include/javascript/yui/build/treeview/assets/skins/sam/treeview.css" + => 'include/javascript/sugar_grp_yui_widgets.css', + "include/javascript/yui/build/datatable/assets/skins/sam/datatable.css" + => 'include/javascript/sugar_grp_yui_widgets.css', + "include/javascript/yui/build/container/assets/skins/sam/container.css" + => 'include/javascript/sugar_grp_yui_widgets.css', + "include/javascript/yui/build/button/assets/skins/sam/button.css" + => 'include/javascript/sugar_grp_yui_widgets.css', + "include/javascript/yui/build/calendar/assets/skins/sam/calendar.css" + => 'include/javascript/sugar_grp_yui_widgets.css', + ), + + $sugar_grp_yui2 = array( + //YUI combination 2 + 'include/javascript/yui/build/dragdrop/dragdrop-min.js' => 'include/javascript/sugar_grp_yui2.js', + 'include/javascript/yui/build/container/container-min.js' => 'include/javascript/sugar_grp_yui2.js', + ), + + $sugar_grp_overlib = array( + //overlib combination + 'include/javascript/overlibmws.js' => 'include/javascript/sugar_grp_overlib.js', + 'include/javascript/overlibmws_iframe.js' => 'include/javascript/sugar_grp_overlib.js', + ), + + //Grouping for emails module. + $sugar_grp_emails = array( + 'include/javascript/yui/ygDDList.js' => 'include/javascript/sugar_grp_emails.js', + 'include/SugarEmailAddress/SugarEmailAddress.js' => 'include/javascript/sugar_grp_emails.js', + 'include/SugarFields/Fields/Collection/SugarFieldCollection.js' => 'include/javascript/sugar_grp_emails.js', + 'modules/InboundEmail/InboundEmail.js' => 'include/javascript/sugar_grp_emails.js', + 'modules/Emails/javascript/EmailUIShared.js' => 'include/javascript/sugar_grp_emails.js', + 'modules/Emails/javascript/EmailUI.js' => 'include/javascript/sugar_grp_emails.js', + 'modules/Emails/javascript/EmailUICompose.js' => 'include/javascript/sugar_grp_emails.js', + 'modules/Emails/javascript/ajax.js' => 'include/javascript/sugar_grp_emails.js', + 'modules/Emails/javascript/grid.js' => 'include/javascript/sugar_grp_emails.js', + 'modules/Emails/javascript/complexLayout.js' => 'include/javascript/sugar_grp_emails.js', + 'modules/Emails/javascript/init.js' => 'include/javascript/sugar_grp_emails.js', + 'modules/Emails/javascript/composeEmailTemplate.js' => 'include/javascript/sugar_grp_emails.js', + 'modules/Emails/javascript/displayOneEmailTemplate.js' => 'include/javascript/sugar_grp_emails.js', + 'modules/Emails/javascript/viewPrintable.js' => 'include/javascript/sugar_grp_emails.js', + 'include/javascript/quicksearch.js' => 'include/javascript/sugar_grp_emails.js', + + ), + + //Grouping for the quick compose functionality. + $sugar_grp_quick_compose = array( + 'modules/Emails/javascript/vars.js' => 'include/javascript/sugar_grp_quickcomp.js', + 'include/SugarFields/Fields/Collection/SugarFieldCollection.js' => 'include/javascript/sugar_grp_quickcomp.js', //For team selection + 'modules/Emails/javascript/EmailUIShared.js' => 'include/javascript/sugar_grp_quickcomp.js', + 'modules/Emails/javascript/ajax.js' => 'include/javascript/sugar_grp_quickcomp.js', + 'modules/Emails/javascript/grid.js' => 'include/javascript/sugar_grp_quickcomp.js', //For address book + 'modules/Emails/javascript/EmailUICompose.js' => 'include/javascript/sugar_grp_quickcomp.js', + 'modules/Emails/javascript/composeEmailTemplate.js' => 'include/javascript/sugar_grp_quickcomp.js', + 'modules/Emails/javascript/complexLayout.js' => 'include/javascript/sugar_grp_quickcomp.js', + ), + ); + +?> diff --git a/jssource/jsmin.php b/jssource/jsmin.php new file mode 100644 index 00000000..3c2f859d --- /dev/null +++ b/jssource/jsmin.php @@ -0,0 +1,291 @@ + + * @copyright 2002 Douglas Crockford (jsmin.c) + * @copyright 2008 Ryan Grove (PHP port) + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 1.1.1 (2008-03-02) + * @link http://code.google.com/p/jsmin-php/ + */ + +class JSMin { + const ORD_LF = 10; + const ORD_SPACE = 32; + + protected $a = ''; + protected $b = ''; + protected $input = ''; + protected $inputIndex = 0; + protected $inputLength = 0; + protected $lookAhead = null; + protected $output = ''; + + // -- Public Static Methods -------------------------------------------------- + + public static function minify($js) { + $jsmin = new JSMin($js); + return $jsmin->min(); + } + + // -- Public Instance Methods ------------------------------------------------ + + public function __construct($input) { + $this->input = str_replace("\r\n", "\n", $input); + $this->inputLength = strlen($this->input); + } + + // -- Protected Instance Methods --------------------------------------------- + + protected function action($d) { + switch($d) { + case 1: + $this->output .= $this->a; + + case 2: + $this->a = $this->b; + + if ($this->a === "'" || $this->a === '"') { + for (;;) { + $this->output .= $this->a; + $this->a = $this->get(); + + if ($this->a === $this->b) { + break; + } + + if (ord($this->a) <= self::ORD_LF) { + throw new JSMinException('Unterminated string literal.'); + } + + if ($this->a === '\\') { + $this->output .= $this->a; + $this->a = $this->get(); + } + } + } + + case 3: + $this->b = $this->next(); + + if ($this->b === '/' && ( + $this->a === '(' || $this->a === ',' || $this->a === '=' || + $this->a === ':' || $this->a === '[' || $this->a === '!' || + $this->a === '&' || $this->a === '|' || $this->a === '?')) { + + $this->output .= $this->a . $this->b; + + for (;;) { + $this->a = $this->get(); + + if ($this->a === '/') { + break; + } elseif ($this->a === '\\') { + $this->output .= $this->a; + $this->a = $this->get(); + } elseif (ord($this->a) <= self::ORD_LF) { + throw new JSMinException('Unterminated regular expression '. + 'literal.'); + } + + $this->output .= $this->a; + } + + $this->b = $this->next(); + } + } + } + + protected function get() { + $c = $this->lookAhead; + $this->lookAhead = null; + + if ($c === null) { + if ($this->inputIndex < $this->inputLength) { + $c = substr($this->input, $this->inputIndex, 1); + $this->inputIndex += 1; + } else { + $c = null; + } + } + + if ($c === "\r") { + return "\n"; + } + + if ($c === null || $c === "\n" || ord($c) >= self::ORD_SPACE) { + return $c; + } + + return ' '; + } + + protected function isAlphaNum($c) { + return ord($c) > 126 || $c === '\\' || preg_match('/^[\w\$]$/', $c) === 1; + } + + protected function min() { + $this->a = "\n"; + $this->action(3); + + while ($this->a !== null) { + switch ($this->a) { + case ' ': + if ($this->isAlphaNum($this->b)) { + $this->action(1); + } else { + $this->action(2); + } + break; + + case "\n": + switch ($this->b) { + case '{': + case '[': + case '(': + case '+': + case '-': + $this->action(1); + break; + + case ' ': + $this->action(3); + break; + + default: + if ($this->isAlphaNum($this->b)) { + $this->action(1); + } + else { + $this->action(2); + } + } + break; + + default: + switch ($this->b) { + case ' ': + if ($this->isAlphaNum($this->a)) { + $this->action(1); + break; + } + + $this->action(3); + break; + + case "\n": + switch ($this->a) { + case '}': + case ']': + case ')': + case '+': + case '-': + case '"': + case "'": + $this->action(1); + break; + + default: + if ($this->isAlphaNum($this->a)) { + $this->action(1); + } + else { + $this->action(3); + } + } + break; + + default: + $this->action(1); + break; + } + } + } + + return $this->output; + } + + protected function next() { + $c = $this->get(); + + if ($c === '/') { + switch($this->peek()) { + case '/': + for (;;) { + $c = $this->get(); + + if (ord($c) <= self::ORD_LF) { + return $c; + } + } + + case '*': + $this->get(); + + for (;;) { + switch($this->get()) { + case '*': + if ($this->peek() === '/') { + $this->get(); + return ' '; + } + break; + + case null: + throw new JSMinException('Unterminated comment.'); + } + } + + default: + return $c; + } + } + + return $c; + } + + protected function peek() { + $this->lookAhead = $this->get(); + return $this->lookAhead; + } +} + +// -- Exceptions --------------------------------------------------------------- +class JSMinException extends Exception {} +?> \ No newline at end of file diff --git a/jssource/minify.php b/jssource/minify.php new file mode 100644 index 00000000..28328cb4 --- /dev/null +++ b/jssource/minify.php @@ -0,0 +1,154 @@ +$concat){ + //make sure both files are still valid + if(is_file($original) && is_file($concat)){ + //if individual file has been modifed date later than modified date of + //concatenated file, then force a rebuild + if(filemtime($original) > filemtime($concat)){ + $forceReb = true; + //no need to continue, we will rebuild + break; + } + }else{ + //if files are not valid, rebuild as one file could have been deleted + $forceReb = true; + //no need to continue, we will rebuild + break; + } + } + } + + } + //if boolean has been set, concatenate files + if($forceReb){ + ConcatenateFiles("$from"); + + } + + }else{ + //We are only allowing rebuilding of concat files from browser. + + } + return; +}else{ + //run via command line + //print_r($argv); + $from=""; + + if(isset($argv[1]) && !empty($argv[1])){ + $from = $argv[1]; + }else{ + //Root Directory was not specified + echo 'Root Directory Input was not provided'; + return; + } + +// require_once($argv[1].'/include/utils/sugar_file_utils.php'); + + if($argv[1] == '-?'){ + $argv[2] = '-?'; + } + + //if second argument is set, then process commands + if(!empty($argv[2])){ + + if($argv[2] == '-r'){ + //replace the compressed scripts with the backed up version + reverseScripts("$from/jssource/src_files","$from"); + + }elseif($argv[2] == '-m'){ + //replace the scripts, and then minify the scripts again + reverseScripts("$from/jssource/src_files","$from"); + BackUpAndCompressScriptFiles("$from","",false,true); + + }elseif($argv[2] == '-c'){ + //replace the scripts, concatenate the files, and then minify the scripts again + reverseScripts("$from/jssource/src_files","$from"); + BackUpAndCompressScriptFiles("$from","",false,true); + ConcatenateFiles("$from",true); + }elseif($argv[2] == '-mo'){ + //do not replace the scriptsjust minify the existing scripts again + BackUpAndCompressScriptFiles("$from","",false,true); + + }elseif($argv[2] == '-co'){ + //concatenate the files only + ConcatenateFiles("$from",true); + + }elseif($argv[2] == '-?'){ + die(" + Usage : minify [[-r]|[-m]|[-c]] + + = path of directory to process. Should be root of sugar instance. + -r = replace javascript of root with scripts from backed up jssource/src_files directory + -m = same as r, only the script is minified and then copied + -c = same as m, only the concatenated files are processed again. + -co = concatenates only the js files that are to be concatenated. Main use is for development when files that make up a concatenated file have been modified. + -mo = minifies only the existing js files. Will not use source files and will not back up scripts. Main use is for development, when changes have been made to working javascript and you wish to recompress your scripts. + + *** note that options are mutually exclusive. You would use -r OR -m OR -c + + examples: say your patch is located in 'c:/sugar' + You wish to have files from root directory concatenated according to file grouping array, as well as all js files compressed and backed up: + minify 'c:/sugar' + + You wish to have backed up jssource files replace your current javascript files: + minify 'c:/sugar' -r + + You wish to have backed up jssource files minified, and replace your current javascript files: + minify 'c:/sugar' -m + + You wish to have backed up jssource files concatenated, minified, and replace your current javascript files: + minify 'c:/sugar' -c + "); + + } + + }else{ + //default is to concatenate the files, then back up and compress them + if(empty($from)){ + echo("directory root to process was not specified"); + } + + BackUpAndCompressScriptFiles("$from", '', true, true); + ConcatenateFiles("$from",true); + + } +} + + +?> diff --git a/jssource/minify_utils.php b/jssource/minify_utils.php new file mode 100644 index 00000000..dd2f942c --- /dev/null +++ b/jssource/minify_utils.php @@ -0,0 +1,466 @@ + 'cache', + $prefix.'include/javascript/tiny_mce' => 'include/javascript/tiny_mce', + $prefix.'include/javascript/yui' => 'include/javascript/yui', + $prefix.'include/javascript/yui-old' => 'include/javascript/yui-old', + $prefix.'include/javascript/ext-1.1.1' => 'include/javascript/ext-1.1.1', + $prefix.'include/javascript/ext-2.0' => 'include/javascript/ext-2.0', + $prefix.'include/javascript/tiny_mce' => 'include/javascript/tiny_mce', + $prefix.'modules/Emails' => 'modules/Emails', + $prefix.'jssource' => 'jssource', + $prefix.'modules/ModuleBuilder' => 'modules/ModuleBuilder', + ); + + return $compress_exempt_files; + +} + + + + /**ConcatenateFiles($from_path) + * + * This method takes in a string value of the root directory to begin processing + * it uses the predefined array of groupings to create a concatenated file for each grouping + * and places the concatenated file in root directory + * @from_path root directory where processing should take place + */ + function ConcatenateFiles($from_path){ + + $js_groupings = array(); + if(isset($_REQUEST['root_directory'])){ + require('jssource/JSGroupings.php'); + }else{ + require('JSGroupings.php'); + } + //get array with file sources to concatenate + $file_groups = $js_groupings;//from JSGroupings.php; + $files_opened = array(); + $currPerm = ''; + + //for each item in array, concatenate the source files + foreach($file_groups as $fg){ + + //process each group array + foreach($fg as $loc=>$trgt){ + $relpath = $loc; + $loc = $from_path.'/'.$loc; + $trgt = $from_path.'/'.$trgt; + + //check to see that source file exists, that it is a file, and is readable + if(file_exists($loc) && is_file($loc) && is_readable($loc)){ + $currPerm = fileperms($loc); + //check to see if target exists, if it does then open file + if(file_exists($trgt)){ + if(in_array($trgt, $files_opened)){ + //open target file + if(function_exists('sugar_fopen')){ + $trgt_handle = sugar_fopen($trgt, 'a'); + }else{ + $trgt_handle = fopen($trgt, 'a'); + } + }else{ + //open target file + if(function_exists('sugar_fopen')){ + $trgt_handle = sugar_fopen($trgt, 'w'); + }else{ + $trgt_handle = fopen($trgt, 'w'); + } + } + + }else{ + //create and open target file + if(function_exists('sugar_fopen')){ + $trgt_handle = @sugar_fopen($trgt, 'w'); + }else{ + $trgt_handle = @fopen($trgt, 'w'); + } + + // todo: make this failure more friendly. Ideally, it will display a + // warning to admin users and revert back to displaying all of the + // Javascript files insted of displaying the minified versions. + if ($trgt_handle === false) { + $target_directory = dirname($trgt); + $base_name = realpath(dirname(__FILE__) . '/..') . '/'; + $target_directory = substr($target_directory, strlen($base_name)); + sugar_die("please make sure {$target_directory} is writable\n"); + } + + } + $files_opened[] = $trgt; + + //make sure we have handles to both source and target file + if ($trgt_handle) { + $buffer = file_get_contents($loc); + $buffer .= "// End of File $relpath + +"; + $num = fwrite($trgt_handle, $buffer); + + if( $num=== false){ + //log error, file did not get appended + echo "Error while concatenating file $loc to target file $trgt \n"; + } + //close file opened. + fclose($trgt_handle); + } + + } + } + + //set permissions on this file + if(!empty($currPerm) && $currPerm !== false){ + //if we can retrieve permissions from target files, use same + //permission on concatenated file + if(function_exists('sugar_chmod')){ + @sugar_chmod($trgt, $currPerm); + }else{ + @chmod($trgt, $currPerm); + } + }else{ + //no permissions could be retrieved, so set to 777 + if(function_exists('sugar_chmod')){ + @sugar_chmod($trgt, 0777); + }else{ + @chmod($trgt, 0777); + } + } + } + + } + + function create_backup_folder($bu_path){ + $bu_path = str_replace('\\', '/', $bu_path); + //get path after root + $jpos = strpos($bu_path,'jssource'); + if($jpos===false){ + $process_path = $bu_path; + }else{ + $process_path = substr($bu_path, $jpos); + $prefix_process_path = substr($bu_path, 0, $jpos-1); + } + //get rest of directories into array + $bu_dir_arr = explode('/', $process_path); + + //iterate through each directory and create if needed + + foreach($bu_dir_arr as $bu_dir){ + if(!file_exists($prefix_process_path.'/'.$bu_dir)){ + if(function_exists('sugar_mkdir')){ + sugar_mkdir($prefix_process_path.'/'.$bu_dir); + }else{ + mkdir($prefix_process_path.'/'.$bu_dir); + } + } + $prefix_process_path = $prefix_process_path.'/'.$bu_dir; + } + + } + + + + + /**CompressFiles + * This method will call jsmin libraries to minify passed in files + * This method takes in 2 string values of the files to process + * Processing will back up javascript files and then minify the original javascript. + * Back up javascript files will have an added .src extension + * @from_path file name and path to be processed + * @to_path file name and path to be used to place newly compressed contents + */ + function CompressFiles($from_path,$to_path){ + if(!defined('JSMIN_AS_LIB')){ + define('JSMIN_AS_LIB', true); + } + //assumes jsmin.php is in same directory + if(isset($_REQUEST['root_directory']) || defined('INSTANCE_PATH')){ + require_once('jssource/jsmin.php'); + }else{ + require_once('jsmin.php'); + } + $nl=' + '; + + //check to make sure from path and to path are not empty + if(isset($from_path) && !empty($from_path)&&isset($to_path) && !empty($to_path)){ + $lic_str = ''; + $ReadNextLine = true; + // Output a minified version of example.js. + if(file_exists($from_path) && is_file($from_path)){ + //read in license script + if(function_exists('sugar_fopen')){ + $file_handle = sugar_fopen($from_path, 'r'); + }else{ + $file_handle = fopen($from_path, 'r'); + } + if($file_handle){ + $beg = false; + + //Read the file until you hit a line with code. This is meant to retrieve + //the initial license string found in the beginning comments of js code. + while (!feof($file_handle) && $ReadNextLine) { + $newLine = fgets($file_handle, 4096); + $newLine = trim($newLine); + //See if line contains open or closing comments + + //if opening comments are found, set $beg to true + if(strpos($newLine, '/*')!== false){ + $beg = true; + } + + //if closing comments are found, set $beg to false + if(strpos($newLine, '*/')!== false){ + $beg = false; + } + + //if line is not empty (has code) set the boolean to false + if(! empty($newLine)){$ReadNextLine = false;} + //If we are in a comment block, then set boolean back to true + if($beg){ + $ReadNextLine = true; + //add new line to license string + $lic_str .=trim($newLine).$nl; + }else{ + //if we are here it means that uncommented and non blank line has been reached + //Check to see that ReadNextLine is true, if so then add the last line collected + //make sure the last line is either the end to a comment block, or starts with '//' + //else do not add as it is live code. + if(!empty($newLine) && ((strpos($newLine, '*/')!== false) || ($newLine{0}.$newLine{1}== '//'))){ + //add new line to license string + $lic_str .=$newLine; + } + //set to false because $beg is false, which means the comment block has ended + $ReadNextLine = false; + + } + } + + } + if($file_handle){ + fclose($file_handle); + } + + //place license string into array for use with jsmin file. + //this will preserve the license in the file + $lic_arr = array($lic_str); + + //minify javascript + //$jMin = new JSMin($from_path,$to_path,$lic_arr); + $out = $lic_str . JSMin::minify(file_get_contents($from_path)); + + if(function_exists('sugar_fopen') && $fh = @sugar_fopen( $to_path, 'w' ) ) + { + fputs( $fh, $out); + fclose( $fh ); + } else { + file_put_contents($to_path, $out); + } + + }else{ + //log failure + echo" COULD NOT COMPRESS $from_path, it is not a file \n"; + } + + }else{ + //log failure + echo" COULD NOT COMPRESS $from_path, missing variables \n"; + } + } + + function reverseScripts($from_path,$to_path=''){ + $from_path = str_replace('\\', '/', $from_path); + if(empty($to_path)){ + $to_path = $from_path; + } + $to_path = str_replace('\\', '/', $to_path); + + //check to see if provided paths are legit + + if (!file_exists("$from_path")) + { + //log error + echo "JS Source directory at $from_path Does Not Exist

            \n"; + return; + } + + //get correct path for backup + $bu_path = $to_path; + $bu_path .= substr($from_path, strlen($to_path.'/jssource/src_files')); + + //if this is a directory, then read it and process files + if(is_dir("$from_path")){ + //grab file / directory and read it. + $handle = opendir("$from_path"); + //loop over the directory and go into each child directory + while (false !== ($dir = readdir($handle))) { + + //make sure you go into directory tree and not out of tree + if($dir!= '.' && $dir!= '..'){ + //make recursive call to process this directory + reverseScripts($from_path.'/'.$dir, $to_path ); + } + } + } + + //if this is not a directory, then + //check if this is a javascript file, then process + $path_parts = pathinfo($from_path); + if(is_file("$from_path") && isset($path_parts['extension']) && $path_parts['extension'] =='js'){ + + //create backup directory if needed + $bu_dir = dirname($bu_path); + + if(!file_exists($bu_dir)){ + //directory does not exist, log it and return + echo" directory $bu_dir does not exist, could not restore $bu_path"; + return; + } + + //delete backup src file if it exists already + if(file_exists($bu_path)){ + unlink($bu_path); + } + copy($from_path, $bu_path); + } + + + } + + /**BackUpAndCompressScriptFiles + * + * This method takes in a string value of the root directory to begin processing + * it will process and iterate through all files and subdirectories + * under the passed in directory, ignoring directories and files from the predefined exclude array. + * Processing includes calling a method that will minify the javascript children files + * @from_path root directory where processing should take place + * @to_path root directory where processing should take place, this gets filled in dynamically + */ + function BackUpAndCompressScriptFiles($from_path,$to_path = '', $backup = true){ + + //check to see if provided paths are legit + if (!file_exists("$from_path")) + { + //log error + echo "The from directory, $from_path Does Not Exist

            \n"; + return; + }else{ + $from_path = str_replace('\\', '/', $from_path); + } + + if(empty($to_path)){ + $to_path = $from_path; + }elseif (!file_exists("$to_path")) + { + //log error + echo "The to directory, $to_path Does Not Exist

            \n"; + return; + } + + //now grab list of files to exclude from minifying + $exclude_files = get_exclude_files($to_path); + + //process only if file/directory is not in exclude list + if(!isset($exclude_files[$from_path])){ + + //get correct path for backup + $bu_path = $to_path.'/jssource/src_files'; + $bu_path .= substr($from_path, strlen($to_path)); + + //if this is a directory, then read it and process files + if(is_dir("$from_path")){ + //grab file / directory and read it. + $handle = opendir("$from_path"); + //loop over the directory and go into each child directory + while (false !== ($dir = readdir($handle))) { + + //make sure you go into directory tree and not out of tree + if($dir!= '.' && $dir!= '..'){ + //make recursive call to process this directory + BackUpAndCompressScriptFiles($from_path.'/'.$dir, $to_path,$backup); + } + } + } + + + //if this is not a directory, then + //check if this is a javascript file, then process + $path_parts = pathinfo($from_path); + if(is_file("$from_path") && isset($path_parts['extension']) && $path_parts['extension'] =='js'){ + + if($backup){ + $bu_dir = dirname($bu_path); + if(!file_exists($bu_dir)){ + create_backup_folder($bu_dir); + } + + //delete backup src file if it exists already + if(file_exists($bu_path)){ + unlink($bu_path); + } + //copy original file into a source file + rename($from_path, $bu_path); + }else{ + //no need to backup, but remove file that is about to be copied + //if it exists in both backed up scripts and working directory + if(file_exists($from_path) && file_exists($bu_path)){unlink($from_path);} + } + + //now make call to minify and overwrite the original file. + CompressFiles($bu_path, $from_path); + + } + } + + } diff --git a/jssource/src_files/include/JSON.js b/jssource/src_files/include/JSON.js new file mode 100644 index 00000000..575ac930 --- /dev/null +++ b/jssource/src_files/include/JSON.js @@ -0,0 +1,217 @@ +/* +Copyright (c) 2005 JSON.org + +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 Software shall be used for Good, not Evil. + +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. + + json.js + + The global object JSON contains two methods. + + JSON.stringify(value) takes a JavaScript value and produces a JSON text. + The value must not be cyclical. + + JSON.parse(text) takes a JSON text and produces a JavaScript value. It will + return false if there is an error. + +2008-10-10: New regular expressions copied in from the new json2.js file on http://json.org (released into the public domain), work better on Safari and IE for more complicated datasets +*/ +var JSON = function () { + var m = { + '\b': '\\b', + '\t': '\\t', + '\n': '\\n', + '\f': '\\f', + '\r': '\\r', + '"' : '\\"', + '\\': '\\\\' + }, + s = { + array: function (x) { + var a = ['['], b, f, i, l = x.length, v; + for (i = 0; i < l; i += 1) { + v = x[i]; + f = s[typeof v]; + if (f) { + v = f(v); + if (typeof v == 'string') { + if (b) { + a[a.length] = ','; + } + a[a.length] = v; + b = true; + } + } + } + a[a.length] = ']'; + return a.join(''); + }, + 'boolean': function (x) { + return String(x); + }, + 'null': function (x) { + return "null"; + }, + number: function (x) { + return isFinite(x) ? String(x) : 'null'; + }, + object: function (x) { + if (x) { + if (x instanceof Array) { + return s.array(x); + } + var a = ['{'], b, f, i, v; + for (i in x) { + if (!x.hasOwnProperty || x.hasOwnProperty(i)) { + v = x[i]; + f = s[typeof v]; + if (f) { + v = f(v); + if (typeof v == 'string') { + if (b) { + a[a.length] = ','; + } + a.push(s.string(i), ':', v); + b = true; + } + } + } + } + a[a.length] = '}'; + return a.join(''); + } + return 'null'; + }, + string: function (x) { + + var unicode = new String; + for(var i=0; i= SUGAR.mySugar.maxCount) { + alert(SUGAR.language.get('app_strings', 'LBL_MAX_DASHLETS_REACHED')); + return; + } +/* if((columns[0].length + columns[1].length) >= SUGAR.mySugar.maxCount) { + alert(SUGAR.language.get('Home', 'LBL_MAX_DASHLETS_REACHED')); + return; + }*/ + ajaxStatus.showStatus(SUGAR.language.get('app_strings', 'LBL_ADDING_DASHLET')); + var success = function(data) { + + colZero = document.getElementById('col_'+activeTab+'_0'); + newDashlet = document.createElement('li'); // build the list item + newDashlet.id = 'dashlet_' + data.responseText; + newDashlet.className = 'noBullet active'; + // hide it first, but append to getRegion + newDashlet.innerHTML = '

            '; + + colZero.insertBefore(newDashlet, colZero.firstChild); // insert it into the first column + + var finishRetrieve = function() { + dashletEntire = document.getElementById('dashlet_entire_' + data.responseText); + dd = new ygDDList('dashlet_' + data.responseText); // make it draggable + dd.setHandleElId('dashlet_header_' + data.responseText); + dd.onMouseDown = SUGAR.mySugar.onDrag; + dd.onDragDrop = SUGAR.mySugar.onDrop; + + ajaxStatus.showStatus(SUGAR.language.get('app_strings', 'LBL_ADDED_DASHLET')); + dashletRegion = YAHOO.util.Dom.getRegion(dashletEntire); + dashletEntire.style.position = 'relative'; + dashletEntire.style.height = '1px'; + dashletEntire.style.top = '0px'; + dashletEntire.className = 'dashletPanel'; + + + var anim = new YAHOO.util.Anim('dashlet_entire_' + data.responseText, { height: {to: dashletRegion.bottom - dashletRegion.top} }, .5 ); + anim.onComplete.subscribe(function() { document.getElementById('dashlet_entire_' + data.responseText).style.height = '100%'; }); + anim.animate(); + + newLayout = SUGAR.mySugar.getLayout(true); + SUGAR.mySugar.saveLayout(newLayout); +// window.setTimeout('ajaxStatus.hideStatus()', 2000); + } + + if (type == 'module' || type == 'web'){ + url = null; + type = 'module'; + } + else if (type == 'predefined_chart'){ + url = 'predefined_chart'; + type = 'predefined_chart'; + } + else if (type == 'chart'){ + url = 'chart'; + type = 'chart'; + } + + SUGAR.mySugar.retrieveDashlet(data.responseText, url, finishRetrieve, true); // retrieve it from the server + } + var cObj = YAHOO.util.Connect.asyncRequest('GET','index.php?to_pdf=1&module='+module+'&action=DynamicAction&DynamicAction=addDashlet&activeTab=' + activeTab + '&id=' + id+'&type=' + type + '&type_module=' + type_module, + {success: success, failure: success}, null); + + return false; + }, + + showDashletsDialog: function() { + columns = SUGAR.mySugar.getLayout(); + + var num_dashlets = 0; + var i = 0; + for ( i = 0 ; i < 3; i++ ) { + if (typeof columns[i] != "undefined") { + num_dashlets = num_dashlets + columns[i].length; + } + } + + if((num_dashlets) >= SUGAR.mySugar.maxCount) { + alert(SUGAR.language.get('app_strings', 'LBL_MAX_DASHLETS_REACHED')); + return; + } + ajaxStatus.showStatus(SUGAR.language.get('app_strings', 'LBL_LOADING')); + + var success = function(data) { + eval(data.responseText); + dashletsListDiv = document.getElementById('dashletsList'); + dashletsListDiv.innerHTML = response['html']; + + document.getElementById('dashletsDialog_c').style.display = ''; + SUGAR.mySugar.dashletsDialog.show(); + + eval(response['script']); + ajaxStatus.hideStatus(); + } + + var cObj = YAHOO.util.Connect.asyncRequest('GET', 'index.php?to_pdf=true&module='+module+'&action=DynamicAction&DynamicAction=dashletsDialog', {success: success, failure: success}); + return false; + }, + + closeDashletsDialog: function(){ + SUGAR.mySugar.dashletsDialog.hide(); + window.setTimeout("document.getElementById('dashletsDialog_c').style.display = 'none';", 2000); + }, + + toggleDashletCategories: function(category){ + document.getElementById('search_string').value = ''; + document.getElementById('searchResults').innerHTML = ''; + + var moduleTab = document.getElementById('moduleCategory'); + var moduleTabAnchor = document.getElementById('moduleCategoryAnchor'); + var moduleListDiv = document.getElementById('moduleDashlets'); + + var chartTab = document.getElementById('chartCategory'); + var chartTabAnchor = document.getElementById('chartCategoryAnchor'); + var chartListDiv = document.getElementById('chartDashlets'); + + var toolsTab = document.getElementById('toolsCategory'); + var toolsTabAnchor = document.getElementById('toolsCategoryAnchor'); + var toolsListDiv = document.getElementById('toolsDashlets'); + + var webTab = document.getElementById('webCategory'); + var webTabAnchor = document.getElementById('webCategoryAnchor'); + var webListDiv = document.getElementById('webDashlets'); + + switch(category){ + case 'module': + moduleTab.className = 'active'; + moduleTabAnchor.className = 'current'; + moduleListDiv.style.display = ''; + + chartTab.className = ''; + chartTabAnchor.className = ''; + chartListDiv.style.display = 'none'; + + toolsTab.className = ''; + toolsTabAnchor.className = ''; + toolsListDiv.style.display = 'none'; + + webTab.className = ''; + webTabAnchor.className = ''; + webListDiv.style.display = 'none'; + + break; + case 'chart': + moduleTab.className = ''; + moduleTabAnchor.className = ''; + moduleListDiv.style.display = 'none'; + + chartTab.className = 'active'; + chartTabAnchor.className = 'current'; + chartListDiv.style.display = ''; + + toolsTab.className = ''; + toolsTabAnchor.className = ''; + toolsListDiv.style.display = 'none'; + + webTab.className = ''; + webTabAnchor.className = ''; + webListDiv.style.display = 'none'; + + break; + case 'tools': + moduleTab.className = ''; + moduleTabAnchor.className = ''; + moduleListDiv.style.display = 'none'; + + chartTab.className = ''; + chartTabAnchor.className = ''; + chartListDiv.style.display = 'none'; + + toolsTab.className = 'active'; + toolsTabAnchor.className = 'current'; + toolsListDiv.style.display = ''; + + webTab.className = ''; + webTabAnchor.className = ''; + webListDiv.style.display = 'none'; + + break; + case 'web': + moduleTab.className = ''; + moduleTabAnchor.className = ''; + moduleListDiv.style.display = 'none'; + + chartTab.className = ''; + chartTabAnchor.className = ''; + chartListDiv.style.display = 'none'; + + toolsTab.className = ''; + toolsTabAnchor.className = ''; + toolsListDiv.style.display = 'none'; + + webTab.className = 'active'; + webTabAnchor.className = 'current'; + webListDiv.style.display = ''; + + break; + default: + break; + } + + document.getElementById('search_category').value = category; + }, + + + searchDashlets: function(searchStr, searchCategory){ + var moduleTab = document.getElementById('moduleCategory'); + var moduleTabAnchor = document.getElementById('moduleCategoryAnchor'); + var moduleListDiv = document.getElementById('moduleDashlets'); + + var chartTab = document.getElementById('chartCategory'); + var chartTabAnchor = document.getElementById('chartCategoryAnchor'); + var chartListDiv = document.getElementById('chartDashlets'); + + var toolsTab = document.getElementById('toolsCategory'); + var toolsTabAnchor = document.getElementById('toolsCategoryAnchor'); + var toolsListDiv = document.getElementById('toolsDashlets'); + + if (moduleTab != null && chartTab != null && toolsTab != null){ + moduleListDiv.style.display = 'none'; + chartListDiv.style.display = 'none'; + toolsListDiv.style.display = 'none'; + + } + // dashboards case, where there are no tabs + else{ + chartListDiv.style.display = 'none'; + } + + var searchResultsDiv = document.getElementById('searchResults'); + searchResultsDiv.style.display = ''; + + var success = function(data) { + eval(data.responseText); + + searchResultsDiv.innerHTML = response['html']; + } + + var cObj = YAHOO.util.Connect.asyncRequest('GET', 'index.php?to_pdf=true&module='+module+'&action=DynamicAction&DynamicAction=searchDashlets&search='+searchStr+'&category='+searchCategory, {success: success, failure: success}); + return false; + }, + + collapseList: function(chartList){ + document.getElementById(chartList+'List').style.display='none'; + document.getElementById(chartList+'ExpCol').innerHTML = ''; + }, + + expandList: function(chartList){ + document.getElementById(chartList+'List').style.display=''; + document.getElementById(chartList+'ExpCol').innerHTML = ''; + }, + + collapseReportList: function(reportChartList){ + document.getElementById(reportChartList+'ReportsChartDashletsList').style.display='none'; + document.getElementById(reportChartList+'ExpCol').innerHTML = ''; + }, + + expandReportList: function(reportChartList){ + document.getElementById(reportChartList+'ReportsChartDashletsList').style.display=''; + document.getElementById(reportChartList+'ExpCol').innerHTML = ''; + }, + + clearSearch: function(){ + document.getElementById('search_string').value = ''; + + var moduleTab = document.getElementById('moduleCategory'); + var moduleTabAnchor = document.getElementById('moduleCategoryAnchor'); + var moduleListDiv = document.getElementById('moduleDashlets'); + + document.getElementById('searchResults').innerHTML = ''; + if (moduleTab != null){ + SUGAR.mySugar.toggleDashletCategories('module'); + } + else{ + document.getElementById('searchResults').style.display = 'none'; + document.getElementById('chartDashlets').style.display = ''; + } + }, + + doneAddDashlets: function() { + SUGAR.mySugar.dashletsDialog.hide(); + return false; + }, + + + + + renderDashletsDialog: function(){ + SUGAR.mySugar.dashletsDialog = new YAHOO.widget.Dialog("dashletsDialog", + { width : "480px", + height: "520px", + fixedcenter : true, + draggable:false, + visible : false, + // effect:[{effect:YAHOO.widget.ContainerEffect.SLIDETOP, duration:0.5},{effect:YAHOO.widget.ContainerEffect.FADE,duration:0.5}], + modal : true, + close:false + } ); + + var listeners = new YAHOO.util.KeyListener(document, { keys : 27 }, {fn: function() {SUGAR.mySugar.closeDashletsDialog();} } ); + SUGAR.mySugar.dashletsDialog.cfg.queueProperty("keylisteners", listeners); + + document.getElementById('dashletsDialog').style.display = ''; + SUGAR.mySugar.dashletsDialog.render(); + document.getElementById('dashletsDialog_c').style.display = 'none'; + } + }; +}(); diff --git a/jssource/src_files/include/SubPanel/SubPanelTiles.js b/jssource/src_files/include/SubPanel/SubPanelTiles.js new file mode 100644 index 00000000..6ff808de --- /dev/null +++ b/jssource/src_files/include/SubPanel/SubPanelTiles.js @@ -0,0 +1,736 @@ +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + + + +var request_id = 0; +var current_child_field = ''; +var current_subpanel_url = ''; +var child_field_loaded = new Object(); +var request_map = new Object(); + +function get_module_name() +{ + if(typeof(window.document.forms['DetailView']) == 'undefined') { + return ''; + } else { + + //check to see if subpanel_parent_module input exists. If so override module name + //this is used in the case when the subpanel contents are of the same module as the current module + //and the record in $_REQUEST is of the parent object. By specifying the subpanel_parent_module, + //you allow normal processing to continue. For an example, see trackdetailview.html/php in campaigns module + if(typeof(window.document.forms['DetailView'].elements['subpanel_parent_module']) != 'undefined' && + window.document.forms['DetailView'].elements['subpanel_parent_module'].value != ''){ + return window.document.forms['DetailView'].elements['subpanel_parent_module'].value; + } + return window.document.forms['DetailView'].elements['module'].value; + } +} +/*this function will take in three parameters, m,i,a and recreate navigation +* m = module +* i = record id +* a = action (detail/edit) +* t = element to be modified +* r = relationship to update after edit. +* This is done to minimize page size +* */ +function subp_nav(m,i,a,t,r){ + if(t.href.search(/#/) < 0){ + //no need to process if url has already been converted + return; + } + if(a=='d'){ + a='DetailView'; + }else{ + a='EditView'; + } + url = "index.php?module="+m+"&action="+a+"&record="+i+"&parent_module="+get_module_name()+"&parent_id="+get_record_id()+"&return_module="+get_module_name()+"&return_id="+get_record_id()+"&return_action=DetailView"; + if (r) + { + url += "&return_relationship=" + r; + } + t.href = url; +} + + +/*this function will take in three parameters, m,i,a and recreate navigation +* m = module +* i = record id +* a = action (detail/edit) +* This is done to minimize page size +* */ +function sub_p_rem(sp,lf,li,rp){ + return_url = "index.php?module="+get_module_name()+"&action=SubPanelViewer&subpanel="+sp+"&record="+get_record_id()+"&sugar_body_only=1&inline=1"; + + remove_url = "index.php?module="+ get_module_name() + + "&action=DeleteRelationship" + + "&record="+ get_record_id() + + "&linked_field="+ lf //$linked_field" + + "&linked_id="+ li //$record" + + "&return_url=" + escape(escape(return_url)) + + "&refresh_page=" + rp;//$refresh_page" + showSubPanel(sp,remove_url,true); +} +function sp_rem_conf(){ + return confirm(SUGAR.language.get('app_strings', 'NTC_REMOVE_CONFIRMATION')) +} + + +function get_record_id() +{ + return window.document.forms['DetailView'].elements['record'].value; +} +function get_layout_def_key() +{ + if(typeof(window.document.forms['DetailView'].elements['layout_def_key']) == 'undefined')return ''; + return window.document.forms['DetailView'].elements['layout_def_key'].value; +} + +function save_finished(args) +{ + var child_field = request_map[args.request_id]; + delete (child_field_loaded[child_field] ); + showSubPanel(child_field); +} + +function set_return_and_save_background(popup_reply_data) +{ + var form_name = popup_reply_data.form_name; + var name_to_value_array = popup_reply_data.name_to_value_array; + var passthru_data = popup_reply_data.passthru_data; + var select_entire_list = typeof( popup_reply_data.select_entire_list ) == 'undefined' ? 0 : popup_reply_data.select_entire_list; + var current_query_by_page = popup_reply_data.current_query_by_page; + // construct the POST request + var query_array = new Array(); + if (name_to_value_array != 'undefined') { + for (var the_key in name_to_value_array) + { + if(the_key == 'toJSON') + { + /* just ignore */ + } + else + { + query_array.push(the_key+"="+name_to_value_array[the_key]); + } + } + } + //construct the muulti select list + var selection_list = popup_reply_data.selection_list; + if (selection_list != 'undefined') { + for (var the_key in selection_list) + { + query_array.push('subpanel_id[]='+selection_list[the_key]) + } + } + var module = get_module_name(); + var id = get_record_id(); + + query_array.push('value=DetailView'); + query_array.push('module='+module); + query_array.push('http_method=get'); + query_array.push('return_module='+module); + query_array.push('return_id='+id); + query_array.push('record='+id); + query_array.push('isDuplicate=false'); + query_array.push('action=Save2'); + query_array.push('inline=1'); + query_array.push('select_entire_list='+select_entire_list); + if(select_entire_list == 1){ + query_array.push('current_query_by_page='+current_query_by_page); + } + var refresh_page = escape(passthru_data['refresh_page']); + for (prop in passthru_data) { + if (prop=='link_field_name') { + query_array.push('subpanel_field_name='+escape(passthru_data[prop])); + } else { + if (prop=='module_name') { + query_array.push('subpanel_module_name='+escape(passthru_data[prop])); + } else { + query_array.push(prop+'='+escape(passthru_data[prop])); + } + } + } + + var query_string = query_array.join('&'); + request_map[request_id] = passthru_data['child_field']; + + var returnstuff = http_fetch_sync('index.php',query_string); + request_id++; + got_data(returnstuff, true); + if(refresh_page == 1){ + document.location.reload(true); + } +} + +function got_data(args, inline) +{ + + var list_subpanel = document.getElementById('list_subpanel_'+request_map[args.request_id].toLowerCase()); + //this function assumes that we are always working with a subpanel.. + //add a null check to prevent failures when we are not. + if (list_subpanel != null) { + var subpanel = document.getElementById('subpanel_'+request_map[args.request_id].toLowerCase()); + var child_field = request_map[args.request_id].toLowerCase(); + if(inline){ + + //CCL - 21752 + //if this is an inline operation, get the original buttons in the td element + //so that we may replace them later + buttonHTML = ''; + trEls = list_subpanel.getElementsByTagName('tr'); + if(trEls && trEls.length > 0) { + for(x in trEls) { + if(trEls[x] && trEls[x].className == 'pagination') { + tableEls = trEls[x].getElementsByTagName('table'); + tdEls = tableEls[0].getElementsByTagName('td'); + span = tdEls[0].getElementsByTagName('span'); + if(span) { + buttonHTML = span[0].innerHTML; + } + break; + } + } + } + + child_field_loaded[child_field] = 2; + list_subpanel.innerHTML=''; + list_subpanel.innerHTML=args.responseText; + + //now if the trPagination element is set then let's replace the new tr element with this + if(buttonHTML != '') { + list_subpanel = document.getElementById('list_subpanel_'+request_map[args.request_id].toLowerCase()); + trEls = list_subpanel.getElementsByTagName('tr'); + for(x in trEls) { + if(trEls[x] && trEls[x].className == 'pagination') { + tableEls = trEls[x].getElementsByTagName('table'); + tdEls = tableEls[0].getElementsByTagName('td'); + span = tdEls[0].getElementsByTagName('span'); + span[0].innerHTML = buttonHTML; + break; + } + } + } + + } else { + child_field_loaded[child_field] = 1; + subpanel.innerHTML=''; + subpanel.innerHTML=args.responseText; + + /* walk into the DOM and insert the list_subpanel_* div */ + var inlineTable = subpanel.getElementsByTagName('table'); + inlineTable = inlineTable[1]; + inlineTable = subpanel.removeChild(inlineTable); + var listDiv = document.createElement('div'); + listDiv.id = 'list_subpanel_'+request_map[args.request_id].toLowerCase(); + subpanel.appendChild(listDiv); + listDiv.appendChild(inlineTable); + } + subpanel.style.display = ''; + set_div_cookie(subpanel.cookie_name, ''); + + if (current_child_field != '' && child_field != current_child_field) + { + // commented out for now. this was originally used by tab UI of subpanels + //hideSubPanel(current_child_field); + } + current_child_field = child_field; + } +} + +function showSubPanel(child_field,url,force_load,layout_def_key) +{ + var inline = 1; + if ( typeof(force_load) == 'undefined' || force_load == null) + { + force_load = false; + } + + if (force_load || typeof( child_field_loaded[child_field] ) == 'undefined') + { + request_map[request_id] = child_field; + if ( typeof (url) == 'undefined' || url == null) + { + var module = get_module_name(); + var id = get_record_id(); + if ( typeof(layout_def_key) == 'undefined' || layout_def_key == null ) { + layout_def_key = get_layout_def_key(); + } + + url = 'index.php?sugar_body_only=1&module='+module+'&subpanel='+child_field+'&action=SubPanelViewer&inline=' + inline + '&record='+id + '&layout_def_key='+ layout_def_key; + } + + if ( url.indexOf('http://') != 0 && url.indexOf('https://') != 0) + { + url = ''+url ; + } + + current_subpanel_url = url; + // http_fetch_async(url,got_data,request_id++); + var returnstuff = http_fetch_sync(url+ '&inline=' + inline + '&ajaxSubpanel=true'); + request_id++; + got_data(returnstuff, inline); + } + else + { + var subpanel = document.getElementById('subpanel_'+child_field); + subpanel.style.display = ''; + + set_div_cookie(subpanel.cookie_name, ''); + + if (current_child_field != '' && child_field != current_child_field) + { + hideSubPanel(current_child_field); + } + + current_child_field = child_field; + } + if(typeof(url) != 'undefined' && url != null && url.indexOf('refresh_page=1') > 0){ + document.location.reload(); + } + +} + +function markSubPanelLoaded(child_field){ + child_field_loaded[child_field] = 2; +} +function hideSubPanel(child_field) +{ + var subpanel = document.getElementById('subpanel_'+child_field); + subpanel.style.display = 'none'; + set_div_cookie(subpanel.cookie_name, 'none'); +} +var sub_cookie_name = get_module_name() + '_divs'; +var temp = Get_Cookie(sub_cookie_name); +var div_cookies = new Array(); + +if(temp && typeof(temp) != 'undefined'){ + div_cookies = get_sub_cookies(temp); +} +function set_div_cookie(name, display){ + div_cookies[name] = display; + Set_Cookie(sub_cookie_name, subs_to_cookie(div_cookies), 3000, false, false,false); +} + + +function local_open_popup(name, width, height,arg1, arg2, arg3, params) +{ + return open_popup(name, width, height,arg1,arg2,arg3, params); +} + +SUGAR.subpanelUtils = function() { + var originalLayout = null; + var subpanelContents = {}; + var subpanelLocked = {}; + + + return { + // get the current subpanel layout + getLayout: function(asString, ignoreHidden) { + subpanels = document.getElementById('subpanel_list'); + subpanelIds = new Array(); + for(wp = 0; wp < subpanels.childNodes.length; wp++) { + if(typeof subpanels.childNodes[wp].id != 'undefined' && subpanels.childNodes[wp].id.match(/whole_subpanel_[\w-]*/) && (typeof ignoreHidden == 'undefined' || subpanels.childNodes[wp].style.display != 'none')) { + subpanelIds.push(subpanels.childNodes[wp].id.replace(/whole_subpanel_/,'')); + } + } + if(asString) return subpanelIds.join(','); + else return subpanelIds; + }, + + // called when subpanel is picked up + onDrag: function(e, id) { + originalLayout = SUGAR.subpanelUtils.getLayout(true, true); + }, + + // called when subpanel is dropped + onDrop: function(e, id) { + newLayout = SUGAR.subpanelUtils.getLayout(true, true); + if(originalLayout != newLayout) { // only save if the layout has changed + SUGAR.subpanelUtils.saveLayout(newLayout); + } + }, + + // save the layout of the subpanels + saveLayout: function(order) { + ajaxStatus.showStatus(SUGAR.language.get('app_strings', 'LBL_SAVING_LAYOUT')); + + if(typeof SUGAR.subpanelUtils.currentSubpanelGroup != 'undefined') { + var orderList = SUGAR.subpanelUtils.getLayout(false, true); + var currentGroup = SUGAR.subpanelUtils.currentSubpanelGroup; + } + var success = function(data) { + ajaxStatus.showStatus(SUGAR.language.get('app_strings', 'LBL_SAVED_LAYOUT')); + window.setTimeout('ajaxStatus.hideStatus()', 2000); + if(typeof SUGAR.subpanelUtils.currentSubpanelGroup != 'undefined') { + SUGAR.subpanelUtils.reorderSubpanelSubtabs(currentGroup, orderList); + } + } + + url = 'index.php?module=Home&action=SaveSubpanelLayout&layout=' + order + '&layoutModule=' + currentModule; + if(typeof SUGAR.subpanelUtils.currentSubpanelGroup != 'undefined') { + url = url + '&layoutGroup=' + encodeURI(SUGAR.subpanelUtils.currentSubpanelGroup); + } + var cObj = YAHOO.util.Connect.asyncRequest('GET', url, {success: success, failure: success}); + }, + + // call when an inline create is saved + // buttonName is the id of the originating 'save' button - we determine the associated subpanel name by climbing the DOM from this point + // We require the subpanel name to refresh the subpanel contents and to close the subpanel after the save. However, the code the generates the button + // doesn't have access to the subpanel name, only the module name. Hence this rather long-winded mechanism. + inlineSave: function(theForm, buttonName) { + ajaxStatus.showStatus(SUGAR.language.get('app_strings', 'LBL_SAVING')); + var success = function(data) { + var element = document.getElementById(buttonName); + do { + element = element.parentNode; + } while ( element.className != 'quickcreate' && element.parentNode ) ; + + if (element.className == 'quickcreate') { + var subpanel = element.id.slice(9,-7) ; // retrieve the subpanel name from the div id - the name is encoded as 'subpanel__newdiv' + SUGAR.subpanelUtils.cancelCreate(buttonName); + + var module = get_module_name(); + var id = get_record_id(); + var layout_def_key = get_layout_def_key(); + try { + eval('result = ' + data.responseText); + } catch (err) { + + } + + if (typeof(result) != 'undefined' && result != null && typeof(result['status']) != 'undefined' && result['status'] !=null && result['status'] == 'dupe') { + document.location.href = "index.php?" + result['get'].replace(/&/gi,'&').replace(/</gi,'<').replace(/>/gi,'>').replace(/'/gi,'\'').replace(/"/gi,'"').replace(/\r\n/gi,'\n'); + return; + } else { + showSubPanel(subpanel, null, true); + ajaxStatus.showStatus(SUGAR.language.get('app_strings', 'LBL_SAVED')); + window.setTimeout('ajaxStatus.hideStatus()', 1000); + if(reloadpage) window.location.reload(false); + } + } + } + // reload page if we are setting status to Held + var reloadpage = false; + if ((buttonName == 'Meetings_subpanel_save_button' || buttonName == 'Calls_subpanel_save_button' ) && document.getElementById(theForm).status[document.getElementById(theForm).status.selectedIndex].value == 'Held') { + reloadpage = true; + } + YAHOO.util.Connect.setForm(theForm, true, true); + var cObj = YAHOO.util.Connect.asyncRequest('POST', 'index.php', {success: success, failure: success, upload:success}); + return false; + }, + + sendAndRetrieve: function(theForm, theDiv, loadingStr) { + function success(data) { + theDivObj = document.getElementById(theDiv); + subpanelContents[theDiv] = new Array(); + subpanelContents[theDiv]['list'] = theDivObj; + + subpanelContents[theDiv]['newDiv'] = document.createElement('div'); + dataToDOMAvail = false; + subpanelContents[theDiv]['newDiv'].innerHTML = '' + data.responseText; // fill the div + subpanelContents[theDiv]['newDiv'].id = theDiv + '_newDiv'; + subpanelContents[theDiv]['newDiv'].className = 'quickcreate' ; + + theDivObj.style.display = 'none'; + theDivObj.parentNode.insertBefore(subpanelContents[theDiv]['newDiv'], theDivObj); + if (!dataToDOMAvail) { + SUGAR.util.evalScript(data.responseText); + } + subpanelLocked[theDiv] = false; + setTimeout("enableQS(false)",500); + ajaxStatus.hideStatus(); + + } + + if(typeof subpanelLocked[theDiv] != 'undefined' && subpanelLocked[theDiv]) return false; + subpanelLocked[theDiv] = true; + + if(typeof loadingStr == 'undefined') loadingStr = SUGAR.language.get('app_strings', 'LBL_LOADING'); + ajaxStatus.showStatus(loadingStr); + YAHOO.util.Connect.setForm(theForm); + var cObj = YAHOO.util.Connect.asyncRequest('POST', 'index.php', {success: success, failure: success}); + + return false; + }, + + cancelCreate: function(buttonName) { + var element = document.getElementById(buttonName); + + var theForm = element.form; + var confirmMsg = onUnloadEditView(theForm); + + do { + element = element.parentNode; + } while ( element.className != 'quickcreate' && element.parentNode ) ; + + var theDiv = element.id.substr(0,element.id.length-7); + + if (typeof(subpanelContents[theDiv]) == 'undefined') + return false; + + if ( confirmMsg != null ) { + if ( !confirm(confirmMsg) ) { + return false; + } else { + disableOnUnloadEditView(theForm); + } + } + + subpanelContents[theDiv]['newDiv'].parentNode.removeChild(subpanelContents[theDiv]['newDiv']); + subpanelContents[theDiv]['list'].style.display = ''; + + return false; + }, + + loadSubpanelGroupFromMore: function(group){ + SUGAR.subpanelUtils.updateSubpanelMoreTab(group); + SUGAR.subpanelUtils.loadSubpanelGroup(group); + }, + + updateSubpanelMoreTab: function(group){ + // Update Tab + var moreTab = document.getElementById(SUGAR.subpanelUtils.subpanelMoreTab + '_sp_tab'); + moreTab.id = group + '_sp_tab'; + moreTab.getElementsByTagName('a')[0].innerHTML = group; + moreTab.getElementsByTagName('a')[0].href = "javascript:SUGAR.subpanelUtils.loadSubpanelGroup('"+group+"');"; + + // Update Menu + var menuLink = document.getElementById(group+'_sp_mm'); + menuLink.id = SUGAR.subpanelUtils.subpanelMoreTab+'_sp_mm'; + menuLink.href = "javascript:SUGAR.subpanelUtils.loadSubpanelGroupFromMore('"+SUGAR.subpanelUtils.subpanelMoreTab+"');"; + menuLink.innerHTML = SUGAR.subpanelUtils.subpanelMoreTab; + + SUGAR.subpanelUtils.subpanelMoreTab = group; + }, + + /* loadSubpanels: + /* construct set of needed subpanels */ + /* if we have not yet loaded this subpanel group, */ + /* set loadedGroups[group] */ + /* for each subpanel in subpanelGroups[group] */ + /* if document.getElementById('whole_subpanel_'+subpanel) doesn't exist */ + /* then add subpanel to set of needed subpanels */ + /* if we need to load any subpanels, send a request for them */ + /* with updateSubpanels as the callback. */ + /* otherwise call updateSubpanels */ + /* call setGroupCookie */ + + loadSubpanelGroup: function(group){ + if(group == SUGAR.subpanelUtils.currentSubpanelGroup) return; + if(SUGAR.subpanelUtils.loadedGroups[group]){ + SUGAR.subpanelUtils.updateSubpanel(group); + }else{ + SUGAR.subpanelUtils.loadedGroups.push(group); + var needed = Array(); + for(group_sp in SUGAR.subpanelUtils.subpanelGroups[group]){ + if(typeof(SUGAR.subpanelUtils.subpanelGroups[group][group_sp]) == 'string' && !document.getElementById('whole_subpanel_'+SUGAR.subpanelUtils.subpanelGroups[group][group_sp])){ + needed.push(SUGAR.subpanelUtils.subpanelGroups[group][group_sp]); + } + } + var success = function(){ + SUGAR.subpanelUtils.updateSubpanelEventHandlers(needed); + SUGAR.subpanelUtils.updateSubpanels(group); + }; + /* needed to retrieve each of the specified subpanels and install them ...*/ + /* load them in bulk, insert via innerHTML, then sort nodes later. */ + if(needed.length){ + ajaxStatus.showStatus(SUGAR.language.get('app_strings', 'LBL_LOADING')); + SUGAR.util.retrieveAndFill(SUGAR.subpanelUtils.requestUrl + needed.join(','),'subpanel_list', null, success, null, true); + }else{ + SUGAR.subpanelUtils.updateSubpanels(group); + } + } + SUGAR.subpanelUtils.setGroupCookie(group); + }, + + /* updateSubpanels: + /* for each child node of subpanel_list */ + /* let subpanel name be id.match(/whole_subpanel_(\w*)/) */ + /* if the subpanel name is in the list of subpanels for the current group, show it */ + /* otherwise hide it */ + /* swap nodes to suit user's order */ + /* call updateSubpanelTabs */ + + updateSubpanels: function(group){ + var sp_list = document.getElementById('subpanel_list'); + for(sp in sp_list.childNodes){ + if(sp_list.childNodes[sp].id){ + sp_list.childNodes[sp].style.display = 'none'; + } + } + for(group_sp in SUGAR.subpanelUtils.subpanelGroups[group]){ + if ( typeof(SUGAR.subpanelUtils.subpanelGroups[group][group_sp]) != 'string' ) continue; + var cur = document.getElementById('whole_subpanel_'+SUGAR.subpanelUtils.subpanelGroups[group][group_sp]); + if (cur != null) + cur.style.display = 'block'; + /* use YDD swapNodes this and first, second, etc. */ + try{ + YAHOO.util.DDM.swapNode(cur, sp_list.getElementsByTagName('LI')[group_sp]); + }catch(e){ + + } + } + SUGAR.subpanelUtils.updateSubpanelTabs(group); + }, + + updateSubpanelTabs: function(group){ + if(SUGAR.subpanelUtils.showLinks){ + SUGAR.subpanelUtils.updateSubpanelSubtabs(group); + document.getElementById('subpanelSubTabs').innerHTML = SUGAR.subpanelUtils.subpanelSubTabs[group]; + } + + oldTab = document.getElementById(SUGAR.subpanelUtils.currentSubpanelGroup+'_sp_tab'); + if(oldTab){ + oldTab.className = ''; + oldTab.getElementsByTagName('a')[0].className = ''; + } + + mainTab = document.getElementById(group+'_sp_tab'); + mainTab.className = 'active'; + mainTab.getElementsByTagName('a')[0].className = 'current'; + + SUGAR.subpanelUtils.currentSubpanelGroup = group; + ajaxStatus.hideStatus(); + }, + + updateSubpanelEventHandlers: function(){ + if(SubpanelInitTabNames){ + SubpanelInitTabNames(SUGAR.subpanelUtils.getLayout(false)); + } + }, + + reorderSubpanelSubtabs: function(group, order){ + SUGAR.subpanelUtils.subpanelGroups[group] = order; + if(SUGAR.subpanelUtils.showLinks==1){ + SUGAR.subpanelUtils.updateSubpanelSubtabs(group); + if(SUGAR.subpanelUtils.currentSubpanelGroup == group){ + document.getElementById('subpanelSubTabs').innerHTML = SUGAR.subpanelUtils.subpanelSubTabs[group]; + } + } + }, + + // Re-renders the contents of subpanelSubTabs[group]. + // Does not immediately affect what's on the screen. + updateSubpanelSubtabs: function(group){ + var notFirst = 0; + var preMore = SUGAR.subpanelUtils.subpanelGroups[group].slice(0, SUGAR.subpanelUtils.subpanelMaxSubtabs); + + SUGAR.subpanelUtils.subpanelSubTabs[group] = ''; + + for(var sp_key = 0; sp_key < preMore.length; sp_key++){ + if(notFirst != 0){ + SUGAR.subpanelUtils.subpanelSubTabs[group] += ''; + }else{ + notFirst = 1; + } + SUGAR.subpanelUtils.subpanelSubTabs[group] += ''; + } + if(document.getElementById('MoreSub'+group+'PanelMenu')){ + SUGAR.subpanelUtils.subpanelSubTabs[group] += ''; + } + SUGAR.subpanelUtils.subpanelSubTabs[group] += '
            | '+SUGAR.subpanelUtils.subpanelTitles[preMore[sp_key]]+' |  >> 
            '; + + // Update the more menu for the current group + var postMore = SUGAR.subpanelUtils.subpanelGroups[group].slice(SUGAR.subpanelUtils.subpanelMaxSubtabs); + var subpanelMenu = document.getElementById('MoreSub'+group+'PanelMenu'); + + if(postMore && subpanelMenu){ + subpanelMenu.innerHTML = ''; + for(var sp_key = 0; sp_key < postMore.length; sp_key++){ + subpanelMenu.innerHTML += '
            '+SUGAR.subpanelUtils.subpanelTitles[postMore[sp_key]]+''; + } + subpanelMenu += '
            '; + } + }, + + setGroupCookie: function(group){ + Set_Cookie(SUGAR.subpanelUtils.tabCookieName, group, 3000, false, false,false); + } + }; +}(); + +SUGAR.subpanelUtils.menu = function(){ + return { + tbspButtonMouseOver : function(id,top,left,leftOffset){ //*// + closeMenusDelay = eraseTimeout(closeMenusDelay); + if (openMenusDelay == null){ + openMenusDelay = window.setTimeout("SUGAR.subpanelUtils.menu.spShowMenu('"+id+"','"+top+"','"+left+"','"+leftOffset+"')", delayTime); + } + }, + spShowMenu : function(id,top,left,leftOffset){ //*// + openMenusDelay = eraseTimeout(openMenusDelay); + var menuName = id.replace(/Handle/i,'Menu'); + var menu = getLayer(menuName); + //if (menu) menu.className = 'tbButtonMouseOverUp'; + if (currentMenu){ + closeAllMenus(); + } + SUGAR.subpanelUtils.menu.spPopupMenu(id, menu, top,left,leftOffset); + }, + spPopupMenu : function(handleID, menu, top, left, leftOffset){ //*// + var bw = checkBrowserWidth(); + var menuName = handleID.replace(/Handle/i,'Menu'); + var menuWidth = 120; + var imgWidth = document.getElementById(handleID).width; + if (menu){ + var menuHandle = getLayer(handleID); + var p=menuHandle; + if (left == "") { + var left = 0; + while(p&&p.tagName.toUpperCase()!='BODY'){ + left+=p.offsetLeft; + p=p.offsetParent; + } + left+=parseInt(leftOffset); + } + if (top == "") { + var top = 0; + p=menuHandle; + top+=p.offsetHeight; + while(p&&p.tagName.toUpperCase()!='BODY'){ + top+=p.offsetTop; + p=p.offsetParent; + } + } + if (left+menuWidth>bw) { + left = left-menuWidth+imgWidth; + } + setMenuVisible(menu, left, top, false); + } + } + }; +}(); diff --git a/jssource/src_files/include/SugarCharts/Jit/FlashCanvas/canvas2png.js b/jssource/src_files/include/SugarCharts/Jit/FlashCanvas/canvas2png.js new file mode 100644 index 00000000..00ea13e0 --- /dev/null +++ b/jssource/src_files/include/SugarCharts/Jit/FlashCanvas/canvas2png.js @@ -0,0 +1,42 @@ +/* + * canvas2png.js + * + * Copyright (c) 2010-2011 Shinya Muramatsu + * Released under the MIT License + * http://flashcanvas.net/ + */ + +(function(doc) { + +var scripts = doc.getElementsByTagName("script"); +var script = scripts[scripts.length - 1]; +var url = script.getAttribute("src").replace(/[^\/]+$/, "save.php"); + +window.canvas2png = function(canvas) { + var tagName = canvas.tagName.toLowerCase(); + if (tagName !== "canvas") { + return; + } + + if (typeof FlashCanvas !== "undefined") { + FlashCanvas.saveImage(canvas); + } else { + var form = doc.createElement("form"); + var input = doc.createElement("input"); + + form.setAttribute("action", url); + form.setAttribute("method", "post"); + + input.setAttribute("type", "hidden"); + input.setAttribute("name", "dataurl"); + input.setAttribute("value", canvas.toDataURL()); + + doc.body.appendChild(form); + form.appendChild(input); + form.submit(); + form.removeChild(input); + doc.body.removeChild(form); + } +} + +})(document); diff --git a/jssource/src_files/include/SugarCharts/Jit/FlashCanvas/flashcanvas.js b/jssource/src_files/include/SugarCharts/Jit/FlashCanvas/flashcanvas.js new file mode 100644 index 00000000..dc0eee00 --- /dev/null +++ b/jssource/src_files/include/SugarCharts/Jit/FlashCanvas/flashcanvas.js @@ -0,0 +1,28 @@ +/* + * FlashCanvas + * + * Copyright (c) 2009 Tim Cameron Ryan + * Copyright (c) 2009-2011 FlashCanvas Project + * Released under the MIT/X License + */ +window.ActiveXObject&&!window.CanvasRenderingContext2D&&function(h,j){function D(a){this.code=a;this.message=T[a]}function U(a){this.width=a}function E(a){this.id=a.C++}function t(a){this.G=a;this.id=a.C++}function u(a,b){this.canvas=a;this.B=b;this.d=a.uniqueID;this.D();this.C=0;this.t="";var c=this;setInterval(function(){n[c.d]===0&&c.e()},30)}function A(){if(j.readyState==="complete"){j.detachEvent(F,A);for(var a=j.getElementsByTagName(r),b=0,c=a.length;b=8?a.src:a.getAttribute("src",4)}function v(a){return(""+a).replace(/&/g,"&").replace(/0)return eval(this.B.CallFunction(''+a.join("�")+""))},I:function(a,b){this.e();this.D();if(a>0)this.B.width=a;if(b>0)this.B.height=b;this.a.push(e.resize,a,b)}};t.prototype={addColorStop:function(a,b){if(isNaN(a)||a<0||a>1)i(1);this.G.a.push(e.addColorStop,this.id,a,b)}};D.prototype=Error();var T={1:"INDEX_SIZE_ERR",9:"NOT_SUPPORTED_ERR",11:"INVALID_STATE_ERR", +12:"SYNTAX_ERR",17:"TYPE_MISMATCH_ERR",18:"SECURITY_ERR"},B={initElement:function(a){if(a.getContext)return a;var b=a.uniqueID,c="external"+b;x[b]=false;n[b]=1;Q(a);a.innerHTML=''; +s[b]=a;var d=a.firstChild;y[b]=a.lastChild;var f=j.body.contains;if(f(a))d.movie=w;else var g=setInterval(function(){if(f(a)){clearInterval(g);d.movie=w}},0);if(j.compatMode==="BackCompat"||!h.XMLHttpRequest)y[b].style.overflow="hidden";var o=new u(a,d);a.getContext=function(l){return l==="2d"?o:k};a.toDataURL=function(l,z){(""+l).replace(/[A-Z]+/g,W)==="image/jpeg"?o.a.push(e.toDataURL,l,typeof z==="number"?z:""):o.a.push(e.toDataURL,l);return o.e()};d.attachEvent(K,G);return a},saveImage:function(a){a.firstChild.saveImage()}, +setOptions:function(){},trigger:function(a,b){s[a].fireEvent("on"+b)},unlock:function(a,b){n[a]&&--n[a];if(b){var c=s[a],d=c.firstChild,f,g;Q(c);f=c.width;g=c.height;c.style.width=f+"px";c.style.height=g+"px";if(f>0)d.width=f;if(g>0)d.height=g;d.resize(f,g);c.attachEvent(L,H);x[a]=true}}};j.createElement(r);j.createStyleSheet().cssText=r+"{display:inline-block;overflow:hidden;width:300px;height:150px}";j.readyState==="complete"?A():j.attachEvent(F,A);h.attachEvent(J,I);if(w.indexOf(location.protocol+ +"//"+location.host+"/")===0){var S=new ActiveXObject("Microsoft.XMLHTTP");S.open("GET",w,false);S.send(k)}h[M]=u;h[N]=t;h[O]=E;h[C]=B;h[P]={init:function(){},init_:function(){},initElement:B.initElement};keep=u.measureText}(window,document); diff --git a/jssource/src_files/include/SugarCharts/Jit/js/Jit/jit.js b/jssource/src_files/include/SugarCharts/Jit/js/Jit/jit.js new file mode 100644 index 00000000..2a82bddf --- /dev/null +++ b/jssource/src_files/include/SugarCharts/Jit/js/Jit/jit.js @@ -0,0 +1,20674 @@ +/* + Copyright (c) 2010, Nicolas Garcia Belmonte + 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 organization 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 NICOLAS GARCIA BELMONTE ``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 NICOLAS GARCIA BELMONTE 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. + */ + + /** Lam Huynh on 10/10/2010 added funnel,guage charts **/ + /** Lam Huynh on 02/27/2011 added image exporting **/ + /** Lam Huynh on 02/23/2011 added line charts **/ + + (function () { + +/* + File: Core.js + + */ + +/* + Object: $jit + + Defines the namespace for all library Classes and Objects. + This variable is the *only* global variable defined in the Toolkit. + There are also other interesting properties attached to this variable described below. + */ +window.$jit = function(w) { + w = w || window; + for(var k in $jit) { + if($jit[k].$extend) { + w[k] = $jit[k]; + } + } +}; + +$jit.version = '2.0.0b'; +/* + Object: $jit.id + + Works just like *document.getElementById* + + Example: + (start code js) + var element = $jit.id('elementId'); + (end code) + +*/ + +/* + Object: $jit.util + + Contains utility functions. + + Some of the utility functions and the Class system were based in the MooTools Framework + . Copyright (c) 2006-2010 Valerio Proietti, . + MIT license . + + These methods are generally also implemented in DOM manipulation frameworks like JQuery, MooTools and Prototype. + I'd suggest you to use the functions from those libraries instead of using these, since their functions + are widely used and tested in many different platforms/browsers. Use these functions only if you have to. + + */ +var $ = function(d) { + return document.getElementById(d); +}; + +$.empty = function() { +}; + +function pad(number, length) { + + var str = '' + number; + while (str.length < length) { + str = str + '0'; + } + + return str; + +}; + +var Url = { + + // public method for url encoding + encode : function (string) { + return escape(this._utf8_encode(string)); + }, + + // public method for url decoding + decode : function (string) { + return this._utf8_decode(unescape(string)); + }, + + // private method for UTF-8 encoding + _utf8_encode : function (string) { + string = string.replace(/\r\n/g,"\n"); + var utftext = ""; + + for (var n = 0; n < string.length; n++) { + + var c = string.charCodeAt(n); + + if (c < 128) { + utftext += String.fromCharCode(c); + } + else if((c > 127) && (c < 2048)) { + utftext += String.fromCharCode((c >> 6) | 192); + utftext += String.fromCharCode((c & 63) | 128); + } + else { + utftext += String.fromCharCode((c >> 12) | 224); + utftext += String.fromCharCode(((c >> 6) & 63) | 128); + utftext += String.fromCharCode((c & 63) | 128); + } + + } + + return utftext; + }, + + // private method for UTF-8 decoding + _utf8_decode : function (utftext) { + var string = ""; + var i = 0; + var c = c1 = c2 = 0; + + while ( i < utftext.length ) { + + c = utftext.charCodeAt(i); + + if (c < 128) { + string += String.fromCharCode(c); + i++; + } + else if((c > 191) && (c < 224)) { + c2 = utftext.charCodeAt(i+1); + string += String.fromCharCode(((c & 31) << 6) | (c2 & 63)); + i += 2; + } + else { + c2 = utftext.charCodeAt(i+1); + c3 = utftext.charCodeAt(i+2); + string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63)); + i += 3; + } + + } + + return string; + } + +}; + +Array.prototype.sum = function() { + return (! this.length) ? 0 : this.slice(1).sum() + + ((typeof this[0] == 'number') ? this[0] : 0); +}; + +function array_match(needle, haystack) { + var length = haystack.length; + var indexValue = new Array(); + for(var i = 0, count = 0; i < length; i++) { + if(haystack[i] == needle) { + indexValue[count] = i; + count++; + } + } + return new Array(count,indexValue); +}; + +$.roundedRect = function (ctx,x,y,width,height,radius,fillType){ + ctx.beginPath(); + ctx.moveTo(x,y+radius); + ctx.lineTo(x,y+height-radius); + ctx.quadraticCurveTo(x,y+height,x+radius,y+height); + ctx.lineTo(x+width-radius,y+height); + ctx.quadraticCurveTo(x+width,y+height,x+width,y+height-radius); + ctx.lineTo(x+width,y+radius); + ctx.quadraticCurveTo(x+width,y,x+width-radius,y); + ctx.lineTo(x+radius,y); + ctx.quadraticCurveTo(x,y,x,y+radius); + if(fillType=="fill") { + ctx.fill(); + } else { + ctx.stroke(); + } +}; + +$.saveImageFile = function (id,jsonfilename,imageExt) { + var parts = jsonfilename.split("/"); + var filename = parts[2].replace(".js","."+imageExt); + var oCanvas = document.getElementById(id+"-canvas"); + + if(oCanvas) { + if(imageExt == "jpg") { + var strDataURI = oCanvas.toDataURL("image/jpeg"); + } else { + var strDataURI = oCanvas.toDataURL("image/png"); + } + var handleFailure = function(o){ + alert('failed to write image' + filename); + } + var handleSuccess = function(o){ + } + var callback = + { + success:handleSuccess, + failure:handleFailure, + argument: { foo:'foo', bar:''} + }; + var path = "index.php?action=DynamicAction&DynamicAction=saveImage&module=Charts&to_pdf=1"; + var postData = "imageStr=" + strDataURI + "&filename=" + filename; + var request = YAHOO.util.Connect.asyncRequest('POST', path, callback, postData); + } +}; + +$.saveImageTest = function (id,jsonfilename,imageExt) { + if(typeof FlashCanvas != "undefined") { + setTimeout(function(){$.saveImageFile(id,jsonfilename,imageExt)},10000); + } else { + $.saveImageFile(id,jsonfilename,imageExt); + } + }; +/* + Method: extend + + Augment an object by appending another object's properties. + + Parameters: + + original - (object) The object to be extended. + extended - (object) An object which properties are going to be appended to the original object. + + Example: + (start code js) + $jit.util.extend({ 'a': 1, 'b': 2 }, { 'b': 3, 'c': 4 }); //{ 'a':1, 'b': 3, 'c': 4 } + (end code) +*/ +$.extend = function(original, extended) { + for ( var key in (extended || {})) + original[key] = extended[key]; + return original; +}; + +$.lambda = function(value) { + return (typeof value == 'function') ? value : function() { + return value; + }; +}; + +$.time = Date.now || function() { + return +new Date; +}; + +/* + Method: splat + + Returns an array wrapping *obj* if *obj* is not an array. Returns *obj* otherwise. + + Parameters: + + obj - (mixed) The object to be wrapped in an array. + + Example: + (start code js) + $jit.util.splat(3); //[3] + $jit.util.splat([3]); //[3] + (end code) +*/ +$.splat = function(obj) { + var type = $.type(obj); + return type ? ((type != 'array') ? [ obj ] : obj) : []; +}; + +$.type = function(elem) { + var type = $.type.s.call(elem).match(/^\[object\s(.*)\]$/)[1].toLowerCase(); + if(type != 'object') return type; + if(elem && elem.$$family) return elem.$$family; + return (elem && elem.nodeName && elem.nodeType == 1)? 'element' : type; +}; +$.type.s = Object.prototype.toString; + +/* + Method: each + + Iterates through an iterable applying *f*. + + Parameters: + + iterable - (array) The original array. + fn - (function) The function to apply to the array elements. + + Example: + (start code js) + $jit.util.each([3, 4, 5], function(n) { alert('number ' + n); }); + (end code) +*/ +$.each = function(iterable, fn) { + var type = $.type(iterable); + if (type == 'object') { + for ( var key in iterable) + fn(iterable[key], key); + } else { + for ( var i = 0, l = iterable.length; i < l; i++) + fn(iterable[i], i); + } +}; + +$.indexOf = function(array, item) { + if(Array.indexOf) return array.indexOf(item); + for(var i=0,l=array.length; i> 16, hex >> 8 & 0xff, hex & 0xff ]; + } +}; + +$.destroy = function(elem) { + $.clean(elem); + if (elem.parentNode) + elem.parentNode.removeChild(elem); + if (elem.clearAttributes) + elem.clearAttributes(); +}; + +$.clean = function(elem) { + for (var ch = elem.childNodes, i = 0, l = ch.length; i < l; i++) { + $.destroy(ch[i]); + } +}; + +/* + Method: addEvent + + Cross-browser add event listener. + + Parameters: + + obj - (obj) The Element to attach the listener to. + type - (string) The listener type. For example 'click', or 'mousemove'. + fn - (function) The callback function to be used when the event is fired. + + Example: + (start code js) + $jit.util.addEvent(elem, 'click', function(){ alert('hello'); }); + (end code) +*/ +$.addEvent = function(obj, type, fn) { + if (obj.addEventListener) + obj.addEventListener(type, fn, false); + else + obj.attachEvent('on' + type, fn); +}; + +$.addEvents = function(obj, typeObj) { + for(var type in typeObj) { + $.addEvent(obj, type, typeObj[type]); + } +}; + +$.hasClass = function(obj, klass) { + return (' ' + obj.className + ' ').indexOf(' ' + klass + ' ') > -1; +}; + +$.addClass = function(obj, klass) { + if (!$.hasClass(obj, klass)) + obj.className = (obj.className + " " + klass); +}; + +$.removeClass = function(obj, klass) { + obj.className = obj.className.replace(new RegExp( + '(^|\\s)' + klass + '(?:\\s|$)'), '$1'); +}; + +$.getPos = function(elem) { + var offset = getOffsets(elem); + var scroll = getScrolls(elem); + return { + x: offset.x - scroll.x, + y: offset.y - scroll.y + }; + + function getOffsets(elem) { + var position = { + x: 0, + y: 0 + }; + while (elem && !isBody(elem)) { + position.x += elem.offsetLeft; + position.y += elem.offsetTop; + elem = elem.offsetParent; + } + return position; + } + + function getScrolls(elem) { + var position = { + x: 0, + y: 0 + }; + while (elem && !isBody(elem)) { + position.x += elem.scrollLeft; + position.y += elem.scrollTop; + elem = elem.parentNode; + } + return position; + } + + function isBody(element) { + return (/^(?:body|html)$/i).test(element.tagName); + } +}; + +$.event = { + get: function(e, win) { + win = win || window; + return e || win.event; + }, + getWheel: function(e) { + return e.wheelDelta? e.wheelDelta / 120 : -(e.detail || 0) / 3; + }, + isRightClick: function(e) { + return (e.which == 3 || e.button == 2); + }, + getPos: function(e, win) { + // get mouse position + win = win || window; + e = e || win.event; + var doc = win.document; + doc = doc.documentElement || doc.body; + //TODO(nico): make touch event handling better + if(e.touches && e.touches.length) { + e = e.touches[0]; + } + var page = { + x: e.pageX || (e.clientX + doc.scrollLeft), + y: e.pageY || (e.clientY + doc.scrollTop) + }; + return page; + }, + stop: function(e) { + if (e.stopPropagation) e.stopPropagation(); + e.cancelBubble = true; + if (e.preventDefault) e.preventDefault(); + else e.returnValue = false; + } +}; + +$jit.util = $jit.id = $; + +var Class = function(properties) { + properties = properties || {}; + var klass = function() { + for ( var key in this) { + if (typeof this[key] != 'function') + this[key] = $.unlink(this[key]); + } + this.constructor = klass; + if (Class.prototyping) + return this; + var instance = this.initialize ? this.initialize.apply(this, arguments) + : this; + //typize + this.$$family = 'class'; + return instance; + }; + + for ( var mutator in Class.Mutators) { + if (!properties[mutator]) + continue; + properties = Class.Mutators[mutator](properties, properties[mutator]); + delete properties[mutator]; + } + + $.extend(klass, this); + klass.constructor = Class; + klass.prototype = properties; + return klass; +}; + +Class.Mutators = { + + Implements: function(self, klasses) { + $.each($.splat(klasses), function(klass) { + Class.prototyping = klass; + var instance = (typeof klass == 'function') ? new klass : klass; + for ( var prop in instance) { + if (!(prop in self)) { + self[prop] = instance[prop]; + } + } + delete Class.prototyping; + }); + return self; + } + +}; + +$.extend(Class, { + + inherit: function(object, properties) { + for ( var key in properties) { + var override = properties[key]; + var previous = object[key]; + var type = $.type(override); + if (previous && type == 'function') { + if (override != previous) { + Class.override(object, key, override); + } + } else if (type == 'object') { + object[key] = $.merge(previous, override); + } else { + object[key] = override; + } + } + return object; + }, + + override: function(object, name, method) { + var parent = Class.prototyping; + if (parent && object[name] != parent[name]) + parent = null; + var override = function() { + var previous = this.parent; + this.parent = parent ? parent[name] : object[name]; + var value = method.apply(this, arguments); + this.parent = previous; + return value; + }; + object[name] = override; + } + +}); + +Class.prototype.implement = function() { + var proto = this.prototype; + $.each(Array.prototype.slice.call(arguments || []), function(properties) { + Class.inherit(proto, properties); + }); + return this; +}; + +$jit.Class = Class; + +/* + Object: $jit.json + + Provides JSON utility functions. + + Most of these functions are JSON-tree traversal and manipulation functions. +*/ +$jit.json = { + /* + Method: prune + + Clears all tree nodes having depth greater than maxLevel. + + Parameters: + + tree - (object) A JSON tree object. For more information please see . + maxLevel - (number) An integer specifying the maximum level allowed for this tree. All nodes having depth greater than max level will be deleted. + + */ + prune: function(tree, maxLevel) { + this.each(tree, function(elem, i) { + if (i == maxLevel && elem.children) { + delete elem.children; + elem.children = []; + } + }); + }, + /* + Method: getParent + + Returns the parent node of the node having _id_ as id. + + Parameters: + + tree - (object) A JSON tree object. See also . + id - (string) The _id_ of the child node whose parent will be returned. + + Returns: + + A tree JSON node if any, or false otherwise. + + */ + getParent: function(tree, id) { + if (tree.id == id) + return false; + var ch = tree.children; + if (ch && ch.length > 0) { + for ( var i = 0; i < ch.length; i++) { + if (ch[i].id == id) + return tree; + else { + var ans = this.getParent(ch[i], id); + if (ans) + return ans; + } + } + } + return false; + }, + /* + Method: getSubtree + + Returns the subtree that matches the given id. + + Parameters: + + tree - (object) A JSON tree object. See also . + id - (string) A node *unique* identifier. + + Returns: + + A subtree having a root node matching the given id. Returns null if no subtree matching the id is found. + + */ + getSubtree: function(tree, id) { + if (tree.id == id) + return tree; + for ( var i = 0, ch = tree.children; i < ch.length; i++) { + var t = this.getSubtree(ch[i], id); + if (t != null) + return t; + } + return null; + }, + /* + Method: eachLevel + + Iterates on tree nodes with relative depth less or equal than a specified level. + + Parameters: + + tree - (object) A JSON tree or subtree. See also . + initLevel - (number) An integer specifying the initial relative level. Usually zero. + toLevel - (number) An integer specifying a top level. This method will iterate only through nodes with depth less than or equal this number. + action - (function) A function that receives a node and an integer specifying the actual level of the node. + + Example: + (start code js) + $jit.json.eachLevel(tree, 0, 3, function(node, depth) { + alert(node.name + ' ' + depth); + }); + (end code) + */ + eachLevel: function(tree, initLevel, toLevel, action) { + if (initLevel <= toLevel) { + action(tree, initLevel); + if(!tree.children) return; + for ( var i = 0, ch = tree.children; i < ch.length; i++) { + this.eachLevel(ch[i], initLevel + 1, toLevel, action); + } + } + }, + /* + Method: each + + A JSON tree iterator. + + Parameters: + + tree - (object) A JSON tree or subtree. See also . + action - (function) A function that receives a node. + + Example: + (start code js) + $jit.json.each(tree, function(node) { + alert(node.name); + }); + (end code) + + */ + each: function(tree, action) { + this.eachLevel(tree, 0, Number.MAX_VALUE, action); + } +}; + + +/* + An object containing multiple type of transformations. +*/ + +$jit.Trans = { + $extend: true, + + linear: function(p){ + return p; + } +}; + +var Trans = $jit.Trans; + +(function(){ + + var makeTrans = function(transition, params){ + params = $.splat(params); + return $.extend(transition, { + easeIn: function(pos){ + return transition(pos, params); + }, + easeOut: function(pos){ + return 1 - transition(1 - pos, params); + }, + easeInOut: function(pos){ + return (pos <= 0.5)? transition(2 * pos, params) / 2 : (2 - transition( + 2 * (1 - pos), params)) / 2; + } + }); + }; + + var transitions = { + + Pow: function(p, x){ + return Math.pow(p, x[0] || 6); + }, + + Expo: function(p){ + return Math.pow(2, 8 * (p - 1)); + }, + + Circ: function(p){ + return 1 - Math.sin(Math.acos(p)); + }, + + Sine: function(p){ + return 1 - Math.sin((1 - p) * Math.PI / 2); + }, + + Back: function(p, x){ + x = x[0] || 1.618; + return Math.pow(p, 2) * ((x + 1) * p - x); + }, + + Bounce: function(p){ + var value; + for ( var a = 0, b = 1; 1; a += b, b /= 2) { + if (p >= (7 - 4 * a) / 11) { + value = b * b - Math.pow((11 - 6 * a - 11 * p) / 4, 2); + break; + } + } + return value; + }, + + Elastic: function(p, x){ + return Math.pow(2, 10 * --p) + * Math.cos(20 * p * Math.PI * (x[0] || 1) / 3); + } + + }; + + $.each(transitions, function(val, key){ + Trans[key] = makeTrans(val); + }); + + $.each( [ + 'Quad', 'Cubic', 'Quart', 'Quint' + ], function(elem, i){ + Trans[elem] = makeTrans(function(p){ + return Math.pow(p, [ + i + 2 + ]); + }); + }); + +})(); + +/* + A Class that can perform animations for generic objects. + + If you are looking for animation transitions please take a look at the object. + + Used by: + + + + Based on: + + The Animation class is based in the MooTools Framework . Copyright (c) 2006-2009 Valerio Proietti, . MIT license . + +*/ + +var Animation = new Class( { + + initialize: function(options){ + this.setOptions(options); + }, + + setOptions: function(options){ + var opt = { + duration: 2500, + fps: 40, + transition: Trans.Quart.easeInOut, + compute: $.empty, + complete: $.empty, + link: 'ignore' + }; + this.opt = $.merge(opt, options || {}); + return this; + }, + + step: function(){ + var time = $.time(), opt = this.opt; + if (time < this.time + opt.duration) { + var delta = opt.transition((time - this.time) / opt.duration); + opt.compute(delta); + } else { + this.timer = clearInterval(this.timer); + opt.compute(1); + opt.complete(); + } + }, + + start: function(){ + if (!this.check()) + return this; + this.time = 0; + this.startTimer(); + return this; + }, + + startTimer: function(){ + var that = this, fps = this.opt.fps; + if (this.timer) + return false; + this.time = $.time() - this.time; + this.timer = setInterval((function(){ + that.step(); + }), Math.round(1000 / fps)); + return true; + }, + + pause: function(){ + this.stopTimer(); + return this; + }, + + resume: function(){ + this.startTimer(); + return this; + }, + + stopTimer: function(){ + if (!this.timer) + return false; + this.time = $.time() - this.time; + this.timer = clearInterval(this.timer); + return true; + }, + + check: function(){ + if (!this.timer) + return true; + if (this.opt.link == 'cancel') { + this.stopTimer(); + return true; + } + return false; + } +}); + + +var Options = function() { + var args = arguments; + for(var i=0, l=args.length, ans={}; i options. + Other options included in the AreaChart are , , , and . + + Syntax: + + (start code js) + + Options.AreaChart = { + animate: true, + labelOffset: 3, + type: 'stacked', + selectOnHover: true, + showAggregates: true, + showLabels: true, + filterOnClick: false, + restoreOnRightClick: false + }; + + (end code) + + Example: + + (start code js) + + var areaChart = new $jit.AreaChart({ + animate: true, + type: 'stacked:gradient', + selectOnHover: true, + filterOnClick: true, + restoreOnRightClick: true + }); + + (end code) + + Parameters: + + animate - (boolean) Default's *true*. Whether to add animated transitions when filtering/restoring stacks. + labelOffset - (number) Default's *3*. Adds margin between the label and the default place where it should be drawn. + type - (string) Default's *'stacked'*. Stack style. Posible values are 'stacked', 'stacked:gradient' to add gradients. + selectOnHover - (boolean) Default's *true*. If true, it will add a mark to the hovered stack. + showAggregates - (boolean) Default's *true*. Display the sum of the values of the different stacks. + showLabels - (boolean) Default's *true*. Display the name of the slots. + filterOnClick - (boolean) Default's *true*. Select the clicked stack by hiding all other stacks. + restoreOnRightClick - (boolean) Default's *true*. Show all stacks by right clicking. + +*/ + +Options.AreaChart = { + $extend: true, + + animate: true, + labelOffset: 3, // label offset + type: 'stacked', // gradient + Tips: { + enable: false, + onShow: $.empty, + onHide: $.empty + }, + Events: { + enable: false, + onClick: $.empty + }, + selectOnHover: true, + showAggregates: true, + showLabels: true, + filterOnClick: false, + restoreOnRightClick: false +}; + +/* + * File: Options.Margin.js + * +*/ + +/* + Object: Options.Margin + + Canvas drawing margins. + + Syntax: + + (start code js) + + Options.Margin = { + top: 0, + left: 0, + right: 0, + bottom: 0 + }; + + (end code) + + Example: + + (start code js) + + var viz = new $jit.Viz({ + Margin: { + right: 10, + bottom: 20 + } + }); + + (end code) + + Parameters: + + top - (number) Default's *0*. Top margin. + left - (number) Default's *0*. Left margin. + right - (number) Default's *0*. Right margin. + bottom - (number) Default's *0*. Bottom margin. + +*/ + +Options.Margin = { + $extend: false, + + top: 0, + left: 0, + right: 0, + bottom: 0 +}; + +/* + * File: Options.Canvas.js + * +*/ + +/* + Object: Options.Canvas + + These are Canvas general options, like where to append it in the DOM, its dimensions, background, + and other more advanced options. + + Syntax: + + (start code js) + + Options.Canvas = { + injectInto: 'id', + width: false, + height: false, + useCanvas: false, + withLabels: true, + background: false + }; + (end code) + + Example: + + (start code js) + var viz = new $jit.Viz({ + injectInto: 'someContainerId', + width: 500, + height: 700 + }); + (end code) + + Parameters: + + injectInto - *required* (string|element) The id of the DOM container for the visualization. It can also be an Element provided that it has an id. + width - (number) Default's to the *container's offsetWidth*. The width of the canvas. + height - (number) Default's to the *container's offsetHeight*. The height of the canvas. + useCanvas - (boolean|object) Default's *false*. You can pass another instance to be used by the visualization. + withLabels - (boolean) Default's *true*. Whether to use a label container for the visualization. + background - (boolean|object) Default's *false*. An object containing information about the rendering of a background canvas. +*/ + +Options.Canvas = { + $extend: true, + + injectInto: 'id', + width: false, + height: false, + useCanvas: false, + withLabels: true, + background: false, + colorStop1: 'rgba(255,255,255,1)', + colorStop2: 'rgba(255,255,255,0)' +}; + +/* + * File: Options.Tree.js + * +*/ + +/* + Object: Options.Tree + + Options related to (strict) Tree layout algorithms. These options are used by the visualization. + + Syntax: + + (start code js) + Options.Tree = { + orientation: "left", + subtreeOffset: 8, + siblingOffset: 5, + indent:10, + multitree: false, + align:"center" + }; + (end code) + + Example: + + (start code js) + var st = new $jit.ST({ + orientation: 'left', + subtreeOffset: 1, + siblingOFfset: 5, + multitree: true + }); + (end code) + + Parameters: + + subtreeOffset - (number) Default's 8. Separation offset between subtrees. + siblingOffset - (number) Default's 5. Separation offset between siblings. + orientation - (string) Default's 'left'. Tree orientation layout. Possible values are 'left', 'top', 'right', 'bottom'. + align - (string) Default's *center*. Whether the tree alignment is 'left', 'center' or 'right'. + indent - (number) Default's 10. Used when *align* is left or right and shows an indentation between parent and children. + multitree - (boolean) Default's *false*. Used with the node $orn data property for creating multitrees. + +*/ +Options.Tree = { + $extend: true, + + orientation: "left", + subtreeOffset: 8, + siblingOffset: 5, + indent:10, + multitree: false, + align:"center" +}; + + +/* + * File: Options.Node.js + * +*/ + +/* + Object: Options.Node + + Provides Node rendering options for Tree and Graph based visualizations. + + Syntax: + + (start code js) + Options.Node = { + overridable: false, + type: 'circle', + color: '#ccb', + alpha: 1, + dim: 3, + height: 20, + width: 90, + autoHeight: false, + autoWidth: false, + lineWidth: 1, + transform: true, + align: "center", + angularWidth:1, + span:1, + CanvasStyles: {} + }; + (end code) + + Example: + + (start code js) + var viz = new $jit.Viz({ + Node: { + overridable: true, + width: 30, + autoHeight: true, + type: 'rectangle' + } + }); + (end code) + + Parameters: + + overridable - (boolean) Default's *false*. Determine whether or not general node properties can be overridden by a particular . + type - (string) Default's *circle*. Node's shape. Node built-in types include 'circle', 'rectangle', 'square', 'ellipse', 'triangle', 'star'. The default Node type might vary in each visualization. You can also implement (non built-in) custom Node types into your visualizations. + color - (string) Default's *#ccb*. Node color. + alpha - (number) Default's *1*. The Node's alpha value. *1* is for full opacity. + dim - (number) Default's *3*. An extra parameter used by other node shapes such as circle or square, to determine the shape's diameter. + height - (number) Default's *20*. Used by 'rectangle' and 'ellipse' node types. The height of the node shape. + width - (number) Default's *90*. Used by 'rectangle' and 'ellipse' node types. The width of the node shape. + autoHeight - (boolean) Default's *false*. Whether to set an auto height for the node depending on the content of the Node's label. + autoWidth - (boolean) Default's *false*. Whether to set an auto width for the node depending on the content of the Node's label. + lineWidth - (number) Default's *1*. Used only by some Node shapes. The line width of the strokes of a node. + transform - (boolean) Default's *true*. Only used by the visualization. Whether to scale the nodes according to the moebius transformation. + align - (string) Default's *center*. Possible values are 'center', 'left' or 'right'. Used only by the visualization, these parameters are used for aligning nodes when some of they dimensions vary. + angularWidth - (number) Default's *1*. Used in radial layouts (like or visualizations). The amount of relative 'space' set for a node. + span - (number) Default's *1*. Used in radial layouts (like or visualizations). The angle span amount set for a node. + CanvasStyles - (object) Default's an empty object (i.e. {}). Attach any other canvas specific property that you'd set to the canvas context before plotting a Node. + +*/ +Options.Node = { + $extend: false, + + overridable: false, + type: 'circle', + color: '#ccb', + alpha: 1, + dim: 3, + height: 20, + width: 90, + autoHeight: false, + autoWidth: false, + lineWidth: 1, + transform: true, + align: "center", + angularWidth:1, + span:1, + //Raw canvas styles to be + //applied to the context instance + //before plotting a node + CanvasStyles: {} +}; + + +/* + * File: Options.Edge.js + * +*/ + +/* + Object: Options.Edge + + Provides Edge rendering options for Tree and Graph based visualizations. + + Syntax: + + (start code js) + Options.Edge = { + overridable: false, + type: 'line', + color: '#ccb', + lineWidth: 1, + dim:15, + alpha: 1, + CanvasStyles: {} + }; + (end code) + + Example: + + (start code js) + var viz = new $jit.Viz({ + Edge: { + overridable: true, + type: 'line', + color: '#fff', + CanvasStyles: { + shadowColor: '#ccc', + shadowBlur: 10 + } + } + }); + (end code) + + Parameters: + + overridable - (boolean) Default's *false*. Determine whether or not general edges properties can be overridden by a particular . + type - (string) Default's 'line'. Edge styles include 'line', 'hyperline', 'arrow'. The default Edge type might vary in each visualization. You can also implement custom Edge types. + color - (string) Default's '#ccb'. Edge color. + lineWidth - (number) Default's *1*. Line/Edge width. + alpha - (number) Default's *1*. The Edge's alpha value. *1* is for full opacity. + dim - (number) Default's *15*. An extra parameter used by other complex shapes such as quadratic, bezier or arrow, to determine the shape's diameter. + epsilon - (number) Default's *7*. Only used when using *enableForEdges* in . This dimension is used to create an area for the line where the contains method for the edge returns *true*. + CanvasStyles - (object) Default's an empty object (i.e. {}). Attach any other canvas specific property that you'd set to the canvas context before plotting an Edge. + + See also: + + If you want to know more about how to customize Node/Edge data per element, in the JSON or programmatically, take a look at this article. +*/ +Options.Edge = { + $extend: false, + + overridable: false, + type: 'line', + color: '#ccb', + lineWidth: 1, + dim:15, + alpha: 1, + epsilon: 7, + + //Raw canvas styles to be + //applied to the context instance + //before plotting an edge + CanvasStyles: {} +}; + + +/* + * File: Options.Fx.js + * +*/ + +/* + Object: Options.Fx + + Provides animation options like duration of the animations, frames per second and animation transitions. + + Syntax: + + (start code js) + Options.Fx = { + fps:40, + duration: 2500, + transition: $jit.Trans.Quart.easeInOut, + clearCanvas: true + }; + (end code) + + Example: + + (start code js) + var viz = new $jit.Viz({ + duration: 1000, + fps: 35, + transition: $jit.Trans.linear + }); + (end code) + + Parameters: + + clearCanvas - (boolean) Default's *true*. Whether to clear the frame/canvas when the viz is plotted or animated. + duration - (number) Default's *2500*. Duration of the animation in milliseconds. + fps - (number) Default's *40*. Frames per second. + transition - (object) Default's *$jit.Trans.Quart.easeInOut*. The transition used for the animations. See below for a more detailed explanation. + + Object: $jit.Trans + + This object is used for specifying different animation transitions in all visualizations. + + There are many different type of animation transitions. + + linear: + + Displays a linear transition + + >Trans.linear + + (see Linear.png) + + Quad: + + Displays a Quadratic transition. + + >Trans.Quad.easeIn + >Trans.Quad.easeOut + >Trans.Quad.easeInOut + + (see Quad.png) + + Cubic: + + Displays a Cubic transition. + + >Trans.Cubic.easeIn + >Trans.Cubic.easeOut + >Trans.Cubic.easeInOut + + (see Cubic.png) + + Quart: + + Displays a Quartetic transition. + + >Trans.Quart.easeIn + >Trans.Quart.easeOut + >Trans.Quart.easeInOut + + (see Quart.png) + + Quint: + + Displays a Quintic transition. + + >Trans.Quint.easeIn + >Trans.Quint.easeOut + >Trans.Quint.easeInOut + + (see Quint.png) + + Expo: + + Displays an Exponential transition. + + >Trans.Expo.easeIn + >Trans.Expo.easeOut + >Trans.Expo.easeInOut + + (see Expo.png) + + Circ: + + Displays a Circular transition. + + >Trans.Circ.easeIn + >Trans.Circ.easeOut + >Trans.Circ.easeInOut + + (see Circ.png) + + Sine: + + Displays a Sineousidal transition. + + >Trans.Sine.easeIn + >Trans.Sine.easeOut + >Trans.Sine.easeInOut + + (see Sine.png) + + Back: + + >Trans.Back.easeIn + >Trans.Back.easeOut + >Trans.Back.easeInOut + + (see Back.png) + + Bounce: + + Bouncy transition. + + >Trans.Bounce.easeIn + >Trans.Bounce.easeOut + >Trans.Bounce.easeInOut + + (see Bounce.png) + + Elastic: + + Elastic curve. + + >Trans.Elastic.easeIn + >Trans.Elastic.easeOut + >Trans.Elastic.easeInOut + + (see Elastic.png) + + Based on: + + Easing and Transition animation methods are based in the MooTools Framework . Copyright (c) 2006-2010 Valerio Proietti, . MIT license . + + +*/ +Options.Fx = { + $extend: true, + + fps:40, + duration: 2500, + transition: $jit.Trans.Quart.easeInOut, + clearCanvas: true +}; + +/* + * File: Options.Label.js + * +*/ +/* + Object: Options.Label + + Provides styling for Labels such as font size, family, etc. Also sets Node labels as HTML, SVG or Native canvas elements. + + Syntax: + + (start code js) + Options.Label = { + overridable: false, + type: 'HTML', //'SVG', 'Native' + style: ' ', + size: 10, + family: 'sans-serif', + textAlign: 'center', + textBaseline: 'alphabetic', + color: '#fff' + }; + (end code) + + Example: + + (start code js) + var viz = new $jit.Viz({ + Label: { + type: 'Native', + size: 11, + color: '#ccc' + } + }); + (end code) + + Parameters: + + overridable - (boolean) Default's *false*. Determine whether or not general label properties can be overridden by a particular . + type - (string) Default's *HTML*. The type for the labels. Can be 'HTML', 'SVG' or 'Native' canvas labels. + style - (string) Default's *empty string*. Can be 'italic' or 'bold'. This parameter is only taken into account when using 'Native' canvas labels. For DOM based labels the className *node* is added to the DOM element for styling via CSS. You can also use methods to style individual labels. + size - (number) Default's *10*. The font's size. This parameter is only taken into account when using 'Native' canvas labels. For DOM based labels the className *node* is added to the DOM element for styling via CSS. You can also use methods to style individual labels. + family - (string) Default's *sans-serif*. The font's family. This parameter is only taken into account when using 'Native' canvas labels. For DOM based labels the className *node* is added to the DOM element for styling via CSS. You can also use methods to style individual labels. + color - (string) Default's *#fff*. The font's color. This parameter is only taken into account when using 'Native' canvas labels. For DOM based labels the className *node* is added to the DOM element for styling via CSS. You can also use methods to style individual labels. +*/ +Options.Label = { + $extend: false, + + overridable: false, + type: 'HTML', //'SVG', 'Native' + style: ' ', + size: 10, + family: 'sans-serif', + textAlign: 'center', + textBaseline: 'alphabetic', + color: '#fff' +}; + + +/* + * File: Options.Tips.js + * + */ + +/* + Object: Options.Tips + + Tips options + + Syntax: + + (start code js) + Options.Tips = { + enable: false, + type: 'auto', + offsetX: 20, + offsetY: 20, + onShow: $.empty, + onHide: $.empty + }; + (end code) + + Example: + + (start code js) + var viz = new $jit.Viz({ + Tips: { + enable: true, + type: 'Native', + offsetX: 10, + offsetY: 10, + onShow: function(tip, node) { + tip.innerHTML = node.name; + } + } + }); + (end code) + + Parameters: + + enable - (boolean) Default's *false*. If *true*, a tooltip will be shown when a node is hovered. The tooltip is a div DOM element having "tip" as CSS class. + type - (string) Default's *auto*. Defines where to attach the MouseEnter/Leave tooltip events. Possible values are 'Native' to attach them to the canvas or 'HTML' to attach them to DOM label elements (if defined). 'auto' sets this property to the value of 's *type* property. + offsetX - (number) Default's *20*. An offset added to the current tooltip x-position (which is the same as the current mouse position). Default's 20. + offsetY - (number) Default's *20*. An offset added to the current tooltip y-position (which is the same as the current mouse position). Default's 20. + onShow(tip, node) - This callack is used right before displaying a tooltip. The first formal parameter is the tip itself (which is a DivElement). The second parameter may be a for graph based visualizations or an object with label, value properties for charts. + onHide() - This callack is used when hiding a tooltip. + +*/ +Options.Tips = { + $extend: false, + + enable: false, + type: 'auto', + offsetX: 20, + offsetY: 20, + force: false, + onShow: $.empty, + onHide: $.empty +}; + + +/* + * File: Options.NodeStyles.js + * + */ + +/* + Object: Options.NodeStyles + + Apply different styles when a node is hovered or selected. + + Syntax: + + (start code js) + Options.NodeStyles = { + enable: false, + type: 'auto', + stylesHover: false, + stylesClick: false + }; + (end code) + + Example: + + (start code js) + var viz = new $jit.Viz({ + NodeStyles: { + enable: true, + type: 'Native', + stylesHover: { + dim: 30, + color: '#fcc' + }, + duration: 600 + } + }); + (end code) + + Parameters: + + enable - (boolean) Default's *false*. Whether to enable this option. + type - (string) Default's *auto*. Use this to attach the hover/click events in the nodes or the nodes labels (if they have been defined as DOM elements: 'HTML' or 'SVG', see for more details). The default 'auto' value will set NodeStyles to the same type defined for . + stylesHover - (boolean|object) Default's *false*. An object with node styles just like the ones defined for or *false* otherwise. + stylesClick - (boolean|object) Default's *false*. An object with node styles just like the ones defined for or *false* otherwise. +*/ + +Options.NodeStyles = { + $extend: false, + + enable: false, + type: 'auto', + stylesHover: false, + stylesClick: false +}; + + +/* + * File: Options.Events.js + * +*/ + +/* + Object: Options.Events + + Configuration for adding mouse/touch event handlers to Nodes. + + Syntax: + + (start code js) + Options.Events = { + enable: false, + enableForEdges: false, + type: 'auto', + onClick: $.empty, + onRightClick: $.empty, + onMouseMove: $.empty, + onMouseEnter: $.empty, + onMouseLeave: $.empty, + onDragStart: $.empty, + onDragMove: $.empty, + onDragCancel: $.empty, + onDragEnd: $.empty, + onTouchStart: $.empty, + onTouchMove: $.empty, + onTouchEnd: $.empty, + onTouchCancel: $.empty, + onMouseWheel: $.empty + }; + (end code) + + Example: + + (start code js) + var viz = new $jit.Viz({ + Events: { + enable: true, + onClick: function(node, eventInfo, e) { + viz.doSomething(); + }, + onMouseEnter: function(node, eventInfo, e) { + viz.canvas.getElement().style.cursor = 'pointer'; + }, + onMouseLeave: function(node, eventInfo, e) { + viz.canvas.getElement().style.cursor = ''; + } + } + }); + (end code) + + Parameters: + + enable - (boolean) Default's *false*. Whether to enable the Event system. + enableForEdges - (boolean) Default's *false*. Whether to track events also in arcs. If *true* the same callbacks -described below- are used for nodes *and* edges. A simple duck type check for edges is to check for *node.nodeFrom*. + type - (string) Default's 'auto'. Whether to attach the events onto the HTML labels (via event delegation) or to use the custom 'Native' canvas Event System of the library. 'auto' is set when you let the *type* parameter decide this. + onClick(node, eventInfo, e) - Triggered when a user performs a click in the canvas. *node* is the clicked or false if no node has been clicked. *e* is the grabbed event (should return the native event in a cross-browser manner). *eventInfo* is an object containing useful methods like *getPos* to get the mouse position relative to the canvas. + onRightClick(node, eventInfo, e) - Triggered when a user performs a right click in the canvas. *node* is the right clicked or false if no node has been clicked. *e* is the grabbed event (should return the native event in a cross-browser manner). *eventInfo* is an object containing useful methods like *getPos* to get the mouse position relative to the canvas. + onMouseMove(node, eventInfo, e) - Triggered when the user moves the mouse. *node* is the under the cursor as it's moving over the canvas or false if no node has been clicked. *e* is the grabbed event (should return the native event in a cross-browser manner). *eventInfo* is an object containing useful methods like *getPos* to get the mouse position relative to the canvas. + onMouseEnter(node, eventInfo, e) - Triggered when a user moves the mouse over a node. *node* is the that the mouse just entered. *e* is the grabbed event (should return the native event in a cross-browser manner). *eventInfo* is an object containing useful methods like *getPos* to get the mouse position relative to the canvas. + onMouseLeave(node, eventInfo, e) - Triggered when the user mouse-outs a node. *node* is the 'mouse-outed'. *e* is the grabbed event (should return the native event in a cross-browser manner). *eventInfo* is an object containing useful methods like *getPos* to get the mouse position relative to the canvas. + onDragStart(node, eventInfo, e) - Triggered when the user mouse-downs over a node. *node* is the being pressed. *e* is the grabbed event (should return the native event in a cross-browser manner). *eventInfo* is an object containing useful methods like *getPos* to get the mouse position relative to the canvas. + onDragMove(node, eventInfo, e) - Triggered when a user, after pressing the mouse button over a node, moves the mouse around. *node* is the being dragged. *e* is the grabbed event (should return the native event in a cross-browser manner). *eventInfo* is an object containing useful methods like *getPos* to get the mouse position relative to the canvas. + onDragEnd(node, eventInfo, e) - Triggered when a user finished dragging a node. *node* is the being dragged. *e* is the grabbed event (should return the native event in a cross-browser manner). *eventInfo* is an object containing useful methods like *getPos* to get the mouse position relative to the canvas. + onDragCancel(node, eventInfo, e) - Triggered when the user releases the mouse button over a that wasn't dragged (i.e. the user didn't perform any mouse movement after pressing the mouse button). *node* is the being dragged. *e* is the grabbed event (should return the native event in a cross-browser manner). *eventInfo* is an object containing useful methods like *getPos* to get the mouse position relative to the canvas. + onTouchStart(node, eventInfo, e) - Behaves just like onDragStart. + onTouchMove(node, eventInfo, e) - Behaves just like onDragMove. + onTouchEnd(node, eventInfo, e) - Behaves just like onDragEnd. + onTouchCancel(node, eventInfo, e) - Behaves just like onDragCancel. + onMouseWheel(delta, e) - Triggered when the user uses the mouse scroll over the canvas. *delta* is 1 or -1 depending on the sense of the mouse scroll. +*/ + +Options.Events = { + $extend: false, + + enable: false, + enableForEdges: false, + type: 'auto', + onClick: $.empty, + onRightClick: $.empty, + onMouseMove: $.empty, + onMouseEnter: $.empty, + onMouseLeave: $.empty, + onDragStart: $.empty, + onDragMove: $.empty, + onDragCancel: $.empty, + onDragEnd: $.empty, + onTouchStart: $.empty, + onTouchMove: $.empty, + onTouchEnd: $.empty, + onMouseWheel: $.empty +}; + +/* + * File: Options.Navigation.js + * +*/ + +/* + Object: Options.Navigation + + Panning and zooming options for Graph/Tree based visualizations. These options are implemented + by all visualizations except charts (, and ). + + Syntax: + + (start code js) + + Options.Navigation = { + enable: false, + type: 'auto', + panning: false, //true, 'avoid nodes' + zooming: false + }; + + (end code) + + Example: + + (start code js) + var viz = new $jit.Viz({ + Navigation: { + enable: true, + panning: 'avoid nodes', + zooming: 20 + } + }); + (end code) + + Parameters: + + enable - (boolean) Default's *false*. Whether to enable Navigation capabilities. + panning - (boolean|string) Default's *false*. Set this property to *true* if you want to add Drag and Drop panning support to the visualization. You can also set this parameter to 'avoid nodes' to enable DnD panning but disable it if the DnD is taking place over a node. This is useful when some other events like Drag & Drop for nodes are added to . + zooming - (boolean|number) Default's *false*. Set this property to a numeric value to turn mouse-scroll zooming on. The number will be proportional to the mouse-scroll sensitivity. + +*/ + +Options.Navigation = { + $extend: false, + + enable: false, + type: 'auto', + panning: false, //true | 'avoid nodes' + zooming: false +}; + +/* + * File: Options.Controller.js + * +*/ + +/* + Object: Options.Controller + + Provides controller methods. Controller methods are callback functions that get called at different stages + of the animation, computing or plotting of the visualization. + + Implemented by: + + All visualizations except charts (, and ). + + Syntax: + + (start code js) + + Options.Controller = { + onBeforeCompute: $.empty, + onAfterCompute: $.empty, + onCreateLabel: $.empty, + onPlaceLabel: $.empty, + onComplete: $.empty, + onBeforePlotLine:$.empty, + onAfterPlotLine: $.empty, + onBeforePlotNode:$.empty, + onAfterPlotNode: $.empty, + request: false + }; + + (end code) + + Example: + + (start code js) + var viz = new $jit.Viz({ + onBeforePlotNode: function(node) { + if(node.selected) { + node.setData('color', '#ffc'); + } else { + node.removeData('color'); + } + }, + onBeforePlotLine: function(adj) { + if(adj.nodeFrom.selected && adj.nodeTo.selected) { + adj.setData('color', '#ffc'); + } else { + adj.removeData('color'); + } + }, + onAfterCompute: function() { + alert("computed!"); + } + }); + (end code) + + Parameters: + + onBeforeCompute(node) - This method is called right before performing all computations and animations. The selected is passed as parameter. + onAfterCompute() - This method is triggered after all animations or computations ended. + onCreateLabel(domElement, node) - This method receives a new label DIV element as first parameter, and the corresponding as second parameter. This method will only be called once for each label. This method is useful when adding events or styles to the labels used by the JIT. + onPlaceLabel(domElement, node) - This method receives a label DIV element as first parameter and the corresponding as second parameter. This method is called each time a label has been placed in the visualization, for example at each step of an animation, and thus it allows you to update the labels properties, such as size or position. Note that onPlaceLabel will be triggered after updating the labels positions. That means that, for example, the left and top css properties are already updated to match the nodes positions. Width and height properties are not set however. + onBeforePlotNode(node) - This method is triggered right before plotting each . This method is useful for changing a node style right before plotting it. + onAfterPlotNode(node) - This method is triggered right after plotting each . + onBeforePlotLine(adj) - This method is triggered right before plotting a . This method is useful for adding some styles to a particular edge before being plotted. + onAfterPlotLine(adj) - This method is triggered right after plotting a . + + *Used in , and visualizations* + + request(nodeId, level, onComplete) - This method is used for buffering information into the visualization. When clicking on an empty node, the visualization will make a request for this node's subtrees, specifying a given level for this subtree (defined by _levelsToShow_). Once the request is completed, the onComplete callback should be called with the given result. This is useful to provide on-demand information into the visualizations withought having to load the entire information from start. The parameters used by this method are _nodeId_, which is the id of the root of the subtree to request, _level_ which is the depth of the subtree to be requested (0 would mean just the root node). _onComplete_ is an object having the callback method _onComplete.onComplete(json)_ that should be called once the json has been retrieved. + + */ +Options.Controller = { + $extend: true, + + onBeforeCompute: $.empty, + onAfterCompute: $.empty, + onCreateLabel: $.empty, + onPlaceLabel: $.empty, + onComplete: $.empty, + onBeforePlotLine:$.empty, + onAfterPlotLine: $.empty, + onBeforePlotNode:$.empty, + onAfterPlotNode: $.empty, + request: false +}; + + +/* + * File: Extras.js + * + * Provides Extras such as Tips and Style Effects. + * + * Description: + * + * Provides the and classes and functions. + * + */ + +/* + * Manager for mouse events (clicking and mouse moving). + * + * This class is used for registering objects implementing onClick + * and onMousemove methods. These methods are called when clicking or + * moving the mouse around the Canvas. + * For now, and are classes implementing these methods. + * + */ +var ExtrasInitializer = { + initialize: function(className, viz) { + this.viz = viz; + this.canvas = viz.canvas; + this.config = viz.config[className]; + this.nodeTypes = viz.fx.nodeTypes; + var type = this.config.type; + this.dom = type == 'auto'? (viz.config.Label.type != 'Native') : (type != 'Native'); + this.labelContainer = this.dom && viz.labels.getLabelContainer(); + this.isEnabled() && this.initializePost(); + }, + initializePost: $.empty, + setAsProperty: $.lambda(false), + isEnabled: function() { + return this.config.enable; + }, + isLabel: function(e, win) { + e = $.event.get(e, win); + var labelContainer = this.labelContainer, + target = e.target || e.srcElement; + if(target && target.parentNode == labelContainer) + return target; + return false; + } +}; + +var EventsInterface = { + onMouseUp: $.empty, + onMouseDown: $.empty, + onMouseMove: $.empty, + onMouseOver: $.empty, + onMouseOut: $.empty, + onMouseWheel: $.empty, + onTouchStart: $.empty, + onTouchMove: $.empty, + onTouchEnd: $.empty, + onTouchCancel: $.empty +}; + +var MouseEventsManager = new Class({ + initialize: function(viz) { + this.viz = viz; + this.canvas = viz.canvas; + this.node = false; + this.edge = false; + this.registeredObjects = []; + this.attachEvents(); + }, + + attachEvents: function() { + var htmlCanvas = this.canvas.getElement(), + that = this; + htmlCanvas.oncontextmenu = $.lambda(false); + $.addEvents(htmlCanvas, { + 'mouseup': function(e, win) { + var event = $.event.get(e, win); + that.handleEvent('MouseUp', e, win, + that.makeEventObject(e, win), + $.event.isRightClick(event)); + }, + 'mousedown': function(e, win) { + var event = $.event.get(e, win); + that.handleEvent('MouseDown', e, win, that.makeEventObject(e, win), + $.event.isRightClick(event)); + }, + 'mousemove': function(e, win) { + that.handleEvent('MouseMove', e, win, that.makeEventObject(e, win)); + }, + 'mouseover': function(e, win) { + that.handleEvent('MouseOver', e, win, that.makeEventObject(e, win)); + }, + 'mouseout': function(e, win) { + that.handleEvent('MouseOut', e, win, that.makeEventObject(e, win)); + }, + 'touchstart': function(e, win) { + that.handleEvent('TouchStart', e, win, that.makeEventObject(e, win)); + }, + 'touchmove': function(e, win) { + that.handleEvent('TouchMove', e, win, that.makeEventObject(e, win)); + }, + 'touchend': function(e, win) { + that.handleEvent('TouchEnd', e, win, that.makeEventObject(e, win)); + } + }); + //attach mousewheel event + var handleMouseWheel = function(e, win) { + var event = $.event.get(e, win); + var wheel = $.event.getWheel(event); + that.handleEvent('MouseWheel', e, win, wheel); + }; + //TODO(nico): this is a horrible check for non-gecko browsers! + if(!document.getBoxObjectFor && window.mozInnerScreenX == null) { + $.addEvent(htmlCanvas, 'mousewheel', handleMouseWheel); + } else { + htmlCanvas.addEventListener('DOMMouseScroll', handleMouseWheel, false); + } + }, + + register: function(obj) { + this.registeredObjects.push(obj); + }, + + handleEvent: function() { + var args = Array.prototype.slice.call(arguments), + type = args.shift(); + for(var i=0, regs=this.registeredObjects, l=regs.length; i and implemented + * by all main visualizations. + * + */ +var Extras = { + initializeExtras: function() { + var mem = new MouseEventsManager(this), that = this; + $.each(['NodeStyles', 'Tips', 'Navigation', 'Events'], function(k) { + var obj = new Extras.Classes[k](k, that); + if(obj.isEnabled()) { + mem.register(obj); + } + if(obj.setAsProperty()) { + that[k.toLowerCase()] = obj; + } + }); + } +}; + +Extras.Classes = {}; +/* + Class: Events + + This class defines an Event API to be accessed by the user. + The methods implemented are the ones defined in the object. +*/ + +Extras.Classes.Events = new Class({ + Implements: [ExtrasInitializer, EventsInterface], + + initializePost: function() { + this.fx = this.viz.fx; + this.ntypes = this.viz.fx.nodeTypes; + this.etypes = this.viz.fx.edgeTypes; + + this.hovered = false; + this.pressed = false; + this.touched = false; + + this.touchMoved = false; + this.moved = false; + + }, + + setAsProperty: $.lambda(true), + + onMouseUp: function(e, win, event, isRightClick) { + var evt = $.event.get(e, win); + if(!this.moved) { + if(isRightClick) { + this.config.onRightClick(this.hovered, event, evt); + } else { + this.config.onClick(this.pressed, event, evt); + } + } + if(this.pressed) { + if(this.moved) { + this.config.onDragEnd(this.pressed, event, evt); + } else { + this.config.onDragCancel(this.pressed, event, evt); + } + this.pressed = this.moved = false; + } + }, + + onMouseOut: function(e, win, event) { + //mouseout a label + var evt = $.event.get(e, win), label; + if(this.dom && (label = this.isLabel(e, win))) { + this.config.onMouseLeave(this.viz.graph.getNode(label.id), + event, evt); + this.hovered = false; + return; + } + //mouseout canvas + var rt = evt.relatedTarget, + canvasWidget = this.canvas.getElement(); + while(rt && rt.parentNode) { + if(canvasWidget == rt.parentNode) return; + rt = rt.parentNode; + } + if(this.hovered) { + this.config.onMouseLeave(this.hovered, + event, evt); + this.hovered = false; + } + }, + + onMouseOver: function(e, win, event) { + //mouseover a label + var evt = $.event.get(e, win), label; + if(this.dom && (label = this.isLabel(e, win))) { + this.hovered = this.viz.graph.getNode(label.id); + this.config.onMouseEnter(this.hovered, + event, evt); + } + }, + + onMouseMove: function(e, win, event) { + var label, evt = $.event.get(e, win); + if(this.pressed) { + this.moved = true; + this.config.onDragMove(this.pressed, event, evt); + return; + } + if(this.dom) { + this.config.onMouseMove(this.hovered, + event, evt); + } else { + if(this.hovered) { + var hn = this.hovered; + var geom = hn.nodeFrom? this.etypes[hn.getData('type')] : this.ntypes[hn.getData('type')]; + var contains = geom && geom.contains + && geom.contains.call(this.fx, hn, event.getPos()); + if(contains) { + this.config.onMouseMove(hn, event, evt); + return; + } else { + this.config.onMouseLeave(hn, event, evt); + this.hovered = false; + } + } + if(this.hovered = (event.getNode() || (this.config.enableForEdges && event.getEdge()))) { + this.config.onMouseEnter(this.hovered, event, evt); + } else { + this.config.onMouseMove(false, event, evt); + } + } + }, + + onMouseWheel: function(e, win, delta) { + this.config.onMouseWheel(delta, $.event.get(e, win)); + }, + + onMouseDown: function(e, win, event) { + var evt = $.event.get(e, win); + this.pressed = event.getNode() || (this.config.enableForEdges && event.getEdge()); + this.config.onDragStart(this.pressed, event, evt); + }, + + onTouchStart: function(e, win, event) { + var evt = $.event.get(e, win); + this.touched = event.getNode() || (this.config.enableForEdges && event.getEdge()); + this.config.onTouchStart(this.touched, event, evt); + }, + + onTouchMove: function(e, win, event) { + var evt = $.event.get(e, win); + if(this.touched) { + this.touchMoved = true; + this.config.onTouchMove(this.touched, event, evt); + } + }, + + onTouchEnd: function(e, win, event) { + var evt = $.event.get(e, win); + if(this.touched) { + if(this.touchMoved) { + this.config.onTouchEnd(this.touched, event, evt); + } else { + this.config.onTouchCancel(this.touched, event, evt); + } + this.touched = this.touchMoved = false; + } + } +}); + +/* + Class: Tips + + A class containing tip related functions. This class is used internally. + + Used by: + + , , , , , , + + See also: + + +*/ + +Extras.Classes.Tips = new Class({ + Implements: [ExtrasInitializer, EventsInterface], + + initializePost: function() { + //add DOM tooltip + if(document.body) { + var tip = $('_tooltip') || document.createElement('div'); + tip.id = '_tooltip'; + tip.className = 'tip'; + $.extend(tip.style, { + position: 'absolute', + display: 'none', + zIndex: 13000 + }); + document.body.appendChild(tip); + this.tip = tip; + this.node = false; + } + }, + + setAsProperty: $.lambda(true), + + onMouseOut: function(e, win) { + //mouseout a label + if(this.dom && this.isLabel(e, win)) { + this.hide(true); + return; + } + //mouseout canvas + var rt = e.relatedTarget, + canvasWidget = this.canvas.getElement(); + while(rt && rt.parentNode) { + if(canvasWidget == rt.parentNode) return; + rt = rt.parentNode; + } + this.hide(false); + }, + + onMouseOver: function(e, win) { + //mouseover a label + var label; + if(this.dom && (label = this.isLabel(e, win))) { + this.node = this.viz.graph.getNode(label.id); + this.config.onShow(this.tip, this.node, label); + } + }, + + onMouseMove: function(e, win, opt) { + if(this.dom && this.isLabel(e, win)) { + this.setTooltipPosition($.event.getPos(e, win)); + } + if(!this.dom) { + var node = opt.getNode(); + if(!node) { + this.hide(true); + return; + } + if(this.config.force || !this.node || this.node.id != node.id) { + this.node = node; + this.config.onShow(this.tip, node, opt.getContains()); + } + this.setTooltipPosition($.event.getPos(e, win)); + } + }, + + setTooltipPosition: function(pos) { + var tip = this.tip, + style = tip.style, + cont = this.config; + style.display = ''; + //get window dimensions + var win = { + 'height': document.body.clientHeight, + 'width': document.body.clientWidth + }; + //get tooltip dimensions + var obj = { + 'width': tip.offsetWidth, + 'height': tip.offsetHeight + }; + //set tooltip position + var x = cont.offsetX, y = cont.offsetY; + style.top = ((pos.y + y + obj.height > win.height)? + (pos.y - obj.height - y) : pos.y + y) + 'px'; + style.left = ((pos.x + obj.width + x > win.width)? + (pos.x - obj.width - x) : pos.x + x) + 'px'; + }, + + hide: function(triggerCallback) { + if(!SUGAR.util.isTouchScreen()) { + this.tip.style.display = 'none'; + } + triggerCallback && this.config.onHide(); + } +}); + +/* + Class: NodeStyles + + Change node styles when clicking or hovering a node. This class is used internally. + + Used by: + + , , , , , , + + See also: + + +*/ +Extras.Classes.NodeStyles = new Class({ + Implements: [ExtrasInitializer, EventsInterface], + + initializePost: function() { + this.fx = this.viz.fx; + this.types = this.viz.fx.nodeTypes; + this.nStyles = this.config; + this.nodeStylesOnHover = this.nStyles.stylesHover; + this.nodeStylesOnClick = this.nStyles.stylesClick; + this.hoveredNode = false; + this.fx.nodeFxAnimation = new Animation(); + + this.down = false; + this.move = false; + }, + + onMouseOut: function(e, win) { + this.down = this.move = false; + if(!this.hoveredNode) return; + //mouseout a label + if(this.dom && this.isLabel(e, win)) { + this.toggleStylesOnHover(this.hoveredNode, false); + } + //mouseout canvas + var rt = e.relatedTarget, + canvasWidget = this.canvas.getElement(); + while(rt && rt.parentNode) { + if(canvasWidget == rt.parentNode) return; + rt = rt.parentNode; + } + this.toggleStylesOnHover(this.hoveredNode, false); + this.hoveredNode = false; + }, + + onMouseOver: function(e, win) { + //mouseover a label + var label; + if(this.dom && (label = this.isLabel(e, win))) { + var node = this.viz.graph.getNode(label.id); + if(node.selected) return; + this.hoveredNode = node; + this.toggleStylesOnHover(this.hoveredNode, true); + } + }, + + onMouseDown: function(e, win, event, isRightClick) { + if(isRightClick) return; + var label; + if(this.dom && (label = this.isLabel(e, win))) { + this.down = this.viz.graph.getNode(label.id); + } else if(!this.dom) { + this.down = event.getNode(); + } + this.move = false; + }, + + onMouseUp: function(e, win, event, isRightClick) { + if(isRightClick) return; + if(!this.move) { + this.onClick(event.getNode()); + } + this.down = this.move = false; + }, + + getRestoredStyles: function(node, type) { + var restoredStyles = {}, + nStyles = this['nodeStylesOn' + type]; + for(var prop in nStyles) { + restoredStyles[prop] = node.styles['$' + prop]; + } + return restoredStyles; + }, + + toggleStylesOnHover: function(node, set) { + if(this.nodeStylesOnHover) { + this.toggleStylesOn('Hover', node, set); + } + }, + + toggleStylesOnClick: function(node, set) { + if(this.nodeStylesOnClick) { + this.toggleStylesOn('Click', node, set); + } + }, + + toggleStylesOn: function(type, node, set) { + var viz = this.viz; + var nStyles = this.nStyles; + if(set) { + var that = this; + if(!node.styles) { + node.styles = $.merge(node.data, {}); + } + for(var s in this['nodeStylesOn' + type]) { + var $s = '$' + s; + if(!($s in node.styles)) { + node.styles[$s] = node.getData(s); + } + } + viz.fx.nodeFx($.extend({ + 'elements': { + 'id': node.id, + 'properties': that['nodeStylesOn' + type] + }, + transition: Trans.Quart.easeOut, + duration:300, + fps:40 + }, this.config)); + } else { + var restoredStyles = this.getRestoredStyles(node, type); + viz.fx.nodeFx($.extend({ + 'elements': { + 'id': node.id, + 'properties': restoredStyles + }, + transition: Trans.Quart.easeOut, + duration:300, + fps:40 + }, this.config)); + } + }, + + onClick: function(node) { + if(!node) return; + var nStyles = this.nodeStylesOnClick; + if(!nStyles) return; + //if the node is selected then unselect it + if(node.selected) { + this.toggleStylesOnClick(node, false); + delete node.selected; + } else { + //unselect all selected nodes... + this.viz.graph.eachNode(function(n) { + if(n.selected) { + for(var s in nStyles) { + n.setData(s, n.styles['$' + s], 'end'); + } + delete n.selected; + } + }); + //select clicked node + this.toggleStylesOnClick(node, true); + node.selected = true; + delete node.hovered; + this.hoveredNode = false; + } + }, + + onMouseMove: function(e, win, event) { + //if mouse button is down and moving set move=true + if(this.down) this.move = true; + //already handled by mouseover/out + if(this.dom && this.isLabel(e, win)) return; + var nStyles = this.nodeStylesOnHover; + if(!nStyles) return; + + if(!this.dom) { + if(this.hoveredNode) { + var geom = this.types[this.hoveredNode.getData('type')]; + var contains = geom && geom.contains && geom.contains.call(this.fx, + this.hoveredNode, event.getPos()); + if(contains) return; + } + var node = event.getNode(); + //if no node is being hovered then just exit + if(!this.hoveredNode && !node) return; + //if the node is hovered then exit + if(node.hovered) return; + //select hovered node + if(node && !node.selected) { + //check if an animation is running and exit it + this.fx.nodeFxAnimation.stopTimer(); + //unselect all hovered nodes... + this.viz.graph.eachNode(function(n) { + if(n.hovered && !n.selected) { + for(var s in nStyles) { + n.setData(s, n.styles['$' + s], 'end'); + } + delete n.hovered; + } + }); + //select hovered node + node.hovered = true; + this.hoveredNode = node; + this.toggleStylesOnHover(node, true); + } else if(this.hoveredNode && !this.hoveredNode.selected) { + //check if an animation is running and exit it + this.fx.nodeFxAnimation.stopTimer(); + //unselect hovered node + this.toggleStylesOnHover(this.hoveredNode, false); + delete this.hoveredNode.hovered; + this.hoveredNode = false; + } + } + } +}); + +Extras.Classes.Navigation = new Class({ + Implements: [ExtrasInitializer, EventsInterface], + + initializePost: function() { + this.pos = false; + this.pressed = false; + }, + + onMouseWheel: function(e, win, scroll) { + if(!this.config.zooming) return; + $.event.stop($.event.get(e, win)); + var val = this.config.zooming / 1000, + ans = 1 + scroll * val; + this.canvas.scale(ans, ans); + }, + + onMouseDown: function(e, win, eventInfo) { + if(!this.config.panning) return; + if(this.config.panning == 'avoid nodes' && eventInfo.getNode()) return; + this.pressed = true; + this.pos = eventInfo.getPos(); + var canvas = this.canvas, + ox = canvas.translateOffsetX, + oy = canvas.translateOffsetY, + sx = canvas.scaleOffsetX, + sy = canvas.scaleOffsetY; + this.pos.x *= sx; + this.pos.x += ox; + this.pos.y *= sy; + this.pos.y += oy; + }, + + onMouseMove: function(e, win, eventInfo) { + if(!this.config.panning) return; + if(!this.pressed) return; + if(this.config.panning == 'avoid nodes' && eventInfo.getNode()) return; + var thispos = this.pos, + currentPos = eventInfo.getPos(), + canvas = this.canvas, + ox = canvas.translateOffsetX, + oy = canvas.translateOffsetY, + sx = canvas.scaleOffsetX, + sy = canvas.scaleOffsetY; + currentPos.x *= sx; + currentPos.y *= sy; + currentPos.x += ox; + currentPos.y += oy; + var x = currentPos.x - thispos.x, + y = currentPos.y - thispos.y; + this.pos = currentPos; + this.canvas.translate(x * 1/sx, y * 1/sy); + }, + + onMouseUp: function(e, win, eventInfo, isRightClick) { + if(!this.config.panning) return; + this.pressed = false; + } +}); + + +/* + * File: Canvas.js + * + */ + +/* + Class: Canvas + + A canvas widget used by all visualizations. The canvas object can be accessed by doing *viz.canvas*. If you want to + know more about options take a look at . + + A canvas widget is a set of DOM elements that wrap the native canvas DOM Element providing a consistent API and behavior + across all browsers. It can also include Elements to add DOM (SVG or HTML) label support to all visualizations. + + Example: + + Suppose we have this HTML + + (start code xml) +
            + (end code) + + Now we create a new Visualization + + (start code js) + var viz = new $jit.Viz({ + //Where to inject the canvas. Any div container will do. + 'injectInto':'infovis', + //width and height for canvas. + //Default's to the container offsetWidth and Height. + 'width': 900, + 'height':500 + }); + (end code) + + The generated HTML will look like this + + (start code xml) +
            +
            + +
            +
            +
            +
            + (end code) + + As you can see, the generated HTML consists of a canvas DOM Element of id *infovis-canvas* and a div label container + of id *infovis-label*, wrapped in a main div container of id *infovis-canvaswidget*. + */ + +var Canvas; +(function() { + //check for native canvas support + var canvasType = typeof HTMLCanvasElement, + supportsCanvas = (canvasType == 'object' || canvasType == 'function'); + //create element function + function $E(tag, props) { + var elem = document.createElement(tag); + for(var p in props) { + if(typeof props[p] == "object") { + $.extend(elem[p], props[p]); + } else { + elem[p] = props[p]; + } + } + if (tag == "canvas" && !supportsCanvas && G_vmlCanvasManager) { + elem = G_vmlCanvasManager.initElement(elem); + } + return elem; + } + //canvas widget which we will call just Canvas + $jit.Canvas = Canvas = new Class({ + canvases: [], + pos: false, + element: false, + labelContainer: false, + translateOffsetX: 0, + translateOffsetY: 0, + scaleOffsetX: 1, + scaleOffsetY: 1, + + initialize: function(viz, opt) { + this.viz = viz; + this.opt = opt; + var id = $.type(opt.injectInto) == 'string'? + opt.injectInto:opt.injectInto.id, + idLabel = id + "-label", + wrapper = $(id), + width = opt.width || wrapper.offsetWidth, + height = opt.height || wrapper.offsetHeight; + this.id = id; + //canvas options + var canvasOptions = { + injectInto: id, + width: width, + height: height + }; + //create main wrapper + this.element = $E('div', { + 'id': id + '-canvaswidget', + 'style': { + 'position': 'relative', + 'width': width + 'px', + 'height': height + 'px' + } + }); + //create label container + this.labelContainer = this.createLabelContainer(opt.Label.type, + idLabel, canvasOptions); + //create primary canvas + this.canvases.push(new Canvas.Base({ + config: $.extend({idSuffix: '-canvas'}, canvasOptions), + plot: function(base) { + viz.fx.plot(); + }, + resize: function() { + viz.refresh(); + } + })); + //create secondary canvas + var back = opt.background; + if(back) { + var backCanvas = new Canvas.Background[back.type](viz, $.extend(back, canvasOptions)); + this.canvases.push(new Canvas.Base(backCanvas)); + } + //insert canvases + var len = this.canvases.length; + while(len--) { + this.element.appendChild(this.canvases[len].canvas); + if(len > 0) { + this.canvases[len].plot(); + } + } + this.element.appendChild(this.labelContainer); + wrapper.appendChild(this.element); + //Update canvas position when the page is scrolled. + var timer = null, that = this; + $.addEvent(window, 'scroll', function() { + clearTimeout(timer); + timer = setTimeout(function() { + that.getPos(true); //update canvas position + }, 500); + }); + $.addEvent(window, 'click', function() { + clearTimeout(timer); + timer = setTimeout(function() { + that.getPos(true); //update canvas position + }, 500); + }); + sb = document.getElementById('sb'+id); + $.addEvent(sb, 'scroll', function() { + clearTimeout(timer); + timer = setTimeout(function() { + that.getPos(true); //update canvas position + }, 500); + }); + }, + /* + Method: getCtx + + Returns the main canvas context object + + Example: + + (start code js) + var ctx = canvas.getCtx(); + //Now I can use the native canvas context + //and for example change some canvas styles + ctx.globalAlpha = 1; + (end code) + */ + getCtx: function(i) { + return this.canvases[i || 0].getCtx(); + }, + /* + Method: getConfig + + Returns the current Configuration for this Canvas Widget. + + Example: + + (start code js) + var config = canvas.getConfig(); + (end code) + */ + getConfig: function() { + return this.opt; + }, + /* + Method: getElement + + Returns the main Canvas DOM wrapper + + Example: + + (start code js) + var wrapper = canvas.getElement(); + //Returns
            ...
            as element + (end code) + */ + getElement: function() { + return this.element; + }, + /* + Method: getSize + + Returns canvas dimensions. + + Returns: + + An object with *width* and *height* properties. + + Example: + (start code js) + canvas.getSize(); //returns { width: 900, height: 500 } + (end code) + */ + getSize: function(i) { + return this.canvases[i || 0].getSize(); + }, + /* + Method: resize + + Resizes the canvas. + + Parameters: + + width - New canvas width. + height - New canvas height. + + Example: + + (start code js) + canvas.resize(width, height); + (end code) + + */ + resize: function(width, height) { + this.getPos(true); + this.translateOffsetX = this.translateOffsetY = 0; + this.scaleOffsetX = this.scaleOffsetY = 1; + for(var i=0, l=this.canvases.length; i class. + * + * Description: + * + * The class, just like the class, is used by the , and as a 2D point representation. + * + * See also: + * + * + * +*/ + +/* + Class: Polar + + A multi purpose polar representation. + + Description: + + The class, just like the class, is used by the , and as a 2D point representation. + + See also: + + + + Parameters: + + theta - An angle. + rho - The norm. +*/ + +var Polar = function(theta, rho) { + this.theta = theta; + this.rho = rho; +}; + +$jit.Polar = Polar; + +Polar.prototype = { + /* + Method: getc + + Returns a complex number. + + Parameters: + + simple - _optional_ If *true*, this method will return only an object holding x and y properties and not a instance. Default's *false*. + + Returns: + + A complex number. + */ + getc: function(simple) { + return this.toComplex(simple); + }, + + /* + Method: getp + + Returns a representation. + + Returns: + + A variable in polar coordinates. + */ + getp: function() { + return this; + }, + + + /* + Method: set + + Sets a number. + + Parameters: + + v - A or instance. + + */ + set: function(v) { + v = v.getp(); + this.theta = v.theta; this.rho = v.rho; + }, + + /* + Method: setc + + Sets a number. + + Parameters: + + x - A number real part. + y - A number imaginary part. + + */ + setc: function(x, y) { + this.rho = Math.sqrt(x * x + y * y); + this.theta = Math.atan2(y, x); + if(this.theta < 0) this.theta += Math.PI * 2; + }, + + /* + Method: setp + + Sets a polar number. + + Parameters: + + theta - A number angle property. + rho - A number rho property. + + */ + setp: function(theta, rho) { + this.theta = theta; + this.rho = rho; + }, + + /* + Method: clone + + Returns a copy of the current object. + + Returns: + + A copy of the real object. + */ + clone: function() { + return new Polar(this.theta, this.rho); + }, + + /* + Method: toComplex + + Translates from polar to cartesian coordinates and returns a new instance. + + Parameters: + + simple - _optional_ If *true* this method will only return an object with x and y properties (and not the whole instance). Default's *false*. + + Returns: + + A new instance. + */ + toComplex: function(simple) { + var x = Math.cos(this.theta) * this.rho; + var y = Math.sin(this.theta) * this.rho; + if(simple) return { 'x': x, 'y': y}; + return new Complex(x, y); + }, + + /* + Method: add + + Adds two instances. + + Parameters: + + polar - A number. + + Returns: + + A new Polar instance. + */ + add: function(polar) { + return new Polar(this.theta + polar.theta, this.rho + polar.rho); + }, + + /* + Method: scale + + Scales a polar norm. + + Parameters: + + number - A scale factor. + + Returns: + + A new Polar instance. + */ + scale: function(number) { + return new Polar(this.theta, this.rho * number); + }, + + /* + Method: equals + + Comparison method. + + Returns *true* if the theta and rho properties are equal. + + Parameters: + + c - A number. + + Returns: + + *true* if the theta and rho parameters for these objects are equal. *false* otherwise. + */ + equals: function(c) { + return this.theta == c.theta && this.rho == c.rho; + }, + + /* + Method: $add + + Adds two instances affecting the current object. + + Paramters: + + polar - A instance. + + Returns: + + The changed object. + */ + $add: function(polar) { + this.theta = this.theta + polar.theta; this.rho += polar.rho; + return this; + }, + + /* + Method: $madd + + Adds two instances affecting the current object. The resulting theta angle is modulo 2pi. + + Parameters: + + polar - A instance. + + Returns: + + The changed object. + */ + $madd: function(polar) { + this.theta = (this.theta + polar.theta) % (Math.PI * 2); this.rho += polar.rho; + return this; + }, + + + /* + Method: $scale + + Scales a polar instance affecting the object. + + Parameters: + + number - A scaling factor. + + Returns: + + The changed object. + */ + $scale: function(number) { + this.rho *= number; + return this; + }, + + /* + Method: interpolate + + Calculates a polar interpolation between two points at a given delta moment. + + Parameters: + + elem - A instance. + delta - A delta factor ranging [0, 1]. + + Returns: + + A new instance representing an interpolation between _this_ and _elem_ + */ + interpolate: function(elem, delta) { + var pi = Math.PI, pi2 = pi * 2; + var ch = function(t) { + var a = (t < 0)? (t % pi2) + pi2 : t % pi2; + return a; + }; + var tt = this.theta, et = elem.theta; + var sum, diff = Math.abs(tt - et); + if(diff == pi) { + if(tt > et) { + sum = ch((et + ((tt - pi2) - et) * delta)) ; + } else { + sum = ch((et - pi2 + (tt - (et)) * delta)); + } + } else if(diff >= pi) { + if(tt > et) { + sum = ch((et + ((tt - pi2) - et) * delta)) ; + } else { + sum = ch((et - pi2 + (tt - (et - pi2)) * delta)); + } + } else { + sum = ch((et + (tt - et) * delta)) ; + } + var r = (this.rho - elem.rho) * delta + elem.rho; + return { + 'theta': sum, + 'rho': r + }; + } +}; + + +var $P = function(a, b) { return new Polar(a, b); }; + +Polar.KER = $P(0, 0); + + + +/* + * File: Complex.js + * + * Defines the class. + * + * Description: + * + * The class, just like the class, is used by the , and as a 2D point representation. + * + * See also: + * + * + * +*/ + +/* + Class: Complex + + A multi-purpose Complex Class with common methods. + + Description: + + The class, just like the class, is used by the , and as a 2D point representation. + + See also: + + + + Parameters: + + x - _optional_ A Complex number real part. + y - _optional_ A Complex number imaginary part. + +*/ + +var Complex = function(x, y) { + this.x = x; + this.y = y; +}; + +$jit.Complex = Complex; + +Complex.prototype = { + /* + Method: getc + + Returns a complex number. + + Returns: + + A complex number. + */ + getc: function() { + return this; + }, + + /* + Method: getp + + Returns a representation of this number. + + Parameters: + + simple - _optional_ If *true*, this method will return only an object holding theta and rho properties and not a instance. Default's *false*. + + Returns: + + A variable in coordinates. + */ + getp: function(simple) { + return this.toPolar(simple); + }, + + + /* + Method: set + + Sets a number. + + Parameters: + + c - A or instance. + + */ + set: function(c) { + c = c.getc(true); + this.x = c.x; + this.y = c.y; + }, + + /* + Method: setc + + Sets a complex number. + + Parameters: + + x - A number Real part. + y - A number Imaginary part. + + */ + setc: function(x, y) { + this.x = x; + this.y = y; + }, + + /* + Method: setp + + Sets a polar number. + + Parameters: + + theta - A number theta property. + rho - A number rho property. + + */ + setp: function(theta, rho) { + this.x = Math.cos(theta) * rho; + this.y = Math.sin(theta) * rho; + }, + + /* + Method: clone + + Returns a copy of the current object. + + Returns: + + A copy of the real object. + */ + clone: function() { + return new Complex(this.x, this.y); + }, + + /* + Method: toPolar + + Transforms cartesian to polar coordinates. + + Parameters: + + simple - _optional_ If *true* this method will only return an object with theta and rho properties (and not the whole instance). Default's *false*. + + Returns: + + A new instance. + */ + + toPolar: function(simple) { + var rho = this.norm(); + var atan = Math.atan2(this.y, this.x); + if(atan < 0) atan += Math.PI * 2; + if(simple) return { 'theta': atan, 'rho': rho }; + return new Polar(atan, rho); + }, + /* + Method: norm + + Calculates a number norm. + + Returns: + + A real number representing the complex norm. + */ + norm: function () { + return Math.sqrt(this.squaredNorm()); + }, + + /* + Method: squaredNorm + + Calculates a number squared norm. + + Returns: + + A real number representing the complex squared norm. + */ + squaredNorm: function () { + return this.x*this.x + this.y*this.y; + }, + + /* + Method: add + + Returns the result of adding two complex numbers. + + Does not alter the original object. + + Parameters: + + pos - A instance. + + Returns: + + The result of adding two complex numbers. + */ + add: function(pos) { + return new Complex(this.x + pos.x, this.y + pos.y); + }, + + /* + Method: prod + + Returns the result of multiplying two numbers. + + Does not alter the original object. + + Parameters: + + pos - A instance. + + Returns: + + The result of multiplying two complex numbers. + */ + prod: function(pos) { + return new Complex(this.x*pos.x - this.y*pos.y, this.y*pos.x + this.x*pos.y); + }, + + /* + Method: conjugate + + Returns the conjugate of this number. + + Does not alter the original object. + + Returns: + + The conjugate of this number. + */ + conjugate: function() { + return new Complex(this.x, -this.y); + }, + + + /* + Method: scale + + Returns the result of scaling a instance. + + Does not alter the original object. + + Parameters: + + factor - A scale factor. + + Returns: + + The result of scaling this complex to a factor. + */ + scale: function(factor) { + return new Complex(this.x * factor, this.y * factor); + }, + + /* + Method: equals + + Comparison method. + + Returns *true* if both real and imaginary parts are equal. + + Parameters: + + c - A instance. + + Returns: + + A boolean instance indicating if both numbers are equal. + */ + equals: function(c) { + return this.x == c.x && this.y == c.y; + }, + + /* + Method: $add + + Returns the result of adding two numbers. + + Alters the original object. + + Parameters: + + pos - A instance. + + Returns: + + The result of adding two complex numbers. + */ + $add: function(pos) { + this.x += pos.x; this.y += pos.y; + return this; + }, + + /* + Method: $prod + + Returns the result of multiplying two numbers. + + Alters the original object. + + Parameters: + + pos - A instance. + + Returns: + + The result of multiplying two complex numbers. + */ + $prod:function(pos) { + var x = this.x, y = this.y; + this.x = x*pos.x - y*pos.y; + this.y = y*pos.x + x*pos.y; + return this; + }, + + /* + Method: $conjugate + + Returns the conjugate for this . + + Alters the original object. + + Returns: + + The conjugate for this complex. + */ + $conjugate: function() { + this.y = -this.y; + return this; + }, + + /* + Method: $scale + + Returns the result of scaling a instance. + + Alters the original object. + + Parameters: + + factor - A scale factor. + + Returns: + + The result of scaling this complex to a factor. + */ + $scale: function(factor) { + this.x *= factor; this.y *= factor; + return this; + }, + + /* + Method: $div + + Returns the division of two numbers. + + Alters the original object. + + Parameters: + + pos - A number. + + Returns: + + The result of scaling this complex to a factor. + */ + $div: function(pos) { + var x = this.x, y = this.y; + var sq = pos.squaredNorm(); + this.x = x * pos.x + y * pos.y; this.y = y * pos.x - x * pos.y; + return this.$scale(1 / sq); + } +}; + +var $C = function(a, b) { return new Complex(a, b); }; + +Complex.KER = $C(0, 0); + + + +/* + * File: Graph.js + * +*/ + +/* + Class: Graph + + A Graph Class that provides useful manipulation functions. You can find more manipulation methods in the object. + + An instance of this class can be accessed by using the *graph* parameter of any tree or graph visualization. + + Example: + + (start code js) + //create new visualization + var viz = new $jit.Viz(options); + //load JSON data + viz.loadJSON(json); + //access model + viz.graph; // instance + (end code) + + Implements: + + The following methods are implemented in + + - + - + - + - + - + - + - + +*/ + +$jit.Graph = new Class({ + + initialize: function(opt, Node, Edge, Label) { + var innerOptions = { + 'complex': false, + 'Node': {} + }; + this.Node = Node; + this.Edge = Edge; + this.Label = Label; + this.opt = $.merge(innerOptions, opt || {}); + this.nodes = {}; + this.edges = {}; + + //add nodeList methods + var that = this; + this.nodeList = {}; + for(var p in Accessors) { + that.nodeList[p] = (function(p) { + return function() { + var args = Array.prototype.slice.call(arguments); + that.eachNode(function(n) { + n[p].apply(n, args); + }); + }; + })(p); + } + + }, + +/* + Method: getNode + + Returns a by *id*. + + Parameters: + + id - (string) A id. + + Example: + + (start code js) + var node = graph.getNode('nodeId'); + (end code) +*/ + getNode: function(id) { + if(this.hasNode(id)) return this.nodes[id]; + return false; + }, + + /* + Method: getByName + + Returns a by *name*. + + Parameters: + + name - (string) A name. + + Example: + + (start code js) + var node = graph.getByName('someName'); + (end code) + */ + getByName: function(name) { + for(var id in this.nodes) { + var n = this.nodes[id]; + if(n.name == name) return n; + } + return false; + }, + +/* + Method: getAdjacence + + Returns a object connecting nodes with ids *id* and *id2*. + + Parameters: + + id - (string) A id. + id2 - (string) A id. +*/ + getAdjacence: function (id, id2) { + if(id in this.edges) { + return this.edges[id][id2]; + } + return false; + }, + + /* + Method: addNode + + Adds a node. + + Parameters: + + obj - An object with the properties described below + + id - (string) A node id + name - (string) A node's name + data - (object) A node's data hash + + See also: + + + */ + addNode: function(obj) { + if(!this.nodes[obj.id]) { + var edges = this.edges[obj.id] = {}; + this.nodes[obj.id] = new Graph.Node($.extend({ + 'id': obj.id, + 'name': obj.name, + 'data': $.merge(obj.data || {}, {}), + 'adjacencies': edges + }, this.opt.Node), + this.opt.complex, + this.Node, + this.Edge, + this.Label); + } + return this.nodes[obj.id]; + }, + + /* + Method: addAdjacence + + Connects nodes specified by *obj* and *obj2*. If not found, nodes are created. + + Parameters: + + obj - (object) A object. + obj2 - (object) Another object. + data - (object) A data object. Used to store some extra information in the object created. + + See also: + + , + */ + addAdjacence: function (obj, obj2, data) { + if(!this.hasNode(obj.id)) { this.addNode(obj); } + if(!this.hasNode(obj2.id)) { this.addNode(obj2); } + obj = this.nodes[obj.id]; obj2 = this.nodes[obj2.id]; + if(!obj.adjacentTo(obj2)) { + var adjsObj = this.edges[obj.id] = this.edges[obj.id] || {}; + var adjsObj2 = this.edges[obj2.id] = this.edges[obj2.id] || {}; + adjsObj[obj2.id] = adjsObj2[obj.id] = new Graph.Adjacence(obj, obj2, data, this.Edge, this.Label); + return adjsObj[obj2.id]; + } + return this.edges[obj.id][obj2.id]; + }, + + /* + Method: removeNode + + Removes a matching the specified *id*. + + Parameters: + + id - (string) A node's id. + + */ + removeNode: function(id) { + if(this.hasNode(id)) { + delete this.nodes[id]; + var adjs = this.edges[id]; + for(var to in adjs) { + delete this.edges[to][id]; + } + delete this.edges[id]; + } + }, + +/* + Method: removeAdjacence + + Removes a matching *id1* and *id2*. + + Parameters: + + id1 - (string) A id. + id2 - (string) A id. +*/ + removeAdjacence: function(id1, id2) { + delete this.edges[id1][id2]; + delete this.edges[id2][id1]; + }, + + /* + Method: hasNode + + Returns a boolean indicating if the node belongs to the or not. + + Parameters: + + id - (string) Node id. + */ + hasNode: function(id) { + return id in this.nodes; + }, + + /* + Method: empty + + Empties the Graph + + */ + empty: function() { this.nodes = {}; this.edges = {};} + +}); + +var Graph = $jit.Graph; + +/* + Object: Accessors + + Defines a set of methods for data, canvas and label styles manipulation implemented by and instances. + + */ +var Accessors; + +(function () { + var getDataInternal = function(prefix, prop, type, force, prefixConfig) { + var data; + type = type || 'current'; + prefix = "$" + (prefix ? prefix + "-" : ""); + + if(type == 'current') { + data = this.data; + } else if(type == 'start') { + data = this.startData; + } else if(type == 'end') { + data = this.endData; + } + + var dollar = prefix + prop; + + if(force) { + return data[dollar]; + } + + if(!this.Config.overridable) + return prefixConfig[prop] || 0; + + return (dollar in data) ? + data[dollar] : ((dollar in this.data) ? this.data[dollar] : (prefixConfig[prop] || 0)); + } + + var setDataInternal = function(prefix, prop, value, type) { + type = type || 'current'; + prefix = '$' + (prefix ? prefix + '-' : ''); + + var data; + + if(type == 'current') { + data = this.data; + } else if(type == 'start') { + data = this.startData; + } else if(type == 'end') { + data = this.endData; + } + + data[prefix + prop] = value; + } + + var removeDataInternal = function(prefix, properties) { + prefix = '$' + (prefix ? prefix + '-' : ''); + var that = this; + $.each(properties, function(prop) { + var pref = prefix + prop; + delete that.data[pref]; + delete that.endData[pref]; + delete that.startData[pref]; + }); + } + + Accessors = { + /* + Method: getData + + Returns the specified data value property. + This is useful for querying special/reserved data properties + (i.e dollar prefixed properties). + + Parameters: + + prop - (string) The name of the property. The dollar sign is not needed. For + example *getData(width)* will return *data.$width*. + type - (string) The type of the data property queried. Default's "current". You can access *start* and *end* + data properties also. These properties are used when making animations. + force - (boolean) Whether to obtain the true value of the property (equivalent to + *data.$prop*) or to check for *node.overridable = true* first. + + Returns: + + The value of the dollar prefixed property or the global Node/Edge property + value if *overridable=false* + + Example: + (start code js) + node.getData('width'); //will return node.data.$width if Node.overridable=true; + (end code) + */ + getData: function(prop, type, force) { + return getDataInternal.call(this, "", prop, type, force, this.Config); + }, + + + /* + Method: setData + + Sets the current data property with some specific value. + This method is only useful for reserved (dollar prefixed) properties. + + Parameters: + + prop - (string) The name of the property. The dollar sign is not necessary. For + example *setData(width)* will set *data.$width*. + value - (mixed) The value to store. + type - (string) The type of the data property to store. Default's "current" but + can also be "start" or "end". + + Example: + + (start code js) + node.setData('width', 30); + (end code) + + If we were to make an animation of a node/edge width then we could do + + (start code js) + var node = viz.getNode('nodeId'); + //set start and end values + node.setData('width', 10, 'start'); + node.setData('width', 30, 'end'); + //will animate nodes width property + viz.fx.animate({ + modes: ['node-property:width'], + duration: 1000 + }); + (end code) + */ + setData: function(prop, value, type) { + setDataInternal.call(this, "", prop, value, type); + }, + + /* + Method: setDataset + + Convenience method to set multiple data values at once. + + Parameters: + + types - (array|string) A set of 'current', 'end' or 'start' values. + obj - (object) A hash containing the names and values of the properties to be altered. + + Example: + (start code js) + node.setDataset(['current', 'end'], { + 'width': [100, 5], + 'color': ['#fff', '#ccc'] + }); + //...or also + node.setDataset('end', { + 'width': 5, + 'color': '#ccc' + }); + (end code) + + See also: + + + + */ + setDataset: function(types, obj) { + types = $.splat(types); + for(var attr in obj) { + for(var i=0, val = $.splat(obj[attr]), l=types.length; i canvas style data properties (i.e. + dollar prefixed properties that match with $canvas-). + + Parameters: + + prop - (string) The name of the property. The dollar sign is not needed. For + example *getCanvasStyle(shadowBlur)* will return *data[$canvas-shadowBlur]*. + type - (string) The type of the data property queried. Default's *current*. You can access *start* and *end* + data properties also. + + Example: + (start code js) + node.getCanvasStyle('shadowBlur'); + (end code) + + See also: + + + */ + getCanvasStyle: function(prop, type, force) { + return getDataInternal.call( + this, 'canvas', prop, type, force, this.Config.CanvasStyles); + }, + + /* + Method: setCanvasStyle + + Sets the canvas style data property with some specific value. + This method is only useful for reserved (dollar prefixed) properties. + + Parameters: + + prop - (string) Name of the property. Can be any canvas property like 'shadowBlur', 'shadowColor', 'strokeStyle', etc. + value - (mixed) The value to set to the property. + type - (string) Default's *current*. Whether to set *start*, *current* or *end* type properties. + + Example: + + (start code js) + node.setCanvasStyle('shadowBlur', 30); + (end code) + + If we were to make an animation of a node/edge shadowBlur canvas style then we could do + + (start code js) + var node = viz.getNode('nodeId'); + //set start and end values + node.setCanvasStyle('shadowBlur', 10, 'start'); + node.setCanvasStyle('shadowBlur', 30, 'end'); + //will animate nodes canvas style property for nodes + viz.fx.animate({ + modes: ['node-style:shadowBlur'], + duration: 1000 + }); + (end code) + + See also: + + . + */ + setCanvasStyle: function(prop, value, type) { + setDataInternal.call(this, 'canvas', prop, value, type); + }, + + /* + Method: setCanvasStyles + + Convenience method to set multiple styles at once. + + Parameters: + + types - (array|string) A set of 'current', 'end' or 'start' values. + obj - (object) A hash containing the names and values of the properties to be altered. + + See also: + + . + */ + setCanvasStyles: function(types, obj) { + types = $.splat(types); + for(var attr in obj) { + for(var i=0, val = $.splat(obj[attr]), l=types.length; i. + */ + removeCanvasStyle: function() { + removeDataInternal.call(this, 'canvas', Array.prototype.slice.call(arguments)); + }, + + /* + Method: getLabelData + + Returns the specified label data value property. This is useful for + querying special/reserved label options (i.e. + dollar prefixed properties that match with $label-). + + Parameters: + + prop - (string) The name of the property. The dollar sign prefix is not needed. For + example *getLabelData(size)* will return *data[$label-size]*. + type - (string) The type of the data property queried. Default's *current*. You can access *start* and *end* + data properties also. + + See also: + + . + */ + getLabelData: function(prop, type, force) { + return getDataInternal.call( + this, 'label', prop, type, force, this.Label); + }, + + /* + Method: setLabelData + + Sets the current label data with some specific value. + This method is only useful for reserved (dollar prefixed) properties. + + Parameters: + + prop - (string) Name of the property. Can be any canvas property like 'shadowBlur', 'shadowColor', 'strokeStyle', etc. + value - (mixed) The value to set to the property. + type - (string) Default's *current*. Whether to set *start*, *current* or *end* type properties. + + Example: + + (start code js) + node.setLabelData('size', 30); + (end code) + + If we were to make an animation of a node label size then we could do + + (start code js) + var node = viz.getNode('nodeId'); + //set start and end values + node.setLabelData('size', 10, 'start'); + node.setLabelData('size', 30, 'end'); + //will animate nodes label size + viz.fx.animate({ + modes: ['label-property:size'], + duration: 1000 + }); + (end code) + + See also: + + . + */ + setLabelData: function(prop, value, type) { + setDataInternal.call(this, 'label', prop, value, type); + }, + + /* + Method: setLabelDataset + + Convenience function to set multiple label data at once. + + Parameters: + + types - (array|string) A set of 'current', 'end' or 'start' values. + obj - (object) A hash containing the names and values of the properties to be altered. + + See also: + + . + */ + setLabelDataset: function(types, obj) { + types = $.splat(types); + for(var attr in obj) { + for(var i=0, val = $.splat(obj[attr]), l=types.length; i. + */ + removeLabelData: function() { + removeDataInternal.call(this, 'label', Array.prototype.slice.call(arguments)); + } + }; +})(); + +/* + Class: Graph.Node + + A node. + + Implements: + + methods. + + The following methods are implemented by + + - + - + - + - + - + - + - + - +*/ +Graph.Node = new Class({ + + initialize: function(opt, complex, Node, Edge, Label) { + var innerOptions = { + 'id': '', + 'name': '', + 'data': {}, + 'startData': {}, + 'endData': {}, + 'adjacencies': {}, + + 'selected': false, + 'drawn': false, + 'exist': false, + + 'angleSpan': { + 'begin': 0, + 'end' : 0 + }, + + 'pos': (complex && $C(0, 0)) || $P(0, 0), + 'startPos': (complex && $C(0, 0)) || $P(0, 0), + 'endPos': (complex && $C(0, 0)) || $P(0, 0) + }; + + $.extend(this, $.extend(innerOptions, opt)); + this.Config = this.Node = Node; + this.Edge = Edge; + this.Label = Label; + }, + + /* + Method: adjacentTo + + Indicates if the node is adjacent to the node specified by id + + Parameters: + + id - (string) A node id. + + Example: + (start code js) + node.adjacentTo('nodeId') == true; + (end code) + */ + adjacentTo: function(node) { + return node.id in this.adjacencies; + }, + + /* + Method: getAdjacency + + Returns a object connecting the current and the node having *id* as id. + + Parameters: + + id - (string) A node id. + */ + getAdjacency: function(id) { + return this.adjacencies[id]; + }, + + /* + Method: getPos + + Returns the position of the node. + + Parameters: + + type - (string) Default's *current*. Possible values are "start", "end" or "current". + + Returns: + + A or instance. + + Example: + (start code js) + var pos = node.getPos('end'); + (end code) + */ + getPos: function(type) { + type = type || "current"; + if(type == "current") { + return this.pos; + } else if(type == "end") { + return this.endPos; + } else if(type == "start") { + return this.startPos; + } + }, + /* + Method: setPos + + Sets the node's position. + + Parameters: + + value - (object) A or instance. + type - (string) Default's *current*. Possible values are "start", "end" or "current". + + Example: + (start code js) + node.setPos(new $jit.Complex(0, 0), 'end'); + (end code) + */ + setPos: function(value, type) { + type = type || "current"; + var pos; + if(type == "current") { + pos = this.pos; + } else if(type == "end") { + pos = this.endPos; + } else if(type == "start") { + pos = this.startPos; + } + pos.set(value); + } +}); + +Graph.Node.implement(Accessors); + +/* + Class: Graph.Adjacence + + A adjacence (or edge) connecting two . + + Implements: + + methods. + + See also: + + , + + Properties: + + nodeFrom - A connected by this edge. + nodeTo - Another connected by this edge. + data - Node data property containing a hash (i.e {}) with custom options. +*/ +Graph.Adjacence = new Class({ + + initialize: function(nodeFrom, nodeTo, data, Edge, Label) { + this.nodeFrom = nodeFrom; + this.nodeTo = nodeTo; + this.data = data || {}; + this.startData = {}; + this.endData = {}; + this.Config = this.Edge = Edge; + this.Label = Label; + } +}); + +Graph.Adjacence.implement(Accessors); + +/* + Object: Graph.Util + + traversal and processing utility object. + + Note: + + For your convenience some of these methods have also been appended to and classes. +*/ +Graph.Util = { + /* + filter + + For internal use only. Provides a filtering function based on flags. + */ + filter: function(param) { + if(!param || !($.type(param) == 'string')) return function() { return true; }; + var props = param.split(" "); + return function(elem) { + for(var i=0; i by *id*. + + Also implemented by: + + + + Parameters: + + graph - (object) A instance. + id - (string) A id. + + Example: + + (start code js) + $jit.Graph.Util.getNode(graph, 'nodeid'); + //or... + graph.getNode('nodeid'); + (end code) + */ + getNode: function(graph, id) { + return graph.nodes[id]; + }, + + /* + Method: eachNode + + Iterates over nodes performing an *action*. + + Also implemented by: + + . + + Parameters: + + graph - (object) A instance. + action - (function) A callback function having a as first formal parameter. + + Example: + (start code js) + $jit.Graph.Util.eachNode(graph, function(node) { + alert(node.name); + }); + //or... + graph.eachNode(function(node) { + alert(node.name); + }); + (end code) + */ + eachNode: function(graph, action, flags) { + var filter = this.filter(flags); + for(var i in graph.nodes) { + if(filter(graph.nodes[i])) action(graph.nodes[i]); + } + }, + + /* + Method: eachAdjacency + + Iterates over adjacencies applying the *action* function. + + Also implemented by: + + . + + Parameters: + + node - (object) A . + action - (function) A callback function having as first formal parameter. + + Example: + (start code js) + $jit.Graph.Util.eachAdjacency(node, function(adj) { + alert(adj.nodeTo.name); + }); + //or... + node.eachAdjacency(function(adj) { + alert(adj.nodeTo.name); + }); + (end code) + */ + eachAdjacency: function(node, action, flags) { + var adj = node.adjacencies, filter = this.filter(flags); + for(var id in adj) { + var a = adj[id]; + if(filter(a)) { + if(a.nodeFrom != node) { + var tmp = a.nodeFrom; + a.nodeFrom = a.nodeTo; + a.nodeTo = tmp; + } + action(a, id); + } + } + }, + + /* + Method: computeLevels + + Performs a BFS traversal setting the correct depth for each node. + + Also implemented by: + + . + + Note: + + The depth of each node can then be accessed by + >node._depth + + Parameters: + + graph - (object) A . + id - (string) A starting node id for the BFS traversal. + startDepth - (optional|number) A minimum depth value. Default's 0. + + */ + computeLevels: function(graph, id, startDepth, flags) { + startDepth = startDepth || 0; + var filter = this.filter(flags); + this.eachNode(graph, function(elem) { + elem._flag = false; + elem._depth = -1; + }, flags); + var root = graph.getNode(id); + root._depth = startDepth; + var queue = [root]; + while(queue.length != 0) { + var node = queue.pop(); + node._flag = true; + this.eachAdjacency(node, function(adj) { + var n = adj.nodeTo; + if(n._flag == false && filter(n)) { + if(n._depth < 0) n._depth = node._depth + 1 + startDepth; + queue.unshift(n); + } + }, flags); + } + }, + + /* + Method: eachBFS + + Performs a BFS traversal applying *action* to each . + + Also implemented by: + + . + + Parameters: + + graph - (object) A . + id - (string) A starting node id for the BFS traversal. + action - (function) A callback function having a as first formal parameter. + + Example: + (start code js) + $jit.Graph.Util.eachBFS(graph, 'mynodeid', function(node) { + alert(node.name); + }); + //or... + graph.eachBFS('mynodeid', function(node) { + alert(node.name); + }); + (end code) + */ + eachBFS: function(graph, id, action, flags) { + var filter = this.filter(flags); + this.clean(graph); + var queue = [graph.getNode(id)]; + while(queue.length != 0) { + var node = queue.pop(); + node._flag = true; + action(node, node._depth); + this.eachAdjacency(node, function(adj) { + var n = adj.nodeTo; + if(n._flag == false && filter(n)) { + n._flag = true; + queue.unshift(n); + } + }, flags); + } + }, + + /* + Method: eachLevel + + Iterates over a node's subgraph applying *action* to the nodes of relative depth between *levelBegin* and *levelEnd*. + + Also implemented by: + + . + + Parameters: + + node - (object) A . + levelBegin - (number) A relative level value. + levelEnd - (number) A relative level value. + action - (function) A callback function having a as first formal parameter. + + */ + eachLevel: function(node, levelBegin, levelEnd, action, flags) { + var d = node._depth, filter = this.filter(flags), that = this; + levelEnd = levelEnd === false? Number.MAX_VALUE -d : levelEnd; + (function loopLevel(node, levelBegin, levelEnd) { + var d = node._depth; + if(d >= levelBegin && d <= levelEnd && filter(node)) action(node, d); + if(d < levelEnd) { + that.eachAdjacency(node, function(adj) { + var n = adj.nodeTo; + if(n._depth > d) loopLevel(n, levelBegin, levelEnd); + }); + } + })(node, levelBegin + d, levelEnd + d); + }, + + /* + Method: eachSubgraph + + Iterates over a node's children recursively. + + Also implemented by: + + . + + Parameters: + node - (object) A . + action - (function) A callback function having a as first formal parameter. + + Example: + (start code js) + $jit.Graph.Util.eachSubgraph(node, function(node) { + alert(node.name); + }); + //or... + node.eachSubgraph(function(node) { + alert(node.name); + }); + (end code) + */ + eachSubgraph: function(node, action, flags) { + this.eachLevel(node, 0, false, action, flags); + }, + + /* + Method: eachSubnode + + Iterates over a node's children (without deeper recursion). + + Also implemented by: + + . + + Parameters: + node - (object) A . + action - (function) A callback function having a as first formal parameter. + + Example: + (start code js) + $jit.Graph.Util.eachSubnode(node, function(node) { + alert(node.name); + }); + //or... + node.eachSubnode(function(node) { + alert(node.name); + }); + (end code) + */ + eachSubnode: function(node, action, flags) { + this.eachLevel(node, 1, 1, action, flags); + }, + + /* + Method: anySubnode + + Returns *true* if any subnode matches the given condition. + + Also implemented by: + + . + + Parameters: + node - (object) A . + cond - (function) A callback function returning a Boolean instance. This function has as first formal parameter a . + + Example: + (start code js) + $jit.Graph.Util.anySubnode(node, function(node) { return node.name == "mynodename"; }); + //or... + node.anySubnode(function(node) { return node.name == 'mynodename'; }); + (end code) + */ + anySubnode: function(node, cond, flags) { + var flag = false; + cond = cond || $.lambda(true); + var c = $.type(cond) == 'string'? function(n) { return n[cond]; } : cond; + this.eachSubnode(node, function(elem) { + if(c(elem)) flag = true; + }, flags); + return flag; + }, + + /* + Method: getSubnodes + + Collects all subnodes for a specified node. + The *level* parameter filters nodes having relative depth of *level* from the root node. + + Also implemented by: + + . + + Parameters: + node - (object) A . + level - (optional|number) Default's *0*. A starting relative depth for collecting nodes. + + Returns: + An array of nodes. + + */ + getSubnodes: function(node, level, flags) { + var ans = [], that = this; + level = level || 0; + var levelStart, levelEnd; + if($.type(level) == 'array') { + levelStart = level[0]; + levelEnd = level[1]; + } else { + levelStart = level; + levelEnd = Number.MAX_VALUE - node._depth; + } + this.eachLevel(node, levelStart, levelEnd, function(n) { + ans.push(n); + }, flags); + return ans; + }, + + + /* + Method: getParents + + Returns an Array of which are parents of the given node. + + Also implemented by: + + . + + Parameters: + node - (object) A . + + Returns: + An Array of . + + Example: + (start code js) + var pars = $jit.Graph.Util.getParents(node); + //or... + var pars = node.getParents(); + + if(pars.length > 0) { + //do stuff with parents + } + (end code) + */ + getParents: function(node) { + var ans = []; + this.eachAdjacency(node, function(adj) { + var n = adj.nodeTo; + if(n._depth < node._depth) ans.push(n); + }); + return ans; + }, + + /* + Method: isDescendantOf + + Returns a boolean indicating if some node is descendant of the node with the given id. + + Also implemented by: + + . + + + Parameters: + node - (object) A . + id - (string) A id. + + Example: + (start code js) + $jit.Graph.Util.isDescendantOf(node, "nodeid"); //true|false + //or... + node.isDescendantOf('nodeid');//true|false + (end code) + */ + isDescendantOf: function(node, id) { + if(node.id == id) return true; + var pars = this.getParents(node), ans = false; + for ( var i = 0; !ans && i < pars.length; i++) { + ans = ans || this.isDescendantOf(pars[i], id); + } + return ans; + }, + + /* + Method: clean + + Cleans flags from nodes. + + Also implemented by: + + . + + Parameters: + graph - A instance. + */ + clean: function(graph) { this.eachNode(graph, function(elem) { elem._flag = false; }); }, + + /* + Method: getClosestNodeToOrigin + + Returns the closest node to the center of canvas. + + Also implemented by: + + . + + Parameters: + + graph - (object) A instance. + prop - (optional|string) Default's 'current'. A position property. Possible properties are 'start', 'current' or 'end'. + + */ + getClosestNodeToOrigin: function(graph, prop, flags) { + return this.getClosestNodeToPos(graph, Polar.KER, prop, flags); + }, + + /* + Method: getClosestNodeToPos + + Returns the closest node to the given position. + + Also implemented by: + + . + + Parameters: + + graph - (object) A instance. + pos - (object) A or instance. + prop - (optional|string) Default's *current*. A position property. Possible properties are 'start', 'current' or 'end'. + + */ + getClosestNodeToPos: function(graph, pos, prop, flags) { + var node = null; + prop = prop || 'current'; + pos = pos && pos.getc(true) || Complex.KER; + var distance = function(a, b) { + var d1 = a.x - b.x, d2 = a.y - b.y; + return d1 * d1 + d2 * d2; + }; + this.eachNode(graph, function(elem) { + node = (node == null || distance(elem.getPos(prop).getc(true), pos) < distance( + node.getPos(prop).getc(true), pos)) ? elem : node; + }, flags); + return node; + } +}; + +//Append graph methods to +$.each(['getNode', 'eachNode', 'computeLevels', 'eachBFS', 'clean', 'getClosestNodeToPos', 'getClosestNodeToOrigin'], function(m) { + Graph.prototype[m] = function() { + return Graph.Util[m].apply(Graph.Util, [this].concat(Array.prototype.slice.call(arguments))); + }; +}); + +//Append node methods to +$.each(['eachAdjacency', 'eachLevel', 'eachSubgraph', 'eachSubnode', 'anySubnode', 'getSubnodes', 'getParents', 'isDescendantOf'], function(m) { + Graph.Node.prototype[m] = function() { + return Graph.Util[m].apply(Graph.Util, [this].concat(Array.prototype.slice.call(arguments))); + }; +}); + +/* + * File: Graph.Op.js + * +*/ + +/* + Object: Graph.Op + + Perform operations like adding/removing or , + morphing a into another , contracting or expanding subtrees, etc. + +*/ +Graph.Op = { + + options: { + type: 'nothing', + duration: 2000, + hideLabels: true, + fps:30 + }, + + initialize: function(viz) { + this.viz = viz; + }, + + /* + Method: removeNode + + Removes one or more from the visualization. + It can also perform several animations like fading sequentially, fading concurrently, iterating or replotting. + + Parameters: + + node - (string|array) The node's id. Can also be an array having many ids. + opt - (object) Animation options. It's an object with optional properties described below + type - (string) Default's *nothing*. Type of the animation. Can be "nothing", "replot", "fade:seq", "fade:con" or "iter". + duration - Described in . + fps - Described in . + transition - Described in . + hideLabels - (boolean) Default's *true*. Hide labels during the animation. + + Example: + (start code js) + var viz = new $jit.Viz(options); + viz.op.removeNode('nodeId', { + type: 'fade:seq', + duration: 1000, + hideLabels: false, + transition: $jit.Trans.Quart.easeOut + }); + //or also + viz.op.removeNode(['someId', 'otherId'], { + type: 'fade:con', + duration: 1500 + }); + (end code) + */ + + removeNode: function(node, opt) { + var viz = this.viz; + var options = $.merge(this.options, viz.controller, opt); + var n = $.splat(node); + var i, that, nodeObj; + switch(options.type) { + case 'nothing': + for(i=0; i from the visualization. + It can also perform several animations like fading sequentially, fading concurrently, iterating or replotting. + + Parameters: + + vertex - (array) An array having two strings which are the ids of the nodes connected by this edge (i.e ['id1', 'id2']). Can also be a two dimensional array holding many edges (i.e [['id1', 'id2'], ['id3', 'id4'], ...]). + opt - (object) Animation options. It's an object with optional properties described below + type - (string) Default's *nothing*. Type of the animation. Can be "nothing", "replot", "fade:seq", "fade:con" or "iter". + duration - Described in . + fps - Described in . + transition - Described in . + hideLabels - (boolean) Default's *true*. Hide labels during the animation. + + Example: + (start code js) + var viz = new $jit.Viz(options); + viz.op.removeEdge(['nodeId', 'otherId'], { + type: 'fade:seq', + duration: 1000, + hideLabels: false, + transition: $jit.Trans.Quart.easeOut + }); + //or also + viz.op.removeEdge([['someId', 'otherId'], ['id3', 'id4']], { + type: 'fade:con', + duration: 1500 + }); + (end code) + + */ + removeEdge: function(vertex, opt) { + var viz = this.viz; + var options = $.merge(this.options, viz.controller, opt); + var v = ($.type(vertex[0]) == 'string')? [vertex] : vertex; + var i, that, adj; + switch(options.type) { + case 'nothing': + for(i=0; i + + Parameters: + + json - (object) A json tree or graph structure. See also . + opt - (object) Animation options. It's an object with optional properties described below + type - (string) Default's *nothing*. Type of the animation. Can be "nothing", "replot", "fade:seq", "fade:con". + duration - Described in . + fps - Described in . + transition - Described in . + hideLabels - (boolean) Default's *true*. Hide labels during the animation. + + Example: + (start code js) + //...json contains a tree or graph structure... + + var viz = new $jit.Viz(options); + viz.op.sum(json, { + type: 'fade:seq', + duration: 1000, + hideLabels: false, + transition: $jit.Trans.Quart.easeOut + }); + //or also + viz.op.sum(json, { + type: 'fade:con', + duration: 1500 + }); + (end code) + + */ + sum: function(json, opt) { + var viz = this.viz; + var options = $.merge(this.options, viz.controller, opt), root = viz.root; + var graph; + viz.root = opt.id || viz.root; + switch(options.type) { + case 'nothing': + graph = viz.construct(json); + graph.eachNode(function(elem) { + elem.eachAdjacency(function(adj) { + viz.graph.addAdjacence(adj.nodeFrom, adj.nodeTo, adj.data); + }); + }); + break; + + case 'replot': + viz.refresh(true); + this.sum(json, { type: 'nothing' }); + viz.refresh(true); + break; + + case 'fade:seq': case 'fade': case 'fade:con': + that = this; + graph = viz.construct(json); + + //set alpha to 0 for nodes to add. + var fadeEdges = this.preprocessSum(graph); + var modes = !fadeEdges? ['node-property:alpha'] : ['node-property:alpha', 'edge-property:alpha']; + viz.reposition(); + if(options.type != 'fade:con') { + viz.fx.animate($.merge(options, { + modes: ['linear'], + onComplete: function() { + viz.fx.animate($.merge(options, { + modes: modes, + onComplete: function() { + options.onComplete(); + } + })); + } + })); + } else { + viz.graph.eachNode(function(elem) { + if (elem.id != root && elem.pos.getp().equals(Polar.KER)) { + elem.pos.set(elem.endPos); elem.startPos.set(elem.endPos); + } + }); + viz.fx.animate($.merge(options, { + modes: ['linear'].concat(modes) + })); + } + break; + + default: this.doError(); + } + }, + + /* + Method: morph + + This method will transform the current visualized graph into the new JSON representation passed in the method. + The JSON object must at least have the root node in common with the current visualized graph. + + Parameters: + + json - (object) A json tree or graph structure. See also . + opt - (object) Animation options. It's an object with optional properties described below + type - (string) Default's *nothing*. Type of the animation. Can be "nothing", "replot", "fade:con". + duration - Described in . + fps - Described in . + transition - Described in . + hideLabels - (boolean) Default's *true*. Hide labels during the animation. + id - (string) The shared id between both graphs. + + extraModes - (optional|object) When morphing with an animation, dollar prefixed data parameters are added to + *endData* and not *data* itself. This way you can animate dollar prefixed parameters during your morphing operation. + For animating these extra-parameters you have to specify an object that has animation groups as keys and animation + properties as values, just like specified in . + + Example: + (start code js) + //...json contains a tree or graph structure... + + var viz = new $jit.Viz(options); + viz.op.morph(json, { + type: 'fade', + duration: 1000, + hideLabels: false, + transition: $jit.Trans.Quart.easeOut + }); + //or also + viz.op.morph(json, { + type: 'fade', + duration: 1500 + }); + //if the json data contains dollar prefixed params + //like $width or $height these too can be animated + viz.op.morph(json, { + type: 'fade', + duration: 1500 + }, { + 'node-property': ['width', 'height'] + }); + (end code) + + */ + morph: function(json, opt, extraModes) { + var viz = this.viz; + var options = $.merge(this.options, viz.controller, opt), root = viz.root; + var graph; + //TODO(nico) this hack makes morphing work with the Hypertree. + //Need to check if it has been solved and this can be removed. + viz.root = opt.id || viz.root; + switch(options.type) { + case 'nothing': + graph = viz.construct(json); + graph.eachNode(function(elem) { + var nodeExists = viz.graph.hasNode(elem.id); + elem.eachAdjacency(function(adj) { + var adjExists = !!viz.graph.getAdjacence(adj.nodeFrom.id, adj.nodeTo.id); + viz.graph.addAdjacence(adj.nodeFrom, adj.nodeTo, adj.data); + //Update data properties if the node existed + if(adjExists) { + var addedAdj = viz.graph.getAdjacence(adj.nodeFrom.id, adj.nodeTo.id); + for(var prop in (adj.data || {})) { + addedAdj.data[prop] = adj.data[prop]; + } + } + }); + //Update data properties if the node existed + if(nodeExists) { + var addedNode = viz.graph.getNode(elem.id); + for(var prop in (elem.data || {})) { + addedNode.data[prop] = elem.data[prop]; + } + } + }); + viz.graph.eachNode(function(elem) { + elem.eachAdjacency(function(adj) { + if(!graph.getAdjacence(adj.nodeFrom.id, adj.nodeTo.id)) { + viz.graph.removeAdjacence(adj.nodeFrom.id, adj.nodeTo.id); + } + }); + if(!graph.hasNode(elem.id)) viz.graph.removeNode(elem.id); + }); + + break; + + case 'replot': + viz.labels.clearLabels(true); + this.morph(json, { type: 'nothing' }); + viz.refresh(true); + viz.refresh(true); + break; + + case 'fade:seq': case 'fade': case 'fade:con': + that = this; + graph = viz.construct(json); + //preprocessing for nodes to delete. + //get node property modes to interpolate + var nodeModes = extraModes && ('node-property' in extraModes) + && $.map($.splat(extraModes['node-property']), + function(n) { return '$' + n; }); + viz.graph.eachNode(function(elem) { + var graphNode = graph.getNode(elem.id); + if(!graphNode) { + elem.setData('alpha', 1); + elem.setData('alpha', 1, 'start'); + elem.setData('alpha', 0, 'end'); + elem.ignore = true; + } else { + //Update node data information + var graphNodeData = graphNode.data; + for(var prop in graphNodeData) { + if(nodeModes && ($.indexOf(nodeModes, prop) > -1)) { + elem.endData[prop] = graphNodeData[prop]; + } else { + elem.data[prop] = graphNodeData[prop]; + } + } + } + }); + viz.graph.eachNode(function(elem) { + if(elem.ignore) return; + elem.eachAdjacency(function(adj) { + if(adj.nodeFrom.ignore || adj.nodeTo.ignore) return; + var nodeFrom = graph.getNode(adj.nodeFrom.id); + var nodeTo = graph.getNode(adj.nodeTo.id); + if(!nodeFrom.adjacentTo(nodeTo)) { + var adj = viz.graph.getAdjacence(nodeFrom.id, nodeTo.id); + fadeEdges = true; + adj.setData('alpha', 1); + adj.setData('alpha', 1, 'start'); + adj.setData('alpha', 0, 'end'); + } + }); + }); + //preprocessing for adding nodes. + var fadeEdges = this.preprocessSum(graph); + + var modes = !fadeEdges? ['node-property:alpha'] : + ['node-property:alpha', + 'edge-property:alpha']; + //Append extra node-property animations (if any) + modes[0] = modes[0] + ((extraModes && ('node-property' in extraModes))? + (':' + $.splat(extraModes['node-property']).join(':')) : ''); + //Append extra edge-property animations (if any) + modes[1] = (modes[1] || 'edge-property:alpha') + ((extraModes && ('edge-property' in extraModes))? + (':' + $.splat(extraModes['edge-property']).join(':')) : ''); + //Add label-property animations (if any) + if(extraModes && ('label-property' in extraModes)) { + modes.push('label-property:' + $.splat(extraModes['label-property']).join(':')) + } + viz.reposition(); + viz.graph.eachNode(function(elem) { + if (elem.id != root && elem.pos.getp().equals(Polar.KER)) { + elem.pos.set(elem.endPos); elem.startPos.set(elem.endPos); + } + }); + viz.fx.animate($.merge(options, { + modes: ['polar'].concat(modes), + onComplete: function() { + viz.graph.eachNode(function(elem) { + if(elem.ignore) viz.graph.removeNode(elem.id); + }); + viz.graph.eachNode(function(elem) { + elem.eachAdjacency(function(adj) { + if(adj.ignore) viz.graph.removeAdjacence(adj.nodeFrom.id, adj.nodeTo.id); + }); + }); + options.onComplete(); + } + })); + break; + + default:; + } + }, + + + /* + Method: contract + + Collapses the subtree of the given node. The node will have a _collapsed=true_ property. + + Parameters: + + node - (object) A . + opt - (object) An object containing options described below + type - (string) Whether to 'replot' or 'animate' the contraction. + + There are also a number of Animation options. For more information see . + + Example: + (start code js) + var viz = new $jit.Viz(options); + viz.op.contract(node, { + type: 'animate', + duration: 1000, + hideLabels: true, + transition: $jit.Trans.Quart.easeOut + }); + (end code) + + */ + contract: function(node, opt) { + var viz = this.viz; + if(node.collapsed || !node.anySubnode($.lambda(true))) return; + opt = $.merge(this.options, viz.config, opt || {}, { + 'modes': ['node-property:alpha:span', 'linear'] + }); + node.collapsed = true; + (function subn(n) { + n.eachSubnode(function(ch) { + ch.ignore = true; + ch.setData('alpha', 0, opt.type == 'animate'? 'end' : 'current'); + subn(ch); + }); + })(node); + if(opt.type == 'animate') { + viz.compute('end'); + if(viz.rotated) { + viz.rotate(viz.rotated, 'none', { + 'property':'end' + }); + } + (function subn(n) { + n.eachSubnode(function(ch) { + ch.setPos(node.getPos('end'), 'end'); + subn(ch); + }); + })(node); + viz.fx.animate(opt); + } else if(opt.type == 'replot'){ + viz.refresh(); + } + }, + + /* + Method: expand + + Expands the previously contracted subtree. The given node must have the _collapsed=true_ property. + + Parameters: + + node - (object) A . + opt - (object) An object containing options described below + type - (string) Whether to 'replot' or 'animate'. + + There are also a number of Animation options. For more information see . + + Example: + (start code js) + var viz = new $jit.Viz(options); + viz.op.expand(node, { + type: 'animate', + duration: 1000, + hideLabels: true, + transition: $jit.Trans.Quart.easeOut + }); + (end code) + + */ + expand: function(node, opt) { + if(!('collapsed' in node)) return; + var viz = this.viz; + opt = $.merge(this.options, viz.config, opt || {}, { + 'modes': ['node-property:alpha:span', 'linear'] + }); + delete node.collapsed; + (function subn(n) { + n.eachSubnode(function(ch) { + delete ch.ignore; + ch.setData('alpha', 1, opt.type == 'animate'? 'end' : 'current'); + subn(ch); + }); + })(node); + if(opt.type == 'animate') { + viz.compute('end'); + if(viz.rotated) { + viz.rotate(viz.rotated, 'none', { + 'property':'end' + }); + } + viz.fx.animate(opt); + } else if(opt.type == 'replot'){ + viz.refresh(); + } + }, + + preprocessSum: function(graph) { + var viz = this.viz; + graph.eachNode(function(elem) { + if(!viz.graph.hasNode(elem.id)) { + viz.graph.addNode(elem); + var n = viz.graph.getNode(elem.id); + n.setData('alpha', 0); + n.setData('alpha', 0, 'start'); + n.setData('alpha', 1, 'end'); + } + }); + var fadeEdges = false; + graph.eachNode(function(elem) { + elem.eachAdjacency(function(adj) { + var nodeFrom = viz.graph.getNode(adj.nodeFrom.id); + var nodeTo = viz.graph.getNode(adj.nodeTo.id); + if(!nodeFrom.adjacentTo(nodeTo)) { + var adj = viz.graph.addAdjacence(nodeFrom, nodeTo, adj.data); + if(nodeFrom.startAlpha == nodeFrom.endAlpha + && nodeTo.startAlpha == nodeTo.endAlpha) { + fadeEdges = true; + adj.setData('alpha', 0); + adj.setData('alpha', 0, 'start'); + adj.setData('alpha', 1, 'end'); + } + } + }); + }); + return fadeEdges; + } +}; + + + +/* + File: Helpers.js + + Helpers are objects that contain rendering primitives (like rectangles, ellipses, etc), for plotting nodes and edges. + Helpers also contain implementations of the *contains* method, a method returning a boolean indicating whether the mouse + position is over the rendered shape. + + Helpers are very useful when implementing new NodeTypes, since you can access them through *this.nodeHelper* and + *this.edgeHelper* properties, providing you with simple primitives and mouse-position check functions. + + Example: + (start code js) + //implement a new node type + $jit.Viz.Plot.NodeTypes.implement({ + 'customNodeType': { + 'render': function(node, canvas) { + this.nodeHelper.circle.render ... + }, + 'contains': function(node, pos) { + this.nodeHelper.circle.contains ... + } + } + }); + //implement an edge type + $jit.Viz.Plot.EdgeTypes.implement({ + 'customNodeType': { + 'render': function(node, canvas) { + this.edgeHelper.circle.render ... + }, + //optional + 'contains': function(node, pos) { + this.edgeHelper.circle.contains ... + } + } + }); + (end code) + +*/ + +/* + Object: NodeHelper + + Contains rendering and other type of primitives for simple shapes. + */ +var NodeHelper = { + 'none': { + 'render': $.empty, + 'contains': $.lambda(false) + }, + /* + Object: NodeHelper.circle + */ + 'circle': { + /* + Method: render + + Renders a circle into the canvas. + + Parameters: + + type - (string) Possible options are 'fill' or 'stroke'. + pos - (object) An *x*, *y* object with the position of the center of the circle. + radius - (number) The radius of the circle to be rendered. + canvas - (object) A instance. + + Example: + (start code js) + NodeHelper.circle.render('fill', { x: 10, y: 30 }, 30, viz.canvas); + (end code) + */ + 'render': function(type, pos, radius, canvas){ + var ctx = canvas.getCtx(); + ctx.beginPath(); + ctx.arc(pos.x, pos.y, radius, 0, Math.PI * 2, true); + ctx.closePath(); + ctx[type](); + }, + /* + Method: contains + + Returns *true* if *pos* is contained in the area of the shape. Returns *false* otherwise. + + Parameters: + + npos - (object) An *x*, *y* object with the position. + pos - (object) An *x*, *y* object with the position to check. + radius - (number) The radius of the rendered circle. + + Example: + (start code js) + NodeHelper.circle.contains({ x: 10, y: 30 }, { x: 15, y: 35 }, 30); //true + (end code) + */ + 'contains': function(npos, pos, radius){ + var diffx = npos.x - pos.x, + diffy = npos.y - pos.y, + diff = diffx * diffx + diffy * diffy; + return diff <= radius * radius; + } + }, + /* + Object: NodeHelper.ellipse + */ + 'ellipse': { + /* + Method: render + + Renders an ellipse into the canvas. + + Parameters: + + type - (string) Possible options are 'fill' or 'stroke'. + pos - (object) An *x*, *y* object with the position of the center of the ellipse. + width - (number) The width of the ellipse. + height - (number) The height of the ellipse. + canvas - (object) A instance. + + Example: + (start code js) + NodeHelper.ellipse.render('fill', { x: 10, y: 30 }, 30, 40, viz.canvas); + (end code) + */ + 'render': function(type, pos, width, height, canvas){ + var ctx = canvas.getCtx(); + height /= 2; + width /= 2; + ctx.save(); + ctx.scale(width / height, height / width); + ctx.beginPath(); + ctx.arc(pos.x * (height / width), pos.y * (width / height), height, 0, + Math.PI * 2, true); + ctx.closePath(); + ctx[type](); + ctx.restore(); + }, + /* + Method: contains + + Returns *true* if *pos* is contained in the area of the shape. Returns *false* otherwise. + + Parameters: + + npos - (object) An *x*, *y* object with the position. + pos - (object) An *x*, *y* object with the position to check. + width - (number) The width of the rendered ellipse. + height - (number) The height of the rendered ellipse. + + Example: + (start code js) + NodeHelper.ellipse.contains({ x: 10, y: 30 }, { x: 15, y: 35 }, 30, 40); + (end code) + */ + 'contains': function(npos, pos, width, height){ + // TODO(nico): be more precise... + width /= 2; + height /= 2; + var dist = (width + height) / 2, + diffx = npos.x - pos.x, + diffy = npos.y - pos.y, + diff = diffx * diffx + diffy * diffy; + return diff <= dist * dist; + } + }, + /* + Object: NodeHelper.square + */ + 'square': { + /* + Method: render + + Renders a square into the canvas. + + Parameters: + + type - (string) Possible options are 'fill' or 'stroke'. + pos - (object) An *x*, *y* object with the position of the center of the square. + dim - (number) The radius (or half-diameter) of the square. + canvas - (object) A instance. + + Example: + (start code js) + NodeHelper.square.render('stroke', { x: 10, y: 30 }, 40, viz.canvas); + (end code) + */ + 'render': function(type, pos, dim, canvas){ + canvas.getCtx()[type + "Rect"](pos.x - dim, pos.y - dim, 2*dim, 2*dim); + }, + /* + Method: contains + + Returns *true* if *pos* is contained in the area of the shape. Returns *false* otherwise. + + Parameters: + + npos - (object) An *x*, *y* object with the position. + pos - (object) An *x*, *y* object with the position to check. + dim - (number) The radius (or half-diameter) of the square. + + Example: + (start code js) + NodeHelper.square.contains({ x: 10, y: 30 }, { x: 15, y: 35 }, 30); + (end code) + */ + 'contains': function(npos, pos, dim){ + return Math.abs(pos.x - npos.x) <= dim && Math.abs(pos.y - npos.y) <= dim; + } + }, + /* + Object: NodeHelper.rectangle + */ + 'rectangle': { + /* + Method: render + + Renders a rectangle into the canvas. + + Parameters: + + type - (string) Possible options are 'fill' or 'stroke'. + pos - (object) An *x*, *y* object with the position of the center of the rectangle. + width - (number) The width of the rectangle. + height - (number) The height of the rectangle. + canvas - (object) A instance. + + Example: + (start code js) + NodeHelper.rectangle.render('fill', { x: 10, y: 30 }, 30, 40, viz.canvas); + (end code) + */ + 'render': function(type, pos, width, height, canvas){ + canvas.getCtx()[type + "Rect"](pos.x - width / 2, pos.y - height / 2, + width, height); + }, + /* + Method: contains + + Returns *true* if *pos* is contained in the area of the shape. Returns *false* otherwise. + + Parameters: + + npos - (object) An *x*, *y* object with the position. + pos - (object) An *x*, *y* object with the position to check. + width - (number) The width of the rendered rectangle. + height - (number) The height of the rendered rectangle. + + Example: + (start code js) + NodeHelper.rectangle.contains({ x: 10, y: 30 }, { x: 15, y: 35 }, 30, 40); + (end code) + */ + 'contains': function(npos, pos, width, height){ + return Math.abs(pos.x - npos.x) <= width / 2 + && Math.abs(pos.y - npos.y) <= height / 2; + } + }, + /* + Object: NodeHelper.triangle + */ + 'triangle': { + /* + Method: render + + Renders a triangle into the canvas. + + Parameters: + + type - (string) Possible options are 'fill' or 'stroke'. + pos - (object) An *x*, *y* object with the position of the center of the triangle. + dim - (number) The dimension of the triangle. + canvas - (object) A instance. + + Example: + (start code js) + NodeHelper.triangle.render('stroke', { x: 10, y: 30 }, 40, viz.canvas); + (end code) + */ + 'render': function(type, pos, dim, canvas){ + var ctx = canvas.getCtx(), + c1x = pos.x, + c1y = pos.y - dim, + c2x = c1x - dim, + c2y = pos.y + dim, + c3x = c1x + dim, + c3y = c2y; + ctx.beginPath(); + ctx.moveTo(c1x, c1y); + ctx.lineTo(c2x, c2y); + ctx.lineTo(c3x, c3y); + ctx.closePath(); + ctx[type](); + }, + /* + Method: contains + + Returns *true* if *pos* is contained in the area of the shape. Returns *false* otherwise. + + Parameters: + + npos - (object) An *x*, *y* object with the position. + pos - (object) An *x*, *y* object with the position to check. + dim - (number) The dimension of the shape. + + Example: + (start code js) + NodeHelper.triangle.contains({ x: 10, y: 30 }, { x: 15, y: 35 }, 30); + (end code) + */ + 'contains': function(npos, pos, dim) { + return NodeHelper.circle.contains(npos, pos, dim); + } + }, + /* + Object: NodeHelper.star + */ + 'star': { + /* + Method: render + + Renders a star into the canvas. + + Parameters: + + type - (string) Possible options are 'fill' or 'stroke'. + pos - (object) An *x*, *y* object with the position of the center of the star. + dim - (number) The dimension of the star. + canvas - (object) A instance. + + Example: + (start code js) + NodeHelper.star.render('stroke', { x: 10, y: 30 }, 40, viz.canvas); + (end code) + */ + 'render': function(type, pos, dim, canvas){ + var ctx = canvas.getCtx(), + pi5 = Math.PI / 5; + ctx.save(); + ctx.translate(pos.x, pos.y); + ctx.beginPath(); + ctx.moveTo(dim, 0); + for (var i = 0; i < 9; i++) { + ctx.rotate(pi5); + if (i % 2 == 0) { + ctx.lineTo((dim / 0.525731) * 0.200811, 0); + } else { + ctx.lineTo(dim, 0); + } + } + ctx.closePath(); + ctx[type](); + ctx.restore(); + }, + /* + Method: contains + + Returns *true* if *pos* is contained in the area of the shape. Returns *false* otherwise. + + Parameters: + + npos - (object) An *x*, *y* object with the position. + pos - (object) An *x*, *y* object with the position to check. + dim - (number) The dimension of the shape. + + Example: + (start code js) + NodeHelper.star.contains({ x: 10, y: 30 }, { x: 15, y: 35 }, 30); + (end code) + */ + 'contains': function(npos, pos, dim) { + return NodeHelper.circle.contains(npos, pos, dim); + } + } +}; + +/* + Object: EdgeHelper + + Contains rendering primitives for simple edge shapes. +*/ +var EdgeHelper = { + /* + Object: EdgeHelper.line + */ + 'line': { + /* + Method: render + + Renders a line into the canvas. + + Parameters: + + from - (object) An *x*, *y* object with the starting position of the line. + to - (object) An *x*, *y* object with the ending position of the line. + canvas - (object) A instance. + + Example: + (start code js) + EdgeHelper.line.render({ x: 10, y: 30 }, { x: 10, y: 50 }, viz.canvas); + (end code) + */ + 'render': function(from, to, canvas){ + var ctx = canvas.getCtx(); + ctx.beginPath(); + ctx.moveTo(from.x, from.y); + ctx.lineTo(to.x, to.y); + ctx.stroke(); + }, + /* + Method: contains + + Returns *true* if *pos* is contained in the area of the shape. Returns *false* otherwise. + + Parameters: + + posFrom - (object) An *x*, *y* object with a position. + posTo - (object) An *x*, *y* object with a position. + pos - (object) An *x*, *y* object with the position to check. + epsilon - (number) The dimension of the shape. + + Example: + (start code js) + EdgeHelper.line.contains({ x: 10, y: 30 }, { x: 15, y: 35 }, { x: 15, y: 35 }, 30); + (end code) + */ + 'contains': function(posFrom, posTo, pos, epsilon) { + var min = Math.min, + max = Math.max, + minPosX = min(posFrom.x, posTo.x), + maxPosX = max(posFrom.x, posTo.x), + minPosY = min(posFrom.y, posTo.y), + maxPosY = max(posFrom.y, posTo.y); + + if(pos.x >= minPosX && pos.x <= maxPosX + && pos.y >= minPosY && pos.y <= maxPosY) { + if(Math.abs(posTo.x - posFrom.x) <= epsilon) { + return true; + } + var dist = (posTo.y - posFrom.y) / (posTo.x - posFrom.x) * (pos.x - posFrom.x) + posFrom.y; + return Math.abs(dist - pos.y) <= epsilon; + } + return false; + } + }, + /* + Object: EdgeHelper.arrow + */ + 'arrow': { + /* + Method: render + + Renders an arrow into the canvas. + + Parameters: + + from - (object) An *x*, *y* object with the starting position of the arrow. + to - (object) An *x*, *y* object with the ending position of the arrow. + dim - (number) The dimension of the arrow. + swap - (boolean) Whether to set the arrow pointing to the starting position or the ending position. + canvas - (object) A instance. + + Example: + (start code js) + EdgeHelper.arrow.render({ x: 10, y: 30 }, { x: 10, y: 50 }, 13, false, viz.canvas); + (end code) + */ + 'render': function(from, to, dim, swap, canvas){ + var ctx = canvas.getCtx(); + // invert edge direction + if (swap) { + var tmp = from; + from = to; + to = tmp; + } + var vect = new Complex(to.x - from.x, to.y - from.y); + vect.$scale(dim / vect.norm()); + var intermediatePoint = new Complex(to.x - vect.x, to.y - vect.y), + normal = new Complex(-vect.y / 2, vect.x / 2), + v1 = intermediatePoint.add(normal), + v2 = intermediatePoint.$add(normal.$scale(-1)); + + ctx.beginPath(); + ctx.moveTo(from.x, from.y); + ctx.lineTo(to.x, to.y); + ctx.stroke(); + ctx.beginPath(); + ctx.moveTo(v1.x, v1.y); + ctx.lineTo(v2.x, v2.y); + ctx.lineTo(to.x, to.y); + ctx.closePath(); + ctx.fill(); + }, + /* + Method: contains + + Returns *true* if *pos* is contained in the area of the shape. Returns *false* otherwise. + + Parameters: + + posFrom - (object) An *x*, *y* object with a position. + posTo - (object) An *x*, *y* object with a position. + pos - (object) An *x*, *y* object with the position to check. + epsilon - (number) The dimension of the shape. + + Example: + (start code js) + EdgeHelper.arrow.contains({ x: 10, y: 30 }, { x: 15, y: 35 }, { x: 15, y: 35 }, 30); + (end code) + */ + 'contains': function(posFrom, posTo, pos, epsilon) { + return EdgeHelper.line.contains(posFrom, posTo, pos, epsilon); + } + }, + /* + Object: EdgeHelper.hyperline + */ + 'hyperline': { + /* + Method: render + + Renders a hyperline into the canvas. A hyperline are the lines drawn for the visualization. + + Parameters: + + from - (object) An *x*, *y* object with the starting position of the hyperline. *x* and *y* must belong to [0, 1). + to - (object) An *x*, *y* object with the ending position of the hyperline. *x* and *y* must belong to [0, 1). + r - (number) The scaling factor. + canvas - (object) A instance. + + Example: + (start code js) + EdgeHelper.hyperline.render({ x: 10, y: 30 }, { x: 10, y: 50 }, 100, viz.canvas); + (end code) + */ + 'render': function(from, to, r, canvas){ + var ctx = canvas.getCtx(); + var centerOfCircle = computeArcThroughTwoPoints(from, to); + if (centerOfCircle.a > 1000 || centerOfCircle.b > 1000 + || centerOfCircle.ratio < 0) { + ctx.beginPath(); + ctx.moveTo(from.x * r, from.y * r); + ctx.lineTo(to.x * r, to.y * r); + ctx.stroke(); + } else { + var angleBegin = Math.atan2(to.y - centerOfCircle.y, to.x + - centerOfCircle.x); + var angleEnd = Math.atan2(from.y - centerOfCircle.y, from.x + - centerOfCircle.x); + var sense = sense(angleBegin, angleEnd); + ctx.beginPath(); + ctx.arc(centerOfCircle.x * r, centerOfCircle.y * r, centerOfCircle.ratio + * r, angleBegin, angleEnd, sense); + ctx.stroke(); + } + /* + Calculates the arc parameters through two points. + + More information in + + Parameters: + + p1 - A instance. + p2 - A instance. + scale - The Disk's diameter. + + Returns: + + An object containing some arc properties. + */ + function computeArcThroughTwoPoints(p1, p2){ + var aDen = (p1.x * p2.y - p1.y * p2.x), bDen = aDen; + var sq1 = p1.squaredNorm(), sq2 = p2.squaredNorm(); + // Fall back to a straight line + if (aDen == 0) + return { + x: 0, + y: 0, + ratio: -1 + }; + + var a = (p1.y * sq2 - p2.y * sq1 + p1.y - p2.y) / aDen; + var b = (p2.x * sq1 - p1.x * sq2 + p2.x - p1.x) / bDen; + var x = -a / 2; + var y = -b / 2; + var squaredRatio = (a * a + b * b) / 4 - 1; + // Fall back to a straight line + if (squaredRatio < 0) + return { + x: 0, + y: 0, + ratio: -1 + }; + var ratio = Math.sqrt(squaredRatio); + var out = { + x: x, + y: y, + ratio: ratio > 1000? -1 : ratio, + a: a, + b: b + }; + + return out; + } + /* + Sets angle direction to clockwise (true) or counterclockwise (false). + + Parameters: + + angleBegin - Starting angle for drawing the arc. + angleEnd - The HyperLine will be drawn from angleBegin to angleEnd. + + Returns: + + A Boolean instance describing the sense for drawing the HyperLine. + */ + function sense(angleBegin, angleEnd){ + return (angleBegin < angleEnd)? ((angleBegin + Math.PI > angleEnd)? false + : true) : ((angleEnd + Math.PI > angleBegin)? true : false); + } + }, + /* + Method: contains + + Not Implemented + + Returns *true* if *pos* is contained in the area of the shape. Returns *false* otherwise. + + Parameters: + + posFrom - (object) An *x*, *y* object with a position. + posTo - (object) An *x*, *y* object with a position. + pos - (object) An *x*, *y* object with the position to check. + epsilon - (number) The dimension of the shape. + + Example: + (start code js) + EdgeHelper.hyperline.contains({ x: 10, y: 30 }, { x: 15, y: 35 }, { x: 15, y: 35 }, 30); + (end code) + */ + 'contains': $.lambda(false) + } +}; + + +/* + * File: Graph.Plot.js + */ + +/* + Object: Graph.Plot + + rendering and animation methods. + + Properties: + + nodeHelper - object. + edgeHelper - object. +*/ +Graph.Plot = { + //Default intializer + initialize: function(viz, klass){ + this.viz = viz; + this.config = viz.config; + this.node = viz.config.Node; + this.edge = viz.config.Edge; + this.animation = new Animation; + this.nodeTypes = new klass.Plot.NodeTypes; + this.edgeTypes = new klass.Plot.EdgeTypes; + this.labels = viz.labels; + }, + + //Add helpers + nodeHelper: NodeHelper, + edgeHelper: EdgeHelper, + + Interpolator: { + //node/edge property parsers + 'map': { + 'border': 'color', + 'color': 'color', + 'width': 'number', + 'height': 'number', + 'dim': 'number', + 'alpha': 'number', + 'lineWidth': 'number', + 'angularWidth':'number', + 'span':'number', + 'valueArray':'array-number', + 'dimArray':'array-number' + //'colorArray':'array-color' + }, + + //canvas specific parsers + 'canvas': { + 'globalAlpha': 'number', + 'fillStyle': 'color', + 'strokeStyle': 'color', + 'lineWidth': 'number', + 'shadowBlur': 'number', + 'shadowColor': 'color', + 'shadowOffsetX': 'number', + 'shadowOffsetY': 'number', + 'miterLimit': 'number' + }, + + //label parsers + 'label': { + 'size': 'number', + 'color': 'color' + }, + + //Number interpolator + 'compute': function(from, to, delta) { + return from + (to - from) * delta; + }, + + //Position interpolators + 'moebius': function(elem, props, delta, vector) { + var v = vector.scale(-delta); + if(v.norm() < 1) { + var x = v.x, y = v.y; + var ans = elem.startPos + .getc().moebiusTransformation(v); + elem.pos.setc(ans.x, ans.y); + v.x = x; v.y = y; + } + }, + + 'linear': function(elem, props, delta) { + var from = elem.startPos.getc(true); + var to = elem.endPos.getc(true); + elem.pos.setc(this.compute(from.x, to.x, delta), + this.compute(from.y, to.y, delta)); + }, + + 'polar': function(elem, props, delta) { + var from = elem.startPos.getp(true); + var to = elem.endPos.getp(); + var ans = to.interpolate(from, delta); + elem.pos.setp(ans.theta, ans.rho); + }, + + //Graph's Node/Edge interpolators + 'number': function(elem, prop, delta, getter, setter) { + var from = elem[getter](prop, 'start'); + var to = elem[getter](prop, 'end'); + elem[setter](prop, this.compute(from, to, delta)); + }, + + 'color': function(elem, prop, delta, getter, setter) { + var from = $.hexToRgb(elem[getter](prop, 'start')); + var to = $.hexToRgb(elem[getter](prop, 'end')); + var comp = this.compute; + var val = $.rgbToHex([parseInt(comp(from[0], to[0], delta)), + parseInt(comp(from[1], to[1], delta)), + parseInt(comp(from[2], to[2], delta))]); + + elem[setter](prop, val); + }, + + 'array-number': function(elem, prop, delta, getter, setter) { + var from = elem[getter](prop, 'start'), + to = elem[getter](prop, 'end'), + cur = []; + for(var i=0, l=from.length; i, + + */ + prepare: function(modes) { + var graph = this.viz.graph, + accessors = { + 'node-property': { + 'getter': 'getData', + 'setter': 'setData' + }, + 'edge-property': { + 'getter': 'getData', + 'setter': 'setData' + }, + 'node-style': { + 'getter': 'getCanvasStyle', + 'setter': 'setCanvasStyle' + }, + 'edge-style': { + 'getter': 'getCanvasStyle', + 'setter': 'setCanvasStyle' + } + }; + + //parse modes + var m = {}; + if($.type(modes) == 'array') { + for(var i=0, len=modes.length; i < len; i++) { + var elems = modes[i].split(':'); + m[elems.shift()] = elems; + } + } else { + for(var p in modes) { + if(p == 'position') { + m[modes.position] = []; + } else { + m[p] = $.splat(modes[p]); + } + } + } + + graph.eachNode(function(node) { + node.startPos.set(node.pos); + $.each(['node-property', 'node-style'], function(p) { + if(p in m) { + var prop = m[p]; + for(var i=0, l=prop.length; i < l; i++) { + node[accessors[p].setter](prop[i], node[accessors[p].getter](prop[i]), 'start'); + } + } + }); + $.each(['edge-property', 'edge-style'], function(p) { + if(p in m) { + var prop = m[p]; + node.eachAdjacency(function(adj) { + for(var i=0, l=prop.length; i < l; i++) { + adj[accessors[p].setter](prop[i], adj[accessors[p].getter](prop[i]), 'start'); + } + }); + } + }); + }); + return m; + }, + + /* + Method: animate + + Animates a by interpolating some , or properties. + + Parameters: + + opt - (object) Animation options. The object properties are described below + duration - (optional) Described in . + fps - (optional) Described in . + hideLabels - (optional|boolean) Whether to hide labels during the animation. + modes - (required|object) An object with animation modes (described below). + + Animation modes: + + Animation modes are strings representing different node/edge and graph properties that you'd like to animate. + They are represented by an object that has as keys main categories of properties to animate and as values a list + of these specific properties. The properties are described below + + position - Describes the way nodes' positions must be interpolated. Possible values are 'linear', 'polar' or 'moebius'. + node-property - Describes which Node properties will be interpolated. These properties can be any of the ones defined in . + edge-property - Describes which Edge properties will be interpolated. These properties can be any the ones defined in . + label-property - Describes which Label properties will be interpolated. These properties can be any of the ones defined in like color or size. + node-style - Describes which Node Canvas Styles will be interpolated. These are specific canvas properties like fillStyle, strokeStyle, lineWidth, shadowBlur, shadowColor, shadowOffsetX, shadowOffsetY, etc. + edge-style - Describes which Edge Canvas Styles will be interpolated. These are specific canvas properties like fillStyle, strokeStyle, lineWidth, shadowBlur, shadowColor, shadowOffsetX, shadowOffsetY, etc. + + Example: + (start code js) + var viz = new $jit.Viz(options); + //...tweak some Data, CanvasStyles or LabelData properties... + viz.fx.animate({ + modes: { + 'position': 'linear', + 'node-property': ['width', 'height'], + 'node-style': 'shadowColor', + 'label-property': 'size' + }, + hideLabels: false + }); + //...can also be written like this... + viz.fx.animate({ + modes: ['linear', + 'node-property:width:height', + 'node-style:shadowColor', + 'label-property:size'], + hideLabels: false + }); + (end code) + */ + animate: function(opt, versor) { + opt = $.merge(this.viz.config, opt || {}); + var that = this, + viz = this.viz, + graph = viz.graph, + interp = this.Interpolator, + animation = opt.type === 'nodefx'? this.nodeFxAnimation : this.animation; + //prepare graph values + var m = this.prepare(opt.modes); + + //animate + if(opt.hideLabels) this.labels.hideLabels(true); + animation.setOptions($.merge(opt, { + $animating: false, + compute: function(delta) { + graph.eachNode(function(node) { + for(var p in m) { + interp[p](node, m[p], delta, versor); + } + }); + that.plot(opt, this.$animating, delta); + this.$animating = true; + }, + complete: function() { + if(opt.hideLabels) that.labels.hideLabels(false); + that.plot(opt); + opt.onComplete(); + opt.onAfterCompute(); + } + })).start(); + }, + + /* + nodeFx + + Apply animation to node properties like color, width, height, dim, etc. + + Parameters: + + options - Animation options. This object properties is described below + elements - The Elements to be transformed. This is an object that has a properties + + (start code js) + 'elements': { + //can also be an array of ids + 'id': 'id-of-node-to-transform', + //properties to be modified. All properties are optional. + 'properties': { + 'color': '#ccc', //some color + 'width': 10, //some width + 'height': 10, //some height + 'dim': 20, //some dim + 'lineWidth': 10 //some line width + } + } + (end code) + + - _reposition_ Whether to recalculate positions and add a motion animation. + This might be used when changing _width_ or _height_ properties in a like layout. Default's *false*. + + - _onComplete_ A method that is called when the animation completes. + + ...and all other options like _duration_, _fps_, _transition_, etc. + + Example: + (start code js) + var rg = new RGraph(canvas, config); //can be also Hypertree or ST + rg.fx.nodeFx({ + 'elements': { + 'id':'mynodeid', + 'properties': { + 'color':'#ccf' + }, + 'transition': Trans.Quart.easeOut + } + }); + (end code) + */ + nodeFx: function(opt) { + var viz = this.viz, + graph = viz.graph, + animation = this.nodeFxAnimation, + options = $.merge(this.viz.config, { + 'elements': { + 'id': false, + 'properties': {} + }, + 'reposition': false + }); + opt = $.merge(options, opt || {}, { + onBeforeCompute: $.empty, + onAfterCompute: $.empty + }); + //check if an animation is running + animation.stopTimer(); + var props = opt.elements.properties; + //set end values for nodes + if(!opt.elements.id) { + graph.eachNode(function(n) { + for(var prop in props) { + n.setData(prop, props[prop], 'end'); + } + }); + } else { + var ids = $.splat(opt.elements.id); + $.each(ids, function(id) { + var n = graph.getNode(id); + if(n) { + for(var prop in props) { + n.setData(prop, props[prop], 'end'); + } + } + }); + } + //get keys + var propnames = []; + for(var prop in props) propnames.push(prop); + //add node properties modes + var modes = ['node-property:' + propnames.join(':')]; + //set new node positions + if(opt.reposition) { + modes.push('linear'); + viz.compute('end'); + } + //animate + this.animate($.merge(opt, { + modes: modes, + type: 'nodefx' + })); + }, + + + /* + Method: plot + + Plots a . + + Parameters: + + opt - (optional) Plotting options. Most of them are described in . + + Example: + + (start code js) + var viz = new $jit.Viz(options); + viz.fx.plot(); + (end code) + + */ + plot: function(opt, animating) { + var viz = this.viz, + aGraph = viz.graph, + canvas = viz.canvas, + id = viz.root, + that = this, + ctx = canvas.getCtx(), + min = Math.min, + opt = opt || this.viz.controller; + opt.clearCanvas && canvas.clear(); + + var root = aGraph.getNode(id); + if(!root) return; + + var T = !!root.visited; + aGraph.eachNode(function(node) { + var nodeAlpha = node.getData('alpha'); + node.eachAdjacency(function(adj) { + var nodeTo = adj.nodeTo; + if(!!nodeTo.visited === T && node.drawn && nodeTo.drawn) { + !animating && opt.onBeforePlotLine(adj); + ctx.save(); + ctx.globalAlpha = min(nodeAlpha, + nodeTo.getData('alpha'), + adj.getData('alpha')); + that.plotLine(adj, canvas, animating); + ctx.restore(); + !animating && opt.onAfterPlotLine(adj); + } + }); + ctx.save(); + if(node.drawn) { + !animating && opt.onBeforePlotNode(node); + that.plotNode(node, canvas, animating); + !animating && opt.onAfterPlotNode(node); + } + if(!that.labelsHidden && opt.withLabels) { + if(node.drawn && nodeAlpha >= 0.95) { + that.labels.plotLabel(canvas, node, opt); + } else { + that.labels.hideLabel(node, false); + } + } + ctx.restore(); + node.visited = !T; + }); + }, + + /* + Plots a Subtree. + */ + plotTree: function(node, opt, animating) { + var that = this, + viz = this.viz, + canvas = viz.canvas, + config = this.config, + ctx = canvas.getCtx(); + var nodeAlpha = node.getData('alpha'); + node.eachSubnode(function(elem) { + if(opt.plotSubtree(node, elem) && elem.exist && elem.drawn) { + var adj = node.getAdjacency(elem.id); + !animating && opt.onBeforePlotLine(adj); + ctx.globalAlpha = Math.min(nodeAlpha, elem.getData('alpha')); + that.plotLine(adj, canvas, animating); + !animating && opt.onAfterPlotLine(adj); + that.plotTree(elem, opt, animating); + } + }); + if(node.drawn) { + !animating && opt.onBeforePlotNode(node); + this.plotNode(node, canvas, animating); + !animating && opt.onAfterPlotNode(node); + if(!opt.hideLabels && opt.withLabels && nodeAlpha >= 0.95) + this.labels.plotLabel(canvas, node, opt); + else + this.labels.hideLabel(node, false); + } else { + this.labels.hideLabel(node, true); + } + }, + + /* + Method: plotNode + + Plots a . + + Parameters: + + node - (object) A . + canvas - (object) A element. + + */ + plotNode: function(node, canvas, animating) { + var f = node.getData('type'), + ctxObj = this.node.CanvasStyles; + if(f != 'none') { + var width = node.getData('lineWidth'), + color = node.getData('color'), + alpha = node.getData('alpha'), + ctx = canvas.getCtx(); + + ctx.lineWidth = width; + ctx.fillStyle = ctx.strokeStyle = color; + ctx.globalAlpha = alpha; + + for(var s in ctxObj) { + ctx[s] = node.getCanvasStyle(s); + } + + this.nodeTypes[f].render.call(this, node, canvas, animating); + } + }, + + /* + Method: plotLine + + Plots a . + + Parameters: + + adj - (object) A . + canvas - (object) A instance. + + */ + plotLine: function(adj, canvas, animating) { + var f = adj.getData('type'), + ctxObj = this.edge.CanvasStyles; + if(f != 'none') { + var width = adj.getData('lineWidth'), + color = adj.getData('color'), + ctx = canvas.getCtx(); + + ctx.lineWidth = width; + ctx.fillStyle = ctx.strokeStyle = color; + + for(var s in ctxObj) { + ctx[s] = adj.getCanvasStyle(s); + } + + this.edgeTypes[f].render.call(this, adj, canvas, animating); + } + } + +}; + + + +/* + * File: Graph.Label.js + * +*/ + +/* + Object: Graph.Label + + An interface for plotting/hiding/showing labels. + + Description: + + This is a generic interface for plotting/hiding/showing labels. + The interface is implemented in multiple ways to provide + different label types. + + For example, the Graph.Label interface is implemented as to provide + HTML label elements. Also we provide the interface for SVG type labels. + The interface implements these methods with the native Canvas text rendering functions. + + All subclasses (, and ) implement the method plotLabel. +*/ + +Graph.Label = {}; + +/* + Class: Graph.Label.Native + + Implements labels natively, using the Canvas text API. +*/ +Graph.Label.Native = new Class({ + /* + Method: plotLabel + + Plots a label for a given node. + + Parameters: + + canvas - (object) A instance. + node - (object) A . + controller - (object) A configuration object. + + Example: + + (start code js) + var viz = new $jit.Viz(options); + var node = viz.graph.getNode('nodeId'); + viz.labels.plotLabel(viz.canvas, node, viz.config); + (end code) + */ + plotLabel: function(canvas, node, controller) { + var ctx = canvas.getCtx(); + var pos = node.pos.getc(true); + + ctx.font = node.getLabelData('style') + ' ' + node.getLabelData('size') + 'px ' + node.getLabelData('family'); + ctx.textAlign = node.getLabelData('textAlign'); + ctx.fillStyle = ctx.strokeStyle = node.getLabelData('color'); + ctx.textBaseline = node.getLabelData('textBaseline'); + + this.renderLabel(canvas, node, controller); + }, + + /* + renderLabel + + Does the actual rendering of the label in the canvas. The default + implementation renders the label close to the position of the node, this + method should be overriden to position the labels differently. + + Parameters: + + canvas - A instance. + node - A . + controller - A configuration object. See also , , . + */ + renderLabel: function(canvas, node, controller) { + var ctx = canvas.getCtx(); + var pos = node.pos.getc(true); + ctx.fillText(node.name, pos.x, pos.y + node.getData("height") / 2); + }, + + hideLabel: $.empty, + hideLabels: $.empty +}); + +/* + Class: Graph.Label.DOM + + Abstract Class implementing some DOM label methods. + + Implemented by: + + and . + +*/ +Graph.Label.DOM = new Class({ + //A flag value indicating if node labels are being displayed or not. + labelsHidden: false, + //Label container + labelContainer: false, + //Label elements hash. + labels: {}, + + /* + Method: getLabelContainer + + Lazy fetcher for the label container. + + Returns: + + The label container DOM element. + + Example: + + (start code js) + var viz = new $jit.Viz(options); + var labelContainer = viz.labels.getLabelContainer(); + alert(labelContainer.innerHTML); + (end code) + */ + getLabelContainer: function() { + return this.labelContainer ? + this.labelContainer : + this.labelContainer = document.getElementById(this.viz.config.labelContainer); + }, + + /* + Method: getLabel + + Lazy fetcher for the label element. + + Parameters: + + id - (string) The label id (which is also a id). + + Returns: + + The label element. + + Example: + + (start code js) + var viz = new $jit.Viz(options); + var label = viz.labels.getLabel('someid'); + alert(label.innerHTML); + (end code) + + */ + getLabel: function(id) { + return (id in this.labels && this.labels[id] != null) ? + this.labels[id] : + this.labels[id] = document.getElementById(id); + }, + + /* + Method: hideLabels + + Hides all labels (by hiding the label container). + + Parameters: + + hide - (boolean) A boolean value indicating if the label container must be hidden or not. + + Example: + (start code js) + var viz = new $jit.Viz(options); + rg.labels.hideLabels(true); + (end code) + + */ + hideLabels: function (hide) { + var container = this.getLabelContainer(); + if(hide) + container.style.display = 'none'; + else + container.style.display = ''; + this.labelsHidden = hide; + }, + + /* + Method: clearLabels + + Clears the label container. + + Useful when using a new visualization with the same canvas element/widget. + + Parameters: + + force - (boolean) Forces deletion of all labels. + + Example: + (start code js) + var viz = new $jit.Viz(options); + viz.labels.clearLabels(); + (end code) + */ + clearLabels: function(force) { + for(var id in this.labels) { + if (force || !this.viz.graph.hasNode(id)) { + this.disposeLabel(id); + delete this.labels[id]; + } + } + }, + + /* + Method: disposeLabel + + Removes a label. + + Parameters: + + id - (string) A label id (which generally is also a id). + + Example: + (start code js) + var viz = new $jit.Viz(options); + viz.labels.disposeLabel('labelid'); + (end code) + */ + disposeLabel: function(id) { + var elem = this.getLabel(id); + if(elem && elem.parentNode) { + elem.parentNode.removeChild(elem); + } + }, + + /* + Method: hideLabel + + Hides the corresponding label. + + Parameters: + + node - (object) A . Can also be an array of . + show - (boolean) If *true*, nodes will be shown. Otherwise nodes will be hidden. + + Example: + (start code js) + var rg = new $jit.Viz(options); + viz.labels.hideLabel(viz.graph.getNode('someid'), false); + (end code) + */ + hideLabel: function(node, show) { + node = $.splat(node); + var st = show ? "" : "none", lab, that = this; + $.each(node, function(n) { + var lab = that.getLabel(n.id); + if (lab) { + lab.style.display = st; + } + }); + }, + + /* + fitsInCanvas + + Returns _true_ or _false_ if the label for the node is contained in the canvas dom element or not. + + Parameters: + + pos - A instance (I'm doing duck typing here so any object with _x_ and _y_ parameters will do). + canvas - A instance. + + Returns: + + A boolean value specifying if the label is contained in the DOM element or not. + + */ + fitsInCanvas: function(pos, canvas) { + var size = canvas.getSize(); + if(pos.x >= size.width || pos.x < 0 + || pos.y >= size.height || pos.y < 0) return false; + return true; + } +}); + +/* + Class: Graph.Label.HTML + + Implements HTML labels. + + Extends: + + All methods. + +*/ +Graph.Label.HTML = new Class({ + Implements: Graph.Label.DOM, + + /* + Method: plotLabel + + Plots a label for a given node. + + Parameters: + + canvas - (object) A instance. + node - (object) A . + controller - (object) A configuration object. + + Example: + + (start code js) + var viz = new $jit.Viz(options); + var node = viz.graph.getNode('nodeId'); + viz.labels.plotLabel(viz.canvas, node, viz.config); + (end code) + + + */ + plotLabel: function(canvas, node, controller) { + var id = node.id, tag = this.getLabel(id); + + if(!tag && !(tag = document.getElementById(id))) { + tag = document.createElement('div'); + var container = this.getLabelContainer(); + tag.id = id; + tag.className = 'node'; + tag.style.position = 'absolute'; + controller.onCreateLabel(tag, node); + container.appendChild(tag); + this.labels[node.id] = tag; + } + + this.placeLabel(tag, node, controller); + } +}); + +/* + Class: Graph.Label.SVG + + Implements SVG labels. + + Extends: + + All methods. +*/ +Graph.Label.SVG = new Class({ + Implements: Graph.Label.DOM, + + /* + Method: plotLabel + + Plots a label for a given node. + + Parameters: + + canvas - (object) A instance. + node - (object) A . + controller - (object) A configuration object. + + Example: + + (start code js) + var viz = new $jit.Viz(options); + var node = viz.graph.getNode('nodeId'); + viz.labels.plotLabel(viz.canvas, node, viz.config); + (end code) + + + */ + plotLabel: function(canvas, node, controller) { + var id = node.id, tag = this.getLabel(id); + if(!tag && !(tag = document.getElementById(id))) { + var ns = 'http://www.w3.org/2000/svg'; + tag = document.createElementNS(ns, 'svg:text'); + var tspan = document.createElementNS(ns, 'svg:tspan'); + tag.appendChild(tspan); + var container = this.getLabelContainer(); + tag.setAttribute('id', id); + tag.setAttribute('class', 'node'); + container.appendChild(tag); + controller.onCreateLabel(tag, node); + this.labels[node.id] = tag; + } + this.placeLabel(tag, node, controller); + } +}); + + + +Graph.Geom = new Class({ + + initialize: function(viz) { + this.viz = viz; + this.config = viz.config; + this.node = viz.config.Node; + this.edge = viz.config.Edge; + }, + /* + Applies a translation to the tree. + + Parameters: + + pos - A number specifying translation vector. + prop - A position property ('pos', 'start' or 'end'). + + Example: + + (start code js) + st.geom.translate(new Complex(300, 100), 'end'); + (end code) + */ + translate: function(pos, prop) { + prop = $.splat(prop); + this.viz.graph.eachNode(function(elem) { + $.each(prop, function(p) { elem.getPos(p).$add(pos); }); + }); + }, + /* + Hides levels of the tree until it properly fits in canvas. + */ + setRightLevelToShow: function(node, canvas, callback) { + var level = this.getRightLevelToShow(node, canvas), + fx = this.viz.labels, + opt = $.merge({ + execShow:true, + execHide:true, + onHide: $.empty, + onShow: $.empty + }, callback || {}); + node.eachLevel(0, this.config.levelsToShow, function(n) { + var d = n._depth - node._depth; + if(d > level) { + opt.onHide(n); + if(opt.execHide) { + n.drawn = false; + n.exist = false; + fx.hideLabel(n, false); + } + } else { + opt.onShow(n); + if(opt.execShow) { + n.exist = true; + } + } + }); + node.drawn= true; + }, + /* + Returns the right level to show for the current tree in order to fit in canvas. + */ + getRightLevelToShow: function(node, canvas) { + var config = this.config; + var level = config.levelsToShow; + var constrained = config.constrained; + if(!constrained) return level; + while(!this.treeFitsInCanvas(node, canvas, level) && level > 1) { level-- ; } + return level; + } +}); + +/* + * File: Loader.js + * + */ + +/* + Object: Loader + + Provides methods for loading and serving JSON data. +*/ +var Loader = { + construct: function(json) { + var isGraph = ($.type(json) == 'array'); + var ans = new Graph(this.graphOptions, this.config.Node, this.config.Edge, this.config.Label); + if(!isGraph) + //make tree + (function (ans, json) { + ans.addNode(json); + if(json.children) { + for(var i=0, ch = json.children; i will override the general value for that option with that particular value. For this to work + however, you do have to set *overridable = true* in . + + The same thing is true for JSON adjacencies. Dollar prefixed data properties will alter values set in + if has *overridable = true*. + + When loading JSON data into TreeMaps, the *data* property must contain a value for the *$area* key, + since this is the value which will be taken into account when creating the layout. + The same thing goes for the *$color* parameter. + + In JSON Nodes you can use also *$label-* prefixed properties to refer to properties. For example, + *$label-size* will refer to size property. Also, in JSON nodes and adjacencies you can set + canvas specific properties individually by using the *$canvas-* prefix. For example, *$canvas-shadowBlur* will refer + to the *shadowBlur* property. + + These properties can also be accessed after loading the JSON data from and + by using . For more information take a look at the and documentation. + + Finally, these properties can also be used to create advanced animations like with . For more + information about creating animations please take a look at the and documentation. + + loadJSON Parameters: + + json - A JSON Tree or Graph structure. + i - For Graph structures only. Sets the indexed node as root for the visualization. + + */ + loadJSON: function(json, i) { + this.json = json; + //if they're canvas labels erase them. + if(this.labels && this.labels.clearLabels) { + this.labels.clearLabels(true); + } + this.graph = this.construct(json); + if($.type(json) != 'array'){ + this.root = json.id; + } else { + this.root = json[i? i : 0].id; + } + }, + + /* + Method: toJSON + + Returns a JSON tree/graph structure from the visualization's . + See for the graph formats available. + + See also: + + + + Parameters: + + type - (string) Default's "tree". The type of the JSON structure to be returned. + Possible options are "tree" or "graph". + */ + toJSON: function(type) { + type = type || "tree"; + if(type == 'tree') { + var ans = {}; + var rootNode = this.graph.getNode(this.root); + var ans = (function recTree(node) { + var ans = {}; + ans.id = node.id; + ans.name = node.name; + ans.data = node.data; + var ch =[]; + node.eachSubnode(function(n) { + ch.push(recTree(n)); + }); + ans.children = ch; + return ans; + })(rootNode); + return ans; + } else { + var ans = []; + var T = !!this.graph.getNode(this.root).visited; + this.graph.eachNode(function(node) { + var ansNode = {}; + ansNode.id = node.id; + ansNode.name = node.name; + ansNode.data = node.data; + var adjs = []; + node.eachAdjacency(function(adj) { + var nodeTo = adj.nodeTo; + if(!!nodeTo.visited === T) { + var ansAdj = {}; + ansAdj.nodeTo = nodeTo.id; + ansAdj.data = adj.data; + adjs.push(ansAdj); + } + }); + ansNode.adjacencies = adjs; + ans.push(ansNode); + node.visited = !T; + }); + return ans; + } + } +}; + + + +/* + * File: Layouts.js + * + * Implements base Tree and Graph layouts. + * + * Description: + * + * Implements base Tree and Graph layouts like Radial, Tree, etc. + * + */ + +/* + * Object: Layouts + * + * Parent object for common layouts. + * + */ +var Layouts = $jit.Layouts = {}; + + +//Some util shared layout functions are defined here. +var NodeDim = { + label: null, + + compute: function(graph, prop, opt) { + this.initializeLabel(opt); + var label = this.label, style = label.style; + graph.eachNode(function(n) { + var autoWidth = n.getData('autoWidth'), + autoHeight = n.getData('autoHeight'); + if(autoWidth || autoHeight) { + //delete dimensions since these are + //going to be overridden now. + delete n.data.$width; + delete n.data.$height; + delete n.data.$dim; + + var width = n.getData('width'), + height = n.getData('height'); + //reset label dimensions + style.width = autoWidth? 'auto' : width + 'px'; + style.height = autoHeight? 'auto' : height + 'px'; + + //TODO(nico) should let the user choose what to insert here. + label.innerHTML = n.name; + + var offsetWidth = label.offsetWidth, + offsetHeight = label.offsetHeight; + var type = n.getData('type'); + if($.indexOf(['circle', 'square', 'triangle', 'star'], type) === -1) { + n.setData('width', offsetWidth); + n.setData('height', offsetHeight); + } else { + var dim = offsetWidth > offsetHeight? offsetWidth : offsetHeight; + n.setData('width', dim); + n.setData('height', dim); + n.setData('dim', dim); + } + } + }); + }, + + initializeLabel: function(opt) { + if(!this.label) { + this.label = document.createElement('div'); + document.body.appendChild(this.label); + } + this.setLabelStyles(opt); + }, + + setLabelStyles: function(opt) { + $.extend(this.label.style, { + 'visibility': 'hidden', + 'position': 'absolute', + 'width': 'auto', + 'height': 'auto' + }); + this.label.className = 'jit-autoadjust-label'; + } +}; + + +/* + * Class: Layouts.Tree + * + * Implements a Tree Layout. + * + * Implemented By: + * + * + * + * Inspired by: + * + * Drawing Trees (Andrew J. Kennedy) + * + */ +Layouts.Tree = (function() { + //Layout functions + var slice = Array.prototype.slice; + + /* + Calculates the max width and height nodes for a tree level + */ + function getBoundaries(graph, config, level, orn, prop) { + var dim = config.Node; + var multitree = config.multitree; + if (dim.overridable) { + var w = -1, h = -1; + graph.eachNode(function(n) { + if (n._depth == level + && (!multitree || ('$orn' in n.data) && n.data.$orn == orn)) { + var dw = n.getData('width', prop); + var dh = n.getData('height', prop); + w = (w < dw) ? dw : w; + h = (h < dh) ? dh : h; + } + }); + return { + 'width' : w < 0 ? dim.width : w, + 'height' : h < 0 ? dim.height : h + }; + } else { + return dim; + } + } + + + function movetree(node, prop, val, orn) { + var p = (orn == "left" || orn == "right") ? "y" : "x"; + node.getPos(prop)[p] += val; + } + + + function moveextent(extent, val) { + var ans = []; + $.each(extent, function(elem) { + elem = slice.call(elem); + elem[0] += val; + elem[1] += val; + ans.push(elem); + }); + return ans; + } + + + function merge(ps, qs) { + if (ps.length == 0) + return qs; + if (qs.length == 0) + return ps; + var p = ps.shift(), q = qs.shift(); + return [ [ p[0], q[1] ] ].concat(merge(ps, qs)); + } + + + function mergelist(ls, def) { + def = def || []; + if (ls.length == 0) + return def; + var ps = ls.pop(); + return mergelist(ls, merge(ps, def)); + } + + + function fit(ext1, ext2, subtreeOffset, siblingOffset, i) { + if (ext1.length <= i || ext2.length <= i) + return 0; + + var p = ext1[i][1], q = ext2[i][0]; + return Math.max(fit(ext1, ext2, subtreeOffset, siblingOffset, ++i) + + subtreeOffset, p - q + siblingOffset); + } + + + function fitlistl(es, subtreeOffset, siblingOffset) { + function $fitlistl(acc, es, i) { + if (es.length <= i) + return []; + var e = es[i], ans = fit(acc, e, subtreeOffset, siblingOffset, 0); + return [ ans ].concat($fitlistl(merge(acc, moveextent(e, ans)), es, ++i)); + } + ; + return $fitlistl( [], es, 0); + } + + + function fitlistr(es, subtreeOffset, siblingOffset) { + function $fitlistr(acc, es, i) { + if (es.length <= i) + return []; + var e = es[i], ans = -fit(e, acc, subtreeOffset, siblingOffset, 0); + return [ ans ].concat($fitlistr(merge(moveextent(e, ans), acc), es, ++i)); + } + ; + es = slice.call(es); + var ans = $fitlistr( [], es.reverse(), 0); + return ans.reverse(); + } + + + function fitlist(es, subtreeOffset, siblingOffset, align) { + var esl = fitlistl(es, subtreeOffset, siblingOffset), esr = fitlistr(es, + subtreeOffset, siblingOffset); + + if (align == "left") + esr = esl; + else if (align == "right") + esl = esr; + + for ( var i = 0, ans = []; i < esl.length; i++) { + ans[i] = (esl[i] + esr[i]) / 2; + } + return ans; + } + + + function design(graph, node, prop, config, orn) { + var multitree = config.multitree; + var auxp = [ 'x', 'y' ], auxs = [ 'width', 'height' ]; + var ind = +(orn == "left" || orn == "right"); + var p = auxp[ind], notp = auxp[1 - ind]; + + var cnode = config.Node; + var s = auxs[ind], nots = auxs[1 - ind]; + + var siblingOffset = config.siblingOffset; + var subtreeOffset = config.subtreeOffset; + var align = config.align; + + function $design(node, maxsize, acum) { + var sval = node.getData(s, prop); + var notsval = maxsize + || (node.getData(nots, prop)); + + var trees = [], extents = [], chmaxsize = false; + var chacum = notsval + config.levelDistance; + node.eachSubnode(function(n) { + if (n.exist + && (!multitree || ('$orn' in n.data) && n.data.$orn == orn)) { + + if (!chmaxsize) + chmaxsize = getBoundaries(graph, config, n._depth, orn, prop); + + var s = $design(n, chmaxsize[nots], acum + chacum); + trees.push(s.tree); + extents.push(s.extent); + } + }); + var positions = fitlist(extents, subtreeOffset, siblingOffset, align); + for ( var i = 0, ptrees = [], pextents = []; i < trees.length; i++) { + movetree(trees[i], prop, positions[i], orn); + pextents.push(moveextent(extents[i], positions[i])); + } + var resultextent = [ [ -sval / 2, sval / 2 ] ] + .concat(mergelist(pextents)); + node.getPos(prop)[p] = 0; + + if (orn == "top" || orn == "left") { + node.getPos(prop)[notp] = acum; + } else { + node.getPos(prop)[notp] = -acum; + } + + return { + tree : node, + extent : resultextent + }; + } + + $design(node, false, 0); + } + + + return new Class({ + /* + Method: compute + + Computes nodes' positions. + + */ + compute : function(property, computeLevels) { + var prop = property || 'start'; + var node = this.graph.getNode(this.root); + $.extend(node, { + 'drawn' : true, + 'exist' : true, + 'selected' : true + }); + NodeDim.compute(this.graph, prop, this.config); + if (!!computeLevels || !("_depth" in node)) { + this.graph.computeLevels(this.root, 0, "ignore"); + } + + this.computePositions(node, prop); + }, + + computePositions : function(node, prop) { + var config = this.config; + var multitree = config.multitree; + var align = config.align; + var indent = align !== 'center' && config.indent; + var orn = config.orientation; + var orns = multitree ? [ 'top', 'right', 'bottom', 'left' ] : [ orn ]; + var that = this; + $.each(orns, function(orn) { + //calculate layout + design(that.graph, node, prop, that.config, orn, prop); + var i = [ 'x', 'y' ][+(orn == "left" || orn == "right")]; + //absolutize + (function red(node) { + node.eachSubnode(function(n) { + if (n.exist + && (!multitree || ('$orn' in n.data) && n.data.$orn == orn)) { + + n.getPos(prop)[i] += node.getPos(prop)[i]; + if (indent) { + n.getPos(prop)[i] += align == 'left' ? indent : -indent; + } + red(n); + } + }); + })(node); + }); + } + }); + +})(); + +/* + * File: Spacetree.js + */ + +/* + Class: ST + + A Tree layout with advanced contraction and expansion animations. + + Inspired by: + + SpaceTree: Supporting Exploration in Large Node Link Tree, Design Evolution and Empirical Evaluation (Catherine Plaisant, Jesse Grosjean, Benjamin B. Bederson) + + + Drawing Trees (Andrew J. Kennedy) + + Note: + + This visualization was built and engineered from scratch, taking only the papers as inspiration, and only shares some features with the visualization described in those papers. + + Implements: + + All methods + + Constructor Options: + + Inherits options from + + - + - + - + - + - + - + - + - + - + - + + Additionally, there are other parameters and some default values changed + + constrained - (boolean) Default's *true*. Whether to show the entire tree when loaded or just the number of levels specified by _levelsToShow_. + levelsToShow - (number) Default's *2*. The number of levels to show for a subtree. This number is relative to the selected node. + levelDistance - (number) Default's *30*. The distance between two consecutive levels of the tree. + Node.type - Described in . Default's set to *rectangle*. + offsetX - (number) Default's *0*. The x-offset distance from the selected node to the center of the canvas. + offsetY - (number) Default's *0*. The y-offset distance from the selected node to the center of the canvas. + duration - Described in . It's default value has been changed to *700*. + + Instance Properties: + + canvas - Access a instance. + graph - Access a instance. + op - Access a instance. + fx - Access a instance. + labels - Access a interface implementation. + + */ + +$jit.ST= (function() { + // Define some private methods first... + // Nodes in path + var nodesInPath = []; + // Nodes to contract + function getNodesToHide(node) { + node = node || this.clickedNode; + if(!this.config.constrained) { + return []; + } + var Geom = this.geom; + var graph = this.graph; + var canvas = this.canvas; + var level = node._depth, nodeArray = []; + graph.eachNode(function(n) { + if(n.exist && !n.selected) { + if(n.isDescendantOf(node.id)) { + if(n._depth <= level) nodeArray.push(n); + } else { + nodeArray.push(n); + } + } + }); + var leafLevel = Geom.getRightLevelToShow(node, canvas); + node.eachLevel(leafLevel, leafLevel, function(n) { + if(n.exist && !n.selected) nodeArray.push(n); + }); + + for (var i = 0; i < nodesInPath.length; i++) { + var n = this.graph.getNode(nodesInPath[i]); + if(!n.isDescendantOf(node.id)) { + nodeArray.push(n); + } + } + return nodeArray; + }; + // Nodes to expand + function getNodesToShow(node) { + var nodeArray = [], config = this.config; + node = node || this.clickedNode; + this.clickedNode.eachLevel(0, config.levelsToShow, function(n) { + if(config.multitree && !('$orn' in n.data) + && n.anySubnode(function(ch){ return ch.exist && !ch.drawn; })) { + nodeArray.push(n); + } else if(n.drawn && !n.anySubnode("drawn")) { + nodeArray.push(n); + } + }); + return nodeArray; + }; + // Now define the actual class. + return new Class({ + + Implements: [Loader, Extras, Layouts.Tree], + + initialize: function(controller) { + var $ST = $jit.ST; + + var config= { + levelsToShow: 2, + levelDistance: 30, + constrained: true, + Node: { + type: 'rectangle' + }, + duration: 700, + offsetX: 0, + offsetY: 0 + }; + + this.controller = this.config = $.merge( + Options("Canvas", "Fx", "Tree", "Node", "Edge", "Controller", + "Tips", "NodeStyles", "Events", "Navigation", "Label"), config, controller); + + var canvasConfig = this.config; + if(canvasConfig.useCanvas) { + this.canvas = canvasConfig.useCanvas; + this.config.labelContainer = this.canvas.id + '-label'; + } else { + if(canvasConfig.background) { + canvasConfig.background = $.merge({ + type: 'Fade', + colorStop1: this.config.colorStop1, + colorStop2: this.config.colorStop2 + }, canvasConfig.background); + } + this.canvas = new Canvas(this, canvasConfig); + this.config.labelContainer = (typeof canvasConfig.injectInto == 'string'? canvasConfig.injectInto : canvasConfig.injectInto.id) + '-label'; + } + + this.graphOptions = { + 'complex': true + }; + this.graph = new Graph(this.graphOptions, this.config.Node, this.config.Edge); + this.labels = new $ST.Label[canvasConfig.Label.type](this); + this.fx = new $ST.Plot(this, $ST); + this.op = new $ST.Op(this); + this.group = new $ST.Group(this); + this.geom = new $ST.Geom(this); + this.clickedNode= null; + // initialize extras + this.initializeExtras(); + }, + + /* + Method: plot + + Plots the . This is a shortcut to *fx.plot*. + + */ + plot: function() { this.fx.plot(this.controller); }, + + + /* + Method: switchPosition + + Switches the tree orientation. + + Parameters: + + pos - (string) The new tree orientation. Possible values are "top", "left", "right" and "bottom". + method - (string) Set this to "animate" if you want to animate the tree when switching its position. You can also set this parameter to "replot" to just replot the subtree. + onComplete - (optional|object) This callback is called once the "switching" animation is complete. + + Example: + + (start code js) + st.switchPosition("right", "animate", { + onComplete: function() { + alert('completed!'); + } + }); + (end code) + */ + switchPosition: function(pos, method, onComplete) { + var Geom = this.geom, Plot = this.fx, that = this; + if(!Plot.busy) { + Plot.busy = true; + this.contract({ + onComplete: function() { + Geom.switchOrientation(pos); + that.compute('end', false); + Plot.busy = false; + if(method == 'animate') { + that.onClick(that.clickedNode.id, onComplete); + } else if(method == 'replot') { + that.select(that.clickedNode.id, onComplete); + } + } + }, pos); + } + }, + + /* + Method: switchAlignment + + Switches the tree alignment. + + Parameters: + + align - (string) The new tree alignment. Possible values are "left", "center" and "right". + method - (string) Set this to "animate" if you want to animate the tree after aligning its position. You can also set this parameter to "replot" to just replot the subtree. + onComplete - (optional|object) This callback is called once the "switching" animation is complete. + + Example: + + (start code js) + st.switchAlignment("right", "animate", { + onComplete: function() { + alert('completed!'); + } + }); + (end code) + */ + switchAlignment: function(align, method, onComplete) { + this.config.align = align; + if(method == 'animate') { + this.select(this.clickedNode.id, onComplete); + } else if(method == 'replot') { + this.onClick(this.clickedNode.id, onComplete); + } + }, + + /* + Method: addNodeInPath + + Adds a node to the current path as selected node. The selected node will be visible (as in non-collapsed) at all times. + + + Parameters: + + id - (string) A id. + + Example: + + (start code js) + st.addNodeInPath("nodeId"); + (end code) + */ + addNodeInPath: function(id) { + nodesInPath.push(id); + this.select((this.clickedNode && this.clickedNode.id) || this.root); + }, + + /* + Method: clearNodesInPath + + Removes all nodes tagged as selected by the method. + + See also: + + + + Example: + + (start code js) + st.clearNodesInPath(); + (end code) + */ + clearNodesInPath: function(id) { + nodesInPath.length = 0; + this.select((this.clickedNode && this.clickedNode.id) || this.root); + }, + + /* + Method: refresh + + Computes positions and plots the tree. + + */ + refresh: function() { + this.reposition(); + this.select((this.clickedNode && this.clickedNode.id) || this.root); + }, + + reposition: function() { + this.graph.computeLevels(this.root, 0, "ignore"); + this.geom.setRightLevelToShow(this.clickedNode, this.canvas); + this.graph.eachNode(function(n) { + if(n.exist) n.drawn = true; + }); + this.compute('end'); + }, + + requestNodes: function(node, onComplete) { + var handler = $.merge(this.controller, onComplete), + lev = this.config.levelsToShow; + if(handler.request) { + var leaves = [], d = node._depth; + node.eachLevel(0, lev, function(n) { + if(n.drawn && + !n.anySubnode()) { + leaves.push(n); + n._level = lev - (n._depth - d); + } + }); + this.group.requestNodes(leaves, handler); + } + else + handler.onComplete(); + }, + + contract: function(onComplete, switched) { + var orn = this.config.orientation; + var Geom = this.geom, Group = this.group; + if(switched) Geom.switchOrientation(switched); + var nodes = getNodesToHide.call(this); + if(switched) Geom.switchOrientation(orn); + Group.contract(nodes, $.merge(this.controller, onComplete)); + }, + + move: function(node, onComplete) { + this.compute('end', false); + var move = onComplete.Move, offset = { + 'x': move.offsetX, + 'y': move.offsetY + }; + if(move.enable) { + this.geom.translate(node.endPos.add(offset).$scale(-1), "end"); + } + this.fx.animate($.merge(this.controller, { modes: ['linear'] }, onComplete)); + }, + + expand: function (node, onComplete) { + var nodeArray = getNodesToShow.call(this, node); + this.group.expand(nodeArray, $.merge(this.controller, onComplete)); + }, + + selectPath: function(node) { + var that = this; + this.graph.eachNode(function(n) { n.selected = false; }); + function path(node) { + if(node == null || node.selected) return; + node.selected = true; + $.each(that.group.getSiblings([node])[node.id], + function(n) { + n.exist = true; + n.drawn = true; + }); + var parents = node.getParents(); + parents = (parents.length > 0)? parents[0] : null; + path(parents); + }; + for(var i=0, ns = [node.id].concat(nodesInPath); i < ns.length; i++) { + path(this.graph.getNode(ns[i])); + } + }, + + /* + Method: setRoot + + Switches the current root node. Changes the topology of the Tree. + + Parameters: + id - (string) The id of the node to be set as root. + method - (string) Set this to "animate" if you want to animate the tree after adding the subtree. You can also set this parameter to "replot" to just replot the subtree. + onComplete - (optional|object) An action to perform after the animation (if any). + + Example: + + (start code js) + st.setRoot('nodeId', 'animate', { + onComplete: function() { + alert('complete!'); + } + }); + (end code) + */ + setRoot: function(id, method, onComplete) { + if(this.busy) return; + this.busy = true; + var that = this, canvas = this.canvas; + var rootNode = this.graph.getNode(this.root); + var clickedNode = this.graph.getNode(id); + function $setRoot() { + if(this.config.multitree && clickedNode.data.$orn) { + var orn = clickedNode.data.$orn; + var opp = { + 'left': 'right', + 'right': 'left', + 'top': 'bottom', + 'bottom': 'top' + }[orn]; + rootNode.data.$orn = opp; + (function tag(rootNode) { + rootNode.eachSubnode(function(n) { + if(n.id != id) { + n.data.$orn = opp; + tag(n); + } + }); + })(rootNode); + delete clickedNode.data.$orn; + } + this.root = id; + this.clickedNode = clickedNode; + this.graph.computeLevels(this.root, 0, "ignore"); + this.geom.setRightLevelToShow(clickedNode, canvas, { + execHide: false, + onShow: function(node) { + if(!node.drawn) { + node.drawn = true; + node.setData('alpha', 1, 'end'); + node.setData('alpha', 0); + node.pos.setc(clickedNode.pos.x, clickedNode.pos.y); + } + } + }); + this.compute('end'); + this.busy = true; + this.fx.animate({ + modes: ['linear', 'node-property:alpha'], + onComplete: function() { + that.busy = false; + that.onClick(id, { + onComplete: function() { + onComplete && onComplete.onComplete(); + } + }); + } + }); + } + + // delete previous orientations (if any) + delete rootNode.data.$orns; + + if(method == 'animate') { + $setRoot.call(this); + that.selectPath(clickedNode); + } else if(method == 'replot') { + $setRoot.call(this); + this.select(this.root); + } + }, + + /* + Method: addSubtree + + Adds a subtree. + + Parameters: + subtree - (object) A JSON Tree object. See also . + method - (string) Set this to "animate" if you want to animate the tree after adding the subtree. You can also set this parameter to "replot" to just replot the subtree. + onComplete - (optional|object) An action to perform after the animation (if any). + + Example: + + (start code js) + st.addSubtree(json, 'animate', { + onComplete: function() { + alert('complete!'); + } + }); + (end code) + */ + addSubtree: function(subtree, method, onComplete) { + if(method == 'replot') { + this.op.sum(subtree, $.extend({ type: 'replot' }, onComplete || {})); + } else if (method == 'animate') { + this.op.sum(subtree, $.extend({ type: 'fade:seq' }, onComplete || {})); + } + }, + + /* + Method: removeSubtree + + Removes a subtree. + + Parameters: + id - (string) The _id_ of the subtree to be removed. + removeRoot - (boolean) Default's *false*. Remove the root of the subtree or only its subnodes. + method - (string) Set this to "animate" if you want to animate the tree after removing the subtree. You can also set this parameter to "replot" to just replot the subtree. + onComplete - (optional|object) An action to perform after the animation (if any). + + Example: + + (start code js) + st.removeSubtree('idOfSubtreeToBeRemoved', false, 'animate', { + onComplete: function() { + alert('complete!'); + } + }); + (end code) + + */ + removeSubtree: function(id, removeRoot, method, onComplete) { + var node = this.graph.getNode(id), subids = []; + node.eachLevel(+!removeRoot, false, function(n) { + subids.push(n.id); + }); + if(method == 'replot') { + this.op.removeNode(subids, $.extend({ type: 'replot' }, onComplete || {})); + } else if (method == 'animate') { + this.op.removeNode(subids, $.extend({ type: 'fade:seq'}, onComplete || {})); + } + }, + + /* + Method: select + + Selects a node in the without performing an animation. Useful when selecting + nodes which are currently hidden or deep inside the tree. + + Parameters: + id - (string) The id of the node to select. + onComplete - (optional|object) an onComplete callback. + + Example: + (start code js) + st.select('mynodeid', { + onComplete: function() { + alert('complete!'); + } + }); + (end code) + */ + select: function(id, onComplete) { + var group = this.group, geom = this.geom; + var node= this.graph.getNode(id), canvas = this.canvas; + var root = this.graph.getNode(this.root); + var complete = $.merge(this.controller, onComplete); + var that = this; + + complete.onBeforeCompute(node); + this.selectPath(node); + this.clickedNode= node; + this.requestNodes(node, { + onComplete: function(){ + group.hide(group.prepare(getNodesToHide.call(that)), complete); + geom.setRightLevelToShow(node, canvas); + that.compute("current"); + that.graph.eachNode(function(n) { + var pos = n.pos.getc(true); + n.startPos.setc(pos.x, pos.y); + n.endPos.setc(pos.x, pos.y); + n.visited = false; + }); + var offset = { x: complete.offsetX, y: complete.offsetY }; + that.geom.translate(node.endPos.add(offset).$scale(-1), ["start", "current", "end"]); + group.show(getNodesToShow.call(that)); + that.plot(); + complete.onAfterCompute(that.clickedNode); + complete.onComplete(); + } + }); + }, + + /* + Method: onClick + + Animates the to center the node specified by *id*. + + Parameters: + + id - (string) A node id. + options - (optional|object) A group of options and callbacks described below. + onComplete - (object) An object callback called when the animation finishes. + Move - (object) An object that has as properties _offsetX_ or _offsetY_ for adding some offset position to the centered node. + + Example: + + (start code js) + st.onClick('mynodeid', { + Move: { + enable: true, + offsetX: 30, + offsetY: 5 + }, + onComplete: function() { + alert('yay!'); + } + }); + (end code) + + */ + onClick: function (id, options) { + var canvas = this.canvas, that = this, Geom = this.geom, config = this.config; + var innerController = { + Move: { + enable: true, + offsetX: config.offsetX || 0, + offsetY: config.offsetY || 0 + }, + setRightLevelToShowConfig: false, + onBeforeRequest: $.empty, + onBeforeContract: $.empty, + onBeforeMove: $.empty, + onBeforeExpand: $.empty + }; + var complete = $.merge(this.controller, innerController, options); + + if(!this.busy) { + this.busy = true; + var node = this.graph.getNode(id); + this.selectPath(node, this.clickedNode); + this.clickedNode = node; + complete.onBeforeCompute(node); + complete.onBeforeRequest(node); + this.requestNodes(node, { + onComplete: function() { + complete.onBeforeContract(node); + that.contract({ + onComplete: function() { + Geom.setRightLevelToShow(node, canvas, complete.setRightLevelToShowConfig); + complete.onBeforeMove(node); + that.move(node, { + Move: complete.Move, + onComplete: function() { + complete.onBeforeExpand(node); + that.expand(node, { + onComplete: function() { + that.busy = false; + complete.onAfterCompute(id); + complete.onComplete(); + } + }); // expand + } + }); // move + } + });// contract + } + });// request + } + } + }); + +})(); + +$jit.ST.$extend = true; + +/* + Class: ST.Op + + Custom extension of . + + Extends: + + All methods + + See also: + + + +*/ +$jit.ST.Op = new Class({ + + Implements: Graph.Op + +}); + +/* + + Performs operations on group of nodes. + +*/ +$jit.ST.Group = new Class({ + + initialize: function(viz) { + this.viz = viz; + this.canvas = viz.canvas; + this.config = viz.config; + this.animation = new Animation; + this.nodes = null; + }, + + /* + + Calls the request method on the controller to request a subtree for each node. + */ + requestNodes: function(nodes, controller) { + var counter = 0, len = nodes.length, nodeSelected = {}; + var complete = function() { controller.onComplete(); }; + var viz = this.viz; + if(len == 0) complete(); + for(var i=0; i= b._depth); }); + for(var i=0; i 0 + && n.drawn) { + n.drawn = false; + nds[node.id].push(n); + } else if((!root || !orns) && n.drawn) { + n.drawn = false; + nds[node.id].push(n); + } + }); + node.drawn = true; + } + // plot the whole (non-scaled) tree + if(nodes.length > 0) viz.fx.plot(); + // show nodes that were previously hidden + for(i in nds) { + $.each(nds[i], function(n) { n.drawn = true; }); + } + // plot each scaled subtree + for(i=0; i method + (end code) + +*/ + +$jit.ST.Geom = new Class({ + Implements: Graph.Geom, + /* + Changes the tree current orientation to the one specified. + + You should usually use instead. + */ + switchOrientation: function(orn) { + this.config.orientation = orn; + }, + + /* + Makes a value dispatch according to the current layout + Works like a CSS property, either _top-right-bottom-left_ or _top|bottom - left|right_. + */ + dispatch: function() { + // TODO(nico) should store Array.prototype.slice.call somewhere. + var args = Array.prototype.slice.call(arguments); + var s = args.shift(), len = args.length; + var val = function(a) { return typeof a == 'function'? a() : a; }; + if(len == 2) { + return (s == "top" || s == "bottom")? val(args[0]) : val(args[1]); + } else if(len == 4) { + switch(s) { + case "top": return val(args[0]); + case "right": return val(args[1]); + case "bottom": return val(args[2]); + case "left": return val(args[3]); + } + } + return undefined; + }, + + /* + Returns label height or with, depending on the tree current orientation. + */ + getSize: function(n, invert) { + var data = n.data, config = this.config; + var siblingOffset = config.siblingOffset; + var s = (config.multitree + && ('$orn' in data) + && data.$orn) || config.orientation; + var w = n.getData('width') + siblingOffset; + var h = n.getData('height') + siblingOffset; + if(!invert) + return this.dispatch(s, h, w); + else + return this.dispatch(s, w, h); + }, + + /* + Calculates a subtree base size. This is an utility function used by _getBaseSize_ + */ + getTreeBaseSize: function(node, level, leaf) { + var size = this.getSize(node, true), baseHeight = 0, that = this; + if(leaf(level, node)) return size; + if(level === 0) return 0; + node.eachSubnode(function(elem) { + baseHeight += that.getTreeBaseSize(elem, level -1, leaf); + }); + return (size > baseHeight? size : baseHeight) + this.config.subtreeOffset; + }, + + + /* + getEdge + + Returns a Complex instance with the begin or end position of the edge to be plotted. + + Parameters: + + node - A that is connected to this edge. + type - Returns the begin or end edge position. Possible values are 'begin' or 'end'. + + Returns: + + A number specifying the begin or end position. + */ + getEdge: function(node, type, s) { + var $C = function(a, b) { + return function(){ + return node.pos.add(new Complex(a, b)); + }; + }; + var dim = this.node; + var w = node.getData('width'); + var h = node.getData('height'); + + if(type == 'begin') { + if(dim.align == "center") { + return this.dispatch(s, $C(0, h/2), $C(-w/2, 0), + $C(0, -h/2),$C(w/2, 0)); + } else if(dim.align == "left") { + return this.dispatch(s, $C(0, h), $C(0, 0), + $C(0, 0), $C(w, 0)); + } else if(dim.align == "right") { + return this.dispatch(s, $C(0, 0), $C(-w, 0), + $C(0, -h),$C(0, 0)); + } else throw "align: not implemented"; + + + } else if(type == 'end') { + if(dim.align == "center") { + return this.dispatch(s, $C(0, -h/2), $C(w/2, 0), + $C(0, h/2), $C(-w/2, 0)); + } else if(dim.align == "left") { + return this.dispatch(s, $C(0, 0), $C(w, 0), + $C(0, h), $C(0, 0)); + } else if(dim.align == "right") { + return this.dispatch(s, $C(0, -h),$C(0, 0), + $C(0, 0), $C(-w, 0)); + } else throw "align: not implemented"; + } + }, + + /* + Adjusts the tree position due to canvas scaling or translation. + */ + getScaledTreePosition: function(node, scale) { + var dim = this.node; + var w = node.getData('width'); + var h = node.getData('height'); + var s = (this.config.multitree + && ('$orn' in node.data) + && node.data.$orn) || this.config.orientation; + + var $C = function(a, b) { + return function(){ + return node.pos.add(new Complex(a, b)).$scale(1 - scale); + }; + }; + if(dim.align == "left") { + return this.dispatch(s, $C(0, h), $C(0, 0), + $C(0, 0), $C(w, 0)); + } else if(dim.align == "center") { + return this.dispatch(s, $C(0, h / 2), $C(-w / 2, 0), + $C(0, -h / 2),$C(w / 2, 0)); + } else if(dim.align == "right") { + return this.dispatch(s, $C(0, 0), $C(-w, 0), + $C(0, -h),$C(0, 0)); + } else throw "align: not implemented"; + }, + + /* + treeFitsInCanvas + + Returns a Boolean if the current subtree fits in canvas. + + Parameters: + + node - A which is the current root of the subtree. + canvas - The object. + level - The depth of the subtree to be considered. + */ + treeFitsInCanvas: function(node, canvas, level) { + var csize = canvas.getSize(); + var s = (this.config.multitree + && ('$orn' in node.data) + && node.data.$orn) || this.config.orientation; + + var size = this.dispatch(s, csize.width, csize.height); + var baseSize = this.getTreeBaseSize(node, level, function(level, node) { + return level === 0 || !node.anySubnode(); + }); + return (baseSize < size); + } +}); + +/* + Class: ST.Plot + + Custom extension of . + + Extends: + + All methods + + See also: + + + +*/ +$jit.ST.Plot = new Class({ + + Implements: Graph.Plot, + + /* + Plots a subtree from the spacetree. + */ + plotSubtree: function(node, opt, scale, animating) { + var viz = this.viz, canvas = viz.canvas, config = viz.config; + scale = Math.min(Math.max(0.001, scale), 1); + if(scale >= 0) { + node.drawn = false; + var ctx = canvas.getCtx(); + var diff = viz.geom.getScaledTreePosition(node, scale); + ctx.translate(diff.x, diff.y); + ctx.scale(scale, scale); + } + this.plotTree(node, $.merge(opt, { + 'withLabels': true, + 'hideLabels': !!scale, + 'plotSubtree': function(n, ch) { + var root = config.multitree && !('$orn' in node.data); + var orns = root && node.getData('orns'); + return !root || orns.indexOf(elem.getData('orn')) > -1; + } + }), animating); + if(scale >= 0) node.drawn = true; + }, + + /* + Method: getAlignedPos + + Returns a *x, y* object with the position of the top/left corner of a node. + + Parameters: + + pos - (object) A position. + width - (number) The width of the node. + height - (number) The height of the node. + + */ + getAlignedPos: function(pos, width, height) { + var nconfig = this.node; + var square, orn; + if(nconfig.align == "center") { + square = { + x: pos.x - width / 2, + y: pos.y - height / 2 + }; + } else if (nconfig.align == "left") { + orn = this.config.orientation; + if(orn == "bottom" || orn == "top") { + square = { + x: pos.x - width / 2, + y: pos.y + }; + } else { + square = { + x: pos.x, + y: pos.y - height / 2 + }; + } + } else if(nconfig.align == "right") { + orn = this.config.orientation; + if(orn == "bottom" || orn == "top") { + square = { + x: pos.x - width / 2, + y: pos.y - height + }; + } else { + square = { + x: pos.x - width, + y: pos.y - height / 2 + }; + } + } else throw "align: not implemented"; + + return square; + }, + + getOrientation: function(adj) { + var config = this.config; + var orn = config.orientation; + + if(config.multitree) { + var nodeFrom = adj.nodeFrom; + var nodeTo = adj.nodeTo; + orn = (('$orn' in nodeFrom.data) + && nodeFrom.data.$orn) + || (('$orn' in nodeTo.data) + && nodeTo.data.$orn); + } + + return orn; + } +}); + +/* + Class: ST.Label + + Custom extension of . + Contains custom , and extensions. + + Extends: + + All methods and subclasses. + + See also: + + , , , . + */ +$jit.ST.Label = {}; + +/* + ST.Label.Native + + Custom extension of . + + Extends: + + All methods + + See also: + + +*/ +$jit.ST.Label.Native = new Class({ + Implements: Graph.Label.Native, + + renderLabel: function(canvas, node, controller) { + var ctx = canvas.getCtx(); + var coord = node.pos.getc(true); + ctx.fillText(node.name, coord.x, coord.y); + } +}); + +$jit.ST.Label.DOM = new Class({ + Implements: Graph.Label.DOM, + + /* + placeLabel + + Overrides abstract method placeLabel in . + + Parameters: + + tag - A DOM label element. + node - A . + controller - A configuration/controller object passed to the visualization. + + */ + placeLabel: function(tag, node, controller) { + var pos = node.pos.getc(true), + config = this.viz.config, + dim = config.Node, + canvas = this.viz.canvas, + w = node.getData('width'), + h = node.getData('height'), + radius = canvas.getSize(), + labelPos, orn; + + var ox = canvas.translateOffsetX, + oy = canvas.translateOffsetY, + sx = canvas.scaleOffsetX, + sy = canvas.scaleOffsetY, + posx = pos.x * sx + ox, + posy = pos.y * sy + oy; + + if(dim.align == "center") { + labelPos= { + x: Math.round(posx - w / 2 + radius.width/2), + y: Math.round(posy - h / 2 + radius.height/2) + }; + } else if (dim.align == "left") { + orn = config.orientation; + if(orn == "bottom" || orn == "top") { + labelPos= { + x: Math.round(posx - w / 2 + radius.width/2), + y: Math.round(posy + radius.height/2) + }; + } else { + labelPos= { + x: Math.round(posx + radius.width/2), + y: Math.round(posy - h / 2 + radius.height/2) + }; + } + } else if(dim.align == "right") { + orn = config.orientation; + if(orn == "bottom" || orn == "top") { + labelPos= { + x: Math.round(posx - w / 2 + radius.width/2), + y: Math.round(posy - h + radius.height/2) + }; + } else { + labelPos= { + x: Math.round(posx - w + radius.width/2), + y: Math.round(posy - h / 2 + radius.height/2) + }; + } + } else throw "align: not implemented"; + + var style = tag.style; + style.left = labelPos.x + 'px'; + style.top = labelPos.y + 'px'; + style.display = this.fitsInCanvas(labelPos, canvas)? '' : 'none'; + controller.onPlaceLabel(tag, node); + } +}); + +/* + ST.Label.SVG + + Custom extension of . + + Extends: + + All methods + + See also: + + +*/ +$jit.ST.Label.SVG = new Class({ + Implements: [$jit.ST.Label.DOM, Graph.Label.SVG], + + initialize: function(viz) { + this.viz = viz; + } +}); + +/* + ST.Label.HTML + + Custom extension of . + + Extends: + + All methods. + + See also: + + + +*/ +$jit.ST.Label.HTML = new Class({ + Implements: [$jit.ST.Label.DOM, Graph.Label.HTML], + + initialize: function(viz) { + this.viz = viz; + } +}); + + +/* + Class: ST.Plot.NodeTypes + + This class contains a list of built-in types. + Node types implemented are 'none', 'circle', 'rectangle', 'ellipse' and 'square'. + + You can add your custom node types, customizing your visualization to the extreme. + + Example: + + (start code js) + ST.Plot.NodeTypes.implement({ + 'mySpecialType': { + 'render': function(node, canvas) { + //print your custom node to canvas + }, + //optional + 'contains': function(node, pos) { + //return true if pos is inside the node or false otherwise + } + } + }); + (end code) + +*/ +$jit.ST.Plot.NodeTypes = new Class({ + 'none': { + 'render': $.empty, + 'contains': $.lambda(false) + }, + 'circle': { + 'render': function(node, canvas) { + var dim = node.getData('dim'), + pos = this.getAlignedPos(node.pos.getc(true), dim, dim), + dim2 = dim/2; + this.nodeHelper.circle.render('fill', {x:pos.x+dim2, y:pos.y+dim2}, dim2, canvas); + }, + 'contains': function(node, pos) { + var dim = node.getData('dim'), + npos = this.getAlignedPos(node.pos.getc(true), dim, dim), + dim2 = dim/2; + this.nodeHelper.circle.contains({x:npos.x+dim2, y:npos.y+dim2}, dim2); + } + }, + 'square': { + 'render': function(node, canvas) { + var dim = node.getData('dim'), + dim2 = dim/2, + pos = this.getAlignedPos(node.pos.getc(true), dim, dim); + this.nodeHelper.square.render('fill', {x:pos.x+dim2, y:pos.y+dim2}, dim2, canvas); + }, + 'contains': function(node, pos) { + var dim = node.getData('dim'), + npos = this.getAlignedPos(node.pos.getc(true), dim, dim), + dim2 = dim/2; + this.nodeHelper.square.contains({x:npos.x+dim2, y:npos.y+dim2}, dim2); + } + }, + 'ellipse': { + 'render': function(node, canvas) { + var width = node.getData('width'), + height = node.getData('height'), + pos = this.getAlignedPos(node.pos.getc(true), width, height); + this.nodeHelper.ellipse.render('fill', {x:pos.x+width/2, y:pos.y+height/2}, width, height, canvas); + }, + 'contains': function(node, pos) { + var width = node.getData('width'), + height = node.getData('height'), + npos = this.getAlignedPos(node.pos.getc(true), width, height); + this.nodeHelper.ellipse.contains({x:npos.x+width/2, y:npos.y+height/2}, width, height, canvas); + } + }, + 'rectangle': { + 'render': function(node, canvas) { + var width = node.getData('width'), + height = node.getData('height'), + pos = this.getAlignedPos(node.pos.getc(true), width, height); + this.nodeHelper.rectangle.render('fill', {x:pos.x+width/2, y:pos.y+height/2}, width, height, canvas); + }, + 'contains': function(node, pos) { + var width = node.getData('width'), + height = node.getData('height'), + npos = this.getAlignedPos(node.pos.getc(true), width, height); + this.nodeHelper.rectangle.contains({x:npos.x+width/2, y:npos.y+height/2}, width, height, canvas); + } + } +}); + +/* + Class: ST.Plot.EdgeTypes + + This class contains a list of built-in types. + Edge types implemented are 'none', 'line', 'arrow', 'quadratic:begin', 'quadratic:end', 'bezier'. + + You can add your custom edge types, customizing your visualization to the extreme. + + Example: + + (start code js) + ST.Plot.EdgeTypes.implement({ + 'mySpecialType': { + 'render': function(adj, canvas) { + //print your custom edge to canvas + }, + //optional + 'contains': function(adj, pos) { + //return true if pos is inside the arc or false otherwise + } + } + }); + (end code) + +*/ +$jit.ST.Plot.EdgeTypes = new Class({ + 'none': $.empty, + 'line': { + 'render': function(adj, canvas) { + var orn = this.getOrientation(adj), + nodeFrom = adj.nodeFrom, + nodeTo = adj.nodeTo, + rel = nodeFrom._depth < nodeTo._depth, + from = this.viz.geom.getEdge(rel? nodeFrom:nodeTo, 'begin', orn), + to = this.viz.geom.getEdge(rel? nodeTo:nodeFrom, 'end', orn); + this.edgeHelper.line.render(from, to, canvas); + }, + 'contains': function(adj, pos) { + var orn = this.getOrientation(adj), + nodeFrom = adj.nodeFrom, + nodeTo = adj.nodeTo, + rel = nodeFrom._depth < nodeTo._depth, + from = this.viz.geom.getEdge(rel? nodeFrom:nodeTo, 'begin', orn), + to = this.viz.geom.getEdge(rel? nodeTo:nodeFrom, 'end', orn); + return this.edgeHelper.line.contains(from, to, pos, this.edge.epsilon); + } + }, + 'arrow': { + 'render': function(adj, canvas) { + var orn = this.getOrientation(adj), + node = adj.nodeFrom, + child = adj.nodeTo, + dim = adj.getData('dim'), + from = this.viz.geom.getEdge(node, 'begin', orn), + to = this.viz.geom.getEdge(child, 'end', orn), + direction = adj.data.$direction, + inv = (direction && direction.length>1 && direction[0] != node.id); + this.edgeHelper.arrow.render(from, to, dim, inv, canvas); + }, + 'contains': function(adj, pos) { + var orn = this.getOrientation(adj), + nodeFrom = adj.nodeFrom, + nodeTo = adj.nodeTo, + rel = nodeFrom._depth < nodeTo._depth, + from = this.viz.geom.getEdge(rel? nodeFrom:nodeTo, 'begin', orn), + to = this.viz.geom.getEdge(rel? nodeTo:nodeFrom, 'end', orn); + return this.edgeHelper.arrow.contains(from, to, pos, this.edge.epsilon); + } + }, + 'quadratic:begin': { + 'render': function(adj, canvas) { + var orn = this.getOrientation(adj); + var nodeFrom = adj.nodeFrom, + nodeTo = adj.nodeTo, + rel = nodeFrom._depth < nodeTo._depth, + begin = this.viz.geom.getEdge(rel? nodeFrom:nodeTo, 'begin', orn), + end = this.viz.geom.getEdge(rel? nodeTo:nodeFrom, 'end', orn), + dim = adj.getData('dim'), + ctx = canvas.getCtx(); + ctx.beginPath(); + ctx.moveTo(begin.x, begin.y); + switch(orn) { + case "left": + ctx.quadraticCurveTo(begin.x + dim, begin.y, end.x, end.y); + break; + case "right": + ctx.quadraticCurveTo(begin.x - dim, begin.y, end.x, end.y); + break; + case "top": + ctx.quadraticCurveTo(begin.x, begin.y + dim, end.x, end.y); + break; + case "bottom": + ctx.quadraticCurveTo(begin.x, begin.y - dim, end.x, end.y); + break; + } + ctx.stroke(); + } + }, + 'quadratic:end': { + 'render': function(adj, canvas) { + var orn = this.getOrientation(adj); + var nodeFrom = adj.nodeFrom, + nodeTo = adj.nodeTo, + rel = nodeFrom._depth < nodeTo._depth, + begin = this.viz.geom.getEdge(rel? nodeFrom:nodeTo, 'begin', orn), + end = this.viz.geom.getEdge(rel? nodeTo:nodeFrom, 'end', orn), + dim = adj.getData('dim'), + ctx = canvas.getCtx(); + ctx.beginPath(); + ctx.moveTo(begin.x, begin.y); + switch(orn) { + case "left": + ctx.quadraticCurveTo(end.x - dim, end.y, end.x, end.y); + break; + case "right": + ctx.quadraticCurveTo(end.x + dim, end.y, end.x, end.y); + break; + case "top": + ctx.quadraticCurveTo(end.x, end.y - dim, end.x, end.y); + break; + case "bottom": + ctx.quadraticCurveTo(end.x, end.y + dim, end.x, end.y); + break; + } + ctx.stroke(); + } + }, + 'bezier': { + 'render': function(adj, canvas) { + var orn = this.getOrientation(adj), + nodeFrom = adj.nodeFrom, + nodeTo = adj.nodeTo, + rel = nodeFrom._depth < nodeTo._depth, + begin = this.viz.geom.getEdge(rel? nodeFrom:nodeTo, 'begin', orn), + end = this.viz.geom.getEdge(rel? nodeTo:nodeFrom, 'end', orn), + dim = adj.getData('dim'), + ctx = canvas.getCtx(); + ctx.beginPath(); + ctx.moveTo(begin.x, begin.y); + switch(orn) { + case "left": + ctx.bezierCurveTo(begin.x + dim, begin.y, end.x - dim, end.y, end.x, end.y); + break; + case "right": + ctx.bezierCurveTo(begin.x - dim, begin.y, end.x + dim, end.y, end.x, end.y); + break; + case "top": + ctx.bezierCurveTo(begin.x, begin.y + dim, end.x, end.y - dim, end.x, end.y); + break; + case "bottom": + ctx.bezierCurveTo(begin.x, begin.y - dim, end.x, end.y + dim, end.x, end.y); + break; + } + ctx.stroke(); + } + } +}); + + +Options.LineChart = { + $extend: true, + + animate: false, + labelOffset: 3, // label offset + type: 'basic', // gradient + dataPointSize: 10, + Tips: { + enable: false, + onShow: $.empty, + onHide: $.empty + }, + Ticks: { + enable: false, + segments: 4, + color: '#000000' + }, + Events: { + enable: false, + onClick: $.empty + }, + selectOnHover: true, + showAggregates: true, + showLabels: true, + filterOnClick: false, + restoreOnRightClick: false +}; + + +/* + * File: LineChart.js + * +*/ + +$jit.ST.Plot.NodeTypes.implement({ + 'linechart-basic' : { + 'render' : function(node, canvas) { + var pos = node.pos.getc(true), + width = node.getData('width'), + height = node.getData('height'), + algnPos = this.getAlignedPos(pos, width, height), + x = algnPos.x + width/2 , y = algnPos.y, + stringArray = node.getData('stringArray'), + lastNode = node.getData('lastNode'), + dimArray = node.getData('dimArray'), + valArray = node.getData('valueArray'), + colorArray = node.getData('colorArray'), + colorLength = colorArray.length, + config = node.getData('config'), + gradient = node.getData('gradient'), + showLabels = config.showLabels, + aggregates = config.showAggregates, + label = config.Label, + prev = node.getData('prev'), + dataPointSize = config.dataPointSize; + + var ctx = canvas.getCtx(), border = node.getData('border'); + if (colorArray && dimArray && stringArray) { + + for (var i=0, l=dimArray.length, acumLeft=0, acumRight=0, valAcum=0; i x + dataPointMidPoint) { + return false; + } + //deep check + for(var i=0, l=dimArray.length; i= x - dataPointMidPoint && mpos.x <= x + dataPointMidPoint && mpos.y >= y - dimi[0] - dataPointMidPoint && mpos.y <= y - dimi[0] + dataPointMidPoint) { + var valArrayCur = node.getData('valArrayCur'); + var results = array_match(valArrayCur[i],valArrayCur); + var matches = results[0]; + var indexValues = results[1]; + if(matches > 1) { + var names = new Array(), + values = new Array(), + percentages = new Array(), + linksArr = new Array(); + for(var j=0, il=indexValues.length; j. + +*/ +$jit.LineChart = new Class({ + st: null, + colors: ["#416D9C", "#70A35E", "#EBB056", "#C74243", "#83548B", "#909291", "#557EAA"], + selected: {}, + busy: false, + + initialize: function(opt) { + this.controller = this.config = + $.merge(Options("Canvas", "Margin", "Label", "LineChart"), { + Label: { type: 'Native' } + }, opt); + //set functions for showLabels and showAggregates + var showLabels = this.config.showLabels, + typeLabels = $.type(showLabels), + showAggregates = this.config.showAggregates, + typeAggregates = $.type(showAggregates); + this.config.showLabels = typeLabels == 'function'? showLabels : $.lambda(showLabels); + this.config.showAggregates = typeAggregates == 'function'? showAggregates : $.lambda(showAggregates); + Options.Fx.clearCanvas = false; + this.initializeViz(); + }, + + initializeViz: function() { + var config = this.config, + that = this, + nodeType = config.type.split(":")[0], + nodeLabels = {}; + + var st = new $jit.ST({ + injectInto: config.injectInto, + orientation: "bottom", + backgroundColor: config.backgroundColor, + renderBackground: config.renderBackground, + levelDistance: 0, + siblingOffset: 0, + subtreeOffset: 0, + withLabels: config.Label.type != 'Native', + useCanvas: config.useCanvas, + Label: { + type: config.Label.type + }, + Node: { + overridable: true, + type: 'linechart-' + nodeType, + align: 'left', + width: 1, + height: 1 + }, + Edge: { + type: 'none' + }, + Tips: { + enable: config.Tips.enable, + type: 'Native', + force: true, + onShow: function(tip, node, contains) { + var elem = contains; + config.Tips.onShow(tip, elem, node); + } + }, + Events: { + enable: true, + type: 'Native', + onClick: function(node, eventInfo, evt) { + if(!config.filterOnClick && !config.Events.enable) return; + var elem = eventInfo.getContains(); + if(elem) config.filterOnClick && that.filter(elem.name); + config.Events.enable && config.Events.onClick(elem, eventInfo, evt); + }, + onRightClick: function(node, eventInfo, evt) { + if(!config.restoreOnRightClick) return; + that.restore(); + }, + onMouseMove: function(node, eventInfo, evt) { + if(!config.selectOnHover) return; + if(node) { + var elem = eventInfo.getContains(); + that.select(node.id, elem.name, elem.index); + } else { + that.select(false, false, false); + } + } + }, + onCreateLabel: function(domElement, node) { + var labelConf = config.Label, + valueArray = node.getData('valueArray'), + acumLeft = $.reduce(valueArray, function(x, y) { return x + y[0]; }, 0), + acumRight = $.reduce(valueArray, function(x, y) { return x + y[1]; }, 0); + if(node.getData('prev')) { + var nlbs = { + wrapper: document.createElement('div'), + aggregate: document.createElement('div'), + label: document.createElement('div') + }; + var wrapper = nlbs.wrapper, + label = nlbs.label, + aggregate = nlbs.aggregate, + wrapperStyle = wrapper.style, + labelStyle = label.style, + aggregateStyle = aggregate.style; + //store node labels + nodeLabels[node.id] = nlbs; + //append labels + wrapper.appendChild(label); + wrapper.appendChild(aggregate); + if(!config.showLabels(node.name, acumLeft, acumRight, node)) { + label.style.display = 'none'; + } + if(!config.showAggregates(node.name, acumLeft, acumRight, node)) { + aggregate.style.display = 'none'; + } + wrapperStyle.position = 'relative'; + wrapperStyle.overflow = 'visible'; + wrapperStyle.fontSize = labelConf.size + 'px'; + wrapperStyle.fontFamily = labelConf.family; + wrapperStyle.color = labelConf.color; + wrapperStyle.textAlign = 'center'; + aggregateStyle.position = labelStyle.position = 'absolute'; + + domElement.style.width = node.getData('width') + 'px'; + domElement.style.height = node.getData('height') + 'px'; + label.innerHTML = node.name; + + domElement.appendChild(wrapper); + } + }, + onPlaceLabel: function(domElement, node) { + if(!node.getData('prev')) return; + var labels = nodeLabels[node.id], + wrapperStyle = labels.wrapper.style, + labelStyle = labels.label.style, + aggregateStyle = labels.aggregate.style, + width = node.getData('width'), + height = node.getData('height'), + dimArray = node.getData('dimArray'), + valArray = node.getData('valueArray'), + acumLeft = $.reduce(valArray, function(x, y) { return x + y[0]; }, 0), + acumRight = $.reduce(valArray, function(x, y) { return x + y[1]; }, 0), + font = parseInt(wrapperStyle.fontSize, 10), + domStyle = domElement.style; + + if(dimArray && valArray) { + if(config.showLabels(node.name, acumLeft, acumRight, node)) { + labelStyle.display = ''; + } else { + labelStyle.display = 'none'; + } + if(config.showAggregates(node.name, acumLeft, acumRight, node)) { + aggregateStyle.display = ''; + } else { + aggregateStyle.display = 'none'; + } + wrapperStyle.width = aggregateStyle.width = labelStyle.width = domElement.style.width = width + 'px'; + aggregateStyle.left = labelStyle.left = -width/2 + 'px'; + for(var i=0, l=valArray.length, acum=0, leftAcum=0; i 0) { + acum+= valArray[i][0]; + leftAcum+= dimArray[i][0]; + } + } + aggregateStyle.top = (-font - config.labelOffset) + 'px'; + labelStyle.top = (config.labelOffset + leftAcum) + 'px'; + domElement.style.top = parseInt(domElement.style.top, 10) - leftAcum + 'px'; + domElement.style.height = wrapperStyle.height = leftAcum + 'px'; + labels.aggregate.innerHTML = acum; + } + } + }); + + var size = st.canvas.getSize(), + margin = config.Margin; + st.config.offsetY = -size.height/2 + margin.bottom + + (config.showLabels && (config.labelOffset + config.Label.size)); + st.config.offsetX = (margin.right - margin.left - config.labelOffset - config.Label.size)/2; + this.st = st; + this.canvas = this.st.canvas; + }, + + renderTitle: function() { + var canvas = this.canvas, + size = canvas.getSize(), + config = this.config, + margin = config.Margin, + label = config.Label, + title = config.Title; + ctx = canvas.getCtx(); + ctx.fillStyle = title.color; + ctx.textAlign = 'left'; + ctx.textBaseline = 'top'; + ctx.font = label.style + ' bold ' +' ' + title.size + 'px ' + label.family; + if(label.type == 'Native') { + ctx.fillText(title.text, -size.width/2+margin.left, -size.height/2+margin.top); + } + }, + + renderTicks: function() { + + var canvas = this.canvas, + size = canvas.getSize(), + config = this.config, + margin = config.Margin, + ticks = config.Ticks, + title = config.Title, + subtitle = config.Subtitle, + label = config.Label, + maxValue = this.maxValue, + maxTickValue = Math.ceil(maxValue*.1)*10; + if(maxTickValue == maxValue) { + var length = maxTickValue.toString().length; + maxTickValue = maxTickValue + parseInt(pad(1,length)); + } + + + labelValue = 0, + labelIncrement = maxTickValue/ticks.segments, + ctx = canvas.getCtx(); + ctx.strokeStyle = ticks.color; + ctx.font = label.style + ' ' + label.size + 'px ' + label.family; + ctx.textAlign = 'center'; + ctx.textBaseline = 'middle'; + + idLabel = canvas.id + "-label"; + labelDim = 100; + container = document.getElementById(idLabel); + + + var axis = (size.height/2)-(margin.bottom+config.labelOffset+label.size+(subtitle.text? subtitle.size+subtitle.offset:0)), + htmlOrigin = size.height - (margin.bottom+config.labelOffset+label.size+(subtitle.text? subtitle.size+subtitle.offset:0)), + grid = -size.height+(margin.bottom+config.labelOffset+label.size+margin.top+(title.text? title.size+title.offset:0)+(subtitle.text? subtitle.size+subtitle.offset:0)), + segmentLength = grid/ticks.segments; + ctx.fillStyle = ticks.color; + ctx.fillRect(-(size.width/2)+margin.left+config.labelOffset+label.size-1, -(size.height/2)+margin.top+(title.text? title.size+title.offset:0),1,size.height-margin.top-margin.bottom-label.size-config.labelOffset-(title.text? title.size+title.offset:0)-(subtitle.text? subtitle.size+subtitle.offset:0)); + + while(axis>=grid) { + ctx.save(); + ctx.translate(-(size.width/2)+margin.left, Math.round(axis)); + ctx.rotate(Math.PI / 2); + ctx.fillStyle = label.color; + if(config.showLabels) { + if(label.type == 'Native') { + ctx.fillText(labelValue, 0, 0); + } else { + //html labels on y axis + labelDiv = document.createElement('div'); + labelDiv.innerHTML = labelValue; + labelDiv.className = "rotatedLabel"; +// labelDiv.class = "rotatedLabel"; + labelDiv.style.top = (htmlOrigin - (labelDim/2)) + "px"; + labelDiv.style.left = margin.left + "px"; + labelDiv.style.width = labelDim + "px"; + labelDiv.style.height = labelDim + "px"; + labelDiv.style.textAlign = "center"; + labelDiv.style.verticalAlign = "middle"; + labelDiv.style.position = "absolute"; + container.appendChild(labelDiv); + } + } + ctx.restore(); + ctx.fillStyle = ticks.color; + ctx.fillRect(-(size.width/2)+margin.left+config.labelOffset+label.size, Math.round(axis), size.width-margin.right-margin.left-config.labelOffset-label.size,1 ); + htmlOrigin += segmentLength; + axis += segmentLength; + labelValue += labelIncrement; + } + + + + + + + }, + + renderBackground: function() { + var canvas = this.canvas, + config = this.config, + backgroundColor = config.backgroundColor, + size = canvas.getSize(), + ctx = canvas.getCtx(); + //ctx.globalCompositeOperation = "destination-over"; + ctx.fillStyle = backgroundColor; + ctx.fillRect(-size.width/2,-size.height/2,size.width,size.height); + }, + + + /* + Method: loadJSON + + Loads JSON data into the visualization. + + Parameters: + + json - The JSON data format. This format is described in . + + Example: + (start code js) + var areaChart = new $jit.AreaChart(options); + areaChart.loadJSON(json); + (end code) + */ + loadJSON: function(json) { + var prefix = $.time(), + ch = [], + st = this.st, + name = $.splat(json.label), + color = $.splat(json.color || this.colors), + config = this.config, + ticks = config.Ticks, + renderBackground = config.renderBackground, + gradient = !!config.type.split(":")[1], + animate = config.animate, + title = config.Title, + groupTotalValue = 0; + + var valArrayAll = new Array(); + + for(var i=0, values=json.values, l=values.length; i. + onComplete - (object) A callback object to be called when the animation transition when updating the data end. + + Example: + + (start code js) + areaChart.updateJSON(json, { + onComplete: function() { + alert('update complete!'); + } + }); + (end code) + */ + updateJSON: function(json, onComplete) { + if(this.busy) return; + this.busy = true; + + var st = this.st, + graph = st.graph, + labels = json.label && $.splat(json.label), + values = json.values, + animate = this.config.animate, + that = this; + $.each(values, function(v) { + var n = graph.getByName(v.label); + if(n) { + v.values = $.splat(v.values); + var stringArray = n.getData('stringArray'), + valArray = n.getData('valueArray'); + $.each(valArray, function(a, i) { + a[0] = v.values[i]; + if(labels) stringArray[i] = labels[i]; + }); + n.setData('valueArray', valArray); + var prev = n.getData('prev'), + next = n.getData('next'), + nextNode = graph.getByName(next); + if(prev) { + var p = graph.getByName(prev); + if(p) { + var valArray = p.getData('valueArray'); + $.each(valArray, function(a, i) { + a[1] = v.values[i]; + }); + } + } + if(!nextNode) { + var valArray = n.getData('valueArray'); + $.each(valArray, function(a, i) { + a[1] = v.values[i]; + }); + } + } + }); + this.normalizeDims(); + st.compute(); + + st.select(st.root); + if(animate) { + st.fx.animate({ + modes: ['node-property:height:dimArray'], + duration:1500, + onComplete: function() { + that.busy = false; + onComplete && onComplete.onComplete(); + } + }); + } + }, + +/* + Method: filter + + Filter selected stacks, collapsing all other stacks. You can filter multiple stacks at the same time. + + Parameters: + + Variable strings arguments with the name of the stacks. + + Example: + + (start code js) + areaChart.filter('label A', 'label C'); + (end code) + + See also: + + . + */ + filter: function() { + if(this.busy) return; + this.busy = true; + if(this.config.Tips.enable) this.st.tips.hide(); + this.select(false, false, false); + var args = Array.prototype.slice.call(arguments); + var rt = this.st.graph.getNode(this.st.root); + var that = this; + rt.eachAdjacency(function(adj) { + var n = adj.nodeTo, + dimArray = n.getData('dimArray'), + stringArray = n.getData('stringArray'); + n.setData('dimArray', $.map(dimArray, function(d, i) { + return ($.indexOf(args, stringArray[i]) > -1)? d:[0, 0]; + }), 'end'); + }); + this.st.fx.animate({ + modes: ['node-property:dimArray'], + duration:1500, + onComplete: function() { + that.busy = false; + } + }); + }, + + /* + Method: restore + + Sets all stacks that could have been filtered visible. + + Example: + + (start code js) + areaChart.restore(); + (end code) + + See also: + + . + */ + restore: function() { + if(this.busy) return; + this.busy = true; + if(this.config.Tips.enable) this.st.tips.hide(); + this.select(false, false, false); + this.normalizeDims(); + var that = this; + this.st.fx.animate({ + modes: ['node-property:height:dimArray'], + duration:1500, + onComplete: function() { + that.busy = false; + } + }); + }, + //adds the little brown bar when hovering the node + select: function(id, name, index) { + if(!this.config.selectOnHover) return; + var s = this.selected; + if(s.id != id || s.name != name + || s.index != index) { + s.id = id; + s.name = name; + s.index = index; + this.st.graph.eachNode(function(n) { + n.setData('border', false); + }); + if(id) { + var n = this.st.graph.getNode(id); + n.setData('border', s); + var link = index === 0? 'prev':'next'; + link = n.getData(link); + if(link) { + n = this.st.graph.getByName(link); + if(n) { + n.setData('border', { + name: name, + index: 1-index + }); + } + } + } + this.st.plot(); + } + }, + + /* + Method: getLegend + + Returns an object containing as keys the legend names and as values hex strings with color values. + + Example: + + (start code js) + var legend = areaChart.getLegend(); + (end code) + */ + getLegend: function() { + var legend = new Array(); + var name = new Array(); + var color = new Array(); + var n; + this.st.graph.getNode(this.st.root).eachAdjacency(function(adj) { + n = adj.nodeTo; + }); + var colors = n.getData('colorArray'), + len = colors.length; + $.each(n.getData('stringArray'), function(s, i) { + color[i] = colors[i % len]; + name[i] = s; + }); + legend['name'] = name; + legend['color'] = color; + return legend; + }, + + /* + Method: getMaxValue + + Returns the maximum accumulated value for the stacks. This method is used for normalizing the graph heights according to the canvas height. + + Example: + + (start code js) + var ans = areaChart.getMaxValue(); + (end code) + + In some cases it could be useful to override this method to normalize heights for a group of AreaCharts, like when doing small multiples. + + Example: + + (start code js) + //will return 100 for all AreaChart instances, + //displaying all of them with the same scale + $jit.AreaChart.implement({ + 'getMaxValue': function() { + return 100; + } + }); + (end code) + +*/ + + normalizeDims: function() { + //number of elements + var root = this.st.graph.getNode(this.st.root), l=0; + root.eachAdjacency(function() { + l++; + }); + + + var maxValue = this.maxValue || 1, + size = this.st.canvas.getSize(), + config = this.config, + margin = config.Margin, + labelOffset = config.labelOffset + config.Label.size, + fixedDim = (size.width - (margin.left + margin.right + labelOffset )) / (l-1), + animate = config.animate, + ticks = config.Ticks, + height = size.height - (margin.top + margin.bottom) - (config.showAggregates && labelOffset) + - (config.showLabels && labelOffset); + + + var maxTickValue = Math.ceil(maxValue*.1)*10; + if(maxTickValue == maxValue) { + var length = maxTickValue.toString().length; + maxTickValue = maxTickValue + parseInt(pad(1,length)); + } + + + + this.st.graph.eachNode(function(n) { + var acumLeft = 0, acumRight = 0, animateValue = []; + $.each(n.getData('valueArray'), function(v) { + acumLeft += +v[0]; + acumRight += +v[1]; + animateValue.push([0, 0]); + }); + var acum = acumRight>acumLeft? acumRight:acumLeft; + + n.setData('width', fixedDim); + if(animate) { + n.setData('height', acum * height / maxValue, 'end'); + n.setData('dimArray', $.map(n.getData('valueArray'), function(n) { + return [n[0] * height / maxValue, n[1] * height / maxValue]; + }), 'end'); + var dimArray = n.getData('dimArray'); + if(!dimArray) { + n.setData('dimArray', animateValue); + } + } else { + + if(ticks.enable) { + n.setData('height', acum * height / maxValue); + n.setData('dimArray', $.map(n.getData('valueArray'), function(n) { + return [n[0] * height / maxTickValue, n[1] * height / maxTickValue]; + })); + } else { + n.setData('height', acum * height / maxValue); + n.setData('dimArray', $.map(n.getData('valueArray'), function(n) { + return [n[0] * height / maxValue, n[1] * height / maxValue]; + })); + } + + + } + }); + } +}); + + + + + +/* + * File: AreaChart.js + * +*/ + +$jit.ST.Plot.NodeTypes.implement({ + 'areachart-stacked' : { + 'render' : function(node, canvas) { + var pos = node.pos.getc(true), + width = node.getData('width'), + height = node.getData('height'), + algnPos = this.getAlignedPos(pos, width, height), + x = algnPos.x, y = algnPos.y, + stringArray = node.getData('stringArray'), + dimArray = node.getData('dimArray'), + valArray = node.getData('valueArray'), + valLeft = $.reduce(valArray, function(x, y) { return x + y[0]; }, 0), + valRight = $.reduce(valArray, function(x, y) { return x + y[1]; }, 0), + colorArray = node.getData('colorArray'), + colorLength = colorArray.length, + config = node.getData('config'), + gradient = node.getData('gradient'), + showLabels = config.showLabels, + aggregates = config.showAggregates, + label = config.Label, + prev = node.getData('prev'); + + var ctx = canvas.getCtx(), border = node.getData('border'); + if (colorArray && dimArray && stringArray) { + for (var i=0, l=dimArray.length, acumLeft=0, acumRight=0, valAcum=0; i 0 || dimArray[i][1] > 0)) { + var h1 = acumLeft + dimArray[i][0], + h2 = acumRight + dimArray[i][1], + alpha = Math.atan((h2 - h1) / width), + delta = 55; + var linear = ctx.createLinearGradient(x + width/2, + y - (h1 + h2)/2, + x + width/2 + delta * Math.sin(alpha), + y - (h1 + h2)/2 + delta * Math.cos(alpha)); + var color = $.rgbToHex($.map($.hexToRgb(colorArray[i % colorLength].slice(1)), + function(v) { return (v * 0.85) >> 0; })); + linear.addColorStop(0, colorArray[i % colorLength]); + linear.addColorStop(1, color); + ctx.fillStyle = linear; + } + ctx.beginPath(); + ctx.moveTo(x, y - acumLeft); + ctx.lineTo(x + width, y - acumRight); + ctx.lineTo(x + width, y - acumRight - dimArray[i][1]); + ctx.lineTo(x, y - acumLeft - dimArray[i][0]); + ctx.lineTo(x, y - acumLeft); + ctx.fill(); + ctx.restore(); + if(border) { + var strong = border.name == stringArray[i]; + var perc = strong? 0.7 : 0.8; + var color = $.rgbToHex($.map($.hexToRgb(colorArray[i % colorLength].slice(1)), + function(v) { return (v * perc) >> 0; })); + ctx.strokeStyle = color; + ctx.lineWidth = strong? 4 : 1; + ctx.save(); + ctx.beginPath(); + if(border.index === 0) { + ctx.moveTo(x, y - acumLeft); + ctx.lineTo(x, y - acumLeft - dimArray[i][0]); + } else { + ctx.moveTo(x + width, y - acumRight); + ctx.lineTo(x + width, y - acumRight - dimArray[i][1]); + } + ctx.stroke(); + ctx.restore(); + } + acumLeft += (dimArray[i][0] || 0); + acumRight += (dimArray[i][1] || 0); + + if(dimArray[i][0] > 0) + valAcum += (valArray[i][0] || 0); + } + if(prev && label.type == 'Native') { + ctx.save(); + ctx.beginPath(); + ctx.fillStyle = ctx.strokeStyle = label.color; + ctx.font = label.style + ' ' + label.size + 'px ' + label.family; + ctx.textAlign = 'center'; + ctx.textBaseline = 'middle'; + if(aggregates(node.name, valLeft, valRight, node)) { + ctx.fillText(valAcum, x, y - acumLeft - config.labelOffset - label.size/2, width); + } + if(showLabels(node.name, valLeft, valRight, node)) { + ctx.fillText(node.name, x, y + label.size/2 + config.labelOffset); + } + ctx.restore(); + } + } + }, + 'contains': function(node, mpos) { + var pos = node.pos.getc(true), + width = node.getData('width'), + height = node.getData('height'), + algnPos = this.getAlignedPos(pos, width, height), + x = algnPos.x, y = algnPos.y, + dimArray = node.getData('dimArray'), + rx = mpos.x - x; + //bounding box check + if(mpos.x < x || mpos.x > x + width + || mpos.y > y || mpos.y < y - height) { + return false; + } + //deep check + for(var i=0, l=dimArray.length, lAcum=y, rAcum=y; i= intersec) { + var index = +(rx > width/2); + return { + 'name': node.getData('stringArray')[i], + 'color': node.getData('colorArray')[i], + 'value': node.getData('valueArray')[i][index], + 'index': index + }; + } + } + return false; + } + } +}); + +/* + Class: AreaChart + + A visualization that displays stacked area charts. + + Constructor Options: + + See . + +*/ +$jit.AreaChart = new Class({ + st: null, + colors: ["#416D9C", "#70A35E", "#EBB056", "#C74243", "#83548B", "#909291", "#557EAA"], + selected: {}, + busy: false, + + initialize: function(opt) { + this.controller = this.config = + $.merge(Options("Canvas", "Margin", "Label", "AreaChart"), { + Label: { type: 'Native' } + }, opt); + //set functions for showLabels and showAggregates + var showLabels = this.config.showLabels, + typeLabels = $.type(showLabels), + showAggregates = this.config.showAggregates, + typeAggregates = $.type(showAggregates); + this.config.showLabels = typeLabels == 'function'? showLabels : $.lambda(showLabels); + this.config.showAggregates = typeAggregates == 'function'? showAggregates : $.lambda(showAggregates); + + this.initializeViz(); + }, + + initializeViz: function() { + var config = this.config, + that = this, + nodeType = config.type.split(":")[0], + nodeLabels = {}; + + var st = new $jit.ST({ + injectInto: config.injectInto, + orientation: "bottom", + levelDistance: 0, + siblingOffset: 0, + subtreeOffset: 0, + withLabels: config.Label.type != 'Native', + useCanvas: config.useCanvas, + Label: { + type: config.Label.type + }, + Node: { + overridable: true, + type: 'areachart-' + nodeType, + align: 'left', + width: 1, + height: 1 + }, + Edge: { + type: 'none' + }, + Tips: { + enable: config.Tips.enable, + type: 'Native', + force: true, + onShow: function(tip, node, contains) { + var elem = contains; + config.Tips.onShow(tip, elem, node); + } + }, + Events: { + enable: true, + type: 'Native', + onClick: function(node, eventInfo, evt) { + if(!config.filterOnClick && !config.Events.enable) return; + var elem = eventInfo.getContains(); + if(elem) config.filterOnClick && that.filter(elem.name); + config.Events.enable && config.Events.onClick(elem, eventInfo, evt); + }, + onRightClick: function(node, eventInfo, evt) { + if(!config.restoreOnRightClick) return; + that.restore(); + }, + onMouseMove: function(node, eventInfo, evt) { + if(!config.selectOnHover) return; + if(node) { + var elem = eventInfo.getContains(); + that.select(node.id, elem.name, elem.index); + } else { + that.select(false, false, false); + } + } + }, + onCreateLabel: function(domElement, node) { + var labelConf = config.Label, + valueArray = node.getData('valueArray'), + acumLeft = $.reduce(valueArray, function(x, y) { return x + y[0]; }, 0), + acumRight = $.reduce(valueArray, function(x, y) { return x + y[1]; }, 0); + if(node.getData('prev')) { + var nlbs = { + wrapper: document.createElement('div'), + aggregate: document.createElement('div'), + label: document.createElement('div') + }; + var wrapper = nlbs.wrapper, + label = nlbs.label, + aggregate = nlbs.aggregate, + wrapperStyle = wrapper.style, + labelStyle = label.style, + aggregateStyle = aggregate.style; + //store node labels + nodeLabels[node.id] = nlbs; + //append labels + wrapper.appendChild(label); + wrapper.appendChild(aggregate); + if(!config.showLabels(node.name, acumLeft, acumRight, node)) { + label.style.display = 'none'; + } + if(!config.showAggregates(node.name, acumLeft, acumRight, node)) { + aggregate.style.display = 'none'; + } + wrapperStyle.position = 'relative'; + wrapperStyle.overflow = 'visible'; + wrapperStyle.fontSize = labelConf.size + 'px'; + wrapperStyle.fontFamily = labelConf.family; + wrapperStyle.color = labelConf.color; + wrapperStyle.textAlign = 'center'; + aggregateStyle.position = labelStyle.position = 'absolute'; + + domElement.style.width = node.getData('width') + 'px'; + domElement.style.height = node.getData('height') + 'px'; + label.innerHTML = node.name; + + domElement.appendChild(wrapper); + } + }, + onPlaceLabel: function(domElement, node) { + if(!node.getData('prev')) return; + var labels = nodeLabels[node.id], + wrapperStyle = labels.wrapper.style, + labelStyle = labels.label.style, + aggregateStyle = labels.aggregate.style, + width = node.getData('width'), + height = node.getData('height'), + dimArray = node.getData('dimArray'), + valArray = node.getData('valueArray'), + acumLeft = $.reduce(valArray, function(x, y) { return x + y[0]; }, 0), + acumRight = $.reduce(valArray, function(x, y) { return x + y[1]; }, 0), + font = parseInt(wrapperStyle.fontSize, 10), + domStyle = domElement.style; + + if(dimArray && valArray) { + if(config.showLabels(node.name, acumLeft, acumRight, node)) { + labelStyle.display = ''; + } else { + labelStyle.display = 'none'; + } + if(config.showAggregates(node.name, acumLeft, acumRight, node)) { + aggregateStyle.display = ''; + } else { + aggregateStyle.display = 'none'; + } + wrapperStyle.width = aggregateStyle.width = labelStyle.width = domElement.style.width = width + 'px'; + aggregateStyle.left = labelStyle.left = -width/2 + 'px'; + for(var i=0, l=valArray.length, acum=0, leftAcum=0; i 0) { + acum+= valArray[i][0]; + leftAcum+= dimArray[i][0]; + } + } + aggregateStyle.top = (-font - config.labelOffset) + 'px'; + labelStyle.top = (config.labelOffset + leftAcum) + 'px'; + domElement.style.top = parseInt(domElement.style.top, 10) - leftAcum + 'px'; + domElement.style.height = wrapperStyle.height = leftAcum + 'px'; + labels.aggregate.innerHTML = acum; + } + } + }); + + var size = st.canvas.getSize(), + margin = config.Margin; + st.config.offsetY = -size.height/2 + margin.bottom + + (config.showLabels && (config.labelOffset + config.Label.size)); + st.config.offsetX = (margin.right - margin.left)/2; + this.st = st; + this.canvas = this.st.canvas; + }, + + /* + Method: loadJSON + + Loads JSON data into the visualization. + + Parameters: + + json - The JSON data format. This format is described in . + + Example: + (start code js) + var areaChart = new $jit.AreaChart(options); + areaChart.loadJSON(json); + (end code) + */ + loadJSON: function(json) { + var prefix = $.time(), + ch = [], + st = this.st, + name = $.splat(json.label), + color = $.splat(json.color || this.colors), + config = this.config, + gradient = !!config.type.split(":")[1], + animate = config.animate; + + for(var i=0, values=json.values, l=values.length; i. + onComplete - (object) A callback object to be called when the animation transition when updating the data end. + + Example: + + (start code js) + areaChart.updateJSON(json, { + onComplete: function() { + alert('update complete!'); + } + }); + (end code) + */ + updateJSON: function(json, onComplete) { + if(this.busy) return; + this.busy = true; + + var st = this.st, + graph = st.graph, + labels = json.label && $.splat(json.label), + values = json.values, + animate = this.config.animate, + that = this; + $.each(values, function(v) { + var n = graph.getByName(v.label); + if(n) { + v.values = $.splat(v.values); + var stringArray = n.getData('stringArray'), + valArray = n.getData('valueArray'); + $.each(valArray, function(a, i) { + a[0] = v.values[i]; + if(labels) stringArray[i] = labels[i]; + }); + n.setData('valueArray', valArray); + var prev = n.getData('prev'), + next = n.getData('next'), + nextNode = graph.getByName(next); + if(prev) { + var p = graph.getByName(prev); + if(p) { + var valArray = p.getData('valueArray'); + $.each(valArray, function(a, i) { + a[1] = v.values[i]; + }); + } + } + if(!nextNode) { + var valArray = n.getData('valueArray'); + $.each(valArray, function(a, i) { + a[1] = v.values[i]; + }); + } + } + }); + this.normalizeDims(); + st.compute(); + st.select(st.root); + if(animate) { + st.fx.animate({ + modes: ['node-property:height:dimArray'], + duration:1500, + onComplete: function() { + that.busy = false; + onComplete && onComplete.onComplete(); + } + }); + } + }, + +/* + Method: filter + + Filter selected stacks, collapsing all other stacks. You can filter multiple stacks at the same time. + + Parameters: + + Variable strings arguments with the name of the stacks. + + Example: + + (start code js) + areaChart.filter('label A', 'label C'); + (end code) + + See also: + + . + */ + filter: function() { + if(this.busy) return; + this.busy = true; + if(this.config.Tips.enable) this.st.tips.hide(); + this.select(false, false, false); + var args = Array.prototype.slice.call(arguments); + var rt = this.st.graph.getNode(this.st.root); + var that = this; + rt.eachAdjacency(function(adj) { + var n = adj.nodeTo, + dimArray = n.getData('dimArray'), + stringArray = n.getData('stringArray'); + n.setData('dimArray', $.map(dimArray, function(d, i) { + return ($.indexOf(args, stringArray[i]) > -1)? d:[0, 0]; + }), 'end'); + }); + this.st.fx.animate({ + modes: ['node-property:dimArray'], + duration:1500, + onComplete: function() { + that.busy = false; + } + }); + }, + + /* + Method: restore + + Sets all stacks that could have been filtered visible. + + Example: + + (start code js) + areaChart.restore(); + (end code) + + See also: + + . + */ + restore: function() { + if(this.busy) return; + this.busy = true; + if(this.config.Tips.enable) this.st.tips.hide(); + this.select(false, false, false); + this.normalizeDims(); + var that = this; + this.st.fx.animate({ + modes: ['node-property:height:dimArray'], + duration:1500, + onComplete: function() { + that.busy = false; + } + }); + }, + //adds the little brown bar when hovering the node + select: function(id, name, index) { + if(!this.config.selectOnHover) return; + var s = this.selected; + if(s.id != id || s.name != name + || s.index != index) { + s.id = id; + s.name = name; + s.index = index; + this.st.graph.eachNode(function(n) { + n.setData('border', false); + }); + if(id) { + var n = this.st.graph.getNode(id); + n.setData('border', s); + var link = index === 0? 'prev':'next'; + link = n.getData(link); + if(link) { + n = this.st.graph.getByName(link); + if(n) { + n.setData('border', { + name: name, + index: 1-index + }); + } + } + } + this.st.plot(); + } + }, + + /* + Method: getLegend + + Returns an object containing as keys the legend names and as values hex strings with color values. + + Example: + + (start code js) + var legend = areaChart.getLegend(); + (end code) + */ + getLegend: function() { + var legend = {}; + var n; + this.st.graph.getNode(this.st.root).eachAdjacency(function(adj) { + n = adj.nodeTo; + }); + var colors = n.getData('colorArray'), + len = colors.length; + $.each(n.getData('stringArray'), function(s, i) { + legend[s] = colors[i % len]; + }); + return legend; + }, + + /* + Method: getMaxValue + + Returns the maximum accumulated value for the stacks. This method is used for normalizing the graph heights according to the canvas height. + + Example: + + (start code js) + var ans = areaChart.getMaxValue(); + (end code) + + In some cases it could be useful to override this method to normalize heights for a group of AreaCharts, like when doing small multiples. + + Example: + + (start code js) + //will return 100 for all AreaChart instances, + //displaying all of them with the same scale + $jit.AreaChart.implement({ + 'getMaxValue': function() { + return 100; + } + }); + (end code) + +*/ + getMaxValue: function() { + var maxValue = 0; + this.st.graph.eachNode(function(n) { + var valArray = n.getData('valueArray'), + acumLeft = 0, acumRight = 0; + $.each(valArray, function(v) { + acumLeft += +v[0]; + acumRight += +v[1]; + }); + var acum = acumRight>acumLeft? acumRight:acumLeft; + maxValue = maxValue>acum? maxValue:acum; + }); + return maxValue; + }, + + normalizeDims: function() { + //number of elements + var root = this.st.graph.getNode(this.st.root), l=0; + root.eachAdjacency(function() { + l++; + }); + var maxValue = this.getMaxValue() || 1, + size = this.st.canvas.getSize(), + config = this.config, + margin = config.Margin, + labelOffset = config.labelOffset + config.Label.size, + fixedDim = (size.width - (margin.left + margin.right)) / l, + animate = config.animate, + height = size.height - (margin.top + margin.bottom) - (config.showAggregates && labelOffset) + - (config.showLabels && labelOffset); + this.st.graph.eachNode(function(n) { + var acumLeft = 0, acumRight = 0, animateValue = []; + $.each(n.getData('valueArray'), function(v) { + acumLeft += +v[0]; + acumRight += +v[1]; + animateValue.push([0, 0]); + }); + var acum = acumRight>acumLeft? acumRight:acumLeft; + n.setData('width', fixedDim); + if(animate) { + n.setData('height', acum * height / maxValue, 'end'); + n.setData('dimArray', $.map(n.getData('valueArray'), function(n) { + return [n[0] * height / maxValue, n[1] * height / maxValue]; + }), 'end'); + var dimArray = n.getData('dimArray'); + if(!dimArray) { + n.setData('dimArray', animateValue); + } + } else { + n.setData('height', acum * height / maxValue); + n.setData('dimArray', $.map(n.getData('valueArray'), function(n) { + return [n[0] * height / maxValue, n[1] * height / maxValue]; + })); + } + }); + } +}); + +/* + * File: Options.BarChart.js + * +*/ + +/* + Object: Options.BarChart + + options. + Other options included in the BarChart are , , , and . + + Syntax: + + (start code js) + + Options.BarChart = { + animate: true, + labelOffset: 3, + barsOffset: 0, + type: 'stacked', + hoveredColor: '#9fd4ff', + orientation: 'horizontal', + showAggregates: true, + showLabels: true + }; + + (end code) + + Example: + + (start code js) + + var barChart = new $jit.BarChart({ + animate: true, + barsOffset: 10, + type: 'stacked:gradient' + }); + + (end code) + + Parameters: + + animate - (boolean) Default's *true*. Whether to add animated transitions when filtering/restoring stacks. + offset - (number) Default's *25*. Adds margin between the visualization and the canvas. + labelOffset - (number) Default's *3*. Adds margin between the label and the default place where it should be drawn. + barsOffset - (number) Default's *0*. Separation between bars. + type - (string) Default's *'stacked'*. Stack or grouped styles. Posible values are 'stacked', 'grouped', 'stacked:gradient', 'grouped:gradient' to add gradients. + hoveredColor - (boolean|string) Default's *'#9fd4ff'*. Sets the selected color for a hovered bar stack. + orientation - (string) Default's 'horizontal'. Sets the direction of the bars. Possible options are 'vertical' or 'horizontal'. + showAggregates - (boolean) Default's *true*. Display the sum of the values of the different stacks. + showLabels - (boolean) Default's *true*. Display the name of the slots. + +*/ + +Options.BarChart = { + $extend: true, + + animate: true, + type: 'stacked', //stacked, grouped, : gradient + labelOffset: 3, //label offset + barsOffset: 0, //distance between bars + nodeCount: 0, //number of bars + hoveredColor: '#9fd4ff', + background: false, + renderBackground: false, + orientation: 'horizontal', + showAggregates: true, + showLabels: true, + Ticks: { + enable: false, + segments: 4, + color: '#000000' + }, + Tips: { + enable: false, + onShow: $.empty, + onHide: $.empty + }, + Events: { + enable: false, + onClick: $.empty + } +}; + +/* + * File: BarChart.js + * +*/ + +$jit.ST.Plot.NodeTypes.implement({ + 'barchart-stacked' : { + 'render' : function(node, canvas) { + var pos = node.pos.getc(true), + width = node.getData('width'), + height = node.getData('height'), + algnPos = this.getAlignedPos(pos, width, height), + x = algnPos.x, y = algnPos.y, + dimArray = node.getData('dimArray'), + valueArray = node.getData('valueArray'), + stringArray = node.getData('stringArray'), + linkArray = node.getData('linkArray'), + gvl = node.getData('gvl'), + colorArray = node.getData('colorArray'), + colorLength = colorArray.length, + nodeCount = node.getData('nodeCount'); + var ctx = canvas.getCtx(), + canvasSize = canvas.getSize(), + opt = {}, + border = node.getData('border'), + gradient = node.getData('gradient'), + config = node.getData('config'), + horz = config.orientation == 'horizontal', + aggregates = config.showAggregates, + showLabels = config.showLabels, + label = config.Label, + margin = config.Margin; + + + if (colorArray && dimArray && stringArray) { + for (var i=0, l=dimArray.length, acum=0, valAcum=0; i> 0; })); + linear.addColorStop(0, color); + linear.addColorStop(0.3, colorArray[i % colorLength]); + linear.addColorStop(0.7, colorArray[i % colorLength]); + linear.addColorStop(1, color); + ctx.fillStyle = linear; + } + if(horz) { + ctx.fillRect(x + acum, y, dimArray[i], height); + } else { + ctx.fillRect(x, y - acum - dimArray[i], width, dimArray[i]); + } + if(border && border.name == stringArray[i]) { + opt.acum = acum; + opt.dimValue = dimArray[i]; + } + acum += (dimArray[i] || 0); + valAcum += (valueArray[i] || 0); + } + if(border) { + ctx.save(); + ctx.lineWidth = 2; + ctx.strokeStyle = border.color; + if(horz) { + ctx.strokeRect(x + opt.acum + 1, y + 1, opt.dimValue -2, height - 2); + } else { + ctx.strokeRect(x + 1, y - opt.acum - opt.dimValue + 1, width -2, opt.dimValue -2); + } + ctx.restore(); + } + if(label.type == 'Native') { + ctx.save(); + ctx.fillStyle = ctx.strokeStyle = label.color; + ctx.font = label.style + ' ' + label.size + 'px ' + label.family; + ctx.textBaseline = 'middle'; + if(gvl) { + acumValueLabel = gvl; + } else { + acumValueLabel = valAcum; + } + if(aggregates(node.name, valAcum)) { + if(!horz) { + ctx.textAlign = 'center'; + ctx.font = label.style + ' ' + label.size + 'px ' + label.family; + //background box + ctx.save(); + gridHeight = canvasSize.height - (margin.top + margin.bottom + (config.Title.text ? config.Title.size + config.Title.offset : 0) + + (config.Subtitle.text ? config.Subtitle.size + config.Subtitle.offset : 0) + + (label ? label.size + config.labelOffset : 0)); + mtxt = ctx.measureText(acumValueLabel); + boxWidth = mtxt.width+10; + inset = 10; + boxHeight = label.size+6; + + if(boxHeight + acum + config.labelOffset > gridHeight) { + bottomPadding = acum - config.labelOffset - boxHeight; + } else { + bottomPadding = acum + config.labelOffset + inset; + } + + + ctx.translate(x + width/2 - (mtxt.width/2) , y - bottomPadding); + cornerRadius = 4; + boxX = -inset/2; + boxY = -boxHeight/2; + + ctx.rotate(0 * Math.PI / 180); + ctx.fillStyle = "rgba(255,255,255,.8)"; + if(boxHeight + acum + config.labelOffset > gridHeight) { + $.roundedRect(ctx,boxX,boxY,boxWidth,boxHeight,cornerRadius,"fill"); + } + //$.roundedRect(ctx,boxX,boxY,boxWidth,boxHeight,cornerRadius,"stroke"); + ctx.fillStyle = ctx.strokeStyle = label.color; + ctx.fillText(acumValueLabel, mtxt.width/2, 0); + ctx.restore(); + + } + } + if(showLabels(node.name, valAcum, node)) { + if(horz) { + + + //background box + ctx.font = label.style + ' ' + label.size + 'px ' + label.family; + inset = 10; + + gridWidth = canvasSize.width - (config.Margin.left + config.Margin.right); + mtxt = ctx.measureText(node.name + ": " + acumValueLabel); + boxWidth = mtxt.width+10; + inset = 10; + + if(acum + boxWidth + config.labelOffset + inset > gridWidth) { + leftPadding = acum - config.labelOffset - boxWidth - inset; + } else { + leftPadding = acum + config.labelOffset; + } + + + ctx.textAlign = 'left'; + ctx.translate(x + inset + leftPadding, y + height/2); + boxHeight = label.size+6; + boxX = -inset/2; + boxY = -boxHeight/2; + ctx.fillStyle = "rgba(255,255,255,.8)"; + cornerRadius = 4; + if(acum + boxWidth + config.labelOffset + inset > gridWidth) { + $.roundedRect(ctx,boxX,boxY,boxWidth,boxHeight,cornerRadius,"fill"); + } + //$.roundedRect(ctx,boxX,boxY,boxWidth,boxHeight,cornerRadius,"stroke"); + + ctx.fillStyle = label.color; + ctx.rotate(0 * Math.PI / 180); + ctx.fillText(node.name + ": " + acumValueLabel, 0, 0); + + + } else { + ctx.textAlign = 'center'; + ctx.fillText(node.name, x + width/2, y + label.size/2 + config.labelOffset); + } + } + ctx.restore(); + } + } + }, + 'contains': function(node, mpos) { + var pos = node.pos.getc(true), + width = node.getData('width'), + height = node.getData('height'), + algnPos = this.getAlignedPos(pos, width, height), + x = algnPos.x, y = algnPos.y, + dimArray = node.getData('dimArray'), + config = node.getData('config'), + rx = mpos.x - x, + horz = config.orientation == 'horizontal'; + //bounding box check + if(horz) { + if(mpos.x < x || mpos.x > x + width + || mpos.y > y + height || mpos.y < y) { + return false; + } + } else { + if(mpos.x < x || mpos.x > x + width + || mpos.y > y || mpos.y < y - height) { + return false; + } + } + //deep check + for(var i=0, l=dimArray.length, acum=(horz? x:y); i= intersec) { + return { + 'name': node.getData('stringArray')[i], + 'color': node.getData('colorArray')[i], + 'value': node.getData('valueArray')[i], + 'valuelabel': node.getData('valuelabelArray')[i], + 'percentage': ((node.getData('valueArray')[i]/node.getData('barTotalValue')) * 100).toFixed(1), + 'link': url, + 'label': node.name + }; + } + } + } + return false; + } + }, + 'barchart-grouped' : { + 'render' : function(node, canvas) { + var pos = node.pos.getc(true), + width = node.getData('width'), + height = node.getData('height'), + algnPos = this.getAlignedPos(pos, width, height), + x = algnPos.x, y = algnPos.y, + dimArray = node.getData('dimArray'), + valueArray = node.getData('valueArray'), + valuelabelArray = node.getData('valuelabelArray'), + linkArray = node.getData('linkArray'), + valueLength = valueArray.length, + colorArray = node.getData('colorArray'), + colorLength = colorArray.length, + stringArray = node.getData('stringArray'); + + var ctx = canvas.getCtx(), + canvasSize = canvas.getSize(), + opt = {}, + border = node.getData('border'), + gradient = node.getData('gradient'), + config = node.getData('config'), + horz = config.orientation == 'horizontal', + aggregates = config.showAggregates, + showLabels = config.showLabels, + label = config.Label, + shadow = config.shadow, + margin = config.Margin, + fixedDim = (horz? height : width) / valueLength; + + //drop shadow + + maxValue = Math.max.apply(null, dimArray); + + + + ctx.fillStyle = "rgba(0,0,0,.2)"; + if (colorArray && dimArray && stringArray && shadow.enable) { + shadowThickness = shadow.size; + + for (var i=0, l=valueLength, acum=0, valAcum=0; i dimArray[i]) { + ctx.fillRect((x - shadowThickness) + fixedDim * i, y - dimArray[i] - shadowThickness, fixedDim, dimArray[i]+ shadowThickness); + } else if (nextBar && nextBar < dimArray[i]){ + ctx.fillRect((x - shadowThickness) + fixedDim * i, y - dimArray[i] - shadowThickness, fixedDim + shadowThickness*2, dimArray[i]+ shadowThickness); + } else { + ctx.fillRect((x - shadowThickness) + fixedDim * i, y - dimArray[i] - shadowThickness, fixedDim + shadowThickness, dimArray[i]+ shadowThickness); + } + } else if (i> 0 && i dimArray[i]) { + ctx.fillRect((x - ((prevBar < dimArray[i]) ? shadowThickness : 0)) + fixedDim * i, y - dimArray[i] - shadowThickness, fixedDim, dimArray[i]+ shadowThickness); + } else if (nextBar && nextBar < dimArray[i]){ + ctx.fillRect((x - ((prevBar < dimArray[i]) ? shadowThickness : 0)) + fixedDim * i, y - dimArray[i] - shadowThickness, fixedDim + shadowThickness*2, dimArray[i]+ shadowThickness); + } else { + ctx.fillRect((x - ((prevBar < dimArray[i]) ? shadowThickness : 0)) + fixedDim * i, y - dimArray[i] - shadowThickness, fixedDim + shadowThickness, dimArray[i]+ shadowThickness); + } + } else if (i == l-1) { + ctx.fillRect((x - ((prevBar < dimArray[i]) ? shadowThickness : 0)) + fixedDim * i, y - dimArray[i] - shadowThickness, fixedDim + shadowThickness*2, dimArray[i]+ shadowThickness); + } + + + } + } + + } + + + if (colorArray && dimArray && stringArray) { + for (var i=0, l=valueLength, acum=0, valAcum=0; i> 0; })); + linear.addColorStop(0, color); + linear.addColorStop(0.3, colorArray[i % colorLength]); + linear.addColorStop(0.7, colorArray[i % colorLength]); + linear.addColorStop(1, color); + ctx.fillStyle = linear; + } + if(horz) { + ctx.fillRect(x, y + fixedDim * i, dimArray[i], fixedDim); + } else { + ctx.fillRect(x + fixedDim * i, y - dimArray[i], fixedDim, dimArray[i]); + } + if(border && border.name == stringArray[i]) { + opt.acum = fixedDim * i; + opt.dimValue = dimArray[i]; + } + acum += (dimArray[i] || 0); + valAcum += (valueArray[i] || 0); + ctx.fillStyle = ctx.strokeStyle = label.color; + ctx.font = label.style + ' ' + label.size + 'px ' + label.family; + + inset = 10; + if(aggregates(node.name, valAcum) && label.type == 'Native') { + if(valuelabelArray[i]) { + acumValueLabel = valuelabelArray[i]; + } else { + acumValueLabel = valueArray[i]; + } + if(horz) { + ctx.font = label.style + ' ' + label.size + 'px ' + label.family; + ctx.textAlign = 'left'; + ctx.textBaseline = 'top'; + ctx.fillStyle = "rgba(255,255,255,.8)"; + //background box + gridWidth = canvasSize.width - (margin.left + margin.right + config.labeloffset + label.size); + mtxt = ctx.measureText(acumValueLabel); + boxWidth = mtxt.width+10; + + if(boxWidth + dimArray[i] + config.labelOffset > gridWidth) { + leftPadding = dimArray[i] - config.labelOffset - boxWidth - inset; + } else { + leftPadding = dimArray[i] + config.labelOffset + inset; + } + boxHeight = label.size+6; + boxX = x + leftPadding; + boxY = y + i*fixedDim + (fixedDim/2) - boxHeight/2; + cornerRadius = 4; + + + if(boxWidth + dimArray[i] + config.labelOffset > gridWidth) { + $.roundedRect(ctx,boxX,boxY,boxWidth,boxHeight,cornerRadius,"fill"); + } + // $.roundedRect(ctx,boxX,boxY,boxWidth,boxHeight,cornerRadius,"stroke"); + + ctx.fillStyle = ctx.strokeStyle = label.color; + ctx.fillText(acumValueLabel, x + inset/2 + leftPadding, y + i*fixedDim + (fixedDim/2) - (label.size/2)); + + + + + } else { + + ctx.font = label.style + ' ' + label.size + 'px ' + label.family; + ctx.save(); + ctx.textAlign = 'center'; + + //background box + gridHeight = canvasSize.height - (margin.top + margin.bottom + (config.Title.text ? config.Title.size + config.Title.offset : 0) + + (config.Subtitle.text ? config.Subtitle.size + config.Subtitle.offset : 0) + + (label ? label.size + config.labelOffset : 0)); + + mtxt = ctx.measureText(acumValueLabel); + boxWidth = mtxt.width+10; + boxHeight = label.size+6; + if(boxHeight + dimArray[i] + config.labelOffset > gridHeight) { + bottomPadding = dimArray[i] - config.labelOffset - boxHeight - inset; + } else { + bottomPadding = dimArray[i] + config.labelOffset + inset; + } + + + ctx.translate(x + (i*fixedDim) + (fixedDim/2) , y - bottomPadding); + + boxX = -boxWidth/2; + boxY = -boxHeight/2; + ctx.fillStyle = "rgba(255,255,255,.8)"; + + cornerRadius = 4; + + //ctx.rotate(270* Math.PI / 180); + if(boxHeight + dimArray[i] + config.labelOffset > gridHeight) { + $.roundedRect(ctx,boxX,boxY,boxWidth,boxHeight,cornerRadius,"fill"); + } + //$.roundedRect(ctx,boxX,boxY,boxWidth,boxHeight,cornerRadius,"stroke"); + + ctx.fillStyle = ctx.strokeStyle = label.color; + ctx.fillText(acumValueLabel, 0,0); + ctx.restore(); + + } + } + } + if(border) { + ctx.save(); + ctx.lineWidth = 2; + ctx.strokeStyle = border.color; + if(horz) { + ctx.strokeRect(x + 1, y + opt.acum + 1, opt.dimValue -2, fixedDim - 2); + } else { + ctx.strokeRect(x + opt.acum + 1, y - opt.dimValue + 1, fixedDim -2, opt.dimValue -2); + } + ctx.restore(); + } + if(label.type == 'Native') { + ctx.save(); + ctx.fillStyle = ctx.strokeStyle = label.color; + ctx.font = label.style + ' ' + label.size + 'px ' + label.family; + ctx.textBaseline = 'middle'; + + if(showLabels(node.name, valAcum, node)) { + if(horz) { + ctx.textAlign = 'center'; + ctx.translate(x - config.labelOffset - label.size/2, y + height/2); + ctx.rotate(Math.PI / 2); + ctx.fillText(node.name, 0, 0); + } else { + ctx.textAlign = 'center'; + ctx.fillText(node.name, x + width/2, y + label.size/2 + config.labelOffset); + } + } + ctx.restore(); + } + } + }, + 'contains': function(node, mpos) { + var pos = node.pos.getc(true), + width = node.getData('width'), + height = node.getData('height'), + algnPos = this.getAlignedPos(pos, width, height), + x = algnPos.x, y = algnPos.y, + dimArray = node.getData('dimArray'), + len = dimArray.length, + config = node.getData('config'), + rx = mpos.x - x, + horz = config.orientation == 'horizontal', + fixedDim = (horz? height : width) / len; + //bounding box check + if(horz) { + if(mpos.x < x || mpos.x > x + width + || mpos.y > y + height || mpos.y < y) { + return false; + } + } else { + if(mpos.x < x || mpos.x > x + width + || mpos.y > y || mpos.y < y - height) { + return false; + } + } + //deep check + for(var i=0, l=dimArray.length; i= limit && mpos.y <= limit + fixedDim) { + return { + 'name': node.getData('stringArray')[i], + 'color': node.getData('colorArray')[i], + 'value': node.getData('valueArray')[i], + 'valuelabel': node.getData('valuelabelArray')[i], + 'title': node.getData('titleArray')[i], + 'percentage': ((node.getData('valueArray')[i]/node.getData('barTotalValue')) * 100).toFixed(1), + 'link': url, + 'label': node.name + }; + } + } else { + var limit = x + fixedDim * i; + if(mpos.x >= limit && mpos.x <= limit + fixedDim && mpos.y >= y - dimi) { + return { + 'name': node.getData('stringArray')[i], + 'color': node.getData('colorArray')[i], + 'value': node.getData('valueArray')[i], + 'valuelabel': node.getData('valuelabelArray')[i], + 'title': node.getData('titleArray')[i], + 'percentage': ((node.getData('valueArray')[i]/node.getData('barTotalValue')) * 100).toFixed(1), + 'link': url, + 'label': node.name + }; + } + } + } + return false; + } + }, + 'barchart-basic' : { + 'render' : function(node, canvas) { + var pos = node.pos.getc(true), + width = node.getData('width'), + height = node.getData('height'), + algnPos = this.getAlignedPos(pos, width, height), + x = algnPos.x, y = algnPos.y, + dimArray = node.getData('dimArray'), + valueArray = node.getData('valueArray'), + valuelabelArray = node.getData('valuelabelArray'), + linkArray = node.getData('linkArray'), + valueLength = valueArray.length, + colorArray = node.getData('colorMono'), + colorLength = colorArray.length, + stringArray = node.getData('stringArray'); + + var ctx = canvas.getCtx(), + canvasSize = canvas.getSize(), + opt = {}, + border = node.getData('border'), + gradient = node.getData('gradient'), + config = node.getData('config'), + horz = config.orientation == 'horizontal', + aggregates = config.showAggregates, + showLabels = config.showLabels, + label = config.Label, + fixedDim = (horz? height : width) / valueLength, + margin = config.Margin; + + if (colorArray && dimArray && stringArray) { + for (var i=0, l=valueLength, acum=0, valAcum=0; i> 0; })); + linear.addColorStop(0, color); + linear.addColorStop(0.3, colorArray[i % colorLength]); + linear.addColorStop(0.7, colorArray[i % colorLength]); + linear.addColorStop(1, color); + ctx.fillStyle = linear; + } + if(horz) { + ctx.fillRect(x, y + fixedDim * i, dimArray[i], fixedDim); + } else { + ctx.fillRect(x + fixedDim * i, y - dimArray[i], fixedDim, dimArray[i]); + } + if(border && border.name == stringArray[i]) { + opt.acum = fixedDim * i; + opt.dimValue = dimArray[i]; + } + acum += (dimArray[i] || 0); + valAcum += (valueArray[i] || 0); + + if(label.type == 'Native') { + ctx.fillStyle = ctx.strokeStyle = label.color; + ctx.font = label.style + ' ' + label.size + 'px ' + label.family; + if(aggregates(node.name, valAcum)) { + if(valuelabelArray[i]) { + acumValueLabel = valuelabelArray[i]; + } else { + acumValueLabel = valueArray[i]; + } + if(!horz) { + ctx.textAlign = 'center'; + ctx.font = label.style + ' ' + label.size + 'px ' + label.family; + //background box + ctx.save(); + gridHeight = canvasSize.height - (margin.top + margin.bottom + (config.Title.text ? config.Title.size + config.Title.offset : 0) + + (config.Subtitle.text ? config.Subtitle.size + config.Subtitle.offset : 0) + + (label ? label.size + config.labelOffset : 0)); + mtxt = ctx.measureText(acumValueLabel); + boxWidth = mtxt.width+10; + inset = 10; + boxHeight = label.size+6; + + if(boxHeight + dimArray[i] + config.labelOffset > gridHeight) { + bottomPadding = dimArray[i] - config.labelOffset - inset; + } else { + bottomPadding = dimArray[i] + config.labelOffset + inset; + } + + + ctx.translate(x + width/2 - (mtxt.width/2) , y - bottomPadding); + cornerRadius = 4; + boxX = -inset/2; + boxY = -boxHeight/2; + + //ctx.rotate(270* Math.PI / 180); + ctx.fillStyle = "rgba(255,255,255,.6)"; + if(boxHeight + dimArray[i] + config.labelOffset > gridHeight) { + $.roundedRect(ctx,boxX,boxY,boxWidth,boxHeight,cornerRadius,"fill"); + } + // $.roundedRect(ctx,boxX,boxY,boxWidth,boxHeight,cornerRadius,"stroke"); + ctx.fillStyle = ctx.strokeStyle = label.color; + ctx.fillText(acumValueLabel, mtxt.width/2, 0); + ctx.restore(); + } + } + } + } + if(border) { + ctx.save(); + ctx.lineWidth = 2; + ctx.strokeStyle = border.color; + if(horz) { + ctx.strokeRect(x + 1, y + opt.acum + 1, opt.dimValue -2, fixedDim - 2); + } else { + ctx.strokeRect(x + opt.acum + 1, y - opt.dimValue + 1, fixedDim -2, opt.dimValue -2); + } + ctx.restore(); + } + if(label.type == 'Native') { + ctx.save(); + ctx.fillStyle = ctx.strokeStyle = label.color; + ctx.font = label.style + ' ' + label.size + 'px ' + label.family; + ctx.textBaseline = 'middle'; + if(showLabels(node.name, valAcum, node)) { + if(horz) { + + //background box + gridWidth = canvasSize.width - (config.Margin.left + config.Margin.right); + mtxt = ctx.measureText(node.name + ": " + valAcum); + boxWidth = mtxt.width+10; + inset = 10; + + if(acum + boxWidth + config.labelOffset + inset > gridWidth) { + leftPadding = acum - config.labelOffset - boxWidth - inset; + } else { + leftPadding = acum + config.labelOffset; + } + + + ctx.textAlign = 'left'; + ctx.translate(x + inset + leftPadding, y + height/2); + boxHeight = label.size+6; + boxX = -inset/2; + boxY = -boxHeight/2; + ctx.fillStyle = "rgba(255,255,255,.8)"; + + cornerRadius = 4; + if(acum + boxWidth + config.labelOffset + inset > gridWidth) { + $.roundedRect(ctx,boxX,boxY,boxWidth,boxHeight,cornerRadius,"fill"); + } + //$.roundedRect(ctx,boxX,boxY,boxWidth,boxHeight,cornerRadius,"stroke"); + + + ctx.fillStyle = label.color; + ctx.fillText(node.name + ": " + valAcum, 0, 0); + + } else { + + if(stringArray.length > 8) { + ctx.textAlign = 'left'; + ctx.translate(x + width/2, y + label.size/2 + config.labelOffset); + ctx.rotate(45* Math.PI / 180); + ctx.fillText(node.name, 0, 0); + } else { + ctx.textAlign = 'center'; + ctx.fillText(node.name, x + width/2, y + label.size/2 + config.labelOffset); + } + + } + } + ctx.restore(); + } + } + }, + 'contains': function(node, mpos) { + var pos = node.pos.getc(true), + width = node.getData('width'), + height = node.getData('height'), + config = node.getData('config'), + algnPos = this.getAlignedPos(pos, width, height), + x = algnPos.x, y = algnPos.y , + dimArray = node.getData('dimArray'), + len = dimArray.length, + rx = mpos.x - x, + horz = config.orientation == 'horizontal', + fixedDim = (horz? height : width) / len; + + //bounding box check + if(horz) { + if(mpos.x < x || mpos.x > x + width + || mpos.y > y + height || mpos.y < y) { + return false; + } + } else { + if(mpos.x < x || mpos.x > x + width + || mpos.y > y || mpos.y < y - height) { + return false; + } + } + //deep check + for(var i=0, l=dimArray.length; i= limit && mpos.y <= limit + fixedDim) { + return { + 'name': node.getData('stringArray')[i], + 'color': node.getData('colorArray')[i], + 'value': node.getData('valueArray')[i], + 'valuelabel': node.getData('valuelabelArray')[i], + 'percentage': ((node.getData('valueArray')[i]/node.getData('groupTotalValue')) * 100).toFixed(1), + 'link': url, + 'label': node.name + }; + } + } else { + var limit = x + fixedDim * i; + if(mpos.x >= limit && mpos.x <= limit + fixedDim && mpos.y >= y - dimi) { + return { + 'name': node.getData('stringArray')[i], + 'color': node.getData('colorArray')[i], + 'value': node.getData('valueArray')[i], + 'valuelabel': node.getData('valuelabelArray')[i], + 'percentage': ((node.getData('valueArray')[i]/node.getData('groupTotalValue')) * 100).toFixed(1), + 'link': url, + 'label': node.name + }; + } + } + } + return false; + } + } +}); + +/* + Class: BarChart + + A visualization that displays stacked bar charts. + + Constructor Options: + + See . + +*/ +$jit.BarChart = new Class({ + st: null, + colors: ["#004b9c", "#9c0079", "#9c0033", "#28009c", "#9c0000", "#7d009c", "#001a9c","#00809c","#009c80","#009c42","#009c07","#469c00","#799c00","#9c9600","#9c5c00"], + selected: {}, + busy: false, + + initialize: function(opt) { + this.controller = this.config = + $.merge(Options("Canvas", "Margin", "Label", "BarChart"), { + Label: { type: 'Native' } + }, opt); + //set functions for showLabels and showAggregates + var showLabels = this.config.showLabels, + typeLabels = $.type(showLabels), + showAggregates = this.config.showAggregates, + typeAggregates = $.type(showAggregates); + this.config.showLabels = typeLabels == 'function'? showLabels : $.lambda(showLabels); + this.config.showAggregates = typeAggregates == 'function'? showAggregates : $.lambda(showAggregates); + Options.Fx.clearCanvas = false; + this.initializeViz(); + }, + + initializeViz: function() { + var config = this.config, that = this; + var nodeType = config.type.split(":")[0], + horz = config.orientation == 'horizontal', + nodeLabels = {}; + var st = new $jit.ST({ + injectInto: config.injectInto, + orientation: horz? 'left' : 'bottom', + background: config.background, + renderBackground: config.renderBackground, + backgroundColor: config.backgroundColor, + colorStop1: config.colorStop1, + colorStop2: config.colorStop2, + levelDistance: 0, + nodeCount: config.nodeCount, + siblingOffset: config.barsOffset, + subtreeOffset: 0, + withLabels: config.Label.type != 'Native', + useCanvas: config.useCanvas, + Label: { + type: config.Label.type + }, + Node: { + overridable: true, + type: 'barchart-' + nodeType, + align: 'left', + width: 1, + height: 1 + }, + Edge: { + type: 'none' + }, + Tips: { + enable: config.Tips.enable, + type: 'Native', + force: true, + onShow: function(tip, node, contains) { + var elem = contains; + config.Tips.onShow(tip, elem, node); + if(elem.link != 'undefined' && elem.link != '') { + document.body.style.cursor = 'pointer'; + } + }, + onHide: function(call) { + document.body.style.cursor = 'default'; + + } + }, + Events: { + enable: true, + type: 'Native', + onClick: function(node, eventInfo, evt) { + if(!config.Events.enable) return; + var elem = eventInfo.getContains(); + config.Events.onClick(elem, eventInfo, evt); + }, + onMouseMove: function(node, eventInfo, evt) { + if(!config.hoveredColor) return; + if(node) { + var elem = eventInfo.getContains(); + that.select(node.id, elem.name, elem.index); + } else { + that.select(false, false, false); + } + } + }, + onCreateLabel: function(domElement, node) { + var labelConf = config.Label, + valueArray = node.getData('valueArray'), + acum = $.reduce(valueArray, function(x, y) { return x + y; }, 0), + grouped = config.type.split(':')[0] == 'grouped', + horz = config.orientation == 'horizontal'; + var nlbs = { + wrapper: document.createElement('div'), + aggregate: document.createElement('div'), + label: document.createElement('div') + }; + + var wrapper = nlbs.wrapper, + label = nlbs.label, + aggregate = nlbs.aggregate, + wrapperStyle = wrapper.style, + labelStyle = label.style, + aggregateStyle = aggregate.style; + //store node labels + nodeLabels[node.id] = nlbs; + //append labels + wrapper.appendChild(label); + wrapper.appendChild(aggregate); + if(!config.showLabels(node.name, acum, node)) { + labelStyle.display = 'none'; + } + if(!config.showAggregates(node.name, acum, node)) { + aggregateStyle.display = 'none'; + } + wrapperStyle.position = 'relative'; + wrapperStyle.overflow = 'visible'; + wrapperStyle.fontSize = labelConf.size + 'px'; + wrapperStyle.fontFamily = labelConf.family; + wrapperStyle.color = labelConf.color; + wrapperStyle.textAlign = 'center'; + aggregateStyle.position = labelStyle.position = 'absolute'; + + domElement.style.width = node.getData('width') + 'px'; + domElement.style.height = node.getData('height') + 'px'; + aggregateStyle.left = "0px"; + labelStyle.left = config.labelOffset + 'px'; + labelStyle.whiteSpace = "nowrap"; + label.innerHTML = node.name; + + domElement.appendChild(wrapper); + }, + onPlaceLabel: function(domElement, node) { + if(!nodeLabels[node.id]) return; + var labels = nodeLabels[node.id], + wrapperStyle = labels.wrapper.style, + labelStyle = labels.label.style, + aggregateStyle = labels.aggregate.style, + grouped = config.type.split(':')[0] == 'grouped', + horz = config.orientation == 'horizontal', + dimArray = node.getData('dimArray'), + valArray = node.getData('valueArray'), + nodeCount = node.getData('nodeCount'), + valueLength = valArray.length; + valuelabelArray = node.getData('valuelabelArray'), + stringArray = node.getData('stringArray'), + width = (grouped && horz)? Math.max.apply(null, dimArray) : node.getData('width'), + height = (grouped && !horz)? Math.max.apply(null, dimArray) : node.getData('height'), + font = parseInt(wrapperStyle.fontSize, 10), + domStyle = domElement.style, + fixedDim = (horz? height : width) / valueLength; + + + if(dimArray && valArray) { + wrapperStyle.width = aggregateStyle.width = labelStyle.width = domElement.style.width = width + 'px'; + + aggregateStyle.width = width - config.labelOffset + "px"; + for(var i=0, l=valArray.length, acum=0; i 0) { + acum+= valArray[i]; + } + } + if(config.showLabels(node.name, acum, node)) { + labelStyle.display = ''; + } else { + labelStyle.display = 'none'; + } + if(config.showAggregates(node.name, acum, node)) { + aggregateStyle.display = ''; + } else { + aggregateStyle.display = 'none'; + } + if(config.orientation == 'horizontal') { + aggregateStyle.textAlign = 'right'; + labelStyle.textAlign = 'left'; + labelStyle.textIndex = aggregateStyle.textIndent = config.labelOffset + 'px'; + aggregateStyle.top = labelStyle.top = (height-font)/2 + 'px'; + domElement.style.height = wrapperStyle.height = height + 'px'; + } else { + aggregateStyle.top = (-font - config.labelOffset) + 'px'; + labelStyle.top = (config.labelOffset + height) + 'px'; + domElement.style.top = parseInt(domElement.style.top, 10) - height + 'px'; + domElement.style.height = wrapperStyle.height = height + 'px'; + if(stringArray.length > 8) { + labels.label.className = "rotatedLabelReverse"; + labelStyle.textAlign = "left"; + labelStyle.top = config.labelOffset + height + width/2 + "px"; + } + } + + if(horz) { + + labels.label.innerHTML = labels.label.innerHTML + ": " + acum; + labels.aggregate.innerHTML = ""; + + } else { + + if(grouped) { + maxValue = Math.max.apply(null,dimArray); + for (var i=0, l=valArray.length, acum=0, valAcum=0; i 40) ? 40 : fixedDim; + whiteSpace = size.width - (marginWidth + (fixedDim * l)); + + //if not a grouped chart and is a vertical chart, adjust bar spacing to fix canvas width. + if(!grouped && !horz) { + st.config.siblingOffset = whiteSpace/(l+1); + } + + + + //Bars offset + if(horz) { + st.config.offsetX = size.width/2 - margin.left - (grouped && config.Label ? config.labelOffset + config.Label.size : 0); + if(config.Ticks.enable) { + st.config.offsetY = ((margin.bottom+config.Label.size+config.labelOffset+(subtitle.text? subtitle.size+subtitle.offset:0)) - (margin.top + (title.text? title.size+title.offset:0))) /2; + } else { + st.config.offsetY = (margin.bottom - margin.top - (title.text? title.size+title.offset:0) - (subtitle.text? subtitle.size+subtitle.offset:0))/2; + } + } else { + st.config.offsetY = -size.height/2 + margin.bottom + + (config.showLabels && (config.labelOffset + config.Label.size)) + (subtitle.text? subtitle.size+subtitle.offset:0); + if(config.Ticks.enable) { + st.config.offsetX = ((margin.right-config.Label.size-config.labelOffset) - margin.left)/2; + } else { + st.config.offsetX = (margin.right - margin.left)/2; + } + } + this.st = st; + this.canvas = this.st.canvas; + }, + + renderTitle: function() { + var canvas = this.canvas, + size = canvas.getSize(), + config = this.config, + margin = config.Margin, + label = config.Label, + title = config.Title; + ctx = canvas.getCtx(); + ctx.fillStyle = title.color; + ctx.textAlign = 'left'; + ctx.font = label.style + ' bold ' +' ' + title.size + 'px ' + label.family; + if(label.type == 'Native') { + ctx.fillText(title.text, -size.width/2+margin.left, -size.height/2+margin.top); + } + }, + + renderSubtitle: function() { + var canvas = this.canvas, + size = canvas.getSize(), + config = this.config, + margin = config.Margin, + label = config.Label, + subtitle = config.Subtitle; + ctx = canvas.getCtx(); + ctx.fillStyle = title.color; + ctx.textAlign = 'left'; + ctx.font = label.style + ' ' + subtitle.size + 'px ' + label.family; + if(label.type == 'Native') { + ctx.fillText(subtitle.text, -size.width/2+margin.left, size.height/2-margin.bottom-subtitle.size); + } + }, + + renderScrollNote: function() { + var canvas = this.canvas, + size = canvas.getSize(), + config = this.config, + margin = config.Margin, + label = config.Label, + note = config.ScrollNote; + ctx = canvas.getCtx(); + ctx.fillStyle = title.color; + title = config.Title; + ctx.textAlign = 'center'; + ctx.font = label.style + ' bold ' +' ' + note.size + 'px ' + label.family; + if(label.type == 'Native') { + ctx.fillText(note.text, 0, -size.height/2+margin.top+title.size); + } + }, + + renderTicks: function() { + + var canvas = this.canvas, + size = canvas.getSize(), + config = this.config, + margin = config.Margin, + ticks = config.Ticks, + title = config.Title, + subtitle = config.Subtitle, + label = config.Label, + shadow = config.shadow; + horz = config.orientation == 'horizontal', + maxValue = this.getMaxValue(), + maxTickValue = Math.ceil(maxValue*.1)*10; + if(maxTickValue == maxValue) { + var length = maxTickValue.toString().length; + maxTickValue = maxTickValue + parseInt(pad(1,length)); + } + grouped = config.type.split(':')[0] == 'grouped', + labelValue = 0, + labelIncrement = maxTickValue/ticks.segments, + ctx = canvas.getCtx(); + ctx.strokeStyle = ticks.color; + ctx.font = label.style + ' ' + label.size + 'px ' + label.family; + + ctx.textAlign = 'center'; + ctx.textBaseline = 'middle'; + + idLabel = canvas.id + "-label"; + labelDim = 100; + container = document.getElementById(idLabel); + + + if(horz) { + var axis = -(size.width/2)+margin.left + (grouped && config.Label ? config.labelOffset + label.size : 0), + grid = size.width-(margin.left + margin.right + (grouped && config.Label ? config.labelOffset + label.size : 0)), + segmentLength = grid/ticks.segments; + ctx.fillStyle = ticks.color; + ctx.fillRect(axis, + (size.height/2)-margin.bottom-config.labelOffset-label.size - (subtitle.text? subtitle.size+subtitle.offset:0) + (shadow.enable ? shadow.size : 0), + size.width - margin.left - margin.right - (grouped && config.Label ? config.labelOffset + label.size : 0), + 1); + while(axis<=grid) { + ctx.fillStyle = ticks.color; + lineHeight = size.height-margin.bottom-margin.top-config.labelOffset-label.size-(title.text? title.size+title.offset:0)-(subtitle.text? subtitle.size+subtitle.offset:0); + ctx.fillRect(Math.round(axis), -(size.height/2)+margin.top+(title.text? title.size+title.offset:0) - (shadow.enable ? shadow.size : 0), 1, lineHeight + (shadow.enable ? shadow.size * 2: 0)); + ctx.fillStyle = label.color; + + if(label.type == 'Native' && config.showLabels) { + ctx.fillText(labelValue, Math.round(axis), -(size.height/2)+margin.top+(title.text? title.size+title.offset:0)+config.labelOffset+lineHeight+label.size); + } + axis += segmentLength; + labelValue += labelIncrement; + } + + } else { + + var axis = (size.height/2)-(margin.bottom+config.labelOffset+label.size+(subtitle.text? subtitle.size+subtitle.offset:0)), + htmlOrigin = size.height - (margin.bottom+config.labelOffset+label.size+(subtitle.text? subtitle.size+subtitle.offset:0)), + grid = -size.height+(margin.bottom+config.labelOffset+label.size+margin.top+(title.text? title.size+title.offset:0)+(subtitle.text? subtitle.size+subtitle.offset:0)), + segmentLength = grid/ticks.segments; + ctx.fillStyle = ticks.color; + ctx.fillRect(-(size.width/2)+margin.left+config.labelOffset+label.size-1, -(size.height/2)+margin.top+(title.text? title.size+title.offset:0),1,size.height-margin.top-margin.bottom-label.size-config.labelOffset-(title.text? title.size+title.offset:0)-(subtitle.text? subtitle.size+subtitle.offset:0)); + + while(axis>=grid) { + ctx.save(); + ctx.translate(-(size.width/2)+margin.left, Math.round(axis)); + ctx.rotate(0 * Math.PI / 180 ); + ctx.fillStyle = label.color; + if(config.showLabels) { + if(label.type == 'Native') { + ctx.fillText(labelValue, 0, 0); + } else { + //html labels on y axis + labelDiv = document.createElement('div'); + labelDiv.innerHTML = labelValue; + labelDiv.className = "rotatedLabel"; +// labelDiv.class = "rotatedLabel"; + labelDiv.style.top = (htmlOrigin - (labelDim/2)) + "px"; + labelDiv.style.left = margin.left + "px"; + labelDiv.style.width = labelDim + "px"; + labelDiv.style.height = labelDim + "px"; + labelDiv.style.textAlign = "center"; + labelDiv.style.verticalAlign = "middle"; + labelDiv.style.position = "absolute"; + container.appendChild(labelDiv); + } + } + ctx.restore(); + ctx.fillStyle = ticks.color; + ctx.fillRect(-(size.width/2)+margin.left+config.labelOffset+label.size, Math.round(axis), size.width-margin.right-margin.left-config.labelOffset-label.size,1 ); + htmlOrigin += segmentLength; + axis += segmentLength; + labelValue += labelIncrement; + } + } + + + + + }, + + renderBackground: function() { + var canvas = this.canvas, + config = this.config, + backgroundColor = config.backgroundColor, + size = canvas.getSize(), + ctx = canvas.getCtx(); + ctx.fillStyle = backgroundColor; + ctx.fillRect(-size.width/2,-size.height/2,size.width,size.height); + }, + /* + Method: loadJSON + + Loads JSON data into the visualization. + + Parameters: + + json - The JSON data format. This format is described in . + + Example: + (start code js) + var barChart = new $jit.BarChart(options); + barChart.loadJSON(json); + (end code) + */ + loadJSON: function(json) { + if(this.busy) return; + this.busy = true; + + var prefix = $.time(), + ch = [], + st = this.st, + name = $.splat(json.label), + color = $.splat(json.color || this.colors), + config = this.config, + gradient = !!config.type.split(":")[1], + renderBackground = config.renderBackground, + animate = config.animate, + ticks = config.Ticks, + title = config.Title, + note = config.ScrollNote, + subtitle = config.Subtitle, + horz = config.orientation == 'horizontal', + that = this, + colorLength = color.length, + nameLength = name.length; + groupTotalValue = 0; + for(var i=0, values=json.values, l=values.length; i. + onComplete - (object) A callback object to be called when the animation transition when updating the data end. + + Example: + + (start code js) + barChart.updateJSON(json, { + onComplete: function() { + alert('update complete!'); + } + }); + (end code) + */ + updateJSON: function(json, onComplete) { + if(this.busy) return; + this.busy = true; + + var st = this.st; + var graph = st.graph; + var values = json.values; + var animate = this.config.animate; + var that = this; + var horz = this.config.orientation == 'horizontal'; + $.each(values, function(v) { + var n = graph.getByName(v.label); + if(n) { + n.setData('valueArray', $.splat(v.values)); + if(json.label) { + n.setData('stringArray', $.splat(json.label)); + } + } + }); + this.normalizeDims(); + st.compute(); + st.select(st.root); + if(animate) { + if(horz) { + st.fx.animate({ + modes: ['node-property:width:dimArray'], + duration:1500, + onComplete: function() { + that.busy = false; + onComplete && onComplete.onComplete(); + } + }); + } else { + st.fx.animate({ + modes: ['node-property:height:dimArray'], + duration:1500, + onComplete: function() { + that.busy = false; + onComplete && onComplete.onComplete(); + } + }); + } + } + }, + + //adds the little brown bar when hovering the node + select: function(id, name) { + + if(!this.config.hoveredColor) return; + var s = this.selected; + if(s.id != id || s.name != name) { + s.id = id; + s.name = name; + s.color = this.config.hoveredColor; + this.st.graph.eachNode(function(n) { + if(id == n.id) { + n.setData('border', s); + } else { + n.setData('border', false); + } + }); + this.st.plot(); + } + }, + + /* + Method: getLegend + + Returns an object containing as keys the legend names and as values hex strings with color values. + + Example: + + (start code js) + var legend = barChart.getLegend(); + (end code) + */ + getLegend: function() { + var legend = new Array(); + var name = new Array(); + var color = new Array(); + var n; + this.st.graph.getNode(this.st.root).eachAdjacency(function(adj) { + n = adj.nodeTo; + }); + var colors = n.getData('colorArray'), + len = colors.length; + $.each(n.getData('stringArray'), function(s, i) { + color[i] = colors[i % len]; + name[i] = s; + }); + legend['name'] = name; + legend['color'] = color; + return legend; + }, + + /* + Method: getMaxValue + + Returns the maximum accumulated value for the stacks. This method is used for normalizing the graph heights according to the canvas height. + + Example: + + (start code js) + var ans = barChart.getMaxValue(); + (end code) + + In some cases it could be useful to override this method to normalize heights for a group of BarCharts, like when doing small multiples. + + Example: + + (start code js) + //will return 100 for all BarChart instances, + //displaying all of them with the same scale + $jit.BarChart.implement({ + 'getMaxValue': function() { + return 100; + } + }); + (end code) + + */ + getMaxValue: function() { + var maxValue = 0, stacked = this.config.type.split(':')[0] == 'stacked'; + this.st.graph.eachNode(function(n) { + var valArray = n.getData('valueArray'), + acum = 0; + if(!valArray) return; + if(stacked) { + $.each(valArray, function(v) { + acum += +v; + }); + } else { + acum = Math.max.apply(null, valArray); + } + maxValue = maxValue>acum? maxValue:acum; + }); + return maxValue; + }, + + setBarType: function(type) { + this.config.type = type; + this.st.config.Node.type = 'barchart-' + type.split(':')[0]; + }, + + normalizeDims: function() { + //number of elements + var root = this.st.graph.getNode(this.st.root), l=0; + root.eachAdjacency(function() { + l++; + }); + var maxValue = this.getMaxValue() || 1, + size = this.st.canvas.getSize(), + config = this.config, + margin = config.Margin, + ticks = config.Ticks, + title = config.Title, + subtitle = config.Subtitle, + grouped = config.type.split(':')[0] == 'grouped', + marginWidth = margin.left + margin.right + (config.Label && grouped ? config.Label.size + config.labelOffset: 0), + marginHeight = (title.text? title.size + title.offset : 0) + (subtitle.text? subtitle.size + subtitle.offset : 0) + margin.top + margin.bottom, + horz = config.orientation == 'horizontal', + fixedDim = (size[horz? 'height':'width'] - (horz? marginHeight:marginWidth) - (ticks.enable? config.Label.size + config.labelOffset : 0) - (l -1) * config.barsOffset) / l, + animate = config.animate, + height = size[horz? 'width':'height'] - (horz? marginWidth:marginHeight) + + - ((config.showLabels && !horz) ? (config.Label.size + config.labelOffset) : 0), + dim1 = horz? 'height':'width', + dim2 = horz? 'width':'height', + basic = config.type.split(':')[0] == 'basic'; + + + var maxTickValue = Math.ceil(maxValue*.1)*10; + if(maxTickValue == maxValue) { + var length = maxTickValue.toString().length; + maxTickValue = maxTickValue + parseInt(pad(1,length)); + } + + fixedDim = fixedDim > 40 ? 40 : fixedDim; + + + this.st.graph.eachNode(function(n) { + var acum = 0, animateValue = []; + $.each(n.getData('valueArray'), function(v) { + acum += +v; + animateValue.push(0); + }); + + if(grouped) { + fixedDim = animateValue.length * 40; + } + n.setData(dim1, fixedDim); + + + if(animate) { + n.setData(dim2, acum * height / maxValue, 'end'); + n.setData('dimArray', $.map(n.getData('valueArray'), function(n) { + return n * height / maxValue; + }), 'end'); + var dimArray = n.getData('dimArray'); + if(!dimArray) { + n.setData('dimArray', animateValue); + } + } else { + + + if(ticks.enable) { + n.setData(dim2, acum * height / maxTickValue); + n.setData('dimArray', $.map(n.getData('valueArray'), function(n) { + return n * height / maxTickValue; + })); + } else { + n.setData(dim2, acum * height / maxValue); + n.setData('dimArray', $.map(n.getData('valueArray'), function(n) { + return n * height / maxValue; + })); + } + } + }); + } +}); + +//funnel chart options + + +Options.FunnelChart = { + $extend: true, + + animate: true, + type: 'stacked', //stacked, grouped, : gradient + labelOffset: 3, //label offset + barsOffset: 0, //distance between bars + hoveredColor: '#9fd4ff', + orientation: 'vertical', + showAggregates: true, + showLabels: true, + Tips: { + enable: false, + onShow: $.empty, + onHide: $.empty + }, + Events: { + enable: false, + onClick: $.empty + } +}; + +$jit.ST.Plot.NodeTypes.implement({ + 'funnelchart-basic' : { + 'render' : function(node, canvas) { + var pos = node.pos.getc(true), + width = node.getData('width'), + height = node.getData('height'), + algnPos = this.getAlignedPos(pos, width, height), + x = algnPos.x, y = algnPos.y, + dimArray = node.getData('dimArray'), + valueArray = node.getData('valueArray'), + valuelabelArray = node.getData('valuelabelArray'), + linkArray = node.getData('linkArray'), + colorArray = node.getData('colorArray'), + colorLength = colorArray.length, + stringArray = node.getData('stringArray'); + var ctx = canvas.getCtx(), + opt = {}, + border = node.getData('border'), + gradient = node.getData('gradient'), + config = node.getData('config'), + horz = config.orientation == 'horizontal', + aggregates = config.showAggregates, + showLabels = config.showLabels, + label = config.Label, + size = canvas.getSize(), + labelOffset = config.labelOffset + 10; + minWidth = width * .25; + ratio = .65; + + if (colorArray && dimArray && stringArray) { + + + // horizontal lines + for (var i=0, l=dimArray.length, acum=0, valAcum=0; i 0) ? dimArray[i - 1] : 100; + var labelOffsetHeight = (previousElementHeight < label.size && i > 0) ? ((dimArray[i] > label.size) ? (dimArray[i]/2) - (label.size/2) : label.size) : 0; + var topWidth = minWidth + ((acum + dimArray[i]) * ratio); + var bottomWidth = minWidth + ((acum) * ratio); + var bottomWidthLabel = minWidth + ((acum + labelOffsetHeight) * ratio); + var labelOffsetRight = (previousElementHeight < label.size && i > 0) ? ((i%2!=0 && dimArray[i] < label.size) ? mV.width + 20 : 0) : 0; + var labelOffsetLeft = (previousElementHeight < label.size && i > 0) ? ((i%2!=0 && dimArray[i] < label.size) ? mVL.width + 20 : 0) : 0; +// ctx.fillRect((-bottomWidth/2) - mVL.width - config.labelOffset , y - acum, bottomWidth + mVL.width + mV.width + (config.labelOffset*2), 1); + + //right lines + ctx.beginPath(); + ctx.moveTo(bottomWidth/2,y - acum); // + ctx.lineTo(bottomWidthLabel/2 + (labelOffset-10),y - acum - labelOffsetHeight); // top right + ctx.lineTo(bottomWidthLabel/2 + (labelOffset) + labelOffsetRight + mV.width,y - acum - labelOffsetHeight); // bottom right + ctx.stroke(); + //left lines + ctx.beginPath(); + ctx.moveTo(-bottomWidth/2,y - acum); // + ctx.lineTo(-bottomWidthLabel/2 - (labelOffset-10),y - acum - labelOffsetHeight); // top right + ctx.lineTo(-bottomWidthLabel/2 - (labelOffset) - labelOffsetLeft -mVL.width,y - acum - labelOffsetHeight); // bottom right + ctx.stroke(); + } + } + + acum += (dimArray[i] || 0); + valAcum += (valueArray[i] || 0); + + + } + + + + //funnel segments and labels + for (var i=0, l=dimArray.length, acum=0, valAcum=0; i 0) ? dimArray[i - 1] : 100; + var labelOffsetHeight = (previousElementHeight < label.size && i > 0) ? ((dimArray[i] > label.size) ? (dimArray[i]/2) - (label.size/2) : label.size) : 0; + var labelOffsetRight = (previousElementHeight < label.size && i > 0) ? ((i%2!=0 && dimArray[i] < label.size) ? mV.width + 20 : 0) : 0; + var labelOffsetLeft = (previousElementHeight < label.size && i > 0) ? ((i%2!=0 && dimArray[i] < label.size) ? mVL.width + 20 : 0) : 0; + + var topWidth = minWidth + ((acum + dimArray[i]) * ratio); + var bottomWidth = minWidth + ((acum) * ratio); + var bottomWidthLabel = minWidth + ((acum + labelOffsetHeight) * ratio); + + + if(gradient) { + var linear; + linear = ctx.createLinearGradient(-topWidth/2, y - acum - dimArray[i]/2, topWidth/2, y - acum- dimArray[i]/2); + var colorRgb = $.hexToRgb(colori); + var color = $.map($.hexToRgb(colorArray[i % colorLength].slice(1)), + function(v) { return (v * .5) >> 0; }); + linear.addColorStop(0, 'rgba('+color+',1)'); + linear.addColorStop(0.5, 'rgba('+colorRgb+',1)'); + linear.addColorStop(1, 'rgba('+color+',1)'); + ctx.fillStyle = linear; + } + + ctx.beginPath(); + ctx.moveTo(-topWidth/2,y - acum - dimArray[i]); //top left + ctx.lineTo(topWidth/2,y - acum - dimArray[i]); // top right + ctx.lineTo(bottomWidth/2,y - acum); // bottom right + ctx.lineTo(-bottomWidth/2,y - acum); // bottom left + ctx.closePath(); + ctx.fill(); + + + if(border && border.name == stringArray[i]) { + opt.acum = acum; + opt.dimValue = dimArray[i]; + } + + + if(border) { + ctx.save(); + ctx.lineWidth = 2; + ctx.strokeStyle = border.color; + + //ctx.strokeRect(x + 1, y - opt.acum - opt.dimValue + 1, minWidth -2, opt.dimValue -2); + + ctx.restore(); + } + if(label.type == 'Native') { + ctx.save(); + ctx.fillStyle = ctx.strokeStyle = label.color; + ctx.font = label.style + ' ' + label.size + 'px ' + label.family; + ctx.textBaseline = 'middle'; + + acumValueLabel = valAcum; + + if(showLabels(node.name, valAcum, node)) { + + + ctx.textAlign = 'left'; + ctx.fillText(stringArray[i],(bottomWidthLabel/2) + labelOffset + labelOffsetRight, y - acum - labelOffsetHeight - label.size/2); + ctx.textAlign = 'right'; + ctx.fillText(valuelabelArray[i],(-bottomWidthLabel/2) - labelOffset - labelOffsetLeft, y - acum - labelOffsetHeight - label.size/2); + } + ctx.restore(); + } + + acum += (dimArray[i] || 0); + valAcum += (valueArray[i] || 0); + + } + + } + }, + 'contains': function(node, mpos) { + var pos = node.pos.getc(true), + width = node.getData('width'), + height = node.getData('height'), + algnPos = this.getAlignedPos(pos, width, height), + x = algnPos.x, y = algnPos.y, + dimArray = node.getData('dimArray'), + config = node.getData('config'), + st = node.getData('st'), + rx = mpos.x - x, + horz = config.orientation == 'horizontal', + minWidth = width * .25; + ratio = .65, + canvas = node.getData('canvas'), + size = canvas.getSize(), + offsetY = st.config.offsetY; + //bounding box check + + if(mpos.y > y || mpos.y < y - height) { + return false; + } + + var newY = Math.abs(mpos.y + offsetY); + var bound = minWidth + (newY * ratio); + var boundLeft = -bound/2; + var boundRight = bound/2; + if(mpos.x < boundLeft || mpos.x > boundRight ) { + return false; + } + + + //deep check + for(var i=0, l=dimArray.length, acum=(horz? x:y); i= intersec) { + return { + 'name': node.getData('stringArray')[i], + 'color': node.getData('colorArray')[i], + 'value': node.getData('valueArray')[i], + 'percentage': node.getData('percentageArray')[i], + 'valuelabel': node.getData('valuelabelArray')[i], + 'link': url, + 'label': node.name + }; + } + + } + return false; + } + } +}); + +/* + Class: FunnelChart + + A visualization that displays funnel charts. + + Constructor Options: + + See . + +*/ +$jit.FunnelChart = new Class({ + st: null, + colors: ["#004b9c", "#9c0079", "#9c0033", "#28009c", "#9c0000", "#7d009c", "#001a9c","#00809c","#009c80","#009c42","#009c07","#469c00","#799c00","#9c9600","#9c5c00"], + selected: {}, + busy: false, + + initialize: function(opt) { + this.controller = this.config = + $.merge(Options("Canvas", "Margin", "Label", "BarChart"), { + Label: { type: 'Native' } + }, opt); + //set functions for showLabels and showAggregates + var showLabels = this.config.showLabels, + typeLabels = $.type(showLabels), + showAggregates = this.config.showAggregates, + typeAggregates = $.type(showAggregates); + this.config.showLabels = typeLabels == 'function'? showLabels : $.lambda(showLabels); + this.config.showAggregates = typeAggregates == 'function'? showAggregates : $.lambda(showAggregates); + Options.Fx.clearCanvas = false; + this.initializeViz(); + }, + + initializeViz: function() { + var config = this.config, that = this; + var nodeType = config.type.split(":")[0], + horz = config.orientation == 'horizontal', + nodeLabels = {}; + var st = new $jit.ST({ + injectInto: config.injectInto, + orientation: horz? 'left' : 'bottom', + levelDistance: 0, + background: config.background, + renderBackground: config.renderBackground, + backgroundColor: config.backgroundColor, + colorStop1: config.colorStop1, + colorStop2: config.colorStop2, + siblingOffset: config.segmentOffset, + subtreeOffset: 0, + withLabels: config.Label.type != 'Native', + useCanvas: config.useCanvas, + Label: { + type: config.Label.type + }, + Node: { + overridable: true, + type: 'funnelchart-' + nodeType, + align: 'left', + width: 1, + height: 1 + }, + Edge: { + type: 'none' + }, + Tips: { + enable: config.Tips.enable, + type: 'Native', + force: true, + onShow: function(tip, node, contains) { + var elem = contains; + config.Tips.onShow(tip, elem, node); + if(elem.link != 'undefined' && elem.link != '') { + document.body.style.cursor = 'pointer'; + } + }, + onHide: function(call) { + document.body.style.cursor = 'default'; + + } + }, + Events: { + enable: true, + type: 'Native', + onClick: function(node, eventInfo, evt) { + if(!config.Events.enable) return; + var elem = eventInfo.getContains(); + config.Events.onClick(elem, eventInfo, evt); + }, + onMouseMove: function(node, eventInfo, evt) { + if(!config.hoveredColor) return; + if(node) { + var elem = eventInfo.getContains(); + that.select(node.id, elem.name, elem.index); + } else { + that.select(false, false, false); + } + } + }, + onCreateLabel: function(domElement, node) { + var labelConf = config.Label, + valueArray = node.getData('valueArray'), + idArray = node.getData('idArray'), + valuelabelArray = node.getData('valuelabelArray'), + stringArray = node.getData('stringArray'); + size = st.canvas.getSize() + prefix = $.time(); + + for(var i=0, l=valueArray.length; i. + onComplete - (object) A callback object to be called when the animation transition when updating the data end. + + Example: + + (start code js) + barChart.updateJSON(json, { + onComplete: function() { + alert('update complete!'); + } + }); + (end code) + */ + updateJSON: function(json, onComplete) { + if(this.busy) return; + this.busy = true; + + var st = this.st; + var graph = st.graph; + var values = json.values; + var animate = this.config.animate; + var that = this; + var horz = this.config.orientation == 'horizontal'; + $.each(values, function(v) { + var n = graph.getByName(v.label); + if(n) { + n.setData('valueArray', $.splat(v.values)); + if(json.label) { + n.setData('stringArray', $.splat(json.label)); + } + } + }); + this.normalizeDims(); + st.compute(); + st.select(st.root); + if(animate) { + if(horz) { + st.fx.animate({ + modes: ['node-property:width:dimArray'], + duration:1500, + onComplete: function() { + that.busy = false; + onComplete && onComplete.onComplete(); + } + }); + } else { + st.fx.animate({ + modes: ['node-property:height:dimArray'], + duration:1500, + onComplete: function() { + that.busy = false; + onComplete && onComplete.onComplete(); + } + }); + } + } + }, + + //adds the little brown bar when hovering the node + select: function(id, name) { + + if(!this.config.hoveredColor) return; + var s = this.selected; + if(s.id != id || s.name != name) { + s.id = id; + s.name = name; + s.color = this.config.hoveredColor; + this.st.graph.eachNode(function(n) { + if(id == n.id) { + n.setData('border', s); + } else { + n.setData('border', false); + } + }); + this.st.plot(); + } + }, + + /* + Method: getLegend + + Returns an object containing as keys the legend names and as values hex strings with color values. + + Example: + + (start code js) + var legend = barChart.getLegend(); + (end code) + */ + getLegend: function() { + var legend = new Array(); + var name = new Array(); + var color = new Array(); + var n; + this.st.graph.getNode(this.st.root).eachAdjacency(function(adj) { + n = adj.nodeTo; + }); + var colors = n.getData('colorArray'), + len = colors.length; + $.each(n.getData('stringArray'), function(s, i) { + color[i] = colors[i % len]; + name[i] = s; + }); + legend['name'] = name; + legend['color'] = color; + return legend; + }, + + /* + Method: getMaxValue + + Returns the maximum accumulated value for the stacks. This method is used for normalizing the graph heights according to the canvas height. + + Example: + + (start code js) + var ans = barChart.getMaxValue(); + (end code) + + In some cases it could be useful to override this method to normalize heights for a group of BarCharts, like when doing small multiples. + + Example: + + (start code js) + //will return 100 for all BarChart instances, + //displaying all of them with the same scale + $jit.BarChart.implement({ + 'getMaxValue': function() { + return 100; + } + }); + (end code) + + */ + getMaxValue: function() { + var maxValue = 0, stacked = true; + this.st.graph.eachNode(function(n) { + var valArray = n.getData('valueArray'), + acum = 0; + if(!valArray) return; + if(stacked) { + $.each(valArray, function(v) { + acum += +v; + }); + } else { + acum = Math.max.apply(null, valArray); + } + maxValue = maxValue>acum? maxValue:acum; + }); + return maxValue; + }, + + setBarType: function(type) { + this.config.type = type; + this.st.config.Node.type = 'funnelchart-' + type.split(':')[0]; + }, + + normalizeDims: function() { + //number of elements + var root = this.st.graph.getNode(this.st.root), l=0; + root.eachAdjacency(function() { + l++; + }); + var maxValue = this.getMaxValue() || 1, + size = this.st.canvas.getSize(), + config = this.config, + margin = config.Margin, + title = config.Title, + subtitle = config.Subtitle, + marginWidth = margin.left + margin.right, + marginHeight = (title.text? title.size + title.offset : 0) + (subtitle.text? subtitle.size + subtitle.offset : 0) + margin.top + margin.bottom, + horz = config.orientation == 'horizontal', + animate = config.animate, + height = size[horz? 'width':'height'] - (horz? marginWidth:marginHeight) + + - (config.showLabels && (config.Label.size + config.labelOffset)), + dim1 = horz? 'height':'width', + dim2 = horz? 'width':'height'; + + + minWidth = size.width/8; + + + + this.st.graph.eachNode(function(n) { + var acum = 0, animateValue = []; + $.each(n.getData('valueArray'), function(v) { + acum += +v; + animateValue.push(0); + }); + n.setData(dim1, minWidth); + + if(animate) { + n.setData(dim2, acum * height / maxValue, 'end'); + n.setData('dimArray', $.map(n.getData('valueArray'), function(n) { + return n * height / maxValue; + }), 'end'); + var dimArray = n.getData('dimArray'); + if(!dimArray) { + n.setData('dimArray', animateValue); + } + } else { + n.setData(dim2, acum * height / maxValue); + n.setData('dimArray', $.map(n.getData('valueArray'), function(n) { + return n * height / maxValue; + })); + } + + }); + } +}); + + + +/* + * File: Options.PieChart.js + * +*/ +/* + Object: Options.PieChart + + options. + Other options included in the PieChart are , , and . + + Syntax: + + (start code js) + + Options.PieChart = { + animate: true, + offset: 25, + sliceOffset:0, + labelOffset: 3, + type: 'stacked', + hoveredColor: '#9fd4ff', + showLabels: true, + resizeLabels: false, + updateHeights: false + }; + + (end code) + + Example: + + (start code js) + + var pie = new $jit.PieChart({ + animate: true, + sliceOffset: 5, + type: 'stacked:gradient' + }); + + (end code) + + Parameters: + + animate - (boolean) Default's *true*. Whether to add animated transitions when plotting/updating the visualization. + offset - (number) Default's *25*. Adds margin between the visualization and the canvas. + sliceOffset - (number) Default's *0*. Separation between the center of the canvas and each pie slice. + labelOffset - (number) Default's *3*. Adds margin between the label and the default place where it should be drawn. + type - (string) Default's *'stacked'*. Stack style. Posible values are 'stacked', 'stacked:gradient' to add gradients. + hoveredColor - (boolean|string) Default's *'#9fd4ff'*. Sets the selected color for a hovered pie stack. + showLabels - (boolean) Default's *true*. Display the name of the slots. + resizeLabels - (boolean|number) Default's *false*. Resize the pie labels according to their stacked values. Set a number for *resizeLabels* to set a font size minimum. + updateHeights - (boolean) Default's *false*. Only for mono-valued (most common) pie charts. Resize the height of the pie slices according to their current values. + +*/ +Options.PieChart = { + $extend: true, + + animate: true, + offset: 25, // page offset + sliceOffset:0, + labelOffset: 3, // label offset + type: 'stacked', // gradient + labelType: 'name', + hoveredColor: '#9fd4ff', + Events: { + enable: false, + onClick: $.empty + }, + Tips: { + enable: false, + onShow: $.empty, + onHide: $.empty + }, + showLabels: true, + resizeLabels: false, + + //only valid for mono-valued datasets + updateHeights: false +}; + +/* + * Class: Layouts.Radial + * + * Implements a Radial Layout. + * + * Implemented By: + * + * , + * + */ +Layouts.Radial = new Class({ + + /* + * Method: compute + * + * Computes nodes' positions. + * + * Parameters: + * + * property - _optional_ A position property to store the new + * positions. Possible values are 'pos', 'end' or 'start'. + * + */ + compute : function(property) { + var prop = $.splat(property || [ 'current', 'start', 'end' ]); + NodeDim.compute(this.graph, prop, this.config); + this.graph.computeLevels(this.root, 0, "ignore"); + var lengthFunc = this.createLevelDistanceFunc(); + this.computeAngularWidths(prop); + this.computePositions(prop, lengthFunc); + }, + + /* + * computePositions + * + * Performs the main algorithm for computing node positions. + */ + computePositions : function(property, getLength) { + var propArray = property; + var graph = this.graph; + var root = graph.getNode(this.root); + var parent = this.parent; + var config = this.config; + + for ( var i=0, l=propArray.length; i < l; i++) { + var pi = propArray[i]; + root.setPos($P(0, 0), pi); + root.setData('span', Math.PI * 2, pi); + } + + root.angleSpan = { + begin : 0, + end : 2 * Math.PI + }; + + graph.eachBFS(this.root, function(elem) { + var angleSpan = elem.angleSpan.end - elem.angleSpan.begin; + var angleInit = elem.angleSpan.begin; + var len = getLength(elem); + //Calculate the sum of all angular widths + var totalAngularWidths = 0, subnodes = [], maxDim = {}; + elem.eachSubnode(function(sib) { + totalAngularWidths += sib._treeAngularWidth; + //get max dim + for ( var i=0, l=propArray.length; i < l; i++) { + var pi = propArray[i], dim = sib.getData('dim', pi); + maxDim[pi] = (pi in maxDim)? (dim > maxDim[pi]? dim : maxDim[pi]) : dim; + } + subnodes.push(sib); + }, "ignore"); + //Maintain children order + //Second constraint for + if (parent && parent.id == elem.id && subnodes.length > 0 + && subnodes[0].dist) { + subnodes.sort(function(a, b) { + return (a.dist >= b.dist) - (a.dist <= b.dist); + }); + } + //Calculate nodes positions. + for (var k = 0, ls=subnodes.length; k < ls; k++) { + var child = subnodes[k]; + if (!child._flag) { + var angleProportion = child._treeAngularWidth / totalAngularWidths * angleSpan; + var theta = angleInit + angleProportion / 2; + + for ( var i=0, l=propArray.length; i < l; i++) { + var pi = propArray[i]; + child.setPos($P(theta, len), pi); + child.setData('span', angleProportion, pi); + child.setData('dim-quotient', child.getData('dim', pi) / maxDim[pi], pi); + } + + child.angleSpan = { + begin : angleInit, + end : angleInit + angleProportion + }; + angleInit += angleProportion; + } + } + }, "ignore"); + }, + + /* + * Method: setAngularWidthForNodes + * + * Sets nodes angular widths. + */ + setAngularWidthForNodes : function(prop) { + this.graph.eachBFS(this.root, function(elem, i) { + var diamValue = elem.getData('angularWidth', prop[0]) || 5; + elem._angularWidth = diamValue / i; + }, "ignore"); + }, + + /* + * Method: setSubtreesAngularWidth + * + * Sets subtrees angular widths. + */ + setSubtreesAngularWidth : function() { + var that = this; + this.graph.eachNode(function(elem) { + that.setSubtreeAngularWidth(elem); + }, "ignore"); + }, + + /* + * Method: setSubtreeAngularWidth + * + * Sets the angular width for a subtree. + */ + setSubtreeAngularWidth : function(elem) { + var that = this, nodeAW = elem._angularWidth, sumAW = 0; + elem.eachSubnode(function(child) { + that.setSubtreeAngularWidth(child); + sumAW += child._treeAngularWidth; + }, "ignore"); + elem._treeAngularWidth = Math.max(nodeAW, sumAW); + }, + + /* + * Method: computeAngularWidths + * + * Computes nodes and subtrees angular widths. + */ + computeAngularWidths : function(prop) { + this.setAngularWidthForNodes(prop); + this.setSubtreesAngularWidth(); + } + +}); + + +/* + * File: Sunburst.js + */ + +/* + Class: Sunburst + + A radial space filling tree visualization. + + Inspired by: + + Sunburst . + + Note: + + This visualization was built and engineered from scratch, taking only the paper as inspiration, and only shares some features with the visualization described in the paper. + + Implements: + + All methods + + Constructor Options: + + Inherits options from + + - + - + - + - + - + - + - + - + - + + Additionally, there are other parameters and some default values changed + + interpolation - (string) Default's *linear*. Describes the way nodes are interpolated. Possible values are 'linear' and 'polar'. + levelDistance - (number) Default's *100*. The distance between levels of the tree. + Node.type - Described in . Default's to *multipie*. + Node.height - Described in . Default's *0*. + Edge.type - Described in . Default's *none*. + Label.textAlign - Described in . Default's *start*. + Label.textBaseline - Described in . Default's *middle*. + + Instance Properties: + + canvas - Access a instance. + graph - Access a instance. + op - Access a instance. + fx - Access a instance. + labels - Access a interface implementation. + +*/ + +$jit.Sunburst = new Class({ + + Implements: [ Loader, Extras, Layouts.Radial ], + + initialize: function(controller) { + var $Sunburst = $jit.Sunburst; + + var config = { + interpolation: 'linear', + levelDistance: 100, + Node: { + 'type': 'multipie', + 'height':0 + }, + Edge: { + 'type': 'none' + }, + Label: { + textAlign: 'start', + textBaseline: 'middle' + } + }; + + this.controller = this.config = $.merge(Options("Canvas", "Node", "Edge", + "Fx", "Tips", "NodeStyles", "Events", "Navigation", "Controller", "Label"), config, controller); + + var canvasConfig = this.config; + if(canvasConfig.useCanvas) { + this.canvas = canvasConfig.useCanvas; + this.config.labelContainer = this.canvas.id + '-label'; + } else { + if(canvasConfig.background) { + canvasConfig.background = $.merge({ + type: 'Fade', + colorStop1: this.config.colorStop1, + colorStop2: this.config.colorStop2 + }, canvasConfig.background); + } + this.canvas = new Canvas(this, canvasConfig); + this.config.labelContainer = (typeof canvasConfig.injectInto == 'string'? canvasConfig.injectInto : canvasConfig.injectInto.id) + '-label'; + } + + this.graphOptions = { + 'complex': false, + 'Node': { + 'selected': false, + 'exist': true, + 'drawn': true + } + }; + this.graph = new Graph(this.graphOptions, this.config.Node, + this.config.Edge); + this.labels = new $Sunburst.Label[canvasConfig.Label.type](this); + this.fx = new $Sunburst.Plot(this, $Sunburst); + this.op = new $Sunburst.Op(this); + this.json = null; + this.root = null; + this.rotated = null; + this.busy = false; + // initialize extras + this.initializeExtras(); + }, + + /* + + createLevelDistanceFunc + + Returns the levelDistance function used for calculating a node distance + to its origin. This function returns a function that is computed + per level and not per node, such that all nodes with the same depth will have the + same distance to the origin. The resulting function gets the + parent node as parameter and returns a float. + + */ + createLevelDistanceFunc: function() { + var ld = this.config.levelDistance; + return function(elem) { + return (elem._depth + 1) * ld; + }; + }, + + /* + Method: refresh + + Computes positions and plots the tree. + + */ + refresh: function() { + this.compute(); + this.plot(); + }, + + /* + reposition + + An alias for computing new positions to _endPos_ + + See also: + + + + */ + reposition: function() { + this.compute('end'); + }, + + /* + Method: rotate + + Rotates the graph so that the selected node is horizontal on the right. + + Parameters: + + node - (object) A . + method - (string) Whether to perform an animation or just replot the graph. Possible values are "replot" or "animate". + opt - (object) Configuration options merged with this visualization configuration options. + + See also: + + + + */ + rotate: function(node, method, opt) { + var theta = node.getPos(opt.property || 'current').getp(true).theta; + this.rotated = node; + this.rotateAngle(-theta, method, opt); + }, + + /* + Method: rotateAngle + + Rotates the graph of an angle theta. + + Parameters: + + node - (object) A . + method - (string) Whether to perform an animation or just replot the graph. Possible values are "replot" or "animate". + opt - (object) Configuration options merged with this visualization configuration options. + + See also: + + + + */ + rotateAngle: function(theta, method, opt) { + var that = this; + var options = $.merge(this.config, opt || {}, { + modes: [ 'polar' ] + }); + var prop = opt.property || (method === "animate" ? 'end' : 'current'); + if(method === 'animate') { + this.fx.animation.pause(); + } + this.graph.eachNode(function(n) { + var p = n.getPos(prop); + p.theta += theta; + if (p.theta < 0) { + p.theta += Math.PI * 2; + } + }); + if (method == 'animate') { + this.fx.animate(options); + } else if (method == 'replot') { + this.fx.plot(); + this.busy = false; + } + }, + + /* + Method: plot + + Plots the Sunburst. This is a shortcut to *fx.plot*. + */ + plot: function() { + this.fx.plot(); + } +}); + +$jit.Sunburst.$extend = true; + +(function(Sunburst) { + + /* + Class: Sunburst.Op + + Custom extension of . + + Extends: + + All methods + + See also: + + + + */ + Sunburst.Op = new Class( { + + Implements: Graph.Op + + }); + + /* + Class: Sunburst.Plot + + Custom extension of . + + Extends: + + All methods + + See also: + + + + */ + Sunburst.Plot = new Class( { + + Implements: Graph.Plot + + }); + + /* + Class: Sunburst.Label + + Custom extension of . + Contains custom , and extensions. + + Extends: + + All methods and subclasses. + + See also: + + , , , . + + */ + Sunburst.Label = {}; + + /* + Sunburst.Label.Native + + Custom extension of . + + Extends: + + All methods + + See also: + + + */ + Sunburst.Label.Native = new Class( { + Implements: Graph.Label.Native, + + initialize: function(viz) { + this.viz = viz; + this.label = viz.config.Label; + this.config = viz.config; + }, + + renderLabel: function(canvas, node, controller) { + var span = node.getData('span'); + if(span < Math.PI /2 && Math.tan(span) * + this.config.levelDistance * node._depth < 10) { + return; + } + var ctx = canvas.getCtx(); + var measure = ctx.measureText(node.name); + if (node.id == this.viz.root) { + var x = -measure.width / 2, y = 0, thetap = 0; + var ld = 0; + } else { + var indent = 5; + var ld = controller.levelDistance - indent; + var clone = node.pos.clone(); + clone.rho += indent; + var p = clone.getp(true); + var ct = clone.getc(true); + var x = ct.x, y = ct.y; + // get angle in degrees + var pi = Math.PI; + var cond = (p.theta > pi / 2 && p.theta < 3 * pi / 2); + var thetap = cond ? p.theta + pi : p.theta; + if (cond) { + x -= Math.abs(Math.cos(p.theta) * measure.width); + y += Math.sin(p.theta) * measure.width; + } else if (node.id == this.viz.root) { + x -= measure.width / 2; + } + } + ctx.save(); + ctx.translate(x, y); + ctx.rotate(thetap); + ctx.fillText(node.name, 0, 0); + ctx.restore(); + } + }); + + /* + Sunburst.Label.SVG + + Custom extension of . + + Extends: + + All methods + + See also: + + + + */ + Sunburst.Label.SVG = new Class( { + Implements: Graph.Label.SVG, + + initialize: function(viz) { + this.viz = viz; + }, + + /* + placeLabel + + Overrides abstract method placeLabel in . + + Parameters: + + tag - A DOM label element. + node - A . + controller - A configuration/controller object passed to the visualization. + + */ + placeLabel: function(tag, node, controller) { + var pos = node.pos.getc(true), viz = this.viz, canvas = this.viz.canvas; + var radius = canvas.getSize(); + var labelPos = { + x: Math.round(pos.x + radius.width / 2), + y: Math.round(pos.y + radius.height / 2) + }; + tag.setAttribute('x', labelPos.x); + tag.setAttribute('y', labelPos.y); + + var bb = tag.getBBox(); + if (bb) { + // center the label + var x = tag.getAttribute('x'); + var y = tag.getAttribute('y'); + // get polar coordinates + var p = node.pos.getp(true); + // get angle in degrees + var pi = Math.PI; + var cond = (p.theta > pi / 2 && p.theta < 3 * pi / 2); + if (cond) { + tag.setAttribute('x', x - bb.width); + tag.setAttribute('y', y - bb.height); + } else if (node.id == viz.root) { + tag.setAttribute('x', x - bb.width / 2); + } + + var thetap = cond ? p.theta + pi : p.theta; + if(node._depth) + tag.setAttribute('transform', 'rotate(' + thetap * 360 / (2 * pi) + ' ' + x + + ' ' + y + ')'); + } + + controller.onPlaceLabel(tag, node); +} + }); + + /* + Sunburst.Label.HTML + + Custom extension of . + + Extends: + + All methods. + + See also: + + + + */ + Sunburst.Label.HTML = new Class( { + Implements: Graph.Label.HTML, + + initialize: function(viz) { + this.viz = viz; + }, + /* + placeLabel + + Overrides abstract method placeLabel in . + + Parameters: + + tag - A DOM label element. + node - A . + controller - A configuration/controller object passed to the visualization. + + */ + placeLabel: function(tag, node, controller) { + var pos = node.pos.clone(), + canvas = this.viz.canvas, + height = node.getData('height'), + ldist = ((height || node._depth == 0)? height : this.viz.config.levelDistance) /2, + radius = canvas.getSize(); + pos.rho += ldist; + pos = pos.getc(true); + + var labelPos = { + x: Math.round(pos.x + radius.width / 2), + y: Math.round(pos.y + radius.height / 2) + }; + + var style = tag.style; + style.left = labelPos.x + 'px'; + style.top = labelPos.y + 'px'; + style.display = this.fitsInCanvas(labelPos, canvas) ? '' : 'none'; + + controller.onPlaceLabel(tag, node); + } + }); + + /* + Class: Sunburst.Plot.NodeTypes + + This class contains a list of built-in types. + Node types implemented are 'none', 'pie', 'multipie', 'gradient-pie' and 'gradient-multipie'. + + You can add your custom node types, customizing your visualization to the extreme. + + Example: + + (start code js) + Sunburst.Plot.NodeTypes.implement({ + 'mySpecialType': { + 'render': function(node, canvas) { + //print your custom node to canvas + }, + //optional + 'contains': function(node, pos) { + //return true if pos is inside the node or false otherwise + } + } + }); + (end code) + + */ + Sunburst.Plot.NodeTypes = new Class( { + 'none': { + 'render': $.empty, + 'contains': $.lambda(false), + 'anglecontains': function(node, pos) { + var span = node.getData('span') / 2, theta = node.pos.theta; + var begin = theta - span, end = theta + span; + if (begin < 0) + begin += Math.PI * 2; + var atan = Math.atan2(pos.y, pos.x); + if (atan < 0) + atan += Math.PI * 2; + if (begin > end) { + return (atan > begin && atan <= Math.PI * 2) || atan < end; + } else { + return atan > begin && atan < end; + } + }, + 'anglecontainsgauge': function(node, pos) { + var span = node.getData('span') / 2, theta = node.pos.theta; + var config = node.getData('config'); + var ld = this.config.levelDistance; + var yOffset = pos.y-(ld/2); + var begin = ((theta - span)/2)+Math.PI, + end = ((theta + span)/2)+Math.PI; + + if (begin < 0) + begin += Math.PI * 2; + var atan = Math.atan2(yOffset, pos.x); + + + if (atan < 0) + atan += Math.PI * 2; + + + if (begin > end) { + return (atan > begin && atan <= Math.PI * 2) || atan < end; + } else { + return atan > begin && atan < end; + } + } + }, + + 'pie': { + 'render': function(node, canvas) { + var span = node.getData('span') / 2, theta = node.pos.theta; + var begin = theta - span, end = theta + span; + var polarNode = node.pos.getp(true); + var polar = new Polar(polarNode.rho, begin); + var p1coord = polar.getc(true); + polar.theta = end; + var p2coord = polar.getc(true); + + var ctx = canvas.getCtx(); + ctx.beginPath(); + ctx.moveTo(0, 0); + ctx.lineTo(p1coord.x, p1coord.y); + ctx.moveTo(0, 0); + ctx.lineTo(p2coord.x, p2coord.y); + ctx.moveTo(0, 0); + ctx.arc(0, 0, polarNode.rho * node.getData('dim-quotient'), begin, end, + false); + ctx.fill(); + }, + 'contains': function(node, pos) { + if (this.nodeTypes['none'].anglecontains.call(this, node, pos)) { + var rho = Math.sqrt(pos.x * pos.x + pos.y * pos.y); + var ld = this.config.levelDistance, d = node._depth; + return (rho <= ld * d); + } + return false; + } + }, + 'multipie': { + 'render': function(node, canvas) { + var height = node.getData('height'); + var ldist = height? height : this.config.levelDistance; + var span = node.getData('span') / 2, theta = node.pos.theta; + var begin = theta - span, end = theta + span; + var polarNode = node.pos.getp(true); + + var polar = new Polar(polarNode.rho, begin); + var p1coord = polar.getc(true); + + polar.theta = end; + var p2coord = polar.getc(true); + + polar.rho += ldist; + var p3coord = polar.getc(true); + + polar.theta = begin; + var p4coord = polar.getc(true); + + var ctx = canvas.getCtx(); + ctx.moveTo(0, 0); + ctx.beginPath(); + ctx.arc(0, 0, polarNode.rho, begin, end, false); + ctx.arc(0, 0, polarNode.rho + ldist, end, begin, true); + ctx.moveTo(p1coord.x, p1coord.y); + ctx.lineTo(p4coord.x, p4coord.y); + ctx.moveTo(p2coord.x, p2coord.y); + ctx.lineTo(p3coord.x, p3coord.y); + ctx.fill(); + + if (node.collapsed) { + ctx.save(); + ctx.lineWidth = 2; + ctx.moveTo(0, 0); + ctx.beginPath(); + ctx.arc(0, 0, polarNode.rho + ldist + 5, end - 0.01, begin + 0.01, + true); + ctx.stroke(); + ctx.restore(); + } + }, + 'contains': function(node, pos) { + if (this.nodeTypes['none'].anglecontains.call(this, node, pos)) { + var rho = Math.sqrt(pos.x * pos.x + pos.y * pos.y); + var height = node.getData('height'); + var ldist = height? height : this.config.levelDistance; + var ld = this.config.levelDistance, d = node._depth; + return (rho >= ld * d) && (rho <= (ld * d + ldist)); + } + return false; + } + }, + + 'gradient-multipie': { + 'render': function(node, canvas) { + var ctx = canvas.getCtx(); + var height = node.getData('height'); + var ldist = height? height : this.config.levelDistance; + var radialGradient = ctx.createRadialGradient(0, 0, node.getPos().rho, + 0, 0, node.getPos().rho + ldist); + + var colorArray = $.hexToRgb(node.getData('color')), ans = []; + $.each(colorArray, function(i) { + ans.push(parseInt(i * 0.5, 10)); + }); + var endColor = $.rgbToHex(ans); + radialGradient.addColorStop(0, endColor); + radialGradient.addColorStop(1, node.getData('color')); + ctx.fillStyle = radialGradient; + this.nodeTypes['multipie'].render.call(this, node, canvas); + }, + 'contains': function(node, pos) { + return this.nodeTypes['multipie'].contains.call(this, node, pos); + } + }, + + 'gradient-pie': { + 'render': function(node, canvas) { + var ctx = canvas.getCtx(); + var radialGradient = ctx.createRadialGradient(0, 0, 0, 0, 0, node + .getPos().rho); + + var colorArray = $.hexToRgb(node.getData('color')), ans = []; + $.each(colorArray, function(i) { + ans.push(parseInt(i * 0.5, 10)); + }); + var endColor = $.rgbToHex(ans); + radialGradient.addColorStop(1, endColor); + radialGradient.addColorStop(0, node.getData('color')); + ctx.fillStyle = radialGradient; + this.nodeTypes['pie'].render.call(this, node, canvas); + }, + 'contains': function(node, pos) { + return this.nodeTypes['pie'].contains.call(this, node, pos); + } + } + }); + + /* + Class: Sunburst.Plot.EdgeTypes + + This class contains a list of built-in types. + Edge types implemented are 'none', 'line' and 'arrow'. + + You can add your custom edge types, customizing your visualization to the extreme. + + Example: + + (start code js) + Sunburst.Plot.EdgeTypes.implement({ + 'mySpecialType': { + 'render': function(adj, canvas) { + //print your custom edge to canvas + }, + //optional + 'contains': function(adj, pos) { + //return true if pos is inside the arc or false otherwise + } + } + }); + (end code) + + */ + Sunburst.Plot.EdgeTypes = new Class({ + 'none': $.empty, + 'line': { + 'render': function(adj, canvas) { + var from = adj.nodeFrom.pos.getc(true), + to = adj.nodeTo.pos.getc(true); + this.edgeHelper.line.render(from, to, canvas); + }, + 'contains': function(adj, pos) { + var from = adj.nodeFrom.pos.getc(true), + to = adj.nodeTo.pos.getc(true); + return this.edgeHelper.line.contains(from, to, pos, this.edge.epsilon); + } + }, + 'arrow': { + 'render': function(adj, canvas) { + var from = adj.nodeFrom.pos.getc(true), + to = adj.nodeTo.pos.getc(true), + dim = adj.getData('dim'), + direction = adj.data.$direction, + inv = (direction && direction.length>1 && direction[0] != adj.nodeFrom.id); + this.edgeHelper.arrow.render(from, to, dim, inv, canvas); + }, + 'contains': function(adj, pos) { + var from = adj.nodeFrom.pos.getc(true), + to = adj.nodeTo.pos.getc(true); + return this.edgeHelper.arrow.contains(from, to, pos, this.edge.epsilon); + } + }, + 'hyperline': { + 'render': function(adj, canvas) { + var from = adj.nodeFrom.pos.getc(), + to = adj.nodeTo.pos.getc(), + dim = Math.max(from.norm(), to.norm()); + this.edgeHelper.hyperline.render(from.$scale(1/dim), to.$scale(1/dim), dim, canvas); + }, + 'contains': $.lambda(false) //TODO(nico): Implement this! + } + }); + +})($jit.Sunburst); + + +/* + * File: PieChart.js + * +*/ + +$jit.Sunburst.Plot.NodeTypes.implement({ + 'piechart-stacked' : { + 'render' : function(node, canvas) { + var pos = node.pos.getp(true), + dimArray = node.getData('dimArray'), + valueArray = node.getData('valueArray'), + colorArray = node.getData('colorArray'), + colorLength = colorArray.length, + stringArray = node.getData('stringArray'), + span = node.getData('span') / 2, + theta = node.pos.theta, + begin = theta - span, + end = theta + span, + polar = new Polar; + + var ctx = canvas.getCtx(), + opt = {}, + gradient = node.getData('gradient'), + border = node.getData('border'), + config = node.getData('config'), + showLabels = config.showLabels, + resizeLabels = config.resizeLabels, + label = config.Label; + + var xpos = config.sliceOffset * Math.cos((begin + end) /2); + var ypos = config.sliceOffset * Math.sin((begin + end) /2); + + if (colorArray && dimArray && stringArray) { + for (var i=0, l=dimArray.length, acum=0, valAcum=0; i> 0; }), + endColor = $.rgbToHex(ans); + + radialGradient.addColorStop(0, colori); + radialGradient.addColorStop(0.5, colori); + radialGradient.addColorStop(1, endColor); + ctx.fillStyle = radialGradient; + } + + polar.rho = acum + config.sliceOffset; + polar.theta = begin; + var p1coord = polar.getc(true); + polar.theta = end; + var p2coord = polar.getc(true); + polar.rho += dimi; + var p3coord = polar.getc(true); + polar.theta = begin; + var p4coord = polar.getc(true); + + ctx.beginPath(); + //fixing FF arc method + fill + ctx.arc(xpos, ypos, acum + .01, begin, end, false); + ctx.arc(xpos, ypos, acum + dimi + .01, end, begin, true); + ctx.fill(); + if(border && border.name == stringArray[i]) { + opt.acum = acum; + opt.dimValue = dimArray[i]; + opt.begin = begin; + opt.end = end; + } + acum += (dimi || 0); + valAcum += (valueArray[i] || 0); + } + if(border) { + ctx.save(); + ctx.globalCompositeOperation = "source-over"; + ctx.lineWidth = 2; + ctx.strokeStyle = border.color; + var s = begin < end? 1 : -1; + ctx.beginPath(); + //fixing FF arc method + fill + ctx.arc(xpos, ypos, opt.acum + .01 + 1, opt.begin, opt.end, false); + ctx.arc(xpos, ypos, opt.acum + opt.dimValue + .01 - 1, opt.end, opt.begin, true); + ctx.closePath(); + ctx.stroke(); + ctx.restore(); + } + if(showLabels && label.type == 'Native') { + ctx.save(); + ctx.fillStyle = ctx.strokeStyle = label.color; + var scale = resizeLabels? node.getData('normalizedDim') : 1, + fontSize = (label.size * scale) >> 0; + fontSize = fontSize < +resizeLabels? +resizeLabels : fontSize; + + ctx.font = label.style + ' ' + fontSize + 'px ' + label.family; + ctx.textBaseline = 'middle'; + ctx.textAlign = 'center'; + + polar.rho = acum + config.labelOffset + config.sliceOffset; + polar.theta = node.pos.theta; + var cart = polar.getc(true); + + ctx.fillText(node.name, cart.x, cart.y); + ctx.restore(); + } + } + }, + 'contains': function(node, pos) { + if (this.nodeTypes['none'].anglecontains.call(this, node, pos)) { + var rho = Math.sqrt(pos.x * pos.x + pos.y * pos.y); + var ld = this.config.levelDistance, d = node._depth; + var config = node.getData('config'); + if(rho <=ld * d + config.sliceOffset) { + var dimArray = node.getData('dimArray'); + for(var i=0,l=dimArray.length,acum=config.sliceOffset; i= acum && rho <= acum + dimi) { + return { + name: node.getData('stringArray')[i], + color: node.getData('colorArray')[i], + value: node.getData('valueArray')[i], + label: node.name + }; + } + acum += dimi; + } + } + return false; + + } + return false; + } + }, + 'piechart-basic' : { + 'render' : function(node, canvas) { + var pos = node.pos.getp(true), + dimArray = node.getData('dimArray'), + valueArray = node.getData('valueArray'), + colorArray = node.getData('colorMono'), + colorLength = colorArray.length, + stringArray = node.getData('stringArray'), + percentage = node.getData('percentage'), + span = node.getData('span') / 2, + theta = node.pos.theta, + begin = theta - span, + end = theta + span, + polar = new Polar; + + var ctx = canvas.getCtx(), + opt = {}, + gradient = node.getData('gradient'), + border = node.getData('border'), + config = node.getData('config'), + showLabels = config.showLabels, + resizeLabels = config.resizeLabels, + label = config.Label; + + var xpos = config.sliceOffset * Math.cos((begin + end) /2); + var ypos = config.sliceOffset * Math.sin((begin + end) /2); + + if (colorArray && dimArray && stringArray) { + for (var i=0, l=dimArray.length, acum=0, valAcum=0; i> 0; }), + endColor2 = $.map(colorRgb, function(i) { return (i * 0.7) >> 0; }); + + radialGradient.addColorStop(0, 'rgba('+colorRgb+',1)'); + radialGradient.addColorStop(.7, 'rgba('+colorRgb+',1)'); + radialGradient.addColorStop(.98, 'rgba('+endColor+',1)'); + radialGradient.addColorStop(1, 'rgba('+endColor2+',1)'); + ctx.fillStyle = radialGradient; + } + } + + + //fixing FF arc method + fill + ctx.beginPath(); + ctx.arc(xpos, ypos, acum + .01, begin, end, false); + ctx.arc(xpos, ypos, acum + dimi + .01, end, begin, true); + ctx.fill(); + if(border && border.name == stringArray[i]) { + opt.acum = acum; + opt.dimValue = dimArray[i]; + opt.begin = begin; + opt.end = end; + opt.sliceValue = valueArray[i]; + } + acum += (dimi || 0); + valAcum += (valueArray[i] || 0); + } + if(border) { + ctx.save(); + ctx.globalCompositeOperation = "source-over"; + ctx.lineWidth = 2; + ctx.strokeStyle = border.color; + var s = begin < end? 1 : -1; + ctx.beginPath(); + //fixing FF arc method + fill + ctx.arc(xpos, ypos, opt.acum + .01 + 1, opt.begin, opt.end, false); + ctx.arc(xpos, ypos, opt.acum + opt.dimValue + .01 - 1, opt.end, opt.begin, true); + ctx.closePath(); + ctx.stroke(); + ctx.restore(); + } + if(showLabels && label.type == 'Native') { + ctx.save(); + ctx.fillStyle = ctx.strokeStyle = label.color; + var scale = resizeLabels? node.getData('normalizedDim') : 1, + fontSize = (label.size * scale) >> 0; + fontSize = fontSize < +resizeLabels? +resizeLabels : fontSize; + + ctx.font = label.style + ' ' + fontSize + 'px ' + label.family; + ctx.textBaseline = 'middle'; + ctx.textAlign = 'center'; + pi = Math.PI; + angle = theta * 360 / (2 * pi); + polar.rho = acum + config.labelOffset + config.sliceOffset; + polar.theta = node.pos.theta; + var cart = polar.getc(true); + if(((angle >= 225 && angle <= 315) || (angle <= 135 && angle >= 45)) && percentage <= 5) { + + } else { + if(config.labelType == 'name') { + ctx.fillText(node.name, cart.x, cart.y); + } else { + ctx.fillText(node.data.valuelabel, cart.x, cart.y); + } + } + ctx.restore(); + } + } + }, + 'contains': function(node, pos) { + if (this.nodeTypes['none'].anglecontains.call(this, node, pos)) { + var rho = Math.sqrt(pos.x * pos.x + pos.y * pos.y); + var ld = this.config.levelDistance, d = node._depth; + var config = node.getData('config'); + + if(rho <=ld * d + config.sliceOffset) { + var dimArray = node.getData('dimArray'); + for(var i=0,l=dimArray.length,acum=config.sliceOffset; i= acum && rho <= acum + dimi) { + var url = Url.decode(node.getData('linkArray')[i]); + return { + name: node.getData('stringArray')[i], + link: url, + color: node.getData('colorArray')[i], + value: node.getData('valueArray')[i], + percentage: node.getData('percentage'), + valuelabel: node.getData('valuelabelsArray')[i], + label: node.name + }; + } + acum += dimi; + } + } + return false; + + } + return false; + } + } +}); + +/* + Class: PieChart + + A visualization that displays stacked bar charts. + + Constructor Options: + + See . + +*/ +$jit.PieChart = new Class({ + sb: null, + colors: ["#416D9C", "#70A35E", "#EBB056", "#C74243", "#83548B", "#909291", "#557EAA"], + selected: {}, + busy: false, + + initialize: function(opt) { + this.controller = this.config = + $.merge(Options("Canvas", "PieChart", "Label"), { + Label: { type: 'Native' } + }, opt); + this.initializeViz(); + }, + + initializeViz: function() { + var config = this.config, that = this; + var nodeType = config.type.split(":")[0]; + var sb = new $jit.Sunburst({ + injectInto: config.injectInto, + useCanvas: config.useCanvas, + withLabels: config.Label.type != 'Native', + background: config.background, + renderBackground: config.renderBackground, + backgroundColor: config.backgroundColor, + colorStop1: config.colorStop1, + colorStop2: config.colorStop2, + Label: { + type: config.Label.type + }, + Node: { + overridable: true, + type: 'piechart-' + nodeType, + width: 1, + height: 1 + }, + Edge: { + type: 'none' + }, + Tips: { + enable: config.Tips.enable, + type: 'Native', + force: true, + onShow: function(tip, node, contains) { + var elem = contains; + config.Tips.onShow(tip, elem, node); + if(elem.link != 'undefined' && elem.link != '') { + document.body.style.cursor = 'pointer'; + } + }, + onHide: function() { + document.body.style.cursor = 'default'; + } + }, + Events: { + enable: true, + type: 'Native', + onClick: function(node, eventInfo, evt) { + if(!config.Events.enable) return; + var elem = eventInfo.getContains(); + config.Events.onClick(elem, eventInfo, evt); + }, + onMouseMove: function(node, eventInfo, evt) { + if(!config.hoveredColor) return; + if(node) { + var elem = eventInfo.getContains(); + that.select(node.id, elem.name, elem.index); + } else { + that.select(false, false, false); + } + } + }, + onCreateLabel: function(domElement, node) { + var labelConf = config.Label; + if(config.showLabels) { + var style = domElement.style; + style.fontSize = labelConf.size + 'px'; + style.fontFamily = labelConf.family; + style.color = labelConf.color; + style.textAlign = 'center'; + if(config.labelType == 'name') { + domElement.innerHTML = node.name; + } else { + domElement.innerHTML = (node.data.valuelabel != undefined) ? node.data.valuelabel : ""; + } + domElement.style.width = '400px'; + } + }, + onPlaceLabel: function(domElement, node) { + if(!config.showLabels) return; + var pos = node.pos.getp(true), + dimArray = node.getData('dimArray'), + span = node.getData('span') / 2, + theta = node.pos.theta, + begin = theta - span, + end = theta + span, + polar = new Polar; + + var showLabels = config.showLabels, + resizeLabels = config.resizeLabels, + label = config.Label; + + if (dimArray) { + for (var i=0, l=dimArray.length, acum=0; i> 0; + fontSize = fontSize < +resizeLabels? +resizeLabels : fontSize; + domElement.style.fontSize = fontSize + 'px'; + polar.rho = acum + config.labelOffset + config.sliceOffset; + polar.theta = (begin + end) / 2; + var pos = polar.getc(true); + var radius = that.canvas.getSize(); + var labelPos = { + x: Math.round(pos.x + radius.width / 2), + y: Math.round(pos.y + radius.height / 2) + }; + domElement.style.left = (labelPos.x - 200) + 'px'; + domElement.style.top = labelPos.y + 'px'; + } + } + }); + + var size = sb.canvas.getSize(), + min = Math.min; + sb.config.levelDistance = min(size.width, size.height)/2 + - config.offset - config.sliceOffset; + this.sb = sb; + this.canvas = this.sb.canvas; + this.canvas.getCtx().globalCompositeOperation = 'lighter'; + }, + renderBackground: function() { + var canvas = this.canvas, + config = this.config, + backgroundColor = config.backgroundColor, + size = canvas.getSize(), + ctx = canvas.getCtx(); + ctx.globalCompositeOperation = "destination-over"; + ctx.fillStyle = backgroundColor; + ctx.fillRect(-size.width/2,-size.height/2,size.width,size.height); + }, + /* + Method: loadJSON + + Loads JSON data into the visualization. + + Parameters: + + json - The JSON data format. This format is described in . + + Example: + (start code js) + var pieChart = new $jit.PieChart(options); + pieChart.loadJSON(json); + (end code) + */ + loadJSON: function(json) { + var prefix = $.time(), + ch = [], + sb = this.sb, + name = $.splat(json.label), + nameLength = name.length, + color = $.splat(json.color || this.colors), + colorLength = color.length, + config = this.config, + renderBackground = config.renderBackground, + gradient = !!config.type.split(":")[1], + animate = config.animate, + mono = nameLength == 1; + totalValue = 0; + for(var i=0, values=json.values, l=values.length; i. + onComplete - (object) A callback object to be called when the animation transition when updating the data end. + + Example: + + (start code js) + pieChart.updateJSON(json, { + onComplete: function() { + alert('update complete!'); + } + }); + (end code) + */ + updateJSON: function(json, onComplete) { + if(this.busy) return; + this.busy = true; + + var sb = this.sb; + var graph = sb.graph; + var values = json.values; + var animate = this.config.animate; + var that = this; + $.each(values, function(v) { + var n = graph.getByName(v.label), + vals = $.splat(v.values); + if(n) { + n.setData('valueArray', vals); + n.setData('angularWidth', $.reduce(vals, function(x,y){return x+y;})); + if(json.label) { + n.setData('stringArray', $.splat(json.label)); + } + } + }); + this.normalizeDims(); + if(animate) { + sb.compute('end'); + sb.fx.animate({ + modes: ['node-property:dimArray:span', 'linear'], + duration:1500, + onComplete: function() { + that.busy = false; + onComplete && onComplete.onComplete(); + } + }); + } else { + sb.refresh(); + } + }, + + //adds the little brown bar when hovering the node + select: function(id, name) { + if(!this.config.hoveredColor) return; + var s = this.selected; + if(s.id != id || s.name != name) { + s.id = id; + s.name = name; + s.color = this.config.hoveredColor; + this.sb.graph.eachNode(function(n) { + if(id == n.id) { + n.setData('border', s); + } else { + n.setData('border', false); + } + }); + this.sb.plot(); + } + }, + + /* + Method: getLegend + + Returns an object containing as keys the legend names and as values hex strings with color values. + + Example: + + (start code js) + var legend = pieChart.getLegend(); + (end code) + */ + getLegend: function() { + var legend = new Array(); + var name = new Array(); + var color = new Array(); + var n; + this.sb.graph.getNode(this.sb.root).eachAdjacency(function(adj) { + n = adj.nodeTo; + }); + var colors = n.getData('colorArray'), + len = colors.length; + $.each(n.getData('stringArray'), function(s, i) { + color[i] = colors[i % len]; + name[i] = s; + }); + legend['name'] = name; + legend['color'] = color; + return legend; + }, + + /* + Method: getMaxValue + + Returns the maximum accumulated value for the stacks. This method is used for normalizing the graph heights according to the canvas height. + + Example: + + (start code js) + var ans = pieChart.getMaxValue(); + (end code) + + In some cases it could be useful to override this method to normalize heights for a group of PieCharts, like when doing small multiples. + + Example: + + (start code js) + //will return 100 for all PieChart instances, + //displaying all of them with the same scale + $jit.PieChart.implement({ + 'getMaxValue': function() { + return 100; + } + }); + (end code) + + */ + getMaxValue: function() { + var maxValue = 0; + this.sb.graph.eachNode(function(n) { + var valArray = n.getData('valueArray'), + acum = 0; + $.each(valArray, function(v) { + acum += +v; + }); + maxValue = maxValue>acum? maxValue:acum; + }); + return maxValue; + }, + + normalizeDims: function() { + //number of elements + var root = this.sb.graph.getNode(this.sb.root), l=0; + root.eachAdjacency(function() { + l++; + }); + var maxValue = this.getMaxValue() || 1, + config = this.config, + animate = config.animate, + rho = this.sb.config.levelDistance; + this.sb.graph.eachNode(function(n) { + var acum = 0, animateValue = []; + $.each(n.getData('valueArray'), function(v) { + acum += +v; + animateValue.push(1); + }); + var stat = (animateValue.length == 1) && !config.updateHeights; + if(animate) { + n.setData('dimArray', $.map(n.getData('valueArray'), function(n) { + return stat? rho: (n * rho / maxValue); + }), 'end'); + var dimArray = n.getData('dimArray'); + if(!dimArray) { + n.setData('dimArray', animateValue); + } + } else { + n.setData('dimArray', $.map(n.getData('valueArray'), function(n) { + return stat? rho : (n * rho / maxValue); + })); + } + n.setData('normalizedDim', acum / maxValue); + }); + } +}); + + +//Gauge Chart + +Options.GaugeChart = { + $extend: true, + + animate: true, + offset: 25, // page offset + sliceOffset:0, + labelOffset: 3, // label offset + type: 'stacked', // gradient + labelType: 'name', + hoveredColor: '#9fd4ff', + Events: { + enable: false, + onClick: $.empty + }, + Tips: { + enable: false, + onShow: $.empty, + onHide: $.empty + }, + showLabels: true, + resizeLabels: false, + + //only valid for mono-valued datasets + updateHeights: false +}; + + + +$jit.Sunburst.Plot.NodeTypes.implement({ + 'gaugechart-basic' : { + 'render' : function(node, canvas) { + var pos = node.pos.getp(true), + dimArray = node.getData('dimArray'), + valueArray = node.getData('valueArray'), + valuelabelsArray = node.getData('valuelabelsArray'), + gaugeTarget = node.getData('gaugeTarget'), + nodeIteration = node.getData('nodeIteration'), + nodeLength = node.getData('nodeLength'), + colorArray = node.getData('colorMono'), + colorLength = colorArray.length, + stringArray = node.getData('stringArray'), + span = node.getData('span') / 2, + theta = node.pos.theta, + begin = ((theta - span)/2)+Math.PI, + end = ((theta + span)/2)+Math.PI, + polar = new Polar; + + + var ctx = canvas.getCtx(), + opt = {}, + gradient = node.getData('gradient'), + border = node.getData('border'), + config = node.getData('config'), + showLabels = config.showLabels, + resizeLabels = config.resizeLabels, + label = config.Label; + + var xpos = Math.cos((begin + end) /2); + var ypos = Math.sin((begin + end) /2); + + if (colorArray && dimArray && stringArray && gaugeTarget != 0) { + for (var i=0, l=dimArray.length, acum=0, valAcum=0; i> 0; }), + endColor = $.rgbToHex(ans); + + radialGradient.addColorStop(0, 'rgba('+colorRgb+',1)'); + radialGradient.addColorStop(0.1, 'rgba('+colorRgb+',1)'); + radialGradient.addColorStop(0.85, 'rgba('+colorRgb+',1)'); + radialGradient.addColorStop(1, 'rgba('+ans+',1)'); + ctx.fillStyle = radialGradient; + } + + polar.rho = acum; + polar.theta = begin; + var p1coord = polar.getc(true); + polar.theta = end; + var p2coord = polar.getc(true); + polar.rho += dimi; + var p3coord = polar.getc(true); + polar.theta = begin; + var p4coord = polar.getc(true); + + + ctx.beginPath(); + //fixing FF arc method + fill + ctx.arc(xpos, (ypos + dimi/2), (acum + dimi + .01) * .8, begin, end, false); + ctx.arc(xpos, (ypos + dimi/2), (acum + dimi + .01), end, begin, true); + ctx.fill(); + + + acum += (dimi || 0); + valAcum += (valueArray[i] || 0); + } + + if(showLabels && label.type == 'Native') { + ctx.save(); + ctx.fillStyle = ctx.strokeStyle = label.color; + + + ctx.font = label.style + ' ' + label.size + 'px ' + label.family; + ctx.textBaseline = 'bottom'; + ctx.textAlign = 'center'; + + polar.rho = acum * .65; + polar.theta = begin; + var cart = polar.getc(true); + + //changes y pos of first label + if(nodeIteration == 1) { + textY = cart.y - (label.size/2) + acum /2; + } else { + textY = cart.y + acum/2; + } + + if(config.labelType == 'name') { + ctx.fillText(node.name, cart.x, textY); + } else { + ctx.fillText(valuelabelsArray[0], cart.x, textY); + } + + //adds final label + if(nodeIteration == nodeLength) { + polar.theta = end; + var cart = polar.getc(true); + if(config.labelType == 'name') { + ctx.fillText(node.name, cart.x, cart.x, cart.y - (label.size/2) + acum/2); + } else { + ctx.fillText(valuelabelsArray[1], cart.x, cart.y - (label.size/2) + acum/2); + } + + } + ctx.restore(); + } + + } + }, + 'contains': function(node, pos) { + + + + if (this.nodeTypes['none'].anglecontainsgauge.call(this, node, pos)) { + var config = node.getData('config'); + var ld = this.config.levelDistance , d = node._depth; + var yOffset = pos.y - (ld/2); + var xOffset = pos.x; + var rho = Math.sqrt(xOffset * xOffset + yOffset * yOffset); + if(rho <=parseInt(ld * d)) { + var dimArray = node.getData('dimArray'); + for(var i=0,l=dimArray.length,acum=config.sliceOffset; i= ld * .8 && rho <= acum + dimi) { + + var url = Url.decode(node.getData('linkArray')[i]); + return { + name: node.getData('stringArray')[i], + link: url, + color: node.getData('colorArray')[i], + value: node.getData('valueArray')[i], + valuelabel: node.getData('valuelabelsArray')[0] + " - " + node.getData('valuelabelsArray')[1], + label: node.name + }; + } + acum += dimi; + + + } + } + return false; + + } + return false; + } + } +}); + +/* + Class: GaugeChart + + A visualization that displays gauge charts + + Constructor Options: + + See . + +*/ +$jit.GaugeChart = new Class({ + sb: null, + colors: ["#416D9C", "#70A35E", "#EBB056", "#C74243", "#83548B", "#909291", "#557EAA"], + selected: {}, + busy: false, + + initialize: function(opt) { + this.controller = this.config = + $.merge(Options("Canvas", "GaugeChart", "Label"), { + Label: { type: 'Native' } + }, opt); + this.initializeViz(); + }, + + initializeViz: function() { + var config = this.config, that = this; + var nodeType = config.type.split(":")[0]; + var sb = new $jit.Sunburst({ + injectInto: config.injectInto, + useCanvas: config.useCanvas, + withLabels: config.Label.type != 'Native', + background: config.background, + renderBackground: config.renderBackground, + backgroundColor: config.backgroundColor, + colorStop1: config.colorStop1, + colorStop2: config.colorStop2, + Label: { + type: config.Label.type + }, + Node: { + overridable: true, + type: 'gaugechart-' + nodeType, + width: 1, + height: 1 + }, + Edge: { + type: 'none' + }, + Tips: { + enable: config.Tips.enable, + type: 'Native', + force: true, + onShow: function(tip, node, contains) { + var elem = contains; + config.Tips.onShow(tip, elem, node); + if(elem.link != 'undefined' && elem.link != '') { + document.body.style.cursor = 'pointer'; + } + }, + onHide: function() { + document.body.style.cursor = 'default'; + } + }, + Events: { + enable: true, + type: 'Native', + onClick: function(node, eventInfo, evt) { + if(!config.Events.enable) return; + var elem = eventInfo.getContains(); + config.Events.onClick(elem, eventInfo, evt); + } + }, + onCreateLabel: function(domElement, node) { + var labelConf = config.Label; + if(config.showLabels) { + var style = domElement.style; + style.fontSize = labelConf.size + 'px'; + style.fontFamily = labelConf.family; + style.color = labelConf.color; + style.textAlign = 'center'; + valuelabelsArray = node.getData('valuelabelsArray'), + nodeIteration = node.getData('nodeIteration'), + nodeLength = node.getData('nodeLength'), + canvas = sb.canvas, + prefix = $.time(); + + if(config.labelType == 'name') { + domElement.innerHTML = node.name; + } else { + domElement.innerHTML = (valuelabelsArray[0] != undefined) ? valuelabelsArray[0] : ""; + } + + domElement.style.width = '400px'; + + //adds final label + if(nodeIteration == nodeLength && nodeLength != 0) { + idLabel = canvas.id + "-label"; + container = document.getElementById(idLabel); + finalLabel = document.createElement('div'); + finalLabelStyle = finalLabel.style; + finalLabel.id = prefix + "finalLabel"; + finalLabelStyle.position = "absolute"; + finalLabelStyle.width = "400px"; + finalLabelStyle.left = "0px"; + container.appendChild(finalLabel); + if(config.labelType == 'name') { + finalLabel.innerHTML = node.name; + } else { + finalLabel.innerHTML = (valuelabelsArray[1] != undefined) ? valuelabelsArray[1] : ""; + } + + } + } + }, + onPlaceLabel: function(domElement, node) { + if(!config.showLabels) return; + var pos = node.pos.getp(true), + dimArray = node.getData('dimArray'), + nodeIteration = node.getData('nodeIteration'), + nodeLength = node.getData('nodeLength'), + span = node.getData('span') / 2, + theta = node.pos.theta, + begin = ((theta - span)/2)+Math.PI, + end = ((theta + span)/2)+Math.PI, + polar = new Polar; + + var showLabels = config.showLabels, + resizeLabels = config.resizeLabels, + label = config.Label, + radiusOffset = sb.config.levelDistance; + + if (dimArray) { + for (var i=0, l=dimArray.length, acum=0; i> 0; + fontSize = fontSize < +resizeLabels? +resizeLabels : fontSize; + domElement.style.fontSize = fontSize + 'px'; + polar.rho = acum * .65; + polar.theta = begin; + var pos = polar.getc(true); + var radius = that.canvas.getSize(); + var labelPos = { + x: Math.round(pos.x + radius.width / 2), + y: Math.round(pos.y + (radius.height / 2) + radiusOffset/2) + }; + + + + domElement.style.left = (labelPos.x - 200) + 'px'; + domElement.style.top = labelPos.y + 'px'; + + //reposition first label + if(nodeIteration == 1) { + domElement.style.top = labelPos.y - label.size + 'px'; + } + + + //position final label + if(nodeIteration == nodeLength && nodeLength != 0) { + polar.theta = end; + var final = polar.getc(true); + var finalPos = { + x: Math.round(final.x + radius.width / 2), + y: Math.round(final.y + (radius.height / 2) + radiusOffset/2) + }; + finalLabel.style.left = (finalPos.x - 200) + "px"; + finalLabel.style.top = finalPos.y - label.size + "px"; + } + + } + } + + }); + this.sb = sb; + this.canvas = this.sb.canvas; + var size = sb.canvas.getSize(), + min = Math.min; + sb.config.levelDistance = min(size.width, size.height)/2 + - config.offset - config.sliceOffset; + + + }, + + renderBackground: function() { + var canvas = this.sb.canvas, + config = this.config, + style = config.gaugeStyle, + ctx = canvas.getCtx(), + size = canvas.getSize(), + radius = this.sb.config.levelDistance, + startAngle = (Math.PI/180)*1, + endAngle = (Math.PI/180)*179; + + + //background border + ctx.fillStyle = style.borderColor; + ctx.beginPath(); + ctx.arc(0,radius/2,radius+4,startAngle,endAngle, true); + ctx.fill(); + + + var radialGradient = ctx.createRadialGradient(0,radius/2,0,0,radius/2,radius); + radialGradient.addColorStop(0, '#ffffff'); + radialGradient.addColorStop(0.3, style.backgroundColor); + radialGradient.addColorStop(0.6, style.backgroundColor); + radialGradient.addColorStop(1, '#FFFFFF'); + ctx.fillStyle = radialGradient; + + //background + startAngle = (Math.PI/180)*0; + endAngle = (Math.PI/180)*180; + ctx.beginPath(); + ctx.arc(0,radius/2,radius,startAngle,endAngle, true); + ctx.fill(); + + + + }, + + + renderNeedle: function(gaugePosition,target) { + var canvas = this.sb.canvas, + config = this.config, + style = config.gaugeStyle, + ctx = canvas.getCtx(), + size = canvas.getSize(), + radius = this.sb.config.levelDistance; + gaugeCenter = (radius/2); + startAngle = 0; + endAngle = (Math.PI/180)*180; + + + // needle + ctx.fillStyle = style.needleColor; + var segments = 180/target; + needleAngle = gaugePosition * segments; + ctx.translate(0, gaugeCenter); + ctx.save(); + ctx.rotate(needleAngle * Math.PI / 180); + ctx.beginPath(); + ctx.moveTo(0,0); + ctx.lineTo(0,-4); + ctx.lineTo(-radius*.9,-1); + ctx.lineTo(-radius*.9,1); + ctx.lineTo(0,4); + ctx.lineTo(0,0); + ctx.closePath(); + ctx.fill(); + ctx.restore(); + + + // stroke needle + ctx.lineWidth = 1; + ctx.strokeStyle = '#aa0000'; + ctx.save(); + ctx.rotate(needleAngle * Math.PI / 180); + ctx.beginPath(); + ctx.moveTo(0,0); + ctx.lineTo(0,-4); + ctx.lineTo(-radius*.8,-1); + ctx.lineTo(-radius*.8,1); + ctx.lineTo(0,4); + ctx.lineTo(0,0); + ctx.closePath(); + ctx.stroke(); + ctx.restore(); + + //needle cap + ctx.fillStyle = "#000000"; + ctx.lineWidth = style.borderSize; + ctx.strokeStyle = style.borderColor; + var radialGradient = ctx.createRadialGradient(0,style.borderSize,0,0,style.borderSize,radius*.2); + radialGradient.addColorStop(0, '#666666'); + radialGradient.addColorStop(0.8, '#444444'); + radialGradient.addColorStop(1, 'rgba(0,0,0,0)'); + ctx.fillStyle = radialGradient; + ctx.translate(0,5); + ctx.save(); + ctx.beginPath(); + ctx.arc(0,0,radius*.2,startAngle,endAngle, true); + ctx.fill(); + ctx.restore(); + + + }, + + renderTicks: function(values) { + var canvas = this.sb.canvas, + config = this.config, + style = config.gaugeStyle, + ctx = canvas.getCtx(), + size = canvas.getSize(), + radius = this.sb.config.levelDistance, + gaugeCenter = (radius/2); + + + ctx.strokeStyle = style.borderColor; + ctx.lineWidth = 5; + ctx.lineCap = "round"; + for(var i=0, total = 0, l=values.length; iacum? maxValue:acum; + }); + return maxValue; + }, + + normalizeDims: function() { + //number of elements + var root = this.sb.graph.getNode(this.sb.root), l=0; + root.eachAdjacency(function() { + l++; + }); + var maxValue = this.getMaxValue() || 1, + config = this.config, + animate = config.animate, + rho = this.sb.config.levelDistance; + this.sb.graph.eachNode(function(n) { + var acum = 0, animateValue = []; + $.each(n.getData('valueArray'), function(v) { + acum += +v; + animateValue.push(1); + }); + var stat = (animateValue.length == 1) && !config.updateHeights; + if(animate) { + n.setData('dimArray', $.map(n.getData('valueArray'), function(n) { + return stat? rho: (n * rho / maxValue); + }), 'end'); + var dimArray = n.getData('dimArray'); + if(!dimArray) { + n.setData('dimArray', animateValue); + } + } else { + n.setData('dimArray', $.map(n.getData('valueArray'), function(n) { + return stat? rho : (n * rho / maxValue); + })); + } + n.setData('normalizedDim', acum / maxValue); + }); + } +}); + + +/* + * Class: Layouts.TM + * + * Implements TreeMaps layouts (SliceAndDice, Squarified, Strip). + * + * Implemented By: + * + * + * + */ +Layouts.TM = {}; + +Layouts.TM.SliceAndDice = new Class({ + compute: function(prop) { + var root = this.graph.getNode(this.clickedNode && this.clickedNode.id || this.root); + this.controller.onBeforeCompute(root); + var size = this.canvas.getSize(), + config = this.config, + width = size.width, + height = size.height; + this.graph.computeLevels(this.root, 0, "ignore"); + //set root position and dimensions + root.getPos(prop).setc(-width/2, -height/2); + root.setData('width', width, prop); + root.setData('height', height + config.titleHeight, prop); + this.computePositions(root, root, this.layout.orientation, prop); + this.controller.onAfterCompute(root); + }, + + computePositions: function(par, ch, orn, prop) { + //compute children areas + var totalArea = 0; + par.eachSubnode(function(n) { + totalArea += n.getData('area', prop); + }); + + var config = this.config, + offst = config.offset, + width = par.getData('width', prop), + height = par.getData('height', prop) - config.titleHeight, + fact = par == ch? 1: (ch.getData('area', prop) / totalArea); + + var otherSize, size, dim, pos, pos2, posth, pos2th; + var horizontal = (orn == "h"); + if(horizontal) { + orn = 'v'; + otherSize = height; + size = width * fact; + dim = 'height'; + pos = 'y'; + pos2 = 'x'; + posth = config.titleHeight; + pos2th = 0; + } else { + orn = 'h'; + otherSize = height * fact; + size = width; + dim = 'width'; + pos = 'x'; + pos2 = 'y'; + posth = 0; + pos2th = config.titleHeight; + } + var cpos = ch.getPos(prop); + ch.setData('width', size, prop); + ch.setData('height', otherSize, prop); + var offsetSize = 0, tm = this; + ch.eachSubnode(function(n) { + var p = n.getPos(prop); + p[pos] = offsetSize + cpos[pos] + posth; + p[pos2] = cpos[pos2] + pos2th; + tm.computePositions(ch, n, orn, prop); + offsetSize += n.getData(dim, prop); + }); + } + +}); + +Layouts.TM.Area = { + /* + Method: compute + + Called by loadJSON to calculate recursively all node positions and lay out the tree. + + Parameters: + + json - A JSON tree. See also . + coord - A coordinates object specifying width, height, left and top style properties. + */ + compute: function(prop) { + prop = prop || "current"; + var root = this.graph.getNode(this.clickedNode && this.clickedNode.id || this.root); + this.controller.onBeforeCompute(root); + var config = this.config, + size = this.canvas.getSize(), + width = size.width, + height = size.height, + offst = config.offset, + offwdth = width - offst, + offhght = height - offst; + this.graph.computeLevels(this.root, 0, "ignore"); + //set root position and dimensions + root.getPos(prop).setc(-width/2, -height/2); + root.setData('width', width, prop); + root.setData('height', height, prop); + //create a coordinates object + var coord = { + 'top': -height/2 + config.titleHeight, + 'left': -width/2, + 'width': offwdth, + 'height': offhght - config.titleHeight + }; + this.computePositions(root, coord, prop); + this.controller.onAfterCompute(root); + }, + + /* + Method: computeDim + + Computes dimensions and positions of a group of nodes + according to a custom layout row condition. + + Parameters: + + tail - An array of nodes. + initElem - An array of nodes (containing the initial node to be laid). + w - A fixed dimension where nodes will be layed out. + coord - A coordinates object specifying width, height, left and top style properties. + comp - A custom comparison function + */ + computeDim: function(tail, initElem, w, coord, comp, prop) { + if(tail.length + initElem.length == 1) { + var l = (tail.length == 1)? tail : initElem; + this.layoutLast(l, w, coord, prop); + return; + } + if(tail.length >= 2 && initElem.length == 0) { + initElem = [tail.shift()]; + } + if(tail.length == 0) { + if(initElem.length > 0) this.layoutRow(initElem, w, coord, prop); + return; + } + var c = tail[0]; + if(comp(initElem, w) >= comp([c].concat(initElem), w)) { + this.computeDim(tail.slice(1), initElem.concat([c]), w, coord, comp, prop); + } else { + var newCoords = this.layoutRow(initElem, w, coord, prop); + this.computeDim(tail, [], newCoords.dim, newCoords, comp, prop); + } + }, + + + /* + Method: worstAspectRatio + + Calculates the worst aspect ratio of a group of rectangles. + + See also: + + + + Parameters: + + ch - An array of nodes. + w - The fixed dimension where rectangles are being laid out. + + Returns: + + The worst aspect ratio. + + + */ + worstAspectRatio: function(ch, w) { + if(!ch || ch.length == 0) return Number.MAX_VALUE; + var areaSum = 0, maxArea = 0, minArea = Number.MAX_VALUE; + for(var i=0, l=ch.length; i area? maxArea : area; + } + var sqw = w * w, sqAreaSum = areaSum * areaSum; + return Math.max(sqw * maxArea / sqAreaSum, + sqAreaSum / (sqw * minArea)); + }, + + /* + Method: avgAspectRatio + + Calculates the average aspect ratio of a group of rectangles. + + See also: + + + + Parameters: + + ch - An array of nodes. + w - The fixed dimension where rectangles are being laid out. + + Returns: + + The average aspect ratio. + + + */ + avgAspectRatio: function(ch, w) { + if(!ch || ch.length == 0) return Number.MAX_VALUE; + var arSum = 0; + for(var i=0, l=ch.length; i h? w / h : h / w; + } + return arSum / l; + }, + + /* + layoutLast + + Performs the layout of the last computed sibling. + + Parameters: + + ch - An array of nodes. + w - A fixed dimension where nodes will be layed out. + coord - A coordinates object specifying width, height, left and top style properties. + */ + layoutLast: function(ch, w, coord, prop) { + var child = ch[0]; + child.getPos(prop).setc(coord.left, coord.top); + child.setData('width', coord.width, prop); + child.setData('height', coord.height, prop); + } +}; + + +Layouts.TM.Squarified = new Class({ + Implements: Layouts.TM.Area, + + computePositions: function(node, coord, prop) { + var config = this.config; + + if (coord.width >= coord.height) + this.layout.orientation = 'h'; + else + this.layout.orientation = 'v'; + + var ch = node.getSubnodes([1, 1], "ignore"); + if(ch.length > 0) { + this.processChildrenLayout(node, ch, coord, prop); + for(var i=0, l=ch.length; i. + coord - A coordinates object specifying width, height, left and top style properties. + */ + computePositions: function(node, coord, prop) { + var ch = node.getSubnodes([1, 1], "ignore"), config = this.config; + if(ch.length > 0) { + this.processChildrenLayout(node, ch, coord, prop); + for(var i=0, l=ch.length; i + * + */ + +Layouts.Icicle = new Class({ + /* + * Method: compute + * + * Called by loadJSON to calculate all node positions. + * + * Parameters: + * + * posType - The nodes' position to compute. Either "start", "end" or + * "current". Defaults to "current". + */ + compute: function(posType) { + posType = posType || "current"; + var root = this.graph.getNode(this.root), + config = this.config, + size = this.canvas.getSize(), + width = size.width, + height = size.height, + offset = config.offset, + levelsToShow = config.constrained ? config.levelsToShow : Number.MAX_VALUE; + + this.controller.onBeforeCompute(root); + + Graph.Util.computeLevels(this.graph, root.id, 0, "ignore"); + + var treeDepth = 0; + + Graph.Util.eachLevel(root, 0, false, function (n, d) { if(d > treeDepth) treeDepth = d; }); + + var startNode = this.graph.getNode(this.clickedNode && this.clickedNode.id || root.id); + var maxDepth = Math.min(treeDepth, levelsToShow-1); + var initialDepth = startNode._depth; + if(this.layout.horizontal()) { + this.computeSubtree(startNode, -width/2, -height/2, width/(maxDepth+1), height, initialDepth, maxDepth, posType); + } else { + this.computeSubtree(startNode, -width/2, -height/2, width, height/(maxDepth+1), initialDepth, maxDepth, posType); + } + }, + + computeSubtree: function (root, x, y, width, height, initialDepth, maxDepth, posType) { + root.getPos(posType).setc(x, y); + root.setData('width', width, posType); + root.setData('height', height, posType); + + var nodeLength, prevNodeLength = 0, totalDim = 0; + var children = Graph.Util.getSubnodes(root, [1, 1]); // next level from this node + + if(!children.length) + return; + + $.each(children, function(e) { totalDim += e.getData('dim'); }); + + for(var i=0, l=children.length; i < l; i++) { + if(this.layout.horizontal()) { + nodeLength = height * children[i].getData('dim') / totalDim; + this.computeSubtree(children[i], x+width, y, width, nodeLength, initialDepth, maxDepth, posType); + y += nodeLength; + } else { + nodeLength = width * children[i].getData('dim') / totalDim; + this.computeSubtree(children[i], x, y+height, nodeLength, height, initialDepth, maxDepth, posType); + x += nodeLength; + } + } + } +}); + + + +/* + * File: Icicle.js + * +*/ + +/* + Class: Icicle + + Icicle space filling visualization. + + Implements: + + All methods + + Constructor Options: + + Inherits options from + + - + - + - + - + - + - + - + - + - + + Additionally, there are other parameters and some default values changed + + orientation - (string) Default's *h*. Whether to set horizontal or vertical layouts. Possible values are 'h' and 'v'. + offset - (number) Default's *2*. Boxes offset. + constrained - (boolean) Default's *false*. Whether to show the entire tree when loaded or just the number of levels specified by _levelsToShow_. + levelsToShow - (number) Default's *3*. The number of levels to show for a subtree. This number is relative to the selected node. + animate - (boolean) Default's *false*. Whether to animate transitions. + Node.type - Described in . Default's *rectangle*. + Label.type - Described in . Default's *Native*. + duration - Described in . Default's *700*. + fps - Described in . Default's *45*. + + Instance Properties: + + canvas - Access a instance. + graph - Access a instance. + op - Access a instance. + fx - Access a instance. + labels - Access a interface implementation. + +*/ + +$jit.Icicle = new Class({ + Implements: [ Loader, Extras, Layouts.Icicle ], + + layout: { + orientation: "h", + vertical: function(){ + return this.orientation == "v"; + }, + horizontal: function(){ + return this.orientation == "h"; + }, + change: function(){ + this.orientation = this.vertical()? "h" : "v"; + } + }, + + initialize: function(controller) { + var config = { + animate: false, + orientation: "h", + offset: 2, + levelsToShow: Number.MAX_VALUE, + constrained: false, + Node: { + type: 'rectangle', + overridable: true + }, + Edge: { + type: 'none' + }, + Label: { + type: 'Native' + }, + duration: 700, + fps: 45 + }; + + var opts = Options("Canvas", "Node", "Edge", "Fx", "Tips", "NodeStyles", + "Events", "Navigation", "Controller", "Label"); + this.controller = this.config = $.merge(opts, config, controller); + this.layout.orientation = this.config.orientation; + + var canvasConfig = this.config; + if (canvasConfig.useCanvas) { + this.canvas = canvasConfig.useCanvas; + this.config.labelContainer = this.canvas.id + '-label'; + } else { + this.canvas = new Canvas(this, canvasConfig); + this.config.labelContainer = (typeof canvasConfig.injectInto == 'string'? canvasConfig.injectInto : canvasConfig.injectInto.id) + '-label'; + } + + this.graphOptions = { + 'complex': true, + 'Node': { + 'selected': false, + 'exist': true, + 'drawn': true + } + }; + + this.graph = new Graph( + this.graphOptions, this.config.Node, this.config.Edge, this.config.Label); + + this.labels = new $jit.Icicle.Label[this.config.Label.type](this); + this.fx = new $jit.Icicle.Plot(this, $jit.Icicle); + this.op = new $jit.Icicle.Op(this); + this.group = new $jit.Icicle.Group(this); + this.clickedNode = null; + + this.initializeExtras(); + }, + + /* + Method: refresh + + Computes positions and plots the tree. + */ + refresh: function(){ + var labelType = this.config.Label.type; + if(labelType != 'Native') { + var that = this; + this.graph.eachNode(function(n) { that.labels.hideLabel(n, false); }); + } + this.compute(); + this.plot(); + }, + + /* + Method: plot + + Plots the Icicle visualization. This is a shortcut to *fx.plot*. + + */ + plot: function(){ + this.fx.plot(this.config); + }, + + /* + Method: enter + + Sets the node as root. + + Parameters: + + node - (object) A . + + */ + enter: function (node) { + if (this.busy) + return; + this.busy = true; + + var that = this, + config = this.config; + + var callback = { + onComplete: function() { + //compute positions of newly inserted nodes + if(config.request) + that.compute(); + + if(config.animate) { + that.graph.nodeList.setDataset(['current', 'end'], { + 'alpha': [1, 0] //fade nodes + }); + + Graph.Util.eachSubgraph(node, function(n) { + n.setData('alpha', 1, 'end'); + }, "ignore"); + + that.fx.animate({ + duration: 500, + modes:['node-property:alpha'], + onComplete: function() { + that.clickedNode = node; + that.compute('end'); + + that.fx.animate({ + modes:['linear', 'node-property:width:height'], + duration: 1000, + onComplete: function() { + that.busy = false; + that.clickedNode = node; + } + }); + } + }); + } else { + that.clickedNode = node; + that.busy = false; + that.refresh(); + } + } + }; + + if(config.request) { + this.requestNodes(clickedNode, callback); + } else { + callback.onComplete(); + } + }, + + /* + Method: out + + Sets the parent node of the current selected node as root. + + */ + out: function(){ + if(this.busy) + return; + + var that = this, + GUtil = Graph.Util, + config = this.config, + graph = this.graph, + parents = GUtil.getParents(graph.getNode(this.clickedNode && this.clickedNode.id || this.root)), + parent = parents[0], + clickedNode = parent, + previousClickedNode = this.clickedNode; + + this.busy = true; + this.events.hoveredNode = false; + + if(!parent) { + this.busy = false; + return; + } + + //final plot callback + callback = { + onComplete: function() { + that.clickedNode = parent; + if(config.request) { + that.requestNodes(parent, { + onComplete: function() { + that.compute(); + that.plot(); + that.busy = false; + } + }); + } else { + that.compute(); + that.plot(); + that.busy = false; + } + } + }; + + //animate node positions + if(config.animate) { + this.clickedNode = clickedNode; + this.compute('end'); + //animate the visible subtree only + this.clickedNode = previousClickedNode; + this.fx.animate({ + modes:['linear', 'node-property:width:height'], + duration: 1000, + onComplete: function() { + //animate the parent subtree + that.clickedNode = clickedNode; + //change nodes alpha + graph.nodeList.setDataset(['current', 'end'], { + 'alpha': [0, 1] + }); + GUtil.eachSubgraph(previousClickedNode, function(node) { + node.setData('alpha', 1); + }, "ignore"); + that.fx.animate({ + duration: 500, + modes:['node-property:alpha'], + onComplete: function() { + callback.onComplete(); + } + }); + } + }); + } else { + callback.onComplete(); + } + }, + requestNodes: function(node, onComplete){ + var handler = $.merge(this.controller, onComplete), + levelsToShow = this.config.constrained ? this.config.levelsToShow : Number.MAX_VALUE; + + if (handler.request) { + var leaves = [], d = node._depth; + Graph.Util.eachLevel(node, 0, levelsToShow, function(n){ + if (n.drawn && !Graph.Util.anySubnode(n)) { + leaves.push(n); + n._level = n._depth - d; + if (this.config.constrained) + n._level = levelsToShow - n._level; + + } + }); + this.group.requestNodes(leaves, handler); + } else { + handler.onComplete(); + } + } +}); + +/* + Class: Icicle.Op + + Custom extension of . + + Extends: + + All methods + + See also: + + + + */ +$jit.Icicle.Op = new Class({ + + Implements: Graph.Op + +}); + +/* + * Performs operations on group of nodes. + */ +$jit.Icicle.Group = new Class({ + + initialize: function(viz){ + this.viz = viz; + this.canvas = viz.canvas; + this.config = viz.config; + }, + + /* + * Calls the request method on the controller to request a subtree for each node. + */ + requestNodes: function(nodes, controller){ + var counter = 0, len = nodes.length, nodeSelected = {}; + var complete = function(){ + controller.onComplete(); + }; + var viz = this.viz; + if (len == 0) + complete(); + for(var i = 0; i < len; i++) { + nodeSelected[nodes[i].id] = nodes[i]; + controller.request(nodes[i].id, nodes[i]._level, { + onComplete: function(nodeId, data){ + if (data && data.children) { + data.id = nodeId; + viz.op.sum(data, { + type: 'nothing' + }); + } + if (++counter == len) { + Graph.Util.computeLevels(viz.graph, viz.root, 0); + complete(); + } + } + }); + } + } +}); + +/* + Class: Icicle.Plot + + Custom extension of . + + Extends: + + All methods + + See also: + + + + */ +$jit.Icicle.Plot = new Class({ + Implements: Graph.Plot, + + plot: function(opt, animating){ + opt = opt || this.viz.controller; + var viz = this.viz, + graph = viz.graph, + root = graph.getNode(viz.clickedNode && viz.clickedNode.id || viz.root), + initialDepth = root._depth; + + viz.canvas.clear(); + this.plotTree(root, $.merge(opt, { + 'withLabels': true, + 'hideLabels': false, + 'plotSubtree': function(root, node) { + return !viz.config.constrained || + (node._depth - initialDepth < viz.config.levelsToShow); + } + }), animating); + } +}); + +/* + Class: Icicle.Label + + Custom extension of . + Contains custom , and extensions. + + Extends: + + All methods and subclasses. + + See also: + + , , , . + + */ +$jit.Icicle.Label = {}; + +/* + Icicle.Label.Native + + Custom extension of . + + Extends: + + All methods + + See also: + + + + */ +$jit.Icicle.Label.Native = new Class({ + Implements: Graph.Label.Native, + + renderLabel: function(canvas, node, controller) { + var ctx = canvas.getCtx(), + width = node.getData('width'), + height = node.getData('height'), + size = node.getLabelData('size'), + m = ctx.measureText(node.name); + + // Guess as much as possible if the label will fit in the node + if(height < (size * 1.5) || width < m.width) + return; + + var pos = node.pos.getc(true); + ctx.fillText(node.name, + pos.x + width / 2, + pos.y + height / 2); + } +}); + +/* + Icicle.Label.SVG + + Custom extension of . + + Extends: + + All methods + + See also: + + +*/ +$jit.Icicle.Label.SVG = new Class( { + Implements: Graph.Label.SVG, + + initialize: function(viz){ + this.viz = viz; + }, + + /* + placeLabel + + Overrides abstract method placeLabel in . + + Parameters: + + tag - A DOM label element. + node - A . + controller - A configuration/controller object passed to the visualization. + */ + placeLabel: function(tag, node, controller){ + var pos = node.pos.getc(true), canvas = this.viz.canvas; + var radius = canvas.getSize(); + var labelPos = { + x: Math.round(pos.x + radius.width / 2), + y: Math.round(pos.y + radius.height / 2) + }; + tag.setAttribute('x', labelPos.x); + tag.setAttribute('y', labelPos.y); + + controller.onPlaceLabel(tag, node); + } +}); + +/* + Icicle.Label.HTML + + Custom extension of . + + Extends: + + All methods. + + See also: + + + + */ +$jit.Icicle.Label.HTML = new Class( { + Implements: Graph.Label.HTML, + + initialize: function(viz){ + this.viz = viz; + }, + + /* + placeLabel + + Overrides abstract method placeLabel in . + + Parameters: + + tag - A DOM label element. + node - A . + controller - A configuration/controller object passed to the visualization. + */ + placeLabel: function(tag, node, controller){ + var pos = node.pos.getc(true), canvas = this.viz.canvas; + var radius = canvas.getSize(); + var labelPos = { + x: Math.round(pos.x + radius.width / 2), + y: Math.round(pos.y + radius.height / 2) + }; + + var style = tag.style; + style.left = labelPos.x + 'px'; + style.top = labelPos.y + 'px'; + style.display = ''; + + controller.onPlaceLabel(tag, node); + } +}); + +/* + Class: Icicle.Plot.NodeTypes + + This class contains a list of built-in types. + Node types implemented are 'none', 'rectangle'. + + You can add your custom node types, customizing your visualization to the extreme. + + Example: + + (start code js) + Icicle.Plot.NodeTypes.implement({ + 'mySpecialType': { + 'render': function(node, canvas) { + //print your custom node to canvas + }, + //optional + 'contains': function(node, pos) { + //return true if pos is inside the node or false otherwise + } + } + }); + (end code) + + */ +$jit.Icicle.Plot.NodeTypes = new Class( { + 'none': { + 'render': $.empty + }, + + 'rectangle': { + 'render': function(node, canvas, animating) { + var config = this.viz.config; + var offset = config.offset; + var width = node.getData('width'); + var height = node.getData('height'); + var border = node.getData('border'); + var pos = node.pos.getc(true); + var posx = pos.x + offset / 2, posy = pos.y + offset / 2; + var ctx = canvas.getCtx(); + + if(width - offset < 2 || height - offset < 2) return; + + if(config.cushion) { + var color = node.getData('color'); + var lg = ctx.createRadialGradient(posx + (width - offset)/2, + posy + (height - offset)/2, 1, + posx + (width-offset)/2, posy + (height-offset)/2, + width < height? height : width); + var colorGrad = $.rgbToHex($.map($.hexToRgb(color), + function(r) { return r * 0.3 >> 0; })); + lg.addColorStop(0, color); + lg.addColorStop(1, colorGrad); + ctx.fillStyle = lg; + } + + if (border) { + ctx.strokeStyle = border; + ctx.lineWidth = 3; + } + + ctx.fillRect(posx, posy, Math.max(0, width - offset), Math.max(0, height - offset)); + border && ctx.strokeRect(pos.x, pos.y, width, height); + }, + + 'contains': function(node, pos) { + if(this.viz.clickedNode && !$jit.Graph.Util.isDescendantOf(node, this.viz.clickedNode.id)) return false; + var npos = node.pos.getc(true), + width = node.getData('width'), + height = node.getData('height'); + return this.nodeHelper.rectangle.contains({x: npos.x + width/2, y: npos.y + height/2}, pos, width, height); + } + } +}); + +$jit.Icicle.Plot.EdgeTypes = new Class( { + 'none': $.empty +}); + + + +/* + * File: Layouts.ForceDirected.js + * +*/ + +/* + * Class: Layouts.ForceDirected + * + * Implements a Force Directed Layout. + * + * Implemented By: + * + * + * + * Credits: + * + * Marcus Cobden + * + */ +Layouts.ForceDirected = new Class({ + + getOptions: function(random) { + var s = this.canvas.getSize(); + var w = s.width, h = s.height; + //count nodes + var count = 0; + this.graph.eachNode(function(n) { + count++; + }); + var k2 = w * h / count, k = Math.sqrt(k2); + var l = this.config.levelDistance; + + return { + width: w, + height: h, + tstart: w * 0.1, + nodef: function(x) { return k2 / (x || 1); }, + edgef: function(x) { return /* x * x / k; */ k * (x - l); } + }; + }, + + compute: function(property, incremental) { + var prop = $.splat(property || ['current', 'start', 'end']); + var opt = this.getOptions(); + NodeDim.compute(this.graph, prop, this.config); + this.graph.computeLevels(this.root, 0, "ignore"); + this.graph.eachNode(function(n) { + $.each(prop, function(p) { + var pos = n.getPos(p); + if(pos.equals(Complex.KER)) { + pos.x = opt.width/5 * (Math.random() - 0.5); + pos.y = opt.height/5 * (Math.random() - 0.5); + } + //initialize disp vector + n.disp = {}; + $.each(prop, function(p) { + n.disp[p] = $C(0, 0); + }); + }); + }); + this.computePositions(prop, opt, incremental); + }, + + computePositions: function(property, opt, incremental) { + var times = this.config.iterations, i = 0, that = this; + if(incremental) { + (function iter() { + for(var total=incremental.iter, j=0; j= times) { + incremental.onComplete(); + return; + } + } + incremental.onStep(Math.round(i / (times -1) * 100)); + setTimeout(iter, 1); + })(); + } else { + for(; i < times; i++) { + opt.t = opt.tstart * (1 - i/(times -1)); + this.computePositionStep(property, opt); + } + } + }, + + computePositionStep: function(property, opt) { + var graph = this.graph; + var min = Math.min, max = Math.max; + var dpos = $C(0, 0); + //calculate repulsive forces + graph.eachNode(function(v) { + //initialize disp + $.each(property, function(p) { + v.disp[p].x = 0; v.disp[p].y = 0; + }); + graph.eachNode(function(u) { + if(u.id != v.id) { + $.each(property, function(p) { + var vp = v.getPos(p), up = u.getPos(p); + dpos.x = vp.x - up.x; + dpos.y = vp.y - up.y; + var norm = dpos.norm() || 1; + v.disp[p].$add(dpos + .$scale(opt.nodef(norm) / norm)); + }); + } + }); + }); + //calculate attractive forces + var T = !!graph.getNode(this.root).visited; + graph.eachNode(function(node) { + node.eachAdjacency(function(adj) { + var nodeTo = adj.nodeTo; + if(!!nodeTo.visited === T) { + $.each(property, function(p) { + var vp = node.getPos(p), up = nodeTo.getPos(p); + dpos.x = vp.x - up.x; + dpos.y = vp.y - up.y; + var norm = dpos.norm() || 1; + node.disp[p].$add(dpos.$scale(-opt.edgef(norm) / norm)); + nodeTo.disp[p].$add(dpos.$scale(-1)); + }); + } + }); + node.visited = !T; + }); + //arrange positions to fit the canvas + var t = opt.t, w2 = opt.width / 2, h2 = opt.height / 2; + graph.eachNode(function(u) { + $.each(property, function(p) { + var disp = u.disp[p]; + var norm = disp.norm() || 1; + var p = u.getPos(p); + p.$add($C(disp.x * min(Math.abs(disp.x), t) / norm, + disp.y * min(Math.abs(disp.y), t) / norm)); + p.x = min(w2, max(-w2, p.x)); + p.y = min(h2, max(-h2, p.y)); + }); + }); + } +}); + +/* + * File: ForceDirected.js + */ + +/* + Class: ForceDirected + + A visualization that lays graphs using a Force-Directed layout algorithm. + + Inspired by: + + Force-Directed Drawing Algorithms (Stephen G. Kobourov) + + Implements: + + All methods + + Constructor Options: + + Inherits options from + + - + - + - + - + - + - + - + - + - + + Additionally, there are two parameters + + levelDistance - (number) Default's *50*. The natural length desired for the edges. + iterations - (number) Default's *50*. The number of iterations for the spring layout simulation. Depending on the browser's speed you could set this to a more 'interesting' number, like *200*. + + Instance Properties: + + canvas - Access a instance. + graph - Access a instance. + op - Access a instance. + fx - Access a instance. + labels - Access a interface implementation. + +*/ + +$jit.ForceDirected = new Class( { + + Implements: [ Loader, Extras, Layouts.ForceDirected ], + + initialize: function(controller) { + var $ForceDirected = $jit.ForceDirected; + + var config = { + iterations: 50, + levelDistance: 50 + }; + + this.controller = this.config = $.merge(Options("Canvas", "Node", "Edge", + "Fx", "Tips", "NodeStyles", "Events", "Navigation", "Controller", "Label"), config, controller); + + var canvasConfig = this.config; + if(canvasConfig.useCanvas) { + this.canvas = canvasConfig.useCanvas; + this.config.labelContainer = this.canvas.id + '-label'; + } else { + if(canvasConfig.background) { + canvasConfig.background = $.merge({ + type: 'Circles' + }, canvasConfig.background); + } + this.canvas = new Canvas(this, canvasConfig); + this.config.labelContainer = (typeof canvasConfig.injectInto == 'string'? canvasConfig.injectInto : canvasConfig.injectInto.id) + '-label'; + } + + this.graphOptions = { + 'complex': true, + 'Node': { + 'selected': false, + 'exist': true, + 'drawn': true + } + }; + this.graph = new Graph(this.graphOptions, this.config.Node, + this.config.Edge); + this.labels = new $ForceDirected.Label[canvasConfig.Label.type](this); + this.fx = new $ForceDirected.Plot(this, $ForceDirected); + this.op = new $ForceDirected.Op(this); + this.json = null; + this.busy = false; + // initialize extras + this.initializeExtras(); + }, + + /* + Method: refresh + + Computes positions and plots the tree. + */ + refresh: function() { + this.compute(); + this.plot(); + }, + + reposition: function() { + this.compute('end'); + }, + +/* + Method: computeIncremental + + Performs the Force Directed algorithm incrementally. + + Description: + + ForceDirected algorithms can perform many computations and lead to JavaScript taking too much time to complete. + This method splits the algorithm into smaller parts allowing the user to track the evolution of the algorithm and + avoiding browser messages such as "This script is taking too long to complete". + + Parameters: + + opt - (object) The object properties are described below + + iter - (number) Default's *20*. Split the algorithm into pieces of _iter_ iterations. For example, if the _iterations_ configuration property + of your class is 100, then you could set _iter_ to 20 to split the main algorithm into 5 smaller pieces. + + property - (string) Default's *end*. Whether to update starting, current or ending node positions. Possible values are 'end', 'start', 'current'. + You can also set an array of these properties. If you'd like to keep the current node positions but to perform these + computations for final animation positions then you can just choose 'end'. + + onStep - (function) A callback function called when each "small part" of the algorithm completed. This function gets as first formal + parameter a percentage value. + + onComplete - A callback function called when the algorithm completed. + + Example: + + In this example I calculate the end positions and then animate the graph to those positions + + (start code js) + var fd = new $jit.ForceDirected(...); + fd.computeIncremental({ + iter: 20, + property: 'end', + onStep: function(perc) { + Log.write("loading " + perc + "%"); + }, + onComplete: function() { + Log.write("done"); + fd.animate(); + } + }); + (end code) + + In this example I calculate all positions and (re)plot the graph + + (start code js) + var fd = new ForceDirected(...); + fd.computeIncremental({ + iter: 20, + property: ['end', 'start', 'current'], + onStep: function(perc) { + Log.write("loading " + perc + "%"); + }, + onComplete: function() { + Log.write("done"); + fd.plot(); + } + }); + (end code) + + */ + computeIncremental: function(opt) { + opt = $.merge( { + iter: 20, + property: 'end', + onStep: $.empty, + onComplete: $.empty + }, opt || {}); + + this.config.onBeforeCompute(this.graph.getNode(this.root)); + this.compute(opt.property, opt); + }, + + /* + Method: plot + + Plots the ForceDirected graph. This is a shortcut to *fx.plot*. + */ + plot: function() { + this.fx.plot(); + }, + + /* + Method: animate + + Animates the graph from the current positions to the 'end' node positions. + */ + animate: function(opt) { + this.fx.animate($.merge( { + modes: [ 'linear' ] + }, opt || {})); + } +}); + +$jit.ForceDirected.$extend = true; + +(function(ForceDirected) { + + /* + Class: ForceDirected.Op + + Custom extension of . + + Extends: + + All methods + + See also: + + + + */ + ForceDirected.Op = new Class( { + + Implements: Graph.Op + + }); + + /* + Class: ForceDirected.Plot + + Custom extension of . + + Extends: + + All methods + + See also: + + + + */ + ForceDirected.Plot = new Class( { + + Implements: Graph.Plot + + }); + + /* + Class: ForceDirected.Label + + Custom extension of . + Contains custom , and extensions. + + Extends: + + All methods and subclasses. + + See also: + + , , , . + + */ + ForceDirected.Label = {}; + + /* + ForceDirected.Label.Native + + Custom extension of . + + Extends: + + All methods + + See also: + + + + */ + ForceDirected.Label.Native = new Class( { + Implements: Graph.Label.Native + }); + + /* + ForceDirected.Label.SVG + + Custom extension of . + + Extends: + + All methods + + See also: + + + + */ + ForceDirected.Label.SVG = new Class( { + Implements: Graph.Label.SVG, + + initialize: function(viz) { + this.viz = viz; + }, + + /* + placeLabel + + Overrides abstract method placeLabel in . + + Parameters: + + tag - A DOM label element. + node - A . + controller - A configuration/controller object passed to the visualization. + + */ + placeLabel: function(tag, node, controller) { + var pos = node.pos.getc(true), + canvas = this.viz.canvas, + ox = canvas.translateOffsetX, + oy = canvas.translateOffsetY, + sx = canvas.scaleOffsetX, + sy = canvas.scaleOffsetY, + radius = canvas.getSize(); + var labelPos = { + x: Math.round(pos.x * sx + ox + radius.width / 2), + y: Math.round(pos.y * sy + oy + radius.height / 2) + }; + tag.setAttribute('x', labelPos.x); + tag.setAttribute('y', labelPos.y); + + controller.onPlaceLabel(tag, node); + } + }); + + /* + ForceDirected.Label.HTML + + Custom extension of . + + Extends: + + All methods. + + See also: + + + + */ + ForceDirected.Label.HTML = new Class( { + Implements: Graph.Label.HTML, + + initialize: function(viz) { + this.viz = viz; + }, + /* + placeLabel + + Overrides abstract method placeLabel in . + + Parameters: + + tag - A DOM label element. + node - A . + controller - A configuration/controller object passed to the visualization. + + */ + placeLabel: function(tag, node, controller) { + var pos = node.pos.getc(true), + canvas = this.viz.canvas, + ox = canvas.translateOffsetX, + oy = canvas.translateOffsetY, + sx = canvas.scaleOffsetX, + sy = canvas.scaleOffsetY, + radius = canvas.getSize(); + var labelPos = { + x: Math.round(pos.x * sx + ox + radius.width / 2), + y: Math.round(pos.y * sy + oy + radius.height / 2) + }; + var style = tag.style; + style.left = labelPos.x + 'px'; + style.top = labelPos.y + 'px'; + style.display = this.fitsInCanvas(labelPos, canvas) ? '' : 'none'; + + controller.onPlaceLabel(tag, node); + } + }); + + /* + Class: ForceDirected.Plot.NodeTypes + + This class contains a list of built-in types. + Node types implemented are 'none', 'circle', 'triangle', 'rectangle', 'star', 'ellipse' and 'square'. + + You can add your custom node types, customizing your visualization to the extreme. + + Example: + + (start code js) + ForceDirected.Plot.NodeTypes.implement({ + 'mySpecialType': { + 'render': function(node, canvas) { + //print your custom node to canvas + }, + //optional + 'contains': function(node, pos) { + //return true if pos is inside the node or false otherwise + } + } + }); + (end code) + + */ + ForceDirected.Plot.NodeTypes = new Class({ + 'none': { + 'render': $.empty, + 'contains': $.lambda(false) + }, + 'circle': { + 'render': function(node, canvas){ + var pos = node.pos.getc(true), + dim = node.getData('dim'); + this.nodeHelper.circle.render('fill', pos, dim, canvas); + }, + 'contains': function(node, pos){ + var npos = node.pos.getc(true), + dim = node.getData('dim'); + return this.nodeHelper.circle.contains(npos, pos, dim); + } + }, + 'ellipse': { + 'render': function(node, canvas){ + var pos = node.pos.getc(true), + width = node.getData('width'), + height = node.getData('height'); + this.nodeHelper.ellipse.render('fill', pos, width, height, canvas); + }, + // TODO(nico): be more precise... + 'contains': function(node, pos){ + var npos = node.pos.getc(true), + width = node.getData('width'), + height = node.getData('height'); + return this.nodeHelper.ellipse.contains(npos, pos, width, height); + } + }, + 'square': { + 'render': function(node, canvas){ + var pos = node.pos.getc(true), + dim = node.getData('dim'); + this.nodeHelper.square.render('fill', pos, dim, canvas); + }, + 'contains': function(node, pos){ + var npos = node.pos.getc(true), + dim = node.getData('dim'); + return this.nodeHelper.square.contains(npos, pos, dim); + } + }, + 'rectangle': { + 'render': function(node, canvas){ + var pos = node.pos.getc(true), + width = node.getData('width'), + height = node.getData('height'); + this.nodeHelper.rectangle.render('fill', pos, width, height, canvas); + }, + 'contains': function(node, pos){ + var npos = node.pos.getc(true), + width = node.getData('width'), + height = node.getData('height'); + return this.nodeHelper.rectangle.contains(npos, pos, width, height); + } + }, + 'triangle': { + 'render': function(node, canvas){ + var pos = node.pos.getc(true), + dim = node.getData('dim'); + this.nodeHelper.triangle.render('fill', pos, dim, canvas); + }, + 'contains': function(node, pos) { + var npos = node.pos.getc(true), + dim = node.getData('dim'); + return this.nodeHelper.triangle.contains(npos, pos, dim); + } + }, + 'star': { + 'render': function(node, canvas){ + var pos = node.pos.getc(true), + dim = node.getData('dim'); + this.nodeHelper.star.render('fill', pos, dim, canvas); + }, + 'contains': function(node, pos) { + var npos = node.pos.getc(true), + dim = node.getData('dim'); + return this.nodeHelper.star.contains(npos, pos, dim); + } + } + }); + + /* + Class: ForceDirected.Plot.EdgeTypes + + This class contains a list of built-in types. + Edge types implemented are 'none', 'line' and 'arrow'. + + You can add your custom edge types, customizing your visualization to the extreme. + + Example: + + (start code js) + ForceDirected.Plot.EdgeTypes.implement({ + 'mySpecialType': { + 'render': function(adj, canvas) { + //print your custom edge to canvas + }, + //optional + 'contains': function(adj, pos) { + //return true if pos is inside the arc or false otherwise + } + } + }); + (end code) + + */ + ForceDirected.Plot.EdgeTypes = new Class({ + 'none': $.empty, + 'line': { + 'render': function(adj, canvas) { + var from = adj.nodeFrom.pos.getc(true), + to = adj.nodeTo.pos.getc(true); + this.edgeHelper.line.render(from, to, canvas); + }, + 'contains': function(adj, pos) { + var from = adj.nodeFrom.pos.getc(true), + to = adj.nodeTo.pos.getc(true); + return this.edgeHelper.line.contains(from, to, pos, this.edge.epsilon); + } + }, + 'arrow': { + 'render': function(adj, canvas) { + var from = adj.nodeFrom.pos.getc(true), + to = adj.nodeTo.pos.getc(true), + dim = adj.getData('dim'), + direction = adj.data.$direction, + inv = (direction && direction.length>1 && direction[0] != adj.nodeFrom.id); + this.edgeHelper.arrow.render(from, to, dim, inv, canvas); + }, + 'contains': function(adj, pos) { + var from = adj.nodeFrom.pos.getc(true), + to = adj.nodeTo.pos.getc(true); + return this.edgeHelper.arrow.contains(from, to, pos, this.edge.epsilon); + } + } + }); + +})($jit.ForceDirected); + + +/* + * File: Treemap.js + * +*/ + +$jit.TM = {}; + +var TM = $jit.TM; + +$jit.TM.$extend = true; + +/* + Class: TM.Base + + Abstract class providing base functionality for , and visualizations. + + Implements: + + All methods + + Constructor Options: + + Inherits options from + + - + - + - + - + - + - + - + - + - + + Additionally, there are other parameters and some default values changed + + orientation - (string) Default's *h*. Whether to set horizontal or vertical layouts. Possible values are 'h' and 'v'. + titleHeight - (number) Default's *13*. The height of the title rectangle for inner (non-leaf) nodes. + offset - (number) Default's *2*. Boxes offset. + constrained - (boolean) Default's *false*. Whether to show the entire tree when loaded or just the number of levels specified by _levelsToShow_. + levelsToShow - (number) Default's *3*. The number of levels to show for a subtree. This number is relative to the selected node. + animate - (boolean) Default's *false*. Whether to animate transitions. + Node.type - Described in . Default's *rectangle*. + duration - Described in . Default's *700*. + fps - Described in . Default's *45*. + + Instance Properties: + + canvas - Access a instance. + graph - Access a instance. + op - Access a instance. + fx - Access a instance. + labels - Access a interface implementation. + + Inspired by: + + Squarified Treemaps (Mark Bruls, Kees Huizing, and Jarke J. van Wijk) + + Tree visualization with tree-maps: 2-d space-filling approach (Ben Shneiderman) + + Note: + + This visualization was built and engineered from scratch, taking only the paper as inspiration, and only shares some features with the visualization described in the paper. + +*/ +TM.Base = { + layout: { + orientation: "h", + vertical: function(){ + return this.orientation == "v"; + }, + horizontal: function(){ + return this.orientation == "h"; + }, + change: function(){ + this.orientation = this.vertical()? "h" : "v"; + } + }, + + initialize: function(controller){ + var config = { + orientation: "h", + titleHeight: 13, + offset: 2, + levelsToShow: 0, + constrained: false, + animate: false, + Node: { + type: 'rectangle', + overridable: true, + //we all know why this is not zero, + //right, Firefox? + width: 3, + height: 3, + color: '#444' + }, + Label: { + textAlign: 'center', + textBaseline: 'top' + }, + Edge: { + type: 'none' + }, + duration: 700, + fps: 45 + }; + + this.controller = this.config = $.merge(Options("Canvas", "Node", "Edge", + "Fx", "Controller", "Tips", "NodeStyles", "Events", "Navigation", "Label"), config, controller); + this.layout.orientation = this.config.orientation; + + var canvasConfig = this.config; + if (canvasConfig.useCanvas) { + this.canvas = canvasConfig.useCanvas; + this.config.labelContainer = this.canvas.id + '-label'; + } else { + if(canvasConfig.background) { + canvasConfig.background = $.merge({ + type: 'Circles' + }, canvasConfig.background); + } + this.canvas = new Canvas(this, canvasConfig); + this.config.labelContainer = (typeof canvasConfig.injectInto == 'string'? canvasConfig.injectInto : canvasConfig.injectInto.id) + '-label'; + } + + this.graphOptions = { + 'complex': true, + 'Node': { + 'selected': false, + 'exist': true, + 'drawn': true + } + }; + this.graph = new Graph(this.graphOptions, this.config.Node, + this.config.Edge); + this.labels = new TM.Label[canvasConfig.Label.type](this); + this.fx = new TM.Plot(this); + this.op = new TM.Op(this); + this.group = new TM.Group(this); + this.geom = new TM.Geom(this); + this.clickedNode = null; + this.busy = false; + // initialize extras + this.initializeExtras(); + }, + + /* + Method: refresh + + Computes positions and plots the tree. + */ + refresh: function(){ + if(this.busy) return; + this.busy = true; + var that = this; + if(this.config.animate) { + this.compute('end'); + this.config.levelsToShow > 0 && this.geom.setRightLevelToShow(this.graph.getNode(this.clickedNode + && this.clickedNode.id || this.root)); + this.fx.animate($.merge(this.config, { + modes: ['linear', 'node-property:width:height'], + onComplete: function() { + that.busy = false; + } + })); + } else { + var labelType = this.config.Label.type; + if(labelType != 'Native') { + var that = this; + this.graph.eachNode(function(n) { that.labels.hideLabel(n, false); }); + } + this.busy = false; + this.compute(); + this.config.levelsToShow > 0 && this.geom.setRightLevelToShow(this.graph.getNode(this.clickedNode + && this.clickedNode.id || this.root)); + this.plot(); + } + }, + + /* + Method: plot + + Plots the TreeMap. This is a shortcut to *fx.plot*. + + */ + plot: function(){ + this.fx.plot(); + }, + + /* + Method: leaf + + Returns whether the node is a leaf. + + Parameters: + + n - (object) A . + + */ + leaf: function(n){ + return n.getSubnodes([ + 1, 1 + ], "ignore").length == 0; + }, + + /* + Method: enter + + Sets the node as root. + + Parameters: + + n - (object) A . + + */ + enter: function(n){ + if(this.busy) return; + this.busy = true; + + var that = this, + config = this.config, + graph = this.graph, + clickedNode = n, + previousClickedNode = this.clickedNode; + + var callback = { + onComplete: function() { + //ensure that nodes are shown for that level + if(config.levelsToShow > 0) { + that.geom.setRightLevelToShow(n); + } + //compute positions of newly inserted nodes + if(config.levelsToShow > 0 || config.request) that.compute(); + if(config.animate) { + //fade nodes + graph.nodeList.setData('alpha', 0, 'end'); + n.eachSubgraph(function(n) { + n.setData('alpha', 1, 'end'); + }, "ignore"); + that.fx.animate({ + duration: 500, + modes:['node-property:alpha'], + onComplete: function() { + //compute end positions + that.clickedNode = clickedNode; + that.compute('end'); + //animate positions + //TODO(nico) commenting this line didn't seem to throw errors... + that.clickedNode = previousClickedNode; + that.fx.animate({ + modes:['linear', 'node-property:width:height'], + duration: 1000, + onComplete: function() { + that.busy = false; + //TODO(nico) check comment above + that.clickedNode = clickedNode; + } + }); + } + }); + } else { + that.busy = false; + that.clickedNode = n; + that.refresh(); + } + } + }; + if(config.request) { + this.requestNodes(clickedNode, callback); + } else { + callback.onComplete(); + } + }, + + /* + Method: out + + Sets the parent node of the current selected node as root. + + */ + out: function(){ + if(this.busy) return; + this.busy = true; + this.events.hoveredNode = false; + var that = this, + config = this.config, + graph = this.graph, + parents = graph.getNode(this.clickedNode + && this.clickedNode.id || this.root).getParents(), + parent = parents[0], + clickedNode = parent, + previousClickedNode = this.clickedNode; + + //if no parents return + if(!parent) { + this.busy = false; + return; + } + //final plot callback + callback = { + onComplete: function() { + that.clickedNode = parent; + if(config.request) { + that.requestNodes(parent, { + onComplete: function() { + that.compute(); + that.plot(); + that.busy = false; + } + }); + } else { + that.compute(); + that.plot(); + that.busy = false; + } + } + }; + //prune tree + if (config.levelsToShow > 0) + this.geom.setRightLevelToShow(parent); + //animate node positions + if(config.animate) { + this.clickedNode = clickedNode; + this.compute('end'); + //animate the visible subtree only + this.clickedNode = previousClickedNode; + this.fx.animate({ + modes:['linear', 'node-property:width:height'], + duration: 1000, + onComplete: function() { + //animate the parent subtree + that.clickedNode = clickedNode; + //change nodes alpha + graph.eachNode(function(n) { + n.setDataset(['current', 'end'], { + 'alpha': [0, 1] + }); + }, "ignore"); + previousClickedNode.eachSubgraph(function(node) { + node.setData('alpha', 1); + }, "ignore"); + that.fx.animate({ + duration: 500, + modes:['node-property:alpha'], + onComplete: function() { + callback.onComplete(); + } + }); + } + }); + } else { + callback.onComplete(); + } + }, + + requestNodes: function(node, onComplete){ + var handler = $.merge(this.controller, onComplete), + lev = this.config.levelsToShow; + if (handler.request) { + var leaves = [], d = node._depth; + node.eachLevel(0, lev, function(n){ + var nodeLevel = lev - (n._depth - d); + if (n.drawn && !n.anySubnode() && nodeLevel > 0) { + leaves.push(n); + n._level = nodeLevel; + } + }); + this.group.requestNodes(leaves, handler); + } else { + handler.onComplete(); + } + } +}; + +/* + Class: TM.Op + + Custom extension of . + + Extends: + + All methods + + See also: + + + + */ +TM.Op = new Class({ + Implements: Graph.Op, + + initialize: function(viz){ + this.viz = viz; + } +}); + +//extend level methods of Graph.Geom +TM.Geom = new Class({ + Implements: Graph.Geom, + + getRightLevelToShow: function() { + return this.viz.config.levelsToShow; + }, + + setRightLevelToShow: function(node) { + var level = this.getRightLevelToShow(), + fx = this.viz.labels; + node.eachLevel(0, level+1, function(n) { + var d = n._depth - node._depth; + if(d > level) { + n.drawn = false; + n.exist = false; + n.ignore = true; + fx.hideLabel(n, false); + } else { + n.drawn = true; + n.exist = true; + delete n.ignore; + } + }); + node.drawn = true; + delete node.ignore; + } +}); + +/* + +Performs operations on group of nodes. + +*/ +TM.Group = new Class( { + + initialize: function(viz){ + this.viz = viz; + this.canvas = viz.canvas; + this.config = viz.config; + }, + + /* + + Calls the request method on the controller to request a subtree for each node. + */ + requestNodes: function(nodes, controller){ + var counter = 0, len = nodes.length, nodeSelected = {}; + var complete = function(){ + controller.onComplete(); + }; + var viz = this.viz; + if (len == 0) + complete(); + for ( var i = 0; i < len; i++) { + nodeSelected[nodes[i].id] = nodes[i]; + controller.request(nodes[i].id, nodes[i]._level, { + onComplete: function(nodeId, data){ + if (data && data.children) { + data.id = nodeId; + viz.op.sum(data, { + type: 'nothing' + }); + } + if (++counter == len) { + viz.graph.computeLevels(viz.root, 0); + complete(); + } + } + }); + } + } +}); + +/* + Class: TM.Plot + + Custom extension of . + + Extends: + + All methods + + See also: + + + + */ +TM.Plot = new Class({ + + Implements: Graph.Plot, + + initialize: function(viz){ + this.viz = viz; + this.config = viz.config; + this.node = this.config.Node; + this.edge = this.config.Edge; + this.animation = new Animation; + this.nodeTypes = new TM.Plot.NodeTypes; + this.edgeTypes = new TM.Plot.EdgeTypes; + this.labels = viz.labels; + }, + + plot: function(opt, animating){ + var viz = this.viz, + graph = viz.graph; + viz.canvas.clear(); + this.plotTree(graph.getNode(viz.clickedNode && viz.clickedNode.id || viz.root), $.merge(viz.config, opt || {}, { + 'withLabels': true, + 'hideLabels': false, + 'plotSubtree': function(n, ch){ + return n.anySubnode("exist"); + } + }), animating); + } +}); + +/* + Class: TM.Label + + Custom extension of . + Contains custom , and extensions. + + Extends: + + All methods and subclasses. + + See also: + + , , , . + +*/ +TM.Label = {}; + +/* + TM.Label.Native + + Custom extension of . + + Extends: + + All methods + + See also: + + +*/ +TM.Label.Native = new Class({ + Implements: Graph.Label.Native, + + initialize: function(viz) { + this.config = viz.config; + this.leaf = viz.leaf; + }, + + renderLabel: function(canvas, node, controller){ + if(!this.leaf(node) && !this.config.titleHeight) return; + var pos = node.pos.getc(true), + ctx = canvas.getCtx(), + width = node.getData('width'), + height = node.getData('height'), + x = pos.x + width/2, + y = pos.y; + + ctx.fillText(node.name, x, y, width); + } +}); + +/* + TM.Label.SVG + + Custom extension of . + + Extends: + + All methods + + See also: + + +*/ +TM.Label.SVG = new Class( { + Implements: Graph.Label.SVG, + + initialize: function(viz){ + this.viz = viz; + this.leaf = viz.leaf; + this.config = viz.config; + }, + + /* + placeLabel + + Overrides abstract method placeLabel in . + + Parameters: + + tag - A DOM label element. + node - A . + controller - A configuration/controller object passed to the visualization. + + */ + placeLabel: function(tag, node, controller){ + var pos = node.pos.getc(true), + canvas = this.viz.canvas, + ox = canvas.translateOffsetX, + oy = canvas.translateOffsetY, + sx = canvas.scaleOffsetX, + sy = canvas.scaleOffsetY, + radius = canvas.getSize(); + var labelPos = { + x: Math.round(pos.x * sx + ox + radius.width / 2), + y: Math.round(pos.y * sy + oy + radius.height / 2) + }; + tag.setAttribute('x', labelPos.x); + tag.setAttribute('y', labelPos.y); + + if(!this.leaf(node) && !this.config.titleHeight) { + tag.style.display = 'none'; + } + controller.onPlaceLabel(tag, node); + } +}); + +/* + TM.Label.HTML + + Custom extension of . + + Extends: + + All methods. + + See also: + + + +*/ +TM.Label.HTML = new Class( { + Implements: Graph.Label.HTML, + + initialize: function(viz){ + this.viz = viz; + this.leaf = viz.leaf; + this.config = viz.config; + }, + + /* + placeLabel + + Overrides abstract method placeLabel in . + + Parameters: + + tag - A DOM label element. + node - A . + controller - A configuration/controller object passed to the visualization. + + */ + placeLabel: function(tag, node, controller){ + var pos = node.pos.getc(true), + canvas = this.viz.canvas, + ox = canvas.translateOffsetX, + oy = canvas.translateOffsetY, + sx = canvas.scaleOffsetX, + sy = canvas.scaleOffsetY, + radius = canvas.getSize(); + var labelPos = { + x: Math.round(pos.x * sx + ox + radius.width / 2), + y: Math.round(pos.y * sy + oy + radius.height / 2) + }; + + var style = tag.style; + style.left = labelPos.x + 'px'; + style.top = labelPos.y + 'px'; + style.width = node.getData('width') * sx + 'px'; + style.height = node.getData('height') * sy + 'px'; + style.zIndex = node._depth * 100; + style.display = ''; + + if(!this.leaf(node) && !this.config.titleHeight) { + tag.style.display = 'none'; + } + controller.onPlaceLabel(tag, node); + } +}); + +/* + Class: TM.Plot.NodeTypes + + This class contains a list of built-in types. + Node types implemented are 'none', 'rectangle'. + + You can add your custom node types, customizing your visualization to the extreme. + + Example: + + (start code js) + TM.Plot.NodeTypes.implement({ + 'mySpecialType': { + 'render': function(node, canvas) { + //print your custom node to canvas + }, + //optional + 'contains': function(node, pos) { + //return true if pos is inside the node or false otherwise + } + } + }); + (end code) + +*/ +TM.Plot.NodeTypes = new Class( { + 'none': { + 'render': $.empty + }, + + 'rectangle': { + 'render': function(node, canvas, animating){ + var leaf = this.viz.leaf(node), + config = this.config, + offst = config.offset, + titleHeight = config.titleHeight, + pos = node.pos.getc(true), + width = node.getData('width'), + height = node.getData('height'), + border = node.getData('border'), + ctx = canvas.getCtx(), + posx = pos.x + offst / 2, + posy = pos.y + offst / 2; + if(width <= offst || height <= offst) return; + if (leaf) { + if(config.cushion) { + var lg = ctx.createRadialGradient(posx + (width-offst)/2, posy + (height-offst)/2, 1, + posx + (width-offst)/2, posy + (height-offst)/2, width < height? height : width); + var color = node.getData('color'); + var colorGrad = $.rgbToHex($.map($.hexToRgb(color), + function(r) { return r * 0.2 >> 0; })); + lg.addColorStop(0, color); + lg.addColorStop(1, colorGrad); + ctx.fillStyle = lg; + } + ctx.fillRect(posx, posy, width - offst, height - offst); + if(border) { + ctx.save(); + ctx.strokeStyle = border; + ctx.strokeRect(posx, posy, width - offst, height - offst); + ctx.restore(); + } + } else if(titleHeight > 0){ + ctx.fillRect(pos.x + offst / 2, pos.y + offst / 2, width - offst, + titleHeight - offst); + if(border) { + ctx.save(); + ctx.strokeStyle = border; + ctx.strokeRect(pos.x + offst / 2, pos.y + offst / 2, width - offst, + height - offst); + ctx.restore(); + } + } + }, + 'contains': function(node, pos) { + if(this.viz.clickedNode && !node.isDescendantOf(this.viz.clickedNode.id) || node.ignore) return false; + var npos = node.pos.getc(true), + width = node.getData('width'), + leaf = this.viz.leaf(node), + height = leaf? node.getData('height') : this.config.titleHeight; + return this.nodeHelper.rectangle.contains({x: npos.x + width/2, y: npos.y + height/2}, pos, width, height); + } + } +}); + +TM.Plot.EdgeTypes = new Class( { + 'none': $.empty +}); + +/* + Class: TM.SliceAndDice + + A slice and dice TreeMap visualization. + + Implements: + + All methods and properties. +*/ +TM.SliceAndDice = new Class( { + Implements: [ + Loader, Extras, TM.Base, Layouts.TM.SliceAndDice + ] +}); + +/* + Class: TM.Squarified + + A squarified TreeMap visualization. + + Implements: + + All methods and properties. +*/ +TM.Squarified = new Class( { + Implements: [ + Loader, Extras, TM.Base, Layouts.TM.Squarified + ] +}); + +/* + Class: TM.Strip + + A strip TreeMap visualization. + + Implements: + + All methods and properties. +*/ +TM.Strip = new Class( { + Implements: [ + Loader, Extras, TM.Base, Layouts.TM.Strip + ] +}); + + +/* + * File: RGraph.js + * + */ + +/* + Class: RGraph + + A radial graph visualization with advanced animations. + + Inspired by: + + Animated Exploration of Dynamic Graphs with Radial Layout (Ka-Ping Yee, Danyel Fisher, Rachna Dhamija, Marti Hearst) + + Note: + + This visualization was built and engineered from scratch, taking only the paper as inspiration, and only shares some features with the visualization described in the paper. + + Implements: + + All methods + + Constructor Options: + + Inherits options from + + - + - + - + - + - + - + - + - + - + + Additionally, there are other parameters and some default values changed + + interpolation - (string) Default's *linear*. Describes the way nodes are interpolated. Possible values are 'linear' and 'polar'. + levelDistance - (number) Default's *100*. The distance between levels of the tree. + + Instance Properties: + + canvas - Access a instance. + graph - Access a instance. + op - Access a instance. + fx - Access a instance. + labels - Access a interface implementation. +*/ + +$jit.RGraph = new Class( { + + Implements: [ + Loader, Extras, Layouts.Radial + ], + + initialize: function(controller){ + var $RGraph = $jit.RGraph; + + var config = { + interpolation: 'linear', + levelDistance: 100 + }; + + this.controller = this.config = $.merge(Options("Canvas", "Node", "Edge", + "Fx", "Controller", "Tips", "NodeStyles", "Events", "Navigation", "Label"), config, controller); + + var canvasConfig = this.config; + if(canvasConfig.useCanvas) { + this.canvas = canvasConfig.useCanvas; + this.config.labelContainer = this.canvas.id + '-label'; + } else { + if(canvasConfig.background) { + canvasConfig.background = $.merge({ + type: 'Circles' + }, canvasConfig.background); + } + this.canvas = new Canvas(this, canvasConfig); + this.config.labelContainer = (typeof canvasConfig.injectInto == 'string'? canvasConfig.injectInto : canvasConfig.injectInto.id) + '-label'; + } + + this.graphOptions = { + 'complex': false, + 'Node': { + 'selected': false, + 'exist': true, + 'drawn': true + } + }; + this.graph = new Graph(this.graphOptions, this.config.Node, + this.config.Edge); + this.labels = new $RGraph.Label[canvasConfig.Label.type](this); + this.fx = new $RGraph.Plot(this, $RGraph); + this.op = new $RGraph.Op(this); + this.json = null; + this.root = null; + this.busy = false; + this.parent = false; + // initialize extras + this.initializeExtras(); + }, + + /* + + createLevelDistanceFunc + + Returns the levelDistance function used for calculating a node distance + to its origin. This function returns a function that is computed + per level and not per node, such that all nodes with the same depth will have the + same distance to the origin. The resulting function gets the + parent node as parameter and returns a float. + + */ + createLevelDistanceFunc: function(){ + var ld = this.config.levelDistance; + return function(elem){ + return (elem._depth + 1) * ld; + }; + }, + + /* + Method: refresh + + Computes positions and plots the tree. + + */ + refresh: function(){ + this.compute(); + this.plot(); + }, + + reposition: function(){ + this.compute('end'); + }, + + /* + Method: plot + + Plots the RGraph. This is a shortcut to *fx.plot*. + */ + plot: function(){ + this.fx.plot(); + }, + /* + getNodeAndParentAngle + + Returns the _parent_ of the given node, also calculating its angle span. + */ + getNodeAndParentAngle: function(id){ + var theta = false; + var n = this.graph.getNode(id); + var ps = n.getParents(); + var p = (ps.length > 0)? ps[0] : false; + if (p) { + var posParent = p.pos.getc(), posChild = n.pos.getc(); + var newPos = posParent.add(posChild.scale(-1)); + theta = Math.atan2(newPos.y, newPos.x); + if (theta < 0) + theta += 2 * Math.PI; + } + return { + parent: p, + theta: theta + }; + }, + /* + tagChildren + + Enumerates the children in order to maintain child ordering (second constraint of the paper). + */ + tagChildren: function(par, id){ + if (par.angleSpan) { + var adjs = []; + par.eachAdjacency(function(elem){ + adjs.push(elem.nodeTo); + }, "ignore"); + var len = adjs.length; + for ( var i = 0; i < len && id != adjs[i].id; i++) + ; + for ( var j = (i + 1) % len, k = 0; id != adjs[j].id; j = (j + 1) % len) { + adjs[j].dist = k++; + } + } + }, + /* + Method: onClick + + Animates the to center the node specified by *id*. + + Parameters: + + id - A id. + opt - (optional|object) An object containing some extra properties described below + hideLabels - (boolean) Default's *true*. Hide labels when performing the animation. + + Example: + + (start code js) + rgraph.onClick('someid'); + //or also... + rgraph.onClick('someid', { + hideLabels: false + }); + (end code) + + */ + onClick: function(id, opt){ + if (this.root != id && !this.busy) { + this.busy = true; + this.root = id; + that = this; + this.controller.onBeforeCompute(this.graph.getNode(id)); + var obj = this.getNodeAndParentAngle(id); + + // second constraint + this.tagChildren(obj.parent, id); + this.parent = obj.parent; + this.compute('end'); + + // first constraint + var thetaDiff = obj.theta - obj.parent.endPos.theta; + this.graph.eachNode(function(elem){ + elem.endPos.set(elem.endPos.getp().add($P(thetaDiff, 0))); + }); + + var mode = this.config.interpolation; + opt = $.merge( { + onComplete: $.empty + }, opt || {}); + + this.fx.animate($.merge( { + hideLabels: true, + modes: [ + mode + ] + }, opt, { + onComplete: function(){ + that.busy = false; + opt.onComplete(); + } + })); + } + } +}); + +$jit.RGraph.$extend = true; + +(function(RGraph){ + + /* + Class: RGraph.Op + + Custom extension of . + + Extends: + + All methods + + See also: + + + + */ + RGraph.Op = new Class( { + + Implements: Graph.Op + + }); + + /* + Class: RGraph.Plot + + Custom extension of . + + Extends: + + All methods + + See also: + + + + */ + RGraph.Plot = new Class( { + + Implements: Graph.Plot + + }); + + /* + Object: RGraph.Label + + Custom extension of . + Contains custom , and extensions. + + Extends: + + All methods and subclasses. + + See also: + + , , , . + + */ + RGraph.Label = {}; + + /* + RGraph.Label.Native + + Custom extension of . + + Extends: + + All methods + + See also: + + + + */ + RGraph.Label.Native = new Class( { + Implements: Graph.Label.Native + }); + + /* + RGraph.Label.SVG + + Custom extension of . + + Extends: + + All methods + + See also: + + + + */ + RGraph.Label.SVG = new Class( { + Implements: Graph.Label.SVG, + + initialize: function(viz){ + this.viz = viz; + }, + + /* + placeLabel + + Overrides abstract method placeLabel in . + + Parameters: + + tag - A DOM label element. + node - A . + controller - A configuration/controller object passed to the visualization. + + */ + placeLabel: function(tag, node, controller){ + var pos = node.pos.getc(true), + canvas = this.viz.canvas, + ox = canvas.translateOffsetX, + oy = canvas.translateOffsetY, + sx = canvas.scaleOffsetX, + sy = canvas.scaleOffsetY, + radius = canvas.getSize(); + var labelPos = { + x: Math.round(pos.x * sx + ox + radius.width / 2), + y: Math.round(pos.y * sy + oy + radius.height / 2) + }; + tag.setAttribute('x', labelPos.x); + tag.setAttribute('y', labelPos.y); + + controller.onPlaceLabel(tag, node); + } + }); + + /* + RGraph.Label.HTML + + Custom extension of . + + Extends: + + All methods. + + See also: + + + + */ + RGraph.Label.HTML = new Class( { + Implements: Graph.Label.HTML, + + initialize: function(viz){ + this.viz = viz; + }, + /* + placeLabel + + Overrides abstract method placeLabel in . + + Parameters: + + tag - A DOM label element. + node - A . + controller - A configuration/controller object passed to the visualization. + + */ + placeLabel: function(tag, node, controller){ + var pos = node.pos.getc(true), + canvas = this.viz.canvas, + ox = canvas.translateOffsetX, + oy = canvas.translateOffsetY, + sx = canvas.scaleOffsetX, + sy = canvas.scaleOffsetY, + radius = canvas.getSize(); + var labelPos = { + x: Math.round(pos.x * sx + ox + radius.width / 2), + y: Math.round(pos.y * sy + oy + radius.height / 2) + }; + + var style = tag.style; + style.left = labelPos.x + 'px'; + style.top = labelPos.y + 'px'; + style.display = this.fitsInCanvas(labelPos, canvas)? '' : 'none'; + + controller.onPlaceLabel(tag, node); + } + }); + + /* + Class: RGraph.Plot.NodeTypes + + This class contains a list of built-in types. + Node types implemented are 'none', 'circle', 'triangle', 'rectangle', 'star', 'ellipse' and 'square'. + + You can add your custom node types, customizing your visualization to the extreme. + + Example: + + (start code js) + RGraph.Plot.NodeTypes.implement({ + 'mySpecialType': { + 'render': function(node, canvas) { + //print your custom node to canvas + }, + //optional + 'contains': function(node, pos) { + //return true if pos is inside the node or false otherwise + } + } + }); + (end code) + + */ + RGraph.Plot.NodeTypes = new Class({ + 'none': { + 'render': $.empty, + 'contains': $.lambda(false) + }, + 'circle': { + 'render': function(node, canvas){ + var pos = node.pos.getc(true), + dim = node.getData('dim'); + this.nodeHelper.circle.render('fill', pos, dim, canvas); + }, + 'contains': function(node, pos){ + var npos = node.pos.getc(true), + dim = node.getData('dim'); + return this.nodeHelper.circle.contains(npos, pos, dim); + } + }, + 'ellipse': { + 'render': function(node, canvas){ + var pos = node.pos.getc(true), + width = node.getData('width'), + height = node.getData('height'); + this.nodeHelper.ellipse.render('fill', pos, width, height, canvas); + }, + // TODO(nico): be more precise... + 'contains': function(node, pos){ + var npos = node.pos.getc(true), + width = node.getData('width'), + height = node.getData('height'); + return this.nodeHelper.ellipse.contains(npos, pos, width, height); + } + }, + 'square': { + 'render': function(node, canvas){ + var pos = node.pos.getc(true), + dim = node.getData('dim'); + this.nodeHelper.square.render('fill', pos, dim, canvas); + }, + 'contains': function(node, pos){ + var npos = node.pos.getc(true), + dim = node.getData('dim'); + return this.nodeHelper.square.contains(npos, pos, dim); + } + }, + 'rectangle': { + 'render': function(node, canvas){ + var pos = node.pos.getc(true), + width = node.getData('width'), + height = node.getData('height'); + this.nodeHelper.rectangle.render('fill', pos, width, height, canvas); + }, + 'contains': function(node, pos){ + var npos = node.pos.getc(true), + width = node.getData('width'), + height = node.getData('height'); + return this.nodeHelper.rectangle.contains(npos, pos, width, height); + } + }, + 'triangle': { + 'render': function(node, canvas){ + var pos = node.pos.getc(true), + dim = node.getData('dim'); + this.nodeHelper.triangle.render('fill', pos, dim, canvas); + }, + 'contains': function(node, pos) { + var npos = node.pos.getc(true), + dim = node.getData('dim'); + return this.nodeHelper.triangle.contains(npos, pos, dim); + } + }, + 'star': { + 'render': function(node, canvas){ + var pos = node.pos.getc(true), + dim = node.getData('dim'); + this.nodeHelper.star.render('fill', pos, dim, canvas); + }, + 'contains': function(node, pos) { + var npos = node.pos.getc(true), + dim = node.getData('dim'); + return this.nodeHelper.star.contains(npos, pos, dim); + } + } + }); + + /* + Class: RGraph.Plot.EdgeTypes + + This class contains a list of built-in types. + Edge types implemented are 'none', 'line' and 'arrow'. + + You can add your custom edge types, customizing your visualization to the extreme. + + Example: + + (start code js) + RGraph.Plot.EdgeTypes.implement({ + 'mySpecialType': { + 'render': function(adj, canvas) { + //print your custom edge to canvas + }, + //optional + 'contains': function(adj, pos) { + //return true if pos is inside the arc or false otherwise + } + } + }); + (end code) + + */ + RGraph.Plot.EdgeTypes = new Class({ + 'none': $.empty, + 'line': { + 'render': function(adj, canvas) { + var from = adj.nodeFrom.pos.getc(true), + to = adj.nodeTo.pos.getc(true); + this.edgeHelper.line.render(from, to, canvas); + }, + 'contains': function(adj, pos) { + var from = adj.nodeFrom.pos.getc(true), + to = adj.nodeTo.pos.getc(true); + return this.edgeHelper.line.contains(from, to, pos, this.edge.epsilon); + } + }, + 'arrow': { + 'render': function(adj, canvas) { + var from = adj.nodeFrom.pos.getc(true), + to = adj.nodeTo.pos.getc(true), + dim = adj.getData('dim'), + direction = adj.data.$direction, + inv = (direction && direction.length>1 && direction[0] != adj.nodeFrom.id); + this.edgeHelper.arrow.render(from, to, dim, inv, canvas); + }, + 'contains': function(adj, pos) { + var from = adj.nodeFrom.pos.getc(true), + to = adj.nodeTo.pos.getc(true); + return this.edgeHelper.arrow.contains(from, to, pos, this.edge.epsilon); + } + } + }); + +})($jit.RGraph); + + +/* + * File: Hypertree.js + * +*/ + +/* + Complex + + A multi-purpose Complex Class with common methods. Extended for the Hypertree. + +*/ +/* + moebiusTransformation + + Calculates a moebius transformation for this point / complex. + For more information go to: + http://en.wikipedia.org/wiki/Moebius_transformation. + + Parameters: + + c - An initialized Complex instance representing a translation Vector. +*/ + +Complex.prototype.moebiusTransformation = function(c) { + var num = this.add(c); + var den = c.$conjugate().$prod(this); + den.x++; + return num.$div(den); +}; + +/* + moebiusTransformation + + Calculates a moebius transformation for the hyperbolic tree. + + + + Parameters: + + graph - A instance. + pos - A . + prop - A property array. + theta - Rotation angle. + startPos - _optional_ start position. +*/ +Graph.Util.moebiusTransformation = function(graph, pos, prop, startPos, flags) { + this.eachNode(graph, function(elem) { + for ( var i = 0; i < prop.length; i++) { + var p = pos[i].scale(-1), property = startPos ? startPos : prop[i]; + elem.getPos(prop[i]).set(elem.getPos(property).getc().moebiusTransformation(p)); + } + }, flags); +}; + +/* + Class: Hypertree + + A Hyperbolic Tree/Graph visualization. + + Inspired by: + + A Focus+Context Technique Based on Hyperbolic Geometry for Visualizing Large Hierarchies (John Lamping, Ramana Rao, and Peter Pirolli). + + + Note: + + This visualization was built and engineered from scratch, taking only the paper as inspiration, and only shares some features with the Hypertree described in the paper. + + Implements: + + All methods + + Constructor Options: + + Inherits options from + + - + - + - + - + - + - + - + - + - + + Additionally, there are other parameters and some default values changed + + radius - (string|number) Default's *auto*. The radius of the disc to plot the in. 'auto' will take the smaller value from the width and height canvas dimensions. You can also set this to a custom value, for example *250*. + offset - (number) Default's *0*. A number in the range [0, 1) that will be substracted to each node position to make a more compact . This will avoid placing nodes too far from each other when a there's a selected node. + fps - Described in . It's default value has been changed to *35*. + duration - Described in . It's default value has been changed to *1500*. + Edge.type - Described in . It's default value has been changed to *hyperline*. + + Instance Properties: + + canvas - Access a instance. + graph - Access a instance. + op - Access a instance. + fx - Access a instance. + labels - Access a interface implementation. + +*/ + +$jit.Hypertree = new Class( { + + Implements: [ Loader, Extras, Layouts.Radial ], + + initialize: function(controller) { + var $Hypertree = $jit.Hypertree; + + var config = { + radius: "auto", + offset: 0, + Edge: { + type: 'hyperline' + }, + duration: 1500, + fps: 35 + }; + this.controller = this.config = $.merge(Options("Canvas", "Node", "Edge", + "Fx", "Tips", "NodeStyles", "Events", "Navigation", "Controller", "Label"), config, controller); + + var canvasConfig = this.config; + if(canvasConfig.useCanvas) { + this.canvas = canvasConfig.useCanvas; + this.config.labelContainer = this.canvas.id + '-label'; + } else { + if(canvasConfig.background) { + canvasConfig.background = $.merge({ + type: 'Circles' + }, canvasConfig.background); + } + this.canvas = new Canvas(this, canvasConfig); + this.config.labelContainer = (typeof canvasConfig.injectInto == 'string'? canvasConfig.injectInto : canvasConfig.injectInto.id) + '-label'; + } + + this.graphOptions = { + 'complex': false, + 'Node': { + 'selected': false, + 'exist': true, + 'drawn': true + } + }; + this.graph = new Graph(this.graphOptions, this.config.Node, + this.config.Edge); + this.labels = new $Hypertree.Label[canvasConfig.Label.type](this); + this.fx = new $Hypertree.Plot(this, $Hypertree); + this.op = new $Hypertree.Op(this); + this.json = null; + this.root = null; + this.busy = false; + // initialize extras + this.initializeExtras(); + }, + + /* + + createLevelDistanceFunc + + Returns the levelDistance function used for calculating a node distance + to its origin. This function returns a function that is computed + per level and not per node, such that all nodes with the same depth will have the + same distance to the origin. The resulting function gets the + parent node as parameter and returns a float. + + */ + createLevelDistanceFunc: function() { + // get max viz. length. + var r = this.getRadius(); + // get max depth. + var depth = 0, max = Math.max, config = this.config; + this.graph.eachNode(function(node) { + depth = max(node._depth, depth); + }, "ignore"); + depth++; + // node distance generator + var genDistFunc = function(a) { + return function(node) { + node.scale = r; + var d = node._depth + 1; + var acum = 0, pow = Math.pow; + while (d) { + acum += pow(a, d--); + } + return acum - config.offset; + }; + }; + // estimate better edge length. + for ( var i = 0.51; i <= 1; i += 0.01) { + var valSeries = (1 - Math.pow(i, depth)) / (1 - i); + if (valSeries >= 2) { return genDistFunc(i - 0.01); } + } + return genDistFunc(0.75); + }, + + /* + Method: getRadius + + Returns the current radius of the visualization. If *config.radius* is *auto* then it + calculates the radius by taking the smaller size of the widget. + + See also: + + + + */ + getRadius: function() { + var rad = this.config.radius; + if (rad !== "auto") { return rad; } + var s = this.canvas.getSize(); + return Math.min(s.width, s.height) / 2; + }, + + /* + Method: refresh + + Computes positions and plots the tree. + + Parameters: + + reposition - (optional|boolean) Set this to *true* to force all positions (current, start, end) to match. + + */ + refresh: function(reposition) { + if (reposition) { + this.reposition(); + this.graph.eachNode(function(node) { + node.startPos.rho = node.pos.rho = node.endPos.rho; + node.startPos.theta = node.pos.theta = node.endPos.theta; + }); + } else { + this.compute(); + } + this.plot(); + }, + + /* + reposition + + Computes nodes' positions and restores the tree to its previous position. + + For calculating nodes' positions the root must be placed on its origin. This method does this + and then attemps to restore the hypertree to its previous position. + + */ + reposition: function() { + this.compute('end'); + var vector = this.graph.getNode(this.root).pos.getc().scale(-1); + Graph.Util.moebiusTransformation(this.graph, [ vector ], [ 'end' ], + 'end', "ignore"); + this.graph.eachNode(function(node) { + if (node.ignore) { + node.endPos.rho = node.pos.rho; + node.endPos.theta = node.pos.theta; + } + }); + }, + + /* + Method: plot + + Plots the . This is a shortcut to *fx.plot*. + + */ + plot: function() { + this.fx.plot(); + }, + + /* + Method: onClick + + Animates the to center the node specified by *id*. + + Parameters: + + id - A id. + opt - (optional|object) An object containing some extra properties described below + hideLabels - (boolean) Default's *true*. Hide labels when performing the animation. + + Example: + + (start code js) + ht.onClick('someid'); + //or also... + ht.onClick('someid', { + hideLabels: false + }); + (end code) + + */ + onClick: function(id, opt) { + var pos = this.graph.getNode(id).pos.getc(true); + this.move(pos, opt); + }, + + /* + Method: move + + Translates the tree to the given position. + + Parameters: + + pos - (object) A *x, y* coordinate object where x, y in [0, 1), to move the tree to. + opt - This object has been defined in + + Example: + + (start code js) + ht.move({ x: 0, y: 0.7 }, { + hideLabels: false + }); + (end code) + + */ + move: function(pos, opt) { + var versor = $C(pos.x, pos.y); + if (this.busy === false && versor.norm() < 1) { + this.busy = true; + var root = this.graph.getClosestNodeToPos(versor), that = this; + this.graph.computeLevels(root.id, 0); + this.controller.onBeforeCompute(root); + opt = $.merge( { + onComplete: $.empty + }, opt || {}); + this.fx.animate($.merge( { + modes: [ 'moebius' ], + hideLabels: true + }, opt, { + onComplete: function() { + that.busy = false; + opt.onComplete(); + } + }), versor); + } + } +}); + +$jit.Hypertree.$extend = true; + +(function(Hypertree) { + + /* + Class: Hypertree.Op + + Custom extension of . + + Extends: + + All methods + + See also: + + + + */ + Hypertree.Op = new Class( { + + Implements: Graph.Op + + }); + + /* + Class: Hypertree.Plot + + Custom extension of . + + Extends: + + All methods + + See also: + + + + */ + Hypertree.Plot = new Class( { + + Implements: Graph.Plot + + }); + + /* + Object: Hypertree.Label + + Custom extension of . + Contains custom , and extensions. + + Extends: + + All methods and subclasses. + + See also: + + , , , . + + */ + Hypertree.Label = {}; + + /* + Hypertree.Label.Native + + Custom extension of . + + Extends: + + All methods + + See also: + + + + */ + Hypertree.Label.Native = new Class( { + Implements: Graph.Label.Native, + + initialize: function(viz) { + this.viz = viz; + }, + + renderLabel: function(canvas, node, controller) { + var ctx = canvas.getCtx(); + var coord = node.pos.getc(true); + var s = this.viz.getRadius(); + ctx.fillText(node.name, coord.x * s, coord.y * s); + } + }); + + /* + Hypertree.Label.SVG + + Custom extension of . + + Extends: + + All methods + + See also: + + + + */ + Hypertree.Label.SVG = new Class( { + Implements: Graph.Label.SVG, + + initialize: function(viz) { + this.viz = viz; + }, + + /* + placeLabel + + Overrides abstract method placeLabel in . + + Parameters: + + tag - A DOM label element. + node - A . + controller - A configuration/controller object passed to the visualization. + + */ + placeLabel: function(tag, node, controller) { + var pos = node.pos.getc(true), + canvas = this.viz.canvas, + ox = canvas.translateOffsetX, + oy = canvas.translateOffsetY, + sx = canvas.scaleOffsetX, + sy = canvas.scaleOffsetY, + radius = canvas.getSize(), + r = this.viz.getRadius(); + var labelPos = { + x: Math.round((pos.x * sx) * r + ox + radius.width / 2), + y: Math.round((pos.y * sy) * r + oy + radius.height / 2) + }; + tag.setAttribute('x', labelPos.x); + tag.setAttribute('y', labelPos.y); + controller.onPlaceLabel(tag, node); + } + }); + + /* + Hypertree.Label.HTML + + Custom extension of . + + Extends: + + All methods. + + See also: + + + + */ + Hypertree.Label.HTML = new Class( { + Implements: Graph.Label.HTML, + + initialize: function(viz) { + this.viz = viz; + }, + /* + placeLabel + + Overrides abstract method placeLabel in . + + Parameters: + + tag - A DOM label element. + node - A . + controller - A configuration/controller object passed to the visualization. + + */ + placeLabel: function(tag, node, controller) { + var pos = node.pos.getc(true), + canvas = this.viz.canvas, + ox = canvas.translateOffsetX, + oy = canvas.translateOffsetY, + sx = canvas.scaleOffsetX, + sy = canvas.scaleOffsetY, + radius = canvas.getSize(), + r = this.viz.getRadius(); + var labelPos = { + x: Math.round((pos.x * sx) * r + ox + radius.width / 2), + y: Math.round((pos.y * sy) * r + oy + radius.height / 2) + }; + var style = tag.style; + style.left = labelPos.x + 'px'; + style.top = labelPos.y + 'px'; + style.display = this.fitsInCanvas(labelPos, canvas) ? '' : 'none'; + + controller.onPlaceLabel(tag, node); + } + }); + + /* + Class: Hypertree.Plot.NodeTypes + + This class contains a list of built-in types. + Node types implemented are 'none', 'circle', 'triangle', 'rectangle', 'star', 'ellipse' and 'square'. + + You can add your custom node types, customizing your visualization to the extreme. + + Example: + + (start code js) + Hypertree.Plot.NodeTypes.implement({ + 'mySpecialType': { + 'render': function(node, canvas) { + //print your custom node to canvas + }, + //optional + 'contains': function(node, pos) { + //return true if pos is inside the node or false otherwise + } + } + }); + (end code) + + */ + Hypertree.Plot.NodeTypes = new Class({ + 'none': { + 'render': $.empty, + 'contains': $.lambda(false) + }, + 'circle': { + 'render': function(node, canvas) { + var nconfig = this.node, + dim = node.getData('dim'), + p = node.pos.getc(); + dim = nconfig.transform? dim * (1 - p.squaredNorm()) : dim; + p.$scale(node.scale); + if (dim > 0.2) { + this.nodeHelper.circle.render('fill', p, dim, canvas); + } + }, + 'contains': function(node, pos) { + var dim = node.getData('dim'), + npos = node.pos.getc().$scale(node.scale); + return this.nodeHelper.circle.contains(npos, pos, dim); + } + }, + 'ellipse': { + 'render': function(node, canvas) { + var pos = node.pos.getc().$scale(node.scale), + width = node.getData('width'), + height = node.getData('height'); + this.nodeHelper.ellipse.render('fill', pos, width, height, canvas); + }, + 'contains': function(node, pos) { + var width = node.getData('width'), + height = node.getData('height'), + npos = node.pos.getc().$scale(node.scale); + return this.nodeHelper.circle.contains(npos, pos, width, height); + } + }, + 'square': { + 'render': function(node, canvas) { + var nconfig = this.node, + dim = node.getData('dim'), + p = node.pos.getc(); + dim = nconfig.transform? dim * (1 - p.squaredNorm()) : dim; + p.$scale(node.scale); + if (dim > 0.2) { + this.nodeHelper.square.render('fill', p, dim, canvas); + } + }, + 'contains': function(node, pos) { + var dim = node.getData('dim'), + npos = node.pos.getc().$scale(node.scale); + return this.nodeHelper.square.contains(npos, pos, dim); + } + }, + 'rectangle': { + 'render': function(node, canvas) { + var nconfig = this.node, + width = node.getData('width'), + height = node.getData('height'), + pos = node.pos.getc(); + width = nconfig.transform? width * (1 - pos.squaredNorm()) : width; + height = nconfig.transform? height * (1 - pos.squaredNorm()) : height; + pos.$scale(node.scale); + if (width > 0.2 && height > 0.2) { + this.nodeHelper.rectangle.render('fill', pos, width, height, canvas); + } + }, + 'contains': function(node, pos) { + var width = node.getData('width'), + height = node.getData('height'), + npos = node.pos.getc().$scale(node.scale); + return this.nodeHelper.square.contains(npos, pos, width, height); + } + }, + 'triangle': { + 'render': function(node, canvas) { + var nconfig = this.node, + dim = node.getData('dim'), + p = node.pos.getc(); + dim = nconfig.transform? dim * (1 - p.squaredNorm()) : dim; + p.$scale(node.scale); + if (dim > 0.2) { + this.nodeHelper.triangle.render('fill', p, dim, canvas); + } + }, + 'contains': function(node, pos) { + var dim = node.getData('dim'), + npos = node.pos.getc().$scale(node.scale); + return this.nodeHelper.triangle.contains(npos, pos, dim); + } + }, + 'star': { + 'render': function(node, canvas) { + var nconfig = this.node, + dim = node.getData('dim'), + p = node.pos.getc(); + dim = nconfig.transform? dim * (1 - p.squaredNorm()) : dim; + p.$scale(node.scale); + if (dim > 0.2) { + this.nodeHelper.star.render('fill', p, dim, canvas); + } + }, + 'contains': function(node, pos) { + var dim = node.getData('dim'), + npos = node.pos.getc().$scale(node.scale); + return this.nodeHelper.star.contains(npos, pos, dim); + } + } + }); + + /* + Class: Hypertree.Plot.EdgeTypes + + This class contains a list of built-in types. + Edge types implemented are 'none', 'line', 'arrow' and 'hyperline'. + + You can add your custom edge types, customizing your visualization to the extreme. + + Example: + + (start code js) + Hypertree.Plot.EdgeTypes.implement({ + 'mySpecialType': { + 'render': function(adj, canvas) { + //print your custom edge to canvas + }, + //optional + 'contains': function(adj, pos) { + //return true if pos is inside the arc or false otherwise + } + } + }); + (end code) + + */ + Hypertree.Plot.EdgeTypes = new Class({ + 'none': $.empty, + 'line': { + 'render': function(adj, canvas) { + var from = adj.nodeFrom.pos.getc(true), + to = adj.nodeTo.pos.getc(true), + r = adj.nodeFrom.scale; + this.edgeHelper.line.render({x:from.x*r, y:from.y*r}, {x:to.x*r, y:to.y*r}, canvas); + }, + 'contains': function(adj, pos) { + var from = adj.nodeFrom.pos.getc(true), + to = adj.nodeTo.pos.getc(true), + r = adj.nodeFrom.scale; + this.edgeHelper.line.contains({x:from.x*r, y:from.y*r}, {x:to.x*r, y:to.y*r}, pos, this.edge.epsilon); + } + }, + 'arrow': { + 'render': function(adj, canvas) { + var from = adj.nodeFrom.pos.getc(true), + to = adj.nodeTo.pos.getc(true), + r = adj.nodeFrom.scale, + dim = adj.getData('dim'), + direction = adj.data.$direction, + inv = (direction && direction.length>1 && direction[0] != adj.nodeFrom.id); + this.edgeHelper.arrow.render({x:from.x*r, y:from.y*r}, {x:to.x*r, y:to.y*r}, dim, inv, canvas); + }, + 'contains': function(adj, pos) { + var from = adj.nodeFrom.pos.getc(true), + to = adj.nodeTo.pos.getc(true), + r = adj.nodeFrom.scale; + this.edgeHelper.arrow.contains({x:from.x*r, y:from.y*r}, {x:to.x*r, y:to.y*r}, pos, this.edge.epsilon); + } + }, + 'hyperline': { + 'render': function(adj, canvas) { + var from = adj.nodeFrom.pos.getc(), + to = adj.nodeTo.pos.getc(), + dim = this.viz.getRadius(); + this.edgeHelper.hyperline.render(from, to, dim, canvas); + }, + 'contains': $.lambda(false) + } + }); + +})($jit.Hypertree); + + + + + })(); \ No newline at end of file diff --git a/jssource/src_files/include/SugarCharts/Jit/js/mySugarCharts.js b/jssource/src_files/include/SugarCharts/Jit/js/mySugarCharts.js new file mode 100644 index 00000000..72be7fce --- /dev/null +++ b/jssource/src_files/include/SugarCharts/Jit/js/mySugarCharts.js @@ -0,0 +1,117 @@ +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + + + +SUGAR.mySugar.sugarCharts = function() { + +var activeTab = activePage, + charts = new Object(), + windowWidth = 0, + firstLoad = (SUGAR.isIE) ? true: false; + + return { + loadSugarCharts: function(activeTab) { + var chartFound = false; + for (id in charts[activeTab]){ + if(id != 'undefined'){ + chartFound = true; + //alert(charts[activeTab][id]['chartType']); + loadSugarChart( + charts[activeTab][id]['chartId'], + charts[activeTab][id]['jsonFilename'], + charts[activeTab][id]['css'], + charts[activeTab][id]['chartConfig'] + ); + } + } + //clear charts array + charts = new Object(); + + }, + + addToChartsArrayJson: function(json,activeTab) { + for (id in json) { + if(json[id]['supported'] == "true") { + SUGAR.mySugar.sugarCharts.addToChartsArray( + json[id]['chartId'], + json[id]['filename'], + json[id]['css'], + json[id]['chartConfig'], + activeTab); + } + } + }, + addToChartsArray: function(chartId,jsonFilename,css,chartConfig,activeTab) { + + if (charts[activeTab] == null){ + charts[activeTab] = new Object(); + } + charts[activeTab][chartId] = new Object(); + charts[activeTab][chartId]['chartId'] = chartId; + charts[activeTab][chartId]['jsonFilename'] = jsonFilename; + charts[activeTab][chartId]['css'] = css; + charts[activeTab][chartId]['chartConfig'] = chartConfig; + + }, + refreshPage: function() { + var newWidth = document.body.offsetWidth; + if(newWidth != windowWidth && !firstLoad){ + if(SUGAR.isIE) { + SUGAR.mySugar.loading.show(); + document.getElementById('loading_c').style.display = 'inline'; + setTimeout(function() {location.reload();}, 500); + + } else { + SUGAR.mySugar.retrievePage(activePage); + } + SUGAR.mySugar.sugarCharts.loadSugarCharts(activePage); + + } + firstLoad = false; + windowWidth = newWidth; + + }, + refreshGraphs: function() { + + setTimeout("SUGAR.mySugar.sugarCharts.refreshPage()", 1000); + } + + + } +}(); + +YAHOO.util.Event.addListener(window, 'resize', SUGAR.mySugar.sugarCharts.refreshGraphs); \ No newline at end of file diff --git a/jssource/src_files/include/SugarCharts/Jit/js/sugarCharts.js b/jssource/src_files/include/SugarCharts/Jit/js/sugarCharts.js new file mode 100644 index 00000000..8d276e04 --- /dev/null +++ b/jssource/src_files/include/SugarCharts/Jit/js/sugarCharts.js @@ -0,0 +1,784 @@ +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + + + +function loadSugarChart (chartId,jsonFilename,css,chartConfig) { + + var labelType, useGradients, nativeTextSupport, animate; + (function() { + var ua = navigator.userAgent, + typeOfCanvas = typeof HTMLCanvasElement, + nativeCanvasSupport = (typeOfCanvas == 'object' || typeOfCanvas == 'function'), + textSupport = nativeCanvasSupport + && (typeof document.createElement('canvas').getContext('2d').fillText == 'function'); + labelType = 'Native'; + nativeTextSupport = labelType == 'Native'; + useGradients = nativeCanvasSupport; + animate = false; + })(); + + + switch(chartConfig["chartType"]) { + case "barChart": + var handleFailure = function(o){ + alert('fail'); + if(o.responseText !== undefined){ + alert('failed'); + } + } + var handleSuccess = function(o){ + + if(o.responseText !== undefined && o.responseText != "No Data"){ + var json = eval('('+o.responseText+')'); + + var properties = $jit.util.splat(json.properties)[0]; + var marginBottom = (chartConfig["orientation"] == 'vertical' && json.values.length > 8) ? 20*4 : 20; + //init BarChart + var barChart = new $jit.BarChart({ + //id of the visualization container + injectInto: chartId, + //whether to add animations + animate: false, + nodeCount: json.values.length, + renderBackground: chartConfig['imageExportType'] == "jpg" ? true: false, + backgroundColor: 'rgb(255,255,255)', + colorStop1: 'rgba(255,255,255,.8)', + colorStop2: 'rgba(255,255,255,0)', + shadow: { + enable: true, + size: 2 + }, + //horizontal or vertical barcharts + orientation: chartConfig["orientation"], + hoveredColor: false, + Title: { + text: properties['title'], + size: 16, + color: '#444444', + offset: 20 + }, + Subtitle: { + text: properties['subtitle'], + size: 11, + color: css["color"], + offset: 20 + }, + Ticks: { + enable: true, + color: css["gridLineColor"] + }, + //bars separation + barsOffset: (chartConfig["orientation"] == "vertical") ? 30 : 20, + //visualization offset + Margin: { + top:20, + left: 30, + right: 20, + bottom: marginBottom + }, + ScrollNote: { + text: (chartConfig["scroll"] && SUGAR.util.isTouchScreen()) ? "Use two fingers to scroll" : "", + size: 12 + }, + Events: { + enable: true, + onClick: function(node) { + if(!node || SUGAR.util.isTouchScreen()) return; + if(node.link == 'undefined' || node.link == '') return; + window.location.href=node.link; + } + }, + //labels offset position + labelOffset: 5, + //bars style + type: useGradients? chartConfig["barType"]+':gradient' : chartConfig["barType"], + //whether to show the aggregation of the values + showAggregates:true, + //whether to show the labels for the bars + showLabels:true, + //labels style + Label: { + type: labelType, //Native or HTML + size: 12, + family: css["font-family"], + color: css["color"], + colorAlt: "#ffffff" + }, + //add tooltips + Tips: { + enable: true, + onShow: function(tip, elem) { + if(elem.link != 'undefined' && elem.link != '') { + drillDown = (SUGAR.util.isTouchScreen()) ? "
            Click to drilldown" : "
            Click to drilldown"; + } else { + drillDown = ""; + } + + if(elem.valuelabel != 'undefined' && elem.valuelabel != undefined && elem.valuelabel != '') { + value = "elem.valuelabel"; + } else { + value = "elem.value"; + } + eval("tip.innerHTML = '' + elem."+chartConfig["tip"]+" + ': ' + "+value+" + ' - ' + elem.percentage + '%' + drillDown"); + } + } + }); + //load JSON data. + barChart.loadJSON(json); + //end + + /* + var list = $jit.id('id-list'), + button = $jit.id('update'), + orn = $jit.id('switch-orientation'); + //update json on click 'Update Data' + $jit.util.addEvent(button, 'click', function() { + var util = $jit.util; + if(util.hasClass(button, 'gray')) return; + util.removeClass(button, 'white'); + util.addClass(button, 'gray'); + barChart.updateJSON(json2); + }); + */ + //dynamically add legend to list + var list = $jit.id('legend'+chartId); + var legend = barChart.getLegend(), + cols = (typeof SUGAR == 'undefined' || typeof SUGAR.mySugar == 'undefined') ? 8 : 4, + rows = Math.ceil(legend["name"].length/cols), + table = ""; + var j = 0; + for(i=0;i ' + legend["name"][j]; + } + + table += ''; + j++; + } + table += ""; + } + + table += "
            "; + list.innerHTML = table; + + + //save canvas to image for pdf consumption + $jit.util.saveImageTest(chartId,jsonFilename,chartConfig["imageExportType"]); + + + } + } + + var callback = + { + success:handleSuccess, + failure:handleFailure, + argument: { foo:'foo', bar:''} + }; + + var request = YAHOO.util.Connect.asyncRequest('GET', jsonFilename + "?r=" + new Date().getTime(), callback); + break; + + case "lineChart": + var handleFailure = function(o){ + alert('fail'); + if(o.responseText !== undefined){ + alert('failed'); + } + } + var handleSuccess = function(o){ + + if(o.responseText !== undefined && o.responseText != "No Data"){ + var json = eval('('+o.responseText+')'); + + var properties = $jit.util.splat(json.properties)[0]; + //init Linecahrt + var lineChart = new $jit.LineChart({ + //id of the visualization container + injectInto: chartId, + //whether to add animations + animate: false, + renderBackground: chartConfig['imageExportType'] == "jpg" ? true: false, + backgroundColor: 'rgb(255,255,255)', + colorStop1: 'rgba(255,255,255,.8)', + colorStop2: 'rgba(255,255,255,0)', + selectOnHover: false, + Title: { + text: properties['title'], + size: 16, + color: '#444444', + offset: 20 + }, + Subtitle: { + text: properties['subtitle'], + size: 11, + color: css["color"], + offset: 20 + }, + Ticks: { + enable: true, + color: css["gridLineColor"] + }, + //visualization offset + Margin: { + top:20, + left: 40, + right: 40, + bottom: 20 + }, + Events: { + enable: true, + onClick: function(node) { + if(!node || SUGAR.util.isTouchScreen()) return; + if(node.link == 'undefined' || node.link == '') return; + window.location.href=node.link; + } + }, + //labels offset position + labelOffset: 5, + //bars style + type: useGradients? chartConfig["lineType"]+':gradient' : chartConfig["lineType"], + //whether to show the aggregation of the values + showAggregates:true, + //whether to show the labels for the bars + showLabels:true, + //labels style + Label: { + type: labelType, //Native or HTML + size: 12, + family: css["font-family"], + color: css["color"], + colorAlt: "#ffffff" + }, + //add tooltips + Tips: { + enable: true, + onShow: function(tip, elem) { + if(elem.link != 'undefined' && elem.link != '') { + drillDown = (SUGAR.util.isTouchScreen()) ? "
            Click to drilldown" : "
            Click to drilldown"; + } else { + drillDown = ""; + } + + if(elem.valuelabel != 'undefined' && elem.valuelabel != undefined && elem.valuelabel != '') { + var value = "elem.valuelabel"; + } else { + var value = "elem.value"; + } + + if(elem.collision) { + eval("var name = elem."+chartConfig["tip"]+";"); + var content = ''; + + for(var i=0; i:'; + } + content += '
            ' + elem.value[i] + ' - ' + elem.percentage[i] + '%' + '
            '; + tip.innerHTML = content; + } else { + eval("tip.innerHTML = '' + elem."+chartConfig["tip"]+" + ': ' + "+value+" + ' - ' + elem.percentage + '%' + drillDown"); + } + } + } + }); + //load JSON data. + lineChart.loadJSON(json); + //end + + /* + var list = $jit.id('id-list'), + button = $jit.id('update'), + orn = $jit.id('switch-orientation'); + //update json on click 'Update Data' + $jit.util.addEvent(button, 'click', function() { + var util = $jit.util; + if(util.hasClass(button, 'gray')) return; + util.removeClass(button, 'white'); + util.addClass(button, 'gray'); + barChart.updateJSON(json2); + }); + */ + //dynamically add legend to list + var list = $jit.id('legend'+chartId); + var legend = lineChart.getLegend(), + cols = (typeof SUGAR == 'undefined' || typeof SUGAR.mySugar == 'undefined') ? 8 : 4, + rows = Math.ceil(legend["name"].length/cols), + table = ""; + var j = 0; + for(i=0;i ' + legend["name"][j]; + } + + table += ''; + j++; + } + table += ""; + } + + table += "
            "; + list.innerHTML = table; + + + //save canvas to image for pdf consumption + $jit.util.saveImageTest(chartId,jsonFilename,chartConfig["imageExportType"]); + + + } + } + + var callback = + { + success:handleSuccess, + failure:handleFailure, + argument: { foo:'foo', bar:''} + }; + + var request = YAHOO.util.Connect.asyncRequest('GET', jsonFilename + "?r=" + new Date().getTime(), callback); + break; + + + case "pieChart": + + var handleFailure = function(o){ + alert('fail'); + if(o.responseText !== undefined){ + alert('failed'); + } + } + var handleSuccess = function(o){ + + if(o.responseText !== undefined){ + var json = eval('('+o.responseText+')'); + var properties = $jit.util.splat(json.properties)[0]; + + //init BarChart + var pieChart = new $jit.PieChart({ + //id of the visualization container + injectInto: chartId, + //whether to add animations + animate: false, + renderBackground: chartConfig['imageExportType'] == "jpg" ? true: false, + backgroundColor: 'rgb(255,255,255)', + colorStop1: 'rgba(255,255,255,.8)', + colorStop2: 'rgba(255,255,255,0)', + labelType: properties['labels'], + hoveredColor: false, + //offsets + offset: 50, + sliceOffset: 0, + labelOffset: 30, + //slice style + type: useGradients? chartConfig["pieType"]+':gradient' : chartConfig["pieType"], + //whether to show the labels for the slices + showLabels:true, + Events: { + enable: true, + onClick: function(node) { + if(!node || SUGAR.util.isTouchScreen()) return; + if(node.link == 'undefined' || node.link == '') return; + window.location.href=node.link; + } + }, + //label styling + Label: { + type: labelType, //Native or HTML + size: 12, + family: css["font-family"], + color: css["color"] + }, + //enable tips + Tips: { + enable: true, + onShow: function(tip, elem) { + if(elem.link != 'undefined' && elem.link != '') { + drillDown = (SUGAR.util.isTouchScreen()) ? "
            Click to drilldown" : "
            Click to drilldown"; + } else { + drillDown = ""; + } + + if(elem.valuelabel != 'undefined' && elem.valuelabel != undefined && elem.valuelabel != '') { + value = "elem.valuelabel"; + } else { + value = "elem.value"; + } + eval("tip.innerHTML = '' + elem.label + ': ' + "+ value +" + ' - ' + elem.percentage + '%' + drillDown"); + } + } + }); + //load JSON data. + pieChart.loadJSON(json); + //end + //dynamically add legend to list + var list = $jit.id('legend'+chartId); + var legend = pieChart.getLegend(), + cols = (typeof SUGAR == 'undefined' || typeof SUGAR.mySugar == 'undefined') ? 8 : 4, + rows = Math.ceil(legend["name"].length/cols); + table = ""; + var j = 0; + for(i=0;i ' + legend["name"][j]; + } + + table += ''; + j++; + } + table += ""; + } + + table += "
            "; + list.innerHTML = table; + + + //save canvas to image for pdf consumption + $jit.util.saveImageTest(chartId,jsonFilename,chartConfig["imageExportType"]); + } + } + + var callback = + { + success:handleSuccess, + failure:handleFailure, + argument: { foo:'foo', bar:''} + }; + + var request = YAHOO.util.Connect.asyncRequest('GET', jsonFilename + "?r=" + new Date().getTime(), callback); + + break; + + + case "funnelChart": + + var handleFailure = function(o){ + alert('fail'); + if(o.responseText !== undefined){ + alert('failed'); + } + } + var handleSuccess = function(o){ + + if(o.responseText !== undefined && o.responseText != "No Data"){ + var json = eval('('+o.responseText+')'); + + var properties = $jit.util.splat(json.properties)[0]; + + //init Funnel Chart + var funnelChart = new $jit.FunnelChart({ + //id of the visualization container + injectInto: chartId, + //whether to add animations + animate: false, + renderBackground: chartConfig['imageExportType'] == "jpg" ? true: false, + backgroundColor: 'rgb(255,255,255)', + colorStop1: 'rgba(255,255,255,.8)', + colorStop2: 'rgba(255,255,255,0)', + //orientation setting should not be changed + orientation: "vertical", + hoveredColor: false, + Title: { + text: properties['title'], + size: 16, + color: '#444444', + offset: 20 + }, + Subtitle: { + text: properties['subtitle'], + size: 11, + color: css["color"], + offset: 20 + }, + //segment separation + segmentOffset: 20, + //visualization offset + Margin: { + top:20, + left: 20, + right: 20, + bottom: 20 + }, + Events: { + enable: true, + onClick: function(node) { + if(!node || SUGAR.util.isTouchScreen()) return; + if(node.link == 'undefined' || node.link == '') return; + window.location.href=node.link; + } + }, + //labels offset position + labelOffset: 10, + //bars style + type: useGradients? chartConfig["funnelType"]+':gradient' : chartConfig["funnelType"], + //whether to show the aggregation of the values + showAggregates:true, + //whether to show the labels for the bars + showLabels:true, + //labels style + Label: { + type: labelType, //Native or HTML + size: 12, + family: css["font-family"], + color: css["color"], + colorAlt: "#ffffff" + }, + //add tooltips + Tips: { + enable: true, + onShow: function(tip, elem) { + if(elem.link != 'undefined' && elem.link != '') { + drillDown = (SUGAR.util.isTouchScreen()) ? "
            Click to drilldown" : "
            Click to drilldown"; + } else { + drillDown = ""; + } + + if(elem.valuelabel != 'undefined' && elem.valuelabel != undefined && elem.valuelabel != '') { + value = "elem.valuelabel"; + } else { + value = "elem.value"; + } + eval("tip.innerHTML = '' + elem."+chartConfig["tip"]+" + ': ' + "+value+" + ' - ' + elem.percentage + '%' + drillDown"); + } + } + }); + //load JSON data. + funnelChart.loadJSON(json); + //end + + /* + var list = $jit.id('id-list'), + button = $jit.id('update'), + orn = $jit.id('switch-orientation'); + //update json on click 'Update Data' + $jit.util.addEvent(button, 'click', function() { + var util = $jit.util; + if(util.hasClass(button, 'gray')) return; + util.removeClass(button, 'white'); + util.addClass(button, 'gray'); + barChart.updateJSON(json2); + }); + */ + //dynamically add legend to list + var list = $jit.id('legend'+chartId); + var legend = funnelChart.getLegend(), + cols = (typeof SUGAR == 'undefined' || typeof SUGAR.mySugar == 'undefined') ? 8 : 4, + rows = Math.ceil(legend["name"].length/cols); + table = ""; + var j = 0; + for(i=0;i ' + legend["name"][j]; + } + + table += ''; + j++; + } + table += ""; + } + + table += "
            "; + list.innerHTML = table; + + //save canvas to image for pdf consumption + $jit.util.saveImageTest(chartId,jsonFilename,chartConfig["imageExportType"]); + } + } + + var callback = + { + success:handleSuccess, + failure:handleFailure, + argument: { foo:'foo', bar:''} + }; + + var request = YAHOO.util.Connect.asyncRequest('GET', jsonFilename + "?r=" + new Date().getTime(), callback); + break; + + + + case "gaugeChart": + + var handleFailure = function(o){ + alert('fail'); + if(o.responseText !== undefined){ + alert('failed'); + } + } + var handleSuccess = function(o){ + + if(o.responseText !== undefined){ + var json = eval('('+o.responseText+')'); + var properties = $jit.util.splat(json.properties)[0]; + + //init Gauge Chart + var gaugeChart = new $jit.GaugeChart({ + //id of the visualization container + injectInto: chartId, + //whether to add animations + animate: false, + renderBackground: chartConfig['imageExportType'] == "jpg" ? true: false, + backgroundColor: 'rgb(255,255,255)', + colorStop1: 'rgba(255,255,255,.8)', + colorStop2: 'rgba(255,255,255,0)', + labelType: properties['labels'], + hoveredColor: false, + Title: { + text: properties['title'], + size: 16, + color: '#444444', + offset: 20 + }, + Subtitle: { + text: properties['subtitle'], + size: 11, + color: css["color"], + offset: 5 + }, + //offsets + offset: 20, + gaugeStyle: { + backgroundColor: '#aaaaaa', + borderColor: '#999999', + needleColor: 'rgba(255,0,0,.8)', + borderSize: 4, + positionFontSize: 24, + positionOffset: 2 + }, + //slice style + type: useGradients? chartConfig["gaugeType"]+':gradient' : chartConfig["gaugeType"], + //whether to show the labels for the slices + showLabels:true, + Events: { + enable: true, + onClick: function(node) { + if(!node || SUGAR.util.isTouchScreen()) return; + if(node.link == 'undefined' || node.link == '') return; + window.location.href=node.link; + } + }, + //label styling + Label: { + type: labelType, //Native or HTML + size: 12, + family: css["font-family"], + color: css["color"] + }, + //enable tips + Tips: { + enable: true, + onShow: function(tip, elem) { + if(elem.link != 'undefined' && elem.link != '') { + drillDown = (SUGAR.util.isTouchScreen()) ? "
            Click to drilldown" : "
            Click to drilldown"; + } else { + drillDown = ""; + } + if(elem.valuelabel != 'undefined' && elem.valuelabel != undefined && elem.valuelabel != '') { + value = "elem.valuelabel"; + } else { + value = "elem.value"; + } + eval("tip.innerHTML = '' + elem.label + ': ' + "+ value +" + drillDown"); + } + } + }); + //load JSON data. + gaugeChart.loadJSON(json); + + + var list = $jit.id('legend'+chartId); + var legend = gaugeChart.getLegend(), + cols = (typeof SUGAR == 'undefined' || typeof SUGAR.mySugar == 'undefined') ? 8 : 4, + rows = Math.ceil(legend["name"].length/cols); + table = ""; + var j = 1; + for(i=0;i ' + legend["name"][j]; + } + + table += ''; + j++; + } + table += ""; + } + + table += "
            "; + list.innerHTML = table; + + + //save canvas to image for pdf consumption + $jit.util.saveImageTest(chartId,jsonFilename,chartConfig["imageExportType"]); + } + } + + var callback = + { + success:handleSuccess, + failure:handleFailure, + argument: { foo:'foo', bar:''} + }; + + var request = YAHOO.util.Connect.asyncRequest('GET', jsonFilename + "?r=" + new Date().getTime(), callback); + + break; + + } + } \ No newline at end of file diff --git a/jssource/src_files/include/SugarDependentDropdown/javascript/SugarDependentDropdown.js b/jssource/src_files/include/SugarDependentDropdown/javascript/SugarDependentDropdown.js new file mode 100644 index 00000000..318ca52a --- /dev/null +++ b/jssource/src_files/include/SugarDependentDropdown/javascript/SugarDependentDropdown.js @@ -0,0 +1,305 @@ +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +SUGAR.dependentDropdown = { + /* + * Container for "action" metadata - allows DD to parse saved choices and apply them at display time + */ + currentAction : null, + /* + * Flag to turn on debug mode. + * Current debug output: + * SUGAR.dependentDropdown._stack - simple list of this class' called methods + */ + debugMode : false +} + +/** + * Handle drop-down dependencies + * @param object HTML form element object + */ +SUGAR.dependentDropdown.handleDependentDropdown = function(el) { + /** + * + * + * PROTOTYPE THIS METHOD TO CUSTOMIZE RESPONSES FOR YOUR DEPENDENT DROPDOWNS + * + * + * + */ + /** + if(SUGAR.dependentDropdown.debugMode) SUGAR.dependentDropdown.utils.debugStack('handleDependentDropdown'); + + /* + * el.id example: + * "criteriaGroup::0:::0:-:crit0id" + * [grouping from metadata]::[index]:::[elementIndex]:-:[assignedID from metadata] + * index is row-number + * elementIndex is the index of the current element in this row + var index = el.id.slice(el.id.indexOf("::") + 2, el.id.indexOf(":::")); + var elementRow = el.boxObject.parentBox; + var elementIndex = el.id.slice(el.id.indexOf(":::") + 3, el.id.indexOf(":-:")); + + elementIndex++; + var elementKey = "element" + elementIndex; + var focusElement = SUGAR.dependentDropdown.dropdowns[focusDD].elements[elementKey]; + + if(focusElement) { + if(focusElement.handlers) { + try { + focusElement = focusElement.handlers[el.value]; + } catch(e) { + if(SUGAR.dependentDropdown.dropdowns.debugMode) { + debugger; + } + } + } + SUGAR.dependentDropdown.generateElement(focusElement, elementRow, index, elementIndex); + } else { + } + */ +} + + + + + + +SUGAR.dependentDropdown.generateElement = function(focusElement, elementRow, index, elementIndex) { + if(SUGAR.dependentDropdown.debugMode) SUGAR.dependentDropdown.utils.debugStack('generateElement'); + + var tmp = null; + + if(focusElement) { + /* get sandbox to play in */ + var sandbox = SUGAR.dependentDropdown.utils.generateElementContainer(focusElement, elementRow, index, elementIndex); + + /* handle labels that appear 'left' or 'top' */ + if(focusElement.label) { + focusLabel = { + tag : 'span', + cls : 'routingLabel', + html : " " + focusElement.label + " " + } + + switch(focusElement.label_pos) { + case "top": + focusLabel.html = focusElement.label + "
            "; + break; + + case "bottom": + focusLabel.html = "
            " + focusElement.label; + break; + } + + if(focusElement.label_pos == 'left' || focusElement.label_pos == 'top') { + YAHOO.ext.DomHelper.append(sandbox, focusLabel); + } + } + + /********************************************************************** + * FUN PART BELOW + */ + switch(focusElement.type) { + case 'input': + /* + * focusElement.values can be lazy-loaded via JS call + */ + if(typeof(focusElement.values) == 'string') { + focusElement.values = eval(focusElement.values); + } + + /* Define the key-value that is to be used to pre-select a value in the dropdown */ + var preselect = SUGAR.dependentDropdown.utils.getPreselectKey(focusElement.name); + + if(preselect.match(/::/)) + preselect = ''; + + tmp = YAHOO.ext.DomHelper.append(sandbox, { + tag : 'input', + id : focusElement.grouping + "::" + index + ":::" + elementIndex + ":-:" + focusElement.id, + name : focusElement.grouping + "::" + index + "::" + focusElement.name, + cls : 'input', + onchange : focusElement.onchange, + value : preselect + }, true); + var newElement = tmp.dom; + break; + + + case 'select': + tmp = YAHOO.ext.DomHelper.append(sandbox, { + tag : 'select', + id : focusElement.grouping + "::" + index + ":::" + elementIndex + ":-:" + focusElement.id, + name : focusElement.grouping + "::" + index + "::" + focusElement.name, + cls : 'input', + onchange : focusElement.onchange + }, true); + var newElement = tmp.dom; + + /* + * focusElement.values can be lazy-loaded via JS call + */ + if(typeof(focusElement.values) == 'string') { + focusElement.values = eval(focusElement.values); + } + + /* Define the key-value that is to be used to pre-select a value in the dropdown */ + var preselect = SUGAR.dependentDropdown.utils.getPreselectKey(focusElement.name); + + // Loop through the values (passed or generated) and preselect as needed + var i = 0; + for(var key in focusElement.values) { + var selected = (preselect == key) ? true : false; + newElement.options[i] = new Option(focusElement.values[key], key, selected); + + // ie6/7 workaround + if(selected) { + newElement.options[i].selected = true; + } + i++; + } + break; + + case 'none': + break; + + case 'checkbox': + alert('implement checkbox pls'); + break; + case 'multiple': + alert('implement multiple pls'); + break; + + default: + if(SUGAR.dependentDropdown.dropdowns.debugMode) { + alert("Improper type defined: [ " + focusElement.type + "]"); + } + return; + break; + } + + /* handle label placement *after* or *below* the drop-down */ + if(focusElement.label) { + if(focusElement.label_pos == 'right' || focusElement.label_pos == 'bottom') { + YAHOO.ext.DomHelper.append(sandbox, focusLabel); + } + } + + /* trigger dependent dropdown action to cascade dependencies */ + try { + newElement.onchange(); + //eval(focusElement.onchange); "this" has no reference + } catch(e) { + if(SUGAR.dependentDropdown.dropdowns.debugMode) { + debugger; + } + } + + } else { + } +} + + + +/////////////////////////////////////////////////////////////////////////////// +//// UTILS +SUGAR.dependentDropdown.utils = { + /** + * creates a DIV container for a given element + * @param object focusElement Element in focus' metadata + * @param object elementRow Parent DIV container's DOM object + * @param int index Index of current elementRow + * @param int elementIndex Index of the element in focus relative to others in the definition + * @return obj Reference DOM object generated + */ + generateElementContainer : function(focusElement, elementRow, index, elementIndex) { + /* clear out existing element if exists */ + var oldElement = document.getElementById('elementContainer' + focusElement.grouping + "::" + index + ":::" + elementIndex); + + if(oldElement) { + SUGAR.dependentDropdown.utils.removeChildren(oldElement); + } + + /* create sandbox to ease removal */ + var tmp = YAHOO.ext.DomHelper.append(elementRow, { + tag : 'span', + id : 'elementContainer' + focusElement.grouping + "::" + index + ":::" + elementIndex + }, true); + + return tmp.dom; + }, + /** + * Finds the preselect key from the User's saved (loaded into memory) metadata + * @param string elementName Name of form element - functions as key to user's saved value + */ + getPreselectKey : function(elementName) { + try { + if(SUGAR.dependentDropdown.currentAction.action[elementName]) { + return SUGAR.dependentDropdown.currentAction.action[elementName]; + } else { + return ''; + } + } catch(e) { + if(SUGAR.dependentDropdown.dropdowns.debugMode) { + //debugger; + } + return ''; + } + }, + + /** + * provides a list of methods called in order when debugging + * @param object + */ + debugStack : function(func) { + if(!SUGAR.dependentDropdown._stack) { + SUGAR.dependentDropdown._stack = new Array(); + } + + SUGAR.dependentDropdown._stack.push(func); + }, + + /** + * Removes all child nodes from the passed DOM element + */ + removeChildren : function(el) { + for(i=el.childNodes.length - 1; i >= 0; i--) { + if(el.childNodes[i]) { + el.removeChild(el.childNodes[i]); + } + } + } +} diff --git a/jssource/src_files/include/SugarEmailAddress/SugarEmailAddress.js b/jssource/src_files/include/SugarEmailAddress/SugarEmailAddress.js new file mode 100644 index 00000000..46418a4b --- /dev/null +++ b/jssource/src_files/include/SugarEmailAddress/SugarEmailAddress.js @@ -0,0 +1,490 @@ +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +(function() { + //Do not double define + if (SUGAR.EmailAddressWidget) return; + + var Dom = YAHOO.util.Dom; + + SUGAR.EmailAddressWidget = function(module) { + if (!SUGAR.EmailAddressWidget.count[module]) SUGAR.EmailAddressWidget.count[module] = 0; + this.count = SUGAR.EmailAddressWidget.count[module]; + SUGAR.EmailAddressWidget.count[module]++; + this.module = module; + this.id = this.module + this.count; + if (document.getElementById(module+'_email_widget_id')) + document.getElementById(module+'_email_widget_id').value = this.id; + SUGAR.EmailAddressWidget.instances[this.id] = this; + } + + SUGAR.EmailAddressWidget.instances = {}; + SUGAR.EmailAddressWidget.count = {}; + + SUGAR.EmailAddressWidget.prototype = { + emailTemplate : '' + + '' + + ' ' + + '' + + '' + + '' + + '' + + '', + + numberEmailAddresses : 0, + replyToFlagObject : new Object(), + verifying : false, + enterPressed : false, + tabPressed : false, + emailView:"", + emailIsRequired: false, + tabIndex: -1, + + prefillEmailAddresses: function(tableId, o){ + for (i = 0; i < o.length; i++) { + o[i].email_address = o[i].email_address.replace(''', "'"); + this.addEmailAddress(tableId, o[i].email_address, o[i].primary_address, o[i].reply_to_address, o[i].opt_out, o[i].invalid_email); + } + }, + + retrieveEmailAddress: function (event) { + var callbackFunction = function success(data) { + var vals = YAHOO.lang.JSON.parse(data.responseText); + var target = vals.target; + event = this.getEvent(event); + + if(vals.email) { + var email = vals.email; + if(email != '' && /\d+$/.test(target)) { + var matches = target.match(/\d+$/); + var targetNumber = matches[0]; + var optOutEl = Dom.get(this.id + 'emailAddressOptOutFlag' + targetNumber); + if(optOutEl) { + optOutEl.checked = email['opt_out'] == 1 ? true : false; + } + var invalidEl = Dom.get(this.id + 'emailAddressInvalidFlag' + targetNumber); + if(invalidEl) { + invalidEl.checked = email['invalid_email'] == 1 ? true : false; + } + } + } + //Set the verified flag to true + var index = /[a-z]*\d?emailAddress(\d+)/i.exec(target)[1]; + + var verifyElementFlag = Dom.get(this.id + 'emailAddressVerifiedFlag' + index); + + if(verifyElementFlag.parentNode.childNodes.length > 1) { + verifyElementFlag.parentNode.removeChild(verifyElementFlag.parentNode.lastChild); + } + + var verifiedTextNode = document.createElement('span'); + verifiedTextNode.innerHTML = ''; + verifyElementFlag.parentNode.appendChild(verifiedTextNode); + verifyElementFlag.value = "true"; + this.verifyElementValue = Dom.get(this.id +'emailAddressVerifiedValue' + index); + this.verifyElementValue.value = Dom.get(this.id +'emailAddress' + index).value; + this.verifying = false; + + // If Enter key or Save button was pressed then we proceed to attempt a form submission + var savePressed = false; + if(event) { + var elm = document.activeElement || event.explicitOriginalTarget; + if(typeof elm.type != 'undefined' && /submit|button/.test(elm.type.toLowerCase())) { + savePressed = true; + } + } + + if(savePressed || this.enterPressed) { + setTimeout("SUGAR.EmailAddressWidget.instances." + this.id + ".forceSubmit()", 2100); + } else if(this.tabPressed) { + Dom.get(this.id + 'emailAddressPrimaryFlag' + index).focus(); + } + } + + var event = this.getEvent(event); + var targetEl = this.getEventElement(event); + var index = /[a-z]*\d?emailAddress(\d+)/i.exec(targetEl.id)[1]; + var verifyElementFlag = Dom.get(this.id + 'emailAddressVerifiedFlag' + index); + this.verifyElementValue = Dom.get(this.id + 'emailAddressVerifiedValue' + index); + verifyElementFlag.value = (trim(targetEl.value) == '' || targetEl.value == this.verifyElementValue.value) ? "true" : "false" + + //Remove the span element if it is present + if(verifyElementFlag.parentNode.childNodes.length > 1) { + verifyElementFlag.parentNode.removeChild(verifyElementFlag.parentNode.lastChild); + } + + if(/emailAddress\d+$/.test(targetEl.id) && isValidEmail(targetEl.value) && !this.verifying && verifyElementFlag.value == "false") { + verifiedTextNode = document.createElement('span'); + verifyElementFlag.parentNode.appendChild(verifiedTextNode); + verifiedTextNode.innerHTML = SUGAR.language.get('app_strings', 'LBL_VERIFY_EMAIL_ADDRESS'); + this.verifying = true; + var cObj = YAHOO.util.Connect.asyncRequest( + 'GET', + 'index.php?module=Contacts&action=RetrieveEmail&target=' + targetEl.id + '&email=' + targetEl.value, + {success: callbackFunction, failure: callbackFunction, scope: this} + ); + } + }, + + handleKeyDown: function (event) { + var e = this.getEvent(event); + var eL = this.getEventElement(e); + if ((kc = e["keyCode"])) { + this.enterPressed = (kc == 13) ? true : false; + this.tabPressed = (kc == 9) ? true : false; + + if(this.enterPressed || this.tabPressed) { + this.retrieveEmailAddress(e); + if (this.enterPressed); + this.freezeEvent(e); + } + } + }, //handleKeyDown() + + getEvent :function (event) { + return (event ? event : window.event); + },//getEvent + + getEventElement : function (e) { + return (e.srcElement ? e.srcElement: (e.target ? e.target : e.currentTarget)); + },//getEventElement + + freezeEvent : function (e) { + if (e.preventDefault) e.preventDefault(); + e.returnValue = false; + e.cancelBubble = true; + if (e.stopPropagation) e.stopPropagation(); + return false; + },//freezeEvent + + addEmailAddress : function (tableId, address, primaryFlag, replyToFlag, optOutFlag, invalidFlag) { + if (this.addInProgress) + return; + this.addInProgress = true; + if (!address) + address = ""; + var insertInto = Dom.get(tableId); + var parentObj = insertInto.parentNode; + var newContent = document.createElement("input"); + var nav = new String(navigator.appVersion); + var newContentPrimaryFlag; + if(SUGAR.isIE){ + newContentPrimaryFlag = document.createElement(""); + }else{ + newContentPrimaryFlag = document.createElement("input"); + } + var newContentReplyToFlag = document.createElement("input"); + var newContentOptOutFlag = document.createElement("input"); + var newContentInvalidFlag = document.createElement("input"); + var newContentVerifiedFlag = document.createElement("input"); + var newContentVerifiedValue = document.createElement("input"); + var removeButton = document.createElement("img"); + var tbody = document.createElement("tbody"); + var tr = document.createElement("tr"); + var td1 = document.createElement("td"); + var td2 = document.createElement("td"); + var td3 = document.createElement("td"); + var td4 = document.createElement("td"); + var td5 = document.createElement("td"); + var td6 = document.createElement("td"); + var td7 = document.createElement("td"); + var td8 = document.createElement("td"); + + // set input field attributes + newContent.setAttribute("type", "text"); + newContent.setAttribute("name", this.id + "emailAddress" + this.numberEmailAddresses); + newContent.setAttribute("id", this.id + "emailAddress" + this.numberEmailAddresses); + newContent.setAttribute("tabindex", this.tabIndex); + newContent.setAttribute("size", "30"); + + if(address != '') { + newContent.setAttribute("value", address); + } + + // remove button + removeButton.setAttribute("id", this.id + "removeButton" + this.numberEmailAddresses); + removeButton.setAttribute("class", "id-ff-remove"); + removeButton.setAttribute("name", this.numberEmailAddresses); + removeButton.eaw = this; + removeButton.setAttribute("src", "index.php?entryPoint=getImage&themeName="+SUGAR.themes.theme_name+"&imageName=id-ff-remove.png"); + removeButton.onclick = function(){this.eaw.removeEmailAddress(this.name);}; + + // set primary flag + newContentPrimaryFlag.setAttribute("type", "radio"); + newContentPrimaryFlag.setAttribute("name", this.id + "emailAddressPrimaryFlag"); + newContentPrimaryFlag.setAttribute("id", this.id + "emailAddressPrimaryFlag" + this.numberEmailAddresses); + newContentPrimaryFlag.setAttribute("value", this.id + "emailAddress" + this.numberEmailAddresses); + newContentPrimaryFlag.setAttribute("enabled", "true"); + + // set reply-to flag + newContentReplyToFlag.setAttribute("type", "radio"); + newContentReplyToFlag.setAttribute("name", this.id + "emailAddressReplyToFlag"); + newContentReplyToFlag.setAttribute("id", this.id + "emailAddressReplyToFlag" + this.numberEmailAddresses); + newContentReplyToFlag.setAttribute("value", this.id + "emailAddress" + this.numberEmailAddresses); + newContentReplyToFlag.setAttribute("enabled", "true"); + newContentReplyToFlag.eaw = this; + newContentReplyToFlag['onclick']= function() { + var form = document.forms[this.eaw.emailView]; + if (!form) { + form = document.forms['editContactForm']; + } + var nav = new String(navigator.appVersion); + + if(nav.match(/MSIE/gim)) { + for(i=0; iinput into the DOM + parentObj.insertBefore(Dom.get('targetBody'), insertInto); + + // CL Fix for 17651 (added OR condition check to see if this is the first email added) + if(primaryFlag == '1' || (this.numberEmailAddresses == 0)) { + newContentPrimaryFlag.setAttribute("checked", 'true'); + } + + if(replyToFlag == '1') { + newContentReplyToFlag.setAttribute("checked", "true"); + } + + if (replyToFlag == '1') { + this.replyToFlagObject[newContentReplyToFlag.id] = true; + } else { + this.replyToFlagObject[newContentReplyToFlag.id] = false; + } + + if(optOutFlag == '1') { + newContentOptOutFlag.setAttribute("checked", 'true'); + } + + if(invalidFlag == '1') { + newContentInvalidFlag.setAttribute("checked", "true"); + } + newContent.eaw = this; + newContent.onblur = function(e){this.eaw.retrieveEmailAddress(e)}; + newContent.onkeydown = function(e){this.eaw.handleKeyDown(e)}; + + // Add validation to field + addToValidate(this.emailView, this.id + 'emailAddress' + this.numberEmailAddresses, 'email', this.emailIsRequired, SUGAR.language.get('app_strings', 'LBL_EMAIL_ADDRESS_BOOK_EMAIL_ADDR')); + this.numberEmailAddresses++; + this.addInProgress = false; + }, //addEmailAddress + + removeEmailAddress : function(index) { + removeFromValidate(this.emailView, this.id + 'emailAddress' + index); + var oNodeToRemove = Dom.get(this.id + 'emailAddressRow' + index); + oNodeToRemove.parentNode.removeChild(oNodeToRemove); + + var removedIndex = parseInt(index); + //If we are not deleting the last email address, we need to shift the numbering to fill the gap + if(this.numberEmailAddresses != removedIndex) { + for(var x = removedIndex + 1; x < this.numberEmailAddresses; x++) { + Dom.get(this.id + 'emailAddress' + x).setAttribute("name", this.id +"emailAddress" + (x-1)); + Dom.get(this.id + 'emailAddress' + x).setAttribute("id", this.id +"emailAddress" + (x-1)); + + if(Dom.get(this.id + 'emailAddressInvalidFlag' + x)) { + Dom.get(this.id + 'emailAddressInvalidFlag' + x).setAttribute("id", this.id + "emailAddressInvalidFlag" + (x-1)); + } + + if(Dom.get(this.id + 'emailAddressOptOutFlag' + x)){ + Dom.get(this.id + 'emailAddressOptOutFlag' + x).setAttribute("id", this.id + "emailAddressOptOutFlag" + (x-1)); + } + + if(Dom.get(this.id + 'emailAddressPrimaryFlag' + x)) { + Dom.get(this.id + 'emailAddressPrimaryFlag' + x).setAttribute("id", this.id + "emailAddressPrimaryFlag" + (x-1)); + } + + Dom.get(this.id + 'emailAddressVerifiedValue' + x).setAttribute("id", this.id + "emailAddressVerifiedValue" + (x-1)); + Dom.get(this.id + 'emailAddressVerifiedFlag' + x).setAttribute("id", this.id + "emailAddressVerifiedFlag" + (x-1)); + + var rButton = Dom.get(this.id + 'removeButton' + x); + rButton.setAttribute("name", (x-1)); + rButton.setAttribute("id", this.id + "removeButton" + (x-1)); + Dom.get(this.id + 'emailAddressRow' + x).setAttribute("id", this.id + 'emailAddressRow' + (x-1)); + } + } + + this.numberEmailAddresses--; + + + // CL Fix for 17651 + if(this.numberEmailAddresses == 0) { + return; + } + + var primaryFound = false; + for(x=0; x < this.numberEmailAddresses; x++) { + if(Dom.get(this.id + 'emailAddressPrimaryFlag' + x).checked) { + primaryFound = true; + } + } + + if(!primaryFound) { + Dom.get(this.id + 'emailAddressPrimaryFlag0').checked = true; + Dom.get(this.id + 'emailAddressPrimaryFlag0').value = this.id + 'emailAddress0'; + } + }, + + toggleCheckbox : function (el) + { + var form = document.forms[this.emailView]; + if (!form) { + form = document.forms['editContactForm']; + } + + if(SUGAR.isIE) { + for(i=0; i
  • '; + + // append the list_view as the third row of the outside table + this.parentNode.innerHTML += html; + + var div = document.createElement('div'); + div.setAttribute('id','list_div_win'); + div.style.overflow = 'auto'; + div.style.width = '100%'; + div.style.height= '125px'; + div.style.display = 'none'; + this.parentNode.appendChild(div); + + this.list_view = new SugarWidgetListView(); + this.list_view.load(div); +} + +////////////////////////////////////////////////// +// class: SugarWidgetScheduler +// widget to display the meeting scheduler +// +////////////////////////////////////////////////// + +SugarClass.inherit("SugarWidgetScheduler","SugarClass"); + +function SugarWidgetScheduler() { + this.init(); +} + +SugarWidgetScheduler.prototype.init = function() { + //var row = new SugarWidgetScheduleAttendees(); + //row.load(this); +} + +SugarWidgetScheduler.prototype.load = function(parentNode) { + this.parentNode = parentNode; + this.display(); +} + +SugarWidgetScheduler.fill_invitees = function(form) { + for(var i=0;i'; + html += ''; + html += ''; + html += ''; + html += ''; + html += ''; + + for(var i=0;i < (this.timeslots.length/this.segments); i++) { + var hours = this.timeslots[i*this.segments].date_obj.getHours(); + var am_pm = ''; + + if(time_reg_format.indexOf('A') >= 0 || time_reg_format.indexOf('a') >= 0) { + am_pm = "AM"; + + if(hours > 12) { + am_pm = "PM"; + hours -= 12; + } + if(hours == 12) { + am_pm = "PM"; + } + if(hours == 0) { + hours = 12; + am_pm = "AM"; + } + if(time_reg_format.indexOf('a') >= 0) { + am_pm = am_pm.toLowerCase(); + } + if(hours != 0 && hours != 12 && i != 0) { + am_pm = ""; + } + + } + + var form_hours = hours+time_separator+"00"; + html += ''; + } + + html += ''; + html += ''; + html += '

    '+ top_date +'

     '+form_hours+am_pm+' 
    '; + if ( this.parentNode.childNodes.length < 1 ) + this.parentNode.innerHTML += '
    ' + html + '
    '; + else + this.parentNode.childNodes[0].innerHTML = html; + + var thetable = "schedulerTable"; + + if(typeof (GLOBAL_REGISTRY) == 'undefined') { + return; + } + + //set the current user (as event-coordinator) so that they can be added to invitee list + //only IF the first removed flag has not been set AND this is a new record + if((typeof (GLOBAL_REGISTRY.focus.users_arr) == 'undefined' || GLOBAL_REGISTRY.focus.users_arr.length == 0) + && document.EditView.record.value =='' && typeof(GLOBAL_REGISTRY.FIRST_REMOVE)=='undefined') { + GLOBAL_REGISTRY.focus.users_arr = [ GLOBAL_REGISTRY.current_user ]; + } + + if(typeof GLOBAL_REGISTRY.focus.users_arr_hash == 'undefined') { + GLOBAL_REGISTRY.focus.users_arr_hash = new Object(); + } + + // append attendee rows + for(var i=0;i < GLOBAL_REGISTRY.focus.users_arr.length;i++) { + var row = new SugarWidgetScheduleRow(this.timeslots); + row.focus_bean = GLOBAL_REGISTRY.focus.users_arr[i]; + GLOBAL_REGISTRY.focus.users_arr_hash[ GLOBAL_REGISTRY.focus.users_arr[i]['fields']['id']] = GLOBAL_REGISTRY.focus.users_arr[i]; + row.load(thetable); + } +} + +SugarWidgetSchedulerAttendees.form_add_attendee = function (list_row) { + if(typeof (GLOBAL_REGISTRY.result_list[list_row]) != 'undefined' && typeof(GLOBAL_REGISTRY.focus.users_arr_hash[ GLOBAL_REGISTRY.result_list[list_row].fields.id]) == 'undefined') { + GLOBAL_REGISTRY.focus.users_arr[ GLOBAL_REGISTRY.focus.users_arr.length ] = GLOBAL_REGISTRY.result_list[list_row]; + } + GLOBAL_REGISTRY.scheduler_attendees_obj.display(); +} + + +////////////////////////////////////////////////// +// class: SugarWidgetScheduleRow +// widget to display each row in the scheduler +// +////////////////////////////////////////////////// +SugarClass.inherit("SugarWidgetScheduleRow","SugarClass"); + +function SugarWidgetScheduleRow(timeslots) { + this.init(timeslots); +} + +SugarWidgetScheduleRow.prototype.init = function(timeslots) { + this.timeslots = timeslots; +} + +SugarWidgetScheduleRow.prototype.load = function (thetableid) { + this.thetableid = thetableid; + var self = this; + + vcalClient = new SugarVCalClient(); + if(typeof (GLOBAL_REGISTRY['freebusy_adjusted']) == 'undefined' || typeof (GLOBAL_REGISTRY['freebusy_adjusted'][this.focus_bean.fields.id]) == 'undefined') { + global_request_registry[req_count] = [this,'display']; + vcalClient.load(this.focus_bean.fields.id,req_count); + req_count++; + } else { + this.display(); + } +} + +SugarWidgetScheduleRow.prototype.display = function() { + var self = this; + var tr; + this.thetable = document.getElementById(this.thetableid); + + if(typeof (this.element) != 'undefined') { + if (this.element.parentNode != null) + this.thetable.deleteRow(this.element.rowIndex); + + tr = document.createElement('tr'); + this.thetable.appendChild(tr); + } else { + tr = this.thetable.insertRow(this.thetable.rows.length); + } + tr.className = "schedulerAttendeeRow"; + + td = document.createElement('td'); + tr.appendChild(td); + //insertCell(tr.cells.length); + + // icon + full name + td.scope = 'row'; + var img = ' '; + td.innerHTML = img; + + td.innerHTML = td.innerHTML; + + if (self.focus_bean.fields.full_name) + td.innerHTML += ' ' + self.focus_bean.fields.full_name; + else + td.innerHTML += ' ' + self.focus_bean.fields.name; + + // add freebusy tds here: + this.add_freebusy_nodes(tr); + + // delete button + var td = document.createElement('td'); + tr.appendChild(td); + //var td = tr.insertCell(tr.cells.length); + td.className = 'schedulerAttendeeDeleteCell'; + td.noWrap = true; + //CCL - Remove check to disallow removal of assigned user or current user + //if ( GLOBAL_REGISTRY.focus.fields.assigned_user_id != self.focus_bean.fields.id && GLOBAL_REGISTRY.current_user.fields.id != self.focus_bean.fields.id) { + td.innerHTML = ' '+ GLOBAL_REGISTRY['meeting_strings']['LBL_REMOVE'] +' '+ GLOBAL_REGISTRY['meeting_strings']['LBL_REMOVE'] +''; + //} + this.element = tr; + this.element_index = this.thetable.rows.length - 1; +} + +SugarWidgetScheduleRow.deleteRow = function(bean_id) { + // can't delete organizer + /* + if(GLOBAL_REGISTRY.focus.users_arr.length == 1 || GLOBAL_REGISTRY.focus.fields.assigned_user_id == bean_id) { + return; + } + */ + for(var i=0;is for freebusy display within a row +SugarWidgetScheduleRow.prototype.add_freebusy_nodes = function(tr,attendee) { + var hours = 9; + var segments = 4; + var html = ''; + var is_loaded = false; + + if(typeof GLOBAL_REGISTRY['freebusy_adjusted'] != 'undefined' && typeof GLOBAL_REGISTRY['freebusy_adjusted'][this.focus_bean.fields.id] != 'undefined') { + is_loaded = true; + } + + for(var i=0;i < this.timeslots.length; i++) { + var td = document.createElement('td'); + tr.appendChild(td); + //var td = tr.insertCell(tr.cells.length); + td.innerHTML = ' '; + if(typeof(this.timeslots[i]['is_start']) != 'undefined') { + td.className = 'schedulerSlotCellStartTime'; + } + if(typeof(this.timeslots[i]['is_end']) != 'undefined') { + td.className = 'schedulerSlotCellEndTime'; + } + + if(is_loaded) { + // iftheres a freebusy stack in this slice + if( typeof(GLOBAL_REGISTRY['freebusy_adjusted'][this.focus_bean.fields.id][this.timeslots[i].hash]) != 'undefined') { + td.style.backgroundColor="#4D5EAA"; + + if(td.className == 'schedulerSlotCellStartTime') { + fb_limit = 1; + if(typeof(GLOBAL_REGISTRY.focus.orig_users_arr_hash) != 'undefined' && typeof(GLOBAL_REGISTRY.focus.orig_users_arr_hash[this.focus_bean.fields.id]) != 'undefined') { + fb_limit = 2; + } + + if( GLOBAL_REGISTRY['freebusy_adjusted'][this.focus_bean.fields.id][this.timeslots[i].hash] >= fb_limit) { + td.style.backgroundColor="#AA4D4D"; + } else { + td.style.backgroundColor="#4D5EAA"; + } + } + } + } + } +} \ No newline at end of file diff --git a/jssource/src_files/modules/MergeRecords/Merge.js b/jssource/src_files/modules/MergeRecords/Merge.js new file mode 100644 index 00000000..dad3b192 --- /dev/null +++ b/jssource/src_files/modules/MergeRecords/Merge.js @@ -0,0 +1,404 @@ +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + + + +var lbl_remove = SUGAR.language.get('app_strings', 'LBL_REMOVE'); + +function remove_filter(spanfieldid) { + var selspan = document.getElementById(spanfieldid); + //hide the span + selspan.setAttribute("style","visibility:hidden"); + selspan.innerHTML='';//' ' + + //and id to avail list. + var ops=object_refs['field_avail_list'].options; + var newoption = new Option(selspan.getAttribute("Value"),selspan.getAttribute("ValueId"),false,true); + ops.add(newoption); +} +function ajax_fetch_sync(url,post_data) +{ + global_xmlhttp = getXMLHTTPinstance(); + + var method = 'GET'; + if ( typeof(post_data) != 'undefined' ) + { + method = 'POST'; + } + + try + { + global_xmlhttp.open(method, url,false); + } + catch(error) + { + alert('message:'+error.message+":url:"+url); + } + + if ( method == 'POST') + { + global_xmlhttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); + } + + global_xmlhttp.send(post_data); + var ajax_response = {"responseText":global_xmlhttp.responseText,"responseXML":global_xmlhttp.responseXML}; + + return ajax_response; +} + +//---------------------------------------------------- +//---------------------------------------------------- +//---------------------------------------------------- +function get_fields_to_dedup(parent_mod) +{ + var rel_map_div_obj = document.getElementById('rel_map'); + + if(parent_mod != '') + { + var request_id = 1; + var url = site_url + '/index.php?to_pdf=1&sugar_body_only=1&inline=1&parent_module=' + parent_mod + '&module=MigrationMappings&action=GetRelationshipsToMap'; + var ajax_return_obj = ajax_fetch_sync(url); + + try { eval("var responseObj =" + ajax_return_obj['responseText']); } + catch(e) { alert(ajax_return_obj['responseText']); } + + build_avail_rels_array(responseObj); + + rel_map_div_obj.innerHTML = responseObj['html_content']; + } + else + { + rel_map_div_obj.innerHTML = ''; + } + + return true; +} + +function get_dedup_fields() +{ + var parent_div = document.getElementById('filter_def'); + var node; + var spannode; + var value; + var valueid; + var style; + document.DedupSetup.dedup_fields.value=''; + for (node in parent_div.childNodes) { + spannode=parent_div.childNodes[node]; + if (spannode.tagName=='SPAN') { + value= spannode.getAttribute('value'); + valueid=spannode.getAttribute('valueid'); + style=spannode.getAttribute('style'); + if (typeof(style) == 'undefined' || style==null || style=='' || style.lastIndexOf('hidden') == -1 ) { + if (document.DedupSetup.dedup_fields.value != '') { + document.DedupSetup.dedup_fields.value=document.DedupSetup.dedup_fields.value + '#'; + } + document.DedupSetup.dedup_fields.value = document.DedupSetup.dedup_fields.value + valueid; + } + } + } + + //var selected_fields_obj = document.getElementById('field_include_list[]'); + + //for(i=0; i < selected_fields_obj.length; i++) + //{ + // document.DedupSetup.dedup_fields.value = document.DedupSetup.dedup_fields.value + selected_fields_obj.options[i].value; + // if(i != (selected_fields_obj.length - 1)) { document.DedupSetup.dedup_fields.value += '#'; } + //} + +// document.DedupSetup.submit(); +} + +//------------------------------------------------------------------- +//------------------------------------------------------------------- +//------------------------------------------------------------------- +//------------------------------------------------------------------- +//------------------------------------------------------------------- +//------------------------------------------------------------------- +var object_refs = new Object(); +object_refs['field_include_list'] = document.DedupSetup['field_include_list']; +object_refs['field_avail_list'] = document.DedupSetup['field_avail_list']; + +function setselected(included_name,avail_name) +{ + var included_columns_ref = object_refs[included_name]; + var avail_columns_ref = object_refs[avail_name]; + + var included_td = document.getElementById(included_name+'_td'); + var avail_td = document.getElementById(avail_name+'_td'); + + var selected_avail = new Array(); + var notselected_avail = new Array(); + var notselected_include = new Array(); + + for (i=0; i < avail_columns_ref.options.length; i++) + { + if (avail_columns_ref.options[i].selected == true) + { + selected_avail[selected_avail.length] = {text:avail_columns_ref.options[i].text, value:avail_columns_ref.options[i].value}; + } + else + { + notselected_avail[notselected_avail.length] = {text:avail_columns_ref.options[i].text, value:avail_columns_ref.options[i].value}; + } + + } + + var right_select_html_info = new Object(); + var right_options = new Array(); + var right_select = new Object(); + + right_select['name'] = avail_name+ '[]'; + right_select['id'] = avail_name; + right_select['multiple'] = 'true'; + right_select['size'] = '10'; + + for (i=0;i < notselected_avail.length;i++) + { + right_options[right_options.length] = notselected_avail[i]; + } + + right_select_html_info['options'] = right_options; + right_select_html_info['select'] = right_select; + + var right_html = buildSelectHTML(right_select_html_info); + + avail_td.innerHTML = right_html; + object_refs[avail_name] = avail_td.getElementsByTagName('select')[0]; + + ////////////////////////////// + for(p=0; p < selected_avail.length; p++) + { + addFieldRow(selected_avail[p].value, selected_avail[p].text) + } + /////////////////////////// + +} + + +function up(name) { + var td = document.getElementById(name+'_td'); + var obj = td.getElementsByTagName('select')[0]; + obj = (typeof obj == "string") ? document.getElementById(obj) : obj; + if (obj.tagName.toLowerCase() != "select" && obj.length < 2) + return false; + var sel = new Array(); + + for (i=0; i-1; i--) { + if (obj[i].selected == true) { + sel[sel.length] = i; + } + } + for (i in sel) { + if (sel[i] != obj.length-1 && !obj[sel[i]+1].selected) { + var tmp = new Array(obj[sel[i]+1].text, obj[sel[i]+1].value); + obj[sel[i]+1].text = obj[sel[i]].text; + obj[sel[i]+1].value = obj[sel[i]].value; + obj[sel[i]].text = tmp[0]; + obj[sel[i]].value = tmp[1]; + obj[sel[i]+1].selected = true; + obj[sel[i]].selected = false; + } + } +} + +function buildSelectHTML(info) +{ + var text; + text = "
    "; + } + text += "
    "; + return text; +} + +////////////////////////////////////////////// +var fieldCount = 0; +function addFieldRow(colName, colLabel) { + var tableId = 'search_type'; + var rowIdName = 'field'; + + var fieldArrayCount; + var optionVal; + var optionDispVal; + var optionsIndex = 0; + + fieldCount = fieldCount + 1; + document.DedupSetup.num_fields.value = fieldCount; + + var selElement = document.createElement("select"); + var selectName = colName + "SearchType"; + selElement.setAttribute("name", selectName); + + var i=0; + for (theoption in operator_options) { + selElement.options[i] = new Option(operator_options[theoption],theoption, false, false); + i++; + } + + var aElement = document.createElement("a"); + aElement.setAttribute("href","javascript:remove_filter('filter_" + colName + "')"); + aElement.setAttribute("class","listViewTdToolsS1"); + + var imgElement = document.createElement("img"); + imgElement.setAttribute("src", delete_inline_image); + imgElement.setAttribute("align","absmiddle"); + imgElement.setAttribute("alt",lbl_remove); + imgElement.setAttribute("border","0"); + imgElement.setAttribute("height","12"); + imgElement.setAttribute("width","12"); + + aElement.appendChild(imgElement); + aElement.appendChild(document.createTextNode(" ")); + + var div = document.getElementById('filter_def'); + var span1 = document.getElementById('filter_'+colName); + if (span1 == null || span1=='' || typeof(span1)=='undefined') { + span1=document.createElement("span"); + } else { + span1.setAttribute("style","visibility:visible"); + } + + span1.setAttribute("id",'filter_'+colName); + span1.setAttribute("Value",colLabel); + span1.setAttribute("ValueId",colName); + + //table as a child of span element. + //table with only row only. + var table = document.createElement("table"); + //usage or insertRow is required by IE, ironically this call + //produces bad UI when using IE on mac. + var row = table.insertRow(table.rows.length ); + table.setAttribute("width","100%"); + table.setAttribute("border","0"); + table.setAttribute("cellpadding","0"); + + var td1= document.createElement("td"); + td1.setAttribute("width","2%"); + + td1.appendChild(aElement); + row.appendChild(td1) + + var td2= document.createElement("td"); + td2.setAttribute("width","20%"); + td2.appendChild(document.createTextNode(colLabel + ': ')); + row.appendChild(td2) + + var td3= document.createElement("td"); + td3.setAttribute("width","10%"); + td3.appendChild(selElement); + row.appendChild(td3); + + var coldata; + eval("coldata=bean_data."+ colName+ ";"); + + var edit=document.createElement("input"); + edit.setAttribute("type","text"); + edit.setAttribute("name",colName + 'SearchField'); + edit.setAttribute("id",colName + 'SearchField'); + edit.setAttribute("value",coldata); + + + var td5= document.createElement("td"); + td5.setAttribute("width","68%"); + td5.appendChild(edit); + row.appendChild(td5); + + + //table.appendChild(row); + span1.appendChild(table); + div.appendChild(span1); +} \ No newline at end of file diff --git a/jssource/src_files/modules/Project/Project.js b/jssource/src_files/modules/Project/Project.js new file mode 100644 index 00000000..b586f1c4 --- /dev/null +++ b/jssource/src_files/modules/Project/Project.js @@ -0,0 +1,97 @@ +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + + + +function prep_edit(the_form) +{ + the_form.return_module.value='Project'; + the_form.return_action.value='DetailView'; + the_form.return_id.value='{id}'; + the_form.action.value='EditView'; + the_form.sugar_body_only.value='0'; +} + +function prep_edit_project_tasks(the_form) +{ + the_form.return_module.value='Project'; + the_form.return_action.value='DetailView'; + the_form.return_id.value='{id}'; + the_form.action.value='EditGridView'; + the_form.sugar_body_only.value='0'; +} + +function prep_duplicate(the_form) +{ + the_form.return_module.value='Project'; + the_form.return_action.value='index'; + the_form.isDuplicate.value=true; + the_form.action.value='EditView'; + the_form.sugar_body_only.value='0'; +} + +function prep_delete(the_form) +{ + the_form.return_module.value='Project'; + the_form.return_action.value='ListView'; + the_form.action.value='Delete'; + the_form.sugar_body_only.value='0'; +} + +function prep_save_as_template(the_form) +{ + the_form.return_module.value='Project'; + the_form.return_action.value='DetailView'; + the_form.return_id.value='{id}'; + the_form.action.value='Convert'; + the_form.sugar_body_only.value='0'; +} +function prep_save_as_project(the_form) +{ + the_form.return_module.value='Project'; + the_form.return_action.value='ProjectTemplatesDetailView'; + the_form.return_id.value='{id}'; + the_form.action.value='Convert'; +} + +function prep_export_to_project(the_form) +{ + the_form.return_module.value='Project'; + the_form.return_action.value='DetailView'; + the_form.return_id.value='{id}'; + the_form.action.value='Export'; + the_form.sugar_body_only.value='1'; +} diff --git a/jssource/src_files/modules/ProjectTask/ProjectTask.js b/jssource/src_files/modules/ProjectTask/ProjectTask.js new file mode 100644 index 00000000..c84bb524 --- /dev/null +++ b/jssource/src_files/modules/ProjectTask/ProjectTask.js @@ -0,0 +1,66 @@ +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + + + + +function update_status(percent_complete){ + if (percent_complete == '0'){ + document.getElementById('status').value = 'Not Started'; + } + else if (percent_complete == '100'){ + document.getElementById('status').value = 'Completed'; + } + else if (isNaN(percent_complete) || (percent_complete < 0 || percent_complete > 100)){ + document.getElementById('percent_complete').value = ''; + } + else{ + document.getElementById('status').value = 'In Progress'; + } +} + +function update_percent_complete(status){ + if (status == 'In Progress'){ + percent_value = '50'; + } + else if (status == 'Completed'){ + percent_value = '100'; + } + else{ + percent_value = '0'; + } + document.getElementById('percent_complete').value = percent_value; +} \ No newline at end of file diff --git a/jssource/src_files/modules/Studio/JSTransaction.js b/jssource/src_files/modules/Studio/JSTransaction.js new file mode 100644 index 00000000..c31ca457 --- /dev/null +++ b/jssource/src_files/modules/Studio/JSTransaction.js @@ -0,0 +1,79 @@ +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + + + +function JSTransaction(){ + this.JSTransactions = new Array(); + this.JSTransactionIndex = 0; + this.JSTransactionCanRedo = false; + this.JSTransactionTypes = new Array(); + + +} + + JSTransaction.prototype.record = function(transaction, data){ + this.JSTransactions[this.JSTransactionIndex] = {'transaction':transaction , 'data':data}; + this.JSTransactionIndex++; + this.JSTransactionCanRedo = false + } + JSTransaction.prototype.register = function(transaction, undo, redo){ + this.JSTransactionTypes[transaction] = {'undo': undo, 'redo':redo}; + } + JSTransaction.prototype.undo = function(){ + if(this.JSTransactionIndex > 0){ + if(this.JSTransactionIndex > this.JSTransactions.length ){ + this.JSTransactionIndex = this.JSTransactions.length; + } + var transaction = this.JSTransactions[this.JSTransactionIndex - 1]; + var undoFunction = this.JSTransactionTypes[transaction['transaction']]['undo']; + undoFunction(transaction['data']); + this.JSTransactionIndex--; + this.JSTransactionCanRedo = true; + } + } + JSTransaction.prototype.redo = function(){ + if(this.JSTransactionCanRedo && this.JSTransactions.length < 0)this.JSTransactionIndex = 0; + if(this.JSTransactionCanRedo && this.JSTransactionIndex <= this.JSTransactions.length ){ + this.JSTransactionIndex++; + var transaction = this.JSTransactions[this.JSTransactionIndex - 1]; + var redoFunction = this.JSTransactionTypes[transaction['transaction']]['redo']; + redoFunction(transaction['data']); + } + } + + + diff --git a/jssource/src_files/modules/Studio/studio.js b/jssource/src_files/modules/Studio/studio.js new file mode 100644 index 00000000..05b56c32 --- /dev/null +++ b/jssource/src_files/modules/Studio/studio.js @@ -0,0 +1,549 @@ +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + + +var yahooSlots = new Array(); +function addNewRowToView(id){ + var curRow = document.getElementById(id); + var parent = curRow.parentNode; + var newRow = document.createElement('tr'); + var newRow = parent.insertRow(parent.rows.length); + var re = /studiorow[0-9]+/g; + var cell = newRow.insertCell(0); + + cell.innerHTML = curRow.cells[0].innerHTML.replace(re, 'studiorow' + slotCount); + cell.className = curRow.cells[0].className; + for(var j = 1; j < curRow.cells.length ; j++){ + var cell = newRow.insertCell(j); + cell.innerHTML = ' '; + cell.className = curRow.cells[j].className; + } + var index = parent.rows.length; + for(var i = 0; i < parent.rows.length ; i++){ + if(parent.rows[i].id == id){ + index = i + 1; + } + } + newRow.id = 'studiorow' + slotCount; + if(typeof(curRow.parentId) == 'undefined'){ + newRow.parentId = id; + }else{ + newRow.parentId = curRow.parentId; + } + if(index < parent.rows.length){ + parent.insertBefore(newRow, parent.rows[index]); + }else{ + parent.appendChild(newRow); + } + document.getElementById('add_' + newRow.parentId).value = 1 + parseInt(document.getElementById('add_' + newRow.parentId).value); + slotCount++; +} + +function deleteRowFromView(id, index){ + var curRow = document.getElementById(id); + curRow.parentNode.removeChild(curRow); + if(typeof(curRow.parentId) == 'undefined'){ + document.getElementById('form_' + id).value=-1; + }else{ + document.getElementById('add_' + curRow.parentId).value = parseInt(document.getElementById('add_' + curRow.parentId).value) - 1; + } +} + +function addNewColToView(id, index){ + + var curCol = document.getElementById(id); + var index = curCol.cellIndex; + var parent = curCol.parentNode; + var cell = parent.insertCell(index + 1); + if(parent.parentNode.rows[parent.rowIndex + 1])parent.parentNode.rows[parent.rowIndex + 1].insertCell(index + 1) + var re = /studiocol[0-9]+/g; + cell.innerHTML = '[NEW]'; + cell.className = curCol.className; + if(typeof(curCol.parentId) == 'undefined'){ + cell.parentId = id; + }else{ + cell.parentId = curCol.parentId; + } + + document.getElementById('add_' + cell.parentId).value = 1 + parseInt(document.getElementById('add_' + cell.parentId).value); + slotCount++; +} + +function deleteColFromView(id, index){ + var curCol = document.getElementById(id); + var row = curCol.parentNode; + var index = curCol.cellIndex; + if(typeof(row.cells[index + 1].parentId) == 'undefined'){ + row.deleteCell(index); + row.deleteCell(index - 1); + if(row.parentNode.rows[row.rowIndex + 1]){ + row.parentNode.rows[row.rowIndex + 1].deleteCell(index ); + row.parentNode.rows[row.rowIndex + 1].deleteCell(index - 1); + } + + + }else{ + row.deleteCell(index + 1); + if(row.parentNode.rows[row.rowIndex + 1])row.parentNode.rows[row.rowIndex + 1].deleteCell(index +1); + + } + document.getElementById('add_' + curCol.id).value = parseInt(document.getElementById('add_' + curCol.id).value) - 1; + +} + + + + +var field_count_MSI = 0; +var studioLoaded = false; +var dyn_field_count = 0; +function addNewFieldType(type){ + var select = document.getElementById('studio_display_type').options; + for(var i = 0; i < select.length; i++){ + if(select[i].value == type){ + return; + } + } + select[i] = new Option(type, type); +} + +function filterStudioFields(type){ + var table = document.getElementById('studio_fields'); + for(var i = 0; i < table.rows.length; i++){ + children = table.rows[i].cells[0].childNodes; + for(var j = 0; j < children.length; j++){ + child = children[j]; + if(child.nodeName == 'DIV' && typeof(child.fieldType) != 'undefined'){ + if(type == 'all'){ + table.rows[i].style.display = ''; + }else if(type == 'custom'){ + if(child.isCustom){ + table.rows[i].style.display = '' + }else{ + table.rows[i].style.display = 'none'; + } + }else{ + if(child.fieldType == type){ + table.rows[i].style.display = '' + }else{ + table.rows[i].style.display = 'none'; + } + + } + } + } + } + +} + + +function addNewField(id, name, label, html, fieldType,isCustom, table_id, top){ + + html = replaceAll(html, "&qt;", '"'); + html = replaceAll(html, "&sqt;", "'"); + var table = document.getElementById(table_id); + var row = false; + if(top){ + row = table.insertRow(1); + }else{ + row = table.insertRow(table.rows.length); + } + + var cell = row.insertCell(0); + var div = document.createElement('div'); + div.className = 'slot'; + div.setAttribute('id', id); + div.fieldType = fieldType; + addNewFieldType(fieldType); + div.isCustom = isCustom; + div.style.width='100%'; + var textEl = document.createElement('input'); + textEl.setAttribute('type', 'hidden') + textEl.setAttribute('name', 'slot_field_' + field_count_MSI ); + textEl.setAttribute('id', 'slot_field_' + field_count_MSI ); + textEl.setAttribute('value', 'add:' + name ); + field_list_MSI['form_' + name] = textEl; + document.studio.appendChild(textEl); + div.innerHTML = label; + var cell2 = row.insertCell(1); + var div2 = document.createElement('div'); + setMouseOverForField(div, true); + div2.style.display = 'none'; + div2.setAttribute('id', id + 'b' ); + html = html.replace(/(]*)/g, '$1 disabled readonly $2'); + html = html.replace(/(]*)/g, '$1 disabled readonly $2'); + html = html.replace(/(onclick=')([^']*)/g, '$1'); // to strip {} from after a JS onclick call + div2.innerHTML += html; + cell.appendChild(div); + cell2.appendChild(div2); + field_count_MSI++; + if(top){ + yahooSlots[id] = new ygDDSlot(id, "studio"); + }else{ + dyn_field_count++; + } + return name; + +} + + +function removeFieldFromTable(field, table) +{ + var table = document.getElementById(table); + var rows = table.rows; + for(i = 0 ; i < rows.length; i++){ + cells = rows[i].cells; + for(j = 0; j < cells.length; j++){ + cell = rows[i].cells[j]; + children = cell.childNodes; + for(k = 0; k < children.length; k++){ + child = children[k]; + if(child.nodeType == 1){ + + if(child.getAttribute('id') == 'slot_' + field){ + table.deleteRow(i); + return; + } + } + } + } + } +} +function setMouseOverForField(field, on){ + + if(on){ + field.onmouseover = function(){ + return overlib(document.getElementById(this.id + 'b').innerHTML, FGCLASS, 'olFgClass', + CGCLASS, 'olCgClass', BGCLASS, 'olBgClass', TEXTFONTCLASS, 'olFontClass', CAPTIONFONTCLASS, 'olCapFontClass'); + + }; + field.onmouseout = function(){ + return nd(); + }; + }else{ + field.onmouseover = function(){}; + field.onmouseout = function(){}; + } +} +var lastIDClick = ''; +var lastIDClickTime = 0; +var dblDelay = 500; +function wasDoubleClick(id) { + var d = new Date(); + var now = d.getTime(); + + if (lastIDClick == id && (now - lastIDClickTime) < dblDelay) { + lastIDClick = ''; + + return true; + } + lastIDClickTime = now; + lastIDClick = id; + return false; +} +function confirmNoSave(){ + return confirm(SUGAR.language.get('Studio', 'LBL_CONFIRM_UNSAVE')); +} +var labelEdit = false; + SUGAR.Studio = function(){ + this.labelEdit = false; + this.lastLabel = false; +} + SUGAR.Studio.prototype.endLabelEdit = function(id){ + if(id == 'undefined')return; + document.getElementById('span' + id).style.display = 'none'; + jstransaction.record('studioLabelEdit', {'id':id, 'new': document.getElementById(id).value , 'old':document.getElementById('label' + id).innerHTML}); + document.getElementById('label' + id).innerHTML = document.getElementById(id).value; + document.getElementById('label_' + id).value = document.getElementById(id).value; + document.getElementById('label' + id).style.display = ''; + this.labelEdit = false; + YAHOO.util.DragDropMgr.unlock(); +}; + + SUGAR.Studio.prototype.undoLabelEdit = function (transaction){ + var id = transaction['id']; + document.getElementById('span' + id).style.display = 'none'; + document.getElementById('label' + id).innerHTML = transaction['old']; + document.getElementById('label_' + id).value = transaction['old']; +}; + SUGAR.Studio.prototype.redoLabelEdit= function (transaction){ + var id = transaction['id']; + document.getElementById('span' + id).style.display = 'none'; + document.getElementById('label' + id).innerHTML = transaction['new']; + document.getElementById('label_' + id).value = transaction['new']; +}; + + SUGAR.Studio.prototype.handleLabelClick = function(id, count){ + if(this.lastLabel != ''){ + //endLabelEdit(lastLabel); + } + if(wasDoubleClick(id) || count == 1){ + document.getElementById('span' + id).style.display = ''; + document.getElementById(id).focus(); + document.getElementById(id).select(); + document.getElementById('label' + id).style.display = 'none'; + this.lastLabel = id; + YAHOO.util.DragDropMgr.lock(); + } + + + +} +jstransaction.register('studioLabelEdit', SUGAR.Studio.prototype.undoLabelEdit, SUGAR.Studio.prototype.redoLabelEdit); + + +SUGAR.Studio.prototype.save = function(formName, publish){ + ajaxStatus.showStatus(SUGAR.language.get('app_strings', 'LBL_SAVING')); + var formObject = document.forms[formName]; + YAHOO.util.Connect.setForm(formObject); + var cObj = YAHOO.util.Connect.asyncRequest('POST','index.php', + {success: SUGAR.Studio.prototype.saved, failure: SUGAR.Studio.prototype.saved,timeout:5000, argument: publish}); +} +SUGAR.Studio.prototype.saved= function(o){ + if(o){ + ajaxStatus.showStatus(SUGAR.language.get('app_strings', 'LBL_SAVED')); + window.setTimeout('ajaxStatus.hideStatus();', 2000); + + if(o.argument){ + + studiojs.publish(); + }else{ + document.location.reload(); + } + }else{ + ajaxStatus.showStatus(SUGAR.language.get('Studio', 'LBL_FAILED_TO_SAVE')); + window.setTimeout('ajaxStatus.hideStatus();', 2000); + } +} + +SUGAR.Studio.prototype.publish = function(){ + ajaxStatus.showStatus(SUGAR.language.get('Studio', 'LBL_PUBLISHING')); + var cObj = YAHOO.util.Connect.asyncRequest('GET','index.php?to_pdf=1&module=Studio&action=Publish', + {success: SUGAR.Studio.prototype.published, failure: SUGAR.Studio.prototype.published}, null); +} + +SUGAR.Studio.prototype.published= function(o){ + if(o){ + ajaxStatus.showStatus(SUGAR.language.get('Studio', 'LBL_PUBLISHED')); + window.setTimeout('ajaxStatus.hideStatus();', 2000); + document.location.reload(); + }else{ + ajaxStatus.showStatus(SUGAR.language.get('Studio', 'LBL_FAILED_PUBLISHED')); + window.setTimeout('ajaxStatus.hideStatus();', 2000); + } + } + +var studiopopup = function() { + return { + // covers the page w/ white overlay + display: function() { + if(studiojs.popupVisible)return false; + studiojs.popupVisible = true; + var cObj = YAHOO.util.Connect.asyncRequest('GET','index.php?to_pdf=1&module=Studio&action=wizard&wizard=EditCustomFieldsWizard&option=CreateCustomFields&popup=true', + {success: studiopopup.render, failure: studiopopup.render}, null); + + + + + }, + destroy:function(){ + studiojs.popup.hide(); + }, + evalScript:function(text){ + SUGAR.util.evalScript(text); + + }, + render: function(obj){ + if(obj){ + + studiojs.popup = new YAHOO.widget.Dialog("dlg", { effect:{effect:YAHOO.widget.ContainerEffect.SLIDE,duration:.5}, fixedcenter: false, constraintoviewport: false, underlay:"shadow",modal:true, close:true, visible:false, draggable:true, monitorresize:true} ); + + studiojs.popup.setBody(obj.responseText); + studiojs.popupAvailable = true; + studiojs.popup.render(document.body); + studiojs.popup.center(); + studiojs.popup.beforeHideEvent.fire = function(e){ + studiojs.popupVisible = false; + } + studiopopup.evalScript(obj.responseText); + + + } + + } + + + }; +}(); +var studiojs = new SUGAR.Studio(); +studiojs.popupAvailable = false; +studiojs.popupVisible = false; + + + + + +var popupSave = function(o){ + var errorIndex = o.responseText.indexOf('[ERROR]'); + + if(errorIndex > -1){ + var error = o.responseText.substr(errorIndex + 7, o.responseText.length); + ajaxStatus.showStatus(error); + window.setTimeout('ajaxStatus.hideStatus();', 2000); + return; + } + var typeIndex = o.responseText.indexOf('[TYPE]') ; + var labelIndex = o.responseText.indexOf('[LABEL]') ; + var dataIndex = o.responseText.indexOf('[DATA]'); + var errorIndex = o.responseText.indexOf('[ERROR]'); + var name = o.responseText.substr(6, typeIndex - 6); + var type = o.responseText.substr(typeIndex + 6,labelIndex - (typeIndex + 6)); + var label = o.responseText.substr(labelIndex + 7,dataIndex - (labelIndex + 7)); + var data = o.responseText.substr(dataIndex + 6, o.responseText.length); + + addNewField('dyn_field_' + field_count_MSI, name, label, data, type, 1, 'studio_fields', true) + + +}; +function submitCustomFieldForm(isPopup){ + + if(typeof(document.popup_form.presave) != 'undefined'){ + document.popup_form.presave(); + } + + if(!check_form('popup_form'))return; + if(isPopup){ + + + var callback = + { + success: popupSave , + failure: popupSave , + argument: '' + } + YAHOO.util.Connect.setForm('popup_form'); + var cObj = YAHOO.util.Connect.asyncRequest('POST', 'index.php', callback); + studiopopup.destroy(); + }else{ + + document.popup_form.submit(); + } +} + +function deleteCustomFieldForm(isPopup){ + + + + if(confirm("WARNING\nDeleting a custom field will delete all data related to that custom field. \nYou will still need to remove the field from any layouts you have added it to.")){ + document.popup_form.option.value = 'DeleteCustomField'; + document.popup_form.submit(); + } +} + +function dropdownChanged(value){ + if(typeof(app_list_strings[value]) == 'undefined')return; + var select = document.getElementById('default_value').options; + select.length = 0; + + var count = 0; + for(var key in app_list_strings[value]){ + select[count] = new Option(app_list_strings[value][key], key); + count++; + } +} + +function customFieldChanged(){ +} + +var populateCustomField = function(response){ + var div = document.getElementById('customfieldbody'); + if(response.status = 0){ + div.innerHTML = 'Server Connection Failed'; + }else{ + validate['popup_form'] = new Array(); + inputsWithErrors = new Array(); + div.innerHTML = response.responseText; + studiopopup.evalScript(response.responseText); + if(studiojs.popupAvailable){ + + var region = YAHOO.util.Dom.getRegion('custom_field_table') ; + studiojs.popup.cfg.setProperty('width', region.right - region.left + 30 + 'px'); + studiojs.popup.cfg.setProperty('height', region.bottom - region.top + 30 + 'px'); + + studiojs.popup.render(document.body); + studiojs.popup.center(); + studiojs.popup.show(); + } + + } +}; +var populateCustomFieldCallback = { + success: populateCustomField , + failure: populateCustomField, + argument: 1 +}; +var COBJ = false; +function changeTypeData(type){ + document.getElementById('customfieldbody').innerHTML = '

    Loading...

    '; + COBJ = YAHOO.util.Connect.asyncRequest('GET','index.php?module=Studio&popup=true&action=index&&ajax=editcustomfield&to_pdf=true&type=' + type,populateCustomFieldCallback,null); + +} + +function typeChanged(obj) +{ + changeTypeData(obj.options[obj.selectedIndex].value); + +} + +function handle_duplicate(){ + document.popup_form.action.value = 'EditView'; + document.popup_form.duplicate.value = 'true'; + document.popup_form.submit(); +} + +function forceRange(field, min, max){ + field.value = parseInt(field.value); + if(field.value == 'NaN')field.value = max; + if(field.value > max) field.value = max; + if(field.value < min) field.value = min; +} +function changeMaxLength(field, length){ + field.maxLength = parseInt(length); + field.value = field.value.substr(0, field.maxLength); +} + + + diff --git a/jssource/src_files/modules/Studio/studiodd.js b/jssource/src_files/modules/Studio/studiodd.js new file mode 100644 index 00000000..f836935d --- /dev/null +++ b/jssource/src_files/modules/Studio/studiodd.js @@ -0,0 +1,219 @@ +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + + +/*Portions Copyright (c) 2006 Yahoo! Inc. All rights reserved. */ + +/** + * @class a ygDDFramed implementation like ygDDMy, but the content channels are + * not restricted to one column, and we drag a miniature representation of the + * content channel rather than a frame of the channel. + * + * @extends YAHOO.util.DDProxy + * @constructor + * @param {String} id the id of the linked element + * @param {String} sGroup the group of related DragDrop objects + */ + + +function ygDDSlot(id, sGroup) { + + if (id) { + this.init(id, sGroup); + this.initFrame(); + } + + // Change the style of the frame to be a miniature representation of a + // content channel + var s = this.getDragEl().style; + s.borderColor = "transparent"; + s.backgroundColor = "#f6f5e5"; + s.opacity = 0.76; + s.filter = "alpha(opacity=76)"; + + // Specify that we do not want to resize the drag frame... we want to keep + // the drag frame the size of our miniature content channel image + this.resizeFrame = true; + if(id == 's_field_delete'){ + this.isValidHandle = false; + } + // Specify that we want the drag frame centered around the cursor rather + // than relative to the click location so that the miniature content + // channel appears in the location that was clicked + //this.centerFrame = true; +} + +ygDDSlot.prototype = new YAHOO.util.DDProxy(); +ygDDSlot.prototype.handleDelete = function(cur, curb){ + var parentID = (typeof(cur.parentID) == 'undefined')?cur.id.substr(4,cur.id.length):cur.parentID ; + if(parentID.indexOf('field') == 0){ + return false; + } + var myfieldcount = field_count_MSI; + addNewField('dyn_field_' + field_count_MSI, 'delete', ' ', ' ', 'deleted', 0, 'studio_fields') + yahooSlots["dyn_field_" + myfieldcount] = new ygDDSlot("dyn_field_" + myfieldcount, "studio"); + ygDDSlot.prototype.handleSwap(cur, curb, document.getElementById("dyn_field_" + myfieldcount), document.getElementById("dyn_field_" + myfieldcount+ 'b'), true); +} + +ygDDSlot.prototype.undo = function(transaction){ + ygDDSlot.prototype.handleSwap(document.getElementById(transaction['el']),document.getElementById(transaction['elb']), document.getElementById(transaction['cur']), document.getElementById(transaction['curb']), false); +} +ygDDSlot.prototype.redo = function(transaction){ + ygDDSlot.prototype.handleSwap(document.getElementById(transaction['el']),document.getElementById(transaction['elb']), document.getElementById(transaction['cur']), document.getElementById(transaction['curb']), false); +} + +ygDDSlot.prototype.handleSwap = function(cur, curb,el, elb, record ){ + if(record){ + if(curb){ + jstransaction.record('studioSwap', {'cur': cur.id, 'curb': curb.id, 'el':el.id, 'elb':elb.id}); + }else{ + jstransaction.record('studioSwap', {'cur': cur.id, 'curb': null, 'el':el.id, 'elb':null}); + } + } + var parentID1 = (typeof(el.parentID) == 'undefined')?el.id.substr(4,el.id.length):el.parentID ; + var parentID2 = (typeof(cur.parentID) == 'undefined')?cur.id.substr(4,cur.id.length):cur.parentID ; + var slot1 = YAHOO.util.DDM.getElement("slot_" + parentID1); + var slot2 = YAHOO.util.DDM.getElement("slot_" + parentID2); + + var temp = slot1.value; + slot1.value = slot2.value; + slot2.value = temp; + + YAHOO.util.DDM.swapNode(cur, el); + if(curb){ + YAHOO.util.DDM.swapNode(curb, elb); + } + //swap ids also or else form swaps don't work properly since the actual div is swapped + cur.parentID = parentID1; + el.parentID = parentID2; + if(parentID1.indexOf('field') == 0){ + if(curb)curb.style.display = 'none'; + setMouseOverForField(cur, true); + }else{ + if(curb)curb.style.display = 'inline'; + setMouseOverForField(cur, false); + } + if(parentID2.indexOf('field') == 0){ + if(elb)elb.style.display = 'none'; + setMouseOverForField(el, true); + }else{ + if(elb)elb.style.display = 'inline'; + setMouseOverForField(el, false); + } +} +ygDDSlot.prototype.onDragDrop = function(e, id) { + + var cur = this.getEl(); + + var curb; + if ("string" == typeof id) { + curb = YAHOO.util.DDM.getElement(cur.id + "b"); + } else { + curb = YAHOO.util.DDM.getBestMatch(cur.id + "b").getEl(); + } + if(id == 's_field_delete'){ + id = ygDDSlot.prototype.handleDelete(cur, curb); + if(!id)return false; + } + + + var el; + if ("string" == typeof id) { + el = YAHOO.util.DDM.getElement(id); + } else { + el = YAHOO.util.DDM.getBestMatch(id).getEl(); + } + + + + + id2 = el.id + "b"; + if ("string" == typeof id) { + elb =YAHOO.util.DDM.getElement(id2); + } else { + elb =YAHOO.util.DDM.getBestMatch(id2).getEl(); + } + + ygDDSlot.prototype.handleSwap(cur, curb, el, elb, true) + var dragEl = this.getDragEl(); + dragEl.innerHTML = ''; +}; + +ygDDSlot.prototype.startDrag = function(x, y) { + + var dragEl = this.getDragEl(); + var clickEl = this.getEl(); + dragEl.innerHTML = clickEl.innerHTML; + dragEl.className = clickEl.className; + dragEl.style.color = clickEl.style.color; + dragEl.style.border = "2px solid #aaa"; + + // save the style of the object + this.clickContent = clickEl.innerHTML; + this.clickBorder = clickEl.style.border; + this.clickHeight = clickEl.style.height; + clickElRegion = YAHOO.util.Dom.getRegion(clickEl); + dragEl.style.height = clickEl.style.height; + + dragEl.style.width = (clickElRegion.right - clickElRegion.left) + 'px'; + clickEl.style.height = (clickElRegion.bottom - clickElRegion.top) + 'px'; + + //clickEl.innerHTML = ' '; + clickEl.style.border = '2px dashed #cccccc'; + clickEl.style.opacity = .5; + clickEl.style.filter = "alpha(opacity=10)"; + +}; + +ygDDSlot.prototype.endDrag = function(e) { + // disable moving the linked element + var clickEl = this.getEl(); + //clickEl.innerHTML = this.clickContent + + if(this.clickHeight) + clickEl.style.height = this.clickHeight; + else + clickEl.style.height = ''; + + if(this.clickBorder) + clickEl.style.border = this.clickBorder; + else + clickEl.style.border = ''; + clickEl.style.opacity = 1; + clickEl.style.filter = "alpha(opacity=100)"; + +}; +jstransaction.register('studioSwap',ygDDSlot.prototype.undo, ygDDSlot.prototype.redo); \ No newline at end of file diff --git a/jssource/src_files/modules/Studio/studiotabgroups.js b/jssource/src_files/modules/Studio/studiotabgroups.js new file mode 100644 index 00000000..a0c42c35 --- /dev/null +++ b/jssource/src_files/modules/Studio/studiotabgroups.js @@ -0,0 +1,142 @@ +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + + +var subtabCount = []; +var subtabModules = []; +var tabLabelToValue = []; +StudioTabGroup = function(){ + this.lastEditTabGroupLabel = -1; +}; + + +StudioTabGroup.prototype.editTabGroupLabel = function (id, done){ + if(!done){ + if(this.lastEditTabGroupLabel != -1)StudioTabGroup.prototype.editTabGroupLabel(this.lastEditTabGroupLabel, true); + document.getElementById('tabname_'+id).style.display = 'none'; + document.getElementById('tablabel_'+id).style.display = ''; + document.getElementById('tabother_'+id).style.display = 'none'; + //#28274, I think this is a simple way when a element can't accept focus() + try{ + document.getElementById('tablabel_'+id).focus(); + } + catch(er){ + //TODO + } + this.lastEditTabGroupLabel = id; + YAHOO.util.DragDropMgr.lock(); + }else{ + this.lastEditTabGroupLabel = -1; + document.getElementById('tabname_'+id).innerHTML =document.getElementById('tablabel_'+id).value; + document.getElementById('tabname_'+id).style.display = ''; + document.getElementById('tablabel_'+id).style.display = 'none'; + document.getElementById('tabother_'+id).style.display = ''; + YAHOO.util.DragDropMgr.unlock(); + } +} + + StudioTabGroup.prototype.generateForm = function(formname){ + var form = document.getElementById(formname); + for(var j = 0; j < slotCount; j++){ + var ul = document.getElementById('ul' + j); + var items = ul.getElementsByTagName('li'); + for(var i = 0; i < items.length; i++) { + if(typeof(subtabModules[items[i].id]) != 'undefined'){ + + var input = document.createElement('input'); + input.type='hidden'; + input.name= j + '_'+ i; + input.value = tabLabelToValue[subtabModules[items[i].id]]; + form.appendChild(input); + } + } + } + //set the slotcount in the form. + form.slot_count.value = slotCount; +}; + + StudioTabGroup.prototype.generateGroupForm = function(formname){ + var form = document.getElementById(formname); + for(j = 0; j < slotCount; j++){ + var ul = document.getElementById('ul' + j); + items = ul.getElementsByTagName('li'); + for(i = 0; i < items.length; i++) { + if(typeof(subtabModules[items[i].id]) != 'undefined'){ + var input = document.createElement('input'); + input.type='hidden' + input.name= 'group_'+ j + '[]'; + input.value = tabLabelToValue[subtabModules[items[i].id]]; + form.appendChild(input); + } + } + } + }; + +StudioTabGroup.prototype.deleteTabGroup = function(id){ + if(document.getElementById('delete_' + id).value == 0){ + document.getElementById('ul' + id).style.display = 'none'; + document.getElementById('tabname_'+id).style.textDecoration = 'line-through' + document.getElementById('delete_' + id).value = 1; + }else{ + document.getElementById('ul' + id).style.display = ''; + document.getElementById('tabname_'+id).style.textDecoration = 'none' + document.getElementById('delete_' + id).value = 0; + } + } + + +var lastField = ''; + var lastRowCount = -1; + var undoDeleteDropDown = function(transaction){ + deleteDropDownValue(transaction['row'], document.getElementById(transaction['id']), false); + } + jstransaction.register('deleteDropDown', undoDeleteDropDown, undoDeleteDropDown); + function deleteDropDownValue(rowCount, field, record){ + if(record){ + jstransaction.record('deleteDropDown',{'row':rowCount, 'id': field.id }); + } + //We are deleting if the value is 0 + if(field.value == '0'){ + field.value = '1'; + document.getElementById('slot' + rowCount + '_value').style.textDecoration = 'line-through'; + }else{ + field.value = '0'; + document.getElementById('slot' + rowCount + '_value').style.textDecoration = 'none'; + } + + + } +var studiotabs = new StudioTabGroup(); \ No newline at end of file diff --git a/jssource/src_files/modules/Studio/ygDDListStudio.js b/jssource/src_files/modules/Studio/ygDDListStudio.js new file mode 100644 index 00000000..aa8a4bcc --- /dev/null +++ b/jssource/src_files/modules/Studio/ygDDListStudio.js @@ -0,0 +1,240 @@ +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + + + +/* Copyright (c) 2006 Yahoo! Inc. All rights reserved. */ + +/** + * @class a YAHOO.util.DDProxy implementation. During the drag over event, the + * dragged element is inserted before the dragged-over element. + * + * @extends YAHOO.util.DDProxy + * @constructor + * @param {String} id the id of the linked element + * @param {String} sGroup the group of related DragDrop objects + */ +var addListStudioCount = 0; +var moduleTabs = []; + + +function ygDDListStudio(id, sGroup, fromOnly) { + + if (id) { + + if(id == 'trashcan' || id.indexOf('noselect') ==0){ + this.initTarget(id, sGroup); + }else{ + this.init(id, sGroup); + } + this.initFrame(); + this.fromOnly = fromOnly; + } + + var s = this.getDragEl().style; + s.borderColor = "transparent"; + s.backgroundColor = "#f6f5e5"; + s.opacity = 0.76; + s.filter = "alpha(opacity=76)"; +} + + +ygDDListStudio.prototype = new YAHOO.util.DDProxy(); +ygDDListStudio.prototype.clickContent = ''; +ygDDListStudio.prototype.clickBorder = ''; +ygDDListStudio.prototype.clickHeight = ''; +ygDDListStudio.prototype.lastNode = false; +ygDDListStudio.prototype.startDrag +ygDDListStudio.prototype.startDrag = function(x, y) { + + var dragEl = this.getDragEl(); + var clickEl = this.getEl(); + + this.parentID = clickEl.parentNode.id; + dragEl.innerHTML = clickEl.innerHTML; + dragElObjects = dragEl.getElementsByTagName('object'); + + dragEl.className = clickEl.className; + dragEl.style.color = clickEl.style.color; + dragEl.style.border = "1px solid #aaa"; + + // save the style of the object + this.clickContent = clickEl.innerHTML; + this.clickBorder = clickEl.style.border; + this.clickHeight = clickEl.style.height; + + clickElRegion = YAHOO.util.Dom.getRegion(clickEl); + clickEl.style.height = (clickElRegion.bottom - clickElRegion.top) + 'px'; + clickEl.style.opacity = .5; + clickEl.style.filter = "alpha(opacity=10)"; + clickEl.style.border = '2px dashed #cccccc'; +}; +ygDDListStudio.prototype.updateTabs = function(){ + moduleTabs = []; + for(j = 0; j < slotCount; j++){ + + var ul = document.getElementById('ul' + j); + moduleTabs[j] = []; + items = ul.getElementsByTagName("li"); + for(i = 0; i < items.length; i++) { + if(items.length == 1){ + items[i].innerHTML = SUGAR.language.get('app_strings', 'LBL_DROP_HERE'); + + }else{ + if(items[i].innerHTML == SUGAR.language.get('app_strings', 'LBL_DROP_HERE')){ + items[i].innerHTML=''; + } + } + + moduleTabs[ul.id.substr(2, ul.id.length)][subtabModules[items[i].id]] = true; + } + + } + +}; +ygDDListStudio.prototype.endDrag = function(e) { + + var clickEl = this.getEl(); + clickEl.innerHTML = this.clickContent + var p = clickEl.parentNode; + if(p.id == 'trash'){ + p.removeChild(clickEl); + this.lastNode = false; + this.updateTabs(); + return; + } + if(this.clickHeight) { + clickEl.style.height = this.clickHeight; + if(this.lastNode)this.lastNode.style.height=this.clickHeight; + } + else{ + clickEl.style.height = ''; + if(this.lastNode)this.lastNode.style.height=''; + } + + if(this.clickBorder){ + clickEl.style.border = this.clickBorder; + if(this.lastNode)this.lastNode.style.border=this.clickBorder; + } + else { + clickEl.style.border = ''; + if(this.lastNode)this.lastNode.style.border=''; + } + clickEl.style.opacity = 1; + clickEl.style.filter = "alpha(opacity=100)"; + if(this.lastNode){ + this.lastNode.id = 'addLS' + addListStudioCount; + subtabModules[this.lastNode.id] = this.lastNode.module; + yahooSlots[this.lastNode.id] = new ygDDListStudio(this.lastNode.id, 'subTabs', false); + addListStudioCount++; + this.lastNode.style.opacity = 1; + this.lastNode.style.filter = "alpha(opacity=100)"; + } + this.lastNode = false; + this.updateTabs(); +}; + +ygDDListStudio.prototype.onDrag = function(e, id) { + +}; + +ygDDListStudio.prototype.onDragOver = function(e, id) { + // this.logger.debug(this.id.toString() + " onDragOver " + id); + var el; + if(this.lastNode){ + this.lastNode.parentNode.removeChild(this.lastNode); + this.lastNode = false; + } + if(id.substr(0, 7) == 'modSlot'){ + return; + } + if ("string" == typeof id) { + el = YAHOO.util.DDM.getElement(id); + } else { + el = YAHOO.util.DDM.getBestMatch(id).getEl(); + } + + dragEl = this.getDragEl(); + elRegion = YAHOO.util.Dom.getRegion(el); + + + var mid = YAHOO.util.DDM.getPosY(el) + (Math.floor((elRegion.bottom - elRegion.top) / 2)); + var el2 = this.getEl(); + var p = el.parentNode; + if( (this.fromOnly || ( el.id != 'trashcan' && el2.parentNode.id != p.id && el2.parentNode.id == this.parentID)) ){ + if(typeof(moduleTabs[p.id.substr(2,p.id.length)][subtabModules[el2.id]]) != 'undefined')return; + + } + + if(this.fromOnly && el.id != 'trashcan'){ + el2 = el2.cloneNode(true); + el2.module = subtabModules[el2.id]; + el2.id = 'addListStudio' + addListStudioCount; + this.lastNode = el2; + this.lastNode.clickContent = el2.clickContent; + this.lastNode.clickBorder = el2.clickBorder; + this.lastNode.clickHeight = el2.clickHeight + + + } + if (YAHOO.util.DDM.getPosY(dragEl) < mid ) { // insert on top triggering item + p.insertBefore(el2, el); + } + if (YAHOO.util.DDM.getPosY(dragEl) >= mid ) { // insert below triggered item + p.insertBefore(el2, el.nextSibling); + } + + +}; + +ygDDListStudio.prototype.onDragEnter = function(e, id) { + +}; + +ygDDListStudio.prototype.onDragOut = function(e, id) { + +} + +///////////////////////////////////////////////////////////////////////////// + +function ygDDListStudioBoundary(id, sGroup) { + if (id) { + this.init(id, sGroup); + this.isBoundary = true; + } +} + +ygDDListStudioBoundary.prototype = new YAHOO.util.DDTarget(); diff --git a/jssource/src_files/modules/UpgradeWizard/upgradeWizard.js b/jssource/src_files/modules/UpgradeWizard/upgradeWizard.js new file mode 100644 index 00000000..d59eaf86 --- /dev/null +++ b/jssource/src_files/modules/UpgradeWizard/upgradeWizard.js @@ -0,0 +1,137 @@ +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + + +var req; +var uw_check_msg = ""; +//var uw_check_type = ''; +var find_done = false; + +function loadXMLDoc(url) { + req = false; + // branch for native XMLHttpRequest object + if(window.XMLHttpRequest) { + try { + req = new XMLHttpRequest(); + } catch(e) { + req = false; + } + // branch for IE/Windows ActiveX version + } else if(window.ActiveXObject) { + try { + req = new ActiveXObject("Msxml2.XMLHTTP"); + } catch(e) { + try { + req = new ActiveXObject("Microsoft.XMLHTTP"); + } catch(e) { + req = false; + } + } + } + + if(req) { + req.onreadystatechange = processReqChange; + req.open("GET", url, true); + req.send(""); + } +} + + + + +///// preflight scripts +function preflightToggleAll(cb) { + var checkAll = false; + var form = document.getElementById('diffs'); + + if(cb.checked == true) { + checkAll = true; + } + + for(i=0; i0) || (length > parseInt(maxpwdlength) && parseInt(maxpwdlength)>0 )){ + document.getElementById('lengths').className='bad'; + good_rules=1; + } + else{document.getElementById('lengths').className='good';} + } + + // One lower case + if(document.getElementById('1lowcase')){ + if(!passwd.match('[abcdefghijklmnopqrstuvwxyz]')){ + document.getElementById('1lowcase').className='bad'; + good_rules=1; + } + else{document.getElementById('1lowcase').className='good';} + } + + // One upper case + if(document.getElementById('1upcase')){ + if(!passwd.match('[ABCDEFGHIJKLMNOPQRSTUVWXYZ]')){ + document.getElementById('1upcase').className='bad'; + good_rules=1; + } + else{document.getElementById('1upcase').className='good';} + } + + // One number + if(document.getElementById('1number')){ + if(!passwd.match('[0123456789]')){ + document.getElementById('1number').className='bad'; + good_rules=1; + } + else{document.getElementById('1number').className='good';} + } + + // One special character + if(document.getElementById('1special')){ + var custom_regex= new RegExp('[|}{~!@#$%^&*()_+=-]'); + if(!custom_regex.test(passwd)){ + document.getElementById('1special').className='bad'; + good_rules=1; + } + else{document.getElementById('1special').className='good';} + } + + + // Custom regex + if(document.getElementById('regex')){ + var regex = new RegExp(customregex); + if(regex.test(passwd)){ + document.getElementById('regex').className='bad'; + good_rules=1; + } + else{document.getElementById('regex').className='good';} + } + return good_rules; + } + + +function set_focus() { + if (document.getElementById('error_pwd')){ + if (document.forms.length > 0) { + for (i = 0; i < document.forms.length; i++) { + for (j = 0; j < document.forms[i].elements.length; j++) { + var field = document.forms[i].elements[j]; + if ((field.type == "password") && (field.name == "old_password" )) { + field.focus(); + if (field.type == "text") { + field.select(); + } + break; + } + } + } + } + } + else{ + if (document.forms.length > 0) { + for (i = 0; i < document.forms.length; i++) { + for (j = 0; j < document.forms[i].elements.length; j++) { + var field = document.forms[i].elements[j]; + if ((field.type == "text" || field.type == "textarea" || field.type == "password") && + !field.disabled && (field.name == "first_name" || field.name == "name" || field.name == "user_name" || field.name=="document_name")) { + field.focus(); + if (field.type == "text") { + field.select(); + } + break; + } + } + } + } + } +} diff --git a/jssource/src_files/modules/Users/User.js b/jssource/src_files/modules/Users/User.js new file mode 100644 index 00000000..14f6862f --- /dev/null +++ b/jssource/src_files/modules/Users/User.js @@ -0,0 +1,216 @@ +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + + +function clearInboundSettings() { + var url = document.getElementById('server_url'); + var user = document.getElementById('email_user'); + var prot = document.getElementById('protocol'); + var pass = document.getElementById('email_password'); + var port = document.getElementById('port'); + var inbox = document.getElementById('mailbox'); + + url.value = ''; + user.value =''; + pass.value = ''; + port.value = ''; + inbox.value = ''; + + for(i=0; i tag at the start of some themes, skip it + continue; + } + // notCurrentTabLeft, notCurrentTabRight, notCurrentTab + var classStarter = 'notC'; + if ( aElem.id == "grouptab_"+tabNum ) { + // currentTabLeft, currentTabRight, currentTab + classStarter = 'c'; + currentGroupItem = i; + } + var spanTags = groupList[i].getElementsByTagName("span"); + for (var ii = 0 ; ii < spanTags.length; ii++ ) { + if ( spanTags[ii].className == null ) { continue; } + var oldClass = spanTags[ii].className.match(/urrentTab.*/); + spanTags[ii].className = classStarter + oldClass; + } + } + //////////////////////////////////////////////////////////////////////////////////////// + ////update submenu position + //get sub menu dom node + var menuHandle = moduleGroups[tabNum]; + + //get group tab dom node + var parentMenu = groupList[currentGroupItem]; + + if(menuHandle && parentMenu){ + updateSubmenuPosition(menuHandle , parentMenu); + } + //////////////////////////////////////////////////////////////////////////////////////// + }; + for (var i = 0; i < moduleLinks.length; i++) { + moduleLinks[i].onmouseover = moduleLinkMouseOver; + } +}; + +function updateSubmenuPosition(menuHandle , parentMenu){ + var left=''; + if (left == "") { + p = parentMenu; + var left = 0; + while(p&&p.tagName.toUpperCase()!='BODY'){ + left+=p.offsetLeft; + p=p.offsetParent; + } + } + + //get browser width + var bw = checkBrowserWidth(); + + //If the mouse over on 'MoreMenu' group tab, stop the following function + if(!parentMenu){ + return; + } + //Calculate left position of the middle of current group tab . + var groupTabLeft = left + (parentMenu.offsetWidth / 2); + var subTabHalfLength = 0; + var children = menuHandle.getElementsByTagName('li'); + for(var i = 0; i< children.length; i++){ + //offsetWidth = width + padding + border + if(children[i].className == 'subTabMore' || children[i].parentNode.className == 'cssmenu'){ + continue; + } + subTabHalfLength += parseInt(children[i].offsetWidth); + } + + if(subTabHalfLength != 0){ + subTabHalfLength = subTabHalfLength / 2; + } + + var totalLengthInTheory = subTabHalfLength + groupTabLeft; + if(subTabHalfLength>0 && groupTabLeft >0){ + if(subTabHalfLength >= groupTabLeft){ + left = 1; + }else{ + left = groupTabLeft - subTabHalfLength; + } + } + + //If the sub menu length > browser length + if(totalLengthInTheory > bw){ + var differ = totalLengthInTheory - bw; + left = groupTabLeft - subTabHalfLength - differ - 2; + } + + if (left >=0){ + menuHandle.style.marginLeft = left+'px'; + } +} + +YAHOO.util.Event.onDOMReady(function() +{ + if ( document.getElementById('subModuleList') ) { + //////////////////////////////////////////////////////////////////////////////////////// + ////update current submenu position + var parentMenu = false; + var moduleListDom = document.getElementById('moduleList'); + if(moduleListDom !=null){ + var parentTabLis = moduleListDom.getElementsByTagName("li"); + var tabNum = 0; + for(var ii = 0; ii < parentTabLis.length; ii++){ + var spans = parentTabLis[ii].getElementsByTagName("span"); + for(var jj =0; jj < spans.length; jj++){ + if(spans[jj].className.match(/currentTab.*/)){ + tabNum = ii; + } + } + } + var parentMenu = parentTabLis[tabNum]; + } + var moduleGroups = document.getElementById('subModuleList').getElementsByTagName("span"); + for(var i = 0; i < moduleGroups.length; i++){ + if(moduleGroups[i].className.match(/selected/)){ + tabNum = i; + } + } + var menuHandle = moduleGroups[tabNum]; + + if(menuHandle && parentMenu){ + updateSubmenuPosition(menuHandle , parentMenu); + } + } + //////////////////////////////////////////////////////////////////////////////////////// +}); diff --git a/jssource/src_files/themes/default/js/style.js b/jssource/src_files/themes/default/js/style.js new file mode 100644 index 00000000..6381d160 --- /dev/null +++ b/jssource/src_files/themes/default/js/style.js @@ -0,0 +1,45 @@ +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + +/** + * Handles loading the theme picker popup + */ +YAHOO.util.Event.onDOMReady(function() +{ + // open print dialog if we requested the print view + if ( location.href.indexOf('print=true') > -1 ) + setTimeout("window.print();", 1000); +}); diff --git a/leadCapture.php b/leadCapture.php new file mode 100644 index 00000000..e0d30f76 --- /dev/null +++ b/leadCapture.php @@ -0,0 +1,46 @@ + \ No newline at end of file diff --git a/log4php/LoggerManager.php b/log4php/LoggerManager.php new file mode 100644 index 00000000..c5c50fc0 --- /dev/null +++ b/log4php/LoggerManager.php @@ -0,0 +1,7 @@ + diff --git a/log_file_restricted.html b/log_file_restricted.html new file mode 100644 index 00000000..fc5ab2e7 --- /dev/null +++ b/log_file_restricted.html @@ -0,0 +1,42 @@ + + + +

    Access to the log file is restricted.

    + + diff --git a/maintenance.php b/maintenance.php new file mode 100644 index 00000000..2f969306 --- /dev/null +++ b/maintenance.php @@ -0,0 +1,41 @@ +" ); + print( "Down for maintenance." ); + print( "" ); +?> diff --git a/metadata/accounts_bugsMetaData.php b/metadata/accounts_bugsMetaData.php new file mode 100644 index 00000000..d9bec374 --- /dev/null +++ b/metadata/accounts_bugsMetaData.php @@ -0,0 +1,57 @@ + 'accounts_bugs' + , 'fields' => array ( + array('name' =>'id', 'type' =>'varchar', 'len'=>'36',) + , array('name' =>'account_id', 'type' =>'varchar', 'len'=>'36') + , array('name' =>'bug_id', 'type' =>'varchar', 'len'=>'36') + , array ('name' => 'date_modified','type' => 'datetime') + , array('name' =>'deleted', 'type' =>'bool', 'len'=>'1', 'required'=>false, 'default'=>'0') + ) , 'indices' => array ( + array('name' =>'accounts_bugspk', 'type' =>'primary', 'fields'=>array('id')) + , array('name' =>'idx_acc_bug_acc', 'type' =>'index', 'fields'=>array('account_id')) + , array('name' =>'idx_acc_bug_bug', 'type' =>'index', 'fields'=>array('bug_id')) + , array('name' => 'idx_account_bug', 'type'=>'alternate_key', 'fields'=>array('account_id','bug_id')) + ) + + , 'relationships' => array ('accounts_bugs' => array('lhs_module'=> 'Accounts', 'lhs_table'=> 'accounts', 'lhs_key' => 'id', + 'rhs_module'=> 'Bugs', 'rhs_table'=> 'bugs', 'rhs_key' => 'id', + 'relationship_type'=>'many-to-many', + 'join_table'=> 'accounts_bugs', 'join_key_lhs'=>'account_id', 'join_key_rhs'=>'bug_id')) +) +?> diff --git a/metadata/accounts_casesMetaData.php b/metadata/accounts_casesMetaData.php new file mode 100644 index 00000000..61c73427 --- /dev/null +++ b/metadata/accounts_casesMetaData.php @@ -0,0 +1,51 @@ + 'accounts_cases' + , 'fields' => array ( + array('name' =>'id', 'type' =>'varchar', 'len'=>'36') + , array('name' =>'account_id', 'type' =>'varchar', 'len'=>'36') + , array('name' =>'case_id', 'type' =>'varchar', 'len'=>'36') + , array ('name' => 'date_modified','type' => 'datetime') + ,array('name' =>'deleted', 'type' =>'bool', 'len'=>'1', 'required'=>false, 'default'=>'0') + ) , 'indices' => array ( + array('name' =>'accounts_casespk', 'type' =>'primary', 'fields'=>array('id')) + , array('name' =>'idx_acc_case_acc', 'type' =>'index', 'fields'=>array('account_id')) + , array('name' =>'idx_acc_acc_case', 'type' =>'index', 'fields'=>array('case_id')) + ) + ) +?> diff --git a/metadata/accounts_contactsMetaData.php b/metadata/accounts_contactsMetaData.php new file mode 100644 index 00000000..1bc15e13 --- /dev/null +++ b/metadata/accounts_contactsMetaData.php @@ -0,0 +1,59 @@ + 'accounts_contacts' + , 'fields' => array ( + array('name' =>'id', 'type' =>'varchar', 'len'=>'36') + , array('name' =>'contact_id', 'type' =>'varchar', 'len'=>'36') + , array('name' =>'account_id', 'type' =>'varchar', 'len'=>'36') + , array ('name' => 'date_modified','type' => 'datetime') + , array('name' =>'deleted', 'type' =>'bool', 'len'=>'1', 'required'=>false, 'default'=>'0') + ) , 'indices' => array ( + array('name' =>'accounts_contactspk', 'type' =>'primary', 'fields'=>array('id')) + , array('name' => 'idx_account_contact', 'type'=>'alternate_key', 'fields'=>array('account_id','contact_id')) + , array('name' => 'idx_contid_del_accid', 'type' => 'index', 'fields'=> array('contact_id', 'deleted', 'account_id')) + + ) + + , 'relationships' => array ('accounts_contacts' => array('lhs_module'=> 'Accounts', 'lhs_table'=> 'accounts', 'lhs_key' => 'id', + 'rhs_module'=> 'Contacts', 'rhs_table'=> 'contacts', 'rhs_key' => 'id', + 'relationship_type'=>'many-to-many', + 'join_table'=> 'accounts_contacts', 'join_key_lhs'=>'account_id', 'join_key_rhs'=>'contact_id')) + + +) +?> diff --git a/metadata/accounts_opportunitiesMetaData.php b/metadata/accounts_opportunitiesMetaData.php new file mode 100644 index 00000000..3e94f615 --- /dev/null +++ b/metadata/accounts_opportunitiesMetaData.php @@ -0,0 +1,58 @@ + 'accounts_opportunities' + , 'fields' => array ( + array('name' =>'id', 'type' =>'varchar', 'len'=>'36') + , array('name' =>'opportunity_id', 'type' =>'varchar', 'len'=>'36', ) + , array('name' =>'account_id', 'type' =>'varchar', 'len'=>'36', ) + , array ('name' => 'date_modified','type' => 'datetime') + , array('name' =>'deleted', 'type' =>'bool', 'len'=>'1', 'default'=>'0', 'required'=>false) + ) + , 'indices' => array ( + array('name' =>'accounts_opportunitiespk', 'type' =>'primary', 'fields'=>array('id')) + , array('name' => 'idx_account_opportunity', 'type'=>'alternate_key', 'fields'=>array('account_id','opportunity_id')) + , array('name' => 'idx_oppid_del_accid', 'type' => 'index', 'fields'=> array('opportunity_id', 'deleted', 'account_id')) + ) + + ,'relationships' => array ('accounts_opportunities' => array('lhs_module'=> 'Accounts', 'lhs_table'=> 'accounts', 'lhs_key' => 'id', + 'rhs_module'=> 'Opportunities', 'rhs_table'=> 'opportunities', 'rhs_key' => 'id', + 'relationship_type'=>'many-to-many', + 'join_table'=> 'accounts_opportunities', 'join_key_lhs'=>'account_id', 'join_key_rhs'=>'opportunity_id')) + +) +?> diff --git a/metadata/acl_roles_actionsMetaData.php b/metadata/acl_roles_actionsMetaData.php new file mode 100644 index 00000000..ec909ed7 --- /dev/null +++ b/metadata/acl_roles_actionsMetaData.php @@ -0,0 +1,98 @@ + 'acl_roles_actions', + + 'fields' => array ( + array ( + 'name' => 'id', + 'type' => 'varchar', + 'len' => '36', + ), + array ( + 'name' => 'role_id', + 'type' => 'varchar', + 'len' => '36', + ), + array ( + 'name' => 'action_id', + 'type' => 'varchar', + 'len' => '36', + ), + array ( + 'name' => 'access_override', + 'type' => 'int', + 'len' => '3', + 'required' => false, + ) + , array ('name' => 'date_modified','type' => 'datetime'), + array ( + 'name' => 'deleted', + 'type' => 'bool', + 'len' => '1', + 'default' => '0' + ), + ), + + 'indices' => array ( + array ( + 'name' => 'acl_roles_actionspk', + 'type' => 'primary', + 'fields' => array ( 'id' ) + ), + array ( + 'name' => 'idx_acl_role_id', + 'type' => 'index', + 'fields' => array ('role_id') + ), + array ( + 'name' => 'idx_acl_action_id', + 'type' => 'index', + 'fields' => array ('action_id') + ), + array('name' => 'idx_aclrole_action', 'type'=>'alternate_key', 'fields'=>array('role_id','action_id')) + ), + 'relationships' => array ('acl_roles_actions' => array('lhs_module'=> 'ACLRoles', 'lhs_table'=> 'acl_roles', 'lhs_key' => 'id', + 'rhs_module'=> 'ACLActions', 'rhs_table'=> 'acl_actions', 'rhs_key' => 'id', + 'relationship_type'=>'many-to-many', + 'join_table'=> 'acl_roles_actions', 'join_key_lhs'=>'role_id', 'join_key_rhs'=>'action_id')), + +) + +?> \ No newline at end of file diff --git a/metadata/acl_roles_usersMetaData.php b/metadata/acl_roles_usersMetaData.php new file mode 100644 index 00000000..49632d38 --- /dev/null +++ b/metadata/acl_roles_usersMetaData.php @@ -0,0 +1,92 @@ + 'acl_roles_users', + + 'fields' => array ( + array ( + 'name' => 'id', + 'type' => 'varchar', + 'len' => '36', + ), + array ( + 'name' => 'role_id', + 'type' => 'varchar', + 'len' => '36', + ), + array ( + 'name' => 'user_id', + 'type' => 'varchar', + 'len' => '36', + ) + , array ('name' => 'date_modified','type' => 'datetime'), + array ( + 'name' => 'deleted', + 'type' => 'bool', + 'len' => '1', + 'default' => '0' + ), + ), + + 'indices' => array ( + array ( + 'name' => 'acl_roles_userspk', + 'type' => 'primary', + 'fields' => array ( 'id' ) + ), + array ( + 'name' => 'idx_aclrole_id', + 'type' => 'index', + 'fields' => array ('role_id') + ), + array ( + 'name' => 'idx_acluser_id', + 'type' => 'index', + 'fields' => array ('user_id') + ), + array('name' => 'idx_aclrole_user', 'type'=>'alternate_key', 'fields'=>array('role_id','user_id')) + ), + 'relationships' => array ('acl_roles_users' => array('lhs_module'=> 'ACLRoles', 'lhs_table'=> 'acl_roles', 'lhs_key' => 'id', + 'rhs_module'=> 'Users', 'rhs_table'=> 'users', 'rhs_key' => 'id', + 'relationship_type'=>'many-to-many', + 'join_table'=> 'acl_roles_users', 'join_key_lhs'=>'role_id', 'join_key_rhs'=>'user_id')), + +) + +?> \ No newline at end of file diff --git a/metadata/addressBookMetaData.php b/metadata/addressBookMetaData.php new file mode 100644 index 00000000..7430a4e1 --- /dev/null +++ b/metadata/addressBookMetaData.php @@ -0,0 +1,81 @@ + 'address_book', + 'fields' => array ( + 'assigned_user_id' => array ( + 'name' => 'assigned_user_id', + 'vname' => 'LBL_USER_ID', + 'type' => 'id', + 'required' => true, + 'reportable' => false, + ), + 'bean' => array ( + 'name' => 'bean', + 'vname' => 'LBL_BEAN', + 'type' => 'varchar', + 'len' => '50', + 'required' => true, + 'reportable' => false, + ), + 'bean_id' => array ( + 'name' => 'bean_id', + 'vname' => 'LBL_BEAN_ID', + 'type' => 'id', + 'required' => true, + 'reportable' => false, + ), + ), + 'indices' => array ( + array( + 'name' => 'ab_user_bean_idx', + 'type' =>'index', + 'fields' => array( + 'assigned_user_id', + 'bean', + ) + ), + ), /* end indices */ +); + diff --git a/metadata/audit_templateMetaData.php b/metadata/audit_templateMetaData.php new file mode 100644 index 00000000..d8d4b425 --- /dev/null +++ b/metadata/audit_templateMetaData.php @@ -0,0 +1,61 @@ + 'audit', + 'fields' => array ( + 'id'=> array('name' =>'id', 'type' =>'id', 'len'=>'36','required'=>true), + 'parent_id'=>array('name' =>'parent_id', 'type' =>'id', 'len'=>'36','required'=>true), + 'date_created'=>array('name' =>'date_created','type' => 'datetime'), + 'created_by'=>array('name' =>'created_by','type' => 'varchar','len' => 36), + 'field_name'=>array('name' =>'field_name','type' => 'varchar','len' => 100), + 'data_type'=>array('name' =>'data_type','type' => 'varchar','len' => 100), + 'before_value_string'=>array('name' =>'before_value_string','type' => 'varchar'), + 'after_value_string'=>array('name' =>'after_value_string','type' => 'varchar'), + 'before_value_text'=>array('name' =>'before_value_text','type' => 'text'), + 'after_value_text'=>array('name' =>'after_value_text','type' => 'text'), + ), + 'indices' => array ( + //name will be re-constructed adding idx_ and table name as the prefix like 'idx_accounts_' + array ('name' => 'primary', 'type' => 'index', 'fields' => array('id')), + array ('name' => 'parent_id', 'type' => 'index', 'fields' => array('parent_id')) + ) + ) +?> \ No newline at end of file diff --git a/metadata/calls_contactsMetaData.php b/metadata/calls_contactsMetaData.php new file mode 100644 index 00000000..06ce4eb8 --- /dev/null +++ b/metadata/calls_contactsMetaData.php @@ -0,0 +1,61 @@ + 'calls_contacts' + , 'fields' => array ( + array('name' =>'id', 'type' =>'varchar', 'len'=>'36') + , array('name' =>'call_id', 'type' =>'varchar', 'len'=>'36', ) + , array('name' =>'contact_id', 'type' =>'varchar', 'len'=>'36', ) + , array('name' =>'required', 'type' =>'varchar', 'len'=>'1', 'default'=>'1') + , array('name' =>'accept_status', 'type' =>'varchar', 'len'=>'25', 'default'=>'none') + , array ('name' => 'date_modified','type' => 'datetime') + , array('name' =>'deleted', 'type' =>'bool', 'len'=>'1', 'default'=>'0', 'required'=>false) + ) + , 'indices' => array ( + array('name' =>'calls_contactspk', 'type' =>'primary', 'fields'=>array('id')) + , array('name' =>'idx_con_call_call', 'type' =>'index', 'fields'=>array('call_id')) + , array('name' =>'idx_con_call_con', 'type' =>'index', 'fields'=>array('contact_id')) + , array('name' => 'idx_call_contact', 'type'=>'alternate_key', 'fields'=>array('call_id','contact_id')) + ) + + , 'relationships' => array ('calls_contacts' => array('lhs_module'=> 'Calls', 'lhs_table'=> 'calls', 'lhs_key' => 'id', + 'rhs_module'=> 'Contacts', 'rhs_table'=> 'contacts', 'rhs_key' => 'id', + 'relationship_type'=>'many-to-many', + 'join_table'=> 'calls_contacts', 'join_key_lhs'=>'call_id', 'join_key_rhs'=>'contact_id')) + +) +?> diff --git a/metadata/calls_leadsMetaData.php b/metadata/calls_leadsMetaData.php new file mode 100644 index 00000000..be0789fb --- /dev/null +++ b/metadata/calls_leadsMetaData.php @@ -0,0 +1,61 @@ + 'calls_leads' + , 'fields' => array ( + array('name' =>'id', 'type' =>'varchar', 'len'=>'36') + , array('name' =>'call_id', 'type' =>'varchar', 'len'=>'36', ) + , array('name' =>'lead_id', 'type' =>'varchar', 'len'=>'36', ) + , array('name' =>'required', 'type' =>'varchar', 'len'=>'1', 'default'=>'1') + , array('name' =>'accept_status', 'type' =>'varchar', 'len'=>'25', 'default'=>'none') + , array ('name' => 'date_modified','type' => 'datetime') + , array('name' =>'deleted', 'type' =>'bool', 'len'=>'1', 'default'=>'0', 'required'=>false) + ) + , 'indices' => array ( + array('name' =>'calls_leadspk', 'type' =>'primary', 'fields'=>array('id')) + , array('name' =>'idx_lead_call_call', 'type' =>'index', 'fields'=>array('call_id')) + , array('name' =>'idx_lead_call_lead', 'type' =>'index', 'fields'=>array('lead_id')) + , array('name' => 'idx_call_lead', 'type'=>'alternate_key', 'fields'=>array('call_id','lead_id')) + ) + + , 'relationships' => array ('calls_leads' => array('lhs_module'=> 'Calls', 'lhs_table'=> 'calls', 'lhs_key' => 'id', + 'rhs_module'=> 'Leads', 'rhs_table'=> 'leads', 'rhs_key' => 'id', + 'relationship_type'=>'many-to-many', + 'join_table'=> 'calls_leads', 'join_key_lhs'=>'call_id', 'join_key_rhs'=>'lead_id')) + +) +?> diff --git a/metadata/calls_usersMetaData.php b/metadata/calls_usersMetaData.php new file mode 100644 index 00000000..e520a43d --- /dev/null +++ b/metadata/calls_usersMetaData.php @@ -0,0 +1,59 @@ + 'calls_users' + , 'fields' => array ( + array('name' =>'id', 'type' =>'varchar', 'len'=>'36') + , array('name' =>'call_id', 'type' =>'varchar', 'len'=>'36') + , array('name' =>'user_id', 'type' =>'varchar', 'len'=>'36') + , array('name' =>'required', 'type' =>'varchar', 'len'=>'1', 'default'=>'1') + , array('name' =>'accept_status', 'type' =>'varchar', 'len'=>'25', 'default'=>'none') + , array ('name' => 'date_modified','type' => 'datetime') + , array('name' =>'deleted', 'type' =>'bool', 'len'=>'1', 'default'=>'0', 'required'=>false) + ) , 'indices' => array ( + array('name' =>'calls_userspk', 'type' =>'primary', 'fields'=>array('id')) + , array('name' =>'idx_usr_call_call', 'type' =>'index', 'fields'=>array('call_id')) + , array('name' =>'idx_usr_call_usr', 'type' =>'index', 'fields'=>array('user_id')) + , array('name' => 'idx_call_users', 'type'=>'alternate_key', 'fields'=>array('call_id','user_id')) + ) + , 'relationships' => array ('calls_users' => array('lhs_module'=> 'Calls', 'lhs_table'=> 'calls', 'lhs_key' => 'id', + 'rhs_module'=> 'Users', 'rhs_table'=> 'users', 'rhs_key' => 'id', + 'relationship_type'=>'many-to-many', + 'join_table'=> 'calls_users', 'join_key_lhs'=>'call_id', 'join_key_rhs'=>'user_id')) + +) +?> diff --git a/metadata/cases_bugsMetaData.php b/metadata/cases_bugsMetaData.php new file mode 100644 index 00000000..2d31b2e1 --- /dev/null +++ b/metadata/cases_bugsMetaData.php @@ -0,0 +1,58 @@ + 'cases_bugs' + , 'fields' => array ( + array('name' =>'id', 'type' =>'varchar', 'len'=>'36') + , array('name' =>'case_id', 'type' =>'varchar', 'len'=>'36') + , array('name' =>'bug_id', 'type' =>'varchar', 'len'=>'36') + , array ('name' => 'date_modified','type' => 'datetime') + , array('name' =>'deleted', 'type' =>'bool', 'len'=>'1', 'default'=>'0', 'required'=>false) + ) , 'indices' => array ( + array('name' =>'cases_bugspk', 'type' =>'primary', 'fields'=>array('id')) + , array('name' =>'idx_cas_bug_cas', 'type' =>'index', 'fields'=>array('case_id')) + , array('name' =>'idx_cas_bug_bug', 'type' =>'index', 'fields'=>array('bug_id')) + , array('name' => 'idx_case_bug', 'type'=>'alternate_key', 'fields'=>array('case_id','bug_id')) + + ) + , 'relationships' => array ('cases_bugs' => array('lhs_module'=> 'Cases', 'lhs_table'=> 'cases', 'lhs_key' => 'id', + 'rhs_module'=> 'Bugs', 'rhs_table'=> 'bugs', 'rhs_key' => 'id', + 'relationship_type'=>'many-to-many', + 'join_table'=> 'cases_bugs', 'join_key_lhs'=>'case_id', 'join_key_rhs'=>'bug_id')) + + ) +?> diff --git a/metadata/configMetaData.php b/metadata/configMetaData.php new file mode 100644 index 00000000..faeb1bdf --- /dev/null +++ b/metadata/configMetaData.php @@ -0,0 +1,39 @@ + diff --git a/metadata/contacts_bugsMetaData.php b/metadata/contacts_bugsMetaData.php new file mode 100644 index 00000000..26b3f54f --- /dev/null +++ b/metadata/contacts_bugsMetaData.php @@ -0,0 +1,60 @@ + 'contacts_bugs' + , 'fields' => array ( + array('name' =>'id', 'type' =>'varchar', 'len'=>'36') + , array('name' =>'contact_id', 'type' =>'varchar', 'len'=>'36', ) + , array('name' =>'bug_id', 'type' =>'varchar', 'len'=>'36', ) + , array('name' =>'contact_role', 'type' =>'varchar', 'len'=>'50', ) + , array ('name' => 'date_modified','type' => 'datetime') + , array('name' =>'deleted', 'type' =>'bool', 'len'=>'1', 'default'=>'0','required'=>false) + ) , 'indices' => array ( + array('name' =>'contacts_bugspk', 'type' =>'primary', 'fields'=>array('id')) + , array('name' =>'idx_con_bug_con', 'type' =>'index', 'fields'=>array('contact_id')) + , array('name' =>'idx_con_bug_bug', 'type' =>'index', 'fields'=>array('bug_id')) + , array('name' => 'idx_contact_bug', 'type'=>'alternate_key', 'fields'=>array('contact_id','bug_id')) + + ) + , 'relationships' => array ('contacts_bugs' => array('lhs_module'=> 'Contacts', 'lhs_table'=> 'contacts', 'lhs_key' => 'id', + 'rhs_module'=> 'Bugs', 'rhs_table'=> 'bugs', 'rhs_key' => 'id', + 'relationship_type'=>'many-to-many', + 'join_table'=> 'contacts_bugs', 'join_key_lhs'=>'contact_id', 'join_key_rhs'=>'bug_id')) + + + ) +?> diff --git a/metadata/contacts_casesMetaData.php b/metadata/contacts_casesMetaData.php new file mode 100644 index 00000000..c0315783 --- /dev/null +++ b/metadata/contacts_casesMetaData.php @@ -0,0 +1,58 @@ + 'contacts_cases' + , 'fields' => array ( + array('name' =>'id', 'type' =>'varchar', 'len'=>'36') + , array('name' =>'contact_id', 'type' =>'varchar', 'len'=>'36', ) + , array('name' =>'case_id', 'type' =>'varchar', 'len'=>'36', ) + , array('name' =>'contact_role', 'type' =>'varchar', 'len'=>'50') + , array ('name' => 'date_modified','type' => 'datetime') + , array('name' =>'deleted', 'type' =>'bool', 'len'=>'1', 'default'=>'0','required'=>false) + ) , 'indices' => array ( + array('name' =>'contacts_casespk', 'type' =>'primary', 'fields'=>array('id')) + , array('name' =>'idx_con_case_con', 'type' =>'index', 'fields'=>array('contact_id')) + , array('name' =>'idx_con_case_case', 'type' =>'index', 'fields'=>array('case_id')) + , array('name' => 'idx_contacts_cases', 'type'=>'alternate_key', 'fields'=>array('contact_id','case_id')) + ) + , 'relationships' => array ('contacts_cases' => array('lhs_module'=> 'Contacts', 'lhs_table'=> 'contacts', 'lhs_key' => 'id', + 'rhs_module'=> 'Cases', 'rhs_table'=> 'cases', 'rhs_key' => 'id', + 'relationship_type'=>'many-to-many', + 'join_table'=> 'contacts_cases', 'join_key_lhs'=>'contact_id', 'join_key_rhs'=>'case_id')) + +) +?> diff --git a/metadata/contacts_usersMetaData.php b/metadata/contacts_usersMetaData.php new file mode 100644 index 00000000..07c04474 --- /dev/null +++ b/metadata/contacts_usersMetaData.php @@ -0,0 +1,57 @@ + 'contacts_users' + , 'fields' => array ( + array('name' =>'id', 'type' =>'varchar', 'len'=>'36') + , array('name' =>'contact_id', 'type' =>'varchar', 'len'=>'36', ) + , array('name' =>'user_id', 'type' =>'varchar', 'len'=>'36', ) + , array ('name' => 'date_modified','type' => 'datetime') + , array('name' =>'deleted', 'type' =>'bool', 'len'=>'1', 'default'=>'0','required'=>false) + ) , 'indices' => array ( + array('name' =>'contacts_userspk', 'type' =>'primary', 'fields'=>array('id')) + , array('name' =>'idx_con_users_con', 'type' =>'index', 'fields'=>array('contact_id')) + , array('name' =>'idx_con_users_user', 'type' =>'index', 'fields'=>array('user_id')) + , array('name' =>'idx_contacts_users', 'type' =>'alternate_key', 'fields'=>array('contact_id', 'user_id')) + ) + , 'relationships' => array ('contacts_users' => array('lhs_module'=> 'Contacts', 'lhs_table'=> 'contacts', 'lhs_key' => 'id', + 'rhs_module'=> 'Users', 'rhs_table'=> 'users', 'rhs_key' => 'id', + 'relationship_type'=>'many-to-many', + 'join_table'=> 'contacts_users', 'join_key_lhs'=>'contact_id', 'join_key_rhs'=>'user_id')) + +) +?> \ No newline at end of file diff --git a/metadata/custom_fieldsMetaData.php b/metadata/custom_fieldsMetaData.php new file mode 100644 index 00000000..76f18c59 --- /dev/null +++ b/metadata/custom_fieldsMetaData.php @@ -0,0 +1,57 @@ + 'custom_fields' + , 'fields' => array ( + array('name' =>'bean_id', 'type' =>'varchar', 'len'=>'36') + , array('name' =>'set_num', 'type' =>'int', 'len'=>'11', 'default'=>'0') + , array('name' =>'field0', 'type' =>'varchar', 'len'=>'255') + , array('name' =>'field1', 'type' =>'varchar', 'len'=>'255') + , array('name' =>'field2', 'type' =>'varchar', 'len'=>'255') + , array('name' =>'field3', 'type' =>'varchar', 'len'=>'255') + , array('name' =>'field4', 'type' =>'varchar', 'len'=>'255') + , array('name' =>'field5', 'type' =>'varchar', 'len'=>'255') + , array('name' =>'field6', 'type' =>'varchar', 'len'=>'255') + , array('name' =>'field7', 'type' =>'varchar', 'len'=>'255') + , array('name' =>'field8', 'type' =>'varchar', 'len'=>'255') + , array('name' =>'field9', 'type' =>'varchar', 'len'=>'255') + , array('name' =>'deleted', 'type' =>'bool', 'len'=>'1', 'default'=>'0') + ) , 'indices' => array ( + array('name' =>'idx_beanid_set_num', 'type' =>'index', 'fields'=>array('bean_id','set_num')) + ) + ) +?> diff --git a/metadata/documents_accountsMetaData.php b/metadata/documents_accountsMetaData.php new file mode 100644 index 00000000..b7a8c48b --- /dev/null +++ b/metadata/documents_accountsMetaData.php @@ -0,0 +1,124 @@ + 'many-to-many', + 'relationships' => + array ( + 'documents_accounts' => + array ( + 'lhs_module' => 'Documents', + 'lhs_table' => 'documents', + 'lhs_key' => 'id', + 'rhs_module' => 'Accounts', + 'rhs_table' => 'accounts', + 'rhs_key' => 'id', + 'relationship_type' => 'many-to-many', + 'join_table' => 'documents_accounts', + 'join_key_lhs' => 'document_id', + 'join_key_rhs' => 'account_id', + ), + ), + 'table' => 'documents_accounts', + 'fields' => + array ( + 0 => + array ( + 'name' => 'id', + 'type' => 'varchar', + 'len' => 36, + ), + 1 => + array ( + 'name' => 'date_modified', + 'type' => 'datetime', + ), + 2 => + array ( + 'name' => 'deleted', + 'type' => 'bool', + 'len' => '1', + 'default' => '0', + 'required' => true, + ), + 3 => + array ( + 'name' => 'document_id', + 'type' => 'varchar', + 'len' => 36, + ), + 4 => + array ( + 'name' => 'account_id', + 'type' => 'varchar', + 'len' => 36, + ), + ), + 'indices' => + array ( + 0 => + array ( + 'name' => 'documents_accountsspk', + 'type' => 'primary', + 'fields' => + array ( + 0 => 'id', + ), + ), + 1 => + array ( + 'name' => 'documents_accounts_account_id', + 'type' => 'alternate_key', + 'fields' => + array ( + 0 => 'account_id', + 1 => 'document_id', + ), + ), + 2 => + array ( + 'name' => 'documents_accounts_document_id', + 'type' => 'alternate_key', + 'fields' => + array ( + 0 => 'document_id', + 1 => 'account_id', + ), + ), + ), +); + diff --git a/metadata/documents_bugsMetaData.php b/metadata/documents_bugsMetaData.php new file mode 100644 index 00000000..e77f83be --- /dev/null +++ b/metadata/documents_bugsMetaData.php @@ -0,0 +1,124 @@ + 'many-to-many', + 'relationships' => + array ( + 'documents_bugs' => + array ( + 'lhs_module' => 'Documents', + 'lhs_table' => 'documents', + 'lhs_key' => 'id', + 'rhs_module' => 'Bugs', + 'rhs_table' => 'bugs', + 'rhs_key' => 'id', + 'relationship_type' => 'many-to-many', + 'join_table' => 'documents_bugs', + 'join_key_lhs' => 'document_id', + 'join_key_rhs' => 'bug_id', + ), + ), + 'table' => 'documents_bugs', + 'fields' => + array ( + 0 => + array ( + 'name' => 'id', + 'type' => 'varchar', + 'len' => 36, + ), + 1 => + array ( + 'name' => 'date_modified', + 'type' => 'datetime', + ), + 2 => + array ( + 'name' => 'deleted', + 'type' => 'bool', + 'len' => '1', + 'default' => '0', + 'required' => true, + ), + 3 => + array ( + 'name' => 'document_id', + 'type' => 'varchar', + 'len' => 36, + ), + 4 => + array ( + 'name' => 'bug_id', + 'type' => 'varchar', + 'len' => 36, + ), + ), + 'indices' => + array ( + 0 => + array ( + 'name' => 'documents_bugsspk', + 'type' => 'primary', + 'fields' => + array ( + 0 => 'id', + ), + ), + 1 => + array ( + 'name' => 'documents_bugs_bug_id', + 'type' => 'alternate_key', + 'fields' => + array ( + 0 => 'bug_id', + 1 => 'document_id', + ), + ), + 2 => + array ( + 'name' => 'documents_bugs_document_id', + 'type' => 'alternate_key', + 'fields' => + array ( + 0 => 'document_id', + 1 => 'bug_id', + ), + ), + ), +); + diff --git a/metadata/documents_casesMetaData.php b/metadata/documents_casesMetaData.php new file mode 100644 index 00000000..02da9a92 --- /dev/null +++ b/metadata/documents_casesMetaData.php @@ -0,0 +1,124 @@ + 'many-to-many', + 'relationships' => + array ( + 'documents_cases' => + array ( + 'lhs_module' => 'Documents', + 'lhs_table' => 'documents', + 'lhs_key' => 'id', + 'rhs_module' => 'Cases', + 'rhs_table' => 'cases', + 'rhs_key' => 'id', + 'relationship_type' => 'many-to-many', + 'join_table' => 'documents_cases', + 'join_key_lhs' => 'document_id', + 'join_key_rhs' => 'case_id', + ), + ), + 'table' => 'documents_cases', + 'fields' => + array ( + 0 => + array ( + 'name' => 'id', + 'type' => 'varchar', + 'len' => 36, + ), + 1 => + array ( + 'name' => 'date_modified', + 'type' => 'datetime', + ), + 2 => + array ( + 'name' => 'deleted', + 'type' => 'bool', + 'len' => '1', + 'default' => '0', + 'required' => true, + ), + 3 => + array ( + 'name' => 'document_id', + 'type' => 'varchar', + 'len' => 36, + ), + 4 => + array ( + 'name' => 'case_id', + 'type' => 'varchar', + 'len' => 36, + ), + ), + 'indices' => + array ( + 0 => + array ( + 'name' => 'documents_casesspk', + 'type' => 'primary', + 'fields' => + array ( + 0 => 'id', + ), + ), + 1 => + array ( + 'name' => 'documents_cases_case_id', + 'type' => 'alternate_key', + 'fields' => + array ( + 0 => 'case_id', + 1 => 'document_id', + ), + ), + 2 => + array ( + 'name' => 'documents_cases_document_id', + 'type' => 'alternate_key', + 'fields' => + array ( + 0 => 'document_id', + 1 => 'case_id', + ), + ), + ), +); + diff --git a/metadata/documents_contactsMetaData.php b/metadata/documents_contactsMetaData.php new file mode 100644 index 00000000..329cb601 --- /dev/null +++ b/metadata/documents_contactsMetaData.php @@ -0,0 +1,124 @@ + 'many-to-many', + 'relationships' => + array ( + 'documents_contacts' => + array ( + 'lhs_module' => 'Documents', + 'lhs_table' => 'documents', + 'lhs_key' => 'id', + 'rhs_module' => 'Contacts', + 'rhs_table' => 'contacts', + 'rhs_key' => 'id', + 'relationship_type' => 'many-to-many', + 'join_table' => 'documents_contacts', + 'join_key_lhs' => 'document_id', + 'join_key_rhs' => 'contact_id', + ), + ), + 'table' => 'documents_contacts', + 'fields' => + array ( + 0 => + array ( + 'name' => 'id', + 'type' => 'varchar', + 'len' => 36, + ), + 1 => + array ( + 'name' => 'date_modified', + 'type' => 'datetime', + ), + 2 => + array ( + 'name' => 'deleted', + 'type' => 'bool', + 'len' => '1', + 'default' => '0', + 'required' => true, + ), + 3 => + array ( + 'name' => 'document_id', + 'type' => 'varchar', + 'len' => 36, + ), + 4 => + array ( + 'name' => 'contact_id', + 'type' => 'varchar', + 'len' => 36, + ), + ), + 'indices' => + array ( + 0 => + array ( + 'name' => 'documents_contactsspk', + 'type' => 'primary', + 'fields' => + array ( + 0 => 'id', + ), + ), + 1 => + array ( + 'name' => 'documents_contacts_contact_id', + 'type' => 'alternate_key', + 'fields' => + array ( + 0 => 'contact_id', + 1 => 'document_id', + ), + ), + 2 => + array ( + 'name' => 'documents_contacts_document_id', + 'type' => 'alternate_key', + 'fields' => + array ( + 0 => 'document_id', + 1 => 'contact_id', + ), + ), + ), +); + diff --git a/metadata/documents_opportunitiesMetaData.php b/metadata/documents_opportunitiesMetaData.php new file mode 100644 index 00000000..7fd748a7 --- /dev/null +++ b/metadata/documents_opportunitiesMetaData.php @@ -0,0 +1,124 @@ + 'many-to-many', + 'relationships' => + array ( + 'documents_opportunities' => + array ( + 'lhs_module' => 'Documents', + 'lhs_table' => 'documents', + 'lhs_key' => 'id', + 'rhs_module' => 'Opportunities', + 'rhs_table' => 'opportunities', + 'rhs_key' => 'id', + 'relationship_type' => 'many-to-many', + 'join_table' => 'documents_opportunities', + 'join_key_lhs' => 'document_id', + 'join_key_rhs' => 'opportunity_id', + ), + ), + 'table' => 'documents_opportunities', + 'fields' => + array ( + 0 => + array ( + 'name' => 'id', + 'type' => 'varchar', + 'len' => 36, + ), + 1 => + array ( + 'name' => 'date_modified', + 'type' => 'datetime', + ), + 2 => + array ( + 'name' => 'deleted', + 'type' => 'bool', + 'len' => '1', + 'default' => '0', + 'required' => true, + ), + 3 => + array ( + 'name' => 'document_id', + 'type' => 'varchar', + 'len' => 36, + ), + 4 => + array ( + 'name' => 'opportunity_id', + 'type' => 'varchar', + 'len' => 36, + ), + ), + 'indices' => + array ( + 0 => + array ( + 'name' => 'documents_opportunitiesspk', + 'type' => 'primary', + 'fields' => + array ( + 0 => 'id', + ), + ), + 1 => + array ( + 'name' => 'idx_docu_opps_oppo_id', + 'type' => 'alternate_key', + 'fields' => + array ( + 0 => 'opportunity_id', + 1 => 'document_id', + ), + ), + 2 => + array ( + 'name' => 'idx_docu_oppo_docu_id', + 'type' => 'alternate_key', + 'fields' => + array ( + 0 => 'document_id', + 1 => 'opportunity_id', + ), + ), + ), +); + diff --git a/metadata/email_addressesMetaData.php b/metadata/email_addressesMetaData.php new file mode 100644 index 00000000..694802d1 --- /dev/null +++ b/metadata/email_addressesMetaData.php @@ -0,0 +1,245 @@ + 'email_addresses', + 'fields' => array( + 'id' => array( + 'name' => 'id', + 'type' => 'id', + 'vname' => 'LBL_EMAIL_ADDRESS_ID', + 'required' => true, + ), + 'email_address' =>array( + 'name' => 'email_address', + 'type' => 'varchar', + 'vname' => 'LBL_EMAIL_ADDRESS', + 'length' => 100, + 'required' => true, + ), + 'email_address_caps' => array( + 'name' => 'email_address_caps', + 'type' => 'varchar', + 'vname' => 'LBL_EMAIL_ADDRESS_CAPS', + 'length' => 100, + 'required' => true, + 'reportable' => false, + ), + 'invalid_email' => array( + 'name' => 'invalid_email', + 'type' => 'bool', + 'default' => 0, + 'vname' => 'LBL_INVALID_EMAIL', + ), + 'opt_out' => array( + 'name' => 'opt_out', + 'type' => 'bool', + 'default' => 0, + 'vname' => 'LBL_OPT_OUT', + ), + 'date_created' => array( + 'name' => 'date_created', + 'type' => 'datetime', + 'vname' => 'LBL_DATE_CREATE', + ), + 'date_modified' => array( + 'name' => 'date_modified', + 'type' => 'datetime', + 'vname' => 'LBL_DATE_MODIFIED', + ), + 'deleted' => array( + 'name' => 'deleted', + 'type' => 'bool', + 'default' => 0, + 'vname' => 'LBL_DELETED', + ), + ), + 'indices' => array( + array( + 'name' => 'email_addressespk', + 'type' => 'primary', + 'fields' => array('id') + ), + array( + 'name' => 'idx_ea_caps_opt_out_invalid', + 'type' => 'index', + 'fields' => array('email_address_caps','opt_out','invalid_email') + ), + array( + 'name' => 'idx_ea_opt_out_invalid', + 'type' => 'index', + 'fields' => array('email_address', 'opt_out', 'invalid_email') + ), + ), +); + +// hack for installer +$dictionary['EmailAddress'] = $dictionary['email_addresses']; + +/** + * Relationship table linking email addresses to an instance of a Sugar Email object + */ +$dictionary['emails_email_addr_rel'] = array( + 'table' => 'emails_email_addr_rel', + 'comment' => 'Normalization of multi-address fields such as To:, CC:, BCC', + 'fields' => array( + 'id' => array( + 'name' => 'id', + 'type' => 'id', + 'required' => true, + 'comment' => 'GUID', + ), + 'email_id' => array( + 'name' => 'email_id', + 'type' => 'id', + 'required' => true, + 'comment' => 'Foriegn key to emails table NOT unique', + ), + 'address_type' => array( + 'name' => 'address_type', + 'type' => 'varchar', + 'len' => 4, + 'required' => true, + 'comment' => 'Type of entry, TO, CC, or BCC', + ), + 'email_address_id' => array( + 'name' => 'email_address_id', + 'type' => 'id', + 'required' => true, + 'comment' => 'Foriegn key to emails table NOT unique', + ), + 'deleted' => array( + 'name' => 'deleted', + 'type' => 'bool', + 'default' => 0, + ), + ), + 'indices' => array( + array( + 'name' => 'emails_email_addr_relpk', + 'type' => 'primary', + 'fields' => array('id'), + ), + array( + 'name' => 'idx_eearl_email_id', + 'type' => 'index', + 'fields' => array('email_id', 'address_type'), + ), + array( + 'name' => 'idx_eearl_address_id', + 'type' => 'index', + 'fields' => array('email_address_id'), + ), + ), +); + +/** + * Relationship table linking email addresses to various SugarBeans or type Person + */ +$dictionary['email_addr_bean_rel'] = array( + 'table' => 'email_addr_bean_rel', + 'fields' => array( + array( + 'name' => 'id', + 'type' => 'id', + 'required' => true, + ), + array( + 'name' => 'email_address_id', + 'type' => 'id', + 'required' => true, + ), + array( + 'name' => 'bean_id', + 'type' => 'id', + 'required' => true, + ), + array( + 'name' => 'bean_module', + 'type' => 'varchar', + 'len' => 100, + 'required' => true, + ), + array( + 'name' => 'primary_address', + 'type' => 'bool', + 'default' => '0', + ), + array( + 'name' => 'reply_to_address', + 'type' => 'bool', + 'default' => '0', + ), + array( + 'name' => 'date_created', + 'type' => 'datetime' + ), + array( + 'name' => 'date_modified', + 'type' => 'datetime' + ), + array( + 'name' => 'deleted', + 'type' => 'bool', + 'default' => 0, + ), + ), + 'indices' => array( + array( + 'name' => 'email_addresses_relpk', + 'type' => 'primary', + 'fields' => array('id') + ), + array( + 'name' => 'idx_email_address_id', + 'type' => 'index', + 'fields' => array('email_address_id') + ), + array( + 'name' => 'idx_bean_id', + 'type' => 'index', + 'fields' => array('bean_id', 'bean_module'), + ), + ), + 'relationships' => array ( + //Defined in Person/Company template vardefs + ), +); diff --git a/metadata/email_cacheMetaData.php b/metadata/email_cacheMetaData.php new file mode 100644 index 00000000..a100daad --- /dev/null +++ b/metadata/email_cacheMetaData.php @@ -0,0 +1,188 @@ + 'email_cache', + 'fields' => array( + 'ie_id' => array( + 'name' => 'ie_id', + 'type' => 'id', + 'required' => 'true', + ), + 'mbox' => array( + 'name' => 'mbox', + 'type' => 'varchar', + 'len' => 60, + 'required' => true, + ), + 'subject' => array( + 'name' => 'subject', + 'type' => 'varchar', + 'len' => 255, + 'required' => false, + ), + 'fromaddr' => array( + 'name' => 'fromaddr', + 'type' => 'varchar', + 'len' => 100, + 'required' => false, + ), + 'toaddr' => array( + 'name' => 'toaddr', + 'type' => 'varchar', + 'len' => 255, + 'required' => false, + ), + 'senddate' => array( + 'name' => 'senddate', + 'type' => 'datetime', + 'required' => false, + ), + 'message_id' => array( + 'name' => 'message_id', + 'type' => 'varchar', + 'len' => 255, + 'required' => false, + ), + 'mailsize' => array( + 'name' => 'mailsize', + 'type' => 'uint', + 'len' => 16, + 'required' => true, + ), + 'imap_uid' => array( + 'name' => 'imap_uid', + 'type' => 'uint', + 'len' => 32, + 'required' => true, + ), + 'msgno' => array( + 'name' => 'msgno', + 'type' => 'uint', + 'len' => 32, + 'required' => false, + ), + 'recent' => array( + 'name' => 'recent', + 'type' => 'tinyint', + 'len' => 1, + 'required' => true, + ), + 'flagged' => array( + 'name' => 'flagged', + 'type' => 'tinyint', + 'len' => 1, + 'required' => true, + ), + 'answered' => array( + 'name' => 'answered', + 'type' => 'tinyint', + 'len' => 1, + 'required' => true, + ), + 'deleted' => array( + 'name' => 'deleted', + 'type' => 'tinyint', + 'len' => 1, + 'required' => false, + ), + 'seen' => array( + 'name' => 'seen', + 'type' => 'tinyint', + 'len' => 1, + 'required' => true, + ), + 'draft' => array( + 'name' => 'draft', + 'type' => 'tinyint', + 'len' => 1, + 'required' => true, + ), + ), + 'indices' => array( + array( + 'name' => 'idx_ie_id', + 'type' => 'index', + 'fields' => array( + 'ie_id', + ), + ), + array( + 'name' => 'idx_mail_date', + 'type' => 'index', + 'fields' => array( + 'ie_id', + 'mbox', + 'senddate', + ) + ), + array( + 'name' => 'idx_mail_from', + 'type' => 'index', + 'fields' => array( + 'ie_id', + 'mbox', + 'fromaddr', + ) + ), + array( + 'name' => 'idx_mail_subj', + 'type' => 'index', + 'fields' => array( + 'subject', + ) + ), + array( + 'name' => 'idx_mail_to', + 'type' => 'index', + 'fields' => array( + 'toaddr', + ) + ), + + ), +); \ No newline at end of file diff --git a/metadata/email_marketing_prospect_listsMetaData.php b/metadata/email_marketing_prospect_listsMetaData.php new file mode 100644 index 00000000..4356f509 --- /dev/null +++ b/metadata/email_marketing_prospect_listsMetaData.php @@ -0,0 +1,99 @@ + 'email_marketing_prospect_lists', + + 'fields' => array ( + array ( + 'name' => 'id', + 'type' => 'varchar', + 'len' => '36', + ), + array ( + 'name' => 'prospect_list_id', + 'type' => 'varchar', + 'len' => '36', + ), + array ( + 'name' => 'email_marketing_id', + 'type' => 'varchar', + 'len' => '36', + ), + array ( + 'name' => 'date_modified', + 'type' => 'datetime' + ), + array ( + 'name' => 'deleted', + 'type' => 'bool', + 'len' => '1', + 'default' => '0' + ), + ), + 'indices' => array ( + array ( + 'name' => 'email_mp_listspk', + 'type' => 'primary', + 'fields' => array ( 'id' ) + ), + array ( + 'name' => 'email_mp_prospects', + 'type' => 'alternate_key', + 'fields' => array ( 'email_marketing_id', + 'prospect_list_id' + ) + ), + ), + + 'relationships' => array ( + 'email_marketing_prospect_lists' => array( + 'lhs_module'=> 'EmailMarketing', + 'lhs_table'=> 'email_marketing', + 'lhs_key' => 'id', + 'rhs_module'=> 'ProspectLists', + 'rhs_table'=> 'prospect_lists', + 'rhs_key' => 'id', + 'relationship_type'=>'many-to-many', + 'join_table'=> 'email_marketing_prospect_lists', + 'join_key_lhs'=>'email_marketing_id', + 'join_key_rhs'=>'prospect_list_id', + ), + ) +) +?> \ No newline at end of file diff --git a/metadata/emails_beansMetaData.php b/metadata/emails_beansMetaData.php new file mode 100644 index 00000000..36d24210 --- /dev/null +++ b/metadata/emails_beansMetaData.php @@ -0,0 +1,383 @@ + 'emails_beans', + 'fields' => array( + array( + 'name' => 'id', + 'type' => 'varchar', + 'dbType' => 'id', + 'len' => '36' + ), + array( + 'name' => 'email_id', + 'type' => 'varchar', + 'dbType' => 'id', + 'len' => '36', + 'comment' => 'FK to emails table', + ), + array( + 'name' => 'bean_id', + 'dbType' => 'id', + 'type' => 'varchar', + 'len' => '36', + 'comment' => 'FK to various beans\'s tables', + ), + array( + 'name' => 'bean_module', + 'type' => 'varchar', + 'len' => '100', + 'comment' => 'bean\'s Module', + ), + array( 'name' => 'campaign_data', + 'type' => 'text', + ), + array( + 'name' => 'date_modified', + 'type' => 'datetime' + ), + array( + 'name' => 'deleted', + 'type' => 'bool', + 'len' => '1', + 'default' => '0', + 'required' => false + ) + ), + 'indices' => array( + array( + 'name' => 'emails_beanspk', + 'type' => 'primary', + 'fields' => array('id') + ), + array( + 'name' => 'idx_emails_beans_bean_id', + 'type' => 'index', + 'fields' => array('bean_id') + ), + array( + 'name' => 'idx_emails_beans_email_bean', + 'type' => 'alternate_key', + 'fields' => array('email_id', 'bean_id', 'deleted') + ), + ), + 'relationships' => array( + 'emails_accounts_rel' => array( + 'lhs_module' => 'Emails', + 'lhs_table' => 'emails', + 'lhs_key' => 'id', + 'rhs_module' => 'Accounts', + 'rhs_table' => 'accounts', + 'rhs_key' => 'id', + 'relationship_type' => 'many-to-many', + 'join_table' => 'emails_beans', + 'join_key_lhs' => 'email_id', + 'join_key_rhs' => 'bean_id', + 'relationship_role_column' => 'bean_module', + 'relationship_role_column_value' => 'Accounts', + ), + 'emails_bugs_rel' => array( + 'lhs_module' => 'Emails', + 'lhs_table' => 'emails', + 'lhs_key' => 'id', + 'rhs_module' => 'Bugs', + 'rhs_table' => 'bugs', + 'rhs_key' => 'id', + 'relationship_type' => 'many-to-many', + 'join_table' => 'emails_beans', + 'join_key_lhs' => 'email_id', + 'join_key_rhs' => 'bean_id', + 'relationship_role_column' => 'bean_module', + 'relationship_role_column_value' => 'Bugs', + ), + 'emails_cases_rel' => array( + 'lhs_module' => 'Emails', + 'lhs_table' => 'emails', + 'lhs_key' => 'id', + 'rhs_module' => 'Cases', + 'rhs_table' => 'cases', + 'rhs_key' => 'id', + 'relationship_type' => 'many-to-many', + 'join_table' => 'emails_beans', + 'join_key_lhs' => 'email_id', + 'join_key_rhs' => 'bean_id', + 'relationship_role_column' => 'bean_module', + 'relationship_role_column_value' => 'Cases', + ), + 'emails_contacts_rel' => array( + 'lhs_module' => 'Emails', + 'lhs_table' => 'emails', + 'lhs_key' => 'id', + 'rhs_module' => 'Contacts', + 'rhs_table' => 'contacts', + 'rhs_key' => 'id', + 'relationship_type' => 'many-to-many', + 'relationship_role_column' => 'bean_module', + 'relationship_role_column_value' => 'Contacts', + 'join_table' => 'emails_beans', + 'join_key_lhs' => 'email_id', + 'join_key_rhs' => 'bean_id', + 'relationship_role_column' => 'bean_module', + 'relationship_role_column_value' => 'Contacts', + ), + 'emails_leads_rel' => array( + 'lhs_module' => 'Emails', + 'lhs_table' => 'emails', + 'lhs_key' => 'id', + 'rhs_module' => 'Leads', + 'rhs_table' => 'leads', + 'rhs_key' => 'id', + 'relationship_type' => 'many-to-many', + 'join_table' => 'emails_beans', + 'join_key_lhs' => 'email_id', + 'join_key_rhs' => 'bean_id', + 'relationship_role_column' => 'bean_module', + 'relationship_role_column_value' => 'Leads', + ), + 'emails_opportunities_rel' => array( + 'lhs_module' => 'Emails', + 'lhs_table' => 'emails', + 'lhs_key' => 'id', + 'rhs_module' => 'Opportunities', + 'rhs_table' => 'opportunities', + 'rhs_key' => 'id', + 'relationship_type' => 'many-to-many', + 'join_table' => 'emails_beans', + 'join_key_lhs' => 'email_id', + 'join_key_rhs' => 'bean_id', + 'relationship_role_column' => 'bean_module', + 'relationship_role_column_value' => 'Opportunities', + ), + 'emails_tasks_rel' => array( + 'lhs_module' => 'Emails', + 'lhs_table' => 'emails', + 'lhs_key' => 'id', + 'rhs_module' => 'Tasks', + 'rhs_table' => 'tasks', + 'rhs_key' => 'id', + 'relationship_type' => 'many-to-many', + 'join_table' => 'emails_beans', + 'join_key_lhs' => 'email_id', + 'join_key_rhs' => 'bean_id', + 'relationship_role_column' => 'bean_module', + 'relationship_role_column_value' => 'Tasks', + ), + 'emails_users_rel' => array( + 'lhs_module' => 'Emails', + 'lhs_table' => 'emails', + 'lhs_key' => 'id', + 'rhs_module' => 'Users', + 'rhs_table' => 'users', + 'rhs_key' => 'id', + 'relationship_type' => 'many-to-many', + 'join_table' => 'emails_beans', + 'join_key_lhs' => 'email_id', + 'join_key_rhs' => 'bean_id', + 'relationship_role_column' => 'bean_module', + 'relationship_role_column_value' => 'Users', + ), + 'emails_project_task_rel' => array( + 'lhs_module' => 'Emails', + 'lhs_table' => 'emails', + 'lhs_key' => 'id', + 'rhs_module' => 'ProjectTask', + 'rhs_table' => 'project_task', + 'rhs_key' => 'id', + 'relationship_type' => 'many-to-many', + 'join_table' => 'emails_beans', + 'join_key_lhs' => 'email_id', + 'join_key_rhs' => 'bean_id', + 'relationship_role_column' => 'bean_module', + 'relationship_role_column_value' => 'ProjectTask', + ), + 'emails_projects_rel' => array( + 'lhs_module' => 'Emails', + 'lhs_table' => 'emails', + 'lhs_key' => 'id', + 'rhs_module' => 'Project', + 'rhs_table' => 'project', + 'rhs_key' => 'id', + 'relationship_type' => 'many-to-many', + 'join_table' => 'emails_beans', + 'join_key_lhs' => 'email_id', + 'join_key_rhs' => 'bean_id', + 'relationship_role_column' => 'bean_module', + 'relationship_role_column_value' => 'Project', + ), + 'emails_prospects_rel' => array( + 'lhs_module' => 'Emails', + 'lhs_table' => 'emails', + 'lhs_key' => 'id', + 'rhs_module' => 'Prospects', + 'rhs_table' => 'prospects', + 'rhs_key' => 'id', + 'relationship_type' => 'many-to-many', + 'join_table' => 'emails_beans', + 'join_key_lhs' => 'email_id', + 'join_key_rhs' => 'bean_id', + 'relationship_role_column' => 'bean_module', + 'relationship_role_column_value' => 'Prospects', + ), + 'emails_quotes' => array( + 'lhs_module' => 'Emails', + 'lhs_table' => 'emails', + 'lhs_key' => 'id', + 'rhs_module' => 'Quotes', + 'rhs_table' => 'quotes', + 'rhs_key' => 'id', + 'relationship_type' => 'many-to-many', + 'join_table' => 'emails_beans', + 'join_key_lhs' => 'email_id', + 'join_key_rhs' => 'bean_id', + 'relationship_role_column' => 'bean_module', + 'relationship_role_column_value' => 'Quotes', + ), + ) +); + + +/** + * Large text field table, shares a 1:1 with the emails table. Moving all longtext fields to this table allows more + * effiencient email management and full-text search capabilities with MyISAM for MySQL. + */ +$dictionary['emails_text'] = array( + 'table' => 'emails_text', + 'comment' => 'Large email text fields', + 'mysqlengine' => 'MyISAM', + 'fields' => array( + 'email_id' => array ( + 'name' => 'email_id', + 'vname' => 'LBL_ID', + 'type' => 'id', + 'dbType' => 'id', + 'len' => 36, + 'required' => true, + 'reportable' => true, + 'comment' => 'Foriegn key to emails table', + ), + 'from_addr' => array ( + 'name' => 'from_addr', + 'vname' => 'LBL_FROM', + 'type' => 'varchar', + 'len' => 255, + 'comment' => 'Email address of person who send the email', + ), + 'reply_to_addr' => array ( + 'name' => 'reply_to_addr', + 'vname' => 'LBL_REPLY_TO', + 'type' => 'varchar', + 'len' => 255, + 'comment' => 'reply to email address', + ), + 'to_addrs' => array ( + 'name' => 'to_addrs', + 'vname' => 'LBL_TO', + 'type' => 'text', + 'comment' => 'Email address(es) of person(s) to receive the email', + ), + 'cc_addrs' => array ( + 'name' => 'cc_addrs', + 'vname' => 'LBL_CC', + 'type' => 'text', + 'comment' => 'Email address(es) of person(s) to receive a carbon copy of the email', + ), + 'bcc_addrs' => array ( + 'name' => 'bcc_addrs', + 'vname' => 'LBL_BCC', + 'type' => 'text', + 'comment' => 'Email address(es) of person(s) to receive a blind carbon copy of the email', + ), + 'description' => array ( + 'name' => 'description', + 'vname' => 'LBL_TEXT_BODY', + 'type' => 'longtext', + 'reportable' => false, + 'comment' => 'Email body in plain text', + ), + 'description_html' => array ( + 'name' => 'description_html', + 'vname' => 'LBL_HTML_BODY', + 'type' => 'longtext', + 'reportable' => false, + 'comment' => 'Email body in HTML format', + ), + 'raw_source' => array ( + 'name' => 'raw_source', + 'vname' => 'LBL_RAW', + 'type' => 'longtext', + 'reportable' => false, + 'comment' => 'Full raw source of email', + ), + 'deleted' => array( + 'name' => 'deleted', + 'type' => 'bool', + 'default' => 0, + ), + ), + 'indices' => array( + array( + 'name' => 'emails_textpk', + 'type' => 'primary', + 'fields' => array('email_id') + ), + array( + 'name' => 'emails_textfromaddr', + 'type' => 'index', + 'fields' => array('from_addr') + ), + ), +); + + + + + + + + + + diff --git a/metadata/fields_meta_dataMetaData.php b/metadata/fields_meta_dataMetaData.php new file mode 100644 index 00000000..faeb1bdf --- /dev/null +++ b/metadata/fields_meta_dataMetaData.php @@ -0,0 +1,39 @@ + diff --git a/metadata/foldersMetaData.php b/metadata/foldersMetaData.php new file mode 100644 index 00000000..1516d488 --- /dev/null +++ b/metadata/foldersMetaData.php @@ -0,0 +1,205 @@ + 'folders', + 'fields' => array( + array( + 'name' => 'id', + 'type' => 'id', + 'required' => true, + ), + array( + 'name' => 'name', + 'type' => 'varchar', + 'len' => 25, + 'required' => true, + ), + array( + 'name' => 'folder_type', + 'type' => 'varchar', + 'len' => 25, + 'default' => NULL, + ), + array( + 'name' => 'parent_folder', + 'type' => 'id', + 'required' => false, + ), + array( + 'name' => 'has_child', + 'type' => 'bool', + 'default' => '0', + ), + array( + 'name' => 'is_group', + 'type' => 'bool', + 'default' => '0', + ), + array( + 'name' => 'is_dynamic', + 'type' => 'bool', + 'default' => '0', + ), + array( + 'name' => 'dynamic_query', + 'type' => 'text', + ), + array( + 'name' => 'assign_to_id', + 'type' => 'id', + 'required' => false, + ), + + array( + 'name' => 'created_by', + 'type' => 'id', + 'required' => true, + ), + array( + 'name' => 'modified_by', + 'type' => 'id', + 'required' => true, + ), + array( + 'name' => 'deleted', + 'type' => 'bool', + 'default' => '0', + ), + ), + 'indices' => array( + array( + 'name' => 'folderspk', + 'type' => 'primary', + 'fields' => array('id') + ), + array( + 'name' => 'idx_parent_folder', + 'type' => 'index', + 'fields' => array('parent_folder') + ), + ), +); + +$dictionary['folders_subscriptions'] = array( + 'table' => 'folders_subscriptions', + 'fields' => array( + array( + 'name' => 'id', + 'type' => 'id', + 'required' => true, + ), + array( + 'name' => 'folder_id', + 'type' => 'id', + 'required' => true, + ), + array( + 'name' => 'assigned_user_id', + 'type' => 'id', + 'required' => true, + ), + ), + 'indices' => array( + array( + 'name' => 'folders_subscriptionspk', + 'type' => 'primary', + 'fields' => array('id') + ), + array( + 'name' => 'idx_folder_id_assigned_user_id', + 'type' => 'index', + 'fields' => array('folder_id', 'assigned_user_id') + ), + ), +); + +$dictionary['folders_rel'] = array( + 'table' => 'folders_rel', + 'fields' => array( + array( + 'name' => 'id', + 'type' => 'id', + 'required' => true, + ), + array( + 'name' => 'folder_id', + 'type' => 'id', + 'required' => true, + ), + array( + 'name' => 'polymorphic_module', + 'type' => 'varchar', + 'len' => 25, + 'required' => true, + ), + array( + 'name' => 'polymorphic_id', + 'type' => 'id', + 'required' => true, + ), + array( + 'name' => 'deleted', + 'type' => 'bool', + 'default' => '0', + ), + ), + 'indices' => array( + array( + 'name' => 'folders_relpk', + 'type' => 'primary', + 'fields' => array('id'), + ), + array( + 'name' => 'idx_poly_module_poly_id', + 'type' => 'index', + 'fields' => array('polymorphic_module', 'polymorphic_id'), + ), + array( + 'name' => 'idx_folders_rel_folder_id', + 'type' => 'index', + 'fields' => array('folder_id'), + ), + ), +); diff --git a/metadata/import_mapsMetaData.php b/metadata/import_mapsMetaData.php new file mode 100644 index 00000000..faeb1bdf --- /dev/null +++ b/metadata/import_mapsMetaData.php @@ -0,0 +1,39 @@ + diff --git a/metadata/inboundEmail_autoreplyMetaData.php b/metadata/inboundEmail_autoreplyMetaData.php new file mode 100644 index 00000000..b8983064 --- /dev/null +++ b/metadata/inboundEmail_autoreplyMetaData.php @@ -0,0 +1,105 @@ + 'inbound_email_autoreply', + 'fields' => array ( + 'id' => array ( + 'name' => 'id', + 'vname' => 'LBL_ID', + 'type' => 'id', + 'required' => true, + 'reportable' => false, + ), + 'deleted' => array ( + 'name' => 'deleted', + 'vname' => 'LBL_DELETED', + 'type' => 'bool', + 'required' => false, + 'default' => '0', + 'reportable'=>false, + ), + 'date_entered' => array ( + 'name' => 'date_entered', + 'vname' => 'LBL_DATE_ENTERED', + 'type' => 'datetime', + 'required' => true, + ), + 'date_modified' => array ( + 'name' => 'date_modified', + 'vname' => 'LBL_DATE_MODIFIED', + 'type' => 'datetime', + 'required' => true, + ), + 'autoreplied_to' => array ( + 'name' => 'autoreplied_to', + 'vname' => 'LBL_AUTOREPLIED_TO', + 'type' => 'varchar', + 'len' => 100, + 'required' => true, + 'reportable'=>false, + ), + 'ie_id' => array( + 'name' => 'ie_id', + 'vname' => 'LBL_INBOUNDEMAIL_ID', + 'type' => 'id', + 'len' => '36', + 'default' => '', + 'required' => true, + 'reportable' => false, + ), + ), + 'indices' => array ( + array( + 'name' => 'ie_autopk', + 'type' =>'primary', + 'fields' => array( + 'id' + ) + ), + array( + 'name' =>'idx_ie_autoreplied_to', + 'type'=>'index', + 'fields' => array( + 'autoreplied_to' + ) + ), + ), /* end indices */ + 'relationships' => array ( + ), /* end relationships */ +); + +?> diff --git a/metadata/inboundEmail_cacheTimestampMetaData.php b/metadata/inboundEmail_cacheTimestampMetaData.php new file mode 100644 index 00000000..dd9b02e5 --- /dev/null +++ b/metadata/inboundEmail_cacheTimestampMetaData.php @@ -0,0 +1,68 @@ + 'inbound_email_cache_ts', + 'fields' => array ( + 'id' => array ( + 'name' => 'id', + 'vname' => 'LBL_ID', + 'type' => 'varchar', + 'len' => 255, + 'required' => true, + 'reportable' => false, + ), + 'ie_timestamp' => array( + 'name' => 'ie_timestamp', + 'type' => 'uint', + 'len' => 16, + 'required' => true, + ), + ), + 'indices' => array ( + array( + 'name' => 'ie_cachetimestamppk', + 'type' =>'primary', + 'fields' => array( + 'id' + ) + ), + ), /* end indices */ + 'relationships' => array ( + ), /* end relationships */ +); + +?> diff --git a/metadata/kbdocuments_views_ratingsMetaData.php b/metadata/kbdocuments_views_ratingsMetaData.php new file mode 100644 index 00000000..06f4af41 --- /dev/null +++ b/metadata/kbdocuments_views_ratingsMetaData.php @@ -0,0 +1,54 @@ + 'kbdocuments_views_ratings', + 'fields' => array ( + array('name' =>'id', 'type' =>'varchar', 'len'=>'36') + , array ('name' => 'date_modified','type' => 'datetime') + , array('name' =>'deleted', 'type' =>'bool', 'len'=>'1', 'default'=>'0', 'required' => false,) + , array('name' =>'kbdocument_id', 'type' =>'varchar', 'len'=>'36', ) + , array('name' =>'views_number', 'type' =>'int', 'default'=>'0','required' => false,) + , array('name' =>'ratings_number', 'type' =>'int', 'default'=>'0','required' => false,) + ), + 'indices' => array ( + array('name' =>'kbdoc_views_ratingspk', 'type' =>'primary', 'fields'=>array('id')) + , array('name' =>'idx_kbvr_kbdoc', 'type' =>'index', 'fields'=>array('kbdocument_id')) + ), +); +?> diff --git a/metadata/linked_documentsMetaData.php b/metadata/linked_documentsMetaData.php new file mode 100644 index 00000000..868c56a0 --- /dev/null +++ b/metadata/linked_documentsMetaData.php @@ -0,0 +1,73 @@ + 'linked_documents' + , 'fields' => array ( + array('name' =>'id', 'type' =>'varchar', 'len'=>'36') + , array('name' =>'parent_id', 'type' =>'varchar', 'len'=>'36') + , array('name' =>'parent_type', 'type' =>'varchar', 'len'=>'25') + , array('name' =>'document_id', 'type' =>'varchar', 'len'=>'36') + , array('name' =>'document_revision_id', 'type' =>'varchar', 'len'=>'36') + , array('name' =>'date_modified','type' => 'datetime') + , array('name' =>'deleted', 'type' =>'bool', 'len'=>'1', 'default'=>'0', 'required'=>false) + ) + , 'indices' => array ( + array('name' =>'linked_documentspk', 'type' =>'primary', 'fields'=>array('id')), + array( 'name' => 'idx_parent_document', + 'type' => 'alternate_key', + 'fields' => array('parent_type','parent_id','document_id'), + ), + ) + , 'relationships' => array ( + 'contracts_documents' => array('lhs_module'=> 'Contracts', 'lhs_table'=> 'contracts', 'lhs_key' => 'id', + 'rhs_module'=> 'Documents', 'rhs_table'=> 'documents', 'rhs_key' => 'id', + 'relationship_type'=>'many-to-many', + 'join_table'=> 'linked_documents', 'join_key_lhs'=>'parent_id', 'join_key_rhs'=>'document_id', 'relationship_role_column'=>'parent_type', + 'relationship_role_column_value'=>'Contracts'), + 'leads_documents' => array('lhs_module'=> 'Leads', 'lhs_table'=> 'leads', 'lhs_key' => 'id', + 'rhs_module'=> 'Documents', 'rhs_table'=> 'documents', 'rhs_key' => 'id', + 'relationship_type'=>'many-to-many', + 'join_table'=> 'linked_documents', 'join_key_lhs'=>'parent_id', 'join_key_rhs'=>'document_id', 'relationship_role_column'=>'parent_type', + 'relationship_role_column_value'=>'Leads'), + 'contracttype_documents' => array('lhs_module'=> 'ContractTypes', 'lhs_table'=> 'contract_types', 'lhs_key' => 'id', + 'rhs_module'=> 'Documents', 'rhs_table'=> 'documents', 'rhs_key' => 'id', + 'relationship_type'=>'many-to-many', + 'join_table'=> 'linked_documents', 'join_key_lhs'=>'parent_id', 'join_key_rhs'=>'document_id', 'relationship_role_column'=>'parent_type', + 'relationship_role_column_value'=>'ContracTemplates'), + ), + ); +?> \ No newline at end of file diff --git a/metadata/meetings_contactsMetaData.php b/metadata/meetings_contactsMetaData.php new file mode 100644 index 00000000..847c7df4 --- /dev/null +++ b/metadata/meetings_contactsMetaData.php @@ -0,0 +1,106 @@ + 'meetings_contacts', + 'fields'=> array( + array( 'name' => 'id', + 'type' => 'varchar', + 'len' => '36' + ), + array( 'name' => 'meeting_id', + 'type' => 'varchar', + 'len' => '36', + ), + array( 'name' => 'contact_id', + 'type' => 'varchar', + 'len' => '36', + ), + array( 'name' => 'required', + 'type' => 'varchar', + 'len' => '1', + 'default' => '1', + ), + array( 'name' => 'accept_status', + 'type' => 'varchar', + 'len' => '25', + 'default' => 'none' + ), + array( 'name' => 'date_modified', + 'type' => 'datetime' + ), + array( 'name' => 'deleted', + 'type' => 'bool', + 'len' => '1', + 'default' => '0', + 'required' => false + ), + ), + 'indices' => array( + array( 'name' => 'meetings_contactspk', + 'type' => 'primary', + 'fields' => array('id'), + ), + array( 'name' => 'idx_con_mtg_mtg', + 'type' => 'index', + 'fields' => array('meeting_id'), + ), + array( 'name' => 'idx_con_mtg_con', + 'type' => 'index', + 'fields' => array('contact_id'), + ), + array( 'name' => 'idx_meeting_contact', + 'type' => 'alternate_key', + 'fields' => array('meeting_id','contact_id'), + ), + ), + 'relationships' => array( + 'meetings_contacts' => array( + 'lhs_module' => 'Meetings', + 'lhs_table' => 'meetings', + 'lhs_key' => 'id', + 'rhs_module' => 'Contacts', + 'rhs_table' => 'contacts', + 'rhs_key' => 'id', + 'relationship_type' => 'many-to-many', + 'join_table' => 'meetings_contacts', + 'join_key_lhs' => 'meeting_id', + 'join_key_rhs' => 'contact_id', + ), + ), +); +?> \ No newline at end of file diff --git a/metadata/meetings_leadsMetaData.php b/metadata/meetings_leadsMetaData.php new file mode 100644 index 00000000..c0594b45 --- /dev/null +++ b/metadata/meetings_leadsMetaData.php @@ -0,0 +1,61 @@ + 'meetings_leads' + , 'fields' => array ( + array('name' =>'id', 'type' =>'varchar', 'len'=>'36') + , array('name' =>'meeting_id', 'type' =>'varchar', 'len'=>'36', ) + , array('name' =>'lead_id', 'type' =>'varchar', 'len'=>'36', ) + , array('name' =>'required', 'type' =>'varchar', 'len'=>'1', 'default'=>'1') + , array('name' =>'accept_status', 'type' =>'varchar', 'len'=>'25', 'default'=>'none') + , array ('name' => 'date_modified','type' => 'datetime') + , array('name' =>'deleted', 'type' =>'bool', 'len'=>'1', 'default'=>'0', 'required'=>false) + ) + , 'indices' => array ( + array('name' =>'meetings_leadspk', 'type' =>'primary', 'fields'=>array('id')) + , array('name' =>'idx_lead_meeting_meeting', 'type' =>'index', 'fields'=>array('meeting_id')) + , array('name' =>'idx_lead_meeting_lead', 'type' =>'index', 'fields'=>array('lead_id')) + , array('name' => 'idx_meeting_lead', 'type'=>'alternate_key', 'fields'=>array('meeting_id','lead_id')) + ) + + , 'relationships' => array ('meetings_leads' => array('lhs_module'=> 'Meetings', 'lhs_table'=> 'meetings', 'lhs_key' => 'id', + 'rhs_module'=> 'Leads', 'rhs_table'=> 'leads', 'rhs_key' => 'id', + 'relationship_type'=>'many-to-many', + 'join_table'=> 'meetings_leads', 'join_key_lhs'=>'meeting_id', 'join_key_rhs'=>'lead_id')) + +) +?> diff --git a/metadata/meetings_usersMetaData.php b/metadata/meetings_usersMetaData.php new file mode 100644 index 00000000..32d7fb2f --- /dev/null +++ b/metadata/meetings_usersMetaData.php @@ -0,0 +1,106 @@ + 'meetings_users', + 'fields' => array( + array( 'name' => 'id', + 'type' => 'varchar', + 'len' => '36', + ), + array( 'name' => 'meeting_id', + 'type' => 'varchar', + 'len' => '36', + ), + array( 'name' => 'user_id', + 'type' => 'varchar', + 'len' => '36', + ), + array( 'name' => 'required', + 'type' => 'varchar', + 'len' => '1', + 'default' => '1', + ), + array( 'name' => 'accept_status', + 'type' => 'varchar', + 'len' => '25', + 'default' => 'none', + ), + array( 'name' => 'date_modified', + 'type' => 'datetime', + ), + array( 'name' => 'deleted', + 'type' => 'bool', + 'len' => '1', + 'default' => '0', + 'required' => false, + ), + ), + 'indices' => array( + array( 'name' => 'meetings_userspk', + 'type' => 'primary', + 'fields' => array('id'), + ), + array( 'name' => 'idx_usr_mtg_mtg', + 'type' => 'index', + 'fields' => array('meeting_id'), + ), + array( 'name' => 'idx_usr_mtg_usr', + 'type' => 'index', + 'fields' => array('user_id'), + ), + array( 'name' => 'idx_meeting_users', + 'type' => 'alternate_key', + 'fields' => array('meeting_id', 'user_id'), + ), + ), + 'relationships' => array( + 'meetings_users' => array( + 'lhs_module' => 'Meetings', + 'lhs_table' => 'meetings', + 'lhs_key' => 'id', + 'rhs_module' => 'Users', + 'rhs_table' => 'users', + 'rhs_key' => 'id', + 'relationship_type' => 'many-to-many', + 'join_table' => 'meetings_users', + 'join_key_lhs' => 'meeting_id', + 'join_key_rhs' => 'user_id', + ), + ), +); +?> \ No newline at end of file diff --git a/metadata/opportunities_contactsMetaData.php b/metadata/opportunities_contactsMetaData.php new file mode 100644 index 00000000..28e5ac0e --- /dev/null +++ b/metadata/opportunities_contactsMetaData.php @@ -0,0 +1,65 @@ + 'opportunities_contacts' + , 'fields' => array ( + array('name' =>'id', 'type' =>'varchar', 'len'=>'36') + , array('name' =>'contact_id', 'type' =>'varchar', 'len'=>'36', ) + , array('name' =>'opportunity_id', 'type' =>'varchar', 'len'=>'36',) + , array('name' =>'contact_role', 'type' =>'varchar', 'len'=>'50') + , array ('name' => 'date_modified','type' => 'datetime') + , array('name' =>'deleted', 'type' =>'bool', 'len'=>'1', 'default'=>'0', 'required'=>false) + ) , 'indices' => array ( + array('name' =>'opportunities_contactspk', 'type' =>'primary', 'fields'=>array('id')) + , array('name' =>'idx_con_opp_con', 'type' =>'index', 'fields'=>array('contact_id')) + , array('name' =>'idx_con_opp_opp', 'type' =>'index', 'fields'=>array('opportunity_id')) + , array('name' => 'idx_opportunities_contacts', 'type'=>'alternate_key', 'fields'=>array('opportunity_id','contact_id')) + + + ) + + , 'relationships' => array ('opportunities_contacts' => array('lhs_module'=> 'Opportunities', 'lhs_table'=> 'opportunities', 'lhs_key' => 'id', + 'rhs_module'=> 'Contacts', 'rhs_table'=> 'contacts', 'rhs_key' => 'id', + 'relationship_type'=>'many-to-many', + 'join_table'=> 'opportunities_contacts', 'join_key_lhs'=>'opportunity_id', 'join_key_rhs'=>'contact_id', + )) + + ) + + + +?> diff --git a/metadata/outboundEmailMetaData.php b/metadata/outboundEmailMetaData.php new file mode 100644 index 00000000..22f01466 --- /dev/null +++ b/metadata/outboundEmailMetaData.php @@ -0,0 +1,160 @@ + 'outbound_email', + 'fields' => array ( + 'id' => array ( + 'name' => 'id', + 'vname' => 'LBL_ID', + 'type' => 'id', + 'required' => true, + 'reportable' => false, + ), + 'name' => array ( + 'name' => 'name', + 'vname' => 'LBL_NAME', + 'type' => 'varchar', + 'len' => 50, + 'required' => true, + 'reportable' => false, + ), + 'type' => array ( + 'name' => 'type', + 'vname' => 'LBL_TYPE', + 'type' => 'varchar', + 'len' => 15, + 'required' => true, + 'default' => 'user', + 'reportable' => false, + ), + 'user_id' => array ( + 'name' => 'user_id', + 'vname' => 'LBL_USER_ID', + 'type' => 'id', + 'required' => true, + 'reportable' => false, + ), + 'mail_sendtype' => array( + 'name' => 'mail_sendtype', + 'vname' => 'LBL_MAIL_SENDTYPE', + 'type' => 'varchar', + 'len' => 8, + 'required' => true, + 'default' => 'smtp', + 'reportable' => false, + ), + 'mail_smtptype' => array( + 'name' => 'mail_smtptype', + 'vname' => 'LBL_MAIL_SENDTYPE', + 'type' => 'varchar', + 'len' => 20, + 'required' => true, + 'default' => 'other', + 'reportable' => false, + ), + 'mail_smtpserver' => array( + 'name' => 'mail_smtpserver', + 'vname' => 'LBL_MAIL_SMTPSERVER', + 'type' => 'varchar', + 'len' => 100, + 'required' => false, + 'reportable' => false, + ), + 'mail_smtpport' => array( + 'name' => 'mail_smtpport', + 'vname' => 'LBL_MAIL_SMTPPORT', + 'type' => 'int', + 'len' => 5, + 'default' => 0, + 'reportable' => false, + ), + 'mail_smtpuser' => array( + 'name' => 'mail_smtpuser', + 'vname' => 'LBL_MAIL_SMTPUSER', + 'type' => 'varchar', + 'len' => 100, + 'reportable' => false, + ), + 'mail_smtppass' => array( + 'name' => 'mail_smtppass', + 'vname' => 'LBL_MAIL_SMTPPASS', + 'type' => 'varchar', + 'len' => 100, + 'reportable' => false, + ), + 'mail_smtpauth_req' => array( + 'name' => 'mail_smtpauth_req', + 'vname' => 'LBL_MAIL_SMTPAUTH_REQ', + 'type' => 'bool', + 'default' => 0, + 'reportable' => false, + ), + 'mail_smtpssl' => array( + 'name' => 'mail_smtpssl', + 'vname' => 'LBL_MAIL_SMTPSSL', + 'type' => 'int', + 'len' => 1, + 'default' => 0, + 'reportable' => false, + ), + ), + 'indices' => array ( + array( + 'name' => 'outbound_email_pk', + 'type' =>'primary', + 'fields' => array( + 'id' + ) + ), + array( + 'name' => 'oe_user_id_idx', + 'type' =>'index', + 'fields' => array( + 'id', + 'user_id', + ) + ), + ), /* end indices */ +); + diff --git a/metadata/project_bugsMetaData.php b/metadata/project_bugsMetaData.php new file mode 100644 index 00000000..7211c8fc --- /dev/null +++ b/metadata/project_bugsMetaData.php @@ -0,0 +1,69 @@ + 'projects_bugs', + 'fields' => array ( + array('name' => 'id', 'type' => 'varchar', 'len' => '36'), + array('name' => 'bug_id', 'type' => 'varchar', 'len' => '36'), + array('name' => 'project_id', 'type' => 'varchar', 'len' => '36'), + array('name' => 'date_modified', 'type' => 'datetime'), + array('name' => 'deleted', 'type' => 'bool', 'len' => '1', 'default' => '0', 'required' => false), + ), + 'indices' => array ( + array('name' => 'projects_bugs_pk', 'type' =>'primary', 'fields'=>array('id')), + array('name' => 'idx_proj_bug_proj', 'type' =>'index', 'fields'=>array('project_id')), + array('name' => 'idx_proj_bug_bug', 'type' =>'index', 'fields'=>array('bug_id')), + array('name' => 'projects_bugs_alt', 'type'=>'alternate_key', 'fields'=>array('project_id','bug_id')), + ), + 'relationships' => array ( + 'projects_bugs' => array( + 'lhs_module' => 'Project', + 'lhs_table' => 'project', + 'lhs_key' => 'id', + 'rhs_module' => 'Bugs', + 'rhs_table' => 'bugs', + 'rhs_key' => 'id', + 'relationship_type' => 'many-to-many', + 'join_table' => 'projects_bugs', + 'join_key_lhs' => 'project_id', + 'join_key_rhs' => 'bug_id', + ), + ), +); +?> diff --git a/metadata/project_casesMetaData.php b/metadata/project_casesMetaData.php new file mode 100644 index 00000000..14e03c75 --- /dev/null +++ b/metadata/project_casesMetaData.php @@ -0,0 +1,69 @@ + 'projects_cases', + 'fields' => array ( + array('name' => 'id', 'type' => 'varchar', 'len' => '36'), + array('name' => 'case_id', 'type' => 'varchar', 'len' => '36'), + array('name' => 'project_id', 'type' => 'varchar', 'len' => '36'), + array('name' => 'date_modified', 'type' => 'datetime'), + array('name' => 'deleted', 'type' => 'bool', 'len' => '1', 'default' => '0', 'required' => false), + ), + 'indices' => array ( + array('name' => 'projects_cases_pk', 'type' =>'primary', 'fields'=>array('id')), + array('name' => 'idx_proj_case_proj', 'type' =>'index', 'fields'=>array('project_id')), + array('name' => 'idx_proj_case_case', 'type' =>'index', 'fields'=>array('case_id')), + array('name' => 'projects_cases_alt', 'type'=>'alternate_key', 'fields'=>array('project_id','case_id')), + ), + 'relationships' => array ( + 'projects_cases' => array( + 'lhs_module' => 'Project', + 'lhs_table' => 'project', + 'lhs_key' => 'id', + 'rhs_module' => 'Cases', + 'rhs_table' => 'cases', + 'rhs_key' => 'id', + 'relationship_type' => 'many-to-many', + 'join_table' => 'projects_cases', + 'join_key_lhs' => 'project_id', + 'join_key_rhs' => 'case_id', + ), + ), +); +?> diff --git a/metadata/project_productsMetaData.php b/metadata/project_productsMetaData.php new file mode 100644 index 00000000..c1b334e5 --- /dev/null +++ b/metadata/project_productsMetaData.php @@ -0,0 +1,69 @@ + 'projects_products', + 'fields' => array ( + array('name' => 'id', 'type' => 'varchar', 'len' => '36'), + array('name' => 'product_id', 'type' => 'varchar', 'len' => '36'), + array('name' => 'project_id', 'type' => 'varchar', 'len' => '36'), + array('name' => 'date_modified', 'type' => 'datetime'), + array('name' => 'deleted', 'type' => 'bool', 'len' => '1', 'default' => '0', 'required' => false), + ), + 'indices' => array ( + array('name' => 'projects_products_pk', 'type' =>'primary', 'fields'=>array('id')), + array('name' => 'idx_proj_prod_project', 'type' =>'index', 'fields'=>array('project_id')), + array('name' => 'idx_proj_prod_product', 'type' =>'index', 'fields'=>array('product_id')), + array('name' => 'projects_products_alt', 'type'=>'alternate_key', 'fields'=>array('project_id','product_id')), + ), + 'relationships' => array ( + 'projects_products' => array( + 'lhs_module' => 'Project', + 'lhs_table' => 'project', + 'lhs_key' => 'id', + 'rhs_module' => 'Products', + 'rhs_table' => 'products', + 'rhs_key' => 'id', + 'relationship_type' => 'many-to-many', + 'join_table' => 'projects_products', + 'join_key_lhs' => 'project_id', + 'join_key_rhs' => 'product_id', + ), + ), +); +?> diff --git a/metadata/project_relationMetaData.php b/metadata/project_relationMetaData.php new file mode 100644 index 00000000..c6d6fd7b --- /dev/null +++ b/metadata/project_relationMetaData.php @@ -0,0 +1,119 @@ + 'project_relation', + 'fields' => array( + 'id' => array( + 'name' => 'id', + 'vname' => 'LBL_ID', + 'required' => true, + 'type' => 'id', + ), + 'project_id' => array( + 'name' => 'project_id', + 'vname' => 'LBL_PROJECT_ID', + 'required' => true, + 'type' => 'id', + ), + 'relation_id' => array( + 'name' => 'relation_id', + 'vname' => 'LBL_PROJECT_NAME', + 'required' => true, + 'type' => 'id', + ), + 'relation_type' => array( + 'name' => 'relation_type', + 'vname' => 'LBL_PROJECT_NAME', + 'required' => true, + 'type' => 'enum', + 'options' => 'project_relation_type_options', + ), + 'deleted' => array( + 'name' => 'deleted', + 'vname' => 'LBL_DELETED', + 'type' => 'bool', + 'required' => true, + 'default' => '0', + ), + 'date_modified' => array ( + 'name' => 'date_modified', + 'vname' => 'LBL_DATE_MODIFIED', + 'type' => 'datetime', + 'required'=>true, + ), + ), + 'indices' => array( + array( + 'name' =>'proj_rel_pk', + 'type' =>'primary', + 'fields'=>array('id') + ), + ), + + 'relationships' => + array ('projects_accounts' => array('lhs_module'=> 'Accounts', 'lhs_table'=> 'accounts', 'lhs_key' => 'id', + 'rhs_module'=> 'Project', 'rhs_table'=> 'project', 'rhs_key' => 'id', + 'relationship_type'=>'many-to-many', + 'join_table'=> 'project_relation', 'join_key_lhs'=>'relation_id', 'join_key_rhs'=>'project_id', + 'relationship_role_column'=>'relation_type','relationship_role_column_value'=>'Accounts'), + + 'projects_contacts' => array('lhs_module'=> 'Project', 'lhs_table'=> 'project', 'lhs_key' => 'id', + 'rhs_module'=> 'Contacts', 'rhs_table'=> 'contacts', 'rhs_key' => 'id', + 'relationship_type'=>'many-to-many', + 'join_table'=> 'project_relation', 'join_key_lhs'=>'project_id', 'join_key_rhs'=>'relation_id', + 'relationship_role_column'=>'relation_type','relationship_role_column_value'=>'Contacts'), + + 'projects_opportunities' => array('lhs_module'=> 'Project', 'lhs_table'=> 'project', 'lhs_key' => 'id', + 'rhs_module'=> 'Opportunities', 'rhs_table'=> 'opportunities', 'rhs_key' => 'id', + 'relationship_type'=>'many-to-many', + 'join_table'=> 'project_relation', 'join_key_lhs'=>'project_id', 'join_key_rhs'=>'relation_id', + 'relationship_role_column'=>'relation_type','relationship_role_column_value'=>'Opportunities'), + + 'projects_quotes' => array('lhs_module'=> 'Project', 'lhs_table'=> 'project', 'lhs_key' => 'id', + 'rhs_module'=> 'Quotes', 'rhs_table'=> 'quotes', 'rhs_key' => 'id', + 'relationship_type'=>'many-to-many', + 'join_table'=> 'project_relation', 'join_key_lhs'=>'project_id', 'join_key_rhs'=>'relation_id', + 'relationship_role_column'=>'relation_type','relationship_role_column_value'=>'Quotes'), + + ), +); + +?> diff --git a/metadata/project_task_project_tasksMetaData.php b/metadata/project_task_project_tasksMetaData.php new file mode 100644 index 00000000..e07aa500 --- /dev/null +++ b/metadata/project_task_project_tasksMetaData.php @@ -0,0 +1,94 @@ + 'project_task_project_tasks', + 'fields' => array( + 'id' => array( + 'name' => 'id', + 'vname' => 'LBL_ID', + 'required' => true, + 'type' => 'id', + ), + 'project_task_id' => array( + 'name' => 'project_task_id', + 'vname' => 'LBL_PROJECT_TASK_ID', + 'required' => true, + 'type' => 'id', + ), + 'predecessor_project_task_id' => array( + 'name' => 'predecessor_project_task_id', + 'vname' => 'LBL_PROJECT_TASK_ID', + 'required' => true, + 'type' => 'id', + ), + 'deleted' => array( + 'name' => 'deleted', + 'vname' => 'LBL_DELETED', + 'type' => 'bool', + 'required' => false, + 'default' => '0', + ), + ), + 'indices' => array( + array( + 'name' =>'proj_rel_pk', + 'type' =>'primary', + 'fields'=>array('id') + ), + ), + + 'relationships' => array( + 'project_task_project_tasks' => array( + 'lhs_module' => 'ProjectTasks2', + 'lhs_table' => 'project_tasks', + 'lhs_key' => 'id', + 'rhs_module' => 'ProjectTasks2', + 'rhs_table' => 'project_tasks', + 'rhs_key' => 'id', + 'relationship_type' => 'many-to-many', + 'join_table' => 'project_task_project_tasks', + 'join_key_lhs' => 'project_task_id', + 'join_key_rhs' => 'predecessor_project_task_id', + ), + ), +); + +?> diff --git a/metadata/projects_accountsMetaData.php b/metadata/projects_accountsMetaData.php new file mode 100644 index 00000000..ee468ec8 --- /dev/null +++ b/metadata/projects_accountsMetaData.php @@ -0,0 +1,70 @@ + 'projects_accounts', + 'fields' => array ( + array('name' => 'id', 'type' => 'varchar', 'len' => '36'), + array('name' => 'account_id', 'type' => 'varchar', 'len' => '36'), + array('name' => 'project_id', 'type' => 'varchar', 'len' => '36'), + array('name' => 'date_modified', 'type' => 'datetime'), + array('name' => 'deleted', 'type' => 'bool', 'len' => '1', 'default' => '0', 'required' => false), + ), + 'indices' => array ( + array('name' => 'projects_accounts_pk', 'type' =>'primary', 'fields'=>array('id')), + array('name' => 'idx_proj_acct_proj', 'type' =>'index', 'fields'=>array('project_id')), + array('name' => 'idx_proj_acct_acct', 'type' =>'index', 'fields'=>array('account_id')), + array('name' => 'projects_accounts_alt', 'type'=>'alternate_key', 'fields'=>array('project_id','account_id')), + ), + 'relationships' => array ( + 'projects_accounts' => array( + 'lhs_module' => 'Project', + 'lhs_table' => 'project', + 'lhs_key' => 'id', + 'rhs_module' => 'Accounts', + 'rhs_table' => 'accounts', + 'rhs_key' => 'id', + 'relationship_type' => 'many-to-many', + 'join_table' => 'projects_accounts', + 'join_key_lhs' => 'project_id', + 'join_key_rhs' => 'account_id', + ), + ), +); +?> diff --git a/metadata/projects_contactsMetaData.php b/metadata/projects_contactsMetaData.php new file mode 100644 index 00000000..ac808087 --- /dev/null +++ b/metadata/projects_contactsMetaData.php @@ -0,0 +1,70 @@ + 'projects_contacts', + 'fields' => array ( + array('name' => 'id', 'type' => 'varchar', 'len' => '36'), + array('name' => 'contact_id', 'type' => 'varchar', 'len' => '36'), + array('name' => 'project_id', 'type' => 'varchar', 'len' => '36'), + array('name' => 'date_modified', 'type' => 'datetime'), + array('name' => 'deleted', 'type' => 'bool', 'len' => '1', 'default' => '0', 'required' => false), + ), + 'indices' => array ( + array('name' => 'projects_contacts_pk', 'type' =>'primary', 'fields'=>array('id')), + array('name' => 'idx_proj_con_proj', 'type' =>'index', 'fields'=>array('project_id')), + array('name' => 'idx_proj_con_con', 'type' =>'index', 'fields'=>array('contact_id')), + array('name' => 'projects_contacts_alt', 'type'=>'alternate_key', 'fields'=>array('project_id','contact_id')), + ), + 'relationships' => array ( + 'projects_contacts' => array( + 'lhs_module' => 'Project', + 'lhs_table' => 'project', + 'lhs_key' => 'id', + 'rhs_module' => 'Contacts', + 'rhs_table' => 'contacts', + 'rhs_key' => 'id', + 'relationship_type' => 'many-to-many', + 'join_table' => 'projects_contacts', + 'join_key_lhs' => 'project_id', + 'join_key_rhs' => 'contact_id', + ), + ), +); +?> diff --git a/metadata/projects_opportunitiesMetaData.php b/metadata/projects_opportunitiesMetaData.php new file mode 100644 index 00000000..9b0cab42 --- /dev/null +++ b/metadata/projects_opportunitiesMetaData.php @@ -0,0 +1,70 @@ + 'projects_opportunities', + 'fields' => array ( + array('name' => 'id', 'type' => 'varchar', 'len' => '36'), + array('name' => 'opportunity_id', 'type' => 'varchar', 'len' => '36'), + array('name' => 'project_id', 'type' => 'varchar', 'len' => '36'), + array('name' => 'date_modified', 'type' => 'datetime'), + array('name' => 'deleted', 'type' => 'bool', 'len' => '1', 'default' => '0', 'required' => false), + ), + 'indices' => array ( + array('name' => 'projects_opportunities_pk', 'type' =>'primary', 'fields'=>array('id')), + array('name' => 'idx_proj_opp_proj', 'type' =>'index', 'fields'=>array('project_id')), + array('name' => 'idx_proj_opp_opp', 'type' =>'index', 'fields'=>array('opportunity_id')), + array('name' => 'projects_opportunities_alt', 'type'=>'alternate_key', 'fields'=>array('project_id','opportunity_id')), + ), + 'relationships' => array ( + 'projects_opportunities' => array( + 'lhs_module' => 'Project', + 'lhs_table' => 'project', + 'lhs_key' => 'id', + 'rhs_module' => 'Opportunities', + 'rhs_table' => 'opportunities', + 'rhs_key' => 'id', + 'relationship_type' => 'many-to-many', + 'join_table' => 'projects_opportunities', + 'join_key_lhs' => 'project_id', + 'join_key_rhs' => 'opportunity_id', + ), + ), +); +?> diff --git a/metadata/projects_quotesMetaData.php b/metadata/projects_quotesMetaData.php new file mode 100644 index 00000000..cebeadc3 --- /dev/null +++ b/metadata/projects_quotesMetaData.php @@ -0,0 +1,70 @@ + 'projects_quotes', + 'fields' => array ( + array('name' => 'id', 'type' => 'varchar', 'len' => '36'), + array('name' => 'quote_id', 'type' => 'varchar', 'len' => '36'), + array('name' => 'project_id', 'type' => 'varchar', 'len' => '36'), + array('name' => 'date_modified', 'type' => 'datetime'), + array('name' => 'deleted', 'type' => 'bool', 'len' => '1', 'default' => '0', 'required' => false), + ), + 'indices' => array ( + array('name' => 'projects_quotes_pk', 'type' =>'primary', 'fields'=>array('id')), + array('name' => 'idx_proj_quote_proj', 'type' =>'index', 'fields'=>array('project_id')), + array('name' => 'idx_proj_quote_quote', 'type' =>'index', 'fields'=>array('quote_id')), + array('name' => 'projects_quotes_alt', 'type'=>'alternate_key', 'fields'=>array('project_id','quote_id')), + ), + 'relationships' => array ( + 'projects_quotes' => array( + 'lhs_module' => 'Project', + 'lhs_table' => 'project', + 'lhs_key' => 'id', + 'rhs_module' => 'Quotes', + 'rhs_table' => 'quotes', + 'rhs_key' => 'id', + 'relationship_type' => 'many-to-many', + 'join_table' => 'projects_quotes', + 'join_key_lhs' => 'project_id', + 'join_key_rhs' => 'quote_id', + ), + ), +); +?> diff --git a/metadata/prospect_list_campaignsMetaData.php b/metadata/prospect_list_campaignsMetaData.php new file mode 100644 index 00000000..50ac15ad --- /dev/null +++ b/metadata/prospect_list_campaignsMetaData.php @@ -0,0 +1,99 @@ + 'prospect_list_campaigns', + + 'fields' => array ( + array ( + 'name' => 'id', + 'type' => 'varchar', + 'len' => '36', + ), + array ( + 'name' => 'prospect_list_id', + 'type' => 'varchar', + 'len' => '36', + ), + array ( + 'name' => 'campaign_id', + 'type' => 'varchar', + 'len' => '36', + ), + array ('name' => 'date_modified','type' => 'datetime'), + array ( + 'name' => 'deleted', + 'type' => 'bool', + 'len' => '1', + 'default' => '0' + ), + + ), + + 'indices' => array ( + array ( + 'name' => 'prospect_list_campaignspk', + 'type' => 'primary', + 'fields' => array ( 'id' ) + ), + array ( + 'name' => 'idx_pro_id', + 'type' => 'index', + 'fields' => array ('prospect_list_id') + ), + array ( + 'name' => 'idx_cam_id', + 'type' => 'index', + 'fields' => array ('campaign_id') + ), + array ( + 'name' => 'idx_prospect_list_campaigns', + 'type'=>'alternate_key', + 'fields'=>array('prospect_list_id','campaign_id') + ), + ), + + 'relationships' => array ( + 'prospect_list_campaigns' => array('lhs_module'=> 'ProspectLists', 'lhs_table'=> 'prospect_lists', 'lhs_key' => 'id', + 'rhs_module'=> 'Campaigns', 'rhs_table'=> 'campaigns', 'rhs_key' => 'id', + 'relationship_type'=>'many-to-many', + 'join_table'=> 'prospect_list_campaigns', 'join_key_lhs'=>'prospect_list_id', 'join_key_rhs'=>'campaign_id') + ) +) + +?> diff --git a/metadata/prospect_lists_prospectsMetaData.php b/metadata/prospect_lists_prospectsMetaData.php new file mode 100644 index 00000000..772bc96e --- /dev/null +++ b/metadata/prospect_lists_prospectsMetaData.php @@ -0,0 +1,169 @@ + 'prospect_lists_prospects', + + 'fields' => array ( + array ( + 'name' => 'id', + 'type' => 'varchar', + 'len' => '36', + ), + array ( + 'name' => 'prospect_list_id', + 'type' => 'varchar', + 'len' => '36', + ), + array ( + 'name' => 'related_id', + 'type' => 'varchar', + 'len' => '36', + ), + array ( + 'name' => 'related_type', + 'type' => 'varchar', + 'len' => '25', //valid values are Prospect, Contact, Lead, User + ), + array ( + 'name' => 'date_modified', + 'type' => 'datetime' + ), + array ( + 'name' => 'deleted', + 'type' => 'bool', + 'len' => '1', + 'default' => '0' + ), + ), + + 'indices' => array ( + array ( + 'name' => 'prospect_lists_prospectspk', + 'type' => 'primary', + 'fields' => array ( 'id' ) + ), + array ( + 'name' => 'idx_plp_pro_id', + 'type' => 'index', + 'fields' => array ('prospect_list_id') + ), + array ( + 'name' => 'idx_plp_rel_id', + 'type' => 'alternate_key', + 'fields' => array ( 'related_id', + 'related_type', + 'prospect_list_id' + ) + ), + ), + + 'relationships' => array ( + 'prospect_list_contacts' => array( 'lhs_module'=> 'ProspectLists', + 'lhs_table'=> 'prospect_lists', + 'lhs_key' => 'id', + 'rhs_module'=> 'Contacts', + 'rhs_table'=> 'contacts', + 'rhs_key' => 'id', + 'relationship_type'=>'many-to-many', + 'join_table'=> 'prospect_lists_prospects', + 'join_key_lhs'=>'prospect_list_id', + 'join_key_rhs'=>'related_id', + 'relationship_role_column'=>'related_type', + 'relationship_role_column_value'=>'Contacts' + ), + + 'prospect_list_prospects' =>array( 'lhs_module'=> 'ProspectLists', + 'lhs_table'=> 'prospect_lists', + 'lhs_key' => 'id', + 'rhs_module'=> 'Prospects', + 'rhs_table'=> 'prospects', + 'rhs_key' => 'id', + 'relationship_type'=>'many-to-many', + 'join_table'=> 'prospect_lists_prospects', + 'join_key_lhs'=>'prospect_list_id', + 'join_key_rhs'=>'related_id', + 'relationship_role_column'=>'related_type', + 'relationship_role_column_value'=>'Prospects' + ), + + 'prospect_list_leads' =>array( 'lhs_module'=> 'ProspectLists', + 'lhs_table'=> 'prospect_lists', + 'lhs_key' => 'id', + 'rhs_module'=> 'Leads', + 'rhs_table'=> 'leads', + 'rhs_key' => 'id', + 'relationship_type'=>'many-to-many', + 'join_table'=> 'prospect_lists_prospects', + 'join_key_lhs'=>'prospect_list_id', + 'join_key_rhs'=>'related_id', + 'relationship_role_column'=>'related_type', + 'relationship_role_column_value'=>'Leads', + ), + + 'prospect_list_users' =>array( 'lhs_module'=> 'ProspectLists', + 'lhs_table'=> 'prospect_lists', + 'lhs_key' => 'id', + 'rhs_module'=> 'Users', + 'rhs_table'=> 'users', + 'rhs_key' => 'id', + 'relationship_type'=>'many-to-many', + 'join_table'=> 'prospect_lists_prospects', + 'join_key_lhs'=>'prospect_list_id', + 'join_key_rhs'=>'related_id', + 'relationship_role_column'=>'related_type', + 'relationship_role_column_value'=>'Users', + ), + + 'prospect_list_accounts' =>array( 'lhs_module'=> 'ProspectLists', + 'lhs_table'=> 'prospect_lists', + 'lhs_key' => 'id', + 'rhs_module'=> 'Accounts', + 'rhs_table'=> 'accounts', + 'rhs_key' => 'id', + 'relationship_type'=>'many-to-many', + 'join_table'=> 'prospect_lists_prospects', + 'join_key_lhs'=>'prospect_list_id', + 'join_key_rhs'=>'related_id', + 'relationship_role_column'=>'related_type', + 'relationship_role_column_value'=>'Accounts', + ) + ) + +) +?> \ No newline at end of file diff --git a/metadata/queues_beansMetaData.php b/metadata/queues_beansMetaData.php new file mode 100644 index 00000000..4ecf2e72 --- /dev/null +++ b/metadata/queues_beansMetaData.php @@ -0,0 +1,132 @@ + 'queues_beans', + 'fields' => array ( + 'id' => array ( + 'name' => 'id', + 'vname' => 'LBL_ID', + 'type' => 'id', + 'required' => true, + 'reportable'=>false, + ), + 'deleted' => array ( + 'name' => 'deleted', + 'vname' => 'LBL_DELETED', + 'type' => 'bool', + 'required' => true, + 'default' => '0', + 'reportable'=>false, + ), + 'date_entered' => array ( + 'name' => 'date_entered', + 'vname' => 'LBL_DATE_ENTERED', + 'type' => 'datetime', + 'required' => true, + ), + 'date_modified' => array ( + 'name' => 'date_modified', + 'vname' => 'LBL_DATE_MODIFIED', + 'type' => 'datetime', + 'required' => true, + ), + 'queue_id' => array ( + 'name' => 'queue_id', + 'vname' => 'LBL_QUEUE_ID', + 'type' => 'id', + 'required' => true, + 'reportable'=>false, + ), + 'module_dir' => array ( + 'name' => 'module_dir', + 'vname' => 'LBL_MODULE_DIR', + 'type' => 'varchar', + 'len' => '30', + 'required' => true, + 'reportable'=>false, + ), + 'object_id' => array ( + 'name' => 'object_id', + 'vname' => 'LBL_OBJECT_ID', + 'type' => 'id', + 'required' => true, + 'reportable'=>false, + ), + ), + 'relationships' => array ( + 'queues_emails_rel' => array( + 'lhs_module' => 'Queues', + 'lhs_table' => 'queues', + 'lhs_key' => 'id', + 'rhs_module' => 'Emails', + 'rhs_table' => 'emails', + 'rhs_key' => 'id', + 'relationship_type' => 'many-to-many', + 'join_table' => 'queues_beans', + 'join_key_rhs' => 'object_id', + 'join_key_lhs' => 'queue_id', + 'relationship_role_column' => 'module_dir', + 'relationship_role_column_value'=> 'Emails' + ), + ), /* end relationship definitions */ + 'indices' => array ( + array( + 'name' => 'queues_itemspk', + 'type' =>'primary', + 'fields' => array( + 'id' + ) + ), + array( + 'name' =>'idx_queue_id', + 'type'=>'index', + 'fields' => array( + 'queue_id' + ) + ), + array( + 'name' =>'idx_object_id', + 'type'=>'index', + 'fields' => array( + 'object_id' + ) + ), + ), /* end indices */ +); + +?> diff --git a/metadata/queues_queueMetaData.php b/metadata/queues_queueMetaData.php new file mode 100644 index 00000000..3cfe6280 --- /dev/null +++ b/metadata/queues_queueMetaData.php @@ -0,0 +1,141 @@ + 'queues_queue', + 'fields' => array ( + 'id' => array ( + 'name' => 'id', + 'vname' => 'LBL_QUEUES_QUEUE_ID', + 'type' => 'id', + 'required' => true, + 'reportable' => false, + ), + 'deleted' => array ( + 'name' => 'deleted', + 'vname' => 'LBL_DELETED', + 'type' => 'bool', + 'required' => true, + 'default' => '0', + 'reportable'=>false, + ), + 'date_entered' => array ( + 'name' => 'date_entered', + 'vname' => 'LBL_DATE_ENTERED', + 'type' => 'datetime', + 'required' => true, + ), + 'date_modified' => array ( + 'name' => 'date_modified', + 'vname' => 'LBL_DATE_MODIFIED', + 'type' => 'datetime', + 'required' => true, + ), + 'queue_id' => array ( + 'name' => 'queue_id', + 'vname' => 'LBL_QUEUE_ID', + 'type' => 'id', + 'required' => true, + 'reportable'=>false, + ), + 'parent_id' => array ( + 'name' => 'parent_id', + 'vname' => 'LBL_PARENT_ID', + 'type' => 'id', + 'required' => true, + 'reportable'=>false, + ), + ), + 'indices' => array ( + array( + 'name' => 'queues_queuepk', + 'type' =>'primary', + 'fields' => array( + 'id' + ) + ), + array( + 'name' =>'idx_queue_id', + 'type'=>'index', + 'fields' => array( + 'queue_id' + ) + ), + array( + 'name' =>'idx_parent_id', + 'type'=>'index', + 'fields' => array( + 'parent_id' + ) + ), + array( + 'name' => 'compidx_queue_id_parent_id', + 'type' => 'alternate_key', + 'fields' => array ( + 'queue_id', + 'parent_id' + ), + ), + ), /* end indices */ + 'relationships' => array ( + 'child_queues_rel' => array( + 'lhs_module' => 'Queues', + 'lhs_table' => 'queues', + 'lhs_key' => 'id', + 'rhs_module' => 'Queues', + 'rhs_table' => 'queues', + 'rhs_key' => 'id', + 'relationship_type' => 'many-to-many', + 'join_table' => 'queues_queue', + 'join_key_lhs' => 'queue_id', + 'join_key_rhs' => 'parent_id' + ), + 'parent_queues_rel' => array( + 'lhs_module' => 'Queues', + 'lhs_table' => 'queues', + 'lhs_key' => 'id', + 'rhs_module' => 'Queues', + 'rhs_table' => 'queues', + 'rhs_key' => 'id', + 'relationship_type' => 'many-to-many', + 'join_table' => 'queues_queue', + 'join_key_rhs' => 'queue_id', + 'join_key_lhs' => 'parent_id' + ), + ), /* end relationships */ +); + +?> diff --git a/metadata/roles_modulesMetaData.php b/metadata/roles_modulesMetaData.php new file mode 100644 index 00000000..2cec4f14 --- /dev/null +++ b/metadata/roles_modulesMetaData.php @@ -0,0 +1,92 @@ + 'roles_modules', + + 'fields' => array ( + array ( + 'name' => 'id', + 'type' => 'varchar', + 'len' => '36', + ), + array ( + 'name' => 'role_id', + 'type' => 'varchar', + 'len' => '36', + ), + array ( + 'name' => 'module_id', + 'type' => 'varchar', + 'len' => '36', + ), + array ( + 'name' => 'allow', + 'type' => 'bool', + 'len' => '1', + 'default' => '0', + ) + , array ('name' => 'date_modified','type' => 'datetime'), + array ( + 'name' => 'deleted', + 'type' => 'bool', + 'len' => '1', + 'default' => '0' + ), + ), + + 'indices' => array ( + array ( + 'name' => 'roles_modulespk', + 'type' => 'primary', + 'fields' => array ( 'id' ) + ), + array ( + 'name' => 'idx_role_id', + 'type' => 'index', + 'fields' => array ('role_id') + ), + array ( + 'name' => 'idx_module_id', + 'type' => 'index', + 'fields' => array ('module_id') + ), + ), +) + +?> diff --git a/metadata/roles_usersMetaData.php b/metadata/roles_usersMetaData.php new file mode 100644 index 00000000..efabae41 --- /dev/null +++ b/metadata/roles_usersMetaData.php @@ -0,0 +1,91 @@ + 'roles_users', + + 'fields' => array ( + array ( + 'name' => 'id', + 'type' => 'varchar', + 'len' => '36', + ), + array ( + 'name' => 'role_id', + 'type' => 'varchar', + 'len' => '36', + ), + array ( + 'name' => 'user_id', + 'type' => 'varchar', + 'len' => '36', + ) + , array ('name' => 'date_modified','type' => 'datetime'), + array ( + 'name' => 'deleted', + 'type' => 'bool', + 'len' => '1', + 'default' => '0' + ), + ), + + 'indices' => array ( + array ( + 'name' => 'roles_userspk', + 'type' => 'primary', + 'fields' => array ( 'id' ) + ), + array ( + 'name' => 'idx_ru_role_id', + 'type' => 'index', + 'fields' => array ('role_id') + ), + array ( + 'name' => 'idx_ru_user_id', + 'type' => 'index', + 'fields' => array ('user_id') + ), + ), + 'relationships' => array ('roles_users' => array('lhs_module'=> 'Roles', 'lhs_table'=> 'roles', 'lhs_key' => 'id', + 'rhs_module'=> 'Users', 'rhs_table'=> 'users', 'rhs_key' => 'id', + 'relationship_type'=>'many-to-many', + 'join_table'=> 'roles_users', 'join_key_lhs'=>'role_id', 'join_key_rhs'=>'user_id')), + +) + +?> \ No newline at end of file diff --git a/metadata/schedulers_timesMetaData.php b/metadata/schedulers_timesMetaData.php new file mode 100644 index 00000000..e25e4d99 --- /dev/null +++ b/metadata/schedulers_timesMetaData.php @@ -0,0 +1,115 @@ + 'schedulers_times', + 'fields' => array ( + 'id' => array ( + 'name' => 'id', + 'vname' => 'LBL_NAME', + 'type' => 'id', + 'len' => '36', + 'required' => true, + 'reportable'=>false, + ), + 'deleted' => array ( + 'name' => 'deleted', + 'vname' => 'LBL_DELETED', + 'type' => 'bool', + 'required' => false, + 'default' => '0', + 'reportable'=>false, + ), + 'date_entered' => array ( + 'name' => 'date_entered', + 'vname' => 'LBL_DATE_ENTERED', + 'type' => 'datetime', + 'required' => true, + ), + 'date_modified' => array ( + 'name' => 'date_modified', + 'vname' => 'LBL_DATE_MODIFIED', + 'type' => 'datetime', + 'required' => true, + ), + 'scheduler_id' => array ( + 'name' => 'scheduler_id', + 'vname' => 'LBL_SCHEDULER_ID', + 'type' => 'id', + 'db_type' => 'varchar', + 'len' => 36, + 'required' => true, + 'reportable' => false, + ), + 'execute_time' => array ( + 'name' => 'execute_time', + 'vname' => 'LBL_EXECUTE_TIME', + 'type' => 'datetime', + 'required' => true, + 'reportable' => true, + ), + 'status' => array ( + 'name' => 'status', + 'vname' => 'LBL_STATUS', + 'type' => 'varchar', + 'len' => '25', + 'required' => true, + 'reportable' => true, + 'default' => 'ready', + ), + ), + 'indices' => array ( + array( + 'name' =>'schedulers_timespk', + 'type' =>'primary', + 'fields' => array( + 'id' + ) + ), + array( + 'name' =>'idx_scheduler_id', + 'type'=>'index', + 'fields' => array( + 'scheduler_id', + 'execute_time', + ) + ), + ), +); + + +?> diff --git a/metadata/user_feedsMetaData.php b/metadata/user_feedsMetaData.php new file mode 100644 index 00000000..4190fdb1 --- /dev/null +++ b/metadata/user_feedsMetaData.php @@ -0,0 +1,52 @@ + 'users_feeds' + , 'fields' => array ( + + array('name' =>'user_id', 'type' =>'varchar', 'len'=>'36', ) + , array('name' =>'feed_id', 'type' =>'varchar', 'len'=>'36', ) + , array('name' =>'rank', 'type' =>'int', 'required' => false) + , array ('name' => 'date_modified','type' => 'datetime') + , array('name' =>'deleted', 'type' =>'bool', 'len'=>'', 'default'=>'0', 'required' => false) + ) + , 'indices' => array ( + + array('name' =>'idx_ud_user_id', 'type' =>'index', 'fields'=>array('user_id', 'feed_id')) + ) + ) +?> diff --git a/metadata/usersMetaData.php b/metadata/usersMetaData.php new file mode 100644 index 00000000..faeb1bdf --- /dev/null +++ b/metadata/usersMetaData.php @@ -0,0 +1,39 @@ + diff --git a/metadata/users_last_importMetaData.php b/metadata/users_last_importMetaData.php new file mode 100644 index 00000000..544fba50 --- /dev/null +++ b/metadata/users_last_importMetaData.php @@ -0,0 +1,51 @@ + 'users_last_import' + , 'fields' => array ( + array('name' =>'id', 'type' =>'varchar', 'len'=>'36') + , array('name' =>'assigned_user_id', 'type' =>'varchar', 'len'=>'36') + , array('name' =>'bean_type', 'type' =>'varchar', 'len'=>'36') + , array('name' =>'bean_id', 'type' =>'varchar', 'len'=>'36',) + , array ('name' => 'date_modified','type' => 'datetime') + , array('name' =>'deleted', 'required'=>false, 'type' =>'bool', 'len'=>'1') + ) , 'indices' => array ( + array('name' =>'users_last_importpk', 'type' =>'primary', 'fields'=>array('id')) + , array('name' =>'idx_user_id', 'type' =>'index', 'fields'=>array('assigned_user_id')) + ) + ) +?> diff --git a/metadata/users_passwordLinkMetaData.php b/metadata/users_passwordLinkMetaData.php new file mode 100644 index 00000000..2c374595 --- /dev/null +++ b/metadata/users_passwordLinkMetaData.php @@ -0,0 +1,84 @@ + 'users_password_link', + 'fields' => array( + 'id' => array( + 'name' => 'id', + 'vname' => 'LBL_ID', + 'type' => 'id', + 'required' => true, + ) , + 'username' => array( + 'name' => 'username', + 'vname' => 'LBL_USERNAME', + 'type' => 'varchar', + 'len' => 36, + ) , + 'date_generated' => array( + 'name' => 'date_generated', + 'vname' => 'LBL_DATE_ENTERED', + 'type' => 'datetime', + ) , + 'deleted' => array( + 'name' => 'deleted', + 'vname' => 'LBL_DELETED', + 'type' => 'bool', + 'required' => false, + 'reportable' => false, + ) , + ) , + 'indices' => array( + array( + 'name' => 'users_password_link_pk', + 'type' => 'primary', + 'fields' => array( + 'id' + ) + ) , + array( + 'name' => 'idx_username', + 'type' => 'index', + 'fields' => array( + 'username' + ) + ) + ) , +); + +?> \ No newline at end of file diff --git a/metadata/users_signaturesMetaData.php b/metadata/users_signaturesMetaData.php new file mode 100644 index 00000000..3069acbe --- /dev/null +++ b/metadata/users_signaturesMetaData.php @@ -0,0 +1,108 @@ + 'users_signatures', + 'fields' => array( + 'id' => array( + 'name' => 'id', + 'vname' => 'LBL_ID', + 'type' => 'id', + 'required' => true, + ), + 'date_entered' => array ( + 'name' => 'date_entered', + 'vname' => 'LBL_DATE_ENTERED', + 'type' => 'datetime', + 'required'=>true, + ), + 'date_modified' => array ( + 'name' => 'date_modified', + 'vname' => 'LBL_DATE_MODIFIED', + 'type' => 'datetime', + 'required'=>true, + ), + 'deleted' => array ( + 'name' => 'deleted', + 'vname' => 'LBL_DELETED', + 'type' => 'bool', + 'required' => false, + 'reportable'=>false, + ), + 'user_id' => array( + 'name' => 'user_id', + 'vname' => 'LBL_USER_ID', + 'type' => 'varchar', + 'len' => 36, + ), + 'name' => array( + 'name' => 'name', + 'vname' => 'LBL_SUBJECT', + 'type' => 'varchar', + 'required' => false, + 'len' => '255', + ), + 'signature' => array( + 'name' => 'signature', + 'vname' => 'LBL_SIGNATURE', + 'type' => 'text', + 'reportable' => false, + ), + 'signature_html' => array( + 'name' => 'signature_html', + 'vname' => 'LBL_SIGNATURE_HTML', + 'type' => 'text', + 'reportable' => false, + ), + ), + 'indices' => array( + array( + 'name' => 'users_signaturespk', + 'type' =>'primary', + 'fields' => array('id') + ), + array( + 'name' => 'idx_usersig_uid', + 'type' => 'index', + 'fields' => array('user_id') + ) + ), +); +?> \ No newline at end of file diff --git a/metagen.php b/metagen.php new file mode 100644 index 00000000..f8f6ea26 --- /dev/null +++ b/metagen.php @@ -0,0 +1,39 @@ + \ No newline at end of file diff --git a/modules/ACL/ACLController.php b/modules/ACL/ACLController.php new file mode 100644 index 00000000..e9aa387f --- /dev/null +++ b/modules/ACL/ACLController.php @@ -0,0 +1,231 @@ +id, 'Calls', $action,$type, $is_owner) || ACLAction::userHasAccess($current_user->id, 'Meetings', $action,'module', $is_owner) || ACLAction::userHasAccess($current_user->id, 'Tasks', $action,'module', $is_owner); + } + if($category == 'Activities'){ + return ACLAction::userHasAccess($current_user->id, 'Calls', $action,$type, $is_owner) || ACLAction::userHasAccess($current_user->id, 'Meetings', $action,'module', $is_owner) || ACLAction::userHasAccess($current_user->id, 'Tasks', $action,'module', $is_owner)|| ACLAction::userHasAccess($current_user->id, 'Emails', $action,'module', $is_owner)|| ACLAction::userHasAccess($current_user->id, 'Notes', $action,'module', $is_owner); + } + return ACLAction::userHasAccess($current_user->id, $category, $action,$type, $is_owner); + } + + function requireOwner($category, $value, $type='module'){ + global $current_user; + if(is_admin($current_user))return false; + return ACLAction::userNeedsOwnership($current_user->id, $category, $value,$type); + } + + function filterModuleList(&$moduleList, $by_value=true){ + + global $aclModuleList, $current_user; + if(is_admin($current_user)) return; + $actions = ACLAction::getUserActions($current_user->id, false); + + $compList = array(); + if($by_value){ + foreach($moduleList as $key=>$value){ + $compList[$value]= $key; + } + }else{ + $compList =& $moduleList; + } + foreach($actions as $action_name=>$action){ + + if(!empty($action['module'])){ + $aclModuleList[$action_name] = $action_name; + if(isset($compList[$action_name])){ + if($action['module']['access']['aclaccess'] < ACL_ALLOW_ENABLED){ + if($by_value){ + unset($moduleList[$compList[$action_name]]); + }else{ + unset($moduleList[$action_name]); + } + } + } + } + } + if(isset($compList['Calendar']) && + !( ACLController::checkModuleAllowed('Calls', $actions) || ACLController::checkModuleAllowed('Meetings', $actions) || ACLController::checkModuleAllowed('Tasks', $actions))) + { + if($by_value){ + unset($moduleList[$compList['Calendar']]); + }else{ + unset($moduleList['Calendar']); + } + if(isset($compList['Activities']) && + !( ACLController::checkModuleAllowed('Notes', $actions) || ACLController::checkModuleAllowed('Notes', $actions))){ + if($by_value){ + unset($moduleList[$compList['Activities']]); + }else{ + unset($moduleList['Activities']); + } + } + } + + } + + /** + * Check to see if the module is available for this user. + * + * @param String $module_name + * @return true if they are allowed. false otherwise. + */ + function checkModuleAllowed($module_name, $actions) + { + if(!empty($actions[$module_name]['module']['access']['aclaccess']) && + ACL_ALLOW_ENABLED == $actions[$module_name]['module']['access']['aclaccess']) + { + return true; + } + + return false; + } + + function disabledModuleList($moduleList, $by_value=true,$view='list'){ + global $aclModuleList, $current_user; + if(is_admin($GLOBALS['current_user'])) return array(); + $actions = ACLAction::getUserActions($current_user->id, false); + $disabled = array(); + $compList = array(); + + if($by_value){ + foreach($moduleList as $key=>$value){ + $compList[$value]= $key; + } + }else{ + $compList =& $moduleList; + } + if(isset($moduleList['ProductTemplates'])){ + $moduleList['Products'] ='Products'; + } + + foreach($actions as $action_name=>$action){ + + if(!empty($action['module'])){ + $aclModuleList[$action_name] = $action_name; + if(isset($compList[$action_name])){ + if($action['module']['access']['aclaccess'] < ACL_ALLOW_ENABLED || $action['module'][$view]['aclaccess'] < 0){ + if($by_value){ + $disabled[$compList[$action_name]] =$compList[$action_name] ; + }else{ + $disabled[$action_name] = $action_name; + } + } + } + } + } + if(isset($compList['Calendar']) && !( ACL_ALLOW_ENABLED == $actions['Calls']['module']['access']['aclaccess'] || ACL_ALLOW_ENABLED == $actions['Meetings']['module']['access']['aclaccess'] || ACL_ALLOW_ENABLED == $actions['Tasks']['module']['access']['aclaccess'])){ + if($by_value){ + $disabled[$compList['Calendar']] = $compList['Calendar']; + }else{ + $disabled['Calendar'] = 'Calendar'; + } + if(isset($compList['Activities']) &&!( ACL_ALLOW_ENABLED == $actions['Notes']['module']['access']['aclaccess'] || ACL_ALLOW_ENABLED == $actions['Notes']['module']['access']['aclaccess'] )){ + if($by_value){ + $disabled[$compList['Activities']] = $compList['Activities']; + }else{ + $disabled['Activities'] = 'Activities'; + } + } + } + if(isset($disabled['Products'])){ + $disabled['ProductTemplates'] = 'ProductTemplates'; + } + + + return $disabled; + + } + + + + function addJavascript($category,$form_name='', $is_owner=false){ + $jscontroller = new ACLJSController($category, $form_name, $is_owner); + echo $jscontroller->getJavascript(); + } + + function moduleSupportsACL($module){ + static $checkModules = array(); + global $beanFiles, $beanList; + if(isset($checkModules[$module])){ + return $checkModules[$module]; + } + if(!isset($beanList[$module])){ + $checkModules[$module] = false; + + }else{ + $class = $beanList[$module]; + require_once($beanFiles[$class]); + $mod = new $class(); + if(!is_subclass_of($mod, 'SugarBean')){ + $checkModules[$module] = false; + }else{ + $checkModules[$module] = $mod->bean_implements('ACL'); + } + } + return $checkModules[$module] ; + + } + + function displayNoAccess($redirect_home = false){ + echo '

    ' . translate('LBL_NO_ACCESS', 'ACL') . '

    '; + if($redirect_home)echo 'Redirect to Home in 3 seconds'; + } + +} + + + + + + + + + +?> \ No newline at end of file diff --git a/modules/ACL/ACLJSController.php b/modules/ACL/ACLJSController.php new file mode 100644 index 00000000..8e6363b6 --- /dev/null +++ b/modules/ACL/ACLJSController.php @@ -0,0 +1,178 @@ +module = $module; + $this->is_owner = $is_owner; + $this->form = $form; + } + + function getJavascript(){ + global $action; + if(!ACLController::moduleSupportsACL($this->module)){ + return ''; + } + $script = "'; + + return $script; + + + } + + function getHTMLValues($def){ + $return_array = array(); + switch($def['display_option']){ + case 'clear_link': + $return_array['href']= "#"; + $return_array['className']= "nolink"; + break; + default; + $return_array[$def['display_option']] = $def['display_option']; + break; + + } + return $return_array; + + } + + function getFieldByIdScript($name, $def){ + $script = ''; + if(!ACLController::checkAccess($def['module'], $def['action_option'], true)){ + foreach($this->getHTMLValues($def) as $key=>$value){ + $script .= "\nif(document.getElementById('$name'))document.getElementById('$name')." . $key . '="' .$value. '";'. "\n"; + } + } + return $script; + + } + + function getFieldByNameScript($name, $def){ + $script = ''; + if(!ACLController::checkAccess($def['module'], $def['action_option'], true)){ + + foreach($this->getHTMLValues($def) as $key=>$value){ + $script .= <<getHTMLValues($def) as $key=>$value){ + $script .= "\nif(typeof(document.$form.$name.$key) != 'undefined')\n document.$form.$name.".$key . '="' .$value. '";'; + } + } + return $script; + + } + + + + + + + + +} + + + +?> \ No newline at end of file diff --git a/modules/ACL/Forms.php b/modules/ACL/Forms.php new file mode 100644 index 00000000..e69de29b diff --git a/modules/ACL/List.php b/modules/ACL/List.php new file mode 100644 index 00000000..e2ff65bd --- /dev/null +++ b/modules/ACL/List.php @@ -0,0 +1,46 @@ + \ No newline at end of file diff --git a/modules/ACL/Menu.php b/modules/ACL/Menu.php new file mode 100644 index 00000000..4fae814d --- /dev/null +++ b/modules/ACL/Menu.php @@ -0,0 +1,44 @@ + \ No newline at end of file diff --git a/modules/ACL/Save.php b/modules/ACL/Save.php new file mode 100644 index 00000000..cb5f8f95 --- /dev/null +++ b/modules/ACL/Save.php @@ -0,0 +1,40 @@ + \ No newline at end of file diff --git a/modules/ACL/install_actions.php b/modules/ACL/install_actions.php new file mode 100644 index 00000000..b44c2b51 --- /dev/null +++ b/modules/ACL/install_actions.php @@ -0,0 +1,76 @@ +$class){ + + if(empty($installed_classes[$class]) && isset($beanFiles[$class]) && file_exists($beanFiles[$class])){ + if($class == 'Tracker'){ + } else { + require_once($beanFiles[$class]); + $mod = new $class(); + $GLOBALS['log']->debug("DOING: $class"); + if($mod->bean_implements('ACL') && empty($mod->acl_display_only)){ + // BUG 10339: do not display messages for upgrade wizard + if(!isset($_REQUEST['upgradeWizard'])){ + echo translate('LBL_ADDING','ACL','') . $mod->module_dir . '
    '; + } + if(!empty($mod->acltype)){ + ACLAction::addActions($mod->getACLCategory(), $mod->acltype); + }else{ + ACLAction::addActions($mod->getACLCategory()); + } + + $installed_classes[$class] = true; + } + } + } + } + + +} +?> \ No newline at end of file diff --git a/modules/ACL/language/en_us.lang.php b/modules/ACL/language/en_us.lang.php new file mode 100644 index 00000000..dab46b7d --- /dev/null +++ b/modules/ACL/language/en_us.lang.php @@ -0,0 +1,53 @@ +'All', +'LBL_ALLOW_NONE'=>'None', +'LBL_ALLOW_OWNER'=>'Owner', +'LBL_ROLE'=>'Role', +'LBL_NAME'=>'Name', +'LBL_DESCRIPTION'=>'Description', +'LIST_ROLES'=>'List Roles', +'LBL_USERS_SUBPANEL_TITLE'=>'Users', +'LIST_ROLES_BY_USER'=>'List Roles By User', +'LBL_ROLES_SUBPANEL_TITLE'=>'User Roles', +'LBL_SEARCH_FORM_TITLE'=>'Search', +'LBL_NO_ACCESS'=>'You do not have access to this area. Contact your site administrator to obtain access.', +'LBL_ADDING'=>'Adding for ', +) +?> \ No newline at end of file diff --git a/modules/ACL/metadata/subpaneldefs.php b/modules/ACL/metadata/subpaneldefs.php new file mode 100644 index 00000000..7a68f50d --- /dev/null +++ b/modules/ACL/metadata/subpaneldefs.php @@ -0,0 +1,73 @@ + array( + 'users' => array( + 'top_buttons' => array( array('widget_class' => 'SubPanelTopSubModuleSelectButton', 'popup_module' => 'Users'),), + 'order' => 20, + 'module' => 'Users', + 'subpanel_name' => 'ForSubModules', + 'get_subpanel_data' => 'users', + 'add_subpanel_data' => 'user_id', + 'title_key' => 'LBL_USERS_SUBPANEL_TITLE', + ), + ), +); +$layout_defs['UserRoles'] = array( + // sets up which panels to show, in which order, and with what linked_fields + 'subpanel_setup' => array( + 'acl' => array( + 'top_buttons' => array(array('widget_class' => 'SubPanelTopSubModuleSelectButton', 'popup_module' => 'ACL'),), + 'order' => 20, + 'module' => 'ACL', + 'subpanel_def_path'=>'modules/ACL/Roles/subpanels/default.php', + 'subpanel_name' => 'default', + 'get_subpanel_data' => 'roles', + 'add_subpanel_data' => 'role_id', + 'title_key' => 'LBL_ROLES_SUBPANEL_TITLE', + ), + ), + +); + + +?> \ No newline at end of file diff --git a/modules/ACL/remove_actions.php b/modules/ACL/remove_actions.php new file mode 100644 index 00000000..17275325 --- /dev/null +++ b/modules/ACL/remove_actions.php @@ -0,0 +1,58 @@ +category]) || !file_exists($beanFiles[$beanList[$actionobj->category]])){ + if(!isset($_REQUEST['upgradeWizard'])){ + echo 'Removing for ' . $actionobj->category . '
    '; + } + $foundOne = true; + ACLAction::removeActions($actionobj->category); + } + } + if(!$foundOne) + echo 'No ACL modules found that needed to be removed'; +} + + +?> \ No newline at end of file diff --git a/modules/ACL/vardefs.php b/modules/ACL/vardefs.php new file mode 100644 index 00000000..f8f23685 --- /dev/null +++ b/modules/ACL/vardefs.php @@ -0,0 +1,41 @@ + diff --git a/modules/ACLActions/ACLAction.php b/modules/ACLActions/ACLAction.php new file mode 100644 index 00000000..138d9657 --- /dev/null +++ b/modules/ACLActions/ACLAction.php @@ -0,0 +1,510 @@ +$action_def){ + + $action = new ACLAction(); + $query = "SELECT * FROM " . $action->table_name . " WHERE name='$action_name' AND category = '$category' AND acltype='$type' AND deleted=0 "; + $result = $db->query($query); + //only add if an action with that name and category don't exist + $row=$db->fetchByAssoc($result); + if ($row == null) { + $action->name = $action_name; + $action->category = $category; + $action->aclaccess = $action_def['default']; + $action->acltype = $type; + $action->modified_user_id = 1; + $action->created_by = 1; + $action->save(); + + } + } + + }else{ + sugar_die("FAILED TO ADD: $category - TYPE $type NOT DEFINED IN modules/ACLActions/actiondefs.php"); + } + + } + + /** + * static removeActions($category, $type='module') + * Removes all default actions for a category/type + * + * @param STRING $category - the category (e.g module name - Accounts, Contacts) + * @param STRING $type - the type (e.g. 'module', 'field') + */ + function removeActions($category, $type='module'){ + global $ACLActions; + $db = DBManagerFactory::getInstance(); + if(isset($ACLActions[$type])){ + foreach($ACLActions[$type]['actions'] as $action_name =>$action_def){ + + $action = new ACLAction(); + $query = "SELECT * FROM " . $action->table_name . " WHERE name='$action_name' AND category = '$category' AND acltype='$type' and deleted=0"; + $result = $db->query($query); + //only add if an action with that name and category don't exist + $row=$db->fetchByAssoc($result); + if ($row != null) { + $action->mark_deleted($row['id']); + } + } + }else{ + sugar_die("FAILED TO REMOVE: $category : $name - TYPE $type NOT DEFINED IN modules/ACLActions/actiondefs.php"); + } + } + + /** + * static AccessColor($access) + * + * returns the color associated with an access level + * these colors exist in the definitions in modules/ACLActions/actiondefs.php + * @param INT $access - the access level you want the color for + * @return the color either name or hex representation or false if the level does not exist + */ + function AccessColor($access){ + global $ACLActionAccessLevels; + if(isset($ACLActionAccessLevels[$access])){ + + return $ACLActionAccessLevels[$access]['color']; + } + return false; + + } + + /** + * static AccessName($access) + * + * returns the translated name associated with an access level + * these label definitions exist in the definitions in modules/ACLActions/actiondefs.php + * @param INT $access - the access level you want the color for + * @return the translated access level name or false if the level does not exist + */ + function AccessName($access){ + global $ACLActionAccessLevels; + if(isset($ACLActionAccessLevels[$access])){ + return translate($ACLActionAccessLevels[$access]['label'], 'ACLActions'); + } + return false; + + } + + /** + * static AccessLabel($access) + * + * returns the label associated with an access level + * these label definitions exist in the definitions in modules/ACLActions/actiondefs.php + * @param INT $access - the access level you want the color for + * @return the access level label or false if the level does not exist + */ + function AccessLabel($access){ + global $ACLActionAccessLevels; + if(isset($ACLActionAccessLevels[$access])){ + $label=preg_replace('/(LBL_ACCESS_)(.*)/', '$2', $ACLActionAccessLevels[$access]['label']); + return strtolower($label); + + } + return false; + + } + + /** + * static getAccessOptions() + * this is used for building select boxes + * @return array containg access levels (ints) as keys and access names as values + */ + function getAccessOptions( $action, $type='module'){ + global $ACLActions; + $options = array(); + + if(empty($ACLActions[$type]['actions'][$action]['aclaccess']))return $options; + foreach($ACLActions[$type]['actions'][$action]['aclaccess'] as $action){ + $options[$action] = ACLAction::AccessName($action); + } + return $options; + + } + + /** + * function static getDefaultActions() + * This function will return a list of acl actions with their default access levels + * + * + */ + function getDefaultActions($type='module', $action=''){ + $query = "SELECT * FROM acl_actions WHERE deleted=0 "; + if(!empty($type)){ + $query .= " AND acltype='$type'"; + } + if(!empty($action)){ + $query .= "AND name='$action'"; + } + $query .= " ORDER BY category"; + + $db = DBManagerFactory::getInstance(); + $result = $db->query($query); + $default_actions = array(); + while($row = $db->fetchByAssoc($result) ){ + $acl = new ACLAction(); + $acl->populateFromRow($row); + $default_actions[] = $acl; + } + return $default_actions; + } + + + /** + * static getUserActions($user_id,$refresh=false, $category='', $action='') + * returns a list of user actions + * @param GUID $user_id + * @param BOOLEAN $refresh + * @param STRING $category + * @param STRING $action + * @return ARRAY of ACLActionsArray + */ + + function getUserActions($user_id,$refresh=false, $category='',$type='', $action=''){ + //check in the session if we already have it loaded + if(!$refresh && !empty($_SESSION['ACL'][$user_id])){ + if(empty($category) && empty($action)){ + return $_SESSION['ACL'][$user_id]; + }else{ + if(!empty($category) && isset($_SESSION['ACL'][$user_id][$category])){ + if(empty($action)){ + if(empty($type)){ + return $_SESSION['ACL'][$user_id][$category]; + } + return $_SESSION['ACL'][$user_id][$category][$type]; + }else if(!empty($type) && isset($_SESSION['ACL'][$user_id][$category][$type][$action])){ + return $_SESSION['ACL'][$user_id][$category][$type][$action]; + } + } + } + } + //if we don't have it loaded then lets check against the db + $additional_where = ''; + $db = DBManagerFactory::getInstance(); + if(!empty($category)){ + $additional_where .= " AND $this->table_name.category = '$category' "; + } + if(!empty($action)){ + $additional_where .= " AND $this->table_name.name = '$action' "; + } + if(!empty($type)){ + $additional_where .= " AND $this->table_name.acltype = '$type' "; + } + $query=null; + if ($db->dbType == 'oci8') { + } + if (empty($query)) { + $query = "SELECT acl_actions .*, acl_roles_actions.access_override + FROM acl_actions + LEFT JOIN acl_roles_users ON acl_roles_users.user_id = '$user_id' AND acl_roles_users.deleted = 0 + LEFT JOIN acl_roles_actions ON acl_roles_actions.role_id = acl_roles_users.role_id AND acl_roles_actions.action_id = acl_actions.id AND acl_roles_actions.deleted=0 + WHERE acl_actions.deleted=0 $additional_where ORDER BY category,name"; + } + $result = $db->query($query); + $selected_actions = array(); + while($row = $db->fetchByAssoc($result) ){ + $acl = new ACLAction(); + $isOverride = false; + $acl->populateFromRow($row); + if(!empty($row['access_override'])){ + $acl->aclaccess = $row['access_override']; + $isOverride = true; + } + if(!isset($selected_actions[$acl->category])){ + $selected_actions[$acl->category] = array(); + + } + if(!isset($selected_actions[$acl->category][$acl->acltype][$acl->name]) + || ($selected_actions[$acl->category][$acl->acltype][$acl->name]['aclaccess'] > $acl->aclaccess + && $isOverride + ) + || + (!empty($selected_actions[$acl->category][$acl->acltype][$acl->name]['isDefault']) + && $isOverride + ) + ) + { + + + $selected_actions[$acl->category][$acl->acltype][$acl->name] = $acl->toArray(); + $selected_actions[$acl->category][$acl->acltype][$acl->name]['isDefault'] = !$isOverride; + } + + } + + //only set the session variable if it was a full list; + if(empty($category) && empty($action)){ + if(!isset($_SESSION['ACL'])){ + $_SESSION['ACL'] = array(); + } + $_SESSION['ACL'][$user_id] = $selected_actions; + }else{ + if(empty($action) && !empty($category)){ + if(!empty($type)){ + $_SESSION['ACL'][$user_id][$category][$type] = $selected_actions[$category][$type];} + $_SESSION['ACL'][$user_id][$category] = $selected_actions[$category]; + }else{ + if(!empty($action) && !empty($category) && !empty($type)){ + $_SESSION['ACL'][$user_id][$category][$type][$action] = $selected_actions[$category][$action]; + + } + } + } + return $selected_actions; + } + /** + * (static/ non-static)function hasAccess($is_owner= false , $access = 0) + * checks if a user has access to this acl if the user is an owner it will check if owners have access + * + * This function may either be used statically or not. If used staticlly a user must pass in an access level not equal to zero + * @param boolean $is_owner + * @param int $access + * @return true or false + */ + function hasAccess($is_owner=false, $access = 0){ + + if($access != 0 && $access == ACL_ALLOW_ALL || ($is_owner && $access == ACL_ALLOW_OWNER))return true; + if(isset($this) && isset($this->aclaccess)){ + if($this->aclaccess == ACL_ALLOW_ALL || ($is_owner && $this->aclaccess == ACL_ALLOW_OWNER)) + return true; + } + return false; + } + + + + + + + + + + /** + * static function userHasAccess($user_id, $category, $action, $is_owner = false) + * + * @param GUID $user_id the user id who you want to check access for + * @param STRING $category the category you would like to check access for + * @param STRING $action the action of that category you would like to check access for + * @param BOOLEAN OPTIONAL $is_owner if the object is owned by the user you are checking access for + */ + function userHasAccess($user_id, $category, $action,$type='module', $is_owner = false){ + global $current_user; + if(is_admin_for_module($current_user,$category)&& !isset($_SESSION['ACL'][$user_id][$category][$type][$action]['aclaccess'])){ + return true; + } + //check if we don't have it set in the cache if not lets reload the cache + if(ACLAction::getUserAccessLevel($user_id, $category, 'access', $type) < ACL_ALLOW_ENABLED) return false; + if(empty($_SESSION['ACL'][$user_id][$category][$type][$action])){ + ACLAction::getUserActions($user_id, false); + + } + + if(!empty($_SESSION['ACL'][$user_id][$category][$type][$action])){ + return ACLAction::hasAccess($is_owner, $_SESSION['ACL'][$user_id][$category][$type][$action]['aclaccess']); + } + return false; + + } + /** + * function getUserAccessLevel($user_id, $category, $action,$type='module') + * returns the access level for a given category and action + * + * @param GUID $user_id + * @param STRING $category + * @param STRING $action + * @param STRING $type + * @return INT (ACCESS LEVEL) + */ + function getUserAccessLevel($user_id, $category, $action,$type='module'){ + if(empty($_SESSION['ACL'][$user_id][$category][$type][$action])){ + ACLAction::getUserActions($user_id, false); + + } + if(!empty($_SESSION['ACL'][$user_id][$category][$type][$action])){ + return $_SESSION['ACL'][$user_id][$category][$type][$action]['aclaccess']; + } + } + + /** + * STATIC function userNeedsOwnership($user_id, $category, $action,$type='module') + * checks if a user should have ownership to do an action + * + * @param GUID $user_id + * @param STRING $category + * @param STRING $action + * @param STRING $type + * @return boolean + */ + function userNeedsOwnership($user_id, $category, $action,$type='module'){ + //check if we don't have it set in the cache if not lets reload the cache + + if(empty($_SESSION['ACL'][$user_id][$category][$type][$action])){ + ACLAction::getUserActions($user_id, false); + + } + + + if(!empty($_SESSION['ACL'][$user_id][$category][$type][$action])){ + return $_SESSION['ACL'][$user_id][$category][$type][$action]['aclaccess'] == ACL_ALLOW_OWNER; + } + return false; + + } + /** + * + * static pass by ref setupCategoriesMatrix(&$categories) + * takes in an array of categories and modifes them adding display information + * + * @param unknown_type $categories + */ + function setupCategoriesMatrix(&$categories){ + global $ACLActions, $current_user; + $names = array(); + $disabled = array(); + foreach($categories as $cat_name=>$category){ + foreach($category as $type_name=>$type){ + foreach($type as $act_name=>$action){ + $names[$act_name] = translate($ACLActions[$type_name]['actions'][$act_name]['label'], 'ACLActions'); + $categories[$cat_name][$type_name][$act_name]['accessColor'] = ACLAction::AccessColor($action['aclaccess']); + if($type_name== 'module'){ + + if($act_name != 'aclaccess' && $categories[$cat_name]['module']['access']['aclaccess'] == ACL_ALLOW_DISABLED){ + $categories[$cat_name][$type_name][$act_name]['accessColor'] = 'darkgray'; + $disabled[] = $cat_name; + } + + } + $categories[$cat_name][$type_name][$act_name]['accessName'] = ACLAction::AccessName($action['aclaccess']); + $categories[$cat_name][$type_name][$act_name]['accessLabel'] = ACLAction::AccessLabel($action['aclaccess']); + + if($cat_name=='Users'&& $act_name=='admin'){ + $categories[$cat_name][$type_name][$act_name]['accessOptions'][ACL_ALLOW_DEFAULT]=ACLAction::AccessName(ACL_ALLOW_DEFAULT);; + $categories[$cat_name][$type_name][$act_name]['accessOptions'][ACL_ALLOW_DEV]=ACLAction::AccessName(ACL_ALLOW_DEV);; + } + else{ + $categories[$cat_name][$type_name][$act_name]['accessOptions'] = ACLAction::getAccessOptions($act_name, $type_name); + } + } + } + } + + if(!is_admin($current_user)){ + foreach($disabled as $cat_name){ + unset($categories[$cat_name]); + } + } + return $names; + } + + + + /** + * function toArray() + * returns this acl as an array + * + * @return array of fields with id, name, access and category + */ + function toArray(){ + $array_fields = array('id', 'aclaccess'); + $arr = array(); + foreach($array_fields as $field){ + $arr[$field] = $this->$field; + } + return $arr; + } + + /** + * function fromArray($arr) + * converts an array into an acl mapping name value pairs into files + * + * @param Array $arr + */ + function fromArray($arr){ + foreach($arr as $name=>$value){ + $this->$name = $value; + } + } + + /** + * function clearSessionCache() + * clears the session variable storing the cache information for acls + * + */ + function clearSessionCache(){ + unset($_SESSION['ACL']); + } + + + + + + + + + + + + + +} + + +?> \ No newline at end of file diff --git a/modules/ACLActions/Forms.php b/modules/ACLActions/Forms.php new file mode 100644 index 00000000..e69de29b diff --git a/modules/ACLActions/Menu.php b/modules/ACLActions/Menu.php new file mode 100644 index 00000000..4fae814d --- /dev/null +++ b/modules/ACLActions/Menu.php @@ -0,0 +1,44 @@ + \ No newline at end of file diff --git a/modules/ACLActions/actiondefs.php b/modules/ACLActions/actiondefs.php new file mode 100644 index 00000000..de85d91c --- /dev/null +++ b/modules/ACLActions/actiondefs.php @@ -0,0 +1,126 @@ +array('color'=>'#008000', 'label'=>'LBL_ACCESS_ALL', 'text_color'=>'white'), + ACL_ALLOW_OWNER=>array('color'=>'#6F6800', 'label'=>'LBL_ACCESS_OWNER', 'text_color'=>'white'), + ACL_ALLOW_NONE=>array('color'=>'#FF0000', 'label'=>'LBL_ACCESS_NONE', 'text_color'=>'white'), + ACL_ALLOW_ENABLED=>array('color'=>'#008000', 'label'=>'LBL_ACCESS_ENABLED', 'text_color'=>'white'), + ACL_ALLOW_DISABLED=>array('color'=>'#FF0000', 'label'=>'LBL_ACCESS_DISABLED', 'text_color'=>'white'), + ACL_ALLOW_ADMIN=>array('color'=>'#0000FF', 'label'=>'LBL_ACCESS_ADMIN', 'text_color'=>'white'), + ACL_ALLOW_NORMAL=>array('color'=>'#008000', 'label'=>'LBL_ACCESS_NORMAL', 'text_color'=>'white'), + ACL_ALLOW_DEFAULT=>array('color'=>'#008000', 'label'=>'LBL_ACCESS_DEFAULT', 'text_color'=>'white'), + ACL_ALLOW_DEV=>array('color'=>'#0000FF', 'label'=>'LBL_ACCESS_DEV', 'text_color'=>'white'), + ACL_ALLOW_ADMIN_DEV=>array('color'=>'#0000FF', 'label'=>'LBL_ACCESS_ADMIN_DEV', 'text_color'=>'white'), + ); +/** + * $GLOBALS['ACLActions + * These are the actions for a given type. It includes the ACCESS Levels for that action and the label for that action. Every an object of the category (e.g. module) is added all associated actions are added for that object + */ +$GLOBALS['ACLActions'] = array( + 'module'=>array('actions'=> + array( + 'access'=> + array( + 'aclaccess'=>array(ACL_ALLOW_ENABLED,ACL_ALLOW_DEFAULT, ACL_ALLOW_DISABLED), + 'label'=>'LBL_ACTION_ACCESS', + 'default'=>ACL_ALLOW_ENABLED, + ), + + 'view'=> + array( + 'aclaccess'=>array(ACL_ALLOW_ALL,ACL_ALLOW_OWNER,ACL_ALLOW_DEFAULT, ACL_ALLOW_NONE), + 'label'=>'LBL_ACTION_VIEW', + 'default'=>ACL_ALLOW_ALL, + ), + + 'list'=> + array( + 'aclaccess'=>array(ACL_ALLOW_ALL,ACL_ALLOW_OWNER,ACL_ALLOW_DEFAULT, ACL_ALLOW_NONE), + 'label'=>'LBL_ACTION_LIST', + 'default'=>ACL_ALLOW_ALL, + ), + 'edit'=> + array( + 'aclaccess'=>array(ACL_ALLOW_ALL,ACL_ALLOW_OWNER,ACL_ALLOW_DEFAULT, ACL_ALLOW_NONE), + 'label'=>'LBL_ACTION_EDIT', + 'default'=>ACL_ALLOW_ALL, + + ), + 'delete'=> + array( + 'aclaccess'=>array(ACL_ALLOW_ALL,ACL_ALLOW_OWNER,ACL_ALLOW_DEFAULT, ACL_ALLOW_NONE), + 'label'=>'LBL_ACTION_DELETE', + 'default'=>ACL_ALLOW_ALL, + + ), + 'import'=> + array( + 'aclaccess'=>array(ACL_ALLOW_ALL,ACL_ALLOW_DEFAULT, ACL_ALLOW_NONE), + 'label'=>'LBL_ACTION_IMPORT', + 'default'=>ACL_ALLOW_ALL, + ), + 'export'=> + array( + 'aclaccess'=>array(ACL_ALLOW_ALL,ACL_ALLOW_OWNER,ACL_ALLOW_DEFAULT, ACL_ALLOW_NONE), + 'label'=>'LBL_ACTION_EXPORT', + 'default'=>ACL_ALLOW_ALL, + ), + + + + ),), +); + + +?> \ No newline at end of file diff --git a/modules/ACLActions/language/en_us.lang.php b/modules/ACLActions/language/en_us.lang.php new file mode 100644 index 00000000..2127c55b --- /dev/null +++ b/modules/ACLActions/language/en_us.lang.php @@ -0,0 +1,65 @@ +'All', +'LBL_ACCESS_NONE'=>'None', +'LBL_ACCESS_OWNER'=>'Owner', +'LBL_ACCESS_NORMAL'=>'Normal', +'LBL_ACCESS_ADMIN'=>'Admin', +'LBL_ACCESS_ENABLED'=>'Enabled', +'LBL_ACCESS_DISABLED'=>'Disabled', +'LBL_ACCESS_DEV'=>'Developer', +'LBL_ACCESS_ADMIN_DEV'=>'Admin & Developer', +'LBL_NAME'=>'Name', +'LBL_DESCRIPTION'=>'Description', +'LIST_ROLES'=>'List Roles', +'LBL_USERS_SUBPANEL_TITLE'=>'Users', +'LIST_ROLES_BY_USER'=>'List Roles By User', +'LBL_ROLES_SUBPANEL_TITLE'=>'User Roles', +'LBL_SEARCH_FORM_TITLE'=>'Search', +'LBL_ACTION_VIEW'=>'View', +'LBL_ACTION_EDIT'=>'Edit', +'LBL_ACTION_DELETE'=>'Delete', +'LBL_ACTION_IMPORT'=>'Import', +'LBL_ACTION_EXPORT'=>'Export', +'LBL_ACTION_LIST'=>'List', +'LBL_ACTION_ACCESS'=>'Access', +'LBL_ACTION_ADMIN'=>'Access Type', +'LBL_ACCESS_DEFAULT'=>'Not Set', +) +?> \ No newline at end of file diff --git a/modules/ACLActions/metadata/subpaneldefs.php b/modules/ACLActions/metadata/subpaneldefs.php new file mode 100644 index 00000000..7a68f50d --- /dev/null +++ b/modules/ACLActions/metadata/subpaneldefs.php @@ -0,0 +1,73 @@ + array( + 'users' => array( + 'top_buttons' => array( array('widget_class' => 'SubPanelTopSubModuleSelectButton', 'popup_module' => 'Users'),), + 'order' => 20, + 'module' => 'Users', + 'subpanel_name' => 'ForSubModules', + 'get_subpanel_data' => 'users', + 'add_subpanel_data' => 'user_id', + 'title_key' => 'LBL_USERS_SUBPANEL_TITLE', + ), + ), +); +$layout_defs['UserRoles'] = array( + // sets up which panels to show, in which order, and with what linked_fields + 'subpanel_setup' => array( + 'acl' => array( + 'top_buttons' => array(array('widget_class' => 'SubPanelTopSubModuleSelectButton', 'popup_module' => 'ACL'),), + 'order' => 20, + 'module' => 'ACL', + 'subpanel_def_path'=>'modules/ACL/Roles/subpanels/default.php', + 'subpanel_name' => 'default', + 'get_subpanel_data' => 'roles', + 'add_subpanel_data' => 'role_id', + 'title_key' => 'LBL_ROLES_SUBPANEL_TITLE', + ), + ), + +); + + +?> \ No newline at end of file diff --git a/modules/ACLActions/vardefs.php b/modules/ACLActions/vardefs.php new file mode 100644 index 00000000..b99797a3 --- /dev/null +++ b/modules/ACLActions/vardefs.php @@ -0,0 +1,154 @@ + 'acl_actions', 'comment' => 'Determine the allowable actions available to users' + ,'fields' => array ( + 'id' => + array ( + 'name' => 'id', + 'vname' => 'LBL_ID', + 'required'=>true, + 'type' => 'id', + 'reportable'=>false, + 'comment' => 'Unique identifier' + ), + 'date_entered' => + array ( + 'name' => 'date_entered', + 'vname' => 'LBL_DATE_ENTERED', + 'type' => 'datetime', + 'required'=>true, + 'comment' => 'Date record created' + ), + 'date_modified' => + array ( + 'name' => 'date_modified', + 'vname' => 'LBL_DATE_MODIFIED', + 'type' => 'datetime', + 'required'=>true, + 'comment' => 'Date record last modified' + ), + 'modified_user_id' => + array ( + 'name' => 'modified_user_id', + 'rname' => 'user_name', + 'id_name' => 'modified_user_id', + 'vname' => 'LBL_MODIFIED', + 'type' => 'assigned_user_name', + 'table' => 'modified_user_id_users', + 'isnull' => 'false', + 'dbType' => 'id', + 'required'=> false, + 'len' => 36, + 'reportable'=>true, + 'comment' => 'User who last modified record' + ), + 'created_by' => + array ( + 'name' => 'created_by', + 'rname' => 'user_name', + 'id_name' => 'created_by', + 'vname' => 'LBL_CREATED', + 'type' => 'assigned_user_name', + 'table' => 'created_by_users', + 'isnull' => 'false', + 'dbType' => 'id', + 'len' => 36, + 'comment' => 'User ID who created record' + ), + 'name' => + array ( + 'name' => 'name', + 'type' => 'varchar', + 'vname' => 'LBL_NAME', + 'len' => 150, + 'comment' => 'Name of the allowable action (view, list, delete, edit)' + ), + 'category' => + array ( + 'name' => 'category', + 'vname' => 'LBL_CATEGORY', + 'type' => 'varchar', + 'len' =>100, + 'reportable'=>true, + 'comment' => 'Category of the allowable action (usually the name of a module)' + ), + 'acltype' => + array ( + 'name' => 'acltype', + 'vname' => 'LBL_TYPE', + 'type' => 'varchar', + 'len' =>100, + 'reportable'=>true, + 'comment' => 'Specifier for Category, usually "module"' + ), + 'aclaccess' => + array ( + 'name' => 'aclaccess', + 'vname' => 'LBL_ACCESS', + 'type' => 'int', + 'len'=>3, + 'reportable'=>true, + 'comment' => 'Number specifying access priority; highest access "wins"' + ), + 'deleted' => + array ( + 'name' => 'deleted', + 'vname' => 'LBL_DELETED', + 'type' => 'bool', + 'reportable'=>false, + 'comment' => 'Record deletion indicator' + ), + 'roles' => + array ( + 'name' => 'roles', + 'type' => 'link', + 'relationship' => 'acl_roles_actions', + 'source'=>'non-db', + 'vname'=>'LBL_USERS', + ), +), +'indices' => array ( + array('name' =>'aclactionid', 'type' =>'primary', 'fields'=>array('id')), + array('name' =>'idx_aclaction_id_del', 'type' =>'index', 'fields'=>array('id', 'deleted')), + array('name' =>'idx_category_name', 'type' =>'index', 'fields'=>array('category', 'name')), ) + + ); +?> \ No newline at end of file diff --git a/modules/ACLRoles/ACLRole.php b/modules/ACLRoles/ACLRole.php new file mode 100644 index 00000000..42fad02e --- /dev/null +++ b/modules/ACLRoles/ACLRole.php @@ -0,0 +1,274 @@ +'users' + ); + + var $created_by; + + function ACLRole(){ + parent::SugarBean(); + } + + // bug 16790 - missing get_summary_text method led Tracker to display SugarBean's "base implementation" + function get_summary_text() + { + return "$this->name"; + } + + +/** + * function setAction($role_id, $action_id, $access) + * + * Sets the relationship between a role and an action and sets the access level of that relationship + * + * @param GUID $role_id - the role id + * @param GUID $action_id - the ACL Action id + * @param int $access - the access level ACL_ALLOW_ALL ACL_ALLOW_NONE ACL_ALLOW_OWNER... + */ +function setAction($role_id, $action_id, $access){ + $relationship_data = array('role_id'=>$role_id, 'action_id'=>$action_id,); + $additional_data = array('access_override'=>$access); + $this->set_relationship('acl_roles_actions',$relationship_data,true, true,$additional_data); +} + + +/** + * static getUserRoles($user_id) + * returns a list of ACLRoles for a given user id + * + * @param GUID $user_id + * @return a list of ACLRole objects + */ +function getUserRoles($user_id, $getAsNameArray = true){ + + //if we don't have it loaded then lets check against the db + $additional_where = ''; + $query = "SELECT acl_roles.* ". + "FROM acl_roles ". + "INNER JOIN acl_roles_users ON acl_roles_users.user_id = '$user_id' ". + "AND acl_roles_users.role_id = acl_roles.id AND acl_roles_users.deleted = 0 ". + "WHERE acl_roles.deleted=0 "; + + $result = $GLOBALS['db']->query($query); + $user_roles = array(); + + while($row = $GLOBALS['db']->fetchByAssoc($result) ){ + $role = new ACLRole(); + $role->populateFromRow($row); + if($getAsNameArray) + $user_roles[] = $role->name; + else + $user_roles[] = $role; + } + + return $user_roles; +} + +/** + * static getUserRoleNames($user_id) + * returns a list of Role names for a given user id + * + * @param GUID $user_id + * @return a list of ACLRole Names + */ +function getUserRoleNames($user_id){ + + $user_roles = sugar_cache_retrieve("RoleMembershipNames_".$user_id); + + if(!$user_roles){ + //if we don't have it loaded then lets check against the db + $additional_where = ''; + $query = "SELECT acl_roles.* ". + "FROM acl_roles ". + "INNER JOIN acl_roles_users ON acl_roles_users.user_id = '$user_id' ". + "AND acl_roles_users.role_id = acl_roles.id AND acl_roles_users.deleted = 0 ". + "WHERE acl_roles.deleted=0 "; + + $result = $GLOBALS['db']->query($query); + $user_roles = array(); + + while($row = $GLOBALS['db']->fetchByAssoc($result) ){ + $user_roles[] = $row['name']; + } + + sugar_cache_put("RoleMembershipNames_".$user_id, $user_roles); + } + + return $user_roles; +} + + +/** + * static getAllRoles($returnAsArray = false) + * + * @param boolean $returnAsArray - should it return the results as an array of arrays or as an array of ACLRoles + * @return either an array of array representations of acl roles or an array of ACLRoles + */ +function getAllRoles($returnAsArray = false){ + $db = DBManagerFactory::getInstance(); + $query = "SELECT acl_roles.* FROM acl_roles + WHERE acl_roles.deleted=0 ORDER BY name"; + + $result = $db->query($query); + $roles = array(); + + while($row = $db->fetchByAssoc($result) ){ + $role = new ACLRole(); + $role->populateFromRow($row); + if($returnAsArray){ + $roles[] = $role->toArray(); + }else{ + $roles[] = $role; + } + + } + return $roles; + + +} + +/** + * static getRoleActions($role_id) + * + * gets the actions of a given role + * + * @param GUID $role_id + * @return array of actions + */ +function getRoleActions($role_id, $type='module'){ + global $beanList; + //if we don't have it loaded then lets check against the db + $additional_where = ''; + $db = DBManagerFactory::getInstance(); + $query = "SELECT acl_actions.*"; + //only if we have a role id do we need to join the table otherwise lets use the ones defined in acl_actions as the defaults + if(!empty($role_id)){ + $query .=" ,acl_roles_actions.access_override "; + } + $query .=" FROM acl_actions "; + + if(!empty($role_id)){ + $query .= " LEFT JOIN acl_roles_actions ON acl_roles_actions.role_id = '$role_id' AND acl_roles_actions.action_id = acl_actions.id AND acl_roles_actions.deleted = 0"; + } + $query .= " WHERE acl_actions.deleted=0 ORDER BY acl_actions.category, acl_actions.name"; + $result = $db->query($query); + $role_actions = array(); + + while($row = $db->fetchByAssoc($result) ){ + $action = new ACLAction(); + $action->populateFromRow($row); + if(!empty($row['access_override'])){ + $action->aclaccess = $row['access_override']; + }else{ + $action->aclaccess = ACL_ALLOW_DEFAULT; + + } + //#27877 . If there is no this module in beanlist , we will not show them in UI, no matter this module was deleted or not in ACL_ACTIONS table. + if(empty($beanList[$action->category])){ + continue; + } + //end + + if(!isset($role_actions[$action->category])){ + $role_actions[$action->category] = array(); + } + + $role_actions[$action->category][$action->acltype][$action->name] = $action->toArray(); + + + } + return $role_actions; + + } +/** + * function mark_relationships_deleted($id) + * + * special case to delete acl_roles_actions relationship + * + * @param ACLRole GUID $id + */ +function mark_relationships_deleted($id){ + //we need to delete the actions relationship by hand (special case) + $date_modified = db_convert("'".TimeDate::getInstance()->nowDb()."'", 'datetime'); + $query = "UPDATE acl_roles_actions SET deleted=1 , date_modified=$date_modified WHERE role_id = '$id' AND deleted=0"; + $this->db->query($query); + parent::mark_relationships_deleted($id); +} + +/** + * toArray() + * returns this role as an array + * + * @return array of fields with id, name, description + */ + function toArray(){ + $array_fields = array('id', 'name', 'description'); + $arr = array(); + foreach($array_fields as $field){ + if(isset($this->$field)){ + $arr[$field] = $this->$field; + }else{ + $arr[$field] = ''; + } + } + return $arr; + } + + /** + * fromArray($arr) + * converts an array into an role mapping name value pairs into files + * + * @param Array $arr + */ + function fromArray($arr){ + foreach($arr as $name=>$value){ + $this->$name = $value; + } + } +} + +?> \ No newline at end of file diff --git a/modules/ACLRoles/ACLRoles.js b/modules/ACLRoles/ACLRoles.js new file mode 100644 index 00000000..84b34099 --- /dev/null +++ b/modules/ACLRoles/ACLRoles.js @@ -0,0 +1,36 @@ +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ +var aclviewer=function(){var lastDisplay='';return{view:function(role_id,role_module){YAHOO.util.Connect.asyncRequest('POST','index.php',{'success':aclviewer.display,'failure':aclviewer.failed},'module=ACLRoles&action=EditRole&record='+role_id+'&category_name='+role_module);ajaxStatus.showStatus(SUGAR.language.get('app_strings','LBL_REQUEST_PROCESSED'));},save:function(form_name){var formObject=document.getElementById(form_name);YAHOO.util.Connect.setForm(formObject);YAHOO.util.Connect.asyncRequest('POST','index.php',{'success':aclviewer.postSave,'failure':aclviewer.failed});ajaxStatus.showStatus(SUGAR.language.get('app_strings','LBL_SAVING'));},postSave:function(o){eval(o.responseText);aclviewer.view(result['role_id'],result['module']);},display:function(o){aclviewer.lastDisplay='';ajaxStatus.flashStatus('Done');document.getElementById('category_data').innerHTML=o.responseText;},failed:function(){ajax.flashStatus('Could Not Connect');},toggleDisplay:function(id){if(aclviewer.lastDisplay!=''&&typeof(aclviewer.lastDisplay)!='undefined'){aclviewer.hideDisplay(aclviewer.lastDisplay);} +if(aclviewer.lastDisplay!=id){aclviewer.showDisplay(id);aclviewer.lastDisplay=id;}else{aclviewer.lastDisplay='';}},hideDisplay:function(id){document.getElementById(id).style.display='none';document.getElementById(id+'link').style.display='';},showDisplay:function(id){document.getElementById(id).style.display='';document.getElementById(id+'link').style.display='none';}};}(); \ No newline at end of file diff --git a/modules/ACLRoles/Delete.php b/modules/ACLRoles/Delete.php new file mode 100644 index 00000000..0a83ac5d --- /dev/null +++ b/modules/ACLRoles/Delete.php @@ -0,0 +1,46 @@ +mark_deleted($_REQUEST['record']); +} +require_once('include/formbase.php'); +handleRedirect(); + +?> \ No newline at end of file diff --git a/modules/ACLRoles/DetailUserRole.php b/modules/ACLRoles/DetailUserRole.php new file mode 100644 index 00000000..dcbc34a2 --- /dev/null +++ b/modules/ACLRoles/DetailUserRole.php @@ -0,0 +1,92 @@ +retrieve($_REQUEST['record']); +if ( !is_admin($focus) ) { + $sugar_smarty = new Sugar_Smarty(); + $sugar_smarty->assign('MOD', $mod_strings); + $sugar_smarty->assign('APP', $app_strings); + $sugar_smarty->assign('APP_LIST', $app_list_strings); + + $categories = ACLAction::getUserActions($_REQUEST['record'],true); + + //clear out any removed tabs from user display + if(!is_admin($current_user)&& !is_admin_for_module($GLOBALS['current_user'],'Users')){ + $tabs = $focus->getPreference('display_tabs'); + global $modInvisList; + if(!empty($tabs)){ + foreach($categories as $key=>$value){ + if(!in_array($key, $tabs) && !in_array($key, $modInvisList) ){ + unset($categories[$key]); + + } + } + + } + } + + $names = array(); + $names = ACLAction::setupCategoriesMatrix($categories); + if(!empty($names))$tdwidth = 100 / sizeof($names); + $sugar_smarty->assign('APP', $app_list_strings); + $sugar_smarty->assign('CATEGORIES', $categories); + $sugar_smarty->assign('TDWIDTH', $tdwidth); + $sugar_smarty->assign('ACTION_NAMES', $names); + + $title = getClassicModuleTitle( '',array($mod_strings['LBL_MODULE_NAME'],$mod_strings['LBL_ROLES_SUBPANEL_TITLE']), ''); + + $sugar_smarty->assign('TITLE', $title); + $sugar_smarty->assign('USER_ID', $focus->id); + $sugar_smarty->assign('LAYOUT_DEF_KEY', 'UserRoles'); + echo $sugar_smarty->fetch('modules/ACLRoles/DetailViewUser.tpl'); + + + //this gets its layout_defs.php file from the user not from ACLRoles so look in modules/Users for the layout defs + require_once('include/SubPanel/SubPanelTiles.php'); + $modules_exempt_from_availability_check=array('Users'=>'Users','ACLRoles'=>'ACLRoles',); + $subpanel = new SubPanelTiles($focus, 'UserRoles'); + + echo $subpanel->display(true,true); +} diff --git a/modules/ACLRoles/DetailView.php b/modules/ACLRoles/DetailView.php new file mode 100644 index 00000000..f53f6bd2 --- /dev/null +++ b/modules/ACLRoles/DetailView.php @@ -0,0 +1,98 @@ +assign('MOD', $mod_strings); +$sugar_smarty->assign('APP', $app_strings); + +//nsingh bug: 21669. Messes up localization +/*foreach($modInvisList as $modinvisname){ + if(empty($app_list_strings['moduleList'][$modinvisname])){ + $app_list_strings['moduleList'][$modinvisname] = $modinvisname; + } +}*/ +$sugar_smarty->assign('APP_LIST', $app_list_strings); +/*foreach($modInvisList as $modinvisname){ + unset($app_list_strings['moduleList'][$modinvisname]); +}*/ +$role = new ACLRole(); +$role->retrieve($_REQUEST['record']); +$categories = ACLRole::getRoleActions($_REQUEST['record']); +$names = ACLAction::setupCategoriesMatrix($categories); + +$categories2 = array(); +$categories2=$categories; +$hidden_categories = array( +"KBDocuments", "Campaigns","Forecasts","ForecastSchedule", +"Emails","EmailTemplates","EmailMarketing","Reports"); +foreach($hidden_categories as $v){ + if (isset($categories2[$v])) { + unset($categories2[$v]); + } +} +if(!empty($names))$tdwidth = 100 / sizeof($names); +$sugar_smarty->assign('ROLE', $role->toArray()); +$sugar_smarty->assign('CATEGORIES', $categories); +$sugar_smarty->assign('CATEGORIES2', $categories2); +$sugar_smarty->assign('TDWIDTH', $tdwidth); +$sugar_smarty->assign('ACTION_NAMES', $names); + +$return= array('module'=>'ACLRoles', 'action'=>'DetailView', 'record'=>$role->id); +$sugar_smarty->assign('RETURN', $return); +$params = array(); +$params[] = "{$mod_strings['LBL_MODULE_NAME']}"; +$params[] = $role->get_summary_text(); +echo getClassicModuleTitle("ACLRoles", $params, true); +//$sugar_smarty->assign('TITLE', $title); +$hide_hide_supanels = true; + +echo $sugar_smarty->fetch('modules/ACLRoles/DetailView.tpl'); +//for subpanels the variable must be named focus; +$focus =& $role; +$_REQUEST['module'] = 'ACLRoles'; +require_once('include/SubPanel/SubPanelTiles.php'); + +$subpanel = new SubPanelTiles($role, 'ACLRoles'); + +echo $subpanel->display(); + + + +?> \ No newline at end of file diff --git a/modules/ACLRoles/DetailView.tpl b/modules/ACLRoles/DetailView.tpl new file mode 100644 index 00000000..5f2540c1 --- /dev/null +++ b/modules/ACLRoles/DetailView.tpl @@ -0,0 +1,70 @@ +{* + +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + + + +*} + + +
    + + + + + + + + + + + + +
    +

    +

    + + + + + +
    {$MOD.LBL_NAME}:{$ROLE.name}
    {$MOD.LBL_DESCRIPTION}:{$ROLE.description | nl2br}
    +

    +

    + +{include file="modules/ACLRoles/EditViewBody.tpl" } \ No newline at end of file diff --git a/modules/ACLRoles/DetailViewBody.tpl b/modules/ACLRoles/DetailViewBody.tpl new file mode 100644 index 00000000..a8311c47 --- /dev/null +++ b/modules/ACLRoles/DetailViewBody.tpl @@ -0,0 +1,92 @@ +{* + +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + + + +*} + + + + + +{foreach from=$ACTION_NAMES item="ACTION_NAME" } + +{foreachelse} + + + +{/foreach} + +{foreach from=$CATEGORIES item="TYPES" key="CATEGORY_NAME"} + + + {if $APP_LIST.moduleList[$CATEGORY_NAME]!='Users'} + + + + {if $APP_LIST.moduleList[$CATEGORY_NAME]=='Users'} + + {else} + + {/if} + {foreach from=$ACTION_NAMES item="ACTION_LABEL" key="ACTION_NAME"} + {assign var='ACTION_FIND' value='false'} + {foreach from=$TYPES item="ACTIONS" key="TYPE_NAME"} + {foreach from=$ACTIONS item="ACTION" key="ACTION_NAME_ACTIVE"} + {if $ACTION_NAME==$ACTION_NAME_ACTIVE} + {assign var='ACTION_FIND' value='true'} + + {/if} + {/foreach} + {/foreach} + {if $ACTION_FIND=='false'} + + {/if} + {/foreach} + + + + {/if} + + +{foreachelse} + +{/foreach} +
    {$ACTION_NAME} 
    {$MOD.LBL_USER_NAME_FOR_ROLE}{$APP_LIST.moduleList[$CATEGORY_NAME]}
    {$ACTION.accessName}
    +
    N/A
    +
    No Actions
    \ No newline at end of file diff --git a/modules/ACLRoles/DetailViewUser.tpl b/modules/ACLRoles/DetailViewUser.tpl new file mode 100644 index 00000000..8545490b --- /dev/null +++ b/modules/ACLRoles/DetailViewUser.tpl @@ -0,0 +1,46 @@ +{* + +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + + + +*} + + + + +{include file="modules/ACLRoles/DetailViewBody.tpl" } \ No newline at end of file diff --git a/modules/ACLRoles/EditAllBody.tpl b/modules/ACLRoles/EditAllBody.tpl new file mode 100644 index 00000000..48e7c200 --- /dev/null +++ b/modules/ACLRoles/EditAllBody.tpl @@ -0,0 +1,127 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} +

    + + + + + + +   + +

    +

    +

    + + + + +{foreach from=$ACTION_NAMES item="ACTION_NAME" } + +{foreachelse} + + + +{/foreach} + +{literal} + + {/literal} +{foreach from=$CATEGORIES item="TYPES" key="CATEGORY_NAME"} + + + {if $APP_LIST.moduleList[$CATEGORY_NAME]!='Users'} + + + + {foreach from=$ACTION_NAMES item="ACTION_LABEL" key="ACTION_NAME"} + {assign var='ACTION_FIND' value='false'} + {foreach from=$TYPES item="ACTIONS"} + {foreach from=$ACTIONS item="ACTION" key="ACTION_NAME_ACTIVE"} + {if $ACTION_NAME==$ACTION_NAME_ACTIVE} + + {assign var='ACTION_FIND' value='true'} + {/if} + {/foreach} + {/foreach} + {if $ACTION_FIND=='false'} + + {/if} + {/foreach} + + + + {/if} + + +{foreachelse} + +{/foreach} +
    {$ACTION_NAME}
     
    + {if $APP_LIST.moduleList[$CATEGORY_NAME]=='Users'} + {$MOD.LBL_USER_NAME_FOR_ROLE} + {elseif !empty($APP_LIST.moduleList[$CATEGORY_NAME])} + {$APP_LIST.moduleList[$CATEGORY_NAME]} + {else} + {$CATEGORY_NAME} + {/if} + + + {if $ACTION.accessLabel == 'dev' || $ACTION.accessLabel == 'admin_dev'} + + {else} + + {/if} + +
    N/A
    +
    No Actions Defined
    +
      + +
    +
    \ No newline at end of file diff --git a/modules/ACLRoles/EditRole.php b/modules/ACLRoles/EditRole.php new file mode 100644 index 00000000..fb136000 --- /dev/null +++ b/modules/ACLRoles/EditRole.php @@ -0,0 +1,103 @@ +assign('MOD', $mod_strings); +$sugar_smarty->assign('APP', $app_strings); +//mass localization +/*foreach($modInvisList as $modinvisname){ + $app_list_strings['moduleList'][$modinvisname] = $modinvisname; +}*/ +$sugar_smarty->assign('APP_LIST', $app_list_strings); +/*foreach($modInvisList as $modinvisname){ + unset($app_list_strings['moduleList'][$modinvisname]); +}*/ +$role = new ACLRole(); +$role_name = ''; +$return= array('module'=>'ACLRoles', 'action'=>'index', 'record'=>''); +if(!empty($_REQUEST['record'])){ + $role->retrieve($_REQUEST['record']); + $categories = ACLRole::getRoleActions($_REQUEST['record']); + + $role_name = $role->name; + if(!empty($_REQUEST['isDuplicate'])){ + //role id is stripped here in duplicate so anything using role id after this will not have it + $role->id = ''; + }else{ + $return['record']= $role->id; + $return['action']='DetailView'; + } + +}else{ + $categories = ACLRole::getRoleActions(''); +} +$sugar_smarty->assign('ROLE', $role->toArray()); +$tdwidth = 10; + +if(isset($_REQUEST['return_module'])){ + $return['module']=$_REQUEST['return_module']; + if(isset($_REQUEST['return_action']))$return['action']=$_REQUEST['return_action']; + if(isset($_REQUEST['return_record']))$return['record']=$_REQUEST['return_record']; +} + +$sugar_smarty->assign('RETURN', $return); +$names = ACLAction::setupCategoriesMatrix($categories); +if(!empty($names))$tdwidth = 100 / sizeof($names); +$sugar_smarty->assign('CATEGORIES', $categories); +$sugar_smarty->assign('CATEGORY_NAME', $_REQUEST['category_name']); +$sugar_smarty->assign('TDWIDTH', $tdwidth); +$sugar_smarty->assign('ACTION_NAMES', $names); +$actions = $categories[$_REQUEST['category_name']]['module']; +$sugar_smarty->assign('ACTIONS', $actions); +ob_clean(); + +if($_REQUEST['category_name'] == 'All'){ + echo $sugar_smarty->fetch('modules/ACLRoles/EditAllBody.tpl'); +}else{ +//WDong Bug 23195: Strings not localized in Role Management. +echo getClassicModuleTitle($_REQUEST['category_name'],array($app_list_strings['moduleList'][$_REQUEST['category_name']]), false); +echo $sugar_smarty->fetch('modules/ACLRoles/EditRole.tpl'); +echo ''; +} +sugar_cleanup(true); \ No newline at end of file diff --git a/modules/ACLRoles/EditRole.tpl b/modules/ACLRoles/EditRole.tpl new file mode 100644 index 00000000..81a02ff0 --- /dev/null +++ b/modules/ACLRoles/EditRole.tpl @@ -0,0 +1,96 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} +
    + + + + + + +   + +
    + +{if !empty($CATEGORIES[$CATEGORY_NAME])} + + {foreach from=$ACTION_NAMES item="ACTION_LABEL" key="ACTION_NAME"} + {foreach from=$CATEGORIES[$CATEGORY_NAME] item="ACTIONS"} + {foreach from=$ACTIONS item="ACTION" key="ACTION_NAME_ACTIVE"} + {if $ACTION_NAME==$ACTION_NAME_ACTIVE} + + {/if} + {/foreach} + {/foreach} + {foreachelse} + + + + {/foreach} + + + + {foreach from=$ACTION_NAMES item="ACTION_LABEL" key="ACTION_NAME"} + {foreach from=$CATEGORIES[$CATEGORY_NAME] item="ACTIONS"} + {foreach from=$ACTIONS item="ACTION" key="ACTION_NAME_ACTIVE"} + {if $ACTION_NAME==$ACTION_NAME_ACTIVE} + + {/if} + {/foreach} + {/foreach} + {foreachelse} + + {/foreach} + + +{else} + +{/if} +
    {$ACTION_LABEL}
     
    + + +  
    No Actions Defined
    \ No newline at end of file diff --git a/modules/ACLRoles/EditView.php b/modules/ACLRoles/EditView.php new file mode 100644 index 00000000..8f57239f --- /dev/null +++ b/modules/ACLRoles/EditView.php @@ -0,0 +1,108 @@ +assign('MOD', $mod_strings); +$sugar_smarty->assign('APP', $app_strings); +$sugar_smarty->assign('ISDUPLICATE', ''); +$duplicateString=''; +//mass localization +/*foreach($modInvisList as $modinvisname){ + $app_list_strings['moduleList'][$modinvisname] = $modinvisname; +}*/ +$sugar_smarty->assign('APP_LIST', $app_list_strings); +/*foreach($modInvisList as $modinvisname){ + unset($app_list_strings['moduleList'][$modinvisname]); +}*/ +$role = new ACLRole(); +$role_name = ''; +$return= array('module'=>'ACLRoles', 'action'=>'index', 'record'=>''); +if(!empty($_REQUEST['record'])){ + $role->retrieve($_REQUEST['record']); + $categories = ACLRole::getRoleActions($_REQUEST['record']); + $role_name = $role->name; + if(!empty($_REQUEST['isDuplicate'])){ + //role id is stripped here in duplicate so anything using role id after this will not have it + $role->id = ''; + $sugar_smarty->assign('ISDUPLICATE', $_REQUEST['record']); + $duplicateString=translate('LBL_DUPLICATE_OF', 'ACLRoles'); + }else{ + $return['record']= $role->id; + $return['action']='DetailView'; + } + +}else{ + $categories = ACLRole::getRoleActions(''); +} +$sugar_smarty->assign('ROLE', $role->toArray()); +$tdwidth = 10; + +if(isset($_REQUEST['return_module'])){ + $return['module']=$_REQUEST['return_module']; + if(isset($_REQUEST['return_id']))$return['record']=$_REQUEST['return_id']; + if(isset($_REQUEST['return_record'])){$return['record']=$_REQUEST['return_record'];} + if(isset($_REQUEST['return_action'])){$return['action']=$_REQUEST['return_action'];} + if ( !empty($return['record']) ) { + $return['action'] = 'DetailView'; + } +} + +$sugar_smarty->assign('RETURN', $return); +$names = ACLAction::setupCategoriesMatrix($categories); + +$sugar_smarty->assign('CATEGORIES', $categories); +$sugar_smarty->assign('TDWIDTH', $tdwidth); +$sugar_smarty->assign('ACTION_NAMES', $names); + +$params = array(); +$params[] = "{$mod_strings['LBL_MODULE_NAME']}"; +if(empty($role->id)){ + $params[] = $GLOBALS['app_strings']['LBL_CREATE_BUTTON_LABEL']; +}else{ + $params[] = "".$role->get_summary_text().""; + $params[] = $GLOBALS['app_strings']['LBL_EDIT_BUTTON_LABEL']; +} +echo getClassicModuleTitle("ACLRoles", $params, true); +echo $sugar_smarty->fetch('modules/ACLRoles/EditView.tpl'); + +?> \ No newline at end of file diff --git a/modules/ACLRoles/EditView.tpl b/modules/ACLRoles/EditView.tpl new file mode 100644 index 00000000..a9b7deb2 --- /dev/null +++ b/modules/ACLRoles/EditView.tpl @@ -0,0 +1,85 @@ +{* + +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + + + +*} + + + + + + + + + + + +
    + + + + + + +   + + +
    + + + + + + + + +
    {$MOD.LBL_NAME}:{$APP.LBL_REQUIRED_SYMBOL} + +  
    {$MOD.LBL_DESCRIPTION}:
    + +
    + \ No newline at end of file diff --git a/modules/ACLRoles/EditViewBody.tpl b/modules/ACLRoles/EditViewBody.tpl new file mode 100644 index 00000000..230f1449 --- /dev/null +++ b/modules/ACLRoles/EditViewBody.tpl @@ -0,0 +1,48 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} + +{$MOD.LBL_EDIT_VIEW_DIRECTIONS} + + +
    +
    +{include file='modules/ACLRoles/EditAllBody.tpl'} +
    +
    + + diff --git a/modules/ACLRoles/Forms.php b/modules/ACLRoles/Forms.php new file mode 100644 index 00000000..e69de29b diff --git a/modules/ACLRoles/ListUsers.php b/modules/ACLRoles/ListUsers.php new file mode 100644 index 00000000..37c7bc22 --- /dev/null +++ b/modules/ACLRoles/ListUsers.php @@ -0,0 +1,71 @@ + +
    + + + + + + + + +
    + + + + +"; +if(!empty($record)){ + $hideTeams = true; // to not show the teams subpanel in the following file + require_once('modules/ACLRoles/DetailUserRole.php'); +} + + +?> \ No newline at end of file diff --git a/modules/ACLRoles/Menu.php b/modules/ACLRoles/Menu.php new file mode 100644 index 00000000..1a346e5d --- /dev/null +++ b/modules/ACLRoles/Menu.php @@ -0,0 +1,45 @@ + \ No newline at end of file diff --git a/modules/ACLRoles/Popup_picker.html b/modules/ACLRoles/Popup_picker.html new file mode 100644 index 00000000..83681813 --- /dev/null +++ b/modules/ACLRoles/Popup_picker.html @@ -0,0 +1,108 @@ + + + + + + + + + + + +
    +xxxxx + +
    + + + + + + +{PAGINATION} + + + + + + + + + + + + + + +
    {CHECKALL}{MOD.LBL_NAME}{arrow_start}{name_arrow}{arrow_end}{MOD.LBL_DESCRIPTION}{arrow_start}{description_arrow}{arrow_end}
    {PREROW}{ROLE.NAME}{ROLE.DESCRIPTION}
    +{ASSOCIATED_JAVASCRIPT_DATA} + \ No newline at end of file diff --git a/modules/ACLRoles/Popup_picker.php b/modules/ACLRoles/Popup_picker.php new file mode 100644 index 00000000..bb6ed4cb --- /dev/null +++ b/modules/ACLRoles/Popup_picker.php @@ -0,0 +1,147 @@ +_get_where_clause(); + + $name = empty($_REQUEST['name']) ? '' : $_REQUEST['name']; + $request_data = empty($_REQUEST['request_data']) ? '' : $_REQUEST['request_data']; + $hide_clear_button = empty($_REQUEST['hide_clear_button']) ? false : true; + + $button = "
    \n"; + if(!$hide_clear_button) + { + $button .= "\n"; + } + $button .= "\n"; + $button .= "
    \n"; + + $form = new XTemplate('modules/ACLRoles/Popup_picker.html'); + $form->assign('MOD', $mod_strings); + $form->assign('APP', $app_strings); + $form->assign('MODULE_NAME', $currentModule); + $form->assign('NAME', $name); + $form->assign('request_data', $request_data); + + ob_start(); + insert_popup_header(); + $output_html .= ob_get_contents(); + ob_end_clean(); + + $output_html .= get_form_header($mod_strings['LBL_SEARCH_FORM_TITLE'], '', false); + + $form->parse('main.SearchHeader'); + $output_html .= $form->text('main.SearchHeader'); + + // Reset the sections that are already in the page so that they do not print again later. + $form->reset('main.SearchHeader'); + + // create the listview + $seed_bean = new ACLRole(); + $ListView = new ListView(); + $ListView->show_export_button = false; + $ListView->process_for_popups = true; + $ListView->setXTemplate($form); + $ListView->setHeaderTitle($mod_strings['LBL_ROLE']); + $ListView->setHeaderText($button); + $ListView->setQuery($where, '', 'name', 'ROLE'); + $ListView->setModStrings($mod_strings); + + ob_start(); + $ListView->processListView($seed_bean, 'main', 'ROLE'); + $output_html .= ob_get_contents(); + ob_end_clean(); + + $output_html .= insert_popup_footer(); + return $output_html; + } +} // end of class Popup_Picker +?> \ No newline at end of file diff --git a/modules/ACLRoles/Save.php b/modules/ACLRoles/Save.php new file mode 100644 index 00000000..52261996 --- /dev/null +++ b/modules/ACLRoles/Save.php @@ -0,0 +1,75 @@ +id = $_POST['record']; +if(!empty($_REQUEST['name'])){ + $role->name = $_POST['name']; + $role->description = $_POST['description']; + $role->save(); + //if duplicate + if(isset($_REQUEST['isduplicate']) && !empty($_REQUEST['isduplicate'])){ + //duplicate actions + $role_actions=$role->getRoleActions($_REQUEST['isduplicate']); + foreach($role_actions as $module){ + foreach($module as $type){ + foreach($type as $act){ + $role->setAction($role->id, $act['id'], $act['aclaccess']); + } + } + } + } +}else{ + ob_clean(); + $flc_module = 'All'; + foreach($_POST as $name=>$value){ + if(substr_count($name, 'act_guid') > 0){ + $name = str_replace('act_guid', '', $name); + + $role->setAction($role->id,$name, $value); + } + + } + echo "result = {role_id:'$role->id', module:'$flc_module'}"; + sugar_cleanup(true); +} + +header("Location: index.php?module=ACLRoles&action=DetailView&record=". $role->id); +?> \ No newline at end of file diff --git a/modules/ACLRoles/language/en_us.lang.php b/modules/ACLRoles/language/en_us.lang.php new file mode 100644 index 00000000..a450afc3 --- /dev/null +++ b/modules/ACLRoles/language/en_us.lang.php @@ -0,0 +1,57 @@ + 'Roles', +'LBL_MODULE_TITLE' => 'Roles: Home', +'LBL_ROLE'=>'Role', +'LBL_NAME'=>'Name', +'LBL_DESCRIPTION'=>'Description', +'LIST_ROLES'=>'List Roles', +'LBL_USERS_SUBPANEL_TITLE'=>'Users', +'LIST_ROLES_BY_USER'=>'List Roles By User', +'LBL_LIST_FORM_TITLE' => 'Roles', +'LBL_ROLES_SUBPANEL_TITLE'=>'User Roles', +'LBL_SEARCH_FORM_TITLE'=>'Search', +'LBL_CREATE_ROLE'=>'Create Role', +'LBL_EDIT_VIEW_DIRECTIONS'=>'Double click on a cell to change value.', +'LBL_ACCESS_DEFAULT'=>'Not Set', +'LBL_ACTION_ADMIN'=>'Access Type', +'LBL_ALL'=>'All', +'LBL_DUPLICATE_OF'=>'Duplicate Of ', +) +?> \ No newline at end of file diff --git a/modules/ACLRoles/metadata/SearchFields.php b/modules/ACLRoles/metadata/SearchFields.php new file mode 100644 index 00000000..e69445f0 --- /dev/null +++ b/modules/ACLRoles/metadata/SearchFields.php @@ -0,0 +1,42 @@ + array( 'query_type'=>'default'), + ); +?> diff --git a/modules/ACLRoles/metadata/listviewdefs.php b/modules/ACLRoles/metadata/listviewdefs.php new file mode 100644 index 00000000..9fb27ff4 --- /dev/null +++ b/modules/ACLRoles/metadata/listviewdefs.php @@ -0,0 +1,51 @@ + array( + 'width' => '20', + 'label' => 'LBL_NAME', + 'link' => true, + 'default' => true), + 'DESCRIPTION' => array( + 'width' => '80', + 'label' => 'LBL_DESCRIPTION', + 'default' => true), +); diff --git a/modules/ACLRoles/metadata/popupdefs.php b/modules/ACLRoles/metadata/popupdefs.php new file mode 100644 index 00000000..8405f71d --- /dev/null +++ b/modules/ACLRoles/metadata/popupdefs.php @@ -0,0 +1,50 @@ + 'ACLRole', + 'varName' => 'ROLE', + 'listTitle' => $mod_strings['LBL_ROLE'], + 'orderBy' => 'name', + 'whereClauses' => array('name' => 'acl_roles.name'), + 'searchInputs' => array('name'), + 'searchdefs' => array('name' => array('name' => 'name', 'label' => 'LBL_NAME',),) +); +?> + + \ No newline at end of file diff --git a/modules/ACLRoles/metadata/searchdefs.php b/modules/ACLRoles/metadata/searchdefs.php new file mode 100644 index 00000000..51b5233d --- /dev/null +++ b/modules/ACLRoles/metadata/searchdefs.php @@ -0,0 +1,55 @@ + array( + 'maxColumns' => '3', + 'widths' => array('label' => '10', 'field' => '30'), + ), + 'layout' => array( + 'basic_search' => array( + 'name' => array('name' => 'name', 'label' => 'LBL_NAME',), + ), + 'advanced_search' => array(), + ), + ); +?> diff --git a/modules/ACLRoles/metadata/subpaneldefs.php b/modules/ACLRoles/metadata/subpaneldefs.php new file mode 100644 index 00000000..eb686603 --- /dev/null +++ b/modules/ACLRoles/metadata/subpaneldefs.php @@ -0,0 +1,76 @@ + array( + 'users' => array( + 'top_buttons' => array( array('widget_class' => 'SubPanelTopSelectUsersButton', 'mode' => 'MultiSelect', 'popup_module' => 'Users', 'filter_out_is_admin' => true,),), + 'order' => 20, + 'module' => 'Users', + 'sort_by' => 'user_name', + 'sort_order' => 'asc', + 'subpanel_name' => 'default', + 'get_subpanel_data' => 'users', + 'add_subpanel_data' => 'user_id', + 'title_key' => 'LBL_USERS_SUBPANEL_TITLE', + ), + ), +); +$layout_defs['UserRoles'] = array( + // sets up which panels to show, in which order, and with what linked_fields + 'subpanel_setup' => array( + 'aclroles' => array( + 'top_buttons' => array(array('widget_class' => 'SubPanelTopSelectUsersButton', 'mode' => 'MultiSelect','popup_module' => 'ACLRoles', 'filter_out_is_admin' => true,),), + 'order' => 20, + 'module' => 'ACLRoles', + 'sort_by' => 'name', + 'sort_order' => 'asc', + 'subpanel_name' => 'default', + 'get_subpanel_data' => 'aclroles', + 'add_subpanel_data' => 'role_id', + 'title_key' => 'LBL_ROLES_SUBPANEL_TITLE', + ), + ), + +); + + +?> \ No newline at end of file diff --git a/modules/ACLRoles/metadata/subpanels/admin.php b/modules/ACLRoles/metadata/subpanels/admin.php new file mode 100644 index 00000000..5b6421db --- /dev/null +++ b/modules/ACLRoles/metadata/subpanels/admin.php @@ -0,0 +1,75 @@ + array( + array('widget_class' => 'SubPanelTopCreateButton'), + array('widget_class' => 'SubPanelTopSelectButton'), + ), + + 'where' => '', + 'default_order_by' => '', + + 'list_fields' => array( + 'name'=>array( + 'vname' => 'LBL_NAME', + 'widget_class' => 'SubPanelDetailViewLink', + 'width' => '25%', + ), + 'description'=>array( + 'vname' => 'LBL_DESCRIPTION', + 'width' => '60%', + 'sortable'=>false, + ), + 'edit_button'=>array( + 'vname' => 'LBL_EDIT_BUTTON', + 'widget_class' => 'SubPanelEditButton', + 'module' => 'Contacts', + 'width' => '5%', + ), + 'remove_button'=>array( + 'vname' => 'LBL_REMOVE', + 'widget_class' => 'SubPanelRemoveButton', + 'module' => 'Contacts', + 'width' => '5%', + 'refresh_page'=>true, + ), + ), +); +?> \ No newline at end of file diff --git a/modules/ACLRoles/metadata/subpanels/default.php b/modules/ACLRoles/metadata/subpanels/default.php new file mode 100644 index 00000000..21b6ff16 --- /dev/null +++ b/modules/ACLRoles/metadata/subpanels/default.php @@ -0,0 +1,77 @@ + array( + array('widget_class' => 'SubPanelTopCreateButton'), + array('widget_class' => 'SubPanelTopSelectButton'), + ), + + 'where' => '', + + + 'list_fields' => array( + 'name'=>array( + 'vname' => 'LBL_NAME', + 'width' => '25%', + ), + 'description'=>array( + 'vname' => 'LBL_DESCRIPTION', + 'width' => '70%', + 'sortable'=>false, + ), +/* + 'edit_button'=>array( + 'vname' => 'LBL_EDIT_BUTTON', + 'widget_class' => 'SubPanelEditButton', + 'module' => 'Contacts', + 'width' => '5%', + ), + 'remove_button'=>array( + 'vname' => 'LBL_REMOVE', + 'widget_class' => 'SubPanelRemoveButton', + 'module' => 'Contacts', + 'width' => '5%', + 'refresh_page'=>true, + ), +*/ + + ), +); +?> \ No newline at end of file diff --git a/modules/ACLRoles/popup.tpl b/modules/ACLRoles/popup.tpl new file mode 100644 index 00000000..9953babf --- /dev/null +++ b/modules/ACLRoles/popup.tpl @@ -0,0 +1,77 @@ + + + + + + + + + + + + + +{foreach from=$ROLES item="ROLE"} + + + + + + + +{foreachelse} + + + +{/foreach} + + + +
    {$CHECKALL} {$MOD.LBL_NAME}{$MOD.LBL_DESCRIPTION}
    {$PREROW} {$ROLE.name}{$ROLE.description}
    No Roles
    +{$ASSOCIATED_JAVASCRIPT_DATA} diff --git a/modules/ACLRoles/vardefs.php b/modules/ACLRoles/vardefs.php new file mode 100644 index 00000000..5fd332c1 --- /dev/null +++ b/modules/ACLRoles/vardefs.php @@ -0,0 +1,144 @@ + 'acl_roles', 'comment' => 'ACL Role definition' + ,'fields' => array ( + 'id' => + array ( + 'name' => 'id', + 'vname' => 'LBL_ID', + 'required'=>true, + 'type' => 'id', + 'reportable'=>false, + 'comment' => 'Unique identifier' + ), + 'date_entered' => + array ( + 'name' => 'date_entered', + 'vname' => 'LBL_DATE_ENTERED', + 'type' => 'datetime', + 'required'=>true, + 'comment' => 'Date record created' + ), + 'date_modified' => + array ( + 'name' => 'date_modified', + 'vname' => 'LBL_DATE_MODIFIED', + 'type' => 'datetime', + 'required'=>true, + 'comment' => 'Date record last modified' + ), + 'modified_user_id' => + array ( + 'name' => 'modified_user_id', + 'rname' => 'user_name', + 'id_name' => 'modified_user_id', + 'vname' => 'LBL_MODIFIED', + 'type' => 'assigned_user_name', + 'table' => 'modified_user_id_users', + 'isnull' => 'false', + 'dbType' => 'id', + 'required'=> false, + 'len' => 36, + 'reportable'=>true, + 'comment' => 'User who last modified record' + ), + 'created_by' => + array ( + 'name' => 'created_by', + 'rname' => 'user_name', + 'id_name' => 'created_by', + 'vname' => 'LBL_CREATED', + 'type' => 'assigned_user_name', + 'table' => 'created_by_users', + 'isnull' => 'false', + 'dbType' => 'id', + 'len' => 36, + 'comment' => 'User who created record' + ), + 'name' => + array ( + 'name' => 'name', + 'type' => 'varchar', + 'vname' => 'LBL_NAME', + 'len' => 150, + 'comment' => 'The role name' + ), + 'description' => + array ( + 'name' => 'description', + 'vname' => 'LBL_DESCRIPTION', + 'type' => 'text', + 'comment' => 'The role description' + ), + 'deleted' => + array ( + 'name' => 'deleted', + 'vname' => 'LBL_DELETED', + 'type' => 'bool', + 'reportable'=>false, + 'comment' => 'Record deletion indicator' + ), + 'users' => + array ( + 'name' => 'users', + 'type' => 'link', + 'relationship' => 'acl_roles_users', + 'source'=>'non-db', + 'vname'=>'LBL_USERS', + ), + 'actions' => + array ( + 'name' => 'actions', + 'type' => 'link', + 'relationship' => 'acl_roles_actions', + 'source'=>'non-db', + 'vname'=>'LBL_USERS', + ), +) +, 'indices' => array ( + array('name' =>'aclrolespk', 'type' =>'primary', 'fields'=>array('id')), + array('name' =>'idx_aclrole_id_del', 'type' =>'index', 'fields'=>array('id', 'deleted')), + ) + + ); + + + +?> diff --git a/modules/ACLRoles/views/view.list.php b/modules/ACLRoles/views/view.list.php new file mode 100644 index 00000000..015c25dc --- /dev/null +++ b/modules/ACLRoles/views/view.list.php @@ -0,0 +1,51 @@ +lv = new ListViewSmarty(); + $this->lv->export = false; + $this->lv->showMassupdateFields = false; + } +} diff --git a/modules/Accounts/Account.js b/modules/Accounts/Account.js new file mode 100644 index 00000000..1ea37866 --- /dev/null +++ b/modules/Accounts/Account.js @@ -0,0 +1,50 @@ +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ +function open_contact_popup(module_name,width,height,initial_filter,close_popup,hide_clear_button,popup_request_data,popup_mode,create,metadata) +{window.document.popup_request_data=popup_request_data;window.document.close_popup=close_popup;URL='index.php?mode=MultiSelect&' ++'module='+module_name ++'&action=ContactAddressPopup';if(initial_filter!='') +{URL+='&query=true'+initial_filter;} +if(hide_clear_button) +{URL+='&hide_clear_button=true';} +windowName='popup_window';windowFeatures='width='+width ++',height='+height ++',resizable=1,scrollbars=1';if(popup_mode==''&&popup_mode=='undefined'){popup_mode='single';} +URL+='&mode='+popup_mode;if(create==''&&create=='undefined'){create='false';} +URL+='&create='+create;if(metadata!=''&&metadata!='undefined'){URL+='&metadata='+metadata;} +win=window.open(URL,windowName,windowFeatures);if(window.focus) +{win.focus();} +return win;} +function set_focus(){document.getElementById('name').focus();} \ No newline at end of file diff --git a/modules/Accounts/Account.php b/modules/Accounts/Account.php new file mode 100644 index 00000000..a3322a47 --- /dev/null +++ b/modules/Accounts/Account.php @@ -0,0 +1,341 @@ +'opportunities', 'bug_id' => 'bugs', 'case_id'=>'cases', + 'contact_id'=>'contacts', 'task_id'=>'tasks', 'note_id'=>'notes', + 'meeting_id'=>'meetings', 'call_id'=>'calls', 'email_id'=>'emails','member_id'=>'members', + 'project_id'=>'project', + ); + + //Meta-Data Framework fields + var $push_billing; + var $push_shipping; + + function Account() { + parent::Company(); + + $this->setupCustomFields('Accounts'); + + foreach ($this->field_defs as $field) { + $this->field_name_map[$field['name']] = $field; + } + + + //Combine the email logic original here with bug #26450. + if( (!empty($_REQUEST['parent_id']) && !empty($_REQUEST['parent_type']) && $_REQUEST['parent_type'] == 'Emails' + && !empty($_REQUEST['return_module']) && $_REQUEST['return_module'] == 'Emails' ) + || + (!empty($_REQUEST['parent_type']) && $_REQUEST['parent_type'] != 'Accounts' && + !empty($_REQUEST['return_module']) && $_REQUEST['return_module'] != 'Accounts') ){ + $_REQUEST['parent_name'] = ''; + $_REQUEST['parent_id'] = ''; + } + } + + function get_summary_text() + { + return $this->name; + } + + function get_contacts() { + return $this->get_linked_beans('contacts','Contact'); + } + + + + function clear_account_case_relationship($account_id='', $case_id='') + { + if (empty($case_id)) $where = ''; + else $where = " and id = '$case_id'"; + $query = "UPDATE cases SET account_name = '', account_id = '' WHERE account_id = '$account_id' AND deleted = 0 " . $where; + $this->db->query($query,true,"Error clearing account to case relationship: "); + } + + /** + * This method is used to provide backward compatibility with old data that was prefixed with http:// + * We now automatically prefix http:// + * @deprecated. + */ + function remove_redundant_http() + { /* + if(preg_match("@http://@", $this->website)) + { + $this->website = substr($this->website, 7); + } + */ + } + + function fill_in_additional_list_fields() + { + parent::fill_in_additional_list_fields(); + // Fill in the assigned_user_name + // $this->assigned_user_name = get_assigned_user_name($this->assigned_user_id); + + } + + function fill_in_additional_detail_fields() + { + parent::fill_in_additional_detail_fields(); + + //rrs bug: 28184 - instead of removing this code altogether just adding this check to ensure that if the parent_name + //is empty then go ahead and fill it. + if(empty($this->parent_name) && !empty($this->id)){ + $query = "SELECT a1.name from accounts a1, accounts a2 where a1.id = a2.parent_id and a2.id = '$this->id' and a1.deleted=0"; + $result = $this->db->query($query,true," Error filling in additional detail fields: "); + + // Get the id and the name. + $row = $this->db->fetchByAssoc($result); + + if($row != null) + { + $this->parent_name = $row['name']; + } + else + { + $this->parent_name = ''; + } + } + + // Set campaign name if there is a campaign id + if( !empty($this->campaign_id)){ + + $camp = new Campaign(); + $where = "campaigns.id='{$this->campaign_id}'"; + $campaign_list = $camp->get_full_list("campaigns.name", $where, true); + $this->campaign_name = $campaign_list[0]->name; + } + } + + function get_list_view_data(){ + global $system_config,$current_user; + $temp_array = $this->get_list_view_array(); + $temp_array["ENCODED_NAME"]=$this->name; +// $temp_array["ENCODED_NAME"]=htmlspecialchars($this->name, ENT_QUOTES); + if(!empty($this->billing_address_state)) + { + $temp_array["CITY"] = $this->billing_address_city . ', '. $this->billing_address_state; + } + else + { + $temp_array["CITY"] = $this->billing_address_city; + } + $temp_array["BILLING_ADDRESS_STREET"] = preg_replace("/[\r]/",'',$this->billing_address_street); + $temp_array["SHIPPING_ADDRESS_STREET"] = preg_replace("/[\r]/",'',$this->shipping_address_street); + $temp_array["BILLING_ADDRESS_STREET"] = preg_replace("/[\n]/",'\n',$temp_array["BILLING_ADDRESS_STREET"] ); + $temp_array["SHIPPING_ADDRESS_STREET"] = preg_replace("/[\n]/",'\n',$temp_array["SHIPPING_ADDRESS_STREET"] ); + if(isset($system_config->settings['system_skypeout_on']) && $system_config->settings['system_skypeout_on'] == 1){ + if(!empty($temp_array['PHONE_OFFICE']) && skype_formatted($temp_array['PHONE_OFFICE'])){ + $temp_array['PHONE_OFFICE'] = ''.$temp_array['PHONE_OFFICE']. '' ; + }} + $temp_array["EMAIL1"] = $this->emailAddress->getPrimaryAddress($this); + $this->email1 = $temp_array['EMAIL1']; + $temp_array["EMAIL1_LINK"] = $current_user->getEmailLink('email1', $this, '', '', 'ListView'); + return $temp_array; + } + /** + builds a generic search based on the query string using or + do not include any $this-> because this is called on without having the class instantiated + */ + function build_generic_where_clause ($the_query_string) { + $where_clauses = Array(); + $the_query_string = $this->db->quote($the_query_string); + array_push($where_clauses, "accounts.name like '$the_query_string%'"); + if (is_numeric($the_query_string)) { + array_push($where_clauses, "accounts.phone_alternate like '%$the_query_string%'"); + array_push($where_clauses, "accounts.phone_fax like '%$the_query_string%'"); + array_push($where_clauses, "accounts.phone_office like '%$the_query_string%'"); + } + + $the_where = ""; + foreach($where_clauses as $clause) + { + if(!empty($the_where)) $the_where .= " or "; + $the_where .= $clause; + } + + return $the_where; +} + + + function create_export_query(&$order_by, &$where, $relate_link_join='') + { + $custom_join = $this->custom_fields->getJOIN(true, true,$where); + if($custom_join) + $custom_join['join'] .= $relate_link_join; + $query = "SELECT + accounts.*,email_addresses.email_address email_address, + accounts.name as account_name, + users.user_name as assigned_user_name "; + if($custom_join){ + $query .= $custom_join['select']; + } + $query .= " FROM accounts "; + $query .= "LEFT JOIN users + ON accounts.assigned_user_id=users.id "; + + //join email address table too. + $query .= ' LEFT JOIN email_addr_bean_rel on accounts.id = email_addr_bean_rel.bean_id and email_addr_bean_rel.bean_module=\'Accounts\' and email_addr_bean_rel.deleted=0 and email_addr_bean_rel.primary_address=1 '; + $query .= ' LEFT JOIN email_addresses on email_addresses.id = email_addr_bean_rel.email_address_id ' ; + + if($custom_join){ + $query .= $custom_join['join']; + } + + $where_auto = "( accounts.deleted IS NULL OR accounts.deleted=0 )"; + + if($where != "") + $query .= "where ($where) AND ".$where_auto; + else + $query .= "where ".$where_auto; + + if(!empty($order_by)) + $query .= " ORDER BY ". $this->process_order_by($order_by, null); + + return $query; + } + + function set_notification_body($xtpl, $account) + { + $xtpl->assign("ACCOUNT_NAME", $account->name); + $xtpl->assign("ACCOUNT_TYPE", $account->account_type); + $xtpl->assign("ACCOUNT_DESCRIPTION", $account->description); + + return $xtpl; + } + + function bean_implements($interface){ + switch($interface){ + case 'ACL':return true; + } + return false; + } + function get_unlinked_email_query($type=array()) { + + return get_unlinked_email_query($type, $this); + } + +} \ No newline at end of file diff --git a/modules/Accounts/AccountFormBase.php b/modules/Accounts/AccountFormBase.php new file mode 100644 index 00000000..3836e088 --- /dev/null +++ b/modules/Accounts/AccountFormBase.php @@ -0,0 +1,551 @@ +query($query); + $i=-1; + while(($row=$db->fetchByAssoc($result)) != null) { + $i++; + $rows[$i] = $row; + } + if ($i==-1) return null; + + return $rows; + } + return null; +} + + +function buildTableForm($rows, $mod='Accounts'){ + if(!ACLController::checkAccess('Accounts', 'edit', true)){ + return ''; + } + global $action; + if(!empty($mod)){ + global $current_language; + $mod_strings = return_module_language($current_language, $mod); + }else global $mod_strings; + global $app_strings; + $cols = sizeof($rows[0]) * 2 + 1; + if ($action != 'ShowDuplicates') + { + $form = "
    "; + $form .= '
    '.$mod_strings['MSG_DUPLICATE']. '
    '; + unset($_POST['selectedAccount']); + } + else + { + $form = '
    '.$mod_strings['MSG_SHOW_DUPLICATES']. '
    '; + } + + $form .= ""; + if ($action != 'ShowDuplicates') + { + $form .= ""; + } + require_once('include/formbase.php'); + + if(isset($_POST['return_action']) && $_POST['return_action'] == 'SubPanelViewer') { + $_POST['return_action'] = 'DetailView'; + } + + if(isset($_POST['return_action']) && $_POST['return_action'] == 'DetailView' && empty($_REQUEST['return_id'])) { + unset($_POST['return_action']); + } + + $form .= getPostToForm(); + if(isset($rows[0])){ + foreach ($rows[0] as $key=>$value){ + if($key != 'id'){ + + $form .= ""; + }} + + $form .= ""; + } + + $rowColor = 'oddListRowS1'; + foreach($rows as $row){ + + $form .= ""; + if ($action != 'ShowDuplicates') + { + $form .= "\n"; + } + foreach ($row as $key=>$value){ + if($key != 'id'){ + if(isset($_POST['popup']) && $_POST['popup']==true){ + $form .= "\n"; + } + else + $form .= "\n"; + + }} + + if($rowColor == 'evenListRowS1'){ + $rowColor = 'oddListRowS1'; + }else{ + $rowColor = 'evenListRowS1'; + } + $form .= ""; + } + $form .= "
    "; + // handle buttons + if ($action == 'ShowDuplicates') { + $return_action = 'ListView'; // cn: bug 6658 - hardcoded return action break popup -> create -> duplicate -> cancel + $return_action = (isset($_REQUEST['return_action']) && !empty($_REQUEST['return_action'])) ? $_REQUEST['return_action'] : $return_action; + $form .= "\n"; + + if (!empty($_REQUEST['return_module']) && !empty($_REQUEST['return_action']) && !empty($_REQUEST['return_id'])) + $form .= ""; + else if (!empty($_POST['return_module']) && !empty($_POST['return_action'])) + $form .= ""; + else + $form .= ""; + } else { + $form .= "\n"; + } + $form .= "
     ". $mod_strings[$mod_strings['db_'.$key]]. "
    [${app_strings['LBL_SELECT_BUTTON_LABEL']}]  $value$value
    "; + + // handle buttons + if ($action == 'ShowDuplicates') { + $return_action = 'ListView'; // cn: bug 6658 - hardcoded return action break popup -> create -> duplicate -> cancel + $return_action = (isset($_REQUEST['return_action']) && !empty($_REQUEST['return_action'])) ? $_REQUEST['return_action'] : $return_action; + $form .= "\n"; + + if (!empty($_REQUEST['return_module']) && !empty($_REQUEST['return_action']) && !empty($_REQUEST['return_id'])) + $form .= ""; + else if (!empty($_POST['return_module']) && !empty($_POST['return_action'])) + $form .= ""; + else + $form .= ""; + } else { + $form .= "\n"; + } + $form .= "
    "; + return $form; + + + +} + +function getForm($prefix, $mod='', $form=''){ + if(!ACLController::checkAccess('Accounts', 'edit', true)){ + return ''; + } +if(!empty($mod)){ + global $current_language; + $mod_strings = return_module_language($current_language, $mod); +}else global $mod_strings; +global $app_strings; +$lbl_save_button_title = $app_strings['LBL_SAVE_BUTTON_TITLE']; +$lbl_save_button_key = $app_strings['LBL_SAVE_BUTTON_KEY']; +$lbl_save_button_label = $app_strings['LBL_SAVE_BUTTON_LABEL']; + + +$the_form = get_left_form_header($mod_strings['LBL_NEW_FORM_TITLE']); +$the_form .= << + + +EOQ; +$the_form .= $this->getFormBody($prefix, $mod, $prefix."AccountSave"); +$the_form .= <<

    + + +EOQ; +$the_form .= get_left_form_footer(); +$the_form .= get_validate_record_js(); + +return $the_form; +} + + +function getFormBody($prefix,$mod='', $formname=''){ + if(!ACLController::checkAccess('Accounts', 'edit', true)){ + return ''; + } +global $mod_strings; +$temp_strings = $mod_strings; +if(!empty($mod)){ + global $current_language; + $mod_strings = return_module_language($current_language, $mod); +} + global $app_strings; +global $current_user; + +$lbl_required_symbol = $app_strings['LBL_REQUIRED_SYMBOL']; +$lbl_account_name = $mod_strings['LBL_ACCOUNT_NAME']; +$lbl_phone = $mod_strings['LBL_PHONE']; +$lbl_website = $mod_strings['LBL_WEBSITE']; +$lbl_save_button_title = $app_strings['LBL_SAVE_BUTTON_TITLE']; +$lbl_save_button_key = $app_strings['LBL_SAVE_BUTTON_KEY']; +$lbl_save_button_label = $app_strings['LBL_SAVE_BUTTON_LABEL']; +$user_id = $current_user->id; + + $form = << + + + + +EOQ; + $form .= "$lbl_account_name $lbl_required_symbol

    "; + $form .= "$lbl_phone

    "; + $form .= "$lbl_website

    "; +$form .='

    '; + + + +$javascript = new javascript(); +$javascript->setFormName($formname); +$javascript->setSugarBean(new Account()); +$javascript->addRequiredFields($prefix); +$form .=$javascript->getScript(); +$mod_strings = $temp_strings; +return $form; +} + + + +function getWideFormBody($prefix, $mod='',$formname='', $contact=''){ + if(!ACLController::checkAccess('Accounts', 'edit', true)){ + return ''; + } + + if(empty($contact)){ + $contact = new Contact(); + } +global $mod_strings; +$temp_strings = $mod_strings; +if(!empty($mod)){ + global $current_language; + $mod_strings = return_module_language($current_language, $mod); +} +global $app_strings; +global $current_user; +$account = new Account(); + +$lbl_required_symbol = $app_strings['LBL_REQUIRED_SYMBOL']; +$lbl_account_name = $mod_strings['LBL_ACCOUNT_NAME']; +$lbl_phone = $mod_strings['LBL_PHONE']; +$lbl_website = $mod_strings['LBL_WEBSITE']; +if (isset($contact->assigned_user_id)) { + $user_id=$contact->assigned_user_id; +} else { + $user_id = $current_user->id; +} + + //Retrieve Email address and set email1, email2 + $sugarEmailAddress = new SugarEmailAddress(); + $sugarEmailAddress->handleLegacyRetrieve($contact); + if(!isset($contact->email1)){ + $contact->email1 = ''; + } + if(!isset($contact->email2)){ + $contact->email2 = ''; + } + if(!isset($contact->email_opt_out)){ + $contact->email_opt_out = ''; + } + $form=""; + $default_desc=""; + if (!empty($contact->description)) { + $default_desc=$contact->description; + } + $form .= << + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +EOQ; + //carry forward custom lead fields common to accounts during Lead Conversion + $tempAccount = new Account(); + if (method_exists($contact, 'convertCustomFieldsForm')) $contact->convertCustomFieldsForm($form, $tempAccount, $prefix); + unset($tempAccount); +$form .= << +EOQ; + + +$javascript = new javascript(); +$javascript->setFormName($formname); +$javascript->setSugarBean(new Account()); +$javascript->addRequiredFields($prefix); +$form .=$javascript->getScript(); +$mod_strings = $temp_strings; + return $form; +} + + +function handleSave($prefix,$redirect=true, $useRequired=false){ + + + require_once('include/formbase.php'); + + $focus = new Account(); + + if($useRequired && !checkRequired($prefix, array_keys($focus->required_fields))){ + return null; + } + $focus = populateFromPost($prefix, $focus); + + if (isset($GLOBALS['check_notify'])) { + $check_notify = $GLOBALS['check_notify']; + } + else { + $check_notify = FALSE; + } + + if (empty($_POST['record']) && empty($_POST['dup_checked'])) { + $duplicateAccounts = $this->checkForDuplicates($prefix); + if(isset($duplicateAccounts)){ + $location='module=Accounts&action=ShowDuplicates'; + $get = ''; + + // Bug 25311 - Add special handling for when the form specifies many-to-many relationships + if(isset($_POST['relate_to']) && !empty($_POST['relate_to'])) { + $get .= '&Accountsrelate_to='.$_POST['relate_to']; + } + if(isset($_POST['relate_id']) && !empty($_POST['relate_id'])) { + $get .= '&Accountsrelate_id='.$_POST['relate_id']; + } + + //add all of the post fields to redirect get string + foreach ($focus->column_fields as $field) + { + if (!empty($focus->$field) && !is_object($focus->$field)) + { + $get .= "&Accounts$field=".urlencode($focus->$field); + } + } + + foreach ($focus->additional_column_fields as $field) + { + if (!empty($focus->$field)) + { + $get .= "&Accounts$field=".urlencode($focus->$field); + } + } + + + if($focus->hasCustomFields()) { + foreach($focus->field_defs as $name=>$field) { + if (!empty($field['source']) && $field['source'] == 'custom_fields') + { + $get .= "&Accounts$name=".urlencode($focus->$name); + } + } + } + + + + $emailAddress = new SugarEmailAddress(); + $get .= $emailAddress->getFormBaseURL($focus); + + + + //create list of suspected duplicate account id's in redirect get string + $i=0; + foreach ($duplicateAccounts as $account) + { + $get .= "&duplicate[$i]=".$account['id']; + $i++; + } + + //add return_module, return_action, and return_id to redirect get string + $get .= '&return_module='; + if(!empty($_POST['return_module'])) $get .= $_POST['return_module']; + else $get .= 'Accounts'; + $get .= '&return_action='; + if(!empty($_POST['return_action'])) $get .= $_POST['return_action']; + //else $get .= 'DetailView'; + if(!empty($_POST['return_id'])) $get .= '&return_id='.$_POST['return_id']; + if(!empty($_POST['popup'])) $get .= '&popup='.$_POST['popup']; + if(!empty($_POST['create'])) $get .= '&create='.$_POST['create']; + + //now redirect the post to modules/Accounts/ShowDuplicates.php + if (!empty($_POST['is_ajax_call']) && $_POST['is_ajax_call'] == '1') + { + ob_clean(); + $json = getJSONobj(); + $_SESSION['SHOW_DUPLICATES'] = $get; + echo $json->encode(array('status' => 'dupe', 'get' => $location)); + } else { + if(!empty($_POST['to_pdf'])) $location .= '&to_pdf='.$_POST['to_pdf']; + $_SESSION['SHOW_DUPLICATES'] = $get; + header("Location: index.php?$location"); + } + return null; + } + } + if(!$focus->ACLAccess('Save')){ + ACLController::displayNoAccess(true); + sugar_cleanup(true); + } + + $focus->save($check_notify); + $return_id = $focus->id; + + $GLOBALS['log']->debug("Saved record with id of ".$return_id); + + + if (!empty($_POST['is_ajax_call']) && $_POST['is_ajax_call'] == '1') { + $json = getJSONobj(); + echo $json->encode(array('status' => 'success', + 'get' => '')); + $trackerManager = TrackerManager::getInstance(); + $timeStamp = TimeDate::getInstance()->nowDb(); + if($monitor = $trackerManager->getMonitor('tracker')){ + $monitor->setValue('action', 'detailview'); + $monitor->setValue('user_id', $GLOBALS['current_user']->id); + $monitor->setValue('module_name', 'Accounts'); + $monitor->setValue('date_modified', $timeStamp); + $monitor->setValue('visible', 1); + + if (!empty($this->bean->id)) { + $monitor->setValue('item_id', $return_id); + $monitor->setValue('item_summary', $focus->get_summary_text()); + } + $trackerManager->saveMonitor($monitor, true, true); + } + return null; + } + + if(isset($_POST['popup']) && $_POST['popup'] == 'true') { + $get = '&module='; + if(!empty($_POST['return_module'])) $get .= $_POST['return_module']; + else $get .= 'Accounts'; + $get .= '&action='; + if(!empty($_POST['return_action'])) $get .= $_POST['return_action']; + else $get .= 'Popup'; + if(!empty($_POST['return_id'])) $get .= '&return_id='.$_POST['return_id']; + if(!empty($_POST['popup'])) $get .= '&popup='.$_POST['popup']; + if(!empty($_POST['create'])) $get .= '&create='.$_POST['create']; + if(!empty($_POST['to_pdf'])) $get .= '&to_pdf='.$_POST['to_pdf']; + $get .= '&name=' . $focus->name; + $get .= '&query=true'; + header("Location: index.php?$get"); + return; + } + if($redirect){ + handleRedirect($return_id,'Accounts'); + }else{ + return $focus; + } +} + + +} +?> diff --git a/modules/Accounts/AccountsQuickCreate.php b/modules/Accounts/AccountsQuickCreate.php new file mode 100644 index 00000000..6868e9f7 --- /dev/null +++ b/modules/Accounts/AccountsQuickCreate.php @@ -0,0 +1,70 @@ +viaAJAX) { // override for ajax call + $this->ss->assign('saveOnclick', "onclick='if(check_form(\"accountsQuickCreate\")) return SUGAR.subpanelUtils.inlineSave(this.form.id, \"accounts\"); else return false;'"); + $this->ss->assign('cancelOnclick', "onclick='return SUGAR.subpanelUtils.cancelCreate(\"subpanel_accounts\")';"); + } + + $this->ss->assign('viaAJAX', $this->viaAJAX); + + $this->javascript = new javascript(); + $this->javascript->setFormName('accountsQuickCreate'); + + $focus = new Account(); + $this->javascript->setSugarBean($focus); + $this->javascript->addAllFields(''); + + $this->ss->assign('additionalScripts', $this->javascript->getScript(false)); + } +} +?> \ No newline at end of file diff --git a/modules/Accounts/Dashlets/MyAccountsDashlet/MyAccountsDashlet.data.php b/modules/Accounts/Dashlets/MyAccountsDashlet/MyAccountsDashlet.data.php new file mode 100644 index 00000000..21b48a87 --- /dev/null +++ b/modules/Accounts/Dashlets/MyAccountsDashlet/MyAccountsDashlet.data.php @@ -0,0 +1,99 @@ + array('default' => ''), + 'account_type' => array('default' => ''), + 'industry' => array('default' => ''), + 'billing_address_country' => array('default'=>''), + 'assigned_user_id' => array('type' => 'assigned_user_name', + 'default' => $current_user->name, + 'label' => 'LBL_ASSIGNED_TO')); +$dashletData['MyAccountsDashlet']['columns'] = array('name' => array('width' => '40', + 'label' => 'LBL_LIST_ACCOUNT_NAME', + 'link' => true, + 'default' => true), + 'website' => array('width' => '8', + 'label' => 'LBL_WEBSITE', + 'default' => true), + 'phone_office' => array('width' => '15', + 'label' => 'LBL_LIST_PHONE', + 'default' => true), + 'phone_fax' => array('width' => '8', + 'label' => 'LBL_PHONE_FAX'), + 'phone_alternate' => array('width' => '8', + 'label' => 'LBL_OTHER_PHONE'), + 'billing_address_city' => array('width' => '8', + 'label' => 'LBL_BILLING_ADDRESS_CITY'), + 'billing_address_street' => array('width' => '8', + 'label' => 'LBL_BILLING_ADDRESS_STREET'), + 'billing_address_state' => array('width' => '8', + 'label' => 'LBL_BILLING_ADDRESS_STATE'), + 'billing_address_postalcode' => array('width' => '8', + 'label' => 'LBL_BILLING_ADDRESS_POSTALCODE'), + 'billing_address_country' => array('width' => '8', + 'label' => 'LBL_BILLING_ADDRESS_COUNTRY', + 'default' => true), + 'shipping_address_city' => array('width' => '8', + 'label' => 'LBL_SHIPPING_ADDRESS_CITY'), + 'shipping_address_street' => array('width' => '8', + 'label' => 'LBL_SHIPPING_ADDRESS_STREET'), + 'shipping_address_state' => array('width' => '8', + 'label' => 'LBL_SHIPPING_ADDRESS_STATE'), + 'shipping_address_postalcode' => array('width' => '8', + 'label' => 'LBL_SHIPPING_ADDRESS_POSTALCODE'), + 'shipping_address_country' => array('width' => '8', + 'label' => 'LBL_SHIPPING_ADDRESS_COUNTRY'), + 'email1' => array('width' => '8', + 'label' => 'LBL_EMAIL_ADDRESS_PRIMARY'), + 'parent_name' => array('width' => '15', + 'label' => 'LBL_MEMBER_OF', + 'sortable' => false), + 'date_entered' => array('width' => '15', + 'label' => 'LBL_DATE_ENTERED'), + 'date_modified' => array('width' => '15', + 'label' => 'LBL_DATE_MODIFIED'), + 'created_by' => array('width' => '8', + 'label' => 'LBL_CREATED'), + 'assigned_user_name' => array('width' => '8', + 'label' => 'LBL_LIST_ASSIGNED_USER'), + ); +?> diff --git a/modules/Accounts/Dashlets/MyAccountsDashlet/MyAccountsDashlet.meta.php b/modules/Accounts/Dashlets/MyAccountsDashlet/MyAccountsDashlet.meta.php new file mode 100644 index 00000000..6bd7f2bb --- /dev/null +++ b/modules/Accounts/Dashlets/MyAccountsDashlet/MyAccountsDashlet.meta.php @@ -0,0 +1,47 @@ + 'Accounts', + 'title' => translate('LBL_HOMEPAGE_TITLE', 'Accounts'), + 'description' => 'A customizable view into Accounts', + 'category' => 'Module Views'); +?> diff --git a/modules/Accounts/Dashlets/MyAccountsDashlet/MyAccountsDashlet.php b/modules/Accounts/Dashlets/MyAccountsDashlet/MyAccountsDashlet.php new file mode 100644 index 00000000..408b7519 --- /dev/null +++ b/modules/Accounts/Dashlets/MyAccountsDashlet/MyAccountsDashlet.php @@ -0,0 +1,85 @@ +title = translate('LBL_HOMEPAGE_TITLE', 'Accounts'); + + $this->searchFields = $dashletData['MyAccountsDashlet']['searchFields']; + $this->columns = $dashletData['MyAccountsDashlet']['columns']; + + $this->seedBean = new Account(); + } + + /** + * Overrides the generic process to include custom logic for email addresses, + * since they are no longer stored in a list view friendly manner. + * (A record may have an undetermined number of email addresses). + * + * @param array $lvsParams + */ + + function process($lvsParams = array()) { + if (isset($this->displayColumns) && array_search('email1', $this->displayColumns) !== false) { + $lvsParams['custom_select'] = ', email_address as email1'; + $lvsParams['custom_from'] = ' LEFT JOIN email_addr_bean_rel eabr ON eabr.deleted = 0 AND bean_module = \'Accounts\'' + . ' AND eabr.bean_id = accounts.id AND primary_address = 1' + . ' LEFT JOIN email_addresses ea ON ea.deleted = 0 AND ea.id = eabr.email_address_id'; + } + + if (isset($this->displayColumns) && array_search('parent_name', $this->displayColumns) !== false) { + $lvsParams['custom_select'] = empty($lvsParams['custom_select']) ? ', a1.name as parent_name ' : $lvsParams['custom_select'] . ', a1.name as parent_name '; + $lvsParams['custom_from'] = empty($lvsParams['custom_from']) ? ' LEFT JOIN accounts a1 on a1.id = accounts.parent_id' : $lvsParams['custom_from'] . ' LEFT JOIN accounts a1 on a1.id = accounts.parent_id'; + } + + parent::process($lvsParams); + } +} + +?> diff --git a/modules/Accounts/Menu.php b/modules/Accounts/Menu.php new file mode 100644 index 00000000..7d4b89b5 --- /dev/null +++ b/modules/Accounts/Menu.php @@ -0,0 +1,53 @@ + \ No newline at end of file diff --git a/modules/Accounts/Popup_picker.html b/modules/Accounts/Popup_picker.html new file mode 100644 index 00000000..1b5aebc8 --- /dev/null +++ b/modules/Accounts/Popup_picker.html @@ -0,0 +1,140 @@ + + + + + + + + +
    $lbl_account_name $lbl_required_symbol{$mod_strings['LBL_DESCRIPTION']}
    $lbl_phone
    $lbl_website
    + + + +
    + +
    + + + +

    +

    + +

    + + + + +{PAGINATION} + + + + + + + + + + + + + + + + +{PAGINATION} +
    {CHECKALL}{MOD.LBL_LIST_ACCOUNT_NAME}{arrow_start}{name_arrow}{arrow_end}{MOD.LBL_LIST_CITY}{arrow_start}{BILLING_ADDRESS_CITY_arrow}{arrow_end}{MOD.LBL_PHONE_OFFICE}{arrow_start}{PHONE_OFFICE_arrow}{arrow_end}
    {PREROW}<{TAG_TYPE} href="#" onclick="send_back('Accounts','{ACCOUNT.ID}');" >{ACCOUNT.NAME}{ACCOUNT.CITY}{ACCOUNT.PHONE_OFFICE}
    +{ASSOCIATED_JAVASCRIPT_DATA} + \ No newline at end of file diff --git a/modules/Accounts/Save.php b/modules/Accounts/Save.php new file mode 100644 index 00000000..e31abfa7 --- /dev/null +++ b/modules/Accounts/Save.php @@ -0,0 +1,51 @@ +handleSave($prefix, true, false); + +?> \ No newline at end of file diff --git a/modules/Accounts/ShowDuplicates.html b/modules/Accounts/ShowDuplicates.html new file mode 100644 index 00000000..a62ead2b --- /dev/null +++ b/modules/Accounts/ShowDuplicates.html @@ -0,0 +1,73 @@ + + + +{ERROR} + + +
    + + + + + + +{INPUT_FIELDS} +

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

    {FORMHEADER}

    +
    + {FORMBODY}{FORMFOOTER}{POSTFORM} +
    +
    +

    + + \ No newline at end of file diff --git a/modules/Accounts/ShowDuplicates.php b/modules/Accounts/ShowDuplicates.php new file mode 100644 index 00000000..8ebee6b1 --- /dev/null +++ b/modules/Accounts/ShowDuplicates.php @@ -0,0 +1,159 @@ +debug('ShowDuplicates.php: _POST = '.print_r($_SESSION['SHOW_DUPLICATES'],true)); +parse_str($_SESSION['SHOW_DUPLICATES'],$_POST); +unset($_SESSION['SHOW_DUPLICATES']); +//$GLOBALS['log']->debug('ShowDuplicates.php: _POST = '.print_r($_POST,true)); + +global $app_strings; +global $app_list_strings; + +$error_msg = ''; + +global $current_language; +$mod_strings = return_module_language($current_language, 'Accounts'); +echo getClassicModuleTitle($mod_strings['LBL_MODULE_NAME'], array($mod_strings['LBL_MODULE_NAME'],$mod_strings['LBL_SAVE_ACCOUNT']), true); +$xtpl=new XTemplate ('modules/Accounts/ShowDuplicates.html'); +$xtpl->assign("MOD", $mod_strings); +$xtpl->assign("APP", $app_strings); +$xtpl->assign("PRINT_URL", "index.php?".$GLOBALS['request_string']); +$xtpl->assign("MODULE", $_REQUEST['module']); +if ($error_msg != '') +{ + $xtpl->assign("ERROR", $error_msg); + $xtpl->parse("main.error"); +} + +if((isset($_REQUEST['popup']) && $_REQUEST['popup'] == 'true') ||(isset($_POST['popup']) && $_POST['popup']==true)) insert_popup_header($theme); + + +$account = new Account(); +require_once('modules/Accounts/AccountFormBase.php'); +$accountForm = new AccountFormBase(); +$GLOBALS['check_notify'] = FALSE; + +$query = 'select id, name, website, billing_address_city from accounts where deleted=0 '; +$duplicates = $_POST['duplicate']; +$count = count($duplicates); +if ($count > 0) +{ + $query .= "and ("; + $first = true; + foreach ($duplicates as $duplicate_id) + { + if (!$first) $query .= ' OR '; + $first = false; + $query .= "id='$duplicate_id' "; + } + $query .= ')'; +} + +$duplicateAccounts = array(); + +$db = DBManagerFactory::getInstance(); +$result = $db->query($query); +$i=-1; +while(($row=$db->fetchByAssoc($result)) != null) { + $i++; + $duplicateAccounts[$i] = $row; +} + +$xtpl->assign('FORMBODY', $accountForm->buildTableForm($duplicateAccounts, 'Accounts')); + +$input = ''; +foreach ($account->column_fields as $field) +{ + if (!empty($_POST['Accounts'.$field])) { + $value = urldecode($_POST['Accounts'.$field]); + $input .= "\n"; + } +} +foreach ($account->additional_column_fields as $field) +{ + if (!empty($_POST['Accounts'.$field])) { + $value = urldecode($_POST['Accounts'.$field]); + $input .= "\n"; + } +} + +// Bug 25311 - Add special handling for when the form specifies many-to-many relationships +if(!empty($_POST['Contactsrelate_to'])) { + $input .= "\n"; +} +if(!empty($_POST['Contactsrelate_id'])) { + $input .= "\n"; +} + + +$emailAddress = new SugarEmailAddress(); +$input .= $emailAddress->getEmailAddressWidgetDuplicatesView($account); + +$get = ''; +if(!empty($_POST['return_module'])) $xtpl->assign('RETURN_MODULE', $_POST['return_module']); +else $get .= "Accounts"; +$get .= "&return_action="; +if(!empty($_POST['return_action'])) $xtpl->assign('RETURN_ACTION', $_POST['return_action']); +else $get .= "DetailView"; +if(!empty($_POST['return_id'])) $xtpl->assign('RETURN_ID', $_POST['return_id']); + +if(!empty($_POST['popup'])) + $input .= ''; +else + $input .= ''; + +if(!empty($_POST['to_pdf'])) + $input .= ''; +else + $input .= ''; + +if(!empty($_POST['create'])) + $input .= ''; +else + $input .= ''; + +$xtpl->assign('INPUT_FIELDS',$input); +$xtpl->parse('main'); +$xtpl->out('main'); + + +?> diff --git a/modules/Accounts/field_arrays.php b/modules/Accounts/field_arrays.php new file mode 100644 index 00000000..be5a68d8 --- /dev/null +++ b/modules/Accounts/field_arrays.php @@ -0,0 +1,94 @@ + Array( + "annual_revenue" + ,"billing_address_street" + ,"billing_address_city" + ,"billing_address_state" + ,"billing_address_postalcode" + ,"billing_address_country" + ,"date_entered" + ,"date_modified" + ,"modified_user_id" + ,"assigned_user_id" + ,"description" + ,"email1" + ,"email2" + ,"employees" + ,"id" + ,"industry" + ,"name" + ,"ownership" + ,"parent_id" + ,"phone_alternate" + ,"phone_fax" + ,"phone_office" + ,"rating" + ,"shipping_address_street" + ,"shipping_address_city" + ,"shipping_address_state" + ,"shipping_address_postalcode" + ,"shipping_address_country" + ,"sic_code" + ,"ticker_symbol" + ,"account_type" + ,"website" + , "created_by" + ), + 'list_fields' => Array('id', 'name', 'website', 'phone_office', 'assigned_user_name', 'assigned_user_id' + , 'billing_address_street' + , 'billing_address_city' + , 'billing_address_state' + , 'billing_address_postalcode' + , 'billing_address_country' + , 'shipping_address_street' + , 'shipping_address_city' + , 'shipping_address_state' + , 'shipping_address_postalcode' + , 'shipping_address_country' + ), + 'required_fields' => array("name"=>1), +); +?> \ No newline at end of file diff --git a/modules/Accounts/language/en_us.lang.php b/modules/Accounts/language/en_us.lang.php new file mode 100644 index 00000000..12443ab7 --- /dev/null +++ b/modules/Accounts/language/en_us.lang.php @@ -0,0 +1,183 @@ + 'LBL_LIST_ACCOUNT_NAME', + 'db_website' => 'LBL_LIST_WEBSITE', + 'db_billing_address_city' => 'LBL_LIST_CITY', + // END DON'T CONVERT + 'LBL_DOCUMENTS_SUBPANEL_TITLE' => 'Documents', + // Dashlet Categories + 'LBL_CHARTS' => 'Charts', + 'LBL_DEFAULT' => 'Views', + 'LBL_MISC' => 'Misc', + 'LBL_UTILS' => 'Utils', + // END Dashlet Categories + + 'ACCOUNT_REMOVE_PROJECT_CONFIRM' => 'Are you sure you want to remove this account from the project?', + 'ERR_DELETE_RECORD' => 'You must specify a record number in order to delete the account.', + 'LBL_ACCOUNT_INFORMATION' => 'Account Overview', + 'LBL_ACCOUNT_NAME' => 'Account Name:', + 'LBL_ACCOUNT' => 'Account:', + 'LBL_ACTIVITIES_SUBPANEL_TITLE'=>'Activities', + 'LBL_ADDRESS_INFORMATION' => 'Address Information', + 'LBL_ANNUAL_REVENUE' => 'Annual Revenue:', + 'LBL_ANY_ADDRESS' => 'Any Address:', + 'LBL_ANY_EMAIL' => 'Any Email:', + 'LBL_ANY_PHONE' => 'Any Phone:', + 'LBL_ASSIGNED_TO_NAME' => 'Assigned to:', + 'LBL_ASSIGNED_TO_ID' => 'Assigned User:', + 'LBL_BILLING_ADDRESS_CITY' => 'Billing City:', + 'LBL_BILLING_ADDRESS_COUNTRY' => 'Billing Country:', + 'LBL_BILLING_ADDRESS_POSTALCODE' => 'Billing Postal Code:', + 'LBL_BILLING_ADDRESS_STATE' => 'Billing State:', + 'LBL_BILLING_ADDRESS_STREET_2' =>'Billing Street 2', + 'LBL_BILLING_ADDRESS_STREET_3' =>'Billing Street 3', + 'LBL_BILLING_ADDRESS_STREET_4' =>'Billing Street 4', + 'LBL_BILLING_ADDRESS_STREET' => 'Billing Street:', + 'LBL_BILLING_ADDRESS' => 'Billing Address:', + 'LBL_BUG_FORM_TITLE' => 'Accounts', + 'LBL_BUGS_SUBPANEL_TITLE' => 'Bugs', + 'LBL_CALLS_SUBPANEL_TITLE' => 'Calls', + 'LBL_CAMPAIGN_ID' => 'Campaign ID', + 'LBL_CASES_SUBPANEL_TITLE' => 'Cases', + 'LBL_CITY' => 'City:', + 'LBL_CONTACTS_SUBPANEL_TITLE' => 'Contacts', + 'LBL_COUNTRY' => 'Country:', + 'LBL_DATE_ENTERED' => 'Date Created:', + 'LBL_DATE_MODIFIED' => 'Date Modified:', + 'LBL_MODIFIED_ID'=>'Modified By Id', + 'LBL_DEFAULT_SUBPANEL_TITLE' => 'Accounts', + 'LBL_DESCRIPTION_INFORMATION' => 'Description Information', + 'LBL_DESCRIPTION' => 'Description:', + 'LBL_DUPLICATE' => 'Possible Duplicate Account', + 'LBL_EMAIL' => 'Email Address:', + 'LBL_EMAIL_OPT_OUT' => 'Email Opt Out:', + //'LBL_EMAIL_ADDRESSES' => 'Email Addresses', + 'LBL_EMPLOYEES' => 'Employees:', + 'LBL_FAX' => 'Fax:', + 'LBL_HISTORY_SUBPANEL_TITLE'=>'History', + 'LBL_HOMEPAGE_TITLE' => 'My Accounts', + 'LBL_INDUSTRY' => 'Industry:', + 'LBL_INVALID_EMAIL'=>'Invalid Email:', + 'LBL_INVITEE' => 'Contacts', + 'LBL_LEADS_SUBPANEL_TITLE' => 'Leads', + 'LBL_LIST_ACCOUNT_NAME' => 'Account Name', + 'LBL_LIST_CITY' => 'City', + 'LBL_LIST_CONTACT_NAME' => 'Contact Name', + 'LBL_LIST_EMAIL_ADDRESS' => 'Email Address', + 'LBL_LIST_FORM_TITLE' => 'Account List', + 'LBL_LIST_PHONE' => 'Phone', + 'LBL_LIST_STATE' => 'State', + 'LBL_LIST_WEBSITE' => 'Website', + 'LBL_MEETINGS_SUBPANEL_TITLE' => 'Meetings', + 'LBL_MEMBER_OF' => 'Member of:', + 'LBL_MEMBER_ORG_FORM_TITLE' => 'Member Organizations', + 'LBL_MEMBER_ORG_SUBPANEL_TITLE'=>'Member Organizations', + 'LBL_MODULE_NAME' => 'Accounts', + 'LBL_MODULE_TITLE' => 'Accounts: Home', + 'LBL_MODULE_ID'=> 'Accounts', + 'LBL_NAME'=>'Name:', + 'LBL_NEW_FORM_TITLE' => 'New Account', + 'LBL_OPPORTUNITIES_SUBPANEL_TITLE' => 'Opportunities', + 'LBL_OTHER_EMAIL_ADDRESS' => 'Other Email:', + 'LBL_OTHER_PHONE' => 'Other Phone:', + 'LBL_OWNERSHIP' => 'Ownership:', + 'LBL_PARENT_ACCOUNT_ID' => 'Parent Account ID', + 'LBL_PHONE_ALT' => 'Alternate Phone:', + 'LBL_PHONE_FAX' => 'Phone Fax:', + 'LBL_PHONE_OFFICE' => 'Office Phone:', + 'LBL_PHONE' => 'Phone:', + 'LBL_POSTAL_CODE' => 'Postal Code:', + 'LBL_PRODUCTS_TITLE'=>'Products', + 'LBL_PROJECTS_SUBPANEL_TITLE' => 'Projects', + 'LBL_PUSH_BILLING' => 'Push Billing', + 'LBL_PUSH_CONTACTS_BUTTON_LABEL' => 'Copy to Contacts', + 'LBL_PUSH_CONTACTS_BUTTON_TITLE' => 'Copy...', + 'LBL_PUSH_SHIPPING' => 'Push Shipping', + 'LBL_RATING' => 'Rating:', + 'LBL_SAVE_ACCOUNT' => 'Save Account', + 'LBL_SEARCH_FORM_TITLE' => 'Account Search', + 'LBL_SHIPPING_ADDRESS_CITY' => 'Shipping City:', + 'LBL_SHIPPING_ADDRESS_COUNTRY' => 'Shipping Country:', + 'LBL_SHIPPING_ADDRESS_POSTALCODE' => 'Shipping Postal Code:', + 'LBL_SHIPPING_ADDRESS_STATE' => 'Shipping State:', + 'LBL_SHIPPING_ADDRESS_STREET_2' => 'Shipping Street 2', + 'LBL_SHIPPING_ADDRESS_STREET_3' => 'Shipping Street 3', + 'LBL_SHIPPING_ADDRESS_STREET_4' => 'Shipping Street 4', + 'LBL_SHIPPING_ADDRESS_STREET' => 'Shipping Street:', + 'LBL_SHIPPING_ADDRESS' => 'Shipping Address:', + 'LBL_SIC_CODE' => 'SIC Code:', + 'LBL_STATE' => 'State:', + 'LBL_TASKS_SUBPANEL_TITLE' => 'Tasks', + 'LBL_TEAMS_LINK'=>'Teams', + 'LBL_TICKER_SYMBOL' => 'Ticker Symbol:', + 'LBL_TYPE' => 'Type:', + 'LBL_USERS_ASSIGNED_LINK'=>'Assigned Users', + 'LBL_USERS_CREATED_LINK'=>'Created By Users', + 'LBL_USERS_MODIFIED_LINK'=>'Modified Users', + 'LBL_VIEW_FORM_TITLE' => 'Account View', + 'LBL_WEBSITE' => 'Website:', + 'LBL_CREATED_ID'=>'Created By Id', + 'LBL_CAMPAIGNS' =>'Campaigns', + 'LNK_ACCOUNT_LIST' => 'View Accounts', + 'LNK_NEW_ACCOUNT' => 'Create Account', + 'LNK_IMPORT_ACCOUNTS' => 'Import Accounts', + 'MSG_DUPLICATE' => 'The account record you are about to create might be a duplicate of an account record that already exists. Account records containing similar names are listed below.
    Click Create Account to continue creating this new account, or select an existing account listed below.', + 'MSG_SHOW_DUPLICATES' => 'The account record you are about to create might be a duplicate of an account record that already exists. Account records containing similar names are listed below.
    Click Save to continue creating this new account, or click Cancel to return to the module without creating the account.', + 'NTC_COPY_BILLING_ADDRESS' => 'Copy billing address to shipping address', + 'NTC_COPY_BILLING_ADDRESS2' => 'Copy to shipping', + 'NTC_COPY_SHIPPING_ADDRESS' => 'Copy shipping address to billing address', + 'NTC_COPY_SHIPPING_ADDRESS2' => 'Copy to billing', + 'NTC_DELETE_CONFIRMATION' => 'Are you sure you want to delete this record?', + 'NTC_REMOVE_ACCOUNT_CONFIRMATION' => 'Are you sure you want to remove this record?', + 'NTC_REMOVE_MEMBER_ORG_CONFIRMATION' => 'Are you sure you want to remove this record as a member organization?', + 'LBL_ASSIGNED_USER_NAME' => 'Assigned to:', + 'LBL_PROSPECT_LIST' => 'Prospect List', + 'LBL_ACCOUNTS_SUBPANEL_TITLE'=>'Accounts', + 'LBL_PROJECT_SUBPANEL_TITLE' => 'Projects', +); +?> \ No newline at end of file diff --git a/modules/Accounts/metadata/SearchFields.php b/modules/Accounts/metadata/SearchFields.php new file mode 100644 index 00000000..f8b39143 --- /dev/null +++ b/modules/Accounts/metadata/SearchFields.php @@ -0,0 +1,76 @@ + array( 'query_type'=>'default'), + 'account_type'=> array('query_type'=>'default', 'options' => 'account_type_dom', 'template_var' => 'ACCOUNT_TYPE_OPTIONS'), + 'industry'=> array('query_type'=>'default', 'options' => 'industry_dom', 'template_var' => 'INDUSTRY_OPTIONS'), + 'annual_revenue'=> array('query_type'=>'default'), + 'address_street'=> array('query_type'=>'default','db_field'=>array('billing_address_street','shipping_address_street')), + 'address_city'=> array('query_type'=>'default','db_field'=>array('billing_address_city','shipping_address_city'), 'vname' =>'LBL_CITY'), + 'address_state'=> array('query_type'=>'default','db_field'=>array('billing_address_state','shipping_address_state'), 'vname' =>'LBL_STATE'), + 'address_postalcode'=> array('query_type'=>'default','db_field'=>array('billing_address_postalcode','shipping_address_postalcode'), 'vname' =>'LBL_POSTAL_CODE'), + 'address_country'=> array('query_type'=>'default','db_field'=>array('billing_address_country','shipping_address_country'), 'vname' =>'LBL_COUNTRY'), + 'rating'=> array('query_type'=>'default'), + 'phone'=> array('query_type'=>'default','db_field'=>array('phone_office'),'vname' =>'LBL_ANY_PHONE'), + 'email'=> array( + 'query_type' => 'default', + 'operator' => 'subquery', + 'subquery' => 'SELECT eabr.bean_id FROM email_addr_bean_rel eabr JOIN email_addresses ea ON (ea.id = eabr.email_address_id) WHERE eabr.deleted=0 AND ea.email_address LIKE', + 'db_field' => array( + 'id', + ), + 'vname' =>'LBL_ANY_EMAIL', + ), + 'website'=> array('query_type'=>'default'), + 'ownership'=> array('query_type'=>'default'), + 'employees'=> array('query_type'=>'default'), + 'sic_code'=> array('query_type'=>'default'), + 'ticker_symbol'=> array('query_type'=>'default'), + 'current_user_only'=> array('query_type'=>'default','db_field'=>array('assigned_user_id'),'my_items'=>true, 'vname' => 'LBL_CURRENT_USER_FILTER', 'type' => 'bool'), + 'assigned_user_id'=> array('query_type'=>'default'), + //Range Search Support + 'range_date_entered' => array ('query_type' => 'default', 'enable_range_search' => true, 'is_date_field' => true), + 'start_range_date_entered' => array ('query_type' => 'default', 'enable_range_search' => true, 'is_date_field' => true), + 'end_range_date_entered' => array ('query_type' => 'default', 'enable_range_search' => true, 'is_date_field' => true), + 'range_date_modified' => array ('query_type' => 'default', 'enable_range_search' => true, 'is_date_field' => true), + 'start_range_date_modified' => array ('query_type' => 'default', 'enable_range_search' => true, 'is_date_field' => true), + 'end_range_date_modified' => array ('query_type' => 'default', 'enable_range_search' => true, 'is_date_field' => true), + //Range Search Support + ); +?> diff --git a/modules/Accounts/metadata/acldefs.php b/modules/Accounts/metadata/acldefs.php new file mode 100644 index 00000000..bba88501 --- /dev/null +++ b/modules/Accounts/metadata/acldefs.php @@ -0,0 +1,61 @@ + + array ( + 'by_name' => + array ( + 'btn1' => + array ( + 'display_option' => 'disabled', + 'action_option' => 'list', + 'app_action' => 'EditView', + 'module' => 'Accounts', + ), + ), + ), + 'form_names' => + array ( + 'by_id' => 'by_id', + 'by_name' => 'by_name', + 'DetailView' => 'DetailView', + 'EditView' => 'EditView', + ), +); +?> diff --git a/modules/Accounts/metadata/additionalDetails.php b/modules/Accounts/metadata/additionalDetails.php new file mode 100644 index 00000000..b8bfff72 --- /dev/null +++ b/modules/Accounts/metadata/additionalDetails.php @@ -0,0 +1,84 @@ +' . $mod_strings['LBL_BILLING_ADDRESS'] . '

    '; + if(!empty($fields['BILLING_ADDRESS_STREET'])) $overlib_string .= $fields['BILLING_ADDRESS_STREET'] . '
    '; + if(!empty($fields['BILLING_ADDRESS_STREET_2'])) $overlib_string .= $fields['BILLING_ADDRESS_STREET_2'] . '
    '; + if(!empty($fields['BILLING_ADDRESS_STREET_3'])) $overlib_string .= $fields['BILLING_ADDRESS_STREET_3'] . '
    '; + if(!empty($fields['BILLING_ADDRESS_STREET_4'])) $overlib_string .= $fields['BILLING_ADDRESS_STREET_4'] . '
    '; + if(!empty($fields['BILLING_ADDRESS_CITY'])) $overlib_string .= $fields['BILLING_ADDRESS_CITY'] . ', '; + if(!empty($fields['BILLING_ADDRESS_STATE'])) $overlib_string .= $fields['BILLING_ADDRESS_STATE'] . ' '; + if(!empty($fields['BILLING_ADDRESS_POSTALCODE'])) $overlib_string .= $fields['BILLING_ADDRESS_POSTALCODE'] . ' '; + if(!empty($fields['BILLING_ADDRESS_COUNTRY'])) $overlib_string .= $fields['BILLING_ADDRESS_COUNTRY'] . '
    '; + + if(strlen($overlib_string) > 0 && !(strrpos($overlib_string, '
    ') == strlen($overlib_string) - 4)) + $overlib_string .= '
    '; + + if(!empty($fields['PHONE_FAX'])) $overlib_string .= ''. $mod_strings['LBL_FAX'] . ' ' . $fields['PHONE_FAX'] . '
    '; + if(!empty($fields['PHONE_ALTERNATE'])) $overlib_string .= ''. $mod_strings['LBL_OTHER_PHONE'] . ' ' . $fields['PHONE_ALTERNATE'] . '
    '; + if(!empty($fields['WEBSITE'])) + $overlib_string .= '' . $fields['WEBSITE'] . '
    '; + if(!empty($fields['INDUSTRY'])) $overlib_string .= ''. $mod_strings['LBL_INDUSTRY'] . ' ' . $fields['INDUSTRY'] . '
    '; + if(!empty($fields['DESCRIPTION'])) { + $overlib_string .= ''. $mod_strings['LBL_DESCRIPTION'] . ' ' . substr($fields['DESCRIPTION'], 0, 300); + if(strlen($fields['DESCRIPTION']) > 300) $overlib_string .= '...'; + } + + return array('fieldToAddTo' => 'NAME', + 'string' => $overlib_string, + 'editLink' => "index.php?action=EditView&module=Accounts&return_module=Accounts&record={$fields['ID']}", + 'viewLink' => "index.php?action=DetailView&module=Accounts&return_module=Accounts&record={$fields['ID']}"); +} + + ?> + + \ No newline at end of file diff --git a/modules/Accounts/metadata/detailviewdefs.php b/modules/Accounts/metadata/detailviewdefs.php new file mode 100644 index 00000000..ca0466dd --- /dev/null +++ b/modules/Accounts/metadata/detailviewdefs.php @@ -0,0 +1,219 @@ + array('form' => array('buttons'=>array('EDIT', + 'DUPLICATE', + 'DELETE', + 'FIND_DUPLICATES', +)), + 'maxColumns' => '2', + 'widths' => array( + array('label' => '10', 'field' => '30'), + array('label' => '10', 'field' => '30') + ), + 'includes'=> array( + array('file'=>'modules/Accounts/Account.js'), + ), + ), + 'panels' => + array ( + 'lbl_account_information' => + array ( + array ( + array ( + 'name' => 'name', + 'comment' => 'Name of the Company', + 'label' => 'LBL_NAME', + 'displayParams' => + array ( + 'enableConnectors' => true, + 'module' => 'Accounts', + 'connectors' => + array ( + 0 => 'ext_rest_linkedin', + ), + ), + ), + array ( + 'name' => 'phone_office', + 'comment' => 'The office phone number', + 'label' => 'LBL_PHONE_OFFICE', + ), + ), + + array ( + + array ( + 'name' => 'website', + 'type' => 'link', + 'label' => 'LBL_WEBSITE', + 'displayParams' => + array ( + 'link_target' => '_blank', + ), + ), + array ( + 'name' => 'phone_fax', + 'comment' => 'The fax phone number of this company', + 'label' => 'LBL_FAX', + ), + ), + + array ( + array ( + 'name' => 'billing_address_street', + 'label' => 'LBL_BILLING_ADDRESS', + 'type' => 'address', + 'displayParams' => + array ( + 'key' => 'billing', + ), + ), + + array ( + 'name' => 'shipping_address_street', + 'label' => 'LBL_SHIPPING_ADDRESS', + 'type' => 'address', + 'displayParams' => + array ( + 'key' => 'shipping', + ), + ), + ), + + array ( + array ( + 'name' => 'email1', + 'studio' => 'false', + 'label' => 'LBL_EMAIL', + ), + ), + array ( + array ( + 'name' => 'description', + 'comment' => 'Full text of the note', + 'label' => 'LBL_DESCRIPTION', + ), + ), + ), + 'LBL_PANEL_ADVANCED' => + array ( + + array ( + array ( + 'name' => 'account_type', + 'comment' => 'The Company is of this type', + 'label' => 'LBL_TYPE', + ), + array ( + 'name' => 'industry', + 'comment' => 'The company belongs in this industry', + 'label' => 'LBL_INDUSTRY', + ), + ), + + array ( + array ( + 'name' => 'annual_revenue', + 'comment' => 'Annual revenue for this company', + 'label' => 'LBL_ANNUAL_REVENUE', + ), + array ( + 'name' => 'employees', + 'comment' => 'Number of employees, varchar to accomodate for both number (100) or range (50-100)', + 'label' => 'LBL_EMPLOYEES', + ), + ), + + array ( + array ( + 'name' => 'sic_code', + 'comment' => 'SIC code of the account', + 'label' => 'LBL_SIC_CODE', + ), + array ( + 'name' => 'ticker_symbol', + 'comment' => 'The stock trading (ticker) symbol for the company', + 'label' => 'LBL_TICKER_SYMBOL', + ), + ), + + array ( + array ( + 'name' => 'parent_name', + 'label' => 'LBL_MEMBER_OF', + ), + array ( + 'name' => 'ownership', + 'comment' => '', + 'label' => 'LBL_OWNERSHIP', + ), + ), + + array ( + 'campaign_name', + + array ( + 'name' => 'rating', + 'comment' => 'An arbitrary rating for this company for use in comparisons with others', + 'label' => 'LBL_RATING', + ), + ), + ), + 'LBL_PANEL_ASSIGNMENT' => + array ( + array ( + array ( + 'name' => 'assigned_user_name', + 'label' => 'LBL_ASSIGNED_TO', + ), + array ( + 'name' => 'date_modified', + 'label' => 'LBL_DATE_MODIFIED', + 'customCode' => '{$fields.date_modified.value} {$APP.LBL_BY} {$fields.modified_by_name.value}', + ), + ), + array ( + array ( + 'name' => 'date_entered', + 'customCode' => '{$fields.date_entered.value} {$APP.LBL_BY} {$fields.created_by_name.value}', + ), + ), + ), + ) +); +?> \ No newline at end of file diff --git a/modules/Accounts/metadata/editviewdefs.php b/modules/Accounts/metadata/editviewdefs.php new file mode 100644 index 00000000..68cdd545 --- /dev/null +++ b/modules/Accounts/metadata/editviewdefs.php @@ -0,0 +1,170 @@ + array( + 'form' => array('buttons'=>array('SAVE', 'CANCEL')), + 'maxColumns' => '2', + 'widths' => array( + array('label' => '10', 'field' => '30'), + array('label' => '10', 'field' => '30'), + ), + 'includes'=> array( + array('file'=>'modules/Accounts/Account.js'), + ), + ), + + 'panels' => array( + + 'lbl_account_information' => + array ( + array ( + array ( + 'name' => 'name', + 'label' => 'LBL_NAME', + 'displayParams' => + array ( + 'required' => true, + ), + ), + array ( + 'name' => 'phone_office', + 'label' => 'LBL_PHONE_OFFICE', + ), + ), + + array ( + + array ( + 'name' => 'website', + 'type' => 'link', + 'label' => 'LBL_WEBSITE', + ), + + array ( + 'name' => 'phone_fax', + 'label' => 'LBL_FAX', + ), + ), + + array ( + + array ( + 'name' => 'billing_address_street', + 'hideLabel' => true, + 'type' => 'address', + 'displayParams' => + array ( + 'key' => 'billing', + 'rows' => 2, + 'cols' => 30, + 'maxlength' => 150, + ), + ), + + array ( + 'name' => 'shipping_address_street', + 'hideLabel' => true, + 'type' => 'address', + 'displayParams' => + array ( + 'key' => 'shipping', + 'copy' => 'billing', + 'rows' => 2, + 'cols' => 30, + 'maxlength' => 150, + ), + ), + ), + + array ( + + array ( + 'name' => 'email1', + 'studio' => 'false', + 'label' => 'LBL_EMAIL', + ), + ), + + array ( + + array ( + 'name' => 'description', + 'label' => 'LBL_DESCRIPTION', + ), + ), + ), + 'LBL_PANEL_ADVANCED' => + array ( + + array ( + 'account_type', + 'industry' + ), + + array ( + 'annual_revenue', + 'employees' + ), + + array ( + 'sic_code', + 'ticker_symbol' + ), + + array ( + 'parent_name', + 'ownership' + ), + + array ( + 'campaign_name', + 'rating' + ), + ), + 'LBL_PANEL_ASSIGNMENT' => + array ( + + array ( + array ( + 'name' => 'assigned_user_name', + 'label' => 'LBL_ASSIGNED_TO', + ), + ), + ), + ) +); +?> \ No newline at end of file diff --git a/modules/Accounts/metadata/fieldGroups.php b/modules/Accounts/metadata/fieldGroups.php new file mode 100644 index 00000000..2a9e4983 --- /dev/null +++ b/modules/Accounts/metadata/fieldGroups.php @@ -0,0 +1,38 @@ + \ No newline at end of file diff --git a/modules/Accounts/metadata/listviewdefs.php b/modules/Accounts/metadata/listviewdefs.php new file mode 100644 index 00000000..72520d77 --- /dev/null +++ b/modules/Accounts/metadata/listviewdefs.php @@ -0,0 +1,224 @@ + + array ( + 'width' => '20%', + 'label' => 'LBL_LIST_ACCOUNT_NAME', + 'link' => true, + 'default' => true, + ), + 'BILLING_ADDRESS_CITY' => + array ( + 'width' => '10%', + 'label' => 'LBL_LIST_CITY', + 'default' => true, + ), + 'BILLING_ADDRESS_COUNTRY' => + array ( + 'width' => '10%', + 'label' => 'LBL_BILLING_ADDRESS_COUNTRY', + 'default' => true, + ), + 'PHONE_OFFICE' => + array ( + 'width' => '10%', + 'label' => 'LBL_LIST_PHONE', + 'default' => true, + ), + 'ASSIGNED_USER_NAME' => + array ( + 'width' => '10%', + 'label' => 'LBL_LIST_ASSIGNED_USER', + 'module' => 'Employees', + 'id' => 'ASSIGNED_USER_ID', + 'default' => true, + ), + 'ACCOUNT_TYPE' => + array ( + 'width' => '10%', + 'label' => 'LBL_TYPE', + 'default' => false, + ), + 'INDUSTRY' => + array ( + 'width' => '10%', + 'label' => 'LBL_INDUSTRY', + 'default' => false, + ), + 'ANNUAL_REVENUE' => + array ( + 'width' => '10%', + 'label' => 'LBL_ANNUAL_REVENUE', + 'default' => false, + ), + 'PHONE_FAX' => + array ( + 'width' => '10%', + 'label' => 'LBL_PHONE_FAX', + 'default' => false, + ), + 'BILLING_ADDRESS_STREET' => + array ( + 'width' => '15%', + 'label' => 'LBL_BILLING_ADDRESS_STREET', + 'default' => false, + ), + 'BILLING_ADDRESS_STATE' => + array ( + 'width' => '7%', + 'label' => 'LBL_BILLING_ADDRESS_STATE', + 'default' => false, + ), + 'BILLING_ADDRESS_POSTALCODE' => + array ( + 'width' => '10%', + 'label' => 'LBL_BILLING_ADDRESS_POSTALCODE', + 'default' => false, + ), + 'SHIPPING_ADDRESS_STREET' => + array ( + 'width' => '15%', + 'label' => 'LBL_SHIPPING_ADDRESS_STREET', + 'default' => false, + ), + 'SHIPPING_ADDRESS_CITY' => + array ( + 'width' => '10%', + 'label' => 'LBL_SHIPPING_ADDRESS_CITY', + 'default' => false, + ), + 'SHIPPING_ADDRESS_STATE' => + array ( + 'width' => '7%', + 'label' => 'LBL_SHIPPING_ADDRESS_STATE', + 'default' => false, + ), + 'SHIPPING_ADDRESS_POSTALCODE' => + array ( + 'width' => '10%', + 'label' => 'LBL_SHIPPING_ADDRESS_POSTALCODE', + 'default' => false, + ), + 'SHIPPING_ADDRESS_COUNTRY' => + array ( + 'width' => '10%', + 'label' => 'LBL_SHIPPING_ADDRESS_COUNTRY', + 'default' => false, + ), + 'RATING' => + array ( + 'width' => '10%', + 'label' => 'LBL_RATING', + 'default' => false, + ), + 'PHONE_ALTERNATE' => + array ( + 'width' => '10%', + 'label' => 'LBL_OTHER_PHONE', + 'default' => false, + ), + 'WEBSITE' => + array ( + 'width' => '10%', + 'label' => 'LBL_WEBSITE', + 'default' => false, + ), + 'OWNERSHIP' => + array ( + 'width' => '10%', + 'label' => 'LBL_OWNERSHIP', + 'default' => false, + ), + 'EMPLOYEES' => + array ( + 'width' => '10%', + 'label' => 'LBL_EMPLOYEES', + 'default' => false, + ), + 'SIC_CODE' => + array ( + 'width' => '10%', + 'label' => 'LBL_SIC_CODE', + 'default' => false, + ), + 'TICKER_SYMBOL' => + array ( + 'width' => '10%', + 'label' => 'LBL_TICKER_SYMBOL', + 'default' => false, + ), + 'DATE_MODIFIED' => + array ( + 'width' => '5%', + 'label' => 'LBL_DATE_MODIFIED', + 'default' => false, + ), + 'CREATED_BY_NAME' => + array ( + 'width' => '10%', + 'label' => 'LBL_CREATED', + 'default' => false, + ), + 'MODIFIED_BY_NAME' => + array ( + 'width' => '10%', + 'label' => 'LBL_MODIFIED', + 'default' => false, + ), + 'EMAIL1' => + array( + 'width' => '15%', + 'label' => 'LBL_EMAIL_ADDRESS', + 'sortable' => false, + 'link' => true, + 'customCode' => '{$EMAIL1_LINK}{$EMAIL1}', + 'default' => true + ), + 'DATE_ENTERED' => + array ( + 'width' => '5%', + 'label' => 'LBL_DATE_ENTERED', + 'default' => true, + ), +); +?> \ No newline at end of file diff --git a/modules/Accounts/metadata/metafiles.php b/modules/Accounts/metadata/metafiles.php new file mode 100644 index 00000000..9bc070d3 --- /dev/null +++ b/modules/Accounts/metadata/metafiles.php @@ -0,0 +1,52 @@ + 'modules/Accounts/metadata/detailviewdefs.php', + 'editviewdefs' => 'modules/Accounts/metadata/editviewdefs.php', + 'listviewdefs' => 'modules/Accounts/metadata/listviewdefs.php', + 'searchdefs' => 'modules/Accounts/metadata/searchdefs.php', + 'popupdefs' => 'modules/Accounts/metadata/popupdefs.php', + 'searchfields' => 'modules/Accounts/metadata/SearchFields.php', + + ); +?> diff --git a/modules/Accounts/metadata/popupdefs.php b/modules/Accounts/metadata/popupdefs.php new file mode 100644 index 00000000..bc3d14ee --- /dev/null +++ b/modules/Accounts/metadata/popupdefs.php @@ -0,0 +1,138 @@ + 'Account', + 'varName' => 'ACCOUNT', + 'orderBy' => 'name', + 'whereClauses' => array( + 'name' => 'accounts.name', + 'billing_address_city' => 'accounts.billing_address_city', + 'phone_office' => 'accounts.phone_office' + ), + 'searchInputs' => array('name', 'billing_address_city', 'phone_office'), + 'create' => array( + 'formBase' => 'AccountFormBase.php', + 'formBaseClass' => 'AccountFormBase', + 'getFormBodyParams' => array('','','AccountSave'), + 'createButton' => $mod_strings['LNK_NEW_ACCOUNT'] + ), + 'listviewdefs' => array( + 'NAME' => array( + 'width' => '40', + 'label' => 'LBL_LIST_ACCOUNT_NAME', + 'link' => true, + 'default' => true, + ), + 'BILLING_ADDRESS_STREET' => array( + 'width' => '10', + 'label' => 'LBL_BILLING_ADDRESS_STREET', + 'default' => false, + ), + 'BILLING_ADDRESS_CITY' => array( + 'width' => '10', + 'label' => 'LBL_LIST_CITY', + 'default' => true, + ), + 'BILLING_ADDRESS_STATE' => array( + 'width' => '7', + 'label' => 'LBL_STATE', + 'default' => true, + ), + 'BILLING_ADDRESS_COUNTRY' => array( + 'width' => '10', + 'label' => 'LBL_COUNTRY', + 'default' => true, + ), + 'BILLING_ADDRESS_POSTALCODE' => array( + 'width' => '10', + 'label' => 'LBL_BILLING_ADDRESS_POSTALCODE', + 'default' => false, + ), + 'SHIPPING_ADDRESS_STREET' => array( + 'width' => '10', + 'label' => 'LBL_SHIPPING_ADDRESS_STREET', + 'default' => false, + ), + 'SHIPPING_ADDRESS_CITY' => array( + 'width' => '10', + 'label' => 'LBL_LIST_CITY', + 'default' => false, + ), + 'SHIPPING_ADDRESS_STATE' => array( + 'width' => '7', + 'label' => 'LBL_STATE', + 'default' => false, + ), + 'SHIPPING_ADDRESS_COUNTRY' => array( + 'width' => '10', + 'label' => 'LBL_COUNTRY', + 'default' => false, + ), + 'SHIPPING_ADDRESS_POSTALCODE' => array( + 'width' => '10', + 'label' => 'LBL_SHIPPING_ADDRESS_POSTALCODE', + 'default' => false, + ), + 'ASSIGNED_USER_NAME' => array( + 'width' => '2', + 'label' => 'LBL_LIST_ASSIGNED_USER', + 'default' => true, + ), + 'PHONE_OFFICE' => array( + 'width' => '10', + 'label' => 'LBL_LIST_PHONE', + 'default' => false + ), + ), + 'searchdefs' => array( + 'name', + 'billing_address_city', + 'billing_address_state', + 'billing_address_country', + array( + 'name' => 'assigned_user_id', + 'label'=>'LBL_ASSIGNED_TO', + 'type' => 'enum', + 'function' => array('name' => 'get_user_array', 'params' => array(false)) + ), + ) +); +?> diff --git a/modules/Accounts/metadata/quickcreatedefs.php b/modules/Accounts/metadata/quickcreatedefs.php new file mode 100644 index 00000000..90b0f24e --- /dev/null +++ b/modules/Accounts/metadata/quickcreatedefs.php @@ -0,0 +1,126 @@ + + array ( + 'templateMeta' => + array ( + 'form' => + array ( + 'buttons' => + array ( + 'SAVE', + 'CANCEL', + ), + ), + 'maxColumns' => '2', + 'widths' => + array ( + array ( + 'label' => '10', + 'field' => '30', + ), + array ( + 'label' => '10', + 'field' => '30', + ), + ), + 'includes' => + array ( + array ( + 'file' => 'modules/Accounts/Account.js', + ), + ), + ), + 'panels' => + array ( + 'default' => + array ( + array ( + array ( + 'name' => 'name', + 'displayParams' => + array ( + 'required' => true, + ), + ), + ), + array ( + array ( + 'name' => 'website', + ), + array ( + 'name' => 'phone_office', + ), + ), + array ( + array ( + 'name' => 'email1', + ), + array ( + 'name' => 'phone_fax', + ), + ), + array ( + array ( + 'name' => 'industry', + ), + array ( + 'name' => 'account_type', + ), + ), + array ( + array ( + 'name' => 'assigned_user_name', + ), + ), + ), + ), + ), +); + +?> \ No newline at end of file diff --git a/modules/Accounts/metadata/searchdefs.php b/modules/Accounts/metadata/searchdefs.php new file mode 100644 index 00000000..55c94bde --- /dev/null +++ b/modules/Accounts/metadata/searchdefs.php @@ -0,0 +1,171 @@ + array( + 'maxColumns' => '3', + 'widths' => array('label' => '10', 'field' => '30'), + ), + 'layout' => + array ( + 'basic_search' => + array ( + 'name' => + array ( + 'name' => 'name', + 'default' => true, + 'width' => '10%', + ), + 'current_user_only' => + array ( + 'name' => 'current_user_only', + 'label' => 'LBL_CURRENT_USER_FILTER', + 'type' => 'bool', + 'default' => true, + 'width' => '10%', + ), + + ), + 'advanced_search' => + array ( + 'name' => + array ( + 'name' => 'name', + 'default' => true, + 'width' => '10%', + ), + 'website' => + array ( + 'name' => 'website', + 'default' => true, + 'width' => '10%', + ), + 'phone' => + array ( + 'name' => 'phone', + 'label' => 'LBL_ANY_PHONE', + 'type' => 'name', + 'default' => true, + 'width' => '10%', + ), + 'email' => + array ( + 'name' => 'email', + 'label' => 'LBL_ANY_EMAIL', + 'type' => 'name', + 'default' => true, + 'width' => '10%', + ), + 'address_street' => + array ( + 'name' => 'address_street', + 'label' => 'LBL_ANY_ADDRESS', + 'type' => 'name', + 'default' => true, + 'width' => '10%', + ), + 'address_city' => + array ( + 'name' => 'address_city', + 'label' => 'LBL_CITY', + 'type' => 'name', + 'default' => true, + 'width' => '10%', + ), + 'address_state' => + array ( + 'name' => 'address_state', + 'label' => 'LBL_STATE', + 'type' => 'name', + 'default' => true, + 'width' => '10%', + ), + 'address_postalcode' => + array ( + 'name' => 'address_postalcode', + 'label' => 'LBL_POSTAL_CODE', + 'type' => 'name', + 'default' => true, + 'width' => '10%', + ), + 'billing_address_country' => + array ( + 'name' => 'billing_address_country', + 'label' => 'LBL_COUNTRY', + 'type' => 'name', + 'options' => 'countries_dom', + 'default' => true, + 'width' => '10%', + ), + 'account_type' => + array ( + 'name' => 'account_type', + 'default' => true, + 'width' => '10%', + ), + 'industry' => + array ( + 'name' => 'industry', + 'default' => true, + 'width' => '10%', + ), + 'assigned_user_id' => + array ( + 'name' => 'assigned_user_id', + 'type' => 'enum', + 'label' => 'LBL_ASSIGNED_TO', + 'function' => + array ( + 'name' => 'get_user_array', + 'params' => + array ( + 0 => false, + ), + ), + 'default' => true, + 'width' => '10%', + ), + + ), + ), +); +?> \ No newline at end of file diff --git a/modules/Accounts/metadata/studio.php b/modules/Accounts/metadata/studio.php new file mode 100644 index 00000000..a3ce7f01 --- /dev/null +++ b/modules/Accounts/metadata/studio.php @@ -0,0 +1,66 @@ +array( + 'template'=>'xtpl', + 'template_file'=>'modules/Accounts/DetailView.html', + 'php_file'=>'modules/Accounts/DetailView.php', + 'type'=>'DetailView', + ), + 'LBL_EDITVIEW'=>array( + 'template'=>'xtpl', + 'template_file'=>'modules/Accounts/EditView.html', + 'php_file'=>'modules/Accounts/EditView.php', + 'type'=>'EditView', + ), + 'LBL_LISTVIEW'=>array( + 'template'=>'listview', + 'meta_file'=>'modules/Accounts/listviewdefs.php', + 'type'=>'ListView', + ), + 'LBL_SEARCHFORM'=>array( + 'template'=>'xtpl', + 'template_file'=>'modules/Accounts/SearchForm.html', + 'php_file'=>'modules/Accounts/ListView.php', + 'type'=>'SearchForm', + ), + +); diff --git a/modules/Accounts/metadata/subpaneldefs.php b/modules/Accounts/metadata/subpaneldefs.php new file mode 100644 index 00000000..f0eb063f --- /dev/null +++ b/modules/Accounts/metadata/subpaneldefs.php @@ -0,0 +1,264 @@ + array( + + 'activities' => array( + 'order' => 10, + 'sort_order' => 'desc', + 'sort_by' => 'date_start', + 'title_key' => 'LBL_ACTIVITIES_SUBPANEL_TITLE', + 'type' => 'collection', + 'subpanel_name' => 'activities', //this values is not associated with a physical file. + 'header_definition_from_subpanel'=> 'meetings', + 'module'=>'Activities', + + 'top_buttons' => array( + array('widget_class' => 'SubPanelTopCreateTaskButton'), + array('widget_class' => 'SubPanelTopScheduleMeetingButton'), + array('widget_class' => 'SubPanelTopScheduleCallButton'), + array('widget_class' => 'SubPanelTopComposeEmailButton'), + ), + + 'collection_list' => array( + 'tasks' => array( + 'module' => 'Tasks', + 'subpanel_name' => 'ForActivities', + 'get_subpanel_data' => 'tasks', + ), + 'meetings' => array( + 'module' => 'Meetings', + 'subpanel_name' => 'ForActivities', + 'get_subpanel_data' => 'meetings', + ), + 'calls' => array( + 'module' => 'Calls', + 'subpanel_name' => 'ForActivities', + 'get_subpanel_data' => 'calls', + ), + ) + ), + 'history' => array( + 'order' => 20, + 'sort_order' => 'desc', + 'sort_by' => 'date_entered', + 'title_key' => 'LBL_HISTORY_SUBPANEL_TITLE', + 'type' => 'collection', + 'subpanel_name' => 'history', //this values is not associated with a physical file. + 'header_definition_from_subpanel'=> 'meetings', + 'module'=>'History', + + 'top_buttons' => array( + array('widget_class' => 'SubPanelTopCreateNoteButton'), + array('widget_class' => 'SubPanelTopArchiveEmailButton'), + array('widget_class' => 'SubPanelTopSummaryButton'), + ), + + 'collection_list' => array( + 'tasks' => array( + 'module' => 'Tasks', + 'subpanel_name' => 'ForHistory', + 'get_subpanel_data' => 'tasks', + ), + 'meetings' => array( + 'module' => 'Meetings', + 'subpanel_name' => 'ForHistory', + 'get_subpanel_data' => 'meetings', + ), + 'calls' => array( + 'module' => 'Calls', + 'subpanel_name' => 'ForHistory', + 'get_subpanel_data' => 'calls', + ), + 'notes' => array( + 'module' => 'Notes', + 'subpanel_name' => 'ForHistory', + 'get_subpanel_data' => 'notes', + ), + 'emails' => array( + 'module' => 'Emails', + 'subpanel_name' => 'ForHistory', + 'get_subpanel_data' => 'emails', + ), + 'linkedemails' => array( + 'module' => 'Emails', + 'subpanel_name' => 'ForUnlinkedEmailHistory', + 'get_subpanel_data' => 'function:get_unlinked_email_query', + 'generate_select'=>true, + 'function_parameters' => array('return_as_array'=>'true'), + ), + ) + ), + 'documents' => array( + 'order' => 25, + 'module' => 'Documents', + 'subpanel_name' => 'default', + 'sort_order' => 'asc', + 'sort_by' => 'id', + 'title_key' => 'LBL_DOCUMENTS_SUBPANEL_TITLE', + 'get_subpanel_data' => 'documents', + 'top_buttons' => + array ( + 0 => + array ( + 'widget_class' => 'SubPanelTopButtonQuickCreate', + ), + 1 => + array ( + 'widget_class' => 'SubPanelTopSelectButton', + 'mode' => 'MultiSelect', + ), + ), + ), + 'contacts' => array( + 'order' => 30, + 'module' => 'Contacts', + 'sort_order' => 'asc', + 'sort_by' => 'last_name, first_name', + 'subpanel_name' => 'ForAccounts', + 'get_subpanel_data' => 'contacts', + 'add_subpanel_data' => 'contact_id', + 'title_key' => 'LBL_CONTACTS_SUBPANEL_TITLE', + 'top_buttons' => array( + array('widget_class' => 'SubPanelTopCreateAccountNameButton'), + array('widget_class' => 'SubPanelTopSelectButton', 'mode'=>'MultiSelect') + ), + + ), + 'opportunities' => array( + 'order' => 40, + 'module' => 'Opportunities', + 'subpanel_name' => 'ForAccounts', + 'sort_order' => 'desc', + 'sort_by' => 'date_closed', + 'get_subpanel_data' => 'opportunities', + 'add_subpanel_data' => 'opportunity_id', + 'title_key' => 'LBL_OPPORTUNITIES_SUBPANEL_TITLE', + 'top_buttons' => array( + array('widget_class' => 'SubPanelTopButtonQuickCreate') + ), + ), + 'leads' => array( + 'order' => 80, + 'module' => 'Leads', + 'sort_order' => 'asc', + 'sort_by' => 'last_name, first_name', + 'subpanel_name' => 'default', + 'get_subpanel_data' => 'leads', + 'add_subpanel_data' => 'lead_id', + 'title_key' => 'LBL_LEADS_SUBPANEL_TITLE', + 'top_buttons' => array( + array('widget_class' => 'SubPanelTopCreateLeadNameButton'), + array('widget_class' => 'SubPanelTopSelectButton', + 'popup_module' => 'Opportunities', + 'mode' => 'MultiSelect', + ), + ), + + ), + 'cases' => array( + 'order' => 100, + 'sort_order' => 'desc', + 'sort_by' => 'case_number', + 'module' => 'Cases', + 'subpanel_name' => 'ForAccounts', + 'get_subpanel_data' => 'cases', + 'add_subpanel_data' => 'case_id', + 'title_key' => 'LBL_CASES_SUBPANEL_TITLE', + 'top_buttons' => array( + array('widget_class' => 'SubPanelTopButtonQuickCreate'), + array('widget_class' => 'SubPanelTopSelectButton', 'mode'=>'MultiSelect') + ), + ), + 'accounts' => array( + 'order' => 90, + 'sort_order' => 'asc', + 'sort_by' => 'name', + 'module' => 'Accounts', + 'subpanel_name' => 'default', + 'get_subpanel_data' => 'members', + 'add_subpanel_data' => 'member_id', + 'title_key' => 'LBL_MEMBER_ORG_SUBPANEL_TITLE', + 'top_buttons' => array( + array('widget_class' => 'SubPanelTopButtonQuickCreate'), + array('widget_class' => 'SubPanelTopSelectButton', 'mode'=>'MultiSelect') + ), + ), + 'bugs' => array( + 'order' => 110, + 'sort_order' => 'desc', + 'sort_by' => 'bug_number', + 'module' => 'Bugs', + 'subpanel_name' => 'default', + 'get_subpanel_data' => 'bugs', + 'add_subpanel_data' => 'bug_id', + 'title_key' => 'LBL_BUGS_SUBPANEL_TITLE', + 'top_buttons' => array( + array('widget_class' => 'SubPanelTopButtonQuickCreate'), + array('widget_class' => 'SubPanelTopSelectButton', 'mode'=>'MultiSelect') + ), + ), + 'project' => array( + 'order' => 120, + 'sort_order' => 'asc', + 'sort_by' => 'name', + 'module' => 'Project', + 'subpanel_name' => 'default', + 'get_subpanel_data' => 'project', + 'add_subpanel_data' => 'project_id', + 'title_key' => 'LBL_PROJECTS_SUBPANEL_TITLE', + 'top_buttons' => array( + array('widget_class' => 'SubPanelTopButtonQuickCreate'), + array('widget_class' => 'SubPanelTopSelectButton', 'mode'=>'MultiSelect'), + ), + ), + 'campaigns' => array( + 'order' => 70, + 'module' => 'CampaignLog', + 'sort_order' => 'desc', + 'sort_by' => 'activity_date', + 'get_subpanel_data'=>'campaigns', + 'subpanel_name' => 'ForTargets', + 'title_key' => 'LBL_CAMPAIGNS', + ), + ), +); +?> \ No newline at end of file diff --git a/modules/Accounts/metadata/subpanels/ForEmails.php b/modules/Accounts/metadata/subpanels/ForEmails.php new file mode 100644 index 00000000..7b20d140 --- /dev/null +++ b/modules/Accounts/metadata/subpanels/ForEmails.php @@ -0,0 +1,76 @@ + array( + array('widget_class' => 'SubPanelTopCreateButton'), + array('widget_class' => 'SubPanelTopSelectButton', 'popup_module' => 'Accounts'), + ), + + 'where' => '', + + + 'list_fields' => array( + 'name' => array( + 'vname' => 'LBL_LIST_ACCOUNT_NAME', + 'widget_class' => 'SubPanelDetailViewLink', + 'width' => '45%', + ), + 'billing_address_city' => array( + 'vname' => 'LBL_LIST_CITY', + 'width' => '27%', + ), + 'phone_office' => array( + 'vname' => 'LBL_LIST_PHONE', + 'width' => '20%', + ), + 'edit_button' => array( + 'vname' => 'LBL_EDIT_BUTTON', + 'widget_class' => 'SubPanelEditButton', + 'width' => '4%', + ), + 'remove_button' => array( + 'vname' => 'LBL_REMOVE', + 'widget_class' => 'SubPanelRemoveButton', + 'width' => '4%', + ), + ), +); + +?> \ No newline at end of file diff --git a/modules/Accounts/metadata/subpanels/ForProspectLists.php b/modules/Accounts/metadata/subpanels/ForProspectLists.php new file mode 100644 index 00000000..132f874e --- /dev/null +++ b/modules/Accounts/metadata/subpanels/ForProspectLists.php @@ -0,0 +1,81 @@ + array( + array('widget_class' => 'SubPanelTopCreateButton'), + array('widget_class' => 'SubPanelTopSelectButton', 'popup_module' => 'Accounts'), + ), + + 'where' => '', + + + 'list_fields' => array( + 'name' => array( + 'vname' => 'LBL_LIST_NAME', + 'widget_class' => 'SubPanelDetailViewLink', + 'width' => '25%', + ), + 'phone_office' => array( + 'vname' => 'LBL_LIST_PHONE', + 'width' => '20%', + ), + 'email1' => array( + 'vname' => 'LBL_LIST_EMAIL', + 'widget_class' => 'SubPanelEmailLink', + 'width' => '20%', + ), + 'assigned_user_name' => array( + 'vname' => 'LBL_ASSIGNED_TO', + 'width' => '20%', + ), + 'edit_button' => array( + 'vname' => 'LBL_EDIT_BUTTON', + 'widget_class' => 'SubPanelEditButton', + 'width' => '4%', + ), + 'remove_button' => array( + 'vname' => 'LBL_REMOVE', + 'widget_class' => 'SubPanelRemoveButton', + 'width' => '4%', + ), + ), +); + +?> \ No newline at end of file diff --git a/modules/Accounts/metadata/subpanels/default.php b/modules/Accounts/metadata/subpanels/default.php new file mode 100644 index 00000000..6682f0f7 --- /dev/null +++ b/modules/Accounts/metadata/subpanels/default.php @@ -0,0 +1,91 @@ + array( + array('widget_class' => 'SubPanelTopCreateButton'), + array('widget_class' => 'SubPanelTopSelectButton', 'popup_module' => 'Accounts'), + ), + + 'where' => '', + + 'list_fields' => array ( + 'name' => + array ( + 'vname' => 'LBL_LIST_ACCOUNT_NAME', + 'widget_class' => 'SubPanelDetailViewLink', + 'width' => '45%', + 'default' => true, + ), + 'billing_address_city' => + array ( + 'vname' => 'LBL_LIST_CITY', + 'width' => '20%', + 'default' => true, + ), + 'billing_address_country' => + array ( + 'type' => 'varchar', + 'vname' => 'LBL_BILLING_ADDRESS_COUNTRY', + 'width' => '7%', + 'default' => true, + ), + 'phone_office' => + array ( + 'vname' => 'LBL_LIST_PHONE', + 'width' => '20%', + 'default' => true, + ), + 'edit_button' => + array ( + 'vname' => 'LBL_EDIT_BUTTON', + 'widget_class' => 'SubPanelEditButton', + 'width' => '4%', + 'default' => true, + ), + 'remove_button' => + array ( + 'vname' => 'LBL_REMOVE', + 'widget_class' => 'SubPanelRemoveButton', + 'width' => '4%', + 'default' => true, + ), + ) +); +?> \ No newline at end of file diff --git a/modules/Accounts/tpls/QuickCreate.tpl b/modules/Accounts/tpls/QuickCreate.tpl new file mode 100644 index 00000000..513a8c32 --- /dev/null +++ b/modules/Accounts/tpls/QuickCreate.tpl @@ -0,0 +1,90 @@ +{* + +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + + + +*} + + + + + + + + + + + + + + + + + + + + + + +
    + + + {$APP.LBL_REQUIRED_SYMBOL} {$APP.NTC_REQUIRED}
    + + +"); + $sugar_smarty->assign("MYSQL_CAPABLE", ""); + $sugar_smarty->assign("MYSQL_CAPABLE_CHECKBOXES", + "" + ); +} +else { + $sugar_smarty->assign("NO_MYSQL_MESSAGE", ""); + $sugar_smarty->assign("MYSQL_CAPABLE", "checked"); + $sugar_smarty->assign("MYSQL_CAPABLE_CHECKBOXES", ""); +} + +$sugar_smarty->assign("RETURN_MODULE", "Administration"); +$sugar_smarty->assign("RETURN_ACTION", "index"); + +$sugar_smarty->assign("MODULE", $currentModule); +$sugar_smarty->assign("PRINT_URL", "index.php?".$GLOBALS['request_string']); + + +$sugar_smarty->assign("ADVANCED_SEARCH_PNG", SugarThemeRegistry::current()->getImage('advanced_search','alt="'.$app_strings['LNK_ADVANCED_SEARCH'].'" border="0"')); +$sugar_smarty->assign("BASIC_SEARCH_PNG", SugarThemeRegistry::current()->getImage('basic_search','alt="'.$app_strings['LNK_BASIC_SEARCH'].'" border="0"')); + +$sugar_smarty->display("modules/Administration/Diagnostic.tpl"); diff --git a/modules/Administration/Diagnostic.tpl b/modules/Administration/Diagnostic.tpl new file mode 100644 index 00000000..0eabe78c --- /dev/null +++ b/modules/Administration/Diagnostic.tpl @@ -0,0 +1,129 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +/********************************************************************************* + + ********************************************************************************/ +*} + + + + + +
    + + + + + + + + + + + + + + + +

    {$MOD.LBL_ACCOUNT_INFORMATION}

    {$MOD.LBL_ACCOUNT_NAME} {$APP.LBL_REQUIRED_SYMBOL}{$MOD.LBL_PHONE}
    {$MOD.LBL_WEBSITE}{$MOD.LBL_EMAIL}
    + + \ No newline at end of file diff --git a/modules/Accounts/vardefs.php b/modules/Accounts/vardefs.php new file mode 100644 index 00000000..65a73d0a --- /dev/null +++ b/modules/Accounts/vardefs.php @@ -0,0 +1,461 @@ + 'accounts', 'audited'=>true, 'unified_search' => true, 'unified_search_default_enabled' => true, 'duplicate_merge'=>true, + 'comment' => 'Accounts are organizations or entities that are the target of selling, support, and marketing activities, or have already purchased products or services', + 'fields' => array ( + + 'parent_id' => + array ( + 'name' => 'parent_id', + 'vname' => 'LBL_PARENT_ACCOUNT_ID', + 'type' => 'id', + 'required'=>false, + 'reportable'=>false, + 'audited'=>true, + 'comment' => 'Account ID of the parent of this account', + ), + + 'sic_code' => + array ( + 'name' => 'sic_code', + 'vname' => 'LBL_SIC_CODE', + 'type' => 'varchar', + 'len' => 10, + 'comment' => 'SIC code of the account', + ), + + + 'parent_name' => + array ( + 'name' => 'parent_name', + 'rname' => 'name', + 'id_name' => 'parent_id', + 'vname' => 'LBL_MEMBER_OF', + 'type' => 'relate', + 'isnull' => 'true', + 'module' => 'Accounts', + 'table' => 'accounts', + 'massupdate' => false, + 'source'=>'non-db', + 'len' => 36, + 'link'=>'member_of', + 'unified_search' => true, + 'importable' => 'true', + ), + + + 'members' => + array ( + 'name' => 'members', + 'type' => 'link', + 'relationship' => 'member_accounts', + 'module'=>'Accounts', + 'bean_name'=>'Account', + 'source'=>'non-db', + 'vname'=>'LBL_MEMBERS', + ), + 'member_of' => + array ( + 'name' => 'member_of', + 'type' => 'link', + 'relationship' => 'member_accounts', + 'module'=>'Accounts', + 'bean_name'=>'Account', + 'link_type'=>'one', + 'source'=>'non-db', + 'vname'=>'LBL_MEMBER_OF', + 'side'=>'right', + ), + 'email_opt_out' => + array( + 'name' => 'email_opt_out', + 'vname' => 'LBL_EMAIL_OPT_OUT', + 'source' => 'non-db', + 'type' => 'bool', + 'massupdate' => false, + 'studio'=>'false', + ), + 'invalid_email' => + array( + 'name' => 'invalid_email', + 'vname' => 'LBL_INVALID_EMAIL', + 'source' => 'non-db', + 'type' => 'bool', + 'massupdate' => false, + 'studio'=>'false', + ), + 'cases' => + array ( + 'name' => 'cases', + 'type' => 'link', + 'relationship' => 'account_cases', + 'module'=>'Cases', + 'bean_name'=>'aCase', + 'source'=>'non-db', + 'vname'=>'LBL_CASES', + ), + 'tasks' => + array ( + 'name' => 'tasks', + 'type' => 'link', + 'relationship' => 'account_tasks', + 'module'=>'Tasks', + 'bean_name'=>'Task', + 'source'=>'non-db', + 'vname'=>'LBL_TASKS', + ), + 'notes' => + array ( + 'name' => 'notes', + 'type' => 'link', + 'relationship' => 'account_notes', + 'module'=>'Notes', + 'bean_name'=>'Note', + 'source'=>'non-db', + 'vname'=>'LBL_NOTES', + ), + 'meetings' => + array ( + 'name' => 'meetings', + 'type' => 'link', + 'relationship' => 'account_meetings', + 'module'=>'Meetings', + 'bean_name'=>'Meeting', + 'source'=>'non-db', + 'vname'=>'LBL_MEETINGS', + ), + 'calls' => + array ( + 'name' => 'calls', + 'type' => 'link', + 'relationship' => 'account_calls', + 'module'=>'Calls', + 'bean_name'=>'Call', + 'source'=>'non-db', + 'vname'=>'LBL_CALLS', + ), + + 'emails' => + array ( + 'name' => 'emails', + 'type' => 'link', + 'relationship' => 'emails_accounts_rel', /* reldef in emails */ + 'module'=>'Emails', + 'bean_name'=>'Email', + 'source'=>'non-db', + 'vname'=>'LBL_EMAILS', + ), + 'documents'=> + array ( + 'name' => 'documents', + 'type' => 'link', + 'relationship' => 'documents_accounts', + 'source' => 'non-db', + 'vname' => 'LBL_DOCUMENTS_SUBPANEL_TITLE', + ), + 'bugs' => + array ( + 'name' => 'bugs', + 'type' => 'link', + 'relationship' => 'accounts_bugs', + 'module'=>'Bugs', + 'bean_name'=>'Bug', + 'source'=>'non-db', + 'vname'=>'LBL_BUGS', + ), + 'contacts' => + array ( + 'name' => 'contacts', + 'type' => 'link', + 'relationship' => 'accounts_contacts', + 'module'=>'Contacts', + 'bean_name'=>'Contact', + 'source'=>'non-db', + 'vname'=>'LBL_CONTACTS', + ), + 'email_addresses' => + array ( + 'name' => 'email_addresses', + 'type' => 'link', + 'relationship' => 'accounts_email_addresses', + 'source' => 'non-db', + 'vname' => 'LBL_EMAIL_ADDRESSES', + 'reportable'=>false, + 'unified_search' => true, + 'rel_fields' => array('primary_address' => array('type'=>'bool')), + ), + 'email_addresses_primary' => + array ( + 'name' => 'email_addresses_primary', + 'type' => 'link', + 'relationship' => 'accounts_email_addresses_primary', + 'source' => 'non-db', + 'vname' => 'LBL_EMAIL_ADDRESS_PRIMARY', + 'duplicate_merge'=> 'disabled', + ), + 'opportunities' => + array ( + 'name' => 'opportunities', + 'type' => 'link', + 'relationship' => 'accounts_opportunities', + 'module'=>'Opportunities', + 'bean_name'=>'Opportunity', + 'source'=>'non-db', + 'vname'=>'LBL_OPPORTUNITY', + ), + + + 'project' => + array ( + 'name' => 'project', + 'type' => 'link', + 'relationship' => 'projects_accounts', + 'module'=>'Project', + 'bean_name'=>'Project', + 'source'=>'non-db', + 'vname'=>'LBL_PROJECTS', + ), + 'leads' => + array ( + 'name' => 'leads', + 'type' => 'link', + 'relationship' => 'account_leads', + 'module'=>'Leads', + 'bean_name'=>'Lead', + 'source'=>'non-db', + 'vname'=>'LBL_LEADS', + ), + 'campaigns' => + array ( + 'name' => 'campaigns', + 'type' => 'link', + 'relationship' => 'account_campaign_log', + 'module'=>'CampaignLog', + 'bean_name'=>'CampaignLog', + 'source'=>'non-db', + 'vname'=>'LBL_CAMPAIGNLOG', + ), + 'campaign_accounts' => + array ( + 'name' => 'campaign_accounts', + 'type' => 'link', + 'vname' => 'LBL_CAMPAIGNS', + 'relationship' => 'campaign_accounts', + 'source' => 'non-db', + ), + + 'created_by_link' => + array ( + 'name' => 'created_by_link', + 'type' => 'link', + 'relationship' => 'accounts_created_by', + 'vname' => 'LBL_CREATED_BY_USER', + 'link_type' => 'one', + 'module'=>'Users', + 'bean_name'=>'User', + 'source'=>'non-db', + ), + 'modified_user_link' => + array ( + 'name' => 'modified_user_link', + 'type' => 'link', + 'relationship' => 'accounts_modified_user', + 'vname' => 'LBL_MODIFIED_BY_USER', + 'link_type' => 'one', + 'module'=>'Users', + 'bean_name'=>'User', + 'source'=>'non-db', + ), + 'assigned_user_link' => + array ( + 'name' => 'assigned_user_link', + 'type' => 'link', + 'relationship' => 'accounts_assigned_user', + 'vname' => 'LBL_ASSIGNED_TO_USER', + 'link_type' => 'one', + 'module'=>'Users', + 'bean_name'=>'User', + 'source'=>'non-db', + 'duplicate_merge'=>'enabled', + 'rname' => 'user_name', + 'id_name' => 'assigned_user_id', + 'table' => 'users', + ), + + 'products' => array( + 'name' => 'products', + 'type' => 'link', + 'relationship' => 'products_accounts', + 'source' => 'non-db', + 'vname' => 'LBL_PRODUCTS', + ), + + 'campaign_id' => + array ( + 'name' => 'campaign_id', + 'comment' => 'Campaign that generated Account', + 'vname'=>'LBL_CAMPAIGN_ID', + 'rname' => 'id', + 'id_name' => 'campaign_id', + 'type' => 'id', + 'table' => 'campaigns', + 'isnull' => 'true', + 'module' => 'Campaigns', + 'reportable'=>false, + 'massupdate' => false, + 'duplicate_merge'=> 'disabled', + ), + + 'campaign_name' => + array ( + 'name'=>'campaign_name', + 'rname'=>'name', + 'vname' => 'LBL_CAMPAIGN', + 'type' => 'relate', + 'reportable'=>false, + 'source'=>'non-db', + 'table' => 'campaigns', + 'id_name' => 'campaign_id', + 'link' => 'campaign_accounts', + 'module'=>'Campaigns', + 'duplicate_merge'=>'disabled', + 'comment' => 'The first campaign name for Account (Meta-data only)', + ), + + 'prospect_lists' => + array ( + 'name' => 'prospect_lists', + 'type' => 'link', + 'relationship' => 'prospect_list_accounts', + 'module'=>'ProspectLists', + 'source'=>'non-db', + 'vname'=>'LBL_PROSPECT_LIST', + ), +) +, 'indices' => array ( + array('name' =>'idx_accnt_id_del', 'type' =>'index', 'fields'=>array('id', 'deleted')), + array('name' =>'idx_accnt_name_del', 'type' => 'index', 'fields'=>array('name', 'deleted')),//bug #5530 + array('name' =>'idx_accnt_assigned_del', 'type' =>'index', 'fields'=>array( 'deleted', 'assigned_user_id')), + array('name' =>'idx_accnt_parent_id', 'type' =>'index', 'fields'=>array( 'parent_id')), + ) + +, 'relationships' => array ( + 'member_accounts' => array('lhs_module'=> 'Accounts', 'lhs_table'=> 'accounts', 'lhs_key' => 'id', + 'rhs_module'=> 'Accounts', 'rhs_table'=> 'accounts', 'rhs_key' => 'parent_id', + 'relationship_type'=>'one-to-many') + + ,'account_cases' => array('lhs_module'=> 'Accounts', 'lhs_table'=> 'accounts', 'lhs_key' => 'id', + 'rhs_module'=> 'Cases', 'rhs_table'=> 'cases', 'rhs_key' => 'account_id', + 'relationship_type'=>'one-to-many') + + ,'account_tasks' => array('lhs_module'=> 'Accounts', 'lhs_table'=> 'accounts', 'lhs_key' => 'id', + 'rhs_module'=> 'Tasks', 'rhs_table'=> 'tasks', 'rhs_key' => 'parent_id', + 'relationship_type'=>'one-to-many', 'relationship_role_column'=>'parent_type', + 'relationship_role_column_value'=>'Accounts') + + ,'account_notes' => array('lhs_module'=> 'Accounts', 'lhs_table'=> 'accounts', 'lhs_key' => 'id', + 'rhs_module'=> 'Notes', 'rhs_table'=> 'notes', 'rhs_key' => 'parent_id', + 'relationship_type'=>'one-to-many', 'relationship_role_column'=>'parent_type', + 'relationship_role_column_value'=>'Accounts') + + ,'account_meetings' => array('lhs_module'=> 'Accounts', 'lhs_table'=> 'accounts', 'lhs_key' => 'id', + 'rhs_module'=> 'Meetings', 'rhs_table'=> 'meetings', 'rhs_key' => 'parent_id', + 'relationship_type'=>'one-to-many', 'relationship_role_column'=>'parent_type', + 'relationship_role_column_value'=>'Accounts') + + ,'account_calls' => array('lhs_module'=> 'Accounts', 'lhs_table'=> 'accounts', 'lhs_key' => 'id', + 'rhs_module'=> 'Calls', 'rhs_table'=> 'calls', 'rhs_key' => 'parent_id', + 'relationship_type'=>'one-to-many', 'relationship_role_column'=>'parent_type', + 'relationship_role_column_value'=>'Accounts') + +/*,'accounts_emails' => array( + 'rhs_module' => 'Emails', + 'rhs_table' => 'emails', + 'rhs_key' => 'id', + 'lhs_module' => 'Accounts', + 'lhs_table' => 'accounts', + 'lhs_key' => 'id', + 'relationship_type' => 'many-to-many', + 'join_table' => 'emails_accounts', + 'join_key_rhs' => 'email_id', + 'join_key_lhs' => 'account_id' +) +*/ + ,'account_emails' => array('lhs_module'=> 'Accounts', 'lhs_table'=> 'accounts', 'lhs_key' => 'id', + 'rhs_module'=> 'Emails', 'rhs_table'=> 'emails', 'rhs_key' => 'parent_id', + 'relationship_type'=>'one-to-many', 'relationship_role_column'=>'parent_type', + 'relationship_role_column_value'=>'Accounts') + + ,'account_leads' => array('lhs_module'=> 'Accounts', 'lhs_table'=> 'accounts', 'lhs_key' => 'id', + 'rhs_module'=> 'Leads', 'rhs_table'=> 'leads', 'rhs_key' => 'account_id', + 'relationship_type'=>'one-to-many') + , + + 'accounts_assigned_user' => + array('lhs_module'=> 'Users', 'lhs_table'=> 'users', 'lhs_key' => 'id', + 'rhs_module'=> 'Accounts', 'rhs_table'=> 'accounts', 'rhs_key' => 'assigned_user_id', + 'relationship_type'=>'one-to-many'), + + 'accounts_modified_user' => + array('lhs_module'=> 'Users', 'lhs_table'=> 'users', 'lhs_key' => 'id', + 'rhs_module'=> 'Accounts', 'rhs_table'=> 'accounts', 'rhs_key' => 'modified_user_id', + 'relationship_type'=>'one-to-many'), + + 'accounts_created_by' => + array('lhs_module'=> 'Users', 'lhs_table'=> 'users', 'lhs_key' => 'id', + 'rhs_module'=> 'Accounts', 'rhs_table'=> 'accounts', 'rhs_key' => 'created_by', + 'relationship_type'=>'one-to-many'), + + 'account_campaign_log' => array('lhs_module' => 'Accounts', 'lhs_table'=> 'accounts', 'lhs_key'=> 'id', + 'rhs_module'=> 'CampaignLog','rhs_table'=>'campaign_log', 'rhs_key'=> 'target_id', + 'relationship_type' =>'one-to-many'), + + ), + //This enables optimistic locking for Saves From EditView + 'optimistic_locking'=>true, +); + +VardefManager::createVardef('Accounts','Account', array('default', 'assignable', +'company', +)); + +//jc - adding for refactor for import to not use the required_fields array +//defined in the field_arrays.php file +$dictionary['Account']['fields']['name']['importable'] = 'required'; + +?> \ No newline at end of file diff --git a/modules/Accounts/views/view.detail.php b/modules/Accounts/views/view.detail.php new file mode 100644 index 00000000..00490581 --- /dev/null +++ b/modules/Accounts/views/view.detail.php @@ -0,0 +1,106 @@ +bean->id)){ + global $app_strings; + sugar_die($app_strings['ERROR_NO_RECORD']); + } + + $this->dv->process(); + global $mod_strings; + if(ACLController::checkAccess('Contacts', 'edit', true)) { + $push_billing = ''; + + $push_shipping = ''; + } else { + $push_billing = ''; + $push_shipping = ''; + } + + $this->ss->assign("custom_code_billing", $push_billing); + $this->ss->assign("custom_code_shipping", $push_shipping); + + if(empty($this->bean->id)){ + global $app_strings; + sugar_die($app_strings['ERROR_NO_RECORD']); + } + echo $this->dv->display(); + } +} + +?> \ No newline at end of file diff --git a/modules/Accounts/views/view.list.php b/modules/Accounts/views/view.list.php new file mode 100644 index 00000000..89634869 --- /dev/null +++ b/modules/Accounts/views/view.list.php @@ -0,0 +1,48 @@ +lv->targetList = true; + } +} diff --git a/modules/Activities/Forms.php b/modules/Activities/Forms.php new file mode 100644 index 00000000..d1077c21 --- /dev/null +++ b/modules/Activities/Forms.php @@ -0,0 +1,37 @@ + diff --git a/modules/Activities/OpenListView.html b/modules/Activities/OpenListView.html new file mode 100644 index 00000000..4671a22c --- /dev/null +++ b/modules/Activities/OpenListView.html @@ -0,0 +1,117 @@ +admin + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    {MOD.LBL_LIST_CLOSE}{MOD.LBL_LIST_SUBJECT}{MOD.LBL_LIST_DATE}{MOD.LBL_ACCEPT_THIS}
    {ACTIVITY_MODULE_PNG}{ACTIVITY.SET_COMPLETE}<{ACTIVITY.TAG} title="{ACTIVITY.TITLE}" href="{URL_PREFIX}index.php?action=DetailView&module={ACTIVITY.MODULE}&record={ACTIVITY.ID}{RETURN_URL}" >{ACTIVITY.NAME}{ACTIVITY.TIME}{ACTIVITY.SET_ACCEPT_LINKS}
    + diff --git a/modules/Activities/OpenListView.php b/modules/Activities/OpenListView.php new file mode 100644 index 00000000..c51f1e83 --- /dev/null +++ b/modules/Activities/OpenListView.php @@ -0,0 +1,328 @@ +getPreference('appointment_filter') == '') { + $appointment_filter = 'today'; + } else { + $appointment_filter = $current_user->getPreference('appointment_filter'); + } +} else { + $appointment_filter = $_REQUEST['appointment_filter']; + $current_user->setPreference('appointment_filter', $_REQUEST['appointment_filter']); +} + +if ($appointment_filter == 'last this_month') { + $laterDate = $timedate->getNow(true)->get("last day of this month"); +} elseif ($appointment_filter == 'last next_month') { + $laterDate = $timedate->getNow(true)->get("last day of next month"); +} else { + $laterDate = $timedate->fromString($appointment_filter); +} + +$dayEnd = $timedate->asDb($laterDate->get_day_end_time()); +$GLOBALS['log']->debug("filter $appointment_filter date $dayEnd"); + +if(ACLController::checkAccess('Meetings', 'list', true)){ + $meeting = new Meeting(); + $where = '('; + $or = false; + foreach ($open_status as $status) { + if ($or) $where .= ' OR '; + $or = true; + $where .= " meetings.status = '$status' "; + } + $where .= ") "; + $where .= " AND meetings_users.user_id='$current_user->id' "; + $where .= " AND meetings_users.accept_status != 'decline'"; + + // allow for differences between MySQL and Oracle 9 + if($sugar_config["dbconfig"]["db_type"] == "mysql") { + $where .= " HAVING datetime <= '$dayEnd' "; + } elseif ($sugar_config["dbconfig"]["db_type"] == "oci8") { + } + else if ($sugar_config["dbconfig"]["db_type"] == "mssql") + { + $where .= " AND meetings.date_start + ' ' + meetings.time_start <= '$dayEnd' "; + } + else { + $GLOBALS['log']->fatal("No database type identified."); + } + + $meeting->disable_row_level_security = true; + $focus_meetings_list = $meeting->get_full_list("time_start", $where); +} + +if(ACLController::checkAccess('Calls', 'list', true)) { + $call = new Call(); + $where = '('; + $or = false; + + foreach ($open_status as $status) { + if ($or) $where .= ' OR '; + $or = true; + $where .= " calls.status = '$status' "; + } + + $where .= ") "; + $where .= " AND calls_users.user_id='$current_user->id' "; + $where .= " AND calls_users.accept_status != 'decline'"; + + // allow for differences between MySQL and Oracle 9 + if($sugar_config["dbconfig"]["db_type"] == "mysql") { + $where .= " HAVING datetime <= '$dayEnd' "; + } elseif ($sugar_config["dbconfig"]["db_type"] == "oci8") { + }else if ($sugar_config["dbconfig"]["db_type"] == "mssql") + { + //add condition for MS Sql server. + $where .= " AND calls.date_start + ' ' + calls.time_start <= '$dayEnd' "; + } else { + $GLOBALS['log']->fatal("No database type identified."); + } + + $call->disable_row_level_security = true; + $focus_calls_list = $call->get_full_list("time_start", $where); +} + +$open_activity_list = array(); +if(count($focus_meetings_list)>0) { + foreach ($focus_meetings_list as $meeting) { + $td = $timedate->merge_date_time(from_db_convert($meeting->date_start,'date'),from_db_convert($meeting->time_start, 'time')); + $tag = 'span'; + + if($meeting->ACLAccess('view', $meeting->isOwner($current_user->id))){ + $tag = 'a'; + } + + $open_activity_list[] = array( + 'name' => $meeting->name, + 'id' => $meeting->id, + 'type' => 'Meeting', + 'module' => 'Meetings', + 'status' => $meeting->status, + 'parent_id' => $meeting->parent_id, + 'parent_type' => $meeting->parent_type, + 'parent_name' => $meeting->parent_name, + 'contact_id' => $meeting->contact_id, + 'contact_name' => $meeting->contact_name, + 'normal_date_start' => $meeting->date_start, + 'date_start' => $timedate->to_display_date($td), + 'normal_time_start' => $meeting->time_start, + 'time_start' => $timedate->to_display_time($td,true), + 'required' => $meeting->required, + 'accept_status' => $meeting->accept_status, + 'tag' => $tag, + ); + } +} + +if (count($focus_calls_list)>0) { + foreach ($focus_calls_list as $call) { + + $td = $timedate->merge_date_time(from_db_convert($call->date_start,'date'),from_db_convert($call->time_start, 'time')); + $tag = 'span'; + + if($call->ACLAccess('view', $call->isOwner($current_user->id))) { + $tag = 'a'; + } + + $open_activity_list[] = array( + 'name' => $call->name, + 'id' => $call->id, + 'type' => 'Call', + 'module' => 'Calls', + 'status' => $call->status, + 'parent_id' => $call->parent_id, + 'parent_type' => $call->parent_type, + 'parent_name' => $call->parent_name, + 'contact_id' => $call->contact_id, + 'contact_name' => $call->contact_name, + 'date_start' => $timedate->to_display_date($td), + 'normal_date_start' => $call->date_start, + 'normal_time_start' => $call->time_start, + 'time_start' => $timedate->to_display_time($td,true), + 'required' => $call->required, + 'accept_status' => $call->accept_status, + 'tag' => $tag, + ); + } +} + +/////////////////////////////////////////////////////////////////////////////// +//// START OUTPUT + +$xtpl=new XTemplate ('modules/Activities/OpenListView.html'); +$xtpl->assign("MOD", $current_module_strings); +$xtpl->assign("APP", $app_strings); +$xtpl->assign('JSON_CONFIG_JAVASCRIPT', $json_config->get_static_json_server()); +$xtpl->assign("SUGAR_VERSION", $sugar_version); +$xtpl->assign("JS_CUSTOM_VERSION", $sugar_config['js_custom_version']); + +// Stick the form header out there. +$filter = get_select_options_with_id($current_module_strings['appointment_filter_dom'], $appointment_filter ); +echo "
    \n"; +echo "\n"; +echo "\n"; +$day_filter = ""; + +echo get_form_header($current_module_strings['LBL_UPCOMING'], $current_module_strings['LBL_TODAY'].$day_filter.' ('.$timedate->to_display_date($later, false).') ', false); +echo "
    \n"; + +$xtpl->assign("RETURN_URL", "&return_module=$currentModule&return_action=DetailView&return_id=" . ((is_object($focus) && ! empty($focus->id)) ? $focus->id : "")); + +$oddRow = true; +if(count($open_activity_list) > 0) { + $open_activity_list = array_csort($open_activity_list, 'normal_date_start', 'normal_time_start', SORT_ASC); +} + +$today = $timedate->handle_offset('today', $timedate->dbDayFormat.' '.$timedate->dbTimeFormat, false); +$todayOffset = $timedate->handleOffsetMax('today', $timedate->dbDayFormat.' '.$timedate->dbTimeFormat, true); + +foreach($open_activity_list as $activity) { + $concatActDate = $activity['normal_date_start'].' '.$activity['normal_time_start']; + + if($concatActDate < $today) { + $time = "".$activity['date_start'].' '.$activity['time_start'].""; + } elseif(($concatActDate >= $todayOffset['min']) && ($concatActDate <= $todayOffset['max'])) { + $time = "".$activity['date_start'].' '.$activity['time_start'].""; + } else { + $time = "".$activity['date_start'].' '.$activity['time_start'].""; + } + + $activity_fields = array( + 'ID' => $activity['id'], + 'NAME' => $activity['name'], + 'TYPE' => $activity['type'], + 'MODULE' => $activity['module'], + 'STATUS' => $activity['status'], + 'CONTACT_NAME' => $activity['contact_name'], + 'CONTACT_ID' => $activity['contact_id'], + 'PARENT_TYPE' => $activity['parent_type'], + 'PARENT_NAME' => $activity['parent_name'], + 'PARENT_ID' => $activity['parent_id'], + 'TIME' => $time, + 'TAG' => $activity['tag'], + ); + + switch ($activity['parent_type']) { + case 'Accounts': + $activity_fields['PARENT_MODULE'] = 'Accounts'; + break; + case 'Cases': + $activity_fields['PARENT_MODULE'] = 'Cases'; + break; + case 'Opportunities': + $activity_fields['PARENT_MODULE'] = 'Opportunities'; + break; + case 'Quotes': + $activity_fields['PARENT_MODULE'] = 'Quotes'; + break; + } + switch ($activity['type']) { + case 'Call': + $activity_fields['SET_COMPLETE'] = "".SugarThemeRegistry::current()->getImage("close_inline","title=".translate('LBL_LIST_CLOSE','Activities')." border='0'").""; + break; + case 'Meeting': + $activity_fields['SET_COMPLETE'] = "".SugarThemeRegistry::current()->getImage("close_inline","title=".translate('LBL_LIST_CLOSE','Activities')." border='0'").""; + break; + } + + if (! empty($activity['accept_status'])) { + if ( $activity['accept_status'] == 'none') { + $activity_fields['SET_ACCEPT_LINKS'] = ""; + } else { + $activity_fields['SET_ACCEPT_LINKS'] = $app_list_strings['dom_meeting_accept_status'][$activity['accept_status']]; + } + } + + $activity_fields['TITLE'] = ''; + if (!empty($activity['contact_name'])) { + $activity_fields['TITLE'] .= $current_module_strings['LBL_LIST_CONTACT'].": ".$activity['contact_name']; + } + if (!empty($activity['parent_name'])) { + $activity_fields['TITLE'] .= "\n".$app_list_strings['record_type_display'][$activity['parent_type']].": ".$activity['parent_name']; + } + + $xtpl->assign("ACTIVITY_MODULE_PNG", SugarThemeRegistry::current()->getImage($activity_fields['MODULE'].'','border="0" alt="'.$activity_fields['NAME'].'"')); + $xtpl->assign("ACTIVITY", $activity_fields); + $xtpl->assign("BG_HILITE", $hilite_bg); + $xtpl->assign("BG_CLICK", $click_bg); + + if($oddRow) { + $xtpl->assign("ROW_COLOR", 'oddListRow'); + $xtpl->assign("BG_COLOR", $odd_bg); + } else { + $xtpl->assign("ROW_COLOR", 'evenListRow'); + $xtpl->assign("BG_COLOR", $even_bg); + } + $oddRow = !$oddRow; + $xtpl->parse("open_activity.row"); +} // END FOREACH() + +$xtpl->parse("open_activity"); +if (count($open_activity_list)>0) $xtpl->out("open_activity"); +else echo "".$current_module_strings['NTC_NONE_SCHEDULED'].""; +?> \ No newline at end of file diff --git a/modules/Activities/Popup_picker.html b/modules/Activities/Popup_picker.html new file mode 100644 index 00000000..b5fc3b4a --- /dev/null +++ b/modules/Activities/Popup_picker.html @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    {MOD.LBL_LIST_SUBJECT}{MOD.LBL_LIST_STATUS}{MOD.LBL_LIST_CONTACT}{MOD.LBL_LIST_DATE}
    {ACTIVITY_MODULE_PNG}{ACTIVITY.NAME} {ACTIVITY.ATTACHMENT}{ACTIVITY.TYPE} {ACTIVITY.STATUS}{ACTIVITY.CONTACT_NAME}{ACTIVITY.DATE_TYPE}{ACTIVITY.DATE}
    +
    {ACTIVITY.DESCRIPTION} +
    +
    + \ No newline at end of file diff --git a/modules/Activities/Popup_picker.php b/modules/Activities/Popup_picker.php new file mode 100644 index 00000000..e5b7d494 --- /dev/null +++ b/modules/Activities/Popup_picker.php @@ -0,0 +1,429 @@ +retrieve($_REQUEST['record']); + if($result == null) + { + sugar_die($app_strings['ERROR_NO_RECORD']); + } + } + + $activitiesRels = array('tasks' => 'Task', 'meetings' => 'Meeting', 'calls' => 'Call', 'emails' => 'Email', 'notes' => 'Note'); + //Setup the arrays to store the linked records. + foreach($activitiesRels as $relMod => $beanName) { + $varname = "focus_" . $relMod . "_list"; + $$varname = array(); + } + foreach($focus->get_linked_fields() as $field => $def) { + if ($focus->load_relationship($field)) { + $relTable = $focus->$field->getRelatedTableName(); + if (in_array($relTable, array_keys($activitiesRels))) + { + $varname = "focus_" . $relTable . "_list"; + $$varname = sugarArrayMerge($$varname, $focus->get_linked_beans($field,$activitiesRels[$relTable])); + } + + } + } + + foreach ($focus_tasks_list as $task) { + $sort_date_time=''; + if (empty($task->date_due) || $task->date_due == '0000-00-00') { + $date_due = ''; + } + else { + $date_due = $task->date_due; + } + + if ($task->status != "Not Started" && $task->status != "In Progress" && $task->status != "Pending Input") { + $history_list[] = array('name' => $task->name, + 'id' => $task->id, + 'type' => "Task", + 'direction' => '', + 'module' => "Tasks", + 'status' => $task->status, + 'parent_id' => $task->parent_id, + 'parent_type' => $task->parent_type, + 'parent_name' => $task->parent_name, + 'contact_id' => $task->contact_id, + 'contact_name' => $task->contact_name, + 'date_modified' => $date_due, + 'description' => $this->getTaskDetails($task), + 'date_type' => $app_strings['DATA_TYPE_DUE'], + 'sort_value' => strtotime($task->fetched_row['date_due'].' GMT'), + ); + } else { + $open_activity_list[] = array('name' => $task->name, + 'id' => $task->id, + 'type' => "Task", + 'direction' => '', + 'module' => "Tasks", + 'status' => $task->status, + 'parent_id' => $task->parent_id, + 'parent_type' => $task->parent_type, + 'parent_name' => $task->parent_name, + 'contact_id' => $task->contact_id, + 'contact_name' => $task->contact_name, + 'date_due' => $date_due, + 'description' => $this->getTaskDetails($task), + 'date_type' => $app_strings['DATA_TYPE_DUE'] + ); + } + } // end Tasks + + foreach ($focus_meetings_list as $meeting) { + + if (empty($meeting->contact_id) && empty($meeting->contact_name)) { + $meeting_contacts = $meeting->get_linked_beans('contacts','Contact'); + if (!empty($meeting_contacts[0]->id) && !empty($meeting_contacts[0]->name)) { + $meeting->contact_id = $meeting_contacts[0]->id; + $meeting->contact_name = $meeting_contacts[0]->name; + } + } + if ($meeting->status != "Planned") { + $history_list[] = array('name' => $meeting->name, + 'id' => $meeting->id, + 'type' => "Meeting", + 'direction' => '', + 'module' => "Meetings", + 'status' => $meeting->status, + 'parent_id' => $meeting->parent_id, + 'parent_type' => $meeting->parent_type, + 'parent_name' => $meeting->parent_name, + 'contact_id' => $meeting->contact_id, + 'contact_name' => $meeting->contact_name, + 'date_modified' => $meeting->date_start, + 'description' => $this->formatDescription($meeting->description), + 'date_type' => $app_strings['DATA_TYPE_START'], + 'sort_value' => strtotime($meeting->fetched_row['date_start'].' GMT'), + ); + } else { + $open_activity_list[] = array('name' => $meeting->name, + 'id' => $meeting->id, + 'type' => "Meeting", + 'direction' => '', + 'module' => "Meetings", + 'status' => $meeting->status, + 'parent_id' => $meeting->parent_id, + 'parent_type' => $meeting->parent_type, + 'parent_name' => $meeting->parent_name, + 'contact_id' => $meeting->contact_id, + 'contact_name' => $meeting->contact_name, + 'date_due' => $meeting->date_start, + 'description' => $this->formatDescription($meeting->description), + 'date_type' => $app_strings['DATA_TYPE_START'] + ); + } + } // end Meetings + + foreach ($focus_calls_list as $call) { + + if (empty($call->contact_id) && empty($call->contact_name)) { + $call_contacts = $call->get_linked_beans('contacts','Contact'); + if (!empty($call_contacts[0]->id) && !empty($call_contacts[0]->name)) { + $call->contact_id = $call_contacts[0]->id; + $call->contact_name = $call_contacts[0]->name; + } + } + + if ($call->status != "Planned") { + $history_list[] = array('name' => $call->name, + 'id' => $call->id, + 'type' => "Call", + 'direction' => $call->direction, + 'module' => "Calls", + 'status' => $call->status, + 'parent_id' => $call->parent_id, + 'parent_type' => $call->parent_type, + 'parent_name' => $call->parent_name, + 'contact_id' => $call->contact_id, + 'contact_name' => $call->contact_name, + 'date_modified' => $call->date_start, + 'description' => $this->formatDescription($call->description), + 'date_type' => $app_strings['DATA_TYPE_START'], + 'sort_value' => strtotime($call->fetched_row['date_start'].' GMT'), + ); + } else { + $open_activity_list[] = array('name' => $call->name, + 'id' => $call->id, + 'direction' => $call->direction, + 'type' => "Call", + 'module' => "Calls", + 'status' => $call->status, + 'parent_id' => $call->parent_id, + 'parent_type' => $call->parent_type, + 'parent_name' => $call->parent_name, + 'contact_id' => $call->contact_id, + 'contact_name' => $call->contact_name, + 'date_due' => $call->date_start, + 'description' => $this->formatDescription($call->description), + 'date_type' => $app_strings['DATA_TYPE_START'] + ); + } + } // end Calls + + foreach ($focus_emails_list as $email) { + + if (empty($email->contact_id) && empty($email->contact_name)) { + $email_contacts = $email->get_linked_beans('contacts','Contact'); + if (!empty($email_contacts[0]->id) && !empty($email_contacts[0]->name)) { + $email->contact_id = $email_contacts[0]->id; + $email->contact_name = $email_contacts[0]->name; + } + } + $history_list[] = array('name' => $email->name, + 'id' => $email->id, + 'type' => "Email", + 'direction' => '', + 'module' => "Emails", + 'status' => '', + 'parent_id' => $email->parent_id, + 'parent_type' => $email->parent_type, + 'parent_name' => $email->parent_name, + 'contact_id' => $email->contact_id, + 'contact_name' => $email->contact_name, + 'date_modified' => $email->date_start." ".$email->time_start, + 'description' => $this->getEmailDetails($email), + 'date_type' => $app_strings['DATA_TYPE_SENT'], + 'sort_value' => strtotime($email->fetched_row['date_sent'].' GMT'), + ); + } //end Emails + + foreach ($focus_notes_list as $note) { + + $history_list[] = array('name' => $note->name, + 'id' => $note->id, + 'type' => "Note", + 'direction' => '', + 'module' => "Notes", + 'status' => '', + 'parent_id' => $note->parent_id, + 'parent_type' => $note->parent_type, + 'parent_name' => $note->parent_name, + 'contact_id' => $note->contact_id, + 'contact_name' => $note->contact_name, + 'date_modified' => $note->date_modified, + 'description' => $this->formatDescription($note->description), + 'date_type' => $app_strings['DATA_TYPE_MODIFIED'], + 'sort_value' => strtotime($note->fetched_row['date_modified'].' GMT'), + ); + if(!empty($note->filename)) { + $count = count($history_list); + $count--; + $history_list[$count]['filename'] = $note->filename; + $history_list[$count]['fileurl'] = UploadFile::get_url($note->filename,$note->id); + } + } // end Notes + + $xtpl=new XTemplate ('modules/Activities/Popup_picker.html'); + + $xtpl->assign('MOD', $mod_strings); + $xtpl->assign('APP', $app_strings); + insert_popup_header(); + + //output header + echo "
    "; + echo getClassicModuleTitle($focus->module_dir, array(translate('LBL_MODULE_NAME', $focus->module_dir),$focus->name), false); + echo ""; + echo "".$app_strings[ ".$app_strings['LNK_PRINT']."\n"; + echo "
    "; + + $oddRow = true; + if (count($history_list) > 0) $history_list = array_csort($history_list, 'sort_value', SORT_DESC); + foreach($history_list as $activity) + { + $activity_fields = array( + 'ID' => $activity['id'], + 'NAME' => $activity['name'], + 'MODULE' => $activity['module'], + 'CONTACT_NAME' => $activity['contact_name'], + 'CONTACT_ID' => $activity['contact_id'], + 'PARENT_TYPE' => $activity['parent_type'], + 'PARENT_NAME' => $activity['parent_name'], + 'PARENT_ID' => $activity['parent_id'], + 'DATE' => $activity['date_modified'], + 'DESCRIPTION' => $activity['description'], + 'DATE_TYPE' => $activity['date_type'] + ); + if (empty($activity['direction'])) { + $activity_fields['TYPE'] = $app_list_strings['activity_dom'][$activity['type']]; + } + else { + $activity_fields['TYPE'] = $app_list_strings['call_direction_dom'][$activity['direction']].' '.$app_list_strings['activity_dom'][$activity['type']]; + } + + switch ($activity['type']) { + case 'Call': + $activity_fields['STATUS'] = $app_list_strings['call_status_dom'][$activity['status']]; + break; + case 'Meeting': + $activity_fields['STATUS'] = $app_list_strings['meeting_status_dom'][$activity['status']]; + break; + case 'Task': + $activity_fields['STATUS'] = $app_list_strings['task_status_dom'][$activity['status']]; + break; + } + + if (isset($activity['location'])) $activity_fields['LOCATION'] = $activity['location']; + if (isset($activity['filename'])) { + $activity_fields['ATTACHMENT'] = "".SugarThemeRegistry::current()->getImage("attachment","alt='".$activity['filename']."' border='0' align='absmiddle'").""; + } + + if (isset($activity['parent_type'])) $activity_fields['PARENT_MODULE'] = $activity['parent_type']; + + $xtpl->assign("ACTIVITY", $activity_fields); + $xtpl->assign("ACTIVITY_MODULE_PNG", SugarThemeRegistry::current()->getImage($activity_fields['MODULE'].'','border="0" alt="'.$activity_fields['NAME'].'"')); + + if($oddRow) + { + //todo move to themes + $xtpl->assign("ROW_COLOR", 'oddListRow'); + $xtpl->assign("BG_COLOR", $odd_bg); + } + else + { + //todo move to themes + $xtpl->assign("ROW_COLOR", 'evenListRow'); + $xtpl->assign("BG_COLOR", $even_bg); + } + $oddRow = !$oddRow; + if(!empty($activity_fields['DESCRIPTION'])) { + $xtpl->parse("history.row.description"); + } + $xtpl->parse("history.row"); + // Put the rows in. +} + $xtpl->parse("history"); + $xtpl->out("history"); + insert_popup_footer(); + } + + function getEmailDetails($email){ + $details = ""; + + if(!empty($email->to_addrs)){ + $details .= "To: ".$email->to_addrs."
    "; + } + if(!empty($email->from_addr)){ + $details .= "From: ".$email->from_addr."
    "; + } + if(!empty($email->cc_addrs)){ + $details .= "CC: ".$email->cc_addrs."
    "; + } + if(!empty($email->from_addr) || !empty($email->cc_addrs) || !empty($email->to_addrs)){ + $details .= "
    "; + } + + // cn: bug 8433 - history does not distinguish b/t text/html emails + $details .= empty($email->description_html) + ? $this->formatDescription($email->description) + : $this->formatDescription(strip_tags(br2nl(from_html($email->description_html)))); + + return $details; + } + + function getTaskDetails($task){ + global $app_strings; + + $details = ""; + if (!empty($task->date_start) && $task->date_start != '0000-00-00') { + $details .= $app_strings['DATA_TYPE_START'].$task->date_start."
    "; + $details .= "
    "; + } + $details .= $this->formatDescription($task->description); + + return $details; + } + + function formatDescription($description){ + return nl2br($description); + } +} // end of class Popup_Picker +?> \ No newline at end of file diff --git a/modules/Activities/SetAcceptStatus.php b/modules/Activities/SetAcceptStatus.php new file mode 100644 index 00000000..3e3d0efc --- /dev/null +++ b/modules/Activities/SetAcceptStatus.php @@ -0,0 +1,59 @@ +id = $_REQUEST['object_id']; + $test = $focus->set_accept_status($current_user, $_REQUEST['accept_status']); + } + else if ($_REQUEST['object_type'] == "Call") + { + $focus = new Call(); + $focus->id = $_REQUEST['object_id']; + $test = $focus->set_accept_status($current_user, $_REQUEST['accept_status']); + } + print 1; + exit; +?> diff --git a/modules/Activities/SubPanelView.html b/modules/Activities/SubPanelView.html new file mode 100644 index 00000000..94ef06e8 --- /dev/null +++ b/modules/Activities/SubPanelView.html @@ -0,0 +1,94 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    {MOD.LBL_LIST_CLOSE}{MOD.LBL_LIST_SUBJECT}{MOD.LBL_LIST_STATUS}{MOD.LBL_LIST_CONTACT}{MOD.LBL_LIST_RELATED_TO}{MOD.LBL_LIST_DUE_DATE}
    {ACTIVITY_MODULE_PNG}{ACTIVITY.SET_COMPLETE}{ACTIVITY.NAME}{ACTIVITY.TYPE} {ACTIVITY.STATUS}{ACTIVITY.CONTACT_NAME}{ACTIVITY.PARENT_NAME}{ACTIVITY.DATE}{EDIT_INLINE_PNG} {APP.LNK_EDIT}  {DELETE_INLINE_PNG} {APP.LNK_DELETE}
    + + + + + + + + + + + + + + + + + + +
    + + {MOD.LBL_LIST_SUBJECT} + {MOD.LBL_LIST_STATUS} + {MOD.LBL_LIST_CONTACT} + {MOD.LBL_LIST_RELATED_TO} + {MOD.LBL_LIST_LAST_MODIFIED} + +
    {ACTIVITY_MODULE_PNG}{ACTIVITY.NAME} {ACTIVITY.ATTACHMENT}{ACTIVITY.TYPE} {ACTIVITY.STATUS}{ACTIVITY.CONTACT_NAME}{ACTIVITY.PARENT_NAME}{ACTIVITY.DATE}{EDIT_INLINE_PNG} {APP.LNK_EDIT}  {DELETE_INLINE_PNG} {APP.LNK_DELETE}
    + diff --git a/modules/Activities/SubPanelView.php b/modules/Activities/SubPanelView.php new file mode 100644 index 00000000..44b38cc4 --- /dev/null +++ b/modules/Activities/SubPanelView.php @@ -0,0 +1,456 @@ +status != "Not Started" && $task->status != "In Progress" && $task->status != "Pending Input") { + $history_list[] = Array('name' => $task->name, + 'id' => $task->id, + 'type' => "Task", + 'direction' => '', + 'module' => "Tasks", + 'status' => $task->status, + 'parent_id' => $task->parent_id, + 'parent_type' => $task->parent_type, + 'parent_name' => $task->parent_name, + 'contact_id' => $task->contact_id, + 'contact_name' => $task->contact_name, + 'date_modified' => $timedate->to_display_date($task->date_modified, true), + ); + } + else { + if ($task->date_due == '0000-00-00') $date_due = ''; + else { + $date_due = $task->date_due; + + } + $open_activity_list[] = Array('name' => $task->name, + 'id' => $task->id, + 'type' => "Task", + 'direction' => '', + 'module' => "Tasks", + 'status' => $task->status, + 'parent_id' => $task->parent_id, + 'parent_type' => $task->parent_type, + 'parent_name' => $task->parent_name, + 'contact_id' => $task->contact_id, + 'contact_name' => $task->contact_name, + 'date_due' => $date_due + ); + } +} + +foreach ($focus_meetings_list as $meeting) { + if ($meeting->status != "Planned") { + $history_list[] = Array('name' => $meeting->name, + 'id' => $meeting->id, + 'type' => "Meeting", + 'direction' => '', + 'module' => "Meetings", + 'status' => $meeting->status, + 'parent_id' => $meeting->parent_id, + 'parent_type' => $meeting->parent_type, + 'parent_name' => $meeting->parent_name, + 'contact_id' => $meeting->contact_id, + 'contact_name' => $meeting->contact_name, + 'date_modified' => $meeting->date_modified + ); + } + else { + $open_activity_list[] = Array('name' => $meeting->name, + 'id' => $meeting->id, + 'type' => "Meeting", + 'direction' => '', + 'module' => "Meetings", + 'status' => $meeting->status, + 'parent_id' => $meeting->parent_id, + 'parent_type' => $meeting->parent_type, + 'parent_name' => $meeting->parent_name, + 'contact_id' => $meeting->contact_id, + 'contact_name' => $meeting->contact_name, + 'date_due' => $meeting->date_start + ); + } +} + +foreach ($focus_calls_list as $call) { + if ($call->status != "Planned") { + $history_list[] = Array('name' => $call->name, + 'id' => $call->id, + 'type' => "Call", + 'direction' => $call->direction, + 'module' => "Calls", + 'status' => $call->status, + 'parent_id' => $call->parent_id, + 'parent_type' => $call->parent_type, + 'parent_name' => $call->parent_name, + 'contact_id' => $call->contact_id, + 'contact_name' => $call->contact_name, + 'date_modified' => $call->date_modified + ); + } + else { + $open_activity_list[] = Array('name' => $call->name, + 'id' => $call->id, + 'direction' => $call->direction, + 'type' => "Call", + 'module' => "Calls", + 'status' => $call->status, + 'parent_id' => $call->parent_id, + 'parent_type' => $call->parent_type, + 'parent_name' => $call->parent_name, + 'contact_id' => $call->contact_id, + 'contact_name' => $call->contact_name, + 'date_due' => $call->date_start + ); + } +} + +foreach ($focus_emails_list as $email) { + $history_list[] = Array('name' => $email->name, + 'id' => $email->id, + 'type' => "Email", + 'direction' => '', + 'module' => "Emails", + 'status' => '', + 'parent_id' => $email->parent_id, + 'parent_type' => $email->parent_type, + 'parent_name' => $email->parent_name, + 'contact_id' => $email->contact_id, + 'contact_name' => $email->contact_name, + 'date_modified' => $email->date_start." ".$email->time_start + ); +} + +foreach ($focus_notes_list as $note) { + $history_list[] = Array('name' => $note->name, + 'id' => $note->id, + 'type' => "Note", + 'direction' => '', + 'module' => "Notes", + 'status' => '', + 'parent_id' => $note->parent_id, + 'parent_type' => $note->parent_type, + 'parent_name' => $note->parent_name, + 'contact_id' => $note->contact_id, + 'contact_name' => $note->contact_name, + 'date_modified' => $note->date_modified + ); + if (!empty($note->filename)) + { + $count = count($history_list); + $count--; + $history_list[$count]['filename'] = $note->filename; + $history_list[$count]['fileurl'] = UploadFile::get_url($note->filename,$note->id); + } + +} + +if ($currentModule == 'Contacts') +{ + $xtpl=new XTemplate ('modules/Activities/SubPanelViewContacts.html'); + $xtpl->assign("CONTACT_ID", $focus->id); +} +else +{ + $xtpl=new XTemplate ('modules/Activities/SubPanelView.html'); +} + +$xtpl->assign("DELETE_INLINE_PNG", SugarThemeRegistry::current()->getImage('delete_inline','align="absmiddle" alt="'.$app_strings['LNK_DELETE'].'" border="0"')); +$xtpl->assign("EDIT_INLINE_PNG", SugarThemeRegistry::current()->getImage('edit_inline','align="absmiddle" alt="'.$app_strings['LNK_EDIT'].'" border="0"')); + +$xtpl->assign("MOD", $current_module_strings); +$xtpl->assign("APP", $app_strings); + +$button = "
    \n"; +$button .= "\n"; +$button .= "\n"; +if ($currentModule == 'Accounts') +{ + $button .= "\n\n\n"; +} +elseif ($currentModule == 'Opportunities') +{ + $button .= "\n\n\n"; +} +elseif ($currentModule == 'Cases') +{ + $button .= "\n\n\n"; +} +elseif ($currentModule == 'Contacts') +{ + $button .= "\n\n"; + $button .= "\n\n\n"; + $button .= "\n"; +} +else +{ + $button .= "\n\n\n"; +} + +$button .= "\n"; +$button .= "\n"; +$button .= "\n"; +$button .= "\n"; +$button .= "\n"; + +if($currentModule != 'Project' && $currentModule != 'ProjectTask') +{ + $button .= "\n"; +} + +$button .= "\n"; + +$button .= "\n"; + +$button .= "\n"; + +$button .= "
    \n"; + +// Stick the form header out there. +echo get_form_header($current_module_strings['LBL_OPEN_ACTIVITIES'], $button, false); + +$xtpl->assign("RETURN_URL", "&return_module=$currentModule&return_action=DetailView&return_id=$focus->id"); + +$oddRow = true; +if (count($open_activity_list) > 0) $open_activity_list = array_csort($open_activity_list, 'date_due', SORT_DESC); +foreach($open_activity_list as $activity) +{ + $activity_fields = array( + 'ID' => $activity['id'], + 'NAME' => $activity['name'], + 'MODULE' => $activity['module'], + 'CONTACT_NAME' => $activity['contact_name'], + 'CONTACT_ID' => $activity['contact_id'], + 'PARENT_TYPE' => $activity['parent_type'], + 'PARENT_NAME' => $activity['parent_name'], + 'PARENT_ID' => $activity['parent_id'], + 'DATE' => $activity['date_due'] + ); + + if (empty($activity['direction'])) { + $activity_fields['TYPE'] = $app_list_strings['activity_dom'][$activity['type']]; + } + else { + $activity_fields['TYPE'] = $app_list_strings['call_direction_dom'][$activity['direction']].' '.$app_list_strings['activity_dom'][$activity['type']]; + } + if (isset($activity['parent_type'])) $activity_fields['PARENT_MODULE'] = $activity['parent_type']; + switch ($activity['type']) { + case 'Call': + $activity_fields['SET_COMPLETE'] = "".SugarThemeRegistry::current()->getImage("close_inline","title=".translate('LBL_LIST_CLOSE','Activities')." border='0'").""; + $activity_fields['STATUS'] = $app_list_strings['call_status_dom'][$activity['status']]; + break; + case 'Meeting': + $activity_fields['SET_COMPLETE'] = "".SugarThemeRegistry::current()->getImage("close_inline","title=".translate('LBL_LIST_CLOSE','Activities')." border='0'").""; + $activity_fields['STATUS'] = $app_list_strings['meeting_status_dom'][$activity['status']]; + break; + case 'Task': + $activity_fields['SET_COMPLETE'] = "".SugarThemeRegistry::current()->getImage("close_inline","title=".translate('LBL_LIST_CLOSE','Activities')." border='0'").""; + $activity_fields['STATUS'] = $app_list_strings['task_status_dom'][$activity['status']]; + break; + } + + global $odd_bg; + global $even_bg; + global $hilite_bg; + global $click_bg; +$xtpl->assign("BG_HILITE", $hilite_bg); +$xtpl->assign("BG_CLICK", $click_bg); +$xtpl->assign("ACTIVITY_MODULE_PNG", SugarThemeRegistry::current()->getImage($activity_fields['MODULE'].'','border="0" alt="'.$activity_fields['NAME'].'"')); + $xtpl->assign("ACTIVITY", $activity_fields); + + if($oddRow) + { + //todo move to themes + $xtpl->assign("ROW_COLOR", 'oddListRow'); + $xtpl->assign("BG_COLOR", $odd_bg); + } + else + { + //todo move to themes + $xtpl->assign("ROW_COLOR", 'evenListRow'); + $xtpl->assign("BG_COLOR", $even_bg); + } + $oddRow = !$oddRow; + + $xtpl->parse("open_activity.row"); +// Put the rows in. +} + +$xtpl->parse("open_activity"); +$xtpl->out("open_activity"); +echo "
    "; + + +//requestdata +$popup_request_data = array( + 'call_back_function' => 'set_return', + 'form_name' => 'EditView', + 'field_to_name_array' => array(), + ); + +$json = getJSONobj(); +$encoded_popup_request_data = $json->encode($popup_request_data); + +$button = "
    \n"; +$button .= "\n"; +$button .= "\n"; +if ($currentModule == 'Accounts') $button .= "\n\n\n"; +if ($currentModule == 'Opportunities') $button .= "\n\n\n"; +elseif ($currentModule == 'Cases') $button .= "\n\n\n"; +elseif ($currentModule == 'Contacts') { + $button .= "\n\n"; + $button .= "\n"; + $button .= "\n\n\n"; +}else{ + $button .= "\n\n\n"; +} +$button .= "\n"; +$button .= "\n"; +$button .= "\n"; +$button .= "\n"; +$button .= "\n"; +$button .= "\n"; +$button .= "\n"; +$button .= "
    \n"; + +// Stick the form header out there. +echo get_form_header($current_module_strings['LBL_HISTORY'], $button, false); + +$xtpl->assign("RETURN_URL", "&return_module=$currentModule&return_action=DetailView&return_id=$focus->id"); + +$oddRow = true; +if (count($history_list) > 0) $history_list = array_csort($history_list, 'date_modified', SORT_DESC); +foreach($history_list as $activity) +{ + $activity_fields = array( + 'ID' => $activity['id'], + 'NAME' => $activity['name'], + 'MODULE' => $activity['module'], + 'CONTACT_NAME' => $activity['contact_name'], + 'CONTACT_ID' => $activity['contact_id'], + 'PARENT_TYPE' => $activity['parent_type'], + 'PARENT_NAME' => $activity['parent_name'], + 'PARENT_ID' => $activity['parent_id'], + 'DATE' => $activity['date_modified'], + ); + if (empty($activity['direction'])) { + $activity_fields['TYPE'] = $app_list_strings['activity_dom'][$activity['type']]; + } + else { + $activity_fields['TYPE'] = $app_list_strings['call_direction_dom'][$activity['direction']].' '.$app_list_strings['activity_dom'][$activity['type']]; + } + + switch ($activity['type']) { + case 'Call': + $activity_fields['STATUS'] = $app_list_strings['call_status_dom'][$activity['status']]; + break; + case 'Meeting': + $activity_fields['STATUS'] = $app_list_strings['meeting_status_dom'][$activity['status']]; + break; + case 'Task': + $activity_fields['STATUS'] = $app_list_strings['task_status_dom'][$activity['status']]; + break; + } + + if (isset($activity['location'])) $activity_fields['LOCATION'] = $activity['location']; + if (isset($activity['filename'])) { + $activity_fields['ATTACHMENT'] = "".SugarThemeRegistry::current()->getImage("attachment","alt='".$activity['filename']."' border='0' align='absmiddle'").""; + } + + if (isset($activity['parent_type'])) $activity_fields['PARENT_MODULE'] = $activity['parent_type']; + + $xtpl->assign("ACTIVITY", $activity_fields); + $xtpl->assign("ACTIVITY_MODULE_PNG", SugarThemeRegistry::current()->getImage($activity_fields['MODULE'].'','border="0" alt="'.$activity_fields['NAME'].'"')); + + if($oddRow) + { + //todo move to themes + $xtpl->assign("ROW_COLOR", 'oddListRow'); + $xtpl->assign("BG_COLOR", $odd_bg); + } + else + { + //todo move to themes + $xtpl->assign("ROW_COLOR", 'evenListRow'); + $xtpl->assign("BG_COLOR", $even_bg); + } + $oddRow = !$oddRow; + + $xtpl->parse("history.row"); +// Put the rows in. +} + +$xtpl->parse("history"); +$xtpl->out("history"); + +?> diff --git a/modules/Activities/SubPanelViewContacts.html b/modules/Activities/SubPanelViewContacts.html new file mode 100644 index 00000000..6614b5c5 --- /dev/null +++ b/modules/Activities/SubPanelViewContacts.html @@ -0,0 +1,101 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
     {MOD.LBL_LIST_CLOSE}{MOD.LBL_LIST_SUBJECT}{MOD.LBL_LIST_STATUS}{MOD.LBL_LIST_RELATED_TO}{MOD.LBL_LIST_DUE_DATE} 
    {ACTIVITY_MODULE_PNG}{ACTIVITY.SET_COMPLETE}{ACTIVITY.NAME}{ACTIVITY.TYPE} {ACTIVITY.STATUS}{ACTIVITY.PARENT_NAME}{ACTIVITY.DATE}{EDIT_INLINE_PNG} {APP.LNK_EDIT}  {DELETE_INLINE_PNG} {APP.LNK_DELETE}
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
     {MOD.LBL_LIST_SUBJECT}{MOD.LBL_LIST_STATUS}{MOD.LBL_LIST_RELATED_TO}{MOD.LBL_LIST_LAST_MODIFIED} 
    {ACTIVITY_MODULE_PNG}{ACTIVITY.NAME} {ACTIVITY.ATTACHMENT}{ACTIVITY.TYPE} {ACTIVITY.STATUS}{ACTIVITY.PARENT_NAME}{ACTIVITY.DATE}{EDIT_INLINE_PNG} {APP.LNK_EDIT}  {DELETE_INLINE_PNG} {APP.LNK_DELETE}
    + diff --git a/modules/Activities/config.php b/modules/Activities/config.php new file mode 100644 index 00000000..51ef17fc --- /dev/null +++ b/modules/Activities/config.php @@ -0,0 +1,46 @@ + diff --git a/modules/Activities/language/en_us.lang.php b/modules/Activities/language/en_us.lang.php new file mode 100644 index 00000000..d60eb42f --- /dev/null +++ b/modules/Activities/language/en_us.lang.php @@ -0,0 +1,130 @@ + 'Activities', + 'LBL_MODULE_TITLE' => 'Activities: Home', + 'LBL_SEARCH_FORM_TITLE' => 'Activities Search', + 'LBL_LIST_FORM_TITLE' => 'Activities List', + 'LBL_LIST_SUBJECT' => 'Subject', + 'LBL_LIST_CONTACT' => 'Contact', + 'LBL_LIST_RELATED_TO' => 'Related to', + 'LBL_LIST_DATE' => 'Date', + 'LBL_LIST_TIME' => 'Start Time', + 'LBL_LIST_CLOSE' => 'Close', + 'LBL_SUBJECT' => 'Subject:', + 'LBL_STATUS' => 'Status:', + 'LBL_LOCATION' => 'Location:', + 'LBL_DATE_TIME' => 'Start Date & Time:', + 'LBL_DATE' => 'Start Date:', + 'LBL_TIME' => 'Start Time:', + 'LBL_DURATION' => 'Duration:', + 'LBL_DURATION_MINUTES' => 'Duration Minutes:', + 'LBL_HOURS_MINS' => '(hours/minutes)', + 'LBL_CONTACT_NAME' => 'Contact Name: ', + 'LBL_MEETING' => 'Meeting:', + 'LBL_DESCRIPTION_INFORMATION' => 'Description Information', + 'LBL_DESCRIPTION' => 'Description:', + 'LBL_COLON' => ':', + 'LNK_NEW_CALL' => 'Log Call', + 'LNK_NEW_MEETING' => 'Schedule Meeting', + 'LNK_NEW_TASK' => 'Create Task', + 'LNK_NEW_NOTE' => 'Create Note or Add Attachment', + 'LNK_NEW_EMAIL' => 'Create Archived Email', + 'LNK_CALL_LIST' => 'View Calls', + 'LNK_MEETING_LIST' => 'View Meetings', + 'LNK_TASK_LIST' => 'View Tasks', + 'LNK_NOTE_LIST' => 'View Notes', + 'LNK_EMAIL_LIST' => 'View Emails', + 'ERR_DELETE_RECORD' => 'You must specify a record number to delete the account.', + 'NTC_REMOVE_INVITEE' => 'Are you sure you want to remove this invitee from the meeting?', + 'LBL_INVITEE' => 'Invitees', + 'LBL_LIST_DIRECTION' => 'Direction', + 'LBL_DIRECTION' => 'Direction', + 'LNK_NEW_APPOINTMENT' => 'New Appointment', + 'LNK_VIEW_CALENDAR' => 'View Calendar', + 'LBL_OPEN_ACTIVITIES' => 'Open Activities', + 'LBL_HISTORY' => 'History', + 'LBL_UPCOMING' => 'My Upcoming Appointments', + 'LBL_TODAY' => 'through ', + 'LBL_NEW_TASK_BUTTON_TITLE' => 'Create Task [Alt+N]', + 'LBL_NEW_TASK_BUTTON_KEY' => 'N', + 'LBL_NEW_TASK_BUTTON_LABEL' => 'Create Task', + 'LBL_SCHEDULE_MEETING_BUTTON_TITLE' => 'Schedule Meeting [Alt+M]', + 'LBL_SCHEDULE_MEETING_BUTTON_KEY' => 'M', + 'LBL_SCHEDULE_MEETING_BUTTON_LABEL' => 'Schedule Meeting', + 'LBL_SCHEDULE_CALL_BUTTON_TITLE' => 'Log Call [Alt+C]', + 'LBL_SCHEDULE_CALL_BUTTON_KEY' => 'C', + 'LBL_SCHEDULE_CALL_BUTTON_LABEL' => 'Log Call', + 'LBL_NEW_NOTE_BUTTON_TITLE' => 'Create Note or Attachment [Alt+T]', + 'LBL_NEW_NOTE_BUTTON_KEY' => 'T', + 'LBL_NEW_NOTE_BUTTON_LABEL' => 'Create Note or Attachment', + 'LBL_TRACK_EMAIL_BUTTON_TITLE' => 'Archive Email [Alt+K]', + 'LBL_TRACK_EMAIL_BUTTON_KEY' => 'K', + 'LBL_TRACK_EMAIL_BUTTON_LABEL' => 'Archive Email', + 'LBL_LIST_STATUS' => 'Status', + 'LBL_LIST_DUE_DATE' => 'Due Date', + 'LBL_LIST_LAST_MODIFIED' => 'Last Modified', + 'NTC_NONE_SCHEDULED' => 'None scheduled.', + 'appointment_filter_dom' => array( + 'today' => 'today' + ,'tomorrow' => 'tomorrow' + ,'this Saturday' => 'this week' + ,'next Saturday' => 'next week' + ,'last this_month' => 'this month' + ,'last next_month' => 'next month' + ), + 'LNK_IMPORT_CALLS'=>'Import Calls', + 'LNK_IMPORT_MEETINGS'=>'Import Meetings', + 'LNK_IMPORT_TASKS'=>'Import Tasks', + 'LNK_IMPORT_NOTES'=>'Import Notes', + 'NTC_NONE'=>'None', + 'LBL_ACCEPT_THIS'=>'Accept?', + 'LBL_DEFAULT_SUBPANEL_TITLE' => 'Open Activities', + 'LBL_LIST_ASSIGNED_TO_NAME' => 'Assigned User', +); + + +?> diff --git a/modules/Activities/metadata/subpaneldefs.php b/modules/Activities/metadata/subpaneldefs.php new file mode 100644 index 00000000..22b20cb5 --- /dev/null +++ b/modules/Activities/metadata/subpaneldefs.php @@ -0,0 +1,252 @@ + array( + 'subpanel_title' => 'LBL_DEFAULT_SUBPANEL_TITLE', + 'top_buttons' => array( + array('widget_class' => 'SubPanelTopCreateTaskButton'), + array('widget_class' => 'SubPanelTopScheduleMeetingButton'), + array('widget_class' => 'SubPanelTopScheduleCallButton'), + array('widget_class' => 'SubPanelTopComposeEmailButton'), + ), + 'list_fields' => array( + 'Meetings' => array( + 'columns' => array( + array( +//TODO remove name=nothing and make it safe +//TODO update layout editor to match new file structure + + 'name' => 'nothing', + 'widget_class' => 'SubPanelIcon', + 'module' => 'Meetings', + 'width' => '2%', + ), + array( + 'name' => 'nothing', + 'widget_class' => 'SubPanelCloseButton', + 'module' => 'Meetings', + 'vname' => 'LBL_LIST_CLOSE', + 'width' => '6%', + ), + array( + 'name' => 'name', + 'vname' => 'LBL_LIST_SUBJECT', + 'widget_class' => 'SubPanelDetailViewLink', + 'width' => '30%', + ), + array( + 'name' => 'status', + 'widget_class' => 'SubPanelActivitiesStatusField', + 'vname' => 'LBL_LIST_STATUS', + 'width' => '15%', + ), + array( + 'name' => 'contact_name', + 'module' => 'Contacts', + 'widget_class' => 'SubPanelDetailViewLink', + 'target_record_key' => 'contact_id', + 'target_module' => 'Contacts', + 'vname' => 'LBL_LIST_CONTACT', + 'width' => '11%', + ), + array( + 'name' => 'parent_name', + 'module' => 'Meetings', + 'vname' => 'LBL_LIST_RELATED_TO', + 'width' => '22%', + ), + array( + 'name' => 'date_start', + //'db_alias_to' => 'the_date', + 'vname' => 'LBL_LIST_DUE_DATE', + 'width' => '10%', + ), + array( + 'name' => 'nothing', + 'widget_class' => 'SubPanelEditButton', + 'module' => 'Meetings', + 'width' => '2%', + ), + array( + 'name' => 'nothing', + 'widget_class' => 'SubPanelRemoveButton', + 'linked_field' => 'meetings', + 'module' => 'Meetings', + 'width' => '2%', + ), + ), + 'where' => "(meetings.status='Planned')", + 'order_by' => 'meetings.date_start', + ), + 'Tasks' => array( + 'columns' => array( + array( + 'name' => 'nothing', + 'widget_class' => 'SubPanelIcon', + 'module' => 'Tasks', + 'width' => '2%', + ), + array( + 'name' => 'nothing', + 'widget_class' => 'SubPanelCloseButton', + 'module' => 'Tasks', + 'vname' => 'LBL_LIST_CLOSE', + 'width' => '6%', + ), + array( + 'name' => 'name', + 'vname' => 'LBL_LIST_SUBJECT', + 'widget_class' => 'SubPanelDetailViewLink', + 'width' => '30%', + ), + array( + 'name' => 'status', + 'widget_class' => 'SubPanelActivitiesStatusField', + 'vname' => 'LBL_LIST_STATUS', + 'width' => '15%', + ), + array( + 'name' => 'contact_name', + 'module' => 'Contacts', + 'widget_class' => 'SubPanelDetailViewLink', + 'target_record_key' => 'contact_id', + 'target_module' => 'Contacts', + 'vname' => 'LBL_LIST_CONTACT', + 'width' => '11%', + ), + array( + 'name' => 'parent_name', + 'module' => 'Tasks', + 'vname' => 'LBL_LIST_RELATED_TO', + 'width' => '22%', + ), + array( + 'name' => 'date_start', + //'db_alias_to' => 'the_date', + 'vname' => 'LBL_LIST_DUE_DATE', + 'width' => '10%', + ), + array( + 'name' => 'nothing', + 'widget_class' => 'SubPanelEditButton', + 'module' => 'Tasks', + 'width' => '2%', + ), + array( + 'name' => 'nothing', + 'widget_class' => 'SubPanelRemoveButton', + 'linked_field' => 'tasks', + 'module' => 'Tasks', + 'width' => '2%', + ), + ), + 'where' => "(tasks.status='Not Started' OR tasks.status='In Progress' OR tasks.status='Pending Input')", + 'order_by' => 'tasks.date_start', + ), + 'Calls' => array( + 'columns' => array( + array( + 'name' => 'nothing', + 'widget_class' => 'SubPanelIcon', + 'module' => 'Calls', + 'width' => '2%', + ), + array( + 'name' => 'nothing', + 'widget_class' => 'SubPanelCloseButton', + 'module' => 'Calls', + 'vname' => 'LBL_LIST_CLOSE', + 'width' => '6%', + ), + array( + 'name' => 'name', + 'vname' => 'LBL_LIST_SUBJECT', + 'widget_class' => 'SubPanelDetailViewLink', + 'width' => '30%', + ), + array( + 'name' => 'status', + 'widget_class' => 'SubPanelActivitiesStatusField', + 'vname' => 'LBL_LIST_STATUS', + 'width' => '15%', + ), + array( + 'name' => 'contact_name', + 'module' => 'Contacts', + 'widget_class' => 'SubPanelDetailViewLink', + 'target_record_key' => 'contact_id', + 'target_module' => 'Contacts', + 'vname' => 'LBL_LIST_CONTACT', + 'width' => '11%', + ), + array( + 'name' => 'parent_name', + 'module' => 'Calls', + 'vname' => 'LBL_LIST_RELATED_TO', + 'width' => '20%', + ), + array( + 'name' => 'date_start', + //'db_alias_to' => 'the_date', + 'vname'=>'LBL_LIST_DUE_DATE', + 'width' => '22%', + ), + array( + 'name' => 'nothing', + 'widget_class' => 'SubPanelEditButton', + 'module' => 'Calls', + 'width' => '2%', + ), + array( + 'name' => 'nothing', + 'widget_class' => 'SubPanelRemoveButton', + 'linked_field' => 'calls', + 'module' => 'Calls', + 'width' => '2%', + ), + ), + 'where' => "(calls.status='Planned')", + 'order_by' => 'calls.date_start', + ), + ), + ), +); +?> \ No newline at end of file diff --git a/modules/Activities/views/view.list.php b/modules/Activities/views/view.list.php new file mode 100644 index 00000000..d3812f08 --- /dev/null +++ b/modules/Activities/views/view.list.php @@ -0,0 +1,47 @@ +get_recently_viewed($GLOBALS['current_user']->id, array('Calls','Meetings','Tasks','Notes','Emails')); + foreach ( $history as $key => $row ) { + $history[$key]['item_summary_short'] = getTrackerSubstring($row['item_summary']); + $history[$key]['image'] = SugarThemeRegistry::current() + ->getImage($row['module_name'],'border="0" align="absmiddle" alt="'.$row['item_summary'].'"'); + } + $this->ss->assign('LAST_VIEWED',$history); + + $this->ss->display('include/MVC/View/tpls/modulelistmenu.tpl'); + } +} +?> diff --git a/modules/Administration/Administration.php b/modules/Administration/Administration.php new file mode 100644 index 00000000..191bdd3b --- /dev/null +++ b/modules/Administration/Administration.php @@ -0,0 +1,171 @@ +setupCustomFields('Administration'); + } + + function retrieveSettings($category = FALSE, $clean=false) { + // declare a cache for all settings + $settings_cache = sugar_cache_retrieve('admin_settings_cache'); + + if($clean) { + $settings_cache = array(); + } + + // Check for a cache hit + if(!empty($settings_cache)) { + $this->settings = $settings_cache; + return $this; + } + + $query = "SELECT category, name, value FROM {$this->table_name}"; + + $result = $this->db->query($query, true, "Unable to retrieve system settings"); + + if(empty($result)) { + return NULL; + } + + while($row = $this->db->fetchByAssoc($result, -1, true)) { + if($row['category']."_".$row['name'] == 'ldap_admin_password' || $row['category']."_".$row['name'] == 'proxy_password') + $this->settings[$row['category']."_".$row['name']] = $this->decrypt_after_retrieve($row['value']); + else + $this->settings[$row['category']."_".$row['name']] = $row['value']; + } + + // outbound email settings + $oe = new OutboundEmail(); + $oe->getSystemMailerSettings(); + + foreach($oe->field_defs as $def) { + if(strpos($def, "mail_") !== false) + $this->settings[$def] = $oe->$def; + } + + // At this point, we have built a new array that should be cached. + sugar_cache_put('admin_settings_cache',$this->settings); + return $this; + } + + function saveConfig() { + + + // outbound email settings + $oe = new OutboundEmail(); + + foreach($_POST as $key => $val) { + $prefix = $this->get_config_prefix($key); + if(in_array($prefix[0], $this->config_categories)) { + if(is_array($val)){ + $val=implode(",",$val); + } + $this->saveSetting($prefix[0], $prefix[1], $val); + } + if(strpos($key, "mail_") !== false) { + if(in_array($key, $oe->field_defs)) { + $oe->$key = $val; + } + } + } + + //saving outbound email from here is probably redundant, adding a check to make sure + //smtpserver name is set. + if (!empty($oe->mail_smtpserver)) { + $oe->saveSystem(); + } + + $this->retrieveSettings(false, true); + } + + function saveSetting($category, $key, $value) { + $result = $this->db->query("SELECT count(*) AS the_count FROM config WHERE category = '{$category}' AND name = '{$key}'"); + $row = $this->db->fetchByAssoc( $result, -1, true ); + $row_count = $row['the_count']; + + if($category."_".$key == 'ldap_admin_password' || $category."_".$key == 'proxy_password') + $value = $this->encrpyt_before_save($value); + + if( $row_count == 0){ + $result = $this->db->query("INSERT INTO config (value, category, name) VALUES ('$value','$category', '$key')"); + } + else{ + $result = $this->db->query("UPDATE config SET value = '{$value}' WHERE category = '{$category}' AND name = '{$key}'"); + } + sugar_cache_clear('admin_settings_cache'); + return $this->db->getAffectedRowCount(); + } + + function get_config_prefix($str) { + return Array(substr($str, 0, strpos($str, "_")), substr($str, strpos($str, "_")+1)); + } +} +?> diff --git a/modules/Administration/Async.php b/modules/Administration/Async.php new file mode 100644 index 00000000..1ac599ce --- /dev/null +++ b/modules/Administration/Async.php @@ -0,0 +1,153 @@ +table_name}"; + $r = $bean->db->query($q); + $a = $bean->db->fetchByAssoc($r); + + $count += $a['count']; + + // populate to_repair array + $q2 = "SELECT id FROM {$bean->table_name}"; + $r2 = $bean->db->query($q2); + $ids = ''; + while($a2 = $bean->db->fetchByAssoc($r2)) { + $ids[] = $a2['id']; + } + $toRepair[$module] = $ids; + } + } elseif(in_array($target, $moduleList)) { + require_once($beanFiles[$beanList[$target]]); + $bean = new $beanList[$target](); + $q = "SELECT count(*) as count FROM {$bean->table_name}"; + $r = $bean->db->query($q); + $a = $bean->db->fetchByAssoc($r); + + $count += $a['count']; + + // populate to_repair array + $q2 = "SELECT id FROM {$bean->table_name}"; + $r2 = $bean->db->query($q2); + $ids = ''; + while($a2 = $bean->db->fetchByAssoc($r2)) { + $ids[] = $a2['id']; + } + $toRepair[$target] = $ids; + } + + $out = array('count' => $count, 'target' => $target, 'toRepair' => $toRepair); + break; + + case "repairXssExecute": + if(isset($_REQUEST['bean']) && !empty($_REQUEST['bean']) && isset($_REQUEST['id']) && !empty($_REQUEST['id'])) { + include("include/modules.php"); // provide $moduleList + $target = $_REQUEST['bean']; + require_once($beanFiles[$beanList[$target]]); + + $ids = $json->decode(from_html($_REQUEST['id'])); + $count = 0; + foreach($ids as $id) { + if(!empty($id)) { + $bean = new $beanList[$target](); + $bean->retrieve($id); + $bean->new_with_id = false; + $bean->save(); // cleanBean() is called on save() + $count++; + } + } + + $out = array('msg' => "success", 'count' => $count); + } else { + $out = array('msg' => "failure: bean or ID not defined"); + } + break; + //// END REPAIRXSS + /////////////////////////////////////////////////////////////////////////// + + default: + die(); + break; +} + +$ret = $json->encode($out, true); +echo $ret; diff --git a/modules/Administration/Common.php b/modules/Administration/Common.php new file mode 100644 index 00000000..bcf72740 --- /dev/null +++ b/modules/Administration/Common.php @@ -0,0 +1,707 @@ +","\n\$mod_strings['{$key}'] = '$value';\n?>", $old_contents); + + + } + else + { + $contents = ""; + } + + return $contents; +} + +/** + * @return string& + * @param the_array array, language string + * @desc Returns the contents of the customized language pack. + */ +function &create_dropdown_lang_pak_contents(&$the_array, $language) +{ + $contents = ""; + + return $contents; +} + +/** + * @return bool + * @param module string, key string, value string + * @desc Wrapper function that will create a field label for every language. + */ +function create_field_label_all_lang($module, $key, $value, $overwrite = false) +{ + $languages = get_languages(); + $return_value = false; + + foreach($languages as $lang_key => $lang_value) + { + $return_value = create_field_label($module, $lang_key, $key, $value, $overwrite); + if(!$return_value) + { + break; + } + } + + return $return_value; +} + +/** + * @return bool + * @param module string, language string, key string, value string + * @desc Returns true if new field label can be created, false otherwise. + * Probable reason for returning false: new_field_key already exists. + */ +function create_field_label($module, $language, $key, $value, $overwrite=false) +{ + $return_value = false; + $mod_strings = return_module_language($language, $module); + + if(isset($mod_strings[$key]) && !$overwrite) + { + $GLOBALS['log']->info("Tried to create a key that already exists: $key"); + } + else + { + $mod_strings = array_merge($mod_strings, array($key => $value)); + $dirname = "custom/modules/$module/language"; + $dir_exists = is_dir($dirname); + + if(!$dir_exists) + { + + $dir_exists = create_module_lang_dir($module); + } + + if($dir_exists) + { + $filename = "$dirname/$language.lang.php"; + if(is_file($filename) && filesize($filename) > 0){ + $old_contents = file_get_contents($filename); + }else{ + $old_contents = ''; + } + $handle = sugar_fopen($filename, 'wb'); + + + if($handle) + { + $contents =create_field_lang_pak_contents($old_contents, $key, + $value, $language, $module); + + if(fwrite($handle, $contents)) + { + $return_value = true; + $GLOBALS['log']->info("Successful write to: $filename"); + } + + fclose($handle); + } + else + { + $GLOBALS['log']->info("Unable to write edited language pak to file: $filename"); + } + } + else + { + $GLOBALS['log']->info("Unable to create dir: $dirname"); + } + } + + return $return_value; +} + +/** + * @return bool + * @param dropdown_name string + * @desc Wrapper function that creates a dropdown type for all languages. + */ +function create_dropdown_type_all_lang($dropdown_name) +{ + $languages = get_languages(); + $return_value = false; + + foreach($languages as $lang_key => $lang_value) + { + $return_value = create_dropdown_type($dropdown_name, $lang_key); + if(!$return_value) + { + break; + } + } + + return $return_value; +} + +/** + * @return bool + * @param app_list_strings array + * @desc Saves the app_list_strings to file in the 'custom' dir. + */ +function save_custom_app_list_strings_contents(&$contents, $language, $custom_dir_name = '') +{ + $return_value = false; + $dirname = 'custom/include/language'; + if(!empty($custom_dir_name)) + $dirname = $custom_dir_name; + + $dir_exists = is_dir($dirname); + + if(!$dir_exists) + { + $dir_exists = create_include_lang_dir($dirname); + } + + if($dir_exists) + { + $filename = "$dirname/$language.lang.php"; + $handle = @sugar_fopen($filename, 'wt'); + + if($handle) + { + if(fwrite($handle, $contents)) + { + $return_value = true; + $GLOBALS['log']->info("Successful write to: $filename"); + } + + fclose($handle); + } + else + { + $GLOBALS['log']->info("Unable to write edited language pak to file: $filename"); + } + } + else + { + $GLOBALS['log']->info("Unable to create dir: $dirname"); + } +if($return_value){ + $cache_key = 'app_list_strings.'.$language; + sugar_cache_clear($cache_key); + } + + return $return_value; +} + +/** + * @return bool + * @param app_list_strings array + * @desc Saves the app_list_strings to file in the 'custom' dir. + */ +function save_custom_app_list_strings(&$app_list_strings, $language) +{ + $return_value = false; + $dirname = 'custom/include/language'; + + $dir_exists = is_dir($dirname); + + if(!$dir_exists) + { + $dir_exists = create_include_lang_dir($dirname); + } + + if($dir_exists) + { + $filename = "$dirname/$language.lang.php"; + $handle = @sugar_fopen($filename, 'wt'); + + if($handle) + { + $contents =create_dropdown_lang_pak_contents($app_list_strings, + $language); + + if(fwrite($handle, $contents)) + { + $return_value = true; + $GLOBALS['log']->info("Successful write to: $filename"); + } + + fclose($handle); + } + else + { + $GLOBALS['log']->info("Unable to write edited language pak to file: $filename"); + } + } + else + { + $GLOBALS['log']->info("Unable to create dir: $dirname"); + } +if($return_value){ + $cache_key = 'app_list_strings.'.$language; + sugar_cache_clear($cache_key); + } + + return $return_value; +} + +function return_custom_app_list_strings_file_contents($language, $custom_filename = '') +{ + $contents = ''; + + $filename = "custom/include/language/$language.lang.php"; + if(!empty($custom_filename)) + $filename = $custom_filename; + + if (is_file($filename)) + { + $contents = file_get_contents($filename); + } + + return $contents; +} + +/** + * @return bool + * @param dropdown_name string, language string + * @desc Creates a new dropdown type. + */ +function create_dropdown_type($dropdown_name, $language) +{ + $return_value = false; + $app_list_strings = return_app_list_strings_language($language); + + if(isset($app_list_strings[$dropdown_name])) + { + $GLOBALS['log']->info("Tried to create a dropdown list key that already exists: $dropdown_name"); + } + else + { + // get the contents of the custom app list strings file + $contents = return_custom_app_list_strings_file_contents($language); + + // add the new dropdown_name to it + if($contents == '') + { + $new_contents = "'');\n?>"; + } + else + { + $new_contents = str_replace('?>', "\$app_list_strings['$dropdown_name'] = array(''=>'');\n?>", $contents); + } + + // save the new contents to file + $return_value = save_custom_app_list_strings_contents($new_contents, $language); + } + + return $return_value; +} + +/** + * @return string& + * @param identifier string, pairs array, first_entry string, selected_key string + * @desc Generates the HTML for a dropdown list. + */ +function &create_dropdown_html($identifier, &$pairs, $first_entry='', $selected_key='') +{ + $html = "\n"; + + return $html; +} + + +function dropdown_item_delete($dropdown_type, $language, $index) +{ + $app_list_strings_to_edit = return_app_list_strings_language($language); + $dropdown_array =$app_list_strings_to_edit[$dropdown_type]; + helper_dropdown_item_delete($dropdown_array, $index); + + $contents = return_custom_app_list_strings_file_contents($language); + $new_contents = replace_or_add_dropdown_type($dropdown_type, $dropdown_array, + $contents); + + save_custom_app_list_strings_contents($new_contents, $language); +} + +function helper_dropdown_item_delete(&$dropdown_array, $index) +{ + // perform the delete from the array + $sliced_off_array = array_splice($dropdown_array, $index); + array_shift($sliced_off_array); + $dropdown_array = array_merge($dropdown_array, $sliced_off_array); +} + +function dropdown_item_move_up($dropdown_type, $language, $index) +{ + $app_list_strings_to_edit = return_app_list_strings_language($language); + $dropdown_array =$app_list_strings_to_edit[$dropdown_type]; + + if($index > 0 && $index < count($dropdown_array)) + { + $key = ''; + $value = ''; + $i = 0; + + reset($dropdown_array); + while(list($k, $v) = each($dropdown_array)) + { + if($i == $index) + { + $key = $k; + $value = $v; + break; + } + + $i++; + } + + helper_dropdown_item_delete($dropdown_array, $index); + helper_dropdown_item_insert($dropdown_array, $index - 1, $key, $value); + + // get the contents of the custom app list strings file + $contents = return_custom_app_list_strings_file_contents($language); + $new_contents = replace_or_add_dropdown_type($dropdown_type, + $dropdown_array, $contents); + + save_custom_app_list_strings_contents($new_contents, $language); + } +} + +function dropdown_item_move_down($dropdown_type, $language, $index) +{ + $app_list_strings_to_edit = return_app_list_strings_language($language); + $dropdown_array =$app_list_strings_to_edit[$dropdown_type]; + + if($index >= 0 && $index < count($dropdown_array) - 1) + { + $key = ''; + $value = ''; + $i = 0; + + reset($dropdown_array); + while(list($k, $v) = each($dropdown_array)) + { + if($i == $index) + { + $key = $k; + $value = $v; + break; + } + + $i++; + } + + helper_dropdown_item_delete($dropdown_array, $index); + helper_dropdown_item_insert($dropdown_array, $index + 1, $key, $value); + + // get the contents of the custom app list strings file + $contents = return_custom_app_list_strings_file_contents($language); + $new_contents = replace_or_add_dropdown_type($dropdown_type, + $dropdown_array, $contents); + + save_custom_app_list_strings_contents($new_contents, $language); + } +} + +function dropdown_item_insert($dropdown_type, $language, $index, $key, $value) +{ + $app_list_strings_to_edit = return_app_list_strings_language($language); + $dropdown_array =$app_list_strings_to_edit[$dropdown_type]; + helper_dropdown_item_insert($dropdown_array, $index, $key, $value); + + // get the contents of the custom app list strings file + $contents = return_custom_app_list_strings_file_contents($language); + $new_contents = replace_or_add_dropdown_type($dropdown_type, + $dropdown_array, $contents); + + save_custom_app_list_strings_contents($new_contents, $language); +} + +function helper_dropdown_item_insert(&$dropdown_array, $index, $key, $value) +{ + $pair = array($key => $value); + if($index <= 0) + { + $dropdown_array = array_merge($pair, $dropdown_array); + } + if($index >= count($dropdown_array)) + { + $dropdown_array = array_merge($dropdown_array, $pair); + } + else + { + $sliced_off_array = array_splice($dropdown_array, $index); + $dropdown_array = array_merge($dropdown_array, $pair); + $dropdown_array = array_merge($dropdown_array, $sliced_off_array); + } +} + +function dropdown_item_edit($dropdown_type, $language, $key, $value) +{ + $app_list_strings_to_edit = return_app_list_strings_language($language); + $dropdown_array =$app_list_strings_to_edit[$dropdown_type]; + + $dropdown_array[$key] = $value; + + $contents = return_custom_app_list_strings_file_contents($language); + + // get the contents of the custom app list strings file + $new_contents = replace_or_add_dropdown_type($dropdown_type, + $dropdown_array, $contents); + + save_custom_app_list_strings_contents($new_contents, $language); +} + +function replace_or_add_dropdown_type($dropdown_type, &$dropdown_array, + &$file_contents) +{ + $new_contents = ""; + $new_entry = override_value_to_string('app_list_strings', + $dropdown_type, $dropdown_array); + + if(empty($file_contents)) + { + // empty file, must create the php tags + $new_contents = ""; + } + else + { + // existing file, try to replace + $new_contents = replace_dropdown_type($dropdown_type, + $dropdown_array, $file_contents); + + $new_contents = dropdown_duplicate_check($dropdown_type, $new_contents); + + if($new_contents == $file_contents) + { + // replace failed, append to end of file + $new_contents = str_replace("?>", '', $file_contents); + $new_contents .= "\n$new_entry\n?>"; + } + } + + return $new_contents; +} + +function replace_or_add_app_string($name, $value, + &$file_contents) +{ + $new_contents = ""; + $new_entry = override_value_to_string('app_strings', + $name, $value); + + if(empty($file_contents)) + { + // empty file, must create the php tags + $new_contents = ""; + } + else + { + // existing file, try to replace + $new_contents = replace_app_string($name, + $value, $file_contents); + + $new_contents = app_string_duplicate_check($name, $new_contents); + + if($new_contents == $file_contents) + { + // replace failed, append to end of file + $new_contents = str_replace("?>", '', $file_contents); + $new_contents .= "\n$new_entry\n?>"; + } + } + + return $new_contents; +} + + +function dropdown_duplicate_check($dropdown_type, &$file_contents) +{ + + if(!empty($dropdown_type) && + !empty($file_contents)) + { + $pattern = '/\$app_list_strings\[\''. $dropdown_type . + '\'\][\ ]*=[\ ]*array[\ ]*\([^\)]*\)[\ ]*;/'; + + $result = array(); + preg_match_all($pattern, $file_contents, $result); + + if(count($result[0]) > 1) + { + $new_entry = $result[0][0]; + $new_contents = preg_replace($pattern, '', $file_contents); + + // Append the new entry. + $new_contents = str_replace("?>", '', $new_contents); + $new_contents .= "\n$new_entry\n?>"; + return $new_contents; + } + + return $file_contents; + } + + return $file_contents; + +} + +function replace_dropdown_type($dropdown_type, &$dropdown_array, + &$file_contents) +{ + $new_contents = $file_contents; + + if(!empty($dropdown_type) && + is_array($dropdown_array) && + !empty($file_contents)) + { + $pattern = '/\$app_list_strings\[\''. $dropdown_type . + '\'\][\ ]*=[\ ]*array[\ ]*\([^\)]*\)[\ ]*;/'; + $replacement = override_value_to_string('app_list_strings', + $dropdown_type, $dropdown_array); + $new_contents = preg_replace($pattern, $replacement, $file_contents, 1); + } + + return $new_contents; +} + +function replace_app_string($name, $value, + &$file_contents) +{ + $new_contents = $file_contents; + + if(!empty($name) && + is_string($value) && + !empty($file_contents)) + { + $pattern = '/\$app_strings\[\''. $name .'\'\][\ ]*=[\ ]*\'[^\']*\'[\ ]*;/'; + $replacement = override_value_to_string('app_strings', + $name, $value); + $new_contents = preg_replace($pattern, $replacement, $file_contents, 1); + } + + return $new_contents; +} + +function app_string_duplicate_check($name, &$file_contents) +{ + + if(!empty($name) && + !empty($file_contents)) + { + $pattern = '/\$app_strings\[\''. $name .'\'\][\ ]*=[\ ]*\'[^\']*\'[\ ]*;/'; + + $result = array(); + preg_match_all($pattern, $file_contents, $result); + + if(count($result[0]) > 1) + { + $new_entry = $result[0][0]; + $new_contents = preg_replace($pattern, '', $file_contents); + + // Append the new entry. + $new_contents = str_replace("?>", '', $new_contents); + $new_contents .= "\n$new_entry\n?>"; + return $new_contents; + } + return $file_contents; + } + + return $file_contents; + +} + +?> diff --git a/modules/Administration/CustomizeFields.php b/modules/Administration/CustomizeFields.php new file mode 100644 index 00000000..d5d9fae6 --- /dev/null +++ b/modules/Administration/CustomizeFields.php @@ -0,0 +1,71 @@ + + + + + +
    +
    +Module Name: + + +
    +
    + diff --git a/modules/Administration/Development.php b/modules/Administration/Development.php new file mode 100644 index 00000000..0bff09a7 --- /dev/null +++ b/modules/Administration/Development.php @@ -0,0 +1,64 @@ + +

    + + + + + + + + + + +
    getImage('ImportCustomFields','alt="'. $mod_strings['LBL_IMPORT_CUSTOM_FIELDS_TITLE'].'" align="absmiddle" border="0"'); ?> 
    getImage('ExportCustomFields','alt="'. $mod_strings['LBL_EXPORT_CUSTOM_FIELDS_TITLE'].'" align="absmiddle" border="0"'); ?> 

    + + diff --git a/modules/Administration/Diagnostic.php b/modules/Administration/Diagnostic.php new file mode 100644 index 00000000..58d8d864 --- /dev/null +++ b/modules/Administration/Diagnostic.php @@ -0,0 +1,103 @@ +{$mod_strings['LBL_MODULE_NAME']}", + translate('LBL_DIAGNOSTIC_TITLE') + ), + false + ); + +global $currentModule; + +$GLOBALS['log']->info("Administration Diagnostic"); + +$sugar_smarty = new Sugar_Smarty(); +$sugar_smarty->assign("MOD", $mod_strings); +$sugar_smarty->assign("APP", $app_strings); + +if($db->dbType != 'mysql') { + $sugar_smarty->assign("NO_MYSQL_MESSAGE", "
    ". + $mod_strings['LBL_DIAGNOSTIC_NO_MYSQL']. + "
     
    + + + + +
    + +
    +
    + + + {if $NO_MYSQL_MESSAGE} + + {/if} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    {$NO_MYSQL_MESSAGE}{$MOD.LBL_DIAGNOSTIC_CONFIGPHP}
    {$MOD.LBL_DIAGNOSTIC_CUSTOMDIR}
    {$MOD.LBL_DIAGNOSTIC_PHPINFO}
    {$MOD.LBL_DIAGNOSTIC_MYSQLDUMPS}
    {$MOD.LBL_DIAGNOSTIC_MYSQLSCHEMA}
    {$MOD.LBL_DIAGNOSTIC_MYSQLINFO}
    {$MOD.LBL_DIAGNOSTIC_MD5}
    {$MOD.LBL_DIAGNOSTIC_FILESMD5}
    {$MOD.LBL_DIAGNOSTIC_CALCMD5}
    {$MOD.LBL_DIAGNOSTIC_BLBF}
    {$MOD.LBL_DIAGNOSTIC_SUGARLOG}
    {$MOD.LBL_DIAGNOSTIC_VARDEFS}
    +
    + + +{$MYSQL_CAPABLE_CHECKBOXES} +{literal} + +{/literal} \ No newline at end of file diff --git a/modules/Administration/DiagnosticDelete.php b/modules/Administration/DiagnosticDelete.php new file mode 100644 index 00000000..5007d53a --- /dev/null +++ b/modules/Administration/DiagnosticDelete.php @@ -0,0 +1,82 @@ +{$mod_strings['LBL_MODULE_NAME']}", + translate('LBL_DIAGNOSTIC_TITLE') + ), + true + ); + + +if(empty($_REQUEST['file']) || empty($_REQUEST['guid'])) +{ + echo $mod_strings['LBL_DIAGNOSTIC_DELETE_ERROR']; +} +else +{ + // Make sure the guid and file are valid file names for security purposes + clean_string($_REQUEST['guid'], "ALPHANUM"); + clean_string($_REQUEST['file'], "FILE"); + + //Making sure someone doesn't pass a variable name as a false reference + // to delete a file + if(strcmp(substr($_REQUEST['file'], 0, 10), "diagnostic") != 0) + { + die($mod_strings['LBL_DIAGNOSTIC_DELETE_DIE']); + } + + if(file_exists("{$GLOBALS['sugar_config']['cache_dir']}diagnostic/".$_REQUEST['guid']."/".$_REQUEST['file'].".zip")) + { + unlink("{$GLOBALS['sugar_config']['cache_dir']}diagnostic/".$_REQUEST['guid']."/".$_REQUEST['file'].".zip"); + rmdir("{$GLOBALS['sugar_config']['cache_dir']}diagnostic/".$_REQUEST['guid']); + echo $mod_strings['LBL_DIAGNOSTIC_DELETED']."

    "; + } + else + echo $mod_strings['LBL_DIAGNOSTIC_FILE'] . $_REQUEST['file'].$mod_strings['LBL_DIAGNOSTIC_ZIP']; +} + +print "" . $mod_strings['LBL_DIAGNOSTIC_DELETE_RETURN'] . "
    "; + +?> diff --git a/modules/Administration/DiagnosticDownload.php b/modules/Administration/DiagnosticDownload.php new file mode 100644 index 00000000..0f5c8c7d --- /dev/null +++ b/modules/Administration/DiagnosticDownload.php @@ -0,0 +1,65 @@ + diff --git a/modules/Administration/DiagnosticRun.php b/modules/Administration/DiagnosticRun.php new file mode 100644 index 00000000..6b1ff387 --- /dev/null +++ b/modules/Administration/DiagnosticRun.php @@ -0,0 +1,837 @@ +"; + $returnString .= "
    Table ".$tableName."
    "; + //get table field definitions + $definitions = array(); + $def_result = $db->query("describe ".$tableName); + if(!$def_result) + { + return mysql_error(); + } + else + { + $returnString .= "Row Num"; + $def_count = 0; + while($row = $db->fetchByAssoc($def_result)) + { + $row = array_values($row); + $definitions[$def_count] = $row[0]; + $def_count++; + $returnString .= "".$row[0].""; + } + $returnString .= ""; + } + + $td_result = $db->query("select * from ".$tableName); + if(!$td_result) + { + return mysql_error(); + } + else + { + $row_counter = 1; + while($row = $db->fetchByAssoc($td_result)) + { + $row = array_values($row); + $returnString .= ""; + $returnString .= "".$row_counter.""; + for($counter = 0; $counter < $def_count; $counter++){ + + $replace_val = false; + //perform this check when counter is set to two, which means it is on the 'value' column + if($counter == 2){ + //if the previous "name" column value was set to smtppass, set replace_val to true + if(strcmp($row[$counter - 1], "smtppass") == 0 ) + $replace_val = true; + + //if the previous "name" column value was set to smtppass, + //and the "category" value set to ldap, set replace_val to true + if (strcmp($row[$counter - 2], "ldap") == 0 && strcmp($row[$counter - 1], "admin_password") == 0) + $replace_val = true; + + //if the previous "name" column value was set to password, + //and the "category" value set to proxy, set replace_val to true + if(strcmp($row[$counter - 2], "proxy") == 0 && strcmp($row[$counter - 1], "password") == 0 ) + $replace_val = true; + } + + if($replace_val) + $returnString .= "********"; + else + $returnString .= "".($row[$counter] == "" ? " " : $row[$counter]).""; + } + $row_counter++; + $returnString .= ""; + } + } + $returnString .= ""; + + return $returnString; + +} + +// Deletes the directory recursively +function deleteDir($dir) +{ + if (substr($dir, strlen($dir)-1, 1) != '/') + $dir .= '/'; + + if ($handle = opendir($dir)) + { + while ($obj = readdir($handle)) + { + if ($obj != '.' && $obj != '..') + { + if (is_dir($dir.$obj)) + { + if (!deleteDir($dir.$obj)) + return false; + } + elseif (is_file($dir.$obj)) + { + if (!unlink($dir.$obj)) + return false; + } + } + } + + closedir($handle); + + if (!@rmdir($dir)) + return false; + return true; + } + return false; +} + + +function prepareDiag() +{ + global $getDumpsFrom; + global $cacheDir; + global $curdatetime; + global $progress_bar_percent; + global $skip_md5_diff; + global $sod_guid; + global $mod_strings; + + echo getClassicModuleTitle( + "Administration", + array( + "{$mod_strings['LBL_MODULE_NAME']}", + translate('LBL_DIAGNOSTIC_TITLE') + ), + false + ); + echo "
    "; + echo $mod_strings['LBL_DIAGNOSTIC_EXECUTING']; + echo "
    "; + + + //determine if files.md5 exists or not + if(file_exists('files.md5')) + $skip_md5_diff = false; + else + $skip_md5_diff = true; + + // array of all tables that we need to pull rows from below + $getDumpsFrom = array('config' => 'config', + 'fields_meta_data' => 'fields_meta_data', + 'upgrade_history' => 'upgrade_history', + 'versions' => 'versions', + ); + + + //Creates the diagnostic directory in the cache directory + $cacheDir = create_cache_directory("diagnostic/"); + $cacheDir = create_cache_directory("diagnostic/".$sod_guid); + $cacheDir = create_cache_directory("diagnostic/".$sod_guid."/diagnostic".$curdatetime."/"); + + display_progress_bar("diagnostic", $progress_bar_percent, 100); + + ob_flush(); +} + +function executesugarlog() +{ + //BEGIN COPY SUGARCRM.LOG + //Copies the Sugarcrm log to our diagnostic directory + global $cacheDir; + require_once('include/SugarLogger/SugarLogger.php'); + $logger = new SugarLogger(); + if(!copy($logger->getLogFileNameWithPath(), $cacheDir.'/'.$logger->getLogFileName())) { + echo "Couldn't copy sugarcrm.log to cacheDir.
    "; + } + //END COPY SUGARCRM.LOG + + //UPDATING PROGRESS BAR + sodUpdateProgressBar(SUGARLOG_WEIGHT); +} + +function executephpinfo() +{ + //BEGIN GETPHPINFO + //This gets phpinfo, writes to a buffer, then I write to phpinfo.html + global $cacheDir; + + ob_start(); + phpinfo(); + $phpinfo = ob_get_contents(); + ob_clean(); + + $handle = sugar_fopen($cacheDir."phpinfo.html", "w"); + if(fwrite($handle, $phpinfo) === FALSE){ + echo "Cannot write to file ".$cacheDir."phpinfo.html
    "; + } + fclose($handle); + //END GETPHPINFO + + //UPDATING PROGRESS BAR + sodUpdateProgressBar(PHPINFO_WEIGHT); +} + +function executeconfigphp() +{ + //BEGIN COPY CONFIG.PHP + //store db_password in temp var so we can get config.php w/o making anyone angry + global $cacheDir; global $sugar_config; + + $tempPass = $sugar_config['dbconfig']['db_password']; + $sugar_config['dbconfig']['db_password'] = '********'; + //write config.php to a file + write_array_to_file("Diagnostic", $sugar_config, $cacheDir."config.php"); + //restore db_password so everything still works + $sugar_config['dbconfig']['db_password'] = $tempPass; + //END COPY CONFIG.PHP + + //UPDATING PROGRESS BAR + sodUpdateProgressBar(CONFIG_WEIGHT); +} + +function executemysql($getinfo, $getdumps, $getschema) +{ + //BEGIN GET DB INFO + global $getDumpsFrom; + global $curdatetime; + global $sugar_config; + global $progress_bar_percent; + global $sod_guid; + global $db; + + if($db->dbType != "mysql") { + if($getinfo) sodUpdateProgressBar(MYSQL_INFO_WEIGHT); + if($getschema) sodUpdateProgressBar(MYSQL_SCHEMA_WEIGHT); + if($getdumps) sodUpdateProgressBar(MYSQL_DUMPS_WEIGHT); + return; + } + + $mysqlInfoDir = create_cache_directory("diagnostic/".$sod_guid."/diagnostic".$curdatetime."/MySQL/"); + + + //create directory for table definitions + if($getschema) + $tablesSchemaDir = create_cache_directory("diagnostic/".$sod_guid."/diagnostic".$curdatetime."/MySQL/TableSchema/"); + + //BEGIN GET MYSQL INFO + //make sure they checked the box to get basic info + if($getinfo) + { + ob_start(); + echo "MySQL Version: ".(function_exists('mysqli_get_client_info') ? @mysqli_get_client_info() : @mysql_get_client_info())."
    "; + echo "MySQL Host Info: ".(function_exists('mysqli_get_host_info') ? @mysqli_get_host_info($db->getDatabase()) : @mysql_get_host_info())."
    "; + echo "MySQL Server Info: ".(function_exists('mysqli_get_client_info') ? @mysqli_get_client_info() : @mysql_get_client_info())."
    "; + echo "MySQL Client Encoding: ".(function_exists('mysqli_character_set_name') ? @mysqli_character_set_name($db->getDatabase()) : @mysql_client_encoding())."
    "; + + /* Uncomment to get current processes as well + echo "
    MySQL Processes
    "; + $res = $db->query('SHOW PROCESSLIST'); + echo ""; + if($db->getRowCount($res) > 0) + { + while($row = $db->fetchByAssoc($res)) + { + printf("", + $row['Id'], $row['Host'], $row['db'], $row['Command'], $row['Time'] + ); + } + echo "
    IdHostdbCommandTime
    %s%s%s%s%s

    "; + } + else + { + echo ""; + echo "No processes running
    "; + } + */ + + echo "
    MySQL Character Set Settings
    "; + $res = $db->query("show variables like 'character\_set\_%'"); + echo ""; + while($row = $db->fetchByAssoc($res)) + { + printf("", + $row['Variable_name'], $row['Value'] + ); + } + echo "
    Variable NameValue
    %s%s
    "; + + $content = ob_get_contents(); + ob_clean(); + + $handle = sugar_fopen($mysqlInfoDir."MySQL-General-info.html", "w"); + if(fwrite($handle, $content) === FALSE){ + echo "Cannot write to file ".$mysqlInfoDir."_MySQL-General-info.html
    "; + } + fclose($handle); + //BEGIN UPDATING PROGRESS BAR + sodUpdateProgressBar(MYSQL_INFO_WEIGHT); + //END UPDATING PROGRESS BAR + } + //END GET MYSQL INFO + + + if($getschema) + { + //BEGIN GET ALL TABLES SCHEMAS + $all_tables = $db->getTablesArray(); + + global $theme_path; + + ob_start(); + echo ""; + foreach($all_tables as $tablename){ + //setting up table header for each file + echo ""; + echo "MySQL ".$tablename." Definitions:". + "". + "". + "". + "". + "". + ""; + $describe = $db->query("describe ".$tablename); + while($inner_row = $db->fetchByAssoc($describe)){ + $inner_row = array_values($inner_row); + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + } + echo "
    FieldTypeNullKeyDefaultExtra
    ".$inner_row[0]."".$inner_row[1]."".$inner_row[2]."".$inner_row[3]."".$inner_row[4]."".$inner_row[5]."
    "; + echo "

    "; + } + + $content = ob_get_contents(); + ob_clean(); + + $handle = sugar_fopen($tablesSchemaDir."MySQLTablesSchema.html", "w"); + if(fwrite($handle, $content) === FALSE){ + echo "Cannot write to file ".$tablesSchemaDir."MySQLTablesSchema.html
    "; + } + fclose($handle); + + //END GET ALL TABLES SCHEMAS + //BEGIN UPDATING PROGRESS BAR + sodUpdateProgressBar(MYSQL_SCHEMA_WEIGHT); + //END UPDATING PROGRESS BAR + } + + if($getdumps) + { + //BEGIN GET TABLEDUMPS + $tableDumpsDir = create_cache_directory("diagnostic/".$sod_guid."/diagnostic".$curdatetime."/MySQL/TableDumps/"); + + + foreach ($getDumpsFrom as $table) + { + ob_start(); + //calling function defined above to get the string for dump + echo getFullTableDump($table); + $content = ob_get_contents(); + ob_clean(); + $handle = sugar_fopen($tableDumpsDir.$table.".html", "w"); + if(fwrite($handle, $content) === FALSE){ + echo "Cannot write to file ".$tableDumpsDir.$table."html
    "; + } + fclose($handle); + } + //END GET TABLEDUMPS + //BEGIN UPDATING PROGRESS BAR + sodUpdateProgressBar(MYSQL_DUMPS_WEIGHT); + //END UPDATING PROGRESS BAR + } + + + //END GET DB INFO +} + + +function executebeanlistbeanfiles() +{ + //BEGIN CHECK BEANLIST FILES ARE AVAILABLE + global $cacheDir; + global $beanList; + global $beanFiles; + global $mod_strings; + + ob_start(); + + echo $mod_strings['LBL_DIAGNOSTIC_BEANLIST_DESC']; + echo "
    "; + echo ""; + echo $mod_strings['LBL_DIAGNOSTIC_BEANLIST_GREEN']; + echo ""; + echo "
    "; + echo ""; + echo $mod_strings['LBL_DIAGNOSTIC_BEANLIST_ORANGE']; + echo ""; + echo "
    "; + echo ""; + echo $mod_strings['LBL_DIAGNOSTIC_BEANLIST_RED']; + echo ""; + echo "

    "; + + foreach ($beanList as $beanz) + { + if(!isset($beanFiles[$beanz])) + { + echo "NO! --- ".$beanz." is not an index in \$beanFiles
    "; + } + else + { + if(file_exists($beanFiles[$beanz])) + echo "YES --- ".$beanz." file \"".$beanFiles[$beanz]."\" exists
    "; + else + echo "NO! --- ".$beanz." file \"".$beanFiles[$beanz]."\" does NOT exist
    "; + } + } + + $content = ob_get_contents(); + ob_clean(); + + $handle = sugar_fopen($cacheDir."beanFiles.html", "w"); + if(fwrite($handle, $content) === FALSE){ + echo "Cannot write to file ".$cacheDir."beanFiles.html
    "; + } + fclose($handle); + //END CHECK BEANLIST FILES ARE AVAILABLE + //BEGIN UPDATING PROGRESS BAR + sodUpdateProgressBar(BEANLISTBEANFILES_WEIGHT); + //END UPDATING PROGRESS BAR +} + +function executecustom_dir() +{ + //BEGIN ZIP AND SAVE CUSTOM DIRECTORY + global $cacheDir; + + zip_dir("custom", $cacheDir."custom_directory.zip"); + //END ZIP AND SAVE CUSTOM DIRECTORY + //BEGIN UPDATING PROGRESS BAR + sodUpdateProgressBar(CUSTOM_DIR_WEIGHT); + //END UPDATING PROGRESS BAR +} + +function executemd5($filesmd5, $md5calculated) +{ + //BEGIN ALL MD5 CHECKS + global $curdatetime; + global $skip_md5_diff; + global $sod_guid; + if(file_exists('files.md5')) + include( 'files.md5'); + //create dir for md5s + $md5_directory = create_cache_directory("diagnostic/".$sod_guid."/diagnostic".$curdatetime."/md5/"); + + //skip this if the files.md5 didn't exist + if(!$skip_md5_diff) + { + //make sure the files.md5 + if($filesmd5) + if(!copy('files.md5', $md5_directory."files.md5")) + echo "Couldn't copy files.md5 to ".$md5_directory."
    Skipping md5 checks.
    "; + } + + $md5_string_calculated = generateMD5array('./'); + + if($md5calculated) + write_array_to_file('md5_string_calculated', $md5_string_calculated, $md5_directory."md5_array_calculated.php"); + + + //if the files.md5 didn't exist, we can't do this + if(!$skip_md5_diff) + { + $md5_string_diff = array_diff($md5_string_calculated, $md5_string); + + write_array_to_file('md5_string_diff', $md5_string_diff, $md5_directory."md5_array_diff.php"); + } + //END ALL MD5 CHECKS + //BEGIN UPDATING PROGRESS BAR + sodUpdateProgressBar(MD5_WEIGHT); + //END UPDATING PROGRESS BAR +} + +function executevardefs() +{ + //BEGIN DUMP OF SUGAR SCHEMA (VARDEFS) + + //END DUMP OF SUGAR SCHEMA (VARDEFS) + //BEGIN UPDATING PROGRESS BAR + //This gets the vardefs, writes to a buffer, then I write to vardefschema.html + global $cacheDir; + global $beanList; + global $beanFiles; + global $dictionary; + global $sugar_version; + global $sugar_db_version; + global $sugar_flavor; + + ob_start(); + foreach ( $beanList as $beanz ) { + // echo "Module: ".$beanz."
    "; + + $path_parts = pathinfo( $beanFiles[ $beanz ] ); + $vardefFileName = $path_parts[ 'dirname' ]."/vardefs.php"; + if( file_exists( $vardefFileName )) { + // echo "
    ".$vardefFileName."
    "; + include_once( $vardefFileName ); + } + } + + echo ""; + echo ""; + echo "

    Schema listing based on vardefs

    "; + echo "

    Sugar version: ".$sugar_version." / Sugar DB version: ".$sugar_db_version." / Sugar flavor: ".$sugar_flavor; + echo "

    "; + + echo ""; + + $tables = array(); + foreach($dictionary as $vardef) { + $tables[] = $vardef['table']; + $fields[$vardef['table']] = $vardef['fields']; + $comments[$vardef['table']] = $vardef['comment']; + } + + asort($tables); + + foreach($tables as $t) { + $name = $t; + if ( $name == "does_not_exist" ) + continue; + $comment = $comments[$t]; + echo "

    Table: $t

    +

    {$comment}

    "; + echo ""; + echo ' + + + + + + '; + + ksort( $fields[ $t ] ); + + foreach($fields[$t] as $k => $v) { + // we only care about physical tables ('source' can be 'non-db' or 'nondb' or 'function' ) + if ( isset( $v[ 'source' ] )) + continue; + $columnname = $v[ 'name' ]; + $columntype = $v[ 'type' ]; + $columndbtype = $v[ 'dbType' ]; + $columnlen = $v[ 'len' ]; + $columncomment = $v[ 'comment' ]; + $columnrequired = $v[ 'required' ]; + + if ( empty( $columnlen ) ) $columnlen = 'n/a'; + if ( empty( $columncomment ) ) $columncomment = '(none)'; + if ( !empty( $columndbtype ) ) $columntype = $columndbtype; + if ( empty( $columnrequired ) || ( $columnrequired == false )) + $columndisplayrequired = 'no'; + else + $columndisplayrequired = 'yes'; + + echo ' + + + + + '; + } + + echo "
    ColumnTypeLengthRequiredComment
    '.$columnname.''.$columntype.''.$columnlen.''.$columndisplayrequired.''.$columncomment.'

    "; + } + + echo ""; + + $vardefFormattedOutput = ob_get_contents(); + ob_clean(); + + $handle = sugar_fopen($cacheDir."vardefschema.html", "w"); + if(fwrite($handle, $vardefFormattedOutput) === FALSE){ + echo "Cannot write to file ".$cacheDir."vardefschema.html
    "; + } + fclose($handle); + sodUpdateProgressBar(VARDEFS_WEIGHT); + //END UPDATING PROGRESS BAR +} + +function finishDiag(){ + //BEGIN ZIP ALL FILES AND EXTRACT IN CACHE ROOT + global $cacheDir; + global $curdatetime; + global $sod_guid; + global $mod_strings; + + chdir($cacheDir); + zip_dir(".", "../diagnostic".$curdatetime.".zip"); + //END ZIP ALL FILES AND EXTRACT IN CACHE ROOT + chdir(RETURN_FROM_DIAG_DIR); + + deleteDir($cacheDir); + + + print "".$mod_strings['LBL_DIAGNOSTIC_DOWNLOADLINK']."
    "; + + print "".$mod_strings['LBL_DIAGNOSTIC_DELETELINK']."
    "; + +} + +//BEGIN check for what we are executing +$doconfigphp = ((empty($_POST['configphp']) || $_POST['configphp'] == 'off') ? false : true); +$docustom_dir = ((empty($_POST['custom_dir']) || $_POST['custom_dir'] == 'off') ? false : true); +$dophpinfo = ((empty($_POST['phpinfo']) || $_POST['phpinfo'] == 'off') ? false : true); +$domysql_dumps = ((empty($_POST['mysql_dumps']) || $_POST['mysql_dumps'] == 'off') ? false : true); +$domysql_schema = ((empty($_POST['mysql_schema']) || $_POST['mysql_schema'] == 'off') ? false : true); +$domysql_info = ((empty($_POST['mysql_info']) || $_POST['mysql_info'] == 'off') ? false : true); +$domd5 = ((empty($_POST['md5']) || $_POST['md5'] == 'off') ? false : true); +$domd5filesmd5 = ((empty($_POST['md5filesmd5']) || $_POST['md5filesmd5'] == 'off') ? false : true); +$domd5calculated = ((empty($_POST['md5calculated']) || $_POST['md5calculated'] == 'off') ? false : true); +$dobeanlistbeanfiles = ((empty($_POST['beanlistbeanfiles']) || $_POST['beanlistbeanfiles'] == 'off') ? false : true); +$dosugarlog = ((empty($_POST['sugarlog']) || $_POST['sugarlog'] == 'off') ? false : true); +$dovardefs = ((empty($_POST['vardefs']) || $_POST['vardefs'] == 'off') ? false : true); +//END check for what we are executing + + +//BEGIN items to calculate progress bar +$totalitems = 0; +$totalweight = 0; +if($doconfigphp) {$totalweight += CONFIG_WEIGHT; $totalitems++;} +if($docustom_dir) {$totalweight += CUSTOM_DIR_WEIGHT; $totalitems++;} +if($dophpinfo) {$totalweight += PHPINFO_WEIGHT; $totalitems++;} +if($domysql_dumps) {$totalweight += MYSQL_DUMPS_WEIGHT; $totalitems++;} +if($domysql_schema) {$totalweight += MYSQL_SCHEMA_WEIGHT; $totalitems++;} +if($domysql_info) {$totalweight += MYSQL_INFO_WEIGHT; $totalitems++;} +if($domd5) {$totalweight += MD5_WEIGHT; $totalitems++;} +if($dobeanlistbeanfiles) {$totalweight += BEANLISTBEANFILES_WEIGHT; $totalitems++;} +if($dosugarlog) {$totalweight += SUGARLOG_WEIGHT; $totalitems++;} +if($dovardefs) {$totalweight += VARDEFS_WEIGHT; $totalitems++;} +//END items to calculate progress bar + +//prepare initial steps +prepareDiag(); + + +if($doconfigphp) +{ + echo $mod_strings['LBL_DIAGNOSTIC_GETCONFPHP']."
    "; + executeconfigphp(); + echo $mod_strings['LBL_DIAGNOSTIC_DONE']."

    "; +} +if($docustom_dir) +{ + echo $mod_strings['LBL_DIAGNOSTIC_GETCUSTDIR']."
    "; + executecustom_dir(); + echo $mod_strings['LBL_DIAGNOSTIC_DONE']."

    "; +} +if($dophpinfo) +{ + echo $mod_strings['LBL_DIAGNOSTIC_GETPHPINFO']."
    "; + executephpinfo(); + echo $mod_strings['LBL_DIAGNOSTIC_DONE']."

    "; +} +if($domysql_info || $domysql_dumps || $domysql_schema) +{ + echo $mod_strings['LBL_DIAGNOSTIC_GETTING']. + ($domysql_info ? "... ".$mod_strings['LBL_DIAGNOSTIC_GETMYSQLINFO'] : " "). + ($domysql_dumps ? "... ".$mod_strings['LBL_DIAGNOSTIC_GETMYSQLTD'] : " "). + ($domysql_schema ? "... ".$mod_strings['LBL_DIAGNOSTIC_GETMYSQLTS'] : "..."). + "
    "; + executemysql($domysql_info, $domysql_dumps, $domysql_schema); + echo $mod_strings['LBL_DIAGNOSTIC_DONE']."

    "; +} +if($domd5) +{ + echo $mod_strings['LBL_DIAGNOSTIC_GETMD5INFO']."
    "; + executemd5($domd5filesmd5, $domd5calculated); + echo $mod_strings['LBL_DIAGNOSTIC_DONE']."

    "; +} +if($dobeanlistbeanfiles) +{ + echo $mod_strings['LBL_DIAGNOSTIC_GETBEANFILES']."
    "; + executebeanlistbeanfiles(); + echo $mod_strings['LBL_DIAGNOSTIC_DONE']."

    "; +} +if($dosugarlog) +{ + echo $mod_strings['LBL_DIAGNOSTIC_GETSUGARLOG']."
    "; + executesugarlog(); + echo $mod_strings['LBL_DIAGNOSTIC_DONE']."

    "; +} +if($dovardefs) +{ + echo $mod_strings['LBL_DIAGNOSTIC_VARDEFS']."
    "; + executevardefs(); + echo $mod_strings['LBL_DIAGNOSTIC_DONE']."

    "; +} + +//finish up the last steps +finishDiag(); + +?> diff --git a/modules/Administration/DisplayWarnings.php b/modules/Administration/DisplayWarnings.php new file mode 100644 index 00000000..6b55e896 --- /dev/null +++ b/modules/Administration/DisplayWarnings.php @@ -0,0 +1,159 @@ +' . $errorString .'

    '; + echo $output; +} + +if(isset($_SESSION['rebuild_relationships'])){ + displayAdminError(translate('MSG_REBUILD_RELATIONSHIPS', 'Administration')); +} + +if(isset($_SESSION['rebuild_extensions'])){ + displayAdminError(translate('MSG_REBUILD_EXTENSIONS', 'Administration')); +} + +if (empty($license)){ + $license=new Administration(); + $license=$license->retrieveSettings('license'); +} + + + +if(!empty($_SESSION['HomeOnly'])){ + displayAdminError(translate('FATAL_LICENSE_ALTERED', 'Administration')); +} + +if(isset($license) && !empty($license->settings['license_msg_all'])){ + displayAdminError(base64_decode($license->settings['license_msg_all'])); +} +if ( (strpos($_SERVER["SERVER_SOFTWARE"],'Microsoft-IIS') !== false) && (php_sapi_name() == 'cgi-fcgi') && (ini_get('fastcgi.logging') != '0') ) { + displayAdminError(translate('LBL_FASTCGI_LOGGING', 'Administration')); +} +if(is_admin($current_user)){ +if(!empty($_SESSION['COULD_NOT_CONNECT'])){ + displayAdminError(translate('LBL_COULD_NOT_CONNECT', 'Administration') . ' '. $timedate->to_display_date_time($_SESSION['COULD_NOT_CONNECT'])); +} +if(!empty($_SESSION['EXCEEDING_OC_LICENSES']) && $_SESSION['EXCEEDING_OC_LICENSES'] == true){ + displayAdminError(translate('LBL_EXCEEDING_OC_LICENSES', 'Administration')); +} +if(isset($license) && !empty($license->settings['license_msg_admin'])){ + // UUDDLRLRBA + $GLOBALS['log']->fatal(base64_decode($license->settings['license_msg_admin'])); + //displayAdminError(base64_decode($license->settings['license_msg_admin'])); + return; +} + +//No SMTP server is set up Error. +$smtp_error = false; +$admin = new Administration(); +$admin->retrieveSettings(); + +//If sendmail has been configured by setting the config variable ignore this warning +$sendMailEnabled = isset($sugar_config['allow_sendmail_outbound']) && $sugar_config['allow_sendmail_outbound']; + +if(trim($admin->settings['mail_smtpserver']) == '' && !$sendMailEnabled) { + if($admin->settings['notify_on']) { + $smtp_error = true; + } +} + +if($smtp_error) { + displayAdminError(translate('WARN_NO_SMTP_SERVER_AVAILABLE_ERROR','Administration')); +} + + if(!empty($dbconfig['db_host_name']) || $sugar_config['sugar_version'] != $sugar_version ){ + displayAdminError(translate('WARN_REPAIR_CONFIG', 'Administration')); + } + + if( !isset($sugar_config['installer_locked']) || $sugar_config['installer_locked'] == false ){ + displayAdminError(translate('WARN_INSTALLER_LOCKED', 'Administration')); + } + + + + + + + + + + + if(empty($GLOBALS['sugar_config']['admin_access_control'])){ + if(isset($_SESSION['invalid_versions'])){ + $invalid_versions = $_SESSION['invalid_versions']; + foreach($invalid_versions as $invalid){ + displayAdminError(translate('WARN_UPGRADE', 'Administration'). $invalid['name'] .translate('WARN_UPGRADE2', 'Administration')); + } + } + + if (isset($_SESSION['available_version'])){ + if($_SESSION['available_version'] != $sugar_version) + { + displayAdminError(translate('WARN_UPGRADENOTE', 'Administration').$_SESSION['available_version_description']); + } + } + } + +// if (!isset($_SESSION['dst_fixed']) || $_SESSION['dst_fixed'] != true) { +// $qDst = "SELECT count(*) AS dst FROM versions WHERE name = 'DST Fix'"; +// $rDst = $db->query($qDst); +// $rowsDst = $db->fetchByAssoc($rDst); +// if($rowsDst['dst'] > 0) { +// $_SESSION['dst_fixed'] = true; +// } else { +// $_SESSION['dst_fixed'] = false; +// displayAdminError($app_strings['LBL_DST_NEEDS_FIXIN']); +// } +// +// } + + if(isset($_SESSION['administrator_error'])) + { + // Only print DB errors once otherwise they will still look broken + // after they are fixed. + displayAdminError($_SESSION['administrator_error']); + } + + unset($_SESSION['administrator_error']); +} + +?> diff --git a/modules/Administration/DstFix.php b/modules/Administration/DstFix.php new file mode 100644 index 00000000..99a23075 --- /dev/null +++ b/modules/Administration/DstFix.php @@ -0,0 +1,402 @@ +dbType == 'oci8') { + echo "
    "; + echo "

    ".$mod_strings['ERR_NOT_FOR_ORACLE']."

    "; + echo "
    "; + sugar_die(''); +} +if ($db->dbType == 'mssql') { + echo "
    "; + echo "

    ".$mod_strings['ERR_NOT_FOR_MSSQL']."

    "; + echo "
    "; + sugar_die(''); +} + + + +$display = ''; +if(empty($db)) { + + $db = DBManagerFactory::getInstance(); +} + +// check if this fix has been applied already +$qDone = "SELECT * FROM versions WHERE name = 'DST Fix'"; +$rDone = $db->query($qDone); +$rowsDone = $db->getRowCount($rDone); +if($rowsDone > 0) { + $done = true; +} else { + $done = false; +} + +// some inits: +$disabled = 'DISABLED'; +$confirmed = 'false'; + +// apply the fix +if(!empty($_REQUEST['confirmed']) && $_REQUEST['confirmed'] == true) { + // blowaway vCal server cache + $qvCal = "TRUNCATE vcals"; + $rvCal = $db->query($qvCal); + + // disable refresh double-ups + $rDblCheck = $db->query($qDone); + $rowsDblCheck = $db->getRowCount($rDblCheck); + if($rowsDblCheck < 1) { + + // majed's sql generation + $tables = array( + 'calls'=>array( + 'date_start'=>'time_start', + ), + 'meetings'=>array( + 'date_start'=>'time_start', + ), + 'tasks'=>array( + 'date_due'=>'time_due', + ), + 'project_task'=>array( + 'date_due'=>'time_due', + ), + 'email_marketing'=>array( + 'date_start'=>'time_start', + ), + 'emailman'=>array( + 'send_date_time'=>'datetime', + ) + ); + + $zone = $_REQUEST['server_timezone']; + $startyear = 2004; + $maxyear = 2014; + $date_modified = $timedate->nowDb(); + $display = ''; + + foreach($tables as $table_name =>$table) { + + //$display .= ''. $table_name . '
    '; + $year = $startyear; + + for($year = $startyear; $year <= $maxyear; $year++) { + $range = $timedate->getDSTRange($year,$timezones[$zone]); + $startDateTime = explode(' ',$range['start']); + $endDateTime = explode(' ',$range['end']); + + if($range) { + if( strtotime($range['start']) < strtotime($range['end'])) { + foreach($table as $date=>$time) { + $interval='PLUSMINUS INTERVAL 3600 second'; + if($time != 'datetime'){ + if ( ( $db->dbType == 'mysql' ) or ( $db->dbType == 'oci8' ) ) + { + $field = "CONCAT($table_name.$date,' ', $table_name.$time)"; + } + if ( $db->dbType == 'mssql' ) + { + $field = "$table_name.$date + ' ' + $table_name.$time"; + } + $updateBase= "UPDATE $table_name SET date_modified='$date_modified', $table_name.$date=LEFT($field $interval,10),"; + $updateBase .= " $table_name.$time=RIGHT($field $interval,8)"; + + }else{ + $field = "$table_name.$date"; + $updateBase = "UPDATE $table_name SET date_modified='$date_modified', $table_name.$date = $table_name.$date $interval"; + } + //BEGIN DATE MODIFIED IN DST WITH DATE OUT DST + $update = str_replace('PLUSMINUS', '+', $updateBase); + $queryInDST = $update ." + WHERE + $table_name.date_modified >= '{$range['start']}' AND $table_name.date_modified < '{$range['end']}' + AND ( $field < '{$range['start']}' OR $field >= '{$range['end']}' )"; + + $result = $db->query($queryInDST); + $count = $db->getAffectedRowCount(); + //$display .= "$year - Records updated with date modified in DST with date out of DST: $count
    "; + //BEGIN DATE MODIFIED OUT DST WITH DATE IN DST + $update = str_replace('PLUSMINUS', '-', $updateBase); + $queryOutDST = $update ." + WHERE + ( $table_name.date_modified < '{$range['start']}' OR $table_name.date_modified >= '{$range['end']}' ) + AND $field >= '{$range['start']}' AND $field < '{$range['end']}' "; + + $result = $db->query($queryOutDST); + $count = $db->getAffectedRowCount(); + //$display .= "$year - Records updated with date modified out of DST with date in DST: $count
    "; + } + }else{ + + foreach($table as $date=>$time){ + $interval='PLUSMINUS INTERVAL 3600 second'; + if($time != 'datetime'){ + + if ( ( $this->db->dbType == 'mysql' ) or ( $this->db->dbType == 'oci8' ) ) + { + $field = "CONCAT($table_name.$date,' ', $table_name.$time)"; + } + if ( $this->db->dbType == 'mssql' ) + { + $field = "$table_name.$date + ' ' + $table_name.$time"; + } + $updateBase= "UPDATE $table_name SET $table_name.$date=LEFT($field $interval,10),"; + $updateBase .= " $table_name.$time=RIGHT($field $interval,8)"; + + }else{ + $field = "$table_name.$date"; + $updateBase = "UPDATE $table_name SET $table_name.$date = $table_name.$date $interval"; + } + + + //BEGIN DATE MODIFIED IN DST WITH DATE OUT OF DST + $update = str_replace('PLUSMINUS', '+', $updateBase); + $queryInDST = $update ." + WHERE + ($table_name.date_modified >= '{$range['start']}' OR $table_name.date_modified < '{$range['end']}' ) + AND $field < '{$range['start']}' AND $field >= '{$range['end']}'"; + + $result = $db->query($queryInDST); + $count = $db->getAffectedRowCount(); + //$display .= "$year - Records updated with date modified in DST with date out of DST: $count
    "; + + //BEGIN DATE MODIFIED OUT DST WITH DATE IN DST + $update = str_replace('PLUSMINUS', '-', $updateBase); + $queryOutDST = $update ." + WHERE + ($table_name.date_modified < '{$range['start']}' AND $table_name.date_modified >= '{$range['end']}' ) + AND + ($field >= '{$range['start']}' OR $field < '{$range['end']}' )"; + + + + } + + $result = $db->query($queryOutDST); + $count = $db->getAffectedRowCount(); + //$display .= "$year - Records updated with date modified out of DST with date in DST: $count
    "; + } + } + } // end outer forloop + }// end foreach loop + + + } + $display .= "
    ".$mod_strings['LBL_DST_FIX_DONE_DESC'].""; +} elseif(!$done) { // show primary screen + $disabled = ""; + $confirmed = 'true'; + require_once('include/timezone/timezones.php'); + global $timezones; + $timezoneOptions = ''; + ksort($timezones); + if(!isset($defaultServerZone)){ + $defaultServerZone = TimeDate::guessTimezone(0); + } + foreach($timezones as $key => $value) { + if(!empty($value['dstOffset'])) { + $dst = " (+DST)"; + } else { + $dst = ""; + } + if($key == $defaultServerZone){ + $selected = 'selected'; + }else{ + $selected = ''; + } + $gmtOffset = ($value['gmtOffset'] / 60); + if(!strstr($gmtOffset,'-')) { + $gmtOffset = "+".$gmtOffset; + } + $timezoneOptions .= ""; + } + + // descriptions and assumptions + $display = " + + + + ".$mod_strings['LBL_DST_FIX_TARGET']." + + + ".$mod_strings['LBL_APPLY_DST_FIX_DESC']." + + + + + ".$mod_strings['LBL_DST_BEFORE']." + + + ".$mod_strings['LBL_DST_BEFORE_DESC']." + + + + + ".$mod_strings['LBL_DST_FIX_CONFIRM']." + + + ".$mod_strings['LBL_DST_FIX_CONFIRM_DESC']." + + + + + + + + + + + + + + + + + + + + +
    + ".$mod_strings['LBL_DST_CURRENT_SERVER_TIME']." + + ".$timedate->to_display_time($timedate->nowDb(), true, false)." +
    + ".$mod_strings['LBL_DST_CURRENT_SERVER_TIME_ZONE']." + + ".date("T")."
    +
    + ".$mod_strings['LBL_DST_CURRENT_SERVER_TIME_ZONE_LOCALE']." + +
    +
    +
    + "; +} else { // fix has been applied - don't want to allow a 2nd pass + $display = $mod_strings['LBL_DST_FIX_DONE_DESC']; + $disabled = 'DISABLED'; + $confirmed = 'false'; +} + +if(!empty($_POST['upgrade'])){ + // enter row in versions table + $qDst = "INSERT INTO versions VALUES ('".create_guid()."', 0, '".$timedate->nowDB()."', '".$timedate->nowDB()."', '".$current_user->id."', '".$current_user->id."', 'DST Fix', '3.5.1b', '3.5.1b')"; + $qRes = $db->query($qDst); + // record server's time zone locale for future upgrades + $qSTZ = "INSERT INTO config VALUES ('Update', 'server_timezone', '".$_REQUEST['server_timezone']."')"; + $rSTZ = $db->query($qSTZ); + if(empty($_REQUEST['confirmed']) || $_REQUEST['confirmed'] == 'false') { + $display = $mod_strings['LBL_DST_FIX_DONE_DESC']; + $disabled = 'DISABLED'; + $confirmed = 'false'; + } + unset($_SESSION['GMTO']); +} + + + +echo getClassicModuleTitle($mod_strings['LBL_MODULE_NAME'], array($mod_strings['LBL_APPLY_DST_FIX']), true); + +if(empty($disabled)){ +?> +

    Step 1:

    + + + + + +
    + + + +
    + ' onclick='document.location.href="index.php?module=Administration&action=updateTimezonePrefs"'> +
    +
    + +

    +

    + + +Step 2:"; +} +?> + + + + + + + + + + + +
    + + + + + + +
    + +"; +}else{ +echo ""; +} +?> + +
    +
    diff --git a/modules/Administration/ExportCustomFieldStructure.php b/modules/Administration/ExportCustomFieldStructure.php new file mode 100644 index 00000000..098df41f --- /dev/null +++ b/modules/Administration/ExportCustomFieldStructure.php @@ -0,0 +1,58 @@ +query('SELECT * FROM fields_meta_data WHERE deleted = 0'); +$fields = array(); +$str = ''; +while($row = $db->fetchByAssoc($result)){ + foreach($row as $name=>$value){ + $str.= "$name:::$value\n"; + } + $str .= "DONE\n"; +} +ob_get_clean(); + +header("Content-Disposition: attachment; filename=CustomFieldStruct.sugar"); +header("Content-Type: text/txt; charset={$app_strings['LBL_CHARSET']}"); +header( "Expires: Mon, 26 Jul 1997 05:00:00 GMT" ); +header( "Last-Modified: " . TimeDate::httpTime() ); +header( "Cache-Control: post-check=0, pre-check=0", false ); +header("Content-Length: ".strlen($str)); +echo $str; +?> \ No newline at end of file diff --git a/modules/Administration/Forms.php b/modules/Administration/Forms.php new file mode 100644 index 00000000..a540bd72 --- /dev/null +++ b/modules/Administration/Forms.php @@ -0,0 +1,79 @@ + + + +EOQ; + +return $the_script; +} + + +?> diff --git a/modules/Administration/ImportCustomFieldStructure.php b/modules/Administration/ImportCustomFieldStructure.php new file mode 100644 index 00000000..be6efb59 --- /dev/null +++ b/modules/Administration/ImportCustomFieldStructure.php @@ -0,0 +1,86 @@ + +
    +
    + + + {$mod_strings['LBL_IMPORT_CUSTOM_FIELDS_STRUCT']}: + +
    +EOQ; + + + }else{ + + $fmd = new FieldsMetaData(); + + echo $mod_strings['LBL_ICF_DROPPING'] . '
    '; + $lines = file($_FILES['sugfile']['tmp_name']); + $cur = array(); + foreach($lines as $line){ + + if(trim($line) == 'DONE'){ + $fmd->new_with_id = true; + echo 'Adding:'.$fmd->custom_module . '-'. $fmd->name. '
    '; + $fmd->db->query("DELETE FROM $fmd->table_name WHERE id='$fmd->id'"); + $fmd->save(false); + $fmd = new FieldsMetaData(); + + + + }else{ + + $ln = explode(':::', $line ,2); + if(sizeof($ln) == 2){ + $KEY = trim($ln[0]); + $fmd->$KEY = trim($ln[1]); + } + } + + } + $_REQUEST['run'] = true; + $result = $fmd->db->query("SELECT count(*) field_count FROM $fmd->table_name"); + $row = $fmd->db->fetchByAssoc($result); + echo 'Total Custom Fields :' . $row['field_count'] . '
    '; + include('modules/Administration/UpgradeFields.php'); + } +?> diff --git a/modules/Administration/Locale.php b/modules/Administration/Locale.php new file mode 100644 index 00000000..7193155c --- /dev/null +++ b/modules/Administration/Locale.php @@ -0,0 +1,121 @@ +".translate('LBL_MODULE_NAME','Administration')."", + $mod_strings['LBL_MANAGE_LOCALE'], + ), + false + ); + +$cfg = new Configurator(); +$sugar_smarty = new Sugar_Smarty(); +$errors = ''; + +/////////////////////////////////////////////////////////////////////////////// +//// HANDLE CHANGES +if(isset($_REQUEST['process']) && $_REQUEST['process'] == 'true') { + if(isset($_REQUEST['collation']) && !empty($_REQUEST['collation'])) { + //kbrill Bug #14922 + if(array_key_exists('collation', $sugar_config['dbconfigoption']) && $_REQUEST['collation'] != $sugar_config['dbconfigoption']['collation']) { + $GLOBALS['db']->disconnect(); + $GLOBALS['db']->connect(); + } + + $cfg->config['dbconfigoption']['collation'] = $_REQUEST['collation']; + } + $cfg->populateFromPost(); + $cfg->handleOverride(); + header('Location: index.php?module=Administration&action=index'); +} + +/////////////////////////////////////////////////////////////////////////////// +//// DB COLLATION +if($GLOBALS['db']->dbType == 'mysql') { + // set sugar default if not set from before + if(!isset($sugar_config['dbconfigoption']['collation'])) { + $sugar_config['dbconfigoption']['collation'] = 'utf8_general_ci'; + } + + $sugar_smarty->assign('dbType', 'mysql'); + $q = "SHOW COLLATION LIKE 'utf8%'"; + $r = $GLOBALS['db']->query($q); + $collationOptions = ''; + while($a = $GLOBALS['db']->fetchByAssoc($r)) { + $selected = ''; + if($sugar_config['dbconfigoption']['collation'] == $a['Collation']) { + $selected = " SELECTED"; + } + $collationOptions .= "\n"; + } + $sugar_smarty->assign('collationOptions', $collationOptions); +} +//// END DB COLLATION +/////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +//// PAGE OUTPUT +$sugar_smarty->assign('MOD', $mod_strings); +$sugar_smarty->assign('APP', $app_strings); +$sugar_smarty->assign('APP_LIST', $app_list_strings); +$sugar_smarty->assign('LANGUAGES', get_languages()); +$sugar_smarty->assign("JAVASCRIPT",get_set_focus_js()); +$sugar_smarty->assign('config', $sugar_config); +$sugar_smarty->assign('error', $errors); +$sugar_smarty->assign("exportCharsets", get_select_options_with_id($locale->getCharsetSelect(), $sugar_config['default_export_charset'])); +//$sugar_smarty->assign('salutation', 'Mr.'); +//$sugar_smarty->assign('first_name', 'John'); +//$sugar_smarty->assign('last_name', 'Doe'); +$sugar_smarty->assign('getNameJs', $locale->getNameJs()); + +$sugar_smarty->display('modules/Administration/Locale.tpl'); + +?> \ No newline at end of file diff --git a/modules/Administration/Locale.tpl b/modules/Administration/Locale.tpl new file mode 100644 index 00000000..7f4a4b24 --- /dev/null +++ b/modules/Administration/Locale.tpl @@ -0,0 +1,217 @@ +{* + +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + + + +*} + + + +{/literal} +
    +
    + +{$error.main} + + + + + +
    + +  
    + + + + + + + + + + + + + + + + + + + + + + + +

    {$MOD.LBL_LOCALE_DEFAULT_SYSTEM_SETTINGS}

    {$MOD.LBL_LOCALE_DEFAULT_DATE_FORMAT}: + {html_options name='default_date_format' selected=$config.default_date_format options=$config.date_formats} + {$MOD.LBL_LOCALE_DEFAULT_TIME_FORMAT}: + {html_options name='default_time_format' selected=$config.default_time_format options=$config.time_formats} +
    {$MOD.LBL_LOCALE_DEFAULT_LANGUAGE}: + {html_options name='default_language' selected=$config.default_language options=$LANGUAGES} +
    {$MOD.LBL_LOCALE_DEFAULT_NAME_FORMAT}: + +
    + {$MOD.LBL_LOCALE_NAME_FORMAT_DESC} +
    {$MOD.LBL_LOCALE_EXAMPLE_NAME_FORMAT}:
    + + + + + + + + + + + + + + + + + + + + + + +

    {$MOD.LBL_LOCALE_DEFAULT_CURRENCY}

    {$MOD.LBL_LOCALE_DEFAULT_CURRENCY_NAME}: + + {$MOD.LBL_LOCALE_DEFAULT_CURRENCY_SYMBOL}: + +
    {$MOD.LBL_LOCALE_DEFAULT_CURRENCY_ISO4217}: + + {$MOD.LBL_LOCALE_DEFAULT_NUMBER_GROUPING_SEP}: + +
    {$MOD.LBL_LOCALE_DEFAULT_DECIMAL_SEP}: + +
    + + + + + + + + + + + + + {if !empty($config.disable_export)} + {assign var='disable_export_checked' value='CHECKED'} + {else} + {assign var='disable_export_checked' value=''} + {/if} + + + {if !empty($config.admin_export_only)} + {assign var='admin_export_only_checked' value='CHECKED'} + {else} + {assign var='admin_export_only_checked' value=''} + {/if} + + + +

    {$MOD.EXPORT}

    {$MOD.EXPORT_DELIMITER}: + + {$MOD.EXPORT_CHARSET}: + + {$MOD.DISABLE_EXPORT}: {$MOD.ADMIN_EXPORT_ONLY}:
    + + +{if $dbType == 'mysql'} + + + + + + + + +
    +

    + {$MOD.LBL_LOCALE_DB_COLLATION_TITLE} +

    +
    + {$MOD.LBL_LOCALE_DB_COLLATION} + + +
    + + + +{/if} +
    + +   +
    +{$JAVASCRIPT} +
    + + diff --git a/modules/Administration/Menu.php b/modules/Administration/Menu.php new file mode 100644 index 00000000..91dc5c07 --- /dev/null +++ b/modules/Administration/Menu.php @@ -0,0 +1,46 @@ +".translate('LBL_MODULE_NAME','Administration')."", + $mod_strings['LBL_MANAGE_PASSWORD_TITLE'], + ), + false + ); +require_once('modules/Configurator/Configurator.php'); +$configurator = new Configurator(); +$sugarConfig = SugarConfig::getInstance(); +$focus = new Administration(); +$configurator->parseLoggerSettings(); +$valid_public_key= true; +if(!empty($_POST['saveConfig'])){ + if ($_POST['captcha_on'] == '1'){ + $handle = @fopen("http://api.recaptcha.net/challenge?k=".$_POST['captcha_public_key']."&cachestop=35235354", "r"); + $buffer =''; + if ($handle) { + while (!feof($handle)) { + $buffer .= fgets($handle, 4096); + } + fclose($handle); + } + $valid_public_key= substr($buffer, 1, 4) == 'var '? true : false; + } + if ($valid_public_key){ + if (isset($_REQUEST['system_ldap_enabled']) && $_REQUEST['system_ldap_enabled'] == 'on') { + $_POST['system_ldap_enabled'] = 1; + clearPasswordSettings(); + } + else + $_POST['system_ldap_enabled'] = 0; + + + + if (isset($_REQUEST['authenticationClass'])) { + + $configurator->useAuthenticationClass = true; + } + + + if (isset($_REQUEST['ldap_group_checkbox']) && $_REQUEST['ldap_group_checkbox'] == 'on') + $_POST['ldap_group'] = 1; + else + $_POST['ldap_group'] = 0; + + if (isset($_REQUEST['ldap_authentication_checkbox']) && $_REQUEST['ldap_authentication_checkbox'] == 'on') + $_POST['ldap_authentication'] = 1; + else + $_POST['ldap_authentication'] = 0; + + if( isset($_REQUEST['passwordsetting_lockoutexpirationtime']) && is_numeric($_REQUEST['passwordsetting_lockoutexpirationtime']) ) + $_POST['passwordsetting_lockoutexpiration'] = 2; + + $configurator->saveConfig(); + + $focus->saveConfig(); + + header('Location: index.php?module=Administration&action=index'); + } +} + +$focus->retrieveSettings(); + + +require_once('include/SugarLogger/SugarLogger.php'); +$sugar_smarty = new Sugar_Smarty(); + +// if no IMAP libraries available, disable Save/Test Settings +if(!function_exists('imap_open')) $sugar_smarty->assign('IE_DISABLED', 'DISABLED'); + +$config_strings=return_module_language($GLOBALS['current_language'],'Configurator'); +$sugar_smarty->assign('CONF', $config_strings); +$sugar_smarty->assign('MOD', $mod_strings); +$sugar_smarty->assign('APP', $app_strings); +$sugar_smarty->assign('APP_LIST', $app_list_strings); +$sugar_smarty->assign('config', $configurator->config); +$sugar_smarty->assign('error', $configurator->errors); +$sugar_smarty->assign('LANGUAGES', get_languages()); +$sugar_smarty->assign("settings", $focus->settings); + +$sugar_smarty->assign('saml_enabled_checked', false); + +//echo "sugar_config[authenticationClass]: " . $sugar_config['authenticationClass']; +//if (array_key_exists('authenticationClass', $sugar_config) && $sugar_config['authenticationClass'] == 'SAMLAuthenticate') { +// $sugar_smarty->assign('saml_enabled_checked', true); +//} else { +// $sugar_smarty->assign('saml_enabled_checked', false); +//} + + +if(!function_exists('mcrypt_cbc')){ + $sugar_smarty->assign("LDAP_ENC_KEY_READONLY", 'readonly'); + $sugar_smarty->assign("LDAP_ENC_KEY_DESC", $config_strings['LDAP_ENC_KEY_NO_FUNC_DESC']); +}else{ + $sugar_smarty->assign("LDAP_ENC_KEY_DESC", $config_strings['LBL_LDAP_ENC_KEY_DESC']); +} +$sugar_smarty->assign("settings", $focus->settings); + +if ($valid_public_key){ + if(!empty($focus->settings['captcha_on'])){ + $sugar_smarty->assign("CAPTCHA_CONFIG_DISPLAY", 'inline'); + }else{ + $sugar_smarty->assign("CAPTCHA_CONFIG_DISPLAY", 'none'); + } +}else{ + $sugar_smarty->assign("CAPTCHA_CONFIG_DISPLAY", 'inline'); +} + +$sugar_smarty->assign("VALID_PUBLIC_KEY", $valid_public_key); + + + +$res=$GLOBALS['sugar_config']['passwordsetting']; + + +require_once('include/SugarPHPMailer.php'); +$mail = new SugarPHPMailer(); +$mail->setMailerForSystem(); +if($mail->Mailer == 'smtp' && $mail->Host ==''){ + $sugar_smarty->assign("SMTP_SERVER_NOT_SET", '1'); + } +else + $sugar_smarty->assign("SMTP_SERVER_NOT_SET", '0'); + +$focus = new InboundEmail(); +$focus->checkImap(); +$storedOptions = unserialize(base64_decode($focus->stored_options)); +$email_templates_arr = get_bean_select_array(true, 'EmailTemplate','name', '','name',true); +$create_case_email_template = (isset($storedOptions['create_case_email_template'])) ? $storedOptions['create_case_email_template'] : ""; +$TMPL_DRPDWN_LOST =get_select_options_with_id($email_templates_arr, $res['lostpasswordtmpl']); +$TMPL_DRPDWN_GENERATE =get_select_options_with_id($email_templates_arr, $res['generatepasswordtmpl']); + +$sugar_smarty->assign("TMPL_DRPDWN_LOST", $TMPL_DRPDWN_LOST); +$sugar_smarty->assign("TMPL_DRPDWN_GENERATE", $TMPL_DRPDWN_GENERATE); + +$sugar_smarty->display('modules/Administration/PasswordManager.tpl'); +?> \ No newline at end of file diff --git a/modules/Administration/PasswordManager.tpl b/modules/Administration/PasswordManager.tpl new file mode 100644 index 00000000..159eb35a --- /dev/null +++ b/modules/Administration/PasswordManager.tpl @@ -0,0 +1,685 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + + +*} + +
    + + + +{$error.main} + + + + + +
    + +   +
    + + + + +
    + + + + + + + + + {if !($config.passwordsetting.SystemGeneratedPasswordON)} + {assign var='smtp_warning' value='none'} + {/if} + + + + + + + + + + +
    +

    + {$MOD.LBL_PASSWORD_SYST_GENERATED_TITLE} +

    +
    + {$MOD.LBL_PASSWORD_SYST_GENERATED_PWD_ON}: {sugar_help text=$MOD.LBL_PASSWORD_SYST_GENERATED_PWD_HELP WIDTH=400} + + {if ($config.passwordsetting.SystemGeneratedPasswordON ) == '1'} + {assign var='SystemGeneratedPasswordON' value='CHECKED'} + {else} + {assign var='SystemGeneratedPasswordON' value=''} + {/if} + + +
    + {if $SMTP_SERVER_NOT_SET}    {$MOD.ERR_SMTP_SERVER_NOT_SET}
    {/if} +     {$MOD.LBL_EMAIL_ADDRESS_REQUIRED_FOR_FEATURE}
    +
    + {$MOD.LBL_PASSWORD_SYST_EXPIRATION} +
    + + + {assign var='systexplogin' value=''} + {assign var='systexptime' value=''} + {assign var='systexpnone' value=''} + {if ($config.passwordsetting.systexpiration) == '0' || $config.passwordsetting.systexpiration==''} + {assign var='systexpnone' value='CHECKED'} + {/if} + {if ($config.passwordsetting.systexpiration) == '1'} + {assign var='systexptime' value='CHECKED'} + {/if} + {if ($config.passwordsetting.systexpiration) == '2'} + {assign var='systexplogin' value='CHECKED'} + {/if} + + + + +
    + + {$MOD.LBL_UW_NONE} + + + {$MOD.LBL_PASSWORD_EXP_IN} + {assign var='sdays' value=''} + {assign var='sweeks' value=''} + {assign var='smonths' value=''} + {if ($config.passwordsetting.systexpirationtype ) == '1'} + {assign var='sdays' value='SELECTED'} + {/if} + {if ($config.passwordsetting.systexpirationtype ) == '7'} + {assign var='sweeks' value='SELECTED'} + {/if} + {if ($config.passwordsetting.systexpirationtype ) == '30'} + {assign var='smonths' value='SELECTED'} + {/if} + + + + + {$MOD.LBL_PASSWORD_EXP_AFTER} + + {$MOD.LBL_PASSWORD_LOGINS} +
    +
    + + + + + + + + + + {if !($config.passwordsetting.forgotpasswordON)} + {assign var='smtp_warning_2' value='none'} + {/if} + + + + + + + + + {if !empty($settings.captcha_on) || !($VALID_PUBLIC_KEY)} + {assign var='captcha_checked' value='CHECKED'} + {else} + {assign var='captcha_checked' value=''} + {/if} + + + +

    {$MOD.LBL_PASSWORD_USER_RESET}

    +
    {$MOD.LBL_PASSWORD_FORGOT_FEATURE}: {sugar_help text=$MOD.LBL_PASSWORD_FORGOT_FEATURE_HELP WIDTH=400} + {if ($config.passwordsetting.forgotpasswordON ) == '1'} + {assign var='forgotpasswordON' value='CHECKED'} + {else} + {assign var='forgotpasswordON' value=''} + {/if} + + +
    + {if $SMTP_SERVER_NOT_SET}    {$MOD.ERR_SMTP_SERVER_NOT_SET}
    {/if} +     {$MOD.LBL_EMAIL_ADDRESS_REQUIRED_FOR_FEATURE}
    +
    {$MOD.LBL_PASSWORD_LINK_EXPIRATION}: {sugar_help text=$MOD.LBL_PASSWORD_LINK_EXPIRATION_HELP WIDTH=400} + + + + {assign var='linkexptime' value=''} + {assign var='linkexpnone' value=''} + {if ($config.passwordsetting.linkexpiration) == '0'} + {assign var='linkexpnone' value='CHECKED'} + {/if} + {if ($config.passwordsetting.linkexpiration) == '1'} + {assign var='linkexptime' value='CHECKED'} + {/if} + + + + +
    + + {$MOD.LBL_UW_NONE} + + + {$MOD.LBL_PASSWORD_LINK_EXP_IN} + {assign var='ldays' value=''} + {assign var='lweeks' value=''} + {assign var='lmonths' value=''} + {if ($config.passwordsetting.linkexpirationtype ) == '1'} + {assign var='ldays' value='SELECTED'} + {/if} + {if ($config.passwordsetting.linkexpirationtype ) == '60'} + {assign var='lweeks' value='SELECTED'} + {/if} + {if ($config.passwordsetting.linkexpirationtype ) == '1440'} + {assign var='lmonths' value='SELECTED'} + {/if} + + + +
    +
    {$MOD.ENABLE_CAPTCHA}: {sugar_help text=$MOD.LBL_CAPTCHA_HELP_TEXT WIDTH=400}
    + + + + + {if !($VALID_PUBLIC_KEY)} + + {/if} +
    +
    + + + + + + + +
    {$MOD.LBL_PUBLIC_KEY}*{$MOD.LBL_PRIVATE_KEY}*
    +
    +
    {$MOD.ERR_PUBLIC_CAPTCHA_KEY}
    + + + + + + + + + + + + + + + + + + + + + +
    +

    + {$MOD.LBL_PASSWORD_TEMPLATE} +

    +
    {$MOD.LBL_PASSWORD_GENERATE_TEMPLATE_MSG}: + + + + + +
    {$MOD.LBL_PASSWORD_LOST_TEMPLATE_MSG}: + + + + + +
    + + + {if !empty($settings.system_ldap_enabled)} + {assign var='system_ldap_enabled_checked' value='CHECKED'} + {assign var='ldap_display' value='inline'} + {else} + {assign var='system_ldap_enabled_checked' value=''} + {assign var='ldap_display' value='none'} + {/if} + + + + +
    + + + + + + + + + +

    {$MOD.LBL_LDAP_TITLE}

    + {$MOD.LBL_LDAP_ENABLE}{sugar_help text=$MOD.LBL_LDAP_HELP_TXT} +   
    + + + {$settings.proxy_host} + + {$settings.proxy_port} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {if !empty($settings.ldap_auto_create_users)} + {assign var='ldap_auto_create_users_checked' value='CHECKED'} + {else} + {assign var='ldap_auto_create_users_checked' value=''} + {/if} + + + + + + + + + + +
    {$MOD.LBL_LDAP_SERVER_HOSTNAME} {sugar_help text=$MOD.LBL_LDAP_SERVER_HOSTNAME_DESC}{$MOD.LBL_LDAP_SERVER_PORT} {sugar_help text=$MOD.LBL_LDAP_SERVER_PORT_DESC}
    {$MOD.LBL_LDAP_USER_DN} {sugar_help text=$MOD.LBL_LDAP_USER_DN_DESC}{$MOD.LBL_LDAP_USER_FILTER} {sugar_help text=$MOD.LBL_LDAP_USER_FILTER_DESC}
    {$MOD.LBL_LDAP_BIND_ATTRIBUTE} {sugar_help text=$MOD.LBL_LDAP_BIND_ATTRIBUTE_DESC} {$MOD.LBL_LDAP_LOGIN_ATTRIBUTE} {sugar_help text=$MOD.LBL_LDAP_LOGIN_ATTRIBUTE_DESC}
    {$MOD.LBL_LDAP_GROUP_MEMBERSHIP} {sugar_help text=$MOD.LBL_LDAP_GROUP_MEMBERSHIP_DESC} + {if !empty($settings.ldap_group)} + {assign var='ldap_group_checked' value='CHECKED'} + {assign var='ldap_group_display' value=''} + {else} + {assign var='ldap_group_checked' value=''} + {assign var='ldap_group_display' value='none'} + {/if} + +
    + + + + + + + + + + + + + + +
    {$MOD.LBL_LDAP_GROUP_DN} {sugar_help text=$MOD.LBL_LDAP_GROUP_DN_DESC}{$MOD.LBL_LDAP_GROUP_NAME} {sugar_help text=$MOD.LBL_LDAP_GROUP_NAME_DESC}
    {$MOD.LBL_LDAP_GROUP_USER_ATTR} {sugar_help text=$MOD.LBL_LDAP_GROUP_USER_ATTR_DESC} {$MOD.LBL_LDAP_GROUP_ATTR} {sugar_help text=$MOD.LBL_LDAP_GROUP_ATTR_DESC}
    +
    +
    +
    {$MOD.LBL_LDAP_AUTHENTICATION} {sugar_help text=$MOD.LBL_LDAP_AUTHENTICATION_DESC} + {if !empty($settings.ldap_authentication)} + {assign var='ldap_authentication_checked' value='CHECKED'} + {assign var='ldap_authentication_display' value=''} + {else} + {assign var='ldap_authentication_checked' value=''} + {assign var='ldap_authentication_display' value='none'} + {/if} + +
    + + + + + + + + +
    {$MOD.LBL_LDAP_ADMIN_USER} {sugar_help text=$MOD.LBL_LDAP_ADMIN_USER_DESC}{$MOD.LBL_LDAP_ADMIN_PASSWORD}
    +
    +
    +
    {$MOD.LBL_LDAP_AUTO_CREATE_USERS} {sugar_help text=$MOD.LBL_LDAP_AUTO_CREATE_USERS_DESC}
    {$MOD.LBL_LDAP_ENC_KEY} {sugar_help text=$LDAP_ENC_KEY_DESC}
    +
    +
    + + + {if !empty($config.authenticationClass) && $config.authenticationClass === 'SAMLAuthenticate'} + {assign var='saml_enabled_checked' value='CHECKED'} + {assign var='saml_display' value='inline'} + {else} + {assign var='saml_enabled_checked' value=''} + {assign var='saml_display' value='none'} + {/if} + + + + + +
    + + + + + + + + + +

    {$MOD.LBL_SAML_TITLE}

    + {$MOD.LBL_SAML_ENABLE}{sugar_help text=$MOD.LBL_SAML_HELP_TXT} + + + +   
    + + + + + + + + {$settings.proxy_host} + + + + + +
    {$MOD.LBL_SAML_LOGIN_URL} {sugar_help text=$MOD.LBL_SAML_LOGIN_URL_DESC}
    {$MOD.LBL_SAML_CERT} {sugar_help text=$MOD.LBL_SAML_CERT_DESC}
    + + +
    + +
    +
    + +   +
    +
    + + + + +
    +{$JAVASCRIPT} + + +{if !($VALID_PUBLIC_KEY)} + +{/if} + + +{literal} + + +{/literal} \ No newline at end of file diff --git a/modules/Administration/QuickRepairAndRebuild.php b/modules/Administration/QuickRepairAndRebuild.php new file mode 100644 index 00000000..107293ec --- /dev/null +++ b/modules/Administration/QuickRepairAndRebuild.php @@ -0,0 +1,470 @@ +module_list= $modules; + $this->show_output = $show_output; + $this->actions = $selected_actions; + $this->actions[] = 'repairDatabase'; + $this->execute=$autoexecute; + + //clear vardefs always.. + $this->clearVardefs(); + //first clear the language cache. + $this->clearLanguageCache(); + foreach ($this->actions as $current_action) + switch($current_action) + { + case 'repairDatabase': + if(in_array($mod_strings['LBL_ALL_MODULES'], $this->module_list)) + $this->repairDatabase(); + else + $this->repairDatabaseSelectModules(); + break; + case 'rebuildExtensions': + $this->rebuildExtensions(); + break; + case 'clearTpls': + $this->clearTpls(); + break; + case 'clearJsFiles': + $this->clearJsFiles(); + break; + case 'clearDashlets': + $this->clearDashlets(); + break; + case 'clearSugarFeedCache': + $this->clearSugarFeedCache(); + break; + case 'clearThemeCache': + $this->clearThemeCache(); + break; + case 'clearVardefs': + $this->clearVardefs(); + break; + case 'clearJsLangFiles': + $this->clearJsLangFiles(); + break; + case 'rebuildAuditTables': + $this->rebuildAuditTables(); + break; + case 'clearSearchCache': + $this->clearSearchCache(); + break; + case 'clearAll': + $this->clearTpls(); + $this->clearJsFiles(); + $this->clearVardefs(); + $this->clearJsLangFiles(); + $this->clearLanguageCache(); + $this->clearDashlets(); + $this->clearSugarFeedCache(); + $this->clearSmarty(); + $this->clearThemeCache(); + $this->clearXMLfiles(); + $this->clearSearchCache(); + $this->clearExternalAPICache(); + $this->rebuildExtensions(); + $this->rebuildAuditTables(); + $this->repairDatabase(); + break; + } + } + + /////////////OLD + + + public function repairDatabase() + { + global $dictionary, $mod_strings; + if(false == $this->show_output) + $_REQUEST['repair_silent']='1'; + $_REQUEST['execute']=$this->execute; + $GLOBALS['reload_vardefs'] = true; + $hideModuleMenu = true; + include_once('modules/Administration/repairDatabase.php'); + } + + public function repairDatabaseSelectModules() + { + global $current_user, $mod_strings, $dictionary; + set_time_limit(3600); + + include('include/modules.php'); //bug 15661 + $db = DBManagerFactory::getInstance(); + + if (is_admin($current_user) || is_admin_for_any_module($current_user)) + { + $export = false; + if($this->show_output) echo getClassicModuleTitle($mod_strings['LBL_REPAIR_DATABASE'], array($mod_strings['LBL_REPAIR_DATABASE']), false); + if($this->show_output) { + echo "

    {$mod_strings['LBL_REPAIR_DATABASE_PROCESSING']}

    "; + ob_flush(); + } + $sql = ''; + if($this->module_list && !in_array($mod_strings['LBL_ALL_MODULES'],$this->module_list)) + { + $repair_related_modules = array_keys($dictionary); + //repair DB + $dm = !empty($GLOBALS['sugar_config']['developerMode']); + $GLOBALS['sugar_config']['developerMode'] = true; + foreach($this->module_list as $bean_name) + { + + if (isset($beanFiles[$bean_name]) && file_exists($beanFiles[$bean_name])) + { + require_once($beanFiles[$bean_name]); + $GLOBALS['reload_vardefs'] = true; + $focus = new $bean_name (); + #30273 + if($focus->disable_vardefs == false) { + include('modules/' . $focus->module_dir . '/vardefs.php'); + + + if($this->show_output) + print_r("

    " .$mod_strings['LBL_REPAIR_DB_FOR'].' '. $bean_name . "

    "); + $sql .= $db->repairTable($focus, $this->execute); + } + } + } + + $GLOBALS['sugar_config']['developerMode'] = $dm; + + if ($this->show_output) echo ""; + if (isset ($sql) && !empty ($sql)) + { + $qry_str = ""; + foreach (explode("\n", $sql) as $line) { + if (!empty ($line) && substr($line, -2) != "*/") { + $line .= ";"; + } + + $qry_str .= $line . "\n"; + } + if ($this->show_output){ + echo "

    {$mod_strings['LBL_REPAIR_DATABASE_DIFFERENCES']}

    "; + echo "

    {$mod_strings['LBL_REPAIR_DATABASE_TEXT']}

    "; + + echo "
    "; + echo ""; + echo "
    "; + } + } + else + if ($this->show_output) echo "

    {$mod_strings['LBL_REPAIR_DATABASE_SYNCED']}

    "; + } + + } + else { + sugar_die($GLOBALS['app_strings']['ERR_NOT_ADMIN']); + } + } + + public function rebuildExtensions() + { + global $mod_strings; + if($this->show_output) echo $mod_strings['LBL_QR_REBUILDEXT']; + global $current_user; + require_once('ModuleInstall/ModuleInstaller.php'); + $mi = new ModuleInstaller(); + $mi->rebuild_all(!$this->show_output); + + // Remove the "Rebuild Extensions" red text message on admin logins + + if($this->show_output) echo $mod_strings['LBL_REBUILD_REL_UPD_WARNING']; + + // clear the database row if it exists (just to be sure) + $query = "DELETE FROM versions WHERE name='Rebuild Extensions'"; + $GLOBALS['log']->info($query); + $GLOBALS['db']->query($query); + + // insert a new database row to show the rebuild extensions is done + $id = create_guid(); + $gmdate = gmdate('Y-m-d H:i:s'); + $date_entered = db_convert("'$gmdate'", 'datetime'); + $query = 'INSERT INTO versions (id, deleted, date_entered, date_modified, modified_user_id, created_by, name, file_version, db_version) ' + . "VALUES ('$id', '0', $date_entered, $date_entered, '1', '1', 'Rebuild Extensions', '4.0.0', '4.0.0')"; + $GLOBALS['log']->info($query); + $GLOBALS['db']->query($query); + + // unset the session variable so it is not picked up in DisplayWarnings.php + if(isset($_SESSION['rebuild_extensions'])) { + unset($_SESSION['rebuild_extensions']); + } + } + + //Cache Clear Methods + public function clearSmarty() + { + global $mod_strings; + if($this->show_output) echo "

    {$mod_strings['LBL_QR_CLEARSMARTY']}

    "; + $this->_clearCache($GLOBALS['sugar_config']['cache_dir'].'smarty/templates_c', '.tpl.php'); + } + public function clearXMLfiles() + { + global $mod_strings; + if($this->show_output) echo "

    {$mod_strings['LBL_QR_XMLFILES']}

    "; + $this->_clearCache($GLOBALS['sugar_config']['tmp_dir'], '.xml'); + + include('modules/Versions/ExpectedVersions.php'); + + global $expect_versions; + + if (isset($expect_versions['Chart Data Cache'])) { + $version = new Version(); + $version->retrieve_by_string_fields(array('name'=>'Chart Data Cache')); + + $version->name = $expect_versions['Chart Data Cache']['name']; + $version->file_version = $expect_versions['Chart Data Cache']['file_version']; + $version->db_version = $expect_versions['Chart Data Cache']['db_version']; + $version->save(); + } + } + public function clearDashlets() + { + global $mod_strings; + if($this->show_output) echo "

    {$mod_strings['LBL_QR_CLEARDASHLET']}

    "; + $this->_clearCache($GLOBALS['sugar_config']['cache_dir'].'dashlets', '.php'); + } + public function clearThemeCache() + { + global $mod_strings; + if($this->show_output) echo "

    {$mod_strings['LBL_QR_CLEARTHEMECACHE']}

    "; + SugarThemeRegistry::clearAllCaches(); + } + public function clearSugarFeedCache() + { + global $mod_strings; + if($this->show_output) echo "

    {$mod_strings['LBL_QR_CLEARSUGARFEEDCACHE']}

    "; + + SugarFeed::flushBackendCache(); + } + public function clearTpls() + { + global $mod_strings; + if($this->show_output) echo "

    {$mod_strings['LBL_QR_CLEARTEMPLATE']}

    "; + if(!in_array( translate('LBL_ALL_MODULES'),$this->module_list) && !empty($this->module_list)) + { + foreach($this->module_list as $module_name_singular ) + $this->_clearCache($GLOBALS['sugar_config']['cache_dir'].'modules/'.$this->_getModuleNamePlural($module_name_singular), '.tpl'); + } + else + $this->_clearCache($GLOBALS['sugar_config']['cache_dir'].'modules', '.tpl'); + } + public function clearVardefs() + { + global $mod_strings; + if($this->show_output) echo "

    {$mod_strings['LBL_QR_CLEARVADEFS']}

    "; + if(!empty($this->module_list) && is_array($this->module_list) && !in_array( translate('LBL_ALL_MODULES'),$this->module_list)) + { + foreach($this->module_list as $module_name_singular ) + $this->_clearCache($GLOBALS['sugar_config']['cache_dir'].'modules/'.$this->_getModuleNamePlural($module_name_singular), 'vardefs.php'); + } + else + $this->_clearCache($GLOBALS['sugar_config']['cache_dir'].'modules', 'vardefs.php'); + } + public function clearJsFiles() + { + global $mod_strings; + if($this->show_output) echo "

    {$mod_strings['LBL_QR_CLEARJS']}

    "; + + if(!in_array( translate('LBL_ALL_MODULES'),$this->module_list) && !empty($this->module_list)) + { + foreach($this->module_list as $module_name_singular ) + $this->_clearCache($GLOBALS['sugar_config']['cache_dir'].'modules/'.$this->_getModuleNamePlural($module_name_singular), '.js'); + } + + else + $this->_clearCache($GLOBALS['sugar_config']['cache_dir'].'modules', '.js'); + + } + public function clearJsLangFiles() + { + global $mod_strings; + if($this->show_output) echo "

    {$mod_strings['LBL_QR_CLEARJSLANG']}

    "; + if(!in_array(translate('LBL_ALL_MODULES'),$this->module_list ) && !empty($this->module_list)) + { + foreach($this->module_list as $module_name_singular ) + $this->_clearCache($GLOBALS['sugar_config']['cache_dir'].'jsLanguage/'.$this->_getModuleNamePlural($module_name_singular), '.js'); + } + else + $this->_clearCache($GLOBALS['sugar_config']['cache_dir'].'jsLanguage', '.js'); + } + /** + * Remove the language cache files from cache/modules//language + */ + public function clearLanguageCache() + { + global $mod_strings; + + if($this->show_output) echo "

    {$mod_strings['LBL_QR_CLEARLANG']}

    "; + //clear cache using the list $module_list_from_cache + if ( !empty($this->module_list) && is_array($this->module_list) ) { + if( in_array(translate('LBL_ALL_MODULES'), $this->module_list)) + { + LanguageManager::clearLanguageCache(); + } + else { //use the modules selected thrut the select list. + foreach($this->module_list as $module_name) + LanguageManager::clearLanguageCache($module_name); + } + } + } + + /** + * Remove the cached unified_search_modules.php and unified_search_modules_display.php files + */ + public function clearSearchCache() { + global $mod_strings, $sugar_config; + if($this->show_output) echo "

    {$mod_strings['LBL_QR_CLEARSEARCH']}

    "; + $search_dir='cache/'; + if (!empty($sugar_config['cache_dir'])) { + $search_dir=$sugar_config['cache_dir']; + } + $src_file = $search_dir . 'modules/unified_search_modules.php'; + if(file_exists($src_file)) { + unlink( "$src_file" ); + } + + $src_file = $search_dir . 'modules/unified_search_modules_display.php'; + if(file_exists($src_file)) { + unlink( "$src_file" ); + } + } + public function clearExternalAPICache() + { + global $mod_strings, $sugar_config; + if($this->show_output) echo "

    {$mod_strings['LBL_QR_CLEAR_EXT_API']}

    "; + require_once('include/externalAPI/ExternalAPIFactory.php'); + ExternalAPIFactory::clearCache(); + } + + ////////////////////////////////////////////////////////////// + /////REPAIR AUDIT TABLES + public function rebuildAuditTables() + { + global $mod_strings; + include('include/modules.php'); //bug 15661 + if($this->show_output) echo "

    {$mod_strings['LBL_QR_REBUILDAUDIT']}

    "; + + if(!in_array( translate('LBL_ALL_MODULES'), $this->module_list) && !empty($this->module_list)) + { + foreach ($this->module_list as $bean_name){ + if( isset($beanFiles[$bean_name]) && file_exists($beanFiles[$bean_name])) { + require_once($beanFiles[$bean_name]); + $this->_rebuildAuditTablesHelper(new $bean_name()); + } + } + } else if(in_array(translate('LBL_ALL_MODULES'), $this->module_list)) { + foreach ($beanFiles as $bean => $file){ + if( file_exists($file)) { + require_once($file); + $this->_rebuildAuditTablesHelper(new $bean()); + } + } + } + if($this->show_output) echo $mod_strings['LBL_DONE']; + } + + private function _rebuildAuditTablesHelper($focus) + { + global $mod_strings; + + // skip if not a SugarBean object + if ( !($focus instanceOf SugarBean) ) + return; + + if ($focus->is_AuditEnabled()) { + if (!$focus->db->tableExists($focus->get_audit_table_name())) { + if($this->show_output) echo $mod_strings['LBL_QR_CREATING_TABLE']." ".$focus->get_audit_table_name().' '.$mod_strings['LBL_FOR'].' '. $focus->object_name.'.
    '; + $focus->create_audit_table(); + } else { + if($this->show_output){ + $echo=str_replace('%1$',$focus->object_name,$mod_strings['LBL_REBUILD_AUDIT_SKIP']); + echo $echo; + } + } + }else + if($this->show_output) echo $focus->object_name.$mod_strings['LBL_QR_NOT_AUDIT_ENABLED']; + } + + /////////////////////////////////////////////////////////////// + ////END REPAIR AUDIT TABLES + + + /////////////////////////////////////////////////////////////// + //// Recursively unlink all files of the given $extension in the given $thedir. + // + private function _clearCache($thedir, $extension) + { + if ($current = @opendir($thedir)) { + while (false !== ($children = readdir($current))) { + if ($children != "." && $children != "..") { + if (is_dir($thedir . "/" . $children)) { + $this->_clearCache($thedir . "/" . $children, $extension); + } + elseif (is_file($thedir . "/" . $children) && (substr_count($children, $extension))) { + unlink($thedir . "/" . $children); + } + } + } + } + } + ///////////////////////////////////////////////////////////// + //////// + private function _getModuleNamePlural($module_name_singular) + { + global $beanList; + while ($curr_module = current($beanList)) + { + if ($curr_module == $module_name_singular) + return key($beanList); //name of the module, plural. + next($beanList); + } + } +} diff --git a/modules/Administration/RebuildAudit.php b/modules/Administration/RebuildAudit.php new file mode 100644 index 00000000..e8a16d11 --- /dev/null +++ b/modules/Administration/RebuildAudit.php @@ -0,0 +1,58 @@ +'; +foreach ($beanFiles as $bean => $file) +{ + if(strlen($file) > 0 && file_exists($file)) { + require_once($file); + $focus = new $bean(); + if ($focus->is_AuditEnabled()) { + if (!$focus->db->tableExists($focus->get_audit_table_name())) { + printf($mod_strings['LBL_REBUILD_AUDIT_SEARCH'],$focus->get_audit_table_name(), $focus->object_name); + $focus->create_audit_table(); + } else { + printf($mod_strings['LBL_REBUILD_AUDIT_SKIP'],$focus->object_name); + } + } + } +} +echo $mod_strings['LBL_DONE']; +?> \ No newline at end of file diff --git a/modules/Administration/RebuildConfig.html b/modules/Administration/RebuildConfig.html new file mode 100644 index 00000000..647ff248 --- /dev/null +++ b/modules/Administration/RebuildConfig.html @@ -0,0 +1,58 @@ + + +

    + + + + + + + + + + + + + + + +
    {LBL_CONFIG_CHECK}{CONFIG_CHECK}
    {LBL_PERFORM_REBUILD}
    +

    +

    + diff --git a/modules/Administration/RebuildConfig.php b/modules/Administration/RebuildConfig.php new file mode 100644 index 00000000..da0b7a6f --- /dev/null +++ b/modules/Administration/RebuildConfig.php @@ -0,0 +1,84 @@ +assign('LBL_CONFIG_CHECK', $mod_strings['LBL_CONFIG_CHECK']); +$xtpl->assign('CONFIG_CHECK', $config_check); +$xtpl->assign('LBL_PERFORM_REBUILD', $lbl_rebuild_config); +$xtpl->assign('DISABLE_CONFIG_REBUILD', $disable_config_rebuild); +$xtpl->assign('BTN_PERFORM_REBUILD', $btn_rebuild_config); +$xtpl->parse('main'); +$xtpl->out('main'); +?> diff --git a/modules/Administration/RebuildDashlets.php b/modules/Administration/RebuildDashlets.php new file mode 100644 index 00000000..90cf18b9 --- /dev/null +++ b/modules/Administration/RebuildDashlets.php @@ -0,0 +1,55 @@ +buildCache(); + if( !$silent ) echo '



    ' . $mod_strings['LBL_REBUILD_DASHLETS_DESC_SUCCESS']; +} +else{ + sugar_die($GLOBALS['app_strings']['ERR_NOT_ADMIN']); +} +?> \ No newline at end of file diff --git a/modules/Administration/RebuildExpressionPlugins.php b/modules/Administration/RebuildExpressionPlugins.php new file mode 100644 index 00000000..67e22f1b --- /dev/null +++ b/modules/Administration/RebuildExpressionPlugins.php @@ -0,0 +1,41 @@ +dbType != "oci8") { +// die('Action not supported for your database.'); +} +//find modules that have a full-text index and rebuild it. +global $beanFiles; +foreach ($beanFiles as $beanname=>$beanpath) { + require_once($beanpath); + $focus= new $beanname(); + + //skips beans based on same tables. user, employee and group are an example. + if(empty($focus->table_name) || isset($processed_tables[$focus->table_name])) { + continue; + } else { + $processed_tables[$focus->table_name]=$focus->table_name; + } + + if(!empty($dictionary[$focus->object_name]['indices'])) { + $indices=$dictionary[$focus->object_name]['indices']; + } else { + $indices=array(); + } + + //clean vardef defintions.. removed indexes not value for this dbtype. + //set index name as the key. + $var_indices=array(); + foreach ($indices as $definition) { + //database helpers do not know how to handle full text indices + if ($definition['type']=='fulltext') { + if (isset($definition['db']) and $definition['db'] != $GLOBALS['db']->dbType) { + continue; + } + + echo "Rebuilding Index {$definition['name']}
    "; + $GLOBALS['db']->query('alter index ' .$definition['name'] . " REBUILD"); + } + + } +} +?> diff --git a/modules/Administration/RebuildJSLang.php b/modules/Administration/RebuildJSLang.php new file mode 100644 index 00000000..8b67eeb5 --- /dev/null +++ b/modules/Administration/RebuildJSLang.php @@ -0,0 +1,61 @@ + \ No newline at end of file diff --git a/modules/Administration/RebuildRelationship.php b/modules/Administration/RebuildRelationship.php new file mode 100644 index 00000000..879463a1 --- /dev/null +++ b/modules/Administration/RebuildRelationship.php @@ -0,0 +1,151 @@ +query ( $query ) ; + +//clear cache before proceeding.. +VardefManager::clearVardef () ; + +// loop through all of the modules and create entries in the Relationships table (the relationships metadata) for every standard relationship, that is, relationships defined in the /modules//vardefs.php +// SugarBean::createRelationshipMeta just takes the relationship definition in a file and inserts it as is into the Relationships table +// It does not override or recreate existing relationships +foreach ( $GLOBALS['beanFiles'] as $bean => $file ) +{ + if (strlen ( $file ) > 0 && file_exists ( $file )) + { + if (! class_exists ( $bean )) + { + require ($file) ; + } + $focus = new $bean ( ) ; + if ( $focus instanceOf SugarBean ) { + $table_name = $focus->table_name ; + $empty = '' ; + if (empty ( $_REQUEST [ 'silent' ] )) + echo $mod_strings [ 'LBL_REBUILD_REL_PROC_META' ] . $focus->table_name . "..." ; + SugarBean::createRelationshipMeta ( $focus->getObjectName (), $db, $table_name, $empty, $focus->module_dir ) ; + if (empty ( $_REQUEST [ 'silent' ] )) + echo $mod_strings [ 'LBL_DONE' ] . '
    ' ; + } + } +} + +// do the same for custom relationships (true in the last parameter to SugarBean::createRelationshipMeta) - that is, relationships defined in the custom/modules//Ext/vardefs/ area +foreach ( $GLOBALS['beanFiles'] as $bean => $file ) +{ + //skip this file if it does not exist + if(!file_exists($file)) continue; + + if (! class_exists ( $bean )) + { + require ($file) ; + } + $focus = new $bean ( ) ; + if ( $focus instanceOf SugarBean ) { + $table_name = $focus->table_name ; + $empty = '' ; + if (empty ( $_REQUEST [ 'silent' ] )) + echo $mod_strings [ 'LBL_REBUILD_REL_PROC_C_META' ] . $focus->table_name . "..." ; + SugarBean::createRelationshipMeta ( $focus->getObjectName (), $db, $table_name, $empty, $focus->module_dir, true ) ; + if (empty ( $_REQUEST [ 'silent' ] )) + echo $mod_strings [ 'LBL_DONE' ] . '
    ' ; + } +} + +// finally, whip through the list of relationships defined in TableDictionary.php, that is all the relationships in the metadata directory, and install those + $dictionary = array ( ) ; + require ('modules/TableDictionary.php') ; + //for module installer incase we alredy loaded the table dictionary + if (file_exists ( 'custom/application/Ext/TableDictionary/tabledictionary.ext.php' )) + { + include ('custom/application/Ext/TableDictionary/tabledictionary.ext.php') ; + } + $rel_dictionary = $dictionary ; + foreach ( $rel_dictionary as $rel_name => $rel_data ) + { + $table = $rel_data [ 'table' ] ; + + if (empty ( $_REQUEST [ 'silent' ] )) + echo $mod_strings [ 'LBL_REBUILD_REL_PROC_C_META' ] . $rel_name . "..." ; + SugarBean::createRelationshipMeta ( $rel_name, $db, $table, $rel_dictionary, '' ) ; + if (empty ( $_REQUEST [ 'silent' ] )) + echo $mod_strings [ 'LBL_DONE' ] . '
    ' ; + } + +//clean relationship cache..will be rebuilt upon first access. +if (empty ( $_REQUEST [ 'silent' ] )) + echo $mod_strings [ 'LBL_REBUILD_REL_DEL_CACHE' ] ; +Relationship::delete_cache () ; + +////////////////////////////////////////////////////////////////////////////// +// Remove the "Rebuild Relationships" red text message on admin logins + + +if (empty ( $_REQUEST [ 'silent' ] )) + echo $mod_strings [ 'LBL_REBUILD_REL_UPD_WARNING' ] ; + +// clear the database row if it exists (just to be sure) +$query = "DELETE FROM versions WHERE name='Rebuild Relationships'" ; +$log->info ( $query ) ; +$db->query ( $query ) ; + +// insert a new database row to show the rebuild relationships is done +$id = create_guid () ; +$gmdate = gmdate('Y-m-d H:i:s'); +$date_entered = db_convert ( "'$gmdate'", 'datetime' ) ; +$query = 'INSERT INTO versions (id, deleted, date_entered, date_modified, modified_user_id, created_by, name, file_version, db_version) ' . "VALUES ('$id', '0', $date_entered, $date_entered, '1', '1', 'Rebuild Relationships', '4.0.0', '4.0.0')" ; +$log->info ( $query ) ; +$db->query ( $query ) ; + +// unset the session variable so it is not picked up in DisplayWarnings.php +if (isset ( $_SESSION [ 'rebuild_relationships' ] )) +{ + unset ( $_SESSION [ 'rebuild_relationships' ] ) ; +} + +if (empty ( $_REQUEST [ 'silent' ] )) + echo $mod_strings [ 'LBL_DONE' ] ; +?> diff --git a/modules/Administration/RebuildSchedulers.php b/modules/Administration/RebuildSchedulers.php new file mode 100644 index 00000000..eca72e2f --- /dev/null +++ b/modules/Administration/RebuildSchedulers.php @@ -0,0 +1,77 @@ +rebuildDefaultSchedulers(); + +$admin_mod_strings = return_module_language($current_language, 'Administration'); +?> + + + + + +
    + +

    +

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

    + \ No newline at end of file diff --git a/modules/Administration/RepairActivities.php b/modules/Administration/RepairActivities.php new file mode 100644 index 00000000..55c045ba --- /dev/null +++ b/modules/Administration/RepairActivities.php @@ -0,0 +1,68 @@ +db->query($callQuery, true, ""); +$row = $callBean->db->fetchByAssoc($result); +while ($row != null) { + $date_end = $timedate->fromDb($row['date_start'])->modify("+{$row['duration_hours']} hours {$row['duration_minutes']} mins")->asDb(); + $updateQuery = "UPDATE calls set calls.date_end='{$date_end}' where calls.id='{$row['id']}'"; + $call = new Call(); + $call->db->query($updateQuery); + $row = $callBean->db->fetchByAssoc($result); +} + +$meetingBean = new Meeting(); +$meetingQuery = "SELECT * FROM meetings where meetings.status != 'Held' and meetings.deleted=0"; + +$result = $meetingBean->db->query($meetingQuery, true, ""); +$row = $meetingBean->db->fetchByAssoc($result); +while ($row != null) { + $date_end = $timedate->fromDb($row['date_start'])->modify("+{$row['duration_hours']} hours {$row['duration_minutes']} mins")->asDb(); + $updateQuery = "UPDATE meetings set meetings.date_end='{$date_end}' where meetings.id='{$row['id']}'"; + $call = new Call(); + $call->db->query($updateQuery); + $row = $callBean->db->fetchByAssoc($result); +} +echo $mod_strings['LBL_DIAGNOSTIC_DONE']; + diff --git a/modules/Administration/RepairFieldCasing.php b/modules/Administration/RepairFieldCasing.php new file mode 100644 index 00000000..71ccd9eb --- /dev/null +++ b/modules/Administration/RepairFieldCasing.php @@ -0,0 +1,152 @@ +'.$mod_strings['LBL_REPAIR_FIELD_CASING_PROCESSING']; + + //store the affected entries + $database_entries = array(); + $module_entries = array(); + + $query = "SELECT * FROM fields_meta_data"; + $result = $GLOBALS['db']->query($query); + while($row = $GLOBALS['db']->fetchByAssoc($result)) { + $name = $row['name']; + $id = $row['id']; + $module_entries[$row['custom_module']] = true; + + //Only run database SQL where the name or id casing does is not lowercased + if($name != strtolower($row['name'])) { + $database_entries[$row['custom_module']][$name] = $row; + } + } + + //If we have database entries to process + if(!empty($database_entries)) { + + foreach($database_entries as $module=>$entries) { + $table_name = strtolower($module) . '_cstm'; + + foreach($entries as $original_col_name=>$entry) { + echo '
    '. string_format($mod_strings['LBL_REPAIR_FIELD_CASING_SQL_FIELD_META_DATA'], array($entry['name'])); + $update_sql = "UPDATE fields_meta_data SET id = '" . $entry['custom_module'] . strtolower($entry['name']) . "', name = '" . strtolower($entry['name']) . "' WHERE id = '" . $entry['id'] . "'"; + $GLOBALS['db']->query($update_sql); + + echo '
    '. string_format($mod_strings['LBL_REPAIR_FIELD_CASING_SQL_CUSTOM_TABLE'], array($entry['name'], $table_name)); + + if($GLOBALS['db']->dbType == 'mssql') { + $sql = "SP_RENAME '{$table_name}.{$entry['name']}', '" . strtolower($entry['name']) . "', 'COLUMN'"; + $GLOBALS['db']->query($sql); + } else if($GLOBALS['db']->dbType == 'mysql') { + $entry['name'] = strtolower($entry['name']); + $GLOBALS['db']->alterColumn($table_name, $entry); + } else if($GLOBALS['db']->dbType == 'oci8') { + $sql = "ALTER TABLE \"" . strtoupper($table_name) ."\" RENAME COLUMN \"" . $entry['name'] . "\" TO \"" . strtolower($entry['name']) . "\""; + $GLOBALS['db']->query($sql); + } + } + } + } + + //If we have metadata files to alter + if(!empty($module_entries)) { + $modules = array_keys($module_entries); + $views = array('basic_search', 'advanced_search', 'detailview', 'editview', 'quickcreate'); + $class_names = array(); + + require_once ('include/TemplateHandler/TemplateHandler.php') ; + require_once('modules/ModuleBuilder/parsers/ParserFactory.php'); + + foreach($modules as $module) { + if(isset($GLOBALS['beanList'][$module])) { + $class_names[] = $GLOBALS['beanList'][$module]; + } + + $repairClass->module_list[] = $module; + foreach($views as $view) { + try{ + $parser = ParserFactory::getParser($view, $module); + } + catch(Exception $e){ + $GLOBALS['log']->fatal("Caught exception in RepairFieldCasing script: ".$e->getMessage()); + continue; + } + if(isset($parser->_viewdefs['panels'])) { + foreach($parser->_viewdefs['panels'] as $panel_id=>$panel) { + foreach($panel as $row_id=>$row) { + foreach($row as $entry_id=>$entry) { + if(is_array($entry) && isset($entry['name'])) { + $parser->_viewdefs['panels'][$panel_id][$row_id][$entry_id]['name'] = strtolower($entry['name']); + } + } + } + } + } else { + //For basic_search and advanced_search views, just process the fields + foreach($parser->_viewdefs as $entry_id=>$entry) { + if(is_array($entry) && isset($entry['name'])) { + $parser->_viewdefs[$entry_id]['name'] = strtolower($entry['name']); + } + } + } + + //Save the changes + $parser->handleSave(false); + } //foreach + + //Now clear the cache of the .tpl files + TemplateHandler::clearCache($module); + + + } //foreach + + echo '
    '.$mod_strings['LBL_CLEAR_VARDEFS_DATA_CACHE_TITLE']; + require_once('modules/Administration/QuickRepairAndRebuild.php'); + $repair = new RepairAndClear(); + $repair->show_output = false; + $repair->module_list = array($class_names); + $repair->clearVardefs(); + } + + echo '
    '.$mod_strings['LBL_DIAGNOSTIC_DONE']; + +} +?> diff --git a/modules/Administration/RepairIE.php b/modules/Administration/RepairIE.php new file mode 100644 index 00000000..d51551ab --- /dev/null +++ b/modules/Administration/RepairIE.php @@ -0,0 +1,72 @@ +query($q); + +while($a = $db->fetchByAssoc($r)) { + $ieX = new InboundEmail(); + $ieX->retrieve($a['id']); + if(!$ieX->repairAccount()) { + // none of the iterations worked. flag for display + $badAccts[$a['id']] = $a['name']; + } +} + +if(empty($badAccts)) { + echo $mod_strings['LBL_REPAIR_IE_SUCCESS']; +} else { + echo "
    {$mod_strings['LBL_REPAIR_IE_FAILURE']}

    "; + foreach($badAccts as $id => $acctName) { + echo "{$acctName}
    "; + } +} + +?> \ No newline at end of file diff --git a/modules/Administration/RepairIndex.php b/modules/Administration/RepairIndex.php new file mode 100644 index 00000000..a66c6c0c --- /dev/null +++ b/modules/Administration/RepairIndex.php @@ -0,0 +1,253 @@ +$var_i_def) { + //find corresponding db index with same name + //else by columns in the index. + $sel_db_index = null; + $var_fields_string =''; + if(count($var_i_def['fields'])>0) + $var_fields_string = implode('',$var_i_def['fields']); + $field_list_match = false; + if(isset($db_indexes[$var_i_name])) { + $sel_db_index = $db_indexes[$var_i_name]; + $db_fields_string = implode('', $db_indexes[$var_i_name]['fields']); + if(strcasecmp($var_fields_string, $db_fields_string)==0) { + $field_list_match=true; + } + } else { + //search by column list. + foreach ($db_indexes as $db_i_name=>$db_i_def) { + $db_fields_string=implode('',$db_i_def['fields']); + if(strcasecmp($var_fields_string , $db_fields_string)==0) { + $sel_db_index=$db_indexes[$db_i_name]; + $field_list_match=true; + break; + } + } + } + + //no matching index in database. + if(empty($sel_db_index)) { + $add_index[]=$GLOBALS['db']->helper->add_drop_constraint($table_name,$var_i_def); + continue; + } + if(!$field_list_match) { + //drop the db index and create new index based on vardef + $drop_index[]=$GLOBALS['db']->helper->add_drop_constraint($table_name,$sel_db_index,true); + $add_index[]=$GLOBALS['db']->helper->add_drop_constraint($table_name,$var_i_def); + continue; + } + //check for name match. + //it should not occur for indexes of type primary or unique. + if( $var_i_def['type'] != 'primary' and $var_i_def['type'] != 'unique' and $var_i_def['name'] != $sel_db_index['name']) { + //rename index. + $rename=$GLOBALS['db']->helper->rename_index($sel_db_index,$var_i_def,$table_name); + if(is_array($rename)) { + $change_index=array_merge($change_index,$rename); + } else { + $change_index[]=$rename; + } + continue; + } + } +} +//// END LOCAL UTILITY +/////////////////////////////////////////////////////////////////////////////// + + +/////////////////////////////////////////////////////////////////////////////// +//// PROCESS +if(!is_admin($current_user)) sugar_die("Unauthorized access to administration."); +set_time_limit(3600); +/** + * Note: $_REQUEST['silent'] is set from ModuleInstaller::repair_indices(); + */ +if(!isset($_REQUEST['silent'])) $_REQUEST['silent'] = false; + +$add_index=array(); +$drop_index=array(); +$change_index=array(); + +global $current_user, $beanFiles, $dictionary, $sugar_config, $mod_strings;; +include_once ('include/database/DBManager.php'); + +$db = &DBManagerFactory::getInstance(); +$processed_tables=array(); + +/////////////////////////////////////////////////////////////////////////////// +//// PROCESS MODULE BEANS +(function_exists('logThis')) ? logThis("found ".count($beanFiles)." Beans to process") : ""; +(function_exists('logThis')) ? logThis("found ".count($dictionary)." Dictionary entries to process") : ""; + +foreach ($beanFiles as $beanname=>$beanpath) { + require_once($beanpath); + $focus= new $beanname(); + + //skips beans based on same tables. user, employee and group are an example. + if(empty($focus->table_name) || isset($processed_tables[$focus->table_name])) { + continue; + } else { + $processed_tables[$focus->table_name]=$focus->table_name; + } + + if(!empty($dictionary[$focus->object_name]['indices'])) { + $indices=$dictionary[$focus->object_name]['indices']; + } else { + $indices=array(); + } + + //clean vardef defintions.. removed indexes not value for this dbtype. + //set index name as the key. + $var_indices=array(); + foreach ($indices as $definition) { + //database helpers do not know how to handle full text indices + if ($definition['type']=='fulltext') { + continue; + } + + if(empty($definition['db']) or $definition['db'] == $focus->db->dbType) { + $var_indices[$definition['name']] = $definition; + } + } + + $db_indices=$focus->db->helper->get_indices($focus->table_name); + compare($focus->table_name,$db_indices,$var_indices); +} +//// END PROCESS MODULE BEANS +/////////////////////////////////////////////////////////////////////////////// + + +/////////////////////////////////////////////////////////////////////////////// +//// PROCESS RELATIONSHIP METADATA - run thru many to many relationship files too... +include('modules/TableDictionary.php'); +foreach ($dictionary as $rel=>$rel_def) { + if(!empty($rel_def['indices'])) { + $indices=$rel_def['indices']; + } else { + $indices=array(); + } + + //clean vardef defintions.. removed indexes not value for this dbtype. + //set index name as the key. + $var_indices=array(); + foreach ($indices as $definition) { + if(empty($definition['db']) or $definition['db'] == $focus->db->dbType) { + $var_indices[$definition['name']] = $definition; + } + } + + $db_indices=$focus->db->helper->get_indices($rel_def['table']); + + compare($rel_def['table'],$db_indices,$var_indices); +} +//// END PROCESS RELATIONSHIP METADATA +/////////////////////////////////////////////////////////////////////////////// + + +(function_exists('logThis')) ? logThis("RepairIndex: we have ".count($drop_index)." indices to DROP.") : ""; +(function_exists('logThis')) ? logThis("RepairIndex: we have ".count($add_index)." indices to ADD.") : ""; +(function_exists('logThis')) ? logThis("RepairIndex: we have ".count($change_index)." indices to CHANGE.") : ""; + +if((count($drop_index) > 0 or count($add_index) > 0 or count($change_index) > 0)) { + if(!isset($_REQUEST['mode']) or $_REQUEST['mode'] != 'execute') { + echo ($_REQUEST['silent']) ? "" : "


    "; + echo ($_REQUEST['silent']) ? "" : "Execute Script"; + } + + $focus = new Account(); + if(count($drop_index) > 0) { + if(isset($_REQUEST['mode']) and $_REQUEST['mode']=='execute') { + echo ($_REQUEST['silent']) ? "" : $mod_strings['LBL_REPAIR_INDEX_DROPPING']; + foreach ($drop_index as $statement) { + echo ($_REQUEST['silent']) ? "" : $mod_strings['LBL_REPAIR_INDEX_EXECUTING'].$statement; + (function_exists('logThis')) ? logThis("RepairIndex: {$statement}") : ""; + $focus->db->query($statement); + } + } else { + echo ($_REQUEST['silent']) ? "" : $mod_strings['LBL_REPAIR_INDEX_DROP']; + foreach ($drop_index as $statement) { + echo ($_REQUEST['silent']) ? "" : "
    ".$statement.";"; + } + } + } + + if(count($add_index) > 0) { + if(isset($_REQUEST['mode']) and $_REQUEST['mode']=='execute') { + echo ($_REQUEST['silent']) ? "" : $mod_strings['LBL_REPAIR_INDEX_ADDING']; + foreach ($add_index as $statement) { + echo ($_REQUEST['silent']) ? "" : $mod_strings['LBL_REPAIR_INDEX_EXECUTING'].$statement; + (function_exists('logThis')) ? logThis("RepairIndex: {$statement}") : ""; + $focus->db->query($statement); + } + } else { + echo ($_REQUEST['silent']) ? "" : $mod_strings['LBL_REPAIR_INDEX_ADD']; + foreach ($add_index as $statement) { + echo ($_REQUEST['silent']) ? "" : "
    ".$statement.";"; + } + } + } + if(count($change_index) > 0) { + if(isset($_REQUEST['mode']) and $_REQUEST['mode']=='execute') { + echo ($_REQUEST['silent']) ? "" : $mod_strings['LBL_REPAIR_INDEX_ALTERING']; + foreach ($change_index as $statement) { + echo ($_REQUEST['silent']) ? "" : $mod_strings['LBL_REPAIR_INDEX_EXECUTING'].$statement; + (function_exists('logThis')) ? logThis("RepairIndex: {$statement}") : ""; + $focus->db->query($statement); + } + } else { + echo ($_REQUEST['silent']) ? "" : $mod_strings['LBL_REPAIR_INDEX_ALTER']; + foreach ($change_index as $statement) { + echo ($_REQUEST['silent']) ? "" : "
    ".$statement.";"; + } + } + } + + if(!isset($_REQUEST['mode']) or $_REQUEST['mode'] != 'execute') { + echo ($_REQUEST['silent']) ? "" : "


    "; + echo ($_REQUEST['silent']) ? "" : "Execute Script"; + } +} else { + (function_exists('logThis')) ? logThis("RepairIndex: Index definitions are in sync.") : ""; + echo ($_REQUEST['silent']) ? "" : $mod_strings['LBL_REPAIR_INDEX_SYNC']; +} \ No newline at end of file diff --git a/modules/Administration/RepairJSFile.php b/modules/Administration/RepairJSFile.php new file mode 100644 index 00000000..ace6bbb1 --- /dev/null +++ b/modules/Administration/RepairJSFile.php @@ -0,0 +1,99 @@ +'.$mod_strings['LBL_REPAIR_JS_FILES_PROCESSING']; + echo'
    '; + + //echo out script that will make an ajax call to process the files via callJSRepair.php + echo ""; + +} + + + + +?> \ No newline at end of file diff --git a/modules/Administration/RepairSeedUsers.php b/modules/Administration/RepairSeedUsers.php new file mode 100644 index 00000000..36ab56c1 --- /dev/null +++ b/modules/Administration/RepairSeedUsers.php @@ -0,0 +1,87 @@ +query($query); + } + $query = "SELECT status FROM users WHERE id LIKE 'seed%'"; + $result = $GLOBALS['db']->query($query); + $row = $GLOBALS['db']->fetchByAssoc($result, -1, true); + if(!empty($row['status'])){ + $activate = 'false'; + if($row['status'] == 'Inactive'){ + $activate = 'true'; + } + ?> +

    +

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

    + \ No newline at end of file diff --git a/modules/Administration/RepairXSS.php b/modules/Administration/RepairXSS.php new file mode 100644 index 00000000..7eaf6f2b --- /dev/null +++ b/modules/Administration/RepairXSS.php @@ -0,0 +1,89 @@ +{$options}"; + + echo getClassicModuleTitle('Administration', array($mod_strings['LBL_REPAIRXSS_TITLE']), false); + echo ""; + + $smarty = new Sugar_Smarty(); + $smarty->assign("mod", $mod_strings); + $smarty->assign("beanDropDown", $beanDropDown); + $smarty->display("modules/Administration/templates/RepairXSS.tpl"); +} // end else \ No newline at end of file diff --git a/modules/Administration/Save.php b/modules/Administration/Save.php new file mode 100644 index 00000000..b70278a3 --- /dev/null +++ b/modules/Administration/Save.php @@ -0,0 +1,81 @@ + $val) { + $prefix = $focus->get_config_prefix($key); + if (in_array($prefix[0], $focus->config_categories)) { + if ( $prefix[0] == "license" ) + { + if ( $prefix[1] == "expire_date" ) + { + global $timedate; + $val = $timedate->swap_formats( $val, $timedate->get_date_format(), $timedate->dbDayFormat ); + } + else + if ( $prefix[1] == "key" ) + { + $val = trim($val); // bug 16860 tyoung - trim whitespace from the start and end of the licence key value + } + } + + $focus->saveSetting($prefix[0], $prefix[1], $val); + } +} + + + + + + +header("Location: index.php?action={$_POST['return_action']}&module={$_POST['return_module']}"); +?> diff --git a/modules/Administration/SupportPortal.php b/modules/Administration/SupportPortal.php new file mode 100644 index 00000000..59e155d8 --- /dev/null +++ b/modules/Administration/SupportPortal.php @@ -0,0 +1,270 @@ +info("Administration SupportPortal"); + + $iframe_url = add_http("www.sugarcrm.com/network/redirect.php?tmpl=network"); + + echo getClassicModuleTitle( + "Administration", + array( + "".translate('LBL_MODULE_NAME','Administration')."", + $mod_strings['LBL_SUPPORT_TITLE'], + ), + false + ); + + $sugar_smarty = new Sugar_Smarty(); + $sugar_smarty->assign('iframeURL', $iframe_url); + echo $sugar_smarty->fetch('modules/Administration/SupportPortal.tpl'); + + break; + default: + + $send_version = isset($_REQUEST['version']) ? $_REQUEST['version'] : ""; + $send_edition = isset($_REQUEST['edition']) ? $_REQUEST['edition'] : ""; + $send_lang = isset($_REQUEST['lang']) ? $_REQUEST['lang'] : ""; + $send_module = isset($_REQUEST['help_module']) ? $_REQUEST['help_module'] : ""; + $send_action = isset($_REQUEST['help_action']) ? $_REQUEST['help_action'] : ""; + $send_key = isset($_REQUEST['key']) ? $_REQUEST['key'] : ""; + $send_anchor = ''; + // awu: Fixes the ProjectTasks pluralization issue -- must fix in later versions. + if ($send_module == 'ProjectTasks') + $send_module = 'ProjectTask'; + if ($send_module == 'ProductCatalog') + $send_module = 'ProductTemplates'; + if ($send_module == 'TargetLists') + $send_module = 'ProspectLists'; + if ($send_module == 'Targets') + $send_module = 'Prospects'; + $helpPath = 'modules/'.$send_module.'/language/'.$send_lang.'.help.'.$send_action.'.html'; + + $sugar_smarty = new Sugar_Smarty(); + + //if the language is english then be sure to skip this check, otherwise go to the support + //portal if the file is not found. + if ($send_lang != 'en_us' && file_exists($helpPath)) + { + $sugar_smarty->assign('helpFileExists', TRUE); + $sugar_smarty->assign('helpPath', $helpPath); + $sugar_smarty->assign('helpBar', getHelpBar($send_module)); + $sugar_smarty->assign('bookmarkScript', bookmarkJS()); + $sugar_smarty->assign('title', $mod_strings['LBL_SUGARCRM_HELP'] . " - " . $send_module); + $sugar_smarty->assign('styleSheet', SugarThemeRegistry::current()->getCSS()); + $sugar_smarty->assign('table', getTable()); + $sugar_smarty->assign('endtable', endTable()); + $sugar_smarty->assign('charset', $app_strings['LBL_CHARSET']); + echo $sugar_smarty->fetch('modules/Administration/SupportPortal.tpl'); + + } else { + if(empty($send_module)){ + $send_module = 'toc'; + } + + $dev_status = 'GA'; + //If there is an alphabetic portion between the decimal prefix and integer suffix, then use the + //value there as the dev_status value + $dev_status = getVersionStatus($GLOBALS['sugar_version']); + $send_version = getMajorMinorVersion($GLOBALS['sugar_version']); + $editionMap = array('ENT' => 'Enterprise', 'PRO' => 'Professional', 'CE' => 'Community_Edition'); + if(!empty($editionMap[$send_edition])){ + $send_edition = $editionMap[$send_edition]; + } + + //map certain modules + $sendModuleMap = array( + 'administration' => array( + array('name' => 'Administration', 'action' => 'supportportal', 'anchor' => '1910574'), + array('name' => 'Administration', 'action' => 'updater', 'anchor' => '1910574'), + array('name' => 'Administration', 'action' => 'licensesettings', 'anchor' => '1910574'), + array('name' => 'Administration', 'action' => 'diagnostic', 'anchor' => '1111949'), + array('name' => 'Administration', 'action' => 'listviewofflineclient', 'anchor' => '1111949'), + array('name' => 'Administration', 'action' => 'enablewirelessmodules', 'anchor' => '1111949'), + array('name' => 'Administration', 'action' => 'backups', 'anchor' => '1111949'), + array('name' => 'Administration', 'action' => 'upgrade', 'anchor' => '1111949'), + array('name' => 'Administration', 'action' => 'locale', 'anchor' => '1111949'), + array('name' => 'Administration', 'action' => 'themesettings', 'anchor' => '1111949'), + array('name' => 'Administration', 'action' => 'passwordmanager', 'anchor' => '1446494'), + array('name' => 'Administration', 'action' => 'upgradewizard', 'anchor' => '1168410'), + array('name' => 'Administration', 'action' => 'configuretabs', 'anchor' => '1168410'), + array('name' => 'Administration', 'action' => 'configuresubpanels', 'anchor' => '1168410'), + array('name' => 'Administration', 'action' => 'wizard', 'anchor' => '1168410'), + ), + 'calls' => array(array('name' => 'Activities')), + 'tasks' => array(array('name' => 'Activities')), + 'meetings' => array(array('name' => 'Activities')), + 'notes' => array(array('name' => 'Activities')), + 'calendar' => array(array('name' => 'Activities')), + 'configurator' => array(array('name' => 'Administration', 'anchor' => '1878359')), + 'upgradewizard' => array(array('name' => 'Administration', 'anchor' => '1878359')), + 'schedulers' => array(array('name' => 'Administration', 'anchor' => '1878359')), + 'sugarfeed' => array(array('name' => 'Administration', 'anchor' => '1878359')), + 'connectors' => array(array('name' => 'Administration', 'anchor' => '1878359')), + 'trackers' => array(array('name' => 'Administration', 'anchor' => '1878359')), + 'currencies' => array(array('name' => 'Administration', 'anchor' => '1878359')), + 'aclroles' => array(array('name' => 'Administration', 'anchor' => '1916499')), + 'roles' => array(array('name' => 'Administration', 'anchor' => '1916499')), + 'teams' => array(array('name' => 'Administration', 'anchor' => '1916499')), + 'users' => array(array('name' => 'Administration', 'anchor' => '1916499'), array('name' => 'Administration', 'action' => 'detailview', 'anchor' => '1916518')), + 'modulebuilder' => array(array('name' => 'Administration', 'anchor' => '1168410')), + 'studio' => array(array('name' => 'Administration', 'anchor' => '1168410')), + 'workflow' => array(array('name' => 'Administration', 'anchor' => '1168410')), + 'producttemplates' => array(array('name' => 'Administration', 'anchor' => '1957376')), + 'productcategories' => array(array('name' => 'Administration', 'anchor' => '1957376')), + 'producttypes' => array(array('name' => 'Administration', 'anchor' => '1957376')), + 'manufacturers' => array(array('name' => 'Administration', 'anchor' => '1957376')), + 'shippers' => array(array('name' => 'Administration', 'anchor' => '1957376')), + 'taxrates' => array(array('name' => 'Administration', 'anchor' => '1957376')), + 'releases' => array(array('name' => 'Administration', 'anchor' => '1868932')), + 'timeperiods' => array(array('name' => 'Administration', 'anchor' => '1957639')), + 'contracttypes' => array(array('name' => 'Administration', 'anchor' => '1957677')), + 'contracttype' => array(array('name' => 'Administration', 'anchor' => '1957677')), + 'emailman' => array(array('name' => 'Administration', 'anchor' => '1445484')), + 'inboundemail' => array(array('name' => 'Administration', 'anchor' => '1445484')), + 'emailtemplates' => array(array('name' => 'Emails')), + 'prospects' => array(array('name' => 'Campaigns')), + 'prospectlists' => array(array('name' => 'Campaigns')), + 'reportmaker' => array(array('name' => 'Reports')), + 'customqueries' => array(array('name' => 'Reports')), + 'quotas' => array(array('name' => 'Forecasts')), + 'projecttask' => array(array('name' => 'Projects')), + 'project' => array(array('name' => 'Projects'), array('name' => 'Dashboard', 'action' => 'dashboard'), ), + 'projecttemplate' => array(array('name' => 'Projects')), + 'datasets' => array(array('name' => 'Reports')), + 'dataformat' => array(array('name' => 'Reports')), + 'employees' => array(array('name' => 'Administration', 'anchor' => '1957677')), + 'kbdocuments' => array(array('name' => 'Administration', 'action' => 'kbadminview', 'anchor' => '1957677')), + ); + + if(!empty($sendModuleMap[strtolower($send_module)])){ + $mappings = $sendModuleMap[strtolower($send_module)]; + + foreach($mappings as $map){ + if(!empty($map['action'])){ + if($map['action'] == strtolower($send_action)){ + $send_module = $map['name']; + if(!empty($map['anchor'])){ + $send_anchor = $map['anchor']; + } + } + }else{ + $send_module = $map['name']; + if(!empty($map['anchor'])){ + $send_anchor = $map['anchor']; + } + } + } + //$send_module = $sendModuleMap[strtolower($send_module)]; + } + $sendUrl = "http://www.sugarcrm.com/crm/product_doc.php?edition={$send_edition}&version={$send_version}&lang={$send_lang}&module={$send_module}&help_action={$send_action}&status={$dev_status}&key={$send_key}&anchor={$send_anchor}"; + if(!empty($send_anchor)){ + $sendUrl .= "&anchor=".$send_anchor; + } + $iframe_url = $sendUrl; + + header("Location: {$iframe_url}"); + + //$sugar_smarty->assign('helpFileExists', FALSE); + //$sugar_smarty->assign('iframeURL', $iframe_url); + } + break; +} + + +function getHelpBar($moduleName) +{ + global $mod_strings; + + $helpBar = "
    " . + "" . $mod_strings['LBL_HELP_PRINT'] . " - " . + "" . $mod_strings['LBL_HELP_EMAIL'] . " - " . + "" . $mod_strings['LBL_HELP_BOOKMARK'] . "" . + "
    "; + + return $helpBar; +} + +function getTable() +{ + $table = "
    "; + + return $table; +} + +function endTable() +{ + $endtable = "
    "; + + return $endtable; +} + +function bookmarkJS() { + +$script = +<< + + +EOQ; + +return $script; +} + +?> \ No newline at end of file diff --git a/modules/Administration/SupportPortal.tpl b/modules/Administration/SupportPortal.tpl new file mode 100644 index 00000000..cb29055e --- /dev/null +++ b/modules/Administration/SupportPortal.tpl @@ -0,0 +1,62 @@ +{* + +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + + +*} + + +{if $helpFileExists} + + + {$title} + {$styleSheet} + + + + {$helpBar} + + + + +
    {include file="$helpPath"}
    + {$bookmarkScript} + + +{else} + +{/if} \ No newline at end of file diff --git a/modules/Administration/Updater.html b/modules/Administration/Updater.html new file mode 100644 index 00000000..95c39012 --- /dev/null +++ b/modules/Administration/Updater.html @@ -0,0 +1,98 @@ + + + +
    + + + + + + + + + + +
    {APP.LBL_REQUIRED_SYMBOL} {APP.NTC_REQUIRED}
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

    {MOD.LBL_UPDATE_TITLE}

    {MOD.HEARTBEAT_MESSAGE}

    {MOD.LBL_SEND_STAT}
     
    {MOD.LBL_UPDATE_CHECK_TYPE} +
     

    {MOD.LBL_AVAILABLE_UPDATES} {MOD.LBL_UPDATE_DESCRIPTIONS}
    {VERSION.version}{VERSION.description}
    {MOD.LBL_UPTODATE}
    +
    + diff --git a/modules/Administration/Updater.php b/modules/Administration/Updater.php new file mode 100644 index 00000000..10b9fe2d --- /dev/null +++ b/modules/Administration/Updater.php @@ -0,0 +1,126 @@ +assign("MOD", $mod_strings); +$xtpl->assign("APP", $app_strings); + +if (isset($_REQUEST['useraction']) && ($_REQUEST['useraction']=='Save' || $_REQUEST['useraction']=='CheckNow')) { + if(!empty($_REQUEST['type']) && $_REQUEST['type'] == 'automatic') { + set_CheckUpdates_config_setting('automatic'); + }else{ + set_CheckUpdates_config_setting('manual'); + } + + $beat=false; + if(!empty($_REQUEST['beat'])) { + $beat=true; + } + if ($beat != get_sugarbeat()) { + set_sugarbeat($beat); + } +} + +echo getClassicModuleTitle( + "Administration", + array( + "".translate('LBL_MODULE_NAME','Administration')."", + $mod_strings['LBL_SUGAR_UPDATE_TITLE'], + ), + false + ); + +if (get_sugarbeat()) $xtpl->assign("SEND_STAT_CHECKED", "checked"); + +if (get_CheckUpdates_config_setting()=='automatic') { + $xtpl->assign("AUTOMATIC_CHECKED", "checked"); +} + + +if (isset($_REQUEST['useraction']) && $_REQUEST['useraction']=='CheckNow') { + check_now(get_sugarbeat()); + loadLicense(); + +} + +$xtpl->parse('main.stats'); + +$has_updates= false; +if(!empty($license->settings['license_latest_versions'])){ + + $encodedVersions = $license->settings['license_latest_versions']; + + $versions = unserialize(base64_decode( $encodedVersions)); + include('sugar_version.php'); + if(!empty($versions)){ + foreach($versions as $version){ + if($version['version'] > $sugar_version ) + { + $has_updates = true; + $xtpl->assign("VERSION", $version); + $xtpl->parse('main.updates.version'); + } + } + } + if(!$has_updates){ + $xtpl->parse('main.noupdates'); + }else{ + $xtpl->parse('main.updates'); + } +} + +//return module and index. +$xtpl->assign("RETURN_MODULE", "Administration"); +$xtpl->assign("RETURN_ACTION", "index"); + +$xtpl->parse("main"); +$xtpl->out("main"); +?> diff --git a/modules/Administration/Upgrade.php b/modules/Administration/Upgrade.php new file mode 100644 index 00000000..8913b6e5 --- /dev/null +++ b/modules/Administration/Upgrade.php @@ -0,0 +1,144 @@ +dbType=='oci8') { + + $str1=''; + $str1.=SugarThemeRegistry::current()->getImage('Repair','alt="'. $mod_strings['LBL_REPAIR_ORACLE_FULLTEXT'].'" align="absmiddle" border="0"'); + $str1.=' ' . $mod_strings['LBL_REPAIR_ORACLE_FULLTEXT'] .''; + $str1.='' .$mod_strings['LBL_REPAIR_ORACLE_FULLTEXT_DESC'] . ''; +} +?> +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    getImage('Repair','alt="'. $mod_strings['LBL_QUICK_REPAIR_AND_REBUILD'].'" align="absmiddle" border="0"'); ?> 
    getImage('Repair','alt="'. $mod_strings['LBL_EXPAND_DATABASE_COLUMNS'].'" align="absmiddle" border="0"'); ?> 
    getImage('Rebuild','alt="'. $mod_strings['LBL_REBUILD_HTACCESS'].'" align="absmiddle" border="0"'); ?>  getImage('Rebuild','alt="'. $mod_strings['LBL_REBUILD_WEBCONFIG'].'" align="absmiddle" border="0"'); ?> 
    getImage('Rebuild','alt="'. $mod_strings['LBL_REBUILD_CONFIG'].'" align="absmiddle" border="0"'); ?> 
    getImage('Rebuild','alt="'. $mod_strings['LBL_REBUILD_REL_TITLE'].'" align="absmiddle" border="0"'); ?> 
    getImage('Rebuild','alt="'. $mod_strings['LBL_REBUILD_SCHEDULERS_TITLE'].'" align="absmiddle" border="0"'); ?> 
    getImage('Rebuild','alt="'. $mod_strings['LBL_REBUILD_DASHLETS_TITLE'].'" align="absmiddle" border="0"'); ?> 
    getImage('Rebuild','alt="'. $mod_strings['LBL_REBUILD_JAVASCRIPT_LANG_TITLE'].'" align="absmiddle" border="0"'); ?> 
    getImage('Rebuild','alt="'. $mod_strings['LBL_REBUILD_JS_FILES_TITLE'].'" align="absmiddle" border="0"'); ?> 
    getImage('Rebuild','alt="'. $mod_strings['LBL_REBUILD_CONCAT_JS_FILES_TITLE'].'" align="absmiddle" border="0"'); ?> 
    getImage('Rebuild','alt="'. $mod_strings['LBL_REBUILD_JS_MINI_FILES_TITLE'].'" align="absmiddle" border="0"'); ?> 
    getImage('Repair','alt="'. $mod_strings['LBL_REPAIR_JS_FILES_TITLE'].'" align="absmiddle" border="0"'); ?> 
    getImage('Repair','alt="'. $mod_strings['LBL_REPAIR_FIELD_CASING_TITLE'].'" align="absmiddle" border="0"'); ?> 
    getImage('Repair','alt="'. $mod_strings['LBL_REPAIR_ROLES'].'" align="absmiddle" border="0"'); ?> 
    getImage('Repair','alt="'. $mod_strings['LBL_REPAIR_IE'].'" align="absmiddle" border="0"'); ?> 
    getImage('Repair','alt="'. $mod_strings['LBL_REPAIR_XSS'].'" align="absmiddle" border="0"'); ?> 
    getImage('Repair','alt="'. $mod_strings['LBL_REPAIR_ACTIVITIES'].'" align="absmiddle" border="0"'); ?> 
    getImage('Repair','alt="'. $mod_strings['LBL_REPAIR_SEED_USERS_TITLE'].'" align="absmiddle" border="0"'); ?> 

    diff --git a/modules/Administration/UpgradeAccess.php b/modules/Administration/UpgradeAccess.php new file mode 100644 index 00000000..7286416a --- /dev/null +++ b/modules/Administration/UpgradeAccess.php @@ -0,0 +1,151 @@ + 0)?'(?i)':''; +$htaccess_file = getcwd() . "/.htaccess"; +$contents = ''; +$restrict_str = <<' . $mod_strings['LBL_HT_NO_WRITE'] . '$htaccess_file

    \n'; + echo '

    ' . $mod_strings['LBL_HT_NO_WRITE_2'] . '

    \n'; + echo "$redirect_str"; +} + + +// cn: bug 9365 - security for filesystem +$uploadDir=''; +$uploadHta=''; + +if (empty($GLOBALS['sugar_config']['upload_dir'])) { + $GLOBALS['sugar_config']['upload_dir']='cache/upload/'; +} +$uploadDir = getcwd()."/".$sugar_config['upload_dir']; +if(file_exists($uploadDir)){ + $uploadHta = $uploadDir.".htaccess"; +} +else{ + mkdir_recursive($uploadDir); + if(is_dir($uploadDir)){ + $uploadHta = $uploadDir.".htaccess"; + } +} + +$denyAll =<< + Order Deny,Allow + Deny from all + +eoq; + +if(file_exists($uploadHta) && filesize($uploadHta)) { + // file exists, parse to make sure it is current + if(is_writable($uploadHta) && ($fpUploadHta = @sugar_fopen($uploadHta, "r+"))) { + $oldHtaccess = file_get_contents($uploadHta); + // use a different regex boundary b/c .htaccess uses the typicals + if(!preg_match("=".$denyAll."=", $oldHtaccess)) { + $oldHtaccess .= $denyAll; + } + + rewind($fpUploadHta); + fwrite($fpUploadHta, $oldHtaccess); + ftruncate($fpUploadHta, ftell($fpUploadHta)); + fclose($fpUploadHta); + } else { + $htaccess_failed = true; + } +} else { + // no .htaccess yet, create a fill + if($fpUploadHta = @sugar_fopen($uploadHta, "w")) { + fputs($fpUploadHta, $denyAll); + fclose($fpUploadHta); + } else { + $htaccess_failed = true; + } +} + + + + +include('modules/Versions/ExpectedVersions.php'); + + +global $expect_versions; + +if (isset($expect_versions['htaccess'])) { + $version = new Version(); + $version->retrieve_by_string_fields(array('name'=>'htaccess')); + + $version->name = $expect_versions['htaccess']['name']; + $version->file_version = $expect_versions['htaccess']['file_version']; + $version->db_version = $expect_versions['htaccess']['db_version']; + $version->save(); +} + +/* Commenting out as this shows on upgrade screen + * echo "\n" . $mod_strings['LBL_HT_DONE']. "
    \n"; +*/ + +?> \ No newline at end of file diff --git a/modules/Administration/UpgradeFields.php b/modules/Administration/UpgradeFields.php new file mode 100644 index 00000000..a94fd26d --- /dev/null +++ b/modules/Administration/UpgradeFields.php @@ -0,0 +1,154 @@ +query('SELECT * FROM fields_meta_data WHERE deleted = 0 ORDER BY custom_module'); +$modules = array (); +/* + * get the real field_meta_data + */ +while ($row = $db->fetchByAssoc($result)) { + $the_modules = $row['custom_module']; + if (!isset ($modules[$the_modules])) { + $modules[$the_modules] = array (); + } + $modules[$the_modules][$row['name']] = $row['name']; +} + +$simulate = false; +if (!isset ($_REQUEST['run'])) { + $simulate = true; + echo "SIMULATION MODE - NO CHANGES WILL BE MADE EXCEPT CLEARING CACHE"; +} + +foreach ($modules as $the_module => $fields) { + $class_name = $beanList[$the_module]; + echo "

    Scanning $the_module
    "; + + require_once ($beanFiles[$class_name]); + $mod = new $class_name (); + if (!$db->tableExists($mod->table_name."_cstm")) { + $mod->custom_fields = new DynamicField(); + $mod->custom_fields->setup($mod); + $mod->custom_fields->createCustomTable(); + } + + if ($db->dbType == 'oci8') { + } elseif ($db->dbType == 'mssql') { + $def_query="SELECT col.name as field, col_type.name as type, col.is_nullable, col.precision as data_precision, col.max_length as data_length, col.scale data_scale"; + $def_query.=" FROM sys.columns col"; + $def_query.=" join sys.types col_type on col.user_type_id=col_type.user_type_id "; + $def_query.=" where col.object_id = (select object_id(sys.schemas.name + '.' + sys.tables.name)"; + $def_query.=" from sys.tables join sys.schemas on sys.schemas.schema_id = sys.tables.schema_id"; + $def_query.=" where sys.tables.name='".$mod->table_name."_cstm')"; + $result = $db->query($def_query); + } + else { + $result = $db->query("DESCRIBE $mod->table_name"."_cstm"); + } + + while ($row = $db->fetchByAssoc($result)) { + $col = strtolower(empty ($row['Field']) ? $row['field'] : $row['Field']); + $the_field = $mod->custom_fields->getField($col); + $type = strtolower(empty ($row['Type']) ? $row['type'] : $row['Type']); + if ($db->dbType == 'oci8' or $db->dbType == 'mssql') { + if ($row['data_precision']!= '' and $row['data_scale']!='') { + $type.='(' . $row['data_precision']; + if (!empty($row['data_scale'])) { + $type.=',' . $row['data_scale']; + } + $type.=')'; + } else { + if ($row['data_length']!= '' && (strtolower($row['type'])=='varchar' or strtolower($row['type'])=='varchar2')) { + $type.='(' . $row['data_length'] . ')'; + + } + } + } + if (!isset ($fields[$col]) && $col != 'id_c') { + if (!$simulate) { + $db->query("ALTER TABLE $mod->table_name"."_cstm DROP COLUMN $col"); + } + unset ($fields[$col]); + echo "Dropping Column $col from $mod->table_name"."_cstm for module $the_module
    "; + } else { + if ($col != 'id_c') { + //$db_data_type = $dbManager->helper->getColumnType(strtolower($the_field->data_type)); + $db_data_type = strtolower(str_replace(' ' , '', $the_field->get_db_type())); + + $type = strtolower(str_replace(' ' , '', $type)); + if (strcmp($db_data_type,$type) != 0) { + + echo "Fixing Column Type for $col changing $type to ".$db_data_type."
    "; + if (!$simulate) { + $db->query($the_field->get_db_modify_alter_table($mod->table_name.'_cstm')); + } + } + } + + unset ($fields[$col]); + } + + } + + echo sizeof($fields)." field(s) missing from $mod->table_name"."_cstm
    "; + foreach ($fields as $field) { + echo "Adding Column $field to $mod->table_name"."_cstm
    "; + if (!$simulate) + $mod->custom_fields->add_existing_custom_field($field); + } + +} + +DynamicField :: deleteCache(); +echo '
    Done
    '; +if ($simulate) { + echo 'Execute non-simulation mode'; +} +?> \ No newline at end of file diff --git a/modules/Administration/UpgradeHistory.php b/modules/Administration/UpgradeHistory.php new file mode 100644 index 00000000..344198df --- /dev/null +++ b/modules/Administration/UpgradeHistory.php @@ -0,0 +1,288 @@ +dbManager->query( "delete from " . $this->table_name . " where id = '" . $this->id . "'" ); + } + + function UpgradeHistory() + { + parent::SugarBean(); + $this->disable_row_level_security = true; + } + + function getAllOrderBy($orderBy){ + $query = "SELECT id FROM " . $this->table_name . " ORDER BY ".$orderBy; + return $this->getList($query); + } + /** + * Given a name check if it exists in the table + * @param name the unique key from the manifest + * @param id the id of the item you are comparing to + * @return upgrade_history object if found, null otherwise + */ + function checkForExisting($patch_to_check){ + $uh = new UpgradeHistory(); + if($patch_to_check != null){ + + if(empty($patch_to_check->id_name)){ + $where = " WHERE name = '$patch_to_check->name' "; + }else{ + $where = " WHERE id_name = '$patch_to_check->id_name' "; + } + + if(!empty($patch_to_check->id)){ + $where .= " AND id != '$patch_to_check->id' "; + }else{ + $where .= " AND id is not null "; + } + + $query = "SELECT id FROM " . $this->table_name . " ". $where; + + $result = $uh->db->query($query); + if(empty($result)){ + return null; + } + $row = $uh->db->fetchByAssoc($result); + if(empty($row)){ + return null; + } + if(!empty($row['id'])){ + return $uh->retrieve($row['id']); + } + } + return null; + } + + /** + * Check if this is an upgrade, if it is then return the latest version before this installation + */ + function determineIfUpgrade($id_name, $version){ + $query = "SELECT id, version FROM " . $this->table_name . " WHERE id_name = '$id_name' ORDER BY date_entered DESC"; + $result = $this->db->query($query); + if(empty($result)){ + return null; + }else{ + $temp_version = 0; + $id = ''; + while($row = $this->db->fetchByAssoc($result)) + { + if(!$this->is_right_version_greater(explode('.', $row['version']), explode('.', $temp_version))){ + $temp_version = $row['version']; + $id = $row['id']; + } + }//end while + if($this->is_right_version_greater(explode('.', $temp_version), explode('.', $version), false)) + return array('id' => $id, 'version' => $temp_version); + else + return null; + } + } + + function getAll() + { + $query = "SELECT id FROM " . $this->table_name . " ORDER BY date_entered desc"; + return $this->getList($query); + } + + function getList($query){ + return( parent::build_related_list( $query, $this ) ); + } + + function findByMd5( $var_md5 ) + { + $query = "SELECT id FROM " . $this->table_name . " where md5sum = '$var_md5'"; + return( parent::build_related_list( $query, $this ) ); + } + + function UninstallAvailable($patch_list, $patch_to_check) + { + //before we even go through the list, let us try to see if we find a match. + $history_object = $this->checkForExisting($patch_to_check); + if($history_object != null){ + if((!empty($history_object->id_name) && !empty($patch_to_check->id_name) && strcmp($history_object->id_name, $patch_to_check->id_name) == 0) || strcmp($history_object->name, $patch_to_check->name) == 0){ + //we have found a match + //if the patch_to_check version is greater than the found version + return ($this->is_right_version_greater(explode('.', $history_object->version), explode('.', $patch_to_check->version))); + }else{ + return true; + } + } + //we will only go through this loop if we have not found another UpgradeHistory object + //with a matching unique_key in the database + foreach($patch_list as $more_recent_patch) + { + if($more_recent_patch->id == $patch_to_check->id) + break; + + //we will only resort to checking the files if we cannot find the unique_keys + //or the unique_keys do not match + $patch_to_check_backup_path = clean_path(remove_file_extension(from_html($patch_to_check->filename))).'-restore'; + $more_recent_patch_backup_path = clean_path(remove_file_extension(from_html($more_recent_patch->filename))).'-restore'; + if($this->foundConflict($patch_to_check_backup_path, $more_recent_patch_backup_path) && + ($more_recent_patch->date_entered >= $patch_to_check->date_entered)){ + return false; + } + } + + return true; + } + + function foundConflict($check_path, $recent_path) + { + if(is_file($check_path)) + { + if(file_exists($recent_path)) + return true; + else + return false; + } + elseif(is_dir($check_path)) + { + $status = false; + + $d = dir( $check_path ); + while( $f = $d->read() ) + { + if( $f == "." || $f == ".." ) + continue; + + $status = $this->foundConflict("$check_path/$f", "$recent_path/$f"); + + if($status) + break; + } + + $d->close(); + return( $status ); + } + + return false; + } + + /** + * Given a left version and a right version, determine if the right hand side is greater + * + * @param left the client sugar version + * @param right the server version + * + * return true if the right version is greater or they are equal + * false if the left version is greater + */ + function is_right_version_greater($left, $right, $equals_is_greater = true){ + if(count($left) == 0 && count($right) == 0){ + return $equals_is_greater; + } + else if(count($left) == 0 || count($right) == 0){ + return true; + } + else if($left[0] == $right[0]){ + array_shift($left); + array_shift($right); + return $this->is_right_version_greater($left, $right, $equals_is_greater); + } + else if($left[0] < $right[0]){ + return true; + } + else + return false; + } + + /** + * Given an array of id_names and versions, check if the dependencies are installed + * + * @param dependencies an array of id_name, version to check if these dependencies are installed + * on the system + * + * @return not_found an array of id_names that were not found to be installed on the system + */ + function checkDependencies($dependencies = array()){ + $not_found = array(); + foreach($dependencies as $dependent){ + $found = false; + $query = "SELECT id FROM $this->table_name WHERE id_name = '".$dependent['id_name']."'"; + $matches = $this->getList($query); + if(0 != sizeof($matches)){ + foreach($matches as $match){ + if($this->is_right_version_greater(explode('.', $match->version), explode('.', $dependent['version']))){ + $found = true; + break; + }//fi + }//rof + }//fi + if(!$found){ + $not_found[] = $dependent['id_name']; + }//fi + }//rof + return $not_found; + } + function retrieve($id = -1, $encode=true,$deleted=true) { + return parent::retrieve($id,$encode,false); //ignore the deleted filter. the table does not have the deleted column in it. + } + +} +?> \ No newline at end of file diff --git a/modules/Administration/UpgradeIISAccess.php b/modules/Administration/UpgradeIISAccess.php new file mode 100644 index 00000000..b31b57f1 --- /dev/null +++ b/modules/Administration/UpgradeIISAccess.php @@ -0,0 +1,43 @@ +debug("detected upload_max_filesize: $upload_max_filesize"); + print('

    ' . $mod_strings['MSG_INCREASE_UPLOAD_MAX_FILESIZE'] . ' ' + . get_cfg_var('cfg_file_path') . "

    \n"); +} + +// +// process "run" commands +// + +if( isset( $_REQUEST['run'] ) && ($_REQUEST['run'] != "") ){ + $run = $_REQUEST['run']; + + if( $run == "upload" ){ + $perform = false; + if(isset($_REQUEST['release_id']) && $_REQUEST['release_id'] != ""){ + require_once('ModuleInstall/PackageManager.php'); + $pm = new PackageManager(); + $tempFile = $pm->download('','',$_REQUEST['release_id'], getAbsolutePath($sugar_config['upload_dir'],true)); + $perform = true; + $base_filename = urldecode($tempFile); + } + elseif(!empty($_REQUEST['load_module_from_dir'])){ + //copy file to proper location then call performSetup + $tempFile = getAbsolutePath($sugar_config['upload_dir'].$_REQUEST['upgrade_zip_escaped'],true); + copy($_REQUEST['load_module_from_dir'].'/'.$_REQUEST['upgrade_zip_escaped'], $tempFile); + + $perform = true; + $base_filename = urldecode( $_REQUEST['upgrade_zip_escaped'] ); + }else if( empty( $_FILES['upgrade_zip']['tmp_name'] ) ){ + echo $mod_strings['ERR_UW_NO_UPLOAD_FILE']; + } + else{ + $ext = end(explode(".", $_FILES['upgrade_zip']['name'])); + if($ext === $_FILES['upgrade_zip']['name'] || $ext != 'zip' || !move_uploaded_file($_FILES['upgrade_zip']['tmp_name'], getAbsolutePath($sugar_config['upload_dir'].$_FILES['upgrade_zip']['name'],true))) { + unlinkTempFiles(); + sugar_die("Invalid Package"); + } else { + $tempFile = getAbsolutePath($sugar_config['upload_dir'].$_FILES['upgrade_zip']['name'],true); + $perform = true; + $base_filename = urldecode( $_REQUEST['upgrade_zip_escaped'] ); + } + } + if($perform){ + $manifest_file = extractManifest( $tempFile ); + if(is_file($manifest_file)) + { + //SCAN THE MANIFEST FILE TO MAKE SURE NO COPIES OR ANYTHING ARE HAPPENING IN IT + $ms = new ModuleScanner(); + $fileIssues = $ms->scanFile($manifest_file); + if(!empty($fileIssues)){ + echo '

    ' . $mod_strings['ML_MANIFEST_ISSUE'] . '


    '; + $ms->displayIssues(); + die(); + } + require_once( $manifest_file ); + validate_manifest( $manifest ); + + $upgrade_zip_type = $manifest['type']; + + // exclude the bad permutations + if( $view == "module" ) + { + if ($upgrade_zip_type != "module" && $upgrade_zip_type != "theme" && $upgrade_zip_type != "langpack") + { + unlinkTempFiles(); + die($mod_strings['ERR_UW_NOT_ACCEPTIBLE_TYPE']); + } + } + elseif( $view == "default" ) + { + if($upgrade_zip_type != "patch" ) + { + unlinkTempFiles(); + die($mod_strings['ERR_UW_ONLY_PATCHES']); + } + } + + //$base_filename = urldecode( $_REQUEST['upgrade_zip_escaped'] ); + $base_filename = preg_replace( "#\\\\#", "/", $base_filename ); + $base_filename = basename( $base_filename ); + + mkdir_recursive( "$base_upgrade_dir/$upgrade_zip_type" ); + $target_path = "$base_upgrade_dir/$upgrade_zip_type/$base_filename"; + $target_manifest = remove_file_extension( $target_path ) . "-manifest.php"; + + if( isset($manifest['icon']) && $manifest['icon'] != "" ){ + $icon_location = extractFile( $tempFile ,$manifest['icon'] ); + $path_parts = pathinfo( $icon_location ); + copy( $icon_location, remove_file_extension( $target_path ) . "-icon." . $path_parts['extension'] ); + } + + if( copy( $tempFile , $target_path ) ){ + copy( $manifest_file, $target_manifest ); + $GLOBALS['ML_STATUS_MESSAGE'] = $base_filename.$mod_strings['LBL_UW_UPLOAD_SUCCESS']; + } + else{ + $GLOBALS['ML_STATUS_MESSAGE'] = $mod_strings['ERR_UW_UPLOAD_ERROR']; + } + } + else + { + unlinkTempFiles(); + die($mod_strings['ERR_UW_NO_MANIFEST']); + } + } + } + else if( $run == $mod_strings['LBL_UW_BTN_DELETE_PACKAGE'] ){ + if(!empty ($_REQUEST['install_file']) ){ + die($mod_strings['ERR_UW_NO_UPLOAD_FILE']); + } + + $delete_me = hashToFile($delete_me); + + $checkFile = clean_path(trim(strtolower($delete_me))); + + if(false !== strpos($checkFile, '.zip')) { // is zip file? + if(false !== strpos($checkFile, $sugar_config['upload_dir'])) { // is in upload dir? + if(false === strpos($checkFile, "..")) { // no dir navigation + if(!file_exists($checkFile)) { // file exists? + if(unlink($delete_me)) { // successful deletion? + echo "Package $delete_me has been removed.
    "; + } else { + die("Problem removing package $delete_me."); + } + } else { + die("File to be deleted does not exist."); + } + } else { + die("Path is trying to navigate folders."); + } + } else { + die("File is not located in SugarCRM's upload cache directory."); + } + } else { + die("File is not a zipped archive."); + } + } +} + +if( $view == "module") { + print( getClassicModuleTitle($mod_strings['LBL_MODULE_NAME'], array($mod_strings['LBL_MODULE_LOADER_TITLE']), false) ); +} +else { + print( getClassicModuleTitle($mod_strings['LBL_MODULE_NAME'], array($mod_strings['LBL_MODULE_NAME'],$mod_strings['LBL_UPGRADE_WIZARD_TITLE']), false) ); +} + +// upload link +if(!empty($GLOBALS['sugar_config']['use_common_ml_dir']) && $GLOBALS['sugar_config']['use_common_ml_dir'] && !empty($GLOBALS['sugar_config']['common_ml_dir'])){ + //rrs + $form = '
    '; + $form .= '
    '.$mod_strings['LBL_MODULE_UPLOAD_DISABLE_HELP_TEXT'].'
    '; + $form .=''; + if ($handle = opendir($GLOBALS['sugar_config']['common_ml_dir'])) { + while (false !== ($filename = readdir($handle))) { + if($filename == '.' || $filename == '..' || !preg_match("#.*\.zip\$#", $filename)) { + continue; + } + $form .= ''; + } + } + $form .= '
    '.$mod_strings['LBL_ML_NAME'].''.$mod_strings['LBL_ML_ACTION'].'
    '.$filename.'
    '; +//rrs + +}else{ +$form =<< + +
    + + + + +
    +{$uploaddLabel} + + + + + +
    + +eoq; +} +$hidden_fields = ""; +$hidden_fields .= ""; +$form2 = PackageManagerDisplay::buildPackageDisplay($form, $hidden_fields, $form_action, array('module')); +$form3 =<<\n"); +print( "
      \n" ); +$upgrade_contents = findAllFiles( "$base_upgrade_dir", array() ); +$upgrades_available = 0; + +print( "\n" ); +print( "\n" ); +foreach($upgrade_contents as $upgrade_content) +{ + if(!preg_match("#.*\.zip\$#", $upgrade_content)) + { + continue; + } + + $upgrade_content = clean_path($upgrade_content); + $the_base = basename($upgrade_content); + $the_md5 = md5_file($upgrade_content); + $md5_matches = $uh->findByMd5($the_md5); + + if(0 == sizeof($md5_matches)) + { + $target_manifest = remove_file_extension( $upgrade_content ) . '-manifest.php'; + require_once($target_manifest); + + $name = empty($manifest['name']) ? $upgrade_content : $manifest['name']; + $version = empty($manifest['version']) ? '' : $manifest['version']; + $published_date = empty($manifest['published_date']) ? '' : $manifest['published_date']; + $icon = ''; + $description = empty($manifest['description']) ? 'None' : $manifest['description']; + $uninstallable = empty($manifest['is_uninstallable']) ? 'No' : 'Yes'; + $type = getUITextForType( $manifest['type'] ); + $manifest_type = $manifest['type']; + + if($view == 'default' && $manifest_type != 'patch') + { + continue; + } + + if($view == 'module' + && $manifest_type != 'module' && $manifest_type != 'theme' && $manifest_type != 'langpack') + { + continue; + } + + if(empty($manifest['icon'])) + { + $icon = getImageForType( $manifest['type'] ); + } + else + { + $path_parts = pathinfo( $manifest['icon'] ); + $icon = ""; + } + + $upgrades_available++; + print( "\n" ); + + $upgrade_content = urlencode($upgrade_content); + + $form2 =<< + + + + + + + + + + +eoq; + echo $form2; + } +} +print( "
      {$mod_strings['LBL_ML_NAME']}{$mod_strings['LBL_ML_TYPE']}{$mod_strings['LBL_ML_VERSION']}{$mod_strings['LBL_ML_PUBLISHED']}{$mod_strings['LBL_ML_UNINSTALLABLE']}{$mod_strings['LBL_ML_DESCRIPTION']}
      $icon$name$type$version$published_date$uninstallable$description
      \n" ); + +if( $upgrades_available == 0 ){ + print($mod_strings['LBL_UW_NONE']); +} +print( "
    \n" ); + +?> +*/ + +$GLOBALS['log']->info( "Upgrade Wizard view"); + +?> + + + diff --git a/modules/Administration/UpgradeWizardCommon.php b/modules/Administration/UpgradeWizardCommon.php new file mode 100644 index 00000000..b44b77fc --- /dev/null +++ b/modules/Administration/UpgradeWizardCommon.php @@ -0,0 +1,264 @@ + constant('SUGARCRM_PRE_INSTALL_FILE'), + "post-install" => constant('SUGARCRM_POST_INSTALL_FILE'), + "pre-uninstall" => constant('SUGARCRM_PRE_UNINSTALL_FILE'), + "post-uninstall" => constant('SUGARCRM_POST_UNINSTALL_FILE'), +); + + +function extractFile( $zip_file, $file_in_zip ){ + global $base_tmp_upgrade_dir; + if(empty($base_tmp_upgrade_dir)){ + $base_tmp_upgrade_dir = $GLOBALS['sugar_config']['upload_dir'] . "upgrades/temp"; + } + $my_zip_dir = mk_temp_dir( $base_tmp_upgrade_dir ); + unzip_file( $zip_file, $file_in_zip, $my_zip_dir ); + return( "$my_zip_dir/$file_in_zip" ); +} + +function extractManifest( $zip_file ){ + return( extractFile( $zip_file, "manifest.php" ) ); +} + +function getInstallType( $type_string ){ + // detect file type + global $subdirs; + + foreach( $subdirs as $subdir ){ + if( preg_match( "#/$subdir/#", $type_string ) ){ + return( $subdir ); + } + } + // return empty if no match + return( "" ); +} + +function getImageForType( $type ){ + + $icon = ""; + switch( $type ){ + case "full": + $icon = SugarThemeRegistry::current()->getImage("Upgrade", "" ); + break; + case "langpack": + $icon = SugarThemeRegistry::current()->getImage("LanguagePacks", "" ); + break; + case "module": + $icon = SugarThemeRegistry::current()->getImage("ModuleLoader", "" ); + break; + case "patch": + $icon = SugarThemeRegistry::current()->getImage("PatchUpgrades", "" ); + break; + case "theme": + $icon = SugarThemeRegistry::current()->getImage("Themes", "" ); + break; + default: + break; + } + return( $icon ); +} + +function getLanguagePackName( $the_file ){ + global $app_list_strings; + require_once( "$the_file" ); + if( isset( $app_list_strings["language_pack_name"] ) ){ + return( $app_list_strings["language_pack_name"] ); + } + return( "" ); +} + +function getUITextForType( $type ){ + $type = 'LBL_UW_TYPE_'.strtoupper($type); + global $mod_strings; + return $mod_strings[$type]; +} + +function getUITextForMode( $mode ){ + $mode = 'LBL_UW_MODE_'.strtoupper($mode); + global $mod_strings; + return $mod_strings[$mode]; +} + +/** + * @deprecated + * @todo this function doesn't seemed to be used anymore; trying kill this off + */ +function run_upgrade_wizard_sql( $script ){ + global $unzip_dir; + global $sugar_config; + global $mod_strings; + + $db_type = $sugar_config['dbconfig']['db_type']; + $script = str_replace( "%db_type%", $db_type, $script ); + if( !run_sql_file( "$unzip_dir/$script" ) ){ + die( "{$mod_strings['ERR_UW_RUN_SQL']} $unzip_dir/$script" ); + } +} + +function validate_manifest( $manifest ){ + // takes a manifest.php manifest array and validates contents + global $subdirs; + global $sugar_version; + global $sugar_flavor; + global $mod_strings; + + if( !isset($manifest['type']) ){ + die($mod_strings['ERROR_MANIFEST_TYPE']); + } + $type = $manifest['type']; + if( getInstallType( "/$type/" ) == "" ){ + die($mod_strings['ERROR_PACKAGE_TYPE']. ": '" . $type . "'." ); + } + + if( isset($manifest['acceptable_sugar_versions']) ){ + $version_ok = false; + $matches_empty = true; + if( isset($manifest['acceptable_sugar_versions']['exact_matches']) ){ + $matches_empty = false; + foreach( $manifest['acceptable_sugar_versions']['exact_matches'] as $match ){ + if( $match == $sugar_version ){ + $version_ok = true; + } + } + } + if( !$version_ok && isset($manifest['acceptable_sugar_versions']['regex_matches']) ){ + $matches_empty = false; + foreach( $manifest['acceptable_sugar_versions']['regex_matches'] as $match ){ + if( preg_match( "/$match/", $sugar_version ) ){ + $version_ok = true; + } + } + } + + if( !$matches_empty && !$version_ok ){ + die( $mod_strings['ERROR_VERSION_INCOMPATIBLE'] . $sugar_version ); + } + } + + if( isset($manifest['acceptable_sugar_flavors']) && sizeof($manifest['acceptable_sugar_flavors']) > 0 ){ + $flavor_ok = false; + foreach( $manifest['acceptable_sugar_flavors'] as $match ){ + if( $match == $sugar_flavor ){ + $flavor_ok = true; + } + } + if( !$flavor_ok ){ + die( $mod_strings['ERROR_FLAVOR_INCOMPATIBLE'] . $sugar_flavor ); + } + } +} + +function getDiffFiles($unzip_dir, $install_file, $is_install = true, $previous_version = ''){ + //require_once($unzip_dir . '/manifest.php'); + global $installdefs; + if(!empty($previous_version)){ + //check if the upgrade path exists + if(!empty($upgrade_manifest)){ + if(!empty($upgrade_manifest['upgrade_paths'])){ + if(!empty($upgrade_manifest['upgrade_paths'][$previous_version])){ + $installdefs = $upgrade_manifest['upgrade_paths'][$previous_version]; + } + }//fi + }//fi + }//fi + $modified_files = array(); + if(!empty($installdefs['copy'])){ + foreach($installdefs['copy'] as $cp){ + $cp['to'] = clean_path(str_replace('', $unzip_dir, $cp['to'])); + $restore_path = remove_file_extension(urldecode($install_file))."-restore/"; + $backup_path = clean_path($restore_path.$cp['to'] ); + //check if this file exists in the -restore directory + if(file_exists($backup_path)){ + //since the file exists, then we want do an md5 of the install version and the file system version + $from = $backup_path; + $needle = $restore_path; + if(!$is_install){ + $from = str_replace('', $unzip_dir, $cp['from']); + $needle = $unzip_dir; + } + $files_found = md5DirCompare($from.'/', $cp['to'].'/', array('.svn'), false); + if(count($files_found > 0)){ + foreach($files_found as $key=>$value){ + $modified_files[] = str_replace($needle, '', $key); + } + } + }//fi + }//rof + }//fi + return $modified_files; +} +?> diff --git a/modules/Administration/UpgradeWizard_commit.php b/modules/Administration/UpgradeWizard_commit.php new file mode 100644 index 00000000..89be3719 --- /dev/null +++ b/modules/Administration/UpgradeWizard_commit.php @@ -0,0 +1,555 @@ +info('Deleting Relationship Cache. Relationships will automatically refresh.'); + + echo " +
    + "; + + $log->info('Rebuilding everything.'); + require_once('ModuleInstall/ModuleInstaller.php'); + $mi = new ModuleInstaller(); + $mi->rebuild_all(); + $query = "DELETE FROM versions WHERE name='Rebuild Extensions'"; + $log->info($query); + $db->query($query); + + // insert a new database row to show the rebuild extensions is done + $id = create_guid(); + $gmdate = TimeDate::getInstance()->nowDb(); + $date_entered = db_convert("'$gmdate'", 'datetime'); + $query = 'INSERT INTO versions (id, deleted, date_entered, date_modified, modified_user_id, created_by, name, file_version, db_version) ' + . "VALUES ('$id', '0', $date_entered, $date_entered, '1', '1', 'Rebuild Extensions', '4.0.0', '4.0.0')"; + $log->info($query); + $db->query($query); +} + +unset($_SESSION['rebuild_relationships']); +unset($_SESSION['rebuild_extensions']); + +$log =& $GLOBALS['log']; +$db =& $GLOBALS['db']; + +// process commands +if( !isset($_REQUEST['mode']) || ($_REQUEST['mode'] == "") ){ + die($mod_strings['ERR_UW_NO_MODE']); +} +$mode = $_REQUEST['mode']; + + +if( !isset($_REQUEST['version']) ){ + die($mod_strings['ERR_UW_NO_MODE']); +} +$version = $_REQUEST['version']; + +if( !isset($_REQUEST['copy_count']) || ($_REQUEST['copy_count'] == "") ){ + die($mod_strings['ERR_UW_NO_FILES']); +} + +if( !isset($_REQUEST['unzip_dir']) || ($_REQUEST['unzip_dir'] == "") ){ + die($mod_strings['ERR_UW_NO_TEMP_DIR']); +} +$unzip_dir = $_REQUEST['unzip_dir']; + +if(empty($_REQUEST['install_file'])){ + die($mod_strings['ERR_UW_NO_INSTALL_FILE']); +} + +$install_file = hashToFile($_REQUEST['install_file'] ); +$install_type = getInstallType( $install_file ); +$id_name = ''; +if(isset($_REQUEST['id_name'])){ + $id_name = $_REQUEST['id_name']; +} +$s_manifest = ''; +if(isset($_REQUEST['s_manifest'])){ + $s_manifest = $_REQUEST['s_manifest']; +} +$previous_version = ''; +if(isset($_REQUEST['previous_version'])){ + $previous_version = $_REQUEST['previous_version']; +} +$previous_id = ''; +if(isset($_REQUEST['previous_id'])){ + $previous_id = $_REQUEST['previous_id']; +} +if( $install_type != "module" ){ + if( !isset($_REQUEST['zip_from_dir']) || ($_REQUEST['zip_from_dir'] == "") ){ + $zip_from_dir = "."; + } + else{ + $zip_from_dir = $_REQUEST['zip_from_dir']; + } + if( !isset($_REQUEST['zip_to_dir']) || ($_REQUEST['zip_to_dir'] == "") ){ + $zip_to_dir = "."; + } + else{ + $zip_to_dir = $_REQUEST['zip_to_dir']; + } +} +$remove_tables = 'true'; +if(isset($_REQUEST['remove_tables'])){ + $remove_tables = $_REQUEST['remove_tables']; +} +$overwrite_files = true; +if(isset($_REQUEST['radio_overwrite'])){ + $overwrite_files = (($_REQUEST['radio_overwrite'] == 'do_not_overwrite') ? false : true); +} + +//rrs +$author = ''; +$is_uninstallable = true; +$name = ''; +$description = ''; + +if($install_type == 'module'){ + $is_uninstallable = $_REQUEST['is_uninstallable']; + $name = $_REQUEST['name']; + $description = $_REQUEST['description']; +} + + +$file_action = ""; +$uh_status = ""; + +$rest_dir = clean_path( remove_file_extension($install_file)."-restore"); + +$files_to_handle = array(); + +if(!empty($GLOBALS['sugar_config']['moduleInstaller']['packageScan']) && $install_type != 'patch'){ + require_once('ModuleInstall/ModuleScanner.php'); + $ms = new ModuleScanner(); + $ms->scanPackage($unzip_dir); + if($ms->hasIssues()){ + $ms->displayIssues(); + sugar_cleanup(true); + } +} + +// +// execute the PRE scripts +// +if($install_type == 'patch' || $install_type == 'module') +{ + switch($mode) + { + case 'Install': + $file = "$unzip_dir/" . constant('SUGARCRM_PRE_INSTALL_FILE'); + if(is_file($file)) + { + print("{$mod_strings['LBL_UW_INCLUDING']}: $file
    \n"); + include($file); + pre_install(); + } + break; + case 'Uninstall': + $file = "$unzip_dir/" . constant('SUGARCRM_PRE_UNINSTALL_FILE'); + if(is_file($file)) + { + print("{$mod_strings['LBL_UW_INCLUDING']}: $file
    \n"); + include($file); + pre_uninstall(); + } + break; + default: + break; + } +} + +// +// perform the action +// + +for( $iii = 0; $iii < $_REQUEST['copy_count']; $iii++ ){ + if( isset($_REQUEST["copy_" . $iii]) && ($_REQUEST["copy_" . $iii] != "") ){ + $file_to_copy = $_REQUEST["copy_" . $iii]; + $src_file = clean_path( "$unzip_dir/$zip_from_dir/$file_to_copy" ); + + $sugar_home_dir = getCwd(); + $dest_file = clean_path( "$sugar_home_dir/$zip_to_dir/$file_to_copy" ); + if($zip_to_dir != '.') + $rest_file = clean_path("$rest_dir/$zip_to_dir/$file_to_copy"); + else + $rest_file = clean_path("$rest_dir/$file_to_copy"); + + switch( $mode ){ + case "Install": + mkdir_recursive( dirname( $dest_file ) ); + + if($install_type=="patch" && is_file($dest_file)) + { + if(!is_dir(dirname( $rest_file ))) + mkdir_recursive( dirname( $rest_file ) ); + + copy( $dest_file, $rest_file); + sugar_touch( $rest_file, filemtime($dest_file) ); + } + + if( !copy( $src_file, $dest_file ) ){ + die( $mod_strings['ERR_UW_COPY_FAILED'].$src_file.$mod_strings['LBL_TO'].$dest_file); + } + $uh_status = "installed"; + break; + case "Uninstall": + if($install_type=="patch" && is_file($rest_file)) + { + copy( $rest_file, $dest_file); + sugar_touch( $dest_file, filemtime($rest_file) ); + } + elseif(file_exists($dest_file) && !unlink($dest_file)) + { + die($mod_strings['ERR_UW_REMOVE_FAILED'].$dest_file); + } + $uh_status = "uninstalled"; + break; + default: + die("{$mod_strings['LBL_UW_OP_MODE']} '$mode' {$mod_strings['ERR_UW_NOT_RECOGNIZED']}." ); + } + $files_to_handle[] = clean_path( "$zip_to_dir/$file_to_copy" ); + } +} + +switch( $install_type ){ + case "langpack": + if( !isset($_REQUEST['new_lang_name']) || ($_REQUEST['new_lang_name'] == "") ){ + die($mod_strings['ERR_UW_NO_LANG']); + } + if( !isset($_REQUEST['new_lang_desc']) || ($_REQUEST['new_lang_desc'] == "") ){ + die($mod_strings['ERR_UW_NO_LANG_DESC']); + } + + if( $mode == "Install" || $mode=="Enable" ){ + $sugar_config['languages'] = $sugar_config['languages'] + array( $_REQUEST['new_lang_name'] => $_REQUEST['new_lang_desc'] ); + } + else if( $mode == "Uninstall" || $mode=="Disable" ){ + $new_langs = array(); + $old_langs = $sugar_config['languages']; + foreach( $old_langs as $key => $value ){ + if( $key != $_REQUEST['new_lang_name'] ){ + $new_langs += array( $key => $value ); + } + } + $sugar_config['languages'] = $new_langs; + + $default_sugar_instance_lang = 'en_us'; + if($current_language == $_REQUEST['new_lang_name']){ + $_SESSION['authenticated_user_language'] =$default_sugar_instance_lang; + $lang_changed_string = $mod_strings['LBL_CURRENT_LANGUAGE_CHANGE'].$sugar_config['languages'][$default_sugar_instance_lang].'
    '; + } + + if($sugar_config['default_language'] == $_REQUEST['new_lang_name']){ + $cfg = new Configurator(); + $cfg->config['languages'] = $new_langs; + $cfg->config['default_language'] = $default_sugar_instance_lang; + $cfg->handleOverride(); + $lang_changed_string .= $mod_strings['LBL_DEFAULT_LANGUAGE_CHANGE'].$sugar_config['languages'][$default_sugar_instance_lang].'
    '; + } + } + ksort( $sugar_config ); + if( !write_array_to_file( "sugar_config", $sugar_config, "config.php" ) ){ + die($mod_strings['ERR_UW_CONFIG_FAILED']); + } + break; + case "module": + require_once( "ModuleInstall/ModuleInstaller.php" ); + $mi = new ModuleInstaller(); + switch( $mode ){ + case "Install": + //here we can determine if this is an upgrade or a new version + if(!empty($previous_version)){ + $mi->install( "$unzip_dir", true, $previous_version); + }else{ + $mi->install( "$unzip_dir" ); + } + + $file = "$unzip_dir/" . constant('SUGARCRM_POST_INSTALL_FILE'); + if(is_file($file)) + { + print("{$mod_strings['LBL_UW_INCLUDING']}: $file
    \n"); + include($file); + post_install(); + } + break; + case "Uninstall": + if($remove_tables == 'false') + $GLOBALS['mi_remove_tables'] = false; + else + $GLOBALS['mi_remove_tables'] = true; + $mi->uninstall( "$unzip_dir" ); + break; + case "Disable": + if(!$overwrite_files) + $GLOBALS['mi_overwrite_files'] = false; + else + $GLOBALS['mi_overwrite_files'] = true; + $mi->disable( "$unzip_dir" ); + break; + case "Enable": + if(!$overwrite_files) + $GLOBALS['mi_overwrite_files'] = false; + else + $GLOBALS['mi_overwrite_files'] = true; + $mi->enable( "$unzip_dir" ); + break; + default: + break; + } + break; + case "full": + // purposely flow into "case: patch" + case "patch": + switch($mode) + { + case 'Install': + $file = "$unzip_dir/" . constant('SUGARCRM_POST_INSTALL_FILE'); + if(is_file($file)) + { + print("{$mod_strings['LBL_UW_INCLUDING']}: $file
    \n"); + include($file); + post_install(); + } + + UWrebuild(); + break; + case 'Uninstall': + $file = "$unzip_dir/" . constant('SUGARCRM_POST_UNINSTALL_FILE'); + if(is_file($file)) { + print("{$mod_strings['LBL_UW_INCLUDING']}: $file
    \n"); + include($file); + post_uninstall(); + } + + if(is_dir($rest_dir)) + { + rmdir_recursive($rest_dir); + } + + UWrebuild(); + break; + default: + break; + } + + require( "sugar_version.php" ); + $sugar_config['sugar_version'] = $sugar_version; + ksort( $sugar_config ); + + if( !write_array_to_file( "sugar_config", $sugar_config, "config.php" ) ) + { + die($mod_strings['ERR_UW_UPDATE_CONFIG']); + } + break; + default: + break; +} + +switch( $mode ){ + case "Install": + $file_action = "copied"; + // if error was encountered, script should have died before now + $new_upgrade = new UpgradeHistory(); + //determine if this module has already been installed given the unique_key to + //identify the module + // $new_upgrade->checkForExisting($unique_key); + if(!empty($previous_id)){ + $new_upgrade->id = $previous_id; + $uh = new UpgradeHistory(); + $uh->retrieve($previous_id); + if(is_file($uh->filename)) { + unlink($uh->filename); + } + } + $new_upgrade->filename = $install_file; + $new_upgrade->md5sum = md5_file( $install_file ); + $new_upgrade->type = $install_type; + $new_upgrade->version = $version; + $new_upgrade->status = "installed"; + $new_upgrade->name = $name; + $new_upgrade->description = $description; + $new_upgrade->id_name = $id_name; + $new_upgrade->manifest = $s_manifest; + $new_upgrade->save(); + + //Check if we need to show a page for the user to finalize their install with. + if (is_file("$unzip_dir/manifest.php")) + { + include("$unzip_dir/manifest.php"); + if (!empty($manifest['post_install_url'])) + { + $url_conf = $manifest['post_install_url']; + if (is_string($url_conf)) + $url_conf = array('url' => $url_conf); + if (isset($url_conf['type']) && $url_conf['type'] == 'popup') + { + echo ''; + } else + { + echo ''; + } + } + } + break; + case "Uninstall": + $file_action = "removed"; + $uh = new UpgradeHistory(); + $the_md5 = md5_file( $install_file ); + $md5_matches = $uh->findByMd5( $the_md5 ); + if( sizeof( $md5_matches ) == 0 ){ + die( "{$mod_strings['ERR_UW_NO_UPDATE_RECORD']} $install_file." ); + } + foreach( $md5_matches as $md5_match ){ + $md5_match->delete(); + } + break; + case "Disable": + $file_action = "disabled"; + $uh = new UpgradeHistory(); + $the_md5 = md5_file( $install_file ); + $md5_matches = $uh->findByMd5( $the_md5 ); + if( sizeof( $md5_matches ) == 0 ){ + die( "{$mod_strings['ERR_UW_NO_UPDATE_RECORD']} $install_file." ); + } + foreach( $md5_matches as $md5_match ){ + $md5_match->enabled = 0; + $md5_match->save(); + } + break; + case "Enable": + $file_action = "enabled"; + $uh = new UpgradeHistory(); + $the_md5 = md5_file( $install_file ); + $md5_matches = $uh->findByMd5( $the_md5 ); + if( sizeof( $md5_matches ) == 0 ){ + die( "{$mod_strings['ERR_UW_NO_UPDATE_RECORD']} $install_file." ); + } + foreach( $md5_matches as $md5_match ){ + $md5_match->enabled = 1; + $md5_match->save(); + } + break; +} + +// present list to user +?> +
    + + +"; +print( getUITextForType($install_type) . " ". getUITextForMode($mode) . " ". $mod_strings['LBL_UW_SUCCESSFULLY']); +echo "
    "; +echo "
    "; +print( "
    " ); +echo "
    "; +echo "
    "; +if(isset($lang_changed_string)) + print($lang_changed_string); +if ($install_type != "module" && $install_type != "langpack"){ + if( sizeof( $files_to_handle ) > 0 ){ + echo '
    Show Details
    +
    Hide Details

    '; + print( "{$mod_strings['LBL_UW_FOLLOWING_FILES']} $file_action:
    \n" ); + print( "
      \n" ); + foreach( $files_to_handle as $file_to_copy ){ + print( "
    • $file_to_copy
      \n" ); + } + print( "
    \n" ); + echo '
    '; + } + else if( $mode != 'Disable' && $mode !='Enable' ){ + print( "{$mod_strings['LBL_UW_NO_FILES_SELECTED']} $file_action.
    \n" ); + } + + print($mod_strings['LBL_UW_UPGRADE_SUCCESSFUL']); + print( "\n" ); +} +?> + + +info( "Upgrade Wizard patches" ); +?> \ No newline at end of file diff --git a/modules/Administration/UpgradeWizard_prepare.php b/modules/Administration/UpgradeWizard_prepare.php new file mode 100644 index 00000000..58bb0046 --- /dev/null +++ b/modules/Administration/UpgradeWizard_prepare.php @@ -0,0 +1,534 @@ +"; + + +$install_type = getInstallType( $install_file ); + +$version = ""; +$previous_version = ""; +$show_files = true; + +$zip_from_dir = "."; +$zip_to_dir = "."; +$zip_force_copy = array(); +$license_file = $unzip_dir.'/LICENSE.txt'; +$readme_file = $unzip_dir.'/README.txt'; +$require_license = false; +$found_readme = false; +$author = ''; +$name = ''; +$description = ''; +$is_uninstallable = true; +$id_name = ''; +$dependencies = array(); +$remove_tables = 'true'; + +unzip( $install_file, $unzip_dir ); +if($install_type == 'module' && $mode != 'Uninstall'){ + if(file_exists($license_file)){ + $require_license = true; + } +} + +//Scan the unzip dir for unsafe files +if(!empty($GLOBALS['sugar_config']['moduleInstaller']['packageScan']) && $install_type != 'patch'){ + require_once('ModuleInstall/ModuleScanner.php'); + $ms = new ModuleScanner(); + $ms->scanPackage($unzip_dir); + if($ms->hasIssues()){ + $ms->displayIssues(); + sugar_cleanup(true); + } +} + +// assumption -- already validated manifest.php at time of upload +require_once( "$unzip_dir/manifest.php" ); + + + +if( isset( $manifest['copy_files']['from_dir'] ) && $manifest['copy_files']['from_dir'] != "" ){ + $zip_from_dir = $manifest['copy_files']['from_dir']; +} +if( isset( $manifest['copy_files']['to_dir'] ) && $manifest['copy_files']['to_dir'] != "" ){ + $zip_to_dir = $manifest['copy_files']['to_dir']; +} +if( isset( $manifest['copy_files']['force_copy'] ) && $manifest['copy_files']['force_copy'] != "" ){ + $zip_force_copy = $manifest['copy_files']['force_copy']; +} +if( isset( $manifest['version'] ) ){ + $version = $manifest['version']; +} +if( isset( $manifest['author'] ) ){ + $author = $manifest['author']; +} +if( isset( $manifest['name'] ) ){ + $name = $manifest['name']; +} +if( isset( $manifest['description'] ) ){ + $description = $manifest['description']; +} +if( isset( $manifest['is_uninstallable'] ) ){ + $is_uninstallable = $manifest['is_uninstallable']; +} +if(isset($installdefs) && isset( $installdefs['id'] ) ){ + $id_name = $installdefs['id']; +} +if( isset( $manifest['dependencies']) ){ + $dependencies = $manifest['dependencies']; +} +if( isset( $manifest['remove_tables']) ){ + $remove_tables = $manifest['remove_tables']; +} + +if($remove_tables != 'prompt'){ + $hidden_fields .= ""; +} +if(file_exists($readme_file) || !empty($manifest['readme'])){ + $found_readme = true; + } +$uh = new UpgradeHistory(); +//check dependencies first +if(!empty($dependencies)){ + $not_found = $uh->checkDependencies($dependencies); + if(!empty($not_found) && count($not_found) > 0){ + die( $mod_strings['ERR_UW_NO_DEPENDENCY']."[".implode(',', $not_found)."]"); + }//fi +} +switch( $install_type ){ + case "full": + case "patch": + if( !is_writable( "config.php" ) ){ + die( $mod_strings['ERR_UW_CONFIG'] ); + } + break; + case "theme": + break; + case "langpack": + // find name of language pack: find single file in include/language/xx_xx.lang.php + $d = dir( "$unzip_dir/$zip_from_dir/include/language" ); + while( $f = $d->read() ){ + if( $f == "." || $f == ".." ){ + continue; + } + else if( preg_match("/(.*)\.lang\.php\$/", $f, $match) ){ + $new_lang_name = $match[1]; + } + } + if( $new_lang_name == "" ){ + die( $mod_strings['ERR_UW_NO_LANGPACK'].$install_file ); + } + $hidden_fields .= ""; + + $new_lang_desc = getLanguagePackName( "$unzip_dir/$zip_from_dir/include/language/$new_lang_name.lang.php" ); + if( $new_lang_desc == "" ){ + die( $mod_strings['ERR_UW_NO_LANG_DESC_1']."include/language/$new_lang_name.lang.php".$mod_strings['ERR_UW_NO_LANG_DESC_2']."$install_file." ); + } + $hidden_fields .= ""; + + if( !is_writable( "config.php" ) ){ + die( $mod_strings['ERR_UW_CONFIG'] ); + } + break; + case "module": + $previous_install = array(); + if(!empty($id_name) & !empty($version)) + $previous_install = $uh->determineIfUpgrade($id_name, $version); + $previous_version = (empty($previous_install['version'])) ? '' : $previous_install['version']; + $previous_id = (empty($previous_install['id'])) ? '' : $previous_install['id']; + $show_files = false; + //rrs pull out unique_key + $hidden_fields .= ""; + $hidden_fields .= ""; + $hidden_fields .= ""; + $hidden_fields .= ""; + $hidden_fields .= ""; + $hidden_fields .= ""; + $hidden_fields .= ""; + break; + default: + die( $mod_strings['ERR_UW_WRONG_TYPE'].$install_type ); +} + + +$new_files = findAllFilesRelative( "$unzip_dir/$zip_from_dir", array() ); +$hidden_fields .= ""; +$serial_manifest = array(); +$serial_manifest['manifest'] = (isset($manifest) ? $manifest : ''); +$serial_manifest['installdefs'] = (isset($installdefs) ? $installdefs : ''); +$serial_manifest['upgrade_manifest'] = (isset($upgrade_manifest) ? $upgrade_manifest : ''); +$hidden_fields .= ""; +// present list to user +?> +
    " name="files" method="post" onSubmit="return validateForm();"> + '.$mod_strings['LBL_UW_CHECK_ALL']; + foreach($new_studio_mod_files as $the_file) { + $new_file = clean_path( "$zip_to_dir/$the_file" ); + print( "
  • " . $new_file . "
  • "); + $count++; + } +} +echo '
    '; +if($require_license){ + $contents = sugar_file_get_contents($license_file); + $readme_contents = ''; + if($found_readme){ + if(file_exists($readme_file) && filesize($readme_file) > 0){ + $readme_contents = file_get_contents($readme_file); + }elseif(!empty($manifest['readme'])){ + $readme_contents = $manifest['readme']; + } + } + $license_final =<< + + + + +
    + + + + + + + + + + + + + + +
     
    + {$mod_strings['LBL_MODULE_LICENSE']} +
    + +
    + {$mod_strings['LBL_ACCEPT']}  + {$mod_strings['LBL_DENY']} +
    +
    + + +eoq2; + echo $license_final; + echo "
    "; +} + +switch( $mode ){ + case "Install": + if( $install_type == "langpack") { + print( $mod_strings['LBL_UW_LANGPACK_READY'] ); + echo '

    '; + } + break; + case "Uninstall": + if( $install_type == "langpack" ){ + print( $mod_strings['LBL_UW_LANGPACK_READY_UNISTALL'] ); + echo '

    '; + } + else if($install_type != "module"){ + print( $mod_strings['LBL_UW_FILES_REMOVED'] ); + } + break; + case "Disable": + if( $install_type == "langpack" ){ + print( $mod_strings['LBL_UW_LANGPACK_READY_DISABLE'] ); + echo '

    '; + } + break; + case "Enable": + if( $install_type == "langpack" ){ + print( $mod_strings['LBL_UW_LANGPACK_READY_ENABLE'] ); + echo '

    '; + } + break; +} + + +?> + + + +
    "); + print ("".$mod_strings['ML_LBL_REMOVE_TABLES']." "); + print ("".$mod_strings['ML_LBL_DO_NOT_REMOVE_TABLES']."
    "); +} +$count = 0; + +if( $show_files == true ){ + $count = 0; + + $new_studio_mod_files = array(); + $new_sugar_mod_files = array(); + + $cache_html_files = findAllFilesRelative( "{$GLOBALS['sugar_config']['cache_dir']}layout", array()); + + foreach($new_files as $the_file) { + if(substr(strtolower($the_file), -5, 5) == '.html' && in_array($the_file, $cache_html_files)) + array_push($new_studio_mod_files, $the_file); + else + array_push($new_sugar_mod_files, $the_file); + } + + echo ''; + + + + global $theme; + + echo '

    '; + + echo '
    + '.' '.$mod_strings['LBL_UW_SHOW_DETAILS'].'
    +
    ' + .' '.$mod_strings['LBL_UW_HIDE_DETAILS'].'

    '; + echo ' '.$mod_strings['LBL_UW_CHECK_ALL']; + echo '
      '; + foreach( $new_sugar_mod_files as $the_file ){ + $highlight_start = ""; + $highlight_end = ""; + $checked = ""; + $disabled = ""; + $unzip_file = "$unzip_dir/$zip_from_dir/$the_file"; + $new_file = clean_path( "$zip_to_dir/$the_file" ); + $forced_copy = false; + + if( $mode == "Install" ){ + $checked = "checked"; + foreach( $zip_force_copy as $pattern ){ + if( preg_match("#" . $pattern . "#", $unzip_file) ){ + $disabled = "disabled=\"true\""; + $forced_copy = true; + } + } + if( !$forced_copy && is_file( $new_file ) && (md5_file( $unzip_file ) == md5_file( $new_file )) ){ + $disabled = "disabled=\"true\""; + //$checked = ""; + } + if( $checked != "" && $disabled != "" ){ // need to put a hidden field + print( "\n" ); + } + print( "
    • " . $highlight_start . $new_file . $highlight_end ); + if( $checked == "" && $disabled != "" ){ // need to explain this file hasn't changed + print( " (no changes)" ); + } + print( "
      \n" ); + } + else if( $mode == "Uninstall" && file_exists( $new_file ) ){ + if( md5_file( $unzip_file ) == md5_file( $new_file ) ){ + $checked = "checked=\"true\""; + } + else{ + $highlight_start = ""; + $highlight_end = ""; + } + print( "
    • " . $highlight_start . $new_file . $highlight_end . "
      \n" ); + } + $count++; + } + print( "
    \n" ); +} +// echo '
    '; +if($mode == "Disable" || $mode == "Enable"){ + //check to see if any files have been modified + $modified_files = getDiffFiles($unzip_dir, $install_file, ($mode == 'Enable'), $previous_version); + if(count($modified_files) > 0){ + //we need to tell the user that some files have been modified since they last did an install + echo ''; + print(''.$mod_strings['ML_LBL_OVERWRITE_FILES'].''); + print('
    '); + print("{$mod_strings['LBL_OVERWRITE_FILES']} "); + print("{$mod_strings['LBL_DO_OVERWRITE_FILES']}"); + print("
    "); + print('
      '); + foreach($modified_files as $modified_file){ + print('
    • '.$modified_file.'
    • '); + } + print('
    '); + }else{ + echo ''; + } +}else{ + echo ''; +} +echo ''; + + $fileHash = fileToHash($install_file ); +?> + + + + + + + + + +info( "Upgrade Wizard patches" ); +?> \ No newline at end of file diff --git a/modules/Administration/action_view_map.php b/modules/Administration/action_view_map.php new file mode 100644 index 00000000..ba031bdb --- /dev/null +++ b/modules/Administration/action_view_map.php @@ -0,0 +1,46 @@ + diff --git a/modules/Administration/clear_chart_cache.php b/modules/Administration/clear_chart_cache.php new file mode 100644 index 00000000..796fd51e --- /dev/null +++ b/modules/Administration/clear_chart_cache.php @@ -0,0 +1,77 @@ +" ); + +$search_dir='cache/'; +if (!empty($sugar_config['cache_dir'])) { + $search_dir=$sugar_config['cache_dir']; +} + +$all_src_files = findAllFiles($search_dir.'/xml', array() ); + +print( $mod_strings['LBL_CLEAR_CHART_DATA_CACHE_DELETING1'] . "
    " ); +foreach( $all_src_files as $src_file ){ + if (preg_match('/\.xml$/',$src_file)) + { + print( $mod_strings['LBL_CLEAR_CHART_DATA_CACHE_DELETING2'] . " $src_file
    " ) ; + unlink( "$src_file" ); + } +} + +include('modules/Versions/ExpectedVersions.php'); + + +global $expect_versions; + +if (isset($expect_versions['Chart Data Cache'])) { + $version = new Version(); + $version->retrieve_by_string_fields(array('name'=>'Chart Data Cache')); + + $version->name = $expect_versions['Chart Data Cache']['name']; + $version->file_version = $expect_versions['Chart Data Cache']['file_version']; + $version->db_version = $expect_versions['Chart Data Cache']['db_version']; + $version->save(); +} + +echo "\n--- " . $mod_strings['LBL_DONE'] . "---
    \n"; +?> diff --git a/modules/Administration/controller.php b/modules/Administration/controller.php new file mode 100644 index 00000000..b67a413d --- /dev/null +++ b/modules/Administration/controller.php @@ -0,0 +1,166 @@ +set_system_tabs($enabled_tabs); + $tabs->set_users_can_edit(isset($_REQUEST['user_edit_tabs']) && $_REQUEST['user_edit_tabs'] == 1); + + // handle the subpanels + if(isset($_REQUEST['disabled_tabs'])) { + $disabledTabs = json_decode(html_entity_decode($_REQUEST['disabled_tabs'], ENT_QUOTES)); + $disabledTabsKeyArray = TabController::get_key_array($disabledTabs); + SubPanelDefinitions::set_hidden_subpanels($disabledTabsKeyArray); + } + + header("Location: index.php?module=Administration&action=ConfigureTabs"); + } + + public function action_savelanguages() + { + global $sugar_config; + $toDecode = html_entity_decode ($_REQUEST['disabled_langs'], ENT_QUOTES); + $disabled_langs = json_decode($toDecode); + $toDecode = html_entity_decode ($_REQUEST['enabled_langs'], ENT_QUOTES); + $enabled_langs = json_decode($toDecode); + $cfg = new Configurator(); + $cfg->config['disabled_languages'] = join(',', $disabled_langs); + // TODO: find way to enforce order + $cfg->handleOverride(); + header("Location: index.php?module=Administration&action=Languages"); + } + + public function action_updatewirelessenabledmodules() + { + require_once('modules/Administration/Forms.php'); + + global $mod_strings; + global $app_list_strings; + global $app_strings; + global $current_user; + + if (!is_admin($current_user)) sugar_die($app_strings['ERR_NOT_ADMIN']); + + require_once('modules/Configurator/Configurator.php'); + $configurator = new Configurator(); + $configurator->saveConfig(); + + if ( isset( $_REQUEST['enabled_modules'] ) && ! empty ($_REQUEST['enabled_modules'] )) + { + $updated_enabled_modules = array () ; + foreach ( explode (',', $_REQUEST['enabled_modules'] ) as $e ) + { + $updated_enabled_modules [ $e ] = array () ; + } + + // transfer across any pre-existing definitions for the enabled modules from the current module registry + if (file_exists('include/MVC/Controller/wireless_module_registry.php')) + { + require('include/MVC/Controller/wireless_module_registry.php'); + if ( ! empty ( $wireless_module_registry ) ) + { + foreach ( $updated_enabled_modules as $e => $def ) + { + if ( isset ( $wireless_module_registry [ $e ] ) ) + { + $updated_enabled_modules [ $e ] = $wireless_module_registry [ $e ] ; + } + + } + } + } + + $filename = 'custom/include/MVC/Controller/wireless_module_registry.php' ; + + mkdir_recursive ( dirname ( $filename ) ) ; + write_array_to_file ( 'wireless_module_registry', $updated_enabled_modules, $filename ); + + } + + echo "true"; + } + + + /** + * action_saveglobalsearchsettings + * + * This method handles saving the selected modules to display in the Global Search Settings. + * It instantiates an instance of UnifiedSearchAdvanced and then calls the saveGlobalSearchSettings + * method. + * + */ + public function action_saveglobalsearchsettings() + { + global $current_user, $app_strings; + + if (!is_admin($current_user)) + { + sugar_die($GLOBALS['app_strings']['ERR_NOT_ADMIN']); + } + + try { + require_once('modules/Home/UnifiedSearchAdvanced.php'); + $unifiedSearchAdvanced = new UnifiedSearchAdvanced(); + $unifiedSearchAdvanced->saveGlobalSearchSettings(); + echo "true"; + } catch (Exception $ex) { + echo "false"; + } + } +} diff --git a/modules/Administration/expandDatabase.php b/modules/Administration/expandDatabase.php new file mode 100644 index 00000000..fc01ce08 --- /dev/null +++ b/modules/Administration/expandDatabase.php @@ -0,0 +1,170 @@ +dbType == 'oci8') { + echo "
    "; + echo "

    ".$mod_strings['ERR_NOT_FOR_ORACLE']."

    "; + echo "
    "; + sugar_die(''); +} +if ($db->dbType == 'mysql') { + echo "
    "; + echo "

    ".$mod_strings['ERR_NOT_FOR_MYSQL']."

    "; + echo "
    "; + sugar_die(''); +} +if(is_admin($current_user) || isset($from_sync_client)){ + + $execute = false; + $export = false; + + + if(isset($_REQUEST['do_action'])){ + switch($_REQUEST['do_action']){ + case 'display': + break; + case 'execute': + $execute = true; + break; + case 'export': + header('Location: index.php?module=Administration&action=expandDatabase&do_action=do_export&to_pdf=true'); + die(); + case 'do_export': + $export = true; + break; + } + + if(!$export && empty($_REQUEST['repair_silent'])){ + echo getClassicModuleTitle($mod_strings['LBL_EXPAND_DATABASE_COLUMNS'], array($mod_strings['LBL_EXPAND_DATABASE_COLUMNS'],$_REQUEST['do_action']), true); + } + + $alter_queries = array(); + $restore_quries = array(); + $sql = "SELECT SO.name AS table_name, SC.name AS column_name, CONVERT(int, SC.length) AS length, SC.isnullable, type_name(SC.xusertype) AS type + FROM sys.sysobjects AS SO INNER JOIN sys.syscolumns AS SC ON SC.id = SO.id + WHERE (SO.type = 'U') + AND (type_name(SC.xusertype) IN ('varchar', 'char', ' text ')) + AND (SC.name NOT LIKE '%_id') AND (SC.name NOT LIKE 'id_%') AND (SC.name <> 'id') + ORDER BY SO.name, column_name"; + $result = $db->query($sql); + + + $theAlterQueries = ''; + $theRestoreQueries = ''; + $alter_queries = array(); + while ($row = $db->fetchByAssoc($result)) { + $length = (int)$row['length']; + if($length < 255) { + $newLength = ($length * 3 < 255) ? $length * 3 : 255; + $sql = 'ALTER TABLE ' . $row['table_name'] . ' ALTER COLUMN ' . $row['column_name'] . ' ' . $row['type'] . ' (' . $newLength . ')'; + $theAlterQueries .= $sql . "\n"; + $alter_queries[] = $sql; + + $sql2 = 'ALTER TABLE ' . $row['table_name'] . ' ALTER COLUMN ' . $row['column_name'] . ' ' . $row['type'] . ' (' . $length . ')'; + $theRestoreQueries .= $sql2 . "\n"; + } + } //while + + //If there are no ALTER queries to run, echo message + if(count($alter_queries) == 0) { + echo $mod_strings['ERR_NO_COLUMNS_TO_EXPAND']; + } else { + + // Create a backup file to restore columns to original length + if($execute) { + $fh = sugar_fopen('restoreExpand.sql', 'w'); + if(-1 == fwrite($fh, $theRestoreQueries)) { + $GLOBALS['log']->error($mod_strings['ERR_CANNOT_CREATE_RESTORE_FILE']); + echo($mod_strings['ERR_CANNOT_CREATE_RESTORE_FILE']); + } else { + $GLOBALS['log']->info($mod_strings['LBL_CREATE_RESOTRE_FILE']); + echo($mod_strings['LBL_CREATE_RESOTRE_FILE']); + } + + foreach($alter_queries as $key=>$value) { + $db->query($value); + } + } + + if($export) { + header("Content-Disposition: attachment; filename=expandSugarDB.sql"); + header("Content-Type: text/sql; charset={$app_strings['LBL_CHARSET']}"); + header( "Expires: Mon, 26 Jul 1997 05:00:00 GMT" ); + header( "Last-Modified: " . TimeDate::httpTime() ); + header( "Cache-Control: post-check=0, pre-check=0", false ); + header("Content-Length: ".strlen($theAlterQueries)); + echo $theAlterQueries; + die(); + } else { + if(empty($_REQUEST['repair_silent'])) { + echo nl2br($theAlterQueries); + } + } + + } //if-else + } // end do_action + + if(empty($_REQUEST['repair_silent']) && empty($_REQUEST['do_action'])) { + if(!file_exists('restoreExpand.sql')) { + echo " {$mod_strings['LBL_REPAIR_ACTION']}
    +
    + + + + +


    + ".$mod_strings['LBL_EXPAND_DATABASE_TEXT']; + } else { + echo "{$mod_strings['LBL_EXPAND_DATABASE_FINISHED_ERROR']}
    "; + } //if-else + } //if +}else{ + sugar_die($GLOBALS['app_strings']['ERR_NOT_ADMIN']); +} + + +?> diff --git a/modules/Administration/index.html b/modules/Administration/index.html new file mode 100644 index 00000000..2295c857 --- /dev/null +++ b/modules/Administration/index.html @@ -0,0 +1,62 @@ + + + + + +

    {GROUP_HEADER}{GROUP_DESC} + + + + + + + + + + + + + + + +
    {ITEM_HEADER_IMAGE} {ITEM_HEADER_LABEL}{ITEM_DESCRIPTION}  
    +

    + + + \ No newline at end of file diff --git a/modules/Administration/index.php b/modules/Administration/index.php new file mode 100644 index 00000000..87ba8198 --- /dev/null +++ b/modules/Administration/index.php @@ -0,0 +1,156 @@ +$values) { + $module_index = array_keys($values[3]); + $addedHeaderGroups = array(); + foreach ($module_index as $mod_key=>$mod_val) { + if( + (!isset($addedHeaderGroups[$values[0]]))) { + $admin_group_header_tab[]=$values; + $group_header_value=get_form_header(translate($values[0],'Administration'),$values[1],$values[2]); + $group[$j][0] = ''; + $addedHeaderGroups[$values[0]] = 1; + if (isset($values[4])) + $group[$j][1] = '

    ' . translate($values[0]) . '

    ' . translate($values[4]) . '
    '; + else + $group[$j][2] = ''; + $colnum=0; + $i=0; + $fix = array_keys($values[3]); + if(count($values[3])>1){ + + ////////////////// + $tmp_array = $values[3]; + $return_array = array(); + foreach ($tmp_array as $mod => $value){ + $keys = array_keys($value); + foreach ($keys as $key){ + $return_array[$key] = $value[$key]; + } + } + $values_3_tab[]= $return_array; + $mod = $return_array; + } + else { + $mod = $values[3][$fix[0]]; + $values_3_tab[]= $mod; + } + + foreach ($mod as $link_idx =>$admin_option) { + if(!empty($GLOBALS['admin_access_control_links']) && in_array($link_idx, $GLOBALS['admin_access_control_links'])){ + continue; + } + $colnum+=1; + $header_image[$j][$i]= SugarThemeRegistry::current()->getImage($admin_option[0],'alt="' . translate($admin_option[1],'Administration') .'" border="0" align="absmiddle"'); + $url[$j][$i] = $admin_option[3]; + $label = translate($admin_option[1],'Administration'); + if(!empty($admin_option['additional_label']))$label.= ' '. $admin_option['additional_label']; + if(!empty($admin_option[4])){ + $label = ' '. $label . ''; + } + + $label_tab[$j][$i]= $label; + $description[$j][$i]= translate($admin_option[2],'Administration'); + if (($colnum % 2) == 0) { + $tab[$j][$i]= ($colnum % 2); + } + else { + $tab[$j][$i]= 10; + } + $i+=1; + } + + //if the loop above ends with an odd entry add a blank column. + if (($colnum % 2) != 0) { + $tab[$j][$i]= 10; + } + $j+=1; + } + } +} + +$sugar_smarty->assign('MY_FRAME',""); +$sugar_smarty->assign("VALUES_3_TAB", $values_3_tab); +$sugar_smarty->assign("ADMIN_GROUP_HEADER", $admin_group_header_tab); +$sugar_smarty->assign("GROUP_HEADER", $group); +$sugar_smarty->assign("ITEM_HEADER_IMAGE", $header_image); +$sugar_smarty->assign("ITEM_URL", $url); +$sugar_smarty->assign("ITEM_HEADER_LABEL",$label_tab); +$sugar_smarty->assign("ITEM_DESCRIPTION", $description); +$sugar_smarty->assign("COLNUM", $tab); + +echo $sugar_smarty->fetch('modules/Administration/index.tpl'); +?> diff --git a/modules/Administration/index.tpl b/modules/Administration/index.tpl new file mode 100644 index 00000000..f72f312f --- /dev/null +++ b/modules/Administration/index.tpl @@ -0,0 +1,90 @@ +{* + + +*} +
    +
    +
    +
    +
    +
    + +{$MY_FRAME} +{foreach from=$ADMIN_GROUP_HEADER key=j item=val1} + + {if isset($GROUP_HEADER[$j][1])} +

    {$GROUP_HEADER[$j][0]}{$GROUP_HEADER[$j][1]} + + + {else} +

    {$GROUP_HEADER[$j][0]}{$GROUP_HEADER[$j][2]} +

    + {/if} + + {assign var='i' value=0} + {foreach from=$VALUES_3_TAB[$j] key=link_idx item=admin_option} + {if isset($COLNUM[$j][$i])} + + + + + {assign var='i' value=$i+1} + {if $COLNUM[$j][$i] == '0'} + + + + {else} + + + {/if} + + {/if} + {assign var='i' value=$i+1} + {/foreach} + +
    {$ITEM_HEADER_IMAGE[$j][$i]} {$ITEM_HEADER_LABEL[$j][$i]}{$ITEM_DESCRIPTION[$j][$i]}{$ITEM_HEADER_IMAGE[$j][$i]} {$ITEM_HEADER_LABEL[$j][$i]}{$ITEM_DESCRIPTION[$j][$i]}  
    +

    +{/foreach} + +

    +
    +
    +
    +
    +
    \ No newline at end of file diff --git a/modules/Administration/javascript/Administration.js b/modules/Administration/javascript/Administration.js new file mode 100644 index 00000000..5deeb6e1 --- /dev/null +++ b/modules/Administration/javascript/Administration.js @@ -0,0 +1,39 @@ +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ +if(typeof(SUGAR)=='undefined'){var SUGAR={};} +SUGAR.Administration={Async:{},RepairXSS:{toRepair:new Object,currentRepairObject:"",currentRepairIds:new Array(),repairedCount:0,numberToFix:25,refreshEstimate:function(select){this.toRepair=new Object();this.repairedCount=0;var button=document.getElementById('repairXssButton');var selected=select.value;var totalDisplay=document.getElementById('repairXssDisplay');var counter=document.getElementById('repairXssCount');var repaired=document.getElementById('repairXssResults');var repairedCounter=document.getElementById('repairXssResultCount');if(selected!="0"){button.style.display='inline';repairedCounter.value=0;AjaxObject.startRequest(callbackRepairXssRefreshEstimate,"&adminAction=refreshEstimate&bean="+selected);}else{button.style.display='none';totalDisplay.style.display='none';repaired.style.display='none';counter.value=0;repaired.value=0;}},executeRepair:function(){if(this.toRepair){if(this.currentRepairIds.length<1){if(!this.loadRepairQueue()){alert(done);return;}} +var beanIds=new Array();for(var i=0;i0){beanIds.push(this.currentRepairIds.pop());}} +var beanId=JSON.stringifyNoSecurity(beanIds);AjaxObject.startRequest(callbackRepairXssExecute,"&adminAction=repairXssExecute&bean="+this.currentRepairObject+"&id="+beanId);}},loadRepairQueue:function(){var loaded=false;this.currentRepairObject='';this.currentRepairIds=new Array();for(var bean in this.toRepair){if(this.toRepair[bean].length>0){this.currentRepairObject=bean;this.currentRepairIds=this.toRepair[bean];loaded=true;}} +this.toRepair[this.currentRepairObject]=new Array();return loaded;}}} \ No newline at end of file diff --git a/modules/Administration/javascript/Async.js b/modules/Administration/javascript/Async.js new file mode 100644 index 00000000..9873f75d --- /dev/null +++ b/modules/Administration/javascript/Async.js @@ -0,0 +1,37 @@ +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ +var AjaxObject={ret:'',currentRequestObject:null,timeout:30000,forceAbort:false,_reset:function(){this.timeout=30000;this.forceAbort=false;},handleFailure:function(o){alert('asynchronous call failed.');},startRequest:function(callback,args,forceAbort){if(this.currentRequestObject!=null){if(this.forceAbort==true||callback.forceAbort==true){YAHOO.util.Connect.abort(this.currentRequestObject,null,false);}} +this.currentRequestObject=YAHOO.util.Connect.asyncRequest('POST',"./index.php?module=Administration&action=Async&to_pdf=true",callback,args);this._reset();},refreshEstimate:function(o){this.ret=JSON.parse(o.responseText);document.getElementById('repairXssDisplay').style.display='inline';document.getElementById('repairXssCount').value=this.ret.count;SUGAR.Administration.RepairXSS.toRepair=this.ret.toRepair;},showRepairXssResult:function(o){var resultCounter=document.getElementById('repairXssResultCount');this.ret=JSON.parse(o.responseText);document.getElementById('repairXssResults').style.display='inline';if(this.ret.msg=='success'){SUGAR.Administration.RepairXSS.repairedCount+=this.ret.count;resultCounter.value=SUGAR.Administration.RepairXSS.repairedCount;}else{resultCounter.value=this.ret;} +SUGAR.Administration.RepairXSS.executeRepair();}};var callbackRepairXssRefreshEstimate={success:AjaxObject.refreshEstimate,failure:AjaxObject.handleFailure,timeout:AjaxObject.timeout,scope:AjaxObject};var callbackRepairXssExecute={success:AjaxObject.showRepairXssResult,failure:AjaxObject.handleFailure,timeout:AjaxObject.timeout,scope:AjaxObject}; \ No newline at end of file diff --git a/modules/Administration/language/en_us.lang.php b/modules/Administration/language/en_us.lang.php new file mode 100644 index 00000000..cd74ba7a --- /dev/null +++ b/modules/Administration/language/en_us.lang.php @@ -0,0 +1,1093 @@ +'Captcha is a challenge-response test used to ensure that the response is not generated by a computer. Obtain a Public key and a Private key from reCAPTCHA at http://recaptcha.net/.', + 'CAPTCHA'=>'Captcha Validation', + 'CAPTCHA_PRIVATE_KEY'=>'Captcha private Key', + 'CAPTCHA_PUBLIC_KEY'=>'Captcha public Key', + 'ENABLE_CAPTCHA'=>'Enable reCAPTCHA Validations', + 'ERR_PUBLIC_CAPTCHA_KEY'=> 'Invalid Captcha Key', + 'BTN_REBUILD_CONFIG' =>'Rebuild', + 'EXPORT_DELIMITER' => 'Export Delimiter', + 'ADMIN_EXPORT_ONLY'=>'Admin export only', + 'EXPORT'=>'Export Settings', + 'EXPORT_CHARSET' => 'Default Character Set for Import and Export', + 'DISABLE_EXPORT'=>'Disable export', + 'DESC_DROPDOWN_EDITOR' => 'Add, delete, or change the dropdown lists', + 'DESC_EDIT_CUSTOM_FIELDS' => 'Edit the custom fields created for the Field Layout', + 'DESC_FILES_INSTALLED' => 'The following upgrades have been installed:', + 'DESC_FILES_QUEUED' => 'The following modules are ready to be installed:', + 'DESC_IFRAME' => 'Add tabs which can display any web site', + 'DESC_MODULES_INSTALLED' => 'The following modules have been installed:', + + 'DOWNLOAD_QUESTION' => 'Are you sure you wish to download the selected package(s)?', + 'ENABLED_OFFLINE_CLIENTS' => 'Offline Clients are enabled.', + + 'SEARCHING_UPDATES' => 'Searching for updates...', + 'DOWNLOADING' => 'Downloading...', + 'DL_PACKAGES_DOWNLOADING' => 'Downloading', + 'DL_PACKAGES_OF' => 'of', + 'DL_PACKAGES_PACKAGES' => 'Package(s)', + 'LOADING_CATEGORIES' => 'Loading categories...', + 'SEARCHING_PACKAGES' => 'Searching for packages...', + 'AUTHENTICATING' => 'Authenticating...', + + 'LBL_MINUTES'=>'Minutes', + 'LBL_HOURS'=>'Hours', + 'LBL_DAYS'=>'Days', + 'LBL_WEEKS'=>'Weeks', + 'LBL_MONTHS'=>'Months', + + 'LBL_PUBLIC_KEY'=>'Public Key', + 'LBL_PRIVATE_KEY'=>'Private Key', + + 'ERR_CANNOT_CREATE_RESTORE_FILE' => 'Error: Could not create restore file', + 'ERR_CREDENTIALS_MISSING' => 'Your sugarcrm.com credentials are missing.', + 'ERR_DELETE_RECORD' => 'A record number must be specified to delete the account.', + 'ERR_ENABLE_CURL' => 'Please ensure that you have curl enabled.', + 'ERR_EXPAND_DATABASE_COMPLETED' => 'Error: The presence of the restoreExpand.sql file indicates that you have already expanded the database columns.', + 'ERR_INCORRECT_REGEX' => 'The regular expression in the Regex Requirement field contains incorrect syntax. Please check the expression and provide the correct syntax', + 'ERR_EMPTY_REGEX_DESCRIPTION' => 'Provide a description of the Regex Requirement. This description will be displayed for users when they provide new passwords.', + 'ERR_NO_COLUMNS_TO_EXPAND' => 'Error: Database does not contain any varchar, char or text columns to expand.', + 'ERR_NOT_FOR_MSSQL'=>'This function is not currently implemented for this configuration.', + 'ERR_NOT_FOR_MYSQL'=>'This function is not currently implemented for this configuration.', + 'ERR_NOT_FOR_ORACLE'=>'This function is not currently implemented for this configuration.', + 'ERR_NUM_OFFLINE_CLIENTS_MET' => 'You have already met the number of Offline Clients for your license key. You must either disable an existing Offline Client or update your license.', + 'ERR_OC_USER_ALREADY_EXISTS' => 'The user you have selected already exists in the system.', + 'ERR_SUGAR_DEPOT_DOWN' => 'The system is unable to connect to Sugar Exchange for browsing and downloading packages.', + 'ERR_SMTP_SERVER_NOT_SET' => 'Warning: An SMTP server for outbound emails is not configured in Email Settings. It must be configured in order to send passwords to users.', + 'ERR_UW_ACCEPT_LICENSE' => 'Before proceeding you must accept the License Agreement', + 'ERR_UW_CONFIG_FAILED' => "Error writing out config.php file.", + 'ERR_UW_COPY_FAILED' => 'Could not copy file ', + 'ERR_UW_INVALID_VIEW' => 'Invalid View specified.', + 'ERR_UW_MUST_SELECT_OVERWRITE_OPTION' => 'Please select an overwrite option', + 'ERR_UW_NO_DEPENDENCY' => "The following dependencies were not found on the system.", + 'ERR_UW_NO_FILES' => "File(s) to copy not specified.", + 'ERR_UW_NO_INSTALL_FILE' => "Install file not specified.", + 'ERR_UW_NO_LANG_DESC' => "Language description not specified.", + 'ERR_UW_NO_LANG' => "Language name not specified.", + 'ERR_UW_NO_MANIFEST' => "The zip file is missing a manifest.php file. Cannot proceed.", + 'ERR_UW_NO_MODE' => "Mode of operation not specified.", + 'ERR_UW_NO_TEMP_DIR' => "Temp directory to copy files from not specified.", + 'ERR_UW_NO_UPDATE_RECORD' => 'Could not locate installation record of', + 'ERR_UW_NO_UPLOAD_FILE' => "Please click Browse to select a file from your system to upload.
    \n", + 'ERR_UW_NO_VIEW' => "View not defined. Please go to the Administration home to navigate to this page.", + 'ERR_UW_NOT_ACCEPTIBLE_TYPE' => "You can only upload module packs, theme packs, and language packs on this page.", + 'ERR_UW_NOT_RECOGNIZED' => 'is not recognized', + 'ERR_UW_NOT_VALID_UPLOAD' => 'Not valid upload.', + 'ERR_UW_ONLY_PATCHES' => "You can only upload patches on this page.", + 'ERR_UW_REMOVE_FAILED' => 'Could not remove file ', + 'ERR_UW_REMOVE_PACKAGE' => "Problem removing package ", + 'ERR_UW_RUN_SQL' => "Error running sql file: ", + 'ERR_UW_UPDATE_CONFIG' => "Error updating config.php with new version information.", + 'ERR_UW_UPLOAD_ERROR' => "There was an error uploading the file, please try again!
    \n", + 'ERROR_FLAVOR_INCOMPATIBLE' => 'The uploaded file is not compatible with this flavor (Community Edition, Professional, or Enterprise) of Sugar: ', + 'ERROR_LICENSE_EXPIRED'=> "Error: Your license expired ", + 'ERROR_LICENSE_EXPIRED2' => " day(s) ago. Please go to the '\"License Management\" in the Admin screen to enter your new license key. If you do not enter a new license key within 30 days of your license key expiration, you will no longer be able to log into this application.", + 'ERROR_MANIFEST_TYPE' => 'Manifest file must specify the package type.', + 'ERROR_PACKAGE_TYPE' => 'Manifest file specifies an unrecognized package type', + 'ERROR_VALIDATION_EXPIRED'=> "Error: Your validation key expired ", + 'ERROR_VALIDATION_EXPIRED2' => " day(s) ago. Please go to the '\"License Management\" in the Admin screen to enter your new validation key. If you do not enter a new validation key within 30 days of your validation key expiration, you will no longer be able to log into this application.", + 'ERROR_VERSION_INCOMPATIBLE' => 'The uploaded file is not compatible with this version of Sugar: ', + + 'FATAL_LICENSE_ALTERED' => "Your license has been altered since the last time you validated it.
    Please go to the '\"License Management\" in the Admin screen.", + 'FATAL_LICENSE_EXPIRED'=> "Fatal: Your license expired more than 30 days ago", + 'FATAL_LICENSE_EXPIRED2'=> "Please go to the '\"License Management\" on the Admin page to update your license information and restore full functionality.", + 'FATAL_LICENSE_REQUIRED' => "Fatal: Your license key information is required .
    Please go to the '\"License Management\" in the Admin screen to update your license information and restore full functionality.", + 'FATAL_VALIDATION_EXPIRED'=> "Fatal: Your validation key expired more than 30 days ago", + 'FATAL_VALIDATION_EXPIRED2'=> "Please go to the '\"License Management\" in the Admin screen to update your license information and restore full functionality.", + 'FATAL_VALIDATION_REQUIRED' => "Fatal: Your validation key information is required .
    Please go to the '\"License Management\" in the Admin screen to update your license information and restore full functionality.
    Either re-save your license information to have it authenticated or export the key and import the validation key. " , + 'HDR_LOGIN_PANEL' => 'Please enter your sugarcrm.com credentials.', + 'HEARTBEAT_MESSAGE'=>"
    The Sugar Updates mechanism allows your server to check to see if an update for your version of Sugar is available.", + + 'LBL_ACCEPT_TERMS' =>'Accept Terms and Conditions', + 'LBL_ACCEPT' => 'Accept', + 'LBL_ADMIN_SUGAR_SERVER' => 'Admin User Name:', + 'LBL_ADMIN_WIZARD_TITLE' => 'Admin Wizard', + 'LBL_ADMIN_WIZARD' => 'Easily setup your SugarCRM system', + 'LBL_ADMINISTRATION_HOME_TITLE' => 'System', + 'LBL_ADMINISTRATION_HOME_DESC' =>'Configure the system-wide settings according to the specifications of your organization. Users can override some of the default locale settings within their user settings page.', + 'LBL_ALLOW_USER_TABS' => 'Allow users to hide tabs', + 'LBL_ALREADY_RUNNING' => 'This server is running as an Offline Client.', + 'LBL_APPLY_DST_FIX_DESC' => 'This mandatory step will update the time handling functionality (MYSQL ONLY).', + 'LBL_APPLY_DST_FIX' => 'Apply Daylight Savings Time Fix', + 'LBL_AVAILABLE_MODULES' => 'Modules Available for Download', + 'LBL_AVAILABLE_UPDATES'=>'Available Updates', + 'LBL_BACKUP_BACK_HOME' => 'Back to Admin Home', + 'LBL_BACKUP_CONFIRM' => 'Confirm Settings', + 'LBL_BACKUP_CONFIRMED' => 'Settings confirmed. Press backup to perform the backup.', + 'LBL_BACKUP_DIRECTORY_ERROR' => 'You must specify a Backup directory.', + 'LBL_BACKUP_DIRECTORY_EXISTS' => 'Backup directory does not exist, and could not be created.', + 'LBL_BACKUP_DIRECTORY_NOT_WRITABLE' => 'Backup directory exists, but is not writable.', + 'LBL_BACKUP_DIRECTORY_WRITABLE' => 'Must be writable by Sugar', + 'LBL_BACKUP_DIRECTORY' => 'Directory:', + 'LBL_BACKUP_FILE_AS_SUB' => 'Target file already exists as a sub-directory in the specified backup directory', + 'LBL_BACKUP_FILE_EXISTS' => 'The target file already exists in directory.', + 'LBL_BACKUP_FILE_STORED' => 'Backup successfully stored as', + 'LBL_BACKUP_FILENAME_ERROR' => 'Backup filename must be specified.', + 'LBL_BACKUP_FILENAME' => 'Filename:', + 'LBL_BACKUP_INSTRUCTIONS_1' => 'The purpose of this tool is to assist in creating backups of the Sugar application files. (Database backups should also be performed regularly. Please refer to your database vendor\'s documentation for information on how to backup your database.)', + 'LBL_BACKUP_INSTRUCTIONS_2' => 'To backup your Sugar application files in a .zip file, enter the following information:', + 'LBL_BACKUP_RUN_BACKUP' => 'Run Backup', + 'LBL_BACKUP_TITLE' => 'Online Backups', + 'LBL_BACKUP' => 'Schedule backups to the Sugar Online Data Vault. Activate a system restoration from backup.', + 'LBL_BACKUPS_TITLE' => 'Backups', + 'LBL_BACKUPS' => 'Backup Sugar files', + 'LBL_BROWSE' => 'Browse', + 'LBL_BUG_TITLE' => 'Bug Tracker', + 'LBL_BUG_DESC' => 'Maintain a list of releases for your product. Active releases are displayed in the Releases drop-down menus in bug records created within the Bug Tracker module.', + 'LBL_CANCEL_BUTTON_TITLE' => 'Cancel', + 'LBL_CAT_VIEW' => 'Categories', + 'LBL_CHANGE_NAME_TABS'=>'Change the names of the navigation tabs', + 'LBL_CHECK_FOR_UPDATES' => 'Check for Updates', + 'LBL_CHECK_NOW_LABEL' =>'Check Now', + 'LBL_CHECK_NOW_TITLE' =>'Check Now', + 'LBL_CHECK_DB_VARDEFS' => 'Checking database structure against vardefs...', + 'LBL_CONFIGURE_TABS_AND_SUBPANELS_DESC'=>'Choose which module tabs and subpanels are displayed system-wide', + 'LBL_CLEAR_CHART_DATA_CACHE_DESC'=>'Removes cached data files used by charts', + 'LBL_CLEAR_CHART_DATA_CACHE_TITLE'=>'Clear Chart Data Cache', + 'LBL_CLEAR_CHART_DATA_CACHE_FINDING'=>'Finding files...', + 'LBL_CLEAR_CHART_DATA_CACHE_DELETING1'=>'Deleting chart data cache files...', + 'LBL_CLEAR_CHART_DATA_CACHE_DELETING2'=>'deleting:', + 'LBL_CLEAR_THEME_CACHE_DESC'=>'Removes cached data files used by themes', + 'LBL_CLEAR_THEME_CACHE_TITLE'=>'Clear Theme Cache', + 'LBL_CLEAR_UNIFIED_SEARCH_CACHE_DELETING1'=>'Deleting unified search cache files...', + 'LBL_CLEAR_UNIFIED_SEARCH_CACHE_DELETING2'=>'deleting:', + 'LBL_CLEAR_PDFFONTS_DESC'=>'Removing PDF Font Cache File, will rebuild when needed.', + 'LBL_CLEAR_PDFFONTS_DESC_SUCCESS'=>'Success : PDF Font Cache File deleted', + 'LBL_CLEAR_PDFFONTS_DESC_FAILURE'=>'Error : Clearing PDF Font Cache File failed', + 'LBL_CLEAR_PDF_FONT_CACHE_TITLE'=>'Clear PDF Font File Cache', + 'LBL_CLEAR_PDF_FONT_CACHE_DESC'=>'Removes cached file used to store PDF fonts data', + 'LBL_CONFIG_CHECK' =>'Config Check', + 'LBL_CONFIG_TABS'=>'Display Module Tabs and Subpanels', + 'LBL_CONFIG_TABS_DESC'=>'Drag and Drop the names of the modules below to set tabs or subpanels to be displayed or to be hidden.', + 'LBL_CONFIG_LANGS_DESC'=>'Drag and Drop the names of the languages below to enable and disable them.', + 'LBL_CONFIG_TABS_ALLOW_USERS_HIDE_TABS_HELP'=>'Select this option to allow users to choose which module tabs they can view. When selected, users will be able to choose which module tabs are visible by managing the tabs within their User Settings.', + 'LBL_CONFIGURATOR_DESC'=>'Set up Config.php', + 'LBL_CONFIGURATOR_TITLE'=>'Configurator', + 'LBL_CONFIGURE_GROUP_TABS_DESC' => 'Create and edit the grouping of navigation tabs', + 'LBL_CONFIGURE_GROUP_TABS' => 'Configure Grouped Modules', + 'LBL_CONFIGURE_SETTINGS_TITLE' => 'System Settings', + 'LBL_CONFIGURE_SETTINGS' => 'Configure system-wide settings', + 'LBL_CONFIGURE_TABS_AND_SUBPANELS' => 'Display Module Tabs and Subpanels', + 'LBL_CONFIGURE_UPDATER'=>'Configure Sugar Updates', + 'LBL_CONTRACT_TITLE'=>'Contracts', + 'LBL_CONTRACT_DESC'=>'Define contract types for the Contracts module. When users create a contract, the Types drop-down menu displays the contract types for selection.', + 'LBL_CONTRACT_TYPES'=>'Manage contract types', + 'LBL_COULD_NOT_CONNECT'=>'Error: Could not connect to the Sugar Server. + Please check your Proxy Settings value in the System Settings admin panel. + Last attempted connection @ ', + 'LBL_CREATE_RESOTRE_FILE' => 'restoreExpand.sql file was successfully created. Please use this file to revert column changes.', + 'LBL_CURRENCY' => 'Set up currencies and conversion rates', + 'LBL_CONNECTOR_SETTINGS' => 'Connectors', + 'LBL_CONNECTOR_SETTINGS_DESC' => 'Manage connector settings', + 'LBL_SUGARPDF_SETTINGS' => 'PDF', + 'LBL_SUGARPDF_SETTINGS_DESC' => 'Manage settings for generated PDF files', + 'LBL_DENY' => 'Deny', + 'LBL_DIAG_CANCEL_BUTTON' => 'Cancel', + 'LBL_DIAG_EXECUTE_BUTTON' => 'Execute Diagnostic', + 'LBL_DIAGNOSTIC_ACCESS' => 'You must be an administrator to run the diagnostic tool.', + 'LBL_DIAGNOSTIC_BEANLIST_DESC' => 'This information tells us whether or not the beanFiles specified in the beanList actually exists. This can be an issue with an improperly defined module loaded extension.', + 'LBL_DIAGNOSTIC_BEANLIST_GREEN' => 'Green means the file does exist.', + 'LBL_DIAGNOSTIC_BEANLIST_ORANGE' => 'Orange means there is no indexed file, so we cannot look it up.', + 'LBL_DIAGNOSTIC_BEANLIST_RED' => 'Red means the file does not exist.', + 'LBL_DIAGNOSTIC_BLBF'=>'BeanList/BeanFiles files exist', + 'LBL_DIAGNOSTIC_CALCMD5'=>'    -  Copy MD5 Calculated array', + 'LBL_DIAGNOSTIC_CONFIGPHP'=>'SugarCRM config.php', + 'LBL_DIAGNOSTIC_CUSTOMDIR'=>'SugarCRM Custom directory', + 'LBL_DIAGNOSTIC_DELETED' => 'File has been deleted', + 'LBL_DIAGNOSTIC_DELETELINK' => 'Delete the Diagnostic file', + 'LBL_DIAGNOSTIC_FILE' => 'File', + 'LBL_DIAGNOSTIC_ZIP' => '.zip doesn\'t exist.

    ', + 'LBL_DIAGNOSTIC_DELETE_ERROR' => 'Did not receive a filename or guid path to delete the file

    ', + 'LBL_DIAGNOSTIC_DELETE_DIE' => 'You are trying to delete a non diagnostic file.', + 'LBL_DIAGNOSTIC_DELETE_RETURN' => 'Return to Administration page', + 'LBL_DIAGNOSTIC_DESC'=>'Capture system configuration for diagnostics and analysis', + 'LBL_DIAGNOSTIC_DONE' => 'Done', + 'LBL_DIAGNOSTIC_DOWNLOADLINK' => 'Download the Diagnostic file', + 'LBL_DIAGNOSTIC_EXECUTING' => 'Executing Diagnostic Operations...', + 'LBL_DIAGNOSTIC_FILESMD5'=>'    -  Copy files.md5', + 'LBL_DIAGNOSTIC_GETBEANFILES' => 'Checking that bean files exist...', + 'LBL_DIAGNOSTIC_GETCONFPHP' => 'Getting config.php...', + 'LBL_DIAGNOSTIC_GETCUSTDIR' => 'Getting custom dir...', + 'LBL_DIAGNOSTIC_GETMD5INFO' => 'Getting md5 information...', + 'LBL_DIAGNOSTIC_GETMYSQLINFO' => 'mysql info', + 'LBL_DIAGNOSTIC_GETMYSQLTD' => 'mysql dumps', + 'LBL_DIAGNOSTIC_GETMYSQLTS' => 'mysql schema', + 'LBL_DIAGNOSTIC_GETPHPINFO' => 'Getting phpinfo()', + 'LBL_DIAGNOSTIC_GETSUGARLOG' => 'Getting sugarcrm.log', + 'LBL_DIAGNOSTIC_GETTING' => 'Getting...', + 'LBL_DIAGNOSTIC_MD5'=>'MD5 info', + 'LBL_DIAGNOSTIC_MYSQLDUMPS'=>'MySQL - Configuration Table Dumps', + 'LBL_DIAGNOSTIC_MYSQLINFO'=>'MySQL - General Information', + 'LBL_DIAGNOSTIC_MYSQLSCHEMA'=>'MySQL - All Tables Schema', + 'LBL_DIAGNOSTIC_NO_MYSQL' => 'You do not have MySQL. The MySQL functions in have been disabled.', + 'LBL_DIAGNOSTIC_PHPINFO'=>'phpinfo()', + 'LBL_DIAGNOSTIC_SUGARLOG'=>'SugarCRM Log File', + 'LBL_DIAGNOSTIC_TITLE'=>'Diagnostic Tool', + 'LBL_DIAGNOSTIC_VARDEFS'=>'Sugar schema output (VARDEFS)', + 'LBL_DISABLED' => 'Disabled', + 'LBL_DISPLAY_TABS'=>'Display Tabs', + 'LBL_DO_OVERWRITE_FILES' => 'Do Not Overwrite Files', + 'LBL_DOCUMENTATION_TITLE' => 'Online Documentation', + 'LBL_DOCUMENTATION' => 'View Sugar documentation for administrators and end-users', + 'LBL_DONE' => 'Done', + 'LBL_DROP_HERE' => '[Drop Here]', + 'LBL_DROPDOWN_EDITOR' => 'Dropdown Editor', + 'LBL_DST_APPLY_FIX' => 'Apply Daylight Savings Time fix to existing data. Please backup your data first.', + 'LBL_DST_BEFORE_DESC' => 'This fix will make changes to your data. Please make a full backup of your database before running this fix.', + 'LBL_DST_BEFORE' => 'Before Beginning:', + 'LBL_DST_CURRENT_SERVER_TIME_ZONE_LOCALE' => 'Server Time Zone Locale:', + 'LBL_DST_CURRENT_SERVER_TIME_ZONE' => 'Detected Server Time Zone:', + 'LBL_DST_CURRENT_SERVER_TIME' => 'Detected Local Server Time:', + 'LBL_DST_END_DATE_TIME' => 'End Date/Time', + 'LBL_DST_FIX_CONFIRM_DESC' => 'Please review the values below and confirm that your system is correctly configured.', + 'LBL_DST_FIX_CONFIRM' => 'Confirm: ', + 'LBL_DST_FIX_DONE_DESC' => 'The Daylight Saving Time fix has been successfully applied.', + 'LBL_DST_FIX_TARGET' => 'Target:', + 'LBL_DST_FIX_USER_TZ' => 'This step sets the time zone for all users to the most likely value.', + 'LBL_DST_FIX_USER' => 'User Timezones:
    (OPTIONAL)', + 'LBL_DST_SET_USER_TZ' => 'Set User Time Zones', + 'LBL_DST_START_DATE_TIME' => 'Start Date/Time', + 'LBL_DST_UPGRADE' => 'Upgrade:', + 'LBL_EDIT_CUSTOM_FIELDS' => 'Edit Custom Fields', + 'LBL_EDIT_TABS'=>'Edit Tabs', + 'LBL_EMAIL_TITLE' => 'Email', + 'LBL_EMAIL_DESC' => 'Manage outbound and inbound emails. The email settings must be configured in order to enable users to send out email and newsletter campaigns.', + 'LBL_EMAIL_ADDRESS_REQUIRED_FOR_FEATURE' => 'A primary email address is required for each user in order to use this feature.', + 'LBL_ENABLE_MAILMERGE' => 'Enable Mail Merge?', + 'LBL_ENABLED' => 'Enabled', + 'LBL_ERROR_VERSION_INFO'=>'Error fetching version information, please try again later.', + 'LBL_EXCEEDING_OC_LICENSES' =>"Error: The number of enabled Offline Clients currently exceeds the number specified in your license. Please go to '\"Manage Offline Clients\" in the Admin screen to disable Offline Clients or update your License.", + 'LBL_EXECUTE' => 'Execute', + 'LBL_EXPAND_DATABASE_COLUMNS_DESC' => 'Expands certain char, varchar and text columns in database (MSSQL ONLY)', + 'LBL_EXPAND_DATABASE_COLUMNS' => 'Expand Column Width', + 'LBL_EXPAND_DATABASE_TEXT'=>'This tool allows you to expand selected database columns as an interim fix for multi-byte character limitations in SQL Server.
    You may choose from three options:
    Display SQL will display the sql that will be executed on the screen
    Export SQL will export the sql to a file
    Execute SQL will execute the SQL.', + 'LBL_EXPORT_CUSTOM_FIELDS_TITLE' => 'Export Custom Fields Structure', + 'LBL_EXPORT_CUSTOM_FIELDS'=> 'Export custom field definitions to a .sugar file', + 'LBL_EXPORT_DOWNLOAD_KEY' =>'Export Download Key', + 'LBL_EXTERNAL_DEV_DESC'=> 'Migrate custom field structures from one system to another', + 'LBL_EXTERNAL_DEV_TITLE'=> 'Migrate Custom Fields', + 'LBL_FORECAST_TITLE'=> 'Forecast', + 'LBL_FORECAST_DESC'=> 'Define time periods for the Forecasts module. These time periods display in the Time Periods drop-down menus in the Forecasts Module.', + 'LBL_GLOBAL_SEARCH_SETTINGS' => 'Global Search', + 'LBL_GLOBAL_SEARCH_SETTINGS_DESC' => 'Configure the global search options for the system.', + 'LBL_GLOBAL_TEAM_DESC' => 'Globally Visible', + 'LBL_GLOBAL_TEAM_SELECT' => 'A default global team was not found. Please select a team from this list.', + 'LBL_GLOBAL_TEAM' => 'Rebuild access to global team.', + 'LBL_GO' => 'Go', + 'LBL_HELP_BOOKMARK' => 'Bookmark this page', + 'LBL_HELP_EMAIL' => 'Email', + 'LBL_HELP_LINK' => 'Link to this page', + 'LBL_HELP_PRINT' => 'Print', + 'LBL_HIDE_TABS'=>'Hide Tabs', + 'LBL_HIDDEN_PANELS'=>'Hidden Subpanels', + 'LBL_HIDDEN_TABS'=>'Hidden Tabs', + 'LBL_HIDE_ADVANCED_OPTIONS'=>'Hide Advanced Options', + 'LBL_HT_DONE' => '--- DONE ---', + 'LBL_HT_NO_WRITE_2' => 'If you want to secure your files from being accessible via browser, create an .htaccess file in your root directory with the lines:', + 'LBL_HT_NO_WRITE' => 'Cannot write to the file: ', + 'LBL_ICF_ADDING' => 'Adding Custom Field Meta Data Information - ', + 'LBL_ICF_DROPPING' => 'Dropping - Custom Fields Meta Data Information', + 'LBL_ICF_IMPORT_S' => 'Import Structure', + 'LBL_IFRAME'=> 'My Sites', + 'LBL_IMPORT_CUSTOM_FIELDS_DESC'=> '
    Import a .sug file that was exported from another machine. This will cause the custom field structure on this machine to match that of the other machine. It is recommended that you export your current Custom Field Structure prior to importing one. After importing the Custom Field Structure, the system will automatically run you through a Custom Field Upgrade informing you of what changes will be made to the database. If you agree with these changes click the execute non-simulation mode link at the bottom. If you wish to reverse the import process, then import the structure you exported prior to running this import. If you do
    Warning: This will remove any previously defined custom field structures that are not defined in the .sug file as well as any data stored in those custom fields.', + 'LBL_IMPORT_CUSTOM_FIELDS_STRUCT'=> ' Custom Field Structure (SugarCustomFieldStruct.sug)', + 'LBL_IMPORT_CUSTOM_FIELDS_TITLE' => 'Import Custom Fields Structure', + 'LBL_IMPORT_CUSTOM_FIELDS'=> 'Import custom field definitions from a .sugar file', + 'LBL_IMPORT_VALIDATION_KEY' =>'Import Validation Key', + 'LBL_INBOUND_EMAIL_TITLE' => 'Inbound Email', + 'LBL_LANGUAGES' => 'Manage which languages are available for users', + 'LBL_LAYOUT' => 'Add, remove, change fields, and layout fields and panels across the application', + 'LBL_LICENSE_EXPIRE_DATE' => 'Expiration Date', + 'LBL_LICENSE_KEY' => 'Download Key', + 'LBL_LICENSE_NUM_LIC_OC' => 'Number of Offline Client Licenses', + 'LBL_LICENSE_NUM_PORTAL_USERS' => 'Number of Concurrent Self-Service Portal Users', + 'LBL_LICENSE_USERS' => 'Number of Users', + 'LBL_LICENSE_VALIDATION_END' => 'Validation Key Expiration', + 'LBL_LICENSE_VALIDATION_KEY' => 'Validation Key', + 'LBL_LICENSE_VALIDATION' => 'License Validation', + 'LBL_LICENSE' => 'License', + 'LBL_LIST_FIRST_CONNECT_DATE' => 'First Connect Date', + 'LBL_LIST_LAST_CONNECT_DATE' => 'Last Connect Date', + 'LBL_LIST_NUM_SYNCS' => 'Num. of Syncs', + 'LBL_LIST_SET_STATUS' => 'Set Status', + 'LBL_LIST_SYSTEM_KEY' => 'System Key', + 'LBL_LIST_SYSTEM_NAME' => 'System Name', + 'LBL_LIST_VIEW' => 'List', + + 'LBL_LDAP_TITLE'=>'LDAP Support', + 'LBL_LDAP_ENABLE'=>'Enable LDAP Authentication', + 'LBL_LDAP_HELP_TXT'=>'When LDAP authentication is enabled, passwords can only be handled through LDAP. None of the Sugar Password Management feature settings will apply.', + 'LBL_LDAP_SERVER_HOSTNAME'=> 'Server:', + 'LBL_LDAP_SERVER_PORT'=> 'Port Number:', + 'LBL_LDAP_ADMIN_USER'=> 'User Name:', + 'LBL_LDAP_ADMIN_USER_DESC'=>'Used to search for the Sugar user. [May need to be fully qualified] It will bind anonymously if not provided.', + 'LBL_LDAP_ADMIN_PASSWORD'=> 'Password:', + 'LBL_LDAP_AUTHENTICATION'=> 'Authentication:', + 'LBL_LDAP_AUTHENTICATION_DESC'=>'Bind to the LDAP server using a specific users credentials', + 'LBL_LDAP_AUTO_CREATE_USERS'=>'Auto Create Users:', + 'LBL_LDAP_USER_DN'=>'User DN:', + 'LBL_LDAP_GROUP_DN'=>'Group DN:', + 'LBL_LDAP_GROUP_DN_DESC'=>'Example: ou=groups,dc=example,dc=com', + 'LBL_LDAP_USER_FILTER'=>'User Filter:', + 'LBL_LDAP_GROUP_MEMBERSHIP'=>'Group Membership:', + 'LBL_LDAP_GROUP_MEMBERSHIP_DESC'=>'Users must be a member of a specific group', + 'LBL_LDAP_GROUP_USER_ATTR'=>'User Attribute:', + 'LBL_LDAP_GROUP_USER_ATTR_DESC'=>'The unique identifier of the person that will be used to check if they are a member of the group Example: uid', + 'LBL_LDAP_GROUP_ATTR_DESC'=>'The attribute of the Group that will be used to filter against the User Attribute Example: memberUid', + 'LBL_LDAP_GROUP_ATTR'=>'Group Attribute:', + 'LBL_LDAP_USER_FILTER_DESC'=>'Any additional filter params to apply when authenticating users e.g.\nis_sugar_user=1 or (is_sugar_user=1)(is_sales=1)', + 'LBL_LDAP_LOGIN_ATTRIBUTE'=>'Login Attribute:', + 'LBL_LDAP_BIND_ATTRIBUTE'=>'Bind Attribute:', + 'LBL_LDAP_BIND_ATTRIBUTE_DESC'=>'For Binding the LDAP User
    Examples: AD: userPrincipalName, openLDAP: userPrincipalName, Mac OS X: uid ', + 'LBL_LDAP_LOGIN_ATTRIBUTE_DESC'=>'For searching for the LDAP User
    Examples:AD: userPrincipalName, openLDAP: dn, Mac OS X: dn ', + 'LBL_LDAP_SERVER_HOSTNAME_DESC'=>'Example: ldap.example.com or ldaps://ldap.example.com for SSL', + 'LBL_LDAP_SERVER_PORT_DESC'=>'Example: 389 or 636 for SSL', + 'LBL_LDAP_GROUP_NAME'=>'Group Name:', + 'LBL_LDAP_GROUP_NAME_DESC'=>'Example cn=sugarcrm', + 'LBL_LDAP_USER_DN_DESC'=>'Example: ou=people,dc=example,dc=com', + 'LBL_LDAP_AUTO_CREATE_USERS_DESC'=> 'If an authenticated user does not exist one will be created in Sugar.', + 'LBL_LDAP_ENC_KEY' => 'Encryption Key:', + + 'LBL_LOADING' => 'Loading, Please wait...', + 'LBL_LOCALE_DB_COLLATION_TITLE' => 'Database Collation', + 'LBL_LOCALE_DB_COLLATION' => 'Collation', + 'LBL_LOCALE_DEFAULT_CURRENCY_ISO4217' => 'ISO 4217 Currency Code', + 'LBL_LOCALE_DEFAULT_CURRENCY_NAME' => 'Currency', + 'LBL_LOCALE_DEFAULT_CURRENCY_SYMBOL' => 'Currency Symbol', + 'LBL_LOCALE_DEFAULT_CURRENCY' => 'System Currency', + 'LBL_LOCALE_DEFAULT_DATE_FORMAT' => 'Date Format', + 'LBL_LOCALE_DEFAULT_DECIMAL_SEP' => 'Decimal Symbol', + 'LBL_LOCALE_DEFAULT_LANGUAGE' => 'Language', + 'LBL_LOCALE_DEFAULT_NAME_FORMAT' => 'Name Format', + 'LBL_LOCALE_DEFAULT_NUMBER_GROUPING_SEP' => '1000s Separator', + 'LBL_LOCALE_DEFAULT_SYSTEM_SETTINGS' => 'User Interface', + 'LBL_LOCALE_DEFAULT_TIME_FORMAT' => 'Time Format', + 'LBL_LOCALE_EXAMPLE_NAME_FORMAT' => 'Example', + 'LBL_LOCALE_NAME_FORMAT_DESC' => '"s" Salutation
    "f" First Name
    "l" Last Name', + 'LBL_LOCALE_TITLE' => 'System Locale Settings', + 'LBL_LOCALE' => 'Set default localization settings for your system', + 'LBL_LOGIN_SUGAR_SERVER_DESC' => '- The User Name of the person who will operate this offline client', + 'LBL_LOGIN_SUGAR_SERVER' => 'End User Name:', + 'LBL_MAILBOX_DESC' => 'Set up group mail accounts for monitoring inbound email and manage personal inbound mail account information for users', + 'LBL_MANAGE_CONTRACTEMPLATES_TITLE'=>'Contract Types', + 'LBL_MANAGE_CURRENCIES' => 'Currencies', + 'LBL_MANAGE_GROUPS_TITLE' => 'Manage Groups', + 'LBL_MANAGE_GROUPS' => 'Manage groups queues', + 'LBL_MANAGE_LANGUAGES' => 'Languages', + 'LBL_MANAGE_LAYOUT' => 'Field Layout', + 'LBL_MANAGE_LICENSE_TITLE' => 'License Management', + 'LBL_MANAGE_LICENSE' => 'Manage license properties', + 'LBL_MANAGE_LOCALE' => 'Locale', + 'LBL_MANAGE_MAILBOX' => 'Inbound Email', + 'LBL_MANAGE_OFFLINE_CLIENT' => 'View Offline Clients', + 'LBL_MANAGE_OPPORTUNITIES' => 'Opportunities', + 'LBL_MANAGE_PASSWORD_TITLE' => 'Password Management', + 'LBL_MANAGE_PASSWORD'=>'Manage password requirements and expiration', + 'LBL_MANAGE_RELEASES' => 'Releases', + 'LBL_MANAGE_ROLES_TITLE' => 'Role Management', + 'LBL_MANAGE_ROLES' => 'Manage role membership and properties', + 'LBL_MANAGE_TEAMS_TITLE' => 'Team Management', + 'LBL_MANAGE_TEAMS' => 'Manage team membership and properties', + 'LBL_MANAGE_TIMEPERIODS_TITLE' => 'Time Periods', + 'LBL_MANAGE_TIMEPERIODS' => 'Manage time periods', + 'LBL_MANAGE_USERS_TITLE' => 'User Management', + 'LBL_MANAGE_USERS' => 'Manage user accounts and passwords', + 'LBL_MANAGE_WORKFLOW' => 'Workflow Management', + 'LBL_MANUAL_VALIDATION_TXT' => 'Manual Validation', + 'LBL_MANUAL_VALIDATION'=>' + If you experience persistent problems with automatic validation, please check your Proxy configuration in the System Settings admin panel. + If your system environment prohibits your system from communicating to the license validation server through the internet, you should proceed with the Manual Validation steps. ', + 'LBL_MANUAL_VALIDATION1'=> 'Step 1: Generate a license key information file by clicking the following button. ', + 'LBL_MANUAL_VALIDATION2'=> 'Then save the file (sugarkey.lic) on your local file system.', + 'LBL_MANUAL_VALIDATION3'=> 'Step 2: Transfer the sugarkey.lic file to a system where you can access the internet with a web browser. Go to http://updates.sugarcrm.com/license and submit the sugarkey.lic file.

    The license validation web site will perform the validation immediately and return you the validation key file (sugarvalidationkey.lic) if the validation is successful. Your browser should prompt you to save the file. ', + 'LBL_MANUAL_VALIDATION4'=>'Step 3: Transfer the validation key file (sugarvalidationkey.lic) back to the SugarCRM system. Import the validation key using this form below: ', + 'LBL_MANUAL_VALIDATION5'=> 'After you import the validation key, you have completed the manual validation process. Your system will update the validation key expiration date, which is the date when you need re-validate.', + 'LBL_MANUFACTURERS_TITLE' => 'Manufacturers', + 'LBL_MANUFACTURERS' => 'Set up the list of manufacturers', + 'LBL_MASS_EMAIL_CONFIG_DESC'=> 'Configure email settings', + 'LBL_MASS_EMAIL_CONFIG_TITLE'=>'Email Settings', + 'LBL_MASS_EMAIL_MANAGER_DESC'=> 'Manage the outbound email queue', + 'LBL_MASS_EMAIL_MANAGER_HEADER'=>'Campaign Email Management', + 'LBL_MASS_EMAIL_MANAGER_TITLE'=> 'Email Queue', + 'LBL_MASSAGE_MASS_EMAIL_DESC'=>'SugarCRM 3.5.1+ requires an update to the Mass Email data. Click "Begin Update" to continue.', + 'LBL_MASSAGE_MASS_EMAIL'=>'GMT Date Time Fix for Sent Mass Email', + 'LBL_MISSING_GLOBAL'=> 'We have noticed that there are users missing global team membership. If you would like to have a global team, please check the option below.', + 'LBL_MISSING_PRIVATE'=> 'We have noticed that some users do not have private teams. If you would like to ensure that all users have private teams, we recommend that you repair the option below.', + 'LBL_MISSING_TEAMS'=> 'We have noticed discrepancies between your reports to structure and your team structure. If you would like to repair this, please check the option below.', + //ModuleInstaller + 'LBL_MI_REBUILDING' => 'Rebuilding', + 'LBL_MI_SECTION' => 'Section...', + 'LBL_MI_UN_CUSTOMFIELD' => 'Uninstalling Custom Fields...', + 'LBL_MI_IN_CUSTOMFIELD' => 'Installing Custom Fields...', + 'LBL_MI_COMPLETE' => 'Complete', + 'LBL_MI_UN_BEAN' => 'Uninstalling Bean :', + 'LBL_MI_IN_BEAN' => 'Installing Bean :', + 'LBL_MI_IN_DASHLETS' => 'Installing Sugar Dashlet ', + 'LBL_MI_UN_DASHLETS' => 'Uninstalling Sugar Dashlet ', + 'LBL_MI_IN_IMAGES' => 'Installing Images', + 'LBL_MI_IN_MENUS' => 'Installing menus', + 'LBL_MI_UN_MENUS' => 'Uninstalling menus', + 'LBL_MI_IN_ADMIN' => 'Installing Administration Section ', + 'LBL_MI_UN_ADMIN' => 'Uninstalling Administration Section ', + 'LBL_MI_IN_USER' => 'Installing User Page Section ', + 'LBL_MI_UN_USER' => 'Uninstalling User Page Section ', + 'LBL_MI_IN_VAR' => 'Installing Variable Definitions', + 'LBL_MI_UN_VAR' => 'Uninstalling Variable Definitions', + 'LBL_MI_IN_SUBPANEL' => 'Installing Subpanel Layouts', + 'LBL_MI_UN_SUBPANEL' => 'Uninstalling Subpanel Layouts', + 'LBL_MI_IN_LANG' => 'Installing Language Packs', + 'LBL_MI_UN_LANG' => 'Uninstalling Language Packs', + 'LBL_MI_IN_RELATIONSHIPS' => 'Installing Relationships', + 'LBL_MI_UN_RELATIONSHIPS' => 'Uninstalling Relationships', + 'LBL_MI_UN_RELATIONSHIPS_DROP' => 'droping table ', + 'LBL_MI_REPAIR_INDICES' => 'Repairing indexes', + 'LBL_MI_IN_CONNECTORS' => 'Installing Connectors', + 'LBL_MI_UN_CONNECTORS' => 'UnInstalling Connectors', + + 'LBL_ML_ACTION' => 'Action', + 'LBL_ML_CANCEL' => 'Cancel', + 'LBL_ML_COMMIT'=>'Commit', + 'LBL_ML_DESCRIPTION' => 'Description', + 'LBL_ML_INSTALLED' => 'Date Installed', + 'LBL_ML_NAME' => 'Name', + 'LBL_ML_PUBLISHED' => 'Date Published', + 'LBL_ML_TYPE' => 'Type', + 'LBL_ML_UNINSTALLABLE' => 'Uninstallable', + 'LBL_ML_VERSION' => 'Version', + 'LBL_ML_INSTALL'=>'Install', + 'LBL_ML_ENABLE_OR_DISABLE'=>'Enable/Disable', + 'LBL_ML_DELETE'=>'Delete', + 'LBL_MODIFY_CREDENTIALS' => 'Modify Credentials', + 'LBL_MODULE_LICENSE' => 'Please read the following License Agreement:', + 'LBL_MODULE_LOADER_TITLE' => 'Module Loader', + 'LBL_MODULE_LOADER' => 'Add or remove Sugar modules, themes, language packs and other extensions', + 'LBL_MODULE_NAME' => 'Administration', + 'LBL_MODULE_TITLE' => 'Administration: Home', + 'LBL_MODULES_TO_DOWNLOAD' => 'Modules to Download (drag and drop here)', + 'LBL_NEVER'=>'Never', + 'LBL_NEW_FORM_TITLE' => 'Create Account', + 'LBL_NOTIFY_SUBJECT' => 'Email subject:', + 'LBL_OC_SEARCH_FORM_TITLE' => 'Offline Client Search', + 'LBL_OFFLINE_CLIENT' => 'View Offline Clients that are connected to this Sugar system', + 'LBL_OOTB_BOUNCE' => 'Run Nightly Process Bounced Campaign Emails', + 'LBL_OOTB_CAMPAIGN' => 'Run Nightly Mass Email Campaigns', + 'LBL_OOTB_IE' => 'Check Inbound Email Accounts', + 'LBL_OOTB_PRUNE' => 'Prune Database on 1st of Month', + 'LBL_OOTB_REPORTS' => 'Run Report Generation Scheduled Tasks', + 'LBL_OOTB_WORKFLOW' => 'Process Workflow Tasks', + 'LBL_OOTB_TRACKER' => 'Prune User History Table on 1st of Month', + 'LBL_UPDATE_TRACKER_SESSIONS' => 'Update tracker_sessions Table', + 'LBL_OOTB_DCE_CLNUP' => 'Close loop on completed DCE actions', + 'LBL_OOTB_DCE_REPORT' => 'Create Action to gather daily reports', + 'LBL_OOTB_DCE_SALES_REPORT' => 'Create weekly Sales Report Email', + 'LBL_OVERWRITE_FILES' => 'Overwrite Files', + 'LBL_PASSWORD_SUGAR_SERVER_DESC' => '- An Admin user name and password on the server', + 'LBL_PASSWORD_SUGAR_SERVER' => 'Admin Password:', + 'LBL_PASSWORD' => 'Password', + 'LBL_PASSWORD_RESET_MANAGEMENT'=> 'Reset password option', + 'LBL_PASSWORD_RULES_MANAGEMENT'=> 'Password Requirements', + 'LBL_PASSWORD_TEMPLATE' => 'Email Templates', + 'LBL_PASSWORD_CREATE_TEMPLATE' => 'Create', + 'LBL_PASSWORD_EDIT_TEMPLATE' => 'Edit', + 'LBL_PASSWORD_GENERATE_TEMPLATE_MSG' => 'Email template containing system-generated password', + 'LBL_PASSWORD_LOST_TEMPLATE_MSG' => 'Email template containing system-generated link to reset password', + 'LBL_PASSWORD_INVALID_LENGTH' => 'Minimum Length must be less than Maximum Length', + 'LBL_PASSWORD_INVALID_MINLENGTH' => 'Minimum Length must be more than 0', + 'LBL_PASSWORD_SYST_GENERATED_PWD_ON' =>'Enable System-Generated Passwords Feature', + 'LBL_PASSWORD_SYST_GENERATED_PWD_HELP' => 'When this feature is enabled, users will be emailed a system-generated link to reset their passwords. Requirements for this feature are: 1) a outbound email server must be configured properly in Email Settings, and 2) users must have valid email addresses in their user records', + 'LBL_PASSWORD_EXP_AFTER'=> 'Password Expires upon', + 'LBL_PASSWORD_FORGOT_FEATURE'=> 'Enable Forgot Password feature', + 'LBL_PASSWORD_FORGOT_FEATURE_HELP'=> 'When enabled, users will have the ability to reset their own passwords at the Login page. Requirements to use this feature: 1) users must have email addresses provided in their user records, and 2) an outbound email server must be configured in the Email Settings page.', + 'LBL_PASSWORD_ONE_UPPER_CASE' => 'Must contain one upper case letter (A-Z)', + 'LBL_PASSWORD_ONE_LOWER_CASE' => 'Must contain one lower case letter (a-z)', + 'LBL_PASSWORD_ONE_NUMBER' => 'Must contain one number (0-9)', + 'LBL_PASSWORD_ONE_SPECIAL_CHAR' => 'Must contain one of the following special characters (~,!,@,#,$,%,^,&,*,(,),_,+,-,=,{,},|)', + 'LBL_PASSWORD_ONLY_LOWCASE' => 'Only lowcase caracters', + 'LBL_PASSWORD_LOCKOUT' => 'Login Lockout', + 'LBL_PASSWORD_LOCKOUT_ATTEMPT1' => 'Lockout users after ', + 'LBL_PASSWORD_LOCKOUT_ATTEMPT2' => ' un-successful login attempts', + 'LBL_PASSWORD_LOGIN' => 'Login', + 'LBL_PASSWORD_LOGINS' => 'logins', + 'LBL_PASSWORD_LOGIN_DELAY' => 'Enable login again after', + 'LBL_PASSWORD_NEEDED_CARACTERS' => 'Needed caracters', + 'LBL_PASSWORD_PROHIBITED_CARACTERS' => 'Prohibited caracters', + 'LBL_PASSWORD_MINIMUM_LENGTH'=> 'Minimum Length', + 'LBL_PASSWORD_MAXIMUM_LENGTH'=> 'Maximum Length', + 'LBL_PASSWORD_AND_MAXIMUM_LENGTH'=> 'and Maximum Length', + 'LBL_PASSWORD_FIRSTNAME_PROHIBITED'=> 'First name not allowed', + 'LBL_PASSWORD_LASTNAME_PROHIBITED'=> 'Last name not allowed', + 'LBL_PASSWORD_SYST_EXPIRATION'=> 'System-Generated Password Expiration', + 'LBL_PASSWORD_SYST_GENERATED_TITLE'=> 'System-Generated Passwords', + 'LBL_PASSWORD_USER_EXPIRATION'=> 'User-Generated Password Expiration', + 'ERR_PASSWORD_LINK_EXPIRE_TIME' => 'Specify the time after which the generated link will expire.', + 'ERR_PASSWORD_EXPIRE_TIME' => 'Specify the time after which the password will expire.', + 'ERR_PASSWORD_EXPIRE_LOGIN' => 'Specify the number of logins after which the password will expire.', + 'ERR_PASSWORD_LOCKOUT_TIME' => 'Specify the time after which users may attempt to login again.', + 'ERR_PASSWORD_LOCKOUT_LOGIN' => 'Specify the number of failed login attempts after which users will be locked out.', + 'LBL_PASSWORD_LINK_EXPIRATION'=> 'Generated Link Expiration', + 'LBL_PASSWORD_LINK_EXPIRATION_HELP'=> 'A link is generated by the system and sent to the user to allow the user to access the Reset Password page.', + 'LBL_PASSWORD_REGEX'=> 'Regex Requirement', + 'LBL_PASSWORD_REGEX_COMMENT'=> 'Regex Description', + 'LBL_PASSWORD_RULES' => 'Password Rules', + 'LBL_PASSWORD_LINK_EXP_IN'=> 'Link Expires in', + 'LBL_PASSWORD_EXP_IN'=> 'Password Expires in', + 'LBL_PASSWORD_USER_RESET' => 'User Reset Password', + 'LBL_PERFORM_UPDATE'=>'Perform Update', + 'LBL_PLUGINS_TITLE' => 'Sugar Forge', + 'LBL_PLUGINS' => 'Get plug-ins and other Sugar extensions.', + 'LBL_PRICE_LIST_TITLE' => 'Product and Quotes', + 'LBL_PRICE_LIST_DESC' => 'Manage the product catalog, along with the related information on manufacturers and shipping providers.', + 'LBL_PRIVATE_TEAM' => 'Rebuild access to private team. Every user of the application must have one, and all managers in the upline must have access to it.', + 'LBL_PRODUCT_CATEGORIES_TITLE' => 'Product Categories', + 'LBL_PRODUCT_CATEGORIES' => 'Update the list of product categories', + 'LBL_PRODUCT_TYPES_TITLE' => 'Product Types', + 'LBL_PRODUCT_TYPES' => 'Configure the list of product types', + 'LBL_PRODUCTS_TITLE' => 'Product Catalog', + 'LBL_PRODUCTS' => 'Enter items in the product catalog', + 'LBL_PROXY_AUTH'=>'Authentication?', + 'LBL_PROXY_HOST'=>'Proxy Host', + 'LBL_PROXY_ON_DESC'=>'Use a proxy to access external information such as Sugar updates.', + 'LBL_PROXY_ON'=>'Enable Proxy?', + 'LBL_PROXY_PASSWORD'=>'Password', + 'LBL_PROXY_PORT'=>'Port', + 'LBL_PROXY_TITLE'=>'Proxy Settings', + 'LBL_PROXY_USERNAME'=>'User Name', + 'LBL_QUOTES_ORDERS_TITLE' => 'Quotes and Orders', + 'LBL_README' => 'Readme', + 'LBL_REBUILD_AUDIT_DESC' => 'Rebuilds audit table', + 'LBL_REBUILD_AUDIT_TITLE' => 'Rebuild Audit', + 'LBL_REBUILD_AUDIT_SEARCH' => 'Searching for new audit enabled modules', + 'LBL_REBUILD_AUDIT_CREATING' => 'creating table %1$s for %2$s .
    ', + 'LBL_REBUILD_AUDIT_SKIP' => 'Audit table for %1$s already exists. skipping...
    ', + 'LBL_REBUILD_CONFIG_DESC' =>'Rebuilds config.php by updating version and adding defaults when not explicitly declared', + 'LBL_REBUILD_CONFIG' =>'Rebuild Config File', + 'LBL_REBUILD_DASHLETS_DESC_SHORT' => 'Rebuilds the Sugar Dashlets cache file', + 'LBL_REBUILD_DASHLETS_DESC_SUCCESS' => 'Sugar Dashlets cache file rebuilt.', + 'LBL_REBUILD_DASHLETS_DESC' => 'Removing Sugar Dashlets cache and scanning known directories for Sugar Dashlet files.', + 'LBL_REBUILD_DASHLETS_TITLE' => 'Rebuild Sugar Dashlets', + 'LBL_REBUILD_EXTENSIONS_DESC' => 'Rebuilds extensions including extended vardefs, language packs, menus and administration', + 'LBL_REBUILD_EXTENSIONS_TITLE' => 'Rebuild Extensions', +//BEGIN SUGARCRM flav=een + 'LBL_REBUILD_EXPRESSIONS_DESC' => 'Rebuilds Sugar Logic functions cache', + 'LBL_REBUILD_EXPRESSIONS_TITLE' => 'Rebuild Sugar Logic Functions', +//END SUGARCRM flav=een + 'LBL_REBUILD_HTACCESS_DESC'=>'Rebuilds .htaccess to limit access to certain files directly', + 'LBL_REBUILD_HTACCESS'=>'Rebuild .htaccess File', + 'LBL_REBUILD_WEBCONFIG_DESC'=>'Rebuilds web.config to limit access to certain files directly', + 'LBL_REBUILD_WEBCONFIG'=>'Rebuild web.config File', + 'LBL_REBUILD_JAVASCRIPT_LANG_DESC_SHORT' => 'Rebuilds javascript versions of language files', + 'LBL_REBUILD_JAVASCRIPT_LANG_DESC' => 'Removing javascript versions of language files, will rebuild when needed.', + 'LBL_REBUILD_JAVASCRIPT_LANG_TITLE' => 'Rebuild Javascript Languages', + + 'LBL_REBUILD_JS_FILES_TITLE' => 'Rebuild JS Compressed Files', + 'LBL_REBUILD_JS_FILES_DESC_SHORT' => 'Copies original Full JS Source files and replaces existing compressed JS files', + 'LBL_REBUILD_CONCAT_JS_FILES_TITLE' => 'Rebuild JS Grouping Files', + 'LBL_REBUILD_CONCAT_JS_FILES_DESC_SHORT' => 'Re-concatenates and overwrites existing group files with latest versions of group files', + 'LBL_REBUILD_JS_MINI_FILES_TITLE' => 'Rebuild Minified JS Files', + 'LBL_REBUILD_JS_MINI_FILES_DESC_SHORT' => 'Copies original Full JS Source Files and minifies them, then replaces existing compressed files', + 'LBL_REPAIR_JS_FILES_TITLE' => 'Repair JS Files', + 'LBL_REPAIR_JS_FILES_DESC_SHORT' => 'Compresses Existing JS files - includes any changes made, but does not overwrite original JS Source files', + 'LBL_REPAIR_JS_FILES_PROCESSING' => 'Processing files. This may take several minutes. Going away from this page will not cancel the process, so feel free to move on or wait for confirmation...', + 'LBL_REPAIR_JS_FILES_DONE_PROCESSING' => 'Done Processing files.', + 'LBL_REPAIR_FIELD_CASING_TITLE' => 'Repair Non-Lowercase Fields', + 'LBL_REPAIR_FIELD_CASING_DESC_SHORT' => 'Repair mixed-case custom table(s) and metadata file(s) to fix issues where code expects lowercase field names', + 'LBL_REPAIR_FIELD_CASING_PROCESSING' => 'Scanning custom fields and files...', + 'LBL_REPAIR_FIELD_CASING_SQL_FIELD_META_DATA' => 'Updating row entry {0} in table fields_meta_data', + 'LBL_REPAIR_FIELD_CASING_SQL_CUSTOM_TABLE' => 'Updating column {0} in table {1}', + 'LBL_REBUILD_REL_DESC'=>'Rebuilds relationship metadata and drops the cache file', + 'LBL_REBUILD_REL_TITLE'=>'Rebuild Relationships', + 'LBL_REBUILD_REL_PROC_META'=>'Processing relationship meta for ', + 'LBL_REBUILD_REL_PROC_C_META'=>'Processing custom relationship meta for ', + 'LBL_REBUILD_REL_DEL_CACHE'=>'Deleting relationship cache file...
    ', + 'LBL_REBUILD_REL_UPD_WARNING'=>'Updating the admin warning message...
    ', + 'LBL_REBUILD_SCHEDULERS_DESC_SHORT' => 'Rebuilds out-of-the-box Scheduler Jobs', + 'LBL_REBUILD_SCHEDULERS_DESC_SUCCESS' => 'Scheduler Job rebuild complete.', + 'LBL_REBUILD_SCHEDULERS_DESC' => 'Rebuilding your Scheduler Jobs will delete all existing job entries and their respective logs. All out-of-the-box Scheduler jobs will be rebuilt with their default settings, including the Active/Inactive flag.', + 'LBL_REBUILD_SCHEDULERS_TITLE' => 'Rebuild Schedulers', + 'LBL_REBUILD_WORKFLOW_CACHE' => 'Rebuilding Workflow Cache...
    ', + 'LBL_REBUILD_WORKFLOW_COMPILING' => 'Compiling Plugins...
    ', + 'LBL_REBUILD' => 'Rebuild', + 'LBL_REBUILD'=>'Rebuild', + 'LBL_REGEX_HELP_TITLE' =>'Regex Description', + 'LBL_REGEX_HELP_TEXT' =>'Regular Expressions provide a concise and flexible means for identifying strings of the password, such as particular characters or patterns of characters. You can create custom password rules by providing a regex that will be used in a NOT MATCH condition; the password must not contain a match to any expressions in the regex.', + 'LBL_REGEX_DESC_HELP_TEXT' =>'This description should explain the Regex Requirement and will be displayed in the list of requirements for users when they provide new passwords.', + 'LBL_RELEASE' => 'Manage releases and versions', + 'LBL_RENAME_TABS'=>'Rename Tabs', + 'LBL_REPAIR_ACTION' => 'What action would you like to take?', + 'LBL_REPAIR_DATABASE_DESC' => 'Repairs database based on values defined in vardefs', + 'LBL_REPAIR_DATABASE_PROCESSING' => 'Processing database and vardef comparison...', + 'LBL_REPAIR_DATABASE_DIFFERENCES' => "Differences found between database and vardefs", + 'LBL_REPAIR_DATABASE_TEXT' => "The following script will sync the database structure with the structure defined " . + "in the vardefs. You have the option of exporting this script and then running it " . + "against your database using external database management tools, or to allow the " . + "administration module to run the script." . + "

    NOTE: any changes you make to the script in the textbox will be reflected " . + "in the exported or executed code.

    ", + 'LBL_REPAIR_DATABASE_SYNCED' => "Database tables are synced with vardefs", + 'LBL_REPAIR_DATABASE_EXECUTE' => "Execute", + 'LBL_REPAIR_DATABASE_EXPORT' => "Export", + 'LBL_REPAIR_DATABASE' =>'Repair Database', + 'LBL_REPAIR_DISPLAYSQL' =>'Display SQL', + 'LBL_REPAIR_ENTRY_POINTS_DESC' => 'Repair Entry Points check. Run this script if you receive \'Not A Valid Entry Point\' errors.', + 'LBL_REPAIR_ENTRY_POINTS' => 'Repair Entry Points', + 'LBL_REPAIR_EXECUTESQL' =>'Execute SQL', + 'LBL_REPAIR_EXPORTSQL' =>'Export SQL', + 'LBL_REPAIR_IE_DESC' => 'Repairs Inbound Email accounts and encrypts account passwords', + 'LBL_REPAIR_IE_FAILURE' => 'The following Inbound Email accounts must be repaired manually - please re-enter login name and password for each:', + 'LBL_REPAIR_IE_SUCCESS' => 'All Inbound Email accounts repaired successfully!', + 'LBL_REPAIR_IE' => 'Repair Inbound Email Accounts', + 'LBL_REPAIR_INDEX'=>'Repair Indexes', + 'LBL_REPAIR_INDEX_DROPPING'=>'
    Dropping constraints/indexes.', + 'LBL_REPAIR_INDEX_EXECUTING'=>'
    Executing ', + 'LBL_REPAIR_INDEX_DROP'=>'
    Drop these constraints/indexes.', + 'LBL_REPAIR_INDEX_ADDING'=>'
    Adding constraints/indexes.', + 'LBL_REPAIR_INDEX_ADD'=>'

    Add these constraints/indexes.', + 'LBL_REPAIR_INDEX_ALTERING'=>'
    Altering constraints/indexes.', + 'LBL_REPAIR_INDEX_ALTER'=>'

    Alter these constraints/indexes.', + 'LBL_REPAIR_INDEX_SYNC'=>'


    Index definitions are in sync.', + 'LBL_REPAIR_ORACLE_COMMIT_DONE' => 'All SQL queries committed.', + 'LBL_REPAIR_ORACLE_COMMIT' => 'Commit', + 'LBL_REPAIR_ORACLE_VARCHAR_DESC_LONG_1' => 'The following queries should be run against your database. Run them manually with the client of your choice or click the "Commit" button to have SugarCRM run the queries immediately.', + 'LBL_REPAIR_ORACLE_VARCHAR_DESC_LONG_2' => 'No columns were discovered needing the VARCHAR2 char semantic change.', + 'LBL_REPAIR_ORACLE_VARCHAR_DESC' => 'Changes the semantics of VARCHAR2 columns from byte to char; necessary for UTF-8, MBCS support', + 'LBL_REPAIR_ORACLE_VARCHAR' => 'Repair Oracle VARCHAR2 Columns', + 'LBL_REPAIR_ROLES_DESC'=>'Repairs Roles by adding all new modules that support Access Controls, and by adding any new Access Controls to existing modules', + 'LBL_REPAIR_ROLES'=>'Repair Roles', + 'LBL_REPAIR_TEAMS_DESC'=>'Rebuilds private team memberships based on user reporting hierarchy', + 'LBL_REPAIR_TEAMS'=>'Repair Teams', + 'LBL_REPAIR_TEAMS_PROCESS_USER'=>'
    Processing user=', + 'LBL_REPAIR_TEAMS_REPORT'=>' reports to=', + 'LBL_REPAIR_TEAMS_SKIP_USER'=>'
    Skipping user=', + 'LBL_REPAIR_TEAMS_NO_PROC'=>'

    Nothing to process...', + 'LBL_REPAIR_THEME_IMAGES' => 'Optimize Themes', + 'LBL_REPAIR_THEME_IMAGES_DESC' => 'Optimize themes by removing cloned images.', + 'LBL_REPAIR_XSS' => 'Remove XSS', + 'LBL_REPAIR_ACTIVITIES_DESC' =>'Repairs Activities (Calls, Meetings) end dates', + 'LBL_REPAIR_ACTIVITIES_TEXT'=>'This tool allows you to fix the end date for Calls and Meetings.', + 'LBL_REPAIR_ACTIVITIES' =>'Repair Activities', + 'LBL_CHECK_REPORTS_DESC' =>'Checks whether reports are still valid after an upgrade and lists any invalid reports that are found during the check', + 'LBL_CHECK_REPORTS_TEXT'=>'This tool allows you to check if all your reports are valid.', + 'LBL_CHECK_REPORTS' =>'Check Reports', + + 'LBL_ALL' => 'All', + 'LBL_REPAIRXSS_COUNT' => 'Object(s) found', + 'LBL_REPAIRXSS_INSTRUCTIONS' => 'Select a module to remove potential XSS strings. Select "All" to address every module.
    Press execute to start the detection and removal process.', + 'LBL_REPAIRXSS_REPAIRED' => 'Object(s) repaired', + 'LBL_REPAIRXSS_TITLE' => 'Removes XSS Vulnerabilities from the database', + + 'LBL_RESERVE_OC_SPOT' => 'Reserve an Offline Client Position', + 'LBL_RESTORE_BUTTON_LABEL' => 'Restore', + 'LBL_RETURN' => 'Return', + 'LBL_REVALIDATE'=>'Re-validate' , + 'LBL_SEARCH_MODULE_NAME' => 'Enter all or part of the module name:', + 'LBL_SELECT_USER' => 'Select User:', + 'LBL_SEND_STAT'=>'Send Anonymous Usage Statistics - If checked, Sugar will send anonymous statistics about your installation to SugarCRM Inc. every time your system checks for new versions. This information will help us better understand how the application is used and guide improvements to the product.', + 'LBL_SHIPPERS_TITLE' => 'Shipping Providers', + 'LBL_SHIPPERS' => 'Set up the list of available shipment methods', + 'LBL_SHOW_ADVANCED_OPTIONS' => 'Show Advanced Options', + 'LBL_STATUS'=>'Status ', + 'LBL_TOOLS_DESC' => 'Create and edit modules and module layouts, manage standard and custom fields and configure tabs. ', + 'LBL_STUDIO_DESC' => 'Customize module fields, layouts and relationships', + 'LBL_STUDIO_TITLE' => 'Developer Tools', + 'LBL_STUDIO' => 'Studio', + 'LBL_SUGAR_NETWORK_TITLE' => 'Sugar Connect', + 'LBL_SUGAR_NETWORK_DESC' => 'Connect to the various SugarCRM services where you can access the SugarCRM forums and Sugar Wiki, search FAQs (Frequently Asked Questions), download the latest Sugar version, file and research reported bugs and request new features and more.', + 'LBL_SUGAR_SCHEDULER_TITLE' => 'Scheduler', + 'LBL_SUGAR_SCHEDULER' => 'Set up scheduled events', + 'LBL_SUGAR_SERVER_URL_DESC' => '- The URL of the server this client will connect to (e.g., http://localhost/sugarserver).', + 'LBL_SUGAR_SERVER_URL' => 'Server URL:', + 'LBL_SUGAR_UPDATE_TITLE'=>'Sugar Updates', + 'LBL_SUGAR_UPDATE'=>'Check for the latest Sugar version', + 'LBL_SUGARCRM_HELP' => 'SugarCRM Help', + 'LBL_SUPPORT_TITLE' => 'Sugar Support Portal', + 'LBL_SUPPORT' => 'Access technical support and more', + 'LBL_SYSTEM_NAME' => 'System Name', + 'LBL_TAXRATES_TITLE' => 'Tax Rates', + 'LBL_TAXRATES' => 'Configure the list of available tax rates for quotes', + 'LBL_TEAM_HIERARCHY' => 'Rebuild team hierarchy. Implicit access to all teams for all users will be rebuilt.
    Let\'s say User A reports to User B who reports to User C. If explicit access to Team 1 is provided to User A, then User B and User C will acquire implicit access to this team.', + 'LBL_TEAMS_TITLE' => 'Teams', + 'LBL_TERMS_AND_CONDITIONS' => 'Terms and Conditions', + 'LBL_THEME_SETTINGS' => 'Themes', + 'LBL_THEME_SETTINGS_DESC' => 'Choose themes for users to be able to select', + 'LBL_THEME_SETTINGS_AVAILABLE_THEMES' => 'Available Themes', + 'LBL_THEME_SETTINGS_UNAVAILABLE_THEMES' => 'Unavailable Themes', + 'LBL_TIMEZONE' => 'Time Zone', + 'LBL_TO' => ' to ', + 'LBL_TRACKER_SETTINGS' => 'Tracker', + 'LBL_TRACKER_SETTINGS_DESC' => 'Select what system and user data is tracked', + 'LBL_SUGARFEED_SETTINGS' => 'Activity Streams', + 'LBL_SUGARFEED_SETTINGS_DESC' => 'Enable the user feed and module feeds for the My Activity Stream dashlet.', + 'LBL_UPDATE_CHECK_AUTO'=>'Automatically', + 'LBL_UPDATE_CHECK_MANUAL'=>'Manually', + 'LBL_UPDATE_CHECK_TYPE'=>'Automatically Check For Updates - If checked, the system will periodically check to see if updated versions of the application are available.', + 'LBL_UPDATE_DESCRIPTIONS'=>'Description', + 'LBL_UPDATE_TITLE'=>'Sugar Updates', + 'LBL_UPGRADE_ADDED_TO_GROUP' =>'Added to Group', + 'LBL_UPGRADE_ALREADY_EXISTS_GROUP' =>'a group already exists', + 'LBL_UPGRADE_ALREADY_EXISTS_IN_GROUP' =>'Already exists in group:', + 'LBL_UPGRADE_CONVERT_DISC_CLIENT_TITLE' => 'Convert to Offline Client', + 'LBL_UPGRADE_CONVERT_DISC_CLIENT' => 'Convert this Sugar installation to an Offline Client', + 'LBL_UPGRADE_CONVERT_DISC_DESCRIPTION' => 'Warning: Please ensure this is a fresh install with no seed data.
    Enter the following information and press Save to convert this system into an offline client.', + 'LBL_UPGRADE_CURRENCY' => 'Upgrade currency amounts in ', + 'LBL_UPGRADE_CUSTOM_LABELS_DESC'=>'Upgrade the format of the custom field labels in every language file.', + 'LBL_UPGRADE_CUSTOM_LABELS_TITLE'=>'Upgrade Custom Labels', + 'LBL_UPGRADE_DB_BEGIN' => 'Beginning Upgrade', + 'LBL_UPGRADE_DB_COMPLETE' => 'Upgrade Complete', + 'LBL_UPGRADE_DB_FAIL' => 'Upgrade Failed', + 'LBL_UPGRADE_DB_TITLE' => 'Upgrade database', + 'LBL_UPGRADE_DB' => 'Update the database from version 2.0.x to 2.5 ', + 'LBL_UPGRADE_FOR_PRODUCT'=> 'for Product', + 'LBL_UPGRADE_NEW_GROUP' =>'Created new Group', + 'LBL_UPGRADE_NOT_UPGRADING' =>'Not attempting to upgrade', + 'LBL_UPGRADE_STUDIO_DESC'=>' Upgrade pre 4.5 files for 4.5 studio', + 'LBL_UPGRADE_STUDIO_TITLE'=>'Upgrade Studio', + 'LBL_UPGRADE_SYNC_DISC_CLIENT_TITLE' => 'Sync Client', + 'LBL_UPGRADE_SYNC_DISC_CLIENT' => 'Synchronize client files and data to server', + 'LBL_UPGRADE_TEAM_CREATE' => 'Created Teams for -', + 'LBL_UPGRADE_TEAM_EXISTS'=> 'Team Already Exists', + 'LBL_UPGRADE_TEAM_TITLE' => 'Upgrade Teams', + 'LBL_UPGRADE_TEAMS' => 'Creates teams for users', + 'LBL_UPGRADE_TITLE' => 'Repair', + 'LBL_UPGRADE_VERSION'=>'Updating version info', + 'LBL_UPGRADE_WIZARD_TITLE' => 'Upgrade Wizard', + 'LBL_UPGRADE_WIZARD' => 'Upload and install Sugar upgrades', + 'LBL_UPGRADE' => 'Check and repair Sugar', + 'LBL_UPLOAD_UPGRADE' => 'Upload an upgrade: ', + 'LBL_UPTODATE'=>'You have the latest version available', + 'LBL_USER_NAME' => 'User Name:', + 'LBL_USERNAME' => 'User Name', + 'LBL_USERS_TITLE' => 'Users', + + 'LBL_USERS_DESC' => 'Create, edit, activate and deactivate users in Sugar.', + + + + 'LBL_UW_BTN_BACK_TO_MOD_LOADER' => 'Back to Module Loader', + 'LBL_UW_BTN_BACK_TO_UW' => 'Back to Upgrade Wizard', + 'LBL_UW_BTN_DELETE_PACKAGE' => 'Delete Package', + 'LBL_UW_BTN_DOWNLOAD' => 'Download', + 'LBL_UW_BTN_INSTALL' => 'Install', + 'LBL_UW_BTN_UPLOAD' => 'Upload', + 'LBL_UW_CHECK_ALL'=>'Check All', + 'LBL_UW_DESC_MODULES_INSTALLED' => 'The following extensions are installed on this system:', + 'LBL_UW_DESC_MODULES_QUEUED' => 'The following modules are ready to be installed:', + 'LBL_UW_DISABLE' => 'Disable', + 'LBL_UW_ENABLE' => 'Enable', + 'LBL_UW_FOLLOWING_FILES' => 'The following files were ', + 'LBL_UW_HIDE_DETAILS'=> 'Hide Details', + 'LBL_UW_INCLUDING' => 'Including', + 'LBL_UW_MODULE_READY_DISABLE' => 'The module is ready to be disabled.', + 'LBL_UW_MODULE_READY_ENABLE' => 'The module is ready to enable.', + 'LBL_UW_LANGPACK_READY_DISABLE' => 'The language package is ready to be disabled.', + 'LBL_UW_LANGPACK_READY_ENABLE' => 'The language package is ready to be enabled.', + 'LBL_UW_MODULE_READY_UNISTALL' => 'The module is ready to be uninstalled.', + 'LBL_UW_LANGPACK_READY_UNISTALL' => 'The language package is ready to be uninstalled.', + 'LBL_UW_MODULE_READY' => 'The module is ready to be installed.', + 'LBL_UW_LANGPACK_READY' => 'The language package is ready to be installed.', + 'LBL_UW_NO_FILES_SELECTED' => 'No files selected to be ', + 'LBL_UW_NO_INSTALLED_UPGRADES' => "No recorded upgrades.
    \n", + 'LBL_UW_NONE' => 'None', + 'LBL_UW_NOT_AVAILABLE' => "Not Available", + 'LBL_UW_OP_MODE' => 'Mode of operation:', + 'LBL_UW_PACKAGE_REMOVED' => " has been removed.
    \n", + 'LBL_UW_PATCH_READY'=> '

    Ready To Install

    ', + 'LBL_UW_UNINSTALL_READY'=> '

    Ready To Uninstall

    ', + 'LBL_UW_DISABLE_READY'=> '

    Ready To Disable

    ', + 'LBL_UW_ENABLE_READY'=> '

    Ready To Enable

    ', + 'LBL_UW_SHOW_DETAILS'=> 'Show Details', + 'LBL_UW_SUCCESSFUL' => 'Successful', + 'LBL_UW_SUCCESSFULLY' => 'Successfully', + 'LBL_UW_UNINSTALL' => 'Uninstall', + 'LBL_UW_UPGRADE_SUCCESSFUL' => "Upgrade applied successfully!
    \n", + 'LBL_UW_UPLOAD_MODULE' => 'Module', + 'LBL_UW_TYPE_FULL' => 'Full Upgrade', + 'LBL_UW_TYPE_LANGPACK' => 'Language Pack', + 'LBL_UW_TYPE_MODULE' => 'Module', + 'LBL_UW_TYPE_PATCH' => 'Patch', + 'LBL_UW_TYPE_THEME' => 'Theme', + 'LBL_UW_MODE_INSTALL' => 'Installed', + 'LBL_UW_MODE_UNINSTALL' => 'Uninstalled', + 'LBL_UW_MODE_DISABLE' => 'Disabled', + 'LBL_UW_MODE_ENABLE' => 'Enabled', + 'LBL_UW_UPLOAD_SUCCESS' => " has been uploaded.
    ", + 'LBL_VALIDATION_FAIL_DATE'=>'Last failed validation : ', + 'LBL_VALIDATION_FILE'=>'Validation Key File', + 'LBL_VALIDATION_SUCCESS_DATE'=>'Last successful validation : ', + 'LBL_VISIBLE_PANELS'=>'Displayed Subpanels', + 'LBL_VISIBLE_TABS'=>'Displayed Tabs', + 'LBL_WORKFLOW_DESC' => 'Manage workflow conditions, alerts and actions', + 'LBL_WORKFLOW_TITLE' => 'Workflow Management', + 'LBL_WORKBENCH' => 'Workbench', + 'LBL_WORKBENCH_DESC' => 'Customize the application and create new modules.', + + 'LNK_DISABLE' => 'Deactivate', + 'LNK_ENABLE' => 'Activate', + 'LNK_FORGOT_PASS' => 'Forgotten your password?', + 'LNK_NEW_ACCOUNT' => 'Create an account', + 'LNK_NEW_PRODUCT' => 'Create Product', + 'LNK_NEW_TEAM' => 'Create Team', + 'LNK_NEW_USER' => 'Create New User', + 'LNK_REPAIR_CUSTOM_FIELD' => 'Repair Custom Fields', + 'LNK_SELECT_CUSTOM_FIELD' => 'Select Custom Field', + 'LNK_NEW_PORTAL_USER' => 'Create New Portal User', + 'LNK_NEW_GROUP_USER' => 'Create New Group User', + 'MI_LBL_DISABLE_DEPEDENCIES' => 'This module cannot be disabled as there are other modules which are dependent on this module.', + 'MI_REDIRECT_TO_UPGRADE_WIZARD' => 'Selecting this patch will redirect you to the Upgrade Wizard to perform the necessary system checks. Do you wish to continue?', + 'ML_DESC_DOCUMENTATION' => 'Click on a tree node to view the associated details and documentation.', + 'ML_LBL_DETAIILS' => 'Details', + 'ML_LBL_DO_NOT_REMOVE_TABLES' => 'Do Not Remove Tables', + 'ML_LBL_DOCUMENTATION' => 'Documentation', + 'ML_LBL_INSTALL_FROM_LOCAL'=> 'Install from local file', + 'ML_LBL_INSTALL_FROM_SERVER' => 'Install from Sugar', + 'ML_LBL_OVERWRITE_FILES' => 'Since your last action with this module the following files have changed. What action would you like to take?', + 'ML_LBL_REMOVE_TABLES' => 'Remove Tables', + 'ML_LBL_REVIEWS' => 'Reviews', + 'ML_LBL_SCREENSHOTS' => 'Screenshots', + 'MSG_CONFIG_FILE_READY_FOR_REBUILD' => 'The config.php file is ready for rebuild.', + 'MSG_CONFIG_FILE_REBUILD_FAILED' => 'The config.php could not be rebuilt.', + 'MSG_CONFIG_FILE_REBUILD_SUCCESS' => 'The config.php was successfully rebuilt.', + 'MSG_INCREASE_UPLOAD_MAX_FILESIZE' => 'Warning: Your PHP configuration must be changed to allow files of at least 6MB to be uploaded. Please modify the upload_max_filesize value in your php.ini located at:', + 'MSG_MAKE_CONFIG_FILE_WRITABLE' => 'Please make the config.php writable and try again.', + 'MSG_REBUILD_EXTENSIONS' => 'Please go to the Repair screen and click on Rebuild Extensions.', + 'MSG_REBUILD_RELATIONSHIPS' => 'Please go to the Repair screen and click on Rebuild Relationships.', + 'NO_ENABLED_OFFLINE_CLIENTS' => 'There currently are no enabled Offline Clients.', + 'NTC_DISABLE_OFFLINE_CLIENT_ALERT' => 'Are you sure you want to disable this Offline Client?', + 'NTC_ENABLE_OFFLINE_CLIENT_ALERT' => 'Are you sure you want to enable this Offline Client?', + 'NTC_OC_NOT_AVAILABLE' => 'Not Available', + 'NTC_OC_RESERVED' => 'Reserved', + 'REMOVE_QUESTION' => 'Are you sure you wish to remove the selected package?', + 'WARN_POSSIBLE_JS_OVERWRITE'=>'Caution, this will overwrite any changes you may have made to javascript files, would you like to proceed?', + 'WARN_INSTALLER_LOCKED'=>'Warning: To safeguard your data, the installer must be locked by setting \'installer_locked\' to \'true\' in the config.php file.', + 'WARN_LICENSE_EXPIRED'=> "Notice: Your license expires in ", + 'WARN_LICENSE_EXPIRED2' =>" day(s). Please go to the '\"License Management\" in the Admin screen.", + 'WARN_LICENSE_SEATS'=> "Warning: User licenses exceeded by ", + 'WARN_LICENSE_SEATS2' => ". Please contact your sales representative or email cagroup@sugarcrm.com.", + 'WARN_LICENSE_SEATS_MAXED'=> "Warning: The number of active users is already the maximum number of licenses allowed: ", + 'WARN_LICENSE_SEATS_EDIT_USER'=> "Warning: The number of active users is already the maximum number of licenses allowed", + 'WARN_LICENSE_SEATS_USER_CREATE'=>"Warning: The number of active users allowed by your license matches the number of active users in the system. You will not be able to create additional active users.", + 'WARN_REPAIR_CONFIG' => 'Warning: The config.php file needs to be repaired. Please use the Rebuild Config File script in the Repair page in the Admin area to repair the config file.', + 'WARN_UPGRADE_APP'=> "An updated version of the application is now available. ", + 'WARN_UPGRADE' => 'Warning: Please upgrade ', + 'WARN_UPGRADENOTE' => 'Note: ', + 'WARN_UPGRADE2'=>' using the upgrade in the administration panel', + 'WARN_VALIDATION_EXPIRED'=> "Notice: Your validation key expires in ", + 'WARN_VALIDATION_EXPIRED2' =>" day(s). Please update information in the '\"License Management\" page in the Admin area.", + 'WARN_NO_SMTP_SERVER_AVAILABLE_ERROR' =>"Note: To send record assignment notifications, an SMTP server must be configured in Email Settings.", + 'LBL_MODULEBUILDER'=>'Module Builder', + 'LBL_MODULEBUILDER_DESC'=>'Build new modules to expand the functionality of Sugar', + 'LBL_SUGARPORTAL'=>'Sugar Portal', + 'LBL_SUGARPORTAL_DESC' => 'Manage the Sugar Portal', + 'LBL_CLEAR_TEMPLATE_DATA_CACHE_DESC' => 'Removes cached template files', + 'LBL_CLEAR_TEMPLATE_DATA_CACHE_TITLE'=>'Clear Template Data Cache', + 'LBL_CLEAR_VARDEFS_DATA_CACHE_TITLE'=>'Clear Vardefs Data Cache', + 'LBL_CLEAR_VARDEFS_DATA_CACHE_DESC'=>'Removes vardefs from the cache', + 'LBL_CLEAR_UNIFIED_SEARCH_CACHE_TITLE'=>'Clear Unified Search Cache', + 'LBL_CLEAR_UNIFIED_SEARCH_CACHE_DESC'=>'Removes unified_search_modules.php from the cache', + 'LBL_QUICK_REPAIR_AND_REBUILD'=>'Quick Repair and Rebuild', + 'LBL_QUICK_REPAIR_TITLE'=>'Please select Module(s) to repair:', + 'LBL_FAILED_CONNECTION'=> 'Failed to connect :', + 'LBL_QUICK_REPAIR_AND_REBUILD_DESC'=>'Repairs and rebuilds DB, Extensions, Vardefs, Sugar Dashlets etc.', + 'LBL_ALL_MODULES'=>'All Modules', + 'LBL_CAMPAIGN_CONFIG_TITLE'=>'Campaign Email Settings', + 'LBL_CAMPAIGN_CONFIG_DESC'=>'Configure email settings for campaigns', + 'LBL_REPAIR_ORACLE_FULLTEXT' => 'Rebuild fulltext indices', + 'LBL_REPAIR_ORACLE_FULLTEXT_DESC' => 'Triggers a rebuild of fulltext indices. Oracle 9i owners should run this frequently.', + 'LBL_REPAIR'=>'Repair', + 'LBL_QR_CBOX_DATAB'=> 'Repair Database', + 'LBL_QR_CBOX_CLEARTPL'=> 'Clear .tpl Files', + 'LBL_QR_CBOX_CLEARJS'=> 'Clear Javascript Files', + 'LBL_QR_CBOX_CLEARVARDEFS'=> 'Clear Vardefs', + 'LBL_QR_CBOX_CLEARJSLANG'=> 'Clear Javascript Language Files', + 'LBL_QR_CBOX_CLEARDASHLET'=> 'Clear Sugar Dashlet Cache Data', + 'LBL_QR_CBOX_REBUILDAUDIT'=> 'Rebuild Audit Tables', + 'LBL_QR_CBOX_REBUILDEXT'=> 'Rebuild Extensions', + 'LBL_QR_CBOX_CLEARLANG'=> 'Clear Language Files', + 'LBL_QR_CBOX_CLEARSEARCH'=> 'Clear Unified Search Cache', + 'LBL_QR_REBUILDEXT'=>'

    Rebuilding Extensions...

    ', + 'LBL_QR_CLEARSMARTY'=>'Clearing Smarty templates from cache...done', + 'LBL_QR_XMLFILES'=>'Clearing XML files from cache...done', + 'LBL_QR_CLEARDASHLET'=>'Clearing Sugar Dashlet files from cache...done', + 'LBL_QR_CLEARTEMPLATE'=>'Clearing Template files from cache...done', + 'LBL_QR_CLEARVADEFS'=>'Clearing Vardefs from cache...done', + 'LBL_QR_CLEARJS'=>'Clearing JS files from cache...done', + 'LBL_QR_CLEARJSLANG'=>'Clearing JS Language files from cache...done', + 'LBL_QR_CLEARLANG'=>'Clearing language files from cache...done', + 'LBL_QR_CLEARSEARCH'=>'Clearing Unified Search Cache...done', + 'LBL_QR_REBUILDAUDIT'=>'Rebuilding Audit Tables...', + 'LBL_QR_CBOX_CLEARSUGARFEEDCACHE'=> 'Clear Sugar Feed Cache', + 'LBL_QR_CLEARSUGARFEEDCACHE'=>'Clearing Sugar Feed Cache...done', + 'LBL_QR_CBOX_CLEARTHEMECACHE'=> 'Clear Theme Cache', + 'LBL_QR_CLEARTHEMECACHE'=>'Clearing Theme Cache...done', + 'LBL_REPAIR_DB_FOR'=>'Repairing DB for', + 'LBL_QR_CREATING_TABLE'=>'creating table', + 'LBL_QR_NOT_AUDIT_ENABLED'=>' not Audit Enabled...
    ', + 'LBL_FOR'=>'for', + 'LBL_QR_CBOX_CLEARPDFFONT'=> 'Clear PDF Font Cache File', + 'LBL_QR_CLEARPDFFONT'=>'Clearing PDF Font Cache File...done', + 'LBL_QR_CLEAR_EXT_API'=>'Clearing External API Cache File...done', + 'LBL_TRACKER_SETTINGS' => 'Tracker', + 'LBL_TRACKER_SETTINGS_DESC' => 'Enable/Disable tracking', + 'LBL_REPAIR_SEED_USERS_TITLE' => 'Enable/Disable Seed Users', + 'LBL_REPAIR_SEED_USERS_ACTIVATE' => 'Activate', + 'LBL_REPAIR_SEED_USERS_DECACTIVATE' => 'DeActivate', + 'LBL_REPAIR_SEED_USERS_DESC' => 'Quickly enable or disable seed users populated during demo installation.', + 'LBL_UW_FILES_REMOVED' => "These files will be removed from the system:
    \n", + 'LBL_TEAM_SETS' => 'Clean up unused combinations of teams.', + + 'LBL_MODULE_UPLOAD_DISABLE_HELP_TEXT' => 'New uploads for Module Loader are disabled. Installable modules are restricted to the modules pre-loaded below.', + +'ML_PACKAGE_SCANNING'=> 'Scanning {PACKAGE}', +'ML_INSTALLATION_FAILED'=> 'Installation failed!', +'ML_PACKAGE_NOT_CONFIRM'=> 'The package you are attempting to install does not conform to the policies established within the Sugar Open Cloud or by your system administrator.', +'ML_TO_RESOLVE'=>'To resolve this issue:', +'ML_OBTAIN_NEW_PACKAGE'=>'Sugar Open Cloud customers must obtain a new package from the package provider that addresses the issues described below.', +'ML_RELAX_LOCAL'=>'If you are running Sugar locally, you can relax your Module Loader restrictions to allow the package to be installed.', +'ML_SUGAR_LOADING_POLICY'=>'The Sugar Open Cloud package loading policies are detailed in the', +'ML_SUGAR_KB'=>'SugarCRM Knowledge Base', +'ML_SUGAR_DZ'=>'SugarCRM Developer Zone', +'ML_AVAIL_RESTRICTION'=>'The available restrictions and exceptions are detailed in the', +'ML_OVERRIDE_CORE_FILES'=>'Overriding of core SugarCRM files is not allowed ', +'ML_PATH_MAY_NOT_CONTAIN'=>'File path may not contain', +'ML_INVALID_ACTION_IN_MANIFEST'=>'Invalid action in your manifest:', +'ML_NO_MANIFEST'=>'This package does not contain a manifest', +'ML_INVALID_FUNCTION'=>'Invalid usage of a function ', +'ML_INVALID_EXT'=>'Invalid file extension ', +'ML_ISSUES'=>'Issues', +'ML_MANIFEST_ISSUE'=>'Issue with the manifest', + + 'LBL_ACTIVE_MODULES' => 'Enabled Modules', + 'LBL_DISABLED_MODULES' => 'Disabled Modules', + 'LBL_SAVE_SUCCESS' => '

    Changes Successfully Saved


    You will now be redirected back to the administration home.', + 'LBL_SAVE_FAILED' => 'Save failed.
    Please check your file permissions', + 'LBL_SAVING' => 'Saving...', + 'LBL_ACTIVE_THEMES' => 'Enabled Themes', + 'LBL_DISABLED_THEMES' => 'Disabled Themes', + 'DEFAULT_THEME'=> 'Default theme', + 'LBL_DEFAULT_THEME_IS_DISABLED' => 'The Default Theme you have chosen is disabled. Click "OK" to continue saving the theme changes or "Cancel" to pick a different default theme.', + 'LBL_ENABLED_LANGS' => 'Enabled Languages', + 'LBL_DISABLED_LANGS' => 'Disabled Languages', + + //language changed + 'LBL_CURRENT_LANGUAGE_CHANGE' => 'Your current language is changed to ', + 'LBL_DEFAULT_LANGUAGE_CHANGE' => 'System\'s default language is changed to ', + 'ACLActions' => 'ACLAction', + 'ACLFields' => 'ACLField', + 'ACLRoles' => 'ACLRole', + 'Administration' => 'Administration', + 'Audit' => 'Audit', + 'CampaignTrackers' => 'CampaignTracker', + 'Connectors' => 'Connectors', + 'ContractTypes' => 'ContractType', + 'Currencies' => 'Currency', + 'CustomFields' => 'CustomFields', + 'CustomQueries' => 'CustomQuery', + 'DataSets' => 'DataSet', + 'DocumentRevisions' => 'DocumentRevision', + 'DynamicFields' => 'DynamicField', + 'EditCustomFields' => 'FieldsMetaData', + 'EmailMan' => 'EmailMan', + 'Employees' => 'Employee', + 'Expressions' => 'Expression', + 'Feeds' => 'Feed', + 'ForecastOpportunities' => 'ForecastOpportunities', + 'ForecastSchedule' => 'ForecastSchedule', + 'Groups' => 'Group', + 'Holidays' => 'Holiday', + 'Import_1' => 'ImportMap', + 'Import_2' => 'UsersLastImport', + 'InboundEmail' => 'InboundEmail', + + 'KBContents' => 'KBContent', + 'KBDocumentKBTags' => 'KBDocumentKBTag', + 'KBDocumentRevisions' => 'KBDocumentRevision', + 'KBTags' => 'KBTag', + 'Manufacturers' => 'Manufacturer', + 'ProductBundleNotes' => 'ProductBundleNote', + 'ProductBundles' => 'ProductBundle', + 'ProjectResources' => 'ProjectResource', + + 'Relationships' => 'Relationship', + 'Releases' => 'Release', + 'ReportMaker' => 'Advanced Reports', + 'Reports_1' => 'SavedReport', + 'Roles' => 'Role', + 'Schedulers' => 'Scheduler', + 'SchedulersJobs' => 'SchedulersJob', + 'Shippers' => 'Shipper', + 'TaxRates' => 'TaxRate', + 'TeamHierarchies' => 'TeamHierarchy', + 'TeamMemberships' => 'TeamMembership', + 'TeamNotices' => 'TeamNotice', + 'TeamSetModules' => 'TeamSetModule', + 'TeamSets' => 'TeamSet', + 'TimePeriods' => 'TimePeriod', + 'TrackerPerfs' => 'TrackerPerf', + 'TrackerQueries' => 'TrackerQuery', + 'TrackerSessions'=> 'TrackerSession', + 'UserPreferences' => 'UserPreference', + 'Versions' => 'Version', + 'WorkFlowActions' => 'WorkFlowAction', + 'WorkFlowActionShells' => 'WorkFlowActionShell', + 'WorkFlowAlerts' => 'WorkFlowAlert', + 'WorkFlowAlertShells' => 'WorkFlowAlertShell', + 'WorkFlowTriggerShells' => 'WorkFlowTriggerShell', + 'Worksheet' => 'Worksheet', + 'LBL_SAML_ENABLE' => 'Enable SAML Authentication', + 'LBL_SAML_HELP_TXT' => 'When SAML authentication is enabled, passwords can only be handled through SAML. None of the Sugar Password Management feature settings will apply.', + 'LBL_SAML_TITLE' => 'SAML Authentication', + 'LBL_SAML_CERT' => 'X509 Certificate', + 'LBL_SAML_CERT_DESC' => 'Enter X509 Certificate', + 'LBL_SAML_LOGIN_URL' => 'Login URL', + 'LBL_SAML_LOGIN_URL_DESC' => 'Enter Login URL', + + 'LBL_GLOBAL_SEARCH_SETTINGS_TITLE' => 'Select the module(s) that users will be able to search against using the Global Search.', + 'LBL_SELECT_MODULES' => 'Advanced', + 'LBL_SELECT_MODULES_TITLE' => 'Drag and drop to select modules and to change the display order. Perform a search to apply the changes.', + 'LBL_EAPM_SETTINGS' => 'External Accounts', + 'LBL_EAPM_SETTINGS_DESC' => 'Select external applications for which users can provide their account information in order to access from within Sugar.', + + ); diff --git a/modules/Administration/metadata/SearchFields.php b/modules/Administration/metadata/SearchFields.php new file mode 100644 index 00000000..cc696b69 --- /dev/null +++ b/modules/Administration/metadata/SearchFields.php @@ -0,0 +1,45 @@ + array( + 'query_type'=>'default', + 'operator' => 'subquery', + 'subquery' => 'SELECT users.id FROM users WHERE users.deleted=0 and users.user_name LIKE', + 'db_field'=>array('user_id')), + ); +?> diff --git a/modules/Administration/metadata/adminpaneldefs.php b/modules/Administration/metadata/adminpaneldefs.php new file mode 100644 index 00000000..c390ea82 --- /dev/null +++ b/modules/Administration/metadata/adminpaneldefs.php @@ -0,0 +1,200 @@ +settings['license_latest_versions'])){ + $encodedVersions = $license->settings['license_latest_versions']; + $versions = unserialize(base64_decode( $encodedVersions)); + include('sugar_version.php'); + if(!empty($versions)){ + foreach($versions as $version){ + if($version['version'] > $sugar_version ) + { + $admin_option_defs['Administration']['update'][] ='red'; + if(!isset($admin_option_defs['Administration']['update']['additional_label']))$admin_option_defs['Administration']['update']['additional_label']= '('.$version['version'].')'; + + } + } + } +} + + + +$admin_group_header[]= array('LBL_SUGAR_NETWORK_TITLE','',false,$admin_option_defs, 'LBL_SUGAR_NETWORK_DESC'); + + + +//system. +$admin_option_defs=array(); +$admin_option_defs['Administration']['configphp_settings']= array('Administration','LBL_CONFIGURE_SETTINGS_TITLE','LBL_CONFIGURE_SETTINGS','./index.php?module=Configurator&action=EditView'); +if(!defined('TEMPLATE_URL')){ + $admin_option_defs['Administration']['upgrade_wizard']= array('Upgrade','LBL_UPGRADE_WIZARD_TITLE','LBL_UPGRADE_WIZARD','./index.php?module=UpgradeWizard&action=index'); +} + +$admin_option_defs['Administration']['locale']= array('Currencies','LBL_MANAGE_LOCALE','LBL_LOCALE','./index.php?module=Administration&action=Locale&view=default'); +$admin_option_defs['Administration']['backup_management']= array('Backups','LBL_BACKUPS_TITLE','LBL_BACKUPS','./index.php?module=Administration&action=Backups'); + + +$admin_option_defs['Administration']['currencies_management']= array('Currencies','LBL_MANAGE_CURRENCIES','LBL_CURRENCY','./index.php?module=Currencies&action=index'); +$admin_option_defs['Administration']['repair']= array('Repair','LBL_UPGRADE_TITLE','LBL_UPGRADE','./index.php?module=Administration&action=Upgrade'); + +$admin_option_defs['Administration']['scheduler'] = array('Schedulers','LBL_SUGAR_SCHEDULER_TITLE','LBL_SUGAR_SCHEDULER','./index.php?module=Schedulers&action=index'); +$admin_option_defs['Administration']['diagnostic']= array('Diagnostic','LBL_DIAGNOSTIC_TITLE','LBL_DIAGNOSTIC_DESC','./index.php?module=Administration&action=Diagnostic'); + +// Theme Enable/Disable +$admin_option_defs['Administration']['theme_settings']=array('icon_AdminThemes','LBL_THEME_SETTINGS','LBL_THEME_SETTINGS_DESC','./index.php?module=Administration&action=ThemeSettings'); + +$admin_option_defs['Administration']['feed_settings']=array('icon_SugarFeed','LBL_SUGARFEED_SETTINGS','LBL_SUGARFEED_SETTINGS_DESC','./index.php?module=SugarFeed&action=AdminSettings'); + +// Connector Integration +$admin_option_defs['Administration']['connector_settings']=array('icon_Connectors','LBL_CONNECTOR_SETTINGS','LBL_CONNECTOR_SETTINGS_DESC','./index.php?module=Connectors&action=ConnectorSettings'); + + +//$admin_option_defs['module_loader'] = array('ModuleLoader','LBL_MODULE_LOADER_TITLE','LBL_MODULE_LOADER','./index.php?module=Administration&action=UpgradeWizard&view=module'); + + + + +$admin_option_defs['Administration']['global_search']=array('icon_SearchForm','LBL_GLOBAL_SEARCH_SETTINGS','LBL_GLOBAL_SEARCH_SETTINGS_DESC','./index.php?module=Administration&action=GlobalSearchSettings'); +$admin_option_defs['Administration']['languages']= array('Currencies','LBL_MANAGE_LANGUAGES','LBL_LANGUAGES','./index.php?module=Administration&action=Languages&view=default'); + +$admin_group_header[]= array('LBL_ADMINISTRATION_HOME_TITLE','',false,$admin_option_defs, 'LBL_ADMINISTRATION_HOME_DESC'); + + +//email manager. +$admin_option_defs=array(); +$admin_option_defs['Emails']['mass_Email_config']= array('EmailMan','LBL_MASS_EMAIL_CONFIG_TITLE','LBL_MASS_EMAIL_CONFIG_DESC','./index.php?module=EmailMan&action=config'); +$admin_option_defs['Campaigns']['campaignconfig']= array('Campaigns','LBL_CAMPAIGN_CONFIG_TITLE','LBL_CAMPAIGN_CONFIG_DESC','./index.php?module=EmailMan&action=campaignconfig'); +$admin_option_defs['Emails']['mailboxes']= array('InboundEmail','LBL_MANAGE_MAILBOX','LBL_MAILBOX_DESC','./index.php?module=InboundEmail&action=index'); +$admin_option_defs['Campaigns']['mass_Email']= array('EmailMan','LBL_MASS_EMAIL_MANAGER_TITLE','LBL_MASS_EMAIL_MANAGER_DESC','./index.php?module=EmailMan&action=index'); +$admin_group_header[]= array('LBL_EMAIL_TITLE','',false,$admin_option_defs, 'LBL_EMAIL_DESC'); + +//studio. +$admin_option_defs=array(); +$admin_option_defs['studio']['studio']= array('Studio','LBL_STUDIO','LBL_STUDIO_DESC','./index.php?module=ModuleBuilder&action=index&type=studio'); +if(isset($GLOBALS['beanFiles']['iFrame'])) { + $admin_option_defs['Administration']['portal']= array('iFrames','LBL_IFRAME','DESC_IFRAME','./index.php?module=iFrames&action=index'); +} +$admin_option_defs['Administration']['rename_tabs']= array('RenameTabs','LBL_RENAME_TABS','LBL_CHANGE_NAME_TABS',"./index.php?action=wizard&module=Studio&wizard=StudioWizard&option=RenameTabs"); +$admin_option_defs['Administration']['moduleBuilder']= array('ModuleBuilder','LBL_MODULEBUILDER','LBL_MODULEBUILDER_DESC','./index.php?module=ModuleBuilder&action=index&type=mb'); +$admin_option_defs['Administration']['configure_tabs']= array('ConfigureTabs','LBL_CONFIGURE_TABS_AND_SUBPANELS','LBL_CONFIGURE_TABS_AND_SUBPANELS_DESC','./index.php?module=Administration&action=ConfigureTabs'); + +$admin_option_defs['Administration']['module_loader'] = array('ModuleLoader','LBL_MODULE_LOADER_TITLE','LBL_MODULE_LOADER','./index.php?module=Administration&action=UpgradeWizard&view=module'); +$admin_option_defs['any']['configure_group_tabs']= array('ConfigureTabs','LBL_CONFIGURE_GROUP_TABS','LBL_CONFIGURE_GROUP_TABS_DESC','./index.php?action=wizard&module=Studio&wizard=StudioWizard&option=ConfigureGroupTabs'); + +$admin_option_defs['any']['dropdowneditor']= array('Dropdown','LBL_DROPDOWN_EDITOR','DESC_DROPDOWN_EDITOR','./index.php?module=ModuleBuilder&action=index&type=dropdowns'); + + +//$admin_option_defs['migrate_custom_fields']= array('MigrateFields','LBL_EXTERNAL_DEV_TITLE','LBL_EXTERNAL_DEV_DESC','./index.php?module=Administration&action=Development'); + + +$admin_group_header[]= array('LBL_STUDIO_TITLE','',false,$admin_option_defs, 'LBL_TOOLS_DESC'); + +//bug tracker. +$admin_option_defs=array(); +$admin_option_defs['Bugs']['bug_tracker']= array('Releases','LBL_MANAGE_RELEASES','LBL_RELEASE','./index.php?module=Releases&action=index'); +$admin_group_header[]= array('LBL_BUG_TITLE','',false,$admin_option_defs, 'LBL_BUG_DESC'); + + +if(file_exists('custom/modules/Administration/Ext/Administration/administration.ext.php')){ + require_once('custom/modules/Administration/Ext/Administration/administration.ext.php'); +} + +//For users with MLA access we need to find which entries need to be shown. +//lets process the $admin_group_header and apply all the access control rules. +$access = get_admin_modules_for_user($current_user); +foreach ($admin_group_header as $key=>$values) { + $module_index = array_keys($values[3]); //get the actual links.. + foreach ($module_index as $mod_key=>$mod_val) { + if (is_admin($current_user) || + in_array($mod_val, $access) || + $mod_val=='studio'|| + ($mod_val=='Forecasts' && in_array('ForecastSchedule', $access)) || + ($mod_val =='any') + ) { + if(!is_admin($current_user)&& isset($values[3]['Administration'])){ + unset($values[3]['Administration']); + } + if(displayStudioForCurrentUser() == false) { + unset($values[3]['studio']); + } + + if(displayWorkflowForCurrentUser() == false) { + unset($values[3]['any']['workflow_management']); + } + + // Need this check because Quotes and Products share the header group + if(!in_array('Quotes', $access)&& isset($values[3]['Quotes'])){ + unset($values[3]['Quotes']); + } + if(!in_array('Products', $access)&& isset($values[3]['Products'])){ + unset($values[3]['Products']); + } + + // Need this check because Emails and Campaigns share the header group + if(!in_array('Campaigns', $access)&& isset($values[3]['Campaigns'])){ + unset($values[3]['Campaigns']); + } + + ////////////////// + + } else { + //hide the link + unset($admin_group_header[$key][3][$mod_val]); + } + + } +} +?> diff --git a/modules/Administration/ncc_config.php b/modules/Administration/ncc_config.php new file mode 100644 index 00000000..4e44a308 --- /dev/null +++ b/modules/Administration/ncc_config.php @@ -0,0 +1,38 @@ + '1.2'); +?> diff --git a/modules/Administration/repairDatabase.php b/modules/Administration/repairDatabase.php new file mode 100644 index 00000000..7d7a0360 --- /dev/null +++ b/modules/Administration/repairDatabase.php @@ -0,0 +1,176 @@ +query($stmt,true,'Executing repair query: '); + } + } + + echo "

    {$mod_strings['LBL_REPAIR_DATABASE_SYNCED']}

    "; + } + } else { + + if (!$export && empty ($_REQUEST['repair_silent'])) { + if ( empty($hideModuleMenu) ) + echo getClassicModuleTitle($mod_strings['LBL_REPAIR_DATABASE'], array($mod_strings['LBL_REPAIR_DATABASE']), true); + echo "

    {$mod_strings['LBL_REPAIR_DATABASE_PROCESSING']}

    "; + ob_flush(); + } + + $sql = ''; + + VardefManager::clearVardef(); + $repairedTables = array(); + + foreach ($beanFiles as $bean => $file) { + if(file_exists($file)){ + require_once ($file); + unset($GLOBALS['dictionary'][$bean]); + $focus = new $bean (); + if (($focus instanceOf SugarBean) && !isset($repairedTables[$focus->table_name])) { + $sql .= $db->repairTable($focus, $execute); + $repairedTables[$focus->table_name] = true; + } + //Repair Custom Fields + if (($focus instanceOf SugarBean) && $focus->hasCustomFields() && !isset($repairedTables[$focus->table_name . '_cstm'])) { + $df = new DynamicField($focus->module_dir); + //Need to check if the method exists as during upgrade an old version of Dynamic Fields may be loaded. + if (method_exists($df, "repairCustomFields")) + { + $df->bean = $focus; + $sql .= $df->repairCustomFields($execute); + $repairedTables[$focus->table_name . '_cstm'] = true; + } + } + } + } + + $olddictionary = $dictionary; + + unset ($dictionary); + include ('modules/TableDictionary.php'); + + foreach ($dictionary as $meta) { + $tablename = $meta['table']; + if (isset($repairedTables[$tablename])) continue; + + $fielddefs = $meta['fields']; + $indices = $meta['indices']; + $engine = isset($meta['engine'])?$meta['engine']:null; + $sql .= $db->repairTableParams($tablename, $fielddefs, $indices, $execute, $engine); + $repairedTables[$tablename] = true; + } + + $dictionary = $olddictionary; + + + + if (empty ($_REQUEST['repair_silent'])) { + echo ""; + + if (isset ($sql) && !empty ($sql)) { + + $qry_str = ""; + foreach (explode("\n", $sql) as $line) { + if (!empty ($line) && substr($line, -2) != "*/") { + $line .= ";"; + } + + $qry_str .= $line . "\n"; + } + + $ss = new Sugar_Smarty(); + $ss->assign('MOD', $GLOBALS['mod_strings']); + $ss->assign('qry_str', $qry_str); + echo $ss->fetch('modules/Administration/templates/RepairDatabase.tpl'); + } else { + echo "

    {$mod_strings['LBL_REPAIR_DATABASE_SYNCED']}

    "; + } + } + } + +} else { + sugar_die($GLOBALS['app_strings']['ERR_NOT_ADMIN']); +} \ No newline at end of file diff --git a/modules/Administration/repairSelectModule.php b/modules/Administration/repairSelectModule.php new file mode 100644 index 00000000..73e9859c --- /dev/null +++ b/modules/Administration/repairSelectModule.php @@ -0,0 +1,97 @@ +assign('checkbox_values', $checkbox_values); + $smarty->assign('values', $values); + $smarty->assign('output', $output); + $smarty->assign('MOD', $mod_strings); + $smarty->assign('checkbox_output', $checkbox_output); + $smarty->assign('checkbox_values', $checkbox_values); + $smarty->display("modules/Administration/templates/QuickRepairAndRebuild.tpl"); + + +?> diff --git a/modules/Administration/repairUniSearch.php b/modules/Administration/repairUniSearch.php new file mode 100644 index 00000000..de5f5e5e --- /dev/null +++ b/modules/Administration/repairUniSearch.php @@ -0,0 +1,56 @@ +" ); + print( $mod_strings['LBL_CLEAR_UNIFIED_SEARCH_CACHE_DELETING2'] . " $src_file
    " ) ; + unlink( "$src_file" ); +} + +echo "\n--- " . $mod_strings['LBL_DONE'] . "---
    \n"; +?> \ No newline at end of file diff --git a/modules/Administration/templates/ConfigureTabs.tpl b/modules/Administration/templates/ConfigureTabs.tpl new file mode 100644 index 00000000..61b4e0cc --- /dev/null +++ b/modules/Administration/templates/ConfigureTabs.tpl @@ -0,0 +1,206 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} + + +{overlib_includes} + + + + + + + + "; + $smarty->assign("REPLY_TO", $replyTo); + } + /////////////////////////////////////////////////////////////////////////////// + //// JAVASCRIPT VARS + $jsVars = ''; + $jsVars .= "var showRaw = '{$mod_strings['LBL_BUTTON_RAW_LABEL']}';"; + $jsVars .= "var hideRaw = '{$mod_strings['LBL_BUTTON_RAW_LABEL_HIDE']}';"; + $smarty->assign("JS_VARS", $jsVars); + /////////////////////////////////////////////////////////////////////////////// + //// NOTES (attachements, etc.) + /////////////////////////////////////////////////////////////////////////////// + + $note = new Note(); + $where = "notes.parent_id='{$focus->id}'"; + //take in account if this is from campaign and the template id is stored in the macros. + + if(isset($macro_values) && isset($macro_values['email_template_id'])){ + $where = "notes.parent_id='{$macro_values['email_template_id']}'"; + } + $notes_list = $note->get_full_list("notes.name", $where, true); + + if(! isset($notes_list)) { + $notes_list = array(); + } + + $attachments = ''; + for($i=0; $ifilename,$the_note->id)."\" target=\"_blank\">".$the_note->name.$the_note->description ."
    "; + $attachments .= "id."&type=Notes\">".$the_note->name."
    "; + } + $smarty->assign("ATTACHMENTS", $attachments); + /////////////////////////////////////////////////////////////////////////////// + //// SUBPANELS + /////////////////////////////////////////////////////////////////////////////// + $show_subpanels = true; + if ($show_subpanels) { + require_once('include/SubPanel/SubPanelTiles.php'); + $subpanel = new SubPanelTiles($focus, 'Emails'); + $smarty->assign("SUBPANEL", $subpanel->display()); + } + $meta['html'] = $smarty->fetch("modules/Emails/templates/emailDetailView.tpl"); + return $meta; + + } // fn + + /** + * Sets the "read" flag in the overview cache + */ + function setReadFlag($ieId, $mbox, $uid) { + $this->markEmails('read', $ieId, $mbox, $uid); + } + + /** + * Marks emails with the passed flag type. This will be applied to local + * cache files as well as remote emails. + * @param string $type Flag type + * @param string $ieId + * @param string $folder IMAP folder structure or SugarFolder GUID + * @param string $uids Comma sep list of UIDs or GUIDs + */ + function markEmails($type, $ieId, $folder, $uids) { + + global $app_strings; + $uids = $this->_cleanUIDList($uids); + $exUids = explode($app_strings['LBL_EMAIL_DELIMITER'], $uids); + + if(strpos($folder, 'sugar::') !== false) { + // dealing with a sugar email object, uids are GUIDs + foreach($exUids as $id) { + $email = new Email(); + $email->retrieve($id); + + switch($type) { + case "unread": + $email->status = 'unread'; + $email->save(); + break; + + case "read": + $email->status = 'read'; + $email->save(); + break; + + case "deleted": + $email->delete(); + break; + + case "flagged": + $email->flagged = 1; + $email->save(); + break; + + case "unflagged": + $email->flagged = 0; + $email->save(); + break; + + } + } + } else { + /* dealing with IMAP email, uids are IMAP uids */ + global $ie; // provided by EmailUIAjax.php + if(empty($ie)) { + + $ie = new InboundEmail(); + } + $ie->retrieve($ieId); + $ie->mailbox = $folder; + $ie->connectMailserver(); + // mark cache files + if($type == 'deleted') { + $ie->deleteMessageOnMailServer($uids); + $ie->deleteMessageFromCache($uids); + } else { + $overviews = $ie->getCacheValueForUIDs($ie->mailbox, $exUids); + $manipulated = array(); + + foreach($overviews['retArr'] as $k => $overview) { + if(in_array($overview->uid, $exUids)) { + switch($type) { + case "unread": + $overview->seen = 0; + break; + + case "read": + $overview->seen = 1; + break; + + case "flagged": + $overview->flagged = 1; + break; + + case "unflagged": + $overview->flagged = 0; + break; + } + $manipulated[] = $overview; + } + } + + if(!empty($manipulated)) { + $ie->setCacheValue($ie->mailbox, array(), $manipulated); + /* now mark emails on email server */ + $ie->markEmails(implode(",", explode($app_strings['LBL_EMAIL_DELIMITER'], $uids)), $type); + } + } // end not type == deleted + } + } + +function doAssignment($distributeMethod, $ieid, $folder, $uids, $users) { + global $app_strings; + $users = explode(",", $users); + $emailIds = explode($app_strings['LBL_EMAIL_DELIMITER'], $uids); + $out = ""; + if($folder != 'sugar::Emails') { + $emailIds = array(); + $uids = explode($app_strings['LBL_EMAIL_DELIMITER'], $uids); + $ie = new InboundEmail(); + $ie->retrieve($ieid); + $messageIndex = 1; + // dealing with an inbound email data so we need to import an email and then + foreach($uids as $uid) { + $ie->mailbox = $folder; + $ie->connectMailserver(); + $msgNo = $uid; + if (!$ie->isPop3Protocol()) { + $msgNo = imap_msgno($ie->conn, $uid); + } else { + $msgNo = $ie->getCorrectMessageNoForPop3($uid); + } + + if(!empty($msgNo)) { + if ($ie->importOneEmail($msgNo, $uid)) { + $emailIds[] = $ie->email->id; + $ie->deleteMessageOnMailServer($uid); + //$ie->retrieve($ieid); + //$ie->connectMailserver(); + $ie->mailbox = $folder; + $ie->deleteMessageFromCache(($uids[] = $uid)); + } else { + $out = $out . "Message No : " . $messageIndex . " failed. Reason : Message already imported \r\n"; + } + } + $messageIndex++; + } // for + } // if + + if (count($emailIds) > 0) { + $this->doDistributionWithMethod($users, $emailIds, $distributeMethod); + } // if + return $out; +} // fn + +/** + * get team id and team set id from request + * @return array + */ +function getTeams() { +} + +function doDistributionWithMethod($users, $emailIds, $distributionMethod) { + // we have users and the items to distribute + if($distributionMethod == 'roundRobin') { + $this->distRoundRobin($users, $emailIds); + } elseif($distributionMethod == 'leastBusy') { + $this->distLeastBusy($users, $emailIds); + } elseif($distributionMethod == 'direct') { + if(count($users) > 1) { + // only 1 user allowed in direct assignment + $error = 1; + } else { + $user = $users[0]; + $this->distDirect($user, $emailIds); + } // else + } // elseif + +} // fn + +/** + * distributes emails to users on Round Robin basis + * @param $userIds array of users to dist to + * @param $mailIds array of email ids to push on those users + * @return boolean true on success + */ +function distRoundRobin($userIds, $mailIds) { + // check if we have a 'lastRobin' + $lastRobin = $userIds[0]; + foreach($mailIds as $k => $mailId) { + $userIdsKeys = array_flip($userIds); // now keys are values + $thisRobinKey = $userIdsKeys[$lastRobin] + 1; + if(!empty($userIds[$thisRobinKey])) { + $thisRobin = $userIds[$thisRobinKey]; + $lastRobin = $userIds[$thisRobinKey]; + } else { + $thisRobin = $userIds[0]; + $lastRobin = $userIds[0]; + } + + $email = new Email(); + $email->retrieve($mailId); + $email->assigned_user_id = $thisRobin; + $email->status = 'unread'; + $email->save(); + } + + return true; +} + +/** + * distributes emails to users on Least Busy basis + * @param $userIds array of users to dist to + * @param $mailIds array of email ids to push on those users + * @return boolean true on success + */ +function distLeastBusy($userIds, $mailIds) { + foreach($mailIds as $k => $mailId) { + $email = new Email(); + $email->retrieve($mailId); + foreach($userIds as $k => $id) { + $r = $this->db->query("SELECT count(*) AS c FROM emails WHERE assigned_user_id = '.$id.' AND status = 'unread'"); + $a = $this->db->fetchByAssoc($r); + $counts[$id] = $a['c']; + } + asort($counts); // lowest to highest + $countsKeys = array_flip($counts); // keys now the 'count of items' + $leastBusy = array_shift($countsKeys); // user id of lowest item count + $email->assigned_user_id = $leastBusy; + $email->status = 'unread'; + $email->save(); + } + return true; +} + +/** + * distributes emails to 1 user + * @param $user users to dist to + * @param $mailIds array of email ids to push + * @return boolean true on success + */ +function distDirect($user, $mailIds) { + foreach($mailIds as $k => $mailId) { + $email = new Email(); + $email->retrieve($mailId); + $email->assigned_user_id = $user; + $email->status = 'unread'; + + $email->save(); + } + return true; +} + +function getAssignedEmailsCountForUsers($userIds) { + $counts = array(); + foreach($userIds as $id) { + $r = $this->db->query("SELECT count(*) AS c FROM emails WHERE assigned_user_id = '$id' AND status = 'unread'"); + $a = $this->db->fetchByAssoc($r); + $counts[$id] = $a['c']; + } // foreach + return $counts; +} // fn + +function getLastRobin($ie) { + $lastRobin = ""; + if($this->validCacheFileExists($ie->id, 'folders', "robin.cache.php")) { + $lastRobin = $this->getCacheValue($ie->id, 'folders', "robin.cache.php", 'robin'); + } // if + return $lastRobin; +} // fn + +function setLastRobin($ie, $lastRobin) { + global $sugar_config; + $cacheFolderPath = clean_path("{$sugar_config['cache_dir']}modules/Emails/{$ie->id}/folders"); + if (!file_exists($cacheFolderPath)) { + mkdir_recursive($cacheFolderPath); + } + $this->writeCacheFile('robin', $lastRobin, $ie->id, 'folders', "robin.cache.php"); +} // fn + + /** + * returns the metadata defining a single email message for display. Uses cache file if it exists + * @return array + */ +function getSingleMessage($ie) { + + global $timedate; + global $app_strings,$mod_strings; + $ie->retrieve($_REQUEST['ieId']); + $noCache = true; + + $ie->mailbox = $_REQUEST['mbox']; + $filename = $_REQUEST['mbox'].$_REQUEST['uid'].".php"; + $md5uidl = ""; + if ($ie->isPop3Protocol()) { + $md5uidl = md5($_REQUEST['uid']); + $filename = $_REQUEST['mbox'].$md5uidl.".php"; + } // if + + if($this->validCacheFileExists($_REQUEST['ieId'], 'messages', $filename)) { + $out = $this->getCacheValue($_REQUEST['ieId'], 'messages', $filename, 'out'); + $noCache = false; + + // something fubar'd the cache? + if(empty($out['meta']['email']['name']) && empty($out['meta']['email']['description'])) { + $noCache = true; + } else { + // When sending data from cache, convert date into users preffered format + $dateTimeInGMTFormat = $out['meta']['email']['date_start']; + $out['meta']['email']['date_start'] = $timedate->to_display_date_time($dateTimeInGMTFormat); + } // else + } + + if($noCache) { + $writeToCacheFile = true; + if ($ie->isPop3Protocol()) { + $status = $ie->setEmailForDisplay($_REQUEST['uid'], true, true, true); + } else { + $status = $ie->setEmailForDisplay($_REQUEST['uid'], false, true, true); + } + $out = $ie->displayOneEmail($_REQUEST['uid'], $_REQUEST['mbox']); + // modify the out object to store date in GMT format on the local cache file + $dateTimeInUserFormat = $out['meta']['email']['date_start']; + $out['meta']['email']['date_start'] = $timedate->to_db($dateTimeInUserFormat); + if ($status == 'error') { + $writeToCacheFile = false; + } + if ($writeToCacheFile) { + if ($ie->isPop3Protocol()) { + $this->writeCacheFile('out', $out, $_REQUEST['ieId'], 'messages', "{$_REQUEST['mbox']}{$md5uidl}.php"); + } else { + $this->writeCacheFile('out', $out, $_REQUEST['ieId'], 'messages', "{$_REQUEST['mbox']}{$_REQUEST['uid']}.php"); + } // else + // restore date in the users preferred format to be send on to UI for diaply + $out['meta']['email']['date_start'] = $dateTimeInUserFormat; + } // if + } + $out['meta']['email']['toaddrs'] = $this->generateExpandableAddrs($out['meta']['email']['toaddrs']); + if(!empty($out['meta']['email']['cc_addrs'])) { + $ccs = $this->generateExpandableAddrs($out['meta']['email']['cc_addrs']); + $out['meta']['cc'] = << +
    + + +eoq; + } + + if(empty($out['meta']['email']['description'])) + $out['meta']['email']['description'] = $mod_strings['LBL_EMPTY_EMAIL_BODY']; + + if($noCache) { + $GLOBALS['log']->debug("EMAILUI: getSingleMessage() NOT using cache file"); + } else { + $GLOBALS['log']->debug("EMAILUI: getSingleMessage() using cache file [ ".$_REQUEST['mbox'].$_REQUEST['uid'].".php ]"); + } + + $this->setReadFlag($_REQUEST['ieId'], $_REQUEST['mbox'], $_REQUEST['uid']); + return $out; + } + + + /** + * Returns the HTML for a list of emails in a given folder + * @param GUID $ieId GUID to InboundEmail instance + * @param string $mbox Mailbox path name in dot notation + * @param int $folderListCacheOffset Seconds for valid cache file + * @return string HTML render of list. + */ + function getListEmails($ieId, $mbox, $folderListCacheOffset, $forceRefresh='false') { + global $sugar_config; + + + $ie = new InboundEmail(); + $ie->retrieve($ieId); + $list = $ie->displayFolderContents($mbox, $forceRefresh); + + return $list; + } + + /** + * Returns the templatized compose screen. Used by reply, forwards and draft status messages. + * @param object email Email bean in focus + */ + function displayComposeEmail($email) { + global $locale; + global $current_user; + + + $ea = new SugarEmailAddress(); + + if(!empty($email)) { + $description = (empty($email->description_html)) ? $email->description : $email->description_html; + } + + //Get the most complete address list availible for this email + $addresses = array('toAddresses' => 'to', 'ccAddresses' => 'cc', 'bccAddresses' => 'bcc'); + foreach($addresses as $var => $type) + { + $$var = ""; + foreach (array("{$type}_addrs_names", "{$type}addrs", "{$type}_addrs") as $emailVar) + { + if (!empty($email->$emailVar)) { + $$var = $email->$emailVar; + break; + } + } + } + + $ret = array(); + $ret['type'] = $email->type; + $ret['name'] = $email->name; + $ret['description'] = $description; + $ret['from'] = (isset($_REQUEST['composeType']) && $_REQUEST['composeType'] == 'forward') ? "" : $email->from_addr; + $ret['to'] = from_html($toAddresses); + $ret['uid'] = $email->id; + $ret['parent_name'] = $email->parent_name; + $ret['parent_type'] = $email->parent_type; + $ret['parent_id'] = $email->parent_id; + + // reply all + if(isset($_REQUEST['composeType']) && $_REQUEST['composeType'] == 'replyAll') { + $ret['cc'] = from_html($ccAddresses); + $ret['bcc'] = $bccAddresses; + + $userEmails = array(); + $userEmailsMeta = $ea->getAddressesByGUID($current_user->id, 'Users'); + foreach($userEmailsMeta as $emailMeta) { + $userEmails[] = from_html(strtolower(trim($emailMeta['email_address']))); + } + $userEmails[] = from_html(strtolower(trim($email->from_addr))); + + $ret['cc'] = from_html($email->cc_addrs); + $toAddresses = from_html($toAddresses); + $to = str_replace($this->addressSeparators, "::", $toAddresses); + $exTo = explode("::", $to); + + if(is_array($exTo)) { + foreach($exTo as $addr) { + $addr = strtolower(trim($addr)); + if(!in_array($addr, $userEmails)) { + if(!empty($ret['cc'])) { + $ret['cc'] = $ret['cc'].", "; + } + $ret['cc'] = $ret['cc'].trim($addr); + } + } + } elseif(!empty($exTo)) { + $exTo = trim($exTo); + if(!in_array($exTo, $userEmails)) { + $ret['cc'] = $ret['cc'].", ".$exTo; + } + } + } + return $ret; + } + /** + * Formats email body on reply/forward + * @param object email Email object in focus + * @param string type + * @return object email + */ + function handleReplyType($email, $type) { + global $mod_strings; + $GLOBALS['log']->debug("****At Handle Reply Type: $type"); + switch($type) { + case "reply": + case "replyAll": + $header = $email->getReplyHeader(); + if(!preg_match('/^(re:)+/i', $email->name)) { + $email->name = "{$mod_strings['LBL_RE']} {$email->name}"; + } + if ($type == "reply") { + $email->cc_addrs = ""; + if (!empty($email->reply_to_addr)) { + $email->from_addr = $email->reply_to_addr; + } // if + } else { + if (!empty($email->reply_to_addr)) { + $email->to_addrs = $email->to_addrs . "," . $email->reply_to_addr; + } // if + } // else + break; + + case "forward": + $header = $email->getForwardHeader(); + if(!preg_match('/^(fw:)+/i', $email->name)) { + $email->name = "{$mod_strings['LBL_FW']} {$email->name}"; + } + $email->cc_addrs = ""; + break; + + case "replyCase": + $GLOBALS['log']->debug("EMAILUI: At reply case"); + $header = $email->getReplyHeader(); + + $myCase = new aCase(); + $myCase->retrieve($email->parent_id); + $myCaseMacro = $myCase->getEmailSubjectMacro(); + $email->parent_name = $myCase->name; + $GLOBALS['log']->debug("****Case # : {$myCase->case_number} macro: $myCaseMacro"); + if(!strpos($email->name, str_replace('%1',$myCase->case_number,$myCaseMacro))) { + $GLOBALS['log']->debug("Replacing"); + $email->name = str_replace('%1',$myCase->case_number,$myCaseMacro) . ' '. $email->name; + } + $email->name = "{$mod_strings['LBL_RE']} {$email->name}"; + break; + } + + $html = trim($email->description_html); + $plain = trim($email->description); + + $desc = (!empty($html)) ? $html : $plain; + + $email->description = $header.$email->quoteHtmlEmailForNewEmailUI($desc); + return $email; + + } + + /////////////////////////////////////////////////////////////////////////// + //// PRIVATE HELPERS + /** + * Generates a UNION query to get one list of users, contacts, leads, and + * prospects; used specifically for the addressBook + */ + function _getPeopleUnionQuery($whereArr , $person) { + global $current_user , $app_strings; + global $db; + if(!isset($person) || $person === 'LBL_DROPDOWN_LIST_ALL'){ + $peopleTables = array("users", + "contacts", + "leads", + "prospects", + "accounts" + ); + }else{ + $peopleTables = array($person); + } + $q = ''; + + $whereAdd = ""; + + foreach($whereArr as $column => $clause) { + if(!empty($whereAdd)) { + $whereAdd .= " AND "; + } + $clause = $current_user->db->helper->escape_quote($clause); + $whereAdd .= "{$column} LIKE '{$clause}%'"; + } + + + foreach($peopleTables as $table) { + $module = ucfirst($table); + $class = substr($module, 0, strlen($module) - 1); + require_once("modules/{$module}/{$class}.php"); + $person = new $class(); + if (!$person->ACLAccess('list')) { + continue; + } // if + $where = "({$table}.deleted = 0 AND eabr.primary_address = 1 AND {$table}.id <> '{$current_user->id}')"; + + if (ACLController::requireOwner($module, 'list')) { + $where = $where . " AND ({$table}.assigned_user_id = '{$current_user->id}')"; + } // if + if(!empty($whereAdd)) { + $where .= " AND ({$whereAdd})"; + } + + if ($person === 'accounts') { + $t = "SELECT {$table}.id, '' first_name, {$table}.name, eabr.primary_address, ea.email_address, '{$module}' module "; + } else { + $t = "SELECT {$table}.id, {$table}.first_name, {$table}.last_name, eabr.primary_address, ea.email_address, '{$module}' module "; + } + $t .= "FROM {$table} "; + $t .= "JOIN email_addr_bean_rel eabr ON ({$table}.id = eabr.bean_id and eabr.deleted=0) "; + $t .= "JOIN email_addresses ea ON (eabr.email_address_id = ea.id) "; + $t .= " WHERE {$where}"; + + if(!empty($q)) { + $q .= "\n UNION ALL \n"; + } + + $q .= "({$t})"; + } + $countq = "SELECT count(people.id) c from ($q) people"; + $q .= "ORDER BY last_name"; + + return array('query' => $q, 'countQuery' => $countq); + } + + /** + * get emails of related bean for a given bean id + * @param $beanType + * @param $condition array of conditions inclued bean id + * @return array('query' => $q, 'countQuery' => $countq); + */ + function getRelatedEmail($beanType, $whereArr, $relatedBeanInfoArr = ''){ + global $beanList, $current_user, $app_strings, $db; + $finalQuery = ''; + $searchBeans = null; + if($beanType === 'LBL_DROPDOWN_LIST_ALL') + $searchBeans = array("users", + "contacts", + "leads", + "prospects", + "accounts" + ); + + if ($relatedBeanInfoArr == '' || empty($relatedBeanInfoArr['related_bean_type']) ) + { + if ($searchBeans != null) + { + $q = array(); + foreach ($searchBeans as $searchBean) + { + $searchq = $this->findEmailFromBeanIds('', $searchBean, $whereArr); + if(!empty($searchq)) { + $q[] = "($searchq)"; + } + } + if (!empty($q)) + $finalQuery .= implode("\n UNION ALL \n", $q); + } + else + $finalQuery = $this->findEmailFromBeanIds('', $beanType, $whereArr); + } + else + { + $class = $beanList[$relatedBeanInfoArr['related_bean_type']]; + $focus = new $class(); + $focus->retrieve($relatedBeanInfoArr['related_bean_id']); + if ($searchBeans != null) + { + $q = array(); + foreach ($searchBeans as $searchBean) + { + if ($focus->load_relationship($searchBean)) + { + $data = $focus->$searchBean->get(); + if (count($data) != 0) + $q[] = '('.$this->findEmailFromBeanIds($data, $searchBean, $whereArr).')'; + } + } + if (!empty($q)) + $finalQuery .= implode("\n UNION ALL \n", $q); + } + else + { + if ($focus->load_relationship($beanType)) + { + $data = $focus->$beanType->get(); + if (count($data) != 0) + $finalQuery = $this->findEmailFromBeanIds($data, $beanType, $whereArr); + } + } + } + $countq = "SELECT count(people.id) c from ($finalQuery) people"; + return array('query' => $finalQuery, 'countQuery' => $countq); + } + + function findEmailFromBeanIds($beanIds, $beanType, $whereArr) { + global $current_user; + $q = ''; + $whereAdd = ""; + $relatedIDs = ''; + if ($beanIds != '') { + foreach ($beanIds as $key => $value) { + $beanIds[$key] = '\''.$value.'\''; + } + $relatedIDs = implode(',', $beanIds); + } + + if ($beanType == 'accounts') { + if (isset($whereArr['first_name'])) { + $whereArr['name'] = $whereArr['first_name']; + } + unset($whereArr['last_name']); + unset($whereArr['first_name']); + } + + foreach($whereArr as $column => $clause) { + if(!empty($whereAdd)) { + $whereAdd .= " OR "; + } + $clause = $current_user->db->helper->escape_quote($clause); + $whereAdd .= "{$column} LIKE '{$clause}%'"; + } + $table = $beanType; + $module = ucfirst($table); + $class = substr($module, 0, strlen($module) - 1); + require_once("modules/{$module}/{$class}.php"); + $person = new $class(); + if ($person->ACLAccess('list')) { + if ($relatedIDs != '') { + $where = "({$table}.deleted = 0 AND eabr.primary_address = 1 AND {$table}.id in ($relatedIDs))"; + } else { + $where = "({$table}.deleted = 0 AND eabr.primary_address = 1)"; + } + + if (ACLController::requireOwner($module, 'list')) { + $where = $where . " AND ({$table}.assigned_user_id = '{$current_user->id}')"; + } // if + if(!empty($whereAdd)) { + $where .= " AND ({$whereAdd})"; + } + + if ($beanType === 'accounts') { + $t = "SELECT {$table}.id, '' first_name, {$table}.name last_name, eabr.primary_address, ea.email_address, '{$module}' module "; + } else { + $t = "SELECT {$table}.id, {$table}.first_name, {$table}.last_name, eabr.primary_address, ea.email_address, '{$module}' module "; + } + + $t .= "FROM {$table} "; + $t .= "JOIN email_addr_bean_rel eabr ON ({$table}.id = eabr.bean_id and eabr.deleted=0) "; + $t .= "JOIN email_addresses ea ON (eabr.email_address_id = ea.id) "; + $t .= " WHERE {$where}"; + } // if + return $t; + } + + /** + * Cleans UID lists + * @param mixed $uids + * @param bool $returnString False will return an array + * @return mixed + */ + function _cleanUIDList($uids, $returnString=false) { + global $app_strings; + $GLOBALS['log']->debug("_cleanUIDList: before - [ {$uids} ]"); + + if(!is_array($uids)) { + $returnString = true; + + $exUids = explode($app_strings['LBL_EMAIL_DELIMITER'], $uids); + $uids = $exUids; + } + + $cleanUids = array(); + foreach($uids as $uid) { + $cleanUids[$uid] = $uid; + } + + sort($cleanUids); + + if($returnString) { + $cleanImplode = implode($app_strings['LBL_EMAIL_DELIMITER'], $cleanUids); + $GLOBALS['log']->debug("_cleanUIDList: after - [ {$cleanImplode} ]"); + return $cleanImplode; + } + + return $cleanUids; + } + + /** + * Creates defaults for the User + * @param object $user User in focus + */ + function preflightUser(&$user) { + global $mod_strings; + + $goodToGo = $user->getPreference("email2Preflight", "Emails"); + $q = "SELECT count(*) count FROM folders f where f.created_by = '{$user->id}' AND f.folder_type = 'inbound' AND f.deleted = 0"; + $r = $user->db->query($q); + $a = $user->db->fetchByAssoc($r); + + if($a['count'] < 1) { + require_once("include/SugarFolders/SugarFolders.php"); + // My Emails + $folder = new SugarFolder(); + $folder->new_with_id = true; + $folder->id = create_guid(); + $folder->name = $mod_strings['LNK_MY_INBOX']; + $folder->has_child = 1; + $folder->created_by = $user->id; + $folder->modified_by = $user->id; + $folder->is_dynamic = 1; + $folder->folder_type = "inbound"; + $folder->dynamic_query = $this->generateDynamicFolderQuery('inbound', $user->id); + $folder->save(); + + // My Drafts + $drafts = new SugarFolder(); + $drafts->name = $mod_strings['LNK_MY_DRAFTS']; + $drafts->has_child = 0; + $drafts->parent_folder = $folder->id; + $drafts->created_by = $user->id; + $drafts->modified_by = $user->id; + $drafts->is_dynamic = 1; + $drafts->folder_type = "draft"; + $drafts->dynamic_query = $this->generateDynamicFolderQuery('draft', $user->id); + $drafts->save(); + + + // Sent Emails + $archived = new SugarFolder(); + $archived->name = $mod_strings['LNK_SENT_EMAIL_LIST']; + $archived->has_child = 0; + $archived->parent_folder = $folder->id; + $archived->created_by = $user->id; + $archived->modified_by = $user->id; + $archived->is_dynamic = 1; + $archived->folder_type = "sent"; + $archived->dynamic_query = $this->generateDynamicFolderQuery('sent', $user->id); + $archived->save(); + + // set flag to show that this was run + $user->setPreference("email2Preflight", true, 1, "Emails"); + } + } + + /** + * Parses the core dynamic folder query + * @param string $type 'inbound', 'draft', etc. + * @param string $userId + * @return string + */ + function generateDynamicFolderQuery($type, $userId) { + $q = $this->coreDynamicFolderQuery; + + $status = $type; + + if($type == "sent") { + $type = "out"; + } + + $replacee = array("::TYPE::", "::STATUS::", "::USER_ID::"); + $replacer = array($type, $status, $userId); + + $ret = str_replace($replacee, $replacer, $q); + + if($type == 'inbound') { + $ret .= " AND status NOT IN ('sent', 'archived', 'draft') AND type NOT IN ('out', 'archived', 'draft')"; + } else { + $ret .= " AND status NOT IN ('archived') AND type NOT IN ('archived')"; + } + + return $ret; + } + + /** + * Preps the User's cache dir + */ + function preflightUserCache() { + $path = clean_path($this->userCacheDir); + if(!file_exists($this->userCacheDir)) + mkdir_recursive($path); + + $files = findAllFiles($path, array()); + + foreach($files as $file) { + unlink($file); + } + } + + function clearInboundAccountCache($ieId) { + global $sugar_config; + $cacheRoot = getcwd()."/{$sugar_config['cache_dir']}modules/Emails/{$ieId}"; + $files = findAllFiles($cacheRoot."/messages/", array()); + foreach($files as $file) { + unlink($file); + } // fn + $files = findAllFiles($cacheRoot."/attachments/", array()); + foreach($files as $file) { + unlink($file); + } // for + } // fn + + /** + * returns an array of EmailTemplates that the user has access to for the compose email screen + * @return array + */ + function getEmailTemplatesArray() { + + global $app_strings; + + if(ACLController::checkAccess('EmailTemplates', 'list', true) && ACLController::checkAccess('EmailTemplates', 'view', true)) { + $et = new EmailTemplate(); + $etResult = $et->db->query($et->create_new_list_query('','',array(),array(),'')); + $email_templates_arr = array('' => $app_strings['LBL_NONE']); + while($etA = $et->db->fetchByAssoc($etResult)) { + $email_templates_arr[$etA['id']] = $etA['name']; + } + } else { + $email_templates_arr = array('' => $app_strings['LBL_NONE']); + } + + return $email_templates_arr; + } + + function getFromAccountsArray($ie) { + global $current_user; + global $app_strings; + + $ieAccountsFull = $ie->retrieveAllByGroupIdWithGroupAccounts($current_user->id); + $ieAccountsFrom= array(); + + $oe = new OutboundEmail(); + $system = $oe->getSystemMailerSettings(); + $ret = $current_user->getUsersNameAndEmail(); + $ret['name'] = from_html($ret['name']); + $useMyAccountString = true; + + if(empty($ret['email'])) { + $systemReturn = $current_user->getSystemDefaultNameAndEmail(); + $ret['email'] = $systemReturn['email']; + $ret['name'] = from_html($systemReturn['name']); + $useMyAccountString = false; + } // if + + $myAccountString = ''; + if ($useMyAccountString) { + $myAccountString = " - {$app_strings['LBL_MY_ACCOUNT']}"; + } // if + + //Check to make sure that the user has set the associated inbound email acount -> outbound acount is active. + $showFolders = unserialize(base64_decode($current_user->getPreference('showFolders', 'Emails'))); + $sf = new SugarFolder(); + $groupSubs = $sf->getSubscriptions($current_user); + + foreach($ieAccountsFull as $k => $v) + { + $personalSelected = (!empty($showFolders) && in_array($v->id, $showFolders)); + + $allowOutboundGroupUsage = $v->get_stored_options('allow_outbound_group_usage',FALSE); + $groupSelected = ( in_array($v->groupfolder_id, $groupSubs) && $allowOutboundGroupUsage); + $selected = ( $personalSelected || $groupSelected ); + + if(!$selected) + { + $GLOBALS['log']->debug("Inbound Email {$v->name}, not selected and will not be available for selection within compose UI."); + continue; + } + + $name = $v->get_stored_options('from_name'); + $addr = $v->get_stored_options('from_addr'); + if ($name != null && $addr != null) { + $name = from_html($name); + if (!$v->is_personal) { + $ieAccountsFrom[] = array("value" => $v->id, "text" => "{$name} ({$addr}) - {$app_strings['LBL_EMAIL_UPPER_CASE_GROUP']}"); + } else { + $ieAccountsFrom[] = array("value" => $v->id, "text" => "{$name} ({$addr})"); + } // else + } // if + } // foreach + + + $userSystemOverride = $oe->getUsersMailerForSystemOverride($current_user->id); + //Substitute in the users system override if its available. + if($userSystemOverride != null) + $system = $userSystemOverride; + + if( !empty($system->mail_smtpserver) ) + { + $admin = new Administration(); + $admin->retrieveSettings(); //retrieve all admin settings. + $ieAccountsFrom[] = array("value" => $system->id, "text" => + "{$ret['name']} ({$ret['email']}){$myAccountString}"); + } + + return $ieAccountsFrom; + } // fn + + /** + * This function will return all the accounts this user has access to based on the + * match of the emailId passed in as a parameter + * + * @param unknown_type $ie + * @return unknown + */ + function getFromAllAccountsArray($ie, $ret) { + global $current_user; + global $app_strings; + + $ret['fromAccounts'] = array(); + if (!isset($ret['to']) && !empty($ret['from'])) { + $ret['fromAccounts']['status'] = false; + return $ret; + } + $ieAccountsFull = $ie->retrieveAllByGroupIdWithGroupAccounts($current_user->id); + $foundInPersonalAccounts = false; + $foundInGroupAccounts = false; + $foundInSystemAccounts = false; + + //$toArray = array(); + if ($ret['type'] == "draft") { + $toArray = explode(",", $ret['from']); + } else { + $toArray = $ie->email->email2ParseAddressesForAddressesOnly($ret['to']); + } // else + foreach($ieAccountsFull as $k => $v) { + $storedOptions = unserialize(base64_decode($v->stored_options)); + if ( array_search_insensitive($storedOptions['from_addr'], $toArray)) { + if ($v->is_personal) { + $foundInPersonalAccounts = true; + break; + } else { + $foundInGroupAccounts = true; + } // else + } // if + } // foreach + + $oe = new OutboundEmail(); + $system = $oe->getSystemMailerSettings(); + + $return = $current_user->getUsersNameAndEmail(); + $return['name'] = from_html($return['name']); + $useMyAccountString = true; + + if(empty($return['email'])) { + $systemReturn = $current_user->getSystemDefaultNameAndEmail(); + $return['email'] = $systemReturn['email']; + $return['name'] = from_html($systemReturn['name']); + $useMyAccountString = false; + } // if + + $myAccountString = ''; + if ($useMyAccountString) { + $myAccountString = " - {$app_strings['LBL_MY_ACCOUNT']}"; + } // if + + if(!empty($system->id)) { + + $admin = new Administration(); + $admin->retrieveSettings(); //retrieve all admin settings. + if (in_array(trim($return['email']), $toArray)) { + $foundInSystemAccounts = true; + } // if + } // if + + if (!$foundInPersonalAccounts && !$foundInGroupAccounts && !$foundInSystemAccounts) { + $ret['fromAccounts']['status'] = false; + return $ret; + } // if + + $ieAccountsFrom= array(); + foreach($ieAccountsFull as $k => $v) { + $storedOptions = unserialize(base64_decode($v->stored_options)); + $storedOptionsName = from_html($storedOptions['from_name']); + + $selected = false; + if (array_search_insensitive($storedOptions['from_addr'], $toArray)) { + //if ($ret['to'] == $storedOptions['from_addr']) { + $selected = true; + } // if + if ($foundInPersonalAccounts) { + if ($v->is_personal) { + $ieAccountsFrom[] = array("value" => $v->id, "selected" => $selected, "text" => "{$storedOptionsName} ({$storedOptions['from_addr']})"); + } // if + } else { + $ieAccountsFrom[] = array("value" => $v->id, "selected" => $selected, "text" => "{$storedOptionsName} ({$storedOptions['from_addr']}) - {$app_strings['LBL_EMAIL_UPPER_CASE_GROUP']}"); + } // else + } // foreach + + if(!empty($system->id)) { + if (!$foundInPersonalAccounts && !$foundInGroupAccounts && $foundInSystemAccounts) { + $ieAccountsFrom[] = array("value" => $system->id, "selected" => true, "text" => + "{$return['name']} ({$return['email']}){$myAccountString}"); + } else { + $ieAccountsFrom[] = array("value" => $system->id, "text" => + "{$return['name']} ({$return['email']}){$myAccountString}"); + } // else + } // if + + $ret['fromAccounts']['status'] = ($foundInPersonalAccounts || $foundInGroupAccounts || $foundInSystemAccounts) ? true : false; + $ret['fromAccounts']['data'] = $ieAccountsFrom; + return $ret; + } // fn + + + /** + * takes an array and creates XML + * @param array Array to convert + * @param string Name to wrap highest level items in array + * @return string XML + */ + function arrayToXML($a, $paramName) { + if(!is_array($a)) + return ''; + + $bad = array("<",">","'",'"',"&"); + $good = array("<", ">", "'", ""","&"); + + $ret = ""; + + for($i=0; $i $v) { + $ret .= "\n\t<{$k}>".str_replace($bad, $good, $v).""; + } + $ret .= "\n"; + } + return $ret; + } + + /** + * Re-used option getter for Show Accounts multiselect pane + */ + function getShowAccountsOptions(&$ie) { + global $current_user; + global $app_strings; + global $mod_strings; + + $ieAccountsFull = $ie->retrieveAllByGroupId($current_user->id); + $ieAccountsShowOptionsMeta = array(); + $showFolders = unserialize(base64_decode($current_user->getPreference('showFolders', 'Emails'))); + + $defaultIEAccount = $ie->getUsersDefaultOutboundServerId($current_user); + + foreach($ieAccountsFull as $k => $v) { + $selected = (!empty($showFolders) && in_array($v->id, $showFolders)) ? true : false; + $default = ($defaultIEAccount == $v->id) ? TRUE : FALSE; + $has_groupfolder = !empty($v->groupfolder_id) ? TRUE : FALSE; + $type = ($v->is_personal) ? $mod_strings['LBL_MAILBOX_TYPE_PERSONAL'] : $mod_strings['LBL_MAILBOX_TYPE_GROUP']; + + $ieAccountsShowOptionsMeta[] = array("id" => $v->id, "name" => $v->name, 'is_active' => $selected, + 'server_url' => $v->server_url, 'is_group' => !$v->is_personal,'group_id' => $v->group_id, + 'is_default' => $default, 'has_groupfolder' => $has_groupfolder,'type' => $type ); + } + + //Retrieve the grou folders + $f = new SugarFolder(); + $groupFolders = $f->getGroupFoldersForSettings($current_user); + + foreach ($groupFolders as $singleGroup) + { + //Retrieve the related IE accounts. + $relatedIEAccounts = $ie->retrieveByGroupFolderId($singleGroup['id']); + + if(count($relatedIEAccounts) == 0) + $server_url = $app_strings['LBL_EMAIL_MULT_GROUP_FOLDER_ACCOUNTS_EMPTY']; + else if(count($relatedIEAccounts) == 1) + { + if($relatedIEAccounts[0]->status != 'Active' || $relatedIEAccounts[0]->mailbox_type == 'bounce') + continue; + + $server_url = $relatedIEAccounts[0]->server_url; + } + else + $server_url = $app_strings['LBL_EMAIL_MULT_GROUP_FOLDER_ACCOUNTS']; + + $type = $mod_strings['LBL_MAILBOX_TYPE_GROUP_FOLDER']; + $ieAccountsShowOptionsMeta[] = array("id" => $singleGroup['id'], "name" => $singleGroup['origName'], 'is_active' => $singleGroup['selected'], + 'server_url' => $server_url, 'is_group' => true,'group_id' => $singleGroup['id'], + 'is_default' => FALSE, 'has_groupfolder' => true,'type' => $type); + } + + + return $ieAccountsShowOptionsMeta; + } + + function getShowAccountsOptionsForSearch(&$ie) { + global $current_user; + global $app_strings; + + $ieAccountsFull = $ie->retrieveAllByGroupId($current_user->id); + //$ieAccountsShowOptions = "\n"; + $ieAccountsShowOptionsMeta = array(); + $ieAccountsShowOptionsMeta[] = array("value" => "", "text" => $app_strings['LBL_NONE'], 'selected' => ''); + $showFolders = unserialize(base64_decode($current_user->getPreference('showFolders', 'Emails'))); + + foreach($ieAccountsFull as $k => $v) { + if(!in_array($v->id, $showFolders)) { + continue; + } + $group = (!$v->is_personal) ? $app_strings['LBL_EMAIL_GROUP']."." : ""; + $ieAccountsShowOptionsMeta[] = array("value" => $v->id, "text" => $group.$v->name, 'protocol' => $v->protocol); + } + + return $ieAccountsShowOptionsMeta; + } + /** + * Formats a display message on successful async call + * @param string $type Type of message to display + */ + function displaySuccessMessage($type) { + global $app_strings; + + switch($type) { + case "delete": + $message = $app_strings['LBL_EMAIL_DELETE_SUCCESS']; + break; + + default: + $message = "NOOP: invalid type"; + break; + } + + $this->smarty->assign('app_strings', $app_strings); + $this->smarty->assign('message', $message); + echo $this->smarty->fetch("modules/Emails/templates/successMessage.tpl"); + } + + /** + * Validates existence and expiration of a cache file + * @param string $ieId + * @param string $type Type of cache file: folders, messages, etc. + * @param string $file The cachefile name + * @param int refreshOffset Refresh time in secs. + * @return mixed. + */ + function validCacheFileExists($ieId, $type, $file, $refreshOffset=-1) { + global $sugar_config; + + if($refreshOffset == -1) { + $refreshOffset = $this->cacheTimeouts[$type]; // use defaults + } + + $cacheFilePath = getcwd()."/{$sugar_config['cache_dir']}modules/Emails/{$ieId}/{$type}/{$file}"; + if(file_exists($cacheFilePath)) { + return true; + } + + return false; + } + + /** + * retrieves the cached value + * @param string $ieId + * @param string $type Type of cache file: folders, messages, etc. + * @param string $file The cachefile name + * @param string $key name of cache value + * @return mixed + */ + function getCacheValue($ieId, $type, $file, $key) { + global $sugar_config; + + $cacheFilePath = "{$sugar_config['cache_dir']}modules/Emails/{$ieId}/{$type}/{$file}"; + $cacheFile = array(); + + if(file_exists($cacheFilePath)) { + include($cacheFilePath); // provides $cacheFile + + if(isset($cacheFile[$key])) { + $ret = unserialize($cacheFile[$key]); + return $ret; + } + } else { + $GLOBALS['log']->debug("EMAILUI: cache file not found [ {$cacheFilePath} ] - creating blank cache file"); + $this->writeCacheFile('retArr', array(), $ieId, $type, $file); + } + + return null; + } + + /** + * retrieves the cache file last touched time + * @param string $ieId + * @param string $type Type of cache file: folders, messages, etc. + * @param string $file The cachefile name + * @return string + */ + function getCacheTimestamp($ieId, $type, $file) { + global $sugar_config; + + $cacheFilePath = "{$sugar_config['cache_dir']}modules/Emails/{$ieId}/{$type}/{$file}"; + $cacheFile = array(); + + if(file_exists($cacheFilePath)) { + include($cacheFilePath); // provides $cacheFile['timestamp'] + + if(isset($cacheFile['timestamp'])) { + $GLOBALS['log']->debug("EMAILUI: found timestamp [ {$cacheFile['timestamp']} ]"); + return $cacheFile['timestamp']; + } + } + + return ''; + } + + /** + * Updates the timestamp for a cache file - usually to mark a "check email" + * process + * @param string $ieId + * @param string $type Type of cache file: folders, messages, etc. + * @param string $file The cachefile name + */ + function setCacheTimestamp($ieId, $type, $file) { + global $sugar_config; + + $cacheFilePath = "{$sugar_config['cache_dir']}modules/Emails/{$ieId}/{$type}/{$file}"; + $cacheFile = array(); + + if(file_exists($cacheFilePath)) { + include($cacheFilePath); // provides $cacheFile['timestamp'] + + if(isset($cacheFile['timestamp'])) { + $cacheFile['timestamp'] = strtotime('now'); + $GLOBALS['log']->debug("EMAILUI: setting updated timestamp [ {$cacheFile['timestamp']} ]"); + return $this->_writeCacheFile($cacheFile, $cacheFilePath); + } + } + } + + + /** + * Writes caches to flat file in cache dir. + * @param string $key Key to the main cache entry (not timestamp) + * @param mixed $var Variable to be cached + * @param string $ieId I-E focus ID + * @param string $type Folder in cache + * @param string $file Cache file name + */ + function writeCacheFile($key, $var, $ieId, $type, $file) { + global $sugar_config; + + $the_file = clean_path("{$sugar_config['cache_dir']}/modules/Emails/{$ieId}/{$type}/{$file}"); + $timestamp = strtotime('now'); + $array = array(); + $array['timestamp'] = $timestamp; + $array[$key] = serialize($var); // serialized since varexport_helper() can't handle PHP objects + + return $this->_writeCacheFile($array, $the_file); + } + + /** + * Performs the actual file write. Abstracted from writeCacheFile() for + * flexibility + * @param array $array The array to write to the cache + * @param string $file Full path (relative) with cache file name + * @return bool + */ + function _writeCacheFile($array, $file) { + global $sugar_config; + + $arrayString = var_export_helper($array); + + $date = date("r"); + $the_string =<< +eoq; + if($fh = @sugar_fopen($file, "w")) { + fputs($fh, $the_string); + fclose($fh); + return true; + } else { + $GLOBALS['log']->debug("EMAILUI: Could not write cache file [ {$file} ]"); + return false; + } + } + + /** + * Generate JSON encoded data to be consumed by yui datatable. + * + * @param array $data + * @param string $resultsParam The resultsList name + * @return string + */ + function jsonOuput($data, $resultsParam, $count=0, $fromCache=true, $unread=-1) { + global $app_strings; + + $count = ($count > 0) ? $count : 0; + + if(isset($a['fromCache'])) + $cached = ($a['fromCache'] == 1) ? 1 : 0; + else + $cached = ($fromCache) ? 1 : 0; + + if($data['mbox'] == 'undefined' || empty($data['mbox'])) + $data['mbox'] = $app_strings['LBL_NONE']; + + $jsonOut = array('TotalCount' => $count, 'FromCache' => $cached, 'UnreadCount' => $unread, $resultsParam => $data['out']); + + return json_encode($jsonOut); + } + /** + * generates XML output from an array + * @param array + * @param string master list Item + * @return string + */ + function xmlOutput($a, $paramName, $count=0, $fromCache=true, $unread=-1) { + global $app_strings; + $count = ($count > 0) ? $count : 0; + + if(isset($a['fromCache'])) { + $cached = ($a['fromCache'] == 1) ? 1 : 0; + } else { + $cached = ($fromCache) ? 1 : 0; + } + + if($a['mbox'] == 'undefined' || empty($a['mbox'])) { + $a['mbox'] = $app_strings['LBL_NONE']; + } + + $xml = $this->arrayToXML($a['out'], $paramName); + + $ret =<< + +{$count} +{$unread} + {$cached} +<{$paramName}s> +{$xml} + + +eoq; + return $ret; + } + + /** + * Generate to/cc addresses string in email detailview. + * + * @param string $str + * @param string $target values: to, cc + * @param int $defaultNum + * @return string $str + */ + function generateExpandableAddrs($str) { + global $mod_strings; + $tempStr = $str.','; + $tempStr = html_entity_decode($tempStr); + $tempStr = $this->unifyEmailString($tempStr); + $defaultNum = 2; + $pattern = '/@.*,/U'; + preg_match_all($pattern, $tempStr, $matchs); + $totalCount = count($matchs[0]); + + if(!empty($matchs[0]) && $totalCount > $defaultNum) { + $position = strpos($tempStr, $matchs[0][$defaultNum]); + $hiddenCount = $totalCount - $defaultNum; + $frontStr = substr($tempStr, 0, $position); + $backStr = substr($tempStr, $position, -1); + $str = htmlentities($frontStr) . '...['.$mod_strings['LBL_EMAIL_DETAIL_VIEW_SHOW'].$hiddenCount.$mod_strings['LBL_EMAIL_DETAIL_VIEW_MORE'].']' .htmlentities($backStr).''; + } + + return $str; + } + + /** + * Unify the seperator as , + * + * @param String $str email address string + * @return String converted string + */ + function unifyEmailString($str) { + preg_match_all('/@.*;/U', $str, $matches); + if(!empty($matches[0])) { + foreach($matches[0] as $key => $value) { + $new[] = str_replace(";",",",$value); + } + return str_replace($matches[0], $new, $str); + } + return $str; + } +} // end class def diff --git a/modules/Emails/EmailUIAjax.php b/modules/Emails/EmailUIAjax.php new file mode 100644 index 00000000..3e744a47 --- /dev/null +++ b/modules/Emails/EmailUIAjax.php @@ -0,0 +1,1622 @@ +email2init(); + $ie = new InboundEmail(); + $ie->email = $email; + $json = getJSONobj(); + + + $showFolders = unserialize(base64_decode($current_user->getPreference('showFolders', 'Emails'))); + + switch($_REQUEST['emailUIAction']) { + + + /////////////////////////////////////////////////////////////////////////// + //// COMPOSE REPLY FORWARD + // this is used in forward/reply + case "composeEmail": + $GLOBALS['log']->debug("********** EMAIL 2.0 - Asynchronous - at: composeEmail"); + if(isset($_REQUEST['sugarEmail']) && $_REQUEST['sugarEmail'] == 'true' && isset($_REQUEST['uid']) && !empty($_REQUEST['uid'])) { + $ie->email->retrieve($_REQUEST['uid']); + $ie->email->from_addr = $ie->email->from_addr_name; + $ie->email->to_addrs = to_html($ie->email->to_addrs_names); + $ie->email->cc_addrs = to_html($ie->email->cc_addrs_names); + $ie->email->bcc_addrs = $ie->email->bcc_addrs_names; + $ie->email->from_name = $ie->email->from_addr; + $email = $ie->email->et->handleReplyType($ie->email, $_REQUEST['composeType']); + $ret = $ie->email->et->displayComposeEmail($email); + $ret['description'] = empty($email->description_html) ? str_replace("\n", "\n
    ", $email->description) : $email->description_html; + //get the forward header and add to description + $forward_header = $email->getForwardHeader(); + + $ret['description'] = $forward_header . $ret['description']; + if ($_REQUEST['composeType'] == 'forward') { + $ret = $ie->email->et->getDraftAttachments($ret); + } + $ret = $ie->email->et->getFromAllAccountsArray($ie, $ret); + $ret['from'] = from_html($ret['from']); + $ret['name'] = from_html($ret['name']); + $out = $json->encode($ret, true); + echo $out; + } elseif(isset($_REQUEST['uid']) && !empty($_REQUEST['uid']) && isset($_REQUEST['ieId']) && !empty($_REQUEST['ieId'])) { + $ie->retrieve($_REQUEST['ieId']); + $ie->mailbox = $_REQUEST['mbox']; + global $timedate; + $ie->setEmailForDisplay($_REQUEST['uid']); + $ie->email->date_start = $timedate->to_display_date($ie->email->date_sent); + $ie->email->time_start = $timedate->to_display_time($ie->email->date_sent); + $ie->email->date_sent = $timedate->to_display_date_time($ie->email->date_sent); + $email = $ie->email->et->handleReplyType($ie->email, $_REQUEST['composeType']); + $ret = $ie->email->et->displayComposeEmail($email); + if ($_REQUEST['composeType'] == 'forward') { + $ret = $ie->email->et->createCopyOfInboundAttachment($ie, $ret, $_REQUEST['uid']); + } + $ret = $ie->email->et->getFromAllAccountsArray($ie, $ret); + $ret['from'] = from_html($ret['from']); + $ret['name'] = from_html($ret['name']); + $ret['ieId'] = $_REQUEST['ieId']; + $ret['mbox'] = $_REQUEST['mbox']; + $out = $json->encode($ret, true); + echo $out; + } + break; + + /** + * sendEmail handles both send and save draft duties + */ + case "sendEmail": + $GLOBALS['log']->debug("********** EMAIL 2.0 - Asynchronous - at: sendEmail"); + + + $sea = new SugarEmailAddress(); + + $email->type = 'out'; + $email->status = 'sent'; + + if(isset($_REQUEST['email_id']) && !empty($_REQUEST['email_id'])) {// && isset($_REQUEST['saveDraft']) && !empty($_REQUEST['saveDraft'])) { + $email->retrieve($_REQUEST['email_id']); // uid is GUID in draft cases + } + if (isset($_REQUEST['uid']) && !empty($_REQUEST['uid'])) { + $email->uid = $_REQUEST['uid']; + } + + if ($email->email2Send($_REQUEST)) { + $ret = array( + 'composeLayoutId' => $_REQUEST['composeLayoutId'], + ); + $out = $json->encode($ret, true); + echo $out; // async call to close the proper compose tab + } + break; + + case "uploadAttachment": + $GLOBALS['log']->debug("********** EMAIL 2.0 - Asynchronous - at: uploadAttachment"); + $metadata = $email->email2saveAttachment(); + + if(!empty($metadata)) { + $out = $json->encode($metadata); + echo $out; + } + break; + + case "removeUploadedAttachment": + $GLOBALS['log']->debug("********** EMAIL 2.0 - Asynchronous - at: removeUploadedAttachment"); + $fileFromRequest = from_html($_REQUEST['file']); + $fileGUID = substr($fileFromRequest, 0, 36); + $fileName = $email->et->userCacheDir . "/" . $fileGUID; + $filePath = clean_path($fileName); + unlink($filePath); + break; + + case "fillComposeCache": // fills client-side compose email cache with signatures and email templates + $GLOBALS['log']->debug("********** EMAIL 2.0 - Asynchronous - at: fillComposeCache"); + $out = array(); + $email_templates_arr = $email->et->getEmailTemplatesArray(); + natcasesort($email_templates_arr); + $out['emailTemplates'] = $email_templates_arr; + $sigs = $current_user->getSignaturesArray(); + // clean "none" + foreach($sigs as $k => $v) { + if($k == "") { + $sigs[$k] = $app_strings['LBL_NONE']; + } else if (is_array($v) && isset($v['name'])){ + $sigs[$k] = $v['name']; + } else{ + $sigs[$k] = $v; + } + } + $out['signatures'] = $sigs; + $out['fromAccounts'] = $email->et->getFromAccountsArray($ie); + $out['errorArray'] = array(); + + $oe = new OutboundEmail(); + if( $oe->doesUserOverrideAccountRequireCredentials($current_user->id) ) + { + $overideAccount = $oe->getUsersMailerForSystemOverride($current_user->id); + //If the user override account has not been created yet, create it for the user. + if($overideAccount == null) + $overideAccount = $oe->createUserSystemOverrideAccount($current_user->id); + + $out['errorArray'] = array($overideAccount->id => $app_strings['LBL_EMAIL_WARNING_MISSING_USER_CREDS']); + } + + $ret = $json->encode($out); + echo $ret; + break; + + case "getSignature": + $GLOBALS['log']->debug("********** EMAIL 2.0 - Asynchronous - at: getSignature"); + if(isset($_REQUEST['id'])) { + $signature = $current_user->getSignature($_REQUEST['id']); + $signature['signature_html'] = from_html($signature['signature_html']); + $out = $json->encode($signature); + echo $out; + } else { + die(); + } + break; + + case "deleteSignature": + $GLOBALS['log']->debug("********** EMAIL 2.0 - Asynchronous - at: deleteSignature"); + if(isset($_REQUEST['id'])) { + require_once("modules/Users/UserSignature.php"); + $us = new UserSignature(); + $us->mark_deleted($_REQUEST['id']); + $signatureArray = $current_user->getSignaturesArray(); + // clean "none" + foreach($signatureArray as $k => $v) { + if($k == "") { + $sigs[$k] = $app_strings['LBL_NONE']; + } else if (is_array($v) && isset($v['name'])){ + $sigs[$k] = $v['name']; + } else{ + $sigs[$k] = $v; + } + } + $out['signatures'] = $signatureArray; + $ret = $json->encode($out); + echo $ret; + } else { + die(); + } + break; + case "getTemplateAttachments": + $GLOBALS['log']->debug("********** EMAIL 2.0 - Asynchronous - at: getTemplateAttachments"); + if(isset($_REQUEST['parent_id']) && !empty($_REQUEST['parent_id'])) { + + + $where = "parent_id='{$_REQUEST['parent_id']}'"; + $order = ""; + $seed = new Note(); + $fullList = $seed->get_full_list($order, $where, ''); + $all_fields = array_merge($seed->column_fields, $seed->additional_column_fields); + + $js_fields_arr = array(); + + $i=1; // js doesn't like 0 index? + if (!empty($fullList)) { + foreach($fullList as $note) { + $js_fields_arr[$i] = array(); + + foreach($all_fields as $field) { + if(isset($note->$field)) { + $note->$field = from_html($note->$field); + $note->$field = preg_replace('/\r\n/','
    ',$note->$field); + $note->$field = preg_replace('/\n/','
    ',$note->$field); + $js_fields_arr[$i][$field] = addslashes($note->$field); + } + } + $i++; + } + } + + $out = $json->encode($js_fields_arr); + echo $out; + } + break; + //// END COMPOSE REPLY FORWARD + /////////////////////////////////////////////////////////////////////////// + + + + /////////////////////////////////////////////////////////////////////////// + //// MESSAGE HANDLING + case "displayView": + $ret = array(); + $ie->retrieve($_REQUEST['ieId']); + $ie->mailbox = $_REQUEST['mailbox']; + $ie->connectMailserver(); + + switch($_REQUEST['type']) { + case "headers": + $title = "{$app_strings['LBL_EMAIL_VIEW_HEADERS']}"; + $text = $ie->getFormattedHeaders($_REQUEST['uid']); + break; + + case "raw": + $title = "{$app_strings['LBL_EMAIL_VIEW_RAW']}"; + $text = $ie->getFormattedRawSource($_REQUEST['uid']); + break; + + case "printable": + + break; + } + + $ret['html'] = $text; + $ret['title'] = $title; + + $out = $json->encode($ret, true); + echo $out; + break; + + case "getQuickCreateForm": + $GLOBALS['log']->debug("********** EMAIL 2.0 - Asynchronous - at: getQuickCreateForm"); + if(isset($_REQUEST['qc_module']) && !empty($_REQUEST['qc_module'])) { + if (!ACLController::checkAccess($_REQUEST['qc_module'],'edit', true)) { + echo trim($json->encode(array('html' => translate('LBL_NO_ACCESS', 'ACL')), true)); + break; + } + $people = array("Users", "Contacts", "Leads", "Prospects"); + $showSaveToAddressBookButton = false;//(in_array($_REQUEST['qc_module'], $people)) ? true : false; + + if(isset($_REQUEST['sugarEmail']) && !empty($_REQUEST['sugarEmail'])) { + $ie->email->retrieve($_REQUEST['uid']); // uid is a sugar GUID in this case + } else { + $ie->retrieve($_REQUEST['ieId']); + $ie->mailbox = $_REQUEST['mailbox']; + $ie->setEmailForDisplay($_REQUEST['uid']); + } + $ret = $email->et->getQuickCreateForm($_REQUEST, $ie->email, $showSaveToAddressBookButton); + $ret['ieId'] = $_REQUEST['ieId']; + $ret['mbox'] = $_REQUEST['mailbox']; + $ret['uid'] = $_REQUEST['uid']; + $ret['module'] = $_REQUEST['qc_module']; + if (!isset($_REQUEST['iframe'])) { + $out = trim($json->encode($ret, false)); + } else { + $out = $ret['html']; + } + echo $out; + } + break; + + case 'saveQuickCreate': + $GLOBALS['log']->debug("********** EMAIL 2.0 - Asynchronous - at: saveQuickCreate"); + require_once('include/MVC/Controller/ControllerFactory.php'); + if (isset($_REQUEST['qcmodule'])) { + $GLOBALS['log']->debug("********** QCmodule was set: {$_REQUEST['qcmodule']}"); + } + $controller = ControllerFactory::getController($_REQUEST['qcmodule']); + $controller->loadBean(); + $controller->pre_save(); + $GLOBALS['log']->debug("********** saving new {$controller->module}"); + $controller->action_save(); + //Relate the email to the new bean + if(isset($_REQUEST['sugarEmail']) && $_REQUEST['sugarEmail'] == 'true' && isset($_REQUEST['uid']) && !empty($_REQUEST['uid'])) { + $ie->email->retrieve($_REQUEST['uid']); + } elseif(isset($_REQUEST['uid']) && !empty($_REQUEST['uid']) && isset($_REQUEST['ieId']) && !empty($_REQUEST['ieId'])) { + $GLOBALS['log']->debug("********** Quick Create from non-imported message"); + $ie->retrieve($_REQUEST['ieId']); + $ie->mailbox = $_REQUEST['mbox']; + $ie->connectMailserver(); + $uid = $_REQUEST['uid']; + if($ie->protocol == 'imap') { + $_REQUEST['uid'] = imap_msgno($ie->conn, $_REQUEST['uid']); + } else { + $_REQUEST['uid'] = $ie->getCorrectMessageNoForPop3($_REQUEST['uid']); + } + + if (!$ie->importOneEmail($_REQUEST['uid'], $uid)) { + $ie->getDuplicateEmailId($_REQUEST['uid'], $uid); + } // id + $ie->email->retrieve($ie->email->id); + $GLOBALS['log']->debug("**********Imported Email"); + $ie->email->assigned_user_id = $controller->bean->assigned_user_id; + $ie->email->assigned_user_name = $controller->bean->assigned_user_name; + } + if (isset($ie->email->id)) { + if (empty($ie->email->parent_id)) { + $ie->email->parent_id = $controller->bean->id; + $ie->email->parent_type = $controller->module; + } // if + $ie->email->status = 'read'; + $ie->email->save(); + $mod = strtolower($controller->module); + $ie->email->load_relationship($mod); + $ie->email->$mod->add($controller->bean->id); + if($controller->bean->load_relationship('emails')) { + $controller->bean->emails->add($ie->email->id); + } + if ($controller->bean->module_dir == 'Cases') { + if($controller->bean->load_relationship('contacts')) { + $emailAddressWithName = $ie->email->from_addr_name; + if (!empty($ie->email->reply_to_addr)) { + $emailAddressWithName = $ie->email->reply_to_addr; + } // if + + $emailAddress = SugarEmailAddress::_cleanAddress($emailAddressWithName); + $contactIds = $ie->email->emailAddress->getRelatedId($emailAddress, 'contacts'); + if (!empty($contactIds)) { + $controller->bean->contacts->add($contactIds); + } // if + } // if + } // if + echo $json->encode(array('id' => $ie->email->id)); + } + break; + + case "getImportForm": + $ie->retrieve($_REQUEST['ieId']); + // $ie->mailbox = $_REQUEST['mailbox']; + $ie->setEmailForDisplay($_REQUEST['uid']); + $ret = $email->et->getImportForm($_REQUEST, $ie->email); + $out = trim($json->encode($ret, false)); + echo $out; + break; + + case "getRelateForm": + if (isset($_REQUEST['uid']) && !empty($_REQUEST['uid'])) { + $uids = $json->decode(from_html($_REQUEST['uid'])); + $email->retrieve($uids[0]); + $ret = $email->et->getImportForm(array('showTeam' => false, 'showAssignTo' => false, 'showDelete' => false), $email,'RelateEditView'); + $out = trim($json->encode($ret, false)); + echo $out; + } + break; + + case "getEmail2DetailView": + if (isset($_REQUEST['uid']) && !empty($_REQUEST['uid'])) { + $ret = $email->et->getDetailViewForEmail2($_REQUEST['uid']); + if( !isset($_REQUEST['print']) || $_REQUEST['print'] === FALSE) + { + $out = trim($json->encode($ret, false)); + echo $out; + } + else + echo $ret['html']; + + } + break; + + case "relateEmails": + if (isset($_REQUEST['uid']) && !empty($_REQUEST['uid']) && + isset($_REQUEST['parent_id']) && !empty($_REQUEST['parent_id']) && + isset($_REQUEST['parent_type']) && !empty($_REQUEST['parent_type'])) { + $uids = explode($app_strings['LBL_EMAIL_DELIMITER'], $_REQUEST['uid']); + $mod = strtolower($_REQUEST['parent_type']); + $modId = $_REQUEST['parent_id']; + foreach($uids as $id) { + $email = new Email(); + $email->retrieve($id); + $email->parent_id = $modId; + $email->parent_type = $_REQUEST['parent_type']; + $email->status = 'read'; + $email->save(); + $email->load_relationship($mod); + $email->$mod->add($modId); + } + } + break; + + + case "getAssignmentDialogContent": + $out = $email->distributionForm(""); + $out = trim($json->encode($out, false)); + echo $out; + break; + case "doAssignmentAssign": + $out = $email->et->doAssignment($_REQUEST['distribute_method'], $_REQUEST['ieId'], $_REQUEST['folder'], $_REQUEST['uids'], $_REQUEST['users']); + echo $out; + break; + case "doAssignmentDelete"; + $GLOBALS['log']->debug("********** EMAIL 2.0 - Asynchronous - at: doAssignmentDelete"); + if(isset($_REQUEST['uids']) && !empty($_REQUEST['uids']) && + isset($_REQUEST['ieId']) && !empty($_REQUEST['ieId']) && + isset($_REQUEST['folder']) && !empty($_REQUEST['folder'])) { + $email->et->markEmails("deleted", $_REQUEST['ieId'], $_REQUEST['folder'], $_REQUEST['uids']); + } else { + } + break; + case "markEmail": + global $app_strings; + $GLOBALS['log']->debug("********** EMAIL 2.0 - Asynchronous - at: markEmail"); + if(isset($_REQUEST['uids']) && !empty($_REQUEST['uids']) && + isset($_REQUEST['type']) && !empty($_REQUEST['type']) && + isset($_REQUEST['ieId']) && !empty($_REQUEST['ieId']) && + isset($_REQUEST['folder']) && !empty($_REQUEST['folder'])) { + $uid = $json->decode(from_html($_REQUEST['uids'])); + $uids = array(); + if(is_array($uid)) { + $uids = $uid; + } else { + if(strpos($uid, $app_strings['LBL_EMAIL_DELIMITER']) !== false) { + $uids = explode($app_strings['LBL_EMAIL_DELIMITER'], $uid); + } else { + $uids[] = $uid; + } + } // else + $uids = implode($app_strings['LBL_EMAIL_DELIMITER'], $uids); + $GLOBALS['log']->debug("********** EMAIL 2.0 - Marking emails $uids as {$_REQUEST['type']}"); + + $ret = array(); + if(strpos($_REQUEST['folder'], 'sugar::') !== false && ($_REQUEST['type'] == 'deleted') && !ACLController::checkAccess('Emails', 'delete')) { + $ret['status'] = false; + $ret['message'] = $app_strings['LBL_EMAIL_DELETE_ERROR_DESC']; + } else { + $email->et->markEmails($_REQUEST['type'], $_REQUEST['ieId'], $_REQUEST['folder'], $uids); + $ret['status'] = true; + } + $out = trim($json->encode($ret, false)); + echo $out; + } else { + } + break; + + case "checkEmail2": + $GLOBALS['log']->debug("********** EMAIL 2.0 - Asynchronous - at: checkEmail2"); + + $showFolders = unserialize(base64_decode($current_user->getPreference('showFolders', 'Emails'))); + + $ret = array(); + $ret['numberAccounts'] = count($showFolders); + + $GLOBALS['log']->info("EMAIL2.0: async checkEmail - found [ ".$ret['numberAccounts']." ] accounts to check"); + + if(!empty($showFolders) && is_array($showFolders)) { + foreach($showFolders as $ieId) { + $ieId = trim($ieId); + + if(!empty($ieId)) { + $GLOBALS['log']->info("INBOUNDEMAIL: trying to check email for GUID [ {$ieId} ]"); + $ie->disconnectMailserver(); + $ie->retrieve($ieId); + + $ret[$ieId] = $ie->checkEmail2_meta(); + } + } + } else { + $GLOBALS['log']->info("EMAIL2.0: at checkEmail() async call - not subscribed accounts to check."); + } + + + + $out = $json->encode($ret, true); + echo $out; + break; + + case "checkEmail": + $GLOBALS['log']->info("[EMAIL] - Start checkEmail action for user [{$current_user->user_name}]"); + if(isset($_REQUEST['ieId']) && !empty($_REQUEST['ieId'])) { + $ie->retrieve($_REQUEST['ieId']); + $ie->mailbox = (isset($_REQUEST['mbox']) && !empty($_REQUEST['mbox'])) ? $_REQUEST['mbox'] : "INBOX"; + $ie->checkEmail(false); + } elseif(isset($_REQUEST['all']) && !empty($_REQUEST['all'])) { + $showFolders = unserialize(base64_decode($current_user->getPreference('showFolders', 'Emails'))); + + $GLOBALS['log']->info("[EMAIL] - checkEmail found ".count($showFolders)." accounts to check for user [{$current_user->user_name}]"); + + if(!empty($showFolders) && is_array($showFolders)) { + foreach($showFolders as $ieId) { + $ieId = trim($ieId); + if(!empty($ieId)) { + $GLOBALS['log']->info("[EMAIL] - Start checking email for GUID [{$ieId}] for user [{$current_user->user_name}]"); + $ie->disconnectMailserver(); + $ie->retrieve($ieId); + $ie->checkEmail(false); + $GLOBALS['log']->info("[EMAIL] - Done checking email for GUID [{$ieId}] for user [{$current_user->user_name}]"); + } + } + } else { + $GLOBALS['log']->info("EMAIL2.0: at checkEmail() async call - not subscribed accounts to check."); + } + } + + $tree = $email->et->getMailboxNodes(true); // preserve cache files + $return = $tree->generateNodesRaw(); + $out = $json->encode($return); + echo $out; + $GLOBALS['log']->info("[EMAIL] - Done checkEmail action for user [{$current_user->user_name}]"); + break; + + case "checkEmailProgress": + $GLOBALS['log']->info("[EMAIL] - Start checkEmail action for user [{$current_user->user_name}]"); + if(isset($_REQUEST['ieId']) && !empty($_REQUEST['ieId'])) { + $ie->retrieve($_REQUEST['ieId']); + $ie->mailbox = (isset($_REQUEST['mbox']) && !empty($_REQUEST['mbox'])) ? $_REQUEST['mbox'] : "INBOX"; + $synch = (isset($_REQUEST['synch']) && ($_REQUEST['synch'] == "true")); + if (!$ie->is_personal) { + $return = array('status' => "done"); + } else { + if ($ie->protocol == "pop3") { + $return = $ie->pop3_checkPartialEmail($synch); + } else { + $return = $ie->checkEmailIMAPPartial(false, $synch); + } // else + } // if + $return['ieid'] = $ie->id; + $return['synch'] = $synch; + if(isset($_REQUEST['totalcount']) && !empty($_REQUEST['totalcount']) && $_REQUEST['totalcount'] >= 0) { + if ($ie->protocol == "pop3") { + $return['totalcount'] = $_REQUEST['totalcount']; + } // else + } + echo $json->encode($return); + } // if + break; + + case "getAllFoldersTree": + $tree = $email->et->getMailboxNodes(true); // preserve cache files + $return = $tree->generateNodesRaw(); + $out = $json->encode($return); + echo $out; + $GLOBALS['log']->info("[EMAIL] - Done checkEmail action for user [{$current_user->user_name}]"); + break; + + case "synchronizeEmail": + $GLOBALS['log']->info("[EMAIL] Start action synchronizeEmail for user [{$current_user->user_name}]"); + $ie->syncEmail(true); + $tree = $email->et->getMailboxNodes(true); + $return = $tree->generateNodesRaw(); + $out = $json->encode($return); + echo $out; + $GLOBALS['log']->info("[EMAIL] Done action synchronizeEmail for user [{$current_user->user_name}]"); + break; + + case "importEmail": + $GLOBALS['log']->debug("********** EMAIL 2.0 - Asynchronous - at: importEmail"); + $ie->retrieve($_REQUEST['ieId']); + $ie->mailbox = $_REQUEST['mbox']; + $ie->connectMailserver(); + $return = array(); + $status = true; + $count = 1; + if(strpos($_REQUEST['uid'], $app_strings['LBL_EMAIL_DELIMITER']) !== false) { + $exUids = explode($app_strings['LBL_EMAIL_DELIMITER'], $_REQUEST['uid']); + foreach($exUids as $msgNo) { + $uid = $msgNo; + if($ie->protocol == 'imap') { + $msgNo = imap_msgno($ie->conn, $msgNo); + $status = $ie->importOneEmail($msgNo, $uid); + } else { + $status = $ie->importOneEmail($ie->getCorrectMessageNoForPop3($msgNo), $uid); + } // else + $return[] = $app_strings['LBL_EMAIL_MESSAGE_NO'] . " " . $count . ", " . $app_strings['LBL_STATUS'] . " " . ($status ? $app_strings['LBL_EMAIL_IMPORT_SUCCESS'] : $app_strings['LBL_EMAIL_IMPORT_FAIL']); + $count++; + if(($_REQUEST['delete'] == 'true') && $status && ($current_user->is_admin == 1 || $ie->group_id == $current_user->id)) { + $ie->deleteMessageOnMailServer($uid); + $ie->deleteMessageFromCache($uid); + } // if + } // for + } else { + $msgNo = $_REQUEST['uid']; + if($ie->protocol == 'imap') { + $msgNo = imap_msgno($ie->conn, $_REQUEST['uid']); + $status = $ie->importOneEmail($msgNo, $_REQUEST['uid']); + } else { + $status = $ie->importOneEmail($ie->getCorrectMessageNoForPop3($msgNo), $_REQUEST['uid']); + } // else + $return[] = $app_strings['LBL_EMAIL_MESSAGE_NO'] . " " . $count . ", " . $app_strings['LBL_STATUS'] . " " . ($status ? $app_strings['LBL_EMAIL_IMPORT_SUCCESS'] : $app_strings['LBL_EMAIL_IMPORT_FAIL']); + + if(($_REQUEST['delete'] == 'true') && $status && ($current_user->is_admin == 1 || $ie->group_id == $current_user->id)) { + $ie->deleteMessageOnMailServer($_REQUEST['uid']); + $ie->deleteMessageFromCache($_REQUEST['uid']); + } // if + } // else + echo $json->encode($return); + break; + + case "setReadFlag": + $GLOBALS['log']->debug("********** EMAIL 2.0 - Asynchronous - at: setReadFlag"); + $ie->retrieve($_REQUEST['ieId']); + $ie->setReadFlagOnFolderCache($_REQUEST['mbox'], $_REQUEST['uid']); + $email->et->getListEmails($_REQUEST['ieId'], $_REQUEST['mbox'], 0, 'true'); + //unlink("{$cacheRoot}/{$_REQUEST['ieId']}/folders/{$_REQUEST['mbox']}.php"); + break; + + case "deleteMessage": + $GLOBALS['log']->debug("********** EMAIL 2.0 - Asynchronous - at: deleteMessage"); + if(isset($_REQUEST['uid']) && !empty($_REQUEST['uid']) && isset($_REQUEST['ieId']) && !empty($_REQUEST['ieId'])) { + $ie->retrieve($_REQUEST['ieId']); + $ie->mailbox = $_REQUEST['mbox']; + + if($current_user->is_admin == 1 || $ie->group_id == $current_user->id) { + $ie->deleteMessageOnMailServer($_REQUEST['uid']); + $ie->deleteMessageFromCache($_REQUEST['uid']); + } else { + $GLOBALS['log']->debug("*** ERROR: tried to delete an email for an account for which {$current_user->full_name} is not the owner!"); + echo "NOOP: error see log"; + } + } else { + echo "error: missing credentials"; + } + break; + + case "getSingleMessage": + $GLOBALS['log']->debug("********** EMAIL 2.0 - Asynchronous - at: getSingleMessage"); + if(isset($_REQUEST['uid']) && !empty($_REQUEST['uid']) && isset($_REQUEST['ieId']) && !empty($_REQUEST['ieId'])) { + $out = $email->et->getSingleMessage($ie); + echo $json->encode($out); + } else { + echo "error: no UID"; + } + break; + + case "getSingleMessageFromSugar": + $GLOBALS['log']->debug("********** EMAIL 2.0 - Asynchronous - at: getSingleMessageFromSugar"); + if(isset($_REQUEST['uid']) && !empty($_REQUEST['uid'])) { + $email->retrieve($_REQUEST['uid']); + //$email->description_html = from_html($email->description_html); + $ie->email = $email; + + if($email->status == 'draft' || $email->type == 'draft') { + // forcing an editview since we are looking at a draft message + global $current_user; + $ret = $ie->email->et->displayComposeEmail($email); + + $ret = $ie->email->et->getDraftAttachments($ret, $ie); + $ret = $ie->email->et->getFromAllAccountsArray($ie, $ret); + + + $out = $json->encode($ret, true); + echo $out; + } else { + $out = $ie->displayOneEmail($_REQUEST['uid'], $_REQUEST['mbox']); + $out['meta']['email']['description'] = + empty($email->description_html) ? str_replace("\n", "\n
    ", $email->description) : $email->description_html; + $out['meta']['email']['date_start'] = $email->date_start; + $out['meta']['email']['time_start'] = $email->time_start; + $out['meta']['ieId'] = $_REQUEST['ieId']; + $out['meta']['mbox'] = $_REQUEST['mbox']; + $out['meta']['email']['toaddrs'] = $email->et->generateExpandableAddrs($out['meta']['email']['toaddrs']); + if(!empty($out['meta']['email']['cc_addrs'])) { + $ccs = $email->et->generateExpandableAddrs($out['meta']['email']['cc_addrs']); + $out['meta']['cc'] = << +
    + + +eoq; + } + echo $json->encode($out); + } + } else { + echo "error: no UID"; + } + break; + + case "getMultipleMessages": + $GLOBALS['log']->debug("********** EMAIL 2.0 - Asynchronous - at: getMultipleMessages"); + if(isset($_REQUEST['uid']) && !empty($_REQUEST['uid']) && isset($_REQUEST['ieId']) && !empty($_REQUEST['ieId'])) { + $exUids = explode(",", $_REQUEST['uid']); + + $out = array(); + foreach($exUids as $k => $uid) { + if($email->et->validCacheFileExists($_REQUEST['ieId'], 'messages', $_REQUEST['mbox'].$uid.".php")) { + $msg = $email->et->getCacheValue($_REQUEST['ieId'], 'messages', $_REQUEST['mbox'].$uid.".php", 'out'); + } else { + $ie->retrieve($_REQUEST['ieId']); + $ie->mailbox = $_REQUEST['mbox']; + $ie->setEmailForDisplay($uid, false, true); + $msg = $ie->displayOneEmail($uid, $_REQUEST['mbox']); + $email->et->writeCacheFile('out', $msg, $_REQUEST['ieId'], 'messages', "{$_REQUEST['mbox']}{$uid}.php"); + } + + $out[] = $msg; + } + echo $json->encode($out); + } else { + echo "error: no UID"; + } + break; + + case "getMultipleMessagesFromSugar": + $GLOBALS['log']->debug("********** EMAIL 2.0 - Asynchronous - at: getMultipleMessagesFromSugar"); + if(isset($_REQUEST['uid']) && !empty($_REQUEST['uid'])) { + $exIds = explode(",", $_REQUEST['uid']); + $out = array(); + + foreach($exIds as $id) { + $e = new Email(); + $e->retrieve($id); + $e->description_html = from_html($e->description_html); + $ie->email = $e; + $out[] = $ie->displayOneEmail($id, $_REQUEST['mbox']); + } + + echo $json->encode($out); + } + + break; + //// END MESSAGE HANDLING + /////////////////////////////////////////////////////////////////////////// + + + + /////////////////////////////////////////////////////////////////////////// + //// LIST VIEW + case "getMessageCount": + $GLOBALS['log']->debug("********** EMAIL 2.0 - Asynchronous - at: getMessageCount"); + + $out = $ie->getCacheCount($_REQUEST['mbox']); + echo $json->encode($out); + break; + + case "getMessageList": + $GLOBALS['log']->debug("********** EMAIL 2.0 - Asynchronous - at: getMessageListJSON"); + if(isset($_REQUEST['ieId']) && !empty($_REQUEST['ieId'])) { + // user view preferences + $email->et->saveListView($_REQUEST['ieId'], $_REQUEST['mbox']); + // list output + $ie->retrieve($_REQUEST['ieId']); + if(isset($_REQUEST['start']) && isset($_REQUEST['limit'])) { + $page = ceil($_REQUEST['start'] / $_REQUEST['limit']) + 1; + } else { + $page = 1; + } + $list = $ie->displayFolderContents($_REQUEST['mbox'], $_REQUEST['forceRefresh'], $page); + $count = $ie->getCacheCount($_REQUEST['mbox']); + $unread = $ie->getCacheUnread($_REQUEST['mbox']); + $out = $email->et->jsonOuput($list, 'Email', $count, true, $unread); + + @ob_end_clean(); + ob_start(); + echo $out; + ob_end_flush(); + //die(); + } else { + echo "error: no ieID"; + } + break; + + case "getMessageListSugarFolders": + $GLOBALS['log']->debug("********** EMAIL 2.0 - Asynchronous - at: getMessageListSugarFoldersJSON"); + if(isset($_REQUEST['ieId']) && !empty($_REQUEST['ieId'])) { + // user view preferences + $email->et->saveListView($_REQUEST['ieId'], "SUGAR.{$_REQUEST['mbox']}"); + if(isset($_REQUEST['start']) && isset($_REQUEST['limit'])) { + $page = ceil($_REQUEST['start'] / $_REQUEST['limit']) + 1; + } else { + $page = 1; + } + if(!isset($_REQUEST['sort']) || !isset($_REQUEST['dir'])) { + $_REQUEST['sort'] = ''; + $_REQUEST['dir'] = ''; + } + $emailSettings = $current_user->getPreference('emailSettings', 'Emails'); + // cn: default to a low number until user specifies otherwise + if(empty($emailSettings['showNumInList'])) { + $emailSettings['showNumInList'] = 20; + } + + // jchi #9424, get sort and direction from user preference + $sort = 'date'; + $direction = 'desc'; + $sortSerial = $current_user->getPreference('folderSortOrder', 'Emails'); + if(!empty($sortSerial) && !empty($_REQUEST['ieId']) && !empty($_REQUEST['mbox'])) { + $sortArray = unserialize($sortSerial); + $GLOBALS['log']->debug("********** EMAIL 2.0********** ary=".print_r($sortArray,true).' id='.$_REQUEST['ieId'].'; box='.$_REQUEST['mbox']); + $sort = $sortArray[$_REQUEST['ieId']][$_REQUEST['mbox']]['current']['sort']; + $direction = $sortArray[$_REQUEST['ieId']][$_REQUEST['mbox']]['current']['direction']; + } + //set sort and direction to user predference + if(!empty($_REQUEST['sort']) && !empty($_REQUEST['dir'])) { + $email->et->saveListViewSortOrder($_REQUEST['ieId'], $_REQUEST['mbox'], $_REQUEST['sort'], $_REQUEST['dir']); + $sort = $_REQUEST['sort']; + $direction = $_REQUEST['dir']; + } else { + $_REQUEST['sort'] = ''; + $_REQUEST['dir'] = ''; + } + //end + + $metalist = $email->et->folder->getListItemsForEmailXML($_REQUEST['ieId'], $page, + $emailSettings['showNumInList'], $sort, $direction); + $count = $email->et->folder->getCountItems($_REQUEST['ieId']); + $unread = $email->et->folder->getCountUnread($_REQUEST['ieId']); + $out = $email->et->jsonOuput($metalist, 'Email', $count, false, $unread); + + @ob_end_clean(); + ob_start(); + echo $out; + ob_end_flush(); + } else { + echo "error: no ieID"; + } + break; + //// END LIST VIEW + /////////////////////////////////////////////////////////////////////////// + + + + /////////////////////////////////////////////////////////////////////////// + //// FOLDER ACTIONS + case "emptyTrash": + $email->et->emptyTrash($ie); + break; + + case "clearInboundAccountCache": + $email->et->clearInboundAccountCache($_REQUEST['ieId']); + break; + + case "updateSubscriptions": + $GLOBALS['log']->debug("********** EMAIL 2.0 - Asynchronous - at: updateSubscriptions"); + if(isset($_REQUEST['subscriptions']) && !empty($_REQUEST['subscriptions'])) + { + $subs = explode("::", $_REQUEST['subscriptions']); + $childrenSubs = array(); + //Find all children of the group folder subscribed to and add + //them to the list of folders to show. + foreach ($subs as $singleSub) + $email->et->folder->findAllChildren($singleSub, $childrenSubs); + + $subs = array_merge($subs, $childrenSubs); + $email->et->folder->setSubscriptions($subs); + } + elseif(empty($_REQUEST['subscriptions'])) { + $email->et->folder->clearSubscriptions(); + } + break; + + case "refreshSugarFolders": + $GLOBALS['log']->debug("********** EMAIL 2.0 - Asynchronous - at: refreshSugarFolders"); + $rootNode = new ExtNode('',''); + $folderOpenState = $current_user->getPreference('folderOpenState', 'Emails'); + $folderOpenState = (empty($folderOpenState)) ? "" : $folderOpenState; + $ret = $email->et->folder->getUserFolders($rootNode, unserialize($folderOpenState), $current_user, true); + $out = $json->encode($ret); + echo $out; + break; + + + + case "getFoldersForSettings": + $GLOBALS['log']->debug("********** EMAIL 2.0 - Asynchronous - at: getFoldersForSettings"); + $ret = $email->et->folder->getFoldersForSettings($current_user); + $out = $json->encode($ret); + echo $out; + break; + + case "moveEmails": + $GLOBALS['log']->debug("********** EMAIL 2.0 - Asynchronous - at: moveEmails"); + $ie->moveEmails($_REQUEST['sourceIeId'], $_REQUEST['sourceFolder'], $_REQUEST['destinationIeId'], $_REQUEST['destinationFolder'], $_REQUEST['emailUids']); + break; + + case "saveNewFolder": + $GLOBALS['log']->debug("********** EMAIL 2.0 - Asynchronous - at: saveNewFolder"); + if(isset($_REQUEST['folderType']) && !empty($_REQUEST['folderType'])) { + switch($_REQUEST['folderType']) { + case "sugar": + $ret = $email->et->saveNewFolder($_REQUEST['nodeLabel'], $_REQUEST['parentId']); + $out = $json->encode($ret); + echo $out; + break; + + case "imap": + $ie->retrieve($_REQUEST['ieId']); + $ie->connectMailserver(); + $ie->saveNewFolder($_REQUEST['newFolderName'], $_REQUEST['mbox']); + break; + } + } else { + echo "NOOP: no folderType defined"; + } + break; + + case "setFolderViewSelection": // flows into next case statement + $GLOBALS['log']->debug("********** EMAIL 2.0 - Asynchronous - at: setFolderViewSelection"); + $viewFolders = $_REQUEST['ieIdShow']; + $current_user->setPreference('showFolders', base64_encode(serialize($viewFolders)), '', 'Emails'); + $tree = $email->et->getMailboxNodes(false); + $return = $tree->generateNodesRaw(); + $out = $json->encode($return); + echo $out; + break; + + case "deleteFolder": + $v = $app_strings['LBL_NONE']; + $return = array(); + $GLOBALS['log']->debug("********** EMAIL 2.0 - Asynchronous - at: deleteFolder"); + if(isset($_REQUEST['folderType']) && !empty($_REQUEST['folderType'])) { + switch($_REQUEST['folderType']) { + case "sugar": + $status = $email->et->folder->deleteChildrenCascade($_REQUEST['folder_id']); + if ($status == true) { + $return['status'] = true; + $return['folder_id'] = $_REQUEST['folder_id']; + } else { + $return['status'] = false; + $return['errorMessage'] = $app_strings['LBL_EMAIL_ERROR_DELETE_GROUP_FOLDER']; + } + break; + + case "imap": + $ie->retrieve($_REQUEST['ieId']); + $ie->connectMailserver(); + $returnArray = $ie->deleteFolder($_REQUEST['mbox']); + $status = $returnArray['status']; + $errorMessage = $returnArray['errorMessage']; + if ($status == true) { + $return['status'] = true; + $return['mbox'] = $_REQUEST['mbox']; + $return['ieId'] = $_REQUEST['ieId']; + } else { + $return['status'] = false; + $return['errorMessage'] = $errorMessage; + } + break; + } + } else { + $return['status'] = false; + $return['errorMessage'] = "NOOP: no folderType defined"; + } + $out = $json->encode($return); + echo $out; + break; + case "renameFolder": + $GLOBALS['log']->debug("********** EMAIL 2.0 - Asynchronous - at: renameFolder"); + + if(isset($_REQUEST['ieId']) && isset($_REQUEST['oldFolderName']) && !empty($_REQUEST['oldFolderName']) + && isset($_REQUEST['newFolderName']) && !empty($_REQUEST['newFolderName'])) { + $ie->retrieve($_REQUEST['ieId']); + $ie->renameFolder($_REQUEST['oldFolderName'], $_REQUEST['newFolderName']); + } elseif(isset($_REQUEST['folderId']) && !empty($_REQUEST['folderId']) && isset($_REQUEST['newFolderName']) && !empty($_REQUEST['newFolderName'])) { + if(is_guid($_REQUEST['folderId'])) { + $email->et->folder->retrieve($_REQUEST['folderId']); + $email->et->folder->name = $_REQUEST['newFolderName']; + $email->et->folder->save(); + } else { + echo "NOOP - not a Sugar Folder"; + } + } + case "moveFolder": + $GLOBALS['log']->debug("********** EMAIL 2.0 - Asynchronous - at: moveFolder"); + if(isset($_REQUEST['folderId']) && !empty($_REQUEST['folderId']) && isset($_REQUEST['newParentId']) && !empty($_REQUEST['newParentId']) && $_REQUEST['newParentId'] != $_REQUEST['folderId']) { + if(is_guid($_REQUEST['folderId']) && is_guid($_REQUEST['newParentId'])) { + $email->et->folder->retrieve($_REQUEST['folderId']); + $email->et->folder->updateFolder(array( + "record" => $_REQUEST['folderId'], + "name" => $email->et->folder->name, + "parent_folder" => $_REQUEST['newParentId'], + "team_id" => $email->et->folder->team_id, + "team_set_id" => $email->et->folder->team_set_id, + )); + } else { + echo "NOOP - not a Sugar Folder"; + } + } + break; + case "getGroupFolder": + $email->et->folder->retrieve($_REQUEST['folderId']); + $_REQUEST['record'] = $_REQUEST['folderId']; + $ret = array(); + $ret['folderId'] = $email->et->folder->id; + $ret['folderName'] = $email->et->folder->name; + $ret['parentFolderId'] = $email->et->folder->parent_folder; + $out = $json->encode($ret); + echo $out; + break; + + + case "rebuildFolders": + $GLOBALS['log']->debug("********** EMAIL 2.0 - Asynchronous - at: rebuildFolders"); + $tree = $email->et->getMailboxNodes(false); + $return = $tree->generateNodesRaw(); + $out = $json->encode($return); + echo $out; + break; + + case "setFolderOpenState": + $GLOBALS['log']->debug("********** EMAIL 2.0 - Asynchronous - at: setFolderOpenState"); + $email->et->saveFolderOpenState($_REQUEST['focusFolder'], $_REQUEST['focusFolderOpen']); + break; + + case "saveListViewSortOrder": + $GLOBALS['log']->debug("********** EMAIL 2.0 - Asynchronous - at: saveListViewSortOrder"); + $email->et->saveListViewSortOrder($_REQUEST['ieId'], $_REQUEST['focusFolder'], $_REQUEST['sortBy'], $_REQUEST['reverse']); + break; + //// END FOLDER ACTIONS + /////////////////////////////////////////////////////////////////////////// + + /////////////////////////////////////////////////////////////////////////// + //// INBOUND EMAIL ACCOUNTS + + case "retrieveAllOutbound": + $GLOBALS['log']->debug("********** EMAIL 2.0 - Asynchronous - at: retrieveAllOutbound"); + global $current_user; + $oe = new OutboundEmail(); + $outbounds = $oe->getUserMailers($current_user); + $results = array('outbound_account_list' => $outbounds, 'count' => count($outbounds)); + $out = $json->encode($results, false); + echo $out; + + break; + + case "editOutbound": + $GLOBALS['log']->debug("********** EMAIL 2.0 - Asynchronous - at: editOutbound"); + if(isset($_REQUEST['outbound_email']) && !empty($_REQUEST['outbound_email'])) { + $oe = new OutboundEmail(); + $oe->retrieve($_REQUEST['outbound_email']); + + $ret = array(); + + foreach($oe->field_defs as $def) { + $ret[$def] = $oe->$def; + } + $ret['mail_smtppass']=''; // don't send back the password + + $out = $json->encode($ret, true); + echo $out; + + } else { + echo "NOOP"; + } + break; + + case "deleteOutbound": + $GLOBALS['log']->debug("********** EMAIL 2.0 - Asynchronous - at: deleteOutbound"); + if(isset($_REQUEST['outbound_email']) && !empty($_REQUEST['outbound_email'])) + { + $oe = new OutboundEmail(); + global $current_user; + $oe->retrieve($_REQUEST['outbound_email']); + $affectedInboundAccounts = $oe->getAssociatedInboundAccounts($current_user); + + //Check if the user has confirmed he wants to delete the email account even if associated to an inbound accnt. + $confirmedDelete = ( isset($_REQUEST['confirm']) && $_REQUEST['confirm'] ) ? TRUE : FALSE; + + if( count($affectedInboundAccounts) > 0 && !$confirmedDelete) + { + $results = array('is_error' => true, 'error_message' => $app_strings['LBL_EMAIL_REMOVE_SMTP_WARNING'] , 'outbound_email' => $_REQUEST['outbound_email']); + } + else + { + $oe->delete(); + $results = array('is_error' => false, 'error_message' => ''); + } + + $out = $json->encode($results); + @ob_end_clean(); + ob_start(); + echo $out; + ob_end_flush(); + die(); + } + else + { + echo "NOOP"; + } + break; + + case "saveOutbound": + $GLOBALS['log']->debug("********** EMAIL 2.0 - Asynchronous - at: saveOutbound"); + + $oe = new OutboundEmail(); + $oe->id = $_REQUEST['mail_id']; + $oe->retrieve($oe->id); + $oe->name = $_REQUEST['mail_name']; + $type = empty($_REQUEST['type']) ? 'user' : $_REQUEST['type']; + $oe->type = $type; + $oe->user_id = $current_user->id; + $oe->mail_sendtype = "SMTP"; + $oe->mail_smtptype = $_REQUEST['mail_smtptype']; + $oe->mail_smtpserver = $_REQUEST['mail_smtpserver']; + $oe->mail_smtpport = $_REQUEST['mail_smtpport']; + $oe->mail_smtpssl = $_REQUEST['mail_smtpssl']; + $oe->mail_smtpauth_req = isset($_REQUEST['mail_smtpauth_req']) ? 1 : 0; + $oe->mail_smtpuser = $_REQUEST['mail_smtpuser']; + if(!empty($_REQUEST['mail_smtppass'])) { + $oe->mail_smtppass = $_REQUEST['mail_smtppass']; + } + $oe = $oe->save(); + echo $oe->id; + break; + + case "saveDefaultOutbound": + global $current_user; + $GLOBALS['log']->debug("********** EMAIL 2.0 - Asynchronous - at: saveDefaultOutbound"); + $outbound_id = empty($_REQUEST['id']) ? "" : $_REQUEST['id']; + $ie = new InboundEmail(); + $ie->setUsersDefaultOutboundServerId($current_user, $outbound_id); + break; + case "testOutbound": + $GLOBALS['log']->debug("********** EMAIL 2.0 - Asynchronous - at: testOutbound"); + + $pass = ''; + if(!empty($_REQUEST['mail_smtppass'])) { + $pass = $_REQUEST['mail_smtppass']; + } elseif(isset($_REQUEST['mail_name'])) { + $oe = new OutboundEmail(); + $oe = $oe->getMailerByName($current_user, $_REQUEST['mail_name']); + if(!empty($oe)) { + $pass = $oe->mail_smtppass; + } + } + $out = $email->sendEmailTest($_REQUEST['mail_smtpserver'], $_REQUEST['mail_smtpport'], $_REQUEST['mail_smtpssl'], + (isset($_REQUEST['mail_smtpauth_req']) ? 1 : 0), $_REQUEST['mail_smtpuser'], + $pass, $_REQUEST['outboundtest_from_address'], $_REQUEST['outboundtest_from_address']); + + $out = $json->encode($out); + echo $out; + break; + + case "rebuildShowAccount": + $GLOBALS['log']->debug("********** EMAIL 2.0 - Asynchronous - at: rebuildShowAccount"); + $ret = $email->et->getShowAccountsOptions($ie); + $results = array('account_list' => $ret, 'count' => count($ret)); + $out = $json->encode($results); + echo $out; + break; + + case "rebuildShowAccountForSearch": + $GLOBALS['log']->debug("********** EMAIL 2.0 - Asynchronous - at: rebuildShowAccount"); + $ret = $email->et->getShowAccountsOptionsForSearch($ie); + $out = $json->encode($ret); + echo $out; + break; + + case "deleteIeAccount": + $GLOBALS['log']->debug("********** EMAIL 2.0 - Asynchronous - at: deleteIeAccount"); + if(isset($_REQUEST['group_id']) && $_REQUEST['group_id'] == $current_user->id) { + $ret = array(); + $ret['id'] = $_REQUEST['ie_id']; + $out = $json->encode($ret); + $ie->hardDelete($_REQUEST['ie_id']); + $out = $json->encode(array('id' => $_REQUEST['ie_id'])); + echo $out; + + foreach($showFolders as $id) { + if($id != $_REQUEST['ie_id']) + $updateFolders[] = $id; + } + + $showStore = base64_encode(serialize($updateFolders)); + $current_user->setPreference('showFolders', $showStore, 0, 'Emails'); + } + break; + + case "saveIeAccount": + $GLOBALS['log']->debug("********** EMAIL 2.0 - Asynchronous - at: saveIeAccount"); + if(isset($_REQUEST['server_url']) && !empty($_REQUEST['server_url'])) { + if(false === $ie->savePersonalEmailAccount($current_user->id, $current_user->user_name, false)) { + $ret = array('error' => 'error'); + $out = $json->encode($ret); + echo $out; + } else { + $ie->retrieve($_REQUEST['ie_id']); + if (!isset($ie->created_by_link)) { + $ie->created_by_link = null; + } + if (!isset($ie->modified_user_id_link)) { + $ie->modified_user_id_link = null; + } + if (!is_array($showFolders)) { + $showFolders = array(); + } + if(!in_array($ie->id, $showFolders)) { + $showFolders[] = $ie->id; + $showStore = base64_encode(serialize($showFolders)); + $current_user->setPreference('showFolders', $showStore, 0, 'Emails'); + } + + foreach($ie->field_defs as $k => $v) { + if (isset($v['type']) && ($v['type'] == 'link')) { + continue; + } + if($k == 'stored_options') { + $ie->$k = unserialize(base64_decode($ie->$k)); + if (isset($ie->stored_options['from_name'])) { + $ie->stored_options['from_name'] = from_html($ie->stored_options['from_name']); + } + } elseif($k == 'service') { + $service = explode("::", $ie->$k); + $retService = array(); + + foreach($service as $serviceK => $serviceV) { + if(!empty($serviceV)) { + $retService[$serviceK] = $serviceV; + } + } + + $ie->$k = $retService; + } + + if (isset($ie->$k)) + $ret[$k] = $ie->$k; + } + + $out = $json->encode($ret); + echo $out; + } + + //If the user is saving the username/password then we need to update the outbound account. + $outboundMailUser = (isset($_REQUEST['mail_smtpuser'])) ? $_REQUEST['mail_smtpuser'] : ""; + $outboundMailPass = (isset($_REQUEST['mail_smtppass'])) ? $_REQUEST['mail_smtppass'] : ""; + $outboundMailId = (isset($_REQUEST['outbound_email'])) ? $_REQUEST['outbound_email'] : ""; + + if( !empty($outboundMailUser) && !empty($outboundMailPass) && !empty($outboundMailId) ) + { + $oe = new OutboundEmail(); + $oe->retrieve($outboundMailId); + $oe->mail_smtpuser = $outboundMailUser; + $oe->mail_smtppass = $outboundMailPass; + $oe->save(); + } + + } else { + echo "NOOP"; + } + break; + + case "getIeAccount": + $GLOBALS['log']->debug("********** EMAIL 2.0 - Asynchronous - at: getIeAccount"); + $ie->retrieve($_REQUEST['ieId']); + if($ie->group_id == $current_user->id) { + $ret = array(); + + foreach($ie->field_defs as $k => $v) { + if($k == 'stored_options') { + $ie->$k = unserialize(base64_decode($ie->$k)); + if (isset($ie->stored_options['from_name'])) { + $ie->stored_options['from_name'] = from_html($ie->stored_options['from_name']); + } + } elseif($k == 'service') { + $service = explode("::", $ie->$k); + $retService = array(); + foreach($service as $serviceK => $serviceV) { + if(!empty($serviceV)) { + $retService[$serviceK] = $serviceV; + } + } + + $ie->$k = $retService; + } + + $ret[$k] = $ie->$k; + } + unset($ret['email_password']); // no need to send the password out + + $out = $json->encode($ret); + } else { + $out = "NOOP: ID mismatch"; + } + echo $out; + break; + //// END INBOUND EMAIL ACCOUNTS + /////////////////////////////////////////////////////////////////////////// + + + + /////////////////////////////////////////////////////////////////////////// + //// SEARCH + case "search": + $GLOBALS['log']->debug("********** EMAIL 2.0 - Asynchronous - at: search"); + if(isset($_REQUEST['subject']) && !empty($_REQUEST['subject']) && isset($_REQUEST['ieId']) && !empty($_REQUEST['ieId'])) { + $metalist = $ie->search($_REQUEST['ieId'], $_REQUEST['subject']); + if (!isset($_REQUEST['page'])) { + $_REQUEST['page'] = 1; + } + $_REQUEST['pageSize'] = count($metalist['out']); + $out = $email->et->xmlOutput($metalist, 'Email', false); + @ob_end_clean(); + ob_start(); + header("Content-type: text/xml"); + echo $out; + ob_end_flush(); + die(); + } else { + echo "NOOP: no search criteria found"; + } + break; + + case "searchAdvanced": + $GLOBALS['log']->debug("********** EMAIL 2.0 - Asynchronous - at: searchAdvanced"); + + $metalist = $email->searchImportedEmails(); + $out = $email->et->jsonOuput($metalist, 'Email', $metalist['totalCount']); + + @ob_end_clean(); + ob_start(); + echo $out; + ob_end_flush(); + die(); + + break; + //// END SEARCH + /////////////////////////////////////////////////////////////////////////// + + + + /////////////////////////////////////////////////////////////////////////// + //// SETTINGS + case "loadPreferences": + $GLOBALS['log']->debug("********** EMAIL 2.0 - Asynchronous - at: loadPreferences"); + $prefs = $email->et->getUserPrefsJS(); + $out = $json->encode($prefs); + echo $out; + break; + + case "saveSettingsGeneral": + $GLOBALS['log']->debug("********** EMAIL 2.0 - Asynchronous - at: saveSettingsGeneral"); + $emailSettings = array(); + $emailSettings['emailCheckInterval'] = $_REQUEST['emailCheckInterval']; + //$emailSettings['autoImport'] = isset($_REQUEST['autoImport']) ? '1' : '0'; + $emailSettings['alwaysSaveOutbound'] = '1'; + $emailSettings['sendPlainText'] = isset($_REQUEST['sendPlainText']) ? '1' : '0'; + $emailSettings['showNumInList'] = $_REQUEST['showNumInList']; + $emailSettings['defaultOutboundCharset'] = $_REQUEST['default_charset']; + $current_user->setPreference('emailSettings', $emailSettings, '', 'Emails'); + + // signature + $current_user->setPreference('signature_default', $_REQUEST['signature_id']); + $current_user->setPreference('signature_prepend', (isset($_REQUEST['signature_prepend'])) ? true : false); + + $out = $json->encode($email->et->getUserPrefsJS()); + echo $out; + break; + + case "setPreference": + $GLOBALS['log']->debug("********** EMAIL 2.0 - Asynchronous - at: setPreference"); + if(isset($_REQUEST['prefName']) && isset($_REQUEST['prefValue'])) { + // handle potential JSON encoding + if(isset($_REQUEST['decode'])) { + $_REQUEST['prefValue'] = $json->decode(from_html($_REQUEST['prefValue'])); + } + + $current_user->setPreference($_REQUEST['prefName'], $_REQUEST['prefValue'], '', 'Emails'); + } + break; + //// END SETTINGS + /////////////////////////////////////////////////////////////////////////// + + + + + /////////////////////////////////////////////////////////////////////////// + //// ADDRESS BOOK + + case "editContact": + $GLOBALS['log']->debug("********** EMAIL 2.0 - Asynchronous - at: editContact"); + if(isset($_REQUEST['id']) && !empty($_REQUEST['id'])) { + $module = "Contacts"; + $ret = $email->et->getEditContact($_REQUEST['id'], $module); + } + $out = $json->encode($ret); + echo $out; + break; + + + /* The four calls below all have the same return signature */ + case "removeContact": + $GLOBALS['log']->debug("********** EMAIL 2.0 - Asynchronous - at: removeContacts"); + if(strpos($_REQUEST['ids'], "::") !== false) { + $removeIds = explode("::", $_REQUEST['ids']); + } else { + $removeIds[] = $_REQUEST['ids']; + } + $email->et->removeContacts($removeIds); + + case "saveContactEdit": + $GLOBALS['log']->debug("********** EMAIL 2.0 - Asynchronous - at: saveContactEdit"); + if(isset($_REQUEST['args']) && !empty($_REQUEST['args'])) { + $email->et->saveContactEdit($_REQUEST['args']); + } + // flow into getUserContacts(); + case "addContact": + $GLOBALS['log']->debug("********** EMAIL 2.0 - Asynchronous - at: addContacts"); + $contacts = array(); + + if(isset($_REQUEST['bean_module']) && !empty($_REQUEST['bean_module']) && isset($_REQUEST['bean_id']) && !empty($_REQUEST['bean_id'])) { + $contacts[$_REQUEST['bean_id']] = array( + 'id' => $_REQUEST['bean_id'], + 'module' => $_REQUEST['bean_module'] + ); + $email->et->setContacts($contacts); + } + + case "addContactsMultiple": + $GLOBALS['log']->debug("********** EMAIL 2.0 - Asynchronous - at: addContacts"); + if (isset($_REQUEST['contactData'])) { + $contacts = $json->decode(from_HTML($_REQUEST['contactData'])); + if ($contacts) { + //_ppd($contacts); + $email->et->setContacts($contacts); + } + } + + case "getUserContacts": + $GLOBALS['log']->debug("********** EMAIL 2.0 - Asynchronous - at: getUserContacts"); + $contacts = $email->et->getContacts(); + + if(is_array($contacts) && !empty($contacts)) { + $ret = $email->et->getUserContacts($contacts, $current_user); + $out = $json->encode($ret); + echo $out; + } else { + echo "{}"; + } + break; + + + // address book search + case "getUnionData": + $wheres = array(); + $person; + if(isset($_REQUEST['first_name']) && !empty($_REQUEST['first_name'])) { + $wheres['first_name'] = $_REQUEST['first_name']; + } + if(isset($_REQUEST['last_name']) && !empty($_REQUEST['last_name'])) { + $wheres['last_name'] = $_REQUEST['last_name']; + } + if(isset($_REQUEST['email_address']) && !empty($_REQUEST['email_address'])) { + $wheres['email_address'] = $_REQUEST['email_address']; + } + if(isset($_REQUEST['person']) && !empty($_REQUEST['person'])) { + $person = $_REQUEST['person']; + } + $q = $email->et->_getPeopleUnionQuery($wheres , $person); + $r = $ie->db->limitQuery($q, 0, 25, true); + + $out = array(); + while($a = $ie->db->fetchByAssoc($r)) { + $person = array(); + $person['id'] = $a['id']; + $person['module'] = $a['module']; + $person['full_name'] = $locale->getLocaleFormattedName($a['first_name'], $a['last_name'],''); + $person['email_address'] = $a['email_address']; + $out[] = $person; + } + + $ret = $json->encode($out, true); + echo $ret; + break; + + case "getAddressSearchResults": + $wheres = array(); + $person = 'contacts'; + $relatedBeanInfo = ''; + if(isset($_REQUEST['related_bean_id']) && !empty($_REQUEST['related_bean_id'])) { + $isRelatedSearch = true; + $relatedBeanInfo['related_bean_id'] = $_REQUEST['related_bean_id']; + $relatedBeanInfo['related_bean_type'] = ucfirst($_REQUEST['related_bean_type']); + } + + if (isset($_REQUEST['search_field'])) { + $wheres['first_name'] = $_REQUEST['search_field']; + $wheres['last_name'] = $_REQUEST['search_field']; + $wheres['email_address'] = $_REQUEST['search_field']; + } + + if(isset($_REQUEST['person']) && !empty($_REQUEST['person'])) { + $person = $_REQUEST['person']; + } + if(isset($_REQUEST['start']) && !empty($_REQUEST['start'])) { + $start = $_REQUEST['start']; + } else { + $start = 0; + } + + $qArray = $email->et->getRelatedEmail($person, $wheres, $relatedBeanInfo); + $out = array(); + $count = 0; + if (!empty($qArray['query'])) { + $countq = $qArray['countQuery']; + $time = microtime(true); + $r = $ie->db->query($countq); + $GLOBALS['log']->debug("***QUERY counted in " . (microtime(true) - $time) . " milisec\n"); + if($row = $GLOBALS['db']->fetchByAssoc($r)){ + $count = $row['c']; + } + $time = microtime(true); + + //Handle sort and order requests + $sort = !empty($_REQUEST['sort']) ? $_REQUEST['sort'] : "id"; + $sort = ($sort == 'bean_id') ? 'id' : $sort; + $sort = ($sort == 'email') ? 'email_address' : $sort; + $sort = ($sort == 'name') ? 'last_name' : $sort; + $direction = !empty($_REQUEST['dir']) ? $_REQUEST['dir'] : "asc"; + $order = ( !empty($sort) && !empty($direction) ) ? " ORDER BY {$sort} {$direction}" : ""; + + $r = $ie->db->limitQuery($qArray['query'] . " $order ", $start, 25, true); + $GLOBALS['log']->debug("***QUERY Got results in " . (microtime(true) - $time) . " milisec\n"); + + + while($a = $ie->db->fetchByAssoc($r)) { + $person = array(); + $person['bean_id'] = $a['id']; + $person['bean_module'] = $a['module']; + $person['name'] = $locale->getLocaleFormattedName($a['first_name'], $a['last_name'],''); + $person['email'] = $a['email_address']; + $out[] = $person; + } + } + $ret = $email->et->jsonOuput(array('out' => $out), 'Person', $count); + + @ob_end_clean(); + ob_start(); + echo $ret; + ob_end_flush(); + break; + + //// END ADDRESS BOOK + /////////////////////////////////////////////////////////////////////////// + + + + /////////////////////////////////////////////////////////////////////////// + //// MISC + + default: + $GLOBALS['log']->debug("********** EMAIL 2.0 - Asynchronous - at: default"); + echo "NOOP"; + break; + } + + + + + + + + + + + + + + diff --git a/modules/Emails/GenerateQuickComposeFrame.php b/modules/Emails/GenerateQuickComposeFrame.php new file mode 100644 index 00000000..3c63f798 --- /dev/null +++ b/modules/Emails/GenerateQuickComposeFrame.php @@ -0,0 +1,50 @@ +displayQuickComposeEmailFrame(); + +@ob_end_clean(); +ob_start(); +echo $out; +ob_end_flush(); \ No newline at end of file diff --git a/modules/Emails/Grab.php b/modules/Emails/Grab.php new file mode 100644 index 00000000..9e1cdc0f --- /dev/null +++ b/modules/Emails/Grab.php @@ -0,0 +1,73 @@ +db->query($groupUserQuery); +$groupIds = ''; +while($a = $focus->db->fetchByAssoc($r)) { + $groupIds .= "'".$a['group_id']."', "; +} +$groupIds = substr($groupIds, 0, (strlen($groupIds) - 2)); + +$query = 'SELECT emails.id AS id FROM emails'; +$query .= " WHERE emails.deleted = 0 AND emails.status = 'unread' AND emails.assigned_user_id IN ({$groupIds})"; +//$query .= ' LIMIT 1'; + +//_ppd($query); +$r2 = $focus->db->query($query); +$count = 0; +$a2 = $focus->db->fetchByAssoc($r2); + +$focus->retrieve($a2['id']); +$focus->assigned_user_id = $current_user->id; +$focus->save(); + +if(!empty($a2['id'])) { + header('Location: index.php?module=Emails&action=ListView&type=inbound&assigned_user_id='.$current_user->id); +} else { + header('Location: index.php?module=Emails&action=ListView&show_error=true&type=inbound&assigned_user_id='.$current_user->id); +} + +?> diff --git a/modules/Emails/ListViewDrafts.html b/modules/Emails/ListViewDrafts.html new file mode 100644 index 00000000..8f40f200 --- /dev/null +++ b/modules/Emails/ListViewDrafts.html @@ -0,0 +1,72 @@ + + + + +

    {$title}

    +{$MOD.LBL_CONFIG_TABS_DESC} +

    + +
    + + + + + + + + + + + +
    + + +
    + +
    + + + + + + + + +
    +   + {$MOD.LBL_ALLOW_USER_TABS} +  {sugar_help text=$MOD.LBL_CONFIG_TABS_ALLOW_USERS_HIDE_TABS_HELP} +
    +
    +
    +
    +
    +
    +
    +
    + +
    + + + + + +
    +
    +
    +
    +
    +
    + + + + + +
    + + +
    +
    + + + \ No newline at end of file diff --git a/modules/Administration/templates/GlobalSearchSettings.tpl b/modules/Administration/templates/GlobalSearchSettings.tpl new file mode 100644 index 00000000..fe3c31cf --- /dev/null +++ b/modules/Administration/templates/GlobalSearchSettings.tpl @@ -0,0 +1,154 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} + + +
    + + + + + + + + +
    + + +
    + +
    + + + + + +
    +
    +
    +
    +
    +
    + + + + + +
    + + +
    +
    + + \ No newline at end of file diff --git a/modules/Administration/templates/Languages.tpl b/modules/Administration/templates/Languages.tpl new file mode 100644 index 00000000..6b645e97 --- /dev/null +++ b/modules/Administration/templates/Languages.tpl @@ -0,0 +1,152 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} + + +{overlib_includes} + + + + + + + + "; + $xtpl->assign("REPLY_TO", $replyTo); +} + +/////////////////////////////////////////////////////////////////////////////// +//// JAVASCRIPT VARS +$jsVars = ''; +$jsVars .= "var showRaw = '{$mod_strings['LBL_BUTTON_RAW_LABEL']}';"; +$jsVars .= "var hideRaw = '{$mod_strings['LBL_BUTTON_RAW_LABEL_HIDE']}';"; +$xtpl->assign("JS_VARS", $jsVars); + + +// ADMIN EDIT +if(is_admin($GLOBALS['current_user']) && $_REQUEST['module'] != 'DynamicLayout' && !empty($_SESSION['editinplace'])){ + $xtpl->assign("ADMIN_EDIT","".SugarThemeRegistry::current()->getImage("EditLayout","border='0' alt='Edit Layout' align='bottom'").""); +} + +if(isset($_REQUEST['offset']) && !empty($_REQUEST['offset'])) { $offset = $_REQUEST['offset']; } +else $offset = 1; +$detailView->processListNavigation($xtpl, "EMAIL", $offset, false); + + + +// adding custom fields: +require_once('modules/DynamicFields/templates/Files/DetailView.php'); +$do_open = true; +if ($do_open) { + $xtpl->parse("main.open_source"); +} + +/////////////////////////////////////////////////////////////////////////////// +//// NOTES (attachements, etc.) +/////////////////////////////////////////////////////////////////////////////// + +$note = new Note(); +$where = "notes.parent_id='{$focus->id}'"; +//take in account if this is from campaign and the template id is stored in the macros. + +if(isset($macro_values) && isset($macro_values['email_template_id'])){ + $where = "notes.parent_id='{$macro_values['email_template_id']}'"; +} +$notes_list = $note->get_full_list("notes.name", $where, true); + +if(! isset($notes_list)) { + $notes_list = array(); +} + +$attachments = ''; +for($i=0; $ifilename)) + $attachments .= "id."&type=Notes\">".$the_note->name."
    "; +} + +$xtpl->assign("ATTACHMENTS", $attachments); +$xtpl->parse("main"); +$xtpl->out("main"); + +$sub_xtpl = $xtpl; +$old_contents = ob_get_contents(); +ob_end_clean(); +ob_start(); +echo $old_contents; + +/////////////////////////////////////////////////////////////////////////////// +//// SUBPANELS +/////////////////////////////////////////////////////////////////////////////// +if ($show_subpanels) { + require_once('include/SubPanel/SubPanelTiles.php'); + $subpanel = new SubPanelTiles($focus, 'Emails'); + echo $subpanel->display(); +} +?> \ No newline at end of file diff --git a/modules/Emails/DetailViewSent.html b/modules/Emails/DetailViewSent.html new file mode 100644 index 00000000..f85bc0aa --- /dev/null +++ b/modules/Emails/DetailViewSent.html @@ -0,0 +1,182 @@ + + + + +
    + + + + + + + + + + + + + + + + + + +

    {$title}

    +{$MOD.LBL_CONFIG_LANGS_DESC} +

    + +
    + + + + + + + + + + + +
    + + +
    + +
    + + + + + +
    +
    +
    +
    +
    +
    +
    +
    + + + + + +
    + + +
    +
    + + + \ No newline at end of file diff --git a/modules/Administration/templates/QuickRepairAndRebuild.tpl b/modules/Administration/templates/QuickRepairAndRebuild.tpl new file mode 100644 index 00000000..2e4c4780 --- /dev/null +++ b/modules/Administration/templates/QuickRepairAndRebuild.tpl @@ -0,0 +1,49 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} + +
    +

    {$MOD.LBL_QUICK_REPAIR_TITLE}


    + + + + {html_options multiple ="1" size="10" name=repair_module[] values=$values output=$output selected=$MOD.LBL_ALL_MODULES} +

    + {html_checkboxes name="selected_actions" values = $checkbox_values output = $checkbox_output separator="
    " selected=$checkbox_values } +
    + +
    diff --git a/modules/Administration/templates/RepairDatabase.tpl b/modules/Administration/templates/RepairDatabase.tpl new file mode 100644 index 00000000..32df6721 --- /dev/null +++ b/modules/Administration/templates/RepairDatabase.tpl @@ -0,0 +1,48 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} + +

    {$MOD.LBL_REPAIR_DATABASE_DIFFERENCES}

    +

    {$MOD.LBL_REPAIR_DATABASE_TEXT}

    +
    + + + + +
    + + \ No newline at end of file diff --git a/modules/Administration/templates/RepairXSS.tpl b/modules/Administration/templates/RepairXSS.tpl new file mode 100644 index 00000000..011edcdb --- /dev/null +++ b/modules/Administration/templates/RepairXSS.tpl @@ -0,0 +1,61 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} + + + + +
    + {$mod.LBL_REPAIRXSS_INSTRUCTIONS} +
    +
    + +
    + {$beanDropDown} +
    +
    + + +
    + + \ No newline at end of file diff --git a/modules/Administration/templates/ShortcutBar.tpl b/modules/Administration/templates/ShortcutBar.tpl new file mode 100644 index 00000000..a92b21c0 --- /dev/null +++ b/modules/Administration/templates/ShortcutBar.tpl @@ -0,0 +1,170 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} + + + + + + + + + + +

    {$title}

    {$msg}
    +{if empty($msg)} + + + + + + + + + + + +
    + + +
    +
    + + + + + +
    +
    +
    +
    +
    +
    + + + + + +
    + + +
    + + + +{/if} \ No newline at end of file diff --git a/modules/Administration/templates/themeSettings.tpl b/modules/Administration/templates/themeSettings.tpl new file mode 100644 index 00000000..b5def1b8 --- /dev/null +++ b/modules/Administration/templates/themeSettings.tpl @@ -0,0 +1,158 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} + + + +
    + + + + + + + + +
    + + +
    + +
    + + + + + + +
    {$MOD.DEFAULT_THEME}   + +
    +
    +
    +
    +
    +
    + + + + + +
    + + +
    +
    + + \ No newline at end of file diff --git a/modules/Administration/undoupdateclass.php b/modules/Administration/undoupdateclass.php new file mode 100644 index 00000000..0c2f18f8 --- /dev/null +++ b/modules/Administration/undoupdateclass.php @@ -0,0 +1,54 @@ + + $filename){ + // Find the name of the file generated by the updateclass script + $pos=strrpos($filename,"/"); + $Newfilename=substr_replace($filename, 'SugarCore.', $pos+1, 0); + //delete the new SugarBean that extends CoreBean and replace it by the old one undoing all the changes + if (file_exists($Newfilename)){ + unlink($filename); + $handle = file_get_contents($Newfilename); + $data = preg_replace("/class SugarCore".$Classname."/", 'class '.$Classname, $handle); + $data1 = preg_replace("/function SugarCore".$Classname."/", 'function '.$Classname, $data); + file_put_contents($Newfilename,$data1); + rename($Newfilename,$filename); + } +} +?> diff --git a/modules/Administration/updateTimezonePrefs.php b/modules/Administration/updateTimezonePrefs.php new file mode 100644 index 00000000..d2228d63 --- /dev/null +++ b/modules/Administration/updateTimezonePrefs.php @@ -0,0 +1,172 @@ + +
    + + + + +query("SELECT id, user_preferences, user_name FROM users"); +$execute = false; +// loop through user preferences and check for "bad" elements; rebuild preferences array and update database +if(isset($_POST['execute'])){ + $execute = true; +} +$serverTimeZone = lookupTimezone(0); +while ($row = $db->fetchByAssoc($result)) { + $adjustment = 'none'; + + if(isset($_POST[$row['id'].'adjust'])){ + $adjustment = $_POST[$row['id'].'adjust']; + } + + $string = "Preview"; + if($execute)$string = "Updating"; + echo ""; + + $the_old_prefs[] = $prefs; + $the_new_prefs[] = $newprefs; + + unset($prefs); + unset($newprefs); + unset($newstr); +} + +echo "
    $string timezone preferences for user {$row['user_name']}..."; + + + $prefs = array(); + $newprefs = array(); + + $prefs = unserialize(base64_decode($row['user_preferences'])); + $setTo = ''; + $alreadySet = ''; + if(!empty($prefs)){ + + foreach ($prefs as $key => $val) { + if ($key == 'timez') { + if(empty($prefs['timezone']) && $val != ''){ + $hourAdjust = $adjustment; + if($hourAdjust == 'none'){ + $hourAdjust = 0; + } + $selectedZone = lookupTimezone($prefs['timez'] + $hourAdjust); + + if(!empty($selectedZone)){ + $newprefs['timezone'] = $selectedZone; + $newprefs['timez'] = $val; + $setTo = $selectedZone; + if(empty($prompt_users)){ + $newprefs['ut']=1; + }else{ + $newprefs['ut']=0; + } + }else{ + $newprefs['timezone'] = $serverTimeZone; + $newprefs['timez'] = $val; + $setTo = $serverTimeZone; + if(empty($prompt_users)){ + $newprefs['ut']=1; + }else{ + $newprefs['ut']=0; + } + } + }else{ + $newprefs[$key] = $val; + if(!empty($prefs['timezone'])){ + $alreadySet = 'Previously Set - '. $prefs['timezone']; + } + } + + + }else{ + $newprefs[$key] = $val; + } + } + if($execute){ + $newstr = mysql_real_escape_string(base64_encode(serialize($newprefs))); + $db->query("UPDATE users SET user_preferences = '{$newstr}' WHERE id = '{$row['id']}'"); + } + } + if(!empty($setTo)){ + echo $setTo; + }else{ + if(!empty($alreadySet)){ + echo $alreadySet; + }else{ + echo $serverTimeZone; + $prefs['timezone'] = $serverTimeZone; + } + } + echo ""; + if(!empty($setTo)){ + echo "Adjust: "; + if($execute){ + if(isset($_POST[$row['id'].'adjust'])){ + echo $adjustment; + } + }else{ + echo "'; + + } + echo ' hour'; + } + echo ' '; + echo "
    "; + +if($execute){ + echo "
    All timezone preferences updated!

    "; + +}else{ + echo "Prompt users on login to confirm:
    "; + echo "  "; + +} +echo " "; +?> +
    diff --git a/modules/Administration/updateclass.php b/modules/Administration/updateclass.php new file mode 100644 index 00000000..b4dd4d22 --- /dev/null +++ b/modules/Administration/updateclass.php @@ -0,0 +1,111 @@ + $filename){ + if (file_exists($filename)){ + // Rename the class and its constructor adding SugarCore at the beginning (Ex: class SugarCoreCall) + $handle = file_get_contents($filename); + $patterns = array ('/class '.$classname.'/','/function '.$classname.'/'); + $replace = array ('class SugarCore'.$classname,'function SugarCore'.$classname); + $data = preg_replace($patterns,$replace, $handle); + sugar_file_put_contents($filename,$data); + + // Rename the SugarBean file into SugarCore.SugarBean (Ex: SugarCore.Call.php) + $pos=strrpos($filename,"/"); + $newfilename=substr_replace($filename, 'SugarCore.', $pos+1, 0); + sugar_rename($filename,$newfilename); + + //Create a new SugarBean that extends CoreBean + $fileHandle = sugar_fopen($filename, 'w') ; +$newclass = << +FABRICE; + fwrite($fileHandle, $newclass); + fclose($fileHandle); + } +} +?> \ No newline at end of file diff --git a/modules/Administration/updater_utils.php b/modules/Administration/updater_utils.php new file mode 100644 index 00000000..ea46ec0a --- /dev/null +++ b/modules/Administration/updater_utils.php @@ -0,0 +1,423 @@ + 0){ + if(isset($_SERVER['SERVER_ADDR'])) + $info['ip_address'] = $_SERVER['SERVER_ADDR']; + else + $info['ip_address'] = '127.0.0.1'; + } + $info['application_key']=$sugar_config['unique_key']; + $info['php_version']=phpversion(); + if(isset($_SERVER['SERVER_SOFTWARE'])) { + $info['server_software'] = $_SERVER['SERVER_SOFTWARE']; + } // if + + //get user count. + + $user_list = get_user_array(false, "Active", "", false, null, " AND is_group=0 AND portal_only=0 ", false); + + + + $info['users']=count($user_list); + if(empty($administration)){ + + $administration = new Administration(); + } + $administration->retrieveSettings('system'); + $info['system_name'] = (!empty($administration->settings['system_name']))?substr($administration->settings['system_name'], 0 ,255):''; + + + $query="select count(*) count from users where status='Active' and deleted=0 and is_admin='1'"; + $result=$db->query($query, 'fetching admin count', false); + $row = $db->fetchByAssoc($result); + if(!empty($row)) { + $info['admin_users'] = $row['count']; + } + if(empty($authLevel)){ + $authLevel = 0; + } + $query="select count(*) count from users"; + $result=$db->query($query, 'fetching all users count', false); + $row = $db->fetchByAssoc($result); + + if(!empty($row)) { + $info['registered_users'] = $row['count']; + } + $lastMonth = db_convert("'". $timedate->getNow()->modify("-30 days")->asDb(false) . "'", 'datetime'); + if( !$send_usage_info){ + $info['users_active_30_days'] = -1; + } + else{ + $query = "SELECT count( DISTINCT users.id ) user_count FROM tracker, users WHERE users.id = tracker.user_id AND tracker.date_modified >= $lastMonth"; + $result=$db->query($query, 'fetching last 30 users count', false); + $row = $db->fetchByAssoc($result); + $info['users_active_30_days'] = $row['user_count']; + + } + + + + + if(!$send_usage_info){ + $info['latest_tracker_id'] = -1; + }else{ + $query="select id from tracker order by date_modified desc"; + $id=$db->getOne($query,'fetching most recent tracker entry',false); + if ( $id !== false ) + $info['latest_tracker_id'] = $id; + } + + $dbManager = &DBManagerFactory::getInstance(); + $info['db_type']=$sugar_config['dbconfig']['db_type']; + $info['db_version']=$dbManager->version(); + } + if(file_exists('distro.php')){ + include('distro.php'); + if(!empty($distro_name))$info['distro_name'] = $distro_name; + } + $info['auth_level'] = $authLevel; + $info['os'] = php_uname('s'); + $info['os_version'] = php_uname('r'); + $info['timezone_u'] = $GLOBALS['current_user']->getPreference('timezone'); + $info['timezone'] = date('e'); + if($info['timezone'] == 'e'){ + $info['timezone'] = date('T'); + } + return $info; + +} + +function getBaseSystemInfo($send_usage_info=true){ + global $authLevel; + include('sugar_version.php'); + $info=array(); + + if($send_usage_info){ + $info['sugar_db_version']=$sugar_db_version; + } + $info['sugar_version']=$sugar_version; + $info['sugar_flavor']=$sugar_flavor; + $info['auth_level'] = $authLevel; + + + + return $info; + + +} + +function check_now($send_usage_info=true, $get_request_data=false, $response_data = false, $from_install=false ) { + global $sugar_config, $timedate; + global $db, $license; + + + $return_array=array(); + if(!$from_install && empty($license))loadLicense(true); + + if(!$response_data){ + + if($from_install){ + $info = getBaseSystemInfo(false); + + }else{ + $info = getSystemInfo($send_usage_info); + } + + require_once('include/nusoap/nusoap.php'); + + $GLOBALS['log']->debug('USING HTTPS TO CONNECT TO HEARTBEAT'); + $sclient = new nusoapclient('https://updates.sugarcrm.com/heartbeat/soap.php', false, false, false, false, false, 15, 15); + $ping = $sclient->call('sugarPing', array()); + if(empty($ping) || $sclient->getError()){ + $sclient = ''; + } + + if(empty($sclient)){ + $GLOBALS['log']->debug('USING HTTP TO CONNECT TO HEARTBEAT'); + $sclient = new nusoapclient('http://updates.sugarcrm.com/heartbeat/soap.php', false, false, false, false, false, 15, 15); + } + + + + + + + $key = '4829482749329'; + + + + $encoded = sugarEncode($key, serialize($info)); + + if($get_request_data){ + $request_data = array('key'=>$key, 'data'=>$encoded); + return serialize($request_data); + } + $encodedResult = $sclient->call('sugarHome', array('key'=>$key, 'data'=>$encoded)); + + }else{ + $encodedResult = $response_data['data']; + $key = $response_data['key']; + + } + + if($response_data || !$sclient->getError()){ + $serializedResultData = sugarDecode($key,$encodedResult); + $resultData = unserialize($serializedResultData); + if($response_data && empty($resultData))$resultData['validation'] = 'invalid validation key'; + }else + { + $resultData = array(); + $resultData['versions'] = array(); + + } + + if($response_data || !$sclient->getError() ) + { + if(!empty($resultData['msg'])){ + if(!empty($resultData['msg']['admin'])){ + $license->saveSetting('license', 'msg_admin', base64_encode($resultData['msg']['admin'])); + }else{ + $license->saveSetting('license', 'msg_admin',''); + } + if(!empty($resultData['msg']['all'])){ + $license->saveSetting('license', 'msg_all', base64_encode($resultData['msg']['all'])); + }else{ + $license->saveSetting('license', 'msg_all',''); + } + }else{ + $license->saveSetting('license', 'msg_admin',''); + $license->saveSetting('license', 'msg_all',''); + } + $license->saveSetting('license', 'last_validation', 'success'); + unset($_SESSION['COULD_NOT_CONNECT']); + } + else + { + $resultData = array(); + $resultData['versions'] = array(); + + $license->saveSetting('license', 'last_connection_fail', TimeDate::getInstance()->nowDb()); + $license->saveSetting('license', 'last_validation', 'no_connection'); + + if( empty($license->settings['license_last_validation_success']) && empty($license->settings['license_last_validation_fail']) && empty($license->settings['license_vk_end_date'])){ + $license->saveSetting('license', 'vk_end_date', TimeDate::getInstance()->nowDb()); + + $license->saveSetting('license', 'validation_key', base64_encode(serialize(array('verified'=>false)))); + } + $_SESSION['COULD_NOT_CONNECT'] =TimeDate::getInstance()->nowDb(); + + } + if(!empty($resultData['versions'])){ + + $license->saveSetting('license', 'latest_versions',base64_encode(serialize($resultData['versions']))); + }else{ + $resultData['versions'] = array(); + $license->saveSetting('license', 'latest_versions','') ; + } + + + + + include('sugar_version.php'); + + if(sizeof($resultData) == 1 && !empty($resultData['versions'][0]['version']) && $resultData['versions'][0]['version'] < $sugar_version) + { + $resultData['versions'][0]['version'] = $sugar_version; + $resultData['versions'][0]['description'] = "You have the latest version."; + } + + + return $resultData['versions']; +} +function set_CheckUpdates_config_setting($value) { + + + $admin=new Administration(); + $admin->saveSetting('Update','CheckUpdates',$value); +} +/* return's value for the 'CheckUpdates' config setting +* if the setting does not exist one gets created with a default value of automatic. +*/ +function get_CheckUpdates_config_setting() { + + $checkupdates='automatic'; + + + $admin=new Administration(); + $admin=$admin->retrieveSettings('Update',true); + if (empty($admin->settings) or empty($admin->settings['Update_CheckUpdates'])) { + $admin->saveSetting('Update','CheckUpdates','automatic'); + } else { + $checkupdates=$admin->settings['Update_CheckUpdates']; + } + return $checkupdates; +} + +function set_last_check_version_config_setting($value) { + + + $admin=new Administration(); + $admin->saveSetting('Update','last_check_version',$value); +} +function get_last_check_version_config_setting() { + + + + $admin=new Administration(); + $admin=$admin->retrieveSettings('Update'); + if (empty($admin->settings) or empty($admin->settings['Update_last_check_version'])) { + return null; + } else { + return $admin->settings['Update_last_check_version']; + } +} + + +function set_last_check_date_config_setting($value) { + + + $admin=new Administration(); + $admin->saveSetting('Update','last_check_date',$value); +} +function get_last_check_date_config_setting() { + + + + $admin=new Administration(); + $admin=$admin->retrieveSettings('Update'); + if (empty($admin->settings) or empty($admin->settings['Update_last_check_date'])) { + return 0; + } else { + return $admin->settings['Update_last_check_date']; + } +} + +function set_sugarbeat($value) { + global $sugar_config; + $_SUGARBEAT="sugarbeet"; + $sugar_config[$_SUGARBEAT] = $value; + write_array_to_file( "sugar_config", $sugar_config, "config.php" ); +} +function get_sugarbeat() { + + + global $sugar_config; + $_SUGARBEAT="sugarbeet"; + + if (isset($sugar_config[$_SUGARBEAT]) && $sugar_config[$_SUGARBEAT] == false) { + return false; + } + return true; + +} + + + +function shouldCheckSugar(){ + global $license, $timedate; + if( + + get_CheckUpdates_config_setting() == 'automatic' ){ + return true; + } + + return false; +} + + + +function loadLicense($firstLogin=false){ + + $GLOBALS['license']=new Administration(); + $GLOBALS['license']=$GLOBALS['license']->retrieveSettings('license', $firstLogin); + +} + +function loginLicense(){ + global $current_user, $license, $authLevel; + loadLicense(true); + + $authLevel = 0; + + if (shouldCheckSugar()) { + + + $last_check_date=get_last_check_date_config_setting(); + $current_date_time=time(); + $time_period=3*23*3600 ; + if (($current_date_time - $last_check_date) > $time_period + ) { + $version = check_now(get_sugarbeat()); + + unset($_SESSION['license_seats_needed']); + loadLicense(); + set_last_check_date_config_setting("$current_date_time"); + include('sugar_version.php'); + + if(!empty($version)&& count($version) == 1 && $version[0]['version'] > $sugar_version && is_admin($current_user)) + { + //set session variables. + $_SESSION['available_version']=$version[0]['version']; + $_SESSION['available_version_description']=$version[0]['description']; + set_last_check_version_config_setting($version[0]['version']); + } + } + } + + +} + + + + + + + + +?> diff --git a/modules/Administration/upgrade_custom_relationships.php b/modules/Administration/upgrade_custom_relationships.php new file mode 100644 index 00000000..40678ad9 --- /dev/null +++ b/modules/Administration/upgrade_custom_relationships.php @@ -0,0 +1,122 @@ +getRelationshipList(); + foreach($relList as $relName) + { + $relObject = $depRels->get($relName); + $def = $relObject->getDefinition(); + //We only need to fix self referencing one to many relationships + if ($def['lhs_module'] == $def['rhs_module'] && $def['is_custom'] && $def['relationship_type'] == "one-to-many") + { + $layout_defs = array(); + if (!is_dir("custom/Extension/modules/$module/Ext/Layoutdefs") || !is_dir("custom/Extension/modules/$module/Ext/Vardefs")) + continue; + //Find the extension file containing the vardefs for this relationship + foreach(scandir("custom/Extension/modules/$module/Ext/Vardefs") as $file) + { + if (substr($file,0,1) != "." && strtolower(substr($file, -4)) == ".php") + { + $dictionary = array($module => array("fields" => array())); + $filePath = "custom/Extension/modules/$module/Ext/Vardefs/$file"; + include($filePath); + if(isset($dictionary[$module]["fields"][$relName])) + { + $rhsDef = $dictionary[$module]["fields"][$relName]; + //Update the vardef for the left side link field + if (!isset($rhsDef['side']) || $rhsDef['side'] != 'left') + { + $rhsDef['side'] = 'left'; + $fileContents = file_get_contents($filePath); + $out = preg_replace( + '/\$dictionary[\w"\'\[\]]*?' . $relName . '["\'\[\]]*?\s*?=\s*?array\s*?\(.*?\);/s', + '$dictionary["' . $module . '"]["fields"]["' . $relName . '"]=' . var_export_helper($rhsDef) . ";", + $fileContents + ); + file_put_contents($filePath, $out); + } + } + } + } + //Find the extension file containing the subpanel definition for this relationship + foreach(scandir("custom/Extension/modules/$module/Ext/Layoutdefs") as $file) + { + if (substr($file,0,1) != "." && strtolower(substr($file, -4)) == ".php") + { + $layout_defs = array($module => array("subpanel_setup" => array())); + $filePath = "custom/Extension/modules/$module/Ext/Layoutdefs/$file"; + include($filePath); + foreach($layout_defs[$module]["subpanel_setup"] as $key => $subDef) + { + if ($layout_defs[$module]["subpanel_setup"][$key]['get_subpanel_data'] == $relName) + { + $fileContents = file_get_contents($filePath); + $out = preg_replace( + '/[\'"]get_subpanel_data[\'"]\s*=>\s*[\'"]' . $relName . '[\'"],/s', + "'get_subpanel_data' => '{$def["join_key_lhs"]}',", + $fileContents + ); + file_put_contents($filePath, $out); + } + } + } + } + } + } + } +} + +if (isset($_REQUEST['execute']) && $_REQUEST['execute']) + upgrade_custom_relationships(); \ No newline at end of file diff --git a/modules/Administration/vardefs.php b/modules/Administration/vardefs.php new file mode 100644 index 00000000..a059d0fc --- /dev/null +++ b/modules/Administration/vardefs.php @@ -0,0 +1,149 @@ + 'config', 'comment' => 'System table containing system-wide definitions' + ,'fields' => array ( + 'category' => + array ( + 'name' => 'category', + 'vname' => 'LBL_LIST_SYMBOL', + 'type' => 'varchar', + 'len' => '32', + 'comment' => 'Settings are grouped under this category; arbitraily defined based on requirements' + ), + 'name' => + array ( + 'name' => 'name', + 'vname' => 'LBL_LIST_NAME', + 'type' => 'varchar', + 'len' => '32', + 'comment' => 'The name given to the setting' + ), + 'value' => + array ( + 'name' => 'value', + 'vname' => 'LBL_LIST_RATE', + 'type' => 'text', + 'comment' => 'The value given to the setting' + ), + +), 'indices'=>array( array('name'=>'idx_config_cat', 'type'=>'index', 'fields'=>array('category')),) + ); + +$dictionary['UpgradeHistory'] = array( + 'table' => 'upgrade_history', 'comment' => 'Tracks Sugar upgrades made over time; used by Upgrade Wizard and Module Loader', + 'fields' => array ( + 'id' => array ( + 'name' => 'id', + 'type' => 'id', + 'required' => true, + 'reportable' => false, + 'comment' => 'Unique identifier' + ), + 'filename' => array ( + 'name' => 'filename', + 'type' => 'varchar', + 'len' => '255', + 'comment' => 'Cached filename containing the upgrade scripts and content' + ), + 'md5sum' => array ( + 'name' => 'md5sum', + 'type' => 'varchar', + 'len' => '32', + 'comment' => 'The MD5 checksum of the upgrade file' + ), + 'type' => array ( + 'name' => 'type', + 'type' => 'varchar', + 'len' => '30', + 'comment' => 'The upgrade type (module, patch, theme, etc)' + ), + 'status' => array ( + 'name' => 'status', + 'type' => 'varchar', + 'len' => '50', + 'comment' => 'The status of the upgrade (ex: "installed")', + ), + 'version' => array ( + 'name' => 'version', + 'type' => 'varchar', + 'len' => '10', + 'comment' => 'Version as contained in manifest file' + ), + 'name' => array ( + 'name' => 'name', + 'type' => 'varchar', + 'len' => '255', + ), + 'description' => array ( + 'name' => 'description', + 'type' => 'text', + ), + 'id_name' => array ( + 'name' => 'id_name', + 'type' => 'varchar', + 'len' => '255', + 'comment' => 'The unique id of the module' + ), + 'manifest' => array ( + 'name' => 'manifest', + 'type' => 'longtext', + 'comment' => 'A serialized copy of the manifest file.' + ), + 'date_entered' => array ( + 'name' => 'date_entered', + 'type' => 'datetime', + 'required'=>true, + 'comment' => 'Date of upgrade or module load' + ), + 'enabled' => array( + 'name' => 'enabled', + 'type' => 'bool', + 'len' => '1', + 'default' => '1', + ), + ), + + 'indices' => array( + array('name'=>'upgrade_history_pk', 'type'=>'primary', 'fields'=>array('id')), + array('name'=>'upgrade_history_md5_uk', 'type'=>'unique', 'fields'=>array('md5sum')), + + ), +); + + +?> diff --git a/modules/Administration/views/view.backups.php b/modules/Administration/views/view.backups.php new file mode 100644 index 00000000..7f6acae8 --- /dev/null +++ b/modules/Administration/views/view.backups.php @@ -0,0 +1,189 @@ +".$mod_strings['LBL_MODULE_NAME']."", + $mod_strings['LBL_BACKUPS_TITLE'] + ); + } + + /** + * @see SugarView::preDisplay() + */ + public function preDisplay() + { + global $current_user; + + if (!is_admin($current_user)) { + sugar_die("Unauthorized access to administration."); + } + } + + /** + * @see SugarView::display() + */ + public function display() + { + require_once('include/utils/zip_utils.php'); + + $form_action = "index.php?module=Administration&action=Backups"; + + $backup_dir = ""; + $backup_zip = ""; + $run = "confirm"; + $input_disabled = ""; + global $mod_strings; + $errors = array(); + + // process "run" commands + if( isset( $_REQUEST['run'] ) && ($_REQUEST['run'] != "") ){ + $run = $_REQUEST['run']; + + $backup_dir = $_REQUEST['backup_dir']; + $backup_zip = $_REQUEST['backup_zip']; + + if( $run == "confirm" ){ + if( $backup_dir == "" ){ + $errors[] = $mod_strings['LBL_BACKUP_DIRECTORY_ERROR']; + } + if( $backup_zip == "" ){ + $errors[] = $mod_strings['LBL_BACKUP_FILENAME_ERROR']; + } + + if( sizeof($errors) > 0 ){ + return( $errors ); + } + + if( !is_dir( $backup_dir ) ){ + if( !mkdir_recursive( $backup_dir ) ){ + $errors[] = $mod_strings['LBL_BACKUP_DIRECTORY_EXISTS']; + } + } + + if( !is_writable( $backup_dir ) ){ + $errors[] = $mod_strings['LBL_BACKUP_DIRECTORY_NOT_WRITABLE']; + } + + if( is_file( "$backup_dir/$backup_zip" ) ){ + $errors[] = $mod_strings['LBL_BACKUP_FILE_EXISTS']; + } + if( is_dir( "$backup_dir/$backup_zip" ) ){ + $errors[] = $mod_strings['LBL_BACKUP_FILE_AS_SUB']; + } + if( sizeof( $errors ) == 0 ){ + $run = "confirmed"; + $input_disabled = "readonly"; + } + } + else if( $run == "confirmed" ){ + ini_set( "memory_limit", "-1" ); + ini_set( "max_execution_time", "0" ); + zip_dir( ".", "$backup_dir/$backup_zip" ); + $run = "done"; + } + } + if( sizeof($errors) > 0 ){ + foreach( $errors as $error ){ + print( "$error
    " ); + } + } + if( $run == "done" ){ + $size = filesize( "$backup_dir/$backup_zip" ); + print( $mod_strings['LBL_BACKUP_FILE_STORED'] . " $backup_dir/$backup_zip ($size bytes).
    \n" ); + print( "" . $mod_strings['LBL_BACKUP_BACK_HOME']. "\n" ); + } + else{ + ?> + + ".translate('LBL_MODULE_NAME','Administration')."", + $mod_strings['LBL_BACKUPS_TITLE'], + ), + false + ); + echo $mod_strings['LBL_BACKUP_INSTRUCTIONS_1']; ?> +
    +
    +
    + + + + + + + + + +

    value=""/>
    value=""/>
    + + + + + +
    + + + +
    + + info( "Backups" ); + } +} diff --git a/modules/Administration/views/view.configuretabs.php b/modules/Administration/views/view.configuretabs.php new file mode 100644 index 00000000..094455dc --- /dev/null +++ b/modules/Administration/views/view.configuretabs.php @@ -0,0 +1,137 @@ +".$mod_strings['LBL_MODULE_NAME']."", + $mod_strings['LBL_CONFIG_TABS'] + ); + } + + /** + * @see SugarView::preDisplay() + */ + public function preDisplay() + { + global $current_user; + + if (!is_admin($current_user)) { + sugar_die("Unauthorized access to administration."); + } + } + + /** + * @see SugarView::display() + */ + public function display() + { + global $mod_strings; + global $app_list_strings; + global $app_strings; + + require_once("modules/MySettings/TabController.php"); + $controller = new TabController(); + $tabs = $controller->get_tabs_system(); + + $enabled= array(); + foreach ($tabs[0] as $key=>$value) + { + $enabled[] = array("module" => $key, 'label' => translate($key)); + } + $disabled = array(); + foreach ($tabs[1] as $key=>$value) + { + $disabled[] = array("module" => $key, 'label' => translate($key)); + } + + $user_can_edit = $controller->get_users_can_edit(); + $this->ss->assign('APP', $GLOBALS['app_strings']); + $this->ss->assign('MOD', $GLOBALS['mod_strings']); + $this->ss->assign('user_can_edit', $user_can_edit); + $this->ss->assign('enabled_tabs', json_encode($enabled)); + $this->ss->assign('disabled_tabs', json_encode($disabled)); + $this->ss->assign('title',$this->getModuleTitle(false)); + + //get list of all subpanels and panels to hide + $mod_list_strings_key_to_lower = array_change_key_case($app_list_strings['moduleList']); + $panels_arr = SubPanelDefinitions::get_all_subpanels(); + $hidpanels_arr = SubPanelDefinitions::get_hidden_subpanels(); + + if(!$hidpanels_arr || !is_array($hidpanels_arr)) $hidpanels_arr = array(); + + //create array of subpanels to show, used to create Drag and Drop widget + $enabled = array(); + foreach ($panels_arr as $key) { + if(empty($key)) continue; + $key = strtolower($key); + $enabled[] = array("module" => $key, "label" => $mod_list_strings_key_to_lower[$key]); + } + + //now create array of subpanels to hide for use in Drag and Drop widget + $disabled = array(); + foreach ($hidpanels_arr as $key) { + if(empty($key)) continue; + $key = strtolower($key); + $disabled[] = array("module" => $key, "label" => $mod_list_strings_key_to_lower[$key]); + } + + $this->ss->assign('enabled_panels', json_encode($enabled)); + $this->ss->assign('disabled_panels', json_encode($disabled)); + + echo $this->ss->fetch('modules/Administration/templates/ConfigureTabs.tpl'); + } +} diff --git a/modules/Administration/views/view.globalsearchsettings.php b/modules/Administration/views/view.globalsearchsettings.php new file mode 100644 index 00000000..f7b1c01e --- /dev/null +++ b/modules/Administration/views/view.globalsearchsettings.php @@ -0,0 +1,85 @@ +".translate('LBL_MODULE_NAME','Administration')."", + $mod_strings['LBL_GLOBAL_SEARCH_SETTINGS'] + ); + } + + /** + * @see SugarView::_getModuleTab() + */ + protected function _getModuleTab() + { + return 'Administration'; + } + + /** + * @see SugarView::display() + */ + public function display() + { + global $mod_strings; + + echo ' + "; +if ($focus->parent_type == "Accounts") $button .= "\n"; +else $button .= "\n"; +$button .= "\n"; +$button .= "

    ' . $this->getModuleTitle(false) . + '

    ' . + $mod_strings['LBL_GLOBAL_SEARCH_SETTINGS_TITLE'] . + '

    '; + + //echo $this->getModuleTitle(); + require_once('modules/Home/UnifiedSearchAdvanced.php'); + $usa = new UnifiedSearchAdvanced(); + + + + echo $usa->modifyGlobalSearchSettings(); + } +} +?> \ No newline at end of file diff --git a/modules/Administration/views/view.languages.php b/modules/Administration/views/view.languages.php new file mode 100644 index 00000000..22e026ab --- /dev/null +++ b/modules/Administration/views/view.languages.php @@ -0,0 +1,109 @@ +".$mod_strings['LBL_MODULE_NAME']."", + $mod_strings['LBL_MANAGE_LANGUAGES'] + ); + } + + /** + * @see SugarView::preDisplay() + */ + public function preDisplay() + { + global $current_user; + + if (!is_admin($current_user)) { + sugar_die("Unauthorized access to administration."); + } + } + + /** + * @see SugarView::display() + */ + public function display() + { + global $mod_strings; + global $app_list_strings; + global $app_strings; + global $sugar_config; + + $disabled = array(); + $disabled_list = array(); + if ( isset($sugar_config['disabled_languages'])) { + if(!is_array($sugar_config['disabled_languages'])){ + $disabled_list = array_flip(explode(',', $sugar_config['disabled_languages'])); + }else{ + $disabled_list = array_flip($sugar_config['disabled_languages']); + } + } + foreach ($sugar_config['languages'] as $key=>$value) + { + if(isset($disabled_list[$key])) { + $disabled[] = array("module" => $key, 'label' => $value); + } else { + $enabled[] = array("module" => $key, 'label' => $value); + } + } + + $this->ss->assign('APP', $GLOBALS['app_strings']); + $this->ss->assign('MOD', $GLOBALS['mod_strings']); + $this->ss->assign('enabled_langs', json_encode($enabled)); + $this->ss->assign('disabled_langs', json_encode($disabled)); + $this->ss->assign('title',$this->getModuleTitle(false)); + + echo $this->ss->fetch('modules/Administration/templates/Languages.tpl'); + } +} diff --git a/modules/Administration/views/view.repair.php b/modules/Administration/views/view.repair.php new file mode 100644 index 00000000..d15f267b --- /dev/null +++ b/modules/Administration/views/view.repair.php @@ -0,0 +1,61 @@ +repairAndClearAll(array('clearAll'),array(translate('LBL_ALL_MODULES')), false,true); + + echo <<
    {$GLOBALS['mod_strings']['LBL_DIAGNOSTIC_DELETE_RETURN']} +EOHTML; + } +} diff --git a/modules/Administration/views/view.themesettings.php b/modules/Administration/views/view.themesettings.php new file mode 100644 index 00000000..f70f3088 --- /dev/null +++ b/modules/Administration/views/view.themesettings.php @@ -0,0 +1,119 @@ +".$mod_strings['LBL_MODULE_NAME']."", + $mod_strings['LBL_THEME_SETTINGS'] + ); + } + + /** + * @see SugarView::process() + */ + public function process() + { + global $current_user; + if (!is_admin($current_user)) sugar_die("Unauthorized access to administration."); + + if (isset($_REQUEST['disabled_themes']) ) { + $toDecode = html_entity_decode ($_REQUEST['disabled_themes'], ENT_QUOTES); + $disabledThemes = json_decode($toDecode, true); + if ( ($key = array_search(SugarThemeRegistry::current()->__toString(),$disabledThemes)) !== FALSE ) { + unset($disabledThemes[$key]); + } + $_REQUEST['disabled_themes'] = implode(',',$disabledThemes); + $configurator = new Configurator(); + $configurator->config['disabled_themes'] = $_REQUEST['disabled_themes']; + $configurator->config['default_theme'] = $_REQUEST['default_theme']; + $configurator->handleOverride(); + echo "true"; + } else { + parent::process(); + } + } + + /** + * display the form + */ + public function display() + { + global $mod_strings, $app_strings, $current_user; + + if ( !is_admin($current_user) ) + sugar_die($GLOBALS['app_strings']['ERR_NOT_ADMIN']); + + $enabled = array(); + foreach(SugarThemeRegistry::availableThemes() as $dir => $theme) + { + $enabled[] = array("theme" => $theme, "dir" => $dir); + } + $disabled = array(); + foreach(SugarThemeRegistry::unAvailableThemes() as $dir => $theme) + { + $disabled[] = array("theme" => $theme, "dir" => $dir); + } + $this->ss->assign("THEMES", get_select_options_with_id(SugarThemeRegistry::allThemes(), $GLOBALS['sugar_config']['default_theme'])); + $this->ss->assign('enabled_modules', json_encode($enabled)); + $this->ss->assign('disabled_modules', json_encode($disabled)); + $this->ss->assign('mod', $mod_strings); + $this->ss->assign('APP', $app_strings); + $this->ss->assign('currentTheme', SugarThemeRegistry::current()); + + echo $this->getModuleTitle(false); + echo $this->ss->fetch('modules/Administration/templates/themeSettings.tpl'); + } +} diff --git a/modules/Audit/Audit.php b/modules/Audit/Audit.php new file mode 100644 index 00000000..d8f2b89a --- /dev/null +++ b/modules/Audit/Audit.php @@ -0,0 +1,219 @@ +name; + } + + function create_export_query(&$order_by, &$where) + { + } + + function fill_in_additional_list_fields() + { + } + + function fill_in_additional_detail_fields() + { + } + + function fill_in_additional_parent_fields() + { + } + + function get_list_view_data() + { + } + + function get_audit_link() + { + + } + + function get_audit_list() + { + + global $focus, $genericAssocFieldsArray, $moduleAssocFieldsArray, $current_user, $timedate, $app_strings; + $audit_list = array(); + if(!empty($_REQUEST['record'])) { + $result = $focus->retrieve($_REQUEST['record']); + + if($result == null || !$focus->ACLAccess('', $focus->isOwner($current_user->id))) + { + sugar_die($app_strings['ERROR_NO_RECORD']); + } + } + + if($focus->is_AuditEnabled()){ + $order= ' order by '.$focus->get_audit_table_name().'.date_created desc' ;//order by contacts_audit.date_created desc + $query = "SELECT ".$focus->get_audit_table_name().".*, users.user_name FROM ".$focus->get_audit_table_name().", users WHERE ".$focus->get_audit_table_name().".created_by = users.id AND ".$focus->get_audit_table_name().".parent_id = '$focus->id'".$order; + + $result = $focus->db->query($query); + // We have some data. + require('metadata/audit_templateMetaData.php'); + $fieldDefs = $dictionary['audit']['fields']; + while (($row = $focus->db->fetchByAssoc($result))!= null) { + $temp_list = array(); + + foreach($fieldDefs as $field){ + if(isset($row[$field['name']])) { + if(($field['name'] == 'before_value_string' || $field['name'] == 'after_value_string') && + (array_key_exists($row['field_name'], $genericAssocFieldsArray) || (!empty($moduleAssocFieldsArray[$focus->object_name]) && array_key_exists($row['field_name'], $moduleAssocFieldsArray[$focus->object_name])) ) + ) { + + $temp_list[$field['name']] = Audit::getAssociatedFieldName($row['field_name'], $row[$field['name']]); + } else{ + $temp_list[$field['name']] = $row[$field['name']]; + } + + if ($field['name'] == 'date_created') { + $temp_list[$field['name']]=$timedate->to_display_date_time($temp_list[$field['name']]); + } + if(($field['name'] == 'before_value_string' || $field['name'] == 'after_value_string') && ($row['data_type'] == "enum" || $row['data_type'] == "multienum")) + { + global $app_list_strings; + $enum_keys = unencodeMultienum($temp_list[$field['name']]); + $enum_values = array(); + foreach($enum_keys as $enum_key) { + if(isset($focus->field_defs[$row['field_name']]['options'])) { + $domain = $focus->field_defs[$row['field_name']]['options']; + if(isset($app_list_strings[$domain][$enum_key])) + $enum_values[] = $app_list_strings[$domain][$enum_key]; + } + } + if(!empty($enum_values)){ + $temp_list[$field['name']] = implode(', ', $enum_values); + } + if($temp_list['data_type']==='date'){ + $temp_list[$field['name']]=$timedate->to_display_date($temp_list[$field['name']], false); + } + } + elseif($field['name'] == 'field_name') + { + global $mod_strings; + if(isset($focus->field_defs[$row['field_name']]['vname'])) { + $label = $focus->field_defs[$row['field_name']]['vname']; + $temp_list[$field['name']] = translate($label, $focus->module_dir); + } + } + } + } + + $temp_list['created_by'] = $row['user_name']; + $audit_list[] = $temp_list; + } + } + return $audit_list; + } + + function getAssociatedFieldName($fieldName, $fieldValue){ + global $focus, $genericAssocFieldsArray, $moduleAssocFieldsArray; + + if(!empty($moduleAssocFieldsArray[$focus->object_name]) && array_key_exists($fieldName, $moduleAssocFieldsArray[$focus->object_name])){ + $assocFieldsArray = $moduleAssocFieldsArray[$focus->object_name]; + + } + else if(array_key_exists($fieldName, $genericAssocFieldsArray)){ + $assocFieldsArray = $genericAssocFieldsArray; + } + else{ + return $fieldValue; + } + $query = ""; + $field_arr = $assocFieldsArray[$fieldName]; + $query = "SELECT "; + if(is_array($field_arr['select_field_name'])){ + $count = count($field_arr['select_field_name']); + $index = 1; + foreach($field_arr['select_field_name'] as $col){ + $query .= $col; + if($index < $count){ + $query .= ", "; + } + $index++; + } + } + else{ + $query .= $field_arr['select_field_name']; + } + + $query .= " FROM ".$field_arr['table_name']." WHERE ".$field_arr['select_field_join']." = '".$fieldValue."'"; + + $result = $focus->db->query($query); + if(!empty($result)){ + if($row = $focus->db->fetchByAssoc($result)){ + if(is_array($field_arr['select_field_name'])){ + $returnVal = ""; + foreach($field_arr['select_field_name'] as $col){ + $returnVal .= $row[$col]." "; + } + return $returnVal; + } + else{ + return $row[$field_arr['select_field_name']]; + } + } + } + } +} +?> \ No newline at end of file diff --git a/modules/Audit/Popup_picker.html b/modules/Audit/Popup_picker.html new file mode 100644 index 00000000..5d711ea1 --- /dev/null +++ b/modules/Audit/Popup_picker.html @@ -0,0 +1,65 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    {MOD.LBL_FIELD_NAME}{MOD.LBL_OLD_NAME}{MOD.LBL_NEW_VALUE}{MOD.LBL_CREATED_BY}{MOD.LBL_LIST_DATE}
    {ACTIVITY_MODULE_PNG}{ACTIVITY.NAME}{ACTIVITY.BEFORE_VALUE}{ACTIVITY.AFTER_VALUE}{ACTIVITY.CREATED_BY}{ACTIVITY.DATE_CREATED}
    + \ No newline at end of file diff --git a/modules/Audit/Popup_picker.php b/modules/Audit/Popup_picker.php new file mode 100644 index 00000000..51454436 --- /dev/null +++ b/modules/Audit/Popup_picker.php @@ -0,0 +1,201 @@ +assign('MOD', $mod_strings); + $xtpl->assign('APP', $app_strings); + insert_popup_header($theme); + + //output header + echo " +"; + + if($args['show_link'] == 'on') { + template_echo_slice_date($args); + } else { + template_echo_slice_date_nolink($args); + } + + template_echo_slice_activities_shared($args); + + echo ""; +} + +function template_calendar_year($args) { + $count = 0; +?> +
    "; + $mod_strings = return_module_language($current_language, $focus->module_dir); + + $printImageURL = SugarThemeRegistry::current()->getImageURL('print.gif'); + $titleExtra = << +{$GLOBALS['app_strings']['LNK_PRINT']} + +{$GLOBALS['app_strings']['LNK_PRINT']} + +EOHTML; + + $params = array(); + $params[] = translate('LBL_MODULE_NAME', $focus->module_dir); + $params[] = $focus->get_summary_text(); + $params[] = translate('LBL_CHANGE_LOG', 'Audit'); + echo str_replace('',"$titleExtra",getClassicModuleTitle($focus->module_dir, $params, false)); + + $oddRow = true; + $audited_fields = $focus->getAuditEnabledFieldDefinitions(); + asort($audited_fields); + $fields = ''; + $field_count = count($audited_fields); + $start_tag = "
    "; + $end_tag = "
    "; + + if($field_count > 0) + { + $index = 0; + foreach($audited_fields as $key=>$value) + { + $index++; + $vname = ''; + if(isset($value['vname'])) + $vname = $value['vname']; + else if(isset($value['label'])) + $vname = $value['label']; + $fields .= str_replace(':', '', translate($vname, $focus->module_dir)); + + if($index < $field_count) + { + $fields .= ", "; + } + } + + echo $start_tag.translate('LBL_AUDITED_FIELDS', 'Audit').$fields.$end_tag; + } + else + { + echo $start_tag.translate('LBL_AUDITED_FIELDS', 'Audit').$end_tag; + } + + foreach($audit_list as $audit) + { + if(empty($audit['before_value_string']) && empty($audit['after_value_string'])) + { + $before_value = $audit['before_value_text']; + $after_value = $audit['after_value_text']; + } + else { + $before_value = $audit['before_value_string']; + $after_value = $audit['after_value_string']; + } + + // Let's run the audit data through the sugar field system + if(isset($audit['data_type'])){ + require_once('include/SugarFields/SugarFieldHandler.php'); + $vardef = array('name'=>'audit_field','type'=>$audit['data_type']); + $field = SugarFieldHandler::getSugarField($audit['data_type']); + $before_value = $field->getChangeLogSmarty(array($vardef['name']=>$before_value), $vardef, array(), $vardef['name']); + $after_value = $field->getChangeLogSmarty(array($vardef['name']=>$after_value), $vardef, array(), $vardef['name']); + } + + $activity_fields = array( + 'ID' => $audit['id'], + 'NAME' => $audit['field_name'], + 'BEFORE_VALUE' => $before_value, + 'AFTER_VALUE' => $after_value, + 'CREATED_BY' => $audit['created_by'], + 'DATE_CREATED' => $audit['date_created'], + ); + + $xtpl->assign("ACTIVITY", $activity_fields); + + if($oddRow) + { + //todo move to themes + $xtpl->assign("ROW_COLOR", 'oddListRow'); + $xtpl->assign("BG_COLOR", $odd_bg); + } + else + { + //todo move to themes + $xtpl->assign("ROW_COLOR", 'evenListRow'); + $xtpl->assign("BG_COLOR", $even_bg); + } + $oddRow = !$oddRow; + + $xtpl->parse("audit.row"); + // Put the rows in. + }//end foreach + + $xtpl->parse("audit"); + $xtpl->out("audit"); + insert_popup_footer(); + } +} // end of class Popup_Picker +?> \ No newline at end of file diff --git a/modules/Audit/field_assoc.php b/modules/Audit/field_assoc.php new file mode 100644 index 00000000..3a8306af --- /dev/null +++ b/modules/Audit/field_assoc.php @@ -0,0 +1,86 @@ + + array('table_name' => 'users', + 'select_field_name' => 'user_name', + 'select_field_join' => 'id', + ), + 'account_id' => + array('table_name' => 'accounts', + 'select_field_name' => 'name', + 'select_field_join' => 'id', + ), + 'contact_id' => + array('table_name' => 'contacts', + 'select_field_name' => + array('first_name', + 'last_name', + ), + 'select_field_join' => 'id', + ), + 'fixed_in_release' => + array('table_name' => 'releases', + 'select_field_name' => 'name', + 'select_field_join' => 'id', + ), + 'found_in_release' => + array('table_name' => 'releases', + 'select_field_name' => 'name', + 'select_field_join' => 'id', + ), + ); +$moduleAssocFieldsArray = array('Account' => + array('parent_id' => + array('table_name' => 'accounts', + 'select_field_name' => 'name', + 'select_field_join' => 'id', + ) + ), + ); + +?> \ No newline at end of file diff --git a/modules/Audit/language/en_us.lang.php b/modules/Audit/language/en_us.lang.php new file mode 100644 index 00000000..0066e7c4 --- /dev/null +++ b/modules/Audit/language/en_us.lang.php @@ -0,0 +1,50 @@ + 'Field', + 'LBL_OLD_NAME' => 'Old Value', + 'LBL_NEW_VALUE' => 'New Value', + 'LBL_CREATED_BY' => 'Changed By', + 'LBL_LIST_DATE' => 'Change Date', + 'LBL_AUDITED_FIELDS' => 'Fields audited in this module: ', + 'LBL_NO_AUDITED_FIELDS_TEXT' => 'There are no fields audited in this module', + 'LBL_CHANGE_LOG' => 'Change Log', +); \ No newline at end of file diff --git a/modules/Audit/vardefs.php b/modules/Audit/vardefs.php new file mode 100644 index 00000000..e48083d1 --- /dev/null +++ b/modules/Audit/vardefs.php @@ -0,0 +1,39 @@ + \ No newline at end of file diff --git a/modules/BeanDictionary.php b/modules/BeanDictionary.php new file mode 100644 index 00000000..c56642d5 --- /dev/null +++ b/modules/BeanDictionary.php @@ -0,0 +1,40 @@ + diff --git a/modules/Bugs/Bug.php b/modules/Bugs/Bug.php new file mode 100644 index 00000000..f9c73ce6 --- /dev/null +++ b/modules/Bugs/Bug.php @@ -0,0 +1,397 @@ +'cases', 'account_id' => 'accounts', 'contact_id'=>'contacts', + 'task_id'=>'tasks', 'note_id'=>'notes', 'meeting_id'=>'meetings', + 'call_id'=>'calls', 'email_id'=>'emails'); + + function Bug() { + parent::SugarBean(); + + + $this->setupCustomFields('Bugs'); + + foreach ($this->field_defs as $field) + { + $this->field_name_map[$field['name']] = $field; + } + + } + + var $new_schema = true; + + + + + + function get_summary_text() + { + return "$this->name"; + } + + function create_list_query($order_by, $where, $show_deleted = 0) + { + // Fill in the assigned_user_name +// $this->assigned_user_name = get_assigned_user_name($this->assigned_user_id); + + $custom_join = $this->custom_fields->getJOIN(); + + $query = "SELECT "; + + $query .= " + bugs.* + + ,users.user_name as assigned_user_name, releases.id release_id, releases.name release_name"; + if($custom_join){ + $query .= $custom_join['select']; + } + $query .= " FROM bugs "; + + + $query .= " LEFT JOIN releases ON bugs.found_in_release=releases.id + LEFT JOIN users + ON bugs.assigned_user_id=users.id"; + $query .= " "; + if($custom_join){ + $query .= $custom_join['join']; + } + $where_auto = '1=1'; + if($show_deleted == 0){ + $where_auto = " $this->table_name.deleted=0 "; + }else if($show_deleted == 1){ + $where_auto = " $this->table_name.deleted=1 "; + } + + + if($where != "") + $query .= "where $where AND ".$where_auto; + else + $query .= "where ".$where_auto; + if(substr_count($order_by, '.') > 0){ + $query .= " ORDER BY $order_by"; + } + else if($order_by != "") + $query .= " ORDER BY $order_by"; + else + $query .= " ORDER BY bugs.name"; + return $query; + } + + function create_export_query(&$order_by, &$where, $relate_link_join='') + { + $custom_join = $this->custom_fields->getJOIN(true, true,$where); + if($custom_join) + $custom_join['join'] .= $relate_link_join; + $query = "SELECT + bugs.*, + r1.name found_in_release_name, + r2.name fixed_in_release_name, + users.user_name assigned_user_name"; + if($custom_join){ + $query .= $custom_join['select']; + } + $query .= " FROM bugs "; + $query .= " LEFT JOIN releases r1 ON bugs.found_in_release = r1.id + LEFT JOIN releases r2 ON bugs.fixed_in_release = r2.id + LEFT JOIN users + ON bugs.assigned_user_id=users.id"; + if($custom_join){ + $query .= $custom_join['join']; + } + $query .= ""; + $where_auto = " bugs.deleted=0 + "; + + if($where != "") + $query .= " where $where AND ".$where_auto; + else + $query .= " where ".$where_auto; + + if($order_by != "") + $query .= " ORDER BY $order_by"; + else + $query .= " ORDER BY bugs.bug_number"; + + return $query; + } + function fill_in_additional_list_fields() + { + parent::fill_in_additional_list_fields(); + // Fill in the assigned_user_name + //$this->assigned_user_name = get_assigned_user_name($this->assigned_user_id); + +// $this->set_fixed_in_release(); + } + + function fill_in_additional_detail_fields() + { + + /* + // Fill in the assigned_user_name + $this->assigned_user_name = get_assigned_user_name($this->assigned_user_id); + */ + parent::fill_in_additional_detail_fields(); + //$this->created_by_name = get_assigned_user_name($this->created_by); + //$this->modified_by_name = get_assigned_user_name($this->modified_user_id); + $this->set_release(); + $this->set_fixed_in_release(); + } + + + public function set_release() + { + static $releases; + + if ( empty($this->found_in_release) ) { + return; + } + if ( isset($releases[$this->found_in_release]) ) { + $this->release_name = $releases[$this->found_in_release]; + return; + } + + $query = "SELECT r1.name from releases r1, $this->table_name i1 where r1.id = i1.found_in_release and i1.id = '$this->id' and i1.deleted=0 and r1.deleted=0"; + $result = $this->db->query($query,true," Error filling in additional detail fields: "); + + // Get the id and the name. + $row = $this->db->fetchByAssoc($result); + + if($row != null) + { + $this->release_name = $row['name']; + } + else + { + $this->release_name = ''; + } + + $releases[$this->found_in_release] = $this->release_name; + } + + + public function set_fixed_in_release() + { + static $releases; + + if ( empty($this->fixed_in_release) ) { + return; + } + if ( isset($releases[$this->fixed_in_release]) ) { + $this->fixed_in_release_name = $releases[$this->fixed_in_release]; + return; + } + + $query = "SELECT r1.name from releases r1, $this->table_name i1 where r1.id = i1.fixed_in_release and i1.id = '$this->id' and i1.deleted=0 and r1.deleted=0"; + $result = $this->db->query($query,true," Error filling in additional detail fields: "); + + // Get the id and the name. + $row = $this->db->fetchByAssoc($result); + + + + if($row != null) + { + $this->fixed_in_release_name = $row['name']; + } + else + { + $this->fixed_in_release_name = ''; + } + + $releases[$this->fixed_in_release] = $this->fixed_in_release_name; + + } + + + function get_list_view_data(){ + global $current_language; + $the_array = parent::get_list_view_data(); + $app_list_strings = return_app_list_strings_language($current_language); + $mod_strings = return_module_language($current_language, 'Bugs'); + + $this->set_release(); + + // The new listview code only fetches columns that we're displaying and not all + // the columns so we need these checks. + $the_array['NAME'] = (($this->name == "") ? "blank" : $this->name); + if (!empty($this->priority)) + $the_array['PRIORITY'] = $app_list_strings['bug_priority_dom'][$this->priority]; + if (!empty($this->status)) + $the_array['STATUS'] =$app_list_strings['bug_status_dom'][$this->status]; + $the_array['RELEASE']= $this->release_name; + if (!empty($this->type)) + $the_array['TYPE']= $app_list_strings['bug_type_dom'][$this->type]; + $the_array['BUG_NUMBER'] = $this->bug_number; + $the_array['ENCODED_NAME']=$this->name; + + return $the_array; + } + + /** + builds a generic search based on the query string using or + do not include any $this-> because this is called on without having the class instantiated + */ + function build_generic_where_clause ($the_query_string) { + $where_clauses = Array(); + $the_query_string = $this->db->quote($the_query_string); + array_push($where_clauses, "bugs.name like '$the_query_string%'"); + if (is_numeric($the_query_string)) array_push($where_clauses, "bugs.bug_number like '$the_query_string%'"); + + $the_where = ""; + foreach($where_clauses as $clause) + { + if($the_where != "") $the_where .= " or "; + $the_where .= $clause; + } + + return $the_where; + } + + function set_notification_body($xtpl, $bug) + { + global $mod_strings, $app_list_strings; + + $bug->set_release(); + + $xtpl->assign("BUG_SUBJECT", $bug->name); + $xtpl->assign("BUG_TYPE", $app_list_strings['bug_type_dom'][$bug->type]); + $xtpl->assign("BUG_PRIORITY", $app_list_strings['bug_priority_dom'][$bug->priority]); + $xtpl->assign("BUG_STATUS", $app_list_strings['bug_status_dom'][$bug->status]); + $xtpl->assign("BUG_RESOLUTION", $app_list_strings['bug_resolution_dom'][$bug->resolution]); + $xtpl->assign("BUG_RELEASE", $bug->release_name); + $xtpl->assign("BUG_DESCRIPTION", $bug->description); + $xtpl->assign("BUG_WORK_LOG", $bug->work_log); + $xtpl->assign("BUG_BUG_NUMBER", $bug->bug_number); + return $xtpl; + } + + function bean_implements($interface){ + switch($interface){ + case 'ACL':return true; + } + return false; + } + + function save($check_notify = FALSE){ + return parent::save($check_notify); + } +} + +function getReleaseDropDown(){ + static $releases = null; + if(!$releases){ + $seedRelease = new Release(); + $releases = $seedRelease->get_releases(TRUE, "Active"); + } + return $releases; +} +?> \ No newline at end of file diff --git a/modules/Bugs/BugsQuickCreate.php b/modules/Bugs/BugsQuickCreate.php new file mode 100644 index 00000000..ca610d9b --- /dev/null +++ b/modules/Bugs/BugsQuickCreate.php @@ -0,0 +1,74 @@ +ss->assign("PRIORITY_OPTIONS", get_select_options_with_id($app_list_strings['bug_priority_dom'], $app_list_strings['bug_priority_default_key'])); + $this->ss->assign("STATUS_OPTIONS", get_select_options_with_id($app_list_strings['bug_status_dom'], $app_list_strings['bug_status_default_key'])); + $this->ss->assign("TYPE_OPTIONS", get_select_options_with_id($app_list_strings['bug_type_dom'],$app_list_strings['bug_type_default_key'])); + + if($this->viaAJAX) { // override for ajax call + $this->ss->assign('saveOnclick', "onclick='if(check_form(\"bugsQuickCreate\")) return SUGAR.subpanelUtils.inlineSave(this.form.id, \"bugs\"); else return false;'"); + $this->ss->assign('cancelOnclick', "onclick='return SUGAR.subpanelUtils.cancelCreate(\"subpanel_bugs\")';"); + } + + $this->ss->assign('viaAJAX', $this->viaAJAX); + + $this->javascript = new javascript(); + $this->javascript->setFormName('bugsQuickCreate'); + + $focus = new Bug(); + $this->javascript->setSugarBean($focus); + $this->javascript->addAllFields(''); + + $this->ss->assign('additionalScripts', $this->javascript->getScript(false)); + } +} +?> \ No newline at end of file diff --git a/modules/Bugs/Dashlets/MyBugsDashlet/MyBugsDashlet.data.php b/modules/Bugs/Dashlets/MyBugsDashlet/MyBugsDashlet.data.php new file mode 100644 index 00000000..027ede2f --- /dev/null +++ b/modules/Bugs/Dashlets/MyBugsDashlet/MyBugsDashlet.data.php @@ -0,0 +1,85 @@ + array('default' => ''), + '' => array('default' => ''), + 'priority' => array('default' => ''), + 'status' => array('default' => array('Assigned', 'New', 'Pending')), + 'type' => array('default' => ''), + 'name' => array('default' => ''), + 'assigned_user_id' => array('type' => 'assigned_user_name', + 'label' => 'LBL_ASSIGNED_TO', + 'default' => $current_user->name)); +$dashletData['MyBugsDashlet']['columns'] = array('bug_number' => array('width' => '5', + 'label' => 'LBL_NUMBER', + 'default' => true), + 'name' => array('width' => '40', + 'label' => 'LBL_LIST_SUBJECT', + 'link' => true, + 'default' => true), + 'priority' => array('width' => '10', + 'label' => 'LBL_PRIORITY', + 'default' => true), + 'status' => array('width' => '10', + 'label' => 'LBL_STATUS', + 'default' => true), + 'resolution' => array('width' => '15', + 'label' => 'LBL_RESOLUTION'), + 'release_name' => array('width' => '15', + 'label' => 'LBL_FOUND_IN_RELEASE', + 'related_fields' => array('found_in_release')), + 'type' => array('width' => '15', + 'label' => 'LBL_TYPE'), + 'fixed_in_release_name' => array('width' => '15', + 'label' => 'LBL_FIXED_IN_RELEASE'), + 'source' => array('width' => '15', + 'label' => 'LBL_SOURCE'), + 'date_entered' => array('width' => '15', + 'label' => 'LBL_DATE_ENTERED'), + 'date_modified' => array('width' => '15', + 'label' => 'LBL_DATE_MODIFIED'), + 'created_by' => array('width' => '8', + 'label' => 'LBL_CREATED'), + 'assigned_user_name' => array('width' => '8', + 'label' => 'LBL_LIST_ASSIGNED_USER'), + ); +?> diff --git a/modules/Bugs/Dashlets/MyBugsDashlet/MyBugsDashlet.meta.php b/modules/Bugs/Dashlets/MyBugsDashlet/MyBugsDashlet.meta.php new file mode 100644 index 00000000..3a42e024 --- /dev/null +++ b/modules/Bugs/Dashlets/MyBugsDashlet/MyBugsDashlet.meta.php @@ -0,0 +1,47 @@ + 'Bugs', + 'title' => translate('LBL_LIST_MY_BUGS', 'Bugs'), + 'description' => 'A customizable view into Bugs', + 'category' => 'Module Views'); +?> diff --git a/modules/Bugs/Dashlets/MyBugsDashlet/MyBugsDashlet.php b/modules/Bugs/Dashlets/MyBugsDashlet/MyBugsDashlet.php new file mode 100644 index 00000000..75507dd6 --- /dev/null +++ b/modules/Bugs/Dashlets/MyBugsDashlet/MyBugsDashlet.php @@ -0,0 +1,80 @@ +searchFields = $dashletData['MyBugsDashlet']['searchFields']; + $this->columns = $dashletData['MyBugsDashlet']['columns']; + + if(empty($def['title'])) $this->title = translate('LBL_LIST_MY_BUGS', 'Bugs'); + $this->seedBean = new Bug(); + } + + function displayOptions() { + + $this->processDisplayOptions(); + + $seedRelease = new Release(); + + if(!empty($this->searchFields['fixed_in_release'])) { + $this->currentSearchFields['fixed_in_release']['input'] = ''; + } + + if(!empty($this->searchFields['found_in_release'])) { + $this->currentSearchFields['found_in_release']['input'] = ''; + } + $this->configureSS->assign('searchFields', $this->currentSearchFields); + return $this->configureSS->fetch($this->configureTpl); + } +} + +?> diff --git a/modules/Bugs/Menu.php b/modules/Bugs/Menu.php new file mode 100644 index 00000000..cd0b94a9 --- /dev/null +++ b/modules/Bugs/Menu.php @@ -0,0 +1,53 @@ + \ No newline at end of file diff --git a/modules/Bugs/field_arrays.php b/modules/Bugs/field_arrays.php new file mode 100644 index 00000000..7f051df0 --- /dev/null +++ b/modules/Bugs/field_arrays.php @@ -0,0 +1,68 @@ + Array("id" + , "name" + , "bug_number" + , "date_entered" + , "date_modified" + , "modified_user_id" + , "assigned_user_id" + , "status" + , "found_in_release" + , "created_by" + , "resolution" + , "priority" + , "description" + ,'type' + , "fixed_in_release" + , "work_log" + , "source" + , "product_category" + ), + 'list_fields' => Array('id', 'priority', 'status', 'name', 'bug_number', 'assigned_user_name', 'assigned_user_id', 'release', 'found_in_release', 'resolution', 'type' + ), + 'required_fields' => array('name'=>1), +); +?> \ No newline at end of file diff --git a/modules/Bugs/language/en_us.lang.php b/modules/Bugs/language/en_us.lang.php new file mode 100644 index 00000000..5f36bff9 --- /dev/null +++ b/modules/Bugs/language/en_us.lang.php @@ -0,0 +1,115 @@ + 'Bugs', + 'LBL_MODULE_TITLE' => 'Bug Tracker: Home', + 'LBL_MODULE_ID' => 'Bugs', + 'LBL_SEARCH_FORM_TITLE' => 'Bug Search', + 'LBL_LIST_FORM_TITLE' => 'Bug List', + 'LBL_NEW_FORM_TITLE' => 'New Bug', + 'LBL_CONTACT_BUG_TITLE' => 'Contact-Bug:', + 'LBL_SUBJECT' => 'Subject:', + 'LBL_BUG' => 'Bug:', + 'LBL_BUG_NUMBER' => 'Bug Number:', + 'LBL_NUMBER' => 'Number:', + 'LBL_STATUS' => 'Status:', + 'LBL_PRIORITY' => 'Priority:', + 'LBL_DESCRIPTION' => 'Description:', + 'LBL_CONTACT_NAME' => 'Contact Name:', + 'LBL_BUG_SUBJECT' => 'Bug Subject:', + 'LBL_CONTACT_ROLE' => 'Role:', + 'LBL_LIST_NUMBER' => 'Num.', + 'LBL_LIST_SUBJECT' => 'Subject', + 'LBL_LIST_STATUS' => 'Status', + 'LBL_LIST_PRIORITY' => 'Priority', + 'LBL_LIST_RELEASE' => 'Release', + 'LBL_LIST_RESOLUTION' => 'Resolution', + 'LBL_LIST_LAST_MODIFIED' => 'Last Modified', + 'LBL_INVITEE' => 'Contacts', + 'LBL_TYPE' => 'Type:', + 'LBL_LIST_TYPE' => 'Type', + 'LBL_RESOLUTION' => 'Resolution:', + 'LBL_RELEASE' => 'Release:', + 'LNK_NEW_BUG' => 'Report Bug', + 'LNK_BUG_LIST' => 'View Bugs', + 'NTC_REMOVE_INVITEE' => 'Are you sure you want to remove this contact from the bug?', + 'NTC_REMOVE_ACCOUNT_CONFIRMATION' => 'Are you sure you want to remove this bug from this account?', + 'ERR_DELETE_RECORD' => 'You must specify a record number in order to delete the bug.', + 'LBL_LIST_MY_BUGS' => 'My Assigned Bugs', + 'LNK_IMPORT_BUGS' => 'Import Bugs', + 'LBL_FOUND_IN_RELEASE' => 'Found in Release:', + 'LBL_FIXED_IN_RELEASE' => 'Fixed in Release:', + 'LBL_LIST_FIXED_IN_RELEASE' => 'Fixed in Release', + 'LBL_WORK_LOG' => 'Work Log:', + 'LBL_SOURCE' => 'Source:', + 'LBL_PRODUCT_CATEGORY' => 'Category:', + + 'LBL_CREATED_BY' => 'Created by:', + 'LBL_DATE_CREATED' => 'Create Date:', + 'LBL_MODIFIED_BY' => 'Last Modified by:', + 'LBL_DATE_LAST_MODIFIED' => 'Modify Date:', + + 'LBL_LIST_EMAIL_ADDRESS' => 'Email Address', + 'LBL_LIST_CONTACT_NAME' => 'Contact Name', + 'LBL_LIST_ACCOUNT_NAME' => 'Account Name', + 'LBL_LIST_PHONE' => 'Phone', + 'NTC_DELETE_CONFIRMATION' => 'Are you sure you want to remove this contact from this bug?', + + 'LBL_DEFAULT_SUBPANEL_TITLE' => 'Bug Tracker', + 'LBL_ACTIVITIES_SUBPANEL_TITLE'=>'Activities', + 'LBL_HISTORY_SUBPANEL_TITLE'=>'History', + 'LBL_CONTACTS_SUBPANEL_TITLE' => 'Contacts', + 'LBL_ACCOUNTS_SUBPANEL_TITLE' => 'Accounts', + 'LBL_CASES_SUBPANEL_TITLE' => 'Cases', + 'LBL_PROJECTS_SUBPANEL_TITLE' => 'Projects', + 'LBL_DOCUMENTS_SUBPANEL_TITLE' => 'Documents', + 'LBL_SYSTEM_ID' => 'System ID', + 'LBL_LIST_ASSIGNED_TO_NAME' => 'Assigned User', + 'LBL_ASSIGNED_TO_NAME' => 'Assigned to', + + 'LBL_BUG_INFORMATION' => 'Bug Overview', + ); +?> diff --git a/modules/Bugs/metadata/SearchFields.php b/modules/Bugs/metadata/SearchFields.php new file mode 100644 index 00000000..94ee4511 --- /dev/null +++ b/modules/Bugs/metadata/SearchFields.php @@ -0,0 +1,66 @@ + array( 'query_type'=>'default'), + 'status'=> array('query_type'=>'default', 'options' => 'bug_status_dom', 'template_var' => 'STATUS_OPTIONS'), + 'priority'=> array('query_type'=>'default', 'options' => 'bug_priority_dom', 'template_var' => 'PRIORITY_OPTIONS'), + 'found_in_release'=> array('query_type'=>'default','options' => 'bug_release_dom', 'template_var' => 'RELEASE_OPTIONS', 'options_add_blank' => true), + 'fixed_in_release'=> array('query_type'=>'default','options' => 'bug_release_dom', 'template_var' => 'RELEASE_OPTIONS', 'options_add_blank' => true), + 'resolution'=> array('query_type'=>'default', 'options' => 'bug_resolution_dom', 'template_var' => 'RESOLUTION_OPTIONS'), + 'bug_number'=> array('query_type'=>'default','operator'=>'in'), + 'current_user_only'=> array('query_type'=>'default','db_field'=>array('assigned_user_id'),'my_items'=>true, 'vname' => 'LBL_CURRENT_USER_FILTER', 'type' => 'bool'), + 'assigned_user_id'=> array('query_type'=>'default'), + 'type'=> array('query_type'=>'default', 'options' => 'bug_type_dom', 'template_var' => 'TYPE_OPTIONS', 'options_add_blank' => true), + 'open_only' => array( + 'query_type'=>'default', + 'db_field'=>array('status'), + 'operator'=>'not in', + 'closed_values' => array('Closed', 'Rejected'), + 'type'=>'bool', + ), + //Range Search Support + 'range_date_entered' => array ('query_type' => 'default', 'enable_range_search' => true, 'is_date_field' => true), + 'start_range_date_entered' => array ('query_type' => 'default', 'enable_range_search' => true, 'is_date_field' => true), + 'end_range_date_entered' => array ('query_type' => 'default', 'enable_range_search' => true, 'is_date_field' => true), + 'range_date_modified' => array ('query_type' => 'default', 'enable_range_search' => true, 'is_date_field' => true), + 'start_range_date_modified' => array ('query_type' => 'default', 'enable_range_search' => true, 'is_date_field' => true), + 'end_range_date_modified' => array ('query_type' => 'default', 'enable_range_search' => true, 'is_date_field' => true), + //Range Search Support + ); +?> diff --git a/modules/Bugs/metadata/additionalDetails.php b/modules/Bugs/metadata/additionalDetails.php new file mode 100644 index 00000000..f9857f09 --- /dev/null +++ b/modules/Bugs/metadata/additionalDetails.php @@ -0,0 +1,80 @@ +'. $app_strings['LBL_DATE_ENTERED'] . ' ' . $fields['DATE_ENTERED'] . '
    '; + if(!empty($fields['SOURCE'])) + $overlib_string .= ''. $mod_strings['LBL_SOURCE'] . ' ' . $fields['SOURCE'] . '
    '; + if(!empty($fields['PRODUCT_CATEGORY'])) + $overlib_string .= ''. $mod_strings['LBL_PRODUCT_CATEGORY'] . ' ' . $fields['PRODUCT_CATEGORY'] . '
    '; + if(!empty($fields['RESOLUTION'])) + $overlib_string .= ''. $mod_strings['LBL_RESOLUTION'] . ' ' . $fields['RESOLUTION'] . '
    '; + + if(!empty($fields['DESCRIPTION'])) { + $overlib_string .= ''. $mod_strings['LBL_DESCRIPTION'] . ' ' . substr($fields['DESCRIPTION'], 0, 300); + if(strlen($fields['DESCRIPTION']) > 300) $overlib_string .= '...'; + $overlib_string .= '
    '; + } + + if(!empty($fields['WORK_LOG'])) { + $overlib_string .= ''. $mod_strings['LBL_WORK_LOG'] . ' ' . substr($fields['WORK_LOG'], 0, 300); + if(strlen($fields['WORK_LOG']) > 300) $overlib_string .= '...'; + } + + return array('fieldToAddTo' => 'NAME', + 'string' => $overlib_string, + 'editLink' => "index.php?action=EditView&module=Bugs&return_module=Bugs&record={$fields['ID']}", + 'viewLink' => "index.php?action=DetailView&module=Bugs&return_module=Bugs&record={$fields['ID']}"); + +} + + ?> + + \ No newline at end of file diff --git a/modules/Bugs/metadata/detailviewdefs.php b/modules/Bugs/metadata/detailviewdefs.php new file mode 100644 index 00000000..5774977e --- /dev/null +++ b/modules/Bugs/metadata/detailviewdefs.php @@ -0,0 +1,118 @@ + array('form' => array('buttons'=>array('EDIT', 'DUPLICATE', 'DELETE', 'FIND_DUPLICATES',)), + 'maxColumns' => '2', + 'widths' => array( + array('label' => '10', 'field' => '30'), + array('label' => '10', 'field' => '30') + ), + ), + +'panels' =>array ( + 'lbl_bug_information'=>array( + array ( + 'bug_number', + 'priority', + ), + + array ( + array ( + 'name' => 'name', + 'label' => 'LBL_SUBJECT', + ), + 'status', + ), + + array ( + 'type', + 'source', + ), + + array ( + 'product_category', + 'resolution', + ), + + array ( + array ( + 'name' => 'found_in_release', + 'label' => 'LBL_FOUND_IN_RELEASE', + ), + 'fixed_in_release', + ), + + array ( + 'description', + ), + + array ( + 'work_log', + ), + + ), + + 'LBL_PANEL_ASSIGNMENT' => + array ( + + array ( + + array ( + 'name' => 'assigned_user_name', + 'label' => 'LBL_ASSIGNED_TO_NAME', + ), + + array ( + 'name' => 'date_modified', + 'customCode' => '{$fields.date_modified.value} {$APP.LBL_BY} {$fields.modified_by_name.value}', + 'label' => 'LBL_DATE_MODIFIED', + ), + ), + + array ( + + array ( + 'name' => 'date_entered', + 'customCode' => '{$fields.date_entered.value} {$APP.LBL_BY} {$fields.created_by_name.value}', + 'label' => 'LBL_DATE_ENTERED', + ), + + ), + ), +) +); +?> \ No newline at end of file diff --git a/modules/Bugs/metadata/editviewdefs.php b/modules/Bugs/metadata/editviewdefs.php new file mode 100644 index 00000000..463c3e2b --- /dev/null +++ b/modules/Bugs/metadata/editviewdefs.php @@ -0,0 +1,115 @@ + array('form'=>array('hidden'=>array('', + '') + ), + 'maxColumns' => '2', + 'widths' => array( + array('label' => '10', 'field' => '30'), + array('label' => '10', 'field' => '30') + ), + ), + + + 'panels' =>array ( + 'lbl_bug_information' => + array ( + + array ( + array ( + 'name' => 'bug_number', + 'type' => 'readonly', + ), + ), + + array ( + array('name'=>'name', 'displayParams'=>array('size'=>60, 'required'=>true)), + ), + + array ( + 'priority', + 'type', + ), + + array ( + 'source', + 'status', + + ), + + array ( + 'product_category', + 'resolution', + ), + + + array ( + 'found_in_release', + 'fixed_in_release' + ), + + array ( + array ( + 'name' => 'description', + 'nl2br' => true, + ), + ), + + + array ( + array ( + 'name' => 'work_log', + 'nl2br' => true, + ), + ), + + ), + + 'LBL_PANEL_ASSIGNMENT' => + array ( + array ( + array ( + 'name' => 'assigned_user_name', + 'label' => 'LBL_ASSIGNED_TO_NAME', + ), + ), + ), +), + +); +?> \ No newline at end of file diff --git a/modules/Bugs/metadata/listviewdefs.php b/modules/Bugs/metadata/listviewdefs.php new file mode 100644 index 00000000..ab4a5b45 --- /dev/null +++ b/modules/Bugs/metadata/listviewdefs.php @@ -0,0 +1,90 @@ + array( + 'width' => '5', + 'label' => 'LBL_LIST_NUMBER', + 'link' => true, + 'default' => true), + 'NAME' => array( + 'width' => '32', + 'label' => 'LBL_LIST_SUBJECT', + 'default' => true, + 'link' => true), + 'STATUS' => array( + 'width' => '10', + 'label' => 'LBL_LIST_STATUS', + 'default' => true), + 'TYPE' => array( + 'width' => '10', + 'label' => 'LBL_LIST_TYPE', + 'default' => true), + 'PRIORITY' => array( + 'width' => '10', + 'label' => 'LBL_LIST_PRIORITY', + 'default' => true), + 'RELEASE_NAME' => array( + 'width' => '10', + 'label' => 'LBL_FOUND_IN_RELEASE', + 'default' => false, + 'related_fields' => array('found_in_release'), + 'module' => 'Releases', + 'id' => 'FOUND_IN_RELEASE',), + 'FIXED_IN_RELEASE_NAME' => array( + 'width' => '10', + 'label' => 'LBL_LIST_FIXED_IN_RELEASE', + 'default' => true, + 'related_fields' => array('fixed_in_release'), + 'module' => 'Releases', + 'id' => 'FIXED_IN_RELEASE',), + 'RESOLUTION' => array( + 'width' => '10', + 'label' => 'LBL_LIST_RESOLUTION', + 'default' => false), + 'ASSIGNED_USER_NAME' => array( + 'width' => '9', + 'label' => 'LBL_LIST_ASSIGNED_USER', + 'module' => 'Employees', + 'id' => 'ASSIGNED_USER_ID', + 'default' => true) +); +?> diff --git a/modules/Bugs/metadata/metafiles.php b/modules/Bugs/metadata/metafiles.php new file mode 100644 index 00000000..1820fca4 --- /dev/null +++ b/modules/Bugs/metadata/metafiles.php @@ -0,0 +1,52 @@ + 'modules/Bugs/metadata/detailviewdefs.php', + 'editviewdefs' => 'modules/Bugs/metadata/editviewdefs.php', + 'listviewdefs' => 'modules/Bugs/metadata/listviewdefs.php', + 'searchdefs' => 'modules/Bugs/metadata/searchdefs.php', + 'popupdefs' => 'modules/Bugs/metadata/popupdefs.php', + 'searchfields' => 'modules/Bugs/metadata/SearchFields.php', + + ); +?> diff --git a/modules/Bugs/metadata/popupdefs.php b/modules/Bugs/metadata/popupdefs.php new file mode 100644 index 00000000..9acec512 --- /dev/null +++ b/modules/Bugs/metadata/popupdefs.php @@ -0,0 +1,89 @@ + 'Bug', + 'varName' => 'BUG', + 'orderBy' => 'bugs.name', + 'whereClauses' => array( + 'name' => 'bugs.name', + 'bug_number' => 'bugs.bug_number' + ), + 'listviewdefs' => array( + 'BUG_NUMBER' => array( + 'width' => '5', + 'label' => 'LBL_LIST_NUMBER', + 'link' => true, + 'default' => true), + 'NAME' => array( + 'width' => '32', + 'label' => 'LBL_LIST_SUBJECT', + 'default' => true, + 'link' => true), + 'PRIORITY' => array( + 'width' => '10', + 'label' => 'LBL_LIST_PRIORITY', + 'default' => true), + 'STATUS' => array( + 'width' => '10', + 'label' => 'LBL_LIST_STATUS', + 'default' => true), + 'TYPE' => array( + 'width' => '10', + 'label' => 'LBL_LIST_TYPE', + 'default' => true), + 'PRODUCT_CATEGORY' => array( + 'width' => '10', + 'label' => 'LBL_PRODUCT_CATEGORY', + 'default' => true), + 'ASSIGNED_USER_NAME' => array( + 'width' => '9', + 'label' => 'LBL_LIST_ASSIGNED_USER', + 'default' => true) + + ), + 'searchdefs' => array( + 'bug_number', + 'name', + 'priority', + 'status', + 'type', + 'product_category', + array('name' => 'assigned_user_id', 'type' => 'enum', 'label' => 'LBL_ASSIGNED_TO', 'function' => array('name' => 'get_user_array', 'params' => array(false))), + ) +); \ No newline at end of file diff --git a/modules/Bugs/metadata/quickcreatedefs.php b/modules/Bugs/metadata/quickcreatedefs.php new file mode 100644 index 00000000..89cfe72a --- /dev/null +++ b/modules/Bugs/metadata/quickcreatedefs.php @@ -0,0 +1,143 @@ + + array ( + 'QuickCreate' => + array ( + 'templateMeta' => + array ( + 'form' => + array ( + 'hidden' => + array ( + 0 => '', + 1 => '', + ), + ), + 'maxColumns' => '2', + 'widths' => + array ( + 0 => + array ( + 'label' => '10', + 'field' => '30', + ), + 1 => + array ( + 'label' => '10', + 'field' => '30', + ), + ), + ), + 'panels' => + array ( + 'DEFAULT' => + array ( + 0 => + array ( + 0 => + array ( + 'name' => 'priority', + ), + 1 => + array ( + 'name' => 'assigned_user_name', + ), + ), + 1 => + array ( + 0 => + array ( + 'name' => 'source', + ), + 1 => + array ( + 'name' => 'team_name', + ), + ), + 2 => + array ( + 0 => + array ( + 'name' => 'type', + ), + 1 => + array ( + 'name' => 'status', + ), + ), + 3 => + array ( + 0 => + array ( + 'name' => 'product_category', + ), + 1 => + array ( + 'name' => 'found_in_release', + ), + ), + 4 => + array ( + 0 => + array ( + 'name' => 'name', + 'displayParams'=>array('required'=>true), + ), + ), + 5 => + array ( + 0 => + array ( + 'name' => 'description', + ), + ), + ), + ), + ), + ), +); +?> diff --git a/modules/Bugs/metadata/searchdefs.php b/modules/Bugs/metadata/searchdefs.php new file mode 100644 index 00000000..83d46c41 --- /dev/null +++ b/modules/Bugs/metadata/searchdefs.php @@ -0,0 +1,69 @@ + array( + 'maxColumns' => '4', + 'widths' => array('label' => '10', 'field' => '30'), + ), + 'layout' => array( + 'basic_search' => array( + 'name', + array('name'=>'current_user_only', 'label'=>'LBL_CURRENT_USER_FILTER', 'type'=>'bool'), + + array ('name' => 'open_only', 'label' => 'LBL_OPEN_ITEMS', 'type' => 'bool', 'default' => false, 'width' => '10%'), + ), + 'advanced_search' => array( + 'bug_number', + 'name', + 'resolution', + 'found_in_release', + 'fixed_in_release', + 'type', + 'status', + array('name' => 'assigned_user_id', 'type' => 'enum', 'label' => 'LBL_ASSIGNED_TO', 'function' => array('name' => 'get_user_array', 'params' => array(false))), + 'priority', + + ), + ), + ); +?> diff --git a/modules/Bugs/metadata/studio.php b/modules/Bugs/metadata/studio.php new file mode 100644 index 00000000..3d016c59 --- /dev/null +++ b/modules/Bugs/metadata/studio.php @@ -0,0 +1,66 @@ +array( + 'template'=>'xtpl', + 'template_file'=>'modules/Bugs/DetailView.html', + 'php_file'=>'modules/Bugs/DetailView.php', + 'type'=>'DetailView', + ), + 'LBL_EDITVIEW'=>array( + 'template'=>'xtpl', + 'template_file'=>'modules/Bugs/EditView.html', + 'php_file'=>'modules/Bugs/EditView.php', + 'type'=>'EditView', + ), + 'LBL_LISTVIEW'=>array( + 'template'=>'listview', + 'meta_file'=>'modules/Bugs/listviewdefs.php', + 'type'=>'ListView', + ), + 'LBL_SEARCHFORM'=>array( + 'template'=>'xtpl', + 'template_file'=>'modules/Bugs/SearchForm.html', + 'php_file'=>'modules/Bugs/ListView.php', + 'type'=>'SearchForm', + ), + +); diff --git a/modules/Bugs/metadata/subpaneldefs.php b/modules/Bugs/metadata/subpaneldefs.php new file mode 100644 index 00000000..0fc26f5b --- /dev/null +++ b/modules/Bugs/metadata/subpaneldefs.php @@ -0,0 +1,186 @@ + array( + 'contacts' => array( + 'order' => 30, + 'module' => 'Contacts', + 'sort_order' => 'asc', + 'sort_by' => 'last_name, first_name', + 'subpanel_name' => 'default', + 'get_subpanel_data' => 'contacts', + 'add_subpanel_data' => 'contact_id', + 'title_key' => 'LBL_CONTACTS_SUBPANEL_TITLE', + 'top_buttons' => array( + array('widget_class' => 'SubPanelTopButtonQuickCreate'), + array('widget_class' => 'SubPanelTopSelectButton', 'mode'=>'MultiSelect') + ), + ), + 'activities' => array( + 'order' => 10, + 'sort_order' => 'desc', + 'sort_by' => 'date_start', + 'title_key' => 'LBL_ACTIVITIES_SUBPANEL_TITLE', + 'type' => 'collection', + 'subpanel_name' => 'activities', //this values is not associated with a physical file. + 'module'=>'Activities', + + 'top_buttons' => array( + array('widget_class' => 'SubPanelTopCreateTaskButton'), + array('widget_class' => 'SubPanelTopScheduleMeetingButton'), + array('widget_class' => 'SubPanelTopScheduleCallButton'), + array('widget_class' => 'SubPanelTopComposeEmailButton'), + ), + + 'collection_list' => array( + 'meetings' => array( + 'module' => 'Meetings', + 'subpanel_name' => 'ForActivities', + 'get_subpanel_data' => 'meetings', + ), + 'tasks' => array( + 'module' => 'Tasks', + 'subpanel_name' => 'ForActivities', + 'get_subpanel_data' => 'tasks', + ), + 'calls' => array( + 'module' => 'Calls', + 'subpanel_name' => 'ForActivities', + 'get_subpanel_data' => 'calls', + ), + ) + ), + 'history' => array( + 'order' => 20, + 'sort_order' => 'desc', + 'sort_by' => 'date_entered', + 'title_key' => 'LBL_HISTORY_SUBPANEL_TITLE', + 'type' => 'collection', + 'subpanel_name' => 'history', //this values is not associated with a physical file. + 'module'=>'History', + + 'top_buttons' => array( + array('widget_class' => 'SubPanelTopCreateNoteButton'), + array('widget_class' => 'SubPanelTopArchiveEmailButton'), + array('widget_class' => 'SubPanelTopSummaryButton'), + ), + + 'collection_list' => array( + 'meetings' => array( + 'module' => 'Meetings', + 'subpanel_name' => 'ForHistory', + 'get_subpanel_data' => 'meetings', + ), + 'tasks' => array( + 'module' => 'Tasks', + 'subpanel_name' => 'ForHistory', + 'get_subpanel_data' => 'tasks', + ), + 'calls' => array( + 'module' => 'Calls', + 'subpanel_name' => 'ForHistory', + 'get_subpanel_data' => 'calls', + ), + 'notes' => array( + 'module' => 'Notes', + 'subpanel_name' => 'ForHistory', + 'get_subpanel_data' => 'notes', + ), + 'emails' => array( + 'module' => 'Emails', + 'subpanel_name' => 'ForHistory', + 'get_subpanel_data' => 'emails', + ), + ) + ), + 'documents' => array( + 'order' => 25, + 'module' => 'Documents', + 'subpanel_name' => 'default', + 'sort_order' => 'asc', + 'sort_by' => 'id', + 'title_key' => 'LBL_DOCUMENTS_SUBPANEL_TITLE', + 'get_subpanel_data' => 'documents', + 'top_buttons' => + array ( + 0 => + array ( + 'widget_class' => 'SubPanelTopButtonQuickCreate', + ), + 1 => + array ( + 'widget_class' => 'SubPanelTopSelectButton', + 'mode' => 'MultiSelect', + ), + ), + ), + 'accounts' => array( + 'order' => 40, + 'module' => 'Accounts', + 'sort_order' => 'asc', + 'sort_by' => 'name', + 'subpanel_name' => 'default', + 'get_subpanel_data' => 'accounts', + 'add_subpanel_data' => 'account_id', + 'title_key' => 'LBL_ACCOUNTS_SUBPANEL_TITLE', + 'top_buttons' => array( + array('widget_class' => 'SubPanelTopButtonQuickCreate'), + array('widget_class' => 'SubPanelTopSelectButton', 'mode'=>'MultiSelect') + ), + ), + 'cases' => array( + 'order' => 50, + 'module' => 'Cases', + 'sort_order' => 'desc', + 'sort_by' => 'case_number', + 'subpanel_name' => 'default', + 'get_subpanel_data' => 'cases', + 'add_subpanel_data' => 'case_id', + 'title_key' => 'LBL_CASES_SUBPANEL_TITLE', + 'top_buttons' => array( + array('widget_class' => 'SubPanelTopButtonQuickCreate'), + array('widget_class' => 'SubPanelTopSelectButton', 'mode'=>'MultiSelect'), + ), + ), + ), +); +?> \ No newline at end of file diff --git a/modules/Bugs/metadata/subpanels/ForEmails.php b/modules/Bugs/metadata/subpanels/ForEmails.php new file mode 100644 index 00000000..b5949487 --- /dev/null +++ b/modules/Bugs/metadata/subpanels/ForEmails.php @@ -0,0 +1,85 @@ + array( + array('widget_class' => 'SubPanelTopSelectButton', 'popup_module' => 'Bugs'), + ), + + 'where' => '', + + + + 'list_fields' => array( + 'bug_number'=>array( + 'vname' => 'LBL_LIST_NUMBER', + 'width' => '5%', + ), + + 'name'=>array( + 'vname' => 'LBL_LIST_SUBJECT', + 'widget_class' => 'SubPanelDetailViewLink', + 'width' => '50%', + ), + 'status'=>array( + 'vname' => 'LBL_LIST_STATUS', + 'width' => '15%', + ), + 'type'=>array( + 'vname' => 'LBL_LIST_TYPE', + 'width' => '15%', + ), + 'priority'=>array( + 'vname' => 'LBL_LIST_PRIORITY', + 'width' => '11%', + ), + 'edit_button'=>array( + 'widget_class' => 'SubPanelEditButton', + 'module' => 'Bugs', + 'width' => '4%', + ), + 'remove_button'=>array( + 'widget_class' => 'SubPanelRemoveButton', + 'module' => 'Bugs', + 'width' => '5%', + ), + ), +); + +?> \ No newline at end of file diff --git a/modules/Bugs/metadata/subpanels/default.php b/modules/Bugs/metadata/subpanels/default.php new file mode 100644 index 00000000..7fa6f329 --- /dev/null +++ b/modules/Bugs/metadata/subpanels/default.php @@ -0,0 +1,95 @@ + array( + array('widget_class' => 'SubPanelTopCreateButton'), + array('widget_class' => 'SubPanelTopSelectButton', 'popup_module' => 'Bugs'), + ), + + 'where' => '', + + + + 'list_fields' => array( + 'bug_number'=>array( + 'vname' => 'LBL_LIST_NUMBER', + 'width' => '5%', + ), + + 'name'=>array( + 'vname' => 'LBL_LIST_SUBJECT', + 'widget_class' => 'SubPanelDetailViewLink', + 'width' => '50%', + ), + 'status'=>array( + 'vname' => 'LBL_LIST_STATUS', + 'width' => '15%', + ), + 'type'=>array( + 'vname' => 'LBL_LIST_TYPE', + 'width' => '15%', + ), + 'priority'=>array( + 'vname' => 'LBL_LIST_PRIORITY', + 'width' => '11%', + ), + 'assigned_user_name' => array ( + 'name' => 'assigned_user_name', + 'vname' => 'LBL_LIST_ASSIGNED_TO_NAME', + 'widget_class' => 'SubPanelDetailViewLink', + 'target_record_key' => 'assigned_user_id', + 'target_module' => 'Employees', + ), + 'edit_button'=>array( + 'vname' => 'LBL_EDIT_BUTTON', + 'widget_class' => 'SubPanelEditButton', + 'module' => 'Bugs', + 'width' => '4%', + ), + 'remove_button'=>array( + 'vname' => 'LBL_REMOVE', + 'widget_class' => 'SubPanelRemoveButton', + 'module' => 'Bugs', + 'width' => '5%', + ), + ), +); + +?> \ No newline at end of file diff --git a/modules/Bugs/tpls/QuickCreate.tpl b/modules/Bugs/tpls/QuickCreate.tpl new file mode 100644 index 00000000..fa1857d5 --- /dev/null +++ b/modules/Bugs/tpls/QuickCreate.tpl @@ -0,0 +1,93 @@ +{* + +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + + + +*} + + +
    + + + + + + + + + + + + + + + + + +
    + + + {$APP.LBL_REQUIRED_SYMBOL} {$APP.NTC_REQUIRED}
    + + +"; + + // need to change these values after we find out what activities + // occur outside of these values + $start_slice_idx = $args['calendar']->get_start_slice_idx(); + $end_slice_idx = $args['calendar']->get_end_slice_idx(); + $cur_slice_idx = 1; + for($cur_slice_idx = $start_slice_idx; $cur_slice_idx <= $end_slice_idx; $cur_slice_idx ++) { + $calendar = $args['calendar']; + $args['slice'] = $calendar->slice_hash[$calendar->slices_arr[$cur_slice_idx]]; + + template_cal_horizontal_slice($args); + } + + echo "
    + + + + + + + + + + + + + + + + + + + + +

    {$MOD.LBL_BUG_INFORMATION}

    {$MOD.LBL_SUBJECT} {$APP.LBL_REQUIRED_SYMBOL}{$MOD.LBL_TYPE}
    {$MOD.LBL_DESCRIPTION}{$MOD.LBL_PRIORITY}
    {$MOD.LBL_STATUS}
    + + \ No newline at end of file diff --git a/modules/Bugs/vardefs.php b/modules/Bugs/vardefs.php new file mode 100644 index 00000000..a36138f3 --- /dev/null +++ b/modules/Bugs/vardefs.php @@ -0,0 +1,318 @@ + 'bugs', 'audited'=>true, 'comment' => 'Bugs are defects in products and services','duplicate_merge'=>true + ,'unified_search' => true,'fields' => array ( + 'found_in_release'=> + array( + 'name'=>'found_in_release', + 'type' => 'enum', + 'function'=>'getReleaseDropDown', + 'vname' => 'LBL_FOUND_IN_RELEASE', + 'reportable'=>false, + //'merge_filter' => 'enabled', //bug 22994, I think the former fixing is just avoiding the cross table query, it is not a good method. + 'comment' => 'The software or service release that manifested the bug', + 'duplicate_merge' => 'disabled', + 'audited' =>true, + 'studio' => array('fields' => 'false', 'listview' => false, 'wirelesslistview' => false ), // tyoung bug 16442 - don't show in studio fields list + 'massupdate' => true, + ), +'release_name'=> + array ( + 'name' => 'release_name', + 'rname' => 'name', + 'vname'=>'LBL_FOUND_IN_RELEASE', + 'type' => 'relate', + 'dbType'=>'varchar', + 'group'=>'found_in_release', + 'reportable'=>false, + 'source'=>'non-db', + 'table'=>'releases', + 'merge_filter' => 'enabled', //bug 22994, we should use the release name to search, I have write codes to operate the cross table query. + 'id_name'=>'found_in_release', + 'module'=>'Releases', + 'link' => 'release_link', + 'massupdate' => false, + 'studio' => array( + 'editview' => false, + 'detailview' => false, + 'quickcreate' => false, + 'basic_search' => false, + 'advanced_search' => false, + //BEGIN SUGARCRM flav=pro + 'wirelesseditview' => false, + 'wirelessdetailview' => false, + 'wirelesslistview' => 'visible', + 'wireless_basic_search' => false, + 'wireless_advanced_search' => false, + //END SUGARCRM flav=pro + ), + ), + + 'fixed_in_release'=> + array( + 'name'=>'fixed_in_release', + 'type' => 'enum', + 'function'=>'getReleaseDropDown', + 'vname' => 'LBL_FIXED_IN_RELEASE', + 'reportable'=>false, + 'comment' => 'The software or service release that corrected the bug', + 'duplicate_merge' => 'disabled', + 'audited' =>true, + 'studio' => array('fields' => 'false', 'listview' => false, 'wirelesslistview' => false), // tyoung bug 16442 - don't show in studio fields list + 'massupdate' => true, + ), + 'fixed_in_release_name'=> + array ( + 'name' => 'fixed_in_release_name', + 'rname' => 'name', + 'group'=>'fixed_in_release', + 'id_name' => 'fixed_in_release', + 'vname' => 'LBL_FIXED_IN_RELEASE', + 'type' => 'relate', + 'table' => 'releases', + 'isnull' => 'false', + 'massupdate' => false, + 'module' => 'Releases', + 'dbType' => 'varchar', + 'len' => 36, + 'source'=>'non-db', + 'link' => 'fixed_in_release_link', + 'studio' => array( + 'editview' => false, + 'detailview' => false, + 'quickcreate' => false, + 'basic_search' => false, + 'advanced_search' => false, + //BEGIN SUGARCRM flav=pro + 'wirelesseditview' => false, + 'wirelessdetailview' => false, + 'wirelesslistview' => 'visible', + 'wireless_basic_search' => false, + 'wireless_advanced_search' => false, + //END SUGARCRM flav=pro + ), + ), + 'source' => + array ( + 'name' => 'source', + 'vname' => 'LBL_SOURCE', + 'type' => 'enum', + 'options'=>'source_dom', + 'len' => 255, + 'comment' => 'An indicator of how the bug was entered (ex: via web, email, etc.)' + ), + 'product_category' => + array ( + 'name' => 'product_category', + 'vname' => 'LBL_PRODUCT_CATEGORY', + 'type' => 'enum', + 'options'=>'product_category_dom', + 'len' => 255, + 'comment' => 'Where the bug was discovered (ex: Accounts, Contacts, Leads)' + ), + + + 'tasks' => + array ( + 'name' => 'tasks', + 'type' => 'link', + 'relationship' => 'bug_tasks', + 'source'=>'non-db', + 'vname'=>'LBL_TASKS' + ), + 'notes' => + array ( + 'name' => 'notes', + 'type' => 'link', + 'relationship' => 'bug_notes', + 'source'=>'non-db', + 'vname'=>'LBL_NOTES' + ), + 'meetings' => + array ( + 'name' => 'meetings', + 'type' => 'link', + 'relationship' => 'bug_meetings', + 'source'=>'non-db', + 'vname'=>'LBL_MEETINGS' + ), + 'calls' => + array ( + 'name' => 'calls', + 'type' => 'link', + 'relationship' => 'bug_calls', + 'source'=>'non-db', + 'vname'=>'LBL_CALLS' + ), + 'emails' => + array ( + 'name' => 'emails', + 'type' => 'link', + 'relationship' => 'emails_bugs_rel',/* reldef in emails */ + 'source'=>'non-db', + 'vname'=>'LBL_EMAILS' + ), + 'documents'=> + array ( + 'name' => 'documents', + 'type' => 'link', + 'relationship' => 'documents_bugs', + 'source' => 'non-db', + 'vname' => 'LBL_DOCUMENTS_SUBPANEL_TITLE', + ), + 'contacts' => + array ( + 'name' => 'contacts', + 'type' => 'link', + 'relationship' => 'contacts_bugs', + 'source'=>'non-db', + 'vname'=>'LBL_CONTACTS' + ), + 'accounts' => + array ( + 'name' => 'accounts', + 'type' => 'link', + 'relationship' => 'accounts_bugs', + 'source'=>'non-db', + 'vname'=>'LBL_ACCOUNTS' + ), + 'cases' => + array ( + 'name' => 'cases', + 'type' => 'link', + 'relationship' => 'cases_bugs', + 'source'=>'non-db', + 'vname'=>'LBL_CASES' + ), + 'release_link' => + array ( + 'name' => 'release_link', + 'type' => 'link', + 'relationship' => 'bugs_release', + 'vname' => 'LBL_FOUND_IN_RELEASE', + 'link_type' => 'one', + 'module'=>'Releases', + 'bean_name'=>'Release', + 'source'=>'non-db', + ), + 'fixed_in_release_link' => + array ( + 'name' => 'fixed_in_release_link', + 'type' => 'link', + 'relationship' => 'bugs_fixed_in_release', + 'vname' => 'LBL_FIXED_IN_RELEASE', + 'link_type' => 'one', + 'module'=>'Releases', + 'bean_name'=>'Release', + 'source'=>'non-db', + ), + + 'projects' => + array ( + 'name' => 'projects', + 'type' => 'link', + 'relationship' => 'projects_bugs', + 'source'=>'non-db', + 'vname'=>'LBL_PROJECTS', + ), + +) + , 'indices' => array ( + array('name' =>'bug_number', 'type' =>'index', 'fields'=>array('bug_number')), + + array('name' =>'idx_bug_name', 'type' =>'index', 'fields'=>array('name')) + ) + +, 'relationships' => array ( + 'bug_tasks' => array('lhs_module'=> 'Bugs', 'lhs_table'=> 'bugs', 'lhs_key' => 'id', + 'rhs_module'=> 'Tasks', 'rhs_table'=> 'tasks', 'rhs_key' => 'parent_id', + 'relationship_type'=>'one-to-many', 'relationship_role_column'=>'parent_type', + 'relationship_role_column_value'=>'Bugs') + ,'bug_meetings' => array('lhs_module'=> 'Bugs', 'lhs_table'=> 'bugs', 'lhs_key' => 'id', + 'rhs_module'=> 'Meetings', 'rhs_table'=> 'meetings', 'rhs_key' => 'parent_id', + 'relationship_type'=>'one-to-many', 'relationship_role_column'=>'parent_type', + 'relationship_role_column_value'=>'Bugs') + ,'bug_calls' => array('lhs_module'=> 'Bugs', 'lhs_table'=> 'bugs', 'lhs_key' => 'id', + 'rhs_module'=> 'Calls', 'rhs_table'=> 'calls', 'rhs_key' => 'parent_id', + 'relationship_type'=>'one-to-many', 'relationship_role_column'=>'parent_type', + 'relationship_role_column_value'=>'Bugs') + ,'bug_emails' => array('lhs_module'=> 'Bugs', 'lhs_table'=> 'bugs', 'lhs_key' => 'id', + 'rhs_module'=> 'Emails', 'rhs_table'=> 'emails', 'rhs_key' => 'parent_id', + 'relationship_type'=>'one-to-many', 'relationship_role_column'=>'parent_type', + 'relationship_role_column_value'=>'Bugs') + ,'bug_notes' => array('lhs_module'=> 'Bugs', 'lhs_table'=> 'bugs', 'lhs_key' => 'id', + 'rhs_module'=> 'Notes', 'rhs_table'=> 'notes', 'rhs_key' => 'parent_id', + 'relationship_type'=>'one-to-many', 'relationship_role_column'=>'parent_type', + 'relationship_role_column_value'=>'Bugs') + + ,'bugs_assigned_user' => + array('lhs_module'=> 'Users', 'lhs_table'=> 'users', 'lhs_key' => 'id', + 'rhs_module'=> 'Bugs', 'rhs_table'=> 'bugs', 'rhs_key' => 'assigned_user_id', + 'relationship_type'=>'one-to-many') + + ,'bugs_modified_user' => + array('lhs_module'=> 'Users', 'lhs_table'=> 'users', 'lhs_key' => 'id', + 'rhs_module'=> 'Bugs', 'rhs_table'=> 'bugs', 'rhs_key' => 'modified_user_id', + 'relationship_type'=>'one-to-many') + + ,'bugs_created_by' => + array('lhs_module'=> 'Users', 'lhs_table'=> 'users', 'lhs_key' => 'id', + 'rhs_module'=> 'Bugs', 'rhs_table'=> 'bugs', 'rhs_key' => 'created_by', + 'relationship_type'=>'one-to-many') + ,'bugs_release' => + array('lhs_module'=> 'Releases', 'lhs_table'=> 'releases', 'lhs_key' => 'id', + 'rhs_module'=> 'Bugs', 'rhs_table'=> 'bugs', 'rhs_key' => 'found_in_release', + 'relationship_type'=>'one-to-many') + ,'bugs_fixed_in_release' => + array('lhs_module'=> 'Releases', 'lhs_table'=> 'releases', 'lhs_key' => 'id', + 'rhs_module'=> 'Bugs', 'rhs_table'=> 'bugs', 'rhs_key' => 'fixed_in_release', + 'relationship_type'=>'one-to-many') + +), //This enables optimistic locking for Saves From EditView + 'optimistic_locking'=>true, + ); + +VardefManager::createVardef('Bugs','Bug', array('default', 'assignable', +'issue', +)); + +//jc - adding for refactor for import to not use the required_fields array +//defined in the field_arrays.php file +$dictionary['Bug']['fields']['name']['importable'] = 'required'; + +?> diff --git a/modules/Bugs/views/view.detail.php b/modules/Bugs/views/view.detail.php new file mode 100644 index 00000000..2bf3e6a9 --- /dev/null +++ b/modules/Bugs/views/view.detail.php @@ -0,0 +1,65 @@ +retrieveSettings(); + if(isset($admin->settings['portal_on']) && $admin->settings['portal_on']) { + $this->ss->assign("PORTAL_ENABLED", true); + } + parent::display(); + } +} +?> diff --git a/modules/Bugs/views/view.edit.php b/modules/Bugs/views/view.edit.php new file mode 100644 index 00000000..4ccca633 --- /dev/null +++ b/modules/Bugs/views/view.edit.php @@ -0,0 +1,65 @@ +retrieveSettings(); + if(isset($admin->settings['portal_on']) && $admin->settings['portal_on']) { + $this->ev->ss->assign("PORTAL_ENABLED", true); + } + parent::display(); + } +} +?> diff --git a/modules/Calendar/Calendar.php b/modules/Calendar/Calendar.php new file mode 100644 index 00000000..413bd1bb --- /dev/null +++ b/modules/Calendar/Calendar.php @@ -0,0 +1,613 @@ +start_time->ts == $act1->start_time->ts) + { + return 0; + } + + return ($act0->start_time->ts < $act1->start_time->ts) ? -1 : 1; +} + +class Calendar +{ + var $view = 'month'; + /** + * Current date + * @var SugarDateTime + */ + var $date_time; + var $slices_arr = array(); + // for monthly calendar view, if you want to see all the + // days in the grid, otherwise you only see that months + var $show_only_current_slice = false; + var $show_activities = true; + var $show_tasks = true; + var $activity_focus; + var $show_week_on_month_view = true; + var $use_24 = 1; + var $toggle_appt = true; + var $slice_hash = array(); + var $shared_users_arr = array(); + + function __construct($view,$time_arr=array()) + { + global $current_user, $timedate; + global $sugar_config; + if ( $current_user->getPreference('time')) + { + $time = $current_user->getPreference('time'); + } + else + { + $time = $sugar_config['default_time_format']; + } + + if( substr_count($time, 'h') > 0) + { + $this->use_24 = 0; + } + + if (!( $view == 'day' || $view == 'month' || $view == 'year' || $view == 'week' || $view == 'shared') ) + { + sugar_die ("view needs to be one of: day, week, month, shared, or year"); + } + + $this->view = $view; + + if ( isset($time_arr['activity_focus'])) + { + $this->activity_focus = new CalendarActivity($time_arr['activity_focus']); + $this->date_time = $this->activity_focus->start_time; + } + else + { + if(!empty($time_arr)) { + // FIXME: what format? + $this->date_time = $timedate->fromTimeArray($time_arr); + } else { + $this->date_time = $timedate->getNow(); + } + } + + $timedate->tzUser($this->date_time, $current_user); + $GLOBALS['log']->debug("CALENDATE: ".$this->date_time->format('r')); + $this->create_slices(); + + } + function add_shared_users($shared_users_arr) + { + $this->shared_users_arr = $shared_users_arr; + } + + function get_view_name($view) + { + if ($view == 'month') + { + return "MONTH"; + } + else if ($view == 'week') + { + return "WEEK"; + } + else if ($view == 'day') + { + return "DAY"; + } + else if ($view == 'year') + { + return "YEAR"; + } + else if ($view == 'shared') + { + return "SHARED"; + } + else + { + sugar_die ("get_view_name: view ".$this->view." not supported"); + } + } + + function isDayView() { + return $this->view == 'day'; + } + + function get_slices_arr() + { + return $this->slices_arr; + } + + + function create_slices() + { + global $current_user; + + if ( $this->view == 'month') + { + $days_in_month = $this->date_time->days_in_month; + + $first_day_of_month = $this->date_time->get_day_by_index_this_month(0); + $num_of_prev_days = $first_day_of_month->day_of_week; + // do 42 slices (6x7 grid) + + for($i=0;$i < 42;$i++) + { + $slice = new Slice('day',$this->date_time->get_day_by_index_this_month($i-$num_of_prev_days)); + $this->slice_hash[$slice->start_time->get_mysql_date()] = $slice; + array_push($this->slices_arr, $slice->start_time->get_mysql_date()); + } + + } + else if ( $this->view == 'week' || $this->view == 'shared') + { + $days_in_week = 7; + + for($i=0;$i<$days_in_week;$i++) + { + $slice = new Slice('day',$this->date_time->get_day_by_index_this_week($i)); + $this->slice_hash[$slice->start_time->get_mysql_date()] = $slice; + array_push($this->slices_arr, $slice->start_time->get_mysql_date()); + } + } + else if ( $this->view == 'day') + { + $hours_in_day = 24; + + for($i=0;$i<$hours_in_day;$i++) + { + $slice = new Slice('hour',$this->date_time->get_datetime_by_index_today($i)); + $this->slice_hash[$slice->start_time->get_mysql_date().":".$slice->start_time->hour ] = $slice; + $this->slices_arr[] = $slice->start_time->get_mysql_date().":".$slice->start_time->hour; + } + } + else if ( $this->view == 'year') + { + + for($i=0;$i<12;$i++) + { + $slice = new Slice('month',$this->date_time->get_day_by_index_this_year($i)); + $this->slice_hash[$slice->start_time->get_mysql_date()] = $slice; + array_push($this->slices_arr, $slice->start_time->get_mysql_date()); + } + } + else + { + sugar_die("not a valid view:".$this->view); + } + + } + + function add_activities($user,$type='sugar') { + global $timedate; + if ( $this->view == 'week' || $this->view == 'shared') { + $end_date_time = $this->date_time->get("+7 days"); + } else { + $end_date_time = $this->date_time; + } + + $acts_arr = array(); + if($type == 'vfb') { + $acts_arr = CalendarActivity::get_freebusy_activities($user, $this->date_time, $end_date_time); + } else { + $acts_arr = CalendarActivity::get_activities($user->id, $this->show_tasks, $this->date_time, $end_date_time, $this->view); + } + + // loop thru each activity for this user + foreach ($acts_arr as $act) { + // get "hashed" time slots for the current activity we are looping through + $start = $timedate->tzUser($act->start_time); + $end = $timedate->tzUser($act->end_time); + $hash_list = SugarDateTime::getHashList($this->view, $start, $end); + + for($j=0;$j < count($hash_list); $j++) { + if(!isset($this->slice_hash[$hash_list[$j]]) || !isset($this->slice_hash[$hash_list[$j]]->acts_arr[$user->id])) { + $this->slice_hash[$hash_list[$j]]->acts_arr[$user->id] = array(); + } + $this->slice_hash[$hash_list[$j]]->acts_arr[$user->id][] = $act; + } + } + } + + function occurs_within_slice($slice, $act) + { + // if activity starts within this slice + // OR activity ends within this slice + // OR activity starts before and ends after this slice + if ( ( $act->start_time->ts >= $slice->start_time->ts && + $act->start_time->ts <= $slice->end_time->ts ) + || + ( $act->end_time->ts >= $slice->start_time->ts && + $act->end_time->ts <= $slice->end_time->ts ) + || + ( $act->start_time->ts <= $slice->start_time->ts && + $act->end_time->ts >= $slice->end_time->ts ) + ) + { + return true; + } + + return false; + + } + + function get_previous_date_str() + { + if ($this->view == 'month') + { + $day = $this->date_time->get("-1 month")->get_day_begin(1); + } + else if ($this->view == 'week' || $this->view == 'shared') + { + // first day last week + $day = $this->date_time->get("-7 days")->get_day_by_index_this_week(0)->get_day_begin(); + } + else if ($this->view == 'day') + { + $day = $this->date_time->get("yesterday")->get_day_begin(); + } + else if ($this->view == 'year') + { + $day = $this->date_time->get_year_begin($this->year-1); + } + else + { + return "get_previous_date_str: notdefined for this view"; + } + return $day->get_date_str(); + } + + function get_next_date_str() + { + if ($this->view == 'month') + { + $day = $this->date_time->get("+1 month")->get_day_begin(1); + } + else + if ($this->view == 'week' || $this->view == 'shared' ) + { + $day = $this->date_time->get("+7 days")->get_day_by_index_this_week(0)->get_day_begin(); + } + else + if ($this->view == 'day') + { + $day = $this->date_time->get("tomorrow")->get_day_begin(); + } + else + if ($this->view == 'year') + { + $day = $this->date_time->get_year_begin($this->year+1); + } + else + { + sugar_die("get_next_date_str: not defined for view"); + } + return $day->get_date_str(); + } + + function get_start_slice_idx() + { + + if ($this->isDayView()) + { + $start_at = 8; + + for($i=0;$i < 8; $i++) + { + if (count($this->slice_hash[$this->slices_arr[$i]]->acts_arr) > 0) + { + $start_at = $i; + break; + } + } + return $start_at; + } + else + { + return 0; + } + } + function get_end_slice_idx() + { + if ( $this->view == 'month') + { + return $this->date_time->days_in_month - 1; + } + else if ( $this->view == 'week' || $this->view == 'shared') + { + return 6; + } + else if ($this->isDayView()) + { + $end_at = 18; + + for($i=$end_at;$i < 23; $i++) + { + if (count($this->slice_hash[$this->slices_arr[$i+1]]->acts_arr) > 0) + { + $end_at = $i + 1; + } + } + + + return $end_at; + + } + else + { + return 1; + } + } + + +} + +class Slice +{ + var $view = 'day'; + var $start_time; + var $end_time; + var $acts_arr = array(); + + function Slice($view,$time) + { + $this->view = $view; + $this->start_time = $time; + + if ( $view == 'day') + { + $this->end_time = $this->start_time->get_day_end_time(); + } + if ( $view == 'hour') + { + $this->end_time = $this->start_time->get_hour_end_time(); + } + + } + function get_view() + { + return $this->view; + } + +} + +// global to switch on the offet + +$DO_USER_TIME_OFFSET = false; + +class CalendarActivity +{ + var $sugar_bean; + var $start_time; + var $end_time; + + function CalendarActivity($args) + { + // if we've passed in an array, then this is a free/busy slot + // and does not have a sugarbean associated to it + global $DO_USER_TIME_OFFSET; + global $timedate; + + if ( is_array ( $args )) + { + $this->start_time = clone $args[0]; + $this->end_time = clone $args[1]; + $this->sugar_bean = null; + $timedate->tzGMT($this->start_time); + $timedate->tzGMT($this->end_time); + return; + } + + // else do regular constructor.. + + $sugar_bean = $args; + $this->sugar_bean = $sugar_bean; + + + if ($sugar_bean->object_name == 'Task') + { + $this->start_time = $timedate->fromUser($this->sugar_bean->date_due); + if ( empty($this->start_time)) + { + return null; + } + + $this->end_time = $timedate->fromUser($this->sugar_bean->date_due); + } + else + { + $this->start_time = $timedate->fromUser($this->sugar_bean->date_start); + if ( empty($this->start_time)) + { + return null; + } + $hours = $this->sugar_bean->duration_hours; + if(empty($hours)) { + $hours = 0; + } + $mins = $this->sugar_bean->duration_minutes; + if(empty($mins)) { + $mins = 0; + } + $this->end_time = $this->start_time->get("+$hours hours $mins minutes"); + } + // Convert it back to database time so we can properly manage it for getting the proper start and end dates + $timedate->tzGMT($this->start_time); + $timedate->tzGMT($this->end_time); + } + + function get_occurs_within_where_clause($table_name, $rel_table, $start_ts_obj, $end_ts_obj, $field_name='date_start', $view) + { + global $timedate; + // ensure we're working with user TZ + $start_ts_obj = $timedate->tzUser($start_ts_obj); + $end_ts_obj = $timedate->tzUser($end_ts_obj); + switch ($view) { + case 'month': + $start = $start_ts_obj->get_day_begin(1); + $end = $end_ts_obj->get("first day of next month")->get_day_begin(); + break; + default: + // Date for the past 5 days as that is the maximum duration of a single activity + $start = $start_ts_obj->get("-5 days")->get_day_begin(); + $end = $start_ts_obj->get("+5 days")->get_day_begin(); + break; + } + + $field_date = $GLOBALS['db']->convert($table_name.'.'.$field_name,'datetime'); + $start_day = $start->asDb(); + $end_day = $end->asDb(); + + $where = "($field_date >= '{$start_day}' AND $field_date < '{$end_day}'"; + if($rel_table != '') { + $where .= " AND $rel_table.accept_status != 'decline'"; + } + + $where .= ")"; + return $where; + } + + function get_freebusy_activities($user_focus, $start_date_time, $end_date_time) + { + $act_list = array(); + $vcal_focus = new vCal(); + $vcal_str = $vcal_focus->get_vcal_freebusy($user_focus); + + $lines = explode("\n",$vcal_str); + $utc = new DateTimeZone("UTC"); + foreach ($lines as $line) + { + if ( preg_match('/^FREEBUSY.*?:([^\/]+)\/([^\/]+)/i',$line,$matches)) + { + $dates_arr = array(SugarDateTime::createFromFormat(vCal::UTC_FORMAT, $matches[1], $utc), + SugarDateTime::createFromFormat(vCal::UTC_FORMAT, $matches[2], $utc)); + $act_list[] = new CalendarActivity($dates_arr); + } + } + usort($act_list,'sort_func_by_act_date'); + return $act_list; + } + + + function get_activities($user_id, $show_tasks, $view_start_time, $view_end_time, $view) { + global $current_user; + $act_list = array(); + $seen_ids = array(); + + + // get all upcoming meetings, tasks due, and calls for a user + if(ACLController::checkAccess('Meetings', 'list', $current_user->id == $user_id)) { + $meeting = new Meeting(); + + if($current_user->id == $user_id) { + $meeting->disable_row_level_security = true; + } + + $where = CalendarActivity::get_occurs_within_where_clause($meeting->table_name, $meeting->rel_users_table, $view_start_time, $view_end_time, 'date_start', $view); + $focus_meetings_list = build_related_list_by_user_id($meeting,$user_id,$where); + foreach($focus_meetings_list as $meeting) { + if(isset($seen_ids[$meeting->id])) { + continue; + } + + $seen_ids[$meeting->id] = 1; + $act = new CalendarActivity($meeting); + + if(!empty($act)) { + $act_list[] = $act; + } + } + } + + if(ACLController::checkAccess('Calls', 'list',$current_user->id == $user_id)) { + $call = new Call(); + + if($current_user->id == $user_id) { + $call->disable_row_level_security = true; + } + + $where = CalendarActivity::get_occurs_within_where_clause($call->table_name, $call->rel_users_table, $view_start_time, $view_end_time, 'date_start', $view); + $focus_calls_list = build_related_list_by_user_id($call,$user_id,$where); + + foreach($focus_calls_list as $call) { + if(isset($seen_ids[$call->id])) { + continue; + } + $seen_ids[$call->id] = 1; + + $act = new CalendarActivity($call); + if(!empty($act)) { + $act_list[] = $act; + } + } + } + + + if($show_tasks) { + if(ACLController::checkAccess('Tasks', 'list',$current_user->id == $user_id)) { + $task = new Task(); + + $where = CalendarActivity::get_occurs_within_where_clause('tasks', '', $view_start_time, $view_end_time, 'date_due', $view); + $where .= " AND tasks.assigned_user_id='$user_id' "; + + $focus_tasks_list = $task->get_full_list("", $where,true); + + if(!isset($focus_tasks_list)) { + $focus_tasks_list = array(); + } + + foreach($focus_tasks_list as $task) { + $act = new CalendarActivity($task); + if(!empty($act)) { + $act_list[] = $act; + } + } + } + } + + usort($act_list,'sort_func_by_act_date'); + return $act_list; + } +} diff --git a/modules/Calendar/DateTimeUtil.php b/modules/Calendar/DateTimeUtil.php new file mode 100644 index 00000000..7521d1c1 --- /dev/null +++ b/modules/Calendar/DateTimeUtil.php @@ -0,0 +1,637 @@ +adjustmentForUserTimeZone()*60; + $time_arr['sec'] = $gmtdiff; + return new DateTimeUtil($time_arr,true); + } + + function get_time_end( $start_time, $duration_hours,$duration_minutes) + { + if ( empty($duration_hours)) + { + $duration_hours = "00"; + } + if ( empty($duration_minutes)) + { + $duration_minutes = "00"; + } + + $added_seconds = ($duration_hours * 60 * 60 + $duration_minutes * 60 ) - 1; + + $time_arr = array(); + $time_arr['year'] = $start_time->year; + $time_arr['month'] = $start_time->month; + $time_arr['day'] = $start_time->day; + $time_arr['hour'] = $start_time->hour; + $time_arr['min'] = $start_time->min; + $time_arr['sec'] = $added_seconds; + return new DateTimeUtil($time_arr,true); + + } + + function get_date_str() + { + + $arr = array(); + if ( isset( $this->hour)) + { + array_push( $arr, "hour=".$this->hour); + } + if ( isset( $this->day)) + { + array_push( $arr, "day=".$this->day); + } + if ( isset( $this->month)) + { + array_push( $arr, "month=".$this->month); + } + if ( isset( $this->year)) + { + array_push( $arr, "year=".$this->year); + } + return ("&".implode('&',$arr)); + } + + function get_tomorrow() + { + $date_arr = array('day'=>($this->day + 1), + 'month'=>$this->month, + 'year'=>$this->year); + + return new DateTimeUtil($date_arr,true); + } + function get_yesterday() + { + $date_arr = array('day'=>($this->day - 1), + 'month'=>$this->month, + 'year'=>$this->year); + + return new DateTimeUtil($date_arr,true); + } + + function get_mysql_date() + { + return $this->year."-".$this->zmonth."-".$this->zday; + } + function get_mysql_time() + { + return $this->hour.":".$this->min; + } + + function parse_utc_date_time($str) + { + preg_match('/(\d{4})(\d{2})(\d{2})T(\d{2})(\d{2})(\d{2})Z/',$str,$matches); + + $date_arr = array( + 'year'=>$matches[1], + 'month'=>$matches[2], + 'day'=>$matches[3], + 'hour'=>$matches[4], + 'min'=>$matches[5]); + + $date_time = new DateTimeUtil($date_arr,true); + + $date_arr = array('ts'=>$date_time->ts + $date_time->tz_offset); + + return new DateTimeUtil($date_arr,true); + } + + function get_utc_date_time() + { + return gmdate('Ymd\THi', $this->ts)."00Z"; + } + + function get_first_day_of_last_year() + { + $date_arr = array('day'=>1, + 'month'=>1, + 'year'=>($this->year - 1)); + + return new DateTimeUtil($date_arr,true); + + } + function get_first_day_of_next_year() + { + $date_arr = array('day'=>1, + 'month'=>1, + 'year'=>($this->year + 1)); + + return new DateTimeUtil($date_arr,true); + + } + + function get_first_day_of_next_week() + { + $first_day = $this->get_day_by_index_this_week(0); + $date_arr = array('day'=>($first_day->day + 7), + 'month'=>$first_day->month, + 'year'=>$first_day->year); + + return new DateTimeUtil($date_arr,true); + + } + function get_first_day_of_last_week() + { + $first_day = $this->get_day_by_index_this_week(0); + $date_arr = array('day'=>($first_day->day - 7), + 'month'=>$first_day->month, + 'year'=>$first_day->year); + + return new DateTimeUtil($date_arr,true); + } + function get_first_day_of_last_month() + { + if ($this->month == 1) + { + $month = 12; + $year = $this->year - 1; + } + else + { + $month = $this->month - 1; + $year = $this->year ; + } + $date_arr = array('day'=>1, + 'month'=>$month, + 'year'=>$year); + + return new DateTimeUtil($date_arr,true); + + } + function get_first_day_of_this_month() + { + $month = $this->month; + $year = $this->year ; + $date_arr = array('day'=>1, + 'month'=>$month, + 'year'=>$year); + + return new DateTimeUtil($date_arr,true); + + } + function get_first_day_of_next_month() + { + $date_arr = array('day'=>1, + 'month'=>($this->month + 1), + 'year'=>$this->year); + return new DateTimeUtil($date_arr,true); + } + + + function fill_in_details() + { + global $mod_strings, $timedate; + $hour = 0; + $min = 0; + $sec = 0; + $day = 1; + $month = 1; + $year = 1970; + + if ( isset($this->sec)) + { + $sec = $this->sec; + } + if ( isset($this->min)) + { + $min = $this->min; + } + if ( isset($this->hour)) + { + $hour = $this->hour; + } + if ( isset($this->day)) + { + $day= $this->day; + } + if ( isset($this->month)) + { + $month = $this->month; + } + if ( isset($this->year)) + { + $year = $this->year; + } + else + { + sugar_die ("fill_in_details: year was not set"); + } + $this->ts = mktime($hour,$min,$sec,$month,$day,$year)+$timedate->adjustmentForUserTimeZone()*60; + $this->load_ts($this->ts); + + } + + function load_ts($timestamp) + { + // global $mod_list_strings; + global $current_language; + $mod_list_strings = return_mod_list_strings_language($current_language,"Calendar"); + if ( empty($timestamp)) + { + + $timestamp = time(); + } + + $this->ts = $timestamp; + global $timedate; + + $tdiff = $timedate->adjustmentForUserTimeZone(); + $date_str = date('i:G:H:j:d:t:w:z:L:W:n:m:Y:Z',$timestamp-$tdiff*60); + list( + $this->min, + $this->hour, + $this->zhour, + $this->day, + $this->zday, + $this->days_in_month, + $this->day_of_week, + $this->day_of_year, + $is_leap, + $this->week, + $this->month, + $this->zmonth, + $this->year, + $this->tz_offset) + = explode(':',$date_str); + $this->tz_offset = date('Z') - $tdiff * 60; + + $this->day_of_week_short =$mod_list_strings['dom_cal_weekdays'][$this->day_of_week]; + $this->day_of_week_long=$mod_list_strings['dom_cal_weekdays_long'][$this->day_of_week]; + $this->month_short=$mod_list_strings['dom_cal_month'][$this->month]; + $this->month_long=$mod_list_strings['dom_cal_month_long'][$this->month]; + + $this->days_in_year = 365; + + if ($is_leap == 1) + { + $this->days_in_year += 1; + } + + + } + + function DateTimeUtil($time,$fill_in_details) + { + if (! isset( $time) || count($time) == 0 ) + { + $this->load_ts(null); + } + else if ( isset( $time['ts'])) + { + $this->load_ts($time['ts']); + } + else if ( isset( $time['date_str'])) + { + list($this->year,$this->month,$this->day)= + explode("-",$time['date_str']); + if ($fill_in_details == true) + { + $this->fill_in_details(); + } + } + else + { + if ( isset($time['sec'])) + { + $this->sec = $time['sec']; + } + if ( isset($time['min'])) + { + $this->min = $time['min']; + } + if ( isset($time['hour'])) + { + $this->hour = $time['hour']; + } + if ( isset($time['day'])) + { + $this->day = $time['day']; + } + if ( isset($time['week'])) + { + $this->week = $time['week']; + } + if ( isset($time['month'])) + { + $this->month = $time['month']; + } + if ( isset($time['year']) && $time['year'] >= 1970) + { + $this->year = $time['year']; + } + else + { + return null; + } + + if ($fill_in_details == true) + { + $this->fill_in_details(); + } + + } + } + + function dump_date_info() + { + echo "min:".$this->min."
    \n"; + echo "hour:".$this->hour."
    \n"; + echo "day:".$this->day."
    \n"; + echo "month:".$this->month."
    \n"; + echo "year:".$this->year."
    \n"; + } + + function get_hour() + { + $hour = $this->hour; + if ($this->hour > 12) + { + $hour -= 12; + } + else if ($this->hour == 0) + { + $hour = 12; + } + return $hour; + } + + function get_24_hour() + { + return $this->hour; + } + + function get_am_pm() + { + if ($this->hour >=12) + { + return "PM"; + } + return "AM"; + } + + function get_day() + { + return $this->day; + } + + function get_month() + { + return $this->month; + } + + function get_day_of_week_short() + { + return $this->day_of_week_short; + } + function get_day_of_week() + { + return $this->day_of_week_long; + } + + + function get_month_name() + { + return $this->month_long; + } + + function get_datetime_by_index_today($hour_index) + { + $arr = array(); + + if ( $hour_index < 0 || $hour_index > 23 ) + { + sugar_die("hour is outside of range"); + } + + $arr['hour'] = $hour_index; + $arr['min'] = 0; + $arr['day'] = $this->day; + + $arr['month'] = $this->month; + $arr['year'] = $this->year; + + return new DateTimeUtil($arr,true); + } + + function get_hour_end_time() + { + $arr = array(); + $arr['hour'] = $this->hour; + $arr['min'] = 59; + $arr['sec'] = 59; + $arr['day'] = $this->day; + + $arr['month'] = $this->month; + $arr['year'] = $this->year; + + return new DateTimeUtil($arr,true); + } + + function get_day_end_time() + { + $arr = array(); + $arr['hour'] = 23; + $arr['min'] = 59; + $arr['sec'] = 59; + $arr['day'] = $this->day; + + $arr['month'] = $this->month; + $arr['year'] = $this->year; + + return new DateTimeUtil($arr,true); + } + + function get_day_by_index_this_week($day_index) + { + $arr = array(); + + if ( $day_index < 0 || $day_index > 6 ) + { + sugar_die("day is outside of week range"); + } + + $arr['day'] = $this->day + + ($day_index - $this->day_of_week); + + $arr['month'] = $this->month; + $arr['year'] = $this->year; + + return new DateTimeUtil($arr,true); + } + function get_day_by_index_this_year($month_index) + { + $arr = array(); + $arr['month'] = $month_index+1; + $arr['year'] = $this->year; + // wp: Find the last day of the month requested, ensure that is the ceiling of the day param + $arr['day'] = min(strftime("%d", mktime(0, 0, 0, $arr['month']+1, 0, $arr['year'])), $this->day); + + return new DateTimeUtil($arr,true); + } + + function get_day_by_index_this_month($day_index) + { + $arr = array(); + $arr['day'] = $day_index + 1; + $arr['month'] = $this->month; + $arr['year'] = $this->year; + + return new DateTimeUtil($arr,true); + } + + function getHashList($view, &$start_time, &$end_time) + { + $hash_list = array(); + + if (version_compare(phpversion(), '5.0') < 0) + $new_time = $start_time; + else + $new_time = clone($start_time); + + $arr = array(); + + if ( $view != 'day') + { + $end_time = $end_time->get_day_end_time(); + } + + + if (empty($new_time->ts)) + { + return; + } + + if ( $new_time->ts == $end_time->ts) + { + $end_time->ts+=1; + } + + while( $new_time->ts < $end_time->ts) + { + + $arr['month'] = $new_time->month; + $arr['year'] = $new_time->year; + $arr['day'] = $new_time->day; + $arr['hour'] = $new_time->hour; + if ( $view == 'day') + { + $hash_list[] = $new_time->get_mysql_date().":".$new_time->hour; + $arr['hour'] += 1; + } + else + { + $hash_list[] = $new_time->get_mysql_date(); + $arr['day'] += 1; + } + $new_time = new DateTimeUtil($arr,true); + } + return $hash_list; + } + +} + +?> diff --git a/modules/Calendar/Forms.php b/modules/Calendar/Forms.php new file mode 100644 index 00000000..26fbd9db --- /dev/null +++ b/modules/Calendar/Forms.php @@ -0,0 +1,45 @@ + \ No newline at end of file diff --git a/modules/Calendar/Menu.php b/modules/Calendar/Menu.php new file mode 100644 index 00000000..00da147a --- /dev/null +++ b/modules/Calendar/Menu.php @@ -0,0 +1,57 @@ + diff --git a/modules/Calendar/SubPanelSharedCalendar.php b/modules/Calendar/SubPanelSharedCalendar.php new file mode 100644 index 00000000..b2510b2a --- /dev/null +++ b/modules/Calendar/SubPanelSharedCalendar.php @@ -0,0 +1,69 @@ +$focus, +"users"=>$focus->get_users()); + +template_shared_calendar($args); + +$mod_strings = return_module_language($current_language,$temp_module); +$currentModule = $_REQUEST['module']; +/// END SHARED CALENDAR +} + +?> diff --git a/modules/Calendar/TasksListView.html b/modules/Calendar/TasksListView.html new file mode 100644 index 00000000..29047545 --- /dev/null +++ b/modules/Calendar/TasksListView.html @@ -0,0 +1,61 @@ + + + + +{PAGINATION} + + + + + + + + + + + + + + + +
    {MOD.LBL_LIST_STATUS}{arrow_start}{status_arrow}{arrow_end}{MOD.LBL_LIST_SUBJECT}{arrow_start}{name_arrow}{arrow_end}{MOD.LBL_LIST_DUE_DATE}{arrow_start}{date_due_arrow}{arrow_end}
    {TASK.STATUS}{TASK.NAME}{TASK.DATE_DUE}
    + diff --git a/modules/Calendar/TasksListView.php b/modules/Calendar/TasksListView.php new file mode 100644 index 00000000..b7ffaab7 --- /dev/null +++ b/modules/Calendar/TasksListView.php @@ -0,0 +1,144 @@ +setPreference('ListViewDisplayColumns', array(), 0, 'Calendar'); + +$savedDisplayColumns = $current_user->getPreference('ListViewDisplayColumns', 'Calendar'); // get user defined display columns + +$json = getJSONobj(); +$seedTask = new Task(); + +// setup listview smarty +$lv = new ListViewSmarty(); + +$displayColumns = array(); +// check $_REQUEST if new display columns from post +if(!empty($_REQUEST['displayColumns'])) { + foreach(explode('|', $_REQUEST['displayColumns']) as $num => $col) { + if(!empty($listViewDefs['Tasks'][$col])) + $displayColumns[$col] = $listViewDefs['Tasks'][$col]; + } +} +elseif(!empty($savedDisplayColumns)) { // use user defined display columns from preferences + $displayColumns = $savedDisplayColumns; +} +else { // use columns defined in listviewdefs for default display columns + foreach($listViewDefs['Calendar'] as $col => $params) { + if(!empty($params['default']) && $params['default']) + $displayColumns[$col] = $params; + } +} +$params = array('massupdate' => false); // setup ListViewSmarty params +if(!empty($_REQUEST['orderBy'])) { // order by coming from $_REQUEST + $params['orderBy'] = $_REQUEST['orderBy']; + $params['overrideOrder'] = true; + if(!empty($_REQUEST['sortOrder'])) $params['sortOrder'] = $_REQUEST['sortOrder']; +} +$params['orderBy'] = ''; +$lv->displayColumns = $displayColumns; + +// use the stored query if there is one +if (!isset($where)) $where = ""; +require_once('modules/MySettings/StoreQuery.php'); +$storeQuery = new StoreQuery(); +if(!isset($_REQUEST['query'])){ + $storeQuery->loadQuery('Calendar'); + $storeQuery->populateRequest(); +}else{ + $storeQuery->saveFromGet('Calendar'); +} +global $timedate; + +//jc: bug 14616 - dates need to specificy the end of the current date in order to get tasks +// that are scheduled to start today +$today = $timedate->getNow(true)->get_day_end_time()->asDb(); +//end bug 14616 + +$where = "(tasks.assigned_user_id='$current_user->id' and tasks.status<>'Completed' and tasks.status<>'Deferred'"; +$where .= "and (tasks.date_start is NULL or tasks.date_start <= '$today'))"; + +$lv->export = false; +$lv->delete = false; +$lv->select = false; +$lv->mailMerge = false; +$lv->multiSelect = false; +$lv->showMassupdateFields = false; +$lv->setup($seedTask, 'include/ListView/ListViewNoMassUpdate.tpl', $where, $params); +echo getClassicModuleTitle($current_module_strings['LBL_MODULE_NAME'], array($current_module_strings['LBL_LIST_FORM_TITLE']), false); + + +echo $lv->display(); +//Fake Mass Update +$form = "
    "; +echo $form; +?> diff --git a/modules/Calendar/index.php b/modules/Calendar/index.php new file mode 100644 index 00000000..3c128324 --- /dev/null +++ b/modules/Calendar/index.php @@ -0,0 +1,128 @@ + 2037 || $_REQUEST['year'] < 1970) + { + print("Sorry, calendar cannot handle the year you requested"); + print("
    Year must be between 1970 and 2037"); + exit; + } + $date_arr['year'] = $_REQUEST['year']; +} + +// today adjusted for user's timezone +$args['calendar'] = new Calendar($_REQUEST['view'], $date_arr); +if ($_REQUEST['view'] == 'day' || $_REQUEST['view'] == 'week' || $_REQUEST['view'] == 'month') +{ + global $current_user; + $args['calendar']->add_activities($current_user); +} +$args['view'] = $_REQUEST['view']; + +?> + + + + + + + + +
    + + + +
    diff --git a/modules/Calendar/language/en_us.lang.php b/modules/Calendar/language/en_us.lang.php new file mode 100644 index 00000000..3b8c1538 --- /dev/null +++ b/modules/Calendar/language/en_us.lang.php @@ -0,0 +1,142 @@ +'Calendar', + 'LBL_MODULE_TITLE'=>'Calendar', + 'LBL_MODULE_ACTION'=>'View', + 'LNK_NEW_CALL' => 'Log Call', + 'LNK_NEW_MEETING' => 'Schedule Meeting', + 'LNK_NEW_APPOINTMENT' => 'Create Appointment', + 'LNK_NEW_TASK' => 'Create Task', + 'LNK_CALL_LIST' => 'View Calls', + 'LNK_MEETING_LIST' => 'View Meetings', + 'LNK_TASK_LIST' => 'View Tasks', + 'LNK_VIEW_CALENDAR' => 'View Calendar', + 'LNK_IMPORT_CALLS'=>'Import Calls', + 'LNK_IMPORT_MEETINGS'=>'Import Meetings', + 'LNK_IMPORT_TASKS'=>'Import Tasks', + 'LBL_MONTH' => 'Month', + 'LBL_DAY' => 'Day', + 'LBL_YEAR' => 'Year', + 'LBL_WEEK' => 'Week', + 'LBL_PREVIOUS_MONTH' => 'Previous Month', + 'LBL_PREVIOUS_DAY' => 'Previous Day', + 'LBL_PREVIOUS_YEAR' => 'Previous Year', + 'LBL_PREVIOUS_WEEK' => 'Previous Week', + 'LBL_NEXT_MONTH' => 'Next Month', + 'LBL_NEXT_DAY' => 'Next Day', + 'LBL_NEXT_YEAR' => 'Next Year', + 'LBL_NEXT_WEEK' => 'Next Week', + 'LBL_AM' => 'AM', + 'LBL_PM' => 'PM', + 'LBL_SCHEDULED' => 'Scheduled', + 'LBL_BUSY' => 'Busy', + 'LBL_CONFLICT' => 'Conflict', + 'LBL_USER_CALENDARS' => 'User Calendars', + 'LBL_SHARED' => 'Shared', + 'LBL_PREVIOUS_SHARED' => 'Previous', + 'LBL_NEXT_SHARED' => 'Next', + 'LBL_SHARED_CAL_TITLE' => 'Shared Calendar', + 'LBL_USERS' => 'User', + 'LBL_REFRESH' => 'Refresh', + 'LBL_EDIT' => 'Edit', + 'LBL_SELECT_USERS' => 'Select users for calendar display', + 'LBL_FILTER_BY_TEAM' => 'Filter user list by team:', + 'LBL_ASSIGNED_TO_NAME' => 'Assigned to', + 'LBL_DATE' => 'Start Date & Time' +); + +$mod_list_strings = array( +'dom_cal_weekdays'=>array( +"Sun", +"Mon", +"Tue", +"Wed", +"Thu", +"Fri", +"Sat", +), +'dom_cal_weekdays_long'=>array( +"Sunday", +"Monday", +"Tuesday", +"Wednesday", +"Thursday", +"Friday", +"Saturday", +), +'dom_cal_month'=>array( +"", +"Jan", +"Feb", +"Mar", +"Apr", +"May", +"Jun", +"Jul", +"Aug", +"Sep", +"Oct", +"Nov", +"Dec", +), +'dom_cal_month_long'=>array( +"", +"January", +"February", +"March", +"April", +"May", +"June", +"July", +"August", +"September", +"October", +"November", +"December", +) +); +?> diff --git a/modules/Calendar/metadata/listviewdefs.php b/modules/Calendar/metadata/listviewdefs.php new file mode 100644 index 00000000..6e35a68f --- /dev/null +++ b/modules/Calendar/metadata/listviewdefs.php @@ -0,0 +1,68 @@ + array( + 'width' => '10', + 'label' => 'LBL_LIST_STATUS', + 'link' => false, + 'default' => true), + */ + 'SET_COMPLETE' => array( + 'width' => '1', + 'label' => 'LBL_LIST_CLOSE', + 'link' => true, + 'sortable' => false, + 'default' => true, + 'related_fields' => array('status')), + 'NAME' => array( + 'width' => '40', + 'label' => 'LBL_LIST_SUBJECT', + 'link' => true, + 'default' => true), + 'DATE_DUE' => array( + 'width' => '15', + 'label' => 'LBL_LIST_DUE_DATE', + 'link' => false, + 'default' => true), +); +?> diff --git a/modules/Calendar/small_month.php b/modules/Calendar/small_month.php new file mode 100644 index 00000000..fb85f6c0 --- /dev/null +++ b/modules/Calendar/small_month.php @@ -0,0 +1,56 @@ + + diff --git a/modules/Calendar/templates/template_shared_calendar.php b/modules/Calendar/templates/template_shared_calendar.php new file mode 100644 index 00000000..4d9509da --- /dev/null +++ b/modules/Calendar/templates/template_shared_calendar.php @@ -0,0 +1,183 @@ +$args['activity_focus']); +$calendar = new Calendar("day",$date_arr); +$calendar->show_tasks = false; +$calendar->toggle_appt = false; +foreach($args['users'] as $user) +{ +/* + if ($user->id != $current_user->id) + { +*/ + $calendar->add_activities($user,'vfb'); +/* + } +*/ +} +?> +

    + + +

    +
    +

    date_time);?>

    +
    + + + +get_start_slice_idx(); + $end_slice_idx = $calendar->get_end_slice_idx(); + $cur_slice_idx = 1; + $slice_args = array(); + for($cur_slice_idx=$start_slice_idx;$cur_slice_idx<=$end_slice_idx;$cur_slice_idx++) + { + $slice_args['slice'] = $calendar->slice_hash[$calendar->slices_arr[$cur_slice_idx]]; + $slice_args['calendar'] = $calendar; + //print_r($cur_time); + ?> + + + + + + +slice_hash[$calendar->slices_arr[$cur_slice_idx]]; + + // if this current activitiy occurs within this time slice + if ( Calendar::occurs_within_slice($cur_slice,$calendar->activity_focus)) + { +/* + $got_conflict = 0; + if ( isset($cur_slice->acts_arr[$curr_user->id]) ) + { + foreach( $cur_slice->acts_arr[$curr_user->id] as $act) + { + if ($act->sugar_bean->id != $calendar->activity_focus->sugar_bean->id) + { + $got_conflict = 1; + } + } + } +*/ + + if (isset($cur_slice->acts_arr[$curr_user->id]) && count($cur_slice->acts_arr[$curr_user->id]) > 1) + { +?> + + + + +acts_arr[$curr_user->id])) + { + ?> + + + + + + + + +
    +full_name; ?>    
    + + + + + + + + + + + +
    <?php echo $mod_strings['LBL_SCHEDULED']; ?>   <?php echo $mod_strings['LBL_BUSY']; ?>   <?php echo $mod_strings['LBL_CONFLICT']; ?>  
    +

    + diff --git a/modules/Calendar/templates/templates_calendar.php b/modules/Calendar/templates/templates_calendar.php new file mode 100644 index 00000000..49baf236 --- /dev/null +++ b/modules/Calendar/templates/templates_calendar.php @@ -0,0 +1,868 @@ + + '; + } + +?> + + + + +
    + +selected="selected" value=" get_view_name($tab)]; ?> " title="get_view_name($tab)]; ?>" onclick="window.location.href='index.php?module=Calendar&action=index&view=date_time->get_date_str(); ?>'">  + +
    + + +start_time->month; + $cal_arr['year'] = $args['slice']->start_time->year; + $newargs['calendar'] = new Calendar('month', $cal_arr); + $newargs['calendar']->show_only_current_slice = true; + $newargs['calendar']->show_activities = false; + $newargs['calendar']->show_week_on_month_view = false; + template_calendar_month($newargs); +?> +acts_arr[$current_user->id])) { + return; + } + foreach($args['slice']->acts_arr[$current_user->id] as $act) { + $fields = array(); + foreach($act->sugar_bean->field_name_map as $field) { + if(!empty($act->sugar_bean->$field['name'])) + $fields[strtoupper($field['name'])] = $act->sugar_bean->$field['name']; + } + + $extra = "id=\"adspan_{$act->sugar_bean->id}\" " + . "onmouseover=\"return SUGAR.util.getAdditionalDetails( '{$act->sugar_bean->module_dir}','{$act->sugar_bean->id}', 'adspan_{$act->sugar_bean->id}');\" " + . "onmouseout=\"return SUGAR.util.clearAdditionalDetailsCall()\" onmouseout=\"return nd(1000);\" "; + + + $count ++; + echo '
    '; + if($act->sugar_bean->object_name == 'Call') { + if ( isset($app_list_strings['call_status_dom'][$act->sugar_bean->status]) ) { + $callStatus = $app_list_strings['call_status_dom'][$act->sugar_bean->status]; + } + else { + $callStatus = ''; + } + echo ' + '; + } else if($act->sugar_bean->object_name == 'Meeting') { + if ( isset($app_list_strings['meeting_status_dom'][$act->sugar_bean->status]) ) { + $meetingStatus = $app_list_strings['meeting_status_dom'][$act->sugar_bean->status]; + } + else { + $meetingStatus = ''; + } + $out = ' + "; + echo $out; + + } else if($act->sugar_bean->object_name == 'Task') { + echo ' + '; + } + echo '
    ' . SugarThemeRegistry::current()->getImage('Calls','alt="'.$app_list_strings['call_status_dom'][$act->sugar_bean->status].': '.$act->sugar_bean->name.'"') . '' . $callStatus . ': ' . $act->sugar_bean->name . '' . SugarThemeRegistry::current()->getImage('Meetings','alt="'.$app_list_strings['meeting_status_dom'][$act->sugar_bean->status].': '.$act->sugar_bean->name.'"') . '' . $meetingStatus . ': ' . $act->sugar_bean->name .''; + + /////////////////////////////////////////////////////////////// + //// MEETING INTEGRATION + if(method_exists($act->sugar_bean, 'hasIntegratedMeeting')) { + if($act->sugar_bean->hasIntegratedMeeting()) { + $out .= $act->sugar_bean->miIcon; + } + } + //// END MEETING INTEGRATION + /////////////////////////////////////////////////////////////// + $out .= "' . SugarThemeRegistry::current()->getImage('Tasks','alt="'.$app_list_strings['task_status_dom'][$act->sugar_bean->status].': '.$act->sugar_bean->name.'"') . ''.$app_list_strings['task_status_dom'][$fields['STATUS']].': ' . $act->sugar_bean->name . '
    '; + } + } + + function template_echo_slice_activities_shared($args) { + global $app_list_strings; + + global $shared_user, $timedate; + $count = 0; + if(empty($args['slice']->acts_arr[$shared_user->id])) { + return; + } + + $out = ''; + + foreach($args['slice']->acts_arr[$shared_user->id] as $act) { + $count ++; + echo "
    + "; + + if($act->sugar_bean->object_name == 'Call') { + echo ""; + + if(empty($act->sugar_bean->name)) { + echo ""; + } else { + echo ""; + } + } else if($act->sugar_bean->object_name == 'Meeting') { + echo ""; + + if(empty($act->sugar_bean->name)) { + echo ""; + } else { + echo ""; + echo $out; + } + } else if($act->sugar_bean->object_name == 'Task') { + echo ""; + + if(empty($act->sugar_bean->name)) { + echo ""; + } else { + echo ""; + } + } + echo "
    " . SugarThemeRegistry::current()->getImage('Calls','alt=\"'.$app_list_strings['call_status_dom'][$act->sugar_bean->status].': '.$act->sugar_bean->name.'\"') . ""; + echo $timedate->getTimePart($act->sugar_bean->date_start); + echo "
    + sugar_bean->id."\">". + $app_list_strings['call_status_dom'][$act->sugar_bean->status].": ". + $act->sugar_bean->name."
    (". + $timedate->getTimePart($act->sugar_bean->date_start).")
    ". + SugarThemeRegistry::current()->getImage('Meetings','alt=\"'.$app_list_strings['meeting_status_dom'][$act->sugar_bean->status].': '.$act->sugar_bean->name.'\"'); + echo "". + $timedate->getTimePart($act->sugar_bean->date_start); + echo "
    + sugar_bean->id."\">". + $app_list_strings['meeting_status_dom'][$act->sugar_bean->status].":". + $act->sugar_bean->name."
    (". + $timedate->getTimePart($act->sugar_bean->date_start).")
    "; + + // MEETING INTEGRATION + if($act->sugar_bean->hasIntegratedMeeting()) { + $out .= $act->sugar_bean->miIcon; + } + // END MEETING INTEGRATION + + $out .= "
    ". + SugarThemeRegistry::current()->getImage('Tasks','alt="'.$app_list_strings['task_status_dom'][$act->sugar_bean->status].': '.$act->sugar_bean->name.'"'); + echo "". + $timedate->getTimePart($act->sugar_bean->date_due); + echo "
    + sugar_bean->id."\">". + $app_list_strings['task_status_dom'][$act->sugar_bean->status].': '.$act->sugar_bean->name."
    (". + $timedate->getTimePart($act->sugar_bean->date_due).")
    "; + } + } + + ///////////////////////////////// + // template + ///////////////////////////////// + function template_cal_day_slice($args) { + /* + echo "cale:".$args['calendar']->view; + echo "cal1:".$args['calendar']->date_time->month; + echo "cal3:".$args['slice']->date_time->month; + */ + if($args['calendar']->show_only_current_slice == false || $args['calendar']->date_time->month == $args['slice']->start_time->month) { + template_echo_slice_date($args); + + if($args['calendar']->show_activities == true) { + template_echo_slice_activities($args); + } + + } + } + + ///////////////////////////////// + // template + ///////////////////////////////// + function template_calendar($args) { + global $timedate; + if(isset($args['size']) && $args['size'] == 'small') { + $args['calendar']->show_activities = false; + $args['calendar']->show_week_on_month_view = false; + } + + $newargs = array(); + $newargs['view'] = $args['view']; + $newargs['calendar'] = $args['calendar']; + if(!isset($args['size']) || $args['size'] != 'small') { + template_cal_tabs($newargs); + } + + if(isset($_REQUEST['view']) && $_REQUEST['view'] == 'shared') { + global $ids; + global $current_user; + global $mod_strings; + global $app_list_strings, $current_language, $currentModule, $action, $app_strings; + $current_module_strings = return_module_language($current_language, 'Calendar'); + + $ids = array(); + $user_ids = $current_user->getPreference('shared_ids'); + //get list of user ids for which to display data + if(!empty($user_ids) && count($user_ids) != 0 && !isset($_REQUEST['shared_ids'])) { + $ids = $user_ids; + } + elseif(isset($_REQUEST['shared_ids']) && count($_REQUEST['shared_ids']) > 0) { + $ids = $_REQUEST['shared_ids']; + $current_user->setPreference('shared_ids', $_REQUEST['shared_ids']); + } else { + //$ids = get_user_array(false); + //$ids = array_keys($ids); + $ids = array($current_user->id); + + } + + + //get team id for which to display user list + + $tools = ''; + + echo get_form_header($mod_strings['LBL_SHARED_CAL_TITLE'], $tools, false); + if(empty($_SESSION['shared_ids'])) + $_SESSION['shared_ids'] = ""; + + echo " + + +

    "; + + if(isset($_REQUEST['edit']) && $_REQUEST['edit']) + echo " "; + + echo " + + + + + + + + + + +
    + + + + + + +
    "; + + if(!isset($args['size']) || $args['size'] != 'small') { + template_get_previous_calendar($args); + } + + echo " + "; + + if(isset( $args['size']) && $args['size'] = 'small') + { + ?> + + +

    +date_time); ?> +

    +"; + } +?> + +
    +
    +view == 'month') { + template_calendar_month($args); + } else + if($args['calendar']->view == 'year') { + template_calendar_year($args); + } else + if($args['calendar']->view == 'shared') { + + global $current_user, $shared_user; + $shared_args = array(); + foreach($args as $key => $val) { + $shared_args[$key] = $val; + } + $shared_args['calendar'] = $args['calendar']; + $shared_user = new User(); + foreach($ids as $member) { + $shared_user->retrieve($member); + $shared_args['calendar']->show_tasks = true; + $shared_args['calendar']->add_activities($shared_user); + $shared_args['show_link'] = 'off'; + if(($shared_user->id == $current_user->id)) + $shared_args['show_link'] = 'on'; + echo '
    '.$shared_user->full_name.'
    '; + template_calendar_horizontal($shared_args); + } + } else { + template_calendar_vertical($args); + } +?> +
    + + + + + +
    + +
    + + + get_start_slice_idx(); + $end_slice_idx = $args['calendar']->get_end_slice_idx(); + $cur_slice_idx = 1; + for($cur_slice_idx = $start_slice_idx; $cur_slice_idx <= $end_slice_idx; $cur_slice_idx ++) { + $calendar = $args['calendar']; + $args['slice'] = $calendar->slice_hash[$calendar->slices_arr[$cur_slice_idx]]; +?> + + + + +
    +
    "; +} + +function template_cal_vertical_slice($args) { + global $timedate; +?> +
    + + + + + + + + +
    + + + +
    + + + +slice_hash[$args['calendar']->slices_arr[$count]]; +?> + + + + + + +
    +
    + + + + + get_start_slice_idx(); + $end_slice_idx = $args['calendar']->get_end_slice_idx(); + $cur_slice_idx = 1; + */ + $count = 0; + if($args['calendar']->slice_hash[$args['calendar']->slices_arr[35]]->start_time->month != $args['calendar']->date_time->month) { + $rows = 5; + } else { + $rows = 6; + } +?> + +slice_hash[$args['calendar']->slices_arr[$i]]; +?> + + + + + +slice_hash[$args['calendar']->slices_arr[$count]]; +?> + + + + + + +
    start_time->get_day_of_week_short(); ?>
    class="weekEnd">
    +start_time->get_mysql_date() == $timedate->nowDbDate()) { + return true; + } + return false; +} + +function template_echo_daily_view_hour($args) { + + $slice = $args['slice']; + $hour = $slice->start_time->get_hour(); + return $hour; + +} + +function template_echo_daily_view_24_hour($args) { + + $slice = $args['slice']; + $hour = $slice->start_time->get_24_hour(); + return $hour; + +} + +function template_echo_slice_date($args) { + global $mod_strings; + global $timedate; + $slice = $args['slice']; + + if($slice->view != 'hour') { + if($slice->start_time->get_day_of_week_short() == 'Sun' || $slice->start_time->get_day_of_week_short() == 'Sat') { + echo "get_view().$slice->start_time->get_date_str()."\" "; + } else { + echo "get_view().$slice->start_time->get_date_str()."\" "; + } + } + + if($slice->view == 'day' &&($args['calendar']->view == 'week')) { + echo ">"; + echo $slice->start_time->get_day_of_week_short(); + echo " "; + echo $slice->start_time->get_day(); + } + elseif($args['calendar']->view == 'shared') { + echo ">"; + echo $slice->start_time->get_day_of_week_short(); + echo " "; + echo $slice->start_time->get_day(); + } else + if($slice->view == 'day') { + echo ">"; + if($slice->start_time->get_month() == $args['calendar']->date_time->get_month()) { + echo $slice->start_time->get_day(); + } + //echo $slice->start_time->get_day(); + } else + if($slice->view == 'month') { + echo ">"; + echo $slice->start_time->get_month_name(); + } else + if($slice->view == 'hour') { + if($args['calendar']->toggle_appt == true) { + echo ''; + } + //Bug 13324, We are now using the users time format instead of a custom AM/PM setting + echo $timedate->to_display_time($slice->start_time->get_24_hour() . ":00:00", true, false); + } else { + sugar_die("template_echo_slice_date: view not supported"); + } + + echo ""; +} + +function template_echo_slice_date_nolink($args) { + global $mod_strings; + $slice = $args['slice']; + echo $slice->start_time->get_day_of_week_short(); + echo " "; + echo $slice->start_time->get_day(); +} + +function template_echo_date_info($view, $date_time) { + global $current_user; + $dateFormat = $current_user->getUserDateTimePreferences(); + + if($view == 'month') { + for($i=0; $iyear; + break; + case "m": + echo " ".$date_time->get_month_name(); + break; + } + } + } else + if($view == 'week' || $view == 'shared') { + $first_day = $date_time->get_day_by_index_this_week(0); + $last_day = $date_time->get_day_by_index_this_week(6); + + for($i=0; $iyear; + break; + case "m": + echo " ".$first_day->get_month_name(); + break; + case "d": + echo " ".$first_day->get_day(); + break; + } + } + echo " - "; + for($i=0; $iyear; + break; + case "m": + echo " ".$last_day->get_month_name(); + break; + case "d": + echo " ".$last_day->get_day(); + break; + } + } + } else + if($view == 'day') { + echo $date_time->get_day_of_week()." "; + + for($i=0; $iyear; + break; + case "m": + echo " ".$date_time->get_month_name(); + break; + case "d": + echo " ".$date_time->get_day(); + break; + } + } + } else + if($view == 'year') { + echo $date_time->year; + } else { + sugar_die("echo_date_info: date not supported"); + } +} + +function template_get_next_calendar($args) { + + global $mod_strings; +?> +get_view_name($args['calendar']->view)]; ?> getImage('calendar_next','alt="'. $mod_strings["LBL_NEXT_".$args['calendar']->get_view_name($args['calendar']->view)].'" align="absmiddle" border="0"'); ?> + +getImage('calendar_previous','alt="'. $mod_strings["LBL_PREVIOUS_".$args['calendar']->get_view_name($args['calendar']->view)].'" align="absmiddle" border="0"'); ?>  get_view_name($args['calendar']->view)]; ?> + + diff --git a/modules/Calendar/views/view.list.php b/modules/Calendar/views/view.list.php new file mode 100644 index 00000000..f3438d11 --- /dev/null +++ b/modules/Calendar/views/view.list.php @@ -0,0 +1,52 @@ + diff --git a/modules/Calls/Call.php b/modules/Calls/Call.php new file mode 100644 index 00000000..65d7346b --- /dev/null +++ b/modules/Calls/Call.php @@ -0,0 +1,687 @@ +'00','15'=>'15','30'=>'30','45'=>'45'); + var $table_name = "calls"; + var $rel_users_table = "calls_users"; + var $rel_contacts_table = "calls_contacts"; + var $rel_leads_table = "calls_leads"; + var $module_dir = 'Calls'; + var $object_name = "Call"; + var $new_schema = true; + var $importable = true; + + // This is used to retrieve related fields from form posts. + var $additional_column_fields = array('assigned_user_name', 'assigned_user_id', 'contact_id', 'user_id', 'contact_name'); + var $relationship_fields = array( 'account_id' => 'accounts', + 'opportunity_id' => 'opportunities', + 'contact_id' => 'contacts', + 'case_id' => 'cases', + 'user_id' => 'users', + 'assigned_user_id' => 'users', + 'note_id' => 'notes', + ); + + function Call() { + parent::SugarBean(); + global $app_list_strings; + + $this->setupCustomFields('Calls'); + + foreach ($this->field_defs as $field) { + $this->field_name_map[$field['name']] = $field; + } + + + if(!empty($GLOBALS['app_list_strings']['duration_intervals'])) + $this->minutes_values = $GLOBALS['app_list_strings']['duration_intervals']; + } + + // save date_end by calculating user input + // this is for calendar + function save($check_notify = FALSE) { + global $timedate,$current_user; + global $disable_date_format; + + if(isset($this->date_start) && isset($this->duration_hours) && isset($this->duration_minutes)) + { + $td = $timedate->fromDb($this->date_start); + if($td) + { + $this->date_end = $td->modify("+{$this->duration_hours} hours {$this->duration_minutes} mins")->asDb(); + } + } + + if(!empty($_REQUEST['send_invites']) && $_REQUEST['send_invites'] == '1') { + $check_notify = true; + } else { + $check_notify = false; + } + if(empty($_REQUEST['send_invites'])) { + if(!empty($this->id)) { + $old_record = new Call(); + $old_record->retrieve($this->id); + $old_assigned_user_id = $old_record->assigned_user_id; + } + if((empty($this->id) && isset($_REQUEST['assigned_user_id']) && !empty($_REQUEST['assigned_user_id']) && $GLOBALS['current_user']->id != $_REQUEST['assigned_user_id']) || (isset($old_assigned_user_id) && !empty($old_assigned_user_id) && isset($_REQUEST['assigned_user_id']) && !empty($_REQUEST['assigned_user_id']) && $old_assigned_user_id != $_REQUEST['assigned_user_id']) ){ + $this->special_notification = true; + $check_notify = true; + if(isset($_REQUEST['assigned_user_name'])) { + $this->new_assigned_user_name = $_REQUEST['assigned_user_name']; + } + } + } + if (empty($this->status) ) { + $this->status = $this->getDefaultStatus(); + } + /*nsingh 7/3/08 commenting out as bug #20814 is invalid + if($current_user->getPreference('reminder_time')!= -1 && isset($_POST['reminder_checked']) && isset($_POST['reminder_time']) && $_POST['reminder_checked']==0 && $_POST['reminder_time']==-1){ + $this->reminder_checked = '1'; + $this->reminder_time = $current_user->getPreference('reminder_time'); + }*/ + + $return_id = parent::save($check_notify); + global $current_user; + + + if($this->update_vcal) { + vCal::cache_sugar_vcal($current_user); + } + + return $return_id; + } + + /** Returns a list of the associated contacts + * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.. + * All Rights Reserved.. + * Contributor(s): ______________________________________.. + */ + function get_contacts() + { + // First, get the list of IDs. + $query = "SELECT contact_id as id from calls_contacts where call_id='$this->id' AND deleted=0"; + + return $this->build_related_list($query, new Contact()); + } + + + function get_summary_text() + { + return "$this->name"; + } + + function create_list_query($order_by, $where, $show_deleted=0) + { + $custom_join = $this->custom_fields->getJOIN(); + $query = "SELECT "; + $query .= " + calls.*,"; + if ( preg_match("/calls_users\.user_id/",$where)) + { + $query .= "calls_users.required, + calls_users.accept_status,"; + } + + $query .= " + users.user_name as assigned_user_name"; + if($custom_join){ + $query .= $custom_join['select']; + } + + // this line will help generate a GMT-metric to compare to a locale's timezone + + if ( preg_match("/contacts/",$where)){ + $query .= ", contacts.first_name, contacts.last_name"; + $query .= ", contacts.assigned_user_id contact_name_owner"; + } + $query .= " FROM calls "; + + /* + if ( $this->db->dbType == 'mssql' ) + { + $query .= ", calls.date_start "; + if ( preg_match("/contacts/",$where)){ + $query .= ", contacts.first_name, contacts.last_name"; + $query .= ", contacts.assigned_user_id contact_name_owner"; + } + $query .= " FROM calls "; + } + */ + if ( preg_match("/contacts/",$where)){ + $query .= "LEFT JOIN calls_contacts + ON calls.id=calls_contacts.call_id + LEFT JOIN contacts + ON calls_contacts.contact_id=contacts.id "; + } + if ( preg_match("/calls_users\.user_id/",$where)) + { + $query .= "LEFT JOIN calls_users + ON calls.id=calls_users.call_id and calls_users.deleted=0 "; + } + $query .= " + LEFT JOIN users + ON calls.assigned_user_id=users.id "; + if($custom_join){ + $query .= $custom_join['join']; + } + $where_auto = '1=1'; + if($show_deleted == 0){ + $where_auto = " $this->table_name.deleted=0 "; + }else if($show_deleted == 1){ + $where_auto = " $this->table_name.deleted=1 "; + } + + //$where_auto .= " GROUP BY calls.id"; + + if($where != "") + $query .= "where $where AND ".$where_auto; + else + $query .= "where ".$where_auto; + + if($order_by != "") + $query .= " ORDER BY ". $this->process_order_by($order_by, null); + else + $query .= " ORDER BY calls.name"; + return $query; + } + + function create_export_query(&$order_by, &$where, $relate_link_join='') + { + $custom_join = $this->custom_fields->getJOIN(true, true,$where); + if($custom_join) + $custom_join['join'] .= $relate_link_join; + $contact_required = stristr($where, "contacts"); + if($contact_required) + { + $query = "SELECT calls.*, contacts.first_name, contacts.last_name"; + if($custom_join){ + $query .= $custom_join['select']; + } + $query .= " FROM contacts, calls, calls_contacts "; + $where_auto = "calls_contacts.contact_id = contacts.id AND calls_contacts.call_id = calls.id AND calls.deleted=0 AND contacts.deleted=0"; + } + else + { + $query = 'SELECT calls.*'; + if($custom_join){ + $query .= $custom_join['select']; + } + $query .= ' FROM calls '; + $where_auto = "calls.deleted=0"; + } + + + if($custom_join){ + $query .= $custom_join['join']; + } + + if($where != "") + $query .= "where $where AND ".$where_auto; + else + $query .= "where ".$where_auto; + + if($order_by != "") + $query .= " ORDER BY ". $this->process_order_by($order_by, null); + else + $query .= " ORDER BY calls.name"; + + return $query; + } + + + + + + function fill_in_additional_detail_fields() + { + global $locale; + parent::fill_in_additional_detail_fields(); + if (!empty($this->contact_id)) { + $query = "SELECT first_name, last_name FROM contacts "; + $query .= "WHERE id='$this->contact_id' AND deleted=0"; + $result = $this->db->limitQuery($query,0,1,true," Error filling in additional detail fields: "); + + // Get the contact name. + $row = $this->db->fetchByAssoc($result); + $GLOBALS['log']->info("additional call fields $query"); + if($row != null) + { + $this->contact_name = $locale->getLocaleFormattedName($row['first_name'], $row['last_name'], '', ''); + $GLOBALS['log']->debug("Call($this->id): contact_name = $this->contact_name"); + $GLOBALS['log']->debug("Call($this->id): contact_id = $this->contact_id"); + } + } + if (!isset($this->duration_minutes)) { + $this->duration_minutes = $this->minutes_value_default; + } + + global $timedate; + //setting default date and time + if (is_null($this->date_start)) { + $this->date_start = $timedate->now(); + } + + if (is_null($this->duration_hours)) + $this->duration_hours = "0"; + if (is_null($this->duration_minutes)) + $this->duration_minutes = "1"; + + $this->fill_in_additional_parent_fields(); + + global $app_list_strings; + $parent_types = $app_list_strings['record_type_display']; + $disabled_parent_types = ACLController::disabledModuleList($parent_types,false, 'list'); + foreach($disabled_parent_types as $disabled_parent_type){ + if($disabled_parent_type != $this->parent_type){ + unset($parent_types[$disabled_parent_type]); + } + } + + $this->parent_type_options = get_select_options_with_id($parent_types, $this->parent_type); + + if (empty($this->reminder_time)) { + $this->reminder_time = -1; + } + + if ( empty($this->id) ) { + $reminder_t = $GLOBALS['current_user']->getPreference('reminder_time'); + if ( isset($reminder_t) ) + $this->reminder_time = $reminder_t; + } + $this->reminder_checked = $this->reminder_time == -1 ? false : true; + + + if (isset ($_REQUEST['parent_type'])) { + $this->parent_type = $_REQUEST['parent_type']; + } elseif (is_null($this->parent_type)) { + $this->parent_type = $app_list_strings['record_type_default_key']; + } + } + + + function get_list_view_data(){ + $call_fields = $this->get_list_view_array(); + global $app_list_strings, $focus, $action, $currentModule; + if (isset($focus->id)) $id = $focus->id; + else $id = ''; + if (isset($this->parent_type) && $this->parent_type != null) + { + $call_fields['PARENT_MODULE'] = $this->parent_type; + } + if ($this->status == "Planned") { + //cn: added this if() to deal with sequential Closes in Meetings. this is a hack to a hack (formbase.php->handleRedirect) + if(empty($action)) + $action = "index"; + + $setCompleteUrl = ""; + $call_fields['SET_COMPLETE'] = $setCompleteUrl . SugarThemeRegistry::current()->getImage("close_inline","title=".translate('LBL_LIST_CLOSE','Calls')." border='0'").""; + } + global $timedate; + $today = $timedate->nowDb(); + $nextday = $timedate->asDbDate($timedate->getNow()->modify("+1 day")); + $mergeTime = $call_fields['DATE_START']; //$timedate->merge_date_time($call_fields['DATE_START'], $call_fields['TIME_START']); + $date_db = $timedate->to_db($mergeTime); + if( $date_db < $today){ + $call_fields['DATE_START']= "".$call_fields['DATE_START'].""; + }else if($date_db < $nextday){ + $call_fields['DATE_START'] = "".$call_fields['DATE_START'].""; + }else{ + $call_fields['DATE_START'] = "".$call_fields['DATE_START'].""; + } + $this->fill_in_additional_detail_fields(); + + //make sure we grab the localized version of the contact name, if a contact is provided + if (!empty($this->contact_id)) { + global $locale; + $query = "SELECT first_name, last_name, salutation, title FROM contacts "; + $query .= "WHERE id='$this->contact_id' AND deleted=0"; + $result = $this->db->limitQuery($query,0,1,true," Error filling in contact name fields: "); + + // Get the contact name. + $row = $this->db->fetchByAssoc($result); + + if($row != null) + { + $this->contact_name = $locale->getLocaleFormattedName($row['first_name'], $row['last_name'], $row['salutation'], $row['title']); + } + } + + $call_fields['CONTACT_ID'] = $this->contact_id; + $call_fields['CONTACT_NAME'] = $this->contact_name; + + $call_fields['PARENT_NAME'] = $this->parent_name; + + $call_fields['REMINDER_CHECKED'] = $this->reminder_time==-1 ? false : true; + + return $call_fields; + } + + function set_notification_body($xtpl, $call) { + global $sugar_config; + global $app_list_strings; + global $current_user; + global $app_list_strings; + global $timedate; + + // rrs: bug 42684 - passing a contact breaks this call + $notifyUser =($call->current_notify_user->object_name == 'User') ? $call->current_notify_user : $current_user; + + + // Assumes $call dates are in user format + $calldate = $timedate->fromDb($call->date_start); + $xOffset = $timedate->asUser($calldate, $notifyUser).' '.$timedate->userTimezoneSuffix($calldate, $notifyUser); + + if ( strtolower(get_class($call->current_notify_user)) == 'contact' ) { + $xtpl->assign("ACCEPT_URL", $sugar_config['site_url']. + '/index.php?entryPoint=acceptDecline&module=Calls&contact_id='.$call->current_notify_user->id.'&record='.$call->id); + } elseif ( strtolower(get_class($call->current_notify_user)) == 'lead' ) { + $xtpl->assign("ACCEPT_URL", $sugar_config['site_url']. + '/index.php?entryPoint=acceptDecline&module=Calls&lead_id='.$call->current_notify_user->id.'&record='.$call->id); + } else { + $xtpl->assign("ACCEPT_URL", $sugar_config['site_url']. + '/index.php?entryPoint=acceptDecline&module=Calls&user_id='.$call->current_notify_user->id.'&record='.$call->id); + } + + $xtpl->assign("CALL_TO", $call->current_notify_user->new_assigned_user_name); + $xtpl->assign("CALL_SUBJECT", $call->name); + $xtpl->assign("CALL_STARTDATE", $xOffset); + $xtpl->assign("CALL_HOURS", $call->duration_hours); + $xtpl->assign("CALL_MINUTES", $call->duration_minutes); + $xtpl->assign("CALL_STATUS", ((isset($call->status))?$app_list_strings['call_status_dom'][$call->status] : "")); + $xtpl->assign("CALL_DESCRIPTION", $call->description); + + return $xtpl; + } + + + function get_call_users() { + $template = new User(); + // First, get the list of IDs. + $query = "SELECT calls_users.required, calls_users.accept_status, calls_users.user_id from calls_users where calls_users.call_id='$this->id' AND calls_users.deleted=0"; + $GLOBALS['log']->debug("Finding linked records $this->object_name: ".$query); + $result = $this->db->query($query, true); + $list = Array(); + + while($row = $this->db->fetchByAssoc($result)) { + $template = new User(); // PHP 5 will retrieve by reference, always over-writing the "old" one + $record = $template->retrieve($row['user_id']); + $template->required = $row['required']; + $template->accept_status = $row['accept_status']; + + if($record != null) { + // this copies the object into the array + $list[] = $template; + } + } + return $list; + } + + + function get_invite_calls(&$user) + { + $template = $this; + // First, get the list of IDs. + $query = "SELECT calls_users.required, calls_users.accept_status, calls_users.call_id from calls_users where calls_users.user_id='$user->id' AND ( calls_users.accept_status IS NULL OR calls_users.accept_status='none') AND calls_users.deleted=0"; + $GLOBALS['log']->debug("Finding linked records $this->object_name: ".$query); + + + $result = $this->db->query($query, true); + + + $list = Array(); + + + while($row = $this->db->fetchByAssoc($result)) + { + $record = $template->retrieve($row['call_id']); + $template->required = $row['required']; + $template->accept_status = $row['accept_status']; + + + if($record != null) + { + // this copies the object into the array + $list[] = $template; + } + } + return $list; + + } + + + function set_accept_status(&$user,$status) + { + if ( $user->object_name == 'User') + { + $relate_values = array('user_id'=>$user->id,'call_id'=>$this->id); + $data_values = array('accept_status'=>$status); + $this->set_relationship($this->rel_users_table, $relate_values, true, true,$data_values); + global $current_user; + + if ( $this->update_vcal ) + { + vCal::cache_sugar_vcal($user); + } + } + else if ( $user->object_name == 'Contact') + { + $relate_values = array('contact_id'=>$user->id,'call_id'=>$this->id); + $data_values = array('accept_status'=>$status); + $this->set_relationship($this->rel_contacts_table, $relate_values, true, true,$data_values); + } + else if ( $user->object_name == 'Lead') + { + $relate_values = array('lead_id'=>$user->id,'call_id'=>$this->id); + $data_values = array('accept_status'=>$status); + $this->set_relationship($this->rel_leads_table, $relate_values, true, true,$data_values); + } + } + + + + function get_notification_recipients() { + if($this->special_notification) { + return parent::get_notification_recipients(); + } + +// $GLOBALS['log']->debug('Call.php->get_notification_recipients():'.print_r($this,true)); + $list = array(); + if(!is_array($this->contacts_arr)) { + $this->contacts_arr = array(); + } + + if(!is_array($this->users_arr)) { + $this->users_arr = array(); + } + + if(!is_array($this->leads_arr)) { + $this->leads_arr = array(); + } + + foreach($this->users_arr as $user_id) { + $notify_user = new User(); + $notify_user->retrieve($user_id); + $notify_user->new_assigned_user_name = $notify_user->full_name; + $GLOBALS['log']->info("Notifications: recipient is $notify_user->new_assigned_user_name"); + $list[$notify_user->id] = $notify_user; + } + + foreach($this->contacts_arr as $contact_id) { + $notify_user = new Contact(); + $notify_user->retrieve($contact_id); + $notify_user->new_assigned_user_name = $notify_user->full_name; + $GLOBALS['log']->info("Notifications: recipient is $notify_user->new_assigned_user_name"); + $list[$notify_user->id] = $notify_user; + } + + foreach($this->leads_arr as $lead_id) { + $notify_user = new Lead(); + $notify_user->retrieve($lead_id); + $notify_user->new_assigned_user_name = $notify_user->full_name; + $GLOBALS['log']->info("Notifications: recipient is $notify_user->new_assigned_user_name"); + $list[$notify_user->id] = $notify_user; + } +// $GLOBALS['log']->debug('Call.php->get_notification_recipients():'.print_r($list,true)); + return $list; + } + + function bean_implements($interface){ + switch($interface){ + case 'ACL':return true; + } + return false; + } + + function listviewACLHelper(){ + $array_assign = parent::listviewACLHelper(); + $is_owner = false; + if(!empty($this->parent_name)){ + + if(!empty($this->parent_name_owner)){ + global $current_user; + $is_owner = $current_user->id == $this->parent_name_owner; + } + } + if(!ACLController::moduleSupportsACL($this->parent_type) || ACLController::checkAccess($this->parent_type, 'view', $is_owner)){ + $array_assign['PARENT'] = 'a'; + }else{ + $array_assign['PARENT'] = 'span'; + } + $is_owner = false; + if(!empty($this->contact_name)){ + + if(!empty($this->contact_name_owner)){ + global $current_user; + $is_owner = $current_user->id == $this->contact_name_owner; + } + } + if( ACLController::checkAccess('Contacts', 'view', $is_owner)){ + $array_assign['CONTACT'] = 'a'; + }else{ + $array_assign['CONTACT'] = 'span'; + } + + return $array_assign; + } + + function save_relationship_changes($is_update) { + $exclude = array(); + if(empty($this->in_workflow)) { + //if the global soap_server_object variable is not empty (as in from a soap/OPI call), then process the assigned_user_id relationship, otherwise + //add assigned_user_id to exclude list and let the logic from MeetingFormBase determine whether assigned user id gets added to the relationship + if(!empty($GLOBALS['soap_server_object'])){ + $exclude = array('lead_id', 'contact_id', 'user_id'); + }else{ + $exclude = array('lead_id', 'contact_id', 'user_id', 'assigned_user_id'); + } + } + parent::save_relationship_changes($is_update, $exclude); + } + + public function getDefaultStatus() + { + $def = $this->field_defs['status']; + if (isset($def['default'])) { + return $def['default']; + } else { + $app = return_app_list_strings_language($GLOBALS['current_language']); + if (isset($def['options']) && isset($app[$def['options']])) { + $keys = array_keys($app[$def['options']]); + return $keys[0]; + } + } + return ''; + } +} diff --git a/modules/Calls/CallFormBase.php b/modules/Calls/CallFormBase.php new file mode 100644 index 00000000..7cd9ec77 --- /dev/null +++ b/modules/Calls/CallFormBase.php @@ -0,0 +1,614 @@ +get_cal_date_format(); + +$lbl_required_symbol = $app_strings['LBL_REQUIRED_SYMBOL']; +$lbl_date = $mod_strings['LBL_DATE']; +$lbl_time = $mod_strings['LBL_TIME']; +$ntc_date_format = $timedate->get_user_date_format(); +$ntc_time_format = '('.$timedate->get_user_time_format().')'; + + $user_id = $current_user->id; +$default_status = $app_list_strings['call_status_default']; +$default_parent_type= $app_list_strings['record_type_default_key']; +$date = TimeDate::getInstance()->nowDb(); +$default_date_start = $timedate->to_display_date($date,false); +$default_time_start = $timedate->to_display_time($date); +$time_ampm = $timedate->AMPMMenu($prefix,$default_time_start); +$lbl_save_button_title = $app_strings['LBL_SAVE_BUTTON_TITLE']; +$lbl_save_button_key = $app_strings['LBL_SAVE_BUTTON_KEY']; +$lbl_save_button_label = $app_strings['LBL_SAVE_BUTTON_LABEL']; + $form = << + + + + + + + + + + + + + + + + + + + + + + + + + + +EOQ; + + + +$javascript = new javascript(); +$javascript->setFormName($formname); +$javascript->setSugarBean(new Call()); +$javascript->addRequiredFields($prefix); +$form .=$javascript->getScript(); +$form .= "
    ${mod_strings['LNK_NEW_CALL']} +  +  +${mod_strings['LNK_NEW_MEETING']}
    $lbl_subject $lbl_required_symbol
    "; +$mod_strings = $temp_strings; +return $form; + +} +function getFormHeader($prefix, $mod='', $title=''){ + if(!ACLController::checkAccess('Calls', 'edit', true)){ + return ''; + } + if(!empty($mod)){ + global $current_language; + $mod_strings = return_module_language($current_language, $mod); +}else global $mod_strings; + + + + + + +if(!empty($title)){ + $the_form = get_left_form_header($title); +}else{ + $the_form = get_left_form_header($mod_strings['LBL_NEW_FORM_TITLE']); +} +$the_form .= << + + + +EOQ; +return $the_form; +} +function getFormFooter($prefic, $mod=''){ + if(!ACLController::checkAccess('Calls', 'edit', true)){ + return ''; + } +global $app_strings; +global $app_list_strings; +$lbl_save_button_title = $app_strings['LBL_SAVE_BUTTON_TITLE']; +$lbl_save_button_key = $app_strings['LBL_SAVE_BUTTON_KEY']; +$lbl_save_button_label = $app_strings['LBL_SAVE_BUTTON_LABEL']; +$the_form = "

    "; +$the_form .= get_left_form_footer(); +$the_form .= get_validate_record_js(); +return $the_form; +} + +function getForm($prefix, $mod=''){ + if(!ACLController::checkAccess('Calls', 'edit', true)){ + return ''; + } +$the_form = $this->getFormHeader($prefix, $mod); +$the_form .= $this->getFormBody($prefix, $mod, "${prefix}CallSave"); +$the_form .= $this->getFormFooter($prefix, $mod); + +return $the_form; +} + + +function handleSave($prefix,$redirect=true,$useRequired=false) { + + + require_once('include/formbase.php'); + + global $current_user; + global $timedate; + + //BUG 17418 MFH + if (isset($_POST[$prefix.'duration_hours'])){ + $_POST[$prefix.'duration_hours'] = trim($_POST[$prefix.'duration_hours']); + } + + $focus = new Call(); + + if($useRequired && !checkRequired($prefix, array_keys($focus->required_fields))) { + return null; + } + if ( !isset($_POST[$prefix.'reminder_checked']) or ($_POST[$prefix.'reminder_checked'] == 0)) { + $GLOBALS['log']->debug(__FILE__.'('.__LINE__.'): No reminder checked, resetting the reminder_time'); + $_POST[$prefix.'reminder_time'] = -1; + } + + if(!isset($_POST[$prefix.'reminder_time'])) { + $GLOBALS['log']->debug(__FILE__.'('.__LINE__.'): Getting the users default reminder time'); + $_POST[$prefix.'reminder_time'] = $current_user->getPreference('reminder_time'); + } + + $time_format = $timedate->get_user_time_format(); + $time_separator = ":"; + if(preg_match('/\d+([^\d])\d+([^\d]*)/s', $time_format, $match)) { + $time_separator = $match[1]; + } + + if(!empty($_POST[$prefix.'time_hour_start']) && empty($_POST[$prefix.'time_start'])) { + $_POST[$prefix.'time_start'] = $_POST[$prefix.'time_hour_start']. $time_separator .$_POST[$prefix.'time_minute_start']; + } + + if(isset($_POST[$prefix.'meridiem']) && !empty($_POST[$prefix.'meridiem'])) { + $_POST[$prefix.'time_start'] = $timedate->merge_time_meridiem($_POST[$prefix.'time_start'],$timedate->get_time_format(), $_POST[$prefix.'meridiem']); + } + + if(isset($_POST[$prefix.'time_start']) && strlen($_POST[$prefix.'date_start']) == 10) { + $_POST[$prefix.'date_start'] = $_POST[$prefix.'date_start'] . ' ' . $_POST[$prefix.'time_start']; + } + + // retrieve happens here + $focus = populateFromPost($prefix, $focus); + if(!$focus->ACLAccess('Save')) { + ACLController::displayNoAccess(true); + sugar_cleanup(true); + } + + //add assigned user and current user if this is the first time bean is saved + if(empty($focus->id) && !empty($_REQUEST['return_module']) && $_REQUEST['return_module'] =='Calls' && !empty($_REQUEST['return_action']) && $_REQUEST['return_action'] =='DetailView'){ + //if return action is set to detail view and return module to call, then this is from the long form, do not add the assigned user (only the current user) + //The current user is already added to UI and we want to give the current user the option of opting out of meeting. + if($current_user->id != $_POST['assigned_user_id']){ + $_POST['user_invitees'] .= ','.$_POST['assigned_user_id'].', '; + $_POST['user_invitees'] = str_replace(',,', ',', $_POST['user_invitees']); + } + }elseif (empty($focus->id) ){ + //this is not from long form so add assigned and current user automatically as there is no invitee list UI. + //This call could be through an ajax call from subpanels or shortcut bar + $_POST['user_invitees'] .= ','.$_POST['assigned_user_id'].', '; + + //add current user if the assigned to user is different than current user. + if($current_user->id != $_POST['assigned_user_id']){ + $_POST['user_invitees'] .= ','.$current_user->id.', '; + } + + //remove any double comma's introduced during appending + $_POST['user_invitees'] = str_replace(',,', ',', $_POST['user_invitees']); + } + + if(isset($_POST['isSaveFromDetailView']) && $_POST['isSaveFromDetailView'] == 'true'){ + $focus->save(true); + $return_id = $focus->id; + }else{ + + if(empty($_REQUEST['return_module']) && empty($_REQUEST['return_action']) && $focus->status == 'Held'){ + //if we are closing the call, and the request does not have a return module AND return action set, then + //the request is coming from a dashlet or subpanel close icon and there is no need to process user invitees, + //just save the current values. + $focus->save(true); + }else{ + /////////////////////////////////////////////////////////////////////////// + //// REMOVE INVITEE RELATIONSHIPS + if(!empty($_POST['user_invitees'])) { + $userInvitees = explode(',', trim($_POST['user_invitees'], ',')); + } else { + $userInvitees = array(); + } + + // Calculate which users to flag as deleted and which to add + $deleteUsers = array(); + $focus->load_relationship('users'); + // Get all users for the call + $q = 'SELECT mu.user_id, mu.accept_status FROM calls_users mu WHERE mu.call_id = \''.$focus->id.'\''; + $r = $focus->db->query($q); + $acceptStatusUsers = array(); + while($a = $focus->db->fetchByAssoc($r)) { + if(!in_array($a['user_id'], $userInvitees)) { + $deleteUsers[$a['user_id']] = $a['user_id']; + } else { + $acceptStatusUsers[$a['user_id']] = $a['accept_status']; + } + } + + if(count($deleteUsers) > 0) { + $sql = ''; + foreach($deleteUsers as $u) { + $sql .= ",'" . $u . "'"; + } + + $sql = substr($sql, 1); + // We could run a delete SQL statement here, but will just mark as deleted instead + $sql = "UPDATE calls_users set deleted = 1 where user_id in ($sql) AND call_id = '". $focus->id . "'"; + $focus->db->query($sql); + } + + // Get all contacts for the call + if(!empty($_POST['contact_invitees'])) { + $contactInvitees = explode(',', trim($_POST['contact_invitees'], ',')); + } else { + $contactInvitees = array(); + } + + $deleteContacts = array(); + $focus->load_relationship('contacts'); + $q = 'SELECT mu.contact_id, mu.accept_status FROM calls_contacts mu WHERE mu.call_id = \''.$focus->id.'\''; + $r = $focus->db->query($q); + $acceptStatusContacts = array(); + while($a = $focus->db->fetchByAssoc($r)) { + if(!in_array($a['contact_id'], $contactInvitees)) { + $deleteContacts[$a['contact_id']] = $a['contact_id']; + } else { + $acceptStatusContacts[$a['contact_id']] = $a['accept_status']; + } + } + + if(count($deleteContacts) > 0) { + $sql = ''; + foreach($deleteContacts as $u) { + $sql .= ",'" . $u . "'"; + } + $sql = substr($sql, 1); + // We could run a delete SQL statement here, but will just mark as deleted instead + $sql = "UPDATE calls_contacts set deleted = 1 where contact_id in ($sql) AND call_id = '". $focus->id . "'"; + $focus->db->query($sql); + } + if(!empty($_POST['lead_invitees'])) { + $leadInvitees = explode(',', trim($_POST['lead_invitees'], ',')); + } else { + $leadInvitees = array(); + } + + // Calculate which leads to flag as deleted and which to add + $deleteLeads = array(); + $focus->load_relationship('leads'); + // Get all leads for the call + $q = 'SELECT mu.lead_id, mu.accept_status FROM calls_leads mu WHERE mu.call_id = \''.$focus->id.'\''; + $r = $focus->db->query($q); + $acceptStatusLeads = array(); + while($a = $focus->db->fetchByAssoc($r)) { + if(!in_array($a['lead_id'], $leadInvitees)) { + $deleteLeads[$a['lead_id']] = $a['lead_id']; + } else { + $acceptStatusLeads[$a['user_id']] = $a['accept_status']; + } + } + + if(count($deleteLeads) > 0) { + $sql = ''; + foreach($deleteLeads as $u) { + // make sure we don't delete the assigned user + if ( $u != $focus->assigned_user_id ) + $sql .= ",'" . $u . "'"; + } + $sql = substr($sql, 1); + // We could run a delete SQL statement here, but will just mark as deleted instead + $sql = "UPDATE calls_leads set deleted = 1 where lead_id in ($sql) AND call_id = '". $focus->id . "'"; + $focus->db->query($sql); + } + //// END REMOVE + /////////////////////////////////////////////////////////////////////////// + + + /////////////////////////////////////////////////////////////////////////// + //// REBUILD INVITEE RELATIONSHIPS + $focus->users_arr = array(); + $focus->users_arr = $userInvitees; + $focus->contacts_arr = array(); + $focus->contacts_arr = $contactInvitees; + $focus->leads_arr = array(); + $focus->leads_arr = $leadInvitees; + if(!empty($_POST['parent_id']) && $_POST['parent_type'] == 'Contacts') { + $focus->contacts_arr[] = $_POST['parent_id']; + } + if(!empty($_POST['parent_id']) && $_POST['parent_type'] == 'Leads') { + $focus->leads_arr[] = $_POST['parent_id']; + } + // Call the Call module's save function to handle saving other fields besides + // the users and contacts relationships + $focus->save(true); + $return_id = $focus->id; + + // Process users + $existing_users = array(); + if(!empty($_POST['existing_invitees'])) { + $existing_users = explode(",", trim($_POST['existing_invitees'], ',')); + } + + foreach($focus->users_arr as $user_id) { + if(empty($user_id) || isset($existing_users[$user_id]) || isset($deleteUsers[$user_id])) { + continue; + } + + if(!isset($acceptStatusUsers[$user_id])) { + $focus->load_relationship('users'); + $focus->users->add($user_id); + } else { + // update query to preserve accept_status + $qU = 'UPDATE calls_users SET deleted = 0, accept_status = \''.$acceptStatusUsers[$user_id].'\' '; + $qU .= 'WHERE call_id = \''.$focus->id.'\' '; + $qU .= 'AND user_id = \''.$user_id.'\''; + $focus->db->query($qU); + } + } + + // Process contacts + $existing_contacts = array(); + if(!empty($_POST['existing_contact_invitees'])) { + $existing_contacts = explode(",", trim($_POST['existing_contact_invitees'], ',')); + } + + foreach($focus->contacts_arr as $contact_id) { + if(empty($contact_id) || isset($existing_contacts[$contact_id]) || isset($deleteContacts[$contact_id])) { + continue; + } + + if(!isset($acceptStatusContacts[$contact_id])) { + $focus->load_relationship('contacts'); + $focus->contacts->add($contact_id); + } else { + // update query to preserve accept_status + $qU = 'UPDATE calls_contacts SET deleted = 0, accept_status = \''.$acceptStatusContacts[$contact_id].'\' '; + $qU .= 'WHERE call_id = \''.$focus->id.'\' '; + $qU .= 'AND contact_id = \''.$contact_id.'\''; + $focus->db->query($qU); + } + } + // Process leads + $existing_leads = array(); + if(!empty($_POST['existing_lead_invitees'])) { + $existing_leads = explode(",", trim($_POST['existing_lead_invitees'], ',')); + } + + foreach($focus->leads_arr as $lead_id) { + if(empty($lead_id) || isset($existing_leads[$lead_id]) || isset($deleteLeads[$lead_id])) { + continue; + } + + if(!isset($acceptStatusLeads[$lead_id])) { + $focus->load_relationship('leads'); + $focus->leads->add($lead_id); + } else { + // update query to preserve accept_status + $qU = 'UPDATE calls_leads SET deleted = 0, accept_status = \''.$acceptStatusLeads[$lead_id].'\' '; + $qU .= 'WHERE call_id = \''.$focus->id.'\' '; + $qU .= 'AND lead_id = \''.$lead_id.'\''; + $focus->db->query($qU); + } + } + + // CCL - Comment out call to set $current_user as invitee + //set organizer to auto-accept + //$focus->set_accept_status($current_user, 'accept'); + + //// END REBUILD INVITEE RELATIONSHIPS + /////////////////////////////////////////////////////////////////////////// + } + } + if (isset($_REQUEST['return_module']) && $_REQUEST['return_module'] == 'Home'){ + header("Location: index.php?module=Home&action=index"); + } + else if($redirect) { + handleRedirect($return_id, 'Calls'); + } else { + return $focus; + } + +} // end handleSave(); + +function getWideFormBody ($prefix, $mod='', $formname='', $wide =true){ + if(!ACLController::checkAccess('Calls', 'edit', true)){ + return ''; + } +global $mod_strings; +$temp_strings = $mod_strings; +if(!empty($mod)){ + global $current_language; + $mod_strings = return_module_language($current_language, $mod); +} +global $app_strings; +global $app_list_strings; +global $current_user; +global $theme; + +$lbl_subject = $mod_strings['LBL_SUBJECT']; +// Unimplemented until jscalendar language files are fixed +// global $current_language; +// global $default_language; +// global $cal_codes; +// Unimplemented until jscalendar language files are fixed +// $cal_lang = (empty($cal_codes[$current_language])) ? $cal_codes[$default_language] : $cal_codes[$current_language]; +$cal_lang = "en"; + + +$lbl_required_symbol = $app_strings['LBL_REQUIRED_SYMBOL']; + $lbl_date = $mod_strings['LBL_DATE']; +$lbl_time = $mod_strings['LBL_TIME']; +global $timedate; +$ntc_date_format = '('.$timedate->get_user_date_format(). ')'; +$ntc_time_format = '('.$timedate->get_user_time_format(). ')'; +$cal_dateformat = $timedate->get_cal_date_format(); + + $user_id = $current_user->id; +$default_status = $app_list_strings['call_status_default']; +$default_parent_type= $app_list_strings['record_type_default_key']; +$date = TimeDate::getInstance()->nowDb(); +$default_date_start = $timedate->to_display_date($date); +$default_time_start = $timedate->to_display_time($date,true); +$time_ampm = $timedate->AMPMMenu($prefix,$default_time_start); + $form = << + + + + + + + + + + +EOQ; + +if($wide){ +$form .= << ${mod_strings['LNK_NEW_CALL']} + + + + + + + + +EOQ; +}else{ + $form .= << ${mod_strings['LNK_NEW_CALL']} + + + + + +EOQ; +} +$jscalenderImage = SugarThemeRegistry::current()->getImageURL('jscalendar.gif'); +$form .= << + + + + + + + + + + + + + + + + + + + + + +
    ${mod_strings['LBL_DESCRIPTION']}
    ${mod_strings['LNK_NEW_MEETING']}
    ${mod_strings['LNK_NEW_MEETING']}
    $lbl_subject $lbl_required_symbol
    $lbl_date $lbl_required_symbol $ntc_date_format
    {$app_strings['LBL_ENTER_DATE']}
    $lbl_time $lbl_required_symbol $ntc_time_format
    $time_ampm
    + + +EOQ; + + +$javascript = new javascript(); +$javascript->setFormName($formname); +$javascript->setSugarBean(new Call()); +$javascript->addRequiredFields($prefix); +$form .=$javascript->getScript(); +$mod_strings = $temp_strings; +return $form; + +} + + + +} +?> diff --git a/modules/Calls/CallHelper.php b/modules/Calls/CallHelper.php new file mode 100644 index 00000000..1f19820a --- /dev/null +++ b/modules/Calls/CallHelper.php @@ -0,0 +1,103 @@ +duration_minutes = $_REQUEST['duration_minutes']; + } + + if (!isset($focus->duration_minutes)) { + $focus->duration_minutes = $focus->minutes_value_default; + } + + global $timedate; + //setting default date and time + if (is_null($focus->date_start)) + $focus->date_start = $timedate->to_display_date(gmdate($timedate->get_date_time_format())); + if (is_null($focus->duration_hours)) + $focus->duration_hours = "0"; + if (is_null($focus->duration_minutes)) + $focus->duration_minutes = "1"; + + + if($view == 'EditView' || $view == 'MassUpdate' || $view == "QuickCreate" + ) { + $html = ''; + return $html; + } + + return $focus->duration_minutes; +} + +function getReminderTime($focus, $field, $value, $view) { + + global $current_user, $app_list_strings; + $reminder_t = -1; + + if (!empty($_REQUEST['full_form']) && !empty($_REQUEST['reminder_time'])) { + $reminder_t = $_REQUEST['reminder_time']; + } else if (isset($focus->reminder_time)) { + $reminder_t = $focus->reminder_time; + } else if (isset($value)) { + $reminder_t = $value; + } + + if($view == 'EditView' || $view == 'MassUpdate' || $view == "SubpanelCreates" || $view == "QuickCreate" + ) { + global $app_list_strings; + $html = ''; + return $html; + } + + if($reminder_t == -1) { + return ""; + } + + return translate('reminder_time_options', '', $reminder_t); +} + +?> diff --git a/modules/Calls/CallsQuickCreate.php b/modules/Calls/CallsQuickCreate.php new file mode 100644 index 00000000..3d54bbbf --- /dev/null +++ b/modules/Calls/CallsQuickCreate.php @@ -0,0 +1,144 @@ +ss->assign("TIME_FORMAT", '('. $timedate->get_user_time_format().')'); + $this->ss->assign("USER_DATEFORMAT", '('. $timedate->get_user_date_format().')'); + $this->ss->assign("CALENDAR_DATEFORMAT", $timedate->get_cal_date_format()); + + + if($this->viaAJAX) { // override for ajax call + $this->ss->assign('saveOnclick', "onclick='if(check_form(\"callsQuickCreate\")) return SUGAR.subpanelUtils.inlineSave(this.form.id, \"activities\"); else return false;'"); + $this->ss->assign('cancelOnclick', "onclick='return SUGAR.subpanelUtils.cancelCreate(\"subpanel_activities\")';"); + } + + $this->ss->assign('viaAJAX', $this->viaAJAX); + + $this->javascript = new javascript(); + $this->javascript->setFormName('callsQuickCreate'); + + $focus = new Call(); + $this->javascript->setSugarBean($focus); + $this->javascript->addAllFields(''); + + if (is_null($focus->date_start)) + $focus->date_start = $timedate->nowDate(); + if (is_null($focus->time_start)) + $focus->time_start = $timedate->asUserTime($timedate->getNow(), true); + if (!isset ($focus->duration_hours)) + $focus->duration_hours = "1"; + + $this->ss->assign("DATE_START", $focus->date_start); + $this->ss->assign("TIME_START", substr($focus->time_start,0,5)); + $time_start_hour = intval(substr($focus->time_start, 0, 2)); + $time_start_minutes = substr($focus->time_start, 3, 5); + + if ($time_start_minutes > 0 && $time_start_minutes < 15) { + $time_start_minutes = "15"; + } else + if ($time_start_minutes > 15 && $time_start_minutes < 30) { + $time_start_minutes = "30"; + } else + if ($time_start_minutes > 30 && $time_start_minutes < 45) { + $time_start_minutes = "45"; + } else + if ($time_start_minutes > 45) { + $time_start_hour += 1; + $time_start_minutes = "00"; + } + + + // We default the to assume that the time preference is set to 11:00 (i.e. without meridiem) + $hours_arr = array (); + $num_of_hours = 24; + $start_at = 0; + + $time_pref = $timedate->get_time_format(); + if(strpos($time_pref, 'a') || strpos($time_pref, 'A')) { + $num_of_hours = 13; + $start_at = 1; + + // It's important to do this block first before we recalculate $time_start_hour + $options = strpos($time_pref, 'a') ? $app_list_strings['dom_meridiem_lowercase'] : $app_list_strings['dom_meridiem_uppercase']; + if(strpos($time_pref, 'a')) { + $this->ss->assign("TIME_MERIDIEM", get_select_options_with_id($options, strpos($focus->time_start,'a') ? 'am' : 'pm')); + } else { + $this->ss->assign("TIME_MERIDIEM", get_select_options_with_id($options, strpos($focus->time_start,'A') ? 'AM' : 'PM')); + } + + // the $num_of_hours array is keyed by values 01, 02, ... 12 for meridiem times + $time_start_hour = $time_start_hour < 10 ? '0'.$time_start_hour : $time_start_hour; + } + + for ($i = $start_at; $i < $num_of_hours; $i ++) { + $i = $i.""; + if (strlen($i) == 1) { + $i = "0".$i; + } + $hours_arr[$i] = $i; + } + + $this->ss->assign("TIME_START_HOUR_OPTIONS", get_select_options_with_id($hours_arr, $time_start_hour)); + $this->ss->assign("TIME_START_MINUTE_OPTIONS", get_select_options_with_id($focus->minutes_values, $time_start_minutes)); + + $this->ss->assign("DURATION_HOURS", $focus->duration_hours); + $this->ss->assign("DURATION_MINUTES_OPTIONS", get_select_options_with_id($focus->minutes_values, $focus->duration_minutes)); + + $focus->direction = (isset ($app_list_strings['call_direction_dom']['Outbound']) ? 'Outbound' : $focus->direction); + $focus->status = (isset ($app_list_strings['call_status_dom']['Planned']) ? 'Outbound' : $focus->status); + + $this->ss->assign("DIRECTION_OPTIONS", get_select_options_with_id($app_list_strings['call_direction_dom'], $focus->direction)); + $this->ss->assign("STATUS_OPTIONS", get_select_options_with_id($app_list_strings['call_status_dom'], $focus->status)); + + $this->ss->assign('additionalScripts', $this->javascript->getScript(false)); + } +} +?> \ No newline at end of file diff --git a/modules/Calls/Dashlets/MyCallsDashlet/MyCallsDashlet.data.php b/modules/Calls/Dashlets/MyCallsDashlet/MyCallsDashlet.data.php new file mode 100644 index 00000000..49751bf9 --- /dev/null +++ b/modules/Calls/Dashlets/MyCallsDashlet/MyCallsDashlet.data.php @@ -0,0 +1,95 @@ + array('default' => ''), + 'status' => array('default' => array('Planned')), + 'date_entered' => array('default' => ''), + 'date_start' => array('default' => ''), + + 'assigned_user_id' => array('type' => 'assigned_user_name', + 'label' => 'LBL_ASSIGNED_TO', + 'default' => $current_user->name)); +$dashletData['MyCallsDashlet']['columns'] = array('set_complete' => array('width' => '5', + 'label' => 'LBL_LIST_CLOSE', + 'default' => true, + 'sortable' => false, + 'related_fields' => array('status')), + 'name' => array('width' => '40', + 'label' => 'LBL_SUBJECT', + 'link' => true, + 'default' => true), + 'parent_name' => array('width' => '29', + 'label' => 'LBL_LIST_RELATED_TO', + 'sortable' => false, + 'dynamic_module' => 'PARENT_TYPE', + 'link' => true, + 'id' => 'PARENT_ID', + 'ACLTag' => 'PARENT', + 'related_fields' => array('parent_id', 'parent_type'), + 'default' => true, + ), + + 'duration' => array('width' => '10', + 'label' => 'LBL_DURATION', + 'sortable' => false, + 'related_fields' => array('duration_hours', 'duration_minutes')), + 'direction' => array('width' => '10', + 'label' => 'LBL_DIRECTION'), + 'date_start' => array('width' => '15', + 'label' => 'LBL_DATE', + 'default' => true, + 'related_fields' => array('time_start')), + 'status' => array('width' => '8', + 'label' => 'LBL_STATUS', + 'default' => true), + 'date_entered' => array('width' => '15', + 'label' => 'LBL_DATE_ENTERED'), + 'date_modified' => array('width' => '15', + 'label' => 'LBL_DATE_MODIFIED'), + 'created_by' => array('width' => '8', + 'label' => 'LBL_CREATED'), + 'assigned_user_name' => array('width' => '8', + 'label' => 'LBL_LIST_ASSIGNED_USER'), + ); +?> diff --git a/modules/Calls/Dashlets/MyCallsDashlet/MyCallsDashlet.meta.php b/modules/Calls/Dashlets/MyCallsDashlet/MyCallsDashlet.meta.php new file mode 100644 index 00000000..12e6a70b --- /dev/null +++ b/modules/Calls/Dashlets/MyCallsDashlet/MyCallsDashlet.meta.php @@ -0,0 +1,47 @@ + 'Calls', + 'title' => translate('LBL_LIST_MY_CALLS', 'Calls'), + 'description' => 'A customizable view into Calls', + 'category' => 'Module Views'); +?> diff --git a/modules/Calls/Dashlets/MyCallsDashlet/MyCallsDashlet.php b/modules/Calls/Dashlets/MyCallsDashlet/MyCallsDashlet.php new file mode 100644 index 00000000..29056a08 --- /dev/null +++ b/modules/Calls/Dashlets/MyCallsDashlet/MyCallsDashlet.php @@ -0,0 +1,163 @@ +title = translate('LBL_LIST_MY_CALLS', 'Calls'); + $this->searchFields = $dashletData['MyCallsDashlet']['searchFields']; + if(empty($def['filters'])){ + if(isset($this->searchFields['status'])){ + if(!empty($this->searchFields['status']['default'])){ + $this->filters['status'] = $this->searchFields['status']['default']; + } + } + } + $this->columns = $dashletData['MyCallsDashlet']['columns']; + $this->columns['set_accept_links']= array('width' => '10', + 'label' => translate('LBL_ACCEPT_THIS', 'Meetings'), + 'sortable' => false, + 'related_fields' => array('status'), + 'default' => 'true'); + $this->seedBean = new Call(); + } + + + function process($lvsParams = array()) { + global $current_language, $app_list_strings, $current_user; + $mod_strings = return_module_language($current_language, 'Calls'); + + // handle myitems only differently -- set the custom query to show assigned meetings and invitee meetings + if($this->myItemsOnly) { + //join with meeting_users table to process related users + $this->seedBean->listview_inner_join = array('LEFT JOIN calls_users c_u on c_u.call_id = calls.id'); + + //set the custom query to include assigned meetings + $lvsParams['custom_where'] = ' AND (calls.assigned_user_id = \'' . $current_user->id . '\' OR c_u.user_id = \'' . $current_user->id . '\' AND c_u.deleted = 0) '; + } + + $this->myItemsOnly = false; + //query needs to be distinct to avoid multiple records being returned for the same meeting (one for each invited user), + //so we need to make sure date entered is also set so the sort can work with the group by + $lvsParams['custom_select']=', calls.date_entered '; + $lvsParams['distinct']=true; + + parent::process($lvsParams); + + $keys = array(); + foreach($this->lvs->data['data'] as $num => $row) { + $keys[] = $row['ID']; + } + + + if(!empty($keys)){ + $query = "SELECT call_id, accept_status FROM calls_users WHERE deleted = 0 and user_id = '" . $current_user->id . "' AND call_id IN ('" . implode("','", $keys ). "')"; + $result = $GLOBALS['db']->query($query); + + while($row = $GLOBALS['db']->fetchByAssoc($result)) { + $rowNums = $this->lvs->data['pageData']['idIndex'][$row['call_id']]; // figure out which rows have this guid + foreach($rowNums as $rowNum) { + $this->lvs->data['data'][$rowNum]['ACCEPT_STATUS'] = $row['accept_status']; + } + } + } + + foreach($this->lvs->data['data'] as $rowNum => $row) { + if(empty($this->lvs->data['data'][$rowNum]['DURATION_HOURS'])) $this->lvs->data['data'][$rowNum]['DURATION'] = '0' . $mod_strings['LBL_HOURS_ABBREV']; + else $this->lvs->data['data'][$rowNum]['DURATION'] = $this->lvs->data['data'][$rowNum]['DURATION_HOURS'] . $mod_strings['LBL_HOURS_ABBREV']; + + if(empty($this->lvs->data['data'][$rowNum]['DURATION_MINUTES']) || empty($this->seedBean->minutes_values[$this->lvs->data['data'][$rowNum]['DURATION_MINUTES']])) { + $this->lvs->data['data'][$rowNum]['DURATION'] .= '00'; + } + else { + $this->lvs->data['data'][$rowNum]['DURATION'] .= $this->seedBean->minutes_values[$this->lvs->data['data'][$rowNum]['DURATION_MINUTES']]; + } + if ($this->lvs->data['data'][$rowNum]['STATUS'] == $app_list_strings['meeting_status_dom']['Planned']) + { + if ($this->lvs->data['data'][$rowNum]['ACCEPT_STATUS'] == ''){ + //if no status has been set, then do not show accept options + $this->lvs->data['data'][$rowNum]['SET_ACCEPT_LINKS'] = "
    id."\" >
    "; + }elseif($this->lvs->data['data'][$rowNum]['ACCEPT_STATUS'] == 'none') + { + $this->lvs->data['data'][$rowNum]['SET_ACCEPT_LINKS'] = ""; + } + else + { + $this->lvs->data['data'][$rowNum]['SET_ACCEPT_LINKS'] = $app_list_strings['dom_meeting_accept_status'][$this->lvs->data['data'][$rowNum]['ACCEPT_STATUS']]; + + } + } + + $this->lvs->data['data'][$rowNum]['DURATION'] .= $mod_strings['LBL_MINSS_ABBREV']; + } + $this->displayColumns[]= "set_accept_links"; + } + + function displayOptions() { + $this->processDisplayOptions(); + $this->configureSS->assign('strings', array('general' => $GLOBALS['mod_strings']['LBL_DASHLET_CONFIGURE_GENERAL'], + 'filters' => $GLOBALS['mod_strings']['LBL_DASHLET_CONFIGURE_FILTERS'], + 'myItems' => translate('LBL_DASHLET_CONFIGURE_MY_ITEMS_ONLY', 'Calls'), + 'displayRows' => $GLOBALS['mod_strings']['LBL_DASHLET_CONFIGURE_DISPLAY_ROWS'], + 'title' => $GLOBALS['mod_strings']['LBL_DASHLET_CONFIGURE_TITLE'], + 'save' => $GLOBALS['app_strings']['LBL_SAVE_BUTTON_LABEL'], + 'autoRefresh' => $GLOBALS['app_strings']['LBL_DASHLET_CONFIGURE_AUTOREFRESH'], + )); + return $this->configureSS->fetch($this->configureTpl); + } +} + +?> diff --git a/modules/Calls/Menu.php b/modules/Calls/Menu.php new file mode 100644 index 00000000..da631b02 --- /dev/null +++ b/modules/Calls/Menu.php @@ -0,0 +1,51 @@ + diff --git a/modules/Calls/Save.php b/modules/Calls/Save.php new file mode 100644 index 00000000..78d13fe3 --- /dev/null +++ b/modules/Calls/Save.php @@ -0,0 +1,49 @@ +handleSave('', true, false); +?> \ No newline at end of file diff --git a/modules/Calls/SubPanelViewInvitees.html b/modules/Calls/SubPanelViewInvitees.html new file mode 100644 index 00000000..2167374b --- /dev/null +++ b/modules/Calls/SubPanelViewInvitees.html @@ -0,0 +1,89 @@ + + +

    {APP.LBL_USER_LIST}

    + + + + + + + + + + + + + + + + + + + + + + +
    {APP.LBL_LIST_NAME}{APP.LBL_LIST_USER_NAME}{APP.LBL_LIST_EMAIL}{APP.LBL_LIST_PHONE}
    {USER.FIRST_NAME} {USER.LAST_NAME}{USER.USER_NAME}{USER.EMAIL1}{USER.PHONE_WORK}

    + + +

    {APP.LBL_CONTACT_LIST}

    + + + + + + + + + + + + + + + + + + + +
    {APP.LBL_LIST_CONTACT_NAME}{APP.LBL_LIST_ACCOUNT_NAME}{APP.LBL_LIST_EMAIL}{APP.LBL_LIST_PHONE}
    {CONTACT.FIRST_NAME} {CONTACT.LAST_NAME}{CONTACT.ACCOUNT_NAME}{CONTACT.EMAIL1}{CONTACT.PHONE_WORK}

    + diff --git a/modules/Calls/SubPanelViewInvitees.php b/modules/Calls/SubPanelViewInvitees.php new file mode 100644 index 00000000..3b5bc4ff --- /dev/null +++ b/modules/Calls/SubPanelViewInvitees.php @@ -0,0 +1,149 @@ +
    \n"; +$button .= "\n"; +if ($currentModule == 'Accounts') $button .= "\n\n"; +$button .= "\n"; +$button .= "\n"; +$button .= "\n"; +$button .= "\n"; +$button .= "
     
    \n"; + +// Stick the form header out there. +echo get_form_header($mod_strings['LBL_INVITEES'], $button, false); +$xtpl=new XTemplate ('modules/Calls/SubPanelViewInvitees.html'); +$xtpl->assign("MOD", $mod_strings); +$xtpl->assign("APP", $app_strings); + +$xtpl->assign("RETURN_URL", "&return_module=$currentModule&return_action=DetailView&return_id=$focus->id"); +$xtpl->assign("CALL_ID", $focus->id); + +$oddRow = true; +foreach($focus_users_list as $user) +{ + $user_fields = array( + 'USER_NAME' => $user->user_name, + 'FULL_NAME' => $locale->getLocaleFormattedName($user->first_name, $user->last_name), + 'ID' => $user->id, + 'EMAIL' => $user->email1, + 'PHONE_WORK' => $user->phone_work + ); + + $xtpl->assign("USER", $user_fields); + + if($oddRow) + { + //todo move to themes + $xtpl->assign("ROW_COLOR", 'oddListRow'); + } + else + { + //todo move to themes + $xtpl->assign("ROW_COLOR", 'evenListRow'); + } + $oddRow = !$oddRow; + + $xtpl->parse("users.row"); +// Put the rows in. +} + +$xtpl->parse("users"); +$xtpl->out("users"); + +$oddRow = true; +foreach($focus_contacts_list as $contact) +{ + $contact_fields = array( + 'FIRST_NAME' => $contact->first_name, + 'LAST_NAME' => $contact->last_name, + 'ACCOUNT_NAME' => $contact->account_name, + 'ID' => $contact->id, + 'EMAIL' => $contact->email1, + 'PHONE_WORK' => $contact->phone_work + ); + + $xtpl->assign("CONTACT", $contact_fields); + + if($oddRow) + { + //todo move to themes + $xtpl->assign("ROW_COLOR", 'oddListRow'); + } + else + { + //todo move to themes + $xtpl->assign("ROW_COLOR", 'evenListRow'); + } + $oddRow = !$oddRow; + + $xtpl->parse("contacts.row"); +// Put the rows in. +} + +$xtpl->parse("contacts"); +$xtpl->out("contacts"); +?> diff --git a/modules/Calls/field_arrays.php b/modules/Calls/field_arrays.php new file mode 100644 index 00000000..192f8310 --- /dev/null +++ b/modules/Calls/field_arrays.php @@ -0,0 +1,69 @@ + Array("id" + , "date_entered" + , "date_modified" + , "assigned_user_id" + , "modified_user_id" + , "created_by" + , "description" + , "status" + , "direction" + , "name" + , "date_start" + , "time_start" + , "duration_hours" + , "duration_minutes" + , "date_end" + , "parent_type" + , "parent_id" + ,'reminder_time' + ,'outlook_id' + ), + 'list_fields' => Array('id', 'duration_hours', 'direction', 'status', 'name', 'parent_type', 'parent_name', 'parent_id', 'date_start', 'time_start', 'assigned_user_name', 'assigned_user_id', 'contact_name', 'contact_id','first_name','last_name','required','outlook_id','accept_status' + ), + 'required_fields' => array("name"=>1, "date_start"=>2, "time_start"=>3,), +); +?> \ No newline at end of file diff --git a/modules/Calls/language/en_us.lang.php b/modules/Calls/language/en_us.lang.php new file mode 100644 index 00000000..341426ea --- /dev/null +++ b/modules/Calls/language/en_us.lang.php @@ -0,0 +1,130 @@ + ' ', + + 'LBL_MODULE_NAME' => 'Calls', + 'LBL_MODULE_TITLE' => 'Calls: Home', + 'LBL_SEARCH_FORM_TITLE' => 'Call Search', + 'LBL_LIST_FORM_TITLE' => 'Call List', + 'LBL_NEW_FORM_TITLE' => 'Create Appointment', + 'LBL_LIST_CLOSE' => 'Close', + 'LBL_LIST_SUBJECT' => 'Subject', + 'LBL_LIST_CONTACT' => 'Contact', + 'LBL_LIST_RELATED_TO' => 'Related to', + 'LBL_LIST_RELATED_TO_ID' => 'Related to ID', + 'LBL_LIST_DATE' => 'Start Date', + 'LBL_LIST_TIME' => 'Start Time', + 'LBL_LIST_DURATION' => 'Duration', + 'LBL_LIST_DIRECTION' => 'Direction', + 'LBL_SUBJECT' => 'Subject:', + 'LBL_REMINDER' => 'Reminder:', + 'LBL_CONTACT_NAME' => 'Contact:', + 'LBL_DESCRIPTION_INFORMATION' => 'Description Information', + 'LBL_DESCRIPTION' => 'Description:', + 'LBL_STATUS' => 'Status:', + 'LBL_DIRECTION' => 'Direction:', + 'LBL_DATE' => 'Start Date:', + 'LBL_DURATION' => 'Duration:', + 'LBL_DURATION_HOURS' => 'Duration Hours:', + 'LBL_DURATION_MINUTES' => 'Duration Minutes:', + 'LBL_HOURS_MINUTES' => '(hours/minutes)', + 'LBL_CALL' => 'Call:', + 'LBL_DATE_TIME' => 'Start Date & Time:', + 'LBL_TIME' => 'Start Time:', + 'LBL_HOURS_ABBREV' => 'h', + 'LBL_MINSS_ABBREV' => 'm', + 'LBL_COLON' => ':', + 'LNK_NEW_CALL' => 'Log Call', + 'LNK_NEW_MEETING' => 'Schedule Meeting', + 'LNK_CALL_LIST' => 'View Calls', + 'LNK_IMPORT_CALLS' => 'Import Calls', + 'ERR_DELETE_RECORD' => 'A record number must be specified to delete the account.', + 'NTC_REMOVE_INVITEE' => 'Are you sure you want to remove this invitee from the call?', + 'LBL_INVITEE' => 'Invitees', + 'LBL_RELATED_TO' => 'Related To:', + 'LNK_NEW_APPOINTMENT' => 'Create Appointment', + 'LBL_SCHEDULING_FORM_TITLE' => 'Scheduling', + 'LBL_ADD_INVITEE' => 'Add Invitees', + 'LBL_NAME' => 'Name', + 'LBL_FIRST_NAME' => 'First Name', + 'LBL_LAST_NAME' => 'Last Name', + 'LBL_EMAIL' => 'Email', + 'LBL_PHONE' => 'Phone', + 'LBL_REMINDER' => 'Reminder:', + 'LBL_SEND_BUTTON_TITLE'=>'Send Invites [Alt+I]', + 'LBL_SEND_BUTTON_KEY'=>'I', + 'LBL_SEND_BUTTON_LABEL'=>'Send Invites', + 'LBL_DATE_END'=>'Date End', + 'LBL_TIME_END'=>'Time End', + 'LBL_REMINDER_TIME'=>'Reminder Time', + 'LBL_SEARCH_BUTTON'=> 'Search', + 'LBL_ACTIVITIES_REPORTS' => 'Activities Report', + 'LBL_ADD_BUTTON'=> 'Add', + 'LBL_DEFAULT_SUBPANEL_TITLE' => 'Calls', + 'LBL_LOG_CALL'=> 'Log Call', + 'LNK_SELECT_ACCOUNT'=> 'Select Account', + 'LNK_NEW_ACCOUNT'=> 'New Account', + 'LNK_NEW_OPPORTUNITY'=> 'New Opportunity', + 'LBL_DEL' => 'Del', + 'LBL_LEADS_SUBPANEL_TITLE' => 'Leads', + 'LBL_CONTACTS_SUBPANEL_TITLE' => 'Contacts', + 'LBL_USERS_SUBPANEL_TITLE' => 'Users', + 'LBL_OUTLOOK_ID' => 'Outlook ID', + 'LBL_MEMBER_OF' => 'Member Of', + 'LBL_HISTORY_SUBPANEL_TITLE' => 'Notes', + 'LBL_LIST_ASSIGNED_TO_NAME' => 'Assigned to', + 'LBL_LIST_MY_CALLS' => 'My Calls', + 'LBL_SELECT_FROM_DROPDOWN' => 'Please make a selection from the Related To dropdown list first.', + 'LBL_ASSIGNED_TO_NAME' => 'Assigned to', + 'LBL_ASSIGNED_TO_ID' => 'Assigned User', + 'NOTICE_DURATION_TIME' => 'Duration time must be greater than 0', + 'LBL_CALL_INFORMATION' => 'Call Overview', + 'LBL_REMOVE' => 'rem', +); + + +?> \ No newline at end of file diff --git a/modules/Calls/metadata/SearchFields.php b/modules/Calls/metadata/SearchFields.php new file mode 100644 index 00000000..4ce7dbdd --- /dev/null +++ b/modules/Calls/metadata/SearchFields.php @@ -0,0 +1,71 @@ + array( 'query_type'=>'default'), + 'contact_name' => array( 'query_type'=>'default','db_field'=>array('contacts.first_name','contacts.last_name')), + 'date_start' => array( 'query_type'=>'default'), + 'location' => array( 'query_type'=>'default'), + 'current_user_only'=> array('query_type'=>'default','db_field'=>array('assigned_user_id'),'my_items'=>true, 'vname' => 'LBL_CURRENT_USER_FILTER', 'type' => 'bool'), + 'assigned_user_id'=> array('query_type'=>'default'), + 'status'=> array('query_type'=>'default', 'options' => 'call_status_dom', 'template_var' => 'STATUS_FILTER'), + + 'open_only' => array( + 'query_type'=>'default', + 'db_field'=>array('status'), + 'operator'=>'not in', + 'closed_values' => array('Held', 'Not Held'), + 'type'=>'bool', + ), + //Range Search Support + 'range_date_entered' => array ('query_type' => 'default', 'enable_range_search' => true, 'is_date_field' => true), + 'start_range_date_entered' => array ('query_type' => 'default', 'enable_range_search' => true, 'is_date_field' => true), + 'end_range_date_entered' => array ('query_type' => 'default', 'enable_range_search' => true, 'is_date_field' => true), + 'range_date_modified' => array ('query_type' => 'default', 'enable_range_search' => true, 'is_date_field' => true), + 'start_range_date_modified' => array ('query_type' => 'default', 'enable_range_search' => true, 'is_date_field' => true), + 'end_range_date_modified' => array ('query_type' => 'default', 'enable_range_search' => true, 'is_date_field' => true), + + 'range_date_start' => array ('query_type' => 'default', 'enable_range_search' => true, 'is_date_field' => true), + 'start_range_date_start' => array ('query_type' => 'default', 'enable_range_search' => true, 'is_date_field' => true), + 'end_range_date_start' => array ('query_type' => 'default', 'enable_range_search' => true, 'is_date_field' => true), + 'range_date_end' => array ('query_type' => 'default', 'enable_range_search' => true, 'is_date_field' => true), + 'start_range_date_end' => array ('query_type' => 'default', 'enable_range_search' => true, 'is_date_field' => true), + 'end_range_date_end' => array ('query_type' => 'default', 'enable_range_search' => true, 'is_date_field' => true), + //Range Search Support + ); +?> diff --git a/modules/Calls/metadata/additionalDetails.php b/modules/Calls/metadata/additionalDetails.php new file mode 100644 index 00000000..508cda1d --- /dev/null +++ b/modules/Calls/metadata/additionalDetails.php @@ -0,0 +1,80 @@ +'. $mod_strings['LBL_DATE_TIME'] . ' ' . $fields['DATE_START'] . '
    '; + if(isset($fields['DURATION_HOURS']) || isset($fields['DURATION_MINUTES'])) { + $overlib_string .= ''. $mod_strings['LBL_DURATION'] . ' '; + if(isset($fields['DURATION_HOURS'])) { + $overlib_string .= $fields['DURATION_HOURS'] . $mod_strings['LBL_HOURS_ABBREV'] . ' '; + } + if(isset($fields['DURATION_MINUTES'])) { + $overlib_string .= $fields['DURATION_MINUTES'] . $mod_strings['LBL_MINSS_ABBREV']; + } + $overlib_string .= '
    '; + } + if(!empty($fields['DESCRIPTION'])) { + $overlib_string .= ''. $mod_strings['LBL_DESCRIPTION'] . ' ' . substr($fields['DESCRIPTION'], 0, 300); + if(strlen($fields['DESCRIPTION']) > 300) $overlib_string .= '...'; + $overlib_string .= '
    '; + } + + $editLink = "index.php?action=EditView&module=Calls&record={$fields['ID']}"; + $viewLink = "index.php?action=DetailView&module=Calls&record={$fields['ID']}"; + + $return_module = empty($_REQUEST['module']) ? 'Calls' : $_REQUEST['module']; + $return_action = empty($_REQUEST['action']) ? 'ListView' : $_REQUEST['action']; + + $editLink .= "&return_module=$return_module&return_action=$return_action"; + $viewLink .= "&return_module=$return_module&return_action=$return_action"; + + return array('fieldToAddTo' => 'NAME', + 'string' => $overlib_string, + 'editLink' => $editLink, + 'viewLink' => $viewLink); +} diff --git a/modules/Calls/metadata/detailviewdefs.php b/modules/Calls/metadata/detailviewdefs.php new file mode 100644 index 00000000..a34dae3a --- /dev/null +++ b/modules/Calls/metadata/detailviewdefs.php @@ -0,0 +1,152 @@ + + array ( + 'templateMeta' => + array ( + 'form' => + array ( + 'buttons' => + array ( + 0 => 'EDIT', + 1 => 'DUPLICATE', + 2 => 'DELETE', + 3 => + array ( + 'customCode' => '{if $fields.status.value != "Held"} {/if}', + ), + 4 => + array ( + 'customCode' => '{if $fields.status.value != "Held"} {/if}', + ), + ), + ), + 'maxColumns' => '2', + 'widths' => + array ( + 0 => + array ( + 'label' => '10', + 'field' => '30', + ), + 1 => + array ( + 'label' => '10', + 'field' => '30', + ), + ), + 'useTabs' => false, + ), + 'panels' => + array ( + 'lbl_call_information' => + array ( + array ( + array ( + 'name' => 'name', + 'label' => 'LBL_SUBJECT', + ), + 1 => + array ( + 'name' => 'direction', + 'customCode' => '{$fields.direction.options[$fields.direction.value]} {$fields.status.options[$fields.status.value]}', + 'label' => 'LBL_STATUS', + ), + ), + array ( + array ( + 'name' => 'date_start', + 'customCode' => '{$fields.date_start.value} {$fields.time_start.value} ', + 'label' => 'LBL_DATE_TIME', + ), + array ( + 'name' => 'parent_name', + 'customLabel' => '{sugar_translate label=\'LBL_MODULE_NAME\' module=$fields.parent_type.value}', + ), + ), + array ( + array ( + 'name' => 'duration_hours', + 'customCode' => '{$fields.duration_hours.value}{$MOD.LBL_HOURS_ABBREV} {$fields.duration_minutes.value}{$MOD.LBL_MINSS_ABBREV} ', + 'label' => 'LBL_DURATION', + ), + array ( + 'name' => 'reminder_checked', + 'fields' => + array ( + 'reminder_checked', + 'reminder_time', + ), + ), + ), + array ( + array ( + 'name' => 'description', + 'comment' => 'Full text of the note', + 'label' => 'LBL_DESCRIPTION', + ), + ), + ), + 'LBL_PANEL_ASSIGNMENT' => + array ( + array ( + array ( + 'name' => 'assigned_user_name', + 'customCode' => '{$fields.assigned_user_name.value}', + 'label' => 'LBL_ASSIGNED_TO', + ), + ), + array ( + array ( + 'name' => 'date_modified', + 'customCode' => '{$fields.date_modified.value} {$APP.LBL_BY} {$fields.modified_by_name.value} ', + 'label' => 'LBL_DATE_MODIFIED', + ), + array ( + 'name' => 'date_entered', + 'customCode' => '{$fields.date_entered.value} {$APP.LBL_BY} {$fields.created_by_name.value} ', + 'label' => 'LBL_DATE_ENTERED', + ), + ), + ), + ), + ), +); +?> diff --git a/modules/Calls/metadata/editviewdefs.php b/modules/Calls/metadata/editviewdefs.php new file mode 100644 index 00000000..39b2b4ba --- /dev/null +++ b/modules/Calls/metadata/editviewdefs.php @@ -0,0 +1,162 @@ + + array ( + 'templateMeta' => + array ( + 'maxColumns' => '2', + 'form' => + array ( + 'hidden' => + array ( + 0 => '', + 1 => '', + 2 => '', + 3 => '', + 4 => '', + ), + 'buttons' => + array ( + 0 => + array ( + 'customCode' => '', + ), + 1 => 'CANCEL', + 2 => + array ( + 'customCode' => '', + ), + 3 => + array ( + 'customCode' => '{if $fields.status.value != "Held"}{/if}', + ), + ), + 'footerTpl' => 'modules/Calls/tpls/footer.tpl', + ), + 'widths' => + array ( + 0 => + array ( + 'label' => '10', + 'field' => '30', + ), + 1 => + array ( + 'label' => '10', + 'field' => '30', + ), + ), + 'javascript' => ' + + + + + + +', + 'useTabs' => false, + ), + 'panels' => + array ( + 'lbl_call_information' => + array ( + array ( + 'name' => 'name', + array ( + 'name' => 'status', + 'fields' => + array ( + array ( + 'name' => 'direction', + ), + array ( + 'name' => 'status', + ), + ), + ), + ), + array ( + array ( + 'name' => 'date_start', + 'displayParams' => + array ( + 'updateCallback' => 'SugarWidgetScheduler.update_time();', + ), + 'label' => 'LBL_DATE_TIME', + ), + array ( + 'name' => 'parent_name', + 'label' => 'LBL_LIST_RELATED_TO', + ), + ), + array ( + array ( + 'name' => 'duration_hours', + 'label' => 'LBL_DURATION', + 'customCode' => '{literal}{/literal}{$fields.duration_minutes.value} {$MOD.LBL_HOURS_MINUTES}', + + ), + array ( + 'name' => 'reminder_time', + 'customCode' => '{if $fields.reminder_checked.value == "1"}{assign var="REMINDER_TIME_DISPLAY" value="inline"}{assign var="REMINDER_CHECKED" value="checked"}{else}{assign var="REMINDER_TIME_DISPLAY" value="none"}{assign var="REMINDER_CHECKED" value=""}{/if}
    {$fields.reminder_time.value}
    ', + 'label' => 'LBL_REMINDER', + ), + ), + array ( + array ( + 'name' => 'description', + 'comment' => 'Full text of the note', + 'label' => 'LBL_DESCRIPTION', + ), + ), + ), + 'LBL_PANEL_ASSIGNMENT' => + array ( + array ( + array ( + 'name' => 'assigned_user_name', + 'label' => 'LBL_ASSIGNED_TO_NAME', + ), + ), + ), + ), + ), +); +?> diff --git a/modules/Calls/metadata/listviewdefs.php b/modules/Calls/metadata/listviewdefs.php new file mode 100644 index 00000000..55afd9cf --- /dev/null +++ b/modules/Calls/metadata/listviewdefs.php @@ -0,0 +1,123 @@ + + array ( + 'width' => '1%', + 'label' => 'LBL_LIST_CLOSE', + 'link' => true, + 'sortable' => false, + 'default' => true, + 'related_fields' => + array ( + 0 => 'status', + ), + ), + 'DIRECTION' => + array ( + 'width' => '10%', + 'label' => 'LBL_LIST_DIRECTION', + 'link' => false, + 'default' => true, + ), + 'NAME' => + array ( + 'width' => '40%', + 'label' => 'LBL_LIST_SUBJECT', + 'link' => true, + 'default' => true, + ), + 'CONTACT_NAME' => + array ( + 'width' => '20%', + 'label' => 'LBL_LIST_CONTACT', + 'link' => true, + 'id' => 'CONTACT_ID', + 'module' => 'Contacts', + 'default' => true, + 'ACLTag' => 'CONTACT', + ), + 'PARENT_NAME' => + array ( + 'width' => '20%', + 'label' => 'LBL_LIST_RELATED_TO', + 'dynamic_module' => 'PARENT_TYPE', + 'id' => 'PARENT_ID', + 'link' => true, + 'default' => true, + 'sortable' => false, + 'ACLTag' => 'PARENT', + 'related_fields' => + array ( + 0 => 'parent_id', + 1 => 'parent_type', + ), + ), + 'DATE_START' => + array ( + 'width' => '15%', + 'label' => 'LBL_LIST_DATE', + 'link' => false, + 'default' => true, + 'related_fields' => + array ( + 0 => 'time_start', + ), + ), + 'ASSIGNED_USER_NAME' => + array ( + 'width' => '2%', + 'label' => 'LBL_LIST_ASSIGNED_TO_NAME', + 'module' => 'Employees', + 'id' => 'ASSIGNED_USER_ID', + 'default' => true, + ), + 'STATUS' => + array ( + 'width' => '10%', + 'label' => 'LBL_STATUS', + 'link' => false, + 'default' => false, + ), + 'DATE_ENTERED' => array ( + 'width' => '10%', + 'label' => 'LBL_DATE_ENTERED', + 'default' => true + ), +); +?> diff --git a/modules/Calls/metadata/quickcreatedefs.php b/modules/Calls/metadata/quickcreatedefs.php new file mode 100644 index 00000000..a28d0c9f --- /dev/null +++ b/modules/Calls/metadata/quickcreatedefs.php @@ -0,0 +1,177 @@ + + array ( + 'templateMeta' => + array ( + 'maxColumns' => '2', + 'form' => + array ( + 'hidden' => + array ( + 0 => '', + 1 => '', + 2 => '', + 3 => '', + 4 => '', + ), + 'buttons' => + array ( + 0 => + array ( + 'customCode' => '', + ), + 1 => 'CANCEL', + 2 => + array ( + 'customCode' => '', + ), + 3 => + array ( + 'customCode' => '{if $fields.status.value != "Held"}{/if}', + ), + ), + 'footerTpl' => 'modules/Calls/tpls/footer.tpl', + ), + 'widths' => + array ( + 0 => + array ( + 'label' => '10', + 'field' => '30', + ), + 1 => + array ( + 'label' => '10', + 'field' => '30', + ), + ), + 'javascript' => ' + + + + +', + + 'useTabs' => false, + ), + 'panels' => + array ( + 'default' => + array ( + array ( + array ( + 'name' => 'name', + 'displayParams' => + array ( + 'required' => true, + ), + ), + array ( + 'name' => 'status', + 'displayParams' => + array ( + 'required' => true, + ), + 'fields' => + array ( + array ( + 'name' => 'direction', + ), + array ( + 'name' => 'status', + ), + ), + ), + ), + + array ( + array ( + 'name' => 'date_start', + 'type' => 'datetimecombo', + 'displayParams' => + array ( + 'required' => true, + 'updateCallback' => 'SugarWidgetScheduler.update_time();', + ), + 'label' => 'LBL_DATE_TIME', + ), + array ( + 'name' => 'parent_name', + 'label' => 'LBL_LIST_RELATED_TO', + ), + ), + + array ( + array ( + 'name' => 'duration_hours', + 'label' => 'LBL_DURATION', + 'customCode' => '{literal}{/literal}{$fields.duration_minutes.value} {$MOD.LBL_HOURS_MINUTES}', + 'displayParams' => + array ( + 'required' => true, + ), + ), + array ( + 'name' => 'reminder_time', + 'customCode' => '{if $fields.reminder_checked.value == "1"}{assign var="REMINDER_TIME_DISPLAY" value="inline"}{assign var="REMINDER_CHECKED" value="checked"}{else}{assign var="REMINDER_TIME_DISPLAY" value="none"}{assign var="REMINDER_CHECKED" value=""}{/if}
    {$fields.reminder_time.value}
    ', + 'label' => 'LBL_REMINDER', + ), + + ), + + array ( + array ( + 'name' => 'assigned_user_name', + 'label' => 'LBL_ASSIGNED_TO_NAME', + ), + ), + + array ( + array ( + 'name' => 'description', + 'comment' => 'Full text of the note', + 'label' => 'LBL_DESCRIPTION', + ), + ), + ), + ), + ), +); +?> \ No newline at end of file diff --git a/modules/Calls/metadata/searchdefs.php b/modules/Calls/metadata/searchdefs.php new file mode 100644 index 00000000..3da25e93 --- /dev/null +++ b/modules/Calls/metadata/searchdefs.php @@ -0,0 +1,126 @@ + + array ( + 'basic_search' => + array ( + 'name' => + array ( + 'name' => 'name', + 'default' => true, + 'width' => '10%', + ), + 'current_user_only' => + array ( + 'name' => 'current_user_only', + 'label' => 'LBL_CURRENT_USER_FILTER', + 'type' => 'bool', + 'default' => true, + 'width' => '10%', + ), + array ('name' => 'open_only', 'label' => 'LBL_OPEN_ITEMS', 'type' => 'bool', 'default' => false, 'width' => '10%'), + ), + 'advanced_search' => + array ( + 'name' => + array ( + 'name' => 'name', + 'default' => true, + 'width' => '10%', + ), + 'parent_name' => + array ( + 'type' => 'parent', + 'label' => 'LBL_LIST_RELATED_TO', + 'width' => '10%', + 'default' => true, + 'name' => 'parent_name', + ), + 'current_user_only' => + array ( + 'name' => 'current_user_only', + 'label' => 'LBL_CURRENT_USER_FILTER', + 'type' => 'bool', + 'default' => true, + 'width' => '10%', + ), + 'direction' => + array ( + 'type' => 'enum', + 'label' => 'LBL_DIRECTION', + 'width' => '10%', + 'default' => true, + 'name' => 'direction', + ), + 'status' => + array ( + 'name' => 'status', + 'default' => true, + 'width' => '10%', + ), + 'assigned_user_id' => + array ( + 'name' => 'assigned_user_id', + 'type' => 'enum', + 'label' => 'LBL_ASSIGNED_TO', + 'function' => + array ( + 'name' => 'get_user_array', + 'params' => + array ( + 0 => false, + ), + ), + 'default' => true, + 'width' => '10%', + ), + + ), + ), + 'templateMeta' => + array ( + 'maxColumns' => '4', + 'widths' => + array ( + 'label' => '10', + 'field' => '30', + ), + ), +); +?> diff --git a/modules/Calls/metadata/studio.php b/modules/Calls/metadata/studio.php new file mode 100644 index 00000000..fb5c4dad --- /dev/null +++ b/modules/Calls/metadata/studio.php @@ -0,0 +1,66 @@ +array( + 'template'=>'xtpl', + 'template_file'=>'modules/Calls/DetailView.html', + 'php_file'=>'modules/Calls/DetailView.php', + 'type'=>'DetailView', + ), + 'LBL_EDITVIEW'=>array( + 'template'=>'xtpl', + 'template_file'=>'modules/Calls/EditView.html', + 'php_file'=>'modules/Calls/EditView.php', + 'type'=>'EditView', + ), + 'LBL_LISTVIEW'=>array( + 'template'=>'listview', + 'meta_file'=>'modules/Calls/listviewdefs.php', + 'type'=>'ListView', + ), + 'LBL_SEARCHFORM'=>array( + 'template'=>'xtpl', + 'template_file'=>'modules/Calls/SearchForm.html', + 'php_file'=>'modules/Calls/ListView.php', + 'type'=>'SearchForm', + ), + +); diff --git a/modules/Calls/metadata/subpaneldefs.php b/modules/Calls/metadata/subpaneldefs.php new file mode 100644 index 00000000..e85f272a --- /dev/null +++ b/modules/Calls/metadata/subpaneldefs.php @@ -0,0 +1,96 @@ + array( + 'contacts' => array( + 'top_buttons' => array(), + 'order' => 10, + 'module' => 'Contacts', + 'sort_order' => 'asc', + 'sort_by' => 'last_name, first_name', + 'subpanel_name' => 'ForCalls', + 'get_subpanel_data' => 'contacts', + 'title_key' => 'LBL_CONTACTS_SUBPANEL_TITLE', + ), + 'users' => array( + 'top_buttons' => array(), + 'order' => 20, + 'module' => 'Users', + 'sort_order' => 'asc', + 'sort_by' => 'full_name', + 'subpanel_name' => 'ForCalls', + 'get_subpanel_data' => 'users', + 'title_key' => 'LBL_USERS_SUBPANEL_TITLE', + ), + 'leads' => array( + 'order' => 30, + 'module' => 'Leads', + 'sort_order' => 'asc', + 'sort_by' => 'last_name, first_name', + 'subpanel_name' => 'ForCalls', + 'get_subpanel_data' => 'leads', + 'title_key' => 'LBL_LEADS_SUBPANEL_TITLE', + 'top_buttons' => array(), + ), + 'history' => array( + 'order' => 40, + 'title_key' => 'LBL_HISTORY_SUBPANEL_TITLE', + 'type' => 'collection', + 'subpanel_name' => 'history', //this values is not associated with a physical file. + 'sort_order' => 'desc', + 'sort_by' => 'date_entered', + 'header_definition_from_subpanel'=> 'calls', + 'module'=>'History', + 'top_buttons' => array( + array('widget_class' => 'SubPanelTopCreateNoteButton'), + ), + 'collection_list' => array( + 'notes' => array( + 'module' => 'Notes', + 'subpanel_name' => 'ForCalls', + 'get_subpanel_data' => 'notes', + ), + ), + ), /* end history subpanel def */ + ), +); +?> diff --git a/modules/Calls/metadata/subpanels/ForActivities.php b/modules/Calls/metadata/subpanels/ForActivities.php new file mode 100644 index 00000000..3ac9bbd1 --- /dev/null +++ b/modules/Calls/metadata/subpanels/ForActivities.php @@ -0,0 +1,120 @@ + "(calls.status=\'Planned\')", + 'where' => "(calls.status != 'Held' AND calls.status != 'Not Held')", + + + 'list_fields' => array( + 'object_image'=>array( + 'vname' => 'LBL_OBJECT_IMAGE', + 'widget_class' => 'SubPanelIcon', + 'width' => '2%', + ), + 'close_button'=>array( + 'widget_class' => 'SubPanelCloseButton', + 'vname' => 'LBL_LIST_CLOSE', + 'width' => '6%', + 'sortable'=>false, + ), + 'name'=>array( + 'vname' => 'LBL_LIST_SUBJECT', + 'widget_class' => 'SubPanelDetailViewLink', + 'width' => '30%', + ), + 'status'=>array( + 'widget_class' => 'SubPanelActivitiesStatusField', + 'vname' => 'LBL_LIST_STATUS', + 'width' => '15%', + + ), + 'contact_name'=>array( + 'widget_class' => 'SubPanelDetailViewLink', + 'target_record_key' => 'contact_id', + 'target_module' => 'Contacts', + 'module' => 'Contacts', + 'vname' => 'LBL_LIST_CONTACT', + 'width' => '11%', + 'sortable'=>false, + ), + 'contact_name_owner'=>array( + 'usage'=>'query_only', + 'force_exists'=>true + ), + 'contact_name_mod'=>array( + 'usage'=>'query_only', + 'force_exists'=>true + ), + 'contact_id'=>array( + 'usage'=>'query_only', + + ), + 'date_start'=>array( + 'vname' => 'LBL_LIST_DUE_DATE', + 'width' => '10%', + ), + 'assigned_user_name' => array ( + 'name' => 'assigned_user_name', + 'vname' => 'LBL_LIST_ASSIGNED_TO_NAME', + 'widget_class' => 'SubPanelDetailViewLink', + 'target_record_key' => 'assigned_user_id', + 'target_module' => 'Employees', + 'width' => '10%', + ), + 'edit_button'=>array( + 'vname' => 'LBL_EDIT_BUTTON', + 'widget_class' => 'SubPanelEditButton', + 'width' => '2%', + ), + 'remove_button'=>array( + 'vname' => 'LBL_REMOVE', + 'widget_class' => 'SubPanelRemoveButton', + 'width' => '2%', + ), + 'time_start'=>array( + 'usage'=>'query_only', + + ), + + ), +); +?> diff --git a/modules/Calls/metadata/subpanels/ForHistory.php b/modules/Calls/metadata/subpanels/ForHistory.php new file mode 100644 index 00000000..dd44f3cb --- /dev/null +++ b/modules/Calls/metadata/subpanels/ForHistory.php @@ -0,0 +1,128 @@ + "(calls.status='Held' OR calls.status='Not Held')", + + + + 'list_fields' => array( + 'object_image'=>array( + 'vname' => 'LBL_OBJECT_IMAGE', + 'widget_class' => 'SubPanelIcon', + 'width' => '2%', + ), + 'name'=>array( + 'vname' => 'LBL_LIST_SUBJECT', + 'widget_class' => 'SubPanelDetailViewLink', + 'width' => '30%', + ), + 'status'=>array( + 'widget_class' => 'SubPanelActivitiesStatusField', + 'vname' => 'LBL_LIST_STATUS', + 'width' => '15%', + 'force_exists'=>true //this will create a fake field in the case a field is not defined + ), + 'reply_to_status' => array( + 'usage' => 'query_only', + 'force_exists' => true, + 'force_default' => 0, + ), + 'contact_name'=>array( + 'widget_class' => 'SubPanelDetailViewLink', + 'target_record_key' => 'contact_id', + 'target_module' => 'Contacts', + 'module' => 'Contacts', + 'vname' => 'LBL_LIST_CONTACT', + 'width' => '11%', + 'sortable'=>false, + ), + 'contact_id'=>array( + 'usage'=>'query_only', + ), + 'contact_name_owner'=>array( + 'usage'=>'query_only', + 'force_exists'=>true + ), + 'contact_name_mod'=>array( + 'usage'=>'query_only', + 'force_exists'=>true + ), + 'parent_id'=>array( + 'usage'=>'query_only', + 'force_exists'=>true + ), + 'parent_type'=>array( + 'usage'=>'query_only', + 'force_exists'=>true + ), + 'date_modified'=>array( + 'vname' => 'LBL_LIST_DATE_MODIFIED', + 'width' => '10%', + ), + 'date_entered'=>array( + 'vname' => 'LBL_LIST_DATE_ENTERED', + 'width' => '10%', + ), + 'assigned_user_name' => array ( + 'name' => 'assigned_user_name', + 'vname' => 'LBL_LIST_ASSIGNED_TO_NAME', + 'widget_class' => 'SubPanelDetailViewLink', + 'target_record_key' => 'assigned_user_id', + 'target_module' => 'Employees', + 'width' => '10%', + ), + 'edit_button'=>array( + 'vname' => 'LBL_EDIT_BUTTON', + 'widget_class' => 'SubPanelEditButton', + 'width' => '2%', + ), + 'remove_button'=>array( + 'vname' => 'LBL_REMOVE', + 'widget_class' => 'SubPanelRemoveButton', + 'width' => '2%', + ), + 'filename'=>array( + 'usage'=>'query_only', + 'force_exists'=>true + ), + ), +); +?> diff --git a/modules/Calls/metadata/subpanels/default.php b/modules/Calls/metadata/subpanels/default.php new file mode 100644 index 00000000..fab72fa6 --- /dev/null +++ b/modules/Calls/metadata/subpanels/default.php @@ -0,0 +1,114 @@ + array( + array ( + 'widget_class'=>'SubPanelTopCreateButton', + ), + array ( + 'widget_class'=>'SubPanelTopSelectButton', 'popup_module' => 'Calls' + ), + ), + + 'list_fields' => array( + 'object_image'=>array( + 'vname' => 'LBL_OBJECT_IMAGE', + 'widget_class' => 'SubPanelIcon', + 'width' => '2%', + ), + 'close_button'=>array( + 'widget_class' => 'SubPanelCloseButton', + 'vname' => 'LBL_LIST_CLOSE', + 'width' => '6%', + 'sortable'=>false, + ), + 'name'=>array( + 'vname' => 'LBL_LIST_SUBJECT', + 'widget_class' => 'SubPanelDetailViewLink', + 'width' => '30%', + ), + 'status'=>array( + 'widget_class' => 'SubPanelActivitiesStatusField', + 'vname' => 'LBL_STATUS', + 'width' => '15%', + + ), + 'contact_name'=>array( + 'widget_class' => 'SubPanelDetailViewLink', + 'target_record_key' => 'contact_id', + 'target_module' => 'Contacts', + 'module' => 'Contacts', + 'vname' => 'LBL_LIST_CONTACT', + 'width' => '11%', + 'sortable'=>false, + ), + + 'date_start'=>array( + 'vname' => 'LBL_DATE_TIME', + 'width' => '10%', + ), + 'assigned_user_name' => array ( + 'name' => 'assigned_user_name', + 'vname' => 'LBL_LIST_ASSIGNED_TO_NAME', + 'widget_class' => 'SubPanelDetailViewLink', + 'target_record_key' => 'assigned_user_id', + 'target_module' => 'Employees', + ), + 'edit_button'=>array( + 'vname' => 'LBL_EDIT_BUTTON', + 'widget_class' => 'SubPanelEditButton', + 'width' => '2%', + ), + 'remove_button'=>array( + 'vname' => 'LBL_REMOVE', + 'widget_class' => 'SubPanelRemoveButton', + 'width' => '2%', + ), + 'time_start'=>array( + 'usage'=>'query_only', + + ), + + ), +); +?> \ No newline at end of file diff --git a/modules/Calls/tpls/QuickCreate.tpl b/modules/Calls/tpls/QuickCreate.tpl new file mode 100644 index 00000000..8470c3bc --- /dev/null +++ b/modules/Calls/tpls/QuickCreate.tpl @@ -0,0 +1,138 @@ +{* + +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + + + +*} + + +
    + + + + + + + + + + + + + + + + + +{if $REQUEST.parent_id} + +{else} + +{/if} +{if $REQUEST.parent_type} + +{else} + +{/if} + + + + + + + + +
    + + + {$APP.LBL_REQUIRED_SYMBOL} {$APP.NTC_REQUIRED}
    + + + + + + + + + + +{include file="modules/DynamicFields/templates/Fields/Forms/coreBottom.tpl"} \ No newline at end of file diff --git a/modules/DynamicFields/templates/Fields/Forms/bool.tpl b/modules/DynamicFields/templates/Fields/Forms/bool.tpl new file mode 100644 index 00000000..b251328a --- /dev/null +++ b/modules/DynamicFields/templates/Fields/Forms/bool.tpl @@ -0,0 +1,46 @@ +{* + +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + + + +*} + + +{include file="modules/DynamicFields/templates/Fields/Forms/coreTop.tpl"} + +{include file="modules/DynamicFields/templates/Fields/Forms/coreBottom.tpl"} \ No newline at end of file diff --git a/modules/DynamicFields/templates/Fields/Forms/coreBottom.tpl b/modules/DynamicFields/templates/Fields/Forms/coreBottom.tpl new file mode 100644 index 00000000..8b8218f5 --- /dev/null +++ b/modules/DynamicFields/templates/Fields/Forms/coreBottom.tpl @@ -0,0 +1,86 @@ +{* + +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + + + +*} + + +{if $vardef.type != 'bool'} + +{/if} + +{if !$hideImportable} + +{/if} +{if !$hideDuplicatable} + +{/if} +
    + + + + + + + + + + + + + + + + + + + + +

    {$MOD.LBL_NEW_FORM_TITLE}

    {$MOD.LBL_SUBJECT} {$APP.LBL_REQUIRED_SYMBOL}{$MOD.LBL_STATUS} {$APP.LBL_REQUIRED_SYMBOL}
    {$MOD.LBL_DESCRIPTION}{$MOD.LBL_DATE_TIME} + + + + + + + + + + +
    + + {$USER_DATEFORMAT}  + {$TIME_SEPARATOR} + + {if $TIME_MERIDIEM} + + {/if} +
    {$USER_DATEFORMAT}{$TIME_FORMAT}
    +
    {$MOD.LBL_DURATION} {$APP.LBL_REQUIRED_SYMBOL} {$MOD.LBL_HOURS_MINS}
    + + \ No newline at end of file diff --git a/modules/Calls/tpls/footer.tpl b/modules/Calls/tpls/footer.tpl new file mode 100644 index 00000000..5d5de236 --- /dev/null +++ b/modules/Calls/tpls/footer.tpl @@ -0,0 +1,87 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} + +{{if $externalJSFile}} +require_once("'".$externalJSFile."'"); +{{/if}} +{$set_focus_block} +{{if isset($scriptBlocks)}} + +{{$scriptBlocks}} + +{{/if}} + + +
    + + + +
    +
    + {{if !empty($form) && !empty($form.buttons)}} + {{foreach from=$form.buttons key=val item=button}} + {{sugar_button module="$module" id="$button" view="$view"}} + {{/foreach}} + {{else}} + {{sugar_button module="$module" id="SAVE" view="$view"}} + {{sugar_button module="$module" id="CANCEL" view="$view"}} + {{/if}} + {{sugar_button module="$module" id="Audit" view="$view"}} +
    +
    \ No newline at end of file diff --git a/modules/Calls/vardefs.php b/modules/Calls/vardefs.php new file mode 100644 index 00000000..819870fc --- /dev/null +++ b/modules/Calls/vardefs.php @@ -0,0 +1,389 @@ + 'calls', 'comment' => 'A Call is an activity representing a phone call', + 'unified_search' => true, 'unified_search_default_enabled' => true, 'fields' => array ( + + 'name' => + array ( + 'name' => 'name', + 'vname' => 'LBL_SUBJECT', + 'dbType' => 'varchar', + 'type' => 'name', + 'len' => '50', + 'comment' => 'Brief description of the call', + 'unified_search' => true, + 'required'=>true, + 'importable' => 'required', + ), + + 'duration_hours' => + array ( + 'name' => 'duration_hours', + 'vname' => 'LBL_DURATION_HOURS', + 'type' => 'int', + 'len' => '2', + 'comment' => 'Call duration, hours portion', + 'required' => true, + ), + 'duration_minutes' => + array ( + 'name' => 'duration_minutes', + 'vname' => 'LBL_DURATION_MINUTES', + 'type' => 'int', + 'function' => array('name'=>'getDurationMinutesOptions', 'returns'=>'html', 'include'=>'modules/Calls/CallHelper.php'), + 'len' => '2', + 'group'=>'duration_hours', + 'importable' => 'required', + 'comment' => 'Call duration, minutes portion' + ), + + 'date_start' => + array ( + 'name' => 'date_start', + 'vname' => 'LBL_DATE', + 'type' => 'datetimecombo', + 'dbType' => 'datetime', + 'comment' => 'Date in which call is schedule to (or did) start', + 'importable' => 'required', + 'required' => true, + 'enable_range_search' => true, + 'options' => 'date_range_search_dom', + ), + + 'date_end' => + array ( + 'name' => 'date_end', + 'vname' => 'LBL_DATE_END', + 'type' => 'datetime', + 'massupdate'=>false, + 'comment' => 'Date is which call is scheduled to (or did) end', + 'enable_range_search' => true, + 'options' => 'date_range_search_dom', + ), + + 'parent_type'=> + array( + 'name'=>'parent_type', + 'vname'=>'LBL_PARENT_TYPE', + 'type' => 'parent_type', + 'dbType'=>'varchar', + 'required'=>false, + 'group'=>'parent_name', + 'options'=> 'parent_type_display', + 'len'=>255, + 'comment' => 'The Sugar object to which the call is related' + ), + + 'parent_name'=> + array( + 'name'=> 'parent_name', + 'parent_type'=>'record_type_display' , + 'type_name'=>'parent_type', + 'id_name'=>'parent_id', + 'vname'=>'LBL_LIST_RELATED_TO', + 'type'=>'parent', + 'group'=>'parent_name', + 'source'=>'non-db', + 'options'=> 'parent_type_display', + ), + 'status' => + array ( + 'name' => 'status', + 'vname' => 'LBL_STATUS', + 'type' => 'enum', + 'len' => 100, + 'options' => 'call_status_dom', + 'comment' => 'The status of the call (Held, Not Held, etc.)', + 'required' => true, + 'importable' => 'required', + 'default' => 'Planned', + ), + 'direction' => + array ( + 'name' => 'direction', + 'vname' => 'LBL_DIRECTION', + 'type' => 'enum', + 'len' => 100, + 'options' => 'call_direction_dom', + 'comment' => 'Indicates whether call is inbound or outbound' + ), + 'parent_id'=> + array( + 'name'=>'parent_id', + 'vname'=>'LBL_LIST_RELATED_TO_ID', + 'type'=>'id', + 'group'=>'parent_name', + 'reportable'=>false, + 'comment' => 'The ID of the parent Sugar object identified by parent_type' + ), + 'reminder_checked'=>array( + 'name' => 'reminder_checked', + 'vname' => 'LBL_REMINDER', + 'type' => 'bool', + 'source' => 'non-db', + 'comment' => 'checkbox indicating whether or not the reminder value is set (Meta-data only)', + 'massupdate'=>false, + ), + + 'reminder_time'=>array ( + 'name' => 'reminder_time', + 'vname' => 'LBL_REMINDER_TIME', + 'type' => 'int', + 'function' => array('name'=>'getReminderTime', 'returns'=>'html', 'include'=>'modules/Calls/CallHelper.php', 'onListView'=>true), + 'required' => false, + 'reportable' => false, + 'default' => -1, + 'len' => '4', + 'comment' => 'Specifies when a reminder alert should be issued; -1 means no alert; otherwise the number of seconds prior to the start' + ), + + 'outlook_id' => + array ( + 'name' => 'outlook_id', + 'vname' => 'LBL_OUTLOOK_ID', + 'type' => 'varchar', + 'len' => '255', + 'reportable' => false, + 'comment' => 'When the Sugar Plug-in for Microsoft Outlook syncs an Outlook appointment, this is the Outlook appointment item ID' + ), + 'accept_status' => array ( + 'name' => 'accept_status', + 'vname' => 'LBL_SUBJECT', + 'dbType' => 'varchar', + 'type' => 'varchar', + 'len' => '20', + 'source'=>'non-db', + ), + 'contact_name' => + array ( + 'name' => 'contact_name', + 'rname' => 'last_name', + 'db_concat_fields'=> array(0=>'first_name', 1=>'last_name'), + 'id_name' => 'contact_id', + 'massupdate' => false, + 'vname' => 'LBL_CONTACT_NAME', + 'type' => 'relate', + 'link'=>'contacts', + 'table' => 'contacts', + 'isnull' => 'true', + 'module' => 'Contacts', + 'join_name' => 'contacts', + 'dbType' => 'varchar', + 'source'=>'non-db', + 'len' => 36, + 'importable' => 'false', + 'studio' => array('required' => false, 'listview'=>true, 'visible' => false), + ), + 'account' => + array ( + 'name' => 'account', + 'type' => 'link', + 'relationship' => 'account_calls', + 'link_type'=>'one', + 'source'=>'non-db', + 'vname'=>'LBL_OLD_ACCOUNT_LINK', + ), + 'opportunity' => + array ( + 'name' => 'opportunity', + 'type' => 'link', + 'relationship' => 'opportunity_calls', + 'source'=>'non-db', + 'link_type'=>'one', + 'vname'=>'LBL_OPPORTUNITY', + ), + 'leads' => + array ( + 'name' => 'leads', + 'type' => 'link', + 'relationship' => 'calls_leads', + 'source'=>'non-db', + 'vname'=>'LBL_LEADS', + ), + 'case' => + array ( + 'name' => 'case', + 'type' => 'link', + 'relationship' => 'case_calls', + 'source'=>'non-db', + 'link_type'=>'one', + 'vname'=>'LBL_CASE', + ), + 'accounts' => + array ( + 'name' => 'accounts', + 'type' => 'link', + 'relationship' => 'account_calls', + 'module'=>'Accounts', + 'bean_name'=>'Account', + 'source'=>'non-db', + 'vname'=>'LBL_ACCOUNT', + ), + 'contacts' => + array ( + 'name' => 'contacts', + 'type' => 'link', + 'relationship' => 'calls_contacts', + 'source'=>'non-db', + 'vname'=>'LBL_CONTACTS', + ), + 'users' => + array ( + 'name' => 'users', + 'type' => 'link', + 'relationship' => 'calls_users', + 'source'=>'non-db', + 'vname'=>'LBL_USERS', + ), + 'notes' => + array ( + 'name' => 'notes', + 'type' => 'link', + 'relationship' => 'calls_notes', + 'module'=>'Notes', + 'bean_name'=>'Note', + 'source'=>'non-db', + 'vname'=>'LBL_NOTES', + ), + 'created_by_link' => + array ( + 'name' => 'created_by_link', + 'type' => 'link', + 'relationship' => 'calls_created_by', + 'vname' => 'LBL_CREATED_BY_USER', + 'link_type' => 'one', + 'module'=>'Users', + 'bean_name'=>'User', + 'source'=>'non-db', + ), + 'modified_user_link' => + array ( + 'name' => 'modified_user_link', + 'type' => 'link', + 'relationship' => 'calls_modified_user', + 'vname' => 'LBL_MODIFIED_BY_USER', + 'link_type' => 'one', + 'module'=>'Users', + 'bean_name'=>'User', + 'source'=>'non-db', + ), + 'assigned_user_link' => + array ( + 'name' => 'assigned_user_link', + 'type' => 'link', + 'relationship' => 'calls_assigned_user', + 'vname' => 'LBL_ASSIGNED_TO_USER', + 'link_type' => 'one', + 'module'=>'Users', + 'bean_name'=>'User', + 'source'=>'non-db', + ), + 'contact_id' => array( + 'name' => 'contact_id', + 'type' => 'id', + 'source' => 'non-db', + 'importable' => false, + ), +), +'indices' => array ( + array( + 'name' => 'idx_call_name', + 'type' => 'index', + 'fields'=> array('name'), + ), + array( + 'name' => 'idx_status', + 'type' => 'index', + 'fields'=> array('status'), + ), + array( + 'name' => 'idx_calls_date_start', + 'type' => 'index', + 'fields' => array('date_start'), + ), + array ( + 'name' => 'idx_calls_par_del', + 'type' => 'index', + 'fields' => array('parent_id','parent_type','deleted') + ) +), +'relationships' => array ( + 'calls_assigned_user' => array( + 'lhs_module' => 'Users', + 'lhs_table' => 'users', + 'lhs_key' => 'id', + 'rhs_module' => 'Calls', + 'rhs_table' => 'calls', + 'rhs_key' => 'assigned_user_id', + 'relationship_type' => 'one-to-many' + ), + 'calls_modified_user' => array( + 'lhs_module' => 'Users', + 'lhs_table' => 'users', + 'lhs_key' => 'id', + 'rhs_module' => 'Calls', + 'rhs_table' => 'calls', + 'rhs_key' => 'modified_user_id', + 'relationship_type' => 'one-to-many' + ), + 'calls_created_by' => array( + 'lhs_module' => 'Users', + 'lhs_table' => 'users', + 'lhs_key' => 'id', + 'rhs_module' => 'Calls', + 'rhs_table' => 'calls', + 'rhs_key' => 'created_by', + 'relationship_type' => 'one-to-many' + ), + 'calls_notes' => array( + 'lhs_module' => 'Calls', + 'lhs_table' => 'calls', + 'lhs_key' => 'id', + 'rhs_module' => 'Notes', + 'rhs_table' => 'notes', + 'rhs_key' => 'parent_id', + 'relationship_type' => 'one-to-many', + ), + ), +//This enables optimistic locking for Saves From EditView + 'optimistic_locking' => true, +); + +VardefManager::createVardef('Calls','Call', array('default', 'assignable', +)); +?> diff --git a/modules/Calls/views/view.edit.php b/modules/Calls/views/view.edit.php new file mode 100644 index 00000000..6ede06ed --- /dev/null +++ b/modules/Calls/views/view.edit.php @@ -0,0 +1,90 @@ +bean->status = ''; + } //if + if(!empty($_REQUEST['status']) && ($_REQUEST['status'] == 'Held')) { + $this->bean->status = 'Held'; + } + parent::preDisplay(); + } + + /** + * @see SugarView::display() + */ + public function display() + { + global $json; + $json = getJSONobj(); + $json_config = new json_config(); + if (isset($this->bean->json_id) && !empty ($this->bean->json_id)) { + $javascript = $json_config->get_static_json_server(false, true, 'Calls', $this->bean->json_id); + + } else { + $this->bean->json_id = $this->bean->id; + $javascript = $json_config->get_static_json_server(false, true, 'Calls', $this->bean->id); + + } + $this->ss->assign('JSON_CONFIG_JAVASCRIPT', $javascript); + + if($this->ev->isDuplicate){ + $this->bean->status = $this->bean->getDefaultStatus(); + } //if + parent::display(); + } +} diff --git a/modules/CampaignLog/CampaignLog.php b/modules/CampaignLog/CampaignLog.php new file mode 100644 index 00000000..0611848d --- /dev/null +++ b/modules/CampaignLog/CampaignLog.php @@ -0,0 +1,204 @@ +get_list_view_array(); + //make sure that both items in array are set to some value, else return null + if(!(isset($temp_array['TARGET_TYPE']) && $temp_array['TARGET_TYPE']!= '') || !(isset($temp_array['TARGET_ID']) && $temp_array['TARGET_ID']!= '')) + { //needed values to construct query are empty/null, so return null + $GLOBALS['log']->debug("CampaignLog.php:get_list_view_data duntion: temp_array['TARGET_TYPE'] and/or temp_array['TARGET_ID'] are empty, return null"); + $emptyArr = array(); + return $emptyArr; + } + if ( ( $this->db->dbType == 'mysql' ) or ( $this->db->dbType == 'oci8' ) ) + { + $query="select first_name, last_name, CONCAT(CONCAT(first_name, ' '), last_name) name from ".strtolower($temp_array['TARGET_TYPE']) . " where id ='{$temp_array['TARGET_ID']}'"; + } + if($this->db->dbType == 'mssql') + { + $query="select first_name, last_name, (first_name + ' ' + last_name) name from ".strtolower($temp_array['TARGET_TYPE']) . " where id ='{$temp_array['TARGET_ID']}'"; + } + if($temp_array['TARGET_TYPE']=='Accounts'){ + $query="select name from ".strtolower($temp_array['TARGET_TYPE']) . " where id ='{$temp_array['TARGET_ID']}'"; + } + + $result=$this->db->query($query); + $row=$this->db->fetchByAssoc($result); + + if ($row) { + if($temp_array['TARGET_TYPE']=='Accounts'){ + $temp_array['RECIPIENT_NAME']=$row['name']; + }else{ + $full_name = $locale->getLocaleFormattedName($row['first_name'], $row['last_name'], ''); + $temp_array['RECIPIENT_NAME']=$full_name; + } + } + $temp_array['RECIPIENT_EMAIL']=$this->retrieve_email_address($temp_array['TARGET_ID']); + + $query = 'select name from email_marketing where id = \'' . $temp_array['MARKETING_ID'] . '\''; + $result=$this->db->query($query); + $row=$this->db->fetchByAssoc($result); + + if ($row) + { + $temp_array['MARKETING_NAME'] = $row['name']; + } + + return $temp_array; + } + + function retrieve_email_address($trgt_id = ''){ + $return_str = ''; + if(!empty($trgt_id)){ + $qry = " select eabr.primary_address, ea.email_address"; + $qry .= " from email_addresses ea "; + $qry .= " Left Join email_addr_bean_rel eabr on eabr.email_address_id = ea.id "; + $qry .= " where eabr.bean_id = '{$trgt_id}' "; + $qry .= " and ea.deleted = 0 "; + $qry .= " and eabr.deleted = 0" ; + $qry .= " order by primary_address desc "; + + $result=$this->db->query($qry); + $row=$this->db->fetchByAssoc($result); + + if (!empty($row['email_address'])){ + $return_str = $row['email_address']; + } + } + return $return_str; + } + + + + + //this function is called statically by the campaing_log subpanel. + function get_related_name($related_id, $related_type) { + global $locale; + $db= DBManagerFactory::getInstance(); + if ($related_type == 'Emails') { + $query="SELECT name from emails where id='$related_id'"; + $result=$db->query($query); + $row=$db->fetchByAssoc($result); + if ($row != null) { + return $row['name']; + } + } + if ($related_type == 'Contacts') { + $query="SELECT first_name, last_name from contacts where id='$related_id'"; + $result=$db->query($query); + $row=$db->fetchByAssoc($result); + if ($row != null) { + return $full_name = $locale->getLocaleFormattedName($row['first_name'], $row['last_name']); + } + } + if ($related_type == 'Leads') { + $query="SELECT first_name, last_name from leads where id='$related_id'"; + $result=$db->query($query); + $row=$db->fetchByAssoc($result); + if ($row != null) { + return $full_name = $locale->getLocaleFormattedName($row['first_name'], $row['last_name']); + } + } + if ($related_type == 'Prospects') { + $query="SELECT first_name, last_name from prospects where id='$related_id'"; + $result=$db->query($query); + $row=$db->fetchByAssoc($result); + if ($row != null) { + return $full_name = $locale->getLocaleFormattedName($row['first_name'], $row['last_name']); + } + } + if ($related_type == 'CampaignTrackers') { + $query="SELECT tracker_url from campaign_trkrs where id='$related_id'"; + $result=$db->query($query); + $row=$db->fetchByAssoc($result); + if ($row != null) { + return $row['tracker_url'] ; + } + } + if ($related_type == 'Accounts') { + $query="SELECT name from accounts where id='$related_id'"; + $result=$db->query($query); + $row=$db->fetchByAssoc($result); + if ($row != null) { + return $row['name']; + } + } + return $related_id.$related_type; + } +} + +?> diff --git a/modules/CampaignLog/Menu.php b/modules/CampaignLog/Menu.php new file mode 100644 index 00000000..bd1e09e2 --- /dev/null +++ b/modules/CampaignLog/Menu.php @@ -0,0 +1,49 @@ + \ No newline at end of file diff --git a/modules/CampaignLog/Popup_picker.html b/modules/CampaignLog/Popup_picker.html new file mode 100644 index 00000000..91a5f29c --- /dev/null +++ b/modules/CampaignLog/Popup_picker.html @@ -0,0 +1,101 @@ + + + + + + + + + + +
    + + + + +
    + + + + + + + +
    +
    + + + + + +{PAGINATION} + + + + + + + + + + + + + + + + + + +
    {CHECKALL}{MOD.LBL_ID}{arrow_start}{campaign_name_arrow}{arrow_end}{MOD.LBL_LIST_ACTIVITY_DATE}{arrow_start}{activity_date_arrow}{arrow_end}{MOD.LBL_LIST_CAMPAIGN_NAME}{arrow_start}{campaign_objective_arrow}{arrow_end}
    {PREROW}<{TAG_TYPE} href="#" onclick="send_back('CampaignLog','{CAMPAIGNLOG.ID}');">{CAMPAIGNLOG.ID}{CAMPAIGNLOG.ACTIVITY_DATE}{CAMPAIGNLOG.CAMPAIGN_NAME1}
    +{ASSOCIATED_JAVASCRIPT_DATA} + diff --git a/modules/CampaignLog/Popup_picker.php b/modules/CampaignLog/Popup_picker.php new file mode 100644 index 00000000..fdfcc947 --- /dev/null +++ b/modules/CampaignLog/Popup_picker.php @@ -0,0 +1,178 @@ +_get_where_clause(); + + + + $first_name = empty($_REQUEST['first_name']) ? '' : $_REQUEST['first_name']; + $last_name = empty($_REQUEST['last_name']) ? '' : $_REQUEST['last_name']; + + $request_data = empty($_REQUEST['request_data']) ? '' : $_REQUEST['request_data']; + $hide_clear_button = empty($_REQUEST['hide_clear_button']) ? false : true; + + $button = "
    \n"; + //START:FOR MULTI-SELECT + $multi_select=false; + if (!empty($_REQUEST['mode']) && strtoupper($_REQUEST['mode']) == 'MULTISELECT') { + $multi_select=true; + $button .= "\n"; + } + //END:FOR MULTI-SELECT + if(!$hide_clear_button) + { + $button .= "\n"; + } + $button .= "\n"; + $button .= "
    \n"; + + $form = new XTemplate('modules/CampaignLog/Popup_picker.html'); + $form->assign('MOD', $mod_strings); + $form->assign('APP', $app_strings); + $form->assign('THEME', $theme); + $form->assign('MODULE_NAME', $currentModule); + $form->assign('request_data', $request_data); + + + ob_start(); + insert_popup_header($theme); + $output_html .= ob_get_contents(); + ob_end_clean(); + + //$output_html .= get_form_header($mod_strings['LBL_SEARCH_FORM_TITLE'], '', false); + + $form->parse('main.SearchHeader'); + $output_html .= $form->text('main.SearchHeader'); + + // Reset the sections that are already in the page so that they do not print again later. + $form->reset('main.SearchHeader'); + + // create the listview + $seed_bean = new CampaignLog(); + $ListView = new ListView(); + $ListView->show_export_button = false; + $ListView->process_for_popups = true; + $ListView->setXTemplate($form); + $ListView->multi_select_popup=$multi_select; //FOR MULTI-SELECT + if ($multi_select) $ListView->xTemplate->assign("TAG_TYPE","SPAN"); else $ListView->xTemplate->assign("TAG_TYPE","A");//FOR MULTI-SELECT + //$ListView->setHeaderTitle($mod_strings['LBL_LIST_FORM_TITLE']); //FOR MULTI-SELECT + //$ListView->setHeaderText($button); //FOR MULTI-SELECT + $ListView->setQuery($where, '', 'campaign_name1', 'CAMPAIGNLOG'); + $ListView->setModStrings($mod_strings); + + ob_start(); + $output_html .= get_form_header($mod_strings['LBL_LIST_FORM_TITLE'], $button, false); //FOR MULTI-SELECT + $ListView->processListView($seed_bean, 'main', 'CAMPAIGNLOG'); + $output_html .= ob_get_contents(); + ob_end_clean(); + + $output_html .= insert_popup_footer(); + return $output_html; + } +} // end of class Popup_Picker +?> \ No newline at end of file diff --git a/modules/CampaignLog/language/en_us.lang.php b/modules/CampaignLog/language/en_us.lang.php new file mode 100644 index 00000000..b3af34b3 --- /dev/null +++ b/modules/CampaignLog/language/en_us.lang.php @@ -0,0 +1,100 @@ +'Prospect List ID', + 'LBL_ID' => 'ID', + 'LBL_TARGET_TRACKER_KEY'=>'Target Tracker Key', + 'LBL_TARGET_ID'=>'Target ID', + 'LBL_TARGET_TYPE'=>'Target Type', + 'LBL_ACTIVITY_TYPE' =>'Activity Type', + 'LBL_ACTIVITY_DATE' => 'Activity Date', + 'LBL_RELATED_ID' => 'Related Id', + 'LBL_RELATED_TYPE'=>'Related Type', + 'LBL_DELETED' => 'Deleted', + 'LBL_MODULE_NAME' =>'Campaign Log', + 'LBL_LIST_RECIPIENT_EMAIL'=>'Recipient Email', + 'LBL_LIST_RECIPIENT_NAME'=>'Recipient Name', + 'LBL_ARCHIVED'=>'Archived', + 'LBL_HITS'=>'Hits', + + 'LBL_CAMPAIGN_NAME' => 'Name:', + 'LBL_CAMPAIGN' => 'Campaign:', + 'LBL_NAME' => 'Name: ', + 'LBL_INVITEE' => 'Contacts', + 'LBL_LIST_CAMPAIGN_NAME' => 'Campaign', + 'LBL_LIST_STATUS' => 'Status', + 'LBL_LIST_TYPE' => 'Type', + 'LBL_LIST_END_DATE' => 'End Date', + 'LBL_DATE_ENTERED' => 'Date Entered', + 'LBL_DATE_MODIFIED' => 'Date Modified', + 'LBL_MODIFIED' => 'Modified By: ', + 'LBL_CREATED' => 'Created By: ', + 'LBL_TEAM' => 'Team: ', + 'LBL_ASSIGNED_TO' => 'Assigned To: ', + 'LBL_CAMPAIGN_START_DATE' => 'Start Date: ', + 'LBL_CAMPAIGN_END_DATE' => 'End Date: ', + 'LBL_CAMPAIGN_STATUS' => 'Status: ', + 'LBL_CAMPAIGN_BUDGET' => 'Budget: ', + 'LBL_CAMPAIGN_EXPECTED_COST' => 'Expected Cost: ', + 'LBL_CAMPAIGN_ACTUAL_COST' => 'Actual Cost: ', + 'LBL_CAMPAIGN_EXPECTED_REVENUE' => 'Expected Revenue: ', + 'LBL_CAMPAIGN_TYPE' => 'Type: ', + 'LBL_CAMPAIGN_OBJECTIVE' => 'Objective: ', + 'LBL_CAMPAIGN_CONTENT' => 'Description: ', + 'LBL_CREATED_LEAD' => 'Created Lead', + 'LBL_CREATED_CONTACT' => 'Created Contact', + 'LBL_LIST_FORM_TITLE'=> 'Targeted Campaigns', + 'LBL_LIST_ACTIVITY_DATE'=>'Activity Date', + 'LBL_LIST_CAMPAIGN_OBJECTIVE'=>'Campaign Objective', + 'LBL_RELATED'=>'Related', + 'LBL_CLICKED_URL_KEY'=>'Clicked URL Key', + 'LBL_URL_CLICKED'=>'URL Clicked', + 'LBL_MORE_INFO'=>'More Information', + + 'LBL_CAMPAIGNS' => 'Campaigns', + 'LBL_LIST_MARKETING_NAME' => 'Marketing Id', +); +?> \ No newline at end of file diff --git a/modules/CampaignLog/metadata/subpanels/ForTargets.php b/modules/CampaignLog/metadata/subpanels/ForTargets.php new file mode 100644 index 00000000..9cc9f5c1 --- /dev/null +++ b/modules/CampaignLog/metadata/subpanels/ForTargets.php @@ -0,0 +1,87 @@ + array( + ), + + 'where' => '', + + + 'list_fields' => array( + 'campaign_name1'=>array( + 'vname' => 'LBL_LIST_CAMPAIGN_NAME', + 'width' => '20%', + 'widget_class' => 'SubPanelDetailViewLink', + 'target_record_key' => 'campaign_id', + 'target_module' => 'Campaigns', + ), + 'activity_type' => array( + 'vname' => 'LBL_ACTIVITY_TYPE', + 'width' => '10%', + ), + 'activity_date' => array( + 'vname' => 'LBL_ACTIVITY_DATE', + 'width' => '10%', + ), + 'related_name' => array( + 'widget_class' => 'SubPanelDetailViewLink', + 'target_record_key' => 'related_id', + 'target_module_key' => 'related_type', + 'parent_id' =>'target_id', + 'parent_module'=>'target_type', + 'vname' => 'LBL_RELATED', + 'width' => '60%', + 'sortable'=>false, + ), + 'related_id'=>array( + 'usage' =>'query_only', + ), + 'related_type'=>array( + 'usage' =>'query_only', + ), + 'target_id'=>array( + 'usage' =>'query_only', + ), + 'target_type'=>array( + 'usage' =>'query_only', + ), + ), +); +?> \ No newline at end of file diff --git a/modules/CampaignLog/metadata/subpanels/default.php b/modules/CampaignLog/metadata/subpanels/default.php new file mode 100644 index 00000000..ae6a0487 --- /dev/null +++ b/modules/CampaignLog/metadata/subpanels/default.php @@ -0,0 +1,100 @@ + array( + array('widget_class' => 'SubPanelAddToProspectListButton','create'=>'true'), + ), + + 'where' => '', + + + 'list_fields' => array( + 'recipient_name'=>array( + 'vname' => 'LBL_LIST_RECIPIENT_NAME', + 'width' => '14%', + 'sortable'=>false, + ), + 'recipient_email'=>array( + 'vname' => 'LBL_LIST_RECIPIENT_EMAIL', + 'width' => '14%', + 'sortable'=>false, + ), + 'marketing_name'=>array( + 'vname' => 'LBL_LIST_MARKETING_NAME', + 'width' => '14%', + 'sortable'=>false, + ), + 'activity_type' => array( + 'vname' => 'LBL_ACTIVITY_TYPE', + 'width' => '14%', + ), + 'activity_date' => array( + 'vname' => 'LBL_ACTIVITY_DATE', + 'width' => '14%', + ), + 'related_name' => array( + 'widget_class' => 'SubPanelDetailViewLink', + 'target_record_key' => 'related_id', + 'target_module_key' => 'related_type', + 'parent_id' =>'target_id', + 'parent_module'=>'target_type', + 'vname' => 'LBL_RELATED', + 'width' => '20%', + 'sortable'=>false, + ), + 'hits' => array( + 'vname' => 'LBL_HITS', + 'width' => '5%', + ), + 'target_id'=>array( + 'usage' =>'query_only', + ), + 'target_type'=>array( + 'usage' =>'query_only', + ), + 'related_id'=>array( + 'usage' =>'query_only', + ), + 'related_type'=>array( + 'usage' =>'query_only', + ), + ), +); +?> diff --git a/modules/CampaignLog/vardefs.php b/modules/CampaignLog/vardefs.php new file mode 100644 index 00000000..9fe4582c --- /dev/null +++ b/modules/CampaignLog/vardefs.php @@ -0,0 +1,289 @@ +false, + 'comment' => 'Tracks items of interest that occurred after you send an email campaign', + 'table' => 'campaign_log', + + 'fields' => array ( + 'id' => array ( + 'name' => 'id', + 'vname' => 'LBL_ID', + 'type' => 'id', + 'required' => true, + 'reportable'=>true, + 'comment' => 'Unique identifier' + ), + 'campaign_id' => array ( + 'name' => 'campaign_id', + 'vname' => 'LBL_CAMPAIGN_ID', + 'type' => 'id', + 'comment' => 'Campaign identifier' + ), + 'target_tracker_key' => array ( + 'name' => 'target_tracker_key', + 'vname' => 'LBL_TARGET_TRACKER_KEY', + 'type' => 'varchar', + 'len' => '36', + 'comment' => 'Identifier of Tracker URL' + ), + 'target_id' => array ( + 'name' => 'target_id', + 'vname' => 'LBL_TARGET_ID', + 'type' => 'varchar', + 'len' => '36', + 'comment' => 'Identifier of target record' + ), + 'target_type' => array ( + 'name' => 'target_type', + 'vname' => 'LBL_TARGET_TYPE', + 'type' => 'varchar', + 'len' => 100, + 'comment' => 'Descriptor of the target record type (e.g., Contact, Lead)' + ), + 'activity_type' => array ( + 'name' => 'activity_type', + 'vname' => 'LBL_ACTIVITY_TYPE', + 'type' => 'enum', + 'options'=>'campainglog_activity_type_dom', + 'len' => 100, + 'comment' => 'The activity that occurred (e.g., Viewed Message, Bounced, Opted out)' + ), + 'activity_date' => array ( + 'name' => 'activity_date', + 'vname' => 'LBL_ACTIVITY_DATE', + 'type' => 'datetime', + 'comment' => 'The date the activity occurred' + ), + 'related_id' => array ( + 'name' => 'related_id', + 'vname' => 'LBL_RELATED_ID', + 'type' => 'varchar', + 'len' => '36', + ), + 'related_type' => array ( + 'name' => 'related_type', + 'vname' => 'LBL_RELATED_TYPE', + 'type' => 'varchar', + 'len' => 100, + ), + 'archived' => array ( + 'name' => 'archived', + 'vname' => 'LBL_ARCHIVED', + 'type' => 'bool', + 'reportable'=>false, + 'default'=>'0', + 'comment' => 'Indicates if item has been archived' + ), + 'hits' => array ( + 'name' => 'hits', + 'vname' => 'LBL_HITS', + 'type' => 'int', + 'default'=>'0', + 'reportable'=>true, + 'comment' => 'Number of times the item has been invoked (e.g., multiple click-thrus)' + ), + 'list_id' => array( + 'name' => 'list_id', + 'vname' => 'LBL_LIST_ID', + 'type' => 'id', + 'reportable' =>false, + 'len' => '36', + 'comment' => 'The target list from which item originated' + ), + 'deleted' => array ( + 'name' => 'deleted', + 'vname' => 'LBL_DELETED', + 'type' => 'bool', + 'reportable'=>false, + 'comment' => 'Record deletion indicator' + ), + 'recipient_name' => array( + 'name' => 'recipient_name', + 'type' => 'varchar', + 'len' => '255', + 'source'=>'non-db', + ), + 'recipient_email' => array( + 'name' => 'recipient_email', + 'type' => 'varchar', + 'len' => '255', + 'source'=>'non-db', + ), + 'marketing_name' => array( + 'name' => 'marketing_name', + 'type' => 'varchar', + 'len' => '255', + 'source'=>'non-db', + ), + 'campaign_name1' => array ( + 'name' => 'campaign_name1', + 'rname' => 'name', + 'id_name' => 'campaign_id', + 'vname' => 'LBL_CAMPAIGN_NAME', + 'type' => 'relate', + 'table' => 'campaigns', + 'isnull' => 'true', + 'module' => 'Campaigns', + 'dbType' => 'varchar', + 'link'=>'campaign', + 'len' => '255', + 'source'=>'non-db', + ), + 'campaign_name' => array( + 'name' => 'campaign_name', + 'type' => 'varchar', + 'len' => '255', + 'source'=>'non-db', + ), + 'campaign_objective' => array( + 'name' => 'campaign_objective', + 'type' => 'varchar', + 'len' => '255', + 'source'=>'non-db', + ), + 'campaign_content' => array( + 'name' => 'campaign_content', + 'type' => 'varchar', + 'len' => '255', + 'source'=>'non-db', + ), + 'campaign'=> array ( + 'name' => 'campaign', + 'type' => 'link', + 'relationship' => 'campaign_campaignlog', + 'source'=>'non-db', + 'vname'=> 'LBL_CAMPAIGNS', + ), + 'related_name'=>array ( + 'source'=>'function', + 'function_name'=>'get_related_name', + 'function_class'=>'CampaignLog', + 'function_params'=> array('related_id', 'related_type'), + 'function_params_source'=>'this', //valid values are 'parent' or 'this' default is parent. + 'type'=>'function', + 'name'=>'related_name', + 'reportable'=>false, + ), + 'date_modified' => array ( + 'name' => 'date_modified', + 'vname' => 'LBL_DATE_MODIFIED', + 'type' => 'datetime', + ), + 'more_information'=> array( + 'name'=>'more_information', + 'vname'=>'LBL_MORE_INFO', + 'type'=>'varchar', + 'len'=>'100', + ), + 'marketing_id' => array( + 'name' => 'marketing_id', + 'vname' => 'LBL_MARKETING_ID', + 'type' => 'id', + 'reportable' =>false, + 'comment' => 'ID of marketing email this entry is associated with', + ), + 'created_contact'=> array ( + 'name' => 'created_contact', + 'vname' => 'LBL_CREATED_CONTACT', + 'type' => 'link', + 'relationship' => 'campaignlog_contact', + 'source'=>'non-db', + ), + 'created_lead'=> array ( + 'name' => 'created_lead', + 'vname' => 'LBL_CREATED_LEAD', + 'type' => 'link', + 'relationship' => 'campaignlog_lead', + 'source'=>'non-db', + ), + ), + 'indices' => array ( + array ( + 'name' =>'campaign_log_pk', + + 'type' =>'primary', + 'fields'=>array('id') + ), + array ( + 'name' =>'idx_camp_tracker', + + 'type' =>'index', + 'fields'=>array('target_tracker_key') + ), + + array ( + 'name' =>'idx_camp_campaign_id', + + 'type' =>'index', + 'fields'=>array('campaign_id') + ), + + array ( + 'name' =>'idx_camp_more_info', + + 'type' =>'index', + 'fields'=>array('more_information') + ), + array ( + 'name' =>'idx_target_id', + + 'type' =>'index', + 'fields'=>array('target_id') + ), + ), + 'relationships' => array ( + 'campaignlog_contact' => array( 'lhs_module'=> 'CampaignLog', + 'lhs_table'=> 'campaign_log', + 'lhs_key' => 'related_id', + 'rhs_module'=> 'Contacts', + 'rhs_table'=> 'contacts', + 'rhs_key' => 'id', + 'relationship_type'=>'one-to-many'), + 'campaignlog_lead' => array('lhs_module'=> 'CampaignLog', + 'lhs_table'=> 'campaign_log', + 'lhs_key' => 'related_id', + 'rhs_module'=> 'Leads', + 'rhs_table'=> 'leads', + 'rhs_key' => 'id', + 'relationship_type'=>'one-to-many'), + + ) + + +); +?> \ No newline at end of file diff --git a/modules/CampaignTrackers/CampaignTracker.php b/modules/CampaignTrackers/CampaignTracker.php new file mode 100644 index 00000000..7c080e14 --- /dev/null +++ b/modules/CampaignTrackers/CampaignTracker.php @@ -0,0 +1,161 @@ +'campaign'); + + var $required_fields = array('tracker_name'=>1,'tracker_url'=>1); + /*This bean's constructor*/ + function CampaignTracker() { + parent::SugarBean(); + } + + function save() { + //make sure that the url has a scheme, if not then add http:// scheme + if ($this->is_optout!=1 ){ + $url = strtolower(trim($this->tracker_url)); + if(!preg_match('/^(http|https|ftp):\/\//i', $url)){ + $this->tracker_url = 'http://'.$url; + } + } + + parent::save(); + } + + /* This method should return the summary text which is used to build the bread crumb navigation*/ + /* Generally from this method you would return value of a field that is required and is of type string*/ + function get_summary_text() + { + return "$this->tracker_name"; + } + + + /* This method is used to generate query for the list form. The base implementation of this method + * uses the table_name and list_field varaible to generate the basic query and then adds the custom field + * join and team filter. If you are implementing this function do not forget to consider the additional conditions. + */ + + function fill_in_additional_detail_fields() { + global $sugar_config; + + //setup campaign name. + $query = "SELECT name from campaigns where id = '$this->campaign_id'"; + $result =$this->db->query($query,true," Error filling in additional detail fields: "); + + // Get the id and the name. + $row = $this->db->fetchByAssoc($result); + if($row != null) { + $this->campaign_name=$row['name']; + } + + if (!class_exists('Administration')) { + + } + $admin=new Administration(); + $admin->retrieveSettings('massemailer'); //retrieve all admin settings. + if (isset($admin->settings['massemailer_tracking_entities_location_type']) and $admin->settings['massemailer_tracking_entities_location_type']=='2' and isset($admin->settings['massemailer_tracking_entities_location']) ) { + $this->message_url=$admin->settings['massemailer_tracking_entities_location']; + } else { + $this->message_url=$sugar_config['site_url']; + } + if ($this->is_optout == 1) { + $this->message_url .= '/index.php?entryPoint=removeme&identifier={MESSAGE_ID}'; + } else { + $this->message_url .= '/index.php?entryPoint=campaign_trackerv2&track=' . $this->id; + } + } +} +?> \ No newline at end of file diff --git a/modules/CampaignTrackers/DetailView.html b/modules/CampaignTrackers/DetailView.html new file mode 100644 index 00000000..9732dd6c --- /dev/null +++ b/modules/CampaignTrackers/DetailView.html @@ -0,0 +1,88 @@ + + +
    + + + + + + + + + + {PORTAL_ON} + + + +
    {ADMIN_EDIT}
    + +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + +
    {MOD.LBL_EDIT_CAMPAIGN_NAME}{CAMPAIGN_NAME} 
    {MOD.LBL_EDIT_TRACKER_NAME}{TRACKER_NAME} 
    {MOD.LBL_EDIT_OPT_OUT}
    {MOD.LBL_EDIT_TRACKER_URL}{TRACKER_URL} 
    {MOD.LBL_EDIT_TRACKER_KEY}{TRACKER_KEY} 
    {MOD.LBL_EDIT_MESSAGE_URL}{MESSAGE_URL} 
    + \ No newline at end of file diff --git a/modules/CampaignTrackers/DetailView.php b/modules/CampaignTrackers/DetailView.php new file mode 100644 index 00000000..1136fd5d --- /dev/null +++ b/modules/CampaignTrackers/DetailView.php @@ -0,0 +1,118 @@ +retrieve($_REQUEST['record']); + +if(isset($_REQUEST['isDuplicate']) && $_REQUEST['isDuplicate'] == 'true') { + $focus->id = ""; +} + +echo getClassicModuleTitle($mod_strings['LBL_MODULE_NAME'], array($mod_strings['LBL_MODULE_NAME'],$focus->tracker_name), true); + + + +$GLOBALS['log']->info("campaign tracker detail view"); + +$xtpl=new XTemplate ('modules/CampaignTrackers/DetailView.html'); +$xtpl->assign("MOD", $mod_strings); +$xtpl->assign("APP", $app_strings); + +if (isset($_REQUEST['return_module'])) { + $xtpl->assign("RETURN_MODULE", $_REQUEST['return_module']); +} else { + $xtpl->assign("RETURN_MODULE", 'Campaigns'); +} +if (isset($_REQUEST['return_action'])) { + $xtpl->assign("RETURN_ACTION", $_REQUEST['return_action']); +} else { + $xtpl->assign("RETURN_ACTION", 'DetailView'); +} +if (isset($_REQUEST['return_id'])) { + $xtpl->assign("RETURN_ID", $_REQUEST['return_id']); +} else { + $xtpl->assign("RETURN_ID", $focus->campaign_id); +} + +$xtpl->assign("GRIDLINE", $gridline); +$xtpl->assign("PRINT_URL", "index.php?".$GLOBALS['request_string']); +$xtpl->assign("ID", $focus->id); +if (!empty($_REQUEST['campaign_name'])) { + $xtpl->assign("CAMPAIGN_NAME", $_REQUEST['campaign_name']); +} else { + $xtpl->assign("CAMPAIGN_NAME", $focus->campaign_name); +} + +if (!empty($_REQUEST['campaign_id'])) { + $xtpl->assign("CAMPAIGN_ID", $_REQUEST['campaign_id']); +} else { + $xtpl->assign("CAMPAIGN_ID", $focus->campaign_id); +} +$xtpl->assign("TRACKER_NAME", $focus->tracker_name); +$xtpl->assign("TRACKER_URL", $focus->tracker_url); +$xtpl->assign("MESSAGE_URL", $focus->message_url); +$xtpl->assign("TRACKER_KEY", $focus->tracker_key); + +if (!empty($focus->is_optout) && $focus->is_optout == 1) { + $xtpl->assign("IS_OPTOUT_CHECKED","checked"); +} + + +//$xtpl->assign("CREATED_BY", $focus->created_by_name); +//$xtpl->assign("MODIFIED_BY", $focus->modified_by_name); +//$xtpl->assign("DATE_MODIFIED", $focus->date_modified); +//$xtpl->assign("DATE_ENTERED", $focus->date_entered); + +$xtpl->parse("main"); +$xtpl->out("main"); +?> \ No newline at end of file diff --git a/modules/CampaignTrackers/EditView.html b/modules/CampaignTrackers/EditView.html new file mode 100644 index 00000000..ee804b2e --- /dev/null +++ b/modules/CampaignTrackers/EditView.html @@ -0,0 +1,91 @@ + + + + + + + + +
    +
    + + + + + + + +
    {APP.LBL_REQUIRED_SYMBOL} {APP.NTC_REQUIRED}{ADMIN_EDIT}
    + + + +"; + $sched_mes_body .= ""; + if($funct['job']==$check_sched1){ + $check_sched1 ="found"; + }else{ + $check_sched2 ="found"; + } + + } +} + +//determine which table header to use, based on whether or not schedulers were found +$show_admin_link = false; +if($sched_mes == 'use'){ + $sched_mes = "
    ".$mod_strings['LBL_SCHEDULER_CHECK_GOOD']."

    + + + + + + + + + + + + + + + + +
    {MOD.LBL_EDIT_CAMPAIGN_NAME}{CAMPAIGN_NAME}
    {MOD.LBL_EDIT_TRACKER_NAME} {APP.LBL_REQUIRED_SYMBOL}{MOD.LBL_EDIT_OPT_OUT}
    {MOD.LBL_EDIT_TRACKER_URL} {APP.LBL_REQUIRED_SYMBOL}
    +{JAVASCRIPT} + + \ No newline at end of file diff --git a/modules/CampaignTrackers/EditView.php b/modules/CampaignTrackers/EditView.php new file mode 100644 index 00000000..bf84272a --- /dev/null +++ b/modules/CampaignTrackers/EditView.php @@ -0,0 +1,132 @@ +retrieve($_REQUEST['record']); +} +$old_id = ''; + +if(isset($_REQUEST['isDuplicate']) && $_REQUEST['isDuplicate'] == 'true') { + $focus->id = ""; +} + + + + +$GLOBALS['log']->info("Campaign Tracker Edit View"); + +$xtpl=new XTemplate ('modules/CampaignTrackers/EditView.html'); +$xtpl->assign("MOD", $mod_strings); +$xtpl->assign("APP", $app_strings); + +$campaignName = ''; +$campaignId = ''; +if (!empty($_REQUEST['campaign_name'])) { + $xtpl->assign("CAMPAIGN_NAME", $_REQUEST['campaign_name']); + $campaignName = $_REQUEST['campaign_name']; +} else { + $xtpl->assign("CAMPAIGN_NAME", $focus->campaign_name); + $campaignName = $focus->campaign_name; +} +if (!empty($_REQUEST['campaign_id'])) { + $xtpl->assign("CAMPAIGN_ID", $_REQUEST['campaign_id']); + $campaignId = $_REQUEST['campaign_id']; +} else { + $xtpl->assign("CAMPAIGN_ID", $focus->campaign_id); + $campaignId = $focus->campaign_id; +} +$params = array(); +$params[] = "{$campaignName}"; +$params[] = $mod_strings['LBL_MODULE_NAME']; +echo getClassicModuleTitle($focus->module_dir, $params, true); + +if (isset($_REQUEST['return_module'])) $xtpl->assign("RETURN_MODULE", $_REQUEST['return_module']); +if (isset($_REQUEST['return_action'])) $xtpl->assign("RETURN_ACTION", $_REQUEST['return_action']); +if (isset($_REQUEST['return_id'])) $xtpl->assign("RETURN_ID", $_REQUEST['return_id']); + +$xtpl->assign("PRINT_URL", "index.php?".$GLOBALS['request_string']); + +$xtpl->assign("JAVASCRIPT", get_set_focus_js().get_validate_record_js()); +$xtpl->assign("ID", $focus->id); + + + +$xtpl->assign("TRACKER_NAME", $focus->tracker_name); +$xtpl->assign("TRACKER_URL", $focus->tracker_url); + +global $current_user; +if(is_admin($current_user) && $_REQUEST['module'] != 'DynamicLayout' && !empty($_SESSION['editinplace'])){ + $record = ''; + if(!empty($_REQUEST['record'])){ + $record = $_REQUEST['record']; + } + $xtpl->assign("ADMIN_EDIT","".SugarThemeRegistry::current()->getImage("EditLayout","border='0' alt='Edit Layout' align='bottom'").""); +} +if (!empty($focus->is_optout) && $focus->is_optout == 1) { + $xtpl->assign("IS_OPTOUT_CHECKED","checked"); + $xtpl->assign("TRACKER_URL_DISABLED","disabled"); +} + +$xtpl->parse("main"); + +$xtpl->out("main"); + +$javascript = new javascript(); +$javascript->setFormName('EditView'); +$javascript->setSugarBean($focus); +$javascript->addAllFields(''); +echo $javascript->getScript(); +?> \ No newline at end of file diff --git a/modules/CampaignTrackers/Forms.html b/modules/CampaignTrackers/Forms.html new file mode 100644 index 00000000..60e10329 --- /dev/null +++ b/modules/CampaignTrackers/Forms.html @@ -0,0 +1,70 @@ + + + + + + + + + +{TEAM_ID} +

    +{MOD.LBL_CAMPAIGN_NAME} *
    +
    +{MOD.LBL_CAMPAIGN_STATUS} *
    +
    +{MOD.LBL_CAMPAIGN_END_DATE} *
    + {APP.LBL_ENTER_DATE} {APP.NTC_DATE_FORMAT}
    +{MOD.LBL_CAMPAIGN_TYPE} *
    + +

    +

    + + +{JAVASCRIPT} + + diff --git a/modules/CampaignTrackers/Forms.php b/modules/CampaignTrackers/Forms.php new file mode 100644 index 00000000..f0963555 --- /dev/null +++ b/modules/CampaignTrackers/Forms.php @@ -0,0 +1,137 @@ + + +function verify_data(form) { + var isError = false; + var errorMessage = ""; + + if (isError == true) { + alert("$err_missing_required_fields" + errorMessage); + return false; + } + return true; +} + + +EOQ; + +return $the_script; + + + +} + +/** + * Create HTML form to enter a new record with the minimum necessary fields. + * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc. + * All Rights Reserved. + * Contributor(s): ______________________________________.. + */ +function get_new_record_form () { + global $app_strings; + global $app_list_strings; + global $mod_strings; + global $currentModule; + global $current_user; + global $timedate; + + $the_form = get_left_form_header($mod_strings['LBL_NEW_FORM_TITLE']); + $form = new XTemplate ('modules/Campaigns/Forms.html'); + + $module_select = empty($_REQUEST['module_select']) ? '' + : $_REQUEST['module_select']; + $form->assign('MOD', $mod_strings); + $form->assign('APP', $app_strings); + $form->assign('THEME', SugarThemeRegistry::current()->__toString()); + $form->assign("JAVASCRIPT", get_set_focus_js().get_validate_record_js()); + $form->assign("STATUS_OPTIONS", get_select_options_with_id($app_list_strings['campaign_status_dom'], "Planning")); + $form->assign("TYPE_OPTIONS", get_select_options_with_id($app_list_strings['campaign_type_dom'], "")); + + $form->assign("USER_ID", $current_user->id); + + + $form->assign("CALENDAR_LANG", "en"); + $form->assign("USER_DATEFORMAT", '('. $timedate->get_user_date_format().')'); + $form->assign("CALENDAR_DATEFORMAT", $timedate->get_cal_date_format()); + + $form->parse('main'); + $the_form .= $form->text('main'); + + + $focus = new Campaign(); + + + $javascript = new javascript(); + $javascript->setFormName('quick_save'); + $javascript->setSugarBean($focus); + $javascript->addRequiredFields(''); + $jscript = $javascript->getScript(); + + $the_form .= $jscript . get_left_form_footer(); + return $the_form; + + +} + +?> \ No newline at end of file diff --git a/modules/CampaignTrackers/Menu.php b/modules/CampaignTrackers/Menu.php new file mode 100644 index 00000000..5a79ae2b --- /dev/null +++ b/modules/CampaignTrackers/Menu.php @@ -0,0 +1,49 @@ + \ No newline at end of file diff --git a/modules/CampaignTrackers/Save.php b/modules/CampaignTrackers/Save.php new file mode 100644 index 00000000..9b3b80df --- /dev/null +++ b/modules/CampaignTrackers/Save.php @@ -0,0 +1,82 @@ +retrieve($_POST['record']); +if(!$focus->ACLAccess('Save')){ + ACLController::displayNoAccess(true); + sugar_cleanup(true); +} + +$check_notify = FALSE; +foreach($focus->column_fields as $field) { + if(isset($_POST[$field])) { + $value = $_POST[$field]; + $focus->$field = $value; + } +} + +foreach($focus->additional_column_fields as $field) { + if(isset($_POST[$field])) { + $value = $_POST[$field]; + $focus->$field = $value; + + } +} +//set check box states. +if (isset($_POST['is_optout']) && $_POST['is_optout'] =='on') { + $focus->is_optout=1; + $focus->tracker_url='index.php?entryPoint=removeme'; +} else { + $focus->is_optout=0; +} + +$focus->save($check_notify); +$return_id = $focus->id; +$GLOBALS['log']->debug("Saved record with id of ".$return_id); +handleRedirect('', ''); +?> \ No newline at end of file diff --git a/modules/CampaignTrackers/language/en_us.lang.php b/modules/CampaignTrackers/language/en_us.lang.php new file mode 100644 index 00000000..9d235966 --- /dev/null +++ b/modules/CampaignTrackers/language/en_us.lang.php @@ -0,0 +1,74 @@ +'Id', + 'LBL_TRACKER_KEY'=>'Tracker Key', + 'LBL_TRACKER_URL'=>'Tracker URL', + 'LBL_TRACKER_NAME'=>'Tracker Name', + 'LBL_CAMPAIGN_ID'=>'Campaign Id', + 'LBL_DATE_ENTERED'=>'Date Entered', + 'LBL_DATE_MODIFIED'=>'Date Modified', + 'LBL_MODIFIED_USER_ID'=>'Modified User Id', + 'LBL_CREATED_BY'=>'Created By', + 'LBL_DELETED'=>'Deleted', + 'LBL_CAMPAIGN'=>'Campaign', + 'LBL_OPTOUT'=>'Opt-out', + + 'LBL_MODULE_NAME'=>'Campaign Trackers', + 'LBL_EDIT_CAMPAIGN_NAME'=>'Campaign Name:', + 'LBL_EDIT_TRACKER_NAME'=>'Tracker Name:', + 'LBL_EDIT_TRACKER_URL'=>'Tracker URL:', + + 'LBL_SUBPANEL_TRACKER_NAME'=>'Name', + 'LBL_SUBPANEL_TRACKER_URL'=>'URL', + 'LBL_SUBPANEL_TRACKER_KEY'=>'Key', + 'LBL_EDIT_MESSAGE_URL'=>'URL for Campaign Message:', + 'LBL_EDIT_TRACKER_KEY'=>'Tracker Key:', + 'LBL_EDIT_OPT_OUT'=>'Opt-out Link?', + 'LNK_CAMPAIGN_LIST'=>'Campaigns', +); + +?> diff --git a/modules/CampaignTrackers/metadata/subpanels/default.php b/modules/CampaignTrackers/metadata/subpanels/default.php new file mode 100644 index 00000000..44e086a6 --- /dev/null +++ b/modules/CampaignTrackers/metadata/subpanels/default.php @@ -0,0 +1,76 @@ + array( + array('widget_class' => 'SubPanelTopCreateButton'), + ), + + 'where' => '', + + + 'list_fields' => array( + 'tracker_name'=>array( + 'vname' => 'LBL_SUBPANEL_TRACKER_NAME', + 'widget_class' => 'SubPanelDetailViewLink', + 'width' => '20%', + ), + 'tracker_url'=>array( + 'vname' => 'LBL_SUBPANEL_TRACKER_URL', + 'width' => '60%', + ), + 'tracker_key'=>array( + 'vname' => 'LBL_SUBPANEL_TRACKER_KEY', + 'width' => '10%', + ), + 'edit_button'=>array( + 'vname' => 'LBL_EDIT_BUTTON', + 'widget_class' => 'SubPanelEditButton', + 'module' => 'Cases', + 'width' => '5%', + ), + 'remove_button'=>array( + 'vname' => 'LBL_REMOVE', + 'widget_class' => 'SubPanelRemoveButton', + 'module' => 'Cases', + 'width' => '5%', + ), + ), +); +?> \ No newline at end of file diff --git a/modules/CampaignTrackers/vardefs.php b/modules/CampaignTrackers/vardefs.php new file mode 100644 index 00000000..7627bd31 --- /dev/null +++ b/modules/CampaignTrackers/vardefs.php @@ -0,0 +1,157 @@ + 'campaign_trkrs', + 'comment' => 'Maintains the Tracker URLs used in campaign emails', + +'fields' => array ( + 'id' => array ( + 'name' => 'id', + 'vname' => 'LBL_ID', + 'type' => 'id', + 'required'=>true, + 'reportable'=>false, + 'comment' => 'Unique identifier' + ), + 'tracker_name' => array ( + 'name' => 'tracker_name', + 'vname' => 'LBL_TRACKER_NAME', + 'type' => 'varchar', + 'len' => '30', + 'comment' => 'The name of the campaign tracker' + ), + 'tracker_url' => array ( + 'name' => 'tracker_url', + 'vname' => 'LBL_TRACKER_URL', + 'type' => 'varchar', + 'len' => '255', + 'default' => 'http://', + 'comment' => 'The URL that represents the landing page when the tracker URL in the campaign email is clicked' + ), + 'tracker_key' => array ( + 'name' => 'tracker_key', + 'vname' => 'LBL_TRACKER_KEY', + 'type' => 'int', + 'len' => '11', + 'auto_increment' => true, + 'required'=>true, + 'studio' => array('editview' => false), + 'comment' => 'Internal key to uniquely identifier the tracker URL' + ), + 'campaign_id'=> array( + 'name'=>'campaign_id', + 'vname'=>'LBL_CAMPAIGN_ID', + 'type'=>'id', + 'required'=>false, + 'reportable'=>false, + 'comment' => 'The ID of the campaign' + ), + 'date_entered' => array ( + 'name' => 'date_entered', + 'vname' => 'LBL_DATE_ENTERED', + 'type' => 'datetime', + 'required' => true, + 'comment' => 'Date record created' + ), + 'date_modified' => array ( + 'name' => 'date_modified', + 'vname' => 'LBL_DATE_MODIFIED', + 'type' => 'datetime', + 'required' => true, + 'comment' => 'Date record last modified' + ), + 'modified_user_id' => array ( + 'name' => 'modified_user_id', + 'vname' => 'LBL_MODIFIED_USER_ID', + 'dbType' => 'id', + 'type'=>'id', + 'comment' => 'User who last modified record' + ), + 'created_by' => array ( + 'name' => 'created_by', + 'vname' => 'LBL_CREATED_BY', + 'type' => 'assigned_user_name', + 'table' => 'users', + 'isnull' => 'false', + 'dbType' => 'id', + 'comment' => 'User ID who created record' + ), + 'is_optout' => array ( + 'name' => 'is_optout', + 'vname' => 'LBL_OPTOUT', + 'type' => 'bool', + 'required' => true, + 'default' => '0', + 'reportable'=>false, + 'comment' => 'Indicator whether tracker URL represents an opt-out link' + ), + 'deleted' => array ( + 'name' => 'deleted', + 'vname' => 'LBL_DELETED', + 'type' => 'bool', + 'required' => false, + 'default' => '0', + 'reportable'=>false, + 'comment' => 'Record deletion indicator' + ), + 'campaign' => array ( + 'name' => 'campaign', + 'type' => 'link', + 'relationship' => 'campaign_campaigntrakers', + 'source'=>'non-db', + 'vname'=>'LBL_CAMPAIGN', + ), +), + +'relationships'=>array( + + 'campaign_campaigntrakers' => array( + 'lhs_module'=> 'Campaigns', + 'lhs_table'=> 'campaigns', + 'lhs_key' => 'id', + 'rhs_module'=> 'CampaignTrackers', + 'rhs_table'=> 'campaign_trkrs', + 'rhs_key' => 'campaign_id', + 'relationship_type'=>'one-to-many' + ) +) +,'indices' => array ( + array('name' =>'campaign_trackepk', 'type' =>'primary', 'fields'=>array('id')), + array('name' => 'campaign_tracker_key_idx', 'type'=>'index', 'fields'=>array('tracker_key')), + ) +); +?> \ No newline at end of file diff --git a/modules/Campaigns/Campaign.php b/modules/Campaigns/Campaign.php new file mode 100644 index 00000000..f511e73b --- /dev/null +++ b/modules/Campaigns/Campaign.php @@ -0,0 +1,406 @@ +'prospect_lists'); + + function Campaign() { + global $sugar_config; + parent::SugarBean(); + } + + var $new_schema = true; + + function list_view_parse_additional_sections(&$listTmpl) { + global $locale; + + // take $assigned_user_id and get the Username value to assign + $assId = $this->getFieldValue('assigned_user_id'); + + $query = "SELECT first_name, last_name FROM users WHERE id = '".$assId."'"; + $result = $this->db->query($query); + $user = $this->db->fetchByAssoc($result); + + //_ppd($user); + if(!empty($user)) { + $fullName = $locale->getLocaleFormattedName($user->first_name, $user->last_name); + $listTmpl->assign('ASSIGNED_USER_NAME', $fullName); + } + } + + + function get_summary_text() + { + return "$this->name"; + } + + function create_export_query(&$order_by, &$where, $relate_link_join='') + { + $custom_join = $this->custom_fields->getJOIN(true, true,$where); + if($custom_join) + $custom_join['join'] .= $relate_link_join; + $query = "SELECT + campaigns.*, + users.user_name as assigned_user_name "; + if($custom_join){ + $query .= $custom_join['select']; + } + $query .= " FROM campaigns "; + $query .= "LEFT JOIN users + ON campaigns.assigned_user_id=users.id"; + if($custom_join){ + $query .= $custom_join['join']; + } + + $where_auto = " campaigns.deleted=0"; + + if($where != "") + $query .= " where $where AND ".$where_auto; + else + $query .= " where ".$where_auto; + + if($order_by != "") + $query .= " ORDER BY $order_by"; + else + $query .= " ORDER BY campaigns.name"; + return $query; + } + + + + function clear_campaign_prospect_list_relationship($campaign_id, $prospect_list_id='') + { + if(!empty($prospect_list_id)) + $prospect_clause = " and prospect_list_id = '$prospect_list_id' "; + else + $prospect_clause = ''; + + $query = "DELETE FROM $this->rel_prospect_list_table WHERE campaign_id='$campaign_id' AND deleted = '0' " . $prospect_clause; + $this->db->query($query, true, "Error clearing campaign to prospect_list relationship: "); + } + + + + function mark_relationships_deleted($id) + { + $this->clear_campaign_prospect_list_relationship($id); + } + + function fill_in_additional_list_fields() + { + parent::fill_in_additional_list_fields(); + } + + function fill_in_additional_detail_fields() + { + parent::fill_in_additional_detail_fields(); + //format numbers. + + //don't need additional formatting here. + //$this->budget=format_number($this->budget); + //$this->expected_cost=format_number($this->expected_cost); + //$this->actual_cost=format_number($this->actual_cost); + //$this->expected_revenue=format_number($this->expected_revenue); + } + + + function update_currency_id($fromid, $toid){ + } + + + function get_list_view_data(){ + + $temp_array = $this->get_list_view_array(); + if ($this->campaign_type != 'Email') { + $temp_array['OPTIONAL_LINK']="display:none"; + } + $temp_array['TRACK_CAMPAIGN_TITLE'] = translate("LBL_TRACK_BUTTON_TITLE",'Campaigns'); + $temp_array['TRACK_CAMPAIGN_IMAGE'] = SugarThemeRegistry::current()->getImageURL('view_status.gif'); + $temp_array['LAUNCH_WIZARD_TITLE'] = translate("LBL_TO_WIZARD_TITLE",'Campaigns'); + $temp_array['LAUNCH_WIZARD_IMAGE'] = SugarThemeRegistry::current()->getImageURL('edit_wizard.gif'); + + return $temp_array; + } + /** + builds a generic search based on the query string using or + do not include any $this-> because this is called on without having the class instantiated + */ + function build_generic_where_clause ($the_query_string) + { + $where_clauses = Array(); + $the_query_string = $this->db->quote($the_query_string); + array_push($where_clauses, "campaigns.name like '$the_query_string%'"); + + $the_where = ""; + foreach($where_clauses as $clause) + { + if($the_where != "") $the_where .= " or "; + $the_where .= $clause; + } + + + return $the_where; + } + + function save($check_notify = FALSE) { + + //US DOLLAR + if(isset($this->amount) && !empty($this->amount)){ + + $currency = new Currency(); + $currency->retrieve($this->currency_id); + $this->amount_usdollar = $currency->convertToDollar($this->amount); + + } + + $this->unformat_all_fields(); + + return parent::save($check_notify); + + } + + function set_notification_body($xtpl, $camp) + { + $xtpl->assign("CAMPAIGN_NAME", $camp->name); + $xtpl->assign("CAMPAIGN_AMOUNT", $camp->budget); + $xtpl->assign("CAMPAIGN_CLOSEDATE", $camp->end_date); + $xtpl->assign("CAMPAIGN_STATUS", $camp->status); + $xtpl->assign("CAMPAIGN_DESCRIPTION", $camp->content); + + return $xtpl; + } + + function track_log_entries($type=array()) { + //get arguments being passed in + $args = func_get_args(); + $mkt_id =''; + + $this->load_relationship('log_entries'); + $query_array = $this->log_entries->getQuery(true); + + //if one of the arguments is marketing ID, then we need to filter by it + foreach($args as $arg){ + if(isset($arg['EMAIL_MARKETING_ID_VALUE'])){ + $mkt_id = $arg['EMAIL_MARKETING_ID_VALUE']; + } + + if(isset($arg['group_by'])) { + $query_array['group_by'] = $arg['group_by']; + } + } + + + + if (empty($type)) + $type[0]='targeted'; + + $query_array['select'] ="SELECT campaign_log.* "; + $query_array['where'] = $query_array['where']. " AND activity_type='{$type[0]}' AND archived=0"; + //add filtering by marketing id, if it exists + if (!empty($mkt_id)) $query_array['where'] = $query_array['where']. " AND marketing_id ='$mkt_id' "; + + //B.F. #37943 + if( isset($query_array['group_by']) && $this->db->dbType != 'mysql' ) + { + //perform the inner join with the group by if a marketing id is defined, which means we need to filter out duplicates. + //if no marketing id is specified then we are displaying results from multiple marketing emails and it is understood there might be duplicate target entries + if (!empty($mkt_id)){ + $group_by = str_replace("campaign_log", "cl", $query_array['group_by']); + $join_where = str_replace("campaign_log", "cl", $query_array['where']); + $query_array['from'] .= " INNER JOIN (select min(id) as id from campaign_log cl $join_where GROUP BY $group_by ) secondary + on campaign_log.id = secondary.id "; + } + unset($query_array['group_by']); + } + else if(isset($query_array['group_by'])) { + $query_array['where'] = $query_array['where'] . ' GROUP BY ' . $query_array['group_by']; + unset($query_array['group_by']); + } + + $query = (implode(" ",$query_array)); + return $query; + } + + + function get_queue_items() { + //get arguments being passed in + $args = func_get_args(); + $mkt_id =''; + + $this->load_relationship('queueitems'); + $query_array = $this->queueitems->getQuery(true); + + //if one of the arguments is marketing ID, then we need to filter by it + foreach($args as $arg){ + if(isset($arg['EMAIL_MARKETING_ID_VALUE'])){ + $mkt_id = $arg['EMAIL_MARKETING_ID_VALUE']; + } + + if(isset($arg['group_by'])) { + $query_array['group_by'] = $arg['group_by']; + } + } + + //add filtering by marketing id, if it exists, and if where key is not empty + if (!empty($mkt_id) && !empty($query_array['where'])){ + $query_array['where'] = $query_array['where']. " AND marketing_id ='$mkt_id' "; + } + + //get select query from email man + $man = new EmailMan(); + $listquery= $man->create_queue_items_query('',str_replace(array("WHERE","where"),"",$query_array['where']),null,$query_array); + return $listquery; + + } +// function get_prospect_list_entries() { +// $this->load_relationship('prospectlists'); +// $query_array = $this->prospectlists->getQuery(true); +// +// $query=<< \ No newline at end of file diff --git a/modules/Campaigns/CampaignDiagnostic.html b/modules/Campaigns/CampaignDiagnostic.html new file mode 100644 index 00000000..ed8dbbda --- /dev/null +++ b/modules/Campaigns/CampaignDiagnostic.html @@ -0,0 +1,77 @@ + +
    + + + + + + + + +
    + + +

    {$EMAIL_IMAGE}{$EMAIL_COMPONENTS}

    + +
    + + {$EMAIL_SETTINGS_CONFIGURED_MESSAGE} + {$MAILBOXES_DETECTED_MESSAGE} + +
    +

    {$EMAIL_SETUP_WIZ_LINK}

    + +

     

    +

    {$SCHEDULE_IMAGE} {$SCHEDULER_COMPONENTS}

    + +
    + + {$SCHEDULER_EMAILS_MESSAGE} + +
    +

    +

    +
    + + + + \ No newline at end of file diff --git a/modules/Campaigns/CampaignDiagnostic.php b/modules/Campaigns/CampaignDiagnostic.php new file mode 100644 index 00000000..7f47630b --- /dev/null +++ b/modules/Campaigns/CampaignDiagnostic.php @@ -0,0 +1,278 @@ +{$mod_strings['LBL_MODULE_NAME']}"; + $params[] = $mod_strings['LBL_CAMPAIGN_DIAGNOSTICS']; + + echo getClassicModuleTitle('Campaigns', $params, true); +} + +global $theme; +global $currentModule; + + + + +if(isset($_REQUEST['inline']) && $_REQUEST['inline'] == 'inline'){ + { + +} +}else{ + //use html if not inline + $ss = new Sugar_Smarty(); + $ss->assign("MOD", $mod_strings); + $ss->assign("APP", $app_strings); + if (isset($_REQUEST['return_module'])) $ss->assign("RETURN_MODULE", $_REQUEST['return_module']); + if (isset($_REQUEST['return_action'])) $ss->assign("RETURN_ACTION", $_REQUEST['return_action']); + if (isset($_REQUEST['return_id'])) $ss->assign("RETURN_ID", $_REQUEST['return_id']); + // handle Create $module then Cancel + if (empty($_REQUEST['return_id'])) { + $ss->assign("RETURN_ACTION", 'index'); + } +} + +/************ EMAIL COMPONENTS *************/ +//monitored mailbox section +$focus = new Administration(); +$focus->retrieveSettings(); //retrieve all admin settings. + + +//run query for mail boxes of type 'bounce' +$email_health = 0; +$email_components = 2; +$mbox_qry = "select * from inbound_email where deleted ='0' and mailbox_type = 'bounce'"; +$mbox_res = $focus->db->query($mbox_qry); +$mboxTable = ""; +//put all rows returned into an array +$mbox = array(); +while ($mbox_row = $focus->db->fetchByAssoc($mbox_res)){$mbox[] = $mbox_row;} + $mbox_msg = ' '; +//if the array is not empty, then set "good" message +if(isset($mbox) && count($mbox)>0){ + $mboxTable .= ""; + $mboxTable .= "" + . " " + . " " + . " " + . " "; + + foreach($mbox as $details){ + $mboxTable .= ""; + $mboxTable .= ""; + $mboxTable .= ""; + $mboxTable .= ""; + $mboxTable .= ""; + } + +}else{ + //if array is empty, then set "bad" message and increment health counter + $mboxTable .= ""; + $email_health =$email_health +1; +} + +$mboxTable.= '
    " .count($mbox) ." ". $mod_strings['LBL_MAILBOX_CHECK1_GOOD']." .
    ".$mod_strings['LBL_MAILBOX_NAME']."".$mod_strings['LBL_LOGIN']."".$mod_strings['LBL_MAILBOX']."".$mod_strings['LBL_SERVER_URL']."".$mod_strings['LBL_LIST_STATUS']."
    ".$details['name']."".$details['email_user']."".$details['mailbox']."".$details['server_url']."".$details['status']."
    ". $mod_strings['LBL_MAILBOX_CHECK1_BAD']."
    ' ; + + + +$ss->assign("MAILBOXES_DETECTED_MESSAGE", $mboxTable); + +//email settings configured +$conf_msg=""; +if (strstr($focus->settings['notify_fromaddress'], 'example.com')){ + //if from address is the default, then set "bad" message and increment health counter + $conf_msg .= ""; + $email_health =$email_health +1; +}else{ + $conf_msg .= ""; + $conf_msg .= "" + . " " + . " "; + if($focus->settings['mail_sendtype']=='SMTP'){ + $conf_msg .= " " + . " "; + + }else{$conf_msg .= "";} + + + + $conf_msg .= ""; + $conf_msg .= ""; + $conf_msg .= ""; + if($focus->settings['mail_sendtype']=='SMTP'){ + $conf_msg .= ""; + $conf_msg .= ""; + + }else{$conf_msg .= "";} + +} + +$conf_msg .= '
    ".$mod_strings['LBL_MAILBOX_CHECK2_BAD']."
    ".$mod_strings['LBL_MAILBOX_CHECK2_GOOD']."
    ".$mod_strings['LBL_WIZ_FROM_NAME']."".$mod_strings['LBL_WIZ_FROM_ADDRESS']."".$mod_strings['LBL_MAIL_SENDTYPE']."".$mod_strings['LBL_MAIL_SMTPSERVER']."".$mod_strings['LBL_MAIL_SMTPUSER']."
    ".$focus->settings['notify_fromname']."".$focus->settings['notify_fromaddress']."".$focus->settings['mail_sendtype']."".$focus->settings['mail_smtpserver']."".$focus->settings['mail_smtpuser']."
    '; +$ss->assign("EMAIL_SETTINGS_CONFIGURED_MESSAGE", $conf_msg); +$email_setup_wiz_link=''; +if ($email_health>0){ + if (is_admin($current_user)){ + $email_setup_wiz_link="".$mod_strings['LBL_EMAIL_SETUP_WIZ'].""; + }else{ + $email_setup_wiz_link=$mod_strings['LBL_NON_ADMIN_ERROR_MSG']; + } +} + +$ss->assign("EMAIL_SETUP_WIZ_LINK", $email_setup_wiz_link); +$ss->assign( 'EMAIL_IMAGE', define_image($email_health, 2)); +$ss->assign( 'EMAIL_COMPONENTS', $mod_strings['LBL_EMAIL_COMPONENTS']); +$ss->assign( 'SCHEDULER_COMPONENTS', $mod_strings['LBL_SCHEDULER_COMPONENTS']); +$ss->assign( 'RECHECK_BTN', $mod_strings['LBL_RECHECK_BTN']); + +/************* SCHEDULER COMPONENTS ************/ + +//create and run the scheduler queries +$sched_qry = "select job, name, status from schedulers where deleted = 0 and status = 'Active'"; +$sched_res = $focus->db->query($sched_qry); +$sched_health = 0; +$sched = array(); +$check_sched1 = 'function::runMassEmailCampaign'; +$check_sched2 = 'function::pollMonitoredInboxesForBouncedCampaignEmails'; +$sched_mes = ''; +$sched_mes_body = ''; + +$scheds = array(); +//build the table rows for scheduler display +while ($sched_row = $focus->db->fetchByAssoc($sched_res)){$scheds[] = $sched_row;} +foreach ($scheds as $funct){ + if( ($funct['job']==$check_sched1) || ($funct['job']==$check_sched2)){ + $sched_mes = 'use'; + $sched_mes_body .= "
    ".$funct['name']."".$funct['status']."
    "; + $sched_mes .= "" + . " "; + +}else{ + $sched_mes = "
    ".$mod_strings['LBL_SCHEDULER_NAME']."".$mod_strings['LBL_SCHEDULER_STATUS']."
    "; + $sched_mes .= ""; + $show_admin_link = true; +} + +//determine if error messages need to be displayed for schedulers +if($check_sched2 != 'found'){ + $sched_health =$sched_health +1; + $sched_mes_body .= ""; +} +if($check_sched1 != 'found'){ + $sched_health =$sched_health +1; + $sched_mes_body .= ""; +} +$admin_sched_link=''; +if ($sched_health>0){ + if (is_admin($current_user)){ + $admin_sched_link="".$mod_strings['LBL_SCHEDULER_LINK'].""; + }else{ + $admin_sched_link=$mod_strings['LBL_NON_ADMIN_ERROR_MSG']; + } +} + +//put table html together and display + $final_sched_msg = $sched_mes . $sched_mes_body . '
    ".$mod_strings['LBL_SCHEDULER_CHECK_BAD']."
    ".$mod_strings['LBL_SCHEDULER_CHECK1_BAD']."
    ".$mod_strings['LBL_SCHEDULER_CHECK2_BAD']."
    ' . $admin_sched_link; + $ss->assign("SCHEDULER_EMAILS_MESSAGE", $final_sched_msg); + $ss->assign( 'SCHEDULE_IMAGE', define_image($sched_health, 2)); + + +/********** FINAL END OF PAGE UI Stuff ********/ +if(!isset($_REQUEST['inline']) || $_REQUEST['inline'] != 'inline'){ + + $ss->display('modules/Campaigns/CampaignDiagnostic.html'); +} + +/** + * This function takes in 3 parameters and determines the appropriate image source. + * + * @param int $num parameter is the "health" parameter being tracked whenever there is something wrong. (higher number =bad) + * @param int $total Parameter is the total number things being checked. + * @return string HTML img tag + */ +function define_image($num, $total) +{ + //if health number is equal to total number then all checks failed, set red image + if($num == $total){ + //red + return " "; + }elseif($num == 0){ + //if health number is zero, then all checks passed, set green image + //green + return " "; + }else{ + //if health number is between total and num params, then some checks failed but not all, set yellow image + //yellow + return " "; + } +} + +?> diff --git a/modules/Campaigns/CaptchaValidate.php b/modules/Campaigns/CaptchaValidate.php new file mode 100644 index 00000000..5928a24e --- /dev/null +++ b/modules/Campaigns/CaptchaValidate.php @@ -0,0 +1,65 @@ +retrieveSettings('captcha'); +if($admin->settings['captcha_on']=='1' && !empty($admin->settings['captcha_private_key'])){ + $privatekey = $admin->settings['captcha_private_key']; +}else + die("Captcha settings not found"); +$response = recaptcha_check_answer($privatekey, + $_SERVER["REMOTE_ADDR"], + $_REQUEST["recaptcha_challenge_field"], + $_REQUEST["recaptcha_response_field"]); +if(!$response->is_valid){ + die("Invalid captcha entry, go back and fix. ". $response->error. " "); +} +else echo("Success"); + +?> diff --git a/modules/Campaigns/Charts.php b/modules/Campaigns/Charts.php new file mode 100644 index 00000000..9f7c00a6 --- /dev/null +++ b/modules/Campaigns/Charts.php @@ -0,0 +1,316 @@ +getXMLFileName($campaign_id); + + if (!file_exists($xmlFile) || $refresh == true) { + $GLOBALS['log']->debug("datay is:"); + $GLOBALS['log']->debug($datay); + $GLOBALS['log']->debug("user_id is: "); + $GLOBALS['log']->debug("cache_file_name is: $xmlFile"); + + $focus = new Campaign(); + + $query = "SELECT activity_type,target_type, count(*) hits "; + $query.= " FROM campaign_log "; + $query.= " WHERE campaign_id = '$campaign_id' AND archived=0 AND deleted=0"; + + //if $marketing id is specified, then lets filter the chart by the value + if (!empty($marketing_id)){ + $query.= " AND marketing_id ='$marketing_id'"; + } + + $query.= " GROUP BY activity_type, target_type"; + $query.= " ORDER BY activity_type, target_type"; + $result = $focus->db->query($query); + //$camp_data=$focus->db->fetchByAssoc($result); + $camp_data = array(); + $leadSourceArr = array(); + $total=0; + $total_targeted=0; + $rowTotalArr = array(); + $rowTotalArr[] = 0; + while($row = $focus->db->fetchByAssoc($result)) + { + if(!isset($leadSourceArr[$row['activity_type']]['row_total'])) { + $leadSourceArr[$row['activity_type']]['row_total']=0; + } + + $leadSourceArr[$row['activity_type']][$row['target_type']]['hits'][] = $row['hits']; + $leadSourceArr[$row['activity_type']][$row['target_type']]['total'][] = $row['hits']; + $leadSourceArr[$row['activity_type']]['outcome'][$row['target_type']]=$row['target_type']; + $leadSourceArr[$row['activity_type']]['row_total'] += $row['hits']; + + if (!isset($leadSourceArr['all_activities'][$row['target_type']])) { + $leadSourceArr['all_activities'][$row['target_type']]=array('total'=>0); + } + + $leadSourceArr['all_activities'][$row['target_type']]['total'] += $row['hits']; + + $total += $row['hits']; + if ($row['activity_type'] =='targeted') { + $targeted[$row['target_type']]=$row['hits']; + $total_targeted+=$row['hits']; + } + } + + foreach ($datay as $key=>$translation) { + if ($key == '') { + //$key = $mod_strings['NTC_NO_LEGENDS']; + $key = 'None'; + $translation = $mod_strings['NTC_NO_LEGENDS']; + } + if(!isset($leadSourceArr[$key])){ + $leadSourceArr[$key] = $key; + } + + + if(is_array($leadSourceArr[$key]) && isset($leadSourceArr[$key]['row_total'])){$rowTotalArr[]=$leadSourceArr[$key]['row_total'];} + if(is_array($leadSourceArr[$key]) && isset($leadSourceArr[$key]['row_total']) && $leadSourceArr[$key]['row_total']>100){ + $leadSourceArr[$key]['row_total'] = round($leadSourceArr[$key]['row_total']); + } + $camp_data[$translation] = array(); + foreach ($targets as $outcome=>$outcome_translation){ + //create alternate text. + $alttext = ' '; + if(isset($targeted) && isset($targeted[$outcome])&& !empty($targeted[$outcome])){ + $alttext=$targets[$outcome].': '.$mod_strings['LBL_TARGETED'].' '.$targeted[$outcome]. ', '.$mod_strings['LBL_TOTAL_TARGETED'].' '. $total_targeted. "."; + } + if ($key != 'targeted'){ + $hits = (isset($leadSourceArr[$key][$outcome]) && is_array($leadSourceArr[$key][$outcome]) && is_array($leadSourceArr[$key][$outcome]['hits'])) ? array_sum($leadSourceArr[$key][$outcome]['hits']) : 0; + $alttext.=" $translation ".$hits; + } + $count = (isset($leadSourceArr[$key][$outcome]) && is_array($leadSourceArr[$key][$outcome]) && is_array($leadSourceArr[$key][$outcome]['total'])) ? array_sum($leadSourceArr[$key][$outcome]['total']) : 0; + $camp_data[$translation][$outcome] = + array( + "numerical_value" => $count, + "group_text" => $translation, + "group_key" => "", + "count" => "{$count}", + "group_label" => $alttext, + "numerical_label" => "Hits", + "numerical_key" => "hits", + "module" => 'Campaigns', + "group_base_text" => $outcome, + "link" => $key + ); + } + + } + + + if($camp_data) + $sugarChart->setData($camp_data); + else + $sugarChart->setData(array()); + + $sugarChart->setProperties($mod_strings['LBL_CAMPAIGN_RESPONSE_BY_RECIPIENT_ACTIVITY'], "", 'horizontal group by chart'); + $sugarChart->saveXMLFile($xmlFile, $sugarChart->generateXML()); + } + + $width = '100%'; + $return = ''; + $return .= $sugarChart->display($campaign_id, $xmlFile, $width, '480',""); + + return $return; + } + + //campaign roi compputations + function campaign_response_roi($datay= array(),$targets=array(),$campaign_id, $cache_file_name='a_file', $refresh=false,$marketing_id='',$is_dashlet=false,$dashlet_id='') { + global $app_strings,$mod_strings, $current_module_strings, $charset, $lang, $app_list_strings, $current_language,$sugar_config; + + $not_empty = false; + + if ($is_dashlet){ + $mod_strings = return_module_language($current_language, 'Campaigns'); + } + + if (!file_exists($cache_file_name) || $refresh == true) { + $GLOBALS['log']->debug("datay is:"); + $GLOBALS['log']->debug($datay); + $GLOBALS['log']->debug("user_id is: "); + $GLOBALS['log']->debug("cache_file_name is: $cache_file_name"); + + $focus = new Campaign(); + $focus->retrieve($campaign_id); + $opp_count=0; + $opp_query = "select count(*) opp_count,sum(" . db_convert("amount_usdollar","IFNULL",array(0)).") total_value"; + $opp_query .= " from opportunities"; + $opp_query .= " where campaign_id='$campaign_id'"; + $opp_query .= " and sales_stage='Prospecting'"; + $opp_query .= " and deleted=0"; + + $opp_result=$focus->db->query($opp_query); + $opp_data=$focus->db->fetchByAssoc($opp_result); +// if (empty($opp_data['opp_count'])) $opp_data['opp_count']=0; + if (empty($opp_data['total_value'])) $opp_data['total_value']=0; + + //report query + $opp_query1 = "select SUM(opp.amount) as revenue"; + $opp_query1 .= " from opportunities opp"; + $opp_query1 .= " right join campaigns camp on camp.id = opp.campaign_id"; + $opp_query1 .= " where opp.sales_stage = 'Closed Won'and camp.id='$campaign_id' and opp.deleted=0"; + $opp_query1 .= " group by camp.name"; + + $opp_result1=$focus->db->query($opp_query1); + $opp_data1=$focus->db->fetchByAssoc($opp_result1); + + //if (empty($opp_data1[])) + if (empty($opp_data1['revenue'])){ + $opp_data1[$mod_strings['LBL_ROI_CHART_REVENUE']] = 0; + unset($opp_data1['revenue']); + }else{ + $opp_data1[$mod_strings['LBL_ROI_CHART_REVENUE']] = $opp_data1['revenue']; + unset($opp_data1['revenue']); + $not_empty = true; + } + + $camp_query1 = "select camp.name, SUM(camp.actual_cost) as investment,SUM(camp.budget) as budget,SUM(camp.expected_revenue) as expected_revenue"; + $camp_query1 .= " from campaigns camp"; + $camp_query1 .= " where camp.id='$campaign_id'"; + $camp_query1 .= " group by camp.name"; + + $camp_result1=$focus->db->query($camp_query1); + $camp_data1=$focus->db->fetchByAssoc($camp_result1); + //query needs to be lowercase, but array keys need to be propercased, as these are used in + //chart to display legend + + if (empty($camp_data1['investment'])) + $camp_data1['investment'] = 0; + else + $not_empty = true; + if (empty($camp_data1['budget'])) + $camp_data1['budget'] = 0; + else + $not_empty = true; + if (empty($camp_data1['expected_revenue'])) + $camp_data1['expected_revenue'] = 0; + else + $not_empty = true; + + $opp_data1[$mod_strings['LBL_ROI_CHART_INVESTMENT']]=$camp_data1['investment']; + $opp_data1[$mod_strings['LBL_ROI_CHART_BUDGET']]=$camp_data1['budget']; + $opp_data1[$mod_strings['LBL_ROI_CHART_EXPECTED_REVENUE']]=$camp_data1['expected_revenue']; + + + $query = "SELECT activity_type,target_type, count(*) hits "; + $query.= " FROM campaign_log "; + $query.= " WHERE campaign_id = '$campaign_id' AND archived=0 AND deleted=0"; + //if $marketing id is specified, then lets filter the chart by the value + if (!empty($marketing_id)){ + $query.= " AND marketing_id ='$marketing_id'"; + } + $query.= " GROUP BY activity_type, target_type"; + $query.= " ORDER BY activity_type, target_type"; + $result = $focus->db->query($query); + + $leadSourceArr = array(); + $total=0; + $total_targeted=0; + + } + + global $current_user; + $user_id = $current_user->id; + + + $width = '100%'; + + $return = ''; + if (!$is_dashlet){ + $return .= '
    '; + } + + + $currency_id = $focus->currency_id; + $currency_symbol = $sugar_config['default_currency_symbol']; + if(!empty($currency_id)){ + + $cur = new Currency(); + $cur->retrieve($currency_id); + $currency_symbol = $cur->symbol; + } + + + $sugarChart = SugarChartFactory::getInstance(); + $sugarChart->is_currency = true; + $sugarChart->currency_symbol = $currency_symbol; + + if ($not_empty) + $sugarChart->setData($opp_data1); + else + $sugarChart->setData(array()); + $sugarChart->setProperties($mod_strings['LBL_CAMPAIGN_RETURN_ON_INVESTMENT'], $mod_strings['LBL_AMOUNT_IN'].$currency_symbol, 'bar chart'); + + if (!$is_dashlet){ + $xmlFile = $sugarChart->getXMLFileName('roi_details_chart'); + $sugarChart->saveXMLFile($xmlFile, $sugarChart->generateXML()); + $return .= $sugarChart->display('roi_details_chart', $xmlFile, $width, '480'); + } + else{ + $xmlFile = $sugarChart->getXMLFileName($dashlet_id); + $sugarChart->saveXMLFile($xmlFile, $sugarChart->generateXML()); + $return .= $sugarChart->display($dashlet_id, $xmlFile, $width, '480'); + } + + return $return; + } +}// end charts class +?> \ No newline at end of file diff --git a/modules/Campaigns/Charts1.php b/modules/Campaigns/Charts1.php new file mode 100644 index 00000000..02b32bc2 --- /dev/null +++ b/modules/Campaigns/Charts1.php @@ -0,0 +1,106 @@ +db->query($query); + while($row = $focus->db->fetchByAssoc($result, -1, false)) { + + if (isset($leadSourceArr[$row['activity_type']]['value'])) { + $leadSourceArr[$row['activity_type']]['value']=0; + } + + $leadSourceArr[$row['activity_type']]['value']= $leadSourceArr[$row['activity_type']]['value'] + $row['hits']; + + if (!empty($row['target_type'])) { + $leadSourceArr[$row['activity_type']]['bars'][$row['target_type']]['value']=$row['hits']; + } + } + + foreach ($targets as $key=>$value) { + if (!isset($leadSourceArr[$key])) { + $leadSourceArr[$key]['value']=0; + } + } + + //use the new template. + $xtpl=new XTemplate ('modules/Campaigns/chart.tpl'); + $xtpl->assign("GRAPHTITLE",'Campaign Response by Recipient Activity'); + $xtpl->assign("Y_DEFAULT_ALT_TEXT",'Rollover a bar to view details.'); + + //process rows + foreach ($leadSourceArr as $key=>$values) { + if (isset($values['bars'])) { + foreach ($values['bars'] as $bar_id=>$bar_value) { + $xtpl->assign("Y_BAR_ID",$bar_id); + } + } + + } + } + }// end charts class +?> + \ No newline at end of file diff --git a/modules/Campaigns/Dashlets/TopCampaignsDashlet/TopCampaignsDashlet.meta.php b/modules/Campaigns/Dashlets/TopCampaignsDashlet/TopCampaignsDashlet.meta.php new file mode 100644 index 00000000..2b9e087d --- /dev/null +++ b/modules/Campaigns/Dashlets/TopCampaignsDashlet/TopCampaignsDashlet.meta.php @@ -0,0 +1,47 @@ + 'Campaigns', + 'title' => translate('LBL_TOP_CAMPAIGNS', 'Campaigns'), + 'description' => 'Top Performing Campaigns by Revenue', + 'category' => 'Module Views'); +?> diff --git a/modules/Campaigns/Dashlets/TopCampaignsDashlet/TopCampaignsDashlet.php b/modules/Campaigns/Dashlets/TopCampaignsDashlet/TopCampaignsDashlet.php new file mode 100644 index 00000000..dc9d44b3 --- /dev/null +++ b/modules/Campaigns/Dashlets/TopCampaignsDashlet/TopCampaignsDashlet.php @@ -0,0 +1,132 @@ +isConfigurable = true; + $this->isRefreshable = true; + + if(empty($def['title'])) { + $this->title = translate('LBL_TOP_CAMPAIGNS', 'Campaigns'); + } + else { + $this->title = $def['title']; + } + + if(isset($def['autoRefresh'])) $this->autoRefresh = $def['autoRefresh']; + + $this->seedBean = new Opportunity(); + + $qry = "SELECT C.name AS campaign_name, SUM(O.amount) AS revenue, C.id as campaign_id " . + "FROM campaigns C, opportunities O " . + "WHERE C.id = O.campaign_id " . + "AND O.sales_stage = 'Closed Won' " . + "GROUP BY C.name,C.id ORDER BY revenue desc"; + + $result = $this->seedBean->db->limitQuery($qry, 0, 10); + $row = $this->seedBean->db->fetchByAssoc($result); + + while ($row != null){ + array_push($this->top_campaigns, $row); + $row = $this->seedBean->db->fetchByAssoc($result); + } + } + + /** + * @see Dashlet::display() + */ + public function display() + { + $ss = new Sugar_Smarty(); + $ss->assign('lbl_campaign_name', translate('LBL_TOP_CAMPAIGNS_NAME', 'Campaigns')); + $ss->assign('lbl_revenue', translate('LBL_TOP_CAMPAIGNS_REVENUE', 'Campaigns')); + $ss->assign('top_campaigns', $this->top_campaigns); + + return parent::display() . $ss->fetch('modules/Campaigns/Dashlets/TopCampaignsDashlet/TopCampaignsDashlet.tpl'); + } + + /** + * @see Dashlet::displayOptions() + */ + public function displayOptions() + { + $ss = new Sugar_Smarty(); + $ss->assign('titleLBL', translate('LBL_DASHLET_OPT_TITLE', 'Home')); + $ss->assign('title', $this->title); + $ss->assign('id', $this->id); + $ss->assign('saveLBL', $GLOBALS['app_strings']['LBL_SAVE_BUTTON_LABEL']); + if($this->isAutoRefreshable()) { + $ss->assign('isRefreshable', true); + $ss->assign('autoRefresh', $GLOBALS['app_strings']['LBL_DASHLET_CONFIGURE_AUTOREFRESH']); + $ss->assign('autoRefreshOptions', $this->getAutoRefreshOptions()); + $ss->assign('autoRefreshSelect', $this->autoRefresh); + } + + return $ss->fetch('modules/Opportunities/Dashlets/MyClosedOpportunitiesDashlet/MyClosedOpportunitiesDashletConfigure.tpl'); + } + + /** + * @see Dashlet::saveOptions() + */ + public function saveOptions($req) + { + $options = array(); + + if ( isset($req['title']) ) { + $options['title'] = $req['title']; + } + $options['autoRefresh'] = empty($req['autoRefresh']) ? '0' : $req['autoRefresh']; + + return $options; + } +} diff --git a/modules/Campaigns/Dashlets/TopCampaignsDashlet/TopCampaignsDashlet.tpl b/modules/Campaigns/Dashlets/TopCampaignsDashlet/TopCampaignsDashlet.tpl new file mode 100644 index 00000000..d315452f --- /dev/null +++ b/modules/Campaigns/Dashlets/TopCampaignsDashlet/TopCampaignsDashlet.tpl @@ -0,0 +1,59 @@ +{* + +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + + + +*} + + + + + + {counter name="num" assign="num"} + {foreach from=$top_campaigns item="campaign"} + + + + + + {counter name="num"} + {/foreach} +
      + {$lbl_campaign_name} + {$lbl_revenue} +
    {$num}.{$campaign.campaign_name}{$campaign.revenue}
    diff --git a/modules/Campaigns/Dashlets/TopCampaignsDashlet/TopCampaignsDashletConfigure.tpl b/modules/Campaigns/Dashlets/TopCampaignsDashlet/TopCampaignsDashletConfigure.tpl new file mode 100644 index 00000000..be180402 --- /dev/null +++ b/modules/Campaigns/Dashlets/TopCampaignsDashlet/TopCampaignsDashletConfigure.tpl @@ -0,0 +1,74 @@ +{* + +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} + + +
    +
    + + + + + + + + + + +{if $isRefreshable} + + + + +{/if} + + + +
    {$titleLBL} + +
    + {$autoRefresh} + + +
    + +
    +
    +
    \ No newline at end of file diff --git a/modules/Campaigns/Delete.php b/modules/Campaigns/Delete.php new file mode 100644 index 00000000..8ae33de0 --- /dev/null +++ b/modules/Campaigns/Delete.php @@ -0,0 +1,116 @@ +retrieve($_REQUEST['record']); + +if (isset($_REQUEST['mode']) and $_REQUEST['mode']=='Test') { + //deletes all data associated with the test run. + + //delete from emails table. + if ($focus->db->dbType=='mysql') { + + $query="update emails "; + $query.="inner join campaign_log on campaign_log.related_id = emails.id and campaign_log.campaign_id = '{$focus->id}' "; + $query.="inner join prospect_lists on campaign_log.list_id = prospect_lists.id and prospect_lists.list_type='test' "; + $query.="set emails.deleted=1 "; + } elseif ($focus->db->dbType=='mssql') { + $query="update emails "; + $query.="set emails.deleted=1 "; + $query.="where id in ( "; + $query.="select related_id from campaign_log "; + $query.="inner join prospect_lists on campaign_log.list_id = prospect_lists.id "; + $query.="and prospect_lists.list_type='test' "; + $query.="and campaign_log.campaign_id = '{$focus->id}' ) "; + } else { + } + $focus->db->query($query); + + //delete from message queue. + if ($focus->db->dbType=='mysql') { + $query="delete emailman.* from emailman "; + $query.="inner join prospect_lists on emailman.list_id = prospect_lists.id and prospect_lists.list_type='test' "; + $query.="WHERE emailman.campaign_id = '{$focus->id}' "; + } elseif ($focus->db->dbType=='mssql') { + $query="delete from emailman "; + $query.="where list_id in ( "; + $query.=" select prospect_list_id from prospect_list_campaigns "; + $query.=" inner join prospect_lists on prospect_list_campaigns.prospect_list_id = prospect_lists.id "; + $query.=" where prospect_lists.list_type='test' and prospect_list_campaigns.campaign_id = '{$focus->id}' ) "; + } else { + } + $focus->db->query($query); + + //delete from campaign_log + if ($focus->db->dbType=='mysql') { + $query="update campaign_log "; + $query.="inner join prospect_lists on campaign_log.list_id = prospect_lists.id and prospect_lists.list_type='test' "; + $query.="set campaign_log.deleted=1 "; + $query.="where campaign_log.campaign_id='{$focus->id}' "; + } elseif ($focus->db->dbType=='mssql') { + $query="update campaign_log "; + $query.="set campaign_log.deleted=1 "; + $query.="where list_id in ( "; + $query.=" select id from prospect_lists "; + $query.=" where prospect_lists.list_type='test') "; + $query.="and campaign_log.campaign_id='{$focus->id}' "; + } else { + } + $focus->db->query($query); +} else { + if(!$focus->ACLAccess('Delete')){ + ACLController::displayNoAccess(true); + sugar_cleanup(true); + } + $focus->mark_deleted($_REQUEST['record']); +} +$return_id=!empty($_REQUEST['return_id'])?$_REQUEST['return_id']:$focus->id; +header("Location: index.php?module=".$_REQUEST['return_module']."&action=".$_REQUEST['return_action']."&record=".$return_id); +?> diff --git a/modules/Campaigns/DetailView.js b/modules/Campaigns/DetailView.js new file mode 100644 index 00000000..395b6f95 --- /dev/null +++ b/modules/Campaigns/DetailView.js @@ -0,0 +1,41 @@ +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ +function set_return_prospect_list_and_save(popup_reply_data) +{var form_name=popup_reply_data.form_name;var name_to_value_array=popup_reply_data.name_to_value_array;for(var the_key in name_to_value_array) +{if(the_key=='toJSON') +{} +else +{window.document.forms[form_name].elements[the_key].value=name_to_value_array[the_key];}} +window.document.forms[form_name].module.value='Campaigns';window.document.forms[form_name].return_module.value=window.document.forms[form_name].module.value;window.document.forms[form_name].return_action.value='DetailView';window.document.forms[form_name].return_id.value=window.document.forms[form_name].record.value;window.document.forms[form_name].action.value='SaveCampaignProspectListRelationship';window.document.forms[form_name].submit();} \ No newline at end of file diff --git a/modules/Campaigns/EmailQueue.php b/modules/Campaigns/EmailQueue.php new file mode 100644 index 00000000..83ead4f6 --- /dev/null +++ b/modules/Campaigns/EmailQueue.php @@ -0,0 +1,125 @@ +retrieve($_REQUEST['record']); + +$query = "SELECT prospect_list_id as id FROM prospect_list_campaigns WHERE campaign_id='$campaign->id' AND deleted=0"; + +$fromName = $_REQUEST['from_name']; +$fromEmail = $_REQUEST['from_address']; +$date_start = $_REQUEST['date_start']; +$time_start = $_REQUEST['time_start']; +$template_id = $_REQUEST['email_template']; + +$dateval = $timedate->merge_date_time($date_start, $time_start); + + +$listresult = $campaign->db->query($query); + +while($list = $campaign->db->fetchByAssoc($listresult)) +{ + $prospect_list = $list['id']; + $focus = new ProspectList(); + + $focus->retrieve($prospect_list); + + $query = "SELECT prospect_id,contact_id,lead_id FROM prospect_lists_prospects WHERE prospect_list_id='$focus->id' AND deleted=0"; + $result = $focus->db->query($query); + + while($row = $focus->db->fetchByAssoc($result)) + { + $prospect_id = $row['prospect_id']; + $contact_id = $row['contact_id']; + $lead_id = $row['lead_id']; + + if($prospect_id <> '') + { + $moduleName = "Prospects"; + $moduleID = $row['prospect_id']; + } + if($contact_id <> '') + { + $moduleName = "Contacts"; + $moduleID = $row['contact_id']; + } + if($lead_id <> '') + { + $moduleName = "Leads"; + $moduleID = $row['lead_id']; + } + + $mailer = new EmailMan(); + $mailer->module = $moduleName; + $mailer->module_id = $moduleID; + $mailer->user_id = $current_user->id; + $mailer->list_id = $prospect_list; + $mailer->template_id = $template_id; + $mailer->from_name = $fromName; + $mailer->from_email = $fromEmail; + $mailer->send_date_time = $dateval; + $mailer->save(); + } + + +} + + +$header_URL = "Location: index.php?action=DetailView&module=Campaigns&record={$_REQUEST['record']}"; +$GLOBALS['log']->debug("about to post header URL of: $header_URL"); + +header($header_URL); +?> + diff --git a/modules/Campaigns/GenerateWebToLeadForm.php b/modules/Campaigns/GenerateWebToLeadForm.php new file mode 100644 index 00000000..85aced5a --- /dev/null +++ b/modules/Campaigns/GenerateWebToLeadForm.php @@ -0,0 +1,580 @@ +assign("MOD", $mod_strings); + $xtpl->assign("APP", $app_strings); + $Web_To_Lead_Form_html = ''; + $Web_To_Lead_Form_html .=''; + $Web_To_Lead_Form_html .= ""; + $Web_To_Lead_Form_html .= ''; + $Web_To_Lead_Form_html .="
    "; + $Web_To_Lead_Form_html .= ""; + +$Web_To_Lead_Form_html .= ""; +$Web_To_Lead_Form_html .= ""; +$Web_To_Lead_Form_html .= ""; +$Web_To_Lead_Form_html .= ""; + + //$Web_To_Lead_Form_html .= "\n

    \n"; + +if(!empty($_REQUEST['colsFirst']) && !empty($_REQUEST['colsSecond'])){ + if(count($_REQUEST['colsFirst']) < count($_REQUEST['colsSecond'])){ + $columns= count($_REQUEST['colsSecond']); + } + if(count($_REQUEST['colsFirst']) > count($_REQUEST['colsSecond']) || count($_REQUEST['colsFirst']) == count($_REQUEST['colsSecond'])){ + $columns= count($_REQUEST['colsFirst']); + } +} +else if(!empty($_REQUEST['colsFirst'])){ + $columns= count($_REQUEST['colsFirst']); +} +else if(!empty($_REQUEST['colsSecond'])){ + $columns= count($_REQUEST['colsSecond']); +} + + +$required_fields = array(); +$bool_fields = array(); +for($i= 0; $i<$columns;$i++){ + $colsFirstField = ''; + $colsSecondField = ''; + + if(!empty($_REQUEST['colsFirst'][$i])){ + $colsFirstField = $_REQUEST['colsFirst'][$i]; + //_pp($_REQUEST['colsFirst']); + } + if(!empty($_REQUEST['colsSecond'][$i])){ + $colsSecondField = $_REQUEST['colsSecond'][$i]; + //_pp($_REQUEST['colsSecond']); + } + + if(isset($lead->field_defs[$colsFirstField]) && $lead->field_defs[$colsFirstField] != null) + { + $field_vname = preg_replace('/:$/','',translate($lead->field_defs[$colsFirstField]['vname'],'Leads')); + $field_name = $colsFirstField; + $field_label = $field_vname .": "; + if(isset($lead->field_defs[$colsFirstField]['custom_type']) && $lead->field_defs[$colsFirstField]['custom_type'] != null){ + $field_type= $lead->field_defs[$colsFirstField]['custom_type']; + } + else{ + $field_type= $lead->field_defs[$colsFirstField]['type']; + } + $field_required = ''; + if(isset($lead->field_defs[$colsFirstField]['required']) && $lead->field_defs[$colsFirstField]['required'] != null + && $lead->field_defs[$colsFirstField]['required'] != 0) + { + $field_required = $lead->field_defs[$colsFirstField]['required']; + if (! in_array($lead->field_defs[$colsFirstField]['name'], $required_fields)){ + array_push($required_fields,$lead->field_defs[$colsFirstField]['name']); + } + } + if($lead->field_defs[$colsFirstField]['name']=='last_name'){ + if (! in_array($lead->field_defs[$colsFirstField]['name'], $required_fields)){ + array_push($required_fields,$lead->field_defs[$colsFirstField]['name']); + } + } + if($field_type=='multienum' || $field_type=='enum' || $field_type=='radioenum') $field_options= $lead->field_defs[$colsFirstField]['options']; + } + //preg_replace('/:$/','',translate($field_def['vname'],'Leads') + if(isset($lead->field_defs[$colsSecondField]) && $lead->field_defs[$colsSecondField] != null) + { + $field1_vname= preg_replace('/:$/','',translate($lead->field_defs[$colsSecondField]['vname'],'Leads')); + $field1_name= $colsSecondField; + $field1_label = $field1_vname .": "; + if(isset($lead->field_defs[$colsSecondField]['custom_type']) && $lead->field_defs[$colsSecondField]['custom_type'] != null){ + $field1_type= $lead->field_defs[$colsSecondField]['custom_type']; + } + else{ + $field1_type= $lead->field_defs[$colsSecondField]['type']; + } + $field1_required = ''; + if(isset($lead->field_defs[$colsSecondField]['required']) && $lead->field_defs[$colsSecondField]['required'] != null + && $lead->field_defs[$colsSecondField]['required'] != 0){ + $field1_required = $lead->field_defs[$colsSecondField]['required']; + if (! in_array($lead->field_defs[$colsSecondField]['name'], $required_fields)){ + array_push($required_fields,$lead->field_defs[$colsSecondField]['name']); + } + } + if($lead->field_defs[$colsSecondField]['name']=='last_name'){ + if (! in_array($lead->field_defs[$colsSecondField]['name'], $required_fields)){ + array_push($required_fields,$lead->field_defs[$colsSecondField]['name']); + } + } + if($field1_type=='multienum' || $field1_type=='enum' || $field1_type=='radioenum') $field1_options= $lead->field_defs[$colsSecondField]['options']; + } + + $Web_To_Lead_Form_html .= "

    "; + + if(isset($lead->field_defs[$colsFirstField]) && $lead->field_defs[$colsFirstField] != null){ + if($field_type=='multienum' || $field_type=='enum' || $field_type=='radioenum'){ + $lead_options = ''; + if(!empty($lead->$field_name)){ + $lead_options= get_select_options_with_id($app_list_strings[$field_options], unencodeMultienum($lead->$field_name)); + } + else{ + $lead_options= get_select_options_with_id($app_list_strings[$field_options], ''); + } + if($field_required){ + $Web_To_Lead_Form_html .= ""; + } + else{ + $Web_To_Lead_Form_html .= ""; + } + if(isset($lead->field_defs[$colsFirstField]['isMultiSelect']) && $lead->field_defs[$colsFirstField]['isMultiSelect'] ==1){ + $Web_To_Lead_Form_html .= ""; + }elseif(ifRadioButton($lead->field_defs[$colsFirstField]['name'])){ + $Web_To_Lead_Form_html .=""; + }else{ + $Web_To_Lead_Form_html .= ""; + } + } + if($field_type=='bool'){ + if($field_required){ + $Web_To_Lead_Form_html .= ""; + } + else{ + $Web_To_Lead_Form_html .= ""; + } + $Web_To_Lead_Form_html .= ""; + if (! in_array($lead->field_defs[$colsFirstField]['name'], $bool_fields)){ + array_push($bool_fields,$lead->field_defs[$colsFirstField]['name']); + } + } + if($field_type=='date') { + global $timedate; + + + $cal_dateformat = $timedate->get_cal_date_format(); + $LBL_ENTER_DATE = translate('LBL_ENTER_DATE', 'Charts'); + if($field_required){ + $Web_To_Lead_Form_html .= ""; + } + else{ + $Web_To_Lead_Form_html .= ""; + } + $Web_To_Lead_Form_html .= ""; + //$Web_To_Lead_Form_html .= ""; + } // if + if( $field_type=='varchar' || $field_type=='name' + || $field_type=='phone' || $field_type=='currency' || $field_type=='url' || $field_type=='int'){ + if($field_name=='last_name' || $field_required){ + $Web_To_Lead_Form_html .= ""; + } + else{ + $Web_To_Lead_Form_html .= ""; + } + $Web_To_Lead_Form_html .= ""; + } + if ( $field_type == 'text' ) { + $Web_To_Lead_Form_html .= ""; + $Web_To_Lead_Form_html .= ""; + } + if($field_type=='relate' && $field_name=='account_name'){ + $Web_To_Lead_Form_html .= ""; + $Web_To_Lead_Form_html .= ""; + } + if($field_type=='email'){ + if($field_required){ + $Web_To_Lead_Form_html .= ""; + } + else{ + $Web_To_Lead_Form_html .= ""; + } + $Web_To_Lead_Form_html .= ""; + } + } + else{ + $Web_To_Lead_Form_html .= ""; + $Web_To_Lead_Form_html .= ""; + } + + if(isset($lead->field_defs[$colsSecondField]) && $lead->field_defs[$colsSecondField] != null){ + if($field1_type=='multienum' || $field1_type=='enum' || $field1_type=='radioenum'){ + $lead1_options = ''; + if(!empty($lead->$field1_name)){ + $lead1_options= get_select_options_with_id($app_list_strings[$field1_options], unencodeMultienum($lead->$field1_name)); + } + else{ + $lead1_options= get_select_options_with_id($app_list_strings[$field1_options], ''); + } + if($field1_required){ + $Web_To_Lead_Form_html .= ""; + } + else{ + $Web_To_Lead_Form_html .= ""; + } + if(isset($lead->field_defs[$colsSecondField]['isMultiSelect']) && $lead->field_defs[$colsSecondField]['isMultiSelect'] ==1){ + $Web_To_Lead_Form_html .= ""; + }elseif(ifRadioButton($lead->field_defs[$colsSecondField]['name'])){ + $Web_To_Lead_Form_html .=""; + }else{ + $Web_To_Lead_Form_html .= ""; + } + } + if($field1_type=='bool'){ + if($field1_required){ + $Web_To_Lead_Form_html .= ""; + } + else{ + $Web_To_Lead_Form_html .= ""; + } + $Web_To_Lead_Form_html .= ""; + if (! in_array($lead->field_defs[$colsSecondField]['name'], $bool_fields)){ + array_push($bool_fields,$lead->field_defs[$colsSecondField]['name']); + } + } + if($field1_type=='date') { + global $timedate; + $cal_dateformat = $timedate->get_cal_date_format(); + $LBL_ENTER_DATE = translate('LBL_ENTER_DATE', 'Charts'); + if($field1_required){ + $Web_To_Lead_Form_html .= ""; + } + else{ + $Web_To_Lead_Form_html .= ""; + } + $Web_To_Lead_Form_html .= " + "; + } // if + if( $field1_type=='varchar' || $field1_type=='name' + || $field1_type=='phone' || $field1_type=='currency' || $field1_type=='url' || $field1_type=='int'){ + if($field1_name=='last_name' || $field1_required){ + $Web_To_Lead_Form_html .= ""; + } + else{ + $Web_To_Lead_Form_html .= ""; + } + $Web_To_Lead_Form_html .= ""; + } + if ( $field1_type == 'text' ) { + $Web_To_Lead_Form_html .= ""; + $Web_To_Lead_Form_html .= ""; + } + if($field1_type=='relate' && $field1_name=='account_name'){ + $Web_To_Lead_Form_html .= ""; + $Web_To_Lead_Form_html .= ""; + } + if($field1_type=='email'){ + if($field1_required){ + $Web_To_Lead_Form_html .= ""; + } + else{ + $Web_To_Lead_Form_html .= ""; + } + $Web_To_Lead_Form_html .= ""; + } + } + else{ + $Web_To_Lead_Form_html .= ""; + $Web_To_Lead_Form_html .= ""; + } + $Web_To_Lead_Form_html .= ""; +} + +$Web_To_Lead_Form_html .= ""; + +if(!empty($web_form_footer)){ + $Web_To_Lead_Form_html .= ""; + $Web_To_Lead_Form_html .= ""; +} + +$Web_To_Lead_Form_html .= ""; + +if(!empty($web_form_campaign)){ + $Web_To_Lead_Form_html .= ""; +} +if(!empty($web_redirect_url)){ + $Web_To_Lead_Form_html .= ""; +} +if(!empty($web_assigned_user)){ + $Web_To_Lead_Form_html .= ""; +} +$req_fields=''; +if(isset($required_fields) && $required_fields != null ){ + foreach($required_fields as $req){ + $req_fields=$req_fields.$req.';'; + } +} +$boolean_fields=''; +if(isset($bool_fields) && $bool_fields != null ){ + foreach($bool_fields as $boo){ + $boolean_fields=$boolean_fields.$boo.';'; + } +} +if(!empty($req_fields)){ + $Web_To_Lead_Form_html .= ""; +} +if(!empty($boolean_fields)){ + $Web_To_Lead_Form_html .= ""; +} + + +$Web_To_Lead_Form_html .= "

    $web_form_header

     
    $web_form_description
     
    $field_label$web_required_symbol$field_label"; + foreach($app_list_strings[$field_options] as $field_option_key => $field_option){ + if($field_option != null){ + if(!empty($lead->$field_name) && in_array($field_option_key,unencodeMultienum($lead->$field_name))){ + $Web_To_Lead_Form_html .=""; + } else{ + $Web_To_Lead_Form_html .=""; + } + $Web_To_Lead_Form_html .="field_defs[$colsFirstField]."_$field_option_key').checked =true style='cursor:default'; onmousedown='return false;'>$field_option
    "; + } + } + $Web_To_Lead_Form_html .="
    $field_label$web_required_symbol$field_label$field_label$web_required_symbol$field_label +getImageURL('jscalendar.gif')."\" alt=\"{$LBL_ENTER_DATE}\" id=\"{$field_name}_trigger\" align=\"absmiddle\"> +$field_label$web_required_symbol$field_label$field_label$field_label$field_label$web_required_symbol$field_label  $field1_label$web_required_symbol$field1_label"; + foreach($app_list_strings[$field1_options] as $field_option_key => $field_option){ + if($field_option != null){ + if(!empty($lead->$field1_name) && in_array($field_option_key,unencodeMultienum($lead->$field1_name))){ + $Web_To_Lead_Form_html .=""; + }else{ + $Web_To_Lead_Form_html .=""; + } + $Web_To_Lead_Form_html .="field_defs[$colsSecondField]."_$field_option_key').checked =true style='cursor:default'; onmousedown='return false;'>$field_option
    "; + } + } + $Web_To_Lead_Form_html .="
    $field1_label$web_required_symbol$field1_label$field1_label$web_required_symbol$field1_label + + "; + $order = explode("%", $cal_dateformat); + foreach($order as $part) + { + if (!isset($part[0])) + continue; + if (strToUpper($part[0]) == "M" ) + $Web_To_Lead_Form_html .= translate("LBL_MONTH") . ":"; + else if (strToUpper($part[0]) == "D" ) + $Web_To_Lead_Form_html .= translate("LBL_DAY") . ":"; + else if (strToUpper($part[0]) == "Y" ) + $Web_To_Lead_Form_html .= translate("LBL_YEAR") . ":"; + } + $Web_To_Lead_Form_html .= "$field1_label$web_required_symbol$field1_label$field1_label$field1_label$field1_label$web_required_symbol$field1_label  
     
     
    $web_form_footer
    "; +$Web_To_Lead_Form_html .="
    "; + +$Web_To_Lead_Form_html .=""; + +if(isset($Web_To_Lead_Form_html)) $xtpl->assign("BODY", $Web_To_Lead_Form_html); else $xtpl->assign("BODY", ""); +if(isset($Web_To_Lead_Form_html)) $xtpl->assign("BODY_HTML", $Web_To_Lead_Form_html); else $xtpl->assign("BODY_HTML", ""); + + +require_once('include/SugarTinyMCE.php'); +$tiny = new SugarTinyMCE(); +$tiny->defaultConfig['height']=400; +$tiny->defaultConfig['apply_source_formatting']=true; +$tiny->defaultConfig['cleanup']=false; +$ed = $tiny->getInstance('body_html'); +$xtpl->assign("tiny", $ed); + +$xtpl->parse("main.textarea"); + +$xtpl->assign("INSERT_VARIABLE_ONCLICK", "insert_variable_html(document.EditView.variable_text.value)"); +$xtpl->parse("main.variable_button"); + + + + +$xtpl->parse("main"); +$xtpl->out("main"); + +function ifRadioButton($customFieldName){ + $custRow = null; + $query="select id,type from fields_meta_data where deleted = 0 and name = '$customFieldName'"; + $result=$GLOBALS['db']->query($query); + $row = $GLOBALS['db']->fetchByAssoc($result); + if($row != null && $row['type'] == 'radioenum'){ + return $custRow = $row; + } + return $custRow; +} + +?> diff --git a/modules/Campaigns/MailMerge.php b/modules/Campaigns/MailMerge.php new file mode 100644 index 00000000..92a53771 --- /dev/null +++ b/modules/Campaigns/MailMerge.php @@ -0,0 +1,42 @@ + diff --git a/modules/Campaigns/Menu.php b/modules/Campaigns/Menu.php new file mode 100644 index 00000000..4d4245ea --- /dev/null +++ b/modules/Campaigns/Menu.php @@ -0,0 +1,91 @@ + + + + + + + +
    + + +
    + \ No newline at end of file diff --git a/modules/Campaigns/PopupCampaignRoi.php b/modules/Campaigns/PopupCampaignRoi.php new file mode 100644 index 00000000..e1f1cf4c --- /dev/null +++ b/modules/Campaigns/PopupCampaignRoi.php @@ -0,0 +1,200 @@ +info("Campaign detail view"); + +$xtpl=new XTemplate ('modules/Campaigns/PopupCampaignRoi.html'); + +//_pp($_REQUEST['id']); +$campaign_id=$_REQUEST['id']; +$campaign = new Campaign(); +$opp_query1 = "select camp.name, camp.actual_cost,camp.budget,camp.expected_revenue,count(*) opp_count,SUM(opp.amount) as Revenue, SUM(camp.actual_cost) as Investment, + ROUND((SUM(opp.amount) - SUM(camp.actual_cost))/(SUM(camp.actual_cost)), 2)*100 as ROI"; + $opp_query1 .= " from opportunities opp"; + $opp_query1 .= " right join campaigns camp on camp.id = opp.campaign_id"; + $opp_query1 .= " where opp.sales_stage = 'Closed Won' and camp.id='$campaign_id'"; + $opp_query1 .= " group by camp.name"; + //$opp_query1 .= " and deleted=0"; + $opp_result1=$campaign->db->query($opp_query1); + $opp_data1=$campaign->db->fetchByAssoc($opp_result1); + //get the click-throughs + $query_click = "SELECT count(*) hits "; + $query_click.= " FROM campaign_log "; + $query_click.= " WHERE campaign_id = '$campaign_id' AND activity_type='link' AND related_type='CampaignTrackers' AND archived=0 AND deleted=0"; + + //if $marketing id is specified, then lets filter the chart by the value + if (!empty($marketing_id)){ + $query_click.= " AND marketing_id ='$marketing_id'"; + } + + $query_click.= " GROUP BY activity_type, target_type"; + $query_click.= " ORDER BY activity_type, target_type"; + $result = $campaign->db->query($query_click); + + + $xtpl->assign("OPP_COUNT", $opp_data1['opp_count']); + $xtpl->assign("ACTUAL_COST",$opp_data1['actual_cost']); + $xtpl->assign("PLANNED_BUDGET",$opp_data1['budget']); + $xtpl->assign("EXPECTED_REVENUE",$opp_data1['expected_revenue']); + + + + + $currency = new Currency(); +if(isset($focus->currency_id) && !empty($focus->currency_id)) +{ + $currency->retrieve($focus->currency_id); + if( $currency->deleted != 1){ + $xtpl->assign("CURRENCY", $currency->iso4217 .' '.$currency->symbol ); + }else $xtpl->assign("CURRENCY", $currency->getDefaultISO4217() .' '.$currency->getDefaultCurrencySymbol() ); +}else{ + + $xtpl->assign("CURRENCY", $currency->getDefaultISO4217() .' '.$currency->getDefaultCurrencySymbol() ); + +} + +global $current_user; +if(is_admin($current_user) && $_REQUEST['module'] != 'DynamicLayout' && !empty($_SESSION['editinplace'])){ + + $xtpl->assign("ADMIN_EDIT","".SugarThemeRegistry::current()->getImage("EditLayout","border='0' alt='Edit Layout' align='bottom'").""); +} + +//$detailView->processListNavigation($xtpl, "CAMPAIGN", $offset, $focus->is_AuditEnabled()); +// adding custom fields: +//require_once('modules/DynamicFields/templates/Files/DetailView.php'); + +/* we need to build the dropdown of related marketing values + $latest_marketing_id = ''; + $selected_marketing_id = ''; + if(isset($_REQUEST['mkt_id'])) $selected_marketing_id = $_REQUEST['mkt_id']; + $options_str = ''; + //query for all email marketing records related to this campaign + $latest_marketing_query = "select id, name, date_modified from email_marketing where campaign_id = '$focus->id' order by date_modified desc"; + + //build string with value(s) retrieved + $result =$campaign->db->query($latest_marketing_query); + if ($row = $campaign->db->fetchByAssoc($result)){ + //first, populated the latest marketing id variable, as this + // variable will be used to build chart and subpanels + $latest_marketing_id = $row['id']; + //fill in first option value + $options_str .= ''; + // if the marketing is not empty, but not same as selected marketing id, then.. + //.. do not set this option to render as "selected" + }else{ + $options_str .='>'. $row['name'] .''; + } + } + //process rest of records, if they exist + while ($row = $campaign->db->fetchByAssoc($result)){ + //add to list of option values + $options_str .= ''; + } + } + //populate the dropdown + $xtpl->assign("MKT_DROP_DOWN",$options_str); + + */ + +//add chart +$seps = array("-", "/"); +$dates = array(date($GLOBALS['timedate']->dbDayFormat), $GLOBALS['timedate']->dbDayFormat); +$dateFileNameSafe = str_replace($seps, "_", $dates); +$cache_file_name_roi = $current_user->getUserPrivGuid()."_campaign_response_by_roi_".$dateFileNameSafe[0]."_".$dateFileNameSafe[1].".xml"; +$chart= new campaign_charts(); + +//ob_start(); + + //if marketing id has been selected, then set "latest_marketing_id" to the selected value + //latest marketing id will be passed in to filter the charts and subpanels + //_pp($sugar_config['tmp_dir'].$cache_file_name_roi); + + if(!empty($selected_marketing_id)){$latest_marketing_id = $selected_marketing_id;} + if(empty($latest_marketing_id) || $latest_marketing_id === 'all'){ + $xtpl->assign("MY_CHART_ROI", $chart->campaign_response_roi_popup($app_list_strings['roi_type_dom'],$app_list_strings['roi_type_dom'],$campaign_id,$sugar_config['tmp_dir'].$cache_file_name_roi,true)); + }else{ + + $xtpl->assign("MY_CHART_ROI", $chart->campaign_response_roi_popup($app_list_strings['roi_type_dom'],$app_list_strings['roi_type_dom'],$campaign_id,$sugar_config['tmp_dir'].$cache_file_name_roi,true)); + } + +//$output_html .= ob_get_contents(); +//ob_end_clean(); + + +//_ppd($xtpl); +//end chart + +$xtpl->parse("main"); +$xtpl->out("main"); + +?> \ No newline at end of file diff --git a/modules/Campaigns/Popup_picker.html b/modules/Campaigns/Popup_picker.html new file mode 100644 index 00000000..c2138cb1 --- /dev/null +++ b/modules/Campaigns/Popup_picker.html @@ -0,0 +1,118 @@ + + + + + + + + + + + +
    + + + + + + + + + + + +
    {MOD.LBL_CAMPAIGN_NAME}{MOD.LBL_CAMPAIGN_TYPE} + + + + + + + + + +
    +
    + + + + + + +{PAGINATION} + + + + + + + + + + + + + + + + + + + + + +
    {CHECKALL}{MOD.LBL_CAMPAIGN_NAME}{arrow_start}{name_arrow}{arrow_end} {MOD.LBL_LIST_STATUS}{arrow_start}{status_arrow}{arrow_end} {MOD.LBL_LIST_TYPE}{arrow_start}{campaign_type_arrow}{arrow_end}
    {PREROW}<{TAG_TYPE} href="#" onclick="send_back('Campaigns','{CAMPAIGN.ID}');">{CAMPAIGN.NAME}{CAMPAIGN.STATUS}{CAMPAIGN.CAMPAIGN_TYPE}
    +{ASSOCIATED_JAVASCRIPT_DATA} + diff --git a/modules/Campaigns/Popup_picker.php b/modules/Campaigns/Popup_picker.php new file mode 100644 index 00000000..6cc0c154 --- /dev/null +++ b/modules/Campaigns/Popup_picker.php @@ -0,0 +1,176 @@ +_get_where_clause(); + + + + $name = empty($_REQUEST['name']) ? '' : $_REQUEST['name']; + $status = empty($_REQUEST['status']) ? '' : $_REQUEST['status']; + $campaign_type = empty($_REQUEST['campaign_type']) ? '' : $_REQUEST['campaign_type']; + + $request_data = empty($_REQUEST['request_data']) ? '' : $_REQUEST['request_data']; + $hide_clear_button = empty($_REQUEST['hide_clear_button']) ? false : true; + + $button = "
    \n"; + //START:FOR MULTI-SELECT + $multi_select=false; + if (!empty($_REQUEST['mode']) && strtoupper($_REQUEST['mode']) == 'MULTISELECT') { + $multi_select=true; + $button .= "\n"; + } + //END:FOR MULTI-SELECT + if(!$hide_clear_button) + { + $button .= "\n"; + } + $button .= "\n"; + $button .= "
    \n"; + + $form = new XTemplate('modules/Campaigns/Popup_picker.html'); + $form->assign('MOD', $mod_strings); + $form->assign('APP', $app_strings); + $form->assign('THEME', $theme); + $form->assign('MODULE_NAME', $currentModule); + + $form->assign('request_data', $request_data); + + $form->assign("TYPE_OPTIONS", get_select_options_with_id($app_list_strings['campaign_type_dom'],"")); + ob_start(); + insert_popup_header($theme); + $output_html .= ob_get_contents(); + ob_end_clean(); + + $output_html .= get_form_header($mod_strings['LBL_SEARCH_FORM_TITLE'], '', false); + + $form->parse('main.SearchHeader'); + $output_html .= $form->text('main.SearchHeader'); + + // Reset the sections that are already in the page so that they do not print again later. + $form->reset('main.SearchHeader'); + + // create the listview + $seed_bean = new Campaign(); + $ListView = new ListView(); + $ListView->show_export_button = false; + $ListView->process_for_popups = true; + $ListView->setXTemplate($form); + $ListView->multi_select_popup=$multi_select; //FOR MULTI-SELECT + $ListView->xTemplate->assign("TAG_TYPE","A"); //FOR MULTI-SELECT + $ListView->setHeaderTitle($mod_strings['LBL_LIST_FORM_TITLE']); //FOR MULTI-SELECT + $ListView->setHeaderText($button); //FOR MULTI-SELECT + $ListView->setQuery($where, '', 'name', 'CAMPAIGN'); + $ListView->setModStrings($mod_strings); + + ob_start(); + //$output_html .= get_form_header($mod_strings['LBL_LIST_FORM_TITLE'], $button, false); //FOR MULTI-SELECT + $ListView->processListView($seed_bean, 'main', 'CAMPAIGN'); + $output_html .= ob_get_contents(); + ob_end_clean(); + + $output_html .= insert_popup_footer(); + return $output_html; + } +} // end of class Popup_Picker +?> \ No newline at end of file diff --git a/modules/Campaigns/ProcessBouncedEmails.php b/modules/Campaigns/ProcessBouncedEmails.php new file mode 100644 index 00000000..36b63e69 --- /dev/null +++ b/modules/Campaigns/ProcessBouncedEmails.php @@ -0,0 +1,214 @@ +id."' AND deleted=0"; + $rs = $GLOBALS['db']->query($query); + while ($row = $GLOBALS['db']->fetchByAssoc($rs)) + $contents .= $row['description']; + + return $contents; +} + +/** + * Create a bounced log campaign entry + * + * @param array $row + * @param Email $email + * @param string $email_description + * @return string + */ +function createBouncedCampaignLogEntry($row,$email, $email_description) +{ + $GLOBALS['log']->debug("Creating bounced email campaign log"); + $bounce = new CampaignLog(); + $bounce->campaign_id=$row['campaign_id']; + $bounce->target_tracker_key=$row['target_tracker_key']; + $bounce->target_id= $row['target_id']; + $bounce->target_type=$row['target_type']; + $bounce->list_id=$row['list_id']; + $bounce->marketing_id=$row['marketing_id']; + + $bounce->activity_date=$email->date_created; + $bounce->related_type='Emails'; + $bounce->related_id= $email->id; + + //do we have the phrase permanent error in the email body. + if (preg_match('/permanent[ ]*error/',$email_description)) + $bounce->activity_type='invalid email'; + else + $bounce->activity_type='send error'; + + $return_id=$bounce->save(); + return $return_id; +} + +/** + * Get the existing campaign log entry by tracker key. + * + * @param string Target Key + * @return array Campaign Log Row + */ +function getExistingCampaignLogEntry($identifier) +{ + $row = FALSE; + $targeted = new CampaignLog(); + $where="campaign_log.activity_type='targeted' and campaign_log.target_tracker_key='{$identifier}'"; + $query=$targeted->create_new_list_query('',$where); + $result=$targeted->db->query($query); + $row=$targeted->db->fetchByAssoc($result); + + return $row; +} + +/** + * Scan the bounced email searching for a valid target identifier. + * + * @param string Email Description + * @return array Results including matches and identifier + */ +function checkBouncedEmailForIdentifier($email_description) +{ + $matches = array(); + $identifiers = array(); + $found = FALSE; + //Check if the identifier is present in the header. + if(preg_match('/X-CampTrackID: [a-z0-9\-]*/',$email_description,$matches)) + { + $identifiers = preg_split('/X-CampTrackID: /',$matches[0],-1,PREG_SPLIT_NO_EMPTY); + $found = TRUE; + $GLOBALS['log']->debug("Found campaign identifier in header of email"); + } + else if( preg_match('/index.php\?entryPoint=removeme&identifier=[a-z0-9\-]*/',$email_description, $matches) ) + { + $identifiers = preg_split('/index.php\?entryPoint=removeme&identifier=/',$matches[0],-1,PREG_SPLIT_NO_EMPTY); + $found = TRUE; + $GLOBALS['log']->debug("Found campaign identifier in body of email"); + } + + return array('found' => $found, 'matches' => $matches, 'identifiers' => $identifiers); +} + +function campaign_process_bounced_emails(&$email, &$email_header) +{ + global $sugar_config; + $emailFromAddress = $email_header->fromaddress; + $email_description = $email->raw_source; + $email_description .= retrieveErrorReportAttachment($email); + + if (preg_match('/MAILER-DAEMON|POSTMASTER/i',$emailFromAddress)) + { + $email_description=quoted_printable_decode($email_description); + $matches=array(); + + //do we have the identifier tag in the email? + $identifierScanResults = checkBouncedEmailForIdentifier($email_description); + + if ( $identifierScanResults['found'] ) + { + $matches = $identifierScanResults['matches']; + $identifiers = $identifierScanResults['identifiers']; + + if (!empty($identifiers)) + { + //array should have only one element in it. + $identifier = trim($identifiers[0]); + $row = getExistingCampaignLogEntry($identifier); + + //Found entry + if (!empty($row)) + { + //do not create another campaign_log record is we already have an + //invalid email or send error entry for this tracker key. + $query_log = "select * from campaign_log where target_tracker_key='{$row['target_tracker_key']}'"; + $query_log .=" and (activity_type='invalid email' or activity_type='send error')"; + $targeted = new CampaignLog(); + $result_log=$targeted->db->query($query_log); + $row_log=$targeted->db->fetchByAssoc($result_log); + + if (empty($row_log)) + { + $return_id = createBouncedCampaignLogEntry($row, $email, $email_description); + return TRUE; + } + else + { + $GLOBALS['log']->debug("Warning: campaign log entry already exists for identifier $identifier"); + return FALSE; + } + } + else + { + $GLOBALS['log']->info("Warning: skipping bounced email with this tracker_key(identifier) in the message body: ".$identifier); + return FALSE; + } + } + else + { + //todo mark the email address as invalid. search for prospects/leads/contact associated + //with this email address and set the invalid_email flag... also make email available. + $GLOBALS['log']->info("Warning: Invalid identifier for campaign log $identifier"); + return FALSE; + } + } + else + { + $GLOBALS['log']->info("Warning: skipping bounced email because it does not have the removeme link."); + return FALSE; + } + } + else + { + $GLOBALS['log']->info("Warning: skipping bounced email because the sender is not MAILER-DAEMON."); + return FALSE; + } +} +?> diff --git a/modules/Campaigns/QueueCampaign.php b/modules/Campaigns/QueueCampaign.php new file mode 100644 index 00000000..a27a0e8e --- /dev/null +++ b/modules/Campaigns/QueueCampaign.php @@ -0,0 +1,212 @@ +retrieve($_REQUEST['record']); +$err_messages=array(); + +$test=false; +if (isset($_REQUEST['mode']) && $_REQUEST['mode'] =='test') { + $test=true; +} + +//this is to account for the case of sending directly from summary page in wizards +$from_wiz =false; +if (isset($_REQUEST['wiz_mass'])) { + $mass[] = $_REQUEST['wiz_mass']; + $_POST['mass'] = $mass; + $from_wiz =true; +} +if (isset($_REQUEST['from_wiz'])) { + $from_wiz =true; +} + +//if campaign status is 'sending' disallow this step. +if (!empty($campaign->status) && $campaign->status == 'sending') { + $err_messages[]=$mod_strings['ERR_SENDING_NOW']; +} +if ($campaign->db->dbType=='oci8') { +} else { + $current_date= "'".$timedate->nowDb()."'"; +} + +//start scheduling now..... +foreach ($_POST['mass'] as $message_id) { + + //fetch email marketing definition. + if (!class_exists('EmailMarketing')) require_once('modules/EmailMarketing/EmailMarketing.php'); + + + $marketing = new EmailMarketing(); + $marketing->retrieve($message_id); + + //make sure that the marketing message has a mailbox. + // + if (empty($marketing->inbound_email_id)) { + + echo "

    "; + echo "

    {$mod_strings['ERR_NO_MAILBOX']}

    "; + echo "
    $marketing->name"; + echo "

    "; + sugar_die(''); + } + + + global $timedate; + $mergedvalue=$timedate->merge_date_time($marketing->date_start,$marketing->time_start); + + if ($campaign->db->dbType=='oci8') { + } else { + if ($test) { + $send_date_time="'".$timedate->getNow()->get("-60 seconds")->asDb() ."'"; + } else { + $send_date_time= "'".$timedate->to_db($mergedvalue)."'"; + } + } + + //find all prospect lists associated with this email marketing message. + if ($marketing->all_prospect_lists == 1) { + $query="SELECT prospect_lists.id prospect_list_id from prospect_lists "; + $query.=" INNER JOIN prospect_list_campaigns plc ON plc.prospect_list_id = prospect_lists.id"; + $query.=" WHERE plc.campaign_id='{$campaign->id}'"; + $query.=" AND prospect_lists.deleted=0"; + $query.=" AND plc.deleted=0"; + if ($test) { + $query.=" AND prospect_lists.list_type='test'"; + } else { + $query.=" AND prospect_lists.list_type!='test' AND prospect_lists.list_type not like 'exempt%'"; + } + } else { + $query="select email_marketing_prospect_lists.* FROM email_marketing_prospect_lists "; + $query.=" inner join prospect_lists on prospect_lists.id = email_marketing_prospect_lists.prospect_list_id"; + $query.=" WHERE prospect_lists.deleted=0 and email_marketing_id = '$message_id' and email_marketing_prospect_lists.deleted=0"; + + if ($test) { + $query.=" AND prospect_lists.list_type='test'"; + } else { + $query.=" AND prospect_lists.list_type!='test' AND prospect_lists.list_type not like 'exempt%'"; + } + } + $result=$campaign->db->query($query); + while (($row=$campaign->db->fetchByAssoc($result))!=null ) { + + + $prospect_list_id=$row['prospect_list_id']; + + //delete all messages for the current campaign and current email marketing message. + $delete_emailman_query="delete from emailman where campaign_id='{$campaign->id}' and marketing_id='{$message_id}' and list_id='{$prospect_list_id}'"; + $campaign->db->query($delete_emailman_query); + + $insert_query= "INSERT INTO emailman (date_entered, user_id, campaign_id, marketing_id,list_id, related_id, related_type, send_date_time"; + if ($campaign->db->dbType=='oci8') { + } + $insert_query.=')'; + $insert_query.= " SELECT $current_date,'{$current_user->id}',plc.campaign_id,'{$message_id}',plp.prospect_list_id, plp.related_id, plp.related_type,{$send_date_time} "; + if ($campaign->db->dbType=='oci8') { + } + $insert_query.= "FROM prospect_lists_prospects plp "; + $insert_query.= "INNER JOIN prospect_list_campaigns plc ON plc.prospect_list_id = plp.prospect_list_id "; + $insert_query.= "WHERE plp.prospect_list_id = '{$prospect_list_id}' "; + $insert_query.= "AND plp.deleted=0 "; + $insert_query.= "AND plc.deleted=0 "; + $insert_query.= "AND plc.campaign_id='{$campaign->id}'"; + + if ($campaign->db->dbType=='oci8') { + } + $campaign->db->query($insert_query); + } +} + +//delete all entries from the emailman table that belong to the exempt list. +if (!$test) { + //id based exempt list treatment. + if ($campaign->db->dbType =='mysql') { + + $delete_query = "DELETE emailman.* FROM emailman "; + $delete_query.= "INNER JOIN prospect_lists_prospects plp on plp.related_id = emailman.related_id and plp.related_type = emailman.related_type "; + $delete_query.= "INNER JOIN prospect_lists pl ON pl.id = plp.prospect_list_id "; + $delete_query .= "INNER JOIN prospect_list_campaigns plc on plp.prospect_list_id = plc.prospect_list_id "; + $delete_query.= "WHERE plp.deleted=0 "; + $delete_query.= "AND plc.campaign_id = '{$campaign->id}'"; + $delete_query.= "AND pl.list_type = 'exempt' "; + $delete_query.= "AND emailman.campaign_id='{$campaign->id}'"; + $campaign->db->query($delete_query); + + }elseif($campaign->db->dbType =='mssql'){ + $delete_query = "DELETE FROM emailman "; + $delete_query .= "WHERE emailman.campaign_id='".$campaign->id."' "; + $delete_query .= "and emailman.related_id in "; + $delete_query .= "(select prospect_lists_prospects.related_id from prospect_lists_prospects where prospect_lists_prospects.prospect_list_id in (select prospect_lists.id from prospect_lists where prospect_lists.list_type = 'exempt' and prospect_lists_prospects.prospect_list_id in(select prospect_list_campaigns.prospect_list_id from prospect_list_campaigns where prospect_list_campaigns.campaign_id = '".$campaign->id."'))) "; + $delete_query .= "and emailman.related_type in "; + $delete_query .= "(select prospect_lists_prospects.related_type from prospect_lists_prospects where prospect_lists_prospects.prospect_list_id in (select prospect_lists.id from prospect_lists where prospect_lists.list_type = 'exempt' and prospect_lists_prospects.prospect_list_id in(select prospect_list_campaigns.prospect_list_id from prospect_list_campaigns where prospect_list_campaigns.campaign_id = '".$campaign->id."'))) "; + $campaign->db->query($delete_query); + } +} + +$return_module=isset($_REQUEST['return_module'])?$_REQUEST['return_module']:'Campaigns'; +$return_action=isset($_REQUEST['return_action'])?$_REQUEST['return_action']:'DetailView'; +$return_id=$_REQUEST['record']; + +if ($test) { + //navigate to EmailManDelivery.. + $header_URL = "Location: index.php?action=EmailManDelivery&module=EmailMan&campaign_id={$_REQUEST['record']}&return_module={$return_module}&return_action={$return_action}&return_id={$return_id}&mode=test"; + if($from_wiz){$header_URL .= "&from_wiz=true";} +} else { + //navigate back to campaign detail view... + $header_URL = "Location: index.php?action={$return_action}&module={$return_module}&record={$return_id}"; + if($from_wiz){$header_URL .= "&from=send";} +} +$GLOBALS['log']->debug("about to post header URL of: $header_URL"); +header($header_URL); +?> \ No newline at end of file diff --git a/modules/Campaigns/RemoveMe.php b/modules/Campaigns/RemoveMe.php new file mode 100644 index 00000000..479ed2ad --- /dev/null +++ b/modules/Campaigns/RemoveMe.php @@ -0,0 +1,89 @@ +retrieve($keys['target_id']); + unsubscribe($keys['campaign_id'], $focus); + + }elseif(!empty($keys)){ + $id = $keys['target_id']; + $module = trim($keys['target_type']); + $class = $beanList[$module]; + require_once($beanFiles[$class]); + $mod = new $class(); + $db = DBManagerFactory::getInstance(); + + $id = $db->quote($id); + + //no opt out for users. + if(preg_match('/^[0-9A-Za-z\-]*$/', $id) && $module != 'Users'){ + //record this activity in the campaing log table.. + $query = "UPDATE email_addresses SET email_addresses.opt_out = 1 WHERE EXISTS(SELECT 1 FROM email_addr_bean_rel ear WHERE ear.bean_id = '$id' AND ear.deleted=0 AND email_addresses.id = ear.email_address_id)"; + $status=$db->query($query); + if($status){ + echo "*"; + } + } + } + //Print Confirmation Message. + echo $mod_strings['LBL_ELECTED_TO_OPTOUT']; + +} +sugar_cleanup(); +?> diff --git a/modules/Campaigns/RoiDetailView.php b/modules/Campaigns/RoiDetailView.php new file mode 100644 index 00000000..38c65ae0 --- /dev/null +++ b/modules/Campaigns/RoiDetailView.php @@ -0,0 +1,210 @@ +processSugarBean("CAMPAIGN", $focus, $offset); + if($result == null) { + sugar_die($app_strings['ERROR_NO_RECORD']); + } + $focus=$result; +} else { + header("Location: index.php?module=Accounts&action=index"); +} + +// For all campaigns show the same ROI interface +// ..else default to legacy detail view +/* +if(!$focus->campaign_type == "NewsLetter"){ + include ('modules/Campaigns/NewsLetterTrackDetailView.php'); +} else{ + +*/ + echo getClassicModuleTitle($mod_strings['LBL_MODULE_NAME'], array($mod_strings['LBL_MODULE_NAME'],$focus->name), true); + + $GLOBALS['log']->info("Campaign detail view"); + + $smarty = new Sugar_Smarty(); + $smarty->assign("MOD", $mod_strings); + $smarty->assign("APP", $app_strings); + + $smarty->assign("THEME", $theme); + $smarty->assign("GRIDLINE", $gridline); + $smarty->assign("PRINT_URL", "index.php?".$GLOBALS['request_string']); + $smarty->assign("ID", $focus->id); + $smarty->assign("ASSIGNED_TO", $focus->assigned_user_name); + $smarty->assign("STATUS", $app_list_strings['campaign_status_dom'][$focus->status]); + $smarty->assign("NAME", $focus->name); + $smarty->assign("TYPE", $app_list_strings['campaign_type_dom'][$focus->campaign_type]); + $smarty->assign("START_DATE", $focus->start_date); + $smarty->assign("END_DATE", $focus->end_date); + + $smarty->assign("BUDGET", $focus->budget); + $smarty->assign("ACTUAL_COST", $focus->actual_cost); + $smarty->assign("EXPECTED_COST", $focus->expected_cost); + $smarty->assign("EXPECTED_REVENUE", $focus->expected_revenue); + + + $smarty->assign("OBJECTIVE", nl2br($focus->objective)); + $smarty->assign("CONTENT", nl2br($focus->content)); + $smarty->assign("DATE_MODIFIED", $focus->date_modified); + $smarty->assign("DATE_ENTERED", $focus->date_entered); + + $smarty->assign("CREATED_BY", $focus->created_by_name); + $smarty->assign("MODIFIED_BY", $focus->modified_by_name); + $smarty->assign("TRACKER_URL", $sugar_config['site_url'] . '/campaign_tracker.php?track=' . $focus->tracker_key); + $smarty->assign("TRACKER_COUNT", intval($focus->tracker_count)); + $smarty->assign("TRACKER_TEXT", $focus->tracker_text); + $smarty->assign("REFER_URL", $focus->refer_url); + $smarty->assign("IMPRESSIONS", $focus->impressions); + $roi_vals = array(); + $roi_vals['budget']= $focus->budget; + $roi_vals['actual_cost']= $focus->actual_cost; + $roi_vals['Expected_Revenue']= $focus->expected_revenue; + $roi_vals['Expected_Cost']= $focus->expected_cost; + +//Query for opportunities won, clickthroughs +$campaign_id = $focus->id; + $opp_query1 = "select camp.name, count(*) opp_count,SUM(opp.amount) as Revenue, SUM(camp.actual_cost) as Investment, + ROUND((SUM(opp.amount) - SUM(camp.actual_cost))/(SUM(camp.actual_cost)), 2)*100 as ROI"; + $opp_query1 .= " from opportunities opp"; + $opp_query1 .= " right join campaigns camp on camp.id = opp.campaign_id"; + $opp_query1 .= " where opp.sales_stage = 'Closed Won' and camp.id='$campaign_id'"; + $opp_query1 .= " and opp.deleted=0"; + $opp_query1 .= " group by camp.name"; + $opp_result1=$focus->db->query($opp_query1); + $opp_data1=$focus->db->fetchByAssoc($opp_result1); + if(empty($opp_data1['opp_count'])) $opp_data1['opp_count']=0; + //_ppd($opp_data1); + $smarty->assign("OPPORTUNITIES_WON",$opp_data1['opp_count']); + + $camp_query1 = "select camp.name, count(*) click_thru_link"; + $camp_query1 .= " from campaign_log camp_log"; + $camp_query1 .= " right join campaigns camp on camp.id = camp_log.campaign_id"; + $camp_query1 .= " where camp_log.activity_type = 'link' and camp.id='$campaign_id'"; + $camp_query1 .= " group by camp.name"; + $opp_query1 .= " and deleted=0"; + $camp_result1=$focus->db->query($camp_query1); + $camp_data1=$focus->db->fetchByAssoc($camp_result1); + + if(unformat_number($focus->impressions) > 0){ + $cost_per_impression= unformat_number($focus->actual_cost)/unformat_number($focus->impressions); + } + else{ + $cost_per_impression = format_number(0); + } + $smarty->assign("COST_PER_IMPRESSION",currency_format_number($cost_per_impression)); + if(empty($camp_data1['click_thru_link'])) $camp_data1['click_thru_link']=0; + $click_thru_links = $camp_data1['click_thru_link']; + + if($click_thru_links >0){ + $cost_per_click_thru= unformat_number($focus->actual_cost)/unformat_number($click_thru_links); + } + else{ + $cost_per_click_thru = format_number(0); + } + $smarty->assign("COST_PER_CLICK_THROUGH",currency_format_number($cost_per_click_thru)); + + + $currency = new Currency(); + if(isset($focus->currency_id) && !empty($focus->currency_id)) + { + $currency->retrieve($focus->currency_id); + if( $currency->deleted != 1){ + $smarty->assign("CURRENCY", $currency->iso4217 .' '.$currency->symbol ); + }else $smarty->assign("CURRENCY", $currency->getDefaultISO4217() .' '.$currency->getDefaultCurrencySymbol() ); + }else{ + + $smarty->assign("CURRENCY", $currency->getDefaultISO4217() .' '.$currency->getDefaultCurrencySymbol() ); + + } + global $current_user; + if(is_admin($current_user) && $_REQUEST['module'] != 'DynamicLayout' && !empty($_SESSION['editinplace'])){ + + $smarty->assign("ADMIN_EDIT","".SugarThemeRegistry::current()->getImage("EditLayout","border='0' alt='Edit Layout' align='bottom'").""); + } + + $detailView->processListNavigation($xtpl, "CAMPAIGN", $offset, $focus->is_AuditEnabled()); + // adding custom fields: + require_once('modules/DynamicFields/templates/Files/DetailView.php'); + + + + + + //add chart + $seps = array("-", "/"); + $dates = array(date($GLOBALS['timedate']->dbDayFormat), $GLOBALS['timedate']->dbDayFormat); + $dateFileNameSafe = str_replace($seps, "_", $dates); + //$cache_file_name = $current_user->getUserPrivGuid()."_campaign_response_by_activity_type_".$dateFileNameSafe[0]."_".$dateFileNameSafe[1].".xml"; + $cache_file_name_roi = $current_user->getUserPrivGuid()."_campaign_response_by_roi_".$dateFileNameSafe[0]."_".$dateFileNameSafe[1].".xml"; + $chart= new campaign_charts(); + //_ppd($roi_vals); + $smarty->assign("MY_CHART_ROI", $chart->campaign_response_roi($app_list_strings['roi_type_dom'],$app_list_strings['roi_type_dom'],$focus->id,true,true)); + //end chart + //custom chart code + require_once('include/SugarCharts/SugarChartFactory.php'); + $sugarChart = SugarChartFactory::getInstance(); + $resources = $sugarChart->getChartResources(); + $smarty->assign('chartResources', $resources); + +echo $smarty->fetch('modules/Campaigns/RoiDetailView.tpl'); +?> \ No newline at end of file diff --git a/modules/Campaigns/RoiDetailView.tpl b/modules/Campaigns/RoiDetailView.tpl new file mode 100644 index 00000000..e0702f24 --- /dev/null +++ b/modules/Campaigns/RoiDetailView.tpl @@ -0,0 +1,140 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} + + +{$chartResources} + + + + + + + + +
    +
    + + + + + + + + + + + +
    + + {$ADMIN_EDIT} + + {$ADMIN_EDIT}
    +

    + + +{$PAGINATION} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    {$MOD.LBL_NAME}{$NAME}{$MOD.LBL_ASSIGNED_TO}{$ASSIGNED_TO}
    {$MOD.LBL_CAMPAIGN_STATUS}{$STATUS}  
    {$MOD.LBL_CAMPAIGN_START_DATE}{$START_DATE}{$APP.LBL_DATE_MODIFIED} {$DATE_MODIFIED} {$APP.LBL_BY} {$MODIFIED_BY}
    {$MOD.LBL_CAMPAIGN_END_DATE}{$END_DATE}{$APP.LBL_DATE_ENTERED} {$DATE_ENTERED} {$APP.LBL_BY} {$CREATED_BY}
    {$MOD.LBL_CAMPAIGN_TYPE}{$TYPE}  
        
    {$MOD.LBL_CAMPAIGN_BUDGET} ({$CURRENCY}){$BUDGET}{$MOD.LBL_CAMPAIGN_IMPRESSIONS}{$IMPRESSIONS}
    {$MOD.LBL_CAMPAIGN_EXPECTED_COST} ({$CURRENCY}){$EXPECTED_COST}{$MOD.LBL_CAMPAIGN_OPPORTUNITIES_WON}{$OPPORTUNITIES_WON}
    {$MOD.LBL_CAMPAIGN_ACTUAL_COST} ({$CURRENCY}){$ACTUAL_COST}{$MOD.LBL_CAMPAIGN_COST_PER_IMPRESSION} ({$CURRENCY}){$COST_PER_IMPRESSION}
    {$MOD.LBL_CAMPAIGN_EXPECTED_REVENUE} ({$CURRENCY}){$EXPECTED_REVENUE}{$MOD.LBL_CAMPAIGN_COST_PER_CLICK_THROUGH} ({$CURRENCY}){$COST_PER_CLICK_THROUGH}
        
    +

    +
    {$MY_CHART_ROI}
    + + diff --git a/modules/Campaigns/Save.php b/modules/Campaigns/Save.php new file mode 100644 index 00000000..e1c82a51 --- /dev/null +++ b/modules/Campaigns/Save.php @@ -0,0 +1,131 @@ +retrieve($_POST['record']); +if(!$focus->ACLAccess('Save')){ + ACLController::displayNoAccess(true); + sugar_cleanup(true); +} +if (!empty($_POST['assigned_user_id']) && ($focus->assigned_user_id != $_POST['assigned_user_id']) && ($_POST['assigned_user_id'] != $current_user->id)) { + $check_notify = TRUE; +} +else { + $check_notify = FALSE; +} + +require_once('include/formbase.php'); +$focus = populateFromPost('', $focus); + +//store preformatted dates for 2nd save +$preformat_start_date = $focus->start_date; +$preformat_end_date = $focus->end_date; +//_ppd($preformat_end_date); + +$focus->save($check_notify); +$return_id = $focus->id; + +$GLOBALS['log']->debug("Saved record with id of ".$return_id); + + +//if type is set to newsletter then make sure there are propsect lists attached +if($focus->campaign_type =='NewsLetter'){ + //if this is a duplicate, and the "relate_to" and "relate_id" elements are not cleared out, + //then prospect lists will get related to the original campaign on save of the prospect list, and then + //will get related to the new newsletter campaign, meaning the same (un)subscription list will belong to + //two campaigns, which is wrong + if((isset($_REQUEST['duplicateSave']) && $_REQUEST['duplicateSave']) || (isset($_REQUEST['isDuplicate']) && $_REQUEST['isDuplicate']) ){ + $_REQUEST['relate_to'] = ''; + $_REQUEST['relate_id'] = ''; + + } + + //add preformatted dates for 2nd save, to avoid formatting conversion errors + $focus->start_date = $preformat_start_date ; + $focus->end_date = $preformat_end_date ; + + $focus->load_relationship('prospectlists'); + $target_lists = $focus->prospectlists->get(); + if(count($target_lists)<1){ + global $current_user; + global $mod_strings; + //if no prospect lists are attached, then lets create a subscription and unsubscription + //default prospect lists as these are required for newsletters. + + //create subscription list + $subs = new ProspectList(); + $subs->name = $focus->name.' '.$mod_strings['LBL_SUBSCRIPTION_LIST']; + $subs->assigned_user_id= $current_user->id; + $subs->list_type = "default"; + $subs->save(); + $focus->prospectlists->add($subs->id); + + //create unsubscription list + $unsubs = new ProspectList(); + $unsubs->name = $focus->name.' '.$mod_strings['LBL_UNSUBSCRIPTION_LIST']; + $unsubs->assigned_user_id= $current_user->id; + $unsubs->list_type = "exempt"; + $unsubs->save(); + $focus->prospectlists->add($unsubs->id); + + //create unsubscription list + $test_subs = new ProspectList(); + $test_subs->name = $focus->name.' '.$mod_strings['LBL_TEST_LIST']; + $test_subs->assigned_user_id= $current_user->id; + $test_subs->list_type = "test"; + $test_subs->save(); + $focus->prospectlists->add($test_subs->id); + } + //save new relationships + $focus->save(); + +}//finish newsletter processing + +handleRedirect($focus->id, 'Campaigns'); + + +?> \ No newline at end of file diff --git a/modules/Campaigns/Schedule.html b/modules/Campaigns/Schedule.html new file mode 100644 index 00000000..af57f766 --- /dev/null +++ b/modules/Campaigns/Schedule.html @@ -0,0 +1,75 @@ + + + + + + + + + +

    +

    {SCHEDULE_MESSAGE_HEADER}

    + + +

    + + +{PAGINATION} + + + + + + + + + + + + + + + +{PAGINATION} +
    {CHECKALL}{MOD.LBL_LIST_NAME}{MOD.LBL_LIST_PROSPECT_LIST_NAME}
    {PREROW}{EMAILMARKETING.NAME}{EMAILMARKETING.PROSPECT_LIST_NAME}
    + + \ No newline at end of file diff --git a/modules/Campaigns/Schedule.php b/modules/Campaigns/Schedule.php new file mode 100644 index 00000000..0d8adf3d --- /dev/null +++ b/modules/Campaigns/Schedule.php @@ -0,0 +1,171 @@ +quote($campaign_id)."'"); + + $where = ""; + foreach($where_clauses as $clause) + { + if($where != "") + $where .= " and "; + $where .= $clause; + } + + $GLOBALS['log']->info("Here is the where clause for the list view: $where"); +} + +$ListView = new ListView(); +$ListView->initNewXTemplate('modules/Campaigns/Schedule.html',$current_module_strings); + +if ($test) { + $ListView->xTemplateAssign("SCHEDULE_MESSAGE_HEADER",$current_module_strings['LBL_SCHEDULE_MESSAGE_TEST']); +} else { + $ListView->xTemplateAssign("SCHEDULE_MESSAGE_HEADER",$current_module_strings['LBL_SCHEDULE_MESSAGE_EMAILS']); +} + +//force multi-select popup +$ListView->process_for_popups=true; +$ListView->multi_select_popup=true; +//end +$ListView->mergeduplicates = false; +$ListView->show_export_button = false; +$ListView->show_select_menu = false; +$ListView->show_delete_button = false; +$ListView->setDisplayHeaderAndFooter(false); +$ListView->xTemplateAssign("RETURN_MODULE",$_POST['return_module']); +$ListView->xTemplateAssign("RETURN_ACTION",$_POST['return_action']); +$ListView->xTemplateAssign("RETURN_ID",$_POST['record']); +$ListView->setHeaderTitle($current_module_strings['LBL_LIST_FORM_TITLE']); +$ListView->setQuery($where, "", "name", "EMAILMARKETING"); + +if ($test) { + $ListView->xTemplateAssign("MODE",$_POST['mode']); + //finds all marketing messages that have an association with prospect list of the test. + //this query can be siplified using sub-selects. + $query="select distinct email_marketing.id email_marketing_id from email_marketing "; + $query.=" inner join email_marketing_prospect_lists empl on empl.email_marketing_id = email_marketing.id "; + $query.=" inner join prospect_lists on prospect_lists.id = empl.prospect_list_id "; + $query.=" inner join prospect_list_campaigns plc on plc.prospect_list_id = empl.prospect_list_id "; + $query.=" where empl.deleted=0 "; + $query.=" and prospect_lists.deleted=0 "; + $query.=" and prospect_lists.list_type='test' "; + $query.=" and plc.deleted=0 "; + $query.=" and plc.campaign_id='$campaign_id'"; + $query.=" and email_marketing.campaign_id='$campaign_id'"; + $query.=" and email_marketing.deleted=0 "; + $query.=" and email_marketing.all_prospect_lists=0 "; + + $seed=array(); + + $result=$focus->db->query($query); + while(($row=$focus->db->fetchByAssoc($result)) != null) { + + $bean = new EmailMarketing(); + $bean->retrieve($row['email_marketing_id']); + $bean->mode='test'; + $seed[]=$bean; + } + $query=" select email_marketing.id email_marketing_id from email_marketing "; + $query.=" WHERE email_marketing.campaign_id='$campaign_id'"; + $query.=" and email_marketing.deleted=0 "; + $query.=" and email_marketing.all_prospect_lists=1 "; + + $result=$focus->db->query($query); + while(($row=$focus->db->fetchByAssoc($result)) != null) { + + $bean = new EmailMarketing(); + $bean->retrieve($row['email_marketing_id']); + $bean->mode='test'; + $seed[]=$bean; + } + + $ListView->processListView($seed, "main", "EMAILMARKETING"); +} else { + $ListView->processListView($focus, "main", "EMAILMARKETING"); +} +?> \ No newline at end of file diff --git a/modules/Campaigns/SearchForm_NewsLetter.html b/modules/Campaigns/SearchForm_NewsLetter.html new file mode 100644 index 00000000..f2c34c15 --- /dev/null +++ b/modules/Campaigns/SearchForm_NewsLetter.html @@ -0,0 +1,103 @@ + + + + +
    + + + + + +
    {MOD.LBL_CAMPAIGN_NAME}  {APP.LBL_CURRENT_USER_FILTER}  
    +
    + + + + + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + +
    {MOD.LBL_CAMPAIGN_NAME}{MOD.LBL_CAMPAIGN_STATUS}
    {MOD.LBL_CAMPAIGN_START_DATE} {APP.LBL_ENTER_DATE} {USER_DATEFORMAT}{MOD.LBL_CAMPAIGN_TYPE}{MOD.LBL_NEWSLETTER}
    {MOD.LBL_CAMPAIGN_END_DATE} {APP.LBL_ENTER_DATE} {USER_DATEFORMAT}{APP.LBL_ASSIGNED_TO}
     
    + {MOD.LBL_SAVED_SEARCH}
    +

    +

    + {SAVED_SEARCH} +
    +
    +
    + + + + diff --git a/modules/Campaigns/SubPanelViewer.php b/modules/Campaigns/SubPanelViewer.php new file mode 100644 index 00000000..2b6db1ec --- /dev/null +++ b/modules/Campaigns/SubPanelViewer.php @@ -0,0 +1,105 @@ +retrieve($record); + +include('include/SubPanel/SubPanel.php'); +$layout_def_key = ''; +if(!empty($_REQUEST['layout_def_key'])){ + $layout_def_key = $_REQUEST['layout_def_key']; +} + +$subpanel_object = new SubPanel($module, $record, $subpanel,null, $layout_def_key); + +$subpanel_object->setTemplateFile('include/SubPanel/SubPanelDynamic.html'); + +if(!empty($_REQUEST['mkt_id']) && $_REQUEST['mkt_id'] != 'all') {// bug 32910 + $mkt_id = $_REQUEST['mkt_id']; +} + +if(!empty($mkt_id)) { + $subpanel_object->subpanel_defs->_instance_properties['function_parameters']['EMAIL_MARKETING_ID_VALUE'] = $mkt_id; +} +echo (empty($_REQUEST['inline']))?$subpanel_object->get_buttons():'' ; + +$subpanel_object->display(); + +if(empty($_REQUEST['inline'])) +{ + insert_popup_footer($theme); +} + +?> \ No newline at end of file diff --git a/modules/Campaigns/Subscriptions.html b/modules/Campaigns/Subscriptions.html new file mode 100644 index 00000000..ff55deb2 --- /dev/null +++ b/modules/Campaigns/Subscriptions.html @@ -0,0 +1,117 @@ + + + +
    + + + + + + + + + + + + + + + + + + +
    + + + + + + + + + +

    {APP.LBL_MANAGE_SUBSCRIPTIONS_FOR}{FOCUS_NAME}

     
    + +
    + {DRAG_DROP_CHOOSER} +
    +
    + +
     
    + + +

    + + + + + diff --git a/modules/Campaigns/Subscriptions.php b/modules/Campaigns/Subscriptions.php new file mode 100644 index 00000000..cba4104e --- /dev/null +++ b/modules/Campaigns/Subscriptions.php @@ -0,0 +1,244 @@ + debug("In Subscriptions, about to retrieve record: ".$_REQUEST['record']); + $result = $focus->retrieve($_REQUEST['record']); + if($result == null) + { + sugar_die($app_strings['ERROR_NO_RECORD']); + } +} + + +$this->ss->assign("MOD", $mod_strings); +$this->ss->assign("APP", $app_strings); + +if(isset($_REQUEST['return_module'])){$this->ss->assign("RETURN_MODULE", $_REQUEST['return_module']);} +if(isset($_REQUEST['return_id'])){$this->ss->assign("RETURN_ID", $_REQUEST['return_id']);} +if(isset($_REQUEST['return_action'])){$this->ss->assign("RETURN_ACTION", $_REQUEST['return_action']);} +if(isset($_REQUEST['record'])){$this->ss->assign("RECORD", $_REQUEST['record']);} + +//if subsaction has been set, then process subscriptions +if(isset($_REQUEST['subs_action'])){manageSubscriptions($focus);} + +//$title = $GLOBALS['app_strings']['LBL_MANAGE_SUBSCRIPTIONS_FOR'].$focus->name; +$params = array(); +$params[] = "{$focus->module_dir}"; +$params[] = "{$focus->name}"; +$params[] = $mod_strings['LBL_MANAGE_SUBSCRIPTIONS_TITLE']; +$title = getClassicModuleTitle($focus->module_dir, $params, true); +$orig_vals_str = printOriginalValues($focus); +$orig_vals_array = constructDDSubscriptionList($focus); + +$this->ss->assign('APP', $GLOBALS['app_strings']); +$this->ss->assign('MOD', $GLOBALS['mod_strings']); +$this->ss->assign('title', $title); + +$this->ss->assign('enabled_subs', $orig_vals_array[0]); +$this->ss->assign('disabled_subs', $orig_vals_array[1]); +$this->ss->assign('enabled_subs_string', $orig_vals_str[0]); +$this->ss->assign('disabled_subs_string', $orig_vals_str[1]); + +echo $this->ss->fetch('modules/Campaigns/Subscriptions.tpl'); + + + + +/* + *This function constructs Drag and Drop multiselect box of subscriptions for display in manage subscription form +*/ +function constructDDSubscriptionList($focus,$classname=''){ +require_once("include/templates/TemplateDragDropChooser.php"); +global $mod_strings; +$unsubs_arr = ''; +$subs_arr = ''; + +// Lets start by creating the subscription and unsubscription arrays + $subscription_arrays = get_subscription_lists($focus); + $unsubs_arr = $subscription_arrays['unsubscribed']; + $subs_arr = $subscription_arrays['subscribed']; + + $comb_array = array(); + $comb_array [0] = array(); + $comb_array [1] = array(); + + foreach ($subs_arr as $key=>$val){ + $comb_array [0][$val] = $key; + } + + + foreach ($unsubs_arr as $key=>$val){ + $comb_array [1][$val] = $key; + } + + return $comb_array ; + +} + + + +/* + *This function constructs multiselect box of subscriptions for display in manage subscription form +*/ +function printOriginalValues($focus){ + global $app_strings; + $unsubs_arr = ''; + $subs_arr = ''; + $return_arr = ''; + + // Lets start by creating the subscription and unsubscription arrays + $subscription_arrays = get_subscription_lists($focus); + $unsubs_arr = $subscription_arrays['unsubscribed']; + $subs_arr = $subscription_arrays['subscribed']; + +// ORIG_UNSUBS_VALUES + $unsubs_vals = ' '; + $subs_vals = ' '; + foreach($subs_arr as $name => $id){ + $subs_vals .= ", $id"; + } + $return_arr[]=$subs_vals; + + foreach($unsubs_arr as $name => $id){ + $unsubs_vals .= ", $id"; + } + + $return_arr[]=$unsubs_vals; + + return $return_arr; + } + + +/* + * Perform Subscription management work. This function processes selected subscriptions and calls the + * right methods to subscribe or unsubscribe the user + * */ + +function manageSubscriptions($focus){ + + + //Process Subscription Lists first + //compare current list of subscriptions to original list and see if there are any additions + $orig_subscription_arr = array(); + $curr_subscription_arr = array(); + //build array of original subscriptions + if(isset($_REQUEST['orig_enabled_values']) && ! empty($_REQUEST['orig_enabled_values'])){ + $orig_subscription_arr = explode(",", $_REQUEST['orig_enabled_values']); + $orig_subscription_arr = process_subscriptions($orig_subscription_arr); + } + + //build array of current subscriptions + if(isset($_REQUEST['enabled_subs']) && ! empty($_REQUEST['enabled_subs'])){ + $curr_subscription_arr = explode(",", $_REQUEST['enabled_subs']); + $curr_subscription_arr = process_subscriptions($curr_subscription_arr); + } + + //compare both arrays and find differences + $i=0; + while($i<(count($curr_subscription_arr)/2)){ + //if current subscription existed in original subscription list, do nothing + if(in_array($curr_subscription_arr['campaign'.$i], $orig_subscription_arr)){ + //nothing to process + }else{ + //current subscription is new, so subscribe + subscribe($curr_subscription_arr['campaign'.$i], $curr_subscription_arr['prospect_list'.$i], $focus); + } + $i = $i +1; + } + + //Now process UnSubscription Lists first + //compare current list of subscriptions to original list and see if there are any additions + $orig_unsubscription_arr = array(); + $curr_unsubscription_arr = array(); + + //build array of original subscriptions + if(isset($_REQUEST['orig_disabled_values']) && ! empty($_REQUEST['orig_disabled_values'])){ + $orig_unsubscription_arr = explode(",", $_REQUEST['orig_disabled_values']); + $orig_unsubscription_arr = process_subscriptions($orig_unsubscription_arr); + } + + //build array of current subscriptions + if(isset($_REQUEST['disabled_subs']) && ! empty($_REQUEST['disabled_subs'])){ + $curr_unsubscription_arr = explode(",", $_REQUEST['disabled_subs']); + $curr_unsubscription_arr = process_subscriptions($curr_unsubscription_arr); + } + //compare both arrays and find differences + $i=0; + while($i<(count($curr_unsubscription_arr)/2)){ + //if current subscription existed in original subscription list, do nothing + if(in_array($curr_unsubscription_arr['campaign'.$i], $orig_unsubscription_arr)){ + //nothing to process + }else{ + //current subscription is new, so subscribe + unsubscribe($curr_unsubscription_arr['campaign'.$i], $focus); + } + $i = $i +1; + } + +} + +?> \ No newline at end of file diff --git a/modules/Campaigns/Subscriptions.tpl b/modules/Campaigns/Subscriptions.tpl new file mode 100644 index 00000000..3d972460 --- /dev/null +++ b/modules/Campaigns/Subscriptions.tpl @@ -0,0 +1,295 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} + + + + + + + + + +', + 'customLabel' => '
    {$MOD.LBL_CAMPAIGN_FREQUENCY}
    ', + ), + ), + + array ( + 'currency_id', + 'impressions', + ), + + array ( + 'budget', + 'expected_cost', + ), + + array ( + 'actual_cost', + 'expected_revenue', + ), + + array ( + array('name'=>'objective','displayParams'=>array('rows'=>8,'cols'=>80)), + ), + + array ( + array('name'=>'content','displayParams'=>array('rows'=>8, 'cols'=>80)), + ), + + ), + 'LBL_PANEL_ASSIGNMENT' => array( + array ( + array ( + 'name' => 'assigned_user_name', + 'label' => 'LBL_ASSIGNED_TO', + ), + ), + ), +) + + +); +?> \ No newline at end of file diff --git a/modules/Campaigns/metadata/listviewdefs.php b/modules/Campaigns/metadata/listviewdefs.php new file mode 100644 index 00000000..dddb56fd --- /dev/null +++ b/modules/Campaigns/metadata/listviewdefs.php @@ -0,0 +1,90 @@ + array( + 'width' => '20', + 'label' => 'LBL_LIST_CAMPAIGN_NAME', + 'link' => true, + 'default' => true), + 'STATUS' => array( + 'width' => '10', + 'label' => 'LBL_LIST_STATUS', + 'default' => true), + 'CAMPAIGN_TYPE' => array( + 'width' => '10', + 'label' => 'LBL_LIST_TYPE', + 'default' => true), + 'END_DATE' => array( + 'width' => '10', + 'label' => 'LBL_LIST_END_DATE', + 'default' => true), + + 'ASSIGNED_USER_NAME' => array( + 'width' => '8', + 'label' => 'LBL_LIST_ASSIGNED_USER', + 'module' => 'Employees', + 'id' => 'ASSIGNED_USER_ID', + 'default' => true), + 'TRACK_CAMPAIGN' => array( + 'width' => '1', + 'label' => ' ', + 'link' => true, + 'customCode' => ' ', + 'default' => true, + 'studio' => false, + 'nowrap' => true, + 'sortable' => false), + 'LAUNCH_WIZARD' => array( + 'width' => '1', + 'label' => ' ', + 'link' => true, + 'customCode' => ' ', + 'default' => true, + 'studio' => false, + 'nowrap' => true, + 'sortable' => false), + 'DATE_ENTERED' => array ( + 'width' => '10', + 'label' => 'LBL_DATE_ENTERED', + 'default' => true), +); +?> diff --git a/modules/Campaigns/metadata/popupdefs.php b/modules/Campaigns/metadata/popupdefs.php new file mode 100644 index 00000000..344f7c26 --- /dev/null +++ b/modules/Campaigns/metadata/popupdefs.php @@ -0,0 +1,78 @@ + 'Campaign', + 'varName' => 'CAMPAIGN', + 'orderBy' => 'name', + 'whereClauses' => + array('name' => 'campaigns.name'), + 'searchInputs' => + array('name'), + 'listviewdefs' => array( + 'NAME' => array( + 'width' => '20', + 'label' => 'LBL_LIST_CAMPAIGN_NAME', + 'link' => true, + 'default' => true), + 'CAMPAIGN_TYPE' => array( + 'width' => '10', + 'label' => 'LBL_LIST_TYPE', + 'default' => true), + 'STATUS' => array( + 'width' => '10', + 'label' => 'LBL_LIST_STATUS', + 'default' => true), + 'START_DATE' => array( + 'width' => '10', + 'label' => 'LBL_LIST_START_DATE', + 'default' => true), + 'END_DATE' => array( + 'width' => '10', + 'label' => 'LBL_LIST_END_DATE', + 'default' => true), + ), + 'searchdefs' => array( + 'name', + 'campaign_type', + 'status', + 'start_date', + 'end_date' + ) +); +?> \ No newline at end of file diff --git a/modules/Campaigns/metadata/searchdefs.php b/modules/Campaigns/metadata/searchdefs.php new file mode 100644 index 00000000..c2fee625 --- /dev/null +++ b/modules/Campaigns/metadata/searchdefs.php @@ -0,0 +1,60 @@ + array( + 'maxColumns' => '3', + 'widths' => array('label' => '10', 'field' => '30'), + ), + 'layout' => array( + 'basic_search' => array( + 'name', + array('name'=>'current_user_only', 'label'=>'LBL_CURRENT_USER_FILTER', 'type'=>'bool'), + + ), + 'advanced_search' => array( + 'name', + array('name'=>'start_date', 'type'=>'date', 'displayParams'=>array('showFormats'=>true)), + array('name'=>'end_date', 'type'=>'date', 'displayParams'=>array('showFormats'=>true)), + 'status', + 'campaign_type', + array('name' => 'assigned_user_id', 'label'=>'LBL_ASSIGNED_TO', 'type' => 'enum', 'function' => array('name' => 'get_user_array', 'params' => array(false))), + + ), + ), +); +?> diff --git a/modules/Campaigns/metadata/studio.php b/modules/Campaigns/metadata/studio.php new file mode 100644 index 00000000..53de57c6 --- /dev/null +++ b/modules/Campaigns/metadata/studio.php @@ -0,0 +1,66 @@ +array( + 'template'=>'xtpl', + 'template_file'=>'modules/Campaigns/DetailView.html', + 'php_file'=>'modules/Campaigns/DetailView.php', + 'type'=>'DetailView', + ), + 'LBL_EDITVIEW'=>array( + 'template'=>'xtpl', + 'template_file'=>'modules/Campaigns/EditView.html', + 'php_file'=>'modules/Campaigns/EditView.php', + 'type'=>'EditView', + ), + 'LBL_LISTVIEW'=>array( + 'template'=>'listview', + 'meta_file'=>'modules/Campaigns/listviewdefs.php', + 'type'=>'ListView', + ), + 'LBL_SEARCHFORM'=>array( + 'template'=>'xtpl', + 'template_file'=>'modules/Campaigns/SearchForm.html', + 'php_file'=>'modules/Campaigns/ListView.php', + 'type'=>'SearchForm', + ), + +); diff --git a/modules/Campaigns/metadata/subpaneldefs.php b/modules/Campaigns/metadata/subpaneldefs.php new file mode 100644 index 00000000..795959bc --- /dev/null +++ b/modules/Campaigns/metadata/subpaneldefs.php @@ -0,0 +1,205 @@ + array( + 'prospectlists' => array( + 'order' => 10, + 'sort_order' => 'asc', + 'sort_by' => 'name', + 'module' => 'ProspectLists', + 'get_subpanel_data'=>'prospectlists', + 'set_subpanel_data'=>'prospectlists', + 'subpanel_name' => 'default', + 'title_key' => 'LBL_PROSPECT_LIST_SUBPANEL_TITLE', + ), + 'tracked_urls' => array( + 'order' => 15, + 'sort_order' => 'asc', + 'sort_by' => 'tracker_name', + 'module' => 'CampaignTrackers', + 'get_subpanel_data'=>'tracked_urls', + 'subpanel_name' => 'default', + 'title_key' => 'LBL_TRACKED_URLS_SUBPANEL_TITLE', + ), + 'emailmarketing' => array( + 'order' => 20, + 'sort_order' => 'desc', + 'sort_by' => 'date_start', + 'module' => 'EmailMarketing', + 'get_subpanel_data'=>'emailmarketing', + 'subpanel_name' => 'default', + 'title_key' => 'LBL_EMAIL_MARKETING_SUBPANEL_TITLE', + ), + + //subpanels for the tracking view... + 'track_queue' => array( + 'order' => 100, + 'module' => 'EmailMan', + 'get_subpanel_data'=>'function:get_queue_items', + 'function_parameters'=>array('EMAIL_MARKETING_ID_VALUE'=>'','distinct'=>'emailman.id', 'group_by'=>'emailman.related_id,emailman.marketing_id'), + 'subpanel_name' => 'default', + 'title_key' => 'LBL_MESSAGE_QUEUE_TITLE', + 'sort_order' => 'desc', + ), + 'targeted' => array( + 'order' => 110, + 'module' => 'CampaignLog', + 'get_subpanel_data'=>"function:track_log_entries", + 'function_parameters'=>array(0=>'targeted','EMAIL_MARKETING_ID_VALUE'=>'',/*'distinct'=>'campaign_log.target_id','group_by'=>'campaign_log.target_id, campaign_log.marketing_id'*/), + 'subpanel_name' => 'default', + 'title_key' => 'LBL_LOG_ENTRIES_TARGETED_TITLE', + 'sort_order' => 'desc', + 'sort_by' => 'campaign_log.id' + ), + 'viewed' => array( + 'order' => 120, + 'module' => 'CampaignLog', + 'get_subpanel_data'=>"function:track_log_entries", + 'subpanel_name' => 'default', + 'function_parameters'=>array(0=>'viewed','EMAIL_MARKETING_ID_VALUE'=>'',/*'group_by'=>'campaign_log.target_id','distinct'=>'campaign_log.target_id'*/), + 'title_key' => 'LBL_LOG_ENTRIES_VIEWED_TITLE', + 'sort_order' => 'desc', + 'sort_by' => 'campaign_log.id' + ), + 'link' => array( + 'order' => 130, + 'module' => 'CampaignLog', + 'get_subpanel_data'=>"function:track_log_entries", + 'function_parameters'=>array(0=>'link','EMAIL_MARKETING_ID_VALUE'=>'',/*'group_by'=>'campaign_log.target_id','distinct'=>'campaign_log.target_id'*/), + 'subpanel_name' => 'default', + 'title_key' => 'LBL_LOG_ENTRIES_LINK_TITLE', + 'sort_order' => 'desc', + 'sort_by' => 'campaign_log.id' + ), + 'lead' => array( + 'order' => 140, + 'module' => 'CampaignLog', + 'get_subpanel_data'=>"function:track_log_entries", + 'function_parameters'=>array(0=>'lead','EMAIL_MARKETING_ID_VALUE'=>'',/*'group_by'=>'campaign_log.target_id','distinct'=>'campaign_log.target_id'*/), + 'subpanel_name' => 'default', + 'title_key' => 'LBL_LOG_ENTRIES_LEAD_TITLE', + 'sort_order' => 'desc', + 'sort_by' => 'campaign_log.id' + ), + 'contact' => array( + 'order' => 150, + 'module' => 'CampaignLog', + 'get_subpanel_data'=>"function:track_log_entries", + 'function_parameters'=>array(0=>'contact','EMAIL_MARKETING_ID_VALUE'=>'',/*'group_by'=>'campaign_log.target_id','distinct'=>'campaign_log.target_id'*/), + 'subpanel_name' => 'default', + 'title_key' => 'LBL_LOG_ENTRIES_CONTACT_TITLE', + 'sort_order' => 'desc', + 'sort_by' => 'campaign_log.id' + ), + 'invalid email' => array( + 'order' => 160, + 'module' => 'CampaignLog', + 'get_subpanel_data'=>"function:track_log_entries", + 'function_parameters'=>array(0=>'invalid email','EMAIL_MARKETING_ID_VALUE'=>'',/*'group_by'=>'campaign_log.target_id','distinct'=>'campaign_log.target_id'*/), + 'subpanel_name' => 'default', + 'title_key' => 'LBL_LOG_ENTRIES_INVALID_EMAIL_TITLE', + 'sort_order' => 'desc', + 'sort_by' => 'campaign_log.id' + ), + 'send error' => array( + 'order' => 170, + 'module' => 'CampaignLog', + 'get_subpanel_data'=>"function:track_log_entries", + 'function_parameters'=>array(0=>'send error','EMAIL_MARKETING_ID_VALUE'=>'',/*'group_by'=>'campaign_log.target_id','distinct'=>'campaign_log.target_id'*/), + 'subpanel_name' => 'default', + 'title_key' => 'LBL_LOG_ENTRIES_SEND_ERROR_TITLE', + 'sort_order' => 'desc', + 'sort_by' => 'campaign_log.id' + ), + 'removed' => array( + 'order' => 180, + 'module' => 'CampaignLog', + 'get_subpanel_data'=>"function:track_log_entries", + 'function_parameters'=>array(0=>'removed','EMAIL_MARKETING_ID_VALUE'=>'',/*'group_by'=>'campaign_log.target_id','distinct'=>'campaign_log.target_id'*/), + 'subpanel_name' => 'default', + 'title_key' => 'LBL_LOG_ENTRIES_REMOVED_TITLE', + 'sort_order' => 'desc', + 'sort_by' => 'campaign_log.id' + ), + 'blocked' => array( + 'order' => 185, + 'module' => 'CampaignLog', + 'get_subpanel_data'=>"function:track_log_entries", + 'function_parameters'=>array(0=>'blocked','EMAIL_MARKETING_ID_VALUE'=>'',/*'group_by'=>'campaign_log.target_id','distinct'=>'campaign_log.target_id'*/), + 'subpanel_name' => 'default', + 'title_key' => 'LBL_LOG_ENTRIES_BLOCKEDD_TITLE', + 'sort_order' => 'desc', + 'sort_by' => 'campaign_log.id' + ), + 'accounts' => array( + 'order' => 190, + 'sort_order' => 'desc', + 'sort_by' => 'name', + 'module' => 'Accounts', + 'get_subpanel_data'=>'accounts', + 'subpanel_name' => 'default', + 'title_key' => 'LBL_CAMPAIGN_ACCOUNTS_SUBPANEL_TITLE', + 'top_buttons' => array(), + ), + 'leads' => array( + 'order' => 195, + 'sort_order' => 'desc', + 'sort_by' => 'name', + 'module' => 'Leads', + 'get_subpanel_data'=>'leads', + 'subpanel_name' => 'default', + 'title_key' => 'LBL_CAMPAIGN_LEAD_SUBPANEL_TITLE', + 'top_buttons' => array(), + ), + 'opportunities' => array( + 'order' => 200, + 'sort_order' => 'desc', + 'sort_by' => 'name', + 'module' => 'Opportunities', + 'get_subpanel_data'=>'opportunities', + 'subpanel_name' => 'default', + 'title_key' => 'LBL_OPPORTUNITY_SUBPANEL_TITLE', + 'top_buttons' => array(), + ), + + ), +); +?> \ No newline at end of file diff --git a/modules/Campaigns/metadata/subpanels/ForEmailMarketing.php b/modules/Campaigns/metadata/subpanels/ForEmailMarketing.php new file mode 100644 index 00000000..a119aeb1 --- /dev/null +++ b/modules/Campaigns/metadata/subpanels/ForEmailMarketing.php @@ -0,0 +1,51 @@ + array( + array('widget_class' => 'SubPanelTopCreateButton'), + array('widget_class' => 'SubPanelTopSelectButton'), + ), + + 'where' => '', + + + 'list_fields' => array(), +); +?> \ No newline at end of file diff --git a/modules/Campaigns/metadata/subpanels/default.php b/modules/Campaigns/metadata/subpanels/default.php new file mode 100644 index 00000000..9b5f5970 --- /dev/null +++ b/modules/Campaigns/metadata/subpanels/default.php @@ -0,0 +1,75 @@ + array( + array('widget_class' => 'SubPanelTopCreateButton'), + array('widget_class' => 'SubPanelTopSelectButton', 'popup_module' => 'Campaigns'), + ), + + 'where' => '', + +'list_fields' => array( + 'name'=>array( + 'name' => 'name', + 'vname' => 'LBL_LIST_CAMPAIGN_NAME', + 'widget_class' => 'SubPanelDetailViewLink', + 'width' => '85%', + ), + 'status'=>array( + 'name' => 'status', + 'vname' => 'LBL_LIST_STATUS', + 'width' => '15%', + ), + 'edit_button'=>array( + 'vname' => 'LBL_EDIT_BUTTON', + 'widget_class' => 'SubPanelEditButton', + 'module' => 'Campaigns', + 'width' => '5%', + ), + 'remove_button'=>array( + 'vname' => 'LBL_REMOVE', + 'widget_class' => 'SubPanelRemoveButton', + 'module' => 'Campgains', + 'width' => '5%', + ), + ), +); + +?> \ No newline at end of file diff --git a/modules/Campaigns/tpls/WizardCampaignBudget.tpl b/modules/Campaigns/tpls/WizardCampaignBudget.tpl new file mode 100644 index 00000000..23568ebc --- /dev/null +++ b/modules/Campaigns/tpls/WizardCampaignBudget.tpl @@ -0,0 +1,137 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +/********************************************************************************* + + ********************************************************************************/ +*} + +

    {$title}

    +{$description} +

    + +
    + + + + + + + + + + + + + + + + + + + +
    + + +
    + +
    + + + + + + + + + +
    {$MOD.LBL_ALREADY_SUBSCRIBED_HEADER}{$MOD.LBL_UNSUBSCRIBED_HEADER} + + +
    +
    +
      + {foreach from=$enabled_subs key=dirname item=name} +
    • {$name}
    • + {/foreach} +
    +
    +
    +
    +
      + {foreach from=$disabled_subs key=dirname item=name} +
    • {$name}
    • + {/foreach} +
    +
    +
    +
    + + + + + +
    + + + +
    +
    + + + + + diff --git a/modules/Campaigns/TrackDetailView.php b/modules/Campaigns/TrackDetailView.php new file mode 100644 index 00000000..1fafeaf4 --- /dev/null +++ b/modules/Campaigns/TrackDetailView.php @@ -0,0 +1,269 @@ +processSugarBean("CAMPAIGN", $focus, $offset); + if($result == null) { + sugar_die($app_strings['ERROR_NO_RECORD']); + } + $focus=$result; +} else { + header("Location: index.php?module=Accounts&action=index"); +} + +// if campaign type is set to newsletter, then include newsletter detail view.. +// ..else default to legacy detail view + +// include ('modules/Campaigns/NewsLetterTrackDetailView.php'); + +if(isset($focus->campaign_type) && $focus->campaign_type == "NewsLetter"){ + echo getClassicModuleTitle($mod_strings['LBL_MODULE_NAME'], array($mod_strings['LBL_NEWSLETTER'],$focus->name), true); +} else{ + echo getClassicModuleTitle($mod_strings['LBL_MODULE_NAME'], array($mod_strings['LBL_MODULE_NAME'],$focus->name), true); +} + + $GLOBALS['log']->info("Campaign detail view"); + $smarty = new Sugar_Smarty(); + $smarty->assign("MOD", $mod_strings); + $smarty->assign("APP", $app_strings); + + $smarty->assign("GRIDLINE", $gridline); + $smarty->assign("PRINT_URL", "index.php?".$GLOBALS['request_string']); + $smarty->assign("ID", $focus->id); + $smarty->assign("ASSIGNED_TO", $focus->assigned_user_name); + $smarty->assign("STATUS", $app_list_strings['campaign_status_dom'][$focus->status]); + $smarty->assign("NAME", $focus->name); + $smarty->assign("TYPE", $app_list_strings['campaign_type_dom'][$focus->campaign_type]); + $smarty->assign("START_DATE", $focus->start_date); + $smarty->assign("END_DATE", $focus->end_date); + + $smarty->assign("BUDGET", $focus->budget); + $smarty->assign("ACTUAL_COST", $focus->actual_cost); + $smarty->assign("EXPECTED_COST", $focus->expected_cost); + $smarty->assign("EXPECTED_REVENUE", $focus->expected_revenue); + + + $smarty->assign("OBJECTIVE", nl2br($focus->objective)); + $smarty->assign("CONTENT", nl2br($focus->content)); + $smarty->assign("DATE_MODIFIED", $focus->date_modified); + $smarty->assign("DATE_ENTERED", $focus->date_entered); + + $smarty->assign("CREATED_BY", $focus->created_by_name); + $smarty->assign("MODIFIED_BY", $focus->modified_by_name); + $smarty->assign("TRACKER_URL", $sugar_config['site_url'] . '/campaign_tracker.php?track=' . $focus->tracker_key); + $smarty->assign("TRACKER_COUNT", intval($focus->tracker_count)); + $smarty->assign("TRACKER_TEXT", $focus->tracker_text); + $smarty->assign("REFER_URL", $focus->refer_url); + + if(isset($focus->campaign_type) && $focus->campaign_type == "Email" || $focus->campaign_type == "NewsLetter") { + $smarty->assign("TRACK_DELETE_BUTTON",""); + } + + $currency = new Currency(); + if(isset($focus->currency_id) && !empty($focus->currency_id)) + { + $currency->retrieve($focus->currency_id); + if( $currency->deleted != 1){ + $smarty->assign("CURRENCY", $currency->iso4217 .' '.$currency->symbol ); + }else $smarty->assign("CURRENCY", $currency->getDefaultISO4217() .' '.$currency->getDefaultCurrencySymbol() ); + }else{ + + $smarty->assign("CURRENCY", $currency->getDefaultISO4217() .' '.$currency->getDefaultCurrencySymbol() ); + + } + global $current_user; + if(is_admin($current_user) && $_REQUEST['module'] != 'DynamicLayout' && !empty($_SESSION['editinplace'])){ + + $smarty->assign("ADMIN_EDIT","".SugarThemeRegistry::current()->getImage("EditLayout","border='0' alt='Edit Layout' align='bottom'").""); + } + + $detailView->processListNavigation($xtpl, "CAMPAIGN", $offset, $focus->is_AuditEnabled()); + // adding custom fields: + require_once('modules/DynamicFields/templates/Files/DetailView.php'); + + + //if this is a newsletter, we need to build dropdown + $selected_marketing_id = ''; + if(isset($focus->campaign_type)){ + //we need to build the dropdown of related marketing values + $options_str = ""; + //populate the dropdown + $smarty->assign("FILTER_LABEL", $mod_strings['LBL_FILTER_CHART_BY']); + $smarty->assign("MKT_DROP_DOWN",$options_str); + } +//add chart +$seps = array("-", "/"); +$dates = array(date($GLOBALS['timedate']->dbDayFormat), $GLOBALS['timedate']->dbDayFormat); +$dateFileNameSafe = str_replace($seps, "_", $dates); +$cache_file_name = $current_user->getUserPrivGuid()."_campaign_response_by_activity_type_".$dateFileNameSafe[0]."_".$dateFileNameSafe[1].".xml"; +$cache_file_name_roi = $current_user->getUserPrivGuid()."_campaign_response_by_roi_".$dateFileNameSafe[0]."_".$dateFileNameSafe[1].".xml"; +$chart= new campaign_charts(); + + //if marketing id has been selected, then set "latest_marketing_id" to the selected value + //latest marketing id will be passed in to filter the charts and subpanels + + if(!empty($selected_marketing_id)){$latest_marketing_id = $selected_marketing_id;} + if(empty($latest_marketing_id) || $latest_marketing_id === 'all'){ + $smarty->assign("MY_CHART", $chart->campaign_response_by_activity_type($app_list_strings['campainglog_activity_type_dom'],$app_list_strings['campainglog_target_type_dom'],$focus->id,$sugar_config['tmp_dir'].$cache_file_name,true)); + }else{ + $smarty->assign("MY_CHART", $chart->campaign_response_by_activity_type($app_list_strings['campainglog_activity_type_dom'],$app_list_strings['campainglog_target_type_dom'],$focus->id,$sugar_config['tmp_dir'].$cache_file_name,true,$latest_marketing_id)); + } + +//end chart +//custom chart code + require_once('include/SugarCharts/SugarChartFactory.php'); + $sugarChart = SugarChartFactory::getInstance(); + $resources = $sugarChart->getChartResources(); + $smarty->assign('chartResources', $resources); + +echo $smarty->fetch('modules/Campaigns/TrackDetailView.tpl'); + +require_once('include/SubPanel/SubPanelTiles.php'); +$subpanel = new SubPanelTiles($focus, 'Campaigns'); + //if latest marketing id is empty, or if it is set to 'all'', then do no filtering, otherwise filter.. + //.. out the chart and subpanels by marketing id + if(empty($latest_marketing_id) || $latest_marketing_id === 'all'){ + //do nothing, no filtering is needed + }else{ + //get array of layout defs + $layoutDefsArr= $subpanel->subpanel_definitions->layout_defs; + + //iterate through layout defs for processing of subpanels. If a marketing Id is specified, then we need to... + //.. filter the subpanels by it so they match the chart rendered in code above. + foreach($layoutDefsArr as $subpanels_name => $subpanels){ + + //process each subpanel definition + foreach($subpanels as $subpane_key => $subpane){ + + //see if "function_parameters" key exists in subpanel properties array + if (isset($subpane['function_parameters'])){ + //if a function_parameters property key exists, then process further + $functionParamsArr = $subpane['function_parameters'];//$panelProperty; + + //Check the array of function parameters and see if + //one exists for market value id. + if (isset($functionParamsArr['EMAIL_MARKETING_ID_VALUE'])){ + //We found the property, lets fill in the marketing id value... + //.. into the subpanel object, using the keys of the array that.. + //.. we used to get to thi property + $subpanel->subpanel_definitions->layout_defs[$subpanels_name][$subpane_key]['function_parameters']['EMAIL_MARKETING_ID_VALUE'] = $latest_marketing_id; + } + }//end if (isset($subpane['function_parameters'])){ + }//end foreach($subpanels as $subpane_key => $subpane){ + + }//_pp($subpanel->subpanel_definitions->layout_defs); + }//end else + +$alltabs=$subpanel->subpanel_definitions->get_available_tabs(); +if (!empty($alltabs)) { + + foreach ($alltabs as $name) { + if ($name == 'prospectlists' || $name=='emailmarketing' || $name == 'tracked_urls') { + $subpanel->subpanel_definitions->exclude_tab($name); + } + } +} +echo $subpanel->display(); +?> \ No newline at end of file diff --git a/modules/Campaigns/TrackDetailView.tpl b/modules/Campaigns/TrackDetailView.tpl new file mode 100644 index 00000000..b71a714f --- /dev/null +++ b/modules/Campaigns/TrackDetailView.tpl @@ -0,0 +1,173 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +/********************************************************************************* + + ********************************************************************************/ +*} + +{$chartResources} + + + + + + + + + + +
    +
    + + + + + + + + + + + + {$TRACK_DELETE_BUTTON} +
    + + + {$ADMIN_EDIT} + {$ADMIN_EDIT}
    +
    + + +{$PAGINATION} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    {$MOD.LBL_NAME}{$NAME}{$MOD.LBL_ASSIGNED_TO}{$ASSIGNED_TO}
    {$MOD.LBL_CAMPAIGN_STATUS}{$STATUS}{$MOD.LBL_TEAM}{$TEAM_NAME}  
    {$MOD.LBL_CAMPAIGN_START_DATE}{$START_DATE}{$APP.LBL_DATE_MODIFIED} {$DATE_MODIFIED} {$APP.LBL_BY} {$MODIFIED_BY}
    {$MOD.LBL_CAMPAIGN_END_DATE}{$END_DATE}{$APP.LBL_DATE_ENTERED} {$DATE_ENTERED} {$APP.LBL_BY} {$CREATED_BY}
    {$MOD.LBL_CAMPAIGN_TYPE}{$TYPE}  
        
    {$MOD.LBL_CAMPAIGN_BUDGET} ({$CURRENCY}){$BUDGET}{$MOD.LBL_CAMPAIGN_ACTUAL_COST} ({$CURRENCY}){$ACTUAL_COST}
    {$MOD.LBL_CAMPAIGN_EXPECTED_REVENUE} ({$CURRENCY}){$EXPECTED_REVENUE}{$MOD.LBL_CAMPAIGN_EXPECTED_COST} ({$CURRENCY}){$EXPECTED_COST}
        
    {$MOD.LBL_CAMPAIGN_OBJECTIVE}{$OBJECTIVE}
    {$MOD.LBL_CAMPAIGN_CONTENT}{$CONTENT}
    +
    + + + + + + + + + +
    {$FILTER_LABEL}{$MKT_DROP_DOWN} 
    {$MY_CHART}
    + + + + + + + +{$SUBPANEL} + \ No newline at end of file diff --git a/modules/Campaigns/Tracker.php b/modules/Campaigns/Tracker.php new file mode 100644 index 00000000..df320932 --- /dev/null +++ b/modules/Campaigns/Tracker.php @@ -0,0 +1,92 @@ +quote($track); + +if(preg_match('/^[0-9A-Za-z\-]*$/', $track)) +{ + $query = "SELECT tracker_url FROM campaign_trkrs WHERE id='$track'"; + $res = $db->query($query); + + $row = $db->fetchByAssoc($res); + + $redirect_URL = $row['tracker_url']; + sugar_cleanup(); + header("Location: $redirect_URL"); +} +else +{ + sugar_cleanup(); +} +exit; +?> diff --git a/modules/Campaigns/WebToLead.js b/modules/Campaigns/WebToLead.js new file mode 100644 index 00000000..165e5f72 --- /dev/null +++ b/modules/Campaigns/WebToLead.js @@ -0,0 +1,63 @@ +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ +var grid2,grid3,grid4,grid3F,grid4F;var add_all_fields=SUGAR.language.get('app_strings','LBL_ADD_ALL_LEAD_FIELDS');var remove_all_fields=SUGAR.language.get('app_strings','LBL_REMOVE_ALL_LEAD_FIELDS');function addGrids(form_name){if(!check_form('WebToLeadCreation')){return false;} +else{grid3=SUGAR_GRID_grid1;grid4=SUGAR_GRID_grid2;var webFormDiv=document.getElementById('webformfields');addCols(grid3,'colsFirst',webFormDiv);addCols(grid4,'colsSecond',webFormDiv);return true;}} +function checkFields(REQUIRED_LEAD_FIELDS,LEAD_SELECT_FIELDS){grid2=SUGAR_GRID_grid0;grid3=SUGAR_GRID_grid1;grid4=SUGAR_GRID_grid2;var reqFields='';for(var i=0;i1){addRemove.setAttribute('value',Add_All_Fields);addRemove.setAttribute('title',Add_All_Fields);} +else{addRemove.setAttribute('value',Remove_All_Fields);addRemove.setAttribute('title',Remove_All_Fields);}} +function dragDropAllFields(Add_All_Fields,Remove_All_Fields){grid2=SUGAR_GRID_grid0;grid3=SUGAR_GRID_grid1;grid4=SUGAR_GRID_grid2;var addRemove=document.getElementById("lead_add_remove_button");var availibleSet=grid2.getRecordSet();var availibleCount=availibleSet.getLength();if(addRemove.value==Add_All_Fields&&availibleCount>1){for(var i=0;i=0;i--){if(grid2.getRecord(i)!=null&&grid2.getRecord(i).getData()[0]!=" "){grid2.deleteRow(i);}}} +else if(addRemove.value==Remove_All_Fields){var count=0;if(grid3.getRecordSet().getLength()>=grid4.getRecordSet().getLength()){count=grid3.getRecordSet().getLength();} +else{count=grid4.getRecordSet().getLength();} +for(var i=0;i=0;i--){if(grid4.getRecord(i)!=null&&grid4.getRecord(i).getData()[0]!=" "){grid4.deleteRow(i);} +if(grid3.getRecord(i)!=null&&grid3.getRecord(i).getData()[0]!=" "){grid3.deleteRow(i);}}} +displayAddRemoveButtons(Add_All_Fields,Remove_All_Fields);} +function addCols(grid,colsNumber,webFormDiv){for(var i=0;i'Contacts', 'Account'=>'Accounts', 'Opportunity'=>'Opportunities', 'Case'=>'Cases', 'Note'=>'Notes', 'Call'=>'Calls', 'Email'=>'Emails', 'Meeting'=>'Meetings', 'Task'=>'Tasks', 'Lead'=>'Leads','Bug'=>'Bugs', + +); + +/** + * To make your changes upgrade safe create a file called leadCapture_override.php and place the changes there + */ +$users = array( + 'PUT A RANDOM KEY FROM THE WEBSITE HERE' => array('name'=>'PUT THE USER_NAME HERE', 'pass'=>'PUT THE USER_HASH FOR THE RESPECTIVE USER HERE'), +); + +if (isset($_POST['campaign_id']) && !empty($_POST['campaign_id'])) { + //adding the client ip address + $_POST['client_id_address'] = query_client_ip(); + $campaign_id=$_POST['campaign_id']; + $campaign = new Campaign(); + $camp_query = "select name,id from campaigns where id='$campaign_id'"; + $camp_query .= " and deleted=0"; + $camp_result=$campaign->db->query($camp_query); + $camp_data=$campaign->db->fetchByAssoc($camp_result); + + if (isset($_REQUEST['assigned_user_id']) && !empty($_REQUEST['assigned_user_id'])) { + $current_user = new User(); + $current_user->retrieve($_REQUEST['assigned_user_id']); + } + + if(isset($camp_data) && $camp_data != null ){ + $leadForm = new LeadFormBase(); + $lead = new Lead(); + $prefix = ''; + if(!empty($_POST['prefix'])){ + $prefix = $_POST['prefix']; + } + + if(empty($lead->id)) { + $lead->id = create_guid(); + $lead->new_with_id = true; + } + $GLOBALS['check_notify'] = true; + + //bug: 42398 - have to unset the id from the required_fields since it is not populated in the $_POST + unset($lead->required_fields['id']); + unset($lead->required_fields['team_name']); + unset($lead->required_fields['team_count']); + $lead = $leadForm->handleSave($prefix, false, true, false, $lead); + + if(!empty($lead)){ + + //create campaign log + $camplog = new CampaignLog(); + $camplog->campaign_id = $_POST['campaign_id']; + $camplog->related_id = $lead->id; + $camplog->related_type = $lead->module_dir; + $camplog->activity_type = "lead"; + $camplog->target_type = $lead->module_dir; + $campaign_log->activity_date=$timedate->now(); + $camplog->target_id = $lead->id; + $camplog->save(); + + //link campaignlog and lead + + if(isset($_POST['webtolead_email1']) && $_POST['webtolead_email1'] != null){ + $lead->email1 = $_POST['webtolead_email1']; + } + if(isset($_POST['webtolead_email2']) && $_POST['webtolead_email2'] != null){ + $lead->email2 = $_POST['webtolead_email2']; + } + $lead->load_relationship('campaigns'); + $lead->campaigns->add($camplog->id); + if(!empty($GLOBALS['check_notify'])) { + $lead->save($GLOBALS['check_notify']); + } + else { + $lead->save(FALSE); + } + } + + //in case there are forms out there still using email_opt_out + if(isset($_POST['webtolead_email_opt_out']) || isset($_POST['email_opt_out'])){ + + if(isset ($lead->email1) && !empty($lead->email1)){ + $sea = new SugarEmailAddress(); + $sea->AddUpdateEmailAddress($lead->email1,0,1); + } + if(isset ($lead->email2) && !empty($lead->email2)){ + $sea = new SugarEmailAddress(); + $sea->AddUpdateEmailAddress($lead->email2,0,1); + + } + } + if(isset($_POST['redirect_url']) && !empty($_POST['redirect_url'])){ + // Get the redirect url, and make sure the query string is not too long + $redirect_url = $_POST['redirect_url']; + $query_string = ''; + $first_char = '&'; + if(strpos($redirect_url, '?') === FALSE){ + $first_char = '?'; + } + $first_iteration = true; + $get_and_post = array_merge($_GET, $_POST); + foreach($get_and_post as $param => $value) { + + if($param == 'redirect_url' || $param == 'submit') + continue; + + if($first_iteration){ + $first_iteration = false; + $query_string .= $first_char; + } + else{ + $query_string .= "&"; + } + $query_string .= "{$param}=".urlencode($value); + } + if(empty($lead)) { + if($first_iteration){ + $query_string .= $first_char; + } + else{ + $query_string .= "&"; + } + $query_string .= "error=1"; + } + + $redirect_url = $redirect_url.$query_string; + + // Check if the headers have been sent, or if the redirect url is greater than 2083 characters (IE max URL length) + // and use a javascript form submission if that is the case. + if(headers_sent() || strlen($redirect_url) > 2083){ + echo 'SugarCRM'; + echo '
    '; + + foreach($_POST as $param => $value) { + if($param != 'redirect_url' ||$param != 'submit') { + echo ''; + } + } + if(empty($lead)) { + echo ''; + } + echo '
    '; + echo ''; + } + else{ + header("Location: {$redirect_url}"); + die(); + } + } + else{ + echo $mod_strings['LBL_THANKS_FOR_SUBMITTING_LEAD']; + } + sugar_cleanup(); + // die to keep code from running into redirect case below + die(); + } + else{ + echo $mod_strings['LBL_SERVER_IS_CURRENTLY_UNAVAILABLE']; + } +} + +if (!empty($_POST['redirect'])) { + if(headers_sent()){ + echo 'SugarCRM'; + echo '
    '; + echo '
    '; + echo ''; + } + else{ + header("Location: {$_POST['redirect']}"); + die(); + } +} +echo $mod_strings['LBL_SERVER_IS_CURRENTLY_UNAVAILABLE']; +?> diff --git a/modules/Campaigns/WebToLeadCreation.html b/modules/Campaigns/WebToLeadCreation.html new file mode 100644 index 00000000..c469ebe1 --- /dev/null +++ b/modules/Campaigns/WebToLeadCreation.html @@ -0,0 +1,204 @@ + + + + + + + + +{JAVASCRIPT} +
    + + + + + + + +
    + + + + + + + + + + + +
    + {TITLE1} +
    +

    {MOD.LBL_DRAG_DROP_COLUMNS}

    +
    + + + + + + + + +
    + +
    + {DRAG_DROP_CHOOSER_WEB_TO_LEAD} +
    +
    +
    +
    + + + + + + +
    + +
    +
    +
    + + + +
    + + + diff --git a/modules/Campaigns/WebToLeadCreation.php b/modules/Campaigns/WebToLeadCreation.php new file mode 100644 index 00000000..72b635c8 --- /dev/null +++ b/modules/Campaigns/WebToLeadCreation.php @@ -0,0 +1,308 @@ +assign("MOD", $mod_strings); +$xtpl->assign("APP", $app_strings); +if(isset($_REQUEST['module'])) +{ + $xtpl->assign("MODULE", $_REQUEST['module']); +} +if(isset($_REQUEST['return_module'])) +{ + $xtpl->assign("RETURN_MODULE", $_REQUEST['return_module']); +} +if(isset($_REQUEST['return_id'])) +{ + $xtpl->assign("RETURN_ID", $_REQUEST['return_id']); +} +if(isset($_REQUEST['return_id'])) +{ + $xtpl->assign("RETURN_ACTION", $_REQUEST['return_action']); +} +if(isset($_REQUEST['record'])) +{ + $xtpl->assign("RECORD", $_REQUEST['record']); +} + +global $theme; +global $currentModule; + +$ev = new EditView; + +$xtpl->assign("TITLE1", + $this->getModuleTitle( + true, + array( + $this->_getModuleTitleListParam(), + $mod_strings['LBL_WEB_TO_LEAD_FORM_TITLE1'] + ) + ) + ); + +$xtpl->assign("TITLE2", + $this->getModuleTitle( + true, + array( + $this->_getModuleTitleListParam(), + $mod_strings['LBL_WEB_TO_LEAD_FORM_TITLE2'] + ) + ) + ); + +$site_url = $sugar_config['site_url']; +$web_post_url = $site_url.'/index.php?entryPoint=WebToLeadCapture'; +$json = getJSONobj(); +// Users Popup +$popup_request_data = array( + 'call_back_function' => 'set_return', + 'form_name' => 'WebToLeadCreation', + 'field_to_name_array' => array( + 'id' => 'assigned_user_id', + 'user_name' => 'assigned_user_name', + ), + ); +$xtpl->assign('encoded_users_popup_request_data', $json->encode($popup_request_data)); + +//Campaigns popup +$popup_request_data = array( + 'call_back_function' => 'set_return', + 'form_name' => 'WebToLeadCreation', + 'field_to_name_array' => array( + 'id' => 'campaign_id', + 'name' => 'campaign_name', + ), +); +$encoded_users_popup_request_data = $json->encode($popup_request_data); +$xtpl->assign('encoded_campaigns_popup_request_data' , $json->encode($popup_request_data)); + +//create the cancel button +$cancel_buttons_html = ""; +$xtpl->assign("CANCEL_BUTTON", $cancel_buttons_html ); + +$field_defs_js = "var field_defs = {'Contacts':["; + +$count= 0; +foreach($lead->field_defs as $field_def) +{ + $email_fields = false; + if($field_def['name']== 'webtolead_email1' || $field_def['name']== 'webtolead_email2') + { + $email_fields = true; + } + if($field_def['name']!= 'account_name'){ + if( ( $field_def['type'] == 'relate' && empty($field_def['custom_type']) ) + || $field_def['type'] == 'assigned_user_name' || $field_def['type'] =='link' + || (isset($field_def['source']) && $field_def['source']=='non-db' && !$email_fields) || $field_def['type'] == 'id') + { + continue; + } + } + if($field_def['name']== 'deleted' || $field_def['name']=='converted' || $field_def['name']=='date_entered' + || $field_def['name']== 'date_modified' || $field_def['name']=='modified_user_id' + || $field_def['name']=='assigned_user_id' || $field_def['name']=='created_by' + || $field_def['name']=='team_id') + { + continue; + } + + + $field_def['vname'] = preg_replace('/:$/','',translate($field_def['vname'],'Leads')); + + //$cols_name = "{'".$field_def['vname']."'}"; + $col_arr = array(); + if((isset($field_def['required']) && $field_def['required'] != null && $field_def['required'] != 0) + || $field_def['name']=='last_name' + ){ + $cols_name=$field_def['vname'].' '.$app_strings['LBL_REQUIRED_SYMBOL']; + $col_arr[0]=$cols_name; + $col_arr[1]=$field_def['name']; + $col_arr[2]=true; + } + else{ + $cols_name=$field_def['vname']; + $col_arr[0]=$cols_name; + $col_arr[1]=$field_def['name']; + } + if (! in_array($cols_name, $fields)) + { + array_push($fields,$col_arr); + } + $count++; +} + +$xtpl->assign("WEB_POST_URL",$web_post_url); +//$xtpl->assign("LEAD_SELECT_FIELDS",'MOD.LBL_SELECT_LEAD_FIELDS'); + +require_once('include/QuickSearchDefaults.php'); +$qsd = new QuickSearchDefaults(); +$sqs_objects = array('account_name' => $qsd->getQSParent(), + 'assigned_user_name' => $qsd->getQSUser(), + 'campaign_name' => $qsd->getQSCampaigns(), + + ); +$quicksearch_js = ''; +$xtpl->assign("JAVASCRIPT", $quicksearch_js); + + + +if (empty($focus->assigned_user_id) && empty($focus->id)) $focus->assigned_user_id = $current_user->id; +if (empty($focus->assigned_name) && empty($focus->id)) $focus->assigned_user_name = $current_user->user_name; +$xtpl->assign("ASSIGNED_USER_OPTIONS", get_select_options_with_id(get_user_array(TRUE, "Active", $focus->assigned_user_id), $focus->assigned_user_id)); +$xtpl->assign("ASSIGNED_USER_NAME", $focus->assigned_user_name); +$xtpl->assign("ASSIGNED_USER_ID", $focus->assigned_user_id ); + +$xtpl->assign("REDIRECT_URL_DEFAULT",'http://'); + +//required fields on Webtolead form +$campaign= new Campaign(); + +$javascript = new javascript(); +$javascript->setFormName('WebToLeadCreation'); +$javascript->setSugarBean($lead); +$javascript->addAllFields(''); +//$javascript->addFieldGeneric('redirect_url', '', 'LBL_REDIRECT_URL' ,'true'); +$javascript->addFieldGeneric('campaign_name', '', 'LBL_RELATED_CAMPAIGN' ,'true'); +$javascript->addFieldGeneric('assigned_user_name', '', 'LBL_ASSIGNED_TO' ,'true'); +$javascript->addToValidateBinaryDependency('campaign_name', 'alpha', $app_strings['ERR_SQS_NO_MATCH_FIELD'] . $mod_strings['LBL_LEAD_NOTIFY_CAMPAIGN'], 'false', '', 'campaign_id'); +$javascript->addToValidateBinaryDependency('assigned_user_name', 'alpha', $app_strings['ERR_SQS_NO_MATCH_FIELD'] . $app_strings['LBL_ASSIGNED_TO'], 'false', '', 'assigned_user_id'); +echo $javascript->getScript(); + +$json = getJSONobj(); +$lead_fields = $json->encode($fields); +$xtpl->assign("LEAD_FIELDS",$lead_fields); +$classname = "SUGAR_GRID"; +$xtpl->assign("CLASSNAME",$classname); +$xtpl->assign("DRAG_DROP_CHOOSER_WEB_TO_LEAD",constructDDWebToLeadFields($fields,$classname)); + +$xtpl->parse("main"); +$xtpl->out("main"); +/* +$str = ""; +echo $str; +*/ +/* + *This function constructs Drag and Drop multiselect box of subscriptions for display in manage subscription form +*/ +function constructDDWebToLeadFields($fields,$classname){ +require_once("include/templates/TemplateDragDropChooser.php"); +global $mod_strings; +$d2 = array(); + //now call function that creates javascript for invoking DDChooser object + $dd_chooser = new TemplateDragDropChooser(); + $dd_chooser->args['classname'] = $classname; + $dd_chooser->args['left_header'] = $mod_strings['LBL_AVALAIBLE_FIELDS_HEADER']; + $dd_chooser->args['mid_header'] = $mod_strings['LBL_LEAD_FORM_FIRST_HEADER']; + $dd_chooser->args['right_header'] = $mod_strings['LBL_LEAD_FORM_SECOND_HEADER']; + $dd_chooser->args['left_data'] = $fields; + $dd_chooser->args['mid_data'] = $d2; + $dd_chooser->args['right_data'] = $d2; + $dd_chooser->args['title'] = ' '; + $dd_chooser->args['left_div_name'] = 'ddgrid2'; + $dd_chooser->args['mid_div_name'] = 'ddgrid3'; + $dd_chooser->args['right_div_name'] = 'ddgrid4'; + $dd_chooser->args['gridcount'] = 'three'; + $str = $dd_chooser->displayScriptTags(); + $str .= $dd_chooser->displayDefinitionScript(); + $str .= $dd_chooser->display(); + $str .= ""; + $str .= ""; + + return $str; +} + +/** + * function to retrieve webtolead image and title. path to help file + * refactored to use SugarView::getModuleTitle() + * + * @deprecated use SugarView::getModuleTitle() instead + * + * @param $module string not used, only for backward compatibility + * @param $image_name string image name + * @param $module_title string to display as the module title + * @param $show_help boolean which determines if the print and help links are shown. + * @return string HTML + */ +function get_webtolead_title( + $module, + $image_name, + $module_title, + $show_help + ) +{ + return $GLOBALS['current_view']->getModuleTitle($show_help); +} \ No newline at end of file diff --git a/modules/Campaigns/WebToLeadDownloadForm.html b/modules/Campaigns/WebToLeadDownloadForm.html new file mode 100644 index 00000000..7a957d67 --- /dev/null +++ b/modules/Campaigns/WebToLeadDownloadForm.html @@ -0,0 +1,90 @@ + + + + + +{JAVASCRIPT} + + + + + + + + + +
    +
    + +
    {APP.LBL_REQUIRED_SYMBOL} {APP.NTC_REQUIRED}{ADMIN_EDIT}
    + + + + + + + + + + +
    + + + + + + {LINK_TO_WEB_FORM} + +
     
    +
    + {MOD.LBL_COPY_AND_PASTE_CODE}
    + +
    + + diff --git a/modules/Campaigns/WebToLeadForm.html b/modules/Campaigns/WebToLeadForm.html new file mode 100644 index 00000000..7b896af3 --- /dev/null +++ b/modules/Campaigns/WebToLeadForm.html @@ -0,0 +1,102 @@ + + + + + +{JAVASCRIPT} + + + + + + + + + + + + + +
    +
    + + + + + + + + + + +
    {APP.LBL_REQUIRED_SYMBOL} {APP.NTC_REQUIRED}{ADMIN_EDIT}
    + + + + + +
    + + + + + + + + +
    + {MOD.LBL_BODY} + + +
    +
    + +{tiny} + diff --git a/modules/Campaigns/WebToLeadFormSave.php b/modules/Campaigns/WebToLeadFormSave.php new file mode 100644 index 00000000..efd88caa --- /dev/null +++ b/modules/Campaigns/WebToLeadFormSave.php @@ -0,0 +1,122 @@ +', $start_border); //get the closing tag after marker ">"; + + //extract the input tag string + $working_str = substr($bodyHTML, $marker-3, $end_border-($marker-3) ); + + //replace input markup with text areas markups + $new_str = str_replace('input','textarea',$working_str); + $new_str = str_replace("type='text'", ' ', $new_str); + $new_str = $new_str . '> tags in the form. Without them, IE8 will attempt to display the page as XML. + $rawsource = $_REQUEST['body_html']; + + $SugarTiny = new SugarTinyMCE(); + $rawsource = $SugarTiny->cleanEncodedMCEHtml($rawsource); + $html = from_html($rawsource); + + if (stripos($html, ""; + } + $file = $dir_path.'WebToLeadForm_'.time().'.html'; + $fp = sugar_fopen($file,'wb'); + fwrite($fp, $html); + fclose($fp); +} +$xtpl=new XTemplate ('modules/Campaigns/WebToLeadDownloadForm.html'); +$xtpl->assign("MOD", $mod_strings); +$xtpl->assign("APP", $app_strings); + +$webformlink = "$mod_strings[LBL_DOWNLOAD_TEXT_WEB_TO_LEAD_FORM]
    "; +$webformlink .= "$mod_strings[LBL_DOWNLOAD_WEB_TO_LEAD_FORM]"; +$xtpl->assign("LINK_TO_WEB_FORM",$webformlink); +if ($rawsource !== false) +{ + $xtpl->assign("RAW_SOURCE", $rawsource); + $xtpl->parse("main.copy_source"); +} + $xtpl->parse("main"); +$xtpl->out("main"); + +?> \ No newline at end of file diff --git a/modules/Campaigns/WizardEmailSetup.html b/modules/Campaigns/WizardEmailSetup.html new file mode 100644 index 00000000..7c681074 --- /dev/null +++ b/modules/Campaigns/WizardEmailSetup.html @@ -0,0 +1,326 @@ + +{$ROLLOVER} +
    + + + + + + + + + + + + +

    +

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

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

    {$MOD.LBL_NAVIGATION_MENU_SETUP}

    + {$EMAILSETUP}{$MOD.LBL_EMAIL_SETUP_DESC} +
     
    + + + + +
    + + + + + + + + + + + + + + + +
    {$MOD.LBL_WIZ_FROM_NAME} {$APP.LBL_REQUIRED_SYMBOL}
    {$MOD.LBL_MAIL_SENDTYPE} + +
    {$MOD.LBL_WIZ_FROM_ADDRESS} {$APP.LBL_REQUIRED_SYMBOL}
    +
    + + + + + + + + + + + + + + + + +
    {$MOD.LBL_MAIL_SMTPSERVER} {$APP.LBL_REQUIRED_SYMBOL}{$MOD.LBL_MAIL_SMTPPORT} {$APP.LBL_REQUIRED_SYMBOL}
    + {$MOD.LBL_MAIL_SMTPAUTH_REQ} + + +   {$APP.LBL_EMAIL_SMTP_SSL_OR_TLS}: + +
    +
    + + + + + + + +
    {$MOD.LBL_MAIL_SMTPUSER} {$APP.LBL_REQUIRED_SYMBOL}{$MOD.LBL_MAIL_SMTPPASS} {$APP.LBL_REQUIRED_SYMBOL}
    +
    +
    +
    +
    +
    + + + + +
     
     

    {$MOD.LBL_MASS_MAILING_TITLE}

    + + + + + + + + + + + + + + + +
    {$MOD.LBL_EMAILS_PER_RUN} {$APP.LBL_REQUIRED_SYMBOL}
    {$MOD.LBL_LOCATION_TRACK} {$APP.LBL_REQUIRED_SYMBOL}{$MOD.LBL_DEFAULT_LOCATION} {$MOD.LBL_CUSTOM_LOCATION} +
    +
    + {$MOD.LBL_CAMP_MESSAGE_COPY} {$APP.LBL_REQUIRED_SYMBOL} + {$MOD.LBL_CAMP_MESSAGE_COPY_DESC} +
    + +
    + {$MOD.LBL_YES} {$MOD.LBL_NO} +
    +
    +
    + +
    + + +
    + + + + + +   + + + +

    {$MOD.LBL_NAVIGATION_MENU_NEW_MAILBOX}

     
    {$MAILBOXES_DETECTED_MESSAGE}
    +  {$MOD.LBL_CREATE_MAILBOX} 
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + {$MOD.LBL_MAILBOX_NAME} {$APP.LBL_REQUIRED_SYMBOL}  + + {$MOD.LBL_FROM_ADDR}:  +  
    + {$MOD.LBL_SERVER_URL}: {$APP.LBL_REQUIRED_SYMBOL}  + + {$MOD.LBL_LOGIN}: + {$APP.LBL_REQUIRED_SYMBOL}  +
    + {$MOD.LBL_SERVER_TYPE}: + {$APP.LBL_REQUIRED_SYMBOL}  + + + {$MOD.LBL_PASSWORD}: + {$APP.LBL_REQUIRED_SYMBOL}  +
    + {$MOD.LBL_PORT}: + {$APP.LBL_REQUIRED_SYMBOL}  + + + +
    {$MOD.LBL_MAILBOX}: {$APP.LBL_REQUIRED_SYMBOL}
     
    +
    +
    +
    + {$MOD.LBL_SSL}:  +
    +
    + + + +
    +
    +
    + + +
    + + + +
    +

    {$MOD.LBL_NAVIGATION_MENU_SUMMARY}

    +
    +
    +
    +
    + +
    +
    + + +
    + + +
    + + + +{$WIZ_JAVASCRIPT} +{$DIV_JAVASCRIPT} +{$JAVASCRIPT} + + + \ No newline at end of file diff --git a/modules/Campaigns/WizardEmailSetup.php b/modules/Campaigns/WizardEmailSetup.php new file mode 100644 index 00000000..84431aae --- /dev/null +++ b/modules/Campaigns/WizardEmailSetup.php @@ -0,0 +1,413 @@ +{$mod_strings['LBL_MODULE_NAME']}"; +$params[] = $mod_strings['LBL_EMAIL_SETUP_WIZARD_TITLE']; + +echo getClassicModuleTitle('Campaigns', $params, true); + + +global $theme; +global $currentModule; + + + + + +//get administration bean for email setup +$focus = new Administration(); +$focus->retrieveSettings(); //retrieve all admin settings. +$GLOBALS['log']->info("Mass Emailer(EmailMan) ConfigureSettings view"); +$email = new Email(); +$ss = new Sugar_Smarty(); +$ss->assign("MOD", $mod_strings); +$ss->assign("APP", $app_strings); +if (isset($_REQUEST['return_module'])) $ss->assign("RETURN_MODULE", $_REQUEST['return_module']); +if (isset($_REQUEST['return_action'])) $ss->assign("RETURN_ACTION", $_REQUEST['return_action']); +if (isset($_REQUEST['return_id'])) $ss->assign("RETURN_ID", $_REQUEST['return_id']); + + + +/******** Email Setup UI DIV Stuff **********/ +//get Settings if they exist +$ss->assign("notify_fromaddress", $focus->settings['notify_fromaddress']); +$ss->assign("notify_send_from_assigning_user", ($focus->settings['notify_send_from_assigning_user']) ? "checked='checked'" : ""); +$ss->assign("notify_on", ($focus->settings['notify_on']) ? "checked='checked'" : ""); +$ss->assign("notify_fromname", $focus->settings['notify_fromname']); +$ss->assign("mail_smtpserver", $focus->settings['mail_smtpserver']); +$ss->assign("mail_smtpport", $focus->settings['mail_smtpport']); +$ss->assign("mail_sendtype_options", get_select_options_with_id($app_list_strings['notifymail_sendtype'], $focus->settings['mail_sendtype'])); +$ss->assign("mail_smtpuser", $focus->settings['mail_smtpuser']); +$ss->assign("mail_smtppass", $focus->settings['mail_smtppass']); +$ss->assign("mail_smtpauth_req", ($focus->settings['mail_smtpauth_req']) ? "checked='checked'" : ""); + +$protocol = filterInboundEmailPopSelection($app_list_strings['dom_email_server_type']); +$ss->assign('PROTOCOL', get_select_options_with_id($protocol, '')); +if (isset($focus->settings['massemailer_campaign_emails_per_run']) && !empty($focus->settings['massemailer_campaign_emails_per_run'])) { + $ss->assign("EMAILS_PER_RUN", $focus->settings['massemailer_campaign_emails_per_run']); +} else { + $ss->assign("EMAILS_PER_RUN", 500); +} + +if (!isset($focus->settings['massemailer_tracking_entities_location_type']) or empty($focus->settings['massemailer_tracking_entities_location_type']) or $focus->settings['massemailer_tracking_entities_location_type']=='1') { + $ss->assign("DEFAULT_CHECKED", "checked"); + $ss->assign("TRACKING_ENTRIES_LOCATION_STATE", "disabled"); + $ss->assign("TRACKING_ENTRIES_LOCATION",$mod_strings['TRACKING_ENTRIES_LOCATION_DEFAULT_VALUE']); +} else { + $ss->assign("USERDEFINED_CHECKED", "checked"); + $ss->assign("TRACKING_ENTRIES_LOCATION",$focus->settings["massemailer_tracking_entities_location"]); +} +// Change the default campaign to not store a copy of each message. +if (!empty($focus->settings['massemailer_email_copy']) and $focus->settings['massemailer_email_copy']=='1') { + $ss->assign("YES_CHECKED", "checked='checked'"); +} else { + $ss->assign("NO_CHECKED", "checked='checked'"); +} + +$ss->assign("MAIL_SSL_OPTIONS", get_select_options_with_id($app_list_strings['email_settings_for_ssl'], $focus->settings['mail_smtpssl'])); + + +/*********** New Mail Box UI DIV Stuff ****************/ +$mbox_qry = "select * from inbound_email where deleted ='0' and mailbox_type = 'bounce'"; +$mbox_res = $focus->db->query($mbox_qry); +while ($mbox_row = $focus->db->fetchByAssoc($mbox_res)){$mbox[] = $mbox_row;} +$mbox_msg = ' '; +$need_mbox = ''; + +$mboxTable = ""; +if(isset($mbox) && count($mbox)>0){ + $mboxTable .= ""; + $mboxTable .= "" + . " " + . " " + . " " + . " "; + $colorclass=' '; + foreach($mbox as $details){ + + if( $colorclass == "class='evenListRowS1'"){ + $colorclass= "class='oddListRowS1'"; + }else{ + $colorclass= "class='evenListRowS1'"; + } + + $mboxTable .= ""; + $mboxTable .= ""; + $mboxTable .= ""; + $mboxTable .= ""; + $mboxTable .= ""; + $mboxTable .= ""; + } + + +}else{ +$need_mbox = 'checked'; +$mboxTable .= ""; +} +$mboxTable .= "
    " .count($mbox) ." ". $mod_strings['LBL_MAILBOX_CHECK_WIZ_GOOD']." .
    ".$mod_strings['LBL_MAILBOX_NAME']."".$mod_strings['LBL_LOGIN']."".$mod_strings['LBL_MAILBOX']."".$mod_strings['LBL_SERVER_URL']."".$mod_strings['LBL_LIST_STATUS']."
    ".$details['name']."".$details['email_user']."".$details['mailbox']."".$details['server_url']."".$details['status']."
    ".$mod_strings['LBL_MAILBOX_CHECK_WIZ_BAD']." .
    "; +$ss->assign("MAILBOXES_DETECTED_MESSAGE", $mboxTable); +$ss->assign("MBOX_NEEDED", $need_mbox); +$ss->assign('ROLLOVER', $email->rolloverStyle); +if(!function_exists('imap_open')) { + $ss->assign('IE_DISABLED', 'DISABLED'); +} +/**************************** SUMMARY UI DIV Stuff *******************/ + +/**************************** WIZARD UI DIV Stuff *******************/ + +// this is the wizard control script that resides in page + $divScript = << + + //this function toggles visibility of fields based on selected options + function notify_setrequired() { + f = document.getElementById("wizform"); + document.getElementById("smtp_settings").style.display = (f.mail_sendtype.value == "SMTP") ? "inline" : "none"; + document.getElementById("smtp_settings").style.visibility = (f.mail_sendtype.value == "SMTP") ? "visible" : "hidden"; + document.getElementById("smtp_auth").style.display = (document.getElementById('mail_smtpauth_req').checked) ? "inline" : "none"; + document.getElementById("smtp_auth").style.visibility = (document.getElementById('mail_smtpauth_req').checked) ? "visible" : "hidden"; + document.getElementById("new_mbox").style.display = (document.getElementById('create_mbox').checked) ? "inline" : "none"; + document.getElementById("new_mbox").style.visibility = (document.getElementById('create_mbox').checked) ? "visible" : "hidden"; + document.getElementById("wiz_new_mbox").value = (document.getElementById('create_mbox').checked) ? "1" : "0"; + return true; + } + + //this function will copy as much information as possible from the first step in wizard + //onto the the second step in wizard + function copy_down() { + document.getElementById("name").value = document.getElementById("notify_fromname").value; + document.getElementById("email_user").value = document.getElementById("notify_fromaddress").value; + document.getElementById("from_addr").value = document.getElementById("notify_fromaddress").value; + if(document.getElementById("mail_sendtype").value=='SMTP'){ + document.getElementById("protocol").value = "SMTP"; + document.getElementById("server_url").value = document.getElementById("mail_smtpserver").value; + if(document.getElementById('mail_smtpauth_req').checked){ + document.getElementById("email_user").value = document.getElementById("mail_smtpuser").value; + document.getElementById("email_password").value = document.getElementById("mail_smtppass").value; + } + + } + return true; + } + + //this calls the validation functions for each step that needs validation + function validate_wiz_form(step){ + switch (step){ + case 'step1': + if(!validate_step1()){return false;} + copy_down(); + break; + case 'step2': + if(!validate_step2()){return false;} + break; + default://no additional validation needed + } + return true; + + } + + //this function will add validation to step1 + function validate_step1(){ + requiredTxt = SUGAR.language.get('app_strings', 'ERR_MISSING_REQUIRED_FIELDS'); + var haserrors = 0; + var fields = new Array(); + + //create list of fields that need validation, based on selected options + fields[0] = 'notify_fromname'; + fields[1] = 'notify_fromaddress'; + fields[2] = 'massemailer_campaign_emails_per_run'; + fields[3] = 'massemailer_tracking_entities_location'; + if(document.getElementById("mail_sendtype").value=='SMTP'){ + fields[4] = 'mail_smtpserver'; + fields[5] = 'mail_smtpport'; + if(document.getElementById('mail_smtpauth_req').checked){ + fields[6] = 'mail_smtpuser'; + fields[7] = 'mail_smtppass'; + } + } + + var field_value = ''; + //iterate through required fields and set empty string values (' '') to null, this will cause failure later on + for (i=0; i < fields.length; i++){ + elem = document.getElementById(fields[i]); + field_value = trim(elem.value); + if(field_value.length<1){ + elem.value = ''; + } + } + //add to generic validation and call function to calidate + if(validate['wizform']!='undefined'){delete validate['wizform']}; + addToValidate('wizform', 'notify_fromaddress', 'email', true, document.getElementById('notify_fromaddress').title); + addToValidate('wizform', 'notify_fromname', 'alphanumeric', true, document.getElementById('notify_fromname').title); + addToValidate('wizform', 'massemailer_campaign_emails_per_run', 'int', true, document.getElementById('massemailer_campaign_emails_per_run').title); + addToValidate('wizform', 'massemailer_tracking_entities_location', 'alphanumeric', true, document.getElementById('massemailer_tracking_entities_location').title); + if(document.getElementById("mail_sendtype").value=='SMTP'){ + addToValidate('wizform', 'mail_smtpserver', 'alphanumeric', true, document.getElementById('mail_smtpserver').title); + addToValidate('wizform', 'mail_smtpport', 'int', true, document.getElementById('mail_smtpport').title); + if(document.getElementById('mail_smtpauth_req').checked){ + addToValidate('wizform', 'mail_smtpuser', 'alphanumeric', true, document.getElementById('mail_smtpuser').title); + addToValidate('wizform', 'mail_smtppass', 'alphanumeric', true, document.getElementById('mail_smtppass').title); + } + } + + + return check_form('wizform'); + } + + + + function validate_step2(){ + requiredTxt = SUGAR.language.get('app_strings', 'ERR_MISSING_REQUIRED_FIELDS'); + //validate only if the create mailbox form input has been selected + if(document.getElementById("wiz_new_mbox").value == "0"){ + //this form is not checked, do not validate + return true; + } + var haserrors = 0; + var wiz_message = document.getElementById('wiz_message'); + + //create list of fields that need validation, based on selected options + var fields = new Array(); + fields[0] = 'name'; + fields[1] = 'server_url'; + fields[2] = 'email_user'; + fields[3] = 'protocol'; + fields[4] = 'email_password'; + fields[5] = 'mailbox'; + fields[6] = 'port'; + + //iterate through required fields and set empty string values (' '') to null, this will cause failure later on + var field_value = ''; + for (i=0; i < fields.length; i++){ + field_value = trim(document.getElementById(fields[i]).value); + if(field_value.length<1){ + add_error_style('wizform', fields[i], requiredTxt +' ' +document.getElementById(fields[i]).title ); + haserrors = 1; + } + } + + //add to generic validation and call function to calidate + if(validate['wizform']!='undefined'){delete validate['wizform']}; + addToValidate('wizform', 'name', 'alphanumeric', true, document.getElementById('name').title); + addToValidate('wizform', 'server_url', 'alphanumeric', true, document.getElementById('server_url').title); + addToValidate('wizform', 'email_user', 'alphanumeric', true, document.getElementById('email_user').title); + addToValidate('wizform', 'email_password', 'alphanumeric', true, document.getElementById('email_password').title); + addToValidate('wizform', 'mailbox', 'alphanumeric', true, document.getElementById('mailbox').title); + addToValidate('wizform', 'protocol', 'alphanumeric', true, document.getElementById('protocol').title); + addToValidate('wizform', 'port', 'int', true, document.getElementById('port').title); + + if(haserrors == 1){ + return false; + } + return check_form('wizform'); + + + } + + /* + * The generic create summary will not work for this wizard, as we have a step that only gets + * displayed if a check box is marked, and we also have certain inputs we do not want displayed(ie. password) + * so this function will override the genereic version + */ + function create_summary(){ + var current_step = document.getElementById('wiz_current_step'); + var currentValue = parseInt(current_step.value); + var temp_elem = ''; + + // alert(test.title);alert(test.name);alert(test.id); + var fields = new Array(); + //create the list of fields to create summary table + fields[0] = 'notify_fromname'; + fields[1] = 'notify_fromaddress'; + fields[2] = 'massemailer_campaign_emails_per_run'; + fields[3] = 'massemailer_tracking_entities_location'; + + if(document.getElementById("mail_sendtype").value=='SMTP'){ + fields[4] = 'mail_smtpserver'; + fields[5] = 'mail_smtpport'; + if(document.getElementById('mail_smtpauth_req').checked){ + fields[6] = 'mail_smtpuser'; + } + fields[7] = 'mail_smtpssl'; + } + + if(document.getElementById("wiz_new_mbox").value != "0"){ + fields[8] = 'name'; + fields[9] = 'server_url'; + fields[10] = 'email_user'; + fields[11] = 'from_addr'; + fields[12] = 'protocol'; + fields[13] = 'mailbox'; + fields[14] = 'port'; + fields[15] = 'ssl'; + } + + //iterate through list and create table + var summhtml = ""; + var colorclass = 'tabDetailViewDF2'; + var elem =''; + for (var i=0; i= 0 ){ + var selInd = elem.selectedIndex; + if(selInd<0){selInd =0;} + summhtml = summhtml+ ""; + }else if(elem.type == 'checked'){ + summhtml = summhtml+ ""; + }else if(elem.type == 'checkbox'){ + if(elem.checked){ + summhtml = summhtml+ ""; + }else{ + summhtml = summhtml+ ""; + } + }else{ + summhtml = summhtml+ ""; + } + } + if( colorclass== 'tabDetailViewDL2'){ + colorclass= 'tabDetailViewDF2'; + }else{ + colorclass= 'tabDetailViewDL2' + } + } + + summhtml = summhtml+ "
    " +elem.title+ "" + elem.options[selInd].text+ " 
    " +elem.title+ "" + elem.value + " 
    " +elem.title+ " 
    " +elem.title+ " 
    " +elem.title+ "" + elem.value + " 
    "; + temp_elem = document.getElementById('wiz_summ'); + temp_elem.innerHTML = summhtml; + + } + + showfirst('email'); + notify_setrequired(); + + + + + +EOQ; + +$ss->assign("DIV_JAVASCRIPT", $divScript); + + +/**************************** FINAL END OF PAGE UI Stuff *******************/ + +//$ss->assign("JAVASCRIPT", get_validate_record_js()); + +$ss->display('modules/Campaigns/WizardEmailSetup.html'); + +?> diff --git a/modules/Campaigns/WizardEmailSetupSave.php b/modules/Campaigns/WizardEmailSetupSave.php new file mode 100644 index 00000000..d5fba20f --- /dev/null +++ b/modules/Campaigns/WizardEmailSetupSave.php @@ -0,0 +1,124 @@ +saveConfig(); + + + +/**************************** Add New Monitored Box *****************************/ +//perform this if the option to create new mail box has been checked +if(isset($_REQUEST['wiz_new_mbox']) && ($_REQUEST['wiz_new_mbox']=='1')){ + + //Populate the Request variables that inboundemail expects + $_REQUEST['mark_read'] = 1; + $_REQUEST['only_since'] = 1; + $_REQUEST['mailbox_type'] = 'bounce'; + $_REQUEST['from_name'] = $_REQUEST['name']; + $_REQUEST['group_id'] = 'new'; +// $_REQUEST['from_addr'] = $_REQUEST['wiz_step1_notify_fromaddress']; + //reuse save functionality for inbound email + require_once('modules/InboundEmail/Save.php'); + +} +//set navigation details +header("Location: index.php?action=index&module=Campaigns"); + + +/* + * This function will re-add the post variables that exist with the specified prefix. + * It will add them minus the specified prefix. This is needed in order to reuse the save functionality, + * which does not expect the prefix, and still use the generic create summary functionality in wizard, which + * does expect the prefix. + */ +function clean_up_post($prefix){ + + foreach ($_REQUEST as $key => $val) { + if((strstr($key, $prefix )) && (strpos($key, $prefix )== 0)){ + $newkey =substr($key, strlen($prefix)) ; + $_REQUEST[$newkey] = $val; + } + } + + foreach ($_POST as $key => $val) { + if((strstr($key, $prefix )) && (strpos($key, $prefix )== 0)){ + $newkey =substr($key, strlen($prefix)) ; + $_POST[$newkey] = $val; + + } + } +} + +?> \ No newline at end of file diff --git a/modules/Campaigns/WizardHome.html b/modules/Campaigns/WizardHome.html new file mode 100644 index 00000000..0daaa466 --- /dev/null +++ b/modules/Campaigns/WizardHome.html @@ -0,0 +1,92 @@ + +
    + + + + + + + + + + + + + + + + + + +
    + + + +{$CAMPAIGN_DIAGNOSTIC_LINK}

    + + + + + + + + +
    +
    {$CAMPAIGN_TBL}

    +

     
    +

    {$TRACKERS_TBL}
    +
     
    +

    {$TARGETS_TBL}
    +
     
    +

    {$MARKETING_TBL}
    +
    + + +

    + +
    + \ No newline at end of file diff --git a/modules/Campaigns/WizardHome.php b/modules/Campaigns/WizardHome.php new file mode 100644 index 00000000..4dbd72a7 --- /dev/null +++ b/modules/Campaigns/WizardHome.php @@ -0,0 +1,490 @@ +retrieve($_REQUEST['record']); + +global $mod_strings; +global $app_list_strings; +global $app_strings; +global $current_user; + + +//if (!is_admin($current_user)) sugar_die("Unauthorized access to administration."); +//account for use within wizards +if($focus->campaign_type == 'NewsLetter'){ + echo getClassicModuleTitle($mod_strings['LBL_MODULE_NAME'], array($mod_strings['LBL_NEWSLETTER_WIZARD_START_TITLE'].$focus->name), true, false); +}else{ + echo getClassicModuleTitle($mod_strings['LBL_MODULE_NAME'], array($mod_strings['LBL_CAMPAIGN_WIZARD_START_TITLE'].$focus->name), true, false); +} + +global $theme; +global $currentModule; + + + + + + + $ss = new Sugar_Smarty(); + $ss->assign("MOD", $mod_strings); + $ss->assign("APP", $app_strings); + + //if this page has been refreshed as a result of sending emails, then display status + if(isset($_REQUEST['from'])){ + $mess = $mod_strings['LBL_TEST_EMAILS_SENT']; + if($_REQUEST['from']=='send'){ $mess = $mod_strings['LBL_EMAILS_SCHEDULED']; } + $confirm_msg = "var ajaxWizStatus = new SUGAR.ajaxStatusClass(); "; + $confirm_msg .= "window.setTimeout(\"ajaxWizStatus.showStatus('".$mess."')\",1000); "; + $confirm_msg .= "window.setTimeout('ajaxWizStatus.hideStatus()', 1500); "; + $confirm_msg .= "window.setTimeout(\"ajaxWizStatus.showStatus('".$mess."')\",2000); "; + $confirm_msg .= "window.setTimeout('ajaxWizStatus.hideStatus()', 5000); "; + $ss->assign("MSG_SCRIPT",$confirm_msg); + } + + if (isset($_REQUEST['return_module'])) $ss->assign("RETURN_MODULE", $_REQUEST['return_module']); + if (isset($_REQUEST['return_action'])) $ss->assign("RETURN_ACTION", $_REQUEST['return_action']); + if (isset($_REQUEST['return_id'])) $ss->assign("RETURN_ID", $_REQUEST['return_id']); + if (isset($_REQUEST['record'])) $ss->assign("ID", $_REQUEST['record']); + // handle Create $module then Cancel + if (empty($_REQUEST['return_id'])) { + $ss->assign("RETURN_ACTION", 'index'); + } + + + + $ss->assign("CAMPAIGN_TBL", create_campaign_summary ($focus)); + $ss->assign("TARGETS_TBL", create_target_summary ($focus)); + $ss->assign("TRACKERS_TBL", create_tracker_summary ($focus)); + if($focus->campaign_type =='NewsLetter' || $focus->campaign_type =='Email'){ + $ss->assign("MARKETING_TBL", create_marketing_summary ($focus)); + } + + $camp_url = "index.php?action=WizardNewsletter&module=Campaigns&return_module=Campaigns&return_action=WizardHome"; + $camp_url .= "&return_id=".$focus->id."&record=".$focus->id."&direct_step="; + $ss->assign("CAMP_WIZ_URL", $camp_url); + + $mrkt_string = $mod_strings['LBL_NAVIGATION_MENU_MARKETING']; + if(!empty($focus->id)){ + $mrkt_url = "". $mrkt_string.""; + $mrkt_string = $mrkt_url; + } + + $mrkt_url = "". $mod_strings['LBL_NAVIGATION_MENU_MARKETING'].""; + $ss->assign("MRKT_WIZ_URL", $mrkt_url); + + $summ_url = " ". $mod_strings['LBL_NAVIGATION_MENU_SUMMARY'].""; + + + //Create the html to fill in the wizard steps + if($focus->campaign_type == 'NewsLetter'){ + $ss->assign('NAV_ITEMS',create_wiz_menu_items('newsletter',$mrkt_string,$camp_url,$summ_url )); + $ss->assign("CAMPAIGN_DIAGNOSTIC_LINK", diagnose()); + }elseif($focus->campaign_type == 'Email'){ + $ss->assign('NAV_ITEMS',create_wiz_menu_items('email',$mrkt_string,$camp_url,$summ_url )); + $ss->assign("CAMPAIGN_DIAGNOSTIC_LINK", diagnose()); + }else{ + $ss->assign('NAV_ITEMS',create_wiz_menu_items('general',$mrkt_string,$camp_url,$summ_url )); + } + + + /********** FINAL END OF PAGE UI Stuff ********/ + $ss->display('modules/Campaigns/WizardHome.html'); + +}else{ + //there is no record to retrieve, so ask which type of campaign wizard to launch +/* $header_URL = "Location: index.php?module=Campaigns&action=index"; + $GLOBALS['log']->debug("about to post header URL of: $header_URL"); + header($header_URL); +*/ + global $mod_strings; + global $app_list_strings; + global $app_strings; + global $current_user; + + //if (!is_admin($current_user)) sugar_die("Unauthorized access to administration."); + //account for use within wizards + echo getClassicModuleTitle($mod_strings['LBL_MODULE_NAME'], array($mod_strings['LBL_CAMPAIGN_WIZARD'].$focus->name), true, false); + + + $ss = new Sugar_Smarty(); + $ss->assign("MOD", $mod_strings); + $ss->assign("APP", $app_strings); + $ss->display('modules/Campaigns/tpls/WizardHomeStart.tpl'); + +} + + + + +function create_campaign_summary ($focus){ + global $mod_strings,$app_strings; + $fields = array(); + $fields[] = 'name'; + $fields[] = 'assigned_user_name'; + $fields[] = 'status'; + $fields[] = 'team_name'; + $fields[] = 'start_date'; + $fields[] = 'end_date'; + if($focus->campaign_type=='NewsLetter'){ + $fields[] = 'frequency'; + } + $fields[] = 'content'; + $fields[] = 'budget'; + $fields[] = 'actual_cost'; + $fields[] = 'expected_revenue'; + $fields[] = 'expected_cost'; + $fields[] = 'impressions'; + $fields[] = 'objective'; + + //create edit view status and input buttons + $cmp_input = ''; + + //create edit campaign button + $cmp_input = "id."';"; + $cmp_input.= "this.form.return_id.value='".$focus->id."';\" "; + $cmp_input.= "class='button' value='".$mod_strings['LBL_EDIT_EXISTING']."' type='submit'> "; + + //create view status button + if(($focus->campaign_type == 'NewsLetter') || ($focus->campaign_type == 'Email')){ + $cmp_input .= " id."';"; + $cmp_input.= "this.form.return_id.value='".$focus->id."';\" "; + $cmp_input.= "class='button' value='".$mod_strings['LBL_TRACK_BUTTON_TITLE']."' type='submit'>"; + } + //create view roi button + $cmp_input .= " id."';"; + $cmp_input.= "this.form.return_id.value='".$focus->id."';\" "; + $cmp_input.= "class='button' value='".$mod_strings['LBL_TRACK_ROI_BUTTON_LABEL']."' type='submit'>"; + + //Create Campaign Header + $cmpgn_tbl = "

    "; + $cmpgn_tbl .= ""; + $cmpgn_tbl .= ""; + $colorclass = ''; + foreach($fields as $key){ + + if(!empty($focus->$key)){ + $cmpgn_tbl .= "\n"; + if($key == 'team_name') { + require_once('modules/Teams/TeamSetManager.php'); + $cmpgn_tbl .= "\n"; + } else { + $cmpgn_tbl .= "\n"; + } + } + } + $cmpgn_tbl .= "

    ".$mod_strings['LBL_LIST_CAMPAIGN_NAME'].' '. $mod_strings['LBL_WIZ_NEWSLETTER_TITLE_SUMMARY']."

    $cmp_input
    ".$mod_strings[$focus->field_name_map[$key]['vname']]."".TeamSetManager::getCommaDelimitedTeams($focus->team_set_id, $focus->team_id, true)."
    ".$focus->$key."

    "; + + + return $cmpgn_tbl ; +} + +function create_marketing_summary ($focus){ + global $mod_strings,$app_strings; + $colorclass = ''; + + //create new marketing button input + $new_mrkt_input = "id."';"; + $new_mrkt_input .= "this.form.return_id.value='".$focus->id."';\" "; + $new_mrkt_input .= "class='button' value='".$mod_strings['LBL_CREATE_NEW_MARKETING_EMAIL']."' type='submit'>"; + + //create marketing email table + $mrkt_tbl=''; + + $focus->load_relationship('emailmarketing'); + $mrkt_lists = $focus->emailmarketing->get(); + + + $mrkt_tbl = "

    "; + $mrkt_tbl .= "" . + ""; + $mrkt_tbl .= ""; + + if(count($mrkt_lists)>0){ + + + $mrkt_focus = new EmailMarketing(); + foreach($mrkt_lists as $mrkt_id){ + $mrkt_focus->retrieve($mrkt_id); + + //create send test marketing button input + $test_mrkt_input = "id."'; "; + $test_mrkt_input .= "this.form.mode.value='test'; "; + $test_mrkt_input .= "this.form.direct_step.value='1'; "; + $test_mrkt_input .= "this.form.record.value='".$focus->id."'; "; + $test_mrkt_input .= "this.form.return_id.value='".$focus->id."';\" "; + $test_mrkt_input .= "class='button' value='".$mod_strings['LBL_TEST_BUTTON_LABEL']."' type='submit'>"; + + //create send marketing button input + $send_mrkt_input = "id."'; "; + $send_mrkt_input .= "this.form.mode.value='send'; "; + $send_mrkt_input .= "this.form.direct_step.value='1'; "; + $send_mrkt_input .= "this.form.record.value='".$focus->id."'; "; + $send_mrkt_input .= "this.form.return_id.value='".$focus->id."';\" "; + $send_mrkt_input .= "class='button' value='".$mod_strings['LBL_SEND_EMAIL']."' type='submit'>"; + + + + if( $colorclass== "class='evenListRowS1'"){ + $colorclass= "class='oddListRowS1'"; + }else{ + $colorclass= "class='evenListRowS1'"; + } + + if(isset($mrkt_focus->name) && !empty($mrkt_focus->name)){ + $mrkt_tbl .= ""; + $mrkt_tbl .= ""; + $mrkt_tbl .= ""; + $mrkt_tbl .= ""; + $mrkt_tbl .= ""; + $mrkt_tbl .= ""; + $mrkt_tbl .= ""; + + } + } + }else{ + $mrkt_tbl .= ""; + } + $mrkt_tbl .= "

    ".$mod_strings['LBL_WIZ_MARKETING_TITLE']."

    $new_mrkt_input
    ".$mod_strings['LBL_MRKT_NAME']."".$mod_strings['LBL_FROM_MAILBOX_NAME']."".$mod_strings['LBL_STATUS_TEXT']." 
    ".$mrkt_focus->name."".$mrkt_focus->from_name."".$mrkt_focus->status."$test_mrkt_input$send_mrkt_input
    ".$mod_strings['LBL_NONE']."

    "; + return $mrkt_tbl ; +} + +function create_target_summary ($focus){ + global $mod_strings,$app_strings,$app_list_strings; + $colorclass = ''; + $camp_type = $focus->campaign_type; + + + //create schedule table + $pltbl=''; + //set the title based on campaign type + $target_title = $mod_strings['LBL_TARGET_LISTS']; + if($camp_type=='NewsLetter'){ + $target_title = $mod_strings['LBL_NAVIGATION_MENU_SUBSCRIPTIONS']; + } + + + $focus->load_relationship('prospectlists'); + $pl_lists = $focus->prospectlists->get(); + + $pl_tbl = "

    "; + $pl_tbl .= ""; + $pl_tbl .= ""; + $pl_tbl .= ""; + + if(count($pl_lists)>0){ + + + $pl_focus = new ProspectList(); + foreach($pl_lists as $pl_id){ + + if( $colorclass== "class='evenListRowS1'"){ + $colorclass= "class='oddListRowS1'"; + }else{ + $colorclass= "class='evenListRowS1'"; + } + + $pl_focus->retrieve($pl_id); + //set the list type if this is a newsletter + $type=$pl_focus->list_type; + if($camp_type=='NewsLetter'){ + if (($pl_focus->list_type == 'default') || ($pl_focus->list_type == 'seed')){$type = $mod_strings['LBL_SUBSCRIPTION_TYPE_NAME'];} + if($pl_focus->list_type == 'exempt'){$type = $mod_strings['LBL_UNSUBSCRIPTION_TYPE_NAME'];} + if($pl_focus->list_type == 'test'){$type = $mod_strings['LBL_TEST_TYPE_NAME'];} + }else{ + $type = $app_list_strings['prospect_list_type_dom'][$pl_focus->list_type]; + } + if(isset($pl_focus->id) && !empty($pl_focus->id)){ + $pl_tbl .= ""; + $pl_tbl .= ""; + $pl_tbl .= ""; + $pl_tbl .= ""; + $pl_tbl .= ""; + } + } + }else{ + $pl_tbl .= ""; + } + + $pl_tbl .= "

    ".$target_title."

    ".$mod_strings['LBL_LIST_NAME']."".$mod_strings['LBL_LIST_TYPE']."".$mod_strings['LBL_TOTAL_ENTRIES']." 
    "; + $pl_tbl .= $pl_focus->name."$type".$pl_focus->get_entry_count().""; + $pl_tbl .= " "; + $pl_tbl .= ""; + $pl_tbl .= "
    ".$mod_strings['LBL_NONE']."

    "; + return $pl_tbl; + +} + +function create_tracker_summary ($focus){ + global $mod_strings,$app_strings; + $colorclass = ''; + $trkr_tbl=''; + //create tracker table + $focus->load_relationship('tracked_urls'); + $trkr_lists = $focus->tracked_urls->get(); + + $trkr_tbl = "

    "; + $trkr_tbl .= ""; + $trkr_tbl .= ""; + + if(count($trkr_lists)>0){ + + foreach($trkr_lists as $trkr_id){ + if( $colorclass== "class='evenListRowS1'"){ + $colorclass= "class='oddListRowS1'"; + }else{ + $colorclass= "class='evenListRowS1'"; + } + + + $ct_focus = new CampaignTracker(); + $ct_focus->retrieve($trkr_id); + if(isset($ct_focus->tracker_name) && !empty($ct_focus->tracker_name)){ + if($ct_focus->is_optout){$opt = 'checked';}else{$opt = '';} + $trkr_tbl .= ""; + $trkr_tbl .= ""; + $trkr_tbl .= ""; + $trkr_tbl .= ""; + $trkr_tbl .= ""; + } + } + }else{ + $trkr_tbl .= ""; + } + $trkr_tbl .= "

    ".$mod_strings['LBL_NAVIGATION_MENU_TRACKERS']."

    ".$mod_strings['LBL_EDIT_TRACKER_NAME']."".$mod_strings['LBL_EDIT_TRACKER_URL']."".$mod_strings['LBL_EDIT_OPT_OUT']."
    "; + $trkr_tbl .= $ct_focus->tracker_name."".$ct_focus->tracker_url."  
    ".$mod_strings['LBL_NONE']."

    "; + return $trkr_tbl ; + +} + + +function create_wiz_menu_items($type,$mrkt_string,$camp_url,$summ_url){ + global $mod_strings; + + $steps[$mod_strings['LBL_NAVIGATION_MENU_GEN1']] = 'modules/Campaigns/tpls/WizardCampaignHeader.tpl'; + $steps[$mod_strings['LBL_NAVIGATION_MENU_GEN2']] = 'modules/Campaigns/tpls/WizardCampaignBudget.tpl'; + $steps[$mod_strings['LBL_NAVIGATION_MENU_TRACKERS']] = 'modules/Campaigns/tpls/WizardCampaignTracker.tpl'; + if($type == 'newsletter'){ + $steps[$mod_strings['LBL_NAVIGATION_MENU_SUBSCRIPTIONS']] = 'modules/Campaigns/tpls/WizardCampaignTargetList.tpl'; + }else{ + $steps[$mod_strings['LBL_TARGET_LISTS']] = 'modules/Campaigns/tpls/WizardCampaignTargetListForNonNewsLetter.tpl'; + } + + $nav_html = ''; + if(isset($steps) && !empty($steps)){ + $i=1; + foreach($steps as $name=>$step){ + $nav_html .= ""; + $i=$i+1; + } + } + + if($type == 'newsletter' || $type == 'email'){ + $nav_html .= ""; + $nav_html .= ""; + $nav_html .= ""; + }else{ + $nav_html .= ""; + } + + $nav_html .= '
    '; + + return $nav_html; +} + +?> \ No newline at end of file diff --git a/modules/Campaigns/WizardMarketing.html b/modules/Campaigns/WizardMarketing.html new file mode 100644 index 00000000..8bd63ad4 --- /dev/null +++ b/modules/Campaigns/WizardMarketing.html @@ -0,0 +1,382 @@ + + + +
    +
    + + + + + + + + + + + + + + + +

    +

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

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

    {$MOD.LBL_WIZ_MARKETING_TITLE} {$MRKT_NAME}

    +
    {$MOD.LBL_WIZARD_MARKETING_MESSAGE}
     
     
    {$MOD.LBL_MRKT_NAME} {$APP.LBL_REQUIRED_SYMBOL}{$MOD.LBL_STATUS_TEXT} {$APP.LBL_REQUIRED_SYMBOL}
    {$MOD.LBL_FROM_MAILBOX_NAME}{$APP.LBL_REQUIRED_SYMBOL}{$MOD.LBL_START_DATE_TIME} {$APP.LBL_REQUIRED_SYMBOL} +
    {$CALENDAR_DATEFORMAT} {$TIME_MERIDIEM}
    {$USER_DATEFORMAT}{$TIME_FORMAT}
    {$MOD.LBL_FROM_NAME} {$APP.LBL_REQUIRED_SYMBOL}{$MOD.LBL_FROM_ADDR} {$APP.LBL_REQUIRED_SYMBOL}
    {$MOD.LBL_REPLY_NAME}{$MOD.LBL_REPLY_ADDR}
    {$MOD.LBL_MESSAGE_FOR} {$APP.LBL_REQUIRED_SYMBOL}{$MOD.LBL_ALL_PROSPECT_LISTS}{$MOD.LBL_TEMPLATE} {$APP.LBL_REQUIRED_SYMBOL} + +   + +   + + +
       
    + + + {literal} + + {/literal} +
    +
    + + +
    + + + + + + +

    {$MOD.LBL_WIZ_SENDMAIL_TITLE} {$MRKT_NAME}

    {$MOD.LBL_WIZARD_SENDMAIL_MESSAGE}
     
    + {$MOD.LBL_SAVE_EXIT_BUTTON_LABEL} +
    +  
    {$WARNING_MESSAGE}
    +  
    {$MOD.LBL_SEND_AS_TEST}
    +
    +  
    {$MOD.LBL_SEND_EMAIL}
    +
    +
    + + + + +
    + +{literal} + +{/literal} +
    +
    + + + + +{$WIZ_JAVASCRIPT} +{$DIV_JAVASCRIPT} +{$JAVASCRIPT} + + + diff --git a/modules/Campaigns/WizardMarketing.php b/modules/Campaigns/WizardMarketing.php new file mode 100644 index 00000000..70b4f87e --- /dev/null +++ b/modules/Campaigns/WizardMarketing.php @@ -0,0 +1,318 @@ +retrieve($_REQUEST['campaign_id']); +}else{ + sugar_die($app_strings['ERROR_NO_RECORD']); +} + +global $theme; + + + +$json = getJSONobj(); + +$GLOBALS['log']->info("Wizard Continue Create Wizard"); + if($campaign_focus->campaign_type=='NewsLetter'){ + echo getClassicModuleTitle($mod_strings['LBL_MODULE_NAME'], array($mod_strings['LBL_NEWSLETTER WIZARD_TITLE'].' '.$campaign_focus->name), true); + }else{ + echo getClassicModuleTitle($mod_strings['LBL_MODULE_NAME'], array($mod_strings['LBL_CAMPAIGN'].' '.$campaign_focus->name), true); + } + +$ss = new Sugar_Smarty(); +$ss->assign("MOD", $mod_strings); +$ss->assign("APP", $app_strings); +if (isset($_REQUEST['return_module'])) $ss->assign("RETURN_MODULE", $_REQUEST['return_module']); +if (isset($_REQUEST['return_action'])) $ss->assign("RETURN_ACTION", $_REQUEST['return_action']); +if (isset($_REQUEST['return_id'])) $ss->assign("RETURN_ID", $_REQUEST['return_id']); +// handle Create $module then Cancel +$ss->assign('CAMPAIGN_ID', $campaign_focus->id); + +$seps = get_number_seperators(); +$ss->assign("NUM_GRP_SEP", $seps[0]); +$ss->assign("DEC_SEP", $seps[1]); + + +/**************************** MARKETING UI DIV Stuff *******************/ +//$campaign_focus->load_relationship('emailmarketing'); +//$mrkt_ids = $campaign_focus->emailmarketing->get(); + +$mrkt_focus = new EmailMarketing(); + +//if record param exists and it is not empty, then retrieve this bean +if(isset($_REQUEST['record']) and !empty($_REQUEST['record'])){ + $mrkt_focus->retrieve($_REQUEST['record']); +}else{ + //check to see if this campaign has an email marketing already attached, and if so, create duplicate + $campaign_focus->load_relationship('emailmarketing'); + $mrkt_lists = $campaign_focus->emailmarketing->get(); + if(!empty($mrkt_lists)){ + //reverse array so we always use the most recent one: + $mrkt_lists = array_reverse($mrkt_lists); + $mrkt_focus->retrieve($mrkt_lists[0]); + $mrkt_focus->id = ''; + $mrkt_focus->name = $mod_strings['LBL_COPY_OF'] . ' '. $mrkt_focus->name; + } + +} + + +$ss->assign("CALENDAR_LANG", "en"); +$ss->assign("USER_DATEFORMAT", '('. $timedate->get_user_date_format().')'); +$ss->assign("CALENDAR_DATEFORMAT", $timedate->get_cal_date_format()); +$ss->assign("TIME_MERIDIEM", $timedate->AMPMMenu('', $mrkt_focus->time_start)); +$ss->assign("MRKT_ID", $mrkt_focus->id); +$ss->assign("MRKT_NAME", $mrkt_focus->name); +$ss->assign("MRKT_FROM_NAME", $mrkt_focus->from_name); +$ss->assign("MRKT_FROM_ADDR", $mrkt_focus->from_addr); +$def = $mrkt_focus->getFieldDefinition('from_name'); +$ss->assign("MRKT_FROM_NAME_LEN", $def['len']); + +//jc: bug 15498 +// assigning the length of the reply name from the var defs to the template to be used +// as the max length for the input field +$def = $mrkt_focus->getFieldDefinition('reply_to_name'); +$ss->assign("MRKT_REPLY_NAME_LEN", $def['len']); +$ss->assign("MRKT_REPLY_NAME", $mrkt_focus->reply_to_name); +$def = $mrkt_focus->getFieldDefinition('reply_to_addr'); +$ss->assign("MRKT_REPLY_ADDR_LEN", $def['len']); +// end bug 15498 +$ss->assign("MRKT_REPLY_ADDR", $mrkt_focus->reply_to_addr); +$ss->assign("MRKT_DATE_START", $mrkt_focus->date_start); +$ss->assign("MRKT_TIME_START", $mrkt_focus->time_start); +//$_REQUEST['mass'] = $mrkt_focus->id; +$ss->assign("MRKT_ID", $mrkt_focus->id); +$emails=array(); +$mailboxes=get_campaign_mailboxes($emails); + +/* + * get full array of stored options + */ +$IEStoredOptions = get_campaign_mailboxes_with_stored_options(); +$IEStoredOptionsJSON = (!empty($IEStoredOptions)) ? $json->encode($IEStoredOptions, false) : 'new Object()'; +$ss->assign("IEStoredOptions", $IEStoredOptionsJSON); + +//add empty options. +$emails['']='nobody@example.com'; +$mailboxes['']=''; + +//inbound_email_id +$default_email_address='nobody@example.com'; +$from_emails = ''; +foreach ($mailboxes as $id=>$name) { + if (!empty($from_emails)) { + $from_emails.=','; + } + if ($id=='') { + $from_emails.="'EMPTY','$name','$emails[$id]'"; + } else { + $from_emails.="'$id','$name','$emails[$id]'"; + } +} +$ss->assign("FROM_EMAILS",$from_emails); +$ss->assign("DEFAULT_FROM_EMAIL",$default_email_address); +$ss->assign("STATUS_OPTIONS", get_select_options_with_id($app_list_strings['email_marketing_status_dom'],$mrkt_focus->status)); +if (empty($mrkt_focus->inbound_email_id)) { + $ss->assign("MAILBOXES", get_select_options_with_id($mailboxes, '')); +} else { + $ss->assign("MAILBOXES", get_select_options_with_id($mailboxes, $mrkt_focus->inbound_email_id)); +} + +$ss->assign("TIME_MERIDIEM", $timedate->AMPMMenu('', $mrkt_focus->time_start)); +$ss->assign("TIME_FORMAT", '('. $timedate->get_user_time_format().')'); + +$email_templates_arr = get_bean_select_array(true, 'EmailTemplate','name','','name'); +if($mrkt_focus->template_id) { + $ss->assign("TEMPLATE_ID", $mrkt_focus->template_id); + $ss->assign("EMAIL_TEMPLATE_OPTIONS", get_select_options_with_id($email_templates_arr, $mrkt_focus->template_id)); + $ss->assign("EDIT_TEMPLATE","visibility:inline"); +} +else { + $ss->assign("EMAIL_TEMPLATE_OPTIONS", get_select_options_with_id($email_templates_arr, "")); + $ss->assign("EDIT_TEMPLATE","visibility:hidden"); +} + + +$scope_options=get_message_scope_dom($campaign_focus->id,$campaign_focus->name,$mrkt_focus->db); +$prospectlists=array(); +if (isset($mrkt_focus->all_prospect_lists) && $mrkt_focus->all_prospect_lists==1) { + $ss->assign("ALL_PROSPECT_LISTS_CHECKED","checked"); + $ss->assign("MESSAGE_FOR_DISABLED","disabled"); +} +else { + //get select prospect list. + if (!empty($mrkt_focus->id)) { + $mrkt_focus->load_relationship('prospectlists'); + $prospectlists=$mrkt_focus->prospectlists->get(); + }; +} +if (empty($prospectlists)) $prospectlists=array(); +if (empty($scope_options)) $scope_options=array(); +$ss->assign("SCOPE_OPTIONS", get_select_options_with_id($scope_options, $prospectlists)); +$ss->assign("SAVE_CONFIRM_MESSAGE", $mod_strings['LBL_CONFIRM_SEND_SAVE']); + + + +$javascript = new javascript(); +$javascript->setFormName('wizform'); +$javascript->setSugarBean($mrkt_focus); +$javascript->addAllFields(''); +echo $javascript->getScript(); + +/**************************** Final Step UI DIV *******************/ + + //Grab the prospect list of type default + $default_pl_focus = ' '; + $campaign_focus->load_relationship('prospectlists'); + $prospectlists=$campaign_focus->prospectlists->get(); + + + $pl_count = 0; + $pl_lists = 0; + if(!empty($prospectlists)){ + foreach ($prospectlists as $prospect_id){ + $pl_focus = new ProspectList(); + $pl_focus->retrieve($prospect_id); + + if (($pl_focus->list_type == 'default') || ($pl_focus->list_type == 'seed')){ + $default_pl_focus= $pl_focus; + // get count of all attached target types + $pl_count = $default_pl_focus->get_entry_count(); + } + $pl_lists = $pl_lists+1; + } + + + } + //if count is 0, then hide inputs and and print warning message + if ($pl_count==0){ + if ($pl_lists==0){ + //print no target list warning + $ss->assign("WARNING_MESSAGE", $mod_strings['LBL_NO_TARGETS_WARNING']); + }else{ + //print no entries warning + if($campaign_focus->campaign_type='NewsLetter'){ + $ss->assign("WARNING_MESSAGE", $mod_strings['LBL_NO_SUBS_ENTRIES_WARNING']); + }else{ + $ss->assign("WARNING_MESSAGE", $mod_strings['LBL_NO_TARGET_ENTRIES_WARNING']); + } + } + //disable the send email options + $ss->assign("PL_DISABLED",'disabled'); + + }else{ + //show inputs and assign type to be radio + } + + + +/**************************** WIZARD UI DIV Stuff *******************/ + +$camp_url = "index.php?action=WizardNewsletter&module=Campaigns&return_module=Campaigns&return_action=WizardHome"; +$camp_url .= "&return_id=".$campaign_focus->id."&record=".$campaign_focus->id."&direct_step="; +$ss->assign("CAMP_WIZ_URL", $camp_url); + $summ_url = $mod_strings['LBL_NAVIGATION_MENU_SUMMARY']; + if(!empty($focus->id)){ + $summ_url = " ". $mod_strings['LBL_NAVIGATION_MENU_SUMMARY'].""; + } +$summ_url = $mod_strings['LBL_NAVIGATION_MENU_SUMMARY']; +if(!empty($focus->id)){ + $summ_url = "index.php?action=WizardHome&module=Campaigns&return_id=".$focus->id."&record=".$focus->id; +} +$ss->assign("SUMM_URL", $summ_url); + +// this is the wizard control script that resides in page + $divScript = << + /* + * this is the custom validation script that will call the right validation for each div + */ + function validate_wiz_form(step){ + switch (step){ + case 'step1': + return check_form('wizform'); + break; + default://no additional validation needed + } + return true; + + } + + showfirst('marketing') + +EOQ; + +//$ss->assign("WIZ_JAVASCRIPT", print_wizard_jscript()); +$ss->assign("DIV_JAVASCRIPT", $divScript); + + + + + +/**************************** FINAL END OF PAGE UI Stuff *******************/ + + $ss->display('modules/Campaigns/WizardMarketing.html'); +?> diff --git a/modules/Campaigns/WizardMarketingSave.php b/modules/Campaigns/WizardMarketingSave.php new file mode 100644 index 00000000..607503da --- /dev/null +++ b/modules/Campaigns/WizardMarketingSave.php @@ -0,0 +1,189 @@ +retrieve($_REQUEST['record']); +} +if(!$marketing->ACLAccess('Save')){ + ACLController::displayNoAccess(true); + sugar_cleanup(true); +} + +if (!empty($_REQUEST['assigned_user_id']) && ($marketing->assigned_user_id != $_REQUEST['assigned_user_id']) && ($_POST['assigned_user_id'] != $current_user->id)) { + $check_notify = TRUE; +} +else { + $check_notify = FALSE; +} + + foreach ($_REQUEST as $key => $val) { + if((strstr($key, $prefix )) && (strpos($key, $prefix )== 0)){ + $newkey =substr($key, strlen($prefix)) ; + $_REQUEST[$newkey] = $val; + } + } + + foreach ($_REQUEST as $key => $val) { + if((strstr($key, $prefix )) && (strpos($key, $prefix )== 0)){ + $newkey =substr($key, strlen($prefix)) ; + $_REQUEST[$newkey] = $val; + } + } + +if(!empty($_REQUEST['meridiem'])){ + $_REQUEST['time_start'] = $timedate->merge_time_meridiem($_REQUEST['time_start'],$timedate->get_time_format(), $_REQUEST['meridiem']); +} + +if(empty($_REQUEST['time_start'])) { + $_REQUEST['date_start'] = $_REQUEST['date_start'] . ' 00:00'; +} else { + $_REQUEST['date_start'] = $_REQUEST['date_start'] . ' ' . $_REQUEST['time_start']; +} + +foreach($marketing->column_fields as $field) +{ + if ($field == 'all_prospect_lists') { + if(isset($_REQUEST[$field]) && $_REQUEST[$field]='on' ) + { + $marketing->$field = 1; + } else { + $marketing->$field = 0; + } + }else { + if(isset($_REQUEST[$field])) + { + $value = $_REQUEST[$field]; + $marketing->$field = trim($value); + } + } +} + +foreach($marketing->additional_column_fields as $field) +{ + if(isset($_REQUEST[$field])) + { + $value = $_REQUEST[$field]; + $marketing->$field = $value; + } +} + +$marketing->campaign_id = $_REQUEST['campaign_id']; +$marketing->save($check_notify); + +//add prospect lists to campaign. +$marketing->load_relationship('prospectlists'); +$prospectlists=$marketing->prospectlists->get(); +if ($marketing->all_prospect_lists==1) { + //remove all related prospect lists. + if (!empty($prospectlists)) { + $marketing->prospectlists->delete($marketing->id); + } +} else { + if (isset($_REQUEST['message_for']) && is_array($_REQUEST['message_for'])) { + foreach ($_REQUEST['message_for'] as $prospect_list_id) { + + $key=array_search($prospect_list_id,$prospectlists); + if ($key === null or $key === false) { + $marketing->prospectlists->add($prospect_list_id); + } else { + unset($prospectlists[$key]); + } + } + if (count($prospectlists) != 0) { + foreach ($prospectlists as $key=>$list_id) { + $marketing->prospectlists->delete($marketing->id,$list_id); + } + } + } +} + +//populate an array with marketing email id to use +$mass[] = $marketing->id; +//if sending an email was chosen, set all the needed variables for queuing campaign + +if($master !='save'){ + $_REQUEST['mass']= $mass; + $_POST['mass']=$mass; + $_REQUEST['record'] =$marketing->campaign_id; + $_POST['record']=$marketing->campaign_id; + $_REQUEST['mode'] = $master; + $_POST['mode'] = $master; + $_REQUEST['from_wiz']= 'true'; + require_once('modules/Campaigns/QueueCampaign.php'); +} + +$header_URL = "Location: index.php?action=WizardHome&module=Campaigns&record=".$marketing->campaign_id; +$GLOBALS['log']->debug("about to post header URL of: $header_URL"); +header($header_URL); + +?> \ No newline at end of file diff --git a/modules/Campaigns/WizardNewsletter.html b/modules/Campaigns/WizardNewsletter.html new file mode 100644 index 00000000..4a3572f3 --- /dev/null +++ b/modules/Campaigns/WizardNewsletter.html @@ -0,0 +1,107 @@ + + +{$ROLLOVERSTYLE} +
    + + + + + + + + + + + + + + + + + +
    + + + +
    +
    + +{$STEPS} + + +
    +
    +
    + + + + + +
    + + + + + +
    +
    + + +
    +
    +
    +
    + + + + + +{$WIZ_JAVASCRIPT} +{$DIV_JAVASCRIPT} +{$JAVASCRIPT} + + diff --git a/modules/Campaigns/WizardNewsletter.php b/modules/Campaigns/WizardNewsletter.php new file mode 100644 index 00000000..689a3850 --- /dev/null +++ b/modules/Campaigns/WizardNewsletter.php @@ -0,0 +1,611 @@ +retrieve($_REQUEST['record']); +} +if(isset($_REQUEST['isDuplicate']) && $_REQUEST['isDuplicate'] == 'true') { + $focus->id = ""; +} +global $theme; + + + +$json = getJSONobj(); + +$GLOBALS['log']->info("Campaign NewsLetter Wizard"); + +if( (isset($_REQUEST['wizardtype']) && $_REQUEST['wizardtype']==1) || ($focus->campaign_type=='NewsLetter')){ + echo getClassicModuleTitle($mod_strings['LBL_MODULE_NAME'], array($mod_strings['LBL_NEWSLETTER WIZARD_TITLE'].$focus->name), true, false); +}else{ + echo getClassicModuleTitle($mod_strings['LBL_MODULE_NAME'], array($mod_strings['LBL_CAMPAIGN'].$focus->name), true, false); +} + + +$ss = new Sugar_Smarty(); +$ss->assign("MOD", $mod_strings); +$ss->assign("APP", $app_strings); + +if (isset($_REQUEST['return_module'])) $ss->assign("RETURN_MODULE", $_REQUEST['return_module']); +if (isset($_REQUEST['return_action'])) $ss->assign("RETURN_ACTION", $_REQUEST['return_action']); +if (isset($_REQUEST['return_id'])) $ss->assign("RETURN_ID", $_REQUEST['return_id']); +// handle Create $module then Cancel +if (empty($_REQUEST['return_id'])) { + $ss->assign("RETURN_ACTION", 'index'); +} +$ss->assign("PRINT_URL", "index.php?".$GLOBALS['request_string']); + +require_once('include/QuickSearchDefaults.php'); +$qsd = new QuickSearchDefaults(); +$qsd->setFormName('wizform'); +$sqs_objects = array('parent_name' => $qsd->getQSParent(), + 'assigned_user_name' => $qsd->getQSUser(), + //'prospect_list_name' => getProspectListQSObjects(), + 'test_name' => getProspectListQSObjects('prospect_list_type_test', 'test_name','wiz_step3_test_name_id'), + 'unsubscription_name' => getProspectListQSObjects('prospect_list_type_exempt', 'unsubscription_name','wiz_step3_unsubscription_name_id'), + 'subscription_name' => getProspectListQSObjects('prospect_list_type_default', 'subscription_name','wiz_step3_subscription_name_id'), + ); + + +$quicksearch_js = ''; + +$ss->assign("JAVASCRIPT", $quicksearch_js); + + +//set the campaign type based on wizardtype value from request object +$campaign_type = 'newsletter'; +if( (isset($_REQUEST['wizardtype']) && $_REQUEST['wizardtype']==1) || ($focus->campaign_type=='NewsLetter')){ + $campaign_type = 'newsletter'; + $ss->assign("CAMPAIGN_DIAGNOSTIC_LINK", diagnose()); +}elseif( (isset($_REQUEST['wizardtype']) && $_REQUEST['wizardtype']==2) || ($focus->campaign_type=='Email') ){ + $campaign_type = 'email'; + $ss->assign("CAMPAIGN_DIAGNOSTIC_LINK", diagnose()); +}else{ + $campaign_type = 'general'; +} + + +//******** CAMPAIGN HEADER AND BUDGET UI DIV Stuff (both divs) **********/ +/// Users Popup +$popup_request_data = array( + 'call_back_function' => 'set_return', + 'form_name' => 'wizform', + 'field_to_name_array' => array( + 'id' => 'assigned_user_id', + 'user_name' => 'assigned_user_name', + ), + ); +$ss->assign('encoded_users_popup_request_data', $json->encode($popup_request_data)); + + +//set default values +$ss->assign("CALENDAR_LANG", "en"); +$ss->assign("USER_DATEFORMAT", '('. $timedate->get_user_date_format().')'); +$ss->assign("CALENDAR_DATEFORMAT", $timedate->get_cal_date_format()); +$ss->assign("CAMP_DATE_ENTERED", $focus->date_entered); +$ss->assign("CAMP_DATE_MODIFIED", $focus->date_modified); +$ss->assign("CAMP_CREATED_BY", $focus->created_by_name); +$ss->assign("CAMP_MODIFIED_BY", $focus->modified_by_name); +$ss->assign("ID", $focus->id); +$ss->assign("CAMP_TRACKER_TEXT", $focus->tracker_text); +$ss->assign("CAMP_START_DATE", $focus->start_date); +$ss->assign("CAMP_END_DATE", $focus->end_date); +$ss->assign("CAMP_BUDGET", $focus->budget); +$ss->assign("CAMP_ACTUAL_COST", $focus->actual_cost); +$ss->assign("CAMP_EXPECTED_REVENUE", $focus->expected_revenue); +$ss->assign("CAMP_EXPECTED_COST", $focus->expected_cost); +$ss->assign("CAMP_OBJECTIVE", $focus->objective); +$ss->assign("CAMP_CONTENT", $focus->content); +$ss->assign("CAMP_NAME", $focus->name); +$ss->assign("CAMP_RECORD", $focus->id); +$ss->assign("CAMP_IMPRESSIONS", $focus->impressions); +if (empty($focus->assigned_user_id) && empty($focus->id)) $focus->assigned_user_id = $current_user->id; +if (empty($focus->assigned_name) && empty($focus->id)) $focus->assigned_user_name = $current_user->user_name; +$ss->assign("ASSIGNED_USER_OPTIONS", get_select_options_with_id(get_user_array(TRUE, "Active", $focus->assigned_user_id), $focus->assigned_user_id)); +$ss->assign("ASSIGNED_USER_NAME", $focus->assigned_user_name); +$ss->assign("ASSIGNED_USER_ID", $focus->assigned_user_id ); + +if((!isset($focus->status)) && (!isset($focus->id))) + $ss->assign("STATUS_OPTIONS", get_select_options_with_id($app_list_strings['campaign_status_dom'], 'Planning')); +else + $ss->assign("STATUS_OPTIONS", get_select_options_with_id($app_list_strings['campaign_status_dom'], $focus->status)); + +//hide frequency options if this is not a newsletter +if($campaign_type == 'newsletter'){ + $ss->assign("HIDE_FREQUENCY_IF_NEWSLETTER", "Select"); + $ss->assign("FREQUENCY_LABEL", $mod_strings['LBL_CAMPAIGN_FREQUENCY']); + if((!isset($focus->frequency)) && (!isset($focus->id))){ + $ss->assign("FREQ_OPTIONS", get_select_options_with_id($app_list_strings['newsletter_frequency_dom'], 'Monthly')); + }else{ + $ss->assign("FREQ_OPTIONS", get_select_options_with_id($app_list_strings['newsletter_frequency_dom'], $focus->frequency)); + } +}else{ + $ss->assign("HIDE_FREQUENCY_IF_NEWSLETTER", "input type='hidden'"); + $ss->assign("FREQUENCY_LABEL", ' '); +} +global $current_user; +require_once('modules/Currencies/ListCurrency.php'); +$currency = new ListCurrency(); +if(isset($focus->currency_id) && !empty($focus->currency_id)){ + $selectCurrency = $currency->getSelectOptions($focus->currency_id); + $ss->assign("CURRENCY", $selectCurrency); +} +else if($current_user->getPreference('currency') && !isset($focus->id)) +{ + $selectCurrency = $currency->getSelectOptions($current_user->getPreference('currency')); + $ss->assign("CURRENCY", $selectCurrency); +}else{ + + $selectCurrency = $currency->getSelectOptions(); + $ss->assign("CURRENCY", $selectCurrency); + +} +global $current_user; +if(is_admin($current_user) && $_REQUEST['module'] != 'DynamicLayout' && !empty($_SESSION['editinplace'])){ + $record = ''; + if(!empty($_REQUEST['record'])){ + $record = $_REQUEST['record']; + } + $ss->assign("ADMIN_EDIT","".SugarThemeRegistry::current()->getImage("EditLayout","border='0' alt='Edit Layout' align='bottom'").""); +} + +echo $currency->getJavascript(); + +$seps = get_number_seperators(); +$ss->assign("NUM_GRP_SEP", $seps[0]); +$ss->assign("DEC_SEP", $seps[1]); + + +//fill out the campaign type dropdown based on type of campaign being created +if($campaign_type == 'general'){ + //get regular campaign dom object and strip out entries for email and newsletter + $myTypeOptionsArr = array(); + $OptionsArr = $app_list_strings['campaign_type_dom']; + foreach($OptionsArr as $key=>$val){ + if($val =='Newsletter' || $val =='Email' || $val =='' ){ + //do not add + }else{ + $myTypeOptionsArr[$key] = $val; + } + } + + //now create select option html without the newsletter/email, or blank ('') options + $type_option_html =' '; + $selected = false; + foreach($myTypeOptionsArr as $optionKey=>$optionName){ + //if the selected flag is set to true, then just populate + if($selected){ + $type_option_html .=""; + }else{//if not selected yet, check to see if this option should be selected + //if the campaign type is not empty, then select the retrieved type + if(!empty($focus->campaign_type)){ + //check to see if key matches campaign type + if($optionKey == $focus->campaign_type){ + //mark as selected + $type_option_html .=""; + //mark as selected for next time + $selected=true; + }else{ + //key does not match, just populate + $type_option_html .=""; + } + }else{ + //since the campaign type is empty, then select first one + $type_option_html .=""; + //mark as selected for next time + $selected=true; + } + } + } + //assign the modified dropdown for general campaign creation + $ss->assign("CAMPAIGN_TYPE_OPTIONS", $type_option_html); + $ss->assign("SHOULD_TYPE_BE_DISABLED", "select"); +}elseif($campaign_type == 'email'){ + //Assign Email as type of campaign being created an disable the select widget + $ss->assign("CAMPAIGN_TYPE_OPTIONS", $mod_strings['LBL_EMAIL']); + $ss->assign("SHOULD_TYPE_BE_DISABLED", "input type='hidden' value='Email'"); +}else{ + //Assign NewsLetter as type of campaign being created an disable the select widget + $ss->assign("CAMPAIGN_TYPE_OPTIONS", $mod_strings['LBL_NEWSLETTER']); + $ss->assign("SHOULD_TYPE_BE_DISABLED", "input type='hidden' value='NewsLetter'"); + +} + + + + + +/*************** TRACKER UI DIV Stuff ***************/ +//retrieve the trackers +$focus->load_relationship('tracked_urls'); + +$trkr_lists = $focus->tracked_urls->get(); +$trkr_html =''; +$ss->assign('TRACKER_COUNT',count($trkr_lists)); +if(count($trkr_lists)>0){ +global $odd_bg, $even_bg, $hilite_bg; + + $trkr_count = 0; +//create the html to create tracker table + foreach($trkr_lists as $trkr_id){ + $ct_focus = new CampaignTracker(); + $ct_focus->retrieve($trkr_id); + if(isset($ct_focus->tracker_name) && !empty($ct_focus->tracker_name)){ + if($ct_focus->is_optout){$opt = 'checked';}else{$opt = '';} + $trkr_html .= "
    " ; + $trkr_html .= ""; + $trkr_html .= ""; + $trkr_html .= ""; + $trkr_html .= "
    id."'); \" > "; + $trkr_html .= "rem". $mod_strings['LBL_REMOVE']."
    "; + + } + $trkr_count =$trkr_count+1; + } + + $trkr_html .= "
    "; + }else{ + $trkr_html .= "
    ".$mod_strings['LBL_NONE']."
    "; + } + $ss->assign('EXISTING_TRACKERS', $trkr_html); + + + + + + + + + +/************** SUBSCRIPTION UI DIV Stuff ***************/ +//fill in popups for target list options + $popup_request_data = array( + 'call_back_function' => 'set_return', + 'form_name' => 'wizform', + 'field_to_name_array' => array( + 'id' => 'wiz_step3_subscription_name_id', + 'name' => 'wiz_step3_subscription_name', + + ), + ); + +$json = getJSONobj(); +$encoded_newsletter_popup_request_data = $json->encode($popup_request_data); +$ss->assign('encoded_subscription_popup_request_data', $encoded_newsletter_popup_request_data); + + $popup_request_data = array( + 'call_back_function' => 'set_return', + 'form_name' => 'wizform', + 'field_to_name_array' => array( + 'id' => 'wiz_step3_unsubscription_name_id', + 'name' => 'unsubscription_name', + + ), + ); + +$json = getJSONobj(); +$encoded_newsletter_popup_request_data = $json->encode($popup_request_data); +$ss->assign('encoded_unsubscription_popup_request_data', $encoded_newsletter_popup_request_data); + + $popup_request_data = array( + 'call_back_function' => 'set_return', //set_return_and_save_background + 'form_name' => 'wizform', + 'field_to_name_array' => array( + 'id' => 'wiz_step3_test_name_id', + 'name' => 'test_name', + + ), + ); + +$json = getJSONobj(); +$encoded_newsletter_popup_request_data = $json->encode($popup_request_data); +$ss->assign('encoded_test_popup_request_data', $encoded_newsletter_popup_request_data); + + + $popup_request_data = array( + 'call_back_function' => 'set_return_prospect_list', + 'form_name' => 'wizform', + 'field_to_name_array' => array( + 'id' => 'popup_target_list_id', + 'name' => 'popup_target_list_name', + 'list_type' => 'popup_target_list_type', + + ), + ); + +$json = getJSONobj(); +$encoded_newsletter_popup_request_data = $json->encode($popup_request_data); +$ss->assign('encoded_target_list_popup_request_data', $encoded_newsletter_popup_request_data); + +$ss->assign('TARGET_OPTIONS', get_select_options_with_id($app_list_strings['prospect_list_type_dom'], 'default')); + +//retrieve the subscriptions +$focus->load_relationship('prospectlists'); + +$prospect_lists = $focus->prospectlists->get(); + +if((isset($_REQUEST['wizardtype']) && $_REQUEST['wizardtype'] ==1) || ($focus->campaign_type=='NewsLetter')){ + //this is a newsletter type campaign, fill in subscription values + +//if prospect lists are returned, then iterate through and populate form values +if(count($prospect_lists)>0){ + + foreach($prospect_lists as $pl_id){ + //retrieve prospect list + $pl = new ProspectList(); + $pl->retrieve($pl_id); + + if(isset($pl->list_type) && !empty($pl->list_type)){ + //assign values based on type + if(($pl->list_type == 'default') || ($pl->list_type == 'seed')){ + $ss->assign('SUBSCRIPTION_ID', $pl->id); + $ss->assign('SUBSCRIPTION_NAME', $pl->name); + }; + if($pl->list_type == 'exempt'){ + $ss->assign('UNSUBSCRIPTION_ID', $pl->id); + $ss->assign('UNSUBSCRIPTION_NAME', $pl->name); + + }; + if($pl->list_type == 'test'){ + $ss->assign('TEST_ID', $pl->id); + $ss->assign('TEST_NAME', $pl->name); + + }; + } + + } +} + + + +}else{ + //this is not a newlsetter campaign, so fill in target list table + //create array for javascript, this will help to display the option text, not the value + $dom_txt =' '; + foreach($app_list_strings['prospect_list_type_dom'] as $key=>$val){ + $dom_txt .="if(trgt_type_text =='$key'){trgt_type_text='$val';}"; + } + $ss->assign("PL_DOM_STMT", $dom_txt); + $trgt_count = 0; + $trgt_html = ' '; + if(count($prospect_lists)>0){ + + foreach($prospect_lists as $pl_id){ + //retrieve prospect list + $pl = new ProspectList(); + $pl_focus = $pl->retrieve($pl_id); + $trgt_html .= "
    " ; + $trgt_html .= ""; + $trgt_html .= ""; + $trgt_html .= "
    ". $pl_focus->name."".$app_list_strings['prospect_list_type_dom'][$pl_focus->list_type]; + $trgt_html .= "id."'); \" > "; + $trgt_html .= "rem". $mod_strings['LBL_REMOVE']."
    "; + + + $trgt_count =$trgt_count +1; + } + + $trgt_html .= "
    "; + }else{ + $trgt_html .= "
    ".$mod_strings['LBL_NONE']."
    "; + + } + $ss->assign('EXISTING_TARGETS', $trgt_html ); + +} + + +/**************************** WIZARD UI DIV Stuff *******************/ +$mrkt_string = $mod_strings['LBL_NAVIGATION_MENU_MARKETING']; +if(!empty($focus->id)){ + $mrkt_url = "". $mrkt_string.""; + $mrkt_string = $mrkt_url; +} + $summ_url = $mod_strings['LBL_NAVIGATION_MENU_SUMMARY']; + if(!empty($focus->id)){ + $summ_url = " ". $mod_strings['LBL_NAVIGATION_MENU_SUMMARY'].""; + } + + + +$script_to_call =''; + if (!empty($focus->id)){ + $script_to_call = "link_navs(1,4);"; + if(isset($_REQUEST['direct_step']) and !empty($_REQUEST['direct_step'])){ + $script_to_call .=' direct('.$_REQUEST['direct_step'].');'; + } + } + $ss->assign("HILITE_ALL", $script_to_call); + + +// this is the wizard control script that resides in page + $divScript = << + + /* + * this is the custom validation script that will call the right validation for each div + */ + function validate_wiz_form(step){ + switch (step){ + case 'step1': + if(!validate_step1()){return false;} + break; + case 'step2': + if(!validate_step2()){return false;} + break; + default://no additional validation needed + } + return true; + + } + + showfirst('newsletter'); + +EOQ; + +$ss->assign("DIV_JAVASCRIPT", $divScript); + + +$sshtml = ' '; + $i = 1; + +//Create the html to fill in the wizard steps + +if($campaign_type == 'general'){ + $steps = create_campaign_steps(); + $ss->assign('NAV_ITEMS',create_wiz_menu_items($steps,'campaign',$mrkt_string,$summ_url)); + $ss->assign('HIDE_CONTINUE','hidden'); + +}elseif($campaign_type == 'email'){ + $steps = create_email_steps(); + $ss->assign('NAV_ITEMS',create_wiz_menu_items($steps,'email',$mrkt_string,$summ_url)); + $ss->assign('HIDE_CONTINUE','submit'); +}else{ + $steps = create_newsletter_steps(); + $ss->assign('NAV_ITEMS',create_wiz_menu_items($steps,'newsletter',$mrkt_string,$summ_url)); + $ss->assign('HIDE_CONTINUE','submit'); +} + +$ss->assign('TOTAL_STEPS', count($steps)); +$sshtml = create_wiz_step_divs($steps,$ss); +$ss->assign('STEPS',$sshtml); + + +/**************************** FINAL END OF PAGE UI Stuff *******************/ + +$ss->display("modules/Campaigns/tpls/WizardNewsletter.tpl"); + + +function create_newsletter_steps(){ + global $mod_strings; + $steps[$mod_strings['LBL_NAVIGATION_MENU_GEN1']] = 'modules/Campaigns/tpls/WizardCampaignHeader.tpl'; + $steps[$mod_strings['LBL_NAVIGATION_MENU_GEN2']] = 'modules/Campaigns/tpls/WizardCampaignBudget.tpl'; + $steps[$mod_strings['LBL_NAVIGATION_MENU_TRACKERS']] = 'modules/Campaigns/tpls/WizardCampaignTracker.tpl'; + $steps[$mod_strings['LBL_NAVIGATION_MENU_SUBSCRIPTIONS']] = 'modules/Campaigns/tpls/WizardCampaignTargetList.tpl'; + return $steps; +} + +function create_campaign_steps(){ + global $mod_strings; + $steps[$mod_strings['LBL_NAVIGATION_MENU_GEN1']] = 'modules/Campaigns/tpls/WizardCampaignHeader.tpl'; + $steps[$mod_strings['LBL_NAVIGATION_MENU_GEN2']] = 'modules/Campaigns/tpls/WizardCampaignBudget.tpl'; + $steps[$mod_strings['LBL_NAVIGATION_MENU_TRACKERS']] = 'modules/Campaigns/tpls/WizardCampaignTracker.tpl'; + $steps[$mod_strings['LBL_TARGET_LISTS']] = 'modules/Campaigns/tpls/WizardCampaignTargetListForNonNewsLetter.tpl'; + return $steps; +} + +function create_email_steps(){ + global $mod_strings; + $steps[$mod_strings['LBL_NAVIGATION_MENU_GEN1']] = 'modules/Campaigns/tpls/WizardCampaignHeader.tpl'; + $steps[$mod_strings['LBL_NAVIGATION_MENU_GEN2']] = 'modules/Campaigns/tpls/WizardCampaignBudget.tpl'; + $steps[$mod_strings['LBL_NAVIGATION_MENU_TRACKERS']] = 'modules/Campaigns/tpls/WizardCampaignTracker.tpl'; + $steps[$mod_strings['LBL_TARGET_LISTS']] = 'modules/Campaigns/tpls/WizardCampaignTargetListForNonNewsLetter.tpl'; + return $steps; +} + + +function create_wiz_step_divs($steps,$ss){ + $step_html = ''; + if(isset($steps) && !empty($steps)){ + $i=1; + foreach($steps as $name=>$step){ + $step_html .="

    "; + $step_html .= $ss->fetch($step); + $step_html .="

    "; + $i = $i+1; + } + } + return $step_html; +} + +function create_wiz_menu_items($steps,$type,$mrkt_string,$summ_url){ + global $mod_strings; + $nav_html = ''; + if(isset($steps) && !empty($steps)){ + $i=1; + foreach($steps as $name=>$step){ + $nav_html .= ""; + $i=$i+1; + } + } + if($type == 'newsletter' || $type == 'email'){ + $nav_html .= ""; + $nav_html .= ""; + }else{ + $nav_html .= ""; + } + + $nav_html .= '
    "; + $nav_html .= "
    '; + + return $nav_html; +} + + + +?> diff --git a/modules/Campaigns/WizardNewsletterSave.php b/modules/Campaigns/WizardNewsletterSave.php new file mode 100644 index 00000000..e0f2bfb6 --- /dev/null +++ b/modules/Campaigns/WizardNewsletterSave.php @@ -0,0 +1,337 @@ +retrieve($_REQUEST['record']); + } + + $camp_steps[] = 'wiz_step1_'; + $camp_steps[] = 'wiz_step2_'; + + $campaign_focus = populateFromPost('', $campaign_focus); + + foreach($camp_steps as $step){ + $campaign_focus = populate_wizard_bean_from_request($campaign_focus,$step); + } + + //save here so we can link relationships + $campaign_focus->save(); + $GLOBALS['log']->debug("Saved record with id of ".$campaign_focus->id); + + //process prospect lists + + //process subscription lists if this is a newsletter + if($campaign_focus->campaign_type =='NewsLetter'){ + $pl_list = process_subscriptions_from_request($campaign_focus->name); + + $campaign_focus->load_relationship('prospectlists'); + $existing_pls = $campaign_focus->prospectlists->get(); + $ui_ids = array(); + + //for each list returned, add the list to the relationship + foreach($pl_list as $pl){ + $campaign_focus->prospectlists->add($pl->id); + //populate array with id's from UI' + $ui_ids[] = $pl->id; + } + + //now remove the lists that may have existed before, but were not specified in UI. + //this will enforce that Newsletters only have 3 available target lists. + foreach($existing_pls as $pl_del){ + if (!in_array($pl_del, $ui_ids)){ + $campaign_focus->prospectlists->delete($campaign_focus->id, $pl_del); + } + } + }else{ + //process target lists if this is not a newsletter + //remove Target Lists if defined + + if(isset($_REQUEST['wiz_remove_target_list'])){ + + $remove_target_strings = explode(",", $_REQUEST['wiz_remove_target_list']); + foreach($remove_target_strings as $remove_trgt_string){ + if(!empty($remove_trgt_string)){ + //load relationship and add to the list + $campaign_focus->load_relationship('prospectlists'); + $campaign_focus->prospectlists->delete($campaign_focus->id,$remove_trgt_string); + } + } + } + + + //create new campaign tracker and save if defined + if(isset($_REQUEST['wiz_list_of_targets'])){ + $target_strings = explode(",", $_REQUEST['wiz_list_of_targets']); + foreach($target_strings as $trgt_string){ + $target_values = explode("@@", $trgt_string); + if(count($target_values)==3){ + + if(!empty($target_values[0])){ + //this is a selected target, as the id is already populated, retrieve and link + $trgt_focus = new ProspectList(); + $trgt_focus->retrieve($target_values[0]); + + //load relationship and add to the list + $campaign_focus->load_relationship('prospectlists'); + $campaign_focus->prospectlists->add($trgt_focus ->id); + }else{ + + //this is a new target, as the id is not populated, need to create and link + $trgt_focus = new ProspectList(); + $trgt_focus->name = $target_values[1]; + $trgt_focus->list_type = $target_values[2]; + $trgt_focus->save(); + + //load relationship and add to the list + $campaign_focus->load_relationship('prospectlists'); + $campaign_focus->prospectlists->add($trgt_focus->id); + } + + } + + + } + } + + + } + + + + //remove campaign trackers if defined + if(isset($_REQUEST['wiz_remove_tracker_list'])){ + + $remove_tracker_strings = explode(",", $_REQUEST['wiz_remove_tracker_list']); + foreach($remove_tracker_strings as $remove_trkr_string){ + if(!empty($remove_trkr_string)){ + //load relationship and add to the list + $campaign_focus->load_relationship('tracked_urls'); + $campaign_focus->tracked_urls->delete($campaign_focus->id,$remove_trkr_string); + } + } + } + + + //save campaign trackers and save if defined + if(isset($_REQUEST['wiz_list_of_existing_trackers'])){ + $tracker_strings = explode(",", $_REQUEST['wiz_list_of_existing_trackers']); + foreach($tracker_strings as $trkr_string){ + $tracker_values = explode("@@", $trkr_string); + $ct_focus = new CampaignTracker(); + $ct_focus->retrieve($tracker_values[0]); + if(!empty($ct_focus->tracker_name)){ + $ct_focus->tracker_name = $tracker_values[1]; + $ct_focus->is_optout = $tracker_values[2]; + $ct_focus->tracker_url = $tracker_values[3]; + $ct_focus->save(); + + //load relationship and add to the list + $campaign_focus->load_relationship('tracked_urls'); + $campaign_focus->tracked_urls->add($ct_focus->id); + } + } + } + + + //create new campaign tracker and save if defined + if(isset($_REQUEST['wiz_list_of_trackers'])){ + $tracker_strings = explode(",", $_REQUEST['wiz_list_of_trackers']); + foreach($tracker_strings as $trkr_string){ + $tracker_values = explode("@@", $trkr_string); + if(count($tracker_values)==3){ + $ct_focus = new CampaignTracker(); + $ct_focus->tracker_name = $tracker_values[0]; + $ct_focus->is_optout = $tracker_values[1]; + $ct_focus->tracker_url = $tracker_values[2]; + $ct_focus->save(); + + //load relationship and add to the list + $campaign_focus->load_relationship('tracked_urls'); + $campaign_focus->tracked_urls->add($ct_focus->id); + } + } + } + +//set navigation details +$_REQUEST['return_id'] = $campaign_focus->id; +$_REQUEST['return_module'] = $campaign_focus->module_dir; +$_REQUEST['return_action'] = "WizardNewsLetter"; +$_REQUEST['action'] = "WizardMarketing"; +$_REQUEST['record'] = $campaign_focus->id;; + +$action = ''; +if(isset($_REQUEST['wiz_direction']) && $_REQUEST['wiz_direction']== 'continue'){ + $action = 'WizardMarketing'; +}else{ + $action = 'WizardHome&record='.$campaign_focus->id; +} +//require_once('modules/Campaigns/WizardMarketing.php'); +$header_URL = "Location: index.php?return_module=Campaigns&module=Campaigns&action=".$action."&campaign_id=".$campaign_focus->id."&return_action=WizardNewsLetter&return_id=".$campaign_focus->id; +$GLOBALS['log']->debug("about to post header URL of: $header_URL"); + header($header_URL); + + + +/* + * This function will populate the passed in bean with the post variables + * that contain the specified prefix + */ +function populate_wizard_bean_from_request($bean,$prefix){ + foreach($_REQUEST as $key=> $val){ + $key = trim($key); + if((strstr($key, $prefix )) && (strpos($key, $prefix )== 0)){ + $field =substr($key, strlen($prefix)) ; + if(isset($_REQUEST[$key]) && !empty($_REQUEST[$key])){ + //echo "prefix is $prefix, field is $field, key is $key, and value is $val
    "; + $value = $_REQUEST[$key]; + $bean->$field = $value; + } + } + } + + return $bean; +} + + +/* + * This function will process any specified prospect lists and attach them to current campaign + * If no prospect lists have been specified, then it will create one for you. A total of 3 prospect lists + * will be created for you (Subscription, Unsubscription, and test) + */ +function process_subscriptions_from_request($campaign_name){ + global $mod_strings; + $pl_list = array(); + + //process default target list + $create_new = true; + $pl_subs = new ProspectList($campaign_name); + if(!empty($_REQUEST['wiz_step3_subscription_list_id'])){ + //if subscription list is specified then attach + $pl_subs->retrieve($_REQUEST['wiz_step3_subscription_list_id']); + //check to see name matches the bean, if not, then the user has chosen to create new bean + if($pl_subs->name == $_REQUEST['wiz_step3_subscription_name']){ + $pl_list[] = $pl_subs; + $create_new = false; + } + + } + //create new bio if one was not retrieved succesfully + if($create_new){ + //use default name if one has not been specified + $name = $campaign_name . " ".$mod_strings['LBL_SUBSCRIPTION_LIST']; + if(isset($_REQUEST['wiz_step3_subscription_name']) && !empty($_REQUEST['wiz_step3_subscription_name'])){ + $name = $_REQUEST['wiz_step3_subscription_name']; + } + //if subscription list is not specified then create and attach default one + $pl_subs->name = $name; + $pl_subs->list_type = 'default'; + $pl_subs->assigned_user_id= $GLOBALS['current_user']->id; + $pl_subs->save(); + $pl_list[] = $pl_subs; + } + + //process exempt target list + $create_new = true; + $pl_un_subs = new ProspectList(); + if(!empty($_REQUEST['wiz_step3_unsubscription_list_id'])){ + //if unsubscription list is specified then attach + $pl_un_subs->retrieve($_REQUEST['wiz_step3_unsubscription_list_id']); + //check to see name matches the bean, if not, then the user has chosen to create new bean + if($pl_un_subs->name == $_REQUEST['wiz_step3_unsubscription_name']){ + $pl_list[] = $pl_un_subs; + $create_new = false; + } + + } + //create new bean if one was not retrieved succesfully + if($create_new){ + //use default name if one has not been specified + $name = $campaign_name . " ".$mod_strings['LBL_UNSUBSCRIPTION_LIST']; + if(isset($_REQUEST['wiz_step3_unsubscription_name']) && !empty($_REQUEST['wiz_step3_unsubscription_name'])){ + $name = $_REQUEST['wiz_step3_unsubscription_name']; + } + //if unsubscription list is not specified then create and attach default one + $pl_un_subs->name = $name; + $pl_un_subs->list_type = 'exempt'; + $pl_un_subs->assigned_user_id= $GLOBALS['current_user']->id; + $pl_un_subs->save(); + $pl_list[] = $pl_un_subs; + } + + //process test target list + $pl_test = new ProspectList(); + $create_new = true; + if(!empty($_REQUEST['wiz_step3_test_list_id'])){ + //if test list is specified then attach + $pl_test->retrieve($_REQUEST['wiz_step3_test_list_id']); + //check to see name matches the bean, if not, then the user has chosen to create new bean + if($pl_test->name == $_REQUEST['wiz_step3_test_name']){ + $pl_list[] = $pl_test; + $create_new = false; + } + } + //create new bio if one was not retrieved succesfully + if($create_new){ + //use default name if one has not been specified + $name = $campaign_name . " ".$mod_strings['LBL_TEST_LIST']; + if(isset($_REQUEST['wiz_step3_test_name']) && !empty($_REQUEST['wiz_step3_test_name'])){ + $name = $_REQUEST['wiz_step3_test_name']; + } + //if test list is not specified then create and attach default one + $pl_test->name = $name; + $pl_test->list_type = 'test'; + $pl_test->assigned_user_id= $GLOBALS['current_user']->id; + $pl_test->save(); + $pl_list[] = $pl_test; + } + + return $pl_list; +} +?> \ No newline at end of file diff --git a/modules/Campaigns/action_file_map.php b/modules/Campaigns/action_file_map.php new file mode 100644 index 00000000..192899ae --- /dev/null +++ b/modules/Campaigns/action_file_map.php @@ -0,0 +1,45 @@ + \ No newline at end of file diff --git a/modules/Campaigns/chart.tpl b/modules/Campaigns/chart.tpl new file mode 100644 index 00000000..9c52f821 --- /dev/null +++ b/modules/Campaigns/chart.tpl @@ -0,0 +1,63 @@ +{* + +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + + + +*} + + + + + + + + + + + + + + + + + + + + + + diff --git a/modules/Campaigns/controller.php b/modules/Campaigns/controller.php new file mode 100644 index 00000000..de4c0f64 --- /dev/null +++ b/modules/Campaigns/controller.php @@ -0,0 +1,45 @@ +view = 'newsletterlist'; + } +} +?> \ No newline at end of file diff --git a/modules/Campaigns/field_arrays.php b/modules/Campaigns/field_arrays.php new file mode 100644 index 00000000..4cd03331 --- /dev/null +++ b/modules/Campaigns/field_arrays.php @@ -0,0 +1,68 @@ + array( + "id", "date_entered", + "date_modified", "modified_user_id", + "assigned_user_id", "created_by", + "name", "start_date", + "end_date", "status", + "budget", "expected_cost", + "actual_cost", "expected_revenue", + "campaign_type", "objective", + "content", "tracker_key","refer_url","tracker_text", + "tracker_count","currency_id","impressions", + "frequency", + ), + 'list_fields' => array( + 'id', 'name', 'status', + 'campaign_type','assigned_user_id','assigned_user_name','end_date', + 'refer_url',"currency_id", + ), + 'required_fields' => array( + 'name'=>1, 'end_date'=>2, + 'status'=>3, 'campaign_type'=>4 + ), +); +?> \ No newline at end of file diff --git a/modules/Campaigns/image.php b/modules/Campaigns/image.php new file mode 100644 index 00000000..094f6466 --- /dev/null +++ b/modules/Campaigns/image.php @@ -0,0 +1,48 @@ +debug('identifier from the image request is'.$_REQUEST['identifier']); +if(!empty($_REQUEST['identifier'])) { + $keys=log_campaign_activity($_REQUEST['identifier'],'viewed'); +} +sugar_cleanup(); +Header("Content-Type: image/gif"); +$fn=sugar_fopen(SugarThemeRegistry::current()->getImageURL("blank.gif",false),"r"); +fpassthru($fn); +?> diff --git a/modules/Campaigns/language/en_us.lang.php b/modules/Campaigns/language/en_us.lang.php new file mode 100644 index 00000000..cbb71fe7 --- /dev/null +++ b/modules/Campaigns/language/en_us.lang.php @@ -0,0 +1,430 @@ + '"From" Address: ', + 'LBL_REPLY_ADDR' => '"Reply-to" Address: ', + 'LBL_REPLY_NAME' => '"Reply-to" Name: ', + + 'LBL_MODULE_NAME' => 'Campaigns', + 'LBL_MODULE_TITLE' => 'Campaigns: Home', + 'LBL_NEWSLETTER_TITLE'=>'Campaigns: Newsletters', + 'LBL_SEARCH_FORM_TITLE' => 'Campaign Search', + 'LBL_LIST_FORM_TITLE' => 'Campaign List', + 'LBL_NEWSLETTER_LIST_FORM_TITLE' => 'Newsletter List', + 'LBL_CAMPAIGN_NAME' => 'Name:', + 'LBL_CAMPAIGN' => 'Campaign:', + 'LBL_NAME' => 'Name: ', + 'LBL_INVITEE' => 'Contacts', + 'LBL_LIST_CAMPAIGN_NAME' => 'Campaign', + 'LBL_LIST_STATUS' => 'Status', + 'LBL_LIST_TYPE' => 'Type', + 'LBL_LIST_START_DATE' => 'Start Date', + 'LBL_LIST_END_DATE' => 'End Date', + 'LBL_DATE_ENTERED' => 'Date Created', + 'LBL_DATE_MODIFIED' => 'Date Modified', + 'LBL_MODIFIED' => 'Modified by: ', + 'LBL_CREATED' => 'Created by: ', + 'LBL_TEAM' => 'Team: ', + 'LBL_ASSIGNED_TO' => 'Assigned to: ', + 'LBL_ASSIGNED_TO_ID' => 'Assigned to:', + 'LBL_ASSIGNED_TO_NAME'=> 'Assigned to:', + 'LBL_CAMPAIGN_START_DATE' => 'Start Date: ', + 'LBL_CAMPAIGN_END_DATE' => 'End Date: ', + 'LBL_CAMPAIGN_STATUS' => 'Status: ', + 'LBL_CAMPAIGN_BUDGET' => 'Budget: ', + 'LBL_CAMPAIGN_EXPECTED_COST' => 'Expected Cost: ', + 'LBL_CAMPAIGN_ACTUAL_COST' => 'Actual Cost: ', + 'LBL_CAMPAIGN_EXPECTED_REVENUE' => 'Expected Revenue: ', + 'LBL_CAMPAIGN_IMPRESSIONS' => 'Impressions: ', + 'LBL_CAMPAIGN_COST_PER_IMPRESSION' => 'Cost Per Impression: ', + 'LBL_CAMPAIGN_COST_PER_CLICK_THROUGH' => 'Cost Per Click Through: ', + 'LBL_CAMPAIGN_OPPORTUNITIES_WON' =>'Opportunities Won:', + 'LBL_CAMPAIGN_TYPE' => 'Type: ', + 'LBL_CAMPAIGN_OBJECTIVE' => 'Objective: ', + 'LBL_CAMPAIGN_CONTENT' => 'Description: ', + 'LBL_CAMPAIGN_DAYS_REMAIN' => 'Days Remaining', + 'LNK_NEW_CAMPAIGN' => 'Create Campaign (Classic)', + 'LNL_NEW_CAMPAIGN_WIZARD' => 'Create Campaign (Wizard)', + 'LNK_CAMPAIGN_LIST' => 'View Campaigns', + 'LNK_NEW_PROSPECT' => 'Create Target', + 'LNK_PROSPECT_LIST' => 'View Targets', + 'LNK_NEW_PROSPECT_LIST' => 'Create Target List', + 'LNK_PROSPECT_LIST_LIST' => 'View Target Lists', + 'LBL_MODIFIED_BY' => 'Modified by: ', + 'LBL_CREATED_BY' => 'Created by: ', + 'LBL_DATE_CREATED' => 'Date Created: ', + 'LBL_DATE_LAST_MODIFIED' => 'Date Modified: ', + 'LBL_TRACKER_KEY' => 'Tracker: ', + 'LBL_TRACKER_URL' => 'Tracker URL: ', + 'LBL_TRACKER_TEXT' => 'Tracker Link Text: ', + 'LBL_TRACKER_COUNT' => 'Tracker Count: ', + 'LBL_REFER_URL' => 'Tracker Redirect URL: ', + 'LBL_DEFAULT_SUBPANEL_TITLE' => 'Campaigns', + 'LBL_EMAIL_CAMPAIGNS_TITLE' =>'Email Campaigns', + 'LBL_NEW_FORM_TITLE' => 'New Campaign', + 'LBL_TRACKED_URLS'=>'Tracker URLs', + 'LBL_TRACKED_URLS_SUBPANEL_TITLE'=>'Tracker URLs', + 'LBL_CAMPAIGN_ACCOUNTS_SUBPANEL_TITLE'=>'Accounts', + 'LBL_PROSPECT_LIST_SUBPANEL_TITLE' => 'Target List', + 'LBL_EMAIL_MARKETING_SUBPANEL_TITLE' => 'Email Marketing', + 'LNK_NEW_EMAIL_TEMPLATE' => 'Create Email Template', + 'LNK_EMAIL_TEMPLATE_LIST' => 'View Email Templates', + 'LBL_TRACK_BUTTON_TITLE' =>'View Status', + 'LBL_TRACK_BUTTON_KEY' =>'T', + 'LBL_TRACK_BUTTON_LABEL' =>'View Status', + 'LBL_QUEUE_BUTTON_TITLE'=>'Send Emails', + 'LBL_QUEUE_BUTTON_KEY'=>'u', + 'LBL_QUEUE_BUTTON_LABEL'=>'Send Emails', + 'LBL_TEST_BUTTON_TITLE'=>'Send Test', + 'LBL_TEST_BUTTON_KEY'=>'e', + 'LBL_TEST_BUTTON_LABEL'=>'Send Test', + 'LBL_COPY_AND_PASTE_CODE' => 'Or copy and paste the html below into an existing page', + + 'LBL_TODETAIL_BUTTON_TITLE'=>'View Details', + 'LBL_TODETAIL_BUTTON_KEY'=>'T', + 'LBL_TODETAIL_BUTTON_LABEL'=>'View Details', + + 'LBL_DEFAULT'=>'All Target Lists', + 'LBL_MESSAGE_QUEUE_TITLE'=>'Message Queue', + 'LBL_LOG_ENTRIES_TITLE'=>'Responses', + + 'LBL_LOG_ENTRIES_TARGETED_TITLE'=>'Message Sent/Attempted', + 'LBL_LOG_ENTRIES_SEND_ERROR_TITLE'=>'Bounced Messages,Other', + 'LBL_LOG_ENTRIES_INVALID_EMAIL_TITLE'=>'Bounced Messages,Invalid Email', + 'LBL_LOG_ENTRIES_LINK_TITLE'=>'Click-thru Link', + 'LBL_LOG_ENTRIES_VIEWED_TITLE'=>'Viewed Message', + 'LBL_LOG_ENTRIES_REMOVED_TITLE'=>'Opted Out', + 'LBL_LOG_ENTRIES_LEAD_TITLE'=>'Leads Created', + 'LBL_CAMPAIGN_LEAD_SUBPANEL_TITLE'=>'Leads', + 'LBL_OPPORTUNITY_SUBPANEL_TITLE'=>'Opportunities', + 'LBL_LOG_ENTRIES_CONTACT_TITLE'=>'Contacts Created', + + 'LBL_BACK_TO_CAMPAIGNS'=>'Back to Campaigns', + //error messages. + 'ERR_NO_EMAIL_MARKETING'=>'There must be at least one active Email Marketing message associated with the campaign.', + 'ERR_NO_TARGET_LISTS'=>'There must be at least one Target List associated with the campaign.', + 'ERR_NO_TEST_TARGET_LISTS'=>'There must be at least one Target List of type Test associated with the campaign.', + 'ERR_SENDING_NOW'=>'Messages are being delivered , please try this later.', + 'ERR_MESS_NOT_FOUND_FOR_LIST'=>'No Email Marketing message found for this target list', + 'ERR_MESS_DUPLICATE_FOR_LIST'=>'Multiple Email Marketing messages are defined for this target list', + 'ERR_FIX_MESSAGES'=>'Please correct the following errors before proceeding', + + 'LBL_TRACK_DELETE_BUTTON_KEY'=>'D', + 'LBL_TRACK_ROI_BUTTON_LABEL' =>'View ROI', + 'LBL_TRACK_DELETE_BUTTON_TITLE'=>'Delete Test Entries', + 'LBL_TRACK_DELETE_BUTTON_LABEL'=>'Delete Test Entries', + 'LBL_TRACK_DELETE_CONFIRM'=>'This option will delete log entries created by the test run. Continue?', + 'ERR_NO_MAILBOX'=>"The following marketing messages do not have a mail account associated with them.
    Please correct that before proceeding.", + 'LBL_LIST_TO_ACTIVITY'=>'View Status', + 'LBL_CURRENCY_ID'=>'Currency ID', + 'LBL_CURRENCY'=>'Currency:', + 'LBL_ROLLOVER_VIEW' => 'Rollover a bar to view details.', + 'LBL_TARGETED' => 'Targeted', + 'LBL_TOTAL_TARGETED' => 'Total Targeted', + 'LBL_CAMPAIGN_FREQUENCY'=>'Frequency:', + 'LBL_NEWSLETTERS'=>'View Newsletters', + 'LBL_NEWSLETTER'=>'Newsletter', + 'LBL_NEWSLETTER_FORENTRY'=>'NewsLetter', + 'LBL_MORE_DETAILS' => 'More Details', + 'LBL_CREATE_NEWSLETTER'=>'Create Newsletter', + 'LBL_LIST_NAME' => 'Name', + 'LBL_STATUS_TEXT' => 'Status:' , + 'LBL_FROM_MAILBOX_NAME'=>'Use Mail Account:', + 'LBL_FROM_NAME' => 'From Name: ', + 'LBL_START_DATE_TIME' => 'Start Date & Time: ', + 'LBL_DATE_START' => 'Start Date ', + 'LBL_TIME_START' => 'Start Time ', + 'LBL_TEMPLATE' => 'Email Template: ', + 'LBL_CREATE_EMAIL_TEMPLATE'=> 'Create', + 'LBL_MESSAGE_FOR' => 'Send This Message To:', + 'LBL_FINISH' => 'Finish', + 'LBL_ALL_PROSPECT_LISTS'=>'All Target List(s) in the Campaign.', + 'LBL_EDIT_EMAIL_TEMPLATE'=> 'Edit', + 'LBL_EMAIL_SETUP_WIZARD'=> 'Set Up Email', + 'LBL_DIAGNOSTIC_WIZARD'=> 'View Diagnostics', + 'LBL_ALREADY_SUBSCRIBED_HEADER'=>'Newsletters Subscribed To', + 'LBL_UNSUBSCRIBED_HEADER'=>'Available/Newsletters Unsubscribed To', + 'LBL_UNSUBSCRIBED_HEADER_EXPL'=>'Moving the newsletter to the Available Newsletters/Newsletters Unsubscribed To list will add the contact to the Unsubscription List for this newsletter. It will not remove the contact from the original Subscription List or Target List.', + 'LBL_FILTER_CHART_BY'=>'Filter Chart By:', + 'LBL_MANAGE_SUBSCRIPTIONS_TITLE'=>'Manage Subscriptions', + 'LBL_MARK_AS_SENT' =>'Mark As Sent', + 'LBL_DEFAULT_LIST_NOT_FOUND'=>'Target list of type default was not found', + 'LBL_DEFAULT_LIST_ENTRIES_NOT_FOUND'=>'No entries were found', + 'LBL_DEFAULT_LIST_ENTRIES_WERE_PROCESSED' => 'Entries were Processed', + //newsletter wizard + 'LBL_EDIT_TRACKER_NAME'=>'Tracker Name:', + 'LBL_EDIT_TRACKER_URL'=>'Tracker URL:', + 'LBL_EDIT_OPT_OUT_'=>'Opt-out Link?', + 'LBL_EDIT_OPT_OUT'=>'Opt-out Link:', + 'LBL_UNSUBSCRIPTION_LIST_NAME'=>'Unsubscription List Name:', + 'LBL_SUBSCRIPTION_LIST_NAME'=>'Subscription List Name:', + 'LBL_TEST_LIST_NAME'=>'Test List Name:', + 'LBL_UNSUBSCRIPTION_TYPE_NAME'=>'Unsubscription', + 'LBL_SUBSCRIPTION_TYPE_NAME'=>'Subscription', + 'LBL_TEST_TYPE_NAME'=>'Test', + 'LBL_UNSUBSCRIPTION_LIST'=>'Unsubscription List', + 'LBL_SUBSCRIPTION_LIST'=>'Subscription List', + 'LBL_MRKT_NAME' => 'Name', + 'LBL_TEST_LIST'=>'Test List', + 'LBL_WIZARD_HEADER_MESSAGE' => 'Fill out the required fields to help identify the campaign.', + 'LBL_WIZARD_BUDGET_MESSAGE' => 'Enter the budget to calculate the ROI.', + 'LBL_WIZARD_SUBSCRIPTION_MESSAGE' => 'Each newsletter must have three target lists (Subscription, Unsubscription, and Test). You can assign an existing target list. If not, an empty target list will be created when you save the newsletter.', + 'LBL_WIZARD_TARGET_MESSAGE1' => 'Select or create a target list for use with your campaign. This list will be used while sending emails with your marketing messages.', + 'LBL_WIZARD_TARGET_MESSAGE2' => 'Or create a new one using the form below:', + 'LBL_WIZARD_TRACKER_MESSAGE' => 'Define a tracker URL here to use with this campaign. You must enter both the name and the URL to create the tracker.', + 'LBL_WIZARD_MARKETING_MESSAGE' => 'Fill out the form below to create an email instance for your newsletter. This will allow you to specify the information regarding when and how your newsletter should be distributed.', + 'LBL_WIZARD_SENDMAIL_MESSAGE' => 'This is the last step in the process. Select whether you wish to send out a test email, schedule your newsletter for distribution, or save the changes and proceed to the summary page.', + 'LBL_HOME_START_MESSAGE' => 'Select the type of Campaign you would like to create.', + 'LBL_WIZARD_LAST_STEP_MESSAGE'=> ' You are already at the last step.', + 'LBL_WIZARD_FIRST_STEP_MESSAGE'=>' You are already at the first step.', + 'LBL_WIZ_NEWSLETTER_TITLE_STEP1' => 'Campaign Header', + 'LBL_WIZ_NEWSLETTER_TITLE_STEP2' => 'Campaign Budget', + 'LBL_WIZ_NEWSLETTER_TITLE_STEP3' => 'Campaign Tracker URLs ', + 'LBL_WIZ_NEWSLETTER_TITLE_STEP4' => 'Subscription Information', + 'LBL_WIZ_MARKETING_TITLE' => 'Marketing Email', + 'LBL_WIZ_SENDMAIL_TITLE' => 'Send Email', + 'LBL_WIZ_TEST_EMAIL_TITLE' => 'Test Email', + 'LBL_WIZ_NEWSLETTER_TITLE_SUMMARY' => 'Summary', + 'LBL_NAVIGATION_MENU_GEN1' => 'Campaign Header', + 'LBL_NAVIGATION_MENU_GEN2' => 'Budget', + 'LBL_NAVIGATION_MENU_TRACKERS' => 'Trackers', + 'LBL_NAVIGATION_MENU_MARKETING' => 'Marketing', + 'LBL_NAVIGATION_MENU_SEND_EMAIL' => 'Send Email', + 'LBL_NAVIGATION_MENU_SUBSCRIPTIONS' => 'Subscriptions', + 'LBL_NAVIGATION_MENU_SUMMARY' => 'Summary', + 'LBL_SUBSCRIPTION_TARGET_WIZARD_DESC' => 'This will define the target list of type Subscription for this campaign.
    This target list will be used to send out emails for this campaign.
    If you do not have a list ready, an empty list will be created for you.', + 'LBL_UNSUBSCRIPTION_TARGET_WIZARD_DESC' => 'This will define the target list of type Unsubscription for this campaign.
    This target list will contain names of people who have opted out of your campaign and should not be contacted through email.
    If you do not have a list ready, an empty list will be created for you.', + 'LBL_TEST_TARGET_WIZARD_DESC' => 'This will define the target list of type Test for this campaign.
    This target list will be used to send out test emails for this campaign.
    If you do not have a list ready, an empty list will be created for you.', + 'LBL_TRACKERS' => 'Trackers', + 'LBL_ADD_TRACKER' => 'Create Tracker', + 'LBL_ADD_TARGET' => 'Add', + 'LBL_CREATE_TARGET'=> 'Create', + 'LBL_SELECT_TARGET'=> 'Use existing Target List', + 'LBL_REMOVE' => ' rem', + 'LBL_CONFIRM' => 'Start', + 'LBL_START' => 'Start', + 'LBL_TOTAL_ENTRIES' => 'Entries', + 'LBL_CONFIRM_CAMPAIGN_SAVE_CONTINUE' => 'Save work and proceed to Marketing Email', + 'LBL_CONFIRM_CAMPAIGN_SAVE_OPTIONS' => 'Save Options', + 'LBL_CONFIRM_CAMPAIGN_SAVE_EXIT' => 'Do you wish to save the information and exit?', + 'LBL_CONFIRM_SEND_SAVE' => 'You are about to leave and proceed to the Send Campaign Email page. Do you wish to save and continue?', + 'LBL_NEWSLETTER WIZARD_TITLE' => 'Newsletter: ', + 'LBL_NEWSLETTER_WIZARD_START_TITLE' => 'Edit Newsletter: ', + 'LBL_CAMPAIGN_WIZARD_START_TITLE' => 'Edit Campaign: ', + 'LBL_SEND_AS_TEST' => 'Send Marketing Email As Test', + 'LBL_SAVE_EXIT_BUTTON_LABEL' => 'Finish', + 'LBL_SAVE_CONTINUE_BUTTON_LABEL' => 'Save and Continue', + 'LBL_TARGET_LISTS' => 'Target Lists', + 'LBL_NO_SUBS_ENTRIES_WARNING' => 'You cannot send a marketing email until your subscription list has at least one entry. You can populate your list after finishing.', + 'LBL_NO_TARGET_ENTRIES_WARNING' => 'You cannot send a marketing email until your target list has at least one entry. You can populate your list after finishing.', + 'LBL_NO_TARGETS_WARNING' => 'You cannot send a marketing email until your campaign has at least one target list.', + 'LBL_NONE' => 'none created', + 'LBL_CAMPAIGN_WIZARD' => 'Campaign Wizard', + 'LBL_EMAIL' =>'Email', + 'LBL_OTHER_TYPE_CAMPAIGN' => 'Non-email based Campaign', + 'LBL_CHOOSE_CAMPAIGN_TYPE' => 'Campaign Type', + 'LBL_TARGET_LIST' => 'Target List', + 'LBL_TARGET_TYPE' => 'Target List Type', + 'LBL_TARGET_NAME' => 'Target List Name', + 'LBL_EMAILS_SCHEDULED' => 'Emails Scheduled', + 'LBL_TEST_EMAILS_SENT' => 'Test Emails Sent', + 'LBL_USERS_CANNOT_OPTOUT' => 'System Users cannot opt out of receiving emails.', + 'LBL_ELECTED_TO_OPTOUT' => 'You have elected to opt out of receiving emails.', + 'LBL_COPY_OF' => 'Copy of ', + 'LBL_SAVED_SEARCH' => 'Saved Search & Layout', + //email setup wizard + 'LBL_WIZ_FROM_NAME' => 'From Name:', + 'LBL_WIZ_FROM_ADDRESS' => 'From Address:', + 'LBL_EMAILS_PER_RUN' => 'Number of emails sent per batch:', + 'LBL_CUSTOM_LOCATION' => 'User Defined', + 'LBL_DEFAULT_LOCATION' => 'Default ', + 'ERR_INT_ONLY_EMAIL_PER_RUN' => 'Only integer values are allow for Number of emails sent per batch', + 'LBL_LOCATION_TRACK' => 'Location of campaign tracking files (like campaign_tracker.php):', + 'LBL_MAIL_SENDTYPE' => 'Mail Transfer Agent:', + 'LBL_MAIL_SMTPAUTH_REQ' => 'Use SMTP Authentication?', + 'LBL_MAIL_SMTPPASS' => 'SMTP Password:', + 'LBL_MAIL_SMTPPORT' => 'SMTP Port', + 'LBL_MAIL_SMTPSERVER' => 'SMTP Server', + 'LBL_MAIL_SMTPUSER' => 'SMTP Username', + 'LBL_EMAIL_SETUP_WIZARD_TITLE' => 'Email Setup for Campaigns', + 'TRACKING_ENTRIES_LOCATION_DEFAULT_VALUE' => 'Value of Config.php setting site_url', + 'LBL_NOTIFY_TITLE' => 'Email Notification Options', + 'LBL_MASS_MAILING_TITLE' => 'Mass Mailing Options', + 'LBL_SERVER_TYPE' => 'Mail Server Protocol', + 'LBL_SERVER_URL' => 'Mail Server Address', + 'LBL_LOGIN' => 'User Name', + 'LBL_PORT' => 'Mail Server Port', + 'LBL_MAILBOX_NAME' => 'Mail Account Name:', + 'LBL_PASSWORD' => 'Password', + 'LBL_MAILBOX_DEFAULT' => 'INBOX', + 'LBL_MAILBOX' => 'Monitored Folder', + 'LBL_NAVIGATION_MENU_SETUP' => 'Setup Email', + 'LBL_NAVIGATION_MENU_NEW_MAILBOX' => 'New Mail Account', + 'LBL_NAVIGATION_MENU_SUMMARY' => 'Summary', + 'LBL_MAILBOX_CHECK_WIZ_GOOD' => 'Mail account(s) with bounce handling were detected. You do not need to create a new one, but you can still do so below.', + 'LBL_MAILBOX_CHECK_WIZ_BAD' => 'No mail accounts with bounce handling were detected, please create a new one below.', + 'LBL_CAMP_MESSAGE_COPY' => 'Keep copies of campaign messages:', + 'LBL_CAMP_MESSAGE_COPY_DESC' => 'Would you like to store complete copies of EACH email message sent during all campaigns? We recommend and default to no. Choosing no will store only the template that is sent and the needed variables to recreate the individual message.', + 'LBL_YES' => 'Yes', + 'LBL_NO' => 'No', + 'LBL_FROM_ADDR' => '"From" Address', + 'LBL_DEFAULT_FROM_ADDR' => 'Default: ', + 'LBL_EMAIL_SETUP_DESC' => 'Fill out the form below to modify your system settings so that campaign emails can be sent out.', + 'LBL_CREATE_MAILBOX' => 'Create New Mail Account', + 'LBL_SSL_DESC' => 'If your mail server supports secure socket connections, enabling this will force SSL connections when importing email.', + 'LBL_SSL' => 'Use SSL', + //campaign diagnostics + 'LNK_CAMPAIGN_DIGNOSTIC_LINK' => 'Campaign may not function as desired and your emails may not be sent for the following reasons:', + 'LBL_CAMPAIGN_DIAGNOSTICS' => 'Campaign Diagnostics', + 'LBL_DIAGNOSTIC' => 'Diagnostic', + 'LBL_MAILBOX_CHECK1_GOOD' => ' Mail account(s)) with bounce handling detected:', + 'LBL_MAILBOX_CHECK1_BAD' => 'No mail account(s) with bounce handling detected.', + 'LBL_MAILBOX_CHECK2_GOOD' => ' E-mail Settings have been configured:', + 'LBL_MAILBOX_CHECK2_BAD' => 'Please configure your system email address. E-mail Settings have not been configured.', + 'LBL_SCHEDULER_CHECK_GOOD' => 'Schedulers detected', + 'LBL_SCHEDULER_CHECK_BAD' => 'No Schedulers detected', + 'LBL_SCHEDULER_CHECK1_BAD' => 'Scheduler has not been set up to process Bounced Campaign Emails.', + 'LBL_SCHEDULER_CHECK2_BAD' => 'Scheduler has not been set up to process Campaign Emails.', + 'LBL_SCHEDULER_NAME' => 'Scheduler', + 'LBL_SCHEDULER_STATUS' => 'Status', + 'LBL_MARKETING_CHECK1_GOOD' => 'Email marketing components detected.', + 'LBL_MARKETING_CHECK1_BAD' => 'No Email marketing components detected, you will need to create one to mail out a campaign.', + 'LBL_MARKETING_CHECK2_GOOD' => 'Target lists detected.', + 'LBL_MARKETING_CHECK2_BAD' => 'No target lists detected, you will need to create one from desired campaign screen.', + 'LBL_EMAIL_SETUP_WIZ' => 'Launch Email Setup', + 'LBL_SCHEDULER_LINK' => 'go to scheduler admin screen.', + 'LBL_TO_WIZARD' => 'launch', + 'LBL_TO_WIZARD_TITLE' => 'Launch Wizard', + 'LBL_EDIT_EXISTING' => 'Edit Campaign', + 'LBL_EDIT_TARGET_LIST' => 'Edit Target List', + 'LBL_SEND_EMAIL' => 'Schedule Email', + 'LBL_USE_EXISTING' => 'Use Existing', + 'LBL_CREATE_NEW_MARKETING_EMAIL' => 'Create New Marketing Email', + 'LBL_CHOOSE_NEXT_STEP' => 'Choose your next step', + 'LBL_NON_ADMIN_ERROR_MSG' => 'Please notify your System Administrator so that they may correct this problem', + 'LBL_EMAIL_COMPONENTS' => 'Email Components', + 'LBL_SCHEDULER_COMPONENTS' => 'Scheduler Components', + 'LBL_RECHECK_BTN'=>'Re-Check', + //web to lead wizard titles + 'LBL_WEB_TO_LEAD_FORM_TITLE1' => 'Create Lead Form: Select fields', + 'LBL_WEB_TO_LEAD_FORM_TITLE2' => 'Create Lead Form: Form properties', + 'LBL_DRAG_DROP_COLUMNS' => 'Drag and drop lead fields in column 1 & 2', + 'LBL_DEFINE_LEAD_HEADER' => 'Form Header:', + 'LBL_LEAD_DEFAULT_HEADER' => 'Web to lead form for Campaign', + 'LBL_DEFINE_LEAD_SUBMIT' => 'Submit Button Label:', + 'LBL_DEFINE_LEAD_POST_URL' => 'Post URL:', + 'LBL_EDIT_LEAD_POST_URL' => 'Edit Post URL?', + 'LBL_DEFINE_LEAD_REDIRECT_URL' => 'Redirect URL:', + 'LBL_LEAD_NOTIFY_CAMPAIGN' => 'Related Campaign:', + 'LBL_DEFAULT_LEAD_SUBMIT' => 'Submit', + 'LBL_WEB_TO_LEAD' => 'Create Lead Form', + 'LBL_LEAD_FOOTER' => 'Form Footer:', + 'LBL_CAMPAIGN_NOT_SELECTED' => 'Select and associate a campaign:', + 'NTC_NO_LEGENDS' => 'None', + 'LBL_SELECT_LEAD_FIELDS' => 'Please select from available fields', + 'LBL_DESCRIPTION_LEAD_FORM' => 'Form Description:', + 'LBL_DESCRIPTION_TEXT_LEAD_FORM' => 'Submitting this form will create a lead and link with campaign', + 'LBL_DOWNLOAD_TEXT_WEB_TO_LEAD_FORM' =>'Please download your Web To Lead form', + 'LBL_DOWNLOAD_WEB_TO_LEAD_FORM' =>'Web To Lead Form', + 'LBL_PROVIDE_WEB_TO_LEAD_FORM_FIELDS' =>'Please provide all the required fields', + 'LBL_NOT_VALID_EMAIL_ADDRESS' =>'Not a valid email address', + 'LBL_AVALAIBLE_FIELDS_HEADER' => 'Available Fields', + 'LBL_LEAD_FORM_FIRST_HEADER' => 'Lead Form (First Column)', + 'LBL_LEAD_FORM_SECOND_HEADER' =>'Lead Form (Second Column)', + 'LBL_LEAD_MODULE' => 'Leads', + 'LBL_CREATE_WEB_TO_LEAD_FORM' => 'CreateWebToLeadForm', + 'LBL_SELECT_REQUIRED_LEAD_FIELDS' => 'Please select required fields:', + //Campaign charts + 'LBL_CAMPAIGN_RETURN_ON_INVESTMENT' =>'Campaign Return On Investment', + 'LBL_CAMPAIGN_RESPONSE_BY_RECIPIENT_ACTIVITY'=>'Campaign Response by Recipient Activity', + 'LBL_LOG_ENTRIES_BLOCKEDD_TITLE'=>'Suppressed by Email Address or domain', + + 'LBL_AMOUNT_IN' => 'Amount in ', + + // Labels for ROI Chart + 'LBL_ROI_CHART_REVENUE' => 'Revenue', + 'LBL_ROI_CHART_INVESTMENT' => 'Investment', + 'LBL_ROI_CHART_BUDGET' => 'Budget', + 'LBL_ROI_CHART_EXPECTED_REVENUE' => 'Expected Revenue', + + // Top Campaigns Dashlet + 'LBL_TOP_CAMPAIGNS' => 'Top Campaigns', + 'LBL_TOP_CAMPAIGNS_NAME' => 'Campaign Name', + 'LBL_TOP_CAMPAIGNS_REVENUE' => 'Revenue', + 'LBL_LEADS' => 'Leads', + 'LBL_CONTACTS' => 'Contacts', + 'LBL_ACCOUNTS' => 'Accounts', + 'LBL_OPPORTUNITIES' => 'Opportunities', + 'LBL_CREATED_USER' => 'Created User', + 'LBL_MODIFIED_USER' => 'Modified User', + 'LBL_LOG_ENTRIES' => 'Log Entries', + 'LBL_PROSPECTLISTS_SUBPANEL_TITLE' => 'Prospect List', + 'LBL_EMAILMARKETING_SUBPANEL_TITLE' => 'Email Marketing', + 'LBL_TRACK_QUEUE_SUBPANEL_TITLE' => 'Track Queue', + 'LBL_TARGETED_SUBPANEL_TITLE' => 'Targeted', + 'LBL_VIEWED_SUBPANEL_TITLE' => 'Viewed', + 'LBL_LINK_SUBPANEL_TITLE' => 'Link', + 'LBL_LEAD_SUBPANEL_TITLE' => 'Lead', + 'LBL_CONTACT_SUBPANEL_TITLE' => 'Contact', + 'LBL_INVALID EMAIL_SUBPANEL_TITLE' => 'Invalid Email', + 'LBL_SEND ERROR_SUBPANEL_TITLE' => 'Send Error', + 'LBL_REMOVED_SUBPANEL_TITLE' => 'Removed', + 'LBL_BLOCKED_SUBPANEL_TITLE' => 'Blocked', + 'LBL_ACCOUNTS_SUBPANEL_TITLE' => 'Accounts', + 'LBL_LEADS_SUBPANEL_TITLE' => 'Leads', + 'LBL_OPPORTUNITIES_SUBPANEL_TITLE' => 'Opportunities', + + 'LBL_IMPORT_PROSPECTS'=>'Import Targets', + 'LBL_LEAD_FORM_WIZARD' => 'Lead Form Wizard', + 'LBL_CAMPAIGN_INFORMATION' => 'Campaign Overview', + + 'LBL_MONTH' => "Month", + 'LBL_YEAR' => "Year", + 'LBL_DAY' => "Day", +); + + +?> diff --git a/modules/Campaigns/metadata/SearchFields.php b/modules/Campaigns/metadata/SearchFields.php new file mode 100644 index 00000000..e27b1a37 --- /dev/null +++ b/modules/Campaigns/metadata/SearchFields.php @@ -0,0 +1,66 @@ + array( 'query_type'=>'default'), + 'campaign_type'=> array('query_type'=>'default', 'options' => 'campaign_type_dom', 'template_var' => 'TYPE_OPTIONS'), + 'status'=> array('query_type'=>'default', 'options' => 'campaign_status_dom', 'template_var' => 'STATUS_OPTIONS'), + 'current_user_only'=> array('query_type'=>'default','db_field'=>array('assigned_user_id'),'my_items'=>true, 'vname' => 'LBL_CURRENT_USER_FILTER', 'type' => 'bool'), + 'assigned_user_id'=> array('query_type'=>'default'), + + //Range Search Support + 'range_date_entered' => array ('query_type' => 'default', 'enable_range_search' => true, 'is_date_field' => true), + 'start_range_date_entered' => array ('query_type' => 'default', 'enable_range_search' => true, 'is_date_field' => true), + 'end_range_date_entered' => array ('query_type' => 'default', 'enable_range_search' => true, 'is_date_field' => true), + 'range_date_modified' => array ('query_type' => 'default', 'enable_range_search' => true, 'is_date_field' => true), + 'start_range_date_modified' => array ('query_type' => 'default', 'enable_range_search' => true, 'is_date_field' => true), + 'end_range_date_modified' => array ('query_type' => 'default', 'enable_range_search' => true, 'is_date_field' => true), + + 'range_start_date' => array ('query_type' => 'default', 'enable_range_search' => true, 'is_date_field' => true), + 'start_range_start_date' => array ('query_type' => 'default', 'enable_range_search' => true, 'is_date_field' => true), + 'end_range_start_date' => array ('query_type' => 'default', 'enable_range_search' => true, 'is_date_field' => true), + 'range_end_date' => array ('query_type' => 'default', 'enable_range_search' => true, 'is_date_field' => true), + 'start_range_end_date' => array ('query_type' => 'default', 'enable_range_search' => true, 'is_date_field' => true), + 'end_range_end_date' => array ('query_type' => 'default', 'enable_range_search' => true, 'is_date_field' => true), + + 'range_amount' => array ('query_type' => 'default', 'enable_range_search' => true), + 'start_range_amount' => array ('query_type' => 'default', 'enable_range_search' => true), + 'end_range_amount' => array ('query_type' => 'default', 'enable_range_search' => true), + //Range Search Support + ); +?> diff --git a/modules/Campaigns/metadata/additionalDetails.php b/modules/Campaigns/metadata/additionalDetails.php new file mode 100644 index 00000000..4dab4593 --- /dev/null +++ b/modules/Campaigns/metadata/additionalDetails.php @@ -0,0 +1,74 @@ +'. $mod_strings['LBL_CAMPAIGN_START_DATE'] . ' ' . $fields['START_DATE'] . '
    '; + + if(!empty($fields['TRACKER_TEXT'])) + $overlib_string .= ''. $mod_strings['LBL_TRACKER_TEXT'] . ' ' . $fields['TRACKER_TEXT'] . '
    '; + if(!empty($fields['REFER_URL'])) + $overlib_string .= '' . $fields['REFER_URL'] . '
    '; + + if(!empty($fields['OBJECTIVE'])) { + $overlib_string .= ''. $mod_strings['LBL_CAMPAIGN_OBJECTIVE'] . ' ' . substr($fields['OBJECTIVE'], 0, 300); + if(strlen($fields['OBJECTIVE']) > 300) $overlib_string .= '...'; + $overlib_string .= '
    '; + } + if(!empty($fields['CONTENT'])) { + $overlib_string .= ''. $mod_strings['LBL_CAMPAIGN_CONTENT'] . ' ' . substr($fields['CONTENT'], 0, 300); + if(strlen($fields['CONTENT']) > 300) $overlib_string .= '...'; + } + + return array('fieldToAddTo' => 'NAME', + 'string' => $overlib_string, + 'editLink' => "index.php?action=EditView&module=Campaigns&return_module=Campaigns&record={$fields['ID']}", + 'viewLink' => "index.php?action=DetailView&module=Campaigns&return_module=Campaigns&record={$fields['ID']}"); +} + + ?> + + \ No newline at end of file diff --git a/modules/Campaigns/metadata/detailviewdefs.php b/modules/Campaigns/metadata/detailviewdefs.php new file mode 100644 index 00000000..d50bc5de --- /dev/null +++ b/modules/Campaigns/metadata/detailviewdefs.php @@ -0,0 +1,158 @@ + array('form' => array('buttons' => + array('EDIT', 'DUPLICATE', 'DELETE', + array('customCode'=>''), + array('customCode'=>''), + array('customCode'=>''), + array('customCode'=>''), + array('customCode'=>''), + ), + 'links' => array('', + '', + '', + ), + ), + 'maxColumns' => '2', + 'widths' => array( + array('label' => '10', 'field' => '30'), + array('label' => '10', 'field' => '30') + ), + + ), +'panels' =>array ( + 'lbl_campaign_information'=> array( + array ( + 'name', + array ( + 'name' => 'status', + 'label' => 'LBL_CAMPAIGN_STATUS', + ), + ), + + array ( + + array ( + 'name' => 'start_date', + 'label' => 'LBL_CAMPAIGN_START_DATE', + ), + 'campaign_type', + ), + + array ( + array ( + 'name' => 'end_date', + 'label' => 'LBL_CAMPAIGN_END_DATE', + ), + array( + 'name' => 'frequency', + 'customCode' => '{if $fields.campaign_type.value == "NewsLetter"}
    {$fields.frequency.value}
    {/if} ', + 'customLabel' => '{if $fields.campaign_type.value == "NewsLetter"}
    {$MOD.LBL_CAMPAIGN_FREQUENCY}
    {/if} ' + ), + ), + + array ( + array ( + 'name' => 'impressions', + 'label' => 'LBL_CAMPAIGN_IMPRESSIONS', + ), + ), + + array ( + + array ( + 'name' => 'budget', + 'label' => '{$MOD.LBL_CAMPAIGN_BUDGET} ({$CURRENCY})', + ), + array ( + 'name' => 'expected_cost', + 'label' => '{$MOD.LBL_CAMPAIGN_EXPECTED_COST} ({$CURRENCY})', + ), + ), + + array ( + array ( + 'name' => 'actual_cost', + 'label' => '{$MOD.LBL_CAMPAIGN_ACTUAL_COST} ({$CURRENCY})', + ), + array ( + 'name' => 'expected_revenue', + 'label' => '{$MOD.LBL_CAMPAIGN_EXPECTED_REVENUE} ({$CURRENCY})', + ), + ), + + array ( + + array ( + 'name' => 'objective', + 'label' => 'LBL_CAMPAIGN_OBJECTIVE', + ), + ), + + array ( + + array ( + 'name' => 'content', + 'label' => 'LBL_CAMPAIGN_CONTENT', + ), + ), + ), + + 'LBL_PANEL_ASSIGNMENT' => array( + array ( + array ( + 'name' => 'assigned_user_name', + 'label' => 'LBL_ASSIGNED_TO', + ), + array ( + 'name' => 'date_modified', + 'label' => 'LBL_DATE_MODIFIED', + 'customCode' => '{$fields.date_modified.value} {$APP.LBL_BY} {$fields.modified_by_name.value}', + ), + ), + array ( + array ( + 'name' => 'date_entered', + 'customCode' => '{$fields.date_entered.value} {$APP.LBL_BY} {$fields.created_by_name.value}', + ), + ), + ), +) + +); +?> \ No newline at end of file diff --git a/modules/Campaigns/metadata/editviewdefs.php b/modules/Campaigns/metadata/editviewdefs.php new file mode 100644 index 00000000..5ebb708c --- /dev/null +++ b/modules/Campaigns/metadata/editviewdefs.php @@ -0,0 +1,150 @@ + array('maxColumns' => '2', + 'widths' => array( + array('label' => '10', 'field' => '30'), + array('label' => '10', 'field' => '30') + ), + 'javascript' => ' +', +), + 'panels' =>array ( + 'lbl_campaign_information' => + array ( + + array ( + array('name'=>'name'), + array('name' => 'status'), + ), + + array ( + array('name'=>'start_date', 'displayParams'=>array('required'=>false, 'showFormats'=>true)), + array('name'=>'campaign_type', + 'displayParams'=>array('javascript'=>'onchange="type_change();"'), + ), + ), + + array ( + array('name'=>'end_date', 'displayParams'=>array('showFormats'=>true)), + array ( + 'name' => 'frequency', + 'customCode' => '
    {html_options name="frequency" options=$fields.frequency.options selected=$fields.frequency.value}
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

    {$MOD.LBL_WIZ_NEWSLETTER_TITLE_STEP2}

    {$MOD.LBL_WIZARD_BUDGET_MESSAGE}
     
     
    {$MOD.LBL_CAMPAIGN_BUDGET}{$MOD.LBL_CAMPAIGN_ACTUAL_COST}
    {$MOD.LBL_CAMPAIGN_EXPECTED_REVENUE}{$MOD.LBL_CAMPAIGN_EXPECTED_COST}
    {$MOD.LBL_CURRENCY}{$MOD.LBL_CAMPAIGN_IMPRESSIONS}
        
    {$MOD.LBL_CAMPAIGN_OBJECTIVE}
        
    +

    + + diff --git a/modules/Campaigns/tpls/WizardCampaignHeader.tpl b/modules/Campaigns/tpls/WizardCampaignHeader.tpl new file mode 100644 index 00000000..30e2db2b --- /dev/null +++ b/modules/Campaigns/tpls/WizardCampaignHeader.tpl @@ -0,0 +1,156 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +/********************************************************************************* + + ********************************************************************************/ +*} + + + {$CAMPAIGN_DIAGNOSTIC_LINK} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

    {$MOD.LBL_WIZ_NEWSLETTER_TITLE_STEP1}

     
    {$MOD.LBL_WIZARD_HEADER_MESSAGE}
     
     
    {$MOD.LBL_NAME} {$APP.LBL_REQUIRED_SYMBOL}{$APP.LBL_ASSIGNED_TO} + +
    {$MOD.LBL_CAMPAIGN_STATUS} {$APP.LBL_REQUIRED_SYMBOL}
    {$MOD.LBL_CAMPAIGN_START_DATE} {$APP.LBL_ENTER_DATE} {$USER_DATEFORMAT}{$MOD.LBL_CAMPAIGN_TYPE} <{$SHOULD_TYPE_BE_DISABLED} id='campaign_type' title='{$MOD.LBL_CAMPAIGN_TYPE}' name='wiz_step1_campaign_type' >{$CAMPAIGN_TYPE_OPTIONS}
    {$MOD.LBL_CAMPAIGN_END_DATE} {$APP.LBL_REQUIRED_SYMBOL} {$APP.LBL_ENTER_DATE} {$USER_DATEFORMAT}{$FREQUENCY_LABEL} <{$HIDE_FREQUENCY_IF_NEWSLETTER} tabindex='1' id='frequency' name='wiz_step1_frequency' title='{$MOD.LBL_CAMPAIGN_FREQUENCY}'>{$FREQ_OPTIONS}
        
    {$MOD.LBL_CAMPAIGN_CONTENT}
        

    + + {literal} + + {/literal} + diff --git a/modules/Campaigns/tpls/WizardCampaignTargetList.tpl b/modules/Campaigns/tpls/WizardCampaignTargetList.tpl new file mode 100644 index 00000000..0fb7bced --- /dev/null +++ b/modules/Campaigns/tpls/WizardCampaignTargetList.tpl @@ -0,0 +1,183 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +/********************************************************************************* + + ********************************************************************************/ +*} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

    {$MOD.LBL_WIZ_NEWSLETTER_TITLE_STEP4}

    {$MOD.LBL_WIZARD_SUBSCRIPTION_MESSAGE}
     
    + {$MOD.LBL_SUBSCRIPTION_LIST_NAME} + {$MOD.LBL_DEFAULT_LOCATION}
    + {$MOD.LBL_CUSTOM_LOCATION} +
    + + + + +
     
    + {$MOD.LBL_UNSUBSCRIPTION_LIST_NAME} + {$MOD.LBL_DEFAULT_LOCATION}
    + {$MOD.LBL_CUSTOM_LOCATION} +
    + + + + +
     
    + + {$MOD.LBL_TEST_LIST_NAME} + {$MOD.LBL_DEFAULT_LOCATION}
    + {$MOD.LBL_CUSTOM_LOCATION} +
    + + + + +
        
    +

    + + {literal} + + {/literal} diff --git a/modules/Campaigns/tpls/WizardCampaignTargetListForNonNewsLetter.tpl b/modules/Campaigns/tpls/WizardCampaignTargetListForNonNewsLetter.tpl new file mode 100644 index 00000000..731de60e --- /dev/null +++ b/modules/Campaigns/tpls/WizardCampaignTargetListForNonNewsLetter.tpl @@ -0,0 +1,308 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +/********************************************************************************* + + ********************************************************************************/ +*} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

    {$MOD.LBL_TARGET_LISTS}

    {$MOD.LBL_WIZARD_TARGET_MESSAGE1}
     
    {$MOD.LBL_SELECT_TARGET}  + + + + + +  
     
    {$MOD.LBL_WIZARD_TARGET_MESSAGE2}
    {$MOD.LBL_TARGET_NAME} + + + {$MOD.LBL_TARGET_TYPE} + + + + + +
     
    + + + +
    {$MOD.LBL_TRACKERS_ADDED}
    + + + + + + +
    {$MOD.LBL_TARGET_NAME}{$MOD.LBL_TARGET_TYPE}  
    +
    + {$EXISTING_TARGETS} +
    + + +
    + +

    + + + + {/literal} diff --git a/modules/Campaigns/tpls/WizardCampaignTracker.tpl b/modules/Campaigns/tpls/WizardCampaignTracker.tpl new file mode 100644 index 00000000..883cc673 --- /dev/null +++ b/modules/Campaigns/tpls/WizardCampaignTracker.tpl @@ -0,0 +1,257 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +/********************************************************************************* + + ********************************************************************************/ +*} + + + + + + + + + + + + + + + +

    {$MOD.LBL_WIZ_NEWSLETTER_TITLE_STEP3}

    {$MOD.LBL_WIZARD_TRACKER_MESSAGE}
     
     
    +

    + + + + + + + + + + + + +
    {$MOD.LBL_EDIT_TRACKER_NAME}  {$MOD.LBL_EDIT_OPT_OUT_} 
    {$MOD.LBL_EDIT_TRACKER_URL} 
     
    +
    + + + +
    {$MOD.LBL_TRACKERS_ADDED}
    + + + + + + +
    {$MOD.LBL_EDIT_OPT_OUT}{$MOD.LBL_EDIT_TRACKER_NAME}{$MOD.LBL_EDIT_TRACKER_URL}
    +
    + {$EXISTING_TRACKERS} +
    + + +
    +

    + + {/literal} diff --git a/modules/Campaigns/tpls/WizardHomeStart.tpl b/modules/Campaigns/tpls/WizardHomeStart.tpl new file mode 100644 index 00000000..f98b8d6a --- /dev/null +++ b/modules/Campaigns/tpls/WizardHomeStart.tpl @@ -0,0 +1,111 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +/********************************************************************************* + + ********************************************************************************/ +*} + +

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

    +

    +

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

    {$MOD.LBL_CHOOSE_CAMPAIGN_TYPE}

    {$MOD.LBL_HOME_START_MESSAGE}

      + {$MOD.LBL_NEWSLETTER}
    + {$MOD.LBL_EMAIL}
    + {$MOD.LBL_OTHER_TYPE_CAMPAIGN}
    +
    +
    +

    + + + +
    + +
    + + + + + +
      + + +
    +
    +
    + +
    + + + +
    + + + diff --git a/modules/Campaigns/tpls/WizardNewsletter.tpl b/modules/Campaigns/tpls/WizardNewsletter.tpl new file mode 100644 index 00000000..d1124224 --- /dev/null +++ b/modules/Campaigns/tpls/WizardNewsletter.tpl @@ -0,0 +1,109 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +/********************************************************************************* + + ********************************************************************************/ +*} + +{$ROLLOVERSTYLE} +
    + + + + + + + + + + + +

    +

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

    + + + + + +
    + + + +
    +
    + +{$STEPS} + + +
    +
    +
    + + + + + + +{$WIZ_JAVASCRIPT} +{$DIV_JAVASCRIPT} +{$JAVASCRIPT} + + diff --git a/modules/Campaigns/utils.php b/modules/Campaigns/utils.php new file mode 100644 index 00000000..a81bd220 --- /dev/null +++ b/modules/Campaigns/utils.php @@ -0,0 +1,985 @@ +query($query); + while(($row=$db->fetchByAssoc($result))!= null) { + $return_array[$row['prospect_list_id']]=$row['name']; + } + if (empty($return_array)) $return_array=array(); + else return $return_array; +} +/** + * Return bounce handling mailboxes for campaign. + * + * @param unknown_type $emails + * @param unknown_type $get_box_name, Set it to false if want to get "From Name" other than the InboundEmail Name. + * @return $get_name=true, bounce handling mailboxes' name; $get_name=false, bounce handling mailboxes' from name. + */ +function get_campaign_mailboxes(&$emails, $get_name=true) { + if (!class_exists('InboundEmail')) { + require('modules/InboundEmail/InboundEmail.php'); + } + $query = "select id,name,stored_options from inbound_email where mailbox_type='bounce' and status='Active' and deleted='0'"; + $db = DBManagerFactory::getInstance(); + $result=$db->query($query); + while(($row=$db->fetchByAssoc($result))!= null) { + if($get_name) { + $return_array[$row['id']] = $row['name']; + } else { + $return_array[$row['id']]= InboundEmail::get_stored_options('from_name',$row['name'],$row['stored_options']); + } + $emails[$row['id']]=InboundEmail::get_stored_options('from_addr','nobody@example.com',$row['stored_options']); + } + + if (empty($return_array)) $return_array=array(''=>''); + return $return_array; + +} + +function get_campaign_mailboxes_with_stored_options() { + $ret = array(); + + if(!class_exists('InboundEmail')) { + require('modules/InboundEmail/InboundEmail.php'); + } + + $q = "SELECT id, name, stored_options FROM inbound_email WHERE mailbox_type='bounce' AND status='Active' AND deleted='0'"; + + $db = DBManagerFactory::getInstance(); + + $r = $db->query($q); + + while($a = $db->fetchByAssoc($r)) { + $ret[$a['id']] = unserialize(base64_decode($a['stored_options'])); + } + return $ret; +} + +function log_campaign_activity($identifier, $activity, $update=true, $clicked_url_key=null) { + + $return_array = array(); + + $db = DBManagerFactory::getInstance(); + + + + //check to see if the identifier has been replaced with Banner string + if($identifier == 'BANNER' && isset($clicked_url_key) && !empty($clicked_url_key)) + { + // create md5 encrypted string using the client ip, this will be used for tracker id purposes + $enc_id = 'BNR'.md5($_SERVER['REMOTE_ADDR']); + + //default the identifier to ip address + $identifier = $enc_id; + + //if user has chosen to not use this mode of id generation, then replace identifier with plain guid. + //difference is that guid will generate a new campaign log for EACH CLICK!! + //encrypted generation will generate 1 campaign log and update the hit counter for each click + if(isset($sugar_config['campaign_banner_id_generation']) && $sugar_config['campaign_banner_id_generation'] != 'md5'){ + $identifier = create_guid(); + } + + //retrieve campaign log. + $trkr_query = "select * from campaign_log where target_tracker_key='$identifier ' and related_id = '$clicked_url_key'"; + $current_trkr=$db->query($trkr_query); + $row=$db->fetchByAssoc($current_trkr); + + //if campaign log is not retrieved (this is a new ip address or we have chosen to create + //unique entries for each click + if($row==null || empty($row)){ + + + //retrieve campaign id + $trkr_query = "select ct.campaign_id from campaign_trkrs ct, campaigns c where c.id = ct.campaign_id and ct.id = '$clicked_url_key'"; + $current_trkr=$db->query($trkr_query); + $row=$db->fetchByAssoc($current_trkr); + + + //create new campaign log with minimal info. Note that we are creating new unique id + //as target id, since we do not link banner/web campaigns to any users + + $data['target_id']="'" . create_guid() . "'"; + $data['target_type']= "'Prospects'"; + $data['id']="'" . create_guid() . "'"; + $data['campaign_id']="'" . $row['campaign_id'] . "'"; + $data['target_tracker_key']="'" . $identifier . "'"; + $data['activity_type']="'" . $activity . "'"; + $data['activity_date']="'" . TimeDate::getInstance()->nowDb() . "'"; + $data['hits']=1; + if (!empty($clicked_url_key)) { + $data['related_id']="'".$clicked_url_key."'"; + $data['related_type']="'".'CampaignTrackers'."'"; + } + + //values for return array.. + $return_array['target_id']=$data['target_id']; + $return_array['target_type']=$data['target_type']; + + //create insert query for new campaign log + $insert_query="INSERT into campaign_log (" . implode(",",array_keys($data)) . ")"; + $insert_query.=" VALUES (" . implode(",",array_values($data)) . ")"; + $db->query($insert_query); + }else{ + + //campaign log already exists, so just set the return array and update hits column + $return_array['target_id']= $row['target_id']; + $return_array['target_type']= $row['target_type']; + $query1="update campaign_log set hits=hits+1 where id='{$row['id']}'"; + $current=$db->query($query1); + + + } + + //return array and exit + return $return_array; + + } + + + + $query1="select * from campaign_log where target_tracker_key='$identifier' and activity_type='$activity'"; + if (!empty($clicked_url_key)) { + $query1.=" AND related_id='$clicked_url_key'"; + } + $current=$db->query($query1); + $row=$db->fetchByAssoc($current); + + if ($row==null) { + $query="select * from campaign_log where target_tracker_key='$identifier' and activity_type='targeted'"; + $targeted=$db->query($query); + $row=$db->fetchByAssoc($targeted); + + //if activity is removed and target type is users, then a user is trying to opt out + //of emails. This is not possible as Users Table does not have opt out column. + if ($row && (strtolower($row['target_type']) == 'users' && $activity == 'removed' )) { + $return_array['target_id']= $row['target_id']; + $return_array['target_type']= $row['target_type']; + return $return_array; + } + elseif ($row){ + $data['id']="'" . create_guid() . "'"; + $data['campaign_id']="'" . $row['campaign_id'] . "'"; + $data['target_tracker_key']="'" . $identifier . "'"; + $data['target_id']="'" . $row['target_id'] . "'"; + $data['target_type']="'" . $row['target_type'] . "'"; + $data['activity_type']="'" . $activity . "'"; + $data['activity_date']="'" . TimeDate::getInstance()->nowDb() . "'"; + $data['list_id']="'" . $row['list_id'] . "'"; + $data['marketing_id']="'" . $row['marketing_id'] . "'"; + $data['hits']=1; + if (!empty($clicked_url_key)) { + $data['related_id']="'".$clicked_url_key."'"; + $data['related_type']="'".'CampaignTrackers'."'"; + } + //values for return array.. + $return_array['target_id']=$row['target_id']; + $return_array['target_type']=$row['target_type']; + $insert_query="INSERT into campaign_log (" . implode(",",array_keys($data)) . ")"; + $insert_query.=" VALUES (" . implode(",",array_values($data)) . ")"; + $db->query($insert_query); + } + } else { + + $return_array['target_id']= $row['target_id']; + $return_array['target_type']= $row['target_type']; + + $query1="update campaign_log set hits=hits+1 where id='{$row['id']}'"; + $current=$db->query($query1); + + } + //check to see if this is a removal action + if ($row && $activity == 'removed' ) { + //retrieve campaign and check it's type, we are looking for newsletter Campaigns + $query = "SELECT campaigns.* FROM campaigns WHERE campaigns.id = '".$row['campaign_id']."' "; + $result = $db->query($query); + if(!empty($result)) + { + $c_row = $db->fetchByAssoc($result); + + //if type is newsletter, then add campaign id to return_array for further processing. + if(isset($c_row['campaign_type']) && $c_row['campaign_type'] == 'NewsLetter'){ + $return_array['campaign_id']=$c_row['id']; + } + } + } + return $return_array; + } + + +function campaign_log_lead_entry($campaign_id, $parent_bean,$child_bean,$activity_type){ + global $timedate; + + + //create campaign tracker id and retrieve related bio bean + $tracker_id = create_guid(); + //create new campaign log record. + $campaign_log = new CampaignLog(); + $campaign_log->campaign_id = $campaign_id; + $campaign_log->target_tracker_key = $tracker_id; + $campaign_log->related_id = $parent_bean->id; + $campaign_log->related_type = $parent_bean->module_dir; + $campaign_log->target_id = $child_bean->id; + $campaign_log->target_type = $child_bean->module_dir; + $campaign_log->activity_date = $timedate->now(); + $campaign_log->activity_type = $activity_type; + //save the campaign log entry + $campaign_log->save(); +} + +function get_campaign_urls($campaign_id) { + $return_array=array(); + + if (!empty($campaign_id)) { + + $db = DBManagerFactory::getInstance(); + + $query1="select * from campaign_trkrs where campaign_id='$campaign_id' and deleted=0"; + $current=$db->query($query1); + while (($row=$db->fetchByAssoc($current)) != null) { + $return_array['{'.$row['tracker_name'].'}']=$row['tracker_name'] . ' : ' . $row['tracker_url']; + } + } + return $return_array; +} + +/** + * Queries for the list + */ +function get_subscription_lists_query($focus, $additional_fields = null) { + //get all prospect lists belonging to Campaigns of type newsletter + $all_news_type_pl_query = "select c.name, pl.list_type, plc.campaign_id, plc.prospect_list_id"; + if(is_array($additional_fields) && !empty($additional_fields)) $all_news_type_pl_query .= ', ' . implode(', ', $additional_fields); + $all_news_type_pl_query .= " from prospect_list_campaigns plc , prospect_lists pl, campaigns c "; + + + $all_news_type_pl_query .= "where plc.campaign_id = c.id "; + $all_news_type_pl_query .= "and plc.prospect_list_id = pl.id "; + $all_news_type_pl_query .= "and c.campaign_type = 'NewsLetter' and pl.deleted = 0 and c.deleted=0 and plc.deleted=0 "; + $all_news_type_pl_query .= "and (pl.list_type like 'exempt%' or pl.list_type ='default') "; + + $all_news_type_list =$focus->db->query($all_news_type_pl_query); + + //build array of all newsletter campaigns + $news_type_list_arr = array(); + while ($row = $focus->db->fetchByAssoc($all_news_type_list)){$news_type_list_arr[] = $row;} + + //now get all the campaigns that the current user is assigned to + $all_plp_current = "select prospect_list_id from prospect_lists_prospects where related_id = '$focus->id' and deleted = 0 "; + + //build array of prospect lists that this user belongs to + $current_plp =$focus->db->query($all_plp_current ); + $current_plp_arr = array(); + while ($row = $focus->db->fetchByAssoc($current_plp)){$current_plp_arr[] = $row;} + + return array('current_plp_arr' => $current_plp_arr, 'news_type_list_arr' => $news_type_list_arr); +} +/* + * This function takes in a bean from a lead, propsect, or contact and returns an array containing + * all subscription lists that the bean is a part of, and all the subscriptions that the bean is not + * a part of. The array elements have the key names of "subscribed" and "unsusbscribed". These elements contain an array + * of the corresponding list. In other words, the "subscribed" element holds another array that holds the subscription information. + * + * The subscription information is a concatenated string that holds the prospect list id and the campaign id, seperated by at "@" character. + * To parse these information string into something more usable, use the "process subscriptions()" function + * + * */ +function get_subscription_lists($focus, $descriptions = false) { + $subs_arr = array(); + $unsubs_arr = array(); + + $results = get_subscription_lists_query($focus, $descriptions); + + $news_type_list_arr = $results['news_type_list_arr']; + $current_plp_arr = $results['current_plp_arr']; + + //For each prospect list of type 'NewsLetter', check to see if current user is already in list, + foreach($news_type_list_arr as $news_list){ + $match = 'false'; + + //perform this check against each prospect list this user belongs to + foreach($current_plp_arr as $current_list_key => $current_list){//echo " new entry from current lists user is subscribed to-------------"; + //compare current user list id against newsletter id + if ($news_list['prospect_list_id'] == $current_list['prospect_list_id']){ + //if id's match, user is subscribed to this list, check to see if this is an exempt list, + if(strpos($news_list['list_type'], 'exempt')!== false){ + //this is an exempt list, so process + if(array_key_exists($news_list['name'],$subs_arr)){ + //first, add to unsubscribed array + $unsubs_arr[$news_list['name']] = $subs_arr[$news_list['name']]; + //now remove from exempt subscription list + unset($subs_arr[$news_list['name']]); + }else{ + //we know this is an exempt list the user belongs to, but the + //non exempt list has not been processed yet, so just add to exempt array + $unsubs_arr[$news_list['name']] = "prospect_list@".$news_list['prospect_list_id']."@campaign@".$news_list['campaign_id']; + } + $match = 'false';//although match is false, this is an exempt array, so + //it will not be added a second time down below + }else{ + //this list is not exempt, and user is subscribed, so add to subscribed array, and unset from the unsubs_arr + //as long as this list is not in exempt array + $temp = "prospect_list@".$news_list['prospect_list_id']."@campaign@".$news_list['campaign_id']; + if(!array_search($temp,$unsubs_arr)){ + $subs_arr[$news_list['name']] = "prospect_list@".$news_list['prospect_list_id']."@campaign@".$news_list['campaign_id']; + $match = 'true'; + //unset($unsubs_arr[$news_list['name']]); + } + } + }else{ + //do nothing, there is no match + } + } + //if this newsletter id never matched a user subscription.. + //..then add to available(unsubscribed) NewsLetters if list is not of type exempt + if(($match == 'false') && (strpos($news_list['list_type'], 'exempt') === false)){ + $unsubs_arr[$news_list['name']] = "prospect_list@".$news_list['prospect_list_id']."@campaign@".$news_list['campaign_id']; + } + + } + $return_array['unsubscribed'] = $unsubs_arr; + $return_array['subscribed'] = $subs_arr; + return $return_array; +} + +/** + * same function as get_subscription_lists, but with the data seperated in an associated array + */ +function get_subscription_lists_keyed($focus) { + $subs_arr = array(); + $unsubs_arr = array(); + + $results = get_subscription_lists_query($focus, array('c.content', 'c.frequency')); + + $news_type_list_arr = $results['news_type_list_arr']; + $current_plp_arr = $results['current_plp_arr']; + + //For each prospect list of type 'NewsLetter', check to see if current user is already in list, + foreach($news_type_list_arr as $news_list){ + $match = false; + + $news_list_data = array('prospect_list_id' => $news_list['prospect_list_id'], + 'campaign_id' => $news_list['campaign_id'], + 'description' => $news_list['content'], + 'frequency' => $news_list['frequency']); + + //perform this check against each prospect list this user belongs to + foreach($current_plp_arr as $current_list_key => $current_list){//echo " new entry from current lists user is subscribed to-------------"; + //compare current user list id against newsletter id + if ($news_list['prospect_list_id'] == $current_list['prospect_list_id']){ + //if id's match, user is subscribed to this list, check to see if this is an exempt list, + + if($news_list['list_type'] == 'exempt'){ + //this is an exempt list, so process + if(array_key_exists($news_list['name'],$subs_arr)){ + //first, add to unsubscribed array + $unsubs_arr[$news_list['name']] = $subs_arr[$news_list['name']]; + //now remove from exempt subscription list + unset($subs_arr[$news_list['name']]); + }else{ + //we know this is an exempt list the user belongs to, but the + //non exempt list has not been processed yet, so just add to exempt array + $unsubs_arr[$news_list['name']] = $news_list_data; + } + $match = false;//although match is false, this is an exempt array, so + //it will not be added a second time down below + }else{ + //this list is not exempt, and user is subscribed, so add to subscribed array + //as long as this list is not in exempt array + if(!array_key_exists($news_list['name'],$unsubs_arr)){ + $subs_arr[$news_list['name']] = $news_list_data; + $match = 'true'; + } + } + }else{ + //do nothing, there is no match + } + } + //if this newsletter id never matched a user subscription.. + //..then add to available(unsubscribed) NewsLetters if list is not of type exempt + if(($match == false) && ($news_list['list_type'] != 'exempt')){ + $unsubs_arr[$news_list['name']] = $news_list_data; + } + + } + + $return_array['unsubscribed'] = $unsubs_arr; + $return_array['subscribed'] = $subs_arr; + return $return_array; +} + + + +/* + * This function will take an array of strings that have been created by the "get_subscription_lists()" method + * and parses it into an array. The returned array has it's key's labeled in a specific fashion. + * + * Each string produces a campaign and a prospect id. The keys are appended with a number specifying the order + * it was process in. So an input array containing 3 strings will have the following key values: + * "prospect_list0", "campaign0" + * "prospect_list1", "campaign1" + * "prospect_list2", "campaign2" + * + * */ +function process_subscriptions($subscription_string_to_parse) { + $subs_change = array(); + + //parse through and build list of id's'. We are retrieving the campaign_id and + //the prospect_list id from the selected subscriptions + $i = 0; + foreach($subscription_string_to_parse as $subs_changes){ + $subs_changes = trim($subs_changes); + if(!empty($subs_changes)){ + $ids_arr = explode("@", $subs_changes); + $subs_change[$ids_arr[0].$i] = $ids_arr[1]; + $subs_change[$ids_arr[2].$i] = $ids_arr[3]; + $i = $i+1; + } + } + return $subs_change; +} + + + /*This function is used by the Manage Subscriptions page in order to add the user + * to the default prospect lists of the passed in campaign + * Takes in campaign and prospect list id's we are subscribing to. + * It also takes in a bean of the user (lead,target,prospect) we are subscribing + * */ + function subscribe($campaign, $prospect_list, $focus, $default_list = false) { + $relationship = strtolower($focus->getObjectName()).'s'; + + //--grab all the lists for the passed in campaign id + $pl_qry ="select id, list_type from prospect_lists where id in (select prospect_list_id from prospect_list_campaigns "; + $pl_qry .= "where campaign_id = '$campaign') and deleted = 0 "; + $GLOBALS['log']->debug("In Campaigns Util: subscribe function, about to run query: ".$pl_qry ); + $pl_qry_result = $focus->db->query($pl_qry); + + //build the array of all prospect_lists + $pl_arr = array(); + while ($row = $focus->db->fetchByAssoc($pl_qry_result)){$pl_arr[] = $row;} + + //--grab all the prospect_lists this user belongs to + $curr_pl_qry ="select prospect_list_id, related_id from prospect_lists_prospects "; + $curr_pl_qry .="where related_id = '$focus->id' and deleted = 0 "; + $GLOBALS['log']->debug("In Campaigns Util: subscribe function, about to run query: ".$curr_pl_qry ); + $curr_pl_qry_result = $focus->db->query($curr_pl_qry); + + //build the array of all prospect lists that this current user belongs to + $curr_pl_arr = array(); + while ($row = $focus->db->fetchByAssoc($curr_pl_qry_result)){$curr_pl_arr[] = $row;} + + //search through prospect lists for this campaign and identifiy the "unsubscription list" + $exempt_id = ''; + foreach($pl_arr as $subscription_list){ + if(strpos($subscription_list['list_type'], 'exempt')!== false){ + $exempt_id = $subscription_list['id']; + } + + if($subscription_list['list_type'] == 'default' && $default_list) { + $prospect_list = $subscription_list['id']; + } + } + + //now that we have exempt (unsubscription) list id, compare against user list id's + if(!empty($exempt_id)){ + $exempt_array['exempt_id'] = $exempt_id; + + foreach($curr_pl_arr as $curr_subscription_list){ + if($curr_subscription_list['prospect_list_id'] == $exempt_id){ + //--if we are in here then user is subscribing to a list in which they are exempt. + // we need to remove the user from this unsubscription list. + //Begin by retrieving unsubscription prospect list + $exempt_subscription_list = new ProspectList(); + + + $exempt_result = $exempt_subscription_list->retrieve($exempt_id); + if($exempt_result == null) + {//error happened while retrieving this list + return; + } + //load realationships and delete user from unsubscription list + $exempt_subscription_list->load_relationship($relationship); + $exempt_subscription_list->$relationship->delete($exempt_id,$focus->id); + + } + } + } + + //Now we need to check if user is already in subscription list + $already_here = 'false'; + //for each list user is subscribed to, compare id's with current list id' + foreach($curr_pl_arr as $user_list){ + if(in_array($prospect_list, $user_list)){ + //if user already exists, then set flag to true + $already_here = 'true'; + } + } + if($already_here ==='true'){ + //do nothing, user is already subscribed + }else{ + //user is not subscribed already, so add to subscription list + $subscription_list = new ProspectList(); + $subs_result = $subscription_list->retrieve($prospect_list); + if($subs_result == null) + {//error happened while retrieving this list, iterate and continue + return; + } + //load subscription list and add this user + $GLOBALS['log']->debug("In Campaigns Util, loading relationship: ".$relationship); + $subscription_list->load_relationship($relationship); + $subscription_list->$relationship->add($focus->id); + } +} + + + /*This function is used by the Manage Subscriptions page in order to add the user + * to the exempt prospect lists of the passed in campaign + * Takes in campaign and focus parameters. + * */ + function unsubscribe($campaign, $focus) { + $relationship = strtolower($focus->getObjectName()).'s'; + //--grab all the list for this campaign id + $pl_qry ="select id, list_type from prospect_lists where id in (select prospect_list_id from prospect_list_campaigns "; + $pl_qry .= "where campaign_id = '$campaign') and deleted = 0 "; + $pl_qry_result = $focus->db->query($pl_qry); + //build the array with list information + $pl_arr = array(); + $GLOBALS['log']->debug("In Campaigns Util, about to run query: ".$pl_qry); + while ($row = $focus->db->fetchByAssoc($pl_qry_result)){$pl_arr[] = $row;} + + //retrieve lists that this user belongs to + $curr_pl_qry ="select prospect_list_id, related_id from prospect_lists_prospects "; + $curr_pl_qry .="where related_id = '$focus->id' and deleted = 0 "; + $GLOBALS['log']->debug("In Campaigns Util, unsubscribe function about to run query: ".$curr_pl_qry ); + $curr_pl_qry_result = $focus->db->query($curr_pl_qry); + + //build the array with current user list information + $curr_pl_arr = array(); + while ($row = $focus->db->fetchByAssoc($curr_pl_qry_result)){$curr_pl_arr[] = $row;} + //check to see if user is already there in prospect list + $already_here = 'false'; + $exempt_id = ''; + + foreach($curr_pl_arr as $user_list){ + foreach($pl_arr as $v){ + //if list is exempt list + if($v['list_type'] == 'exempt'){ + //save the exempt list id for later use + $exempt_id = $v['id']; + //check to see if user is already in this exempt list + if(in_array($v['id'], $user_list)){ + $already_here = 'true'; + } + + break 2; + } + } + } + + //unsubscribe subscripted newsletter + foreach($pl_arr as $subscription_list){ + //create a new instance of the prospect list + $exempt_list = new ProspectList(); + $exempt_list->retrieve($subscription_list['id']); + $exempt_list->load_relationship($relationship); + //if list type is default, then delete the relationship + //if list type is exempt, then add the relationship to unsubscription list + if($subscription_list['list_type'] == 'exempt') { + $exempt_list->$relationship->add($focus->id); + }elseif($subscription_list['list_type'] == 'default' || $subscription_list['list_type'] == 'test'){ + //if list type is default or test, then delete the relationship + //$exempt_list->$relationship->delete($subscription_list['id'],$focus->id); + } + + } + + if($already_here =='true'){ + //do nothing, user is already exempted + + }else{ + //user is not exempted yet , so add to unsubscription list + + + $exempt_result = $exempt_list->retrieve($exempt_id); + if($exempt_result == null) + {//error happened while retrieving this list + return; + } + $GLOBALS['log']->debug("In Campaigns Util, loading relationship: ".$relationship); + $exempt_list->load_relationship($relationship); + $exempt_list->$relationship->add($focus->id); + } + + } + + + /* + *This function will return a string to the newsletter wizard if campaign check + *does not return 100% healthy. + */ + function diagnose() + { + global $mod_strings; + global $current_user; + $msg = " "; + //Start with email components + //monitored mailbox section + $focus = new Administration(); + $focus->retrieveSettings(); //retrieve all admin settings. + + + //run query for mail boxes of type 'bounce' + $email_health = 0; + $email_components = 2; + $mbox_qry = "select * from inbound_email where deleted ='0' and mailbox_type = 'bounce'"; + $mbox_res = $focus->db->query($mbox_qry); + + $mbox = array(); + while ($mbox_row = $focus->db->fetchByAssoc($mbox_res)){$mbox[] = $mbox_row;} + //if the array is not empty, then set "good" message + if(isset($mbox) && count($mbox)>0){ + //everything is ok, do nothing + + }else{ + //if array is empty, then increment health counter + $email_health =$email_health +1; + $msg .= ""; + } + + + if (strstr($focus->settings['notify_fromaddress'], 'example.com')){ + //if "from_address" is the default, then set "bad" message and increment health counter + $email_health =$email_health +1; + $msg .= ""; + }else{ + //do nothing, address has been changed + } + //if health counter is above 1, then show admin link + if($email_health>0){ + if (is_admin($current_user)){ + $msg.=""; + }else{ + $msg.=""; + + } + + } + + + // proceed with scheduler components + + //create and run the scheduler queries + $sched_qry = "select job, name, status from schedulers where deleted = 0 and status = 'Active'"; + $sched_res = $focus->db->query($sched_qry); + $sched_health = 0; + $sched = array(); + $check_sched1 = 'function::runMassEmailCampaign'; + $check_sched2 = 'function::pollMonitoredInboxesForBouncedCampaignEmails'; + $sched_mes = ''; + $sched_mes_body = ''; + $scheds = array(); + + while ($sched_row = $focus->db->fetchByAssoc($sched_res)){$scheds[] = $sched_row;} + //iterate through and see which jobs were found + foreach ($scheds as $funct){ + if( ($funct['job']==$check_sched1) || ($funct['job']==$check_sched2)){ + if($funct['job']==$check_sched1){ + $check_sched1 ="found"; + }else{ + $check_sched2 ="found"; + } + + } + } + //determine if error messages need to be displayed for schedulers + if($check_sched2 != 'found'){ + $sched_health =$sched_health +1; + $msg.= ""; + } + if($check_sched1 != 'found'){ + $sched_health =$sched_health +1; + $msg.= ""; + } + //if health counter is above 1, then show admin link + if($sched_health>0){ + global $current_user; + if (is_admin($current_user)){ + $msg.=""; + }else{ + $msg.=""; + } + + } + + //determine whether message should be returned + if(($sched_health + $email_health)>0){ + $msg .= "
    ".$mod_strings['LNK_CAMPAIGN_DIGNOSTIC_LINK']."
    ". $mod_strings['LBL_MAILBOX_CHECK1_BAD']."
    ".$mod_strings['LBL_MAILBOX_CHECK2_BAD']."
    ".$mod_strings['LBL_NON_ADMIN_ERROR_MSG']."
    ".$mod_strings['LBL_SCHEDULER_CHECK1_BAD']."
    ".$mod_strings['LBL_SCHEDULER_CHECK2_BAD']."
    ".$mod_strings['LBL_SCHEDULER_LINK']."
    ".$mod_strings['LBL_NON_ADMIN_ERROR_MSG']."
    "; + }else{ + $msg = ''; + } + return $msg; + } + + +/** + * Handle campaign log entry creation for mail-merge activity. The function will be called by the soap component. + * + * @param String campaign_id Primary key of the campaign + * @param array targets List of keys for entries from prospect_lists_prosects table + */ + function campaign_log_mail_merge($campaign_id, $targets) { + + $campaign= new Campaign(); + $campaign->retrieve($campaign_id); + + if (empty($campaign->id)) { + $GLOBALS['log']->debug('set_campaign_merge: Invalid campaign id'. $campaign_id); + } else { + foreach ($targets as $target_list_id) { + $pl_query = "select * from prospect_lists_prospects where id='$target_list_id'"; + $result=$GLOBALS['db']->query($pl_query); + $row=$GLOBALS['db']->fetchByAssoc($result); + if (!empty($row)) { + write_mail_merge_log_entry($campaign_id,$row); + } + } + } + + } +/** + * Function creates a campaign_log entry for campaigns processesed using the mail-merge feature. If any entry + * exist the hit counter is updated. target_tracker_key is used to locate duplicate entries. + * @param string campaign_id Primary key of the campaign + * @param array $pl_row A row of data from prospect_lists_prospects table. + */ +function write_mail_merge_log_entry($campaign_id,$pl_row) { + + //Update the log entry if it exists. + $update="update campaign_log set hits=hits+1 where campaign_id='$campaign_id' and target_tracker_key='" . $pl_row['id'] . "'"; + $result=$GLOBALS['db']->query($update); + + //get affected row count... + $count=$GLOBALS['db']->getAffectedRowCount(); + if ($count==0) { + $data=array(); + + $data['id']="'" . create_guid() . "'"; + $data['campaign_id']="'" . $campaign_id . "'"; + $data['target_tracker_key']="'" . $pl_row['id'] . "'"; + $data['target_id']="'" . $pl_row['related_id'] . "'"; + $data['target_type']="'" . $pl_row['related_type'] . "'"; + $data['activity_type']="'targeted'"; + $data['activity_date']="'" . TimeDate::getInstance()->nowDb() . "'"; + $data['list_id']="'" . $pl_row['prospect_list_id'] . "'"; + $data['hits']=1; + + $insert_query="INSERT into campaign_log (" . implode(",",array_keys($data)) . ")"; + $insert_query.=" VALUES (" . implode(",",array_values($data)) . ")"; + $GLOBALS['db']->query($insert_query); + } +} + + function track_campaign_prospects($focus){ + $delete_query="delete from campaign_log where campaign_id='{$focus->id}' and activity_type='targeted'"; + $focus->db->query($delete_query); + + $query="SELECT prospect_lists.id prospect_list_id from prospect_lists "; + $query.=" INNER JOIN prospect_list_campaigns plc ON plc.prospect_list_id = prospect_lists.id"; + $query.=" WHERE plc.campaign_id='{$focus->id}'"; + $query.=" AND prospect_lists.deleted=0"; + $query.=" AND plc.deleted=0"; + $query.=" AND prospect_lists.list_type!='test' AND prospect_lists.list_type not like 'exempt%'"; + $result=$focus->db->query($query); + while (($row=$focus->db->fetchByAssoc($result))!=null ) { + $prospect_list_id=$row['prospect_list_id']; + + if ($focus->db->dbType=='oci8') { + } + else if ($focus->db->dbType=='mssql') { + $current_date= "'".TimeDate::getInstance()->nowDb()."'"; + $guid = "NEWID()"; + } + else { + $current_date= "'".TimeDate::getInstance()->nowDb()."'"; + $guid = "UUID()"; + } + + $insert_query= "INSERT INTO campaign_log (id,activity_date, campaign_id, target_tracker_key,list_id, target_id, target_type, activity_type"; + $insert_query.=')'; + $insert_query.= " SELECT $guid,$current_date,plc.campaign_id,$guid,plp.prospect_list_id, plp.related_id, plp.related_type,'targeted' "; + $insert_query.= "FROM prospect_lists_prospects plp "; + $insert_query.= "INNER JOIN prospect_list_campaigns plc ON plc.prospect_list_id = plp.prospect_list_id "; + $insert_query.= "WHERE plp.prospect_list_id = '{$prospect_list_id}' "; + $insert_query.= "AND plp.deleted=0 "; + $insert_query.= "AND plc.deleted=0 "; + $insert_query.= "AND plc.campaign_id='{$focus->id}'"; +/* + if ($focus->db->dbType=='oci8') { + } + */ + $focus->db->query($insert_query); + } + global $mod_strings; + //return success message + return $mod_strings['LBL_DEFAULT_LIST_ENTRIES_WERE_PROCESSED']; + } + + function create_campaign_log_entry($campaign_id, $focus, $rel_name, $rel_bean, $target_id = ''){ + global $timedate; + + $target_ids = array(); + //check if this is specified for one target/contact/prospect/lead (from contact/lead detail subpanel) + if(!empty($target_id)){ + $target_ids[] = $target_id; + }else{ + //this is specified for all, so load target/prospect relationships (mark as sent button) + $focus->load_relationship($rel_name); + $target_ids = $focus->$rel_name->get(); + + } + if(count($target_ids)>0){ + + + //retrieve the target beans and create campaign log entry + foreach($target_ids as $id){ + //perform duplicate check + $dup_query = "select id from campaign_log where campaign_id = '$campaign_id' and target_id = '$id'"; + $dup_result = $focus->db->query($dup_query); + $row = $focus->db->fetchByAssoc($dup_result); + + //process if this is not a duplicate campaign log entry + if(empty($row)){ + //create campaign tracker id and retrieve related bio bean + $tracker_id = create_guid(); + $rel_bean->retrieve($id); + + //create new campaign log record. + $campaign_log = new CampaignLog(); + $campaign_log->campaign_id = $campaign_id; + $campaign_log->target_tracker_key = $tracker_id; + $campaign_log->target_id = $rel_bean->id; + $campaign_log->target_type = $rel_bean->module_dir; + $campaign_log->activity_type = 'targeted'; + $campaign_log->activity_date=$timedate->now(); + //save the campaign log entry + $campaign_log->save(); + } + } + } + + } + + /* + * This function will return an array that has been formatted to work as a Quick Search Object for prospect lists + */ + function getProspectListQSObjects($source = '', $return_field_name='name', $return_field_id='id' ) { + global $app_strings; + //if source has not been specified, then search across all prospect lists + if(empty($source)){ + $qsProspectList = array('method' => 'query', + 'modules'=> array('ProspectLists'), + 'group' => 'and', + 'field_list' => array('name', 'id'), + 'populate_list' => array('prospect_list_name', 'prospect_list_id'), + 'conditions' => array( array('name'=>'name','op'=>'like_custom','end'=>'%','value'=>'') ), + 'order' => 'name', + 'limit' => '30', + 'no_match_text' => $app_strings['ERR_SQS_NO_MATCH']); + }else{ + //source has been specified use it to tell quicksearch.js which html input to use to get filter value + $qsProspectList = array('method' => 'query', + 'modules'=> array('ProspectLists'), + 'group' => 'and', + 'field_list' => array('name', 'id'), + 'populate_list' => array($return_field_name, $return_field_id), + 'conditions' => array( + array('name'=>'name','op'=>'like_custom','end'=>'%','value'=>''), + //this condition has the source parameter defined, meaning the query will take the value specified below + array('name'=>'list_type', 'op'=>'like_custom', 'end'=>'%','value'=>'', 'source' => $source) + ), + 'order' => 'name', + 'limit' => '30', + 'no_match_text' => $app_strings['ERR_SQS_NO_MATCH']); + + } + + return $qsProspectList; + } + + +?> diff --git a/modules/Campaigns/vardefs.php b/modules/Campaigns/vardefs.php new file mode 100644 index 00000000..bb414709 --- /dev/null +++ b/modules/Campaigns/vardefs.php @@ -0,0 +1,323 @@ +true, + 'comment' => 'Campaigns are a series of operations undertaken to accomplish a purpose, usually acquiring leads', + 'table' => 'campaigns', + 'unified_search' => true, + 'fields' => array ( + 'tracker_key' => array ( + 'name' => 'tracker_key', + 'vname' => 'LBL_TRACKER_KEY', + 'type' => 'int', + 'required' => true, + 'studio' => array('editview' => false), + 'len' => '11', + 'auto_increment' => true, + 'comment' => 'The internal ID of the tracker used in a campaign; no longer used as of 4.2 (see campaign_trkrs)' + ), + 'tracker_count' => array ( + 'name' => 'tracker_count', + 'vname' => 'LBL_TRACKER_COUNT', + 'type' => 'int', + 'len' => '11', + 'default' => '0', + 'comment' => 'The number of accesses made to the tracker URL; no longer used as of 4.2 (see campaign_trkrs)' + ), + 'name' => array ( + 'name' => 'name', + 'vname' => 'LBL_CAMPAIGN_NAME', + 'dbType' => 'varchar', + 'type' => 'name', + 'len' => '50', + 'comment' => 'The name of the campaign', + 'importable' => 'required', + 'required' => true, + 'unified_search' => true, + ), + 'refer_url' => array ( + 'name' => 'refer_url', + 'vname' => 'LBL_REFER_URL', + 'type' => 'varchar', + 'len' => '255', + 'default' => 'http://', + 'comment' => 'The URL referenced in the tracker URL; no longer used as of 4.2 (see campaign_trkrs)' + ), + 'description'=>array('name'=>'description','type'=>'none', 'comment'=>'inhertied but not used', 'source'=>'non-db'), + 'tracker_text' => array ( + 'name' => 'tracker_text', + 'vname' => 'LBL_TRACKER_TEXT', + 'type' => 'varchar', + 'len' => '255', + 'comment' => 'The text that appears in the tracker URL; no longer used as of 4.2 (see campaign_trkrs)' + ), + + 'start_date' => array ( + 'name' => 'start_date', + 'vname' => 'LBL_CAMPAIGN_START_DATE', + 'type' => 'date', + 'audited'=>true, + 'comment' => 'Starting date of the campaign', + 'validation' => array ('type' => 'isbefore', 'compareto' => 'end_date'), + 'enable_range_search' => true, + 'options' => 'date_range_search_dom', + ), + 'end_date' => array ( + 'name' => 'end_date', + 'vname' => 'LBL_CAMPAIGN_END_DATE', + 'type' => 'date', + 'audited'=>true, + 'comment' => 'Ending date of the campaign', + 'importable' => 'required', + 'required' => true, + 'enable_range_search' => true, + 'options' => 'date_range_search_dom', + ), + 'status' => array ( + 'name' => 'status', + 'vname' => 'LBL_CAMPAIGN_STATUS', + 'type' => 'enum', + 'options' => 'campaign_status_dom', + 'len' => 100, + 'audited'=>true, + 'comment' => 'Status of the campaign', + 'importable' => 'required', + 'required' => true, + ), + 'impressions' => array ( + 'name' => 'impressions', + 'vname' => 'LBL_CAMPAIGN_IMPRESSIONS', + 'type' => 'int', + 'default'=>0, + 'reportable'=>true, + 'comment' => 'Expected Click throughs manually entered by Campaign Manager' + ), + 'currency_id' => + array ( + 'name' => 'currency_id', + 'vname' => 'LBL_CURRENCY', + 'type' => 'id', + 'group'=>'currency_id', + 'function'=>array('name'=>'getCurrencyDropDown', 'returns'=>'html'), + 'required'=>false, + 'do_report'=>false, + 'reportable'=>false, + 'comment' => 'Currency in use for the campaign' + ), + 'budget' => array ( + 'name' => 'budget', + 'vname' => 'LBL_CAMPAIGN_BUDGET', + 'type' => 'currency', + 'dbType' => 'double', + 'comment' => 'Budgeted amount for the campaign' + ), + 'expected_cost' => array ( + 'name' => 'expected_cost', + 'vname' => 'LBL_CAMPAIGN_EXPECTED_COST', + 'type' => 'currency', + 'dbType' => 'double', + 'comment' => 'Expected cost of the campaign' + ), + 'actual_cost' => array ( + 'name' => 'actual_cost', + 'vname' => 'LBL_CAMPAIGN_ACTUAL_COST', + 'type' => 'currency', + 'dbType' => 'double', + 'comment' => 'Actual cost of the campaign' + ), + 'expected_revenue' => array ( + 'name' => 'expected_revenue', + 'vname' => 'LBL_CAMPAIGN_EXPECTED_REVENUE', + 'type' => 'currency', + 'dbType' => 'double', + 'comment' => 'Expected revenue stemming from the campaign' + ), + 'campaign_type' => array ( + 'name' => 'campaign_type', + 'vname' => 'LBL_CAMPAIGN_TYPE', + 'type' => 'enum', + 'options' => 'campaign_type_dom', + 'len' => 100, + 'audited'=>true, + 'comment' => 'The type of campaign', + 'importable' => 'required', + 'required' => true, + ), + 'objective' => array ( + 'name' => 'objective', + 'vname' => 'LBL_CAMPAIGN_OBJECTIVE', + 'type' => 'text', + 'comment' => 'The objective of the campaign' + ), + 'content' => array ( + 'name' => 'content', + 'vname' => 'LBL_CAMPAIGN_CONTENT', + 'type' => 'text', + 'comment' => 'The campaign description' + ), + 'prospectlists'=> array ( + 'name' => 'prospectlists', + 'type' => 'link', + 'relationship' => 'prospect_list_campaigns', + 'source'=>'non-db', + ), + 'emailmarketing'=> array ( + 'name' => 'emailmarketing', + 'type' => 'link', + 'relationship' => 'campaign_email_marketing', + 'source'=>'non-db', + ), + 'queueitems'=> array ( + 'name' => 'queueitems', + 'type' => 'link', + 'relationship' => 'campaign_emailman', + 'source'=>'non-db', + ), + 'log_entries'=> array ( + 'name' => 'log_entries', + 'type' => 'link', + 'relationship' => 'campaign_campaignlog', + 'source'=>'non-db', + 'vname' => 'LBL_LOG_ENTRIES', + ), + 'tracked_urls' => array ( + 'name' => 'tracked_urls', + 'type' => 'link', + 'relationship' => 'campaign_campaigntrakers', + 'source'=>'non-db', + 'vname'=>'LBL_TRACKED_URLS', + ), + 'frequency' => array ( + 'name' => 'frequency', + 'vname' => 'LBL_CAMPAIGN_FREQUENCY', + 'type' => 'enum', + //'options' => 'campaign_status_dom', + 'len' => 100, + 'comment' => 'Frequency of the campaign', + 'options' => 'newsletter_frequency_dom', + 'len' => 100, + ), + 'leads'=> array ( + 'name' => 'leads', + 'type' => 'link', + 'relationship' => 'campaign_leads', + 'source'=>'non-db', + 'vname' => 'LBL_LEADS', + ), + + 'opportunities'=> array ( + 'name' => 'opportunities', + 'type' => 'link', + 'relationship' => 'campaign_opportunities', + 'source'=>'non-db', + 'vname' => 'LBL_OPPORTUNITIES', + ), + 'contacts'=> array ( + 'name' => 'contacts', + 'type' => 'link', + 'relationship' => 'campaign_contacts', + 'source'=>'non-db', + 'vname' => 'LBL_CONTACTS', + ), + 'accounts'=> array ( + 'name' => 'accounts', + 'type' => 'link', + 'relationship' => 'campaign_accounts', + 'source'=>'non-db', + 'vname' => 'LBL_ACCOUNTS', + ), + + + ), + 'indices' => array ( + array ( + 'name' => 'camp_auto_tracker_key' , + 'type'=>'index' , + 'fields'=>array('tracker_key') + ), + array ( + 'name' =>'idx_campaign_name', + 'type' =>'index', + 'fields'=>array('name') + ), + ), + + 'relationships' => array ( + 'campaign_accounts' => array('lhs_module'=> 'Campaigns', 'lhs_table'=> 'campaigns', 'lhs_key' => 'id', + 'rhs_module'=> 'Accounts', 'rhs_table'=> 'accounts', 'rhs_key' => 'campaign_id', + 'relationship_type'=>'one-to-many'), + + 'campaign_contacts' => array('lhs_module'=> 'Campaigns', 'lhs_table'=> 'campaigns', 'lhs_key' => 'id', + 'rhs_module'=> 'Contacts', 'rhs_table'=> 'contacts', 'rhs_key' => 'campaign_id', + 'relationship_type'=>'one-to-many'), + + 'campaign_leads' => array('lhs_module'=> 'Campaigns', 'lhs_table'=> 'campaigns', 'lhs_key' => 'id', + 'rhs_module'=> 'Leads', 'rhs_table'=> 'leads', 'rhs_key' => 'campaign_id', + 'relationship_type'=>'one-to-many'), + + 'campaign_prospects' => array('lhs_module'=> 'Campaigns', 'lhs_table'=> 'campaigns', 'lhs_key' => 'id', + 'rhs_module'=> 'Prospects', 'rhs_table'=> 'prospects', 'rhs_key' => 'campaign_id', + 'relationship_type'=>'one-to-many'), + + 'campaign_opportunities' => array('lhs_module'=> 'Campaigns', 'lhs_table'=> 'campaigns', 'lhs_key' => 'id', + 'rhs_module'=> 'Opportunities', 'rhs_table'=> 'opportunities', 'rhs_key' => 'campaign_id', + 'relationship_type'=>'one-to-many'), + + 'campaign_email_marketing' => array('lhs_module'=> 'Campaigns', 'lhs_table'=> 'campaigns', 'lhs_key' => 'id', + 'rhs_module'=> 'EmailMarketing', 'rhs_table'=> 'email_marketing', 'rhs_key' => 'campaign_id', + 'relationship_type'=>'one-to-many'), + + 'campaign_emailman' => array('lhs_module'=> 'Campaigns', 'lhs_table'=> 'campaigns', 'lhs_key' => 'id', + 'rhs_module'=> 'EmailMan', 'rhs_table'=> 'emailman', 'rhs_key' => 'campaign_id', + 'relationship_type'=>'one-to-many'), + + 'campaign_campaignlog' => array('lhs_module'=> 'Campaigns', 'lhs_table'=> 'campaigns', 'lhs_key' => 'id', + 'rhs_module'=> 'CampaignLog', 'rhs_table'=> 'campaign_log', 'rhs_key' => 'campaign_id', + 'relationship_type'=>'one-to-many'), + + 'campaign_assigned_user' => array('lhs_module'=> 'Users', 'lhs_table'=> 'users', 'lhs_key' => 'id', + 'rhs_module'=> 'Campaigns', 'rhs_table'=> 'campaigns', 'rhs_key' => 'assigned_user_id', + 'relationship_type'=>'one-to-many'), + + 'campaign_modified_user' => array('lhs_module'=> 'Users', 'lhs_table'=> 'users', 'lhs_key' => 'id', + 'rhs_module'=> 'Campaigns', 'rhs_table'=> 'campaigns', 'rhs_key' => 'modified_user_id', + 'relationship_type'=>'one-to-many'), + ) +); +VardefManager::createVardef('Campaigns','Campaign', array('default', 'assignable', +)); +?> \ No newline at end of file diff --git a/modules/Campaigns/views/view.classic.php b/modules/Campaigns/views/view.classic.php new file mode 100644 index 00000000..b756f110 --- /dev/null +++ b/modules/Campaigns/views/view.classic.php @@ -0,0 +1,109 @@ +type = $this->action; + } + + /** + * @see SugarView::display() + */ + public function display() + { + // Call SugarController::getActionFilename to handle case sensitive file names + $file = SugarController::getActionFilename($this->action); + if(file_exists('custom/modules/' . $this->module . '/'. $file . '.php')){ + $this->includeClassicFile('custom/modules/'. $this->module . '/'. $file . '.php'); + return true; + }elseif(file_exists('modules/' . $this->module . '/'. $file . '.php')){ + $this->includeClassicFile('modules/'. $this->module . '/'. $file . '.php'); + return true; + } + return false; + } + + /** + * @see SugarView::_getModuleTitleParams() + */ + protected function _getModuleTitleParams($browserTitle = false) + { + $params = array(); + $params[] = $this->_getModuleTitleListParam($browserTitle); + if (isset($this->action)){ + switch($_REQUEST['action']){ + case 'WizardHome': + if(!empty($this->bean->id)) + { + $params[] = "".$this->bean->name.""; + } + $params[] = $GLOBALS['mod_strings']['LBL_CAMPAIGN_WIZARD']; + break; + case 'WebToLeadCreation': + $params[] = $GLOBALS['mod_strings']['LBL_LEAD_FORM_WIZARD']; + break; + case 'WizardNewsletter': + if(!empty($this->bean->id)) + { + $params[] = "".$GLOBALS['mod_strings']['LBL_NEWSLETTER_TITLE'].""; + } + $params[] = $GLOBALS['mod_strings']['LBL_CREATE_NEWSLETTER']; + break; + case 'CampaignDiagnostic': + $params[] = $GLOBALS['mod_strings']['LBL_CAMPAIGN_DIAGNOSTICS']; + break; + case 'WizardEmailSetup': + $params[] = $GLOBALS['mod_strings']['LBL_EMAIL_SETUP_WIZARD_TITLE']; + break; + case 'TrackDetailView': + if(!empty($this->bean->id)) + { + $params[] = "".$this->bean->name.""; + } + $params[] = $GLOBALS['mod_strings']['LBL_LIST_TO_ACTIVITY']; + break; + }//switch + }//fi + + return $params; + } +} \ No newline at end of file diff --git a/modules/Campaigns/views/view.detail.php b/modules/Campaigns/views/view.detail.php new file mode 100644 index 00000000..2cfed6ae --- /dev/null +++ b/modules/Campaigns/views/view.detail.php @@ -0,0 +1,138 @@ +options['show_subpanels'] = false; + + } + + + function preDisplay(){ + global $mod_strings; + if (isset($this->bean->campaign_type) && strtolower($this->bean->campaign_type) == 'newsletter'){ + $mod_strings['LBL_MODULE_NAME'] = $mod_strings['LBL_NEWSLETTERS']; + } + parent::preDisplay(); + + } + + function display() { + + if (isset($_REQUEST['mode']) && $_REQUEST['mode']=='set_target'){ + require_once('modules/Campaigns/utils.php'); + //call function to create campaign logs + $mess = track_campaign_prospects($this->bean); + + $confirm_msg = "var ajax_C_LOG_Status = new SUGAR.ajaxStatusClass(); + window.setTimeout(\"ajax_C_LOG_Status.showStatus('".$mess."')\",1000); + window.setTimeout('ajax_C_LOG_Status.hideStatus()', 1500); + window.setTimeout(\"ajax_C_LOG_Status.showStatus('".$mess."')\",2000); + window.setTimeout('ajax_C_LOG_Status.hideStatus()', 5000); "; + $this->ss->assign("MSG_SCRIPT",$confirm_msg); + + } + + if (($this->bean->campaign_type == 'Email') || ($this->bean->campaign_type == 'NewsLetter' )) { + $this->ss->assign("ADD_BUTTON_STATE", "submit"); + $this->ss->assign("TARGET_BUTTON_STATE", "hidden"); + } else { + $this->ss->assign("ADD_BUTTON_STATE", "hidden"); + $this->ss->assign("DISABLE_LINK", "display:none"); + $this->ss->assign("TARGET_BUTTON_STATE", "submit"); + } + + $currency = new Currency(); + if(isset($this->bean->currency_id) && !empty($this->bean->currency_id)) + { + $currency->retrieve($this->bean->currency_id); + if( $currency->deleted != 1){ + $this->ss->assign('CURRENCY', $currency->iso4217 .' '.$currency->symbol); + }else { + $this->ss->assign('CURRENCY', $currency->getDefaultISO4217() .' '.$currency->getDefaultCurrencySymbol()); + } + }else{ + $this->ss->assign('CURRENCY', $currency->getDefaultISO4217() .' '.$currency->getDefaultCurrencySymbol()); + } + + parent::display(); + + //We want to display subset of available, panels, so we will call subpanel + //object directly instead of using sugarview. + $GLOBALS['focus'] = $this->bean; + require_once('include/SubPanel/SubPanelTiles.php'); + $subpanel = new SubPanelTiles($this->bean, $this->module); + //get available list of subpanels + $alltabs=$subpanel->subpanel_definitions->get_available_tabs(); + if (!empty($alltabs)) { + //iterate through list, and filter out all but 3 subpanels + foreach ($alltabs as $key=>$name) { + if ($name != 'prospectlists' && $name!='emailmarketing' && $name != 'tracked_urls') { + //exclude subpanels that are not prospectlists, emailmarketing, or tracked urls + $subpanel->subpanel_definitions->exclude_tab($name); + } + } + //only show email marketing subpanel for email/newsletter campaigns + if ($this->bean->campaign_type != 'Email' && $this->bean->campaign_type != 'NewsLetter' ) { + //exclude subpanels that are not prospectlists, emailmarketing, or tracked urls + $subpanel->subpanel_definitions->exclude_tab('emailmarketing'); + } + } + //show filtered subpanel list + echo $subpanel->display(); + + } +} +?> \ No newline at end of file diff --git a/modules/Campaigns/views/view.modulelistmenu.php b/modules/Campaigns/views/view.modulelistmenu.php new file mode 100644 index 00000000..6bd5c547 --- /dev/null +++ b/modules/Campaigns/views/view.modulelistmenu.php @@ -0,0 +1,55 @@ +get_recently_viewed($GLOBALS['current_user']->id, array('Campaigns','ProspectLists','Prospects')); + foreach ( $history as $key => $row ) { + $history[$key]['item_summary_short'] = getTrackerSubstring($row['item_summary']); + $history[$key]['image'] = SugarThemeRegistry::current() + ->getImage($row['module_name'],'border="0" align="absmiddle" alt="'.$row['item_summary'].'"'); + } + $this->ss->assign('LAST_VIEWED',$history); + + $this->ss->display('include/MVC/View/tpls/modulelistmenu.tpl'); + } +} +?> diff --git a/modules/Campaigns/views/view.newsletterlist.php b/modules/Campaigns/views/view.newsletterlist.php new file mode 100644 index 00000000..8ed35b84 --- /dev/null +++ b/modules/Campaigns/views/view.newsletterlist.php @@ -0,0 +1,75 @@ +searchForm->populateFromArray($this->storeQuery->query); + } + else { + $this->searchForm->populateFromRequest(); + } + $where_clauses = $this->searchForm->generateSearchWhere(true, $this->seed->module_dir); + $where_clauses[] = "campaigns.campaign_type in ('NewsLetter')"; + if (count($where_clauses) > 0 )$this->where = '('. implode(' ) AND ( ', $where_clauses) . ')'; + $GLOBALS['log']->info("List View Where Clause: $this->where"); + + + echo $this->searchForm->display($this->headers); + } + + /** + * @see SugarView::preDisplay() + */ + public function preDisplay() + { + global $mod_strings; + $mod_strings['LBL_MODULE_TITLE'] = $mod_strings['LBL_NEWSLETTER_TITLE']; + $mod_strings['LBL_LIST_FORM_TITLE'] = $mod_strings['LBL_NEWSLETTER_LIST_FORM_TITLE']; + parent::preDisplay(); + + } +} \ No newline at end of file diff --git a/modules/Campaigns/wizard.js b/modules/Campaigns/wizard.js new file mode 100644 index 00000000..76f3e512 --- /dev/null +++ b/modules/Campaigns/wizard.js @@ -0,0 +1,56 @@ +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ +function hide(divname){var elem1=document.getElementById(divname);elem1.style.display='none';} +function show(div){var elem1=document.getElementById(div);elem1.style.display='';} +function showdiv(div){hideall();show(div);} +function hideall(){var last_val=document.getElementById('wiz_total_steps');var last=parseInt(last_val.value);for(i=1;i<=last;i++){hide('step'+i);}} +function showfirst(wiz_mode){showdiv('step1');var current_step=document.getElementById('wiz_current_step');current_step.value="1";var save_button=document.getElementById('wiz_submit_button');var next_button=document.getElementById('wiz_next_button');var save_button_div=document.getElementById('save_button_div');var next_button_div=document.getElementById('next_button_div');var back_button_div=document.getElementById('back_button_div');save_button.disabled=true;back_button_div.style.display='none';save_button_div.style.display='none';next_button.focus();if(wiz_mode=='marketing'){back_button_div.style.display='';} +hilite(current_step.value);} +function navigate(direction){var current_step=document.getElementById('wiz_current_step');var currentValue=parseInt(current_step.value);if(validate_wiz(current_step.value,direction)){if(direction=='back'){current_step.value=currentValue-1;} +if(direction=='next'){current_step.value=currentValue+1;} +if(direction=='direct'){} +showdiv("step"+current_step.value);hilite(current_step.value);var total=document.getElementById('wiz_total_steps').value;var save_button=document.getElementById('wiz_submit_button');var back_button_div=document.getElementById('back_button_div');var save_button_div=document.getElementById('save_button_div');var next_button_div=document.getElementById('next_button_div');if(current_step.value==total){save_button.disabled=false;back_button_div.style.display='';save_button_div.style.display='';next_button_div.style.display='none';}else{if(current_step.value<2){back_button_div.style.display='none';}else{back_button_div.style.display='';} +var next_button=document.getElementById('wiz_next_button');next_button_div.style.display='';save_button_div.style.display='none';next_button.focus();}}else{}} +var already_linked='';function hilite(hilite){var last=parseInt(document.getElementById('wiz_total_steps').value);for(i=1;i<=last;i++){var nav_step=document.getElementById('nav_step'+i);nav_step.className='';} +var nav_step=document.getElementById('nav_step'+hilite);nav_step.className='';if(already_linked.indexOf(hilite)<0){nav_step.innerHTML=""+nav_step.innerHTML+"";already_linked+=',hilite';}} +function link_navs(beg,end){if(beg==''){beg=1;} +if(end==''){var last=document.getElementById('wiz_total_steps').value;end=last;} +beg=parseInt(beg);end=parseInt(end);for(i=beg;i<=end;i++){var nav_step=document.getElementById('nav_step'+i);nav_step.innerHTML=""+nav_step.innerHTML+"";}} +function direct(stepnumber){var current_step=document.getElementById('wiz_current_step');var currentValue=parseInt(current_step.value);if(validate_wiz(current_step.value,'direct')){current_step.value=stepnumber;navigate('direct');}else{}} +function validate_wiz(step,direction){var total=document.getElementById('wiz_total_steps').value;var wiz_message=document.getElementById('wiz_message');if(direction=='back'){if(step=='1'){var msg=SUGAR.language.get('mod_strings','LBL_WIZARD_FIRST_STEP_MESSAGE');wiz_message.innerHTML=""+msg+"";return false;}else{wiz_message.innerHTML='';}} +if(direction=='next'){if(step==total){var msg=SUGAR.language.get('mod_strings','LBL_WIZARD_LAST_STEP_MESSAGE');wiz_message.innerHTML=""+msg+"";return false;}else{wiz_message.innerHTML='';}} +if(direction=='direct'){} +if((direction!='direct')&&(window.validate_wiz_form)&&(!validate_wiz_form('step'+step))){return false;} +return true;} \ No newline at end of file diff --git a/modules/Cases/Case.php b/modules/Cases/Case.php new file mode 100644 index 00000000..2bbadd5a --- /dev/null +++ b/modules/Cases/Case.php @@ -0,0 +1,317 @@ +'accounts', 'bug_id' => 'bugs', + 'task_id'=>'tasks', 'note_id'=>'notes', + 'meeting_id'=>'meetings', 'call_id'=>'calls', 'email_id'=>'emails', + ); + + function aCase() { + parent::SugarBean(); + global $sugar_config; + if(!$sugar_config['require_accounts']){ + unset($this->required_fields['account_name']); + } + + $this->setupCustomFields('Cases'); + foreach ($this->field_defs as $field) { + $this->field_name_map[$field['name']] = $field; + } + } + + var $new_schema = true; + + + + + + function get_summary_text() + { + return "$this->name"; + } + + function listviewACLHelper(){ + $array_assign = parent::listviewACLHelper(); + $is_owner = false; + if(!empty($this->account_id)){ + + if(!empty($this->account_id_owner)){ + global $current_user; + $is_owner = $current_user->id == $this->account_id_owner; + } + } + if(!ACLController::moduleSupportsACL('Accounts') || ACLController::checkAccess('Accounts', 'view', $is_owner)){ + $array_assign['ACCOUNT'] = 'a'; + }else{ + $array_assign['ACCOUNT'] = 'span'; + } + + return $array_assign; + } + + function save_relationship_changes($is_update) + { + parent::save_relationship_changes($is_update); + + if (!empty($this->contact_id)) { + $this->set_case_contact_relationship($this->contact_id); + } + } + + function set_case_contact_relationship($contact_id) + { + global $app_list_strings; + $default = $app_list_strings['case_relationship_type_default_key']; + $this->load_relationship('contacts'); + $this->contacts->add($contact_id,array('contact_role'=>$default)); + } + + function fill_in_additional_list_fields() + { + parent::fill_in_additional_list_fields(); + /*// Fill in the assigned_user_name + //$this->assigned_user_name = get_assigned_user_name($this->assigned_user_id); + + $account_info = $this->getAccount($this->id); + $this->account_name = $account_info['account_name']; + $this->account_id = $account_info['account_id'];*/ + } + + function fill_in_additional_detail_fields() + { + parent::fill_in_additional_detail_fields(); + // Fill in the assigned_user_name + $this->assigned_user_name = get_assigned_user_name($this->assigned_user_id); + + $this->created_by_name = get_assigned_user_name($this->created_by); + $this->modified_by_name = get_assigned_user_name($this->modified_user_id); + + if(!empty($this->id)) { + $account_info = $this->getAccount($this->id); + if(!empty($account_info)) { + $this->account_name = $account_info['account_name']; + $this->account_id = $account_info['account_id']; + } + } + } + + + /** Returns a list of the associated contacts + * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.. + * All Rights Reserved.. + * Contributor(s): ______________________________________.. + */ + function get_contacts() + { + $this->load_relationship('contacts'); + $query_array=$this->contacts->getQuery(true); + + //update the select clause in the retruned query. + $query_array['select']="SELECT contacts.id, contacts.first_name, contacts.last_name, contacts.title, contacts.email1, contacts.phone_work, contacts_cases.contact_role as case_role, contacts_cases.id as case_rel_id "; + + $query=''; + foreach ($query_array as $qstring) { + $query.=' '.$qstring; + } + $temp = Array('id', 'first_name', 'last_name', 'title', 'email1', 'phone_work', 'case_role', 'case_rel_id'); + return $this->build_related_list2($query, new Contact(), $temp); + } + + function get_list_view_data(){ + global $current_language; + $app_list_strings = return_app_list_strings_language($current_language); + + $temp_array = $this->get_list_view_array(); + $temp_array['NAME'] = (($this->name == "") ? "blank" : $this->name); + $temp_array['PRIORITY'] = empty($this->priority)? "" : $app_list_strings['case_priority_dom'][$this->priority]; + $temp_array['STATUS'] = empty($this->status)? "" : $app_list_strings['case_status_dom'][$this->status]; + $temp_array['ENCODED_NAME'] = $this->name; + $temp_array['CASE_NUMBER'] = $this->case_number; + $temp_array['SET_COMPLETE'] = "".SugarThemeRegistry::current()->getImage("close_inline","title=".translate('LBL_LIST_CLOSE','Cases')." border='0'").""; + //$temp_array['ACCOUNT_NAME'] = $this->account_name; //overwrites the account_name value returned from the cases table. + return $temp_array; + } + + /** + builds a generic search based on the query string using or + do not include any $this-> because this is called on without having the class instantiated + */ + function build_generic_where_clause ($the_query_string) { + $where_clauses = Array(); + $the_query_string = $this->db->quote($the_query_string); + array_push($where_clauses, "cases.name like '$the_query_string%'"); + array_push($where_clauses, "accounts.name like '$the_query_string%'"); + + if (is_numeric($the_query_string)) array_push($where_clauses, "cases.case_number like '$the_query_string%'"); + + $the_where = ""; + + foreach($where_clauses as $clause) + { + if($the_where != "") $the_where .= " or "; + $the_where .= $clause; + } + + if($the_where != ""){ + $the_where = "(".$the_where.")"; + } + + return $the_where; + } + + function set_notification_body($xtpl, $case) + { + global $app_list_strings; + + $xtpl->assign("CASE_SUBJECT", $case->name); + $xtpl->assign("CASE_PRIORITY", (isset($case->priority) ? $app_list_strings['case_priority_dom'][$case->priority]:"")); + $xtpl->assign("CASE_STATUS", (isset($case->status) ? $app_list_strings['case_status_dom'][$case->status]:"")); + $xtpl->assign("CASE_DESCRIPTION", $case->description); + + return $xtpl; + } + + function bean_implements($interface){ + switch($interface){ + case 'ACL':return true; + } + return false; + } + + function save($check_notify = FALSE){ + return parent::save($check_notify); + } + + /** + * retrieves the Subject line macro for InboundEmail parsing + * @return string + */ + function getEmailSubjectMacro() { + global $sugar_config; + return (isset($sugar_config['inbound_email_case_subject_macro']) && !empty($sugar_config['inbound_email_case_subject_macro'])) ? + $sugar_config['inbound_email_case_subject_macro'] : $this->emailSubjectMacro; + } + + function getAccount($case_id){ + if(empty($case_id)) return array(); + $ret_array = array(); + $query = "SELECT acc.id, acc.name from accounts acc, cases where acc.id = cases.account_id and cases.id = '" . $case_id . "' and cases.deleted=0 and acc.deleted=0"; + $result = $this->db->query($query,true," Error filling in additional detail fields: "); + + // Get the id and the name. + $row = $this->db->fetchByAssoc($result); + + if($row != null){ + $ret_array['account_name'] = stripslashes($row['name']); + $ret_array['account_id'] = $row['id']; + } + else{ + $ret_array['account_name'] = ''; + $ret_array['account_id'] = ''; + } + return $ret_array; + } +} +?> diff --git a/modules/Cases/CasesQuickCreate.php b/modules/Cases/CasesQuickCreate.php new file mode 100644 index 00000000..fd4738bb --- /dev/null +++ b/modules/Cases/CasesQuickCreate.php @@ -0,0 +1,89 @@ +ss->assign("PRIORITY_OPTIONS", get_select_options_with_id($app_list_strings['case_priority_dom'], $app_list_strings['case_priority_default_key'])); + + if($this->viaAJAX) { // override for ajax call + $this->ss->assign('saveOnclick', "onclick='if(check_form(\"casesQuickCreate\")) return SUGAR.subpanelUtils.inlineSave(this.form.id, \"cases\"); else return false;'"); + $this->ss->assign('cancelOnclick', "onclick='return SUGAR.subpanelUtils.cancelCreate(\"subpanel_cases\")';"); + } + + $this->ss->assign('viaAJAX', $this->viaAJAX); + + $this->javascript = new javascript(); + $this->javascript->setFormName('casesQuickCreate'); + + $focus = new aCase(); + $this->javascript->setSugarBean($focus); + $this->javascript->addAllFields(''); + + $this->ss->assign("STATUS_OPTIONS", get_select_options_with_id($app_list_strings['case_status_dom'], $focus->status)); + $this->ss->assign('additionalScripts', $this->javascript->getScript(false)); + + $json = getJSONobj(); + + $popup_request_data = array( + 'call_back_function' => 'set_return', + 'form_name' => 'casesQuickCreate', + 'field_to_name_array' => array( + 'id' => 'account_id', + 'name' => 'account_name', + ), + ); + + $encoded_popup_request_data = $json->encode($popup_request_data); + $this->ss->assign('encoded_popup_request_data', $encoded_popup_request_data); + + + } +} +?> \ No newline at end of file diff --git a/modules/Cases/Dashlets/MyCasesDashlet/MyCasesDashlet.data.php b/modules/Cases/Dashlets/MyCasesDashlet/MyCasesDashlet.data.php new file mode 100644 index 00000000..4bc4d953 --- /dev/null +++ b/modules/Cases/Dashlets/MyCasesDashlet/MyCasesDashlet.data.php @@ -0,0 +1,84 @@ + array('default' => ''), + 'priority' => array('default' => ''), + 'status' => array('default' => array('Assigned', 'New', 'Pending Input')), + + 'name' => array('default' => ''), + 'type' => array('default' => ''), + //'date_modified' => array('default' => ''), + 'assigned_user_id' => array('type' => 'assigned_user_name', + 'label' => 'LBL_ASSIGNED_TO', + 'default' => $current_user->name)); +$dashletData['MyCasesDashlet']['columns'] = array('case_number' => array('width' => '6', + 'label' => 'LBL_NUMBER', + 'default' => true), + 'name' => array('width' => '40', + 'label' => 'LBL_LIST_SUBJECT', + 'link' => true, + 'default' => true), + 'account_name' => array('width' => '29', + 'link' => true, + 'module' => 'Accounts', + 'id' => 'ACCOUNT_ID', + 'ACLTag' => 'ACCOUNT', + 'label' => 'LBL_ACCOUNT_NAME', + 'related_fields' => array('account_id')), + 'priority' => array('width' => '15', + 'label' => 'LBL_PRIORITY', + 'default' => true), + 'status' => array('width' => '8', + 'label' => 'LBL_STATUS', + 'default' => true), + 'resolution' => array('width' => '8', + 'label' => 'LBL_RESOLUTION'), + 'date_entered' => array('width' => '15', + 'label' => 'LBL_DATE_ENTERED'), + 'date_modified' => array('width' => '15', + 'label' => 'LBL_DATE_MODIFIED'), + 'created_by' => array('width' => '8', + 'label' => 'LBL_CREATED'), + 'assigned_user_name' => array('width' => '8', + 'label' => 'LBL_LIST_ASSIGNED_USER'), + ); +?> diff --git a/modules/Cases/Dashlets/MyCasesDashlet/MyCasesDashlet.meta.php b/modules/Cases/Dashlets/MyCasesDashlet/MyCasesDashlet.meta.php new file mode 100644 index 00000000..b97f4bb3 --- /dev/null +++ b/modules/Cases/Dashlets/MyCasesDashlet/MyCasesDashlet.meta.php @@ -0,0 +1,47 @@ + 'Cases', + 'title' => translate('LBL_LIST_MY_CASES', 'Cases'), + 'description' => 'A customizable view into Cases', + 'category' => 'Module Views'); +?> diff --git a/modules/Cases/Dashlets/MyCasesDashlet/MyCasesDashlet.php b/modules/Cases/Dashlets/MyCasesDashlet/MyCasesDashlet.php new file mode 100644 index 00000000..08c9d915 --- /dev/null +++ b/modules/Cases/Dashlets/MyCasesDashlet/MyCasesDashlet.php @@ -0,0 +1,58 @@ +title = translate('LBL_LIST_MY_CASES', 'Cases'); + $this->searchFields = $dashletData['MyCasesDashlet']['searchFields']; + $this->columns = $dashletData['MyCasesDashlet']['columns']; + $this->seedBean = new aCase(); + } +} + +?> diff --git a/modules/Cases/Menu.php b/modules/Cases/Menu.php new file mode 100644 index 00000000..5d8fcee0 --- /dev/null +++ b/modules/Cases/Menu.php @@ -0,0 +1,54 @@ + \ No newline at end of file diff --git a/modules/Cases/SugarFeeds/CaseFeed.php b/modules/Cases/SugarFeeds/CaseFeed.php new file mode 100644 index 00000000..713cad2f --- /dev/null +++ b/modules/Cases/SugarFeeds/CaseFeed.php @@ -0,0 +1,59 @@ +fetched_row)){ + $text = '{SugarFeed.CREATED_CASE} [' . $bean->module_dir . ':' . $bean->id . ':' . $bean->name.'] {SugarFeed.FOR} [Accounts:' . $bean->account_id . ':' . $bean->account_name . ']: '. $bean->description; + }else{ + if(!empty($bean->fetched_row['status'] ) && $bean->fetched_row['status'] != $bean->status && $bean->status == 'Closed'){ + $text = '{SugarFeed.CLOSED_CASE} [' . $bean->module_dir . ':' . $bean->id . ':' . $bean->name. '] {SugarFeed.FOR} [Accounts:' . $bean->account_id . ':' . $bean->account_name . ']'; + } + } + + if(!empty($text)){ + SugarFeed::pushFeed2($text, $bean); + } + + } +} +?> diff --git a/modules/Cases/field_arrays.php b/modules/Cases/field_arrays.php new file mode 100644 index 00000000..3754312f --- /dev/null +++ b/modules/Cases/field_arrays.php @@ -0,0 +1,64 @@ + Array("id" + , "name" + , "case_number" + , "account_name" + , "account_id" + , "date_entered" + , "date_modified" + , "modified_user_id" + , "assigned_user_id" + , "created_by" + , "status" + , "priority" + , "description" + , "resolution" + ), + 'list_fields' => Array('id', 'priority', 'status', 'name', 'account_name', 'case_number', 'account_id', 'assigned_user_name', 'assigned_user_id' + ), + 'required_fields' => array('name'=>1, 'account_name'=>2), +); +?> \ No newline at end of file diff --git a/modules/Cases/language/en_us.lang.php b/modules/Cases/language/en_us.lang.php new file mode 100644 index 00000000..94f7ec00 --- /dev/null +++ b/modules/Cases/language/en_us.lang.php @@ -0,0 +1,110 @@ + 'You must specify a record number to delete the account.', + + 'LBL_ACCOUNT_ID' => 'Account ID', + 'LBL_ACCOUNT_NAME' => 'Account Name:', + 'LBL_ACCOUNTS_SUBPANEL_TITLE' => 'Accounts', + 'LBL_ACTIVITIES_SUBPANEL_TITLE' => 'Activities', + 'LBL_ATTACH_NOTE' => 'Attach Note', + 'LBL_BUGS_SUBPANEL_TITLE' => 'Bugs', + 'LBL_CASE_NUMBER' => 'Case Number:', + 'LBL_CASE_SUBJECT' => 'Case Subject:', + 'LBL_CASE' => 'Case:', + 'LBL_CONTACT_CASE_TITLE' => 'Contact-Case:', + 'LBL_CONTACT_NAME' => 'Contact Name:', + 'LBL_CONTACT_ROLE' => 'Role:', + 'LBL_CONTACTS_SUBPANEL_TITLE' => 'Contacts', + 'LBL_DEFAULT_SUBPANEL_TITLE' => 'Cases', + 'LBL_DESCRIPTION' => 'Description:', + 'LBL_FILENANE_ATTACHMENT' => 'File Attachment', + 'LBL_HISTORY_SUBPANEL_TITLE' => 'History', + 'LBL_INVITEE' => 'Contacts', + 'LBL_MEMBER_OF' => 'Account', + 'LBL_MODULE_NAME' => 'Cases', + 'LBL_MODULE_TITLE' => 'Cases: Home', + 'LBL_NEW_FORM_TITLE' => 'New Case', + 'LBL_NUMBER' => 'Number:', + 'LBL_PRIORITY' => 'Priority:', + 'LBL_PROJECTS_SUBPANEL_TITLE' => 'Projects', + 'LBL_DOCUMENTS_SUBPANEL_TITLE' => 'Documents', + 'LBL_RESOLUTION' => 'Resolution:', + 'LBL_SEARCH_FORM_TITLE' => 'Case Search', + 'LBL_STATUS' => 'Status:', + 'LBL_SUBJECT' => 'Subject:', + 'LBL_SYSTEM_ID' => 'System ID', + 'LBL_LIST_ASSIGNED_TO_NAME' => 'Assigned User', + 'LBL_LIST_ACCOUNT_NAME' => 'Account Name', + 'LBL_LIST_ASSIGNED' => 'Assigned To', + 'LBL_LIST_CLOSE' => 'Close', + 'LBL_LIST_FORM_TITLE' => 'Case List', + 'LBL_LIST_LAST_MODIFIED' => 'Last Modified', + 'LBL_LIST_MY_CASES' => 'My Open Cases', + 'LBL_LIST_NUMBER' => 'Num.', + 'LBL_LIST_PRIORITY' => 'Priority', + 'LBL_LIST_STATUS' => 'Status', + 'LBL_LIST_SUBJECT' => 'Subject', + 'LBL_LIST_ASSIGNED_TO_NAME' => 'Assigned User', + + 'LNK_CASE_LIST' => 'View Cases', + 'LNK_NEW_CASE' => 'Create Case', + 'NTC_REMOVE_FROM_BUG_CONFIRMATION' => 'Are you sure you want to remove this case from the bug?', + 'NTC_REMOVE_INVITEE' => 'Are you sure you want to remove this contact from the case?', + 'LBL_LIST_DATE_CREATED' => 'Date Created', + 'LBL_ASSIGNED_TO_NAME' => 'Assigned to', + 'LBL_TYPE'=>'Type', + 'LBL_WORK_LOG'=>'Work Log', + 'LNK_IMPORT_CASES' => 'Import Cases', + + 'LBL_CREATED_USER' => 'Created User', + 'LBL_MODIFIED_USER' => 'Modified User', + 'LBL_PROJECT_SUBPANEL_TITLE' => 'Projects', + 'LBL_CASE_INFORMATION' => 'Case Overview', +); + + +?> \ No newline at end of file diff --git a/modules/Cases/metadata/SearchFields.php b/modules/Cases/metadata/SearchFields.php new file mode 100644 index 00000000..daf230eb --- /dev/null +++ b/modules/Cases/metadata/SearchFields.php @@ -0,0 +1,55 @@ + array( 'query_type'=>'default'), + 'account_name' => array( 'query_type'=>'default','db_field'=>array('accounts.name')), + 'status'=> array('query_type'=>'default', 'options' => 'case_status_dom', 'template_var' => 'STATUS_OPTIONS'), + 'priority'=> array('query_type'=>'default', 'options' => 'case_priority_dom', 'template_var' => 'PRIORITY_OPTIONS', 'options_add_blank' => true), + 'case_number' => array( 'query_type'=>'default', 'operator'=>'in'), + 'current_user_only'=> array('query_type'=>'default','db_field'=>array('assigned_user_id'),'my_items'=>true, 'vname' => 'LBL_CURRENT_USER_FILTER', 'type' => 'bool'), + 'assigned_user_id'=> array('query_type'=>'default'), + 'open_only' => array( + 'query_type'=>'default', + 'db_field'=>array('status'), + 'operator'=>'not in', + 'closed_values' => array('Closed', 'Rejected', 'Duplicate'), + 'type'=>'bool', + ), + ); +?> diff --git a/modules/Cases/metadata/accountsquickcreatedefs.php b/modules/Cases/metadata/accountsquickcreatedefs.php new file mode 100644 index 00000000..f81f3885 --- /dev/null +++ b/modules/Cases/metadata/accountsquickcreatedefs.php @@ -0,0 +1,77 @@ + array('form' => + array ( + 'hidden' => + array ( + 0 => '', + 1 => '', + ), + ), + 'maxColumns' => '2', + 'widths' => array( + array('label' => '10', 'field' => '30'), + array('label' => '10', 'field' => '30') + ), + ), +'panels' => + +array ( + + array ( + array ('name'=>'name', 'displayParams'=>array('size'=>65, 'required'=>true)), + 'priority' + ), + + array ( + 'status', + array('name'=>'account_name', 'type'=>'readonly'), + ), + + array ( + array ( + 'name' => 'description', + 'displayParams' => array ('rows' => '4','cols' => '60'), + 'nl2br' => true, + ), + ), + +), + +); +?> \ No newline at end of file diff --git a/modules/Cases/metadata/additionalDetails.php b/modules/Cases/metadata/additionalDetails.php new file mode 100644 index 00000000..17506fb9 --- /dev/null +++ b/modules/Cases/metadata/additionalDetails.php @@ -0,0 +1,69 @@ +'. $mod_strings['LBL_DESCRIPTION'] . ' ' . substr($fields['DESCRIPTION'], 0, 300); + if(strlen($fields['DESCRIPTION']) > 300) $overlib_string .= '...'; + $overlib_string .= '
    '; + } + if(!empty($fields['RESOLUTION'])) { + $overlib_string .= ''. $mod_strings['LBL_RESOLUTION'] . ' ' . substr($fields['RESOLUTION'], 0, 300); + if(strlen($fields['RESOLUTION']) > 300) $overlib_string .= '...'; + } + + return array('fieldToAddTo' => 'NAME', + 'string' => $overlib_string, + 'width' => '400', + 'editLink' => "index.php?action=EditView&module=Cases&return_module=Cases&record={$fields['ID']}", + 'viewLink' => "index.php?action=DetailView&module=Cases&return_module=Cases&record={$fields['ID']}"); +} + + ?> + + \ No newline at end of file diff --git a/modules/Cases/metadata/detailviewdefs.php b/modules/Cases/metadata/detailviewdefs.php new file mode 100644 index 00000000..166ece85 --- /dev/null +++ b/modules/Cases/metadata/detailviewdefs.php @@ -0,0 +1,105 @@ + array('form' => array('buttons' => + array('EDIT', 'DUPLICATE', 'DELETE', 'FIND_DUPLICATES', + ), + ), + 'maxColumns' => '2', + 'widths' => array( + array('label' => '10', 'field' => '30'), + array('label' => '10', 'field' => '30') + ), + ), +'panels' =>array ( + 'lbl_case_information'=>array( + array ( + array('name' => 'case_number', 'label' => 'LBL_CASE_NUMBER'), + 'priority' + ), + + array ( + 'status', + 'account_name', + ), + array ( + 'type', + ), + + array ( + + array ( + 'name' => 'name', + 'label' => 'LBL_SUBJECT', + ), + ), + + array ( + 'description', + ), + + array ( + 'resolution', + ), + + ), + + 'LBL_PANEL_ASSIGNMENT' => array( + array ( + array ( + 'name' => 'assigned_user_name', + 'label' => 'LBL_ASSIGNED_TO', + ), + array ( + 'name' => 'date_modified', + 'label' => 'LBL_DATE_MODIFIED', + 'customCode' => '{$fields.date_modified.value} {$APP.LBL_BY} {$fields.modified_by_name.value}', + ), + ), + array ( + array ( + 'name' => 'date_entered', + 'customCode' => '{$fields.date_entered.value} {$APP.LBL_BY} {$fields.created_by_name.value}', + ), + ), + ), +) + + + +); +?> \ No newline at end of file diff --git a/modules/Cases/metadata/editviewdefs.php b/modules/Cases/metadata/editviewdefs.php new file mode 100644 index 00000000..7bfd5935 --- /dev/null +++ b/modules/Cases/metadata/editviewdefs.php @@ -0,0 +1,99 @@ + array('maxColumns' => '2', + 'widths' => array( + array('label' => '10', 'field' => '30'), + array('label' => '10', 'field' => '30') + ), + ), + 'panels' => array ( + + 'lbl_case_information' => + array( + array ( + array('name'=>'case_number', 'type'=>'readonly') , + ), + + array ( + 'priority', + ), + + array ( + 'status', + 'account_name', + ), + + array ( + 'type', + ), + array ( + array ( + 'name' => 'name', + 'displayParams' => array ('size'=>75) + ), + ), + + array ( + + array ( + 'name' => 'description', + 'nl2br' => true, + ), + ), + + array ( + + array ( + 'name' => 'resolution', + 'nl2br' => true, + ), + ), + + ), + + 'LBL_PANEL_ASSIGNMENT' => + array( + array ( + 'assigned_user_name', + ), + ), +), + + +); +?> \ No newline at end of file diff --git a/modules/Cases/metadata/listviewdefs.php b/modules/Cases/metadata/listviewdefs.php new file mode 100644 index 00000000..ac560ee7 --- /dev/null +++ b/modules/Cases/metadata/listviewdefs.php @@ -0,0 +1,80 @@ + array( + 'width' => '5', + 'label' => 'LBL_LIST_NUMBER', + 'default' => true), + 'NAME' => array( + 'width' => '25', + 'label' => 'LBL_LIST_SUBJECT', + 'link' => true, + 'default' => true), + 'ACCOUNT_NAME' => array( + 'width' => '20', + 'label' => 'LBL_LIST_ACCOUNT_NAME', + 'module' => 'Accounts', + 'id' => 'ACCOUNT_ID', + 'link' => true, + 'default' => true, + 'ACLTag' => 'ACCOUNT', + 'related_fields' => array('account_id')), + 'PRIORITY' => array( + 'width' => '10', + 'label' => 'LBL_LIST_PRIORITY', + 'default' => true), + 'STATUS' => array( + 'width' => '10', + 'label' => 'LBL_LIST_STATUS', + 'default' => true), + 'ASSIGNED_USER_NAME' => array( + 'width' => '10', + 'label' => 'LBL_ASSIGNED_TO_NAME', + 'module' => 'Employees', + 'id' => 'ASSIGNED_USER_ID', + 'default' => true), + 'DATE_ENTERED' => array ( + 'width' => '10', + 'label' => 'LBL_DATE_ENTERED', + 'default' => true), +); +?> diff --git a/modules/Cases/metadata/popupdefs.php b/modules/Cases/metadata/popupdefs.php new file mode 100644 index 00000000..79876268 --- /dev/null +++ b/modules/Cases/metadata/popupdefs.php @@ -0,0 +1,92 @@ + 'Case', + 'varName' => 'CASE', + 'className' => 'aCase', + 'orderBy' => 'name', + 'whereClauses' => + array('name' => 'cases.name', + 'case_number' => 'cases.case_number', + 'account_name' => 'accounts.name'), + 'listviewdefs' => array( + 'CASE_NUMBER' => array( + 'width' => '5', + 'label' => 'LBL_LIST_NUMBER', + 'default' => true), + 'NAME' => array( + 'width' => '35', + 'label' => 'LBL_LIST_SUBJECT', + 'link' => true, + 'default' => true), + 'ACCOUNT_NAME' => array( + 'width' => '25', + 'label' => 'LBL_LIST_ACCOUNT_NAME', + 'module' => 'Accounts', + 'id' => 'ACCOUNT_ID', + 'link' => true, + 'default' => true, + 'ACLTag' => 'ACCOUNT', + 'related_fields' => array('account_id')), + 'PRIORITY' => array( + 'width' => '8', + 'label' => 'LBL_LIST_PRIORITY', + 'default' => true), + 'STATUS' => array( + 'width' => '8', + 'label' => 'LBL_LIST_STATUS', + 'default' => true), + 'ASSIGNED_USER_NAME' => array( + 'width' => '2', + 'label' => 'LBL_LIST_ASSIGNED_USER', + 'default' => true, + ), + ), + 'searchdefs' => array( + 'case_number', + 'name', + array('name' => 'account_name', 'displayParams' => array('hideButtons'=>'true', 'size'=>30, 'class'=>'sqsEnabled sqsNoAutofill')), + 'priority', + 'status', + array('name' => 'assigned_user_id', 'type' => 'enum', 'label' => 'LBL_ASSIGNED_TO', 'function' => array('name' => 'get_user_array', 'params' => array(false))), + ) +); +?> + + \ No newline at end of file diff --git a/modules/Cases/metadata/quickcreatedefs.php b/modules/Cases/metadata/quickcreatedefs.php new file mode 100644 index 00000000..515f4a13 --- /dev/null +++ b/modules/Cases/metadata/quickcreatedefs.php @@ -0,0 +1,75 @@ + array('maxColumns' => '2', + 'widths' => array( + array('label' => '10', 'field' => '30'), + array('label' => '10', 'field' => '30') + ), + ), +'panels' => + +array ( + + array ( + array ('name'=>'name', 'displayParams'=>array('size'=>65, 'required'=>true)), + 'priority' + ), + + array ( + 'status', + array('name'=>'account_name'), + ), + + array ( + 'assigned_user_name', + ), + + array ( + array ( + 'name' => 'description', + 'displayParams' => array ('rows' => '4','cols' => '60'), + 'nl2br' => true, + ), + ), + +), + +); +?> \ No newline at end of file diff --git a/modules/Cases/metadata/searchdefs.php b/modules/Cases/metadata/searchdefs.php new file mode 100644 index 00000000..a6937ea0 --- /dev/null +++ b/modules/Cases/metadata/searchdefs.php @@ -0,0 +1,61 @@ + array( + 'maxColumns' => '4', + 'widths' => array('label' => '10', 'field' => '30'), + ), + 'layout' => array( + 'basic_search' => array( + 'name', + array('name'=>'current_user_only', 'label'=>'LBL_CURRENT_USER_FILTER', 'type'=>'bool'), + + array ('name' => 'open_only', 'label' => 'LBL_OPEN_ITEMS', 'type' => 'bool', 'default' => false, 'width' => '10%'), + + ), + 'advanced_search' => array( + 'case_number', + 'name', + 'account_name', + 'status', + array('name' => 'assigned_user_id', 'type' => 'enum', 'label' => 'LBL_ASSIGNED_TO', 'function' => array('name' => 'get_user_array', 'params' => array(false))), + 'priority', + + ), + ), + ); +?> diff --git a/modules/Cases/metadata/studio.php b/modules/Cases/metadata/studio.php new file mode 100644 index 00000000..28d3710f --- /dev/null +++ b/modules/Cases/metadata/studio.php @@ -0,0 +1,66 @@ +array( + 'template'=>'xtpl', + 'template_file'=>'modules/Cases/DetailView.html', + 'php_file'=>'modules/Cases/DetailView.php', + 'type'=>'DetailView', + ), + 'LBL_EDITVIEW'=>array( + 'template'=>'xtpl', + 'template_file'=>'modules/Cases/EditView.html', + 'php_file'=>'modules/Cases/EditView.php', + 'type'=>'EditView', + ), + 'LBL_LISTVIEW'=>array( + 'template'=>'listview', + 'meta_file'=>'modules/Cases/listviewdefs.php', + 'type'=>'ListView', + ), + 'LBL_SEARCHFORM'=>array( + 'template'=>'xtpl', + 'template_file'=>'modules/Cases/SearchForm.html', + 'php_file'=>'modules/Cases/ListView.php', + 'type'=>'SearchForm', + ), + +); diff --git a/modules/Cases/metadata/subpaneldefs.php b/modules/Cases/metadata/subpaneldefs.php new file mode 100644 index 00000000..8f0dc52f --- /dev/null +++ b/modules/Cases/metadata/subpaneldefs.php @@ -0,0 +1,195 @@ + array( + 'contacts' => array( + 'order' => 30, + 'module' => 'Contacts', + 'sort_order' => 'asc', + 'sort_by' => 'last_name, first_name', + 'subpanel_name' => 'default', + 'get_subpanel_data' => 'contacts', + 'add_subpanel_data' => 'contact_id', + 'title_key' => 'LBL_CONTACTS_SUBPANEL_TITLE', + 'top_buttons' => array( + array('widget_class' => 'SubPanelTopCreateAccountNameButton'), + array( + 'widget_class' => 'SubPanelTopSelectButton', + 'popup_module' => 'Cases', + 'mode' => 'MultiSelect', + 'initial_filter_fields' => array('account_id' => 'account_id', 'account_name' => 'account_name'), + ), + ), + ), + 'activities' => array( + 'order' => 10, + 'sort_order' => 'desc', + 'sort_by' => 'date_start', + 'title_key' => 'LBL_ACTIVITIES_SUBPANEL_TITLE', + 'type' => 'collection', + 'subpanel_name' => 'activities', //this values is not associated with a physical file. + 'module'=>'Activities', + + 'top_buttons' => array( + array('widget_class' => 'SubPanelTopCreateTaskButton'), + array('widget_class' => 'SubPanelTopScheduleMeetingButton'), + array('widget_class' => 'SubPanelTopScheduleCallButton'), + array('widget_class' => 'SubPanelTopComposeEmailButton'), + ), + + 'collection_list' => array( + 'meetings' => array( + 'module' => 'Meetings', + 'subpanel_name' => 'ForActivities', + 'get_subpanel_data' => 'meetings', + ), + 'tasks' => array( + 'module' => 'Tasks', + 'subpanel_name' => 'ForActivities', + 'get_subpanel_data' => 'tasks', + ), + 'calls' => array( + 'module' => 'Calls', + 'subpanel_name' => 'ForActivities', + 'get_subpanel_data' => 'calls', + ), + ) + ), + 'history' => array( + 'order' => 20, + 'sort_order' => 'desc', + 'sort_by' => 'date_entered', + 'title_key' => 'LBL_HISTORY_SUBPANEL_TITLE', + 'type' => 'collection', + 'subpanel_name' => 'history', //this values is not associated with a physical file. + 'module'=>'History', + + 'top_buttons' => array( + array('widget_class' => 'SubPanelTopCreateNoteButton'), + array('widget_class' => 'SubPanelTopArchiveEmailButton'), + array('widget_class' => 'SubPanelTopSummaryButton'), + ), + + 'collection_list' => array( + 'meetings' => array( + 'module' => 'Meetings', + 'subpanel_name' => 'ForHistory', + 'get_subpanel_data' => 'meetings', + ), + 'tasks' => array( + 'module' => 'Tasks', + 'subpanel_name' => 'ForHistory', + 'get_subpanel_data' => 'tasks', + ), + 'calls' => array( + 'module' => 'Calls', + 'subpanel_name' => 'ForHistory', + 'get_subpanel_data' => 'calls', + ), + 'notes' => array( + 'module' => 'Notes', + 'subpanel_name' => 'ForHistory', + 'get_subpanel_data' => 'notes', + ), + 'emails' => array( + 'module' => 'Emails', + 'subpanel_name' => 'ForHistory', + 'get_subpanel_data' => 'emails', + ), + ) + ), + 'documents' => array( + 'order' => 25, + 'module' => 'Documents', + 'subpanel_name' => 'default', + 'sort_order' => 'asc', + 'sort_by' => 'id', + 'title_key' => 'LBL_DOCUMENTS_SUBPANEL_TITLE', + 'get_subpanel_data' => 'documents', + 'top_buttons' => + array ( + 0 => + array ( + 'widget_class' => 'SubPanelTopButtonQuickCreate', + ), + 1 => + array ( + 'widget_class' => 'SubPanelTopSelectButton', + 'mode' => 'MultiSelect', + ), + ), + ), + 'bugs' => array( + 'order' => 40, + 'module' => 'Bugs', + 'sort_order' => 'desc', + 'sort_by' => 'bug_number', + 'subpanel_name' => 'default', + 'get_subpanel_data' => 'bugs', + 'add_subpanel_data' => 'bug_id', + 'title_key' => 'LBL_BUGS_SUBPANEL_TITLE', + 'top_buttons' => array( + array('widget_class' => 'SubPanelTopButtonQuickCreate'), + array( + 'widget_class' => 'SubPanelTopSelectButton', + 'popup_module' => 'Bugs', + 'mode' => 'MultiSelect', + ), + ), + ), + 'project' => array( + 'order' => 110, + 'sort_order' => 'asc', + 'sort_by' => 'name', + 'module' => 'Project', + 'subpanel_name' => 'default', + 'get_subpanel_data' => 'project', + 'add_subpanel_data' => 'project_id', + 'title_key' => 'LBL_PROJECTS_SUBPANEL_TITLE', + 'top_buttons' => array( + array('widget_class' => 'SubPanelTopButtonQuickCreate'), + array('widget_class' => 'SubPanelTopSelectButton'), + ), + ), + ), +); +?> \ No newline at end of file diff --git a/modules/Cases/metadata/subpanels/ForAccounts.php b/modules/Cases/metadata/subpanels/ForAccounts.php new file mode 100644 index 00000000..baef9075 --- /dev/null +++ b/modules/Cases/metadata/subpanels/ForAccounts.php @@ -0,0 +1,95 @@ + array( + array('widget_class' => 'SubPanelTopCreateButton'), + array('widget_class' => 'SubPanelTopSelectButton', 'popup_module' => 'Cases'), + ), + + 'where' => '', + + + + 'list_fields' => array( + 'case_number'=>array( + 'vname' => 'LBL_LIST_NUMBER', + 'width' => '6%', + ), + + 'name'=>array( + 'vname' => 'LBL_LIST_SUBJECT', + 'widget_class' => 'SubPanelDetailViewLink', + 'width' => '50%', + ), + 'status'=>array( + 'vname' => 'LBL_LIST_STATUS', + 'width' => '10%', + ), + 'priority'=>array( + 'vname' => 'LBL_LIST_PRIORITY', + 'width' => '10%', + ), + 'date_entered'=>array( + 'vname' => 'LBL_LIST_DATE_CREATED', + 'width' => '15%', + ), + 'assigned_user_name' => array ( + 'name' => 'assigned_user_name', + 'widget_class' => 'SubPanelDetailViewLink', + 'target_record_key' => 'assigned_user_id', + 'target_module' => 'Employees', + 'vname' => 'LBL_LIST_ASSIGNED_TO_NAME', + ), + 'edit_button'=>array( + 'vname' => 'LBL_EDIT_BUTTON', + 'widget_class' => 'SubPanelEditButton', + 'module' => 'Cases', + 'width' => '4%', + ), + 'remove_button'=>array( + 'vname' => 'LBL_REMOVE', + 'widget_class' => 'SubPanelRemoveButton', + 'module' => 'Cases', + 'width' => '5%', + ), + ), +); + +?> \ No newline at end of file diff --git a/modules/Cases/metadata/subpanels/ForEmails.php b/modules/Cases/metadata/subpanels/ForEmails.php new file mode 100644 index 00000000..e1a6324d --- /dev/null +++ b/modules/Cases/metadata/subpanels/ForEmails.php @@ -0,0 +1,94 @@ + array( + array('widget_class' => 'SubPanelTopSelectButton', 'popup_module' => 'Cases'), + ), + + 'where' => '', + + + + 'list_fields' => array( + 'case_number'=>array( + 'vname' => 'LBL_LIST_NUMBER', + 'width' => '6%', + ), + + 'name'=>array( + 'vname' => 'LBL_LIST_SUBJECT', + 'widget_class' => 'SubPanelDetailViewLink', + 'width' => '30%', + ), + 'reply_to_status' => array( + 'usage' => 'query_only', + 'force_exists' => true, + ), + 'assigned_user_name'=>array( + 'vname' => 'LBL_LIST_ASSIGNED', + 'widget_class' => 'SubPanelDetailViewLink', + 'width' => '30%', + ), + 'account_name'=>array( + 'module' => 'Accounts', + 'widget_class' => 'SubPanelDetailViewLink', + 'vname' => 'LBL_LIST_ACCOUNT_NAME', + 'width' => '30%', + ), + 'status'=>array( + 'vname' => 'LBL_LIST_STATUS', + 'width' => '10%', + ), + 'edit_button'=>array( + 'vname' => 'LBL_EDIT_BUTTON', + 'widget_class' => 'SubPanelEditButton', + 'module' => 'Cases', + 'width' => '4%', + ), + 'remove_button'=>array( + 'vname' => 'LBL_REMOVE', + 'widget_class' => 'SubPanelRemoveButton', + 'module' => 'Cases', + 'width' => '5%', + ), + ), +); + +?> \ No newline at end of file diff --git a/modules/Cases/metadata/subpanels/default.php b/modules/Cases/metadata/subpanels/default.php new file mode 100644 index 00000000..b016ed5a --- /dev/null +++ b/modules/Cases/metadata/subpanels/default.php @@ -0,0 +1,100 @@ + array( + array('widget_class' => 'SubPanelTopCreateButton'), + array('widget_class' => 'SubPanelTopSelectButton', 'popup_module' => 'Cases'), + ), + + 'where' => '', + + 'fill_in_additional_fields'=>true, + + 'list_fields' => array( + 'case_number'=>array( + 'vname' => 'LBL_LIST_NUMBER', + 'width' => '6%', + ), + + 'name'=>array( + 'vname' => 'LBL_LIST_SUBJECT', + 'widget_class' => 'SubPanelDetailViewLink', + 'width' => '40%', + ), + 'account_name'=>array( + 'vname' => 'LBL_LIST_ACCOUNT_NAME', + 'widget_class' => 'SubPanelDetailViewLink', + 'module' => 'Accounts', + 'width' => '31%', + 'target_record_key' => 'account_id', + 'target_module' => 'Accounts', + ), + 'status'=>array( + 'vname' => 'LBL_LIST_STATUS', + 'width' => '10%', + ), + 'date_entered'=>array( + 'vname' => 'LBL_LIST_DATE_CREATED', + 'width' => '15%', + ), + 'assigned_user_name' => array ( + 'name' => 'assigned_user_name', + 'vname' => 'LBL_LIST_ASSIGNED_TO_NAME', + 'widget_class' => 'SubPanelDetailViewLink', + 'target_record_key' => 'assigned_user_id', + 'target_module' => 'Employees', + ), + 'edit_button'=>array( + 'vname' => 'LBL_EDIT_BUTTON', + 'widget_class' => 'SubPanelEditButton', + 'module' => 'Cases', + 'width' => '4%', + ), + 'remove_button'=>array( + 'vname' => 'LBL_REMOVE', + 'widget_class' => 'SubPanelRemoveButton', + 'module' => 'Cases', + 'width' => '5%', + ), + + ), +); + +?> \ No newline at end of file diff --git a/modules/Cases/tpls/QuickCreate.tpl b/modules/Cases/tpls/QuickCreate.tpl new file mode 100644 index 00000000..8be9ab79 --- /dev/null +++ b/modules/Cases/tpls/QuickCreate.tpl @@ -0,0 +1,100 @@ +{* + +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + + + +*} + + +
    + + + + + + + + + + + + + + + + + +
    + + + {$APP.LBL_REQUIRED_SYMBOL} {$APP.NTC_REQUIRED}
    + + +{/if} + + + + +{counter} +{else} + {if $count is odd} + + {/if} + + + {if $count is not odd} + + {/if} +{/if} \ No newline at end of file diff --git a/modules/Configurator/tpls/addFontResult.tpl b/modules/Configurator/tpls/addFontResult.tpl new file mode 100644 index 00000000..0f2138d4 --- /dev/null +++ b/modules/Configurator/tpls/addFontResult.tpl @@ -0,0 +1,59 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + + + +*} + +

    +{$MODULE_TITLE} +

    + + + +
    + + + + + + + + + + + + + + + + + + {if $REQUEST.account_id != ''} + + + {else} + + + {/if} + +

    {$MOD.LBL_CASE_INFORMATION}

    {$MOD.LBL_SUBJECT} {$APP.LBL_REQUIRED_SYMBOL}{$MOD.LBL_PRIORITY}
    {$MOD.LBL_DESCRIPTION}{$MOD.LBL_STATUS}
    {$MOD.LBL_ACCOUNT_NAME} {$APP.LBL_REQUIRED_SYMBOL}{$REQUEST.parent_name} {$MOD.LBL_ACCOUNT_NAME} {$APP.LBL_REQUIRED_SYMBOL} +  
    + + \ No newline at end of file diff --git a/modules/Cases/vardefs.php b/modules/Cases/vardefs.php new file mode 100644 index 00000000..716a94e9 --- /dev/null +++ b/modules/Cases/vardefs.php @@ -0,0 +1,264 @@ + 'cases','audited'=>true, 'unified_search' => true, 'unified_search_default_enabled' => true, 'duplicate_merge'=>true, + 'comment' => 'Cases are issues or problems that a customer asks a support representative to resolve' + ,'fields' => array ( + + + 'account_name' => + array ( + 'name' => 'account_name', + 'rname' => 'name', + 'id_name' => 'account_id', + 'vname' => 'LBL_ACCOUNT_NAME', + 'type' => 'relate', + 'link'=>'accounts', + 'table' => 'accounts', + 'join_name'=>'accounts', + 'isnull' => 'true', + 'module' => 'Accounts', + 'dbType' => 'varchar', + 'len' => 100, + 'source'=>'non-db', + 'unified_search' => true, + 'comment' => 'The name of the account represented by the account_id field', + 'required' => true, + 'importable' => 'required', + ), + 'account_name1' => + array ( + 'name' => 'account_name1', + 'source'=>'non-db', + 'type'=>'text', + 'len' => 100, + 'importable' => 'false', + ), + + 'account_id'=> + array( + 'name'=>'account_id', + 'type' => 'relate', + 'dbType' => 'id', + 'rname' => 'id', + 'module' => 'Accounts', + 'id_name' => 'account_id', + 'reportable'=>false, + 'vname'=>'LBL_ACCOUNT_ID', + 'audited'=>true, + 'massupdate' => false, + 'comment' => 'The account to which the case is associated' + ), + + 'status' => + array ( + 'name' => 'status', + 'vname' => 'LBL_STATUS', + 'type' => 'enum', + 'options' => 'case_status_dom', + 'len' => 100, + 'audited'=>true, + 'comment' => 'The status of the case', + + ), + 'priority' => + array ( + 'name' => 'priority', + 'vname' => 'LBL_PRIORITY', + 'type' => 'enum', + 'options' => 'case_priority_dom', + 'len' => 100, + 'audited'=>true, + 'comment' => 'The priority of the case', + + ), + 'resolution' => + array ( + 'name' => 'resolution', + 'vname' => 'LBL_RESOLUTION', + 'type' => 'text', + 'comment' => 'The resolution of the case' + ), + + + 'tasks' => + array ( + 'name' => 'tasks', + 'type' => 'link', + 'relationship' => 'case_tasks', + 'source'=>'non-db', + 'vname'=>'LBL_TASKS', + ), + 'notes' => + array ( + 'name' => 'notes', + 'type' => 'link', + 'relationship' => 'case_notes', + 'source'=>'non-db', + 'vname'=>'LBL_NOTES', + ), + 'meetings' => + array ( + 'name' => 'meetings', + 'type' => 'link', + 'relationship' => 'case_meetings', + 'bean_name'=>'Meeting', + 'source'=>'non-db', + 'vname'=>'LBL_MEETINGS', + ), + 'emails' => + array ( + 'name' => 'emails', + 'type' => 'link', + 'relationship' => 'emails_cases_rel',/* reldef in emails */ + 'source'=>'non-db', + 'vname'=>'LBL_EMAILS', + ), + 'documents'=> + array ( + 'name' => 'documents', + 'type' => 'link', + 'relationship' => 'documents_cases', + 'source' => 'non-db', + 'vname' => 'LBL_DOCUMENTS_SUBPANEL_TITLE', + ), + 'calls' => + array ( + 'name' => 'calls', + 'type' => 'link', + 'relationship' => 'case_calls', + 'source'=>'non-db', + 'vname'=>'LBL_CALLS', + ), + 'bugs' => + array ( + 'name' => 'bugs', + 'type' => 'link', + 'relationship' => 'cases_bugs', + 'source'=>'non-db', + 'vname'=>'LBL_BUGS', + ), + 'contacts' => + array ( + 'name' => 'contacts', + 'type' => 'link', + 'relationship' => 'contacts_cases', + 'source'=>'non-db', + 'vname'=>'LBL_CONTACTS', + ), + 'accounts' => + array ( + 'name' => 'accounts', + 'type' => 'link', + 'relationship' => 'account_cases', + 'link_type'=>'one', + 'side'=>'right', + 'source'=>'non-db', + 'vname'=>'LBL_ACCOUNT', + ), + 'project' => + array ( + 'name' => 'project', + 'type' => 'link', + 'relationship' => 'projects_cases', + 'source'=>'non-db', + 'vname'=>'LBL_PROJECTS', + ), + + ), 'indices' => array ( + array('name' =>'case_number' , 'type'=>'index' , 'fields'=>array('case_number')), + + array('name' =>'idx_case_name', 'type' =>'index', 'fields'=>array('name')), + array( 'name' => 'idx_account_id', 'type' => 'index', 'fields'=> array('account_id')), + array('name' => 'idx_cases_stat_del', 'type' => 'index', 'fields'=> array('assigned_user_id', 'status', 'deleted')), + ) + +, 'relationships' => array ( + 'case_calls' => array('lhs_module'=> 'Cases', 'lhs_table'=> 'cases', 'lhs_key' => 'id', + 'rhs_module'=> 'Calls', 'rhs_table'=> 'calls', 'rhs_key' => 'parent_id', + 'relationship_type'=>'one-to-many', 'relationship_role_column'=>'parent_type', + 'relationship_role_column_value'=>'Cases') + + ,'case_tasks' => array('lhs_module'=> 'Cases', 'lhs_table'=> 'cases', 'lhs_key' => 'id', + 'rhs_module'=> 'Tasks', 'rhs_table'=> 'tasks', 'rhs_key' => 'parent_id', + 'relationship_type'=>'one-to-many', 'relationship_role_column'=>'parent_type', + 'relationship_role_column_value'=>'Cases') + + ,'case_notes' => array('lhs_module'=> 'Cases', 'lhs_table'=> 'cases', 'lhs_key' => 'id', + 'rhs_module'=> 'Notes', 'rhs_table'=> 'notes', 'rhs_key' => 'parent_id', + 'relationship_type'=>'one-to-many', 'relationship_role_column'=>'parent_type', + 'relationship_role_column_value'=>'Cases') + + ,'case_meetings' => array('lhs_module'=> 'Cases', 'lhs_table'=> 'cases', 'lhs_key' => 'id', + 'rhs_module'=> 'Meetings', 'rhs_table'=> 'meetings', 'rhs_key' => 'parent_id', + 'relationship_type'=>'one-to-many', 'relationship_role_column'=>'parent_type', + 'relationship_role_column_value'=>'Cases') + + ,'case_emails' => array('lhs_module'=> 'Cases', 'lhs_table'=> 'cases', 'lhs_key' => 'id', + 'rhs_module'=> 'Emails', 'rhs_table'=> 'emails', 'rhs_key' => 'parent_id', + 'relationship_type'=>'one-to-many', 'relationship_role_column'=>'parent_type', + 'relationship_role_column_value'=>'Cases') + , + 'cases_assigned_user' => + array('lhs_module'=> 'Users', 'lhs_table'=> 'users', 'lhs_key' => 'id', + 'rhs_module'=> 'Cases', 'rhs_table'=> 'cases', 'rhs_key' => 'assigned_user_id', + 'relationship_type'=>'one-to-many') + + ,'cases_modified_user' => + array('lhs_module'=> 'Users', 'lhs_table'=> 'users', 'lhs_key' => 'id', + 'rhs_module'=> 'Cases', 'rhs_table'=> 'cases', 'rhs_key' => 'modified_user_id', + 'relationship_type'=>'one-to-many') + + ,'cases_created_by' => + array('lhs_module'=> 'Users', 'lhs_table'=> 'users', 'lhs_key' => 'id', + 'rhs_module'=> 'Cases', 'rhs_table'=> 'cases', 'rhs_key' => 'created_by', + 'relationship_type'=>'one-to-many') +) +//This enables optimistic locking for Saves From EditView + ,'optimistic_locking'=>true, +); +VardefManager::createVardef('Cases','Case', array('default', 'assignable', +'issue', +), +'case' +); + +//jc - adding for refactor for import to not use the required_fields array +//defined in the field_arrays.php file +$dictionary['Case']['fields']['name']['importable'] = 'required'; +?> \ No newline at end of file diff --git a/modules/Charts/Dashlets/CampaignROIChartDashlet/CampaignROIChartConfigure.tpl b/modules/Charts/Dashlets/CampaignROIChartDashlet/CampaignROIChartConfigure.tpl new file mode 100644 index 00000000..d5cbaf30 --- /dev/null +++ b/modules/Charts/Dashlets/CampaignROIChartDashlet/CampaignROIChartConfigure.tpl @@ -0,0 +1,71 @@ +{* + +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + + + +*} + + +
    +
    + + + + + + + + + + + + + + + + + +
    {$LBL_CAMPAIGN_NAME} + +
    + +
    +
    +
    \ No newline at end of file diff --git a/modules/Charts/Dashlets/CampaignROIChartDashlet/CampaignROIChartDashlet.data.php b/modules/Charts/Dashlets/CampaignROIChartDashlet/CampaignROIChartDashlet.data.php new file mode 100644 index 00000000..9c008cec --- /dev/null +++ b/modules/Charts/Dashlets/CampaignROIChartDashlet/CampaignROIChartDashlet.data.php @@ -0,0 +1,48 @@ + array( + 'name' => 'campaign_id', + 'vname' => 'LBL_CAMPAIGN_NAME', + 'type' => 'enum', + ) + ); +?> diff --git a/modules/Charts/Dashlets/CampaignROIChartDashlet/CampaignROIChartDashlet.en_us.lang.php b/modules/Charts/Dashlets/CampaignROIChartDashlet/CampaignROIChartDashlet.en_us.lang.php new file mode 100644 index 00000000..f860da2c --- /dev/null +++ b/modules/Charts/Dashlets/CampaignROIChartDashlet/CampaignROIChartDashlet.en_us.lang.php @@ -0,0 +1,45 @@ + 'Campaign ROI', + 'LBL_DESCRIPTION' => 'ROI Chart', + 'LBL_REFRESH' => 'Refresh Chart'); +?> \ No newline at end of file diff --git a/modules/Charts/Dashlets/CampaignROIChartDashlet/CampaignROIChartDashlet.meta.php b/modules/Charts/Dashlets/CampaignROIChartDashlet/CampaignROIChartDashlet.meta.php new file mode 100644 index 00000000..8805b1ea --- /dev/null +++ b/modules/Charts/Dashlets/CampaignROIChartDashlet/CampaignROIChartDashlet.meta.php @@ -0,0 +1,50 @@ + 'LBL_TITLE', + 'description' => 'LBL_TITLE', + 'icon' => 'icon_Charts_GroupBy_32.gif', + 'category' => 'Charts', + 'module' => 'Campaigns',); +?> diff --git a/modules/Charts/Dashlets/CampaignROIChartDashlet/CampaignROIChartDashlet.php b/modules/Charts/Dashlets/CampaignROIChartDashlet/CampaignROIChartDashlet.php new file mode 100644 index 00000000..5384dfcc --- /dev/null +++ b/modules/Charts/Dashlets/CampaignROIChartDashlet/CampaignROIChartDashlet.php @@ -0,0 +1,87 @@ +getSeedBean()->disable_row_level_security = false; + + $campaigns = $this->getSeedBean()->get_full_list("",""); + if ( $campaigns != null ) + foreach ($campaigns as $c) + $this->_searchFields['campaign_id']['options'][$c->id] = $c->name; + else + $this->_searchFields['campaign_id']['options'] = array(); + + return parent::displayOptions(); + } + + /** + * @see DashletGenericChart::display() + */ + public function display() + { + require_once('modules/Campaigns/Charts.php'); + + $roi_chart = new campaign_charts(); + $chartStr = $roi_chart->campaign_response_roi( + $GLOBALS['app_list_strings']['roi_type_dom'], + $GLOBALS['app_list_strings']['roi_type_dom'], + $this->campaign_id[0],null,true,true,true,$this->id); + + $returnStr = $chartStr; + + return $this->getTitle('
    ') . '
    ' . $returnStr . '
    '. $this->processAutoRefresh(); + } +} \ No newline at end of file diff --git a/modules/Charts/Dashlets/MyPipelineBySalesStageDashlet/MyPipelineBySalesStageConfigure.tpl b/modules/Charts/Dashlets/MyPipelineBySalesStageDashlet/MyPipelineBySalesStageConfigure.tpl new file mode 100644 index 00000000..944e196b --- /dev/null +++ b/modules/Charts/Dashlets/MyPipelineBySalesStageDashlet/MyPipelineBySalesStageConfigure.tpl @@ -0,0 +1,100 @@ +{* + +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + + + +*} + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    {$LBL_TITLE}
    + +
    {$LBL_DATE_START}
    {$user_date_format}
    + + {$LBL_ENTER_DATE} +
    {$LBL_DATE_END}
    {$user_date_format}
    + + {$LBL_ENTER_DATE} +
    {$LBL_SALES_STAGES} +
    + +
    +
    +{literal} + +
    \ No newline at end of file diff --git a/modules/Charts/Dashlets/MyPipelineBySalesStageDashlet/MyPipelineBySalesStageDashlet.data.php b/modules/Charts/Dashlets/MyPipelineBySalesStageDashlet/MyPipelineBySalesStageDashlet.data.php new file mode 100644 index 00000000..03fc1e24 --- /dev/null +++ b/modules/Charts/Dashlets/MyPipelineBySalesStageDashlet/MyPipelineBySalesStageDashlet.data.php @@ -0,0 +1,59 @@ + array( + 'name' => 'mypbss_date_start', + 'vname' => 'LBL_CLOSE_DATE_START', + 'type' => 'datepicker', + ), + 'mypbss_date_end' => array( + 'name' => 'mypbss_date_end', + 'vname' => 'LBL_CLOSE_DATE_END', + 'type' => 'datepicker', + ), + 'mypbss_sales_stages' => array( + 'name' => 'mypbss_sales_stages', + 'vname' => 'LBL_SALES_STAGES', + 'type' => 'enum', + ), + + ); +?> diff --git a/modules/Charts/Dashlets/MyPipelineBySalesStageDashlet/MyPipelineBySalesStageDashlet.en_us.lang.php b/modules/Charts/Dashlets/MyPipelineBySalesStageDashlet/MyPipelineBySalesStageDashlet.en_us.lang.php new file mode 100644 index 00000000..64f0e92e --- /dev/null +++ b/modules/Charts/Dashlets/MyPipelineBySalesStageDashlet/MyPipelineBySalesStageDashlet.en_us.lang.php @@ -0,0 +1,45 @@ + 'My Pipeline By Sales Stage', + 'LBL_DESCRIPTION' => 'Vertical Bar Chart of My Sales Stage Pipeline', + 'LBL_REFRESH' => 'Refresh Chart'); +?> \ No newline at end of file diff --git a/modules/Charts/Dashlets/MyPipelineBySalesStageDashlet/MyPipelineBySalesStageDashlet.meta.php b/modules/Charts/Dashlets/MyPipelineBySalesStageDashlet/MyPipelineBySalesStageDashlet.meta.php new file mode 100644 index 00000000..42970089 --- /dev/null +++ b/modules/Charts/Dashlets/MyPipelineBySalesStageDashlet/MyPipelineBySalesStageDashlet.meta.php @@ -0,0 +1,48 @@ + 'LBL_TITLE', + 'description' => 'LBL_TITLE', + 'icon' => 'icon_Charts_Funnel_32.gif', + 'module' => 'Opportunities', + 'category' => 'Charts'); +?> diff --git a/modules/Charts/Dashlets/MyPipelineBySalesStageDashlet/MyPipelineBySalesStageDashlet.php b/modules/Charts/Dashlets/MyPipelineBySalesStageDashlet/MyPipelineBySalesStageDashlet.php new file mode 100644 index 00000000..17977adf --- /dev/null +++ b/modules/Charts/Dashlets/MyPipelineBySalesStageDashlet/MyPipelineBySalesStageDashlet.php @@ -0,0 +1,256 @@ +nowDbDate(); + if(empty($options['mypbss_date_end'])) + $options['mypbss_date_end'] = $timedate->asDbDate($timedate->getNow()->modify("+6 months")); + if(empty($options['title'])) + $options['title'] = translate('LBL_MY_PIPELINE_FORM_TITLE', 'Home'); + + parent::__construct($id,$options); + } + + /** + * @see DashletGenericChart::displayOptions() + */ + public function displayOptions() + { + global $app_list_strings; + + $selected_datax = array(); + if (count($this->mypbss_sales_stages) > 0) + foreach ($this->mypbss_sales_stages as $key) + $selected_datax[] = $key; + else + $selected_datax = array_keys($app_list_strings['sales_stage_dom']); + + $this->_searchFields['mypbss_sales_stages']['options'] = $app_list_strings['sales_stage_dom']; + $this->_searchFields['mypbss_sales_stages']['input_name0'] = $selected_datax; + + return parent::displayOptions(); + } + + /** + * @see DashletGenericChart::display() + */ + public function display() + { + global $sugar_config, $current_user; + + require_once('include/SugarCharts/SugarChartFactory.php'); + $sugarChart = SugarChartFactory::getInstance(); + $sugarChart->base_url = array( 'module' => 'Opportunities', + 'action' => 'index', + 'query' => 'true', + 'searchFormTab' => 'advanced_search', + ); + $sugarChart->url_params = array( 'assigned_user_id' => $current_user->id ); + $sugarChart->group_by = $this->constructGroupBy(); + + $currency_symbol = $sugar_config['default_currency_symbol']; + if ($current_user->getPreference('currency')){ + + $currency = new Currency(); + $currency->retrieve($current_user->getPreference('currency')); + $currency_symbol = $currency->symbol; + } + + $sugarChart->is_currency = true; + $sugarChart->thousands_symbol = translate('LBL_OPP_THOUSANDS', 'Charts'); + + $subtitle = translate('LBL_OPP_SIZE', 'Charts') . " " . $currency_symbol . "1" . translate('LBL_OPP_THOUSANDS', 'Charts'); + + $query = $this->constructQuery(); + $dataset = $this->constructCEChartData($this->getChartData($query)); + $sugarChart->setData($dataset); + $total = format_number($this->getHorizBarTotal($dataset), 0, 0, array('convert'=>true)); + $pipeline_total_string = translate('LBL_TOTAL_PIPELINE', 'Charts') . $sugarChart->currency_symbol . $total . $sugarChart->thousands_symbol; + $sugarChart->setProperties($pipeline_total_string, $subtitle, 'horizontal bar chart'); + + $xmlFile = $sugarChart->getXMLFileName($this->id); + $sugarChart->saveXMLFile($xmlFile, $sugarChart->generateXML()); + + return $this->getTitle('') . + '
    ' .$sugarChart->display($this->id, $xmlFile, '100%', '480', false) . '

    '. $this->processAutoRefresh(); + } + + /** + * awu: Bug 16794 - this function is a hack to get the correct sales stage order + * until i can clean it up later + * + * @param $query string + * @return array + */ + private function getChartData( + $query + ) + { + global $app_list_strings, $db; + + $data = array(); + $temp_data = array(); + $selected_datax = array(); + + $user_sales_stage = $this->mypbss_sales_stages; + $tempx = $user_sales_stage; + + //set $datax using selected sales stage keys + if (count($tempx) > 0) { + foreach ($tempx as $key) { + $datax[$key] = $app_list_strings['sales_stage_dom'][$key]; + array_push($selected_datax, $key); + } + } + else { + $datax = $app_list_strings['sales_stage_dom']; + $selected_datax = array_keys($app_list_strings['sales_stage_dom']); + } + + $result = $db->query($query); + $row = $db->fetchByAssoc($result, -1, false); + + while($row != null){ + $temp_data[] = $row; + $row = $db->fetchByAssoc($result, -1, false); + } + + // reorder and set the array based on the order of selected_datax + foreach($selected_datax as $sales_stage){ + foreach($temp_data as $key => $value){ + if ($value['sales_stage'] == $sales_stage){ + $value['sales_stage'] = $app_list_strings['sales_stage_dom'][$value['sales_stage']]; + $value['key'] = $sales_stage; + $value['value'] = $value['sales_stage']; + $data[] = $value; + unset($temp_data[$key]); + } + } + } + return $data; + } + + /** + * @param $dataset array + * @return int + */ + private function getHorizBarTotal( + $dataset + ) + { + $total = 0; + foreach($dataset as $value){ + $total += $value; + } + + return $total; + } + + /** + * @param $dataset array + * @return array + */ + private function constructCEChartData( + $dataset + ) + { + $newData = array(); + foreach($dataset as $key=>$value){ + $newData[$value['sales_stage']] = $value['total']; + } + return $newData; + } + + /** + * @see DashletGenericChart::constructQuery() + */ + protected function constructQuery() + { + $query = "SELECT opportunities.sales_stage, + users.user_name, + opportunities.assigned_user_id, + count( * ) AS opp_count, + sum(amount_usdollar/1000) AS total + FROM users,opportunities "; + $query .= " WHERE opportunities.assigned_user_id IN ('{$GLOBALS['current_user']->id}') " . + " AND opportunities.date_closed >= ". db_convert("'".$this->mypbss_date_start."'",'datetime'). + " AND opportunities.date_closed <= ".db_convert("'".$this->mypbss_date_end."'",'datetime') . + " AND opportunities.assigned_user_id = users.id AND opportunities.deleted=0 "; + if ( count($this->mypbss_sales_stages) > 0 ) + $query .= " AND opportunities.sales_stage IN ('" . implode("','",$this->mypbss_sales_stages) . "') "; + $query .= " GROUP BY opportunities.sales_stage ,users.user_name,opportunities.assigned_user_id"; + + return $query; + } + + /** + * @see DashletGenericChart::constructGroupBy() + */ + protected function constructGroupBy() + { + $groupBy = array('sales_stage'); + + array_push($groupBy, 'user_name'); + return $groupBy; + } +} + +?> diff --git a/modules/Charts/Dashlets/OppByLeadOutcomeDashlet/OppByLeadOutcomeConfigure.tpl b/modules/Charts/Dashlets/OppByLeadOutcomeDashlet/OppByLeadOutcomeConfigure.tpl new file mode 100644 index 00000000..c3cf728a --- /dev/null +++ b/modules/Charts/Dashlets/OppByLeadOutcomeDashlet/OppByLeadOutcomeConfigure.tpl @@ -0,0 +1,79 @@ +{* + +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + + + +*} + + +
    +
    + + + + + + + + + + + + + + + + + + + + + +
    {$LBL_LEAD_SOURCES} + +
    {$LBL_USERS} + +
    + +
    +
    +
    \ No newline at end of file diff --git a/modules/Charts/Dashlets/OppByLeadOutcomeDashlet/OppByLeadOutcomeDashlet.data.php b/modules/Charts/Dashlets/OppByLeadOutcomeDashlet/OppByLeadOutcomeDashlet.data.php new file mode 100644 index 00000000..2ae7d316 --- /dev/null +++ b/modules/Charts/Dashlets/OppByLeadOutcomeDashlet/OppByLeadOutcomeDashlet.data.php @@ -0,0 +1,53 @@ + array( + 'name' => 'lsbo_lead_sources', + 'vname' => 'LBL_LEAD_SOURCES', + 'type' => 'enum', + ), + 'lsbo_ids' => array( + 'name' => 'lsbo_ids', + 'vname' => 'LBL_USERS', + 'type' => 'user_name', + ), + ); +?> diff --git a/modules/Charts/Dashlets/OppByLeadOutcomeDashlet/OppByLeadOutcomeDashlet.en_us.lang.php b/modules/Charts/Dashlets/OppByLeadOutcomeDashlet/OppByLeadOutcomeDashlet.en_us.lang.php new file mode 100644 index 00000000..82704a0a --- /dev/null +++ b/modules/Charts/Dashlets/OppByLeadOutcomeDashlet/OppByLeadOutcomeDashlet.en_us.lang.php @@ -0,0 +1,45 @@ + 'All Opportunities By Lead Source By Outcome', + 'LBL_DESCRIPTION' => 'Horizontal stacked chart of Opportunities By Lead Source By Outcome', + 'LBL_REFRESH' => 'Refresh Chart'); +?> \ No newline at end of file diff --git a/modules/Charts/Dashlets/OppByLeadOutcomeDashlet/OppByLeadOutcomeDashlet.meta.php b/modules/Charts/Dashlets/OppByLeadOutcomeDashlet/OppByLeadOutcomeDashlet.meta.php new file mode 100644 index 00000000..64ee24fd --- /dev/null +++ b/modules/Charts/Dashlets/OppByLeadOutcomeDashlet/OppByLeadOutcomeDashlet.meta.php @@ -0,0 +1,48 @@ + 'LBL_TITLE', + 'description' => 'LBL_TITLE', + 'icon' => 'icon_Charts_Horizontal_32.gif', + 'module' => 'Opportunities', + 'category' => 'Charts'); +?> diff --git a/modules/Charts/Dashlets/OppByLeadOutcomeDashlet/OppByLeadOutcomeDashlet.php b/modules/Charts/Dashlets/OppByLeadOutcomeDashlet/OppByLeadOutcomeDashlet.php new file mode 100644 index 00000000..ee07b5a2 --- /dev/null +++ b/modules/Charts/Dashlets/OppByLeadOutcomeDashlet/OppByLeadOutcomeDashlet.php @@ -0,0 +1,129 @@ +lsbo_lead_sources) && sizeof($this->lsbo_lead_sources) > 0) + foreach ($this->lsbo_lead_sources as $key) + $selected_datax[] = $key; + else + $selected_datax = array_keys($app_list_strings['lead_source_dom']); + + $this->_searchFields['lsbo_lead_sources']['options'] = array_filter($app_list_strings['lead_source_dom']); + $this->_searchFields['lsbo_lead_sources']['input_name0'] = $selected_datax; + + if (!isset($this->lsbo_ids) || count($this->lsbo_ids) == 0) + $this->_searchFields['lsbo_ids']['input_name0'] = array_keys(get_user_array(false)); + + return parent::displayOptions(); + } + + /** + * @see DashletGenericChart::display() + */ + public function display() + { + global $current_user, $sugar_config; + require("modules/Charts/chartdefs.php"); + $chartDef = $chartDefs['lead_source_by_outcome']; + + require_once('include/SugarCharts/SugarChartFactory.php'); + $sugarChart = SugarChartFactory::getInstance(); + $sugarChart->is_currency = true; + $currency_symbol = $sugar_config['default_currency_symbol']; + if ($current_user->getPreference('currency')){ + + $currency = new Currency(); + $currency->retrieve($current_user->getPreference('currency')); + $currency_symbol = $currency->symbol; + } + $subtitle = translate('LBL_OPP_SIZE', 'Charts') . " " . $currency_symbol . "1" . translate('LBL_OPP_THOUSANDS', 'Charts'); + $sugarChart->setProperties('', $subtitle, $chartDef['chartType']); + $sugarChart->base_url = $chartDef['base_url']; + $sugarChart->group_by = $chartDef['groupBy']; + $sugarChart->url_params = array(); + if ( count($this->lsbo_ids) > 0 ) + $sugarChart->url_params['assigned_user_id'] = array_values($this->lsbo_ids); + $sugarChart->getData($this->constuctQuery()); + $sugarChart->data_set = $sugarChart->sortData($sugarChart->data_set, 'lead_source', true, 'sales_stage', true, true); + $xmlFile = $sugarChart->getXMLFileName($this->id); + $sugarChart->saveXMLFile($xmlFile, $sugarChart->generateXML()); + + return $this->getTitle('
    ') . + '
    ' . $sugarChart->display($this->id, $xmlFile, '100%', '480', false) . '
    '. $this->processAutoRefresh(); + } + + /** + * @see DashletGenericChart::constructQuery() + */ + protected function constuctQuery() + { + $query = "SELECT lead_source,sales_stage,sum(amount_usdollar/1000) as total, ". + "count(*) as opp_count FROM opportunities "; + $query .= " WHERE opportunities.deleted=0 "; + if ( count($this->lsbo_ids) > 0 ) + $query .= "AND opportunities.assigned_user_id IN ('".implode("','",$this->lsbo_ids)."') "; + if ( count($this->lsbo_lead_sources) > 0 ) + $query .= "AND opportunities.lead_source IN ('".implode("','",$this->lsbo_lead_sources)."') "; + else + $query .= "AND opportunities.lead_source IN ('".implode("','",array_keys($GLOBALS['app_list_strings']['lead_source_dom']))."') "; + $query .= " GROUP BY sales_stage,lead_source ORDER BY lead_source,sales_stage"; + + return $query; + } +} \ No newline at end of file diff --git a/modules/Charts/Dashlets/OppByLeadSourceDashlet/OppByLeadSourceConfigure.tpl b/modules/Charts/Dashlets/OppByLeadSourceDashlet/OppByLeadSourceConfigure.tpl new file mode 100644 index 00000000..d64d93fe --- /dev/null +++ b/modules/Charts/Dashlets/OppByLeadSourceDashlet/OppByLeadSourceConfigure.tpl @@ -0,0 +1,79 @@ +{* + +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + + + +*} + + +
    +
    + + + + + + + + + + + + + + + + + + + + + +
    {$LBL_LEAD_SOURCES} + +
    {$LBL_USERS} + +
    + +
    +
    +
    \ No newline at end of file diff --git a/modules/Charts/Dashlets/OppByLeadSourceDashlet/OppByLeadSourceDashlet.data.php b/modules/Charts/Dashlets/OppByLeadSourceDashlet/OppByLeadSourceDashlet.data.php new file mode 100644 index 00000000..fbcda4d0 --- /dev/null +++ b/modules/Charts/Dashlets/OppByLeadSourceDashlet/OppByLeadSourceDashlet.data.php @@ -0,0 +1,53 @@ + array( + 'name' => 'pbls_lead_sources', + 'vname' => 'LBL_LEAD_SOURCES', + 'type' => 'enum', + ), + 'pbls_ids' => array( + 'name' => 'pbls_ids', + 'vname' => 'LBL_USERS', + 'type' => 'user_name', + ), + ); +?> diff --git a/modules/Charts/Dashlets/OppByLeadSourceDashlet/OppByLeadSourceDashlet.en_us.lang.php b/modules/Charts/Dashlets/OppByLeadSourceDashlet/OppByLeadSourceDashlet.en_us.lang.php new file mode 100644 index 00000000..80e0c586 --- /dev/null +++ b/modules/Charts/Dashlets/OppByLeadSourceDashlet/OppByLeadSourceDashlet.en_us.lang.php @@ -0,0 +1,45 @@ + 'All Opportunities by Lead Source', + 'LBL_DESCRIPTION' => 'Pie Chart of Opportunities by Lead Source', + 'LBL_REFRESH' => 'Refresh Chart'); +?> \ No newline at end of file diff --git a/modules/Charts/Dashlets/OppByLeadSourceDashlet/OppByLeadSourceDashlet.meta.php b/modules/Charts/Dashlets/OppByLeadSourceDashlet/OppByLeadSourceDashlet.meta.php new file mode 100644 index 00000000..85acd77a --- /dev/null +++ b/modules/Charts/Dashlets/OppByLeadSourceDashlet/OppByLeadSourceDashlet.meta.php @@ -0,0 +1,48 @@ + 'LBL_TITLE', + 'description' => 'LBL_TITLE', + 'icon' => 'icon_Charts_Pie_32.gif', + 'module' => 'Opportunities', + 'category' => 'Charts'); +?> diff --git a/modules/Charts/Dashlets/OppByLeadSourceDashlet/OppByLeadSourceDashlet.php b/modules/Charts/Dashlets/OppByLeadSourceDashlet/OppByLeadSourceDashlet.php new file mode 100644 index 00000000..8af9578e --- /dev/null +++ b/modules/Charts/Dashlets/OppByLeadSourceDashlet/OppByLeadSourceDashlet.php @@ -0,0 +1,130 @@ +pbls_lead_sources) && sizeof($this->pbls_lead_sources) > 0) + foreach ($this->pbls_lead_sources as $key) + $selected_datax[] = $key; + else + $selected_datax = array_keys($app_list_strings['lead_source_dom']); + + $this->_searchFields['pbls_lead_sources']['options'] = array_filter($app_list_strings['lead_source_dom']); + $this->_searchFields['pbls_lead_sources']['input_name0'] = $selected_datax; + + if (!isset($this->pbls_ids) || count($this->pbls_ids) == 0) + $this->_searchFields['pbls_ids']['input_name0'] = array_keys(get_user_array(false)); + + return parent::displayOptions(); + } + + /** + * @see DashletGenericChart::display() + */ + public function display() + { + global $current_user, $sugar_config; + require("modules/Charts/chartdefs.php"); + $chartDef = $chartDefs['pipeline_by_lead_source']; + + require_once('include/SugarCharts/SugarChartFactory.php'); + $sugarChart = SugarChartFactory::getInstance(); + $sugarChart->is_currency = true; + $currency_symbol = $sugar_config['default_currency_symbol']; + if ($current_user->getPreference('currency')){ + + $currency = new Currency(); + $currency->retrieve($current_user->getPreference('currency')); + $currency_symbol = $currency->symbol; + } + $subtitle = translate('LBL_OPP_SIZE', 'Charts') . " " . $currency_symbol . "1" . translate('LBL_OPP_THOUSANDS', 'Charts'); + $sugarChart->setProperties('', $subtitle, $chartDef['chartType']); + $sugarChart->base_url = $chartDef['base_url']; + $sugarChart->group_by = $chartDef['groupBy']; + $sugarChart->url_params = array(); + if ( count($this->pbls_ids) > 0 ) + $sugarChart->url_params['assigned_user_id'] = array_values($this->pbls_ids); + $sugarChart->getData($this->constructQuery()); + $sugarChart->data_set = $sugarChart->sortData($sugarChart->data_set, 'lead_source', true); + $xmlFile = $sugarChart->getXMLFileName($this->id); + $sugarChart->saveXMLFile($xmlFile, $sugarChart->generateXML()); + + return $this->getTitle('
    ') . + '
    ' . $sugarChart->display($this->id, $xmlFile, '100%', '480', false) . '
    '. $this->processAutoRefresh(); + } + + /** + * @see DashletGenericChart::constructQuery() + */ + protected function constructQuery() + { + $query = "SELECT lead_source,sum(amount_usdollar/1000) as total,count(*) as opp_count ". + "FROM opportunities "; + $query .= "WHERE opportunities.deleted=0 "; + if ( count($this->pbls_ids) > 0 ) + $query .= "AND opportunities.assigned_user_id IN ('".implode("','",$this->pbls_ids)."') "; + if ( count($this->pbls_lead_sources) > 0 ) + $query .= "AND opportunities.lead_source IN ('".implode("','",$this->pbls_lead_sources)."') "; + else + $query .= "AND opportunities.lead_source IN ('".implode("','",array_keys($GLOBALS['app_list_strings']['lead_source_dom']))."') "; + $query .= "GROUP BY lead_source ORDER BY total DESC"; + + return $query; + } +} \ No newline at end of file diff --git a/modules/Charts/Dashlets/OutcomeByMonthDashlet/OutcomeByMonthConfigure.tpl b/modules/Charts/Dashlets/OutcomeByMonthDashlet/OutcomeByMonthConfigure.tpl new file mode 100644 index 00000000..7193e61c --- /dev/null +++ b/modules/Charts/Dashlets/OutcomeByMonthDashlet/OutcomeByMonthConfigure.tpl @@ -0,0 +1,100 @@ +{* + +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + + + +*} + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    {$LBL_TITLE}
    + +
    {$LBL_DATE_START}
    {$user_date_format}
    + + {$LBL_ENTER_DATE} +
    {$LBL_DATE_END}
    {$user_date_format}
    + + {$LBL_ENTER_DATE} +
    {$LBL_USERS} + +
    + +
    +
    +{literal} + +
    \ No newline at end of file diff --git a/modules/Charts/Dashlets/OutcomeByMonthDashlet/OutcomeByMonthDashlet.data.php b/modules/Charts/Dashlets/OutcomeByMonthDashlet/OutcomeByMonthDashlet.data.php new file mode 100644 index 00000000..56192623 --- /dev/null +++ b/modules/Charts/Dashlets/OutcomeByMonthDashlet/OutcomeByMonthDashlet.data.php @@ -0,0 +1,58 @@ + array( + 'name' => 'obm_date_start', + 'vname' => 'LBL_DATE_START', + 'type' => 'datepicker', + ), + 'obm_date_end' => array( + 'name' => 'obm_date_end', + 'vname' => 'LBL_DATE_END', + 'type' => 'datepicker', + ), + 'obm_ids' => array( + 'name' => 'obm_ids', + 'vname' => 'LBL_USERS', + 'type' => 'user_name', + ), + ); +?> diff --git a/modules/Charts/Dashlets/OutcomeByMonthDashlet/OutcomeByMonthDashlet.en_us.lang.php b/modules/Charts/Dashlets/OutcomeByMonthDashlet/OutcomeByMonthDashlet.en_us.lang.php new file mode 100644 index 00000000..e2b809c8 --- /dev/null +++ b/modules/Charts/Dashlets/OutcomeByMonthDashlet/OutcomeByMonthDashlet.en_us.lang.php @@ -0,0 +1,45 @@ + 'Outcome by Month', + 'LBL_DESCRIPTION' => 'Chart of the Monthly Outcomes', + 'LBL_REFRESH' => 'Refresh Chart'); +?> \ No newline at end of file diff --git a/modules/Charts/Dashlets/OutcomeByMonthDashlet/OutcomeByMonthDashlet.meta.php b/modules/Charts/Dashlets/OutcomeByMonthDashlet/OutcomeByMonthDashlet.meta.php new file mode 100644 index 00000000..21c1b252 --- /dev/null +++ b/modules/Charts/Dashlets/OutcomeByMonthDashlet/OutcomeByMonthDashlet.meta.php @@ -0,0 +1,48 @@ + 'LBL_TITLE', + 'description' => 'LBL_TITLE', + 'icon' => 'icon_Charts_Vertical_32.gif', + 'module' => 'Opportunities', + 'category' => 'Charts'); +?> diff --git a/modules/Charts/Dashlets/OutcomeByMonthDashlet/OutcomeByMonthDashlet.php b/modules/Charts/Dashlets/OutcomeByMonthDashlet/OutcomeByMonthDashlet.php new file mode 100644 index 00000000..8283c7b3 --- /dev/null +++ b/modules/Charts/Dashlets/OutcomeByMonthDashlet/OutcomeByMonthDashlet.php @@ -0,0 +1,138 @@ +nowDbDate(); + + if(empty($options['obm_date_end'])) + $options['obm_date_end'] = $timedate->asDbDate($timedate->getNow()->modify("+6 months")); + + parent::__construct($id,$options); + } + + /** + * @see DashletGenericChart::displayOptions() + */ + public function displayOptions() + { + if (!isset($this->obm_ids) || count($this->obm_ids) == 0) + $this->_searchFields['obm_ids']['input_name0'] = array_keys(get_user_array(false)); + + return parent::displayOptions(); + } + + /** + * @see DashletGenericChart::display() + */ + public function display() + { + $currency_symbol = $GLOBALS['sugar_config']['default_currency_symbol']; + if ($GLOBALS['current_user']->getPreference('currency')){ + + $currency = new Currency(); + $currency->retrieve($GLOBALS['current_user']->getPreference('currency')); + $currency_symbol = $currency->symbol; + } + + require("modules/Charts/chartdefs.php"); + $chartDef = $chartDefs['outcome_by_month']; + + require_once('include/SugarCharts/SugarChartFactory.php'); + $sugarChart = SugarChartFactory::getInstance(); + $sugarChart->setProperties('', + translate('LBL_OPP_SIZE', 'Charts') . ' ' . $currency_symbol . '1' .translate('LBL_OPP_THOUSANDS', 'Charts'), + $chartDef['chartType']); + $sugarChart->base_url = $chartDef['base_url']; + $sugarChart->group_by = $chartDef['groupBy']; + $sugarChart->url_params = array(); + $sugarChart->getData($this->constructQuery()); + $sugarChart->is_currency = true; + $sugarChart->data_set = $sugarChart->sortData($sugarChart->data_set, 'm', false, 'sales_stage', true, true); + $xmlFile = $sugarChart->getXMLFileName($this->id); + $sugarChart->saveXMLFile($xmlFile, $sugarChart->generateXML()); + + return $this->getTitle('
    ') . + '
    ' . $sugarChart->display($this->id, $xmlFile, '100%', '480', false) . '
    '. $this->processAutoRefresh(); + } + + /** + * @see DashletGenericChart::constructQuery() + */ + protected function constructQuery() + { + $query = "SELECT sales_stage,". + db_convert('opportunities.date_closed','date_format',array("'%Y-%m'"),array("'YYYY-MM'"))." as m, ". + "sum(amount_usdollar/1000) as total, count(*) as opp_count FROM opportunities "; + $query .= " WHERE opportunities.date_closed >= ".db_convert("'".$this->obm_date_start."'",'datetime') . + " AND opportunities.date_closed <= ".db_convert("'".$this->obm_date_end."'",'datetime') . + " AND opportunities.deleted=0"; + if (count($this->obm_ids) > 0) + $query .= " AND opportunities.assigned_user_id IN ('" . implode("','",$this->obm_ids) . "')"; + $query .= " GROUP BY sales_stage,". + db_convert('opportunities.date_closed','date_format',array("'%Y-%m'"),array("'YYYY-MM'")) . + " ORDER BY m"; + + return $query; + } +} \ No newline at end of file diff --git a/modules/Charts/Dashlets/PipelineBySalesStageDashlet/PipelineBySalesStageConfigure.tpl b/modules/Charts/Dashlets/PipelineBySalesStageDashlet/PipelineBySalesStageConfigure.tpl new file mode 100644 index 00000000..d9b9224a --- /dev/null +++ b/modules/Charts/Dashlets/PipelineBySalesStageDashlet/PipelineBySalesStageConfigure.tpl @@ -0,0 +1,100 @@ +{* + +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + + + +*} + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    {$LBL_TITLE}
    + +
    {$LBL_DATE_START}
    {$user_date_format}
    + + {$LBL_ENTER_DATE} +
    {$LBL_DATE_END}
    {$user_date_format}
    + + {$LBL_ENTER_DATE} +
    {$LBL_SALES_STAGES} +
    + +
    +
    +{literal} + +
    \ No newline at end of file diff --git a/modules/Charts/Dashlets/PipelineBySalesStageDashlet/PipelineBySalesStageDashlet.data.php b/modules/Charts/Dashlets/PipelineBySalesStageDashlet/PipelineBySalesStageDashlet.data.php new file mode 100644 index 00000000..8c8b9029 --- /dev/null +++ b/modules/Charts/Dashlets/PipelineBySalesStageDashlet/PipelineBySalesStageDashlet.data.php @@ -0,0 +1,58 @@ + array( + 'name' => 'pbss_date_start', + 'vname' => 'LBL_CLOSE_DATE_START', + 'type' => 'datepicker', + ), + 'pbss_date_end' => array( + 'name' => 'pbss_date_end', + 'vname' => 'LBL_CLOSE_DATE_END', + 'type' => 'datepicker', + ), + 'pbss_sales_stages' => array( + 'name' => 'pbss_sales_stages', + 'vname' => 'LBL_SALES_STAGES', + 'type' => 'enum', + ), + ); +?> diff --git a/modules/Charts/Dashlets/PipelineBySalesStageDashlet/PipelineBySalesStageDashlet.en_us.lang.php b/modules/Charts/Dashlets/PipelineBySalesStageDashlet/PipelineBySalesStageDashlet.en_us.lang.php new file mode 100644 index 00000000..d21b5cf6 --- /dev/null +++ b/modules/Charts/Dashlets/PipelineBySalesStageDashlet/PipelineBySalesStageDashlet.en_us.lang.php @@ -0,0 +1,45 @@ + 'Pipeline By Sales Stage', + 'LBL_DESCRIPTION' => 'Vertical Bar Chart of Sales Stage Pipeline', + 'LBL_REFRESH' => 'Refresh Chart'); +?> \ No newline at end of file diff --git a/modules/Charts/Dashlets/PipelineBySalesStageDashlet/PipelineBySalesStageDashlet.meta.php b/modules/Charts/Dashlets/PipelineBySalesStageDashlet/PipelineBySalesStageDashlet.meta.php new file mode 100644 index 00000000..ad2bf4b1 --- /dev/null +++ b/modules/Charts/Dashlets/PipelineBySalesStageDashlet/PipelineBySalesStageDashlet.meta.php @@ -0,0 +1,48 @@ + 'LBL_TITLE', + 'description' => 'LBL_TITLE', + 'module' => 'Opportunities', + 'icon' => 'icon_Charts_Funnel_32.gif', + 'category' => 'Charts'); +?> diff --git a/modules/Charts/Dashlets/PipelineBySalesStageDashlet/PipelineBySalesStageDashlet.php b/modules/Charts/Dashlets/PipelineBySalesStageDashlet/PipelineBySalesStageDashlet.php new file mode 100644 index 00000000..5524020c --- /dev/null +++ b/modules/Charts/Dashlets/PipelineBySalesStageDashlet/PipelineBySalesStageDashlet.php @@ -0,0 +1,217 @@ +get_db_date_time_format(), time()); + + if(empty($options['pbss_date_end'])) + $options['pbss_date_end'] = date($timedate->get_db_date_time_format(), strtotime("+6 months", time())); + + if(empty($options['title'])) + $options['title'] = translate('LBL_PIPELINE_FORM_TITLE', 'Home'); + + parent::__construct($id,$options); + } + + /** + * @see DashletGenericChart::displayOptions() + */ + public function displayOptions() + { + global $app_list_strings; + + if (!empty($this->pbss_sales_stages) && count($this->pbss_sales_stages) > 0) + foreach ($this->pbss_sales_stages as $key) + $selected_datax[] = $key; + else + $selected_datax = array_keys($app_list_strings['sales_stage_dom']); + + $this->_searchFields['pbss_sales_stages']['options'] = $app_list_strings['sales_stage_dom']; + $this->_searchFields['pbss_sales_stages']['input_name0'] = $selected_datax; + + return parent::displayOptions(); + } + + /** + * @see DashletGenericChart::display() + */ + public function display() + { + global $current_user, $sugar_config; + + require_once('include/SugarCharts/SugarChartFactory.php'); + $sugarChart = SugarChartFactory::getInstance(); + $sugarChart->base_url = array( + 'module' => 'Opportunities', + 'action' => 'index', + 'query' => 'true', + 'searchFormTab' => 'advanced_search', + ); + $sugarChart->url_params = array( ); + $sugarChart->group_by = $this->constructGroupBy(); + $sugarChart->setData($this->getChartData($this->constructQuery())); + $sugarChart->is_currency = true; + $sugarChart->thousands_symbol = translate('LBL_OPP_THOUSANDS', 'Charts'); + + $currency_symbol = $sugar_config['default_currency_symbol']; + if ($current_user->getPreference('currency')){ + + $currency = new Currency(); + $currency->retrieve($current_user->getPreference('currency')); + $currency_symbol = $currency->symbol; + } + $subtitle = translate('LBL_OPP_SIZE', 'Charts') . " " . $currency_symbol . "1" . translate('LBL_OPP_THOUSANDS', 'Charts'); + + $pipeline_total_string = translate('LBL_TOTAL_PIPELINE', 'Charts') . $sugarChart->currency_symbol . format_number($sugarChart->getTotal(), 0, 0, array('convert'=>true)) . $sugarChart->thousands_symbol; + $sugarChart->setProperties($pipeline_total_string, $subtitle, 'horizontal group by chart'); + + $xmlFile = $sugarChart->getXMLFileName($this->id); + $sugarChart->saveXMLFile($xmlFile, $sugarChart->generateXML()); + + return $this->getTitle('') . '
    ' . $sugarChart->display($this->id, $xmlFile, '100%', '480', false) . '
    '. $this->processAutoRefresh(); + } + + /** + * awu: Bug 16794 - this function is a hack to get the correct sales stage order until + * i can clean it up later + * + * @param $query string + * @return array + */ + private function getChartData( + $query + ) + { + global $app_list_strings, $db; + + $data = array(); + $temp_data = array(); + $selected_datax = array(); + + $user_sales_stage = $this->pbss_sales_stages; + $tempx = $user_sales_stage; + + //set $datax using selected sales stage keys + if (count($tempx) > 0) { + foreach ($tempx as $key) { + $datax[$key] = $app_list_strings['sales_stage_dom'][$key]; + $selected_datax[] = $key; + } + } + else { + $datax = $app_list_strings['sales_stage_dom']; + $selected_datax = array_keys($app_list_strings['sales_stage_dom']); + } + + $result = $db->query($query); + while($row = $db->fetchByAssoc($result, -1, false)) + $temp_data[] = $row; + + // reorder and set the array based on the order of selected_datax + foreach($selected_datax as $sales_stage){ + foreach($temp_data as $key => $value){ + if ($value['sales_stage'] == $sales_stage){ + $value['sales_stage'] = $app_list_strings['sales_stage_dom'][$value['sales_stage']]; + $value['key'] = $sales_stage; + $value['value'] = $value['sales_stage']; + $data[] = $value; + unset($temp_data[$key]); + } + } + } + return $data; + } + + /** + * @see DashletGenericChart::constructQuery() + */ + protected function constructQuery() + { + $query = " SELECT opportunities.sales_stage, + users.user_name, + opportunities.assigned_user_id, + count( * ) AS opp_count, + sum(amount_usdollar/1000) AS total + FROM users,opportunities "; + $query .= " WHERE opportunities.date_closed >= ". db_convert("'".$this->pbss_date_start."'",'datetime'). + " AND opportunities.date_closed <= ".db_convert("'".$this->pbss_date_end."'",'datetime') . + " AND opportunities.assigned_user_id = users.id AND opportunities.deleted=0 "; + if ( count($this->pbss_sales_stages) > 0 ) + $query .= " AND opportunities.sales_stage IN ('" . implode("','",$this->pbss_sales_stages) . "') "; + $query .= " GROUP BY opportunities.sales_stage ,users.user_name,opportunities.assigned_user_id"; + + return $query; + } + + /** + * @see DashletGenericChart::constructGroupBy() + */ + protected function constructGroupBy() + { + return array( + 'sales_stage', + 'user_name', + ); + } +} diff --git a/modules/Charts/Dashlets/PredefinedChartDashletScript.tpl b/modules/Charts/Dashlets/PredefinedChartDashletScript.tpl new file mode 100644 index 00000000..fb30f45a --- /dev/null +++ b/modules/Charts/Dashlets/PredefinedChartDashletScript.tpl @@ -0,0 +1,45 @@ +{* + +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + + + +*} + + diff --git a/modules/Charts/DynamicAction.php b/modules/Charts/DynamicAction.php new file mode 100644 index 00000000..ab0064d2 --- /dev/null +++ b/modules/Charts/DynamicAction.php @@ -0,0 +1,51 @@ +pipelineBySalesStageQuery(); + case 'lead_source_by_outcome': + return $this->leadSourceByOutcomeQuery($params); + case 'outcome_by_month': + return $this->outcomeByMonthQuery(); + case 'pipeline_by_lead_source': + return $this->pipelineByLeadSourceQuery($params); + case 'my_modules_used_last_30_days': + return $this->myModuleUsageLast30Days(); + default: + return $this->customChartQuery($chart); + } + return; + } + + function pipelineBySalesStageQuery(){ + + + global $current_user; + global $timedate; + global $app_list_strings; + + //get the dates to display + $user_date_start = $current_user->getPreference('pbss_date_start'); + + if (!empty($user_date_start) && !isset($_REQUEST['pbss_date_start'])) { + $date_start = $timedate->to_display_date($user_date_start, false); + $GLOBALS['log']->debug("USER PREFERENCES['pbss_date_start'] is:"); + $GLOBALS['log']->debug($user_date_start); + } + elseif (isset($_REQUEST['pbss_date_start']) && $_REQUEST['pbss_date_start'] != '') { + $date_start = $_REQUEST['pbss_date_start']; + $ds = $timedate->to_db_date($date_start, false); + $current_user->setPreference('pbss_date_start', $ds); + $GLOBALS['log']->debug("_REQUEST['pbss_date_start'] is:"); + $GLOBALS['log']->debug($_REQUEST['pbss_date_start']); + $GLOBALS['log']->debug("USER PREFERENCES['pbss_date_start'] is:"); + $GLOBALS['log']->debug($current_user->getPreference('pbss_date_start')); + } + else { + $date_start = $timedate->nowDate(); + } + + $user_date_end = $current_user->getPreference('pbss_date_end'); + if (!empty($user_date_end) && !isset($_REQUEST['pbss_date_end'])) { + $date_end = $timedate->to_display_date($user_date_end, false); + $GLOBALS['log']->debug("USER PREFERENCES['pbss_date_end'] is:"); + $GLOBALS['log']->debug($user_date_end); + } + elseif (isset($_REQUEST['pbss_date_end']) && $_REQUEST['pbss_date_end'] != '') { + $date_end = $_REQUEST['pbss_date_end']; + $de = $timedate->to_db_date($date_end, false); + $current_user->setPreference('pbss_date_end', $de); + $GLOBALS['log']->debug("_REQUEST['pbss_date_end'] is:"); + $GLOBALS['log']->debug($_REQUEST['pbss_date_end']); + $GLOBALS['log']->debug("USER PREFERENCES['pbss_date_end'] is:"); + $GLOBALS['log']->debug( $current_user->getPreference('pbss_date_end')); + } + else { + $date_end = $timedate->asUserDate($timedate->fromString("2010-01-01")); + $GLOBALS['log']->debug("USER PREFERENCES['pbss_date_end'] not found. Using: ".$date_end); + } + + $tempx = array(); + $datax = array(); + $datax_selected= array(); + $user_tempx = $current_user->getPreference('pbss_sales_stages'); + //get list of sales stage keys to display + if (!empty($user_tempx) && count($user_tempx) > 0 && !isset($_REQUEST['pbss_sales_stages'])) { + $tempx = $user_tempx ; + $GLOBALS['log']->debug("USER PREFERENCES['pbss_sales_stages'] is:"); + $GLOBALS['log']->debug($user_tempx ); + } + elseif (isset($_REQUEST['pbss_sales_stages']) && count($_REQUEST['pbss_sales_stages']) > 0) { + $tempx = $_REQUEST['pbss_sales_stages']; + $current_user->setPreference('pbss_sales_stages', $_REQUEST['pbss_sales_stages']); + $GLOBALS['log']->debug("_REQUEST['pbss_sales_stages'] is:"); + $GLOBALS['log']->debug($_REQUEST['pbss_sales_stages']); + $GLOBALS['log']->debug("USER PREFERENCES['pbss_sales_stages'] is:"); + $GLOBALS['log']->debug($current_user->getPreference('pbss_sales_stages')); + } + + //set $datax using selected sales stage keys + if (count($tempx) > 0) { + foreach ($tempx as $key) { + $datax[$key] = $app_list_strings['sales_stage_dom'][$key]; + array_push($datax_selected,$key); + } + } + else { + $datax = $app_list_strings['sales_stage_dom']; + $datax_selected = array_keys($app_list_strings['sales_stage_dom']); + } + $GLOBALS['log']->debug("datax is:"); + $GLOBALS['log']->debug($datax); + + $ids = array(); + $new_ids = array(); + $user_ids = $current_user->getPreference('pbss_ids'); + //get list of user ids for which to display data + if (!empty($user_ids) && count($user_ids) != 0 && !isset($_REQUEST['pbss_ids'])) { + $ids = $user_ids; + + $GLOBALS['log']->debug("USER PREFERENCES['pbss_ids'] is:"); + $GLOBALS['log']->debug($user_ids); + } + elseif (isset($_REQUEST['pbss_ids']) && count($_REQUEST['pbss_ids']) > 0) { + $ids = $_REQUEST['pbss_ids']; + $current_user->setPreference('pbss_ids', $_REQUEST['pbss_ids']); + $GLOBALS['log']->debug("_REQUEST['pbss_ids'] is:"); + $GLOBALS['log']->debug($_REQUEST['pbss_ids']); + $GLOBALS['log']->debug("USER PREFERENCES['pbss_ids'] is:"); + $GLOBALS['log']->debug($current_user->getPreference('pbss_ids')); + } + else { + $ids = get_user_array(false); + $ids = array_keys($ids); + + } + + $user_id = $ids; + $opp = new Opportunity; + $where=""; + //build the where clause for the query that matches $user + $count = count($user_id); + $id = array(); + $user_list = get_user_array(false); + foreach ($user_id as $key) { + $new_ids[$key] = $user_list[$key]; + } + if ($count>0) { + foreach ($new_ids as $the_id=>$the_name) { + $id[] = "'".$the_id."'"; + } + $ids = join(",",$id); + $where .= "opportunities.assigned_user_id IN ($ids) "; + + } + //build the where clause for the query that matches $datax + $count = count($datax); + $dataxArr = array(); + if ($count>0) { + + foreach ($datax as $key=>$value) { + $dataxArr[] = "'".$key."'"; + } + $dataxArr = join(",",$dataxArr); + $where .= "AND opportunities.sales_stage IN ($dataxArr) "; + } + + $date_start = $timedate->swap_formats($date_start, $timedate->get_date_format(), $timedate->dbDayFormat); + $date_end = $timedate->swap_formats($date_end, $timedate->get_date_format(), $timedate->dbDayFormat); + //build the where clause for the query that matches $date_start and $date_end + $where .= " AND opportunities.date_closed >= ". db_convert("'".$date_start."'",'date'). " + AND opportunities.date_closed <= ".db_convert("'".$date_end."'",'date') ; + $where .= " AND opportunities.assigned_user_id = users.id AND opportunities.deleted=0 "; + + //Now do the db queries + //query for opportunity data that matches $datax and $user + $query = " SELECT opportunities.sales_stage, + users.user_name, + opportunities.assigned_user_id, + count( * ) AS opp_count, + sum(amount_usdollar/1000) AS total + FROM users,opportunities "; + $query .= "WHERE " .$where; + $query .= " GROUP BY opportunities.sales_stage"; + + $additional_params = array( 'date_start' => $date_start, 'date_closed' => $date_end, ); + + $this->params = $additional_params; + + return $query; + } + + function leadSourceByOutcomeQuery($filters){ + + + global $current_user; + global $app_list_strings; + + $tempx = array(); + $datax = array(); + $selected_datax = array(); + //get list of sales stage keys to display + + $tempx = $filters['lsbo_lead_sources']; + if (!empty($lsbo_lead_sources) && count($lsbo_lead_sources) > 0 && !isset($_REQUEST['lsbo_lead_sources'])) { + $GLOBALS['log']->fatal("user->getPreference('lsbo_lead_sources') is:"); + $GLOBALS['log']->fatal($tempx); + } + elseif (isset($_REQUEST['lsbo_lead_sources']) && count($_REQUEST['lsbo_lead_sources']) > 0) { + $tempx = $_REQUEST['lsbo_lead_sources']; + $current_user->setPreference('lsbo_lead_sources', $_REQUEST['lsbo_lead_sources']); + $GLOBALS['log']->fatal("_REQUEST['lsbo_lead_sources'] is:"); + $GLOBALS['log']->fatal($_REQUEST['lsbo_lead_sources']); + $GLOBALS['log']->fatal("user->getPreference('lsbo_lead_sources') is:"); + $GLOBALS['log']->fatal($current_user->getPreference('lsbo_lead_sources')); + } + //set $datax using selected sales stage keys + if (!empty($tempx) && sizeof($tempx) > 0) { + foreach ($tempx as $key) { + $datax[$key] = $app_list_strings['lead_source_dom'][$key]; + array_push($selected_datax,$key); + } + } + else { + $datax = $app_list_strings['lead_source_dom']; + $selected_datax = array_keys($app_list_strings['lead_source_dom']); + } + + $datay = $datax; + + $ids = $filters['lsbo_ids']; + //get list of user ids for which to display data + if (!empty($ids) && count($ids) != 0 && !isset($_REQUEST['lsbo_ids'])) { + $GLOBALS['log']->debug("_SESSION['lsbo_ids'] is:"); + $GLOBALS['log']->debug($ids); + } + elseif (isset($_REQUEST['lsbo_ids']) && count($_REQUEST['lsbo_ids']) > 0) { + $ids = $_REQUEST['lsbo_ids']; + $current_user->setPreference('lsbo_ids', $_REQUEST['lsbo_ids']); + $GLOBALS['log']->debug("_REQUEST['lsbo_ids'] is:"); + $GLOBALS['log']->debug($_REQUEST['lsbo_ids']); + $GLOBALS['log']->debug("user->getPreference('lsbo_ids') is:"); + $GLOBALS['log']->debug($current_user->getPreference('lsbo_ids')); + } + else { + $ids = get_user_array(false); + $ids = array_keys($ids); + } + + $user_id = $ids; + + $opp = new Opportunity(); + $where=""; + //build the where clause for the query that matches $user + $count = count($user_id); + $id = array(); + if ($count>0) { + foreach ($user_id as $the_id) { + $id[] = "'".$the_id."'"; + } + $ids = join(",",$id); + $where .= "opportunities.assigned_user_id IN ($ids) "; + + } + + //build the where clause for the query that matches $datay + $count = count($datay); + $datayArr = array(); + if ($count>0) { + + foreach ($datay as $key=>$value) { + $datayArr[] = "'".$key."'"; + } + $datayArr = join(",",$datayArr); + $where .= "AND opportunities.lead_source IN ($datayArr) "; + } + $query = "SELECT lead_source,sales_stage,sum(amount_usdollar/1000) as total,count(*) as opp_count FROM opportunities "; + $query .= "WHERE " .$where." AND opportunities.deleted=0 "; + $query .= " GROUP BY sales_stage,lead_source ORDER BY lead_source,sales_stage"; + + return $query; + } + + function outcomeByMonthQuery(){ + + + global $current_user; + global $timedate; + + $user_date_start = $current_user->getPreference('obm_date_start'); + if (!empty($user_date_start) && !isset($_REQUEST['obm_date_start'])) { + $date_start =$user_date_start; + $GLOBALS['log']->debug("USER PREFERENCES['obm_date_start'] is:"); + $GLOBALS['log']->debug($user_date_start); + } + elseif (isset($_REQUEST['obm_year']) && $_REQUEST['obm_year'] != '') { + $date_start = $_REQUEST['obm_year'].'-01-01'; + $current_user->setPreference('obm_date_start', $date_start); + $GLOBALS['log']->debug("_REQUEST['obm_date_start'] is:"); + $GLOBALS['log']->debug($_REQUEST['obm_date_start']); + $GLOBALS['log']->debug("_SESSION['obm_date_start'] is:"); + $GLOBALS['log']->debug($current_user->getPreference('obm_date_start')); + } + else { + $date_start = date('Y').'-01-01'; + } + $user_date_end = $current_user->getPreference('obm_date_end'); + if (!empty($user_date_end) && !isset($_REQUEST['obm_date_end'])) { + $date_end =$user_date_end; + $GLOBALS['log']->debug("USER PREFERENCES['obm_date_end'] is:"); + $GLOBALS['log']->debug($date_end); + } + elseif (isset($_REQUEST['obm_year']) && $_REQUEST['obm_year'] != '') { + $date_end = $_REQUEST['obm_year'].'-12-31'; + $current_user->setPreference('obm_date_end', $date_end ); + $GLOBALS['log']->debug("_REQUEST['obm_date_end'] is:"); + $GLOBALS['log']->debug($_REQUEST['obm_date_end']); + $GLOBALS['log']->debug("USER PREFERENCES['obm_date_end'] is:"); + $GLOBALS['log']->debug($current_user->getPreference('obm_date_end')); + } + else { + $date_end = date('Y').'-12-31'; + } + + $ids = array(); + //get list of user ids for which to display data + $user_ids = $current_user->getPreference('obm_ids'); + if (!empty($user_ids) && count($user_ids) != 0 && !isset($_REQUEST['obm_ids'])) { + $ids = $user_ids; + $GLOBALS['log']->debug("USER PREFERENCES['obm_ids'] is:"); + $GLOBALS['log']->debug($user_ids); + } + elseif (isset($_REQUEST['obm_ids']) && count($_REQUEST['obm_ids']) > 0) { + $ids = $_REQUEST['obm_ids']; + $current_user->setPreference('obm_ids', $_REQUEST['obm_ids']); + $GLOBALS['log']->debug("_REQUEST['obm_ids'] is:"); + $GLOBALS['log']->debug($_REQUEST['obm_ids']); + $GLOBALS['log']->debug("USER PREFRENCES['obm_ids'] is:"); + $GLOBALS['log']->debug($current_user->getPreference('obm_ids')); + } + else { + $ids = get_user_array(false); + $ids = array_keys($ids); + } + + $user_id = $ids; + + $where = ""; + //build the where clause for the query that matches $user + $count = count($user_id); + $id = array(); + if ($count>0) { + foreach ($user_id as $the_id) { + $id[] = "'".$the_id."'"; + } + $ids = join(",",$id); + $where .= "opportunities.assigned_user_id IN ($ids) "; + + } + + // cn: adding user-pref date handling + $dateStartDisplay = $timedate->asUserDate($timedate->fromString($date_start)); + $dateEndDisplay = $timedate->asUserDate($timedate->fromString($date_end)); + + $opp = new Opportunity(); + //build the where clause for the query that matches $date_start and $date_end + $where .= "AND opportunities.date_closed >= ".db_convert("'".$date_start."'",'date')." AND opportunities.date_closed <= ".db_convert("'".$date_end."'",'date')." AND opportunities.deleted=0"; + $query = "SELECT sales_stage,".db_convert('opportunities.date_closed','date_format',array("'%Y-%m'"),array("'YYYY-MM'"))." as m, sum(amount_usdollar/1000) as total, count(*) as opp_count FROM opportunities "; + $query .= "WHERE ".$where; + $query .= " GROUP BY sales_stage,".db_convert('opportunities.date_closed','date_format',array("'%Y-%m'"),array("'YYYY-MM'"))."ORDER BY m"; + return $query; + } + + function pipelineByLeadSourceQuery($filters){ + + + global $current_user; + global $app_list_strings; + + $tempx = array(); + $datax = array(); + $selected_datax = array(); + + //get list of sales stage keys to display + $user_tempx = $filters['pbls_lead_sources']; + if (!empty($user_tempx) && count($user_tempx) > 0 && !isset($_REQUEST['pbls_lead_sources'])) { + $tempx = $user_tempx; + $GLOBALS['log']->debug("USER PREFERENCES['pbls_lead_sources'] is:"); + $GLOBALS['log']->debug($user_tempx); + } + elseif (isset($_REQUEST['pbls_lead_sources']) && count($_REQUEST['pbls_lead_sources']) > 0) { + $tempx = $_REQUEST['pbls_lead_sources']; + $current_user->setPreference('pbls_lead_sources', $_REQUEST['pbls_lead_sources']); + $GLOBALS['log']->debug("_REQUEST['pbls_lead_sources'] is:"); + $GLOBALS['log']->debug($_REQUEST['pbls_lead_sources']); + $GLOBALS['log']->debug("USER PREFERENCES['pbls_lead_sources'] is:"); + $GLOBALS['log']->debug($current_user->getPreference('pbls_lead_sources')); + } + + //set $datax using selected sales stage keys + if (count($tempx) > 0) { + foreach ($tempx as $key) { + $datax[$key] = $app_list_strings['lead_source_dom'][$key]; + array_push($selected_datax,$key); + } + } + else { + $datax = $app_list_strings['lead_source_dom']; + $selected_datax = array_keys($app_list_strings['lead_source_dom']); + } + + $legends = $datax; + + $ids = array(); + $user_ids = $filters['pbls_ids']; + //get list of user ids for which to display data + if (!empty($user_ids) && count($user_ids) > 0){ + $ids = $user_ids; + } + else { + $ids = get_user_array(false); + $ids = array_keys($ids); + } + + $user_id = $ids; + $opp = new Opportunity; + //Now do the db queries + //query for opportunity data that matches $legends and $user + $where=""; + //build the where clause for the query that matches $user + + $count = count($user_id); + $id = array(); + if ($count > 0 && !empty($user_id)) { + foreach ($user_id as $the_id) { + $id[] = "'".$the_id."'"; + } + $ids = join(",",$id); + $where .= "opportunities.assigned_user_id IN ($ids) "; + + } + if(!empty($where)) $where .= 'AND'; + //build the where clause for the query that matches $datax + $count = count($legends); + $legendItem = array(); + if ($count > 0 && !empty($legends)) { + + foreach ($legends as $key=>$value) { + $legendItem[] = "'".$key."'"; + } + $legendItems = join(",",$legendItem); + $where .= " opportunities.lead_source IN ($legendItems) "; + } + $query = "SELECT lead_source,sum(amount_usdollar/1000) as total,count(*) as opp_count FROM opportunities "; + $query .= "WHERE ".$where." AND opportunities.deleted=0 "; + $query .= "GROUP BY lead_source ORDER BY total DESC"; + + return $query; + } + + function myModuleUsageLast30Days() { + global $current_user; + $dateValue = db_convert("'".$timedate->getNow()->modify("-30 days")->asDb()."'" ,"datetime"); + + $query = "SELECT tracker.module_name as module_name "; + $query .= ",COUNT(*) count FROM tracker "; + $query .= "WHERE tracker.user_id = '$current_user->id' AND tracker.module_name != 'UserPreferences' AND tracker.date_modified > $dateValue "; + $query .= "GROUP BY tracker.module_name ORDER BY count DESC"; + + return $query; + } + + + // This function will grab a query from the custom directory to be used for charting + function customChartQuery($chart){ + if (file_exists('custom/Charts/' . $chart . '.php')){ + require_once('custom/Charts/' . $chart . '.php'); + return customChartQuery(); + } + else return false; + } +} + + +?> \ No newline at end of file diff --git a/modules/Charts/chartdefs.php b/modules/Charts/chartdefs.php new file mode 100644 index 00000000..e147da6e --- /dev/null +++ b/modules/Charts/chartdefs.php @@ -0,0 +1,122 @@ + + array( 'type' => 'code', + 'id' => 'Chart_pipeline_by_sales_stage', + 'label' => 'Pipeline by Sales Stage', + 'chartUnits' => 'Opportunity Size in $1K', + 'chartType' => 'horizontal group by chart', + 'groupBy' => array( 'sales_stage', 'user_name' ), + 'base_url'=> + array( 'module' => 'Opportunities', + 'action' => 'index', + 'query' => 'true', + 'searchFormTab' => 'advanced_search', + ), + 'url_params' => array( 'assigned_user_id', 'sales_stage', 'date_start', 'date_closed' ), + ), + 'lead_source_by_outcome'=> + array( 'type' => 'code', + 'id' => 'Chart_lead_source_by_outcome', + 'label' => 'Lead Source By Outcome', + 'chartUnits' => '', + 'chartType' => 'horizontal group by chart', + 'groupBy' => array( 'lead_source', 'sales_stage' ), + 'base_url'=> + array( 'module' => 'Opportunities', + 'action' => 'index', + 'query' => 'true', + 'searchFormTab' => 'advanced_search', + ), + 'url_params' => array( 'lead_source', 'sales_stage', 'date_start', 'date_closed' ), + ), + 'outcome_by_month'=> + array( 'type' => 'code', + 'id' => 'Chart_outcome_by_month', + 'label' => 'Outcome by Month', + 'chartUnits' => 'Opportunity Size in $1K', + 'chartType' => 'stacked group by chart', + 'groupBy' => array( 'm', 'sales_stage', ), + 'base_url'=> + array( 'module' => 'Opportunities', + 'action' => 'index', + 'query' => 'true', + 'searchFormTab' => 'advanced_search', + ), + 'url_params' => array( 'sales_stage', 'date_closed' ), + ), + 'pipeline_by_lead_source'=> + array( 'type' => 'code', + 'id' => 'Chart_pipeline_by_lead_source', + 'label' => 'Pipeline By Lead Source', + 'chartUnits' => 'Opportunity Size in $1K', + 'chartType' => 'pie chart', + 'groupBy' => array( 'lead_source', ), + 'base_url'=> + array( 'module' => 'Opportunities', + 'action' => 'index', + 'query' => 'true', + 'searchFormTab' => 'advanced_search', + ), + 'url_params' => array( 'lead_source', ), + ), + + 'my_modules_used_last_30_days' => + array( 'type' => 'code', + 'id' => 'my_modules_used_last_30_days', + 'label' => 'My Modules Used (Last 30 Days)', + 'chartType' => 'horizontal bar chart', + 'chartUnits' => 'Access Count', + 'groupBy' => array( 'module_name'), + 'base_url'=> + array( 'module' => 'Trackers', + 'action' => 'index', + 'query' => 'true', + 'searchFormTab' => 'advanced_search', + ), + + ), + +); + +if(file_exists('custom/Charts/chartDefs.ext.php')){ + include_once('custom/Charts/chartDefs.ext.php'); +} +?> \ No newline at end of file diff --git a/modules/Charts/code/Chart_lead_source_by_outcome.php b/modules/Charts/code/Chart_lead_source_by_outcome.php new file mode 100644 index 00000000..28bfcd70 --- /dev/null +++ b/modules/Charts/code/Chart_lead_source_by_outcome.php @@ -0,0 +1,449 @@ +getPreference('lsbo_lead_sources'); +if (!empty($lsbo_lead_sources) && count($lsbo_lead_sources) > 0 && !isset($_REQUEST['lsbo_lead_sources'])) { + $GLOBALS['log']->fatal("user->getPreference('lsbo_lead_sources') is:"); + $GLOBALS['log']->fatal($tempx); +} +elseif (isset($_REQUEST['lsbo_lead_sources']) && count($_REQUEST['lsbo_lead_sources']) > 0) { + $tempx = $_REQUEST['lsbo_lead_sources']; + $current_user->setPreference('lsbo_lead_sources', $_REQUEST['lsbo_lead_sources']); + $GLOBALS['log']->fatal("_REQUEST['lsbo_lead_sources'] is:"); + $GLOBALS['log']->fatal($_REQUEST['lsbo_lead_sources']); + $GLOBALS['log']->fatal("user->getPreference('lsbo_lead_sources') is:"); + $GLOBALS['log']->fatal($current_user->getPreference('lsbo_lead_sources')); +} +//set $datax using selected sales stage keys +if (!empty($tempx) && sizeof($tempx) > 0) { + foreach ($tempx as $key) { + $datax[$key] = $app_list_strings['lead_source_dom'][$key]; + array_push($selected_datax,$key); + } +} +else { + $datax = $app_list_strings['lead_source_dom']; + $selected_datax = array_keys($app_list_strings['lead_source_dom']); +} + +$ids =$current_user->getPreference('lsbo_ids'); +//get list of user ids for which to display data +if (!empty($ids) && count($ids) != 0 && !isset($_REQUEST['lsbo_ids'])) { + $GLOBALS['log']->debug("_SESSION['lsbo_ids'] is:"); + $GLOBALS['log']->debug($ids); +} +elseif (isset($_REQUEST['lsbo_ids']) && count($_REQUEST['lsbo_ids']) > 0) { + $ids = $_REQUEST['lsbo_ids']; + $current_user->setPreference('lsbo_ids', $_REQUEST['lsbo_ids']); + $GLOBALS['log']->debug("_REQUEST['lsbo_ids'] is:"); + $GLOBALS['log']->debug($_REQUEST['lsbo_ids']); + $GLOBALS['log']->debug("user->getPreference('lsbo_ids') is:"); + $GLOBALS['log']->debug($current_user->getPreference('lsbo_ids')); +} +else { + $ids = get_user_array(false); + $ids = array_keys($ids); +} + +//create unique prefix based on selected users for image files +$id_hash = '1'; +if (isset($ids)) { + sort($ids); + $id_hash = crc32(implode('',$ids)); + if($id_hash < 0) + { + $id_hash = $id_hash * -1; + } + +} +$GLOBALS['log']->debug("ids is:"); +$GLOBALS['log']->debug($ids); +$id_md5 = substr(md5($current_user->id),0,9); + + +$seps = array("-", "/"); +$dates = array(date($GLOBALS['timedate']->dbDayFormat), $GLOBALS['timedate']->dbDayFormat); +$dateFileNameSafe = str_replace($seps, "_", $dates); +$cache_file_name = $current_user->getUserPrivGuid()."_lead_source_by_outcome_".$dateFileNameSafe[0]."_".$dateFileNameSafe[1].".xml"; +$GLOBALS['log']->debug("cache file name is: $cache_file_name"); + + +$tools=''; +?> + +order . '">' . get_form_header($current_module_strings['LBL_LEAD_SOURCE_BY_OUTCOME'],$tools,false) . ''; + +if (empty($_SESSION['lsbo_ids'])) $_SESSION['lsbo_ids'] = ""; +?> + +

    +

    +

    +".$this->gen_xml($datax, $ids, $sugar_config['tmp_dir'].$cache_file_name, $refresh,$current_module_strings)."

    "; +echo "

    ".$current_module_strings['LBL_LEAD_SOURCE_BY_OUTCOME_DESC']."

    "; + + + if (file_exists($sugar_config['tmp_dir'].$cache_file_name)) { +global $timedate; + $file_date = $timedate->asUser($timedate->fromTimestamp(filemtime($sugar_config['tmp_dir'].$cache_file_name))); + } + else { + $file_date = ''; + } +?> + +

    +
    +getPreference('num_grp_sep'); + + if (!file_exists($cache_file_name) || $refresh == true) { + $GLOBALS['log']->debug("datay is:"); + $GLOBALS['log']->debug($datay); + $GLOBALS['log']->debug("user_id is: "); + $GLOBALS['log']->debug($user_id); + $GLOBALS['log']->debug("cache_file_name is: $cache_file_name"); + $opp = new Opportunity(); + $where=""; + //build the where clause for the query that matches $user + $count = count($user_id); + $id = array(); + if ($count>0) { + foreach ($user_id as $the_id) { + $id[] = "'".$the_id."'"; + } + $ids = join(",",$id); + $where .= "opportunities.assigned_user_id IN ($ids) "; + + } + + //build the where clause for the query that matches $datay + $count = count($datay); + $datayArr = array(); + if ($count>0) { + + foreach ($datay as $key=>$value) { + $datayArr[] = "'".$key."'"; + } + $datayArr = join(",",$datayArr); + $where .= "AND opportunities.lead_source IN ($datayArr) "; + } + $query = "SELECT lead_source,sales_stage,sum(amount_usdollar/1000) as total,count(*) as opp_count FROM opportunities "; + $query .= "WHERE " .$where." AND opportunities.deleted=0 "; + $query .= " GROUP BY sales_stage,lead_source ORDER BY lead_source,sales_stage"; + //Now do the db queries + //query for opportunity data that matches $datay and $user + + $result = $opp->db->query($query) + or sugar_die("Error selecting sugarbean: ".mysql_error()); + //build pipeline by sales stage data + $total = 0; + $div = 1; + global $sugar_config; + $symbol = $sugar_config['default_currency_symbol']; + $other = $current_module_strings['LBL_LEAD_SOURCE_OTHER']; + $rowTotalArr = array(); + $rowTotalArr[] = 0; + global $current_user; + $salesStages = array("Closed Lost"=>$app_list_strings['sales_stage_dom']["Closed Lost"],"Closed Won"=>$app_list_strings['sales_stage_dom']["Closed Won"],"Other"=>$other); + if($current_user->getPreference('currency') ){ + + $currency = new Currency(); + $currency->retrieve($current_user->getPreference('currency')); + $div = $currency->conversion_rate; + $symbol = $currency->symbol; + } + $fileContents = ' '."\n"; + $leadSourceArr = array(); + while($row = $opp->db->fetchByAssoc($result, -1, false)) + { + if($row['total']*$div<=100){ + $sum = round($row['total']*$div, 2); + } else { + $sum = round($row['total']*$div); + } + if($row['lead_source'] == ''){ + $row['lead_source'] = $current_module_strings['NTC_NO_LEGENDS']; + } + if($row['sales_stage'] == 'Closed Won' || $row['sales_stage'] == 'Closed Lost'){ + $salesStage = $row['sales_stage']; + $salesStageT = $app_list_strings['sales_stage_dom'][$row['sales_stage']]; + } else { + $salesStage = "Other"; + $salesStageT = $other; + } + if(!isset($leadSourceArr[$row['lead_source']]['row_total'])) {$leadSourceArr[$row['lead_source']]['row_total']=0;} + $leadSourceArr[$row['lead_source']][$salesStage]['opp_count'][] = $row['opp_count']; + $leadSourceArr[$row['lead_source']][$salesStage]['total'][] = $sum; + $leadSourceArr[$row['lead_source']]['outcome'][$salesStage]=$salesStageT; + $leadSourceArr[$row['lead_source']]['row_total'] += $sum; + + $total += $sum; + } + foreach ($datay as $key=>$translation) { + if ($key == '') { + $key = $current_module_strings['NTC_NO_LEGENDS']; + $translation = $current_module_strings['NTC_NO_LEGENDS']; + } + if(!isset($leadSourceArr[$key])){ + $leadSourceArr[$key] = $key; + } + if(isset($leadSourceArr[$key]['row_total'])){$rowTotalArr[]=$leadSourceArr[$key]['row_total'];} + if(isset($leadSourceArr[$key]['row_total']) && $leadSourceArr[$key]['row_total']>100){ + $leadSourceArr[$key]['row_total'] = round($leadSourceArr[$key]['row_total']); + } + $fileContents .= ' '."\n"; + if(is_array($leadSourceArr[$key]['outcome'])){ + foreach ($leadSourceArr[$key]['outcome'] as $outcome=>$outcome_translation){ + $fileContents .= ' '."\n"; + } + } + $fileContents .= ' '."\n"; + } + $fileContents .= ' '."\n"; + $max = get_max($rowTotalArr); + $fileContents .= ' ' . "\n"; + $fileContents .= ' '."\n"; + $i=0; + + foreach ($salesStages as $outcome=>$outcome_translation) { + $color = generate_graphcolor($outcome,$i); + $fileContents .= ' '."\n"; + $i++; + } + $fileContents .= ' '."\n"; + $fileContents .= ' '."\n"; + $fileContents .= ' '."\n"; + $fileContents .= ' '."\n"; + $fileContents .= ' $value) { + $fileContents .= ' '.$key.'='.'"'.$value.'" '; + } + $fileContents .= ' />'."\n"; + $fileContents .= ''."\n"; + $total = round($total, 2); + $title = ''."\n"; + $fileContents = $title.$fileContents; + + save_xml_file($cache_file_name, $fileContents); + } + $return = create_chart('hBarF',$cache_file_name); + return $return; + } + + + function constructQuery(){ + global $current_user; + global $app_list_strings; + + $tempx = array(); + $datax = array(); + $selected_datax = array(); + //get list of sales stage keys to display + + $tempx = $current_user->getPreference('lsbo_lead_sources'); + if (!empty($lsbo_lead_sources) && count($lsbo_lead_sources) > 0 && !isset($_REQUEST['lsbo_lead_sources'])) { + $GLOBALS['log']->fatal("user->getPreference('lsbo_lead_sources') is:"); + $GLOBALS['log']->fatal($tempx); + } + elseif (isset($_REQUEST['lsbo_lead_sources']) && count($_REQUEST['lsbo_lead_sources']) > 0) { + $tempx = $_REQUEST['lsbo_lead_sources']; + $current_user->setPreference('lsbo_lead_sources', $_REQUEST['lsbo_lead_sources']); + $GLOBALS['log']->fatal("_REQUEST['lsbo_lead_sources'] is:"); + $GLOBALS['log']->fatal($_REQUEST['lsbo_lead_sources']); + $GLOBALS['log']->fatal("user->getPreference('lsbo_lead_sources') is:"); + $GLOBALS['log']->fatal($current_user->getPreference('lsbo_lead_sources')); + } + //set $datax using selected sales stage keys + if (!empty($tempx) && sizeof($tempx) > 0) { + foreach ($tempx as $key) { + $datax[$key] = $app_list_strings['lead_source_dom'][$key]; + array_push($selected_datax,$key); + } + } + else { + $datax = $app_list_strings['lead_source_dom']; + $selected_datax = array_keys($app_list_strings['lead_source_dom']); + } + + $datay = $datax; + + $ids =$current_user->getPreference('lsbo_ids'); + //get list of user ids for which to display data + if (!empty($ids) && count($ids) != 0 && !isset($_REQUEST['lsbo_ids'])) { + $GLOBALS['log']->debug("_SESSION['lsbo_ids'] is:"); + $GLOBALS['log']->debug($ids); + } + elseif (isset($_REQUEST['lsbo_ids']) && count($_REQUEST['lsbo_ids']) > 0) { + $ids = $_REQUEST['lsbo_ids']; + $current_user->setPreference('lsbo_ids', $_REQUEST['lsbo_ids']); + $GLOBALS['log']->debug("_REQUEST['lsbo_ids'] is:"); + $GLOBALS['log']->debug($_REQUEST['lsbo_ids']); + $GLOBALS['log']->debug("user->getPreference('lsbo_ids') is:"); + $GLOBALS['log']->debug($current_user->getPreference('lsbo_ids')); + } + else { + $ids = get_user_array(false); + $ids = array_keys($ids); + } + + $user_id = $ids; + + $opp = new Opportunity(); + $where=""; + //build the where clause for the query that matches $user + $count = count($user_id); + $id = array(); + if ($count>0) { + foreach ($user_id as $the_id) { + $id[] = "'".$the_id."'"; + } + $ids = join(",",$id); + $where .= "opportunities.assigned_user_id IN ($ids) "; + + } + + //build the where clause for the query that matches $datay + $count = count($datay); + $datayArr = array(); + if ($count>0) { + + foreach ($datay as $key=>$value) { + $datayArr[] = "'".$key."'"; + } + $datayArr = join(",",$datayArr); + $where .= "AND opportunities.lead_source IN ($datayArr) "; + } + $query = "SELECT lead_source,sales_stage,sum(amount_usdollar/1000) as total,count(*) as opp_count FROM opportunities "; + $query .= "WHERE " .$where." AND opportunities.deleted=0 "; + $query .= " GROUP BY sales_stage,lead_source ORDER BY lead_source,sales_stage"; + + return $query; + } + + function constructGroupBy(){ + return array( 'lead_source', 'sales_stage' ); + } +} + +?> diff --git a/modules/Charts/code/Chart_my_pipeline_by_sales_stage.php b/modules/Charts/code/Chart_my_pipeline_by_sales_stage.php new file mode 100644 index 00000000..9a663962 --- /dev/null +++ b/modules/Charts/code/Chart_my_pipeline_by_sales_stage.php @@ -0,0 +1,495 @@ +get_date_format(); +$current_module_strings = return_module_language($current_language, 'Charts'); + +global $timedate; + +if (isset($_REQUEST['mypbss_refresh'])) { $refresh = $_REQUEST['mypbss_refresh']; } +else { $refresh = false; } + +//get the dates to display +$user_date_start = $current_user->getPreference('mypbss_date_start'); + +if (!empty($user_date_start) && !isset($_REQUEST['mypbss_date_start'])) { + $date_start = $user_date_start; + $GLOBALS['log']->debug("USER PREFERENCES['mypbss_date_start'] is:"); + $GLOBALS['log']->debug($user_date_start); +} +elseif (isset($_REQUEST['mypbss_date_start']) && $_REQUEST['mypbss_date_start'] != '') { + $date_start = $_REQUEST['mypbss_date_start']; + $current_user->setPreference('mypbss_date_start', $_REQUEST['mypbss_date_start']); + $GLOBALS['log']->debug("_REQUEST['mypbss_date_start'] is:"); + $GLOBALS['log']->debug($_REQUEST['mypbss_date_start']); + $GLOBALS['log']->debug("USER PREFERENCES['mypbss_date_start'] is:"); + $GLOBALS['log']->debug($current_user->getPreference('mypbss_date_start')); +} +else { + $date_start = $timedate->nowDate(); +} +$user_date_end = $current_user->getPreference('mypbss_date_end'); + +if (!empty($user_date_end) && !isset($_REQUEST['mypbss_date_end'])) { + $date_end = $user_date_end; + $GLOBALS['log']->debug("USER PREFERENCES['mypbss_date_end'] is:"); + $GLOBALS['log']->debug($user_date_end); +} +elseif (isset($_REQUEST['mypbss_date_end']) && $_REQUEST['mypbss_date_end'] != '') { + $date_end = $_REQUEST['mypbss_date_end']; + $current_user->setPreference('mypbss_date_end', $_REQUEST['mypbss_date_end']); + $GLOBALS['log']->debug("_REQUEST['mypbss_date_end'] is:"); + $GLOBALS['log']->debug($_REQUEST['mypbss_date_end']); + $GLOBALS['log']->debug("USER PREFERENCES['mypbss_date_end'] is:"); + $GLOBALS['log']->debug( $current_user->getPreference('mypbss_date_end')); +} +else { + $date_end = $timedate->asUserDate($timedate->fromString("2010-01-01")); + $GLOBALS['log']->debug("USER PREFERENCES['mypbss_date_end'] not found. Using: ".$date_end); +} + +// cn: format date_start|end to user's preferred +$dateStartDisplay = strftime($timedate->get_user_date_format(), strtotime($date_start)); +$dateEndDisplay = strftime($timedate->get_user_date_format(), strtotime($date_end)); +$seps = array("-", "/"); +$dates = array($date_start, $date_end); +$dateFileNameSafe = str_replace($seps, "_", $dates); +$dateXml[0] = $timedate->swap_formats($date_start, $user_dateFormat, $timedate->dbDayFormat); +$dateXml[1] = $timedate->swap_formats($date_end, $user_dateFormat, $timedate->dbDayFormat); + +$tempx = array(); +$datax = array(); +$selected_datax = array(); +//get list of sales stage keys to display +$user_sales_stage = $current_user->getPreference('mypbss_sales_stages'); +if (!empty($user_sales_stage) && count($user_sales_stage) > 0 && !isset($_REQUEST['mypbss_sales_stages'])) { + $tempx = $user_sales_stage; + $GLOBALS['log']->debug("USER PREFERENCES['mypbss_sales_stages'] is:"); + $GLOBALS['log']->debug($user_sales_stage); +} +elseif (isset($_REQUEST['mypbss_sales_stages']) && count($_REQUEST['mypbss_sales_stages']) > 0) { + $tempx = $_REQUEST['mypbss_sales_stages']; + $current_user->setPreference('mypbss_sales_stages', $_REQUEST['mypbss_sales_stages']); + $GLOBALS['log']->debug("_REQUEST['mypbss_sales_stages'] is:"); + $GLOBALS['log']->debug($_REQUEST['mypbss_sales_stages']); + $GLOBALS['log']->debug("USER PREFRENCES['mypbss_sales_stages'] is:"); + $GLOBALS['log']->debug($current_user->getPreference('mypbss_sales_stages')); +} + +//set $datax using selected sales stage keys +if (count($tempx) > 0) { + foreach ($tempx as $key) { + $datax[$key] = $app_list_strings['sales_stage_dom'][$key]; + array_push($selected_datax, $key); + } +} +else { + $datax = $app_list_strings['sales_stage_dom']; + $selected_datax = array_keys($app_list_strings['sales_stage_dom']); +} +$GLOBALS['log']->debug("datax is:"); +$GLOBALS['log']->debug($datax); + +$ids = array($current_user->id); +//create unique prefix based on selected users for image files +$id_hash = '1'; +if (isset($ids)) { + sort($ids); + $id_hash = crc32(implode('',$ids)); + if($id_hash < 0) + { + $id_hash = $id_hash * -1; + } +} +$GLOBALS['log']->debug("ids is:"); +$GLOBALS['log']->debug($ids); +$id_md5 = substr(md5($current_user->id),0,9); +$seps = array("-", "/"); +$dates = array($dateStartDisplay, $dateEndDisplay); +$dateFileNameSafe = str_replace($seps, "_", $dates); +$cache_file_name = $current_user->getUserPrivGuid()."_".$theme."_my_pipeline_".$dateFileNameSafe[0]."_".$dateFileNameSafe[1].".xml"; + +$GLOBALS['log']->debug("cache file name is: $cache_file_name"); + + +$tools=''; + +?> + + +get_cal_date_format(); +?> +

    +

    +

    + +".gen_xml_pipeline_by_sales_stage($datax, $dateXml[0], $dateXml[1], $ids, $sugar_config['tmp_dir'].$cache_file_name, $refresh,'hBarS',$current_module_strings)."

    "; +echo "

    ".$current_module_strings['LBL_PIPELINE_FORM_TITLE_DESC']."

    "; + + + if (file_exists($sugar_config['tmp_dir'].$cache_file_name)) { + $file_date = $timedate->asUser($timedate->fromTimestamp(filemtime($sugar_config['tmp_dir'].$cache_file_name))); + } + else { + $file_date = ''; + } + +?> + +

    +
    + +getPreference('num_grp_sep'); + global $timedate; + + if (!file_exists($cache_file_name) || $refresh == true) { + + $GLOBALS['log']->debug("starting pipeline chart"); + $GLOBALS['log']->debug("datax is:"); + $GLOBALS['log']->debug($datax); + $GLOBALS['log']->debug("user_id is: "); + $GLOBALS['log']->debug($user_id); + $GLOBALS['log']->debug("cache_file_name is: $cache_file_name"); + $opp = new Opportunity; + $where=""; + //build the where clause for the query that matches $user + $count = count($user_id); + $id = array(); + $user_list = get_user_array(false); + foreach ($user_id as $key) { + $new_ids[$key] = $user_list[$key]; + } + if ($count>0) { + foreach ($new_ids as $the_id=>$the_name) { + $id[] = "'".$the_id."'"; + } + $ids = join(",",$id); + $where .= "opportunities.assigned_user_id IN ($ids) "; + + } + //build the where clause for the query that matches $datax + $count = count($datax); + $dataxArr = array(); + if ($count>0) { + + foreach ($datax as $key=>$value) { + $dataxArr[] = "'".$key."'"; + } + $dataxArr = join(",",$dataxArr); + $where .= "AND opportunities.sales_stage IN ($dataxArr) "; + } + + //build the where clause for the query that matches $date_start and $date_end + $where .= " AND opportunities.date_closed >= ". db_convert("'".$date_start."'",'date'). " + AND opportunities.date_closed <= ".db_convert("'".$date_end."'",'date') ; + $where .= " AND opportunities.assigned_user_id = users.id AND opportunities.deleted=0 "; + + //Now do the db queries + //query for opportunity data that matches $datax and $user + $query = " SELECT opportunities.sales_stage, + users.user_name, + opportunities.assigned_user_id, + count( * ) AS opp_count, + sum(amount_usdollar/1000) AS total + FROM users,opportunities "; + $query .= "WHERE " .$where; + $query .= " GROUP BY opportunities.sales_stage,users.user_name,opportunities.assigned_user_id"; + + $result = $opp->db->query($query) + or sugar_die("Error selecting sugarbean: ".mysql_error()); + //build pipeline by sales stage data + $total = 0; + $div = 1; + global $sugar_config; + $symbol = $sugar_config['default_currency_symbol']; + global $current_user; + if($current_user->getPreference('currency') ){ + + $currency = new Currency(); + $currency->retrieve($current_user->getPreference('currency')); + $div = $currency->conversion_rate; + $symbol = $currency->symbol; + } + // cn: adding user-pref date handling + $dateStartDisplay = $timedate->asUserDate($timedate->fromString($date_start)); + $dateEndDisplay = $timedate->asUserDate($timedate->fromString($date_end)); + + $fileContents = ' '."\n"; + $stageArr = array(); + $usernameArr = array(); + $rowTotalArr = array(); + $rowTotalArr[] = 0; + while($row = $opp->db->fetchByAssoc($result, -1, false)) + { + if($row['total']*$div<=100){ + $sum = round($row['total']*$div, 2); + } else { + $sum = round($row['total']*$div); + } + if(!isset($stageArr[$row['sales_stage']]['row_total'])) {$stageArr[$row['sales_stage']]['row_total']=0;} + $stageArr[$row['sales_stage']][$row['assigned_user_id']]['opp_count'] = $row['opp_count']; + $stageArr[$row['sales_stage']][$row['assigned_user_id']]['total'] = $sum; + $stageArr[$row['sales_stage']]['people'][$row['assigned_user_id']] = $row['user_name']; + $stageArr[$row['sales_stage']]['row_total'] += $sum; + + $usernameArr[$row['assigned_user_id']] = $row['user_name']; + $total += $sum; + } + foreach ($datax as $key=>$translation) { + if(isset($stageArr[$key]['row_total'])){$rowTotalArr[]=$stageArr[$key]['row_total'];} + if(isset($stageArr[$key]['row_total']) && $stageArr[$key]['row_total']>100) { + $stageArr[$key]['row_total'] = round($stageArr[$key]['row_total']); + } + $fileContents .= ' '."\n"; + if(isset($stageArr[$key]['people'])){ + asort($stageArr[$key]['people']); + reset($stageArr[$key]['people']); + foreach ($stageArr[$key]['people'] as $nameKey=>$nameValue) { + $fileContents .= ' '."\n"; + } + } + $fileContents .= ' '."\n"; + } + $fileContents .= ' '."\n"; + $max = get_max($rowTotalArr); + if($chart_size=='hBarF'){ + $length = "10"; + }else{ + $length = "4"; + } + $fileContents .= ' '."\n"; + $fileContents .= ' '."\n"; + $i=0; + asort($new_ids); + foreach ($new_ids as $key=>$value) { + $color = generate_graphcolor($key,$i); + $fileContents .= ' '."\n"; + $i++; + } + $fileContents .= ' '."\n"; + $fileContents .= ' '."\n"; + $fileContents .= ' '.$current_module_strings['LBL_OPP_SIZE'].' '.$symbol.'1'.$current_module_strings['LBL_OPP_THOUSANDS'].']]>'."\n"; + $fileContents .= ' '."\n"; + $fileContents .= ' $value) { + $fileContents .= ' '.$key.'='.'"'.$value.'" '; + } + $fileContents .= ' />'."\n"; + $fileContents .= '
    '."\n"; + $total = $total; + $title = ''."\n"; + $fileContents = $title.$fileContents; + + save_xml_file($cache_file_name, $fileContents); + } + + if($chart_size=='hBarF'){ + $width = "800"; + $height = "400"; + } else { + $width = "350"; + $height = "400"; + } + $return = create_chart($chart_size,$cache_file_name,$width,$height); + return $return; + } + + function constructQuery(){ + global $current_user; + global $time_date; + + //get the dates to display + $user_date_start = $current_user->getPreference('mypbss_date_start'); + + if (!empty($user_date_start) && !isset($_REQUEST['mypbss_date_start'])) { + $date_start = $user_date_start; + $GLOBALS['log']->debug("USER PREFERENCES['mypbss_date_start'] is:"); + $GLOBALS['log']->debug($user_date_start); + } + elseif (isset($_REQUEST['mypbss_date_start']) && $_REQUEST['mypbss_date_start'] != '') { + $date_start = $_REQUEST['mypbss_date_start']; + $current_user->setPreference('mypbss_date_start', $_REQUEST['mypbss_date_start']); + $GLOBALS['log']->debug("_REQUEST['mypbss_date_start'] is:"); + $GLOBALS['log']->debug($_REQUEST['mypbss_date_start']); + $GLOBALS['log']->debug("USER PREFERENCES['mypbss_date_start'] is:"); + $GLOBALS['log']->debug($current_user->getPreference('mypbss_date_start')); + } + else { + $date_start = $timedate->nowDate(); + } + $user_date_end = $current_user->getPreference('mypbss_date_end'); + + if (!empty($user_date_end) && !isset($_REQUEST['mypbss_date_end'])) { + $date_end = $user_date_end; + $GLOBALS['log']->debug("USER PREFERENCES['mypbss_date_end'] is:"); + $GLOBALS['log']->debug($user_date_end); + } + elseif (isset($_REQUEST['mypbss_date_end']) && $_REQUEST['mypbss_date_end'] != '') { + $date_end = $_REQUEST['mypbss_date_end']; + $current_user->setPreference('mypbss_date_end', $_REQUEST['mypbss_date_end']); + $GLOBALS['log']->debug("_REQUEST['mypbss_date_end'] is:"); + $GLOBALS['log']->debug($_REQUEST['mypbss_date_end']); + $GLOBALS['log']->debug("USER PREFERENCES['mypbss_date_end'] is:"); + $GLOBALS['log']->debug( $current_user->getPreference('mypbss_date_end')); + } + else { + $date_end = $timedate->asUserDate($timedate->fromString("2010-01-01")); + $GLOBALS['log']->debug("USER PREFERENCES['mypbss_date_end'] not found. Using: ".$date_end); + } + + $user_id = array($current_user->id); + + $opp = new Opportunity; + $where=""; + //build the where clause for the query that matches $user + $count = count($user_id); + $id = array(); + $user_list = get_user_array(false); + foreach ($user_id as $key) { + $new_ids[$key] = $user_list[$key]; + } + if ($count>0) { + foreach ($new_ids as $the_id=>$the_name) { + $id[] = "'".$the_id."'"; + } + $ids = join(",",$id); + $where .= "opportunities.assigned_user_id IN ($ids) "; + } + //build the where clause for the query that matches $datax + $count = count($datax); + $dataxArr = array(); + if ($count>0) { + foreach ($datax as $key=>$value) { + $dataxArr[] = "'".$key."'"; + } + $dataxArr = join(",",$dataxArr); + $where .= "AND opportunities.sales_stage IN ($dataxArr) "; + } + + //build the where clause for the query that matches $date_start and $date_end + $where .= " AND opportunities.date_closed >= ". db_convert("'".$date_start."'",'date'). " + AND opportunities.date_closed <= ".db_convert("'".$date_end."'",'date') ; + $where .= " AND opportunities.assigned_user_id = users.id AND opportunities.deleted=0 "; + + //Now do the db queries + //query for opportunity data that matches $datax and $user + $query = " SELECT opportunities.sales_stage, + users.user_name, + opportunities.assigned_user_id, + count( * ) AS opp_count, + sum(amount_usdollar/1000) AS total + FROM users,opportunities "; + $query .= "WHERE " .$where; + $query .= " GROUP BY opportunities.sales_stage,users.user_name,opportunities.assigned_user_id"; + + return $query; + + } + + function constructGroupBy(){ + return array('sales_stage'); + } + +?> diff --git a/modules/Charts/code/Chart_outcome_by_month.php b/modules/Charts/code/Chart_outcome_by_month.php new file mode 100644 index 00000000..06f5665b --- /dev/null +++ b/modules/Charts/code/Chart_outcome_by_month.php @@ -0,0 +1,460 @@ +getPreference('obm_date_start'); +if (!empty($user_date_start) && !isset($_REQUEST['obm_date_start'])) { + $date_start =$user_date_start; + $GLOBALS['log']->debug("USER PREFERENCES['obm_date_start'] is:"); + $GLOBALS['log']->debug($user_date_start); +} +elseif (isset($_REQUEST['obm_year']) && $_REQUEST['obm_year'] != '') { + $date_start = $_REQUEST['obm_year'].'-01-01'; + $current_user->setPreference('obm_date_start', $date_start); + $GLOBALS['log']->debug("_REQUEST['obm_date_start'] is:"); + $GLOBALS['log']->debug($_REQUEST['obm_date_start']); + $GLOBALS['log']->debug("_SESSION['obm_date_start'] is:"); + $GLOBALS['log']->debug($current_user->getPreference('obm_date_start')); +} +else { + $date_start = date('Y').'-01-01'; +} +$user_date_end = $current_user->getPreference('obm_date_end'); +if (!empty($user_date_end) && !isset($_REQUEST['obm_date_end'])) { + $date_end =$user_date_end; + $GLOBALS['log']->debug("USER PREFERENCES['obm_date_end'] is:"); + $GLOBALS['log']->debug($date_end); +} +elseif (isset($_REQUEST['obm_year']) && $_REQUEST['obm_year'] != '') { + $date_end = $_REQUEST['obm_year'].'-12-31'; + $current_user->setPreference('obm_date_end', $date_end ); + $GLOBALS['log']->debug("_REQUEST['obm_date_end'] is:"); + $GLOBALS['log']->debug($_REQUEST['obm_date_end']); + $GLOBALS['log']->debug("USER PREFERENCES['obm_date_end'] is:"); + $GLOBALS['log']->debug($current_user->getPreference('obm_date_end')); +} +else { + $date_end = date('Y').'-12-31'; +} + +$ids = array(); +//get list of user ids for which to display data +$user_ids = $current_user->getPreference('obm_ids'); +if (!empty($user_ids) && count($user_ids) != 0 && !isset($_REQUEST['obm_ids'])) { + $ids = $user_ids; + $GLOBALS['log']->debug("USER PREFERENCES['obm_ids'] is:"); + $GLOBALS['log']->debug($user_ids); +} +elseif (isset($_REQUEST['obm_ids']) && count($_REQUEST['obm_ids']) > 0) { + $ids = $_REQUEST['obm_ids']; + $current_user->setPreference('obm_ids', $_REQUEST['obm_ids']); + $GLOBALS['log']->debug("_REQUEST['obm_ids'] is:"); + $GLOBALS['log']->debug($_REQUEST['obm_ids']); + $GLOBALS['log']->debug("USER PREFRENCES['obm_ids'] is:"); + $GLOBALS['log']->debug($current_user->getPreference('obm_ids')); +} +else { + $ids = get_user_array(false); + $ids = array_keys($ids); +} + +//create unique prefix based on selected users for image files +$id_hash = '1'; +if (isset($ids)) { + sort($ids); + $id_hash = crc32(implode('',$ids)); + if($id_hash < 0) + { + $id_hash = $id_hash * -1; + } +} +$GLOBALS['log']->debug("ids is:"); +$GLOBALS['log']->debug($ids); +$id_md5 = substr(md5($current_user->id),0,9); + + +// cn: format date_start|end to user's preferred +global $timedate; +$dateDisplayStart = strftime($timedate->get_user_date_format(), strtotime($date_start)); +$dateDisplayEnd = strftime($timedate->get_user_date_format(), strtotime($date_end)); +$seps = array("-", "/"); +$dates = array($date_start, $date_end); +$dateFileNameSafe = str_replace($seps, "_", $dates); + +$cache_file_name = $current_user->getUserPrivGuid()."_outcome_by_month_".$dateFileNameSafe[0]."_".$dateFileNameSafe[1].".xml"; + +$GLOBALS['log']->debug("cache file name is: $cache_file_name"); + + +global $app_strings; +$tools=''; +?> + order . '">' . get_form_header($current_module_strings['LBL_YEAR_BY_OUTCOME'],$tools,false) . '';?> + + +

    +

    +

    +".$this->gen_xml($date_start, $date_end, $ids, $sugar_config['tmp_dir'].$cache_file_name, $refresh,$current_module_strings)."

    "; +echo "

    ".$current_module_strings['LBL_MONTH_BY_OUTCOME_DESC']."

    "; + + + +?> + + +asUser($timedate->fromTimestamp(filemtime($sugar_config['tmp_dir'].$cache_file_name))); + } + else { + $file_date = ''; + } +?> + + +

    +
    +getPreference('num_grp_sep'); + global $timedate; + + if (!file_exists($cache_file_name) || $refresh == true) { + $GLOBALS['log']->debug("date_start is: $date_start"); + $GLOBALS['log']->debug("date_end is: $date_end"); + $GLOBALS['log']->debug("user_id is: "); + $GLOBALS['log']->debug($user_id); + $GLOBALS['log']->debug("cache_file_name is: $cache_file_name"); + + $where = ""; + //build the where clause for the query that matches $user + $count = count($user_id); + $id = array(); + if ($count>0) { + foreach ($user_id as $the_id) { + $id[] = "'".$the_id."'"; + } + $ids = join(",",$id); + $where .= "opportunities.assigned_user_id IN ($ids) "; + + } + + // cn: adding user-pref date handling + $dateStartDisplay = $timedate->asUserDate($timedate->fromString($date_start)); + $dateEndDisplay = $timedate->asUserDate($timedate->fromString($date_end)); + + $opp = new Opportunity(); + //build the where clause for the query that matches $date_start and $date_end + $where .= "AND opportunities.date_closed >= ".db_convert("'".$date_start."'",'date')." AND opportunities.date_closed <= ".db_convert("'".$date_end."'",'date')." AND opportunities.deleted=0"; + $query = "SELECT sales_stage,".db_convert('opportunities.date_closed','date_format',array("'%Y-%m'"),array("'YYYY-MM'"))." as m, sum(amount_usdollar/1000) as total, count(*) as opp_count FROM opportunities "; + $query .= "WHERE ".$where; + $query .= " GROUP BY sales_stage,".db_convert('opportunities.date_closed','date_format',array("'%Y-%m'"),array("'YYYY-MM'"))."ORDER BY m"; + //Now do the db queries + //query for opportunity data that matches $datay and $user + //_pp($query); + + $result = $opp->db->query($query) + or sugar_die("Error selecting sugarbean: ".mysql_error()); + //build pipeline by sales stage data + $total = 0; + $div = 1; + global $sugar_config; + $symbol = $sugar_config['default_currency_symbol']; + $other = $current_module_strings['LBL_LEAD_SOURCE_OTHER']; + $rowTotalArr = array(); + $rowTotalArr[] = 0; + global $current_user; + $salesStages = array("Closed Lost"=>$app_list_strings['sales_stage_dom']["Closed Lost"],"Closed Won"=>$app_list_strings['sales_stage_dom']["Closed Won"],"Other"=>$other); + if($current_user->getPreference('currency') ){ + + $currency = new Currency(); + $currency->retrieve($current_user->getPreference('currency')); + $div = $currency->conversion_rate; + $symbol = $currency->symbol; + } + $months = array(); + $monthArr = array(); + while($row = $opp->db->fetchByAssoc($result, -1, false)) + { + if($row['total']*$div<=100){ + $sum = round($row['total']*$div, 2); + } else { + $sum = round($row['total']*$div); + } + if($row['sales_stage'] == 'Closed Won' || $row['sales_stage'] == 'Closed Lost'){ + $salesStage = $row['sales_stage']; + $salesStageT = $app_list_strings['sales_stage_dom'][$row['sales_stage']]; + } else { + $salesStage = "Other"; + $salesStageT = $other; + } + + $months[$row['m']] = $row['m']; + if(!isset($monthArr[$row['m']]['row_total'])) {$monthArr[$row['m']]['row_total']=0;} + $monthArr[$row['m']][$salesStage]['opp_count'][] = $row['opp_count']; + $monthArr[$row['m']][$salesStage]['total'][] = $sum; + $monthArr[$row['m']]['outcome'][$salesStage]=$salesStageT; + $monthArr[$row['m']]['row_total'] += $sum; + + $total += $sum; + } + + $fileContents = ' '."\n"; + if (!empty($months)) { + foreach ($months as $month){ + $rowTotalArr[]=$monthArr[$month]['row_total']; + if($monthArr[$month]['row_total']>100) + { + $monthArr[$month]['row_total']=round($monthArr[$month]['row_total']); + } + $fileContents .= ' '."\n"; + arsort($salesStages); + foreach ($salesStages as $outcome=>$outcome_translation){ + if(isset($monthArr[$month][$outcome])) { + $fileContents .= ' '."\n"; + } + } + $fileContents .= ' '."\n"; + } + } else { + $fileContents .= ' '."\n"; + $fileContents .= ' '."\n"; + $fileContents .= ' '."\n"; + $rowTotalArr[] = 1000; + } + $fileContents .= ' '."\n"; + $max = get_max($rowTotalArr); + $fileContents .= ' '."\n"; + $fileContents .= ' '."\n"; + $i=0; + asort($salesStages); + foreach ($salesStages as $outcome=>$outcome_translation) { + $color = generate_graphcolor($outcome,$i); + $fileContents .= ' '."\n"; + $i++; + } + $fileContents .= ' '."\n"; + $fileContents .= ' '."\n"; + $fileContents .= ' ".$current_module_strings['LBL_OPP_SIZE'].' '.$symbol.'1'.$current_module_strings['LBL_OPP_THOUSANDS'].']]>'."\n"; + $fileContents .= ' '."\n"; + $fileContents .= ' $value) { + $fileContents .= ' '.$key.'='.'"'.$value.'" '; + } + $fileContents .= ' />'."\n"; + $fileContents .= '
    '."\n"; + $total = round($total, 2); + $title = ''."\n"; + $fileContents = $title.$fileContents; + + //echo $fileContents; + save_xml_file($cache_file_name, $fileContents); + } + $return = create_chart('vBarF',$cache_file_name); + return $return; + + } + + function constructQuery(){ + global $current_user; + global $timedate; + + $user_date_start = $current_user->getPreference('obm_date_start'); + if (!empty($user_date_start) && !isset($_REQUEST['obm_date_start'])) { + $date_start =$user_date_start; + $GLOBALS['log']->debug("USER PREFERENCES['obm_date_start'] is:"); + $GLOBALS['log']->debug($user_date_start); + } + elseif (isset($_REQUEST['obm_year']) && $_REQUEST['obm_year'] != '') { + $date_start = $_REQUEST['obm_year'].'-01-01'; + $current_user->setPreference('obm_date_start', $date_start); + $GLOBALS['log']->debug("_REQUEST['obm_date_start'] is:"); + $GLOBALS['log']->debug($_REQUEST['obm_date_start']); + $GLOBALS['log']->debug("_SESSION['obm_date_start'] is:"); + $GLOBALS['log']->debug($current_user->getPreference('obm_date_start')); + } + else { + $date_start = date('Y').'-01-01'; + } + $user_date_end = $current_user->getPreference('obm_date_end'); + if (!empty($user_date_end) && !isset($_REQUEST['obm_date_end'])) { + $date_end =$user_date_end; + $GLOBALS['log']->debug("USER PREFERENCES['obm_date_end'] is:"); + $GLOBALS['log']->debug($date_end); + } + elseif (isset($_REQUEST['obm_year']) && $_REQUEST['obm_year'] != '') { + $date_end = $_REQUEST['obm_year'].'-12-31'; + $current_user->setPreference('obm_date_end', $date_end ); + $GLOBALS['log']->debug("_REQUEST['obm_date_end'] is:"); + $GLOBALS['log']->debug($_REQUEST['obm_date_end']); + $GLOBALS['log']->debug("USER PREFERENCES['obm_date_end'] is:"); + $GLOBALS['log']->debug($current_user->getPreference('obm_date_end')); + } + else { + $date_end = date('Y').'-12-31'; + } + + $ids = array(); + //get list of user ids for which to display data + $user_ids = $current_user->getPreference('obm_ids'); + if (!empty($user_ids) && count($user_ids) != 0 && !isset($_REQUEST['obm_ids'])) { + $ids = $user_ids; + $GLOBALS['log']->debug("USER PREFERENCES['obm_ids'] is:"); + $GLOBALS['log']->debug($user_ids); + } + elseif (isset($_REQUEST['obm_ids']) && count($_REQUEST['obm_ids']) > 0) { + $ids = $_REQUEST['obm_ids']; + $current_user->setPreference('obm_ids', $_REQUEST['obm_ids']); + $GLOBALS['log']->debug("_REQUEST['obm_ids'] is:"); + $GLOBALS['log']->debug($_REQUEST['obm_ids']); + $GLOBALS['log']->debug("USER PREFRENCES['obm_ids'] is:"); + $GLOBALS['log']->debug($current_user->getPreference('obm_ids')); + } + else { + $ids = get_user_array(false); + $ids = array_keys($ids); + } + + $user_id = $ids; + + $where = ""; + //build the where clause for the query that matches $user + $count = count($user_id); + $id = array(); + if ($count>0) { + foreach ($user_id as $the_id) { + $id[] = "'".$the_id."'"; + } + $ids = join(",",$id); + $where .= "opportunities.assigned_user_id IN ($ids) "; + + } + + // cn: adding user-pref date handling + $dateStartDisplay = $timedate->asUserDate($timedate->fromString($date_start)); + $dateEndDisplay = $timedate->asUserDate($timedate->fromString($date_end)); + + $opp = new Opportunity(); + //build the where clause for the query that matches $date_start and $date_end + $where .= "AND opportunities.date_closed >= ".db_convert("'".$date_start."'",'date')." AND opportunities.date_closed <= ".db_convert("'".$date_end."'",'date')." AND opportunities.deleted=0"; + $query = "SELECT sales_stage,".db_convert('opportunities.date_closed','date_format',array("'%Y-%m'"),array("'YYYY-MM'"))." as m, sum(amount_usdollar/1000) as total, count(*) as opp_count FROM opportunities "; + $query .= "WHERE ".$where; + $query .= " GROUP BY sales_stage,".db_convert('opportunities.date_closed','date_format',array("'%Y-%m'"),array("'YYYY-MM'"))."ORDER BY m"; + return $query; + } + + function constructGroupBy(){ + return array( 'm', 'sales_stage', ); + } + +} + +?> diff --git a/modules/Charts/code/Chart_pipeline_by_lead_source.php b/modules/Charts/code/Chart_pipeline_by_lead_source.php new file mode 100644 index 00000000..9f336214 --- /dev/null +++ b/modules/Charts/code/Chart_pipeline_by_lead_source.php @@ -0,0 +1,431 @@ +getPreference('pbls_lead_sources'); +if (!empty($user_tempx) && count($user_tempx) > 0 && !isset($_REQUEST['pbls_lead_sources'])) { + $tempx = $user_tempx; + $GLOBALS['log']->debug("USER PREFERENCES['pbls_lead_sources'] is:"); + $GLOBALS['log']->debug($user_tempx); +} +elseif (isset($_REQUEST['pbls_lead_sources']) && count($_REQUEST['pbls_lead_sources']) > 0) { + $tempx = $_REQUEST['pbls_lead_sources']; + $current_user->setPreference('pbls_lead_sources', $_REQUEST['pbls_lead_sources']); + $GLOBALS['log']->debug("_REQUEST['pbls_lead_sources'] is:"); + $GLOBALS['log']->debug($_REQUEST['pbls_lead_sources']); + $GLOBALS['log']->debug("USER PREFERENCES['pbls_lead_sources'] is:"); + $GLOBALS['log']->debug($current_user->getPreference('pbls_lead_sources')); +} + +//set $datax using selected sales stage keys +if (count($tempx) > 0) { + foreach ($tempx as $key) { + $datax[$key] = $app_list_strings['lead_source_dom'][$key]; + array_push($selected_datax,$key); + } +} +else { + $datax = $app_list_strings['lead_source_dom']; + $selected_datax = array_keys($app_list_strings['lead_source_dom']); +} +$GLOBALS['log']->debug("datax is:"); +$GLOBALS['log']->debug($datax); + +$ids = array(); +$user_ids = $current_user->getPreference('pbls_ids'); +//get list of user ids for which to display data +if (!empty($user_ids) && count($user_ids) != 0 && !isset($_REQUEST['pbls_ids'])) { + if(isset($_SESSION['pbls_ids'])) {$ids = $_SESSION['pbls_ids'];} + $GLOBALS['log']->debug("USER PREFERENCES['pbls_ids'] is:"); + $GLOBALS['log']->debug($user_ids); +} +elseif (isset($_REQUEST['pbls_ids']) && count($_REQUEST['pbls_ids']) > 0) { + $ids = $_REQUEST['pbls_ids']; + $current_user->setPreference('pbls_ids', $ids); + $GLOBALS['log']->debug("_REQUEST['pbls_ids'] is:"); + $GLOBALS['log']->debug($_REQUEST['pbls_ids']); + $GLOBALS['log']->debug("USER PREFERENCES['pbls_ids'] is:"); + $GLOBALS['log']->debug($current_user->getPreference('pbls_ids')); +} +else { + $ids = get_user_array(false); + $ids = array_keys($ids); +} + +//create unique prefix based on selected users for image files +$id_hash = '1'; +if (isset($ids) && is_array($ids)) { + sort($ids); + $id_hash = crc32(implode('',$ids)); + if($id_hash < 0) + { + $id_hash = $id_hash * -1; + } +} +$GLOBALS['log']->debug("ids is:"); +$GLOBALS['log']->debug($ids); +$id_md5 = substr(md5($current_user->id),0,9); + + +$seps = array("-", "/"); +$dates = array(date($GLOBALS['timedate']->dbDayFormat), $GLOBALS['timedate']->dbDayFormat); +$dateFileNameSafe = str_replace($seps, "_", $dates); +$cache_file_name = $current_user->getUserPrivGuid()."_pipeline_by_lead_source_".$dateFileNameSafe[0]."_".$dateFileNameSafe[1].".xml"; + +$GLOBALS['log']->debug("cache file name is: $cache_file_name"); +global $currentModule,$action; +$tools=''; +?> + +order . '">' . get_form_header($current_module_strings['LBL_LEAD_SOURCE_FORM_TITLE'],$tools,false) . ''; +if (empty($_SESSION['pbls_lead_sources'])) $_SESSION['pbls_lead_sources'] = ""; +if (empty($_SESSION['pbls_ids'])) $_SESSION['pbls_ids'] = ""; +?> + +

    +

    +

    +".$this->gen_xml($datax, $ids, $sugar_config['tmp_dir'].$cache_file_name, $refresh,$current_module_strings)."

    "; +echo "

    ".$current_module_strings['LBL_LEAD_SOURCE_FORM_DESC']."

    "; + + if (file_exists($sugar_config['tmp_dir'].$cache_file_name)) { +global $timedate; + $file_date = $timedate->asUser($timedate->fromTimestamp(filemtime($sugar_config['tmp_dir'].$cache_file_name))); + } + else { + $file_date = ''; + } +?> + +

    +
    +getPreference('num_grp_sep'); + + if (!file_exists($cache_file_name) || $refresh == true) { + ; + $GLOBALS['log']->debug("starting pipeline chart"); + $GLOBALS['log']->debug("legends is:"); + $GLOBALS['log']->debug($legends); + $GLOBALS['log']->debug("user_id is: "); + $GLOBALS['log']->debug($user_id); + $GLOBALS['log']->debug("cache_file_name is: $cache_file_name"); + + $opp = new Opportunity; + //Now do the db queries + //query for opportunity data that matches $legends and $user + $where=""; + //build the where clause for the query that matches $user + + $count = count($user_id); + $id = array(); + if ($count > 0 && !empty($user_id)) { + foreach ($user_id as $the_id) { + $id[] = "'".$the_id."'"; + } + $ids = join(",",$id); + $where .= "opportunities.assigned_user_id IN ($ids) "; + + } + if(!empty($where)) $where .= 'AND'; + //build the where clause for the query that matches $datax + $count = count($legends); + $legendItem = array(); + if ($count > 0 && !empty($legends)) { + + foreach ($legends as $key=>$value) { + $legendItem[] = "'".$key."'"; + } + $legendItems = join(",",$legendItem); + $where .= " opportunities.lead_source IN ($legendItems) "; + } + $query = "SELECT lead_source,sum(amount_usdollar/1000) as total,count(*) as opp_count FROM opportunities "; + $query .= "WHERE ".$where." AND opportunities.deleted=0 "; + $query .= "GROUP BY lead_source ORDER BY total DESC"; + + //build pipeline by lead source data + $total = 0; + $div = 1; + global $sugar_config; + $symbol = $sugar_config['default_currency_symbol']; + global $current_user; + if($current_user->getPreference('currency') ) { + $currency = new Currency(); + $currency->retrieve($current_user->getPreference('currency')); + $div = $currency->conversion_rate; + $symbol = $currency->symbol; + } + $subtitle = $current_module_strings['LBL_OPP_SIZE'].' '.$symbol.'1'.$current_module_strings['LBL_OPP_THOUSANDS']; + $fileContents = ''; + $fileContents .= ' '."\n"; + $result = $opp->db->query($query) + or sugar_die("Error selecting sugarbean: ".mysql_error()); + $leadSourceArr = array(); + while($row = $opp->db->fetchByAssoc($result, -1, false)) + { + if($row['lead_source'] == ''){ + $leadSource = $current_module_strings['NTC_NO_LEGENDS']; + } else { + $leadSource = $row['lead_source']; + } + if($row['total']*$div<=100){ + $sum = round($row['total']*$div, 2); + } else { + $sum = round($row['total']*$div); + } + + $leadSourceArr[$leadSource]['opp_count'] = $row['opp_count']; + $leadSourceArr[$leadSource]['sum'] = $sum; + } + $i=0; + foreach ($legends as $lead_source_key=>$translation) { + if ($lead_source_key == '') { + $lead_source_key = $current_module_strings['NTC_NO_LEGENDS']; + $translation = $current_module_strings['NTC_NO_LEGENDS']; + } + if(!isset($leadSourceArr[$lead_source_key])) { + $leadSourceArr[$lead_source_key] = $lead_source_key; + $leadSourceArr[$lead_source_key]['sum'] = 0; + } + $color = generate_graphcolor($lead_source_key,$i); + $fileContents .= ' '."\n"; + if(isset($leadSourceArr[$lead_source_key])){$total += $leadSourceArr[$lead_source_key]['sum'];} + $i++; + } + + $fileContents .= ' '."\n"; + $fileContents .= ' '."\n"; + $fileContents .= ' '."\n"; + $fileContents .= ' '."\n"; + $fileContents .= ' $value) { + $fileContents .= ' '.$key.'='.'"'.$value.'" '; + } + $fileContents .= ' />'."\n"; + $fileContents .= '
    '."\n"; + $total = round($total, 2); + $title = $current_module_strings['LBL_TOTAL_PIPELINE'].currency_format_number($total, array('currency_symbol' => true)).$app_strings['LBL_THOUSANDS_SYMBOL']; + $fileContents = ''."\n" . $fileContents; + $GLOBALS['log']->debug("total is: $total"); + if ($total == 0) { + return ($current_module_strings['ERR_NO_OPPS']); + } + + save_xml_file($cache_file_name, $fileContents); + } + + $return = create_chart('pieF',$cache_file_name); + return $return; + + } + + function constructQuery(){ + global $current_user; + global $app_list_strings; + + $tempx = array(); + $datax = array(); + $selected_datax = array(); + //get list of sales stage keys to display + global $current_user; + $user_tempx = $current_user->getPreference('pbls_lead_sources'); + if (!empty($user_tempx) && count($user_tempx) > 0 && !isset($_REQUEST['pbls_lead_sources'])) { + $tempx = $user_tempx; + $GLOBALS['log']->debug("USER PREFERENCES['pbls_lead_sources'] is:"); + $GLOBALS['log']->debug($user_tempx); + } + elseif (isset($_REQUEST['pbls_lead_sources']) && count($_REQUEST['pbls_lead_sources']) > 0) { + $tempx = $_REQUEST['pbls_lead_sources']; + $current_user->setPreference('pbls_lead_sources', $_REQUEST['pbls_lead_sources']); + $GLOBALS['log']->debug("_REQUEST['pbls_lead_sources'] is:"); + $GLOBALS['log']->debug($_REQUEST['pbls_lead_sources']); + $GLOBALS['log']->debug("USER PREFERENCES['pbls_lead_sources'] is:"); + $GLOBALS['log']->debug($current_user->getPreference('pbls_lead_sources')); + } + + //set $datax using selected sales stage keys + if (count($tempx) > 0) { + foreach ($tempx as $key) { + $datax[$key] = $app_list_strings['lead_source_dom'][$key]; + array_push($selected_datax,$key); + } + } + else { + $datax = $app_list_strings['lead_source_dom']; + $selected_datax = array_keys($app_list_strings['lead_source_dom']); + } + + $legends = $datax; + + $ids = array(); + $user_ids = $current_user->getPreference('pbls_ids'); + //get list of user ids for which to display data + if (!empty($user_ids) && count($user_ids) != 0 && !isset($_REQUEST['pbls_ids'])) { + if(isset($_SESSION['pbls_ids'])) {$ids = $_SESSION['pbls_ids'];} + $GLOBALS['log']->debug("USER PREFERENCES['pbls_ids'] is:"); + $GLOBALS['log']->debug($user_ids); + } + elseif (isset($_REQUEST['pbls_ids']) && count($_REQUEST['pbls_ids']) > 0) { + $ids = $_REQUEST['pbls_ids']; + $current_user->setPreference('pbls_ids', $ids); + $GLOBALS['log']->debug("_REQUEST['pbls_ids'] is:"); + $GLOBALS['log']->debug($_REQUEST['pbls_ids']); + $GLOBALS['log']->debug("USER PREFERENCES['pbls_ids'] is:"); + $GLOBALS['log']->debug($current_user->getPreference('pbls_ids')); + } + else { + $ids = get_user_array(false); + $ids = array_keys($ids); + } + + $user_id = $ids; + + $opp = new Opportunity; + //Now do the db queries + //query for opportunity data that matches $legends and $user + $where=""; + //build the where clause for the query that matches $user + + $count = count($user_id); + $id = array(); + if ($count > 0 && !empty($user_id)) { + foreach ($user_id as $the_id) { + $id[] = "'".$the_id."'"; + } + $ids = join(",",$id); + $where .= "opportunities.assigned_user_id IN ($ids) "; + + } + if(!empty($where)) $where .= 'AND'; + //build the where clause for the query that matches $datax + $count = count($legends); + $legendItem = array(); + if ($count > 0 && !empty($legends)) { + + foreach ($legends as $key=>$value) { + $legendItem[] = "'".$key."'"; + } + $legendItems = join(",",$legendItem); + $where .= " opportunities.lead_source IN ($legendItems) "; + } + $query = "SELECT lead_source,sum(amount_usdollar/1000) as total,count(*) as opp_count FROM opportunities "; + $query .= "WHERE ".$where." AND opportunities.deleted=0 "; + $query .= "GROUP BY lead_source ORDER BY total DESC"; + + return $query; + } + + function constructGroupBy(){ + return array( 'lead_source', ); + } +} +?> diff --git a/modules/Charts/code/Chart_pipeline_by_sales_stage.php b/modules/Charts/code/Chart_pipeline_by_sales_stage.php new file mode 100644 index 00000000..b22c0ae1 --- /dev/null +++ b/modules/Charts/code/Chart_pipeline_by_sales_stage.php @@ -0,0 +1,617 @@ +get_date_format(); +$current_module_strings = return_module_language($current_language, 'Charts'); + + +if (isset($_REQUEST['pbss_refresh'])) { $refresh = $_REQUEST['pbss_refresh']; } +else { $refresh = false; } + +//get the dates to display +$user_date_start = $current_user->getPreference('pbss_date_start'); + +if (!empty($user_date_start) && !isset($_REQUEST['pbss_date_start'])) { + $date_start = $timedate->to_display_date($user_date_start, false); + $GLOBALS['log']->debug("USER PREFERENCES['pbss_date_start'] is:"); + $GLOBALS['log']->debug($user_date_start); +} +elseif (isset($_REQUEST['pbss_date_start']) && $_REQUEST['pbss_date_start'] != '') { + $date_start = $_REQUEST['pbss_date_start']; + $ds = $timedate->to_db_date($date_start, false); + $current_user->setPreference('pbss_date_start', $ds); + $GLOBALS['log']->debug("_REQUEST['pbss_date_start'] is:"); + $GLOBALS['log']->debug($_REQUEST['pbss_date_start']); + $GLOBALS['log']->debug("USER PREFERENCES['pbss_date_start'] is:"); + $GLOBALS['log']->debug($current_user->getPreference('pbss_date_start')); +} +else { + $date_start = $timedate->nowDate(); +} + +$user_date_end = $current_user->getPreference('pbss_date_end'); +if (!empty($user_date_end) && !isset($_REQUEST['pbss_date_end'])) { + $date_end = $timedate->to_display_date($user_date_end, false); + $GLOBALS['log']->debug("USER PREFERENCES['pbss_date_end'] is:"); + $GLOBALS['log']->debug($user_date_end); +} +elseif (isset($_REQUEST['pbss_date_end']) && $_REQUEST['pbss_date_end'] != '') { + $date_end = $_REQUEST['pbss_date_end']; + $de = $timedate->to_db_date($date_end, false); + $current_user->setPreference('pbss_date_end', $de); + $GLOBALS['log']->debug("_REQUEST['pbss_date_end'] is:"); + $GLOBALS['log']->debug($_REQUEST['pbss_date_end']); + $GLOBALS['log']->debug("USER PREFERENCES['pbss_date_end'] is:"); + $GLOBALS['log']->debug( $current_user->getPreference('pbss_date_end')); +} +else { + $date_end = $timedate->asUserDate($timedate->fromString("2010-01-01")); + $GLOBALS['log']->debug("USER PREFERENCES['pbss_date_end'] not found. Using: ".$date_end); +} + +// cn: format date_start|end to user's preferred +$dateDisplayStart = strftime($timedate->get_user_date_format(), strtotime($date_start)); +$dateDisplayEnd = strftime($timedate->get_user_date_format(), strtotime($date_end)); +$seps = array("-", "/"); +$dates = array($date_start, $date_end); +$dateFileNameSafe = str_replace($seps, "_", $dates); +$dateXml[0] = $timedate->swap_formats($date_start, $user_dateFormat, $timedate->dbDayFormat); +$dateXml[1] = $timedate->swap_formats($date_end, $user_dateFormat, $timedate->dbDayFormat); + +$tempx = array(); +$datax = array(); +$datax_selected= array(); +$user_tempx = $current_user->getPreference('pbss_sales_stages'); +//get list of sales stage keys to display +if (!empty($user_tempx) && count($user_tempx) > 0 && !isset($_REQUEST['pbss_sales_stages'])) { + $tempx = $user_tempx ; + $GLOBALS['log']->debug("USER PREFERENCES['pbss_sales_stages'] is:"); + $GLOBALS['log']->debug($user_tempx ); +} +elseif (isset($_REQUEST['pbss_sales_stages']) && count($_REQUEST['pbss_sales_stages']) > 0) { + $tempx = $_REQUEST['pbss_sales_stages']; + $current_user->setPreference('pbss_sales_stages', $_REQUEST['pbss_sales_stages']); + $GLOBALS['log']->debug("_REQUEST['pbss_sales_stages'] is:"); + $GLOBALS['log']->debug($_REQUEST['pbss_sales_stages']); + $GLOBALS['log']->debug("USER PREFERENCES['pbss_sales_stages'] is:"); + $GLOBALS['log']->debug($current_user->getPreference('pbss_sales_stages')); +} + +//set $datax using selected sales stage keys +if (count($tempx) > 0) { + foreach ($tempx as $key) { + $datax[$key] = $app_list_strings['sales_stage_dom'][$key]; + array_push($datax_selected,$key); + } +} +else { + $datax = $app_list_strings['sales_stage_dom']; + $datax_selected = array_keys($app_list_strings['sales_stage_dom']); +} +$GLOBALS['log']->debug("datax is:"); +$GLOBALS['log']->debug($datax); + +$ids = array(); +$new_ids = array(); +$user_ids = $current_user->getPreference('pbss_ids'); +//get list of user ids for which to display data +if (!empty($user_ids) && count($user_ids) != 0 && !isset($_REQUEST['pbss_ids'])) { + $ids = $user_ids; + + $GLOBALS['log']->debug("USER PREFERENCES['pbss_ids'] is:"); + $GLOBALS['log']->debug($user_ids); +} +elseif (isset($_REQUEST['pbss_ids']) && count($_REQUEST['pbss_ids']) > 0) { + $ids = $_REQUEST['pbss_ids']; + $current_user->setPreference('pbss_ids', $_REQUEST['pbss_ids']); + $GLOBALS['log']->debug("_REQUEST['pbss_ids'] is:"); + $GLOBALS['log']->debug($_REQUEST['pbss_ids']); + $GLOBALS['log']->debug("USER PREFERENCES['pbss_ids'] is:"); + $GLOBALS['log']->debug($current_user->getPreference('pbss_ids')); +} +else { + $ids = get_user_array(false); + $ids = array_keys($ids); + +} + +//create unique prefix based on selected users for image files +$id_hash = '1'; +if (isset($ids)) { + sort($ids); + $id_hash = crc32(implode('',$ids)); + if($id_hash < 0) + { + $id_hash = $id_hash * -1; + } +} +$GLOBALS['log']->debug("ids is:"); +$GLOBALS['log']->debug($ids); + +$cache_file_name = $current_user->getUserPrivGuid()."_lead_source_by_outcome_".$dateFileNameSafe[0]."_".$dateFileNameSafe[1].".xml"; + +$GLOBALS['log']->debug("cache file name is: $cache_file_name"); + +$tools=''; + +echo '' . get_form_header($current_module_strings['LBL_SALES_STAGE_FORM_TITLE'], $tools , false) . ''; ?> + +get_cal_date_format(); +if (empty($_SESSION['pbss_sales_stages'])) $_SESSION['pbss_sales_stages'] = ""; +if (empty($_SESSION['pbss_ids'])) $_SESSION['pbss_ids'] = ""; + + +// set populate values +$puser_date_start = $current_user->getPreference('user_date_start'); + +?> +

    +

    +

    + ".$this->gen_xml($datax, $dateXml[0], $dateXml[1], $ids, $sugar_config['tmp_dir'].$cache_file_name, $refresh,'hBarF',$current_module_strings)."

    "; +echo "

    ".$current_module_strings['LBL_SALES_STAGE_FORM_DESC']."

    "; + + if (file_exists($sugar_config['tmp_dir'].$cache_file_name)) { + $file_date = $timedate->asUser($timedate->fromTimestamp(filemtime($sugar_config['tmp_dir'].$cache_file_name))); + } + else { + $file_date = ''; + } +?> + + +

    +
    +getPreference('num_grp_sep'); + + global $timedate; + + if (!file_exists($cache_file_name) || $refresh == true) { + + $GLOBALS['log']->debug("starting pipeline chart"); + $GLOBALS['log']->debug("datax is:"); + $GLOBALS['log']->debug($datax); + $GLOBALS['log']->debug("user_id is: "); + $GLOBALS['log']->debug($user_id); + $GLOBALS['log']->debug("cache_file_name is: $cache_file_name"); + $opp = new Opportunity; + $where=""; + //build the where clause for the query that matches $user + $count = count($user_id); + $id = array(); + $user_list = get_user_array(false); + foreach ($user_id as $key) { + $new_ids[$key] = $user_list[$key]; + } + if ($count>0) { + foreach ($new_ids as $the_id=>$the_name) { + $id[] = "'".$the_id."'"; + } + $ids = join(",",$id); + $where .= "opportunities.assigned_user_id IN ($ids) "; + + } + //build the where clause for the query that matches $datax + $count = count($datax); + $dataxArr = array(); + if ($count>0) { + + foreach ($datax as $key=>$value) { + $dataxArr[] = "'".$key."'"; + } + $dataxArr = join(",",$dataxArr); + $where .= "AND opportunities.sales_stage IN ($dataxArr) "; + } + + //build the where clause for the query that matches $date_start and $date_end + $where .= " AND opportunities.date_closed >= ". db_convert("'".$date_start."'",'date'). " + AND opportunities.date_closed <= ".db_convert("'".$date_end."'",'date') ; + $where .= " AND opportunities.assigned_user_id = users.id AND opportunities.deleted=0 "; + + //Now do the db queries + //query for opportunity data that matches $datax and $user + $query = " SELECT opportunities.sales_stage, + users.user_name, + opportunities.assigned_user_id, + count( * ) AS opp_count, + sum(amount_usdollar/1000) AS total + FROM users,opportunities "; + $query .= "WHERE " .$where; + $query .= " GROUP BY opportunities.sales_stage,users.user_name,opportunities.assigned_user_id"; + + + + $result = $opp->db->query($query) + or sugar_die("Error selecting sugarbean: ".mysql_error()); + //build pipeline by sales stage data + $total = 0; + $div = 1; + global $sugar_config; + $symbol = $sugar_config['default_currency_symbol']; + global $current_user; + if($current_user->getPreference('currency') ){ + + $currency = new Currency(); + $currency->retrieve($current_user->getPreference('currency')); + $div = $currency->conversion_rate; + $symbol = $currency->symbol; + } + // cn: adding user-pref date handling + $dateStartDisplay = $timedate->asUserDate($timedate->fromString($date_start)); + $dateEndDisplay = $timedate->asUserDate($timedate->fromString($date_end)); + + $fileContents = ' '."\n"; + $stageArr = array(); + $usernameArr = array(); + $rowTotalArr = array(); + $rowTotalArr[] = 0; + while($row = $opp->db->fetchByAssoc($result, -1, false)) + { + if($row['total']*$div<=100){ + $sum = round($row['total']*$div, 2); + } else { + $sum = round($row['total']*$div); + } + if(!isset($stageArr[$row['sales_stage']]['row_total'])) {$stageArr[$row['sales_stage']]['row_total']=0;} + $stageArr[$row['sales_stage']][$row['assigned_user_id']]['opp_count'] = $row['opp_count']; + $stageArr[$row['sales_stage']][$row['assigned_user_id']]['total'] = $sum; + $stageArr[$row['sales_stage']]['people'][$row['assigned_user_id']] = $row['user_name']; + $stageArr[$row['sales_stage']]['row_total'] += $sum; + + $usernameArr[$row['assigned_user_id']] = $row['user_name']; + $total += $sum; + } + foreach ($datax as $key=>$translation) { + if(isset($stageArr[$key]['row_total'])){$rowTotalArr[]=$stageArr[$key]['row_total'];} + if(isset($stageArr[$key]['row_total']) && $stageArr[$key]['row_total']>100) { + $stageArr[$key]['row_total'] = round($stageArr[$key]['row_total']); + } + $fileContents .= ' '."\n"; + if(isset($stageArr[$key]['people'])){ + asort($stageArr[$key]['people']); + reset($stageArr[$key]['people']); + foreach ($stageArr[$key]['people'] as $nameKey=>$nameValue) { + $fileContents .= ' '."\n"; + } + } + $fileContents .= ' '."\n"; + } + $fileContents .= ' '."\n"; + $max = get_max($rowTotalArr); + if($chart_size=='hBarF'){ + $length = "10"; + }else{ + $length = "4"; + } + $fileContents .= ' '."\n"; + $fileContents .= ' '."\n"; + $i=0; + asort($new_ids); + foreach ($new_ids as $key=>$value) { + $color = generate_graphcolor($key,$i); + $fileContents .= ' '."\n"; + $i++; + } + $fileContents .= ' '."\n"; + $fileContents .= ' '."\n"; + $fileContents .= ' '.$current_module_strings['LBL_OPP_SIZE'].' '.$symbol.'1'.$current_module_strings['LBL_OPP_THOUSANDS'].']]>'."\n"; + $fileContents .= ' '."\n"; + $fileContents .= ' $value) { + $fileContents .= ' '.$key.'='.'"'.$value.'" '; + } + $fileContents .= ' />'."\n"; + $fileContents .= '
    '."\n"; + $total = $total; + $title = ''."\n"; + $fileContents = $title.$fileContents; + + save_xml_file($cache_file_name, $fileContents); + } + + if($chart_size=='hBarF'){ + $width = "800"; + $height = "400"; + } else { + $width = "350"; + $height = "400"; + } + $return = create_chart($chart_size,$cache_file_name,$width,$height); + return $return; + } + + function constructQuery(){ + global $current_user; + global $timedate; + global $app_list_strings; + + //get the dates to display + $user_date_start = $current_user->getPreference('pbss_date_start'); + + if (!empty($user_date_start) && !isset($_REQUEST['pbss_date_start'])) { + $date_start = $timedate->to_display_date($user_date_start, false); + $GLOBALS['log']->debug("USER PREFERENCES['pbss_date_start'] is:"); + $GLOBALS['log']->debug($user_date_start); + } + elseif (isset($_REQUEST['pbss_date_start']) && $_REQUEST['pbss_date_start'] != '') { + $date_start = $_REQUEST['pbss_date_start']; + $ds = $timedate->to_db_date($date_start, false); + $current_user->setPreference('pbss_date_start', $ds); + $GLOBALS['log']->debug("_REQUEST['pbss_date_start'] is:"); + $GLOBALS['log']->debug($_REQUEST['pbss_date_start']); + $GLOBALS['log']->debug("USER PREFERENCES['pbss_date_start'] is:"); + $GLOBALS['log']->debug($current_user->getPreference('pbss_date_start')); + } + else { + $date_start = $timedate->nowDate(); + } + + $user_date_end = $current_user->getPreference('pbss_date_end'); + if (!empty($user_date_end) && !isset($_REQUEST['pbss_date_end'])) { + $date_end = $timedate->to_display_date($user_date_end, false); + $GLOBALS['log']->debug("USER PREFERENCES['pbss_date_end'] is:"); + $GLOBALS['log']->debug($user_date_end); + } + elseif (isset($_REQUEST['pbss_date_end']) && $_REQUEST['pbss_date_end'] != '') { + $date_end = $_REQUEST['pbss_date_end']; + $de = $timedate->to_db_date($date_end, false); + $current_user->setPreference('pbss_date_end', $de); + $GLOBALS['log']->debug("_REQUEST['pbss_date_end'] is:"); + $GLOBALS['log']->debug($_REQUEST['pbss_date_end']); + $GLOBALS['log']->debug("USER PREFERENCES['pbss_date_end'] is:"); + $GLOBALS['log']->debug( $current_user->getPreference('pbss_date_end')); + } + else { + $date_end = $timedate->asUserDate($timedate->fromString("2010-01-01")); + $GLOBALS['log']->debug("USER PREFERENCES['pbss_date_end'] not found. Using: ".$date_end); + } + +$tempx = array(); +$datax = array(); +$datax_selected= array(); +$user_tempx = $current_user->getPreference('pbss_sales_stages'); +//get list of sales stage keys to display +if (!empty($user_tempx) && count($user_tempx) > 0 && !isset($_REQUEST['pbss_sales_stages'])) { + $tempx = $user_tempx ; + $GLOBALS['log']->debug("USER PREFERENCES['pbss_sales_stages'] is:"); + $GLOBALS['log']->debug($user_tempx ); +} +elseif (isset($_REQUEST['pbss_sales_stages']) && count($_REQUEST['pbss_sales_stages']) > 0) { + $tempx = $_REQUEST['pbss_sales_stages']; + $current_user->setPreference('pbss_sales_stages', $_REQUEST['pbss_sales_stages']); + $GLOBALS['log']->debug("_REQUEST['pbss_sales_stages'] is:"); + $GLOBALS['log']->debug($_REQUEST['pbss_sales_stages']); + $GLOBALS['log']->debug("USER PREFERENCES['pbss_sales_stages'] is:"); + $GLOBALS['log']->debug($current_user->getPreference('pbss_sales_stages')); +} + +//set $datax using selected sales stage keys +if (count($tempx) > 0) { + foreach ($tempx as $key) { + $datax[$key] = $app_list_strings['sales_stage_dom'][$key]; + array_push($datax_selected,$key); + } +} +else { + $datax = $app_list_strings['sales_stage_dom']; + $datax_selected = array_keys($app_list_strings['sales_stage_dom']); +} +$GLOBALS['log']->debug("datax is:"); +$GLOBALS['log']->debug($datax); + + + + $ids = array(); + $new_ids = array(); + $user_ids = $current_user->getPreference('pbss_ids'); + //get list of user ids for which to display data + if (!empty($user_ids) && count($user_ids) != 0 && !isset($_REQUEST['pbss_ids'])) { + $ids = $user_ids; + + $GLOBALS['log']->debug("USER PREFERENCES['pbss_ids'] is:"); + $GLOBALS['log']->debug($user_ids); + } + elseif (isset($_REQUEST['pbss_ids']) && count($_REQUEST['pbss_ids']) > 0) { + $ids = $_REQUEST['pbss_ids']; + $current_user->setPreference('pbss_ids', $_REQUEST['pbss_ids']); + $GLOBALS['log']->debug("_REQUEST['pbss_ids'] is:"); + $GLOBALS['log']->debug($_REQUEST['pbss_ids']); + $GLOBALS['log']->debug("USER PREFERENCES['pbss_ids'] is:"); + $GLOBALS['log']->debug($current_user->getPreference('pbss_ids')); + } + else { + $ids = get_user_array(false); + $ids = array_keys($ids); + + } + + $user_id = $ids; + $opp = new Opportunity; + $where=""; + //build the where clause for the query that matches $user + $count = count($user_id); + $id = array(); + $user_list = get_user_array(false); + foreach ($user_id as $key) { + $new_ids[$key] = $user_list[$key]; + } + if ($count>0) { + foreach ($new_ids as $the_id=>$the_name) { + $id[] = "'".$the_id."'"; + } + $ids = join(",",$id); + $where .= "opportunities.assigned_user_id IN ($ids) "; + + } + //build the where clause for the query that matches $datax + $count = count($datax); + $dataxArr = array(); + if ($count>0) { + + foreach ($datax as $key=>$value) { + $dataxArr[] = "'".$key."'"; + } + $dataxArr = join(",",$dataxArr); + $where .= "AND opportunities.sales_stage IN ($dataxArr) "; + } + + //build the where clause for the query that matches $date_start and $date_end + $where .= " AND opportunities.date_closed >= ". db_convert("'".$date_start."'",'date'). " + AND opportunities.date_closed <= ".db_convert("'".$date_end."'",'date') ; + $where .= " AND opportunities.assigned_user_id = users.id AND opportunities.deleted=0 "; + + //Now do the db queries + //query for opportunity data that matches $datax and $user + $query = " SELECT opportunities.sales_stage, + users.user_name, + opportunities.assigned_user_id, + count( * ) AS opp_count, + sum(amount_usdollar/1000) AS total + FROM users,opportunities "; + $query .= "WHERE " .$where; + $query .= " GROUP BY opportunities.sales_stage,users.user_name,opportunities.assigned_user_id"; + + return $query; + } + + function constructGroupBy(){ + return array( 'sales_stage', 'user_name' ); + } + +} + +?> diff --git a/modules/Charts/code/predefined_charts.php b/modules/Charts/code/predefined_charts.php new file mode 100644 index 00000000..ec299e6e --- /dev/null +++ b/modules/Charts/code/predefined_charts.php @@ -0,0 +1,49 @@ + + array('type'=>'code','id'=>'Chart_pipeline_by_sales_stage','label'=>'Pipeline by Sales Stage','chartType'=>'horizontal group by chart',), + 'Chart_lead_source_by_outcome'=> + array('type'=>'code','id'=>'Chart_lead_source_by_outcome','label'=>'Lead Source By Outcome','chartType'=>'horizontal group by chart',), + 'Chart_outcome_by_month'=> + array('type'=>'code','id'=>'Chart_outcome_by_month','label'=>'Outcome by Month','chartType'=>'stacked group by chart',), + 'Chart_pipeline_by_lead_source'=> + array('type'=>'code','id'=>'Chart_pipeline_by_lead_source','label'=>'Pipeline By Lead Source','chartType'=>'pie chart',), + 'Chart_my_pipeline_by_sales_stage'=> + array('type'=>'code','id'=>'Chart_pipeline_by_sales_stage','label'=>'My Pipeline by Sales Stage','chartType'=>'funnel chart',), +); \ No newline at end of file diff --git a/modules/Charts/language/en_us.lang.php b/modules/Charts/language/en_us.lang.php new file mode 100644 index 00000000..6ab4d5a3 --- /dev/null +++ b/modules/Charts/language/en_us.lang.php @@ -0,0 +1,104 @@ + 'Please create some Opportunities to see Opportunity graphs.', + 'LBL_ALL_OPPORTUNITIES' => 'Total amount of all opportunities is ', + 'LBL_CHART_TYPE' => 'Chart Type:', + 'LBL_CREATED_ON' => 'Last run on ', + 'LBL_CLOSE_DATE_START' => 'Expected Close Date - From:', + 'LBL_CLOSE_DATE_END' => 'Expected Close Date - To:', + 'LBL_DATE_END' => 'End Date:', + 'LBL_DATE_RANGE_TO' => 'to', + 'LBL_DATE_RANGE' => 'Date range is', + 'LBL_DATE_START' => 'Begin Date:', + 'LBL_EDIT' => 'Edit', + 'LBL_LEAD_SOURCE_BY_OUTCOME_DESC' => 'Shows cumulative opportunity amounts by selected lead source by outcome for selected users. Outcome is based on whether the sales stage is Closed Won, Closed Lost, or any other value.', + 'LBL_LEAD_SOURCE_BY_OUTCOME' => 'All Opportunities By Lead Source By Outcome', + 'LBL_LEAD_SOURCE_FORM_DESC' => 'Shows cumulative opportunity amounts by selected lead source for selected users.', + 'LBL_LEAD_SOURCE_FORM_TITLE' => 'All Opportunities By Lead Source', + 'LBL_LEAD_SOURCE_OTHER' => 'Other', + 'LBL_LEAD_SOURCES' => 'Lead Sources:', + 'LBL_MODULE_NAME' => 'Dashboard', + 'LBL_MODULE_TITLE' => 'Dashboard: Home', + 'LBL_MONTH_BY_OUTCOME_DESC' => 'Shows cumulative opportunity amounts by month by outcome for selected users where the expected closed date is within the specified date range. Outcome is based on whether the sales stage is Closed Won, Closed Lost, or any other value.', + 'LBL_NUMBER_OF_OPPS' => 'Number of Opportunities', + 'LBL_OPP_SIZE' => 'Opportunity size in', + 'LBL_OPP_THOUSANDS'=> 'K', + 'LBL_OPPS_IN_LEAD_SOURCE' => 'opportunities where lead source is', + 'LBL_OPPS_IN_STAGE' => ' where sales stage is', + 'LBL_OPPS_OUTCOME' => ' where outcome is', + 'LBL_OPPS_WORTH' => 'opportunities worth', + 'LBL_PIPELINE_FORM_TITLE_DESC' => 'Shows cumulative amounts by selected sales stages for your opportunities where the expected closed date is within the specified date range.', + 'LBL_CAMPAIGN_ROI_TITLE_DESC' => 'Shows campaign response by return on investment.', + 'LBL_REFRESH' => 'Refresh', + 'LBL_ROLLOVER_DETAILS' => 'Rollover a bar for details.', + 'LBL_ROLLOVER_WEDGE_DETAILS' => 'Rollover a wedge for details.', + 'LBL_SALES_STAGE_FORM_DESC' => 'Shows cumulative opportunity amounts by selected sales stages for selected users where the expected closed date is within the specified date range.', + 'LBL_SALES_STAGE_FORM_TITLE' => 'Pipeline By Sales Stage', + 'LBL_SALES_STAGES' => 'Sales Stages:', + 'LBL_TOTAL_PIPELINE' => 'Pipeline total is ', + 'LBL_USERS' => 'Users:', + 'LBL_YEAR_BY_OUTCOME' => 'Pipeline By Month By Outcome', + 'LBL_YEAR' => 'Year:', + 'LNK_NEW_ACCOUNT' => 'Create Account', + 'LNK_NEW_CALL' => 'Log Call', + 'LNK_NEW_CASE' => 'Create Case', + 'LNK_NEW_CONTACT' => 'Create Contact', + 'LNK_NEW_ISSUE' => 'Report Bug', + 'LNK_NEW_LEAD' => 'Create Lead', + 'LNK_NEW_MEETING' => 'Schedule Meeting', + 'LNK_NEW_NOTE' => 'Create Note or Attachment', + 'LNK_NEW_OPPORTUNITY' => 'Create Opportunity', + 'LNK_NEW_QUOTE' => 'Create Quote', + 'LNK_NEW_TASK' => 'Create Task', + 'NTC_NO_LEGENDS' => 'None', + + 'LBL_TITLE' => 'Title: ', + 'LBL_MY_MODULES_USED_SIZE' => 'Access Count', +); + + +?> \ No newline at end of file diff --git a/modules/Configurator/Configurator.php b/modules/Configurator/Configurator.php new file mode 100644 index 00000000..5e594f10 --- /dev/null +++ b/modules/Configurator/Configurator.php @@ -0,0 +1,291 @@ + ''); + var $logger = NULL; + var $previous_sugar_override_config_array = array(); + var $useAuthenticationClass = false; + + function Configurator() { + $this->loadConfig(); + } + + function loadConfig() { + $this->logger = LoggerManager::getLogger(); + global $sugar_config; + $this->config = $sugar_config; + } + + function populateFromPost() { + $sugarConfig = SugarConfig::getInstance(); + foreach ($_POST as $key => $value) { + if (isset ($this->config[$key]) || in_array($key, $this->allow_undefined)) { + if (strcmp("$value", 'true') == 0) { + $value = true; + } + if (strcmp("$value", 'false') == 0) { + $value = false; + } + $this->config[$key] = $value; + } else { + $v = $sugarConfig->get(str_replace('_', '.', $key)); + if ($v !== null){ + setDeepArrayValue($this->config, $key, $value); + }} + + } + + } + + function handleOverride($fromParseLoggerSettings=false) { + global $sugar_config, $sugar_version; + $sc = SugarConfig::getInstance(); + $overrideArray = $this->readOverride(); + $this->previous_sugar_override_config_array = $overrideArray; + $diffArray = deepArrayDiff($this->config, $sugar_config); + $overrideArray = sugarArrayMergeRecursive($overrideArray, $diffArray); + + // To remember checkbox state + if (!$this->useAuthenticationClass && !$fromParseLoggerSettings) { + if (isset($overrideArray['authenticationClass']) && + $overrideArray['authenticationClass'] == 'SAMLAuthenticate') { + unset($overrideArray['authenticationClass']); + } + } + + $overideString = "config); + $GLOBALS['sugar_config'] = $this->config; + + //print_r($overrideArray); + + foreach($overrideArray as $key => $val) { + if (in_array($key, $this->allow_undefined) || isset ($sugar_config[$key])) { + if (strcmp("$val", 'true') == 0) { + $val = true; + $this->config[$key] = $val; + } + if (strcmp("$val", 'false') == 0) { + $val = false; + $this->config[$key] = false; + } + } + $overideString .= override_value_to_string_recursive2('sugar_config', $key, $val); + } + $overideString .= '/***CONFIGURATOR***/'; + + $this->saveOverride($overideString); + if(isset($this->config['logger']['level']) && $this->logger) $this->logger->setLevel($this->config['logger']['level']); + } + + //bug #27947 , if previous $sugar_config['stack_trace_errors'] is true and now we disable it , we should clear all the cache. + function clearCache(){ + global $sugar_config, $sugar_version; + $currentConfigArray = $this->readOverride(); + foreach($currentConfigArray as $key => $val) { + if (in_array($key, $this->allow_undefined) || isset ($sugar_config[$key])) { + if (empty($val) ) { + if(!empty($this->previous_sugar_override_config_array['stack_trace_errors']) && $key == 'stack_trace_errors'){ + require_once('include/TemplateHandler/TemplateHandler.php'); + TemplateHandler::clearAll(); + return; + } + } + } + } + } + + function saveConfig() { + $this->saveImages(); + $this->populateFromPost(); + $this->handleOverride(); + $this->clearCache(); + } + + function readOverride() { + $sugar_config = array(); + if (file_exists('config_override.php')) { + include('config_override.php'); + } + return $sugar_config; + } + function saveOverride($override) { + $fp = sugar_fopen('config_override.php', 'w'); + fwrite($fp, $override); + fclose($fp); + } + + function overrideClearDuplicates($array_name, $key) { + if (!empty ($this->override)) { + $pattern = '/.*CONFIGURATOR[^\$]*\$'.$array_name.'\[\''.$key.'\'\][\ ]*=[\ ]*[^;]*;\n/'; + $this->override = preg_replace($pattern, '', $this->override); + } else { + $this->override = ""; + } + + } + + function replaceOverride($array_name, $key, $value) { + $GLOBALS[$array_name][$key] = $value; + $this->overrideClearDuplicates($array_name, $key); + $new_entry = '/***CONFIGURATOR***/'.override_value_to_string($array_name, $key, $value); + $this->override = str_replace('?>', "$new_entry\n?>", $this->override); + } + + function restoreConfig() { + $this->readOverride(); + $this->overrideClearDuplicates('sugar_config', '[a-zA-Z0-9\_]+'); + $this->saveOverride(); + ob_clean(); + header('Location: index.php?action=EditView&module=Configurator'); + } + + function saveImages() { + if (!empty ($_POST['company_logo'])) { + $this->saveCompanyLogo($_POST['company_logo']); + } + } + + function checkTempImage($path){ + $exists = false; + if(file_exists($path)){ + $supportedExtensions = array('jpg', 'png', 'jpeg'); + $img_size = getimagesize($path); + $filetype = $img_size['mime']; + $ext = end(explode(".", $path)); + $exists = true; + } + if(!$exists || substr_count('..', $path) > 0 || $ext === $path || !in_array($ext, $supportedExtensions) || ($filetype != 'image/jpeg' && $filetype != 'image/png') ){ + $GLOBALS['log']->fatal("A user ({$GLOBALS['current_user']->id}) attempted to use an invalid file for the logo - {$path}"); + sugar_die('Invalid File Type'); + } + return $path; + } + /** + * Saves the company logo to the custom directory for the default theme, so all themes can use it + * + * @param string $path path to the image to set as the company logo image + */ + function saveCompanyLogo($path) + { + $path = $this->checkTempImage($path); + mkdir_recursive('custom/'.SugarThemeRegistry::current()->getDefaultImagePath(), true); + copy($path,'custom/'. SugarThemeRegistry::current()->getDefaultImagePath(). '/company_logo.png'); + sugar_cache_clear('company_logo_attributes'); + SugarThemeRegistry::clearAllCaches(); + } + /** + * @params : none + * @return : An array of logger configuration properties including log size, file extensions etc. See SugarLogger for more details. + * Parses the old logger settings from the log4php.properties files. + * + */ + + function parseLoggerSettings(){ + if(!function_exists('setDeepArrayValue')){ + require('include/utils/array_utils.php'); + } + if (file_exists('log4php.properties')) { + $fileContent = file_get_contents('log4php.properties'); + $old_props = explode('\n', $fileContent); + $new_props = array(); + $key_names=array(); + foreach($old_props as $value) { + if(!empty($value) && !preg_match("/^\/\//", $value)) { + $temp = explode("=",$value); + $property = isset( $temp[1])? $temp[1] : array(); + if(preg_match("/log4php.appender.A2.MaxFileSize=/",$value)){ + setDeepArrayValue($this->config, 'logger_file_maxSize', rtrim( $property)); + } + elseif(preg_match("/log4php.appender.A2.File=/", $value)){ + $ext = preg_split("/\./",$property); + if(preg_match( "/^\./", $property)){ //begins with . + setDeepArrayValue($this->config, 'logger_file_ext', isset($ext[2]) ? '.' . rtrim( $ext[2]):'.log'); + setDeepArrayValue($this->config, 'logger_file_name', rtrim( ".".$ext[1])); + }else{ + setDeepArrayValue($this->config, 'logger_file_ext', isset($ext[1]) ? '.' . rtrim( $ext[1]):'.log'); + setDeepArrayValue($this->config, 'logger_file_name', rtrim( $ext[0] )); + } + }elseif(preg_match("/log4php.appender.A2.layout.DateFormat=/",$value)){ + setDeepArrayValue($this->config, 'logger_file_dateFormat', trim(rtrim( $property), '""')); + + }elseif(preg_match("/log4php.rootLogger=/",$value)){ + $property = explode(",",$property); + setDeepArrayValue($this->config, 'logger_level', rtrim( $property[0])); + } + } + } + setDeepArrayValue($this->config, 'logger_file_maxLogs', 10); + setDeepArrayValue($this->config, 'logger_file_suffix', "%m_%Y"); + $this->handleOverride(); + unlink('log4php.properties'); + $GLOBALS['sugar_config'] = $this->config; //load the rest of the sugar_config settings. + require_once('include/SugarLogger/SugarLogger.php'); + //$logger = new SugarLogger(); //this will create the log file. + + } + + if (!isset($this->config['logger']) || empty($this->config['logger'])) { + $this->config['logger'] = array ( + 'file' => array( + 'ext' => '.log', + 'name' => 'sugarcrm', + 'dateFormat' => '%c', + 'maxSize' => '10MB', + 'maxLogs' => 10, + 'suffix' => '%m_%Y'), + 'level' => 'fatal'); + } + $this->handleOverride(true); + + + } + + + + +} +?> diff --git a/modules/Configurator/Forms.php b/modules/Configurator/Forms.php new file mode 100644 index 00000000..1a014391 --- /dev/null +++ b/modules/Configurator/Forms.php @@ -0,0 +1,104 @@ + + + + +EOQ; +} + + +?> diff --git a/modules/Configurator/LogView.php b/modules/Configurator/LogView.php new file mode 100644 index 00000000..d1d42c93 --- /dev/null +++ b/modules/Configurator/LogView.php @@ -0,0 +1,154 @@ + + + + + + + + +
    +{$mod_strings['LBL_SEARCH']}  {$mod_strings['LBL_REG_EXP']} +
    +{$mod_strings['LBL_IGNORE_SELF']} + +EOQ; + +define('PROCESS_ID', 1); +define('LOG_LEVEL', 2); +define('LOG_NAME', 3); +define('LOG_DATA', 4); +$logFile = $sugar_config['log_dir'].'/'.$sugar_config['log_file']; + +if (!file_exists($logFile)) { + die('No Log File'); +} +$lastMatch = false; +$doaction =(!empty($_REQUEST['doaction']))?$_REQUEST['doaction']:''; + +switch($doaction){ + case 'mark': + echo "

    {$mod_strings['LBL_MARKING_WHERE_START_LOGGING']}


    "; + $_SESSION['log_file_size'] = filesize($logFile); + break; + case 'next': + if(!empty($_SESSION['last_log_file_size'])){ + $_SESSION['log_file_size'] = $_SESSION['last_log_file_size']; + }else{ + $_SESSION['log_file_size'] = 0; + } + $_REQUEST['display'] = true; + break; + case 'all': + $_SESSION['log_file_size'] = 0; + $_REQUEST['display'] = true; + break; +} + + +if (!empty ($_REQUEST['display'])) { + echo "

    {$mod_strings['LBL_DISPLAYING_LOG']}

    "; + $process_id = getmypid(); + + echo $mod_strings['LBL_YOUR_PROCESS_ID'].' [' . $process_id. ']'; + echo '
    '.$mod_strings['LBL_YOUR_IP_ADDRESS'].' ' . $_SERVER['REMOTE_ADDR']; + if($ignore_self){ + echo $mod_strings['LBL_IT_WILL_BE_IGNORED']; + } + if (empty ($_SESSION['log_file_size'])) { + $_SESSION['log_file_size'] = 0; + } + $cur_size = filesize($logFile); + $_SESSION['last_log_file_size'] = $cur_size; + $pos = 0; + if ($cur_size >= $_SESSION['log_file_size']) { + $pos = $_SESSION['log_file_size'] - $cur_size; + } + if($_SESSION['log_file_size'] == $cur_size){ + echo $mod_strings['LBL_LOG_NOT_CHANGED'].'
    '; + }else{ + $fp = sugar_fopen($logFile, 'r'); + fseek($fp, $pos , SEEK_END); + echo '
    ';
    +		while($line = fgets($fp)){
    +			
    +			//preg_match('/[^\]]*\[([0-9]*)\] ([a-zA-Z]+) ([a-zA-Z0-9\.]+) - (.*)/', $line, $result);
    +			preg_match('/[^\]]*\[([0-9]*)\]/', $line, $result);
    +			ob_flush();
    +			flush();
    +			if(empty($result) && $lastMatch){
    +				echo $line;	
    +			}else{
    +				$lastMatch = false;
    +				if(empty($result) || ($ignore_self &&$result[LOG_NAME] == $_SERVER['REMOTE_ADDR'] )){
    +					
    +				}else{
    +					if(empty($filter) || (!$reg_ex && substr_count($line, $filter) > 0) || ($reg_ex && preg_match($filter, $line))){
    +						$lastMatch = true;
    +						echo $line;	
    +					}	
    +				}
    +			}	
    +		}
    +		echo '
    '; + fclose($fp); + + } +} +?> diff --git a/modules/Configurator/Menu.php b/modules/Configurator/Menu.php new file mode 100644 index 00000000..6c8b2cb4 --- /dev/null +++ b/modules/Configurator/Menu.php @@ -0,0 +1,43 @@ +decode(html_entity_decode($_REQUEST['forQuotes']))){ + $returnArray['forQuotes']="quotes"; +}else{ + $returnArray['forQuotes']="company"; +} +if(isset($_FILES['file_1'])){ + $uploadTmpDir=$sugar_config['tmp_dir'].'tmp_logo_'.$returnArray['forQuotes'].'_upload'; + $file_name = $uploadTmpDir . DIRECTORY_SEPARATOR . cleanFileName(basename($_FILES['file_1']['name'])); + if(file_exists($uploadTmpDir)) + rmdir_recursive($uploadTmpDir); + + mkdir_recursive( $uploadTmpDir,null,true ); + if (!empty($_FILES['file_1']['error'])){ + rmdir_recursive($uploadTmpDir); + $returnArray['data']='not_recognize'; + echo $json->encode($returnArray); + sugar_cleanup(); + exit(); + } + if (!move_uploaded_file($_FILES['file_1']['tmp_name'], $file_name)){ + rmdir_recursive($uploadTmpDir); + die("Possible file upload attack!\n"); + } +}else{ + $returnArray['data']='not_recognize'; + echo $json->encode($returnArray); + sugar_cleanup(); + exit(); +} +if(file_exists($file_name) && is_file($file_name)){ + $returnArray['path']=$file_name; + $img_size = getimagesize($file_name); + $filetype = $img_size['mime']; + $ext = end(explode(".", $file_name)); + if($ext === $file_name || !in_array($ext, $supportedExtensions) || ($filetype != 'image/jpeg' && $filetype != 'image/png') || ($filetype != 'image/jpeg' && $returnArray['forQuotes'] == 'quotes')){ + $returnArray['data']='other'; + $returnArray['path'] = ''; + + }else{ + $test=$img_size[0]/$img_size[1]; + if (($test>10 || $test<1) && $returnArray['forQuotes'] == 'company'){ + $rmdir=false; + $returnArray['data']='size'; + } + if (($test>20 || $test<3)&& $returnArray['forQuotes'] == 'quotes') + $returnArray['data']='size'; + } + if(!empty($returnArray['data'])){ + echo $json->encode($returnArray); + }else{ + $rmdir=false; + $returnArray['data']='ok'; + echo $json->encode($returnArray); + } +}else{ + $returnArray['data']='file_error'; + echo $json->encode($returnArray); +} +if($rmdir) + rmdir_recursive($uploadTmpDir); +sugar_cleanup(); +exit(); +?> diff --git a/modules/Configurator/action_view_map.php b/modules/Configurator/action_view_map.php new file mode 100644 index 00000000..13241121 --- /dev/null +++ b/modules/Configurator/action_view_map.php @@ -0,0 +1,39 @@ +view = 'fontmanager'; + } + + /** + * Delete a font and go back to the font manager + */ + function action_deleteFont(){ + global $current_user; + if(!is_admin($current_user)){ + sugar_die($GLOBALS['app_strings']['ERR_NOT_ADMIN']); + } + $urlSTR = 'index.php?module=Configurator&action=FontManager'; + if(!empty($_REQUEST['filename'])){ + require_once('include/Sugarpdf/FontManager.php'); + $fontManager = new FontManager(); + $fontManager->filename = $_REQUEST['filename']; + if(!$fontManager->deleteFont()){ + $urlSTR .='&error='.urlencode(implode("
    ",$fontManager->errors)); + } + } + header("Location: $urlSTR"); + } + + function action_listview(){ + global $current_user; + if(!is_admin($current_user)){ + sugar_die($GLOBALS['app_strings']['ERR_NOT_ADMIN']); + } + $this->view = 'edit'; + } + /** + * Show the addFont view + */ + function action_addFontView(){ + global $current_user; + if(!is_admin($current_user)){ + sugar_die($GLOBALS['app_strings']['ERR_NOT_ADMIN']); + } + $this->view = 'addFontView'; + } + /** + * Add a new font and show the addFontResult view + */ + function action_addFont(){ + global $current_user, $mod_strings; + if(!is_admin($current_user)){ + sugar_die($GLOBALS['app_strings']['ERR_NOT_ADMIN']); + } + if(empty($_FILES['pdf_metric_file']['name'])){ + $this->errors[]=translate("ERR_MISSING_REQUIRED_FIELDS")." ".translate("LBL_PDF_METRIC_FILE", "Configurator"); + $this->view = 'addFontView'; + return; + } + if(empty($_FILES['pdf_font_file']['name'])){ + $this->errors[]=translate("ERR_MISSING_REQUIRED_FIELDS")." ".translate("LBL_PDF_FONT_FILE", "Configurator"); + $this->view = 'addFontView'; + return; + } + $path_info = pathinfo($_FILES['pdf_font_file']['name']); + $path_info_metric = pathinfo($_FILES['pdf_metric_file']['name']); + if(($path_info_metric['extension']!="afm" && $path_info_metric['extension']!="ufm") || + ($path_info['extension']!="ttf" && $path_info['extension']!="otf" && $path_info['extension']!="pfb")){ + $this->errors[]=translate("JS_ALERT_PDF_WRONG_EXTENSION", "Configurator"); + $this->view = 'addFontView'; + return; + } + + if($_REQUEST['pdf_embedded'] == "false"){ + if(empty($_REQUEST['pdf_cidinfo'])){ + $this->errors[]=translate("ERR_MISSING_CIDINFO", "Configurator"); + $this->view = 'addFontView'; + return; + } + $_REQUEST['pdf_embedded']=false; + }else{ + $_REQUEST['pdf_embedded']=true; + $_REQUEST['pdf_cidinfo']=""; + } + if(empty($_REQUEST['pdf_patch'])){ + $_REQUEST['pdf_patch']="return array();"; + }else{ + $_REQUEST['pdf_patch']="return {$_REQUEST['pdf_patch']};"; + } + $this->view = 'addFontResult'; + } + function action_saveadminwizard() + { + global $current_user; + if(!is_admin($current_user)){ + sugar_die($GLOBALS['app_strings']['ERR_NOT_ADMIN']); + } + $focus = new Administration(); + $focus->retrieveSettings(); + $focus->saveConfig(); + + $configurator = new Configurator(); + $configurator->populateFromPost(); + $configurator->handleOverride(); + $configurator->parseLoggerSettings(); + $configurator->saveConfig(); + + // Bug 37310 - Delete any existing currency that matches the one we've just set the default to during the admin wizard + $currency = new Currency; + $currency->retrieve($currency->retrieve_id_by_name($_REQUEST['default_currency_name'])); + if ( !empty($currency->id) + && $currency->symbol == $_REQUEST['default_currency_symbol'] + && $currency->iso4217 == $_REQUEST['default_currency_iso4217'] ) { + $currency->deleted = 1; + $currency->save(); + } + + SugarApplication::redirect('index.php?module=Users&action=Wizard&skipwelcome=1'); + } + + function action_saveconfig() + { + global $current_user; + if(!is_admin($current_user)){ + sugar_die($GLOBALS['app_strings']['ERR_NOT_ADMIN']); + } + $configurator = new Configurator(); + $configurator->saveConfig(); + + $focus = new Administration(); + $focus->saveConfig(); + + // Clear the Contacts file b/c portal flag affects rendering + if (file_exists($GLOBALS['sugar_config']['cache_dir'].'modules/Contacts/EditView.tpl')) + unlink($GLOBALS['sugar_config']['cache_dir'].'modules/Contacts/EditView.tpl'); + + SugarApplication::redirect('index.php?module=Administration&action=index'); + } + + function action_detail() + { + global $current_user; + if(!is_admin($current_user)){ + sugar_die($GLOBALS['app_strings']['ERR_NOT_ADMIN']); + } + $this->view = 'edit'; + } +} diff --git a/modules/Configurator/language/en_us.lang.php b/modules/Configurator/language/en_us.lang.php new file mode 100644 index 00000000..5fc706c5 --- /dev/null +++ b/modules/Configurator/language/en_us.lang.php @@ -0,0 +1,419 @@ +'Admin export only',*/ + 'ADVANCED'=>'Advanced', + 'DEFAULT_CURRENCY_ISO4217'=>'ISO 4217 currency code', + 'DEFAULT_CURRENCY_NAME'=>'Currency name', + 'DEFAULT_CURRENCY_SYMBOL'=>'Currency symbol', + 'DEFAULT_CURRENCY'=>'Default Currency', + 'DEFAULT_DATE_FORMAT'=>'Default date format', + 'DEFAULT_DECIMAL_SEP' => 'Decimal symbol', + 'DEFAULT_LANGUAGE'=>'Default language', + 'DEFAULT_NUMBER_GROUPING_SEP' => '1000s separator', + 'DEFAULT_SYSTEM_SETTINGS'=>'User Interface', + 'DEFAULT_THEME'=> 'Default theme', + 'DEFAULT_TIME_FORMAT'=>'Default time format', +/* 'DISABLE_EXPORT'=>'Disable export',*/ + 'DISPLAY_RESPONSE_TIME'=>'Display server response times', + /*'EXPORT'=>'Export', + 'EXPORT_CHARSET' => 'Default Export Character Set', + 'EXPORT_DELIMITER' => 'Export Delimiter',*/ + 'IMAGES'=>'Logos', + 'LBL_ADMIN_WIZARD' => 'Admin Wizard', + 'LBL_ALLOW_USER_TABS' => 'Allow users to hide tabs', + 'LBL_CONFIGURE_SETTINGS_TITLE' => 'System Settings', + 'LBL_ENABLE_MAILMERGE' => 'Enable mail merge?', + 'LBL_LOGVIEW' => 'View Log', + 'LBL_MAIL_SMTPAUTH_REQ' => 'Use SMTP Authentication?', + 'LBL_MAIL_SMTPPASS' => 'SMTP Password:', + 'LBL_MAIL_SMTPPORT' => 'SMTP Port:', + 'LBL_MAIL_SMTPSERVER' => 'SMTP Server:', + 'LBL_MAIL_SMTPUSER' => 'SMTP Username:', + 'LBL_MAIL_SMTPTYPE' => 'SMTP Server Type:', + 'LBL_MAIL_SMTP_SETTINGS' => 'SMTP Server Specification', + 'LBL_CHOOSE_EMAIL_PROVIDER' => 'Choose your Email provider:', + 'LBL_YAHOOMAIL_SMTPPASS' => 'Yahoo! Mail Password:', + 'LBL_YAHOOMAIL_SMTPUSER' => 'Yahoo! Mail ID:', + 'LBL_GMAIL_SMTPPASS' => 'Gmail Password:', + 'LBL_GMAIL_SMTPUSER' => 'Gmail Email Address:', + 'LBL_EXCHANGE_SMTPPASS' => 'Exchange Password:', + 'LBL_EXCHANGE_SMTPUSER' => 'Exchange Username:', + 'LBL_EXCHANGE_SMTPPORT' => 'Exchange Server Port:', + 'LBL_EXCHANGE_SMTPSERVER' => 'Exchange Server:', + 'LBL_ALLOW_DEFAULT_SELECTION' => 'Allow users to use this account for outgoing email:', + 'LBL_ALLOW_DEFAULT_SELECTION_HELP' => 'When this option is selected, all users will be able to send emails using the same outgoing mail account used to send system notifications and alerts. If the option is not selected, users can still use the outgoing mail server after providing their own account information.', + 'LBL_MAILMERGE_DESC' => 'This flag should be checked only if you have the Sugar Plug-in for Microsoft® Word®.', + 'LBL_MAILMERGE' => 'Mail Merge', + 'LBL_MIN_AUTO_REFRESH_INTERVAL' => 'Minimum Dashlet Auto-Refresh Interval', + 'LBL_MIN_AUTO_REFRESH_INTERVAL_HELP' => 'This is the minimum value one can choose to have dashlets auto-refresh. Setting to \'Never\' disables auto-refreshing of dashlets entirely.', + 'LBL_MODULE_FAVICON' => 'Display module icon as favicon', + 'LBL_MODULE_FAVICON_HELP' => 'If you are in a module with an icon, use the module\'s icon as the favicon, instead of the theme\'s favicon, in the browser tab.', + 'LBL_MODULE_NAME'=>'System Settings', + 'LBL_MODULE_ID' => 'Configurator', + 'LBL_MODULE_TITLE'=>'User Interface', + 'LBL_NOTIFY_FROMADDRESS' => '\'From\' Address:', + 'LBL_NOTIFY_SUBJECT' => 'Email subject:', + 'LBL_PORTAL_ON_DESC' => 'Allows users to manage portal user information within contact records. Portal users can access Cases, Bugs, Knowledge Base articles and other data through the Sugar Portal application.', + 'LBL_PORTAL_ON' => 'Enable Portal User Management', + 'LBL_PORTAL_TITLE' => 'Customer Self-Service Portal', + 'LBL_PROXY_AUTH'=>'Authentication?', + 'LBL_PROXY_HOST'=>'Proxy Host', + 'LBL_PROXY_ON_DESC'=>'Configure proxy server address and authentication settings', + 'LBL_PROXY_ON'=>'Use proxy server?', + 'LBL_PROXY_PASSWORD'=>'Password', + 'LBL_PROXY_PORT'=>'Port', + 'LBL_PROXY_TITLE'=>'Proxy Settings', + 'LBL_PROXY_USERNAME'=>'User Name', + 'LBL_RESTORE_BUTTON_LABEL'=>'Restore', + 'LBL_SYSTEM_SETTINGS' => 'System Settings', + 'LBL_SKYPEOUT_ON_DESC' => 'Allows users to click on phone numbers to call using SkypeOut®. The numbers must be formatted properly to make use of this feature. That is, it must be "+" "The Country Code" "The Number", like +1 (555) 555-1234.', + 'LBL_SKYPEOUT_ON' => 'Enable SkypeOut® integration', + 'LBL_SKYPEOUT_TITLE' => 'SkypeOut®', + 'LBL_USE_REAL_NAMES' => 'Show Full Names', + 'LBL_USE_REAL_NAMES_DESC' => 'Display users\' full names instead of their User Names in assignment fields.', + 'LIST_ENTRIES_PER_LISTVIEW'=>'Listview items per page', + 'LIST_ENTRIES_PER_SUBPANEL'=>'Subpanel items per page', + 'LOG_MEMORY_USAGE'=>'Log memory usage', + 'LOG_SLOW_QUERIES'=>'Log slow queries', + 'LOCK_HOMEPAGE_HELP'=>'This setting is to prevent
    1) the addition of any dashlets to the home page,
    2) customization of dashlet placement in the home pages by dragging and dropping.', + 'CURRENT_LOGO'=>'Current Logo:', + 'CURRENT_LOGO_HELP'=>'This logo is displayed at the top left-hand corner of the Sugar application.', + 'NEW_LOGO'=>'Select Logo:', + 'NEW_LOGO_HELP'=>'The image file format can be either .png or .jpg.
    The recommended size is 212x40 px.', + 'NEW_QUOTE_LOGO'=>'Upload new Quotes logo', + 'NEW_QUOTE_LOGO_HELP'=>'The required image file format is .jpg.
    The recommended size is 867x74 px.', + 'QUOTES_CURRENT_LOGO'=>'Quotes logo', + 'SLOW_QUERY_TIME_MSEC'=>'Slow query time threshold (msec)', + 'STACK_TRACE_ERRORS'=>'Display stack trace of errors', + 'UPLOAD_MAX_SIZE'=>'Maximum upload size', + 'VERIFY_CLIENT_IP'=>'Validate user IP address', + 'LOCK_HOMEPAGE' => 'Prevent user customizable Homepage layout', + 'LOCK_SUBPANELS' => 'Prevent user customizable subpanel layout', + 'MAX_DASHLETS' => 'Maximum number of Sugar Dashlets on Homepage', + 'SYSTEM_NAME'=>'System Name:', + 'SYSTEM_NAME_WIZARD'=>'Name:', + 'SYSTEM_NAME_HELP'=>'This is the name that displays in the title bar of your browser.', + 'LBL_LDAP_TITLE'=>'LDAP Authentication Support', + 'LBL_LDAP_ENABLE'=>'Enable LDAP', + 'LBL_LDAP_SERVER_HOSTNAME'=> 'Server:', + 'LBL_LDAP_SERVER_PORT'=> 'Port Number:', + 'LBL_LDAP_ADMIN_USER'=> 'User Name:', + 'LBL_LDAP_ADMIN_USER_DESC'=>'Used to search for the Sugar user. [May need to be fully qualified] It will bind anonymously if not provided.', + 'LBL_LDAP_ADMIN_PASSWORD'=> 'Password:', + 'LBL_LDAP_AUTHENTICATION'=> 'Authentication:', + 'LBL_LDAP_AUTHENTICATION_DESC'=>'Bind to the LDAP server using a specific users credentials', + 'LBL_LDAP_AUTO_CREATE_USERS'=>'Auto Create Users:', + 'LBL_LDAP_USER_DN'=>'User DN:', + 'LBL_LDAP_GROUP_DN'=>'Group DN:', + 'LBL_LDAP_GROUP_DN_DESC'=>'Example: ou=groups,dc=example,dc=com', + 'LBL_LDAP_USER_FILTER'=>'User Filter:', + 'LBL_LDAP_GROUP_MEMBERSHIP'=>'Group Membership:', + 'LBL_LDAP_GROUP_MEMBERSHIP_DESC'=>'Users must be a member of a specific group', + 'LBL_LDAP_GROUP_USER_ATTR'=>'User Attribute:', + 'LBL_LDAP_GROUP_USER_ATTR_DESC'=>'The unique identifier of the person that will be used to check if they are a member of the group Example: uid', + 'LBL_LDAP_GROUP_ATTR_DESC'=>'The attribute of the Group that will be used to filter against the User Attribute Example: memberUid', + 'LBL_LDAP_GROUP_ATTR'=>'Group Attribute:', + 'LBL_LDAP_USER_FILTER_DESC'=>'Any additional filter params to apply when authenticating users e.g.is_sugar_user=1 or (is_sugar_user=1)(is_sales=1)', + 'LBL_LDAP_LOGIN_ATTRIBUTE'=>'Login Attribute:', + 'LBL_LDAP_BIND_ATTRIBUTE'=>'Bind Attribute:', + 'LBL_LDAP_BIND_ATTRIBUTE_DESC'=>'For Binding the LDAP User Examples:[AD: userPrincipalName] [openLDAP: userPrincipalName] [Mac OS X: uid] ', + 'LBL_LDAP_LOGIN_ATTRIBUTE_DESC'=>'For searching for the LDAP User Examples:[AD: userPrincipalName] [openLDAP: dn] [Mac OS X: dn] ', + 'LBL_LDAP_SERVER_HOSTNAME_DESC'=>'Example: ldap.example.com or ldaps://ldap.example.com for SSL', + 'LBL_LDAP_SERVER_PORT_DESC'=>'Example: 389 or 636 for SSL', + 'LBL_LDAP_GROUP_NAME'=>'Group Name:', + 'LBL_LDAP_GROUP_NAME_DESC'=>'Example cn=sugarcrm', + 'LBL_LDAP_USER_DN_DESC'=>'Example: ou=people,dc=example,dc=com', + 'LBL_LDAP_AUTO_CREATE_USERS_DESC'=> 'If an authenticated user does not exist one will be created in Sugar.', + 'LBL_LDAP_ENC_KEY' => 'Encryption Key:', + 'DEVELOPER_MODE'=>'Developer Mode', + + 'SHOW_DOWNLOADS_TAB' =>'Display Downloads Tab', + 'SHOW_DOWNLOADS_TAB_HELP' =>'When selected, the Download tab will appear in the User settings and provide users with access to Sugar plug-ins and other available files', + 'LBL_LDAP_ENC_KEY_DESC' => 'For SOAP authentication when using LDAP.', + 'LDAP_ENC_KEY_NO_FUNC_DESC' => 'The php_mcrypt extension must be enabled in your php.ini file.', + 'LBL_ALL' => 'All', + 'LBL_MARK_POINT' => 'Mark Point', + 'LBL_NEXT_' => 'Next>>', + 'LBL_REFRESH_FROM_MARK' => 'Refresh From Mark', + 'LBL_SEARCH' => 'Search:', + 'LBL_REG_EXP' => 'Reg Exp:', + 'LBL_IGNORE_SELF' => 'Ignore Self:', + 'LBL_MARKING_WHERE_START_LOGGING'=>'Marking Where To Start Logging From', + 'LBL_DISPLAYING_LOG'=>'Displaying Log', + 'LBL_YOUR_PROCESS_ID'=>'Your process ID', + 'LBL_YOUR_IP_ADDRESS'=>'Your IP Address is', + 'LBL_IT_WILL_BE_IGNORED'=>' It will be ignored ', + 'LBL_LOG_NOT_CHANGED'=>'Log has not changed', + 'LBL_ALERT_JPG_IMAGE' => 'The file format of the image must be JPEG. Upload a new file with the file extension .jpg.', + 'LBL_ALERT_TYPE_IMAGE' => 'The file format of the image must be JPEG or PNG. Upload a new file with the file extension .jpg or .png.', + 'LBL_ALERT_SIZE_RATIO' => 'The aspect ratio of the image should be between 1:1 and 10:1. The image will be resized.', + 'LBL_ALERT_SIZE_RATIO_QUOTES' => 'The aspect ratio of the image must be between 3:1 and 20:1. Upload a new file with this ratio.', + 'ERR_ALERT_FILE_UPLOAD' => 'Error during the upload of the image.', + 'LBL_LOGGER'=>'Logger Settings', + 'LBL_LOGGER_FILENAME'=>'Log File Name', + 'LBL_LOGGER_FILE_EXTENSION'=>'Extension', + 'LBL_LOGGER_MAX_LOG_SIZE'=>'Maximum log size', + 'LBL_LOGGER_DEFAULT_DATE_FORMAT'=>'Default date format', + 'LBL_LOGGER_LOG_LEVEL'=>'Log Level', + 'LBL_LOGGER_MAX_LOGS'=>'Maximum number of logs (before rolling)', + 'LBL_LOGGER_FILENAME_SUFFIX' =>'Append after filename', + 'LBL_VCAL_PERIOD' => 'vCal Updates Time Period:', + 'vCAL_HELP' => 'Use this setting to determine the number of months in advance of the current date that Free/Busy information for calls and meetings is published.
    To turn Free/Busy publishing off, enter "0". The minimum is 1 month; the maximum is 12 months.', + 'LBL_PDFMODULE_NAME' => 'PDF Settings', + 'SUGARPDF_BASIC_SETTINGS' => 'Document Properties', + 'SUGARPDF_ADVANCED_SETTINGS' => 'Advanced Settings', + 'SUGARPDF_LOGO_SETTINGS' => 'Images', + + 'PDF_CREATOR' => 'PDF Creator', + 'PDF_CREATOR_INFO' => 'Defines the creator of the document.
    This is typically the name of the application that generates the PDF.', + + 'PDF_AUTHOR' => 'Author', + 'PDF_AUTHOR_INFO' => 'The Author appears in the document properties.', + + 'PDF_HEADER_LOGO' => 'For Quotes PDF Documents', + 'PDF_HEADER_LOGO_INFO' => 'This image appears in the default Header in Quotes PDF Documents.', + + 'PDF_NEW_HEADER_LOGO' => 'Select New Image for Quotes', + 'PDF_NEW_HEADER_LOGO_INFO' => 'The file format can be either .jpg or .png. (Only .jpg for EZPDF)
    The recommended size is 867x74 px.', + + 'PDF_HEADER_LOGO_WIDTH' => 'Quotes Image Width', + 'PDF_HEADER_LOGO_WIDTH_INFO' => 'Change the scale of the uploaded image that appears in Quotes PDF Documents. (TCPDF only)', + + 'PDF_SMALL_HEADER_LOGO' => 'For Reports PDF Documents', + 'PDF_SMALL_HEADER_LOGO_INFO' => 'This image appears in the default Header in Reports PDF Documents.
    This image also appears in the top left-hand corner of the Sugar application.', + + 'PDF_NEW_SMALL_HEADER_LOGO' => 'Select New Image for Reports', + 'PDF_NEW_SMALL_HEADER_LOGO_INFO' => 'The file format can be either .jpg or .png. (Only .jpg for EZPDF)
    The recommended size is 212x40 px.', + + 'PDF_SMALL_HEADER_LOGO_WIDTH' => 'Reports Image Width', + 'PDF_SMALL_HEADER_LOGO_WIDTH_INFO' => 'Change the scale of the uploaded image that appears in Reports PDF Documents. (TCPDF only)', + + + 'PDF_HEADER_STRING' => 'Header String', + 'PDF_HEADER_STRING_INFO' => 'Header description string', + + 'PDF_HEADER_TITLE' => 'Header Title', + 'PDF_HEADER_TITLE_INFO' => 'String to print as title on document header', + + 'PDF_FILENAME' => 'Default Filename', + 'PDF_FILENAME_INFO' => 'Default filename for the generated PDF files', + + 'PDF_TITLE' => 'Title', + 'PDF_TITLE_INFO' => 'The Title appears in the document properties.', + + 'PDF_SUBJECT' => 'Subject', + 'PDF_SUBJECT_INFO' => 'The Subject appears in the document properties.', + + 'PDF_KEYWORDS' => 'Keyword(s)', + 'PDF_KEYWORDS_INFO' => 'Associate Keywords with the document, generally in the form "keyword1 keyword2..."', + + 'PDF_COMPRESSION' => 'Compression', + 'PDF_COMPRESSION_INFO' => 'Activates or deactivates page compression.
    When activated, the internal representation of each page is compressed, which leads to a compression ratio of about 2 for the resulting document.', + + 'PDF_JPEG_QUALITY' => 'JPEG Quality (1-100)', + 'PDF_JPEG_QUALITY_INFO' => 'Set the default JPEG compression quality (1-100)', + + 'PDF_PDF_VERSION' => 'PDF Version', + 'PDF_PDF_VERSION_INFO' => 'Set the PDF version (check PDF reference for valid values).', + + 'PDF_PROTECTION' => 'Document Protection', + 'PDF_PROTECTION_INFO' => 'Set document protection
    - copy: copy text and images to the clipboard
    - print: print the document
    - modify: modify it (except for annotations and forms)
    - annot-forms: add annotations and forms
    Note: the protection against modification is for people who have the full Acrobat product.', + + 'PDF_USER_PASSWORD' => 'User Password', + 'PDF_USER_PASSWORD_INFO' => 'If you don\\\'t set any password, the document will open as usual.
    If you set a user password, the PDF viewer will ask for it before displaying the document.
    The master password, if different from the user one, can be used to get full access.', + + 'PDF_OWNER_PASSWORD' => 'Owner Password', + 'PDF_OWNER_PASSWORD_INFO' => 'If you don\\\'t set any password, the document will open as usual.
    If you set a user password, the PDF viewer will ask for it before displaying the document.
    The master password, if different from the user one, can be used to get full access.', + + 'PDF_ACL_ACCESS' => 'Access Control', + 'PDF_ACL_ACCESS_INFO' => 'Default Access Control for the PDF generation.', + + 'K_CELL_HEIGHT_RATIO' => 'Cell Height Ratio', + 'K_CELL_HEIGHT_RATIO_INFO' => 'If the height of a cell is smaller than (Font Height x Cell Height Ratio), then (Font Height x Cell Height Ratio) is used as the cell height.
    (Font Height x Cell Height Ratio) is also used as the height of the cell when no height is define.', + + 'K_TITLE_MAGNIFICATION' => 'Title Magnification', + 'K_TITLE_MAGNIFICATION_INFO' => 'Title magnification respect main font size.', + + 'K_SMALL_RATIO' => 'Small Font Factor', + 'K_SMALL_RATIO_INFO' => 'Reduction factor for small font.', + + 'HEAD_MAGNIFICATION' => 'Head Magnification', + 'HEAD_MAGNIFICATION_INFO' => 'Magnification factor for titles.', + + 'PDF_IMAGE_SCALE_RATIO' => 'Image scale ratio', + 'PDF_IMAGE_SCALE_RATIO_INFO' => 'Ratio used to scale the images', + + 'PDF_UNIT' => 'Unit', + 'PDF_UNIT_INFO' => 'document unit of measure', + 'PDF_GD_WARNING'=>'You do not have the GD library installed for PHP. Without the GD library installed, only JPEG logos can be displayed in PDF documents.', + 'ERR_EZPDF_DISABLE'=>'Warning : The EZPDF class is disabled from the config table and it set as the PDF class. Please "Save" this form to set TCPDF as the PDF Class and return in a stable state.', + 'LBL_IMG_RESIZED'=>"(resized for display)", + + + 'LBL_FONTMANAGER_BUTTON' => 'PDF Font Manager', + 'LBL_FONTMANAGER_TITLE' => 'PDF Font Manager', + 'LBL_FONT_BOLD' => 'Bold', + 'LBL_FONT_ITALIC' => 'Italic', + 'LBL_FONT_BOLDITALIC' => 'Bold/Italic', + 'LBL_FONT_REGULAR' => 'Regular', + + 'LBL_FONT_TYPE_CID0' => 'CID-0', + 'LBL_FONT_TYPE_CORE' => 'Core', + 'LBL_FONT_TYPE_TRUETYPE' => 'TrueType', + 'LBL_FONT_TYPE_TYPE1' => 'Type1', + 'LBL_FONT_TYPE_TRUETYPEU' => 'TrueTypeUnicode', + + 'LBL_FONT_LIST_NAME' => 'Name', + 'LBL_FONT_LIST_FILENAME' => 'Filename', + 'LBL_FONT_LIST_TYPE' => 'Type', + 'LBL_FONT_LIST_STYLE' => 'Style', + 'LBL_FONT_LIST_STYLE_INFO' => 'Style of the font', + 'LBL_FONT_LIST_ENC' => 'Encoding', + 'LBL_FONT_LIST_EMBEDDED' => 'Embedded', + 'LBL_FONT_LIST_EMBEDDED_INFO' => 'Check to embed the font into the PDF file', + 'LBL_FONT_LIST_CIDINFO' => 'CID Information', + 'LBL_FONT_LIST_CIDINFO_INFO' => "Examples :". +"
    • ". +"Chinese Traditional :
      ". +"
      \$enc=\'UniCNS-UTF16-H\';
      ". +"\$cidinfo=array(\'Registry\'=>\'Adobe\', \'Ordering\'=>\'CNS1\',\'Supplement\'=>0);
      ". +"include(\'include/tcpdf/fonts/uni2cid_ac15.php\');
      ". +"
    • ". +"Chinese Simplified :
      ". +"
      \$enc=\'UniGB-UTF16-H\';
      ". +"\$cidinfo=array(\'Registry\'=>\'Adobe\', \'Ordering\'=>\'GB1\',\'Supplement\'=>2);
      ". +"include(\'include/tcpdf/fonts/uni2cid_ag15.php\');
      ". +"
    • ". +"Korean :
      ". +"
      \$enc=\'UniKS-UTF16-H\';
      ". +"\$cidinfo=array(\'Registry\'=>\'Adobe\', \'Ordering\'=>\'Korea1\',\'Supplement\'=>0);
      ". +"include(\'include/tcpdf/fonts/uni2cid_ak12.php\');
      ". +"
    • ". +"Japanese :
      ". +"
      \$enc=\'UniJIS-UTF16-H\';
      ". +"\$cidinfo=array(\'Registry\'=>\'Adobe\', \'Ordering\'=>\'Japan1\',\'Supplement\'=>5);
      ". +"include(\'include/tcpdf/fonts/uni2cid_aj16.php\');
      ". +"
    ". +"More help : www.tcpdf.org", + 'LBL_FONT_LIST_FILESIZE' => 'Font Size (KB)', + 'LBL_ADD_FONT' => 'Add a font', + 'LBL_BACK' => 'Back', + 'LBL_REMOVE' => 'rem', + 'LBL_JS_CONFIRM_DELETE_FONT' => 'Are you sure that you want to delete this font?', + + 'LBL_ADDFONT_TITLE' => 'Add a PDF Font', + 'LBL_PDF_PATCH' => 'Patch', + 'LBL_PDF_PATCH_INFO' => 'Custom modification of the encoding. Write a PHP array.
    Example :
    ISO-8859-1 does not contain the euro symbol. To add it at position 164, write "array(164=>\\\'Euro\\\')".', + 'LBL_PDF_ENCODING_TABLE' => 'Encoding Table', + 'LBL_PDF_ENCODING_TABLE_INFO' => 'Name of the encoding table.
    This option is ignored for TrueType Unicode, OpenType Unicode and symbolic fonts.
    The encoding defines the association between a code (from 0 to 255) and a character contained in the font.
    The first 128 are fixed and correspond to ASCII.', + 'LBL_PDF_FONT_FILE' => 'Font File', + 'LBL_PDF_FONT_FILE_INFO' => '.ttf or .otf or .pfb file', + 'LBL_PDF_METRIC_FILE' => 'Metric File', + 'LBL_PDF_METRIC_FILE_INFO' => '.afm or .ufm file', + 'LBL_ADD_FONT_BUTTON' => 'Add', + 'JS_ALERT_PDF_WRONG_EXTENSION' => 'This file do not have a good file extension.', + 'LBL_PDF_INSTRUCTIONS' => 'Instructions', + 'PDF_INSTRUCTIONS_ADD_FONT' => << +
  • TrueTypeUnicode (UTF-8 Unicode)
  • +
  • OpenTypeUnicode
  • +
  • TrueType
  • +
  • OpenType
  • +
  • Type1
  • +
  • CID-0
  • + +
    +If you choose to not embed your font in the PDF, the generated PDF file will be lighter but a substitution will be use if the font is not available in the system of your reader. +

    +Adding a PDF font to SugarCRM requires to follow steps 1 and 2 of the TCPDF Fonts documentation available in the "DOCS" section of the TCPDF website. +

    The pfm2afm and ttf2ufm utils are available in fonts/utils in the TCPDF package that you can download on the "DOWNLOAD" section of the TCPDF website. +

    Load the metric file generated in step 2 and your font file below. +BSOFR +, + 'ERR_MISSING_CIDINFO' => 'The field CID Information cannot be empty.', + 'LBL_ADDFONTRESULT_TITLE' => 'Result of the add font process', + 'LBL_STATUS_FONT_SUCCESS' => 'SUCCESS : The font has been added to SugarCRM.', + 'LBL_STATUS_FONT_ERROR' => 'ERROR : The font has not been added. Look at the log below.', + 'LBL_FONT_MOVE_DEFFILE' => 'Font definition file move to : ', + 'LBL_FONT_MOVE_FILE' => 'Font file move to : ', + +// Font manager + 'ERR_LOADFONTFILE' => 'ERROR: LoadFontFile error!', + 'ERR_FONT_EMPTYFILE' => 'ERROR: Empty filename!', + 'ERR_FONT_UNKNOW_TYPE' => 'ERROR: Unknow font type:', + 'ERR_DELETE_CORE_FILE' => 'ERROR: It is not possible to delete a core font.', + 'ERR_NO_FONT_PATH' => 'ERROR: No font path available!', + 'ERR_NO_CUSTOM_FONT_PATH' => 'ERROR: No custom font path available!', + 'ERR_FONT_NOT_WRITABLE' => 'is not writable.', + 'ERR_FONT_FILE_DO_NOT_EXIST' => 'doesn\'t exist or is not a directory.', + 'ERR_FONT_MAKEFONT' => 'ERROR: MakeFont error', + 'ERR_FONT_ALREADY_EXIST' => 'ERROR : This font already exist. Rollback...', + 'ERR_PDF_NO_UPLOAD' => 'Error during the upload of the font or metric file.', + +// Wizard + 'LBL_WIZARD_TITLE' => 'Admin Wizard', + 'LBL_WIZARD_WELCOME_TAB' => 'Welcome', + 'LBL_WIZARD_WELCOME_TITLE' => 'Welcome to Sugar!', + 'LBL_WIZARD_WELCOME' => 'Click Next to brand, localize and configure Sugar now. If you wish to configure Sugar later, click Skip.', + 'LBL_WIZARD_NEXT_BUTTON' => 'Next >', + 'LBL_WIZARD_BACK_BUTTON' => '< Back', + 'LBL_WIZARD_SKIP_BUTTON' => 'Skip', + 'LBL_WIZARD_FINISH_BUTTON' => 'Finish', + 'LBL_WIZARD_CONTINUE_BUTTON' => 'Continue', + 'LBL_WIZARD_FINISH_TAB' => 'Finish', + 'LBL_WIZARD_FINISH_TITLE' => 'Basic system configuration is complete', + 'LBL_WIZARD_FINISH' => 'Click Continue to configure your user settings.

    +To configure additional system settings, click here.', + 'LBL_WIZARD_SYSTEM_TITLE' => 'Branding', + 'LBL_WIZARD_SYSTEM_DESC' => 'Provide your organization\'s name and logo in order to brand your Sugar.', + 'LBL_WIZARD_LOCALE_DESC' => 'Specify how you would like data in Sugar to be displayed, based on your geographical location. The settings you provide here will be the default settings. Users will be able set their own preferences.', + 'LBL_WIZARD_SMTP_DESC' => 'Provide the email account that will be used to send emails, such as the assignment notifications and new user passwords. Users will receive emails from Sugar, as sent from the specified email account.', + 'LBL_MOBILE_MOD_REPORTS_RESTRICTION' => '* The Reports module is only available for the Sugar Mobile iPhone client.', +); + + +?> diff --git a/modules/Configurator/metadata/SugarpdfSettingsdefs.php b/modules/Configurator/metadata/SugarpdfSettingsdefs.php new file mode 100644 index 00000000..80ce02be --- /dev/null +++ b/modules/Configurator/metadata/SugarpdfSettingsdefs.php @@ -0,0 +1,279 @@ +array( + "label"=>$mod_strings["PDF_TITLE"], + "info_label"=>$mod_strings["PDF_TITLE_INFO"], + "value"=>PDF_TITLE, + "class"=>"basic", + "type"=>"text", + ), + "sugarpdf_pdf_subject"=>array( + "label"=>$mod_strings["PDF_SUBJECT"], + "info_label"=>$mod_strings["PDF_SUBJECT_INFO"], + "value"=>PDF_SUBJECT, + "class"=>"basic", + "type"=>"text", + ), +/* "sugarpdf_pdf_creator"=>array( + "label"=>$mod_strings["PDF_CREATOR"], + "info_label"=>$mod_strings["PDF_CREATOR_INFO"], + "value"=>PDF_CREATOR, + "class"=>"basic", + "type"=>"text", + "required"=>"true" + ),*/ + "sugarpdf_pdf_author"=>array( + "label"=>$mod_strings["PDF_AUTHOR"], + "info_label"=>$mod_strings["PDF_AUTHOR_INFO"], + "value"=>PDF_AUTHOR, + "class"=>"basic", + "type"=>"text", + "required"=>"true" + ), + "sugarpdf_pdf_keywords"=>array( + "label"=>$mod_strings["PDF_KEYWORDS"], + "info_label"=>$mod_strings["PDF_KEYWORDS_INFO"], + "value"=>PDF_KEYWORDS, + "class"=>"basic", + "type"=>"text" + ), + /* + "sugarpdf_pdf_header_title"=>array( + "label"=>$mod_strings["PDF_HEADER_TITLE"], + "info_label"=>$mod_strings["PDF_HEADER_TITLE_INFO"], + "value"=>PDF_HEADER_TITLE, + "class"=>"basic", + "type"=>"text", + ), + "sugarpdf_pdf_header_string"=>array( + "label"=>$mod_strings["PDF_HEADER_STRING"], + "info_label"=>$mod_strings["PDF_HEADER_STRING_INFO"], + "value"=>PDF_HEADER_STRING, + "class"=>"basic", + "type"=>"text", + ), + */ + "sugarpdf_pdf_header_logo"=>array( + "label"=>$mod_strings["PDF_HEADER_LOGO"], + "info_label"=>$mod_strings["PDF_HEADER_LOGO_INFO"], + "value"=>PDF_HEADER_LOGO, + "path"=>K_PATH_CUSTOM_IMAGES.PDF_HEADER_LOGO, + "class"=>"logo", + "type"=>"image", + ), + "new_header_logo"=>array( + "label"=>$mod_strings["PDF_NEW_HEADER_LOGO"], + "info_label"=>$mod_strings["PDF_NEW_HEADER_LOGO_INFO"], + "value"=>"", + "class"=>"logo", + "type"=>"file", + ), + /* + "sugarpdf_pdf_header_logo_width"=>array( + "label"=>$mod_strings["PDF_HEADER_LOGO_WIDTH"], + "info_label"=>$mod_strings["PDF_HEADER_LOGO_WIDTH_INFO"], + "value"=>PDF_HEADER_LOGO_WIDTH, + "class"=>"logo", + "type"=>"number", + "required"=>"true", + "unit"=>PDF_UNIT + ), + */ + "sugarpdf_pdf_small_header_logo"=>array( + "label"=>$mod_strings["PDF_SMALL_HEADER_LOGO"], + "info_label"=>$mod_strings["PDF_SMALL_HEADER_LOGO_INFO"], + "value"=>PDF_SMALL_HEADER_LOGO, + "path"=>K_PATH_CUSTOM_IMAGES.PDF_SMALL_HEADER_LOGO, + "class"=>"logo", + "type"=>"image", + ), + "new_small_header_logo"=>array( + "label"=>$mod_strings["PDF_NEW_SMALL_HEADER_LOGO"], + "info_label"=>$mod_strings["PDF_NEW_SMALL_HEADER_LOGO_INFO"], + "value"=>"", + "class"=>"logo", + "type"=>"file", + ), + /* + "sugarpdf_pdf_small_header_logo_width"=>array( + "label"=>$mod_strings["PDF_SMALL_HEADER_LOGO_WIDTH"], + "info_label"=>$mod_strings["PDF_SMALL_HEADER_LOGO_WIDTH_INFO"], + "value"=>PDF_SMALL_HEADER_LOGO_WIDTH, + "class"=>"logo", + "type"=>"number", + "required"=>"true", + "unit"=>PDF_UNIT + ), +*/ + + + "sugarpdf_pdf_filename"=>array( + "label"=>$mod_strings["PDF_FILENAME"], + "info_label"=>$mod_strings["PDF_FILENAME_INFO"], + "value"=>PDF_FILENAME, + "class"=>"advanced", + "type"=>"text", + "required"=>"true" + ), + "sugarpdf_pdf_compression"=>array( + "label"=>$mod_strings["PDF_COMPRESSION"], + "info_label"=>$mod_strings["PDF_COMPRESSION_INFO"], + "value"=>PDF_COMPRESSION, + "class"=>"advanced", + "type"=>"bool", + ), + "sugarpdf_pdf_jpeg_quality"=>array( + "label"=>$mod_strings["PDF_JPEG_QUALITY"], + "info_label"=>$mod_strings["PDF_JPEG_QUALITY_INFO"], + "value"=>PDF_JPEG_QUALITY, + "class"=>"advanced", + "type"=>"percent", + "required"=>"true" + ), + "sugarpdf_pdf_pdf_version"=>array( + "label"=>$mod_strings["PDF_PDF_VERSION"], + "info_label"=>$mod_strings["PDF_PDF_VERSION_INFO"], + "value"=>PDF_PDF_VERSION, + "class"=>"advanced", + "type"=>"number", + "required"=>"true" + ), + + + "sugarpdf_pdf_protection"=>array( + "label"=>$mod_strings["PDF_PROTECTION"], + "info_label"=>$mod_strings["PDF_PROTECTION_INFO"], + "value"=>explode(",",PDF_PROTECTION), + "class"=>"advanced", + "type"=>"multiselect", + "selectList"=>array("print"=>"Print", "modify"=>"Modify", "copy"=>"Copy", "annot-forms"=>"Annotations and forms"), + ), + + "sugarpdf_pdf_user_password"=>array( + "label"=>$mod_strings["PDF_USER_PASSWORD"], + "info_label"=>$mod_strings["PDF_USER_PASSWORD_INFO"], + "value"=>blowfishDecode(blowfishGetKey('sugarpdf_pdf_user_password'), PDF_USER_PASSWORD), + "class"=>"advanced", + "type"=>"password" + ), + "sugarpdf_pdf_owner_password"=>array( + "label"=>$mod_strings["PDF_OWNER_PASSWORD"], + "info_label"=>$mod_strings["PDF_OWNER_PASSWORD_INFO"], + "value"=>blowfishDecode(blowfishGetKey('sugarpdf_pdf_owner_password'), PDF_OWNER_PASSWORD), + "class"=>"advanced", + "type"=>"password" + ), + + "sugarpdf_pdf_acl_access"=>array( + "label"=>$mod_strings["PDF_ACL_ACCESS"], + "info_label"=>$mod_strings["PDF_ACL_ACCESS_INFO"], + "value"=>PDF_ACL_ACCESS, + "class"=>"advanced", + "type"=>"select", + "selectList"=>array("edit"=>"Edition","list"=>"List","detail"=>"Detail", "export"=>"Export"), + "required"=>"true" + ), + +/* "sugarpdf_head_magnification"=>array( + "label"=>$mod_strings["HEAD_MAGNIFICATION"], + "info_label"=>$mod_strings["HEAD_MAGNIFICATION_INFO"], + "value"=>HEAD_MAGNIFICATION, + "class"=>"advanced", + "type"=>"number", + "required"=>"true" + ),*/ +/* "sugarpdf_k_title_magnification"=>array( + "label"=>$mod_strings["K_TITLE_MAGNIFICATION"], + "info_label"=>$mod_strings["K_TITLE_MAGNIFICATION_INFO"], + "value"=>K_TITLE_MAGNIFICATION, + "class"=>"advanced", + "type"=>"number", + "required"=>"true" + ),*/ + + "sugarpdf_k_small_ratio"=>array( + "label"=>$mod_strings["K_SMALL_RATIO"], + "info_label"=>$mod_strings["K_SMALL_RATIO_INFO"], + "value"=>K_SMALL_RATIO, + "class"=>"advanced", + "type"=>"number", + "required"=>"true" + ), + "sugarpdf_k_cell_height_ratio"=>array( + "label"=>$mod_strings["K_CELL_HEIGHT_RATIO"], + "info_label"=>$mod_strings["K_CELL_HEIGHT_RATIO_INFO"], + "value"=>K_CELL_HEIGHT_RATIO, + "class"=>"advanced", + "type"=>"number", + "required"=>"true" + ), + "sugarpdf_pdf_image_scale_ratio"=>array( + "label"=>$mod_strings["PDF_IMAGE_SCALE_RATIO"], + "info_label"=>$mod_strings["PDF_IMAGE_SCALE_RATIO_INFO"], + "value"=>PDF_IMAGE_SCALE_RATIO, + "class"=>"advanced", + "type"=>"number", + "required"=>"true" + ), + "sugarpdf_pdf_unit"=>array( + "label"=>$mod_strings["PDF_UNIT"], + "info_label"=>$mod_strings["PDF_UNIT_INFO"], + "value"=>PDF_UNIT, + "class"=>"advanced", + "type"=>"select", + //TODO translate + "selectList"=>array("mm"=>"Millimeter", "pt"=>"Point", "cm"=>"Centimeter", "in"=>"Inch"), + "required"=>"true" + ), +); + +// Use the OOB directory for images if there is no image in the custom directory +$small_logo = $SugarpdfSettings['sugarpdf_pdf_small_header_logo']['path']; +$logo = $SugarpdfSettings['sugarpdf_pdf_header_logo']['path']; +if (@getimagesize($logo) === FALSE) { + $SugarpdfSettings['sugarpdf_pdf_header_logo']['path'] = K_PATH_IMAGES.$SugarpdfSettings['sugarpdf_pdf_header_logo']['value']; +} +if (@getimagesize($small_logo) === FALSE) { + $SugarpdfSettings['sugarpdf_pdf_small_header_logo']['path'] = K_PATH_IMAGES.$SugarpdfSettings['sugarpdf_pdf_small_header_logo']['value']; +} + +?> \ No newline at end of file diff --git a/modules/Configurator/tpls/EditView.tpl b/modules/Configurator/tpls/EditView.tpl new file mode 100644 index 00000000..9c5ae9e2 --- /dev/null +++ b/modules/Configurator/tpls/EditView.tpl @@ -0,0 +1,428 @@ +{* + +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + + + +*} + +
    + + +{$error.main} + + + + + +
    + +   +  
    + + + + + + + + + + + + + + + + + + + + + + + + {if !empty($config.use_real_names)} + {assign var='use_real_names' value='CHECKED'} + {else} + {assign var='use_real_names' value=''} + {/if} + + + + + {if !empty($config.calculate_response_time )} + {assign var='calculate_response_time_checked' value='CHECKED'} + {else} + {assign var='calculate_response_time_checked' value=''} + {/if} + + + {if !empty($config.default_module_favicon)} + {assign var='default_module_favicon' value='CHECKED'} + {else} + {assign var='default_module_favicon' value=''} + {/if} + + + + + + + + + + + + + + + +

    {$MOD.DEFAULT_SYSTEM_SETTINGS}

    {$MOD.LIST_ENTRIES_PER_LISTVIEW}: + + {$MOD.LIST_ENTRIES_PER_SUBPANEL}: + +
    {$MOD.LOCK_HOMEPAGE}: + {if !empty($config.lock_homepage)} + {assign var='lock_homepage_checked' value='CHECKED'} + {else} + {assign var='lock_homepage_checked' value=''} + {/if} + + + {$MOD.LOCK_SUBPANELS}: + {if !empty($config.lock_subpanels)} + {assign var='lock_subpanels_checked' value='CHECKED'} + {else} + {assign var='lock_subpanels_checked' value=''} + {/if} + + +
    {$MOD.MAX_DASHLETS}: + + {$MOD.LBL_USE_REAL_NAMES}:  {sugar_help text=$MOD.LBL_USE_REAL_NAMES_DESC} + + +
    {$MOD.DISPLAY_RESPONSE_TIME}: {$MOD.LBL_MODULE_FAVICON}  {sugar_help text=$MOD.LBL_MODULE_FAVICON_HELP} + + +
    {$MOD.SYSTEM_NAME} + + {$MOD.LBL_MIN_AUTO_REFRESH_INTERVAL}  {sugar_help text=$MOD.LBL_MIN_AUTO_REFRESH_INTERVAL_HELP} + +
    + {$MOD.CURRENT_LOGO} {sugar_help text=$MOD.CURRENT_LOGO_HELP} + + +
    + {$MOD.NEW_LOGO} {sugar_help text=$MOD.NEW_LOGO_HELP} + +
    + +
    + + + + + + + + + {if !empty($settings.proxy_on)} + {assign var='proxy_on_checked' value='CHECKED'} + {else} + {assign var='proxy_on_checked' value=''} + {/if} + + + + +

    {$MOD.LBL_PROXY_TITLE}

    {$MOD.LBL_PROXY_ON} {sugar_help text=$MOD.LBL_PROXY_ON_DESC}
    +
    + + + + + + + + {if !empty($settings.proxy_auth)} + {assign var='proxy_auth_checked' value='CHECKED'} + {else} + {assign var='proxy_auth_checked' value=''} + {/if} + +
    {$MOD.LBL_PROXY_HOST}{$APP.LBL_REQUIRED_SYMBOL}{$MOD.LBL_PROXY_PORT}{$APP.LBL_REQUIRED_SYMBOL}
    {$MOD.LBL_PROXY_AUTH}
    + +
    + + + + + + + +
    {$MOD.LBL_PROXY_USERNAME}{$APP.LBL_REQUIRED_SYMBOL}{$MOD.LBL_PROXY_PASSWORD}{$APP.LBL_REQUIRED_SYMBOL}
    +
    +
    +
    + + + + + + + + + {if !empty($settings.system_skypeout_on)} + {assign var='system_skypeout_on_checked' value='CHECKED'} + {else} + {assign var='system_skypeout_on_checked' value=''} + {/if} + + +

    {$MOD.LBL_SKYPEOUT_TITLE}

    {$MOD.LBL_SKYPEOUT_ON} {sugar_help text=$MOD.LBL_SKYPEOUT_ON_DESC WIDTH=400}
    + + + + + + + + + {if !empty($settings.system_mailmerge_on)} + {assign var='system_mailmerge_on_checked' value='CHECKED'} + {else} + {assign var='system_mailmerge_on_checked' value=''} + {/if} + + +

    {$MOD.LBL_MAILMERGE}

    {$MOD.LBL_ENABLE_MAILMERGE} {sugar_help text=$MOD.LBL_MAILMERGE_DESC WIDTH=400}
    + + + + + + + + + {if !empty($config.verify_client_ip)} + {assign var='verify_client_ip_checked' value='CHECKED'} + {else} + {assign var='verify_client_ip_checked' value=''} + {/if} + + + + {if !empty($config.log_memory_usage)} + {assign var='log_memory_usage_checked' value='CHECKED'} + {else} + {assign var='log_memory_usage_checked' value=''} + {/if} + + + + + + {if !empty($config.dump_slow_queries)} + {assign var='dump_slow_queries_checked' value='CHECKED'} + {else} + {assign var='dump_slow_queries_checked' value=''} + {/if} + + + + + + + + + + + {if !empty($config.stack_trace_errors)} + {assign var='stack_trace_errors_checked' value='CHECKED'} + {else} + {assign var='stack_trace_errors_checked' value=''} + {/if} + + + + + + + + + {if !empty($config.developerMode)} + {assign var='developerModeChecked' value='CHECKED'} + {else} + {assign var='developerModeChecked' value=''} + {/if} + + + + + + + + + +

    {$MOD.ADVANCED}

    {$MOD.VERIFY_CLIENT_IP}: {$MOD.LOG_MEMORY_USAGE}:
    {$MOD.LOG_SLOW_QUERIES}: {$MOD.SLOW_QUERY_TIME_MSEC}: + +
    {$MOD.UPLOAD_MAX_SIZE}: + + {$MOD.STACK_TRACE_ERRORS}:
    {$MOD.DEVELOPER_MODE}:
    {$MOD.LBL_VCAL_PERIOD} {sugar_help text=$MOD.vCAL_HELP} + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

    {$MOD.LBL_LOGGER}

    {$MOD.LBL_LOGGER_FILENAME}{$MOD.LBL_LOGGER_FILE_EXTENSION}{$MOD.LBL_LOGGER_FILENAME_SUFFIX}
    {$MOD.LBL_LOGGER_MAX_LOG_SIZE} {$MOD.LBL_LOGGER_DEFAULT_DATE_FORMAT}
    {$MOD.LBL_LOGGER_LOG_LEVEL} {$MOD.LBL_LOGGER_MAX_LOGS}
    {$MOD.LBL_LOGVIEW}
    + + + +
    + +   +   +
    +{$JAVASCRIPT} + + + +
    + +{literal} + +{/literal} diff --git a/modules/Configurator/tpls/SugarpdfSettings.tpl b/modules/Configurator/tpls/SugarpdfSettings.tpl new file mode 100644 index 00000000..10f367ca --- /dev/null +++ b/modules/Configurator/tpls/SugarpdfSettings.tpl @@ -0,0 +1,221 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + + + +*} + + + +
    +
    +{$error} + + + + +
    + +   +   +
    + + + + +
    + + + + + +
    {html_radios name="sugarpdf_pdf_class" options=$pdf_class selected=$selected_pdf_class separator=' ' onchange='processPDFClass()'}
    + + + + + + + + +

    {$MOD.SUGARPDF_BASIC_SETTINGS}

    + + {counter start=0 assign='count'} + {foreach from=$SugarpdfSettings item=property key=name} + {if $property.class == "basic"} + {counter} + {include file="modules/Configurator/tpls/SugarpdfSettingsFields.tpl"} + {/if} + {/foreach} + {if $count is odd} + + + + {/if} +
    +
    + + + + + + + + + +

    {$MOD.SUGARPDF_LOGO_SETTINGS}

    + + {counter start=0 assign='count'} + {foreach from=$SugarpdfSettings item=property key=name} + {if $property.class == "logo"} + {counter} + {include file="modules/Configurator/tpls/SugarpdfSettingsFields.tpl"} + {/if} + {/foreach} + {if $count is odd} + + + + {/if} +
    +
    + +
    + +
    + +
    +{$JAVASCRIPT} +
    +{literal} + +{/literal} diff --git a/modules/Configurator/tpls/SugarpdfSettingsFields.tpl b/modules/Configurator/tpls/SugarpdfSettingsFields.tpl new file mode 100644 index 00000000..f49adedc --- /dev/null +++ b/modules/Configurator/tpls/SugarpdfSettingsFields.tpl @@ -0,0 +1,96 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + + + +*} +{if $property.type == "image"} +{if $count is not odd}
    {$property.label}:{sugar_help text=$property.info_label} + + + +
    {$property.label}:{if isset($property.required) && $property.required == true} *{/if}{sugar_help text=$property.info_label} + {if isset($property.custom)} + {$property.custom} + {elseif $property.type == "text"} + + {elseif $property.type == "number"} + + {if isset($property.unit)} + {$property.unit} + {/if} + {elseif $property.type == "percent"} + + {elseif $property.type == "select"} + {html_options name=$name options=$property.selectList selected=$property.value} + {elseif $property.type == "multiselect"} + + {elseif $property.type == "bool"} + + + {elseif $property.type == "password"} + + {elseif $property.type == "file"} + + {/if} +
    + + + +
    + +
    +
    +
    {if isset($error)}{$MOD.LBL_STATUS_FONT_ERROR}{else}{$MOD.LBL_STATUS_FONT_SUCCESS}{/if}
    +
    {$error}
    +
    {$info}
    + \ No newline at end of file diff --git a/modules/Configurator/tpls/addFontView.tpl b/modules/Configurator/tpls/addFontView.tpl new file mode 100644 index 00000000..e324bb84 --- /dev/null +++ b/modules/Configurator/tpls/addFontView.tpl @@ -0,0 +1,166 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + + + +*} + + +

    +{$MODULE_TITLE} +

    +
    +{$error} +
    + + + + +
    + +   +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    {$MOD.LBL_PDF_METRIC_FILE}: *{sugar_help text=$MOD.LBL_PDF_METRIC_FILE_INFO} + +
    {$MOD.LBL_PDF_FONT_FILE}: *{sugar_help text=$MOD.LBL_PDF_FONT_FILE_INFO} + +
    {$MOD.LBL_FONT_LIST_EMBEDDED}: *{sugar_help text=$MOD.LBL_FONT_LIST_EMBEDDED_INFO} + + +
    {$MOD.LBL_PDF_ENCODING_TABLE}: *{sugar_help text=$MOD.LBL_PDF_ENCODING_TABLE_INFO} + {html_options name="pdf_encoding_table" options=$ENCODING_TABLE} +
    {$MOD.LBL_PDF_PATCH}:{sugar_help text=$MOD.LBL_PDF_PATCH_INFO} + +
    {$MOD.LBL_FONT_LIST_STYLE}: *{sugar_help text=$MOD.LBL_FONT_LIST_STYLE_INFO} + {html_options name="pdf_style_list" options=$STYLE_LIST} +
    +
    +
    + +
    +
    +{literal} + diff --git a/modules/Configurator/tpls/adminwizard.tpl b/modules/Configurator/tpls/adminwizard.tpl new file mode 100644 index 00000000..34bf9a65 --- /dev/null +++ b/modules/Configurator/tpls/adminwizard.tpl @@ -0,0 +1,794 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} + + + + + +{$MOD.LBL_WIZARD_TITLE} +{$SUGAR_JS} +{$SUGAR_CSS} +{$CSS} +{overlib_includes} + +{literal} + +{/literal} + +
    +
    + "; + $lead_source_field = ""; + } else { + $lead_source_label = ""; + $lead_source_field = ""; + } + + +global $timedate; +$birthdate = ''; +if(!empty($_REQUEST['birthdate'])){ + $birthdate=$_REQUEST['birthdate']; + } + + +$jsCalendarImage = SugarThemeRegistry::current()->getImageURL('jscalendar.gif'); +$ntc_date_format = $timedate->get_user_date_format(); +$cal_dateformat = $timedate->get_cal_date_format(); +$lbl_required_symbol = $app_strings['LBL_REQUIRED_SYMBOL']; + +$form .= << + +
    + +
    + + +{$error.main} + + + + + +
    +
    +
    +
    +
    +
    + + + + +
    +
    + + + + + + + +

    {$MOD.LBL_WIZARD_WELCOME_TITLE}

    +

    {$MOD.LBL_WIZARD_WELCOME}

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

    {$MOD.LBL_WIZARD_SYSTEM_TITLE}

    {$MOD.LBL_WIZARD_SYSTEM_DESC}
    {$MOD.SYSTEM_NAME_WIZARD} {sugar_help text=$MOD.SYSTEM_NAME_HELP} + +
    {$MOD.NEW_LOGO} {sugar_help text=$MOD.NEW_LOGO_HELP} + +
    + +
    {$MOD.CURRENT_LOGO} {sugar_help text=$MOD.CURRENT_LOGO_HELP} + +
    +
    +
    + +
    + +
    + + + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

    {sugar_translate module='Administration' label='LBL_LOCALE_TITLE'}

    {$MOD.LBL_WIZARD_LOCALE_DESC}
    {sugar_translate module='Administration' label='LBL_LOCALE_DEFAULT_DATE_FORMAT'}: + {html_options name='default_date_format' selected=$config.default_date_format options=$config.date_formats} + {sugar_translate module='Administration' label='LBL_LOCALE_DEFAULT_TIME_FORMAT'}: + {html_options name='default_time_format' selected=$config.default_time_format options=$config.time_formats} +
    {sugar_translate module='Administration' label='LBL_LOCALE_DEFAULT_LANGUAGE'}: + {html_options name='default_language' selected=$config.default_language options=$LANGUAGES} +

    {sugar_translate module='Administration' label='LBL_LOCALE_DEFAULT_CURRENCY_NAME'}: + + {sugar_translate module='Administration' label='LBL_LOCALE_DEFAULT_CURRENCY_SYMBOL'}: + +
    {sugar_translate module='Administration' label='LBL_LOCALE_DEFAULT_CURRENCY_ISO4217'}: + + {sugar_translate module='Administration' label='LBL_LOCALE_DEFAULT_NUMBER_GROUPING_SEP'}: + +
    {sugar_translate module='Administration' label='LBL_LOCALE_DEFAULT_DECIMAL_SEP'}: + +

    {sugar_translate module='Administration' label='LBL_LOCALE_DEFAULT_NAME_FORMAT'}: + +
    + {sugar_translate module='Administration' label='LBL_LOCALE_NAME_FORMAT_DESC'} +
    {sugar_translate module='Administration' label='LBL_LOCALE_EXAMPLE_NAME_FORMAT'}:
    +
    +
    + +
    + +
    + + + +
    +
    + + + + + + + + + + + + + + + + +
    +

    {$MOD.LBL_MAIL_SMTP_SETTINGS}

    +
    {$MOD.LBL_WIZARD_SMTP_DESC}
    {$MOD.LBL_CHOOSE_EMAIL_PROVIDER}
    + +
    + + + + + + + + + + + + + + + + + + + + +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    {$MOD.LBL_MAIL_SMTPSERVER} {$MOD.LBL_MAIL_SMTPPORT}
    {$MOD.LBL_MAIL_SMTPAUTH_REQ} + + {$APP.LBL_EMAIL_SMTP_SSL_OR_TLS} + +
    {$MOD.LBL_MAIL_SMTPUSER}   
    {$MOD.LBL_MAIL_SMTPPASS}   
    + + {$MOD.LBL_ALLOW_DEFAULT_SELECTION}  + + + + + + + +   
    +   +   +   
    +
    +
    +
    +
    + +
    +
    +
    +
    +
    +
    + + +
    + + + +
    +
    +
    + + + + + + + + +
    + {$APP.LBL_EMAIL_SETTINGS_FROM_TO_EMAIL_ADDR} + + + + +
    +   +   +
    +
    +
    +
    + +{literal} + diff --git a/modules/Configurator/tpls/fontmanager.tpl b/modules/Configurator/tpls/fontmanager.tpl new file mode 100644 index 00000000..1dce51ca --- /dev/null +++ b/modules/Configurator/tpls/fontmanager.tpl @@ -0,0 +1,120 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + + + +*} + + +{literal} + +{/literal} +

    +{$MODULE_TITLE} +

    +
    + + + + + +{$error} +
    + + + + +
    +   + +
    + +
    +
    +
    + +
    +{literal} + diff --git a/modules/Configurator/views/view.addfontresult.php b/modules/Configurator/views/view.addfontresult.php new file mode 100644 index 00000000..baa7a7d8 --- /dev/null +++ b/modules/Configurator/views/view.addfontresult.php @@ -0,0 +1,108 @@ +addFont(); + + $this->ss->assign("MODULE_TITLE", + getClassicModuleTitle( + $mod_strings['LBL_MODULE_ID'], + array($mod_strings['LBL_ADDFONTRESULT_TITLE']), + false + ) + ); + if($error){ + $this->ss->assign("error", $this->log); + }else{ + $this->ss->assign("info", $this->log); + } + $this->ss->assign("MOD", $mod_strings); + $this->ss->assign("APP", $app_strings); +//display + $this->ss->display('modules/Configurator/tpls/addFontResult.tpl'); + } + + /** + * This method prepares the received data and call the addFont method of the fontManager + * @return boolean true on success + */ + private function addFont(){ + $this->log=""; + $error=false; + require_once('include/upload_file.php'); + $files = array("pdf_metric_file","pdf_font_file"); + foreach($files as $k){ + // handle uploaded file + $uploadFile = new UploadFile($k); + if (isset($_FILES[$k]) && $uploadFile->confirm_upload()){ + $uploadFile->final_move(basename($_FILES[$k]['name'])); + $uploadFileNames[$k] = $uploadFile->get_upload_path(basename($_FILES[$k]['name'])); + }else{ + $this->log = translate('ERR_PDF_NO_UPLOAD', "Configurator"); + $error=true; + } + } + if(!$error){ + require_once('include/Sugarpdf/FontManager.php'); + $fontManager = new FontManager(); + $error = $fontManager->addFont($uploadFileNames["pdf_font_file"],$uploadFileNames["pdf_metric_file"], $_REQUEST['pdf_embedded'], $_REQUEST['pdf_encoding_table'], eval($_REQUEST['pdf_patch']), htmlspecialchars_decode($_REQUEST['pdf_cidinfo'],ENT_QUOTES), $_REQUEST['pdf_style_list']); + $this->log .= $fontManager->log; + if($error){ + $this->log .= implode("\n",$fontManager->errors); + } + } + return $error; + } +} + \ No newline at end of file diff --git a/modules/Configurator/views/view.addfontview.php b/modules/Configurator/views/view.addfontview.php new file mode 100644 index 00000000..c55f5e35 --- /dev/null +++ b/modules/Configurator/views/view.addfontview.php @@ -0,0 +1,86 @@ +ss->assign("MODULE_TITLE", + getClassicModuleTitle( + $mod_strings['LBL_MODULE_ID'], + array($mod_strings['LBL_ADDFONT_TITLE']), + true + ) + ); + if(!empty($_REQUEST['error'])){ + $this->ss->assign("error", $_REQUEST['error']); + } + $this->ss->assign("MOD", $mod_strings); + $this->ss->assign("APP", $app_strings); + if(isset($_REQUEST['return_action'])){ + $this->ss->assign("RETURN_ACTION", $_REQUEST['return_action']); + }else{ + $this->ss->assign("RETURN_ACTION", 'FontManager'); + } + $this->ss->assign("STYLE_LIST", array( + "regular"=>$mod_strings["LBL_FONT_REGULAR"], + "italic"=>$mod_strings["LBL_FONT_ITALIC"], + "bold"=>$mod_strings["LBL_FONT_BOLD"], + "boldItalic"=>$mod_strings["LBL_FONT_BOLDITALIC"] + )); + $this->ss->assign("ENCODING_TABLE", array_combine(explode(",",PDF_ENCODING_TABLE_LIST), explode(",",PDF_ENCODING_TABLE_LABEL_LIST))); + +//display + $this->ss->display('modules/Configurator/tpls/addFontView.tpl'); + } +} + \ No newline at end of file diff --git a/modules/Configurator/views/view.adminwizard.php b/modules/Configurator/views/view.adminwizard.php new file mode 100644 index 00000000..c8381718 --- /dev/null +++ b/modules/Configurator/views/view.adminwizard.php @@ -0,0 +1,123 @@ +options['show_header'] = false; + $this->options['show_footer'] = false; + $this->options['show_javascript'] = false; + } + + /** + * @see SugarView::display() + */ + public function display() + { + global $current_user, $mod_strings, $app_list_strings, $sugar_config, $locale, $sugar_version; + + if(!is_admin($current_user)){ + sugar_die($GLOBALS['app_strings']['ERR_NOT_ADMIN']); + } + + $themeObject = SugarThemeRegistry::current(); + + $configurator = new Configurator(); + $sugarConfig = SugarConfig::getInstance(); + $focus = new Administration(); + $focus->retrieveSettings(); + + $ut = $GLOBALS['current_user']->getPreference('ut'); + if(empty($ut)) + $this->ss->assign('SKIP_URL','index.php?module=Users&action=Wizard&skipwelcome=1'); + else + $this->ss->assign('SKIP_URL','index.php?module=Home&action=index'); + + // Always mark that we have got past this point + $focus->saveSetting('system','adminwizard',1); + $css = $themeObject->getCSS(); + $favicon = $themeObject->getImageURL('sugar_icon.ico',false); + $this->ss->assign('FAVICON_URL',getJSPath($favicon)); + $this->ss->assign('SUGAR_CSS', $css); + $this->ss->assign('MOD_USERS',return_module_language($GLOBALS['current_language'], 'Users')); + $this->ss->assign('CSS', ''); + $this->ss->assign('LANGUAGES', get_languages()); + $this->ss->assign('config', $sugar_config); + $this->ss->assign('SUGAR_VERSION', $sugar_version); + $this->ss->assign('settings', $focus->settings); + $this->ss->assign('exportCharsets', get_select_options_with_id($locale->getCharsetSelect(), $sugar_config['default_export_charset'])); + $this->ss->assign('getNameJs', $locale->getNameJs()); + $this->ss->assign('JAVASCRIPT',get_set_focus_js(). get_configsettings_js()); + $this->ss->assign('company_logo', SugarThemeRegistry::current()->getImageURL('company_logo.png')); + $this->ss->assign('mail_smtptype', $focus->settings['mail_smtptype']); + $this->ss->assign('mail_smtpserver', $focus->settings['mail_smtpserver']); + $this->ss->assign('mail_smtpport', $focus->settings['mail_smtpport']); + $this->ss->assign('mail_smtpuser', $focus->settings['mail_smtpuser']); + $this->ss->assign('mail_smtppass', $focus->settings['mail_smtppass']); + $this->ss->assign('mail_smtpauth_req', ($focus->settings['mail_smtpauth_req']) ? "checked='checked'" : ''); + $this->ss->assign('MAIL_SSL_OPTIONS', get_select_options_with_id($app_list_strings['email_settings_for_ssl'], $focus->settings['mail_smtpssl'])); + $this->ss->assign('notify_allow_default_outbound_on', (!empty($focus->settings['notify_allow_default_outbound']) && $focus->settings['notify_allow_default_outbound'] == 2) ? 'CHECKED' : ''); + $this->ss->assign('THEME', SugarThemeRegistry::current()->__toString()); + + // get javascript + ob_start(); + $this->options['show_javascript'] = true; + $this->renderJavascript(); + $this->options['show_javascript'] = false; + $this->ss->assign("SUGAR_JS",ob_get_contents().$themeObject->getJS()); + ob_end_clean(); + + $this->ss->assign('START_PAGE', !empty($_REQUEST['page']) ? $_REQUEST['page'] : 'welcome'); + + $this->ss->display('modules/Configurator/tpls/adminwizard.tpl'); + } +} diff --git a/modules/Configurator/views/view.edit.php b/modules/Configurator/views/view.edit.php new file mode 100644 index 00000000..11ac671c --- /dev/null +++ b/modules/Configurator/views/view.edit.php @@ -0,0 +1,138 @@ +".translate('LBL_MODULE_NAME','Administration')."", + $mod_strings['LBL_SYSTEM_SETTINGS'] + ); + } + + /** + * @see SugarView::display() + */ + public function display() + { + global $current_user, $mod_strings, $app_strings, $app_list_strings, $sugar_config, $locale; + + $configurator = new Configurator(); + $sugarConfig = SugarConfig::getInstance(); + $focus = new Administration(); + $configurator->parseLoggerSettings(); + + $focus->retrieveSettings(); + if(!empty($_POST['restore'])){ + $configurator->restoreConfig(); + } + + $this->ss->assign('MOD', $mod_strings); + $this->ss->assign('APP', $app_strings); + $this->ss->assign('APP_LIST', $app_list_strings); + $this->ss->assign('config', $configurator->config); + $this->ss->assign('error', $configurator->errors); + $this->ss->assign("AUTO_REFRESH_INTERVAL_OPTIONS", get_select_options_with_id($app_list_strings['dashlet_auto_refresh_options_admin'], isset($configurator->config['dashlet_auto_refresh_min']) ? $configurator->config['dashlet_auto_refresh_min'] : 30)); + $this->ss->assign('LANGUAGES', get_languages()); + $this->ss->assign("JAVASCRIPT",get_set_focus_js(). get_configsettings_js()); + $this->ss->assign('company_logo', SugarThemeRegistry::current()->getImageURL('company_logo.png')); + $this->ss->assign("settings", $focus->settings); + $this->ss->assign("mail_sendtype_options", get_select_options_with_id($app_list_strings['notifymail_sendtype'], $focus->settings['mail_sendtype'])); + if(!empty($focus->settings['proxy_on'])){ + $this->ss->assign("PROXY_CONFIG_DISPLAY", 'inline'); + }else{ + $this->ss->assign("PROXY_CONFIG_DISPLAY", 'none'); + } + if(!empty($focus->settings['proxy_auth'])){ + $this->ss->assign("PROXY_AUTH_DISPLAY", 'inline'); + }else{ + $this->ss->assign("PROXY_AUTH_DISPLAY", 'none'); + } + if (!empty($configurator->config['logger']['level'])) { + $this->ss->assign('log_levels', get_select_options_with_id( LoggerManager::getLoggerLevels(), $configurator->config['logger']['level'])); + } else { + $this->ss->assign('log_levels', get_select_options_with_id( LoggerManager::getLoggerLevels(), '')); + } + if (!empty($configurator->config['logger']['file']['suffix'])) { + $this->ss->assign('filename_suffix', get_select_options_with_id( SugarLogger::$filename_suffix,$configurator->config['logger']['file']['suffix'])); + } else { + $this->ss->assign('filename_suffix', get_select_options_with_id( SugarLogger::$filename_suffix,'')); + } + + echo $this->getModuleTitle(false); + + $this->ss->display('modules/Configurator/tpls/EditView.tpl'); + + $javascript = new javascript(); + $javascript->setFormName("ConfigureSettings"); + $javascript->addFieldGeneric("notify_fromaddress", "email", $mod_strings['LBL_NOTIFY_FROMADDRESS'], TRUE, ""); + $javascript->addFieldGeneric("notify_subject", "varchar", $mod_strings['LBL_NOTIFY_SUBJECT'], TRUE, ""); + $javascript->addFieldGeneric("proxy_host", "varchar", $mod_strings['LBL_PROXY_HOST'], TRUE, ""); + $javascript->addFieldGeneric("proxy_port", "int", $mod_strings['LBL_PROXY_PORT'], TRUE, ""); + $javascript->addFieldGeneric("proxy_password", "varchar", $mod_strings['LBL_PROXY_PASSWORD'], TRUE, ""); + $javascript->addFieldGeneric("proxy_username", "varchar", $mod_strings['LBL_PROXY_USERNAME'], TRUE, ""); + echo $javascript->getScript(); + } +} diff --git a/modules/Configurator/views/view.fontmanager.php b/modules/Configurator/views/view.fontmanager.php new file mode 100644 index 00000000..7230b272 --- /dev/null +++ b/modules/Configurator/views/view.fontmanager.php @@ -0,0 +1,245 @@ +listFontFiles()){ + $error = implode("
    ",$fontManager->errors); + } + + $this->ss->assign("MODULE_TITLE", + getClassicModuleTitle( + $mod_strings['LBL_MODULE_ID'], + array($mod_strings['LBL_FONTMANAGER_TITLE']), + false + ) + ); + if(!empty($_REQUEST['error'])){ + $error .= "
    ".$_REQUEST['error']; + } + $this->ss->assign("error", $error); + $this->ss->assign("MOD", $mod_strings); + $this->ss->assign("APP", $app_strings); + $this->ss->assign("JAVASCRIPT", $this->_getJS()); + if(isset($_REQUEST['return_action'])){ + $this->ss->assign("RETURN_ACTION", $_REQUEST['return_action']); + }else{ + $this->ss->assign("RETURN_ACTION", 'SugarpdfSettings'); + } + $this->ss->assign("K_PATH_FONTS", K_PATH_FONTS); +// YUI List + $this->ss->assign("COLUMNDEFS", $this->getYuiColumnDefs($fontManager->fontList)); + $this->ss->assign("DATASOURCE", $this->getYuiDataSource($fontManager->fontList)); + $this->ss->assign("RESPONSESCHEMA", $this->getYuiResponseSchema()); + +//display + $this->ss->display('modules/Configurator/tpls/fontmanager.tpl'); + } + + /** + * Returns JS used in this view + */ + private function _getJS() + { + global $mod_strings; + return <<isAllOOBFont($fontList)) + $removeColumn = ''; + + $return = <<$v){ + if($first){ + $first=false; + }else{ + $return .= ','; + } + $return .= '{'; + if(!empty($v['displayname'])){ + $return .= 'name:"'.$v['displayname'].'"'; + }else if(!empty($v['name'])){ + $return .= 'name:"'.$v['name'].'"'; + } + $return .= ', filename:"'.$v['filename'].'"'; + $return .= ', fontpath:"'.$v['fontpath'].'"'; + $return .= ', style:"'.$this->formatStyle($v['style']).'"'; + $return .= ', type:"'.$this->formatType($v['type']).'"'; + $return .= ', filesize:'.$v['filesize']; + if(!empty($v['enc'])){ + $return .= ', enc:"'.$v['enc'].'"'; + } + if($v['embedded'] == true){ + $return .= ', embedded:""}'; + }else{ + $return .= ', embedded:""}'; + } + } + $return .= "]"; + return $return; + } + + /** + * Return the Response Schema for the YUI data table + * @return String + */ + private function getYuiResponseSchema(){ + return <<"; + }else{ + switch($style[0]){ + case "bold": + $return .= "".$mod_strings['LBL_FONT_BOLD'].""; + break; + case "italic": + $return .= "".$mod_strings['LBL_FONT_ITALIC'].""; + break; + default: + $return .= $mod_strings['LBL_FONT_REGULAR']; + } + } + return $return; + } + + private function formatType($type){ + global $mod_strings; + switch($type){ + case "cidfont0": + $return = $mod_strings['LBL_FONT_TYPE_CID0'];break; + case "core": + $return = $mod_strings['LBL_FONT_TYPE_CORE'];break; + case "TrueType": + $return = $mod_strings['LBL_FONT_TYPE_TRUETYPE'];break; + case "Type1": + $return = $mod_strings['LBL_FONT_TYPE_TYPE1'];break; + case "TrueTypeUnicode": + $return = $mod_strings['LBL_FONT_TYPE_TRUETYPEU'];break; + default: + $return = ""; + } + return $return; + } + + /** + * Determine if all the fonts are core fonts + * @param $fontList + * @return boolean return true if all the fonts are core type + */ + private function isAllOOBFont($fontList){ + foreach($fontList as $v){ + if($v['type'] != "core" && $v['fontpath'] != K_PATH_FONTS) + return false; + } + return true; + } +} + + \ No newline at end of file diff --git a/modules/Configurator/views/view.sugarpdfsettings.php b/modules/Configurator/views/view.sugarpdfsettings.php new file mode 100644 index 00000000..992185ce --- /dev/null +++ b/modules/Configurator/views/view.sugarpdfsettings.php @@ -0,0 +1,200 @@ +".translate('LBL_MODULE_NAME','Administration')."", + $mod_strings['LBL_PDFMODULE_NAME'] + ); + } + + /** + * @see SugarView::display() + */ + public function display() + { + global $mod_strings, $app_strings, $app_list_strings; + + require_once("modules/Configurator/metadata/SugarpdfSettingsdefs.php"); + if(file_exists('custom/modules/Configurator/metadata/SugarpdfSettingsdefs.php')){ + require_once('custom/modules/Configurator/metadata/SugarpdfSettingsdefs.php'); + } + + if(!empty($_POST['save'])){ + // Save the logos + $error=$this->checkUploadImage(); + if(empty($error)){ + $focus = new Administration(); + foreach($SugarpdfSettings as $k=>$v){ + if($v['type'] == 'password'){ + if(isset($_POST[$k])){ + $_POST[$k] = blowfishEncode(blowfishGetKey($k), $_POST[$k]); + } + } + } + if(!empty($_POST["sugarpdf_pdf_class"]) && $_POST["sugarpdf_pdf_class"] != PDF_CLASS){ + // clear the cache for quotes detailview in order to switch the pdf class. + if(is_file($GLOBALS['sugar_config']['cache_dir'].'modules/Quotes/DetailView.tpl')) + unlink($GLOBALS['sugar_config']['cache_dir'].'modules/Quotes/DetailView.tpl'); + } + $focus->saveConfig(); + header('Location: index.php?module=Administration&action=index'); + } + } + + if(!empty($_POST['restore'])){ + $focus = new Administration(); + foreach($_POST as $key => $val) { + $prefix = $focus->get_config_prefix($key); + if(in_array($prefix[0], $focus->config_categories)) { + $result = $focus->db->query("SELECT count(*) AS the_count FROM config WHERE category = '{$prefix[0]}' AND name = '{$prefix[1]}'"); + $row = $focus->db->fetchByAssoc( $result, -1, true ); + if( $row['the_count'] != 0){ + $focus->db->query("DELETE FROM config WHERE category = '{$prefix[0]}' AND name = '{$prefix[1]}'"); + } + } + } + header('Location: index.php?module=Configurator&action=SugarpdfSettings'); + } + + echo getClassicModuleTitle( + "Administration", + array( + "".translate('LBL_MODULE_NAME','Administration')."", + $mod_strings['LBL_PDFMODULE_NAME'], + ), + false + ); + + $pdf_class = array("TCPDF"=>"TCPDF","EZPDF"=>"EZPDF"); + + $this->ss->assign('APP_LIST', $app_list_strings); + $this->ss->assign("JAVASCRIPT",get_set_focus_js()); + $this->ss->assign("SugarpdfSettings", $SugarpdfSettings); + $this->ss->assign("pdf_enable_ezpdf", PDF_ENABLE_EZPDF); + if(PDF_ENABLE_EZPDF == "0" && PDF_CLASS == "EZPDF"){ + $error = "ERR_EZPDF_DISABLE"; + $this->ss->assign("selected_pdf_class", "TCPDF"); + }else{ + $this->ss->assign("selected_pdf_class", PDF_CLASS); + } + $this->ss->assign("pdf_class", $pdf_class); + + if(!empty($error)){ + $this->ss->assign("error", $mod_strings[$error]); + } + if (!function_exists('imagecreatefrompng')) { + $this->ss->assign("GD_WARNING", 1); + } + else + $this->ss->assign("GD_WARNING", 0); + + $this->ss->display('modules/Configurator/tpls/SugarpdfSettings.tpl'); + + require_once("include/javascript/javascript.php"); + $javascript = new javascript(); + $javascript->setFormName("ConfigureSugarpdfSettings"); + foreach($SugarpdfSettings as $k=>$v){ + if(isset($v["required"]) && $v["required"] == true) + $javascript->addFieldGeneric($k, "varchar", $v['label'], TRUE, ""); + } + + echo $javascript->getScript(); + } + + private function checkUploadImage() + { + $error=""; + $files = array('sugarpdf_pdf_header_logo'=>$_FILES['new_header_logo'], 'sugarpdf_pdf_small_header_logo'=>$_FILES['new_small_header_logo']); + foreach($files as $k=>$v){ + if(empty($error) && isset($v) && !empty($v['name'])){ + $file_name = K_PATH_CUSTOM_IMAGES .'pdf_logo_'. basename($v['name']); + if(file_exists($file_name)) + rmdir_recursive($file_name); + if (!empty($v['error'])) + $error='ERR_ALERT_FILE_UPLOAD'; + if(!mkdir_recursive(K_PATH_CUSTOM_IMAGES)) + $error='ERR_ALERT_FILE_UPLOAD'; + if(empty($error)){ + if (!move_uploaded_file($v['tmp_name'], $file_name)) + die("Possible file upload attack!\n"); + if(file_exists($file_name) && is_file($file_name)){ + $img_size = getimagesize($file_name); + $filetype = $img_size['mime']; + if($filetype != 'image/jpeg' && !empty($_REQUEST['sugarpdf_pdf_class']) && $_REQUEST['sugarpdf_pdf_class'] == "EZPDF"){ + $error='LBL_ALERT_TYPE_IMAGE_EZPDF'; + } + else if($filetype != 'image/jpeg' && $filetype != 'image/png'){ + $error='LBL_ALERT_TYPE_IMAGE'; + }else{ + $test=$img_size[0]/$img_size[1]; + if (($test>10 || $test<1)){ + //$error='LBL_ALERT_SIZE_RATIO_QUOTES'; + } + } + if(!empty($error)){ + rmdir_recursive($file_name); + }else{ + $_POST[$k]='pdf_logo_'. basename($v['name']); + } + }else{ + $error='ERR_ALERT_FILE_UPLOAD'; + } + } + } + } + return $error; + } +} diff --git a/modules/Connectors/Connector.js b/modules/Connectors/Connector.js new file mode 100644 index 00000000..31fc4e09 --- /dev/null +++ b/modules/Connectors/Connector.js @@ -0,0 +1,56 @@ +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ +function run_test(source_id){var callback={success:function(data){var resultDiv=document.getElementById(source_id+'_result');resultDiv.innerHTML=''+data.responseText+'';},failure:function(data){var resultDiv=document.getElementById(source_id+'_result');resultDiv.innerHTML=''+SUGAR.language.get('app_strings','ERROR_UNABLE_TO_RETRIEVE_DATA')+'';},timeout:300000} +var resultDiv=document.getElementById(source_id+'_result');resultDiv.innerHTML='';document.ModifyProperties.source_id.value=source_id;document.ModifyProperties.action.value='RunTest';YAHOO.util.Connect.setForm(document.ModifyProperties);var cObj=YAHOO.util.Connect.asyncRequest('POST','index.php?module=Connectors',callback);document.ModifyProperties.action.value='SaveModifyProperties';} +var widgetTimout;function dswidget_open(elt){var wdiget_div=document.getElementById('dswidget_div');var objX=findPosX(elt);var objY=findPosY(elt);wdiget_div.style.top=(objY+15)+'px';wdiget_div.style.left=(objX)+'px';wdiget_div.style.display='block';} +function dswidget_close(){widgetTimout=setTimeout("hide_widget()",500);} +function hide_widget(){var wdiget_div=document.getElementById('dswidget_div');wdiget_div.style.display='none';} +function clearButtonTimeout(){if(widgetTimout){clearTimeout(widgetTimout);}} +function findPosX(obj) +{var curleft=0;if(obj.offsetParent) +{while(obj.offsetParent) +{curleft+=obj.offsetLeft;obj=obj.offsetParent;} +if(obj!=null) +curleft+=obj.offsetLeft;} +else if(obj.x) +curleft+=obj.x;return curleft;} +function findPosY(obj) +{var curtop=0;if(obj.offsetParent) +{while(obj.offsetParent) +{curtop+=obj.offsetTop;obj=obj.offsetParent;} +if(obj!=null) +curtop+=obj.offsetTop;} +else if(obj.y) +curtop+=obj.y;return curtop;} \ No newline at end of file diff --git a/modules/Connectors/ConnectorRecord.php b/modules/Connectors/ConnectorRecord.php new file mode 100644 index 00000000..1643b12a --- /dev/null +++ b/modules/Connectors/ConnectorRecord.php @@ -0,0 +1,51 @@ + diff --git a/modules/Connectors/Forms.php b/modules/Connectors/Forms.php new file mode 100644 index 00000000..2a9e4983 --- /dev/null +++ b/modules/Connectors/Forms.php @@ -0,0 +1,38 @@ + \ No newline at end of file diff --git a/modules/Connectors/InstallDefaultConnectors.php b/modules/Connectors/InstallDefaultConnectors.php new file mode 100644 index 00000000..d1fdac19 --- /dev/null +++ b/modules/Connectors/InstallDefaultConnectors.php @@ -0,0 +1,116 @@ + + array ( + 'ext_rest_linkedin' => 'ext_rest_linkedin', + ), + 'Contacts' => + array ( + 'ext_rest_linkedin' => 'ext_rest_linkedin', + ), + + 'Leads' => + array ( + 'ext_rest_linkedin' => 'ext_rest_linkedin', + ), + 'Prospects' => + array ( + 'ext_rest_linkedin' => 'ext_rest_linkedin', + + ), + +); + +$previous_connectors = array(); +if(file_exists('custom/modules/Connectors/metadata/connectors.php')){ + require('custom/modules/Connectors/metadata/connectors.php'); + + foreach($connectors as $connector_array){ + $connector_id = $connector_array['id']; + $previous_connectors[$connector_id] = $connector_id; + } +} + +// Merge in old modules the customer added instead of overriding it completely with defaults +// If they have customized their connectors modules +if(file_exists('custom/modules/Connectors/metadata/display_config.php')){ + require('custom/modules/Connectors/metadata/display_config.php'); + + // Remove the default settings from being copied over since they already existed + foreach($default_modules_sources as $module => $sources){ + foreach($sources as $source_key => $source){ + foreach($previous_connectors as $previous_connector){ + if(in_array($previous_connector, $default_modules_sources[$module])){ + unset($default_modules_sources[$module][$previous_connector]); + } + } + } + } + + // Merge in the new connector default settings with the current settings + if ( isset($modules_sources) && is_array($modules_sources) ) { + foreach($modules_sources as $module => $sources){ + if(!empty($default_modules_sources[$module])){ + $merged = array_merge($modules_sources[$module], $default_modules_sources[$module]); + $default_modules_sources[$module] = $merged; + } + else{ + $default_modules_sources[$module] = $modules_sources[$module]; + } + } + } +} + +if(!file_exists('custom/modules/Connectors/metadata')) { + mkdir_recursive('custom/modules/Connectors/metadata'); +} + +if(!write_array_to_file('modules_sources', $default_modules_sources, 'custom/modules/Connectors/metadata/display_config.php')) { + $GLOBALS['log']->fatal('Cannot write file custom/modules/Connectors/metadata/display_config.php'); +} + +/* +require_once('include/connectors/utils/ConnectorUtils.php'); +if(!ConnectorUtils::updateMetaDataFiles()) { + $GLOBALS['log']->fatal('Cannot update metadata files for connectors'); +} +*/ + +?> diff --git a/modules/Connectors/Menu.php b/modules/Connectors/Menu.php new file mode 100644 index 00000000..5b004cc6 --- /dev/null +++ b/modules/Connectors/Menu.php @@ -0,0 +1,63 @@ + diff --git a/modules/Connectors/action_view_map.php b/modules/Connectors/action_view_map.php new file mode 100644 index 00000000..9a43a1ac --- /dev/null +++ b/modules/Connectors/action_view_map.php @@ -0,0 +1,60 @@ + \ No newline at end of file diff --git a/modules/Connectors/connectors/formatters/ext/rest/linkedin/linkedin.php b/modules/Connectors/connectors/formatters/ext/rest/linkedin/linkedin.php new file mode 100644 index 00000000..2c5d4fab --- /dev/null +++ b/modules/Connectors/connectors/formatters/ext/rest/linkedin/linkedin.php @@ -0,0 +1,60 @@ +getSourceMapping(); + $mapping_name = !empty($mapping['beans'][$this->_module]['name']) ? $mapping['beans'][$this->_module]['name'] : ''; + + if(!empty($mapping_name)) { + $this->_ss->assign('mapping_name', $mapping_name); + return $this->fetchSmarty(); + } + + $GLOBALS['log']->error($GLOBALS['app_strings']['ERR_MISSING_MAPPING_ENTRY_FORM_MODULE']); + return ''; +} + +public function getIconFilePath() { + return 'modules/Connectors/connectors/formatters/ext/rest/linkedin/tpls/linkedin.gif'; +} + +} +?> \ No newline at end of file diff --git a/modules/Connectors/connectors/formatters/ext/rest/linkedin/tpls/default.tpl b/modules/Connectors/connectors/formatters/ext/rest/linkedin/tpls/default.tpl new file mode 100644 index 00000000..f2f5869a --- /dev/null +++ b/modules/Connectors/connectors/formatters/ext/rest/linkedin/tpls/default.tpl @@ -0,0 +1,80 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} + + + +{literal} + +{/literal} + \ No newline at end of file diff --git a/modules/Connectors/connectors/formatters/ext/rest/linkedin/tpls/linkedin.gif b/modules/Connectors/connectors/formatters/ext/rest/linkedin/tpls/linkedin.gif new file mode 100644 index 0000000000000000000000000000000000000000..b610eba94f859591c798b6234e7dbd88a92060db GIT binary patch literal 325 zcmZ?wbhEHbMjSs2+F6c}_smVo@kz?S4N!O2NSNOZyBM&SUf z`RpA_AFZ%jAaTZVL5_uJyT9XM4FjFlQ;rKIa!i7_4mlNWFrMJHh~Yqlns|9-wYXq? pBbTfgn;0_#ix__+JGYFeh#ViUh+qeo_yX|&&#+Lh1qzM~)&K%_YexV8 literal 0 HcmV?d00001 diff --git a/modules/Connectors/connectors/formatters/ext/rest/twitter/tpls/twitter.gif b/modules/Connectors/connectors/formatters/ext/rest/twitter/tpls/twitter.gif new file mode 100644 index 0000000000000000000000000000000000000000..706c63e8d8729a9c283d4d3d45beaa702970a7ed GIT binary patch literal 115 zcmZ?wbhEHb 'LinkedIn©', + 'order' => 1, + 'properties' => + array ( + 'company_url'=>'http://www.linkedin.com/companyInsider?script&useBorder=no', + ), +); +?> diff --git a/modules/Connectors/connectors/sources/ext/rest/linkedin/language/en_us.lang.php b/modules/Connectors/connectors/sources/ext/rest/linkedin/language/en_us.lang.php new file mode 100644 index 00000000..76752d4f --- /dev/null +++ b/modules/Connectors/connectors/sources/ext/rest/linkedin/language/en_us.lang.php @@ -0,0 +1,56 @@ + '', //'LinkedIn© licensing info...', + + 'LBL_NAME' => 'Company Name', + + //Configuration labels + 'company_url' => 'URL', +); + +?> \ No newline at end of file diff --git a/modules/Connectors/connectors/sources/ext/rest/linkedin/linkedin.php b/modules/Connectors/connectors/sources/ext/rest/linkedin/linkedin.php new file mode 100644 index 00000000..3d1ebd45 --- /dev/null +++ b/modules/Connectors/connectors/sources/ext/rest/linkedin/linkedin.php @@ -0,0 +1,69 @@ +_enable_in_wizard = false; + $this->_enable_in_hover = true; + } + + /* + * getItem + * + * As the linked in connector does not have a true API call, we simply + * override this abstract method + */ + public function getItem($args=array(), $module=null){} + + + /* + * getList + * + * As the linked in connector does not have a true API call, we simply + * override this abstract method + */ + public function getList($args=array(), $module=null){} + + + public function __destruct(){ + parent::__destruct(); + } +} + +?> \ No newline at end of file diff --git a/modules/Connectors/connectors/sources/ext/rest/linkedin/mapping.php b/modules/Connectors/connectors/sources/ext/rest/linkedin/mapping.php new file mode 100644 index 00000000..6dc016d8 --- /dev/null +++ b/modules/Connectors/connectors/sources/ext/rest/linkedin/mapping.php @@ -0,0 +1,54 @@ + array ( + 'Accounts' => array ( + 'name'=>'name', + ), + 'Contacts' => array ( + 'name'=>'account_name', + ), + 'Leads' => array ( + 'name'=>'account_name', + ), + 'Prospects' => array( + 'name'=>'account_name', + ) + ), +); +?> \ No newline at end of file diff --git a/modules/Connectors/connectors/sources/ext/rest/linkedin/vardefs.php b/modules/Connectors/connectors/sources/ext/rest/linkedin/vardefs.php new file mode 100644 index 00000000..6e222782 --- /dev/null +++ b/modules/Connectors/connectors/sources/ext/rest/linkedin/vardefs.php @@ -0,0 +1,59 @@ + 'vardefs for linkedin connector', + 'fields' => array ( + 'id' => + array ( + 'name' => 'id', + 'vname' => 'LBL_ID', + 'type' => 'id', + 'comment' => 'Unique identifier', + 'hidden' => true, + ), + 'name'=> array( + 'name' => 'name', + 'vname' => 'LBL_NAME', + 'type' => 'varchar', + 'hover' => true, + 'comment' => 'The name of the company', + ), + ) +); +?> \ No newline at end of file diff --git a/modules/Connectors/controller.php b/modules/Connectors/controller.php new file mode 100644 index 00000000..5ff4057a --- /dev/null +++ b/modules/Connectors/controller.php @@ -0,0 +1,647 @@ +action, $this->admin_actions)) { + $this->hasAccess = false; + } + parent::process(); + } + + + /** + * When the user clicks the Search button, the form is posted back here and this action sets the + * search parameters in the session. Once this call returns, the tabs will then call RetrieveSource to load + * the data that was saved in the session. + * + */ + function action_SetSearch(){ + if(empty($_REQUEST)) { + return; + } + + $this->view = 'ajax'; + require_once('include/connectors/utils/ConnectorUtils.php'); + $searchdefs = ConnectorUtils::getSearchDefs(); + $merge_module = $_REQUEST['merge_module']; + $record_id = $_REQUEST['record']; + $searchDefs = isset($searchdefs) ? $searchdefs : array(); + unset($_SESSION['searchDefs'][$merge_module][$record_id]); + $sMap = array(); + + $search_source = $_REQUEST['source_id']; + $source_instance = ConnectorFactory::getInstance($search_source); + $source_map = $source_instance->getModuleMapping($merge_module); + $module_fields = array(); + foreach($_REQUEST as $search_term => $val){ + if(!empty($source_map[$search_term])){ + $module_fields[$source_map[$search_term]] = $val; + } + } + + foreach($module_fields as $search_term => $val){ + foreach($searchDefs as $source => $modules){ + if(empty($sMap[$source])){ + $instance = ConnectorFactory::getInstance($source); + $sMap[$source] = array_flip($instance->getModuleMapping($merge_module)); + } + + if(!empty($sMap[$source][$search_term])){ + $source_key = $sMap[$source][$search_term]; + $_SESSION['searchDefs'][$merge_module][$record_id][$source][$source_key] = $val; + } + } + } + } + + /** + * This action it meant to handle the hover action on the listview. + * + */ + function action_RetrieveSourceDetails() { + $this->view = 'ajax'; + $source_id = $_REQUEST['source_id']; + $record_id = $_REQUEST['record_id']; + + if(empty($source_id) || empty($record_id)) { + //display error here + return; + } + $source = ConnectorFactory::getInstance($source_id); + $module = $_SESSION['merge_module']; + + $result = $source->fillBean(array('id' => $record_id), $module); + require_once('include/connectors/utils/ConnectorUtils.php'); + $connector_strings = ConnectorUtils::getConnectorStrings($source_id); + + $fields = $source->getModuleMapping($module); + $fieldDefs = $source->getFieldDefs(); + $str = ''; + + foreach($fields as $key=>$field){ + + $label = $field; + if(isset($fieldDefs[$key])) { + $label = isset($connector_strings[$fieldDefs[$key]['vname']]) ? $connector_strings[$fieldDefs[$key]['vname']] : $label; + } + + $val = $result->$field; + if(!empty($val)){ + if(strlen($val) > 50) { + $val = substr($val, 0, 47) . '...'; + } + $str .= $label . ': ' . $val.'
    '; + } + } + global $theme; + $json = getJSONobj(); + $retArray = array(); + + $retArray['body'] = !empty($str) ? str_replace(array("\rn", "\r", "\n"), array('','','
    '), $str) : $GLOBALS['mod_strings']['ERROR_NO_ADDITIONAL_DETAIL']; + $retArray['caption'] = "
    {$GLOBALS['app_strings']['LBL_ADDITIONAL_DETAILS']}
    "; + $retArray['width'] = (empty($results['width']) ? '300' : $results['width']); + $retArray['theme'] = $theme; + echo 'result = ' . $json->encode($retArray); + } + + + function action_GetSearchForm(){ + $this->view = 'ajax'; + if(!empty($_REQUEST['source_id'])){ + //get the search fields and return the search form + + $ss = new Sugar_Smarty(); + require_once('include/connectors/utils/ConnectorUtils.php'); + $searchdefs = ConnectorUtils::getSearchDefs(); + $merge_module = $_REQUEST['merge_module']; + $seed = loadBean($merge_module); + $_searchDefs = isset($searchdefs) ? $searchdefs : array(); + $_trueFields = array(); + $source = $_REQUEST['source_id']; + + $searchLabels = ConnectorUtils::getConnectorStrings($source); + $record = $_REQUEST['record']; + $sourceObj = SourceFactory::getSource($source); + $field_defs = $sourceObj->getFieldDefs(); + + if(!empty($_searchDefs[$source][$merge_module])) { + foreach($_searchDefs[$source][$merge_module] as $key) { + if(!empty($_SESSION['searchDefs'][$merge_module][$record][$source][$key])){ + $_trueFields[$key]['value'] = $_SESSION['searchDefs'][$merge_module][$record][$source][$key]; + }else{ + $_trueFields[$key]['value'] = ''; + } + if(!empty($field_defs[$key]) && isset($searchLabels[$field_defs[$key]['vname']])){ + $_trueFields[$key]['label'] = $searchLabels[$field_defs[$key]['vname']]; + }else{ + $_trueFields[$key]['label'] = $key; + } + }//foreach + }//fi + + $ss->assign('mod', $GLOBALS['mod_strings']); + $ss->assign('search_fields', $_trueFields); + $ss->assign('source_id', $source); + $ss->assign('fields', $seed->field_defs); + $ss->assign('module', $merge_module); + $ss->assign('RECORD', $record); + $ss->assign('APP', $GLOBALS['app_strings']); + $ss->assign('MOD', $GLOBALS['mod_strings']); + echo $ss->fetch('modules/Connectors/tpls/search_form.tpl'); + } + } + + + function pre_save(){} + function post_save(){} + + + function action_CallRest() { + $this->view = 'ajax'; + + if(false === ($result=@file_get_contents($_REQUEST['url']))) { + echo ''; + } else if(!empty($_REQUEST['xml'])){ + $values = array(); + $p = xml_parser_create(); + xml_parse_into_struct($p, $result, $values); + xml_parser_free($p); + $json = getJSONobj(); + echo $json->encode($values); + } else { + echo $result; + } + } + + function action_CallSoap() { + $this->view = 'ajax'; + $source_id = $_REQUEST['source_id']; + $module = $_REQUEST['module_id']; + $return_params = explode(',', $_REQUEST['fields']); + require_once('include/connectors/ConnectorFactory.php'); + $component = ConnectorFactory::getInstance($source_id); + $beans = $component->fillBeans($_REQUEST, $module); + if(!empty($beans) && !empty($return_params)) { + $results = array(); + $count = 0; + foreach($beans as $bean) { + foreach($return_params as $field) { + $results[$count][$field] = $bean->$field; + } + $count++; + } + $json = getJSONobj(); + echo $json->encode($results); + } else { + echo ''; + } + } + + + function action_DefaultSoapPopup() { + $this->view = 'ajax'; + $source_id = $_REQUEST['source_id']; + $module = $_REQUEST['module_id']; + $id = $_REQUEST['record_id']; + $mapping = $_REQUEST['mapping']; + + $mapping = explode(',', $mapping); + //Error checking + + //Load bean + $bean = loadBean($module); + $bean->retrieve($id); + + require_once('include/connectors/ConnectorFactory.php'); + $component = ConnectorFactory::getInstance($source_id); + //Create arguments + $args = array(); + $field_defs = $bean->getFieldDefinitions(); + foreach($field_defs as $id=>$field) { + if(!empty($bean->$id)) { + $args[$id] = $bean->$id; + } + } + + $beans = $component->fillBeans($args, $module); + if(!empty($beans) && !empty($mapping)) { + $results = array(); + $count = 0; + foreach($beans as $bean) { + foreach($mapping as $field) { + $results[$count][$field] = $bean->$field; + } + $count++; + } + $json = getJSONobj(); + echo $json->encode($results); + } else { + $GLOBALS['log']->error($GLOBALS['app_strings']['ERR_MISSING_MAPPING_ENTRY_FORM_MODULE']); + echo ''; + } + } + + function action_SaveModifyProperties() { + require_once('include/connectors/sources/SourceFactory.php'); + $sources = array(); + $properties = array(); + foreach($_REQUEST as $name=>$value) { + if(preg_match("/^source[0-9]+$/", $name, $matches)) { + $source_id = $value; + $properties = array(); + foreach($_REQUEST as $arg=>$val) { + if(preg_match("/^{$source_id}_(.*?)$/", $arg, $matches2)) { + $properties[$matches2[1]] = $val; + } + } + $source = SourceFactory::getSource($source_id); + if(!empty($properties)) { + $source->setProperties($properties); + $source->saveConfig(); + } + } + } + + require_once('include/connectors/utils/ConnectorUtils.php'); + ConnectorUtils::updateMetaDataFiles(); + // BEGIN SUGAR INT + if(empty($_REQUEST['from_unit_test'])) { + // END SUGAR INT + header("Location: index.php?action=ConnectorSettings&module=Connectors"); + // BEGIN SUGAR INT + } + // END SUGAR INT + } + + function action_SaveModifyDisplay() { + if(empty($_REQUEST['display_sources'])) { + return; + } + + require_once('include/connectors/utils/ConnectorUtils.php'); + require_once('include/connectors/sources/SourceFactory.php'); + + $connectors = ConnectorUtils::getConnectors(); + $connector_keys = array_keys($connectors); + + $modules_sources = ConnectorUtils::getDisplayConfig(); + if ( !is_array($modules_sources) ) { + $modules_sources = (array) $modules_sources; + } + + $sources = array(); + $values = array(); + $new_modules_sources = array(); + + if(!empty($_REQUEST['display_values'])) { + $display_values = explode(',', $_REQUEST['display_values']); + foreach($display_values as $value) { + $entry = explode(':', $value); + $new_modules_sources[$entry[1]][$entry[0]] = $entry[0]; + } + } + + //These are the sources that were modified. + //We only update entries for these sources that have been changed + $display_sources = explode(',', $_REQUEST['display_sources']); + foreach($display_sources as $source) { + $sources[$source] = $source; + } //foreach + + $removedModules = array(); + + //Unset entries that have all sources removed + foreach($modules_sources as $module=>$source_entries) { + foreach($source_entries as $source_id) { + if(!empty($sources[$source_id]) && empty($new_modules_sources[$module][$source_id])) { + unset($modules_sources[$module][$source_id]); + $removedModules[$module] = true; + } + } + } + $removedModules = array_keys($removedModules); + foreach($removedModules as $key){ + if(empty($new_modules_sources[$key])){ + ConnectorUtils::cleanMetaDataFile($key); + } + } + + //Update based on new_modules_sources + foreach($new_modules_sources as $module=>$enabled_sources) { + //If the module is not in $modules_sources add it there + if(empty($modules_sources[$module])) { + $modules_sources[$module] = $enabled_sources; + } else { + foreach($enabled_sources as $source_id) { + if(empty($modules_sources[$module][$source_id])) { + $modules_sources[$module][$source_id] = $source_id; + } + } //foreach + } + } //foreach + + //Should we just remove entries where all sources are disabled? + $unset_modules = array(); + foreach($modules_sources as $module=>$mapping) { + if(empty($mapping)) { + $unset_modules[] = $module; + } + } + + foreach($unset_modules as $mod) { + unset($modules_sources[$mod]); + } + + if(!write_array_to_file('modules_sources', $modules_sources, CONNECTOR_DISPLAY_CONFIG_FILE)) { + //Log error and return empty array + $GLOBALS['log']->fatal("Cannot write \$modules_sources to " . CONNECTOR_DISPLAY_CONFIG_FILE); + } + + $sources_modules = array(); + foreach($modules_sources as $module=>$source_entries) { + foreach($source_entries as $id) { + $sources_modules[$id][$module] = $module; + } + } + + + //Now update the searchdefs and field mapping entries accordingly + require('modules/Connectors/metadata/searchdefs.php'); + $originalSearchDefs = $searchdefs; + $connectorSearchDefs = ConnectorUtils::getSearchDefs(); + + $searchdefs = array(); + foreach($sources_modules as $source_id=>$modules) { + foreach($modules as $module) { + $searchdefs[$source_id][$module] = !empty($connectorSearchDefs[$source_id][$module]) ? $connectorSearchDefs[$source_id][$module] : (!empty($originalSearchDefs[$source_id][$module]) ? $originalSearchDefs[$source_id][$module] : array()); + } + } + + //Write the new searchdefs out + if(!write_array_to_file('searchdefs', $searchdefs, 'custom/modules/Connectors/metadata/searchdefs.php')) { + $GLOBALS['log']->fatal("Cannot write file custom/modules/Connectors/metadata/searchdefs.php"); + } + + //Unset the $_SESSION['searchDefs'] variable + if (isset($_SESSION['searchDefs'])) { + unset($_SESSION['searchDefs']); + } + + + + //Clear mapping file if needed (this happens when all modules are removed from a source + foreach($sources as $id) { + if(empty($sources_modules[$source])) { + //Now write the new mapping entry to the custom folder + $dir = $connectors[$id]['directory']; + if(!preg_match('/^custom\//', $dir)) { + $dir = 'custom/' . $dir; + } + + if(!file_exists("{$dir}")) { + mkdir_recursive("{$dir}"); + } + + if(!write_array_to_file('mapping', array('beans'=>array()), "{$dir}/mapping.php")) { + $GLOBALS['log']->fatal("Cannot write file {$dir}/mapping.php"); + } + } //if + } //foreach + + //Now update the field mapping entries + foreach($sources_modules as $id=>$modules) { + $source = SourceFactory::getSource($id); + $mapping = $source->getMapping(); + $mapped_modules = array_keys($mapping['beans']); + + foreach($mapped_modules as $module) { + if(empty($sources_modules[$id][$module])) { + unset($mapping['beans'][$module]); + } + } + + //Remove modules from the mapping entries + foreach($modules as $module) { + if(empty($mapping['beans'][$module])) { + $originalMapping = $source->getOriginalMapping(); + if(empty($originalMapping['beans'][$module])) { + $defs = $source->getFieldDefs(); + $keys = array_keys($defs); + $new_mapping_entry = array(); + foreach($keys as $key) { + $new_mapping_entry[$key] = ''; + } + $mapping['beans'][$module] = $new_mapping_entry; + } else { + $mapping['beans'][$module] = $originalMapping['beans'][$module]; + } + } //if + + } //foreach + + //Now write the new mapping entry to the custom folder + $dir = $connectors[$id]['directory']; + if(!preg_match('/^custom\//', $dir)) { + $dir = 'custom/' . $dir; + } + + if(!file_exists("{$dir}")) { + mkdir_recursive("{$dir}"); + } + + if(!write_array_to_file('mapping', $mapping, "{$dir}/mapping.php")) { + $GLOBALS['log']->fatal("Cannot write file {$dir}/mapping.php"); + } + + } //foreach + + // save eapm configs + foreach($connectors as $connector_name => $data) { + if(isset($sources[$connector_name]) && !empty($data["eapm"])) { + // if we touched it AND it has EAPM data + $connectors[$connector_name]["eapm"]["enabled"] = !empty($_REQUEST[$connector_name."_external"]); + } + } + ConnectorUtils::saveConnectors($connectors); + + ConnectorUtils::updateMetaDataFiles(); + // BEGIN SUGAR INT + if(empty($_REQUEST['from_unit_test'])) { + // END SUGAR INT + header("Location: index.php?action=ConnectorSettings&module=Connectors"); + // BEGIN SUGAR INT + } + // END SUGAR INT + } + + + + + /** + * action_SaveModifyMapping + */ + function action_SaveModifyMapping() { + $mapping_sources = !empty($_REQUEST['mapping_sources']) ? explode(',', $_REQUEST['mapping_sources']) : array(); + $mapping_values = !empty($_REQUEST['mapping_values']) ? explode(',', $_REQUEST['mapping_values']) : array(); + + //Build the source->module->fields mapping + $source_modules_fields = array(); + foreach($mapping_values as $id) { + $parts = explode(':', $id); + $key_vals = explode('=', $parts[2]); + //Note the strtolwer call... we are lowercasing the key values + $source_modules_fields[$parts[0]][$parts[1]][strtolower($key_vals[0])] = $key_vals[1]; + } //foreach + + foreach($mapping_sources as $source_id) { + if(empty($source_modules_fields[$source_id])) { + $source = SourceFactory::getSource($source_id); + $mapping = $source->getMapping(); + foreach($mapping['beans'] as $module=>$entry) { + $source_modules_fields[$source_id][$module] = array(); + } + } + } //foreach + + + + + require_once('include/connectors/utils/ConnectorUtils.php'); + $source_entries = ConnectorUtils::getConnectors(); + + require_once('include/connectors/sources/SourceFactory.php'); + foreach($source_modules_fields as $id=>$mapping_entry) { + //Insert the id mapping + foreach($mapping_entry as $module=>$entry) { + $mapping_entry[$module]['id'] = 'id'; + } + + $source = SourceFactory::getSource($id); + $mapping = $source->getMapping(); + $mapping['beans'] = $mapping_entry; + + //Now write the new mapping entry to the custom folder + $dir = $source_entries[$id]['directory']; + if(!preg_match('/^custom\//', $dir)) { + $dir = 'custom/' . $dir; + } + + if(!file_exists("{$dir}")) { + mkdir_recursive("{$dir}"); + } + + if(!write_array_to_file('mapping', $mapping, "{$dir}/mapping.php")) { + $GLOBALS['log']->fatal("Cannot write file {$dir}/mapping.php"); + } + } + + //Rewrite the metadata files + ConnectorUtils::updateMetaDataFiles(); + + // BEGIN SUGAR INT + if(empty($_REQUEST['from_unit_test'])) { + // END SUGAR INT + header("Location: index.php?action=ConnectorSettings&module=Connectors"); + // BEGIN SUGAR INT + } + // END SUGAR INT + } + + + function action_RunTest() { + $this->view = 'ajax'; + $source_id = $_REQUEST['source_id']; + $source = SourceFactory::getSource($source_id); + $properties = array(); + foreach($_REQUEST as $name=>$value) { + if(preg_match("/^{$source_id}_(.*?)$/", $name, $matches)) { + $properties[$matches[1]] = $value; + } + } + $source->setProperties($properties); + $source->saveConfig(); + + //Call again and call init + $source = SourceFactory::getSource($source_id); + $source->init(); + + global $mod_strings; + + try { + if($source->isRequiredConfigFieldsForButtonSet() && $source->test()) { + echo $mod_strings['LBL_TEST_SOURCE_SUCCESS']; + } else { + echo $mod_strings['LBL_TEST_SOURCE_FAILED']; + } + } catch (Exception $ex) { + $GLOBALS['log']->fatal($ex->getMessage()); + echo $ex->getMessage(); + } + } + + + /** + * action_RetrieveSources + * Returns a JSON encoded format of the Connectors that are configured for the system + * + */ + function action_RetrieveSources() { + require_once('include/connectors/utils/ConnectorUtils.php'); + $this->view = 'ajax'; + $sources = ConnectorUtils:: getConnectors(); + $results = array(); + foreach($sources as $id=>$entry) { + $results[$id] = !empty($entry['name']) ? $entry['name'] : $id; + } + $json = getJSONobj(); + echo $json->encode($results); + } + +} +?> \ No newline at end of file diff --git a/modules/Connectors/language/en_us.lang.php b/modules/Connectors/language/en_us.lang.php new file mode 100644 index 00000000..9fa02eef --- /dev/null +++ b/modules/Connectors/language/en_us.lang.php @@ -0,0 +1,119 @@ + 'Add', + 'LBL_ADDRCITY' => 'City', + 'LBL_ADDRCOUNTRY' => 'Country', + 'LBL_ADDRCOUNTRY_ID' => 'Country Id', + 'LBL_ADDRSTATEPROV' => 'State', + 'LBL_ADMINISTRATION' => 'Connector Administration', + 'LBL_ADMINISTRATION_MAIN' => 'Connector Settings', + 'LBL_AVAILABLE' => 'Available', + 'LBL_BACK' => '< Back', + 'LBL_COMPANY_ID' => 'Company Id', + 'LBL_CONFIRM_CONTINUE_SAVE' => 'Some required fields have been left blank. Proceed to save changes?', + 'LBL_CONNECTOR' => 'Connector', + 'LBL_CONNECTOR_FIELDS' => 'Connector Fields', + 'LBL_DATA' => 'Data', + 'LBL_DEFAULT' => 'Default', + 'LBL_DELETE_MAPPING_ENTRY' => 'Are you sure you want to delete this entry?', + 'LBL_DISABLED' => 'Disabled', + 'LBL_DUNS' => 'DUNS', + 'LBL_EMPTY_BEANS' => 'No matches were found for your search criteria.', + 'LBL_ENABLED' => 'Enabled', + 'LBL_EXTERNAL' => 'Enable users to create external account records to this connector. In order to use this connector, the properties should also be set in the Set Connector Properties settings page.', + 'LBL_FINSALES' => 'Finsales', + 'LBL_MARKET_CAP' => 'Market Cap', + 'LBL_MERGE' => 'Merge', + 'LBL_MODIFY_DISPLAY_TITLE' => 'Enable Connectors', + 'LBL_MODIFY_DISPLAY_DESC' => 'Select which modules are enabled for each connector.', + 'LBL_MODIFY_DISPLAY_PAGE_TITLE' => 'Connector Settings: Enable Connectors', + 'LBL_MODULE_FIELDS' => 'Module Fields', + 'LBL_MODIFY_MAPPING_TITLE' => 'Map Connector Fields', + 'LBL_MODIFY_MAPPING_DESC' => 'Map connector fields to module fields in order to determine what connector data can be viewed and merged into the module records.', + 'LBL_MODIFY_MAPPING_PAGE_TITLE' => 'Connector Settings: Map Connector Fields', + 'LBL_MODIFY_PROPERTIES_TITLE' => 'Set Connector Properties', + 'LBL_MODIFY_PROPERTIES_DESC' => 'Configure the properties for each connector, including URLs and API keys.', + 'LBL_MODIFY_PROPERTIES_PAGE_TITLE' => 'Connector Settings: Set Connector Properties', + 'LBL_MODIFY_SEARCH_TITLE' => 'Manage Connector Search', + 'LBL_MODIFY_SEARCH' => 'Search', + 'LBL_MODIFY_SEARCH_DESC' => 'Select the connector fields to use to search for data for each module.', + 'LBL_MODIFY_SEARCH_PAGE_TITLE' => 'Connector Settings: Manage Connector Search', + 'LBL_MODULE_NAME' => 'Connectors', + 'LBL_NO_PROPERTIES' => 'There are no configurable properties for this connector.', + 'LBL_PARENT_DUNS' => 'Parent DUNS', + 'LBL_PREVIOUS' => '< Back', + 'LBL_QUOTE' => 'Quote', + 'LBL_RECNAME' => 'Company Name', + 'LBL_RESET_TO_DEFAULT' => 'Reset to Default', + 'LBL_RESET_TO_DEFAULT_CONFIRM' => 'Are you sure you want to reset to the default configuration?', + 'LBL_RESET_BUTTON_TITLE' => 'Reset [Alt+R]', + 'LBL_RESULT_LIST' => 'Data List', + 'LBL_RUN_WIZARD' => 'Run Wizard', + 'LBL_SAVE' => 'Save', + 'LBL_SEARCHING_BUTTON_LABEL' => 'Searching...', + 'LBL_SHOW_IN_LISTVIEW' => 'Show In Merge Listview', + 'LBL_SMART_COPY' => 'Smart Copy', + 'LBL_SUMMARY' => 'Summary', + 'LBL_STEP1' => 'Search and View Data', + 'LBL_STEP2' => 'Merge Records with', + 'LBL_TEST_SOURCE' => 'Test Connector', + 'LBL_TEST_SOURCE_FAILED' => 'Test Failed', + 'LBL_TEST_SOURCE_RUNNING' => 'Performing Test...', + 'LBL_TEST_SOURCE_SUCCESS' => 'Test Successful', + 'LBL_TITLE' => 'Data Merge', + 'LBL_ULTIMATE_PARENT_DUNS' => 'Ultimate Parent DUNS', + + 'ERROR_RECORD_NOT_SELECTED' => 'Error: Please select a record from the list before proceeding.', + 'ERROR_EMPTY_WRAPPER' => 'Error: Unable to retrieve wrapper instance for the source [{$source_id}]', + 'ERROR_EMPTY_SOURCE_ID' => 'Error: Source Id not specified or empty.', + 'ERROR_EMPTY_RECORD_ID' => 'Error: Record Id not specified or empty.', + 'ERROR_NO_ADDITIONAL_DETAIL' => 'Error: No additional details were found for the record.', + 'ERROR_NO_SEARCHDEFS_DEFINED' => 'No modules have been enabled for this connector. Select a module for this connector in the Enable Connectors page.', + 'ERROR_NO_SEARCHDEFS_MAPPED' => 'Error: There are no connectors enabled that have search fields defined.', + 'ERROR_NO_SOURCEDEFS_FILE' => 'Error: No sourcedefs.php file could be found.', + 'ERROR_NO_SOURCEDEFS_SPECIFIED' => 'Error: No sources were specified from which to retrieve data.', + 'ERROR_NO_CONNECTOR_DISPLAY_CONFIG_FILE' => 'Error: There are no connectors mapped to this module.', + 'ERROR_NO_SEARCHDEFS_MAPPING' => 'Error: There are no search fields defined for the module and connector. Please contact the system administrator.', + 'ERROR_NO_FIELDS_MAPPED' => 'Error: You must map at least one Connector field to a module field for each module entry.', + 'ERROR_NO_DISPLAYABLE_MAPPED_FIELDS' => 'Error: There are no module fields that have been mapped for display in the results. Please contact the system administrator.', +); + +?> \ No newline at end of file diff --git a/modules/Connectors/metadata/searchdefs.php b/modules/Connectors/metadata/searchdefs.php new file mode 100644 index 00000000..65dde03d --- /dev/null +++ b/modules/Connectors/metadata/searchdefs.php @@ -0,0 +1,43 @@ + diff --git a/modules/Connectors/tpls/administration.tpl b/modules/Connectors/tpls/administration.tpl new file mode 100644 index 00000000..99f724b7 --- /dev/null +++ b/modules/Connectors/tpls/administration.tpl @@ -0,0 +1,102 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} + + + + + + + +
    + + + + + + + + + + + + + + +
      {$mod.LBL_MODIFY_PROPERTIES_TITLE}
    + {$mod.LBL_MODIFY_PROPERTIES_DESC} +
     
      {$mod.LBL_MODIFY_DISPLAY_TITLE}
    + {$mod.LBL_MODIFY_DISPLAY_DESC} +
    +
      + + + + + + + + + + + + + + + + + + +
      {$mod.LBL_MODIFY_MAPPING_TITLE}
    + {$mod.LBL_MODIFY_MAPPING_DESC} +
     
    + +    + {* BEGIN SUGARCRM flav=pro || flav=sales ONLY *} + {$mod.LBL_MODIFY_SEARCH_TITLE}
    + {$mod.LBL_MODIFY_SEARCH_DESC} + {* END SUGARCRM flav=pro || flav=sales ONLY *} +
    +
     
    \ No newline at end of file diff --git a/modules/Connectors/tpls/display_properties.tpl b/modules/Connectors/tpls/display_properties.tpl new file mode 100644 index 00000000..1b3be862 --- /dev/null +++ b/modules/Connectors/tpls/display_properties.tpl @@ -0,0 +1,215 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} +{if !empty($external)} +
    +
    +{/if} +{if empty($externalOnly)} + + + + + + + + + + + +
    +{$mod.LBL_ENABLED} + +{$mod.LBL_DISABLED} + 
    +
    +
      +{foreach from=$enabled_modules item=module} +
    • {$module}
    • +{/foreach} +
    +
    +
    +
    +
      +{foreach from=$disabled_modules item=module} +
    • {$module}
    • +{/foreach} +
    +
    +
     
    + + +{else} + +{/if} \ No newline at end of file diff --git a/modules/Connectors/tpls/listview.tpl b/modules/Connectors/tpls/listview.tpl new file mode 100644 index 00000000..915ab097 --- /dev/null +++ b/modules/Connectors/tpls/listview.tpl @@ -0,0 +1,82 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} + + + + + + +{/if} +{/foreach} + + + +{foreach name=rowIteration from=$DATA key=id item=bean} + {counter name="offset" print=false} + {if $smarty.foreach.rowIteration.iteration is odd} + {assign var='_bgColor' value=$bgColor[0]} + {assign var='_rowColor' value=$rowColor[0]} + {assign var='_class' value='oddListRowS1'} + {else} + {assign var='_bgColor' value=$bgColor[1]} + {assign var='_rowColor' value=$rowColor[1]} + {assign var='_class' value='evenListRowS1'} + {/if} + + + + {foreach from=$displayColumns key=colHeader item=params} + {if $colHeader != 'id'} + + {/if} + {/foreach} + + + + +{/foreach} +
    {$APP.LBL_SELECT_BUTTON_LABEL} +{foreach from=$displayColumns key=colHeader item=params} +{if $colHeader != 'id'} + + {sugar_translate label=$params.label module=$module} + +
    + + + {sugar_connector_display bean=$bean field=$colHeader source=$source_id}
    diff --git a/modules/Connectors/tpls/mapping_properties.tpl b/modules/Connectors/tpls/mapping_properties.tpl new file mode 100644 index 00000000..9de5f178 --- /dev/null +++ b/modules/Connectors/tpls/mapping_properties.tpl @@ -0,0 +1,85 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} +
    +{foreach from=$display_data key=module item=data} + + + + + + + + +
    {$module}
    {$mod.LBL_CONNECTOR_FIELDS}{$mod.LBL_MODULE_FIELDS}
    + + + + + +
    +{foreach from=$data.field_keys key=field_id item=field} +{if $field_id != 'id'} +
    + + + + + +
    +{$field} + + +
    +
    +{/if} +{/foreach} +
    + +
    +{/foreach} +
    + +{if $empty_mapping} +

    {$mod.ERROR_NO_SEARCHDEFS_DEFINED}

    +{/if} + diff --git a/modules/Connectors/tpls/modify_display.tpl b/modules/Connectors/tpls/modify_display.tpl new file mode 100644 index 00000000..383b3fea --- /dev/null +++ b/modules/Connectors/tpls/modify_display.tpl @@ -0,0 +1,188 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} + + + + + +{literal} + + +{/literal} +
    + + + + +{counter assign=source_count start=0 print=0} +{foreach name=connectors from=$SOURCES key=name item=source} +{counter assign=source_count} + +{/foreach} + + + + + + +
    + + +
    + + +
    +
    +
    +
    +
    +
    + + +
    + + +
    +
    + + + + + \ No newline at end of file diff --git a/modules/Connectors/tpls/modify_mapping.tpl b/modules/Connectors/tpls/modify_mapping.tpl new file mode 100644 index 00000000..87a1a329 --- /dev/null +++ b/modules/Connectors/tpls/modify_mapping.tpl @@ -0,0 +1,183 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} + + + + +{literal} + + +{/literal} +
    + + + + + +{counter assign=source_count start=0 print=0} +{foreach name=connectors from=$SOURCES key=name item=source} +{counter assign=source_count} + +{/foreach} + + + + + + +
    + + +
    + + +
    +
    +
    +
    +
    +
    + + +
    + + +
    +
    + +{literal} + +{/literal} \ No newline at end of file diff --git a/modules/Connectors/tpls/modify_properties.tpl b/modules/Connectors/tpls/modify_properties.tpl new file mode 100644 index 00000000..641a086e --- /dev/null +++ b/modules/Connectors/tpls/modify_properties.tpl @@ -0,0 +1,155 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} + + + + + +{literal} + + +{/literal} +
    + + + + + + +{counter assign=source_count start=0 print=0} +{foreach name=connectors from=$SOURCES key=name item=source} +{counter assign=source_count} + +{/foreach} + + + +
    + + +
    + + + + +
    +
    +
    + +
    +
    +
    + + +
    + + +
    +
    + + \ No newline at end of file diff --git a/modules/Connectors/tpls/modify_search.tpl b/modules/Connectors/tpls/modify_search.tpl new file mode 100644 index 00000000..a77c1463 --- /dev/null +++ b/modules/Connectors/tpls/modify_search.tpl @@ -0,0 +1,184 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} + + + + +{literal} + + +{/literal} +
    + + + + + +{counter assign=source_count start=0 print=0} +{if count($SOURCES) == 0} + {$MOD.ERROR_NO_SEARCHDEFS_MAPPED} +{else} + {foreach name=connectors from=$SOURCES key=name item=source} + {counter assign=source_count} + + {/foreach} +{/if} + + + + + + +
    + + +
    + + +
    +
    +
    +
    +
    +
    + + +
    + + +
    +
    + + + \ No newline at end of file diff --git a/modules/Connectors/tpls/search_form.tpl b/modules/Connectors/tpls/search_form.tpl new file mode 100644 index 00000000..14dadefe --- /dev/null +++ b/modules/Connectors/tpls/search_form.tpl @@ -0,0 +1,72 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} + + + + +
    +

    {$mod.LBL_MODIFY_SEARCH}

    + +
    +
    + + + + +{if !empty($search_fields) } + + {counter assign=field_count start=0 print=0} + {foreach from=$search_fields key=field_name item=field_value} + {counter assign=field_count} + {if ($field_count % 3 == 1 && $field_count != 1)} + + {/if} + + + {/foreach} +{else} + {$mod.ERROR_NO_SEARCHDEFS_MAPPING} +{/if} +
    + {$field_value.label}: + + +
    +  + +
    \ No newline at end of file diff --git a/modules/Connectors/tpls/search_properties.tpl b/modules/Connectors/tpls/search_properties.tpl new file mode 100644 index 00000000..aa1dd832 --- /dev/null +++ b/modules/Connectors/tpls/search_properties.tpl @@ -0,0 +1,221 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} + +
    +{foreach from=$display_data key=module item=data} + + + + + + + + + + + + +
    {$module}
    {$mod.LBL_DEFAULT}{$mod.LBL_AVAILABLE}
    +
    +
      +{foreach from=$data.enabled key=enabled_id item=enabled_value} +
    • {$enabled_value}
    • +{/foreach} +
    +
    +
    +
    +
      +{foreach from=$data.disabled key=disabled_id item=disabled_value} +
    • {$disabled_value}
    • +{/foreach} +
    +
    +
    +
    +{/foreach} +
    + + + +{if $no_searchdefs_defined} +

    {$mod.ERROR_NO_SEARCHDEFS_DEFINED}

    +{/if} \ No newline at end of file diff --git a/modules/Connectors/tpls/source_properties.tpl b/modules/Connectors/tpls/source_properties.tpl new file mode 100644 index 00000000..af0f1592 --- /dev/null +++ b/modules/Connectors/tpls/source_properties.tpl @@ -0,0 +1,82 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} + +
    +{if !empty($connector_language.LBL_LICENSING_INFO)} +{$connector_language.LBL_LICENSING_INFO} +{/if} +
    + +{if !empty($properties)} +{foreach from=$properties key=name item=value} + + + + +{/foreach} +{if $hasTestingEnabled} + + + + + + +{/if} +{else} + + + + +{/if} +
    +{$connector_language[$name]}:  +{if isset($required_properties[$name])} +* +{/if} + +
    + +
    +  +
     {$mod.LBL_NO_PROPERTIES}
    + + \ No newline at end of file diff --git a/modules/Connectors/tpls/tabs.css b/modules/Connectors/tpls/tabs.css new file mode 100644 index 00000000..49ab14a4 --- /dev/null +++ b/modules/Connectors/tpls/tabs.css @@ -0,0 +1,134 @@ +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + +/* +Change log +243356 - F6F6F6 //very light gray (Sugar Grey) +a3a3a3 - d8d8d6 +2647a0 - EEEEE8 +EDF5FF - EEEEE8 +fff - 000 +*/ + +div.workarea { + padding: 5px; + float: left; + display:block; + width: 200px; + height: 100px; +} + +.yui-skin-sam .yui-navset .yui-content table, +.yui-skin-sam .yui-navset .yui-content td +{ + background: #F6F6F6 !important; + padding: 2px; + border: none; +} + +div.enabled_workarea, div.disabled_workarea { + background: #FFFFFF; +} + + +div.datasource_content { + padding: 0px; +} + + +div.add_table { + background: #F6F6F6; +} + + +ul.draglist { + position: relative; + float: left; + width: 200px; + height: 100px; + border: 1px solid #808080; + margin: 1px; + padding: 1px; + overflow: auto; + cursor: pointer; + list-style-type: none; + vertical-align: top; + display:block; + background: #FFFFFF; +} + + +li.noBullet2 { + position: relative; + margin: 0px; + cursor: pointer; + padding:0px; + background: #FFFFFF; + /* border:1px solid #7EA6B2; */ +} + + +ul.subpanelTablist +{ +border-bottom: 1px solid; +border-bottom-color: #ABC3D7; +} + + +div.enabled_module_workarea, div.disabled_module_workarea { + padding: 5px; + float: left; + display:block; + width: 200px; + height: 200px; +} + + +ul.module_draglist { + position: relative; + float: left; + width: 200px; + height: 200px; + border: 1px solid #808080; + margin: 1px; + padding: 1px; + overflow: auto; + cursor: pointer; + list-style-type: none; + vertical-align: top; + display:block; + background: #FFFFFF; +} diff --git a/modules/Connectors/views/view.connectorsettings.php b/modules/Connectors/views/view.connectorsettings.php new file mode 100644 index 00000000..82aa5e78 --- /dev/null +++ b/modules/Connectors/views/view.connectorsettings.php @@ -0,0 +1,77 @@ +".translate('LBL_MODULE_NAME','Administration')."", + $mod_strings['LBL_ADMINISTRATION_MAIN'] + ); + } + + /** + * @see SugarView::_getModuleTab() + */ + protected function _getModuleTab() + { + return 'Administration'; + } + + /** + * @see SugarView::display() + */ + public function display() + { + global $mod_strings, $app_strings; + + echo $this->getModuleTitle(false); + + $this->ss->assign('mod', $mod_strings); + $this->ss->assign('app', $app_strings); + $this->ss->assign('IMG', 'themes/default/images/'); + $this->ss->display('modules/Connectors/tpls/administration.tpl'); + } +} \ No newline at end of file diff --git a/modules/Connectors/views/view.displayproperties.php b/modules/Connectors/views/view.displayproperties.php new file mode 100644 index 00000000..b2fff5d8 --- /dev/null +++ b/modules/Connectors/views/view.displayproperties.php @@ -0,0 +1,115 @@ +options['show_all'] = false; + $this->options['show_javascript'] = true; + $this->options['show_footer'] = false; + $this->options['show_header'] = false; + parent::process(); + } + + /** + * @see SugarView::display() + */ + public function display() + { + require_once('include/connectors/utils/ConnectorUtils.php'); + $source = $_REQUEST['source_id']; + $sources = ConnectorUtils::getConnectors(); + $modules_sources = ConnectorUtils::getDisplayConfig(); + //$json = getJSONobj(); + + $enabled_modules = array(); + $disabled_modules = array(); + + //Find all modules this source has been enabled for + foreach($modules_sources as $module=>$mapping) { + foreach($modules_sources[$module] as $entry) { + if($entry == $source) { + $enabled_modules[$module] = $module; + } + } + } + + + global $moduleList, $beanList; + //Do filtering here? + $count = 0; + global $current_user; + $access = get_admin_modules_for_user($current_user); + $d = dir('modules'); + while($e = $d->read()){ + if(substr($e, 0, 1) == '.' || !is_dir('modules/' . $e))continue; + if(empty($enabled_modules[$e]) && file_exists('modules/' . $e . '/metadata/studio.php') && file_exists('modules/' . $e . '/metadata/detailviewdefs.php') && isset($GLOBALS [ 'beanList' ][$e]) && (in_array($e, $access) || is_admin($current_user))) // installed modules must also exist in the beanList + { + $disabled_modules[$e] = $e; + } + } + + asort($enabled_modules); + asort($disabled_modules); + + //$enabled = $json->encode($enabled_modules); + //$disabled = $json->encode($disabled_modules); + //$script = "addTable('{$module}', '{$enabled}', '{$disabled}', '{$source}', '{$GLOBALS['theme']}');\n"; + //$this->ss->assign('new_modules_sources', $modules_sources); + //$this->ss->assign('dynamic_script', $script); + + $this->ss->assign('enabled_modules', $enabled_modules); + $this->ss->assign('disabled_modules', $disabled_modules); + $this->ss->assign('source_id', $source); + $this->ss->assign('mod', $GLOBALS['mod_strings']); + $this->ss->assign('APP', $GLOBALS['app_strings']); + $this->ss->assign('theme', $GLOBALS['theme']); + $this->ss->assign('external', !empty($sources[$source]['eapm'])); + $this->ss->assign('externalOnly', !empty($sources[$source]['eapm']['only'])); + $this->ss->assign('externalChecked', !empty($sources[$source]['eapm']['enabled'])?" checked":""); + echo $this->ss->fetch('modules/Connectors/tpls/display_properties.tpl'); + } +} \ No newline at end of file diff --git a/modules/Connectors/views/view.mappingproperties.php b/modules/Connectors/views/view.mappingproperties.php new file mode 100644 index 00000000..4972b3ec --- /dev/null +++ b/modules/Connectors/views/view.mappingproperties.php @@ -0,0 +1,158 @@ +options['show_all'] = false; + $this->options['show_javascript'] = true; + $this->options['show_footer'] = false; + $this->options['show_header'] = false; + parent::process(); + } + + /** + * @see SugarView::display() + */ + public function display() + { + require_once('include/connectors/utils/ConnectorUtils.php'); + require_once('include/connectors/sources/SourceFactory.php'); + $connector_strings = ConnectorUtils::getConnectorStrings($_REQUEST['source_id']); + $sources = ConnectorUtils::getConnectors(); + $source_id = $_REQUEST['source_id']; + $source = SourceFactory::getSource($source_id); + $is_enabled = ConnectorUtils::isSourceEnabled($source_id); + $script = ''; + $display_data = array(); + if($is_enabled) { + $mapping = $source->getMapping(); + $source_defs = $source->getFieldDefs(); + + //Create the Javascript code to dynamically add the tables + $json = getJSONobj(); + foreach($mapping['beans'] as $module=>$field_mapping) { + + $mod_strings = return_module_language($GLOBALS['current_language'], $module); + $bean = loadBean($module); + if ( !is_object($bean) ) + continue; + $field_defs = $bean->getFieldDefinitions(); + $available_fields = array(); + + $labels = array(); + $duplicate_labels = array(); + foreach($field_defs as $id=>$def) { + + //We are filtering out some fields here + if($def['type'] == 'relate' || $def['type'] == 'link' || (isset($def['dbType']) && $def['dbType'] == 'id')) { + continue; + } + + + if(isset($def['vname'])) { + $available_fields[$id] = !empty($mod_strings[$def['vname']]) ? $mod_strings[$def['vname']] : $id; + } else { + $available_fields[$id] = $id; + } + + //Remove the ':' character in some labels + if(preg_match('/\:$/', $available_fields[$id])) { + $available_fields[$id] = substr($available_fields[$id], 0, strlen($available_fields[$id])-1); + } + + if(isset($labels[$available_fields[$id]])) { + $duplicate_labels[$labels[$available_fields[$id]]] = $labels[$available_fields[$id]]; + $duplicate_labels[$id] = $id; + } else { + $labels[$available_fields[$id]] = $id; + } + } + + foreach($duplicate_labels as $id) { + $available_fields[$id] = $available_fields[$id] . " ({$id})"; + } + + asort($available_fields); + + $field_keys = array(); + $field_values = array(); + + $source_fields = array(); + foreach($field_mapping as $id=>$field) { + if(!empty($source_defs[$id])) { + $source_fields[$id] = $source_defs[$id]; + } + } + $source_fields = array_merge($source_fields, $source_defs); + + foreach($source_fields as $id=>$def) { + if(empty($def['hidden'])){ + $field_keys[strtolower($id)] = !empty($connector_strings[$source_fields[$id]['vname']]) ? $connector_strings[$source_fields[$id]['vname']] : $id; + $field_values[] = !empty($field_mapping[strtolower($id)]) ? $field_mapping[strtolower($id)] : ''; + } + } + + $display_data[$module] = array('field_keys' => $field_keys, + 'field_values' => $field_values, + 'available_fields' => $available_fields, + 'field_mapping' => $field_mapping); + } + } + + $this->ss->assign('display_data', $display_data); + $this->ss->assign('empty_mapping', empty($display_data) ? true : false); + $this->ss->assign('dynamic_script', $script); + $this->ss->assign('sources', $sources); + $this->ss->assign('mod', $GLOBALS['mod_strings']); + $this->ss->assign('APP', $GLOBALS['app_strings']); + $this->ss->assign('source_id', $source_id); + $this->ss->assign('source_name', $sources[$source_id]['name']); + $this->ss->assign('theme', $GLOBALS['theme']); + + echo $this->ss->fetch('modules/Connectors/tpls/mapping_properties.tpl'); + } +} \ No newline at end of file diff --git a/modules/Connectors/views/view.modifydisplay.php b/modules/Connectors/views/view.modifydisplay.php new file mode 100644 index 00000000..093ea189 --- /dev/null +++ b/modules/Connectors/views/view.modifydisplay.php @@ -0,0 +1,82 @@ +".translate('LBL_MODULE_NAME','Administration')."", + "".$mod_strings['LBL_ADMINISTRATION_MAIN']."", + $mod_strings['LBL_MODIFY_DISPLAY_TITLE'] + ); + } + + /** + * @see SugarView::_getModuleTab() + */ + protected function _getModuleTab() + { + return 'Administration'; + } + + /** + * @see SugarView::display() + */ + public function display() + { + require_once('include/connectors/utils/ConnectorUtils.php'); + $sources = ConnectorUtils::getConnectors(); + $this->ss->assign('SOURCES', $sources); + $this->ss->assign('mod', $GLOBALS['mod_strings']); + $this->ss->assign('APP', $GLOBALS['app_strings']); + $this->ss->assign('theme', $GLOBALS['theme']); + + echo $this->getModuleTitle(); + $this->ss->display('modules/Connectors/tpls/modify_display.tpl'); + } +} \ No newline at end of file diff --git a/modules/Connectors/views/view.modifymapping.php b/modules/Connectors/views/view.modifymapping.php new file mode 100644 index 00000000..b2f9e72a --- /dev/null +++ b/modules/Connectors/views/view.modifymapping.php @@ -0,0 +1,90 @@ +".translate('LBL_MODULE_NAME','Administration')."", + "".$mod_strings['LBL_ADMINISTRATION_MAIN']."", + $mod_strings['LBL_MODIFY_MAPPING_TITLE'] + ); + } + + /** + * @see SugarView::_getModuleTab() + */ + protected function _getModuleTab() + { + return 'Administration'; + } + + /** + * @see SugarView::display() + */ + public function display() + { + require_once('include/connectors/utils/ConnectorUtils.php'); + require_once('include/connectors/sources/SourceFactory.php'); + global $mod_strings, $app_strings; + $this->ss->assign('mod', $mod_strings); + $this->ss->assign('APP', $app_strings); + $connectors = ConnectorUtils::getConnectors(true); + foreach($connectors as $id=>$source) { + $s = SourceFactory::getSource($id); + $mapping = $s->getMapping(); + if(empty($mapping)) { + unset($connectors[$id]); + } + } + + $this->ss->assign('SOURCES', $connectors); + echo $this->getModuleTitle(); + $this->ss->display('modules/Connectors/tpls/modify_mapping.tpl'); + } +} \ No newline at end of file diff --git a/modules/Connectors/views/view.modifyproperties.php b/modules/Connectors/views/view.modifyproperties.php new file mode 100644 index 00000000..9cb7a579 --- /dev/null +++ b/modules/Connectors/views/view.modifyproperties.php @@ -0,0 +1,104 @@ +".translate('LBL_MODULE_NAME','Administration')."", + "".$mod_strings['LBL_ADMINISTRATION_MAIN']."", + $mod_strings['LBL_MODIFY_PROPERTIES_TITLE'] + ); + } + + /** + * @see SugarView::_getModuleTab() + */ + protected function _getModuleTab() + { + return 'Administration'; + } + + /** + * @see SugarView::display() + */ + public function display() + { + global $mod_strings, $app_strings; + + require_once('include/connectors/utils/ConnectorUtils.php'); + require_once('include/connectors/sources/SourceFactory.php'); + + $this->ss->assign('mod', $mod_strings); + $this->ss->assign('APP', $app_strings); + $connectors = ConnectorUtils::getConnectors(true); + $required_fields = array(); + //Get required fields for first connector only + + $connectorsToShow = $connectors; + foreach($connectors as $id=>$entry) { + $s = SourceFactory::getSource($id); + $connector_strings = ConnectorUtils::getConnectorStrings($id); + $fields = $s->getRequiredConfigFields(); + + if(empty($fields)){ + unset($connectorsToShow[$id]); + }else{ + if(empty($required_fields)){ + foreach($fields as $field_id) { + $label = isset($connector_strings[$field_id]) ? $connector_strings[$field_id] : $field_id; + $required_fields[$id][$field_id]=$label; + } + } + } + } + $this->ss->assign('SOURCES', $connectorsToShow); + $this->ss->assign('REQUIRED_FIELDS', $required_fields); + echo $this->getModuleTitle(); + $this->ss->display('modules/Connectors/tpls/modify_properties.tpl'); + } +} \ No newline at end of file diff --git a/modules/Connectors/views/view.modifysearch.php b/modules/Connectors/views/view.modifysearch.php new file mode 100644 index 00000000..ed634cd1 --- /dev/null +++ b/modules/Connectors/views/view.modifysearch.php @@ -0,0 +1,90 @@ +".translate('LBL_MODULE_NAME','Administration')."", + "".$mod_strings['LBL_ADMINISTRATION_MAIN']."", + $mod_strings['LBL_MODIFY_SEARCH_TITLE'] + ); + } + + /** + * @see SugarView::_getModuleTab() + */ + protected function _getModuleTab() + { + return 'Administration'; + } + + /** + * @see SugarView::display() + */ + public function display() + { + require_once('include/connectors/utils/ConnectorUtils.php'); + global $mod_strings, $app_strings; + $sugar_smarty = new Sugar_Smarty(); + $this->ss->assign('mod', $mod_strings); + $this->ss->assign('APP', $app_strings); + $connectors = ConnectorUtils::getConnectors(); + foreach($connectors as $id=>$source) { + $s = SourceFactory::getSource($id); + if(!$s->isEnabledInWizard()) { + unset($connectors[$id]); + } + } + + $this->ss->assign('SOURCES', $connectors); + echo $this->getModuleTitle(); + $this->ss->display('modules/Connectors/tpls/modify_search.tpl'); + } +} \ No newline at end of file diff --git a/modules/Connectors/views/view.searchproperties.php b/modules/Connectors/views/view.searchproperties.php new file mode 100644 index 00000000..aca23ff7 --- /dev/null +++ b/modules/Connectors/views/view.searchproperties.php @@ -0,0 +1,126 @@ +options['show_all'] = false; + $this->options['show_javascript'] = true; + $this->options['show_footer'] = false; + $this->options['show_header'] = false; + parent::process(); + } + + /** + * @see SugarView::display() + */ + public function display() + { + require_once('include/connectors/utils/ConnectorUtils.php'); + require_once('include/connectors/sources/SourceFactory.php'); + $source_id = $_REQUEST['source_id']; + $connector_strings = ConnectorUtils::getConnectorStrings($source_id); + $is_enabled = ConnectorUtils::isSourceEnabled($source_id); + $modules_sources = array(); + $sources = ConnectorUtils::getConnectors(); + $display_data = array(); + + if($is_enabled) { + $searchDefs = ConnectorUtils::getSearchDefs(); + $searchDefs = !empty($searchDefs[$_REQUEST['source_id']]) ? $searchDefs[$_REQUEST['source_id']] : array(); + + $source = SourceFactory::getSource($_REQUEST['source_id']); + $field_defs = $source->getFieldDefs(); + + + //Create the Javascript code to dynamically add the tables + $json = getJSONobj(); + foreach($searchDefs as $module=>$fields) { + + $disabled = array(); + $enabled = array(); + + $enabled_fields = array_flip($fields); + $field_keys = array_keys($field_defs); + + foreach($field_keys as $index=>$key) { + if(!empty($field_defs[$key]['hidden']) || empty($field_defs[$key]['search'])) { + continue; + } + + if(!isset($enabled_fields[$key])) { + $disabled[$key] = !empty($connector_strings[$field_defs[$key]['vname']]) ? $connector_strings[$field_defs[$key]['vname']] : $key; + } else { + $enabled[$key] = !empty($connector_strings[$field_defs[$key]['vname']]) ? $connector_strings[$field_defs[$key]['vname']] : $key; + } + } + + $modules_sources[$module] = array_merge($enabled, $disabled); + asort($disabled); + $display_data[$module] = array('enabled' => $enabled, 'disabled' => $disabled); + } + } + + $this->ss->assign('no_searchdefs_defined', !$is_enabled); + $this->ss->assign('display_data', $display_data); + $this->ss->assign('modules_sources', $modules_sources); + $this->ss->assign('sources', $sources); + $this->ss->assign('mod', $GLOBALS['mod_strings']); + $this->ss->assign('APP', $GLOBALS['app_strings']); + $this->ss->assign('source_id', $_REQUEST['source_id']); + $this->ss->assign('theme', $GLOBALS['theme']); + $this->ss->assign('connector_language', $connector_strings); + echo $this->ss->fetch('modules/Connectors/tpls/search_properties.tpl'); + } +} \ No newline at end of file diff --git a/modules/Connectors/views/view.sourceproperties.php b/modules/Connectors/views/view.sourceproperties.php new file mode 100644 index 00000000..2fcf2c1c --- /dev/null +++ b/modules/Connectors/views/view.sourceproperties.php @@ -0,0 +1,88 @@ +getProperties(); + + $required_fields = array(); + $config_fields = $source->getRequiredConfigFields(); + $fields = $source->getRequiredConfigFields(); + foreach($fields as $field_id) { + $label = isset($connector_language[$field_id]) ? $connector_language[$field_id] : $field_id; + $required_fields[$field_id]=$label; + } + + $this->ss->assign('required_properties', $required_fields); + $this->ss->assign('source_id', $source_id); + $this->ss->assign('properties', $properties); + $this->ss->assign('mod', $GLOBALS['mod_strings']); + $this->ss->assign('app', $GLOBALS['app_strings']); + $this->ss->assign('connector_language', $connector_language); + $this->ss->assign('hasTestingEnabled', $source->hasTestingEnabled()); + echo $this->ss->fetch('modules/Connectors/tpls/source_properties.tpl'); + } +} + +?> \ No newline at end of file diff --git a/modules/Contacts/AcceptDecline.php b/modules/Contacts/AcceptDecline.php new file mode 100644 index 00000000..934e3f94 --- /dev/null +++ b/modules/Contacts/AcceptDecline.php @@ -0,0 +1,115 @@ +retrieve($_REQUEST['user_id']); + if ($result == null) { + session_destroy(); + sugar_cleanup(); + die("The user id doesn't exist"); + } + $current_entity = $current_user; +} +else if ( ! empty($_REQUEST['contact_id'])) { + $current_entity = new Contact(); + $current_entity->disable_row_level_security = true; + $result = $current_entity->retrieve($_REQUEST['contact_id']); + if($result == null) { + session_destroy(); + sugar_cleanup(); + die("The contact id doesn't exist"); + } +} +else if ( ! empty($_REQUEST['lead_id'])) { + $current_entity = new Lead(); + $current_entity->disable_row_level_security = true; + $result = $current_entity->retrieve($_REQUEST['lead_id']); + if($result == null) { + session_destroy(); + sugar_cleanup(); + die("The lead id doesn't exist"); + } +} + +$bean = $beanList[clean_string($_REQUEST['module'])]; +require_once($beanFiles[$bean]); +$focus = new $bean; +$focus->disable_row_level_security = true; +$result = $focus->retrieve($_REQUEST['record']); + +if($result == null) { + session_destroy(); + sugar_cleanup(); + die("The focus id doesn't exist"); +} + +$focus->set_accept_status($current_entity,$_REQUEST['accept_status']); + +print $app_strings['LBL_STATUS_UPDATED']."

    "; +print $app_strings['LBL_STATUS']. " ". $app_list_strings['dom_meeting_accept_status'][$_REQUEST['accept_status']]; +print "

    "; +$script = << + + +EOQ; + +print $script; +print "".$app_strings['LBL_CLOSE_WINDOW']."
    "; +sugar_cleanup(); +exit; +?> diff --git a/modules/Contacts/Address_picker.html b/modules/Contacts/Address_picker.html new file mode 100644 index 00000000..88afc89b --- /dev/null +++ b/modules/Contacts/Address_picker.html @@ -0,0 +1,118 @@ + + + + + + + + +{PAGINATION} + + + + + + + + + + + + + + + +{ASSOCIATED_JAVASCRIPT_DATA} +
    {CHECKALL}{MOD.LBL_LIST_CONTACT_NAME}{arrow_start}{last_name_arrow}{arrow_end}{MOD.LBL_PRIMARY_ADDRESS}{arrow_start}{email1_arrow}{arrow_end}{MOD.LBL_LIST_ACCOUNT_NAME}
    {PREROW}{CONTACT.FIRST_NAME} {CONTACT.LAST_NAME} + {CONTACT.PRIMARY_ADDRESS_STREET}
    + {CONTACT.PRIMARY_ADDRESS_CITY} {CONTACT.PRIMARY_ADDRESS_STATE}  {CONTACT.PRIMARY_ADDRESS_POSTALCODE}
    + {CONTACT.PRIMARY_ADDRESS_COUNTRY}
    +
    {CONTACT.ACCOUNT_NAME}
    + + \ No newline at end of file diff --git a/modules/Contacts/BusinessCard.html b/modules/Contacts/BusinessCard.html new file mode 100644 index 00000000..3cd9e2f0 --- /dev/null +++ b/modules/Contacts/BusinessCard.html @@ -0,0 +1,164 @@ + + + +{ERROR} + + + +
    + + + + + + + + +

    + + + +
    + + +
    + +

    + + +
    + + + + + + + + + + + + + + + +
    {ROWVALUE}

    {FORMHEADER}

    {FORMBODY}{FORMFOOTER}{POSTFORM}
    {FORMHEADER}
    {FORMBODY}{FORMFOOTER}{POSTFORM}
     
    +
    + +

    + + +
    + + + + + + + +

    {HEADER}

    {FORMBODY}{FORMFOOTER}{POSTFORM}
    +
    + + + + + +

    + + + +
    + + +
    + + +

    + + + + \ No newline at end of file diff --git a/modules/Contacts/BusinessCard.php b/modules/Contacts/BusinessCard.php new file mode 100644 index 00000000..cd62abcf --- /dev/null +++ b/modules/Contacts/BusinessCard.php @@ -0,0 +1,367 @@ +assign("MOD", $mod_strings); +$xtpl->assign("APP", $app_strings); +$xtpl->assign("PRINT_URL", "index.php?".$GLOBALS['request_string']); + +$xtpl->assign("HEADER", $mod_strings['LBL_ADD_BUSINESSCARD']); + +$xtpl->assign("MODULE", $_REQUEST['module']); +if ($error_msg != '') +{ + $xtpl->assign("ERROR", $error_msg); + $xtpl->parse("main.error"); +} + +if(isset($_POST['handle']) && $_POST['handle'] == 'Save'){ + + require_once('modules/Contacts/ContactFormBase.php'); + $contactForm = new ContactFormBase(); + require_once('modules/Accounts/AccountFormBase.php'); + $accountForm = new AccountFormBase(); + + require_once('modules/Opportunities/OpportunityFormBase.php'); + $oppForm = new OpportunityFormBase(); + if(!isset($_POST['selectedContact']) && !isset($_POST['ContinueContact'])){ + $duplicateContacts = $contactForm->checkForDuplicates('Contacts'); + if(isset($duplicateContacts)){ + $formBody = $contactForm->buildTableForm($duplicateContacts); + $xtpl->assign('FORMBODY', $formBody); + $xtpl->parse('main.formnoborder'); + $xtpl->parse('main'); + $xtpl->out('main'); + return; + } + } + + if(empty($_POST['selectedAccount']) && empty($_POST['ContinueAccount'])){ + $duplicateAccounts = $accountForm->checkForDuplicates('Accounts'); + + if(isset($duplicateAccounts)){ + $xtpl->assign('FORMBODY', $accountForm->buildTableForm($duplicateAccounts)); + $xtpl->parse('main.formnoborder'); + $xtpl->parse('main'); + $xtpl->out('main'); + return; + } + + } + + if(isset($_POST['newopportunity']) && $_POST['newopportunity']=='on' &&!isset($_POST['selectedOpportunity']) && !isset($_POST['ContinueOpportunity'])){ + + $duplicateOpps = $oppForm->checkForDuplicates('Opportunities'); + if(isset($duplicateOpps)){ + $xtpl->assign('FORMBODY', $oppForm->buildTableForm($duplicateOpps)); + $xtpl->parse('main.formnoborder'); + $xtpl->parse('main'); + $xtpl->out('main'); + return; + } + } + if(!empty($_POST['selectedContact'])){ + $contact = new Contact(); + $contact->retrieve($_POST['selectedContact']); + }else{ + $contact= $contactForm->handleSave('Contacts',false, false); + } + if(!empty($_POST['selectedAccount'])){ + $account = new Account(); + $account->retrieve($_POST['selectedAccount']); + }else if(isset($_POST['newaccount']) && $_POST['newaccount']=='on' ){ + $account= $accountForm->handleSave('Accounts',false, false); + } + if(isset($_POST['newopportunity']) && $_POST['newopportunity']=='on' ){ + if(!empty($_POST['selectedOpportunity'])){ + $opportunity = new Opportunity(); + $opportunity->retrieve($_POST['selectedOpportunity']); + }else{ + if(isset($account)){ + $_POST['Opportunitiesaccount_id'] = $account->id; + $_POST['Opportunitiesaccount_name'] = $account->name; + + } + if(isset($_POST['Contactslead_source']) && !empty($_POST['Contactslead_source'])){ + $_POST['Opportunitieslead_source'] = $_POST['Contactslead_source']; + } + $opportunity= $oppForm->handleSave('Opportunities',false, false); + + } + } + require_once('modules/Notes/NoteFormBase.php'); + + $noteForm = new NoteFormBase(); + if(isset($account)) + $_POST['AccountNotesparent_id'] = $account->id; + $accountnote= $noteForm->handleSave('AccountNotes',false, false); + if(isset($contact)) + $_POST['ContactNotesparent_type'] = "Contacts"; + $_POST['ContactNotesparent_id'] = $contact->id; + $contactnote= $noteForm->handleSave('ContactNotes',false, false); + if(isset($opportunity)){ + $_POST['OpportunityNotesparent_type'] = "Opportunities"; + $_POST['OpportunityNotesparent_id'] = $opportunity->id; + $opportunitynote= $noteForm->handleSave('OpportunityNotes',false, false); + } + if(isset($_POST['newappointment']) && $_POST['newappointment']=='on' ){ + if(isset($_POST['appointment']) && $_POST['appointment'] == 'Meeting'){ + require_once('modules/Meetings/MeetingFormBase.php'); + $meetingForm = new MeetingFormBase(); + $meeting= $meetingForm->handleSave('Appointments',false, false); + }else{ + require_once('modules/Calls/CallFormBase.php'); + $callForm = new CallFormBase(); + $call= $callForm->handleSave('Appointments',false, false); + } + } + + if(isset($call)){ + if(isset($contact)) { + $call->load_relationship('contacts'); + $call->contacts->add($contact->id); + } else if(isset($account)){ + $call->load_relationship('account'); + $call->account->add($account->id); + }else if(isset($opportunity)){ + $call->load_relationship('opportunity'); + $call->opportunity->add($opportunity->id); + } + } + if(isset($meeting)){ + if(isset($contact)) { + $meeting->load_relationship('contacts'); + $meeting->contacts->add($contact->id); + } else if(isset($account)){ + $meeting->load_relationship('account'); + $meeting->account->add($account->id); + }else if(isset($opportunity)){ + $meeting->load_relationship('opportunity'); + $meeting->opportunity->add($opportunity->id); + } + } + if(isset($account)){ + if(isset($contact)) { + $account->load_relationship('contacts'); + $account->contacts->add($contact->id); + } else if(isset($accountnote)){ + $account->load_relationship('notes'); + $account->notes->add($accountnote->id); + }else if(isset($opportunity)){ + $account->load_relationship('opportunities'); + $account->opportunities->add($opportunity->id); + } + } + if(isset($opportunity)){ + if(isset($contact)) { + $opportunity->load_relationship('contacts'); + $opportunity->contacts->add($contact->id); + } else if(isset($accountnote)){ + $opportunity->load_relationship('notes'); + $opportunity->notes->add($accountnote->id); + } + } + if(isset($contact)){ + if(isset($contactnote)){ + $contact->load_relationship('notes'); + $contact->notes->add($contactnote->id); + } + } + + if(isset($contact)){ + $contact->track_view($current_user->id, 'Contacts'); + if(isset($_POST['selectedContact']) && $_POST['selectedContact'] == $contact->id){ + $xtpl->assign('ROWVALUE', "
  • ".$mod_strings['LBL_EXISTING_CONTACT']." - ".$locale->getLocaleFormattedName($contact->first_name, $contact->last_name)."" ); + $xtpl->parse('main.row'); + }else{ + + $xtpl->assign('ROWVALUE', "
  • ".$mod_strings['LBL_CREATED_CONTACT']." - ".$locale->getLocaleFormattedName($contact->first_name, $contact->last_name)."" ); + $xtpl->parse('main.row'); + } + } + if(isset($account)){ + $account->track_view($current_user->id, 'Accounts'); + if(isset($_POST['selectedAccount']) && $_POST['selectedAccount'] == $account->id){ + $xtpl->assign('ROWVALUE', "
  • ".$mod_strings['LBL_EXISTING_ACCOUNT']. " - ".$account->name.""); + $xtpl->parse('main.row'); + }else{ + $xtpl->assign('ROWVALUE', "
  • ".$mod_strings['LBL_CREATED_ACCOUNT']. " - ".$account->name.""); + $xtpl->parse('main.row'); + } + + } + if(isset($opportunity)){ + $opportunity->track_view($current_user->id, 'Opportunities'); + if(isset($_POST['selectedOpportunity']) && $_POST['selectedOpportunity'] == $opportunity->id){ + $xtpl->assign('ROWVALUE', "
  • ".$mod_strings['LBL_EXISTING_OPPORTUNITY']. " - ".$opportunity->name.""); + $xtpl->parse('main.row'); + }else{ + $xtpl->assign('ROWVALUE', "
  • ".$mod_strings['LBL_CREATED_OPPORTUNITY']. " - ".$opportunity->name.""); + $xtpl->parse('main.row'); + } + + } + + if(isset($call)){ + $call->track_view($current_user->id, 'Calls'); + $xtpl->assign('ROWVALUE', "
  • ".$mod_strings['LBL_CREATED_CALL']. " - ".$call->name.""); + $xtpl->parse('main.row'); + } + if(isset($meeting)){ + $meeting->track_view($current_user->id, 'Meetings'); + $xtpl->assign('ROWVALUE', "
  • ".$mod_strings['LBL_CREATED_MEETING']. " - ".$meeting->name.""); + $xtpl->parse('main.row'); + } + $xtpl->assign('ROWVALUE'," "); + $xtpl->parse('main.row'); + $xtpl->assign('ROWVALUE',"{$mod_strings['LBL_ADDMORE_BUSINESSCARD']}"); + $xtpl->parse('main.row'); + $xtpl->parse('main'); + $xtpl->out('main'); +} + +else{ + +//CONTACT +$xtpl->assign('FORMHEADER',$mod_strings['LNK_NEW_CONTACT']); +$xtpl->parse("main.startform"); +$xtpl->parse("main.savebegin"); +require_once('modules/Contacts/ContactFormBase.php'); +$xtpl->assign('OPPNEEDSACCOUNT',$mod_strings['NTC_OPPORTUNITY_REQUIRES_ACCOUNT']); +if ($sugar_config['require_accounts']) { + $xtpl->assign('CHECKOPPORTUNITY', "&& checkOpportunity()"); +} +else { + $xtpl->assign('CHECKOPPORTUNITY', ""); +} +$contactForm = new ContactFormBase(); +$xtpl->assign('FORMBODY',$contactForm->getWideFormBody('Contacts', 'Contacts', 'BusinessCard', '', false)); +$xtpl->assign('TABLECLASS', 'edit view'); +$xtpl->assign('CLASS', 'dataLabel'); +require_once('modules/Notes/NoteFormBase.php'); +$noteForm = new NoteFormBase(); +$postform = "
    ${mod_strings['LNK_NEW_NOTE']}
    "; +$postform .= ''; + +$xtpl->assign('POSTFORM',$postform); +$xtpl->parse("main.form"); + + +$xtpl->assign('HEADER', $app_strings['LBL_RELATED_RECORDS']); +$xtpl->parse("main.hrrow"); +$popup_request_data = array( + 'call_back_function' => 'set_return', + 'form_name' => 'BusinessCard', + 'field_to_name_array' => array( + 'id' => 'selectedAccount', + 'name' => 'display_account_name', + ), + ); + +$json = getJSONobj(); +$encoded_contact_popup_request_data = $json->encode($popup_request_data); + +//Account +require_once('include/QuickSearchDefaults.php'); +$qsd = new QuickSearchDefaults(); +$qsd->setFormName('BusinessCard'); +$sqs_objects = array('BusinessCard_display_account_name' => $qsd->getQSParent()); +$sqs_objects['BusinessCard_display_account_name']['populate_list'] = array('display_account_name', 'selectedAccount'); +$quicksearch_js = ''; + +$selectAccountButton = $quicksearch_js; +$selectAccountButton .= "

    "; +$xtpl->assign('FORMHEADER',get_form_header($mod_strings['LNK_NEW_ACCOUNT'], '', '')); +require_once('modules/Accounts/AccountFormBase.php'); +$accountForm = new AccountFormBase(); +$xtpl->assign('CLASS', 'evenListRow'); +$xtpl->assign('FORMBODY',$selectAccountButton." ".$mod_strings['LNK_NEW_ACCOUNT']." 
  •   ${mod_strings['LBL_LEAD_SOURCE']}
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + $lead_source_label + + + + + + + + $lead_source_field + + + + +EOQ; + +$form .= $sugarEmailAddress->getEmailAddressWidgetEditView($contact->id, $_REQUEST['action']=='ConvertLead'?'Leads':'Contacts', false, 'include/SugarEmailAddress/templates/forWideFormBodyView.tpl'); + +require_once('include/SugarFields/Fields/Text/SugarFieldText.php'); +$sugarfield = new SugarFieldText('Text'); +$description_text = $sugarfield->getClassicEditView('description', $contact->description, $prefix, true); + +$form .= << + + + + + +EOQ; + + + + //carry forward custom lead fields common to contacts during Lead Conversion + $tempContact = new Contact(); + + if (method_exists($contact, 'convertCustomFieldsForm')) $contact->convertCustomFieldsForm($form, $tempContact, $prefix); + unset($tempContact); + +$form .= << + + + + + +EOQ; + + if ($portal == true){ + if (isset($contact->portal_name)) { + $form.=""; + } else { + $form.=""; + } + if (isset($contact->portal_app)) { + $form.=""; + } else { + $form.=""; + } + + + if(!empty($contact->portal_name) && !empty($contact->portal_app)){ + $form .= ""; + } + + if(isset($contact->portal_password)){ + $form.=""; + $form.=""; + $form .= ""; + }else{ + $form.=""; + $form.=""; + $form .= ""; + } + } + +$form .= << + Calendar.setup ({ + inputField : "{$prefix}jscal_field", daFormat : "$cal_dateformat", ifFormat : "$cal_dateformat", showsTime : false, button : "{$prefix}jscal_trigger", singleClick : true, step : 1, weekNumbers:false + }); + +EOQ; + + + + $javascript = new javascript(); + $javascript->setFormName($formname); + $javascript->setSugarBean(new Contact()); + $javascript->addField('email1','false',$prefix); + $javascript->addField('email2','false',$prefix); + $javascript->addRequiredFields($prefix); + + $form .=$javascript->getScript(); + $mod_strings = $temp_strings; + + + return $form; +} + +function getFormBody($prefix, $mod='', $formname=''){ + if(!ACLController::checkAccess('Contacts', 'edit', true)){ + return ''; + } +global $mod_strings; +$temp_strings = $mod_strings; +if(!empty($mod)){ + global $current_language; + $mod_strings = return_module_language($current_language, $mod); +} + global $app_strings; + global $current_user; + $lbl_required_symbol = $app_strings['LBL_REQUIRED_SYMBOL']; + $lbl_first_name = $mod_strings['LBL_FIRST_NAME']; + $lbl_last_name = $mod_strings['LBL_LAST_NAME']; + $lbl_phone = $mod_strings['LBL_PHONE']; + $user_id = $current_user->id; + $lbl_email_address = $mod_strings['LBL_EMAIL_ADDRESS']; +if ($formname == 'EmailEditView') +{ + $form = << + + + + $lbl_first_name
    +
    + $lbl_last_name $lbl_required_symbol
    +
    + $lbl_email_address $lbl_required_symbol
    +

    + +EOQ; +} +else +{ + $form = << + + + $lbl_first_name
    +
    + $lbl_last_name $lbl_required_symbol
    +
    + $lbl_phone
    +
    + $lbl_email_address
    +

    + +EOQ; +} + + +$javascript = new javascript(); +$javascript->setFormName($formname); +$javascript->setSugarBean(new Contact()); +$javascript->addField('email1','false',$prefix); +$javascript->addRequiredFields($prefix); + +$form .=$javascript->getScript(); +$mod_strings = $temp_strings; +return $form; + +} +function getForm($prefix, $mod=''){ + if(!ACLController::checkAccess('Contacts', 'edit', true)){ + return ''; + } +if(!empty($mod)){ + global $current_language; + $mod_strings = return_module_language($current_language, $mod); +}else global $mod_strings; +global $app_strings; + +$lbl_save_button_title = $app_strings['LBL_SAVE_BUTTON_TITLE']; +$lbl_save_button_key = $app_strings['LBL_SAVE_BUTTON_KEY']; +$lbl_save_button_label = $app_strings['LBL_SAVE_BUTTON_LABEL']; + + +$the_form = get_left_form_header($mod_strings['LBL_NEW_FORM_TITLE']); +$the_form .= << + + +EOQ; +$the_form .= $this->getFormBody($prefix,'Contacts', "${prefix}ContactSave"); +$the_form .= << + + +EOQ; +$the_form .= get_left_form_footer(); +$the_form .= get_validate_record_js(); + +return $the_form; + + +} + + +function handleSave($prefix, $redirect=true, $useRequired=false){ + global $theme, $current_user; + + + + + require_once('include/formbase.php'); + + global $timedate; + + $focus = new Contact(); + + if($useRequired && !checkRequired($prefix, array_keys($focus->required_fields))){ + return null; + } + + if (!empty($_POST[$prefix.'new_reports_to_id'])) { + $focus->retrieve($_POST[$prefix.'new_reports_to_id']); + $focus->reports_to_id = $_POST[$prefix.'record']; + } else { + + $focus = populateFromPost($prefix, $focus); + if(!empty($focus->portal_password) && $focus->portal_password != $_POST[$prefix.'old_portal_password']){ + $focus->portal_password = md5($focus->portal_password); + } + if (!isset($_POST[$prefix.'email_opt_out'])) $focus->email_opt_out = 0; + if (!isset($_POST[$prefix.'do_not_call'])) $focus->do_not_call = 0; + + } + if(!$focus->ACLAccess('Save')){ + ACLController::displayNoAccess(true); + sugar_cleanup(true); + } + if($_REQUEST['action'] != 'BusinessCard' && $_REQUEST['action'] != 'ConvertLead' && $_REQUEST['action'] != 'ConvertProspect') + { + + if (!empty($_POST[$prefix.'sync_contact'])){ + $focus->contacts_users_id = $current_user->id; + } + else{ + if (!isset($focus->users)) + { + $focus->load_relationship('user_sync'); + } + $focus->contacts_users_id = null; + $focus->user_sync->delete($focus->id, $current_user->id); + } + } + + if (isset($GLOBALS['check_notify'])) { + $check_notify = $GLOBALS['check_notify']; + } + else { + $check_notify = FALSE; + } + + + if (empty($_POST['record']) && empty($_POST['dup_checked'])) { + + $duplicateContacts = $this->checkForDuplicates($prefix); + if(isset($duplicateContacts)){ + $location='module=Contacts&action=ShowDuplicates'; + $get = ''; + if(isset($_POST['inbound_email_id']) && !empty($_POST['inbound_email_id'])) { + $get .= '&inbound_email_id='.$_POST['inbound_email_id']; + } + + // Bug 25311 - Add special handling for when the form specifies many-to-many relationships + if(isset($_POST['relate_to']) && !empty($_POST['relate_to'])) { + $get .= '&Contactsrelate_to='.$_POST['relate_to']; + } + if(isset($_POST['relate_id']) && !empty($_POST['relate_id'])) { + $get .= '&Contactsrelate_id='.$_POST['relate_id']; + } + + //add all of the post fields to redirect get string + foreach ($focus->column_fields as $field) + { + if (!empty($focus->$field) && !is_object($focus->$field)) + { + $get .= "&Contacts$field=".urlencode($focus->$field); + } + } + + foreach ($focus->additional_column_fields as $field) + { + if (!empty($focus->$field)) + { + $get .= "&Contacts$field=".urlencode($focus->$field); + } + } + + if($focus->hasCustomFields()) { + foreach($focus->field_defs as $name=>$field) { + if (!empty($field['source']) && $field['source'] == 'custom_fields') + { + $get .= "&Contacts$name=".urlencode($focus->$name); + } + } + } + + + $emailAddress = new SugarEmailAddress(); + $get .= $emailAddress->getFormBaseURL($focus); + + + //create list of suspected duplicate contact id's in redirect get string + $i=0; + foreach ($duplicateContacts as $contact) + { + $get .= "&duplicate[$i]=".$contact['id']; + $i++; + } + + //add return_module, return_action, and return_id to redirect get string + $get .= "&return_module="; + if(!empty($_POST['return_module'])) $get .= $_POST['return_module']; + else $get .= "Contacts"; + $get .= "&return_action="; + if(!empty($_POST['return_action'])) $get .= $_POST['return_action']; + //else $get .= "DetailView"; + if(!empty($_POST['return_id'])) $get .= "&return_id=".$_POST['return_id']; + if(!empty($_POST['popup'])) $get .= '&popup='.$_POST['popup']; + if(!empty($_POST['create'])) $get .= '&create='.$_POST['create']; + + // for InboundEmail flow + if(!empty($_POST['start'])) $get .= '&start='.$_POST['start']; + + //now redirect the post to modules/Contacts/ShowDuplicates.php + if (!empty($_POST['is_ajax_call']) && $_POST['is_ajax_call'] == '1') + { + ob_clean(); + $json = getJSONobj(); + $_SESSION['SHOW_DUPLICATES'] = $get; + echo $json->encode(array('status' => 'dupe', 'get' => $location)); + } else { + if(!empty($_POST['to_pdf'])) $location .= '&to_pdf='.$_POST['to_pdf']; + $_SESSION['SHOW_DUPLICATES'] = $get; + header("Location: index.php?$location"); + } + return null; + } + } + + global $current_user; + if(is_admin($current_user)){ + if (!isset($_POST[$prefix.'portal_active'])) $focus->portal_active = '0'; + //if no password is set set account to inactive for portal + if(empty($_POST[$prefix.'portal_name']))$focus->portal_active = '0'; + + } + + /////////////////////////////////////////////////////////////////////////////// + //// INBOUND EMAIL HANDLING + /////////////////////////////////////////////////////////////////////////////// + if(isset($_REQUEST['inbound_email_id']) && !empty($_REQUEST['inbound_email_id'])) { + // fake this case like it's already saved. + $focus->save($check_notify); + + $email = new Email(); + $email->retrieve($_REQUEST['inbound_email_id']); + $email->parent_type = 'Contacts'; + $email->parent_id = $focus->id; + $email->assigned_user_id = $current_user->id; + $email->status = 'read'; + $email->save(); + $email->load_relationship('contacts'); + $email->contacts->add($focus->id); + + header("Location: index.php?&module=Emails&action=EditView&type=out&inbound_email_id=".$_REQUEST['inbound_email_id']."&parent_id=".$email->parent_id."&parent_type=".$email->parent_type.'&start='.$_REQUEST['start'].'&assigned_user_id='.$current_user->id); + exit(); + } + //// END INBOUND EMAIL HANDLING + /////////////////////////////////////////////////////////////////////////////// + + $focus->save($check_notify); + $return_id = $focus->id; + + $GLOBALS['log']->debug("Saved record with id of ".$return_id); + + if (!empty($_POST['is_ajax_call']) && $_POST['is_ajax_call'] == '1') { + $json = getJSONobj(); + echo $json->encode(array('status' => 'success', + 'get' => '')); + $trackerManager = TrackerManager::getInstance(); + $timeStamp = TimeDate::getInstance()->nowDb(); + if($monitor = $trackerManager->getMonitor('tracker')){ + $monitor->setValue('action', 'detailview'); + $monitor->setValue('user_id', $GLOBALS['current_user']->id); + $monitor->setValue('module_name', 'Contacts'); + $monitor->setValue('date_modified', $timeStamp); + $monitor->setValue('visible', 1); + + if (!empty($this->bean->id)) { + $monitor->setValue('item_id', $return_id); + $monitor->setValue('item_summary', $focus->get_summary_text()); + } + $trackerManager->saveMonitor($monitor, true, true); + } + return null; + } + + if(isset($_POST['popup']) && $_POST['popup'] == 'true') { + $get = '&module='; + if(!empty($_POST['return_module'])) $get .= $_POST['return_module']; + else $get .= 'Contacts'; + $get .= '&action='; + if(!empty($_POST['return_action'])) $get .= $_POST['return_action']; + else $get .= 'Popup'; + if(!empty($_POST['return_id'])) $get .= '&return_id='.$_POST['return_id']; + if(!empty($_POST['popup'])) $get .= '&popup='.$_POST['popup']; + if(!empty($_POST['create'])) $get .= '&create='.$_POST['create']; + if(!empty($_POST['to_pdf'])) $get .= '&to_pdf='.$_POST['to_pdf']; + $get .= '&first_name=' . urlencode($focus->first_name); + $get .= '&last_name=' . urlencode($focus->last_name); + $get .= '&query=true'; + header("Location: index.php?$get"); + return; + } + + if($redirect){ + $this->handleRedirect($return_id); + }else{ + return $focus; + } +} + +function handleRedirect($return_id){ + if(isset($_POST['return_module']) && $_POST['return_module'] != "") { + $return_module = $_POST['return_module']; + } + else { + $return_module = "Contacts"; + } + + if(isset($_POST['return_action']) && $_POST['return_action'] != "") { + if($_REQUEST['return_module'] == 'Emails') { + $return_action = $_REQUEST['return_action']; + } + // if we create a new record "Save", we want to redirect to the DetailView + elseif($_REQUEST['action'] == "Save" && $_REQUEST['return_module'] != "Home") { + $return_action = 'DetailView'; + } else { + // if we "Cancel", we go back to the list view. + $return_action = $_REQUEST['return_action']; + } + } + else { + $return_action = "DetailView"; + } + + if(isset($_POST['return_id']) && $_POST['return_id'] != "") { + $return_id = $_POST['return_id']; + } + + header("Location: index.php?action=$return_action&module=$return_module&record=$return_id"); +} + +} + + +?> diff --git a/modules/Contacts/ContactOpportunityRelationship.php b/modules/Contacts/ContactOpportunityRelationship.php new file mode 100644 index 00000000..104d5691 --- /dev/null +++ b/modules/Contacts/ContactOpportunityRelationship.php @@ -0,0 +1,124 @@ +array('name' =>'id', 'type' =>'char', 'len'=>'36', 'default'=>'') + , 'contact_id'=>array('name' =>'contact_id', 'type' =>'char', 'len'=>'36', ) + , 'opportunity_id'=>array('name' =>'opportunity_id', 'type' =>'char', 'len'=>'36',) + , 'contact_role'=>array('name' =>'contact_role', 'type' =>'char', 'len'=>'50') + , 'date_modified'=>array ('name' => 'date_modified','type' => 'datetime') + , 'deleted'=>array('name' =>'deleted', 'type' =>'bool', 'len'=>'1', 'default'=>'0', 'required'=>true) + ); + function ContactOpportunityRelationship() { + $this->db = DBManagerFactory::getInstance(); + $this->dbManager = DBManagerFactory::getInstance(); + + $this->disable_row_level_security =true; + + } + + function fill_in_additional_detail_fields() + { + global $locale; + if(isset($this->contact_id) && $this->contact_id != "") + { + $query = "SELECT first_name, last_name from contacts where id='$this->contact_id' AND deleted=0"; + $result =$this->db->query($query,true," Error filling in additional detail fields: "); + // Get the id and the name. + $row = $this->db->fetchByAssoc($result); + + if($row != null) + { + $this->contact_name = $locale->getLocaleFormattedName($row['first_name'], $row['last_name']); + } + } + + if(isset($this->opportunity_id) && $this->opportunity_id != "") + { + $query = "SELECT name from opportunities where id='$this->opportunity_id' AND deleted=0"; + $result =$this->db->query($query,true," Error filling in additional detail fields: "); + // Get the id and the name. + $row = $this->db->fetchByAssoc($result); + + if($row != null) + { + $this->opportunity_name = $row['name']; + } + } + + } +} + + + +?> diff --git a/modules/Contacts/ContactOpportunityRelationshipEdit.html b/modules/Contacts/ContactOpportunityRelationshipEdit.html new file mode 100644 index 00000000..a6f767a4 --- /dev/null +++ b/modules/Contacts/ContactOpportunityRelationshipEdit.html @@ -0,0 +1,104 @@ + + + +
    + + + + + + +
    $lbl_first_name$lbl_last_name $lbl_required_symbol${mod_strings['LBL_TITLE']}${mod_strings['LBL_DEPARTMENT']}
     
    $lbl_address
    ${mod_strings['LBL_CITY']}${mod_strings['LBL_STATE']}${mod_strings['LBL_POSTAL_CODE']}${mod_strings['LBL_COUNTRY']}
    $lbl_phone${mod_strings['LBL_MOBILE_PHONE']}${mod_strings['LBL_FAX_PHONE']}${mod_strings['LBL_HOME_PHONE']}
    ${mod_strings['LBL_OTHER_PHONE']}${mod_strings['LBL_BIRTHDATE']} 
    +   + {$app_strings['LBL_ENTER_DATE']} +
    ${mod_strings['LBL_DESCRIPTION']}
    {$description_text}
    + + + + +
    + + +{APP.LBL_REQUIRED_SYMBOL} {APP.NTC_REQUIRED}
    + + +
    + + + + + + + + + + + + + + +
    {MOD.LBL_CONTACT_NAME} + + + + {MOD.LBL_OPP_NAME} + + + +
    {MOD.LBL_CONTACT_ROLE}  
    +
    + + +{JAVASCRIPT} + \ No newline at end of file diff --git a/modules/Contacts/ContactOpportunityRelationshipEdit.php b/modules/Contacts/ContactOpportunityRelationshipEdit.php new file mode 100644 index 00000000..4eec505c --- /dev/null +++ b/modules/Contacts/ContactOpportunityRelationshipEdit.php @@ -0,0 +1,115 @@ +retrieve($_REQUEST['record']); +} + +if(isset($_REQUEST['isDuplicate']) && $_REQUEST['isDuplicate'] == 'true') { + $focus->id = ""; +} + +// Prepopulate either side of the relationship if passed in. +safe_map('opportunity_name', $focus); +safe_map('opportunity_id', $focus); +safe_map('contact_name', $focus); +safe_map('contact_id', $focus); +safe_map('contact_role', $focus); + + +$GLOBALS['log']->info("Contact opportunity relationship"); + +$json = getJSONobj(); +require_once('include/QuickSearchDefaults.php'); +$qsd = new QuickSearchDefaults(); +$sqs_objects = array('opportunity_name' => $qsd->getQSParent()); +$sqs_objects['opportunity_name']['populate_list'] = array('opportunity_name', 'opportunity_id'); +$quicksearch_js = ''; +echo $quicksearch_js; + +$xtpl=new XTemplate ('modules/Contacts/ContactOpportunityRelationshipEdit.html'); +$xtpl->assign("MOD", $mod_strings); +$xtpl->assign("APP", $app_strings); + +$xtpl->assign("RETURN_URL", "&return_module=$currentModule&return_action=DetailView&return_id=$focus->id"); +$xtpl->assign("RETURN_MODULE", $_REQUEST['return_module']); +$xtpl->assign("RETURN_ACTION", $_REQUEST['return_action']); +$xtpl->assign("RETURN_ID", $_REQUEST['return_id']); +$xtpl->assign("PRINT_URL", "index.php?".$GLOBALS['request_string']); +$xtpl->assign("ID", $focus->id); +$xtpl->assign("CONTACT",$contactName = Array("NAME" => $focus->contact_name, "ID" => $focus->contact_id)); +$xtpl->assign("OPPORTUNITY",$oppName = Array("NAME" => $focus->opportunity_name, "ID" => $focus->opportunity_id)); + +echo getClassicModuleTitle($mod_strings['LBL_MODULE_NAME'], array($mod_strings['LBL_MODULE_NAME'],$mod_strings['LBL_CONTACT_OPP_FORM_TITLE']." ".$contactName['NAME'] . " - ". $oppName['NAME']), true); + +$xtpl->assign("CONTACT_ROLE_OPTIONS", get_select_options_with_id($app_list_strings['opportunity_relationship_type_dom'], $focus->contact_role)); + + + + +$xtpl->parse("main"); + +$xtpl->out("main"); + + +$javascript = new javascript(); +$javascript->setFormName('EditView'); +$javascript->setSugarBean($focus); +$javascript->addToValidateBinaryDependency('opportunity_name', 'alpha', $app_strings['ERR_SQS_NO_MATCH_FIELD'] . $mod_strings['LBL_OPP_NAME'], 'false', '', 'opportunity_id'); +echo $javascript->getScript(); + + +?> \ No newline at end of file diff --git a/modules/Contacts/ContactsQuickCreate.php b/modules/Contacts/ContactsQuickCreate.php new file mode 100644 index 00000000..771c9378 --- /dev/null +++ b/modules/Contacts/ContactsQuickCreate.php @@ -0,0 +1,72 @@ +ss->assign("SALUTATION_OPTIONS", get_select_options_with_id($app_list_strings['salutation_dom'], '')); + + if($this->viaAJAX) { // override for ajax call + $this->ss->assign('saveOnclick', "onclick='if(check_form(\"contactsQuickCreate\")) return SUGAR.subpanelUtils.inlineSave(this.form.id, \"contacts\"); else return false;'"); + $this->ss->assign('cancelOnclick', "onclick='return SUGAR.subpanelUtils.cancelCreate(\"subpanel_contacts\")';"); + } + + $this->ss->assign('viaAJAX', $this->viaAJAX); + + $this->javascript = new javascript(); + $this->javascript->setFormName('contactsQuickCreate'); + + $focus = new Contact(); + $this->javascript->setSugarBean($focus); + $this->javascript->addAllFields(''); + + $this->ss->assign('additionalScripts', $this->javascript->getScript(false)); + } +} +?> \ No newline at end of file diff --git a/modules/Contacts/Dashlets/MyContactsDashlet/MyContactsDashlet.data.php b/modules/Contacts/Dashlets/MyContactsDashlet/MyContactsDashlet.data.php new file mode 100644 index 00000000..1ccbbc34 --- /dev/null +++ b/modules/Contacts/Dashlets/MyContactsDashlet/MyContactsDashlet.data.php @@ -0,0 +1,87 @@ + array('default' => ''), + 'title' => array('default' => ''), + 'primary_address_country' => array('default' => ''), + 'assigned_user_id' => array('type' => 'assigned_user_name', + 'default' => $current_user->name, + 'label' => 'LBL_ASSIGNED_TO')); +$dashletData['MyContactsDashlet']['columns'] = array('name' => array('width' => '30', + 'label' => 'LBL_NAME', + 'link' => true, + 'default' => true, + 'related_fields' => array('first_name', 'last_name', 'salutation')), + 'account_name' => array('width' => '20', + 'label' => 'LBL_ACCOUNT_NAME', + 'sortable' => false, + 'link' => true, + 'module' => 'Accounts', + 'id' => 'ACCOUNT_ID', + 'ACLTag' => 'ACCOUNT'), + 'title' => array('width' => '20s', + 'label' => 'LBL_TITLE', + 'default' => true), + 'email1' => array('width' => '10', + 'label' => 'LBL_EMAIL_ADDRESS', + 'sortable' => false, + 'customCode' => '{$EMAIL1_LINK}{$EMAIL1}',), + 'phone_work' => array('width' => '15', + 'label' => 'LBL_OFFICE_PHONE', + 'default' => true), + 'phone_home' => array('width' => '10', + 'label' => 'LBL_HOME_PHONE'), + 'phone_mobile' => array('width' => '10', + 'label' => 'LBL_MOBILE_PHONE'), + 'phone_other' => array('width' => '10', + 'label' => 'LBL_OTHER_PHONE'), + 'date_entered' => array('width' => '15', + 'label' => 'LBL_DATE_ENTERED', + 'default' => true), + 'date_modified' => array('width' => '15', + 'label' => 'LBL_DATE_MODIFIED'), + 'created_by' => array('width' => '8', + 'label' => 'LBL_CREATED'), + 'assigned_user_name' => array('width' => '15', + 'label' => 'LBL_LIST_ASSIGNED_USER', + 'default' => true), + ); +?> diff --git a/modules/Contacts/Dashlets/MyContactsDashlet/MyContactsDashlet.meta.php b/modules/Contacts/Dashlets/MyContactsDashlet/MyContactsDashlet.meta.php new file mode 100644 index 00000000..28839407 --- /dev/null +++ b/modules/Contacts/Dashlets/MyContactsDashlet/MyContactsDashlet.meta.php @@ -0,0 +1,47 @@ + 'Contacts', + 'title' => translate('LBL_HOMEPAGE_TITLE', 'Contacts'), + 'description' => 'A customizable view into Contacts', + 'category' => 'Module Views'); +?> diff --git a/modules/Contacts/Dashlets/MyContactsDashlet/MyContactsDashlet.php b/modules/Contacts/Dashlets/MyContactsDashlet/MyContactsDashlet.php new file mode 100644 index 00000000..dd588019 --- /dev/null +++ b/modules/Contacts/Dashlets/MyContactsDashlet/MyContactsDashlet.php @@ -0,0 +1,61 @@ +title = translate('LBL_HOMEPAGE_TITLE', 'Contacts'); + + $this->searchFields = $dashletData['MyContactsDashlet']['searchFields']; + $this->columns = $dashletData['MyContactsDashlet']['columns']; + + $this->seedBean = new Contact(); + } +} + +?> diff --git a/modules/Contacts/Email_picker.html b/modules/Contacts/Email_picker.html new file mode 100644 index 00000000..180f68f3 --- /dev/null +++ b/modules/Contacts/Email_picker.html @@ -0,0 +1,178 @@ + + + + + + + +

    +

    + +

    + + + + {PAGINATION} + + + + + + + + + + + + + + + + + + + {ASSOCIATED_JAVASCRIPT_DATA} +
    + {CHECKALL} + + + {MOD.LBL_LIST_CONTACT_NAME}{arrow_start}{last_name_arrow}{arrow_end} + + + + {MOD.LBL_LIST_EMAIL_ADDRESS}{arrow_start}{email1_arrow}{arrow_end} + + + {MOD.LBL_LIST_ACCOUNT_NAME} +
    + {PREROW} + + + {CONTACT.FULL_NAME} + + + + {CONTACT.EMAIL1} + +
    + + {CONTACT.EMAIL2} + +
    + {CONTACT.ACCOUNT_NAME} +
    +
    + diff --git a/modules/Contacts/MailMergePicker.html b/modules/Contacts/MailMergePicker.html new file mode 100644 index 00000000..54eeaa48 --- /dev/null +++ b/modules/Contacts/MailMergePicker.html @@ -0,0 +1,185 @@ + + + + + + + + + + + + +
    + +
    + + +

    +

    + +

    + + + + + {PAGINATION} + + + + + + + + + + + + + + + + + + +
    + {CHECKALL} + + + {MOD.LBL_LIST_CONTACT_NAME}{arrow_start}{last_name_arrow}{arrow_end} + + + {MOD.LBL_LIST_TITLE}{arrow_start}{title_arrow}{arrow_end} + + {MOD.LBL_LIST_ACCOUNT_NAME} +
    + {PREROW} + + <{TAG_TYPE} href="#" onclick="send_back('Contacts','{CONTACT.ID}');" >{CONTACT.FULL_NAME} + + + {CONTACT.TITLE} + + {CONTACT.ACCOUNT_NAME} +
    +
    +{ASSOCIATED_JAVASCRIPT_DATA} + diff --git a/modules/Contacts/Menu.php b/modules/Contacts/Menu.php new file mode 100644 index 00000000..084008f1 --- /dev/null +++ b/modules/Contacts/Menu.php @@ -0,0 +1,53 @@ + \ No newline at end of file diff --git a/modules/Contacts/Popup_picker.php b/modules/Contacts/Popup_picker.php new file mode 100644 index 00000000..8d4f1220 --- /dev/null +++ b/modules/Contacts/Popup_picker.php @@ -0,0 +1,390 @@ +_get_where_clause(); + + + $formBase = new ContactFormBase(); + if(isset($_REQUEST['doAction']) && $_REQUEST['doAction'] == 'save') + { + $formBase->handleSave('', false, true); + } + + $first_name = empty($_REQUEST['first_name']) ? '' : $_REQUEST['first_name']; + $last_name = empty($_REQUEST['last_name']) ? '' : $_REQUEST['last_name']; + $account_name = empty($_REQUEST['account_name']) ? '' : $_REQUEST['account_name']; + $request_data = empty($_REQUEST['request_data']) ? '' : $_REQUEST['request_data']; + $hide_clear_button = empty($_REQUEST['hide_clear_button']) ? false : true; + $lbl_save_button_title = $app_strings['LBL_SAVE_BUTTON_TITLE']; + $lbl_save_button_key = $app_strings['LBL_SAVE_BUTTON_KEY']; + $lbl_save_button_label = $app_strings['LBL_SAVE_BUTTON_LABEL']; + + // TODO: cleanup the construction of $addform + $formbody = $formBase->getFormBody('','','EmailEditView'); + $addform = '
    ' + .str_replace('
    ', '
     ', $formbody) + . '
    ' + . ''; + $formSave = << + +EOQ; + $createContact = << +EOQ; + $addformheader = get_form_header($mod_strings['LNK_NEW_CONTACT'], $formSave, false); + $button = "
    \n"; + if(!$hide_clear_button) + { + $button .= "\n"; + } + $button .= "\n"; + $button .= "
    \n"; + + $form = new XTemplate('modules/Contacts/Address_picker.html'); + $form->assign('MOD', $mod_strings); + $form->assign('APP', $app_strings); + $form->assign('ADDFORMHEADER', $addformheader); + $form->assign('ADDFORM', $addform); + $form->assign('THEME', $theme); + $form->assign('MODULE_NAME', $currentModule); + $form->assign('FIRST_NAME', $first_name); + $form->assign('LAST_NAME', $last_name); + $form->assign('ACCOUNT_NAME', $account_name); + $form->assign('request_data', $request_data); + + // fill in for mass update + $button = "". + "". + "". + "". + "". + ""; + + if(isset($_REQUEST['mass']) && is_array($_REQUEST['mass'])) { + foreach(array_unique($_REQUEST['mass']) as $record) { + $button .= "\n"; + } + } + + $button .= ""; + $button .= ""; + $button .= ""; + $button .= ""; + $button .= ""; + // Added ID attribute to each element to use getElementById. To give ID attribute to an element is a good practice. + $button .= ""; + $button .= ""; + $button .= ""; + $button .= ""; + $button .= ""; + // Adding an onclick event to remove address for alternate address, as user has selected copy address to primary address + $button .= "\n"; + // Adding a new block of code copy the address to alternate address for contacts + $button .= ""; + $button .= ""; + $button .= ""; + $button .= ""; + $button .= ""; + // Adding an onclick event to remove address for primary address, as user has selected copy address to alternate address + // NOTE => You need to change the label as as per SugarCRM way.. + $button .= "\n"; + $button .= "\n"; + ob_start(); + insert_popup_header($theme); + $output_html .= ob_get_contents(); + ob_end_clean(); + + // Reset the sections that are already in the page so that they do not print again later. + $form->reset('main.SearchHeader'); + + // create the listview + $seed_bean = new Contact(); + $ListView = new ListView(); + $ListView->show_export_button = false; + $ListView->process_for_popups = true; + $ListView->show_delete_button = false; + $ListView->show_select_menu = false; + $ListView->setXTemplate($form); + $ListView->setHeaderTitle($mod_strings['LBL_LIST_FORM_TITLE']); + $ListView->setHeaderText($button); + $ListView->setQuery($where, '', '', 'CONTACT'); + $ListView->setModStrings($mod_strings); + + ob_start(); + $ListView->processListViewMulti($seed_bean, 'main', 'CONTACT'); + $output_html .= ob_get_contents(); + ob_end_clean(); + + // Regular Expression to override sListView + $exp = '/sListView.save_checks/si'; + $change = 'save_checks'; + $output_html = preg_replace(array($exp), array($change), $output_html); + + $output_html .= << + +EOJS; + + $output_html .= insert_popup_footer(); + return $output_html; + } + + function process_page_for_merge() + { + global $theme; + global $mod_strings; + global $app_strings; + global $currentModule; + global $sugar_version, $sugar_config; + + $output_html = ''; + $where = ''; + + $where = $this->_get_where_clause(); + + + + $first_name = empty($_REQUEST['first_name']) ? '' : $_REQUEST['first_name']; + $last_name = empty($_REQUEST['last_name']) ? '' : $_REQUEST['last_name']; + $account_name = empty($_REQUEST['account_name']) ? '' : $_REQUEST['account_name']; + $hide_clear_button = empty($_REQUEST['hide_clear_button']) ? false : true; + $button = "
    \n"; + //START:FOR MULTI-SELECT + $multi_select=false; + if (!empty($_REQUEST['mode']) && strtoupper($_REQUEST['mode']) == 'MULTISELECT') { + $multi_select=true; + $button .= "\n"; + } + //END:FOR MULTI-SELECT + if(!$hide_clear_button) + { + $button .= "\n"; + } + $button .= "\n"; + $button .= "
    \n"; + + $form = new XTemplate('modules/Contacts/MailMergePicker.html'); + $form->assign('MOD', $mod_strings); + $form->assign('APP', $app_strings); + $form->assign('THEME', $theme); + $form->assign('MODULE_NAME', $currentModule); + $form->assign('FIRST_NAME', $first_name); + $form->assign('LAST_NAME', $last_name); + $form->assign('ACCOUNT_NAME', $account_name); + $request_data = empty($_REQUEST['request_data']) ? '' : $_REQUEST['request_data']; + $form->assign('request_data', $request_data); + + ob_start(); + insert_popup_header($theme); + $output_html .= ob_get_contents(); + ob_end_clean(); + + $output_html .= get_form_header($mod_strings['LBL_SEARCH_FORM_TITLE'], '', false); + + $form->parse('main.SearchHeader'); + $output_html .= $form->text('main.SearchHeader'); + + // Reset the sections that are already in the page so that they do not print again later. + $form->reset('main.SearchHeader'); + + // create the listview + $seed_bean = new Contact(); + $ListView = new ListView(); + $ListView->display_header_and_footer=false; + $ListView->show_export_button = false; + $ListView->process_for_popups = true; + $ListView->setXTemplate($form); + $ListView->multi_select_popup=$multi_select; + if ($multi_select) $ListView->xTemplate->assign("TAG_TYPE","SPAN"); else $ListView->xTemplate->assign("TAG_TYPE","A"); + $ListView->setHeaderTitle($mod_strings['LBL_LIST_FORM_TITLE']); + $ListView->setQuery($where, '', 'contacts.last_name, contacts.first_name', 'CONTACT'); + $ListView->setModStrings($mod_strings); + + ob_start(); + $output_html .= get_form_header($mod_strings['LBL_LIST_FORM_TITLE'], $button, false); + //BEGIN ATHENA CUSTOMIZATION - rsmith + $query = $_REQUEST['select'].' WHERE '.$_REQUEST['where']."'".$_REQUEST['id']."'"; + + //$response = $seed_bean->process_list_query($_REQUEST['select'], 0, -1, -1, $_REQUEST['where']."'".$_REQUEST['id']."'"); + + $result = $seed_bean->db->query($query,true,"Error retrieving $seed_bean->object_name list: "); + + $list = Array(); + if(empty($rows_found)) + { + $rows_found = $seed_bean->db->getRowCount($result); + } + + $row_offset = 0; +global $sugar_config; + $max_per_page = $sugar_config['list_max_entries_per_page']; + + while(($row = $seed_bean->db->fetchByAssoc($result)) != null) + { + $seed_bean = new Contact(); + foreach($seed_bean->field_defs as $field=>$value) + { + if (isset($row[$field])) + { + $seed_bean->$field = $row[$field]; + } + else if (isset($row[$seed_bean->table_name .'.'.$field])) + { + $seed_bean->$field = $row[$seed_bean->table_name .'.'.$field]; + } + else + { + $seed_bean->$field = ""; + } + } + $seed_bean->fill_in_additional_list_fields(); + + $list[] = $seed_bean; + } + + $ListView->processListViewTwo($list, 'main', 'CONTACT'); + + //END ATHENA CUSTOMIZATION - rsmith + $output_html .= ob_get_contents(); + ob_end_clean(); + + $output_html .= insert_popup_footer(); + return $output_html; + + } +} +?> \ No newline at end of file diff --git a/modules/Contacts/Save.php b/modules/Contacts/Save.php new file mode 100644 index 00000000..298b4c36 --- /dev/null +++ b/modules/Contacts/Save.php @@ -0,0 +1,50 @@ +handleSave($prefix, true, false); + +?> \ No newline at end of file diff --git a/modules/Contacts/SaveContactOpportunityRelationship.php b/modules/Contacts/SaveContactOpportunityRelationship.php new file mode 100644 index 00000000..74e58613 --- /dev/null +++ b/modules/Contacts/SaveContactOpportunityRelationship.php @@ -0,0 +1,81 @@ +retrieve($_REQUEST['record']); + +foreach($focus->column_fields as $field) +{ + safe_map($field, $focus, true); +} + +foreach($focus->additional_column_fields as $field) +{ + safe_map($field, $focus, true); +} + +// send them to the edit screen. +if(isset($_REQUEST['record']) && $_REQUEST['record'] != "") +{ + $recordID = $_REQUEST['record']; +} + +$focus->save(); +$recordID = $focus->id; + +$GLOBALS['log']->debug("Saved record with id of ".$recordID); + +$header_URL = "Location: index.php?action={$_REQUEST['return_action']}&module={$_REQUEST['return_module']}&record={$_REQUEST['return_id']}"; +$GLOBALS['log']->debug("about to post header URL of: $header_URL"); + +header($header_URL); +?> + diff --git a/modules/Contacts/ShowDuplicates.html b/modules/Contacts/ShowDuplicates.html new file mode 100644 index 00000000..983c3d13 --- /dev/null +++ b/modules/Contacts/ShowDuplicates.html @@ -0,0 +1,68 @@ + + + +{ERROR} + + +
    + + + + + + + + +{INPUT_FIELDS} +

    + + +
    + + + + +

    {FORMHEADER}

    {FORMBODY}{FORMFOOTER}{POSTFORM}
    +
    +

    + + diff --git a/modules/Contacts/ShowDuplicates.php b/modules/Contacts/ShowDuplicates.php new file mode 100644 index 00000000..194c74a6 --- /dev/null +++ b/modules/Contacts/ShowDuplicates.php @@ -0,0 +1,174 @@ +debug('ShowDuplicates.php: _POST = '.print_r($_SESSION['SHOW_DUPLICATES'],true)); +parse_str($_SESSION['SHOW_DUPLICATES'],$_POST); +unset($_SESSION['SHOW_DUPLICATES']); +//$GLOBALS['log']->debug('ShowDuplicates.php: _POST = '.print_r($_POST,true)); + +global $app_strings; +global $app_list_strings; +global $theme; + +$error_msg = ''; +global $current_language; +$mod_strings = return_module_language($current_language, 'Contacts'); + +echo getClassicModuleTitle($mod_strings['LBL_MODULE_NAME'], array($mod_strings['LBL_MODULE_NAME'],$mod_strings['LBL_SAVE_CONTACT']), true); +$xtpl=new XTemplate ('modules/Contacts/ShowDuplicates.html'); +$xtpl->assign("MOD", $mod_strings); +$xtpl->assign("APP", $app_strings); +$xtpl->assign("PRINT_URL", "index.php?".$GLOBALS['request_string']); +$xtpl->assign("MODULE", $_REQUEST['module']); +if ($error_msg != '') +{ + $xtpl->assign("ERROR", $error_msg); + $xtpl->parse("main.error"); +} + +if((isset($_REQUEST['popup']) && $_REQUEST['popup'] == 'true') ||(isset($_POST['popup']) && $_POST['popup']==true)) insert_popup_header($theme); + + +$contact = new Contact(); +require_once('modules/Contacts/ContactFormBase.php'); +$contactForm = new ContactFormBase(); +$GLOBALS['check_notify'] = FALSE; + + +$query = 'select id, first_name, last_name, title from contacts where deleted=0 '; +$duplicates = $_POST['duplicate']; +$count = count($duplicates); +if ($count > 0) +{ + $query .= "and ("; + $first = true; + foreach ($duplicates as $duplicate_id) + { + if (!$first) $query .= ' OR '; + $first = false; + $query .= "id='$duplicate_id' "; + } + $query .= ')'; +} + +$duplicateContacts = array(); + +$db = DBManagerFactory::getInstance(); +$result = $db->query($query); +$i=0; +while (($row=$db->fetchByAssoc($result)) != null) { + $duplicateContacts[$i] = $row; + $i++; +} + +$xtpl->assign('FORMBODY', $contactForm->buildTableForm($duplicateContacts, 'Contacts')); + +$input = ''; +foreach ($contact->column_fields as $field) +{ + if (!empty($_POST['Contacts'.$field])) { + $input .= "\n"; + } +} + +foreach ($contact->additional_column_fields as $field) +{ + if (!empty($_POST['Contacts'.$field])) { + $input .= "\n"; + } +} + +// Bug 25311 - Add special handling for when the form specifies many-to-many relationships +if(!empty($_POST['Contactsrelate_to'])) { + $input .= "\n"; +} +if(!empty($_POST['Contactsrelate_id'])) { + $input .= "\n"; +} + + +$emailAddress = new SugarEmailAddress(); +$input .= $emailAddress->getEmailAddressWidgetDuplicatesView($contact); + +$get = ''; +if(!empty($_POST['return_module'])) $xtpl->assign('RETURN_MODULE', $_POST['return_module']); +else $get .= "Contacts"; +$get .= "&return_action="; +if(!empty($_POST['return_action'])) $xtpl->assign('RETURN_ACTION', $_POST['return_action']); +else $get .= "DetailView"; + +/////////////////////////////////////////////////////////////////////////////// +//// INBOUND EMAIL WORKFLOW +if(isset($_REQUEST['inbound_email_id'])) { + $xtpl->assign('INBOUND_EMAIL_ID', $_REQUEST['inbound_email_id']); + $xtpl->assign('RETURN_MODULE', 'Emails'); + $xtpl->assign('RETURN_ACTION', 'EditView'); + if(isset($_REQUEST['start'])) { + $xtpl->assign('START', $_REQUEST['start']); + } + +} +//// END INBOUND EMAIL WORKFLOW +/////////////////////////////////////////////////////////////////////////////// + + + +if(!empty($_POST['popup'])) + $input .= ''; +else + $input .= ''; + +if(!empty($_POST['to_pdf'])) + $input .= ''; +else + $input .= ''; + +if(!empty($_POST['create'])) + $input .= ''; +else + $input .= ''; + +if(!empty($_POST['return_id'])) $xtpl->assign('RETURN_ID', $_POST['return_id']); + +$xtpl->assign('INPUT_FIELDS',$input); +$xtpl->parse('main'); +$xtpl->out('main'); + +?> diff --git a/modules/Contacts/SugarFeeds/ContactFeed.php b/modules/Contacts/SugarFeeds/ContactFeed.php new file mode 100644 index 00000000..ded09d87 --- /dev/null +++ b/modules/Contacts/SugarFeeds/ContactFeed.php @@ -0,0 +1,57 @@ +fetched_row)){ + $text = '{SugarFeed.CREATED_CONTACT} [' . $bean->module_dir . ':' . $bean->id . ':' . $locale->getLocaleFormattedName($bean->first_name, $bean->last_name) . ']'; + } + + if(!empty($text)){ + SugarFeed::pushFeed2($text, $bean); + } + + } +} +?> diff --git a/modules/Contacts/controller.php b/modules/Contacts/controller.php new file mode 100644 index 00000000..ed34f3c6 --- /dev/null +++ b/modules/Contacts/controller.php @@ -0,0 +1,68 @@ +view = 'mailmergepopup'; + }else{ + $this->view = 'popup'; + } + } + + function action_ValidPortalUsername() + { + $this->view = 'validportalusername'; + } + + function action_RetrieveEmail() + { + $this->view = 'retrieveemail'; + } + + function action_ContactAddressPopup() + { + $this->view = 'contactaddresspopup'; + } + + function action_CloseContactAddressPopup() + { + $this->view = 'closecontactaddresspopup'; + } +} +?> \ No newline at end of file diff --git a/modules/Contacts/field_arrays.php b/modules/Contacts/field_arrays.php new file mode 100644 index 00000000..429445de --- /dev/null +++ b/modules/Contacts/field_arrays.php @@ -0,0 +1,91 @@ + Array("id" + ,"date_entered" + ,"date_modified" + ,"modified_user_id" + ,"assigned_user_id" + , "created_by" + ,"salutation" + ,"first_name" + ,"last_name" + ,"lead_source" + ,"title" + ,"department" + ,"birthdate" + ,"reports_to_id" + ,"do_not_call" + ,"phone_home" + ,"phone_mobile" + , "portal_name" + , "portal_app" + ,"portal_active" + ,"portal_password" + ,"phone_work" + ,"phone_other" + ,"phone_fax" + ,"assistant" + ,"assistant_phone" + ,"email_opt_out" + ,"primary_address_street" + ,"primary_address_city" + ,"primary_address_state" + ,"primary_address_postalcode" + ,"primary_address_country" + ,"alt_address_street" + ,"alt_address_city" + ,"alt_address_state" + ,"alt_address_postalcode" + ,"alt_address_country" + ,"description" + ,'invalid_email' + ,"campaign_id" + ), + 'list_fields' => Array('id', 'first_name', 'last_name', 'account_name', 'account_id', 'title', 'phone_work', 'assigned_user_name', 'assigned_user_id', "case_role", 'case_rel_id', 'opportunity_role', 'opportunity_rel_id' + ,'invalid_email' + ), + 'required_fields' => array("last_name"=>1), +); +?> \ No newline at end of file diff --git a/modules/Contacts/language/en_us.lang.php b/modules/Contacts/language/en_us.lang.php new file mode 100644 index 00000000..31eb17b0 --- /dev/null +++ b/modules/Contacts/language/en_us.lang.php @@ -0,0 +1,224 @@ + 'LBL_LIST_LAST_NAME', + 'db_first_name' => 'LBL_LIST_FIRST_NAME', + 'db_title' => 'LBL_LIST_TITLE', + 'db_email1' => 'LBL_LIST_EMAIL_ADDRESS', + 'db_email2' => 'LBL_LIST_OTHER_EMAIL_ADDRESS', + //END DON'T CONVERT + 'ERR_DELETE_RECORD' => 'Specify the record number to delete the contact.', + 'LBL_ACCOUNT_ID' => 'Account ID:', + 'LBL_ACCOUNT_NAME' => 'Account Name:', + 'LBL_CAMPAIGN' => 'Campaign:', + 'LBL_ACTIVITIES_SUBPANEL_TITLE'=>'Activities', + 'LBL_ADD_BUSINESSCARD' => 'Enter Business Card', + 'LBL_ADDMORE_BUSINESSCARD' => 'Add another business card', + 'LBL_ADDRESS_INFORMATION' => 'Address Information', + 'LBL_ALT_ADDRESS_CITY' => 'Alternate Address City:', + 'LBL_ALT_ADDRESS_COUNTRY' => 'Alternate Address Country:', + 'LBL_ALT_ADDRESS_POSTALCODE' => 'Alternate Address Postal Code:', + 'LBL_ALT_ADDRESS_STATE' => 'Alternate Address State:', + 'LBL_ALT_ADDRESS_STREET_2' => 'Alternate Address Street 2:', + 'LBL_ALT_ADDRESS_STREET_3' => 'Alternate Address Street 3:', + 'LBL_ALT_ADDRESS_STREET' => 'Alternate Address Street:', + 'LBL_ALTERNATE_ADDRESS' => 'Other Address:', + 'LBL_ALT_ADDRESS' => 'Other Address:', + 'LBL_ANY_ADDRESS' => 'Any Address:', + 'LBL_ANY_EMAIL' => 'Any Email:', + 'LBL_ANY_PHONE' => 'Any Phone:', + 'LBL_ASSIGNED_TO_NAME' => 'Assigned to:', + 'LBL_ASSIGNED_TO_ID' => 'Assigned User', + 'LBL_ASSISTANT_PHONE' => 'Assistant Phone:', + 'LBL_ASSISTANT' => 'Assistant:', + 'LBL_BIRTHDATE' => 'Birthdate:', + 'LBL_BUSINESSCARD' => 'Business Card', + 'LBL_CITY' => 'City:', + 'LBL_CAMPAIGN_ID' => 'Campaign ID', + 'LBL_CONTACT_INFORMATION' => 'Contact Overview', + 'LBL_CONTACT_NAME' => 'Contact Name:', + 'LBL_CONTACT_OPP_FORM_TITLE' => 'Contact-Opportunity:', + 'LBL_CONTACT_ROLE' => 'Role:', + 'LBL_CONTACT' => 'Contact:', + 'LBL_COUNTRY' => 'Country:', + 'LBL_CREATED_ACCOUNT' => 'Created a new account', + 'LBL_CREATED_CALL' => 'Created a new call', + 'LBL_CREATED_CONTACT' => 'Created a new contact', + 'LBL_CREATED_MEETING' => 'Created a new meeting', + 'LBL_CREATED_OPPORTUNITY' =>'Created a new opportunity', + 'LBL_DATE_MODIFIED' => 'Date Modified:', + 'LBL_DEFAULT_SUBPANEL_TITLE' => 'Contacts', + 'LBL_DEPARTMENT' => 'Department:', + 'LBL_DESCRIPTION_INFORMATION' => 'Description Information', + 'LBL_DESCRIPTION' => 'Description:', + 'LBL_DIRECT_REPORTS_SUBPANEL_TITLE'=>'Direct Reports', + 'LBL_DO_NOT_CALL' => 'Do Not Call:', + 'LBL_DUPLICATE' => 'Possible Duplicate Contacts', + 'LBL_EMAIL_ADDRESS' => 'Email Address:', + 'LBL_EMAIL_OPT_OUT' => 'Email Opt Out:', + 'LBL_EMPTY_VCARD' => 'Please select a vCard file', + 'LBL_EXISTING_ACCOUNT' => 'Used an existing account', + 'LBL_EXISTING_CONTACT' => 'Used an existing contact', + 'LBL_EXISTING_OPPORTUNITY'=> 'Used an existing opportunity', + 'LBL_FAX_PHONE' => 'Fax:', + 'LBL_FIRST_NAME' => 'First Name:', + 'LBL_FULL_NAME' => 'Full Name:', + 'LBL_HISTORY_SUBPANEL_TITLE'=>'History', + 'LBL_HOME_PHONE' => 'Home:', + 'LBL_ID' => 'ID:', + 'LBL_IMPORT_VCARD' => 'Import vCard', + 'LBL_VCARD' => 'vCard', + 'LBL_IMPORT_VCARDTEXT' => 'Automatically create a new contact by importing a vCard from your file system.', + 'LBL_INVALID_EMAIL'=>'Invalid Email:', + 'LBL_INVITEE' => 'Direct Reports', + 'LBL_LAST_NAME' => 'Last Name:', + 'LBL_LEAD_SOURCE' => 'Lead Source:', + 'LBL_LIST_ACCEPT_STATUS' => 'Accept Status', + 'LBL_LIST_ACCOUNT_NAME' => 'Account Name', + 'LBL_LIST_CONTACT_NAME' => 'Contact Name', + 'LBL_LIST_CONTACT_ROLE' => 'Role', + 'LBL_LIST_EMAIL_ADDRESS' => 'Email', + 'LBL_LIST_FIRST_NAME' => 'First Name', + 'LBL_LIST_FORM_TITLE' => 'Contact List', + 'LBL_VIEW_FORM_TITLE' => 'Contact View', + 'LBL_LIST_LAST_NAME' => 'Last Name', + 'LBL_LIST_NAME' => 'Name', + 'LBL_LIST_OTHER_EMAIL_ADDRESS' => 'Other Email', + 'LBL_LIST_PHONE' => 'Office Phone', + 'LBL_LIST_TITLE' => 'Title', + 'LBL_MOBILE_PHONE' => 'Mobile:', + 'LBL_MODIFIED' => 'Modified By:', + 'LBL_MODULE_NAME' => 'Contacts', + 'LBL_MODULE_TITLE' => 'Contacts: Home', + 'LBL_NAME' => 'Name:', + 'LBL_NEW_FORM_TITLE' => 'New Contact', + 'LBL_NEW_PORTAL_PASSWORD' => 'New Portal Password:', + 'LBL_NOTE_SUBJECT' =>'Note Subject', + 'LBL_OFFICE_PHONE' => 'Office Phone:', + 'LBL_OPP_NAME' => 'Opportunity Name:', + 'LBL_OPPORTUNITY_ROLE_ID'=>'Opportunity Role ID:', + 'LBL_OPPORTUNITY_ROLE'=>'Opportunity Role', + 'LBL_OTHER_EMAIL_ADDRESS' => 'Other Email:', + 'LBL_OTHER_PHONE' => 'Other Phone:', + 'LBL_PHONE' => 'Phone:', + 'LBL_PORTAL_ACTIVE' => 'Portal Active:', + 'LBL_PORTAL_APP'=>'Portal Application:', + 'LBL_PORTAL_INFORMATION' => 'Portal Information', + 'LBL_PORTAL_NAME' => 'Portal Name:', + 'LBL_PORTAL_PASSWORD_ISSET' => 'Portal Password is Set:', + 'LBL_STREET' => 'Street', + 'LBL_POSTAL_CODE' => 'Postal Code:', + 'LBL_PRIMARY_ADDRESS_CITY' => 'Primary Address City:', + 'LBL_PRIMARY_ADDRESS_COUNTRY' => 'Primary Address Country:', + 'LBL_PRIMARY_ADDRESS_POSTALCODE' => 'Primary Address Postal Code:', + 'LBL_PRIMARY_ADDRESS_STATE' => 'Primary Address State:', + 'LBL_PRIMARY_ADDRESS_STREET_2' => 'Primary Address Street 2:', + 'LBL_PRIMARY_ADDRESS_STREET_3' => 'Primary Address Street 3:', + 'LBL_PRIMARY_ADDRESS_STREET' => 'Primary Address Street:', + 'LBL_PRIMARY_ADDRESS' => 'Primary Address:', + 'LBL_PRODUCTS_TITLE'=>'Products', + 'LBL_RELATED_CONTACTS_TITLE'=>'Related Contacts', + 'LBL_REPORTS_TO_ID'=>'Reports to ID:', + 'LBL_REPORTS_TO' => 'Reports To:', + 'LBL_RESOURCE_NAME' => 'Resource Name', + 'LBL_SALUTATION' => 'Salutation:', + 'LBL_SAVE_CONTACT' => 'Save Contact', + 'LBL_SEARCH_FORM_TITLE' => 'Contact Search', + 'LBL_SELECT_CHECKED_BUTTON_LABEL' => 'Select Checked Contacts', + 'LBL_SELECT_CHECKED_BUTTON_TITLE' => 'Select Checked Contacts', + 'LBL_STATE' => 'State:', + 'LBL_SYNC_CONTACT' => 'Sync to Outlook®:', + 'LBL_PROSPECT_LIST' => 'Prospect List', + 'LBL_TITLE' => 'Title:', + 'LNK_CONTACT_LIST' => 'View Contacts', + 'LNK_IMPORT_VCARD' => 'Create Contact From vCard', + 'LNK_NEW_ACCOUNT' => 'Create Account', + 'LNK_NEW_APPOINTMENT' => 'Create Appointment', + 'LNK_NEW_CALL' => 'Log Call', + 'LNK_NEW_CASE' => 'Create Case', + 'LNK_NEW_CONTACT' => 'Create Contact', + 'LNK_NEW_EMAIL' => 'Archive Email', + 'LNK_NEW_MEETING' => 'Schedule Meeting', + 'LNK_NEW_NOTE' => 'Create Note', + 'LNK_NEW_OPPORTUNITY' => 'Create Opportunity', + 'LNK_NEW_TASK' => 'Create Task', + 'LNK_SELECT_ACCOUNT' => "Select Account", + 'MSG_DUPLICATE' => 'The contact record you are about to create might be a duplicate of a contact record that already exists. Contact records containing similar names are listed below.
    Click Create Contact to continue creating this new contact, or select an existing contact listed below.', + 'MSG_SHOW_DUPLICATES' => 'The contact record you are about to create might be a duplicate of a contact record that already exists. Contact records containing similar names are listed below.
    Click Save to continue creating this new contact, or click Cancel to return to the module without creating the contact.', + 'NTC_COPY_ALTERNATE_ADDRESS' => 'Copy alternate address to primary address', + 'NTC_COPY_PRIMARY_ADDRESS' => 'Copy primary address to alternate address', + 'NTC_DELETE_CONFIRMATION' => 'Are you sure you want to delete this record?', + 'NTC_OPPORTUNITY_REQUIRES_ACCOUNT' => 'Creating an opportunity requires an account.\n Please either create a new account or select an existing one.', + 'NTC_REMOVE_CONFIRMATION' => 'Are you sure you want to remove this contact from the case?', + 'NTC_REMOVE_DIRECT_REPORT_CONFIRMATION' => 'Are you sure you want to remove this record as a direct report?', + + 'LBL_USER_PASSWORD' => 'Password:', + + 'LBL_LEADS_SUBPANEL_TITLE' => 'Leads', + 'LBL_OPPORTUNITIES_SUBPANEL_TITLE' => 'Opportunities', + 'LBL_DOCUMENTS_SUBPANEL_TITLE' => 'Documents', + 'LBL_COPY_ADDRESS_CHECKED_PRIMARY' => 'Copy to Primary Address', + 'LBL_COPY_ADDRESS_CHECKED_ALT' => 'Copy to Other Address', + + 'LBL_CASES_SUBPANEL_TITLE' => 'Cases', + 'LBL_BUGS_SUBPANEL_TITLE' => 'Bugs', + 'LBL_PROJECTS_SUBPANEL_TITLE' => 'Projects', + 'LBL_TARGET_OF_CAMPAIGNS' => 'Campaigns (Target of) :', + 'LBL_CAMPAIGNS' => 'Campaigns', + 'LBL_CAMPAIGN_LIST_SUBPANEL_TITLE'=>'Campaigns', + 'LBL_LIST_CITY' => 'City', + 'LBL_LIST_STATE' => 'State', + 'LBL_HOMEPAGE_TITLE' => 'My Contacts', + 'LBL_OPPORTUNITIES' => 'Opportunities', + + 'LBL_CHECKOUT_DATE'=>'Checkout Date', + 'LBL_CONTACTS_SUBPANEL_TITLE' => 'Contacts', + 'LBL_PROJECT_SUBPANEL_TITLE' => 'Projects', + 'LBL_CAMPAIGNS_SUBPANEL_TITLE' => 'Campaigns', + 'LNK_IMPORT_CONTACTS' => 'Import Contacts', +) +?> \ No newline at end of file diff --git a/modules/Contacts/metadata/SearchFields.php b/modules/Contacts/metadata/SearchFields.php new file mode 100644 index 00000000..547758d4 --- /dev/null +++ b/modules/Contacts/metadata/SearchFields.php @@ -0,0 +1,74 @@ + array( 'query_type'=>'default'), + 'last_name'=> array('query_type'=>'default'), + 'search_name'=> array('query_type'=>'default','db_field'=>array('first_name','last_name'),'force_unifiedsearch'=>true), + 'account_name'=> array('query_type'=>'default','db_field'=>array('accounts.name')), + 'lead_source'=> array('query_type'=>'default','operator'=>'=', 'options' => 'lead_source_dom', 'template_var' => 'LEAD_SOURCE_OPTIONS'), + 'do_not_call'=> array('query_type'=>'default', 'input_type' => 'checkbox', 'operator'=>'='), + 'phone'=> array('query_type'=>'default','db_field'=>array('phone_mobile','phone_work','phone_other','phone_fax','assistant_phone')), + 'email'=> array( + 'query_type' => 'default', + 'operator' => 'subquery', + 'subquery' => 'SELECT eabr.bean_id FROM email_addr_bean_rel eabr JOIN email_addresses ea ON (ea.id = eabr.email_address_id) WHERE eabr.deleted=0 AND ea.email_address LIKE', + 'db_field' => array( + 'id', + ), + ), + 'assistant'=> array('query_type'=>'default'), + 'address_street'=> array('query_type'=>'default','db_field'=>array('primary_address_street','alt_address_street')), + 'address_city'=> array('query_type'=>'default','db_field'=>array('primary_address_city','alt_address_city')), + 'address_state'=> array('query_type'=>'default','db_field'=>array('primary_address_state','alt_address_state')), + 'address_postalcode'=> array('query_type'=>'default','db_field'=>array('primary_address_postalcode','alt_address_postalcode')), + 'address_country'=> array('query_type'=>'default','db_field'=>array('primary_address_country','alt_address_country')), + 'current_user_only'=> array('query_type'=>'default','db_field'=>array('assigned_user_id'),'my_items'=>true, 'vname' => 'LBL_CURRENT_USER_FILTER', 'type' => 'bool'), + 'assigned_user_id'=> array('query_type'=>'default'), + 'account_id'=> array('query_type'=>'default','db_field'=>array('accounts.id')), + 'campaign_name'=> array('query_type'=>'default'), + //Range Search Support + 'range_date_entered' => array ('query_type' => 'default', 'enable_range_search' => true, 'is_date_field' => true), + 'start_range_date_entered' => array ('query_type' => 'default', 'enable_range_search' => true, 'is_date_field' => true), + 'end_range_date_entered' => array ('query_type' => 'default', 'enable_range_search' => true, 'is_date_field' => true), + 'range_date_modified' => array ('query_type' => 'default', 'enable_range_search' => true, 'is_date_field' => true), + 'start_range_date_modified' => array ('query_type' => 'default', 'enable_range_search' => true, 'is_date_field' => true), + 'end_range_date_modified' => array ('query_type' => 'default', 'enable_range_search' => true, 'is_date_field' => true), + //Range Search Support + ); +?> diff --git a/modules/Contacts/metadata/additionalDetails.php b/modules/Contacts/metadata/additionalDetails.php new file mode 100644 index 00000000..54184e10 --- /dev/null +++ b/modules/Contacts/metadata/additionalDetails.php @@ -0,0 +1,79 @@ +' . $mod_strings['LBL_PRIMARY_ADDRESS'] . '
    '; + if(!empty($fields['PRIMARY_ADDRESS_STREET'])) $overlib_string .= $fields['PRIMARY_ADDRESS_STREET'] . '
    '; + if(!empty($fields['PRIMARY_ADDRESS_STREET_2'])) $overlib_string .= $fields['PRIMARY_ADDRESS_STREET_2'] . '
    '; + if(!empty($fields['PRIMARY_ADDRESS_STREET_3'])) $overlib_string .= $fields['PRIMARY_ADDRESS_STREET_3'] . '
    '; + if(!empty($fields['PRIMARY_ADDRESS_CITY'])) $overlib_string .= $fields['PRIMARY_ADDRESS_CITY'] . ', '; + if(!empty($fields['PRIMARY_ADDRESS_STATE'])) $overlib_string .= $fields['PRIMARY_ADDRESS_STATE'] . ' '; + if(!empty($fields['PRIMARY_ADDRESS_POSTALCODE'])) $overlib_string .= $fields['PRIMARY_ADDRESS_POSTALCODE'] . ' '; + if(!empty($fields['PRIMARY_ADDRESS_COUNTRY'])) $overlib_string .= $fields['PRIMARY_ADDRESS_COUNTRY'] . '
    '; + if(strlen($overlib_string) > 0 && !(strrpos($overlib_string, '
    ') == strlen($overlib_string) - 4)) + $overlib_string .= '
    '; + if(!empty($fields['PHONE_MOBILE'])) $overlib_string .= ''. $mod_strings['LBL_MOBILE_PHONE'] . ' ' . $fields['PHONE_MOBILE'] . '
    '; + if(!empty($fields['PHONE_HOME'])) $overlib_string .= ''. $mod_strings['LBL_HOME_PHONE'] . ' ' . $fields['PHONE_HOME'] . '
    '; + if(!empty($fields['PHONE_OTHER'])) $overlib_string .= ''. $mod_strings['LBL_OTHER_PHONE'] . ' ' . $fields['PHONE_OTHER'] . '
    '; + + if(!empty($fields['DATE_MODIFIED'])) $overlib_string .= ''. $mod_strings['LBL_DATE_MODIFIED'] . ' ' . $fields['DATE_MODIFIED'] . '
    '; + + if(!empty($fields['DESCRIPTION'])) { + $overlib_string .= ''. $mod_strings['LBL_DESCRIPTION'] . ' ' . substr($fields['DESCRIPTION'], 0, 300); + if(strlen($fields['DESCRIPTION']) > 300) $overlib_string .= '...'; + } + + return array('fieldToAddTo' => 'NAME', + 'string' => $overlib_string, + 'editLink' => "index.php?action=EditView&module=Contacts&return_module=Contacts&record={$fields['ID']}", + 'viewLink' => "index.php?action=DetailView&module=Contacts&return_module=Contacts&record={$fields['ID']}"); +} + + ?> + + \ No newline at end of file diff --git a/modules/Contacts/metadata/detailviewdefs.php b/modules/Contacts/metadata/detailviewdefs.php new file mode 100644 index 00000000..bf1a6e8a --- /dev/null +++ b/modules/Contacts/metadata/detailviewdefs.php @@ -0,0 +1,215 @@ + array('form' => array('buttons'=>array('EDIT', 'DUPLICATE', 'DELETE', 'FIND_DUPLICATES', + array('customCode'=>''), + ), + ), + 'maxColumns' => '2', + 'widths' => array( + array('label' => '10', 'field' => '30'), + array('label' => '10', 'field' => '30') + ), + + 'includes'=> array( + array('file'=>'modules/Leads/Lead.js'), + ), + ), + + + + 'panels' => + array ( + 'lbl_contact_information' => + array ( + + array ( + + array ( + 'name' => 'full_name', + 'label' => 'LBL_NAME', + ), + + ), + + array ( + + array ( + 'name' => 'title', + 'comment' => 'The title of the contact', + 'label' => 'LBL_TITLE', + ), + array ( + 'name' => 'phone_work', + 'label' => 'LBL_OFFICE_PHONE', + ), + ), + + array ( + 'department', + array ( + 'name' => 'phone_mobile', + 'label' => 'LBL_MOBILE_PHONE', + ), + ), + + array ( + array ( + 'name' => 'account_name', + 'label' => 'LBL_ACCOUNT_NAME', + ), + array ( + 'name' => 'phone_fax', + 'label' => 'LBL_FAX_PHONE', + ), + ), + + array ( + + array ( + 'name' => 'primary_address_street', + 'label' => 'LBL_PRIMARY_ADDRESS', + 'type' => 'address', + 'displayParams' => + array ( + 'key' => 'primary', + ), + ), + + array ( + 'name' => 'alt_address_street', + 'label' => 'LBL_ALTERNATE_ADDRESS', + 'type' => 'address', + 'displayParams' => + array ( + 'key' => 'alt', + ), + ), + ), + + array ( + + array ( + 'name' => 'email1', + 'studio' => 'false', + 'label' => 'LBL_EMAIL_ADDRESS', + ), + ), + + array ( + + array ( + 'name' => 'description', + 'comment' => 'Full text of the note', + 'label' => 'LBL_DESCRIPTION', + ), + ), + ), + + 'LBL_PANEL_ADVANCED' => + array ( + + array ( + + array ( + 'name' => 'report_to_name', + 'label' => 'LBL_REPORTS_TO', + ), + + array ( + 'name' => 'sync_contact', + 'comment' => 'Synch to outlook? (Meta-Data only)', + 'label' => 'LBL_SYNC_CONTACT', + ), + ), + + array ( + + array ( + 'name' => 'lead_source', + 'comment' => 'How did the contact come about', + 'label' => 'LBL_LEAD_SOURCE', + ), + + array ( + 'name' => 'do_not_call', + 'comment' => 'An indicator of whether contact can be called', + 'label' => 'LBL_DO_NOT_CALL', + ), + ), + + array ( + + array ( + 'name' => 'campaign_name', + 'label' => 'LBL_CAMPAIGN', + ), + + ), + + + ), + 'LBL_PANEL_ASSIGNMENT' => + array ( + + array ( + + array ( + 'name' => 'assigned_user_name', + 'label' => 'LBL_ASSIGNED_TO_NAME', + ), + + array ( + 'name' => 'date_modified', + 'customCode' => '{$fields.date_modified.value} {$APP.LBL_BY} {$fields.modified_by_name.value}', + 'label' => 'LBL_DATE_MODIFIED', + ), + ), + + array ( + + array ( + 'name' => 'date_entered', + 'customCode' => '{$fields.date_entered.value} {$APP.LBL_BY} {$fields.created_by_name.value}', + 'label' => 'LBL_DATE_ENTERED', + ), + + ), + ), + ) +); +?> \ No newline at end of file diff --git a/modules/Contacts/metadata/editviewdefs.php b/modules/Contacts/metadata/editviewdefs.php new file mode 100644 index 00000000..b2d8c99c --- /dev/null +++ b/modules/Contacts/metadata/editviewdefs.php @@ -0,0 +1,213 @@ + array('form'=>array('hidden'=>array('', + '', + '', + '', + '')), + 'maxColumns' => '2', + 'widths' => array( + array('label' => '10', 'field' => '30'), + array('label' => '10', 'field' => '30'), + ), +), + + + 'panels' => + array ( + 'lbl_contact_information' => + array ( + array ( + array ( + 'name' => 'first_name', + 'customCode' => '{html_options name="salutation" id="salutation" options=$fields.salutation.options selected=$fields.salutation.value}' + . ' ', + ), + + + ), + array ( + array ( + 'name' => 'last_name', + ), + array ( + 'name' => 'phone_work', + 'comment' => 'Work phone number of the contact', + 'label' => 'LBL_OFFICE_PHONE', + ), + ), + + array ( + + array ( + 'name' => 'title', + 'comment' => 'The title of the contact', + 'label' => 'LBL_TITLE', + ), + array ( + 'name' => 'phone_mobile', + 'comment' => 'Mobile phone number of the contact', + 'label' => 'LBL_MOBILE_PHONE', + ), + + ), + + array ( + 'department', + array ( + 'name' => 'phone_fax', + 'comment' => 'Contact fax number', + 'label' => 'LBL_FAX_PHONE', + ), + ), + array( + array ( + 'name' => 'account_name', + 'displayParams' => + array ( + 'key' => 'billing', + 'copy' => 'primary', + 'billingKey' => 'primary', + 'additionalFields' => + array ( + 'phone_office' => 'phone_work', + ), + ), + ), + ), + + array ( + + array ( + 'name' => 'primary_address_street', + 'hideLabel' => true, + 'type' => 'address', + 'displayParams' => + array ( + 'key' => 'primary', + 'rows' => 2, + 'cols' => 30, + 'maxlength' => 150, + ), + ), + + array ( + 'name' => 'alt_address_street', + 'hideLabel' => true, + 'type' => 'address', + 'displayParams' => + array ( + 'key' => 'alt', + 'copy' => 'primary', + 'rows' => 2, + 'cols' => 30, + 'maxlength' => 150, + ), + ), + ), + + array ( + + array ( + 'name' => 'email1', + 'studio' => 'false', + 'label' => 'LBL_EMAIL_ADDRESS', + ), + ), + + array ( + + array ( + 'name' => 'description', + 'label' => 'LBL_DESCRIPTION', + ), + ), + ), + + + 'LBL_PANEL_ADVANCED' => + array ( + + array ( + + array ( + 'name' => 'report_to_name', + 'label' => 'LBL_REPORTS_TO', + ), + + array ( + 'name' => 'sync_contact', + 'comment' => 'Synch to outlook? (Meta-Data only)', + 'label' => 'LBL_SYNC_CONTACT', + ), + ), + + array ( + + array ( + 'name' => 'lead_source', + 'comment' => 'How did the contact come about', + 'label' => 'LBL_LEAD_SOURCE', + ), + + array ( + 'name' => 'do_not_call', + 'comment' => 'An indicator of whether contact can be called', + 'label' => 'LBL_DO_NOT_CALL', + ), + ), + + array ( + 'campaign_name', + ), + ), + + + + 'LBL_PANEL_ASSIGNMENT' => + array ( + array ( + array ( + 'name' => 'assigned_user_name', + 'label' => 'LBL_ASSIGNED_TO_NAME', + ), + ), + ), + ) +); +?> \ No newline at end of file diff --git a/modules/Contacts/metadata/listviewdefs.php b/modules/Contacts/metadata/listviewdefs.php new file mode 100644 index 00000000..209ba4b2 --- /dev/null +++ b/modules/Contacts/metadata/listviewdefs.php @@ -0,0 +1,179 @@ + array( + 'width' => '20%', + 'label' => 'LBL_LIST_NAME', + 'link' => true, + 'contextMenu' => array('objectType' => 'sugarPerson', + 'metaData' => array('contact_id' => '{$ID}', + 'module' => 'Contacts', + 'return_action' => 'ListView', + 'contact_name' => '{$FULL_NAME}', + 'parent_id' => '{$ACCOUNT_ID}', + 'parent_name' => '{$ACCOUNT_NAME}', + 'return_module' => 'Contacts', + 'return_action' => 'ListView', + 'parent_type' => 'Account', + 'notes_parent_type' => 'Account') + ), + 'orderBy' => 'name', + 'default' => true, + 'related_fields' => array('first_name', 'last_name', 'salutation', 'account_name', 'account_id'), + ), + 'TITLE' => array( + 'width' => '15%', + 'label' => 'LBL_LIST_TITLE', + 'default' => true), + 'ACCOUNT_NAME' => array( + 'width' => '34%', + 'label' => 'LBL_LIST_ACCOUNT_NAME', + 'module' => 'Accounts', + 'id' => 'ACCOUNT_ID', + 'link' => true, + 'contextMenu' => array('objectType' => 'sugarAccount', + 'metaData' => array('return_module' => 'Contacts', + 'return_action' => 'ListView', + 'module' => 'Accounts', + 'return_action' => 'ListView', + 'parent_id' => '{$ACCOUNT_ID}', + 'parent_name' => '{$ACCOUNT_NAME}', + 'account_id' => '{$ACCOUNT_ID}', + 'account_name' => '{$ACCOUNT_NAME}'), + ), + 'default' => true, + 'sortable'=> true, + 'ACLTag' => 'ACCOUNT', + 'related_fields' => array('account_id')), + 'EMAIL1' => array( + 'width' => '15%', + 'label' => 'LBL_LIST_EMAIL_ADDRESS', + 'sortable' => false, + 'link' => true, + 'customCode' => '{$EMAIL1_LINK}{$EMAIL1}', + 'default' => true + ), + 'PHONE_WORK' => array( + 'width' => '15%', + 'label' => 'LBL_OFFICE_PHONE', + 'default' => true), + 'DEPARTMENT' => array( + 'width' => '10', + 'label' => 'LBL_DEPARTMENT'), + 'DO_NOT_CALL' => array( + 'width' => '10', + 'label' => 'LBL_DO_NOT_CALL'), + 'PHONE_HOME' => array( + 'width' => '10', + 'label' => 'LBL_HOME_PHONE'), + 'PHONE_MOBILE' => array( + 'width' => '10', + 'label' => 'LBL_MOBILE_PHONE'), + 'PHONE_OTHER' => array( + 'width' => '10', + 'label' => 'LBL_OTHER_PHONE'), + 'PHONE_FAX' => array( + 'width' => '10', + 'label' => 'LBL_FAX_PHONE'), + 'EMAIL2' => array( + 'width' => '15', + 'label' => 'LBL_LIST_EMAIL_ADDRESS', + 'sortable' => false, + 'customCode' => '{$EMAIL2_LINK}{$EMAIL2}'), + 'EMAIL_OPT_OUT' => array( + 'width' => '10', + + 'label' => 'LBL_EMAIL_OPT_OUT'), + 'PRIMARY_ADDRESS_STREET' => array( + 'width' => '10', + 'label' => 'LBL_PRIMARY_ADDRESS_STREET'), + 'PRIMARY_ADDRESS_CITY' => array( + 'width' => '10', + 'label' => 'LBL_PRIMARY_ADDRESS_CITY'), + 'PRIMARY_ADDRESS_STATE' => array( + 'width' => '10', + 'label' => 'LBL_PRIMARY_ADDRESS_STATE'), + 'PRIMARY_ADDRESS_POSTALCODE' => array( + 'width' => '10', + 'label' => 'LBL_PRIMARY_ADDRESS_POSTALCODE'), + 'ALT_ADDRESS_COUNTRY' => array( + 'width' => '10', + 'label' => 'LBL_ALT_ADDRESS_COUNTRY'), + 'ALT_ADDRESS_STREET' => array( + 'width' => '10', + 'label' => 'LBL_ALT_ADDRESS_STREET'), + 'ALT_ADDRESS_CITY' => array( + 'width' => '10', + 'label' => 'LBL_ALT_ADDRESS_CITY'), + 'ALT_ADDRESS_STATE' => array( + 'width' => '10', + 'label' => 'LBL_ALT_ADDRESS_STATE'), + 'ALT_ADDRESS_POSTALCODE' => array( + 'width' => '10', + 'label' => 'LBL_ALT_ADDRESS_POSTALCODE'), + 'ALT_ADDRESS_COUNTRY' => array( + 'width' => '10', + 'label' => 'LBL_ALT_ADDRESS_COUNTRY'), + 'CREATED_BY_NAME' => array( + 'width' => '10', + 'label' => 'LBL_CREATED'), + 'ASSIGNED_USER_NAME' => array( + 'width' => '10', + 'label' => 'LBL_LIST_ASSIGNED_USER', + 'module' => 'Employees', + 'id' => 'ASSIGNED_USER_ID', + 'default' => true), + 'MODIFIED_BY_NAME' => array( + 'width' => '10', + 'label' => 'LBL_MODIFIED'), + 'SYNC_CONTACT' => array ( + 'type' => 'bool', + 'label' => 'LBL_SYNC_CONTACT', + 'width' => '10%', + 'default' => false, + 'sortable' => false, + ), + 'DATE_ENTERED' => array( + 'width' => '10', + 'label' => 'LBL_DATE_ENTERED', + 'default' => true) +); +?> diff --git a/modules/Contacts/metadata/metafiles.php b/modules/Contacts/metadata/metafiles.php new file mode 100644 index 00000000..94a082bd --- /dev/null +++ b/modules/Contacts/metadata/metafiles.php @@ -0,0 +1,51 @@ + 'modules/Contacts/metadata/detailviewdefs.php', + 'editviewdefs' => 'modules/Contacts/metadata/editviewdefs.php', + 'listviewdefs' => 'modules/Contacts/metadata/listviewdefs.php', + 'searchdefs' => 'modules/Contacts/metadata/searchdefs.php', + 'popupdefs' => 'modules/Contacts/metadata/popupdefs.php', + 'searchfields' => 'modules/Contacts/metadata/SearchFields.php', + ); +?> diff --git a/modules/Contacts/metadata/popupdefs.php b/modules/Contacts/metadata/popupdefs.php new file mode 100644 index 00000000..41f4d69d --- /dev/null +++ b/modules/Contacts/metadata/popupdefs.php @@ -0,0 +1,93 @@ + 'Contact', + 'varName' => 'CONTACT', + 'orderBy' => 'contacts.first_name, contacts.last_name', + 'whereClauses' => + array('first_name' => 'contacts.first_name', + 'last_name' => 'contacts.last_name', + 'account_name' => 'accounts.name', + 'account_id' => 'accounts.id'), + 'searchInputs' => + array('first_name', 'last_name', 'account_name'), + 'create' => + array('formBase' => 'ContactFormBase.php', + 'formBaseClass' => 'ContactFormBase', + 'getFormBodyParams' => array('','','ContactSave'), + 'createButton' => $mod_strings['LNK_NEW_CONTACT'] + ), + 'listviewdefs' => array( + 'NAME' => array( + 'width' => '20%', + 'label' => 'LBL_LIST_NAME', + 'link' => true, + 'default' => true, + 'related_fields' => array('first_name', 'last_name', 'salutation', 'account_name', 'account_id')), + 'ACCOUNT_NAME' => array( + 'width' => '25', + 'label' => 'LBL_LIST_ACCOUNT_NAME', + 'module' => 'Accounts', + 'id' => 'ACCOUNT_ID', + 'default' => true, + 'sortable'=> true, + 'ACLTag' => 'ACCOUNT', + 'related_fields' => array('account_id')), + 'TITLE' => array( + 'width' => '15%', + 'label' => 'LBL_LIST_TITLE', + 'default' => true), + 'LEAD_SOURCE' => array( + 'width' => '15%', + 'label' => 'LBL_LEAD_SOURCE', + 'default' => true), + ), + 'searchdefs' => array( + 'first_name', + 'last_name', + array('name' => 'account_name', 'type' => 'varchar',), + 'title', + 'lead_source', + array('name' => 'campaign_name', 'displayParams' => array('hideButtons'=>'true', 'size'=>30, 'class'=>'sqsEnabled sqsNoAutofill')), + array('name' => 'assigned_user_id', 'type' => 'enum', 'label' => 'LBL_ASSIGNED_TO', 'function' => array('name' => 'get_user_array', 'params' => array(false))), + ) + ); +?> diff --git a/modules/Contacts/metadata/popupdefsEmail.php b/modules/Contacts/metadata/popupdefsEmail.php new file mode 100644 index 00000000..7621930f --- /dev/null +++ b/modules/Contacts/metadata/popupdefsEmail.php @@ -0,0 +1,59 @@ + 'Contact', + 'varName' => 'CONTACT', + 'orderBy' => 'contacts.first_name, contacts.last_name', + 'whereClauses' => + array('first_name' => 'contacts.first_name', + 'last_name' => 'contacts.last_name', + 'account_name' => 'accounts.name', + 'account_id' => 'accounts.id'), + 'searchInputs' => + array('first_name', 'last_name', 'account_name'), + 'create' => + array('formBase' => 'ContactFormBase.php', + 'formBaseClass' => 'ContactFormBase', + 'getFormBodyParams' => array('','','ContactSave'), + 'createButton' => $mod_strings['LNK_NEW_CONTACT'] + ), + 'templateForm' => 'modules/Contacts/Email_picker.html', + ); +?> diff --git a/modules/Contacts/metadata/quickcreatedefs.php b/modules/Contacts/metadata/quickcreatedefs.php new file mode 100644 index 00000000..7c9d605b --- /dev/null +++ b/modules/Contacts/metadata/quickcreatedefs.php @@ -0,0 +1,147 @@ + + array ( + 'QuickCreate' => + array ( + 'templateMeta' => + array ( + 'form' => + array ( + 'hidden' => + array ( + '', + '', + '', + '', + '', + '{if !empty($smarty.request.contact_id)}{/if}', + '{if !empty($smarty.request.contact_name)}{/if}', + ), + ), + 'maxColumns' => '2', + 'widths' => + array ( + array ( + 'label' => '10', + 'field' => '30', + ), + array ( + 'label' => '10', + 'field' => '30', + ), + ), + ), + 'panels' => + array ( + 'default' => + array ( + + array ( + + array ( + 'name' => 'first_name', + ), + + array ( + 'name' => 'account_name', + ), + ), + + array ( + + array ( + 'name' => 'last_name', + 'displayParams'=>array('required'=>true), + ), + + array ( + 'name' => 'phone_work', + ), + ), + + array ( + + array ( + 'name' => 'title', + ), + + array ( + 'name' => 'phone_mobile', + ), + ), + + array ( + + array ( + 'name' => 'phone_fax', + ), + + array ( + 'name' => 'do_not_call', + ), + ), + + array ( + array ( + 'name' => 'email1', + ), + array ( + 'name' => 'lead_source', + ), + ), + + array ( + + array ( + 'name' => 'assigned_user_name', + ), + ), + ), + ), + ), + ), +); +?> diff --git a/modules/Contacts/metadata/searchdefs.php b/modules/Contacts/metadata/searchdefs.php new file mode 100644 index 00000000..86c4c2f0 --- /dev/null +++ b/modules/Contacts/metadata/searchdefs.php @@ -0,0 +1,154 @@ + array('maxColumns' => '3', + 'widths' => array('label' => '10', 'field' => '30'), + ), + 'layout' => array ( + 'basic_search' => + array ( + array('name'=>'search_name','label' =>'LBL_NAME', 'type' => 'name'), + array ( + 'name' => 'current_user_only', + 'label' => 'LBL_CURRENT_USER_FILTER', + 'type' => 'bool', + ), + ), + 'advanced_search' => + array ( + 'first_name' => + array ( + 'name' => 'first_name', + 'default' => true, + 'width' => '10%', + ), + 'email' => + array ( + 'name' => 'email', + 'label' => 'LBL_ANY_EMAIL', + 'type' => 'name', + 'default' => true, + 'width' => '10%', + ), + 'phone' => + array ( + 'name' => 'phone', + 'label' => 'LBL_ANY_PHONE', + 'type' => 'name', + 'default' => true, + 'width' => '10%', + ), + 'last_name' => + array ( + 'name' => 'last_name', + 'default' => true, + 'width' => '10%', + ), + 'address_street' => + array ( + 'name' => 'address_street', + 'label' => 'LBL_ANY_ADDRESS', + 'type' => 'name', + 'default' => true, + 'width' => '10%', + ), + 'address_city' => + array ( + 'name' => 'address_city', + 'label' => 'LBL_CITY', + 'type' => 'name', + 'default' => true, + 'width' => '10%', + ), + 'account_name' => + array ( + 'name' => 'account_name', + 'default' => true, + 'width' => '10%', + ), + 'address_state' => + array ( + 'name' => 'address_state', + 'label' => 'LBL_STATE', + 'type' => 'name', + 'default' => true, + 'width' => '10%', + ), + 'address_postalcode' => + array ( + 'name' => 'address_postalcode', + 'label' => 'LBL_POSTAL_CODE', + 'type' => 'name', + 'default' => true, + 'width' => '10%', + ), + 'assigned_user_id' => + array ( + 'name' => 'assigned_user_id', + 'type' => 'enum', + 'label' => 'LBL_ASSIGNED_TO', + 'function' => + array ( + 'name' => 'get_user_array', + 'params' => + array ( + 0 => false, + ), + ), + 'default' => true, + 'width' => '10%', + ), + 'primary_address_country' => + array ( + 'name' => 'primary_address_country', + 'label' => 'LBL_COUNTRY', + 'type' => 'name', + 'options' => 'countries_dom', + 'default' => true, + 'width' => '10%', + ), + 'lead_source' => + array ( + 'name' => 'lead_source', + 'default' => true, + 'width' => '10%', + ), + + ), + ) +); +?> \ No newline at end of file diff --git a/modules/Contacts/metadata/studio.php b/modules/Contacts/metadata/studio.php new file mode 100644 index 00000000..f4ccad2e --- /dev/null +++ b/modules/Contacts/metadata/studio.php @@ -0,0 +1,66 @@ +array( + 'template'=>'xtpl', + 'template_file'=>'modules/Contacts/DetailView.html', + 'php_file'=>'modules/Contacts/DetailView.php', + 'type'=>'DetailView', + ), + 'LBL_EDITVIEW'=>array( + 'template'=>'xtpl', + 'template_file'=>'modules/Contacts/EditView.html', + 'php_file'=>'modules/Contacts/EditView.php', + 'type'=>'EditView', + ), + 'LBL_LISTVIEW'=>array( + 'template'=>'listview', + 'meta_file'=>'modules/Contacts/listviewdefs.php', + 'type'=>'ListView', + ), + 'LBL_SEARCHFORM'=>array( + 'template'=>'xtpl', + 'template_file'=>'modules/Contacts/SearchForm.html', + 'php_file'=>'modules/Contacts/ListView.php', + 'type'=>'SearchForm', + ), + +); diff --git a/modules/Contacts/metadata/subpaneldefs.php b/modules/Contacts/metadata/subpaneldefs.php new file mode 100644 index 00000000..d74f2f60 --- /dev/null +++ b/modules/Contacts/metadata/subpaneldefs.php @@ -0,0 +1,257 @@ + array( + + 'activities' => array( + 'order' => 10, + 'sort_order' => 'desc', + 'sort_by' => 'date_start', + 'title_key' => 'LBL_ACTIVITIES_SUBPANEL_TITLE', + 'type' => 'collection', + 'subpanel_name' => 'activities', //this values is not associated with a physical file. + 'module'=>'Activities', + + 'top_buttons' => array( + array('widget_class' => 'SubPanelTopCreateTaskButton'), + array('widget_class' => 'SubPanelTopScheduleMeetingButton'), + array('widget_class' => 'SubPanelTopScheduleCallButton'), + array('widget_class' => 'SubPanelTopComposeEmailButton'), + ), + 'collection_list' => array( + 'tasks' => array( + 'module' => 'Tasks', + 'subpanel_name' => 'ForActivities', + 'get_subpanel_data' => 'tasks', + ), + 'tasks_parent' => array( + 'module' => 'Tasks', + 'subpanel_name' => 'ForActivities', + 'get_subpanel_data' => 'tasks_parent', + ), + 'meetings' => array( + 'module' => 'Meetings', + 'subpanel_name' => 'ForActivities', + 'get_subpanel_data' => 'meetings', + ), + 'calls' => array( + 'module' => 'Calls', + 'subpanel_name' => 'ForActivities', + 'get_subpanel_data' => 'calls', + ), + ) + ), + + 'history' => array( + 'order' => 20, + 'sort_order' => 'desc', + 'sort_by' => 'date_entered', + 'title_key' => 'LBL_HISTORY_SUBPANEL_TITLE', + 'type' => 'collection', + 'subpanel_name' => 'history', //this values is not associated with a physical file. + 'module'=>'History', + + 'top_buttons' => array( + array('widget_class' => 'SubPanelTopCreateNoteButton'), + array('widget_class' => 'SubPanelTopArchiveEmailButton'), + array('widget_class' => 'SubPanelTopSummaryButton'), + ), + + 'collection_list' => array( + 'tasks' => array( + 'module' => 'Tasks', + 'subpanel_name' => 'ForHistory', + 'get_subpanel_data' => 'tasks', + ), + 'tasks_parent' => array( + 'module' => 'Tasks', + 'subpanel_name' => 'ForHistory', + 'get_subpanel_data' => 'tasks_parent', + ), + 'meetings' => array( + 'module' => 'Meetings', + 'subpanel_name' => 'ForHistory', + 'get_subpanel_data' => 'meetings', + ), + 'calls' => array( + 'module' => 'Calls', + 'subpanel_name' => 'ForHistory', + 'get_subpanel_data' => 'calls', + ), + 'notes' => array( + 'module' => 'Notes', + 'subpanel_name' => 'ForHistory', + 'get_subpanel_data' => 'notes', + ), + 'emails' => array( + 'module' => 'Emails', + 'subpanel_name' => 'ForHistory', + 'get_subpanel_data' => 'emails', + ), + 'linkedemails' => array( + 'module' => 'Emails', + 'subpanel_name' => 'ForUnlinkedEmailHistory', + 'get_subpanel_data' => 'function:get_unlinked_email_query', + 'generate_select'=>true, + 'function_parameters' => array('return_as_array'=>'true'), + ), + ) + ), + 'documents' => array( + 'order' => 25, + 'module' => 'Documents', + 'subpanel_name' => 'default', + 'sort_order' => 'asc', + 'sort_by' => 'id', + 'title_key' => 'LBL_DOCUMENTS_SUBPANEL_TITLE', + 'get_subpanel_data' => 'documents', + 'top_buttons' => + array ( + 0 => + array ( + 'widget_class' => 'SubPanelTopButtonQuickCreate', + ), + 1 => + array ( + 'widget_class' => 'SubPanelTopSelectButton', + 'mode' => 'MultiSelect', + ), + ), + ), + 'leads' => array( + 'order' => 60, + 'module' => 'Leads', + 'sort_order' => 'asc', + 'sort_by' => 'last_name, first_name', + 'subpanel_name' => 'default', + 'get_subpanel_data' => 'leads', + 'add_subpanel_data' => 'lead_id', + 'title_key' => 'LBL_LEADS_SUBPANEL_TITLE', + 'top_buttons' => array( + array('widget_class' => 'SubPanelTopCreateLeadNameButton'), + array('widget_class' => 'SubPanelTopSelectButton', + 'popup_module' => 'Opportunities', + 'mode' => 'MultiSelect', + ), + ), + ), + 'opportunities' => array( + 'order' => 30, + 'module' => 'Opportunities', + 'sort_order' => 'desc', + 'sort_by' => 'date_closed', + 'subpanel_name' => 'default', + 'get_subpanel_data' => 'opportunities', + 'add_subpanel_data' => 'opportunity_id', + 'title_key' => 'LBL_OPPORTUNITIES_SUBPANEL_TITLE', + 'top_buttons' => array( + array('widget_class' => 'SubPanelTopButtonQuickCreate'), + array('widget_class' => 'SubPanelTopSelectButton', 'mode'=>'MultiSelect') + ), + ), + 'cases' => array( + 'order' => 80, + 'sort_order' => 'desc', + 'sort_by' => 'case_number', + 'module' => 'Cases', + 'subpanel_name' => 'default', + 'get_subpanel_data' => 'cases', + 'add_subpanel_data' => 'case_id', + 'title_key' => 'LBL_CASES_SUBPANEL_TITLE', + 'top_buttons' => array( + array('widget_class' => 'SubPanelTopButtonQuickCreate'), + array('widget_class' => 'SubPanelTopSelectButton', 'mode'=>'MultiSelect') + ), + ), + 'bugs' => array( + 'order' => 90, + 'module' => 'Bugs', + 'sort_order' => 'desc', + 'sort_by' => 'bug_number', + 'subpanel_name' => 'default', + 'get_subpanel_data' => 'bugs', + 'add_subpanel_data' => 'bug_id', + 'title_key' => 'LBL_BUGS_SUBPANEL_TITLE', + 'top_buttons' => array( + array('widget_class' => 'SubPanelTopButtonQuickCreate'), + array('widget_class' => 'SubPanelTopSelectButton', 'mode'=>'MultiSelect') + ), + ), + 'contacts' => array( + 'order' => 100, + 'module' => 'Contacts', + 'sort_order' => 'asc', + 'sort_by' => 'last_name, first_name', + 'subpanel_name' => 'ForContacts', + 'get_subpanel_data' => 'direct_reports', + 'add_subpanel_data' => 'contact_id', + 'title_key' => 'LBL_DIRECT_REPORTS_SUBPANEL_TITLE', + 'top_buttons' => array( + array('widget_class' => 'SubPanelTopButtonQuickCreate'), + array('widget_class' => 'SubPanelTopSelectButton', 'mode'=>'MultiSelect') + ), + ), + 'project' => array( + 'order' => 110, + 'module' => 'Project', + 'sort_order' => 'asc', + 'sort_by' => 'name', + 'get_subpanel_data' => 'project', + 'subpanel_name' => 'default', + 'title_key' => 'LBL_PROJECTS_SUBPANEL_TITLE', + 'top_buttons' => array( + array('widget_class' => 'SubPanelTopButtonQuickCreate'), + array('widget_class' => 'SubPanelTopSelectButton', 'mode'=>'MultiSelect'), + ), + ), + 'campaigns' => array( + 'order' => 70, + 'module' => 'CampaignLog', + 'sort_order' => 'desc', + 'sort_by' => 'activity_date', + 'get_subpanel_data'=>'campaigns', + 'subpanel_name' => 'ForTargets', + 'title_key' => 'LBL_CAMPAIGN_LIST_SUBPANEL_TITLE', + ), + ), +); +?> diff --git a/modules/Contacts/metadata/subpanels/ForAccounts.php b/modules/Contacts/metadata/subpanels/ForAccounts.php new file mode 100644 index 00000000..8d44b414 --- /dev/null +++ b/modules/Contacts/metadata/subpanels/ForAccounts.php @@ -0,0 +1,106 @@ + array( + array('widget_class' => 'SubPanelTopCreateButton'), + array('widget_class' => 'SubPanelTopSelectButton', 'popup_module' => 'Contacts'), + ), + + 'where' => '', + + + + 'list_fields' => array( + 'first_name'=>array( + 'name'=>'first_name', + 'usage' => 'query_only', + ), + 'last_name'=>array( + 'name'=>'last_name', + 'usage' => 'query_only', + ), + 'salutation'=>array( + 'name'=>'salutation', + 'usage' => 'query_only', + ), + 'name'=>array( + 'name'=>'name', + 'vname' => 'LBL_LIST_NAME', + 'widget_class' => 'SubPanelDetailViewLink', + 'module' => 'Contacts', + 'width' => '43%', + ), + 'primary_address_city'=>array( + 'name'=>'primary_address_city', + 'vname' => 'LBL_LIST_CITY', + 'width' => '20%', + ), + 'primary_address_state'=>array( + 'name'=>'primary_address_state', + 'vname' => 'LBL_LIST_STATE', + 'width' => '10%', + ), + 'email1'=>array( + 'name'=>'email1', + 'vname' => 'LBL_LIST_EMAIL', + 'widget_class' => 'SubPanelEmailLink', + 'width' => '30%', + 'sortable' => false, + ), + 'phone_work'=>array ( + 'name'=>'phone_work', + 'vname' => 'LBL_LIST_PHONE', + 'width' => '15%', + ), + 'edit_button'=>array( + 'vname' => 'LBL_EDIT_BUTTON', + 'widget_class' => 'SubPanelEditButton', + 'module' => 'Contacts', + 'width' => '5%', + ), + 'remove_button'=>array( + 'vname' => 'LBL_REMOVE', + 'widget_class' => 'SubPanelRemoveButton', + 'module' => 'Contacts', + 'width' => '5%', + ), + ), +); +?> diff --git a/modules/Contacts/metadata/subpanels/ForCalls.php b/modules/Contacts/metadata/subpanels/ForCalls.php new file mode 100644 index 00000000..683a1178 --- /dev/null +++ b/modules/Contacts/metadata/subpanels/ForCalls.php @@ -0,0 +1,121 @@ + array( + array('widget_class' => 'SubPanelTopCreateButton'), + array('widget_class' => 'SubPanelTopSelectButton', 'popup_module' => 'Contacts'), + ), + + 'where' => '', + + + + 'list_fields' => array( + 'accept_status_name'=>array ( + 'vname' => 'LBL_LIST_ACCEPT_STATUS', + 'width' => '11%', + 'sortable'=>false + ), + 'c_accept_status_fields'=>array( + 'usage' => 'query_only', + ), + 'accept_status_id'=>array( + 'usage' => 'query_only', + ), + 'first_name'=>array( + 'name'=>'first_name', + 'usage' => 'query_only', + ), + 'last_name'=>array( + 'name'=>'last_name', + 'usage' => 'query_only', + ), + 'salutation'=>array( + 'name'=>'salutation', + 'usage' => 'query_only', + ), + 'name'=>array( + 'name'=>'name', + 'vname' => 'LBL_LIST_NAME', + 'widget_class' => 'SubPanelDetailViewLink', + 'module' => 'Contacts', + 'width' => '23%', + ), + 'account_name'=>array( + 'name'=>'account_name', + 'module' => 'Accounts', + 'target_record_key' => 'account_id', + 'target_module' => 'Accounts', + 'widget_class' => 'SubPanelDetailViewLink', + 'vname' => 'LBL_LIST_ACCOUNT_NAME', + 'width' => '22%', + 'sortable'=>false, + ), + 'account_id'=>array( + 'usage'=>'query_only', + + ), + 'email1'=>array( + 'name'=>'email1', + 'vname' => 'LBL_LIST_EMAIL', + 'widget_class' => 'SubPanelEmailLink', + 'width' => '30%', + 'sortable' => false, + ), + 'phone_work'=>array ( + 'name'=>'phone_work', + 'vname' => 'LBL_LIST_PHONE', + 'width' => '15%', + ), + 'edit_button'=>array( + 'vname' => 'LBL_EDIT_BUTTON', + 'widget_class' => 'SubPanelEditButton', + 'module' => 'Contacts', + 'width' => '5%', + ), + 'remove_button'=>array( + 'vname' => 'LBL_REMOVE', + 'widget_class' => 'SubPanelRemoveButton', + 'module' => 'Contacts', + 'width' => '5%', + ), + ), +); +?> \ No newline at end of file diff --git a/modules/Contacts/metadata/subpanels/ForCases.php b/modules/Contacts/metadata/subpanels/ForCases.php new file mode 100644 index 00000000..6f2d5b01 --- /dev/null +++ b/modules/Contacts/metadata/subpanels/ForCases.php @@ -0,0 +1,110 @@ + array( + array('widget_class' => 'SubPanelTopCreateButton'), + array('widget_class' => 'SubPanelTopSelectButton', 'popup_module' => 'Contacts'), + ), + + 'where' => '', + + + + 'list_fields' => array( + 'first_name'=>array( + 'name'=>'first_name', + 'usage' => 'query_only', + ), + 'last_name'=>array( + 'name'=>'last_name', + 'usage' => 'query_only', + ), + 'salutation'=>array( + 'name'=>'salutation', + 'usage' => 'query_only', + ), + 'name'=>array( + 'name'=>'name', + 'vname' => 'LBL_LIST_NAME', + 'widget_class' => 'SubPanelDetailViewLink', + 'module' => 'Contacts', + 'width' => '23%', + ), + 'account_name'=>array( + 'name'=>'account_name', + 'module' => 'Accounts', + 'target_record_key' => 'account_id', + 'target_module' => 'Accounts', + 'widget_class' => 'SubPanelDetailViewLink', + 'vname' => 'LBL_LIST_ACCOUNT_NAME', + 'width' => '22%', + 'sortable'=>false, + ), + 'account_id'=>array( + 'usage'=>'query_only', + + ), + 'email1'=>array( + 'name'=>'email1', + 'vname' => 'LBL_LIST_EMAIL', + 'widget_class' => 'SubPanelEmailLink', + 'width' => '30%', + 'sortable' => false, + ), + 'phone_work'=>array ( + 'name'=>'phone_work', + 'vname' => 'LBL_LIST_PHONE', + 'width' => '15%', + ), + 'edit_button'=>array( + 'vname' => 'LBL_EDIT_BUTTON', + 'widget_class' => 'SubPanelEditButton', + 'module' => 'Contacts', + 'width' => '5%', + ), + 'remove_button'=>array( + 'vname' => 'LBL_REMOVE', + 'widget_class' => 'SubPanelRemoveButton', + 'module' => 'Contacts', + 'width' => '5%', + ), + ), +); +?> diff --git a/modules/Contacts/metadata/subpanels/ForContacts.php b/modules/Contacts/metadata/subpanels/ForContacts.php new file mode 100644 index 00000000..6a31fac4 --- /dev/null +++ b/modules/Contacts/metadata/subpanels/ForContacts.php @@ -0,0 +1,109 @@ + array( + array('widget_class' => 'SubPanelTopCreateDirectReport'), + array('widget_class' => 'SubPanelTopSelectButton', 'popup_module' => 'Contacts'), + ), + + + + 'list_fields' => array( + 'first_name'=>array( + 'name'=>'first_name', + 'usage' => 'query_only', + ), + 'last_name'=>array( + 'name'=>'last_name', + 'usage' => 'query_only', + ), + 'salutation'=>array( + 'name'=>'salutation', + 'usage' => 'query_only', + ), + 'name'=>array( + 'name'=>'name', + 'vname' => 'LBL_LIST_NAME', + 'widget_class' => 'SubPanelDetailViewLink', + 'module' => 'Contacts', + 'width' => '23%', + ), + 'account_name'=>array( + 'name'=>'account_name', + 'module' => 'Accounts', + 'target_record_key' => 'account_id', + 'target_module' => 'Accounts', + 'widget_class' => 'SubPanelDetailViewLink', + 'vname' => 'LBL_LIST_ACCOUNT_NAME', + 'width' => '22%', + 'sortable'=>false, + ), + 'contact_id'=>array( + 'usage'=>'query_only', + + ), + 'email1'=>array( + 'name'=>'email1', + 'vname' => 'LBL_LIST_EMAIL', + 'widget_class' => 'SubPanelEmailLink', + 'width' => '30%', + 'sortable' => false, + ), + 'phone_work'=>array ( + 'name'=>'phone_work', + 'vname' => 'LBL_LIST_PHONE', + 'width' => '15%', + ), + 'edit_button'=>array( + 'vname' => 'LBL_EDIT_BUTTON', + 'widget_class' => 'SubPanelEditButton', + 'module' => 'Contacts', + 'width' => '5%', + ), + 'remove_button'=>array( + 'vname' => 'LBL_REMOVE', + 'widget_class' => 'SubPanelRemoveButton', + 'module' => 'Contacts', + 'width' => '5%', + ), + ), +); +?> \ No newline at end of file diff --git a/modules/Contacts/metadata/subpanels/ForEmails.php b/modules/Contacts/metadata/subpanels/ForEmails.php new file mode 100644 index 00000000..fe141ea3 --- /dev/null +++ b/modules/Contacts/metadata/subpanels/ForEmails.php @@ -0,0 +1,104 @@ + array( + array('widget_class' => 'SubPanelTopSelectButton', 'popup_module' => 'Contacts'), + ), + + 'where' => '', + + + + 'list_fields' => array( + 'first_name'=>array( + 'name'=>'first_name', + 'usage' => 'query_only', + ), + 'last_name'=>array( + 'name'=>'last_name', + 'usage' => 'query_only', + ), + 'salutation'=>array( + 'name'=>'salutation', + 'usage' => 'query_only', + ), + 'name'=>array( + 'name'=>'name', + 'vname' => 'LBL_LIST_NAME', + 'widget_class' => 'SubPanelDetailViewLink', + 'module' => 'Contacts', + 'width' => '23%', + ), + 'account_name'=>array( + 'name'=>'account_name', + 'module' => 'Accounts', + 'target_record_key' => 'account_id', + 'target_module' => 'Accounts', + 'widget_class' => 'SubPanelDetailViewLink', + 'vname' => 'LBL_LIST_ACCOUNT_NAME', + 'width' => '22%', + 'sortable'=>false, + ), + 'account_id'=>array( + 'usage'=>'query_only', + + ), + 'email1'=>array( + 'name'=>'email1', + 'vname' => 'LBL_LIST_EMAIL', + 'widget_class' => 'SubPanelEmailLink', + 'width' => '30%', + 'sortable' => false, + ), + 'edit_button'=>array( + 'vname' => 'LBL_EDIT_BUTTON', + 'widget_class' => 'SubPanelEditButton', + 'module' => 'Contacts', + 'width' => '5%', + ), + 'remove_button'=>array( + 'vname' => 'LBL_REMOVE', + 'widget_class' => 'SubPanelRemoveButton', + 'module' => 'Contacts', + 'width' => '5%', + ), + ), +); +?> diff --git a/modules/Contacts/metadata/subpanels/ForMeetings.php b/modules/Contacts/metadata/subpanels/ForMeetings.php new file mode 100644 index 00000000..03588bc9 --- /dev/null +++ b/modules/Contacts/metadata/subpanels/ForMeetings.php @@ -0,0 +1,121 @@ + array( + array('widget_class' => 'SubPanelTopCreateButton'), + array('widget_class' => 'SubPanelTopSelectButton', 'popup_module' => 'Contacts'), + ), + + 'where' => '', + + + + 'list_fields' => array( + 'accept_status_name'=>array ( + 'vname' => 'LBL_LIST_ACCEPT_STATUS', + 'width' => '11%', + 'sortable' => false, + ), + 'm_accept_status_fields'=>array( + 'usage' => 'query_only', + ), + 'accept_status_id'=>array( + 'usage' => 'query_only', + ), + 'first_name'=>array( + 'name'=>'first_name', + 'usage' => 'query_only', + ), + 'last_name'=>array( + 'name'=>'last_name', + 'usage' => 'query_only', + ), + 'salutation'=>array( + 'name'=>'salutation', + 'usage' => 'query_only', + ), + 'name'=>array( + 'name'=>'name', + 'vname' => 'LBL_LIST_NAME', + 'widget_class' => 'SubPanelDetailViewLink', + 'module' => 'Contacts', + 'width' => '23%', + ), + 'account_name'=>array( + 'name'=>'account_name', + 'module' => 'Accounts', + 'target_record_key' => 'account_id', + 'target_module' => 'Accounts', + 'widget_class' => 'SubPanelDetailViewLink', + 'vname' => 'LBL_LIST_ACCOUNT_NAME', + 'width' => '22%', + 'sortable'=>false, + ), + 'account_id'=>array( + 'usage'=>'query_only', + + ), + 'email1'=>array( + 'name'=>'email1', + 'vname' => 'LBL_LIST_EMAIL', + 'widget_class' => 'SubPanelEmailLink', + 'width' => '30%', + 'sortable' => false, + ), + 'phone_work'=>array ( + 'name'=>'phone_work', + 'vname' => 'LBL_LIST_PHONE', + 'width' => '15%', + ), + 'edit_button'=>array( + 'vname' => 'LBL_EDIT_BUTTON', + 'widget_class' => 'SubPanelEditButton', + 'module' => 'Contacts', + 'width' => '5%', + ), + 'remove_button'=>array( + 'vname' => 'LBL_REMOVE', + 'widget_class' => 'SubPanelRemoveButton', + 'module' => 'Contacts', + 'width' => '5%', + ), + ), +); +?> diff --git a/modules/Contacts/metadata/subpanels/ForOpportunities.php b/modules/Contacts/metadata/subpanels/ForOpportunities.php new file mode 100644 index 00000000..37b373b2 --- /dev/null +++ b/modules/Contacts/metadata/subpanels/ForOpportunities.php @@ -0,0 +1,131 @@ + array( + array('widget_class' => 'SubPanelTopCreateButton'), + array('widget_class' => 'SubPanelTopSelectButton', 'popup_module' => 'Contacts'), + ), + + 'where' => '', + + + + 'list_fields' => array( + 'first_name'=>array( + 'name'=>'first_name', + 'usage' => 'query_only', + ), + 'last_name'=>array( + 'name'=>'last_name', + 'usage' => 'query_only', + ), + 'salutation'=>array( + 'name'=>'salutation', + 'usage' => 'query_only', + ), + 'name'=>array( + 'name'=>'name', + 'vname' => 'LBL_LIST_NAME', + 'widget_class' => 'SubPanelDetailViewLink', + 'module' => 'Contacts', + 'width' => '23%', + ), + 'account_name'=>array( + 'name'=>'account_name', + 'module' => 'Accounts', + 'target_record_key' => 'account_id', + 'target_module' => 'Accounts', + 'widget_class' => 'SubPanelDetailViewLink', + 'vname' => 'LBL_LIST_ACCOUNT_NAME', + 'width' => '22%', + 'sortable'=>false, + ), + 'account_id'=>array( + 'usage'=>'query_only', + + ), + 'opportunity_role_fields'=>array( + 'usage' => 'query_only', + ), + 'opportunity_role_id'=>array( + 'usage' => 'query_only', + ), + 'opportunity_role'=>array( + 'name'=>'opportunity_role', + 'vname' => 'LBL_LIST_CONTACT_ROLE', + 'width' => '10%', + 'sortable'=>false, + ), + 'email1'=>array( + 'name'=>'email1', + 'vname' => 'LBL_LIST_EMAIL', + 'widget_class' => 'SubPanelEmailLink', + 'width' => '30%', + 'sortable' => false, + ), + + 'phone_work'=>array ( + 'name'=>'phone_work', + 'vname' => 'LBL_LIST_PHONE', + 'width' => '15%', + ), + //kbrill Bug#17483 + 'edit_button'=>array( + 'vname' => 'LBL_EDIT_BUTTON', + //'widget_class' => 'SubPanelEditButton', + //C.L. Bug#18035, changed to use SubPanelEditRoleButton + 'widget_class' => 'SubPanelEditRoleButton', + 'role_id'=>'opportunity_role_id', + 'module' => 'Contacts', + 'width' => '5%', + ), + 'remove_button'=>array( + 'vname' => 'LBL_REMOVE', + 'widget_class' => 'SubPanelRemoveButton', + 'module' => 'Contacts', + 'width' => '5%', + + ), + + + ), +); +?> \ No newline at end of file diff --git a/modules/Contacts/metadata/subpanels/ForProject.php b/modules/Contacts/metadata/subpanels/ForProject.php new file mode 100644 index 00000000..b96a9b5c --- /dev/null +++ b/modules/Contacts/metadata/subpanels/ForProject.php @@ -0,0 +1,81 @@ + array( + array('widget_class' => 'SubPanelTopSelectButton', 'title' => 'LBL_SELECT_USER_RESOURCE', 'popup_module' => 'Users', ), + ), + + 'where' => '', + + 'list_fields' => array( + 'object_image'=>array( + 'widget_class' => 'SubPanelIcon', + 'width' => '2%', + ), + 'name'=>array( + 'name' => 'name', + 'vname' => 'LBL_RESOURCE_NAME', + 'width' => '93%', + ), +/* 'remove_button'=>array( + 'vname' => 'LBL_REMOVE', + 'widget_class' => 'SubPanelRemoveButtonProjects', + 'width' => '5%', + ), + */ + 'remove_button'=>array( + 'vname' => 'LBL_REMOVE', + 'widget_class' => 'SubPanelRemoveButton', + 'module' => 'Contacts', + 'width' => '5%', + ), + 'first_name' => array( + 'usage'=>'query_only', + ), + 'last_name' => array( + 'usage'=>'query_only', + ), + 'salutation'=>array( + 'name'=>'salutation', + 'usage' => 'query_only', + ), + ), +); +?> \ No newline at end of file diff --git a/modules/Contacts/metadata/subpanels/default.php b/modules/Contacts/metadata/subpanels/default.php new file mode 100644 index 00000000..6a58d6d7 --- /dev/null +++ b/modules/Contacts/metadata/subpanels/default.php @@ -0,0 +1,112 @@ + array( + array('widget_class' => 'SubPanelTopCreateButton'), + array('widget_class' => 'SubPanelTopSelectButton', 'popup_module' => 'Contacts'), + ), + + 'where' => '', + + + + 'list_fields' => array( + 'first_name'=>array( + 'name'=>'first_name', + 'usage' => 'query_only', + ), + 'last_name'=>array( + 'name'=>'last_name', + 'usage' => 'query_only', + ), + 'salutation'=>array( + 'name'=>'salutation', + 'usage' => 'query_only', + ), + 'name'=>array( + 'name'=>'name', + 'vname' => 'LBL_LIST_NAME', + 'sort_by' => 'last_name', + 'sort_order' => 'asc', + 'widget_class' => 'SubPanelDetailViewLink', + 'module' => 'Contacts', + 'width' => '23%', + ), + 'account_name'=>array( + 'name'=>'account_name', + 'module' => 'Accounts', + 'target_record_key' => 'account_id', + 'target_module' => 'Accounts', + 'widget_class' => 'SubPanelDetailViewLink', + 'vname' => 'LBL_LIST_ACCOUNT_NAME', + 'width' => '22%', + 'sortable'=>false, + ), + 'account_id'=>array( + 'usage'=>'query_only', + + ), + 'email1'=>array( + 'name'=>'email1', + 'vname' => 'LBL_LIST_EMAIL', + 'widget_class' => 'SubPanelEmailLink', + 'width' => '30%', + 'sortable'=>false, + ), + 'phone_work'=>array ( + 'name'=>'phone_work', + 'vname' => 'LBL_LIST_PHONE', + 'width' => '15%', + ), + 'edit_button'=>array( + 'vname' => 'LBL_EDIT_BUTTON', + 'widget_class' => 'SubPanelEditButton', + 'module' => 'Contacts', + 'width' => '5%', + ), + 'remove_button'=>array( + 'vname' => 'LBL_REMOVE', + 'widget_class' => 'SubPanelRemoveButton', + 'module' => 'Contacts', + 'width' => '5%', + ), + ), +); +?> diff --git a/modules/Contacts/tpls/QuickCreate.tpl b/modules/Contacts/tpls/QuickCreate.tpl new file mode 100644 index 00000000..00533ee9 --- /dev/null +++ b/modules/Contacts/tpls/QuickCreate.tpl @@ -0,0 +1,92 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} + + + + + + +
    + +{if isset($smarty.request.isDuplicate) && $smarty.request.isDuplicate eq "true"} + +{else} + +{/if} + + + + + + +{if !empty($smarty.request.return_module)} + + +{/if} + +{{if isset($form.hidden)}} +{{foreach from=$form.hidden item=field}} +{{$field}} +{{/foreach}} +{{/if}} + +{* -- Begin QuickCreate Specific -- *} + + + + + + + + +{* -- End QuickCreate Specific -- *} + +{{if empty($form.button_location) || $form.button_location == 'top'}} +{{if !empty($form) && !empty($form.buttons)}} + {{foreach from=$form.buttons key=val item=button}} + {{sugar_button module="$module" id="$button" view="$view"}} + {{/foreach}} +{{else}} +{{sugar_button module="$module" id="SAVE" view="$view"}} +{{sugar_button module="$module" id="CANCEL" view="$view"}} +{{/if}} +{{if empty($form.hideAudit) || !$form.hideAudit}} +{{sugar_button module="$module" id="Audit" view="$view"}} +{{/if}} +{{/if}} +{{$ADMIN_EDIT}}
    \ No newline at end of file diff --git a/modules/Contacts/vardefs.php b/modules/Contacts/vardefs.php new file mode 100644 index 00000000..66149696 --- /dev/null +++ b/modules/Contacts/vardefs.php @@ -0,0 +1,597 @@ + 'contacts', 'audited'=>true, + +'unified_search' => true, 'unified_search_default_enabled' => true, 'duplicate_merge'=>true, 'fields' => +array ( + + 'email_and_name1' => + array ( + 'name' => 'email_and_name1', + 'rname' => 'email_and_name1', + 'vname' => 'LBL_NAME', + 'type' => 'varchar', + 'source' => 'non-db', + 'len' => '510', + 'importable' => 'false', + ), + 'lead_source' => + array ( + 'name' => 'lead_source', + 'vname' => 'LBL_LEAD_SOURCE', + 'type' => 'enum', + 'options' => 'lead_source_dom', + 'len' => '255', + 'comment' => 'How did the contact come about', + ), + + 'account_name' => + array ( + 'name' => 'account_name', + 'rname' => 'name', + 'id_name' => 'account_id', + 'vname' => 'LBL_ACCOUNT_NAME', + 'join_name'=>'accounts', + 'type' => 'relate', + 'link' => 'accounts', + 'table' => 'accounts', + 'isnull' => 'true', + 'module' => 'Accounts', + 'dbType' => 'varchar', + 'len' => '255', + 'source' => 'non-db', + 'unified_search' => true, + ), + 'account_id' => + array ( + 'name' => 'account_id', + 'rname' => 'id', + 'id_name' => 'account_id', + 'vname' => 'LBL_ACCOUNT_ID', + 'type' => 'relate', + 'table' => 'accounts', + 'isnull' => 'true', + 'module' => 'Accounts', + 'dbType' => 'id', + 'reportable'=>false, + 'source' => 'non-db', + 'massupdate' => false, + 'duplicate_merge'=> 'disabled', + 'hideacl'=>true, + + ), + 'opportunity_role_fields' => + array ( + 'name' => 'opportunity_role_fields', + 'rname' => 'id', + 'relationship_fields'=>array('id' => 'opportunity_role_id', 'contact_role' => 'opportunity_role'), + 'vname' => 'LBL_ACCOUNT_NAME', + 'type' => 'relate', + 'link' => 'opportunities', + 'link_type' => 'relationship_info', + 'join_link_name' => 'opportunities_contacts', + 'source' => 'non-db', + 'importable' => 'false', + 'duplicate_merge'=> 'disabled', + 'studio' => array('listview' => false), + ), + 'opportunity_role_id' => + array( + 'name' => 'opportunity_role_id', + 'type' => 'varchar', + 'source' => 'non-db', + 'vname' => 'LBL_OPPORTUNITY_ROLE_ID', + 'studio' => array('listview' => false), + ), + 'opportunity_role' => + array( + 'name' => 'opportunity_role', + 'type' => 'enum', + 'source' => 'non-db', + 'vname' => 'LBL_OPPORTUNITY_ROLE', + 'options' => 'opportunity_relationship_type_dom', + ), + 'reports_to_id'=> + array( + 'name' => 'reports_to_id', + 'vname' => 'LBL_REPORTS_TO_ID', + 'type' => 'id', + 'required'=>false, + 'reportable'=>false, + 'comment' => 'The contact this contact reports to' + ), + 'report_to_name' => + array ( + 'name' => 'report_to_name', + 'rname' => 'last_name', + 'id_name' => 'reports_to_id', + 'vname' => 'LBL_REPORTS_TO', + 'type' => 'relate', + 'link' => 'reports_to_link', + 'table' => 'contacts', + 'isnull' => 'true', + 'module' => 'Contacts', + 'dbType' => 'varchar', + 'len' => 'id', + 'reportable'=>false, + 'source' => 'non-db', + ), + 'birthdate' => + array ( + 'name' => 'birthdate', + 'vname' => 'LBL_BIRTHDATE', + 'massupdate' => false, + 'type' => 'date', + 'comment' => 'The birthdate of the contact' + ), + 'accounts' => + array ( + 'name' => 'accounts', + 'type' => 'link', + 'relationship' => 'accounts_contacts', + 'link_type' => 'one', + 'source' => 'non-db', + 'vname' => 'LBL_ACCOUNT', + 'duplicate_merge'=> 'disabled', + ), + 'reports_to_link' => + array ( + 'name' => 'reports_to_link', + 'type' => 'link', + 'relationship' => 'contact_direct_reports', + 'link_type' => 'one', + 'side' => 'right', + 'source' => 'non-db', + 'vname' => 'LBL_REPORTS_TO', + ), + 'opportunities' => + array ( + 'name' => 'opportunities', + 'type' => 'link', + 'relationship' => 'opportunities_contacts', + 'source' => 'non-db', + 'module' => 'Opportunities', + 'bean_name' => 'Opportunity', + 'vname' => 'LBL_OPPORTUNITIES', + ), + 'email_addresses' => + array ( + 'name' => 'email_addresses', + 'type' => 'link', + 'relationship' => 'contacts_email_addresses', + 'module' => 'EmailAddress', + 'bean_name'=>'EmailAddress', + 'source' => 'non-db', + 'vname' => 'LBL_EMAIL_ADDRESSES', + 'reportable'=>false, + 'rel_fields' => array('primary_address' => array('type'=>'bool')), + 'unified_search'=>true, + ), + 'email_addresses_primary' => + array ( + 'name' => 'email_addresses_primary', + 'type' => 'link', + 'relationship' => 'contacts_email_addresses_primary', + 'source' => 'non-db', + 'vname' => 'LBL_EMAIL_ADDRESS_PRIMARY', + 'duplicate_merge'=> 'disabled', + ), + 'bugs' => + array ( + 'name' => 'bugs', + 'type' => 'link', + 'relationship' => 'contacts_bugs', + 'source' => 'non-db', + 'vname' => 'LBL_BUGS', + ), + 'calls' => + array ( + 'name' => 'calls', + 'type' => 'link', + 'relationship' => 'calls_contacts', + 'source' => 'non-db', + 'vname' => 'LBL_CALLS', + ), + 'cases' => + array ( + 'name' => 'cases', + 'type' => 'link', + 'relationship' => 'contacts_cases', + 'source' => 'non-db', + 'vname' => 'LBL_CASES', + ), + 'direct_reports'=> + array ( + 'name' => 'direct_reports', + 'type' => 'link', + 'relationship' => 'contact_direct_reports', + 'source' => 'non-db', + 'vname' => 'LBL_DIRECT_REPORTS', + ), + 'emails'=> + array ( + 'name' => 'emails', + 'type' => 'link', + 'relationship' => 'emails_contacts_rel', + 'source' => 'non-db', + 'vname' => 'LBL_EMAILS', + ), + 'documents'=> + array ( + 'name' => 'documents', + 'type' => 'link', + 'relationship' => 'documents_contacts', + 'source' => 'non-db', + 'vname' => 'LBL_DOCUMENTS_SUBPANEL_TITLE', + ), + 'leads'=> + array ( + 'name' => 'leads', + 'type' => 'link', + 'relationship' => 'contact_leads', + 'source' => 'non-db', + 'vname' => 'LBL_LEADS', + ), + 'meetings'=> + array ( + 'name' => 'meetings', + 'type' => 'link', + 'relationship' => 'meetings_contacts', + 'source' => 'non-db', + 'vname' => 'LBL_MEETINGS', + ), + 'notes'=> + array ( + 'name' => 'notes', + 'type' => 'link', + 'relationship' => 'contact_notes', + 'source' => 'non-db', + 'vname' => 'LBL_NOTES', + ), + 'project'=> + array ( + 'name' => 'project', + 'type' => 'link', + 'relationship' => 'projects_contacts', + 'source' => 'non-db', + 'vname' => 'LBL_PROJECTS', + ), + + 'tasks'=> + array ( + 'name' => 'tasks', + 'type' => 'link', + 'relationship' => 'contact_tasks', + 'source' => 'non-db', + 'vname' => 'LBL_TASKS', + ), + 'tasks_parent'=> + array ( + 'name' => 'tasks_parent', + 'type' => 'link', + 'relationship' => 'contact_tasks_parent', + 'source' => 'non-db', + 'vname' => 'LBL_TASKS', + ), + 'user_sync'=> + array ( + 'name' => 'users', + 'type' => 'link', + 'relationship' => 'contacts_users', + 'source' => 'non-db', + 'vname' => 'LBL_USER_SYNC', + ), + 'created_by_link' => + array ( + 'name' => 'created_by_link', + 'type' => 'link', + 'relationship' => 'contacts_created_by', + 'vname' => 'LBL_CREATED_BY_USER', + 'link_type' => 'one', + 'module' => 'Users', + 'bean_name' => 'User', + 'source' => 'non-db', + ), + 'modified_user_link' => + array ( + 'name' => 'modified_user_link', + 'type' => 'link', + 'relationship' => 'contacts_modified_user', + 'vname' => 'LBL_MODIFIED_BY_USER', + 'link_type' => 'one', + 'module' => 'Users', + 'bean_name' => 'User', + 'source' => 'non-db', + ), + 'assigned_user_link' => + array ( + 'name' => 'assigned_user_link', + 'type' => 'link', + 'relationship' => 'contacts_assigned_user', + 'vname' => 'LBL_ASSIGNED_TO_USER', + 'link_type' => 'one', + 'module' => 'Users', + 'bean_name' => 'User', + 'source' => 'non-db', + 'rname' => 'user_name', + 'id_name' => 'assigned_user_id', + 'table' => 'users', + 'duplicate_merge'=>'enabled' + ), + 'campaign_id' => + array ( + 'name' => 'campaign_id', + 'comment' => 'Campaign that generated lead', + 'vname'=>'LBL_CAMPAIGN_ID', + 'rname' => 'id', + 'id_name' => 'campaign_id', + 'type' => 'id', + //'dbType' => 'char', + 'table' => 'campaigns', + 'isnull' => 'true', + 'module' => 'Campaigns', +// 'reportable'=>false, + 'massupdate' => false, + 'duplicate_merge'=> 'disabled', + ), + + 'campaign_name' => + array ( + 'name' => 'campaign_name', + 'rname' => 'name', + 'vname' => 'LBL_CAMPAIGN', + 'type' => 'relate', + 'link' => 'campaign_contacts', + 'isnull' => 'true', + 'reportable'=>false, + 'source'=>'non-db', + 'table' => 'campaigns', + 'id_name' => 'campaign_id', + 'module'=>'Campaigns', + 'duplicate_merge'=>'disabled', + 'comment' => 'The first campaign name for Contact (Meta-data only)', + ), + + 'campaigns' => + array ( + 'name' => 'campaigns', + 'type' => 'link', + 'relationship' => 'contact_campaign_log', + 'module'=>'CampaignLog', + 'bean_name'=>'CampaignLog', + 'source'=>'non-db', + 'vname'=>'LBL_CAMPAIGNLOG', + ), + + 'campaign_contacts' => + array ( + 'name' => 'campaign_contacts', + 'type' => 'link', + 'vname' => 'LBL_CAMPAIGN_CONTACT', + 'relationship' => 'campaign_contacts', + 'source' => 'non-db', + ), + 'c_accept_status_fields' => + array ( + 'name' => 'c_accept_status_fields', + 'rname' => 'id', + 'relationship_fields'=>array('id' => 'accept_status_id', 'accept_status' => 'accept_status_name'), + 'vname' => 'LBL_LIST_ACCEPT_STATUS', + 'type' => 'relate', + 'link' => 'calls', + 'link_type' => 'relationship_info', + 'source' => 'non-db', + 'importable' => 'false', + 'duplicate_merge'=> 'disabled', + 'studio' => array('listview' => false), + ), + 'm_accept_status_fields' => + array ( + 'name' => 'm_accept_status_fields', + 'rname' => 'id', + 'relationship_fields'=>array('id' => 'accept_status_id', 'accept_status' => 'accept_status_name'), + 'vname' => 'LBL_LIST_ACCEPT_STATUS', + 'type' => 'relate', + 'link' => 'meetings', + 'link_type' => 'relationship_info', + 'source' => 'non-db', + 'importable' => 'false', + 'hideacl'=>true, + 'duplicate_merge'=> 'disabled', + 'studio' => array('listview' => false), + ), + 'accept_status_id' => + array( + 'name' => 'accept_status_id', + 'type' => 'varchar', + 'source' => 'non-db', + 'vname' => 'LBL_LIST_ACCEPT_STATUS', + 'studio' => array('listview' => false), + ), + 'accept_status_name' => + array( + 'massupdate' => false, + 'name' => 'accept_status_name', + 'type' => 'enum', + 'studio' => 'false', + 'source' => 'non-db', + 'vname' => 'LBL_LIST_ACCEPT_STATUS', + 'options' => 'dom_meeting_accept_status', + 'importable' => 'false', + ), + 'prospect_lists' => + array ( + 'name' => 'prospect_lists', + 'type' => 'link', + 'relationship' => 'prospect_list_contacts', + 'module'=>'ProspectLists', + 'source'=>'non-db', + 'vname'=>'LBL_PROSPECT_LIST', + ), + 'sync_contact' => + array ( + 'massupdate' => false, + 'name' => 'sync_contact', + 'vname' => 'LBL_SYNC_CONTACT', + 'type' => 'bool', + 'source' => 'non-db', + 'comment' => 'Synch to outlook? (Meta-Data only)', + 'studio' => 'true', + ), +), +'indices' => array ( + array( + 'name' => 'idx_cont_last_first', + 'type' => 'index', + 'fields' => array('last_name', 'first_name', 'deleted') + ), + array( + 'name' => 'idx_contacts_del_last', + 'type' => 'index', + 'fields' => array('deleted', 'last_name'), + ), + array( + 'name' => 'idx_cont_del_reports', + 'type' => 'index', + 'fields'=>array('deleted', 'reports_to_id', 'last_name') + ), + array( + 'name' => 'idx_reports_to_id', + 'type' => 'index', + 'fields'=> array('reports_to_id'), + ), + array( + 'name' => 'idx_del_id_user', + 'type' => 'index', + 'fields'=> array('deleted', 'id', 'assigned_user_id'), + ), + array( + 'name' => 'idx_cont_assigned', + 'type' => 'index', + 'fields' => array('assigned_user_id') + ), +// array( +// 'name' => 'idx_cont_email1', +// 'type' => 'index', +// 'fields' => array('email1') +// ), +// array( +// 'name' => 'idx_cont_email2', +// 'type' => 'index', +// 'fields' => array('email2') +// ), +), + 'relationships' => array( + 'contact_direct_reports' => array('lhs_module' => 'Contacts', + 'lhs_table' => 'contacts', + 'lhs_key' => 'id', + 'rhs_module' => 'Contacts', + 'rhs_table' => 'contacts', + 'rhs_key' => 'reports_to_id', + 'relationship_type' => 'one-to-many'), + 'contact_leads' => array('lhs_module' => 'Contacts', + 'lhs_table' => 'contacts', + 'lhs_key' => 'id', + 'rhs_module' => 'Leads', + 'rhs_table' => 'leads', + 'rhs_key' => 'contact_id', + 'relationship_type' => 'one-to-many'), + 'contact_notes' => array('lhs_module' => 'Contacts', + 'lhs_table' => 'contacts', + 'lhs_key' => 'id', + 'rhs_module' => 'Notes', + 'rhs_table' => 'notes', + 'rhs_key' => 'contact_id', + 'relationship_type' => 'one-to-many'), + 'contact_tasks' => array('lhs_module' => 'Contacts', + 'lhs_table' => 'contacts', + 'lhs_key' => 'id', + 'rhs_module' => 'Tasks', + 'rhs_table' => 'tasks', + 'rhs_key' => 'contact_id', + 'relationship_type' => 'one-to-many'), + 'contact_tasks_parent' => array('lhs_module' => 'Contacts', + 'lhs_table' => 'contacts', + 'lhs_key' => 'id', + 'rhs_module' => 'Tasks', + 'rhs_table' => 'tasks', + 'rhs_key' => 'parent_id', + 'relationship_type' => 'one-to-many', + 'relationship_role_column'=>'parent_type', + 'relationship_role_column_value'=>'Contacts' + ), + 'contacts_assigned_user' => array('lhs_module' => 'Users', + 'lhs_table' => 'users', + 'lhs_key' => 'id', + 'rhs_module' => 'Contacts', + 'rhs_table' => 'contacts', + 'rhs_key' => 'assigned_user_id', + 'relationship_type' => 'one-to-many'), + 'contacts_modified_user' => array('lhs_module' => 'Users', + 'lhs_table' => 'users', + 'lhs_key' => 'id', + 'rhs_module' => 'Contacts', + 'rhs_table' => 'contacts', + 'rhs_key' => 'modified_user_id', + 'relationship_type' => 'one-to-many'), + 'contacts_created_by' => array('lhs_module' => 'Users', + 'lhs_table' => 'users', + 'lhs_key' => 'id', + 'rhs_module' => 'Contacts', + 'rhs_table' => 'contacts', + 'rhs_key' => 'created_by', + 'relationship_type' => 'one-to-many'), + 'contact_campaign_log' => array( + 'lhs_module' => 'Contacts', + 'lhs_table' => 'contacts', + 'lhs_key' => 'id', + 'rhs_module' => 'CampaignLog', + 'rhs_table' => 'campaign_log', + 'rhs_key' => 'target_id', + 'relationship_type' =>'one-to-many' + ), +), + +//This enables optimistic locking for Saves From EditView +'optimistic_locking'=>true, +); + +VardefManager::createVardef('Contacts','Contact', array('default', 'assignable', + 'person')); + +?> diff --git a/modules/Contacts/views/view.closecontactaddresspopup.php b/modules/Contacts/views/view.closecontactaddresspopup.php new file mode 100644 index 00000000..a7abf6a6 --- /dev/null +++ b/modules/Contacts/views/view.closecontactaddresspopup.php @@ -0,0 +1,51 @@ +window.close();"; + parent::display(); + } +} +?> diff --git a/modules/Contacts/views/view.contactaddresspopup.php b/modules/Contacts/views/view.contactaddresspopup.php new file mode 100644 index 00000000..bf37cb5e --- /dev/null +++ b/modules/Contacts/views/view.contactaddresspopup.php @@ -0,0 +1,62 @@ +display(); + } + + function display() { + $this->renderJavascript(); + $popup = new Popup_Picker(); + echo $popup->process_page_for_address(); + } +} +?> \ No newline at end of file diff --git a/modules/Contacts/views/view.detail.php b/modules/Contacts/views/view.detail.php new file mode 100644 index 00000000..bce07f15 --- /dev/null +++ b/modules/Contacts/views/view.detail.php @@ -0,0 +1,59 @@ +retrieveSettings(); + if(isset($admin->settings['portal_on']) && $admin->settings['portal_on']) { + $this->ss->assign("PORTAL_ENABLED", true); + } + parent::display(); + } +} diff --git a/modules/Contacts/views/view.edit.php b/modules/Contacts/views/view.edit.php new file mode 100644 index 00000000..7da98497 --- /dev/null +++ b/modules/Contacts/views/view.edit.php @@ -0,0 +1,90 @@ +useForSubpanel = true; + $this->useModuleQuickCreateTemplate = true; + } + + /** + * @see SugarView::display() + * + * We are overridding the display method to manipulate the sectionPanels. + * If portal is not enabled then don't show the Portal Information panel. + */ + public function display() + { + $this->ev->process(); + if ( !empty($_REQUEST['contact_name']) && !empty($_REQUEST['contact_id']) + && $this->ev->fieldDefs['report_to_name']['value'] == '' + && $this->ev->fieldDefs['reports_to_id']['value'] == '') { + $this->ev->fieldDefs['report_to_name']['value'] = $_REQUEST['contact_name']; + $this->ev->fieldDefs['reports_to_id']['value'] = $_REQUEST['contact_id']; + } + $admin = new Administration(); + $admin->retrieveSettings(); + if(empty($admin->settings['portal_on']) || !$admin->settings['portal_on']) { + unset($this->ev->sectionPanels[strtoupper('lbl_portal_information')]); + } else { + echo ''; + echo ''; + } + + echo $this->ev->display($this->showTitle); + } +} \ No newline at end of file diff --git a/modules/Contacts/views/view.list.php b/modules/Contacts/views/view.list.php new file mode 100644 index 00000000..297b42b6 --- /dev/null +++ b/modules/Contacts/views/view.list.php @@ -0,0 +1,48 @@ +lv->targetList = true; + } +} diff --git a/modules/Contacts/views/view.mailmergepopup.php b/modules/Contacts/views/view.mailmergepopup.php new file mode 100644 index 00000000..4bc4bc7b --- /dev/null +++ b/modules/Contacts/views/view.mailmergepopup.php @@ -0,0 +1,62 @@ +display(); + } + + function display() { + + $popup = new Popup_Picker(); + echo $popup->process_page_for_merge(); + } +} +?> \ No newline at end of file diff --git a/modules/Contacts/views/view.retrieveemail.php b/modules/Contacts/views/view.retrieveemail.php new file mode 100644 index 00000000..7f41f71a --- /dev/null +++ b/modules/Contacts/views/view.retrieveemail.php @@ -0,0 +1,77 @@ +display(); + } + + function display(){ + $data = array(); + $data['target'] = $_REQUEST['target']; + if(!empty($_REQUEST['email'])) { + $db = DBManagerFactory::getInstance(); + $email = $GLOBALS['db']->quote(strtoupper(trim($_REQUEST['email']))); + $result = $db->query("SELECT * FROM email_addresses WHERE email_address_caps = '$email' AND deleted = 0"); + if($row = $db->fetchByAssoc($result)) { + $data['email'] = $row; + } else { + $data['email'] = ''; + } + } + $json = new JSON(JSON_LOOSE_TYPE); + echo $json->encode($data); + } +} +?> \ No newline at end of file diff --git a/modules/Contacts/views/view.validportalusername.php b/modules/Contacts/views/view.validportalusername.php new file mode 100644 index 00000000..48882e52 --- /dev/null +++ b/modules/Contacts/views/view.validportalusername.php @@ -0,0 +1,78 @@ +display(); + } + + /** + * @see SugarView::display() + */ + public function display() + { + if (!empty($_REQUEST['portal_name'])) { + $portalUsername = $this->bean->db->quote($_REQUEST['portal_name']); + $result = $this->bean->db->query("Select count(id) as total from contacts where portal_name = '$portalUsername' and deleted='0'"); + $total = 0; + while($row = $this->bean->db->fetchByAssoc($result)) + $total = $row['total']; + echo $total; + } + else + echo '0'; + } +} \ No newline at end of file diff --git a/modules/Currencies/Currency.php b/modules/Currencies/Currency.php new file mode 100644 index 00000000..792d3604 --- /dev/null +++ b/modules/Currencies/Currency.php @@ -0,0 +1,630 @@ +field_defs['hide'] = array('name'=>'hide', 'source'=>'non-db', 'type'=>'varchar','len'=>25); + $this->field_defs['unhide'] = array('name'=>'unhide', 'source'=>'non-db', 'type'=>'varchar','len'=>25); + $this->disable_row_level_security =true; + } + + /** + * convertToDollar + * This method accepts a currency amount and converts it to the US Dollar amount + * + * @param $amount The currency amount to convert to US Dollars + * @param $precision The rounding precision scale + * @return currency value in US Dollars from conversion + */ + function convertToDollar($amount, $precision = 6) { + return round(($amount / $this->conversion_rate), $precision); + } + + /** + * convertFromCollar + * This method accepts a US Dollar amount and returns a currency amount + * with the conversion rate applied to it. + * + * @param $amount The currency amount in US Dollars + * @param $precision The rounding precision scale + * @return currency value from US Dollar conversion + */ + function convertFromDollar($amount, $precision = 6){ + return round(($amount * $this->conversion_rate), $precision); + } + + /** + * getDefaultCurrencyName + * + * Returns the default currency name as defined in application + * @return String value of default currency name + */ + function getDefaultCurrencyName(){ + global $sugar_config; + return $sugar_config['default_currency_name']; + } + + /** + * getDefaultCurrencySymbol + * + * Returns the default currency symobol in application + * @return String value of default currency symbol(e.g. $) + */ + function getDefaultCurrencySymbol(){ + global $sugar_config; + return $sugar_config['default_currency_symbol']; + } + + /** + * getDefaultISO4217 + * + * Returns the default ISO 4217 standard currency code value + * @return String value for the ISO 4217 standard code(e.g. EUR) + */ + function getDefaultISO4217(){ + global $sugar_config; + return $sugar_config['default_currency_iso4217']; + } + + /** + * retrieveIDBySmbol + * + * Returns the id value for given currency symbol in Currencies table + * and currency entry for symbol is not set to deleted. + * + * @param $symbol Symbol value + * @return String id value for symbol defined in Currencies table, blank String value + * if none found + */ + function retrieveIDBySymbol($symbol) { + $query = "SELECT id FROM currencies WHERE symbol='$symbol' AND deleted=0;"; + $result = $this->db->query($query); + if($result){ + $row = $this->db->fetchByAssoc($result); + if($row){ + return $row['id']; + } + } + + return ''; + } + + function list_view_parse_additional_sections(&$list_form) { + global $isMerge; + + if(isset($isMerge) && $isMerge && $this->id != '-99'){ + $list_form->assign('PREROW', ''); + } + return $list_form; + } + + function retrieve_id_by_name($name) { + $query = "select id from currencies where name='$name' and deleted=0;"; + $result = $this->db->query($query); + if($result){ + $row = $this->db->fetchByAssoc($result); + if($row){ + return $row['id']; + } + } + return ''; + } + + function retrieve($id, $encode = true){ + if($id == '-99'){ + $this->name = $this->getDefaultCurrencyName(); + $this->symbol = $this->getDefaultCurrencySymbol(); + $this->id = '-99'; + $this->conversion_rate = 1; + $this->iso4217 = $this->getDefaultISO4217(); + $this->deleted = 0; + $this->status = 'Active'; + $this->hide = ''; + }else{ + parent::retrieve($id, $encode); + } + if(!isset($this->name) || $this->deleted == 1){ + $this->name = $this->getDefaultCurrencyName(); + $this->symbol = $this->getDefaultCurrencySymbol(); + $this->conversion_rate = 1; + $this->iso4217 = $this->getDefaultISO4217(); + $this->id = '-99'; + $this->deleted = 0; + $this->status = 'Active'; + $this->hide = ''; + } + + } + + /** + * Method for returning the currency symbol, must return chr(2) for the € symbol + * to display correctly in pdfs + * Parameters: + * none + * Returns: + * $symbol otherwise chr(2) for euro symbol + */ + function getPdfCurrencySymbol() { + if($this->symbol == '€' || $this->symbol == '€') + return chr(2); + return $this->symbol; + } + function get_list_view_data() { + $this->conversion_rate = format_number($this->conversion_rate, 10, 10); + $data = parent::get_list_view_data(); + return $data; + } + function save($check_notify = FALSE) { + sugar_cache_clear('currency_list'); + return parent::save($check_notify); + } +} // end currency class + +/** + * currency_format_number + * + * This method is a wrapper designed exclusively for formatting currency values + * with the assumption that the method caller wants a currency formatted value + * matching his/her user preferences(if set) or the system configuration defaults + *(if user preferences are not defined). + * + * @param $amount The amount to be formatted + * @param $params Optional parameters(see @format_number) + * @return String representation of amount with formatting applied + */ +function currency_format_number($amount, $params = array()) { + global $locale; + if(isset($params['round']) && is_int($params['round'])){ + $real_round = $params['round']; + }else{ + $real_round = $locale->getPrecedentPreference('default_currency_significant_digits'); + } + if(isset($params['decimals']) && is_int($params['decimals'])){ + $real_decimals = $params['decimals']; + }else{ + $real_decimals = $locale->getPrecedentPreference('default_currency_significant_digits'); + } + $real_round = $real_round == '' ? 0 : $real_round; + $real_decimals = $real_decimals == '' ? 0 : $real_decimals; + + $showCurrencySymbol = $locale->getPrecedentPreference('default_currency_symbol') != '' ? true : false; + if($showCurrencySymbol && !isset($params['currency_symbol'])) { + $params["currency_symbol"] = true; + } + return format_number($amount, $real_round, $real_decimals, $params); + +} + +/** + * format_number(deprecated) + * + * This method accepts an amount and formats it given the user's preferences. + * Should the values set in the user preferences be invalid then it will + * apply the system wide Sugar configuration values. Calls to + * getPrecendentPreference() method in Localization.php are made that + * handle this logic. + * + * Going forward with Sugar 4.5.0e+ implementations, users of this class should + * simple call this function with $amount parameter and leave it to the + * class to locate and apply the appropriate formatting. + * + * One of the problems is that there is considerable legacy code that is using + * this method for non currency formatting. In other words, the format_number + * method may be called to just display a number like 1,000 formatted appropriately. + * + * Also, issues about responsibilities arise. Currently the callers of this function + * are responsible for passing in the appropriate decimal and number rounding digits + * as well as parameters to control displaying the currency symbol or not. + * + * @param $amount The currency amount to apply formatting to + * @param $round Integer value for number of places to round to + * @param $decimals Integer value for number of decimals to round to + * @param $params Array of additional parameter values + * + * + * The following are passed in as an array of params: + * boolean $params['currency_symbol'] - true to display currency symbol + * boolean $params['convert'] - true to convert from USD dollar + * boolean $params['percentage'] - true to display % sign + * boolean $params['symbol_space'] - true to have space between currency symbol and amount + * String $params['symbol_override'] - string to over default currency symbol + * String $params['type'] - pass in 'pdf' for pdf currency symbol conversion + * String $params['currency_id'] - currency_id to retreive, defaults to current user + * String $params['human'] - formatting that truncates the first thousands and appends "k" + * @return String formatted currency value + * @see include/Localization/Localization.php + */ +function format_number($amount, $round = null, $decimals = null, $params = array()) { + global $app_strings, $current_user, $sugar_config, $locale; + static $current_users_currency = null; + static $last_override_currency = null; + static $override_currency_id = null; + static $currency; + + $seps = get_number_seperators(); + $num_grp_sep = $seps[0]; + $dec_sep = $seps[1]; + + // cn: bug 8522 - sig digits not honored in pdfs + if(is_null($decimals)) { + $decimals = $locale->getPrecision(); + } + if(is_null($round)) { + $round = $locale->getPrecision(); + } + + // only create a currency object if we need it + if((!empty($params['currency_symbol']) && $params['currency_symbol']) || + (!empty($params['convert']) && $params['convert']) || + (!empty($params['currency_id']))) { + // if we have an override currency_id + if(!empty($params['currency_id'])) { + if($override_currency_id != $params['currency_id']) { + $override_currency_id = $params['currency_id']; + $currency = new Currency(); + $currency->retrieve($override_currency_id); + $last_override_currency = $currency; + } else { + $currency = $last_override_currency; + } + + } elseif(!isset($current_users_currency)) { // else use current user's + $current_users_currency = new Currency(); + if($current_user->getPreference('currency')) $current_users_currency->retrieve($current_user->getPreference('currency')); + else $current_users_currency->retrieve('-99'); // use default if none set + $currency = $current_users_currency; + } + } + if(!empty($params['convert']) && $params['convert']) { + $amount = $currency->convertFromDollar($amount, 6); + } + + if(!empty($params['currency_symbol']) && $params['currency_symbol']) { + if(!empty($params['symbol_override'])) { + $symbol = $params['symbol_override']; + } + elseif(!empty($params['type']) && $params['type'] == 'pdf') { + $symbol = $currency->getPdfCurrencySymbol(); + $symbol_space = false; + } else { + if(empty($currency->symbol)) + $symbol = $currency->getDefaultCurrencySymbol(); + else + $symbol = $currency->symbol; + $symbol_space = true; + } + } else { + $symbol = ''; + } + + if(isset($params['charset_convert'])) { + $symbol = $locale->translateCharset($symbol, 'UTF-8', $locale->getExportCharset()); + } + + if(empty($params['human'])) { + $amount = number_format(round($amount, $round), $decimals, $dec_sep, $num_grp_sep); + $amount = format_place_symbol($amount, $symbol,(empty($params['symbol_space']) ? false : true)); + } else { + // If amount is more greater than a thousand(postiive or negative) + if(strpos($amount, '.') > 0) { + $checkAmount = strlen(substr($amount, 0, strpos($amount, '.'))); + } + + if($checkAmount >= 1000 || $checkAmount <= -1000) { + $amount = round(($amount / 1000), 0); + $amount = $amount . 'k'; + $amount = format_place_symbol($amount, $symbol,(empty($params['symbol_space']) ? false : true)); + } else { + $amount = format_place_symbol($amount, $symbol,(empty($params['symbol_space']) ? false : true)); + } + } + + if(!empty($params['percentage']) && $params['percentage']) $amount .= $app_strings['LBL_PERCENTAGE_SYMBOL']; + return $amount; + +} //end function format_number + + + +function format_place_symbol($amount, $symbol, $symbol_space) { + if($symbol != '') { + if($symbol_space == true) { + $amount = $symbol . ' ' . $amount; + } else { + $amount = $symbol . $amount; + } + } + return $amount; +} + +function unformat_number($string) { + // Just in case someone passes an already unformatted number through. + if ( !is_string($string) ) { + return $string; + } + + static $currency = null; + if(!isset($currency)) { + global $current_user; + $currency = new Currency(); + if(!empty($current_user->id)){ + if($current_user->getPreference('currency')){ + $currency->retrieve($current_user->getPreference('currency')); + } + else{ + $currency->retrieve('-99'); // use default if none set + } + }else{ + $currency->retrieve('-99'); // use default if none set + } + } + + $seps = get_number_seperators(); + // remove num_grp_sep and replace decimal seperater with decimal + $string = trim(str_replace(array($seps[0], $seps[1], $currency->symbol), array('', '.', ''), $string)); + if(preg_match('/^[+-]?\d(\.\d+)?[Ee]([+-]?\d+)?$/', $string)) $string = sprintf("%.0f", $string);//for scientific number format. After round(), we may get this number type. + preg_match('/[\-\+]?[0-9\.]*/', $string, $string); + + $out_number = trim($string[0]); + if ( $out_number == '' ) { + return ''; + } else { + return (float)$out_number; + } +} + +// deprecated use format_number() above +function format_money($amount, $for_display = TRUE) { + // This function formats an amount for display. + // Later on, this should be converted to use proper thousand and decimal seperators + // Currently, it stays closer to the existing format, and just rounds to two decimal points + if(isset($amount)) { + if($for_display) { + return sprintf("%0.02f",$amount); + } else { + // If it's an editable field, don't use a thousand seperator. + // Or perhaps we will want to, but it doesn't matter right now. + return sprintf("%0.02f",$amount); + } + } else { + return; + } +} + +/** + * Returns user/system preference for number grouping separator character(default ",") and the decimal separator + *(default "."). Special case: when num_grp_sep is ".", it will return NULL as the num_grp_sep. + * @return array Two element array, first item is num_grp_sep, 2nd item is dec_sep + */ +function get_number_seperators($reset_sep = false) { + global $current_user, $sugar_config; + + static $dec_sep = null; + static $num_grp_sep = null; + + if ( $reset_sep ) { + // This is typically only used during unit-tests + $dec_sep = $num_grp_sep = null; + } + + if($dec_sep == null) { + $dec_sep = $sugar_config['default_decimal_seperator']; + if(!empty($current_user->id)){ + $user_dec_sep = $current_user->getPreference('dec_sep'); + $dec_sep =(empty($user_dec_sep) ? $sugar_config['default_decimal_seperator'] : $user_dec_sep); + } + } + if($num_grp_sep == null) { + $num_grp_sep = $sugar_config['default_number_grouping_seperator']; + if(!empty($current_user->id)){ + $user_num_grp_sep = $current_user->getPreference('num_grp_sep'); + $num_grp_sep =(empty($user_num_grp_sep) ? $sugar_config['default_number_grouping_seperator'] : $user_num_grp_sep); + } + } + + return array($num_grp_sep, $dec_sep); +} + +/** + * toString + * + * Utility function to print out some information about Currency instance. + */ +function toString($echo = true) { + $s = "\$m_currency_round=$m_currency_round \n" . + "\$m_currency_decimal=$m_currency_decimal \n" . + "\$m_currency_symbol=$m_currency_symbol \n" . + "\$m_currency_iso=$m_currency_iso \n" . + "\$m_currency_name=$m_currency_name \n"; + + if($echo) { + echo $s; + } + + return $s; +} + +function getCurrencyDropDown($focus, $field='currency_id', $value='', $view='DetailView'){ + $view = ucfirst($view); + if($view == 'EditView' || $view == 'MassUpdate' || $view == 'QuickCreate'){ + if ( isset($_REQUEST[$field]) && !empty($_REQUEST[$field]) ) { + $value = $_REQUEST[$field]; + } elseif ( empty($focus->id) ) { + $value = $GLOBALS['current_user']->getPreference('currency'); + if ( empty($value) ) { + // -99 is the system default currency + $value = -99; + } + } + require_once('modules/Currencies/ListCurrency.php'); + $currency_fields = array(); + //Bug 18276 - Fix for php 5.1.6 + $defs=$focus->field_defs; + // + foreach($defs as $name=>$key){ + if($key['type'] == 'currency'){ + $currency_fields[]= $name; + } + } + $currency = new ListCurrency(); + $selectCurrency = $currency->getSelectOptions($value); + + $currency->setCurrencyFields($currency_fields); + $html = ''. + get_select_options_with_id($listitems,$value).''; + }else{ + + $currency = new Currency(); + if ( isset($focus->currency_id) ) { + $currency_id = $focus->currency_id; + } else { + $currency_id = -99; + } + $currency->retrieve($currency_id); + return $currency->name; + } +} + +function getCurrencySymbolDropDown($focus, $field='currency_name', $value='', $view='DetailView') +{ + if($view == 'EditView' || $view == 'MassUpdate' || $view == 'QuickCreate'){ + require_once('modules/Currencies/ListCurrency.php'); + $currency_fields = array(); + //Bug 18276 - Fix for php 5.1.6 + $defs=$focus->field_defs; + // + foreach($defs as $name=>$key){ + if($key['type'] == 'currency'){ + $currency_fields[]= $name; + } + } + $currency = new ListCurrency(); + $currency->lookupCurrencies(); + $listitems = array(); + foreach ( $currency->list as $item ) + $listitems[$item->symbol] = $item->symbol; + return ''; + }else{ + + $currency = new Currency(); + if ( isset($focus->currency_id) ) { + $currency_id = $focus->currency_id; + } else { + $currency_id = -99; + } + $currency->retrieve($currency_id); + return $currency->name; + } +} + +?> diff --git a/modules/Currencies/EditCurrency.php b/modules/Currencies/EditCurrency.php new file mode 100644 index 00000000..81e2509a --- /dev/null +++ b/modules/Currencies/EditCurrency.php @@ -0,0 +1,54 @@ +is_admin){ +require_once('modules/Currencies/ListCurrency.php'); +$lc = new ListCurrency(); +$lc->handleDelete(); +$lc->handleAdd(); +$lc->handleUpdate(); +echo $lc->getTable(); + }else{ + echo 'Admin\'s Only'; + } + +?> \ No newline at end of file diff --git a/modules/Currencies/EditView.js b/modules/Currencies/EditView.js new file mode 100644 index 00000000..47092c8c --- /dev/null +++ b/modules/Currencies/EditView.js @@ -0,0 +1,38 @@ +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ +function isoUpdate(formElem){if(typeof(js_iso4217[formElem.value])=='undefined'){return false;} +var thisForm=formElem.form;var thisCurr=js_iso4217[formElem.value];if(thisForm.name.value==''){thisForm.name.value=thisCurr.name;} +if(thisForm.symbol.value==''){thisForm.symbol.value='';for(var i=0;i +js_iso4217 = {$JS_ISO4217}; + + + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + +
    {$MOD.LBL_LIST_NAME}: {$APP.LBL_REQUIRED_SYMBOL}{$MOD.LBL_LIST_ISO4217}: {sugar_help text=$MOD.LBL_LIST_ISO4217_HELP}
    {$MOD.LBL_LIST_RATE}: {$APP.LBL_REQUIRED_SYMBOL} + +{$MOD.LBL_LIST_SYMBOL}: {$APP.LBL_REQUIRED_SYMBOL}
    {$MOD.LBL_LIST_STATUS}: {$MOD.NTC_STATUS}
    +
    + + +{$JAVASCRIPT} diff --git a/modules/Currencies/Forms.php b/modules/Currencies/Forms.php new file mode 100644 index 00000000..4be184d6 --- /dev/null +++ b/modules/Currencies/Forms.php @@ -0,0 +1,66 @@ + \ No newline at end of file diff --git a/modules/Currencies/ListCurrency.php b/modules/Currencies/ListCurrency.php new file mode 100644 index 00000000..b8722d6b --- /dev/null +++ b/modules/Currencies/ListCurrency.php @@ -0,0 +1,244 @@ +'; + function lookupCurrencies(){ + + + $this->focus = new Currency(); + $this->list = $this->focus->get_full_list('name'); + $this->focus->retrieve('-99'); + if(is_array($this->list)){ + $this->list = array_merge(Array($this->focus), $this->list); + }else{ + $this->list = Array($this->focus); + } + + } + function handleAdd(){ + global $current_user; + if($current_user->is_admin){ + if(isset($_POST['edit']) && $_POST['edit'] == 'true' && isset($_POST['name']) && !empty($_POST['name']) && isset($_POST['conversion_rate']) && !empty($_POST['conversion_rate']) && isset($_POST['symbol']) && !empty($_POST['symbol'])){ + + $currency = new Currency(); + if(isset($_POST['record']) && !empty($_POST['record'])){ + + $currency->retrieve($_POST['record']); + } + $currency->name = $_POST['name']; + $currency->status = $_POST['status']; + $currency->symbol = $_POST['symbol']; + $currency->iso4217 = $_POST['iso4217']; + $currency->conversion_rate = unformat_number($_POST['conversion_rate']); + $currency->save(); + $this->focus = $currency; + } + } + + } + + function handleUpdate(){ + global $current_user; + if($current_user->is_admin){ + if(isset($_POST['id']) && !empty($_POST['id'])&&isset($_POST['name']) && !empty($_POST['name']) && isset($_POST['rate']) && !empty($_POST['rate']) && isset($_POST['symbol']) && !empty($_POST['symbol'])){ + $ids = $_POST['id']; + $names= $_POST['name']; + $symbols= $_POST['symbol']; + $rates = $_POST['rate']; + $isos = $_POST['iso']; + $size = sizeof($ids); + if($size != sizeof($names)|| $size != sizeof($isos) || $size != sizeof($symbols) || $size != sizeof($rates)){ + return; + } + + $temp = new Currency(); + for($i = 0; $i < $size; $i++){ + $temp->id = $ids[$i]; + $temp->name = $names[$i]; + $temp->symbol = $symbols[$i]; + $temp->iso4217 = $isos[$i]; + $temp->conversion_rate = $rates[$i]; + $temp->save(); + } + }} + } + + function getJavascript(){ + // wp: DO NOT add formatting and unformatting numbers in here, add them prior to calling these to avoid double calling + // of unformat number + return $this->javascript . <<
    +EOQ; + return $form; + + } + + function setCurrencyFields($fields){ + $json = getJSONobj(); + $this->javascript .= 'var currencyFields = ' . $json->encode($fields) . ";\n"; + } + + +} + +//$lc = new ListCurrency(); +//$lc->handleDelete(); +//$lc->handleAdd(); +//$lc->handleUpdate(); +//echo ''; +//echo $lc->getTable(); + +?> \ No newline at end of file diff --git a/modules/Currencies/ListView.html b/modules/Currencies/ListView.html new file mode 100644 index 00000000..a85d17da --- /dev/null +++ b/modules/Currencies/ListView.html @@ -0,0 +1,72 @@ + + + +{PRETABLE} + + + + + + + + + + + + + + + + + + + + + + + + + + +
    {CHECKALL}{MOD.LBL_LIST_NAME}{MOD.LBL_LIST_ISO4217}{MOD.LBL_LIST_SYMBOL}{MOD.LBL_LIST_RATE}{MOD.LBL_LIST_STATUS} 
    {PREROW} {CURRENCY.HIDE}{CURRENCY.UNHIDE}{CURRENCY.NAME}{CURRENCY.HIDE}{CURRENCY.UNHIDE}{CURRENCY.ISO4217}{CURRENCY.SYMBOL}{CURRENCY.CONVERSION_RATE}{CURRENCY.STATUS}{CURRENCY.HIDE}{DELETE_INLINE_PNG} {APP.LNK_DELETE}{CURRENCY.UNHIDE}
    + {POSTTABLE} + \ No newline at end of file diff --git a/modules/Currencies/Menu.php b/modules/Currencies/Menu.php new file mode 100644 index 00000000..ea2c942f --- /dev/null +++ b/modules/Currencies/Menu.php @@ -0,0 +1,50 @@ + \ No newline at end of file diff --git a/modules/Currencies/field_arrays.php b/modules/Currencies/field_arrays.php new file mode 100644 index 00000000..373d7c7c --- /dev/null +++ b/modules/Currencies/field_arrays.php @@ -0,0 +1,57 @@ + Array("id" + ,"name" + ,"conversion_rate" + ,"iso4217" + ,"symbol" + ,'status' + ,"deleted" + ,"date_entered" + ,"date_modified" + ), + 'required_fields' => array('name'=>1, 'symbol'=>2, 'conversion_rate'=>3, 'iso4217'=>4 , 'status'=>5), +); +?> \ No newline at end of file diff --git a/modules/Currencies/index.php b/modules/Currencies/index.php new file mode 100644 index 00000000..ec6f55e4 --- /dev/null +++ b/modules/Currencies/index.php @@ -0,0 +1,189 @@ +".translate('LBL_MODULE_NAME','Administration')."", + $mod_strings['LBL_MODULE_NAME'], + ), + false + ); + +if($current_user->is_admin){ +require_once('modules/Currencies/ListCurrency.php'); + +$focus = new Currency(); +$lc = new ListCurrency(); +$lc->handleAdd(); + +if(isset($_REQUEST['merge']) && $_REQUEST['merge'] == 'true'){ + $isMerge = true; + +} +if(isset($_REQUEST['domerge'])){ + $currencies = $_REQUEST['mergecur']; + + + $opp = new Opportunity(); + $opp->update_currency_id($currencies, $_REQUEST['mergeTo'] ); + foreach($currencies as $cur){ + if($cur != $_REQUEST['mergeTo']) + $focus->mark_deleted($cur); + } +} +$lc->lookupCurrencies(); +if (isset($focus->id)) $focus_id = $focus->id; +else $focus_id=''; +$merge_button = ''; +$pretable = ''; +if((isset($_REQUEST['doAction']) && $_REQUEST['doAction'] == 'merge') || (isset($isMerge) && !$isMerge)){ +$merge_button = '
    '; +} +if(isset($isMerge) && $isMerge){ + $currencyList = new ListCurrency(); + $listoptions = $currencyList->getSelectOptions(); + $pretable = << + + + + +
    + + + +
    {$mod_strings['LBL_MERGE_TXT']}
    +

    +EOQ; + + +} +$edit_botton = '
    '; + $edit_botton .= ''; + $edit_botton .= ''; + $edit_botton .= ''; + $edit_botton .= ''; + $edit_botton .= ''; + $edit_botton .= ''; + $edit_botton .= ''; + $edit_botton .= ' '; + $edit_botton .= ' '; +$header_text = ''; +if(is_admin($current_user) && $_REQUEST['module'] != 'DynamicLayout' && !empty($_SESSION['editinplace'])){ + $header_text = " ".SugarThemeRegistry::current()->getImage("EditLayout","border='0' alt='Edit Layout' align='bottom'").""; + } +$ListView = new ListView(); +$ListView->initNewXTemplate( 'modules/Currencies/ListView.html',$mod_strings); +$ListView->xTemplateAssign('PRETABLE', $pretable); +$ListView->xTemplateAssign('POSTTABLE', '
    '); +$ListView->xTemplateAssign("DELETE_INLINE_PNG", SugarThemeRegistry::current()->getImage('delete_inline','align="absmiddle" alt="'.$app_strings['LNK_DELETE'].'" border="0"')); +//$ListView->setHeaderTitle($mod_strings['LBL_LIST_FORM_TITLE']. $header_text ); +$ListView->setHeaderText($merge_button); + +$ListView->processListView($lc->list, "main", "CURRENCY"); + +if(isset($_GET['record']) && !empty($_GET['record']) && !isset($_POST['edit'])) { + $focus->retrieve($_GET['record']); + $focus->conversion_rate = format_number($focus->conversion_rate, 10, 10); +} +if(is_admin($current_user) && $_REQUEST['module'] != 'DynamicLayout' && !empty($_SESSION['editinplace'])){ + $header_text = " ".SugarThemeRegistry::current()->getImage("EditLayout","border='0' alt='Edit Layout' align='bottom'").""; +} +if ( empty($focus->id) ) { + echo get_form_header($app_strings['LBL_CREATE_BUTTON_LABEL'] . $header_text,$edit_botton , false); +} +else { + echo get_form_header($app_strings['LBL_EDIT_BUTTON_LABEL']." » ".$focus->name . $header_text,$edit_botton , false); +} +$sugar_smarty = new Sugar_Smarty(); + + $sugar_smarty->assign("MOD", $mod_strings); + $sugar_smarty->assign("APP", $app_strings); + +// Load in the full ISO 4217 list, so we can dynamically populate the currency strings + require_once('modules/Currencies/iso4217.php'); + $json = getJSONobj(); + $js_iso4217 = $json->encode($fullIsoList); + $sugar_smarty->assign('JS_ISO4217',$js_iso4217); + + if (isset($_REQUEST['return_module'])) $sugar_smarty->assign("RETURN_MODULE", $_REQUEST['return_module']); + if (isset($_REQUEST['return_action'])) $sugar_smarty->assign("RETURN_ACTION", $_REQUEST['return_action']); + if (isset($_REQUEST['return_id'])) $sugar_smarty->assign("RETURN_ID", $_REQUEST['return_id']); + + $sugar_smarty->assign("PRINT_URL", "index.php?".$GLOBALS['request_string']); + $sugar_smarty->assign("JAVASCRIPT", get_set_focus_js()); + $sugar_smarty->assign("THEME", SugarThemeRegistry::current()->__toString()); + $sugar_smarty->assign("ID", $focus->id); + $sugar_smarty->assign('NAME', $focus->name); + $sugar_smarty->assign('STATUS', $focus->status); + $sugar_smarty->assign('ISO4217', $focus->iso4217); + $sugar_smarty->assign('CONVERSION_RATE', $focus->conversion_rate); + $sugar_smarty->assign('SYMBOL', $focus->symbol); + $sugar_smarty->assign('STATUS_OPTIONS', get_select_options_with_id($mod_strings['currency_status_dom'], $focus->status)); + + //if (empty($focus->list_order)) $xtpl->assign('LIST_ORDER', count($focus->get_manufacturers(false,'All'))+1); + //else $xtpl->assign('LIST_ORDER', $focus->list_order); + + $sugar_smarty->display("modules/Currencies/EditView.tpl"); + + $javascript = new javascript(); + $javascript->setFormName('EditView'); + $javascript->setSugarBean($focus); + $javascript->addAllFields('',array('iso4217'=>'iso4217')); + echo $javascript->getScript(); + echo(""); + }else{ + echo 'Admin\'s Only'; + } + +?> \ No newline at end of file diff --git a/modules/Currencies/iso4217.php b/modules/Currencies/iso4217.php new file mode 100644 index 00000000..7740b6a7 --- /dev/null +++ b/modules/Currencies/iso4217.php @@ -0,0 +1,1850 @@ + + array ( + 'full_name' => 'Albania, Leke', + 'name' => 'Leke', + 'code' => 'ALL', + 'symbol' => 'Lek', + 'unicode' => + array ( + 0 => '76', + 1 => ' 101', + 2 => ' 107', + ), + 'unihex' => + array ( + 0 => '4c', + 1 => ' 65', + 2 => ' 6b', + ), + ), + 'USD' => + array ( + 'full_name' => 'US Dollars', + 'name' => 'Dollars', + 'code' => 'USD', + 'symbol' => '$', + 'unicode' => + array ( + 0 => '36', + ), + 'unihex' => + array ( + 0 => '24', + ), + ), + 'AFN' => + array ( + 'full_name' => 'Afghanistan, Afghanis', + 'name' => 'Afghanis', + 'code' => 'AFN', + 'symbol' => '؋', + 'unicode' => + array ( + 0 => '1547', + ), + 'unihex' => + array ( + 0 => '60b', + ), + ), + 'ARS' => + array ( + 'full_name' => 'Argentina, Pesos', + 'name' => 'Pesos', + 'code' => 'ARS', + 'symbol' => '$', + 'unicode' => + array ( + 0 => '36', + ), + 'unihex' => + array ( + 0 => '24', + ), + ), + 'AWG' => + array ( + 'full_name' => 'Aruba, Guilders', + 'name' => 'Guilders', + 'code' => 'AWG', + 'symbol' => 'ƒ', + 'unicode' => + array ( + 0 => '402', + ), + 'unihex' => + array ( + 0 => '192', + ), + ), + 'AUD' => + array ( + 'full_name' => 'Australia, Dollars', + 'name' => 'Dollars', + 'code' => 'AUD', + 'symbol' => '$', + 'unicode' => + array ( + 0 => '36', + ), + 'unihex' => + array ( + 0 => '24', + ), + ), + 'AZN' => + array ( + 'full_name' => 'Azerbaijan, New Manats', + 'name' => 'New Manats', + 'code' => 'AZN', + 'symbol' => 'aман', + 'unicode' => + array ( + 0 => '1084', + 1 => ' 1072', + 2 => ' 1085', + ), + 'unihex' => + array ( + 0 => '43c', + 1 => ' 430', + 2 => ' 43d', + ), + ), + 'BSD' => + array ( + 'full_name' => 'Bahamas, Dollars', + 'name' => 'Dollars', + 'code' => 'BSD', + 'symbol' => '$', + 'unicode' => + array ( + 0 => '36', + ), + 'unihex' => + array ( + 0 => '24', + ), + ), + 'BBD' => + array ( + 'full_name' => 'Barbados, Dollars', + 'name' => 'Dollars', + 'code' => 'BBD', + 'symbol' => '$', + 'unicode' => + array ( + 0 => '36', + ), + 'unihex' => + array ( + 0 => '24', + ), + ), + 'BYR' => + array ( + 'full_name' => 'Belarus, Rubles', + 'name' => 'Rubles', + 'code' => 'BYR', + 'symbol' => 'p.', + 'unicode' => + array ( + 0 => '112', + 1 => ' 46', + ), + 'unihex' => + array ( + 0 => '70', + 1 => ' 2e', + ), + ), + 'EUR' => + array ( + 'full_name' => 'Belgium, Euro', + 'name' => 'Euro', + 'code' => 'EUR', + 'symbol' => '€', + 'unicode' => + array ( + 0 => '8364', + ), + 'unihex' => + array ( + 0 => '20ac', + ), + ), + 'BZD' => + array ( + 'full_name' => 'Belize, Dollars', + 'name' => 'Dollars', + 'code' => 'BZD', + 'symbol' => 'BZ$', + 'unicode' => + array ( + 0 => '66', + 1 => ' 90', + 2 => ' 36', + ), + 'unihex' => + array ( + 0 => '42', + 1 => ' 5a', + 2 => ' 24', + ), + ), + 'BMD' => + array ( + 'full_name' => 'Bermuda, Dollars', + 'name' => 'Dollars', + 'code' => 'BMD', + 'symbol' => '$', + 'unicode' => + array ( + 0 => '36', + ), + 'unihex' => + array ( + 0 => '24', + ), + ), + 'BOB' => + array ( + 'full_name' => 'Bolivia, Bolivianos', + 'name' => 'Bolivianos', + 'code' => 'BOB', + 'symbol' => '$b', + 'unicode' => + array ( + 0 => '36', + 1 => ' 98', + ), + 'unihex' => + array ( + 0 => '24', + 1 => ' 62', + ), + ), + 'BAM' => + array ( + 'full_name' => 'Bosnia and Herzegovina, Convertible Marka', + 'name' => 'Convertible Marka', + 'code' => 'BAM', + 'symbol' => 'KM', + 'unicode' => + array ( + 0 => '75', + 1 => ' 77', + ), + 'unihex' => + array ( + 0 => '4b', + 1 => ' 4d', + ), + ), + 'BWP' => + array ( + 'full_name' => 'Botswana, Pulas', + 'name' => 'Pulas', + 'code' => 'BWP', + 'symbol' => 'P', + 'unicode' => + array ( + 0 => '80', + ), + 'unihex' => + array ( + 0 => '50', + ), + ), + 'BGN' => + array ( + 'full_name' => 'Bulgaria, Leva', + 'name' => 'Leva', + 'code' => 'BGN', + 'symbol' => 'лв', + 'unicode' => + array ( + 0 => '1083', + 1 => ' 1074', + ), + 'unihex' => + array ( + 0 => '43b', + 1 => ' 432', + ), + ), + 'BRL' => + array ( + 'full_name' => 'Brazil, Reais', + 'name' => 'Reais', + 'code' => 'BRL', + 'symbol' => 'R$', + 'unicode' => + array ( + 0 => '82', + 1 => ' 36', + ), + 'unihex' => + array ( + 0 => '52', + 1 => ' 24', + ), + ), + 'GBP' => + array ( + 'full_name' => 'British Pounds', + 'name' => 'Pounds', + 'code' => 'GBP', + 'symbol' => '£', + 'unicode' => + array ( + 0 => '163', + ), + 'unihex' => + array ( + 0 => 'a3', + ), + ), + 'BND' => + array ( + 'full_name' => 'Brunei Darussalam, Dollars', + 'name' => 'Dollars', + 'code' => 'BND', + 'symbol' => '$', + 'unicode' => + array ( + 0 => '36', + ), + 'unihex' => + array ( + 0 => '24', + ), + ), + 'KHR' => + array ( + 'full_name' => 'Cambodia, Riels', + 'name' => 'Riels', + 'code' => 'KHR', + 'symbol' => '៛', + 'unicode' => + array ( + 0 => '6107', + ), + 'unihex' => + array ( + 0 => '17db', + ), + ), + 'CAD' => + array ( + 'full_name' => 'Canada, Dollars', + 'name' => 'Dollars', + 'code' => 'CAD', + 'symbol' => '$', + 'unicode' => + array ( + 0 => '36', + ), + 'unihex' => + array ( + 0 => '24', + ), + ), + 'KYD' => + array ( + 'full_name' => 'Cayman Islands, Dollars', + 'name' => 'Dollars', + 'code' => 'KYD', + 'symbol' => '$', + 'unicode' => + array ( + 0 => '36', + ), + 'unihex' => + array ( + 0 => '24', + ), + ), + 'CLP' => + array ( + 'full_name' => 'Chile, Pesos', + 'name' => 'Pesos', + 'code' => 'CLP', + 'symbol' => '$', + 'unicode' => + array ( + 0 => '36', + ), + 'unihex' => + array ( + 0 => '24', + ), + ), + 'CNY' => + array ( + 'full_name' => 'China, Yuan Renminbi', + 'name' => 'Yuan Renminbi', + 'code' => 'CNY', + 'symbol' => 'Â¥', + 'unicode' => + array ( + 0 => '165', + ), + 'unihex' => + array ( + 0 => 'a5', + ), + ), + 'COP' => + array ( + 'full_name' => 'Colombia, Pesos', + 'name' => 'Pesos', + 'code' => 'COP', + 'symbol' => '$', + 'unicode' => + array ( + 0 => '36', + ), + 'unihex' => + array ( + 0 => '24', + ), + ), + 'CRC' => + array ( + 'full_name' => 'Costa Rica, Colón', + 'name' => 'Colón', + 'code' => 'CRC', + 'symbol' => '₡', + 'unicode' => + array ( + 0 => '8353', + ), + 'unihex' => + array ( + 0 => '20a1', + ), + ), + 'HRK' => + array ( + 'full_name' => 'Croatia, Kuna', + 'name' => 'Kuna', + 'code' => 'HRK', + 'symbol' => 'kn', + 'unicode' => + array ( + 0 => '107', + 1 => ' 110', + ), + 'unihex' => + array ( + 0 => '6b', + 1 => ' 6e', + ), + ), + 'CUP' => + array ( + 'full_name' => 'Cuba, Pesos', + 'name' => 'Pesos', + 'code' => 'CUP', + 'symbol' => '₱', + 'unicode' => + array ( + 0 => '8369', + ), + 'unihex' => + array ( + 0 => '20b1', + ), + ), + 'CZK' => + array ( + 'full_name' => 'Czech Republic, Koruny', + 'name' => 'Koruny', + 'code' => 'CZK', + 'symbol' => 'Kč', + 'unicode' => + array ( + 0 => '75', + 1 => ' 269', + ), + 'unihex' => + array ( + 0 => '4b', + 1 => ' 10d', + ), + ), + 'DKK' => + array ( + 'full_name' => 'Denmark, Kroner', + 'name' => 'Kroner', + 'code' => 'DKK', + 'symbol' => 'kr', + 'unicode' => + array ( + 0 => '107', + 1 => ' 114', + ), + 'unihex' => + array ( + 0 => '6b', + 1 => ' 72', + ), + ), + 'DOP' => + array ( + 'full_name' => 'Dominican Republic, Pesos', + 'name' => 'Pesos', + 'code' => 'DOP', + 'symbol' => 'RD$', + 'unicode' => + array ( + 0 => '82', + 1 => ' 68', + 2 => ' 36', + ), + 'unihex' => + array ( + 0 => '52', + 1 => ' 44', + 2 => ' 24', + ), + ), + 'XCD' => + array ( + 'full_name' => 'East Caribbean, Dollars', + 'name' => 'Dollars', + 'code' => 'XCD', + 'symbol' => '$', + 'unicode' => + array ( + 0 => '36', + ), + 'unihex' => + array ( + 0 => '24', + ), + ), + 'EGP' => + array ( + 'full_name' => 'Egypt, Pounds', + 'name' => 'Pounds', + 'code' => 'EGP', + 'symbol' => '£', + 'unicode' => + array ( + 0 => '163', + ), + 'unihex' => + array ( + 0 => 'a3', + ), + ), + 'SVC' => + array ( + 'full_name' => 'El Salvador, Colones', + 'name' => 'Colones', + 'code' => 'SVC', + 'symbol' => '$', + 'unicode' => + array ( + 0 => '36', + ), + 'unihex' => + array ( + 0 => '24', + ), + ), + 'EEK' => + array ( + 'full_name' => 'Estonia, Krooni', + 'name' => 'Krooni', + 'code' => 'EEK', + 'symbol' => 'kr', + 'unicode' => + array ( + 0 => '107', + 1 => ' 114', + ), + 'unihex' => + array ( + 0 => '6b', + 1 => ' 72', + ), + ), + 'FKP' => + array ( + 'full_name' => 'Falkland Islands, Pounds', + 'name' => 'Pounds', + 'code' => 'FKP', + 'symbol' => '£', + 'unicode' => + array ( + 0 => '163', + ), + 'unihex' => + array ( + 0 => 'a3', + ), + ), + 'FJD' => + array ( + 'full_name' => 'Fiji, Dollars', + 'name' => 'Dollars', + 'code' => 'FJD', + 'symbol' => '$', + 'unicode' => + array ( + 0 => '36', + ), + 'unihex' => + array ( + 0 => '24', + ), + ), + 'GHC' => + array ( + 'full_name' => 'Ghana, Cedis', + 'name' => 'Cedis', + 'code' => 'GHC', + 'symbol' => '¢', + 'unicode' => + array ( + 0 => '162', + ), + 'unihex' => + array ( + 0 => 'a2', + ), + ), + 'GIP' => + array ( + 'full_name' => 'Gibraltar, Pounds', + 'name' => 'Pounds', + 'code' => 'GIP', + 'symbol' => '£', + 'unicode' => + array ( + 0 => '163', + ), + 'unihex' => + array ( + 0 => 'a3', + ), + ), + 'GTQ' => + array ( + 'full_name' => 'Guatemala, Quetzales', + 'name' => 'Quetzales', + 'code' => 'GTQ', + 'symbol' => 'Q', + 'unicode' => + array ( + 0 => '81', + ), + 'unihex' => + array ( + 0 => '51', + ), + ), + 'GGP' => + array ( + 'full_name' => 'Guernsey, Pounds', + 'name' => 'Pounds', + 'code' => 'GGP', + 'symbol' => '£', + 'unicode' => + array ( + 0 => '163', + ), + 'unihex' => + array ( + 0 => 'a3', + ), + ), + 'GYD' => + array ( + 'full_name' => 'Guyana, Dollars', + 'name' => 'Dollars', + 'code' => 'GYD', + 'symbol' => '$', + 'unicode' => + array ( + 0 => '36', + ), + 'unihex' => + array ( + 0 => '24', + ), + ), + 'HNL' => + array ( + 'full_name' => 'Honduras, Lempiras', + 'name' => 'Lempiras', + 'code' => 'HNL', + 'symbol' => 'L', + 'unicode' => + array ( + 0 => '76', + ), + 'unihex' => + array ( + 0 => '4c', + ), + ), + 'HKD' => + array ( + 'full_name' => 'Hong Kong, Dollars', + 'name' => 'Dollars', + 'code' => 'HKD', + 'symbol' => '$', + 'unicode' => + array ( + 0 => '36', + ), + 'unihex' => + array ( + 0 => '24', + ), + ), + 'HUF' => + array ( + 'full_name' => 'Hungary, Forint', + 'name' => 'Forint', + 'code' => 'HUF', + 'symbol' => 'Ft', + 'unicode' => + array ( + 0 => '70', + 1 => ' 116', + ), + 'unihex' => + array ( + 0 => '46', + 1 => ' 74', + ), + ), + 'ISK' => + array ( + 'full_name' => 'Iceland, Kronur', + 'name' => 'Kronur', + 'code' => 'ISK', + 'symbol' => 'kr', + 'unicode' => + array ( + 0 => '107', + 1 => ' 114', + ), + 'unihex' => + array ( + 0 => '6b', + 1 => ' 72', + ), + ), + 'INR' => + array ( + 'full_name' => 'India, Rupees', + 'name' => 'Rupees', + 'code' => 'INR', + 'symbol' => '₨', + 'unicode' => + array ( + 0 => '8360', + ), + 'unihex' => + array ( + 0 => '20a8', + ), + ), + 'IDR' => + array ( + 'full_name' => 'Indonesia, Rupiahs', + 'name' => 'Rupiahs', + 'code' => 'IDR', + 'symbol' => 'Rp', + 'unicode' => + array ( + 0 => '82', + 1 => ' 112', + ), + 'unihex' => + array ( + 0 => '52', + 1 => ' 70', + ), + ), + 'IRR' => + array ( + 'full_name' => 'Iran, Rials', + 'name' => 'Rials', + 'code' => 'IRR', + 'symbol' => 'ï·¼', + 'unicode' => + array ( + 0 => '65020', + ), + 'unihex' => + array ( + 0 => 'fdfc', + ), + ), + 'IMP' => + array ( + 'full_name' => 'Isle of Man, Pounds', + 'name' => 'Pounds', + 'code' => 'IMP', + 'symbol' => '£', + 'unicode' => + array ( + 0 => '163', + ), + 'unihex' => + array ( + 0 => 'a3', + ), + ), + 'ILS' => + array ( + 'full_name' => 'Israel, New Shekels', + 'name' => 'New Shekels', + 'code' => 'ILS', + 'symbol' => '₪', + 'unicode' => + array ( + 0 => '8362', + ), + 'unihex' => + array ( + 0 => '20aa', + ), + ), + 'JMD' => + array ( + 'full_name' => 'Jamaica, Dollars', + 'name' => 'Dollars', + 'code' => 'JMD', + 'symbol' => 'J$', + 'unicode' => + array ( + 0 => '74', + 1 => ' 36', + ), + 'unihex' => + array ( + 0 => '4a', + 1 => ' 24', + ), + ), + 'JPY' => + array ( + 'full_name' => 'Japan, Yen', + 'name' => 'Yen', + 'code' => 'JPY', + 'symbol' => 'Â¥', + 'unicode' => + array ( + 0 => '165', + ), + 'unihex' => + array ( + 0 => 'a5', + ), + ), + 'JEP' => + array ( + 'full_name' => 'Jersey, Pounds', + 'name' => 'Pounds', + 'code' => 'JEP', + 'symbol' => '£', + 'unicode' => + array ( + 0 => '163', + ), + 'unihex' => + array ( + 0 => 'a3', + ), + ), + 'KZT' => + array ( + 'full_name' => 'Kazakhstan, Tenge', + 'name' => 'Tenge', + 'code' => 'KZT', + 'symbol' => 'лв', + 'unicode' => + array ( + 0 => '1083', + 1 => ' 1074', + ), + 'unihex' => + array ( + 0 => '43b', + 1 => ' 432', + ), + ), + 'KPW' => + array ( + 'full_name' => 'Korea (North), Won', + 'name' => 'Won', + 'code' => 'KPW', + 'symbol' => '₩', + 'unicode' => + array ( + 0 => '8361', + ), + 'unihex' => + array ( + 0 => '20a9', + ), + ), + 'KRW' => + array ( + 'full_name' => 'Korea (South), Won', + 'name' => 'Won', + 'code' => 'KRW', + 'symbol' => '₩', + 'unicode' => + array ( + 0 => '8361', + ), + 'unihex' => + array ( + 0 => '20a9', + ), + ), + 'KGS' => + array ( + 'full_name' => 'Kyrgyzstan, Soms', + 'name' => 'Soms', + 'code' => 'KGS', + 'symbol' => 'лв', + 'unicode' => + array ( + 0 => '1083', + 1 => ' 1074', + ), + 'unihex' => + array ( + 0 => '43b', + 1 => ' 432', + ), + ), + 'LAK' => + array ( + 'full_name' => 'Laos, Kips', + 'name' => 'Kips', + 'code' => 'LAK', + 'symbol' => '₭', + 'unicode' => + array ( + 0 => '8365', + ), + 'unihex' => + array ( + 0 => '20ad', + ), + ), + 'LVL' => + array ( + 'full_name' => 'Latvia, Lati', + 'name' => 'Lati', + 'code' => 'LVL', + 'symbol' => 'Ls', + 'unicode' => + array ( + 0 => '76', + 1 => ' 115', + ), + 'unihex' => + array ( + 0 => '4c', + 1 => ' 73', + ), + ), + 'LBP' => + array ( + 'full_name' => 'Lebanon, Pounds', + 'name' => 'Pounds', + 'code' => 'LBP', + 'symbol' => '£', + 'unicode' => + array ( + 0 => '163', + ), + 'unihex' => + array ( + 0 => 'a3', + ), + ), + 'LRD' => + array ( + 'full_name' => 'Liberia, Dollars', + 'name' => 'Dollars', + 'code' => 'LRD', + 'symbol' => '$', + 'unicode' => + array ( + 0 => '36', + ), + 'unihex' => + array ( + 0 => '24', + ), + ), + 'CHF' => + array ( + 'full_name' => 'Liechtenstein, Switzerland Francs', + 'name' => 'Switzerland Francs', + 'code' => 'CHF', + 'symbol' => 'CHF', + 'unicode' => + array ( + 0 => '67', + 1 => ' 72', + 2 => ' 70', + ), + 'unihex' => + array ( + 0 => '43', + 1 => ' 48', + 2 => ' 46', + ), + ), + 'LTL' => + array ( + 'full_name' => 'Lithuania, Litai', + 'name' => 'Litai', + 'code' => 'LTL', + 'symbol' => 'Lt', + 'unicode' => + array ( + 0 => '76', + 1 => ' 116', + ), + 'unihex' => + array ( + 0 => '4c', + 1 => ' 74', + ), + ), + 'MKD' => + array ( + 'full_name' => 'Macedonia, Denars', + 'name' => 'Denars', + 'code' => 'MKD', + 'symbol' => 'ден', + 'unicode' => + array ( + 0 => '1076', + 1 => ' 1077', + 2 => ' 1085', + ), + 'unihex' => + array ( + 0 => '434', + 1 => ' 435', + 2 => ' 43d', + ), + ), + 'MYR' => + array ( + 'full_name' => 'Malaysia, Ringgits', + 'name' => 'Ringgits', + 'code' => 'MYR', + 'symbol' => 'RM', + 'unicode' => + array ( + 0 => '82', + 1 => ' 77', + ), + 'unihex' => + array ( + 0 => '52', + 1 => ' 4d', + ), + ), + 'MUR' => + array ( + 'full_name' => 'Mauritius, Rupees', + 'name' => 'Rupees', + 'code' => 'MUR', + 'symbol' => '₨', + 'unicode' => + array ( + 0 => '8360', + ), + 'unihex' => + array ( + 0 => '20a8', + ), + ), + 'MXN' => + array ( + 'full_name' => 'Mexico, Pesos', + 'name' => 'Pesos', + 'code' => 'MXN', + 'symbol' => '$', + 'unicode' => + array ( + 0 => '36', + ), + 'unihex' => + array ( + 0 => '24', + ), + ), + 'MNT' => + array ( + 'full_name' => 'Mongolia, Tugriks', + 'name' => 'Tugriks', + 'code' => 'MNT', + 'symbol' => '₮', + 'unicode' => + array ( + 0 => '8366', + ), + 'unihex' => + array ( + 0 => '20ae', + ), + ), + 'MZN' => + array ( + 'full_name' => 'Mozambique, Meticais', + 'name' => 'Meticais', + 'code' => 'MZN', + 'symbol' => 'MT', + 'unicode' => + array ( + 0 => '77', + 1 => ' 84', + ), + 'unihex' => + array ( + 0 => '4d', + 1 => ' 54', + ), + ), + 'NAD' => + array ( + 'full_name' => 'Namibia, Dollars', + 'name' => 'Dollars', + 'code' => 'NAD', + 'symbol' => '$', + 'unicode' => + array ( + 0 => '36', + ), + 'unihex' => + array ( + 0 => '24', + ), + ), + 'NPR' => + array ( + 'full_name' => 'Nepal, Rupees', + 'name' => 'Rupees', + 'code' => 'NPR', + 'symbol' => '₨', + 'unicode' => + array ( + 0 => '8360', + ), + 'unihex' => + array ( + 0 => '20a8', + ), + ), + 'ANG' => + array ( + 'full_name' => 'Netherlands Antilles, Guilders', + 'name' => 'Guilders', + 'code' => 'ANG', + 'symbol' => 'ƒ', + 'unicode' => + array ( + 0 => '402', + ), + 'unihex' => + array ( + 0 => '192', + ), + ), + 'NZD' => + array ( + 'full_name' => 'New Zealand, Dollars', + 'name' => 'Dollars', + 'code' => 'NZD', + 'symbol' => '$', + 'unicode' => + array ( + 0 => '36', + ), + 'unihex' => + array ( + 0 => '24', + ), + ), + 'NIO' => + array ( + 'full_name' => 'Nicaragua, Cordobas', + 'name' => 'Cordobas', + 'code' => 'NIO', + 'symbol' => 'C$', + 'unicode' => + array ( + 0 => '67', + 1 => ' 36', + ), + 'unihex' => + array ( + 0 => '43', + 1 => ' 24', + ), + ), + 'NGN' => + array ( + 'full_name' => 'Nigeria, Nairas', + 'name' => 'Nairas', + 'code' => 'NGN', + 'symbol' => '₦', + 'unicode' => + array ( + 0 => '8358', + ), + 'unihex' => + array ( + 0 => '20a6', + ), + ), + 'NOK' => + array ( + 'full_name' => 'Norway, Krone', + 'name' => 'Krone', + 'code' => 'NOK', + 'symbol' => 'kr', + 'unicode' => + array ( + 0 => '107', + 1 => ' 114', + ), + 'unihex' => + array ( + 0 => '6b', + 1 => ' 72', + ), + ), + 'OMR' => + array ( + 'full_name' => 'Oman, Rials', + 'name' => 'Rials', + 'code' => 'OMR', + 'symbol' => 'ï·¼', + 'unicode' => + array ( + 0 => '65020', + ), + 'unihex' => + array ( + 0 => 'fdfc', + ), + ), + 'PKR' => + array ( + 'full_name' => 'Pakistan, Rupees', + 'name' => 'Rupees', + 'code' => 'PKR', + 'symbol' => '₨', + 'unicode' => + array ( + 0 => '8360', + ), + 'unihex' => + array ( + 0 => '20a8', + ), + ), + 'PAB' => + array ( + 'full_name' => 'Panama, Balboa', + 'name' => 'Balboa', + 'code' => 'PAB', + 'symbol' => 'B/.', + 'unicode' => + array ( + 0 => '66', + 1 => ' 47', + 2 => ' 46', + ), + 'unihex' => + array ( + 0 => '42', + 1 => ' 2f', + 2 => ' 2e', + ), + ), + 'PYG' => + array ( + 'full_name' => 'Paraguay, Guarani', + 'name' => 'Guarani', + 'code' => 'PYG', + 'symbol' => 'Gs', + 'unicode' => + array ( + 0 => '71', + 1 => ' 115', + ), + 'unihex' => + array ( + 0 => '47', + 1 => ' 73', + ), + ), + 'PEN' => + array ( + 'full_name' => 'Peru, Nuevos Soles', + 'name' => 'Nuevos Soles', + 'code' => 'PEN', + 'symbol' => 'S/.', + 'unicode' => + array ( + 0 => '83', + 1 => ' 47', + 2 => ' 46', + ), + 'unihex' => + array ( + 0 => '53', + 1 => ' 2f', + 2 => ' 2e', + ), + ), + 'PHP' => + array ( + 'full_name' => 'Philippines, Pesos', + 'name' => 'Pesos', + 'code' => 'PHP', + 'symbol' => 'Php', + 'unicode' => + array ( + 0 => '80', + 1 => ' 104', + 2 => ' 112', + ), + 'unihex' => + array ( + 0 => '50', + 1 => ' 68', + 2 => ' 70', + ), + ), + 'PLN' => + array ( + 'full_name' => 'Poland, Zlotych', + 'name' => 'Zlotych', + 'code' => 'PLN', + 'symbol' => 'zł', + 'unicode' => + array ( + 0 => '122', + 1 => ' 322', + ), + 'unihex' => + array ( + 0 => '7a', + 1 => ' 142', + ), + ), + 'QAR' => + array ( + 'full_name' => 'Qatar, Rials', + 'name' => 'Rials', + 'code' => 'QAR', + 'symbol' => 'ï·¼', + 'unicode' => + array ( + 0 => '65020', + ), + 'unihex' => + array ( + 0 => 'fdfc', + ), + ), + 'RON' => + array ( + 'full_name' => 'Romania, New Lei', + 'name' => 'New Lei', + 'code' => 'RON', + 'symbol' => 'lei', + 'unicode' => + array ( + 0 => '108', + 1 => ' 101', + 2 => ' 105', + ), + 'unihex' => + array ( + 0 => '6c', + 1 => ' 65', + 2 => ' 69', + ), + ), + 'RUB' => + array ( + 'full_name' => 'Russia, Rubles', + 'name' => 'Rubles', + 'code' => 'RUB', + 'symbol' => 'руб', + 'unicode' => + array ( + 0 => '1088', + 1 => ' 1091', + 2 => ' 1073', + ), + 'unihex' => + array ( + 0 => '440', + 1 => ' 443', + 2 => ' 431', + ), + ), + 'SHP' => + array ( + 'full_name' => 'Saint Helena, Pounds', + 'name' => 'Pounds', + 'code' => 'SHP', + 'symbol' => '£', + 'unicode' => + array ( + 0 => '163', + ), + 'unihex' => + array ( + 0 => 'a3', + ), + ), + 'SAR' => + array ( + 'full_name' => 'Saudi Arabia, Riyals', + 'name' => 'Riyals', + 'code' => 'SAR', + 'symbol' => 'ï·¼', + 'unicode' => + array ( + 0 => '65020', + ), + 'unihex' => + array ( + 0 => 'fdfc', + ), + ), + 'RSD' => + array ( + 'full_name' => 'Serbia, Dinars', + 'name' => 'Dinars', + 'code' => 'RSD', + 'symbol' => 'Дин.', + 'unicode' => + array ( + 0 => '1044', + 1 => ' 1080', + 2 => ' 1085', + 3 => ' 46', + ), + 'unihex' => + array ( + 0 => '414', + 1 => ' 438', + 2 => ' 43d', + 3 => ' 2e', + ), + ), + 'SCR' => + array ( + 'full_name' => 'Seychelles, Rupees', + 'name' => 'Rupees', + 'code' => 'SCR', + 'symbol' => '₨', + 'unicode' => + array ( + 0 => '8360', + ), + 'unihex' => + array ( + 0 => '20a8', + ), + ), + 'SGD' => + array ( + 'full_name' => 'Singapore, Dollars', + 'name' => 'Dollars', + 'code' => 'SGD', + 'symbol' => '$', + 'unicode' => + array ( + 0 => '36', + ), + 'unihex' => + array ( + 0 => '24', + ), + ), + 'SBD' => + array ( + 'full_name' => 'Solomon Islands, Dollars', + 'name' => 'Dollars', + 'code' => 'SBD', + 'symbol' => '$', + 'unicode' => + array ( + 0 => '36', + ), + 'unihex' => + array ( + 0 => '24', + ), + ), + 'SOS' => + array ( + 'full_name' => 'Somalia, Shillings', + 'name' => 'Shillings', + 'code' => 'SOS', + 'symbol' => 'S', + 'unicode' => + array ( + 0 => '83', + ), + 'unihex' => + array ( + 0 => '53', + ), + ), + 'ZAR' => + array ( + 'full_name' => 'South Africa, Rand', + 'name' => 'Rand', + 'code' => 'ZAR', + 'symbol' => 'R', + 'unicode' => + array ( + 0 => '82', + ), + 'unihex' => + array ( + 0 => '52', + ), + ), + 'LKR' => + array ( + 'full_name' => 'Sri Lanka, Rupees', + 'name' => 'Rupees', + 'code' => 'LKR', + 'symbol' => '₨', + 'unicode' => + array ( + 0 => '8360', + ), + 'unihex' => + array ( + 0 => '20a8', + ), + ), + 'SEK' => + array ( + 'full_name' => 'Sweden, Kronor', + 'name' => 'Kronor', + 'code' => 'SEK', + 'symbol' => 'kr', + 'unicode' => + array ( + 0 => '107', + 1 => ' 114', + ), + 'unihex' => + array ( + 0 => '6b', + 1 => ' 72', + ), + ), + 'SRD' => + array ( + 'full_name' => 'Suriname, Dollars', + 'name' => 'Dollars', + 'code' => 'SRD', + 'symbol' => '$', + 'unicode' => + array ( + 0 => '36', + ), + 'unihex' => + array ( + 0 => '24', + ), + ), + 'SYP' => + array ( + 'full_name' => 'Syria, Pounds', + 'name' => 'Pounds', + 'code' => 'SYP', + 'symbol' => '£', + 'unicode' => + array ( + 0 => '163', + ), + 'unihex' => + array ( + 0 => 'a3', + ), + ), + 'TWD' => + array ( + 'full_name' => 'Taiwan, New Dollars', + 'name' => 'New Dollars', + 'code' => 'TWD', + 'symbol' => 'NT$', + 'unicode' => + array ( + 0 => '78', + 1 => ' 84', + 2 => ' 36', + ), + 'unihex' => + array ( + 0 => '4e', + 1 => ' 54', + 2 => ' 24', + ), + ), + 'THB' => + array ( + 'full_name' => 'Thailand, Baht', + 'name' => 'Baht', + 'code' => 'THB', + 'symbol' => '฿', + 'unicode' => + array ( + 0 => '3647', + ), + 'unihex' => + array ( + 0 => 'e3f', + ), + ), + 'TTD' => + array ( + 'full_name' => 'Trinidad and Tobago, Dollars', + 'name' => 'Dollars', + 'code' => 'TTD', + 'symbol' => 'TT$', + 'unicode' => + array ( + 0 => '84', + 1 => ' 84', + 2 => ' 36', + ), + 'unihex' => + array ( + 0 => '54', + 1 => ' 54', + 2 => ' 24', + ), + ), + 'TRY' => + array ( + 'full_name' => 'Turkey, Lira', + 'name' => 'Lira', + 'code' => 'TRY', + 'symbol' => 'TL', + 'unicode' => + array ( + 0 => '84', + 1 => ' 76', + ), + 'unihex' => + array ( + 0 => '54', + 1 => ' 4c', + ), + ), + 'TRL' => + array ( + 'full_name' => 'Turkey, Liras', + 'name' => 'Liras', + 'code' => 'TRL', + 'symbol' => '₤', + 'unicode' => + array ( + 0 => '8356', + ), + 'unihex' => + array ( + 0 => '20a4', + ), + ), + 'TVD' => + array ( + 'full_name' => 'Tuvalu, Dollars', + 'name' => 'Dollars', + 'code' => 'TVD', + 'symbol' => '$', + 'unicode' => + array ( + 0 => '36', + ), + 'unihex' => + array ( + 0 => '24', + ), + ), + 'UAH' => + array ( + 'full_name' => 'Ukraine, Hryvnia', + 'name' => 'Hryvnia', + 'code' => 'UAH', + 'symbol' => '₴', + 'unicode' => + array ( + 0 => '8372', + ), + 'unihex' => + array ( + 0 => '20b4', + ), + ), + 'UYU' => + array ( + 'full_name' => 'Uruguay, Pesos', + 'name' => 'Pesos', + 'code' => 'UYU', + 'symbol' => '$U', + 'unicode' => + array ( + 0 => '36', + 1 => ' 85', + ), + 'unihex' => + array ( + 0 => '24', + 1 => ' 55', + ), + ), + 'UZS' => + array ( + 'full_name' => 'Uzbekistan, Sums', + 'name' => 'Sums', + 'code' => 'UZS', + 'symbol' => 'лв', + 'unicode' => + array ( + 0 => '1083', + 1 => ' 1074', + ), + 'unihex' => + array ( + 0 => '43b', + 1 => ' 432', + ), + ), + 'VEF' => + array ( + 'full_name' => 'Venezuela, Bolivares Fuertes', + 'name' => 'Bolivares Fuertes', + 'code' => 'VEF', + 'symbol' => 'Bs', + 'unicode' => + array ( + 0 => '66', + 1 => ' 115', + ), + 'unihex' => + array ( + 0 => '42', + 1 => ' 73', + ), + ), + 'VND' => + array ( + 'full_name' => 'Vietnam, Dong', + 'name' => 'Dong', + 'code' => 'VND', + 'symbol' => '₫', + 'unicode' => + array ( + 0 => '8363', + ), + 'unihex' => + array ( + 0 => '20ab', + ), + ), + 'YER' => + array ( + 'full_name' => 'Yemen, Rials', + 'name' => 'Rials', + 'code' => 'YER', + 'symbol' => 'ï·¼', + 'unicode' => + array ( + 0 => '65020', + ), + 'unihex' => + array ( + 0 => 'fdfc', + ), + ), + 'ZWD' => + array ( + 'full_name' => 'Zimbabwe, Zimbabwe Dollars', + 'name' => 'Zimbabwe Dollars', + 'code' => 'ZWD', + 'symbol' => 'Z$', + 'unicode' => + array ( + 0 => '90', + 1 => ' 36', + ), + 'unihex' => + array ( + 0 => '5a', + 1 => ' 24', + ), + ), +); \ No newline at end of file diff --git a/modules/Currencies/language/en_us.lang.php b/modules/Currencies/language/en_us.lang.php new file mode 100644 index 00000000..6ca1b2c7 --- /dev/null +++ b/modules/Currencies/language/en_us.lang.php @@ -0,0 +1,83 @@ + 'Currencies', + 'LBL_LIST_FORM_TITLE' => 'Currencies', + 'LBL_CURRENCY' => 'Currency', + 'LBL_ADD' => 'Add', + 'LBL_MERGE' => 'Merge', + 'LBL_MERGE_TXT' => 'Please select the currencies you would like to map to the selected currency. This will delete all the currencies with a checkmark and reassign any value associated with them to the selected currency.', + 'LBL_US_DOLLAR' => 'U.S. Dollar', + 'LBL_DELETE' => 'Delete', + 'LBL_LIST_SYMBOL' => 'Currency Symbol', + 'LBL_LIST_NAME' => 'Currency Name', + 'LBL_LIST_ISO4217' => 'ISO 4217 Code', + 'LBL_LIST_ISO4217_HELP' => 'Enter a three-letter ISO 4217 code that defines the currency name and currency symbol.', + 'LBL_UPDATE' => 'Update', + 'LBL_LIST_RATE' => 'Conversion Rate', + 'LBL_LIST_RATE_HELP' => 'A Conversion Rate of 0.5 for Euro means that 10 USD = 5 Euro.', + 'LBL_LIST_STATUS' => 'Status', + 'LNK_NEW_CONTACT' => 'New Contact', + 'LNK_NEW_ACCOUNT' => 'New Account', + 'LNK_NEW_OPPORTUNITY' => 'New Opportunity', + 'LNK_NEW_CASE' => 'New Case', + 'LNK_NEW_NOTE' => 'Create Note or Attachment', + 'LNK_NEW_CALL' => 'New Call', + 'LNK_NEW_EMAIL' => 'New Email', + 'LNK_NEW_MEETING' => 'New Meeting', + 'LNK_NEW_TASK' => 'Create Task', + 'NTC_DELETE_CONFIRMATION' => 'Are you sure you want to delete this record? Any record using this currency will be converted to the system default currency when they are accessed. It may be better to set the status to inactive.', + 'LBL_BELOW_MIN' => 'Conversion rate has to be above 0', + 'currency_status_dom' => + array ( + 'Active' => 'Active', + 'Inactive' => 'Inactive', + ), + 'LBL_CREATED_BY' => 'Created By', +); + + +?> \ No newline at end of file diff --git a/modules/Currencies/vardefs.php b/modules/Currencies/vardefs.php new file mode 100644 index 00000000..16295115 --- /dev/null +++ b/modules/Currencies/vardefs.php @@ -0,0 +1,143 @@ + 'currencies', + 'comment' => 'Currencies allow Sugar to store and display monetary values in various denominations' + ,'fields' => array ( + 'id' => + array ( + 'name' => 'id', + 'vname' => 'LBL_NAME', + 'type' => 'id', + 'required' => true, + 'reportable'=>false, + 'comment' => 'Unique identifer' + ), + 'name' => + array ( + 'name' => 'name', + 'vname' => 'LBL_LIST_NAME', + 'type' => 'varchar', + 'len' => '36', + 'required' => true, + 'comment' => 'Name of the currency', + 'importable' => 'required', + ), + 'symbol' => + array ( + 'name' => 'symbol', + 'vname' => 'LBL_LIST_SYMBOL', + 'type' => 'varchar', + 'len' => '36', + 'required' => true, + 'comment' => 'Symbol representing the currency', + 'importable' => 'required', + ), + 'iso4217' => + array ( + 'name' => 'iso4217', + 'vname' => 'LBL_LIST_ISO4217', + 'type' => 'varchar', + 'len' => '3', + 'comment' => '3-letter identifier specified by ISO 4217 (ex: USD)', + ), + 'conversion_rate' => + array ( + 'name' => 'conversion_rate', + 'vname' => 'LBL_LIST_RATE', + 'type' => 'float', + 'dbType' => 'double', + 'default' => '0', + 'required' => true, + 'comment' => 'Conversion rate factor (relative to stored value)', + 'importable' => 'required', + ), + 'status' => + array ( + 'name' => 'status', + 'vname' => 'LBL_STATUS', + 'type' => 'enum', + 'dbType'=>'varchar', + 'options' => 'currency_status_dom', + 'len' => 100, + 'comment' => 'Currency status', + 'importable' => 'required', + ), + 'deleted' => + array ( + 'name' => 'deleted', + 'vname' => 'LBL_DELETED', + 'type' => 'bool', + 'required' => false, + 'reportable'=>false, + 'comment' => 'Record deletion indicator' + ), + 'date_entered' => + array ( + 'name' => 'date_entered', + 'vname' => 'LBL_DATE_ENTERED', + 'type' => 'datetime', + 'required' => true, + 'comment' => 'Date record created' + + ), + 'date_modified' => + array ( + 'name' => 'date_modified', + 'vname' => 'LBL_DATE_MODIFIED', + 'type' => 'datetime', + 'required' => true, + 'comment' => 'Date record last modified' + ), + 'created_by' => + array ( + 'name' => 'created_by', + 'reportable' => false, + 'vname' => 'LBL_CREATED_BY', + 'type' => 'id', + 'len' => '36', + 'required' => true, + 'comment' => 'User ID who created record' + ), +) + , 'indices' => array ( + array('name' =>'currenciespk', 'type' =>'primary', 'fields'=>array('id')), + array('name' =>'idx_currency_name', 'type' =>'index', 'fields'=>array('name','deleted')) + ) + + ); +?> diff --git a/modules/DocumentRevisions/DocumentRevision.php b/modules/DocumentRevisions/DocumentRevision.php new file mode 100644 index 00000000..1ffae31b --- /dev/null +++ b/modules/DocumentRevisions/DocumentRevision.php @@ -0,0 +1,303 @@ +setupCustomFields('DocumentRevisions'); //parameter is module name + $this->disable_row_level_security =true; //no direct access to this module. + } + + function save($check_notify = false){ + $saveRet = parent::save($check_notify); + + //update documents table. (not through save, because it causes a loop) + // If we don't have a document_id, find it. + if ( empty($this->document_id) ) { + $query = "SELECT document_id FROM document_revisions WHERE id = '".$this->db->quote($this->id)."'"; + $ret = $this->db->query($query,true); + $row = $this->db->fetchByAssoc($ret); + $this->document_id = $row['document_id']; + } + $query = "UPDATE documents set document_revision_id='".$this->db->quote($this->id)."', doc_type='".$this->db->quote($this->doc_type)."', doc_url='".$this->db->quote($this->doc_url)."', doc_id='".$this->db->quote($this->doc_id)."' where id = '".$this->db->quote($this->document_id)."'"; + $this->db->query($query,true); + + return $saveRet; + } + function get_summary_text() + { + return "$this->filename"; + } + + function retrieve($id, $encode=false){ + $ret = parent::retrieve($id, $encode); + + return $ret; + } + + function is_authenticated() + { + return $this->authenticated; + } + + function fill_in_additional_list_fields() { + $this->fill_in_additional_detail_fields(); + } + + function fill_in_additional_detail_fields() + { + global $theme; + global $current_language; + + parent::fill_in_additional_detail_fields(); + + if ( empty($this->id) && empty($this->document_id) && isset($_REQUEST['return_id']) && !empty($_REQUEST['return_id']) ) { + $this->document_id = $_REQUEST['return_id']; + } + + //find the document name and current version. + $query = "SELECT document_name, revision, document_revision_id FROM documents, document_revisions where documents.id = '".$this->db->quote($this->document_id)."' AND document_revisions.id = documents.document_revision_id"; + $result = $this->db->query($query,true,"Error fetching document details...:"); + $row = $this->db->fetchByAssoc($result); + if ($row != null) { + $this->document_name = $row['document_name']; + $this->document_name = ''.$row['document_name'].''; + $this->latest_revision = $row['revision']; + $this->latest_revision_id = $row['document_revision_id']; + + if ( empty($this->revision) ) { + $this->revision = $this->latest_revision + 1; + } + } + } + + /** + * Returns a filename based off of the logical (Sugar-side) Document name and combined with the revision. Tailor + * this to needs created by email RFCs, filesystem name conventions, charset conventions etc. + * @param string revId Revision ID if not latest + * @return string formatted name + */ + function getDocumentRevisionNameForDisplay($revId='') { + global $sugar_config; + global $current_language; + + $localLabels = return_module_language($current_language, 'DocumentRevisions'); + + // prep - get source Document + $document = new Document(); + + // use passed revision ID + if(!empty($revId)) { + $tempDoc = new DocumentRevision(); + $tempDoc->retrieve($revId); + } else { + $tempDoc = $this; + } + + // get logical name + $document->retrieve($tempDoc->document_id); + $logicalName = $document->document_name; + + // get revision string + $revString = ''; + if(!empty($tempDoc->revision)) { + $revString = "-{$localLabels['LBL_REVISION']}_{$tempDoc->revision}"; + } + + // get extension + $realFilename = $tempDoc->filename; + $fileExtension_beg = strrpos($realFilename, "."); + $fileExtension = ""; + + if($fileExtension_beg > 0) { + $fileExtension = substr($realFilename, $fileExtension_beg + 1); + } + //check to see if this is a file with extension located in "badext" + foreach($sugar_config['upload_badext'] as $badExt) { + if(strtolower($fileExtension) == strtolower($badExt)) { + //if found, then append with .txt to filename and break out of lookup + //this will make sure that the file goes out with right extension, but is stored + //as a text in db. + $fileExtension .= ".txt"; + break; // no need to look for more + } + } + $fileExtension = ".".$fileExtension; + + $return = $logicalName.$revString.$fileExtension; + + // apply RFC limitations here + if(mb_strlen($return) > 1024) { + // do something if we find a real RFC issue + } + + return $return; + } + + function fill_document_name_revision($doc_id) { + + //find the document name and current version. + $query = "SELECT documents.document_name, revision FROM documents, document_revisions where documents.id = '$doc_id'"; + $query .= " AND document_revisions.id = documents.document_revision_id"; + $result = $this->db->query($query,true,"Error fetching document details...:"); + $row = $this->db->fetchByAssoc($result); + if ($row != null) { + $this->name = $row['document_name']; + $this->latest_revision = $row['revision']; + } + } + + function list_view_parse_additional_sections(&$list_form, $xTemplateSection){ + return $list_form; + } + + function get_list_view_data(){ + $revision_fields = $this->get_list_view_array(); + + $forecast_fields['FILE_URL'] = $this->file_url; + return $revision_fields; + } + + //static function.. + function get_document_revision_name($doc_revision_id){ + if (empty($doc_revision_id)) return null; + + $db = DBManagerFactory::getInstance(); + $query="select revision from document_revisions where id='$doc_revision_id'"; + $result=$db->query($query); + if (!empty($result)) { + $row=$db->fetchByAssoc($result); + if (!empty($row)) { + return $row['revision']; + } + } + return null; + } + + //static function. + function get_document_revisions($doc_id){ + $return_array= Array(); + if (empty($doc_id)) return $return_array; + + $db = DBManagerFactory::getInstance(); + $query="select id, revision from document_revisions where document_id='$doc_id' and deleted=0"; + $result=$db->query($query); + if (!empty($result)) { + while (($row=$db->fetchByAssoc($result)) != null) { + $return_array[$row['id']]=$row['revision']; + } + } + return $return_array; + } +} + +require_once('modules/Documents/DocumentExternalApiDropDown.php'); \ No newline at end of file diff --git a/modules/DocumentRevisions/Forms.php b/modules/DocumentRevisions/Forms.php new file mode 100644 index 00000000..4edefa4e --- /dev/null +++ b/modules/DocumentRevisions/Forms.php @@ -0,0 +1,195 @@ + + +function verify_data(form) { + var isError = false; + var errorMessage = ""; + if (trim(form.revision.value) == "") { + isError = true; + errorMessage += "\\n$lbl_version"; + } + if (trim(form.uploadfile.value) == "") { + isError = true; + errorMessage += "\\n$lbl_filename"; + } + + if (isError == true) { + alert("$err_missing_required_fields" + errorMessage); + return false; + } + + return true; +} + + +EOQ; + +return $the_script; +} + +function get_chooser_js() +{ +$the_script = << + + +EOQ; + +return $the_script; +} +function get_validate_record_js(){ + +global $mod_strings; +global $app_strings; + +$lbl_name = $mod_strings['ERR_DOC_NAME']; +$lbl_start_date = $mod_strings['ERR_DOC_ACTIVE_DATE']; +$lbl_file_name = $mod_strings['ERR_FILENAME']; +$lbl_file_version=$mod_strings['ERR_DOC_VERSION']; +$sqs_no_match = $app_strings['ERR_SQS_NO_MATCH']; +$err_missing_required_fields = $app_strings['ERR_MISSING_REQUIRED_FIELDS']; + +if(isset($_REQUEST['record'])) { +//do not validate upload file + $the_upload_script=""; + + +} else +{ + +$the_upload_script = << + +function verify_data(form) { + var isError = false; + var errorMessage = ""; + if (trim(form.document_name.value) == "") { + isError = true; + errorMessage += "\\n$lbl_name"; + } + + $the_upload_script + + if (trim(form.active_date.value) == "") { + isError = true; + errorMessage += "\\n$lbl_start_date"; + } + if (trim(form.revision.value) == "") { + isError = true; + errorMessage += "\\n$lbl_file_version"; + } + + + if (isError == true) { + alert("$err_missing_required_fields" + errorMessage); + return false; + } + + //make sure start date is <= end_date + + return true; +} + + +EOQ; + +return $the_script; +} + +?> diff --git a/modules/DocumentRevisions/ListView.html b/modules/DocumentRevisions/ListView.html new file mode 100644 index 00000000..f5206d5d --- /dev/null +++ b/modules/DocumentRevisions/ListView.html @@ -0,0 +1,106 @@ + + + + + + + + + + +
    +
    + + + + + + + + + + + + + +
    +
    {ADMIN_EDIT}
    + + + +{PAGINATION} + + + + + + + + + + + + + + + + + + + + + + + +
     {MOD.LBL_REV_LIST_REVISION}{MOD.LBL_REV_LIST_ENTERED}{MOD.LBL_REV_LIST_CREATED}{MOD.LBL_REV_LIST_LOG}
    {DOCREVISION.FILE_URL}{DOCREVISION.REVISION}{DOCREVISION.DATE_ENTERED}{DOCREVISION.FIRST_NAME} {DOCREVISION.LAST_NAME}{DOCREVISION.CHANGE_LOG}{DELETE_INLINE_PNG} {APP.LNK_DELETE}
    + \ No newline at end of file diff --git a/modules/DocumentRevisions/Menu.php b/modules/DocumentRevisions/Menu.php new file mode 100644 index 00000000..b4c64580 --- /dev/null +++ b/modules/DocumentRevisions/Menu.php @@ -0,0 +1,61 @@ +retrieveSettings(); + $user_merge = $current_user->getPreference('mailmerge_on'); + if ($user_merge == 'on' && isset($admin->settings['system_mailmerge_on']) && $admin->settings['system_mailmerge_on']){ + $module_menu[]=Array("index.php?module=MailMerge&action=index&reset=true", $mod_strings['LNK_NEW_MAIL_MERGE'],"Documents"); + } +} +?> diff --git a/modules/DocumentRevisions/field_arrays.php b/modules/DocumentRevisions/field_arrays.php new file mode 100644 index 00000000..f938f07e --- /dev/null +++ b/modules/DocumentRevisions/field_arrays.php @@ -0,0 +1,72 @@ + Array("id" + ,"change_log" + ,"document_id" + ,"date_entered" + ,"created_by" + ,"filename" + ,"file_ext" + ,"file_mime_type" + ,"revision" + ,"date_modified" + ,"deleted" + ), + 'list_fields' => Array("id" + ,"change_log" + ,"document_id" + ,"date_entered" + ,"created_by" + ,"filename" + ,"file_ext" + ,"file_mime_type" + ,"revision" + ,"date_modified" + ,"deleted" + ,"latest_revision_id" + ), + 'required_fields' => Array("revision"=>1), +); +?> \ No newline at end of file diff --git a/modules/DocumentRevisions/language/en_us.lang.php b/modules/DocumentRevisions/language/en_us.lang.php new file mode 100644 index 00000000..51c745e1 --- /dev/null +++ b/modules/DocumentRevisions/language/en_us.lang.php @@ -0,0 +1,92 @@ + 'Document Revision', + + 'LNK_NEW_DOCUMENT' => 'Create Document', + 'LNK_DOCUMENT_LIST'=> 'View Documents', + + //vardef labels + 'LBL_REVISION_NAME' => 'Revision Number', + 'LBL_FILENAME' => 'Filename', + 'LBL_MIME' => 'Mime Type', + 'LBL_REVISION' => 'Revision', + 'LBL_DOCUMENT' => 'Related Document', + 'LBL_LATEST_REVISION' => 'Latest Revision', + 'LBL_CHANGE_LOG'=> 'Change Log', + 'LBL_ACTIVE_DATE'=> 'Publish Date', + 'LBL_EXPIRATION_DATE' => 'Expiration Date', + 'LBL_FILE_EXTENSION' => 'File Extension', + 'LBL_DET_CREATED_BY' => 'Created By:', + 'LBL_DET_DATE_CREATED' => 'Date Created:', + + 'LBL_DOC_NAME' => 'Document Name:', + 'LBL_DOC_VERSION' => 'Revision:', + + //document revisions. + 'LBL_REV_LIST_REVISION' => 'Revision', + 'LBL_REV_LIST_ENTERED' => 'Date Created', + 'LBL_REV_LIST_CREATED' => 'Created by', + 'LBL_REV_LIST_LOG'=> 'Change Log', + 'LBL_REV_LIST_FILENAME' => 'Filename', + + 'LBL_CURRENT_DOC_VERSION'=> 'Latest Revision:', + 'LBL_SEARCH_FORM_TITLE'=> 'Document Search', + + //error messages + 'ERR_FILENAME'=> 'File Name', + 'ERR_DOC_VERSION'=> 'Document Version', + 'ERR_DELETE_CONFIRM'=> 'Do you want to delete this document revision?', + 'ERR_DELETE_LATEST_VERSION'=> 'You are not allowed to delete the latest revision of a document.', + 'LNK_NEW_MAIL_MERGE' => 'Mail Merge', + 'LBL_DOC_ID' => 'Document Source ID', + 'LBL_DOC_TYPE' => 'Source', + 'LBL_DOC_URL' => 'Document Source URL', +); + + +?> diff --git a/modules/DocumentRevisions/metadata/detailviewdefs.php b/modules/DocumentRevisions/metadata/detailviewdefs.php new file mode 100644 index 00000000..ccb00fcd --- /dev/null +++ b/modules/DocumentRevisions/metadata/detailviewdefs.php @@ -0,0 +1,76 @@ + array('maxColumns' => '2', + 'form' => array( + 'buttons' => array(), + 'hidden'=>array('')), + 'widths' => array( + array('label' => '10', 'field' => '30'), + array('label' => '10', 'field' => '30') + ), + ), + 'panels' => + array ( + '' => + array ( + array ( + 'document_name', + 'latest_revision', + ), + + array ( + 'revision', + ), + + array ( + 'filename', + ), + + array ( + array ( + 'name' => 'date_entered', + 'customCode' => '{$fields.date_entered.value} {$APP.LBL_BY} {$fields.created_by_name.value}', + ), + ), + + array ( + 'change_log', + ), + ), + ), +); \ No newline at end of file diff --git a/modules/DocumentRevisions/metadata/editviewdefs.php b/modules/DocumentRevisions/metadata/editviewdefs.php new file mode 100644 index 00000000..feb36600 --- /dev/null +++ b/modules/DocumentRevisions/metadata/editviewdefs.php @@ -0,0 +1,75 @@ + array('form' => array('enctype'=>'multipart/form-data', + 'hidden'=>array(''), + ), + 'maxColumns' => '2', + 'widths' => array( + array('label' => '10', 'field' => '30'), + array('label' => '10', 'field' => '30') + ), + 'javascript' => ' + + + + + +', + ), + 'panels' =>array ( + '' => + array ( + array ( + array ( 'name' => 'document_name', 'type' => 'readonly' ), + array ( 'name' => 'latest_revision', 'type' => 'readonly' ), + ), + array ( + 'revision', + ), + + array ( + 'filename', + ), + + array ( + array ( 'name' => 'change_log', 'size' => '126', 'maxlength' => '255' ), + ), + + ), + ), +); \ No newline at end of file diff --git a/modules/DocumentRevisions/metadata/subpanels/default.php b/modules/DocumentRevisions/metadata/subpanels/default.php new file mode 100644 index 00000000..e200051d --- /dev/null +++ b/modules/DocumentRevisions/metadata/subpanels/default.php @@ -0,0 +1,80 @@ + array( + array('widget_class' => 'SubPanelTopCreateRevisionButton'), + ), + + 'where' => '', + + + 'list_fields' => array( + 'filename'=>array ( + 'vname'=>'LBL_REV_LIST_FILENAME', + 'widget_class' => 'SubPanelDetailViewLink', + 'width' => '15%', + ), + 'revision'=>array( + 'vname' => 'LBL_REV_LIST_REVISION', + 'width' => '5%', + ), + 'date_entered'=>array( + 'vname' => 'LBL_REV_LIST_ENTERED', + 'width' => '10%', + ), + 'created_by_name'=>array( + 'vname' => 'LBL_REV_LIST_CREATED', + 'width' => '25%', + ), + 'change_log'=>array( + 'vname' => 'LBL_REV_LIST_LOG', + 'width' => '35%', + ), + 'del_button'=>array( + 'vname' => 'LBL_DELETE_BUTTON', + 'widget_class' => 'SubPanelRemoveButton', + 'width' => '5%', + ), + 'document_id'=>array( + 'usage' =>'query_only', + ) + ), +); +?> \ No newline at end of file diff --git a/modules/DocumentRevisions/subpanels/default.php b/modules/DocumentRevisions/subpanels/default.php new file mode 100644 index 00000000..fb684fba --- /dev/null +++ b/modules/DocumentRevisions/subpanels/default.php @@ -0,0 +1,93 @@ + array( + array('widget_class' => 'SubPanelTopCreateRevisionButton'), + ), + + 'where' => '', + + + 'list_fields' => array( + 'filename' => + array ( + 'vname' => 'LBL_REV_LIST_FILENAME', + 'widget_class' => 'SubPanelDetailViewLink', + 'width' => '15%', + 'default' => true, + ), + 'revision' => + array ( + 'vname' => 'LBL_REV_LIST_REVISION', + 'width' => '5%', + 'default' => true, + ), + 'created_by_name' => + array ( + 'vname' => 'LBL_REV_LIST_CREATED', + 'width' => '25%', + 'default' => true, + ), + 'date_entered' => + array ( + 'vname' => 'LBL_REV_LIST_ENTERED', + 'width' => '10%', + 'default' => true, + ), + 'change_log' => + array ( + 'vname' => 'LBL_REV_LIST_LOG', + 'width' => '35%', + 'default' => true, + ), + 'del_button' => + array ( + 'vname' => 'LBL_DELETE_BUTTON', + 'widget_class' => 'SubPanelRemoveButton', + 'width' => '5%', + 'default' => true, + ), + 'document_id' => + array ( + 'usage' => 'query_only', + ), + ), +); +?> \ No newline at end of file diff --git a/modules/DocumentRevisions/vardefs.php b/modules/DocumentRevisions/vardefs.php new file mode 100644 index 00000000..f14e9020 --- /dev/null +++ b/modules/DocumentRevisions/vardefs.php @@ -0,0 +1,239 @@ + 'document_revisions' + ,'fields' => array ( + 'id' => + array ( + 'name' => 'id', + 'vname' => 'LBL_REVISION_NAME', + 'type' => 'varchar', + 'len' => '36', + 'required'=>true, + 'reportable'=>false, + ), + + 'change_log' => + array ( + 'name' => 'change_log', + 'vname' => 'LBL_CHANGE_LOG', + 'type' => 'varchar', + 'len' => '255', + ), + + 'document_id' => + array ( + 'name' => 'document_id', + 'vname' => 'LBL_DOCUMENT', + 'type' => 'varchar', + 'len' => '36', + 'required'=>false, + 'reportable'=>false, + ), +'doc_id' => + array ( + 'name' => 'doc_id', + 'vname' => 'LBL_DOC_ID', + 'type' => 'varchar', + 'len' => '100', + 'comment' => 'Document ID from documents web server provider', + 'importable' => false, + 'studio' => 'false', + ), + 'doc_type' => + array ( + 'name' => 'doc_type', + 'vname' => 'LBL_DOC_TYPE', + 'type' => 'enum', + 'function' => 'getDocumentsExternalApiDropDown', + 'len' => '100', + 'comment' => 'Document type (ex: Google, box.net, LotusLive)', + 'studio' => 'false', + ), +'doc_url' => + array ( + 'name' => 'doc_url', + 'vname' => 'LBL_DOC_URL', + 'type' => 'varchar', + 'len' => '255', + 'comment' => 'Document URL from documents web server provider', + 'importable' => false, + 'studio' => 'false', + ), + 'date_entered' => + array ( + 'name' => 'date_entered', + 'vname' => 'LBL_DATE_ENTERED', + 'type' => 'datetime', + ), + 'created_by' => + array ( + 'name' => 'created_by', + 'rname' => 'user_name', + 'id_name' => 'modified_user_id', + 'vname' => 'LBL_CREATED', + 'type' => 'assigned_user_name', + 'table' => 'users', + 'isnull' => 'false', + 'dbType' => 'id', + 'source'=>'db', + ), + 'filename' => + array ( + 'name' => 'filename', + 'vname' => 'LBL_FILENAME', + 'type' => 'file', + 'dbType' => 'varchar', + 'required'=>true, + 'len' => '255', + 'allowEapm' => true, + 'linkModuleOverride' => 'Documents', + ), + 'file_ext' => + array ( + 'name' => 'file_ext', + 'vname' => 'LBL_FILE_EXTENSION', + 'type' => 'varchar', + 'len' => 100, + ), + 'file_mime_type' => + array ( + 'name' => 'file_mime_type', + 'vname' => 'LBL_MIME', + 'type' => 'varchar', + 'len' => '100', + ), + + 'revision'=> + array ( + 'name' => 'revision', + 'vname' => 'LBL_REVISION', + 'type' => 'varchar', + 'len' => 100, + 'importable' => 'required', + ), + + 'deleted' => + array ( + 'name' => 'deleted', + 'vname' => 'LBL_DELETED', + 'type' => 'bool', + 'default' => 0, + 'reportable'=>false, + ), + 'date_modified' => + array ( + 'name' => 'date_modified', + 'vname' => 'LBL_DATE_MODIFIED', + 'type' => 'datetime', + ), + 'documents' => + array ( + 'name' => 'documents', + 'type' => 'link', + 'relationship' => 'document_revisions', + 'source'=>'non-db', + 'vname'=>'LBL_REVISIONS', + ), + +'created_by_link' => + array ( + 'name' => 'created_by_link', + 'type' => 'link', + 'relationship' => 'revisions_created_by', + 'vname' => 'LBL_CREATED_BY_USER', + 'link_type' => 'one', + 'module'=>'Users', + 'bean_name'=>'User', + 'source'=>'non-db', + ), + +'created_by_name' => + array ( + 'name' => 'created_by_name', + 'rname' => 'user_name', + 'db_concat_fields'=> array(0=>'first_name', 1=>'last_name'), + 'id_name' => 'created_by', + 'vname' => 'LBL_CREATED_BY_NAME', + 'type' => 'relate', + 'table' => 'users', + 'isnull' => 'true', + 'module' => 'Users', + 'dbType' => 'varchar', + 'link'=>'created_by_link', + 'len' => '255', + 'source'=>'non-db', + ), + 'latest_revision_id'=> + array ( + 'name' => 'latest_revision_id', + 'vname' => 'LBL_REVISION', + 'type' => 'varchar', + 'len' => '36', + 'source'=>'non-db', + ), + 'document_name' => + array ( + 'name' => 'document_name', + 'vname' => 'LBL_DOC_NAME', + 'type' => 'varchar', + 'len' => '255', + 'source' => 'non-db', + ), + 'latest_revision' => + array ( + 'name' => 'latest_revision', + 'vname' => 'LBL_CURRENT_DOC_VERSION', + 'type' => 'varchar', + 'len' => '255', + 'source' => 'non-db', + ), + +), +'relationships'=>array( + 'revisions_created_by' => array('lhs_module'=> 'Users', 'lhs_table'=> 'users', 'lhs_key' => 'id', + 'rhs_module'=> 'DocumentRevisions', 'rhs_table'=> 'document_revisions', 'rhs_key' => 'created_by', + 'relationship_type'=>'one-to-many'), +), + +'indices' => array ( + array('name' =>'documentrevisionspk', 'type' =>'primary', 'fields'=>array('id')), + array('name' =>'documentrevision_mimetype', 'type' =>'index', 'fields'=>array('file_mime_type')), + ) +); +?> diff --git a/modules/Documents/Dashlets/MyDocumentsDashlet/MyDocumentsDashlet.data.php b/modules/Documents/Dashlets/MyDocumentsDashlet/MyDocumentsDashlet.data.php new file mode 100644 index 00000000..71d1bfe8 --- /dev/null +++ b/modules/Documents/Dashlets/MyDocumentsDashlet/MyDocumentsDashlet.data.php @@ -0,0 +1,102 @@ + array('default' => ''), + 'document_name' => array('default' => ''), + 'category_id' => array('default' => ''), + 'status_id' => array('default' => ''), + 'active_date' => array('default' => ''), + + 'assigned_user_id' => array('type' => 'assigned_user_name', + 'default' => $current_user->name, + 'label' => 'LBL_ASSIGNED_TO')); + + + +$dashletData['MyDocumentsDashlet']['columns'] = array('document_name' => array('width' => '40', + 'label' => 'LBL_NAME', + 'link' => true, + 'default' => true), + 'category_id' => array('width' => '8', + 'label' => 'LBL_CATEGORY', + 'default' => true), + 'subcategory_id' => array('width' => '8', + 'label' => 'LBL_SUBCATEGORY', + 'default' => false), + 'template_type' => array('width' => '8', + 'label' => 'LBL_TEMPLATE_TYPE', + 'default' => true), + 'is_template' => array('width' => '8', + 'label' => 'LBL_IS_TEMPLATE', + 'default' => false), + 'status_id' => array('width' => '8', + 'label' => 'LBL_STATUS', + 'default' => true), + 'active_date' => array('width' => '8', + 'label' => 'LBL_ACTIVE_DATE', + 'default' => true), + 'exp_date' => array('width' => '8', + 'label' => 'LBL_EXPIRATION_DATE', + 'default' => false), + 'date_entered' => array('width' => '15', + 'label' => 'LBL_DATE_ENTERED'), + 'date_modified' => array('width' => '15', + 'label' => 'LBL_DATE_MODIFIED'), + 'created_by' => array('width' => '8', + 'label' => 'LBL_CREATED'), + 'assigned_user_name' => array('width' => '8', + 'label' => 'LBL_LIST_ASSIGNED_USER'), + 'FILENAME' => array ( + 'width' => '20%', + 'label' => 'LBL_FILENAME', + 'link' => true, + 'default' => false, + 'bold' => false, + 'displayParams' => array ( 'module' => 'Documents', ), + 'related_fields' => + array ( + 0 => 'document_revision_id', + 1 => 'doc_id', + 2 => 'doc_type', + 3 => 'doc_url', + ), + ), + ); +?> \ No newline at end of file diff --git a/modules/Documents/Dashlets/MyDocumentsDashlet/MyDocumentsDashlet.meta.php b/modules/Documents/Dashlets/MyDocumentsDashlet/MyDocumentsDashlet.meta.php new file mode 100644 index 00000000..5f540882 --- /dev/null +++ b/modules/Documents/Dashlets/MyDocumentsDashlet/MyDocumentsDashlet.meta.php @@ -0,0 +1,45 @@ + 'Documents', + 'title' => translate('LBL_HOMEPAGE_TITLE', 'Documents'), + 'description' => 'A customizable view into Documents', + 'category' => 'Module Views'); +?> \ No newline at end of file diff --git a/modules/Documents/Dashlets/MyDocumentsDashlet/MyDocumentsDashlet.php b/modules/Documents/Dashlets/MyDocumentsDashlet/MyDocumentsDashlet.php new file mode 100644 index 00000000..852b7fe9 --- /dev/null +++ b/modules/Documents/Dashlets/MyDocumentsDashlet/MyDocumentsDashlet.php @@ -0,0 +1,71 @@ +title = translate('LBL_HOMEPAGE_TITLE', 'Documents'); + + $this->searchFields = $dashletData['MyDocumentsDashlet']['searchFields']; + $this->columns = $dashletData['MyDocumentsDashlet']['columns']; + + $this->seedBean = new Document(); + } + + function displayOptions() { + $this->processDisplayOptions(); + require_once('modules/Documents/Document.php'); + + $types = getDocumentsExternalApiDropDown(); + $this->currentSearchFields['doc_type']['input'] = ''; + $this->configureSS->assign('searchFields', $this->currentSearchFields); + return $this->configureSS->fetch($this->configureTpl); + } +} + +?> \ No newline at end of file diff --git a/modules/Documents/Delete.php b/modules/Documents/Delete.php new file mode 100644 index 00000000..31595555 --- /dev/null +++ b/modules/Documents/Delete.php @@ -0,0 +1,88 @@ +retrieve($_REQUEST['record']); +if(!$focus->ACLAccess('Delete')){ + ACLController::displayNoAccess(true); + sugar_cleanup(true); +} +if (isset($_REQUEST['object']) && $_REQUEST['object']="documentrevision") { + //delete document revision. + $focus = new DocumentRevision(); + + UploadFile::unlink_file($_REQUEST['revision_id'],$_REQUEST['filename']); + +} else { + //delete document and its revisions. + $focus = new Document(); + $focus->retrieve($_REQUEST['record']); + + $focus->load_relationships('revisions'); + $revisions= $focus->get_linked_beans('revisions','DocumentRevision'); + + if (!empty($revisions) && is_array($revisions)) { + foreach($revisions as $key=>$thisversion) { + UploadFile::unlink_file($thisversion->id,$thisversion->filename); + //mark the version deleted. + $thisversion->mark_deleted($thisversion->id); + } + } +} + +$focus->mark_deleted($_REQUEST['record']); + +header("Location: index.php?module=".$_REQUEST['return_module']."&action=".$_REQUEST['return_action']."&record=".$_REQUEST['return_id']); +?> diff --git a/modules/Documents/Document.php b/modules/Documents/Document.php new file mode 100644 index 00000000..d7804486 --- /dev/null +++ b/modules/Documents/Document.php @@ -0,0 +1,341 @@ +'contracts', + ); + + + function Document() { + parent :: SugarBean(); + $this->setupCustomFields('Documents'); //parameter is module name + $this->disable_row_level_security = false; + } + + function save($check_notify = false) { + + if (empty($this->doc_type)) { + $this->doc_type = 'Sugar'; + } + if (empty($this->id) || $this->new_with_id) + { + if (empty($this->id)) { + $this->id = create_guid(); + $this->new_with_id = true; + } + + if ( isset($_REQUEST) && isset($_REQUEST['duplicateSave']) && $_REQUEST['duplicateSave'] == true && isset($_REQUEST['filename_old_doctype']) ) { + $this->doc_type = $_REQUEST['filename_old_doctype']; + $isDuplicate = true; + } else { + $isDuplicate = false; + } + + $Revision = new DocumentRevision(); + //save revision. + $Revision->in_workflow = true; + $Revision->not_use_rel_in_req = true; + $Revision->new_rel_id = $this->id; + $Revision->new_rel_relname = 'Documents'; + $Revision->change_log = translate('DEF_CREATE_LOG','Documents'); + $Revision->revision = $this->revision; + $Revision->document_id = $this->id; + $Revision->filename = $this->filename; + + if(isset($this->file_ext)) + { + $Revision->file_ext = $this->file_ext; + } + + if(isset($this->file_mime_type)) + { + $Revision->file_mime_type = $this->file_mime_type; + } + + $Revision->doc_type = $this->doc_type; + $Revision->doc_id = $this->doc_id; + $Revision->doc_url = $this->doc_url; + $Revision->save(); + + //Move file saved during populatefrompost to match the revision id rather than document id + if (!empty($_FILES['filename_file'])) { + rename(UploadFile :: get_url($this->filename, $this->id), UploadFile :: get_url($this->filename, $Revision->id)); + } else if ( $isDuplicate && ( empty($this->doc_type) || $this->doc_type == 'Sugar' ) ) { + // Looks like we need to duplicate a file, this is tricky + $oldDocument = new Document(); + $oldDocument->retrieve($_REQUEST['duplicateId']); + $GLOBALS['log']->debug('Attempting to copy from '.UploadFile :: get_url($this->filename, $oldDocument->document_revision_id).' to '.UploadFile :: get_url($this->filename, $Revision->id)); + copy(UploadFile :: get_url($this->filename, $oldDocument->document_revision_id), UploadFile :: get_url($this->filename, $Revision->id)); + } + //update document with latest revision id + $this->process_save_dates=false; //make sure that conversion does not happen again. + $this->document_revision_id = $Revision->id; + + + //set relationship field values if contract_id is passed (via subpanel create) + if (!empty($_POST['contract_id'])) { + $save_revision['document_revision_id']=$this->document_revision_id; + $this->load_relationship('contracts'); + $this->contracts->add($_POST['contract_id'],$save_revision); + } + + if ((isset($_POST['load_signed_id']) and !empty($_POST['load_signed_id']))) { + $query="update linked_documents set deleted=1 where id='".$_POST['load_signed_id']."'"; + $this->db->query($query); + } + } + + return parent :: save($check_notify); + } + function get_summary_text() { + return "$this->document_name"; + } + + function is_authenticated() { + return $this->authenticated; + } + + function fill_in_additional_list_fields() { + $this->fill_in_additional_detail_fields(); + } + + function fill_in_additional_detail_fields() { + global $theme; + global $current_language; + global $timedate; + global $locale; + + parent::fill_in_additional_detail_fields(); + + $mod_strings = return_module_language($current_language, 'Documents'); + + $query = "SELECT users.first_name AS first_name, users.last_name AS last_name, document_revisions.date_entered AS rev_date, document_revisions.filename AS filename, document_revisions.revision AS revision, document_revisions.file_ext AS file_ext FROM users, document_revisions WHERE users.id = document_revisions.created_by AND document_revisions.id = '$this->document_revision_id'"; + $result = $this->db->query($query); + $row = $this->db->fetchByAssoc($result); + + //popuplate filename + if(isset($row['filename']))$this->filename = $row['filename']; + //$this->latest_revision = $row['revision']; + if(isset($row['revision']))$this->revision = $row['revision']; + + //populate the file url. + //image is selected based on the extension name _icon_inline, extension is stored in document_revisions. + //if file is not found then default image file will be used. + global $img_name; + global $img_name_bare; + if (!empty ($row['file_ext'])) { + $img_name = SugarThemeRegistry::current()->getImageURL(strtolower($row['file_ext'])."_image_inline.gif"); + $img_name_bare = strtolower($row['file_ext'])."_image_inline"; + } + + //set default file name. + if (!empty ($img_name) && file_exists($img_name)) { + $img_name = $img_name_bare; + } else { + $img_name = "def_image_inline"; //todo change the default image. + } + if($this->ACLAccess('DetailView')){ + $file_url = "".SugarThemeRegistry::current()->getImage($img_name, 'alt="'.$mod_strings['LBL_LIST_VIEW_DOCUMENT'].'" border="0"').""; + + if(!empty($this->doc_type) && $this->doc_type != 'Sugar' && !empty($this->doc_url)) + $file_url= "".SugarThemeRegistry::current()->getImage($this->doc_type.'_image_inline', 'alt="'.$mod_strings['LBL_LIST_VIEW_DOCUMENT'].'" border="0"',null,null,'.png').""; + $this->file_url = $file_url; + $this->file_url_noimage = basename(UploadFile :: get_url($this->filename, $this->document_revision_id)); + }else{ + $this->file_url = ""; + $this->file_url_noimage = ""; + } + + //get last_rev_by user name. + if (!empty ($row)) { + $this->last_rev_created_name = $locale->getLocaleFormattedName($row['first_name'], $row['last_name']); + + $this->last_rev_create_date = $timedate->to_display_date_time($row['rev_date']); + } + + global $app_list_strings; + if(!empty($this->status_id)) { + //_pp($this->status_id); + $this->status = $app_list_strings['document_status_dom'][$this->status_id]; + } + $this->related_doc_name = Document::get_document_name($this->related_doc_id); + $this->related_doc_rev_number = DocumentRevision::get_document_revision_name($this->related_doc_rev_id); + $this->save_file = basename($this->file_url_noimage); + + } + + function list_view_parse_additional_sections(& $list_form, $xTemplateSection) { + return $list_form; + } + + function create_export_query(&$order_by, &$where, $relate_link_join='') + { + $custom_join = $this->custom_fields->getJOIN(true, true,$where); + if($custom_join) + $custom_join['join'] .= $relate_link_join; + $query = "SELECT + documents.*"; + if($custom_join){ + $query .= $custom_join['select']; + } + $query .= " FROM documents "; + if($custom_join){ + $query .= $custom_join['join']; + } + + $where_auto = " documents.deleted = 0"; + + if ($where != "") + $query .= " WHERE $where AND ".$where_auto; + else + $query .= " WHERE ".$where_auto; + + if ($order_by != "") + $query .= " ORDER BY $order_by"; + else + $query .= " ORDER BY documents.document_name"; + + return $query; + } + + function get_list_view_data() { + global $current_language; + $app_list_strings = return_app_list_strings_language($current_language); + + $document_fields = $this->get_list_view_array(); + + $this->fill_in_additional_list_fields(); + + + $document_fields['FILENAME'] = $this->filename; + $document_fields['FILE_URL'] = $this->file_url; + $document_fields['FILE_URL_NOIMAGE'] = $this->file_url_noimage; + $document_fields['LAST_REV_CREATED_BY'] = $this->last_rev_created_name; + $document_fields['CATEGORY_ID'] = empty ($this->category_id) ? "" : $app_list_strings['document_category_dom'][$this->category_id]; + $document_fields['SUBCATEGORY_ID'] = empty ($this->subcategory_id) ? "" : $app_list_strings['document_subcategory_dom'][$this->subcategory_id]; + $document_fields['NAME'] = $this->document_name; + $document_fields['DOCUMENT_NAME_JAVASCRIPT'] = $GLOBALS['db']->helper->escape_quote($document_fields['DOCUMENT_NAME']); + return $document_fields; + } + function mark_relationships_deleted($id) { + //do nothing, this call is here to avoid default delete processing since + //delete.php handles deletion of document revisions. + } + + function bean_implements($interface) { + switch ($interface) { + case 'ACL' : + return true; + } + return false; + } + + //static function. + function get_document_name($doc_id){ + if (empty($doc_id)) return null; + + $db = DBManagerFactory::getInstance(); + $query="select document_name from documents where id='$doc_id'"; + $result=$db->query($query); + if (!empty($result)) { + $row=$db->fetchByAssoc($result); + if (!empty($row)) { + return $row['document_name']; + } + } + return null; + } +} + +require_once('modules/Documents/DocumentExternalApiDropDown.php'); + diff --git a/modules/Documents/DocumentExternalApiDropDown.php b/modules/Documents/DocumentExternalApiDropDown.php new file mode 100644 index 00000000..81bca083 --- /dev/null +++ b/modules/Documents/DocumentExternalApiDropDown.php @@ -0,0 +1,51 @@ +$GLOBALS['app_list_strings']['eapm_list']['Sugar']),$apiList); + if(!empty($value) && empty($apiList[$value])){ + $apiList[$value] = $value; + } + return $apiList; + +} + diff --git a/modules/Documents/DocumentSoap.php b/modules/Documents/DocumentSoap.php new file mode 100644 index 00000000..649d224a --- /dev/null +++ b/modules/Documents/DocumentSoap.php @@ -0,0 +1,92 @@ +upload_file = new UploadFile('filename_file'); + } + + function saveFile($document, $portal = false){ + global $sugar_config; + + $focus = new Document(); + + + + if(!empty($document['id'])){ + $focus->retrieve($document['id']); + }else{ + return '-1'; + } + + if(!empty($document['file'])){ + $decodedFile = base64_decode($document['file']); + $this->upload_file->set_for_soap($document['filename'], $decodedFile); + + $ext_pos = strrpos($this->upload_file->stored_file_name, "."); + $this->upload_file->file_ext = substr($this->upload_file->stored_file_name, $ext_pos + 1); + if (in_array($this->upload_file->file_ext, $sugar_config['upload_badext'])) { + $this->upload_file->stored_file_name .= ".txt"; + $this->upload_file->file_ext = "txt"; + } + + $revision = new DocumentRevision(); + $revision->filename = $this->upload_file->get_stored_file_name(); + $revision->file_mime_type = $this->upload_file->getMimeSoap($revision->filename); + $revision->file_ext = $this->upload_file->file_ext; + //$revision->document_name = ; + $revision->revision = $document['revision']; + $revision->document_id = $document['id']; + $revision->save(); + + $focus->document_revision_id = $revision->id; + $focus->save(); + $return_id = $revision->id; + $this->upload_file->final_move($revision->id); + }else{ + return '-1'; + } + return $return_id; + } +} +?> \ No newline at end of file diff --git a/modules/Documents/GetLatestRevision.php b/modules/Documents/GetLatestRevision.php new file mode 100644 index 00000000..c166026f --- /dev/null +++ b/modules/Documents/GetLatestRevision.php @@ -0,0 +1,53 @@ +retrieve($_REQUEST['record']); + if (!empty($document->document_revision_id) && !empty($_REQUEST['get_latest_for_id'])) { + $query="update linked_documents set document_revision_id='{$document->document_revision_id}', date_modified='".TimeDate::getInstance()->nowDb()."' where id ='{$_REQUEST['get_latest_for_id']}' "; + $document->db->query($query); + } +} +handleRedirect(); +?> diff --git a/modules/Documents/Menu.php b/modules/Documents/Menu.php new file mode 100644 index 00000000..d7b68d98 --- /dev/null +++ b/modules/Documents/Menu.php @@ -0,0 +1,61 @@ +retrieveSettings(); + $user_merge = $current_user->getPreference('mailmerge_on'); + if ($user_merge == 'on' && isset($admin->settings['system_mailmerge_on']) && $admin->settings['system_mailmerge_on']){ + $module_menu[]=Array("index.php?module=MailMerge&action=index&reset=true", $mod_strings['LNK_NEW_MAIL_MERGE'],"Documents"); + } +} +?> diff --git a/modules/Documents/Popup.php b/modules/Documents/Popup.php new file mode 100644 index 00000000..64fc0292 --- /dev/null +++ b/modules/Documents/Popup.php @@ -0,0 +1,47 @@ +process_page(); + +?> \ No newline at end of file diff --git a/modules/Documents/Popup_picker.html b/modules/Documents/Popup_picker.html new file mode 100644 index 00000000..25f16d24 --- /dev/null +++ b/modules/Documents/Popup_picker.html @@ -0,0 +1,184 @@ + + + + + + + + +
    + +
    + + + + +{SITEURL} +{TREEHEADER} +{SET_RETURN_JS} + + + + + + + + +
    +
    + {TREEINSTANCE} +
    +
    + + + + + + + +{PAGINATION} + + + + + + + + + + + + + + +
    {MOD.LBL_LIST_DOCUMENT}{arrow_start}{name_arrow}{arrow_end}{MOD.LBL_LIST_REVISION}{MOD.LBL_LIST_STATUS}
    {DOCUMENT.DOCUMENT_NAME}{DOCUMENT.LATEST_REVISION}{DOCUMENT.STATUS_ID}
    +{ASSOCIATED_JAVASCRIPT_DATA} + \ No newline at end of file diff --git a/modules/Documents/Popup_picker.php b/modules/Documents/Popup_picker.php new file mode 100644 index 00000000..d6bfeee5 --- /dev/null +++ b/modules/Documents/Popup_picker.php @@ -0,0 +1,220 @@ +assign('MOD', $mod_strings); + $form->assign('APP', $app_strings); + $form->assign('THEME', $theme); + $form->assign('MODULE_NAME', $currentModule); + + //tree header. + $doctree=new Tree('doctree'); + $doctree->set_param('module','Documents'); + if ($b_from_documents) { + $doctree->set_param('caller','Documents'); + $href_string = "javascript:populate_parent_search('doctree')"; + } else { + $href_string = "javascript:populate_search('doctree')"; + } + + $nodes=get_category_nodes($href_string); + foreach ($nodes as $node) { + $doctree->add_node($node); + } + $form->assign("TREEHEADER",$doctree->generate_header()); + $form->assign("TREEINSTANCE",$doctree->generate_nodes_array()); + + $site_data = "\n"; + $form->assign("SITEURL",$site_data); + + $form->parse('main.SearchHeader.TreeView'); + $treehtml = $form->text('main.SearchHeader.TreeView'); + $form->reset('main.SearchHeader.TreeView'); + //end tree + + if (isset($_REQUEST['caller']) && $_REQUEST['caller']=='Documents') { + ///process treeview and return. + return insert_popup_header($theme).$treehtml.insert_popup_footer(); + } + + ////////////////////////process full search form and list view.////////////////////////////// + $output_html = ''; + $where = ''; + $where = $this->_get_where_clause(); + + + $name = empty($_REQUEST['name']) ? '' : $_REQUEST['name']; + $document_name = empty($_REQUEST['document_name']) ? '' : $_REQUEST['document_name']; + $category_id = empty($_REQUEST['category_id']) ? '' : $_REQUEST['category_id']; + $subcategory_id = empty($_REQUEST['subcategory_id']) ? '' : $_REQUEST['subcategory_id']; + $template_type = empty($_REQUEST['template_type']) ? '' : $_REQUEST['template_type']; + $is_template = empty($_REQUEST['is_template']) ? '' : $_REQUEST['is_template']; + $request_data = empty($_REQUEST['request_data']) ? '' : $_REQUEST['request_data']; + + + $hide_clear_button = empty($_REQUEST['hide_clear_button']) ? false : true; + $button = "
    \n"; + if(!$hide_clear_button) + { + $button .= "\n"; + } + $button .= "\n"; + $button .= "
    \n"; + + $form->assign('NAME', $name); + $form->assign('DOCUMENT_NAME', $document_name); + $form->assign('request_data', $request_data); + $form->assign("CATEGORY_OPTIONS", get_select_options_with_id($app_list_strings['document_category_dom'], $category_id)); + $form->assign("SUB_CATEGORY_OPTIONS", get_select_options_with_id($app_list_strings['document_subcategory_dom'], $subcategory_id)); + $form->assign("IS_TEMPLATE_OPTIONS", get_select_options_with_id($app_list_strings['checkbox_dom'], $is_template)); + $form->assign("TEMPLATE_TYPE_OPTIONS", get_select_options_with_id($app_list_strings['document_template_type_dom'], $template_type)); + + + ob_start(); + insert_popup_header($theme); + $output_html .= ob_get_contents(); + ob_end_clean(); + + $output_html .= get_form_header($mod_strings['LBL_SEARCH_FORM_TITLE'], '', false); + + $form->parse('main.SearchHeader'); + $output_html .= $form->text('main.SearchHeader'); + + // Reset the sections that are already in the page so that they do not print again later. + $form->reset('main.SearchHeader'); + + //add tree view to output_html. + $output_html .= $treehtml; + + // create the listview + $seed_bean = new Document(); + $ListView = new ListView(); + $ListView->show_select_menu = false; + $ListView->show_delete_button = false; + $ListView->show_export_button = false; + $ListView->process_for_popups = true; + $ListView->setXTemplate($form); + $ListView->setHeaderTitle($mod_strings['LBL_LIST_FORM_TITLE']); + $ListView->setHeaderText($button); + $ListView->setQuery($where, '', 'document_name', 'DOCUMENT'); + $ListView->setModStrings($mod_strings); + + ob_start(); + $ListView->processListView($seed_bean, 'main', 'DOCUMENT'); + $output_html .= ob_get_contents(); + ob_end_clean(); + + $output_html .= insert_popup_footer(); + return $output_html; + } +} // end of class Popup_Picker +?> \ No newline at end of file diff --git a/modules/Documents/TreeData.php b/modules/Documents/TreeData.php new file mode 100644 index 00000000..9e8dd4cb --- /dev/null +++ b/modules/Documents/TreeData.php @@ -0,0 +1,140 @@ +get_definition(); + } + $json = new JSON(JSON_LOOSE_TYPE); + $str=$json->encode($ret); + return $str; +} + +/* + * + * + */ + function get_category_nodes($href_string){ + $nodes=array(); + global $mod_strings; + global $app_list_strings; + $query="select distinct category_id, subcategory_id from documents where deleted=0 order by category_id, subcategory_id"; + $result=$GLOBALS['db']->query($query); + $current_cat_id=null; + $cat_node=null; + while (($row=$GLOBALS['db']->fetchByAssoc($result))!= null) { + + if (empty($row['category_id'])) { + $cat_id='null'; + $cat_name=$mod_strings['LBL_CAT_OR_SUBCAT_UNSPEC']; + } else { + $cat_id=$row['category_id']; + $cat_name=$app_list_strings['document_category_dom'][$row['category_id']]; + } + if (empty($current_cat_id) or $current_cat_id != $cat_id) { + $current_cat_id = $cat_id; + if (!empty($cat_node)) $nodes[]=$cat_node; + + $cat_node = new Node($cat_id, $cat_name); + $cat_node->set_property("href", $href_string); + $cat_node->expanded = true; + $cat_node->dynamic_load = false; + } + + if (empty($row['subcategory_id'])) { + $subcat_id='null'; + $subcat_name=$mod_strings['LBL_CAT_OR_SUBCAT_UNSPEC']; + } else { + $subcat_id=$row['subcategory_id']; + $subcat_name=$app_list_strings['document_subcategory_dom'][$row['subcategory_id']]; + } + $subcat_node = new Node($subcat_id, $subcat_name); + $subcat_node->set_property("href", $href_string); + $subcat_node->expanded = false; + $subcat_node->dynamic_load = true; + + $cat_node->add_node($subcat_node); + } + if (!empty($cat_node)) $nodes[]=$cat_node; + + return $nodes; + } + +function get_documents($cat_id, $subcat_id,$href=true) { + $nodes=array(); + $href_string = "javascript:select_document('doctree')"; + $query="select * from documents where deleted=0"; + if ($cat_id != 'null') { + $query.=" and category_id='$cat_id'"; + } else { + $query.=" and category_id is null"; + } + + if ($subcat_id != 'null') { + $query.=" and subcategory_id='$subcat_id'"; + } else { + $query.=" and subcategory_id is null"; + } + $result=$GLOBALS['db']->query($query); + $current_cat_id=null; + while (($row=$GLOBALS['db']->fetchByAssoc($result))!= null) { + $node = new Node($row['id'], $row['document_name']); + if ($href) { + $node->set_property("href", $href_string); + } + $node->expanded = true; + $node->dynamic_load = false; + + $nodes[]=$node; + } + return $nodes; +} +?> diff --git a/modules/Documents/action_view_map.php b/modules/Documents/action_view_map.php new file mode 100644 index 00000000..ca3f53c6 --- /dev/null +++ b/modules/Documents/action_view_map.php @@ -0,0 +1,38 @@ +");displayValue=displayValue.replace('<',"<");displayValue=displayValue.replace('" ',"\"");if(the_key=='related_doc_id'){related_doc_id=displayValue;} +window.document.forms[form_name].elements[the_key].value=displayValue;}} +related_doc_id=JSON.stringifyNoSecurity(related_doc_id);var conditions=new Array();conditions[conditions.length]={"name":"document_id","op":"starts_with","value":related_doc_id};var query=new Array();var query={"module":"DocumentRevisions","field_list":['id','revision','date_entered'],"conditions":conditions,"order":'date_entered desc'};result=global_rpcClient.call_method('query',query,true);rhandle.display(result);} +function RevisionListHandler(){} +RevisionListHandler.prototype.display=function(result){var names=result['list'];var rev_tag=document.getElementById('related_doc_rev_id');rev_tag.options.length=0;for(i=0;i Array("id" + ,"document_name" + ,"description" + ,"category_id" + ,"subcategory_id" + ,"status_id" + ,"active_date" + ,"exp_date" + ,"date_entered" + ,"date_modified" + ,"created_by" + ,"modified_user_id" + ,"document_revision_id" + ,"related_doc_id" + ,"related_doc_rev_id" + ,"is_template" + ,"template_type" + ), + 'list_fields' => Array("id" + ,"document_name" + ,"description" + ,"category_id" + ,"subcategory_id" + ,"status_id" + ,"active_date" + ,"exp_date" + ,"date_entered" + ,"date_modified" + ,"created_by" + ,"modified_user_id" + ,"document_revision_id" + ,"last_rev_create_date" + ,"last_rev_created_by" + ,"latest_revision" + ,"file_url" + ,"file_url_noimage" + ), + 'required_fields' => Array("document_name"=>1,"active_date"=>1,"revision"=>1), +); +?> \ No newline at end of file diff --git a/modules/Documents/language/en_us.lang.php b/modules/Documents/language/en_us.lang.php new file mode 100644 index 00000000..c41f1a66 --- /dev/null +++ b/modules/Documents/language/en_us.lang.php @@ -0,0 +1,190 @@ + 'Documents', + 'LBL_MODULE_TITLE' => 'Documents: Home', + 'LNK_NEW_DOCUMENT' => 'Create Document', + 'LNK_DOCUMENT_LIST'=> 'View Documents', + 'LBL_DOC_REV_HEADER' => 'Document Revisions', + 'LBL_SEARCH_FORM_TITLE'=> 'Document Search', + //vardef labels + 'LBL_DOCUMENT_ID' => 'Document ID', + 'LBL_NAME' => 'Document Name', + 'LBL_DESCRIPTION' => 'Description', + 'LBL_CATEGORY' => 'Category', + 'LBL_SUBCATEGORY' => 'Sub Category', + 'LBL_STATUS' => 'Status', + 'LBL_CREATED_BY'=> 'Created by', + 'LBL_DATE_ENTERED'=> 'Date Created', + 'LBL_DATE_MODIFIED'=> 'Date Modified', + 'LBL_DELETED' => 'Deleted', + 'LBL_MODIFIED'=> 'Modified by ID', + 'LBL_MODIFIED_USER' => 'Modified by', + 'LBL_CREATED'=> 'Created by', + 'LBL_REVISIONS'=>'Revisions', + 'LBL_RELATED_DOCUMENT_ID'=>'Related Document ID', + 'LBL_RELATED_DOCUMENT_REVISION_ID'=>'Related Document Revision ID', + 'LBL_IS_TEMPLATE'=>'Is a Template', + 'LBL_TEMPLATE_TYPE'=>'Document Type', + 'LBL_ASSIGNED_TO_NAME'=>'Assigned to:', + 'LBL_REVISION_NAME' => 'Revision Number', + 'LBL_MIME' => 'Mime Type', + 'LBL_REVISION' => 'Revision', + 'LBL_DOCUMENT' => 'Related Document', + 'LBL_LATEST_REVISION' => 'Latest Revision', + 'LBL_CHANGE_LOG'=> 'Change Log', + 'LBL_ACTIVE_DATE'=> 'Publish Date', + 'LBL_EXPIRATION_DATE' => 'Expiration Date', + 'LBL_FILE_EXTENSION' => 'File Extension', + 'LBL_LAST_REV_MIME_TYPE' => 'Last revision MIME type', + 'LBL_CAT_OR_SUBCAT_UNSPEC'=>'Unspecified', + 'LBL_HOMEPAGE_TITLE' => 'My Documents', + //quick search + 'LBL_NEW_FORM_TITLE' => 'New Document', + //document edit and detail view + 'LBL_DOC_NAME' => 'Document Name:', + 'LBL_FILENAME' => 'File Name:', + 'LBL_LIST_FILENAME' => 'File:', + 'LBL_DOC_VERSION' => 'Revision:', + 'LBL_FILE_UPLOAD' => 'File:', + + 'LBL_CATEGORY_VALUE' => 'Category:', + 'LBL_LIST_CATEGORY' => 'Category', + 'LBL_SUBCATEGORY_VALUE'=> 'Sub Category:', + 'LBL_DOC_STATUS'=> 'Status:', + 'LBL_LAST_REV_CREATOR' => 'Revision Created By:', + 'LBL_LASTEST_REVISION_NAME' => 'Lastest revision name:', + 'LBL_SELECTED_REVISION_NAME' => 'Selected revision name:', + 'LBL_CONTRACT_STATUS' => 'Contract status:', + 'LBL_CONTRACT_NAME' => 'Contract name:', + 'LBL_LAST_REV_DATE' => 'Revision Date:', + 'LBL_DOWNNLOAD_FILE'=> 'Download File:', + 'LBL_DET_RELATED_DOCUMENT'=>'Related Document:', + 'LBL_DET_RELATED_DOCUMENT_VERSION'=>"Related Document Revision:", + 'LBL_DET_IS_TEMPLATE'=>'Template? :', + 'LBL_DET_TEMPLATE_TYPE'=>'Document Type:', + 'LBL_DOC_DESCRIPTION'=>'Description:', + 'LBL_DOC_ACTIVE_DATE'=> 'Publish Date:', + 'LBL_DOC_EXP_DATE'=> 'Expiration Date:', + + //document list view. + 'LBL_LIST_FORM_TITLE' => 'Document List', + 'LBL_LIST_DOCUMENT' => 'Document', + 'LBL_LIST_CATEGORY' => 'Category', + 'LBL_LIST_SUBCATEGORY' => 'Sub Category', + 'LBL_LIST_REVISION' => 'Revision', + 'LBL_LIST_LAST_REV_CREATOR' => 'Published By', + 'LBL_LIST_LAST_REV_DATE' => 'Revision Date', + 'LBL_LIST_VIEW_DOCUMENT'=>'View', + 'LBL_LIST_DOWNLOAD'=> 'Download', + 'LBL_LIST_ACTIVE_DATE' => 'Publish Date', + 'LBL_LIST_EXP_DATE' => 'Expiration Date', + 'LBL_LIST_STATUS'=>'Status', + 'LBL_LINKED_ID' => 'Linked id', + 'LBL_SELECTED_REVISION_ID' => 'Selected revision id', + 'LBL_LATEST_REVISION_ID' => 'Latest revision id', + 'LBL_SELECTED_REVISION_FILENAME' => 'Selected revision filename', + 'LBL_FILE_URL' => 'File url', + 'LBL_REVISIONS_PANEL' => 'Revision Details', + 'LBL_REVISIONS_SUBPANEL' => 'Revisions', + + //document search form. + 'LBL_SF_DOCUMENT' => 'Document Name:', + 'LBL_SF_CATEGORY' => 'Category:', + 'LBL_SF_SUBCATEGORY'=> 'Sub Category:', + 'LBL_SF_ACTIVE_DATE' => 'Publish Date:', + 'LBL_SF_EXP_DATE'=> 'Expiration Date:', + + 'DEF_CREATE_LOG' => 'Document Created', + + //error messages + 'ERR_DOC_NAME'=>'Document Name', + 'ERR_DOC_ACTIVE_DATE'=>'Publish Date', + 'ERR_DOC_EXP_DATE'=> 'Expiration Date', + 'ERR_FILENAME'=> 'File Name', + 'ERR_DOC_VERSION'=> 'Document Version', + 'ERR_DELETE_CONFIRM'=> 'Do you want to delete this document revision?', + 'ERR_DELETE_LATEST_VERSION'=> 'You are not allowed to delete the latest revision of a document.', + 'LNK_NEW_MAIL_MERGE' => 'Mail Merge', + 'LBL_MAIL_MERGE_DOCUMENT' => 'Mail Merge Template:', + + 'LBL_TREE_TITLE' => 'Documents', + //sub-panel vardefs. + 'LBL_LIST_DOCUMENT_NAME'=>'Name', + 'LBL_CONTRACT_NAME'=>'Contract Name:', + 'LBL_LIST_IS_TEMPLATE'=>'Template?', + 'LBL_LIST_TEMPLATE_TYPE'=>'Document Type', + 'LBL_LIST_SELECTED_REVISION'=>'Selected Revision', + 'LBL_LIST_LATEST_REVISION'=>'Latest Revision', + 'LBL_CONTRACTS_SUBPANEL_TITLE'=>'Related Contracts', + 'LBL_LAST_REV_CREATE_DATE'=>'Last Revision Create Date', + //'LNK_DOCUMENT_CAT'=>'Document Categories', + 'LBL_CONTRACTS' => 'Contracts', + 'LBL_CREATED_USER' => 'Created User', + 'LBL_THEREVISIONS_SUBPANEL_TITLE' => 'Reversions', + 'LBL_DOCUMENT_INFORMATION' => 'Document Overview', + 'LBL_DOC_ID' => 'Document Source ID', + 'LBL_DOC_TYPE' => 'Source', + 'LBL_LIST_DOC_TYPE' => 'Source', + 'LBL_DOC_TYPE_POPUP' => 'Select a source to which this document will be uploaded
    and from which it will be available.', + 'LBL_DOC_URL' => 'Document Source URL', + 'LBL_SEARCH_EXTERNAL_DOCUMENT' => 'File Name', + 'LBL_EXTERNAL_DOCUMENT_NOTE' => 'The first 20 most recently modified files are displayed in descending order in the list below. Use the Search to find other files.', + 'LBL_LIST_EXT_DOCUMENT_NAME' => 'File Name', + + // Links around the world + 'LBL_ACCOUNTS_SUBPANEL_TITLE' => 'Accounts', + 'LBL_CONTACTS_SUBPANEL_TITLE' => 'Contacts', + 'LBL_OPPORTUNITIES_SUBPANEL_TITLE' => 'Opportunities', + 'LBL_CASES_SUBPANEL_TITLE' => 'Cases', + 'LBL_BUGS_SUBPANEL_TITLE' => 'Bugs', + 'LBL_QUOTES_SUBPANEL_TITLE' => 'Quotes', + 'LBL_PRODUCTS_SUBPANEL_TITLE' => 'Products', +); + + +?> diff --git a/modules/Documents/metadata/SearchFields.php b/modules/Documents/metadata/SearchFields.php new file mode 100644 index 00000000..97e76d3c --- /dev/null +++ b/modules/Documents/metadata/SearchFields.php @@ -0,0 +1,55 @@ + array( 'query_type'=>'default'), + 'category_id'=> array('query_type'=>'default', 'options' => 'document_category_dom', 'template_var' => 'CATEGORY_OPTIONS'), + 'subcategory_id'=> array('query_type'=>'default', 'options' => 'document_subcategory_dom', 'template_var' => 'SUBCATEGORY_OPTIONS'), + 'active_date'=> array('query_type'=>'default'), + 'exp_date'=> array('query_type'=>'default'), + 'assigned_user_id'=> array('query_type'=>'default'), + //Range Search Support + 'range_date_entered' => array ('query_type' => 'default', 'enable_range_search' => true, 'is_date_field' => true), + 'start_range_date_entered' => array ('query_type' => 'default', 'enable_range_search' => true, 'is_date_field' => true), + 'end_range_date_entered' => array ('query_type' => 'default', 'enable_range_search' => true, 'is_date_field' => true), + 'range_date_modified' => array ('query_type' => 'default', 'enable_range_search' => true, 'is_date_field' => true), + 'start_range_date_modified' => array ('query_type' => 'default', 'enable_range_search' => true, 'is_date_field' => true), + 'end_range_date_modified' => array ('query_type' => 'default', 'enable_range_search' => true, 'is_date_field' => true), + //Range Search Support + ); +?> diff --git a/modules/Documents/metadata/detailviewdefs.php b/modules/Documents/metadata/detailviewdefs.php new file mode 100644 index 00000000..b71ed70e --- /dev/null +++ b/modules/Documents/metadata/detailviewdefs.php @@ -0,0 +1,120 @@ + array('maxColumns' => '2', + 'form' => array('hidden'=>array('')), + 'widths' => array( + array('label' => '10', 'field' => '30'), + array('label' => '10', 'field' => '30') + ), + ), +'panels' => + array ( + 'lbl_document_information' => + array ( + array ( + 'filename', + 'status', + ), + + array ( + array ( + 'name' => 'document_name', + 'label' => 'LBL_DOC_NAME', + ), + array ( + 'name' => 'revision', + 'label' => 'LBL_DOC_VERSION', + ), + ), + + array ( + array ( + 'name' => 'template_type', + 'label' => 'LBL_DET_TEMPLATE_TYPE', + ), + array ( + 'name' => 'is_template', + 'label' => 'LBL_DET_IS_TEMPLATE', + ), + ), + + array ( + 'active_date', + 'category_id', + ), + + array ( + 'exp_date', + 'subcategory_id', + ), + + array ( + array ( + 'name' => 'description', + 'label' => 'LBL_DOC_DESCRIPTION', + ), + ), + + array ( + 'related_doc_name', + 'related_doc_rev_number', + ), + + + + ), + 'LBL_REVISIONS_PANEL' => + array ( + array ( + 0 => 'last_rev_created_name', + 1 => 'last_rev_create_date', + ), + ), + 'LBL_PANEL_ASSIGNMENT' => + array ( + array ( + array ( + 'name' => 'assigned_user_name', + 'label' => 'LBL_ASSIGNED_TO_NAME', + ), + ), + ), + ) + +); +?> \ No newline at end of file diff --git a/modules/Documents/metadata/editviewdefs.php b/modules/Documents/metadata/editviewdefs.php new file mode 100644 index 00000000..7bc68c88 --- /dev/null +++ b/modules/Documents/metadata/editviewdefs.php @@ -0,0 +1,128 @@ + array('form' => array('enctype'=>'multipart/form-data', + 'hidden'=>array('', + ''), + ), + 'maxColumns' => '2', + 'widths' => array( + array('label' => '10', 'field' => '30'), + array('label' => '10', 'field' => '30') + ), +'javascript' => ' + + + + + +', +), + 'panels' =>array ( + 'lbl_document_information' => + array ( + array ( + array( + 'name' => 'filename', + 'displayParams' => array('onchangeSetFileNameTo' => 'document_name'), + ), + array ( + 'name' => 'status_id', + 'label' => 'LBL_DOC_STATUS', + ), + ), + + array ( + 'document_name', + + array('name'=>'revision', + 'customCode' => '' + ), + + ), + + array ( + array ( + 'name' => 'template_type', + 'label' => 'LBL_DET_TEMPLATE_TYPE', + ), + array ( + 'name' => 'is_template', + 'label' => 'LBL_DET_IS_TEMPLATE', + ), + ), + + array ( + array('name'=>'active_date'), + 'category_id', + + ), + + array ( + 'exp_date', + 'subcategory_id', + ), + + array ( + array('name'=>'description'), + ), + + array ( + array('name'=>'related_doc_name', + 'customCode' => '' . + ' ' . + ''), + array('name'=>'related_doc_rev_number', + 'customCode' => '', + ), + ), + + ), + 'LBL_PANEL_ASSIGNMENT' => + array ( + array ( + array ( + 'name' => 'assigned_user_name', + 'label' => 'LBL_ASSIGNED_TO_NAME', + ), + ), + ), +) + + +); +?> \ No newline at end of file diff --git a/modules/Documents/metadata/listviewdefs.php b/modules/Documents/metadata/listviewdefs.php new file mode 100644 index 00000000..76ec70f4 --- /dev/null +++ b/modules/Documents/metadata/listviewdefs.php @@ -0,0 +1,122 @@ + + array ( + 'width' => '20%', + 'label' => 'LBL_NAME', + 'link' => true, + 'default' => true, + 'bold' => true, + ), + 'FILENAME' => + array ( + 'width' => '20%', + 'label' => 'LBL_FILENAME', + 'link' => true, + 'default' => true, + 'bold' => false, + 'displayParams' => array ( 'module' => 'Documents', ), + 'sortable' => false, + 'related_fields' => + array ( + 0 => 'document_revision_id', + 1 => 'doc_id', + 2 => 'doc_type', + 3 => 'doc_url', + ), + ), + 'CATEGORY_ID' => + array ( + 'width' => '10%', + 'label' => 'LBL_LIST_CATEGORY', + 'default' => true, + ), + 'SUBCATEGORY_ID' => + array ( + 'width' => '15%', + 'label' => 'LBL_LIST_SUBCATEGORY', + 'default' => true, + ), + 'LAST_REV_CREATE_DATE' => + array ( + 'width' => '10%', + 'label' => 'LBL_LIST_LAST_REV_DATE', + 'default' => true, + 'sortable' => false, + 'related_fields' => + array ( + 0 => 'document_revision_id', + ), + ), + 'EXP_DATE' => + array ( + 'width' => '10%', + 'label' => 'LBL_LIST_EXP_DATE', + 'default' => true, + ), + 'ASSIGNED_USER_NAME' => + array( + 'width' => '10', + 'label' => 'LBL_LIST_ASSIGNED_USER', + 'module' => 'Employees', + 'id' => 'ASSIGNED_USER_ID', + 'default' => true), + 'MODIFIED_BY_NAME' => + array ( + 'width' => '10%', + 'label' => 'LBL_MODIFIED_USER', + 'module' => 'Users', + 'id' => 'USERS_ID', + 'default' => false, + 'sortable' => false, + 'related_fields' => + array ( + 0 => 'modified_user_id', + ), + ), + 'DATE_ENTERED' => array ( + 'width' => '10%', + 'label' => 'LBL_DATE_ENTERED', + 'default' => true, + ) +); +?> \ No newline at end of file diff --git a/modules/Documents/metadata/quickcreatedefs.php b/modules/Documents/metadata/quickcreatedefs.php new file mode 100644 index 00000000..59f7d9bc --- /dev/null +++ b/modules/Documents/metadata/quickcreatedefs.php @@ -0,0 +1,89 @@ + array('form' => array('enctype'=>'multipart/form-data', + 'hidden'=>array('', + '', + '',)), + + 'maxColumns' => '2', + 'widths' => array( + array('label' => '10', 'field' => '30'), + array('label' => '10', 'field' => '30') + ), + 'includes' => + array ( + array('file' => 'include/javascript/popup_parent_helper.js'), + array('file' => 'include/jsolait/init.js'), + array('file' => 'include/jsolait/lib/urllib.js'), + array('file' => 'include/javascript/jsclass_base.js'), + array('file' => 'include/javascript/jsclass_async.js'), + array('file' => 'modules/Documents/documents.js'), + ), +), + 'panels' =>array ( + 'default' => + array ( + + array ( + 'status_id', + ), + array ( + array('name'=>'filename', + 'displayParams'=>array('required'=>true, 'onchangeSetFileNameTo' => 'document_name'), + ), + ), + + array ( + 'document_name', + 'revision' + ), + + array ( + array('name'=>'active_date','displayParams'=>array('required'=>true)), + 'category_id', + ), + + + array ( + array('name'=>'description', 'displayParams'=>array('rows'=>10, 'cols'=>120)), + ), + ), +) + +); +?> \ No newline at end of file diff --git a/modules/Documents/metadata/searchdefs.php b/modules/Documents/metadata/searchdefs.php new file mode 100644 index 00000000..efa6c5ea --- /dev/null +++ b/modules/Documents/metadata/searchdefs.php @@ -0,0 +1,74 @@ + array('maxColumns' => '3', + 'widths' => array('label' => '10', 'field' => '30'), + ), + 'layout' => array( + 'basic_search' => array( + 'document_name', + + ), + 'advanced_search' => array( + 'document_name', + 'category_id', + 'subcategory_id', + 'active_date', + 'exp_date', + 'assigned_user_id' => + array ( + 'name' => 'assigned_user_id', + 'type' => 'enum', + 'label' => 'LBL_ASSIGNED_TO', + 'function' => + array ( + 'name' => 'get_user_array', + 'params' => + array ( + 0 => false, + ), + ), + 'default' => true, + 'width' => '10%', + ), + + ), + ), + ); +?> diff --git a/modules/Documents/metadata/studio.php b/modules/Documents/metadata/studio.php new file mode 100644 index 00000000..05ccc62e --- /dev/null +++ b/modules/Documents/metadata/studio.php @@ -0,0 +1,66 @@ +array( + 'template'=>'xtpl', + 'template_file'=>'modules/Documents/DetailView.html', + 'php_file'=>'modules/Documents/DetailView.php', + 'type'=>'DetailView', + ), + 'LBL_EDITVIEW'=>array( + 'template'=>'xtpl', + 'template_file'=>'modules/Documents/EditView.html', + 'php_file'=>'modules/Documents/EditView.php', + 'type'=>'EditView', + ), + 'LBL_LISTVIEW'=>array( + 'template'=>'listview', + 'meta_file'=>'modules/Documents/listviewdefs.php', + 'type'=>'ListView', + ), + 'LBL_SEARCHFORM'=>array( + 'template'=>'xtpl', + 'template_file'=>'modules/Documents/SearchForm.html', + 'php_file'=>'modules/Documents/ListView.php', + 'type'=>'SearchForm', + ), + +); diff --git a/modules/Documents/metadata/subpaneldefs.php b/modules/Documents/metadata/subpaneldefs.php new file mode 100644 index 00000000..359f43b4 --- /dev/null +++ b/modules/Documents/metadata/subpaneldefs.php @@ -0,0 +1,178 @@ + array( + 'therevisions' => array( + 'order' => 10, + 'sort_order' => 'desc', + 'sort_by' => 'revision', + 'module' => 'DocumentRevisions', + 'subpanel_name' => 'default', + 'title_key' => 'LBL_DOC_REV_HEADER', + 'get_subpanel_data' => 'revisions', + 'fill_in_additional_fields'=>true, + ), + 'accounts' => array( + 'order' => 30, + 'module' => 'Accounts', + 'subpanel_name' => 'default', + 'sort_order' => 'asc', + 'sort_by' => 'id', + 'title_key' => 'LBL_ACCOUNTS_SUBPANEL_TITLE', + 'get_subpanel_data' => 'accounts', + 'top_buttons' => + array ( + 0 => + array ( + 'widget_class' => 'SubPanelTopButtonQuickCreate', + ), + 1 => + array ( + 'widget_class' => 'SubPanelTopSelectButton', + 'mode' => 'MultiSelect', + ), + ), + ), + 'contacts' => array( + 'order' => 40, + 'module' => 'Contacts', + 'subpanel_name' => 'default', + 'sort_order' => 'asc', + 'sort_by' => 'id', + 'title_key' => 'LBL_CONTACTS_SUBPANEL_TITLE', + 'get_subpanel_data' => 'contacts', + 'top_buttons' => + array ( + 0 => + array ( + 'widget_class' => 'SubPanelTopButtonQuickCreate', + ), + 1 => + array ( + 'widget_class' => 'SubPanelTopSelectButton', + 'mode' => 'MultiSelect', + ), + ), + ), + 'opportunities' => array( + 'order' => 40, + 'module' => 'Opportunities', + 'subpanel_name' => 'default', + 'sort_order' => 'asc', + 'sort_by' => 'id', + 'title_key' => 'LBL_OPPORTUNITIES_SUBPANEL_TITLE', + 'get_subpanel_data' => 'opportunities', + 'top_buttons' => + array ( + 0 => + array ( + 'widget_class' => 'SubPanelTopButtonQuickCreate', + ), + 1 => + array ( + 'widget_class' => 'SubPanelTopSelectButton', + 'mode' => 'MultiSelect', + ), + ), + ), + 'cases' => array( + 'order' => 50, + 'module' => 'Cases', + 'subpanel_name' => 'default', + 'sort_order' => 'asc', + 'sort_by' => 'id', + 'title_key' => 'LBL_CASES_SUBPANEL_TITLE', + 'get_subpanel_data' => 'cases', + 'top_buttons' => + array ( + 0 => + array ( + 'widget_class' => 'SubPanelTopButtonQuickCreate', + ), + 1 => + array ( + 'widget_class' => 'SubPanelTopSelectButton', + 'mode' => 'MultiSelect', + ), + ), + ), + 'bugs' => array( + 'order' => 60, + 'module' => 'Bugs', + 'subpanel_name' => 'default', + 'sort_order' => 'asc', + 'sort_by' => 'id', + 'title_key' => 'LBL_BUGS_SUBPANEL_TITLE', + 'get_subpanel_data' => 'bugs', + 'top_buttons' => + array ( + 0 => + array ( + 'widget_class' => 'SubPanelTopButtonQuickCreate', + ), + 1 => + array ( + 'widget_class' => 'SubPanelTopSelectButton', + 'mode' => 'MultiSelect', + ), + ), + ), + 'quotes' => array( + 'order' => 70, + 'module' => 'Quotes', + 'subpanel_name' => 'default', + 'sort_order' => 'asc', + 'sort_by' => 'id', + 'title_key' => 'LBL_QUOTES_SUBPANEL_TITLE', + 'get_subpanel_data' => 'quotes', + 'top_buttons' => + array ( + 0 => + array ( + 'widget_class' => 'SubPanelTopSelectButton', + 'mode' => 'MultiSelect', + ), + ), + ), + ), +); +?> \ No newline at end of file diff --git a/modules/Documents/metadata/subpanels/ForContractType.php b/modules/Documents/metadata/subpanels/ForContractType.php new file mode 100644 index 00000000..75474356 --- /dev/null +++ b/modules/Documents/metadata/subpanels/ForContractType.php @@ -0,0 +1,91 @@ + array( + array('widget_class' => 'SubPanelTopCreateButton'), + array('widget_class' => 'SubPanelTopSelectButton', 'popup_module' => 'Documents','field_to_name_array'=>array('document_revision_id'=>'REL_ATTRIBUTE_document_revision_id')), + ), + + 'where' => '', + + + + 'list_fields'=> array( + 'document_name'=> array( + 'name' => 'document_name', + 'vname' => 'LBL_LIST_DOCUMENT_NAME', + 'widget_class' => 'SubPanelDetailViewLink', + 'width' => '30%', + ), + 'is_template'=>array( + 'name' => 'is_template', + 'vname' => 'LBL_LIST_IS_TEMPLATE', + 'width' => '5%', + 'widget_type'=>'checkbox', + ), + 'template_type'=>array( + 'name' => 'template_types', + 'vname' => 'LBL_LIST_TEMPLATE_TYPE', + 'width' => '15%', + ), + 'latest_revision'=>array( + 'name' => 'latest_revision', + 'vname' => 'LBL_LATEST_REVISION', + 'width' => '10%', + 'sortable' => false + ), + 'edit_button'=>array( + 'vname' => 'LBL_EDIT_BUTTON', + 'widget_class' => 'SubPanelEditButton', + 'module' => 'Documents', + 'width' => '5%', + ), + 'remove_button'=>array( + 'vname' => 'LBL_REMOVE', + 'widget_class' => 'SubPanelRemoveButton', + 'module' => 'Documents', + 'width' => '5%', + ), + 'document_revision_id'=>array( + 'usage'=>'query_only' + ), + ), +); +?> \ No newline at end of file diff --git a/modules/Documents/metadata/subpanels/default.php b/modules/Documents/metadata/subpanels/default.php new file mode 100644 index 00000000..f1a6a6f6 --- /dev/null +++ b/modules/Documents/metadata/subpanels/default.php @@ -0,0 +1,111 @@ + array( + array('widget_class' => 'SubPanelTopCreateButton'), + array('widget_class' => 'SubPanelTopSelectButton', 'popup_module' => 'Documents','field_to_name_array'=>array('document_revision_id'=>'REL_ATTRIBUTE_document_revision_id')), + ), + + 'where' => '', + + + + 'list_fields'=> array( + 'object_image'=>array( + 'vname' => 'LBL_OBJECT_IMAGE', + 'widget_class' => 'SubPanelIcon', + 'width' => '2%', + 'image2'=>'attachment', + 'image2_url_field'=> array( + 'id_field' => 'id', + 'filename_field' => 'filename', + ), + 'attachment_image_only'=>true, + ), + 'document_name'=> array( + 'name' => 'document_name', + 'vname' => 'LBL_LIST_DOCUMENT_NAME', + 'widget_class' => 'SubPanelDetailViewLink', + 'width' => '20%', + ), + 'filename'=>array( + 'name' => 'filename', + 'vname' => 'LBL_LIST_FILENAME', + 'width' => '20%', + 'module' => 'Documents', + 'sortable'=>false, + 'displayParams' => array( + 'module' => 'Documents', + ), + ), + 'document_revision_id' => array( + 'name' => 'document_revision_id', + 'usage' => 'query_only', + ), + 'category_id'=>array( + 'name' => 'category_id', + 'vname' => 'LBL_LIST_CATEGORY', + 'width' => '20%', + ), + 'status_id'=>array( + 'name' => 'status_id', + 'vname' => 'LBL_LIST_STATUS', + 'width' => '10%', + ), + 'active_date'=>array( + 'name' => 'active_date', + 'vname' => 'LBL_LIST_ACTIVE_DATE', + 'width' => '10%', + ), + 'edit_button'=>array( + 'vname' => 'LBL_EDIT_BUTTON', + 'widget_class' => 'SubPanelEditButton', + 'module' => 'Documents', + 'width' => '5%', + ), + 'remove_button'=>array( + 'vname' => 'LBL_REMOVE', + 'widget_class' => 'SubPanelRemoveButton', + 'module' => 'Documents', + 'width' => '5%', + ), + ), +); +?> \ No newline at end of file diff --git a/modules/Documents/tpls/view.extdoc.tpl b/modules/Documents/tpls/view.extdoc.tpl new file mode 100644 index 00000000..4d992cd9 --- /dev/null +++ b/modules/Documents/tpls/view.extdoc.tpl @@ -0,0 +1,132 @@ +{* + +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + +*} + +
    +
    + + + + + + +
    +{$searchFieldLabel}:   + + + + +
    +
    +
    +
    {$displayedNote}
    + + + {counter start=0 name="colCounter" print=false assign="colCounter"} + {foreach from=$displayColumns key=colHeader item=params} + + {counter name="colCounter"} + {/foreach} + + + + {foreach name=rowIteration from=$data key=id item=rowData} + {counter name="offset" print=false} + + {if $smarty.foreach.rowIteration.iteration is odd} + {assign var='_rowColor' value=$rowColor[0]} + {else} + {assign var='_rowColor' value=$rowColor[1]} + {/if} + + {counter start=0 name="colCounter" print=false assign="colCounter"} + {foreach from=$displayColumns key=col item=params} + {strip} + + {/strip} + {counter name="colCounter"} + {/foreach} + + {foreachelse} + + + + {/foreach} +
    +
    + {sugar_translate label=$params.label module='Documents'} +
    +
     
    + {if $col == 'NAME' || $params.bold}{/if} + {if $params.link && !empty($rowData.DOC_URL) } + + {/if} + {sugar_field parentFieldArray=$rowData vardef=$params displayType=ListView field=$col} + {if empty($rowData.$col)} {/if} + {if $params.link && !empty($rowData.DOC_URL) } + + {/if} + {if $params.link && !empty($rowData.URL) } + + {/if} + {if $col == 'NAME' || $params.bold}{/if} +
    + {$APP.LBL_NO_DATA} +
    diff --git a/modules/Documents/vardefs.php b/modules/Documents/vardefs.php new file mode 100644 index 00000000..55d922fc --- /dev/null +++ b/modules/Documents/vardefs.php @@ -0,0 +1,433 @@ + 'documents', + 'unified_search' => true, + 'unified_search_default_enabled' => true, + 'fields' => array ( + + 'document_name' => + array ( + 'name' => 'document_name', + 'vname' => 'LBL_NAME', + 'type' => 'varchar', + 'len' => '255', + 'required'=>true, + 'importable' => 'required', + 'unified_search' => true, + ), + 'name'=> + array('name'=>'name', 'vname' => 'LBL_NAME', 'source'=>'non-db', 'type'=>'varchar'), +'doc_id' => + array ( + 'name' => 'doc_id', + 'vname' => 'LBL_DOC_ID', + 'type' => 'varchar', + 'len' => '100', + 'comment' => 'Document ID from documents web server provider', + 'importable' => false, + 'studio' => 'false', + ), + 'doc_type' => + array ( + 'name' => 'doc_type', + 'vname' => 'LBL_DOC_TYPE', + 'type' => 'enum', + 'function' => 'getDocumentsExternalApiDropDown', + 'len' => '100', + 'comment' => 'Document type (ex: Google, box.net, LotusLive)', + 'popupHelp' => 'LBL_DOC_TYPE_POPUP', + 'massupdate' => false, + 'options' => 'eapm_list', + 'default' => 'Sugar', + 'studio' => 'false', + ), +'doc_url' => + array ( + 'name' => 'doc_url', + 'vname' => 'LBL_DOC_URL', + 'type' => 'varchar', + 'len' => '255', + 'comment' => 'Document URL from documents web server provider', + 'importable' => false, + 'massupdate' => false, + 'studio' => 'false', + ), + 'filename' => + array ( + 'name' => 'filename', + 'vname' => 'LBL_FILENAME', + 'type' => 'file', + 'source' => 'non-db', + 'comment' => 'The filename of the document attachment', + 'required' => true, + 'noChange' => true, + 'allowEapm' => true, + 'fileId' => 'document_revision_id', + 'docType' => 'doc_type', + ), + +'active_date' => + array ( + 'name' => 'active_date', + 'vname' => 'LBL_DOC_ACTIVE_DATE', + 'type' => 'date', + 'importable' => 'required', + 'required' => true, + 'display_default' => 'now', + ), + +'exp_date' => + array ( + 'name' => 'exp_date', + 'vname' => 'LBL_DOC_EXP_DATE', + 'type' => 'date', + ), + + 'category_id' => + array ( + 'name' => 'category_id', + 'vname' => 'LBL_SF_CATEGORY', + 'type' => 'enum', + 'len' => 100, + 'options' => 'document_category_dom', + 'reportable'=>false, + ), + + 'subcategory_id' => + array ( + 'name' => 'subcategory_id', + 'vname' => 'LBL_SF_SUBCATEGORY', + 'type' => 'enum', + 'len' => 100, + 'options' => 'document_subcategory_dom', + 'reportable'=>false, + ), + + 'status_id' => + array ( + 'name' => 'status_id', + 'vname' => 'LBL_DOC_STATUS', + 'type' => 'enum', + 'len' => 100, + 'options' => 'document_status_dom', + 'reportable'=>false, + ), + + 'status' => + array ( + 'name' => 'status', + 'vname' => 'LBL_DOC_STATUS', + 'type' => 'varchar', + 'source' => 'non-db', + 'comment' => 'Document status for Meta-Data framework', + ), + + 'document_revision_id'=> + array ( + 'name' => 'document_revision_id', + 'vname' => 'LBL_LATEST_REVISION', + 'type' => 'varchar', + 'len' => '36', + 'reportable'=>false, + ), + + 'revisions' => + array ( + 'name' => 'revisions', + 'type' => 'link', + 'relationship' => 'document_revisions', + 'source'=>'non-db', + 'vname'=>'LBL_REVISIONS', + ), + + 'revision' => + array ( + 'name' => 'revision', + 'vname' => 'LBL_DOC_VERSION', + 'type' => 'varchar', + 'reportable'=>false, + 'required' => true, + 'source'=>'non-db', + 'importable' => 'required', + 'required' => true, + 'default' => '1', + ), + + 'last_rev_created_name' => + array ( + 'name' => 'last_rev_created_name', + 'vname' => 'LBL_LAST_REV_CREATOR', + 'type' => 'varchar', + 'reportable'=>false, + 'source'=>'non-db' + ), + 'last_rev_mime_type' => + array ( + 'name' => 'last_rev_mime_type', + 'vname' => 'LBL_LAST_REV_MIME_TYPE', + 'type' => 'varchar', + 'reportable'=>false, + 'studio' => 'false', + 'source'=>'non-db' + ), + 'latest_revision' => + array ( + 'name' => 'latest_revision', + 'vname' => 'LBL_LATEST_REVISION', + 'type' => 'varchar', + 'reportable'=>false, + 'source'=>'non-db' + ), + 'last_rev_create_date' => + array ( + 'name' => 'last_rev_create_date', + 'type' => 'date', + 'table' => 'document_revisions', + 'link' => 'revisions', + 'join_name' => 'document_revisions', + 'vname'=>'LBL_LAST_REV_CREATE_DATE', + 'rname'=> 'date_entered', + 'reportable'=>false, + 'source'=>'non-db' + ), + 'contracts' => array ( + 'name' => 'contracts', + 'type' => 'link', + 'relationship' => 'contracts_documents', + 'source' => 'non-db', + 'vname' => 'LBL_CONTRACTS', + ), + //todo remove + 'leads' => array ( + 'name' => 'leads', + 'type' => 'link', + 'relationship' => 'leads_documents', + 'source' => 'non-db', + 'vname' => 'LBL_LEADS', + ), + // Links around the world + 'accounts'=> + array ( + 'name' => 'accounts', + 'type' => 'link', + 'relationship' => 'documents_accounts', + 'source' => 'non-db', + 'vname' => 'LBL_ACCOUNTS_SUBPANEL_TITLE', + ), + 'contacts'=> + array ( + 'name' => 'contacts', + 'type' => 'link', + 'relationship' => 'documents_contacts', + 'source' => 'non-db', + 'vname' => 'LBL_CONTACTS_SUBPANEL_TITLE', + ), + 'opportunities'=> + array ( + 'name' => 'opportunities', + 'type' => 'link', + 'relationship' => 'documents_opportunities', + 'source' => 'non-db', + 'vname' => 'LBL_OPPORTUNITIES_SUBPANEL_TITLE', + ), + 'cases'=> + array ( + 'name' => 'cases', + 'type' => 'link', + 'relationship' => 'documents_cases', + 'source' => 'non-db', + 'vname' => 'LBL_CASES_SUBPANEL_TITLE', + ), + 'bugs'=> + array ( + 'name' => 'bugs', + 'type' => 'link', + 'relationship' => 'documents_bugs', + 'source' => 'non-db', + 'vname' => 'LBL_BUGS_SUBPANEL_TITLE', + ), + 'related_doc_id' => + array ( + 'name' => 'related_doc_id', + 'vname' => 'LBL_RELATED_DOCUMENT_ID', + 'reportable'=>false, + 'dbType' => 'id', + 'type' => 'varchar', + 'len' => '36', + ), + + 'related_doc_name' => + array ( + 'name' => 'related_doc_name', + 'vname' => 'LBL_DET_RELATED_DOCUMENT', + 'type' => 'relate', + 'table' => 'documents', + 'id_name' => 'related_doc_id', + 'module' => 'Documents', + 'source' => 'non-db', + 'comment' => 'The related document name for Meta-Data framework', + ), + + 'related_doc_rev_id' => + array ( + 'name' => 'related_doc_rev_id', + 'vname' => 'LBL_RELATED_DOCUMENT_REVISION_ID', + 'reportable'=>false, + 'dbType' => 'id', + 'type' => 'varchar', + 'len' => '36', + ), + + 'related_doc_rev_number' => + array ( + 'name' => 'related_doc_rev_number', + 'vname' => 'LBL_DET_RELATED_DOCUMENT_VERSION', + 'type' => 'varchar', + 'source' => 'non-db', + 'comment' => 'The related document version number for Meta-Data framework', + ), + + 'is_template' => + array ( + 'name' => 'is_template', + 'vname' => 'LBL_IS_TEMPLATE', + 'type' => 'bool', + 'default'=> 0, + 'reportable'=>false, + ), + 'template_type' => + array ( + 'name' => 'template_type', + 'vname' => 'LBL_TEMPLATE_TYPE', + 'type' => 'enum', + 'len' => 100, + 'options' => 'document_template_type_dom', + 'reportable'=>false, + ), +//BEGIN field used for contract document subpanel. + 'latest_revision_name' => + array ( + 'name' => 'latest_revision_name', + 'vname' => 'LBL_LASTEST_REVISION_NAME', + 'type' => 'varchar', + 'reportable'=>false, + 'source'=>'non-db' + ), + + 'selected_revision_name' => + array ( + 'name' => 'selected_revision_name', + 'vname' => 'LBL_SELECTED_REVISION_NAME', + 'type' => 'varchar', + 'reportable'=>false, + 'source'=>'non-db' + ), + 'contract_status' => + array ( + 'name' => 'contract_status', + 'vname' => 'LBL_CONTRACT_STATUS', + 'type' => 'varchar', + 'reportable'=>false, + 'source'=>'non-db' + ), + 'contract_name'=> + array ( + 'name' => 'contract_name', + 'vname' => 'LBL_CONTRACT_NAME', + 'type' => 'varchar', + 'reportable'=>false, + 'source'=>'non-db' + ), + 'linked_id'=> + array ( + 'name' => 'linked_id', + 'vname' => 'LBL_LINKED_ID', + 'type' => 'varchar', + 'reportable'=>false, + 'source'=>'non-db' + ), + 'selected_revision_id'=> + array ( + 'name' => 'selected_revision_id', + 'vname' => 'LBL_SELECTED_REVISION_ID', + 'type' => 'varchar', + 'reportable'=>false, + 'source'=>'non-db' + ), + 'latest_revision_id'=> + array ( + 'name' => 'latest_revision_id', + 'vname' => 'LBL_LATEST_REVISION_ID', + 'type' => 'varchar', + 'reportable'=>false, + 'source'=>'non-db' + ), + 'selected_revision_filename'=> + array ( + 'name' => 'selected_revision_filename', + 'vname' => 'LBL_SELECTED_REVISION_FILENAME', + 'type' => 'varchar', + 'reportable'=>false, + 'source'=>'non-db' + ), +//END fields used for contract documents subpanel. + +), + 'indices' => array ( + array('name' =>'idx_doc_cat', 'type' =>'index', 'fields'=>array('category_id', 'subcategory_id')), + ), + 'relationships' => array ( + 'document_revisions' => array('lhs_module'=> 'Documents', 'lhs_table'=> 'documents', 'lhs_key' => 'id', + 'rhs_module'=> 'DocumentRevisions', 'rhs_table'=> 'document_revisions', 'rhs_key' => 'document_id', + 'relationship_type'=>'one-to-many') + + ,'documents_modified_user' => + array('lhs_module'=> 'Users', 'lhs_table'=> 'users', 'lhs_key' => 'id', + 'rhs_module'=> 'Documents', 'rhs_table'=> 'documents', 'rhs_key' => 'modified_user_id', + 'relationship_type'=>'one-to-many') + + ,'documents_created_by' => + array('lhs_module'=> 'Users', 'lhs_table'=> 'users', 'lhs_key' => 'id', + 'rhs_module'=> 'Documents', 'rhs_table'=> 'documents', 'rhs_key' => 'created_by', + 'relationship_type'=>'one-to-many') + ), + +); +VardefManager::createVardef('Documents','Document', array('default','assignable', +)); +?> diff --git a/modules/Documents/views/view.detail.php b/modules/Documents/views/view.detail.php new file mode 100644 index 00000000..0b2937b8 --- /dev/null +++ b/modules/Documents/views/view.detail.php @@ -0,0 +1,63 @@ +_getModuleTitleListParam($browserTitle); + $params[] = $this->bean->document_name; + + return $params; + } +} diff --git a/modules/Documents/views/view.edit.php b/modules/Documents/views/view.edit.php new file mode 100644 index 00000000..12a4e246 --- /dev/null +++ b/modules/Documents/views/view.edit.php @@ -0,0 +1,175 @@ +bean->category_name = $app_list_strings['document_category_dom'][$this->bean->category_id]; + $this->bean->subcategory_name = $app_list_strings['document_subcategory_dom'][$this->bean->subcategory_id]; + if(isset($this->bean->status_id)) { + $this->bean->status = $app_list_strings['document_status_dom'][$this->bean->status_id]; + } + $this->bean->related_doc_name = Document::get_document_name($this->bean->related_doc_id); + $this->bean->related_doc_rev_number = DocumentRevision::get_document_revision_name($this->bean->related_doc_rev_id); + $this->bean->save_file = basename($this->bean->file_url_noimage); + */ + $load_signed=false; + if ((isset($_REQUEST['load_signed_id']) && !empty($_REQUEST['load_signed_id']))) { + + $load_signed=true; + if (isset($_REQUEST['record'])) { + $this->bean->related_doc_id=$_REQUEST['record']; + } + if (isset($_REQUEST['selected_revision_id'])) { + $this->bean->related_doc_rev_id=$_REQUEST['selected_revision_id']; + } + + $this->bean->id=null; + $this->bean->document_name=null; + $this->bean->filename=null; + $this->bean->is_template=0; + } //if + + if (!empty($this->bean->id)) { + $this->ss->assign("FILE_OR_HIDDEN", "hidden"); + if (!$this->ev->isDuplicate) { + $this->ss->assign("DISABLED", "disabled"); + } + } else { + $this->bean->revision = 1; + $this->ss->assign("FILE_OR_HIDDEN", "file"); + } + + $popup_request_data = array( + 'call_back_function' => 'document_set_return', + 'form_name' => 'EditView', + 'field_to_name_array' => array( + 'id' => 'related_doc_id', + 'document_name' => 'related_document_name', + ), + ); + $json = getJSONobj(); + $this->ss->assign('encoded_document_popup_request_data', $json->encode($popup_request_data)); + + + //get related document name. + if (!empty($this->bean->related_doc_id)) { + $this->ss->assign("RELATED_DOCUMENT_NAME",Document::get_document_name($this->bean->related_doc_id)); + $this->ss->assign("RELATED_DOCUMENT_ID",$this->bean->related_doc_id); + if (!empty($this->bean->related_doc_rev_id)) { + $this->ss->assign("RELATED_DOCUMENT_REVISION_OPTIONS", get_select_options_with_id(DocumentRevision::get_document_revisions($this->bean->related_doc_id), $this->bean->related_doc_rev_id)); + } else { + $this->ss->assign("RELATED_DOCUMENT_REVISION_OPTIONS", get_select_options_with_id(DocumentRevision::get_document_revisions($this->bean->related_doc_id), '')); + } + } else { + $this->ss->assign("RELATED_DOCUMENT_REVISION_DISABLED", "disabled"); + } + + + //set parent information in the form. + if (isset($_REQUEST['parent_id'])) { + $this->ss->assign("PARENT_ID",$_REQUEST['parent_id']); + } //if + + if (isset($_REQUEST['parent_name'])) { + $this->ss->assign("PARENT_NAME", $_REQUEST['parent_name']); + + if (!empty($_REQUEST['parent_type'])) { + switch (strtolower($_REQUEST['parent_type'])) { + + case "contracts" : + $this->ss->assign("LBL_PARENT_NAME",$mod_strings['LBL_CONTRACT_NAME']); + break; + + //todo remove leads case. + case "leads" : + $this->ss->assign("LBL_PARENT_NAME",$mod_strings['LBL_CONTRACT_NAME']); + break; + } //switch + } //if + } //if + + if (isset($_REQUEST['parent_type'])) { + $this->ss->assign("PARENT_TYPE",$_REQUEST['parent_type']); + } + + if ($load_signed) { + $this->ss->assign("RELATED_DOCUMENT_REVISION_DISABLED", "disabled"); + $this->ss->assign("RELATED_DOCUMENT_BUTTON_AVAILABILITY", "hidden"); + $this->ss->assign("LOAD_SIGNED_ID",$_REQUEST['load_signed_id']); + } else { + $this->ss->assign("RELATED_DOCUMENT_BUTTON_AVAILABILITY", "button"); + } //if-else + + parent::display(); + } + + /** + * @see SugarView::_getModuleTitleParams() + */ + protected function _getModuleTitleParams($browserTitle = false) + { + $params = array(); + $params[] = $this->_getModuleTitleListParam($browserTitle); + if(!empty($this->bean->id)){ + $params[] = "".$this->bean->document_name.""; + $params[] = $GLOBALS['app_strings']['LBL_EDIT_BUTTON_LABEL']; + }else{ + $params[] = $GLOBALS['app_strings']['LBL_CREATE_BUTTON_LABEL']; + } + + return $params; + } +} diff --git a/modules/Documents/views/view.extdoc.php b/modules/Documents/views/view.extdoc.php new file mode 100644 index 00000000..f1bddb1a --- /dev/null +++ b/modules/Documents/views/view.extdoc.php @@ -0,0 +1,187 @@ + false, 'show_title' => false, 'show_subpanels' => false, 'show_search' => true, 'show_footer' => false, 'show_javascript' => false, 'view_print' => false,); + + public function init($bean, $view_object_map) { + $this->seed = $bean; + } + + public function display(){ + + if ( isset($_REQUEST['name_basic']) ) { + $file_search = trim($_REQUEST['name_basic']); + } else { + $file_search = ''; + } + + // $apiName = 'LotusLiveDirect'; + if ( !isset($_REQUEST['apiName']) ) { + $apiName = 'LotusLive'; + } else { + $apiName = $_REQUEST['apiName']; + } + + // See if we are running as a popup window + if ( isset($_REQUEST['isPopup']) && $_REQUEST['isPopup'] == 1 && !empty($_REQUEST['elemBaseName']) ) { + $isPopup = true; + } else { + $isPopup = false; + } + + // Need to manually attempt to fetch the EAPM record, we don't want to give them the signup screen when they just have a deactivated account. + + if ( !$eapmBean = EAPM::getLoginInfo($apiName,true) ) { + $smarty = new Sugar_Smarty(); + echo $smarty->fetch('include/externalAPI/LotusLive/LotusLiveSignup.'.$GLOBALS['current_language'].'.tpl'); + return; + } + + + $api = ExternalAPIFactory::loadAPI($apiName,true); + $api->loadEAPM($eapmBean); + + $quickCheck = $api->quickCheckLogin(); + if ( ! $quickCheck['success'] ) { + $errorMessage = string_format(translate('LBL_ERR_FAILED_QUICKCHECK','EAPM'), array('LotusLive')); + $errorMessage .= '
    '; + $errorMessage .= ''; + $errorMessage .= ''; + $errorMessage .= ''; + $errorMessage .= ''; + $errorMessage .= ''; + $errorMessage .= ''; + + $errorMessage .= '
     '; + $errorMessage .= ''; + $errorMessage .= '
    '; + echo $errorMessage; + return; + } + + $searchDataLower = $api->searchDoc($file_search,true); + + + // In order to emulate the list views for the SugarFields, I need to uppercase all of the key names. + $searchData = array(); + + if ( is_array($searchDataLower) ) { + foreach ( $searchDataLower as $row ) { + $newRow = array(); + foreach ( $row as $key => $value ) { + $newRow[strtoupper($key)] = $value; + } + + if ( $isPopup ) { + // We are running as a popup window, we need to replace the direct url with some javascript + $newRow['DOC_URL'] = "javascript:window.opener.SUGAR.field.file.populateFromPopup('".addslashes($_REQUEST['elemBaseName'])."','".addslashes($newRow['ID'])."','".addslashes($newRow['NAME'])."','".addslashes($newRow['URL'])."','".addslashes($newRow['URL'])."'); window.close();"; + }else{ + $newRow['DOC_URL'] = $newRow['URL']; + } + $searchData[] = $newRow; + } + } + + $displayColumns = array( + 'NAME' => array( + 'label' => 'LBL_LIST_EXT_DOCUMENT_NAME', + 'type' => 'varchar', + 'link' => true, + ), + 'DATE_MODIFIED' => array( + 'label' => 'LBL_DATE', + 'type' => 'date', + ), + ); + + $ss = new Sugar_Smarty(); + $ss->assign('searchFieldLabel',translate('LBL_SEARCH_EXTERNAL_DOCUMENT','Documents')); + $ss->assign('displayedNote',translate('LBL_EXTERNAL_DOCUMENT_NOTE','Documents')); + $ss->assign('APP',$GLOBALS['app_strings']); + $ss->assign('MOD',$GLOBALS['mod_strings']); + $ss->assign('data', $searchData); + $ss->assign('displayColumns',$displayColumns); + $ss->assign('imgPath',SugarThemeRegistry::current()->getImageURL($apiName.'_image_inline.png')); + + if ( $isPopup ) { + $ss->assign('linkTarget',''); + $ss->assign('isPopup',1); + $ss->assign('elemBaseName',$_REQUEST['elemBaseName']); + } else { + $ss->assign('linkTarget','_new'); + $ss->assign('isPopup',0); + $ss->assign('elemBaseName',''); + } + $ss->assign('apiName',$apiName); + $ss->assign('DCSEARCH',$file_search); + + if ( $isPopup ) { + // Need the popup header... I feel so dirty. + ob_start(); + echo('
    '); + insert_popup_header($GLOBALS['theme']); + $output_html = ob_get_contents(); + ob_end_clean(); + + $output_html .= get_form_header(translate('LBL_SEARCH_FORM_TITLE','Documents'), '', false); + + echo($output_html); + } + + $ss->display('modules/Documents/tpls/view.extdoc.tpl'); + + if ( $isPopup ) { + // Close the dccontent div + echo('
    '); + } + } +} diff --git a/modules/DynamicFields/DynamicField.php b/modules/DynamicFields/DynamicField.php new file mode 100644 index 00000000..3d4575ae --- /dev/null +++ b/modules/DynamicFields/DynamicField.php @@ -0,0 +1,923 @@ +module = (! empty ( $module )) ? $module :( (isset($_REQUEST['module']) && ! empty($_REQUEST['module'])) ? $_REQUEST ['module'] : ''); + $this->base_path = "custom/Extension/modules/{$this->module}/Ext/Vardefs"; + } + + function getModuleName() + { + return $this->module ; + } + + /* + * As DynamicField has a counterpart in MBModule, provide the MBModule function getPackagename() here also + */ + function getPackageName() + { + return null ; + } + + function deleteCache(){ + } + + + /** + * This will add the bean as a reference in this object as well as building the custom field cache if it has not been built + * LOADS THE BEAN IF THE BEAN IS NOT BEING PASSED ALONG IN SETUP IT SHOULD BE SET PRIOR TO SETUP + * + * @param SUGARBEAN $bean + */ + function setup($bean = null) { + if ($bean) { + $this->bean = $bean; + } + if (isset ( $this->bean->module_dir )) { + $this->module = $this->bean->module_dir; + } + if(!isset($GLOBALS['dictionary'][$this->bean->object_name]['custom_fields'])){ + $this->buildCache ( $this->module ); + } + } + + function setLabel( $language='en_us' , $key , $value ) + { + $params [ "label_" . $key ] = $value; + require_once 'modules/ModuleBuilder/parsers/parser.label.php' ; + $parser = new ParserLabel ( $this->module ) ; + $parser->handleSave( $params , $language); + } + + /** + * Builds the cache for custom fields based on the vardefs + * + * @param STRING $module + * @return unknown + */ + function buildCache($module = false) { + //We can't build the cache while installing as the required database tables may not exist. + if (!empty($GLOBALS['installing']) && $GLOBALS['installing'] == true|| !$GLOBALS['db']) + return false; + if($module == '../data')return false; + + static $results = array ( ) ; + + $where = ''; + if (! empty ( $module )) { + $where .= " custom_module='$module' AND "; + unset( $results[ $module ] ) ; // clear out any old results for the module as $results is declared static + } + else + { + $results = array ( ) ; // clear out results - if we remove a module we don't want to have its old vardefs hanging around + } + + $GLOBALS['log']->debug('rebuilding cache for ' . $module); + $query = "SELECT * FROM fields_meta_data WHERE $where deleted = 0"; + + $result = $GLOBALS['db']->query ( $query ); + require_once ('modules/DynamicFields/FieldCases.php'); + + // retrieve the field definition from the fields_meta_data table + // using 'encode'=false to fetchByAssoc to prevent any pre-formatting of the base metadata + // for immediate use in HTML. This metadata will be further massaged by get_field_def() and so should not be pre-formatted + while ( $row = $GLOBALS['db']->fetchByAssoc ( $result , -1 ,false ) ) { + $field = get_widget ( $row ['type'] ); + + foreach ( $row as $key => $value ) { + $field->$key = $value; + } + $field->default = $field->default_value; + $vardef = $field->get_field_def (); + $vardef ['id'] = $row ['id']; + $vardef ['custom_module'] = $row ['custom_module']; + if (empty ( $vardef ['source'] )) + $vardef ['source'] = 'custom_fields'; + if (empty ( $results [$row ['custom_module']] )) + $results [$row ['custom_module']] = array ( ); + $results [$row ['custom_module']] [$row ['name']] = $vardef; + } + if (empty ( $module )) { + foreach ( $results as $module => $result ) { + $this->saveToVardef ( $module, $result ); + } + } else { + if (! empty ( $results [$module] )) { + $this->saveToVardef ( $module, $results [$module] ); + }else{ + $this->saveToVardef ( $module, false ); + } + } + return true; + + } + + /** + * Returns the widget for a custom field from the fields_meta_data table. + */ + function getFieldWidget($module, $fieldName) { + if (empty($module) || empty($fieldName)){ + sugar_die("Unable to load widget for '$module' : '$fieldName'"); + } + $query = "SELECT * FROM fields_meta_data WHERE custom_module='$module' AND name='$fieldName' AND deleted = 0"; + $result = $GLOBALS['db']->query ( $query ); + require_once ('modules/DynamicFields/FieldCases.php'); + if ( $row = $GLOBALS['db']->fetchByAssoc ( $result ) ) { + $field = get_widget ( $row ['type'] ); + $field->populateFromRow($row); + return $field; + } + } + + + /** + * Updates the cached vardefs with the custom field information stored in result + * + * @param string $module + * @param array $result + */ + function saveToVardef($module,$result) { + + global $beanList; + if (! empty ( $beanList [$module] )) { + $object = $beanList [$module]; + + if ($object == 'aCase') { + $object = 'Case'; + } + + if(empty($GLOBALS['dictionary'][$object]['fields'])){ + //if the vardef isn't loaded let's try loading it. + VardefManager::refreshVardefs($module,$object, null, false); + //if it's still not loaded we really don't have anything useful to cache + if(empty($GLOBALS['dictionary'][$object]['fields']))return; + } + $GLOBALS ['dictionary'] [$object] ['custom_fields'] = false; + if (! empty ( $GLOBALS ['dictionary'] [$object] )) { + if (! empty ( $result )) { + // First loop to add + + foreach ( $result as $field ) { + foreach($field as $k=>$v){ + //allows values for custom fields to be defined outside of the scope of studio + if(!isset($GLOBALS ['dictionary'] [$object] ['fields'] [$field ['name']][$k])){ + $GLOBALS ['dictionary'] [$object] ['fields'] [$field ['name']][$k] = $v; + } + } + } + + // Second loop to remove + foreach ( $GLOBALS ['dictionary'] [$object] ['fields'] as $name => $fieldDef ) { + + if (isset ( $fieldDef ['custom_module'] )) { + if (! isset ( $result [$name] )) { + unset ( $GLOBALS ['dictionary'] [$object] ['fields'] [$name] ); + } else { + $GLOBALS ['dictionary'] [$object] ['custom_fields'] = true; + } + } + + } //if + } + } + $manager = new VardefManager ( ); + $manager->saveCache ( $this->module, $object ); + } + } + + /** + * returns either false or an array containing the select and join parameter for a query using custom fields + * @param $expandedList boolean If true, return a list of all fields with source=custom_fields in the select instead of the standard _cstm.* + * This is required for any downstream construction of a SQL statement where we need to manipulate the select list, + * for example, listviews with custom relate fields where the value comes from join rather than from the custom table + * + * @return array select=>select columns, join=>prebuilt join statement + */ + function getJOIN( $expandedList = false , $includeRelates = false, &$where = false){ + if(!$this->bean->hasCustomFields()){ + return false; + } + + if (empty($expandedList) ) + { + $select = ",{$this->bean->table_name}_cstm.*" ; + } + else + { + $select = ''; + $isList = is_array($expandedList); + foreach($this->bean->field_defs as $name=>$field) + { + if (!empty($field['source']) && $field['source'] == 'custom_fields' && (!$isList || !empty($expandedList[$name]))){ + // assumption: that the column name in _cstm is the same as the field name. Currently true. + // however, two types of dynamic fields do not have columns in the custom table - html fields (they're readonly) and flex relates (parent_name doesn't exist) + if ( $field['type'] != 'html' && $name != 'parent_name') + $select .= ",{$this->bean->table_name}_cstm.{$name}" ; + } + } + } + $join = " LEFT JOIN " .$this->bean->table_name. "_cstm ON " .$this->bean->table_name. ".id = ". $this->bean->table_name. "_cstm.id_c "; + + if ($includeRelates) { + $jtAlias = "relJoin"; + $jtCount = 1; + foreach($this->bean->field_defs as $name=>$field) + { + if ($field['type'] == 'relate' && isset($field['custom_module'])) { + $relateJoinInfo = $this->getRelateJoin($field, $jtAlias.$jtCount); + $select .= $relateJoinInfo['select']; + $join .= $relateJoinInfo['from']; + //bug 27654 martin + if ($where) + { + $pattern = '/'.$field['name'].'\slike/i'; + $replacement = $relateJoinInfo['name_field'].' like'; + $where = preg_replace($pattern,$replacement,$where); + } + $jtCount++; + } + } + } + + return array('select'=>$select, 'join'=>$join); + + } + + function getRelateJoin($field_def, $joinTableAlias) { + if (empty($field_def['type']) || $field_def['type'] != "relate") { + return false; + } + global $beanFiles, $beanList, $module; + $rel_module = $field_def['module']; + if(empty($beanFiles[$beanList[$rel_module]])) { + return false; + } + + require_once($beanFiles[$beanList[$rel_module]]); + $rel_mod = new $beanList[$rel_module](); + $rel_table = $rel_mod->table_name; + if (isset($rel_mod->field_defs['name'])) + { + $name_field_def = $rel_mod->field_defs['name']; + if(isset($name_field_def['db_concat_fields'])) + { + $name_field = db_concat($joinTableAlias, $name_field_def['db_concat_fields']); + } + //If the name field is non-db, we need to find another field to display + else if(!empty($rel_mod->field_defs['name']['source']) && $rel_mod->field_defs['name']['source'] == "non-db" && !empty($field_def['rname'])) + { + $name_field = "$joinTableAlias." . $field_def['rname']; + } + else + { + $name_field = "$joinTableAlias.name"; + } + } + $tableName = isset($field_def['custom_module']) ? "{$this->bean->table_name}_cstm" : $this->bean->table_name ; + $relID = $field_def['id_name']; + $ret_array['rel_table'] = $rel_table; + $ret_array['name_field'] = $name_field; + $ret_array['select'] = ", $name_field {$field_def['name']} "; + $ret_array['from'] = " LEFT JOIN $rel_table $joinTableAlias ON $tableName.$relID = $joinTableAlias.id" + . " AND $joinTableAlias.deleted=0 "; + return $ret_array; + } + + /** + * Fills in all the custom fields of type relate relationships for an object + * + */ + function fill_relationships(){ + global $beanList, $beanFiles; + if(!empty($this->bean->relDepth)) { + if($this->bean->relDepth > 1)return; + }else{ + $this->bean->relDepth = 0; + } + foreach($this->bean->field_defs as $field){ + if(empty($field['source']) || $field['source'] != 'custom_fields')continue; + if($field['type'] == 'relate'){ + $related_module =$field['ext2']; + $name = $field['name']; + if (empty($this->bean->$name)) { //Don't load the relationship twice + $id_name = $field['id_name']; + if(isset($beanList[ $related_module])){ + $class = $beanList[$related_module]; + + if(file_exists($beanFiles[$class]) && isset($this->bean->$name)){ + require_once($beanFiles[$class]); + $mod = new $class(); + $mod->relDepth = $this->bean->relDepth + 1; + $mod->retrieve($this->bean->$id_name); + $this->bean->$name = $mod->name; + } + } + } + } + } + } + + /** + * Process the save action for sugar bean custom fields + * + * @param boolean $isUpdate + */ + function save($isUpdate){ + + if($this->bean->hasCustomFields() && isset($this->bean->id)){ + + if($isUpdate){ + $query = "UPDATE ". $this->bean->table_name. "_cstm SET "; + } + $queryInsert = "INSERT INTO ". $this->bean->table_name. "_cstm (id_c"; + $values = "('".$this->bean->id."'"; + $first = true; + foreach($this->bean->field_defs as $name=>$field){ + + if(empty($field['source']) || $field['source'] != 'custom_fields')continue; + if($field['type'] == 'html' || $field['type'] == 'parent')continue; + if(isset($this->bean->$name)){ + $quote = "'"; + + if(in_array($field['type'], array('int', 'float', 'double', 'uint', 'ulong', 'long', 'short', 'tinyint', 'currency', 'decimal'))) { + $quote = ''; + if(!isset($this->bean->$name) || !is_numeric($this->bean->$name) ){ + if($field['required']){ + $this->bean->$name = 0; + }else{ + $this->bean->$name = 'NULL'; + } + } + } + if ( $field['type'] == 'bool' ) { + if ( $this->bean->$name === FALSE ) + $this->bean->$name = '0'; + elseif ( $this->bean->$name === TRUE ) + $this->bean->$name = '1'; + } + if(($field['type'] == 'date' || $field['type'] == 'datetimecombo') && (empty($this->bean->$name )|| $this->bean->$name == '1900-01-01')){ + $quote = ''; + $this->bean->$name = "NULL"; + } + if($isUpdate){ + if($first){ + $query .= " $name=$quote".$GLOBALS['db']->quote($this->bean->$name)."$quote"; + + }else{ + $query .= " ,$name=$quote".$GLOBALS['db']->quote($this->bean->$name)."$quote"; + } + } + $first = false; + $queryInsert .= " ,$name"; + $values .= " ,$quote". $GLOBALS['db']->quote($this->bean->$name). "$quote"; + } + } + if($isUpdate){ + $query.= " WHERE id_c='" . $this->bean->id ."'"; + + } + + $queryInsert .= " ) VALUES $values )"; + if(!$first){ + if(!$isUpdate){ + $GLOBALS['db']->query($queryInsert); + }else{ + $checkquery = "SELECT id_c FROM {$this->bean->table_name}_cstm WHERE id_c = '{$this->bean->id}'"; + if ( $GLOBALS['db']->getOne($checkquery) ) + $result = $GLOBALS['db']->query($query); + else + $GLOBALS['db']->query($queryInsert); + } + } + } + + } + /** + * Deletes the field from fields_meta_data and drops the database column then it rebuilds the cache + * Use the widgets get_db_modify_alter_table() method to get the table sql - some widgets do not need any custom table modifications + * @param STRING $name - field name + */ + function deleteField($widget){ + require_once('modules/DynamicFields/templates/Fields/TemplateField.php'); + global $beanList; + if (!($widget instanceof TemplateField)) { + $field_name = $widget; + $widget = new TemplateField(); + $widget->name = $field_name; + } + $object_name = $beanList[$this->module]; + + if ($object_name == 'aCase') { + $object_name = 'Case'; + } + + $GLOBALS['db']->query("DELETE FROM fields_meta_data WHERE id='" . $this->module . $widget->name . "'"); + $sql = $widget->get_db_delete_alter_table( $this->bean->table_name . "_cstm" ) ; + if (! empty( $sql ) ) + $GLOBALS['db']->query( $sql ); + + $this->removeVardefExtension($widget); + VardefManager::clearVardef(); + VardefManager::refreshVardefs($this->module, $object_name); + + } + + /* + * Method required by the TemplateRelatedTextField->save() method + * Taken from MBModule's implementation + */ + function fieldExists($name = '', $type = ''){ + // must get the vardefs from the GLOBAL array as $bean->field_defs does not contain the values from the cache at this point + // TODO: fix this - saveToVardefs() updates GLOBAL['dictionary'] correctly, obtaining its information directly from the fields_meta_data table via buildCache()... + $vardefs = $GLOBALS['dictionary'][$this->bean->object_name]['fields']; + if(!empty($vardefs)){ + if(empty($type) && empty($name)) + return false; + else if(empty($type)) + return !empty($vardefs[$name]); + else if(empty($name)){ + foreach($vardefs as $def){ + if($def['type'] == $type) + return true; + } + return false; + }else + return (!empty($vardefs[$name]) && ($vardefs[$name]['type'] == $type)); + }else{ + return false; + } + } + + + /** + * Adds a custom field using a field object + * + * @param Field Object $field + * @return boolean + */ + function addFieldObject(&$field){ + $GLOBALS['log']->debug('adding field'); + $object_name = $this->module; + $db_name = $field->name; + + $fmd = new FieldsMetaData(); + $id = $fmd->retrieve($object_name.$db_name,true, false); + $is_update = false; + $label = $field->label; + if(!empty($id)){ + $is_update = true; + }else{ + $db_name = $this->getDBName($field->name); + $field->name = $db_name; + } + $this->createCustomTable(); + $fmd->id = $object_name.$db_name; + $fmd->custom_module= $object_name; + $fmd->name = $db_name; + $fmd->vname = $label; + $fmd->type = $field->type; + $fmd->help = $field->help; + if (!empty($field->len)) + $fmd->len = $field->len; // tyoung bug 15407 - was being set to $field->size so changes weren't being saved + $fmd->required = ($field->required ? 1 : 0); + $fmd->default_value = $field->default; + $fmd->ext1 = $field->ext1; + $fmd->ext2 = $field->ext2; + $fmd->ext3 = $field->ext3; + $fmd->ext4 = (isset($field->ext4) ? $field->ext4 : ''); + $fmd->comments = $field->comment; + $fmd->massupdate = $field->massupdate; + $fmd->importable = ( isset ( $field->importable ) ) ? $field->importable : null ; + $fmd->duplicate_merge = $field->duplicate_merge; + $fmd->audited =$field->audited; + $fmd->reportable = ($field->reportable ? 1 : 0); + if(!$is_update){ + $fmd->new_with_id=true; + } + $fmd->save(); + $this->buildCache($this->module); + if($field){ + if(!$is_update){ + $query = $field->get_db_add_alter_table($this->bean->table_name . '_cstm'); + }else{ + $query = $field->get_db_modify_alter_table($this->bean->table_name . '_cstm'); + } + if(!empty($query)){ + $GLOBALS['db']->query($query); + } + $this->saveExtendedAttributes($field, array_keys($fmd->field_defs)); + } + + return true; + } + + function saveExtendedAttributes($field, $column_fields) + { + require_once ('modules/ModuleBuilder/parsers/StandardField.php') ; + require_once ('modules/DynamicFields/FieldCases.php') ; + global $beanList; + + $to_save = array(); + $base_field = get_widget ( $field->type) ; + foreach ($field->vardef_map as $property => $fmd_col){ + + if (!isset($field->$property) || in_array($fmd_col, $column_fields) || in_array($property, $column_fields) + || $this->isDefaultValue($property, $field->$property, $base_field) + || $property == "action" || $property == "label_value" || $property == "label" + || (substr($property, 0,3) == 'ext' && strlen($property) == 4)) + { + continue; + } + $to_save[$property] = + is_string($field->$property) ? htmlspecialchars_decode($field->$property, ENT_QUOTES) : $field->$property; + } + $bean_name = $beanList[$this->module]; + + $this->writeVardefExtension($bean_name, $field, $to_save); + } + + protected function isDefaultValue($property, $value, $baseField) + { + switch ($property) { + case "importable": + return ( $value === 'true' || $value === '1' || $value === true || $value === 1 ); break; + case "required": + case "audited": + case "massupdate": + return ( $value === 'false' || $value === '0' || $value === false || $value === 0); break; + case "default_value": + case "default": + case "help": + case "comments": + return ($value == ""); + case "duplicate_merge": + return ( $value === 'false' || $value === '0' || $value === false || $value === 0 || $value === "disabled"); break; + } + + if (isset($baseField->$property)) + { + return $baseField->$property == $value; + } + + return false; + } + + protected function writeVardefExtension($bean_name, $field, $def_override) + { + //Hack for the broken cases module + $vBean = $bean_name == "aCase" ? "Case" : $bean_name; + $file_loc = "$this->base_path/sugarfield_{$field->name}.php"; + + $out = " $val) + { + $out .= override_value_to_string_recursive(array($vBean, "fields", $field->name, $property), "dictionary", $val) . "\n"; + } + + $out .= "\n ?>"; + + if (!file_exists($this->base_path)) + mkdir_recursive($this->base_path); + + if( $fh = @sugar_fopen( $file_loc, 'w' ) ) + { + fputs( $fh, $out); + fclose( $fh ); + return true ; + } + else + { + return false ; + } + } + + protected function removeVardefExtension($field) + { + $file_loc = "$this->base_path/sugarfield_{$field->name}.php"; + + if (is_file($file_loc)) + { + unlink($file_loc); + } + } + + + /** + * DEPRECIATED: Use addFieldObject instead. + * Adds a Custom Field using parameters + * + * @param unknown_type $name + * @param unknown_type $label + * @param unknown_type $type + * @param unknown_type $max_size + * @param unknown_type $required_option + * @param unknown_type $default_value + * @param unknown_type $ext1 + * @param unknown_type $ext2 + * @param unknown_type $ext3 + * @param unknown_type $audited + * @param unknown_type $mass_update + * @param unknown_type $ext4 + * @param unknown_type $help + * @param unknown_type $duplicate_merge + * @param unknown_type $comment + * @return boolean + */ + function addField($name,$label='', $type='Text',$max_size='255',$required_option='optional', $default_value='', $ext1='', $ext2='', $ext3='',$audited=0, $mass_update = 0 , $ext4='', $help='',$duplicate_merge=0, $comment=''){ + require_once('modules/DynamicFields/templates/Fields/TemplateField.php'); + $field = new TemplateField(); + $field->label = $label; + if(empty($field->label)){ + $field->label = $name; + } + $field->name = $name; + $field->type = $type; + $field->len = $max_size; + $field->required = (!empty($required_option) && $required_option != 'optional'); + $field->default = $default_value; + $field->ext1 = $ext1; + $field->ext2 = $ext2; + $field->ext3 = $ext3; + $field->ext4 = $ext4; + $field->help = $help; + $field->comments = $comment; + $field->massupdate = $mass_update; + $field->duplicate_merge = $duplicate_merge; + $field->audited = $audited; + $field->reportable = 1; + return $this->addFieldObject($field); + } + + /** + * Creates the custom table with an id of id_c + * + */ + function createCustomTable($execute = true){ + $out = ""; + if (!$GLOBALS['db']->tableExists($this->bean->table_name."_cstm")) { + $GLOBALS['log']->debug('creating custom table for '. $this->bean->table_name); + $query = 'CREATE TABLE '.$this->bean->table_name.'_cstm ( '; + $query .='id_c ' . $this->bean->dbManager->helper->getColumnType('id') .' NOT NULL'; + $query .=', PRIMARY KEY ( id_c ) )'; + if($GLOBALS['db']->dbType == 'mysql'){ + $query .= ' CHARACTER SET utf8 COLLATE utf8_general_ci'; + } + $out = $query . "\n"; + if ($execute) + $GLOBALS['db']->query($query); + $out .= $this->add_existing_custom_fields($execute); + } + + return $out; + } + + /** + * Updates the db schema and adds any custom fields we have used if the custom table was dropped + * + */ + function add_existing_custom_fields($execute = true){ + $out = ""; + if($this->bean->hasCustomFields()){ + foreach($this->bean->field_defs as $name=>$data){ + if(empty($data['source']) || $data['source'] != 'custom_fields') + continue; + $out .= $this->add_existing_custom_field($data, $execute); + } + } + return $out; + } + + function add_existing_custom_field($data, $execute = true) + { + + $field = get_widget ( $data ['type'] ); + $field->populateFromRow($data); + $query = "/*MISSING IN DATABASE - {$data['name']} - ROW*/\n" + . $field->get_db_add_alter_table($this->bean->table_name . '_cstm'); + $out = $query . "\n"; + if ($execute) + $GLOBALS['db']->query($query); + + return $out; + } + + public function repairCustomFields($execute = true) + { + $out = $this->createCustomTable($execute); + //If the table didn't exist, createCustomTable will have returned all the SQL to create and populate it + if (!empty($out)) + return "/*Checking Custom Fields for module : {$this->module} */\n$out"; + //Otherwise make sure all the custom fields defined in the vardefs exist in the custom table. + //We aren't checking for data types, just that the column exists. + $db = $GLOBALS['db']; + $tablename = $this->bean->table_name."_cstm"; + $compareFieldDefs = $db->getHelper()->get_columns($tablename); + foreach($this->bean->field_defs as $name=>$data){ + if(empty($data['source']) || $data['source'] != 'custom_fields') + continue; + if(!empty($compareFieldDefs[$name])) { + continue; + } + $out .= $this->add_existing_custom_field($data, $execute); + } + if (!empty($out)) + $out = "/*Checking Custom Fields for module : {$this->module} */\n$out"; + + return $out; + } + + /** + * Adds a label to the module's mod_strings for the current language + * Note that the system label name + * + * @param string $displayLabel The label value to be displayed + * @return string The core of the system label name - returns currency_id5 for example, when the full label would then be LBL_CURRENCY_ID5 + * TODO: Only the core is returned for historical reasons - switch to return the real system label + */ + function addLabel ( $displayLabel ) + { + $mod_strings = return_module_language($GLOBALS[ 'current_language' ], $this->module); + $limit = 10; + $count = 0; + $field_key = $this->getDBName($displayLabel, false); + $systemLabel = $field_key; + if(!$this->use_existing_labels){ // use_existing_labels defaults to false in this module; as of today, only set to true by ModuleInstaller.php + while( isset( $mod_strings [ $systemLabel ] ) && $count <= $limit ) + { + $systemLabel = $field_key. "_$count"; + $count++; + } + } + $selMod = (!empty($_REQUEST['view_module'])) ? $_REQUEST['view_module'] : $this->module; + require_once 'modules/ModuleBuilder/parsers/parser.label.php' ; + $parser = new ParserLabel ( $selMod , isset ( $_REQUEST [ 'view_package' ] ) ? $_REQUEST [ 'view_package' ] : null ) ; + $parser->handleSave ( array('label_'. $systemLabel => $displayLabel ) , $GLOBALS [ 'current_language' ] ) ; + + return $systemLabel; + } + + /** + * Returns a Database Safe Name + * + * @param STRING $name + * @param BOOLEAN $_C do we append _c to the name + * @return STRING + */ + function getDBName($name, $_C= true){ + static $cached_results = array(); + if(!empty($cached_results[$name])) + { + return $cached_results[$name]; + } + $exclusions = array('parent_type', 'parent_id', 'currency_id', 'parent_name'); + // Remove any non-db friendly characters + $return_value = preg_replace("/[^\w]+/","_",$name); + if($_C == true && !in_array($return_value, $exclusions) && substr($return_value, -2) != '_c'){ + $return_value .= '_c'; + } + $cached_results[$name] = $return_value; + return $return_value; + } + + function setWhereClauses(&$where_clauses){ + if (isset($this->avail_fields)) { + foreach($this->avail_fields as $name=>$value){ + if(!empty($_REQUEST[$name])){ + $where_clauses[] = $this->bean->table_name . "_cstm.$name LIKE '". $GLOBALS['db']->quote($_REQUEST[$name]). "%'"; + } + } + } + + } + + /////////////////////////BACKWARDS COMPATABILITY MODE FOR PRE 5.0 MODULES\\\\\\\\\\\\\\\\\\\\\\\\\\\ + ////////////////////////////END BACKWARDS COMPATABILITY MODE FOR PRE 5.0 MODULES\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ + + /** + * + * DEPRECATED + loads fields into the bean + This used to be called during the retrieve process now it is done through a join + Restored from pre-r30895 to maintain support for custom code that may have called retrieve() directly + */ + + function retrieve() + { + if(!isset($this->bean)){ + $GLOBALS['log']->fatal("DynamicField retrieve, bean not instantiated: ".var_export(debug_print_backtrace(), true)); + return false; + } + + if(!$this->bean->hasCustomFields()){ + return false; + } + + $query = "SELECT * FROM ".$this->bean->table_name."_cstm WHERE id_c='".$this->bean->id."'"; + $result = $GLOBALS['db']->query($query); + $row = $GLOBALS['db']->fetchByAssoc($result); + + if($row) + { + foreach($row as $name=>$value) + { + // originally in pre-r30895 we checked if this field was in avail_fields i.e., in fields_meta_data and not deleted + // with the removal of avail_fields post-r30895 we have simplified this - we now retrieve every custom field even if previously deleted + // this is considered harmless as the value although set in the bean will not otherwise be used (nothing else works off the list of fields in the bean) + $this->bean->$name = $value; + } + } + + } + + function populateXTPL(&$xtpl, $view){ + if($this->bean->hasCustomFields()){ + $results = $this->getAllFieldsView($view, 'xtpl'); + foreach($results as $name=>$value){ + if(is_array($value['xtpl'])){ + foreach($value['xtpl'] as $xName=>$xValue){ + $xtpl->assign(strtoupper($xName), $xValue); + + } + }else{ + $xtpl->assign(strtoupper($name), $value['xtpl']); + } + } + } + + } + + function populateAllXTPL(&$xtpl, $view){ + $this->populateXTPL($xtpl, $view); + + } + + function getAllFieldsView($view, $type){ + $results = array(); + foreach($this->bean->field_defs as $name=>$data){ + if(empty($data['source']) || $data['source'] != 'custom_fields')continue; + require_once ('modules/DynamicFields/FieldCases.php'); + $field = get_widget ( $data ['type'] ); + $field->populateFromRow($data); + $field->view = $view; + $field->bean =& $this->bean; + switch(strtolower($type)){ + case 'xtpl': + $results[$name] = array('xtpl'=>$field->get_xtpl()); + break; + case 'html': + $results[$name] = array('html'=> $field->get_html(), 'label'=> $field->get_html_label(), 'fieldType'=>$field->data_type, 'isCustom' =>true); + break; + + } + + } + return $results; + } + + ////////////////////////////END BACKWARDS COMPATABILITY MODE FOR PRE 5.0 MODULES\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ +} + +?> diff --git a/modules/DynamicFields/FieldCases.php b/modules/DynamicFields/FieldCases.php new file mode 100644 index 00000000..cb43e9be --- /dev/null +++ b/modules/DynamicFields/FieldCases.php @@ -0,0 +1,150 @@ + \ No newline at end of file diff --git a/modules/DynamicFields/FieldViewer.php b/modules/DynamicFields/FieldViewer.php new file mode 100644 index 00000000..0ef8e705 --- /dev/null +++ b/modules/DynamicFields/FieldViewer.php @@ -0,0 +1,120 @@ +ss = new Sugar_Smarty(); + } + function getLayout($vardef){ + + if(empty($vardef['type']))$vardef['type'] = 'varchar'; + $mod = return_module_language($GLOBALS['current_language'], 'EditCustomFields'); + $this->ss->assign('vardef', $vardef); + $this->ss->assign('MOD', $mod); + $this->ss->assign('APP', $GLOBALS['app_strings']); + //Only display range search option if in Studio, not ModuleBuilder + $this->ss->assign('range_search_option_enabled', empty($_REQUEST['view_package'])); + + $GLOBALS['log']->debug('FieldViewer.php->getLayout() = '.$vardef['type']); + switch($vardef['type']){ + case 'address': + return $this->ss->fetch('modules/DynamicFields/templates/Fields/Forms/address.tpl'); + case 'bool': + return $this->ss->fetch('modules/DynamicFields/templates/Fields/Forms/bool.tpl'); + case 'int': + return $this->ss->fetch('modules/DynamicFields/templates/Fields/Forms/int.tpl'); + case 'float': + return $this->ss->fetch('modules/DynamicFields/templates/Fields/Forms/float.tpl'); + case 'decimal': + return $this->ss->fetch('modules/DynamicFields/templates/Fields/Forms/float.tpl'); + case 'date': + require_once('modules/DynamicFields/templates/Fields/Forms/date.php'); + return get_body($this->ss, $vardef); + case 'datetimecombo': + case 'datetime': + require_once('modules/DynamicFields/templates/Fields/Forms/datetimecombo.php'); + return get_body($this->ss, $vardef); + case 'enum': + require_once('modules/DynamicFields/templates/Fields/Forms/enum2.php'); + return get_body($this->ss, $vardef); + case 'multienum': + require_once('modules/DynamicFields/templates/Fields/Forms/multienum.php'); + return get_body($this->ss, $vardef); + case 'radioenum': + require_once('modules/DynamicFields/templates/Fields/Forms/radioenum.php'); + return get_body($this->ss, $vardef); + case 'html': + require_once('modules/DynamicFields/templates/Fields/Forms/html.php'); + return get_body($this->ss, $vardef); + case 'currency': + return $this->ss->fetch('modules/DynamicFields/templates/Fields/Forms/currency.tpl'); + case 'relate': + require_once('modules/DynamicFields/templates/Fields/Forms/relate.php'); + return get_body($this->ss, $vardef); + case 'parent': + require_once('modules/DynamicFields/templates/Fields/Forms/parent.php'); + return get_body($this->ss, $vardef); + case 'text': + return $this->ss->fetch('modules/DynamicFields/templates/Fields/Forms/text.tpl'); + case 'encrypt': + require_once('modules/DynamicFields/templates/Fields/Forms/encrypt.php'); + return get_body($this->ss, $vardef); + case 'iframe': + require_once('modules/DynamicFields/templates/Fields/Forms/iframe.php'); + return get_body($this->ss, $vardef); + case 'url': + require_once('modules/DynamicFields/templates/Fields/Forms/url.php'); + return get_body($this->ss, $vardef); + case 'phone:': + require_once('modules/DynamicFields/templates/Fields/Forms/phone.php'); + return get_body($this->ss, $vardef); + default: + $file = false; + if(file_exists('custom/modules/DynamicFields/templates/Fields/Forms/' . $vardef['type'] . '.php')){ + $file = 'custom/modules/DynamicFields/templates/Fields/Forms/' . $vardef['type'] . '.php'; + } elseif(file_exists('modules/DynamicFields/templates/Fields/Forms/' . $vardef['type'] . '.php')){ + $file = 'modules/DynamicFields/templates/Fields/Forms/' . $vardef['type'] . '.php'; + } + if(!empty($file)){ + require_once($file); + return get_body($this->ss, $vardef); + }else{ + return $this->ss->fetch('modules/DynamicFields/templates/Fields/Forms/varchar.tpl'); + } + } + } + +} \ No newline at end of file diff --git a/modules/DynamicFields/FieldsMetaData.php b/modules/DynamicFields/FieldsMetaData.php new file mode 100644 index 00000000..3627defe --- /dev/null +++ b/modules/DynamicFields/FieldsMetaData.php @@ -0,0 +1,139 @@ +1, "date_start"=>2, "time_start"=>3,); + + var $table_name = 'fields_meta_data'; + var $object_name = 'FieldsMetaData'; + var $module_dir = 'DynamicFields'; + var $column_fields = array( + 'id', + 'name', + 'vname', + 'custom_module', + 'type', + 'len', + 'required', + 'default_value', + 'deleted', + 'ext1', + 'ext2', + 'ext3', + 'audited', + 'massupdate', + 'duplicate_merge', + 'reportable', + ); + + var $list_fields = array( + 'id', + 'name', + 'vname', + 'type', + 'len', + 'required', + 'default_value', + 'audited', + 'massupdate', + 'duplicate_merge', + 'reportable', + ); + + var $field_name_map; + var $new_schema = true; + + ////////////////////////////////////////////////////////////////// + // METHODS + ////////////////////////////////////////////////////////////////// + + function FieldsMetaData() + { + parent::SugarBean(); + $this->disable_row_level_security = true; + } + + function mark_deleted($id) + { + $query = "DELETE FROM $this->table_name WHERE id='$id'"; + $this->db->query($query, true,"Error deleting record: "); + $this->mark_relationships_deleted($id); + + } + + function get_list_view_data(){ + $data = parent::get_list_view_data(); + $data['VNAME'] = translate($this->vname, $this->custom_module); + $data['NAMELINK'] = '  '; + return $data; + } + + + function get_summary_text() + { + return $this->name; + } +} +?> diff --git a/modules/DynamicFields/Save.php b/modules/DynamicFields/Save.php new file mode 100644 index 00000000..b8a7a098 --- /dev/null +++ b/modules/DynamicFields/Save.php @@ -0,0 +1,73 @@ +setup($mod); +}else{ + echo "\nNo Module Included Could Not Save"; +} +$name = $_REQUEST['field_label']; +$options = ''; +if($_REQUEST['field_type'] == 'enum'){ + $options = $_REQUEST['options']; +} +$default_value = ''; + +$custom_fields->addField($name,$name, $_REQUEST['field_type'],'255','optional', $default_value, $options, '', '' ); +$html = $custom_fields->getFieldHTML($name, $_REQUEST['file_type']); + +set_register_value('dyn_layout', 'field_counter', $_REQUEST['field_count']); +$label = $custom_fields->getFieldLabelHTML($name, $_REQUEST['field_type']); +require_once('modules/DynamicLayout/AddField.php'); +$af = new AddField(); +$af->add_field($name, $html,$label, 'window.opener.'); +echo $af->get_script('window.opener.'); +echo "\n"; + +?> diff --git a/modules/DynamicFields/UpgradeFields.php b/modules/DynamicFields/UpgradeFields.php new file mode 100644 index 00000000..f8723351 --- /dev/null +++ b/modules/DynamicFields/UpgradeFields.php @@ -0,0 +1,134 @@ +query( 'SELECT * FROM fields_meta_data WHERE deleted = 0 ORDER BY custom_module'); + $modules = array(); + /* + * get the real field_meta_data + */ + while($row = $db->fetchByAssoc($result)){ + $the_modules = $row['custom_module']; + if(!isset($modules[$the_modules])){ + $modules[$the_modules] = array(); + } + $modules[$the_modules][$row['name']] = $row['name']; + } + + $simulate = false; + if(!isset($_REQUEST['run'])){ + $simulate = true; + echo "SIMULATION MODE - NO CHANGES WILL BE MADE EXCEPT CLEARING CACHE"; + } + + foreach($modules as $the_module=>$fields){ + $class_name = $beanList[$the_module]; + echo "

    Scanning $the_module
    "; + + require_once($beanFiles[$class_name]); + $mod = new $class_name(); + if(!$db->tableExists($mod->table_name . "_cstm")){ + $mod->custom_fields = new DynamicField(); + $mod->custom_fields->setup($mod); + $mod->custom_fields->createCustomTable(); + } + + $result = $db->query("DESCRIBE $mod->table_name" . "_cstm"); + + while($row = $db->fetchByAssoc($result)){ + + + $col = $row['Field']; + $type = $row['Type']; + $fieldDef = $mod->getFieldDefinition($col); + $the_field = get_widget($fieldDef['type']); + $the_field->set($fieldDef); + + if(!isset($fields[$col]) && $col != 'id_c'){ + if(!$simulate)$db->query("ALTER TABLE $mod->table_name" . "_cstm DROP COLUMN $col"); + unset($fields[$col]); + echo "Dropping Column $col from $mod->table_name" . "_cstm for module $the_module
    "; + } else{ + if($col != 'id_c'){ + if(trim($the_field->get_db_type()) != trim($type)){ + + echo "Fixing Column Type for $col changing $type to ". $the_field->get_db_type() . "
    "; + if(!$simulate)$db->query($the_field->get_db_modify_alter_table($mod->table_name . '_cstm')); + } + } + + unset($fields[$col]); + } + + } + + echo sizeof($fields) . " field(s) missing from $mod->table_name" . "_cstm
    "; + foreach($fields as $field){ + echo "Adding Column $field to $mod->table_name" . "_cstm
    "; + if(!$simulate){ + $the_field = $mod->getFieldDefinition($field); + $field = get_widget($the_field['type']); + $field->set($the_field); + $query = $field->get_db_add_alter_table($mod->table_name . '_cstm'); + echo $query; + if(!empty($query)){ + $mod->db->query($query); + } + } + } + } + + + DynamicField::deleteCache(); + echo '
    Done
    '; + if($simulate){ + echo '
    Execute non-simulation mode'; + } + + + + + + + + + ?> \ No newline at end of file diff --git a/modules/DynamicFields/language/en_us.lang.php b/modules/DynamicFields/language/en_us.lang.php new file mode 100644 index 00000000..bfd036c1 --- /dev/null +++ b/modules/DynamicFields/language/en_us.lang.php @@ -0,0 +1,130 @@ + 'Log Call', + 'LNK_NEW_MEETING' => 'Schedule Meeting', + 'LNK_NEW_TASK' => 'Create Task', + 'LNK_NEW_NOTE' => 'Create Note or Attachment', + 'LNK_NEW_EMAIL' => 'Archive Email', + 'LNK_CALL_LIST' => 'Calls', + 'LNK_MEETING_LIST' => 'Meetings', + 'LNK_TASK_LIST' => 'Tasks', + 'LNK_NOTE_LIST' => 'Notes', + 'LNK_EMAIL_LIST' => 'Emails', + 'LBL_ADD_FIELD'=> 'Add Field:', + 'LBL_MODULE_SELECT' => 'Module to Edit', + 'LBL_SEARCH_FORM_TITLE' => 'Module Search', + 'COLUMN_TITLE_NAME' => 'Field Name', + 'COLUMN_TITLE_DISPLAY_LABEL' => 'Display Label', + 'COLUMN_TITLE_LABEL_VALUE' => 'Label Value', + 'COLUMN_TITLE_LABEL' => 'System Label', + 'COLUMN_TITLE_DATA_TYPE' => 'Data Type', + 'COLUMN_TITLE_MAX_SIZE' => 'Max Size', + 'COLUMN_TITLE_HELP_TEXT' => 'Help Text', + 'COLUMN_TITLE_COMMENT_TEXT' => 'Comment Text', + 'COLUMN_TITLE_REQUIRED_OPTION' => 'Required Field', + 'COLUMN_TITLE_DEFAULT_VALUE' => 'Default Value', + 'COLUMN_TITLE_DEFAULT_EMAIL' => 'Default Value', + 'COLUMN_TITLE_EXT1' => 'Extra Meta Field 1', + 'COLUMN_TITLE_EXT2' => 'Extra Meta Field 2', + 'COLUMN_TITLE_EXT3' => 'Extra Meta Field 3', + 'COLUMN_TITLE_FRAME_HEIGHT' => 'IFrame Height', + 'COLUMN_TITLE_HTML_CONTENT' =>'HTML', + 'COLUMN_TITLE_URL'=>'Default URL', + 'COLUMN_TITLE_AUDIT' =>'Audit', + 'COLUMN_TITLE_REPORTABLE' => 'Reportable', + 'COLUMN_TITLE_MIN_VALUE' => 'Min Value', + 'COLUMN_TITLE_MAX_VALUE' => 'Max Value', + 'COLUMN_TITLE_LABEL_ROWS' => 'Rows', + 'COLUMN_TITLE_LABEL_COLS' => 'Columns', + 'COLUMN_TITLE_DISPLAYED_ITEM_COUNT'=>'# Items displayed', + 'COLUMN_TITLE_AUTOINC_NEXT' => 'Auto Increment Next Value', + 'COLUMN_DISABLE_NUMBER_FORMAT' => 'Disable Format', + 'COLUMN_TITLE_ENABLE_RANGE_SEARCH' => 'Enable Range Search', + 'LBL_DROP_DOWN_LIST' => 'Drop Down List', + 'LBL_RADIO_FIELDS'=> 'Radio Fields', + 'LBL_MULTI_SELECT_LIST'=> 'Multi Select List', + 'COLUMN_TITLE_PRECISION'=> 'Precision', + 'MSG_DELETE_CONFIRM' => 'Are you sure you want to delete this item?', + 'POPUP_INSERT_HEADER_TITLE' => 'Add Custom Field', + 'POPUP_EDIT_HEADER_TITLE' => 'Edit Custom Field', + 'LNK_SELECT_CUSTOM_FIELD' => 'Select Custom Field', + 'LNK_REPAIR_CUSTOM_FIELD' => 'Repair Custom Fields', + 'LBL_MODULE' => 'Module', + 'COLUMN_TITLE_MASS_UPDATE'=>'Mass Update', + 'COLUMN_TITLE_IMPORTABLE'=>'Importable', + 'COLUMN_TITLE_DUPLICATE_MERGE'=>'Duplicate Merge', + 'LBL_LABEL'=>'Label', + 'LBL_DATA_TYPE'=>'Data Type', + 'LBL_DEFAULT_VALUE'=>'Default Value', + 'LBL_AUDITED'=>'Audited', + 'LBL_REPORTABLE'=>'Reportable', + 'ERR_RESERVED_FIELD_NAME' => "Reserved Keyword", + 'ERR_SELECT_FIELD_TYPE' => 'Please Select a Field Type', + 'ERR_FIELD_NAME_ALREADY_EXISTS' => 'Field Name already exists', + 'LBL_BTN_ADD' => 'Add', + 'LBL_BTN_EDIT' => 'Edit', + 'LBL_GENERATE_URL' => 'Generate URL', + 'LBL_DEPENDENT_CHECKBOX'=>'Dependent', + 'LBL_DEPENDENT_TRIGGER'=>'Trigger', + 'LBL_CALCULATED'=>'Calculated Value', + 'LBL_FORMULA'=>'Formula', + 'LBL_DYNAMIC_VALUES_CHECKBOX' => 'Dependent', + 'LBL_BTN_EDIT_VISIBILITY'=>'Edit Visibility', + 'LBL_LINK_TARGET'=>'Open Link In', + 'LBL_IMAGE_WIDTH' => 'Width', + 'LBL_IMAGE_HEIGHT' => 'Height', + 'LBL_IMAGE_BORDER' => 'Border', + 'COLUMN_TITLE_VALIDATE_US_FORMAT' => 'U.S. Format', + 'LBL_DEPENDENT'=>'Dependent', + 'LBL_VISIBLE_IF'=>'Visible If', + 'LBL_ENFORCED'=>'Enforced', + +); + + +?> diff --git a/modules/DynamicFields/templates/Fields/Forms/address.tpl b/modules/DynamicFields/templates/Fields/Forms/address.tpl new file mode 100644 index 00000000..8d74ec78 --- /dev/null +++ b/modules/DynamicFields/templates/Fields/Forms/address.tpl @@ -0,0 +1,86 @@ +{* + +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + + + +*} + + +{include file="modules/DynamicFields/templates/Fields/Forms/coreTop.tpl"} +
    {sugar_translate module="DynamicFields" label="COLUMN_TITLE_DEFAULT_VALUE"}: + {if $hideLevel < 5} + + {else} + {$vardef.default} + {/if} +
    {sugar_translate module="DynamicFields" label="COLUMN_TITLE_MAX_SIZE"}: + {if $hideLevel < 5} + + + {if $action=="saveSugarField"} + + {/if} + {literal} + + + {else} + {$vardef.len} + {/if} +
    {sugar_translate module="DynamicFields" label="COLUMN_TITLE_DEFAULT_VALUE"}: 5}disabled{/if} />{if $hideLevel > 5}{/if}
    {sugar_translate module="DynamicFields" label="COLUMN_TITLE_REQUIRED_OPTION"}: 5}disabled{/if}/>{if $hideLevel > 5}{/if}
    {sugar_translate module="DynamicFields" label="COLUMN_TITLE_AUDIT"}: 5}disabled{/if}/>{if $hideLevel > 5}{/if}
    {sugar_translate module="DynamicFields" label="COLUMN_TITLE_IMPORTABLE"}: + {if $hideLevel < 5} + {html_options name="importable" id="importable" selected=$vardef.importable options=$importable_options} + + + {else} + {if isset($vardef.importable)}{$importable_options[$vardef.importable]} + {else}{$importable_options.true}{/if} + {/if} +
    {sugar_translate module="DynamicFields" label="COLUMN_TITLE_DUPLICATE_MERGE"}: +{if $hideLevel < 5} + {html_options name="duplicate_merge" id="duplicate_merge" selected=$vardef.duplicate_merge_dom_value options=$duplicate_merge_options} + + +{else} + {if isset($vardef.duplicate_merge_dom_value)}{$vardef.duplicate_merge_dom_value} + {else}{$duplicate_merge_options[0]}{/if} +{/if} +
    diff --git a/modules/DynamicFields/templates/Fields/Forms/coreTop.tpl b/modules/DynamicFields/templates/Fields/Forms/coreTop.tpl new file mode 100644 index 00000000..219db902 --- /dev/null +++ b/modules/DynamicFields/templates/Fields/Forms/coreTop.tpl @@ -0,0 +1,94 @@ +{* + +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + + + +*} + + + + + + + + + + + + + + + + + + + + diff --git a/modules/DynamicFields/templates/Fields/Forms/currency.tpl b/modules/DynamicFields/templates/Fields/Forms/currency.tpl new file mode 100644 index 00000000..f925774b --- /dev/null +++ b/modules/DynamicFields/templates/Fields/Forms/currency.tpl @@ -0,0 +1,62 @@ +{* + +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + + + +*} + +{include file="modules/DynamicFields/templates/Fields/Forms/coreTop.tpl"} +{if $range_search_option_enabled} + + + + +{/if} +{include file="modules/DynamicFields/templates/Fields/Forms/coreBottom.tpl"} \ No newline at end of file diff --git a/modules/DynamicFields/templates/Fields/Forms/date.php b/modules/DynamicFields/templates/Fields/Forms/date.php new file mode 100644 index 00000000..c95744f7 --- /dev/null +++ b/modules/DynamicFields/templates/Fields/Forms/date.php @@ -0,0 +1,47 @@ +assign('default_values', array_flip($td->dateStrings)); + return $ss->fetch('modules/DynamicFields/templates/Fields/Forms/date.tpl'); +} + +?> diff --git a/modules/DynamicFields/templates/Fields/Forms/date.tpl b/modules/DynamicFields/templates/Fields/Forms/date.tpl new file mode 100644 index 00000000..4d76d09c --- /dev/null +++ b/modules/DynamicFields/templates/Fields/Forms/date.tpl @@ -0,0 +1,72 @@ +{* + +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + + + +*} +{include file="modules/DynamicFields/templates/Fields/Forms/coreTop.tpl"} + + + + + + + + +{if $range_search_option_enabled} + + + + +{/if} +{include file="modules/DynamicFields/templates/Fields/Forms/coreBottom.tpl"} \ No newline at end of file diff --git a/modules/DynamicFields/templates/Fields/Forms/datetimecombo.php b/modules/DynamicFields/templates/Fields/Forms/datetimecombo.php new file mode 100644 index 00000000..6211d9e4 --- /dev/null +++ b/modules/DynamicFields/templates/Fields/Forms/datetimecombo.php @@ -0,0 +1,84 @@ +assign('default_values', array_flip($td->dateStrings)); + + global $timedate; + $user_time_format = $timedate->get_user_time_format(); + $show_meridiem = preg_match('/pm$/i', $user_time_format) ? true : false; + if($show_meridiem) { + $ss->assign('default_hours_values', array_flip($td->hoursStrings)); + } else { + $ss->assign('default_hours_values', array_flip($td->hoursStrings24)); + } + + $ss->assign('show_meridiem', $show_meridiem); + $ss->assign('default_minutes_values', array_flip($td->minutesStrings)); + $ss->assign('default_meridiem_values', array_flip($td->meridiemStrings)); + if(isset($vardef['display_default']) && strstr($vardef['display_default'] , '&')){ + $dt = explode("&", $vardef['display_default']); //+1 day&06:00pm + $date = $dt[0]; + $defaultTime = $dt[1]; + $hours = substr($defaultTime, 0, 2); + $minitues = substr($defaultTime, 3, 2); + $meridiem = substr($defaultTime, 5, 2); + if(!$show_meridiem) { + preg_match('/(am|pm)$/i', $meridiem, $matches); + if(strtolower($matches[0]) == 'am' && $hours == 12) { + $hours = '00'; + } else if (strtolower($matches[0]) == 'pm' && $hours != 12) { + $hours += 12; + } + } + $ss->assign('default_date', $date); + } + $ss->assign('default_hours', $hours); + $ss->assign('default_minutes', $minitues); + $ss->assign('default_meridiem', $meridiem); + $ss->assign('defaultTime', $defaultTime); + return $ss->fetch('modules/DynamicFields/templates/Fields/Forms/datetimecombo.tpl'); +} + +?> diff --git a/modules/DynamicFields/templates/Fields/Forms/datetimecombo.tpl b/modules/DynamicFields/templates/Fields/Forms/datetimecombo.tpl new file mode 100644 index 00000000..9d057a94 --- /dev/null +++ b/modules/DynamicFields/templates/Fields/Forms/datetimecombo.tpl @@ -0,0 +1,117 @@ +{* + +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + +*} + +{include file="modules/DynamicFields/templates/Fields/Forms/coreTop.tpl"} +{literal} + +{/literal} + + + + + + + + + + + + +{if $range_search_option_enabled} + + + + +{/if} + +{include file="modules/DynamicFields/templates/Fields/Forms/coreBottom.tpl"} \ No newline at end of file diff --git a/modules/DynamicFields/templates/Fields/Forms/encrypt.php b/modules/DynamicFields/templates/Fields/Forms/encrypt.php new file mode 100644 index 00000000..f6a779ba --- /dev/null +++ b/modules/DynamicFields/templates/Fields/Forms/encrypt.php @@ -0,0 +1,48 @@ +fetch('modules/DynamicFields/templates/Fields/Forms/encrypt.tpl'); + } +?> diff --git a/modules/DynamicFields/templates/Fields/Forms/encrypt.tpl b/modules/DynamicFields/templates/Fields/Forms/encrypt.tpl new file mode 100644 index 00000000..f0989164 --- /dev/null +++ b/modules/DynamicFields/templates/Fields/Forms/encrypt.tpl @@ -0,0 +1,51 @@ +{* + +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + +*} + +{include file="modules/DynamicFields/templates/Fields/Forms/coreTop.tpl"} + + + +{include file="modules/DynamicFields/templates/Fields/Forms/coreBottom.tpl"} \ No newline at end of file diff --git a/modules/DynamicFields/templates/Fields/Forms/enum.tpl b/modules/DynamicFields/templates/Fields/Forms/enum.tpl new file mode 100644 index 00000000..1547d622 --- /dev/null +++ b/modules/DynamicFields/templates/Fields/Forms/enum.tpl @@ -0,0 +1,78 @@ +{* + +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + + + +*} + +{include file="modules/DynamicFields/templates/Fields/Forms/coreTop.tpl"} + + + + + + + + + + + + + + +{include file="modules/DynamicFields/templates/Fields/Forms/coreBottom.tpl"} \ No newline at end of file diff --git a/modules/DynamicFields/templates/Fields/Forms/enum2.php b/modules/DynamicFields/templates/Fields/Forms/enum2.php new file mode 100644 index 00000000..b379a2cc --- /dev/null +++ b/modules/DynamicFields/templates/Fields/Forms/enum2.php @@ -0,0 +1,115 @@ +getPackageModule($view_package, $_REQUEST['view_module']); + $lang = $GLOBALS['current_language']; + //require_once($package->getPackageDir()."/include/language/$lang.lang.php"); + $module->mblanguage->generateAppStrings(false); + $package_strings = $module->mblanguage->appListStrings[$lang.'.lang.php']; + } + } + + global $app_list_strings; + $my_list_strings = $app_list_strings; + $my_list_strings = array_merge($my_list_strings, $package_strings); + foreach($my_list_strings as $key=>$value){ + if(!is_array($value)){ + unset($my_list_strings[$key]); + } + } + $dropdowns = array_keys($my_list_strings); + sort($dropdowns); + $default_dropdowns = array(); + if(!empty($vardef['options']) && !empty($my_list_strings[$vardef['options']])){ + $default_dropdowns = $my_list_strings[$vardef['options']]; + }else{ + //since we do not have a default value then we should assign the first one. + $key = $dropdowns[0]; + $default_dropdowns = $my_list_strings[$key]; + } + + $selected_dropdown = ''; + if(!empty($vardef['options'])){ + $selected_dropdown = $vardef['options']; + + } + $show = true; + if(!empty($_REQUEST['refresh_dropdown'])) + $show = false; + + $ss->assign('dropdowns', $dropdowns); + $ss->assign('default_dropdowns', $default_dropdowns); + $ss->assign('selected_dropdown', $selected_dropdown); + $ss->assign('show', $show); + $ss->assign('selected_options', $selected_options); + $ss->assign('multi', isset($multi) ? $multi: false); + $ss->assign('dropdown_name',(!empty($vardef['options']) ? $vardef['options'] : '')); + + require_once('include/JSON.php'); + $json = new JSON(JSON_LOOSE_TYPE); + $ss->assign('app_list_strings', "''"); + return $ss->fetch('modules/DynamicFields/templates/Fields/Forms/enum.tpl'); + } +?> diff --git a/modules/DynamicFields/templates/Fields/Forms/float.tpl b/modules/DynamicFields/templates/Fields/Forms/float.tpl new file mode 100644 index 00000000..d9d1a5b2 --- /dev/null +++ b/modules/DynamicFields/templates/Fields/Forms/float.tpl @@ -0,0 +1,91 @@ +{* + +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + + + +*} + + +{include file="modules/DynamicFields/templates/Fields/Forms/coreTop.tpl"} + + + + + + + + + {else} + {$vardef.len} + {/if} + + +{if $range_search_option_enabled} + + + + +{/if} + + + + + +{include file="modules/DynamicFields/templates/Fields/Forms/coreBottom.tpl"} \ No newline at end of file diff --git a/modules/DynamicFields/templates/Fields/Forms/html.php b/modules/DynamicFields/templates/Fields/Forms/html.php new file mode 100644 index 00000000..0841d9cb --- /dev/null +++ b/modules/DynamicFields/templates/Fields/Forms/html.php @@ -0,0 +1,55 @@ +assign('MOD', $edit_mod_strings); + + $edValue = ''; + if(!empty($vardef['default_value'])) { + $edValue = $vardef['default_value']; + $edValue = str_replace(array("\r\n", "\n"), " ",$edValue); + } + $ss->assign('HTML_EDITOR', $edValue); + $ss->assign('preSave', 'document.popup_form.presave();'); + /////////////////////////////////// + return $ss->fetch('modules/DynamicFields/templates/Fields/Forms/html.tpl'); +} +?> diff --git a/modules/DynamicFields/templates/Fields/Forms/html.tpl b/modules/DynamicFields/templates/Fields/Forms/html.tpl new file mode 100644 index 00000000..5fe13bf9 --- /dev/null +++ b/modules/DynamicFields/templates/Fields/Forms/html.tpl @@ -0,0 +1,75 @@ +{* + +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + + + +*} + + +{include file="modules/DynamicFields/templates/Fields/Forms/coreTop.tpl"} + + + + + +{include file="modules/DynamicFields/templates/Fields/Forms/coreBottom.tpl"} + + +{/literal} \ No newline at end of file diff --git a/modules/DynamicFields/templates/Fields/Forms/iframe.php b/modules/DynamicFields/templates/Fields/Forms/iframe.php new file mode 100644 index 00000000..22d17ace --- /dev/null +++ b/modules/DynamicFields/templates/Fields/Forms/iframe.php @@ -0,0 +1,48 @@ +get_template_vars(); + $fields = $vars['module']->mbvardefs->vardefs['fields']; + $fieldOptions = array(); + foreach($fields as $id=>$def) { + $fieldOptions[$id] = $def['name']; + } + $ss->assign('fieldOpts', $fieldOptions); + return $ss->fetch('modules/DynamicFields/templates/Fields/Forms/iframe.tpl'); + } diff --git a/modules/DynamicFields/templates/Fields/Forms/iframe.tpl b/modules/DynamicFields/templates/Fields/Forms/iframe.tpl new file mode 100644 index 00000000..cea2d229 --- /dev/null +++ b/modules/DynamicFields/templates/Fields/Forms/iframe.tpl @@ -0,0 +1,116 @@ +{* + +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + + + +*} + + +{include file="modules/DynamicFields/templates/Fields/Forms/coreTop.tpl"} + + + + + + + + + + + + + + + + + + + + + +{include file="modules/DynamicFields/templates/Fields/Forms/coreBottom.tpl"} \ No newline at end of file diff --git a/modules/DynamicFields/templates/Fields/Forms/image.php b/modules/DynamicFields/templates/Fields/Forms/image.php new file mode 100644 index 00000000..30a9223f --- /dev/null +++ b/modules/DynamicFields/templates/Fields/Forms/image.php @@ -0,0 +1,63 @@ +get_template_vars(); + $fields = $vars['module']->mbvardefs->vardefs['fields']; + $fieldOptions = array(); + foreach($fields as $id=>$def) { + $fieldOptions[$id] = $def['name']; + } + $ss->assign('fieldOpts', $fieldOptions); + $link_target = !empty($vardef['link_target']) ? $vardef['link_target'] : '_blank'; + $ss->assign('TARGET_OPTIONS', get_select_options_with_id($app_list_strings['link_target_dom'], $link_target)); + $ss->assign('LINK_TARGET', $link_target); + $ss->assign('LINK_TARGET_LABEL', $app_list_strings['link_target_dom'][$link_target]); + + $ss->assign('hideImportable', 'false'); + $ss->assign('hideDuplicatable', 'false'); + return $ss->fetch('modules/DynamicFields/templates/Fields/Forms/image.tpl'); + } + +?> diff --git a/modules/DynamicFields/templates/Fields/Forms/image.tpl b/modules/DynamicFields/templates/Fields/Forms/image.tpl new file mode 100644 index 00000000..158fb5e0 --- /dev/null +++ b/modules/DynamicFields/templates/Fields/Forms/image.tpl @@ -0,0 +1,78 @@ +{* + +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + + + +*} + + +{include file="modules/DynamicFields/templates/Fields/Forms/coreTop.tpl"} + + + + + + + + + + + + + +{include file="modules/DynamicFields/templates/Fields/Forms/coreBottom.tpl"} \ No newline at end of file diff --git a/modules/DynamicFields/templates/Fields/Forms/int.tpl b/modules/DynamicFields/templates/Fields/Forms/int.tpl new file mode 100644 index 00000000..af14846a --- /dev/null +++ b/modules/DynamicFields/templates/Fields/Forms/int.tpl @@ -0,0 +1,133 @@ +{* + +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + + + +*} + + +{include file="modules/DynamicFields/templates/Fields/Forms/coreTop.tpl"} + + + + + + + + + + + + + + + + {else} + {$vardef.len} + {/if} + + +{if $range_search_option_enabled} + + + + +{/if} +{* + +*} +{if !empty($vardef.auto_increment) } + + + + +{/if} + + + + + +{include file="modules/DynamicFields/templates/Fields/Forms/coreBottom.tpl"} \ No newline at end of file diff --git a/modules/DynamicFields/templates/Fields/Forms/multienum.php b/modules/DynamicFields/templates/Fields/Forms/multienum.php new file mode 100644 index 00000000..ea247261 --- /dev/null +++ b/modules/DynamicFields/templates/Fields/Forms/multienum.php @@ -0,0 +1,46 @@ + diff --git a/modules/DynamicFields/templates/Fields/Forms/multienum.tpl b/modules/DynamicFields/templates/Fields/Forms/multienum.tpl new file mode 100644 index 00000000..dfd784d8 --- /dev/null +++ b/modules/DynamicFields/templates/Fields/Forms/multienum.tpl @@ -0,0 +1,89 @@ +{* + +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + + + +*} + + +{include file="modules/DynamicFields/templates/Fields/Forms/coreTop.tpl"} + + + + + + + + + + + + + + + + + +{include file="modules/DynamicFields/templates/Fields/Forms/coreBottom.tpl"} + + diff --git a/modules/DynamicFields/templates/Fields/Forms/parent.php b/modules/DynamicFields/templates/Fields/Forms/parent.php new file mode 100644 index 00000000..c1934f5c --- /dev/null +++ b/modules/DynamicFields/templates/Fields/Forms/parent.php @@ -0,0 +1,48 @@ +fetch('modules/DynamicFields/templates/Fields/Forms/parent.tpl'); + } +?> diff --git a/modules/DynamicFields/templates/Fields/Forms/parent.tpl b/modules/DynamicFields/templates/Fields/Forms/parent.tpl new file mode 100644 index 00000000..9a596fce --- /dev/null +++ b/modules/DynamicFields/templates/Fields/Forms/parent.tpl @@ -0,0 +1,88 @@ +{* + +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + + + +*} + + +
    {sugar_translate module="DynamicFields" label="COLUMN_TITLE_NAME"}: + {if $hideLevel == 0} + name) && $package->name != "studio"}30{else}28{/if} type="text" name="name" value="{$vardef.name}" + onchange=" + document.getElementById('label_key_id').value = 'LBL_'+document.getElementById('field_name_id').value.toUpperCase(); + document.getElementById('label_value_id').value = document.getElementById('field_name_id').value.replace(/_/,' '); + document.getElementById('field_name_id').value = document.getElementById('field_name_id').value.toLowerCase();" /> + {else} + + {$vardef.name} + {/if} + +
    {sugar_translate module="DynamicFields" label="COLUMN_TITLE_DISPLAY_LABEL"}: + +
    {sugar_translate module="DynamicFields" label="COLUMN_TITLE_LABEL"}: + {if $hideLevel < 1} + + {else} + + + {/if} +
    {sugar_translate module="DynamicFields" label="COLUMN_TITLE_HELP_TEXT"}:{if $hideLevel < 5 }{else}{$vardef.help}{/if} +
    {sugar_translate module="DynamicFields" label="COLUMN_TITLE_COMMENT_TEXT"}:{if $hideLevel < 5 }{else}{$vardef.comment}{/if} +
    {sugar_translate module="DynamicFields" label="COLUMN_TITLE_ENABLE_RANGE_SEARCH"}: + 5}disabled{/if} /> + {if $hideLevel > 5}{/if} +
    {sugar_translate module="DynamicFields" label="COLUMN_TITLE_DEFAULT_VALUE"}: +{if $hideLevel < 5} + + +{else} +{sugar_currency_format var=$vardef.default} +{/if} +
    {sugar_translate module="DynamicFields" label="COLUMN_TITLE_DEFAULT_VALUE"}: + {if $hideLevel < 5} + {html_options id='default' name='default' options=$default_values selected=$vardef.display_default} + {else} + {$vardef.display_default} + {/if} +
    {sugar_translate module="DynamicFields" label="COLUMN_TITLE_MASS_UPDATE"}: + {if $hideLevel < 5} + + {else} + + {/if} +
    {sugar_translate module="DynamicFields" label="COLUMN_TITLE_ENABLE_RANGE_SEARCH"}: + 5}disabled{/if} /> + {if $hideLevel > 5}{/if} +
    {sugar_translate module="DynamicFields" label="COLUMN_TITLE_DEFAULT_VALUE"}: + {if $hideLevel < 5} + {html_options name='defaultDate' id='defaultDate_date' options=$default_values selected=$default_date} + {else} + {$default_date} + {/if} +
    + {if $hideLevel < 5} +
    + {html_options name='defaultHours' size='1' id='defaultTime_hours' options=$default_hours_values onchange="timeValueUpdate();" selected=$default_hours} + : + {html_options name='defaultMinutes' size='1' id='defaultTime_minutes' options=$default_minutes_values onchange="timeValueUpdate();" selected=$default_minutes} + {if $show_meridiem === true} + {html_options name='defaultMeridiem' size='1' id='defaultTime_meridiem' options=$default_meridiem_values onchange="timeValueUpdate();" selected=$default_meridiem} + {/if} +
    + + {else} + {$defaultTime} + {/if} +
    {sugar_translate module="DynamicFields" label="COLUMN_TITLE_MASS_UPDATE"}: + {if $hideLevel < 5} + + {else} + + {/if} +
    {sugar_translate module="DynamicFields" label="COLUMN_TITLE_ENABLE_RANGE_SEARCH"}: + 5}disabled{/if} /> + {if $hideLevel > 5}{/if} +
    {sugar_translate module="DynamicFields" label="COLUMN_TITLE_DEFAULT_VALUE"}: + {if $hideLevel < 5} + + {else} + {$vardef.default} + {/if} +
    {sugar_translate module="DynamicFields" label="LBL_DROP_DOWN_LIST"}: + {if $hideLevel < 5} + {html_options name="options" id="options" selected=$selected_dropdown values=$dropdowns output=$dropdowns onChange="ModuleBuilder.dropdownChanged(this.value);"}
      + {else} + {$selected_dropdown} + {/if} +
    {sugar_translate module="DynamicFields" label="COLUMN_TITLE_DEFAULT_VALUE"}: + {if $hideLevel < 5} + {html_options name="default[]" id="default[]" selected=$selected_options options=$default_dropdowns multiple=$multi} + {else} + {$vardef.default} + {/if} +
    {sugar_translate module="DynamicFields" label="COLUMN_TITLE_MASS_UPDATE"}: + {if $hideLevel < 5} + + {else} + + {/if} +
    {sugar_translate module="DynamicFields" label="COLUMN_TITLE_DEFAULT_VALUE"}: + {if $hideLevel < 5} + + + {else} + {$vardef.default} + {/if} +
    {sugar_translate module="DynamicFields" label="COLUMN_TITLE_MAX_SIZE"}: + {if $hideLevel < 5} +
    {sugar_translate module="DynamicFields" label="COLUMN_TITLE_ENABLE_RANGE_SEARCH"}: + 5}disabled{/if} /> + {if $hideLevel > 5}{/if} +
    {sugar_translate module="DynamicFields" label="COLUMN_TITLE_PRECISION"}: + {if $hideLevel < 5} + + + {else} + {$vardef.precision} + {/if} +
    {sugar_translate module="DynamicFields" label="COLUMN_TITLE_HTML_CONTENT"}: + {if $hideLevel < 5} + + + {else} + + + {/if} +
    +
    {sugar_translate module="DynamicFields" label="LBL_GENERATE_URL"}: + {if $hideLevel < 5} + + {else} + + {/if} +
    {html_options name="flo" id="fieldListOptions" options=$fieldOpts} +
    {sugar_translate module="DynamicFields" label="COLUMN_TITLE_DEFAULT_VALUE"}: + {if $hideLevel < 5} + + {else} + {$vardef.default} + {/if} +
    {sugar_translate module="DynamicFields" label="COLUMN_TITLE_MAX_SIZE"}: + {if $hideLevel < 5} + + {literal} + + {/literal} + {else} + {$vardef.len} + {/if} +
    {sugar_translate module="DynamicFields" label="COLUMN_TITLE_FRAME_HEIGHT"}: + {if $hideLevel < 5} + + {else} + {$vardef.height} + {/if} +
    {sugar_translate module="DynamicFields" label="LBL_IMAGE_WIDTH"}: + + {sugar_help text=$mod_strings.LBL_POPHELP_IMAGE_WIDTH FIXX=300 FIXY=200} +
    {sugar_translate module="DynamicFields" label="LBL_IMAGE_HEIGHT"}: + + {sugar_help text=$mod_strings.LBL_POPHELP_IMAGE_HEIGHT FIXX=300 FIXY=220} +
    {sugar_translate module="DynamicFields" label="LBL_IMAGE_BORDER"}: + +
    {sugar_translate module="DynamicFields" label="COLUMN_TITLE_DEFAULT_VALUE"}: + {if $hideLevel < 5} + + + {else} + {$vardef.default} + {/if} +
    {sugar_translate module="DynamicFields" label="COLUMN_TITLE_MIN_VALUE"}: + {if $hideLevel < 5} + + + {else} + {$vardef.range.min} + {/if} +
    {sugar_translate module="DynamicFields" label="COLUMN_TITLE_MAX_VALUE"}: + {if $hideLevel < 5} + + + {else} + {$vardef.range.max} + {/if} +
    {sugar_translate module="DynamicFields" label="COLUMN_TITLE_MAX_SIZE"}: + {if $hideLevel < 5} +
    {sugar_translate module="DynamicFields" label="COLUMN_TITLE_ENABLE_RANGE_SEARCH"}: + 5}disabled{/if} /> + {if $hideLevel > 5}{/if} +
    {sugar_translate module="DynamicFields" label="COLUMN_TITLE_AUTOINC_NEXT"}: + + + + +
    {sugar_translate module="DynamicFields" label="COLUMN_DISABLE_NUMBER_FORMAT"}: + 5}disabled{/if} /> + {if $hideLevel > 5}{/if} +
    {sugar_translate module="DynamicFields" label="LBL_DROP_DOWN_LIST"}: + {if $hideLevel < 5} + {html_options name="ext1" id="ext1" selected=$cf.ext1 values=$dropdowns output=$dropdowns onChange="dropdownChanged(this.value);"} + {else} + {$cf.ext1} + {/if} +
    {sugar_translate module="DynamicFields" label="COLUMN_TITLE_DEFAULT_VALUE"}: + {if $hideLevel < 5} + {html_options name="default_value" id="default_value" selected=$cf.default_value options=$selected_dropdown } + {else} + {$cf.default_value} + {/if} +
    {sugar_translate module="DynamicFields" label="COLUMN_TITLE_DISPLAYED_ITEM_COUNT"}: + {if $hideLevel < 5} + + + {else} + {$cf.ext2} + {/if} +
    {sugar_translate module="DynamicFields" label="COLUMN_TITLE_MASS_UPDATE"}: + {if $hideLevel < 5} + + {else} + + {/if} +
    + + + + + + + + + + + + + +{include file="modules/DynamicFields/templates/Fields/Forms/coreBottom.tpl"} diff --git a/modules/DynamicFields/templates/Fields/Forms/phone.php b/modules/DynamicFields/templates/Fields/Forms/phone.php new file mode 100644 index 00000000..a5a42a4a --- /dev/null +++ b/modules/DynamicFields/templates/Fields/Forms/phone.php @@ -0,0 +1,45 @@ +fetch('modules/DynamicFields/templates/Fields/Forms/phone.tpl'); +} + +?> diff --git a/modules/DynamicFields/templates/Fields/Forms/phone.tpl b/modules/DynamicFields/templates/Fields/Forms/phone.tpl new file mode 100644 index 00000000..77000f3f --- /dev/null +++ b/modules/DynamicFields/templates/Fields/Forms/phone.tpl @@ -0,0 +1,87 @@ +{* + +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + + + +*} + + +{include file="modules/DynamicFields/templates/Fields/Forms/coreTop.tpl"} + + + + + + + + + + + +{include file="modules/DynamicFields/templates/Fields/Forms/coreBottom.tpl"} \ No newline at end of file diff --git a/modules/DynamicFields/templates/Fields/Forms/radioenum.php b/modules/DynamicFields/templates/Fields/Forms/radioenum.php new file mode 100644 index 00000000..0044a4e1 --- /dev/null +++ b/modules/DynamicFields/templates/Fields/Forms/radioenum.php @@ -0,0 +1,45 @@ + diff --git a/modules/DynamicFields/templates/Fields/Forms/relate.php b/modules/DynamicFields/templates/Fields/Forms/relate.php new file mode 100644 index 00000000..cda157b9 --- /dev/null +++ b/modules/DynamicFields/templates/Fields/Forms/relate.php @@ -0,0 +1,75 @@ +assign ( 'modules', $modules ) ; + + return $ss->fetch ( 'modules/DynamicFields/templates/Fields/Forms/relate.tpl' ) ; +} +?> diff --git a/modules/DynamicFields/templates/Fields/Forms/relate.tpl b/modules/DynamicFields/templates/Fields/Forms/relate.tpl new file mode 100644 index 00000000..76f1e7aa --- /dev/null +++ b/modules/DynamicFields/templates/Fields/Forms/relate.tpl @@ -0,0 +1,54 @@ +{* + +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + + + +*} +{include file="modules/DynamicFields/templates/Fields/Forms/coreTop.tpl"} + + + + +{include file="modules/DynamicFields/templates/Fields/Forms/coreBottom.tpl"} \ No newline at end of file diff --git a/modules/DynamicFields/templates/Fields/Forms/text.tpl b/modules/DynamicFields/templates/Fields/Forms/text.tpl new file mode 100644 index 00000000..b54dbdd0 --- /dev/null +++ b/modules/DynamicFields/templates/Fields/Forms/text.tpl @@ -0,0 +1,76 @@ +{* + +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + + + +*} + + +{include file="modules/DynamicFields/templates/Fields/Forms/coreTop.tpl"} + + + + + + + + + + + + +{include file="modules/DynamicFields/templates/Fields/Forms/coreBottom.tpl"} \ No newline at end of file diff --git a/modules/DynamicFields/templates/Fields/Forms/url.php b/modules/DynamicFields/templates/Fields/Forms/url.php new file mode 100644 index 00000000..21edff06 --- /dev/null +++ b/modules/DynamicFields/templates/Fields/Forms/url.php @@ -0,0 +1,61 @@ +get_template_vars(); + $fields = $vars['module']->mbvardefs->vardefs['fields']; + $fieldOptions = array(); + foreach($fields as $id=>$def) { + $fieldOptions[$id] = $def['name']; + } + $ss->assign('fieldOpts', $fieldOptions); + $link_target = !empty($vardef['link_target']) ? $vardef['link_target'] : '_self'; + $ss->assign('TARGET_OPTIONS', get_select_options_with_id($app_list_strings['link_target_dom'], $link_target)); + $ss->assign('LINK_TARGET', $link_target); + $ss->assign('LINK_TARGET_LABEL', $app_list_strings['link_target_dom'][$link_target]); + //_ppd($ss->fetch('modules/DynamicFields/templates/Fields/Forms/url.tpl')); + return $ss->fetch('modules/DynamicFields/templates/Fields/Forms/url.tpl'); + } + +?> diff --git a/modules/DynamicFields/templates/Fields/Forms/url.tpl b/modules/DynamicFields/templates/Fields/Forms/url.tpl new file mode 100644 index 00000000..875d2d4f --- /dev/null +++ b/modules/DynamicFields/templates/Fields/Forms/url.tpl @@ -0,0 +1,118 @@ +{* + +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + + + +*} +{include file="modules/DynamicFields/templates/Fields/Forms/coreTop.tpl"} + + + + + + + + + + + + + + + + + + + + + + +{include file="modules/DynamicFields/templates/Fields/Forms/coreBottom.tpl"} \ No newline at end of file diff --git a/modules/DynamicFields/templates/Fields/Forms/varchar.tpl b/modules/DynamicFields/templates/Fields/Forms/varchar.tpl new file mode 100644 index 00000000..5030c4bf --- /dev/null +++ b/modules/DynamicFields/templates/Fields/Forms/varchar.tpl @@ -0,0 +1,84 @@ +{* + +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + + + +*} + + +{include file="modules/DynamicFields/templates/Fields/Forms/coreTop.tpl"} + + + + + + + + +{include file="modules/DynamicFields/templates/Fields/Forms/coreBottom.tpl"} \ No newline at end of file diff --git a/modules/DynamicFields/templates/Fields/TemplateAddress.php b/modules/DynamicFields/templates/Fields/TemplateAddress.php new file mode 100644 index 00000000..fa71cf3a --- /dev/null +++ b/modules/DynamicFields/templates/Fields/TemplateAddress.php @@ -0,0 +1,67 @@ +type = 'varchar' ; + + require_once 'modules/ModuleBuilder/parsers/parser.label.php' ; + $parser = new ParserLabel ( $df->getModuleName() , $df->getPackageName() ) ; + foreach ( array ( 'City' , 'State' , 'PostalCode' , 'Country' ) as $addressFieldName ) + { + $systemLabel = strtoupper( "LBL_" . $this->name . '_' . $addressFieldName ); + $parser->handleSave ( array( "label_" . $systemLabel => $this->label_value . ' ' . $addressFieldName ) , $GLOBALS [ 'current_language' ] ) ; + $addressField = new TemplateField ( ) ; + $addressField->len = ($addressFieldName == 'PostalCode') ? 20 : 100 ; + $addressField->name = $this->name . '_' . strtolower ( $addressFieldName ) ; + $addressField->label = $addressField->vname = $systemLabel ; + $addressField->save ( $df ) ; + } + // finally save the base street address field + parent::save($df); + + } +} + +?> diff --git a/modules/DynamicFields/templates/Fields/TemplateAddressCountry.php b/modules/DynamicFields/templates/Fields/TemplateAddressCountry.php new file mode 100644 index 00000000..e7e11269 --- /dev/null +++ b/modules/DynamicFields/templates/Fields/TemplateAddressCountry.php @@ -0,0 +1,53 @@ +group; + $def['options'] = 'countries_dom'; + return $def; + } +} + + +?> diff --git a/modules/DynamicFields/templates/Fields/TemplateBoolean.php b/modules/DynamicFields/templates/Fields/TemplateBoolean.php new file mode 100644 index 00000000..d45ce3b7 --- /dev/null +++ b/modules/DynamicFields/templates/Fields/TemplateBoolean.php @@ -0,0 +1,135 @@ +dbType=='oci8') { + return " NUMBER(1) "; + }elseif($GLOBALS['db']->dbType=='mssql'){ + return " bit "; + }else{ + return " BOOL "; + } + } + //BEGIN BACKWARDS COMPATABILITY +function get_xtpl_edit(){ + $name = $this->name; + $returnXTPL = array(); + if(!empty($this->help)){ + $returnXTPL[$this->name . '_help'] = translate($this->help, $this->bean->module_dir); + } + if(isset($this->bean->$name)){ + + + if(strcmp($this->bean->$name ,'1') ==0 || strcmp($this->bean->$name,'on')==0 || strcmp($this->bean->$name,'yes')==0 || strcmp($this->bean->$name, 'true')==0){ + $returnXTPL[$this->name . '_checked'] = 'checked'; + $returnXTPL[$this->name] = 'checked'; + } + }else{ + + if(empty($this->bean->id)){ + + if(!empty($this->default_value)){ + + if(!(strcmp($this->default_value,'false')==0 || strcmp($this->default_value,'no')==0 || strcmp($this->default_value,'off')==0 )){ + $returnXTPL[$this->name . '_checked'] = 'checked'; + $returnXTPL[$this->name] = 'checked'; + } + + } + $returnXTPL[strtoupper($this->name)] = $this->default_value; + } + } + + + + return $returnXTPL; + } + + + + + function get_xtpl_search(){ + + if(!empty($_REQUEST[$this->name])){ + $returnXTPL = array(); + + if($_REQUEST[$this->name] == '1' || $_REQUEST[$this->name] == 'on' || $_REQUEST[$this->name] == 'yes'){ + $returnXTPL[$this->name . '_checked'] = 'checked'; + $returnXTPL[$this->name] = 'checked'; + } + return $returnXTPL; + + } + return ''; + } + + function get_xtpl_detail(){ + $name = $this->name; + $returnXTPL = array(); + if(!empty($this->help)){ + $returnXTPL[$this->name . '_help'] = translate($this->help, $this->bean->module_dir); + } + $returnXTPL[$this->name . '_checked'] = ''; + $returnXTPL[$this->name] = ''; + + if(isset($this->bean->$name)){ + if(strcmp($this->bean->$name ,'1') ==0 || strcmp($this->bean->$name,'on')==0 || strcmp($this->bean->$name,'yes')==0 || strcmp($this->bean->$name, 'true')==0){ + $returnXTPL[$this->name . '_checked'] = 'checked'; + $returnXTPL[$this->name] = 'checked'; + } + } + return $returnXTPL; + } + function get_xtpl_list(){ + return $this->get_xtpl_edit(); + } + + + + + + + +} + + +?> diff --git a/modules/DynamicFields/templates/Fields/TemplateCurrency.php b/modules/DynamicFields/templates/Fields/TemplateCurrency.php new file mode 100644 index 00000000..f7bdc090 --- /dev/null +++ b/modules/DynamicFields/templates/Fields/TemplateCurrency.php @@ -0,0 +1,105 @@ +name = 'currency_id'; + $currency_id->delete($df); + } + + function save($df){ + //the currency field + $this->default = unformat_number($this->default); + $this->default_value = $this->default; + parent::save($df); + + //currency id + $currency_id = new TemplateCurrencyId(); + $currency_id->name = 'currency_id'; + $currency_id->vname = 'LBL_CURRENCY'; + $currency_id->label = $currency_id->vname; + $currency_id->save($df); + //$df->addLabel($currency_id->vname); + } + + function get_db_type(){ + $precision = (!empty($this->precision)) ? $this->precision : 6; + switch($GLOBALS['db']->dbType){ + case 'oci8': + if(!empty($this->len)) + { + return " number( {$this->len} , $precision )"; + }else{ + return " number(26,$precision)"; + } + case 'mssql': + if(!empty($this->len)) + { + return " decimal( {$this->len} , $precision )"; + }else{ + return " decimal(26,$precision)"; + } + default: + if(!empty($this->len)) + { + return " decimal( {$this->len} , $precision )"; + }else{ + return " decimal(26,$precision)"; + } + } + } +} + + +?> diff --git a/modules/DynamicFields/templates/Fields/TemplateCurrencyId.php b/modules/DynamicFields/templates/Fields/TemplateCurrencyId.php new file mode 100644 index 00000000..e41c88f8 --- /dev/null +++ b/modules/DynamicFields/templates/Fields/TemplateCurrencyId.php @@ -0,0 +1,63 @@ +'getCurrencyDropDown', 'returns'=>'html'); + return $def; + } + + function save($df){ + if(!$df->fieldExists($this->name)) + parent::save($df); + } + + function delete($df){ + if(!$df->fieldExists($this->name)) + parent::delete($df); + } +} + + +?> diff --git a/modules/DynamicFields/templates/Fields/TemplateDate.php b/modules/DynamicFields/templates/Fields/TemplateDate.php new file mode 100644 index 00000000..14a7c599 --- /dev/null +++ b/modules/DynamicFields/templates/Fields/TemplateDate.php @@ -0,0 +1,109 @@ +dateStrings = array( + $app_strings['LBL_NONE']=>'', + $app_strings['LBL_YESTERDAY']=> '-1 day', + $app_strings['LBL_TODAY']=>'now', + $app_strings['LBL_TOMORROW']=>'+1 day', + $app_strings['LBL_NEXT_WEEK']=> '+1 week', + $app_strings['LBL_NEXT_MONDAY']=>'next monday', + $app_strings['LBL_NEXT_FRIDAY']=>'next friday', + $app_strings['LBL_TWO_WEEKS']=> '+2 weeks', + $app_strings['LBL_NEXT_MONTH']=> '+1 month', + $app_strings['LBL_FIRST_DAY_OF_NEXT_MONTH']=> 'first day of next month', // must handle this non-GNU date string in SugarBean->populateDefaultValues; if we don't this will evaluate to 1969... + $app_strings['LBL_THREE_MONTHS']=> '+3 months', //kbrill Bug #17023 + $app_strings['LBL_SIXMONTHS']=> '+6 months', + $app_strings['LBL_NEXT_YEAR']=> '+1 year', + ); +} + + +function get_db_type(){ + + if($GLOBALS['db']->dbType == 'mssql'){ + return " DATETIME "; + } else { + return " DATE "; + } +} +function get_db_default($modify=false){ + return ''; +} + +//BEGIN BACKWARDS COMPATABILITY +function get_xtpl_edit(){ + global $timedate; + $name = $this->name; + $returnXTPL = array(); + if(!empty($this->help)){ + $returnXTPL[strtoupper($this->name . '_help')] = translate($this->help, $this->bean->module_dir); + } + $returnXTPL['USER_DATEFORMAT'] = $timedate->get_user_date_format(); + $returnXTPL['CALENDAR_DATEFORMAT'] = $timedate->get_cal_date_format(); + if(isset($this->bean->$name)){ + $returnXTPL[strtoupper($this->name)] = $this->bean->$name; + }else{ + if(empty($this->bean->id) && !empty($this->default_value) && !empty($this->dateStrings[$this->default_value])){ + $returnXTPL[strtoupper($this->name)] = $timedate->asUserDate($timedate->getNow(true)->modify($this->dateStrings[$this->default_value]), false); + } + } + return $returnXTPL; + } + +function get_field_def(){ + $def = parent::get_field_def(); + if(!empty($def['default'])){ + $def['display_default'] = $def['default']; + $def['default'] = ''; + } + return $def; + } +} +?> diff --git a/modules/DynamicFields/templates/Fields/TemplateDatetimecombo.php b/modules/DynamicFields/templates/Fields/TemplateDatetimecombo.php new file mode 100644 index 00000000..8eba5e10 --- /dev/null +++ b/modules/DynamicFields/templates/Fields/TemplateDatetimecombo.php @@ -0,0 +1,193 @@ + '', + 'today'=>'now', + 'yesterday'=> '-1 day', + 'tomorrow'=>'+1 day', + 'next week'=> '+1 week', + 'next monday'=>'next monday', + 'next friday'=>'next friday', + 'two weeks'=> '+2 weeks', + 'next month'=> '+1 month', + 'first day of next month'=> 'first of next month', // must handle this non-GNU date string in SugarBean->populateDefaultValues; if we don't this will evaluate to 1969... + 'three months'=> '+3 months', //kbrill Bug #17023 + 'six months'=> '+6 months', + 'next year'=> '+1 year', + ); + + var $hoursStrings = array( + '' => '', + '01' => '01', + '02' => '02', + '03' => '03', + '04' => '04', + '05' => '05', + '06' => '06', + '07' => '07', + '08' => '08', + '09' => '09', + '10' => '10', + '11' => '11', + '12' => '12', + ); + + var $hoursStrings24 = array( + '' => '', + '00' => '00', + '01' => '01', + '02' => '02', + '03' => '03', + '04' => '04', + '05' => '05', + '06' => '06', + '07' => '07', + '08' => '08', + '09' => '09', + '10' => '10', + '11' => '11', + '12' => '12', + '13' => '13', + '14' => '14', + '15' => '15', + '16' => '16', + '17' => '17', + '18' => '18', + '19' => '19', + '20' => '20', + '21' => '21', + '22' => '22', + '23' => '23', + ); + + var $minutesStrings = array( + '' => '', + '00' => '00', + '15' => '15', + '30' => '30', + '45' => '45', + ); + + var $meridiemStrings = array( + '' => '', + 'am' => 'am', + 'pm' => 'pm', + ); + + function __construct() + { + parent::__construct(); + } + + function get_db_type(){ + if($GLOBALS['db']->dbType == 'oracle'){ + return " DATE "; + } else { + return " DATETIME "; + } + } + + function get_db_default($modify=false){ + return ''; + } + + function get_field_def(){ + $def = parent::get_field_def(); + if($GLOBALS['db']->dbType == 'oracle'){ + $def['dbType'] = 'date'; + } else { + $def['dbType'] = 'datetime'; + } + if(!empty($def['default'])){ + $def['display_default'] = $def['default']; + $def['default'] = ''; + } + return $def; + } + + function save($df){ + parent::save($df); + } + + function populateFromPost(){ + parent::populateFromPost(); + if(!empty($_REQUEST['defaultDate']) && !empty($_REQUEST['defaultTime'])){ + $_REQUEST['default'] = $_REQUEST['defaultDate'].'&'.$_REQUEST['defaultTime']; + + $defaultTime = $_REQUEST['defaultTime']; + $hours = substr($defaultTime, 0, 2); + $minutes = substr($defaultTime, 3, 2); + $meridiem = substr($defaultTime, 5, 2); + if(empty($meridiem)) { + if($hours == '00') { + $hours = 12; + $meridiem = 'am'; + } else if($hours > 12) { + $hours -= 12; + $meridiem = 'pm'; + } else { + $meridiem = 'am'; + } + $_REQUEST['default'] = $_REQUEST['defaultDate'].'&'.$hours.':'.$minutes.''.$meridiem; + } + }else{ + $_REQUEST['default'] = ''; + } + unset($_REQUEST['defaultDate']); + unset($_REQUEST['defaultTime']); + + foreach($this->vardef_map as $vardef=>$field){ + if(isset($_REQUEST[$vardef])){ + $this->$vardef = $_REQUEST[$vardef]; + if($vardef != $field){ + $this->$field = $this->$vardef; + } + } + } + $GLOBALS['log']->debug('populate: '.print_r($this,true)); + } + +} +?> diff --git a/modules/DynamicFields/templates/Fields/TemplateDecimal.php b/modules/DynamicFields/templates/Fields/TemplateDecimal.php new file mode 100644 index 00000000..33bec56f --- /dev/null +++ b/modules/DynamicFields/templates/Fields/TemplateDecimal.php @@ -0,0 +1,87 @@ +debug('TemplateFloat:get_db_type()'.print_r($this,true)); + + if ($GLOBALS['db']->dbType=='mysql') + { + $type = " DECIMAL"; + if(!empty($this->len)) + { + $precision = (!empty($this->precision)) ? $this->precision : 4; // bug 17041 tyoung - mysql requires a precision value if length is specified + $type .= "({$this->len},$precision)"; + } + } + elseif ($GLOBALS['db']->dbType=='mssql') + { + $type = " decimal"; + if(!empty($this->len)) + { + $precision = (!empty($this->precision)) ? $this->precision : 4; + $type .= "({$this->len},$precision)"; + } + else + { + $type .= "(11,4)"; + } + } + elseif ($GLOBALS['db']->dbType=='oci8') + { + $precision = (!empty($this->precision))? $this->precision: 6; + $type= " NUMBER(30,$precision) "; + } + + /** + * FOR ORACLE + * return " NUMBER($this->max_size, $this->precision)"; + */ + return $type; + } +} + +?> diff --git a/modules/DynamicFields/templates/Fields/TemplateEmail.php b/modules/DynamicFields/templates/Fields/TemplateEmail.php new file mode 100644 index 00000000..d300e512 --- /dev/null +++ b/modules/DynamicFields/templates/Fields/TemplateEmail.php @@ -0,0 +1,48 @@ +name).'}">{'. strtoupper($this->name).'}'; + } + +} + + +?> diff --git a/modules/DynamicFields/templates/Fields/TemplateEncrypt.php b/modules/DynamicFields/templates/Fields/TemplateEncrypt.php new file mode 100644 index 00000000..13da1679 --- /dev/null +++ b/modules/DynamicFields/templates/Fields/TemplateEncrypt.php @@ -0,0 +1,61 @@ +type = 'encrypt'; + $this->ext3 = 'varchar'; + parent::save($df); + + } + function get_field_def(){ + $vardef = parent::get_field_def(); + $vardef['dbType'] = $this->ext3; + return $vardef; + } +} + +?> diff --git a/modules/DynamicFields/templates/Fields/TemplateEnum.php b/modules/DynamicFields/templates/Fields/TemplateEnum.php new file mode 100644 index 00000000..9be5cd18 --- /dev/null +++ b/modules/DynamicFields/templates/Fields/TemplateEnum.php @@ -0,0 +1,204 @@ +localVardefMap = array ( + 'trigger' => 'trigger', + 'action' => 'action' , ) ; + $this->vardef_map = array_merge ( $this->vardef_map , $this->localVardefMap ) ; + } + + function populateFromPost () + { + parent::populateFromPost(); + // now convert trigger,action pairs into a dependency array representation + // we expect the dependencies in the following format: + // trigger = [ trigger for action 1 , trigger for action 2 , ... , trigger for action n ] + // action = [ action 1 , action 2 , ... , action n ] + + // check first if we have the component parts of a dependency + $dependencyPresent = true ; + foreach ( $this->localVardefMap as $def ) + { + $dependencyPresent &= isset ( $this->$def ) ; + } + + if ( $dependencyPresent ) + { + $dependencies = array () ; + + if ( is_array ( $this->trigger ) && is_array ( $this->action ) ) + { + for ( $i = 0 ; $i < count ( $this->action ) ; $i++ ) + { + $dependencies [ $this->trigger [ $i ] ] = $this->action [ $i ] ; + } + $this->dependency = $dependencies ; + } + else + { + if ( ! is_array ( $this->trigger ) && ! is_array ( $this->action ) ) + $this->dependency = array ( $this->trigger => $this->action ) ; + } + // tidy up + unset ( $this->trigger ) ; + unset ( $this->action ) ; + } + } + function get_xtpl_edit(){ + $name = $this->name; + $value = ''; + if(isset($this->bean->$name)){ + $value = $this->bean->$name; + }else{ + if(empty($this->bean->id)){ + $value= $this->default_value; + } + } + if(!empty($this->help)){ + $returnXTPL[strtoupper($this->name . '_help')] = translate($this->help, $this->bean->module_dir); + } + + global $app_list_strings; + $returnXTPL = array(); + $returnXTPL[strtoupper($this->name)] = $value; + if(empty($this->ext1)){ + $this->ext1 = $this->options; + } + $returnXTPL[strtoupper('options_'.$this->name)] = get_select_options_with_id($app_list_strings[$this->ext1], $value); + + return $returnXTPL; + + + } + + function get_xtpl_search(){ + $searchFor = ''; + if(!empty($_REQUEST[$this->name])){ + $searchFor = $_REQUEST[$this->name]; + } + global $app_list_strings; + $returnXTPL = array(); + $returnXTPL[strtoupper($this->name)] = $searchFor; + if(empty($this->ext1)){ + $this->ext1 = $this->options; + } + $returnXTPL[strtoupper('options_'.$this->name)] = get_select_options_with_id(add_blank_option($app_list_strings[$this->ext1]), $searchFor); + return $returnXTPL; + + } + + function get_db_type(){ + if(empty($this->max_size))$this->max_size = 150; + switch($GLOBALS['db']->dbType){ + case 'oci8': return " varchar2($this->max_size)"; + case 'mssql': return !empty($GLOBALS['db']->isFreeTDS) ? " nvarchar($this->max_size)" : " varchar($this->max_size)"; + default: return " varchar($this->max_size)"; + } + + } + + + + function get_field_def(){ + $def = parent::get_field_def(); + $def['options'] = !empty($this->options) ? $this->options : $this->ext1; + $def['default'] = !empty($this->default) ? $this->default : $this->default_value; + $def['len'] = $this->max_size; + $def['studio'] = 'visible'; + // this class may be extended, so only do the unserialize for genuine TemplateEnums + if (get_class( $this ) == 'TemplateEnum' ) + $def['dependency'] = isset($this->ext4)? unserialize(html_entity_decode($this->ext4)) : null ; + return $def; + } + + function get_xtpl_detail(){ + $name = $this->name; + + // awu: custom fields are not being displayed on the detail view because $this->ext1 is always empty, adding this to get the options + if(empty($this->ext1)){ + if(!empty($this->options)) + $this->ext1 = $this->options; + } + + if(isset($this->bean->$name)){ + $key = $this->bean->$name; + global $app_list_strings; + if(preg_match('/&/s', $key)) { + $key = str_replace('&', '&', $key); + } + if(isset($app_list_strings[$this->ext1])){ + if(isset($app_list_strings[$this->ext1][$key])) { + return $app_list_strings[$this->ext1][$key]; + } + + if(isset($app_list_strings[$this->ext1][$this->bean->$name])){ + return $app_list_strings[$this->ext1][$this->bean->$name]; + } + } + } + return ''; + } + + function save($df){ + if (!empty($this->default_value) && is_array($this->default_value)) { + $this->default_value = $this->default_value[0]; + } + if (!empty($this->default) && is_array($this->default)) { + $this->default = $this->default[0]; + } + + if ( get_class( $this ) == 'TemplateEnum' && isset ( $this->dependency ) ) + $this->ext4 = serialize ( $this->dependency ) ; + parent::save($df); + } +} + + +?> diff --git a/modules/DynamicFields/templates/Fields/TemplateField.php b/modules/DynamicFields/templates/Fields/TemplateField.php new file mode 100644 index 00000000..04523a1f --- /dev/null +++ b/modules/DynamicFields/templates/Fields/TemplateField.php @@ -0,0 +1,478 @@ +1, 'date_modified'=>1, 'created_by'=>1, 'id'=>1, 'modified_user_id'=>1); +class TemplateField{ + /* + The view is the context this field will be used in + -edit + -list + -detail + -search + */ + var $view = 'edit'; + var $name = ''; + var $vname = ''; + var $id = ''; + var $size = '20'; + var $len = '255'; + var $required = false; + var $default = null; + var $default_value = null; + var $type = 'varchar'; + var $comment = ''; + var $bean; + var $ext1 = ''; + var $ext2 = ''; + var $ext3 = ''; + var $ext4 = ''; + var $audited= 0; + var $massupdate = 0; + var $importable = 'true' ; + var $duplicate_merge=0; + var $new_field_definition; + var $reportable = true; + var $label_value = ''; + var $help = ''; + var $formula = ''; + + var $vardef_map = array( + 'name'=>'name', + 'label'=>'vname', + // bug 15801 - need to ALWAYS keep default and default_value consistent as some methods/classes use one, some use another... + 'default_value'=>'default', + 'default'=>'default_value', + 'display_default'=>'default_value', + // 'default_value'=>'default_value', + // 'default'=>'default_value', + 'len'=>'len', + 'required'=>'required', + 'type'=>'type', + 'audited'=>'audited', + 'massupdate'=>'massupdate', + 'options'=>'ext1', + 'help'=>'help', + 'comments'=>'comment', + 'importable'=>'importable', + 'duplicate_merge'=>'duplicate_merge', + 'duplicate_merge_dom_value'=>'duplicate_merge_dom_value', //bug #14897 + 'merge_filter'=>'merge_filter', + 'reportable' => 'reportable', + 'min'=>'ext1', + 'max'=>'ext2', + 'ext2'=>'ext2', + 'ext4'=>'ext4', + //'disable_num_format'=>'ext3', + 'ext3'=>'ext3', + 'label_value'=>'label_value', + ); + /* + HTML FUNCTIONS + */ + function get_html(){ + $view = $this->view; + if(!empty($GLOBALS['studioReadOnlyFields'][$this->name]))$view = 'detail'; + switch($view){ + case 'search':return $this->get_html_search(); + case 'edit': return $this->get_html_edit(); + case 'list': return $this->get_html_list(); + case 'detail': return $this->get_html_detail(); + + } + } + function set($values){ + foreach($values as $name=>$value){ + $this->$name = $value; + } + + } + + function get_html_edit(){ + return 'not implemented'; + } + + function get_html_list(){ + return $this->get_html_detail(); + } + + function get_html_detail(){ + return 'not implemented'; + } + + function get_html_search(){ + return $this->get_html_edit(); + } + function get_html_label(){ + + $label = "{MOD." .$this->vname . "}"; + if(!empty($GLOBALS['app_strings'][$this->vname])){ + $label = "{APP." .$this->label . "}"; + } + if($this->view == 'edit' && $this->is_required()){ + $label .= '*'; + } + if($this->view == 'list'){ + if(isset($this->bean)){ + if(!empty($this->id)){ + $name = $this->bean->table_name . '_cstm.'. $this->name; + $arrow = $this->bean->table_name . '_cstm_'. $this->name; + }else{ + $name = $this->bean->table_name . '.'. $this->name; + $arrow = $this->bean->table_name . '_'. $this->name; + } + }else{ + $name = $this->name; + $arrow = $name; + } + $label = "{MOD.$this->label}{arrow_start}{".$arrow."_arrow}{arrow_end}"; + } + return $label; + + } + + /* + XTPL FUNCTIONS + */ + + function get_xtpl($bean = false){ + if($bean) + $this->bean = $bean; + $view = $this->view; + if(!empty($GLOBALS['studioReadOnlyFields'][$this->name]))$view = 'detail'; + switch($view){ + case 'search':return $this->get_xtpl_search(); + case 'edit': return $this->get_xtpl_edit(); + case 'list': return $this->get_xtpl_list(); + case 'detail': return $this->get_xtpl_detail(); + + } + } + + function get_xtpl_edit(){ + return '/*not implemented*/'; + } + + function get_xtpl_list(){ + return get_xtpl_detail(); + } + + function get_xtpl_detail(){ + return '/*not implemented*/'; + } + + function get_xtpl_search(){ + //return get_xtpl_edit(); + } + + function is_required(){ + if($this->required){ + return true; + } + return false; + + } + + + + + /* + DB FUNCTIONS + */ + + function get_db_type(){ + switch($GLOBALS['db']->dbType){ + case 'oci8': return " varchar2($this->len)"; + case 'mssql': return !empty($GLOBALS['db']->isFreeTDS) ? " nvarchar($this->len)" : " varchar($this->len)"; + default: return " varchar($this->len)"; + } + } + + function get_db_default($modify=false){ + $GLOBALS['log']->debug('get_db_default(): default_value='.$this->default_value); + if (!$modify or empty($this->new_field_definition['default_value']) or $this->new_field_definition['default_value'] != $this->default_value ) { + if(!is_null($this->default_value)){ // add a default value if it is not null - we want to set a default even if default_value is '0', which is not null, but which is empty() + if(NULL == trim($this->default_value)){ + return " DEFAULT NULL"; + } + else { + return " DEFAULT '$this->default_value'"; + } + }else{ + return ''; + } + } + } + + /* + * Return the required clause for this field + * Confusingly, when modifying an existing field ($modify=true) there are two exactly opposite cases: + * 1. if called by Studio, only $this->required is set. If set, we return "NOT NULL" otherwise we return "NULL" + * 2. if not called by Studio, $this->required holds the OLD value of required, and new_field_definition['required'] is the NEW + * So if not called by Studio we want to return NULL if required=true (because we are changing FROM this setting) + */ + + function get_db_required($modify=false){ + // $GLOBALS['log']->debug('get_db_required required='.$this->required." and ".(($modify)?"true":"false")." and ".print_r($this->new_field_definition,true)); + $req = ""; + + if ($modify) { + if (!empty($this->new_field_definition['required'])) { + if ($this->required and $this->new_field_definition['required'] != $this->required) { + $req = " NULL "; + } + } + else + { + $req = ($this->required) ? " NOT NULL " : ''; // bug 17184 tyoung - set required correctly when modifying custom field in Studio + } + } + else + { + if (empty($this->new_field_definition['required']) or $this->new_field_definition['required'] != $this->required ) { + if(!empty($this->required) && $this->required){ + $req = " NOT NULL"; + } + } + } + + return $req; + } + + /* function get_db_required($modify=false){ + $GLOBALS['log']->debug('get_db_required required='.$this->required." and ".(($modify)?"true":"false")." and ".print_r($this->new_field_definition,true)); + if ($modify) { + if (!empty($this->new_field_definition['required'])) { + if ($this->required and $this->new_field_definition['required'] != $this->required) { + return " null "; + } + return ""; + } + } + if (empty($this->new_field_definition['required']) or $this->new_field_definition['required'] != $this->required ) { + if(!empty($this->required) && $this->required){ + return " NOT NULL"; + } + } + return ''; + } + */ + /** + * Oracle Support: do not set required constraint if no default value is supplied. + * In this case the default value will be handled by the application/sugarbean. + */ + function get_db_add_alter_table($table) + { + return $GLOBALS['db']->getHelper()->addColumnSQL($table, $this->get_field_def(), true); + } + + function get_db_delete_alter_table($table) + { + return $GLOBALS['db']->getHelper()->dropColumnSQL( + $table, + $this->get_field_def() + ); + } + + /** + * mysql requires the datatype caluse in the alter statment.it will be no-op anyway. + */ + function get_db_modify_alter_table($table){ + global $db; + $db_default=$this->get_db_default(true); + $db_required=$this->get_db_required(true); + switch ($GLOBALS['db']->dbType) { + + case "mssql": + //Bug 21772: MSSQL handles alters in strange ways. Defer to DBHelpers guidance. + $query = $db->helper->alterColumnSQL($table, $this->get_field_def()); + return $query; + break; + + case "mysql": + $query="ALTER TABLE $table MODIFY $this->name " .$this->get_db_type(); + break; + default: + $query="ALTER TABLE $table MODIFY $this->name " .$this->get_db_type();; + break; + + } + if (!empty($db_default) && !empty($db_required)) { + $query .= $db_default . $db_required ; + } else if (!empty($db_default)) { + $query .= $db_default; + } + return $query; + } + + + /* + * BEAN FUNCTIONS + * + */ + function get_field_def(){ + $array = array( + 'required'=>$this->convertBooleanValue($this->required), + 'source'=>'custom_fields', + 'name'=>$this->name, + 'vname'=>$this->vname, + 'type'=>$this->type, + 'massupdate'=>$this->massupdate, + 'default'=>$this->default, + 'comments'=> (isset($this->comments)) ? $this->comments : '', + 'help'=> (isset($this->help)) ? $this->help : '', + 'importable'=>$this->importable, + 'duplicate_merge'=>$this->duplicate_merge, + 'duplicate_merge_dom_value'=> isset($this->duplicate_merge_dom_value) ? $this->duplicate_merge_dom_value : $this->duplicate_merge, + 'audited'=>$this->convertBooleanValue($this->audited), + 'reportable'=>$this->convertBooleanValue($this->reportable), + ); + if(!empty($this->len)){ + $array['len'] = $this->len; + } + if(!empty($this->size)){ + $array['size'] = $this->size; + } + $this->get_dup_merge_def($array); + return $array; + } + + protected function convertBooleanValue($value) + { + if ($value === 'true' || $value === '1' || $value === 1) + return true; + else if ($value === 'false' || $value === '0' || $value === 0) + return false; + else + return $value; + } + + + /* if the field is duplicate merge enabled this function will return the vardef entry for the same. + */ + function get_dup_merge_def(&$def) { + + switch ($def['duplicate_merge_dom_value']) { + case 0: + $def['duplicate_merge']='disabled'; + break; + case 1: + $def['duplicate_merge']='enabled'; + break; + case 2: + $def['merge_filter']='enabled'; + $def['duplicate_merge']='enabled'; + break; + case 3: + $def['merge_filter']='selected'; + $def['duplicate_merge']='enabled'; + break; + case 4: + $def['merge_filter']='enabled'; + $def['duplicate_merge']='disabled'; + break; + } + + } + + /* + HELPER FUNCTIONS + */ + + + function prepare(){ + if(empty($this->id)){ + $this->id = $this->name; + } + } + + /** + * populateFromRow + * This function supports setting the values of all TemplateField instances. + * @param $row The Array key/value pairs from fields_meta_data table + */ + function populateFromRow($row=array()) { + $fmd_to_dyn_map = array('comments' => 'comment', 'require_option' => 'required', 'label' => 'vname', + 'mass_update' => 'massupdate', 'max_size' => 'len', 'default_value' => 'default', 'id_name' => 'ext3'); + if(!is_array($row)) { + $GLOBALS['log']->error("Error: TemplateField->populateFromRow expecting Array"); + } + //Bug 24189: Copy fields from FMD format to Field objects + foreach ($fmd_to_dyn_map as $fmd_key => $dyn_key) { + if (isset($row[$fmd_key])) { + $this->$dyn_key = $row[$fmd_key]; + } + } + foreach($row as $key=>$value) { + $this->$key = $value; + } + } + + function populateFromPost(){ + foreach($this->vardef_map as $vardef=>$field){ + if(isset($_REQUEST[$vardef])){ + $this->$vardef = $_REQUEST[$vardef]; + if($vardef != $field){ + $this->$field = $this->$vardef; + } + } + } + $this->applyVardefRules(); + $GLOBALS['log']->debug('populate: '.print_r($this,true)); + + } + + protected function applyVardefRules() + { + } + + function get_additional_defs(){ + return array(); + } + + function delete($df){ + $df->deleteField($this); + } + + function save($df){ + // $GLOBALS['log']->debug('saving field: '.print_r($this,true)); + $df->addFieldObject($this); + } + +} + + +?> diff --git a/modules/DynamicFields/templates/Fields/TemplateFloat.php b/modules/DynamicFields/templates/Fields/TemplateFloat.php new file mode 100644 index 00000000..f927c3ec --- /dev/null +++ b/modules/DynamicFields/templates/Fields/TemplateFloat.php @@ -0,0 +1,103 @@ +vardef_map['precision']='ext1'; + //$this->vardef_map['precision']='precision'; + } + + function get_field_def(){ + $def = parent::get_field_def(); + $def['precision'] = isset($this->ext1) && $this->ext1 != '' ? $this->ext1 : $this->precision; + return $def; + } + + function get_db_type(){ +// $GLOBALS['log']->debug('TemplateFloat:get_db_type()'.print_r($this,true)); + + if ($GLOBALS['db']->dbType=='mysql') + { + $type = " FLOAT"; + if(!empty($this->len)) + { + $precision = (!empty($this->precision)) ? $this->precision : 4; // bug 17041 tyoung - mysql requires a precision value if length is specified + $type .= "({$this->len},$precision)"; + } + } + elseif ($GLOBALS['db']->dbType=='mssql') + { + $type = " decimal"; + if(!empty($this->len)) + { + $precision = (!empty($this->precision)) ? $this->precision : 4; + $type .= "({$this->len},$precision)"; + } + else + { + $type .= "(11,4)"; + } + } + elseif ($GLOBALS['db']->dbType=='oci8') + { + $precision = (!empty($this->precision))? $this->precision: 6; + $type= " NUMBER(30,$precision) "; + } + + /** + * FOR ORACLE + * return " NUMBER($this->max_size, $this->precision)"; + */ + return $type; + } + + function populateFromRow($row=array()) { + parent::populateFromRow($row); + } +} + +?> diff --git a/modules/DynamicFields/templates/Fields/TemplateHTML.php b/modules/DynamicFields/templates/Fields/TemplateHTML.php new file mode 100644 index 00000000..5a00f361 --- /dev/null +++ b/modules/DynamicFields/templates/Fields/TemplateHTML.php @@ -0,0 +1,119 @@ +ext3 = 'text'; + parent::save($df); + } + + function set($values){ + parent::set($values); + if(!empty($this->ext4)){ + $this->default_value = $this->ext4; + $this->default = $this->ext4; + } + + } + + function get_html_detail(){ + + return '
    {'.strtoupper($this->name) . '}
    '; + } + + function get_html_edit(){ + return $this->get_html_detail(); + } + + function get_html_list(){ + return $this->get_html_detail(); + } + + function get_html_search(){ + return $this->get_html_detail(); + } + + function get_xtpl_detail(){ + + return from_html(nl2br($this->ext4)); + } + + function get_xtpl_edit(){ + return $this->get_xtpl_detail(); + } + + function get_xtpl_list(){ + return $this->get_xtpl_detail(); + } + function get_xtpl_search(){ + return $this->get_xtpl_detail(); + } + + function get_db_add_alter_table($table){ + return ''; + } + + function get_db_modify_alter_table($table){ + return ''; + } + + + function get_db_delete_alter_table($table) + { + return '' ; + } + + function get_field_def() { + $def = parent::get_field_def(); + if(!empty($this->ext4)){ + $def['default_value'] = $this->ext4; + $def['default'] = $this->ext4; + } + $def['studio'] = 'visible'; + $def['dbType'] = isset($this->ext3) ? $this->ext3 : 'text' ; + return array_merge($def, $this->get_additional_defs()); + } + + +} + + +?> diff --git a/modules/DynamicFields/templates/Fields/TemplateIFrame.php b/modules/DynamicFields/templates/Fields/TemplateIFrame.php new file mode 100644 index 00000000..2bc3bfa1 --- /dev/null +++ b/modules/DynamicFields/templates/Fields/TemplateIFrame.php @@ -0,0 +1,64 @@ +prepare(); + return ""; + } + + function get_html_label() { + return "LALALALA"; + } + + function get_xtpl_detail(){ + $value = parent::get_xtpl_detail(); + $value .= "BLAH BLAH"; + return $value; + } + + function get_field_def(){ + $def = parent::get_field_def(); + $def['height'] = !empty($this->height) ? $this->height : $this->ext4; + return $def; + } + +} +?> diff --git a/modules/DynamicFields/templates/Fields/TemplateId.php b/modules/DynamicFields/templates/Fields/TemplateId.php new file mode 100644 index 00000000..f65dc3e9 --- /dev/null +++ b/modules/DynamicFields/templates/Fields/TemplateId.php @@ -0,0 +1,47 @@ + diff --git a/modules/DynamicFields/templates/Fields/TemplateImage.php b/modules/DynamicFields/templates/Fields/TemplateImage.php new file mode 100644 index 00000000..a386cfeb --- /dev/null +++ b/modules/DynamicFields/templates/Fields/TemplateImage.php @@ -0,0 +1,84 @@ +ext1) ) $def[ 'border' ] = $this->ext1 ; + if( isset($this->ext2) ) $def[ 'width' ] = $this->ext2 ; + if( isset($this->ext3) ) $def[ 'height' ] = $this->ext3 ; + if( isset($this->border)) $def[ 'border' ] = $this->border ; + if( isset($this->width) ) $def[ 'width' ] = $this->width ; + if( isset($this->height)) $def[ 'height' ] = $this->height ; + + return $def; + } + + function __construct() + { + $this->vardef_map['border'] = 'ext1'; + $this->vardef_map['width'] = 'ext2'; + $this->vardef_map['height'] = 'ext3'; + } + + function set($values){ + parent::set($values); + if(!empty($this->ext1)){ + $this->border = $this->ext1; + } + if(!empty($this->ext2)){ + $this->width = $this->ext2; + } + if(!empty($this->ext3)){ + $this->height = $this->ext3; + } + + } + + +} + + +?> diff --git a/modules/DynamicFields/templates/Fields/TemplateInt.php b/modules/DynamicFields/templates/Fields/TemplateInt.php new file mode 100644 index 00000000..0e7e7ae2 --- /dev/null +++ b/modules/DynamicFields/templates/Fields/TemplateInt.php @@ -0,0 +1,122 @@ +vardef_map['autoinc_next'] = 'autoinc_next'; + $this->vardef_map['autoinc_start'] = 'autoinc_start'; + $this->vardef_map['auto_increment'] = 'auto_increment'; + } + + var $type = 'int'; + function get_html_edit(){ + $this->prepare(); + return ""; + } + + function populateFromPost(){ + parent::populateFromPost(); + if (isset($this->auto_increment)) + { + $this->auto_increment = $this->auto_increment == "true" || $this->auto_increment === true; + } + } + + function get_field_def(){ + $vardef = parent::get_field_def(); + $vardef['disable_num_format'] = isset($this->disable_num_format) ? $this->disable_num_format : $this->ext3;//40005 + if(!empty($this->ext2)){ + $min = (!empty($this->ext1))?$this->ext1:0; + $max = $this->ext2; + $vardef['validation'] = array('type' => 'range', 'min' => $min, 'max' => $max); + } + if(!empty($this->auto_increment)) + { + $vardef['auto_increment'] = $this->auto_increment; + if ((empty($this->autoinc_next)) && isset($this->module) && isset($this->module->table_name)) + { + global $db; + $helper = $db->gethelper(); + $auto = $helper->getAutoIncrement($this->module->table_name, $this->name); + $this->autoinc_next = $vardef['autoinc_next'] = $auto; + } + } + return $vardef; + } + + function get_db_type(){ + switch($GLOBALS['db']->dbType){ + case 'oci8': return ' NUMBER '; + case 'mysql': return (!empty($this->len) && $this->len <= 11 && $this->len > 0)? ' INT(' .$this->len . ')' : ' INT(11) '; + default: return ' INT '; + } +} + + function save($df){ + $next = false; + if (!empty($this->auto_increment) && (!empty($this->autoinc_next) || !empty($this->autoinc_start)) && isset($this->module)) + { + if (!empty($this->autoinc_start) && $this->autoinc_start > $this->autoinc_next) + { + $this->autoinc_next = $this->autoinc_start; + } + if(isset($this->module->table_name)){ + global $db; + $helper = $db->gethelper(); + //Check that the new value is greater than the old value + $oldNext = $helper->getAutoIncrement($this->module->table_name, $this->name); + if ($this->autoinc_next > $oldNext) + { + $helper->setAutoIncrementStart($this->module->table_name, $this->name, $this->autoinc_next); + } + } + $next = $this->autoinc_next; + $this->autoinc_next = false; + } + parent::save($df); + if ($next) + $this->autoinc_next = $next; + } +} + + +?> diff --git a/modules/DynamicFields/templates/Fields/TemplateMultiEnum.php b/modules/DynamicFields/templates/Fields/TemplateMultiEnum.php new file mode 100644 index 00000000..456e332d --- /dev/null +++ b/modules/DynamicFields/templates/Fields/TemplateMultiEnum.php @@ -0,0 +1,178 @@ +prepare(); + $xtpl_var = strtoupper( $this->name); + // MFH BUG#13645 + return ""; + } + + function get_db_type(){ + if ($GLOBALS['db']->dbType=='oci8') { + return " CLOB "; + } else { + return " TEXT "; + } + } + + function get_xtpl_edit(){ + $name = $this->name; + $value = ''; + if(isset($this->bean->$name)){ + $value = $this->bean->$name; + }else{ + if(empty($this->bean->id)){ + $value= $this->default_value; + } + } + if(!empty($this->help)){ + $returnXTPL[strtoupper($this->name . '_help')] = translate($this->help, $this->bean->module_dir); + } + + global $app_list_strings; + $returnXTPL = array(); + + $returnXTPL[strtoupper($this->name)] = str_replace('^,^', ',', $value); + if(empty($this->ext1)){ + $this->ext1 = $this->options; + } + $returnXTPL[strtoupper('options_'.$this->name)] = get_select_options_with_id($app_list_strings[$this->ext1], unencodeMultienum( $value)); + + return $returnXTPL; + + + } + function prepSave(){ + + } + function get_xtpl_list(){ + return $this->get_xtpl_detail(); + + } + function get_xtpl_detail(){ + + $name = $this->name; + $value = ''; + if(isset($this->bean->$name)){ + $value = $this->bean->$name; + }else{ + if(empty($this->bean->id)){ + $value= $this->default_value; + } + } + $returnXTPL = array(); + if(empty($value)) return $returnXTPL; + global $app_list_strings; + + $values = unencodeMultienum( $value); + $translatedValues = array(); + + foreach($values as $val){ + $translated = translate($this->options, '', $val); + if(is_string($translated))$translatedValues[] = $translated; + } + + $returnXTPL[strtoupper($this->name)] = implode(', ', $translatedValues); + return $returnXTPL; + + + + +} + + function get_field_def(){ + $def = parent::get_field_def(); + if ( !empty ( $this->ext4 ) ) + { + // turn off error reporting in case we are unpacking a value that hasn't been packed... + // this is kludgy, but unserialize doesn't throw exceptions correctly + if($this->ext4[0] == 'a' && $this->ext4[1] == ':') { + $unpacked = @unserialize ( $this->ext4 ) ; + } else { + $unpacked = false; + } + + // if we have a new error, then unserialize must have failed => we don't have a packed ext4 + // safe to assume that false means the unpack failed, as ext4 will either contain an imploded string of default values, or an array, not a boolean false value + if ( $unpacked === false ) { + $def [ 'default' ] = $this->ext4 ; + } + else + { + // we have a packed representation containing one or both of default and dependency + if ( isset ( $unpacked [ 'default' ] ) ) + $def [ 'default' ] = $unpacked [ 'default' ] ; + if ( isset ( $unpacked [ 'dependency' ] ) ) + $def [ 'dependency' ] = $unpacked [ 'dependency' ] ; + } + } + $def['isMultiSelect'] = true; + unset($def['len']); + return $def; + } + + function get_db_default(){ + return ''; + } + + function get_db_modify_alter_table($table){ + return parent::get_db_modify_alter_table($table); + } + + function save($df) { + if ( isset ( $this->default ) ) + { + if ( is_array ( $this->default ) ) + $this->default = encodeMultienumValue($this->default); + $this->ext4 = ( isset ( $this->dependency ) ) ? serialize ( array ( 'default' => $this->default , 'dependency' => $this->dependency ) ) : $this->default ; + } else + { + if ( isset ( $this->dependency ) ) + $this->ext4 = serialize ( array ( 'dependency' => $this->dependency ) ) ; + } + parent::save($df); + } +} + + +?> diff --git a/modules/DynamicFields/templates/Fields/TemplateParent.php b/modules/DynamicFields/templates/Fields/TemplateParent.php new file mode 100644 index 00000000..e9ef7efd --- /dev/null +++ b/modules/DynamicFields/templates/Fields/TemplateParent.php @@ -0,0 +1,107 @@ +name = 'parent_type'; + $parent_type->delete($df); + + $parent_id = new TemplateId(); + $parent_id->name = 'parent_id'; + $parent_id->delete($df); + } + + function save($df){ + $this->ext1 = 'parent_type_display'; + $this->name = 'parent_name'; + $this->default_value = ''; + parent::save($df); // always save because we may have updates + + //save parent_type + $parent_type = new TemplateParentType(); + $parent_type->name = 'parent_type'; + $parent_type->vname = 'LBL_PARENT_TYPE'; + $parent_type->label = $parent_type->vname; + $parent_type->len = 255; + $parent_type->importable = $this->importable; + $parent_type->save($df); + + //save parent_name + $parent_id = new TemplateId(); + $parent_id->name = 'parent_id'; + $parent_id->vname = 'LBL_PARENT_ID'; + $parent_id->label = $parent_id->vname; + $parent_id->len = 36; + $parent_id->importable = $this->importable; + $parent_id->save($df); + } + + function get_db_add_alter_table($table){ + return ''; + } + /** + * mysql requires the datatype caluse in the alter statment.it will be no-op anyway. + */ + function get_db_modify_alter_table($table){ + return ''; + } + + +} + + +?> diff --git a/modules/DynamicFields/templates/Fields/TemplateParentType.php b/modules/DynamicFields/templates/Fields/TemplateParentType.php new file mode 100644 index 00000000..f09f3c40 --- /dev/null +++ b/modules/DynamicFields/templates/Fields/TemplateParentType.php @@ -0,0 +1,53 @@ + diff --git a/modules/DynamicFields/templates/Fields/TemplatePhone.php b/modules/DynamicFields/templates/Fields/TemplatePhone.php new file mode 100644 index 00000000..d6ee3eb0 --- /dev/null +++ b/modules/DynamicFields/templates/Fields/TemplatePhone.php @@ -0,0 +1,69 @@ + diff --git a/modules/DynamicFields/templates/Fields/TemplateRadioEnum.php b/modules/DynamicFields/templates/Fields/TemplateRadioEnum.php new file mode 100644 index 00000000..00e67348 --- /dev/null +++ b/modules/DynamicFields/templates/Fields/TemplateRadioEnum.php @@ -0,0 +1,136 @@ +prepare(); + $xtpl_var = strtoupper( $this->name); + return "{RADIOOPTIONS_".$xtpl_var. "}"; + } + + function get_field_def(){ + $def = parent::get_field_def(); + $def['dbType'] = 'enum'; + $def['separator'] = '
    '; + return $def; + } + + + function get_xtpl_edit($add_blank = false){ + $name = $this->name; + $value = ''; + if(isset($this->bean->$name)){ + $value = $this->bean->$name; + }else{ + if(empty($this->bean->id)){ + $value= $this->default_value; + } + } + if(!empty($this->help)){ + $returnXTPL[$this->name . '_help'] = translate($this->help, $this->bean->module_dir); + } + + global $app_list_strings; + $returnXTPL = array(); + $returnXTPL[strtoupper($this->name)] = $value; + + + $returnXTPL[strtoupper('RADIOOPTIONS_'.$this->name)] = $this->generateRadioButtons($value, false); + return $returnXTPL; + + + } + + + function generateRadioButtons($value = '', $add_blank =false){ + global $app_list_strings; + $radiooptions = ''; + $keyvalues = $app_list_strings[$this->ext1]; + if($add_blank){ + $keyvalues = add_blank_option($keyvalues); + } + $help = (!empty($this->help))?"title='". translate($this->help, $this->bean->module_dir) . "'": ''; + foreach($keyvalues as $key=>$displayText){ + $selected = ($value == $key)?'checked': ''; + $radiooptions .= "$displayText
    \n"; + } + return $radiooptions; + + } + + function get_xtpl_search(){ + $searchFor = ''; + if(!empty($_REQUEST[$this->name])){ + $searchFor = $_REQUEST[$this->name]; + } + global $app_list_strings; + $returnXTPL = array(); + $returnXTPL[strtoupper($this->name)] = $searchFor; + $returnXTPL[strtoupper('RADIOOPTIONS_'.$this->name)] = $this->generateRadioButtons($searchFor, true); + return $returnXTPL; + + } + + function get_xtpl_detail(){ + $name = $this->name; + if(isset($this->bean->$name)){ + global $app_list_strings; + if(isset($app_list_strings[$this->ext1])){ + if(isset($app_list_strings[$this->ext1][$this->bean->$name])){ + return $app_list_strings[$this->ext1][$this->bean->$name]; + } + } + }else{ + if(empty($this->bean->id)){ + return $this->default_value; + } + } + return ''; + } + + function get_db_default(){ + return ''; +} + +} + + +?> diff --git a/modules/DynamicFields/templates/Fields/TemplateRange.php b/modules/DynamicFields/templates/Fields/TemplateRange.php new file mode 100644 index 00000000..a9d8e762 --- /dev/null +++ b/modules/DynamicFields/templates/Fields/TemplateRange.php @@ -0,0 +1,287 @@ +vardef_map['enable_range_search'] = 'enable_range_search'; + $this->vardef_map['options'] = 'options'; + } + + + /** + * populateFromPost + * + * @see parent::populateFromPost + * This method checks to see if enable_range_search is set. If so, ensure that the + * searchdefs for the module include the additional range fields. + */ + function populateFromPost() { + parent::populateFromPost(); + //If we are enabling range search, make sure we add the start and end range fields + if (!empty($this->enable_range_search)) + { + //If range search is enabled, set the options attribute for the dropdown choice selections + $this->options = ($this->type == 'date' || $this->type == 'datetimecombo' || $this->type == 'datetime') ? 'date_range_search_dom' : 'numeric_range_search_dom'; + + if(isset($_REQUEST['view_module'])) + { + $module = $_REQUEST['view_module']; + if(file_exists('custom/modules/'.$module.'/metadata/SearchFields.php')) + { + require('custom/modules/'.$module.'/metadata/SearchFields.php'); + } else if (file_exists('modules/'.$module.'/metadata/SearchFields.php')) { + require('modules/'.$module.'/metadata/SearchFields.php'); + } + + $field_name = $this->get_field_name($module, $_REQUEST['name']); + + if(isset($searchFields[$module])) + { + $field_name_range = 'range_' . $field_name; + $field_name_start = 'start_range_' . $field_name; + $field_name_end = 'end_range_' . $field_name; + + $isDateField = $this->type == 'date' || $this->type == 'datetimecombo' || $this->type == 'datetime'; + + + $searchFields[$module][$field_name_range] = array('query_type'=>'default', 'enable_range_search'=>true); + if($isDateField) + { + $searchFields[$module][$field_name_range]['is_date_field'] = true; + } + + $searchFields[$module][$field_name_start] = array('query_type'=>'default', 'enable_range_search'=>true); + if($isDateField) + { + $searchFields[$module][$field_name_start]['is_date_field'] = true; + } + + $searchFields[$module][$field_name_end] = array('query_type'=>'default', 'enable_range_search'=>true); + if($isDateField) + { + $searchFields[$module][$field_name_end]['is_date_field'] = true; + } + + if(!file_exists('custom/modules/'.$module.'/metadata/SearchFields.php')) + { + mkdir_recursive('custom/modules/'.$module.'/metadata'); + } + write_array_to_file("searchFields['{$module}']", $searchFields[$module], 'custom/modules/'.$module.'/metadata/SearchFields.php'); + } + + if(file_exists($GLOBALS['sugar_config']['cache_dir'] . 'modules/' . $module . '/SearchForm_basic.tpl')) + { + unlink($GLOBALS['sugar_config']['cache_dir'] . 'modules/' . $module . '/SearchForm_basic.tpl'); + } + + if(file_exists($GLOBALS['sugar_config']['cache_dir'] . 'modules/' . $module . '/SearchForm_advanced.tpl')) + { + unlink($GLOBALS['sugar_config']['cache_dir'] . 'modules/' . $module . '/SearchForm_advanced.tpl'); + } + } + } else { + //Otherwise, try to restore the searchFields to their state prior to being enabled + if(isset($_REQUEST['view_module'])) + { + $module = $_REQUEST['view_module']; + if(file_exists('custom/modules/'.$module.'/metadata/SearchFields.php')) + { + require('custom/modules/'.$module.'/metadata/SearchFields.php'); + } else if (file_exists('modules/'.$module.'/metadata/SearchFields.php')) { + require('modules/'.$module.'/metadata/SearchFields.php'); + } + + $field_name = $this->get_field_name($module, $_REQUEST['name']); + + if(isset($searchFields[$module])) + { + $field_name_range = 'range_' . $field_name; + $field_name_start = 'start_range_' . $field_name; + $field_name_end = 'end_range_' . $field_name; + + + if(isset($searchFields[$module][$field_name_range])) + { + unset($searchFields[$module][$field_name_range]); + } + + if(isset($searchFields[$module][$field_name_start])) + { + unset($searchFields[$module][$field_name_start]); + } + + if(isset($searchFields[$module][$field_name_end])) + { + unset($searchFields[$module][$field_name_end]); + } + + if(!file_exists('custom/modules/'.$module.'/metadata/SearchFields.php')) + { + mkdir_recursive('custom/modules/'.$module.'/metadata'); + } + write_array_to_file("searchFields['{$module}']", $searchFields[$module], 'custom/modules/'.$module.'/metadata/SearchFields.php'); + } + + if(file_exists($GLOBALS['sugar_config']['cache_dir'] . 'modules/' . $module . '/SearchForm_basic.tpl')) + { + unlink($GLOBALS['sugar_config']['cache_dir'] . 'modules/' . $module . '/SearchForm_basic.tpl'); + } + + if(file_exists($GLOBALS['sugar_config']['cache_dir'] . 'modules/' . $module . '/SearchForm_advanced.tpl')) + { + unlink($GLOBALS['sugar_config']['cache_dir'] . 'modules/' . $module . '/SearchForm_advanced.tpl'); + } + } + } + } + + + /** + * get_field_def + * + * @see parent::get_field_def + * This method checks to see if the enable_range_search key/value entry should be + * added to the vardef entry representing the module + */ + function get_field_def() + { + $vardef = parent::get_field_def(); + if(!empty($this->enable_range_search)) + { + $vardef['enable_range_search'] = $this->enable_range_search; + $vardef['options'] = ($this->type == 'date' || $this->type == 'datetimecombo' || $this->type == 'datetime') ? 'date_range_search_dom' : 'numeric_range_search_dom'; + } else { + $vardef['enable_range_search'] = false; + } + return $vardef; + } + + /** + * get_field_name + * This function gets the correct name for the field name being submitted from studio + * + * @param String $module The name of the module + * @param String $name The field name + */ + private function get_field_name($module, $name) + { + $bean = loadBean($module); + if(empty($bean) || is_null($bean)) + { + return $name; + } + + $field_defs = $bean->field_defs; + $field_name = isset($field_defs[$_REQUEST['name']]) ? $_REQUEST['name'] : $_REQUEST['name'] . '_c'; + return $field_name; + } + + public static function repairCustomSearchFields($vardefs, $module, $package='') + { + + $fields = array(); + + foreach($vardefs as $key=>$field) + { + if(!empty($field['enable_range_search'])) { + $fields[$field['name']] = $field; + } + } + + if(!empty($fields)) + { + if(file_exists('custom/modules/'.$module.'/metadata/SearchFields.php')) + { + require('custom/modules/'.$module.'/metadata/SearchFields.php'); + } else if (file_exists('modules/'.$module.'/metadata/SearchFields.php')) { + require('modules/'.$module.'/metadata/SearchFields.php'); + } else if (file_exists('custom/modulebuilder/' . $package . '/modules/' . $module . '/metadata/SearchFields.php')) { + require('custom/modulebuilder/' . $package . '/modules/' . $module . '/metadata/SearchFields.php'); + } + + foreach($fields as $field_name=>$field) + { + $field_name_range = 'range_' . $field_name; + $field_name_start = 'start_range_' . $field_name; + $field_name_end = 'end_range_' . $field_name; + + $type = $field['type']; + + $isDateField = $type == 'date' || $type == 'datetimecombo' || $type == 'datetime'; + + $searchFields[$module][$field_name_range] = array('query_type'=>'default', 'enable_range_search'=>true); + if($isDateField) + { + $searchFields[$module][$field_name_range]['is_date_field'] = true; + } + + $searchFields[$module][$field_name_start] = array('query_type'=>'default', 'enable_range_search'=>true); + if($isDateField) + { + $searchFields[$module][$field_name_start]['is_date_field'] = true; + } + + $searchFields[$module][$field_name_end] = array('query_type'=>'default', 'enable_range_search'=>true); + if($isDateField) + { + $searchFields[$module][$field_name_end]['is_date_field'] = true; + } + } + + if(!file_exists('custom/modules/'.$module.'/metadata/SearchFields.php')) + { + mkdir_recursive('custom/modules/'.$module.'/metadata'); + } + + write_array_to_file("searchFields['{$module}']", $searchFields[$module], 'custom/modules/'.$module.'/metadata/SearchFields.php'); + + } + } + + +} +?> \ No newline at end of file diff --git a/modules/DynamicFields/templates/Fields/TemplateRelatedTextField.php b/modules/DynamicFields/templates/Fields/TemplateRelatedTextField.php new file mode 100644 index 00000000..4bbb1adc --- /dev/null +++ b/modules/DynamicFields/templates/Fields/TemplateRelatedTextField.php @@ -0,0 +1,255 @@ +prepare(); + $name = $this->name .'_name'; + $value_name = strtoupper('{'.$name.'}'); + $id = $this->name ; + $value_id = strtoupper('{'.$id .'}'); + return ""; + } + + function get_html_detail(){ + $name = $this->name .'_name'; + $value_name = strtoupper('{'.$name.'}'); + $id = $this->name ; + $value_id = strtoupper('{'.$id .'}'); + + return "{$value_name}" ; + } + + function get_html_list(){ + if(isset($this->bean)){ + $name = $this->bean->object_name . '.'. $this->ext1; + }else{ + $name = $this->ext1; + } + return '{'. strtoupper($name) . '}'; + } + + function get_html_search(){ + $searchable=array(); + $def = $this->bean->field_name_map[$this->name]; + if(!empty($def['id_name']) && in_array($def['id_name'], $searchable)){ + $name = $def['id_name']; + return ""; + } + //return 'NOT AVAILABLE'; + return $this->get_html_edit(); + } + + function get_xtpl_search(){ + $searchable=array(); + $def = $this->bean->field_name_map[$this->name]; + $returnXTPL = array(); + if(!empty($def['id_name']) && in_array($def['id_name'], $searchable)){ + $name = $def['id_name']; + $team_list = ''; + foreach(get_team_array() as $id=>$team){ + $selected = ''; + + if(!empty($_REQUEST[$name]) && is_array($_REQUEST[$name]) && in_array($id, $_REQUEST[$name])){ + $selected = 'selected'; + } + $team_list .= ""; + } + $returnXTPL[strtoupper($name). '_FILTER'] = $team_list; + } else { + $id = $this->name; + $name = $this->name .'_name'; + $module = $this->ext2; + $popup_request_data = array( + 'call_back_function' => 'set_return', + 'form_name' => 'search_form', + 'field_to_name_array' => array( + 'id' => $this->name, + $this->ext1 => $name, + ), + ); + + $json = getJSONobj(); + $encoded_popup_request_data = $json->encode($popup_request_data); + $returnXTPL['ENCODED_'.strtoupper($id).'_POPUP_REQUEST_DATA'] = $encoded_popup_request_data; + $returnXTPL[strtoupper($id).'_MODULE'] = $module; + + if(isset( $_REQUEST[$name])){ + $returnXTPL[strtoupper($name)] = $_REQUEST[$name]; + } + if(isset( $_REQUEST[$id])){ + $returnXTPL[strtoupper($id)] = $_REQUEST[$id]; + } + } + return $returnXTPL; + } + + + function get_xtpl_edit(){ + global $beanList; + + $name = $this->name .'_name'; + $id = $this->name; + $module = $this->ext2; + $returnXTPL = array(); + $popup_request_data = array( + 'call_back_function' => 'set_return', + 'form_name' => 'EditView', + 'field_to_name_array' => array( + 'id' => $this->name, + $this->ext1 => $name, + ), + ); + + //$GLOBALS['log']->fatal($this->bean); + + $json = getJSONobj(); + $encoded_contact_popup_request_data = $json->encode($popup_request_data); + $returnXTPL['ENCODED_'.strtoupper($id).'_POPUP_REQUEST_DATA'] = $encoded_contact_popup_request_data; + $returnXTPL[strtoupper($id).'_MODULE'] = $module; + + if(isset($beanList[$module]) && isset($this->bean->$id)){ + if(!isset($this->bean->$name)){ + $mod_field = $this->ext1; + global $beanFiles; + + $class = $beanList[$module]; + + require_once($beanFiles[$class]); + $mod = new $class(); + $mod->retrieve($this->bean->$id); + if(isset($mod->$mod_field)){ + $this->bean->$name = $mod->$mod_field; + } + } + + + $returnXTPL[strtoupper($id)] = $this->bean->$id; + } + if(isset($this->bean->$name)){ + $returnXTPL[strtoupper($name)] = $this->bean->$name; + } + if(isset($this->bean->$id)) { + $returnXTPL[strtoupper($id)] = $this->bean->$id; + } + + + return $returnXTPL; + } + + function get_xtpl_detail(){ + return $this->get_xtpl_edit(); + } + + function get_related_info(){ + + } + + function get_field_def(){ + $def = parent::get_field_def(); + $def['id_name'] = $this->ext3; + $def['ext2'] = $this->ext2; + $def['module'] = $def['ext2']; + //Special case for documents, which use a document_name rather than name + if ($def['module'] == "Documents") { + $def['rname'] = 'document_name'; + } else { + $def['rname'] = 'name'; + } + $def['quicksearch'] = 'enabled'; + $def['studio'] = 'visible'; + $def['source'] = 'non-db'; + return $def; + } + + function delete($df){ + parent::delete($df); + + $id = new TemplateId(); + $id->name = $this->ext3; + $id->delete($df); + } + + function save($df){ + // create the new ID field associated with this relate field - this will hold the id of the related record + // this field must have a unique name as the name is used when constructing quicksearches and when saving the field + //Check if we have not saved this field so we don't create two ID fields. + //Users should not be able to switch the module after having saved it once. + if (!$df->fieldExists($this->name)) { + $id = new TemplateId(); + $id->len = 36; + $id->label = 'LBL_LIST_RELATED_TO'; + $count = 0; + $basename = strtolower(get_singular_bean_name($this->ext2)).'_id' ; + $idName = $basename.'_c' ; + + while ( $df->fieldExists($idName, 'id') ) + { + $idName = $basename.++$count.'_c' ; + } + $id->name = $idName ; + $id->save($df); + + // record the id field's name, and save + $this->ext3 = $id->name; + } + + parent::save($df); + } + + function get_db_add_alter_table($table){ + return ""; + } + + function get_db_delete_alter_table($table) { + return ""; + } + + function get_db_modify_alter_table($table){ + return ""; + } + +} + + +?> diff --git a/modules/DynamicFields/templates/Fields/TemplateText.php b/modules/DynamicFields/templates/Fields/TemplateText.php new file mode 100644 index 00000000..67677f79 --- /dev/null +++ b/modules/DynamicFields/templates/Fields/TemplateText.php @@ -0,0 +1,80 @@ +name; + $returnXTPL = array(); + + if(!empty($this->help)){ + $returnXTPL[strtoupper($this->name . '_help')] = translate($this->help, $this->bean->module_dir); + } + + if(isset($this->bean->$name)){ + $returnXTPL[$this->name] = $this->bean->$name; + }else{ + if(empty($this->bean->id)){ + $returnXTPL[$this->name] = $this->default_value; + } + } + return $returnXTPL; + } + function get_xtpl_search(){ + if(!empty($_REQUEST[$this->name])){ + return $_REQUEST[$this->name]; + } + } + + + + function get_xtpl_detail(){ + $name = $this->name; + if(isset($this->bean->$name)){ + return $this->bean->$name; + } + return ''; + + } + + +} + + +?> diff --git a/modules/DynamicFields/templates/Fields/TemplateTextArea.php b/modules/DynamicFields/templates/Fields/TemplateTextArea.php new file mode 100644 index 00000000..04ca59e7 --- /dev/null +++ b/modules/DynamicFields/templates/Fields/TemplateTextArea.php @@ -0,0 +1,109 @@ +vardef_map['rows'] = 'ext2'; + $this->vardef_map['cols'] = 'ext3'; + } + + function get_db_type(){ + if ($GLOBALS['db']->dbType=='oci8') { + return " CLOB "; + } else if(!empty($GLOBALS['db']->isFreeTDS)) { + return " NTEXT "; + } else { + return " TEXT "; + } + } + + function set($values){ + parent::set($values); + if(!empty($this->ext2)){ + $this->rows = $this->ext2; + } + if(!empty($this->ext3)){ + $this->cols = $this->ext3; + } + if(!empty($this->ext4)){ + $this->default_value = $this->ext4; + } + + } + + + function get_xtpl_detail(){ + $name = $this->name; + return nl2br($this->bean->$name); + } + + function get_field_def(){ + $def = parent::get_field_def(); + $def['studio'] = 'visible'; + + if ( isset ( $this->ext2 ) && isset ($this->ext3)) + { + $def[ 'rows' ] = $this->ext2 ; + $def[ 'cols' ] = $this->ext3 ; + } + if (isset( $this->rows ) && isset ($this->cols)) + { + $def[ 'rows' ] = $this->rows ; + $def[ 'cols' ] = $this->cols ; + } + return $def; + } + + function get_db_default(){ + // TEXT columns in MySQL cannot have a DEFAULT value - let the Bean handle it on save + return null; // Bug 16612 - null so that the get_db_default() routine in TemplateField doesn't try to set DEFAULT + } + + function get_db_modify_alter_table($table){ + return parent::get_db_modify_alter_table($table); + } + + +} + + +?> diff --git a/modules/DynamicFields/templates/Fields/TemplateURL.php b/modules/DynamicFields/templates/Fields/TemplateURL.php new file mode 100644 index 00000000..4356f94d --- /dev/null +++ b/modules/DynamicFields/templates/Fields/TemplateURL.php @@ -0,0 +1,78 @@ +vardef_map['ext4'] = 'link_target'; + $this->vardef_map['link_target'] = 'ext4'; + } + + var $type='url'; + function get_html_edit(){ + $this->prepare(); + return ""; + } + + function get_html_detail(){ + $xtpl_var = strtoupper($this->name); + return "{" . $xtpl_var . "}"; + } + + function get_xtpl_detail(){ + $value = parent::get_xtpl_detail(); + if(!empty($value) && substr_count($value, '://') == 0 && substr($value ,0,8) != 'index.php'){ + $value = 'http://' . $value; + } + return $value; + } + + function get_field_def(){ + $def = parent::get_field_def(); + //$def['options'] = !empty($this->options) ? $this->options : $this->ext1; + $def['default'] = !empty($this->default) ? $this->default : $this->default_value; + $def['len'] = $this->len; + $def['dbType'] = 'varchar'; + $def['gen'] = !empty($this->gen) ? $this->gen : $this->ext3; + $def['link_target'] = !empty($this->link_target) ? $this->link_target : $this->ext4; + return $def; + } + +} +?> diff --git a/modules/DynamicFields/templates/Files/DetailView.php b/modules/DynamicFields/templates/Files/DetailView.php new file mode 100644 index 00000000..88e00857 --- /dev/null +++ b/modules/DynamicFields/templates/Files/DetailView.php @@ -0,0 +1,49 @@ +custom_fields)){ +/* +$test is set to focus to increment the reference count +since it appears that the reference count was off by 1 +*/ +$test =& $focus; +$focus->custom_fields->bean =& $focus; +$focus->custom_fields->populateXTPL($xtpl, 'detail'); +} +?> diff --git a/modules/DynamicFields/templates/Files/EditView.php b/modules/DynamicFields/templates/Files/EditView.php new file mode 100644 index 00000000..d94012db --- /dev/null +++ b/modules/DynamicFields/templates/Files/EditView.php @@ -0,0 +1,49 @@ +custom_fields)){ +/* +$test is set to focus to increment the reference count +since it appears that the reference count was off by 1 +*/ +$test =& $focus; +$focus->custom_fields->bean =& $focus; +$focus->custom_fields->populateXTPL($xtpl, 'edit'); +} + +?> diff --git a/modules/DynamicFields/vardefs.php b/modules/DynamicFields/vardefs.php new file mode 100644 index 00000000..f77a4b1f --- /dev/null +++ b/modules/DynamicFields/vardefs.php @@ -0,0 +1,69 @@ + 'fields_meta_data', + 'fields' => array ( + 'id'=>array('name' =>'id', 'type' =>'varchar', 'len'=>'255', 'reportable'=>false), + 'name'=>array('name' =>'name', 'vname'=>'COLUMN_TITLE_NAME', 'type' =>'varchar', 'len'=>'255'), + 'vname'=>array('name' =>'vname' ,'type' =>'varchar','vname'=>'COLUMN_TITLE_LABEL', 'len'=>'255'), + 'comments'=>array('name' =>'comments' ,'type' =>'varchar','vname'=>'COLUMN_TITLE_LABEL', 'len'=>'255'), + 'help'=>array('name' =>'help' ,'type' =>'varchar','vname'=>'COLUMN_TITLE_LABEL', 'len'=>'255'), + 'custom_module'=>array('name' =>'custom_module', 'type' =>'varchar', 'len'=>'255', ), + 'type'=>array('name' =>'type', 'vname'=>'COLUMN_TITLE_DATA_TYPE', 'type' =>'varchar', 'len'=>'255'), + 'len'=>array('name' =>'len','vname'=>'COLUMN_TITLE_MAX_SIZE', 'type' =>'int', 'len'=>'11', 'required'=>false, 'validation' => array('type' => 'range', 'min' => 1, 'max' => 255),), + 'required'=>array('name' =>'required', 'type' =>'bool', 'default'=>'0'), + 'default_value'=>array('name' =>'default_value', 'type' =>'varchar', 'len'=>'255', ), + 'date_modified'=>array('name' =>'date_modified', 'type' =>'datetime', 'len'=>'255',), + 'deleted'=>array('name' =>'deleted', 'type' =>'bool', 'default'=>'0', 'reportable'=>false), + 'audited'=>array('name' =>'audited', 'type' =>'bool', 'default'=>'0'), + 'massupdate'=>array('name' =>'massupdate', 'type' =>'bool', 'default'=>'0'), + 'duplicate_merge'=>array('name' =>'duplicate_merge', 'type' =>'short', 'default'=>'0'), + 'reportable' => array('name'=>'reportable', 'type'=>'bool', 'default'=>'1'), + 'importable' => array('name'=>'importable', 'type'=>'varchar', 'len'=>'255'), + 'ext1'=>array('name' =>'ext1', 'type' =>'varchar', 'len'=>'255', 'default'=>''), + 'ext2'=>array('name' =>'ext2', 'type' =>'varchar', 'len'=>'255', 'default'=>''), + 'ext3'=>array('name' =>'ext3', 'type' =>'varchar', 'len'=>'255', 'default'=>''), + 'ext4'=>array('name' =>'ext4', 'type' =>'text'), + ), + 'indices' => array ( + array('name' =>'fields_meta_datapk', 'type' =>'primary', 'fields' => array('id')), + array('name' =>'idx_meta_id_del', 'type' =>'index', 'fields'=>array('id','deleted')), + array('name' => 'idx_meta_cm_del', 'type' => 'index', 'fields' => array('custom_module', 'deleted')), + ), +); \ No newline at end of file diff --git a/modules/EAPM/CheckLogins.php b/modules/EAPM/CheckLogins.php new file mode 100644 index 00000000..663ee6dd --- /dev/null +++ b/modules/EAPM/CheckLogins.php @@ -0,0 +1,89 @@ + $apiOpts ) { + if ( $apiOpts['authMethod'] == 'oauth' ) { + $api = ExternalAPIFactory::loadAPI($apiName); + if ( is_object($api) ) { + $loginCheck = $api->quickCheckLogin(); + } else { + $loginCheck['success'] = false; + } + if ( ! $loginCheck['success'] ) { + $thisFail = array(); + + $thisFail['checkURL'] = 'index.php?module=EAPM&closeWhenDone=1&action=Save&record='.$api->eapmBean->id; + + $translateKey = 'LBL_EXTAPI_'.strtoupper($apiName); + if ( ! empty($app_strings[$translateKey]) ) { + $thisFail['label'] = $app_strings[$translateKey]; + } else { + $thisFail['label'] = $apiName; + } + + $thisFail['label'] .= translate('LBL_ERR_FAILED_QUICKCHECK','EAPM'); + + $failList[$apiName] = $thisFail; + } + } + } +} + +$json = new JSON(); +echo($json->encode($failList)); diff --git a/modules/EAPM/EAPM.php b/modules/EAPM/EAPM.php new file mode 100644 index 00000000..2a42033b --- /dev/null +++ b/modules/EAPM/EAPM.php @@ -0,0 +1,230 @@ +fromArray($_SESSION['EAPM'][$application]); + } else { + return null; + } + } else { + $queryArray = array('assigned_user_id'=>$current_user->id, 'application'=>$application ); + if ( !$includeInactive ) { + $queryArray['validated'] = 1; + $queryArray['active'] = 1; + } + $eapmBean = $eapmBean->retrieve_by_string_fields($queryArray); + + // Don't cache the include inactive results + if ( !$includeInactive ) { + if ( $eapmBean != null ) { + $_SESSION['EAPM'][$application] = $eapmBean->toArray(); + } else { + $_SESSION['EAPM'][$application] = ''; + return null; + } + } + } + + if(isset($eapmBean->password)){ + require_once("include/utils/encryption_utils.php"); + $eapmBean->password = blowfishDecode(blowfishGetKey('encrypt_field'),$eapmBean->password);; + } + + return $eapmBean; + } + + function create_new_list_query($order_by, $where,$filter=array(),$params=array(), $show_deleted = 0,$join_type='', $return_array = false,$parentbean=null, $singleSelect = false) { + global $current_user; + + if ( !is_admin($GLOBALS['current_user']) ) { + // Restrict this so only admins can see other people's records + $owner_where = $this->getOwnerWhere($current_user->id); + + if(empty($where)) { + $where = $owner_where; + } else { + $where .= ' AND '. $owner_where; + } + } + + return parent::create_new_list_query($order_by, $where, $filter, $params, $show_deleted,$join_type, $return_array, $parentbean, $singleSelect); + } + + function save($check_notify = FALSE ) { + $this->fillInName(); + if ( !is_admin($GLOBALS['current_user']) ) { + $this->assigned_user_id = $GLOBALS['current_user']->id; + } + $parentRet = parent::save($check_notify); + + // Nuke the EAPM cache for this record + if ( isset($_SESSION['EAPM'][$this->application]) ) { + unset($_SESSION['EAPM'][$this->application]); + } + + return $parentRet; + } + + function mark_deleted($id) + { + // Nuke the EAPM cache for this record + if ( isset($_SESSION['EAPM'][$this->application]) ) { + unset($_SESSION['EAPM'][$this->application]); + } + + return parent::mark_deleted($id); + } + + function validated() + { + if(empty($this->id)) { + return false; + } + // Don't use save, it will attempt to revalidate + $adata = $GLOBALS['db']->quote($this->api_data); + $GLOBALS['db']->query("UPDATE eapm SET validated=1,api_data='$adata' WHERE id = '{$this->id}' AND deleted = 0"); + if($this->active && !empty($this->application)) { + // deactivate other EAPMs with same app + $sql = "UPDATE eapm SET active=0 WHERE application = '{$this->application}' AND id != '{$this->id}' AND active=1 AND deleted = 0 AND assigned_user_id = '{$this->assigned_user_id}'"; + $GLOBALS['db']->query($sql,true); + } + + // Nuke the EAPM cache for this record + if ( isset($_SESSION['EAPM'][$this->application]) ) { + unset($_SESSION['EAPM'][$this->application]); + } + + } + + protected function fillInName() + { + if ( !empty($this->application) ) { + $apiList = ExternalAPIFactory::loadFullAPIList(false, true); + } + if(!empty($apiList) && isset($apiList[$this->application]) && $apiList[$this->application]['authMethod'] == "oauth") { + $this->name = sprintf(translate('LBL_OAUTH_NAME', $this->module_dir), $this->application); + } + } + + public function fill_in_additional_detail_fields() + { + $this->fillInName(); + parent::fill_in_additional_detail_fields(); + } + + public function fill_in_additional_list_fields() + { + $this->fillInName(); + parent::fill_in_additional_list_fields(); + } + + public function save_cleanup() + { + $this->oauth_token = ""; + $this->oauth_secret = ""; + $this->api_data = ""; + } + + /** + * Given a user remove their associated accounts. This is called when a user is deleted from the system. + * @param $user_id + * @return void + */ + public function delete_user_accounts($user_id){ + $sql = "DELETE FROM {$this->table_name} WHERE assigned_user_id = '{$user_id}'"; + $GLOBALS['db']->query($sql,true); + } +} + +// External API integration, for the dropdown list of what external API's are available +function getEAPMExternalApiDropDown() { + $apiList = ExternalAPIFactory::getModuleDropDown('',true, true); + + return $apiList; + +} diff --git a/modules/EAPM/EAPMEdit.js b/modules/EAPM/EAPMEdit.js new file mode 100644 index 00000000..5348087c --- /dev/null +++ b/modules/EAPM/EAPMEdit.js @@ -0,0 +1,41 @@ +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ +function EAPMChange(){var apiName='';if(EAPMFormName=='EditView'){apiName=document.getElementById('application').value;}else{apiName=document.getElementById('application_raw').value;} +if(SUGAR.eapm[apiName]){var apiOpts=SUGAR.eapm[apiName];var urlObj=new SUGAR.forms.VisibilityAction('url',(apiOpts.needsUrl?'true':'false'),EAPMFormName);if(EAPMFormName=='EditView'){EAPMSetFieldRequired('url',(apiOpts.needsUrl==true));} +var userObj=new SUGAR.forms.VisibilityAction('name',((apiOpts.authMethod=='password')?'true':'false'),EAPMFormName);if(EAPMFormName=='EditView'){EAPMSetFieldRequired('name',(apiOpts.authMethod=='password'));} +var passObj=new SUGAR.forms.VisibilityAction('password',((apiOpts.authMethod=='password')?'true':'false'),EAPMFormName);if(EAPMFormName=='EditView'){EAPMSetFieldRequired('password',(apiOpts.authMethod=='password'));} +urlObj.exec();userObj.exec();passObj.exec();var messageDiv=document.getElementById('eapm_notice_div');if(typeof messageDiv!='undefined'&&messageDiv!=null){if(apiOpts.authMethod){if(apiOpts.authMethod=="oauth"){messageDiv.innerHTML=EAPMOAuthNotice;}else{messageDiv.innerHTML=EAPMBAsicAuthNotice;}}else{messageDiv.innerHTML=EAPMBAsicAuthNotice;}}}} +function EAPMSetFieldRequired(fieldName,isRequired){var formname='EditView';for(var i=0;iaction), $this->admin_actions)) { + $this->hasAccess = false; + } + parent::process(); + } + + protected function failed($error) + { + SugarApplication::appendErrorMessage($error); + $GLOBALS['log']->error("Login error: $error"); + $url = 'index.php?module=EAPM&action=EditView&record='.$this->bean->id; + return $this->set_redirect($url); + } + + public function pre_save() + { + parent::pre_save(); + $this->api = ExternalAPIFactory::loadAPI($this->bean->application,true); + if(empty($this->api)) { + return $this->failed(translate('LBL_AUTH_UNSUPPORTED', $this->bean->module_dir)); + } + if(empty($this->bean->id)){ + $eapmBean = EAPM::getLoginInfo($this->bean->application,true); + if($eapmBean){ + SugarApplication::appendErrorMessage(translate('LBL_APPLICATION_FOUND_NOTICE', $this->bean->module_dir)); + $this->bean->id = $eapmBean->id; + } + } + $this->bean->validated = false; + $this->bean->save_cleanup(); + $this->api->loadEAPM($this->bean); + } + + protected function post_save() + { + if($this->bean->active) { + // do not load bean here since password is already encoded + $reply = $this->api->checkLogin(); + if ( !$reply['success'] ) { + return $this->failed(translate('LBL_AUTH_ERROR', $this->bean->module_dir)); + } else { + $this->bean->validated(); + } + } + if($this->return_module == 'Users'){ + $this->return_action = 'EditView'; + } + return parent::post_save(); + } + + protected function action_oauth() + { + if(empty($this->bean->id)) { + return $this->set_redirect('index.php'); + } + if(!$this->bean->ACLAccess('save')){ + ACLController::displayNoAccess(true); + sugar_cleanup(true); + return true; + } + $this->api = ExternalAPIFactory::loadAPI($this->bean->application,true); + $reply = $this->api->checkLogin($this->bean); + if ( !$reply['success'] ) { + return $this->failed(translate('LBL_AUTH_ERROR', $this->bean->module_dir)); + } else { + $this->bean->validated(); + + // This is a tweak so that we can automatically close windows if requested by the external account system + if ( isset($_REQUEST['closeWhenDone']) && $_REQUEST['closeWhenDone'] == 1 ) { + if(!empty($_REQUEST['callbackFunction']) && !empty($_REQUEST['application'])){ + $js = ''; + }else if(!empty($_REQUEST['refreshParentWindow'])){ + $js = ''; + }else{ + $js = ''; + } + echo($js); + return; + } + + // redirect to detail view, as in save + return parent::post_save(); + } + } + + protected function pre_QuickSave(){ + if(!empty($_REQUEST['application'])){ + $eapmBean = EAPM::getLoginInfo($_REQUEST['application'],true); + if (!$eapmBean) { + $this->bean->application = $_REQUEST['application']; + $this->bean->assigned_user_id = $GLOBALS['current_user']->id; + }else{ + $this->bean = $eapmBean; + $this->bean->active = 1; + } + $this->pre_save(); + + }else{ + sugar_die("Please pass an application name."); + } + } + + public function action_QuickSave(){ + $this->action_save(); + } + + protected function post_QuickSave(){ + $this->post_save(); + } + + protected function pre_Reauthenticate(){ + $this->bean->active = 1; + $this->pre_save(); + } + + protected function action_Reauthenticate(){ + $this->action_save(); + } + + protected function post_Reauthenticate(){ + $this->post_save(); + } + + protected function action_FlushFileCache() + { + $api = ExternalAPIFactory::loadAPI($_REQUEST['api']); + if ( $api == false ) { + echo 'FAILED'; + return; + } + + if ( method_exists($api,'loadDocCache') ) { + $api->loadDocCache(true); + } + + echo 'SUCCESS'; + } +} \ No newline at end of file diff --git a/modules/EAPM/language/en_us.lang.php b/modules/EAPM/language/en_us.lang.php new file mode 100644 index 00000000..58b21514 --- /dev/null +++ b/modules/EAPM/language/en_us.lang.php @@ -0,0 +1,106 @@ + 'Assigned User Id', + 'LBL_ASSIGNED_TO_NAME' => 'Sugar User', + 'LBL_ID' => 'ID', + 'LBL_DATE_ENTERED' => 'Date Created', + 'LBL_DATE_MODIFIED' => 'Date Modified', + 'LBL_MODIFIED' => 'Modified By', + 'LBL_MODIFIED_ID' => 'Modified By Id', + 'LBL_MODIFIED_NAME' => 'Modified By Name', + 'LBL_CREATED' => 'Created By', + 'LBL_CREATED_ID' => 'Created By Id', + 'LBL_DESCRIPTION' => 'Description', + 'LBL_DELETED' => 'Deleted', + 'LBL_NAME' => 'App User Name', + 'LBL_CREATED_USER' => 'Created By User', + 'LBL_MODIFIED_USER' => 'Modified By User', + 'LBL_LIST_NAME' => 'Name', + 'LBL_TEAM' => 'Teams', + 'LBL_TEAMS' => 'Teams', + 'LBL_TEAM_ID' => 'Team Id', + 'LBL_LIST_FORM_TITLE' => 'External Account List', + 'LBL_MODULE_NAME' => 'External Account', + 'LBL_MODULE_TITLE' => 'External Accounts', + 'LBL_HOMEPAGE_TITLE' => 'My External Accounts', + 'LNK_NEW_RECORD' => 'Create External Account', + 'LNK_LIST' => 'View External Accounts', + 'LNK_IMPORT_SUGAR_EAPM' => 'Import External Accounts', + 'LBL_SEARCH_FORM_TITLE' => 'Search External Source', + 'LBL_HISTORY_SUBPANEL_TITLE' => 'View History', + 'LBL_ACTIVITIES_SUBPANEL_TITLE' => 'Activities', + 'LBL_SUGAR_EAPM_SUBPANEL_TITLE' => 'External Accounts', + 'LBL_NEW_FORM_TITLE' => 'New External Account', + 'LBL_PASSWORD' => 'App Password', + 'LBL_USER_NAME' => 'App User Name', + 'LBL_URL' => 'URL', + 'LBL_APPLICATION' => 'Application', + 'LBL_API_DATA' => 'API Data', + 'LBL_API_TYPE' => 'Login Type', + 'LBL_API_CONSKEY' => 'Consumer Key', + 'LBL_API_CONSSECRET' => 'Consumer Secret', + 'LBL_API_OAUTHTOKEN' => 'OAuth Token', + 'LBL_AUTH_UNSUPPORTED' => "This authorization method is not supported by the application", + 'LBL_AUTH_ERROR' => 'Attempt to authenticate the external account failed.', + 'LBL_VALIDATED' => 'Access Validated', + 'LBL_ACTIVE' => 'Active', + 'LBL_OAUTH_NAME' => '%s', + 'LBL_SUGAR_USER_NAME' => 'Sugar User', + 'LBL_DISPLAY_PROPERTIES' => 'Display Properties', + + 'LBL_ERR_NO_AUTHINFO' => 'There is no authentication information for this account.', + 'LBL_ERR_NO_TOKEN' => 'There are no valid login tokens for this account.', + + 'LBL_ERR_FAILED_QUICKCHECK' => 'You are not currently logged in to your {0} account. Click OK to re-login to your account and to activate the external account record.', + + // Various strings used throughout the external account modules + 'LBL_MEET_NOW_BUTTON' => 'Meet Now', + 'LBL_VIEW_LOTUS_LIVE_MEETINGS' => 'View Upcoming LotusLive™ Meetings', + 'LBL_TITLE_LOTUS_LIVE_MEETINGS' => 'Upcoming LotusLive™ Meetings', + 'LBL_VIEW_LOTUS_LIVE_DOCUMENTS' => 'View LotusLive™ Files', + 'LBL_TITLE_LOTUS_LIVE_DOCUMENTS' => 'LotusLive™ Files', + 'LBL_REAUTHENTICATE_LABEL' => 'Reauthenticate', + 'LBL_REAUTHENTICATE_KEY' => 'a', + 'LBL_APPLICATION_FOUND_NOTICE' => 'An account for this application already exists. We have reinstated the existing account.', + 'LBL_OMIT_URL' => '(Omit http:// or https://)', + 'LBL_OAUTH_SAVE_NOTICE' => 'Click Save to create the external account record. You will be directed to a page to enter your account information to authorize access by Sugar. After entering your account information, you will be directed back to Sugar.', + 'LBL_BASIC_SAVE_NOTICE' => 'Click Save to create the external account record. Sugar will then validate your credentials.', + 'LBL_ERR_FACEBOOK' => 'Facebook returned an error, and the feed cannot be displayed.', + 'LBL_ERR_NO_RESPONSE' => 'An error occurred when trying to save to the external account.', + 'LBL_ERR_TWITTER' => 'Twitter returned an error, and the feed cannot be displayed.', +); diff --git a/modules/EAPM/metadata/SearchFields.php b/modules/EAPM/metadata/SearchFields.php new file mode 100644 index 00000000..33d00d8b --- /dev/null +++ b/modules/EAPM/metadata/SearchFields.php @@ -0,0 +1,57 @@ + array( 'query_type'=>'default'), + 'name' => array( 'query_type'=>'default'), + 'application' => array( 'query_type'=>'application'), + 'active' => array( 'query_type'=>'default'), + 'validated' => array( 'query_type'=>'default'), + 'current_user_only'=> array('query_type'=>'default','db_field'=>array('assigned_user_id'),'my_items'=>true, 'vname' => 'LBL_CURRENT_USER_FILTER', 'type' => 'bool'), + 'assigned_user_id'=> array('query_type'=>'default'), + 'favorites_only' => array( + 'query_type'=>'format', + 'operator' => 'subquery', + 'subquery' => 'SELECT sugarfavorites.record_id FROM sugarfavorites + WHERE sugarfavorites.deleted=0 + and sugarfavorites.module = "'.$module_name.'" + and sugarfavorites.assigned_user_id = "{0}"', + 'db_field'=>array('id')), + ); +?> diff --git a/modules/EAPM/metadata/detailviewdefs.php b/modules/EAPM/metadata/detailviewdefs.php new file mode 100644 index 00000000..1c9b7900 --- /dev/null +++ b/modules/EAPM/metadata/detailviewdefs.php @@ -0,0 +1,85 @@ + array('maxColumns' => '2', + 'widths' => array( + array('label' => '10', 'field' => '30'), + array('label' => '10', 'field' => '30') + ), + 'form' => array( + 'buttons' => + array ( + 0 => 'EDIT', + array('customCode'=>''), + array ('customCode' => '{if $bean->aclAccess("delete")}{/if}'), + ), + 'footerTpl'=>'modules/EAPM/tpls/DetailViewFooter.tpl',), + ), + +'panels' =>array ( + array('application'), + array ( + 'name', + ), + array ( + 'active', 'validated' + ), + array ( + 'url' + ), + + + array ( + array ( + 'name' => 'date_entered', + 'customCode' => '{$fields.date_entered.value} {$APP.LBL_BY} {$fields.created_by_name.value}', + 'label' => 'LBL_DATE_ENTERED', + ), + array ( + 'name' => 'date_modified', + 'customCode' => '{$fields.date_modified.value} {$APP.LBL_BY} {$fields.modified_by_name.value}', + 'label' => 'LBL_DATE_MODIFIED', + ), + ), + + array ( + 'description', + ), +) +); +?> diff --git a/modules/EAPM/metadata/editviewdefs.php b/modules/EAPM/metadata/editviewdefs.php new file mode 100644 index 00000000..a35386c5 --- /dev/null +++ b/modules/EAPM/metadata/editviewdefs.php @@ -0,0 +1,84 @@ + array('maxColumns' => '2', + 'widths' => array( + array('label' => '10', 'field' => '30'), + array('label' => '10', 'field' => '30') + ), + 'form' => array( + 'hidden'=>array(''), + 'buttons' => + array ( + 0 => 'SAVE', + array ( + 'customCode' => '', + ), + ), + 'headerTpl'=>'modules/EAPM/tpls/EditViewHeader.tpl', + 'footerTpl'=>'modules/EAPM/tpls/EditViewFooter.tpl',), + ), + + 'panels' =>array ( + 'default' => + array ( + array( + array( + 'name' => 'application', + 'displayParams'=>array('required'=>true) + ), 'active', + ), + array ( + array('name' => 'name', 'displayParams' => array('required' => true) ), + array('name'=>'password', 'type'=>'password', 'displayParams' => array('required' => true) ), + ), + array ( + array('name' => 'url', + 'displayParams' => array('required' => true), + 'customCode' => '
    {$MOD.LBL_OMIT_URL}', + ) + ), + array ( + 'description', + ), + ), + +), + +); +?> diff --git a/modules/EAPM/metadata/listviewdefs.php b/modules/EAPM/metadata/listviewdefs.php new file mode 100644 index 00000000..d519c1ce --- /dev/null +++ b/modules/EAPM/metadata/listviewdefs.php @@ -0,0 +1,69 @@ + array( + 'width' => '32', + 'label' => 'LBL_NAME', + 'default' => true, + 'link' => true, + ), + 'APPLICATION' => array( + 'width' => '40', + 'label' => 'LBL_APPLICATION', + 'default' => true), + 'ACTIVE' => array( + 'width' => '10', + 'label' => 'LBL_ACTIVE', + 'default' => true), + 'VALIDATED' => array( + 'width' => '10', + 'label' => 'LBL_VALIDATED', + 'default' => true), + 'ASSIGNED_USER_NAME' => array( + 'width' => '9', + 'label' => 'LBL_ASSIGNED_TO_NAME', + 'module' => 'Employees', + 'id' => 'ASSIGNED_USER_ID', + 'default' => true), + +); +?> diff --git a/modules/EAPM/metadata/metafiles.php b/modules/EAPM/metadata/metafiles.php new file mode 100644 index 00000000..a8423690 --- /dev/null +++ b/modules/EAPM/metadata/metafiles.php @@ -0,0 +1,52 @@ + 'modules/' . $module_name . '/metadata/detailviewdefs.php', + 'editviewdefs' => 'modules/' . $module_name . '/metadata/editviewdefs.php', + 'listviewdefs' => 'modules/' . $module_name . '/metadata/listviewdefs.php', + 'searchdefs' => 'modules/' . $module_name . '/metadata/searchdefs.php', + 'popupdefs' => 'modules/' . $module_name . '/metadata/popupdefs.php', + 'searchfields' => 'modules/' . $module_name . '/metadata/SearchFields.php', + ); +?> diff --git a/modules/EAPM/metadata/popupdefs.php b/modules/EAPM/metadata/popupdefs.php new file mode 100644 index 00000000..a77e619f --- /dev/null +++ b/modules/EAPM/metadata/popupdefs.php @@ -0,0 +1,52 @@ + $module_name, + 'varName' => $object_name, + 'orderBy' => $_module_name.'.name', + 'whereClauses' => + array('name' => $_module_name . '.name', + ), + 'searchInputs'=> array($_module_name. '_number', 'name', 'priority','status'), + + ); +?> + + diff --git a/modules/EAPM/metadata/quickcreatedefs.php b/modules/EAPM/metadata/quickcreatedefs.php new file mode 100644 index 00000000..aceadb7d --- /dev/null +++ b/modules/EAPM/metadata/quickcreatedefs.php @@ -0,0 +1,64 @@ + array('maxColumns' => '2', + 'widths' => array( + array('label' => '10', 'field' => '30'), + array('label' => '10', 'field' => '30') + ), + ), + + + 'panels' =>array ( + 'default' => + array ( + + array ( + 'name', + 'assigned_user_name', + ), + array ( + 'description', + array('name'=>'team_name', 'displayParams'=>array('display'=>true)), + ), + ), + +), + +); +?> diff --git a/modules/EAPM/metadata/searchdefs.php b/modules/EAPM/metadata/searchdefs.php new file mode 100644 index 00000000..5d24623e --- /dev/null +++ b/modules/EAPM/metadata/searchdefs.php @@ -0,0 +1,62 @@ + array( + 'maxColumns' => '3', + 'widths' => array('label' => '10', 'field' => '30'), + ), + 'layout' => array( + 'basic_search' => array( + 'name', + array('name'=>'current_user_only', 'label'=>'LBL_CURRENT_USER_FILTER', 'type'=>'bool'), + array ('name' => 'favorites_only','label' => 'LBL_FAVORITES_FILTER','type' => 'bool',), + ), + 'advanced_search' => array( + 'name', 'type', 'active', 'validated', + array('name' => 'assigned_user_id', 'label' => 'LBL_ASSIGNED_TO', 'type' => 'enum', 'function' => array('name' => 'get_user_array', 'params' => array(false))), + array ('name' => 'favorites_only','label' => 'LBL_FAVORITES_FILTER','type' => 'bool',), + ), + ), + ); +?> diff --git a/modules/EAPM/metadata/subpanels/default.php b/modules/EAPM/metadata/subpanels/default.php new file mode 100644 index 00000000..5bbf56e4 --- /dev/null +++ b/modules/EAPM/metadata/subpanels/default.php @@ -0,0 +1,77 @@ + array( + array('widget_class' => 'SubPanelTopCreateButton'), + ), + + 'where' => '', + + 'list_fields' => array( + 'name'=>array( + 'vname' => 'LBL_NAME', + 'widget_class' => 'SubPanelDetailViewLink', + 'width' => '25%', + ), + 'application'=>array( + 'vname' => 'LBL_APPLICATION', + 'width' => '20%', + ), + 'active'=>array( + 'vname' => 'LBL_ACTIVE', + 'width' => '5%', + ), + 'validated'=>array( + 'vname' => 'LBL_VALIDATED', + 'width' => '5%', + ), + 'date_modified'=>array( + 'vname' => 'LBL_DATE_MODIFIED', + 'width' => '20%', + ), + 'edit_button'=>array( + 'widget_class' => 'SubPanelEditButton', + 'module' => $module_name, + 'width' => '4%', + ), + ), +); + +?> diff --git a/modules/EAPM/tpls/DetailViewFooter.tpl b/modules/EAPM/tpls/DetailViewFooter.tpl new file mode 100644 index 00000000..7514feb6 --- /dev/null +++ b/modules/EAPM/tpls/DetailViewFooter.tpl @@ -0,0 +1,44 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} + + + + \ No newline at end of file diff --git a/modules/EAPM/tpls/EditViewFooter.tpl b/modules/EAPM/tpls/EditViewFooter.tpl new file mode 100644 index 00000000..c0a88931 --- /dev/null +++ b/modules/EAPM/tpls/EditViewFooter.tpl @@ -0,0 +1,50 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} + + + + \ No newline at end of file diff --git a/modules/EAPM/tpls/EditViewHeader.tpl b/modules/EAPM/tpls/EditViewHeader.tpl new file mode 100644 index 00000000..197fb713 --- /dev/null +++ b/modules/EAPM/tpls/EditViewHeader.tpl @@ -0,0 +1,76 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} + +
     

    +
    +
    {sugar_translate module="DynamicFields" label="COLUMN_TITLE_NAME"}: +{if $hideLevel == 0} + parent_name +{else} + {$vardef.name}{/if} + +
    {sugar_translate module="DynamicFields" label="COLUMN_TITLE_LABEL"}: + {if $hideLevel < 5} + + {else} + {$vardef.vname} + {/if} +
    {sugar_translate module="DynamicFields" label="COLUMN_TITLE_LABEL_VALUE"}: + +
    {sugar_translate module="DynamicFields" label="COLUMN_TITLE_HELP_TEXT"}: + {if $hideLevel < 5 } + + {else} + {$vardef.help} + {/if} +
    {sugar_translate module="DynamicFields" label="COLUMN_TITLE_DEFAULT_VALUE"}: + {if $hideLevel < 5} + + {else} + {$vardef.default} + {/if} +
    {sugar_translate module="DynamicFields" label="COLUMN_TITLE_MAX_SIZE"}: + {if $hideLevel < 5} + + + {if $action=="saveSugarField"} + + {/if} + {literal} + + {/literal} + {else} + {$vardef.len} + {/if} +
    {sugar_translate module="DynamicFields" label="LBL_MODULE"}: + {if $hideLevel == 0} + {html_options name="ext2" id="ext2" selected=$vardef.module options=$modules} + {else} + {$vardef.module} + {/if} + +
    {sugar_translate module="DynamicFields" label="COLUMN_TITLE_LABEL_ROWS"}: + {if $hideLevel < 4} + + {else} + {$vardef.rows} + {/if} +
    {sugar_translate module="DynamicFields" label="COLUMN_TITLE_LABEL_COLS"}: + {if $hideLevel < 4} + + {else} + {$vardef.cols} + {/if} +
    {sugar_translate module="DynamicFields" label="COLUMN_TITLE_DEFAULT_VALUE"}: + {if $hideLevel < 5} + + {else} + + + {/if} +
    {sugar_translate module="DynamicFields" label="LBL_GENERATE_URL"}: + {if $hideLevel < 5} + + {else} + + {/if} +
    {html_options name="flo" id="fieldListOptions" options=$fieldOpts} +
    {sugar_translate module="DynamicFields" label="COLUMN_TITLE_DEFAULT_VALUE"}: + {if $hideLevel < 5} + + {else} + {$vardef.default} + {/if} +
    {sugar_translate module="DynamicFields" label="COLUMN_TITLE_MAX_SIZE"}: + {if $hideLevel < 5} + + {literal} + + {/literal} + {else} + {$vardef.len} + {/if} +
    {sugar_translate module="DynamicFields" label="LBL_LINK_TARGET"}: + {if $hideLevel < 5} + + {else} + + + {/if} +
    {sugar_translate module="DynamicFields" label="COLUMN_TITLE_DEFAULT_VALUE"}: + {if $hideLevel < 5} + + {else} + {$vardef.default} + {/if} +
    {sugar_translate module="DynamicFields" label="COLUMN_TITLE_MAX_SIZE"}: + {if $hideLevel < 5} + + + {if $action=="saveSugarField"} + + {/if} + {literal} + + {/literal} + {else} + {$vardef.len} + {/if} +
    + + + + +
    + + + + + + + + + + + + + + +{{if empty($form.button_location) || $form.button_location == 'top'}} +{{if !empty($form) && !empty($form.buttons)}} + {{foreach from=$form.buttons key=val item=button}} + {{sugar_button module="$module" id="$button" view="$view"}} + {{/foreach}} +{{else}} +{{sugar_button module="$module" id="SAVE" view="$view"}} +{{sugar_button module="$module" id="CANCEL" view="$view"}} +{{/if}} +{{if empty($form.hideAudit) || !$form.hideAudit}} +{{sugar_button module="$module" id="Audit" view="$view"}} +{{/if}} +{{/if}} + + +
    'eapm', + 'audited'=>true, + 'fields'=>array ( + 'password' => + array ( + 'required' => true, + 'name' => 'password', + 'vname' => 'LBL_PASSWORD', + 'type' => 'encrypt', + 'dbtype' => 'varchar', + 'massupdate' => 0, + 'comments' => '', + 'help' => '', + 'importable' => 'true', + 'duplicate_merge' => 'disabled', + 'duplicate_merge_dom_value' => '0', + 'audited' => false, + 'reportable' => false, + 'len' => '255', + 'size' => '20', + ), + 'url' => + array ( + 'required' => true, + 'name' => 'url', + 'vname' => 'LBL_URL', + 'type' => 'varchar', + 'massupdate' => 0, + 'comments' => '', + 'help' => '', + 'importable' => 'true', + 'duplicate_merge' => 'disabled', + 'duplicate_merge_dom_value' => '0', + 'audited' => false, + 'reportable' => true, + 'len' => '255', + 'size' => '20', + ), + 'application' => + array ( + 'required' => true, + 'name' => 'application', + 'vname' => 'LBL_APPLICATION', + 'type' => 'enum', + 'massupdate' => 0, + 'comments' => '', + 'help' => '', + 'importable' => 'true', + 'duplicate_merge' => 'disabled', + 'duplicate_merge_dom_value' => '0', + 'audited' => false, + 'reportable' => true, + 'len' => 100, + 'size' => '20', + 'function' => 'getEAPMExternalApiDropDown', + 'studio' => 'visible', + 'default' => 'webex', + ), + 'name' => + array ( + 'name' => 'name', + 'vname' => 'LBL_NAME', + 'type' => 'name', + 'dbType' => 'varchar', + 'len' => '255', + 'unified_search' => true, +// 'required' => true, + 'importable' => 'required', + 'massupdate' => 0, + 'comments' => '', + 'help' => '', + 'duplicate_merge' => 'disabled', + 'duplicate_merge_dom_value' => '0', + 'audited' => false, + 'reportable' => true, + 'size' => '20', + ), + 'api_data' => + array ( + 'name' => 'api_data', + 'vname' => 'LBL_API_DATA', + 'type' => 'text', + 'comment' => 'Any API data that the external API may wish to store on a per-user basis', + 'rows' => 6, + 'cols' => 80, + ), + 'consumer_key' => array( + 'name' => 'consumer_key', + 'type' => 'varchar', + 'vname' => 'LBL_API_CONSKEY', +// 'required' => true, + 'importable' => 'required', + 'massupdate' => 0, + 'audited' => false, + 'reportable' => false, + 'studio' => 'hidden', + ), + 'consumer_secret' => array( + 'name' => 'consumer_secret', + 'type' => 'varchar', + 'vname' => 'LBL_API_CONSSECRET', +// 'required' => true, + 'importable' => 'required', + 'massupdate' => 0, + 'audited' => false, + 'reportable' => false, + 'studio' => 'hidden', + ), + 'oauth_token' => array( + 'name' => 'oauth_token', + 'type' => 'varchar', + 'vname' => 'LBL_API_OAUTHTOKEN', + 'importable' => false, + 'massupdate' => 0, + 'audited' => false, + 'reportable' => false, + 'required' => false, + 'dbtype' => 'varchar', + 'studio' => 'hidden', + ), + 'oauth_secret' => array( + 'name' => 'oauth_secret', + 'type' => 'varchar', + 'vname' => 'LBL_API_OAUTHSECRET', + 'importable' => false, + 'massupdate' => 0, + 'audited' => false, + 'reportable' => false, + 'required' => false, + 'dbtype' => 'varchar', + 'studio' => 'hidden', + ), + 'validated' => array( + 'required' => false, + 'name' => 'validated', + 'vname' => 'LBL_VALIDATED', + 'type' => 'bool', + 'default' => false, + ), + 'active' => array( + 'required' => false, + 'name' => 'active', + 'vname' => 'LBL_ACTIVE', + 'type' => 'bool', + 'default' => true, + ), + +), + 'relationships'=>array ( + ), + 'indices' => array( + array( + 'name' => 'idx_app_active', + 'type' => 'index', + 'fields'=> array('assigned_user_id', 'application', 'active'), + ), +), + 'optimistic_locking'=>true, +); +if (!class_exists('VardefManager')){ + require_once('include/SugarObjects/VardefManager.php'); +} +VardefManager::createVardef('EAPM','EAPM', array('basic','assignable')); diff --git a/modules/EAPM/views/view.detail.php b/modules/EAPM/views/view.detail.php new file mode 100644 index 00000000..d73f8fa1 --- /dev/null +++ b/modules/EAPM/views/view.detail.php @@ -0,0 +1,111 @@ +id; + $returnName = $GLOBALS['current_user']->full_name; + if(!empty($_REQUEST['return_action']) && !empty($_REQUEST['return_module'])){ + if('Users' == $_REQUEST['return_module']){ + if('EditView' == $_REQUEST['return_action']){ + $returnAction = 'EditView'; + } + if(!empty($_REQUEST['return_name'])){ + $returnName = $_REQUEST['return_name']; + } + if(!empty($_REQUEST['user_id'])){ + $returnId = $_REQUEST['user_id']; + } + } + } + + $this->_returnId = $returnId; + + $iconPath = $this->getModuleTitleIconPath($this->module); + $params = array(); + if (!empty($iconPath) && !$browserTitle) { + $params[] = "".translate("; + } + else { + $params[] = translate('LBL_MODULE_NAME','Users'); + } + $params[] = "".$returnName.""; + if($returnAction == 'EditView'){ + $params[] = $GLOBALS['app_strings']['LBL_EDIT_BUTTON_LABEL']; + } + return $params; + } + + /** + * @see SugarView::getModuleTitleIconPath() + */ + protected function getModuleTitleIconPath($module) + { + return parent::getModuleTitleIconPath('Users'); + } + + function display(){ + $this->ss->assign('return_id', $this->_returnId); + if($GLOBALS['current_user']->is_admin || empty($this->bean) || empty($this->bean->id) || $this->bean->isOwner($GLOBALS['current_user']->id)){ + parent::display(); + } else { + ACLController::displayNoAccess(); + } + } +} + +?> \ No newline at end of file diff --git a/modules/EAPM/views/view.edit.php b/modules/EAPM/views/view.edit.php new file mode 100644 index 00000000..fe4af196 --- /dev/null +++ b/modules/EAPM/views/view.edit.php @@ -0,0 +1,121 @@ +id; + $returnName = $GLOBALS['current_user']->full_name; + if(!empty($_REQUEST['return_action']) && !empty($_REQUEST['return_module'])){ + if('Users' == $_REQUEST['return_module']){ + if('EditView' == $_REQUEST['return_action']){ + $returnAction = 'EditView'; + } + if(!empty($_REQUEST['return_name'])){ + $returnName = $_REQUEST['return_name']; + } + if(!empty($_REQUEST['user_id'])){ + $returnId = $_REQUEST['user_id']; + } + } + } + $this->_returnId = $returnId; + + $iconPath = $this->getModuleTitleIconPath($this->module); + $params = array(); + if (!empty($iconPath) && !$browserTitle) { + $params[] = "".translate("; + } + else { + $params[] = translate('LBL_MODULE_NAME','Users'); + } + $params[] = "".$returnName.""; + $params[] = $GLOBALS['app_strings']['LBL_EDIT_BUTTON_LABEL']; + + return $params; + } + + /** + * @see SugarView::getModuleTitleIconPath() + */ + protected function getModuleTitleIconPath($module) + { + return parent::getModuleTitleIconPath('Users'); + } + + function display() { + $this->ss->assign('return_id', $this->_returnId); + + if($GLOBALS['current_user']->is_admin || empty($this->bean) || empty($this->bean->id) || $this->bean->isOwner($GLOBALS['current_user']->id)){ + if(!empty($this->bean) && empty($this->bean->id) && $this->_returnId != $GLOBALS['current_user']->id){ + $this->bean->assigned_user_id = $this->_returnId; + } + + parent::display(); + } else { + ACLController::displayNoAccess(); + } + } +} +?> \ No newline at end of file diff --git a/modules/EmailAddresses/EmailAddress.php b/modules/EmailAddresses/EmailAddress.php new file mode 100644 index 00000000..ce1569b9 --- /dev/null +++ b/modules/EmailAddresses/EmailAddress.php @@ -0,0 +1,68 @@ + 1 ) { + parent::save($id, $module, $new_addrs, $primary, $replyTo, $invalid, $optOut, $in_workflow); + } + else { + SugarBean::save($id); + } + } +} \ No newline at end of file diff --git a/modules/EmailAddresses/language/en_us.lang.php b/modules/EmailAddresses/language/en_us.lang.php new file mode 100644 index 00000000..f65c461e --- /dev/null +++ b/modules/EmailAddresses/language/en_us.lang.php @@ -0,0 +1,55 @@ + 'ID', + 'LBL_EMAIL_ADDRESS' => 'Email Address', + 'LBL_EMAIL_ADDRESS_CAPS' => 'Email Address caps', + 'LBL_INVALID_EMAIL' => 'Invalid Email', + 'LBL_OPT_OUT' => 'Opted Out', + 'LBL_DATE_CREATE' => 'Date Create', + 'LBL_DATE_MODIFIED' => 'Date Modified', + 'LBL_DELETED' => 'Delete', +); diff --git a/modules/EmailAddresses/vardefs.php b/modules/EmailAddresses/vardefs.php new file mode 100644 index 00000000..229814b6 --- /dev/null +++ b/modules/EmailAddresses/vardefs.php @@ -0,0 +1,59 @@ +id ,user_id= $this->user_id module = $this->module , related_id = $this->related_id , related_type = $this->related_type ,list_id = $this->list_id, send_date_time= $this->send_date_time\n"; + } + + // This is used to retrieve related fields from form posts. + var $additional_column_fields = array(); + + function EmailMan() { + parent::SugarBean(); + + } + + var $new_schema = true; + + function create_new_list_query($order_by, $where,$filter=array(),$params=array(), $show_deleted = 0,$join_type='', $return_array = false,$parentbean=null, $singleSelect = false) { + $query = array('select' => '', 'from' => '', 'where' => '', 'order_by' => ''); + + + + if ( ( $this->db->dbType == 'mysql' ) or ( $this->db->dbType == 'oci8' ) ) + { + + $query['select'] = "SELECT $this->table_name.* , + campaigns.name as campaign_name, + email_marketing.name as message_name, + (CASE related_type + WHEN 'Contacts' THEN CONCAT(CONCAT(contacts.first_name, ' ' ), contacts.last_name) + WHEN 'Leads' THEN CONCAT(CONCAT(leads.first_name, ' ' ), leads.last_name) + WHEN 'Accounts' THEN accounts.name + WHEN 'Users' THEN CONCAT(CONCAT(users.first_name, ' ' ), users.last_name) + WHEN 'Prospects' THEN CONCAT(CONCAT(prospects.first_name, ' ' ), prospects.last_name) + END) recipient_name"; + } + if($this->db->dbType == 'mssql') + { + $query['select'] = "SELECT $this->table_name.* , + campaigns.name as campaign_name, + email_marketing.name as message_name, + (CASE related_type + WHEN 'Contacts' THEN contacts.first_name + ' ' + contacts.last_name + WHEN 'Leads' THEN leads.first_name + ' ' + leads.last_name + WHEN 'Accounts' THEN accounts.name + WHEN 'Users' THEN users.first_name + ' ' + users.last_name + WHEN 'Prospects' THEN prospects.first_name + ' ' + prospects.last_name + END) recipient_name"; + } + + $query['from'] = " FROM $this->table_name + LEFT JOIN users ON users.id = $this->table_name.related_id and $this->table_name.related_type ='Users' + LEFT JOIN contacts ON contacts.id = $this->table_name.related_id and $this->table_name.related_type ='Contacts' + LEFT JOIN leads ON leads.id = $this->table_name.related_id and $this->table_name.related_type ='Leads' + LEFT JOIN accounts ON accounts.id = $this->table_name.related_id and $this->table_name.related_type ='Accounts' + LEFT JOIN prospects ON prospects.id = $this->table_name.related_id and $this->table_name.related_type ='Prospects' + LEFT JOIN prospect_lists ON prospect_lists.id = $this->table_name.list_id + LEFT JOIN email_addr_bean_rel ON email_addr_bean_rel.bean_id = $this->table_name.related_id and $this->table_name.related_type = email_addr_bean_rel.bean_module and email_addr_bean_rel.deleted=0 + LEFT JOIN campaigns ON campaigns.id = $this->table_name.campaign_id + LEFT JOIN email_marketing ON email_marketing.id = $this->table_name.marketing_id "; + + $where_auto = " $this->table_name.deleted=0"; + + if($where != "") + $query['where'] = "WHERE $where AND ".$where_auto; + else + $query['where'] = "WHERE ".$where_auto; + + if(isset($params['group_by'])) { + $query['order_by'] .= " GROUP BY {$params['group_by']}"; + } + + if($order_by != "") + { + $query['order_by'] = ' ORDER BY ' . $this->process_order_by($order_by, null); + } + + if ($return_array) { + return $query; + } + + return $query['select'] . $query['from'] . $query['where']. $query['order_by']; + + } // if + + function create_queue_items_query($order_by, $where,$filter=array(),$params=array(), $show_deleted = 0,$join_type='', $return_array = false,$parentbean=null, $singleSelect = false) { + + if ($return_array) { + return parent::create_new_list_query($order_by, $where,$filter,$params, $show_deleted,$join_type, $return_array,$parentbean, $singleSelect); + } + + if ( ( $this->db->dbType == 'mysql' ) or ( $this->db->dbType == 'oci8' ) ) + { + + $query = "SELECT $this->table_name.* , + campaigns.name as campaign_name, + email_marketing.name as message_name, + (CASE related_type + WHEN 'Contacts' THEN CONCAT(CONCAT(contacts.first_name, ' ' ), contacts.last_name) + WHEN 'Leads' THEN CONCAT(CONCAT(leads.first_name, ' ' ), leads.last_name) + WHEN 'Accounts' THEN accounts.name + WHEN 'Users' THEN CONCAT(CONCAT(users.first_name, ' ' ), users.last_name) + WHEN 'Prospects' THEN CONCAT(CONCAT(prospects.first_name, ' ' ), prospects.last_name) + END) recipient_name"; + } + if($this->db->dbType == 'mssql') + { + $query = "SELECT $this->table_name.* , + campaigns.name as campaign_name, + email_marketing.name as message_name, + (CASE related_type + WHEN 'Contacts' THEN contacts.first_name + ' ' + contacts.last_name + WHEN 'Leads' THEN leads.first_name + ' ' + leads.last_name + WHEN 'Accounts' THEN accounts.name + WHEN 'Users' THEN users.first_name + ' ' + users.last_name + WHEN 'Prospects' THEN prospects.first_name + ' ' + prospects.last_name + END) recipient_name"; + } + + $query .= " FROM $this->table_name + LEFT JOIN users ON users.id = $this->table_name.related_id and $this->table_name.related_type ='Users' + LEFT JOIN contacts ON contacts.id = $this->table_name.related_id and $this->table_name.related_type ='Contacts' + LEFT JOIN leads ON leads.id = $this->table_name.related_id and $this->table_name.related_type ='Leads' + LEFT JOIN accounts ON accounts.id = $this->table_name.related_id and $this->table_name.related_type ='Accounts' + LEFT JOIN prospects ON prospects.id = $this->table_name.related_id and $this->table_name.related_type ='Prospects' + LEFT JOIN prospect_lists ON prospect_lists.id = $this->table_name.list_id + LEFT JOIN email_addr_bean_rel ON email_addr_bean_rel.bean_id = $this->table_name.related_id and $this->table_name.related_type = email_addr_bean_rel.bean_module and email_addr_bean_rel.deleted=0 + LEFT JOIN campaigns ON campaigns.id = $this->table_name.campaign_id + LEFT JOIN email_marketing ON email_marketing.id = $this->table_name.marketing_id "; + + //B.F. #37943 + if( isset($params['group_by']) ) + { + $group_by = str_replace("emailman", "em", $params['group_by']); + $query .= "INNER JOIN (select min(id) as id from emailman em GROUP BY $group_by ) secondary + on {$this->table_name}.id = secondary.id "; + } + + $where_auto = " $this->table_name.deleted=0"; + + if($where != "") + $query .= "WHERE $where AND ".$where_auto; + else + $query .= "WHERE ".$where_auto; + + + if($order_by != "") + { + $query .= ' ORDER BY ' . $this->process_order_by($order_by, null); + } + + return $query; + + } + + function create_list_query($order_by, $where, $show_deleted = 0){ + + if ( ( $this->db->dbType == 'mysql' ) or ( $this->db->dbType == 'oci8' ) ) + { + + $query = "SELECT $this->table_name.* , + campaigns.name as campaign_name, + email_marketing.name as message_name, + (CASE related_type + WHEN 'Contacts' THEN CONCAT(CONCAT(contacts.first_name, ' ' ), contacts.last_name) + WHEN 'Leads' THEN CONCAT(CONCAT(leads.first_name, ' ' ), leads.last_name) + WHEN 'Accounts' THEN accounts.name + WHEN 'Users' THEN CONCAT(CONCAT(users.first_name, ' ' ), users.last_name) + WHEN 'Prospects' THEN CONCAT(CONCAT(prospects.first_name, ' ' ), prospects.last_name) + END) recipient_name"; + } + if($this->db->dbType == 'mssql') + { + $query = "SELECT $this->table_name.* , + campaigns.name as campaign_name, + email_marketing.name as message_name, + (CASE related_type + WHEN 'Contacts' THEN contacts.first_name + ' ' + contacts.last_name + WHEN 'Leads' THEN leads.first_name + ' ' + leads.last_name + WHEN 'Accounts' THEN accounts.name + WHEN 'Users' THEN users.first_name + ' ' + users.last_name + WHEN 'Prospects' THEN prospects.first_name + ' ' + prospects.last_name + END) recipient_name"; + } + + $query .= " FROM $this->table_name + LEFT JOIN users ON users.id = $this->table_name.related_id and $this->table_name.related_type ='Users' + LEFT JOIN contacts ON contacts.id = $this->table_name.related_id and $this->table_name.related_type ='Contacts' + LEFT JOIN leads ON leads.id = $this->table_name.related_id and $this->table_name.related_type ='Leads' + LEFT JOIN accounts ON accounts.id = $this->table_name.related_id and $this->table_name.related_type ='Accounts' + LEFT JOIN prospects ON prospects.id = $this->table_name.related_id and $this->table_name.related_type ='Prospects' + LEFT JOIN prospect_lists ON prospect_lists.id = $this->table_name.list_id + LEFT JOIN email_addr_bean_rel ON email_addr_bean_rel.bean_id = $this->table_name.related_id and $this->table_name.related_type = email_addr_bean_rel.bean_module and email_addr_bean_rel.deleted=0 + LEFT JOIN campaigns ON campaigns.id = $this->table_name.campaign_id + LEFT JOIN email_marketing ON email_marketing.id = $this->table_name.marketing_id "; + + $where_auto = " $this->table_name.deleted=0"; + + if($where != "") + $query .= "where $where AND ".$where_auto; + else + $query .= "where ".$where_auto; + + if($order_by != "") + { + $query .= ' ORDER BY ' . $this->process_order_by($order_by, null); + } + return $query; + } + + function get_list_view_data() + { + global $locale, $current_user; + $temp_array = parent::get_list_view_array(); + + $related_type = $temp_array['RELATED_TYPE']; + $related_id = $temp_array['RELATED_ID']; + $is_person = SugarModule::get($related_type)->moduleImplements('Person'); + + if($is_person) + { + $query = "SELECT first_name, last_name FROM ". strtolower($related_type) ." WHERE id ='". $related_id ."'"; + } else { + $query = "SELECT name FROM ". strtolower($related_type) ." WHERE id ='". $related_id ."'"; + } + + $result=$this->db->query($query); + $row=$this->db->fetchByAssoc($result); + + if($row) + { + $temp_array['RECIPIENT_NAME'] = $is_person ? $locale->getLocaleFormattedName($row['first_name'], $row['last_name'], '') : $row['name']; + } + + //also store the recipient_email address + $query = "SELECT addr.email_address FROM email_addresses addr,email_addr_bean_rel eb WHERE eb.deleted=0 AND addr.id=eb.email_address_id AND bean_id ='". $related_id ."' AND primary_address = '1'"; + + $result=$this->db->query($query); + $row=$this->db->fetchByAssoc($result); + if ($row) + { + $temp_array['RECIPIENT_EMAIL']=$row['email_address']; + } + + $this->email1 = $temp_array['RECIPIENT_EMAIL']; + $temp_array['EMAIL1_LINK'] = $current_user->getEmailLink('email1', $this, '', '', 'ListView'); + + return $temp_array; + } + + + function set_as_sent($email_address, $delete= true,$email_id=null, $email_type=null,$activity_type=null){ + + global $timedate; + + $this->send_attempts++; + if($delete || $this->send_attempts > 5){ + + //create new campaign log record. + + $campaign_log = new CampaignLog(); + $campaign_log->campaign_id=$this->campaign_id; + $campaign_log->target_tracker_key=$this->target_tracker_key; + $campaign_log->target_id= $this->related_id; + $campaign_log->target_type=$this->related_type; + $campaign_log->marketing_id=$this->marketing_id; + //if test suppress duplicate email address checking. + if (!$this->test) { + $campaign_log->more_information=$email_address; + } + $campaign_log->activity_type=$activity_type; + $campaign_log->activity_date=$timedate->now(); + $campaign_log->list_id=$this->list_id; + $campaign_log->related_id= $email_id; + $campaign_log->related_type=$email_type; + $campaign_log->save(); + + $query = "DELETE FROM emailman WHERE id = $this->id"; + $this->db->query($query); + }else{ + //try to send the email again a day later. + $query = 'UPDATE ' . $this->table_name . " SET in_queue='1', send_attempts='$this->send_attempts', in_queue_date='". TimeDate::getInstance()->nowDb() ."' WHERE id = '$this->id'"; + $this->db->query($query); + } + } + + /** + * Function finds the reference email for the campaign. Since a campaign can have multiple email templates + * the reference email has same id as the marketing id. + * this function will create an email if one does not exist. also the function will load these relationships leads, accounts, contacts + * users and targets + * + * @param varchar marketing_id message id + * @param string $subject email subject + * @param string $body_text Email Body Text + * @param string $body_html Email Body HTML + * @param string $campaign_name Campaign Name + * @param string from_address Email address of the sender, usually email address of the configured inbox. + * @param string sender_id If of the user sending the campaign. + * @param array macro_nv array of name value pair, one row for each replacable macro in email template text. + * @return + */ + function create_ref_email($marketing_id,$subject,$body_text,$body_html,$campagin_name,$from_address,$sender_id,$notes,$macro_nv,$newmessage) { + + global $mod_Strings, $timedate; + $upd_ref_email=false; + if ($newmessage or empty($this->ref_email->id)) { + $this->ref_email = new Email(); + $this->ref_email->retrieve($marketing_id, true, false); + + //the reference email should be updated when user swithces from test mode to regular mode,and, for every run in test mode, and is user + //switches back to test mode. + //this is to account for changes to email template. + $upd_ref_email=(!empty($this->ref_email->id) and $this->ref_email->parent_type=='test' and $this->ref_email->parent_id=='test'); + //following condition is for switching back to test mode. + if (!$upd_ref_email) $upd_ref_email=($this->test and !empty($this->ref_email->id) and empty($this->ref_email->parent_type) and empty($this->ref_email->parent_id)); + if (empty($this->ref_email->id) or $upd_ref_email) { + //create email record. + $this->ref_email->id=$marketing_id; + $this->ref_email->date_sent = ''; + + if ($upd_ref_email==false) { + $this->ref_email->new_with_id=true; + } + + $this->ref_email->to_addrs= ''; + $this->ref_email->to_addrs_ids = ''; + $this->ref_email->to_addrs_names = ''; + $this->ref_email->to_addrs_emails =''; + $this->ref_email->type= 'campaign'; + $this->ref_email->deleted = '0'; + $this->ref_email->name = $campagin_name.': '.$subject ; + $this->ref_email->description_html = $body_html; + $this->ref_email->description = $body_text; + $this->ref_email->from_addr = $from_address; + $this->ref_email->assigned_user_id = $sender_id; + if ($this->test) { + $this->ref_email->parent_type = 'test'; + $this->ref_email->parent_id = 'test'; + } else { + $this->ref_email->parent_type = ''; + $this->ref_email->parent_id = ''; + } + $this->ref_email->date_start = $timedate->nowDate(); + $this->ref_email->time_start = $timedate->asUserTime($timedate->getNow(true)); + + $this->ref_email->status='sent'; + $retId = $this->ref_email->save(); + + if (count($notes) > 0 ) { + if (!class_exists('Note')) + if (!class_exists('UploadFile')) require_once('include/upload_file.php'); + + } + + foreach($notes as $note) { + if($note->object_name == 'Note') { + if (! empty($note->file->temp_file_location) && is_file($note->file->temp_file_location)) { + $file_location = $note->file->temp_file_location; + $filename = $note->file->original_file_name; + $mime_type = $note->file->mime_type; + } else { + $file_location = rawurldecode(UploadFile::get_file_path($note->filename,$note->id)); + $filename = $note->id.$note->filename; + $mime_type = $note->file_mime_type; + } + } elseif($note->object_name == 'DocumentRevision') { // from Documents + $filename = $note->id.$note->filename; + $file_location = getcwd().'/'.$GLOBALS['sugar_config']['upload_dir'].$filename; + $mime_type = $note->file_mime_type; + } + + $noteAudit = new Note(); + $noteAudit->parent_id = $retId; + $noteAudit->parent_type = $this->ref_email->module_dir; + $noteAudit->description = "[".$note->filename."] ".$mod_strings['LBL_ATTACHMENT_AUDIT']; + $noteAudit->filename=$filename; + $noteAudit->file_mime_type=$mime_type; + $noteAudit_id=$noteAudit->save(); + + UploadFile::duplicate_file($note->id, $noteAudit_id, $filename); + } + } + + //load relationships. + $this->ref_email->load_relationship('users'); + $this->ref_email->load_relationship('prospects'); + $this->ref_email->load_relationship('contacts'); + $this->ref_email->load_relationship('leads'); + $this->ref_email->load_relationship('accounts'); + } + + if (!empty($this->related_id ) && !empty($this->related_type)) { + + //save relationships. + switch ($this->related_type) { + case 'Users': + $rel_name="users"; + break; + + case 'Prospects': + $rel_name="prospects"; + break; + + case 'Contacts': + $rel_name="contacts"; + break; + + case 'Leads': + $rel_name="leads"; + break; + + case 'Accounts': + $rel_name="accounts"; + break; + } + + //required for one email per campaign per marketing message. + $this->ref_email->$rel_name->add($this->related_id,array('campaign_data'=>serialize($macro_nv))); + } + return $this->ref_email->id; + } + + /** + * The function creates a copy of email send to each target. + */ + function create_indiv_email($module,$mail) { + + global $locale, $timedate; + $email = new Email(); + $email->to_addrs= $module->name . '<'.$module->email1.'>'; + $email->to_addrs_ids = $module->id .';'; + $email->to_addrs_names = $module->name . ';'; + $email->to_addrs_emails = $module->email1 . ';'; + $email->type= 'archived'; + $email->deleted = '0'; + $email->name = $this->current_campaign->name.': '.$mail->Subject ; + if ($mail->ContentType == "text/plain") { + $email->description = $mail->Body; + $email->description_html =null; + } else { + $email->description_html = $mail->Body; + $email->description = $mail->AltBody; + } + $email->from_addr = $mail->From; + $email->assigned_user_id = $this->user_id; + $email->parent_type = $this->related_type; + $email->parent_id = $this->related_id ; + + $email->date_start = $timedate->nowDbDate(); + $email->time_start = $timedate->asDbTime($timedate->getNow()); + $email->status='sent'; + $retId = $email->save(); + + foreach($this->notes_array as $note) { + if(!class_exists('Note')) { + + } + // create "audit" email without duping off the file to save on disk space + $noteAudit = new Note(); + $noteAudit->parent_id = $retId; + $noteAudit->parent_type = $email->module_dir; + $noteAudit->description = "[".$note->filename."] ".$mod_strings['LBL_ATTACHMENT_AUDIT']; + $noteAudit->save(); + } + + if (!empty($this->related_id ) && !empty($this->related_type)) { + + //save relationships. + switch ($this->related_type) { + case 'Users': + $rel_name="users"; + break; + + case 'Prospects': + $rel_name="prospects"; + break; + + case 'Contacts': + $rel_name="contacts"; + break; + + case 'Leads': + $rel_name="leads"; + break; + + case 'Accounts': + $rel_name="accounts"; + break; + } + + if (!empty($rel_name)) { + $email->load_relationship($rel_name); + $email->$rel_name->add($this->related_id); + } + } + return $email->id; + } + /* + * Call this function to verify the email_marketing message and email_template configured + * for the campaign. If issues are found a fatal error will be logged but processing will not stop. + * @return Boolean Returns true if all campaign parameters are set correctly + */ + function verify_campaign($marketing_id) { + + if (!isset($this->verified_email_marketing_ids[$marketing_id])) { + if (!class_exists('EmailMarketing')) { + + } + $email_marketing = new EmailMarketing(); + $ret=$email_marketing->retrieve($marketing_id); + if (empty($ret)) { + $GLOBALS['log']->fatal('Error retrieving marketing message for the email campaign. marketing_id = ' .$marketing_id); + return false; + } + + //verify the email template. + if (empty($email_marketing->template_id)) { + $GLOBALS['log']->fatal('Error retrieving template for the email campaign. marketing_id = ' .$marketing_id); + return false; + } + + if (!class_exists('EmailTemplate')) { + + } + $emailtemplate= new EmailTemplate(); + + $ret=$emailtemplate->retrieve($email_marketing->template_id); + if (empty($ret)) { + $GLOBALS['log']->fatal('Error retrieving template for the email campaign. template_id = ' .$email_marketing->template_id); + return false; + } + + if (empty($emailtemplate->subject) and empty($emailtemplate->body) and empty($emailtemplate->body_html)) { + $GLOBALS['log']->fatal('Email template is empty. email_template_id=' .$email_marketing->template_id); + return false; + } + + } + $this->verified_email_marketing_ids[$marketing_id]=1; + + return true; + } + function sendEmail($mail,$save_emails=1,$testmode=false){ + $this->test=$testmode; + + global $beanList, $beanFiles, $sugar_config; + global $mod_strings; + global $locale; + $OBCharset = $locale->getPrecedentPreference('default_email_charset'); + $mod_strings = return_module_language( $sugar_config['default_language'], 'EmailMan'); + + //get tracking entities locations. + if (!isset($this->tracking_url)) { + if (!class_exists('Administration')) { + + } + $admin=new Administration(); + $admin->retrieveSettings('massemailer'); //retrieve all admin settings. + if (isset($admin->settings['massemailer_tracking_entities_location_type']) and $admin->settings['massemailer_tracking_entities_location_type']=='2' and isset($admin->settings['massemailer_tracking_entities_location']) ) { + $this->tracking_url=$admin->settings['massemailer_tracking_entities_location']; + } else { + $this->tracking_url=$sugar_config['site_url']; + } + } + + //make sure tracking url ends with '/' character + $strLen = strlen($this->tracking_url); + if($this->tracking_url{$strLen-1} !='/'){ + $this->tracking_url .='/'; + } + + if(!isset($beanList[$this->related_type])){ + return false; + } + $class = $beanList[$this->related_type]; + if (!class_exists($class)) { + require_once($beanFiles[$class]); + } + + if (!class_exists('Email')) { + + } + + $module = new $class(); + $module->retrieve($this->related_id); + $module->emailAddress->handleLegacyRetrieve($module); + + //check to see if bean has a primary email address + if (!$this->is_primary_email_address($module)) { + //no primary email address designated, do not send out email, create campaign log + //of type send error to denote that this user was not emailed + $this->set_as_sent($module->email1, true,null,null,'send error'); + //create fatal logging for easy review of cause. + $GLOBALS['log']->fatal('Email Address provided is not Primary Address for email with id ' . $module->email1 . "' Emailman id=$this->id"); + return true; + } + + if (!$this->valid_email_address($module->email1)) { + $this->set_as_sent($module->email1, true,null,null,'invalid email'); + $GLOBALS['log']->fatal('Encountered invalid email address' . $module->email1 . " Emailman id=$this->id"); + return true; + } + + if ((!isset($module->email_opt_out) + || ($module->email_opt_out !== 'on' + && $module->email_opt_out !== 1 + && $module->email_opt_out !== '1')) + && (!isset($module->invalid_email) + || ($module->invalid_email !== 'on' + && $module->invalid_email !== 1 + && $module->invalid_email !== '1'))){ + $lower_email_address=strtolower($module->email1); + //test against indivdual address. + if (isset($this->restricted_addresses) and isset($this->restricted_addresses[$lower_email_address])) { + $this->set_as_sent($lower_email_address, true,null,null,'blocked'); + return true; + } + //test against restricted domains + $at_pos=strrpos($lower_email_address,'@'); + if ($at_pos !== false) { + foreach ($this->restricted_domains as $domain=>$value) { + $pos=strrpos($lower_email_address,$domain); + if ($pos !== false && $pos > $at_pos) { + //found + $this->set_as_sent($lower_email_address, true,null,null,'blocked'); + return true; + } + } + } + + //test for duplicate email address by marketing id. + $dup_query="select id from campaign_log where more_information='".$module->email1."' and marketing_id='".$this->marketing_id."'"; + $dup=$this->db->query($dup_query); + $dup_row=$this->db->fetchByAssoc($dup); + if (!empty($dup_row)) { + //we have seen this email address before + $this->set_as_sent($module->email1,true,null,null,'blocked'); + return true; + } + + $this->target_tracker_key=create_guid(); + + //fetch email marketing. + if (empty($this->current_emailmarketing) or !isset($this->current_emailmarketing)) { + if (!class_exists('EmailMarketing')) { + + } + + $this->current_emailmarketing=new EmailMarketing(); + + } + if (empty($this->current_emailmarketing->id) or $this->current_emailmarketing->id !== $this->marketing_id) { + $this->current_emailmarketing->retrieve($this->marketing_id); + + $this->newmessage = true; + } + //fetch email template associate with the marketing message. + if (empty($this->current_emailtemplate) or $this->current_emailtemplate->id !== $this->current_emailmarketing->template_id) { + if (!class_exists('EmailTemplate')) { + + } + $this->current_emailtemplate= new EmailTemplate(); + + $this->current_emailtemplate->retrieve($this->current_emailmarketing->template_id); + + //escape email template contents. + $this->current_emailtemplate->subject=from_html($this->current_emailtemplate->subject); + $this->current_emailtemplate->body_html=from_html($this->current_emailtemplate->body_html); + $this->current_emailtemplate->body=from_html($this->current_emailtemplate->body); + + $q = "SELECT * FROM notes WHERE parent_id = '".$this->current_emailtemplate->id."' AND deleted = 0"; + $r = $this->db->query($q); + + // cn: bug 4684 - initialize the notes array, else old data is still around for the next round + $this->notes_array = array(); + if (!class_exists('Note')){ + require_once('modules/Notes/Note.php'); + } + while($a = $this->db->fetchByAssoc($r)) { + $noteTemplate = new Note(); + $noteTemplate->retrieve($a['id']); + $this->notes_array[] = $noteTemplate; + } + } + + // fetch mailbox details.. + if(empty($this->current_mailbox)) { + if (!class_exists('InboundEmail')) { + + } + $this->current_mailbox= new InboundEmail(); + } + if (empty($this->current_mailbox->id) or $this->current_mailbox->id !== $this->current_emailmarketing->inbound_email_id) { + $this->current_mailbox->retrieve($this->current_emailmarketing->inbound_email_id); + //extract the email address. + $this->mailbox_from_addr=$this->current_mailbox->get_stored_options('from_addr','nobody@example.com',null); + } + + // fetch campaign details.. + if (empty($this->current_campaign)) { + if (!class_exists('Campaign')) { + + } + $this->current_campaign= new Campaign(); + } + if (empty($this->current_campaign->id) or $this->current_campaign->id !== $this->current_emailmarketing->campaign_id) { + $this->current_campaign->retrieve($this->current_emailmarketing->campaign_id); + + //load defined tracked_urls + $this->current_campaign->load_relationship('tracked_urls'); + $query_array=$this->current_campaign->tracked_urls->getQuery(true); + $query_array['select']="SELECT tracker_name, tracker_key, id, is_optout "; + $result=$this->current_campaign->db->query(implode(' ',$query_array)); + + $this->has_optout_links=false; + $this->tracker_urls=array(); + while (($row=$this->current_campaign->db->fetchByAssoc($result)) != null) { + $this->tracker_urls['{'.$row['tracker_name'].'}']=$row; + //has the user defined opt-out links for the campaign. + if ($row['is_optout']==1) { + $this->has_optout_links=true; + } + } + } + + $mail->ClearAllRecipients(); + $mail->ClearReplyTos(); + $mail->Sender = $this->mailbox_from_addr; + $mail->From = $this->mailbox_from_addr; + $mail->FromName = $this->current_emailmarketing->from_name; + $mail->ClearCustomHeaders(); + $mail->AddCustomHeader('X-CampTrackID:'.$this->target_tracker_key); + //CL - Bug 25256 Check if we have a reply_to_name/reply_to_addr value from the email marketing table. If so use email marketing entry; otherwise current mailbox (inbound email) entry + $replyToName = empty($this->current_emailmarketing->reply_to_name) ? $this->current_mailbox->get_stored_options('reply_to_name',$mail->FromName,null) : $this->current_emailmarketing->reply_to_name; + $replyToAddr = empty($this->current_emailmarketing->reply_to_addr) ? $this->current_mailbox->get_stored_options('reply_to_addr',$mail->From,null) : $this->current_emailmarketing->reply_to_addr; + + $mail->AddReplyTo($replyToAddr,$locale->translateCharsetMIME(trim($replyToName), 'UTF-8', $OBCharset)); + + //parse and replace bean variables. + $macro_nv=array(); + $template_data= $this->current_emailtemplate->parse_email_template(array('subject'=>$this->current_emailtemplate->subject, + 'body_html'=>$this->current_emailtemplate->body_html, + 'body'=>$this->current_emailtemplate->body, + ) + ,'Contacts', $module + ,$macro_nv); + + //add email address to this list. + $macro_nv['sugar_to_email_address']=$module->email1; + $macro_nv['email_template_id']=$this->current_emailmarketing->template_id; + + //parse and replace urls. + //this is new style of adding tracked urls to a campaign. + $tracker_url_template= $this->tracking_url . 'index.php?entryPoint=campaign_trackerv2&track=%s'.'&identifier='.$this->target_tracker_key; + $removeme_url_template=$this->tracking_url . 'index.php?entryPoint=removeme&identifier='.$this->target_tracker_key; + $template_data= $this->current_emailtemplate->parse_tracker_urls($template_data,$tracker_url_template,$this->tracker_urls,$removeme_url_template); + $mail->AddAddress($module->email1,$locale->translateCharsetMIME(trim($module->name), 'UTF-8', $OBCharset) ); + + //refetch strings in case they have been changed by creation of email templates or other beans. + $mod_strings = return_module_language( $sugar_config['default_language'], 'EmailMan'); + + if($this->test){ + $mail->Subject = $mod_strings['LBL_PREPEND_TEST'] . $template_data['subject']; + }else{ + $mail->Subject = $template_data['subject']; + } + + //check if this template is meant to be used as "text only" + $text_only = false; + if(isset($this->current_emailtemplate->text_only) && $this->current_emailtemplate->text_only){$text_only =true;} + //if this template is textonly, then just send text body. Do not add tracker, opt out, + //or perform other processing as it will not show up in text only email + if($text_only){ + $this->description_html = ''; + $mail->IsHTML(false); + $mail->Body = $template_data['body']; + + }else{ + $mail->Body = wordwrap($template_data['body_html'], 900); + //BEGIN:this code will trigger for only campaigns pending before upgrade to 4.2.0. + //will be removed for the next release. + if(!isset($btracker)) $btracker=false; + if ($btracker) { + $mail->Body .= "

    " . $tracker_text . "

    "; + } else { + if (!empty($tracker_url)) { + $mail->Body = str_replace('TRACKER_URL_START', "", $mail->Body); + $mail->Body = str_replace('TRACKER_URL_END', "", $mail->Body); + $mail->AltBody = str_replace('TRACKER_URL_START', "", $mail->AltBody); + $mail->AltBody = str_replace('TRACKER_URL_END', "", $mail->AltBody); + } + } + //END + + //do not add the default remove me link if the campaign has a trackerurl of the opotout link + if ($this->has_optout_links==false) { + $mail->Body .= "
    {$mod_strings['TXT_REMOVE_ME']}{$mod_strings['TXT_REMOVE_ME_CLICK']}"; + } + // cn: bug 11979 - adding single quote to comform with HTML email RFC + $mail->Body .= "
    "; + + $mail->AltBody = $template_data['body']; + if ($btracker) { + $mail->AltBody .="\n". $tracker_url; + } + if ($this->has_optout_links==false) { + $mail->AltBody .="\n\n\n{$mod_strings['TXT_REMOVE_ME_ALT']} ". $this->tracking_url . "index.php?entryPoint=removeme&identifier=$this->target_tracker_key"; + } + + } + + // cn: bug 4684, handle attachments in email templates. + $mail->handleAttachments($this->notes_array); + $tmp_Subject = $mail->Subject; + $mail->prepForOutbound(); + + $success = $mail->Send(); + //Do not save the encoded subject. + $mail->Subject = $tmp_Subject; + if($success ){ + $email_id=null; + if ($save_emails==1) { + $email_id=$this->create_indiv_email($module,$mail); + } else { + //find/create reference email record. all campaign targets reveiving this message will be linked with this message. + $email_id=$this->create_ref_email($this->marketing_id, + $this->current_emailtemplate->subject, + $this->current_emailtemplate->body, + $this->current_emailtemplate->body_html, + $this->current_campaign->name, + $this->mailbox_from_addr, + $this->user_id, + $this->notes_array, + $macro_nv, + $this->newmessage + ); + $this->newmessage = false; + } + } + + if ($success) { + $this->set_as_sent($module->email1, true, $email_id, 'Emails', 'targeted'); + } else { + + if(!empty($layout_def['parent_id'])) { + if (isset($layout_def['fields'][strtoupper($layout_def['parent_id'])])) { + $parent.="&parent_id=".$layout_def['fields'][strtoupper($layout_def['parent_id'])]; + } + } + if(!empty($layout_def['parent_module'])) { + if (isset($layout_def['fields'][strtoupper($layout_def['parent_module'])])) { + $parent.="&parent_module=".$layout_def['fields'][strtoupper($layout_def['parent_module'])]; + } + } + //log send error. save for next attempt after 24hrs. no campaign log entry will be created. + $this->set_as_sent($module->email1,false,null,null,'send error'); + } + }else{ + $success = false; + $this->target_tracker_key=create_guid(); + + if (isset($module->email_opt_out) && ($module->email_opt_out === 'on' || $module->email_opt_out == '1' || $module->email_opt_out == 1)) { + $this->set_as_sent($module->email1,true,null,null,'removed'); + } else { + if (isset($module->invalid_email) && ($module->invalid_email == 1 || $module->invalid_email == '1')) { + $this->set_as_sent($module->email1,true,null,null,'invalid email'); + } else { + $this->set_as_sent($module->email1,true, null,null,'send error'); + } + } + } + + return $success; + } + + /* + * Validates the passed email address. + * Limitations of this algorithm: does not validate email addressess that end with .meuseum + * + */ + function valid_email_address($email_address) { + + $email_address=trim($email_address); + if (empty($email_address)) { + return false; + } + + $pattern='/[A-Z0-9\._%-]+@[A-Z0-9\.-]+\.[A-Za-z]{2,}$/i'; + $ret=preg_match($pattern, $email_address); + echo $ret; + if ($ret===false or $ret==0) { + return false; + } + return true; + } + + /* + * This function takes in the given bean and searches for a related email address + * that has been designated as primary. If one is found, true is returned + * If no primary email address is found, then false is returned + * + */ + function is_primary_email_address($bean){ + $email_address=trim($bean->email1); + + if (empty($email_address)) { + return false; + } + //query for this email address rel and see if this is primary address + $primary_qry = "select email_address_id from email_addr_bean_rel where bean_id = '".$bean->id."' and email_addr_bean_rel.primary_address=1 and deleted=0"; + $res = $bean->db->query($primary_qry); + $prim_row=$this->db->fetchByAssoc($res); + //return true if this is primary + if (!empty($prim_row)) { + return true; + } + return false; + + } + + function create_export_query(&$order_by, &$where) { + $custom_join = $this->custom_fields->getJOIN(true, true,$where); + $query = "SELECT emailman.*"; + if($custom_join){ + $query .= $custom_join['select']; + } + + $query .= " FROM emailman "; + + if($custom_join){ + $query .= $custom_join['join']; + } + + $where_auto = "( emailman.deleted IS NULL OR emailman.deleted=0 )"; + + if($where != "") + $query .= "where ($where) AND ".$where_auto; + else + $query .= "where ".$where_auto; + + if(!empty($order_by)) + { + $query .= ' ORDER BY '. $this->process_order_by($order_by, null); + } + + return $query; + } +} +?> diff --git a/modules/EmailMan/EmailManDelivery.php b/modules/EmailMan/EmailManDelivery.php new file mode 100644 index 00000000..adb9d338 --- /dev/null +++ b/modules/EmailMan/EmailManDelivery.php @@ -0,0 +1,266 @@ +retrieveSettings(); +if (isset($admin->settings['massemailer_campaign_emails_per_run'])) { + $max_emails_per_run=$admin->settings['massemailer_campaign_emails_per_run']; +} +if (empty($max_emails_per_run)) { + $max_emails_per_run=500;//default +} +//save email copies? +$massemailer_email_copy=0; //default: save copies of the email. +if (isset($admin->settings['massemailer_email_copy'])) { + $massemailer_email_copy=$admin->settings['massemailer_email_copy']; +} + +$emailsPerSecond = 10; + +$mail->setMailerForSystem(); +$mail->From = "no-reply@example.com"; +$mail->FromName = "no-reply"; +$mail->ContentType="text/html"; + +$campaign_id=null; +if (isset($_REQUEST['campaign_id']) && !empty($_REQUEST['campaign_id'])) { + $campaign_id=$_REQUEST['campaign_id']; +} + +$db = DBManagerFactory::getInstance(); +$timedate = TimeDate::getInstance(); +$emailman = new EmailMan(); + + if($test){ + //if this is in test mode, then + //find all the message that meet the following criteria. + //1. scheduled send date time is now + //2. campaign matches the current campaign + //3. recipient belongs to a propsect list of type test, attached to this campaign + + $select_query =" SELECT em.* FROM emailman em"; + $select_query.=" join prospect_list_campaigns plc on em.campaign_id = plc.campaign_id"; + $select_query.=" join prospect_lists pl on pl.id = plc.prospect_list_id "; + $select_query.=" WHERE em.list_id = pl.id and pl.list_type = 'test'"; + $select_query.=" AND em.send_date_time <= ". db_convert("'".$timedate->nowDb()."'" ,"datetime"); + $select_query.=" AND (em.in_queue ='0' OR ( em.in_queue ='1' AND em.in_queue_date <= " .db_convert("'". $timedate->fromString("-1 day")->asDb() ."'" ,"datetime")."))"; + $select_query.=" AND em.campaign_id='{$campaign_id}'"; + $select_query.=" ORDER BY em.send_date_time ASC, em.user_id, em.list_id"; + }else{ + //this is not a test.. + //find all the message that meet the following criteria. + //1. scheduled send date time is now + //2. were never processed or last attempt was 24 hours ago + $select_query =" SELECT *"; + $select_query.=" FROM $emailman->table_name"; + $select_query.=" WHERE send_date_time <= ". db_convert("'".TimeDate::getInstance()->nowDb()."'" ,"datetime"); + $select_query.=" AND (in_queue ='0' OR ( in_queue ='1' AND in_queue_date <= " .db_convert("'". $timedate->fromString("-1 day")->asDb() ."'" ,"datetime")."))"; + + if (!empty($campaign_id)) { + $select_query.=" AND campaign_id='{$campaign_id}'"; + } + $select_query.=" ORDER BY send_date_time ASC,user_id, list_id"; + + } + +do { + + $no_items_in_queue=true; + + $result = $db->limitQuery($select_query,0,$max_emails_per_run); + global $current_user; + if(isset($current_user)){ + $temp_user = $current_user; + } + $current_user = new User(); + $startTime = microtime(true); + + while(($row = $db->fetchByAssoc($result))!= null){ + + //verify the queue item before further processing. + //we have found cases where users have taken away access to email templates while them message is in queue. + if (empty($row['campaign_id'])) { + $GLOBALS['log']->fatal('Skipping emailman entry with empty campaign id' . print_r($row,true)); + continue; + } + if (empty($row['marketing_id'])) { + $GLOBALS['log']->fatal('Skipping emailman entry with empty marketing id' . print_r($row,true)); + continue; //do not process this row . + } + + //fetch user that scheduled the campaign. + if(empty($current_user) or $row['user_id'] != $current_user->id){ + $current_user->retrieve($row['user_id']); + } + + if (!$emailman->verify_campaign($row['marketing_id'])) { + $GLOBALS['log']->fatal('Error verifying templates for the campaign, exiting'); + continue; + } + + + //verify the email template too.. + //find the template associated with marketing message. make sure that template has a subject and + //a non-empty body + if (!isset($template_status[$row['marketing_id']])) { + if (!class_exists('EmailMarketing')) { + + } + $current_emailmarketing=new EmailMarketing(); + $current_emailmarketing->retrieve($row['marketing_id']); + + if (!class_exists('EmailTemplate')) { + + } + $current_emailtemplate= new EmailTemplate(); + $current_emailtemplate->retrieve($current_emailmarketing->template_id); + + } + + //acquire a lock. + //if the database does not support repeatable read isolation by default, we might get data that does not meet + //the criteria in the original query, and we care most about the in_queue_date and process_date_time, + //if they are null or in past(older than 24 horus) then we are okay. + $lock_query="UPDATE emailman SET in_queue=1, in_queue_date='". $timedate->nowDb() ."' WHERE id = '${row['id']}'"; + $lock_query.=" AND (in_queue ='0' OR ( in_queue ='1' AND in_queue_date <= " .db_convert("'". $timedate->fromString("-1 day")->asDb() ."'" ,"datetime")."))"; + + //if the query fails to execute.. terminate campaign email process. + $lock_result=$db->query($lock_query,true,'Error acquiring a lock for emailman entry.'); + if ($db->dbType=='oci8') { + } else { + $lock_count=$db->getAffectedRowCount(); + } + + //do not process the message if unable to acquire lock. + if ($lock_count!= 1) { + $GLOBALS['log']->fatal("Error acquiring lock for the emailman entry, skipping email delivery. lock status=$lock_count " . print_r($row,true)); + continue; //do not process this row we will examine it after 24 hrs. the email address based dupe check is in place too. + } + + $no_items_in_queue=false; + + + foreach($row as $name=>$value){ + $emailman->$name = $value; + } + + //for the campaign process the supression lists. + if (!isset($current_campaign_id) or empty($current_campaign_id) or $current_campaign_id != $row['campaign_id']) { + $current_campaign_id= $row['campaign_id']; + + //is this email address suppressed? + $plc_query= " SELECT prospect_list_id, prospect_lists.list_type,prospect_lists.domain_name FROM prospect_list_campaigns "; + $plc_query.=" LEFT JOIN prospect_lists on prospect_lists.id = prospect_list_campaigns.prospect_list_id"; + $plc_query.=" WHERE "; + $plc_query.=" campaign_id='{$current_campaign_id}' "; + $plc_query.=" AND prospect_lists.list_type in ('exempt_address','exempt_domain')"; + $plc_query.=" AND prospect_list_campaigns.deleted=0"; + $plc_query.=" AND prospect_lists.deleted=0"; + + $emailman->restricted_domains=array(); + $emailman->restricted_addresses=array(); + + $result1=$db->query($plc_query); + while($row1 = $db->fetchByAssoc($result1)){ + if ($row1['list_type']=='exempt_domain') { + $emailman->restricted_domains[strtolower($row1['domain_name'])]=1; + } else { + //find email address of targets in this prospect list. + $email_query = "SELECT email_address FROM email_addresses ea JOIN email_addr_bean_rel eabr ON ea.id = eabr.email_address_id JOIN prospect_lists_prospects plp ON eabr.bean_id = plp.related_id AND eabr.bean_module = plp.related_type AND plp.prospect_list_id = '{$row1['prospect_list_id']}' and plp.deleted = 0"; + $email_query_result=$db->query($email_query); + + while($email_address = $db->fetchByAssoc($email_query_result)){ + //ignore empty email addresses; + if (!empty($email_address['email_address'])) { + $emailman->restricted_addresses[strtolower($email_address['email_address'])]=1; + } + } + } + } + } + + if(!$emailman->sendEmail($mail,$massemailer_email_copy,$test)){ + $GLOBALS['log']->fatal("Email delivery FAILURE:" . print_r($row,true)); + } else { + $GLOBALS['log']->debug("Email delivery SUCCESS:" . print_r($row,true)); + } + if($mail->isError()){ + $GLOBALS['log']->fatal("Email delivery error:" . print_r($row,true). $mail->ErrorInfo); + } + } + + $send_all=$send_all?!$no_items_in_queue:$send_all; + +}while ($send_all == true); + +if ($admin->settings['mail_sendtype'] == "SMTP") { + $mail->SMTPClose(); +} +if(isset($temp_user)){ + $current_user = $temp_user; +} +if (isset($_REQUEST['return_module']) && isset($_REQUEST['return_action']) && isset($_REQUEST['return_id'])) { + $from_wiz=' '; + if(isset($_REQUEST['from_wiz'])&& $_REQUEST['from_wiz']==true){ + header("Location: index.php?module={$_REQUEST['return_module']}&action={$_REQUEST['return_action']}&record={$_REQUEST['return_id']}&from=test"); + }else{ + header("Location: index.php?module={$_REQUEST['return_module']}&action={$_REQUEST['return_action']}&record={$_REQUEST['return_id']}"); + } +} else { + /* this will be triggered when manually sending off Email campaigns from the + * Mass Email Queue Manager. + */ + if(isset($_POST['manual'])) { + header("Location: index.php?module=EmailMan&action=index"); + } +} +?> diff --git a/modules/EmailMan/Forms.php b/modules/EmailMan/Forms.php new file mode 100644 index 00000000..11d88760 --- /dev/null +++ b/modules/EmailMan/Forms.php @@ -0,0 +1,155 @@ + + + +EOQ; +return $the_script; +} +?> \ No newline at end of file diff --git a/modules/EmailMan/Menu.php b/modules/EmailMan/Menu.php new file mode 100644 index 00000000..410725f5 --- /dev/null +++ b/modules/EmailMan/Menu.php @@ -0,0 +1,47 @@ +populateFromPost(); + $oe->saveSystem(); +} + +$focus = new Administration(); + +if(isset($_POST['tracking_entities_location_type'])) { + if ($_POST['tracking_entities_location_type'] != '2') { + unset($_POST['tracking_entities_location']); + unset($_POST['tracking_entities_location_type']); + } +} +// cn: handle mail_smtpauth_req checkbox on/off (removing double reference in the form itself +if( !isset($_POST['mail_smtpauth_req']) ) +{ + $_POST['mail_smtpauth_req'] = 0; + $_POST['notify_allow_default_outbound'] = 0; //If smtp auth is disabled ensure outbound is disabled. +} + +if( !empty($_POST['notify_allow_default_outbound']) ) +{ + $oe = new OutboundEmail(); + if( !$oe->isAllowUserAccessToSystemDefaultOutbound() ) + $oe->removeUserOverrideAccounts(); +} + +$focus->saveConfig(); + +// save User defaults for emails +$sugar_config['email_default_delete_attachments'] = (isset($_REQUEST['email_default_delete_attachments'])) ? true : false; + +/////////////////////////////////////////////////////////////////////////////// +//// SECURITY +$security = array(); +if(isset($_REQUEST['applet'])) $security['applet'] = 'applet'; +if(isset($_REQUEST['base'])) $security['base'] = 'base'; +if(isset($_REQUEST['embed'])) $security['embed'] = 'embed'; +if(isset($_REQUEST['form'])) $security['form'] = 'form'; +if(isset($_REQUEST['frame'])) $security['frame'] = 'frame'; +if(isset($_REQUEST['frameset'])) $security['frameset'] = 'frameset'; +if(isset($_REQUEST['iframe'])) $security['iframe'] = 'iframe'; +if(isset($_REQUEST['import'])) $security['import'] = '\?import'; +if(isset($_REQUEST['layer'])) $security['layer'] = 'layer'; +if(isset($_REQUEST['link'])) $security['link'] = 'link'; +if(isset($_REQUEST['object'])) $security['object'] = 'object'; +if(isset($_REQUEST['style'])) $security['style'] = 'style'; +if(isset($_REQUEST['xmp'])) $security['xmp'] = 'xmp'; +$security['script'] = 'script'; + +$sugar_config['email_xss'] = base64_encode(serialize($security)); + +//// SECURITY +/////////////////////////////////////////////////////////////////////////////// + +ksort($sugar_config); +write_array_to_file('sugar_config', $sugar_config, 'config.php'); + +header("Location: index.php?action={$_POST['return_action']}&module={$_POST['return_module']}"); +?> \ No newline at end of file diff --git a/modules/EmailMan/action_view_map.php b/modules/EmailMan/action_view_map.php new file mode 100644 index 00000000..ffe85fbf --- /dev/null +++ b/modules/EmailMan/action_view_map.php @@ -0,0 +1,39 @@ + Array( + "id" + , "date_entered" + , "date_modified" + , 'user_id' + , 'module' + , 'module_id' + , 'marketing_id' + , 'campaign_id' + , 'list_id' + , 'template_id' + , 'from_email' + , 'from_name' + , 'invalid_email' + , 'send_date_time' + , 'in_queue' + , 'in_queue_date' + ,'send_attempts' + ), + 'list_fields' => Array( + "id" + , 'user_id' + , 'module' + , 'module_id' + , 'campaign_id' + , 'marketing_id' + , 'list_id' + , 'invalid_email' + , 'from_name' + , 'from_email' + , 'template_id' + , 'send_date_time' + , 'in_queue' + , 'in_queue_date' + ,'send_attempts' + ,'user_name' + ,'to_email' + ,'from_email' + ,'campaign_name' + ,'to_contact' + ,'to_lead' + ,'to_prospect' + ,'contact_email' + , 'lead_email' + , 'prospect_email' + ), +); +?> \ No newline at end of file diff --git a/modules/EmailMan/language/en_us.lang.php b/modules/EmailMan/language/en_us.lang.php new file mode 100644 index 00000000..9cdfc8f0 --- /dev/null +++ b/modules/EmailMan/language/en_us.lang.php @@ -0,0 +1,159 @@ + 'Send Date', + 'LBL_IN_QUEUE' => 'In Process', + 'LBL_IN_QUEUE_DATE' => 'Queued Date', + + 'ERR_INT_ONLY_EMAIL_PER_RUN' => 'Use only integer values to specify the number of emails sent per batch', + + 'LBL_ATTACHMENT_AUDIT' => ' was sent. It was not duplicated locally to conserve disk usage.', + 'LBL_CONFIGURE_SETTINGS' => 'Configure Email Settings', + 'LBL_CUSTOM_LOCATION' => 'User Defined', + 'LBL_DEFAULT_LOCATION' => 'Default', + + 'LBL_DISCLOSURE_TITLE' => 'Append Disclosure Message to Every Email', + 'LBL_DISCLOSURE_TEXT_TITLE' => 'Disclosure Contents', + 'LBL_DISCLOSURE_TEXT_SAMPLE' => 'NOTICE: This email message is for the sole use of the intended recipient(s) and may contain confidential and privileged information. Any unauthorized review, use, disclosure, or distribution is prohibited. If you are not the intended recipient, please destroy all copies of the original message and notify the sender so that our address record can be corrected. Thank you.', + + 'LBL_EMAIL_DEFAULT_CHARSET' => 'Compose email messages in this character set', + 'LBL_EMAIL_DEFAULT_EDITOR' => 'Compose email using this client', + 'LBL_EMAIL_DEFAULT_DELETE_ATTACHMENTS' => 'Delete related notes & attachments with deleted Emails', + 'LBL_EMAIL_GMAIL_DEFAULTS' => 'Prefill Gmail™ Defaults', + 'LBL_EMAIL_PER_RUN_REQ' => 'Number of emails sent per batch:', + 'LBL_EMAIL_SMTP_SSL' => 'Enable SMTP over SSL?', + 'LBL_EMAIL_USER_TITLE' => 'User Email Defaults', + 'LBL_EMAIL_OUTBOUND_CONFIGURATION' => 'Outgoing Mail Configuration', + 'LBL_EMAILS_PER_RUN' => 'Number of emails sent per batch:', + 'LBL_ID' => 'Id', + 'LBL_LIST_CAMPAIGN' => 'Campaign', + 'LBL_LIST_FORM_PROCESSED_TITLE' => 'Processed', + 'LBL_LIST_FORM_TITLE' => 'Queue', + 'LBL_LIST_FROM_EMAIL' => 'From Email', + 'LBL_LIST_FROM_NAME' => 'From Name', + 'LBL_LIST_IN_QUEUE' => 'In Process', + 'LBL_LIST_MESSAGE_NAME' => 'Marketing Message', + 'LBL_LIST_RECIPIENT_EMAIL' => 'Recipient Email', + 'LBL_LIST_RECIPIENT_NAME' => 'Recipient Name', + 'LBL_LIST_SEND_ATTEMPTS' => 'Send Attempts', + 'LBL_LIST_SEND_DATE_TIME' => 'Send On', + 'LBL_LIST_USER_NAME' => 'User Name', + 'LBL_LOCATION_ONLY' => 'Location', + 'LBL_LOCATION_TRACK' => 'Location of campaign tracking files (like campaign_tracker.php)', + 'LBL_CAMP_MESSAGE_COPY' => 'Keep copies of campaign messages:', + 'LBL_CAMP_MESSAGE_COPY_DESC' => 'Would you like to store complete copies of EACH email message sent during all campaigns? We recommend and default to no. Choosing no will store only the template that is sent and the needed variables to recreate the individual message.', + 'LBL_MAIL_SENDTYPE' => 'Mail Transfer Agent:', + 'LBL_MAIL_SMTPAUTH_REQ' => 'Use SMTP Authentication:', + 'LBL_MAIL_SMTPPASS' => 'Password:', + 'LBL_MAIL_SMTPPORT' => 'SMTP Port:', + 'LBL_MAIL_SMTPSERVER' => 'SMTP Mail Server:', + 'LBL_MAIL_SMTPUSER' => 'Username:', + 'LBL_CHOOSE_EMAIL_PROVIDER' => 'Choose your Email provider', + 'LBL_YAHOOMAIL_SMTPPASS' => 'Yahoo! Mail Password', + 'LBL_YAHOOMAIL_SMTPUSER' => 'Yahoo! Mail ID', + 'LBL_GMAIL_SMTPPASS' => 'Gmail Password', + 'LBL_GMAIL_SMTPUSER' => 'Gmail Email Address', + 'LBL_EXCHANGE_SMTPPASS' => 'Exchange Password', + 'LBL_EXCHANGE_SMTPUSER' => 'Exchange Username', + 'LBL_EXCHANGE_SMTPPORT' => 'Exchange Server Port', + 'LBL_EXCHANGE_SMTPSERVER' => 'Exchange Server', + 'LBL_EMAIL_LINK_TYPE' => 'Email Client', + 'LBL_EMAIL_LINK_TYPE_HELP' => 'Sugar Mail Client: Send emails using the email client in the Sugar application.
    External Mail Client: Send email using an email client outside of the Sugar application, such as Microsoft Outlook.', + 'LBL_MARKETING_ID' => 'Marketing Id', + 'LBL_MODULE_ID' => 'EmailMan', + 'LBL_MODULE_NAME' => 'Email Settings', + 'LBL_CONFIGURE_CAMPAIGN_EMAIL_SETTINGS' => 'Configure Campaign Email Settings', + 'LBL_MODULE_TITLE' => 'Outbound Email Queue Management', + 'LBL_NOTIFICATION_ON_DESC' => 'When enabled, emails are sent to users when records are assigned to them.', + 'LBL_NOTIFY_FROMADDRESS' => '"From" Address:', + 'LBL_NOTIFY_FROMNAME' => '"From" Name:', + 'LBL_NOTIFY_ON' => 'Assignment Notifications', + 'LBL_NOTIFY_SEND_BY_DEFAULT' => 'Send notifications to new users', + 'LBL_NOTIFY_TITLE' => 'Email Options', + 'LBL_OLD_ID' => 'Old Id', + 'LBL_OUTBOUND_EMAIL_TITLE' => 'Outbound Email Options', + 'LBL_RELATED_ID' => 'Related Id', + 'LBL_RELATED_TYPE' => 'Related Type', + 'LBL_SAVE_OUTBOUND_RAW' => 'Save Outbound Raw Emails', + 'LBL_SEARCH_FORM_PROCESSED_TITLE' => 'Processed Search', + 'LBL_SEARCH_FORM_TITLE' => 'Queue Search', + 'LBL_VIEW_PROCESSED_EMAILS' => 'View Processed Emails', + 'LBL_VIEW_QUEUED_EMAILS' => 'View Queued Emails', + 'TRACKING_ENTRIES_LOCATION_DEFAULT_VALUE' => 'Value of Config.php setting site_url', + 'TXT_REMOVE_ME_ALT' => 'To remove yourself from this email list go to', + 'TXT_REMOVE_ME_CLICK' => 'click here', + 'TXT_REMOVE_ME' => 'To remove yourself from this email list ', + 'LBL_NOTIFY_SEND_FROM_ASSIGNING_USER' => 'Send notification from assigning user\'s e-mail address', + + 'LBL_SECURITY_TITLE' => 'Email Security Settings', + 'LBL_SECURITY_DESC' => 'Check the following that should NOT be allowed in via InboundEmail or displayed in the Emails module.', + 'LBL_SECURITY_APPLET' => 'Applet tag', + 'LBL_SECURITY_BASE' => 'Base tag', + 'LBL_SECURITY_EMBED' => 'Embed tag', + 'LBL_SECURITY_FORM' => 'Form tag', + 'LBL_SECURITY_FRAME' => 'Frame tag', + 'LBL_SECURITY_FRAMESET' => 'Frameset tag', + 'LBL_SECURITY_IFRAME' => 'iFrame tag', + 'LBL_SECURITY_IMPORT' => 'Import tag', + 'LBL_SECURITY_LAYER' => 'Layer tag', + 'LBL_SECURITY_LINK' => 'Link tag', + 'LBL_SECURITY_OBJECT' => 'Object tag', + 'LBL_SECURITY_OUTLOOK_DEFAULTS' => 'Select Outlook default minimum security settings (errs on the side of correct display).', + 'LBL_SECURITY_SCRIPT' => 'Script tag', + 'LBL_SECURITY_STYLE' => 'Style tag', + 'LBL_SECURITY_TOGGLE_ALL' => 'Toggle All Options', + 'LBL_SECURITY_XMP' => 'Xmp tag', + 'LBL_YES' => 'Yes', + 'LBL_NO' => 'No', + 'LBL_PREPEND_TEST' => '[Test]: ', + 'LBL_SEND_ATTEMPTS' => 'Send Attempts', + 'LBL_OUTGOING_SECTION_HELP' => 'Configure the default outgoing mail server for sending email notifications, including workflow alerts.', + 'LBL_ALLOW_DEFAULT_SELECTION' => 'Allow users to use this account for outgoing email:', + 'LBL_ALLOW_DEFAULT_SELECTION_HELP' => 'When this option selected, all users will be able to send emails using the same outgoing
    mail account used to send system notifications and alerts. If the option is not selected,
    users can still use the outgoing mail server after providing their own account information.', + 'LBL_FROM_ADDRESS_HELP' => 'When enabled, the assigning user\\\'s name and email address will be included in the From field of the email. This feature might not work with SMTP servers that do not allow sending from a different email account than the server account.' +); + +?> \ No newline at end of file diff --git a/modules/EmailMan/metadata/SearchFields.php b/modules/EmailMan/metadata/SearchFields.php new file mode 100644 index 00000000..7e19c695 --- /dev/null +++ b/modules/EmailMan/metadata/SearchFields.php @@ -0,0 +1,45 @@ + array( 'query_type'=>'default','db_field'=>array('campaigns.name')), + 'to_name'=> array('query_type'=>'default','db_field'=>array('contacts.first_name','contacts.last_name','leads.first_name','leads.last_name','prospects.first_name','prospects.last_name')), + 'to_email'=> array('query_type'=>'default','db_field'=>array('contacts.email1','leads.email1','prospects.email1')), + 'current_user_only'=> array('query_type'=>'default','db_field'=>array('assigned_user_id'),'my_items'=>true, 'vname' => 'LBL_CURRENT_USER_FILTER', 'type' => 'bool'), + ); +?> diff --git a/modules/EmailMan/metadata/listviewdefs.php b/modules/EmailMan/metadata/listviewdefs.php new file mode 100644 index 00000000..8963622f --- /dev/null +++ b/modules/EmailMan/metadata/listviewdefs.php @@ -0,0 +1,78 @@ + array( + 'width' => '10', + 'label' => 'LBL_LIST_CAMPAIGN', + 'link' => true, + 'customCode' => '{$CAMPAIGN_NAME}', + 'default' => true), + 'RECIPIENT_NAME' => array( + 'sortable' => false, + 'width' => '10', + 'label' => 'LBL_LIST_RECIPIENT_NAME', + 'customCode' => '{$RECIPIENT_NAME}', + 'default' => true), + 'RECIPIENT_EMAIL' => array( + 'sortable' => false, + 'width' => '10', + 'label' => 'LBL_LIST_RECIPIENT_EMAIL', + 'customCode' => '{$EMAIL1_LINK}{$RECIPIENT_EMAIL}', + 'default' => true), + 'MESSAGE_NAME' => array( + 'sortable' => false, + 'width' => '10', + 'label' => 'LBL_LIST_MESSAGE_NAME', + 'customCode' => '{$MESSAGE_NAME}', + 'default' => true), + 'SEND_DATE_TIME' => array( + 'width' => '10', + 'label' => 'LBL_LIST_SEND_DATE_TIME', + 'default' => true), + 'SEND_ATTEMPTS' => array( + 'width' => '10', + 'label' => 'LBL_LIST_SEND_ATTEMPTS', + 'default' => true), + 'IN_QUEUE' => array( + 'width' => '10', + 'label' => 'LBL_LIST_IN_QUEUE', + 'default' => true), +); diff --git a/modules/EmailMan/metadata/searchdefs.php b/modules/EmailMan/metadata/searchdefs.php new file mode 100644 index 00000000..a47b31a5 --- /dev/null +++ b/modules/EmailMan/metadata/searchdefs.php @@ -0,0 +1,61 @@ + array( + 'maxColumns' => '3', + 'widths' => array('label' => '10', 'field' => '30'), + ), + 'layout' => array( + 'basic_search' => array( + array('name'=>'campaign_name', 'label'=>'LBL_LIST_CAMPAIGN',), + array('name'=>'current_user_only', 'label'=>'LBL_CURRENT_USER_FILTER', 'type'=>'bool'), + ), + 'advanced_search' => array( + array('name'=>'campaign_name', 'label'=>'LBL_LIST_CAMPAIGN',), + array('name'=>'to_name', 'label'=>'LBL_LIST_RECIPIENT_NAME'), + array('name'=>'to_email', 'label'=>'LBL_LIST_RECIPIENT_EMAIL'), + array('name'=>'current_user_only', 'label'=>'LBL_CURRENT_USER_FILTER', 'type'=>'bool'), + ), + ), + ); +?> diff --git a/modules/EmailMan/metadata/subpanels/default.php b/modules/EmailMan/metadata/subpanels/default.php new file mode 100644 index 00000000..2bc66014 --- /dev/null +++ b/modules/EmailMan/metadata/subpanels/default.php @@ -0,0 +1,78 @@ + array( + ), + + 'where' => '', + + + 'list_fields' => array( + 'recipient_name'=>array( + 'vname' => 'LBL_LIST_RECIPIENT_NAME', + 'width' => '10%', + 'sortable'=>false, + ), + 'recipient_email'=>array( + 'vname' => 'LBL_LIST_RECIPIENT_EMAIL', + 'width' => '10%', + 'sortable'=>false, + ), + 'message_name' => array( + 'vname' => 'LBL_MARKETING_ID', + 'width' => '10%', + 'sortable'=>false, + ), + 'send_date_time' => array( + 'vname' => 'LBL_LIST_SEND_DATE_TIME', + 'width' => '10%', + 'sortable'=>false, + ), + 'related_id'=>array( + 'usage'=>'query_only', + ), + 'related_type'=>array( + 'usage'=>'query_only', + ), + 'marketing_id' => array( + 'usage'=>'query_only', + ), + ), +); +?> \ No newline at end of file diff --git a/modules/EmailMan/subpanels/default.php b/modules/EmailMan/subpanels/default.php new file mode 100644 index 00000000..2bc66014 --- /dev/null +++ b/modules/EmailMan/subpanels/default.php @@ -0,0 +1,78 @@ + array( + ), + + 'where' => '', + + + 'list_fields' => array( + 'recipient_name'=>array( + 'vname' => 'LBL_LIST_RECIPIENT_NAME', + 'width' => '10%', + 'sortable'=>false, + ), + 'recipient_email'=>array( + 'vname' => 'LBL_LIST_RECIPIENT_EMAIL', + 'width' => '10%', + 'sortable'=>false, + ), + 'message_name' => array( + 'vname' => 'LBL_MARKETING_ID', + 'width' => '10%', + 'sortable'=>false, + ), + 'send_date_time' => array( + 'vname' => 'LBL_LIST_SEND_DATE_TIME', + 'width' => '10%', + 'sortable'=>false, + ), + 'related_id'=>array( + 'usage'=>'query_only', + ), + 'related_type'=>array( + 'usage'=>'query_only', + ), + 'marketing_id' => array( + 'usage'=>'query_only', + ), + ), +); +?> \ No newline at end of file diff --git a/modules/EmailMan/testOutboundEmail.php b/modules/EmailMan/testOutboundEmail.php new file mode 100644 index 00000000..4dc61647 --- /dev/null +++ b/modules/EmailMan/testOutboundEmail.php @@ -0,0 +1,73 @@ +getMailerByName($current_user, $_REQUEST['mail_name']); + if(!empty($oe)) { + $pass = $oe->mail_smtppass; + } +} +$out = Email::sendEmailTest($_REQUEST['mail_smtpserver'], $_REQUEST['mail_smtpport'], $_REQUEST['mail_smtpssl'], + ($_REQUEST['mail_smtpauth_req'] == 'true' ? 1 : 0), $_REQUEST['mail_smtpuser'], + $pass, $_REQUEST['outboundtest_from_address'], $_REQUEST['outboundtest_to_address'], $_REQUEST['mail_sendtype']); + +$out = $json->encode($out); +echo $out; +?> \ No newline at end of file diff --git a/modules/EmailMan/tpls/campaignconfig.tpl b/modules/EmailMan/tpls/campaignconfig.tpl new file mode 100644 index 00000000..3b0733b8 --- /dev/null +++ b/modules/EmailMan/tpls/campaignconfig.tpl @@ -0,0 +1,125 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +/********************************************************************************* + + ********************************************************************************/ +*} +{$ROLLOVER} + + + + + + + + + + + + + + +
    + + + + + + + + + + + + + + + + + + + +
    +

    + {$MOD.LBL_OUTBOUND_EMAIL_TITLE} +

    +
    + {$MOD.LBL_EMAILS_PER_RUN} {$APP.LBL_REQUIRED_SYMBOL} + + +
    + {$MOD.LBL_LOCATION_TRACK} {$APP.LBL_REQUIRED_SYMBOL} + + + {$MOD.LBL_DEFAULT_LOCATION} {$MOD.LBL_CUSTOM_LOCATION} +
    + + +
    +
    + {$MOD.LBL_CAMP_MESSAGE_COPY} {$APP.LBL_REQUIRED_SYMBOL} + {$MOD.LBL_CAMP_MESSAGE_COPY_DESC} +
    +
    + + {$MOD.LBL_YES} {$MOD.LBL_NO} +
    +
    + +
    + + +
    + + +{$JAVASCRIPT} \ No newline at end of file diff --git a/modules/EmailMan/tpls/config.tpl b/modules/EmailMan/tpls/config.tpl new file mode 100644 index 00000000..5ae34d2c --- /dev/null +++ b/modules/EmailMan/tpls/config.tpl @@ -0,0 +1,700 @@ + + + + + + +{literal} + +{/literal} +{$ROLLOVER} +
    + + + + + + + + + + + + +
    + + + + {$APP.LBL_REQUIRED_SYMBOL} {$APP.NTC_REQUIRED} +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

    {$MOD.LBL_EMAIL_OUTBOUND_CONFIGURATION}

    + {$MOD.LBL_OUTGOING_SECTION_HELP} +
      +
    {$MOD.LBL_MAIL_SENDTYPE} + +   
    {$MOD.LBL_NOTIFY_FROMNAME} {$APP.LBL_REQUIRED_SYMBOL}
    {$MOD.LBL_NOTIFY_FROMADDRESS} {$APP.LBL_REQUIRED_SYMBOL}
    {$MOD.LBL_CHOOSE_EMAIL_PROVIDER}
    +
    + + + + + + + + + + + + + + + + + + + + +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    {$MOD.LBL_MAIL_SMTPSERVER} {$APP.LBL_REQUIRED_SYMBOL}{$MOD.LBL_MAIL_SMTPPORT} {$APP.LBL_REQUIRED_SYMBOL}
    {$MOD.LBL_MAIL_SMTPAUTH_REQ} + + {$APP.LBL_EMAIL_SMTP_SSL_OR_TLS} + +
    {$MOD.LBL_MAIL_SMTPUSER} {$APP.LBL_REQUIRED_SYMBOL}  
    {$MOD.LBL_MAIL_SMTPPASS} {$APP.LBL_REQUIRED_SYMBOL}  
    + {$MOD.LBL_ALLOW_DEFAULT_SELECTION}  + + + + +   
    +
    +
     
        
    + + + + + + + + + + + + + + + + +
    +

    {$MOD.LBL_NOTIFY_TITLE}

    +
    + {$MOD.LBL_NOTIFY_ON}:  + + + +
    + {$MOD.LBL_EMAIL_DEFAULT_DELETE_ATTACHMENTS}:  + + + + {$MOD.LBL_NOTIFY_SEND_FROM_ASSIGNING_USER}: + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

    {$MOD.LBL_SECURITY_TITLE}

    + {$MOD.LBL_SECURITY_DESC} +
    + {$MOD.LBL_SECURITY_OUTLOOK_DEFAULTS} + +   + {literal} + + {/literal} +
    + {$MOD.LBL_SECURITY_TOGGLE_ALL} + +   +
    + {$MOD.LBL_SECURITY_APPLET} + +   <applet> + + {$MOD.LBL_SECURITY_BASE} + +   <base> +
    + {$MOD.LBL_SECURITY_EMBED} + +   <embed> + + {$MOD.LBL_SECURITY_FORM} + +   <form> +
    + {$MOD.LBL_SECURITY_FRAME} + +   <frame> + + {$MOD.LBL_SECURITY_FRAMESET} + +   <frameset> +
    + {$MOD.LBL_SECURITY_IFRAME} + +   <iframe> + + {$MOD.LBL_SECURITY_IMPORT} + +   <import> +
    + {$MOD.LBL_SECURITY_LAYER} + +   <layer> + + {$MOD.LBL_SECURITY_LINK} + +   <link> +
    + {$MOD.LBL_SECURITY_OBJECT} + +   <object> + + {$MOD.LBL_SECURITY_STYLE} + +   <style> +
    + {$MOD.LBL_SECURITY_XMP} + +   <xmp> +   
    +
    +
    +
    + + + + + + + + + +
    + {$APP.LBL_EMAIL_SETTINGS_FROM_TO_EMAIL_ADDR} + + {$APP.LBL_REQUIRED_SYMBOL} + + + +
    +   +   +
    +
    +
    + +
    + + +
    + + +{$JAVASCRIPT} +{literal} + +{/literal} diff --git a/modules/EmailMan/vardefs.php b/modules/EmailMan/vardefs.php new file mode 100644 index 00000000..1351fff3 --- /dev/null +++ b/modules/EmailMan/vardefs.php @@ -0,0 +1,176 @@ + 'emailman', 'comment' => 'Email campaign queue', 'fields' => array( + 'date_entered' => array( + 'name' => 'date_entered', + 'vname' => 'LBL_DATE_ENTERED', + 'type' => 'datetime', + 'comment' => 'Date record created', + ), + 'date_modified' => array( + 'name' => 'date_modified', + 'vname' => 'LBL_DATE_MODIFIED', + 'type' => 'datetime', + 'comment' => 'Date record last modified', + ), + 'user_id' => array( + 'name' => 'user_id', + 'vname' => 'LBL_USER_ID', + 'type' => 'id','len' => '36', + 'reportable' =>false, + 'comment' => 'User ID representing assigned-to user', + ), + 'id' => + array ( + 'name' => 'id', + 'vname' => 'LBL_ID', + 'type' => 'int', + 'len' => '11', + 'auto_increment'=>true, + 'comment' => 'Unique identifier', + ), + 'campaign_id' => array( + 'name' => 'campaign_id', + 'vname' => 'LBL_CAMPAIGN_ID', + 'type' => 'id', + 'reportable' =>false, + 'comment' => 'ID of related campaign', + ), + 'marketing_id' => array( + 'name' => 'marketing_id', + 'vname' => 'LBL_MARKETING_ID', + 'type' => 'id', + 'reportable' =>false, + 'comment' => '', + ), + 'list_id' => array( + 'name' => 'list_id', + 'vname' => 'LBL_LIST_ID', + 'type' => 'id', + 'reportable' =>false, + 'len' => '36', + 'comment' => 'Associated list', + ), + 'send_date_time' => array( + 'name' => 'send_date_time' , + 'vname' => 'LBL_SEND_DATE_TIME', + 'type' => 'datetime', + ), + 'modified_user_id' => array( + 'name' => 'modified_user_id', + 'vname' => 'LBL_MODIFIED_USER_ID', + 'type' => 'id', + 'reportable' =>false, + 'len' => '36', + 'comment' => 'User ID who last modified record', + ), + 'in_queue' => array( + 'name' => 'in_queue', + 'vname' => 'LBL_IN_QUEUE', + 'type' => 'bool', + 'comment' => 'Flag indicating if item still in queue', + ), + 'in_queue_date' => array( + 'name' => 'in_queue_date', + 'vname' => 'LBL_IN_QUEUE_DATE', + 'type' => 'datetime', + 'comment' => 'Datetime in which item entered queue', + ), + 'send_attempts' => array( + 'name' => 'send_attempts', + 'vname' => 'LBL_SEND_ATTEMPTS', + 'type' => 'int', + 'default' => '0', + 'comment' => 'Number of attempts made to send this item', + ), + 'deleted' => array( + 'name' => 'deleted', + 'vname' => 'LBL_DELETED', + 'type' => 'bool', + 'reportable' =>false, + 'comment' => 'Record deletion indicator', + ), + 'related_id' => array( + 'name' => 'related_id', + 'vname' => 'LBL_RELATED_ID', + 'type' => 'id', + 'reportable' =>false, + 'comment' => 'ID of Sugar object to which this item is related', + ), + 'related_type' => array( + 'name' => 'related_type' , + 'vname' => 'LBL_RELATED_TYPE', + 'type' => 'varchar', + 'len' => '100', + 'comment' => 'Descriptor of the Sugar object indicated by related_id', + ), + 'recipient_name' => array( + 'name' => 'recipient_name', + 'type' => 'varchar', + 'len' => '255', + 'source'=>'non-db', + ), + 'recipient_email' => array( + 'name' => 'recipient_email', + 'type' => 'varchar', + 'len' => '255', + 'source'=>'non-db', + ), + 'message_name' => array( + 'name' => 'message_name', + 'type' => 'varchar', + 'len' => '255', + 'source'=>'non-db', + ), + 'campaign_name' => array( + 'name' => 'campaign_name', + 'vname' => 'LBL_LIST_CAMPAIGN', + 'type' => 'varchar', + 'len' => '50', + 'source'=>'non-db', + ), + +), 'indices' => array ( + array('name' => 'emailmanpk', 'type' => 'primary', 'fields' => array('id')), + array('name' => 'idx_eman_list', 'type' => 'index', 'fields' => array('list_id','user_id','deleted')), + array('name' => 'idx_eman_campaign_id', 'type' => 'index', 'fields' => array('campaign_id')), + array('name' => 'idx_eman_relid_reltype_id', 'type' => 'index', 'fields'=> array('related_id', 'related_type', 'campaign_id')), + ) +); +?> diff --git a/modules/EmailMan/views/view.campaignconfig.php b/modules/EmailMan/views/view.campaignconfig.php new file mode 100644 index 00000000..25bf24ef --- /dev/null +++ b/modules/EmailMan/views/view.campaignconfig.php @@ -0,0 +1,130 @@ +".translate('LBL_MODULE_NAME','Administration')."", + translate('LBL_CAMPAIGN_CONFIG_TITLE','Administration'), + ); + } + + /** + * @see SugarView::preDisplay() + */ + public function preDisplay() + { + global $current_user; + + if ( !is_admin($current_user) + && !is_admin_for_module($GLOBALS['current_user'],'Campaigns') ) + sugar_die("Unauthorized access to administration."); + } + + /** + * @see SugarView::display() + */ + public function display() + { + global $mod_strings; + global $app_list_strings; + global $app_strings; + global $current_user; + + echo $this->getModuleTitle(false); + global $currentModule; + + $focus = new Administration(); + $focus->retrieveSettings(); //retrieve all admin settings. + $GLOBALS['log']->info("Mass Emailer(EmailMan) ConfigureSettings view"); + + $this->ss->assign("MOD", $mod_strings); + $this->ss->assign("APP", $app_strings); + $this->ss->assign("THEME", SugarThemeRegistry::current()->__toString()); + $this->ss->assign("RETURN_MODULE", "Administration"); + $this->ss->assign("RETURN_ACTION", "index"); + + $this->ss->assign("MODULE", $currentModule); + $this->ss->assign("PRINT_URL", "index.php?".$GLOBALS['request_string']); + + if (isset($focus->settings['massemailer_campaign_emails_per_run']) && !empty($focus->settings['massemailer_campaign_emails_per_run'])) { + $this->ss->assign("EMAILS_PER_RUN", $focus->settings['massemailer_campaign_emails_per_run']); + } else { + $this->ss->assign("EMAILS_PER_RUN", 500); + } + + if (!isset($focus->settings['massemailer_tracking_entities_location_type']) or empty($focus->settings['massemailer_tracking_entities_location_type']) or $focus->settings['massemailer_tracking_entities_location_type']=='1') { + $this->ss->assign("default_checked", "checked"); + $this->ss->assign("TRACKING_ENTRIES_LOCATION_STATE", "disabled"); + $this->ss->assign("TRACKING_ENTRIES_LOCATION",$mod_strings['TRACKING_ENTRIES_LOCATION_DEFAULT_VALUE']); + } else { + $this->ss->assign("userdefined_checked", "checked"); + $this->ss->assign("TRACKING_ENTRIES_LOCATION",$focus->settings["massemailer_tracking_entities_location"]); + } + + // Change the default campaign to not store a copy of each message. + if (!empty($focus->settings['massemailer_email_copy']) and $focus->settings['massemailer_email_copy']=='1') { + $this->ss->assign("yes_checked", "checked='checked'"); + } else { + $this->ss->assign("no_checked", "checked='checked'"); + } + + $email = new Email(); + $this->ss->assign('ROLLOVER', $email->rolloverStyle); + + $this->ss->assign("JAVASCRIPT",get_validate_record_js()); + $this->ss->display("modules/EmailMan/tpls/campaignconfig.tpl"); + } +} diff --git a/modules/EmailMan/views/view.config.php b/modules/EmailMan/views/view.config.php new file mode 100644 index 00000000..065d17c1 --- /dev/null +++ b/modules/EmailMan/views/view.config.php @@ -0,0 +1,183 @@ +".translate('LBL_MODULE_NAME','Administration')."", + translate('LBL_MASS_EMAIL_CONFIG_TITLE','Administration'), + ); + } + + /** + * @see SugarView::preDisplay() + */ + public function preDisplay() + { + global $current_user; + + if ( !is_admin($current_user) + && !is_admin_for_module($GLOBALS['current_user'],'Emails') + && !is_admin_for_module($GLOBALS['current_user'],'Campaigns') ) + sugar_die("Unauthorized access to administration."); + } + + /** + * @see SugarView::display() + */ + public function display() + { + global $mod_strings; + global $app_list_strings; + global $app_strings; + global $current_user; + global $sugar_config; + + + echo $this->getModuleTitle(false); + global $currentModule; + + + + + + $focus = new Administration(); + $focus->retrieveSettings(); //retrieve all admin settings. + $GLOBALS['log']->info("Mass Emailer(EmailMan) ConfigureSettings view"); + + $this->ss->assign("MOD", $mod_strings); + $this->ss->assign("APP", $app_strings); + + $this->ss->assign("RETURN_MODULE", "Administration"); + $this->ss->assign("RETURN_ACTION", "index"); + + $this->ss->assign("MODULE", $currentModule); + $this->ss->assign("PRINT_URL", "index.php?".$GLOBALS['request_string']); + $this->ss->assign("HEADER", getClassicModuleTitle("EmailMan", array("{MOD.LBL_CONFIGURE_SETTINGS}"), true)); + + $this->ss->assign("notify_fromaddress", $focus->settings['notify_fromaddress']); + $this->ss->assign("notify_send_from_assigning_user", (isset($focus->settings['notify_send_from_assigning_user']) && !empty($focus->settings['notify_send_from_assigning_user'])) ? "checked='checked'" : ""); + $this->ss->assign("notify_on", ($focus->settings['notify_on']) ? "checked='checked'" : ""); + $this->ss->assign("notify_fromname", $focus->settings['notify_fromname']); + $this->ss->assign("notify_allow_default_outbound_on", (!empty($focus->settings['notify_allow_default_outbound']) && $focus->settings['notify_allow_default_outbound']) ? "checked='checked'" : ""); + + $this->ss->assign("mail_smtptype", $focus->settings['mail_smtptype']); + $this->ss->assign("mail_smtpserver", $focus->settings['mail_smtpserver']); + $this->ss->assign("mail_smtpport", $focus->settings['mail_smtpport']); + $this->ss->assign("mail_smtpuser", $focus->settings['mail_smtpuser']); + $this->ss->assign("mail_smtpauth_req", ($focus->settings['mail_smtpauth_req']) ? "checked='checked'" : ""); + $this->ss->assign("MAIL_SSL_OPTIONS", get_select_options_with_id($app_list_strings['email_settings_for_ssl'], $focus->settings['mail_smtpssl'])); + + //Assign the current users email for the test send dialogue. + $this->ss->assign("CURRENT_USER_EMAIL", $current_user->email1); + + $showSendMail = FALSE; + $outboundSendTypeCSSClass = "yui-hidden"; + if(isset($sugar_config['allow_sendmail_outbound']) && $sugar_config['allow_sendmail_outbound']) + { + $showSendMail = TRUE; + $app_list_strings['notifymail_sendtype']['sendmail'] = 'sendmail'; + $outboundSendTypeCSSClass = ""; + } + + $this->ss->assign("OUTBOUND_TYPE_CLASS", $outboundSendTypeCSSClass); + $this->ss->assign("mail_sendtype_options", get_select_options_with_id($app_list_strings['notifymail_sendtype'], $focus->settings['mail_sendtype'])); + + /////////////////////////////////////////////////////////////////////////////// + //// USER EMAIL DEFAULTS + // editors + $editors = $app_list_strings['dom_email_editor_option']; + $newEditors = array(); + foreach($editors as $k => $v) { + if($k != "") { $newEditors[$k] = $v; } + } + + // preserve attachments + $preserveAttachments = ''; + if(isset($sugar_config['email_default_delete_attachments']) && $sugar_config['email_default_delete_attachments'] == true) { + $preserveAttachments = 'CHECKED'; + } + $this->ss->assign('DEFAULT_EMAIL_DELETE_ATTACHMENTS', $preserveAttachments); + //// END USER EMAIL DEFAULTS + /////////////////////////////////////////////////////////////////////////////// + + + //setting to manage. + //emails_per_run + //tracking_entities_location_type default or custom + //tracking_entities_location http://www.sugarcrm.com/track/ + + ////////////////////////////////////////////////////////////////////////////// + //// EMAIL SECURITY + if(!isset($sugar_config['email_xss']) || empty($sugar_config['email_xss'])) { + $sugar_config['email_xss'] = getDefaultXssTags(); + } + + foreach(unserialize(base64_decode($sugar_config['email_xss'])) as $k => $v) { + $this->ss->assign($k."Checked", 'CHECKED'); + } + + //clean_xss('here'); + //// END EMAIL SECURITY + /////////////////////////////////////////////////////////////////////////////// + + require_once('modules/Emails/Email.php'); + $email = new Email(); + $this->ss->assign('ROLLOVER', $email->rolloverStyle); + + $this->ss->assign("JAVASCRIPT",get_validate_record_js()); + $this->ss->display('modules/EmailMan/tpls/config.tpl'); + } +} diff --git a/modules/EmailMan/views/view.list.php b/modules/EmailMan/views/view.list.php new file mode 100644 index 00000000..c79ae806 --- /dev/null +++ b/modules/EmailMan/views/view.list.php @@ -0,0 +1,100 @@ +lv = new ListViewSmarty(); + $this->lv->export = false; + $this->lv->quickViewLinks = false; + } + + /** + * @see SugarView::_getModuleTitleParams() + */ + protected function _getModuleTitleParams($browserTitle = false) + { + global $mod_strings; + + return array( + "".translate('LBL_MODULE_NAME','Administration')."", + translate('LBL_MASS_EMAIL_MANAGER_TITLE','Administration'), + ); + } + + + function listViewPrepare(){ + $this->options['show_title'] = false; + parent::listViewPrepare(); + echo $this->getModuleTitle(false); + } + /** + * @see ViewList::listViewProcess() + */ + function listViewProcess() + { + parent::listViewProcess(); + + global $app_strings; + + echo "
    + +
    + + + + + + +
    "; + } +} diff --git a/modules/EmailMarketing/Delete.php b/modules/EmailMarketing/Delete.php new file mode 100644 index 00000000..2299a818 --- /dev/null +++ b/modules/EmailMarketing/Delete.php @@ -0,0 +1,69 @@ +retrieve($_REQUEST['record']); +if(!$focus->ACLAccess('Delete')){ + ACLController::displayNoAccess(true); + sugar_cleanup(true); +} +$focus->mark_deleted($_REQUEST['record']); + +if(isset($_REQUEST['record'])) +{ + $query = "DELETE FROM emailman WHERE marketing_id ='" . $_REQUEST['record'] ."'"; + $focus->db->query($query); +} + +header("Location: index.php?module=".$_REQUEST['return_module']."&action=".$_REQUEST['return_action']."&record=".$_REQUEST['return_id']); +?> \ No newline at end of file diff --git a/modules/EmailMarketing/DetailView.html b/modules/EmailMarketing/DetailView.html new file mode 100644 index 00000000..dc0901e9 --- /dev/null +++ b/modules/EmailMarketing/DetailView.html @@ -0,0 +1,95 @@ + + +{ERROR_STRING} +
    + + + + + + + + + + + + + + +
    + + + + {APP.LBL_REQUIRED_SYMBOL} {APP.NTC_REQUIRED}{ADMIN_EDIT}
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + +
    {MOD.LBL_NAME}{NAME} {MOD.LBL_STATUS_TEXT}{STATUS} 
    {MOD.LBL_FROM_MAILBOX_NAME}{FROM_MAILBOX_NAME} {MOD.LBL_FROM_NAME}{FROM_NAME} 
    {MOD.LBL_START_DATE_TIME}{DATE_START} {TIME_START}{MOD.LBL_TEMPLATE}{EMAIL_TEMPLATE} 
    {MOD.LBL_MESSAGE_FOR}{MESSAGE_FOR}   
    +
    +
    +{JAVASCRIPT} + diff --git a/modules/EmailMarketing/DetailView.php b/modules/EmailMarketing/DetailView.php new file mode 100644 index 00000000..f6e22d3b --- /dev/null +++ b/modules/EmailMarketing/DetailView.php @@ -0,0 +1,178 @@ +retrieve($_REQUEST['record']); +} + +global $theme; + + + +$GLOBALS['log']->info("EmailMarketing Edit View"); + +$xtpl=new XTemplate ('modules/EmailMarketing/DetailView.html'); + +$xtpl->assign("MOD", $mod_strings); +$xtpl->assign("APP", $app_strings); + +if (isset($_REQUEST['return_module'])) { + $xtpl->assign("RETURN_MODULE", $_REQUEST['return_module']); +} else { + $xtpl->assign("RETURN_MODULE", 'Campaigns'); +} +if (isset($_REQUEST['return_action'])) { + $xtpl->assign("RETURN_ACTION", $_REQUEST['return_action']); +} else { + $xtpl->assign("RETURN_ACTION", 'DetailView'); +} +if (isset($_REQUEST['return_id'])) { + $xtpl->assign("RETURN_ID", $_REQUEST['return_id']); +} else { + if (!empty($focus->campaign_id)) { + $xtpl->assign("RETURN_ID", $focus->campaign_id); + } +} + + +if($focus->campaign_id) { + $campaign_id=$focus->campaign_id; +} +else { + $campaign_id=$_REQUEST['campaign_id']; +} +$xtpl->assign("CAMPAIGN_ID", $campaign_id); + + +$xtpl->assign("PRINT_URL", "index.php?".$GLOBALS['request_string']); +$xtpl->assign("JAVASCRIPT", get_set_focus_js()); +$xtpl->assign("DATE_ENTERED", $focus->date_entered); +$xtpl->assign("DATE_MODIFIED", $focus->date_modified); +$xtpl->assign("ID", $focus->id); +$xtpl->assign("NAME", $focus->name); +$xtpl->assign("FROM_NAME", $focus->from_name); +$xtpl->assign("FROM_ADDR", $focus->from_addr); +$xtpl->assign("DATE_START", $focus->date_start); +$xtpl->assign("TIME_START", $focus->time_start); + +$email_templates_arr = get_bean_select_array(true, 'EmailTemplate','name'); +if($focus->template_id) { + $xtpl->assign("EMAIL_TEMPLATE", $email_templates_arr[$focus->template_id]); +} + +//include campaign utils.. +require_once('modules/Campaigns/utils.php'); +if (empty($_REQUEST['campaign_name'])) { + + $campaign = new Campaign(); + $campaign->retrieve($campaign_id); + $campaign_name=$campaign->name; +} else { + $campaign_name=$_REQUEST['campaign_name']; +} + +$params = array(); +$params[] = "{$mod_strings['LNK_CAMPAIGN_LIST']}"; +$params[] = "{$campaign_name}"; +$params[] = $focus->name; + +echo getClassicModuleTitle($focus->module_dir, $params, true); + +if (!empty($focus->all_prospect_lists)) { + $xtpl->assign("MESSAGE_FOR", $mod_strings['LBL_ALL_PROSPECT_LISTS']); +} else { + $xtpl->assign("MESSAGE_FOR", $mod_strings['LBL_RELATED_PROSPECT_LISTS']); +} + +if (!empty($focus->status)) { + $xtpl->assign("STATUS",$app_list_strings['email_marketing_status_dom'][$focus->status]); +} +$emails=array(); +$mailboxes=get_campaign_mailboxes($emails); +//_ppd($emails[$focus->inbound_email_id]); +if (!empty($focus->inbound_email_id) && isset($mailboxes[$focus->inbound_email_id])) { + $xtpl->assign("FROM_MAILBOX_NAME", $mailboxes[$focus->inbound_email_id]." <{$emails[$focus->inbound_email_id]}>"); +} + +$xtpl->parse("main"); +$xtpl->out("main"); + + +$javascript = new javascript(); +$javascript->setFormName('EditView'); +$javascript->setSugarBean($focus); +$javascript->addAllFields(''); +echo $javascript->getScript(); + +require_once('include/SubPanel/SubPanelTiles.php'); +$subpanel = new SubPanelTiles($focus, 'EmailMarketing'); + +if ($focus->all_prospect_lists == 1) { + $subpanel->subpanel_definitions->exclude_tab('prospectlists'); +} +else { + $subpanel->subpanel_definitions->exclude_tab('allprospectlists'); + +} + +echo $subpanel->display(); + +?> \ No newline at end of file diff --git a/modules/EmailMarketing/EditView.html b/modules/EmailMarketing/EditView.html new file mode 100644 index 00000000..2c92685b --- /dev/null +++ b/modules/EmailMarketing/EditView.html @@ -0,0 +1,226 @@ + + +{ERROR_STRING} +
    + + + + + + + + + + + + + +
    + + + {APP.LBL_REQUIRED_SYMBOL} {APP.NTC_REQUIRED}{ADMIN_EDIT}
    + + +
    + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    {MOD.LBL_NAME} {APP.LBL_REQUIRED_SYMBOL}{MOD.LBL_STATUS_TEXT} {APP.LBL_REQUIRED_SYMBOL}
    {MOD.LBL_FROM_MAILBOX_NAME} {DEFAULT_FROM_EMAIL}{MOD.LBL_FROM_NAME} {APP.LBL_REQUIRED_SYMBOL}
    {MOD.LBL_START_DATE_TIME} {APP.LBL_REQUIRED_SYMBOL} +
    {CALENDAR_DATEFORMAT} {TIME_MERIDIEM}
    {USER_DATEFORMAT}{TIME_FORMAT}
    {MOD.LBL_TEMPLATE} {APP.LBL_REQUIRED_SYMBOL} + + +   + {MOD.LBL_CREATE_EMAIL_TEMPLATE} +  {MOD.LBL_EDIT_EMAIL_TEMPLATE} + + +
    {MOD.LBL_MESSAGE_FOR} {APP.LBL_REQUIRED_SYMBOL}{MOD.LBL_ALL_PROSPECT_LISTS}  
       
        
    +
    +
    + +
    + +{JAVASCRIPT} + + diff --git a/modules/EmailMarketing/EditView.php b/modules/EmailMarketing/EditView.php new file mode 100644 index 00000000..ef3f7d9a --- /dev/null +++ b/modules/EmailMarketing/EditView.php @@ -0,0 +1,224 @@ +retrieve($_REQUEST['record']); +} + +if(isset($_REQUEST['isDuplicate']) && $_REQUEST['isDuplicate'] == 'true') { + $focus->id = ""; +} +global $theme; + + + +$GLOBALS['log']->info("EmailMarketing Edit View"); +$xtpl=new XTemplate ('modules/EmailMarketing/EditView.html'); +if(!ACLController::checkAccess('EmailTemplates', 'edit', true)){ + unset($mod_strings['LBL_CREATE_EMAIL_TEMPLATE']); + unset($mod_strings['LBL_EDIT_EMAIL_TEMPLATE']); +} +$xtpl->assign("MOD", $mod_strings); +$xtpl->assign("APP", $app_strings); +$xtpl->assign("THEME", SugarThemeRegistry::current()->__toString()); +// Unimplemented until jscalendar language files are fixed +// $xtpl->assign("CALENDAR_LANG", ((empty($cal_codes[$current_language])) ? $cal_codes[$default_language] : $cal_codes[$current_language])); +$xtpl->assign("CALENDAR_LANG", "en"); +$xtpl->assign("USER_DATEFORMAT", '('. $timedate->get_user_date_format().')'); +$xtpl->assign("CALENDAR_DATEFORMAT", $timedate->get_cal_date_format()); +$xtpl->assign("TIME_MERIDIEM", $timedate->AMPMMenu('', $focus->time_start)); + +if (isset($_REQUEST['return_module'])) { + $xtpl->assign("RETURN_MODULE", $_REQUEST['return_module']); +} else { + $xtpl->assign("RETURN_MODULE", 'Campaigns'); +} +if (isset($_REQUEST['return_action'])) { + $xtpl->assign("RETURN_ACTION", $_REQUEST['return_action']); +} else { + $xtpl->assign("RETURN_ACTION", 'DetailView'); +} +if (isset($_REQUEST['return_id'])) { + $xtpl->assign("RETURN_ID", $_REQUEST['return_id']); +} else { + if (!empty($focus->campaign_id)) { + $xtpl->assign("RETURN_ID", $focus->campaign_id); + } +} + +if($focus->campaign_id) { + $campaign_id=$focus->campaign_id; +} +else { + $campaign_id=$_REQUEST['campaign_id']; +} +$xtpl->assign("CAMPAIGN_ID", $campaign_id); + + +$xtpl->assign("PRINT_URL", "index.php?".$GLOBALS['request_string']); +$xtpl->assign("JAVASCRIPT", get_set_focus_js().get_validate_record_js()); +$xtpl->assign("DATE_ENTERED", $focus->date_entered); +$xtpl->assign("DATE_MODIFIED", $focus->date_modified); +$xtpl->assign("ID", $focus->id); +$xtpl->assign("NAME", $focus->name); +$xtpl->assign("FROM_NAME", $focus->from_name); +$xtpl->assign("FROM_ADDR", $focus->from_addr); +$xtpl->assign("DATE_START", $focus->date_start); +$xtpl->assign("TIME_START", $focus->time_start); +$xtpl->assign("TIME_FORMAT", '('. $timedate->get_user_time_format().')'); + +$email_templates_arr = get_bean_select_array(true, 'EmailTemplate','name','','name'); +if($focus->template_id) { + $xtpl->assign("TEMPLATE_ID", $focus->template_id); + $xtpl->assign("EMAIL_TEMPLATE_OPTIONS", get_select_options_with_id($email_templates_arr, $focus->template_id)); + $xtpl->assign("EDIT_TEMPLATE","visibility:inline"); +} +else { + $xtpl->assign("EMAIL_TEMPLATE_OPTIONS", get_select_options_with_id($email_templates_arr, "")); + $xtpl->assign("EDIT_TEMPLATE","visibility:hidden"); +} + +//include campaign utils.. +require_once('modules/Campaigns/utils.php'); +if (empty($_REQUEST['campaign_name'])) { + + $campaign = new Campaign(); + $campaign->retrieve($campaign_id); + $campaign_name=$campaign->name; +} else { + $campaign_name=$_REQUEST['campaign_name']; +} + +$params = array(); +$params[] = "{$mod_strings['LNK_CAMPAIGN_LIST']}"; +$params[] = "{$campaign_name}"; +if(empty($focus->id)){ + $params[] = $GLOBALS['app_strings']['LBL_CREATE_BUTTON_LABEL']." ".$mod_strings['LBL_MODULE_NAME']; +}else{ + $params[] = "{$focus->name}"; + $params[] = $GLOBALS['app_strings']['LBL_EDIT_BUTTON_LABEL']; +} + +echo getClassicModuleTitle($focus->module_dir, $params, true); +$scope_options=get_message_scope_dom($campaign_id,$campaign_name,$focus->db); +$prospectlists=array(); +if (isset($focus->all_prospect_lists) && $focus->all_prospect_lists==1) { + $xtpl->assign("ALL_PROSPECT_LISTS_CHECKED","checked"); + $xtpl->assign("MESSAGE_FOR_DISABLED","disabled"); +} +else { + //get select prospect list. + if (!empty($focus->id)) { + $focus->load_relationship('prospectlists'); + $prospectlists=$focus->prospectlists->get(); + }; +} +if (empty($prospectlists)) $prospectlists=array(); +if (empty($scope_options)) $scope_options=array(); +$xtpl->assign("SCOPE_OPTIONS", get_select_options_with_id($scope_options, $prospectlists)); + +$emails=array(); +$mailboxes=get_campaign_mailboxes($emails); +$mailboxes_with_from_name = get_campaign_mailboxes($emails, false); + +//add empty options. +$emails['']='nobody@example.com'; +$mailboxes['']=''; + +//inbound_email_id +$default_email_address='nobody@example.com'; +$from_emails = ''; +foreach ($mailboxes_with_from_name as $id=>$name) { + if (!empty($from_emails)) { + $from_emails.=','; + } + if ($id=='') { + $from_emails.="'EMPTY','$name','$emails[$id]'"; + } else { + $from_emails.="'$id','$name','$emails[$id]'"; + } + if ($id==$focus->inbound_email_id) { + $default_email_address=$emails[$id]; + } +} +$xtpl->assign("FROM_EMAILS",$from_emails); +$xtpl->assign("DEFAULT_FROM_EMAIL",$default_email_address); + +if (empty($focus->inbound_email_id)) { + $xtpl->assign("MAILBOXES", get_select_options_with_id($mailboxes, '')); +} else { + $xtpl->assign("MAILBOXES", get_select_options_with_id($mailboxes, $focus->inbound_email_id)); +} + +$xtpl->assign("STATUS_OPTIONS", get_select_options_with_id($app_list_strings['email_marketing_status_dom'], $focus->status)); + +$xtpl->parse("main"); +$xtpl->out("main"); + + + +$javascript = new javascript(); +$javascript->setFormName('EditView'); +$javascript->setSugarBean($focus); +$javascript->addAllFields(''); +echo $javascript->getScript(); +?> diff --git a/modules/EmailMarketing/EmailMarketing.php b/modules/EmailMarketing/EmailMarketing.php new file mode 100644 index 00000000..16a111ce --- /dev/null +++ b/modules/EmailMarketing/EmailMarketing.php @@ -0,0 +1,173 @@ +date_start)); + if (count($date_start_array)==2) { + $this->time_start = $date_start_array[1]; + $this->date_start = $date_start_array[0]; + } + return $this; + } + + function get_summary_text() + { + return $this->name; + } + + function create_export_query($order_by, $where) + { + return $this->create_new_list_query($order_by, $where); + } + + function get_list_view_data(){ + + $temp_array = $this->get_list_view_array(); + + $id = $temp_array['ID']; + $template_id = $temp_array['TEMPLATE_ID']; + + //mode is set by schedule.php from campaigns module. + if (!isset($this->mode) or empty($this->mode) or $this->mode!='test') { + $this->mode='rest'; + } + + if ($temp_array['ALL_PROSPECT_LISTS']==1) { + $query="SELECT name from prospect_lists "; + $query.=" INNER JOIN prospect_list_campaigns plc ON plc.prospect_list_id = prospect_lists.id"; + $query.=" WHERE plc.campaign_id='{$temp_array['CAMPAIGN_ID']}'"; + $query.=" AND prospect_lists.deleted=0"; + $query.=" AND plc.deleted=0"; + if ($this->mode=='test') { + $query.=" AND prospect_lists.list_type='test'"; + } else { + $query.=" AND prospect_lists.list_type!='test'"; + } + } else { + $query="SELECT name from prospect_lists "; + $query.=" INNER JOIN email_marketing_prospect_lists empl ON empl.prospect_list_id = prospect_lists.id"; + $query.=" WHERE empl.email_marketing_id='{$id}'"; + $query.=" AND prospect_lists.deleted=0"; + $query.=" AND empl.deleted=0"; + if ($this->mode=='test') { + $query.=" AND prospect_lists.list_type='test'"; + } else { + $query.=" AND prospect_lists.list_type!='test'"; + } + } + $res = $this->db->query($query); + while (($row = $this->db->fetchByAssoc($res)) != null) { + if (!empty($temp_array['PROSPECT_LIST_NAME'])) { + $temp_array['PROSPECT_LIST_NAME'].="
    "; + } + $temp_array['PROSPECT_LIST_NAME'].=$row['name']; + } + return $temp_array; + } + + function bean_implements($interface){ + switch($interface){ + case 'ACL':return true; + } + return false; + } + + function get_all_prospect_lists() { + + $query="select prospect_lists.* from prospect_lists "; + $query.=" left join prospect_list_campaigns on prospect_list_campaigns.prospect_list_id=prospect_lists.id"; + $query.=" where prospect_list_campaigns.deleted=0"; + $query.=" and prospect_list_campaigns.campaign_id='$this->campaign_id'"; + $query.=" and prospect_lists.deleted=0"; + $query.=" and prospect_lists.list_type not like 'exempt%'"; + + return $query; + } +} +?> \ No newline at end of file diff --git a/modules/EmailMarketing/Forms.php b/modules/EmailMarketing/Forms.php new file mode 100644 index 00000000..b19a2943 --- /dev/null +++ b/modules/EmailMarketing/Forms.php @@ -0,0 +1,83 @@ + +function verify_data(form,formname) { + if (!check_form(formname)) + return false; + + var isError = false; + var errorMessage = ""; + + var thecheckbox=document.getElementById('all_prospect_lists'); + var theselectbox=document.getElementById('message_for'); + + if (!thecheckbox.checked && theselectbox.selectedIndex < 0) { + isError=true; + errorMessage="$err_lbl_send_message"; + } + + if (isError == true) { + alert("$err_missing_required_fields" + errorMessage); + return false; + } + return true; +} + + +EOQ; + +return $the_script; + +} + +/** + * Create HTML form to enter a new record with the minimum necessary fields. + * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc. + * All Rights Reserved. + * Contributor(s): ______________________________________.. + */ + +?> diff --git a/modules/EmailMarketing/Menu.php b/modules/EmailMarketing/Menu.php new file mode 100644 index 00000000..ae00c4c7 --- /dev/null +++ b/modules/EmailMarketing/Menu.php @@ -0,0 +1,57 @@ + \ No newline at end of file diff --git a/modules/EmailMarketing/Save.php b/modules/EmailMarketing/Save.php new file mode 100644 index 00000000..3727035a --- /dev/null +++ b/modules/EmailMarketing/Save.php @@ -0,0 +1,142 @@ +merge_time_meridiem($_POST['time_start'],$timedate->get_time_format(), $_POST['meridiem']); +} + +if(empty($_REQUEST['time_start'])) { + $_REQUEST['date_start'] = $_REQUEST['date_start'] . ' 00:00'; + $_POST['date_start'] = $_POST['date_start'] . ' 00:00'; +} else { + $_REQUEST['date_start'] = $_REQUEST['date_start'] . ' ' . $_REQUEST['time_start']; + $_POST['date_start'] = $_POST['date_start'] . ' ' . $_POST['time_start']; +} + +$marketing = new EmailMarketing(); +if (isset($_POST['record']) && !empty($_POST['record'])) { + $marketing->retrieve($_POST['record']); +} +if(!$marketing->ACLAccess('Save')){ + ACLController::displayNoAccess(true); + sugar_cleanup(true); +} + +if (!empty($_POST['assigned_user_id']) && ($marketing->assigned_user_id != $_POST['assigned_user_id']) && ($_POST['assigned_user_id'] != $current_user->id)) { + $check_notify = TRUE; +} +else { + $check_notify = FALSE; +} +foreach($marketing->column_fields as $field) +{ + if ($field == 'all_prospect_lists') { + if(isset($_POST[$field]) && $_POST[$field]='on' ) + { + $marketing->$field = 1; + } else { + $marketing->$field = 0; + } + }else { + if(isset($_POST[$field])) + { + $value = $_POST[$field]; + $marketing->$field = $value; + } + } +} + +foreach($marketing->additional_column_fields as $field) +{ + if(isset($_POST[$field])) + { + $value = $_POST[$field]; + $marketing->$field = $value; + + } +} + +$marketing->campaign_id = $_REQUEST['campaign_id']; +$marketing->save($check_notify); + +//add prospect lists to campaign. +$marketing->load_relationship('prospectlists'); +$prospectlists=$marketing->prospectlists->get(); +if ($marketing->all_prospect_lists==1) { + //remove all related prospect lists. + if (!empty($prospectlists)) { + $marketing->prospectlists->delete($marketing->id); + } +} else { + if (is_array($_REQUEST['message_for'])) { + foreach ($_REQUEST['message_for'] as $prospect_list_id) { + + $key=array_search($prospect_list_id,$prospectlists); + if ($key === null or $key === false) { + $marketing->prospectlists->add($prospect_list_id); + } else { + unset($prospectlists[$key]); + } + } + if (count($prospectlists) != 0) { + foreach ($prospectlists as $key=>$list_id) { + $marketing->prospectlists->delete($marketing->id,$list_id); + } + } + } +} +if($_REQUEST['action'] != 'WizardMarketingSave'){ + $header_URL = "Location: index.php?action=DetailView&module=Campaigns&record={$_REQUEST['campaign_id']}"; + $GLOBALS['log']->debug("about to post header URL of: $header_URL"); + header($header_URL); +} +?> \ No newline at end of file diff --git a/modules/EmailMarketing/SubPanelView.html b/modules/EmailMarketing/SubPanelView.html new file mode 100644 index 00000000..8c2c529b --- /dev/null +++ b/modules/EmailMarketing/SubPanelView.html @@ -0,0 +1,65 @@ + + + + + + + + + + + + + + + + + + + + + + + + +
    {MOD.LBL_LIST_NAME}{MOD.LBL_LIST_DATE_START}{MOD.LBL_LIST_STATUS}{MOD.LBL_LIST_TEMPLATE_NAME}
    {EMAILMARKETING.NAME}{EMAILMARKETING.DATE_START}{EMAILMARKETING.STATUS}{EMAILMARKETING.TEMPLATE_NAME}{EDIT_INLINE_PNG} {APP.LNK_EDIT}   {REMOVE_INLINE_PNG} {APP.LNK_REMOVE}
    + diff --git a/modules/EmailMarketing/SubPanelView.php b/modules/EmailMarketing/SubPanelView.php new file mode 100644 index 00000000..8e4481b6 --- /dev/null +++ b/modules/EmailMarketing/SubPanelView.php @@ -0,0 +1,90 @@ +\n"; +$button .= "\n"; +$button .= "\n"; +$button .= "\n"; +$button .= "\n"; +$button .= "\n"; +$button .= "\n"; + +$button .= "\n"; + +$button .= "\n"; + +$ListView = new ListView(); +$ListView->initNewXTemplate('modules/EmailMarketing/SubPanelView.html', $current_module_strings); + +$ListView->xTemplateAssign("EDIT_INLINE_PNG", SugarThemeRegistry::current()->getImage('edit_inline','align="absmiddle" alt="'.$app_strings['LNK_EDIT'].'" border="0"')); +$ListView->xTemplateAssign("REMOVE_INLINE_PNG", SugarThemeRegistry::current()->getImage('delete_inline','align="absmiddle" alt="'.$app_strings['LNK_REMOVE'].'" border="0"')); + +$ListView->xTemplateAssign("RETURN_URL", "&return_module=".$currentModule."&return_action=DetailView&return_id=".$focus->id); +$ListView->setHeaderTitle($current_module_strings['LBL_MODULE_NAME'] ); +$ListView->setHeaderText($button); +$ListView->processListView($focus_list, "main", "EMAILMARKETING"); + +?> \ No newline at end of file diff --git a/modules/EmailMarketing/field_arrays.php b/modules/EmailMarketing/field_arrays.php new file mode 100644 index 00000000..a7acc72a --- /dev/null +++ b/modules/EmailMarketing/field_arrays.php @@ -0,0 +1,58 @@ + array ( + 'id', 'date_entered', 'date_modified', + 'modified_user_id', 'created_by', 'name', + 'from_addr', 'from_name', 'reply_to_name', 'reply_to_addr', 'date_start','time_start', 'template_id', 'campaign_id','status','inbound_email_id','all_prospect_lists', + ), + 'list_fields' => array ( + 'id','name','date_start','time_start', 'template_id', 'status','all_prospect_lists','campaign_id', + ), + 'required_fields' => array ( + 'name'=>1, 'from_name'=>1,'from_addr'=>1, 'date_start'=>1,'time_start'=>1, + 'template_id'=>1, 'status'=>1, + ), +); +?> \ No newline at end of file diff --git a/modules/EmailMarketing/language/en_us.lang.php b/modules/EmailMarketing/language/en_us.lang.php new file mode 100644 index 00000000..e93136db --- /dev/null +++ b/modules/EmailMarketing/language/en_us.lang.php @@ -0,0 +1,108 @@ + '"Reply-to" Address: ', + 'LBL_REPLY_NAME' => '"Reply-to" Name: ', + + 'LBL_MODULE_NAME' => 'Email Marketing', + 'LBL_MODULE_TITLE' => 'Email Marketing: Home', + 'LBL_LIST_FORM_TITLE' => 'Email Marketing Campaigns', + 'LBL_NAME' => 'Name: ', + 'LBL_LIST_NAME' => 'Name', + 'LBL_LIST_FROM_ADDR' => 'From Email', + 'LBL_LIST_DATE_START' => 'Start Date', + 'LBL_LIST_TEMPLATE_NAME' => 'Email Template', + 'LBL_LIST_STATUS' => 'Status', + 'LBL_STATUS' => 'Status', + 'LBL_STATUS_TEXT' => 'Status:' , + 'LBL_TEMPLATE_NAME'=>'Template Name', + 'LBL_DATE_ENTERED' => 'Date Entered', + 'LBL_DATE_MODIFIED' => 'Date Modified', + 'LBL_MODIFIED' => 'Modified by: ', + 'LBL_CREATED' => 'Created by: ', + 'LBL_MESSAGE_FOR' => 'Send This Message To:', + 'LBL_MESSAGE_FOR_ID' => 'Message For', + + 'LBL_FROM_NAME' => 'From Name: ', + 'LBL_FROM_ADDR' => 'From Email Address: ', + 'LBL_DATE_START' => 'Start Date', + 'LBL_TIME_START' => 'Start Time', + 'LBL_START_DATE_TIME' => 'Start Date & Time: ', + 'LBL_TEMPLATE' => 'Email Template: ', + + 'LBL_MODIFIED_BY' => 'Modified by: ', + 'LBL_CREATED_BY' => 'Created by: ', + 'LBL_DATE_CREATED' => 'Created date: ', + 'LBL_DATE_LAST_MODIFIED' => 'Modified date: ', + + 'LNK_NEW_CAMPAIGN' => 'Create Campaign', + 'LNK_CAMPAIGN_LIST' => 'Campaigns', + 'LNK_NEW_PROSPECT_LIST' => 'Create Target List', + 'LNK_PROSPECT_LIST_LIST' => 'Target Lists', + 'LNK_NEW_PROSPECT' => 'Create Target', + 'LNK_PROSPECT_LIST' => 'Targets', + 'LBL_DEFAULT_SUBPANEL_TITLE'=>'Email Marketing', + 'LBL_CREATE_EMAIL_TEMPLATE'=> 'Create', + 'LBL_EDIT_EMAIL_TEMPLATE'=> 'Edit', + 'LBL_FROM_MAILBOX'=>'From Mailbox', + 'LBL_FROM_MAILBOX_NAME'=>'Use Mailbox:', + 'LBL_PROSPECT_LIST_SUBPANEL_TITLE'=>'Target Lists', + 'LBL_ALL_PROSPECT_LISTS'=>'Select to choose all Target List(s) in the Campaign.', + 'LBL_RELATED_PROSPECT_LISTS'=>'All Target List(s) related to this message.', + 'LBL_PROSPECT_LIST_NAME'=>'Target List Name', + 'LBL_LIST_PROSPECT_LIST_NAME'=>'Targeted Lists', + 'LBL_MODULE_SEND_TEST'=>'Campaign: Send Test', + 'LBL_MODULE_SEND_EMAILS'=>'Campaign: Send Emails', + 'LBL_SCHEDULE_MESSAGE_TEST'=>'Please select the campaign messages that you would like to test:', + 'LBL_SCHEDULE_MESSAGE_EMAILS'=>'Please select the campaign messages that you would like to schedule for distribution on the specified start date and time:', + 'LBL_SCHEDULE_BUTTON_TITLE'=>'Send', + 'LBL_SCHEDULE_BUTTON_LABEL'=>'Send', + 'LBL_SCHEDULE_BUTTON_KEY'=>'T', + + + +); +?> \ No newline at end of file diff --git a/modules/EmailMarketing/metadata/subpaneldefs.php b/modules/EmailMarketing/metadata/subpaneldefs.php new file mode 100644 index 00000000..79e917eb --- /dev/null +++ b/modules/EmailMarketing/metadata/subpaneldefs.php @@ -0,0 +1,67 @@ + array( + 'prospectlists' => array( + 'order' => 10, + 'sort_order' => 'asc', + 'sort_by' => 'name', + 'module' => 'ProspectLists', + 'get_subpanel_data'=>'prospectlists', + 'set_subpanel_data'=>'prospectlists', + 'subpanel_name' => 'default', + 'title_key' => 'LBL_PROSPECT_LIST_SUBPANEL_TITLE', + 'top_buttons' => array(), + ), + 'allprospectlists' => array( + 'order' => 20, + 'module' => 'ProspectLists', + 'sort_order' => 'asc', + 'sort_by' => 'name', + 'get_subpanel_data'=>'function:get_all_prospect_lists', + 'set_subpanel_data'=>'prospectlists', + 'subpanel_name' => 'default', + 'title_key' => 'LBL_PROSPECT_LIST_SUBPANEL_TITLE', + 'top_buttons' => array(), + ), + ) +); +?> \ No newline at end of file diff --git a/modules/EmailMarketing/metadata/subpanels/default.php b/modules/EmailMarketing/metadata/subpanels/default.php new file mode 100644 index 00000000..5cd9f06e --- /dev/null +++ b/modules/EmailMarketing/metadata/subpanels/default.php @@ -0,0 +1,89 @@ + array( + array('widget_class' => 'SubPanelTopCreateButton'), + ), + + 'where' => '', + + + 'list_fields'=> array( + 'name' => array( + 'vname' => 'LBL_LIST_NAME', + 'widget_class' => 'SubPanelDetailViewLink', + 'width' => '40%', + ), + 'date_start'=>array( + 'vname' => 'LBL_LIST_DATE_START', + 'width' => '20%', + + ), + 'status'=>array( + 'vname' => 'LBL_LIST_STATUS', + 'width' => '15%', + ), + 'template_name'=>array( + 'vname' => 'LBL_LIST_TEMPLATE_NAME', + 'width' => '15%', + 'widget_class' => 'SubPanelDetailViewLink', + 'target_record_key' => 'template_id', + 'target_module' => 'EmailTemplates', + + ), + 'edit_button'=>array( + 'vname' => 'LBL_EDIT_BUTTON', + 'widget_class' => 'SubPanelEditButton', + 'module' => 'EmailMarketing', + 'width' => '5%', + ), + 'remove_button'=>array( + 'vname' => 'LBL_REMOVE', + 'widget_class' => 'SubPanelRemoveButton', + 'module' => 'EmailMarketing', + 'width' => '5%', + ), + 'time_start'=>array( + 'usage'=>'query_only' + ), + ), +); + +?> \ No newline at end of file diff --git a/modules/EmailMarketing/subpanels/default.php b/modules/EmailMarketing/subpanels/default.php new file mode 100644 index 00000000..5036f4db --- /dev/null +++ b/modules/EmailMarketing/subpanels/default.php @@ -0,0 +1,88 @@ + array( + array('widget_class' => 'SubPanelTopCreateButton'), + ), + + 'where' => '', + + + 'list_fields'=> array( + 'name' => array( + 'vname' => 'LBL_LIST_NAME', + 'widget_class' => 'SubPanelDetailViewLink', + 'width' => '40%', + ), + 'date_start'=>array( + 'widget_class' => 'SubPanelConcat', + 'vname' => 'LBL_LIST_DATE_START', + 'width' => '20%', + 'source'=> array('date_start',' ','time_start'), + ), + 'status'=>array( + 'vname' => 'LBL_LIST_STATUS', + 'width' => '15%', + ), + 'template_name'=>array( + 'vname' => 'LBL_LIST_TEMPLATE_NAME', + 'width' => '15%', + 'widget_class' => 'SubPanelDetailViewLink', + 'target_record_key' => 'template_id', + 'target_module' => 'EmailTemplates', + + ), + 'edit_button'=>array( + 'widget_class' => 'SubPanelEditButton', + 'module' => 'EmailMarketing', + 'width' => '5%', + ), + 'remove_button'=>array( + 'widget_class' => 'SubPanelRemoveButton', + 'module' => 'EmailMarketing', + 'width' => '5%', + ), + 'time_start'=>array( + 'usage'=>'query_only' + ), + ), +); + +?> \ No newline at end of file diff --git a/modules/EmailMarketing/vardefs.php b/modules/EmailMarketing/vardefs.php new file mode 100644 index 00000000..50314b4d --- /dev/null +++ b/modules/EmailMarketing/vardefs.php @@ -0,0 +1,226 @@ + 'email_marketing' + ,'fields' => array ( + 'id' => + array ( + 'name' => 'id', + 'vname' => 'LBL_NAME', + 'type' => 'id', + 'required'=>true, + ), + 'deleted' => array ( + 'name' => 'deleted', + 'vname' => 'LBL_CREATED_BY', + 'type' => 'bool', + 'required' => false, + 'reportable'=>false, + ), + 'date_entered' => + array ( + 'name' => 'date_entered', + 'vname' => 'LBL_DATE_ENTERED', + 'type' => 'datetime', + 'required'=>true, + ), + 'date_modified' => + array ( + 'name' => 'date_modified', + 'vname' => 'LBL_DATE_MODIFIED', + 'type' => 'datetime', + 'required'=>true, + ), + 'modified_user_id' => + array ( + 'name' => 'modified_user_id', + 'rname' => 'user_name', + 'id_name' => 'modified_user_id', + 'vname' => 'LBL_MODIFIED_BY', + 'type' => 'assigned_user_name', + 'table' => 'users', + 'isnull' => 'false', + 'dbType' => 'id' + ), + 'created_by' => + array ( + 'name' => 'created_by', + 'rname' => 'user_name', + 'id_name' => 'modified_user_id', + 'vname' => 'LBL_CREATED_BY', + 'type' => 'assigned_user_name', + 'table' => 'users', + 'isnull' => 'false', + 'dbType' => 'id' + ), + 'name' => + array ( + 'name' => 'name', + 'vname' => 'LBL_NAME', + 'type' => 'varchar', + 'len' => '255', + 'importable' => 'required', + ), + 'from_name' => //starting from 4.0 from_name is obsolete..replaced with inbound_email_id + array ( + 'name' => 'from_name', + 'vname' => 'LBL_FROM_NAME', + 'type' => 'varchar', + 'len' => '100', + 'importable' => 'required', + ), + 'from_addr' => + array ( + 'name' => 'from_addr', + 'vname' => 'LBL_FROM_ADDR', + 'type' => 'varchar', + 'len' => '100', + 'importable' => 'required', + ), + 'reply_to_name' => + array ( + 'name' => 'reply_to_name', + 'vname' => 'LBL_REPLY_NAME', + 'type' => 'varchar', + 'len' => '100', + ), + 'reply_to_addr' => + array ( + 'name' => 'reply_to_addr', + 'vname' => 'LBL_REPLY_ADDR', + 'type' => 'varchar', + 'len' => '100', + ), + 'inbound_email_id' => + array ( + 'name' => 'inbound_email_id', + 'vname' => 'LBL_FROM_MAILBOX', + 'type' => 'varchar', + 'len' => '36', + ), + 'date_start' => + array ( + 'name' => 'date_start', + 'vname' => 'LBL_DATE_START', + 'type' => 'datetime', + 'importable' => 'required', + ), + + 'template_id' => + array ( + 'name' => 'template_id', + 'vname' => 'LBL_TEMPLATE', + 'type' => 'id', + 'required'=>true, + 'importable' => 'required', + ), + 'status' => + array ( + 'name' => 'status', + 'vname' => 'LBL_STATUS', + 'type' => 'enum', + 'len' => 100, + 'required'=>true, + 'options' => 'email_marketing_status_dom', + 'importable' => 'required', + ), + 'campaign_id' => + array ( + 'name' => 'campaign_id', + 'vname' => 'LBL_CAMPAIGN_ID', + 'type' => 'id', + 'isnull' => true, + 'required'=>false, + ), + 'all_prospect_lists' => array ( + 'name' => 'all_prospect_lists', + 'vname' => 'LBL_ALL_PROSPECT_LISTS', + 'type' => 'bool', + 'default'=> 0, + ), +//no-db-fields. + 'template_name' => + array ( + 'name' => 'template_name', + 'rname' => 'name', + 'id_name' => 'template_id', + 'vname' => 'LBL_TEMPLATE_NAME', + 'type' => 'relate', + 'table' => 'email_templates', + 'isnull' => 'true', + 'module' => 'EmailTemplates', + 'dbType' => 'varchar', + 'link'=>'emailtemplate', + 'len' => '255', + 'source'=>'non-db', + ), + 'prospect_list_name' => + array ( + 'name' => 'prospect_list_name', + 'vname' => 'LBL_PROSPECT_LIST_NAME', + 'type' => 'varchar', + 'len'=>100, + 'source'=>'non-db', + ), + +//related fields. + 'prospectlists'=> array ( + 'name' => 'prospectlists', + 'type' => 'link', + 'relationship' => 'email_marketing_prospect_lists', + 'source'=>'non-db', + ), + 'emailtemplate'=> array ( + 'name' => 'emailtemplate', + 'type' => 'link', + 'relationship' => 'email_template_email_marketings', + 'source'=>'non-db', + ), + ), + 'indices' => array ( + array('name' =>'emmkpk', 'type' =>'primary', 'fields'=>array('id')), + array('name' =>'idx_emmkt_name', 'type'=>'index', 'fields'=>array('name')), + array('name' =>'idx_emmkit_del', 'type'=>'index', 'fields'=>array('deleted')), + ), + 'relationships' => array ( + 'email_template_email_marketings' => array('lhs_module'=> 'EmailTemplates', 'lhs_table'=> 'email_templates', 'lhs_key' => 'id', + 'rhs_module'=> 'EmailMarketing', 'rhs_table'=> 'email_marketing', 'rhs_key' => 'template_id', + 'relationship_type'=>'one-to-many'), + ), +); +?> diff --git a/modules/EmailTemplates/AttachFiles.php b/modules/EmailTemplates/AttachFiles.php new file mode 100644 index 00000000..52b3c938 --- /dev/null +++ b/modules/EmailTemplates/AttachFiles.php @@ -0,0 +1,74 @@ +debug(print_r($_FILES, true)); + $file_ext_allow = FALSE; + +if (!is_dir($GLOBALS['sugar_config']['cache_dir'].'images/')) + mkdir_recursive($GLOBALS['sugar_config']['cache_dir'].'images/'); + +// cn: bug 11012 - fixed some MIME types not getting picked up. Also changed array iterator. +$imgType = array('image/gif', 'image/png', 'image/x-png', 'image/bmp', 'image/jpeg', 'image/jpg', 'image/pjpeg'); + +$ret = array(); + +foreach($_FILES as $k => $file) { + if(in_array(strtolower($_FILES[$k]['type']), $imgType)) { + $dest = $GLOBALS['sugar_config']['cache_dir'].'images/'.$_FILES[$k]['name']; + if(is_uploaded_file($_FILES[$k]['tmp_name'])) { + move_uploaded_file($_FILES[$k]['tmp_name'], $dest); + $ret[] = $dest; + } + } +} + +if (!empty($ret)) { + $json = getJSONobj(); + echo $json->encode($ret); + //return the parameters +} + +?> diff --git a/modules/EmailTemplates/CheckDeletable.php b/modules/EmailTemplates/CheckDeletable.php new file mode 100644 index 00000000..3a93e0bd --- /dev/null +++ b/modules/EmailTemplates/CheckDeletable.php @@ -0,0 +1,84 @@ +retrieve($_REQUEST['record']); + if(check_email_template_in_use($focus)) { + echo 'true'; + return; + } + echo 'false'; +} else if($_REQUEST['from'] == 'ListView') { + $returnString = ''; + $idArray = explode(',', $_REQUEST['records']); + foreach($idArray as $key => $value) { + if($focus->retrieve($value)) { + if(check_email_template_in_use($focus)) { + $returnString .= $focus->name . ','; + } + } + } + $returnString = substr($returnString, 0, -1); + echo $returnString; +} else { + echo ''; +} + +function check_email_template_in_use($focus) +{ + if($focus->is_used_by_email_marketing()) { + return true; + } + $system = $GLOBALS['sugar_config']['passwordsetting']; + if($focus->id == $system['generatepasswordtmpl'] || $focus->id == $system['lostpasswordtmpl']) { + return true; + } + return false; +} diff --git a/modules/EmailTemplates/Delete.php b/modules/EmailTemplates/Delete.php new file mode 100644 index 00000000..5f8075a4 --- /dev/null +++ b/modules/EmailTemplates/Delete.php @@ -0,0 +1,62 @@ +retrieve($_REQUEST['record']); +if(!$focus->ACLAccess('Delete')) { + ACLController::displayNoAccess(true); + sugar_cleanup(true); +} +$focus->mark_deleted($_REQUEST['record']); + +header("Location: index.php?module=".$_REQUEST['return_module']."&action=".$_REQUEST['return_action']."&record=".$_REQUEST['return_id']); +?> diff --git a/modules/EmailTemplates/DetailView.html b/modules/EmailTemplates/DetailView.html new file mode 100644 index 00000000..d4227e0c --- /dev/null +++ b/modules/EmailTemplates/DetailView.html @@ -0,0 +1,128 @@ + + +
    + + + + + + + + + {PORTAL_ON} + + + +
    {ADMIN_EDIT}
    + +
    + +
    + +{PAGINATION} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    {MOD.LBL_NAME}{NAME} {APP.LBL_DATE_MODIFIED}{DATE_MODIFIED} {APP.LBL_BY} {MODIFIED_BY} 
    {MOD.LBL_DESCRIPTION}{DESCRIPTION} {APP.LBL_DATE_ENTERED}{DATE_ENTERED} {APP.LBL_BY} {CREATED_BY} 
    {MOD.LBL_SUBJECT}{SUBJECT}  + {TEAM} 
    {MOD.LBL_SEND_AS_TEXT}{APP.LBL_ASSIGNED_TO}{ASSIGNED_USER_NAME}
    {MOD.LBL_BODY}
    {BODY_HTML}
    +
    +
    + + +
    {MOD.LBL_ATTACHMENTS}{ATTACHMENTS} 
    +
    + diff --git a/modules/EmailTemplates/DetailView.php b/modules/EmailTemplates/DetailView.php new file mode 100644 index 00000000..eac7780d --- /dev/null +++ b/modules/EmailTemplates/DetailView.php @@ -0,0 +1,183 @@ +processSugarBean("EMAIL_TEMPLATE", $focus, $offset); + if($result == null) { + sugar_die($app_strings['ERROR_NO_RECORD']); + } + $focus=$result; +} else { + header("Location: index.php?module=Accounts&action=index"); +} +if(isset($_REQUEST['isDuplicate']) && $_REQUEST['isDuplicate'] == 'true') { + $focus->id = ""; +} + +//needed when creating a new note with default values passed in +if(isset($_REQUEST['contact_name']) && is_null($focus->contact_name)) { + $focus->contact_name = $_REQUEST['contact_name']; +} +if(isset($_REQUEST['contact_id']) && is_null($focus->contact_id)) { + $focus->contact_id = $_REQUEST['contact_id']; +} +if(isset($_REQUEST['opportunity_name']) && is_null($focus->parent_name)) { + $focus->parent_name = $_REQUEST['opportunity_name']; +} +if(isset($_REQUEST['opportunity_id']) && is_null($focus->parent_id)) { + $focus->parent_id = $_REQUEST['opportunity_id']; +} +if(isset($_REQUEST['account_name']) && is_null($focus->parent_name)) { + $focus->parent_name = $_REQUEST['account_name']; +} +if(isset($_REQUEST['account_id']) && is_null($focus->parent_id)) { + $focus->parent_id = $_REQUEST['account_id']; +} + +$params = array(); +$params[] = $focus->name; + +echo getClassicModuleTitle($focus->module_dir, $params, true); + + +$GLOBALS['log']->info("EmailTemplate detail view"); + +$xtpl=new XTemplate ('modules/EmailTemplates/DetailView.html'); +$xtpl->assign("MOD", $mod_strings); +$xtpl->assign("APP", $app_strings); + +if(isset($_REQUEST['return_module'])) $xtpl->assign("RETURN_MODULE", $_REQUEST['return_module']); +if(isset($_REQUEST['return_action'])) $xtpl->assign("RETURN_ACTION", $_REQUEST['return_action']); +if(isset($_REQUEST['return_id'])) $xtpl->assign("RETURN_ID", $_REQUEST['return_id']); +$xtpl->assign("GRIDLINE", $gridline); +$xtpl->assign("PRINT_URL", "index.php?".$GLOBALS['request_string']); +$xtpl->assign("ID", $focus->id); +$xtpl->assign("CREATED_BY", $focus->created_by_name); +$xtpl->assign("MODIFIED_BY", $focus->modified_by_name); +//if text only is set to true, then make sure input is checked and value set to 1 +if(isset($focus->text_only) && $focus->text_only){ + $xtpl->assign("TEXT_ONLY_CHECKED","CHECKED"); +} +$xtpl->assign("NAME", $focus->name); +$xtpl->assign("DESCRIPTION", $focus->description); +$xtpl->assign("SUBJECT", $focus->subject); +$xtpl->assign("BODY", $focus->body); +$xtpl->assign("BODY_HTML", from_html($focus->body_html)); +$xtpl->assign("DATE_MODIFIED", $focus->date_modified); +$xtpl->assign("DATE_ENTERED", $focus->date_entered); +$xtpl->assign("ASSIGNED_USER_NAME", $focus->assigned_user_name); + + +if(ACLController::checkAccess('EmailTemplates', 'edit', true)) { + $xtpl->parse("main.edit"); + //$xtpl->out("EDIT"); + +} +if(!empty($focus->body)) { + $xtpl->assign('ALT_CHECKED', 'CHECKED'); +} +else + $xtpl->assign('ALT_CHECKED', ''); +if( $focus->published == 'on') +{ +$xtpl->assign("PUBLISHED","CHECKED"); +} + + +/////////////////////////////////////////////////////////////////////////////// +//// NOTES (attachements, etc.) +/////////////////////////////////////////////////////////////////////////////// +$note = new Note(); +$where = "notes.parent_id='{$focus->id}'"; +$notes_list = $note->get_full_list("notes.name", $where,true); + +if(! isset($notes_list)) { + $notes_list = array(); +} + +$attachments = ''; +for($i=0; $ifilename,$the_note->id)."\" target=\"_blank\">". $the_note->filename ."
    "; + $attachments .= "id."&type=Notes\">".$the_note->name.$the_note->description."
    "; +} + +$xtpl->assign("ATTACHMENTS", $attachments); + + +global $current_user; +if(is_admin($current_user) && $_REQUEST['module'] != 'DynamicLayout' && !empty($_SESSION['editinplace'])) { + + $xtpl->assign("ADMIN_EDIT","".SugarThemeRegistry::current()->getImage("EditLayout","border='0' alt='Edit Layout' align='bottom'").""); +} + +$xtpl->assign("DESCRIPTION", $focus->description); + +$detailView->processListNavigation($xtpl, "EMAIL_TEMPLATE", $offset); +// adding custom fields: +require_once('modules/DynamicFields/templates/Files/DetailView.php'); + + +$xtpl->parse("main"); + +$xtpl->out("main"); + +?> diff --git a/modules/EmailTemplates/EditView.html b/modules/EmailTemplates/EditView.html new file mode 100644 index 00000000..b1d0ef14 --- /dev/null +++ b/modules/EmailTemplates/EditView.html @@ -0,0 +1,250 @@ + + + +{JAVASCRIPT} + + + + +{JSLANG} + + + + +
    + + + + + + + + + + + + + + + + +
    + + + + + {APP.LBL_REQUIRED_SYMBOL} + + {APP.NTC_REQUIRED} + + {ADMIN_EDIT} +
    +
    + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + {MOD.LBL_NAME} + + {APP.LBL_REQUIRED_SYMBOL} + + + + + +
    + {MOD.LBL_DESCRIPTION} + + +
    +   +
    + {MOD.LBL_INSERT_VARIABLE}  + + + + + {MOD.LBL_USE}: + + + + + +
    + {MOD.LBL_INSERT_TRACKER_URL}  + + + + +
    + {MOD.LBL_SUBJECT} + + +
      + + +  {MOD.LBL_SEND_AS_TEXT} +
    + {MOD.LBL_BODY} + +
    + +
    +
    +
    + +
    +
    + +
    + {MOD.LBL_ATTACHMENTS}: + + {ATTACHMENTS_JAVASCRIPT} {ATTACHMENTS} +
    +
    +
    +
    + +
    +
    + + + + + + +
    +
    +
    +
    + +{tiny} + + + + + \ No newline at end of file diff --git a/modules/EmailTemplates/EditView.php b/modules/EmailTemplates/EditView.php new file mode 100644 index 00000000..fc8e4bee --- /dev/null +++ b/modules/EmailTemplates/EditView.php @@ -0,0 +1,349 @@ +retrieve($_REQUEST['record']); +} + +$old_id = ''; +if(isset($_REQUEST['isDuplicate']) && $_REQUEST['isDuplicate'] == 'true') { + $old_id = $focus->id; // for attachments down below + $focus->id = ""; +} + + + +//setting default flag value so due date and time not required +if(!isset($focus->id)) $focus->date_due_flag = 1; + +//needed when creating a new case with default values passed in +if(isset($_REQUEST['contact_name']) && is_null($focus->contact_name)) { + $focus->contact_name = $_REQUEST['contact_name']; +} +if(isset($_REQUEST['contact_id']) && is_null($focus->contact_id)) { + $focus->contact_id = $_REQUEST['contact_id']; +} +if(isset($_REQUEST['parent_name']) && is_null($focus->parent_name)) { + $focus->parent_name = $_REQUEST['parent_name']; +} +if(isset($_REQUEST['parent_id']) && is_null($focus->parent_id)) { + $focus->parent_id = $_REQUEST['parent_id']; +} +if(isset($_REQUEST['parent_type'])) { + $focus->parent_type = $_REQUEST['parent_type']; +} +elseif(!isset($focus->parent_type)) { + $focus->parent_type = $app_list_strings['record_type_default_key']; +} +if(isset($_REQUEST['filename']) && $_REQUEST['isDuplicate'] != 'true') { + $focus->filename = $_REQUEST['filename']; +} + +if($has_campaign || $inboundEmail) { + insert_popup_header($theme); +} + + +$params = array(); + +if(empty($focus->id)){ + $params[] = $GLOBALS['app_strings']['LBL_CREATE_BUTTON_LABEL']; +}else{ + $params[] = "{$focus->name}"; + $params[] = $GLOBALS['app_strings']['LBL_EDIT_BUTTON_LABEL']; +} + +echo getClassicModuleTitle($focus->module_dir, $params, true); + +$GLOBALS['log']->info("EmailTemplate detail view"); + +if($has_campaign || $inboundEmail) { + $xtpl=new XTemplate ('modules/EmailTemplates/EditView.html'); +} else { + $xtpl=new XTemplate ('modules/EmailTemplates/EditViewMain.html'); +} // else +$xtpl->assign("MOD", $mod_strings); +$xtpl->assign("APP", $app_strings); + +$xtpl->assign("LBL_ACCOUNT",$app_list_strings['moduleList']['Accounts']); +$xtpl->parse("main.variable_option"); + +$returnAction = 'index'; +if(isset($_REQUEST['return_module'])) $xtpl->assign("RETURN_MODULE", $_REQUEST['return_module']); +if(isset($_REQUEST['return_action'])){ + $xtpl->assign("RETURN_ACTION", $_REQUEST['return_action']); + $returnAction = $_REQUEST['return_action']; +} +if(isset($_REQUEST['return_id'])) $xtpl->assign("RETURN_ID", $_REQUEST['return_id']); +// handle Create $module then Cancel +if(empty($_REQUEST['return_id'])) { + $xtpl->assign("RETURN_ACTION", 'index'); +} + +if ($has_campaign || $inboundEmail ) { + $cancel_script="window.close();"; +}else { + $cancel_script="this.form.action.value='{$returnAction}'; this.form.module.value='{$_REQUEST['return_module']}'; + this.form.record.value="; + if(empty($_REQUEST['return_id'])) { + $cancel_script="this.form.action.value='index'; this.form.module.value='{$_REQUEST['return_module']}';this.form.name.value='';this.form.description.value=''"; + } else { + $cancel_script.="'{$_REQUEST['return_id']}'"; + } +} + +//Setup assigned user name +$popup_request_data = array( + 'call_back_function' => 'set_return', + 'form_name' => 'EditView', + 'field_to_name_array' => array( + 'id' => 'assigned_user_id', + 'user_name' => 'assigned_user_name', + ), + ); +$json = getJSONobj(); +$xtpl->assign('encoded_assigned_users_popup_request_data', $json->encode($popup_request_data)); +if(!empty($focus->assigned_user_name)) + $xtpl->assign("ASSIGNED_USER_NAME", $focus->assigned_user_name); + +$xtpl->assign("assign_user_select", SugarThemeRegistry::current()->getImage('id-ff-select')); +$xtpl->assign("assign_user_clear", SugarThemeRegistry::current()->getImage('id-ff-clear')); +//Assign qsd script +require_once('include/QuickSearchDefaults.php'); +$qsd = new QuickSearchDefaults(); +$sqs_objects = array( 'EditView_assigned_user_name' => $qsd->getQSUser()); +$quicksearch_js = ''; + +$xtpl->assign("CANCEL_SCRIPT", $cancel_script); +$xtpl->assign("PRINT_URL", "index.php?".$GLOBALS['request_string']); +$xtpl->assign("JAVASCRIPT", get_set_focus_js() . $quicksearch_js); + +if(!is_file($GLOBALS['sugar_config']['cache_dir'] . 'jsLanguage/' . $GLOBALS['current_language'] . '.js')) { + require_once('include/language/jsLanguage.php'); + jsLanguage::createAppStringsCache($GLOBALS['current_language']); +} +$jsLang = ''; +$xtpl->assign("JSLANG", $jsLang); + +$xtpl->assign("ID", $focus->id); +if(isset($focus->name)) $xtpl->assign("NAME", $focus->name); else $xtpl->assign("NAME", ""); +if(isset($focus->description)) $xtpl->assign("DESCRIPTION", $focus->description); else $xtpl->assign("DESCRIPTION", ""); +if(isset($focus->subject)) $xtpl->assign("SUBJECT", $focus->subject); else $xtpl->assign("SUBJECT", ""); +if( $focus->published == 'on') +{ +$xtpl->assign("PUBLISHED","CHECKED"); +} +//if text only is set to true, then make sure input is checked and value set to 1 +if(isset($focus->text_only) && $focus->text_only){ + $xtpl->assign("TEXTONLY_CHECKED","CHECKED"); + $xtpl->assign("TEXTONLY_VALUE","1"); +}else{//set value to 0 + $xtpl->assign("TEXTONLY_VALUE","0"); +} + + + +$xtpl->assign("FIELD_DEFS_JS", $focus->generateFieldDefsJS()); +$xtpl->assign("LBL_CONTACT",$app_list_strings['moduleList']['Contacts']); + +global $current_user; +if(is_admin($current_user) && $_REQUEST['module'] != 'DynamicLayout' && !empty($_SESSION['editinplace'])) { + $record = ''; + if(!empty($_REQUEST['record'])) { + $record = $_REQUEST['record']; + } + $xtpl->assign("ADMIN_EDIT","".SugarThemeRegistry::current()->getImage("EditLayout","border='0' alt='Edit Layout' align='bottom'").""); +} +if(isset($focus->parent_type) && $focus->parent_type != "") { + $change_parent_button = ""; + $xtpl->assign("CHANGE_PARENT_BUTTON", $change_parent_button); +} +if($focus->parent_type == "Account") { + $xtpl->assign("DEFAULT_SEARCH","&query=true&account_id=$focus->parent_id&account_name=".urlencode($focus->parent_name)); +} + +$xtpl->assign("DESCRIPTION", $focus->description); +$xtpl->assign("TYPE_OPTIONS", get_select_options_with_id($app_list_strings['record_type_display'], $focus->parent_type)); +//$xtpl->assign("DEFAULT_MODULE","Accounts"); + +if(isset($focus->body)) $xtpl->assign("BODY", $focus->body); else $xtpl->assign("BODY", ""); +if(isset($focus->body_html)) $xtpl->assign("BODY_HTML", $focus->body_html); else $xtpl->assign("BODY_HTML", ""); + + +if(true) { + if ( !isTouchScreen() ) { + require_once("include/SugarTinyMCE.php"); + $tiny = new SugarTinyMCE(); + $tiny->defaultConfig['cleanup_on_startup']=true; + $tiny->defaultConfig['height']=600; + $tinyHtml = $tiny->getInstance(); + $xtpl->assign("tiny", $tinyHtml); + } + /////////////////////////////////////// + //// MACRO VARS + $xtpl->assign("INSERT_VARIABLE_ONCLICK", "insert_variable(document.EditView.variable_text.value)"); + if(!$inboundEmail){ + $xtpl->parse("main.NoInbound.variable_button"); + } + /////////////////////////////////////// + //// CAMPAIGNS + if($has_campaign || $inboundEmail) { + $xtpl->assign("INPOPUPWINDOW",'true'); + $xtpl->assign("INSERT_URL_ONCLICK", "insert_variable_html_link(document.EditView.tracker_url.value)"); + if($has_campaign){ + $campaign_urls=get_campaign_urls($_REQUEST['campaign_id']); + } + if(!empty($campaign_urls)) { + $xtpl->assign("DEFAULT_URL_TEXT",key($campaign_urls)); + } + if($has_campaign){ + $xtpl->assign("TRACKER_KEY_OPTIONS", get_select_options_with_id($campaign_urls, null)); + $xtpl->parse("main.NoInbound.tracker_url"); + } + } + + // The insert variable drodown should be conditionally displayed. + // If it's campaign then hide the Account. + if($has_campaign) { + $dropdown=""; + $xtpl->assign("DROPDOWN",$dropdown); + $xtpl->assign("DEFAULT_MODULE",'Contacts'); + //$xtpl->assign("CAMPAIGN_POPUP_JS", ''); + } else { + $dropdown=" + + "; + $xtpl->assign("DROPDOWN",$dropdown); + $xtpl->assign("DEFAULT_MODULE",'Accounts'); + } + //// END CAMPAIGNS + /////////////////////////////////////// + + /////////////////////////////////////// + //// ATTACHMENTS + $attachments = ''; + if(!empty($focus->id)) { + $etid = $focus->id; + } elseif(!empty($old_id)) { + $xtpl->assign('OLD_ID', $old_id); + $etid = $old_id; + } + if(!empty($etid)) { + $note = new Note(); + $where = "notes.parent_id='{$etid}' AND notes.filename IS NOT NULL"; + $notes_list = $note->get_full_list("", $where,true); + + if(!isset($notes_list)) { + $notes_list = array(); + } + for($i = 0;$i < count($notes_list);$i++) { + $the_note = $notes_list[$i]; + if( empty($the_note->filename)) { + continue; + } + $secureLink = 'index.php?entryPoint=download&id='.$the_note->id.'&type=Notes'; + $attachments .= ' '.$app_strings['LNK_REMOVE'].'  '; + $attachments .= ''. $the_note->filename .'
    '; + } + } + $attJs = ''; + $xtpl->assign('ATTACHMENTS', $attachments); + $xtpl->assign('ATTACHMENTS_JAVASCRIPT', $attJs); + + //// END ATTACHMENTS + /////////////////////////////////////// + + // done and parse + $xtpl->parse("main.textarea"); +} + +//Add Custom Fields +require_once('modules/DynamicFields/templates/Files/EditView.php'); +if(!$inboundEmail){ + $xtpl->parse("main.NoInbound"); + $xtpl->parse("main.NoInbound1"); + $xtpl->parse("main.NoInbound2"); + $xtpl->parse("main.NoInbound3"); + $xtpl->parse("main.NoInbound4"); + $xtpl->parse("main.NoInbound5"); +} +$xtpl->parse("main"); + +$xtpl->out("main"); + +$javascript = new javascript(); +$javascript->setFormName('EditView'); +$javascript->setSugarBean($focus); +$javascript->addAllFields(''); +echo $javascript->getScript(); +?> \ No newline at end of file diff --git a/modules/EmailTemplates/EditViewMain.html b/modules/EmailTemplates/EditViewMain.html new file mode 100644 index 00000000..1988855d --- /dev/null +++ b/modules/EmailTemplates/EditViewMain.html @@ -0,0 +1,257 @@ + + + +{JAVASCRIPT} + + + + + + + +{JSLANG} + +
    + + + + + + + + + + + + + + + + +
    + + + + + {APP.LBL_REQUIRED_SYMBOL} + + {APP.NTC_REQUIRED} + + {ADMIN_EDIT} +
    + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + {MOD.LBL_NAME} + + {APP.LBL_REQUIRED_SYMBOL} + + + +
    {APP.LBL_ASSIGNED_TO}  + + + + + + +
    + {MOD.LBL_DESCRIPTION} + + +
    +   +
    + {MOD.LBL_INSERT_VARIABLE}  + + + + + {MOD.LBL_USE}: + + + + + +
    + {MOD.LBL_INSERT_TRACKER_URL}  + + + + +
    + {MOD.LBL_SUBJECT} + + +
      + + +  {MOD.LBL_SEND_AS_TEXT} +
    + {MOD.LBL_BODY} + +
    + +
    +
    +
    + +
    +
    + +
    + {MOD.LBL_ATTACHMENTS}: + + {ATTACHMENTS_JAVASCRIPT} {ATTACHMENTS} +
    +
    +
    + +
    +
    + + + + + + +
    +
    +
    +
    + +{tiny} + + + + + \ No newline at end of file diff --git a/modules/EmailTemplates/EmailTemplate.js b/modules/EmailTemplates/EmailTemplate.js new file mode 100644 index 00000000..17b91b4b --- /dev/null +++ b/modules/EmailTemplates/EmailTemplate.js @@ -0,0 +1,60 @@ +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ +var focus_obj=false;var label=SUGAR.language.get('app_strings','LBL_DEFAULT_LINK_TEXT');function remember_place(obj){focus_obj=obj;} +function showVariable(){document.EditView.variable_text.value=document.EditView.variable_name.options[document.EditView.variable_name.selectedIndex].value;} +function addVariables(the_select,the_module){the_select.options.length=0;for(var i=0;i]+>/gi,'');}} +function insert_variable_text(myField,myValue){if(document.selection){myField.focus();sel=document.selection.createRange();sel.text=myValue;} +else if(myField.selectionStart||myField.selectionStart=='0'){var startPos=myField.selectionStart;var endPos=myField.selectionEnd;myField.value=myField.value.substring(0,startPos) ++myValue ++myField.value.substring(endPos,myField.value.length);}else{myField.value+=myValue;}} +function insert_variable_html(text){var inst=tinyMCE.getInstanceById("body_text");if(inst) +inst.getWin().focus();inst.execCommand('mceInsertRawHTML',false,text);} +function insert_variable_html_link(text){the_label=document.getElementById('url_text').value;if(typeof(the_label)=='undefined'){the_label=label;} +if(the_label[0]=='{'&&the_label[the_label.length-1]=='}'){the_label=the_label.substring(1,the_label.length-1);} +var thelink=" "+the_label+" ";insert_variable_html(thelink);} +function insert_variable(text){if(document.getElementById('toggle_textonly').checked==true){insert_variable_text(document.getElementById('body_text_plain'),text);}else{insert_variable_html(text);}} \ No newline at end of file diff --git a/modules/EmailTemplates/EmailTemplate.php b/modules/EmailTemplates/EmailTemplate.php new file mode 100644 index 00000000..822fc052 --- /dev/null +++ b/modules/EmailTemplates/EmailTemplate.php @@ -0,0 +1,592 @@ + array( + 'Contacts' => $contact, + 'Leads' => $lead, + 'Prospects' => $prospect, + ), + 'Accounts' => array( + 'Accounts' => $account, + ), + 'Users' => array( + 'Users' => $current_user, + ), + ); + + $prefixes = array( + 'Contacts' => 'contact_', + 'Accounts' => 'account_', + 'Users' => 'contact_user_', + ); + + $collection = array(); + foreach($loopControl as $collectionKey => $beans) { + $collection[$collectionKey] = array(); + foreach($beans as $beankey => $bean) { + + foreach($bean->field_defs as $key => $field_def) { + if( ($field_def['type'] == 'relate' && empty($field_def['custom_type'])) || + ($field_def['type'] == 'assigned_user_name' || $field_def['type'] =='link') || + ($field_def['type'] == 'bool') || + (in_array($field_def['name'], $this->badFields)) ) { + continue; + } + if(!isset($field_def['vname'])) { + //echo $key; + } + // valid def found, process + $optionKey = strtolower("{$prefixes[$collectionKey]}{$key}"); + $optionLabel = preg_replace('/:$/', "", translate($field_def['vname'], $beankey)); + $dup=1; + foreach ($collection[$collectionKey] as $value){ + if($value['name']==$optionKey){ + $dup=0; + break; + } + } + if($dup) + $collection[$collectionKey][] = array("name" => $optionKey, "value" => $optionLabel); + } + } + } + + $json = getJSONobj(); + $ret = "var field_defs = "; + $ret .= $json->encode($collection, false); + $ret .= ";"; + return $ret; + } + + function get_summary_text() { + return "$this->name"; + } + + function create_export_query(&$order_by, &$where) { + return $this->create_new_list_query($order_by, $where); + } + + function fill_in_additional_list_fields() { + $this->fill_in_additional_parent_fields(); + } + + function fill_in_additional_detail_fields() { + if (empty($this->body) && !empty($this->body_html)) + { + $this->body = strip_tags(html_entity_decode($this->body_html)); + } + $this->created_by_name = get_assigned_user_name($this->created_by); + $this->modified_by_name = get_assigned_user_name($this->modified_user_id); + $this->fill_in_additional_parent_fields(); + } + + function fill_in_additional_parent_fields() { + } + + function get_list_view_data() { + global $app_list_strings, $focus, $action, $currentModule; + $fields = $this->get_list_view_array(); + $fields["DATE_MODIFIED"] = substr($fields["DATE_MODIFIED"], 0 , 10); + return $fields; + } + + //function all string that match the pattern {.} , also catches the list of found strings. + //the cache will get refreshed when the template bean instance changes. + //The found url key patterns are replaced with name value pairs provided as function parameter. $tracked_urls. + //$url_template is used to construct the url for the email message. the template should have place holder for 1 varaible parameter, represented by %1 + //$template_text_array is a list of text strings that need to be searched. usually the subject, html body and text body of the email message. + //$removeme_url_template, if the url has is_optout property checked then use this template. + function parse_tracker_urls($template_text_array,$url_template,$tracked_urls,$removeme_url_template) { + global $beanFiles,$beanList, $app_list_strings,$sugar_config; + if (!isset($this->parsed_urls)) + $this->parsed_urls=array(); + + //parse the template and find all the dynamic strings that need replacement. + $pattern = '/\{*[^\{\}]*\}/'; // cn: bug 6638, find multibyte strings + foreach ($template_text_array as $key=>$template_text) { + if (!empty($template_text)) { + if(!isset($this->parsed_urls[$key]) || $this->parsed_urls[$key]['text'] != $template_text) { + $matches=array(); + $count=preg_match_all($pattern,$template_text,$matches,PREG_OFFSET_CAPTURE); + $this->parsed_urls[$key]=array('matches' => $matches, 'text' => $template_text); + } else { + $matches=$this->parsed_urls[$key]['matches']; + if(!empty($matches[0])) { + $count=count($matches[0]); + } else { + $count=0; + } + } + + //navigate thru all the matched keys and replace the keys with actual strings. + for ($i=($count -1); $i>=0; $i--) { + $url_key_name=$matches[0][$i][0]; + + if (!empty($tracked_urls[$url_key_name])) { + if ($tracked_urls[$url_key_name]['is_optout']==1){ + $tracker_url = $removeme_url_template; + } else { + $tracker_url = sprintf($url_template,$tracked_urls[$url_key_name]['id']); + } + } + if(!empty($tracker_url) && !empty($template_text) && !empty($matches[0][$i][0]) && !empty($tracked_urls[$matches[0][$i][0]])){ + $template_text=substr_replace($template_text,$tracker_url,$matches[0][$i][1], strlen($matches[0][$i][0])); + $template_text=str_replace($sugar_config['site_url'].'/'.$sugar_config['site_url'],$sugar_config['site_url'],$template_text); + } + } + } + $return_array[$key]=$template_text; + } + + return $return_array; + } + + function parse_email_template($template_text_array, $focus_name, $focus, &$macro_nv) { + + + global $beanFiles, $beanList, $app_list_strings; + + // generate User instance that owns this "Contact" for contact_user_* macros + $user = new User(); + if(isset($focus->assigned_user_id) && !empty($focus->assigned_user_id)){ + $user->retrieve($focus->assigned_user_id); + } + + if(!isset($this->parsed_entities)) + $this->parsed_entities=array(); + + //parse the template and find all the dynamic strings that need replacement. + $pattern_prefix = '$'.strtolower($beanList[$focus_name]).'_'; + $pattern_prefix_length = strlen($pattern_prefix); + $pattern = '/\\'.$pattern_prefix.'[A-Za-z_0-9]*/'; + + foreach($template_text_array as $key=>$template_text) { + if(!isset($this->parsed_entities[$key])) { + $matches = array(); + $count = preg_match_all($pattern, $template_text, $matches, PREG_OFFSET_CAPTURE); + + if($count != 0) { + for($i=($count -1); $i>=0; $i--) { + if(!isset($matches[0][$i][2])) { + //find the field name in the bean. + $matches[0][$i][2]=substr($matches[0][$i][0],$pattern_prefix_length,strlen($matches[0][$i][0]) - $pattern_prefix_length); + + //store the localized strings if the field is of type enum.. + if(isset($focus->field_defs[$matches[0][$i][2]]) && $focus->field_defs[$matches[0][$i][2]]['type']=='enum' && isset($focus->field_defs[$matches[0][$i][2]]['options'])) { + $matches[0][$i][3]=$focus->field_defs[$matches[0][$i][2]]['options']; + } + } + } + } + $this->parsed_entities[$key]=$matches; + } else { + $matches=$this->parsed_entities[$key]; + if(!empty($matches[0])) { + $count=count($matches[0]); + } else { + $count=0; + } + } + + for ($i=($count -1); $i>=0; $i--) { + $field_name=$matches[0][$i][2]; + + // cn: feel for User object attribute key and assign as found + if(strpos($field_name, "user_") === 0) { + $userFieldName = substr($field_name, 5); + $value = $user->$userFieldName; + //_pp($userFieldName."[{$value}]"); + } else { + $value = $focus->{$field_name}; + } + + //check dom + if(isset($matches[0][$i][3])) { + if(isset($app_list_strings[$matches[0][$i][3]][$value])) { + $value=$app_list_strings[$matches[0][$i][3]][$value]; + } + } + + //generate name value pair array of macros and corresponding values for the targed. + $macro_nv[$matches[0][$i][0]] =$value; + + $template_text=substr_replace($template_text,$value,$matches[0][$i][1], strlen($matches[0][$i][0])); + } + + //parse the template for tracker url strings. patter for these strings in {[a-zA-Z_0-9]+} + + $return_array[$key]=$template_text; + } + + return $return_array; + } + + + /** + * Convenience method to parse for user's values in a template + * @param array $repl_arr + * @param object $user + * @return array + */ + function _parseUserValues($repl_arr, &$user) { + foreach($user->field_defs as $field_def) { + if(($field_def['type'] == 'relate' && empty($field_def['custom_type'])) || $field_def['type'] == 'assigned_user_name') { + continue; + } + + if($field_def['type'] == 'enum') { + $translated = translate($field_def['options'], 'Users', $user->$field_def['name']); + + if(isset($translated) && ! is_array($translated)) { + $repl_arr["contact_user_".$field_def['name']] = $translated; + } else { // unset enum field, make sure we have a match string to replace with "" + $repl_arr["contact_user_".$field_def['name']] = ''; + } + } else { + if(isset($user->$field_def['name'])) { + $repl_arr["contact_user_".$field_def['name']] = $user->$field_def['name']; + } else { + $repl_arr["contact_user_".$field_def['name']] = ""; + } + } + } + + return $repl_arr; + } + + + function parse_template_bean($string, $bean_name, &$focus) { + global $current_user; + global $beanFiles, $beanList; + $repl_arr = array(); + + // cn: bug 9277 - create a replace array with empty strings to blank-out invalid vars + if(!class_exists('Account')) + if(!class_exists('Contact')) + if(!class_exists('Leads')) + if(!class_exists('Prospects')) + + require_once('modules/Accounts/Account.php'); + $acct = new Account(); + $contact = new Contact(); + $lead = new Lead(); + $prospect = new Prospect(); + + foreach($lead->field_defs as $field_def) { + if(($field_def['type'] == 'relate' && empty($field_def['custom_type'])) || $field_def['type'] == 'assigned_user_name') { + continue; + } + $repl_arr["contact_".$field_def['name']] = ''; + $repl_arr["contact_account_".$field_def['name']] = ''; + } + foreach($prospect->field_defs as $field_def) { + if(($field_def['type'] == 'relate' && empty($field_def['custom_type'])) || $field_def['type'] == 'assigned_user_name') { + continue; + } + $repl_arr["contact_".$field_def['name']] = ''; + $repl_arr["contact_account_".$field_def['name']] = ''; + } + foreach($contact->field_defs as $field_def) { + if(($field_def['type'] == 'relate' && empty($field_def['custom_type'])) || $field_def['type'] == 'assigned_user_name') { + continue; + } + $repl_arr["contact_".$field_def['name']] = ''; + $repl_arr["contact_account_".$field_def['name']] = ''; + } + foreach($acct->field_defs as $field_def) { + if(($field_def['type'] == 'relate' && empty($field_def['custom_type'])) || $field_def['type'] == 'assigned_user_name') { + continue; + } + $repl_arr["account_".$field_def['name']] = ''; + $repl_arr["account_contact_".$field_def['name']] = ''; + } + // cn: end bug 9277 fix + + + // feel for Parent account, only for Contacts traditionally, but written for future expansion + if(isset($focus->account_id) && !empty($focus->account_id)) { + $acct->retrieve($focus->account_id); + } + + if($bean_name == 'Contacts') { + // cn: bug 9277 - email templates not loading account/opp info for templates + if(!empty($acct->id)) { + foreach($acct->field_defs as $field_def) { + if(($field_def['type'] == 'relate' && empty($field_def['custom_type'])) || $field_def['type'] == 'assigned_user_name') { + continue; + } + + if($field_def['type'] == 'enum') { + $translated = translate($field_def['options'], 'Accounts' ,$acct->$field_def['name']); + + if(isset($translated) && ! is_array($translated)) { + $repl_arr["account_".$field_def['name']] = $translated; + $repl_arr["contact_account_".$field_def['name']] = $translated; + } else { // unset enum field, make sure we have a match string to replace with "" + $repl_arr["account_".$field_def['name']] = ''; + $repl_arr["contact_account_".$field_def['name']] = ''; + } + } else { + $repl_arr["account_".$field_def['name']] = $acct->$field_def['name']; + $repl_arr["contact_account_".$field_def['name']] = $acct->$field_def['name']; + } + } + } + + if(!empty($focus->assigned_user_id)) { + $user = new User(); + $user->retrieve($focus->assigned_user_id); + $repl_arr = EmailTemplate::_parseUserValues($repl_arr, $user); + } + } elseif($bean_name == 'Users') { + /** + * This section of code will on do work when a blank Contact, Lead, + * etc. is passed in to parse the contact_* vars. At this point, + * $current_user will be used to fill in the blanks. + */ + $repl_arr = EmailTemplate::_parseUserValues($repl_arr, $current_user); + } else { + // assumed we have an Account in focus + foreach($contact->field_defs as $field_def) { + if(($field_def['type'] == 'relate' && empty($field_def['custom_type'])) || $field_def['type'] == 'assigned_user_name' || $field_def['type'] == 'link') { + continue; + } + + if($field_def['type'] == 'enum') { + $translated = translate($field_def['options'], 'Accounts' ,$contact->$field_def['name']); + + if(isset($translated) && ! is_array($translated)) { + $repl_arr["contact_".$field_def['name']] = $translated; + $repl_arr["contact_account_".$field_def['name']] = $translated; + } else { // unset enum field, make sure we have a match string to replace with "" + $repl_arr["contact_".$field_def['name']] = ''; + $repl_arr["contact_account_".$field_def['name']] = ''; + } + } else { + if (isset($contact->$field_def['name'])) { + $repl_arr["contact_".$field_def['name']] = $contact->$field_def['name']; + $repl_arr["contact_account_".$field_def['name']] = $contact->$field_def['name']; + } // if + } + } + } + + /////////////////////////////////////////////////////////////////////// + //// LOAD FOCUS DATA INTO REPL_ARR + foreach($focus->field_defs as $field_def) { + if(isset($focus->$field_def['name'])) { + if(($field_def['type'] == 'relate' && empty($field_def['custom_type'])) || $field_def['type'] == 'assigned_user_name') { + continue; + } + + if($field_def['type'] == 'enum' && isset($field_def['options'])) { + $translated = translate($field_def['options'],$bean_name,$focus->$field_def['name']); + + if(isset($translated) && ! is_array($translated)) { + $repl_arr[strtolower($beanList[$bean_name])."_".$field_def['name']] = $translated; + } else { // unset enum field, make sure we have a match string to replace with "" + $repl_arr[strtolower($beanList[$bean_name])."_".$field_def['name']] = ''; + } + } else { + $repl_arr[strtolower($beanList[$bean_name])."_".$field_def['name']] = $focus->$field_def['name']; + } + } else { + if($field_def['name'] == 'full_name') { + $repl_arr[strtolower($beanList[$bean_name]).'_full_name'] = $focus->get_summary_text(); + } else { + $repl_arr[strtolower($beanList[$bean_name])."_".$field_def['name']] = ''; + } + } + } // end foreach() + + krsort($repl_arr); + reset($repl_arr); + //20595 add nl2br() to respect the multi-lines formatting + if(isset($repl_arr['contact_primary_address_street'])){ + $repl_arr['contact_primary_address_street'] = nl2br($repl_arr['contact_primary_address_street']); + } + if(isset($repl_arr['contact_alt_address_street'])){ + $repl_arr['contact_alt_address_street'] = nl2br($repl_arr['contact_alt_address_street']); + } + + foreach ($repl_arr as $name=>$value) { + if($value != '' && is_string($value)) { + $string = str_replace("\$$name", $value, $string); + } else { + $string = str_replace("\$$name", ' ', $string); + } + } + + return $string; + } + + function parse_template($string, &$bean_arr) { + global $beanFiles, $beanList; + + foreach($bean_arr as $bean_name => $bean_id) { + require_once($beanFiles[$beanList[$bean_name]]); + + $focus = new $beanList[$bean_name]; + $result = $focus->retrieve($bean_id); + + if($bean_name == 'Leads' || $bean_name == 'Prospects') { + $bean_name = 'Contacts'; + } + + if(isset($this) && isset($this->module_dir) && $this->module_dir == 'EmailTemplates') { + $string = $this->parse_template_bean($string, $bean_name, $focus); + } else { + $string = EmailTemplate::parse_template_bean($string, $bean_name, $focus); + } + } + return $string; + } + + function bean_implements($interface) { + switch($interface) { + case 'ACL':return true; + } + return false; + } + + function is_used_by_email_marketing() { + $query = "select id from email_marketing where template_id='$this->id' and deleted=0"; + $result = $this->db->query($query); + if($this->db->fetchByAssoc($result)) { + return true; + } + return false; + } +} +?> \ No newline at end of file diff --git a/modules/EmailTemplates/EmailTemplateFormBase.php b/modules/EmailTemplates/EmailTemplateFormBase.php new file mode 100644 index 00000000..a23f5d3f --- /dev/null +++ b/modules/EmailTemplates/EmailTemplateFormBase.php @@ -0,0 +1,370 @@ + + +

    + + + + + + + + + + + + + +
    $lbl_subject $lbl_required_symbol
    $lbl_description

    +EOF; + + $javascript = new javascript(); + $javascript->setFormName($formname); + $javascript->setSugarBean(new EmailTemplate()); + $javascript->addRequiredFields($prefix); + $form .=$javascript->getScript(); + $mod_strings = $temp_strings; + return $form; + } + + function getForm($prefix, $mod='') { + if(!empty($mod)) { + global $current_language; + $mod_strings = return_module_language($current_language, $mod); + }else global $mod_strings; + global $app_strings; + global $app_list_strings; + + $lbl_save_button_title = $app_strings['LBL_SAVE_BUTTON_TITLE']; + $lbl_save_button_key = $app_strings['LBL_SAVE_BUTTON_KEY']; + $lbl_save_button_label = $app_strings['LBL_SAVE_BUTTON_LABEL']; + + + $the_form = get_left_form_header($mod_strings['LBL_NEW_FORM_TITLE']); +$the_form .= << + + +EOQ; + $the_form .= $this->getFormBody($prefix, $mod, "${prefix}EmailTemplateSave", "20"); +$the_form .= <<

    + + +EOQ; + + $the_form .= get_left_form_footer(); + $the_form .= get_validate_record_js(); + + + return $the_form; + } + + + function handleSave($prefix,$redirect=true, $useRequired=false) { + + + + + require_once('include/formbase.php'); + require_once('include/upload_file.php'); + global $upload_maxsize, $upload_dir; + global $mod_strings; + global $sugar_config; + + $focus = new EmailTemplate(); + if($useRequired && !checkRequired($prefix, array_keys($focus->required_fields))) { + return null; + } + $focus = populateFromPost($prefix, $focus); + //process the text only flag + if(isset($_POST['text_only']) && ($_POST['text_only'] == '1')){ + $focus->text_only = 1; + }else{ + $focus->text_only = 0; + } + if(!$focus->ACLAccess('Save')) { + ACLController::displayNoAccess(true); + sugar_cleanup(true); + } + if(!isset($_REQUEST['published'])) $focus->published = 'off'; + + $preProcessedImages = array(); + $emailTemplateBodyHtml = from_html($focus->body_html); + $fileBasePath = "{$sugar_config['cache_dir']}images/"; + $filePatternSearch = "{$sugar_config['cache_dir']}"; + $filePatternSearch = str_replace("/", "\/", $filePatternSearch); + $filePatternSearch = $filePatternSearch . "images\/"; + $fileBasePath1 = "\"" .$fileBasePath; + if(strpos($emailTemplateBodyHtml, "\"{$fileBasePath}")) { + $matches = array(); + preg_match_all("/{$filePatternSearch}.+?\"/i", $emailTemplateBodyHtml, $matches); + foreach($matches[0] as $match) { + $filenameUndecoded = str_replace($fileBasePath, '', $match); + $filename = urldecode(substr($filenameUndecoded, 0, -1)); + $filenameUndecoded = str_replace("\"", '', $filenameUndecoded); + $cid = $filename; + $file_location = clean_path(getcwd()."/{$sugar_config['cache_dir']}images/{$filename}"); + $mime_type = strtolower(substr($filename, strrpos($filename, ".")+1, strlen($filename))); + + if(file_exists($file_location)) { + $id = create_guid(); + $newFileLocation = "{$sugar_config['upload_dir']}{$id}"; + if(!copy($file_location, $newFileLocation)) { + $GLOBALS['log']->debug("EMAIL Template could not copy attachment to {$sugar_config['upload_dir']} [ {$newFileLocation} ]"); + } else { + $secureLink = 'index.php?entryPoint=download&id='.$id.'&type=Notes'; + $emailTemplateBodyHtml = str_replace("{$sugar_config['cache_dir']}images/{$filenameUndecoded}", $secureLink, $emailTemplateBodyHtml); + unlink($file_location); + $preProcessedImages[$filename] = $id; + } + } // if + } // foreach + } // if + if (isset($GLOBALS['check_notify'])) { + $check_notify = $GLOBALS['check_notify']; + } + else { + $check_notify = FALSE; + } + $focus->body_html = $emailTemplateBodyHtml; + $return_id = $focus->save($check_notify); + /////////////////////////////////////////////////////////////////////////////// + //// ATTACHMENT HANDLING + + /////////////////////////////////////////////////////////////////////////// + //// ADDING NEW ATTACHMENTS + + $max_files_upload = count($_FILES); + + if(!empty($focus->id)) { + $note = new Note(); + $where = "notes.parent_id='{$focus->id}'"; + if(!empty($_REQUEST['old_id'])) { // to support duplication of email templates + $where .= " OR notes.parent_id='".$_REQUEST['old_id']."'"; + } + $notes_list = $note->get_full_list("", $where, true); + } + + if(!isset($notes_list)) { + $notes_list = array(); + } + + if(!is_array($focus->attachments)) { // PHP5 does not auto-create arrays(). Need to initialize it here. + $focus->attachments = array(); + } + $focus->attachments = array_merge($focus->attachments, $notes_list); + + + + //for($i = 0; $i < $max_files_upload; $i++) { + + foreach ($_FILES as $key => $file) + { + $note = new Note(); + + //Images are presaved above so we need to prevent duplicate files from being created. + if( isset($preProcessedImages[$file['name']]) ) + { + $oldId = $preProcessedImages[$file['name']]; + $note->id = $oldId; + $note->new_with_id = TRUE; + $GLOBALS['log']->debug("Image {$file['name']} has already been processed."); + } + + $i=preg_replace("/email_attachment(.+)/",'$1',$key); + $upload_file = new UploadFile($key); + + + if(isset($_FILES[$key]) && $upload_file->confirm_upload() && preg_match("/^email_attachment/",$key)) { + $note->filename = $upload_file->get_stored_file_name(); + $note->file = $upload_file; + $note->name = $mod_strings['LBL_EMAIL_ATTACHMENT'].': '.$note->file->original_file_name; + if(isset($_REQUEST['embedded'.$i]) && !empty($_REQUEST['embedded'.$i])){ + if($_REQUEST['embedded'.$i]=='true'){ + $note->embed_flag =true; + } + else{ + $note->embed_flag =false; + } + } + array_push($focus->attachments, $note); + } + + } + + $focus->saved_attachments = array(); + foreach($focus->attachments as $note) + { + if( !empty($note->id) && $note->new_with_id === FALSE) + { + if(empty($_REQUEST['old_id'])) + array_push($focus->saved_attachments, $note); // to support duplication of email templates + else + { + // we're duplicating a template with attachments + // dupe the file, create a new note, assign the note to the new template + $newNote = new Note(); + $newNote->retrieve($note->id); + $newNote->id = create_guid(); + $newNote->parent_id = $focus->id; + $newNote->new_with_id = true; + $newNote->date_modified = ''; + $newNote->date_entered = ''; + $newNoteId = $newNote->save(); + + $dupeFile = new UploadFile('duplicate'); + $dupeFile->duplicate_file($note->id, $newNoteId, $note->filename); + } + continue; + } + $note->parent_id = $focus->id; + $note->parent_type = 'Emails'; + $note->file_mime_type = $note->file->mime_type; + $note_id = $note->save(); + array_push($focus->saved_attachments, $note); + $note->id = $note_id; + + if($note->new_with_id === FALSE) + $note->file->final_move($note->id); + else + $GLOBALS['log']->debug("Not performing final move for note id {$note->id} as it has already been processed"); + } + + //// END NEW ATTACHMENTS + /////////////////////////////////////////////////////////////////////////// + + /////////////////////////////////////////////////////////////////////////// + //// ATTACHMENTS FROM DOCUMENTS + $count=''; + //_pp($_REQUEST); + //_ppd(count($_REQUEST['document'])); + if(!empty($_REQUEST['document'])){ + $count = count($_REQUEST['document']); + } + else{ + $count=10; + } + + for($i=0; $i<$count; $i++) { + if(isset($_REQUEST['documentId'.$i]) && !empty($_REQUEST['documentId'.$i])) { + $doc = new Document(); + $docRev = new DocumentRevision(); + $docNote = new Note(); + $noteFile = new UploadFile('none'); + + $doc->retrieve($_REQUEST['documentId'.$i]); + $docRev->retrieve($doc->document_revision_id); + + array_push($focus->saved_attachments, $docRev); + + $docNote->name = $doc->document_name; + $docNote->filename = $docRev->filename; + $docNote->description = $doc->description; + $docNote->parent_id = $focus->id; + $docNote->parent_type = 'Emails'; + $docNote->file_mime_type = $docRev->file_mime_type; + $docId = $docNote = $docNote->save(); + + $noteFile->duplicate_file($docRev->id, $docId, $docRev->filename); + } + + } + + //// END ATTACHMENTS FROM DOCUMENTS + /////////////////////////////////////////////////////////////////////////// + + /////////////////////////////////////////////////////////////////////////// + //// REMOVE ATTACHMENTS + + if(isset($_REQUEST['remove_attachment']) && !empty($_REQUEST['remove_attachment'])) { + foreach($_REQUEST['remove_attachment'] as $noteId) { + $q = 'UPDATE notes SET deleted = 1 WHERE id = \''.$noteId.'\''; + $focus->db->query($q); + } + + } + + //// END REMOVE ATTACHMENTS + /////////////////////////////////////////////////////////////////////////// + //// END ATTACHMENT HANDLING + /////////////////////////////////////////////////////////////////////////////// + + if($redirect) { + $GLOBALS['log']->debug("Saved record with id of ".$return_id); + handleRedirect($return_id, "EmailTemplates"); + }else{ + return $focus; + } + } + +} +?> \ No newline at end of file diff --git a/modules/EmailTemplates/Menu.php b/modules/EmailTemplates/Menu.php new file mode 100644 index 00000000..6652439b --- /dev/null +++ b/modules/EmailTemplates/Menu.php @@ -0,0 +1,47 @@ + \ No newline at end of file diff --git a/modules/EmailTemplates/PopupDocumentsCampaignTemplate.html b/modules/EmailTemplates/PopupDocumentsCampaignTemplate.html new file mode 100644 index 00000000..fba78e89 --- /dev/null +++ b/modules/EmailTemplates/PopupDocumentsCampaignTemplate.html @@ -0,0 +1,110 @@ + + + + + + + + + + + +
    + +
    + + + + + + + + + +{PAGINATION} + + + + + + + + + + + + + + + + +
    {MOD.LBL_LIST_DOCUMENT}{arrow_start}{name_arrow}{arrow_end}{MOD.LBL_LIST_REVISION}{MOD.LBL_LIST_STATUS}
    + {DOCUMENT.DOCUMENT_NAME} + {DOCUMENT.LATEST_REVISION}{DOCUMENT.STATUS_ID}
    \ No newline at end of file diff --git a/modules/EmailTemplates/PopupDocumentsCampaignTemplate.php b/modules/EmailTemplates/PopupDocumentsCampaignTemplate.php new file mode 100644 index 00000000..62585eb9 --- /dev/null +++ b/modules/EmailTemplates/PopupDocumentsCampaignTemplate.php @@ -0,0 +1,147 @@ +_get_where_clause(); + + + +$name = empty($_REQUEST['name']) ? '' : $_REQUEST['name']; +$document_name = empty($_REQUEST['document_name']) ? '' : $_REQUEST['document_name']; +$category_id = empty($_REQUEST['category_id']) ? '' : $_REQUEST['category_id']; +$subcategory_id = empty($_REQUEST['subcategory_id']) ? '' : $_REQUEST['subcategory_id']; +$template_type = empty($_REQUEST['template_type']) ? '' : $_REQUEST['template_type']; +$is_template = empty($_REQUEST['is_template']) ? '' : $_REQUEST['is_template']; +$document_revision_id = empty($_REQUEST['document_revision_id']) ? '' : $_REQUEST['document_revision_id']; + + +$hide_clear_button = empty($_REQUEST['hide_clear_button']) ? false : true; +$button = "
    \n"; +if(!$hide_clear_button) +{ + $button .= "\n"; +} +$button .= "\n"; +$button .= "
    \n"; + + +$form = new XTemplate('modules/EmailTemplates/PopupDocumentsCampaignTemplate.html'); +$form->assign('MOD', $current_mod_strings); +$form->assign('APP', $app_strings); +$form->assign('THEME', $theme); +$form->assign('MODULE_NAME', $currentModule); +$form->assign('NAME', $name); +$form->assign('DOCUMENT_NAME', $document_name); +$form->assign('DOCUMENT_TARGET', $_REQUEST['target']); +$form->assign('DOCUMENT_REVISION_ID', $document_revision_id); + +$form->assign("CATEGORY_OPTIONS", get_select_options_with_id($app_list_strings['document_category_dom'], $category_id)); +$form->assign("SUB_CATEGORY_OPTIONS", get_select_options_with_id($app_list_strings['document_subcategory_dom'], $subcategory_id)); +$form->assign("IS_TEMPLATE_OPTIONS", get_select_options_with_id($app_list_strings['checkbox_dom'], $is_template)); +$form->assign("TEMPLATE_TYPE_OPTIONS", get_select_options_with_id($app_list_strings['document_template_type_dom'], $template_type)); + + +ob_start(); +insert_popup_header($theme); +$output_html .= ob_get_contents(); +ob_end_clean(); + +$output_html .= get_form_header($current_mod_strings['LBL_SEARCH_FORM_TITLE'], '', false); + +$form->parse('main.SearchHeader'); +$output_html .= $form->text('main.SearchHeader'); + +// Reset the sections that are already in the page so that they do not print again later. +$form->reset('main.SearchHeader'); + +// create the listview +$seed_bean = new Document(); +$ListView = new ListView(); +$ListView->show_export_button = false; +$ListView->process_for_popups = true; +$ListView->setXTemplate($form); +$ListView->setHeaderTitle($current_mod_strings['LBL_LIST_FORM_TITLE']); +$ListView->setHeaderText($button); +$ListView->setQuery($where, '', 'document_name', 'DOCUMENT'); +$ListView->setModStrings($current_mod_strings); + +ob_start(); +$ListView->processListView($seed_bean, 'main', 'DOCUMENT'); +$output_html .= ob_get_contents(); +ob_end_clean(); + +$output_html .= insert_popup_footer(); + + +echo $output_html; + + + + + + + + + + +?> \ No newline at end of file diff --git a/modules/EmailTemplates/Save.php b/modules/EmailTemplates/Save.php new file mode 100644 index 00000000..ffcbe59f --- /dev/null +++ b/modules/EmailTemplates/Save.php @@ -0,0 +1,68 @@ +handleSave('',false, false); //do not redirect. + $body1 = " + "; + echo $body1; +} else { + $form->handleSave('',true, false); +} +?> \ No newline at end of file diff --git a/modules/EmailTemplates/field_arrays.php b/modules/EmailTemplates/field_arrays.php new file mode 100644 index 00000000..2faa1778 --- /dev/null +++ b/modules/EmailTemplates/field_arrays.php @@ -0,0 +1,61 @@ + Array("id" + , "date_entered" + , "date_modified" + , "modified_user_id" + , "created_by" + , "description" + , "subject" + , "body" + , "body_html" + , "name" + , "published" + ), + 'list_fields' => Array('id', 'name', 'description','date_modified' + ), + 'required_fields' => array("name"=>1), +); +?> \ No newline at end of file diff --git a/modules/EmailTemplates/language/en_us.lang.php b/modules/EmailTemplates/language/en_us.lang.php new file mode 100644 index 00000000..8f9d4cc1 --- /dev/null +++ b/modules/EmailTemplates/language/en_us.lang.php @@ -0,0 +1,116 @@ + 'Add Another File', + 'LBL_ADD_DOCUMENT' => 'Add a Sugar Document', + 'LBL_ADD_FILE' => 'Add a file', + 'LBL_ATTACHMENTS' => 'Attachments', + 'LBL_BODY' => 'Body:', + 'LBL_CLOSE' => 'Close:', + 'LBL_COLON' => ':', + 'LBL_CONTACT_AND_OTHERS' => 'Contact/Lead/Target', + 'LBL_DESCRIPTION' => 'Description:', + 'LBL_EDIT_ALT_TEXT' => 'Edit Plain Text', + 'LBL_EMAIL_ATTACHMENT' => 'Email Attachment', + 'LBL_HIDE_ALT_TEXT' => 'Hide Plain Text', + 'LBL_HTML_BODY' => 'HTML Body', + 'LBL_INSERT_VARIABLE' => 'Insert Variable:', + 'LBL_INSERT_URL_REF' => 'Insert URL Reference', + 'LBL_INSERT_TRACKER_URL' => 'Insert Tracker URL:', + 'LBL_INSERT' => 'Insert', + 'LBL_LIST_DATE_MODIFIED' => 'Last Modified', + 'LBL_LIST_DESCRIPTION' => 'Description', + 'LBL_LIST_FORM_TITLE' => 'Email Templates List', + 'LBL_LIST_NAME' => 'Name', + 'LBL_MODULE_NAME' => 'Email Templates', + 'LBL_MODULE_TITLE' => 'Email Templates: Home', + 'LBL_NAME' => 'Name:', + 'LBL_NEW_FORM_TITLE' => 'Create Email Template', + 'LBL_PUBLISH' => 'Publish:', + 'LBL_RELATED_TO' => 'Related To:', + 'LBL_SEARCH_FORM_TITLE' => 'Email Templates Search', + 'LBL_SHOW_ALT_TEXT' => 'Show Plain Text', + 'LBL_SUBJECT' => 'Subject:', + 'LBL_SUGAR_DOCUMENT' => 'Sugar Document', + 'LBL_TEAMS' => 'Teams:', + 'LBL_TEAMS_LINK' => 'Teams', + 'LBL_TEXT_BODY' => 'Text Body', + 'LBL_USERS' => 'Users', + + 'LNK_ALL_EMAIL_LIST' => 'All Emails', + 'LNK_ARCHIVED_EMAIL_LIST' => 'Archived Emails', + 'LNK_CHECK_EMAIL' => 'Check Mail', + 'LNK_DRAFTS_EMAIL_LIST' => 'All Drafts', + 'LNK_EMAIL_TEMPLATE_LIST' => 'View Email Templates', + 'LNK_IMPORT_NOTES' => 'Import Notes', + 'LNK_NEW_ARCHIVE_EMAIL' => 'Create Archived Email', + 'LNK_NEW_EMAIL_TEMPLATE' => 'Create Email Template', + 'LNK_NEW_EMAIL' => 'Archive Email', + 'LNK_NEW_SEND_EMAIL' => 'Compose Email', + 'LNK_SENT_EMAIL_LIST' => 'Sent Emails', + 'LNK_VIEW_CALENDAR' => 'Today', + // for Inbox + 'LBL_NEW' => 'New', + 'LNK_CHECK_MY_INBOX' => 'Check My Mail', + 'LNK_GROUP_INBOX' => 'Group Inbox', + 'LNK_MY_ARCHIVED_LIST' => 'My Archives', + 'LNK_MY_DRAFTS' => 'My Drafts', + 'LNK_MY_INBOX' => 'My Email', + 'LBL_LIST_BASE_MODULE' => 'Base Module:', + 'LBL_TEXT_ONLY' => 'Text Only', + 'LBL_SEND_AS_TEXT' => 'Send Text Only', + 'LBL_ACCOUNT' => 'Account', + 'LBL_BASE_MODULE'=>'Base Module', + 'LBL_FROM_NAME'=>'From Name', + 'LBL_PLAIN_TEXT'=>'Plain Text', + 'LBL_CREATED_BY'=>'Created By', + 'LBL_FROM_ADDRESS'=>'From Address', + 'LBL_PUBLISHED'=>'Published', + 'LBL_ACTIVITIES_REPORTS' => 'Activities Report', + 'LNK_VIEW_MY_INBOX' => 'View My Email', + 'LBL_ASSIGNED_TO_ID' => 'Assigned To', +); +?> \ No newline at end of file diff --git a/modules/EmailTemplates/metadata/SearchFields.php b/modules/EmailTemplates/metadata/SearchFields.php new file mode 100644 index 00000000..7ff9ede3 --- /dev/null +++ b/modules/EmailTemplates/metadata/SearchFields.php @@ -0,0 +1,43 @@ + array( 'query_type'=>'default'), + 'description'=> array('query_type'=>'default'), + ); +?> diff --git a/modules/EmailTemplates/metadata/listviewdefs.php b/modules/EmailTemplates/metadata/listviewdefs.php new file mode 100644 index 00000000..133851fe --- /dev/null +++ b/modules/EmailTemplates/metadata/listviewdefs.php @@ -0,0 +1,67 @@ + array( + 'width' => '20', + 'label' => 'LBL_NAME', + 'link' => true, + 'default' => true), + 'DESCRIPTION' => array( + 'width' => '40', + 'default' => true, + 'sortable' => false, + 'label' => 'LBL_DESCRIPTION'), + 'ASSIGNED_USER_NAME' => array ( + 'width' => '10', + 'label' => 'LBL_LIST_ASSIGNED_USER', + 'module' => 'Employees', + 'id' => 'ASSIGNED_USER_ID', + 'default' => true,), + 'DATE_MODIFIED' => array( + 'width' => '10', + 'default' => true, + 'label' => 'LBL_DATE_MODIFIED'), + 'DATE_ENTERED' => array ( + 'width' => '10', + 'label' => 'LBL_DATE_ENTERED', + 'default' => true), +); +?> diff --git a/modules/EmailTemplates/metadata/searchdefs.php b/modules/EmailTemplates/metadata/searchdefs.php new file mode 100644 index 00000000..6a8d4c78 --- /dev/null +++ b/modules/EmailTemplates/metadata/searchdefs.php @@ -0,0 +1,67 @@ + array( + 'maxColumns' => '2', + 'widths' => array('label' => '10', 'field' => '30'), + ), + 'layout' => array( + 'basic_search' => array( + 'name', + ), + 'advanced_search' => array('name','subject','description', + 'assigned_user_id' => + array ( + 'name' => 'assigned_user_id', + 'type' => 'enum', + 'label' => 'LBL_ASSIGNED_TO', + 'function' => + array ( + 'name' => 'get_user_array', + 'params' => array ( 0 => false,), ), + 'default' => true + ), + ) + ), + ); +?> diff --git a/modules/EmailTemplates/vardefs.php b/modules/EmailTemplates/vardefs.php new file mode 100644 index 00000000..5ff04680 --- /dev/null +++ b/modules/EmailTemplates/vardefs.php @@ -0,0 +1,204 @@ + 'email_templates', 'comment' => 'Templates used in email processing', + 'fields' => array( + 'id' => array( + 'name' => 'id', + 'vname' => 'LBL_NAME', + 'type' => 'id', + 'required' => true, + 'reportable'=>false, + 'comment' => 'Unique identifier' + ), + 'date_entered' => array( + 'name' => 'date_entered', + 'vname' => 'LBL_DATE_ENTERED', + 'type' => 'datetime', + 'required'=>true, + 'comment' => 'Date record created' + ), + 'date_modified' => array( + 'name' => 'date_modified', + 'vname' => 'LBL_DATE_MODIFIED', + 'type' => 'datetime', + 'required'=>true, + 'comment' => 'Date record last modified' + ), + 'modified_user_id' => array( + 'name' => 'modified_user_id', + 'rname' => 'user_name', + 'id_name' => 'modified_user_id', + 'vname' => 'LBL_ASSIGNED_TO', + 'type' => 'assigned_user_name', + 'table' => 'users', + 'reportable'=>true, + 'isnull' => 'false', + 'dbType' => 'id', + 'comment' => 'User who last modified record' + ), + 'created_by' => array( + 'name' => 'created_by', + 'vname' => 'LBL_CREATED_BY', + 'type' => 'varchar', + 'len'=> '36', + 'comment' => 'User who created record' + ), + 'published' => array( + 'name' => 'published', + 'vname' => 'LBL_PUBLISHED', + 'type' => 'varchar', + 'len' => '3', + 'comment' => '' + ), + 'name' => array( + 'name' => 'name', + 'vname' => 'LBL_NAME', + 'type' => 'varchar', + 'len' => '255', + 'comment' => 'Email template name', + 'importable' => 'required', + ), + 'description' => array( + 'name' => 'description', + 'vname' => 'LBL_DESCRIPTION', + 'type' => 'text', + 'comment' => 'Email template description' + ), + 'subject' => array( + 'name' => 'subject', + 'vname' => 'LBL_SUBJECT', + 'type' => 'varchar', + 'len' => '255', + 'comment' => 'Email subject to be used in resulting email' + ), + 'body' => array( + 'name' => 'body', + 'vname' => 'LBL_BODY', + 'type' => 'text', + 'comment' => 'Plain text body to be used in resulting email' + ), + 'body_html' => array( + 'name' => 'body_html', + 'vname' => 'LBL_PLAIN_TEXT', + 'type' => 'text', + 'comment' => 'HTML formatted email body to be used in resulting email' + ), + 'deleted' => array( + 'name' => 'deleted', + 'vname' => 'LBL_DELETED', + 'type' => 'bool', + 'required' => false, + 'reportable'=>false, + 'comment' => 'Record deletion indicator' + ), + 'assigned_user_id' => array ( + 'name' => 'assigned_user_id', + 'rname' => 'user_name', + 'id_name' => 'assigned_user_id', + 'vname' => 'LBL_ASSIGNED_TO_ID', + 'group'=>'assigned_user_name', + 'type' => 'relate', + 'table' => 'users', + 'module' => 'Users', + 'reportable'=>true, + 'isnull' => 'false', + 'dbType' => 'id', + 'audited'=>true, + 'comment' => 'User ID assigned to record', + 'duplicate_merge'=>'disabled' + ), + 'assigned_user_name' => array ( + 'name' => 'assigned_user_name', + 'link'=>'assigned_user_link' , + 'vname' => 'LBL_ASSIGNED_TO_NAME', + 'rname' => 'user_name', + 'type' => 'relate', + 'reportable'=>false, + 'source'=>'non-db', + 'table' => 'users', + 'id_name' => 'assigned_user_id', + 'module'=>'Users', + 'duplicate_merge'=>'disabled' + ), + 'assigned_user_link' => array ( + 'name' => 'assigned_user_link', + 'type' => 'link', + 'relationship' => 'emailtemplates_assigned_user', + 'vname' => 'LBL_ASSIGNED_TO_USER', + 'link_type' => 'one', + 'module'=>'Users', + 'bean_name'=>'User', + 'source'=>'non-db', + 'duplicate_merge'=>'enabled', + 'rname' => 'user_name', + 'id_name' => 'assigned_user_id', + 'table' => 'users', + ), + 'text_only' => array( + 'name' => 'text_only', + 'vname' => 'LBL_TEXT_ONLY', + 'type' => 'bool', + 'required' => false, + 'reportable'=>false, + 'comment' => 'Should be checked if email template is to be sent in text only' + ), + ), + 'indices' => array( + array( + 'name' => 'email_templatespk', + 'type' =>'primary', + 'fields'=>array('id') + ), + array( + 'name' => 'idx_email_template_name', + 'type'=>'index', + 'fields'=>array('name') + ) + ), + 'relationships' => array( + 'emailtemplates_assigned_user' => + array('lhs_module'=> 'Users', 'lhs_table'=> 'users', 'lhs_key' => 'id', + 'rhs_module'=> 'EmailTemplates' , 'rhs_table'=> 'email_templates', 'rhs_key' => 'assigned_user_id', + 'relationship_type'=>'one-to-many') + ), +); + +VardefManager::createVardef('EmailTemplates','EmailTemplate', array( +)); +?> \ No newline at end of file diff --git a/modules/Emails/Check.php b/modules/Emails/Check.php new file mode 100644 index 00000000..af3db5e6 --- /dev/null +++ b/modules/Emails/Check.php @@ -0,0 +1,111 @@ +hasPersonalEmail()) { + + $ie = new InboundEmail(); + $beans = $ie->retrieveByGroupId($current_user->id); + if(!empty($beans)) { + foreach($beans as $bean) { + $bean->connectMailserver(); + $newMsgs = array(); + if ($bean->isPop3Protocol()) { + $newMsgs = $bean->getPop3NewMessagesToDownload(); + } else { + $newMsgs = $bean->getNewMessageIds(); + } + //$newMsgs = $bean->getNewMessageIds(); + if(is_array($newMsgs)) { + foreach($newMsgs as $k => $msgNo) { + $uid = $msgNo; + if ($bean->isPop3Protocol()) { + $uid = $bean->getUIDLForMessage($msgNo); + } else { + $uid = imap_uid($bean->conn, $msgNo); + } // else + $bean->importOneEmail($msgNo, $uid); + } + } + imap_expunge($bean->conn); + imap_close($bean->conn); + } + } + } + header('Location: index.php?module=Emails&action=ListView&type=inbound&assigned_user_id='.$current_user->id); +} elseif(isset($_REQUEST['type']) && $_REQUEST['type'] == 'group') { + $ie = new InboundEmail(); + // this query only polls Group Inboxes + $r = $ie->db->query('SELECT inbound_email.id FROM inbound_email JOIN users ON inbound_email.group_id = users.id WHERE inbound_email.deleted=0 AND inbound_email.status = \'Active\' AND mailbox_type != \'bounce\' AND users.deleted = 0 AND users.is_group = 1'); + + while($a = $ie->db->fetchByAssoc($r)) { + $ieX = new InboundEmail(); + $ieX->retrieve($a['id']); + $ieX->connectMailserver(); + //$newMsgs = $ieX->getNewMessageIds(); + $newMsgs = array(); + if ($ieX->isPop3Protocol()) { + $newMsgs = $ieX->getPop3NewMessagesToDownload(); + } else { + $newMsgs = $ieX->getNewMessageIds(); + } + + if(is_array($newMsgs)) { + foreach($newMsgs as $k => $msgNo) { + $uid = $msgNo; + if ($ieX->isPop3Protocol()) { + $uid = $ieX->getUIDLForMessage($msgNo); + } else { + $uid = imap_uid($ieX->conn, $msgNo); + } // else + $ieX->importOneEmail($msgNo, $uid); + } + } + imap_expunge($ieX->conn); + imap_close($ieX->conn); + } + + header('Location: index.php?module=Emails&action=ListViewGroup'); +} else { // fail gracefully + header('Location: index.php?module=Emails&action=index'); +} + + +?> \ No newline at end of file diff --git a/modules/Emails/Compose.php b/modules/Emails/Compose.php new file mode 100644 index 00000000..71ddbccc --- /dev/null +++ b/modules/Emails/Compose.php @@ -0,0 +1,266 @@ +getNamePlusEmailAddressesForCompose($_REQUEST['action_module'], (explode(",", $_REQUEST['uid']))); +} +//For the full compose/email screen, the compose package is generated and script execution +//continues to the Emails/index.php page. +else if(!isset($data['forQuickCreate'])) { + $ret = generateComposeDataPackage($data); +} + +/** + * Initialize the full compose window by creating the compose package + * and then including Emails index.php file. + * + * @param Array $ret + */ +function initFullCompose($ret) +{ + global $current_user; + $json = getJSONobj(); + $composeOut = $json->encode($ret); + + //For listview 'Email' call initiated by subpanels, just returned the composePackage data, do not + //include the entire Emails page + if ( isset($_REQUEST['ajaxCall']) && $_REQUEST['ajaxCall']) + { + echo $composeOut; + } + else + { + //For normal full compose screen + include('modules/Emails/index.php'); + echo ""; + } +} + +/** + * Generate the compose data package consumed by the full and quick compose screens. + * + * @param Array $data + * @param Bool $forFullCompose If full compose is set to TRUE, then continue execution and include the full Emails UI. Otherwise + * the data generated is returned. + */ +function generateComposeDataPackage($data,$forFullCompose = TRUE) +{ + // we will need the following: + if( isset($data['parent_type']) && !empty($data['parent_type']) && + isset($data['parent_id']) && !empty($data['parent_id']) && + !isset($data['ListView']) && !isset($data['replyForward'])) { + global $beanList; + global $beanFiles; + global $mod_strings; + + $parentName = ''; + $class = $beanList[$data['parent_type']]; + require_once($beanFiles[$class]); + + $bean = new $class(); + $bean->retrieve($data['parent_id']); + if (isset($bean->full_name)) { + $parentName = $bean->full_name; + } elseif(isset($bean->name)) { + $parentName = $bean->name; + }else{ + $parentName = ''; + } + $parentName = from_html($parentName); + $namePlusEmail = ''; + if (isset($data['to_email_addrs'])) { + $namePlusEmail = $data['to_email_addrs']; + $namePlusEmail = from_html(str_replace(" ", " ", $namePlusEmail)); + } else { + if (isset($bean->full_name)) { + $namePlusEmail = from_html($bean->full_name) . " <". from_html($bean->emailAddress->getPrimaryAddress($bean)).">"; + } else if(isset($bean->emailAddress)){ + $namePlusEmail = "<".from_html($bean->emailAddress->getPrimaryAddress($bean)).">"; + } + } + + $subject = ""; + $body = ""; + $email_id = ""; + $attachments = array(); + if ($bean->module_dir == 'Cases') { + $subject = str_replace('%1', $bean->case_number, $bean->getEmailSubjectMacro() . " ". $bean->name) ; + $bean->load_relationship("contacts"); + $contact_ids = $bean->contacts->get(); + $contact = new Contact(); + foreach($contact_ids as $cid) + { + $contact->retrieve($cid); + $namePlusEmail .= empty($namePlusEmail) ? "" : ", "; + $namePlusEmail .= from_html($contact->full_name) . " <".from_html($contact->emailAddress->getPrimaryAddress($contact)).">"; + } + } + if ($bean->module_dir == 'KBDocuments') { + + require_once("modules/Emails/EmailUI.php"); + $subject = $bean->kbdocument_name; + $article_body = str_replace('/'.$GLOBALS['sugar_config']['cache_dir'].'images/',$GLOBALS['sugar_config']['site_url'].'/'.$GLOBALS['sugar_config']['cache_dir'].'images/',KBDocument::get_kbdoc_body_without_incrementing_count($bean->id)); + $body = from_html($article_body); + $attachments = KBDocument::get_kbdoc_attachments_for_newemail($bean->id); + $attachments = $attachments['attachments']; + } // if + if ($bean->module_dir == 'Quotes' && isset($data['recordId'])) { + $quotesData = getQuotesRelatedData($bean,$data); + global $current_language; + $namePlusEmail = $quotesData['toAddress']; + $subject = $quotesData['subject']; + $body = $quotesData['body']; + $attachments = $quotesData['attachments']; + $email_id = $quotesData['email_id']; + } // if + $ret = array( + 'to_email_addrs' => $namePlusEmail, + 'parent_type' => $data['parent_type'], + 'parent_id' => $data['parent_id'], + 'parent_name' => $parentName, + 'subject' => $subject, + 'body' => $body, + 'attachments' => $attachments, + 'email_id' => $email_id, + + ); +} else if(isset($_REQUEST['ListView'])) { + + $email = new Email(); + $namePlusEmail = $email->getNamePlusEmailAddressesForCompose($_REQUEST['action_module'], (explode(",", $_REQUEST['uid']))); + $ret = array( + 'to_email_addrs' => $namePlusEmail, + ); + } else if (isset($data['replyForward'])) { + + require_once("modules/Emails/EmailUI.php"); + + $ret = array(); + $ie = new InboundEmail(); + $ie->email = new Email(); + $ie->email->email2init(); + $replyType = $data['reply']; + $email_id = $data['record']; + $ie->email->retrieve($email_id); + $emailType = ""; + if ($ie->email->type == 'draft') { + $emailType = $ie->email->type; + } + $ie->email->from_addr = $ie->email->from_addr_name; + $ie->email->to_addrs = to_html($ie->email->to_addrs_names); + $ie->email->cc_addrs = to_html($ie->email->cc_addrs_names); + $ie->email->bcc_addrs = $ie->email->bcc_addrs_names; + $ie->email->from_name = $ie->email->from_addr; + $preBodyHTML = " 

    "; + if ($ie->email->type != 'draft') { + $email = $ie->email->et->handleReplyType($ie->email, $replyType); + } else { + $email = $ie->email; + $preBodyHTML = ""; + } // else + if ($ie->email->type != 'draft') { + $emailHeader = $email->description; + } + $ret = $ie->email->et->displayComposeEmail($email); + if ($ie->email->type != 'draft') { + $ret['description'] = $emailHeader; + } + if ($replyType == 'forward' || $emailType == 'draft') { + $ret = $ie->email->et->getDraftAttachments($ret); + } + $return = $ie->email->et->getFromAllAccountsArray($ie, $ret); + + if ($replyType == "forward") { + $return['to'] = ''; + } else { + if ($email->type != 'draft') { + $return['to'] = from_html($ie->email->from_addr); + } + } // else + $ret = array( + 'to_email_addrs' => $return['to'], + 'parent_type' => $return['parent_type'], + 'parent_id' => $return['parent_id'], + 'parent_name' => $return['parent_name'], + 'subject' => $return['name'], + 'body' => $preBodyHTML . $return['description'], + 'attachments' => (isset($return['attachments']) ? $return['attachments'] : array()), + 'email_id' => $email_id, + 'fromAccounts' => $return['fromAccounts'], + ); + + } else { + $ret = array( + 'to_email_addrs' => '', + ); + } + + if($forFullCompose) + initFullCompose($ret); + else + return $ret; +} + +function getQuotesRelatedData($bean,$data) { + $return = array(); + $emailId = $data['recordId']; + + require_once("modules/Emails/EmailUI.php"); + $email = new Email(); + $email->retrieve($emailId); + $return['subject'] = $email->name; + $return['body'] = from_html($email->description_html); + $return['toAddress'] = $email->to_addrs; + $ret = array(); + $ret['uid'] = $emailId; + $ret = EmailUI::getDraftAttachments($ret); + $return['attachments'] = $ret['attachments']; + $return['email_id'] = $emailId; + return $return; +} // fn \ No newline at end of file diff --git a/modules/Emails/Dashlets/MyEmailsDashlet/MyEmailsDashlet.data.php b/modules/Emails/Dashlets/MyEmailsDashlet/MyEmailsDashlet.data.php new file mode 100644 index 00000000..2ee35008 --- /dev/null +++ b/modules/Emails/Dashlets/MyEmailsDashlet/MyEmailsDashlet.data.php @@ -0,0 +1,83 @@ + array('default' => ''), + 'name' => array('default' => ''), + //'from_addr_name' => array('default' => ''), + 'assigned_user_id' => array('default' => ''), + ); +$dashletData['MyEmailsDashlet']['columns'] = array( + 'from_addr' => array('width' => '15', + 'label' => 'LBL_FROM', + 'default' => true), + 'name' => array('width' => '40', + 'label' => 'LBL_SUBJECT', + 'link' => true, + 'default' => true), + 'to_addrs' => array('width' => '15', + 'label' => 'LBL_TO_ADDRS', + 'default' => false), + 'assigned_user_name' => array('width' => '15', + 'label' => 'LBL_LIST_ASSIGNED', + 'default' => false), + + 'date_sent' => array('width' => '15', + 'label' => 'LBL_DATE_SENT', + 'default' => true, + 'defaultOrderColumn' => array('sortOrder' => 'ASC') + ), + 'date_entered' => array('width' => '15', + 'label' => 'LBL_DATE_ENTERED'), + 'date_modified' => array('width' => '15', + 'label' => 'LBL_DATE_MODIFIED'), + 'quick_reply' => array('width' => '15', + 'label' => '', + 'sortable' => false, + 'default' => true), + 'create_related' => array('width' => '25', + 'label' => '', + 'sortable' => false, + 'default' => true), + ); + +?> diff --git a/modules/Emails/Dashlets/MyEmailsDashlet/MyEmailsDashlet.meta.php b/modules/Emails/Dashlets/MyEmailsDashlet/MyEmailsDashlet.meta.php new file mode 100644 index 00000000..a3afc2a9 --- /dev/null +++ b/modules/Emails/Dashlets/MyEmailsDashlet/MyEmailsDashlet.meta.php @@ -0,0 +1,47 @@ + 'Emails', + 'title' => translate('LBL_MY_EMAILS', 'Emails'), + 'description' => translate('A customizable view into Emails'), + 'category' => 'Module Views'); +?> diff --git a/modules/Emails/Dashlets/MyEmailsDashlet/MyEmailsDashlet.php b/modules/Emails/Dashlets/MyEmailsDashlet/MyEmailsDashlet.php new file mode 100644 index 00000000..42e4a330 --- /dev/null +++ b/modules/Emails/Dashlets/MyEmailsDashlet/MyEmailsDashlet.php @@ -0,0 +1,124 @@ +title = translate('LBL_MY_EMAILS', 'Emails'); + + $this->searchFields = $dashletData['MyEmailsDashlet']['searchFields']; + $this->hasScript = true; // dashlet has javascript attached to it + + $this->columns = $dashletData['MyEmailsDashlet']['columns']; + + $this->seedBean = new Email(); + } + + function process() { + global $current_language, $app_list_strings, $image_path, $current_user; + //$where = 'emails.deleted = 0 AND emails.assigned_user_id = \''.$current_user->id.'\' AND emails.type = \'inbound\' AND emails.status = \'unread\''; + $mod_strings = return_module_language($current_language, 'Emails'); + + if ($this->myItemsOnly) { + $this->filters['assigned_user_id'] = $current_user->id; + } + $this->filters['type'] = array("inbound"); + $this->filters['status'] = array("unread"); + + $lvsParams = array(); + $lvsParams['custom_select'] = " ,emails_text.from_addr as from_addr "; + $lvsParams['custom_from'] = " join emails_text on emails.id = emails_text.email_id "; + parent::process($lvsParams); + } + + function displayScript() { + global $current_language; + + $mod_strings = return_module_language($current_language, 'Emails'); + $casesImageURL = "\"" . SugarThemeRegistry::current()->getImageURL('Cases.gif') . "\""; + + $leadsImageURL = "\"" . SugarThemeRegistry::current()->getImageURL('Leads.gif') . "\""; + + $contactsImageURL = "\"" . SugarThemeRegistry::current()->getImageURL('Contacts.gif') . "\""; + + $bugsImageURL = "\"" . SugarThemeRegistry::current()->getImageURL('Bugs.gif') . "\""; + + $tasksURL = "\"" . SugarThemeRegistry::current()->getImageURL('Tasks.gif') . "\""; + $script = << + function quick_create_overlib(id, theme) { + return overlib('' + + "" + '{$mod_strings['LBL_LIST_CASE']}' + '' + + + "" + + "" + + '{$mod_strings['LBL_LIST_LEAD']}' + "" + + + "" + + "" + + '{$mod_strings['LBL_LIST_CONTACT']}' + "" + + + ""+ + "" + + '{$mod_strings['LBL_LIST_BUG']}' + "" + + + "" + + "" + + '{$mod_strings['LBL_LIST_TASK']}' + "" + , CAPTION, '{$mod_strings['LBL_QUICK_CREATE']}' + , STICKY, MOUSEOFF, 3000, CLOSETEXT, '
    ', WIDTH, 150, CLOSETITLE, SUGAR.language.get('app_strings', 'LBL_ADDITIONAL_DETAILS_CLOSE_TITLE'), CLOSECLICK, FGCLASS, 'olOptionsFgClass', + CGCLASS, 'olOptionsCgClass', BGCLASS, 'olBgClass', TEXTFONTCLASS, 'olFontClass', CAPTIONFONTCLASS, 'olOptionsCapFontClass', CLOSEFONTCLASS, 'olOptionsCloseFontClass'); + } + +EOQ; + return $script; + } +} + +?> diff --git a/modules/Emails/Delete.php b/modules/Emails/Delete.php new file mode 100644 index 00000000..a5b6667c --- /dev/null +++ b/modules/Emails/Delete.php @@ -0,0 +1,72 @@ +retrieve($_REQUEST['record']); +$email_type = $focus->type; +if(!$focus->ACLAccess('Delete')){ + ACLController::displayNoAccess(true); + sugar_cleanup(true); +} +$focus->mark_deleted($_REQUEST['record']); + +// make sure assigned_user_id is set - during testing this isn't always set +if (!isset($_REQUEST['assigned_user_id'])) { + $_REQUEST['assigned_user_id'] = ''; +} + +if ($email_type == 'archived') { + global $current_user; + $loc = 'Location: index.php?module=Emails&action=ListView&all=true'; +} else { +$loc = 'Location: index.php?module='.$_REQUEST['return_module'].'&action='.$_REQUEST['return_action'].'&record='.$_REQUEST['return_id'].'&type='.$_REQUEST['type'].'&assigned_user_id='.$_REQUEST['assigned_user_id']; +} + +header($loc); +?> diff --git a/modules/Emails/DetailView.html b/modules/Emails/DetailView.html new file mode 100644 index 00000000..77a0f253 --- /dev/null +++ b/modules/Emails/DetailView.html @@ -0,0 +1,165 @@ + + + + +
    + + + + + + + + + + + + + + + + + + + + + +
    + +   + +   + + {ADMIN_EDIT}
    +
    + +
    + + {PAGINATION} + + + + + + + + + + + + + + + + + + + + + + + + + {REPLY_TO} + + + + + + + + + + + + + + + + + + + + + + + + +
    {MOD.LBL_DATE_SENT}{DATE_START} {TIME_START} {APP.LBL_DATE_ENTERED}{DATE_ENTERED} {APP.LBL_BY} {CREATED_BY} 
      {APP.LBL_DATE_MODIFIED}{DATE_MODIFIED} {APP.LBL_BY} {MODIFIED_BY} 
    {APP.LBL_ASSIGNED_TO}{ASSIGNED_TO} {PARENT_TYPE}{PARENT_NAME}
    {MOD.LBL_FROM}{FROM} 
    {MOD.LBL_TO}{TO} 
    {MOD.LBL_CC}{CC} 
    {MOD.LBL_BCC}{BCC} 
    {MOD.LBL_SUBJECT}{NAME} 
    {MOD.LBL_BODY} +
    {DESCRIPTION_HTML}
    +
    + + +
    {MOD.LBL_ATTACHMENTS}{ATTACHMENTS}
    +
    + diff --git a/modules/Emails/DetailView.php b/modules/Emails/DetailView.php new file mode 100644 index 00000000..f51abd05 --- /dev/null +++ b/modules/Emails/DetailView.php @@ -0,0 +1,356 @@ +getNextFree(); +} +//// END 'NEXT FREE' +/////////////////////////////////////////////////////////////////////////////// + +if (isset($_REQUEST['offset']) or isset($_REQUEST['record'])) { + $result = $detailView->processSugarBean("EMAIL", $focus, $offset); + if($result == null) { + sugar_die($app_strings['ERROR_NO_RECORD']); + } + $focus=$result; +} else { + header("Location: index.php?module=Emails&action=index"); + die(); +} + +/* if the Email status is draft, say as a saved draft to a Lead/Case/etc., + * don't show detail view. go directly to EditView */ +if($focus->status == 'draft') { + //header('Location: index.php?module=Emails&action=EditView&record='.$_REQUEST['record']); + //die(); +} + +// ACL Access Check +if (!$focus->ACLAccess('DetailView')){ + ACLController::displayNoAccess(true); + sugar_cleanup(true); +} + +//needed when creating a new email with default values passed in +if (isset($_REQUEST['contact_name']) && is_null($focus->contact_name)) { + $focus->contact_name = $_REQUEST['contact_name']; +} +if (isset($_REQUEST['contact_id']) && is_null($focus->contact_id)) { + $focus->contact_id = $_REQUEST['contact_id']; +} +if (isset($_REQUEST['opportunity_name']) && is_null($focus->parent_name)) { + $focus->parent_name = $_REQUEST['opportunity_name']; +} +if (isset($_REQUEST['opportunity_id']) && is_null($focus->parent_id)) { + $focus->parent_id = $_REQUEST['opportunity_id']; +} +if (isset($_REQUEST['account_name']) && is_null($focus->parent_name)) { + $focus->parent_name = $_REQUEST['account_name']; +} +if (isset($_REQUEST['account_id']) && is_null($focus->parent_id)) { + $focus->parent_id = $_REQUEST['account_id']; +} + +// un/READ flags +if (!empty($focus->status)) { + // "Read" flag for InboundEmail + if($focus->status == 'unread') { + // creating a new instance here to avoid data corruption below + $e = new Email(); + $e->retrieve($focus->id); + $e->status = 'read'; + $e->save(); + $email_type = $e->status; + } else { + $email_type = $focus->status; + } + +} elseif (!empty($_REQUEST['type'])) { + $email_type = $_REQUEST['type']; +} + + +/////////////////////////////////////////////////////////////////////////////// +//// OUTPUT +/////////////////////////////////////////////////////////////////////////////// +echo "\n

    \n"; +$GLOBALS['log']->info("Email detail view"); +if ($email_type == 'archived') { + echo getClassicModuleTitle('Emails', array($mod_strings['LBL_ARCHIVED_EMAIL'],$focus->name), true); + $xtpl=new XTemplate ('modules/Emails/DetailView.html'); +} else { + $xtpl=new XTemplate ('modules/Emails/DetailViewSent.html'); + if($focus->type == 'out') { + echo getClassicModuleTitle('Emails', array($mod_strings['LBL_SENT_MODULE_NAME'],$focus->name), true); + //$xtpl->assign('DISABLE_REPLY_BUTTON', 'NONE'); + } elseif ($focus->type == 'draft') { + $xtpl->assign('DISABLE_FORWARD_BUTTON', 'NONE'); + echo getClassicModuleTitle('Emails', array($mod_strings['LBL_LIST_FORM_DRAFTS_TITLE'],$focus->name), true); + } elseif($focus->type == 'inbound') { + echo getClassicModuleTitle('Emails', array($mod_strings['LBL_INBOUND_TITLE'],$focus->name), true); + } +} +echo "\n

    \n"; + + + +/////////////////////////////////////////////////////////////////////////////// +//// RETURN NAVIGATION +$uri = isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : 'index.php'; +$start = $focus->getStartPage($uri); +if (isset($_REQUEST['return_id'])) { // coming from a subpanel, return_module|action is not set + $xtpl->assign('RETURN_ID', $_REQUEST['return_id']); + if (isset($_REQUEST['return_module'])) $xtpl->assign('RETURN_MODULE', $_REQUEST['return_module']); + else $xtpl->assign('RETURN_MODULE', 'Emails'); + if (isset($_REQUEST['return_action'])) $xtpl->assign('RETURN_ACTION', $_REQUEST['return_action']); + else $xtpl->assign('RETURN_ACTION', 'DetailView'); +} + +if(isset($start['action']) && !empty($start['action'])) { + $xtpl->assign('DELETE_RETURN_ACTION', $start['action']); +} +if(isset($start['module']) && !empty($start['module'])) { + $xtpl->assign('DELETE_RETURN_MODULE', $start['module']); +} +if(isset($start['record']) && !empty($start['record'])) { + $xtpl->assign('DELETE_RETURN_ID', $start['record']); +} +// this is to support returning to My Inbox +if(isset($start['type']) && !empty($start['type'])) { + $xtpl->assign('DELETE_RETURN_TYPE', $start['type']); +} +if(isset($start['assigned_user_id']) && !empty($start['assigned_user_id'])) { + $xtpl->assign('DELETE_RETURN_ASSIGNED_USER_ID', $start['assigned_user_id']); +} + + + +//// END RETURN NAVIGATION +/////////////////////////////////////////////////////////////////////////////// + + +// DEFAULT TO TEXT IF NO HTML CONTENT: +$html = trim(from_html($focus->description_html)); +if(empty($html)) { + $xtpl->assign('SHOW_PLAINTEXT', 'true'); + $description = nl2br($focus->description); +} else { + $xtpl->assign('SHOW_PLAINTEXT', 'false'); + $description = from_html($focus->description_html); +} +$show_subpanels=true; +//if the email is of type campaign, process the macros...using the values stored in the relationship table. +//this is is part of the feature that adds support for one email per campaign. +if ($focus->type=='campaign' and !empty($_REQUEST['parent_id']) and !empty($_REQUEST['parent_module'])) { + $show_subpanels=false; + $parent_id=$_REQUEST['parent_id']; + + // cn: bug 14300 - emails_beans schema refactor - fixing query + $query="SELECT * FROM emails_beans WHERE email_id='{$focus->id}' AND bean_id='{$parent_id}' AND bean_module = '{$_REQUEST['parent_module']}' " ; + + $res=$focus->db->query($query); + $row=$focus->db->fetchByAssoc($res); + if (!empty($row)) { + $campaign_data=$row['campaign_data']; + $macro_values=array(); + if (!empty($campaign_data)) { + $macro_values=unserialize(from_html($campaign_data)); + } + + if (count($macro_values) > 0) { + $m_keys=array_keys($macro_values); + $m_values=array_values($macro_values); + + $focus->name = str_replace($m_keys,$m_values,$focus->name); + $focus->description = str_replace($m_keys,$m_values,$focus->description); + $focus->description_html = str_replace($m_keys,$m_values,$focus->description_html); + if (!empty($macro_values['sugar_to_email_address'])) { + $focus->to_addrs=$macro_values['sugar_to_email_address']; + } + } + } +} +//if not empty or set to test (from test campaigns) +if (!empty($focus->parent_type) && $focus->parent_type !='test') { + $xtpl->assign('PARENT_MODULE', $focus->parent_type); + $xtpl->assign('PARENT_TYPE_UNTRANSLATE', $focus->parent_type); + $xtpl->assign('PARENT_TYPE', $app_list_strings['record_type_display'][$focus->parent_type] . ':'); +} + +$to_addr = !empty($focus->to_addrs_names) ? htmlspecialchars($focus->to_addrs_names, ENT_COMPAT, 'UTF-8') : nl2br($focus->to_addrs); +$from_addr = !empty($focus->from_addr_name) ? htmlspecialchars($focus->from_addr_name, ENT_COMPAT, 'UTF-8') : nl2br($focus->from_addr); +$cc_addr = !empty($focus->cc_addrs_names) ? htmlspecialchars($focus->cc_addrs_names, ENT_COMPAT, 'UTF-8') : nl2br($focus->cc_addrs); +$bcc_addr = !empty($focus->bcc_addrs_names) ? htmlspecialchars($focus->bcc_addrs_names, ENT_COMPAT, 'UTF-8') : nl2br($focus->bcc_addrs); + +$xtpl->assign('MOD', $mod_strings); +$xtpl->assign('APP', $app_strings); +$xtpl->assign('GRIDLINE', $gridline); +$xtpl->assign('PRINT_URL', 'index.php?'.$GLOBALS['request_string']); +$xtpl->assign('ID', $focus->id); +$xtpl->assign('TYPE', $email_type); +$xtpl->assign('PARENT_NAME', $focus->parent_name); +$xtpl->assign('PARENT_ID', $focus->parent_id); +$xtpl->assign('NAME', $focus->name); +$xtpl->assign('ASSIGNED_TO', $focus->assigned_user_name); +$xtpl->assign('DATE_MODIFIED', $focus->date_modified); +$xtpl->assign('DATE_ENTERED', $focus->date_entered); +$xtpl->assign('DATE_START', $focus->date_start); +$xtpl->assign('TIME_START', $focus->time_start); +$xtpl->assign('FROM', $from_addr); +$xtpl->assign('TO', $to_addr); +$xtpl->assign('CC', $cc_addr); +$xtpl->assign('BCC', $bcc_addr); +$xtpl->assign('CREATED_BY', $focus->created_by_name); +$xtpl->assign('MODIFIED_BY', $focus->modified_by_name); +$xtpl->assign('DESCRIPTION', nl2br($focus->description)); +$xtpl->assign('DESCRIPTION_HTML', from_html($focus->description_html)); +$xtpl->assign('DATE_SENT', $focus->date_entered); +$xtpl->assign('EMAIL_NAME', 'RE: '.$focus->name); +$xtpl->assign("TAG", $focus->listviewACLHelper()); +if(!empty($focus->raw_source)) { + $xtpl->assign("RAW_METADATA", $focus->id); +} else { + $xtpl->assign("DISABLE_RAW_BUTTON", 'none'); +} + +if(!empty($focus->reply_to_email)) { + $replyTo = " +
    ".$mod_strings['LBL_REPLY_TO_NAME']."".$focus->reply_to_email."
    + + + + + + + + + + +
    + +   + +   + +   + + {ADMIN_EDIT}
    + + +
    + + {PAGINATION} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    {APP.LBL_ASSIGNED_TO}{ASSIGNED_TO}{MOD.LBL_DATE_SENT}{DATE_START} {TIME_START}
      {PARENT_TYPE}{PARENT_NAME}
    {MOD.LBL_FROM}{FROM} 
    {MOD.LBL_TO}{TO} 
    {MOD.LBL_CC}{CC} 
    {MOD.LBL_BCC}{BCC} 
    {MOD.LBL_SUBJECT}{NAME} 
    {MOD.LBL_BODY} +
    {DESCRIPTION_HTML}
    +
    + + +
    {MOD.LBL_ATTACHMENTS}{ATTACHMENTS}
    +
    + diff --git a/modules/Emails/EditView.html b/modules/Emails/EditView.html new file mode 100644 index 00000000..0fe9e724 --- /dev/null +++ b/modules/Emails/EditView.html @@ -0,0 +1,434 @@ + + + + + + + + + +{MESSAGE} + +
    + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + {ADMIN_EDIT} +
    + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + + + + +   + + + + + +  {CHANGE_PARENT_BUTTON} + +
    + + {APP.LBL_ASSIGNED_TO}  + + + + + + + + + + + + + + + + +
    +   +
    +   + + {MOD.LBL_NOTE_SEMICOLON} + +   +
    + + {MOD.LBL_TO} + + + + + + + + +
    + + + + + + {CHANGE_TO_ADDRS_BUTTON} +
    +
    +
    + + {MOD.LBL_CC} + + + + + + + + +
    + + + + + + {CHANGE_CC_ADDRS_BUTTON} +
    +
    +
    + + {MOD.LBL_BCC} + + + + + + + +
    + + + + + + {CHANGE_BCC_ADDRS_BUTTON} +
    +
    + + {MOD.LBL_FROM} + + + + + + + +
    + {FROM_ADDR_GROUP} + + +
    +
    +
    +   +
    + + {MOD.LBL_SUBJECT} + + + + + +
    + {MOD.LBL_BODY} + + +
    + + {MOD.LBL_EMAIL_EDITOR_OPTION} +
    +
    +
    + + {MOD.LBL_USE_TEMPLATE}  + + + + + +
    +   + + {TINY} + +
    + +
    +
    + + {MOD.LBL_EDIT_ALT_TEXT} +
    + +
    +
    + {MOD.LBL_ATTACHMENTS} + + {ATTACHMENTS_JAVASCRIPT} {ATTACHMENTS} +
    +
    +
    + + + + + + + + + + + + + + + + + + + + +
    + + +
    +
    +
    +{JAVASCRIPT} + + \ No newline at end of file diff --git a/modules/Emails/EditView.php b/modules/Emails/EditView.php new file mode 100644 index 00000000..0d00c4c4 --- /dev/null +++ b/modules/Emails/EditView.php @@ -0,0 +1,780 @@ +info("Email edit view"); + +require_once('include/SugarTinyMCE.php'); + + + + +global $theme; +global $app_strings; +global $app_list_strings; +global $mod_strings; +global $current_user; +global $sugar_version, $sugar_config; +global $timedate; + +/////////////////////////////////////////////////////////////////////////////// +//// PREPROCESS BEAN DATA FOR DISPLAY +$focus = new Email(); +$email_type = 'archived'; + +if(isset($_REQUEST['record'])) { + $focus->retrieve($_REQUEST['record']); +} +if(!empty($_REQUEST['type'])) { + $email_type = $_REQUEST['type']; +} elseif(!empty($focus->id)) { + $email_type = $focus->type; +} + +$focus->type = $email_type; + +//needed when creating a new email with default values passed in +if(isset($_REQUEST['contact_name']) && is_null($focus->contact_name)) { + $focus->contact_name = $_REQUEST['contact_name']; +} + +if(!empty($_REQUEST['load_id']) && !empty($beanList[$_REQUEST['load_module']])) { + $class_name = $beanList[$_REQUEST['load_module']]; + require_once($beanFiles[$class_name]); + $contact = new $class_name(); + if($contact->retrieve($_REQUEST['load_id'])) { + $link_id = $class_name . '_id'; + $focus->$link_id = $_REQUEST['load_id']; + $focus->contact_name = (isset($contact->full_name)) ? $contact->full_name : $contact->name; + $focus->to_addrs_names = $focus->contact_name; + $focus->to_addrs_ids = $_REQUEST['load_id']; + //Retrieve the email address. + //If Opportunity or Case then Oppurtinity/Case->Accounts->(email_addr_bean_rel->email_addresses) + //If Contacts, Leads etc.. then Contact->(email_addr_bean_rel->email_addresses) + $sugarEmailAddress = new SugarEmailAddress(); + if($class_name == 'Opportunity' || $class_name == 'aCase'){ + $account = new Account(); + if($contact->account_id != null && $account->retrieve($contact->account_id)){ + $sugarEmailAddress->handleLegacyRetrieve($account); + if(isset($account->email1)){ + $focus->to_addrs_emails = $account->email1; + $focus->to_addrs = "$focus->contact_name <$account->email1>"; + } + } + } + else{ + $sugarEmailAddress->handleLegacyRetrieve($contact); + if(isset($contact->email1)){ + $focus->to_addrs_emails = $contact->email1; + $focus->to_addrs = "$focus->contact_name <$contact->email1>"; + } + } + if(!empty($_REQUEST['parent_type']) && empty($app_list_strings['record_type_display'][$_REQUEST['parent_type']])){ + if(!empty($app_list_strings['record_type_display'][$_REQUEST['load_module']])){ + $_REQUEST['parent_type'] = $_REQUEST['load_module']; + $_REQUEST['parent_id'] = $focus->contact_id; + $_REQUEST['parent_name'] = $focus->to_addrs_names; + } else { + unset($_REQUEST['parent_type']); + unset($_REQUEST['parent_id']); + unset($_REQUEST['parent_name']); + } + } + } +} +if(isset($_REQUEST['contact_id']) && is_null($focus->contact_id)) { + $focus->contact_id = $_REQUEST['contact_id']; +} +if(isset($_REQUEST['parent_name'])) { + $focus->parent_name = $_REQUEST['parent_name']; +} +if(isset($_REQUEST['parent_id'])) { + $focus->parent_id = $_REQUEST['parent_id']; +} +if(isset($_REQUEST['parent_type'])) { + $focus->parent_type = $_REQUEST['parent_type']; +} +elseif(is_null($focus->parent_type)) { + $focus->parent_type = $app_list_strings['record_type_default_key']; +} +if(isset($_REQUEST['to_email_addrs'])) { + $focus->to_addrs = $_REQUEST['to_email_addrs']; +} +// needed when clicking through a Contacts detail view: +if(isset($_REQUEST['to_addrs_ids'])) { + $focus->to_addrs_ids = $_REQUEST['to_addrs_ids']; +} +if(isset($_REQUEST['to_addrs_emails'])) { + $focus->to_addrs_emails = $_REQUEST['to_addrs_emails']; +} +if(isset($_REQUEST['to_addrs_names'])) { + $focus->to_addrs_names = $_REQUEST['to_addrs_names']; +} +// user's email, go through 3 levels of precedence: +$from = $current_user->getEmailInfo(); +//// END PREPROCESSING +/////////////////////////////////////////////////////////////////////////////// + + +/////////////////////////////////////////////////////////////////////////////// +//// XTEMPLATE ASSIGNMENT +if($email_type == 'archived') { + echo getClassicModuleTitle('Emails', array($mod_strings['LBL_ARCHIVED_MODULE_NAME']), true); + $xtpl=new XTemplate('modules/Emails/EditViewArchive.html'); +} else { + + if(empty($_REQUEST['parent_module'])) { + $parent_module = "Emails"; + } else { + $parent_module = $_REQUEST['parent_module']; + } + if(empty($_REQUEST['parent_id'])) { + $parent_id = ""; + } else { + $parent_id = $_REQUEST['parent_id']; + } + if(empty($_REQUEST['return_module'])) { + $return_module = "Emails"; + } else { + $return_module = $_REQUEST['return_module']; + } + if(empty($_REQUEST['return_module'])) { + $return_id = ""; + } else { + $return_id = $_REQUEST['return_module']; + } + $replyType = "reply"; + if ($_REQUEST['type'] == 'forward') { + $replyType = 'forward'; + } // if + header("Location: index.php?module=Emails&action=Compose&record=$focus->id&replyForward=true&reply=$replyType"); + return; + + echo getClassicModuleTitle('Emails', array($mod_strings['LBL_COMPOSE_MODULE_NAME']), true); + $xtpl=new XTemplate('modules/Emails/EditView.html'); +} +echo "\n

    \n"; + +// CHECK USER'S EMAIL SETTINGS TO ENABLE/DISABLE 'SEND' BUTTON +if(!$focus->check_email_settings() &&($email_type == 'out' || $email_type == 'draft')) { + print "".$mod_strings['WARNING_SETTINGS_NOT_CONF']." ".$mod_strings['LBL_EDIT_MY_SETTINGS'].""; + $xtpl->assign("DISABLE_SEND", 'DISABLED'); +} + +// CHECK THAT SERVER HAS A PLACE TO PUT UPLOADED TEMP FILES SO THAT ATTACHMENTS WILL WORK +// cn: Bug 5995 +$tmpUploadDir = ini_get('upload_tmp_dir'); +if(!empty($tmpUploadDir)) { + if(!is_writable($tmpUploadDir)) { + echo "{$mod_strings['WARNING_UPLOAD_DIR_NOT_WRITABLE']}"; + } +} else { + //echo "{$mod_strings['WARNING_NO_UPLOAD_DIR']}"; +} + + +/////////////////////////////////////////////////////////////////////////////// +//// INBOUND EMAIL HANDLING +if(isset($_REQUEST['email_name'])) { + $name = str_replace('_',' ',$_REQUEST['email_name']); +} +if(isset($_REQUEST['inbound_email_id'])) { + $ieMail = new Email(); + $ieMail->retrieve($_REQUEST['inbound_email_id']); + + $quoted = ''; + // cn: bug 9725: replies/forwards lose real content + $quotedHtml = $ieMail->quoteHtmlEmail($ieMail->description_html); + + // plain-text + $desc = nl2br(trim($ieMail->description)); + + $exDesc = explode('
    ', $desc); + foreach($exDesc as $k => $line) { + $quoted .= '> '.trim($line)."\r"; + } + + // prefill empties with the other's contents + if(empty($quotedHtml) && !empty($quoted)) { + $quotedHtml = nl2br($quoted); + } + if(empty($quoted) && !empty($quotedHtml)) { + $quoted = strip_tags(br2nl($quotedHtml)); + } + + // forwards have special text + if($_REQUEST['type'] == 'forward') { + $header = $ieMail->getForwardHeader(); + // subject is handled in Subject line handling below + } else { + // we have a reply in focus + $header = $ieMail->getReplyHeader(); + } + + $quoted = br2nl($header.$quoted); + $quotedHtml = $header.$quotedHtml; + + + // if not a forward: it's a reply + if($_REQUEST['type'] != 'forward') { + $ieMailName = 'RE: '.$ieMail->name; + } else { + $ieMailName = $ieMail->name; + } + + $focus->id = null; // nulling this to prevent overwriting a replied email(we're basically doing a "Duplicate" function) + $focus->to_addrs = $ieMail->from_addr; + $focus->description = $quoted; // don't know what i was thinking: ''; // this will be filled on save/send + $focus->description_html = $quotedHtml; // cn: bug 7357 - htmlentities() breaks FCKEditor + $focus->parent_type = $ieMail->parent_type; + $focus->parent_id = $ieMail->parent_id; + $focus->parent_name = $ieMail->parent_name; + $focus->name = $ieMailName; + $xtpl->assign('INBOUND_EMAIL_ID',$_REQUEST['inbound_email_id']); + // un/READ flags + if(!empty($ieMail->status)) { + // "Read" flag for InboundEmail + if($ieMail->status == 'unread') { + // creating a new instance here to avoid data corruption below + $e = new Email(); + $e->retrieve($ieMail->id); + $e->status = 'read'; + $e->save(); + $email_type = $e->status; + } + } + + /////////////////////////////////////////////////////////////////////////// + //// PRIMARY PARENT LINKING + if(empty($focus->parent_type) && empty($focus->parent_id)) { + $focus->fillPrimaryParentFields(); + } + //// END PRIMARY PARENT LINKING + /////////////////////////////////////////////////////////////////////////// + + // setup for my/mailbox email switcher + $mbox = $ieMail->getMailboxDefaultEmail(); + $user = $current_user->getPreferredEmail(); + $useGroup = '  + '; + $useGroup .= $mod_strings['LBL_USE_MAILBOX_INFO']; + + $xtpl->assign('FROM_ADDR_GROUP', $useGroup); +} +//// END INBOUND EMAIL HANDLING +/////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +//// SUBJECT FIELD MANIPULATION +$name = ''; +if(!empty($_REQUEST['parent_id']) && !empty($_REQUEST['parent_type'])) { + $focus->parent_id = $_REQUEST['parent_id']; + $focus->parent_type = $_REQUEST['parent_type']; +} +if(!empty($focus->parent_id) && !empty($focus->parent_type)) { + if($focus->parent_type == 'Cases') { + + $myCase = new aCase(); + $myCase->retrieve($focus->parent_id); + $myCaseMacro = $myCase->getEmailSubjectMacro(); + if(isset($ieMail->name) && !empty($ieMail->name)) { // if replying directly to an InboundEmail + $oldEmailSubj = $ieMail->name; + } elseif(isset($_REQUEST['parent_name']) && !empty($_REQUEST['parent_name'])) { + $oldEmailSubj = $_REQUEST['parent_name']; + } else { + $oldEmailSubj = $focus->name; // replying to an email using old subject + } + + if(!preg_match('/^re:/i', $oldEmailSubj)) { + $oldEmailSubj = 'RE: '.$oldEmailSubj; + } + $focus->name = $oldEmailSubj; + + if(strpos($focus->name, str_replace('%1',$myCase->case_number,$myCaseMacro))) { + $name = $focus->name; + } else { + $name = $focus->name.' '.str_replace('%1',$myCase->case_number,$myCaseMacro); + } + } else { + $name = $focus->name; + } +} else { + if(empty($focus->name)) { + $name = ''; + } else { + $name = $focus->name; + } +} +if($email_type == 'forward') { + $name = 'FW: '.$name; +} +//// END SUBJECT FIELD MANIPULATION +/////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +//// GENERAL TEMPLATE ASSIGNMENTS +$xtpl->assign('MOD', $mod_strings); +$xtpl->assign('APP', $app_strings); +$xtpl->assign('THEME', SugarThemeRegistry::current()->__toString()); +if(!isset($focus->id)) $xtpl->assign('USER_ID', $current_user->id); +if(!isset($focus->id) && isset($_REQUEST['contact_id'])) $xtpl->assign('CONTACT_ID', $_REQUEST['contact_id']); + +if(isset($_REQUEST['return_module']) && !empty($_REQUEST['return_module'])) { + $xtpl->assign('RETURN_MODULE', $_REQUEST['return_module']); +} else { + $xtpl->assign('RETURN_MODULE', 'Emails'); +} +if(isset($_REQUEST['return_action']) && !empty($_REQUEST['return_action']) && ($_REQUEST['return_action'] != 'SubPanelViewer')) { + $xtpl->assign('RETURN_ACTION', $_REQUEST['return_action']); +} else { + $xtpl->assign('RETURN_ACTION', 'DetailView'); +} +if(isset($_REQUEST['return_id']) && !empty($_REQUEST['return_id'])) { + $xtpl->assign('RETURN_ID', $_REQUEST['return_id']); +} +// handle Create $module then Cancel +if(empty($_REQUEST['return_id']) && !isset($_REQUEST['type'])) { + $xtpl->assign('RETURN_ACTION', 'index'); +} + +$xtpl->assign('PRINT_URL', 'index.php?'.$GLOBALS['request_string']); + + + /////////////////////////////////////////////////////////////////////////////// + //// QUICKSEARCH CODE + require_once('include/QuickSearchDefaults.php'); + $qsd = new QuickSearchDefaults(); + $sqs_objects = array('EditView_parent_name' => $qsd->getQSParent(), + 'EditView_assigned_user_name' => $qsd->getQSUser(), + ); + + + $json = getJSONobj(); + + $sqs_objects_encoded = $json->encode($sqs_objects); + $quicksearch_js = <<sqs_objects = $sqs_objects_encoded; var dialog_loaded; + function parent_typechangeQS() { + //new_module = document.getElementById('parent_type').value; + new_module = document.EditView.parent_type.value; + if(new_module == 'Contacts' || new_module == 'Leads' || typeof(disabledModules[new_module]) != 'undefined') { + sqs_objects['EditView_parent_name']['disable'] = true; + document.getElementById('parent_name').readOnly = true; + } + else { + sqs_objects['EditView_parent_name']['disable'] = false; + document.getElementById('parent_name').readOnly = false; + } + + sqs_objects['EditView_parent_name']['modules'] = new Array(new_module); + enableQS(false); + } + parent_typechangeQS(); + +EOQ; + $xtpl->assign('JAVASCRIPT', get_set_focus_js().$quicksearch_js); + //// END QUICKSEARCH CODE + /////////////////////////////////////////////////////////////////////////////// + +// cn: bug 14191 - duping archive emails overwrites the original +if(!isset($_REQUEST['isDuplicate']) || $_REQUEST['isDuplicate'] != 'true') { + $xtpl->assign('ID', $focus->id); +} + +if(isset($_REQUEST['parent_type']) && !empty($_REQUEST['parent_type']) && isset($_REQUEST['parent_id']) && !empty($_REQUEST['parent_id'])) { + $xtpl->assign('OBJECT_ID', $_REQUEST['parent_id']); + $xtpl->assign('OBJECT_TYPE', $_REQUEST['parent_type']); +} +$xtpl->assign('FROM_ADDR', $focus->from_addr); +//// prevent TO: prefill when type is 'forward' +if($email_type != 'forward') { + $xtpl->assign('TO_ADDRS', $focus->to_addrs); + $xtpl->assign('TO_ADDRS_IDS', $focus->to_addrs_ids); + $xtpl->assign('TO_ADDRS_NAMES', $focus->to_addrs_names); + $xtpl->assign('TO_ADDRS_EMAILS', $focus->to_addrs_emails); + $xtpl->assign('CC_ADDRS', $focus->cc_addrs); + $xtpl->assign('CC_ADDRS_IDS', $focus->cc_addrs_ids); + $xtpl->assign('CC_ADDRS_NAMES', $focus->cc_addrs_names); + $xtpl->assign('CC_ADDRS_EMAILS', $focus->cc_addrs_emails); + $xtpl->assign('BCC_ADDRS', $focus->bcc_addrs); + $xtpl->assign('BCC_ADDRS_IDS', $focus->bcc_addrs_ids); + $xtpl->assign('BCC_ADDRS_NAMES', $focus->bcc_addrs_names); + $xtpl->assign('BCC_ADDRS_EMAILS', $focus->bcc_addrs_emails); +} + +//$xtpl->assign('FROM_ADDR', $from['name'].' <'.$from['email'].'>'); +$xtpl->assign('FROM_ADDR_NAME', $from['name']); +$xtpl->assign('FROM_ADDR_EMAIL', $from['email']); + +$xtpl->assign('NAME', from_html($name)); +//$xtpl->assign('DESCRIPTION_HTML', from_html($focus->description_html)); +$xtpl->assign('DESCRIPTION', $focus->description); +$xtpl->assign('TYPE',$email_type); + +// Unimplemented until jscalendar language files are fixed +// $xtpl->assign('CALENDAR_LANG',((empty($cal_codes[$current_language])) ? $cal_codes[$default_language] : $cal_codes[$current_language])); +$xtpl->assign('CALENDAR_LANG', 'en'); +$xtpl->assign('CALENDAR_DATEFORMAT', $timedate->get_cal_date_format()); +$xtpl->assign('DATE_START', $focus->date_start); +$xtpl->assign('TIME_FORMAT', '('. $timedate->get_user_time_format().')'); +$xtpl->assign('TIME_START', substr($focus->time_start,0,5)); +$xtpl->assign('TIME_MERIDIEM', $timedate->AMPMMenu('',$focus->time_start)); + +$parent_types = $app_list_strings['record_type_display']; +$disabled_parent_types = ACLController::disabledModuleList($parent_types,false, 'list'); + +foreach($disabled_parent_types as $disabled_parent_type){ + if($disabled_parent_type != $focus->parent_type){ + unset($parent_types[$disabled_parent_type]); + } +} + +$xtpl->assign('TYPE_OPTIONS', get_select_options_with_id($parent_types, $focus->parent_type)); +$xtpl->assign('USER_DATEFORMAT', '('. $timedate->get_user_date_format().')'); +$xtpl->assign('PARENT_NAME', $focus->parent_name); +$xtpl->assign('PARENT_ID', $focus->parent_id); +if(empty($focus->parent_type)) { + $xtpl->assign('PARENT_RECORD_TYPE', ''); +} else { + $xtpl->assign('PARENT_RECORD_TYPE', $focus->parent_type); +} + +if(is_admin($current_user) && $_REQUEST['module'] != 'DynamicLayout' && !empty($_SESSION['editinplace'])){ + $record = ''; + if(!empty($_REQUEST['record'])){ + $record = $_REQUEST['record']; + } + $xtpl->assign('ADMIN_EDIT',"".SugarThemeRegistry::current()->getImage("EditLayout","border='0' alt='Edit Layout' align='bottom'").""); +} + +//// END GENERAL TEMPLATE ASSIGNMENTS +/////////////////////////////////////////////////////////////////////////////// + + +/////////////////////////////////////// +/// +/// SETUP PARENT POPUP + +$popup_request_data = array( + 'call_back_function' => 'set_return', + 'form_name' => 'EditView', + 'field_to_name_array' => array( + 'id' => 'parent_id', + 'name' => 'parent_name', + ), + ); + +$encoded_popup_request_data = $json->encode($popup_request_data); + +/// Users Popup +$popup_request_data = array( + 'call_back_function' => 'set_return', + 'form_name' => 'EditView', + 'field_to_name_array' => array( + 'id' => 'assigned_user_id', + 'user_name' => 'assigned_user_name', + ), + ); +$xtpl->assign('encoded_users_popup_request_data', $json->encode($popup_request_data)); + + +// +/////////////////////////////////////// + +$change_parent_button = '\n" + .''; + +$xtpl->assign("CHANGE_PARENT_BUTTON", $change_parent_button); + +$button_attr = ''; +if(!ACLController::checkAccess('Contacts', 'list', true)){ + $button_attr = 'disabled="disabled"'; +} + +$change_to_addrs_button = '\n"; +$xtpl->assign("CHANGE_TO_ADDRS_BUTTON", $change_to_addrs_button); + +$change_cc_addrs_button = '\n"; +$xtpl->assign("CHANGE_CC_ADDRS_BUTTON", $change_cc_addrs_button); + +$change_bcc_addrs_button = '\n"; +$xtpl->assign("CHANGE_BCC_ADDRS_BUTTON", $change_bcc_addrs_button); + + +/////////////////////////////////////// +//// USER ASSIGNMENT +global $current_user; +if(is_admin($current_user) && $_REQUEST['module'] != 'DynamicLayout' && !empty($_SESSION['editinplace'])) { + $record = ''; + if(!empty($_REQUEST['record'])) { + $record = $_REQUEST['record']; + } + $xtpl->assign('ADMIN_EDIT',"".SugarThemeRegistry::current()->getImage("EditLayout","border='0' alt='Edit Layout' align='bottom'").""); +} + +if(empty($focus->assigned_user_id) && empty($focus->id)) + $focus->assigned_user_id = $current_user->id; +if(empty($focus->assigned_name) && empty($focus->id)) + $focus->assigned_user_name = $current_user->user_name; +$xtpl->assign('ASSIGNED_USER_OPTIONS', get_select_options_with_id(get_user_array(TRUE, 'Active', $focus->assigned_user_id), $focus->assigned_user_id)); +$xtpl->assign('ASSIGNED_USER_NAME', $focus->assigned_user_name); +$xtpl->assign('ASSIGNED_USER_ID', $focus->assigned_user_id); +$xtpl->assign('DURATION_HOURS', $focus->duration_hours); +$xtpl->assign('TYPE_OPTIONS', get_select_options_with_id($parent_types, $focus->parent_type)); + +if(isset($focus->duration_minutes)) { + $xtpl->assign('DURATION_MINUTES_OPTIONS', get_select_options_with_id($focus->minutes_values,$focus->duration_minutes)); +} +//// END USER ASSIGNMENT +/////////////////////////////////////// + + + +//Add Custom Fields +require_once('modules/DynamicFields/templates/Files/EditView.php'); + + +/////////////////////////////////////// +//// ATTACHMENTS +$attachments = ''; +if(!empty($focus->id) || (!empty($_REQUEST['record']) && $_REQUEST['type'] == 'forward')) { + + $attachments = "\n"; + $ids = ''; + + $focusId = empty($focus->id) ? $_REQUEST['record'] : $focus->id; + $note = new Note(); + $where = "notes.parent_id='{$focusId}' AND notes.filename IS NOT NULL"; + $notes_list = $note->get_full_list("", $where,true); + + if(!isset($notes_list)) { + $notes_list = array(); + } + for($i = 0;$i < count($notes_list);$i++) { + $the_note = $notes_list[$i]; + if(empty($the_note->filename)) { + continue; + } + + // cn: bug 8034 - attachments from forwards/replies lost when saving drafts + if(!empty($ids)) { + $ids .= ","; + } + $ids .= $the_note->id; + + $attachments .= " +
    +  "; + $attachments .= "id."&type=Notes\">".$the_note->name."
    "; + //$attachments .= ''. $the_note->filename .'
    '; + + } + // cn: bug 8034 - attachments from forwards/replies lost when saving drafts + $attachments .= ""; + + // workaround $mod_strings being overriden by Note object instantiation above. + global $current_language, $mod_strings; + $mod_strings = return_module_language($current_language, 'Emails'); +} + +$attJs = ''; +$xtpl->assign('ATTACHMENTS', $attachments); +$xtpl->assign('ATTACHMENTS_JAVASCRIPT', $attJs); +//// END ATTACHMENTS +/////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +//// DOCUMENTS +$popup_request_data = array( + 'call_back_function' => 'document_set_return', + 'form_name' => 'EditView', + 'field_to_name_array' => array( + 'id' => 'related_doc_id', + 'document_name' => 'related_document_name', + ), + ); +$json = getJSONobj(); +$xtpl->assign('encoded_document_popup_request_data', $json->encode($popup_request_data)); +//// END DOCUMENTS +/////////////////////////////////////////////////////////////////////////////// + +$parse_open = true; + +if($parse_open) { + $xtpl->parse('main.open_source_1'); +} +/////////////////////////////////////////////////////////////////////////////// +//// EMAIL TEMPLATES +if(ACLController::checkAccess('EmailTemplates', 'list', true) && ACLController::checkAccess('EmailTemplates', 'view', true)) { + $et = new EmailTemplate(); + $etResult = $focus->db->query($et->create_new_list_query('','',array(),array(),'')); + $email_templates_arr[] = ''; + while($etA = $focus->db->fetchByAssoc($etResult)) { + $email_templates_arr[$etA['id']] = $etA['name']; + } +} else { + $email_templates_arr = array('' => $app_strings['LBL_NONE']); +} + +$xtpl->assign('EMAIL_TEMPLATE_OPTIONS', get_select_options_with_id($email_templates_arr, '')); +//// END EMAIL TEMPLATES +/////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////// +//// TEXT EDITOR +// cascade from User to Sys Default +$editor = $focus->getUserEditorPreference(); + +if($editor != 'plain') { + // this box is checked by Javascript on-load. + $xtpl->assign('EMAIL_EDITOR_OPTION', 'CHECKED'); +} +$description_html = from_html($focus->description_html); +$description = $focus->description; + +///////////////////////////////////////////////// +// signatures +if($sig = $current_user->getDefaultSignature()) { + if(!$focus->hasSignatureInBody($sig) && $focus->type != 'draft') { + if($current_user->getPreference('signature_prepend')) { + $description_html = '
    '.from_html($sig['signature_html']).'

    '.$description_html; + $description = "\n".$sig['signature']."\n\n".$description; + } else { + $description_html .= '

    '.from_html($sig['signature_html']); + $description = $description."\n\n".$sig['signature']; + } + } +} +$xtpl->assign('DESCRIPTION', $description); +// sigs +///////////////////////////////////////////////// +$tiny = new SugarTinyMCE(); +$ed = $tiny->getInstance("description_html"); +$xtpl->assign("TINY", $ed); +$xtpl->assign("DESCRIPTION_HTML", $description_html); + +$xtpl->parse('main.htmlarea'); +//// END TEXT EDITOR +/////////////////////////////////////// + +/////////////////////////////////////// +//// SPECIAL INBOUND LANDING SCREEN ASSIGNS +if(!empty($_REQUEST['inbound_email_id'])) { + if(!empty($_REQUEST['start'])) { + $parts = $focus->getStartPage(base64_decode($_REQUEST['start'])); + $xtpl->assign('RETURN_ACTION', $parts['action']); + $xtpl->assign('RETURN_MODULE', $parts['module']); + $xtpl->assign('GROUP', $parts['group']); + } + $xtpl->assign('ASSIGNED_USER_ID', $current_user->id); + $xtpl->assign('MYINBOX', 'this.form.type.value=\'inbound\';'); +} +//// END SPECIAL INBOUND LANDING SCREEN ASSIGNS +/////////////////////////////////////// + +echo ''; +$jsVars = 'var lbl_send_anyways = "'.$mod_strings['LBL_SEND_ANYWAYS'].'";'; +$xtpl->assign('JS_VARS', $jsVars); +$xtpl->parse("main"); +$xtpl->out("main"); +echo ''; +//// END XTEMPLATE ASSIGNMENT +/////////////////////////////////////////////////////////////////////////////// + + +$javascript = new javascript(); +$javascript->setFormName('EditView'); +$javascript->setSugarBean($focus); +$skip_fields = array(); +if($email_type == 'out') { + $skip_fields['name'] = 1; + $skip_fields['date_start'] = 1; +} +$javascript->addAllFields('',$skip_fields); +$javascript->addToValidateBinaryDependency('parent_name', 'alpha', $app_strings['ERR_SQS_NO_MATCH_FIELD'] . $mod_strings['LBL_MEMBER_OF'], 'false', '', 'parent_id'); +$javascript->addToValidateBinaryDependency('parent_type', 'alpha', $app_strings['ERR_SQS_NO_MATCH_FIELD'] . $mod_strings['LBL_MEMBER_OF'], 'false', '', 'parent_id'); +$javascript->addToValidateBinaryDependency('user_name', 'alpha', $app_strings['ERR_SQS_NO_MATCH_FIELD'] . $app_strings['LBL_ASSIGNED_TO'], 'false', '', 'assigned_user_id'); +if($email_type == 'archived') { + $javascript->addFieldIsValidDate('date_start', 'date', $mod_strings['LBL_DATE'], $mod_strings['ERR_DATE_START'], true); + $javascript->addFieldIsValidTime('time_start', 'time', $mod_strings['LBL_TIME'], $mod_strings['ERR_TIME_SENT'], true); +} +echo $javascript->getScript(); diff --git a/modules/Emails/EditViewArchive.html b/modules/Emails/EditViewArchive.html new file mode 100644 index 00000000..f5b79f77 --- /dev/null +++ b/modules/Emails/EditViewArchive.html @@ -0,0 +1,319 @@ + + + + + + + +{MESSAGE} + +
    + + + + + + + + + + + + + + + + + + + + +
    + + {ADMIN_EDIT}
    + + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + {MOD.LBL_DATE_AND_TIME} {APP.LBL_REQUIRED_SYMBOL} + + + + + + + + + + + +
    + {APP.LBL_ENTER_DATE}  + + {TIME_MERIDIEM} +
    + {USER_DATEFORMAT} + + {TIME_FORMAT} +
    +
    +
    +   + + +  {CHANGE_PARENT_BUTTON} +
    + {APP.LBL_ASSIGNED_TO} + + + + + + + + {MOD.LBL_USE_TEMPLATE}  + + + + +
      +
     {MOD.LBL_NOTE_SEMICOLON}
    {MOD.LBL_TO} + + + + + +
    + + + + + {CHANGE_TO_ADDRS_BUTTON}
    +
    {MOD.LBL_CC} + + + + + +
    + + + + + {CHANGE_CC_ADDRS_BUTTON}
    +
    {MOD.LBL_BCC} + + + + + +
    + + + + + {CHANGE_BCC_ADDRS_BUTTON}
    +
    + {MOD.LBL_FROM} + + + + + +
    + + {FROM_ADDR_GROUP} + + +
    +
     
    {MOD.LBL_SUBJECT} + +
    {MOD.LBL_BODY} +
    + {MOD.LBL_EDIT_ALT_TEXT}
    + +
    + + +
    + {MOD.LBL_EDIT_ALT_TEXT} +
    + + +
    {MOD.LBL_ATTACHMENTS} + {ATTACHMENTS} +
    + + + + + + + + + + + + + + + + + + + + + +
    + + +
    +
    +
    + +{TINY} +{JAVASCRIPT} +{INITIALIZE_IE_RESPONSE} + + + + + diff --git a/modules/Emails/Email.php b/modules/Emails/Email.php new file mode 100644 index 00000000..5691e081 --- /dev/null +++ b/modules/Emails/Email.php @@ -0,0 +1,3125 @@ +div#rollover {position: relative;float: left;margin: none;text-decoration: none;}div#rollover a:hover {padding: 0;text-decoration: none;}div#rollover a span {display: none;}div#rollover a:hover span {text-decoration: none;display: block;width: 250px;margin-top: 5px;margin-left: 5px;position: absolute;padding: 10px;color: #333; border: 1px solid #ccc; background-color: #fff; font-size: 12px;z-index: 1000;}\n"; + var $cachePath; + var $cacheFile = 'robin.cache.php'; + var $replyDelimiter = "> "; + var $emailDescription; + var $emailDescriptionHTML; + var $emailRawSource; + var $link_action; + var $emailAddress; + var $attachments = array(); + + /* to support Email 2.0 */ + var $isDuplicate; + var $uid; + var $to; + var $flagged; + var $answered; + var $seen; + var $draft; + var $relationshipMap = array( + 'Contacts' => 'emails_contacts_rel', + 'Accounts' => 'emails_accounts_rel', + 'Leads' => 'emails_leads_rel', + 'Users' => 'emails_users_rel', + 'Prospects' => 'emails_prospects_rel', + ); + + /* public */ + var $et; // EmailUI object + + + + /** + * sole constructor + */ + function Email() { + $this->cachePath = $GLOBALS['sugar_config']['cache_dir'].'modules/Emails'; + parent::SugarBean(); + + $this->safe = new HTML_Safe(); + $this->safe->clear(); + $this->emailAddress = new SugarEmailAddress(); + } + + function email2init() { + require_once('modules/Emails/EmailUI.php'); + $this->et = new EmailUI(); + } + function bean_implements($interface){ + switch($interface){ + case 'ACL': return true; + default: return false; + } + + } + + /** + * Presaves one attachment for new email 2.0 spec + * DOES NOT CREATE A NOTE + * @return string ID of note associated with the attachment + */ + function email2saveAttachment() { + global $sugar_config; + + $filesError = array( + 0 => 'UPLOAD_ERR_OK - There is no error, the file uploaded with success.', + 1 => 'UPLOAD_ERR_INI_SIZE - The uploaded file exceeds the upload_max_filesize directive in php.ini.', + 2 => 'UPLOAD_ERR_FORM_SIZE - The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form.', + 3 => 'UPLOAD_ERR_PARTIAL - The uploaded file was only partially uploaded.', + 4 => 'UPLOAD_ERR_NO_FILE - No file was uploaded.', + 5 => 'UNKNOWN ERROR', + 6 => 'UPLOAD_ERR_NO_TMP_DIR - Missing a temporary folder. Introduced in PHP 4.3.10 and PHP 5.0.3.', + 7 => 'UPLOAD_ERR_CANT_WRITE - Failed to write file to disk. Introduced in PHP 5.1.0.', + ); + + // cn: Bug 5995 - rudimentary error checking + if($_FILES['email_attachment']['error'] != 0 && $_FILES['email_attachment']['error'] != 4) { + $GLOBALS['log']->debug('Email Attachment could not be attach due to error: '.$filesError[$_FILES['email_attachment']['error']]); + return array(); + } + + if(isset($_FILES['email_attachment']) && is_uploaded_file($_FILES['email_attachment']['tmp_name'])) { + $guid = create_guid(); + $cleanAttachmentFileName = from_html($_FILES['email_attachment']['name']); + $GLOBALS['log']->debug("Email Attachment [ {$cleanAttachmentFileName} ] "); + $cleanAttachmentFileName = str_replace("\\", "", $cleanAttachmentFileName); + $GLOBALS['log']->debug("Email Attachment [ {$cleanAttachmentFileName} ] "); + //$destination = clean_path("{$this->et->userCacheDir}/{$guid}{$cleanAttachmentFileName}"); + $destination = clean_path("{$this->et->userCacheDir}/{$guid}"); + $badExt = $this->safeAttachmentName($cleanAttachmentFileName); + if ($badExt) { + //$destination = $destination . ".txt"; + } // if + $fileName = $badExt ? $cleanAttachmentFileName . ".txt" : $cleanAttachmentFileName; + if(move_uploaded_file($_FILES['email_attachment']['tmp_name'], $destination)) { + return array( + 'guid' => $guid, + 'name' => $GLOBALS['db']->helper->escape_quote($fileName), + 'nameForDisplay' => $fileName + ); + } else { + $GLOBALS['log']->debug("Email Attachment [ {$cleanAttachmentFileName} ] could not be moved to cache dir"); + return array(); + } + } + } + + function safeAttachmentName($filename) { + global $sugar_config; + $badExtension = false; + //get position of last "." in file name + $file_ext_beg = strrpos($filename, "."); + $file_ext = ""; + + //get file extension + if($file_ext_beg !== false) { + $file_ext = substr($filename, $file_ext_beg + 1); + } + + //check to see if this is a file with extension located in "badext" + foreach($sugar_config['upload_badext'] as $badExt) { + if(strtolower($file_ext) == strtolower($badExt)) { + //if found, then append with .txt and break out of lookup + $filename = $filename . ".txt"; + $badExtension = true; + break; // no need to look for more + } // if + } // foreach + + return $badExtension; + } // fn + + /** + * takes output from email 2.0 to/cc/bcc fields and returns appropriate arrays for usage by PHPMailer + * @param string addresses + * @return array + */ + function email2ParseAddresses($addresses) { + $addresses = from_html($addresses); + $addresses = $this->et->unifyEmailString($addresses); + + $pattern = '/@.*,/U'; + preg_match_all($pattern, $addresses, $matchs); + if (!empty($matchs[0])){ + $total = $matchs[0]; + foreach ($total as $match) { + $convertedPattern = str_replace(',', '::;::', $match); + $addresses = str_replace($match, $convertedPattern, $addresses); + } //foreach + } + + $exAddr = explode("::;::", $addresses); + + $ret = array(); + $clean = array("<", ">"); + $dirty = array("<", ">"); + + foreach($exAddr as $addr) { + $name = ''; + + $addr = str_replace($dirty, $clean, $addr); + + if((strpos($addr, "<") === false) && (strpos($addr, ">") === false)) { + $address = $addr; + } else { + $address = substr($addr, strpos($addr, "<") + 1, strpos($addr, ">") - 1 - strpos($addr, "<")); + $name = substr($addr, 0, strpos($addr, "<")); + } + + $addrTemp = array(); + $addrTemp['email'] = trim($address); + $addrTemp['display'] = trim($name); + $ret[] = $addrTemp; + } + + return $ret; + } + + /** + * takes output from email 2.0 to/cc/bcc fields and returns appropriate arrays for usage by PHPMailer + * @param string addresses + * @return array + */ + function email2ParseAddressesForAddressesOnly($addresses) { + $addresses = from_html($addresses); + $pattern = '/@.*,/U'; + preg_match_all($pattern, $addresses, $matchs); + if (!empty($matchs[0])){ + $total = $matchs[0]; + foreach ($total as $match) { + $convertedPattern = str_replace(',', '::;::', $match); + $addresses = str_replace($match, $convertedPattern, $addresses); + } //foreach + } + + $exAddr = explode("::;::", $addresses); + + $ret = array(); + $clean = array("<", ">"); + $dirty = array("<", ">"); + + foreach($exAddr as $addr) { + $name = ''; + + $addr = str_replace($dirty, $clean, $addr); + + if(strpos($addr, "<") && strpos($addr, ">")) { + $address = substr($addr, strpos($addr, "<") + 1, strpos($addr, ">") - 1 - strpos($addr, "<")); + } else { + $address = $addr; + } + + $ret[] = trim($address); + } + + return $ret; + } + + /** + * Determines MIME-type encoding as possible. + * @param string $fileLocation relative path to file + * @return string MIME-type + */ + function email2GetMime($fileLocation) { + if(function_exists('mime_content_type')) { + $mime = mime_content_type($fileLocation); + } elseif(function_exists('ext2mime')) { + $mime = ext2mime($fileLocation); + } else { + $mime = 'application/octet-stream'; + } + return $mime; + } + + + function sendEmailTest($mailserver_url, $port, $ssltls, $smtp_auth_req, $smtp_username, $smtppassword, $fromaddress, $toaddress, $mail_sendtype = 'smtp') { + global $current_user,$app_strings; + $mod_strings = return_module_language($GLOBALS['current_language'], 'Emails'); //Called from EmailMan as well. + $mail = new SugarPHPMailer(); + $mail->Mailer = strtolower($mail_sendtype); + if($mail->Mailer == 'smtp') + { + $mail->Host = $mailserver_url; + $mail->Port = $port; + if (isset($ssltls) && !empty($ssltls)) { + $mail->protocol = "ssl://"; + if ($ssltls == 1) { + $mail->SMTPSecure = 'ssl'; + } // if + if ($ssltls == 2) { + $mail->SMTPSecure = 'tls'; + } // if + } else { + $mail->protocol = "tcp://"; + } + if ($smtp_auth_req) { + $mail->SMTPAuth = TRUE; + $mail->Username = $smtp_username; + $mail->Password = $smtppassword; + } + } + else + $mail->Mailer = 'sendmail'; + + $mail->Subject = from_html($mod_strings['LBL_TEST_EMAIL_SUBJECT']); + $mail->From = $fromaddress; + $mail->FromName = $current_user->name; + $mail->Sender = $mail->From; + $mail->AddAddress($toaddress); + $mail->Body = $mod_strings['LBL_TEST_EMAIL_BODY']; + + $return = array(); + + if(!$mail->Send()) { + ob_clean(); + $return['status'] = false; + $return['errorMessage'] = $app_strings['LBL_EMAIL_ERROR_PREPEND']. $mail->ErrorInfo; + return $return; + } // if + $return['status'] = true; + return $return; + } // fn + + function decodeDuringSend($htmlData) { + $htmlData = str_replace("sugarLessThan", "<", $htmlData); + $htmlData = str_replace("sugarGreaterThan", ">", $htmlData); + return $htmlData; + } + + /** + * Returns true or false if this email is a draft. + * + * @param array $request + * @return bool True indicates this email is a draft. + */ + function isDraftEmail($request) + { + return ( isset($request['saveDraft']) || ($this->type == 'draft' && $this->status == 'draft') ); + } + + /** + * Sends Email for Email 2.0 + */ + function email2Send($request) { + global $mod_strings; + global $app_strings; + global $current_user; + global $sugar_config; + global $locale; + global $timedate; + global $beanList; + global $beanFiles; + $OBCharset = $locale->getPrecedentPreference('default_email_charset'); + + /********************************************************************** + * Sugar Email PREP + */ + /* preset GUID */ + + $orignialId = ""; + if(!empty($this->id)) { + $orignialId = $this->id; + } // if + + if(empty($this->id)) { + $this->id = create_guid(); + $this->new_with_id = true; + } + + /* satisfy basic HTML email requirements */ + $this->name = $request['sendSubject']; + $this->description_html = '<html><body>'.$request['sendDescription'].'</body></html>'; + + /********************************************************************** + * PHPMAILER PREP + */ + $mail = new SugarPHPMailer(); + $mail = $this->setMailer($mail, '', $_REQUEST['fromAccount']); + if (empty($mail->Host) && !$this->isDraftEmail($request)) + { + $this->status = 'send_error'; + + if ($mail->oe->type == 'system') + echo($app_strings['LBL_EMAIL_ERROR_PREPEND']. $app_strings['LBL_EMAIL_INVALID_SYSTEM_OUTBOUND']); + else + echo($app_strings['LBL_EMAIL_ERROR_PREPEND']. $app_strings['LBL_EMAIL_INVALID_PERSONAL_OUTBOUND']); + + return false; + } + + $subject = $this->name; + $mail->Subject = from_html($this->name); + + // work-around legacy code in SugarPHPMailer + if($_REQUEST['setEditor'] == 1) { + $_REQUEST['description_html'] = $_REQUEST['sendDescription']; + $this->description_html = $_REQUEST['description_html']; + } else { + $this->description_html = ''; + $this->description = $_REQUEST['sendDescription']; + } + // end work-around + + if ( $this->isDraftEmail($request) ) + { + if($this->type != 'draft' && $this->status != 'draft') { + $this->id = create_guid(); + $this->new_with_id = true; + $this->date_entered = ""; + } // if + $q1 = "update emails_email_addr_rel set deleted = 1 WHERE email_id = '{$this->id}'"; + $r1 = $this->db->query($q1); + } // if + + if (isset($request['saveDraft'])) { + $this->type = 'draft'; + $this->status = 'draft'; + $forceSave = true; + } else { + /* Apply Email Templates */ + // do not parse email templates if the email is being saved as draft.... + $toAddresses = $this->email2ParseAddresses($_REQUEST['sendTo']); + $sea = new SugarEmailAddress(); + $object_arr = array(); + + if( isset($_REQUEST['parent_type']) && !empty($_REQUEST['parent_type']) && + isset($_REQUEST['parent_id']) && !empty($_REQUEST['parent_id']) && + ($_REQUEST['parent_type'] == 'Accounts' || + $_REQUEST['parent_type'] == 'Contacts' || + $_REQUEST['parent_type'] == 'Leads' || + $_REQUEST['parent_type'] == 'Users' || + $_REQUEST['parent_type'] == 'Prospects')) { + if(isset($beanList[$_REQUEST['parent_type']]) && !empty($beanList[$_REQUEST['parent_type']])) { + $className = $beanList[$_REQUEST['parent_type']]; + if(isset($beanFiles[$className]) && !empty($beanFiles[$className])) { + if(!class_exists($className)) { + require_once($beanFiles[$className]); + } + $bean = new $className(); + $bean->retrieve($_REQUEST['parent_id']); + $object_arr[$bean->module_dir] = $bean->id; + } // if + } // if + } + foreach($toAddresses as $addrMeta) { + $addr = $addrMeta['email']; + $beans = $sea->getBeansByEmailAddress($addr); + foreach($beans as $bean) { + if (!isset($object_arr[$bean->module_dir])) { + $object_arr[$bean->module_dir] = $bean->id; + } + } + } + + /* template parsing */ + if (empty($object_arr)) { + $object_arr= array('Contacts' => '123'); + } + $object_arr['Users'] = $current_user->id; + $this->description_html = EmailTemplate::parse_template($this->description_html, $object_arr); + $this->name = EmailTemplate::parse_template($this->name, $object_arr); + $this->description = EmailTemplate::parse_template($this->description, $object_arr); + $this->description = html_entity_decode($this->description,ENT_COMPAT,'UTF-8'); + if($this->type != 'draft' && $this->status != 'draft') { + $this->id = create_guid(); + $this->date_entered = ""; + $this->new_with_id = true; + $this->type = 'out'; + $this->status = 'sent'; + } + } + + if(isset($_REQUEST['parent_type']) && empty($_REQUEST['parent_type']) && + isset($_REQUEST['parent_id']) && empty($_REQUEST['parent_id']) ) { + $this->parent_id = ""; + $this->parent_type = ""; + } // if + + + $mail->Subject = $this->name; + $mail = $this->handleBody($mail); + $mail->Subject = $this->name; + $this->description_html = from_html($this->description_html); + $this->description_html = $this->decodeDuringSend($this->description_html); + $this->description = $this->decodeDuringSend($this->description); + + /* from account */ + $replyToAddress = $current_user->emailAddress->getReplyToAddress($current_user); + $replyToName = ""; + if(empty($request['fromAccount'])) { + $defaults = $current_user->getPreferredEmail(); + $mail->From = $defaults['email']; + $mail->FromName = $defaults['name']; + $replyToName = $mail->FromName; + //$replyToAddress = $current_user->emailAddress->getReplyToAddress($current_user); + } else { + // passed -> user -> system default + $ie = new InboundEmail(); + $ie->retrieve($request['fromAccount']); + $storedOptions = unserialize(base64_decode($ie->stored_options)); + $fromName = ""; + $fromAddress = ""; + $replyToName = ""; + //$replyToAddress = ""; + if (!empty($storedOptions)) { + $fromAddress = $storedOptions['from_addr']; + $fromName = from_html($storedOptions['from_name']); + $replyToAddress = (isset($storedOptions['reply_to_addr']) ? $storedOptions['reply_to_addr'] : ""); + $replyToName = (isset($storedOptions['reply_to_name']) ? from_html($storedOptions['reply_to_name']) : ""); + } // if + $defaults = $current_user->getPreferredEmail(); + // Personal Account doesn't have reply To Name and Reply To Address. So add those columns on UI + // After adding remove below code + + // code to remove + if ($ie->is_personal) + { + if (empty($replyToAddress)) + { + $replyToAddress = $current_user->emailAddress->getReplyToAddress($current_user); + } // if + if (empty($replyToName)) + { + $replyToName = $defaults['name']; + } // if + //Personal accounts can have a reply_address, which should + //overwrite the users set default. + if( !empty($storedOptions['reply_to_addr']) ) + $replyToAddress = $storedOptions['reply_to_addr']; + + } + // end of code to remove + $mail->From = (!empty($fromAddress)) ? $fromAddress : $defaults['email']; + $mail->FromName = (!empty($fromName)) ? $fromName : $defaults['name']; + $replyToName = (!empty($replyToName)) ? $replyToName : $mail->FromName; + } + + $mail->Sender = $mail->From; /* set Return-Path field in header to reduce spam score in emails sent via Sugar's Email module */ + + if (!empty($replyToAddress)) { + $mail->AddReplyTo($replyToAddress,$locale->translateCharsetMIME(trim( $replyToName), 'UTF-8', $OBCharset)); + } else { + $mail->AddReplyTo($mail->From,$locale->translateCharsetMIME(trim( $mail->FromName), 'UTF-8', $OBCharset)); + } // else + $emailAddressCollection = array(); // used in linking to beans below + // handle to/cc/bcc + foreach($this->email2ParseAddresses($request['sendTo']) as $addr_arr) { + if(empty($addr_arr['email'])) continue; + + if(empty($addr_arr['display'])) { + $mail->AddAddress($addr_arr['email'], ""); + } else { + $mail->AddAddress($addr_arr['email'],$locale->translateCharsetMIME(trim( $addr_arr['display']), 'UTF-8', $OBCharset)); + } + $emailAddressCollection[] = $addr_arr['email']; + } + foreach($this->email2ParseAddresses($request['sendCc']) as $addr_arr) { + if(empty($addr_arr['email'])) continue; + + if(empty($addr_arr['display'])) { + $mail->AddCC($addr_arr['email'], ""); + } else { + $mail->AddCC($addr_arr['email'],$locale->translateCharsetMIME(trim( $addr_arr['display']), 'UTF-8', $OBCharset)); + } + $emailAddressCollection[] = $addr_arr['email']; + } + + foreach($this->email2ParseAddresses($request['sendBcc']) as $addr_arr) { + if(empty($addr_arr['email'])) continue; + + if(empty($addr_arr['display'])) { + $mail->AddBCC($addr_arr['email'], ""); + } else { + $mail->AddBCC($addr_arr['email'],$locale->translateCharsetMIME(trim( $addr_arr['display']), 'UTF-8', $OBCharset)); + } + $emailAddressCollection[] = $addr_arr['email']; + } + + + /* parse remove attachments array */ + $removeAttachments = array(); + if(!empty($request['templateAttachmentsRemove'])) { + $exRemove = explode("::", $request['templateAttachmentsRemove']); + + foreach($exRemove as $file) { + $removeAttachments = substr($file, 0, 36); + } + } + + /* handle attachments */ + if(!empty($request['attachments'])) { + $exAttachments = explode("::", $request['attachments']); + + foreach($exAttachments as $file) { + $file = trim(from_html($file)); + $file = str_replace("\\", "", $file); + if(!empty($file)) { + //$fileLocation = $this->et->userCacheDir."/{$file}"; + $fileGUID = substr($file, 0, 36); + $fileLocation = $this->et->userCacheDir."/{$fileGUID}"; + $filename = substr($file, 36, strlen($file)); // strip GUID for PHPMailer class to name outbound file + + $mail->AddAttachment($fileLocation,$filename, 'base64', $this->email2GetMime($fileLocation)); + //$mail->AddAttachment($fileLocation, $filename, 'base64'); + + // only save attachments if we're archiving or drafting + if((($this->type == 'draft') && !empty($this->id)) || (isset($request['saveToSugar']) && $request['saveToSugar'] == 1)) { + $note = new Note(); + $note->id = create_guid(); + $note->new_with_id = true; // duplicating the note with files + $note->parent_id = $this->id; + $note->parent_type = $this->module_dir; + $note->name = $filename; + $note->filename = $filename; + $noteFile = "{$sugar_config['upload_dir']}{$note->id}"; + $note->file_mime_type = $this->email2GetMime($fileLocation); + + if(!copy($fileLocation, $noteFile)) { + $GLOBALS['log']->debug("EMAIL 2.0: could not copy attachment file to cache/upload [ {$fileLocation} ]"); + } + + $note->save(); + } + } + } + } + + /* handle sugar documents */ + if(!empty($request['documents'])) { + $exDocs = explode("::", $request['documents']); + + + + + foreach($exDocs as $docId) { + $docId = trim($docId); + if(!empty($docId)) { + $doc = new Document(); + $docRev = new DocumentRevision(); + $doc->retrieve($docId); + $docRev->retrieve($doc->document_revision_id); + + $filename = $docRev->filename; + $fileLocation = "{$sugar_config['upload_dir']}{$docRev->id}"; + $mime_type = $docRev->file_mime_type; + $mail->AddAttachment($fileLocation,$locale->translateCharsetMIME(trim($filename), 'UTF-8', $OBCharset), 'base64', $mime_type); + + // only save attachments if we're archiving or drafting + if((($this->type == 'draft') && !empty($this->id)) || (isset($request['saveToSugar']) && $request['saveToSugar'] == 1)) { + $note = new Note(); + $note->id = create_guid(); + $note->new_with_id = true; // duplicating the note with files + $note->parent_id = $this->id; + $note->parent_type = $this->module_dir; + $note->name = $filename; + $note->filename = $filename; + $note->file_mime_type = $mime_type; + $noteFile = "{$sugar_config['upload_dir']}{$note->id}"; + + if(!copy($fileLocation, $noteFile)) { + $GLOBALS['log']->debug("EMAIL 2.0: could not copy SugarDocument revision file to {$sugar_config['upload_dir']} [ {$fileLocation} ]"); + } + + $note->save(); + } + } + } + } + + /* handle template attachments */ + if(!empty($request['templateAttachments'])) { + + $exNotes = explode("::", $request['templateAttachments']); + foreach($exNotes as $noteId) { + $noteId = trim($noteId); + if(!empty($noteId)) { + $note = new Note(); + $note->retrieve($noteId); + if (!empty($note->id)) { + $filename = $note->filename; + $fileLocation = "{$sugar_config['upload_dir']}{$note->id}"; + $mime_type = $note->file_mime_type; + if (!$note->embed_flag) { + $mail->AddAttachment($fileLocation,$filename, 'base64', $mime_type); + // only save attachments if we're archiving or drafting + if((($this->type == 'draft') && !empty($this->id)) || (isset($request['saveToSugar']) && $request['saveToSugar'] == 1)) { + + if ($note->parent_id != $this->id) + $this->saveTempNoteAttachments($filename,$fileLocation, $mime_type); + } // if + + } // if + } else { + //$fileLocation = $this->et->userCacheDir."/{$file}"; + $fileGUID = substr($noteId, 0, 36); + $fileLocation = $this->et->userCacheDir."/{$fileGUID}"; + //$fileLocation = $this->et->userCacheDir."/{$noteId}"; + $filename = substr($noteId, 36, strlen($noteId)); // strip GUID for PHPMailer class to name outbound file + + $mail->AddAttachment($fileLocation,$locale->translateCharsetMIME(trim($filename), 'UTF-8', $OBCharset), 'base64', $this->email2GetMime($fileLocation)); + + //If we are saving an email we were going to forward we need to save the attachments as well. + if( (($this->type == 'draft') && !empty($this->id)) + || (isset($request['saveToSugar']) && $request['saveToSugar'] == 1)) + { + $mimeType = $this->email2GetMime($fileLocation); + $this->saveTempNoteAttachments($filename,$fileLocation, $mimeType); + } // if + } + } + } + } + + + + /********************************************************************** + * Final Touches + */ + /* save email to sugar? */ + $forceSave = false; + + if($this->type == 'draft' && !isset($request['saveDraft'])) { + // sending a draft email + $this->type = 'out'; + $this->status = 'sent'; + $forceSave = true; + } elseif(isset($request['saveDraft'])) { + $this->type = 'draft'; + $this->status = 'draft'; + $forceSave = true; + } + + /********************************************************************** + * SEND EMAIL (finally!) + */ + $mailSent = false; + if ($this->type != 'draft') { + $mail->prepForOutbound(); + $mail->Body = $this->decodeDuringSend($mail->Body); + $mail->AltBody = $this->decodeDuringSend($mail->AltBody); + if (!$mail->Send()) { + $this->status = 'send_error'; + ob_clean(); + echo($app_strings['LBL_EMAIL_ERROR_PREPEND']. $mail->ErrorInfo); + return false; + } + } + + if ((!(empty($orignialId) || isset($request['saveDraft']) || ($this->type == 'draft' && $this->status == 'draft'))) && + (($_REQUEST['composeType'] == 'reply') || ($_REQUEST['composeType'] == 'replyAll') || ($_REQUEST['composeType'] == 'replyCase')) && ($orignialId != $this->id)) { + $originalEmail = new Email(); + $originalEmail->retrieve($orignialId); + $originalEmail->reply_to_status = 1; + $originalEmail->save(); + $this->reply_to_status = 0; + } // if + + if ($_REQUEST['composeType'] == 'reply' || $_REQUEST['composeType'] == 'replyCase') { + if (isset($_REQUEST['ieId']) && isset($_REQUEST['mbox'])) { + $emailFromIe = new InboundEmail(); + $emailFromIe->retrieve($_REQUEST['ieId']); + $emailFromIe->mailbox = $_REQUEST['mbox']; + if (isset($emailFromIe->id) && $emailFromIe->is_personal) { + if ($emailFromIe->isPop3Protocol()) { + $emailFromIe->mark_answered($this->uid, 'pop3'); + } + elseif ($emailFromIe->connectMailserver() == 'true') { + $emailFromIe->markEmails($this->uid, 'answered'); + $emailFromIe->mark_answered($this->uid); + } + } + } + } + + + if( $forceSave || + $this->type == 'draft' || + (isset($request['saveToSugar']) && $request['saveToSugar'] == 1)) { + + // saving a draft OR saving a sent email + $decodedFromName = mb_decode_mimeheader($mail->FromName); + $this->from_addr = "{$decodedFromName} <{$mail->From}>"; + $this->from_addr_name = $this->from_addr; + $this->to_addrs = $_REQUEST['sendTo']; + $this->to_addrs_names = $_REQUEST['sendTo']; + $this->cc_addrs = $_REQUEST['sendCc']; + $this->cc_addrs_names = $_REQUEST['sendCc']; + $this->bcc_addrs = $_REQUEST['sendBcc']; + $this->bcc_addrs_names = $_REQUEST['sendBcc']; + $this->assigned_user_id = $current_user->id; + + $this->date_sent = $timedate->now(); + /////////////////////////////////////////////////////////////////// + //// LINK EMAIL TO SUGARBEANS BASED ON EMAIL ADDY + + if( isset($_REQUEST['parent_type']) && !empty($_REQUEST['parent_type']) && + isset($_REQUEST['parent_id']) && !empty($_REQUEST['parent_id']) ) { + $this->parent_id = $_REQUEST['parent_id']; + $this->parent_type = $_REQUEST['parent_type']; + $q = "SELECT count(*) c FROM emails_beans WHERE email_id = '{$this->id}' AND bean_id = '{$_REQUEST['parent_id']}' AND bean_module = '{$_REQUEST['parent_type']}'"; + $r = $this->db->query($q); + $a = $this->db->fetchByAssoc($r); + if($a['c'] <= 0) { + if(isset($beanList[$_REQUEST['parent_type']]) && !empty($beanList[$_REQUEST['parent_type']])) { + $className = $beanList[$_REQUEST['parent_type']]; + if(isset($beanFiles[$className]) && !empty($beanFiles[$className])) { + if(!class_exists($className)) { + require_once($beanFiles[$className]); + } + $bean = new $className(); + $bean->retrieve($_REQUEST['parent_id']); + if($bean->load_relationship('emails')) { + $bean->emails->add($this->id); + } // if + + } // if + + } // if + + } // if + + } else { + if(!class_exists('aCase')) { + + } + else{ + $c = new aCase(); + if($caseId = InboundEmail::getCaseIdFromCaseNumber($mail->Subject, $c)) { + $c->retrieve($caseId); + $c->load_relationship('emails'); + $c->emails->add($this->id); + $this->parent_type = "Cases"; + $this->parent_id = $caseId; + } // if + } + + } // else + + //// LINK EMAIL TO SUGARBEANS BASED ON EMAIL ADDY + /////////////////////////////////////////////////////////////////// + $this->save(); + } + + if(!empty($request['fromAccount'])) { + if (isset($ie->id) && !$ie->isPop3Protocol()) { + $sentFolder = $ie->get_stored_options("sentFolder"); + if (!empty($sentFolder)) { + $data = $mail->CreateHeader() . "\r\n" . $mail->CreateBody() . "\r\n"; + $ie->mailbox = $sentFolder; + if ($ie->connectMailserver() == 'true') { + $connectString = $ie->getConnectString($ie->getServiceString(), $ie->mailbox); + $returnData = imap_append($ie->conn,$connectString, $data, "\\Seen"); + if (!$returnData) { + $GLOBALS['log']->debug("could not copy email to {$ie->mailbox} for {$ie->name}"); + } // if + } else { + $GLOBALS['log']->debug("could not connect to mail serve for folder {$ie->mailbox} for {$ie->name}"); + } // else + } else { + $GLOBALS['log']->debug("could not copy email to {$ie->mailbox} sent folder as its empty"); + } // else + } // if + } // if + return true; + } // end email2send + + /** + * Generates a comma sperated name and addresses to be used in compose email screen for contacts or leads + * from listview + * + * @param $module string module name + * @param $idsArray array of record ids to get the email address for + * @return string comma delimited list of email addresses + */ + public function getNamePlusEmailAddressesForCompose($module, $idsArray) + { + global $locale; + global $db; + $table = SugarModule::get($module)->loadBean()->table_name; + $returndata = array(); + $idsString = ""; + foreach($idsArray as $id) { + if ($idsString != "") { + $idsString = $idsString . ","; + } // if + $idsString = $idsString . "'" . $id . "'"; + } // foreach + $where = "({$table}.deleted = 0 AND {$table}.id in ({$idsString}))"; + + if ($module == 'Users' || $module == 'Employees') { + $selectColumn = "{$table}.first_name, {$table}.last_name, {$table}.title"; + } + elseif (SugarModule::get($module)->moduleImplements('Person')) { + $selectColumn = "{$table}.first_name, {$table}.last_name, {$table}.salutation, {$table}.title"; + } + else { + $selectColumn = "{$table}.name"; + } + $query = "SELECT {$table}.id, {$selectColumn}, eabr.primary_address, ea.email_address"; + $query .= " FROM {$table} "; + $query .= "JOIN email_addr_bean_rel eabr ON ({$table}.id = eabr.bean_id and eabr.deleted=0) "; + $query .= "JOIN email_addresses ea ON (eabr.email_address_id = ea.id) "; + $query .= " WHERE ({$where}) ORDER BY eabr.primary_address DESC"; + $r = $this->db->query($query); + + while($a = $this->db->fetchByAssoc($r)) { + if (!isset($returndata[$a['id']])) { + if ($module == 'Users' || $module == 'Employees') { + $full_name = from_html($locale->getLocaleFormattedName($a['first_name'], $a['last_name'], '', $a['title'])); + $returndata[$a['id']] = "{$full_name} <".from_html($a['email_address']).">"; + } + elseif (SugarModule::get($module)->moduleImplements('Person')) { + $full_name = from_html($locale->getLocaleFormattedName($a['first_name'], $a['last_name'], $a['salutation'], $a['title'])); + $returndata[$a['id']] = "{$full_name} <".from_html($a['email_address']).">"; + } + else { + $returndata[$a['id']] = from_html($a['name']) . " <".from_html($a['email_address']).">"; + } // else + } + } + + return join(",", array_values($returndata)); + } + + /** + * Overrides + */ + /////////////////////////////////////////////////////////////////////////// + //// SAVERS + function save($check_notify = false) { + if($this->isDuplicate) { + $GLOBALS['log']->debug("EMAIL - tried to save a duplicate Email record"); + } else { + + if(empty($this->id)) { + $this->id = create_guid(); + $this->new_with_id = true; + } + $this->from_addr_name = $this->cleanEmails($this->from_addr_name); + $this->to_addrs_names = $this->cleanEmails($this->to_addrs_names); + $this->cc_addrs_names = $this->cleanEmails($this->cc_addrs_names); + $this->bcc_addrs_names = $this->cleanEmails($this->bcc_addrs_names); + $this->reply_to_addr = $this->cleanEmails($this->reply_to_addr); + $this->description = to_html($this->safeText(from_html($this->description))); + $this->description_html = $this->safeText($this->description_html); + $this->saveEmailText(); + $this->saveEmailAddresses(); + + $GLOBALS['log']->debug('-------------------------------> Email called save()'); + + // handle legacy concatenation of date and time fields + if(empty($this->date_sent)) $this->date_sent = $this->date_start." ".$this->time_start; + + parent::save($check_notify); + + if(!empty($this->parent_type) && !empty($this->parent_id)) { + if(!empty($this->fetched_row) && !empty($this->fetched_row['parent_id']) && !empty($this->fetched_row['parent_type'])) { + if($this->fetched_row['parent_id'] != $this->parent_id || $this->fetched_row['parent_type'] != $this->parent_type) { + $mod = strtolower($this->fetched_row['parent_type']); + $rel = array_key_exists($mod, $this->field_defs) ? $mod : $mod . "_activities_emails"; //Custom modules rel name + if($this->load_relationship($rel) ) { + $this->$rel->delete($this->id, $this->fetched_row['parent_id']); + } + } else { + // we already have this relationship, don't add it + return; + } + } + $mod = strtolower($this->parent_type); + $rel = array_key_exists($mod, $this->field_defs) ? $mod : $mod . "_activities_emails"; //Custom modules rel name + if($this->load_relationship($rel) ) { + $this->$rel->add($this->parent_id); + } + } + } + } + + /** + * Helper function to save temporary attachments assocaited to an email as note. + * + * @param string $filename + * @param string $fileLocation + * @param string $mimeType + */ + function saveTempNoteAttachments($filename,$fileLocation, $mimeType) + { + global $sugar_config; + + $tmpNote = new Note(); + $tmpNote->id = create_guid(); + $tmpNote->new_with_id = true; + $tmpNote->parent_id = $this->id; + $tmpNote->parent_type = $this->module_dir; + $tmpNote->name = $filename; + $tmpNote->filename = $filename; + $tmpNote->file_mime_type = $mimeType; + $noteFile = "{$sugar_config['upload_dir']}{$tmpNote->id}"; + if(!copy($fileLocation, $noteFile)) + $GLOBALS['log']->fatal("EMAIL 2.0: could not copy SugarDocument revision file to {$sugar_config['upload_dir']} [ {$fileLocation} ]"); + $tmpNote->save(); + } + /** + * Handles normalization of Email Addressess + */ + function saveEmailAddresses() { + // from, single address + $fromId = $this->emailAddress->getEmailGUID(from_html($this->from_addr)); + if(!empty($fromId)){ + $this->linkEmailToAddress($fromId, 'from'); + } + + // to, multiple + $replace = array(",",";"); + $toaddrs = str_replace($replace, "::", from_html($this->to_addrs)); + $exToAddrs = explode("::", $toaddrs); + + if(!empty($exToAddrs)) { + foreach($exToAddrs as $toaddr) { + $toaddr = trim($toaddr); + if(!empty($toaddr)) { + $toId = $this->emailAddress->getEmailGUID($toaddr); + $this->linkEmailToAddress($toId, 'to'); + } + } + } + + // cc, multiple + $ccAddrs = str_replace($replace, "::", from_html($this->cc_addrs)); + $exccAddrs = explode("::", $ccAddrs); + + if(!empty($exccAddrs)) { + foreach($exccAddrs as $ccAddr) { + $ccAddr = trim($ccAddr); + if(!empty($ccAddr)) { + $ccId = $this->emailAddress->getEmailGUID($ccAddr); + $this->linkEmailToAddress($ccId, 'cc'); + } + } + } + + // bcc, multiple + $bccAddrs = str_replace($replace, "::", from_html($this->bcc_addrs)); + $exbccAddrs = explode("::", $bccAddrs); + if(!empty($exbccAddrs)) { + foreach($exbccAddrs as $bccAddr) { + $bccAddr = trim($bccAddr); + if(!empty($bccAddr)) { + $bccId = $this->emailAddress->getEmailGUID($bccAddr); + $this->linkEmailToAddress($bccId, 'bcc'); + } + } + } + } + + function linkEmailToAddress($id, $type) { + // TODO: make this update? + $q1 = "SELECT * FROM emails_email_addr_rel WHERE email_id = '{$this->id}' AND email_address_id = '{$id}' AND address_type = '{$type}' AND deleted = 0"; + $r1 = $this->db->query($q1); + $a1 = $this->db->fetchByAssoc($r1); + + if(!empty($a1) && !empty($a1['id'])) { + return $a1['id']; + } else { + $guid = create_guid(); + $q2 = "INSERT INTO emails_email_addr_rel VALUES('{$guid}', '{$this->id}', '{$type}', '{$id}', 0)"; + $r2 = $this->db->query($q2); + } + + return $guid; + } + + function cleanEmails($emails) + { + $emails = str_replace(array(",",";"), "::", from_html($emails)); + $addrs = explode("::", $emails); + $res = array(); + foreach($addrs as $addr) { + $parts = $this->emailAddress->splitEmailAddress($addr); + if(empty($parts["email"])) { + continue; + } + if(!empty($parts["name"])) { + $res[] = "{$parts["name"]} <{$parts["email"]}>"; + } else { + $res[] .= $parts["email"]; + } + } + return join(", ", $res); + } + + function saveEmailText() { + $isOracle = ($this->db->dbType == "oci8") ? true : false; + if ($isOracle) { + } else { + $description = $this->db->quote(trim($this->description)); + $description_html = $this->db->quoteForEmail(trim($this->description_html)); + $raw_source = $this->db->quote(trim($this->raw_source)); + $fromAddressName = $this->db->helper->escape_quote($this->from_addr_name); + $toAddressName = $this->db->helper->escape_quote($this->to_addrs_names); + $ccAddressName = $this->db->helper->escape_quote($this->cc_addrs_names); + $bccAddressName = $this->db->helper->escape_quote($this->bcc_addrs_names); + $replyToAddrName = $this->db->helper->escape_quote($this->reply_to_addr); + + if(!$this->new_with_id) { + $q = "UPDATE emails_text SET from_addr = '{$fromAddressName}', to_addrs = '{$toAddressName}', cc_addrs = '{$ccAddressName}', bcc_addrs = '{$bccAddressName}', reply_to_addr = '{$replyToAddrName}', description = '{$description}', description_html = '{$description_html}', raw_source = '{$raw_source}' WHERE email_id = '{$this->id}'"; + } else { + $q = "INSERT INTO emails_text (email_id, from_addr, to_addrs, cc_addrs, bcc_addrs, reply_to_addr, description, description_html, raw_source, deleted) VALUES('{$this->id}', '{$fromAddressName}', '{$toAddressName}', '{$ccAddressName}', '{$bccAddressName}', '{$replyToAddrName}', '{$description}', '{$description_html}', '{$raw_source}', 0)"; + } + $this->db->query($q); + + } // else + } + + + /////////////////////////////////////////////////////////////////////////// + //// RETRIEVERS + function retrieve($id, $encoded=true, $deleted=true) { + // cn: bug 11915, return SugarBean's retrieve() call bean instead of $this + $ret = parent::retrieve($id, $encoded, $deleted); + + if($ret) { + $ret->retrieveEmailText(); + $ret->retrieveEmailAddresses(); + $ret->raw_source = to_html($ret->safeText(from_html($ret->raw_source))); + $ret->description = to_html($ret->safeText(from_html($ret->description))); + $ret->description_html = $ret->safeText($ret->description_html); + + $ret->date_start = ''; + $ret->time_start = ''; + $dateSent = explode(' ', $ret->date_sent); + if (!empty($dateSent)) { + $ret->date_start = $dateSent[0]; + if ( isset($dateSent[1]) ) + $ret->time_start = $dateSent[1]; + } + // for Email 2.0 + foreach($ret as $k => $v) { + $this->$k = $v; + } + } + return $ret; + } + + + /** + * Retrieves email addresses from GUIDs + */ + function retrieveEmailAddresses() { + $return = array(); + + $q = "SELECT email_address, address_type + FROM emails_email_addr_rel eam + JOIN email_addresses ea ON ea.id = eam.email_address_id + WHERE eam.email_id = '{$this->id}' AND eam.deleted=0"; + $r = $this->db->query($q); + + while($a = $this->db->fetchByAssoc($r)) { + if(!isset($return[$a['address_type']])) { + $return[$a['address_type']] = array(); + } + $return[$a['address_type']][] = $a['email_address']; + } + + if(count($return) > 0) { + if(isset($return['from'])) { + $this->from_addr = implode(", ", $return['from']); + } + if(isset($return['to'])) { + $this->to_addrs = implode(", ", $return['to']); + } + if(isset($return['cc'])) { + $this->cc_addrs = implode(", ", $return['cc']); + } + if(isset($return['bcc'])) { + $this->bcc_addrs = implode(", ", $return['bcc']); + } + } + } + + /** + * Handles longtext fields + */ + function retrieveEmailText() { + $q = "SELECT from_addr, reply_to_addr, to_addrs, cc_addrs, bcc_addrs, description, description_html, raw_source FROM emails_text WHERE email_id = '{$this->id}'"; + $r = $this->db->query($q); + $a = $this->db->fetchByAssoc($r, -1, false); + + $this->description = $a['description']; + $this->description_html = $a['description_html']; + $this->raw_source = $a['raw_source']; + $this->from_addr_name = $a['from_addr']; + $this->reply_to_addr = $a['reply_to_addr']; + $this->to_addrs_names = $a['to_addrs']; + $this->cc_addrs_names = $a['cc_addrs']; + $this->bcc_addrs_names = $a['bcc_addrs']; + } + + function delete($id='') { + if(empty($id)) + $id = $this->id; + + $q = "UPDATE emails SET deleted = 1 WHERE id = '{$id}'"; + $qt = "UPDATE emails_text SET deleted = 1 WHERE email_id = '{$id}'"; + $r = $this->db->query($q); + $rt = $this->db->query($qt); + } + + /** + * creates the standard "Forward" info at the top of the forwarded message + * @return string + */ + function getForwardHeader() { + global $mod_strings; + global $current_user; + + //$from = str_replace(array(">","<"), array(")","("), $this->from_name); + $from = to_html($this->from_name); + $subject = to_html($this->name); + $ret = "

    "; + $ret .= $this->replyDelimiter."{$mod_strings['LBL_FROM']} {$from}
    "; + $ret .= $this->replyDelimiter."{$mod_strings['LBL_DATE_SENT']} {$this->date_sent}
    "; + $ret .= $this->replyDelimiter."{$mod_strings['LBL_TO']} {$this->to_addrs}
    "; + $ret .= $this->replyDelimiter."{$mod_strings['LBL_CC']} {$this->cc_addrs}
    "; + $ret .= $this->replyDelimiter."{$mod_strings['LBL_SUBJECT']} {$subject}
    "; + $ret .= $this->replyDelimiter."
    "; + + return $ret; + //return from_html($ret); + } + + /** + * retrieves Notes that belong to this Email and stuffs them into the "attachments" attribute + */ + function getNotes($id, $duplicate=false) { + if(!class_exists('Note')) { + + } + + $exRemoved = array(); + if(isset($_REQUEST['removeAttachment'])) { + $exRemoved = explode('::', $_REQUEST['removeAttachment']); + } + + $noteArray = array(); + $q = "SELECT id FROM notes WHERE parent_id = '".$id."'"; + $r = $this->db->query($q); + + while($a = $this->db->fetchByAssoc($r)) { + if(!in_array($a['id'], $exRemoved)) { + $note = new Note(); + $note->retrieve($a['id']); + + // duplicate actual file when creating forwards + if($duplicate) { + if(!class_exists('UploadFile')) { + require_once('include/upload_file.php'); + } + // save a brand new Note + $noteDupe->id = create_guid(); + $noteDupe->new_with_id = true; + $noteDupe->parent_id = $this->id; + $noteDupe->parent_type = $this->module_dir; + + $noteFile = new UploadFile('none'); + $noteFile->duplicate_file($a['id'], $note->id, $note->filename); + + $note->save(); + } + // add Note to attachments array + $this->attachments[] = $note; + } + } + } + + /** + * creates the standard "Reply" info at the top of the forwarded message + * @return string + */ + function getReplyHeader() { + global $mod_strings; + global $current_user; + + $from = str_replace(array(">","<", ">","<"), array(")","(",")","("), $this->from_name); + $ret = "
    {$mod_strings['LBL_REPLY_HEADER_1']} {$this->date_start}, {$this->time_start}, {$from} {$mod_strings['LBL_REPLY_HEADER_2']}"; + + return from_html($ret); + } + + /** + * Quotes plain-text email text + * @param string $text + * @return string + */ + function quotePlainTextEmail($text) { + $quoted = "\n"; + + // plain-text + $desc = nl2br(trim($text)); + $exDesc = explode('
    ', $desc); + + foreach($exDesc as $k => $line) { + $quoted .= '> '.trim($line)."\r"; + } + + return $quoted; + } + + /** + * "quotes" (i.e., "> my text yadda" the HTML part of an email + * @param string $text HTML text to quote + * @return string + */ + function quoteHtmlEmail($text) { + $text = trim(from_html($text)); + + if(empty($text)) { + return ''; + } + $out = "
    {$text}
    "; + + return $out; + } + + /** + * "quotes" (i.e., "> my text yadda" the HTML part of an email + * @param string $text HTML text to quote + * @return string + */ + function quoteHtmlEmailForNewEmailUI($text) { + $text = trim($text); + + if(empty($text)) { + return ''; + } + $text = str_replace("\n", "\n
    ", $text); + $out = "
    {$text}
    "; + + return $out; + } + + + + /////////////////////////////////////////////////////////////////////////// + //// LEGACY CODE + /** + * Safes description text (both HTML and Plain Text) for display + * @param string str The text to safe + * @return string Safed text + */ + function safeText($str) { + // Safe_HTML + $this->safe->clear(); + $ret = $this->safe->parse($str); + + // Julian's XSS cleaner + $potentials = clean_xss($str, false); + + if(is_array($potentials) && !empty($potentials)) { + //_ppl($potentials); + foreach($potentials as $bad) { + $ret = str_replace($bad, "", $ret); + } + } + + // clean and tags + $html = '#<\\\\\?HTML[\w =\'\"\&]*>#sim'; + $body = '#<\\\\\?BODY[\w =\'\"\&]*>#sim'; + + $ret = preg_replace($html, "", $ret); + $ret = preg_replace($body, "", $ret); + + return $ret; + } + + /** + * Ensures that the user is able to send outbound emails + */ + function check_email_settings() { + global $current_user; + + $mail_fromaddress = $current_user->emailAddress->getPrimaryAddress($current_user); + $replyToName = $current_user->getPreference('mail_fromname'); + $mail_fromname = (!empty($replyToName)) ? $current_user->getPreference('mail_fromname') : $current_user->full_name; + + if(empty($mail_fromaddress)) { + return false; + } + if(empty($mail_fromname)) { + return false; + } + + $send_type = $current_user->getPreference('mail_sendtype') ; + if (!empty($send_type) && $send_type == "SMTP") { + $mail_smtpserver = $current_user->getPreference('mail_smtpserver'); + $mail_smtpport = $current_user->getPreference('mail_smtpport'); + $mail_smtpauth_req = $current_user->getPreference('mail_smtpauth_req'); + $mail_smtpuser = $current_user->getPreference('mail_smtpuser'); + $mail_smtppass = $current_user->getPreference('mail_smtppass'); + if (empty($mail_smtpserver) || + empty($mail_smtpport) || + (!empty($mail_smtpauth_req) && ( empty($mail_smtpuser) || empty($mail_smtppass))) + ) { + return false; + } + } + return true; + } + + /** + * outputs JS to set fields in the MassUpdate form in the "My Inbox" view + */ + function js_set_archived() { + global $mod_strings; + $script = ' + '; + return $script; + } + + /** + * replaces the javascript in utils.php - more specialized + */ + function u_get_clear_form_js($type='', $group='', $assigned_user_id='') { + $uType = ''; + $uGroup = ''; + $uAssigned_user_id = ''; + + if(!empty($type)) { $uType = '&type='.$type; } + if(!empty($group)) { $uGroup = '&group='.$group; } + if(!empty($assigned_user_id)) { $uAssigned_user_id = '&assigned_user_id='.$assigned_user_id; } + + $the_script = ' + '; + return $the_script; + } + + function pickOneButton() { + global $theme; + global $mod_strings; + $out = '
    '; + return $out; + } + + /** + * Determines what Editor (HTML or Plain-text) the current_user uses; + * @return string Editor type + */ + function getUserEditorPreference() { + global $sugar_config; + global $current_user; + + $editor = ''; + + if(!isset($sugar_config['email_default_editor'])) { + $sugar_config = $current_user->setDefaultsInConfig(); + } + + $userEditor = $current_user->getPreference('email_editor_option'); + $systemEditor = $sugar_config['email_default_editor']; + + if($userEditor != '') { + $editor = $userEditor; + } else { + $editor = $systemEditor; + } + + return $editor; + } + + /** + * takes the mess we pass from EditView and tries to create some kind of order + * @param array addrs + * @param array addrs_ids (from contacts) + * @param array addrs_names (from contacts); + * @param array addrs_emails (from contacts); + * @return array Parsed assoc array to feed to PHPMailer + */ + function parse_addrs($addrs, $addrs_ids, $addrs_names, $addrs_emails) { + // cn: bug 9406 - enable commas to separate email addresses + $addrs = str_replace(",", ";", $addrs); + + $ltgt = array('<','>'); + $gtlt = array('<','>'); + + $return = array(); + $addrs = str_replace($ltgt, '', $addrs); + $addrs_arr = explode(";",$addrs); + $addrs_arr = $this->remove_empty_fields($addrs_arr); + $addrs_ids_arr = explode(";",$addrs_ids); + $addrs_ids_arr = $this->remove_empty_fields($addrs_ids_arr); + $addrs_emails_arr = explode(";",$addrs_emails); + $addrs_emails_arr = $this->remove_empty_fields($addrs_emails_arr); + $addrs_names_arr = explode(";",$addrs_names); + $addrs_names_arr = $this->remove_empty_fields($addrs_names_arr); + + /////////////////////////////////////////////////////////////////////// + //// HANDLE EMAILS HAND-WRITTEN + $contactRecipients = array(); + $knownEmails = array(); + + foreach($addrs_arr as $i => $v) { + if(trim($v) == "") + continue; // skip any "blanks" - will always have 1 + + $recipient = array(); + + //// get the email to see if we're dealing with a dupe + //// what crappy coding + preg_match("/[A-Z0-9._%-]+@[A-Z0-9.-]+\.[A-Z]{2,}/i",$v, $match); + + if(!empty($match[0]) && !in_array(trim($match[0]), $knownEmails)) { + $knownEmails[] = $match[0]; + $recipient['email'] = $match[0]; + + //// handle the Display name + $display = trim(str_replace($match[0], '', $v)); + + //// only trigger a "displayName" when necessary + if(isset($addrs_names_arr[$i])){ + $recipient['display'] = $addrs_names_arr[$i]; + } + else if(!empty($display)) { + $recipient['display'] = $display; + } + if(isset($addrs_ids_arr[$i]) && $addrs_emails_arr[$i] == $match[0]){ + $recipient['contact_id'] = $addrs_ids_arr[$i]; + } + $return[] = $recipient; + } + } + + return $return; + } + + function remove_empty_fields(&$arr) { + $newarr = array(); + + foreach($arr as $field) { + $field = trim($field); + if(empty($field)) { + continue; + } + array_push($newarr,$field); + } + return $newarr; + } + + /** + * handles attachments of various kinds when sending email + */ + function handleAttachments() { + + + + + global $mod_strings; + + /////////////////////////////////////////////////////////////////////////// + //// ATTACHMENTS FROM DRAFTS + if(($this->type == 'out' || $this->type == 'draft') && $this->status == 'draft' && isset($_REQUEST['record'])) { + $this->getNotes($_REQUEST['record']); // cn: get notes from OLD email for use in new email + } + //// END ATTACHMENTS FROM DRAFTS + /////////////////////////////////////////////////////////////////////////// + + /////////////////////////////////////////////////////////////////////////// + //// ATTACHMENTS FROM FORWARDS + // Bug 8034 Jenny - Need the check for type 'draft' here to handle cases where we want to save + // forwarded messages as drafts. We still need to save the original message's attachments. + if(($this->type == 'out' || $this->type == 'draft') && + isset($_REQUEST['origType']) && $_REQUEST['origType'] == 'forward' && + isset($_REQUEST['return_id']) && !empty($_REQUEST['return_id']) + ) { + $this->getNotes($_REQUEST['return_id'], true); + } + + // cn: bug 8034 - attachments from forward/replies lost when saving in draft + if(isset($_REQUEST['prior_attachments']) && !empty($_REQUEST['prior_attachments']) && $this->new_with_id == true) { + $exIds = explode(",", $_REQUEST['prior_attachments']); + if(!isset($_REQUEST['template_attachment'])) { + $_REQUEST['template_attachment'] = array(); + } + $_REQUEST['template_attachment'] = array_merge($_REQUEST['template_attachment'], $exIds); + } + //// END ATTACHMENTS FROM FORWARDS + /////////////////////////////////////////////////////////////////////////// + + /////////////////////////////////////////////////////////////////////////// + //// ATTACHMENTS FROM TEMPLATES + // to preserve individual email integrity, we must dupe Notes and associated files + // for each outbound email - good for integrity, bad for filespace + if(isset($_REQUEST['template_attachment']) && !empty($_REQUEST['template_attachment'])) { + $removeArr = array(); + $noteArray = array(); + + if(isset($_REQUEST['temp_remove_attachment']) && !empty($_REQUEST['temp_remove_attachment'])) { + $removeArr = $_REQUEST['temp_remove_attachment']; + } + + + foreach($_REQUEST['template_attachment'] as $noteId) { + if(in_array($noteId, $removeArr)) { + continue; + } + $noteTemplate = new Note(); + $noteTemplate->retrieve($noteId); + $noteTemplate->id = create_guid(); + $noteTemplate->new_with_id = true; // duplicating the note with files + $noteTemplate->parent_id = $this->id; + $noteTemplate->parent_type = $this->module_dir; + $noteTemplate->date_entered = ''; + $noteTemplate->save(); + + $noteFile = new UploadFile('none'); + $noteFile->duplicate_file($noteId, $noteTemplate->id, $noteTemplate->filename); + $noteArray[] = $noteTemplate; + } + $this->attachments = array_merge($this->attachments, $noteArray); + } + //// END ATTACHMENTS FROM TEMPLATES + /////////////////////////////////////////////////////////////////////////// + + /////////////////////////////////////////////////////////////////////////// + //// ADDING NEW ATTACHMENTS + $max_files_upload = 10; + // Jenny - Bug 8211 Since attachments for drafts have already been processed, + // we don't need to re-process them. + if($this->status != "draft") { + $notes_list = array(); + if(!empty($this->id) && !$this->new_with_id) { + $note = new Note(); + $where = "notes.parent_id='{$this->id}'"; + $notes_list = $note->get_full_list("", $where, true); + } + $this->attachments = array_merge($this->attachments, $notes_list); + } + // cn: Bug 5995 - rudimentary error checking + $filesError = array( + 0 => 'UPLOAD_ERR_OK - There is no error, the file uploaded with success.', + 1 => 'UPLOAD_ERR_INI_SIZE - The uploaded file exceeds the upload_max_filesize directive in php.ini.', + 2 => 'UPLOAD_ERR_FORM_SIZE - The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form.', + 3 => 'UPLOAD_ERR_PARTIAL - The uploaded file was only partially uploaded.', + 4 => 'UPLOAD_ERR_NO_FILE - No file was uploaded.', + 5 => 'UNKNOWN ERROR', + 6 => 'UPLOAD_ERR_NO_TMP_DIR - Missing a temporary folder. Introduced in PHP 4.3.10 and PHP 5.0.3.', + 7 => 'UPLOAD_ERR_CANT_WRITE - Failed to write file to disk. Introduced in PHP 5.1.0.', + ); + + for($i = 0; $i < $max_files_upload; $i++) { + // cn: Bug 5995 - rudimentary error checking + if (!isset($_FILES["email_attachment{$i}"])) { + $GLOBALS['log']->debug("Email Attachment {$i} does not exist."); + continue; + } + if($_FILES['email_attachment'.$i]['error'] != 0 && $_FILES['email_attachment'.$i]['error'] != 4) { + $GLOBALS['log']->debug('Email Attachment could not be attach due to error: '.$filesError[$_FILES['email_attachment'.$i]['error']]); + continue; + } + + $note = new Note(); + $note->parent_id = $this->id; + $note->parent_type = $this->module_dir; + $upload_file = new UploadFile('email_attachment'.$i); + + if(empty($upload_file)) { + continue; + } + + if(isset($_FILES['email_attachment'.$i]) && $upload_file->confirm_upload()) { + $note->filename = $upload_file->get_stored_file_name(); + $note->file = $upload_file; + $note->name = $mod_strings['LBL_EMAIL_ATTACHMENT'].': '.$note->file->original_file_name; + + $this->attachments[] = $note; + } + } + + $this->saved_attachments = array(); + foreach($this->attachments as $note) { + if(!empty($note->id)) { + array_push($this->saved_attachments, $note); + continue; + } + $note->parent_id = $this->id; + $note->parent_type = 'Emails'; + $note->file_mime_type = $note->file->mime_type; + $note_id = $note->save(); + + $this->saved_attachments[] = $note; + + $note->id = $note_id; + $note->file->final_move($note->id); + } + //// END NEW ATTACHMENTS + /////////////////////////////////////////////////////////////////////////// + + /////////////////////////////////////////////////////////////////////////// + //// ATTACHMENTS FROM DOCUMENTS + for($i=0; $i<10; $i++) { + if(isset($_REQUEST['documentId'.$i]) && !empty($_REQUEST['documentId'.$i])) { + $doc = new Document(); + $docRev = new DocumentRevision(); + $docNote = new Note(); + $noteFile = new UploadFile('none'); + + $doc->retrieve($_REQUEST['documentId'.$i]); + $docRev->retrieve($doc->document_revision_id); + + $this->saved_attachments[] = $docRev; + + // cn: bug 9723 - Emails with documents send GUID instead of Doc name + $docNote->name = $docRev->getDocumentRevisionNameForDisplay(); + $docNote->filename = $docRev->filename; + $docNote->description = $doc->description; + $docNote->parent_id = $this->id; + $docNote->parent_type = 'Emails'; + $docNote->file_mime_type = $docRev->file_mime_type; + $docId = $docNote = $docNote->save(); + + $noteFile->duplicate_file($docRev->id, $docId, $docRev->filename); + } + } + + //// END ATTACHMENTS FROM DOCUMENTS + /////////////////////////////////////////////////////////////////////////// + + /////////////////////////////////////////////////////////////////////////// + //// REMOVE ATTACHMENTS + if(isset($_REQUEST['remove_attachment']) && !empty($_REQUEST['remove_attachment'])) { + foreach($_REQUEST['remove_attachment'] as $noteId) { + $q = 'UPDATE notes SET deleted = 1 WHERE id = \''.$noteId.'\''; + $this->db->query($q); + } + } + + //this will remove attachments that have been selected to be removed from drafts. + if(isset($_REQUEST['removeAttachment']) && !empty($_REQUEST['removeAttachment'])) { + $exRemoved = explode('::', $_REQUEST['removeAttachment']); + foreach($exRemoved as $noteId) { + $q = 'UPDATE notes SET deleted = 1 WHERE id = \''.$noteId.'\''; + $this->db->query($q); + } + } + //// END REMOVE ATTACHMENTS + /////////////////////////////////////////////////////////////////////////// + } + + + /** + * Determines if an email body (HTML or Plain) has a User signature already in the content + * @param array Array of signatures + * @return bool + */ + function hasSignatureInBody($sig) { + // strpos can't handle line breaks - normalize + $html = $this->removeAllNewlines($this->description_html); + $htmlSig = $this->removeAllNewlines($sig['signature_html']); + $plain = $this->removeAllNewlines($this->description); + $plainSig = $this->removeAllNewlines($sig['signature']); + + // cn: bug 11621 - empty sig triggers notice error + if(!empty($htmlSig) && false !== strpos($html, $htmlSig)) { + return true; + } elseif(!empty($plainSig) && false !== strpos($plain, $plainSig)) { + return true; + } else { + return false; + } + } + + /** + * internal helper + * @param string String to be normalized + * @return string + */ + function removeAllNewlines($str) { + $bad = array("\r\n", "\n\r", "\n", "\r"); + $good = array('', '', '', ''); + + return str_replace($bad, $good, strip_tags(br2nl(from_html($str)))); + } + + + + /** + * Set navigation anchors to aid DetailView record navigation (VCR buttons) + * @param string uri The URI from the referring page (always ListView) + * @return array start Array of the URI broken down with a special "current_view" for My Inbox Navs + */ + function getStartPage($uri) { + if(strpos($uri, '&')) { // "&" to ensure that we can explode the GET vars - else we're gonna trigger a Notice error + $serial = substr($uri, (strpos($uri, '?')+1), strlen($uri)); + $exUri = explode('&', $serial); + $start = array('module' => '', 'action' => '', 'group' => '', 'record' => '', 'type' => ''); + + foreach($exUri as $k => $pair) { + $exPair = explode('=', $pair); + $start[$exPair[0]] = $exPair[1]; + } + + // specific views for current_user + if(isset($start['assigned_user_id'])) { + $start['current_view'] = "{$start['action']}&module={$start['module']}&assigned_user_id={$start['assigned_user_id']}&type={$start['type']}"; + } + + return $start; + } else { + return array(); + } + } + + /** + * preps SMTP info for email transmission + * @param object mail SugarPHPMailer object + * @param string mailer_id + * @param string ieId + * @return object mail SugarPHPMailer object + */ + function setMailer($mail, $mailer_id='', $ieId='') { + global $current_user; + + require_once("include/OutboundEmail/OutboundEmail.php"); + $oe = new OutboundEmail(); + $oe = $oe->getInboundMailerSettings($current_user, $mailer_id, $ieId); + + // ssl or tcp - keeping outside isSMTP b/c a default may inadvertantly set ssl:// + $mail->protocol = ($oe->mail_smtpssl) ? "ssl://" : "tcp://"; + if($oe->mail_sendtype == "SMTP") + { + //Set mail send type information + $mail->Mailer = "smtp"; + $mail->Host = $oe->mail_smtpserver; + $mail->Port = $oe->mail_smtpport; + if ($oe->mail_smtpssl == 1) { + $mail->SMTPSecure = 'ssl'; + } // if + if ($oe->mail_smtpssl == 2) { + $mail->SMTPSecure = 'tls'; + } // if + + if($oe->mail_smtpauth_req) { + $mail->SMTPAuth = TRUE; + $mail->Username = $oe->mail_smtpuser; + $mail->Password = $oe->mail_smtppass; + } + } + else + $mail->Mailer = "sendmail"; + + $mail->oe = $oe; + return $mail; + } + + /** + * preps SugarPHPMailer object for HTML or Plain text sends + * @param object SugarPHPMailer instance + */ + function handleBody($mail) { + global $current_user; + global $sugar_config; + /////////////////////////////////////////////////////////////////////// + //// HANDLE EMAIL FORMAT PREFERENCE + // the if() below is HIGHLY dependent on the Javascript unchecking the Send HTML Email box + // HTML email + if( (isset($_REQUEST['setEditor']) /* from Email EditView navigation */ + && $_REQUEST['setEditor'] == 1 + && trim($_REQUEST['description_html']) != '') + || trim($this->description_html) != '' /* from email templates */ + && $current_user->getPreference('email_editor_option', 'global') !== 'plain' //user preference is not set to plain text + ) { + $this->handleBodyInHTMLformat($mail); + } else { + // plain text only + $this->description_html = ''; + $mail->IsHTML(false); + $plainText = from_html($this->description); + $plainText = str_replace(" ", " ", $plainText); + $plainText = str_replace("

    ", "


    ", $plainText); + $plainText = strip_tags(br2nl($plainText)); + $plainText = str_replace("&", "&", $plainText); + $plainText = str_replace("'", "'", $plainText); + $mail->Body = wordwrap($plainText, 996); + $mail->Body = $this->decodeDuringSend($mail->Body); + $this->description = $mail->Body; + } + + // wp: if plain text version has lines greater than 998, use base64 encoding + foreach(explode("\n", ($mail->ContentType == "text/html") ? $mail->AltBody : $mail->Body) as $line) { + if(strlen($line) > 998) { + $mail->Encoding = 'base64'; + break; + } + } + //// HANDLE EMAIL FORMAT PREFERENCE + /////////////////////////////////////////////////////////////////////// + + return $mail; + } + + /** + * Retrieve function from handlebody() to unit test easily + * @param $mail + * @return formatted $mail body + */ + function handleBodyInHTMLformat($mail) { + global $current_user; + global $sugar_config; + // wp: if body is html, then insert new lines at 996 characters. no effect on client side + // due to RFC 2822 which limits email lines to 998 + $mail->IsHTML(true); + $body = from_html(wordwrap($this->description_html, 996)); + $mail->Body = $body; + + // cn: bug 9725 + // new plan is to use the selected type (html or plain) to fill the other + $plainText = from_html($this->description_html); + $plainText = strip_tags(br2nl($plainText)); + $mail->AltBody = $plainText; + $this->description = $plainText; + + $fileBasePath = "{$sugar_config['cache_dir']}images/"; + $filePatternSearch = "{$sugar_config['cache_dir']}"; + $filePatternSearch = str_replace("/", "\/", $filePatternSearch); + $filePatternSearch = $filePatternSearch . "images\/"; + if(strpos($mail->Body, "\"{$fileBasePath}") !== FALSE) + { //cache/images + $matches = array(); + preg_match_all("/{$filePatternSearch}.+?\"/i", $mail->Body, $matches); + foreach($matches[0] as $match) { + $filename = str_replace($fileBasePath, '', $match); + $filename = urldecode(substr($filename, 0, -1)); + $cid = $filename; + $file_location = clean_path(getcwd()."/{$sugar_config['cache_dir']}images/{$filename}"); + $mime_type = "image/".strtolower(substr($filename, strrpos($filename, ".")+1, strlen($filename))); + + if(file_exists($file_location)) { + $mail->AddEmbeddedImage($file_location, $cid, $filename, 'base64', $mime_type); + } + } + + //replace references to cache with cid tag + $mail->Body = str_replace("/" . $fileBasePath,'cid:',$mail->Body); + $mail->Body = str_replace($fileBasePath,'cid:',$mail->Body); + // remove bad img line from outbound email + $regex = '#]+src[^=]*=\"\/([^>]*?[^>]*)>#sim'; + $mail->Body = preg_replace($regex, '', $mail->Body); + } + $fileBasePath = "{$sugar_config['upload_dir']}"; + $filePatternSearch = "{$sugar_config['upload_dir']}"; + $filePatternSearch = str_replace("/", "\/", $filePatternSearch); + if(strpos($mail->Body, "\"{$fileBasePath}") !== FALSE) + { + $matches = array(); + preg_match_all("/{$filePatternSearch}.+?\"/i", $mail->Body, $matches); + foreach($matches[0] as $match) { + $filename = str_replace($fileBasePath, '', $match); + $filename = urldecode(substr($filename, 0, -1)); + $cid = $filename; + $file_location = clean_path(getcwd()."/{$sugar_config['upload_dir']}{$filename}"); + $mime_type = "image/".strtolower(substr($filename, strrpos($filename, ".")+1, strlen($filename))); + + if(file_exists($file_location)) { + $mail->AddEmbeddedImage($file_location, $cid, $filename, 'base64', $mime_type); + } + } + + //replace references to cache with cid tag + $mail->Body = str_replace("/" . $fileBasePath,'cid:',$mail->Body); + $mail->Body = str_replace($fileBasePath,'cid:',$mail->Body); + + // remove bad img line from outbound email + $regex = '#]+src[^=]*=\"\/([^>]*?[^>]*)>#sim'; + $mail->Body = preg_replace($regex, '', $mail->Body); + } + + //Replace any embeded images using the secure entryPoint for src url. + $noteImgRegex = "/]*[\s]+src[^=]*=\"index.php\?entryPoint=download\&id=([^\&]*)[^>]*>/im"; + $embededImageMatches = array(); + preg_match_all($noteImgRegex, $mail->Body, $embededImageMatches,PREG_SET_ORDER); + + foreach ($embededImageMatches as $singleMatch ) + { + $fullMatch = $singleMatch[0]; + $noteId = $singleMatch[1]; + $cid = $noteId; + $filename = $noteId; + + //Retrieve note for mimetype + $tmpNote = new Note(); + $tmpNote->retrieve($noteId); + //Replace the src part of img tag with new cid tag + $cidRegex = "/src=\"([^\"]*)\"/im"; + $replaceMatch = preg_replace($cidRegex, "src=\"cid:$noteId\"", $fullMatch); + + //Replace the body, old tag for new tag + $mail->Body = str_replace($fullMatch, $replaceMatch, $mail->Body); + + //Attach the file + $file_location = clean_path(getcwd()."/{$sugar_config['upload_dir']}{$noteId}"); + + if(file_exists($file_location)) + $mail->AddEmbeddedImage($file_location, $cid, $filename, 'base64', $tmpNote->file_mime_type); + } + //End Replace + + + $mail->Body = from_html($mail->Body); + } + + /** + * Sends Email + * @return bool True on success + */ + function send() { + global $mod_strings,$app_strings; + global $current_user; + global $sugar_config; + global $locale; + $OBCharset = $locale->getPrecedentPreference('default_email_charset'); + $mail = new SugarPHPMailer(); + + foreach ($this->to_addrs_arr as $addr_arr) { + if ( empty($addr_arr['display'])) { + $mail->AddAddress($addr_arr['email'], ""); + } else { + $mail->AddAddress($addr_arr['email'],$locale->translateCharsetMIME(trim( $addr_arr['display']), 'UTF-8', $OBCharset)); + } + } + foreach ($this->cc_addrs_arr as $addr_arr) { + if ( empty($addr_arr['display'])) { + $mail->AddCC($addr_arr['email'], ""); + } else { + $mail->AddCC($addr_arr['email'],$locale->translateCharsetMIME(trim($addr_arr['display']), 'UTF-8', $OBCharset)); + } + } + + foreach ($this->bcc_addrs_arr as $addr_arr) { + if ( empty($addr_arr['display'])) { + $mail->AddBCC($addr_arr['email'], ""); + } else { + $mail->AddBCC($addr_arr['email'],$locale->translateCharsetMIME(trim($addr_arr['display']), 'UTF-8', $OBCharset)); + } + } + + $mail = $this->setMailer($mail); + + // FROM ADDRESS + if(!empty($this->from_addr)) { + $mail->From = $this->from_addr; + } else { + $mail->From = $current_user->getPreference('mail_fromaddress'); + $this->from_addr = $mail->From; + } + // FROM NAME + if(!empty($this->from_name)) { + $mail->FromName = $this->from_name; + } else { + $mail->FromName = $current_user->getPreference('mail_fromname'); + $this->from_name = $mail->FromName; + } + + //Reply to information for case create and autoreply. + if(!empty($this->reply_to_name)) { + $ReplyToName = $this->reply_to_name; + } else { + $ReplyToName = $mail->FromName; + } + if(!empty($this->reply_to_addr)) { + $ReplyToAddr = $this->reply_to_addr; + } else { + $ReplyToAddr = $mail->From; + } + $mail->Sender = $mail->From; /* set Return-Path field in header to reduce spam score in emails sent via Sugar's Email module */ + $mail->AddReplyTo($ReplyToAddr,$locale->translateCharsetMIME(trim($ReplyToName), 'UTF-8', $OBCharset)); + + //$mail->Subject = html_entity_decode($this->name, ENT_QUOTES, 'UTF-8'); + $mail->Subject = $this->name; + + /////////////////////////////////////////////////////////////////////// + //// ATTACHMENTS + foreach($this->saved_attachments as $note) { + $mime_type = 'text/plain'; + if($note->object_name == 'Note') { + if(!empty($note->file->temp_file_location) && is_file($note->file->temp_file_location)) { // brandy-new file upload/attachment + $file_location = $sugar_config['upload_dir'].$note->id; + $filename = $note->file->original_file_name; + $mime_type = $note->file->mime_type; + } else { // attachment coming from template/forward + $file_location = rawurldecode(UploadFile::get_file_path($note->filename,$note->id)); + // cn: bug 9723 - documents from EmailTemplates sent with Doc Name, not file name. + $filename = !empty($note->filename) ? $note->filename : $note->name; + $mime_type = $note->file_mime_type; + } + } elseif($note->object_name == 'DocumentRevision') { // from Documents + $filePathName = $note->id; + // cn: bug 9723 - Emails with documents send GUID instead of Doc name + $filename = $note->getDocumentRevisionNameForDisplay(); + $file_location = getcwd().'/'.$GLOBALS['sugar_config']['upload_dir'].$filePathName; + $mime_type = $note->file_mime_type; + } + + // strip out the "Email attachment label if exists + $filename = str_replace($mod_strings['LBL_EMAIL_ATTACHMENT'].': ', '', $filename); + + //is attachment in our list of bad files extensions? If so, append .txt to file location + //get position of last "." in file name + $file_ext_beg = strrpos($file_location,"."); + $file_ext = ""; + //get file extension + if($file_ext_beg >0){ + $file_ext = substr($file_location, $file_ext_beg+1 ); + } + //check to see if this is a file with extension located in "badext" + foreach($sugar_config['upload_badext'] as $badExt) { + if(strtolower($file_ext) == strtolower($badExt)) { + //if found, then append with .txt to filename and break out of lookup + //this will make sure that the file goes out with right extension, but is stored + //as a text in db. + $file_location = $file_location . ".txt"; + break; // no need to look for more + } + } + $mail->AddAttachment($file_location,$locale->translateCharsetMIME(trim($filename), 'UTF-8', $OBCharset), 'base64', $mime_type); + + // embedded Images + if($note->embed_flag == true) { + $cid = $filename; + $mail->AddEmbeddedImage($file_location, $cid, $filename, 'base64',$mime_type); + } + } + //// END ATTACHMENTS + /////////////////////////////////////////////////////////////////////// + + $mail = $this->handleBody($mail); + + $GLOBALS['log']->debug('Email sending --------------------- '); + + /////////////////////////////////////////////////////////////////////// + //// I18N TRANSLATION + $mail->prepForOutbound(); + //// END I18N TRANSLATION + /////////////////////////////////////////////////////////////////////// + + if($mail->Send()) { + /////////////////////////////////////////////////////////////////// + //// INBOUND EMAIL HANDLING + // mark replied + if(!empty($_REQUEST['inbound_email_id'])) { + $ieMail = new Email(); + $ieMail->retrieve($_REQUEST['inbound_email_id']); + $ieMail->status = 'replied'; + $ieMail->save(); + } + $GLOBALS['log']->debug(' --------------------- buh bye -- sent successful'); + //// END INBOUND EMAIL HANDLING + /////////////////////////////////////////////////////////////////// + return true; + } + $GLOBALS['log']->debug($app_strings['LBL_EMAIL_ERROR_PREPEND'].$mail->ErrorInfo); + return false; + } + + + function listviewACLHelper(){ + $array_assign = parent::listviewACLHelper(); + $is_owner = false; + if(!empty($this->parent_name)){ + + if(!empty($this->parent_name_owner)){ + global $current_user; + $is_owner = $current_user->id == $this->parent_name_owner; + } + } + if(!ACLController::moduleSupportsACL($this->parent_type) || ACLController::checkAccess($this->parent_type, 'view', $is_owner)){ + $array_assign['PARENT'] = 'a'; + } else { + $array_assign['PARENT'] = 'span'; + } + $is_owner = false; + if(!empty($this->contact_name)) { + if(!empty($this->contact_name_owner)) { + global $current_user; + $is_owner = $current_user->id == $this->contact_name_owner; + } + } + if(ACLController::checkAccess('Contacts', 'view', $is_owner)) { + $array_assign['CONTACT'] = 'a'; + } else { + $array_assign['CONTACT'] = 'span'; + } + + return $array_assign; + } + + function getSystemDefaultEmail() { + $email = array(); + + $r1 = $this->db->query('SELECT config.value FROM config WHERE name=\'fromaddress\''); + $r2 = $this->db->query('SELECT config.value FROM config WHERE name=\'fromname\''); + $a1 = $this->db->fetchByAssoc($r1); + $a2 = $this->db->fetchByAssoc($r2); + + $email['email'] = $a1['value']; + $email['name'] = $a2['value']; + + return $email; + } + + + function create_new_list_query($order_by, $where,$filter=array(),$params=array(), $show_deleted = 0,$join_type='', $return_array = false,$parentbean=null, $singleSelect = false) { + + if ($return_array) { + return parent::create_new_list_query($order_by, $where,$filter,$params, $show_deleted,$join_type, $return_array,$parentbean, $singleSelect); + } + $custom_join = $this->custom_fields->getJOIN(); + + $query = "SELECT ".$this->table_name.".*, users.user_name as assigned_user_name\n"; + + if($custom_join){ + $query .= $custom_join['select']; + } + $query .= " FROM emails\n"; + if ($where != "" && (strpos($where, "contacts.first_name") > 0)) { + $query .= " LEFT JOIN emails_beans ON emails.id = emails_beans.email_id\n"; + } + + $query .= " LEFT JOIN users ON emails.assigned_user_id=users.id \n"; + if ($where != "" && (strpos($where, "contacts.first_name") > 0)) { + + $query .= " JOIN contacts ON contacts.id= emails_beans.bean_id AND emails_beans.bean_module='Contacts' and contacts.deleted=0 \n"; + } + + if($custom_join){ + $query .= $custom_join['join']; + } + + if($show_deleted == 0) { + $where_auto = " emails.deleted=0 \n"; + }else if($show_deleted == 1){ + $where_auto = " emails.deleted=1 \n"; + } + + if($where != "") + $query .= "WHERE $where AND ".$where_auto; + else + $query .= "WHERE ".$where_auto; + + if($order_by != "") + $query .= " ORDER BY $order_by"; + else + $query .= " ORDER BY date_sent DESC"; + + return $query; + } // fn + + + function fill_in_additional_list_fields() { + global $timedate; + $this->fill_in_additional_detail_fields(); + + $this->link_action = 'DetailView'; + /////////////////////////////////////////////////////////////////////// + //populate attachment_image, used to display attachment icon. + $query = "select 1 from notes where notes.parent_id = '$this->id' and notes.deleted = 0"; + $result =$this->db->query($query,true," Error filling in additional list fields: "); + + $row = $this->db->fetchByAssoc($result); + + if ($row !=null) { + $this->attachment_image = SugarThemeRegistry::current()->getImage('attachment',"","",""); + } else { + $this->attachment_image = SugarThemeRegistry::current()->getImage('blank',"","",""); + } + /////////////////////////////////////////////////////////////////////// + if(empty($this->contact_id) && !empty($this->parent_id) && !empty($this->parent_type) && $this->parent_type === 'Contacts' && !empty($this->parent_name) ){ + $this->contact_id = $this->parent_id; + $this->contact_name = $this->parent_name; + } + } + + function fill_in_additional_detail_fields() { + global $app_list_strings,$mod_strings; + // Fill in the assigned_user_name + $this->assigned_user_name = get_assigned_user_name($this->assigned_user_id, ''); + //if ($this->parent_type == 'Contacts') { + $query = "SELECT contacts.first_name, contacts.last_name, contacts.phone_work, contacts.id, contacts.assigned_user_id contact_name_owner, 'Contacts' contact_name_mod FROM contacts, emails_beans "; + $query .= "WHERE emails_beans.email_id='$this->id' AND emails_beans.bean_id=contacts.id AND emails_beans.bean_module = 'Contacts' AND emails_beans.deleted=0 AND contacts.deleted=0"; + if(!empty($this->parent_id)){ + $query .= " AND contacts.id= '".$this->parent_id."' "; + }else if(!empty($_REQUEST['record'])){ + $query .= " AND contacts.id= '".$_REQUEST['record']."' "; + } + $result =$this->db->query($query,true," Error filling in additional detail fields: "); + + // Get the id and the name. + $row = $this->db->fetchByAssoc($result); + if($row != null) + { + + $contact = new Contact(); + $contact->retrieve($row['id']); + $this->contact_name = $contact->full_name; + $this->contact_phone = $row['phone_work']; + $this->contact_id = $row['id']; + $this->contact_email = $contact->emailAddress->getPrimaryAddress($contact); + $this->contact_name_owner = $row['contact_name_owner']; + $this->contact_name_mod = $row['contact_name_mod']; + $GLOBALS['log']->debug("Call($this->id): contact_name = $this->contact_name"); + $GLOBALS['log']->debug("Call($this->id): contact_phone = $this->contact_phone"); + $GLOBALS['log']->debug("Call($this->id): contact_id = $this->contact_id"); + $GLOBALS['log']->debug("Call($this->id): contact_email1 = $this->contact_email"); + } + else { + $this->contact_name = ''; + $this->contact_phone = ''; + $this->contact_id = ''; + $this->contact_email = ''; + $this->contact_name_owner = ''; + $this->contact_name_mod = ''; + $GLOBALS['log']->debug("Call($this->id): contact_name = $this->contact_name"); + $GLOBALS['log']->debug("Call($this->id): contact_phone = $this->contact_phone"); + $GLOBALS['log']->debug("Call($this->id): contact_id = $this->contact_id"); + $GLOBALS['log']->debug("Call($this->id): contact_email1 = $this->contact_email"); + } + //} + $this->created_by_name = get_assigned_user_name($this->created_by); + $this->modified_by_name = get_assigned_user_name($this->modified_user_id); + + $this->link_action = 'DetailView'; + + if(!empty($this->type)) { + if($this->type == 'out' && $this->status == 'send_error') { + $this->type_name = $mod_strings['LBL_NOT_SENT']; + } else { + $this->type_name = $app_list_strings['dom_email_types'][$this->type]; + } + + if(($this->type == 'out' && $this->status == 'send_error') || $this->type == 'draft') { + $this->link_action = 'EditView'; + } + } + + //todo this isset( $app_list_strings['dom_email_status'][$this->status]) is hack for 3261. + if(!empty($this->status) && isset( $app_list_strings['dom_email_status'][$this->status])) { + $this->status_name = $app_list_strings['dom_email_status'][$this->status]; + } + + if ( empty($this->name ) && empty($_REQUEST['record'])) { + $this->name = $mod_strings['LBL_NO_SUBJECT']; + } + + $this->fill_in_additional_parent_fields(); + } + + + + function create_export_query(&$order_by, &$where) { + $contact_required = stristr($where, "contacts"); + $custom_join = $this->custom_fields->getJOIN(true, true,$where); + + if($contact_required) { + $query = "SELECT emails.*, contacts.first_name, contacts.last_name"; + if($custom_join) { + $query .= $custom_join['select']; + } + + $query .= " FROM contacts, emails, emails_contacts "; + $where_auto = "emails_contacts.contact_id = contacts.id AND emails_contacts.email_id = emails.id AND emails.deleted=0 AND contacts.deleted=0"; + } else { + $query = 'SELECT emails.*'; + if($custom_join) { + $query .= $custom_join['select']; + } + + $query .= ' FROM emails '; + $where_auto = "emails.deleted=0"; + } + + if($custom_join){ + $query .= $custom_join['join']; + } + + if($where != "") + $query .= "where $where AND ".$where_auto; + else + $query .= "where ".$where_auto; + + if($order_by != "") + $query .= " ORDER BY $order_by"; + else + $query .= " ORDER BY emails.name"; + return $query; + } + + function get_list_view_data() { + global $app_list_strings; + global $theme; + global $current_user; + global $timedate; + global $mod_strings; + + $email_fields = $this->get_list_view_array(); + $this->retrieveEmailText(); + $email_fields['FROM_ADDR'] = $this->from_addr_name; + $mod_strings = return_module_language($GLOBALS['current_language'], 'Emails'); // hard-coding for Home screen ListView + + if($this->status != 'replied') { + $email_fields['QUICK_REPLY'] = ''.$mod_strings['LNK_QUICK_REPLY'].''; + $email_fields['STATUS'] = ($email_fields['REPLY_TO_STATUS'] == 1 ? $mod_strings['LBL_REPLIED'] : $email_fields['STATUS']); + } else { + $email_fields['QUICK_REPLY'] = $mod_strings['LBL_REPLIED']; + } + if(!empty($this->parent_type)) { + $email_fields['PARENT_MODULE'] = $this->parent_type; + } else { + switch($this->intent) { + case 'support': + $email_fields['CREATE_RELATED'] = ''.$mod_strings['LBL_CREATE_CASE'].''; + break; + + case 'sales': + $email_fields['CREATE_RELATED'] = ''.$mod_strings['LBL_CREATE_LEAD'].''; + break; + + case 'contact': + $email_fields['CREATE_RELATED'] = ''.$mod_strings['LBL_CREATE_CONTACT'].''; + break; + + case 'bug': + $email_fields['CREATE_RELATED'] = ''.$mod_strings['LBL_CREATE_BUG'].''; + break; + + case 'task': + $email_fields['CREATE_RELATED'] = ''.$mod_strings['LBL_CREATE_TASK'].''; + break; + + case 'bounce': + break; + + case 'pick': + // break; + + case 'info': + //break; + + default: + $email_fields['CREATE_RELATED'] = $this->quickCreateForm(); + break; + } + + } + + //BUG 17098 - MFH changed $this->from_addr to $this->to_addrs + $email_fields['CONTACT_NAME'] = empty($this->contact_name) ? ''.$this->trimLongTo($this->to_addrs).'' : $this->contact_name; + $email_fields['CONTACT_ID'] = empty($this->contact_id) ? '' : $this->contact_id; + $email_fields['ATTACHMENT_IMAGE'] = $this->attachment_image; + $email_fields['LINK_ACTION'] = $this->link_action; + + if(isset($this->type_name)) + $email_fields['TYPE_NAME'] = $this->type_name; + + return $email_fields; + } + + function quickCreateForm() { + global $mod_strings, $app_strings, $currentModule, $current_language; + + // Coming from the home page via Dashlets + if($currentModule != 'Email') + $mod_strings = return_module_language($current_language, 'Emails'); + return $mod_strings['LBL_QUICK_CREATE']." ".SugarThemeRegistry::current()->getImage("advanced_search","alt='".$mod_strings['LBL_QUICK_CREATE']."' border='0' align='absmiddle'").""; + } + + /** + * Searches all imported emails and returns the result set as an array. + * + */ + function searchImportedEmails($sort = '', $direction='') + { + require_once('include/TimeDate.php'); + global $timedate; + global $current_user; + global $beanList; + global $sugar_config; + global $app_strings; + + $emailSettings = $current_user->getPreference('emailSettings', 'Emails'); + // cn: default to a low number until user specifies otherwise + if(empty($emailSettings['showNumInList'])) + $pageSize = 20; + else + $pageSize = $emailSettings['showNumInList']; + + if( isset($_REQUEST['start']) && isset($_REQUEST['limit']) ) + $page = ceil($_REQUEST['start'] / $_REQUEST['limit']) + 1; + else + $page = 1; + + //Determine sort ordering + + //Sort ordering parameters in the request do not coincide with actual column names + //so we need to remap them. + $hrSortLocal = array( + 'flagged' => 'type', + 'status' => 'reply_to_status', + 'from' => 'emails_text.from_addr', + 'subject' => 'name', + 'date' => 'date_sent', + 'AssignedTo' => 'assigned_user_id', + 'flagged' => 'flagged' + ); + + $sort = !empty($_REQUEST['sort']) ? $_REQUEST['sort'] : ""; + $direction = !empty($_REQUEST['dir']) ? $_REQUEST['dir'] : ""; + + $order = ( !empty($sort) && !empty($direction) ) ? " ORDER BY {$hrSortLocal[$sort]} {$direction}" : ""; + + //Get our main query. + $fullQuery = $this->_genereateSearchImportedEmailsQuery(); + + //Perform a count query needed for pagination. + $countQuery = $this->create_list_count_query($fullQuery); + $count_rs = $this->db->query($countQuery, false, 'Error executing count query for imported emails search'); + $count_row = $this->db->fetchByAssoc($count_rs); + $total_count = ($count_row != null) ? $count_row['c'] : 0; + + $start = ($page - 1) * $pageSize; + + //Execute the query + $rs = $this->db->limitQuery($fullQuery . $order, $start, $pageSize); + + $return = array(); + + while($a = $this->db->fetchByAssoc($rs)) { + $temp = array(); + $temp['flagged'] = (is_null($a['flagged']) || $a['flagged'] == '0') ? '' : 1; + $temp['status'] = (is_null($a['reply_to_status']) || $a['reply_to_status'] == '0') ? '' : 1; + $temp['subject'] = $a['name']; + $temp['date'] = $timedate->to_display_date_time($a['date_sent']); + $temp['uid'] = $a['id']; + $temp['ieId'] = $a['mailbox_id']; + $temp['site_url'] = $sugar_config['site_url']; + $temp['seen'] = ($a['status'] == 'unread') ? 0 : 1; + $temp['type'] = $a['type']; + $temp['mbox'] = 'sugar::Emails'; + $temp['hasAttach'] = $this->doesImportedEmailHaveAttachment($a['id']); + //To and from addresses may be stored in emails_text, if nothing is found, revert to + //regular email addresses. + $temp['to_addrs'] = preg_replace('/[\x00-\x08\x0B-\x1F]/', '', $a['to_addrs']); + $temp['from'] = preg_replace('/[\x00-\x08\x0B-\x1F]/', '', $a['from_addr']); + if( empty($temp['from']) || empty($temp['to_addrs']) ) + { + //Retrieve email addresses seperatly. + $tmpEmail = new Email(); + $tmpEmail->id = $a['id']; + $tmpEmail->retrieveEmailAddresses(); + $temp['from'] = $tmpEmail->from_addr; + $temp['to_addrs'] = $tmpEmail->to_addrs; + } + + $return[] = $temp; + } + + $metadata = array(); + $metadata['totalCount'] = $total_count; + $metadata['out'] = $return; + + return $metadata; + } + + /** + * Determine if an imported email has an attachment by examining the relationship to notes. + * + * @param string $id + * @return boolean + */ + function doesImportedEmailHaveAttachment($id) + { + $hasAttachment = FALSE; + $query = "SELECT id FROM notes where parent_id='$id' AND parent_type='Emails' AND file_mime_type is not null AND deleted=0"; + $rs = $this->db->limitQuery($query, 0, 1); + $row = $this->db->fetchByAssoc($rs); + if( !empty($row['id']) ) + $hasAttachment = TRUE; + + return (int) $hasAttachment; + } + + /** + * Generate the query used for searching imported emails. + * + * @return String Query to be executed. + */ + function _genereateSearchImportedEmailsQuery() + { + global $timedate; + + $additionalWhereClause = $this->_generateSearchImportWhereClause(); + + $query = array(); + $fullQuery = ""; + $query['select'] = "emails.id , emails.mailbox_id, emails.name, emails.date_sent, emails.status, emails.type, emails.flagged, emails.reply_to_status, + emails_text.from_addr, emails_text.to_addrs FROM emails "; + + $query['joins'] = " JOIN emails_text on emails.id = emails_text.email_id "; + + //Handle from and to addr joins + if( !empty($_REQUEST['from_addr']) ) + { + $query['joins'] .= "INNER JOIN emails_email_addr_rel er_from ON er_from.email_id = emails.id AND er_from.deleted = 0 INNER JOIN email_addresses ea_from ON ea_from.id = er_from.email_address_id + AND er_from.address_type='from' AND ea_from.email_address='" . strtolower($_REQUEST['from_addr']) . "'"; + } + + if( !empty($_REQUEST['to_addrs']) ) + { + $query['joins'] .= "INNER JOIN emails_email_addr_rel er_to ON er_to.email_id = emails.id AND er_to.deleted = 0 INNER JOIN email_addresses ea_to ON ea_to.id = er_to.email_address_id + AND er_to.address_type='to' AND ea_to.email_address='" . strtolower($_REQUEST['to_addrs']) . "'"; + } + + $query['where'] = " WHERE (emails.type= 'inbound' OR emails.type='archived' OR emails.type='out') AND emails.deleted = 0 "; + if( !empty($additionalWhereClause) ) + $query['where'] .= "AND $additionalWhereClause"; + + //If we are explicitly looking for attachments. Do not use a distinct query as the to_addr is defined + //as a text which equals clob in oracle and the distinct query can not be executed correctly. + $addDistinctKeyword = ""; + if( !empty($_REQUEST['attachmentsSearch']) && $_REQUEST['attachmentsSearch'] == 1) //1 indicates yes + $query['where'] .= " AND EXISTS ( SELECT id FROM notes n WHERE n.parent_id = emails.id AND n.deleted = 0 AND n.filename is not null )"; + else if( !empty($_REQUEST['attachmentsSearch']) && $_REQUEST['attachmentsSearch'] == 2 ) + $query['where'] .= " AND NOT EXISTS ( SELECT id FROM notes n WHERE n.parent_id = emails.id AND n.deleted = 0 AND n.filename is not null )"; + + $fullQuery = "SELECT " . $query['select'] . " " . $query['joins'] . " " . $query['where']; + + return $fullQuery; + } + /** + * Generate the where clause for searching imported emails. + * + */ + function _generateSearchImportWhereClause() + { + global $timedate; + + //The clear button was removed so if a user removes the asisgned user name, do not process the id. + if( empty($_REQUEST['assigned_user_name']) && !empty($_REQUEST['assigned_user_id']) ) + unset($_REQUEST['assigned_user_id']); + + $availableSearchParam = array('name' => array('table_name' =>'emails'), + 'data_parent_id_search' => array('table_name' =>'emails','db_key' => 'parent_id','opp' => '='), + 'assigned_user_id' => array('table_name' => 'emails', 'opp' => '=') ); + + $additionalWhereClause = array(); + foreach ($availableSearchParam as $key => $properties) + { + if( !empty($_REQUEST[$key]) ) + { + $db_key = isset($properties['db_key']) ? $properties['db_key'] : $key; + $searchValue = $_REQUEST[$key]; + + $opp = isset($properties['opp']) ? $properties['opp'] : 'like'; + if($opp == 'like') + $searchValue = $searchValue . "%"; + + $additionalWhereClause[] = "{$properties['table_name']}.$db_key $opp '$searchValue' "; + } + } + + $isDateFromSearchSet = !empty($_REQUEST['searchDateFrom']); + $isdateToSearchSet = !empty($_REQUEST['searchDateTo']); + + $bothDateRangesSet = $isDateFromSearchSet & $isdateToSearchSet; + + //Hanlde date from and to seperately + if($bothDateRangesSet) + { + $dbFormatDateFrom = $timedate->to_db_date($_REQUEST['searchDateFrom'], false); + $dbFormatDateFrom = db_convert("'" . $dbFormatDateFrom . "'",'datetime'); + + $dbFormatDateTo = $timedate->to_db_date($_REQUEST['searchDateTo'], false); + $dbFormatDateTo = db_convert("'" . $dbFormatDateTo . "'",'datetime'); + + $additionalWhereClause[] = "( emails.date_sent >= $dbFormatDateFrom AND + emails.date_sent <= $dbFormatDateTo )"; + } + elseif ($isdateToSearchSet) + { + $dbFormatDateTo = $timedate->to_db_date($_REQUEST['searchDateTo'], false); + $dbFormatDateTo = db_convert("'" . $dbFormatDateTo . "'",'datetime'); + $additionalWhereClause[] = "emails.date_sent <= $dbFormatDateTo "; + } + elseif ($isDateFromSearchSet) + { + $dbFormatDateFrom = $timedate->to_db_date($_REQUEST['searchDateFrom'], false); + $dbFormatDateFrom = db_convert("'" . $dbFormatDateFrom . "'",'datetime'); + $additionalWhereClause[] = "emails.date_sent >= $dbFormatDateFrom "; + } + + $additionalWhereClause = implode(" AND ", $additionalWhereClause); + + return $additionalWhereClause; + } + + + + /** + * takes a long TO: string of emails and returns the first appended by an + * elipse + */ + function trimLongTo($str) { + if(strpos($str, ',')) { + $exStr = explode(',', $str); + return $exStr[0].'...'; + } elseif(strpos($str, ';')) { + $exStr = explode(';', $str); + return $exStr[0].'...'; + } else { + return $str; + } + } + + function get_summary_text() { + return $this->name; + } + + + + function distributionForm($where) { + global $app_list_strings; + global $app_strings; + global $mod_strings; + global $theme; + global $current_user; + + $distribution = get_select_options_with_id($app_list_strings['dom_email_distribution'], ''); + $_SESSION['distribute_where'] = $where; + + + $out = '
    '; + $out .= get_form_header($mod_strings['LBL_DIST_TITLE'], '', false); + $out .=<< + enableQS(true); + +eoq; + $out .= ' + + + + +
    + + + + + + + + + '; + + + $out .= ' + '; + + + $out .= ' + +
    +  '.$mod_strings['LBL_ASSIGN_SELECTED_RESULTS_TO'].' '; + $out .= $this->userSelectTable(); + $out .= ' +  '.$mod_strings['LBL_USING_RULES'].'  + +
    + '; + $out .= '
    +
    + '; + return $out; + } + + function userSelectTable() { + global $theme; + global $mod_strings; + + $colspan = 1; + $setTeamUserFunction = ''; + + + // get users + $r = $this->db->query("SELECT users.id, users.user_name, users.first_name, users.last_name FROM users WHERE deleted=0 AND status = 'Active' AND is_group=0 ORDER BY users.last_name, users.first_name"); + + $userTable = ''; + $userTable .= ''; + $userTable .= ''; + $userTable .= ''; + $userTable .= '
    '.$mod_strings['LBL_USER_SELECT'].'
    '.$mod_strings['LBL_TOGGLE_ALL'].'
    '; + + $out = ' + + +   + + + + + + + '; + return $out; + } + + function checkInbox($type) { + global $theme; + global $mod_strings; + $out = '
    '; + return $out; + } + + /** + * Guesses Primary Parent id from From: email address. Cascades guesses from Accounts to Contacts to Leads to + * Users. This will not affect the many-to-many relationships already constructed as this is, at best, + * informational linking. + */ + function fillPrimaryParentFields() { + if(empty($this->from_addr)) + return; + + $GLOBALS['log']->debug("*** Email trying to guess Primary Parent from address [ {$this->from_addr} ]"); + + $tables = array('accounts'); + $ret = array(); + // loop through types to get hits + foreach($tables as $table) { + $q = "SELECT name, id FROM {$table} WHERE email1 = '{$this->from_addr}' OR email2 = '{$this->from_addr}' AND deleted = 0"; + $r = $this->db->query($q); + while($a = $this->db->fetchByAssoc($r)) { + if(!empty($a['name']) && !empty($a['id'])) { + $this->parent_type = ucwords($table); + $this->parent_id = $a['id']; + $this->parent_name = $a['name']; + return; + } + } + } + } + + + +} // end class def diff --git a/modules/Emails/EmailUI.css b/modules/Emails/EmailUI.css new file mode 100644 index 00000000..06ddad38 --- /dev/null +++ b/modules/Emails/EmailUI.css @@ -0,0 +1,496 @@ +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + +/************** + TreeView Icons +**************/ +.remoteAccount, a.remoteAccount, +.remoteFolderGroup, a.remoteFolderGroup, +.remoteFolderGroupUnseen, a.remoteFolderGroupUnseen, +.sugarFolder, a.sugarFolder, +.sugarFolderUnseen, a.sugarFolderUnseen, +.sugarFolderGroup, a.sugarFolderGroup, +.sugarFolderGroupUnseen, a.sugarFolderGroupUnseen, +.sugarFolderDynamic, a.sugarFolderDynamic, +.sugarFolderDynamicUnseen, a.sugarFolderDynamicUnseen +{ + text-decoration : none; +} +.remoteAccount { + background: transparent url(images/email.gif) no-repeat; +} +.remoteAccountGroup { + background: transparent url(images/emailGroup.gif) no-repeat; + color: #070; + font-style: italic; +} + +.remoteFolder, a.remoteFolder, +.remoteFolderUnseen, a.remoteFolderUnseen, +.remoteFolderGroupUnseen, a.remoteFolderGroupUnseen { + padding-left: 0px; + text-decoration : none; +} +.remoteFolderUnseen, .remoteFolderGroupUnseen, .sugarFolderUnseen, .sugarFolderGroupUnseen, .sugarFolderDynamicUnseen { + font-weight: bold; +} + +.sugarFolderGroup, .sugarFolderGroupUnseen { + background: transparent url(../../index.php?entryPoint=getImage&imageName=icon_email_folder.gif) no-repeat; + font-style: italic; +} + +.sugarFolderDynamic, .sugarFolderDynamicUnseen { + background: transparent url(../../index.php?entryPoint=getImage&imageName=icon_email_folder.gif) no-repeat; +} + +.composeRightTabs span[name="teamset_div"] input { + max-width: 95px; +} +.composeRightTabs input, .composeRightTabs select { + max-width: 190px; +} +/************** + Hack for Sugar's pop-over menus +**************/ +.menu{ + z-index:100; +} + +.subDmenu{ + z-index:100; +} + +/************** + Contacts styles +**************/ +.rowStylenone { + display: none; +} + +/************** + UI Elements +**************/ +.sectionTitle { + background-color: #eee; + padding: 5px; + padding-top: 10px; + padding-bottom: 10px; + font-size: 13px; + font-weight: bold; +} + +.selectedDiv { + color: #00a; + background-color: #ccc; +} + + +.folderSelected { + background-color: #f00; +} + +.emailUILabel { + width: 1%; + vertical-align: top; + font-weight: bold; + text-align: right; + padding-bottom: 1em; +} +.emailUILabel button{ + width: 50px; + text-align: right; +} + +.emailUIField { + text-align: left; + padding-bottom: 1em; +} +.emailUITextField { + border: 1px solid #333; +} +.emailUILink { + font-family: arial; + text-decoration: none; +} + +.groupFolder { + color: #007700; + font-style: italic; +} + +.sugarFolder { + color: #000077; +} + + +.displayEmailLabel { + color: #999; + font-weight: bold; + text-align: right; +} +.displayEmailValue { + color: #000; +} +.displayEmailLabel, .displayEmailValue { + padding: 2px; + background-color: #eee; +} +.displayEmailValueWhite { + padding: 2px; + background-color: #fff; +} + +.ieFolder .ygtvcontent a{ + margin-left:18px; +} + +.ieFolder a.ygtvspacer{ + float:left; + height:16px; + left:17px; + position:relative; + width:16px; + background:transparent url(../../index.php?entryPoint=getImage&imageName=icon_email_folder.gif) no-repeat scroll 0 -1px; +} + +.ieFolder .ygtvtm a.ygtvspacer, .ieFolder .ygtvtmh a.ygtvspacer, .ieFolder .ygtvlm a.ygtvspacer, .ieFolder .ygtvlmh a.ygtvspacer { + background: transparent url(../../index.php?entryPoint=getImage&imageName=icon_email_folder_exp.gif) no-repeat; +} + +.sugarFolder a.ygtvspacer{ + float:left; + height:16px; + left:17px; + position:relative; + width:16px; + background:transparent url(../../index.php?entryPoint=getImage&imageName=icon_email_sugfolder.gif) no-repeat scroll 0 -1px; +} + +.sugarFolder .ygtvtm a.ygtvspacer, .sugarFolder .ygtvlm a.ygtvspacer, .sugarFolder .ygtvtmh a.ygtvspacer, .sugarFolder .ygtvlmh a.ygtvspacer { + background: transparent url(../../index.php?entryPoint=getImage&imageName=icon_email_sugfolder_exp.gif) no-repeat; +} + +.x-tree-node-collapsed.sugarFolder .x-tree-node-icon, .sugarFolder .ygtvcontent a, .folderDragProxy { + background: transparent url(../../index.php?entryPoint=getImage&imageName=icon_email_sugfolder.gif) no-repeat scroll 0 -1px; + padding-left:18px; +} + +.x-tree-node-expanded.sugarFolder .x-tree-node-icon { + background: transparent url(../../index.php?entryPoint=getImage&imageName=icon_email_sugfolder_exp.gif) no-repeat; +} + +.groupFolder .x-tree-node-icon, .groupFolder .ygtvcontent a { + background: transparent url(../../index.php?entryPoint=getImage&imageName=icon_email_folder_grp.gif) no-repeat scroll 0 -1px; + padding-left:18px; +} +.x-view-selected, .x-view-selected td { + background-color:#316ac5; + color:white; +} +.address-primary { + font-weight: bold; +} + +.address-list-exp { + font-style: italic; +} + +.sqsFloater, #smartInputFloaterContent { + z-index: 11000; +} + +.input-error { + border: 1px solid #f00 +} + +.maybe { + display: inline; + white-space: nowrap; +} + +table.list { + margin: 0px; +} + +.view, table.view { + margin-top:0px; + margin-bottom:0px; +} + +.yui-nav img { + float: left; +} + +li.yuimenuitem-disabled { + display: none; +} + +#container .yui-navset { + overflow-y: hidden; +} + +#lefttabs .yui-nav .selected a em { + padding-top: 1px; +} +#lefttabs .yui-content { + border: none; +} + +#lefttabs .yui-dt-empty { + display:none; +} + +/* .yui-dt table tr th { + padding: 2px 5px !important; +}*/ + +div #rollover { + white-space: normal; + display: inline; + float:none !important; +} + +.x-dd-drag-ghost { + opacity : 1; +} + +#settingsDialog .bd, #settingsDialog .yui-content, #contactsDialogue .bd{ + padding: 0px; +} + +#settingsDialog .edit tr th { + +} + + +#_blank, #listBottom, #displayEmailFramePreview { + width:100%; + height:100%; +} +#_blank { + padding-top: 7px; +} +#_blank, #listBottom { + overflow: hidden; +} +#importDiv { + padding:10px 0 !important; +} + +#listRight { + margin-left: 2px; + margin-right: 5px; +} + +#searchTable { + padding: 0px; + margin: 0px; +} + +#peopleTableSearchRow td { + padding: 3px !important; +} + +#peopleTableSearchRow td { + padding: 3px !important; +} + +#listViewDiv .yui-layout-unit .yui-layout-hd { + display: none; +} +#mbfooter img { + position: relative; + top: -1px; +} + +#mbfooter h2 td { + font-weight: normal; +} + +.yui-layout-unit-left .yui-layout-hd { + border-bottom-width:0; +} + +td.yui-dt-col-bean_id { + text-align: center; +} + +.yuimenuitem-disabled .yuimenuitemlabel-disabled, .yuimenuitem-disabled a.yuimenuitemlabel-disabled, .yuimenuitem-disabled a.yuimenuitemlabel-disabled:hover { + display:none; +} + +#listViewDiv .pagination { + margin-bottom: 10px; +} + + +.paginator-start { + width: 27px; + height: 20px; + background: transparent url('../../index.php?entryPoint=getImage&imageName=start_off.gif') no-repeat; +} + +.pagination a .paginator-start { + background: transparent url('../../index.php?entryPoint=getImage&imageName=start.gif') no-repeat; +} + +.paginator-previous { + width: 24px; + height: 24px; + background: transparent url('../../index.php?entryPoint=getImage&imageName=previous_off.gif') no-repeat; +} + +.pagination a .paginator-previous { + background: transparent url('../../index.php?entryPoint=getImage&imageName=previous.gif') no-repeat; +} + +.paginator-next { + width: 24px; + height: 24px; + background: transparent url('../../index.php?entryPoint=getImage&imageName=next_off.gif') no-repeat; +} + +.pagination a .paginator-next { + background: transparent url('../../index.php?entryPoint=getImage&imageName=next.gif') no-repeat; +} + +.paginator-end { + width: 27px; + height: 20px; + background: transparent url('../../index.php?entryPoint=getImage&imageName=end_off.gif') no-repeat; +} + +.pagination a .paginator-end { + background: transparent url('../../index.php?entryPoint=getImage&imageName=end.gif') no-repeat; +} + +.pagination .yui-pg-first, .pagination .yui-pg-previous, .pagination .yui-pg-next, .yui-pg-last, .pagination .yui-pg-current, .pagination .yui-pg-pages, .pagination .yui-pg-page { + padding: 0px; +} + +#settingsDialog .yui-content { + border: none; +} + +#settingsDialog table.view { + padding-top: 10px; + padding-bottom: 10px; + border:0px; + border-bottom: 1px solid #CCCCCC; +} + +#settingsDialog h4 { + text-align:left; + padding-left: 0px; +} + +button img { + border: none; +} + +.addressbookSearch { + padding:4px 0 2px; + width: 180px; +} + +.addressbookSearch .button { + margin-top: -6px; + margin-left: 2px; + padding: 0; +} +.addressbookSearch span { + white-space:nowrap; +} + +.addressbookSearch input { + width: 90px; +} + +.yui-layout th { + text-align:left; +} + +#ieSelect tr td { + display:inline; + position:relative; + left:-2px; +} + +div#content { + padding-bottom: 0px; +} + +.yui-cstm-cntrd-liner { +margin:0; +text-align: center !important; +} + +.rolloverEmail { + position: relative; + margin: none; + display: inline; +} + +.rolloverEmail a { + text-decoration: none; +} + +.rolloverEmail a span { + text-decoration: none; + display: none; + overflow: hidden; +} + +.rolloverEmail a:hover span { + display: inline; + width: 150px; + margin : 5px 5px 5px 5px; + position: absolute; + padding: 10px; + color: #333; + border: 1px solid #ccc; + background-color: #fff; + font-size: 12px; + z-index: 1000; + top: -10px; + right: 10px; +} + +.advancedSearchTD { + padding: 3px; + white-space: nowrap; +} \ No newline at end of file diff --git a/modules/Emails/EmailUI.php b/modules/Emails/EmailUI.php new file mode 100644 index 00000000..5c7f0569 --- /dev/null +++ b/modules/Emails/EmailUI.php @@ -0,0 +1,2960 @@ +div#rollover {position: relative;float: left;margin: none;text-decoration: none;}div#rollover a:hover {padding: 0;}div#rollover a span {display: none;}div#rollover a:hover span {text-decoration: none;display: block;width: 250px;margin-top: 5px;margin-left: 5px;position: absolute;padding: 10px;color: #333; border: 1px solid #ccc; background-color: #fff; font-size: 12px;z-index: 1000;}\n"; + var $groupCss = ""; + var $cacheTimeouts = array( + 'messages' => 86400, // 24 hours + 'folders' => 300, // 5 mins + 'attachments' => 86400, // 24 hours + ); + var $userCacheDir = ''; + var $coreDynamicFolderQuery = "SELECT emails.id polymorphic_id, 'Emails' polymorphic_module FROM emails + JOIN emails_text on emails.id = emails_text.email_id + WHERE (type = '::TYPE::' OR status = '::STATUS::') AND assigned_user_id = '::USER_ID::' AND emails.deleted = '0'"; + + /** + * Sole constructor + */ + function EmailUI() { + global $sugar_config; + global $current_user; + + $folderStateSerial = $current_user->getPreference('folderOpenState', 'Emails'); + + if(!empty($folderStateSerial)) { + $this->folderStates = unserialize($folderStateSerial); + } + + $this->smarty = new Sugar_Smarty(); + $this->folder = new SugarFolder(); + $this->userCacheDir = "{$sugar_config['cache_dir']}modules/Emails/{$current_user->id}"; + $this->db = DBManagerFactory::getInstance(); + } + + + /////////////////////////////////////////////////////////////////////////// + //// CORE + /** + * Renders the frame for emails + */ + function displayEmailFrame() { + + require_once("include/OutboundEmail/OutboundEmail.php"); + + global $app_strings, $app_list_strings; + global $mod_strings; + global $sugar_config; + global $current_user; + global $locale; + global $timedate; + global $theme; + global $sugar_version; + global $sugar_flavor; + global $current_language; + global $server_unique_key; + + $this->preflightUserCache(); + $ie = new InboundEmail(); + + // focus listView + $list = array( + 'mbox' => 'Home', + 'ieId' => '', + 'name' => 'Home', + 'unreadChecked' => 0, + 'out' => array(), + ); + + $this->_generateComposeConfigData('email_compose'); + + + //Check quick create module access + $QCAvailableModules = $this->_loadQuickCreateModules(); + + //Get the quickSearch js needed for assigned user id on Search Tab + require_once('include/QuickSearchDefaults.php'); + $qsd = new QuickSearchDefaults(); + $qsd->setFormName('advancedSearchForm'); + $quicksearchAssignedUser = "if(typeof sqs_objects == 'undefined'){var sqs_objects = new Array;}"; + $quicksearchAssignedUser .= "sqs_objects['advancedSearchForm_assigned_user_name']=" . json_encode($qsd->getQSUser()) . ";"; + $qsd->setFormName('Distribute'); + $quicksearchAssignedUser .= "sqs_objects['Distribute_assigned_user_name']=" . json_encode($qsd->getQSUser()) . ";"; + $this->smarty->assign('quickSearchForAssignedUser', $quicksearchAssignedUser); + + + /////////////////////////////////////////////////////////////////////// + //// BASIC ASSIGNS + $this->smarty->assign("currentUserId",$current_user->id); + $this->smarty->assign("CURRENT_USER_EMAIL",$current_user->email1); + $this->smarty->assign("currentUserName",$current_user->name); + $this->smarty->assign('yuiPath', 'modules/Emails/javascript/yui-ext/'); + $this->smarty->assign('app_strings', $app_strings); + $this->smarty->assign('mod_strings', $mod_strings); + $this->smarty->assign('theme', $theme); + $this->smarty->assign('sugar_config', $sugar_config); + $this->smarty->assign('is_admin', $current_user->is_admin); + $this->smarty->assign('sugar_version', $sugar_version); + $this->smarty->assign('sugar_flavor', $sugar_flavor); + $this->smarty->assign('current_language', $current_language); + $this->smarty->assign('server_unique_key', $server_unique_key); + $this->smarty->assign('qcModules', json_encode($QCAvailableModules)); + $extAllDebugValue = "ext-all.js"; + $this->smarty->assign('extFileName', $extAllDebugValue); + + // settings: general + $e2UserPreferences = $this->getUserPrefsJS(); + $emailSettings = $e2UserPreferences['emailSettings']; + + /////////////////////////////////////////////////////////////////////// + //// USER SETTINGS + // settings: accounts + + $cuDatePref = $current_user->getUserDateTimePreferences(); + $this->smarty->assign('dateFormat', $cuDatePref['date']); + $this->smarty->assign('dateFormatExample', str_replace(array("Y", "m", "d"), array("yyyy", "mm", "dd"), $cuDatePref['date'])); + $this->smarty->assign('calFormat', $timedate->get_cal_date_format()); + $this->smarty->assign('TIME_FORMAT', $timedate->get_user_time_format()); + + $ieAccounts = $ie->retrieveByGroupId($current_user->id); + $ieAccountsOptions = "\n"; + + foreach($ieAccounts as $k => $v) { + $disabled = (!$v->is_personal) ? "DISABLED" : ""; + $group = (!$v->is_personal) ? $app_strings['LBL_EMAIL_GROUP']."." : ""; + $ieAccountsOptions .= "\n"; + } + + $this->smarty->assign('ieAccounts', $ieAccountsOptions); + $this->smarty->assign('rollover', $this->rolloverStyle); + + $protocol = filterInboundEmailPopSelection($app_list_strings['dom_email_server_type']); + $this->smarty->assign('PROTOCOL', get_select_options_with_id($protocol, '')); + $this->smarty->assign('MAIL_SSL_OPTIONS', get_select_options_with_id($app_list_strings['email_settings_for_ssl'], '')); + $this->smarty->assign('ie_mod_strings', return_module_language($current_language, 'InboundEmail')); + + $charsetSelectedValue = isset($emailSettings['defaultOutboundCharset']) ? $emailSettings['defaultOutboundCharset'] : false; + if (!$charsetSelectedValue) { + $charsetSelectedValue = $current_user->getPreference('default_export_charset', 'global'); + if (!$charsetSelectedValue) { + $charsetSelectedValue = $locale->getPrecedentPreference('default_email_charset'); + } + } + $charset = array( + 'options' => $locale->getCharsetSelect(), + 'selected' => $charsetSelectedValue, + ); + $this->smarty->assign('charset', $charset); + + $emailCheckInterval = array('options' => $app_strings['LBL_EMAIL_CHECK_INTERVAL_DOM'], 'selected' => $emailSettings['emailCheckInterval']); + $this->smarty->assign('emailCheckInterval', $emailCheckInterval); + $this->smarty->assign('attachmentsSearchOptions', $app_list_strings['checkbox_dom']); + $this->smarty->assign('sendPlainTextChecked', ($emailSettings['sendPlainText'] == 1) ? 'CHECKED' : ''); + $this->smarty->assign('showNumInList', get_select_options_with_id($app_list_strings['email_settings_num_dom'], $emailSettings['showNumInList'])); + + //// END USER SETTINGS + /////////////////////////////////////////////////////////////////////// + + /////////////////////////////////////////////////////////////////////// + //// SIGNATURES + $prependSignature = ($current_user->getPreference('signature_prepend')) ? 'true' : 'false'; + $defsigID = $current_user->getPreference('signature_default'); + $this->smarty->assign('signatures', $current_user->getSignatures(false, $defsigID)); + $this->smarty->assign('signaturesSettings', $current_user->getSignatures(false, $defsigID, false)); + $signatureButtons = $current_user->getSignatureButtons('SUGAR.email2.settings.createSignature', !empty($defsigID)); + if (!empty($defsigID)) { + $signatureButtons = $signatureButtons . '  + '; + } else { + $signatureButtons = $signatureButtons . ''; + } + $this->smarty->assign('signatureButtons', $signatureButtons); + $this->smarty->assign('signaturePrepend', $prependSignature == 'true' ? 'CHECKED' : ''); + //// END SIGNATURES + /////////////////////////////////////////////////////////////////////// + + /////////////////////////////////////////////////////////////////////// + //// EMAIL TEMPLATES + $email_templates_arr = $this->getEmailTemplatesArray(); + natcasesort($email_templates_arr); + $this->smarty->assign('EMAIL_TEMPLATE_OPTIONS', get_select_options_with_id($email_templates_arr, '')); + //// END EMAIL TEMPLATES + /////////////////////////////////////////////////////////////////////// + + /////////////////////////////////////////////////////////////////////// + //// FOLDERS & TreeView + $this->smarty->assign('groupUserOptions', $ie->getGroupsWithSelectOptions(array('' => $app_strings['LBL_EMAIL_CREATE_NEW']))); + + $tree = $this->getMailboxNodes(); + + // preloaded folder + $preloadFolder = 'lazyLoadFolder = '; + $focusFolderSerial = $current_user->getPreference('focusFolder', 'Emails'); + if(!empty($focusFolderSerial)) { + $focusFolder = unserialize($focusFolderSerial); + //$focusFolder['ieId'], $focusFolder['folder'] + $preloadFolder .= json_encode($focusFolder).";"; + } else { + $preloadFolder .= "new Object();"; + } + //// END FOLDERS + /////////////////////////////////////////////////////////////////////// + + $out = ""; + $out .= $this->smarty->fetch("modules/Emails/templates/_baseEmail.tpl"); + $out .= $tree->generate_header(); + $out .= $tree->generateNodesNoInit(true, 'email2treeinit'); + $out .=<< + + var loader = new YAHOO.util.YUILoader({ + require : [ + "layout", "element", "tabview", "menu", + "cookie", "sugarwidgets" + ], + loadOptional: true, + skin: { base: 'blank', defaultSkin: '' }, + onSuccess: email2init, + allowRollup: true, + base: "include/javascript/yui/build/" + }); + loader.addModule({ + name :"sugarwidgets", + type : "js", + fullpath: "include/javascript/sugarwidgets/SugarYUIWidgets.js", + varName: "YAHOO.SUGAR", + requires: ["datatable", "dragdrop", "treeview", "tabview", "calendar"] + }); + loader.insert(); + + {$preloadFolder}; + + +eoq; + + + return $out; + } + + /** + * Generate the frame needed for the quick compose email UI. This frame is loaded dynamically + * by an ajax call. + * + * @return JSON An object containing html markup and js script variables. + */ + function displayQuickComposeEmailFrame() + { + $this->preflightUserCache(); + + $this->_generateComposeConfigData('email_compose_light'); + $javascriptOut = $this->smarty->fetch("modules/Emails/templates/_baseConfigData.tpl"); + + $divOut = $this->smarty->fetch("modules/Emails/templates/overlay.tpl"); + $divOut .= $this->smarty->fetch("modules/Emails/templates/addressSearchContent.tpl"); + + $outData = array('jsData' => $javascriptOut,'divData'=> $divOut); + $out = json_encode($outData); + return $out; + } + + /** + * Load the modules from the metadata file and include in a custom one if it exists + * + * @return array + */ + protected function _loadQuickCreateModules() + { + $QCAvailableModules = array(); + $QCModules = array(); + + include('modules/Emails/metadata/qcmodulesdefs.php'); + if (file_exists('custom/modules/Emails/metadata/qcmodulesdefs.php')) { + include('custom/modules/Emails/metadata/qcmodulesdefs.php'); + } + + foreach($QCModules as $module) { + $seed = SugarModule::get($module)->loadBean(); + if ( ( $seed instanceOf SugarBean ) && $seed->ACLAccess('edit') ) { + $QCAvailableModules[] = $module; + } + } + + return $QCAvailableModules; + } + + /** + * Given an email link url (eg. index.php?action=Compose&parent_type=Contacts...) break up the + * request components and create a compose package that can be used by the quick compose UI. The + * result is typically passed into the js call SUGAR.quickCompose.init which initalizes the quick compose + * UI. + * + * @param String $emailLinkUrl + * @return JSON Object containing the composePackage and full link url + */ + function generateComposePackageForQuickCreateFromComposeUrl($emailLinkUrl, $lazyLoad=false) + { + $composeData = explode("&",$emailLinkUrl); + $a_composeData = array(); + foreach ($composeData as $singleRequest) + { + $tmp = explode("=",$singleRequest); + $a_composeData[$tmp[0]] = urldecode($tmp[1]); + } + + return $this->generateComposePackageForQuickCreate($a_composeData,$emailLinkUrl, $lazyLoad); + } + /** + * Generate the composePackage for the quick compose email UI. The package contains + * key/value pairs generated by the Compose.php file which are then set into the + * quick compose email UI (eg. to addr, parent id, parent type, etc) + * + * @param Array $composeData Associative array read and processed by generateComposeDataPackage. + * @param String $fullLinkUrl A link that contains all pertinant information so the user can be + * directed to the full compose screen if needed + * @return JSON Object containg composePackage and fullLinkUrl + */ + function generateComposePackageForQuickCreate($composeData,$fullLinkUrl, $lazyLoad=false) + { + $_REQUEST['forQuickCreate'] = true; + + if(!$lazyLoad){ + require_once('modules/Emails/Compose.php'); + $composePackage = generateComposeDataPackage($composeData,FALSE); + }else{ + $composePackage = $composeData; + } + + //JSON object is passed into the function defined within the a href onclick event + //which is delimeted by '. Need to escape all single quotes, every other char is valid. + foreach ($composePackage as $key => $singleCompose) + { + if (is_string($singleCompose)) + $composePackage[$key] = str_replace("'","'",$singleCompose); + } + + $quickComposeOptions = array('fullComposeUrl' => $fullLinkUrl,'composePackage' => $composePackage); + $j_quickComposeOptions = json_encode($quickComposeOptions); + + return $j_quickComposeOptions; + } + + /** + * Generate the config data needed for the Full Compose UI and the Quick Compose UI. The set of config data + * returned is the minimum set needed by the quick compose UI. + * + * @param String $type Drives which tinyMCE options will be included. + */ + function _generateComposeConfigData($type = "email_compose_light" ) + { + global $app_list_strings,$current_user, $app_strings, $mod_strings,$current_language,$locale; + + //Link drop-downs + $parent_types = $app_list_strings['record_type_display']; + $disabled_parent_types = ACLController::disabledModuleList($parent_types, false, 'list'); + + foreach($disabled_parent_types as $disabled_parent_type) { + unset($parent_types[$disabled_parent_type]); + } + asort($parent_types); + $linkBeans = json_encode(get_select_options_with_id($parent_types, '')); + + //TinyMCE Config + require_once("include/SugarTinyMCE.php"); + $tiny = new SugarTinyMCE(); + $tinyConf = $tiny->getConfig($type); + + //Generate Language Packs + $lang = "var app_strings = new Object();\n"; + foreach($app_strings as $k => $v) { + if(strpos($k, 'LBL_EMAIL_') !== false) { + $lang .= "app_strings.{$k} = '{$v}';\n"; + } + } + //Get the email mod strings but don't use the global variable as this may be overridden by + //other modules when the quick create is rendered. + $email_mod_strings = return_module_language($current_language,'Emails'); + $modStrings = "var mod_strings = new Object();\n"; + foreach($email_mod_strings as $k => $v) { + $v = str_replace("'", "\'", $v); + $modStrings .= "mod_strings.{$k} = '{$v}';\n"; + } + $lang .= "\n\n{$modStrings}\n"; + + //Grab the Inboundemail language pack + $ieModStrings = "var ie_mod_strings = new Object();\n"; + $ie_mod_strings = return_module_language($current_language,'InboundEmail'); + foreach($ie_mod_strings as $k => $v) { + $v = str_replace("'", "\'", $v); + $ieModStrings .= "ie_mod_strings.{$k} = '{$v}';\n"; + } + $lang .= "\n\n{$ieModStrings}\n"; + + $this->smarty->assign('linkBeans', $linkBeans); + $this->smarty->assign('linkBeansOptions', $parent_types); + $this->smarty->assign('tinyMCE', $tinyConf); + $this->smarty->assign('lang', $lang); + $this->smarty->assign('app_strings', $app_strings); + $this->smarty->assign('mod_strings', $email_mod_strings); + $ie1 = new InboundEmail(); + + //Signatures + $defsigID = $current_user->getPreference('signature_default'); + $defaultSignature = $current_user->getDefaultSignature(); + $sigJson = !empty($defaultSignature) ? json_encode(array($defaultSignature['id'] => from_html($defaultSignature['signature_html']))) : "new Object()"; + $this->smarty->assign('defaultSignature', $sigJson); + $this->smarty->assign('signatureDefaultId', (isset($defaultSignature['id'])) ? $defaultSignature['id'] : ""); + //User Preferences + $this->smarty->assign('userPrefs', json_encode($this->getUserPrefsJS())); + + //Get the users default outbound id + $defaultOutID = $ie1->getUsersDefaultOutboundServerId($current_user); + $this->smarty->assign('defaultOutID', $defaultOutID); + + //Character Set + $charsets = json_encode($locale->getCharsetSelect()); + $this->smarty->assign('emailCharsets', $charsets); + + //Relateable List of People for address book search + //#20776 jchi + $peopleTables = array("users", + "contacts", + "leads", + "prospects", + "accounts"); + $filterPeopleTables = array(); + global $app_list_strings, $app_strings; + $filterPeopleTables['LBL_DROPDOWN_LIST_ALL'] = $app_strings['LBL_DROPDOWN_LIST_ALL']; + foreach($peopleTables as $table) { + $module = ucfirst($table); + $class = substr($module, 0, strlen($module) - 1); + require_once("modules/{$module}/{$class}.php"); + $person = new $class(); + + if (!$person->ACLAccess('list')) continue; + $filterPeopleTables[$person->table_name] = $app_list_strings['moduleList'][$person->module_dir]; + } + $this->smarty->assign('listOfPersons' , get_select_options_with_id($filterPeopleTables,'')); + + } + + + + //// END CORE + /////////////////////////////////////////////////////////////////////////// + + /////////////////////////////////////////////////////////////////////////// + //// ADDRESS BOOK + /** + * Retrieves all relationship metadata for a user's address book + * @return array + */ + function getContacts() { + global $current_user; + + $q = "SELECT * FROM address_book WHERE assigned_user_id = '{$current_user->id}' ORDER BY bean DESC"; + $r = $this->db->query($q); + + $ret = array(); + + while($a = $this->db->fetchByAssoc($r)) { + $ret[$a['bean_id']] = array( + 'id' => $a['bean_id'], + 'module' => $a['bean'], + ); + } + + return $ret; + } + + /** + * Saves changes to a user's address book + * @param array contacts + */ + function setContacts($contacts) { + global $current_user; + + $oldContacts = $this->getContacts(); + + foreach($contacts as $cid => $contact) { + if(!in_array($contact['id'], $oldContacts)) { + $q = "INSERT INTO address_book (assigned_user_id, bean, bean_id) VALUES ('{$current_user->id}', '{$contact['module']}', '{$contact['id']}')"; + $r = $this->db->query($q, true); + } + } + } + + /** + * Removes contacts from the user's address book + * @param array ids + */ + function removeContacts($ids) { + global $current_user; + + $concat = ""; + + foreach($ids as $id) { + if(!empty($concat)) + $concat .= ", "; + + $concat .= "'{$id}'"; + } + + $q = "DELETE FROM address_book WHERE assigned_user_id = '{$current_user->id}' AND bean_id IN ({$concat})"; + $r = $this->db->query($q); + } + + /** + * saves editted Contact info + * @param string $str JSON serialized object + */ + function saveContactEdit($str) { + + $json = getJSONobj(); + + $str = from_html($str); + $obj = $json->decode($str); + + $contact = new Contact(); + $contact->retrieve($obj['contact_id']); + $contact->first_name = $obj['contact_first_name']; + $contact->last_name = $obj['contact_last_name']; + $contact->save(); + + // handle email address changes + $addresses = array(); + + foreach($obj as $k => $req) { + if(strpos($k, 'emailAddress') !== false) { + $addresses[$k] = $req; + } + } + + // prefill some REQUEST vars for emailAddress save + $_REQUEST['emailAddressOptOutFlag'] = $obj['optOut']; + $_REQUEST['emailAddressInvalidFlag'] = $obj['invalid']; + $contact->emailAddress->save($obj['contact_id'], 'Contacts', $addresses, $obj['primary'], ''); + } + + /** + * Prepares the Edit Contact mini-form via template assignment + * @param string id ID of contact in question + * @param string module Module in focus + * @return array + */ + function getEditContact($id, $module) { + global $app_strings; + + + if(!class_exists("Contact")) { + + } + + $contact = new Contact(); + $contact->retrieve($_REQUEST['id']); + $ret = array(); + + if($contact->ACLAccess('edit')) { + $contactMeta = array(); + $contactMeta['id'] = $contact->id; + $contactMeta['module'] = $contact->module_dir; + $contactMeta['first_name'] = $contact->first_name; + $contactMeta['last_name'] = $contact->last_name; + + $this->smarty->assign("app_strings", $app_strings); + $this->smarty->assign("contact_strings", return_module_language($_SESSION['authenticated_user_language'], 'Contacts')); + $this->smarty->assign("contact", $contactMeta); + + $ea = new SugarEmailAddress(); + $newEmail = $ea->getEmailAddressWidgetEditView($id, $module, true); + $this->smarty->assign("emailWidget", $newEmail['html']); + + $ret['form'] = $this->smarty->fetch("modules/Emails/templates/editContact.tpl"); + $ret['prefillData'] = $newEmail['prefillData']; + } else { + $id = ""; + $ret['form'] = $app_strings['LBL_EMAIL_ERROR_NO_ACCESS']; + $ret['prefillData'] = '{}'; + } + + $ret['id'] = $id; + $ret['contactName'] = $contact->full_name; + + return $ret; + } + + + /** + * Retrieves a concatenated list of contacts, those with assigned_user_id = user's id and those in the address_book + * table + * @param array $contacts Array of contact types -> IDs + * @param object $user User in focus + * @return array + */ + function getUserContacts($contacts, $user=null) { + + global $current_user; + global $locale; + + if(empty($user)) { + $user = $current_user; + } + + $emailAddress = new SugarEmailAddress(); + $ret = array(); + + $union = ''; + + $modules = array(); + foreach($contacts as $contact) { + if(!isset($modules[$contact['module']])) { + $modules[$contact['module']] = array(); + } + $modules[$contact['module']][] = $contact; + } + + foreach($modules as $module => $contacts) { + if(!empty($union)) { + $union .= " UNION ALL "; + } + + $table = strtolower($module); + $idsSerial = ''; + + foreach($contacts as $contact) { + if(!empty($idsSerial)) { + $idsSerial .= ","; + } + $idsSerial .= "'{$contact['id']}'"; + } + + $union .= "(SELECT id, first_name, last_name, title, '{$module}' module FROM {$table} WHERE id IN({$idsSerial}) AND deleted = 0 )"; + } + if(!empty($union)) { + $union .= " ORDER BY last_name"; + } + + $r = $user->db->query($union); + + //_pp($union); + + while($a = $user->db->fetchByAssoc($r)) { + $c = array(); + + $c['name'] = $locale->getLocaleFormattedName($a['first_name'], "{$a['last_name']}", '', $a['title'], '', $user); + $c['id'] = $a['id']; + $c['module'] = $a['module']; + $c['email'] = $emailAddress->getAddressesByGUID($a['id'], $a['module']); + $ret[$a['id']] = $c; + } + + return $ret; + } + //// END ADDRESS BOOK + /////////////////////////////////////////////////////////////////////////// + + + /////////////////////////////////////////////////////////////////////////// + //// EMAIL 2.0 Preferences + function getUserPrefsJS() { + global $current_user; + global $locale; + + // sort order per mailbox view + $sortSerial = $current_user->getPreference('folderSortOrder', 'Emails'); + $sortArray = array(); + if(!empty($sortSerial)) { + $sortArray = unserialize($sortSerial); + } + + // treeview collapsed/open states + $folderStateSerial = $current_user->getPreference('folderOpenState', 'Emails'); + $folderStates = array(); + if(!empty($folderStateSerial)) { + $folderStates = unserialize($folderStateSerial); + } + + // subscribed accounts + $showFolders = unserialize(base64_decode($current_user->getPreference('showFolders', 'Emails'))); + + // general settings + $emailSettings = $current_user->getPreference('emailSettings', 'Emails'); + + if(empty($emailSettings)) { + $emailSettings = array(); + $emailSettings['emailCheckInterval'] = -1; + $emailSettings['autoImport'] = ''; + $emailSettings['alwaysSaveOutbound'] = '1'; + $emailSettings['sendPlainText'] = ''; + $emailSettings['defaultOutboundCharset'] = $GLOBALS['sugar_config']['default_email_charset']; + $emailSettings['showNumInList'] = 20; + } + + // focus folder + $focusFolder = $current_user->getPreference('focusFolder', 'Emails'); + $focusFolder = !empty($focusFolder) ? unserialize($focusFolder) : array(); + + // unread only flag + $showUnreadOnly = $current_user->getPreference('showUnreadOnly', 'Emails'); + + $listViewSort = array( + "sortBy" => 'date', + "sortDirection" => 'DESC', + ); + + // signature prefs + $signaturePrepend = $current_user->getPreference('signature_prepend') ? 'true' : 'false'; + $signatureDefault = $current_user->getPreference('signature_default'); + $signatures = array( + 'signature_prepend' => $signaturePrepend, + 'signature_default' => $signatureDefault + ); + + + // current_user + $user = array( + 'emailAddresses' => $current_user->emailAddress->getAddressesByGUID($current_user->id, 'Users'), + 'full_name' => from_html($current_user->full_name), + ); + + $userPreferences = array(); + $userPreferences['sort'] = $sortArray; + $userPreferences['folderStates'] = $folderStates; + $userPreferences['showFolders'] = $showFolders; + $userPreferences['emailSettings'] = $emailSettings; + $userPreferences['focusFolder'] = $focusFolder; + $userPreferences['showUnreadOnly'] = $showUnreadOnly; + $userPreferences['listViewSort'] = $listViewSort; + $userPreferences['signatures'] = $signatures; + $userPreferences['current_user'] = $user; + return $userPreferences; + } + + + + /////////////////////////////////////////////////////////////////////////// + //// FOLDER FUNCTIONS + + /** + * Creates a new Sugar folder + * @param string $nodeLabel New sugar folder name + * @param string $parentLabel Parent folder name + */ + function saveNewFolder($nodeLabel, $parentId, $isGroup=0) { + global $current_user; + + $this->folder->name = $nodeLabel; + $this->folder->is_group = $isGroup; + $this->folder->parent_folder = ($parentId == 'Home') ? "" : $parentId; + $this->folder->has_child = 0; + $this->folder->created_by = $current_user->id; + $this->folder->modified_by = $current_user->id; + $this->folder->date_modified = $this->folder->date_created = TimeDate::getInstance()->nowDb(); + + $this->folder->save(); + return array( + 'action' => 'newFolderSave', + 'id' => $this->folder->id, + 'name' => $this->folder->name, + 'is_group' => $this->folder->is_group, + 'is_dynamic' => $this->folder->is_dynamic + ); + } + + /** + * Saves user sort prefernces + */ + function saveListViewSortOrder($ieId, $focusFolder, $sortBy, $sortDir) { + global $current_user; + + $sortArray = array(); + + $sortSerial = $current_user->getPreference('folderSortOrder', 'Emails'); + if(!empty($sortSerial)) { + $sortArray = unserialize($sortSerial); + } + + $sortArray[$ieId][$focusFolder]['current']['sort'] = $sortBy; + $sortArray[$ieId][$focusFolder]['current']['direction'] = $sortDir; + $sortSerial = serialize($sortArray); + $current_user->setPreference('folderSortOrder', $sortSerial, '', 'Emails'); + } + + /** + * Stickies folder collapse/open state + */ + function saveFolderOpenState($focusFolder, $focusFolderOpen) { + global $current_user; + + $folderStateSerial = $current_user->getPreference('folderOpenState', 'Emails'); + $folderStates = array(); + + if(!empty($folderStateSerial)) { + $folderStates = unserialize($folderStateSerial); + } + + $folderStates[$focusFolder] = $focusFolderOpen; + $newFolderStateSerial = serialize($folderStates); + $current_user->setPreference('folderOpenState', $newFolderStateSerial, '', 'Emails'); + } + + /** + * saves a folder's view state + */ + function saveListView($ieId, $folder) { + global $current_user; + + $saveState = array(); + $saveState['ieId'] = $ieId; + $saveState['folder'] = $folder; + $saveStateSerial = serialize($saveState); + $current_user->setPreference('focusFolder', $saveStateSerial, '', 'Emails'); + } + + /** + * Generates cache folder structure + */ + function preflightEmailCache($cacheRoot) { + // base + if(!file_exists($cacheRoot)) + mkdir_recursive(clean_path($cacheRoot)); + + // folders + if(!file_exists($cacheRoot."/folders")) + mkdir_recursive(clean_path("{$cacheRoot}/folders")); + + // messages + if(!file_exists($cacheRoot."/messages")) + mkdir_recursive(clean_path("{$cacheRoot}/messages")); + + // attachments + if(!file_exists($cacheRoot."/attachments")) + mkdir_recursive(clean_path("{$cacheRoot}/attachments")); + } + + function deleteEmailCacheForFolders($cacheRoot) { + $filePath = $cacheRoot."/folders/folders.php"; + if (file_exists($filePath)) { + unlink($filePath); + } + } + /////////////////////////////////////////////////////////////////////////// + //// IMAP FUNCTIONS + /** + * Identifies subscribed mailboxes and empties the trash + * @param object $ie InboundEmail + */ + function emptyTrash(&$ie) { + global $current_user; + + $showFolders = unserialize(base64_decode($current_user->getPreference('showFolders', 'Emails'))); + + if(is_array($showFolders)) { + foreach($showFolders as $ieId) { + if(!empty($ieId)) { + $ie->retrieve($ieId); + $ie->emptyTrash(); + } + } + } + } + + /** + * returns an array of nodes that correspond to IMAP mailboxes. + * @param bool $forceRefresh + * @return object TreeView object + */ + function getMailboxNodes() { + global $sugar_config; + global $current_user; + global $app_strings; + + $tree = new Tree("frameFolders"); + $tree->tree_style= 'include/ytree/TreeView/css/check/tree.css'; + + $nodes = array(); + $ie = new InboundEmail(); + $refreshOffset = $this->cacheTimeouts['folders']; // 5 mins. this will be set via user prefs + + $rootNode = new ExtNode($app_strings['LBL_EMAIL_HOME_FOLDER'], $app_strings['LBL_EMAIL_HOME_FOLDER']); + $rootNode->dynamicloadfunction = ''; + $rootNode->expanded = true; + $rootNode->dynamic_load = true; + $showFolders = unserialize(base64_decode($current_user->getPreference('showFolders', 'Emails'))); + + if(empty($showFolders)) { + $showFolders = array(); + } + + // INBOX NODES + if($current_user->hasPersonalEmail()) { + $personals = $ie->retrieveByGroupId($current_user->id); + + foreach($personals as $k => $personalAccount) { + if(in_array($personalAccount->id, $showFolders)) { + // check for cache value + $cacheRoot = "{$sugar_config['cache_dir']}modules/Emails/{$personalAccount->id}"; + $this->preflightEmailCache($cacheRoot); + + if($this->validCacheFileExists($personalAccount->id, 'folders', "folders.php")) { + $mailboxes = $this->getMailBoxesFromCacheValue($personalAccount); + } else { + $mailboxes = $personalAccount->getMailboxes(); + } + + $acctNode = new ExtNode('Home::' . $personalAccount->name, $personalAccount->name); + $acctNode->dynamicloadfunction = ''; + $acctNode->expanded = false; + $acctNode->set_property('cls', 'ieFolder'); + $acctNode->set_property('ieId', $personalAccount->id); + $acctNode->set_property('protocol', $personalAccount->protocol); + + if(array_key_exists('Home::'.$personalAccount->name, $this->folderStates)) { + if($this->folderStates['Home::'.$personalAccount->name] == 'open') { + $acctNode->expanded = true; + } + } + $acctNode->dynamic_load = true; + + $nodePath = $acctNode->_properties['id']; + + foreach($mailboxes as $k => $mbox) { + $acctNode->add_node($this->buildTreeNode($k, $k, $mbox, $personalAccount->id, + $nodePath, false, $personalAccount)); + } + + $rootNode->add_node($acctNode); + } + } + } + + // GROUP INBOX NODES + $beans = $ie->retrieveAllByGroupId($current_user->id, false); + foreach($beans as $k => $groupAccount) { + if(in_array($groupAccount->id, $showFolders)) { + // check for cache value + $cacheRoot = "{$sugar_config['cache_dir']}modules/Emails/{$groupAccount->id}"; + $this->preflightEmailCache($cacheRoot); + //$groupAccount->connectMailserver(); + + if($this->validCacheFileExists($groupAccount->id, 'folders', "folders.php")) { + $mailboxes = $this->getMailBoxesFromCacheValue($groupAccount); + } else { + $mailboxes = $groupAccount->getMailBoxesForGroupAccount(); + } + + $acctNode = new ExtNode($groupAccount->name, "group.{$groupAccount->name}"); + $acctNode->dynamicloadfunction = ''; + $acctNode->expanded = false; + $acctNode->set_property('isGroup', 'true'); + $acctNode->set_property('ieId', $groupAccount->id); + $acctNode->set_property('protocol', $groupAccount->protocol); + + if(array_key_exists('Home::'.$groupAccount->name, $this->folderStates)) { + if($this->folderStates['Home::'.$groupAccount->name] == 'open') { + $acctNode->expanded = true; + } + } + $acctNode->dynamic_load = true; + $nodePath = $rootNode->_properties['id']."::".$acctNode->_properties['id']; + + foreach($mailboxes as $k => $mbox) { + $acctNode->add_node($this->buildTreeNode($k, $k, $mbox, $groupAccount->id, + $nodePath, true, $groupAccount)); + } + + $rootNode->add_node($acctNode); + } + } + + // SugarFolder nodes + /* SugarFolders are built at onload when the UI renders */ + + $tree->add_node($rootNode); + return $tree; + } + + function getMailBoxesFromCacheValue($mailAccount) { + $foldersCache = $this->getCacheValue($mailAccount->id, 'folders', "folders.php", 'foldersCache'); + $mailboxes = $foldersCache['mailboxes']; + $mailboxesArray = $mailAccount->generateFlatArrayFromMultiDimArray($mailboxes, $mailAccount->retrieveDelimiter()); + $mailAccount->saveMailBoxFolders($mailboxesArray); + $this->deleteEmailCacheForFolders($cacheRoot); + return $mailboxes; + } // fn + + /** + * Builds up a TreeView Node object + * @param mixed + * @param mixed + * @param string + * @param string ID of InboundEmail instance + * @param string nodePath Serialized path from root node to current node + * @param bool isGroup + * @param bool forceRefresh + * @return mixed + */ + function buildTreeNode($key, $label, $mbox, $ieId, $nodePath, $isGroup, $ie) { + global $sugar_config; + + // get unread counts + $exMbox = explode("::", $nodePath); + $unseen = 0; + $GLOBALS['log']->debug("$key --- $nodePath::$label"); + + if(count($exMbox) >= 2) { + $mailbox = ""; + for($i=2; $igetUnreadCount($ie, $mailbox); + + if($unseen > 0) { + //$label = " {$label} ({$unseen})"; + } + } + + $nodePath = $nodePath."::".$label; + $node = new ExtNode($nodePath, $label); + $node->dynamicloadfunction = ''; + $node->expanded = false; + $node->set_property('labelStyle', "remoteFolder"); + + + if(array_key_exists($nodePath, $this->folderStates)) { + if($this->folderStates[$nodePath] == 'open') { + $node->expanded = true; + } + } + + $group = ($isGroup) ? 'true' : 'false'; + $node->dynamic_load = true; + //$node->set_property('href', " SUGAR.email2.listView.populateListFrame(YAHOO.namespace('frameFolders').selectednode, '{$ieId}', 'false');"); + $node->set_property('isGroup', $group); + $node->set_property('isDynamic', 'false'); + $node->set_property('ieId', $ieId); + $node->set_property('mbox', $key); + $node->set_property('unseen', $unseen); + $node->set_property('cls', 'ieFolder'); + + if(is_array($mbox)) { + foreach($mbox as $k => $v) { + $node->add_node($this->buildTreeNode("$key.$k", $k, $v, $ieId, $nodePath, $isGroup, $ie)); + } + } + + return $node; + } + + /** + * Totals the unread emails + */ + function getUnreadCount(&$ie, $mailbox) { + global $sugar_config; + $unseen = 0; + + // use cache + return $ie->getCacheUnreadCount($mailbox); + } + + /////////////////////////////////////////////////////////////////////////// + //// DISPLAY CODE + /** + * Used exclusively by draft code. Returns Notes and Documents as attachments. + * @param array $ret + * @return array + */ + function getDraftAttachments($ret) { + global $db; + + // $ret['uid'] is the draft Email object's GUID + $ret['attachments'] = array(); + + $q = "SELECT id, filename FROM notes WHERE parent_id = '{$ret['uid']}' AND deleted = 0"; + $r = $db->query($q); + + while($a = $db->fetchByAssoc($r)) { + $ret['attachments'][$a['id']] = array( + 'id' => $a['id'], + 'filename' => $a['filename'], + ); + } + + return $ret; + } + + function createCopyOfInboundAttachment($ie, $ret, $uid) { + global $sugar_config; + if ($ie->isPop3Protocol()) { + // get the UIDL from database; + $cachedUIDL = md5($uid); + $cache = "{$sugar_config['cache_dir']}modules/Emails/{$ie->id}/messages/{$ie->mailbox}{$cachedUIDL}.php"; + } else { + $cache = "{$sugar_config['cache_dir']}modules/Emails/{$ie->id}/messages/{$ie->mailbox}{$uid}.php"; + } + if(file_exists($cache)) { + include($cache); // profides $cacheFile + $metaOut = unserialize($cacheFile['out']); + $meta = $metaOut['meta']['email']; + if (isset($meta['attachments'])) { + $attachmentHtmlData = $meta['attachments']; + $actualAttachmentInfo = array(); + $this->parseAttachmentInfo($actualAttachmentInfo, $attachmentHtmlData); + if (sizeof($actualAttachmentInfo) > 0) { + foreach($actualAttachmentInfo as $key => $value) { + $attachmentid; + $fileName; + $datasplit = explode("&", $value); + $attachmentIdArray = explode("=", $datasplit[0]); + $attachmentid = $attachmentIdArray[1]; + + $fileNameArray = explode("=", $datasplit[4]); + $fileName = $fileNameArray[1]; + $guid = create_guid(); + //$destination = clean_path("{$this->userCacheDir}/{$guid}{$fileName}"); + $destination = clean_path("{$this->userCacheDir}/{$guid}"); + + $attachmentFilePath = "{$sugar_config['cache_dir']}modules/Emails/{$ie->id}/attachments/{$attachmentid}"; + copy($attachmentFilePath, $destination); + $ret['attachments'][$guid] = array(); + $ret['attachments'][$guid]['id'] = $guid . $fileName; + $ret['attachments'][$guid]['filename'] = $fileName; + } // for + } // if + } // if + + } // if + return $ret; + + } // fn + + function parseAttachmentInfo(&$actualAttachmentInfo, $attachmentHtmlData) { + $downLoadPHP = strpos($attachmentHtmlData, "index.php?entryPoint=download&"); + while ($downLoadPHP) { + $attachmentHtmlData = substr($attachmentHtmlData, $downLoadPHP+30); + $final = strpos($attachmentHtmlData, "\">"); + $actualAttachmentInfo[] = substr($attachmentHtmlData, 0, $final); + $attachmentHtmlData = substr($attachmentHtmlData, $final); + $downLoadPHP = strpos($attachmentHtmlData, "index.php?entryPoint=download&"); + } // while + } + /** + * Renders the QuickCreate form from Smarty and returns HTML + * @param array $vars request variable global + * @param object $email Fetched email object + * @param bool $addToAddressBook + * @return array + */ + function getQuickCreateForm($vars, $email, $addToAddressBookButton=false) { + require_once("include/EditView/EditView2.php"); + global $app_strings; + global $mod_strings; + global $current_user; + global $beanList; + global $beanFiles; + global $current_language; + + //Setup the current module languge + $mod_strings = return_module_language($current_language, $_REQUEST['qc_module']); + + $bean = $beanList[$_REQUEST['qc_module']]; + $class = $beanFiles[$bean]; + require_once($class); + + $focus = new $bean(); + + $people = array( + 'Contact' + ,'Lead' + ); + $emailAddress = array(); + + // people + if(in_array($bean, $people)) { + // lead specific + $focus->lead_source = 'Email'; + $focus->lead_source_description = trim($email->name); + + $from = (isset($email->from_name) && !empty($email->from_name)) ? $email->from_name : $email->from_addr; + + if(isset($_REQUEST['sugarEmail']) && !empty($_REQUEST['sugarEmail'])) + $from = (isset($email->from_name) && !empty($email->from_name)) ? $email->from_name : $email->from_addr_name; + + + $name = explode(" ", trim($from)); + + $address = trim(array_pop($name)); + $address = str_replace(array("<",">","<",">"), "", $address); + + $emailAddress[] = array( + 'email_address' => $address, + 'primary_address' => 1, + 'invalid_email' => 0, + 'opt_out' => 0, + 'reply_to_address' => 1 + ); + + $focus->email1 = $address; + + if(!empty($name)) { + $focus->last_name = trim(array_pop($name)); + + foreach($name as $first) { + if(!empty($focus->first_name)) { + $focus->first_name .= " "; + } + $focus->first_name .= trim($first); + } + } + } else { + // bugs, cases, tasks + $focus->name = trim($email->name); + } + + $focus->description = trim(strip_tags($email->description)); + $focus->assigned_user_id = $current_user->id; + + + $EditView = new EditView(); + $EditView->ss = new Sugar_Smarty(); + //MFH BUG#20283 - checks for custom quickcreate fields + $EditView->setup($_REQUEST['qc_module'], $focus, 'custom/modules/'.$focus->module_dir.'/metadata/editviewdefs.php', 'include/EditView/EditView.tpl'); + $EditView->process(); + $EditView->render(); + + $EditView->defs['templateMeta']['form']['buttons'] = array( + 'email2save' => array( + 'id' => 'e2AjaxSave', + 'customCode' => '' + ), + 'email2saveandreply' => array( + 'id' => 'e2SaveAndReply', + 'customCode' => '' + ), + 'email2cancel' => array( + 'id' => 'e2cancel', + 'customCode' => '' + ) + ); + + + if($addToAddressBookButton) { + $EditView->defs['templateMeta']['form']['buttons']['email2saveAddToAddressBook'] = array( + 'id' => 'e2addToAddressBook', + 'customCode' => '' + ); + } + + //Get the module language for javascript + if(!is_file($GLOBALS['sugar_config']['cache_dir'] . 'jsLanguage/' . $_REQUEST['qc_module'] . '/' . $GLOBALS['current_language'] . '.js')) { + require_once('include/language/jsLanguage.php'); + jsLanguage::createModuleStringsCache($_REQUEST['qc_module'], $GLOBALS['current_language']); + } + $jsLanguage = ''; + + + + $EditView->view = 'EmailQCView'; + $EditView->defs['templateMeta']['form']['headerTpl'] = 'include/EditView/header.tpl'; + $EditView->defs['templateMeta']['form']['footerTpl'] = 'include/EditView/footer.tpl'; + $meta = array(); + $meta['html'] = $jsLanguage . $EditView->display(false, true); + $meta['html'] = str_replace("src='include/SugarEmailAddress/SugarEmailAddress.js?s={$GLOBALS['js_version_key']}&c={$GLOBALS['sugar_config']['js_custom_version']}'", '', $meta['html']); + $meta['emailAddress'] = $emailAddress; + + $mod_strings = return_module_language($current_language, 'Emails'); + + return $meta; + } + + /** + * Renders the Import form from Smarty and returns HTML + * @param array $vars request variable global + * @param object $email Fetched email object + * @param bool $addToAddressBook + * @return array + */ + function getImportForm($vars, $email, $formName = 'ImportEditView') { + require_once("include/EditView/EditView2.php"); + require_once("include/TemplateHandler/TemplateHandler.php"); + require_once('include/QuickSearchDefaults.php'); + $qsd = new QuickSearchDefaults(); + $qsd->setFormName($formName); + + global $app_strings; + global $current_user; + global $app_list_strings; + $sqs_objects = array( + "{$formName}_parent_name" => $qsd->getQSParent(), + ); + $smarty = new Sugar_Smarty(); + $smarty->assign("APP",$app_strings); + $smarty->assign('formName',$formName); + $showAssignTo = false; + if (!isset($vars['showAssignTo']) || $vars['showAssignTo'] == true) { + $showAssignTo = true; + } // if + if ($showAssignTo) { + if(empty($email->assigned_user_id) && empty($email->id)) + $email->assigned_user_id = $current_user->id; + if(empty($email->assigned_name) && empty($email->id)) + $email->assigned_user_name = $current_user->user_name; + $sqs_objects["{$formName}_assigned_user_name"] = $qsd->getQSUser(); + } + $smarty->assign("showAssignedTo",$showAssignTo); + + $showDelete = false; + if (!isset($vars['showDelete']) || $vars['showDelete'] == true) { + $showDelete = true; + } + $smarty->assign("showDelete",$showDelete); + + $smarty->assign("userId",$email->assigned_user_id); + $smarty->assign("userName",$email->assigned_user_name); + $parent_types = $app_list_strings['record_type_display']; + $smarty->assign('parentOptions', get_select_options_with_id($parent_types, $email->parent_type)); + + $quicksearch_js = ''; + $smarty->assign('SQS', $quicksearch_js); + + $meta = array(); + $meta['html'] = $smarty->fetch("modules/Emails/templates/importRelate.tpl"); + return $meta; + } + + /** + * This function returns the detail view for email in new 2.0 interface + * + */ + function getDetailViewForEmail2($emailId) { + + require_once('include/DetailView/DetailView.php'); + global $app_strings, $app_list_strings; + global $mod_strings; + + $smarty = new Sugar_Smarty(); + + // SETTING DEFAULTS + $focus = new Email(); + $focus->retrieve($emailId); + $detailView->ss = new Sugar_Smarty(); + $detailView = new DetailView(); + $title = ""; + $offset = 0; + if($focus->type == 'out') { + $title = getClassicModuleTitle('Emails', array($mod_strings['LBL_SENT_MODULE_NAME'],$focus->name), true); + } elseif ($focus->type == 'draft') { + $title = getClassicModuleTitle('Emails', array($mod_strings['LBL_LIST_FORM_DRAFTS_TITLE'],$focus->name), true); + } elseif($focus->type == 'inbound') { + $title = getClassicModuleTitle('Emails', array($mod_strings['LBL_INBOUND_TITLE'],$focus->name), true); + } + $smarty->assign("emailTitle", $title); + + // DEFAULT TO TEXT IF NO HTML CONTENT: + $html = trim(from_html($focus->description_html)); + if(empty($html)) { + $smarty->assign('SHOW_PLAINTEXT', 'true'); + $description = nl2br($focus->description); + } else { + $smarty->assign('SHOW_PLAINTEXT', 'false'); + $description = from_html($focus->description_html); + } + + //if not empty or set to test (from test campaigns) + if (!empty($focus->parent_type) && $focus->parent_type !='test') { + $smarty->assign('PARENT_MODULE', $focus->parent_type); + $smarty->assign('PARENT_TYPE', $app_list_strings['record_type_display'][$focus->parent_type] . ":"); + } + + global $gridline; + $smarty->assign('MOD', $mod_strings); + $smarty->assign('APP', $app_strings); + $smarty->assign('GRIDLINE', $gridline); + $smarty->assign('PRINT_URL', 'index.php?'.$GLOBALS['request_string']); + $smarty->assign('ID', $focus->id); + $smarty->assign('TYPE', $focus->type); + $smarty->assign('PARENT_NAME', $focus->parent_name); + $smarty->assign('PARENT_ID', $focus->parent_id); + $smarty->assign('NAME', $focus->name); + $smarty->assign('ASSIGNED_TO', $focus->assigned_user_name); + $smarty->assign('DATE_MODIFIED', $focus->date_modified); + $smarty->assign('DATE_ENTERED', $focus->date_entered); + $smarty->assign('DATE_START', $focus->date_start); + $smarty->assign('TIME_START', $focus->time_start); + $smarty->assign('FROM', $focus->from_addr); + $smarty->assign('TO', nl2br($focus->to_addrs)); + $smarty->assign('CC', nl2br($focus->cc_addrs)); + $smarty->assign('BCC', nl2br($focus->bcc_addrs)); + $smarty->assign('CREATED_BY', $focus->created_by_name); + $smarty->assign('MODIFIED_BY', $focus->modified_by_name); + $smarty->assign('DESCRIPTION', nl2br($focus->description)); + $smarty->assign('DESCRIPTION_HTML', from_html($focus->description_html)); + $smarty->assign('DATE_SENT', $focus->date_entered); + $smarty->assign('EMAIL_NAME', 'RE: '.$focus->name); + $smarty->assign("TAG", $focus->listviewACLHelper()); + $smarty->assign("SUGAR_VERSION", $GLOBALS['sugar_version']); + $smarty->assign("JS_CUSTOM_VERSION", $GLOBALS['sugar_config']['js_custom_version']); + if(!empty($focus->reply_to_email)) { + $replyTo = " +
    ".$mod_strings['LBL_REPLY_TO_NAME']."".$focus->reply_to_addr."
    + {$app_strings['LBL_EMAIL_CC']}: + + {$ccs} +
    + {$app_strings['LBL_EMAIL_CC']}: + + {$ccs} +
    + +{PAGINATION} + + + + + + + + + + + + + + + + + + + + + +{PAGINATION} +
    {CHECKALL}{MOD.LBL_LIST_SUBJECT}{arrow_start}{name_arrow}{arrow_end}{MOD.LBL_LIST_CONTACT}{MOD.LBL_LIST_RELATED_TO}{MOD.LBL_LIST_CREATED}{arrow_start}{date_entered_arrow}{arrow_end}
    {PREROW} +   + <{TAG.MAIN} href="{URL_PREFIX}index.php?action=EditView&type=out&module=Emails&record={DRAFTEMAIL.ID}" >{DRAFTEMAIL.NAME}<{TAG.CONTACT} href="{URL_PREFIX}index.php?action=DetailView&module=Contacts&record={DRAFTEMAIL.CONTACT_ID}" >{DRAFTEMAIL.CONTACT_NAME}<{TAG.PARENT} href="{URL_PREFIX}index.php?action=DetailView&module={DRAFTEMAIL.PARENT_MODULE}&record={DRAFTEMAIL.PARENT_ID}" >{DRAFTEMAIL.PARENT_NAME}{DRAFTEMAIL.DATE_ENTERED}
    + diff --git a/modules/Emails/ListViewGroup.php b/modules/Emails/ListViewGroup.php new file mode 100644 index 00000000..0d119dc0 --- /dev/null +++ b/modules/Emails/ListViewGroup.php @@ -0,0 +1,264 @@ +user_preferences[$currentModule.'GroupQ']); + $storeQuery->loadQuery($currentModule.'Group'); + $storeQuery->populateRequest(); +} else { + //_pp($current_user->user_preferences[$currentModule.'GroupQ']); + //_pp('saving: '.$currentModule.'Group'); + $storeQuery->saveFromGet($currentModule.'Group'); +} + +if(isset($_REQUEST['query'])) { + // we have a query + if(isset($_REQUEST['email_type'])) $email_type = $_REQUEST['email_type']; + if(isset($_REQUEST['assigned_to'])) $assigned_to = $_REQUEST['assigned_to']; + if(isset($_REQUEST['status'])) $status = $_REQUEST['status']; + if(isset($_REQUEST['name'])) $name = $_REQUEST['name']; + if(isset($_REQUEST['contact_name'])) $contact_name = $_REQUEST['contact_name']; + + if(isset($email_type) && $email_type != "") $whereClauses['emails.type'] = "emails.type = '".$GLOBALS['db']->quote($email_type)."'"; + if(isset($assigned_to) && $assigned_to != "") $whereClauses['emails.assigned_user_id'] = "emails.assigned_user_id = '".$GLOBALS['db']->quote($assigned_to)."'"; + if(isset($status) && $status != "") $whereClauses['emails.status'] = "emails.status = '".$GLOBALS['db']->quote($status)."'"; + if(isset($name) && $name != "") $whereClauses['emails.name'] = "emails.name like '".$GLOBALS['db']->quote($name)."%'"; + if(isset($contact_name) && $contact_name != '') { + $contact_names = explode(" ", $contact_name); + foreach ($contact_names as $name) { + $whereClauses['contacts.name'] = "(contacts.first_name like '".$GLOBALS['db']->quote($name)."%' OR contacts.last_name like '".$GLOBALS['db']->quote($name)."%')"; + } + } + + $focus->custom_fields->setWhereClauses($whereClauses); + + $GLOBALS['log']->info("Here is the where clause for the list view: $where"); +} // end isset($_REQUEST['query']) + + + +//// OUTPUT GENERATION + +if (!isset($_REQUEST['search_form']) || $_REQUEST['search_form'] != 'false') { + // ASSIGNMENTS pre-processing + $email_type_sel = ''; + $assigned_to_sel = ''; + $status_sel = ''; + if(isset($_REQUEST['email_type'])) $email_type_sel = $_REQUEST['email_type']; + if(isset($_REQUEST['assigned_to'])) $assigned_to_sel = $_REQUEST['assigned_to']; + if(isset($_REQUEST['status'])) $status_sel = $_REQUEST['status']; + if(isset($_REQUEST['search'])) $search_adv = $_REQUEST['search']; + + // drop-downs values + $r = $focus->db->query("SELECT id, user_name FROM users WHERE deleted = 0 AND status = 'Active' OR users.is_group = 1 ORDER BY status"); + $users[] = ''; + while($a = $focus->db->fetchByAssoc($r)) { + $users[$a['id']] = $a['user_name']; + } + + $email_types[] = ''; + $email_types = array_merge($email_types, $app_list_strings['dom_email_types']); + $email_status[] = ''; + $email_status = array_merge($email_status, $app_list_strings['dom_email_status']); + $types = get_select_options_with_id($email_types, $email_type_sel); + $assigned_to = get_select_options_with_id($users, $assigned_to_sel); + $email_status = get_select_options_with_id($email_status, $status_sel); + + // ASSIGNMENTS AND OUTPUT + $search_form = new XTemplate ('modules/Emails/SearchFormGroupInbox.html'); + $search_form->assign('MOD', $mod_strings); + $search_form->assign('APP', $app_strings); + $search_form->assign('ADVANCED_SEARCH_PNG', SugarThemeRegistry::current()->getImage('advanced_search','alt="'.$app_strings['LNK_ADVANCED_SEARCH'].'" border="0"')); + $search_form->assign('BASIC_SEARCH_PNG', SugarThemeRegistry::current()->getImage('basic_search','alt="'.$app_strings['LNK_BASIC_SEARCH'].'" border="0"')); + $search_form->assign('TYPE_OPTIONS', $types); + $search_form->assign('ASSIGNED_TO_OPTIONS', $assigned_to); + $search_form->assign('STATUS_OPTIONS', $email_status); + $search_form->assign('ADV_URL', $_SERVER['REQUEST_URI']); + $search_form->assign('SEARCH_ADV', $search_adv); + $search_form->assign('SEARCH_ACTION', 'ListViewGroup'); + + if(isset($_REQUEST['name'])) $search_form->assign('NAME', $_REQUEST['name']); + if(isset($_REQUEST['contact_name'])) $search_form->assign('CONTACT_NAME', $_REQUEST['contact_name']); + if(isset($current_user_only)) $search_form->assign('CURRENT_USER_ONLY', "checked"); + + // adding custom fields: + $focus->custom_fields->populateXTPL($search_form, 'search' ); + + if(!empty($get['assigned_user_id'])) { + $search_form->assign('ASSIGNED_USER_ID', $get['assigned_user_id']); + } + $search_form->assign('JAVASCRIPT', $focus->u_get_clear_form_js()); +} +//// END SEARCH FORM FUNCTIONALITY +//// +/////////////////////////////////////////////////////////////////////////////// + + + +/////////////////////////////////////////////////////////////////////////////// +//// NAVIGATION HACK +$_SESSION['emailStartAction'] = ''; // empty this value to allow new writes +//// END NAVIGATION HACK +/////////////////////////////////////////////////////////////////////////////// + + + +/////////////////////////////////////////////////////////////////////////////// +//// +//// INBOX FUNCTIONALITY +// for Inbox +$r = $focus->db->query('SELECT count(id) AS c FROM users WHERE users.is_group = 1 AND deleted = 0'); +$a = $focus->db->fetchByAssoc($r); + +$or = 'emails.assigned_user_id IN (\'abc\''; // must have a dummy entry to force group inboxes to not show personal emails +if($a['c'] > 0) { + + $r = $focus->db->query('SELECT id FROM users WHERE users.is_group = 1 AND deleted = 0'); + while($a = $focus->db->fetchByAssoc($r)) { + $or .= ',\''.$a['id'].'\''; + } +} +$or .= ') '; +$whereClauses['emails.assigned_user_id'] = $or; +$whereClauses['emails.type'] = 'emails.type = \'inbound\''; + +$display_title = $mod_strings['LBL_LIST_TITLE_GROUP_INBOX']; +//// END INBOX FUNCTIONALITY +//// +/////////////////////////////////////////////////////////////////////////////// + + + +/////////////////////////////////////////////////////////////////////////////// +//// OUTPUT +/////////////////////////////////////////////////////////////////////////////// + +echo getClassicModuleTitle("Emails", array($mod_strings['LBL_MODULE_TITLE'].$display_title), true); +// admin-edit +if(is_admin($current_user) && $_REQUEST['module'] != 'DynamicLayout' && !empty($_SESSION['editinplace'])){ + $header_text = " ".SugarThemeRegistry::current()->getImage("EditLayout","border='0' alt='Edit Layout' align='bottom'").""; +} +// search form +echo get_form_header($mod_strings['LBL_SEARCH_FORM_TITLE']. $header_text, "", false); +// ADVANCED SEARCH +if(isset($_REQUEST['search']) && $_REQUEST['search'] == 'advanced') { + $search_form->parse('adv'); + $search_form->out('adv'); + +} else { + $search_form->parse('main'); + $search_form->out('main'); +} +echo $focus->rolloverStyle; // for email previews +if(!empty($_REQUEST['error'])) { + $error = $app_list_strings['dom_email_errors'][$_REQUEST['error']]; +} +//_pp($where); +if(!empty($assigned_to_sel)) { + $whereClauses['emails.assigned_user_id'] = 'emails.assigned_user_id = \''.$assigned_to_sel.'\''; +} + +//_pp($whereClauses); + +// CONSTRUCT WHERE STRING FROM WHERECLAUSE ARRAY +foreach($whereClauses as $clause) { + if($where != '') { + $where .= ' AND '; + } + $where .= $clause; +} +//echo $focus->quickCreateJS(); + +$ListView = new ListView(); +// group distributionforms +echo $focus->distributionForm($where); + +$ListView->shouldProcess = true; +$ListView->show_mass_update = true; +$ListView->show_mass_update_form = false; +$ListView->initNewXTemplate( 'modules/Emails/ListViewGroupInbox.html',$mod_strings); +$ListView->xTemplateAssign('ATTACHMENT_HEADER', SugarThemeRegistry::current()->getImage('attachment',"","","")); +$ListView->xTemplateAssign('ERROR', $error); +$ListView->xTemplateAssign('CHECK_MAIL',$focus->checkInbox('group')); +$ListView->setHeaderTitle($display_title . $header_text ); +$ListView->setQuery($where, '', 'date_sent, date_entered DESC', 'EMAIL'); +$ListView->setAdditionalDetails(); +$ListView->processListView($focus, 'main', 'EMAIL'); + +?> diff --git a/modules/Emails/ListViewGroupInbox.html b/modules/Emails/ListViewGroupInbox.html new file mode 100644 index 00000000..ef130d51 --- /dev/null +++ b/modules/Emails/ListViewGroupInbox.html @@ -0,0 +1,83 @@ + + + + +{CHECK_MAIL} + + +{ERROR} + + +{PAGINATION} + + + + + + + + + + + + + + + + + + + + + + + + + + + + +{PAGINATION} +
    {CHECKALL}{ATTACHMENT_HEADER}{MOD.LBL_LIST_SUBJECT}{arrow_start}{name_arrow}{arrow_end}{MOD.LBL_LIST_CONTACT}{MOD.LBL_LIST_RELATED_TO}{MOD.LBL_QUICK_REPLY}{MOD.LBL_LIST_ASSIGNED}{arrow_start}{assigned_user_name_arrow}{arrow_end}{MOD.LBL_LIST_DATE_SENT}{arrow_start}{date_sent_arrow}{arrow_end}
    {PREROW}{EMAIL.ATTACHMENT_IMAGE} +   + <{TAG.MAIN} href="{URL_PREFIX}index.php?action={EMAIL.LINK_ACTION}&module=Emails&record={EMAIL.ID}&offset={EMAIL.OFFSET}&stamp={EMAIL.STAMP}" >{EMAIL.NAME}<{TAG.CONTACT} href="{URL_PREFIX}index.php?action=DetailView&module=Contacts&record={EMAIL.CONTACT_ID}" >{EMAIL.CONTACT_NAME}{EMAIL.CREATE_RELATED}<{TAG.PARENT} href="{URL_PREFIX}index.php?action=DetailView&module={EMAIL.PARENT_MODULE}&record={EMAIL.PARENT_ID}" >{EMAIL.PARENT_NAME}{EMAIL.QUICK_REPLY}{EMAIL.ASSIGNED_USER_NAME}{EMAIL.DATE_SENT}
    + \ No newline at end of file diff --git a/modules/Emails/ListViewHome.html b/modules/Emails/ListViewHome.html new file mode 100644 index 00000000..2e02e112 --- /dev/null +++ b/modules/Emails/ListViewHome.html @@ -0,0 +1,68 @@ + + + + + + +{PAGINATION} + + + + + + + + + + + + + + + + + + +
    {MOD.LBL_LIST_SUBJECT}{arrow_start}{name_arrow}{arrow_end}{MOD.LBL_LIST_CONTACT}{MOD.LBL_LIST_RELATED_TO}{MOD.LBL_QUICK_REPLY}
    +   + <{TAG.MAIN} href="{URL_PREFIX}index.php?action={EMAIL.LINK_ACTION}&module=Emails&record={EMAIL.ID}&offset={EMAIL.OFFSET}&stamp={EMAIL.STAMP}" >{EMAIL.NAME}<{TAG.CONTACT} href="{URL_PREFIX}index.php?action=DetailView&module=Contacts&record={EMAIL.CONTACT_ID}" >{EMAIL.CONTACT_NAME}{EMAIL.CREATE_RELATED}<{TAG.PARENT} href="{URL_PREFIX}index.php?action=DetailView&module={EMAIL.PARENT_MODULE}&record={EMAIL.PARENT_ID}" >{EMAIL.PARENT_NAME}{EMAIL.QUICK_REPLY}
    + \ No newline at end of file diff --git a/modules/Emails/ListViewHome.php b/modules/Emails/ListViewHome.php new file mode 100644 index 00000000..b703ff13 --- /dev/null +++ b/modules/Emails/ListViewHome.php @@ -0,0 +1,77 @@ +id.'\' AND emails.type = \'inbound\' AND emails.status = \'unread\''; +$limit = 10; +/////////////////////////////////////////////////////////////////////////////// +//// OUTPUT +/////////////////////////////////////////////////////////////////////////////// +echo $focus->rolloverStyle; +$ListView->initNewXTemplate('modules/Emails/ListViewHome.html',$current_mod_strings); +$ListView->xTemplateAssign('ATTACHMENT_HEADER', SugarThemeRegistry::current()->getImage('attachment',"","","")); +$ListView->setHeaderTitle($display_title); +$ListView->setQuery($where, '', 'date_sent, date_entered DESC', "EMAIL"); +$ListView->setAdditionalDetails(); +$ListView->processListView($focus, 'main', 'EMAIL'); + +//echo $focus->quickCreateJS(); + +$sugar_config['list_max_entries_per_page'] = $currentMax; +?> \ No newline at end of file diff --git a/modules/Emails/ListViewMyInbox.html b/modules/Emails/ListViewMyInbox.html new file mode 100644 index 00000000..3e0ca148 --- /dev/null +++ b/modules/Emails/ListViewMyInbox.html @@ -0,0 +1,81 @@ + + + + +{TAKE} {CHECK_MAIL} +{TAKE_ERROR} + + +{PAGINATION} + + + + + + + + + + + + + + + + + + + + + + + + + + + + +{PAGINATION} +
    {CHECKALL}{ATTACHMENT_HEADER}{MOD.LBL_LIST_SUBJECT}{arrow_start}{name_arrow}{arrow_end}{MOD.LBL_LIST_CONTACT}{MOD.LBL_LIST_RELATED_TO}{MOD.LBL_QUICK_REPLY}{MOD.LBL_LIST_STATUS}{arrow_start}{status_arrow}{arrow_end}{MOD.LBL_LIST_DATE_SENT}{arrow_start}{date_sent_arrow}{arrow_end}
    {PREROW}{EMAIL.ATTACHMENT_IMAGE} +   + <{TAG.MAIN} href="{URL_PREFIX}index.php?action={EMAIL.LINK_ACTION}&module=Emails&record={EMAIL.ID}&offset={EMAIL.OFFSET}&stamp={EMAIL.STAMP}" >{EMAIL.NAME}<{TAG.CONTACT} href="{URL_PREFIX}index.php?action=DetailView&module=Contacts&record={EMAIL.CONTACT_ID}" >{EMAIL.CONTACT_NAME}{EMAIL.CREATE_RELATED}<{TAG.PARENT} href="{URL_PREFIX}index.php?action=DetailView&module={EMAIL.PARENT_MODULE}&record={EMAIL.PARENT_ID}" >{EMAIL.PARENT_NAME}{EMAIL.QUICK_REPLY}{EMAIL.STATUS}{EMAIL.DATE_SENT}
    + \ No newline at end of file diff --git a/modules/Emails/ListViewSent.html b/modules/Emails/ListViewSent.html new file mode 100644 index 00000000..15d4eecc --- /dev/null +++ b/modules/Emails/ListViewSent.html @@ -0,0 +1,70 @@ + + + + + + +{PAGINATION} + + + + + + + + + + + + + + + + + + + + + +{PAGINATION} +
    {CHECKALL}{MOD.LBL_LIST_TO_ADDR}{arrow_start}{to_addr_arrow}{arrow_end}{MOD.LBL_LIST_SUBJECT}{arrow_start}{name_arrow}{arrow_end}{MOD.LBL_LIST_RELATED_TO}{MOD.LBL_LIST_DATE}{arrow_start}{date_sent_arrow}{arrow_end}
    {PREROW}{SENTEMAIL.TO_ADDRS}<{TAG.MAIN} href="{URL_PREFIX}index.php?action=DetailViewSent&module=Emails&record={SENTEMAIL.ID}" >{SENTEMAIL.NAME}<{TAG.PARENT} href="{URL_PREFIX}index.php?action=DetailView&module={SENTEMAIL.PARENT_MODULE}&record={SENTEMAIL.PARENT_ID}" >{SENTEMAIL.PARENT_NAME}{SENTEMAIL.DATE_SENT}
    + diff --git a/modules/Emails/MassDelete.php b/modules/Emails/MassDelete.php new file mode 100644 index 00000000..4775a212 --- /dev/null +++ b/modules/Emails/MassDelete.php @@ -0,0 +1,61 @@ + $emailId) { + if($emailId != "undefined") { + $focus->mark_deleted($emailId); + } + } + + header('Location: index.php?module=Emails&action=ListViewGroup'); +} else { + global $mod_strings; + // error + $error = $mod_strings['LBL_MASS_DELETE_ERROR']; + header('Location: index.php?module=Emails&action=ListViewGroup&error='.$error); +} + +?> diff --git a/modules/Emails/Menu.php b/modules/Emails/Menu.php new file mode 100644 index 00000000..e3ccf055 --- /dev/null +++ b/modules/Emails/Menu.php @@ -0,0 +1,60 @@ +id; + +$e = new Email(); + +// my inbox +if(ACLController::checkAccess('Emails', 'edit', true)) { + $module_menu[] = array('index.php?module=Emails&action=index', $mod_strings['LNK_VIEW_MY_INBOX'],"EmailFolder","Emails"); +} +// create email template +if(ACLController::checkAccess('EmailTemplates', 'edit', true)) $module_menu[] = array("index.php?module=EmailTemplates&action=EditView&return_module=EmailTemplates&return_action=DetailView", $mod_strings['LNK_NEW_EMAIL_TEMPLATE'],"CreateEmails","Emails"); +// email templates +if(ACLController::checkAccess('EmailTemplates', 'list', true)) $module_menu[] = array("index.php?module=EmailTemplates&action=index", $mod_strings['LNK_EMAIL_TEMPLATE_LIST'],"EmailFolder", 'Emails'); +?> diff --git a/modules/Emails/PessimisticLock.php b/modules/Emails/PessimisticLock.php new file mode 100644 index 00000000..16b93798 --- /dev/null +++ b/modules/Emails/PessimisticLock.php @@ -0,0 +1,111 @@ +retrieve($_REQUEST['user']); + $userName = $locale->getLocaleFormattedName($user->first_name, $user->last_name); +} + + +// NEXT FREE +if(isset($_REQUEST['next_free']) && $_REQUEST['next_free'] == true) { + + $next = new Email(); + $rG = $next->db->query('SELECT count(id) AS c FROM users WHERE deleted = 0 AND users.is_group = 1'); + $aG = $next->db->fetchByAssoc($rG); + if($rG['c'] > 0) { + $rG = $next->db->query('SELECT id FROM users WHERE deleted = 0 AND users.is_group = 1'); + $aG = $next->db->fetchByAssoc($rG); + while($aG = $next->db->fetchByAssoc($rG)) { + $ids[] = $aG['id']; + } + $in = ' IN ('; + foreach($ids as $k => $id) { + $in .= '"'.$id.'", '; + } + $in = substr($in, 0, (strlen($in) - 2)); + $in .= ') '; + + $team = ''; + + $qE = 'SELECT count(id) AS c FROM emails WHERE deleted = 0 AND assigned_user_id'.$in.$team.'LIMIT 1'; + $rE = $next->db->query($qE); + $aE = $next->db->fetchByAssoc($rE); + + if($aE['c'] > 0) { + $qE = 'SELECT id FROM emails WHERE deleted = 0 AND assigned_user_id'.$in.$team.'LIMIT 1'; + $rE = $next->db->query($qE); + $aE = $next->db->fetchByAssoc($rE); + $next->retrieve($aE['id']); + $next->assigned_user_id = $current_user->id; + $next->save(); + + header('Location: index.php?module=Emails&action=DetailView&record='.$next->id); + + } else { + // no free items + header('Location: index.php?module=Emails&action=ListView&type=inbound&group=true'); + } + } else { + // no groups + header('Location: index.php?module=Emails&action=ListView&type=inbound&group=true'); + } +} +?> + + + + + + + + +
    + +
    + +
    + + + +
    diff --git a/modules/Emails/Popup.php b/modules/Emails/Popup.php new file mode 100644 index 00000000..65fcd9fb --- /dev/null +++ b/modules/Emails/Popup.php @@ -0,0 +1,54 @@ +retrieve($_REQUEST['metadata']); + echo nl2br($email->safeText($email->raw_source)); +} else { + require_once('include/Popups/Popup_picker.php'); + $popup = new Popup_Picker(); + echo $popup->process_page(); +} + +?> \ No newline at end of file diff --git a/modules/Emails/PopupDocuments.html b/modules/Emails/PopupDocuments.html new file mode 100644 index 00000000..714b1d45 --- /dev/null +++ b/modules/Emails/PopupDocuments.html @@ -0,0 +1,111 @@ + + + + + + + + + + + + +
    + +
    + + + + + + + + + +{PAGINATION} + + + + + + + + + + + + + + + + +
    {MOD.LBL_LIST_DOCUMENT}{arrow_start}{name_arrow}{arrow_end}{MOD.LBL_LIST_REVISION}{MOD.LBL_LIST_STATUS}
    + {DOCUMENT.DOCUMENT_NAME} + {DOCUMENT.LATEST_REVISION}{DOCUMENT.STATUS_ID}
    \ No newline at end of file diff --git a/modules/Emails/PopupDocuments.php b/modules/Emails/PopupDocuments.php new file mode 100644 index 00000000..e46658b0 --- /dev/null +++ b/modules/Emails/PopupDocuments.php @@ -0,0 +1,154 @@ +_get_where_clause(); + +// We can't attach remote documents to emails because we can't necessarialy fetch a copy of them to include. +if ( ! empty($where) ) { + $where .= ' AND '; +} +$where .= "documents.doc_type IN ( '', 'Sugar')"; + +$name = empty($_REQUEST['name']) ? '' : $_REQUEST['name']; +$document_name = empty($_REQUEST['document_name']) ? '' : $_REQUEST['document_name']; +$category_id = empty($_REQUEST['category_id']) ? '' : $_REQUEST['category_id']; +$subcategory_id = empty($_REQUEST['subcategory_id']) ? '' : $_REQUEST['subcategory_id']; +$template_type = empty($_REQUEST['template_type']) ? '' : $_REQUEST['template_type']; +$is_template = empty($_REQUEST['is_template']) ? '' : $_REQUEST['is_template']; +$document_revision_id = empty($_REQUEST['document_revision_id']) ? '' : $_REQUEST['document_revision_id']; + +//$request_data = empty($_REQUEST['request_data']) ? '' : $_REQUEST['request_data']; + +$hide_clear_button = empty($_REQUEST['hide_clear_button']) ? false : true; +$button = "
    \n"; +if(!$hide_clear_button) +{ + $button .= "\n"; +} +$button .= "\n"; +$button .= "
    \n"; + +$form = new XTemplate('modules/Emails/PopupDocuments.html'); +$form->assign('MOD', $current_mod_strings); +$form->assign('APP', $app_strings); +$form->assign('THEME', $theme); +$form->assign('MODULE_NAME', $currentModule); +$form->assign('NAME', $name); +$form->assign('DOCUMENT_NAME', $document_name); +$form->assign('DOCUMENT_TARGET', $_REQUEST['target']); +$form->assign('DOCUMENT_REVISION_ID', $document_revision_id); + +//$form->assign('request_data', $request_data); +$form->assign("CATEGORY_OPTIONS", get_select_options_with_id($app_list_strings['document_category_dom'], $category_id)); +$form->assign("SUB_CATEGORY_OPTIONS", get_select_options_with_id($app_list_strings['document_subcategory_dom'], $subcategory_id)); +$form->assign("IS_TEMPLATE_OPTIONS", get_select_options_with_id($app_list_strings['checkbox_dom'], $is_template)); +$form->assign("TEMPLATE_TYPE_OPTIONS", get_select_options_with_id($app_list_strings['document_template_type_dom'], $template_type)); + + + +ob_start(); +insert_popup_header($theme); +$output_html .= ob_get_contents(); +ob_end_clean(); + +$output_html .= get_form_header($current_mod_strings['LBL_SEARCH_FORM_TITLE'], '', false); + +$form->parse('main.SearchHeader'); +$output_html .= $form->text('main.SearchHeader'); + +// Reset the sections that are already in the page so that they do not print again later. +$form->reset('main.SearchHeader'); + +// create the listview +$seed_bean = new Document(); +$ListView = new ListView(); +$ListView->show_export_button = false; +$ListView->process_for_popups = true; +$ListView->setXTemplate($form); +$ListView->setHeaderTitle($current_mod_strings['LBL_LIST_FORM_TITLE']); +$ListView->setHeaderText($button); +$ListView->setQuery($where, '', 'document_name', 'DOCUMENT'); +$ListView->setModStrings($current_mod_strings); + +ob_start(); +$ListView->processListView($seed_bean, 'main', 'DOCUMENT'); +$output_html .= ob_get_contents(); +ob_end_clean(); + +$output_html .= insert_popup_footer(); + + +echo $output_html; + + + + + + + + + + +?> \ No newline at end of file diff --git a/modules/Emails/Popup_picker.html b/modules/Emails/Popup_picker.html new file mode 100644 index 00000000..f384a920 --- /dev/null +++ b/modules/Emails/Popup_picker.html @@ -0,0 +1,129 @@ + + + + + + + + + + + + +
    + +
    + + + + + {PAGINATION} + + + + + + + + + + + + + + + + + + +
    + {CHECKALL} + + + {MOD.LBL_LIST_SUBJECT}{arrow_start}{number_arrow}{arrow_end} + + + {MOD.LBL_LIST_CONTACT_NAME}{arrow_start}{last_name_arrow}{arrow_end} + + + {MOD.LBL_LIST_DATE_SENT}{arrow_start}{date_start_arrow}{arrow_end} +
    + {PREROW} + + + {EMAIL.NAME} + + {EMAIL.CONTACT_NAME} + + {EMAIL.DATE_SENT} +
    +
    +{ASSOCIATED_JAVASCRIPT_DATA} + diff --git a/modules/Emails/Popup_picker.php b/modules/Emails/Popup_picker.php new file mode 100644 index 00000000..d48bff0b --- /dev/null +++ b/modules/Emails/Popup_picker.php @@ -0,0 +1,151 @@ +_get_where_clause(); + + + + $name = empty($_REQUEST['name']) ? '' : $_REQUEST['name']; + $contact_name = empty($_REQUEST['contact_name']) ? '' : $_REQUEST['contact_name']; + $request_data = empty($_REQUEST['request_data']) ? '' : $_REQUEST['request_data']; + $hide_clear_button = empty($_REQUEST['hide_clear_button']) ? false : true; + + $button = "
    \n"; + + if(!$hide_clear_button) { + $button .= "\n"; + } + $button .= "\n"; + $button .= "
    \n"; + + $form = new XTemplate('modules/Emails/Popup_picker.html'); + $form->assign('MOD', $mod_strings); + $form->assign('APP', $app_strings); + $form->assign('THEME', $theme); + $form->assign('MODULE_NAME', $currentModule); + $form->assign('NAME', $name); + $form->assign('CONTACT_NAME', $contact_name); + $form->assign('request_data', $request_data); + + ob_start(); + insert_popup_header($theme); + $output_html .= ob_get_contents(); + ob_end_clean(); + + $output_html .= get_form_header($mod_strings['LBL_SEARCH_FORM_TITLE'], '', false); + + $form->parse('main.SearchHeader'); + $output_html .= $form->text('main.SearchHeader'); + + // Reset the sections that are already in the page so that they do not print again later. + $form->reset('main.SearchHeader'); + + // create the listview + $seed_bean = new Email(); + $ListView = new ListView(); + $ListView->show_export_button = false; + $ListView->process_for_popups = true; + $ListView->setXTemplate($form); + $ListView->setHeaderTitle($mod_strings['LBL_LIST_FORM_TITLE']); + $ListView->setHeaderText($button); + $ListView->setQuery($where, '', 'name', 'EMAIL'); + $ListView->setModStrings($mod_strings); + + ob_start(); + $ListView->processListView($seed_bean, 'main', 'EMAIL'); + $output_html .= ob_get_contents(); + ob_end_clean(); + + $output_html .= insert_popup_footer(); + return $output_html; + } +} // end of class Popup_Picker +?> \ No newline at end of file diff --git a/modules/Emails/Save.php b/modules/Emails/Save.php new file mode 100644 index 00000000..8a6f3c63 --- /dev/null +++ b/modules/Emails/Save.php @@ -0,0 +1,291 @@ +merge_time_meridiem($_POST[$prefix.'time_start'], $timedate->get_time_format(), $_POST[$prefix.'meridiem']); +} +//retrieve the record +if(isset($_POST['record']) && !empty($_POST['record'])) { + $focus->retrieve($_POST['record']); + +} +if(isset($_REQUEST['user_id'])) { + $focus->assigned_user_id = $_REQUEST['user_id']; +} +if(!$focus->ACLAccess('Save')){ + ACLController::displayNoAccess(true); + sugar_cleanup(true); +} +if(!empty($_POST['assigned_user_id']) && ($focus->assigned_user_id != $_POST['assigned_user_id']) && ($_POST['assigned_user_id'] != $current_user->id)) { + $check_notify = TRUE; +} +//populate the fields of this Email +$allfields = array_merge($focus->column_fields, $focus->additional_column_fields); +foreach($allfields as $field) { + if(isset($_POST[$field])) { + $value = $_POST[$field]; + $focus->$field = $value; + } +} + +$focus->description = $_REQUEST['description_html']; +$focus->description_html = $_REQUEST['description_html']; + +if (!isset($_REQUEST['to_addrs'])) { + $_REQUEST['to_addrs'] = ""; +} +if (!isset($_REQUEST['to_addrs_ids'])) { + $_REQUEST['to_addrs_ids'] = ""; +} +if (!isset($_REQUEST['to_addrs_names'])) { + $_REQUEST['to_addrs_names'] = ""; +} +if (!isset($_REQUEST['to_addrs_emails'])) { + $_REQUEST['to_addrs_emails'] = ""; +} + +//compare the 3 fields and return list of contact_ids to link: +$focus->to_addrs_arr = $focus->parse_addrs($_REQUEST['to_addrs'], $_REQUEST['to_addrs_ids'], $_REQUEST['to_addrs_names'], $_REQUEST['to_addrs_emails']); + +// make sure the cc_* and bcc_* fields are at least empty if not set +$fields_to_check = array( + 'cc_addrs', + 'cc_addrs_ids', + 'bcc_addrs', + 'bcc_addrs_ids', + 'cc_addrs_names', + 'cc_addrs_emails', + 'bcc_addrs_emails', +); +foreach ($fields_to_check as $field_to_check) { + if (!isset($_REQUEST[$field_to_check])) { + $_REQUEST[$field_to_check] = ''; + } +} + +$focus->cc_addrs_arr = $focus->parse_addrs($_REQUEST['cc_addrs'], $_REQUEST['cc_addrs_ids'], $_REQUEST['cc_addrs_names'], $_REQUEST['cc_addrs_emails']); +$focus->bcc_addrs_arr = $focus->parse_addrs($_REQUEST['bcc_addrs'], $_REQUEST['bcc_addrs_ids'], $_REQUEST['to_addrs_names'], $_REQUEST['bcc_addrs_emails']); + + +if(!empty($_REQUEST['type'])) { + $focus->type = $_REQUEST['type']; +} elseif(empty($focus->type)) { // cn: from drafts/quotes + $focus->type = 'archived'; +} + +/////////////////////////////////////////////////////////////////////////////// +//// TEMPLATE PARSING +// cn: bug 7244 - need to pass an empty bean to parse email templates +$object_arr = array(); +if(!empty($focus->parent_id)) { + $object_arr[$focus->parent_type] = $focus->parent_id; +} +if(isset($focus->to_addrs_arr[0]['contact_id'])) { + $object_arr['Contacts'] = $focus->to_addrs_arr[0]['contact_id']; +} +if(empty($object_arr)) { + $object_arr = array('Contacts' => '123'); +} + +// do not parse email templates if the email is being saved as draft.... +if($focus->type != 'draft' && count($object_arr) > 0) { + require_once($beanFiles['EmailTemplate']); + $focus->name = EmailTemplate::parse_template($focus->name, $object_arr); + $focus->description = EmailTemplate::parse_template($focus->description, $object_arr); + $focus->description_html = EmailTemplate::parse_template($focus->description_html, $object_arr); +} +//// END TEMPLATE PARSING +/////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +//// PREP FOR ATTACHMENTS +if(empty($focus->id)){ + $focus->id = create_guid(); + $focus->new_with_id = true; +} +/////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +//// ATTACHMENT HANDLING +$focus->handleAttachments(); +//// END ATTACHMENT HANDLING +/////////////////////////////////////////////////////////////////////////////// +$focus->status = 'draft'; +if($focus->type == 'archived' ) { + $focus->status= 'archived'; + $focus->date_start = $_REQUEST['date_start']; + $focus->time_start = $_REQUEST['time_start'] . $_REQUEST['meridiem']; +} elseif(($focus->type == 'out' || $focus->type == 'forward') && isset($_REQUEST['send']) && $_REQUEST['send'] == '1') { + /////////////////////////////////////////////////////////////////////////// + //// REPLY PROCESSING + $old = array('<','>'); + $new = array('<','>'); + + if($_REQUEST['from_addr'] != $_REQUEST['from_addr_name'].' <'.$_REQUEST['from_addr_email'].'>') { + if(false === strpos($_REQUEST['from_addr'], '<')) { // we have an email only? + $focus->from_addr = $_REQUEST['from_addr']; + $focus->from_name = ''; + } else { // we have a compound string + $newFromAddr = str_replace($old, $new, $_REQUEST['from_addr']); + $focus->from_addr = substr($newFromAddr, (1 + strpos($newFromAddr, '<')), (strpos($newFromAddr, '>') - strpos($newFromAddr, '<')) -1 ); + $focus->from_name = substr($newFromAddr, 0, (strpos($newFromAddr, '<') -1)); + } + } elseif(!empty($_REQUEST['from_addr_email']) && isset($_REQUEST['from_addr_email'])) { + $focus->from_addr = $_REQUEST['from_addr_email']; + $focus->from_name = $_REQUEST['from_addr_name']; + } else { + $focus->from_addr = $focus->getSystemDefaultEmail(); + } + //// REPLY PROCESSING + /////////////////////////////////////////////////////////////////////////// + if($focus->send()) { + $focus->status = 'sent'; + } else { + $focus->status = 'send_error'; + } +} +$focus->to_addrs = $_REQUEST['to_addrs']; +$focus->cc_addrs = $_REQUEST['cc_addrs']; +$focus->bcc_addrs = $_REQUEST['bcc_addrs']; +$focus->from_addr = $_REQUEST['from_addr']; + +// delete the existing relationship of all the email addresses with this email +$query = "update emails_email_addr_rel set deleted = 1 WHERE email_id = '{$focus->id}'"; +$focus->db->query($query); + +// delete al the relationship of this email with all the beans +//$query = "update emails_beans set deleted = 1, bean_id = '', bean_module = '' WHERE email_id = '{$focus->id}'"; +//$focus->db->query($query); + +if(isset($_REQUEST['object_type']) && !empty($_REQUEST['object_type']) && isset($_REQUEST['object_id']) && !empty($_REQUEST['object_id'])) { + //run linking code only if the object_id has not been linked as part of the contacts above and it is an OOB relationship + $GLOBALS['log']->debug("CESELY".$_REQUEST['object_type']); + if(!in_array($_REQUEST['object_id'],$exContactIds)){ + $rel = strtolower($_REQUEST['object_type']); + if ($focus->load_relationship($rel)) { + $focus->$rel->add($_REQUEST['object_id']); + $GLOBALS['log']->debug("CESELY LOADED".$_REQUEST['object_type']); + } + } +} +//// END RELATIONSHIP LINKING +/////////////////////////////////////////////////////////////////////////////// + +// If came from email archiving edit view, this would have been set from form input. +if (!isset($focus->date_start)) +{ + $timedate = TimeDate::getInstance(); + list($focus->date_start, $focus->time_start) = $timedate->split_date_time($timedate->now()); +} + +$focus->date_sent = ""; + +require_once('include/formbase.php'); +$focus = populateFromPost('', $focus); + +$focus->save(false); +//// END EMAIL SAVE/SEND SETUP +/////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +//// RELATIONSHIP LINKING +$focus->load_relationship('users'); +$focus->users->add($current_user->id); + +if(!empty($_REQUEST['to_addrs_ids'])) { + $focus->load_relationship('contacts'); + $exContactIds = explode(';', $_REQUEST['to_addrs_ids']); + foreach($exContactIds as $contactId) { + $contactId = trim($contactId); + $focus->contacts->add($contactId); + } +} + +/////////////////////////////////////////////////////////////////////////////// +//// PAGE REDIRECTION +/////////////////////////////////////////////////////////////////////////////// +$return_id = $focus->id; + +if(empty($_POST['return_module'])) { + $return_module = "Emails"; +} else { + $return_module = $_POST['return_module']; +} +if(empty($_POST['return_action'])) { + $return_action = "DetailView"; +} else { + $return_action = $_POST['return_action']; +} +$GLOBALS['log']->debug("Saved record with id of ".$return_id); + +if($focus->type == 'draft') { + if($return_module == 'Emails') { + header("Location: index.php?module=$return_module&action=ListViewDrafts"); + } else { + handleRedirect($return_id, 'Emails'); + } +} elseif($focus->type == 'out') { + if($return_module == 'Home') { + header('Location: index.php?module='.$return_module.'&action=index'); + } + if(!empty($_REQUEST['return_id'])) { + $return_id = $_REQUEST['return_id']; + } + header('Location: index.php?action='.$return_action.'&module='.$return_module.'&record='.$return_id.'&assigned_user_id='.$current_user->id.'&type=inbound'); +} elseif(isset($_POST['return_id']) && $_POST['return_id'] != "") { + $return_id = $_POST['return_id']; +} + header("Location: index.php?action=$return_action&module=$return_module&record=$return_id"); +?> diff --git a/modules/Emails/SearchForm.html b/modules/Emails/SearchForm.html new file mode 100644 index 00000000..6be80a9f --- /dev/null +++ b/modules/Emails/SearchForm.html @@ -0,0 +1,117 @@ + + + +{JAVASCRIPT} + + + + + + +{JAVASCRIPT} + \ No newline at end of file diff --git a/modules/Emails/SearchFormGroupInbox.html b/modules/Emails/SearchFormGroupInbox.html new file mode 100644 index 00000000..51755743 --- /dev/null +++ b/modules/Emails/SearchFormGroupInbox.html @@ -0,0 +1,73 @@ + + + + + + +
    +
    + + + + + + + + + + + + + + + + + + +
    {MOD.LBL_STATUS}  {MOD.LBL_SUBJECT}  {MOD.LBL_CONTACT_NAME}  {MOD.LBL_ASSIGNED_TO}   + + +
    +
    +
    +{JAVASCRIPT} + \ No newline at end of file diff --git a/modules/Emails/SearchFormMyInbox.html b/modules/Emails/SearchFormMyInbox.html new file mode 100644 index 00000000..30643d5a --- /dev/null +++ b/modules/Emails/SearchFormMyInbox.html @@ -0,0 +1,71 @@ + + + + + + +
    +
    + + + + + + + + + + + + + + + + +
    {MOD.LBL_STATUS}  {MOD.LBL_SUBJECT}  {MOD.LBL_CONTACT_NAME}   + + +
    +
    +
    +{JAVASCRIPT} + \ No newline at end of file diff --git a/modules/Emails/SearchFormSent.html b/modules/Emails/SearchFormSent.html new file mode 100644 index 00000000..22e29747 --- /dev/null +++ b/modules/Emails/SearchFormSent.html @@ -0,0 +1,70 @@ + + + + + + + +
    +
    + + + + + + + + + + + + + + +
    {MOD.LBL_SUBJECT}  {MOD.LBL_CONTACT_NAME}   + + +
    +
    +
    +{JAVASCRIPT} + \ No newline at end of file diff --git a/modules/Emails/Status.html b/modules/Emails/Status.html new file mode 100644 index 00000000..c3438a4e --- /dev/null +++ b/modules/Emails/Status.html @@ -0,0 +1,43 @@ + + +{STATUS} + diff --git a/modules/Emails/Status.php b/modules/Emails/Status.php new file mode 100644 index 00000000..d20a3423 --- /dev/null +++ b/modules/Emails/Status.php @@ -0,0 +1,112 @@ +retrieve($_REQUEST['record']); + if($result == null) + { + sugar_die($app_strings['ERROR_NO_RECORD']); + } +} +else { + header("Location: index.php?module=Emails&action=index"); +} + +//needed when creating a new email with default values passed in +if (isset($_REQUEST['contact_name']) && is_null($focus->contact_name)) { + $focus->contact_name = $_REQUEST['contact_name']; +} +if (isset($_REQUEST['contact_id']) && is_null($focus->contact_id)) { + $focus->contact_id = $_REQUEST['contact_id']; +} +echo getClassicModuleTitle($mod_strings['LBL_SEND'], array($mod_strings['LBL_SEND']), true); + +$GLOBALS['log']->info("Email detail view"); + +$xtpl=new XTemplate ('modules/Emails/Status.html'); +$xtpl->assign("MOD", $mod_strings); +$xtpl->assign("APP", $app_strings); + +$xtpl->assign("GRIDLINE", $gridline); +$xtpl->assign("PRINT_URL", "index.php?".$GLOBALS['request_string']); +$xtpl->assign("ID", $focus->id); +$xtpl->assign("PARENT_NAME", $focus->parent_name); +if (isset($focus->parent_type)) +{ + $xtpl->assign("PARENT_MODULE", $focus->parent_type); + $xtpl->assign("PARENT_TYPE", $app_list_strings['record_type_display'][$focus->parent_type]); +} +$xtpl->assign("PARENT_ID", $focus->parent_id); +$xtpl->assign("NAME", $focus->name); +//$xtpl->assign("SENT_BY_USER_NAME", $focus->sent_by_user_name); +$xtpl->assign("DATE_SENT", $focus->date_start." ".$focus->time_start); +if ($focus->status == 'sent') +{ +$xtpl->assign("STATUS", $mod_strings['LBL_MESSAGE_SENT']); +} +else +{ +$xtpl->assign("STATUS", "".$mod_strings['LBL_ERROR_SENDING_EMAIL'].""); +} + +global $current_user; +if(is_admin($current_user) && $_REQUEST['module'] != 'DynamicLayout' && !empty($_SESSION['editinplace'])){ + + $xtpl->assign("ADMIN_EDIT","".SugarThemeRegistry::current()->getImage("EditLayout","border='0' alt='Edit Layout' align='bottom'").""); +} + +// adding custom fields: +require_once('modules/DynamicFields/templates/Files/DetailView.php'); + +$xtpl->parse("main"); +$xtpl->out("main"); + +?> diff --git a/modules/Emails/SubPanelViewRecipients.html b/modules/Emails/SubPanelViewRecipients.html new file mode 100644 index 00000000..bf18e6b5 --- /dev/null +++ b/modules/Emails/SubPanelViewRecipients.html @@ -0,0 +1,94 @@ + + +

    {APP.LBL_USER_LIST}

    + + + + + + + + + + + + + + + + + + + + + + + +
    {APP.LBL_LIST_NAME}{APP.LBL_LIST_USER_NAME}{APP.LBL_LIST_EMAIL}{APP.LBL_LIST_PHONE}
    {USER.FIRST_NAME} {USER.LAST_NAME}{USER.USER_NAME}{USER.EMAIL1}{USER.PHONE_WORK}{REMOVE_INLINE_PNG} {APP.LNK_REMOVE}
    + + + +

    {APP.LBL_CONTACT_LIST}

    + + + + + + + + + + + + + + + + + + + + + + +
    {APP.LBL_LIST_CONTACT_NAME}{APP.LBL_LIST_ACCOUNT_NAME}{APP.LBL_LIST_EMAIL}{APP.LBL_LIST_PHONE} 
    {CONTACT.FIRST_NAME} {CONTACT.LAST_NAME}{CONTACT.ACCOUNT_NAME}{CONTACT.EMAIL1}{CONTACT.PHONE_WORK}{EDIT_INLINE_PNG} {APP.LNK_EDIT}  {REMOVE_INLINE_PNG} {APP.LNK_REMOVE}
    + diff --git a/modules/Emails/SubPanelViewRecipients.php b/modules/Emails/SubPanelViewRecipients.php new file mode 100644 index 00000000..802c49a8 --- /dev/null +++ b/modules/Emails/SubPanelViewRecipients.php @@ -0,0 +1,150 @@ +
    \n"; +$button .= "\n"; +if ($currentModule == 'Accounts') $button .= "\n\n"; +$button .= "\n"; +$button .= "\n"; +$button .= "\n"; +$button .= "\n"; +$button .= " "; +if ($focus->parent_type == "Accounts") $button .= "\n"; +else $button .= "\n"; +$button .= "\n"; +$button .= "
    \n"; + +// Stick the form header out there. +echo get_form_header($mod_strings['LBL_INVITEE'], $button, false); +$xtpl=new XTemplate ('modules/Emails/SubPanelViewRecipients.html'); +$xtpl->assign("MOD", $mod_strings); +$xtpl->assign("APP", $app_strings); +$xtpl->assign("RETURN_URL", "&return_module=$currentModule&return_action=DetailView&return_id=$focus->id"); +$xtpl->assign("EMAIL_ID", $focus->id); +$xtpl->assign("DELETE_INLINE_PNG", SugarThemeRegistry::current()->getImage('delete_inline','align="absmiddle" alt="'.$app_strings['LNK_REMOVE'].'" border="0"')); +$xtpl->assign("EDIT_INLINE_PNG", SugarThemeRegistry::current()->getImage('edit_inline','align="absmiddle" alt="'.$app_strings['LNK_EDIT'].'" border="0"')); +$oddRow = true; +foreach($focus_users_list as $user) +{ + $user_fields = array( + 'USER_NAME' => $user->user_name, + 'FULL_NAME' => $user->first_name." ".$user->last_name, + 'ID' => $user->id, + 'EMAIL' => $user->email1, + 'PHONE_WORK' => $user->phone_work + ); + + $xtpl->assign("USER", $user_fields); + + if($oddRow) + { + //todo move to themes + $xtpl->assign("ROW_COLOR", 'oddListRow'); + } + else + { + //todo move to themes + $xtpl->assign("ROW_COLOR", 'evenListRow'); + } + $oddRow = !$oddRow; + + $xtpl->parse("users.row"); +// Put the rows in. +} + +$xtpl->parse("users"); +$xtpl->out("users"); + +$oddRow = true; +print count($focus_contacts_list); + +foreach($focus_contacts_list as $contact) +{ + $contact_fields = array( + 'FIRST_NAME' => $contact->first_name, + 'LAST_NAME' => $contact->last_name, + 'ACCOUNT_NAME' => $contact->account_name, + 'ID' => $contact->id, + 'EMAIL' => $contact->email1, + 'PHONE_WORK' => $contact->phone_work + ); + + $xtpl->assign("CONTACT", $contact_fields); + + if($oddRow) + { + //todo move to themes + $xtpl->assign("ROW_COLOR", 'oddListRow'); + } + else + { + //todo move to themes + $xtpl->assign("ROW_COLOR", 'evenListRow'); + } + $oddRow = !$oddRow; + + $xtpl->parse("contacts.row"); +// Put the rows in. +} + +$xtpl->parse("contacts"); +$xtpl->out("contacts"); + +?> diff --git a/modules/Emails/SugarRoutingAsync.php b/modules/Emails/SugarRoutingAsync.php new file mode 100644 index 00000000..94c8ae8e --- /dev/null +++ b/modules/Emails/SugarRoutingAsync.php @@ -0,0 +1,118 @@ +setRuleStatus($_REQUEST['rule_id'], $_REQUEST['status']); + break; + + case "saveRule": + $rules->save($_REQUEST); + break; + + case "deleteRule": + $rules->deleteRule($_REQUEST['rule_id']); + break; + + /* returns metadata to construct actions */ + case "getActions": + require_once("include/SugarDependentDropdown/SugarDependentDropdown.php"); + + $sdd = new SugarDependentDropdown(); + $sdd->init("include/SugarDependentDropdown/metadata/dependentDropdown.php"); + $out = $json->encode($sdd->metadata, true); + echo $out; + break; + + /* returns metadata to construct a rule */ + case "getRule": + $ret = ''; + if(isset($_REQUEST['rule_id']) && !empty($_REQUEST['rule_id']) && isset($_REQUEST['bean']) && !empty($_REQUEST['bean'])) { + if(!isset($beanList)) + include("include/modules.php"); + + $class = $beanList[$_REQUEST['bean']]; + //$beanList['Groups'] = 'Group'; + if(isset($beanList[$_REQUEST['bean']])) { + require_once("modules/{$_REQUEST['bean']}/{$class}.php"); + $bean = new $class(); + + $rule = $rules->getRule($_REQUEST['rule_id'], $bean); + + $ret = array( + 'bean' => $_REQUEST['bean'], + 'rule' => $rule + ); + } + } else { + $bean = new SugarBean(); + $rule = $rules->getRule('', $bean); + + $ret = array( + 'bean' => $_REQUEST['bean'], + 'rule' => $rule + ); + } + + //_ppd($ret); + + $out = $json->encode($ret, true); + echo $out; + break; + + case "getStrings": + $ret = $rules->getStrings(); + $out = $json->encode($ret, true); + echo $out; + break; + + + default: + echo "NOOP"; +} \ No newline at end of file diff --git a/modules/Emails/field_arrays.php b/modules/Emails/field_arrays.php new file mode 100644 index 00000000..92cd0411 --- /dev/null +++ b/modules/Emails/field_arrays.php @@ -0,0 +1,82 @@ + array( + "id" + , "date_entered" + , "date_modified" + , "assigned_user_id" + , "modified_user_id" + , "created_by" + , "description" + , "description_html" + , "name" + , "date_start" + , "time_start" + , "parent_type" + , "parent_id" + , "from_addr" + , "from_name" + , "to_addrs" + , "cc_addrs" + , "bcc_addrs" + , "to_addrs_ids" + , "to_addrs_names" + , "to_addrs_emails" + , "cc_addrs_ids" + , "cc_addrs_names" + , "cc_addrs_emails" + , "bcc_addrs_ids" + , "bcc_addrs_names" + , "bcc_addrs_emails" + , "type" + , "status" + , "intent" + ), + 'list_fields' => array( + 'id', 'name', 'parent_type', 'parent_name', 'parent_id', 'date_start', 'time_start', 'assigned_user_name', 'assigned_user_id', 'contact_name', 'contact_id', 'first_name','last_name','to_addrs','from_addr','date_sent','type_name','type','status','link_action','date_entered','attachment_image','intent','date_sent' + ), +); +?> \ No newline at end of file diff --git a/modules/Emails/images/autofit.gif b/modules/Emails/images/autofit.gif new file mode 100644 index 0000000000000000000000000000000000000000..00a4c8dce845ad7a19c4bd87d22bf6953a5df4db GIT binary patch literal 63 zcmZ?wbhEHb6cjXn{`~)7pu+$JAaMpJiI)DAT5mTA^rX#eaQ2O4&MuKw Ms=LzZ#>!v~0I)L^od5s; literal 0 HcmV?d00001 diff --git a/modules/Emails/images/colsView.gif b/modules/Emails/images/colsView.gif new file mode 100644 index 0000000000000000000000000000000000000000..98bcb065601a7ce3eaba39b407a7bd7734e2a079 GIT binary patch literal 56 zcmZ?wbhEHb8)mM)qg0cA>GYh_LRr6k7hW$6 J4Ps!h1^}Qa5t0A^ literal 0 HcmV?d00001 diff --git a/modules/Emails/images/email.gif b/modules/Emails/images/email.gif new file mode 100644 index 0000000000000000000000000000000000000000..19766c5b7ffdf0bc87a2539b75831c1621175dec GIT binary patch literal 888 zcmZ?wbhEHb&B-Ew?9p~ z^=azuPt$LInsMjT+`FIV-}|)S-ls+PKP|rhY1xBM%kO_${@~NPho9Cx`n3Mxrwxxj zZG7};+mp}Rf#~t4?N2`KeDdk^i%%C`eVTv&)6xf@Ha-5d`3X?Lr=3qf-G2M&$@@<) zKYV)e;ZsLPhl`5~$Tg#2Gz91v0*XIb7#SG!8FWB)g7O3dM<_!)hm6OD1&&R6LRujf z7mjuaC@FPu7#?bM5Rr@#(3rr~+|4Z(pCPe;;ZPf|o(Kmji*<&Ib3xhQP-pP=m literal 0 HcmV?d00001 diff --git a/modules/Emails/images/emailGroup.gif b/modules/Emails/images/emailGroup.gif new file mode 100644 index 0000000000000000000000000000000000000000..0cc4a4389c500c82ed21ea46754aa06c38d510d6 GIT binary patch literal 192 zcmZ?wbhEHb~{+#>#&xOt3a-RM<^Z);U2HZgLCkrD3gBXJj zND0VJ23Fezs(mS$lN?s9QV!5@w$Wi#aAOa!4W8HC#@+@T8m(X718aD6Ta{&fx0FCugHvj+t literal 0 HcmV?d00001 diff --git a/modules/Emails/images/fullscreen.gif b/modules/Emails/images/fullscreen.gif new file mode 100644 index 0000000000000000000000000000000000000000..1998790e96a5d9dad68482b20263f2a65dc4431b GIT binary patch literal 78 zcmZ?wbhEHb0c@Nc5gsOdQd`UU-jF**rXr^25SItU>9!y literal 0 HcmV?d00001 diff --git a/modules/Emails/images/leftarrow_inline.gif b/modules/Emails/images/leftarrow_inline.gif new file mode 100644 index 0000000000000000000000000000000000000000..7b42fb081095219d649c99e693a89fcf109531d0 GIT binary patch literal 898 zcmZ?wbhEHb-US1v*74`nzyBpVUynp}U>zA)@-n{+r{==h3kDr0S^CyoV zy?piR&fPoB&CLY`1&N7?-rn9pK|z_BneX1cd;Iv(*RNk*zIyrg?c2L|?|%C9>Bf!g z-@bj@y?b|UZ7stn7!85J9Ri9!Sr{1@La-US1v*74`nzyBpVUynp}U>zA)@-n{+r{==h3kDr0S^CyoV zy?piR&fPoB&CLY`1&N7?-rn9pK|z_BneX1cd;Iv(*RNk*zIyrg?c2L|?|%C9>Bf!g z-@bj@y?b|UZ7stn7!85J9Ri9!Sr{1@HGH|<3SOWm+5pZDu literal 0 HcmV?d00001 diff --git a/modules/Emails/images/rowsView.gif b/modules/Emails/images/rowsView.gif new file mode 100644 index 0000000000000000000000000000000000000000..084e26f0a18c6371f5e2244aac8e0abcf6ef1e6a GIT binary patch literal 79 zcmZ?wbhEHb(5^v+Q^gCqAo?Z5qT?(t_=uiZFw|Ld=xKj*AG@Z-mi zxhGy9S23G^`kl1TvgH>(%J?k28k==W(d3w#Me)qTZ{EJ!a`k=I#G{wOQZAXhA3t~N z*PlO^UwnVPW!LJ?d9&v1P!66i=eJnWYtbqL_lDIMXC8ZHp0aS)iN_bO-cblxvFFrN z_qeY@M(JufKb$M3&0FMPQuZ*X<()=P7j9+%bq z^XJdgci)aF8?8zz+hgD$?lyPozWbkl{C)V~{?{9~fB*jd=-u}jN1put^m);_4+Y&j z9J4k~-E!sMpFfHLi_a+;tA@-!rfM$lzeK@*(T&W~eP^C1`Y&E>&7`9y&11?UFD?-5sTafVW-l8lYND=X zte>iY?zk1F+kxD2E{cJMf@wX#fBK literal 0 HcmV?d00001 diff --git a/modules/Emails/images/sugarGroup.gif b/modules/Emails/images/sugarGroup.gif new file mode 100644 index 0000000000000000000000000000000000000000..7e3a718efe10a52a687fc2eca6952408ad66fab5 GIT binary patch literal 228 zcmVz?#7Yq$!e^*(8|3WVeg{QvoO%nSMc^S}6af!z#eu?mv&7=G9cviDoJ_h#SwyKcS; z)B2%fs|m&Vg#Z8lA^8LW0018VEC2ui01N;O000GH;3rA|q5+bkNRW~UL`-lRl1$A+ z4E#V~4MF2#uwXp6hod717$_IYBT}g_4o!o0YCT-D&qu*a2201+Z-c@XlN}WfXJH@~ e7!Jl}f%qs885VaB3mFIyA|DV5I{+w(ApkqC2V_nF literal 0 HcmV?d00001 diff --git a/modules/Emails/index.php b/modules/Emails/index.php new file mode 100644 index 00000000..591dbdec --- /dev/null +++ b/modules/Emails/index.php @@ -0,0 +1,54 @@ +email2init(); +$focus->et->preflightUser($current_user); +$out = $focus->et->displayEmailFrame(); +echo $out; +echo ""; + +$skipFooters = true; + diff --git a/modules/Emails/javascript/Email.js b/modules/Emails/javascript/Email.js new file mode 100644 index 00000000..a46ddc00 --- /dev/null +++ b/modules/Emails/javascript/Email.js @@ -0,0 +1,1001 @@ +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + + + +var uploads_arr=new Array(); +var uploads_count_map=new Object(); +var uploads_count = -1; +var current_uploads_id = -1; +var append = false; // Ed has method InsertHTML which inserts at cursor point - plain does not +//following varaibles store references to input fields grouped with the clicked email selection button (select). +var current_contact = ''; +var current_contact_id = ''; +var current_contact_email = ''; +var current_contact_name = ''; +var uploadIndex = 0; +var select_image = SUGAR.language.get('app_strings', 'LBL_ONLY_IMAGE_ATTACHMENT'); +var lbl_remove = SUGAR.language.get('app_strings', 'LBL_REMOVE'); +var lbl_email_attachments_file = SUGAR.language.get('app_strings', 'LBL_EMAIL_ATTACHMENTS_FILE'); +var lbl_email_attachments_document = SUGAR.language.get('app_strings', 'LBL_EMAIL_ATTACHMENTS_DOCUMENT'); +var lbl_email_attachments_embeded = SUGAR.language.get('app_strings', 'LBL_EMAIL_ATTACHMENTS_EMBEDED'); + + +function toggleRawEmail() { + var raw = document.getElementById('rawEmail'); + var button = document.getElementById('rawButton'); + + if(raw.style.display == '') { + raw.style.display = 'none'; + button.value = showRaw; + } else { + raw.style.display = ''; + button.value = hideRaw; + } +} + +/////////////////////////////////////////////////////////////////////////////// +//// DOCUMENT HANDLING HELPERS + +function deletePriorAttachment(id) { + var rem = document.getElementById('removeAttachment'); + + if(rem.value != '') { + rem.value += "::"; + } + rem.value += id; + + document.getElementById('noteDiv'+id).style.display = 'none'; +} + +function setDocument(target, documentId, documentName, docRevId) { + if(window.opener.SUGAR.email2) { + var idx = window.opener.SUGAR.email2.composeLayout.currentInstanceId; + window.opener.SUGAR.email2.composeLayout.setDocument(idx, target, documentId, documentName, docRevId); + } else { + var docId = window.opener.document.getElementById('documentId' + target); + var docName = window.opener.document.getElementById('documentName' + target); + var docRevisionId = window.opener.document.getElementById('document' + target); + docId.value = documentId; + docName.value = documentName; + docRevisionId.value = docRevId; + } + window.close(); +} + +function setDocumentToCampaignTemplate(target, documentId, documentName,docRevId, documentType) { +// var docId = eval("window.opener.document.forms.EditView.documentId" + target); + var docId = window.opener.document.getElementById('documentId' + target); + //var docName = eval("window.opener.document.EditView.documentName" + target); + var docName = window.opener.document.getElementById('documentName' + target); + var docType = window.opener.document.getElementById('documentType' + target); + + var docId = window.opener.document.getElementById('documentId'); + var docName = window.opener.document.getElementById('documentName'); + var docRevisionId = window.opener.document.getElementById('docRevId'); + var docType = window.opener.document.getElementById('documentType'); + + docId.value = documentId; + //docId.onchange('docUpload(); form_reset_doc();'); + docName.value = documentName; + docRevisionId.value = docRevId; + docType.value = documentType; + docName.onchange('docUpload(); form_reset_doc();'); + //alert(docName.onchange); + window.close(); +} + +function selectDocument(target) { + URL="index.php?module=Emails&action=PopupDocuments&to_pdf=true&target=" + target; + windowName = 'selectDocument'; + windowFeatures = 'width=800' + ',height=600' + ',resizable=1,scrollbars=1'; + + win = window.open(URL, windowName, windowFeatures); + if(window.focus) { + // put the focus on the popup if the browser supports the focus() method + win.focus(); + } +} + +function addDocument() { + for(var i=0;i<10;i++) { + var elem = document.getElementById('document'+i); + if(elem.style.display == 'none') { + elem.style.display='block'; + break; + } + } +} + +function deleteDocument(index) { + var elem = document.getElementById('document'+index); + document.getElementById('documentId'+index).value = ""; + document.getElementById('documentName'+index).value = ""; + elem.style.display='none'; +} + +// attachment functions below +function deleteFile(index) { + //get div element + var elem = document.getElementById('file'+index); + //get upload widget + var ea_input = document.getElementById('email_attachment'+index); + + //get the parent node + var Parent = ea_input.parentNode; + //create replacement node + var ea = document.createElement('input'); + ea.setAttribute('id', 'email_attachment' + index); + ea.setAttribute('name', 'email_attachment' + index); + ea.setAttribute('tabindex', '120'); + ea.setAttribute('size', '40'); + ea.setAttribute('type', 'file'); + + //replace the old node with the new one + Parent.replaceChild(ea, ea_input); + + //hide the div element + elem.style.display='none'; + +} + +function addFile() { + for(var i=0;i<10;i++) { + var elem = document.getElementById('file'+i); + if(elem.style.display == 'none') { + elem.style.display='block'; + break; + } + } +} +//// END DOCUMENT HANDLING HELPERS +/////////////////////////////////////////////////////////////////////////////// + +///// New file upload code + +function multiFiles( list_target){ + // Where to write the list + this.list_target = list_target; + //this.list_target = document.getElementById(list_target); + // How many elements? + this.count = 0; + this.id = 0; + /** + * Add a new file input element + */ + this.addElement = function( element ){ + // Make sure it's a file input element + if( element.tagName == 'INPUT' && element.type == 'file' ){ + var currCount =this.id++; + element.name = 'email_attachment' + currCount; + element.id = 'email_attachment' + currCount; + + // Add reference to this object + element.multi_selector = this; + // What to do when a file is selected + element.onchange = function(){ + + //AJAX call begins + var callback = { + upload:function(r) { + var rets = JSON.parse(r.responseText); + } + } + + var url ='index.php?to_pdf=1&module=EmailTemplates&action=AttachFiles'; + YAHOO.util.Connect.setForm(document.getElementById("upload_form"), true,true); + YAHOO.util.Connect.asyncRequest('POST', url, callback,null); + //AJAX call ends + + //var theForm = document.getElementById('upload_form'); + var theForm = document.getElementById('EditView'); + + + // New file input + var new_element = document.createElement( 'input' ); + new_element.type = 'file'; + // new_element.name = 'email_attachment' +up++; + + // Add new element + this.parentNode.insertBefore( new_element, this ); + // Apply 'update' to element + this.multi_selector.addElement( new_element ); + // Update list + this.multi_selector.addListRow( this ); + // Hide this: we can't use display:none because Safari doesn't like it + //this.style.display='none'; + //display none works fine for FF and IE + this.style.display = 'none'; + //later for Safari add following + //this.style.position = 'absolute'; + //this.style.left = '-5000px'; + }; + // File element counter + this.count++; + // Most recent element + this.current_element = element; + + } else { + // This can only be applied to file input elements! + alert( 'Error: not a file input element' ); + }; + }; + + /** + * Add a new row to the list of files + */ + this.addListRow = function( element ){ + // Row div + var new_row = document.createElement( 'div' ); + + // Delete button + var new_row_button_remove = document.createElement( 'input' ); + new_row_button_remove.type = 'button'; + new_row_button_remove.value = lbl_remove; + + var new_row_file_name = document.createElement( 'input' ); + new_row_file_name.type = 'text'; + new_row_file_name.size = '40'; + new_row_file_name.disabled=true; + + var new_row_chk_box = document.createElement( 'input' ); + new_row_chk_box.setAttribute('id','checkBoxFile[]'); + new_row_chk_box.setAttribute('name','checkBoxFile[]'); + new_row_chk_box.type = 'checkbox'; + new_row_chk_box.checked =false; + new_row_chk_box.disabled =true; + + var new_row_attach_file = document.createElement( 'input' ); + new_row_attach_file.type = 'image'; + new_row_attach_file.value ='/index.php?entryPoint=getImage&themeName='+SUGAR.themes.theme_name+'&imageName=company_logo.png'; + new_row_attach_file.disabled ='true'; + + var imgElement = document.createElement("img"); + imgElement.setAttribute("src", "index.php?entryPoint=getImage&themeName="+SUGAR.themes.theme_name+"&imageName=Accounts.gif"); + imgElement.setAttribute("align","absmiddle"); + imgElement.setAttribute("alt",lbl_email_attachments_file); + imgElement.setAttribute("border","0"); + imgElement.setAttribute("height","16"); + imgElement.setAttribute("width","16"); + + var new_row_button_embed = document.createElement("img"); + new_row_button_embed.setAttribute("src", "index.php?entryPoint=getImage&themeName="+SUGAR.themes.theme_name+"&imageName=attachment.gif"); + new_row_button_embed.setAttribute("align","absmiddle"); + new_row_button_embed.setAttribute("alt",lbl_email_attachments_embeded); + new_row_button_embed.setAttribute("border","0"); + new_row_button_embed.setAttribute("height","16"); + new_row_button_embed.setAttribute("width","16"); + + + + /* + var new_row_button_embed = document.createElement( 'input' ); + new_row_button_embed.type = 'button'; + new_row_button_embed.value = 'Embed'; + */ + // References + new_row.element = element; + element.size='40'; + // Delete function + new_row_button_remove.onclick= function(){ + // Remove element from form + this.parentNode.element.parentNode.removeChild( this.parentNode.element ); + var filename = this.parentNode.element.value; + var filename = filename.replace(/\\/g,'/'); + var text = filename.split("/"); + nbr_elements = text.length; + if(text[nbr_elements-1].indexOf('gif')>=0 || text[nbr_elements-1].indexOf('bmp') >= 0 || text[nbr_elements-1].indexOf('png') >= 0 + || text[nbr_elements-1].indexOf('jpg') >= 0 || text[nbr_elements-1].indexOf('GIF')>=0 || text[nbr_elements-1].indexOf('BMP') >= 0 + || text[nbr_elements-1].indexOf('PNG') >= 0 || text[nbr_elements-1].indexOf('JPG') >= 0) + { + //var imglocation = unescape(document.location.pathname.substr(1)); + //imglocation = imglocation.substring(0,imglocation.lastIndexOf('/')+1); + var tiny = tinyMCE.getInstanceById('body_text'); + var currValTiny = tiny.getContent(); + while(currValTiny.indexOf(unescape(text[nbr_elements-1])) != -1){ + //check where the space is and keep replacing with $#32 + currValTiny = currValTiny.replace(unescape(text[nbr_elements-1]),'QW%%^%%WQ'); + currValTiny = currValTiny.replace(/]*>?/,' '); + } + tiny.setContent(currValTiny); + } + // Remove this row from the list + this.parentNode.parentNode.removeChild( this.parentNode ); + + // Decrement counter + this.parentNode.element.multi_selector.count--; + // Re-enable input element (if it's disabled) + this.parentNode.element.multi_selector.current_element.disabled = false; + + // Appease Safari + // without it Safari wants to reload the browser window + // which nixes your already queued uploads + + return false; + }; + + new_row_button_embed.onclick= function(){ + + var filename = element.value.replace(/\\/g,'/') + var text = filename.split("/"); + nbr_elements = text.length; + + //check if the file name has a space + text[nbr_elements-1]=text[nbr_elements-1].replace(/ /g,' '); + + if(text[nbr_elements-1].indexOf('gif')>=0 || text[nbr_elements-1].indexOf('bmp') >= 0 || text[nbr_elements-1].indexOf('png') >= 0 + || text[nbr_elements-1].indexOf('jpg') >= 0 || text[nbr_elements-1].indexOf('GIF')>=0 || text[nbr_elements-1].indexOf('BMP') >= 0 + || text[nbr_elements-1].indexOf('PNG') >= 0 || text[nbr_elements-1].indexOf('JPG') >= 0) + { + cid='cid:'+text[nbr_elements-1]; + /* + var imglocation = unescape(document.location.pathname.substr(1)); + imglocation = imglocation.substring(0,imglocation.lastIndexOf('/')+1); + imglocation='/'+imglocation+sugar_cache_dir+'images/'; + */ + var imglocation = sugar_cache_dir+'images/'; + embedImage="'; + //insert_variable(embedImage1); + insert_variable(embedImage); + + this.parentNode.childNodes[2].checked='true'; + } + else{ + alert(select_image); + } + + }; + + // Set row value + /* + var oas = new ActiveXObject("Scripting.FileSystemObject"); + var d = document.a.b.value; + var e = oas.getFile(d); + var f = e.size; + alert(f + " bytes"); + alert(element); + */ + //new_row_file_name.value =element.value; + new_row_file_name_tab = element.value.split("\\"); + //alert(new_row_file_name_tab); + nbr_elements = new_row_file_name_tab.length; + new_row_file_name.value = new_row_file_name_tab[nbr_elements-1]; + + //new_row.innerHTML = element.value; + //add all the elements + //new_row.appendChild(new_row_attach_file); + new_row.appendChild(imgElement); + new_row.appendChild(new_row_button_embed); + new_row.appendChild(new_row_chk_box); + new_row.appendChild( new_row_file_name); + // Add button + new_row.appendChild( new_row_button_remove); + // Add it to the list + this.list_target.appendChild( new_row ); + //document.getElementById(list_target).appendChild(new_row); + }; +}; + + +function docUpload() { + + //var theForm = document.getElementById('EditView'); + //var theForm = document.getElementById('upload_form'); + //AJAX call begins + var rets =''; + var callback = { + upload: function(r) { + rets = JSON.parse(r.responseText); + } + } + + var url ='index.php?module=EmailTemplates&action=AttachDocuments'; + YAHOO.util.Connect.asyncRequest('POST', url, callback,null); + //AJAX call ends + + var element = document.getElementById('documentName'); + var element1 = document.getElementById('documentId'); + var element2 = document.getElementById('docRevId'); + var element3 = document.getElementById('documentType'); + var elm = document.createElement('div'); + elm.setAttribute('id','file'+uploadIndex); + + var sugarDoc = document.createElement('input'); + sugarDoc.setAttribute('type', 'label'); + sugarDoc.setAttribute('disabled', 'true'); + sugarDoc.setAttribute('font', 'bold'); + sugarDoc.setAttribute('value',"Sugar Document"); + + + var new_row_button_embed_doc = document.createElement( 'input' ); + new_row_button_embed_doc.type = 'button'; + new_row_button_embed_doc.value = 'Embed'; + + var new_row_chk_box = document.createElement( 'input' ); + new_row_chk_box.setAttribute('id','checkBoxDoc'+uploadIndex); + new_row_chk_box.setAttribute('name','checkBoxDoc'+uploadIndex); + new_row_chk_box.type = 'checkbox'; + new_row_chk_box.checked =false; + new_row_chk_box.disabled='true'; + + + var eah = document.createElement('input'); + eah.setAttribute('id', 'documentId'+uploadIndex); + eah.setAttribute('name', 'documentId'+uploadIndex); + eah.setAttribute('tabindex', '120'); + eah.setAttribute('type', 'hidden'); + eah.setAttribute('value',element1.value); + + + var attId = document.createElement('input'); + attId.setAttribute('id', 'docRevId'+uploadIndex); + attId.setAttribute('name', 'docRevId'+uploadIndex); + attId.setAttribute('tabindex', '120'); + attId.setAttribute('type', 'hidden'); + attId.setAttribute('value',element2.value); + + + var attType = document.createElement('input'); + attType.setAttribute('id', 'documentType'+uploadIndex); + attType.setAttribute('name', 'documentType'+uploadIndex); + attType.setAttribute('tabindex', '120'); + attType.setAttribute('type', 'hidden'); + attType.setAttribute('value',element3.value); + + + var ea = document.createElement('input'); + ea.setAttribute('id', 'document[]'); + ea.setAttribute('name', 'document[]'); + ea.setAttribute('tabindex', '120'); + ea.setAttribute('size', '40'); + ea.setAttribute('type', 'text'); + ea.setAttribute('disabled',true); + ea.setAttribute('value',element.value); + + var eai = document.createElement('input'); + eai.setAttribute('type', 'button'); + //eai.setAttribute('onclick', 'deleteFile('+uploadIndex+');'); + eai.setAttribute('value', lbl_remove); + eai.onclick=function(){ + var filename = this.parentNode.childNodes[4].value; + if(filename != null){ + var tiny = tinyMCE.getInstanceById('body_text'); + var currValTiny = tiny.getContent(); + while(currValTiny.indexOf(unescape(filename)) != -1){ + currValTiny = currValTiny.replace(unescape(filename),'QW%%^%%WQ'); + currValTiny = currValTiny.replace(/]*>?/,' '); + } + tiny.setContent(currValTiny); + } + this.parentNode.parentNode.removeChild(this.parentNode); + } + + + var new_row_button_embed = document.createElement("img"); + new_row_button_embed.setAttribute("src", "index.php?entryPoint=getImage&themeName="+SUGAR.themes.theme_name+"&imageName=attachment.gif"); + new_row_button_embed.setAttribute("align","absmiddle"); + new_row_button_embed.setAttribute("alt",lbl_email_attachments_embeded); + new_row_button_embed.setAttribute("border","0"); + new_row_button_embed.setAttribute("height","16"); + new_row_button_embed.setAttribute("width","16"); + new_row_button_embed.onclick= function(){ + //retrieve the documentid + this.parentNode.childNodes[2].checked='true'; + var documentRevisionId = this.parentNode.childNodes[4].value; + var mime_type = this.parentNode.childNodes[5].value; + if(mime_type == "image/gif" || mime_type == "image/bmp" || mime_type == "image/png" || mime_type == "image/x-png" || mime_type == "image/jpg") + { + var imglocation = unescape(document.location.pathname.substr(1)); + imglocation = imglocation.substring(0,imglocation.lastIndexOf('/')+1); + imglocation='/'+imglocation+sugar_upload_dir; + embedImage=''; + embedImage1=''; + insert_variable(embedImage); + } + else{ + new_row_chk_box.checked =false; + alert(select_image); + } + }; + + var SugarDoc = document.createElement("img"); + SugarDoc.setAttribute("src", "index.php?entryPoint=getImage&themeName="+SUGAR.themes.theme_name+"&imageName=sugar_document.png"); + SugarDoc.setAttribute("align","absmiddle"); + SugarDoc.setAttribute("alt",lbl_email_attachments_document); + SugarDoc.setAttribute("border","0"); + SugarDoc.setAttribute("height","16"); + SugarDoc.setAttribute("width","16"); + + + //elm.appendChild(eah); + elm.appendChild(SugarDoc); + elm.appendChild(new_row_button_embed); + elm.appendChild(new_row_chk_box); + elm.appendChild(eah); + elm.appendChild(attId); + elm.appendChild(attType); + elm.appendChild(ea); + elm.appendChild(eai); + elm.style.display = 'block'; + + var rN= document.getElementById('attachments_div'); + rN.appendChild(elm); + uploadIndex++; +} + +function addUploadFiles(form_name) { + var chForm = document.getElementById('upload_div'); + var theForm = document.getElementById(form_name); + var elems = chForm.getElementsByTagName("input"); + //get the count of all the email_attachment file elements + var count = 0; + //Use the count to add the documents + count=this.multi_selector.id; + for (var i=0; i=0 || el.id=='document[]') { + theForm.appendChild(el); + } + } + } + +function form_reset_doc() { + // var theForm = document.getElementById('upload_form'); + var theForm = document.getElementById('upload_div'); + var elems = theForm.getElementsByTagName("input"); + for (var i=0; i'); + tiny.setContent(plainText); + } else { + // toggling into Plain Text ONLY + html.style.display = 'none'; + plain.style.display = 'block'; + altText.style.display = 'none'; + + if(tiny.getContent()) { + var htmlText = new String(tiny.getContent()); + htmlText = htmlText.replace(/
    /gi, "\n"); + htmlText = htmlText.replace(/>/gi, ">"); + htmlText = htmlText.replace(/</gi, "<"); + htmlText = htmlText.replace(/ /gi, " "); + desc.value = stripTags(htmlText); + } + } +} + +function stripTags(str) { + var theText = new String(str); + + if(theText != 'undefined') { + return theText.replace(/<\/?[^>]+>/gi, ''); + } +} + +function toggle_textarea() { + var checkbox = document.getElementById('toggle_textarea_elem'); + var plain = document.getElementById('text_div'); + + if (checkbox.checked == false) { + plain.style.display = 'none'; + } else { + plain.style.display = 'block'; + } +} +//// END HTML/PLAIN EDITOR FUNCTIONS +/////////////////////////////////////////////////////////////////////////////// + + + + +/////////////////////////////////////////////////////////////////////////////// +//// EMAIL TEMPLATE CODE +function fill_email(id) { + var where = "parent_id='" + id + "'"; + var order = ''; + + if(id == '') { + // query based on template, contact_id0,related_to + if(! append) { + document.EditView.name.value = ''; + document.EditView.description.value = ''; + document.EditView.description_html.value = ''; + } + return; + } + call_json_method('EmailTemplates','retrieve','record='+id,'email_template_object', appendEmailTemplateJSON); + args = {"module":"Notes","where":where, "order":order}; + + if(typeof(global_rpcClient) == 'undefined') { + global_rpcClient = new SugarRPCClient(); + } + + req_id = global_rpcClient.call_method('get_full_list', args); + global_request_registry[req_id] = [ejo, 'display']; +} + +function appendEmailTemplateJSON() { + // query based on template, contact_id0,related_to + if(document.EditView.name.value == '') { // cn: bug 7743, don't stomp populated Subject Line + document.EditView.name.value = decodeURI(encodeURI(json_objects['email_template_object']['fields']['subject'])); + } + + document.EditView.description.value += decodeURI(encodeURI(json_objects['email_template_object']['fields']['body'])).replace(/
    /ig, '\n'); + var tiny = tinyMCE.getInstanceById("description_html"); + var tinyHtml = tiny.getContent(true); + + // cn: bug 10985 - IE6/7 will show inline image at top of screen if we set this with no valid target + if(document.getElementById('setEditor').checked == false) { + var descHtml = decodeURI(encodeURI(json_objects['email_template_object']['fields']['body_html'])).replace(/</gi,'<').replace(/>/gi,'>').replace(/
    /ig, '\n').replace(/'/gi,'\'').replace(/"/gi,'"'); + + // cn: bug 13376 - leave & to last to preserve certain HTML-entities for TinyMCE editor + descHtml = descHtml.replace(/&/gi,'&'); + + tiny.setContent(tinyHtml + descHtml); + } + + var htmlDiv = document.getElementById('html_div'); + + // hide the HTML editor if this is Plain-text only + if((tinyHtml == '' || tinyHtml == '
    ') && htmlDiv.style.display == '') { + var desc = document.getElementById('description'); + var plainText = new String(desc.value); + plainText = plainText.replace(/\n/gi, '
    '); + tiny.setContent(plainText); + + // cn: bug 6212 + // if the template is plain-text, then uncheck "Send HTML Email" + document.getElementById('setEditor').checked = true; + setEditor(); + } +} + +if(typeof SugarClass == "object") { + SugarClass.inherit("EmailJsonObj","SugarClass"); +} +function EmailJsonObj() { +} +EmailJsonObj.prototype.display = function(result) { + var bean; + var block = document.getElementById('template_attachments'); + var target = block.innerHTML; + var full_file_path; + + for(i in result) { + if(typeof result[i] == 'object') { + bean = result[i]; + full_file_path = file_path + bean['id']+bean['filename']; + target += '\n'; + target += '\n '+ lnk_remove + '  '; + target += '' + bean['filename'] + '
    '; + } + } + block.innerHTML = target; +} + +ejo = new EmailJsonObj(); +//// END EMAIL TEMPLATE CODE +/////////////////////////////////////////////////////////////////////////////// + + +function fill_form(type, error_text) { + if(document.getElementById('subjectfield').value == '') { + var sendAnyways = confirm(lbl_send_anyways); + if(sendAnyways == false) { return false; } + } + + if(type == 'out' && document.EditView.to_addrs.value == '' && + document.EditView.cc_addrs.value == '' && + document.EditView.bcc_addrs.value == '') { + + alert(error_text); + return false; + } + + var the_form = document.EditView; + var inputs = the_form.getElementsByTagName('input'); + + // this detects if browser needs the following hack or not.. + if(inputs.length > 0) { + // no need to appendChild to EditView to get file uploads to work + return check_form('EditView'); + } + + if(! check_form('EditView')) { + return false; + } + return true; +} + +function setLabels(uploads_arr) { +} + + + +//this function appends the selected email address to the aggregated email address fields. +function set_current_parent(id,email,name,value) { + current_contact_id.value += id+";"; + current_contact_email.value += email+";"; + current_contact_name.value += name+";"; + + if(current_contact.value != '') { + current_contact.value += "; "; + } + + current_contact.value += name + " <" + email + ">"; +// current_contact.value += value; +} + +function set_email_return(popup_reply_data) { + var form_name = popup_reply_data.form_name; + var name_to_value_array = popup_reply_data.name_to_value_array; + if (typeof name_to_value_array == "object" ) { + update_email_addresses(form_name,name_to_value_array); + } else { + for(var i in name_to_value_array) { + update_email_addresses(form_name,name_to_value_array[i]); + } + } +} + +function update_email_addresses(form_name,name_to_value) { + for(var the_key in name_to_value) { + if(the_key == 'toJSON') { + /* just ignore */ + } else { + var displayValue = name_to_value[the_key]; + displayValue=displayValue.replace(''',"'"); //restore escaped single quote. + displayValue=displayValue.replace('&',"&"); //restore escaped &. + displayValue=displayValue.replace('>',">"); //restore escaped >. + displayValue=displayValue.replace('<',"<"); //restore escaped <. + displayValue=displayValue.replace('" ',"\""); //restore escaped ". + + window.document.forms[form_name].elements[the_key].value += displayValue + '; '; + } + } +} + +//create references to input fields associated with the select email address button. +//Clicked button is passed as the parameter to the function. +function button_change_onclick(obj) { + var prefix = 'to_'; + if(obj.name.match(/^cc_/i)) { + prefix = 'cc_'; + } else if(obj.name.match(/^bcc_/i)) { + prefix = 'bcc_'; + } + + for(var i = 0; i < obj.form.length;i++) { + child = obj.form[i]; + if(child.name.indexOf(prefix) != 0) { + continue; + } + + if(child.name.match(/addrs_emails$/i)) { + current_contact_email = child; + } else if(child.name.match(/addrs_ids$/i)) { + current_contact_id = child; + } else if(child.name.match(/addrs_names$/i)) { + current_contact_name = child; + } else if(child.name.match(/addrs$/i)) { + current_contact = child; + } + } + + var filter = ''; + var acct_name = ''; + + if(document.EditView.parent_type.value == 'Accounts' && typeof(document.EditView.parent_name.value) != 'undefined' && document.EditView.parent_name.value != '') { + filter = "&form_submit=false&query=true&html=Email_picker&account_name=" + escape(document.EditView.parent_name.value); + acct_name = document.EditView.parent_name.value; + } + + var popup_request_data = + { + "call_back_function" : "set_email_return", + "form_name" : "EditView", + "field_to_name_array" : + { + "id" : prefix + "addrs_ids", + "email1" : prefix + "addrs_emails", + "name" : prefix + "addrs_names", + "email_and_name1" : prefix + "addrs_field" + } + }; + + return open_popup("Contacts", 600, 400, filter, true, false, popup_request_data, 'MultiSelect', false, 'popupdefsEmail'); +} + +//this function clear the value stored in the aggregated email address fields(nodes). +//it relies on the references set by the button_change_onclick method +function clear_email_addresses() { + + if(current_contact != '') { + current_contact.value = ''; + } + if(current_contact_id != '') { + current_contact_id.value = ''; + } + if(current_contact_email != '') { + current_contact_email.value = ''; + } + if(current_contact_name != '') { + current_contact_name.value = ''; + } +} + +function quick_create_overlib(id, theme) { + return overlib('' + + "" + SUGAR.language.get('Emails', 'LBL_LIST_CASE') + '' + + "" + + "" + + SUGAR.language.get('Emails', 'LBL_LIST_LEAD') + "" + + "" + + "" + + SUGAR.language.get('Emails', 'LBL_LIST_CONTACT') + "" + + ""+ + "" + + SUGAR.language.get('Emails', 'LBL_LIST_BUG') + "" + + "" + + "" + + SUGAR.language.get('Emails', 'LBL_LIST_TASK') + "" + , CAPTION, SUGAR.language.get('Emails', 'LBL_QUICK_CREATE') + , STICKY, MOUSEOFF, 3000, CLOSETEXT, '', WIDTH, 150, CLOSETITLE, SUGAR.language.get('app_strings', 'LBL_ADDITIONAL_DETAILS_CLOSE_TITLE'), CLOSECLICK, FGCLASS, 'olOptionsFgClass', + CGCLASS, 'olOptionsCgClass', BGCLASS, 'olBgClass', TEXTFONTCLASS, 'olFontClass', CAPTIONFONTCLASS, 'olOptionsCapFontClass', CLOSEFONTCLASS, 'olOptionsCloseFontClass'); +} + + diff --git a/modules/Emails/javascript/EmailUI.js b/modules/Emails/javascript/EmailUI.js new file mode 100644 index 00000000..c6af417b --- /dev/null +++ b/modules/Emails/javascript/EmailUI.js @@ -0,0 +1,3542 @@ +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + +(function() { + var sw = YAHOO.SUGAR, + Event = YAHOO.util.Event, + Connect = YAHOO.util.Connect, + Dom = YAHOO.util.Dom + SE = SUGAR.email2; + +/////////////////////////////////////////////////////////////////////////////// +//// EMAIL ACCOUNTS +SE.accounts = { + outboundDialog : null, + inboundAccountEditDialog : null, + inboundAccountsSettingsTable : null, + outboundAccountsSettingsTable : null, + testOutboundDialog : null, + errorStyle : 'input-error', + normalStyle : '', + newAddedOutboundId : '', + + /** + * makes async call to retrieve an outbound instance for editting + */ + //EXT111 + editOutbound : function(obi) { + + AjaxObject.startRequest(AjaxObject.accounts.callbackEditOutbound, urlStandard + "&emailUIAction=editOutbound&outbound_email=" + obi); + + }, + deleteOutbound : function(obi) { + + if(obi.match(/^(add|line|sendmail)+/)) { + alert('Invalid Operation'); + } else { + overlay(app_strings.LBL_EMAIL_DELETING_OUTBOUND, app_strings.LBL_EMAIL_ONE_MOMENT); + AjaxObject.startRequest(AjaxObject.accounts.callbackDeleteOutbound, urlStandard + "&emailUIAction=deleteOutbound&outbound_email=" + obi); + } + }, + //EXT111 + getReplyAddress : function() { + var primary = ''; + + for(var i=0; i'; + } + }; + + this.showBoolean = function(el, oRecord, oColumn, oData) + { + var is_group = oRecord.getData("is_group"); + var bChecked = oData; + bChecked = (bChecked) ? " checked" : ""; + if(!is_group) + { + el.innerHTML = ""; + } + }; + + + YAHOO.widget.DataTable.Formatter.customImage = this.customImageFormatter; + YAHOO.widget.DataTable.Formatter.showBoolean = this.showBoolean; + + var typeHoverHelp = ' '; + + + this.ieColumnDefs = [{key:'name',label:app_strings.LBL_EMAIL_SETTINGS_NAME }, {key:'server_url',label:ie_mod_strings.LBL_SERVER_URL}, + {key:'is_active',label:ie_mod_strings.LBL_STATUS_ACTIVE,formatter:"checkbox",className:'yui-cstm-cntrd-liner'}, + {key:'is_default',label:app_strings.LBL_EMAIL_ACCOUNTS_SMTPDEFAULT,formatter:"showBoolean",className:'yui-cstm-cntrd-liner'}, + {key:'type',label:mod_strings.LBL_LIST_TYPE + typeHoverHelp }, + {key:'edit',label:mod_strings.LBL_BUTTON_EDIT,formatter:"customImage",className:'yui-cstm-cntrd-liner'}, + {key:'delete',label:app_strings.LBL_EMAIL_DELETE,formatter:"customImage",className:'yui-cstm-cntrd-liner'}]; + var query = "index.php?module=Emails&action=EmailUIAjax&to_pdf=true&emailUIAction=rebuildShowAccount"; + this.ieDataSource = new YAHOO.util.DataSource(query); + this.ieDataSource.responseType = YAHOO.util.DataSource.TYPE_JSON; + this.ieDataSource.responseSchema = { + resultsList: "account_list", + fields: [{key:'id'},{key:'name'},'is_active',{key:'server_url'},'is_group','group_id','is_default','has_groupfolder','type'] + }; + this.inboundAccountsSettingsTable = new YAHOO.widget.DataTable("inboundAccountsTable", this.ieColumnDefs, this.ieDataSource); + this.inboundAccountsSettingsTable.subscribe("checkboxClickEvent", function(oArgs){ + + var elCheckbox = oArgs.target; + var oColumn = this.getColumn(elCheckbox); + if(oColumn.key == 'is_active') + { + var oRecord = this.getRecord(elCheckbox); + oRecord.setData("is_active",elCheckbox.checked); + var t_id = oRecord.getData('id'); + var isGroupFolder = oRecord.getData('has_groupfolder'); + + if(isGroupFolder) + SUGAR.email2.folders.updateSubscriptions(); + else + SUGAR.email2.folders.setFolderSelection(); + + } + }); + var lastDefaultSelectedId = ""; + this.inboundAccountsSettingsTable.subscribe("radioClickEvent", function(oArgs){ + + var elRadio = oArgs.target; + var oColumn = this.getColumn(elRadio); + if(oColumn.key == 'is_default') + { + var oRecord = this.getRecord(elRadio); + var t_id = oRecord.getData('id'); + var t_isGroup = oRecord.getData('is_group'); + if(t_id != lastDefaultSelectedId && !t_isGroup) + { + SUGAR.default_inbound_accnt_id = t_id; //Set in the global space for access during compose + lastDefaultSelectedId = t_id; + AjaxObject.startRequest(callbackDefaultOutboundSave, urlStandard + "&emailUIAction=saveDefaultOutbound&id="+ t_id); + } + else if(t_isGroup) + YAHOO.util.Event.preventDefault(oArgs.event); //Do not allow users to select group mailboxes as a default. + + } + }); + + this.inboundAccountsSettingsTable.subscribe("rowMouseoverEvent", this.inboundAccountsSettingsTable.onEventHighlightRow); + this.inboundAccountsSettingsTable.subscribe("rowMouseoutEvent", this.inboundAccountsSettingsTable.onEventUnhighlightRow); + } + }, + _setupOutboundAccountTable: function() + { + if(!this.outboundAccountsSettingsTable) + { + this.obImageFormatter = function(elLiner, oRecord, oColumn, oData) { + var clckEvent = oColumn.key; + var imgSrc = ""; + var isEditable = oRecord.getData("is_editable"); + var type = oRecord.getData("type"); + if(isEditable) + { + if(oColumn.key == 'edit') + { + clckEvent = "SUGAR.email2.accounts.editOutbound('"+ oRecord.getData('id') +"')"; + imgSrc = 'index.php?entryPoint=getImage&themeName=Sugar&imageName='+oColumn.key+'_inline.gif'; + } + else if(oColumn.key == 'delete' && type == 'user') + { + clckEvent = "SUGAR.email2.accounts.deleteOutbound('"+ oRecord.getData('id')+"')"; + imgSrc = 'index.php?entryPoint=getImage&themeName=Sugar&imageName='+oColumn.key+'_inline.gif'; + } + if(imgSrc != '') + elLiner.innerHTML = ''; + } + }; + + //Custom formatter to display any error messages. + this.messageDisplay = function(elLiner, oRecord, oColumn, oData) { + + if(SUGAR.email2.composeLayout.outboundAccountErrors == null) + SUGAR.email2.composeLayout.outboundAccountErrors = {}; + + var id = oRecord.getData('id'); + var message = oRecord.getData("errors"); + if(message != '') + { + elLiner.innerHTML = '' + message + ''; + //Add the id and message for all outbound accounts. + SUGAR.email2.composeLayout.outboundAccountErrors[id] = message; + } + else + { + if(typeof(SUGAR.email2.composeLayout.outboundAccountErrors[id]) != 'undefined' ) + delete SUGAR.email2.composeLayout.outboundAccountErrors[id]; + } + }; + YAHOO.widget.DataTable.Formatter.actionsImage = this.obImageFormatter; + YAHOO.widget.DataTable.Formatter.messageDisplay = this.messageDisplay; + + this.obAccntsColumnDefs = [{key:'name',label:app_strings.LBL_EMAIL_ACCOUNTS_NAME }, {key:'mail_smtpserver',label:app_strings.LBL_EMAIL_ACCOUNTS_SMTPSERVER}, + {key:'edit',label:mod_strings.LBL_BUTTON_EDIT,formatter:"actionsImage",className:'yui-cstm-cntrd-liner'}, + {key:'delete', label:app_strings.LBL_EMAIL_DELETE,formatter:"actionsImage",className:'yui-cstm-cntrd-liner'}, + {key:'messages',label:'', formatter:"messageDisplay",className:'yui-cstm-cntrd-liner'}]; + + var query = "index.php?module=Emails&action=EmailUIAjax&to_pdf=true&emailUIAction=retrieveAllOutbound"; + this.obDataSource = new YAHOO.util.DataSource(query); + this.obDataSource.responseType = YAHOO.util.DataSource.TYPE_JSON; + this.obDataSource.responseSchema = { + + resultsList: "outbound_account_list", + fields: ['id','name','is_editable','mail_smtpserver','type','errors'] + }; + + this.outboundAccountsSettingsTable = new YAHOO.widget.DataTable("outboundAccountsTable", this.obAccntsColumnDefs, this.obDataSource); + + + this.outboundAccountsSettingsTable.subscribe("rowMouseoverEvent", this.outboundAccountsSettingsTable.onEventHighlightRow); + this.outboundAccountsSettingsTable.subscribe("rowMouseoutEvent", this.outboundAccountsSettingsTable.onEventUnhighlightRow); + this.outboundAccountsSettingsTable.subscribe("postRenderEvent",this.rebuildMailerOptions); + } + }, + /** + * Displays a modal diaglogue to edit outbound account settings + */ + showEditInboundAccountDialogue : function(clear) { + + if(!this.inboundAccountEditDialog) { + var EAD = this.inboundAccountEditDialog = new YAHOO.widget.Dialog("editAccountDialogue", { + modal:true, + visible:true, + fixedcenter:true, + constraintoviewport: true, + width : "600px", + shadow : true + }); + EAD.showEvent.subscribe(function() { + var el = this.element; + var viewH = YAHOO.util.Dom.getViewportHeight(); + if (this.header && el && viewH - 50 < el.clientHeight) { + var body = this.header.nextElementSibling; + body.style.overflow = "hidden"; + body.style.height = "100%"; + } + }, EAD); + EAD.setHeader(mod_strings.LBL_EMAIL_ACCOUNTS_INBOUND); + Dom.removeClass("editAccountDialogue", "yui-hidden"); + + } // end lazy load + + if(clear == undefined || clear == true) + { + SE.accounts.clearInboundAccountEditScreen(); + //Set default protocol to IMAP when creating new records + document.forms['ieAccount'].elements['protocol'].value = "imap"; + SE.accounts.setPortDefault(); + } + + //Check if we should display username/password fields for outbound account if errors were detected. + this.checkOutBoundSelection(); + + this.inboundAccountEditDialog.render(); + this.inboundAccountEditDialog.show(); + }, + + /** + * Set all fields on the outbound edit form to either enabled/disabled + * except for the username/password. + * + */ + toggleOutboundAccountDisabledFields: function(disable) + { + var fields = ['mail_name', 'mail_smtpserver','mail_smtpport','mail_smtpauth_req']; + for(var i=0;iAccounts + */ + fillIeAccount:function(jsonstr) { + var o = JSON.parse(jsonstr); + + document.getElementById('ie_id').value = o.id; + document.getElementById('ie_name').value = o.name; + if (o.stored_options != null) { + document.getElementById('ie_from_name').value = o.stored_options.from_name == 'undefined' ? '' : o.stored_options.from_name; + document.getElementById('ie_from_addr').value = o.stored_options.from_addr == 'undefined' ? '' : o.stored_options.from_addr; + document.getElementById('reply_to_addr').value = typeof(o.stored_options.reply_to_addr) == 'undefined' ? '' : o.stored_options.reply_to_addr; + if (o.stored_options.trashFolder != null) { + document.getElementById('trashFolder').value = o.stored_options.trashFolder; + } + if (o.stored_options.sentFolder != null) { + document.getElementById('sentFolder').value = o.stored_options.sentFolder; + } + } + document.getElementById('server_url').value = o.server_url; + document.getElementById('email_user').value = o.email_user; + document.getElementById('port').value = o.port; + document.getElementById('group_id').value = o.group_id; + document.getElementById('mailbox').value = o.mailbox; + + + var i = 0; + + // handle SSL + if(typeof(o.service[2]) != 'undefined') { + document.getElementById('ssl').checked = true; + } + + // handle protocol + if(document.getElementById('protocol').value != o.protocol) { + var prot = document.getElementById('protocol'); + for(i=0; i"; + } + if(trim(smtpServer) == '') { + isError = true; + errorMessage += app_strings.LBL_EMAIL_ACCOUNTS_SMTPSERVER + "
    "; + } + if(trim(smtpPort) == '') { + isError = true; + errorMessage += app_strings.LBL_EMAIL_ACCOUNTS_SMTPPORT + "
    "; + } + if(mailsmtpauthreq.checked) { + if(trim(document.getElementById('mail_smtpuser').value) == '') { + isError = true; + errorMessage += app_strings.LBL_EMAIL_ACCOUNTS_SMTPUSER + "
    "; + } + } + } + if(isError) { + overlay(mod_strings.ERR_MISSING_REQUIRED_FIELDS, errorMessage, 'alert'); + return false; + } else { + return true; + } + }, + + testOutboundSettings: function() { + var errorMessage = ''; + var isError = false; + var fromAddress = document.getElementById("outboundtest_from_address").value; + if (trim(fromAddress) == "") { + errorMessage += app_strings.LBL_EMAIL_SETTINGS_FROM_TO_EMAIL_ADDR + "
    "; + overlay(mod_strings.ERR_MISSING_REQUIRED_FIELDS, errorMessage, 'alert'); + return false; + + } + else if (!isValidEmail(fromAddress)) { + errorMessage += app_strings.LBL_EMAIL_SETTINGS_FROM_TO_EMAIL_ADDR + "
    "; + overlay(mod_strings.ERR_INVALID_REQUIRED_FIELDS, errorMessage, 'alert'); + return false; + } + + //Hide the dialogue and show an in progress indicator. + SE.accounts.testOutboundDialog.hide(); + overlay(app_strings.LBL_EMAIL_PERFORMING_TASK, app_strings.LBL_EMAIL_ONE_MOMENT, 'plain'); + + //If the outbound mail type is a system override we need to re-enable the post fields otherwise + //nothing is sent in the request. + var outboundType = document.forms['outboundEmailForm'].elements['type'].value; + SUGAR.email2.accounts.toggleOutboundAccountDisabledFields(false); + + YAHOO.util.Connect.setForm(document.getElementById("outboundEmailForm")); + if(outboundType == 'system-override') + SUGAR.email2.accounts.toggleOutboundAccountDisabledFields(true); + + var data = "&emailUIAction=testOutbound&outboundtest_from_address=" + fromAddress; + AjaxObject.startRequest(callbackOutboundTest, urlStandard + data); + + }, + + testOutboundSettingsDialog: function() { + //Ensure that all settings are correct before proceeding to send test email. + if(!SE.accounts.checkOutboundSettings()) + return; + + // lazy load dialogue + if(!SE.accounts.testOutboundDialog) { + SE.accounts.testOutboundDialog = new YAHOO.widget.Dialog("testOutboundDialog", { + modal:true, + visible:true, + fixedcenter:true, + constraintoviewport: true, + width : 600, + shadow : true + }); + SE.accounts.testOutboundDialog.setHeader(app_strings.LBL_EMAIL_TEST_OUTBOUND_SETTINGS); + Dom.removeClass("testOutboundDialog", "yui-hidden"); + } // end lazy load + SE.accounts.testOutboundDialog.render(); + SE.accounts.testOutboundDialog.show(); + }, + + /** + * Saves Outbound email settings + */ + saveOutboundSettings : function() { + if(SE.accounts.checkOutboundSettings()) { + //Enable the form fields for the post. + SUGAR.email2.accounts.toggleOutboundAccountDisabledFields(false); + YAHOO.util.Connect.setForm(document.getElementById("outboundEmailForm")); + AjaxObject.startRequest(callbackOutboundSave, urlStandard + "&emailUIAction=saveOutbound"); + } else { + return false; + } + }, + + saveIeAccount : function() { + + //Before saving check if there are any error messages associated with the outbound account. + var outboundID = document.getElementById('outbound_email').value; + + if( SE.accounts.checkIeCreds({'valiateTrash': true,'validateFromAddr': true,'validateOutbound' :true, + 'validateSMTPCreds':true}) ) + { + document.getElementById('saveButton').disabled = true; + + overlay(app_strings.LBL_EMAIL_IE_SAVE, app_strings.LBL_EMAIL_ONE_MOMENT); + + var formObject = document.getElementById('ieAccount'); + YAHOO.util.Connect.setForm(formObject); + + AjaxObject._reset(); + AjaxObject.target = 'frameFlex'; + AjaxObject.startRequest(callbackAccount, urlStandard + '&emailUIAction=saveIeAccount'); + } + }, + + testSettings : function() { + form = document.getElementById('ieAccount'); + + if(SE.accounts.checkIeCreds()) { + ie_test_open_popup_with_submit("InboundEmail", "Popup", "Popup", 400, 300, trim(form.server_url.value), form.protocol.value, trim(form.port.value), trim(form.email_user.value), Rot13.write(form.email_password.value), trim(form.mailbox.value), form.ssl.checked, true, "ieAccount"); + } + }, + + getFoldersListForInboundAccountForEmail2 : function() { + form = document.getElementById('ieAccount'); + if(SE.accounts.checkIeCreds()) { + var mailBoxValue = form.mailbox.value; + if (form.searchField.value.length > 0) { + mailBoxValue = ""; + } // if + getFoldersListForInboundAccount("InboundEmail", "ShowInboundFoldersList", "Popup", 400, 300, form.server_url.value, form.protocol.value, form.port.value, form.email_user.value, Rot13.write(form.email_password.value), mailBoxValue, form.ssl.checked, true, form.searchField.value ); + } // if + + }, + + checkIeCreds : function(validateRules) { + if(typeof(validateRules) == 'undefined') + validateRules = {}; + + var errors = new Array(); + var out = new String(); + + var ie_name = Dom.get('ie_name').value; + var fromAddress = Dom.get('ie_from_addr').value; + var server_url = Dom.get('server_url').value; + var email_user = Dom.get('email_user').value; + var email_password = Dom.get('email_password').value; + var protocol = Dom.get('protocol').value; + var port = Dom.get('port').value; + var oe = Dom.get('outbound_email'); + var oe_value = typeof(oe.options[oe.selectedIndex]) == 'undefined' ? "" : oe.options[oe.selectedIndex].value; + + var outboundUserName = Dom.get('inbound_mail_smtpuser').value; + var outboundPass = Dom.get('inbound_mail_smtppass').value; + + //If the username and password were provided then ignore the error messge + + var outboundCredentialsFound = false; + + if(outboundUserName != "" && outboundPass != "") + outboundCredentialsFound = true; + + var validateSMTPCreds = (typeof(validateRules.validateSMTPCreds) != 'undefined' && validateRules.validateSMTPCreds); + + if ( SE.composeLayout.outboundAccountErrors != null && SE.composeLayout.outboundAccountErrors[oe_value] != null + && validateSMTPCreds) + { + if(trim(outboundUserName) == "") { + errors.push(app_strings.LBL_EMAIL_ACCOUNTS_SMTPUSER); + } + if(trim(outboundPass) == "") { + errors.push(app_strings.LBL_EMAIL_ACCOUNTS_SMTPPASS); + } + } + + if(trim(ie_name) == "") { + errors.push(app_strings.LBL_EMAIL_ERROR_NAME); + } + + if ( typeof(validateRules.validateFromAddr) != 'undefined' && validateRules.validateFromAddr) + { + if(trim(fromAddress) == "" || !isValidEmail(fromAddress) ) { + errors.push(app_strings.LBL_EMAIL_ERROR_FROM_ADDRESS); + } + } + + + if( (typeof(validateRules.validateOutbound) != 'undefined' && validateRules.validateOutbound) && ( trim(oe_value) == "" + || trim(oe_value) == "SYSTEM_ADD") ) { + errors.push(app_strings.LBL_EMAIL_ERROR_NO_OUTBOUND); + } + if(trim(server_url) == "") { + errors.push(app_strings.LBL_EMAIL_ERROR_SERVER); + } + if(trim(email_user) == "") { + errors.push(app_strings.LBL_EMAIL_ERROR_USER); + } + if(protocol == "") { + errors.push(app_strings.LBL_EMAIL_ERROR_PROTOCOL); + } + if (protocol == 'imap') { + var mailbox = document.getElementById('mailbox').value; + if (trim(mailbox) == "") { + errors.push(app_strings.LBL_EMAIL_ERROR_MONITORED_FOLDER); + } // if + if (typeof(validateRules.valiateTrash) != 'undefined' && validateRules.valiateTrash) { + var trashFolder = document.getElementById('trashFolder').value; + if (trim(trashFolder) == "") { + errors.push(app_strings.LBL_EMAIL_ERROR_TRASH_FOLDER); + } // if + } // if + } + if(port == "") { + errors.push(app_strings.LBL_EMAIL_ERROR_PORT); + } + + if(errors.length > 0) { + out = app_strings.LBL_EMAIL_ERROR_DESC; + for(i=0; i 0) { + node.setUpLabel('' + node.data.origText + '(' + node.data.unseen + ')'); + } + else { + node.setUpLabel(node.data.origText); + } + } else { + node.setUpLabel('' + node.data.origText + ''); + } + SE.accounts.setupDDTarget(node); + }, + + setupDDTarget : function(node) { + if (node.ddTarget) { + node.ddTarget.removeFromGroup(); + delete node.ddTarget; + } + var id = node.getElId(); + var num = id.substring(4); + if (node.data.origText != SUGAR.language.get("Emails", "LNK_MY_INBOX") && + node.data.origText != SUGAR.language.get("Emails", "LNK_MY_DRAFTS") && + node.data.origText != SUGAR.language.get("Emails", "LNK_SENT_EMAIL_LIST")) { + + node.ddTarget = new SUGAR.email2.folders.folderDD("ygtvcontentel" + num); + } + else if (node.data.origText == SUGAR.language.get("Emails", "LNK_MY_INBOX")){ + node.ddTarget = new YAHOO.util.DDTarget("ygtvcontentel" + num); + } + }, + + /** + * Async call to rebuild the folder list. After a folder delete or account delete + */ + rebuildFolderList : function() { + overlay(app_strings.LBL_EMAIL_REBUILDING_FOLDERS, app_strings.LBL_EMAIL_ONE_MOMENT); + AjaxObject.startRequest(callbackFolders, urlStandard + '&emailUIAction=rebuildFolders'); + }, + + /** + * Returns the number of remote accounts the user has active. + */ + getAccountCount : function() { + var tree = SE.tree; + var count = 0; + for(i=0; i 25) { + tabLabel = tabLabel.substring(0, 25) + "..."; + } // if + targetDiv.set("label", tabLabel); + targetDiv.set("content", out); + + var displayEmailFrameDiv = document.getElementById('displayEmailFrameDiv' + targetDiv.id); + if (SUGAR.email2.util.isIe()) { + displayEmailFrameDiv.style.height = "390px"; + } else { + displayEmailFrameDiv.style.height = "410px"; + } + + var displayFrame = document.getElementById('displayEmailFrame' + targetDiv.id); + displayFrame.contentWindow.document.write(email.description); + displayFrame.contentWindow.document.close(); + + // hide archive links + if(ret.meta.is_sugarEmail) { + document.getElementById("archiveEmail" + targetDiv.id).style.display = "none"; + document.getElementById("btnEmailView" + targetDiv.id).style.display = "none"; + } else { + if (document.getElementById("showDeialViewForEmail" + targetDiv.id)) + document.getElementById("showDeialViewForEmail" + targetDiv.id).style.display = "none"; + } // else + + }, + + consumeMetaPreview : function(ret) { + // cache contents browser-side + SE._setDetailCache(ret); + + + + var currrow = SE.grid.getLastSelectedRecord(); + currrow = SE.grid.getRecord(currrow); + if (!currrow) { + document.getElementById('_blank').innerHTML = ''; + return; + } + // handling if the Email drafts + if(ret.type == 'draft'){ + if (currrow.getData().uid == ret.uid) { + SE.composeLayout.c0_composeDraft(); + } + return; + } + + if (currrow.getData().uid != ret.meta.uid) { + return; + } + + // remove loading sprite + document.getElementById('_blank').innerHTML = '
    ' + +//' {email.description}' + +'
    ' +; \ No newline at end of file diff --git a/modules/Emails/javascript/email_popup_helper.js b/modules/Emails/javascript/email_popup_helper.js new file mode 100644 index 00000000..08ec9060 --- /dev/null +++ b/modules/Emails/javascript/email_popup_helper.js @@ -0,0 +1,154 @@ +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + + + +function send_back_selected(module, form, field, error_message, field_to_name_array) +{ + // cn: bug 12274 - stripping false-positive security envelope + var temp_request_data = request_data; + if(temp_request_data.jsonObject) { + request_data = temp_request_data.jsonObject; + } else { + request_data = temp_request_data; // passed data that is NOT incorrectly encoded via JSON.encode(); + } + // cn: end bug 12274 fix + + var passthru_data = Object(); + if(typeof(request_data.passthru_data) != 'undefined') + { + passthru_data = request_data.passthru_data; + } + var form_name = request_data.form_name; + var field_to_name_array = request_data.field_to_name_array; + var call_back_function = eval("window.opener." + request_data.call_back_function); + + var array_contents = Array(); + var j=0; + for (i = 0; i < form.elements.length; i++){ + if(form.elements[i].name == field) { + if (form.elements[i].checked == true) { + ++j; + var id = form.elements[i].value; + array_contents_row = Array(); + for(var the_key in field_to_name_array) + { + if(the_key != 'toJSON') + { + var the_name = field_to_name_array[the_key]; + var the_value = ''; + + if(/*module != '' && */id != '') + { + the_value = associated_javascript_data[id][the_key.toUpperCase()]; + } + + array_contents_row.push('"' + the_name + '":"' + the_value + '"'); + } + } + eval("array_contents.push({" + array_contents_row.join(",") + "})"); + } + } + } + + var result_data = {"form_name":form_name,"name_to_value_array":array_contents}; + + if (array_contents.length ==0 ) { + window.alert(error_message); + return; + } + + call_back_function(result_data); + var close_popup = window.opener.get_close_popup(); + + if(close_popup) + { + window.close(); + } +} + +function send_back(module, id) +{ + var associated_row_data = associated_javascript_data[id]; + + // cn: bug 12274 - stripping false-positive security envelope + eval("var temp_request_data = " + window.document.forms['popup_query_form'].request_data.value); + if(temp_request_data.jsonObject) { + var request_data = temp_request_data.jsonObject; + } else { + var request_data = temp_request_data; // passed data that is NOT incorrectly encoded via JSON.encode(); + } + // cn: end bug 12274 fix + + var passthru_data = Object(); + if(typeof(request_data.passthru_data) != 'undefined') + { + passthru_data = request_data.passthru_data; + } + var form_name = request_data.form_name; + var field_to_name_array = request_data.field_to_name_array; + var call_back_function = eval("window.opener." + request_data.call_back_function); + var array_contents = Array(); + + // constructs the array of values associated to the bean that the user clicked + for(var the_key in field_to_name_array) + { + if(the_key != 'toJSON') + { + var the_name = field_to_name_array[the_key]; + var the_value = ''; + + if(module != '' && id != '') + { + the_value = associated_row_data[the_key.toUpperCase()]; + } + + array_contents.push('"' + the_name + '":"' + the_value + '"'); + } + } + + eval("var name_to_value_array = {'0' : {" + array_contents.join(",") + "}}"); + + var result_data = {"form_name":form_name,"name_to_value_array":name_to_value_array,"passthru_data":passthru_data}; + var close_popup = window.opener.get_close_popup(); + + call_back_function(result_data); + + if(close_popup) + { + window.close(); + } +} \ No newline at end of file diff --git a/modules/Emails/javascript/grid.js b/modules/Emails/javascript/grid.js new file mode 100644 index 00000000..b32502bc --- /dev/null +++ b/modules/Emails/javascript/grid.js @@ -0,0 +1,650 @@ +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +function gridInit() { + if(SUGAR.email2.grid) { + SUGAR.email2.grid.destroy(); + } + + e2Grid = { + init : function() { + + var Ck = YAHOO.util.Cookie; + var widths = [ 10, 10, 150, 250, 175, 125 ]; + + if (Ck.get("EmailGridWidths")) { + for (var i=0; i < widths.length; i++) { + widths[i] = Ck.getSub("EmailGridWidths", i+ "", Number); + } + } else { + for (var i=0; i < widths.length; i++) { + Ck.setSub("EmailGridWidths", i + "", widths[i], {expires: SUGAR.email2.nextYear}); + } + } + + // changes "F" to an icon + function flaggedIcon(cell, record, column, value) { + if(value != "") { + cell.innerHTML = "!"; + } + } + // changes "A" to replied icon + function repliedIcon(cell, record, column, value) { + if(value != "") { + cell.innerHTML = ""; + } + } + function attachIcon(cell, record, column, value) { + if(value == "1") { + cell.innerHTML = ""; + } + } + + var colModel = + [ + { + label: "", + width: 10, + sortable: false, + fixed: true, + resizeable: true, + formatter: attachIcon, + key: 'hasAttach' + }, + { + label: "!", + width: widths[0], + sortable: true, + fixed: true, + resizeable: true, + formatter: flaggedIcon, + key: 'flagged' + }, + { + label: "", + width: widths[1], + sortable: true, + fixed: true, + resizeable: true, + formatter: repliedIcon, + key: 'status' + }, + { + label: app_strings.LBL_EMAIL_FROM, + width: widths[2], + sortable: true, + resizeable: true, + key: 'from' + }, + { + label: app_strings.LBL_EMAIL_SUBJECT, + width: widths[3], + sortable: true, + resizeable: true, + key: 'subject' + }, + { + label: mod_strings.LBL_LIST_DATE, + width: widths[4], + sortable: true, + resizeable: true, + key: 'date' + }, + { + label: app_strings.LBL_EMAIL_TO, + width: widths[5], + sortable: false, + resizeable: true, + key: 'to_addrs' + }, + { + label: 'uid', + hidden: true, + key: 'uid' + }, + { + label: 'mbox', + hidden: true, + key: 'mbox' + }, + { + label: 'ieId', + hidden: true, + key: 'ieId' + }, + { + label: 'site_url', + hidden: true, + key: 'site_url' + }, + { label: 'seen', + hidden: true, + key: 'seen' + }, + { label: 'type', + hidden: true, + key: 'type' + } + ]; + + var dataModel = new YAHOO.util.DataSource(urlBase + "?", { + responseType: YAHOO.util.DataSource.TYPE_JSON, + responseSchema: { + resultsList: 'Email', + fields: ['flagged', 'status', 'from', 'subject', 'date','to_addrs', 'uid', 'mbox', 'ieId', 'site_url', 'seen', 'type', 'AssignedTo','hasAttach'], + metaFields: {total: 'TotalCount', unread:"UnreadCount", fromCache: "FromCache"} + } + }); + var params = { + to_pdf : "true", + module : "Emails", + action : "EmailUIAjax", + emailUIAction : "getMessageList", + mbox : "INBOX", + ieId : "", + forceRefresh : "false" + }; + if(lazyLoadFolder != null) { + params['mbox'] = lazyLoadFolder.folder; + params['ieId'] = lazyLoadFolder.ieId; + //Check if the folder is a Sugar Folder + var test = new String(lazyLoadFolder.folder); + if(test.match(/SUGAR\./)) { + params['emailUIAction'] = 'getMessageListSugarFolders'; + params['mbox'] = test.substr(6); + } + } + //dataModel.initPaging(urlBase, SUGAR.email2.userPrefs.emailSettings.showNumInList); + + // create the Grid + var grid = SUGAR.email2.grid = new YAHOO.SUGAR.SelectionGrid('emailGrid', colModel, dataModel, { + MSG_EMPTY: SUGAR.language.get("Emails", "LBL_EMPTY_FOLDER"), + dynamicData: true, + paginator: new YAHOO.widget.Paginator({ + rowsPerPage:parseInt(SUGAR.email2.userPrefs.emailSettings.showNumInList), + containers : ["dt-pag-nav"], + template: "", + firstPageLinkLabel: "", + previousPageLinkLabel: "", + nextPageLinkLabel: "", + lastPageLinkLabel: "" + }), + initialRequest:SUGAR.util.paramsToUrl(params), + width: "800px", + height: "400px" + }); + + initRowDD(); + + //Override Paging request construction + grid.set("generateRequest", function(oState, oSelf) { + oState = oState || {pagination:null, sortedBy:null}; + var sort = (oState.sortedBy) ? oState.sortedBy.key : oSelf.getColumnSet().keys[1].getKey(); + var dir = (oState.sortedBy && oState.sortedBy.dir === YAHOO.widget.DataTable.CLASS_DESC) ? "desc" : "asc"; + var startIndex = (oState.pagination) ? oState.pagination.recordOffset : 0; + var results = (oState.pagination) ? oState.pagination.rowsPerPage : null; + // Build the request + var ret = + SUGAR.util.paramsToUrl(oSelf.params) + + "&sort=" + sort + + "&dir=" + dir + + "&start=" + startIndex + + ((results !== null) ? "&limit=" + results : ""); + return ret; + }); + + + grid.handleDataReturnPayload = function(oRequest, oResponse, oPayload) { + oPayload = oPayload || { }; + + oPayload.totalRecords = oResponse.meta.total; + oPayload.unreadRecords = oResponse.meta.unread; + + var tabObject = SE.innerLayout.get("tabs")[0]; + var mboxTitle = ""; + if (this.params.mbox != null) { + mboxTitle = this.params.mbox; + } + var tabtext = mboxTitle + " (" + oResponse.meta.total + " " + app_strings.LBL_EMAIL_MESSAGES + " )"; + tabObject.get("labelEl").firstChild.data = tabtext; + + if (SE.tree) { + var node = SE.tree.getNodeByProperty('id', this.params.ieId) || SE.tree.getNodeByProperty('origText', this.params.mbox); + if (node) { + node.data.unseen = oResponse.meta.unread; + SE.accounts.renderTree(); + } + } + return oPayload; + } + + var resize = grid.resizeGrid = function () { + SUGAR.email2.grid.set("width", SUGAR.email2.grid.get("element").parentNode.clientWidth + "px"); + SUGAR.email2.grid.set("height", (SUGAR.email2.grid.get("element").parentNode.clientHeight - 47) + "px"); + } + grid.convertDDRows = function() { + var rowEl = this.getFirstTrEl(); + while (rowEl != null) { + new this.DDRow(this, this.getRecord(rowEl), rowEl); + rowEl = this.getNextTrEl(rowEl); + } + } + + + grid.on("columnResizeEvent", function(o) { + //Find the index of the column + var colSet = SUGAR.email2.grid.getColumnSet().flat; + for (var i=0; i < colSet.length; i++) { + if (o.column == colSet[i]) { + //Store it in the cookie + Ck.setSub("EmailGridWidths", i + "", o.width, {expires: SUGAR.email2.nextYear}); + } + } + //this.resizeGrid(); + }, null, grid); + + grid.on("postRenderEvent", function() {this.convertDDRows()}, null, grid); + grid.on("rowClickEvent", SUGAR.email2.listView.handleClick); + grid.on("rowDblclickEvent", SUGAR.email2.listView.getEmail); + grid.render(); + SUGAR.email2.listViewLayout.on("render", resize); + resize(); + + //Setup the default load parameters + SUGAR.email2.grid.params = params; + + grid.on('postRenderEvent', SUGAR.email2.listView.setEmailListStyles); + dataModel.subscribe("requestEvent", grid.disable, grid, true); + dataModel.subscribe("responseParseEvent", grid.undisable, grid, true); + } + }; + e2Grid.init(); +}; + + +function initRowDD() { + var sg = SUGAR.email2.grid, + Dom = YAHOO.util.Dom; + sg.DDRow = function(oDataTable, oRecord, elTr) { + if(oDataTable && oRecord && elTr) { + this.ddtable = oDataTable; + this.table = oDataTable.getTableEl(); + this.row = oRecord; + this.rowEl = elTr; + this.newIndex = null; + this.init(elTr); + this.initFrame(); // Needed for DDProxy + this.invalidHandleTypes = {}; + } + }; + + YAHOO.extend(sg.DDRow, YAHOO.util.DDProxy, { + _resizeProxy: function() { + this.constructor.superclass._resizeProxy.apply(this, arguments); + var dragEl = this.getDragEl(), + el = this.getEl(); + var xy = Dom.getXY(el); + + Dom.setStyle(dragEl, 'height', this.rowEl.offsetHeight + "px"); + Dom.setStyle(dragEl, 'width', (parseInt(Dom.getStyle(dragEl, 'width'),10) + 4) + 'px'); + Dom.setXY(dragEl, [xy[0] - 100, xy[1] - 20] ); + Dom.setStyle(dragEl, 'display', ""); + }, + + startDrag: function(x, y) { + //Check if we should be dragging a set of rows rather than just the one. + var selectedRows = this.ddtable.getSelectedRows(); + var iSelected = false; + for (var i in selectedRows) { + if (this.rowEl.id == selectedRows[i]) { + iSelected = true; + break + } + } + if (iSelected) { + this.rows = []; + for (var i in selectedRows) { + this.rows[i] = this.ddtable.getRecord(selectedRows[i]); + } + } else { + this.rows = [this.row]; + this.ddtable.unselectAllRows(); + this.ddtable.selectRow(this.row); + } + + //Initialize the dragable proxy + var dragEl = this.getDragEl(); + var clickEl = this.getEl(); + Dom.setStyle(clickEl, "opacity", "0.25"); + dragEl.innerHTML = "" + clickEl.innerHTML + "
    "; + Dom.addClass(dragEl, "yui-dt-liner"); + Dom.setStyle(dragEl, "opacity", "0.5"); + Dom.setStyle(dragEl, "height", (clickEl.clientHeight - 2) + "px"); + Dom.setStyle(dragEl, "backgroundColor", Dom.getStyle(clickEl, "backgroundColor")); + Dom.setStyle(dragEl, "border", "2px solid gray"); + }, + + clickValidator: function(e) { + if (this.row.getData()[0] == " ") + return false; + var target = YAHOO.util.Event.getTarget(e); + return ( this.isValidHandleChild(target) && + (this.id == this.handleElId || this.DDM.handleWasClicked(target, this.id)) ); + }, + /** + * This funciton checks that the target of the drag is a table row in this + * DDGroup and simply moves the sourceEL to that location as a preview. + */ + onDragOver: function(ev, id) { + var node = SUGAR.email2.tree.getNodeByElement(Dom.get(id)); + if (node && node != this.targetNode) { + this.targetNode = node; + SUGAR.email2.folders.unhighliteAll(); + node.highlight(); + } + }, + + onDragOut: function(e, id) { + if (this.targetNode) { + SUGAR.email2.folders.unhighliteAll(); + this.targetNode = false; + } + }, + endDrag: function() { + Dom.setStyle(this.getEl(), "opacity", ""); + Dom.setStyle(this.getDragEl(), "display", "none"); + if (this.targetNode) { + SUGAR.email2.folders.handleDrop(this.rows, this.targetNode); + } + SUGAR.email2.folders.unhighliteAll(); + this.rows = null; + } + }); +} + +function AddressSearchGridInit() { + function moduleIcon(elCell, oRecord, oColumn, oData) { + elCell.innerHTML = ""; + }; + function selectionCheckBox(elCell, oRecord, oColumn, oData) { + elCell.innerHTML = ''; + }; + var checkHeader = '{FirstPageLink} {PreviousPageLink} {PageLinks} {NextPageLink} {LastPageLink}
    ", + firstPageLinkLabel: "", + previousPageLinkLabel: "", + nextPageLinkLabel: "", + lastPageLinkLabel: "" + }), + initialRequest:SUGAR.util.paramsToUrl(dataModel.params), + width: "560px", + height: "250px" + }); + //Override Paging request construction + grid.set("generateRequest", function(oState, oSelf) { + oState = oState || {pagination:null, sortedBy:null}; + var sort = (oState.sortedBy) ? oState.sortedBy.key : oSelf.getColumnSet().keys[0].getKey(); + var dir = (oState.sortedBy && oState.sortedBy.dir === YAHOO.widget.DataTable.CLASS_DESC) ? "desc" : "asc"; + var startIndex = (oState.pagination) ? oState.pagination.recordOffset : 0; + var results = (oState.pagination) ? oState.pagination.rowsPerPage : null; + // Build the request + var ret = + SUGAR.util.paramsToUrl(oSelf.getDataSource().params) + + "&sort=" + sort + "&dir=" + dir + "&start=" + startIndex + + ((results !== null) ? "&limit=" + results : ""); + return ret; + }); + + grid.handleDataReturnPayload = function(oRequest, oResponse, oPayload) { + oPayload = oPayload || { }; + oPayload.totalRecords = oResponse.meta.total; + return oPayload; + } + + grid.clickToggleSelect= function(args) { + var isIE = (args.event.target == null); + var targetElement = isIE ? args.event.srcElement : args.event.target; + if(targetElement.type == null || targetElement.type != 'checkbox') { + SUGAR.email2.addressBook.grid.toggleSelect(args.target.id); + } + } + + grid.reSelectRowsOnRender = function (){ + var rows = SUGAR.email2.addressBook.grid.getRecordSet().getRecords(); + for (var i = 0; i < rows.length; i++) + { + var emailAddress = rows[i].getData("email"); + var alreadyAdded = SUGAR.email2.addressBook.doesEmailAdddressExistInResultTable(emailAddress); + if(alreadyAdded) + { + rows[i].setData("selected", true); + SUGAR.email2.addressBook.grid.selectRow(rows[i]); + } + else + { + rows[i].setData("selected", false); + SUGAR.email2.addressBook.grid.unselectRow(rows[i]); + } + } + } + grid.subscribe("rowMouseoverEvent", grid.onEventHighlightRow); + grid.subscribe("rowMouseoutEvent", grid.onEventUnhighlightRow); + grid.subscribe("rowClickEvent", grid.clickToggleSelect); + grid.subscribe("postRenderEvent", grid.reSelectRowsOnRender); + + grid.render(); + dataModel.subscribe("requestEvent", grid.disable, grid, true); + dataModel.subscribe("responseParseEvent", grid.undisable, grid, true); + + grid.toggleSelectCheckbox = function(id,checked){ + var row = SUGAR.email2.addressBook.grid.getRecord(id); + row.setData("checked",checked); + }; + grid.toggleSelect = function(id, checked) { + var row = SUGAR.email2.addressBook.grid.getRecord(id); + checked = row.getData("selected"); + if (!checked) + { + SUGAR.email2.addressBook.grid.selectRow(row); + SE.addressBook.insertContactRowToResultTable(id,null) + } else + { + SUGAR.email2.addressBook.grid.unselectRow(row); + SE.addressBook.removeRowFromGridResults(id,row.getData("email")); + } + row.setData("selected", !checked); + }; + + grid.toggleSelectAll = function(checked) { + rows = SUGAR.email2.addressBook.grid.getRecordSet().getRecords(); + for (var i = 0; i < rows.length; i++) { + if (typeof(rows[i]) != "undefined") + rows[i].setData("checked", checked); + } + var checkBoxes = SUGAR.email2.addressBook.grid.get("element").getElementsByTagName('input'); + for (var i = 0; i < checkBoxes.length; i++) { + checkBoxes[i].checked = checked; + } + }; + + //Initialize the grid result table. + AddressSearchResultsGridInit(); +} + + + +/** +* Initalize the results table for the address book selection. +* +*/ +function AddressSearchResultsGridInit() +{ + + /* Full name sort funciton to compare by last name if available */ + var fullNameSort = function(a, b, desc) { + // Deal with empty values + if(!YAHOO.lang.isValue(a)) + return (!YAHOO.lang.isValue(b)) ? 0 : 1; + else if(!YAHOO.lang.isValue(b)) + return -1; + + var aNames = a.getData("name").split(' '); + var bNames = b.getData("name").split(' '); + + var aSortField = (aNames.length == 2) ? aNames[1] : a.getData("name"); + var bSortField = (bNames.length == 2) ? bNames[1] : b.getData("name"); + + return YAHOO.util.Sort.compare(aSortField,bSortField, desc); + + }; + + var typeDdOptions = [app_strings.LBL_EMAIL_ADDRESS_BOOK_ADD_TO.replace(/:$/,'') , + app_strings.LBL_EMAIL_ADDRESS_BOOK_ADD_CC.replace(/:$/,''), + app_strings.LBL_EMAIL_ADDRESS_BOOK_ADD_BCC.replace(/:$/,'')]; + + var ColumnDefs = [{key:'type',label:app_strings.LBL_EMAIL_ADDRESS_BOOK_ADRRESS_TYPE, width: 60, sortable: true, editor: new YAHOO.widget.RadioCellEditor({radioOptions:typeDdOptions,disableBtns:true})}, + {key:'name',label:app_strings.LBL_EMAIL_ACCOUNTS_NAME,width: 280,sortable: true, sortOptions:{sortFunction:fullNameSort}}]; + + var myDataSource = new YAHOO.util.DataSource([]); + myDataSource.responseType = YAHOO.util.DataSource.TYPE_JSARRAY; + myDataSource.responseSchema = { + fields: ["name","type","email_address","display_email_address","bean_id","idx"] + }; + + var gridResults = SUGAR.email2.addressBook.gridResults = new YAHOO.widget.ScrollingDataTable("addrSearchResultGrid", ColumnDefs, myDataSource, { + width: "350px",height: "250px", MSG_EMPTY: " "}); + + var highlightEditableCell = function(oArgs) { + var elCell = oArgs.target; + if(YAHOO.util.Dom.hasClass(elCell, "yui-dt-editable")) { + this.highlightCell(elCell); + } + }; + + gridResults.subscribe("cellMouseoverEvent", highlightEditableCell); + gridResults.subscribe("cellMouseoutEvent", gridResults.onEventUnhighlightCell); + gridResults.subscribe("cellClickEvent", gridResults.onEventShowCellEditor); + gridResults.subscribe("rowMouseoverEvent", gridResults.onEventHighlightRow); + gridResults.subscribe("rowMouseoutEvent", gridResults.onEventUnhighlightRow); + + //Setup the context menus + var onContextMenuClick = function(p_sType, p_aArgs, p_myDataTable) { + var task = p_aArgs[1]; + if(task) + { + var elRow = this.contextEventTarget; + elRow = p_myDataTable.getTrEl(elRow); + + if(elRow) + { + switch(task.index) + { + case 0: + var oRecord = p_myDataTable.getRecord(elRow); + p_myDataTable.deleteRow(elRow); + SUGAR.email2.addressBook.grid.reSelectRowsOnRender(); + } + } + } + }; + var contextMenu = new YAHOO.widget.ContextMenu("contextmenu", + {trigger:gridResults.getTbodyEl()}); + contextMenu.addItem(app_strings.LBL_EMAIL_DELETE); + contextMenu.render("addrSearchResultGrid"); + contextMenu.clickEvent.subscribe(onContextMenuClick, gridResults); +} diff --git a/modules/Emails/javascript/init.js b/modules/Emails/javascript/init.js new file mode 100644 index 00000000..17599f13 --- /dev/null +++ b/modules/Emails/javascript/init.js @@ -0,0 +1,461 @@ +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + +/****************************************************************************** + * Initialize Email 2.0 Application + */ + +//Override Sugar Languge so quick creates work properly + + +function email2init() { + + //Init Tiny MCE + // var tinyConfig = "code,bold,italic,underline,strikethrough,separator,justifyleft,justifycenter,justifyright,justifyfull," + + // "separator,bullist,numlist,outdent,indent,separator,forecolor,backcolor,fontselect,fontsizeselect"; + if (!SUGAR.util.isTouchScreen()) { + tinyMCE.init({ + convert_urls : false, + theme_advanced_toolbar_align : tinyConfig.theme_advanced_toolbar_align, + width: tinyConfig.width, + theme: tinyConfig.theme, + theme_advanced_toolbar_location : tinyConfig.theme_advanced_toolbar_location, + theme_advanced_buttons1 : tinyConfig.theme_advanced_buttons1, + theme_advanced_buttons2 : tinyConfig.theme_advanced_buttons2, + theme_advanced_buttons3 : tinyConfig.theme_advanced_buttons3, + plugins : tinyConfig.plugins, + elements : tinyConfig.elements, + language : tinyConfig.language, + extended_valid_elements : tinyConfig.extended_valid_elements, + mode: tinyConfig.mode, + strict_loading_mode : true, + force_br_newlines : true, + forced_root_block : '', + directionality : (typeof(rtl) == "undefined") ? "ltr" : "rtl" + }); + } + + // initialze message overlay + SUGAR.email2.e2overlay = new YAHOO.widget.Dialog("SUGAR.email2.e2overlay", { + //iframe : true, + modal : false, + autoTabs : true, + width : 300, + height : 120, + shadow : true + } + ); + // Hide Sugar menu + if (SUGAR.themes.tempHideLeftCol) + SUGAR.themes.tempHideLeftCol(); + + // add key listener for kb shortcust - disable backspace nav in mozilla/ie +// YAHOO.util.Event.addListener(window.document, 'keypress', SUGAR.email2.keys.overall); + + // set defaults for YAHOO.util.DragDropManager + YAHOO.util.DDM.mode = 0; // point mode, default is point (0) + + SUGAR.email2.nextYear = new Date(); + SUGAR.email2.nextYear.setDate(SUGAR.email2.nextYear.getDate() + 360); + + + // initialize and display UI framework (complexLayout.js) + complexLayoutInit(); + + // initialize and display grid (grid.js) + gridInit(); + + // initialize treeview for folders + //onloadTreeinit(); + SUGAR.email2.folders.rebuildFolders(true); + + + //Setup the Message Box overlay + /*Ext.MessageBox.maxWidth = 350; + Ext.MessageBox.minProgressWidth = 350; + + /////////////////////////////////////////////////////////////////////////// + //// CONTEXT MENUS + // detailView array + SUGAR.email2.contextMenus.detailViewContextMenus = new Object(); +*/ + var SEC = SUGAR.email2.contextMenus; + + //Grid menu + var emailMenu = SEC.emailListContextMenu = new YAHOO.widget.ContextMenu("emailContextMenu", { + trigger: SUGAR.email2.grid.get("element"), + lazyload: true + }); + emailMenu.subscribe("beforeShow", function() { + var oTarget = this.contextEventTarget; + if (typeof(oTarget) == "undefined") + return; + var grid = SUGAR.email2.grid; + var selectedRows = grid.getSelectedRows(); + var multipleSelected = (selectedRows.length > 1) ? true: false; + if (!multipleSelected) + { + grid.unselectAllRows(); + grid.selectRow(oTarget); + SUGAR.email2.contextMenus.showEmailsListMenu(grid, grid.getRecord(oTarget)); + } + else if(multipleSelected) + { + SUGAR.email2.contextMenus.showEmailsListMenu(grid, grid.getRecord(oTarget)); + } + }); + + //When we need to access menu items later we can only do so by indexes so we create a mapping to allow + //us to access individual elements easier by name rather than by index + emailMenu.itemsMapping = {'viewRelationships':0, 'openMultiple': 1, 'archive' : 2, 'reply' : 3,'replyAll' : 4,'forward' : 5, + 'delete' : 6,'print' : 7,'mark' : 8,'assignTo' : 9, 'relateTo' : 10}; + emailMenu.addItems([ + { + text: "" + app_strings.LBL_EMAIL_VIEW_RELATIONSHIPS, + id: 'showDetailView', + onclick: { fn: SEC.showDetailView } + }, + { + text: "" + app_strings.LBL_EMAIL_OPEN_ALL, + onclick: { fn: SEC.openMultiple } + }, + { + text: "" + app_strings.LBL_EMAIL_ARCHIVE_TO_SUGAR, + onclick: { fn: SEC.archiveToSugar } + }, + { + text: ""+ app_strings.LBL_EMAIL_REPLY, + id: 'reply', + onclick: { fn: SEC.replyForwardEmailContext } + }, + { + text: "" + app_strings.LBL_EMAIL_REPLY_ALL, + id: 'replyAll', + onclick: { fn: SEC.replyForwardEmailContext } + }, + { + text: "" + app_strings.LBL_EMAIL_FORWARD, + id: 'forward', + onclick: { fn: SEC.replyForwardEmailContext } + }, + { + text: "" + app_strings.LBL_EMAIL_DELETE, + id: 'delete', + onclick: { fn: SEC.markDeleted } + }, + { + text: "" + app_strings.LBL_EMAIL_PRINT, + id: 'print', + onclick: { fn: SEC.viewPrintable } + }, + // Mark... submenu + { + text: "" + app_strings.LBL_EMAIL_MARK, + submenu: { + id: "markEmailMenu", + itemdata : [ + { + text: app_strings.LBL_EMAIL_MARK + " " + app_strings.LBL_EMAIL_MARK_UNREAD, + onclick: { fn: SEC.markUnread } + }, + { + text: app_strings.LBL_EMAIL_MARK + " " + app_strings.LBL_EMAIL_MARK_READ, + onclick: { fn: SEC.markRead } + }, + { + text: app_strings.LBL_EMAIL_MARK + " " + app_strings.LBL_EMAIL_MARK_FLAGGED, + onclick: { fn: SEC.markFlagged } + }, + { + text: app_strings.LBL_EMAIL_MARK + " " + app_strings.LBL_EMAIL_MARK_UNFLAGGED, + onclick: { fn: SEC.markUnflagged } + } + ] + } + }, + { + text: "" + app_strings.LBL_EMAIL_ASSIGN_TO, + id: 'assignTo', + onclick: { fn: SEC.assignEmailsTo } + }, + { + text: "" + app_strings.LBL_EMAIL_RELATE_TO, + id: 'relateTo', + onclick: { fn: SEC.relateTo } + } + ]); + SEC.emailListContextMenu.render(); + + //Handle the Tree folder menu trigger ourselves + YAHOO.util.Event.addListener(YAHOO.util.Dom.get("emailtree"), "contextmenu", SUGAR.email2.folders.handleRightClick) + + + //Folder Menu + SEC.frameFoldersContextMenu = new YAHOO.widget.ContextMenu("folderContextMenu", { + trigger: "", + lazyload: true + }); + SEC.frameFoldersContextMenu.addItems([ + { text: "" + app_strings.LBL_EMAIL_CHECK, + //helptext: "" + app_strings.LBL_EMAIL_MENU_HELP_ADD_FOLDER + "", + onclick: { fn: function() { + var node = SUGAR.email2.clickedFolderNode; + if (node.data.ieId) { + SUGAR.email2.folders.startEmailCheckOneAccount(node.data.ieId, false)}; + }} + }, + { text: app_strings.LBL_EMAIL_MENU_SYNCHRONIZE, + //helptext: "" + app_strings.LBL_EMAIL_MENU_HELP_ADD_FOLDER + "", + onclick: { fn: function() { + var node = SUGAR.email2.clickedFolderNode; + if (node.data.ieId) { + SUGAR.email2.folders.startEmailCheckOneAccount(node.data.ieId, true)}; + }} + }, + { + text: app_strings.LBL_EMAIL_MENU_ADD_FOLDER, + //helptext: "" + app_strings.LBL_EMAIL_MENU_HELP_ADD_FOLDER + "", + onclick: { fn: SUGAR.email2.folders.folderAdd } + }, + { + text: app_strings.LBL_EMAIL_MENU_DELETE_FOLDER, + //helptext: "" + app_strings.LBL_EMAIL_MENU_HELP_DELETE_FOLDER + "", + onclick: { fn: SUGAR.email2.folders.folderDelete } + }, + { + text: app_strings.LBL_EMAIL_MENU_RENAME_FOLDER, + //helptext: "" + app_strings.LBL_EMAIL_MENU_HELP_RENAME_FOLDER + "", + onclick: { fn: SUGAR.email2.folders.folderRename } + }, + { + text: app_strings.LBL_EMAIL_MENU_EMPTY_TRASH, + //helptext: "" + app_strings.LBL_EMAIL_MENU_HELP_EMPTY_TRASH + "", + onclick: { fn: SUGAR.email2.folders.emptyTrash } + }, + { + text: app_strings.LBL_EMAIL_MENU_CLEAR_CACHE, + onclick: { fn: function() { + var node = SUGAR.email2.clickedFolderNode; + if (node.data.ieId) { + SUGAR.email2.folders.clearCacheFiles(node.data.ieId)}; + }} + } + ]); + SEC.frameFoldersContextMenu.render(); + + SEC.initContactsMenu = function() { + // contacts + SEC.contactsContextMenu = new YAHOO.widget.ContextMenu("contactsMenu", { + trigger: "contacts", + lazyload: true + }); + SEC.contactsContextMenu.addItems([ + { + text: app_strings.LBL_EMAIL_MENU_REMOVE, + onclick:{ fn: SUGAR.email2.addressBook.removeContact } + }, + { + text: app_strings.LBL_EMAIL_MENU_COMPOSE, + onclick:{ fn: function() {SUGAR.email2.addressBook.composeTo('contacts')}} + } + ]); + SEC.contactsContextMenu.subscribe("beforeShow", function() { + var oTarget = this.contextEventTarget, grid = SUGAR.email2.contactView; + if (oTarget && !grid.isSelected(oTarget)) { + grid.unselectAllRows(); + grid.selectRow(oTarget); + } + }); + SEC.contactsContextMenu.render(); + } + + + // set auto-check timer + SUGAR.email2.folders.startCheckTimer(); + // check if we're coming from an email-link click + setTimeout("SUGAR.email2.composeLayout.composePackage()", 2000); + + YAHOO.util.Event.on(window, 'resize', SUGAR.email2.autoSetLayout); + + //Init fix for YUI 2.7.0 datatable sort. + SUGAR.email2.addressBook.initFixForDatatableSort(); +} + +function createTreePanel(treeData, params) { + var tree = new YAHOO.widget.TreeView(params.id); + var root = tree.getRoot(); + + //if (treeData.nodes && treeData[0].id == "Home") + // treeData = treeData[0]; + + addChildNodes(root, treeData); + + return tree; +} + +function addChildNodes(parentNode, parentData) { + var Ck = YAHOO.util.Cookie; + var nextyear = SUGAR.email2.nextYear; + var nodes = parentData.nodes || parentData.children; + for (i in nodes) { + if (typeof(nodes[i]) == 'object') { + if (nodes[i].data) { + nodes[i].data.href = '#'; + var node = new YAHOO.widget.TextNode(nodes[i].data, parentNode) + node.action = nodes[i].data.action; + } else { + if (nodes[i].id == SUGAR.language.get('app_strings','LBL_EMAIL_HOME_FOLDER')) { + addChildNodes(parentNode, nodes[i]); + return; + } + nodes[i].expanded = Ck.getSub("EmailTreeLayout", nodes[i].id + "") == "true"; + Ck.setSub("EmailTreeLayout", nodes[i].id + "", nodes[i].expanded ? true : false, {expires: SUGAR.email2.nextYear}); + if (nodes[i].cls) { + nodes[i].className = nodes[i].cls; + } + nodes[i].href = "#"; + if (nodes[i].text) nodes[i].label = nodes[i].text; + //Override YUI child node creation + if (nodes[i].children) { + nodes[i].nodes = nodes[i].children; + nodes[i].children = [ ]; + } + var node = new YAHOO.widget.TextNode(nodes[i], parentNode); + } + + if (typeof(nodes[i].nodes) == 'object') { + addChildNodes(node, nodes[i]); + } + } + } +} + +/** + * Custom TreeView initialization sequence to setup DragDrop targets for every tree node + */ +function email2treeinit(tree, treedata, treediv, params) { + //ensure the tree data is not corrupt + if (!treedata) { + return; + } + if (SUGAR.email2.tree) { + SUGAR.email2.tree.destroy(); + SUGAR.email2.tree = null; + } + + var tree = SUGAR.email2.tree = createTreePanel({nodes : {}}, { + id: 'emailtree' + }); + + tree.subscribe("clickEvent", SUGAR.email2.folders.handleClick); + tree.subscribe("collapseComplete", function(node){YAHOO.util.Cookie.setSub("EmailTreeLayout", node.data.id + "", false, {expires: SUGAR.email2.nextYear});}); + tree.subscribe("expandComplete", function(node){ + YAHOO.util.Cookie.setSub("EmailTreeLayout", node.data.id + "", true, {expires: SUGAR.email2.nextYear}); + for (var i in node.children) { + SE.accounts.setupDDTarget(node.children[i]); + } + }); + tree.setCollapseAnim("TVSlideOut"); + tree.setExpandAnim("TVSlideIn"); + var root = tree.root; + while (root.hasChildren()) { + var node = root.children[0]; + node.destroy(); + tree.removeNode(root.children[0], false); + } + addChildNodes(root, treedata); + tree.render(); + SUGAR.email2.accounts.renderTree(); +} + +SUGAR.email2.folders.folderDD = function(id, sGroup, config) { + SUGAR.email2.folders.folderDD.superclass.constructor.call(this, id, sGroup, config); +}; + + +YAHOO.extend(SUGAR.email2.folders.folderDD, YAHOO.util.DDProxy, { + startDrag: function(x, y) { + var Dom = YAHOO.util.Dom; + this.dragNode = SUGAR.email2.tree.getNodeByElement(this.getEl()); + + this.dragId = ""; + var dragEl = this.getDragEl(); + var clickEl = this.getEl(); + Dom.setStyle(clickEl, "color", "#AAA"); + Dom.setStyle(clickEl, "opacity", "0.25"); + dragEl.innerHTML = clickEl.innerHTML; + + Dom.addClass(dragEl, "ygtvcell"); + Dom.addClass(dragEl, "ygtvcontent"); + Dom.addClass(dragEl, "folderDragProxy"); + Dom.setStyle(dragEl, "height", (clickEl.clientHeight - 5) + "px"); + Dom.setStyle(dragEl, "width", (clickEl.clientWidth - 5) + "px"); + Dom.setStyle(dragEl, "backgroundColor", "#FFF"); + Dom.setStyle(dragEl, "opacity", "0.5"); + Dom.setStyle(dragEl, "border", "1px solid #AAA"); + }, + + onDragOver: function(ev, id) { + var Dom = YAHOO.util.Dom; + if (id != this.dragId) + { + var node = SUGAR.email2.tree.getNodeByElement(YAHOO.util.Dom.get(id)); + if(node.data.cls != "sugarFolder") { + SUGAR.email2.folders.unhighliteAll(); + return; + } + this.dragId = id; + this.targetNode = node; + SUGAR.email2.folders.unhighliteAll(); + node.highlight(); + } + }, + + onDragOut: function(e, id) { + if (this.targetNode) { + SUGAR.email2.folders.unhighliteAll(); + this.targetNode = false; + this.dragId = false; + } + }, + + endDrag: function() { + YAHOO.util.Dom.setStyle(this.getEl(), "opacity", "1.0"); + if (this.targetNode) { + SUGAR.email2.folders.moveFolder(this.dragNode.data.id, this.targetNode.data.id); + } + } +}); \ No newline at end of file diff --git a/modules/Emails/javascript/vars.js b/modules/Emails/javascript/vars.js new file mode 100644 index 00000000..6d838713 --- /dev/null +++ b/modules/Emails/javascript/vars.js @@ -0,0 +1,53 @@ +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +var req; +var target; +var flexContentOld = ""; +var forcePreview = false; +var inCompose = false; + +/* globals for Callback functions */ +var email; // AjaxObject.showEmailPreview +var ieId; +var ieName; +var focusFolder; +var meta; // AjaxObject.showEmailPreview +var sendType; +var targetDiv; +var urlBase = 'index.php'; +var urlStandard = 'sugar_body_only=true&to_pdf=true&module=Emails&action=EmailUIAjax'; + +var lazyLoadFolder = null; \ No newline at end of file diff --git a/modules/Emails/javascript/viewPrintable.js b/modules/Emails/javascript/viewPrintable.js new file mode 100644 index 00000000..eee203df --- /dev/null +++ b/modules/Emails/javascript/viewPrintable.js @@ -0,0 +1,105 @@ +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +SUGAR.email2.templates['viewPrintable'] = '' + +'' + +'' + +'
    ' + +'' + +' ' + +' ' + +' ' + +' ' + +' ' + +' ' + +'
    ' + +' ' + +' ' + +' ' + +' ' + +' ' + +' ' + +' ' + +' ' + +' ' + +' ' + +' ' + +' ' + +' ' + +' ' + +' ' + +' ' + +' ' + +' {email.cc}' + +' {email.attachments}' + +'
    ' + +' {app_strings.LBL_EMAIL_FROM}:' + +' ' + +' {email.from_name} <{email.from_addr}>' + +'
    ' + +' {app_strings.LBL_EMAIL_SUBJECT}:' + +' ' + +' {email.name}' + +'
    ' + +' {app_strings.LBL_EMAIL_DATE_SENT_BY_SENDER}:' + +' ' + +' {email.date_start} {email.time_start}' + +'
    ' + +' {app_strings.LBL_EMAIL_TO}:' + +' ' + +' {email.toaddrs}' + +'
    ' + +'
    ' + +' ' + +' ' + +' ' + +' ' + +'
    ' + +'
    ' + + '{email.description}' + +'
    ' + +'
    ' + +'
    ' + +'
    ' + +''; diff --git a/modules/Emails/language/en_us.lang.php b/modules/Emails/language/en_us.lang.php new file mode 100644 index 00000000..2ff0e9f0 --- /dev/null +++ b/modules/Emails/language/en_us.lang.php @@ -0,0 +1,371 @@ + 'FW:', + 'LBL_RE' => 'RE:', + + 'LBL_BUTTON_CREATE' => 'Create', + 'LBL_BUTTON_EDIT' => 'Edit', + 'LBL_QS_DISABLED' => '(QuickSearch is not availible for this module. Please use the select button.)', + 'LBL_SIGNATURE_PREPEND' => 'Signature above reply', + 'LBL_EMAIL_DEFAULT_DESCRIPTION' => 'Here is the quote you requested (You can change this text)', + 'LBL_EMAIL_QUOTE_FOR' => 'Quote for: ', + 'LBL_QUOTE_LAYOUT_DOES_NOT_EXIST_ERROR' => 'quote layout file does not exist: $layout', + 'LBL_QUOTE_LAYOUT_REGISTERED_ERROR' => 'quote layout is not registered in modules/Quotes/Layouts.php', + + + 'LBL_CONFIRM_DELETE' => 'Are you sure you want to delete this folder?', + 'LBL_ENTER_FOLDER_NAME' => 'Please enter a folder name', + + 'LBL_ERROR_SELECT_MODULE' => 'Please select a module for the Related to field', + + 'ERR_ARCHIVE_EMAIL' => 'Error: Select emails to archive.', + 'ERR_DATE_START' => 'Date Start', + 'ERR_DELETE_RECORD' => 'Error: You must specify a record number to delete the account.', + 'ERR_NOT_ADDRESSED' => 'Error: Email must have a To, CC, or BCC address', + 'ERR_TIME_START' => 'Time Start', + 'ERR_TIME_SENT' => 'Time Sent', + 'LBL_ACCOUNTS_SUBPANEL_TITLE'=> 'Accounts', + 'LBL_ADD_ANOTHER_FILE' => 'Add Another File', + 'LBL_ADD_DASHLETS' => 'Add Sugar Dashlets', + 'LBL_ADD_DOCUMENT' => 'Add Documents', + 'LBL_ADD_ENTRIES' => 'Add Entries', + 'LBL_ADD_FILE' => 'Add Files', + 'LBL_ARCHIVED_EMAIL' => 'Archived Email', + 'LBL_ARCHIVED_MODULE_NAME' => 'Create Archived Emails', + 'LBL_ATTACHMENTS' => 'Attachments:', + 'LBL_HAS_ATTACHMENT' => 'Has Attachment?:', + 'LBL_BCC' => 'Bcc:', + 'LBL_BODY' => 'Body:', + 'LBL_BUGS_SUBPANEL_TITLE' => 'Bugs', + 'LBL_CC' => 'Cc:', + 'LBL_COLON' => ':', + 'LBL_COMPOSE_MODULE_NAME' => 'Compose Email', + 'LBL_CONTACT_FIRST_NAME' => 'Contact First Name', + 'LBL_CONTACT_LAST_NAME' => 'Contact Last Name', + 'LBL_CONTACT_NAME' => 'Contact:', + 'LBL_CONTACTS_SUBPANEL_TITLE'=> 'Contacts', + 'LBL_CREATED_BY' => 'Created by', + 'LBL_DATE_AND_TIME' => 'Date & Time Sent:', + 'LBL_DATE_SENT' => 'Date Sent:', + 'LBL_DATE' => 'Date Sent:', + 'LBL_DELETE_FROM_SERVER' => 'Delete message from server', + 'LBL_DESCRIPTION' => 'Description', + 'LBL_EDIT_ALT_TEXT' => 'Edit Plain Text', + 'LBL_SEND_IN_PLAIN_TEXT' => 'Send in Plain Text', + 'LBL_EDIT_MY_SETTINGS' => 'Edit My Settings', + 'LBL_EMAIL_ATTACHMENT' => 'Email Attachment', + 'LBL_EMAIL_EDITOR_OPTION' => 'Send HTML Email', + 'LBL_EMAIL_SELECTOR' => 'Select', + 'LBL_EMAIL' => 'Email Address:', + 'LBL_EMAILS_ACCOUNTS_REL' => 'Emails:Accounts', + 'LBL_EMAILS_BUGS_REL' => 'Emails:Bugs', + 'LBL_EMAILS_CASES_REL' => 'Emails:Cases', + 'LBL_EMAILS_CONTACTS_REL' => 'Emails:Contacts', + 'LBL_EMAILS_LEADS_REL' => 'Emails:Leads', + 'LBL_EMAILS_OPPORTUNITIES_REL'=> 'Emails:Opportunities', + 'LBL_EMAILS_NOTES_REL' => 'Emails:Notes', + 'LBL_EMAILS_PROJECT_REL' => 'Emails:Project', + 'LBL_EMAILS_PROJECT_TASK_REL'=> 'Emails:ProjectTask', + 'LBL_EMAILS_PROSPECT_REL' => 'Emails:Prospect', + 'LBL_EMAILS_TASKS_REL' => 'Emails:Tasks', + 'LBL_EMAILS_USERS_REL' => 'Emails:Users', + 'LBL_EMPTY_FOLDER' => 'No Emails to display', + 'LBL_ERROR_SENDING_EMAIL' => 'Error Sending email', + 'LBL_ERROR_SAVING_DRAFT' => 'Error Saving Draft', + 'LBL_FORWARD_HEADER' => 'Begin forwarded message:', + 'LBL_FROM_NAME' => 'From Name', + 'LBL_FROM' => 'From:', + 'LBL_REPLY_TO' => 'Reply To:', + 'LBL_HTML_BODY' => 'HTML Body', + 'LBL_INVITEE' => 'Recipients', + 'LBL_LEADS_SUBPANEL_TITLE' => 'Leads', + 'LBL_MESSAGE_SENT' => 'Message Sent', + 'LBL_MODIFIED_BY' => 'Modified By', + 'LBL_MODULE_NAME_NEW' => 'Archive Email', + 'LBL_MODULE_NAME' => 'All Emails', + 'LBL_MODULE_TITLE' => 'Emails: ', + 'LBL_MY_EMAILS' => 'My Emails', + 'LBL_NEW_FORM_TITLE' => 'Archive Email', + 'LBL_NONE' => 'None', + 'LBL_NOT_SENT' => 'Send Error', + 'LBL_NOTE_SEMICOLON' => 'Note: Use commas or semi-colons as separators for multiple email addresses.', + 'LBL_NOTES_SUBPANEL_TITLE' => 'Attachments', + 'LBL_OPPORTUNITY_SUBPANEL_TITLE' => 'Opportunities', + 'LBL_PROJECT_SUBPANEL_TITLE'=> 'Projects', + 'LBL_PROJECT_TASK_SUBPANEL_TITLE'=> 'Project Tasks', + 'LBL_RAW' => 'Raw Email', + 'LBL_SAVE_AS_DRAFT_BUTTON_KEY'=> 'R', + 'LBL_SAVE_AS_DRAFT_BUTTON_LABEL'=> 'Save Draft', + 'LBL_SAVE_AS_DRAFT_BUTTON_TITLE'=> 'Save Draft [Alt+R]', + 'LBL_SEARCH_FORM_DRAFTS_TITLE'=> 'Search Drafts', + 'LBL_SEARCH_FORM_SENT_TITLE'=> 'Search Sent Emails', + 'LBL_SEARCH_FORM_TITLE' => 'Email Search', + 'LBL_SEND_ANYWAYS' => 'This email has no subject. Send/save anyway?', + 'LBL_SEND_BUTTON_KEY' => 'S', + 'LBL_SEND_BUTTON_LABEL' => 'Send', + 'LBL_SEND_BUTTON_TITLE' => 'Send [Alt+S]', + 'LBL_SEND' => 'SEND', + 'LBL_SENT_MODULE_NAME' => 'Sent Emails', + 'LBL_SHOW_ALT_TEXT' => 'Show Plain Text', + 'LBL_SIGNATURE' => 'Signature', + 'LBL_SUBJECT' => 'Subject:', + 'LBL_TEXT_BODY' => 'Text Body', + 'LBL_TIME' => 'Time Sent:', + 'LBL_TO_ADDRS' => 'To', + 'LBL_USE_TEMPLATE' => 'Use Template:', + 'LBL_USERS_SUBPANEL_TITLE' => 'Users', + 'LBL_USERS' => 'Users', + + 'LNK_ALL_EMAIL_LIST' => 'All Emails', + 'LNK_ARCHIVED_EMAIL_LIST' => 'Archived Emails', + 'LNK_CALL_LIST' => 'Calls', + 'LNK_DRAFTS_EMAIL_LIST' => 'All Drafts', + 'LNK_EMAIL_LIST' => 'Emails', + 'LBL_EMAIL_RELATE' => 'Related To', + 'LNK_EMAIL_TEMPLATE_LIST' => 'View Email Templates', + 'LNK_MEETING_LIST' => 'Meetings', + 'LNK_NEW_ARCHIVE_EMAIL' => 'Create Archived Email', + 'LNK_NEW_CALL' => 'Log Call', + 'LNK_NEW_EMAIL_TEMPLATE' => 'Create Email Template', + 'LNK_NEW_EMAIL' => 'Send Email', + 'LNK_NEW_MEETING' => 'Schedule Meeting', + 'LNK_NEW_NOTE' => 'Create Note or Attachment', + 'LNK_NEW_SEND_EMAIL' => 'Compose', + 'LNK_NEW_TASK' => 'Create Task', + 'LNK_NOTE_LIST' => 'Notes', + 'LNK_SENT_EMAIL_LIST' => 'Sent Emails', + 'LNK_TASK_LIST' => 'Tasks', + 'LNK_VIEW_CALENDAR' => 'Today', + + 'LBL_LIST_ASSIGNED' => 'Assigned', + 'LBL_LIST_CONTACT_NAME' => 'Contact Name', + 'LBL_LIST_CREATED' => 'Created', + 'LBL_LIST_DATE_SENT' => 'Date Sent', + 'LBL_LIST_DATE' => 'Date Sent', + 'LBL_LIST_FORM_DRAFTS_TITLE'=> 'Draft', + 'LBL_LIST_FORM_SENT_TITLE' => 'Sent Emails', + 'LBL_LIST_FORM_TITLE' => 'Email List', + 'LBL_LIST_FROM_ADDR' => 'From', + 'LBL_LIST_RELATED_TO' => 'Recipient Type', + 'LBL_LIST_SUBJECT' => 'Subject', + 'LBL_LIST_TIME' => 'Time Sent', + 'LBL_LIST_TO_ADDR' => 'To', + 'LBL_LIST_TYPE' => 'Type', + + 'NTC_REMOVE_INVITEE' => 'Are you sure you want to remove this recipient from the email?', + 'WARNING_SETTINGS_NOT_CONF' => 'Warning: Your email settings are not configured to send email.', + 'WARNING_NO_UPLOAD_DIR' => 'Attachments may fail: No value for "upload_tmp_dir" was detected. Please correct this in your php.ini file.', + 'WARNING_UPLOAD_DIR_NOT_WRITABLE' => 'Attachments may fail: An incorrect or unusable value for "upload_tmp_dir" was detected. Please correct this in your php.ini file.', + + // for All emails + 'LBL_BUTTON_RAW_TITLE' => 'Show Raw Message [Alt+E]', + 'LBL_BUTTON_RAW_KEY' => 'e', + 'LBL_BUTTON_RAW_LABEL' => 'Show Raw', + 'LBL_BUTTON_RAW_LABEL_HIDE' => 'Hide Raw', + + // for InboundEmail + 'LBL_BUTTON_CHECK' => 'Check Mail', + 'LBL_BUTTON_CHECK_TITLE' => 'Check For New Email [Alt+C]', + 'LBL_BUTTON_CHECK_KEY' => 'c', + 'LBL_BUTTON_FORWARD' => 'Forward', + 'LBL_BUTTON_FORWARD_TITLE' => 'Forward This Email [Alt+F]', + 'LBL_BUTTON_FORWARD_KEY' => 'f', + 'LBL_BUTTON_REPLY_KEY' => 'r', + 'LBL_BUTTON_REPLY_TITLE' => 'Reply [Alt+R]', + 'LBL_BUTTON_REPLY' => 'Reply', + 'LBL_CASES_SUBPANEL_TITLE' => 'Cases', + 'LBL_INBOUND_TITLE' => 'Inbound Email', + 'LBL_INTENT' => 'Intent', + 'LBL_MESSAGE_ID' => 'Message ID', + 'LBL_REPLY_HEADER_1' => 'On ', + 'LBL_REPLY_HEADER_2' => 'wrote:', + 'LBL_REPLY_TO_ADDRESS' => 'Reply-to Address', + 'LBL_REPLY_TO_NAME' => 'Reply-to Name', + + 'LBL_LIST_BUG' => 'Bugs', + 'LBL_LIST_CASE' => 'Cases', + 'LBL_LIST_CONTACT' => 'Contacts', + 'LBL_LIST_LEAD' => 'Leads', + 'LBL_LIST_TASK' => 'Tasks', + 'LBL_LIST_ASSIGNED_TO_NAME' => 'Assigned User', + + // for Inbox + 'LBL_ALL' => 'All', + 'LBL_ASSIGN_WARN' => 'Ensure that all 2 options are selected.', + 'LBL_BACK_TO_GROUP' => 'Back to Group Inbox', + 'LBL_BUTTON_DISTRIBUTE_KEY' => 'a', + 'LBL_BUTTON_DISTRIBUTE_TITLE'=> 'Assign [Alt+A]', + 'LBL_BUTTON_DISTRIBUTE' => 'Assign', + 'LBL_BUTTON_GRAB_KEY' => 't', + 'LBL_BUTTON_GRAB_TITLE' => 'Take from Group [Alt+T]', + 'LBL_BUTTON_GRAB' => 'Take from Group', + 'LBL_CREATE_BUG' => 'Create Bug', + 'LBL_CREATE_CASE' => 'Create Case', + 'LBL_CREATE_CONTACT' => 'Create Contact', + 'LBL_CREATE_LEAD' => 'Create Lead', + 'LBL_CREATE_TASK' => 'Create Task', + 'LBL_DIST_TITLE' => 'Assignment', + 'LBL_LOCK_FAIL_DESC' => 'The chosen item is unavailable currently.', + 'LBL_LOCK_FAIL_USER' => ' has taken ownership.', + 'LBL_MASS_DELETE_ERROR' => 'No checked items were passed for deletion.', + 'LBL_NEW' => 'New', + 'LBL_NEXT_EMAIL' => 'Next Free Item', + 'LBL_NO_GRAB_DESC' => 'There were no items available. Try again in a moment.', + 'LBL_QUICK_REPLY' => 'Reply', + 'LBL_REPLIED' => 'Replied', + 'LBL_SELECT_TEAM' => 'Select Teams', + 'LBL_TAKE_ONE_TITLE' => 'Reps', + 'LBL_TITLE_SEARCH_RESULTS' => 'Search Results', + 'LBL_TO' => 'To: ', + 'LBL_TOGGLE_ALL' => 'Toggle All', + 'LBL_UNKNOWN' => 'Unknown', + 'LBL_UNREAD_HOME' => 'Unread Emails', + 'LBL_UNREAD' => 'Unread', + 'LBL_USE_ALL' => 'All Search Results', + 'LBL_USE_CHECKED' => 'Only Checked', + 'LBL_USE_MAILBOX_INFO' => 'Use Mailbox From: Address', + 'LBL_USE' => 'Assign:', + 'LBL_ASSIGN_SELECTED_RESULTS_TO' => 'Assign Selected Results To: ', + 'LBL_USER_SELECT' => 'Select Users', + 'LBL_USING_RULES' => 'Using Rules:', + 'LBL_WARN_NO_DIST' => 'No Distribution Method Selected', + 'LBL_WARN_NO_USERS' => 'No Users are selected', + 'LBL_WARN_NO_USERS_OR_TEAM' => 'Please select either a user or team for assignment.', + 'LBL_IMPORT_STATUS_TITLE' => 'Status', + 'LBL_LIST_STATUS' => 'Status', + 'LBL_LIST_TITLE_GROUP_INBOX'=> 'Group Inbox', + 'LBL_LIST_TITLE_MY_DRAFTS' => 'My Drafts', + 'LBL_LIST_TITLE_MY_INBOX' => 'My Inbox', + 'LBL_LIST_TITLE_MY_SENT' => 'My Sent Email', + 'LBL_LIST_TITLE_MY_ARCHIVES'=> 'My Archived Emails', + 'LBL_ACTIVITIES_REPORTS' => 'Activities Report', + + 'LNK_CHECK_MY_INBOX' => 'Check My Mail', + 'LNK_DATE_SENT' => 'Date Sent', + 'LNK_GROUP_INBOX' => 'Group Inbox', + 'LNK_MY_DRAFTS' => 'My Drafts', + 'LNK_MY_INBOX' => 'My Email', + 'LNK_VIEW_MY_INBOX' => 'View My Email', + 'LNK_QUICK_REPLY' => 'Reply', + 'LNK_MY_ARCHIVED_LIST' => 'My Archives', + 'LBL_EMAILS_NO_PRIMARY_TEAM_SPECIFIED' =>'No Primary Team specified', + + // advanced search + 'LBL_ASSIGNED_TO' => 'Assigned To:', + 'LBL_MEMBER_OF' => 'Parent', + 'LBL_QUICK_CREATE' => 'Quick Create', + 'LBL_STATUS' => 'Email Status:', + 'LBL_EMAIL_FLAGGED' => 'Flagged:', + 'LBL_EMAIL_REPLY_TO_STATUS' => 'Reply To Status:', + 'LBL_TYPE' => 'Type:', + //#20680 EmialTemplate Ext.Message.show; + 'LBL_EMAILTEMPLATE_MESSAGE_SHOW_TITLE' => 'Please check!', + 'LBL_EMAILTEMPLATE_MESSAGE_SHOW_MSG' => 'Selecting this template will overwrite any data already entered within the email body. Do you wish to continue?', + 'LBL_EMAILTEMPLATE_MESSAGE_CLEAR_MSG' => 'Selecting "--None--" will clear any data already entered within the email body. Do you wish to continue?', + 'LBL_EMAILTEMPLATE_MESSAGE_WARNING_TITLE' => 'Warning', + 'LBL_EMAILTEMPLATE_MESSAGE_MULTIPLE_RECIPIENTS' => 'Using an email template containing contact variables, such as the contact name, to send emails to multiple recipients may have unexpected results. It is recommended that you use an email campaign for mass mailings.', + 'LBL_CHECK_ATTACHMENTS'=>'Please Check Attachments!', + 'LBL_HAS_ATTACHMENTS' => 'This email already has attachment(s). Would you like to keep the attachment(s)?', + 'ERR_MISSING_REQUIRED_FIELDS' => 'Missing required field', + 'ERR_INVALID_REQUIRED_FIELDS' => 'Invalid required field', + 'LBL_FILTER_BY_RELATED_BEAN' => 'Only show recipients related to', + 'LBL_RECIPIENTS_HAVE_BEEN_ADDED' => 'Recipients have been added.', + 'LBL_ADD_INBOUND_ACCOUNT' => 'Add', + 'LBL_ADD_OUTBOUND_ACCOUNT' => 'Add', + 'LBL_EMAIL_ACCOUNTS_INBOUND' => 'Mail Account Properties', + 'LBL_EMAIL_SETTINGS_OUTBOUND_ACCOUNT' => 'Outgoing SMTP Mail Server', + 'LBL_EMAIL_SETTINGS_OUTBOUND_ACCOUNTS' => 'Outgoing SMTP Mail Servers', + 'LBL_EMAIL_SETTINGS_INBOUND_ACCOUNTS' => 'Mail Accounts', + 'LBL_EMAIL_SETTINGS_INBOUND' => 'Incoming Email', + 'LBL_EMAIL_SETTINGS_OUTBOUND' => 'Outgoing Email', + 'LBL_ADD_CC' => 'Add Cc', + 'LBL_ADD_BCC' => 'Add Bcc', + 'LBL_ADD_TO_ADDR' => 'Add To', + 'LBL_SELECTED_ADDR' => 'Selected', + 'LBL_ADD_CC_BCC_SEP' => '|', + 'LBL_SEND_EMAIL_FAIL_TITLE' => 'Error Sending Email', + 'LBL_EMAIL_DETAIL_VIEW_SHOW' => 'show ', + 'LBL_EMAIL_DETAIL_VIEW_MORE' => ' more', + 'LBL_MORE_OPTIONS' => 'More', + 'LBL_LESS_OPTIONS' => 'Less', + 'LBL_MAILBOX_TYPE_PERSONAL' => 'Personal', + 'LBL_MAILBOX_TYPE_GROUP' => 'Group', + 'LBL_MAILBOX_TYPE_GROUP_FOLDER' => 'Group - Auto-Import', + 'LBL_SEARCH_FOR' => 'Search For', + 'LBL_EMAIL_INBOUND_TYPE_HELP' => 'Personal: Email account accessible by you. Only you can manage and import emails from this account.
    Group: Email account accessible by members of specified teams. Team members can manage and import emails from this account.
    Group - auto-import: Email account accessible by members of specified teams. Emails are automatically imported as records.', + 'LBL_ADDRESS_BOOK_SEARCH_HELP' => 'Enter an email address, First Name, Last Name or Account Name to find recipients.', + 'LBL_TEST_SETTINGS' => 'Test Settings', + 'LBL_EMPTY_EMAIL_BODY' => '

    This Message Has No Content

    ', + 'LBL_TEST_EMAIL_SUBJECT' => 'Test Email from Sugar', + 'LBL_NO_SUBJECT' =>'(no subject)', + 'LBL_CHECKING_ACCOUNT' => 'Checking Account', + 'LBL_OF' => 'of', + 'LBL_TEST_EMAIL_BODY' => 'This email was sent in order to test the outgoing mail server information provided in the Sugar application. A successful receipt of this email indicates that the outgoing mail server information provided is valid.', + + // for outbound email dialog + 'LBL_MAIL_SMTPUSER' => 'Username', + 'LBL_MAIL_SMTPPASS' => 'Password', + 'LBL_MAIL_SMTPSERVER' => 'SMTP Mail Server', + 'LBL_SMTP_SERVER_HELP' => 'This SMTP Mail Server can be used for outgoing mail. Provide a username and password for your email account in order to use the mail server.', + 'LBL_MISSING_DEFAULT_OUTBOUND_SMTP_SETTINGS' => 'The administator has not yet configured the default outbound account. Unable to send test email.', + 'LBL_MAIL_SMTPAUTH_REQ' => 'Use SMTP Authentication?', + 'LBL_MAIL_SMTPPASS' => 'SMTP Password:', + 'LBL_MAIL_SMTPPORT' => 'SMTP Port:', + 'LBL_MAIL_SMTPSERVER' => 'SMTP Server:', + 'LBL_MAIL_SMTPUSER' => 'SMTP Username:', + 'LBL_MAIL_SMTPTYPE' => 'SMTP Server Type:', + 'LBL_MAIL_SMTP_SETTINGS' => 'SMTP Server Specification', + 'LBL_CHOOSE_EMAIL_PROVIDER' => 'Choose your Email provider:', + 'LBL_YAHOOMAIL_SMTPPASS' => 'Yahoo! Mail Password:', + 'LBL_YAHOOMAIL_SMTPUSER' => 'Yahoo! Mail ID:', + 'LBL_GMAIL_SMTPPASS' => 'Gmail Password:', + 'LBL_GMAIL_SMTPUSER' => 'Gmail Email Address:', + 'LBL_EXCHANGE_SMTPPASS' => 'Exchange Password:', + 'LBL_EXCHANGE_SMTPUSER' => 'Exchange Username:', + 'LBL_EXCHANGE_SMTPPORT' => 'Exchange Server Port:', + 'LBL_EXCHANGE_SMTPSERVER' => 'Exchange Server:', +); diff --git a/modules/Emails/metadata/additionalDetails.php b/modules/Emails/metadata/additionalDetails.php new file mode 100644 index 00000000..795082d4 --- /dev/null +++ b/modules/Emails/metadata/additionalDetails.php @@ -0,0 +1,89 @@ +' . $mod_strings['LBL_FROM'] . '
     '; + $overlib_string .= $fields['FROM_NAME']; + } + + // email text + if(!empty($fields['DESCRIPTION_HTML'])) { + if(!empty($overlib_string)) $overlib_string .= '
    '; + $overlib_string .= ''.$mod_strings['LBL_BODY'].'
    '; + $descH = strip_tags($fields['DESCRIPTION_HTML'], ''); + $desc = str_replace($newLines, ' ', $descH); + $overlib_string .= substr($desc, 0, 300); + if(strlen($descH) > 300) $overlib_string .= '...'; + } elseif (!empty($fields['DESCRIPTION'])) { + if(!empty($overlib_string)) $overlib_string .= '
    '; + $overlib_string .= ''.$mod_strings['LBL_BODY'].'
    '; + $descH = strip_tags(nl2br($fields['DESCRIPTION'])); + $desc = str_replace($newLines, ' ', $descH); + $overlib_string .= substr($desc, 0, 300); + if(strlen($descH) > 300) $overlib_string .= '...'; + } + + $editLink = "index.php?action=EditView&module=Emails&record={$fields['ID']}"; + $viewLink = "index.php?action=DetailView&module=Emails&record={$fields['ID']}"; + + $return_module = empty($_REQUEST['module']) ? 'Meetings' : $_REQUEST['module']; + $return_action = empty($_REQUEST['action']) ? 'ListView' : $_REQUEST['action']; + $type = empty($_REQUEST['type']) ? '' : $_REQUEST['type']; + $user_id = empty($_REQUEST['assigned_user_id']) ? '' : $_REQUEST['assigned_user_id']; + + $additional_params = "&return_module=$return_module&return_action=$return_action&type=$type&assigned_user_id=$user_id"; + + $editLink .= $additional_params; + $viewLink .= $additional_params; + + return array('fieldToAddTo' => 'NAME', + 'string' => $overlib_string, + 'editLink' => $editLink, + 'viewLink' => $viewLink); +} + + ?> + diff --git a/modules/Emails/metadata/popupdefs.php b/modules/Emails/metadata/popupdefs.php new file mode 100644 index 00000000..f5378438 --- /dev/null +++ b/modules/Emails/metadata/popupdefs.php @@ -0,0 +1,54 @@ + 'Email', + 'varName' => 'EMAIL', + 'orderBy' => 'name', + 'whereClauses' => array( + 'name' => 'emails.name', + 'contact_name' => 'contacts.last_name' + ), + 'searchInputs' => array( + 'name', + 'contact_name', + 'request_data' + ), +); +?> + diff --git a/modules/Emails/metadata/qcmodulesdefs.php b/modules/Emails/metadata/qcmodulesdefs.php new file mode 100644 index 00000000..573f802e --- /dev/null +++ b/modules/Emails/metadata/qcmodulesdefs.php @@ -0,0 +1,45 @@ + array( + 'notes' => array( + 'order' => 5, + 'sort_order' => 'asc', + 'sort_by' => 'name', + 'subpanel_name' => 'default', + 'get_subpanel_data' => 'notes', + 'title_key' => 'LBL_NOTES_SUBPANEL_TITLE', + 'module' => 'Notes', + 'top_buttons' => array(), + ), + 'accounts' => array( + 'order' => 10, + 'module' => 'Accounts', + 'sort_order' => 'asc', + 'sort_by' => 'name', + 'subpanel_name' => 'ForEmails', + 'get_subpanel_data' => 'accounts', + 'add_subpanel_data' => 'account_id', + 'title_key' => 'LBL_ACCOUNTS_SUBPANEL_TITLE', + 'top_buttons' => array( + array('widget_class' => 'SubPanelTopCreateButton'), + array('widget_class' => 'SubPanelTopSelectButton', 'mode'=>'MultiSelect') + ), + ), + 'contacts' => array( + 'order' => 20, + 'module' => 'Contacts', + 'sort_order' => 'asc', + 'sort_by' => 'last_name, first_name', + 'subpanel_name' => 'ForEmails', + 'get_subpanel_data' => 'contacts', + 'add_subpanel_data' => 'contact_id', + 'title_key' => 'LBL_CONTACTS_SUBPANEL_TITLE', + 'top_buttons' => array( + array('widget_class' => 'SubPanelTopCreateButton'), + array('widget_class' => 'SubPanelTopSelectButton', 'mode'=>'MultiSelect') + ), + ), + 'opportunities' => array( + 'order' => 25, + 'module' => 'Opportunities', + 'sort_order' => 'asc', + 'sort_by' => 'name', + 'subpanel_name' => 'ForEmails', + 'get_subpanel_data' => 'opportunities', + 'add_subpanel_data' => 'opportunity_id', + 'title_key' => 'LBL_OPPORTUNITY_SUBPANEL_TITLE', + 'top_buttons' => array( + array('widget_class' => 'SubPanelTopCreateButton'), + array('widget_class' => 'SubPanelTopSelectButton', 'mode'=>'MultiSelect') + ), + ), + 'leads' => array( + 'order' => 30, + 'module' => 'Leads', + 'sort_order' => 'asc', + 'sort_by' => 'last_name, first_name', + 'subpanel_name' => 'ForEmails', + 'get_subpanel_data' => 'leads', + 'add_subpanel_data' => 'lead_id', + 'title_key' => 'LBL_LEADS_SUBPANEL_TITLE', + 'top_buttons' => array( + array('widget_class' => 'SubPanelTopCreateButton'), + array('widget_class' => 'SubPanelTopSelectButton', 'mode'=>'MultiSelect') + ), + ), + 'cases' => array( + 'order' => 40, + 'module' => 'Cases', + 'sort_order' => 'desc', + 'sort_by' => 'case_number', + 'subpanel_name' => 'ForEmails', + 'get_subpanel_data' => 'cases', + 'add_subpanel_data' => 'case_id', + 'title_key' => 'LBL_CASES_SUBPANEL_TITLE', + 'top_buttons' => array( + array('widget_class' => 'SubPanelTopCreateButton'), + array('widget_class' => 'SubPanelTopSelectButton', 'mode'=>'MultiSelect') + ), + ), + 'users' => array( + 'order' => 50, + 'module' => 'Users', + 'sort_order' => 'asc', + 'sort_by' => 'name', + 'subpanel_name' => 'ForEmails', + 'get_subpanel_data' => 'users', + 'add_subpanel_data' => 'user_id', + 'title_key' => 'LBL_USERS_SUBPANEL_TITLE', + 'top_buttons' => array( + array('widget_class' => 'SubPanelTopSelectButton', 'mode'=>'MultiSelect') + ), + ), + 'bugs' => array( + 'order' => 60, + 'module' => 'Bugs', + 'sort_order' => 'desc', + 'sort_by' => 'bug_number', + 'subpanel_name' => 'ForEmails', + 'get_subpanel_data' => 'bugs', + 'add_subpanel_data' => 'bug_id', + 'title_key' => 'LBL_BUGS_SUBPANEL_TITLE', + 'top_buttons' => array( + array('widget_class' => 'SubPanelTopCreateButton'), + array('widget_class' => 'SubPanelTopSelectButton', 'mode'=>'MultiSelect') + ), + ), + + + 'project' => array( + 'order' => 80, + 'module' => 'Project', + 'sort_order' => 'asc', + 'sort_by' => 'name', + 'subpanel_name' => 'ForEmails', + 'get_subpanel_data' => 'project', + 'add_subpanel_data' => 'project_id', + 'title_key' => 'LBL_PROJECT_SUBPANEL_TITLE', + 'top_buttons' => array( + array('widget_class' => 'SubPanelTopCreateButton'), + array('widget_class' => 'SubPanelTopSelectButton', 'mode'=>'MultiSelect') + ), + ), + + ), +); diff --git a/modules/Emails/metadata/subpanels/ForContacts.php b/modules/Emails/metadata/subpanels/ForContacts.php new file mode 100644 index 00000000..11478aa2 --- /dev/null +++ b/modules/Emails/metadata/subpanels/ForContacts.php @@ -0,0 +1,46 @@ + array( + array('widget_class' => 'SubPanelTopSelectButton', 'popup_module' => 'Contacts'), + ), +); +?> \ No newline at end of file diff --git a/modules/Emails/metadata/subpanels/ForHistory.php b/modules/Emails/metadata/subpanels/ForHistory.php new file mode 100644 index 00000000..72cb3f00 --- /dev/null +++ b/modules/Emails/metadata/subpanels/ForHistory.php @@ -0,0 +1,126 @@ + "", + + + 'fill_in_additional_fields' => true, + 'list_fields' => array( + 'object_image'=>array( + 'widget_class' => 'SubPanelIcon', + 'width' => '2%', + ), + 'name' => array( + 'vname' => 'LBL_LIST_SUBJECT', + 'widget_class' => 'SubPanelDetailViewLink', + 'width' => '30%', + 'parent_info' => true + ), + 'status' => array( + 'vname' => 'LBL_LIST_STATUS', + 'width' => '15%', + ), + 'reply_to_status' => array( + 'usage' => 'query_only', + 'force_exists' => true, + 'force_default' => 0, + ), + 'contact_name'=>array( + 'widget_class' => 'SubPanelDetailViewLink', + 'target_record_key' => 'contact_id', + 'target_module' => 'Contacts', + 'module' => 'Contacts', + 'vname' => 'LBL_LIST_CONTACT', + 'width' => '11%', + 'sortable' => false, + 'force_exists' => true, + ), + 'contact_id'=>array( + 'usage'=>'query_only', + 'force_exists'=>true + ), + 'contact_name_owner'=>array( + 'usage'=>'query_only', + 'force_exists'=>true + ), + 'contact_name_mod'=>array( + 'usage'=>'query_only', + 'force_exists'=>true + ), + 'parent_id'=>array( + 'usage'=>'query_only', + 'force_exists'=>true + ), + 'parent_type'=>array( + 'usage'=>'query_only', + 'force_exists'=>true + ), + 'date_modified' => array( + 'width' => '10%', + ), + 'date_entered'=>array( + 'vname' => 'LBL_LIST_DATE_ENTERED', + 'width' => '10%', + ), + 'assigned_user_name' => array ( + 'name' => 'assigned_user_name', + 'vname' => 'LBL_LIST_ASSIGNED_TO_NAME', + 'widget_class' => 'SubPanelDetailViewLink', + 'target_record_key' => 'assigned_user_id', + 'target_module' => 'Employees', + 'width' => '10%', + ), + 'edit_button' => array( + 'vname' => 'LBL_EDIT_BUTTON', + 'widget_class' => 'SubPanelEditButton', + 'width' => '2%', + ), + 'remove_button' => array( + 'vname' => 'LBL_REMOVE', + 'widget_class' => 'SubPanelRemoveButton', + 'width' => '2%', + ), + 'filename' => array( + 'usage' => 'query_only', + 'force_exists' => true + ), + ), // end list_fields +); +?> diff --git a/modules/Emails/metadata/subpanels/ForQueues.php b/modules/Emails/metadata/subpanels/ForQueues.php new file mode 100644 index 00000000..00db69c2 --- /dev/null +++ b/modules/Emails/metadata/subpanels/ForQueues.php @@ -0,0 +1,116 @@ + array( +// array('widget_class' => 'SubPanelTopSelectButton', 'popup_module' => 'Queues'), +// ), +//); + + +$subpanel_layout = array( + 'top_buttons' => array( + array('widget_class' => 'SubPanelTopSelectButton', 'popup_module' => 'Queues'), + ), + 'where' => "", + + 'fill_in_additional_fields'=>true, + 'list_fields' => array( +/* 'mass_update' => array ( + + ), +*/ 'object_image'=>array( + 'widget_class' => 'SubPanelIcon', + 'width' => '2%', + ), + 'name'=>array( + 'vname' => 'LBL_LIST_SUBJECT', + 'widget_class' => 'SubPanelDetailViewLink', + 'width' => '68%', + ), + 'case_name'=>array( + 'widget_class' => 'SubPanelDetailViewLink', + 'target_record_key' => 'case_id', + 'target_module' => 'Cases', + 'module' => 'Cases', + 'vname' => 'LBL_LIST_CASE', + 'width' => '20%', + 'force_exists'=>true, + 'sortable'=>false, + ), + 'contact_id'=>array( + 'usage'=>'query_only', + 'force_exists'=>true, + ) , +/* 'parent_name'=>array( + 'vname' => 'LBL_LIST_RELATED_TO', + 'width' => '22%', + 'target_record_key' => 'parent_id', + 'target_module_key'=>'parent_type', + 'widget_class' => 'SubPanelDetailViewLink', + 'sortable'=>false, + ),*/ + 'date_modified'=>array( + 'vname' => 'LBL_DATE_MODIFIED', + 'width' => '10%', + ), +/* 'edit_button'=>array( + 'widget_class' => 'SubPanelEditButton', + 'width' => '2%', + ), + 'remove_button'=>array( + 'widget_class' => 'SubPanelRemoveButton', + 'width' => '2%', + ), + 'parent_id'=>array( + 'usage'=>'query_only', + ), + 'parent_type'=>array( + 'usage'=>'query_only', + ), + 'filename'=>array( + 'usage'=>'query_only', + 'force_exists'=>true + ), +*/ + ), +); + +?> \ No newline at end of file diff --git a/modules/Emails/metadata/subpanels/ForUnlinkedEmailHistory.php b/modules/Emails/metadata/subpanels/ForUnlinkedEmailHistory.php new file mode 100644 index 00000000..c2d8beae --- /dev/null +++ b/modules/Emails/metadata/subpanels/ForUnlinkedEmailHistory.php @@ -0,0 +1,118 @@ + "", + + + 'fill_in_additional_fields' => true, + 'list_fields' => array( + 'object_image'=>array( + 'widget_class' => 'SubPanelIcon', + 'width' => '2%', + ), + 'name' => array( + 'vname' => 'LBL_LIST_SUBJECT', + 'widget_class' => 'SubPanelDetailViewLink', + 'width' => '30%', + 'parent_info' => true + ), + 'status' => array( + 'vname' => 'LBL_LIST_STATUS', + 'width' => '15%', + ), + 'reply_to_status' => array( + 'usage' => 'query_only', + 'force_exists' => true, + ), + 'contact_name'=>array( + 'widget_class' => 'SubPanelDetailViewLink', + 'target_record_key' => 'contact_id', + 'target_module' => 'Contacts', + 'module' => 'Contacts', + 'vname' => 'LBL_LIST_CONTACT', + 'width' => '11%', + 'sortable' => false, + 'force_exists' => true, + ), + 'contact_id'=>array( + 'usage'=>'query_only', + 'force_exists'=>true + ), + 'contact_name_owner'=>array( + 'usage'=>'query_only', + 'force_exists'=>true + ), + 'contact_name_mod'=>array( + 'usage'=>'query_only', + 'force_exists'=>true + ), + 'parent_id'=>array( + 'usage'=>'query_only', + 'force_exists'=>true + ), + 'parent_type'=>array( + 'usage'=>'query_only', + 'force_exists'=>true + ), + 'date_modified' => array( + 'width' => '10%', + ), + 'date_entered' => array( + 'width' => '10%', + ), + 'assigned_user_name' => array ( + 'name' => 'assigned_user_name', + 'vname' => 'LBL_LIST_ASSIGNED_TO_NAME', + 'widget_class' => 'SubPanelDetailViewLink', + 'target_record_key' => 'assigned_user_id', + 'target_module' => 'Employees', + ), + 'edit_button' => array( + 'vname' => 'LBL_EDIT_BUTTON', + 'widget_class' => 'SubPanelEditButton', + 'width' => '2%', + ), + 'filename' => array( + 'usage' => 'query_only', + 'force_exists' => true + ), + ), // end list_fields +); +?> diff --git a/modules/Emails/metadata/subpanels/ForUsers.php b/modules/Emails/metadata/subpanels/ForUsers.php new file mode 100644 index 00000000..a5e81536 --- /dev/null +++ b/modules/Emails/metadata/subpanels/ForUsers.php @@ -0,0 +1,46 @@ + array( + array('widget_class' => 'SubPanelTopSelectButton', 'popup_module' => 'Users'), + ), +); +?> \ No newline at end of file diff --git a/modules/Emails/subpanels/ForContacts.php b/modules/Emails/subpanels/ForContacts.php new file mode 100644 index 00000000..11478aa2 --- /dev/null +++ b/modules/Emails/subpanels/ForContacts.php @@ -0,0 +1,46 @@ + array( + array('widget_class' => 'SubPanelTopSelectButton', 'popup_module' => 'Contacts'), + ), +); +?> \ No newline at end of file diff --git a/modules/Emails/subpanels/ForHistory.php b/modules/Emails/subpanels/ForHistory.php new file mode 100644 index 00000000..891d0068 --- /dev/null +++ b/modules/Emails/subpanels/ForHistory.php @@ -0,0 +1,107 @@ + "", + + + 'fill_in_additional_fields' => true, + 'list_fields' => array( + 'object_image'=>array( + 'widget_class' => 'SubPanelIcon', + 'width' => '2%', + ), + 'name' => array( + 'vname' => 'LBL_LIST_SUBJECT', + 'widget_class' => 'SubPanelDetailViewLink', + 'width' => '30%', + 'parent_info' => true + ), + 'status' => array( + 'vname' => 'LBL_LIST_STATUS', + 'width' => '15%', + ), + 'contact_name'=>array( + 'widget_class' => 'SubPanelDetailViewLink', + 'target_record_key' => 'contact_id', + 'target_module' => 'Contacts', + 'module' => 'Contacts', + 'vname' => 'LBL_LIST_CONTACT', + 'width' => '11%', + 'sortable' => false, + 'force_exists' => true, + ), + 'contact_id'=>array( + 'usage'=>'query_only', + 'force_exists'=>true + ), + 'contact_name_owner'=>array( + 'usage'=>'query_only', + 'force_exists'=>true + ), + 'contact_name_mod'=>array( + 'usage'=>'query_only', + 'force_exists'=>true + ), + 'date_modified' => array( + 'width' => '10%', + ), + 'date_entered'=>array( + 'vname' => 'LBL_LIST_DATE_ENTERED', + 'width' => '10%', + ), + 'assigned_user_name' => array ( + 'name' => 'assigned_user_name', + 'vname' => 'LBL_LIST_ASSIGNED_TO_NAME', + ), + 'edit_button' => array( + 'widget_class' => 'SubPanelEditButton', + 'width' => '2%', + ), + 'remove_button' => array( + 'widget_class' => 'SubPanelRemoveButton', + 'width' => '2%', + ), + 'filename' => array( + 'usage' => 'query_only', + 'force_exists' => true + ), + ), // end list_fields +); +?> diff --git a/modules/Emails/subpanels/ForQueues.php b/modules/Emails/subpanels/ForQueues.php new file mode 100644 index 00000000..00db69c2 --- /dev/null +++ b/modules/Emails/subpanels/ForQueues.php @@ -0,0 +1,116 @@ + array( +// array('widget_class' => 'SubPanelTopSelectButton', 'popup_module' => 'Queues'), +// ), +//); + + +$subpanel_layout = array( + 'top_buttons' => array( + array('widget_class' => 'SubPanelTopSelectButton', 'popup_module' => 'Queues'), + ), + 'where' => "", + + 'fill_in_additional_fields'=>true, + 'list_fields' => array( +/* 'mass_update' => array ( + + ), +*/ 'object_image'=>array( + 'widget_class' => 'SubPanelIcon', + 'width' => '2%', + ), + 'name'=>array( + 'vname' => 'LBL_LIST_SUBJECT', + 'widget_class' => 'SubPanelDetailViewLink', + 'width' => '68%', + ), + 'case_name'=>array( + 'widget_class' => 'SubPanelDetailViewLink', + 'target_record_key' => 'case_id', + 'target_module' => 'Cases', + 'module' => 'Cases', + 'vname' => 'LBL_LIST_CASE', + 'width' => '20%', + 'force_exists'=>true, + 'sortable'=>false, + ), + 'contact_id'=>array( + 'usage'=>'query_only', + 'force_exists'=>true, + ) , +/* 'parent_name'=>array( + 'vname' => 'LBL_LIST_RELATED_TO', + 'width' => '22%', + 'target_record_key' => 'parent_id', + 'target_module_key'=>'parent_type', + 'widget_class' => 'SubPanelDetailViewLink', + 'sortable'=>false, + ),*/ + 'date_modified'=>array( + 'vname' => 'LBL_DATE_MODIFIED', + 'width' => '10%', + ), +/* 'edit_button'=>array( + 'widget_class' => 'SubPanelEditButton', + 'width' => '2%', + ), + 'remove_button'=>array( + 'widget_class' => 'SubPanelRemoveButton', + 'width' => '2%', + ), + 'parent_id'=>array( + 'usage'=>'query_only', + ), + 'parent_type'=>array( + 'usage'=>'query_only', + ), + 'filename'=>array( + 'usage'=>'query_only', + 'force_exists'=>true + ), +*/ + ), +); + +?> \ No newline at end of file diff --git a/modules/Emails/subpanels/ForUsers.php b/modules/Emails/subpanels/ForUsers.php new file mode 100644 index 00000000..a5e81536 --- /dev/null +++ b/modules/Emails/subpanels/ForUsers.php @@ -0,0 +1,46 @@ + array( + array('widget_class' => 'SubPanelTopSelectButton', 'popup_module' => 'Users'), + ), +); +?> \ No newline at end of file diff --git a/modules/Emails/templates/_baseConfigData.tpl b/modules/Emails/templates/_baseConfigData.tpl new file mode 100644 index 00000000..e1e4cf42 --- /dev/null +++ b/modules/Emails/templates/_baseConfigData.tpl @@ -0,0 +1,45 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} + +SUGAR.email2.composeLayout.charsets = {$emailCharsets}; +SUGAR.default_inbound_accnt_id = '{$defaultOutID}'; +SUGAR.email2.userPrefs = {$userPrefs}; +SUGAR.email2.signatures = {$defaultSignature}; +{$tinyMCE} +linkBeans = {$linkBeans}; +{$lang} diff --git a/modules/Emails/templates/_baseEmail.tpl b/modules/Emails/templates/_baseEmail.tpl new file mode 100644 index 00000000..ef51fb15 --- /dev/null +++ b/modules/Emails/templates/_baseEmail.tpl @@ -0,0 +1,172 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} + + +{include file="modules/Emails/templates/_baseJsVars.tpl"} + + + + + + \ No newline at end of file diff --git a/modules/Emails/templates/_baseJsVars.tpl b/modules/Emails/templates/_baseJsVars.tpl new file mode 100644 index 00000000..e6182b2f --- /dev/null +++ b/modules/Emails/templates/_baseJsVars.tpl @@ -0,0 +1,58 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} + + diff --git a/modules/Emails/templates/_blank.html b/modules/Emails/templates/_blank.html new file mode 100644 index 00000000..12bdbb77 --- /dev/null +++ b/modules/Emails/templates/_blank.html @@ -0,0 +1,38 @@ + + \ No newline at end of file diff --git a/modules/Emails/templates/_createGroupFolder.tpl b/modules/Emails/templates/_createGroupFolder.tpl new file mode 100644 index 00000000..f09d01eb --- /dev/null +++ b/modules/Emails/templates/_createGroupFolder.tpl @@ -0,0 +1,147 @@ + + + + + + + + + +{$languageStrings} + + + +{$CSS} + + +
    + + + + + + + + + + + + + + + + +
    +
    + {$app_strings.LBL_EMAIL_SETTINGS_GROUP_FOLDERS_CREATE}: +
    +
    + {$app_strings.LBL_EMAIL_SETTINGS_GROUP_FOLDERS_EDIT}: +
    +
    + +
    + {$app_strings.LBL_EMAIL_FOLDERS_NEW_FOLDER}: +
    +
    + +
    +
    + +
    + {$app_strings.LBL_EMAIL_FOLDERS_ADD_THIS_TO}: +
    +
    + +
    +
    + + + +
    +
    +
    +{$JAVASCRIPT} + + + \ No newline at end of file diff --git a/modules/Emails/templates/addressBook.tpl b/modules/Emails/templates/addressBook.tpl new file mode 100644 index 00000000..cbb7444e --- /dev/null +++ b/modules/Emails/templates/addressBook.tpl @@ -0,0 +1,47 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} +
    + +
    +
    + {$app_strings.LBL_EMAIL_ADDRESS_BOOK_FILTER}:  + + +
    +
    diff --git a/modules/Emails/templates/addressSearch.tpl b/modules/Emails/templates/addressSearch.tpl new file mode 100644 index 00000000..70b611c0 --- /dev/null +++ b/modules/Emails/templates/addressSearch.tpl @@ -0,0 +1,86 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} +
    + + + + + + + + + + + + + +
    +
    + {$mod_strings.LBL_SEARCH_FOR}: + +
    {$mod_strings.LBL_ADDRESS_BOOK_SEARCH_HELP}
    +
    + + +
    +    {$mod_strings.LBL_LIST_RELATED_TO}:   + +   + + {$mod_strings.LBL_EMAIL_SELECTOR} + + + {$mod_strings.LBL_EMAIL_SELECTOR} + +
    + {$mod_strings.LBL_FILTER_BY_RELATED_BEAN} + +
      
    + + + +
    +
    \ No newline at end of file diff --git a/modules/Emails/templates/addressSearchContent.tpl b/modules/Emails/templates/addressSearchContent.tpl new file mode 100644 index 00000000..e4b402e9 --- /dev/null +++ b/modules/Emails/templates/addressSearchContent.tpl @@ -0,0 +1,67 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} +
    +
    +
    +
    +
    + {include file="modules/Emails/templates/addressSearch.tpl"} +
    + + + + + + + +
    +
    +
    +
    +   +
    +

    {sugar_translate label="LBL_SELECTED_ADDR" module="Emails"}:

    +
    +
    +
    +
    +
     
    +
    + +
    +
    \ No newline at end of file diff --git a/modules/Emails/templates/advancedSearch.tpl b/modules/Emails/templates/advancedSearch.tpl new file mode 100644 index 00000000..c84aa11f --- /dev/null +++ b/modules/Emails/templates/advancedSearch.tpl @@ -0,0 +1,119 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
     
    + {$app_strings.LBL_EMAIL_SUBJECT}:
    + +
    + {$app_strings.LBL_EMAIL_FROM}:
    + +
    + {$app_strings.LBL_EMAIL_TO}:
    + +
    {$mod_strings.LBL_MORE_OPTIONS} 
    + {$app_strings.LBL_EMAIL_SEARCH_DATE_FROM}: ({$dateFormatExample})
    +   + {$app_strings.LBL_ENTER_DATE} +
    + {$app_strings.LBL_EMAIL_SEARCH_DATE_UNTIL}: ({$dateFormatExample})
    +   + {$app_strings.LBL_ENTER_DATE} +
    + {sugar_translate label="LBL_ASSIGNED_TO"}:
    + + + + + {$mod_strings.LBL_EMAIL_SELECTOR} + +
    + {$mod_strings.LBL_HAS_ATTACHMENT}
    + {html_options options=$attachmentsSearchOptions name='attachmentsSearch' id='attachmentsSearch'} +
    + {$mod_strings.LBL_EMAIL_RELATE}:
    + {html_options options=$linkBeansOptions name='data_parent_type_search' id='data_parent_type_search'} + +

    + + {$mod_strings.LBL_EMAIL_SELECTOR} + +
    {$mod_strings.LBL_LESS_OPTIONS} 
    +
     
    +   + +
    +
    \ No newline at end of file diff --git a/modules/Emails/templates/assignTo.tpl b/modules/Emails/templates/assignTo.tpl new file mode 100644 index 00000000..3af42aa8 --- /dev/null +++ b/modules/Emails/templates/assignTo.tpl @@ -0,0 +1,67 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} +
    + + + + + + + + + + + + + + + + + + +
    + {sugar_translate label="LBL_ASSIGNED_TO"}: + + + + + +  
      
      
    + +
    + diff --git a/modules/Emails/templates/dceMenuQuickCreate.tpl b/modules/Emails/templates/dceMenuQuickCreate.tpl new file mode 100644 index 00000000..e72f646e --- /dev/null +++ b/modules/Emails/templates/dceMenuQuickCreate.tpl @@ -0,0 +1,68 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} +
    + \ No newline at end of file diff --git a/modules/Emails/templates/editAccountDialogue.tpl b/modules/Emails/templates/editAccountDialogue.tpl new file mode 100644 index 00000000..89465c65 --- /dev/null +++ b/modules/Emails/templates/editAccountDialogue.tpl @@ -0,0 +1,245 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +

    {$mod_strings.LBL_EMAIL_SETTINGS_INBOUND}

    +
    {$app_strings.LBL_EMAIL_ACCOUNTS_GMAIL_DEFAULTS} 
    + {$app_strings.LBL_EMAIL_SETTINGS_NAME}: {$app_strings.LBL_REQUIRED_SYMBOL} + + +
    + {$ie_mod_strings.LBL_LOGIN}: {$app_strings.LBL_REQUIRED_SYMBOL}  + + +
    + {$ie_mod_strings.LBL_PASSWORD}: {$app_strings.LBL_REQUIRED_SYMBOL}  + + +
    + {$ie_mod_strings.LBL_SERVER_URL}: {$app_strings.LBL_REQUIRED_SYMBOL}  + + +
    + {$ie_mod_strings.LBL_SERVER_TYPE}: {$app_strings.LBL_REQUIRED_SYMBOL}  + + +
    + {$ie_mod_strings.LBL_SSL}:  + + +
    + +
    +
    + {$ie_mod_strings.LBL_PORT}: {$app_strings.LBL_REQUIRED_SYMBOL}  + + +
    + {$ie_mod_strings.LBL_MAILBOX}: {$app_strings.LBL_REQUIRED_SYMBOL}  + + + +
    + {$ie_mod_strings.LBL_TRASH_FOLDER}: {$app_strings.LBL_REQUIRED_SYMBOL}  + + + +
    + {$ie_mod_strings.LBL_SENT_FOLDER}:   + + + +
    + +   +
     
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +

    {$mod_strings.LBL_EMAIL_SETTINGS_OUTBOUND}

    +
    + {$app_strings.LBL_EMAIL_SETTINGS_FROM_NAME}: + + {$app_strings.LBL_REQUIRED_SYMBOL} + + + +
    + {$app_strings.LBL_EMAIL_SETTINGS_FROM_ADDR}: + + {$app_strings.LBL_REQUIRED_SYMBOL} + + + +
    + {$app_strings.LBL_EMAIL_SETTINGS_REPLY_TO_ADDR}: + + +
    + {$mod_strings.LBL_EMAIL_SETTINGS_OUTBOUND_ACCOUNT}: + {$app_strings.LBL_REQUIRED_SYMBOL} + + +
    + {$app_strings.LBL_EMAIL_ACCOUNTS_SMTPUSER}: + {$app_strings.LBL_REQUIRED_SYMBOL} + + +
    + {$app_strings.LBL_EMAIL_ACCOUNTS_SMTPPASS}: + {$app_strings.LBL_REQUIRED_SYMBOL} + + +
     
    + +   + +   +
     
    +
    \ No newline at end of file diff --git a/modules/Emails/templates/editContact.tpl b/modules/Emails/templates/editContact.tpl new file mode 100644 index 00000000..504d7a68 --- /dev/null +++ b/modules/Emails/templates/editContact.tpl @@ -0,0 +1,90 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} +
    +
    + + + + + + + + + + + + + + + + + + + + +
    +   +   + +
      +
    + {$contact_strings.LBL_FIRST_NAME} + + + + {$contact_strings.LBL_LAST_NAME} * + + +
    + {$contact_strings.LBL_EMAIL_ADDRESSES} +
    + {$emailWidget} +
    + {$app_strings.LBL_EMAIL_EDIT_CONTACT_WARN} +
    +
    +
    \ No newline at end of file diff --git a/modules/Emails/templates/editMailingList.tpl b/modules/Emails/templates/editMailingList.tpl new file mode 100644 index 00000000..eeb4c75e --- /dev/null +++ b/modules/Emails/templates/editMailingList.tpl @@ -0,0 +1,81 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} +
    +
    + + + + + + + + + + + + + +
    +   +   + +
      +
    + {$app_strings.LBL_EMAIL_ML_NAME} + + +
    + {$app_strings.LBL_EMAIL_ML_ADDRESSES_1} +
     
    +
    +
    + {$app_strings.LBL_EMAIL_ML_ADDRESSES_2} +
     
    +
    +
    +
    +
    \ No newline at end of file diff --git a/modules/Emails/templates/emailDetailView.tpl b/modules/Emails/templates/emailDetailView.tpl new file mode 100644 index 00000000..cb992584 --- /dev/null +++ b/modules/Emails/templates/emailDetailView.tpl @@ -0,0 +1,128 @@ + + +{$emailTitle} + +

    + + + + +

    + + + + + + + + + + + + + + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    {$APP.LBL_ASSIGNED_TO}{$ASSIGNED_TO}{$MOD.LBL_DATE_SENT}{$DATE_START} {$TIME_START}
      {$PARENT_TYPE}{$PARENT_NAME}
    {$MOD.LBL_FROM}{$FROM}
    {$MOD.LBL_TO}{$TO}
    {$MOD.LBL_CC}{$CC}
    {$MOD.LBL_BCC}{$BCC}
    {$MOD.LBL_SUBJECT}{$NAME}
    {$MOD.LBL_BODY} +
    {$DESCRIPTION_HTML}
    +
    + + +
    {$MOD.LBL_ATTACHMENTS}{$ATTACHMENTS}
    + +{$SUBPANEL} + diff --git a/modules/Emails/templates/emailSettings.tpl b/modules/Emails/templates/emailSettings.tpl new file mode 100644 index 00000000..f5065986 --- /dev/null +++ b/modules/Emails/templates/emailSettings.tpl @@ -0,0 +1,47 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} +
    +
    + {include file="modules/Emails/templates/emailSettingsGeneral.tpl"} +
    +
    + {include file="modules/Emails/templates/emailSettingsAccounts.tpl"} +
    + + +
    diff --git a/modules/Emails/templates/emailSettingsAccountDetails.tpl b/modules/Emails/templates/emailSettingsAccountDetails.tpl new file mode 100644 index 00000000..35ce8bbf --- /dev/null +++ b/modules/Emails/templates/emailSettingsAccountDetails.tpl @@ -0,0 +1,105 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} +{$rollover} + + + + + + + +
    + + + + + + + + + + + + + + + + + + +
    +

    {$mod_strings.LBL_EMAIL_SETTINGS_INBOUND_ACCOUNTS}

    +
    {$app_strings.LBL_EMAIL_ACCOUNTS_SUBTITLE}
     
     
    +
     
    +
    + + + + + + + + + + +
    +

    {$mod_strings.LBL_EMAIL_SETTINGS_OUTBOUND_ACCOUNTS}

    +
    {$app_strings.LBL_EMAIL_ACCOUNTS_OUTBOUND_SUBTITLE}
     
    +
    + + + + + + + + + +
     
    + +
    +
    +
    +
    +
    \ No newline at end of file diff --git a/modules/Emails/templates/emailSettingsAccounts.tpl b/modules/Emails/templates/emailSettingsAccounts.tpl new file mode 100644 index 00000000..eb679a3d --- /dev/null +++ b/modules/Emails/templates/emailSettingsAccounts.tpl @@ -0,0 +1,51 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} + + + + + + + + + +
    + {include file="modules/Emails/templates/emailSettingsAccountDetails.tpl"} +
    + +
    diff --git a/modules/Emails/templates/emailSettingsFolders.tpl b/modules/Emails/templates/emailSettingsFolders.tpl new file mode 100644 index 00000000..1ad53c6e --- /dev/null +++ b/modules/Emails/templates/emailSettingsFolders.tpl @@ -0,0 +1,67 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} + + + + + + + + + + + + + + +
    +

    {$app_strings.LBL_EMAIL_FOLDERS_TITLE}

    +
    +
    + {$app_strings.LBL_EMAIL_SETTINGS_USER_FOLDERS}: + +
    +
    +
    + +
    +
        + +
    diff --git a/modules/Emails/templates/emailSettingsGeneral.tpl b/modules/Emails/templates/emailSettingsGeneral.tpl new file mode 100644 index 00000000..4c3b6e68 --- /dev/null +++ b/modules/Emails/templates/emailSettingsGeneral.tpl @@ -0,0 +1,116 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} +
    + + + + + + + + + + + + + + + + + + + + + + +
    +

    {$app_strings.LBL_EMAIL_SETTINGS_TITLE_PREFERENCES}

    +
    + {$app_strings.LBL_EMAIL_SETTINGS_CHECK_INTERVAL}: + + {html_options options=$emailCheckInterval.options selected=$emailCheckInterval.selected name='emailCheckInterval' id='emailCheckInterval'} + + {$app_strings.LBL_EMAIL_SIGNATURES}: + + {$signaturesSettings} {$signatureButtons} + +
    + {$app_strings.LBL_EMAIL_SETTINGS_SEND_EMAIL_AS}: + + + + {$mod_strings.LBL_SIGNATURE_PREPEND}: + + +
    + {$app_strings.LBL_EMAIL_CHARSET}: + + {html_options options=$charset.options selected=$charset.selected name='default_charset' id='default_charset'} + +   + +   +
    + + + + + + + + + + +
    +

    {$app_strings.LBL_EMAIL_SETTINGS_TITLE_LAYOUT}

    +
    + {$app_strings.LBL_EMAIL_SETTINGS_SHOW_NUM_IN_LIST}: + + + +   
    + +{include file="modules/Emails/templates/emailSettingsFolders.tpl"} + + +
    + diff --git a/modules/Emails/templates/emailSettingsRules.tpl b/modules/Emails/templates/emailSettingsRules.tpl new file mode 100644 index 00000000..9f73d238 --- /dev/null +++ b/modules/Emails/templates/emailSettingsRules.tpl @@ -0,0 +1,48 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} + + + + + + + + +
    +
    {$app_strings.LBL_EMAIL_RULES_TITLE}
    +
     
     
    \ No newline at end of file diff --git a/modules/Emails/templates/importRelate.tpl b/modules/Emails/templates/importRelate.tpl new file mode 100644 index 00000000..5f325fdd --- /dev/null +++ b/modules/Emails/templates/importRelate.tpl @@ -0,0 +1,128 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} +{$SQS} +{literal} + +{/literal} +
    +
    + + + +
    + + + + + + + +
    + + + +{if $showAssignedTo} + + + +{/if} + + + + +{if $showDelete} + + +{/if} +
    + + +{sugar_translate label="LBL_ASSIGNED_TO"}: + + + + + +
    +{sugar_translate label="LBL_EMAIL_RELATE"}: + +
    + + + + + + + + +
    +
    +{sugar_translate label="LBL_DELETE_FROM_SERVER"}: + + +
    +
    +
    \ No newline at end of file diff --git a/modules/Emails/templates/outboundDialog.tpl b/modules/Emails/templates/outboundDialog.tpl new file mode 100644 index 00000000..4effac25 --- /dev/null +++ b/modules/Emails/templates/outboundDialog.tpl @@ -0,0 +1,139 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} +
    +
    + + + + + + + + + + + + + + + + + + + + + +
    + {$app_strings.LBL_EMAIL_ACCOUNTS_NAME}: + + {$app_strings.LBL_REQUIRED_SYMBOL} + + + +
    {sugar_translate module='Emails' label='LBL_CHOOSE_EMAIL_PROVIDER'}
    +
    + + + + + + + + + + + + + + + + + + + + +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + +
    {sugar_translate module='Emails' label='LBL_MAIL_SMTPSERVER'} {$app_strings.LBL_REQUIRED_SYMBOL}{sugar_translate module='Emails' label='LBL_MAIL_SMTPPORT'}
    {sugar_translate module='Emails' label='LBL_MAIL_SMTPAUTH_REQ'} + + {$app_strings.LBL_EMAIL_SMTP_SSL_OR_TLS} + +
    {sugar_translate module='Emails' label='LBL_MAIL_SMTPUSER'} {$app_strings.LBL_REQUIRED_SYMBOL}  
    {sugar_translate module='Emails' label='LBL_MAIL_SMTPPASS'} {$app_strings.LBL_REQUIRED_SYMBOL}  
    +
    +
    +   +   +
    +
    +
    diff --git a/modules/Emails/templates/outboundDialogTest.tpl b/modules/Emails/templates/outboundDialogTest.tpl new file mode 100644 index 00000000..d6a268a9 --- /dev/null +++ b/modules/Emails/templates/outboundDialogTest.tpl @@ -0,0 +1,59 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} +
    + + + + + + + + + +
    + {$app_strings.LBL_EMAIL_SETTINGS_FROM_TO_EMAIL_ADDR} + + {$app_strings.LBL_REQUIRED_SYMBOL} + + + +
    +   +   +
    +
    diff --git a/modules/Emails/templates/overlay.tpl b/modules/Emails/templates/overlay.tpl new file mode 100644 index 00000000..4867cb7c --- /dev/null +++ b/modules/Emails/templates/overlay.tpl @@ -0,0 +1,59 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} + + + +
    +
    +
    + +
    + + + + +   + +
    +
    +
    +
    +{overlib_includes} diff --git a/modules/Emails/templates/successMessage.tpl b/modules/Emails/templates/successMessage.tpl new file mode 100644 index 00000000..de53e06f --- /dev/null +++ b/modules/Emails/templates/successMessage.tpl @@ -0,0 +1,49 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} + + + + + + + +
    + {$app_strings.LBL_EMAIL_SUCCESS} +
    + {$message} +
    \ No newline at end of file diff --git a/modules/Emails/vardefs.php b/modules/Emails/vardefs.php new file mode 100644 index 00000000..968df8f9 --- /dev/null +++ b/modules/Emails/vardefs.php @@ -0,0 +1,501 @@ + 'emails', + 'acl_fields'=>false, + 'comment' => 'Contains a record of emails sent to and from the Sugar application', + 'fields' => array ( + 'id' => array ( + 'name' => 'id', + 'vname' => 'LBL_ID', + 'type' => 'id', + 'required' => true, + 'reportable'=>true, + 'comment' => 'Unique identifier', + ), + 'date_entered' => array ( + 'name' => 'date_entered', + 'vname' => 'LBL_DATE_ENTERED', + 'type' => 'datetime', + 'required'=>true, + 'comment' => 'Date record created', + ), + 'date_modified' => array ( + 'name' => 'date_modified', + 'vname' => 'LBL_DATE_MODIFIED', + 'type' => 'datetime', + 'required'=>true, + 'comment' => 'Date record last modified', + ), + 'assigned_user_id' => array ( + 'name' => 'assigned_user_id', + 'rname' => 'user_name', + 'id_name' => 'assigned_user_id', + 'vname' => 'LBL_ASSIGNED_TO', + 'type' => 'assigned_user_name', + 'table' => 'users', + 'isnull' => 'false', + 'reportable'=>true, + 'dbType' => 'id', + 'comment' => 'User ID that last modified record', + ), + 'assigned_user_name' => array ( + 'name' => 'assigned_user_name', + 'vname' => 'LBL_ASSIGNED_TO', + 'type' => 'varchar', + 'reportable'=>false, + 'source'=> 'non-db', + 'table' => 'users', + ), + 'modified_user_id' => array ( + 'name' => 'modified_user_id', + 'rname' => 'user_name', + 'id_name' => 'modified_user_id', + 'vname' => 'LBL_MODIFIED_BY', + 'type' => 'assigned_user_name', + 'table' => 'users', + 'isnull' => 'false', + 'reportable'=>true, + 'dbType' => 'id', + 'comment' => 'User ID that last modified record', + ), + 'created_by' => array ( + 'name' => 'created_by', + 'vname' => 'LBL_CREATED_BY', + 'type' => 'id', + 'len'=> '36', + 'reportable' => false, + 'comment' => 'User name who created record', + ), + 'deleted' => array ( + 'name' => 'deleted', + 'vname' => 'LBL_DELETED', + 'type' => 'bool', + 'required' => false, + 'reportable'=>false, + 'comment' => 'Record deletion indicator', + ), +/** + * DEPRECATED FOR 5.0 + 'from_addr' => array ( + 'name' => 'from_addr', + 'vname' => 'LBL_FROM', + 'type' => 'id', + 'comment' => 'Email address of the person sending the email', + ), + 'reply_to_addr' => array ( + 'name' => 'reply_to_addr', + 'vname' => 'LBL_REPLY_TO_ADDRESS', + 'type' => 'id', + 'comment' => 'Email address of person indicated in the Reply-to email field', + ), + 'to_addrs' => array ( + 'name' => 'to_addrs', + 'vname' => 'LBL_TO', + 'type' => 'id', + 'comment' => 'Email address(es) of person(s) to receive the email', + ), + 'cc_addrs' => array ( + 'name' => 'cc_addrs', + 'vname' => 'LBL_CC', + 'type' => 'id', + 'comment' => 'Email address(es) of person(s) to receive a carbon copy of the email', + ), + 'bcc_addrs' => array ( + 'name' => 'bcc_addrs', + 'vname' => 'LBL_BCC', + 'type' => 'id', + 'comment' => 'Email address(es) of person(s) to receive a blind carbon copy of the email', + ), +*/ + + + 'from_addr_name' => array ( + 'name' => 'from_addr_name', + 'type' => 'varchar', + 'vname' => 'from_addr_name', + 'source'=> 'non-db', + ), + 'reply_to_addr' => array ( + 'name' => 'reply_to_addr', + 'type' => 'varchar', + 'vname' => 'reply_to_addr', + 'source'=> 'non-db', + ), + 'to_addrs_names' => array ( + 'name' => 'to_addrs_names', + 'type' => 'varchar', + 'vname' => 'to_addrs_names', + 'source'=> 'non-db', + ), + 'cc_addrs_names' => array ( + 'name' => 'cc_addrs_names', + 'type' => 'varchar', + 'vname' => 'cc_addrs_names', + 'source'=> 'non-db', + ), + 'bcc_addrs_names' => array ( + 'name' => 'bcc_addrs_names', + 'type' => 'varchar', + 'vname' => 'bcc_addrs_names', + 'source'=> 'non-db', + ), + 'raw_source' => array ( + 'name' => 'raw_source', + 'type' => 'varchar', + 'vname' => 'raw_source', + 'source'=> 'non-db', + ), + 'description_html' => array ( + 'name' => 'description_html', + 'type' => 'varchar', + 'vname' => 'description_html', + 'source'=> 'non-db', + ), + 'description' => array ( + 'name' => 'description', + 'type' => 'varchar', + 'vname' => 'description', + 'source'=> 'non-db', + ), + 'date_sent' => array ( + 'name' => 'date_sent', + 'vname' => 'LBL_DATE_SENT', + 'type' => 'datetime', + 'type' => 'datetime', + ), + 'message_id' => array ( + 'name' => 'message_id', + 'vname' => 'LBL_MESSAGE_ID', + 'type' => 'varchar', + 'len' => 255, + 'comment' => 'ID of the email item obtained from the email transport system', + ), + + 'name' => array ( + 'name' => 'name', + 'vname' => 'LBL_SUBJECT', + 'type' => 'varchar', + 'required' => false, + 'len' => '255', + 'comment' => 'The subject of the email', + ), + 'type' => array ( + 'name' => 'type', + 'vname' => 'LBL_LIST_TYPE', + 'type' => 'enum', + 'options' => 'dom_email_types', + 'len' => 100, + 'massupdate'=>false, + 'comment' => 'Type of email (ex: draft)', + ), + 'status' => array ( + 'name' => 'status', + 'vname' => 'LBL_STATUS', + 'type' => 'enum', + 'len' => 100, + 'options' => 'dom_email_status', + ), + 'flagged' => array ( + 'name' => 'flagged', + 'vname' => 'LBL_EMAIL_FLAGGED', + 'type' => 'bool', + 'required' => false, + 'reportable'=>false, + 'comment' => 'flagged status', + ), + 'reply_to_status' => array ( + 'name' => 'reply_to_status', + 'vname' => 'LBL_EMAIL_REPLY_TO_STATUS', + 'type' => 'bool', + 'required' => false, + 'reportable'=>false, + 'comment' => 'I you reply to an email then reply to status of original email is set', + ), + 'intent' => array ( + 'name' => 'intent', + 'vname' => 'LBL_INTENT', + 'type' => 'varchar', + 'len' => 100, + 'default' => 'pick', + 'comment' => 'Target of action used in Inbound Email assignment', + ), + 'mailbox_id' => array ( + 'name' => 'mailbox_id', + 'vname' => 'LBL_MAILBOX_ID', + 'type' => 'id', + 'len'=> '36', + 'reportable' => false, + ), + 'created_by_link' => array ( + 'name' => 'created_by_link', + 'type' => 'link', + 'relationship' => 'emails_created_by', + 'vname' => 'LBL_CREATED_BY_USER', + 'link_type' => 'one', + 'module'=> 'Users', + 'bean_name'=> 'User', + 'source'=> 'non-db', + ), + 'modified_user_link' => array ( + 'name' => 'modified_user_link', + 'type' => 'link', + 'relationship' => 'emails_modified_user', + 'vname' => 'LBL_MODIFIED_BY_USER', + 'link_type' => 'one', + 'module'=> 'Users', + 'bean_name'=> 'User', + 'source'=> 'non-db', + ), + 'assigned_user_link' => array ( + 'name' => 'assigned_user_link', + 'type' => 'link', + 'relationship' => 'emails_assigned_user', + 'vname' => 'LBL_ASSIGNED_TO_USER', + 'link_type' => 'one', + 'module'=> 'Users', + 'bean_name'=> 'User', + 'source'=> 'non-db', + ), + + 'parent_name' => array ( + 'name' => 'parent_name', + 'type' => 'varchar', + 'reportable'=>false, + 'source'=> 'non-db', + ), + 'parent_type' => array ( + 'name' => 'parent_type', + 'type' => 'varchar', + 'reportable'=>false, + 'len' => 100, + 'comment' => 'Identifier of Sugar module to which this email is associated (deprecated as of 4.2)', + ), + 'parent_id' => array ( + 'name' => 'parent_id', + 'type' => 'id', + 'len' => '36', + 'reportable'=>false, + 'comment' => 'ID of Sugar object referenced by parent_type (deprecated as of 4.2)', + ), + + /* relationship collection attributes */ + /* added to support InboundEmail */ + 'accounts' => array ( + 'name' => 'accounts', + 'vname' => 'LBL_EMAILS_ACCOUNTS_REL', + 'type' => 'link', + 'relationship' => 'emails_accounts_rel', + 'module' => 'Accounts', + 'bean_name' => 'Account', + 'source' => 'non-db', + ), + 'bugs' => array ( + 'name' => 'bugs', + 'vname' => 'LBL_EMAILS_BUGS_REL', + 'type' => 'link', + 'relationship' => 'emails_bugs_rel', + 'module' => 'Bugs', + 'bean_name' => 'Bug', + 'source' => 'non-db', + ), + 'cases' => array ( + 'name' => 'cases', + 'vname' => 'LBL_EMAILS_CASES_REL', + 'type' => 'link', + 'relationship' => 'emails_cases_rel', + 'module' => 'Cases', + 'bean_name' => 'Case', + 'source' => 'non-db', + ), + 'contacts' => array ( + 'name' => 'contacts', + 'vname' => 'LBL_EMAILS_CONTACTS_REL', + 'type' => 'link', + 'relationship' => 'emails_contacts_rel', + 'module' => 'Contacts', + 'bean_name' => 'Contact', + 'source' => 'non-db', + ), + 'leads' => array ( + 'name' => 'leads', + 'vname' => 'LBL_EMAILS_LEADS_REL', + 'type' => 'link', + 'relationship' => 'emails_leads_rel', + 'module' => 'Leads', + 'bean_name' => 'Lead', + 'source' => 'non-db', + ), + 'opportunities' => array ( + 'name' => 'opportunities', + 'vname' => 'LBL_EMAILS_OPPORTUNITIES_REL', + 'type' => 'link', + 'relationship' => 'emails_opportunities_rel', + 'module' => 'Opportunities', + 'bean_name' => 'Opportunity', + 'source' => 'non-db', + ), + 'project'=> array( + 'name' => 'project', + 'vname' => 'LBL_EMAILS_PROJECT_REL', + 'type' => 'link', + 'relationship' => 'emails_projects_rel', + 'module' => 'Project', + 'bean_name' => 'Project', + 'source' => 'non-db', + ), + 'projecttask'=> array( + 'name' => 'projecttask', + 'vname' => 'LBL_EMAILS_PROJECT_TASK_REL', + 'type' => 'link', + 'relationship' => 'emails_project_task_rel', + 'module' => 'ProjectTask', + 'bean_name' => 'ProjectTask', + 'source' => 'non-db', + ), + 'prospects'=> array( + 'name' => 'prospects', + 'vname' => 'LBL_EMAILS_PROSPECT_REL', + 'type' => 'link', + 'relationship' => 'emails_prospects_rel', + 'module' => 'Prospects', + 'bean_name' => 'Prospect', + 'source' => 'non-db', + ), + + + 'tasks'=> array( + 'name' => 'tasks', + 'vname' => 'LBL_EMAILS_TASKS_REL', + 'type' => 'link', + 'relationship' => 'emails_tasks_rel', + 'module' => 'Tasks', + 'bean_name' => 'Task', + 'source' => 'non-db', + ), + 'users'=> array( + 'name' => 'users', + 'vname' => 'LBL_EMAILS_USERS_REL', + 'type' => 'link', + 'relationship' => 'emails_users_rel', + 'module' => 'Users', + 'bean_name' => 'User', + 'source' => 'non-db', + ), + 'notes' => array( + 'name' => 'notes', + 'vname' => 'LBL_EMAILS_NOTES_REL', + 'type' => 'link', + 'relationship' => 'emails_notes_rel', + 'module' => 'Notes', + 'bean_name' => 'Note', + 'source' => 'non-db', + ), + /* end relationship collections */ + + ), /* end fields() array */ + 'relationships' => array( + 'emails_assigned_user' => array( + 'lhs_module' => 'Users', + 'lhs_table' => 'users', + 'lhs_key' => 'id', + 'rhs_module' => 'Emails', + 'rhs_table' => 'emails', + 'rhs_key' => 'assigned_user_id', + 'relationship_type' => 'one-to-many' + ), + 'emails_modified_user' => array( + 'lhs_module' => 'Users', + 'lhs_table' => 'users', + 'lhs_key' => 'id', + 'rhs_module' => 'Emails', + 'rhs_table' => 'emails', + 'rhs_key' => 'modified_user_id', + 'relationship_type' => 'one-to-many' + ), + 'emails_created_by' => array( + 'lhs_module' => 'Users', + 'lhs_table' => 'users', + 'lhs_key' => 'id', + 'rhs_module' => 'Emails', + 'rhs_table' => 'emails', + 'rhs_key' => 'created_by', + 'relationship_type' => 'one-to-many' + ), + 'emails_notes_rel' => array( + 'lhs_module' => 'Emails', + 'lhs_table' => 'emails', + 'lhs_key' => 'id', + 'rhs_module' => 'Notes', + 'rhs_table' => 'notes', + 'rhs_key' => 'parent_id', + 'relationship_type' => 'one-to-many', + ), + ), // end relationships + 'indices' => array ( + array( + 'name' => 'emailspk', + 'type' => 'primary', + 'fields' => array('id'), + ), + array( + 'name' => 'idx_email_name', + 'type' => 'index', + 'fields' => array('name') + ), + array( + 'name' => 'idx_message_id', + 'type' => 'index', + 'fields' => array('message_id') + ), + array( + 'name' => 'idx_email_parent_id', + 'type' => 'index', + 'fields' => array('parent_id') + ), + array( + 'name' => 'idx_email_assigned', + 'type' => 'index', + 'fields' => array('assigned_user_id', 'type','status') + ), + ) // end indices +); + +VardefManager::createVardef('Emails','Email', array( +)); \ No newline at end of file diff --git a/modules/Emails/views/view.classic.config.php b/modules/Emails/views/view.classic.config.php new file mode 100644 index 00000000..b1369572 --- /dev/null +++ b/modules/Emails/views/view.classic.config.php @@ -0,0 +1,60 @@ + array( + 'index' => array( + 'show_header' => true, + 'show_subpanels' => false, + 'show_search' => false, + 'show_footer' => true, + 'show_javascript' => true, + ), + 'Compose' => array( + 'show_header' => true, + 'show_subpanels' => false, + 'show_search' => false, + 'show_footer' => true, + 'show_javascript' => true, + ), + ), +); diff --git a/modules/Emails/views/view.modulelistmenu.php b/modules/Emails/views/view.modulelistmenu.php new file mode 100644 index 00000000..4dcf3dfd --- /dev/null +++ b/modules/Emails/views/view.modulelistmenu.php @@ -0,0 +1,55 @@ +get_recently_viewed($GLOBALS['current_user']->id, array('Emails','EmailTemplates')); + foreach ( $history as $key => $row ) { + $history[$key]['item_summary_short'] = getTrackerSubstring($row['item_summary']); + $history[$key]['image'] = SugarThemeRegistry::current() + ->getImage($row['module_name'],'border="0" align="absmiddle" alt="'.$row['item_summary'].'"'); + } + $this->ss->assign('LAST_VIEWED',$history); + + $this->ss->display('include/MVC/View/tpls/modulelistmenu.tpl'); + } +} +?> diff --git a/modules/Emails/views/view.quickcreate.php b/modules/Emails/views/view.quickcreate.php new file mode 100644 index 00000000..15519bc7 --- /dev/null +++ b/modules/Emails/views/view.quickcreate.php @@ -0,0 +1,84 @@ +getPreference('email_link_type'); + $defaultPref = $GLOBALS['sugar_config']['email_default_client']; + if($userPref != '') + $client = $userPref; + else + $client = $defaultPref; + + if ( $client == 'sugar' ) { + $eUi = new EmailUI(); + if(!empty($this->bean->id) && !in_array($this->bean->object_name,array('EmailMan')) ) { + $fullComposeUrl = "index.php?module=Emails&action=Compose&parent_id={$this->bean->id}&parent_type={$this->bean->module_dir}"; + $composeData = array('parent_id'=>$this->bean->id, 'parent_type' => $this->bean->module_dir); + } else { + $fullComposeUrl = "index.php?module=Emails&action=Compose"; + $composeData = array('parent_id'=>'', 'parent_type' => ''); + } + + $j_quickComposeOptions = $eUi->generateComposePackageForQuickCreate($composeData, $fullComposeUrl); + $json_obj = getJSONobj(); + $opts = $json_obj->decode($j_quickComposeOptions); + $opts['menu_id'] = 'dccontent'; + + $ss = new Sugar_Smarty(); + $ss->assign('json_output', $json_obj->encode($opts)); + $ss->display('modules/Emails/templates/dceMenuQuickCreate.tpl'); + } + else { + $emailAddress = ''; + if(!empty($this->bean->id) && !in_array($this->bean->object_name,array('EmailMan')) ) { + $emailAddress = $this->bean->emailAddress->getPrimaryAddress($this->bean); + } + echo ""; + die(); + } + } +} \ No newline at end of file diff --git a/modules/Employees/Employee.php b/modules/Employees/Employee.php new file mode 100644 index 00000000..7dff5463 --- /dev/null +++ b/modules/Employees/Employee.php @@ -0,0 +1,230 @@ +setupCustomFields('Employees'); + $this->emailAddress = new SugarEmailAddress(); + } + + + function get_summary_text() { + $this->_create_proper_name_field(); + return $this->name; + } + + + function fill_in_additional_list_fields() { + $this->fill_in_additional_detail_fields(); + } + + function fill_in_additional_detail_fields() + { + global $locale; + $query = "SELECT u1.first_name, u1.last_name from users u1, users u2 where u1.id = u2.reports_to_id AND u2.id = '$this->id' and u1.deleted=0"; + $result =$this->db->query($query, true, "Error filling in additional detail fields") ; + + $row = $this->db->fetchByAssoc($result); + $GLOBALS['log']->debug("additional detail query results: $row"); + + if($row != null) + { + $this->reports_to_name = stripslashes($locale->getLocaleFormattedName($row['first_name'], $row['last_name'])); + } + else + { + $this->reports_to_name = ''; + } + } + + function retrieve_employee_id($employee_name) + { + $query = "SELECT id from users where user_name='$user_name' AND deleted=0"; + $result = $this->db->query($query, false,"Error retrieving employee ID: "); + $row = $this->db->fetchByAssoc($result); + return $row['id']; + } + + /** + * @return -- returns a list of all employees in the system. + * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.. + * All Rights Reserved.. + * Contributor(s): ______________________________________.. + */ + function verify_data() + { + //none of the checks from the users module are valid here since the user_name and + //is_admin_on fields are not editable. + return TRUE; + } + + function get_list_view_data(){ + + global $current_user; + $this->_create_proper_name_field(); // create proper NAME (by combining first + last) + $user_fields = $this->get_list_view_array(); + // Copy over the reports_to_name + if ( isset($GLOBALS['app_list_strings']['messenger_type_dom'][$this->messenger_type]) ) + $user_fields['MESSENGER_TYPE'] = $GLOBALS['app_list_strings']['messenger_type_dom'][$this->messenger_type]; + if ( isset($GLOBALS['app_list_strings']['employee_status_dom'][$this->employee_status]) ) + $user_fields['EMPLOYEE_STATUS'] = $GLOBALS['app_list_strings']['employee_status_dom'][$this->employee_status]; + $user_fields['REPORTS_TO_NAME'] = $this->reports_to_name; + $user_fields['NAME'] = empty($this->name) ? '' : $this->name; + $user_fields['EMAIL1'] = $this->emailAddress->getPrimaryAddress($this,$this->id,'Users'); + $this->email1 = $user_fields['EMAIL1']; + $user_fields['EMAIL1_LINK'] = $current_user->getEmailLink('email1', $this, '', '', 'ListView'); + return $user_fields; + } + + function list_view_parse_additional_sections(&$list_form, $xTemplateSection){ + return $list_form; + } + + + function create_export_query($order_by, $where) { + include('modules/Employees/field_arrays.php'); + + $cols = ''; + foreach($fields_array['Employee']['export_fields'] as $field) { + $cols .= (empty($cols)) ? '' : ', '; + $cols .= $field; + } + + $query = "SELECT {$cols} FROM users "; + + $where_auto = " users.deleted = 0"; + + if($where != "") + $query .= " WHERE $where AND " . $where_auto; + else + $query .= " WHERE " . $where_auto; + + if($order_by != "") + $query .= " ORDER BY $order_by"; + else + $query .= " ORDER BY users.user_name"; + + return $query; + } + + //use parent class + /** + * Generate the name field from the first_name and last_name fields. + */ + /* + function _create_proper_name_field() { + global $locale; + $full_name = $locale->getLocaleFormattedName($this->first_name, $this->last_name); + $this->name = $full_name; + $this->full_name = $full_name; + } + */ + + function preprocess_fields_on_save(){ + parent::preprocess_fields_on_save(); + + } +} + +?> diff --git a/modules/Employees/Error.php b/modules/Employees/Error.php new file mode 100644 index 00000000..01a3312a --- /dev/null +++ b/modules/Employees/Error.php @@ -0,0 +1,52 @@ + +

    + +

    + +
    + diff --git a/modules/Employees/Forms.php b/modules/Employees/Forms.php new file mode 100644 index 00000000..fc1cffa7 --- /dev/null +++ b/modules/Employees/Forms.php @@ -0,0 +1,138 @@ + +function verify_data(form) { + var isError = false; + var errorMessage = ""; + if (trim(form.last_name.value) == "") { + isError = true; + errorMessage += "\\n$lbl_last_name"; + } + + if (isError == true) { + alert("$err_missing_required_fields" + errorMessage); + return false; + } + if (trim(form.email1.value) != "" && !/^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,})+$/.test(form.email1.value)) { + alert('"' + form.email1.value + '" $err_invalid_email_address'); + return false; + } + if (trim(form.email2.value) != "" && !/^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,})+$/.test(form.email2.value)) { + alert('"' + form.email2.value + '" $err_invalid_email_address'); + return false; + } + if ((trim(form.reports_to_name.value) == "" && trim(form.reports_to_id.value) != "") || + (trim(form.reports_to_name.value) != "" && trim(form.reports_to_id.value) == "")) { + alert('$sqs_no_match'); + return false; + } + + if (document.EditView.return_id.value != '' && document.EditView.return_id.value == form.reports_to_id.value) { + alert('$err_self_reporting'); + return false; + } + return true; +} + + +EOQ; + +return $the_script; +} + +function get_chooser_js() +{ +$the_script = << + + +EOQ; + +return $the_script; +} + +?> diff --git a/modules/Employees/Menu.php b/modules/Employees/Menu.php new file mode 100644 index 00000000..c31e724b --- /dev/null +++ b/modules/Employees/Menu.php @@ -0,0 +1,61 @@ + diff --git a/modules/Employees/Popup_picker.html b/modules/Employees/Popup_picker.html new file mode 100644 index 00000000..1d70d030 --- /dev/null +++ b/modules/Employees/Popup_picker.html @@ -0,0 +1,113 @@ + + + + + + + + + + + + +
    + +
    + + + + + + +{PAGINATION} + + + + + + + + + + + + +{PAGINATION} +
    {MOD.LBL_LIST_NAME}{arrow_start}{first_name_arrow}{arrow_end}{MOD.LBL_LIST_USER_NAME}{arrow_start}{user_name_arrow}{arrow_end}
    {EMPLOYEE.FIRST_NAME} {EMPLOYEE.LAST_NAME}{EMPLOYEE.USER_NAME}
    +{ASSOCIATED_JAVASCRIPT_DATA} + \ No newline at end of file diff --git a/modules/Employees/Popup_picker.php b/modules/Employees/Popup_picker.php new file mode 100644 index 00000000..4cf128be --- /dev/null +++ b/modules/Employees/Popup_picker.php @@ -0,0 +1,163 @@ +_get_where_clause(); + + + + $first_name = empty($_REQUEST['first_name']) ? '' : $_REQUEST['first_name']; + $last_name = empty($_REQUEST['last_name']) ? '' : $_REQUEST['last_name']; + $user_name = empty($_REQUEST['user_name']) ? '' : $_REQUEST['user_name']; + $request_data = empty($_REQUEST['request_data']) ? '' : $_REQUEST['request_data']; + $hide_clear_button = empty($_REQUEST['hide_clear_button']) ? false : true; + + $button = "
    \n"; + if(!$hide_clear_button) + { + $button .= "\n"; + } + $button .= "\n"; + $button .= "
    \n"; + + $form = new XTemplate('modules/Employees/Popup_picker.html'); + $form->assign('MOD', $mod_strings); + $form->assign('APP', $app_strings); + $form->assign('THEME', $theme); + $form->assign('MODULE_NAME', $currentModule); + $form->assign('FIRST_NAME', $first_name); + $form->assign('LAST_NAME', $last_name); + $form->assign('USER_NAME', $user_name); + $form->assign('request_data', $request_data); + + ob_start(); + insert_popup_header($theme); + $output_html .= ob_get_contents(); + ob_end_clean(); + + $output_html .= get_form_header($mod_strings['LBL_SEARCH_FORM_TITLE'], '', false); + + $form->parse('main.SearchHeader'); + $output_html .= $form->text('main.SearchHeader'); + + // Reset the sections that are already in the page so that they do not print again later. + $form->reset('main.SearchHeader'); + + // create the listview + $seed_bean = new Employee(); + $ListView = new ListView(); + $ListView->show_export_button = false; + $ListView->process_for_popups = true; + $ListView->setXTemplate($form); + $ListView->setHeaderTitle($mod_strings['LBL_LIST_FORM_TITLE']); + $ListView->setHeaderText($button); + $ListView->setQuery($where, '', 'user_name', 'EMPLOYEE'); + $ListView->setModStrings($mod_strings); + + ob_start(); + $ListView->processListView($seed_bean, 'main', 'EMPLOYEE'); + $output_html .= ob_get_contents(); + ob_end_clean(); + + $output_html .= insert_popup_footer(); + return $output_html; + } +} // end of class Popup_Picker +?> \ No newline at end of file diff --git a/modules/Employees/Save.php b/modules/Employees/Save.php new file mode 100644 index 00000000..79a99def --- /dev/null +++ b/modules/Employees/Save.php @@ -0,0 +1,98 @@ +retrieve($_POST['record']); +//rrs bug: 30035 - I am not sure how this ever worked b/c old_reports_to_id was not populated. +$old_reports_to_id = $focus->reports_to_id; + +populateFromRow($focus,$_POST); + +$focus->save(); +$return_id = $focus->id; + + +if(isset($_POST['return_module']) && $_POST['return_module'] != "") $return_module = $_POST['return_module']; +else $return_module = "Employees"; +if(isset($_POST['return_action']) && $_POST['return_action'] != "") $return_action = $_POST['return_action']; +else $return_action = "DetailView"; +if(isset($_POST['return_id']) && $_POST['return_id'] != "") $return_id = $_POST['return_id']; + +$GLOBALS['log']->debug("Saved record with id of ".$return_id); + + +header("Location: index.php?action=$return_action&module=$return_module&record=$return_id"); + + +function populateFromRow(&$focus,$row){ + + + //only employee specific field values need to be copied. + $e_fields=array('first_name','last_name','reports_to_id','description','phone_home','phone_mobile','phone_work','phone_other','phone_fax','address_street','address_city','address_state','address_country','address_country', 'address_postalcode', 'messenger_id','messenger_type'); + if ( is_admin($GLOBALS['current_user']) ) + $e_fields = array_merge($e_fields,array('title','department','employee_status')); + $nullvalue=''; + foreach($e_fields as $field) + { + $rfield = $field; // fetch returns it in lowercase only + if(isset($row[$rfield])) + { + $focus->$field = $row[$rfield]; + } + else + { + $focus->$field = $nullvalue; + } + } +} +?> \ No newline at end of file diff --git a/modules/Employees/WapAuthenticate.php b/modules/Employees/WapAuthenticate.php new file mode 100644 index 00000000..3b020a20 --- /dev/null +++ b/modules/Employees/WapAuthenticate.php @@ -0,0 +1,137 @@ +user_name = $_REQUEST['user_name']; +$user_password = $_REQUEST['user_password']; + +$focus->load_user($user_password); + +if($focus->is_authenticated()) +{ + // save the user information into the session + // go to the home screen + if (!empty($_POST['login_record'])) { + $login_direction = "module={$_POST['login_module']}&action={$_POST['login_action']}&record={$_POST['login_record']}"; + } + else { + $login_direction = "action=index&module=Home"; + } + + header("Location: index.php?{$login_direction}"); + unset($_SESSION['login_password']); + unset($_SESSION['login_error']); + unset($_SESSION['login_user_name']); + + $_SESSION['authenticated_user_id'] = $focus->id; + + // store the user's theme in the session + if (isset($_REQUEST['login_theme'])) { + $authenticated_user_theme = $_REQUEST['login_theme']; + } + elseif (isset($_REQUEST['ck_login_theme_20'])) { + $authenticated_user_theme = $_REQUEST['ck_login_theme_20']; + } + else { + $authenticated_user_theme = $sugar_config['default_theme']; + } + + // store the user's language in the session + if (isset($_REQUEST['login_language'])) { + $authenticated_user_language = $_REQUEST['login_language']; + } + elseif (isset($_REQUEST['ck_login_language_20'])) { + $authenticated_user_language = $_REQUEST['ck_login_language_20']; + } + else { + $authenticated_user_language = $sugar_config['default_language']; + } + + // If this is the default user and the default user theme is set to reset, reset it to the default theme value on each login + if($reset_theme_on_default_user && $focus->user_name == $sugar_config['default_user_name']) + { + $authenticated_user_theme = $sugar_config['default_theme']; + } + if(isset($reset_language_on_default_user) && $reset_language_on_default_user && $focus->user_name == $sugar_config['default_user_name']) + { + $authenticated_user_language = $sugar_config['default_language']; + } + + $_SESSION['authenticated_user_theme'] = $authenticated_user_theme; + $_SESSION['authenticated_user_language'] = $authenticated_user_language; + + $GLOBALS['log']->debug("authenticated_user_theme is $authenticated_user_theme"); + $GLOBALS['log']->debug("authenticated_user_language is $authenticated_user_language"); + +// Clear all uploaded import files for this user if it exists + + $tmp_file_name = $sugar_config['import_dir']. "IMPORT_".$focus->id; + + if (file_exists($tmp_file_name)) + { + unlink($tmp_file_name); + } + +} +else +{ + $_SESSION['login_user_name'] = $focus->user_name; + $_SESSION['login_password'] = $user_password; + $_SESSION['login_error'] = $mod_strings['ERR_INVALID_PASSWORD']; + + // go back to the login screen. + // create an error message for the user. + header("Location: index.php"); +} + +?> diff --git a/modules/Employees/WapMenu.php b/modules/Employees/WapMenu.php new file mode 100644 index 00000000..67644ffc --- /dev/null +++ b/modules/Employees/WapMenu.php @@ -0,0 +1,56 @@ + \ No newline at end of file diff --git a/modules/Employees/controller.php b/modules/Employees/controller.php new file mode 100644 index 00000000..b28a9505 --- /dev/null +++ b/modules/Employees/controller.php @@ -0,0 +1,69 @@ +id) + $this->view = 'edit'; + else + sugar_die("Unauthorized access to employees."); + return true; + } + + protected function action_delete() + { + if($_REQUEST['record'] != $GLOBALS['current_user']->id && (is_admin($GLOBALS['current_user'])||is_admin_for_module($GLOBALS['current_user'],'Users'))) + { + $u = new User(); + $u->retrieve($_REQUEST['record']); + $u->deleted = 1; + $u->status = 'Inactive'; + $u->employee_status = 'Terminated'; + $u->save(); + $GLOBALS['log']->info("User id: {$GLOBALS['current_user']->id} deleted user record: {$_REQUEST['record']}"); + + SugarApplication::redirect("index.php?module=Employees&action=index"); + } + else + sugar_die("Unauthorized access to administration."); + } + +} +?> \ No newline at end of file diff --git a/modules/Employees/field_arrays.php b/modules/Employees/field_arrays.php new file mode 100644 index 00000000..3923c4c8 --- /dev/null +++ b/modules/Employees/field_arrays.php @@ -0,0 +1,50 @@ + \ No newline at end of file diff --git a/modules/Employees/language/en_us.lang.php b/modules/Employees/language/en_us.lang.php new file mode 100644 index 00000000..281fec6a --- /dev/null +++ b/modules/Employees/language/en_us.lang.php @@ -0,0 +1,136 @@ + 'Employees', + 'LBL_MODULE_TITLE' => 'Employees: Home', + 'LBL_SEARCH_FORM_TITLE' => 'Employee Search', + 'LBL_LIST_FORM_TITLE' => 'Employees', + 'LBL_NEW_FORM_TITLE' => 'New Employee', + 'LBL_EMPLOYEE' => 'Employees:', + 'LBL_LOGIN' => 'Login', + 'LBL_RESET_PREFERENCES' => 'Reset To Default Preferences', + 'LBL_TIME_FORMAT' => 'Time Format:', + 'LBL_DATE_FORMAT' => 'Date Format:', + 'LBL_TIMEZONE' => 'Current Time:', + 'LBL_CURRENCY' => 'Currency:', + 'LBL_LIST_NAME' => 'Name', + 'LBL_LIST_LAST_NAME' => 'Last Name', + 'LBL_LIST_EMPLOYEE_NAME' => 'Employee Name', + 'LBL_LIST_DEPARTMENT' => 'Department', + 'LBL_LIST_REPORTS_TO_NAME' => 'Reports To', + 'LBL_LIST_EMAIL' => 'Email', + 'LBL_LIST_PRIMARY_PHONE' => 'Primary Phone', + 'LBL_LIST_USER_NAME' => 'User Name', + 'LBL_LIST_ADMIN' => 'Admin', + 'LBL_NEW_EMPLOYEE_BUTTON_TITLE' => 'New Employee [Alt+N]', + 'LBL_NEW_EMPLOYEE_BUTTON_LABEL' => 'New Employee', + 'LBL_NEW_EMPLOYEE_BUTTON_KEY' => 'N', + 'LBL_ERROR' => 'Error:', + 'LBL_PASSWORD' => 'Password:', + 'LBL_EMPLOYEE_NAME' => 'Employee Name:', + 'LBL_USER_NAME' => 'User Name:', + 'LBL_FIRST_NAME' => 'First Name:', + 'LBL_LAST_NAME' => 'Last Name:', + 'LBL_EMPLOYEE_SETTINGS' => 'Employee Settings', + 'LBL_THEME' => 'Theme:', + 'LBL_LANGUAGE' => 'Language:', + 'LBL_ADMIN' => 'Administrator:', + 'LBL_EMPLOYEE_INFORMATION' => 'Employee Information', + 'LBL_OFFICE_PHONE' => 'Office Phone:', + 'LBL_REPORTS_TO' => 'Reports to Id:', + 'LBL_REPORTS_TO_NAME' => 'Reports to', + 'LBL_OTHER_PHONE' => 'Other:', + 'LBL_OTHER_EMAIL' => 'Other Email:', + 'LBL_NOTES' => 'Notes:', + 'LBL_DEPARTMENT' => 'Department:', + 'LBL_TITLE' => 'Title:', + 'LBL_ANY_ADDRESS' => 'Any Address:', + 'LBL_ANY_PHONE' => 'Any Phone:', + 'LBL_ANY_EMAIL' => 'Any Email:', + 'LBL_ADDRESS' => 'Address:', + 'LBL_CITY' => 'City:', + 'LBL_STATE' => 'State:', + 'LBL_POSTAL_CODE' => 'Postal Code:', + 'LBL_COUNTRY' => 'Country:', + 'LBL_NAME' => 'Name:', + 'LBL_MOBILE_PHONE' => 'Mobile:', + 'LBL_OTHER' => 'Other:', + 'LBL_FAX' => 'Fax:', + 'LBL_EMAIL' => 'Email Address:', + 'LBL_HOME_PHONE' => 'Home Phone:', + 'LBL_WORK_PHONE' => 'Work Phone:', + 'LBL_ADDRESS_INFORMATION' => 'Address Information', + 'LBL_EMPLOYEE_STATUS' => 'Employee Status:', + 'LBL_PRIMARY_ADDRESS' => 'Primary Address:', + 'LBL_SAVED_SEARCH' => 'Layout Options', + 'LBL_CREATE_USER_BUTTON_TITLE' => 'Create User [Alt+N]', + 'LBL_CREATE_USER_BUTTON_LABEL' => 'Create User', + 'LBL_CREATE_USER_BUTTON_KEY' => 'N', + 'LBL_FAVORITE_COLOR' => 'Favorite Color:', + 'LBL_MESSENGER_ID' => 'IM Name:', + 'LBL_MESSENGER_TYPE' => 'IM Type:', + 'ERR_EMPLOYEE_NAME_EXISTS_1' => 'The employee name ', + 'ERR_EMPLOYEE_NAME_EXISTS_2' => ' already exists. Duplicate employee names are not allowed. Change the employee name to be unique.', + 'ERR_LAST_ADMIN_1' => 'The employee name "', + 'ERR_LAST_ADMIN_2' => '" is the last employee with administrator access. At least one employee must be an administrator.', + 'LNK_NEW_EMPLOYEE' => 'Create Employee', + 'LNK_EMPLOYEE_LIST' => 'View Employees', + 'ERR_DELETE_RECORD' => 'You must specify a record number to delete the account.', + 'LBL_LIST_EMPLOYEE_STATUS' => 'Employee Status', + + 'LBL_SUGAR_LOGIN' => 'Is Sugar User', + 'LBL_RECEIVE_NOTIFICATIONS' => 'Notify on Assignment', + 'LBL_IS_ADMIN' => 'Is Administrator', + 'LBL_GROUP' => 'Group User', + 'LBL_PORTAL_ONLY' => 'Portal Only User', + 'LBL_PHOTO' => 'Photo', + 'LBL_DELETE_USER_CONFIRM' => 'This Employee is also a User. Deleting the Employee record will also delete the User record, and the User will no longer be able to access the application. Do you want to proceed with deleting this record?', + 'LBL_DELETE_EMPLOYEE_CONFIRM' => 'Are you sure you want to delete this employee?', + +); + + +?> diff --git a/modules/Employees/metadata/SearchFields.php b/modules/Employees/metadata/SearchFields.php new file mode 100644 index 00000000..c12db666 --- /dev/null +++ b/modules/Employees/metadata/SearchFields.php @@ -0,0 +1,69 @@ + array( 'query_type'=>'default'), + 'last_name'=> array('query_type'=>'default'), + 'search_name'=> array('query_type'=>'default','db_field'=>array('first_name','last_name')), + 'email'=> array( + 'query_type' => 'default', + 'operator' => 'subquery', + 'subquery' => 'SELECT eabr.bean_id FROM email_addr_bean_rel eabr JOIN email_addresses ea ON (ea.id = eabr.email_address_id) WHERE eabr.deleted=0 and ea.email_address LIKE', + 'db_field' => array( + 'id', + ) + ), + 'phone'=> array( + 'query_type' => 'default', + 'operator' => 'subquery', + 'subquery' => array('SELECT id FROM users where phone_home LIKE ', + 'SELECT id FROM users where phone_fax LIKE', + 'SELECT id FROM users where phone_other LIKE', + 'SELECT id FROM users where phone_work LIKE', + 'SELECT id FROM users where phone_mobile LIKE', + 'OR' =>true + ), + 'db_field' => array( + 'id', + ) + ), + 'current_user_only'=> array('query_type'=>'default','db_field'=>array('assigned_user_id'),'my_items'=>true, 'vname' => 'LBL_CURRENT_USER_FILTER', 'type' => 'bool'), + + 'employee_status'=> array('query_type'=>'default', 'options' => 'employee_status_dom', 'template_var' => 'STATUS_OPTIONS', 'options_add_blank' => true) + ); +?> diff --git a/modules/Employees/metadata/detailviewdefs.php b/modules/Employees/metadata/detailviewdefs.php new file mode 100644 index 00000000..4f7b58f2 --- /dev/null +++ b/modules/Employees/metadata/detailviewdefs.php @@ -0,0 +1,167 @@ + array('form' => array('buttons'=>array( + array('customCode'=>'{if $DISPLAY_EDIT}{/if}'), + array('customCode'=>'{if $DISPLAY_DUPLICATE}{/if}'), + + array('customCode'=>'{if $DISPLAY_DELETE}{/if}'), + ) + ), + 'maxColumns' => '2', + 'widths' => array( + array('label' => '10', 'field' => '30'), + array('label' => '10', 'field' => '30') + ), + ), +'panels' =>array ( + + array ( + 'employee_status', + ), + + array ( + array ( + 'name' => 'first_name', + 'customCode' => '{$fields.full_name.value}', + 'label' => 'LBL_NAME', + ), + ), + + array ( + + array ( + 'name' => 'title', + 'label' => 'LBL_TITLE', + ), + + array ( + 'name' => 'phone_work', + 'label' => 'LBL_OFFICE_PHONE', + ), + ), + + array ( + + array ( + 'name' => 'department', + 'label' => 'LBL_DEPARTMENT', + ), + + array ( + 'name' => 'phone_mobile', + 'label' => 'LBL_MOBILE_PHONE', + ), + ), + + array ( + + array ( + 'name' => 'reports_to_name', + 'customCode' => '
    {$fields.reports_to_name.value}', + 'label' => 'LBL_REPORTS_TO_NAME', + ), + + array ( + 'name' => 'phone_other', + 'label' => 'LBL_OTHER', + ), + ), + + array ( + '', + array ( + 'name' => 'phone_fax', + 'label' => 'LBL_FAX', + ), + ), + + array ( + + '', + + array ( + 'name' => 'phone_home', + 'label' => 'LBL_HOME_PHONE', + ), + ), + + array ( + + array ( + 'name' => 'messenger_type', + 'label' => 'LBL_MESSENGER_TYPE', + ), + ), + + array ( + + array ( + 'name' => 'messenger_id', + 'label' => 'LBL_MESSENGER_ID', + ), + ), + + array ( + + array ( + 'name' => 'address_country', + 'customCode' => '{$fields.address_street.value}
    {$fields.address_city.value} {$fields.address_state.value}  {$fields.address_postalcode.value}
    {$fields.address_country.value}', + 'label' => 'LBL_ADDRESS', + ), + ), + + array ( + + array ( + 'name' => 'description', + 'label' => 'LBL_NOTES', + ), + ), + array( + array ( + 'name' => 'email1', + 'label' => 'LBL_EMAIL', + ), + ), + +) + + + +); +?> \ No newline at end of file diff --git a/modules/Employees/metadata/editviewdefs.php b/modules/Employees/metadata/editviewdefs.php new file mode 100644 index 00000000..1af40f7b --- /dev/null +++ b/modules/Employees/metadata/editviewdefs.php @@ -0,0 +1,122 @@ + array('maxColumns' => '2', + 'widths' => array( + array('label' => '10', 'field' => '30'), + array('label' => '10', 'field' => '30') + ), + ), + 'panels' =>array ( + + 'default'=>array ( + array ( + array('name' => 'employee_status', + 'customCode' => ' +'), + ), + array ( + 'first_name', + array('name'=>'last_name', 'displayParams'=>array('required'=>true)), + ), + array ( + array( + 'name'=>'title', + 'customCode' => '{if $EDIT_REPORTS_TO}'. + '{else}{$fields.title.value}{/if}'), + array('name'=>'phone_work','label'=>'LBL_OFFICE_PHONE'), + ), + array ( + array( + 'name'=>'department', + 'customCode' => '{if $EDIT_REPORTS_TO}'. + '{else}{$fields.department.value}{/if}'), + 'phone_mobile', + ), + array ( + array( + 'name' => 'reports_to_name', + 'label' => 'LBL_REPORTS_TO_NAME', + 'customCode' => '{if $EDIT_REPORTS_TO}{$REPORTS_TO_JS}'. + ''. + ' '. + ''. + '{else}{$fields.reports_to_name.value}{/if}', + ), + 'phone_other', + ), + array ( + '', + array('name'=>'phone_fax', 'label'=>'LBL_FAX'), + ), + array ( + '', + 'phone_home', + ), + array ( + 'messenger_type', + ), + array ( + 'messenger_id', + ), + array ( + array('name'=>'description', 'label'=>'LBL_NOTES'), + ), + array ( + array('name'=>'address_street', 'type'=>'text', 'label'=>'LBL_PRIMARY_ADDRESS', 'displayParams'=>array('rows'=>2, 'cols'=>30)), + array('name'=>'address_city', 'label'=>'LBL_CITY'), + ), + array ( + array('name'=>'address_state', 'label'=>'LBL_STATE'), + array('name'=>'address_postalcode', 'label'=>'LBL_POSTAL_CODE'), + ), + array ( + array('name'=>'address_country', 'label'=>'LBL_COUNTRY'), + ), + array( + array ( + 'name' => 'email1', + 'label' => 'LBL_EMAIL', + ), + ), + ), +), + +); +?> \ No newline at end of file diff --git a/modules/Employees/metadata/listviewdefs.php b/modules/Employees/metadata/listviewdefs.php new file mode 100644 index 00000000..efbd9206 --- /dev/null +++ b/modules/Employees/metadata/listviewdefs.php @@ -0,0 +1,87 @@ + array( + 'width' => '20', + 'label' => 'LBL_LIST_NAME', + 'link' => true, + 'related_fields' => array('last_name', 'first_name'), + 'orderBy' => 'last_name', + 'default' => true), + 'DEPARTMENT' => array( + 'width' => '10', + 'label' => 'LBL_DEPARTMENT', + 'link' => true, + 'default' => true), + 'TITLE' => array( + 'width' => '15', + 'label' => 'LBL_TITLE', + 'link' => true, + 'default' => true), + 'REPORTS_TO_NAME' => array( + 'width' => '15', + 'label' => 'LBL_LIST_REPORTS_TO_NAME', + 'link' => true, + 'sortable' => false, + 'default' => true), + 'EMAIL1' => array( + 'width' => '15', + 'label' => 'LBL_LIST_EMAIL', + 'link' => true, + 'customCode' => '{$EMAIL1_LINK}{$EMAIL1}', + 'default' => true, + 'sortable' => false), + 'PHONE_WORK' => array( + 'width' => '10', + 'label' => 'LBL_LIST_PHONE', + 'link' => true, + 'default' => true), + 'EMPLOYEE_STATUS' => array( + 'width' => '10', + 'label' => 'LBL_LIST_EMPLOYEE_STATUS', + 'link' => false, + 'default' => true), + 'DATE_ENTERED' => array ( + 'width' => '10', + 'label' => 'LBL_DATE_ENTERED', + 'default' => true), +); +?> diff --git a/modules/Employees/metadata/searchdefs.php b/modules/Employees/metadata/searchdefs.php new file mode 100644 index 00000000..6e500f42 --- /dev/null +++ b/modules/Employees/metadata/searchdefs.php @@ -0,0 +1,117 @@ + array('maxColumns' => '3', + 'widths' => array('label' => '10', 'field' => '30'), + ), + 'layout' => array( + 'basic_search' => array( + array('name'=>'search_name','label' =>'LBL_NAME', 'type' => 'name'), + array('name'=>'current_user_only', 'label'=>'LBL_CURRENT_USER_FILTER', 'type'=>'bool'), + ), + 'advanced_search' => array( + 'first_name', + 'last_name', + 'employee_status', + 'title', + 'phone' => + array ( + 'name' => 'phone', + 'label' => 'LBL_ANY_PHONE', + 'type' => 'name', + 'default' => true, + 'width' => '10%', + ), + 'department', + 'email' => + array ( + 'name' => 'email', + 'label' => 'LBL_ANY_EMAIL', + 'type' => 'name', + 'default' => true, + 'width' => '10%', + ), + 'address_street' => + array ( + 'name' => 'address_street', + 'label' => 'LBL_ANY_ADDRESS', + 'type' => 'name', + 'default' => true, + 'width' => '10%', + ), + 'address_city' => + array ( + 'name' => 'address_city', + 'label' => 'LBL_CITY', + 'type' => 'name', + 'default' => true, + 'width' => '10%', + ), + 'address_state' => + array ( + 'name' => 'address_state', + 'label' => 'LBL_STATE', + 'type' => 'name', + 'default' => true, + 'width' => '10%', + ), + 'address_postalcode' => + array ( + 'name' => 'address_postalcode', + 'label' => 'LBL_POSTAL_CODE', + 'type' => 'name', + 'default' => true, + 'width' => '10%', + ), + + 'address_country' => + array ( + 'name' => 'address_country', + 'label' => 'LBL_COUNTRY', + 'type' => 'name', + 'default' => true, + 'width' => '10%', + ), + ), + ), + ); diff --git a/modules/Employees/vardefs.php b/modules/Employees/vardefs.php new file mode 100644 index 00000000..f8c1f39d --- /dev/null +++ b/modules/Employees/vardefs.php @@ -0,0 +1,49 @@ + diff --git a/modules/Employees/views/view.detail.php b/modules/Employees/views/view.detail.php new file mode 100644 index 00000000..0d36b8cf --- /dev/null +++ b/modules/Employees/views/view.detail.php @@ -0,0 +1,79 @@ +id) { + $this->ss->assign('DISPLAY_EDIT', true); + } + if(is_admin($GLOBALS['current_user'])){ + $this->ss->assign('DISPLAY_DUPLICATE', true); + } + + $showDeleteButton = FALSE; + if( $_REQUEST['record'] != $GLOBALS['current_user']->id && ( is_admin($GLOBALS['current_user']) || is_admin_for_module($GLOBALS['current_user'],'Users')) ) + { + $showDeleteButton = TRUE; + if( empty($this->bean->user_name) ) //Indicates just employee + $deleteWarning = $GLOBALS['mod_strings']['LBL_DELETE_EMPLOYEE_CONFIRM']; + else + $deleteWarning = $GLOBALS['mod_strings']['LBL_DELETE_USER_CONFIRM']; + $this->ss->assign('DELETE_WARNING', $deleteWarning); + } + $this->ss->assign('DISPLAY_DELETE', $showDeleteButton); + + parent::display(); + } +} +?> diff --git a/modules/Employees/views/view.edit.php b/modules/Employees/views/view.edit.php new file mode 100644 index 00000000..d939509e --- /dev/null +++ b/modules/Employees/views/view.edit.php @@ -0,0 +1,75 @@ +bean->user_name + && !empty($sugar_config['lock_default_user_name'])) + { + $this->ss->assign('STATUS_DISABLE', true); + } + if(is_admin($GLOBALS['current_user'])) { + $json = getJSONobj(); + require_once('include/QuickSearchDefaults.php'); + $qsd = new QuickSearchDefaults(); + $sqs_objects = array('EditView_reports_to_name' => $qsd->getQSUser()); + $sqs_objects['EditView_reports_to_name']['populate_list'] = array('reports_to_name', 'reports_to_id'); + $quicksearch_js = ''; + + $this->ss->assign('REPORTS_TO_JS', $quicksearch_js); + $this->ss->assign('EDIT_REPORTS_TO', true); + } + parent::display(); + } +} +?> diff --git a/modules/Employees/views/view.list.php b/modules/Employees/views/view.list.php new file mode 100644 index 00000000..ad278e81 --- /dev/null +++ b/modules/Employees/views/view.list.php @@ -0,0 +1,72 @@ +lv = new ListViewSmarty(); + $this->lv->delete = false; + $this->lv->email = false; + if (!is_admin($GLOBALS['current_user'])&& !is_admin_for_module($GLOBALS['current_user'],'Users')){ + $this->lv->multiSelect = false; + } + } + + public function listViewProcess() + { + $this->processSearchForm(); + $this->lv->searchColumns = $this->searchForm->searchColumns; + + if(!$this->headers) + return; + if(empty($_REQUEST['search_form_only']) || $_REQUEST['search_form_only'] == false){ + $this->lv->ss->assign("SEARCH",true); + + $tplFile = 'include/ListView/ListViewGeneric.tpl'; + if (!is_admin($GLOBALS['current_user'])&& !is_admin_for_module($GLOBALS['current_user'],'Users')){ + $tplFile = 'include/ListView/ListViewNoMassUpdate.tpl'; + } + $this->lv->setup($this->seed, $tplFile, $this->where, $this->params); + $savedSearchName = empty($_REQUEST['saved_search_select_name']) ? '' : (' - ' . $_REQUEST['saved_search_select_name']); + echo $this->lv->display(); + } + } +} diff --git a/modules/Groups/Delete.php b/modules/Groups/Delete.php new file mode 100644 index 00000000..2384b797 --- /dev/null +++ b/modules/Groups/Delete.php @@ -0,0 +1,47 @@ +retrieve($_REQUEST['record']); + $focus->mark_deleted($focus->id); +} + +header("Location: index.php?module=Groups&action=index"); + +?> diff --git a/modules/Groups/DetailView.html b/modules/Groups/DetailView.html new file mode 100644 index 00000000..abdb13ae --- /dev/null +++ b/modules/Groups/DetailView.html @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + + +
    + + + +
    + +

    +{PAGINATION} + + + + +
    {MOD.LBL_GROUP_NAME}{USER_NAME} 

    + + \ No newline at end of file diff --git a/modules/Groups/DetailView.php b/modules/Groups/DetailView.php new file mode 100644 index 00000000..8aaf2c4b --- /dev/null +++ b/modules/Groups/DetailView.php @@ -0,0 +1,77 @@ +info("Groups DetailView"); +$focus = new Group(); +$focus->retrieve($_REQUEST['record']); +$detailView = new DetailView(); +$offset=0; +if (isset($_REQUEST['offset']) or isset($_REQUEST['record'])) { + $result = $detailView->processSugarBean("Group", $focus, $offset); + if($result == null) { + sugar_die($app_strings['ERROR_NO_RECORD']); + } + $focus=$result; +} else { + header("Location: index.php?module=Groups&action=index"); +} + +echo getClassicModuleTitle($mod_strings['LBL_MODULE_NAME'], array($mod_strings['LBL_MODULE_NAME'],$focus->user_name), true); + +/* end standard DetailView layout process */ + + +$xtpl = new XTemplate('modules/Groups/DetailView.html'); +$xtpl->assign('MOD', $mod_strings); +$xtpl->assign('APP', $app_strings); +$xtpl->assign("CREATED_BY", $focus->created_by_name); +$xtpl->assign("MODIFIED_BY", $focus->modified_by_name); +$xtpl->assign("GRIDLINE", $gridline); +$xtpl->assign("PRINT_URL", "index.php?".$GLOBALS['request_string']); +$xtpl->assign("ID", $focus->id); +$xtpl->assign('USER_NAME', $focus->user_name); + +$xtpl->parse('main'); +$xtpl->out('main'); +?> \ No newline at end of file diff --git a/modules/Groups/EditView.html b/modules/Groups/EditView.html new file mode 100644 index 00000000..10f2aa98 --- /dev/null +++ b/modules/Groups/EditView.html @@ -0,0 +1,92 @@ + + +
    + + + + + + + + + + + + +
    + + + {APP.LBL_REQUIRED_SYMBOL} {APP.NTC_REQUIRED}
    +

    + + + + + + + + + + + + + +
    + {MOD.LBL_GROUP_NAME} {APP.LBL_REQUIRED_SYMBOL} + + + + {MOD.LBL_DESCRIPTION} + + +
    + {MOD.LBL_TEAM} {APP.LBL_REQUIRED_SYMBOL} + + + + + + +
    +

    +{JAVASCRIPT} + \ No newline at end of file diff --git a/modules/Groups/EditView.php b/modules/Groups/EditView.php new file mode 100644 index 00000000..2a77adf7 --- /dev/null +++ b/modules/Groups/EditView.php @@ -0,0 +1,82 @@ +id) sugar_die("Unauthorized access to administration."); +if(isset($_REQUEST['record'])) { + $focus->retrieve($_REQUEST['record']); + //TODO figure out why i have to hard-code this data load? + $focus->default_team = $focus->fetched_row['default_team']; +} +if(isset($_REQUEST['isDuplicate']) && $_REQUEST['isDuplicate'] == 'true') { + $focus->id = ""; + $focus->user_name = ""; +} + +echo getClassicModuleTitle($mod_strings['LBL_MODULE_NAME'], array($mod_strings['LBL_MODULE_NAME'],$focus->last_name." (".$focus->user_name.")"), true); + +$GLOBALS['log']->info("Groups edit view"); +$xtpl= new XTemplate ('modules/Groups/EditView.html'); +$xtpl->assign("MOD", $mod_strings); +$xtpl->assign("APP", $app_strings); +$xtpl->assign("PRINT_URL", "index.php?".$GLOBALS['request_string']); +$xtpl->assign("ID", $focus->id); +$xtpl->assign("USER_NAME", $focus->user_name); +$xtpl->assign("DESCRIPTION", $focus->description); + +if (isset($_REQUEST['return_module'])) $xtpl->assign("RETURN_MODULE", $_REQUEST['return_module']); +if (isset($_REQUEST['return_action'])) $xtpl->assign("RETURN_ACTION", $_REQUEST['return_action']); +if (isset($_REQUEST['return_id'])) $xtpl->assign("RETURN_ID", $_REQUEST['return_id']); +// handle Create $module then Cancel +if (empty($_REQUEST['return_id'])) { + $xtpl->assign("RETURN_ACTION", 'index'); +} +$xtpl->parse("main"); +$xtpl->out("main"); + +?> \ No newline at end of file diff --git a/modules/Groups/Forms.php b/modules/Groups/Forms.php new file mode 100644 index 00000000..c01c84b6 --- /dev/null +++ b/modules/Groups/Forms.php @@ -0,0 +1,40 @@ + \ No newline at end of file diff --git a/modules/Groups/Group.php b/modules/Groups/Group.php new file mode 100644 index 00000000..0a09ac37 --- /dev/null +++ b/modules/Groups/Group.php @@ -0,0 +1,76 @@ + \ No newline at end of file diff --git a/modules/Groups/ListView.html b/modules/Groups/ListView.html new file mode 100644 index 00000000..a6fe72bf --- /dev/null +++ b/modules/Groups/ListView.html @@ -0,0 +1,66 @@ + + + + +{PAGINATION} + + + + + + + + + + + + + +{PAGINATION} +
    + {MOD.LBL_LIST_USER_NAME}{arrow_start}{user_name_arrow}{arrow_end} +
    + + {USER.USER_NAME} + +
    + \ No newline at end of file diff --git a/modules/Groups/ListView.php b/modules/Groups/ListView.php new file mode 100644 index 00000000..80212375 --- /dev/null +++ b/modules/Groups/ListView.php @@ -0,0 +1,54 @@ +initNewXTemplate('modules/Groups/ListView.html',$current_module_strings); +$ListView->setHeaderTitle($mod_strings['LBL_LIST_TITLE']); +$ListView->setQuery($where, "", "last_name, first_name", "USER"); +$ListView->show_mass_update=false; +$ListView->processListView($focus, "main", "USER"); +?> \ No newline at end of file diff --git a/modules/Groups/Menu.php b/modules/Groups/Menu.php new file mode 100644 index 00000000..0ce65f33 --- /dev/null +++ b/modules/Groups/Menu.php @@ -0,0 +1,45 @@ + \ No newline at end of file diff --git a/modules/Groups/Save.php b/modules/Groups/Save.php new file mode 100644 index 00000000..9ced3be8 --- /dev/null +++ b/modules/Groups/Save.php @@ -0,0 +1,80 @@ +retrieve($_REQUEST['record']); +} + +foreach($focus->column_fields as $field) { + if(isset($_POST[$field])) { + $value = $_POST[$field]; + $focus->$field = $value; + } +} + +foreach($focus->additional_column_fields as $field) { + if(isset($_POST[$field])) { + $value = $_POST[$field]; + $focus->$field = $value; + } +} +if(isset($_REQUEST['user_name']) && !empty($_REQUEST['user_name'])) { + $focus->user_name = $_REQUEST['user_name']; + $focus->last_name = $_REQUEST['user_name']; +} +$focus->description = $_REQUEST['description']; +$focus->save(); + + +if(isset($_POST['return_module']) && $_POST['return_module'] != "") $return_module = $_POST['return_module']; +else $return_module = "Groups"; +if(isset($_POST['return_action']) && $_POST['return_action'] != "") $return_action = $_POST['return_action']; +else $return_action = "DetailView"; +if(isset($_POST['return_id']) && $_POST['return_id'] != "") $return_id = $_POST['return_id']; + +$GLOBALS['log']->debug("Saved record with id of ".$return_id); + +header("Location: index.php?action=$return_action&module=$return_module&record=$return_id"); +?> \ No newline at end of file diff --git a/modules/Groups/index.php b/modules/Groups/index.php new file mode 100644 index 00000000..3c09fb30 --- /dev/null +++ b/modules/Groups/index.php @@ -0,0 +1,40 @@ + \ No newline at end of file diff --git a/modules/Groups/language/en_us.lang.php b/modules/Groups/language/en_us.lang.php new file mode 100644 index 00000000..62f24b6d --- /dev/null +++ b/modules/Groups/language/en_us.lang.php @@ -0,0 +1,51 @@ + 'Groups', + 'LBL_GROUP_NAME' => 'Group Name:', + 'LBL_DESCRIPTION' => 'Description:', + 'LBL_TEAM' => 'Team:', + // ListView + 'LBL_LIST_TITLE' => 'Groups', + // Links + 'LNK_ALL_GROUPS' => 'All Groups', + 'LNK_NEW_GROUP' => 'Create Group', + 'LNK_CONVERT_USER' => 'Convert User to Group', +); +?> \ No newline at end of file diff --git a/modules/Groups/vardefs.php b/modules/Groups/vardefs.php new file mode 100644 index 00000000..c01c84b6 --- /dev/null +++ b/modules/Groups/vardefs.php @@ -0,0 +1,40 @@ + \ No newline at end of file diff --git a/modules/Help/Menu.php b/modules/Help/Menu.php new file mode 100644 index 00000000..e13bfc97 --- /dev/null +++ b/modules/Help/Menu.php @@ -0,0 +1,59 @@ + \ No newline at end of file diff --git a/modules/Help/index.php b/modules/Help/index.php new file mode 100644 index 00000000..8879f852 --- /dev/null +++ b/modules/Help/index.php @@ -0,0 +1,48 @@ + +Sorry! The module has not yet been implemented. +

    +Stay tuned for an upcoming release of SugarCRM! \ No newline at end of file diff --git a/modules/Help/language/en_us.lang.php b/modules/Help/language/en_us.lang.php new file mode 100644 index 00000000..8b674e19 --- /dev/null +++ b/modules/Help/language/en_us.lang.php @@ -0,0 +1,65 @@ + 'Accounts', + 'LBL_MODULE_TITLE' => 'Accounts: Home', + 'LBL_SEARCH_FORM_TITLE' => 'Account Search', + 'LBL_LIST_FORM_TITLE' => 'Account List', + 'LBL_NEW_FORM_TITLE' => 'Create Account', + 'LNK_NEW_CONTACT' => 'Create Contact', + 'LNK_NEW_ACCOUNT' => 'Create Account', + 'LNK_NEW_OPPORTUNITY' => 'Create Opportunity', + 'LNK_NEW_CASE' => 'Create Case', + 'LNK_NEW_NOTE' => 'Create Note or Attachment', + 'LNK_NEW_CALL' => 'Log Call', + 'LNK_NEW_EMAIL' => 'Archive Email', + 'LNK_NEW_MEETING' => 'Schedule Meeting', + 'LNK_NEW_TASK' => 'Create Task', + 'ERR_DELETE_RECORD' => 'A record number must be specified to delete the account.', +); + + +?> \ No newline at end of file diff --git a/modules/History/language/en_us.lang.php b/modules/History/language/en_us.lang.php new file mode 100644 index 00000000..1b18712b --- /dev/null +++ b/modules/History/language/en_us.lang.php @@ -0,0 +1,120 @@ + 'History', + 'LBL_MODULE_TITLE' => 'History: Home', + 'LBL_SEARCH_FORM_TITLE' => 'History Search', + 'LBL_LIST_FORM_TITLE' => 'History', + 'LBL_LIST_SUBJECT' => 'Subject', + 'LBL_LIST_CONTACT' => 'Contact', + 'LBL_LIST_RELATED_TO' => 'Related to', + 'LBL_LIST_DATE' => 'Date', + 'LBL_LIST_TIME' => 'Start Time', + 'LBL_LIST_CLOSE' => 'Close', + 'LBL_SUBJECT' => 'Subject:', + 'LBL_STATUS' => 'Status:', + 'LBL_LOCATION' => 'Location:', + 'LBL_DATE_TIME' => 'Start Date & Time:', + 'LBL_DATE' => 'Start Date:', + 'LBL_TIME' => 'Start Time:', + 'LBL_DURATION' => 'Duration:', + 'LBL_HOURS_MINS' => '(hours/minutes)', + 'LBL_CONTACT_NAME' => 'Contact Name: ', + 'LBL_MEETING' => 'Meeting:', + 'LBL_DESCRIPTION_INFORMATION' => 'Description Information', + 'LBL_DESCRIPTION' => 'Description:', + 'LBL_COLON' => ':', + 'LBL_DEFAULT_STATUS' => 'Planned', + 'LNK_NEW_CALL' => 'Log Call', + 'LNK_NEW_MEETING' => 'Schedule Meeting', + 'LNK_NEW_TASK' => 'Create Task', + 'LNK_NEW_NOTE' => 'Create Note or Attachment', + 'LNK_NEW_EMAIL' => 'Archive Email', + 'LNK_CALL_LIST' => 'Calls', + 'LNK_MEETING_LIST' => 'Meetings', + 'LNK_TASK_LIST' => 'Tasks', + 'LNK_NOTE_LIST' => 'Notes', + 'LNK_EMAIL_LIST' => 'Emails', + 'ERR_DELETE_RECORD' => 'A record number must be specified to delete the account.', + 'NTC_REMOVE_INVITEE' => 'Are you sure you want to remove this invitee from the meeting?', + 'LBL_INVITEE' => 'Invitees', + 'LBL_LIST_DIRECTION' => 'Direction', + 'LBL_DIRECTION' => 'Direction', + 'LNK_NEW_APPOINTMENT' => 'New Appointment', + 'LNK_VIEW_CALENDAR' => 'Today', + 'LBL_OPEN_ACTIVITIES' => 'Open Activities', + 'LBL_HISTORY' => 'History', + 'LBL_UPCOMING' => 'My Upcoming Appointments', + 'LBL_TODAY' => 'through ', + 'LBL_NEW_TASK_BUTTON_TITLE' => 'Create Task [Alt+N]', + 'LBL_NEW_TASK_BUTTON_KEY' => 'N', + 'LBL_NEW_TASK_BUTTON_LABEL' => 'Create Task', + 'LBL_SCHEDULE_MEETING_BUTTON_TITLE' => 'Schedule Meeting [Alt+M]', + 'LBL_SCHEDULE_MEETING_BUTTON_KEY' => 'M', + 'LBL_SCHEDULE_MEETING_BUTTON_LABEL' => 'Schedule Meeting', + 'LBL_SCHEDULE_CALL_BUTTON_TITLE' => 'Log Call [Alt+C]', + 'LBL_SCHEDULE_CALL_BUTTON_KEY' => 'C', + 'LBL_SCHEDULE_CALL_BUTTON_LABEL' => 'Log Call', + 'LBL_NEW_NOTE_BUTTON_TITLE' => 'Create Note or Attachment [Alt+T]', + 'LBL_NEW_NOTE_BUTTON_KEY' => 'T', + 'LBL_NEW_NOTE_BUTTON_LABEL' => 'Create Note or Attachment', + 'LBL_TRACK_EMAIL_BUTTON_TITLE' => 'Archive Email [Alt+K]', + 'LBL_TRACK_EMAIL_BUTTON_KEY' => 'K', + 'LBL_TRACK_EMAIL_BUTTON_LABEL' => 'Archive Email', + 'LBL_LIST_STATUS' => 'Status', + 'LBL_LIST_DUE_DATE' => 'Due Date', + 'LBL_LIST_LAST_MODIFIED' => 'Last Modified', + 'NTC_NONE_SCHEDULED' => 'None scheduled.', + 'appointment_filter_dom' => array( + 'today' => 'today' + ,'tomorrow' => 'tomorrow' + ,'this Saturday' => 'this week' + ,'next Saturday' => 'next week' + ,'last this_month' => 'this month' + ,'last next_month' => 'next month' + ), + 'LNK_IMPORT_NOTES'=>'Import Notes', + 'NTC_NONE'=>'None', + 'LBL_ACCEPT_THIS'=>'Accept?', + 'LBL_DEFAULT_SUBPANEL_TITLE' => 'History', +); + +?> \ No newline at end of file diff --git a/modules/History/metadata/subpaneldefs.php b/modules/History/metadata/subpaneldefs.php new file mode 100644 index 00000000..86a17bcc --- /dev/null +++ b/modules/History/metadata/subpaneldefs.php @@ -0,0 +1,341 @@ + array( + 'subpanel_title' => 'LBL_DEFAULT_SUBPANEL_TITLE', + 'top_buttons' => array( + array('widget_class' => 'SubPanelTopCreateNoteButton'), + array('widget_class' => 'SubPanelTopArchiveEmailButton'), + array('widget_class' => 'SubPanelTopSummaryButton'), + ), + +//TODO try and merge with the activities + 'list_fields' => array( + 'Meetings' => array( + 'columns' => array( + array( + 'name' => 'nothing', + 'widget_class' => 'SubPanelIcon', + 'module' => 'Meetings', + 'width' => '2%', + ), + array( + 'name' => 'name', + 'vname' => 'LBL_LIST_SUBJECT', + 'widget_class' => 'SubPanelDetailViewLink', + 'width' => '28%', + ), + array( + 'name' => 'status', + 'vname' => 'LBL_LIST_STATUS', + 'width' => '10%', + ), + array( + 'name' => 'contact_name', + 'module' => 'Contacts', + 'widget_class' => 'SubPanelDetailViewLink', + 'target_record_key' => 'contact_id', + 'target_module' => 'Contacts', + 'vname' => 'LBL_LIST_CONTACT', + 'width' => '20%', + ), + array( + 'name' => 'parent_name', + 'module' => 'Meetings', + 'vname' => 'LBL_LIST_RELATED_TO', + 'width' => '22%', + ), + array( + 'name' => 'date_modified', + //'db_alias_to' => 'the_date', + 'vname' => 'LBL_LIST_LAST_MODIFIED', + 'width' => '10%', + ), + array( + 'name' => 'nothing', + 'widget_class' => 'SubPanelEditButton', + 'module' => 'Meetings', + 'width' => '4%', + ), + array( + 'name' => 'nothing', + 'widget_class' => 'SubPanelRemoveButton', + 'linked_field' => 'meetings', + 'module' => 'Meetings', + 'width' => '4%', + ), + ), + 'where' => "(meetings.status='Held' OR meetings.status='Not Held')", + 'order_by' => 'meetings.date_modified', + ), + 'Emails' => array( + 'columns' => array( + array( + 'name' => 'nothing', + 'widget_class' => 'SubPanelIcon', + 'module' => 'Emails', + 'width' => '2%', + ), + array( + 'name' => 'name', + 'vname' => 'LBL_LIST_SUBJECT', + 'widget_class' => 'SubPanelDetailViewLink', + 'width' => '28%', + ), + array( + 'name' => 'status', + 'vname' => 'LBL_LIST_STATUS', + 'width' => '10%', + ), + array( + 'name' => 'contact_name', + 'module' => 'Contacts', + 'widget_class' => 'SubPanelDetailViewLink', + 'target_record_key' => 'contact_id', + 'target_module' => 'Contacts', + 'vname' => 'LBL_LIST_CONTACT', + 'width' => '20%', + ), + array( + 'name' => 'parent_name', + 'module' => 'Emails', + 'vname' => 'LBL_LIST_RELATED_TO', + 'width' => '22%', + ), + array( + 'name' => 'date_modified', + //'db_alias_to' => 'the_date', + 'vname' => 'LBL_LIST_LAST_MODIFIED', + 'width' => '10%', + ), + array( + 'name' => 'nothing', + 'widget_class' => 'SubPanelEditButton', + 'module' => 'Emails', + 'width' => '4%', + ), + array( + 'name' => 'nothing', + 'widget_class' => 'SubPanelRemoveButton', + 'linked_field' => 'emails', + 'module' => 'Emails', + 'width' => '4%', + ), + ), + 'where' => "(emails.status='sent')", + 'order_by' => 'emails.date_modified', + ), + 'Notes' => array( + 'columns' => array( + array( + 'name' => 'nothing', + 'widget_class' => 'SubPanelIcon', + 'module' => 'Notes', + 'width' => '2%', + ), + array( + 'name' => 'name', + 'vname' => 'LBL_LIST_SUBJECT', + 'widget_class' => 'SubPanelDetailViewLink', + 'width' => '28%', + ), + array( // this column does not exist on + 'name' => 'status', + 'vname' => 'LBL_LIST_STATUS', + 'width' => '10%', + ), + array( + 'name' => 'contact_name', + 'module' => 'Contacts', + 'widget_class' => 'SubPanelDetailViewLink', + 'target_record_key' => 'contact_id', + 'target_module' => 'Contacts', + 'vname' => 'LBL_LIST_CONTACT', + 'width' => '20%', + ), + array( + 'name' => 'parent_name', + 'module' => 'Notes', + 'vname' => 'LBL_LIST_RELATED_TO', + 'width' => '22%', + ), + array( + 'name' => 'date_modified', + //'db_alias_to' => 'the_date', + 'vname' => 'LBL_LIST_LAST_MODIFIED', + 'width' => '10%', + ), + array( + 'name' => 'nothing', + 'widget_class' => 'SubPanelEditButton', + 'module' => 'Notes', + 'width' => '4%', + ), + array( + 'name' => 'nothing', + 'widget_class' => 'SubPanelRemoveButton', + 'linked_field' => 'notes', + 'module' => 'Notes', + 'width' => '4%', + ), + ), + 'where' => '', + 'order_by' => 'notes.date_modified', + ), + 'Tasks' => array( + 'columns' => array( + array( + 'name' => 'nothing', + 'widget_class' => 'SubPanelIcon', + 'module' => 'Tasks', + 'width' => '2%', + ), + array( + 'name' => 'name', + 'vname' => 'LBL_LIST_SUBJECT', + 'widget_class' => 'SubPanelDetailViewLink', + 'width' => '28%', + ), + array( + 'name' => 'status', + 'vname' => 'LBL_LIST_STATUS', + 'width' => '10%', + ), + array( + 'name' => 'contact_name', + 'module' => 'Contacts', + 'widget_class' => 'SubPanelDetailViewLink', + 'target_record_key' => 'contact_id', + 'target_module' => 'Contacts', + 'vname' => 'LBL_LIST_CONTACT', + 'width' => '20%', + ), + array( + 'name' => 'parent_name', + 'module' => 'Tasks', + 'vname' => 'LBL_LIST_RELATED_TO', + 'width' => '22%', + ), + array( + 'name' => 'date_modified', + //'db_alias_to' => 'the_date', + 'vname' => 'LBL_LIST_LAST_MODIFIED', + 'width' => '10%', + ), + array( + 'name' => 'nothing', + 'widget_class' => 'SubPanelEditButton', + 'module' => 'Tasks', + 'width' => '4%', + ), + array( + 'name' => 'nothing', + 'widget_class' => 'SubPanelRemoveButton', + 'linked_field' => 'tasks', + 'module' => 'Tasks', + 'width' => '4%', + ), + ), + 'where' => "(tasks.status='Completed' OR tasks.status='Deferred')", + 'order_by' => 'tasks.date_start', + ), + 'Calls' => array( + 'columns' => array( + array( + 'name' => 'nothing', + 'widget_class' => 'SubPanelIcon', + 'module' => 'Calls', + 'width' => '2%', + ), + array( + 'name' => 'name', + 'vname' => 'LBL_LIST_SUBJECT', + 'widget_class' => 'SubPanelDetailViewLink', + 'width' => '28%', + ), + array( + 'name' => 'status', + 'vname' => 'LBL_LIST_STATUS', + 'width' => '10%', + ), + array( + 'name' => 'contact_name', + 'module' => 'Contacts', + 'widget_class' => 'SubPanelDetailViewLink', + 'target_record_key' => 'contact_id', + 'target_module' => 'Contacts', + 'vname' => 'LBL_LIST_CONTACT', + 'width' => '20%', + ), + array( + 'name' => 'parent_name', + 'module' => 'Meetings', + 'vname' => 'LBL_LIST_RELATED_TO', + 'width' => '22%', + ), + array( + 'name' => 'date_modified', + //'db_alias_to' => 'the_date', + 'vname' => 'LBL_LIST_LAST_MODIFIED', + 'width' => '10%', + ), + array( + 'name' => 'nothing', + 'widget_class' => 'SubPanelEditButton', + 'module' => 'Calls', + 'width' => '4%', + ), + array( + 'name' => 'nothing', + 'widget_class' => 'SubPanelRemoveButton', + 'linked_field' => 'calls', + 'module' => 'Calls', + 'width' => '4%', + ), + ), + 'where' => "(calls.status='Held' OR calls.status='Not Held')", + 'order_by' => 'calls.date_modified', + ), + ), + ), +); +?> \ No newline at end of file diff --git a/modules/Home/About.php b/modules/Home/About.php new file mode 100644 index 00000000..ae07bfa4 --- /dev/null +++ b/modules/Home/About.php @@ -0,0 +1,200 @@ + + + + +
    +

    +SugarCRM +
    + +

    + +Copyright ".$app_strings['LBL_SUGAR_COPYRIGHT']."

    "; + +// This version of viewLicenseText is for Community Edition only. +$viewLicenseText = $mod_strings['LBL_VIEWLICENSE_COM']; + + + +echo $viewLicenseText; + + + +$imgTagString = 'Powered By SugarCRM'; + + + +echo $imgTagString; +?> + + + +

    SugarCRM ®, + + + ".$mod_strings['LBL_OF']; ?> SugarCRM Inc.

    + + +

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

    + +
      +
    • XML 
    • +
    • XML 
    • +
    • XML 
    • +
    • XML 
    • +
    +
    +

    + + +

    SugarCRM Inc.

    + + 10050 North Wolfe Road, Suite SW2-130, Cupertino, CA, 95014 USA,  + +1 (408) 454-6940,  + +http://www.sugarcrm.com + + +
    +

    + +

     

    +

    + + +
    + + + +
    + + +

    diff --git a/modules/Home/AddToFavorites.php b/modules/Home/AddToFavorites.php new file mode 100644 index 00000000..b720cea0 --- /dev/null +++ b/modules/Home/AddToFavorites.php @@ -0,0 +1,53 @@ +getPreference('objects', 'favorites'); + if(!is_array($objects)) $objects = array(); + if(empty($objects[$_REQUEST['target_module']])) $objects[$_REQUEST['target_module']] = array(); + $objects[$_REQUEST['target_module']][$_REQUEST['target_id']] = true; + + $current_user->setPreference('objects', $objects, 0, 'favorites'); + + echo 1; +} +else { + echo 0; +} +?> diff --git a/modules/Home/Dashlets/ChartsDashlet/ChartsDashlet.en_us.lang.php b/modules/Home/Dashlets/ChartsDashlet/ChartsDashlet.en_us.lang.php new file mode 100644 index 00000000..ff7a752b --- /dev/null +++ b/modules/Home/Dashlets/ChartsDashlet/ChartsDashlet.en_us.lang.php @@ -0,0 +1,45 @@ + 'Charts', + 'LBL_DESCRIPTION' => 'A dashlet to display charts', + 'LBL_CONFIGURE_TITLE' => 'Title', ); +?> \ No newline at end of file diff --git a/modules/Home/Dashlets/ChartsDashlet/ChartsDashlet.meta.php b/modules/Home/Dashlets/ChartsDashlet/ChartsDashlet.meta.php new file mode 100644 index 00000000..b03282f1 --- /dev/null +++ b/modules/Home/Dashlets/ChartsDashlet/ChartsDashlet.meta.php @@ -0,0 +1,48 @@ + 'LBL_TITLE', // array index in language pack + 'description' => 'LBL_DESCRIPTION', // array index in language pack + 'category' => 'Charts', + 'hidden' => true, + ); +?> diff --git a/modules/Home/Dashlets/ChartsDashlet/ChartsDashlet.php b/modules/Home/Dashlets/ChartsDashlet/ChartsDashlet.php new file mode 100644 index 00000000..6dd16a15 --- /dev/null +++ b/modules/Home/Dashlets/ChartsDashlet/ChartsDashlet.php @@ -0,0 +1,185 @@ +report_id = $report_id; + + $this->loadLanguage('ChartsDashlet'); // load the language strings here + + parent::Dashlet($id); // call parent constructor + + $this->searchFields = array(); + $this->isConfigurable = true; // dashlet is configurable + $this->hasScript = true; // dashlet has javascript attached to it + } + + /** + * Displays the dashlet + * + * @return string html to display dashlet + */ + function display() { + require_once("modules/Reports/Report.php"); + + +// ini_set('display_errors', 'false'); + + $chartReport = new SavedReport(); + $chartExists = $chartReport->retrieve($this->report_id, false); + + if (!is_null($chartExists)){ + $this->title = $chartReport->name; + + $reporter = new Report($chartReport->content); + $reporter->is_saved_report = true; + $reporter->saved_report_id = $chartReport->id; + $reporter->get_total_header_row(); + $reporter->run_chart_queries(); + + require_once("modules/Reports/templates/templates_chart.php"); + + ob_start(); + template_chart($reporter, true, true, $this->id); + $str = ob_get_contents(); + ob_end_clean(); + + $xmlFile = get_cache_file_name($reporter); + + $html = parent::display() . "
    " . $str . "
    " . "
    "; // return parent::display for title and such + + $ss = new Sugar_Smarty(); + $ss->assign('chartName', $this->id); + $ss->assign('chartXMLFile', $xmlFile); + $script = $ss->fetch('modules/Home/Dashlets/ChartsDashlet/ChartsDashletScript.tpl'); + $json = getJSONobj(); + + return parent::display() . "
    " . $str . "
    " . "
    "; // return parent::display for title and such + } + } + + /** + * Displays the javascript for the dashlet + * + * @return string javascript to use with this dashlet + */ + function displayScript() { + require_once("modules/Reports/Report.php"); + + + $chartReport = new SavedReport(); + $chartExists = $chartReport->retrieve($this->report_id, false); + + if (!is_null($chartExists)){ + $this->title = $chartReport->name; + + require_once("modules/Reports/templates/templates_chart.php"); + require_once('include/SugarCharts/SugarChartFactory.php'); + + $sugarChart = SugarChartFactory::getInstance(); + + + $reporter = new Report($chartReport->content); + $reporter->is_saved_report = true; + $reporter->saved_report_id = $chartReport->id; + $xmlFile = get_cache_file_name($reporter); + + $str = $sugarChart->getDashletScript($this->id,$xmlFile); + return $str; + } + } + + /** + * Displays the configuration form for the dashlet + * + * @return string html to display form + */ + function displayOptions() { + } + + /** + * called to filter out $_REQUEST object when the user submits the configure dropdown + * + * @param array $req $_REQUEST + * @return array filtered options to save + */ + function saveOptions($req) { + } + + function setConfigureIcon(){ + + + if($this->isConfigurable) + $additionalTitle = '
    ' + . SugarThemeRegistry::current()->getImage('dashlet-header-edit','title="' . translate('LBL_DASHLET_EDIT', 'Home') . '" alt="' . translate('LBL_DASHLET_EDIT', 'Home') . '" border="0" align="absmiddle"').'' + . ''; + else + $additionalTitle = '
    '; + + return $additionalTitle; + } + + function setRefreshIcon(){ + + + $additionalTitle = ''; + if($this->isRefreshable) + $additionalTitle .= '' . translate('LBL_DASHLET_REFRESH', 'Home') . ''; + return $additionalTitle; + } + +} + +?> \ No newline at end of file diff --git a/modules/Home/Dashlets/ChartsDashlet/ChartsDashletScript.tpl b/modules/Home/Dashlets/ChartsDashlet/ChartsDashletScript.tpl new file mode 100644 index 00000000..b1dfb31a --- /dev/null +++ b/modules/Home/Dashlets/ChartsDashlet/ChartsDashletScript.tpl @@ -0,0 +1,45 @@ +{* + +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + + + +*} + + diff --git a/modules/Home/Dashlets/InvadersDashlet/InvadersDashlet.en_us.lang.php b/modules/Home/Dashlets/InvadersDashlet/InvadersDashlet.en_us.lang.php new file mode 100644 index 00000000..c94a3e12 --- /dev/null +++ b/modules/Home/Dashlets/InvadersDashlet/InvadersDashlet.en_us.lang.php @@ -0,0 +1,50 @@ + 'Invaders!', + 'LBL_DESCRIPTION' => 'A little way to pass the time', + 'LBL_DBLCLICK_HELP' => 'Use A and D to move, S to fire.', + 'LBL_START' => 'Click To Start', + 'LBL_GAME_OVER' => 'Game Over
    (Click to play again)', + +); +?> \ No newline at end of file diff --git a/modules/Home/Dashlets/InvadersDashlet/InvadersDashlet.icon.jpg b/modules/Home/Dashlets/InvadersDashlet/InvadersDashlet.icon.jpg new file mode 100644 index 0000000000000000000000000000000000000000..fca9aa91df82f4cb95c57191e69f814fc2c858f7 GIT binary patch literal 81 zcmZ?wbhEHb 'LBL_TITLE', // array index in language pack + 'description' => 'LBL_DESCRIPTION', // array index in language pack + 'icon' => 'icon_Invaders_32.gif', + 'category' => 'Tools', + ); +?> diff --git a/modules/Home/Dashlets/InvadersDashlet/InvadersDashlet.php b/modules/Home/Dashlets/InvadersDashlet/InvadersDashlet.php new file mode 100644 index 00000000..667bc940 --- /dev/null +++ b/modules/Home/Dashlets/InvadersDashlet/InvadersDashlet.php @@ -0,0 +1,160 @@ +loadLanguage('InvadersDashlet'); // load the language strings here + + if(!empty($def['height'])) // set a default height if none is set + $this->height = $def['height']; + + parent::Dashlet($id); // call parent constructor + + $this->isConfigurable = false; // dashlet is configurable + $this->hasScript = true; // dashlet has javascript attached to it + + // if no custom title, use default + if(empty($def['title'])) $this->title = $this->dashletStrings['LBL_TITLE']; + else $this->title = $def['title']; + } + + /** + * Displays the dashlet + * + * @return string html to display dashlet + */ + function display() { + $ss = new Sugar_Smarty(); + $ss->assign('id', $this->id); + $ss->assign('height', $this->height); + $ss->assign('dashletStrings', $this->dashletStrings); + + $str = $ss->fetch('modules/Home/Dashlets/InvadersDashlet/InvadersDashlet.tpl'); + return parent::display($this->dashletStrings['LBL_DBLCLICK_HELP']) . $str . '
    '; // return parent::display for title and such + } + + /** + * Displays the javascript for the dashlet + * + * @return string javascript to use with this dashlet + */ + function displayScript() { + $ss = new Sugar_Smarty(); + $ss->assign('id', $this->id); + $ss->assign('dashletStrings', $this->dashletStrings); + + $str = $ss->fetch('modules/Home/Dashlets/InvadersDashlet/InvadersDashletScript.tpl'); + return $str; // return parent::display for title and such + } + + /** + * Displays the configuration form for the dashlet + * + * @return string html to display form + */ + function displayOptions() { + global $app_strings; + + $ss = new Sugar_Smarty(); + $ss->assign('titleLbl', $this->dashletStrings['LBL_CONFIGURE_TITLE']); + $ss->assign('heightLbl', $this->dashletStrings['LBL_CONFIGURE_HEIGHT']); + $ss->assign('saveLbl', $app_strings['LBL_SAVE_BUTTON_LABEL']); + $ss->assign('title', $this->title); + $ss->assign('height', $this->height); + $ss->assign('id', $this->id); + + return parent::displayOptions() . $ss->fetch('modules/Home/Dashlets/InvadersDashlet/InvadersOptions.tpl'); + } + + /** + * called to filter out $_REQUEST object when the user submits the configure dropdown + * + * @param array $req $_REQUEST + * @return array filtered options to save + */ + function saveOptions($req) { + global $sugar_config, $timedate, $current_user, $theme; + $options = array(); + $options['title'] = $_REQUEST['title']; + if(is_numeric($_REQUEST['height'])) { + if($_REQUEST['height'] > 0 && $_REQUEST['height'] <= 300) $options['height'] = $_REQUEST['height']; + elseif($_REQUEST['height'] > 300) $options['height'] = '300'; + else $options['height'] = '100'; + } + +// $options['savedText'] = br2nl($this->savedText); + $options['savedText'] = $this->savedText; + + return $options; + } + + /** + * Used to save text on textarea blur. Accessed via Home/CallMethodDashlet.php + * This is an example of how to to call a custom method via ajax + */ + function saveText() { + if(isset($_REQUEST['savedText'])) { + $optionsArray = $this->loadOptions(); +// _pp($_REQUEST['savedText']); + $optionsArray['savedText'] = nl2br($_REQUEST['savedText']); + $this->storeOptions($optionsArray); + + } + else { + $optionsArray['savedText'] = ''; + } + $json = getJSONobj(); + echo 'result = ' . $json->encode(array('id' => $_REQUEST['id'], + 'savedText' => $optionsArray['savedText'])); + } +} + +?> \ No newline at end of file diff --git a/modules/Home/Dashlets/InvadersDashlet/InvadersDashlet.tpl b/modules/Home/Dashlets/InvadersDashlet/InvadersDashlet.tpl new file mode 100644 index 00000000..244c36dd --- /dev/null +++ b/modules/Home/Dashlets/InvadersDashlet/InvadersDashlet.tpl @@ -0,0 +1,97 @@ +{* + +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + +*} + +
    +
    + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
         
         
         
         
    +
    + +
    +
    diff --git a/modules/Home/Dashlets/InvadersDashlet/InvadersDashletScript.tpl b/modules/Home/Dashlets/InvadersDashlet/InvadersDashletScript.tpl new file mode 100644 index 00000000..bcebbc16 --- /dev/null +++ b/modules/Home/Dashlets/InvadersDashlet/InvadersDashletScript.tpl @@ -0,0 +1,262 @@ +{* + +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + + +*} + + +{/literal} \ No newline at end of file diff --git a/modules/Home/Dashlets/InvadersDashlet/InvadersOptions.tpl b/modules/Home/Dashlets/InvadersDashlet/InvadersOptions.tpl new file mode 100644 index 00000000..a8c4eeb3 --- /dev/null +++ b/modules/Home/Dashlets/InvadersDashlet/InvadersOptions.tpl @@ -0,0 +1,71 @@ +{* + +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + + + +*} + + +
    + + + + + + + + + + + + + + + + + + +
    {$titleLbl} + +
    {$heightLbl} + +
    + +
    + +
    \ No newline at end of file diff --git a/modules/Home/Dashlets/InvadersDashlet/sprites/alien.png b/modules/Home/Dashlets/InvadersDashlet/sprites/alien.png new file mode 100644 index 0000000000000000000000000000000000000000..30eed769fc663b32d184ff0ca3f4105c1c21e2ee GIT binary patch literal 1192 zcmV;Z1XufsP))8q-E`++MR4Gwt!Bs63#88DA(t_5OHnxp4X)_=1R_ggD@N-t(^OHpj=u_f1VrO<(KX%D))>x%|u2 zZRhF!So-PZgUK_MNxiVJ@Kur|e`&2RYOT*5IdVjA^}hTcQX6>Hah#brjt}|1-|&4O z&-19)>r^TgM9t^AdzzX(N?4A)T2S%I?3_=JpqqwG*2`vvP9V&T<8+gS22-b!e z%d#kp#un@6Fbweh03pQPBuU<%ot-@)TCLVz%d&nA!a(K?haHU39G4V&-PXltyG-BQ zj^}wePKN7l<8*$3x8i9W>0r!7Y6`T?Hj;dvfXN=l^?xoh~^J;%K$ zCvbgcFYlpVt|Fzx7=tketu?t)s5~djGSW09NfHKw!Ek<%!2XAm+3)vJN}-g(&vS}g zk!2ZKmJtL2qobop+aeJ;KaMZ5&5C$?VG7%}>GgUjr6`I5r4;!F`EZgXxi2J1lKm36 z0@NNBFeuR=tR&r6uw_2S97R?n0hF zAS6vwvMd9*B7x&Vh?iDsirR|5K_-#XVYObcy+4ZUxj$$Z^qXwQ9g0k8|O1 zh~t=DyLQo43Ex~j!@rZ7US06PpRcfUVv_m!d6Fb~lBbq|-Bzd5Sq7$o#V6TH)0A$v zOE2k>1%_T-@Xu==-CmEiwKcTfvU!JC1g1Nk&axQ(1?_fw8*l=6ajQ*ZOxS2NLS>u$ zr~ZZf&JJVuYr;Ns{waH+(G)js+*nacJyN-w@Eh=Mr_))1jUpPN-ELP|4`l@4I1aAs zJ`h4FC6;Aj+x7$HWQ?IGieUvm61Sz=bp(vn+@NT72o1KCVh;AgoGpePU-^^67u)^Cle<6eak`Z zM*IB>s-uMLN6h;_FHGam`}bIO?=&6n<){8UktGXiZg=T1IDEW(MLt;ej05uH_0`JuC z(Vr&%=+%(WP`(v$NevpBRlneJDXC6;9K&y+p|q5e_)=0*3SM$a{qHk9urKHl8@%|_qRipdU z^q}L90sl2XJLUcjt=2mR8k(ptjL-g~L-UVap*0-%`1o&sqx`uNi2bpV`6a>sZi(+^ zydUQF8~MJQ{y~TfgXX@8;jd*X4^waX|Cxfc{ptNUuE1A+x+B&9*hK#{?7n07Z+HLS z?)ad;-4CPh-Ttou1%I`=0di07N1*&;?ThR`ZczSp=HXf*{~r_|=BxUy{NKHQaOq*D zFPMK2R3R<<4dfBfG3pT7Rfv{4MXKY{wUOAi)4T>rrl8%z2gFSNfA@%$UG2Uq3R zp5HqrwCi_o`Llua~ ze*$*y{#T0dZ!8|7@DS(+GCpXU?f*lff8r@2@rNZ3#QAsk=*xybFa`zwhiP=9e<1i9 zwf~dWIZXee>jUItZhvGC{=)p_sqUY!Jt*Y=i{QWc_&~CU;Qb@?K>r8Gtxf)N@DIMU zlpP}s_xW+3Z}0!+hS=YH3w=m|2h9&TgZ$USznuFAk{&zrKW0Rw|2sJ!kQjZy!0|71 z54w>4%=rcPKRBuU)%AeoUlMe#js0~f>w&C)2Qd6K@`2FXXMaiefcr!29#qRZ{Q*4l z8_S<$Q~skCsIGq)HLp>v%wMo7Vad?ic@q@c*)0>MuC| zAl>x00^P@HEPN4%CPe80z6U5Cs?!7IAIAJGV*e!R14I;m5_WZTR{P$m_Wy$9Ark+J z!2`h`823MrlzLzc^xq}rFOUy;^Z<@fu*l!~^H2a!h*|!i(i=1W?{dlbm!JQC-yb~t zcjf%+hnvpd$uNZe<}2)5Pq2WACml=aQ_dIRQ;vs5xh{V@adygRSV4x8l#~bsP|4$~39In% zEvQABn)tdiXeYGx>TS%Ja-i9d7uq z`t`Jy^)s&i{rvpV2t;e>oGKNH%A?SiS`?5WAN1^waD zoMNUkT(^@?S$%eJ)P06QRjqeE$l2UlYvX-fkiMr(YT*(i=R}_1=-%jajYsP9aoCyd zjH)qXi?Z&ZAbp^*C>5}K~VRaoI0$=K*f{e1-VK+ggn}d7< z&9@s~s!9Txujzg6%AWsb!?T~7G=t>bph^fvRbnw~) zBpm2$&d5u4ua_7_2Q(=+x^U~K#zMxOOMXYBKJql!Y~F}?bHQ0#M-af#IH0bYs&ihL z^gOGi9_Xs?6>r`n{~~SZ(ej0deZ9`hxIW<8*EZ@Mr&M`56u+Lew!Mq7nVA_!`HA6- zb1JS?RUB%H3bo#Kz|DF<$EjTD=cWxxx|v5$*-xhe{UYW~}v} zY0ON@f>;6U#|Jt}G(P9Sj(8iuOg-75L*`4bJ0&Md&bT%*fa4aYcJzln+<3)Te5U=z zW2&YGbsZYc*6AWly-`p_7xW)bLdK-hu}~g0E|Alcgnq6zPQgFuop2A)-J)Xh!YtZL zz2+*>x)y@nUhherVc)Y^E0y%JEtAOC0;ks4ES(n!C!z=13FVnTg2IOmT;krn^oYVn zePqm$0)(Z_9dvJ<#k_l2-tZLy6!yg2BJzbI2MQRljx1hyqfd`rxc%CzP&1$(0XSg{ zSnKBYHVs4ME3HtS&3w@&#Vl4Zk~PDFpRpo45_f?&AI-fB3NH}cVl1bW*`L7`^V*l6 z&C~Y>8=(d8h}@>cS37nR>?+_8_bFfh@!m=??9jx@m&jM-j45JxMGB}ps9^M& z$x5;O^wiRTg8b}ShlQAEnMFSt`Yp4^!x|%Q&h}QmUpt9tozZZY7LdSw1N1=$ zM~RYvf7nkDdx(02Q}ag3{MKldk>1`NR3bJ{UddMpk58sorKjIExmBWBuCZ zT;N?V=6Fawkw{1J=%`V*VTOZ1Uyj3|a7OyG;%w$L!>e+Y5zH8hPdZ#8{oy#)T=6&o z0?G5u8ThY6fKF)k;Ba=HPxyMbH~D&MWe}x>b4@FOqxa>Mih9>dQ52h75Za#aOzED%+!w1O+vR^v_;psMOJaoIesn4*EB!o5>so2MWy*55s}$9kF#E^~V;9_9+t3U{T8LccD}OHd zBo9nkgzVya+l(?}MVPdQ30m6iL(?xuIXBHB+_w2$8|x{&fZXsn6e-i7szb#cIf<7F z^yLu&%5+Pnb9A7O5qrC(A9LNj_}~rJ2%gR%wSgfj#%Dq$Kd;&|397=EE=GA+U>jso zKMRLQnrGl)vOeyxS%2MWXWOw`4$)^6ngRVqwt))DC*=#FUtUvKz)saAyBv9A`iu*% z=S`9qu?TpEQEEmABR*VF@wRJWe!RT|F&^u+MlNUojHXt2_AML0!)bor>$^hXx?4Ew zyEmL4c^zUGLfx8zJA-GcQcRUHk|0e)1=;n8CvRHZXp6s|ZrOBmDYyWgUzoZHjCRvA zY>wkmBe5tEgGPK>NLU2%`%dvXm{R#5w<3f$*Cm15>FmUmyMH69-yVFlCZINg?{+YKj#BsjZ#zJUJ(ULkQP3vtO!4>~N;y42Gk z6DfCAxjlc5sL@xF*8HvvOmbYjA=5y&88==qOyY7?5JDW6efd?ixzFky4PrsCtlZ>u zi1r-H%(Ir2quB6Z*V#4IQ_>Rj%!0Ae#cK*tVBw5el$9A2Voxj&Smr4h%X!o(#J^e3 zSS2RdG8-?PCh^^l*>X6o|LnMKx{2a5qH4w#$nLd3%89quksMtFv!y*n#c*S2HQ1MQ z6@Nr?;OU3iH323OJYwMf>Xdg|WAX7iSzQN!#O%y)#lG2P>KrTs~AF9RykB)?T zpP^0rFNAK}5WFh4oyS?XnSYyQbA+qsvC0ad5Dt1ae1|8bx72eNWk?M0w#1TIv?$(f zs=LPMQ#$|U2qMH(X)vd_nsAM=mc?fhE*~a~E-(HAsQ0GGpnMpp`8YE$=PlpM3BLu6 zeae)5-K_vY2Sd)4$eNE8#X`ceOLp6qXqYu*e$i}TdE%Iw#wxri*}zf z*SX4MTQJHagM`0%o;?173TmP_j$6=)oYV5JZn|9qt|9@=5LfT@(p`xRT~igDuJ7syUbs@K8c1EGn4mDRGP{y|Pw(c-kT(L}{p?q(-HgkY`KRkd8pXLSrLOxtI{ z@2hy(wp^E1vPEx*h`g?R`PV9KV~B4`vWbDBUUaZXktt7(;UO%=>vgOs^sqRRZ-Lt$owglV;+(QBW zc5r+i$1y+k>j1s`p>vO*>6 zIr?n$1%`~%l5GEh<*FlXLlp9)OZ#D7G^^z#mpkIZEE&;iTetwCs4Yr1VHJ^Oi|^^u zhqHr*;T$5q%SMoK$kyk{j#@Ev8X1i5klsAqbI*OkcWuiwcx_opYkDaG1IH_2)hN;c z&b2zKdbF`8P;O<|i8Q)FN7$76UE5N*`^AU;0J&IF`XK4(`L;P$Aqh6(muW+%`?t01 zd-Ilc%d=F<0&bm#8D^g+-h2Qv_PHbz;Nm=emnQ5?nfEM|!mRL|#`(yRX2bT2d13$sXF_=Mi6dR6-Ehy{p|pwSST)qMPgDS} zY-+&Q^i6i|({8^hvXyvo@u)d7sx=B*UY)XoDVZ8WN-0D4#TD4~n)Q&I+MOp4y;PhO z-dN~yoq@4PM7co0;q+jOudlEp!j5)J7cQyTa-Oyx^h3BuZQ{3~DRa5O7X(f04xrlF z`g>4T&p_*)^haK<(G*2VLOJZ5OK(aSZXR*Md8&#+BgYOAJ+FNmJ@;K(=*yzHENW7b z?FxS}Kcw%9`I?s_2SUzEtb7|^_v)4h5b(m>8Or`^n7&DysBhQg#SuGG+$Pib%jvx> zlMH(;f4sw%$gBHmE1TJpdR7J>HPoMfI}Wtob6*)5euFsjwbvSFj&KcCevGuBd8nvnv~@!Xi6?vO>?`iT1YE>Yv-ZrwFgP0^IiG$jyG zHpS(#3dz?oNsO)weGP)1B}Rb0EHuTnAg)Ot-7yg9!cM6NBL`?wvuCf>kDT(%osESib#S)R{>UN@ z9o)-UJq73g*dv-Ce>}YU*4<~=_FdH^`#ja!Jck__lDU>@`Rd6G zliMiW5llxvV^&XuDri)jI4->*p2> zDk9QE?cXT$_~7d;cDX`t11LxWq(u=p#ew+Ix8ba?=o7ge{{XAP_^<|~p8Y-Y;4 z$=Yml25CoxLMV|Z&~fe>mV#KenrwvAAh%@N=^;T3pi$iR7KE~GSy9EXzuAlcMqQ4PXOAi-5_hh?jJvaV})d~%AyxduR zOU!9PNaTH{)-BIpxK)>1t?;wSUE@I06dDj^m3WbeA@E{8#-RK7ks43c*eX;KBLbTL z8rRc3pElCa!=9UpuijFVuxQEMe~aq+Ik>jO^ty^`slM%{*YTx1AHXc##^IDHZlXwk z<4DvqTKSHer4EYl+7upl9?&;z>!<}eAAr~K!aw+28wmL~Lu~5+kNdG17+9(Gh_(v( zMGY4h5FIn>H$-OoC%QR7^^2NxaXWo?yTj;v85yfEcm-4V$9_sihkBjMTb~bw^W5KW zL-(_Gele<5lnX9+|ap9pyH_e zd_!MWMLVLSKNQ<@xH*xJkjaL8ju(|d1Tazc!`htm>7UV*UzCK@nVir@00qLsTkg(8 zc+CbXuZ^eB0>n8|06SH}6>fFTK5Ttb7`Dvm9XI^7ak~*K_Tu6`>weuKa|d(;{j{vC zy~B}5Cvb#F^lD|c&gn%a`&k65*Cs7vq4C$;aLUaq3?IqLT>lk}dUXJDaOYfMbnRI? z1!AaC)F;!i^qSJl`$SOcahNEm(q)N}aHuIVBTb#-AejqsWqsBQDi3?a#yKJ@1enun zj#i&#>W-iY!N-$m@B^l7FpYdfBCOMK>2%EX`o0~uy`cKSS;g+TLETr4#IA-7)-%Xl zX}~3b%9}$uTM;XIScv~N13cJ!u zhA%W;9HeD=6L-NN8^$#%DM^s9qs2#5?O4$Z{k-1)4& zie(#F3xcuuYZyO_Ex>~ZkGMaN@gO3rm6JDSYxo$-J!Qn<-;S}V()twXX@>ox)+JK- z=5Y6xx!Gm~d$XNL9Ucg_d(mFe(|*2V|Aw))e7nu|v{#qc;qa5_^7;Fg3CHO-T=V@xI9>NqUC*7;}j>58y) z)`ac#gRW>cME1{C?C^xqgL)N_h^5MN)`Bq8f(YaE?#0lL{B}V1kb{C+zz6V zG-eY&4+U*?m=d2Yer8G8-VpbyQsl$2G~raQZd43N*~}d%^OM^~Tr+w(KNU(SpLU+- zSH_}Et%=#H3<$jq)*igUu*tVLdvnt)E=5a!-bjSowT88J67gc0Y{AD8+Irj_xINy zTZ;DdYbEFPEnO$XvLuHcZQOr_)XQhf-R*{G3^&A%@J5)hP-5Vj2y-b3pjawI6j|sC zWDR>-7R+?zyggjM|AbtF!A}}+XtGf}o8X*)0A&U#%t8K>TS?%N z#a8p`?>RDp01*@) zkilnb;8fh{iLXax*a;oQElzh7#NL`8#@f=kzwx}n_ZI>uotR3Jad$xlz$Yh75iHoJ zRy5enKIKiptPxn1rTpEScL7;g=-g_KW1$S#q_f+DRH2`e=;C`v1esn5d~U2*MkW-! z*4C+FKbs~_N;g_UK@x)OSN-sSXqWGqF2I@1_hFfbkSFZrwbD9dUQogFMy+^ zJ;$cwZTlqT2Jp-XVdThUFg01dKiiOqjDoRZ-7#Eg{=-(QB7FX*@gqTaVbJ|6vx}M< zITPc+9^@u~zXi_nD!A?C_)jqMQp3{Okv=fmqZq(&5CJN)cxJm_YWz+*NH|3urLzH- zqhkE0rx{MQky%5P{W7Y>n2kxx>H5Nay%l@5LGW7C0Gm^Rw}w&KOyA03mAFuL-G zM?^rXA9-}$b7#KY!|3O0zx znOXo8y|}q#MGjwB%OCf;NjSct%PaMciqc>_JG?_K6M^G>?GmSXE-okM5m`oo?E713 zhd{K;=<#%;5!OJdF6hlZ^(1ylV#zE93Tu`t$b%UZ5f4cYbT9ZJN9#%D*~I7)4v_Q z#r}=C_(Vp72d;RDM0dN_b6;O8iKvWL(&xS`s!K~}1vm~c3E^_|3!z7ZwfBC(n5c-n zfy1W8Q`u5Pyh(SERd>ie1WG6DmvsTQBc*3d#FnC{pEbHVcF4U2xM~ebe6OgTZOp=& zuLql~ZjN!j`XgP%JUQ&JzTMCFoEA)wtJuz-yI-y#LR48AqmVa@klhZF*Y<sqji)4K13RCl_M;)36`_ zU|I25_wnCM=dS;2%%sm3lw}vJgZNo8gxpwtJ1pCv9U5%bu3&X~z?(^}Y za6TJXRNDg{V!~Imzva8;J*jc=XZ^k8)EeKm9N;8RTxh5z&X$n%!rWw$$rgaXuzuk) ze+0JEIrb#>q@?$B<$ zid}jQVMg$_AjKgtwStqoc#Wc$pmsDIeN+$O-# zVA7?v^361MVv5OxAS-BfXv@A{2=%M9@yy%V;=WI6uJs-WM7hZCA*9CNpN^In^}Q05 z`6OEKI}QlW4hcS&k5_}qNEdw5D5j6<4~KOg3xWz3?wT|#QGDw+-T<=ro*FB0v@VvS z$4?YFH6eWYa(R$Y;+)3x)=f%E{IA~>dpm!}Gi6fWGMyKp)1G*Aq~2D;1AhshaDS7s z9F6dNjpT0->O?0g5Z6|o1`4s!aY@>HG8JrM;=Z#4Lt^t;HHOcY&?lj1qP?luYXq-M z`e%5M)4OIIbpjpaBsfx*^;<6AaKl}mBFh*-;(y0!i;sYZMQUzz5yA3t_IZ8KPw!>n zUeG0wAXzb(e4%ihV*Nut<4&6YRN$?TrN2DgkSFWVMvCuUtQb`$aoaiC zK1VV%DMtQjcFESXVsvKl+<1O53#a5r!d`6cb7)V0`1IDhIsMWomzzyWw&ffZ{47c^ z;)@cS54R}tOM~we=ZX}RuV7|1^b9RR&3hHd<#zgh6{f-Xc>!L%9p%_xI#%DWogQp4 zp)mYJB_7u;ec@6+OqQ^;cQH*dx<`|DJDugVX@%o>!0k+&=^%02?9JxupJrGsxbG|~ zOZ@$)`v}H%+ZAF5MybMW{QIgap}n?>9ggzkNs?;`ow#+hkiu7V6+r zkkTmtuV_NcsKQB+E#9yzMWc_T#rE~7ztx|joF|EEuRo*4J)E^x#_y`O<_(I51Q6Pp zjS~k)_qKNtw{c(A_#y@Ts3X;W?d3#S^|c7}%}=!V{$c~z`l30-AL)Vk-?stm$- zQG;|9G2a~g!qey5gkkIj_=MoM>Li54lE$zl)6t~T!#6GsMK-m3w?@>6@_x%qp~&Bx z&FL^9zLOB;`*8bk=7Owgzb2I3(?6f;=h81h+_PLt;P5!)B{#gxg#&nqz5q)rLAMEu!Qs7IhiS< zaa<(2%$yz+%!;x6bLDD%5#2?s*-pwea;A_e4nsPnafv;XN_E;fBC~5k?`zu=Q#Nq{ zlW9DdmuBGOwv8HAsFPW$)phGPEB(%?@!g0n;g_H$QcAj3%G0m@D3#rEVUMr9j*$E1 zu7?fJhcS!GW&%XNE9LXbc8@>*393K!V4^xKMbn$HO0|Nvq7o)C`VE-0FmoOP3WWqg z6|P48nLK`^GUwQiYHr~Rl}y!phhY^e2Jh9idw@aULTXb{wa-*%^)W$SQOr;LJzA1_ z)a!a-;u)hCS`C?am}Ig!HiB+ul_U1wr?*|_^pP?&c|FhiujBb=W`Yfg;}gym&Tux+ zur@AA&U}JGN*$91Ol({Hky%_b_u6_>FBj^`bOgK&esr)!0FB89Dz`CZTGw_|TMp$P z+18K%F1zc#>$(OZNdu7S#&x$`yuIz6>eMslaB9=qvEUV|9fLCz%Nj}k30F=v2C_)3 zD4fAipO%@({YId$jCkp`kI+>uGI6@FfXw15Ucc%GCNT@EtbOJ7-y5er4( z`A@*RGGHMbXwu%TI!T5Ppcc~H!HttH1-FJ>#3xzUwVd_A1b0h7)bG7k0$emLD-b3A z$0$oQzqx-CusV*P^vvx$xI~-${uwF+vpj8BO#C*6bdp4MbjEAo$vE%%{O$+HRxetE zbkS#7Gc;oRH7mEW$dQGq=^}F0;`7ymr6oKdvUk63#Wq+TG&$XKnN#ewX`RKT-h+3S z%3hfJwz{!IT{pmeqt>@$2JKb#dygpd#(js%Exi;lN_ z;}6ewGJLayjmmFDZTupaeL5HAE2@j47!piv@Ti`bX$8YX zA&28{vOu42lg(MaxFjwu5Q(fY z_qn{dyL8_)3%RoIHfMrm|JxA{e5=ZCS#B8*D&`UA4OBD8Y@*$6iah9iJKQ-t(x1?6 zVWCQ*CwL1e_!^71xHixuxnLVO4+W@B>G3hBB2cMZGU@EB~ zdpsmYYdi;ie`fuN$3<62LAU3CsB?(I`goNNPGbp*=1kMxkHP>!h2GHI2!_Y^u(d0@ zR0{XRhBUpF5O-eko?J!$h~}|K;Pi;l%IX_v>RGTFgQcx$_b~(OWNmCeBh6g$=K2lp zs%G4$6&lZ|!t9jsx6&M52ko^WngD!+H+Sw(SL6ZvO)x%=_h$D-sD_ zo;gR$>)@54p4suvs~;U!Hs30kwT#QiB5FCBga%_9Ok=ZsG=}IvH0-N0OpK@SnX`E3 zCJy1JSKoKE)jAej4NLG#{o3f~Ob!|-0ZS;}QQ3djL1EjNYHFSfuU^~^ZFAe-MnPfwMvvQO4QrdnX-!95_Mg|KskH|8u=yELwxH}` zc^21z-&1foN)qT93@#wTFSe*Q8eoL$`3}zyQ54~Gz89}8alTXXKLvR`wWilYP9d#K zQ;*@Eugb7PI}h>E2B)gOk~B|qMk5e&nG)1Ul=eEENp8a;u;Da}YodpkFJ5&Lu^g(Z z!LpiT_LKAINiLGM;PKqaQ?N~E_iYgls>P`-b{OBb9_g7w-;)~M&t-7_tu92zbSx^K zKJ3#rv2+`)lH)V5<|gjR9b*0wqhUA5cm2l8&E?cdD^CwSoH6CP&2u?G%!qqN-?P_p8|bvDd5SaFC>cGsQ|+XtQy+i_RNwtN$(HZXwo@1KVh_~LsRSc z{nm^#fMBj$VP{6(e)oEYE15)X-T}K9#H$)e3WZWx4 zVQ;?)=GhI73i4+AVb9zFcXtDFM3bTzym(4QT<6h0UulamIW2A_bSC7< z*;S9t&kJX%W)Wp+( z=`>ayJsT#n(RWzTO0`5@$y*KB5ShWN z^t&7DLGsx3Z;r#SMvsgoqMLdZQmVa@T~0QmeNd>{ixzcpuG74Fn>x?T0YIMGC z3A&S;eD1J$vngGAmu_=sobKa!?sRK8C`G%45)~iGCJ*&*Mm(>Oe9^p~InLnucj*l1 zsx>Vk^_Ie>Z-YmUp9JXAS_2zl)O4|a- z4?(V6b~YH<(o4$~R}+u!N`-Nu?RMtqo^eO{cA{Q|Zr3HYF%qG~h1d#Gh3WM2AB?&X z&}*z_)XoN*0()$pmj-wmJEef1P38>pVm~Ot00!@9c-ws0Yz%Y;vPJbnIlgrE^m zf|}xT#vc&r(xh0trXkPyPPmbmZ~3 z29`@{DafW*kp0%5fiq`$~Dr!W%qEiF&iRlBum%0{X)9HU~(3q0K8 zVx6bqc~hT!HU4c}R9xhbl>$@FsVcUAGLqYGC zt$V~ffRjv&CHnJv(OpE;hQiFG*&JbgJI$LX zKH@nZ3Q1z!BNIym-g2)J=_irJm4tjvI$AA;&Uc=7vw8(w*7{CbKD{;U_PV53{Kc>z z7oL%Xf#Rw5bJ{k{DCC0DvW7~q$TBVHI@o10Kkg-n!YN8PcwPVSh?CHg$usiqz3==P zIdcz$=BflS9NER=w|B7hy2Ptsi)58kiP{||>earH-A6hdJz$pZ)BV;>mFp$Gb568&cBD%K2(36iVT4N5~#hyzH&0SI@2 z*_4qF6RN=e)w`dt0T%3+f`!|?3&o=3+(4_Ug8T^r%i{cz@=KlZ$7AnBke1f&k;*v-WL`_tioshgUcZ4g z0fUT@Y~xsx!F8V^FcX8U3)@BZj0<}B+@id_#)bv@AyA=)S=z0fNQWg)gl}$9@{J1K zI%l~lufIDe``KwD*3;=YP@?m)709rTEuure%s`Vw{;c%{W72@xk~?kq;TmN+p83vjHFT2 zK#~S$=3Gxxqb~V&6ujcIL%VC0qPu9Pscm^WN3j~UOs*x5{p_v7NDI8$Vb{-)eAp}+ z+)mBfHx}YNbU6QZ`y_uK9~hreyXU>5pmUpgY@>(V1MaQq#1uXysPdoC!XPjxo)s%t zd0o8Ax4sM{KEF#x5yZ=Y@B1TSDgwNzR64>UZmcqex*kK#wa~ z5#RQDsUH|NqsR8MvvY2ySK}`+dhA0M+{mV4uC~Yr9ewXN^`)n$`J86-$Pb&=1EmV*?csX0EsVhF>FkEON)w&cuI4GXWDP3a8hY* zXRek>;R+)O8Jk*A!X9Vf*fX(70$^MB(j8cdPG`B=eej+B#4|CM4JDJa=*)`y1Ijv! z12FdHvovFnCY`omod7{MCYh5N>TP*B$(LZ&1Co@px6kcF_V!y=sKL*j);ihl_q5wq zuaPL6J}lwq?l3Naw67I(^{Xl34;sSTIpD*!Wy11veMB&MmNDGlT%2sxe(%0{ua)8f zeq3R+RN4aXclZ*gluW$LDaQjA79PWoycf5<9CRZwyTsffFc3JY8;s~%Cqnt=(V0jKNgDj@n_Nht`vre0ARhr%-b zG>wz0Cs`a9IYE7Ueq(-Vpv^@9U7#>YRw&lcCxFk5X>V(}59R5pS32}slGh28#*m07Rlq`mjzC_~oQloVLZ|qZ{C=Sl+=I{6sqO8g`}m2dqXdoFNx3SeAd#3>!GZ%pC*@;ME@pWKLIt@`oAabWk7pD0;$Q z04Tc>NmB_XDb|tfO%C=DO82yo$e+%a1;7`)u?E#O?AB9r!nad+ zJqkJ2V^#C~S^|Bgx~)V#gkmsH^H5=-<6D*K=nN}Yied7JXiiPDrKN#=*c@-q+kK;) z<5>~-?A%Ay&fQ)T;SS>k&BSN7wrtt$Hpe!_tUF|4?Y1p4c9za%?3$QdB|F}juWW_h zpPcf3tNvt|P`&!5iYRwNi(BY;GXM~+xOLV8$)e3L)P4_;4{ex_Ak~pK(WSLEe>TRJ z!zT}1>L4TIRjxl19&ATFENw1t(MMm}1&1>GAgh0=TabvVJvS$DdsAz8yDV7GzWH*b zsz^!GJ8g398hRznd}q~2Qd{;EfeDV~FxHs7TEHM@`B(w$VWzP=*HMe9P*3+_@_8yC!GYdtUPa(9LeJ0; zWIYNZK;+!FH4gJ!3WSXnehrCQt1|Rzje+~|tTP)s%_*DJ1_#%whe=-e97%|27EcP7 zCyUBxROi=1!4X7^94G*`Ux{m;TPzI0?ySQ7^*tG`og4em?$aqv_1Y+TzVH~^6|HL0 zv)KW|_15{9>uE~koRp@-#;n(g!Y>w@2E@3_ZAhFT8Jc1Sj|2Pn^Yql$1T58J&udTH zYIt7{u&y<#4j-AjE0KB_$jtQ7f_o_TTQyWjb02*%x84kLU8KX`Ubc4iE5?5zd?qL8 z=9Dm_QC+9RDB!(n@)Ocn36Ww0Ppt>1BMpdtwd#|%3)reBJFY4-_O5wsRNrRKspR;v zg}H=T=%jm%jXF|gw@bGPd7O#b^JdF&CQ#c&tPDxwN~%&FQ3ctv=cY5XEW_imBa*Dp zRTG+?3UcS&Q4UKTZtCP=T5eo}kHN6-KK+TE)Ec zc`NxQfF;ceTc@2jWMd}n_1y}j{E^Ji6{mU<@5#IJ(0)dnK-fy7nXR!~cGuEb06`rb10>7m=@uT0`xe|nq2J|CAq$%5+M?I#&bkX~G-;a&}y|!U48dShf%bXiByJzRg`xr7Fp?6q`kGE2hhxVhM2>>%bU*5 zo5ETC%aC{acH+C&88*C;E5wuU)HA(-Oye{blmoe(c~3b(#n^!_a90v}6iGE(JujH6 zP;;IHu*(SMUWou_8oynqy4nTdl7Dy|8bZugM=W2?K}WBoF*T0j?yJpzks^M->$@uck8*7S3%ACxnS$FZU`n7^J;CPr`$115Xn_q%S2&<@x zgmjT!BQ_1}&?5vm#a(rz2P)|4QI?dH2ur?-d51bs8QQgPVn7)k^6sSs6XDv>bK6SV z`V6b`BVy%Z7bH_exX0w|rG*-P-!vi z2}OhQGdjMvNxq|t6DDK2zP*bsJ{!{J1$n{2oj(xz)@Gy>6YiT=OA8idAIz6{0|UQL zwP3&u;49dlWgPj}>4;M_S$|CupZiv*rLagDy$iDCNhAKjh^dj z6c9fX#*||T6eqUKr;ZJCmnY!;=IJ=uunYM z{~MlzN|4CETW2)48oxVpJZF}<7JN5Q#bx^gQQ^xC3<<=4U6r{RHPs?N)?@EA&|-89 z_XOk$qsaR??7uqnaD=6M!`fyk+?tQQ&ShVd%20krzcXurBhCnw8t8*(-qHm4`X zyGDVus3lk=druw{Jt_1>s@{2F#1dy$v_)A{#ywdinWSdgu+gaU!vGVIH*|Fe`RU8~ zv(jLw$>dbH(Vf?ypH~|6{ruZCdzEJYMDVm=>H!D(Dc5J(3jT1o1tO0$`iFVg@)uEr{|0;-fff)t?D}9xP56H)vNJ}&Xkwf zI4sf(LCzU4#x{YWxteiS;c-4IF6xKAMC?uH--mM;ahUP-C7YGQ${7a9_{t?7FqkJm z{)A3QhoyvvL#uW_n$Twwxa(OKG0IVM)%Nu4TRO|0cEJvs=&5d!f=A0&oxh9yW$nEU@Yn zxYl_szi;tXIA}w@7!DxMT#h+GLB|_g5<(}+T3x1^ULan<3k#1azzFB&^fL&HHZ&I$ zjuvBo^#x?m<8`V-SeOUfv~Wj4BEtOhe*rcv+T|8=KmKx%qL9*YM{DEKXM19I$v0si zV>01f6|J-~ffg#3A^D=G)XsDkFEx}n)WOJ`-CI>}Q3y(^;_4Bcla3;{{kYcYmhnTP znFRhysXtMK!Q~@1+2g_;$*So05lpUmUHPb-s0q{%XAJk8m%|u$#8h5adn4$UOWrYX z(vQFaMnkVPvz4mox4}@3>@Ig&NR%ZF=Z>U37T>IX2c4;iBNEygRmWwIW>0Ky#*Tl= zN1Rj$M|dI6!W9*$XB$YmoM(_6`fH3NOoCwFK9ZaJO6Odj^9M4%#wJ_L7MHz6dwACS z&^F?j?@Reb_Lk#8KO7FGrt(5%^!`0ogM%(LUsWK*<*^oCnlCC~V;=(=9i4VL` zX83Kr30f^OvU1j1K%egV<~?+klOEfZ^d0qmq`qxNO_N;>ym7aQ41IibcY*f=LfM5s z2t7uLA$Ca%m?@XL12!$+gG7`Fjsbi2A#U}O(Mg`G#IrkR$P&IXqfS)~L6p)PkOszK zyaw{6@~}vGtz!qHah3?Qr8eitTen1BsyAa%K4F2b2%S>N#-Qg)CO%_zuYBvtAx7AV z`CTDSF)vv;@Z0Q{Yll;gf=|U2n7J`d!+GLZtKXKue2QAWPjI%G$_zi?RVsJ=m~aiO zIMJpq>nwO(FF?yMW5LU=Ug5bCHg;0*&Bz+Jm=H@P9As$HfWCha+$U9=J@%%cKwcCv zDE3-pf}O~i3Km6AVmL;v>D&-9t5Mq+Hc)%?s4!+8i5tQq%;5ke5UXY>xyV_lV-TLnk z0%rZLG{iZpUHA5AbFhlmfW;;zlWX&h?&KRoTD&9qlu&nUvT2pF_;=1DdKxs6%*Zhf3zKcu!aW3*_W3V)b*L|9m`suR$iDH`k0@2W=uK%au&ZNWX3iy;7K>hS zVdnG-)VFd%5ylEKMD04#tp@UXyyd_yL29Z(KIjfHMEwawuG8|zZ0Fv3lN^>ck6E?1 zN%qa>67YEDxxPOwRd|jvV)pD^4vvWfrUk`1ypc-;riv*6BtS}!&$P@gb|rT9A{Bq) z0`#=3HoO~O{ z@H=Eh*hXb}8NRqQ*XlDTkl9|U-(`#xD&2=tn)cdTv5lfM?5QN@$i|jCg4>o)W^?sV2zXR8>XyT*=s7 zBoVUYajD=7;0JxkL#6x%mYkH8UGhA~Q_@J=kAnWzEv_sB#49`SVgG~kLO2iXWII-(d#A64sGLdzv zLd>8x(PqP#{@enSp!;V55juu2sV(T2eIV)((~!DOE|{Ja&tHaT)4fJj_r+rrggVm3 zRsR&$#El2!98A`9<6~^~I`nm0!3RQjC$8YZ>~oeO90?jS?ZPn9k~UrdL)p!jc^^g= z*1Xi?&dOT+c}1x@n<(J-vC)&BYCI@GAh9yLVo-Wj!r8g{CcJhVs_jx%JIE{#F*?`^ zD{e8;(8a_Y=aVUVQuB{~bOL1o7W|kba5uGj7trX^^ZtA-FfrtX+9{4SS zvzXwNh^Z)Df#`7^bJnMFVJxd&hWTR)5p#NkHau-bo0&!VU*DedZ(c9tvu6>%_wVNd z?V2YDRauS;Dl{~d;dVLrk}C#yq0)%GY^`#zbuL0^tZH9e=`@Zh7x`nqAwt1xNzuT> zFlb=3Ptc%d5Mmp56TkccvN4TU$d9$MtGW3^h@_Rg=7LAds23`8#t;NM&gjC7 zGx7DGBX-Z<8%p}jIrOeSr;UrEfGuI=1+rNe?lQCo|CacVjw3OgF|5aQwyiKU$SRU#qVP`#5zHr1 zuCzm?6MIBO2%EAi5FmWhBLp`+2E&loe+q)>3PcuC+*cV81j6@x3uV-Ub?i@BUEOu= z94rrG$??DhYNj%%yUvQpB!@2sf}b7L;z~zHsYWCZ$_}$^KBSNS0IWA z4$*k_gV~JDb+@8D{DcvYIM+pN|0&F57BOoPjq0LWtb$1C?|uUzuut|togM3yp*fjb zWff60QSjy)h_+UwD;HBF(_3$5^k=_I3rbrK{1Y4B{BGKJg+)*kdM-R)DJ3wqc`Gvw z_2j(wRF)e8%_p+HekF>ca6`)<5zfAa?h7E5A=Ai-n!blZwjte?@7k zy=wBaZH?=Bcl4c%g;I~}=;vFJr=Bugi(@0nY}zG592~~9=UHL_7iLGM0+Hh~E~gRF zoZsp*iK|41iw-4DV`p=3g9{jd0!aMB*Ii-bvyz0N(O81wEvGFy$<UtJlBVJOpHHL5ti*#lvi+*xPy>r>n7fO$S50C=(*`cKv?DswuNCoH(W2vs&-^Gs zV}Bvz+{GXsI*f2>b}o}MI_<(-nyEnKm`qu5J|)EktV{-h%8j{xZn=Y$%nifs8_VLx zXC)5)cXC=YKs)L5K#Mno&4ee0df#qBhhM`+W{gMC1(sJ9Aj>khH6-H$#&eg1wp`Ku@H;Jh{p|oaJIIax~?Mt zH};?Tzn>qlamaYuMoc0DUKwAr4Lzizi?A+t4VzYNLesQG+p8*yf+&haA`w2nV;8L# z&(YF%0-L5{b86gu^9=cU*GOPk0zTE;gAp_`5N(1J=OsQKHWSY=qXjkWs)Gl2KA6#~ z`C6!}uH$@PE7Q^xn#C}`^q7v~H`7o%jG#SdJp0v<9z|Ll<$0svKY-urXLdqI$N@ny z7A8~B%+3|JQ(0cQ$W_v@rFjd=MVX7!?dTR`uIjKIcVroiotSsz_3iTPQ497X=_G_f z(M(JTqZFmA#j)#i5IOz^1C{{MW;xB!lEN}g1x?rWz5!I{*We!s5O$_=ww0+k8_GtpzFaf63o5To zXWWp%NWH7u`4BFblgPPNV$mqNuG8GyjMHJKudAKF#q{_CfK7txn22UF(|h078Q%6V zywgYg%0Cj;1*7D@6Rd*L+qV{wf)zW4xiLD{=+@yHrD5Z3A2@@eRVTQBTqWr@Ns z*Q`fVYjE`1shMg~%PUo3^WBmEFKlrp6Wp>%MK}^-pj)JtrEDEjT zQ=owohqblE40&f6@rNJ=r4B3Q1unX#XK85ONnhuA#{15qMTyEq4pYIhEKRvTAsht` z?D=-a+J-R2qL|!es157+C}#~L-6L$Pckzb_FVUPbw2>$~9FzDomD42^FayrP5kB4M z;?Tq_llhfUUrFxUBUnZ}j0Tq@OZnHm_$~!DZ6)zhFS_rnZWl~KNo_s1Y`GN-n;YOp%^#6wDR}f&c6l2t*a&g9tSv3)@swcQ*7cX^s*wtv` z{Nya%B^59Q6_aCZt#k0|_zdCPa`L6D}+>)x~Z;9vR0}P)C!cjB_VnLeb-T z)rz>#d_$bdvP{?Pe8>P{74CWXYpht2JzHe&Z-33HED9tI$&&x8Ic!ErWeIsnmHf{q zQcJ$~`4j(?eq?!Z4;v&|t-Ea@Izlg3wy!1vWt$|ZlfL;WX zli2d@5C`$xAprD(6~yYdBX%y0cpwHeJ^nbgwY5}rb`T60H`~~_5}VD&NAJJST%}4bMMGc>%n)Wg9b_AA%QJxaHY97?lVswT0Kz z(?xO-6-5<{Mh2MFjNc_UH;>w~mFT+8+5WQ`K7TIspL9&CTTI=F-z~0X1S+)$1yjk(*zD z$K#>1bK#VFK@f1p6&eMJOXW=*TmKo3UYg}z`4ZD=jH4TFgkf->KhHz!T)ga=Wpw!( z7=(=@r&(2QvUC@G*lb3ZWujVyaLn*}h>AkUY(m#{tifPfNJ#=}qdN3O zG38sC`pdtjHtjZku@h{*stlRq()x}Xh zShLZP`QaJXpMDR!I;HR28oK6U;qxg(A|^wDs5+cGdzR7B>@JPb@x`^~<|`+O^`AwL zYB+11)F>)DpEFASb4(iGX3b15)%z1P3x!skHi;c?{xgCuqNvdR!W2P{#wt{R|u2Q6R$UVQ@Im#+GjR2tqk7 zR|URrOy(%!*%Oj)m{TkS?Yy;nY^t)Nd z!r?IYed9jjrfYNxOcMLeZ}mArI+kd{b-IsqhUrC6UG3s$Kl{%Mj(_u;f5-9T zi@yyz0^@gn6}rLR?*}G`7FIES$5){ZVy~V>(=;Y;{0y3P74H7$fo@_pw{c!O6dZqj zNpp@^^Z5SL|F+=xzxxfEccQsB z;T(7Y2hT6*yEZ-gDEIH)O*|f-b4AOtj3h~%J9CD8U;0wEWL0cJ!fO-8Sj+sR-nT&# zIlma0Y%z@Tu31ttpC-L+?-F1(e}>(=pE4APS%jJCDa_{VR#RZ|+P?B&FvOpq{rTMA zhq4@Vb<$+EB-L8CMN%x*MYsMF6BA5LWv|+so}ONE#q+Yz0PEg;0x*Ji5x>aiPZ^Z# zqDf?6z(rFiMBUrQF&3+ZfdLDj_Fh0Adk=u~k;tNXX95rkhY19;|3V89!_6PRZSpwU z;bQ=(PA7S2eEv;iUXod2V8F?yK!CM}jL&Q~8?&=A_YMBan1e~6XNihcRaF9k>~jr; z!WjjQ3qhQiBLDY$U;s%M^tMucGAc2nf>B{Mn)yUvRDlmgpDP$t3pkVx&rYNGY@=nPT!M4Pm5mj9-($RQl5Y&i#ngI%{INagV_}wR1qFjH+S=Oq YKM(XtPk?ddN&o-=07*qoM6N<$g6>t}DF6Tf literal 0 HcmV?d00001 diff --git a/modules/Home/Dashlets/InvadersDashlet/sprites/cube.png b/modules/Home/Dashlets/InvadersDashlet/sprites/cube.png new file mode 100644 index 0000000000000000000000000000000000000000..89c04bc9b95745717a65d205fff4dc905a6d40da GIT binary patch literal 844 zcmV-S1GD^zP)CO{AbPEizv z5JE2ZgvZL<8ErCm+W`O|Ehm13yk2f~VJ_(Zw#4&1AB)ArO99Ba?Hh0n^$tIrY_mIE z`qsAQQu~u4w-pPlEUtfF`ZtwGBoaxbQt1K! zr_K7|k>0rGxB48yP|?|pdE8&snm*J0QF2=s#^&}Kz76+M;?K-}^J%f=wQ zV*ur(0|q-!J8>Mx3jlI52nxms3NXIc5byn?qy@)KKeasSCh2)xFQ!4+vZ21Z^{1LVDi z!C-LHX0yFqrs;)&31(7`qw#_0z z5Wde8HIEQNZl>GA#1BV1mZKH*W~SCmqQ|)7H7J{N5r1HbEzy=2ea*6igdYI>2qBgv zNm6Sn`EG;jRSqV_ls~MvjqM&LemHt0$@Vvn5!gGiC%W*1Gq+sea!0dbx{~3vUit%3 Wn6_uJcAjhi0000CfUT8NF6u~%$@n3&zv)J?!Blg4{N}4fY!_yep!!>s$y7Y+p{}axOjeuk&zU} zA--Onbprs1fDze<#6|&x4f@}B1bDmvf^3jr!x4C_DKL*4KpsU1)>(+&$!1+Yn{~7! z>u4k*lR)2kv}8eW%`K5|&ZLs&)Z1_NCiXs=;^sedeDmF;e*eQvDG2l>RsHc{^xUNb zB61W+G@1JoFp}$ZUp@2LKw@|(Lo(sg)#;LH70Kl!{pDAMvm&ySYHANP(U?@#UsnZ4 zCC%5*9?ZD&l~Cu(A#-J)8#nx97%~)#$?4Z$Yfp(NGqVAeie=uj1cB1m=aTC($^4jo z1Gt)PchBw{PF3d0A*H#1>4NXv9S=u={i^~PBhH7Xx3%Z*mKpuG#OSROpL{w!T`FnZ z^K?sF8{8S6Ckz$G5vB@06Vnxnvp%hDni#*wkQrY8kdx@dL&4LS|-_@*HEpZ6h3TBUSmT zDZoS!XxEAWBGLhjr&Er}WE@pnyCq<&LIR4l_eJkJsKV5I)t%Nh;j7rHt6o(dTPX#{ z0rT!#eVlqZC#p4PS_QC6`sU9Uud`rP`S#)zAAOt$I01aV62M7-{ZAz+6#Zq6t*u2v zQCsU*g{hD48i>_=tPCJ1cLL7LBo&}zz1~z z5lI3^w)ID)R1PSYL(YFONw!Hr)=Y%wkEWXL^7o%-$vJk}n(@H!^pQB$Lf0lE`7wJ~ zMAE7{TZ_OkAllpOP$+s-JSCBF(5Tc32(@yNO2c%~Z+iM;t%fO2(1iuMu+B|TPir;{ z`7zuDpBHKXCjmNhvM>>b4@DP+xA7Jfie5b>jW;9LyYh{hE>k(MiFVE5g+r&KpuB+-UfG249%lV&es|#$3I9y9c>2M9{vT@=aab;)L za&rQvDu%(FCD#I%Z$Tvx4)!ad!f&IHNxmJO|))^%ogLxkYN48QC2UVC+haIo!shxo|aM&>% zaD-#PHieWbt{90JG;|DB!HGnSi5pvS9gJrs5pxJt)$;|BI z7Ui$Na>*)x0+&?PTk|*JLak_Nu=GN&z)XY90yC;wUX$*_ew04y_8+t9AVTU;$C3a5 N002ovPDHLkV1jKsa9;ob literal 0 HcmV?d00001 diff --git a/modules/Home/Dashlets/JotPadDashlet/JotPadDashlet.en_us.lang.php b/modules/Home/Dashlets/JotPadDashlet/JotPadDashlet.en_us.lang.php new file mode 100644 index 00000000..3cb8cb9a --- /dev/null +++ b/modules/Home/Dashlets/JotPadDashlet/JotPadDashlet.en_us.lang.php @@ -0,0 +1,51 @@ + 'JotPad', + 'LBL_DESCRIPTION' => 'A dashlet to keep your notes', + 'LBL_SAVING' => 'Saving JotPad ...', + 'LBL_SAVED' => 'Saved', + 'LBL_CONFIGURE_TITLE' => 'Title', + 'LBL_CONFIGURE_HEIGHT' => 'Height (1 - 300)', + 'LBL_DBLCLICK_HELP' => 'Double click below to Edit.', + 'LBL_DEFAULT_TEXT' => $defaultText, +); +?> \ No newline at end of file diff --git a/modules/Home/Dashlets/JotPadDashlet/JotPadDashlet.meta.php b/modules/Home/Dashlets/JotPadDashlet/JotPadDashlet.meta.php new file mode 100644 index 00000000..2cd9aa82 --- /dev/null +++ b/modules/Home/Dashlets/JotPadDashlet/JotPadDashlet.meta.php @@ -0,0 +1,47 @@ + 'LBL_TITLE', // array index in language pack + 'description' => 'LBL_DESCRIPTION', // array index in language pack + 'icon' => 'icon_JotPad_32.gif', + 'category' => 'Tools'); +?> diff --git a/modules/Home/Dashlets/JotPadDashlet/JotPadDashlet.php b/modules/Home/Dashlets/JotPadDashlet/JotPadDashlet.php new file mode 100644 index 00000000..eb4a4415 --- /dev/null +++ b/modules/Home/Dashlets/JotPadDashlet/JotPadDashlet.php @@ -0,0 +1,177 @@ +loadLanguage('JotPadDashlet'); // load the language strings here + + if(!empty($def['savedText'])) // load default text is none is defined + $this->savedText = $def['savedText']; + else + $this->savedText = $this->dashletStrings['LBL_DEFAULT_TEXT']; + + if(!empty($def['height'])) // set a default height if none is set + $this->height = $def['height']; + + parent::Dashlet($id); // call parent constructor + + $this->isConfigurable = true; // dashlet is configurable + $this->hasScript = true; // dashlet has javascript attached to it + + // if no custom title, use default + if(empty($def['title'])) $this->title = $this->dashletStrings['LBL_TITLE']; + else $this->title = $def['title']; + } + + /** + * Displays the dashlet + * + * @return string html to display dashlet + */ + function display() { + $ss = new Sugar_Smarty(); + $xss = clean_xss($this->savedText, false); + if(!empty($xss)) { + $this->savedText = str_replace($xss, "", $this->savedText); + } + $ss->assign('savedText', $this->savedText); + $ss->assign('saving', $this->dashletStrings['LBL_SAVING']); + $ss->assign('saved', $this->dashletStrings['LBL_SAVED']); + $ss->assign('id', $this->id); + $ss->assign('height', $this->height); + + $str = $ss->fetch('modules/Home/Dashlets/JotPadDashlet/JotPadDashlet.tpl'); + return parent::display($this->dashletStrings['LBL_DBLCLICK_HELP']) . $str . '
    '; // return parent::display for title and such + } + + /** + * Displays the javascript for the dashlet + * + * @return string javascript to use with this dashlet + */ + function displayScript() { + $ss = new Sugar_Smarty(); + $ss->assign('saving', $this->dashletStrings['LBL_SAVING']); + $ss->assign('saved', $this->dashletStrings['LBL_SAVED']); + $ss->assign('id', $this->id); + + $str = $ss->fetch('modules/Home/Dashlets/JotPadDashlet/JotPadDashletScript.tpl'); + return $str; // return parent::display for title and such + } + + /** + * Displays the configuration form for the dashlet + * + * @return string html to display form + */ + function displayOptions() { + global $app_strings; + + $ss = new Sugar_Smarty(); + $ss->assign('titleLbl', $this->dashletStrings['LBL_CONFIGURE_TITLE']); + $ss->assign('heightLbl', $this->dashletStrings['LBL_CONFIGURE_HEIGHT']); + $ss->assign('saveLbl', $app_strings['LBL_SAVE_BUTTON_LABEL']); + $ss->assign('title', $this->title); + $ss->assign('height', $this->height); + $ss->assign('id', $this->id); + + return parent::displayOptions() . $ss->fetch('modules/Home/Dashlets/JotPadDashlet/JotPadDashletOptions.tpl'); + } + + /** + * called to filter out $_REQUEST object when the user submits the configure dropdown + * + * @param array $req $_REQUEST + * @return array filtered options to save + */ + function saveOptions($req) { + global $sugar_config, $timedate, $current_user, $theme; + $options = array(); + $options['title'] = $_REQUEST['title']; + if(is_numeric($_REQUEST['height'])) { + if($_REQUEST['height'] > 0 && $_REQUEST['height'] <= 300) $options['height'] = $_REQUEST['height']; + elseif($_REQUEST['height'] > 300) $options['height'] = '300'; + else $options['height'] = '100'; + } + +// $options['savedText'] = br2nl($this->savedText); + $options['savedText'] = $this->savedText; + + return $options; + } + + /** + * Used to save text on textarea blur. Accessed via Home/CallMethodDashlet.php + * This is an example of how to to call a custom method via ajax + */ + function saveText() { + $json = getJSONobj(); + if(isset($_REQUEST['savedText'])) { + $optionsArray = $this->loadOptions(); +// _pp($_REQUEST['savedText']); + $optionsArray['savedText']=$json->decode(html_entity_decode($_REQUEST['savedText'])); + $optionsArray['savedText']=nl2br($optionsArray['savedText']['jsonObject']); + $xss = clean_xss($optionsArray['savedText'], false); + if(!empty($xss)) { + $optionsArray['savedText'] = str_replace($xss, "", $optionsArray['savedText']); + } + $this->storeOptions($optionsArray); + + } + else { + $optionsArray['savedText'] = ''; + } + echo 'result = ' . $json->encode(array('id' => $_REQUEST['id'], + 'savedText' => $optionsArray['savedText'])); + } +} + +?> \ No newline at end of file diff --git a/modules/Home/Dashlets/JotPadDashlet/JotPadDashlet.tpl b/modules/Home/Dashlets/JotPadDashlet/JotPadDashlet.tpl new file mode 100644 index 00000000..df1a839c --- /dev/null +++ b/modules/Home/Dashlets/JotPadDashlet/JotPadDashlet.tpl @@ -0,0 +1,45 @@ +{* + +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + + + +*} + + +
    {$savedText}
    + \ No newline at end of file diff --git a/modules/Home/Dashlets/JotPadDashlet/JotPadDashletOptions.tpl b/modules/Home/Dashlets/JotPadDashlet/JotPadDashletOptions.tpl new file mode 100644 index 00000000..0fe2b4c9 --- /dev/null +++ b/modules/Home/Dashlets/JotPadDashlet/JotPadDashletOptions.tpl @@ -0,0 +1,71 @@ +{* + +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + + + +*} + + +
    +
    + + + + + + + + + + + + + + + + + +
    {$titleLbl} + +
    {$heightLbl} + +
    + +
    +
    +
    \ No newline at end of file diff --git a/modules/Home/Dashlets/JotPadDashlet/JotPadDashletScript.tpl b/modules/Home/Dashlets/JotPadDashlet/JotPadDashletScript.tpl new file mode 100644 index 00000000..58ef9bda --- /dev/null +++ b/modules/Home/Dashlets/JotPadDashlet/JotPadDashletScript.tpl @@ -0,0 +1,89 @@ +{* + +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + + + +*} + + +{literal}{/literal} \ No newline at end of file diff --git a/modules/Home/Dashlets/RSSDashlet/RSSDashlet.en_us.lang.php b/modules/Home/Dashlets/RSSDashlet/RSSDashlet.en_us.lang.php new file mode 100644 index 00000000..c877b6f2 --- /dev/null +++ b/modules/Home/Dashlets/RSSDashlet/RSSDashlet.en_us.lang.php @@ -0,0 +1,54 @@ + 'News Feed', + 'LBL_DESCRIPTION' => 'News Feed', + 'LBL_SAVING' => 'Parsing ...', + 'LBL_SAVED' => 'Complete', + 'LBL_AUTO_SCROLL' => 'Auto Scroll', + 'LBL_SCROLL_SPEED' => 'Scroll Speed (%)', + 'LBL_CONFIGURE_TITLE' => 'Title', + 'LBL_CONFIGURE_HEIGHT' => 'Height (1 - 300)', + 'LBL_CONFIGURE_RSSURL' => 'RSS Url', + 'LBL_DBLCLICK_HELP' => '', + 'ERR_LOADING_FEED' => 'Failed loading RSS Feed', + ); +?> \ No newline at end of file diff --git a/modules/Home/Dashlets/RSSDashlet/RSSDashlet.icon.jpg b/modules/Home/Dashlets/RSSDashlet/RSSDashlet.icon.jpg new file mode 100644 index 0000000000000000000000000000000000000000..fca9aa91df82f4cb95c57191e69f814fc2c858f7 GIT binary patch literal 81 zcmZ?wbhEHb 'LBL_TITLE', // array index in language pack + 'description' => 'LBL_DESCRIPTION', // array index in language pack + 'category' => 'Web'); +?> diff --git a/modules/Home/Dashlets/RSSDashlet/RSSDashlet.php b/modules/Home/Dashlets/RSSDashlet/RSSDashlet.php new file mode 100644 index 00000000..dc286dad --- /dev/null +++ b/modules/Home/Dashlets/RSSDashlet/RSSDashlet.php @@ -0,0 +1,185 @@ +loadLanguage('RSSDashlet', 'modules/Home/Dashlets/'); // load the language strings here + + if(!empty($def['height'])) // set a default height if none is set + $this->height = $def['height']; + + if(!empty($def['url'])) + $this->url = $def['url']; + + if(!empty($def['title'])) + $this->title = $def['title']; + else + $this->title = $this->dashletStrings['LBL_TITLE']; + + if(isset($def['autoRefresh'])) $this->autoRefresh = $def['autoRefresh']; + + parent::Dashlet($id); // call parent constructor + + $this->isConfigurable = true; // dashlet is configurable + $this->hasScript = false; // dashlet has javascript attached to it + } + + /** + * Displays the dashlet + * + * @return string html to display dashlet + */ + public function display() + { + $ss = new Sugar_Smarty(); + $ss->assign('saving', $this->dashletStrings['LBL_SAVING']); + $ss->assign('saved', $this->dashletStrings['LBL_SAVED']); + $ss->assign('id', $this->id); + $ss->assign('height', $this->height); + $ss->assign('rss_output', $this->getRSSOutput($this->url)); + $str = $ss->fetch('modules/Home/Dashlets/RSSDashlet/RSSDashlet.tpl'); + return parent::display($this->dashletStrings['LBL_DBLCLICK_HELP']) . $str; // return parent::display for title and such + } + + /** + * Displays the configuration form for the dashlet + * + * @return string html to display form + */ + public function displayOptions() { + global $app_strings, $sugar_version, $sugar_config; + + $ss = new Sugar_Smarty(); + $ss->assign('titleLbl', $this->dashletStrings['LBL_CONFIGURE_TITLE']); + $ss->assign('heightLbl', $this->dashletStrings['LBL_CONFIGURE_HEIGHT']); + $ss->assign('rssUrlLbl', $this->dashletStrings['LBL_CONFIGURE_RSSURL']); + $ss->assign('saveLbl', $app_strings['LBL_SAVE_BUTTON_LABEL']); + $ss->assign('title', $this->title); + $ss->assign('height', $this->height); + $ss->assign('url', $this->url); + $ss->assign('id', $this->id); + if($this->isAutoRefreshable()) { + $ss->assign('isRefreshable', true); + $ss->assign('autoRefresh', $GLOBALS['app_strings']['LBL_DASHLET_CONFIGURE_AUTOREFRESH']); + $ss->assign('autoRefreshOptions', $this->getAutoRefreshOptions()); + $ss->assign('autoRefreshSelect', $this->autoRefresh); + } + + return parent::displayOptions() . $ss->fetch('modules/Home/Dashlets/RSSDashlet/RSSDashletOptions.tpl'); + } + + /** + * called to filter out $_REQUEST object when the user submits the configure dropdown + * + * @param array $req $_REQUEST + * @return array filtered options to save + */ + public function saveOptions( + array $req + ) + { + $options = array(); + $options['title'] = $req['title']; + $options['url'] = $req['url']; + $options['height'] = $req['height']; + $options['autoRefresh'] = empty($req['autoRefresh']) ? '0' : $req['autoRefresh']; + + return $options; + } + + protected function getRSSOutput( + $url + ) + { + // suppress XML errors + libxml_use_internal_errors(true); + $rssdoc = simplexml_load_file($url); + // return back the error message if the loading wasn't successful + if (!$rssdoc) + return $this->dashletStrings['ERR_LOADING_FEED']; + + $output = ""; + if ( isset($rssdoc->channel) ) { + foreach ( $rssdoc->channel as $channel ) { + if ( isset($channel->item ) ) { + foreach ( $channel->item as $item ) { + $output .= << + + +EOHTML; + } + } + } + } + else { + foreach ( $rssdoc->entry as $entry ) { + $output .= << + + +EOHTML; + } + } + $output .= "
    +

    {$item->title}

    + {$item->description} +
    +

    {$entry->title}

    + {$entry->summary} +
    "; + + return $output; + } +} diff --git a/modules/Home/Dashlets/RSSDashlet/RSSDashlet.tpl b/modules/Home/Dashlets/RSSDashlet/RSSDashlet.tpl new file mode 100644 index 00000000..60f646af --- /dev/null +++ b/modules/Home/Dashlets/RSSDashlet/RSSDashlet.tpl @@ -0,0 +1,44 @@ +{* + +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + + + +*} +
    +{$rss_output} +
    \ No newline at end of file diff --git a/modules/Home/Dashlets/RSSDashlet/RSSDashletOptions.tpl b/modules/Home/Dashlets/RSSDashlet/RSSDashletOptions.tpl new file mode 100644 index 00000000..0a139376 --- /dev/null +++ b/modules/Home/Dashlets/RSSDashlet/RSSDashletOptions.tpl @@ -0,0 +1,89 @@ +{* + +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + + + +*} + +
    +
    + + + + + + + + + + +{if $isRefreshable} + + + + +{/if} + + + + + + + + + + + +
    {$titleLbl} + +
    + {$autoRefresh} + + +
    {$rssUrlLbl} + +
    {$heightLbl} + +
    + +
    +
    + +
    \ No newline at end of file diff --git a/modules/Home/Dashlets/SugarNewsDashlet/SugarNewsDashlet.meta.php b/modules/Home/Dashlets/SugarNewsDashlet/SugarNewsDashlet.meta.php new file mode 100644 index 00000000..624734bc --- /dev/null +++ b/modules/Home/Dashlets/SugarNewsDashlet/SugarNewsDashlet.meta.php @@ -0,0 +1,45 @@ + 'Home', + 'title' => translate('LBL_DASHLET_SUGAR_NEWS', 'Home'), + 'description' => 'A customizeable portal page', + 'icon' => 'themes/default/images/icon_SugarNews_32.gif', + 'category' => 'Tools'); \ No newline at end of file diff --git a/modules/Home/Dashlets/SugarNewsDashlet/SugarNewsDashlet.php b/modules/Home/Dashlets/SugarNewsDashlet/SugarNewsDashlet.php new file mode 100644 index 00000000..2ea2267c --- /dev/null +++ b/modules/Home/Dashlets/SugarNewsDashlet/SugarNewsDashlet.php @@ -0,0 +1,119 @@ +isConfigurable = true; + + if(empty($options['title'])) { + $this->title = translate('LBL_DASHLET_SUGAR_NEWS', 'Home'); + } else { + $this->title = $options['title']; + } + if(empty($options['url'])) { + $this->url = $this->defaultURL; + } else { + $this->url = $options['url']; + } + + if(empty($options['height']) || (int)$options['height'] < 1 ) { + $this->height = 315; + } else { + $this->height = (int)$options['height']; + } + + if(isset($options['autoRefresh'])) $this->autoRefresh = $options['autoRefresh']; + } + + function displayOptions() { + global $app_strings; + $ss = new Sugar_Smarty(); + $ss->assign('titleLBL', translate('LBL_DASHLET_OPT_TITLE', 'Home')); + $ss->assign('urlLBL', translate('LBL_DASHLET_OPT_URL', 'Home')); + $ss->assign('heightLBL', translate('LBL_DASHLET_OPT_HEIGHT', 'Home')); + $ss->assign('title', $this->title); + $ss->assign('url', $this->url); + $ss->assign('id', $this->id); + $ss->assign('height', $this->height); + $ss->assign('saveLBL', $app_strings['LBL_SAVE_BUTTON_LABEL']); + if($this->isAutoRefreshable()) { + $ss->assign('isRefreshable', true); + $ss->assign('autoRefresh', $GLOBALS['app_strings']['LBL_DASHLET_CONFIGURE_AUTOREFRESH']); + $ss->assign('autoRefreshOptions', $this->getAutoRefreshOptions()); + $ss->assign('autoRefreshSelect', $this->autoRefresh); + } + + return $ss->fetch('modules/Home/Dashlets/SugarNewsDashlet/configure.tpl'); + } + + function saveOptions($req) { + $options = array(); + + if ( isset($req['title']) ) { + $options['title'] = $req['title']; + } + if ( isset($req['url']) ) { + $options['url'] = $req['url']; + } + if ( isset($req['height']) ) { + $options['height'] = (int)$req['height']; + } + $options['autoRefresh'] = empty($req['autoRefresh']) ? '0' : $req['autoRefresh']; + + return $options; + } + + function display(){ + $sugar_edition = 'COM'; + + $out_url = str_replace( + array('@@LANG@@','@@VER@@','@@EDITION@@'), + array($GLOBALS['current_language'],$GLOBALS['sugar_config']['sugar_version'],$sugar_edition), + $this->url); + return parent::display() . ""; + } +} diff --git a/modules/Home/Dashlets/SugarNewsDashlet/configure.tpl b/modules/Home/Dashlets/SugarNewsDashlet/configure.tpl new file mode 100644 index 00000000..2ca4df29 --- /dev/null +++ b/modules/Home/Dashlets/SugarNewsDashlet/configure.tpl @@ -0,0 +1,86 @@ +{* + +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} + + +
    +
    + + + + + + + + + + +{if $isRefreshable} + + + + +{/if} + + + + + + + + + + + +
    {$titleLBL} + +
    + {$autoRefresh} + + +
    {$urlLBL} + +
    {$heightLBL} + +
    + +
    +
    +
    \ No newline at end of file diff --git a/modules/Home/Dashlets/iFrameDashlet/configure.tpl b/modules/Home/Dashlets/iFrameDashlet/configure.tpl new file mode 100644 index 00000000..2ca4df29 --- /dev/null +++ b/modules/Home/Dashlets/iFrameDashlet/configure.tpl @@ -0,0 +1,86 @@ +{* + +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} + + +
    +
    + + + + + + + + + + +{if $isRefreshable} + + + + +{/if} + + + + + + + + + + + +
    {$titleLBL} + +
    + {$autoRefresh} + + +
    {$urlLBL} + +
    {$heightLBL} + +
    + +
    +
    +
    \ No newline at end of file diff --git a/modules/Home/Dashlets/iFrameDashlet/iFrameDashlet.meta.php b/modules/Home/Dashlets/iFrameDashlet/iFrameDashlet.meta.php new file mode 100644 index 00000000..73943822 --- /dev/null +++ b/modules/Home/Dashlets/iFrameDashlet/iFrameDashlet.meta.php @@ -0,0 +1,45 @@ + 'Home', + 'title' => translate('LBL_DASHLET_TITLE', 'Home'), + 'description' => 'A customizeable portal page', + 'icon' => 'themes/default/images/icon_iFrames_32.gif', + 'category' => 'Web'); \ No newline at end of file diff --git a/modules/Home/Dashlets/iFrameDashlet/iFrameDashlet.php b/modules/Home/Dashlets/iFrameDashlet/iFrameDashlet.php new file mode 100644 index 00000000..d9ef1f67 --- /dev/null +++ b/modules/Home/Dashlets/iFrameDashlet/iFrameDashlet.php @@ -0,0 +1,133 @@ +isConfigurable = true; + + if(empty($options['title'])) { + $this->title = translate('LBL_DASHLET_TITLE', 'Home'); + $this->title = translate('LBL_DASHLET_DISCOVER_SUGAR_PRO', 'Home'); + } else { + $this->title = $options['title']; + } + if(empty($options['url'])) { + $this->url = $this->defaultURL; + $this->url = 'http://apps.sugarcrm.com/dashlet/go-pro.html?lang=@@LANG@@&edition=@@EDITION@@&ver=@@VER@@'; + } else { + $this->url = $options['url']; + } + + $this->checkURL(); + + if(empty($options['height']) || (int)$options['height'] < 1 ) { + $this->height = 315; + } else { + $this->height = (int)$options['height']; + } + + if(isset($options['autoRefresh'])) $this->autoRefresh = $options['autoRefresh']; + } + + protected function checkURL() + { + $scheme = parse_url($this->url, PHP_URL_SCHEME); + if(!in_array($scheme, $this->allowed_schemes)) { + $this->url = 'about:blank'; + } + } + + function displayOptions() { + global $app_strings; + $ss = new Sugar_Smarty(); + $ss->assign('titleLBL', translate('LBL_DASHLET_OPT_TITLE', 'Home')); + $ss->assign('urlLBL', translate('LBL_DASHLET_OPT_URL', 'Home')); + $ss->assign('heightLBL', translate('LBL_DASHLET_OPT_HEIGHT', 'Home')); + $ss->assign('title', $this->title); + $ss->assign('url', $this->url); + $ss->assign('id', $this->id); + $ss->assign('height', $this->height); + $ss->assign('saveLBL', $app_strings['LBL_SAVE_BUTTON_LABEL']); + if($this->isAutoRefreshable()) { + $ss->assign('isRefreshable', true); + $ss->assign('autoRefresh', $GLOBALS['app_strings']['LBL_DASHLET_CONFIGURE_AUTOREFRESH']); + $ss->assign('autoRefreshOptions', $this->getAutoRefreshOptions()); + $ss->assign('autoRefreshSelect', $this->autoRefresh); + } + + return $ss->fetch('modules/Home/Dashlets/iFrameDashlet/configure.tpl'); + } + + function saveOptions($req) { + $options = array(); + + if ( isset($req['title']) ) { + $options['title'] = $req['title']; + } + if ( isset($req['url']) ) { + $options['url'] = $req['url']; + } + if ( isset($req['height']) ) { + $options['height'] = (int)$req['height']; + } + $options['autoRefresh'] = empty($req['autoRefresh']) ? '0' : $req['autoRefresh']; + + return $options; + } + + function display(){ + + $sugar_edition = 'COM'; + + $out_url = str_replace( + array('@@LANG@@','@@VER@@','@@EDITION@@'), + array($GLOBALS['current_language'],$GLOBALS['sugar_config']['sugar_version'],$sugar_edition), + $this->url); + return parent::display() . ""; + } +} diff --git a/modules/Home/DynamicAction.php b/modules/Home/DynamicAction.php new file mode 100644 index 00000000..5cb8c636 --- /dev/null +++ b/modules/Home/DynamicAction.php @@ -0,0 +1,53 @@ +$_REQUEST['DynamicAction'](); +if(isset($_REQUEST['commit_session'])) { + session_commit(); +} +echo $res; \ No newline at end of file diff --git a/modules/Home/Home.html b/modules/Home/Home.html new file mode 100644 index 00000000..1154dfbf --- /dev/null +++ b/modules/Home/Home.html @@ -0,0 +1,61 @@ + + + + + + +
    +{MYAPPOINTMENTS} +{MYEMAILS} +{MYQUEUES} +{MYINVITES} +{MYOPPORTUNITIES} +{MYCASES} +{MYLEADS} +{MYTASKS} +{MYBUGS} +{MYFORECASTS} +{MY_PROJECT_TASKS} + +{SYNC} +{MYCAL} +{TEAMNOTICES} +{MYPIPELINE} +
    + diff --git a/modules/Home/Home.tpl b/modules/Home/Home.tpl new file mode 100644 index 00000000..472ee8ee --- /dev/null +++ b/modules/Home/Home.tpl @@ -0,0 +1,220 @@ +{* + +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + + + +*} +{literal} + +{/literal} + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + + + {if $numCols > 2} + + + + {/if} + {if $numCols > 1} + + + {/if} + + + + {counter assign=hiddenCounter start=0 print=false} + {foreach from=$columns key=colNum item=data} + + {counter} + {/foreach} + +
    +   + + + +   + + + + + + {$lblLnkHelp} + + + {$lblLnkHelp} + +
    +
      +
    •    
    • + {foreach from=$data.dashlets key=id item=dashlet} +
    • +
      + {$dashlet.script} + {$dashlet.display} +
      +
    • + {/foreach} +
    •    
    • +
    +
    +
    + + {foreach from=$divPages key=divPageIndex item=divPageNum} + + {/foreach} + + + + + +
    +
    +
    +
    +
    +
    + + +
    + +{if !$lock_homepage} +{literal} + +{/literal} +{/if} \ No newline at end of file diff --git a/modules/Home/LastViewed.php b/modules/Home/LastViewed.php new file mode 100644 index 00000000..ed01d778 --- /dev/null +++ b/modules/Home/LastViewed.php @@ -0,0 +1,72 @@ + + + +get_recently_viewed($current_user->id); + +foreach($history as $row) +{ + $moduleImage = SugarThemeRegistry::current()->getImageURL("{$row['module_name']}.gif"); + echo << + + + +EOQ; +} +?> +
    {$row['module_name']}$row[item_summary]
    diff --git a/modules/Home/Menu.php b/modules/Home/Menu.php new file mode 100644 index 00000000..09cd4f5d --- /dev/null +++ b/modules/Home/Menu.php @@ -0,0 +1,46 @@ + \ No newline at end of file diff --git a/modules/Home/PopupSugar.php b/modules/Home/PopupSugar.php new file mode 100644 index 00000000..eb6f35c3 --- /dev/null +++ b/modules/Home/PopupSugar.php @@ -0,0 +1,146 @@ + + + +Founders:
    ", 'John Roberts', 'Clint Oram', 'Jacob Taylor'); + +$body = implode('
    ', $founders) . "

    Developers:
    " . implode('
    ', $sugarteam); +?> + +
    +
    +
    + +
    +
    + + + diff --git a/modules/Home/SaveSubpanelLayout.php b/modules/Home/SaveSubpanelLayout.php new file mode 100644 index 00000000..b4d4a170 --- /dev/null +++ b/modules/Home/SaveSubpanelLayout.php @@ -0,0 +1,60 @@ +setPreference('subpanelLayout', $subpanels, 0, $layoutParam); +} +else { + echo 'oops'; +} + +?> \ No newline at end of file diff --git a/modules/Home/SubpanelCreates.php b/modules/Home/SubpanelCreates.php new file mode 100644 index 00000000..36bc1e60 --- /dev/null +++ b/modules/Home/SubpanelCreates.php @@ -0,0 +1,74 @@ +viaAJAX = true; + } + else { // else use base class + require_once('include/EditView/EditViewQuickCreate.php'); + $editview = new EditViewQuickCreate($target_module, 'modules/' . $target_module . '/tpls/' . $tpl); + } + $editview->process(); + echo $editview->display(); +} else{ + + $subpanelView = 'modules/'. $target_module . '/views/view.subpanelquickcreate.php'; + $view = (!empty($_REQUEST['target_view'])) ? $_REQUEST['target_view'] : 'QuickCreate'; + //Check if there is a custom override, then check for module override, finally use default (SubpanelQuickCreate) + if(file_exists('custom/' . $subpanelView)) { + require_once($subpanelView); + $subpanelClass = $target_module . 'SubpanelQuickCreate'; + $sqc = new $subpanelClass($target_module, $view); + } else if(file_exists($subpanelView)) { + require_once($subpanelView); + $subpanelClass = $target_module . 'SubpanelQuickCreate'; + $sqc = new $subpanelClass($target_module, $view); + } else { + require_once('include/EditView/SubpanelQuickCreate.php'); + $sqc = new SubpanelQuickCreate($target_module, $view); + } +} + +?> diff --git a/modules/Home/TrainingPortal.php b/modules/Home/TrainingPortal.php new file mode 100644 index 00000000..22557e41 --- /dev/null +++ b/modules/Home/TrainingPortal.php @@ -0,0 +1,65 @@ +assign('iframeURL', $iframe_url); + +echo $sugar_smarty->fetch('modules/Home/TrainingPortal.tpl'); + +?> \ No newline at end of file diff --git a/modules/Home/TrainingPortal.tpl b/modules/Home/TrainingPortal.tpl new file mode 100644 index 00000000..9aa0f4b9 --- /dev/null +++ b/modules/Home/TrainingPortal.tpl @@ -0,0 +1,44 @@ +{* + +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + + + +*} + + + diff --git a/modules/Home/UnifiedSearch.php b/modules/Home/UnifiedSearch.php new file mode 100644 index 00000000..b76b8c30 --- /dev/null +++ b/modules/Home/UnifiedSearch.php @@ -0,0 +1,57 @@ +getDropDownDiv(); +} else { + global $mod_strings, $modListHeader, $app_strings, $beanList, $beanFiles; + $usa = new UnifiedSearchAdvanced(); + $usa->search(); +} +?> diff --git a/modules/Home/UnifiedSearchAdvanced.php b/modules/Home/UnifiedSearchAdvanced.php new file mode 100644 index 00000000..6932a2bd --- /dev/null +++ b/modules/Home/UnifiedSearchAdvanced.php @@ -0,0 +1,753 @@ +query_string = $query_string; + } + } + } + + function getDropDownDiv($tpl = 'modules/Home/UnifiedSearchAdvanced.tpl') { + global $app_list_strings, $app_strings; + + if(!file_exists($GLOBALS['sugar_config']['cache_dir'].'modules/unified_search_modules.php')) + { + $this->buildCache(); + } + + include($GLOBALS['sugar_config']['cache_dir'].'modules/unified_search_modules.php'); + + if(!file_exists($GLOBALS['sugar_config']['cache_dir'].'modules/unified_search_modules_display.php')) + { + $this->createUnifiedSearchModulesDisplay(); + } + + include($GLOBALS['sugar_config']['cache_dir'].'modules/unified_search_modules_display.php'); + + global $mod_strings, $modListHeader, $app_list_strings, $current_user, $app_strings, $beanList; + $users_modules = $current_user->getPreference('globalSearch', 'search'); + + // preferences are empty, select all + if(empty($users_modules)) { + $users_modules = array(); + foreach($unified_search_modules_display as $module=>$data) { + if (!empty($data['visible']) ) { + $users_modules[$module] = $beanList[$module]; + } + } + $current_user->setPreference('globalSearch', $users_modules, 0, 'search'); + } + + $sugar_smarty = new Sugar_Smarty(); + + $modules_to_search = array(); + + foreach($users_modules as $key=>$module) + { + if(ACLController::checkAccess($key, 'list', true)) + { + $modules_to_search[$key]['checked'] = true; + } + } + + if(!empty($this->query_string)) + { + $sugar_smarty->assign('query_string', securexss($this->query_string)); + } else { + $sugar_smarty->assign('query_string', ''); + } + + $sugar_smarty->assign('MOD', return_module_language($GLOBALS['current_language'], 'Administration')); + $sugar_smarty->assign('APP', $app_strings); + $sugar_smarty->assign('USE_SEARCH_GIF', 0); + $sugar_smarty->assign('LBL_SEARCH_BUTTON_LABEL', $app_strings['LBL_SEARCH_BUTTON_LABEL']); + + $json_enabled = array(); + $json_disabled = array(); + + //Now add the rest of the modules that are searchable via Global Search settings + foreach($unified_search_modules_display as $module=>$data) + { + if(!isset($modules_to_search[$module]) && $data['visible'] && ACLController::checkAccess($module, 'list', true)) + { + $modules_to_search[$module]['checked'] = false; + } else if (isset($modules_to_search[$module]) && !$data['visible']) { + unset($modules_to_search[$module]); + } + } + + //Create the two lists (doing it this way preserves the user's ordering choice for enabled modules) + foreach($modules_to_search as $module=>$data) + { + $label = isset($app_list_strings['moduleList'][$module]) ? $app_list_strings['moduleList'][$module] : $module; + if(!empty($data['checked'])) + { + $json_enabled[] = array("module" => $module, 'label' => $label); + } else { + $json_disabled[] = array("module" => $module, 'label' => $label); + } + } + + $sugar_smarty->assign('enabled_modules', json_encode($json_enabled)); + $sugar_smarty->assign('disabled_modules', json_encode($json_disabled)); + + $showDiv = $current_user->getPreference('showGSDiv', 'search'); + if(!isset($showDiv)) + { + $showDiv = 'no'; + } + + $sugar_smarty->assign('SHOWGSDIV', $showDiv); + $sugar_smarty->debugging = true; + return $sugar_smarty->fetch($tpl); + } + + function search() { + if(!file_exists($GLOBALS['sugar_config']['cache_dir'].'modules/unified_search_modules.php')) + { + $this->buildCache(); + } + + include $GLOBALS['sugar_config']['cache_dir'].'modules/unified_search_modules.php'; + require_once 'include/ListView/ListViewSmarty.php'; + + global $modListHeader, $beanList, $beanFiles, $current_language, $app_strings, $current_user, $mod_strings; + $home_mod_strings = return_module_language($current_language, 'Home'); + + $overlib = true; + $this->query_string = $GLOBALS['db']->quote(securexss(from_html(clean_string($this->query_string, 'UNIFIED_SEARCH')))); + + if(!empty($_REQUEST['advanced']) && $_REQUEST['advanced'] != 'false') { + $modules_to_search = array(); + if(!empty($_REQUEST['search_modules'])) + { + foreach(explode (',', $_REQUEST['search_modules'] ) as $e) + { + $modules_to_search[$e] = $beanList[$e]; + } + } + + $current_user->setPreference('showGSDiv', isset($_REQUEST['showGSDiv']) ? $_REQUEST['showGSDiv'] : 'no', 0, 'search'); + $current_user->setPreference('globalSearch', $modules_to_search, 0, 'search'); // save selections to user preference + } else { + $users_modules = $current_user->getPreference('globalSearch', 'search'); + $modules_to_search = array(); + + if(!empty($users_modules)) { + // use user's previous selections + foreach ( $users_modules as $key => $value ) { + if ( isset($unified_search_modules[$key]) ) { + $modules_to_search[$key] = $value; + } + } + } else { + // select all the modules (ie first time user has used global search) + foreach($unified_search_modules as $module=>$data) { + if (!empty($data['default']) ) { + $modules_to_search[$module] = $beanList[$module]; + } + } + } + $current_user->setPreference('globalSearch', $modules_to_search, 'search'); + } + + + if(!file_exists($GLOBALS['sugar_config']['cache_dir'].'modules/unified_search_modules_display.php')) + { + $this->createUnifiedSearchModulesDisplay(); + } + include($GLOBALS['sugar_config']['cache_dir'].'modules/unified_search_modules_display.php'); + foreach($modules_to_search as $module=>$data) + { + if(isset($unified_search_modules_display[$module]['visible']) && !$unified_search_modules_display[$module]['visible']) + { + unset($modules_to_search[$module]); + } + } + + $templateFile = 'modules/Home/UnifiedSearchAdvancedForm.tpl'; + if(file_exists('custom/' . $templateFile)) + { + $templateFile = 'custom/'.$templateFile; + } + + echo $this->getDropDownDiv($templateFile); + + $module_results = array(); + $module_counts = array(); + $has_results = false; + + if(!empty($this->query_string)) { + foreach($modules_to_search as $moduleName => $beanName) { + require_once $beanFiles[$beanName] ; + $seed = new $beanName(); + + $lv = new ListViewSmarty(); + $lv->lvd->additionalDetails = false; + $mod_strings = return_module_language($current_language, $seed->module_dir); + + //retrieve the original list view defs and store for processing in case of custom layout changes + require('modules/'.$seed->module_dir.'/metadata/listviewdefs.php'); + $orig_listViewDefs = $listViewDefs; + + if(file_exists('custom/modules/'.$seed->module_dir.'/metadata/listviewdefs.php')) + { + require('custom/modules/'.$seed->module_dir.'/metadata/listviewdefs.php'); + } + + if ( !isset($listViewDefs) || !isset($listViewDefs[$seed->module_dir]) ) + { + continue; + } + + $unifiedSearchFields = array () ; + $innerJoins = array(); + foreach ( $unified_search_modules[ $moduleName ]['fields'] as $field=>$def ) + { + $listViewCheckField = strtoupper($field); + //check to see if the field is in listview defs + if ( empty($listViewDefs[$seed->module_dir][$listViewCheckField]['default']) ) { + //check to see if field is in original list view defs (in case we are using custom layout defs) + if (!empty($orig_listViewDefs[$seed->module_dir][$listViewCheckField]['default']) ) { + //if we are here then the layout has been customized, but the field is still needed for query creation + $listViewDefs[$seed->module_dir][$listViewCheckField] = $orig_listViewDefs[$seed->module_dir][$listViewCheckField]; + } + + } + + //bug: 34125 we might want to try to use the LEFT JOIN operator instead of the INNER JOIN in the case we are + //joining against a field that has not been populated. + if(!empty($def['innerjoin']) ) + { + if (empty($def['db_field']) ) + { + continue; + } + $innerJoins[$field] = $def; + $def['innerjoin'] = str_replace('INNER', 'LEFT', $def['innerjoin']); + } + $unifiedSearchFields[ $moduleName ] [ $field ] = $def ; + $unifiedSearchFields[ $moduleName ] [ $field ][ 'value' ] = $this->query_string ; + } + + /* + * Use searchForm2->generateSearchWhere() to create the search query, as it can generate SQL for the full set of comparisons required + * generateSearchWhere() expects to find the search conditions for a field in the 'value' parameter of the searchFields entry for that field + */ + require_once $beanFiles[$beanName] ; + $seed = new $beanName(); + require_once 'include/SearchForm/SearchForm2.php' ; + $searchForm = new SearchForm ( $seed, $moduleName ) ; + + $searchForm->setup (array ( $moduleName => array() ) , $unifiedSearchFields , '' , 'saved_views' /* hack to avoid setup doing further unwanted processing */ ) ; + $where_clauses = $searchForm->generateSearchWhere() ; + //add inner joins back into the where clause + $params = array('custom_select' => ""); + foreach($innerJoins as $field=>$def) { + if (isset ($def['db_field'])) { + foreach($def['db_field'] as $dbfield) + $where_clauses[] = $dbfield . " LIKE '" . $this->query_string . "%'"; + $params['custom_select'] .= ", $dbfield"; + $params['distinct'] = true; + //$filterFields[$dbfield] = $dbfield; + } + } + + if (count($where_clauses) > 0) + { + $where = '(('. implode(' ) OR ( ', $where_clauses) . '))'; + } + + $displayColumns = array(); + foreach($listViewDefs[$seed->module_dir] as $colName => $param) + { + if(!empty($param['default']) && $param['default'] == true) + { + $param['url_sort'] = true;//bug 27933 + $displayColumns[$colName] = $param; + } + } + + if(count($displayColumns) > 0) + { + $lv->displayColumns = $displayColumns; + } else { + $lv->displayColumns = $listViewDefs[$seed->module_dir]; + } + + $lv->export = false; + $lv->mergeduplicates = false; + $lv->multiSelect = false; + $lv->delete = false; + $lv->select = false; + $lv->showMassupdateFields = false; + $lv->email = false; + if($overlib) { + $lv->overlib = true; + $overlib = false; + } else { + $lv->overlib = false; + } + + $lv->setup($seed, 'include/ListView/ListViewNoMassUpdate.tpl', $where, $params, 0, 10); + + $module_results[$moduleName] = '

    ' . get_form_header($GLOBALS['app_list_strings']['moduleList'][$seed->module_dir] . ' (' . $lv->data['pageData']['offsets']['total'] . ')', '', false); + $module_counts[$moduleName] = $lv->data['pageData']['offsets']['total']; + + if($lv->data['pageData']['offsets']['total'] == 0) { + //$module_results[$moduleName] .= "
  • " . $home_mod_strings['LBL_NO_RESULTS_IN_MODULE'] . '

  • '; + $module_results[$moduleName] .= '

    ' . $home_mod_strings['LBL_NO_RESULTS_IN_MODULE'] . '

    '; + } else { + $has_results = true; + //$module_results[$moduleName] .= "
  • " . $lv->display(false, false) . '
  • '; + $module_results[$moduleName] .= $lv->display(false, false); + } + + } + } + + if($has_results) { + //arsort($module_counts); + foreach($module_counts as $name=>$value) { + echo $module_results[$name]; + } + } else { + echo $home_mod_strings['LBL_NO_RESULTS']; + echo $home_mod_strings['LBL_NO_RESULTS_TIPS']; + } + + } + + function buildCache() + { + + global $beanList, $beanFiles, $dictionary; + + $supported_modules = array(); + + foreach($beanList as $moduleName=>$beanName) + { + if (!isset($beanFiles[$beanName])) + continue; + + if($beanName == 'aCase') $beanName = 'Case'; + + $manager = new VardefManager ( ); + $manager->loadVardef( $moduleName , $beanName ) ; + + // obtain the field definitions used by generateSearchWhere (duplicate code in view.list.php) + if(file_exists('custom/modules/'.$moduleName.'/metadata/metafiles.php')){ + require('custom/modules/'.$moduleName.'/metadata/metafiles.php'); + }elseif(file_exists('modules/'.$moduleName.'/metadata/metafiles.php')){ + require('modules/'.$moduleName.'/metadata/metafiles.php'); + } + + + if(!empty($metafiles[$moduleName]['searchfields'])) + { + require $metafiles[$moduleName]['searchfields'] ; + } else if(file_exists("modules/{$moduleName}/metadata/SearchFields.php")) { + require "modules/{$moduleName}/metadata/SearchFields.php" ; + } + + $isCustomModule = preg_match('/^([a-z0-9]{1,5})_([a-z0-9_]+)$/i' , $moduleName); + + //If the bean supports unified search or if it's a custom module bean and unified search is not defined + if(!empty($dictionary[$beanName]['unified_search']) || $isCustomModule) + { + $fields = array(); + foreach ( $dictionary [ $beanName ][ 'fields' ] as $field => $def ) + { + // We cannot enable or disable unified_search for email in the vardefs as we don't actually have a vardef entry for 'email' - + // the searchFields entry for 'email' doesn't correspond to any vardef entry. Instead it contains SQL to directly perform the search. + // So as a proxy we allow any field in the vardefs that has a name starting with 'email...' to be tagged with the 'unified_search' parameter + + if (strpos($field,'email') !== false) + $field = 'email' ; + + //bug: 38139 - allow phone to be searched through Global Search + if (strpos($field,'phone') !== false) + $field = 'phone' ; + + if ( !empty($def['unified_search']) && isset ( $searchFields [ $moduleName ] [ $field ] )) + { + $fields [ $field ] = $searchFields [ $moduleName ] [ $field ] ; + } + } + + if(count($fields) > 0) { + $supported_modules [$moduleName] ['fields'] = $fields; + if (isset($dictionary[$beanName]['unified_search_default_enabled']) && $dictionary[$beanName]['unified_search_default_enabled'] === TRUE) { + $supported_modules [$moduleName]['default'] = true; + } else { + $supported_modules [$moduleName]['default'] = false; + } + } + + } + + } + + ksort($supported_modules); + write_array_to_file('unified_search_modules', $supported_modules, $GLOBALS['sugar_config']['cache_dir'].'modules/unified_search_modules.php'); + } + + + /** + * + */ + function modifyGlobalSearchSettings() + { + global $mod_strings, $app_strings, $app_list_strings; + + if(!file_exists($GLOBALS['sugar_config']['cache_dir'].'modules/unified_search_modules_display.php')) + { + $this->createUnifiedSearchModulesDisplay(); + } + + include($GLOBALS['sugar_config']['cache_dir'].'modules/unified_search_modules_display.php'); + + $sugar_smarty = new Sugar_Smarty(); + $sugar_smarty->assign('APP', $app_strings); + $sugar_smarty->assign('MOD', $mod_strings); + + //Add the translated attribute for display label + $json_enabled = array(); + $json_disabled = array(); + foreach($unified_search_modules_display as $module=>$data) + { + $label = isset($app_list_strings['moduleList'][$module]) ? $app_list_strings['moduleList'][$module] : $module; + if($data['visible'] === true) + { + $json_enabled[] = array("module" => $module, 'label' => $label); + } else { + $json_disabled[] = array("module" => $module, 'label' => $label); + } + } + + //If the file doesn't exist + if(!file_exists($GLOBALS['sugar_config']['cache_dir'].'modules/unified_search_modules.php')) + { + $this->buildCache(); + } + + include($GLOBALS['sugar_config']['cache_dir'].'modules/unified_search_modules.php'); + + //Now add any new modules that may have since been added to unified_search_modules.php + foreach($unified_search_modules as $module=>$data) + { + if(!isset($unified_search_modules_display[$module])) + { + $label = isset($app_list_strings['moduleList'][$module]) ? $app_list_strings['moduleList'][$module] : $module; + if($data['default']) + { + $json_enabled[] = array("module" => $module, 'label' => $label); + } else { + $json_disabled[] = array("module" => $module, 'label' => $label); + } + } + } + + $sugar_smarty->assign('enabled_modules', json_encode($json_enabled)); + $sugar_smarty->assign('disabled_modules', json_encode($json_disabled)); + + //uasort($unified_search_modules_display, 'unified_search_modules_cmp'); + $tpl = 'modules/Administration/templates/GlobalSearchSettings.tpl'; + if(file_exists('custom/' . $tpl)) + { + $tpl = 'custom/' . $tpl; + } + return $sugar_smarty->fetch($tpl); + } + + + /** + * addModuleToUnifiedSearch + * This method handles adding a new module to the unified search list of modules. It will add an + * entry to the unified_search_modules.php if it already exists + * + * @param module String value of the module entry to add + * @return boolean value indiciating whether or not the module was added to the unified_search_modules.php file + */ + function addModuleToUnifiedSearch($module='') + { + if(empty($module)) + { + return false; + } + + //If the file doesn't exist + if(!file_exists($GLOBALS['sugar_config']['cache_dir'].'modules/unified_search_modules.php')) + { + include($GLOBALS['sugar_config']['cache_dir'].'modules/unified_search_modules.php'); + $this->buildCache(); + return isset($unified_search_modules[$module]) ? true : false; + } + + include($GLOBALS['sugar_config']['cache_dir'].'modules/unified_search_modules.php'); + + //If modules is already in list, unset it and rebuild + if(isset($unified_search_modules[$module])) + { + unset($unified_search_modules[$module]); + } + + //Build the entry + global $beanList, $beanFiles, $dictionary; + + if(!isset($beanList[$module])) + { + $GLOBALS['log']->fatal('no beanList entry!'); + $beanName = $module; + //return false; + } + + $beanName = $beanList[$module]; + + if (!isset($beanFiles[$beanName])) + { + $GLOBALS['log']->fatal('no beanFiles entry!'); + //return false; + } + + if($beanName == 'aCase') + { + $beanName = 'Case'; + } + + $manager = new VardefManager(); + $manager->loadVardef($module, $beanName); + + // obtain the field definitions used by generateSearchWhere (duplicate code in view.list.php) + if(file_exists('custom/modules/'.$module.'/metadata/metafiles.php')) + { + require('custom/modules/'.$module.'/metadata/metafiles.php'); + } elseif (file_exists('modules/'.$module.'/metadata/metafiles.php')) { + require('modules/'.$module.'/metadata/metafiles.php'); + } + + + if(!empty($metafiles[$module]['searchfields'])) + { + require $metafiles[$moduleName]['searchfields'] ; + } else if(file_exists("modules/{$module}/metadata/SearchFields.php")) { + require "modules/{$module}/metadata/SearchFields.php" ; + } + + $isCustomModule = preg_match('/^([a-z0-9]{1,5})_([a-z0-9_]+)$/i' , $module); + + //If the bean supports unified search or if it's a custom module bean and unified search is not defined + if(!empty($dictionary[$beanName]['unified_search']) || $isCustomModule) + { + $GLOBALS['log']->fatal("found dictionary entry!"); + $fields = array(); + foreach ( $dictionary [ $beanName ][ 'fields' ] as $field => $def ) + { + // We cannot enable or disable unified_search for email in the vardefs as we don't actually have a vardef entry for 'email' - + // the searchFields entry for 'email' doesn't correspond to any vardef entry. Instead it contains SQL to directly perform the search. + // So as a proxy we allow any field in the vardefs that has a name starting with 'email...' to be tagged with the 'unified_search' parameter + if (strpos($field,'email') !== false) + $field = 'email' ; + + //bug: 38139 - allow phone to be searched through Global Search + if (strpos($field,'phone') !== false) + $field = 'phone' ; + + if (!empty($def['unified_search']) && isset ($searchFields [$module] [ $field ])) + { + $fields[ $field ] = $searchFields [$module] [ $field ] ; + } + } + + if(count($fields) > 0) { + $unified_search_modules [$module] ['fields'] = $fields; + if (isset($dictionary[$beanName]['unified_search_default_enabled']) && $dictionary[$beanName]['unified_search_default_enabled'] === TRUE) { + $unified_search_modules[$module]['default'] = true; + } else { + $unified_search_modules[$module]['default'] = false; + } + } + } + + if(!isset($unified_search_modules[$module])) + { + return false; + } + + return write_array_to_file('unified_search_modules', $unified_search_modules, $GLOBALS['sugar_config']['cache_dir'].'modules/unified_search_modules.php'); + } + + /** + * saveGlobalSearchSettings + * This method handles the administrator's request to save the searchable modules selected and stores + * the results in the unified_search_modules_display.php file + * + */ + function saveGlobalSearchSettings() + { + if(!file_exists($GLOBALS['sugar_config']['cache_dir'].'modules/unified_search_modules_display.php')) + { + $this->createUnifiedSearchModulesDisplay(); + } + + include($GLOBALS['sugar_config']['cache_dir'].'modules/unified_search_modules_display.php'); + + if(isset($_REQUEST['enabled_modules'])) + { + $new_unified_search_modules_display = array(); + + foreach(explode (',', $_REQUEST['enabled_modules'] ) as $module) + { + $new_unified_search_modules_display[$module]['visible'] = true; + } + + foreach($unified_search_modules_display as $module=>$data) + { + if(!isset($new_unified_search_modules_display[$module])) + { + $new_unified_search_modules_display[$module]['visible'] = false; + } + } + + $this->writeUnifiedSearchModulesDisplayFile($new_unified_search_modules_display); + } + } + + + public static function unlinkUnifiedSearchModulesFile() { + //clear the unified_search_module.php file + if(file_exists($GLOBALS['sugar_config']['cache_dir'].'modules/unified_search_modules.php')) + { + $GLOBALS['log']->info("unlink {$GLOBALS['sugar_config']['cache_dir']}modules/unified_search_modules.php file"); + unlink($GLOBALS['sugar_config']['cache_dir'].'modules/unified_search_modules.php'); + } + } + + /** + * createUnifiedSearchModulesDisplay + * method to create the unified_search_modules_display.php file + * + */ + function createUnifiedSearchModulesDisplay() + { + //Make directory if it doesn't exist + if(!file_exists('cache/modules')) + { + mkdir_recursive('cache/modules'); + } + + //Load unified_search_modules.php file + if(!file_exists($GLOBALS['sugar_config']['cache_dir'].'modules/unified_search_modules.php')) + { + $this->buildCache(); + } + + include($GLOBALS['sugar_config']['cache_dir'].'modules/unified_search_modules.php'); + + $unified_search_modules_display = array(); + + if(!empty($unified_search_modules)) + { + foreach($unified_search_modules as $module=>$data) + { + $unified_search_modules_display[$module]['visible'] = (isset($data['default']) && $data['default']) ? true : false; + } + } + + $this->writeUnifiedSearchModulesDisplayFile($unified_search_modules_display); + } + + + /* + * writeUnifiedSearchModulesDisplayFile + * Private method to handle writing the unified_search_modules_display value to file + * + * @param mixed The array of the unified search modules and their display attributes + * @return boolean value indication whether or not file was successfully written + * @throws Exception Thrown if the file write operation fails + */ + private function writeUnifiedSearchModulesDisplayFile($unified_search_modules_display) + { + if(is_null($unified_search_modules_display) || empty($unified_search_modules_display)) + { + return false; + } + + if(!write_array_to_file("unified_search_modules_display", $unified_search_modules_display, $GLOBALS['sugar_config']['cache_dir'].'modules/unified_search_modules_display.php')) + { + //Log error message and throw Exception + global $app_strings; + $msg = string_format($app_strings['ERR_FILE_WRITE'], array($GLOBALS['sugar_config']['cache_dir'].'modules/unified_search_modules_display.php')); + $GLOBALS['log']->error($msg); + throw new Exception($msg); + } + + return true; + } +} + + +function unified_search_modules_cmp($a, $b) { + if(!isset($a['translated']) || !isset($b['translated'])) + { + return 0; + } + + $name1 = strtolower($a['translated']); + $name2 = strtolower($b['translated']); + + return $name1 < $name2 ? -1 : 1; +} + +?> \ No newline at end of file diff --git a/modules/Home/UnifiedSearchAdvanced.tpl b/modules/Home/UnifiedSearchAdvanced.tpl new file mode 100644 index 00000000..0df18b1d --- /dev/null +++ b/modules/Home/UnifiedSearchAdvanced.tpl @@ -0,0 +1,81 @@ +{* + +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + + + +*} + +
    + + + + + + + + +
    + + +
    + + +{foreach from=$MODULES_TO_SEARCH name=m key=module item=info} +{if $smarty.foreach.m.first} + +{/if} + + +{if $smarty.foreach.m.index % 2 == 1} + +{/if} +{/foreach} + +
    + + + {$info.translated} +
    + + + +
    + + +
    +
    \ No newline at end of file diff --git a/modules/Home/UnifiedSearchAdvancedForm.tpl b/modules/Home/UnifiedSearchAdvancedForm.tpl new file mode 100644 index 00000000..a4cb9235 --- /dev/null +++ b/modules/Home/UnifiedSearchAdvancedForm.tpl @@ -0,0 +1,179 @@ +{* + +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + + + +*} + + + + +
    + + + + + + + + + + + + + + + +
    + +   + {$MOD.LBL_SELECT_MODULES}  + {if $SHOWGSDIV == 'yes'} + + {else} + + {/if} + + +
    +
    + + + + + + + + +
    + {sugar_translate label="LBL_SELECT_MODULES_TITLE" module="Administration"} +
    +
    +
    +
    +
    +
    +
    +
    + + \ No newline at end of file diff --git a/modules/Home/UnifiedSearchAdvancedResults.tpl b/modules/Home/UnifiedSearchAdvancedResults.tpl new file mode 100644 index 00000000..23903160 --- /dev/null +++ b/modules/Home/UnifiedSearchAdvancedResults.tpl @@ -0,0 +1,93 @@ +{* + +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + + + +*} + + var SubpanelInit = function() { + SubpanelInitTabNames(["quotes","activities","opportunities","history","leads","campaigns","cases","contacts"]); + } + var SubpanelInitTabNames = function(tabNames) { + subpanel_dd = new Array(); + j = 0; + for(i in tabNames) { + subpanel_dd[j] = new ygDDList('whole_subpanel_' + tabNames[i]); + subpanel_dd[j].setHandleElId('subpanel_title_' + tabNames[i]); + subpanel_dd[j].onMouseDown = SUGAR.subpanelUtils.onDrag; + subpanel_dd[j].afterEndDrag = SUGAR.subpanelUtils.onDrop; + j++; + } + + YAHOO.util.DDM.mode = 1; + } + currentModule = 'Contacts'; + YAHOO.util.Event.addListener(window, 'load', SubpanelInit); + + \ No newline at end of file diff --git a/modules/Home/about.js b/modules/Home/about.js new file mode 100644 index 00000000..004ad4f9 --- /dev/null +++ b/modules/Home/about.js @@ -0,0 +1,35 @@ +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ +var abouter=function(){return{display:function(){abouter.div=document.getElementById('abouterdiv');abouter.div.style.display='';abouter.div.src="index.php?module=Home&action=PopupSugar&to_pdf=true&style="+abouter.style;},ab:function(index,style){if(abouter.starter==3){abouter.style=style;abouter.display();}else{if(index==abouter.starter+1){abouter.starter++;}else{abouter.starter=0;}}}}}();abouter.starter=0;abouter.style='inc'; \ No newline at end of file diff --git a/modules/Home/action_view_map.php b/modules/Home/action_view_map.php new file mode 100644 index 00000000..1925dd4c --- /dev/null +++ b/modules/Home/action_view_map.php @@ -0,0 +1,38 @@ +'Calls', + 'MyMeetingsDashlet'=>'Meetings', + 'MyOpportunitiesDashlet'=>'Opportunities', + 'MyAccountsDashlet'=>'Accounts', + 'MyLeadsDashlet'=>'Leads', + ); + + + + + +if (is_file('custom/modules/Home/dashlets.php')) include_once('custom/modules/Home/dashlets.php'); +?> \ No newline at end of file diff --git a/modules/Home/index.php b/modules/Home/index.php new file mode 100644 index 00000000..50d2fbbc --- /dev/null +++ b/modules/Home/index.php @@ -0,0 +1,307 @@ +buildCache(); +} +require_once($GLOBALS['sugar_config']['cache_dir'].'dashlets/dashlets.php'); + +require('modules/Home/dashlets.php'); + +$pages = $current_user->getPreference('pages', 'Home'); +$dashlets = $current_user->getPreference('dashlets', 'Home'); + +$defaultHomepage = false; +// BEGIN fill in with default homepage and dashlet selections + +$hasUserPreferences = (!isset($pages) || empty($pages) || !isset($dashlets) || empty($dashlets)) ? false : true; + +if(!$hasUserPreferences){ + $dashlets = array(); + + //list of preferences to move over and to where + $prefstomove = array( + 'mypbss_date_start' => 'MyPipelineBySalesStageDashlet', + 'mypbss_date_end' => 'MyPipelineBySalesStageDashlet', + 'mypbss_sales_stages' => 'MyPipelineBySalesStageDashlet', + 'mypbss_chart_type' => 'MyPipelineBySalesStageDashlet', + 'lsbo_lead_sources' => 'OppByLeadOutcomeDashlet', + 'lsbo_ids' => 'OppByLeadOutcomeDashlet', + 'pbls_lead_sources' => 'OppByLeadSourceDashlet', + 'pbls_ids' => 'OppByLeadSourceDashlet', + 'pbss_date_start' => 'PipelineBySalesStageDashlet', + 'pbss_date_end' => 'PipelineBySalesStageDashlet', + 'pbss_sales_stages' => 'PipelineBySalesStageDashlet', + 'pbss_chart_type' => 'PipelineBySalesStageDashlet', + 'obm_date_start' => 'OutcomeByMonthDashlet', + 'obm_date_end' => 'OutcomeByMonthDashlet', + 'obm_ids' => 'OutcomeByMonthDashlet'); + + //upgrading from pre-5.0 homepage + $old_columns = $current_user->getPreference('columns', 'home'); + $old_dashlets = $current_user->getPreference('dashlets', 'home'); + + if (isset($old_columns) && !empty($old_columns) && isset($old_dashlets) && !empty($old_dashlets)){ + $columns = $old_columns; + $dashlets = $old_dashlets; + + // resetting old columns and dashlets to have no preference and data + $old_columns = array(); + $old_dashlets = array(); + $current_user->setPreference('columns', $old_columns, 0, 'home'); + $current_user->setPreference('dashlets', $old_dashlets, 0, 'home'); + } + else{ + // This is here to get Sugar dashlets added above the rest + $dashlets[create_guid()] = array('className' => 'iFrameDashlet', + 'module' => 'Home', + 'forceColumn' => 0, + 'fileLocation' => $dashletsFiles['iFrameDashlet']['file'], + 'options' => array('title' => translate('LBL_DASHLET_DISCOVER_SUGAR_PRO','Home'), + 'url' => 'http://www.sugarcrm.com/crm/product/gopro', + 'height' => 315, + )); + + $dashlets[create_guid()] = array ('className' => 'SugarFeedDashlet', + 'module' => 'SugarFeed', + 'forceColumn' => 1, + 'fileLocation' => $dashletsFiles['SugarFeedDashlet']['file'], + ); + + $dashlets[create_guid()] = array('className' => 'iFrameDashlet', + 'module' => 'Home', + 'forceColumn' => 1, + 'fileLocation' => $dashletsFiles['iFrameDashlet']['file'], + 'options' => array('title' => translate('LBL_DASHLET_SUGAR_NEWS','Home'), + 'url' => 'http://www.sugarcrm.com/crm/product/news', + 'height' => 315, + )); + + foreach($defaultDashlets as $dashletName=>$module){ + // clint - fixes bug #20398 + // only display dashlets that are from visibile modules and that the user has permission to list + $myDashlet = new MySugar($module); + $displayDashlet = $myDashlet->checkDashletDisplay(); + if (isset($dashletsFiles[$dashletName]) && $displayDashlet){ + $options = array(); + $prefsforthisdashlet = array_keys($prefstomove,$dashletName); + foreach ( $prefsforthisdashlet as $pref ) { + $options[$pref] = $current_user->getPreference($pref); + } + $dashlets[create_guid()] = array('className' => $dashletName, + 'module' => $module, + 'forceColumn' => 0, + 'fileLocation' => $dashletsFiles[$dashletName]['file'], + 'options' => $options); + } + } + + $count = 0; + $columns = array(); + $columns[0] = array(); + $columns[0]['width'] = '60%'; + $columns[0]['dashlets'] = array(); + $columns[1] = array(); + $columns[1]['width'] = '40%'; + $columns[1]['dashlets'] = array(); + + foreach($dashlets as $guid=>$dashlet) { + if( $dashlet['forceColumn'] == 0 ) array_push($columns[0]['dashlets'], $guid); + else array_push($columns[1]['dashlets'], $guid); + $count++; + } + } + + + + + $current_user->setPreference('dashlets', $dashlets, 0, 'Home'); +} + +// handles upgrading from versions that had the 'Dashboard' module; move those items over to the Home page +$pagesDashboard = $current_user->getPreference('pages', 'Dashboard'); +$dashletsDashboard = $current_user->getPreference('dashlets', 'Dashboard'); +if ( !empty($pagesDashboard) ) { + // move dashlets from the dashboard to be at the end of the home screen dashlets + foreach ($pagesDashboard[0]['columns'] as $dashboardColumnKey => $dashboardColumn ) { + foreach ($dashboardColumn['dashlets'] as $dashletItem ) { + $pages[0]['columns'][$dashboardColumnKey]['dashlets'][] = $dashletItem; + } + } + $pages = array_merge($pages,$pagesDashboard); + $current_user->setPreference('pages', $pages, 0, 'Home'); +} +if ( !empty($dashletsDashboard) ) { + $dashlets = array_merge($dashlets,$dashletsDashboard); + $current_user->setPreference('dashlets', $dashlets, 0, 'Home'); +} +if ( !empty($pagesDashboard) || !empty($dashletsDashboard) ) + $current_user->resetPreferences('Dashboard'); + +if (empty($pages)){ + $pages = array(); + $pageIndex = 0; + $pages[0]['columns'] = $columns; + $pages[0]['numColumns'] = '2'; + $pages[0]['pageTitle'] = $mod_strings['LBL_HOME_PAGE_1_NAME']; // "My Sugar" + $pageIndex++; + $current_user->setPreference('pages', $pages, 0, 'Home'); + $activePage = 0; +} + +$sugar_smarty = new Sugar_Smarty(); + + $activePage = 0; + +$divPages[] = $activePage; + +$numCols = $pages[$activePage]['numColumns']; + + +$count = 0; +$dashletIds = array(); // collect ids to pass to javascript +$display = array(); + +foreach($pages[$activePage]['columns'] as $colNum => $column) { + if ($colNum == $numCols){ + break; + } + $display[$colNum]['width'] = $column['width']; + $display[$colNum]['dashlets'] = array(); + foreach($column['dashlets'] as $num => $id) { + // clint - fixes bug #20398 + // only display dashlets that are from visibile modules and that the user has permission to list + if(!empty($id) && isset($dashlets[$id]) && is_file($dashlets[$id]['fileLocation'])) { + $module = 'Home'; + if ( !empty($dashletsFiles[$dashlets[$id]['className']]['module']) ) + $module = $dashletsFiles[$dashlets[$id]['className']]['module']; + // Bug 24772 - Look into the user preference for the module the dashlet is a part of in case + // of the Report Chart dashlets. + elseif ( !empty($dashlets[$id]['module']) ) + $module = $dashlets[$id]['module']; + + $myDashlet = new MySugar($module); + + if($myDashlet->checkDashletDisplay()) { + require_once($dashlets[$id]['fileLocation']); + $dashlet = new $dashlets[$id]['className']($id, (isset($dashlets[$id]['options']) ? $dashlets[$id]['options'] : array())); + // Need to add support to dynamically display/hide dashlets + // If it has a method 'shouldDisplay' we will call it to see if we should display it or not + if (method_exists($dashlet,'shouldDisplay')) { + if (!$dashlet->shouldDisplay()) { + // This dashlet doesn't want us to show it, skip it. + continue; + } + } + + array_push($dashletIds, $id); + + $dashlets = $current_user->getPreference('dashlets', 'Home'); // Using hardcoded 'Home' because DynamicAction.php $_REQUEST['module'] value is always Home + $lvsParams = array(); + if(!empty($dashlets[$id]['sort_options'])){ + $lvsParams = $dashlets[$id]['sort_options']; + } + + $dashlet->process($lvsParams); + try { + $display[$colNum]['dashlets'][$id]['display'] = $dashlet->display(); + $display[$colNum]['dashlets'][$id]['displayHeader'] = $dashlet->getHeader(); + $display[$colNum]['dashlets'][$id]['displayFooter'] = $dashlet->getFooter(); + if($dashlet->hasScript) { + $display[$colNum]['dashlets'][$id]['script'] = $dashlet->displayScript(); + } + } catch (Exception $ex) { + $display[$colNum]['dashlets'][$id]['display'] = $ex->getMessage(); + $display[$colNum]['dashlets'][$id]['displayHeader'] = $dashlet->getHeader(); + $display[$colNum]['dashlets'][$id]['displayFooter'] = $dashlet->getFooter(); + } + } + } + } +} + + +if(!empty($sugar_config['lock_homepage']) && $sugar_config['lock_homepage'] == true) $sugar_smarty->assign('lock_homepage', true); + + +$sugar_smarty->assign('sugarVersion', $sugar_version); +$sugar_smarty->assign('sugarFlavor', $sugar_flavor); +$sugar_smarty->assign('currentLanguage', $GLOBALS['current_language']); +$sugar_smarty->assign('serverUniqueKey', $GLOBALS['server_unique_key']); +$sugar_smarty->assign('imagePath', $GLOBALS['image_path']); + +$sugar_smarty->assign('jsCustomVersion', $sugar_config['js_custom_version']); +$sugar_smarty->assign('maxCount', empty($sugar_config['max_dashlets_homepage']) ? 15 : $sugar_config['max_dashlets_homepage']); +$sugar_smarty->assign('dashletCount', $count); +$sugar_smarty->assign('dashletIds', '["' . implode('","', $dashletIds) . '"]'); +$sugar_smarty->assign('columns', $display); + +global $theme; +$sugar_smarty->assign('theme', $theme); + +$sugar_smarty->assign('divPages', $divPages); +$sugar_smarty->assign('activePage', $activePage); + +$sugar_smarty->assign('current_user', $current_user->id); + +$sugar_smarty->assign('lblAdd', $GLOBALS['app_strings']['LBL_ADD_BUTTON']); +$sugar_smarty->assign('lblAddDashlets', $GLOBALS['app_strings']['LBL_ADD_DASHLETS']); +$sugar_smarty->assign('lblLnkHelp', $GLOBALS['app_strings']['LNK_HELP']); + +$sugar_smarty->assign('mod', return_module_language($sugar_config['default_language'], 'Home')); +$sugar_smarty->assign('app', $GLOBALS['app_strings']); +$sugar_smarty->assign('module', 'Home'); +//custom chart code +require_once('include/SugarCharts/SugarChartFactory.php'); +$sugarChart = SugarChartFactory::getInstance(); +$resources = $sugarChart->getChartResources(); +$mySugarResources = $sugarChart->getMySugarChartResources(); +$sugar_smarty->assign('chartResources', $resources); +$sugar_smarty->assign('mySugarChartResources', $mySugarResources); +echo $sugar_smarty->fetch('include/MySugar/tpls/MySugar.tpl'); + +?> \ No newline at end of file diff --git a/modules/Home/language/en_us.lang.php b/modules/Home/language/en_us.lang.php new file mode 100644 index 00000000..b7ae106f --- /dev/null +++ b/modules/Home/language/en_us.lang.php @@ -0,0 +1,247 @@ + 'Home', + 'LBL_MODULES_TO_SEARCH' => 'Modules to Search', + 'LBL_NEW_FORM_TITLE' => 'New Contact', + 'LBL_FIRST_NAME' => 'First Name:', + 'LBL_LAST_NAME' => 'Last Name:', + 'LBL_LIST_LAST_NAME' => 'Last Name', + 'LBL_PHONE' => 'Phone:', + 'LBL_EMAIL_ADDRESS' => 'Email Address:', + 'LBL_MY_PIPELINE_FORM_TITLE' => 'My Pipeline', + 'LBL_PIPELINE_FORM_TITLE' => 'Pipeline By Sales Stage', + 'LBL_CAMPAIGN_ROI_FORM_TITLE' => 'Campaign ROI', + 'LBL_MY_CLOSED_OPPORTUNITIES_GAUGE' => 'My Closed Won Opportunities Gauge', + 'LNK_NEW_CONTACT' => 'Create Contact', + 'LNK_NEW_ACCOUNT' => 'Create Account', + 'LNK_NEW_OPPORTUNITY' => 'Create Opportunity', + 'LNK_NEW_LEAD' => 'Create Lead', + 'LNK_NEW_CASE' => 'Create Case', + 'LNK_NEW_NOTE' => 'Create Note or Attachment', + 'LNK_NEW_CALL' => 'Log Call', + 'LNK_NEW_EMAIL' => 'Archive Email', + 'LNK_COMPOSE_EMAIL' => 'Compose Email', + 'LNK_NEW_MEETING' => 'Schedule Meeting', + 'LNK_NEW_TASK' => 'Create Task', + 'LNK_NEW_BUG' => 'Report Bug', + 'LBL_ADD_BUSINESSCARD' => 'Enter Business Card', + 'ERR_ONE_CHAR' => 'Please enter at least one letter or number for your search ...', + 'LBL_OPEN_TASKS' => 'My Open Tasks', + 'LBL_SEARCH_RESULTS' => 'Search Results', + 'LBL_SEARCH_RESULTS_IN' => 'in', + 'LNK_NEW_SEND_EMAIL' => 'Compose Email', + 'LBL_NO_ACCESS' => 'You do not have access to this area. Contact your site administrator to obtain access', + 'LBL_NO_RESULTS_IN_MODULE' => '-- No Results --', + 'LBL_NO_RESULTS' => '

    There were no results found. Please search again.


    ', + 'LBL_NO_RESULTS_TIPS' => '

    Search Tips:

    • Make sure you have the proper categories selected above.
    • Broaden your search criteria.
    • If you still cannot find any results try the advanced search option.
    ', + + 'LBL_RELOAD_PAGE' => 'Please
    reload the window to use this Sugar Dashlet.', + 'LBL_ADD_DASHLETS' => 'Add Sugar Dashlets', + 'LBL_ADD_PAGE' => 'Add Page', + 'LBL_DEL_PAGE' => 'Delete Page', + 'LBL_WEBSITE_TITLE' => 'Website', + 'LBL_RSS_TITLE' => 'News Feed', + 'LBL_DELETE_PAGE' => 'Delete Page', + 'LBL_CHANGE_LAYOUT' => 'Change Layout', + 'LBL_RENAME_PAGE' => 'Rename Page', + 'LBL_CLOSE_DASHLETS' => 'Close', + 'LBL_CLOSE_SITEMAP' => 'Close', + 'LBL_OPTIONS' => 'Options', + // dashlet search fields + 'LBL_TODAY'=>'Today', + 'LBL_YESTERDAY' => 'Yesterday', + 'LBL_TOMORROW'=>'Tomorrow', + 'LBL_LAST_WEEK'=>'Last Week', + 'LBL_NEXT_WEEK'=>'Next Week', + 'LBL_LAST_7_DAYS'=>'Last 7 Days', + 'LBL_NEXT_7_DAYS'=>'Next 7 Days', + 'LBL_LAST_MONTH'=>'Last Month', + 'LBL_NEXT_MONTH'=>'Next Month', + 'LBL_LAST_QUARTER'=>'Last Quarter', + 'LBL_THIS_QUARTER'=>'This Quarter', + 'LBL_LAST_YEAR'=>'Last Year', + 'LBL_NEXT_YEAR'=>'Next Year', + 'LBL_LAST_30_DAYS' => 'Last 30 Days', + 'LBL_NEXT_30_DAYS' => 'Next 30 Days', + 'LBL_THIS_MONTH' => 'This Month', + 'LBL_THIS_YEAR' => 'This Year', + + 'LBL_MODULES' => 'Modules', + 'LBL_CHARTS' => 'Charts', + 'LBL_TOOLS' => 'Tools', + 'LBL_WEB' => 'Web', + 'LBL_SEARCH_RESULTS' => 'Search Result', + + // Dashlet Categories + 'dashlet_categories_dom' => array( + 'Module Views' => 'Module Views', + 'Portal' => 'Portal', + 'Charts' => 'Charts', + 'Tools' => 'Tools', + 'Miscellaneous' => 'Miscellaneous'), + 'LBL_MAX_DASHLETS_REACHED' => 'You have reached the maximum number of Sugar Dashlets your administrator has set. Please remove a Sugar Dashlet to add a new one.', + 'LBL_ADDING_DASHLET' => 'Adding Sugar Dashlet ...', + 'LBL_ADDED_DASHLET' => 'Sugar Dashlet Added', + 'LBL_REMOVE_DASHLET_CONFIRM' => 'Are you sure you want to remove the Sugar Dashlet?', + 'LBL_REMOVING_DASHLET' => 'Removing Sugar Dashlet ...', + 'LBL_REMOVED_DASHLET' => 'Sugar Dashlet Removed', + 'LBL_DASHLET_CONFIGURE_GENERAL' => 'General', + 'LBL_DASHLET_CONFIGURE_FILTERS' => 'Filters', + 'LBL_DASHLET_CONFIGURE_MY_ITEMS_ONLY' => 'Only My Items', + 'LBL_DASHLET_CONFIGURE_TITLE' => 'Title', + 'LBL_DASHLET_CONFIGURE_DISPLAY_ROWS' => 'Display Rows', + + 'LBL_DASHLET_DELETE' => 'Delete Sugar Dashlet', + 'LBL_DASHLET_REFRESH' => 'Refresh Sugar Dashlet', + 'LBL_DASHLET_EDIT' => 'Edit Sugar Dashlet', + + 'LBL_TRAINING_TITLE' => 'Training', + + 'LBL_CREATING_NEW_PAGE' => 'Creating New Page...', + 'LBL_NEW_PAGE_FEEDBACK' => 'You have created a new page. You can add new content with the Add Sugar Dashlets option.', + 'LBL_DELETE_PAGE_CONFIRM' => 'Are you sure you want to delete this page?', + 'LBL_SAVING_PAGE_TITLE' => 'Saving Page Title...', + 'LBL_RETRIEVING_PAGE' => 'Retrieving Page...', + + // Default out-of-box names for tabs + 'LBL_HOME_PAGE_1_NAME' => 'My Sugar', + 'LBL_HOME_PAGE_2_NAME' => 'Sales', + 'LBL_HOME_PAGE_3_NAME' => 'Support', + 'LBL_HOME_PAGE_6_NAME' => 'Marketing',//bug 16510, separate the support and marketing page from each other + 'LBL_HOME_PAGE_4_NAME' => 'Tracker', + 'LBL_CLOSE_SITEMAP' =>'Close', + + 'LBL_SEARCH' => 'Search', + 'LBL_CLEAR' => 'Clear', + + 'LBL_BASIC_CHARTS' => 'Basic Charts', + 'LBL_REPORT_CHARTS' => 'Report Charts', + + 'LBL_MY_FAVORITE_REPORT_CHARTS' => 'My Favorite Reports', + 'LBL_GLOBAL_REPORT_CHARTS' => 'Global Team Reports', + 'LBL_MY_TEAM_REPORT_CHARTS' => 'My Team Reports', + 'LBL_MY_SAVED_REPORT_CHARTS' => 'My Saved Reports', + + 'LBL_DASHLET_SEARCH' => 'Find Sugar Dashlet', + +//ABOUT page + 'LBL_VERSION' => 'Version', + 'LBL_BUILD' => 'Build', + + + 'LBL_VIEWLICENSE_COM' => '

    This program is free software; you can redistribute it and/or modify it under the terms of the GNU Affero General Public License version 3 as published by the Free Software Foundation, including the additional permission set forth in the source code header.

    ', + 'LBL_ADD_TERM_COM' => '

    The interactive user interfaces in modified source and object code versions of this program must display Appropriate Legal Notices, as required under Section 5 of the GNU Affero General Public License version 3. In accordance with Section 7(b) of the GNU General Public License version 3, these Appropriate Legal Notices must retain the display of the "Powered by SugarCRM" logo. If the display of the logo is not reasonably feasible for technical reasons, the Appropriate Legal Notices must display the words "Powered by SugarCRM".

    ', + + + 'LBL_SUGAR_COMMUNITY_EDITION' => 'Sugar Community Edition', + 'LBL_SUGAR_PROFESSIONAL' => "Sugar Professional", + 'LBL_SUGAR_ENTERPRISE' => "Sugar Enterprise", + 'LBL_AND' => "and", + 'LBL_ARE' => "are", + 'LBL_TRADEMARKS' => 'trademarks', + 'LBL_OF' => 'of', + 'LBL_FOUNDERS' => 'Founders', + 'LBL_JOIN_SUGAR_COMMUNITY' => 'Join the Sugar Community', + 'LBL_DETAILS_SUGARFORGE' => 'Collaborate and develop Sugar extensions', + 'LBL_DETAILS_SUGAREXCHANGE' => 'Buy and sell certified Sugar extensions', + 'LBL_TRAINING' => 'Training', + 'LBL_DETAILS_TRAINING' => 'Learn about Sugar using online and interactive learning content', + 'LBL_FORUMS' => 'Forums', + 'LBL_DETAILS_FORUMS' => 'Discuss Sugar with expert community users and developers', + 'LBL_WIKI' => 'Wiki', + 'LBL_DETAILS_WIKI' => 'Search the knowledge base of user and developer topics', + 'LBL_DEVSITE' => 'Developer Site', + 'LBL_DETAILS_DEVSITE' => 'Discover resources, tutorials, and helpful links to get you up to speed on Sugar development', + 'LBL_GET_SUGARCRM_RSS' => 'Get SugarCRM RSS', + 'LBL_SUGARCRM_NEWS' => 'SugarCRM News', + 'LBL_SUGARCRM_TRAINING_NEWS' => 'SugarCRM Training News', + 'LBL_SUGARCRM_FORUMS' => 'SugarCRM Forums', + 'LBL_SUGARFORGE_NEWS' => 'SugarForge News', + 'LBL_ALL_NEWS' => 'All News', + 'LBL_LINK_CURRENT_CONTRIBUTORS' => 'Click this link for a current list of Sugar contributors!', + 'LBL_SOURCE_CODE' => 'Source Code', + 'LBL_SOURCE_SUGAR' => 'Sugar - The world\'s most popular sales force automation application created by SugarCRM Inc.', + 'LBL_SOURCE_XTEMPLATE' => 'XTemplate - A template engine for PHP created by Barnabás Debreceni', + 'LBL_SOURCE_NUSOAP' => 'NuSOAP - A set of PHP classes that allow developers to create and consume web services created by NuSphere Corporation and Dietrich Ayala', + 'LBL_SOURCE_JSCALENDAR' => 'JS Calendar - A calendar for entering dates created by Mihai Bazon', + 'LBL_SOURCE_PHPPDF' => 'PHP PDF - A library for creating PDF documents created by Wayne Munro', + 'LBL_SOURCE_JSONPHP' => 'JSON.php - A PHP script to convert to and from JSON data format by Michal Migurski.', + 'LBL_SOURCE_JSON' => 'JSON.js - A JSON parser and JSON stringifier in JavaScript.', + 'LBL_SOURCE_HTTP_WEBDAV_SERVER' => 'HTTP_WebDAV_Server - A WebDAV Server Implementation in PHP.', + 'LBL_SOURCE_JS_O_LAIT' => 'JavaScript O Lait - A library of reusable modules and components to enhance JavaScript by Jan-Klaas Kollhof.', + 'LBL_SOURCE_PCLZIP' => 'PclZip - library offers compression and extraction functions for Zip formatted archives by Vincent Blavet', + 'LBL_SOURCE_SMARTY' => 'Smarty - A template engine for PHP.', + 'LBL_SOURCE_OVERLIBMWS' => 'Overlibmws - JavaScript library for client-side windowing.', + 'LBL_SOURCE_YAHOO_UI_LIB' => 'Yahoo! User Interface Library - The UI Library Utilities facilitate the implementation of rich client-side features.', + 'LBL_SOURCE_PHPMAILER' => 'PHPMailer - A full featured email transfer class for PHP', + 'LBL_SOURCE_CRYPT_BLOWFISH' => 'Crypt_Blowfish - Allows for quick two-way blowfish encryption without requiring the MCrypt PHP extension.', + 'LBL_SOURCE_HTML_SAFE' => 'HTML_Safe - A parser that strips down all potentially dangerous content within HTML', + 'LBL_SOURCE_XML_HTMLSAX3' => 'XML_HTMLSax3 - A SAX parser for HTML and other badly formed XML documents', + 'LBL_SOURCE_YAHOO_UI_LIB_EXT' => 'Yahoo! UI Extensions Library - Extensions to the Yahoo! User Interface Library by Jack Slocum', + 'LBL_SOURCE_JSMIN' => 'JSMin - filter which removes comments and unnecessary whitespace from JavaScript files.', + 'LBL_SOURCE_SWFOBJECT' => 'SWFObject - Javascript Flash Player detection and embed script.', + 'LBL_SOURCE_TINYMCE' => 'TinyMCE - A WYSIWYG editor control for web browsers that enables the user to edit HTML contents', + 'LBL_SOURCE_EXT' => 'Ext - A client-side JavaScript framework for building web applications.', + 'LBL_SOURCE_RECAPTCHA' => 'reCAPTCHA - A free CAPTCHA service that helps to digitize books, newspapers and old time radio shows.', + 'LBL_SOURCE_TCPDF' => 'TCPDF - A PHP class for generating PDF documents.', + 'LBL_SOURCE_CSSMIN' => 'CssMin - A css parser and minifier.', + 'LBL_SOURCE_PHPSAML' => 'PHP-SAML - A simple SAML toolkit for PHP.', + 'LBL_SOURCE_ISCROLL' => 'iScroll - The overflow:scroll for mobile webkit. Native scrolling inside a fixed width/height element.', + 'LBL_SOURCE_FLASHCANVAS' => 'FlashCanvas - FlashCanvas is a JavaScript library which adds the HTML5 Canvas support to Internet Explorer. It renders shapes and images via Flash drawing API. It supports almost all Canvas APIs and, in many cases, runs faster than other similar libraries which use VML or Silverlight.', + 'LBL_SOURCE_JIT' => 'JavaScript InfoVis Toolkit - The JavaScript InfoVis Toolkit provides tools for creating Interactive Data Visualizations for the Web.', + + + 'LBL_DASHLET_TITLE' => 'My Sites', + 'LBL_DASHLET_OPT_TITLE' => 'Title', + 'LBL_DASHLET_OPT_URL' => 'Website Location', + 'LBL_DASHLET_OPT_HEIGHT' => 'Dashlet Height (in pixels)', + 'LBL_DASHLET_SUGAR_NEWS' => 'Sugar News', + 'LBL_DASHLET_DISCOVER_SUGAR_PRO' => 'Discover Sugar', +); + + +?> diff --git a/modules/Home/quicksearchQuery.php b/modules/Home/quicksearchQuery.php new file mode 100644 index 00000000..f22d08e5 --- /dev/null +++ b/modules/Home/quicksearchQuery.php @@ -0,0 +1,342 @@ +getTableName(); + if (! empty($table)) { + $table .= "."; + } + $cond_arr = array(); + + if (!is_array($query_obj['conditions'])) { + $query_obj['conditions'] = array(); + } + + foreach($query_obj['conditions'] as $condition) { + if($condition['op'] == 'contains') { + array_push($cond_arr,$GLOBALS['db']->quote($table.$condition['name'])." like '%".$GLOBALS['db']->quote($condition['value'])."%'"); + } else if($condition['op'] == 'like_custom') { + $like = ''; + if(!empty($condition['begin'])) $like .= $GLOBALS['db']->quote($condition['begin']); + $like .= $GLOBALS['db']->quote($condition['value']); + if(!empty($condition['end'])) $like .= $GLOBALS['db']->quote($condition['end']); + + if ($focus instanceof Person){ + $nameFormat = $GLOBALS['locale']->getLocaleFormatMacro($GLOBALS['current_user']); + if ( strpos($nameFormat,'l') > strpos($nameFormat,'f') ) { + array_push($cond_arr,db_concat(rtrim($table,'.'),array('first_name','last_name')) . " like '$like'"); + } + else { + array_push($cond_arr,db_concat(rtrim($table,'.'),array('last_name','first_name')) . " like '$like'"); + } + } + else { + array_push($cond_arr,$GLOBALS['db']->quote($table.$condition['name'])." like '$like'"); + } + } else { // starts_with + array_push($cond_arr,$GLOBALS['db']->quote($table.$condition['name'])." like '".$GLOBALS['db']->quote($condition['value'])."%'"); + } + } + + $whereClause = '('.implode(" {$query_obj['group']} ",$cond_arr).')'; + + if($table == 'users.') + $whereClause .= " AND {$table}status='Active'"; + + // Need to include the default whereStatement + if(!empty($query_obj['whereExtra'])){ + if(!empty($whereClause))$whereClause .= ' AND '; + $whereClause .= html_entity_decode($query_obj['whereExtra'],ENT_QUOTES); + } + + return $whereClause; + } + + /** + * Query a module for a list of items + * + * @param array $args + * example for querying Account module with 'a': + * array ('modules' => array('Accounts'), // module to use + * 'field_list' => array('name', 'id'), // fields to select + * 'group' => 'or', // how the conditions should be combined + * 'conditions' => array(array( // array of where conditions to use + * 'name' => 'name', // field + * 'op' => 'like_custom', // operation + * 'end' => '%', // end of the query + * 'value' => 'a', // query value + * ) + * ), + * 'order' => 'name', // order by + * 'limit' => '30', // limit, number of records to return + * ) + * @return array list of elements returned + */ + function query($args) { + $json = getJSONobj(); + global $sugar_config; + global $beanFiles, $beanList; + + if($sugar_config['list_max_entries_per_page'] < ($args['limit'] + 1)) // override query limits + $sugar_config['list_max_entries_per_page'] = ($args['limit'] + 1); + + $list_return = array(); + + foreach($args['modules'] as $module) { + require_once($beanFiles[$beanList[$module]]); + $focus = new $beanList[$module]; + + $query_orderby = ''; + if (!empty($args['order'])) { + $query_orderby = $args['order']; + if ($focus instanceof Person && $args['order'] == 'name') { + $query_orderby = 'last_name'; + } + } + $query_limit = ''; + if (!empty($args['limit'])) { + $query_limit = $args['limit']; + } + + $query_where = $this->constructWhere($args, $focus); + + $list_arr = array(); + if($focus->ACLAccess('ListView', true)) + { + $curlist = $focus->get_list($query_orderby, $query_where, 0, $query_limit, -1, 0); + $list_return = array_merge($list_return,$curlist['list']); + } + } + $list_arr = $this->formatResults($args, $list_return); + return $json->encodeReal($list_arr); + } + + protected function formatResults($args, $list_return){ + global $sugar_config; + $app_list_strings = null; + $list_arr['totalCount']=count($list_return); + $list_arr['fields']= array(); + for($i = 0; $i < count($list_return); $i++) { + $list_arr['fields'][$i]= array(); + $list_arr['fields'][$i]['module']= $list_return[$i]->object_name; + $listData = $list_return[$i]->get_list_view_data(); + + foreach($args['field_list'] as $field) { + // handle enums + if( (isset($list_return[$i]->field_name_map[$field]['type']) && $list_return[$i]->field_name_map[$field]['type'] == 'enum') || + (isset($list_return[$i]->field_name_map[$field]['custom_type']) && $list_return[$i]->field_name_map[$field]['custom_type'] == 'enum')) { + + // get fields to match enum vals + if(empty($app_list_strings)) { + if(isset($_SESSION['authenticated_user_language']) && $_SESSION['authenticated_user_language'] != '') $current_language = $_SESSION['authenticated_user_language']; + else $current_language = $sugar_config['default_language']; + $app_list_strings = return_app_list_strings_language($current_language); + } + + // match enum vals to text vals in language pack for return + if(!empty($app_list_strings[$list_return[$i]->field_name_map[$field]['options']])) { + $list_return[$i]->$field = $app_list_strings[$list_return[$i]->field_name_map[$field]['options']][$list_return[$i]->$field]; + } + } + + + if (isset($listData[$field])) + { + $list_arr['fields'][$i][$field] = $listData[$field]; + } + else if (isset($list_return[$i]->$field)) + { + $list_arr['fields'][$i][$field] = $list_return[$i]->$field; + } + else { + $list_arr['fields'][$i][$field] = ""; + } + } + } + if(is_array($list_arr['fields'])) { + foreach ( $list_arr['fields'] as $i => $recordIn ) { + if(!is_array($recordIn)){ + continue; + } + foreach( $recordIn as $col => $dataIn ) { + if ( !is_scalar($dataIn) ) { + continue; + } + $list_arr['fields'][$i][$col] = html_entity_decode($dataIn,ENT_QUOTES,'UTF-8'); + } + } + } + return $list_arr; + } + + /** + * get_contact_array + * + */ + function get_contact_array($args) { + $json = getJSONobj(); + global $sugar_config, $beanFiles, $beanList, $locale; + + if($sugar_config['list_max_entries_per_page'] < ($args['limit'] + 1)) // override query limits + $sugar_config['list_max_entries_per_page'] = ($args['limit'] + 1); + + $list_return = array(); + + foreach($args['modules'] as $module) { + require_once($beanFiles[$beanList[$module]]); + $focus = new $beanList[$module]; + + $query_orderby = ''; + if (!empty($args['order'])) { + $query_orderby = $args['order']; + } + $query_limit = ''; + if (!empty($args['limit'])) { + $query_limit = $args['limit']; + } + $query_where = $this->constructWhere($args, $focus); + $list_arr = array(); + if($focus->ACLAccess('ListView', true)) { + $curlist = $focus->get_list($query_orderby, $query_where, 0, $query_limit, -1, 0); + $list_return = array_merge($list_return,$curlist['list']); + } + } + $list_arr['totalCount']=count($list_return); + $list_arr['fields']= array(); + for($i = 0; $i < count($list_return); $i++) { + $list_arr['fields'][$i]= array(); + $list_arr['fields'][$i]['module']= $list_return[$i]->object_name; + $contactName = ""; + foreach($args['field_list'] as $field) { + // We are overriding the contact_id param and the reports_to_id param to change to 'id' + if(preg_match('/reports_to_id$/s',$field) || preg_match('/contact_id$/s',$field)) { // We are overriding the reports_to_id param to change to 'id' + $list_arr['fields'][$i][$field] = $list_return[$i]->id; + } + else { + $list_arr['fields'][$i][$field] = $list_return[$i]->$field; + } + } //foreach + + $contactName = $locale->getLocaleFormattedName($list_arr['fields'][$i]['first_name'], + $list_arr['fields'][$i]['last_name'], + $list_arr['fields'][$i]['salutation']); + + $list_arr['fields'][$i][$args['field_list'][0]] = $contactName; + } //for + + $str = $json->encodeReal($list_arr); + return $str; + } + + /** + * Returns the list of users, faster than using query method for Users module + * + * @param array $args arguments used to construct query, see query() for example + * + * @return array list of users returned + */ + function get_user_array($args) { + global $json; + $json = getJSONobj(); + + $response = array(); + + if(showFullName()) { // utils.php, if system is configured to show full name + $user_array = getUserArrayFromFullName($args['conditions'][0]['value'], true); + } else { + $user_array = get_user_array(false, "Active", '', false, $args['conditions'][0]['value'],' AND portal_only=0 ',false); + } + $response['totalCount']=count($user_array); + $response['fields']=array(); + $i=0; + foreach($user_array as $id=>$name) { + array_push($response['fields'], array('id' => (string) $id, 'user_name' => $name, 'module' => 'Users')); + $i++; + } + + return $json->encodeReal($response); + } + + + function externalApi($data) { + require_once('include/externalAPI/ExternalAPIFactory.php'); + + $api = ExternalAPIFactory::loadAPI($data['api']); + + $json = getJSONobj(); + + $listArray['fields'] = $api->searchDoc($_REQUEST['query']); + $listArray['totalCount'] = count($listArray['fields']); + + $listJson = $json->encodeReal($listArray); + + return $listJson; + } +} + +$json = getJSONobj(); +$data = $json->decode(html_entity_decode($_REQUEST['data'])); +if(isset($_REQUEST['query']) && !empty($_REQUEST['query'])){ + foreach($data['conditions'] as $k=>$v){ + if(empty($data['conditions'][$k]['value'])){ + $data['conditions'][$k]['value']=$_REQUEST['query']; + } + } +} + +$quicksearchQuery = new quicksearchQuery(); + +$method = !empty($data['method']) ? $data['method'] : 'query'; +if(method_exists($quicksearchQuery, $method)) { + echo $quicksearchQuery->$method($data); +} + +?> \ No newline at end of file diff --git a/modules/Home/sitemap.php b/modules/Home/sitemap.php new file mode 100644 index 00000000..c7ac88ea --- /dev/null +++ b/modules/Home/sitemap.php @@ -0,0 +1,151 @@ +assign('CLOSE', isset($mod_strings['LBL_CLOSE_SITEMAP']) ? $mod_strings['LBL_CLOSE_SITEMAP'] : ''); + +// get the list_strings in order for module friendly name display. +$app_list_strings = return_app_list_strings_language($current_language); + +foreach ($sm as $mod_dir_name => $links) +{ + $module_friendly_name = $app_list_strings['moduleList'][$mod_dir_name]; + $temphtml = ""; + $temphtml .= '

    ' . $module_friendly_name .'

      '; + + foreach ($links as $name => $href) + { + $temphtml .= '
    • ' . $name . ' ' . '
    • '; + } + + $temphtml .= '
    '; + $sm_smarty->assign(strtoupper($mod_dir_name), $temphtml); +} + +// Specify the sitemap template to use; allow developers to override this with a custom one to add/remove modules +// from the list +$tpl = 'modules/Home/sitemap.tpl'; +if ( sugar_is_file('custom/modules/Home/sitemap.tpl') ) { + $tpl = 'custom/modules/Home/sitemap.tpl'; +} +echo $sm_smarty->fetch($tpl); + +function sm_build_array() +{ + //if the sitemap array is already stored, then pass it back + if (isset($_SESSION['SM_ARRAY']) && !empty($_SESSION['SM_ARRAY'])){ + return $_SESSION['SM_ARRAY']; + } + + + include("include/modules.php"); + global $sugar_config,$mod_strings; + + + // Need to set up mod_strings when we iterate through module menus. + $orig_modstrings = array(); + if(!empty($mod_strings)) + { + $orig_modstrings = $mod_strings; + } + if(isset($_SESSION['authenticated_user_language']) && $_SESSION['authenticated_user_language'] != '') + { + $current_language = $_SESSION['authenticated_user_language']; + } + else + { + $current_language = $sugar_config['default_language']; + } + $exclude= array(); // in case you want to exclude any. + $mstr_array = array(); + + global $modListHeader; + if(!isset($modListHeader)) + { + global $current_user; + if(isset($current_user)) + { + $modListHeader = query_module_access_list($current_user); + } + } + + foreach($modListHeader as $key=>$val) + { + if(!empty($exclusion_array) && in_array($val,$exclude )) + { + continue; + } + else + { + if (file_exists('modules/'.$val.'/Menu.php')) + { + $mod_strings = return_module_language($current_language, $val); + $module_menu = array(); + include('modules/'.$val.'/Menu.php'); + + $tmp_menu_items = array(); + foreach($module_menu as $menu) + { + if(isset($menu[0]) && !empty($menu[0]) && isset($menu[1]) && !empty($menu[1]) && trim($menu[0]) !='#') + { + $tmp_menu_items[$menu[1]] =$menu[0]; + } + } + $mstr_array[$val] = $tmp_menu_items; + } + } + } + + //reset the modstrings to current module + $mod_strings = $orig_modstrings ; + //store master array into session variable + $_SESSION['SM_ARRAY'] = $mstr_array; + return $mstr_array; +} diff --git a/modules/Home/sitemap.tpl b/modules/Home/sitemap.tpl new file mode 100644 index 00000000..4ec06ac1 --- /dev/null +++ b/modules/Home/sitemap.tpl @@ -0,0 +1,80 @@ +{* + +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + + + +*} + + +
    + + + + + + + + + + + + + + +
    + +
    +
    {$ACTIVITIES}
    +
    {$EMAILS}
    +
    +
    {$CONTACTS}
    +
    {$ACCOUNTS}
    +
    {$LEADS}
    +
    {$OPPORTUNITIES}
    +
    +
    {$PROJECT}
    +
    {$CASES}
    +
    {$BUGS}
    +
    {$DOCUMENTS}
    +
    +
    {$CAMPAIGNS}
    +
    {$QUOTES}
    +
    {$REPORTS}
    +
    +
    + \ No newline at end of file diff --git a/modules/Home/views/view.additionaldetailsretrieve.php b/modules/Home/views/view.additionaldetailsretrieve.php new file mode 100644 index 00000000..24614412 --- /dev/null +++ b/modules/Home/views/view.additionaldetailsretrieve.php @@ -0,0 +1,98 @@ +getAdditionalDetailsMetadataFile($moduleDir); + + if(empty($beanFiles[$beanName]) || + empty($id) || !is_file($additionalDetailsFile) ) { + echo 'bad data'; + die(); + } + + require_once($beanFiles[$beanName]); + require_once($additionalDetailsFile); + $adFunction = 'additionalDetails' . $beanName; + + if(function_exists($adFunction)) { // does the additional details function exist + $json = getJSONobj(); + $bean = new $beanName(); + $bean->retrieve($id); + $arr = array_change_key_case($bean->toArray(), CASE_UPPER); + + $results = $adFunction($arr); + $retArray['body'] = str_replace(array("\rn", "\r", "\n"), array('','','
    '), $results['string']); + if(!$bean->ACLAccess('EditView')) $results['editLink'] = ''; + + $retArray['caption'] = "
    {$app_strings['LBL_ADDITIONAL_DETAILS']}
    "; + $retArray['caption'] .= ""; + $retArray['width'] = (empty($results['width']) ? '300' : $results['width']); + echo 'result = ' . $json->encode($retArray); + } + } + + protected function getAdditionalDetailsMetadataFile( + $moduleName + ) + { + $additionalDetailsFile = 'modules/' . $moduleName . '/metadata/additionalDetails.php'; + if (file_exists('custom/'.$additionalDetailsFile)) { + $additionalDetailsFile = 'custom/'.$additionalDetailsFile; + } + + return $additionalDetailsFile; + } +} \ No newline at end of file diff --git a/modules/Home/views/view.list.php b/modules/Home/views/view.list.php new file mode 100644 index 00000000..984aaf57 --- /dev/null +++ b/modules/Home/views/view.list.php @@ -0,0 +1,52 @@ + diff --git a/modules/Home/views/view.modulelistmenu.php b/modules/Home/views/view.modulelistmenu.php new file mode 100644 index 00000000..91d21578 --- /dev/null +++ b/modules/Home/views/view.modulelistmenu.php @@ -0,0 +1,55 @@ +get_recently_viewed($GLOBALS['current_user']->id); + + foreach ( $history as $key => $row ) { + $history[$key]['item_summary_short'] = getTrackerSubstring($row['item_summary']); + $history[$key]['image'] = SugarThemeRegistry::current()->getImage($row['module_name'],'border="0" align="absmiddle" alt="'.$row['item_summary'].'"'); + } + $this->ss->assign('LAST_VIEWED',$history); + + $this->ss->display('include/MVC/View/tpls/modulelistmenu.tpl'); + } +} +?> diff --git a/modules/Import/Forms.php b/modules/Import/Forms.php new file mode 100644 index 00000000..101c185b --- /dev/null +++ b/modules/Import/Forms.php @@ -0,0 +1,190 @@ +getFieldDefinition($fieldname); + } + + // if this is the id relation field, then don't have a pop-up selector. + if( $vardef['type'] == 'relate' && $vardef['id_name'] == $vardef['name']) { + $vardef['type'] = 'varchar'; + } + + // create the dropdowns for the parent type fields + if ( $vardef['type'] == 'parent_type' ) { + $vardef['type'] = 'enum'; + } + + // remove the special text entry field function 'getEmailAddressWidget' + if ( isset($vardef['function']) + && ( $vardef['function'] == 'getEmailAddressWidget' + || $vardef['function']['name'] == 'getEmailAddressWidget' ) ) + unset($vardef['function']); + + // load SugarFieldHandler to render the field tpl file + static $sfh; + + if(!isset($sfh)) { + require_once('include/SugarFields/SugarFieldHandler.php'); + $sfh = new SugarFieldHandler(); + } + + $displayParams = array(); + $displayParams['formName'] = 'importstep3'; + + $contents = $sfh->displaySmarty('fields', $vardef, 'ImportView', $displayParams); + + // Remove all the copyright comments + $contents = preg_replace('/\{\*[^\}]*?\*\}/', '', $contents); + + // hack to disable one of the js calls in this control + if ( isset($vardef['function']) + && ( $vardef['function'] == 'getCurrencyDropDown' + || $vardef['function']['name'] == 'getCurrencyDropDown' ) ) + $contents .= "{literal}{/literal}"; + + // Save it to the cache file + if($fh = @sugar_fopen($file, 'w')) { + fputs($fh, $contents); + fclose($fh); + } + } + + // Now render the template we received + $ss = new Sugar_Smarty(); + + // Create Smarty variables for the Calendar picker widget + global $timedate; + $time_format = $timedate->get_user_time_format(); + $date_format = $timedate->get_cal_date_format(); + $ss->assign('USER_DATEFORMAT', $timedate->get_user_date_format()); + $ss->assign('TIME_FORMAT', $time_format); + $time_separator = ":"; + $match = array(); + if(preg_match('/\d+([^\d])\d+([^\d]*)/s', $time_format, $match)) { + $time_separator = $match[1]; + } + $t23 = strpos($time_format, '23') !== false ? '%H' : '%I'; + if(!isset($match[2]) || $match[2] == '') { + $ss->assign('CALENDAR_FORMAT', $date_format . ' ' . $t23 . $time_separator . "%M"); + } + else { + $pm = $match[2] == "pm" ? "%P" : "%p"; + $ss->assign('CALENDAR_FORMAT', $date_format . ' ' . $t23 . $time_separator . "%M" . $pm); + } + + // populate the fieldlist from the vardefs + $fieldlist = array(); + if ( !isset($focus) || !($focus instanceof SugarBean) ) + $focus = loadBean($module); + // create the dropdowns for the parent type fields + if ( $vardef['type'] == 'parent_type' ) { + $focus->field_defs[$vardef['name']]['options'] = $focus->field_defs[$vardef['group']]['options']; + } + $vardefFields = $focus->getFieldDefinitions(); + foreach ( $vardefFields as $name => $properties ) { + $fieldlist[$name] = $properties; + // fill in enums + if(isset($fieldlist[$name]['options']) && is_string($fieldlist[$name]['options']) && isset($app_list_strings[$fieldlist[$name]['options']])) + $fieldlist[$name]['options'] = $app_list_strings[$fieldlist[$name]['options']]; + // Bug 32626: fall back on checking the mod_strings if not in the app_list_strings + elseif(isset($fieldlist[$name]['options']) && is_string($fieldlist[$name]['options']) && isset($mod_strings[$fieldlist[$name]['options']])) + $fieldlist[$name]['options'] = $mod_strings[$fieldlist[$name]['options']]; + // Bug 22730: make sure all enums have the ability to select blank as the default value. + if(!isset($fieldlist[$name]['options'][''])) + $fieldlist[$name]['options'][''] = ''; + } + // fill in function return values + if ( !in_array($fieldname,array('email1','email2')) ) { + if (!empty($fieldlist[$fieldname]['function']['returns']) && $fieldlist[$fieldname]['function']['returns'] == 'html'){ + $function = $fieldlist[$fieldname]['function']['name']; + // include various functions required in the various vardefs + if ( isset($fieldlist[$fieldname]['function']['include']) && is_file($fieldlist[$fieldname]['function']['include'])) + require_once($fieldlist[$fieldname]['function']['include']); + $value = $function($focus, $fieldname, $value, 'EditView'); + // Bug 22730 - add a hack for the currency type dropdown, since it's built by a function. + if ( preg_match('/getCurrency.*DropDown/s',$function) ) + $value = str_ireplace('','',$value); + } + } + $fieldlist[$fieldname]['value'] = $value; + $ss->assign("fields",$fieldlist); + $ss->assign("form_name",'importstep3'); + $ss->assign("bean",$focus); + + // add in any additional strings + $ss->assign("MOD", $mod_strings); + $ss->assign("APP", $app_strings); + return $ss->fetch($file); +} diff --git a/modules/Import/ImportCacheFiles.php b/modules/Import/ImportCacheFiles.php new file mode 100644 index 00000000..71b38f8f --- /dev/null +++ b/modules/Import/ImportCacheFiles.php @@ -0,0 +1,125 @@ +id}.csv"; + } + + /** + * Returns the duplicates filename + * + * @return string filename + */ + public static function getDuplicateFileName() + { + return self::_createFileName("dupes"); + } + + /** + * Returns the error filename + * + * @return string filename + */ + public static function getErrorFileName() + { + return self::_createFileName("error"); + } + + /** + * Returns the error records filename + * + * @return string filename + */ + public static function getErrorRecordsFileName() + { + return self::_createFileName("errorrecords"); + } + + /** + * Returns the status filename + * + * @return string filename + */ + public static function getStatusFileName() + { + return self::_createFileName("status"); + } + + /** + * Clears out all cache files in the $sugar_config['import_dir'] directory + */ + public static function clearCacheFiles() + { + global $sugar_config; + + if ( is_dir($sugar_config['import_dir']) ) { + $files = dir($sugar_config['import_dir']); + while (false !== ($file = $files->read())) { + if ( !is_dir($file) && stristr($file,'.csv') ) + unlink($sugar_config['import_dir'].$file); + } + } + } +} diff --git a/modules/Import/ImportDuplicateCheck.php b/modules/Import/ImportDuplicateCheck.php new file mode 100644 index 00000000..6e50b167 --- /dev/null +++ b/modules/Import/ImportDuplicateCheck.php @@ -0,0 +1,179 @@ +_focus = &$focus; + } + + /** + * Returns an array of indices for the current module + * + * @return array + */ + private function _getIndexVardefs() + { + $indexes = $this->_focus->getIndices(); + + if ( $this->_focus->getFieldDefinition('email1') ) + $indexes[] = array( + 'name' => 'special_idx_email1', + 'type' => 'index', + 'fields' => array('email1') + ); + if ( $this->_focus->getFieldDefinition('email2') ) + $indexes[] = array( + 'name' => 'special_idx_email2', + 'type' => 'index', + 'fields' => array('email2') + ); + + return $indexes; + } + + /** + * Returns an array with an element for each index + * + * @return array + */ + public function getDuplicateCheckIndexes() + { + $super_language_pack = sugarArrayMerge( + return_module_language($GLOBALS['current_language'], $this->_focus->module_dir), + $GLOBALS['app_strings'] + ); + + $index_array = array(); + foreach ($this->_getIndexVardefs() as $index){ + if ($index['type'] == "index"){ + $labelsArray = array(); + foreach ($index['fields'] as $field){ + if ($field == 'deleted') continue; + $fieldDef = $this->_focus->getFieldDefinition($field); + if ( isset($fieldDef['vname']) && isset($super_language_pack[$fieldDef['vname']]) ) + $labelsArray[$fieldDef['name']] = $super_language_pack[$fieldDef['vname']]; + else + $labelsArray[$fieldDef['name']] = $fieldDef['name']; + } + $index_array[$index['name']] = str_replace(":", "",implode(", ",$labelsArray)); + } + } + + return $index_array; + } + + /** + * Checks to see if the given bean is a duplicate based off the given indexes + * + * @param array $indexlist + * @return bool true if this bean is a duplicate or false if it isn't + */ + public function isADuplicateRecord( + $indexlist + ) + { + // loop through var def indexes and compare with selected indexes + foreach ( $this->_getIndexVardefs() as $index ) { + // if we get an index not in the indexlist, loop + if ( !in_array($index['name'],$indexlist) ) + continue; + + // This handles the special case of duplicate email checking + if ( $index['name'] == 'special_idx_email1' || $index['name'] == 'special_idx_email2' ) { + $emailAddress = new SugarEmailAddress(); + $email = $index['fields'][0]; + if ( $emailAddress->getCountEmailAddressByBean( + $this->_focus->$email, + $this->_focus, + ($index['name'] == 'special_idx_email1') + ) > 0 ) + return true; + } + // Adds a hook so you can define a method in the bean to handle dupe checking + elseif ( isset($index['dupeCheckFunction']) ) { + $functionName = substr_replace($index['dupeCheckFunction'],'',0,9); + if ( method_exists($this->_focus,$functionName) ) + return $this->_focus->$functionName($index); + } + else { + $index_fields = array('deleted' => '0'); + foreach($index['fields'] as $field){ + if ($field == 'deleted') + continue; + if (!in_array($field,$index_fields)) + if (strlen($this->_focus->$field) > 0) + $index_fields[$field] = $this->_focus->$field; + } + + // if there are no valid fields in the index field list, loop + if ( count($index_fields) <= 1 ) + continue; + + $newfocus = loadBean($this->_focus->module_dir); + $result = $newfocus->retrieve_by_string_fields($index_fields,true); + + if ( !is_null($result) ) + return true; + } + } + return false; + } +} + +?> diff --git a/modules/Import/ImportFieldSanitize.php b/modules/Import/ImportFieldSanitize.php new file mode 100644 index 00000000..0b8a51d7 --- /dev/null +++ b/modules/Import/ImportFieldSanitize.php @@ -0,0 +1,304 @@ +addRelatedBean = true; + else + $this->addRelatedBean = false; + + $field = $sfh->getSugarField(ucfirst($name)); + if ( $field instanceOf SugarFieldBase ) { + $value = $field->importSanitize($value,$vardef,$focus,$this); + } + + return $value; + } + + /** + * Validate date fields + * + * @param $value string + * @param $vardef array + * @param $focus object bean of the module we're importing into + * @return string sanitized and validated value on success, bool false on failure + */ + public function date( + $value, + $vardef, + &$focus + ) + { + global $timedate; + + $format = $this->dateformat; + + if ( !$timedate->check_matching_format($value, $format) ) + return false; + + if ( !$this->isValidTimeDate($value, $format) ) + return false; + + $value = $timedate->swap_formats( + $value, $format, $timedate->get_date_format()); + + return $value; + } + + /** + * Validate email fields + * + * @param $value string + * @param $vardef array + * @param $focus object bean of the module we're importing into + * @return string sanitized and validated value on success, bool false on failure + */ + public function email( + $value, + $vardef + ) + { + if ( !empty($value) && !preg_match('/^\w+(?:[\'.\-+]\w+)*@\w+(?:[.\-]\w+)*(?:[.]\w{2,})+$/',$value) ) { + return false; + } + + return $value; + } + + /** + * Validate sync_to_outlook field + * + * @param $value string + * @param $vardef array + * @param $bad_names array used to return list of bad users/teams in $value + * @return string sanitized and validated value on success, bool false on failure + */ + public function synctooutlook( + $value, + $vardef, + &$bad_names + ) + { + static $focus_user; + + // cache this object since we'll be reusing it a bunch + if ( !($focus_user instanceof User) ) { + + $focus_user = new User(); + } + + + if ( !empty($value) && strtolower($value) != "all" ) { + $theList = explode(",",$value); + $isValid = true; + $bad_names = array(); + foreach ($theList as $eachItem) { + if ( $focus_user->retrieve_user_id($eachItem) + || $focus_user->retrieve($eachItem) + ) { + // all good + } + else { + $isValid = false; + $bad_names[] = $eachItem; + continue; + } + } + if(!$isValid) { + return false; + } + } + + return $value; + } + + /** + * Validate time fields + * + * @param $value string + * @param $vardef array + * @param $focus object bean of the module we're importing into + * @return string sanitized and validated value on success, bool false on failure + */ + public function time( + $value, + $vardef, + $focus + ) + { + global $timedate; + + $format = $this->timeformat; + + if ( !$timedate->check_matching_format($value, $format) ) + return false; + + if ( !$this->isValidTimeDate($value, $format) ) + return false; + + $value = $timedate->swap_formats( + $value, $format, $timedate->get_time_format()); + $value = $timedate->handle_offset( + $value, $timedate->get_time_format(), false, $GLOBALS['current_user'], $this->timezone); + $value = $timedate->handle_offset( + $value, $timedate->get_time_format(), true); + + return $value; + } + + /** + * Added to handle Bug 24104, to make sure the date/time value is correct ( i.e. 20/20/2008 doesn't work ) + * + * @param $value string + * @param $format string + * @return string sanitized and validated value on success, bool false on failure + */ + public function isValidTimeDate( + $value, + $format + ) + { + global $timedate; + + $dateparts = array(); + $reg = $timedate->get_regular_expression($format); + preg_match('@'.$reg['format'].'@', $value, $dateparts); + + if ( empty($dateparts) ) + return false; + if ( isset($reg['positions']['a']) + && !in_array($dateparts[$reg['positions']['a']], array('am','pm')) ) + return false; + if ( isset($reg['positions']['A']) + && !in_array($dateparts[$reg['positions']['A']], array('AM','PM')) ) + return false; + if ( isset($reg['positions']['h']) && ( + !is_numeric($dateparts[$reg['positions']['h']]) + || $dateparts[$reg['positions']['h']] < 1 + || $dateparts[$reg['positions']['h']] > 12 ) ) + return false; + if ( isset($reg['positions']['H']) && ( + !is_numeric($dateparts[$reg['positions']['H']]) + || $dateparts[$reg['positions']['H']] < 0 + || $dateparts[$reg['positions']['H']] > 23 ) ) + return false; + if ( isset($reg['positions']['i']) && ( + !is_numeric($dateparts[$reg['positions']['i']]) + || $dateparts[$reg['positions']['i']] < 0 + || $dateparts[$reg['positions']['i']] > 59 ) ) + return false; + if ( isset($reg['positions']['s']) && ( + !is_numeric($dateparts[$reg['positions']['s']]) + || $dateparts[$reg['positions']['s']] < 0 + || $dateparts[$reg['positions']['s']] > 59 ) ) + return false; + if ( isset($reg['positions']['d']) && ( + !is_numeric($dateparts[$reg['positions']['d']]) + || $dateparts[$reg['positions']['d']] < 1 + || $dateparts[$reg['positions']['d']] > 31 ) ) + return false; + if ( isset($reg['positions']['m']) && ( + !is_numeric($dateparts[$reg['positions']['m']]) + || $dateparts[$reg['positions']['m']] < 1 + || $dateparts[$reg['positions']['m']] > 12 ) ) + return false; + if ( isset($reg['positions']['Y']) && + !is_numeric($dateparts[$reg['positions']['Y']]) ) + return false; + + return true; + } + +} diff --git a/modules/Import/ImportFile.php b/modules/Import/ImportFile.php new file mode 100644 index 00000000..80f2d938 --- /dev/null +++ b/modules/Import/ImportFile.php @@ -0,0 +1,329 @@ +_fp = sugar_fopen($filename,'r'); + $this->_filename = $filename; + $this->_deleteFile = $deleteFile; + $this->_delimiter = ( empty($delimiter) ? ',' : $delimiter ); + $this->_enclosure = ( empty($enclosure) ? '' : trim($enclosure) ); + + // Bug 39494 - Remove the BOM (Byte Order Mark) from the beginning of the import row if it exists + $bomCheck = fread($this->_fp, 3); + if($bomCheck != pack("CCC",0xef,0xbb,0xbf)) { + rewind($this->_fp); + } + } + + /** + * Destructor + * + * Deletes $_importFile if $_deleteFile is true + */ + public function __destruct() + { + if ( $this->_deleteFile && $this->fileExists() ) { + fclose($this->_fp); + //Make sure the file exists before unlinking + if(file_exists($this->_filename)) { + unlink($this->_filename); + } + } + + ini_restore('auto_detect_line_endings'); + } + + /** + * Returns true if the filename given exists and is readable + * + * @return bool + */ + public function fileExists() + { + return !$this->_fp ? false : true; + } + + /** + * Gets the next row from $_importFile + * + * @return array current row of file + */ + public function getNextRow() + { + if (!$this->fileExists()) + return false; + + // explode on delimiter instead if enclosure is an empty string + if ( empty($this->_enclosure) ) { + $row = explode($this->_delimiter,rtrim(fgets($this->_fp, 8192),"\r\n")); + if ($row !== false && !( count($row) == 1 && trim($row[0]) == '') ) + $this->_currentRow = $row; + else + return false; + } + else { + $row = fgetcsv($this->_fp, 8192, $this->_delimiter, $this->_enclosure); + if ($row !== false && $row != array(null)) + $this->_currentRow = $row; + else + return false; + } + + // Bug 26219 - Convert all line endings to the same style as PHP_EOL + foreach ( $this->_currentRow as $key => $value ) { + // use preg_replace instead of str_replace as str_replace may cause extra lines on Windows + $this->_currentRow[$key] = preg_replace("[\r\n|\n|\r]", PHP_EOL, $value); + } + + $this->_rowsCount++; + $this->_rowCountedForErrors = false; + + return $this->_currentRow; + } + + /** + * Returns the number of fields in the current row + * + * @return int count of fiels in the current row + */ + public function getFieldCount() + { + return count($this->_currentRow); + } + + /** + * Writes the row out to the ImportCacheFiles::getDuplicateFileName() file + */ + public function markRowAsDuplicate() + { + $fp = sugar_fopen(ImportCacheFiles::getDuplicateFileName(),'a'); + if ( empty($this->_enclosure) ) + fputs($fp,implode($this->_delimiter,$this->_currentRow).PHP_EOL); + else + fputcsv($fp,$this->_currentRow, $this->_delimiter, $this->_enclosure); + fclose($fp); + + $this->_dupeCount++; + } + + /** + * Writes the row out to the ImportCacheFiles::getErrorFileName() file + * + * @param $error string + * @param $fieldName string + * @param $fieldValue mixed + */ + public function writeError( + $error, + $fieldName, + $fieldValue + ) + { + $fp = sugar_fopen(ImportCacheFiles::getErrorFileName(),'a'); + fputcsv($fp,array($error,$fieldName,$fieldValue,$this->_rowsCount)); + fclose($fp); + + if ( !$this->_rowCountedForErrors ) { + $this->_errorCount++; + $this->_rowCountedForErrors = true; + $this->writeErrorRecord(); + } + } + + /** + * Writes the row out to the ImportCacheFiles::getErrorRecordsFileName() file + */ + public function writeErrorRecord() + { + $fp = sugar_fopen(ImportCacheFiles::getErrorRecordsFileName(),'a'); + if ( empty($this->_enclosure) ) + fputs($fp,implode($this->_delimiter,$this->_currentRow).PHP_EOL); + else + fputcsv($fp,$this->_currentRow, $this->_delimiter, $this->_enclosure); + fclose($fp); + } + + /** + * Writes the totals and filename out to the ImportCacheFiles::getStatusFileName() file + */ + public function writeStatus() + { + $fp = sugar_fopen(ImportCacheFiles::getStatusFileName(),'a'); + fputcsv($fp,array($this->_rowsCount,$this->_errorCount,$this->_dupeCount, + $this->_createdCount,$this->_updatedCount,$this->_filename)); + fclose($fp); + } + + /** + * Add this row to the UsersLastImport table + * + * @param string $import_module name of the module we are doing the import into + * @param string $module name of the bean we are creating for this import + * @param string $id id of the recorded created in the $module + */ + public static function writeRowToLastImport( + $import_module, + $module, + $id + ) + { + // cache $last_import instance + static $last_import; + + if ( !($last_import instanceof UsersLastImport) ) + $last_import = new UsersLastImport(); + + $last_import->id = null; + $last_import->deleted = null; + $last_import->assigned_user_id = $GLOBALS['current_user']->id; + $last_import->import_module = $import_module; + if ( $module == 'Case' ) { + $module = 'aCase'; + } + $last_import->bean_type = $module; + $last_import->bean_id = $id; + return $last_import->save(); + } + + /** + * Marks whether this row created a new record or not + * + * @param $createdRecord bool true if record is created, false if it is just updated + */ + public function markRowAsImported( + $createdRecord = true + ) + { + if ( $createdRecord ) + ++$this->_createdCount; + else + ++$this->_updatedCount; + } +} diff --git a/modules/Import/ImportFileSplitter.php b/modules/Import/ImportFileSplitter.php new file mode 100644 index 00000000..063ddaa0 --- /dev/null +++ b/modules/Import/ImportFileSplitter.php @@ -0,0 +1,206 @@ +_recordThreshold = $recordThreshold; + $this->_sourceFile = $source; + } + + /** + * Returns true if the filename given exists and is readable + * + * @return bool + */ + public function fileExists() + { + if ( !is_file($this->_sourceFile) || !is_readable($this->_sourceFile)) { + return false; + } + + return true; + } + + /** + * Actually split the file into parts + * + * @param string $delimiter + * @param string $enclosure + * @param bool $has_header true if file has a header row + */ + public function splitSourceFile( + $delimiter = ',', + $enclosure = '"', + $has_header = false + ) + { + if (!$this->fileExists()) + return false; + $importFile = new ImportFile($this->_sourceFile,$delimiter,$enclosure,false); + $filecount = 0; + $fw = sugar_fopen("{$this->_sourceFile}-{$filecount}","w"); + $count = 0; + // skip first row if we have a header row + if ( $has_header && $importFile->getNextRow() ) { + // mark as duplicate to stick header row in the dupes file + $importFile->markRowAsDuplicate(); + // same for error records file + $importFile->writeErrorRecord(); + } + while ( $row = $importFile->getNextRow() ) { + // after $this->_recordThreshold rows, close this import file and goto the next one + if ( $count >= $this->_recordThreshold ) { + fclose($fw); + $filecount++; + $fw = sugar_fopen("{$this->_sourceFile}-{$filecount}","w"); + $count = 0; + } + // Bug 25119: Trim the enclosure string to remove any blank spaces that may have been added. + $enclosure = trim($enclosure); + if(!empty($enclosure)) { + foreach($row as $key => $v){ + $row[$key] =preg_replace("/$enclosure/","$enclosure$enclosure", $v); + } + } + $line = $enclosure.implode($enclosure.$delimiter.$enclosure, $row).$enclosure.PHP_EOL; + //Would normally use fputcsv() here. But when enclosure character is used and the field value doesn't include delimiter, enclosure, escape character, "\n", "\r", "\t", or " ", php default function 'fputcsv' will not use enclosure for this string. + fputs($fw, $line); + $count++; + } + + fclose($fw); + $this->_fileCount = $filecount; + $this->_recordCount = ($filecount * $this->_recordThreshold) + $count; + // increment by one to get true count of files created + ++$this->_fileCount; + } + + /** + * Return the count of records in the file, if it's been processed with splitSourceFile() + * + * @return int count of records in the file + */ + public function getRecordCount() + { + if ( !isset($this->_recordCount) ) + return false; + + return $this->_recordCount; + } + + /** + * Return the count of files created by the split, if it's been processed with splitSourceFile() + * + * @return int count of files created by the split + */ + public function getFileCount() + { + if ( !isset($this->_fileCount) ) + return false; + + return $this->_fileCount; + } + + /** + * Return file name of one of the split files + * + * @param int $filenumber which split file we want + * + * @return string filename + */ + public function getSplitFileName( + $filenumber = 0 + ) + { + if ( $filenumber >= $this->getFileCount()) + return false; + + return "{$this->_sourceFile}-{$filenumber}"; + } + +} + \ No newline at end of file diff --git a/modules/Import/ImportMap.php b/modules/Import/ImportMap.php new file mode 100644 index 00000000..da653977 --- /dev/null +++ b/modules/Import/ImportMap.php @@ -0,0 +1,358 @@ +content) ) + { + $pairs = explode("&",$this->content); + foreach ($pairs as $pair){ + list($name,$value) = explode("=",$pair); + $mapping_arr[trim($name)] = $value; + } + } + + return $mapping_arr; + } + + /** + * Sets $content with the mapping given + * + * @param string $mapping_arr + */ + public function setMapping( + $mapping_arr + ) + { + $output = array (); + foreach ($mapping_arr as $key => $item) { + $output[] = "$key=$item"; + } + $this->content = implode("&", $output); + } + + /** + * Returns an array with the default field values + * + * @return array + */ + public function getDefaultValues() + { + $defa_arr = array(); + if ( !empty($this->default_values) ) + { + $pairs = explode("&",$this->default_values); + foreach ($pairs as $pair){ + list($name,$value) = explode("=",$pair); + $defa_arr[trim($name)] = $value; + } + } + + return $defa_arr; + } + + /** + * Sets $default_values with the default values given + * + * @param string $defa_arr + */ + public function setDefaultValues( + $defa_arr + ) + { + $output = array (); + foreach ($defa_arr as $key => $item) { + $output[] = "$key=$item"; + } + $this->default_values = implode("&", $output); + } + + /** + * @see SugarBean::retrieve() + */ + public function retrieve($id = -1, $encode=true,$deleted=true) + { + $returnVal = parent::retrieve($id,$encode,$deleted); + + if ( !($returnVal instanceOf $this) ) { + return $returnVal; + } + + if ( $this->source == 'tab' && $this->delimiter == '' ) { + $this->delimiter = "\t"; + } + + return $this; + } + + /** + * Save + * + * @param string $owner_id + * @param string $name + * @param string $module + * @param string $source + * @param string $has_header + * @param string $delimiter + * @param string $enclosure + * @return bool + */ + public function save( + $owner_id, + $name, + $module, + $source, + $has_header, + $delimiter, + $enclosure + ) + { + $olddefault_values = $this->default_values; + $oldcontent = $this->content; + + $this->retrieve_by_string_fields( + array( + 'assigned_user_id'=>$owner_id, + 'name'=>$name), + false + ); + + // Bug 23354 - Make sure enclosure gets saved as an empty string if + // it is an empty string, instead of as a null + if ( strlen($enclosure) <= 0 ) $enclosure = ' '; + + $this->assigned_user_id = $owner_id; + $this->name = $name; + $this->source = $source; + $this->module = $module; + $this->delimiter = $delimiter; + $this->enclosure = $enclosure; + $this->has_header = $has_header; + $this->deleted = 0; + $this->default_values = $olddefault_values; + $this->content = $oldcontent; + parent::save(); + + // Bug 29365 - The enclosure character isn't saved correctly if it's a tab using MssqlManager, so resave it + if ( $enclosure == '\\t' && $this->db instanceOf MssqlManager ) { + $this->enclosure = $enclosure; + parent::save(); + } + + return 1; + } + + /** + * Checks to see if the user owns this mapping or is an admin first + * If true, then call parent function + * + * @param $id + */ + public function mark_deleted( + $id + ) + { + global $current_user; + + if ( !is_admin($current_user) ) { + $other_map = new ImportMap(); + $other_map->retrieve_by_string_fields(array('id'=> $id), false); + + if ( $other_map->assigned_user_id != $current_user->id ) + return false; + } + + return parent::mark_deleted($id); + } + + /** + * Mark an import map as published + * + * @param string $user_id + * @param bool $flag true if we are publishing or false if we are unpublishing + * @return bool + */ + public function mark_published( + $user_id, + $flag + ) + { + global $current_user; + + if ( !is_admin($current_user) ) + return false; + + // check for problems + if ($flag) { + // if you are trying to publish your map + // but there's another published map + // by the same name + $query_arr = array( + 'name' =>$this->name, + 'is_published' =>'yes' + ); + } + else { + // if you are trying to unpublish a map + // but you own an unpublished map by the same name + $query_arr = array( + 'name' => $this->name, + 'assigned_user_id' => $user_id, + 'is_published' => 'no' + ); + } + $other_map = new ImportMap(); + $other_map->retrieve_by_string_fields($query_arr, false); + + // if we find this other map, quit + if ( isset($other_map->id) ) + return false; + + // otherwise update the is_published flag + $query = "UPDATE $this->table_name + SET is_published = '". ($flag?'yes':'no') . "', + assigned_user_id = '$user_id' + WHERE id = '{$this->id}'"; + + $this->db->query($query,true,"Error marking import map published: "); + + return true; + } + + /** + * Similar to retrieve_by_string_fields, but returns multiple objects instead of just one. + * + * @param array $fields_array + * @return array $obj_arr + */ + public function retrieve_all_by_string_fields( + $fields_array + ) + { + $query = "SELECT * + FROM {$this->table_name} + " . $this->get_where($fields_array); + + $result = $this->db->query($query,true," Error: "); + $obj_arr = array(); + + while ($row = $this->db->fetchByAssoc($result,-1,FALSE) ) { + $focus = new ImportMap(); + + foreach($this->column_fields as $field) { + if(isset($row[$field])) { + $focus->$field = $row[$field]; + } + } + $focus->fill_in_additional_detail_fields(); + $obj_arr[]=$focus; + } + + return $obj_arr; + } + +} + + +?> diff --git a/modules/Import/ImportMapAct.php b/modules/Import/ImportMapAct.php new file mode 100644 index 00000000..f1b5096a --- /dev/null +++ b/modules/Import/ImportMapAct.php @@ -0,0 +1,129 @@ +"website", + "Company"=>"account_name", + "Name Suffix"=>"salutation", + "Address 1"=>"primary_address_street", + "Address 2"=>"primary_address_street_2", + "Address 3"=>"primary_address_street_3", + "City"=>"primary_address_city", + "State"=>"primary_address_state", + "Zip"=>"primary_address_postalcode", + "Country"=>"primary_address_country", + "Phone"=>"phone_work", + "Phone Ext-"=>"phone_work_ext", + "Mobile Phone"=>"phone_mobile", + "Alt Phone"=>"phone_other", + "Fax"=>"phone_fax", + "E-mail Login"=>"email1", + "E-mail"=>"email1", + "Assistant"=>"assistant", + "Asst. Phone"=>"assistant_phone", + "Home Address 1"=>"alt_address_street", + "Home Address 2"=>"alt_address_street_2", + "Home Address 3"=>"alt_address_street_3", + "Home Zip"=>"alt_address_postalcode", + "Home Country"=>"alt_address_country", + "Home Phone"=>"phone_home", + ); + break; + case 'Accounts': + return $return_array + array( + "Revenue"=>"annual_revenue", + "Number of Employees"=>"employees", + "Address 1"=>"billing_address_street", + "City"=>"billing_address_city", + "State"=>"billing_address_state", + "Zip Code"=>"billing_address_postalcode", + "Country"=>"billing_address_country", + "Phone"=>"phone_office", + "Fax Phone"=>"phone_fax", + "Ticker Symbol"=>"ticker_symbol", + ); + break; + default: + return $return_array; + } + } +} + + +?> diff --git a/modules/Import/ImportMapCsv.php b/modules/Import/ImportMapCsv.php new file mode 100644 index 00000000..13d80d21 --- /dev/null +++ b/modules/Import/ImportMapCsv.php @@ -0,0 +1,62 @@ + diff --git a/modules/Import/ImportMapOther.php b/modules/Import/ImportMapOther.php new file mode 100644 index 00000000..06380c9a --- /dev/null +++ b/modules/Import/ImportMapOther.php @@ -0,0 +1,157 @@ +"salutation", + "Full Name"=>"full_name", + "Company"=>"company", + "First Name"=>"first_name", + "Last Name"=>"last_name", + "Title"=>"title", + "Department"=>"department", + "Birthday"=>"birthdate", + "Home Phone"=>"phone_home", + "Mobile Phone"=>"phone_mobile", + "Business Phone"=>"phone_work", + "Other Phone"=>"phone_other", + "Business Fax"=>"phone_fax", + "E-mail Address"=>"email1", + "E-mail 2"=>"email2", + "Assistant's Name"=>"assistant", + "Assistant's Phone"=>"assistant_phone", + "Business Street"=>"primary_address_street", + "Business Street 2"=>"primary_address_street_2", + "Business Street 3"=>"primary_address_street_3", + "Business City"=>"primary_address_city", + "Business State"=>"primary_address_state", + "Business Postal Code"=>"primary_address_postalcode", + "Business Country/Region"=>"primary_address_country", + "Home Street"=>"alt_address_street", + "Home Street 2"=>"alt_address_street_2", + "Home Street 3"=>"alt_address_street_3", + "Home City"=>"alt_address_city", + "Home State"=>"alt_address_state", + "Home Postal Code"=>"alt_address_postalcode", + "Home Country/Region"=>"alt_address_country", + ); + break; + case 'Accounts': + return array( + "Company"=>"name", + "Business Street"=>"billing_address_street", + "Business City"=>"billing_address_city", + "Business State"=>"billing_address_state", + "Business Country"=>"billing_address_country", + "Business Postal Code"=>"billing_address_postalcode", + "Business Fax"=>"phone_fax", + "Company Main Phone"=>"phone_office", + "Web Page"=>"website", + ); + break; + case 'Opportunities': + return array( + "Opportunity Name"=>"name" , + "Type"=>"opportunity_type", + "Lead Source"=>"lead_source", + "Amount"=>"amount", + "Created Date"=>"date_entered", + "Close Date"=>"date_closed", + "Next Step"=>"next_step", + "Stage"=>"sales_stage", + "Probability (%)"=>"probability", + "Account Name"=>"account_name"); + break; + default: + return array(); + } + } + + /** + * Returns a list of fields that should be ignorred for the module during import + * + * @param string $module + * @return array of fields to ignor + */ + public function getIgnoredFields( + $module + ) + { + return array(); + } +} + + +?> diff --git a/modules/Import/ImportMapOutlook.php b/modules/Import/ImportMapOutlook.php new file mode 100644 index 00000000..00ca35f5 --- /dev/null +++ b/modules/Import/ImportMapOutlook.php @@ -0,0 +1,96 @@ +"title", + "Home Country"=>"alt_address_country", + "E-mail 2 Address"=>"email2", + ); + break; + case 'Accounts': + return $return_array; + break; + default: + return $return_array; + } + } +} + + +?> diff --git a/modules/Import/ImportMapSalesforce.php b/modules/Import/ImportMapSalesforce.php new file mode 100644 index 00000000..a3f4d997 --- /dev/null +++ b/modules/Import/ImportMapSalesforce.php @@ -0,0 +1,161 @@ +"description", + "Birthdate"=>"birthdate", + "Lead Source"=>"lead_source", + "Assistant"=>"assistant", + "Asst. Phone"=>"assistant_phone", + "Mailing Street"=>"primary_address_street", + "Mailing Address Line1"=>"primary_address_street_2", + "Mailing Address Line2"=>"primary_address_street_3", + "Mailing Address Line3"=>"primary_address_street_4", + "Mailing City"=>"primary_address_city", + "Mailing State"=>"primary_address_state", + "Mailing Zip/Postal Code"=>"primary_address_postalcode", + "Mailing Country"=>"primary_address_country", + "Other Street"=>"alt_address_street", + "Other Address Line 1"=>"alt_address_street_2", + "Other Address Line 2"=>"alt_address_street_3", + "Other Address Line 3"=>"alt_address_street_4", + "Other City"=>"alt_address_city", + "Other State"=>"alt_address_state", + "Other Zip/Postal Code"=>"alt_address_postalcode", + "Other Country"=>"alt_address_country", + "Phone"=>"phone_work", + "Mobile"=>"phone_mobile", + "Home Phone"=>"phone_home", + "Other Phone"=>"phone_other", + "Fax"=>"phone_fax", + "Email"=>"email1", + "Email Opt Out"=>"email_opt_out", + "Do Not Call"=>"do_not_call", + "Account Name"=>"account_name", + ); + break; + case 'Accounts': + return array( + "Account Name"=>"name", + "Annual Revenue"=>"annual_revenue", + "Type"=>"account_type", + "Ticker Symbol"=>"ticker_symbol", + "Rating"=>"rating", + "Industry"=>"industry", + "SIC Code"=>"sic_code", + "Ownership"=>"ownership", + "Employees"=>"employees", + "Description"=>"description", + "Billing Street"=>"billing_address_street", + "Billing Address Line1"=>"billing_address_street_2", + "Billing Address Line2"=>"billing_address_street_3", + "Billing City"=>"billing_address_city", + "Billing State"=>"billing_address_state", + "Billing Zip/Postal Code"=>"billing_address_postalcode", + "Billing Country"=>"billing_address_country", + "Shipping Street"=>"shipping_address_street", + "Shipping Address Line1"=>"shipping_address_street_2", + "Shipping Address Line2"=>"shipping_address_street_3", + "Shipping City"=>"shipping_address_city", + "Shipping State"=>"shipping_address_state", + "Shipping Zip/Postal Code"=>"shipping_address_postalcode", + "Shipping Country"=>"shipping_address_country", + "Phone"=>"phone_office", + "Fax"=>"phone_fax", + "Website"=>"website", + ); + break; + default: + return $return_array; + } + } + + /** + * @see ImportMapOther::getIgnoredFields() + */ + public function getIgnoredFields( + $module + ) + { + return array_merge(parent::getIgnoredFields($module),array('id')); + } +} + + +?> diff --git a/modules/Import/ImportMapTab.php b/modules/Import/ImportMapTab.php new file mode 100644 index 00000000..b3490f5c --- /dev/null +++ b/modules/Import/ImportMapTab.php @@ -0,0 +1,64 @@ + diff --git a/modules/Import/Menu.php b/modules/Import/Menu.php new file mode 100644 index 00000000..837009c5 --- /dev/null +++ b/modules/Import/Menu.php @@ -0,0 +1,47 @@ +table_name + WHERE assigned_user_id = '$user_id'"; + $this->db->query($query,true,"Error marking last imported records deleted: "); + } + + /** + * Undo a single record + * + * @param string $id specific users_last_import id to undo + */ + public function undoById( + $id + ) + { + global $current_user; + + $query1 = "SELECT bean_id, bean_type + FROM users_last_import + WHERE assigned_user_id = '$current_user->id' + AND id = '$id' + AND deleted=0"; + + $result1 = $this->db->query($query1); + if ( !$result1 ) + return false; + + while ( $row1 = $this->db->fetchByAssoc($result1)) + $this->_deleteRecord($row1['bean_id'],$row1['bean_type']); + + return true; + } + + /** + * Undo an import + * + * @param string $module module being imported into + */ + public function undo( + $module + ) + { + global $current_user; + + $query1 = "SELECT bean_id, bean_type + FROM users_last_import + WHERE assigned_user_id = '$current_user->id' + AND import_module = '$module' + AND deleted=0"; + + $result1 = $this->db->query($query1); + if ( !$result1 ) + return false; + + while ( $row1 = $this->db->fetchByAssoc($result1)) + $this->_deleteRecord($row1['bean_id'],$row1['bean_type']); + + return true; + } + + /** + * Deletes a record in a bean + * + * @param $bean_id + * @param $module + */ + protected function _deleteRecord( + $bean_id, + $module + ) + { + static $focus; + + // load bean + if ( !( $focus instanceof $module) ) { + require_once($GLOBALS['beanFiles'][$module]); + $focus = new $module; + } + + $result = $this->db->query( + "DELETE FROM {$focus->table_name} + WHERE id = '{$bean_id}'" + ); + if (!$result) + return false; + // Bug 26318: Remove all created e-mail addresses ( from jchi ) + $result2 = $this->db->query( + "SELECT email_address_id + FROM email_addr_bean_rel + WHERE email_addr_bean_rel.bean_id='{$bean_id}' + AND email_addr_bean_rel.bean_module='{$focus->module_dir}'"); + $this->db->query( + "DELETE FROM email_addr_bean_rel + WHERE email_addr_bean_rel.bean_id='{$bean_id}' + AND email_addr_bean_rel.bean_module='{$focus->module_dir}'" + ); + + while ( $row2 = $this->db->fetchByAssoc($result2)) { + if ( !$this->db->getOne( + "SELECT email_address_id + FROM email_addr_bean_rel + WHERE email_address_id = '{$row2['email_address_id']}'") ) + $this->db->query( + "DELETE FROM email_addresses + WHERE id = '{$row2['email_address_id']}'"); + } + + if ($focus->hasCustomFields()) + $this->db->query( + "DELETE FROM {$focus->table_name}_cstm + WHERE id_c = '{$bean_id}'"); + } + + /** + * Get a list of bean types created in the import + * + * @param string $module module being imported into + */ + public static function getBeansByImport( + $module + ) + { + global $current_user; + + $query1 = "SELECT DISTINCT bean_type + FROM users_last_import + WHERE assigned_user_id = '$current_user->id' + AND import_module = '$module' + AND deleted=0"; + + $result1 = $GLOBALS['db']->query($query1); + if ( !$result1 ) + return array($module); + + $returnarray = array(); + while ( $row1 = $GLOBALS['db']->fetchByAssoc($result1)) + $returnarray[] = $row1['bean_type']; + + return $returnarray; + } + +} +?> diff --git a/modules/Import/controller.php b/modules/Import/controller.php new file mode 100644 index 00000000..595731bb --- /dev/null +++ b/modules/Import/controller.php @@ -0,0 +1,126 @@ +bean = loadBean($_REQUEST['import_module']); + if ( $this->bean ) { + if ( !$this->bean->importable ) + $this->bean = false; + elseif ( $_REQUEST['import_module'] == 'Users' && !is_admin($GLOBALS['current_user']) ) + $this->bean = false; + elseif ( $this->bean->bean_implements('ACL')){ + if(!ACLController::checkAccess($this->bean->module_dir, 'import', true)){ + ACLController::displayNoAccess(); + sugar_die(''); + } + } + } + + if ( !$this->bean ) { + $_REQUEST['message'] = $mod_strings['LBL_ERROR_IMPORTS_NOT_SET_UP']; + $this->view = 'error'; + } + else + $GLOBALS['FOCUS'] = $this->bean; + } + + function action_index() + { + $this->action_Step1(); + } + + function action_Step1() + { + $this->view = 'step1'; + } + + function action_Step2() + { + $this->view = 'step2'; + } + + function action_Step3() + { + $this->view = 'step3'; + } + + function action_Step4() + { + $this->view = 'step4'; + } + + function action_Last() + { + $this->view = 'last'; + } + + function action_Undo() + { + $this->view = 'undo'; + } + + function action_Error() + { + $this->view = 'error'; + } + + function action_GetControl() + { + echo getControl($_REQUEST['import_module'],$_REQUEST['field_name']); + exit; + } +} +?> \ No newline at end of file diff --git a/modules/Import/language/en_us.lang.php b/modules/Import/language/en_us.lang.php new file mode 100644 index 00000000..699d21e2 --- /dev/null +++ b/modules/Import/language/en_us.lang.php @@ -0,0 +1,315 @@ + 'Import File Read Successfully', + 'LBL_RECORDS_SKIPPED_DUE_TO_ERROR' => 'records were not imported due to error.', + 'LBL_UPDATE_SUCCESSFULLY' => 'records updated successfully', + 'LBL_SUCCESSFULLY_IMPORTED' => 'records created successfully', + 'LBL_STEP_4_TITLE' => 'Step 4: Import File', + 'LBL_STEP_5_TITLE' => 'Step 5: View Results', + 'LBL_CUSTOM_ENCLOSURE' => 'Fields Qualified By:', + 'LBL_ERROR_UNABLE_TO_PUBLISH' => 'Unable to publish. There is another published Import map by the same name.', + 'LBL_ERROR_UNABLE_TO_UNPUBLISH' => 'Unable to un-publish a map owned by another user. You own an Import map by the same name.', + 'LBL_ERROR_IMPORTS_NOT_SET_UP' => 'Imports aren\'t set up for this module type', + 'LBL_IMPORT_TYPE' => 'Import Action', + 'LBL_IMPORT_BUTTON' => 'Create Records', + 'LBL_UPDATE_BUTTON' => 'Create and Update Records', + 'LBL_ERROR_INVALID_BOOL'=>'Invalid boolean value', + 'LBL_NO_ID' => 'ID Required', + 'LBL_PRE_CHECK_SKIPPED' => 'Pre-Check skipped', + 'LBL_IMPORT_ERROR' => 'Import errors:', + 'LBL_ERROR' => 'Error', + 'LBL_NOLOCALE_NEEDED' => 'No locale conversion needed', + 'LBL_FIELD_NAME' => 'Field Name', + 'LBL_VALUE' => 'Value', + 'LBL_ROW_NUMBER' => 'Row Number', + 'LBL_NONE' => 'None', + 'LBL_REQUIRED_VALUE' => 'Required value missing', + 'LBL_ID_EXISTS_ALREADY' => 'ID already exists in this table', + 'LBL_ASSIGNED_USER' => 'If the user does not exist use the current user', + 'LBL_SHOW_HIDDEN' => 'Show fields that are not normally importable', + 'LBL_UPDATE_RECORDS' => 'Update existing records instead of importing them (No Undo)', + 'LBL_TEST'=> 'Test Import (do not save or change data)', + 'LBL_TRUNCATE_TABLE' => 'Empty table before import (delete all records)', + 'LBL_RELATED_ACCOUNTS' => 'Do not create related accounts', + 'LBL_NO_DATECHECK' => 'Skip date check (faster but will fail if any date is wrong)', + 'LBL_NO_EMAILS' => 'Do not send out Email notifications during this import', + 'LBL_NO_PRECHECK' => 'Native Format mode', + 'LBL_STRICT_CHECKS' => 'Use strict ruleset (Check Email addresses and phone numbers too)', + 'LBL_ERROR_SELECTING_RECORD' => 'Error selecting record:', + 'LBL_ERROR_DELETING_RECORD' => 'Error deleting record:', + 'LBL_NOT_SET_UP' => 'Import is not set up for this module type', + 'LBL_ARE_YOU_SURE' => 'Are you sure? This will erase all data in this module.', + 'LBL_NO_RECORD' => 'No record with this ID to update', + 'LBL_NOT_SET_UP_FOR_IMPORTS' => 'Import is not set up for this module type', + 'LBL_DEBUG_MODE' => 'Enable debugging mode', + 'LBL_ERROR_INVALID_ID' => 'ID given is too long to fit in the field (maximum length is 36 characters)', + 'LBL_ERROR_INVALID_PHONE' => 'Invalid phone number', + 'LBL_ERROR_INVALID_NAME' => 'String too long to fit in the field', + 'LBL_ERROR_INVALID_VARCHAR' => 'String too long to fit in the field', + 'LBL_ERROR_INVALID_DATE' => 'Invalid date', + 'LBL_ERROR_INVALID_DATETIME' => 'Invalid datetime', + 'LBL_ERROR_INVALID_DATETIMECOMBO' => 'Invalid datetime', + 'LBL_ERROR_INVALID_TIME' => 'Invalid time', + 'LBL_ERROR_INVALID_INT' => 'Invalid integer value', + 'LBL_ERROR_INVALID_NUM' => 'Invalid numeric value', + 'LBL_ERROR_INVALID_TIME' => 'Invalid time', + 'LBL_ERROR_INVALID_EMAIL'=>'Invalid Email address', + 'LBL_ERROR_INVALID_BOOL'=>'Invalid value (should be a 1 or 0)', + 'LBL_ERROR_INVALID_DATE'=>'Invalid date string', + 'LBL_ERROR_INVALID_USER'=>'Invalid user name or ID', + 'LBL_ERROR_INVALID_TEAM' => 'Invalid team name or ID', + 'LBL_ERROR_INVALID_ACCOUNT' => 'Invalid account name or ID', + 'LBL_ERROR_INVALID_RELATE' => 'Invalid relational field', + 'LBL_ERROR_INVALID_CURRENCY' => 'Invalid currency value', + 'LBL_ERROR_INVALID_FLOAT' => 'Invalid floating point number', + 'LBL_ERROR_NOT_IN_ENUM' => 'Value not in dropDown list. Allowed values are: ', + 'LBL_NOT_MULTIENUM' => 'Not a MultiEnum', + 'LBL_IMPORT_MODULE_NO_TYPE' => 'Import is not set up for this module type', + 'LBL_IMPORT_MODULE_NO_USERS' => 'WARNING: You have no users defined on your system. If you import without adding users first, all records will be owned by the Administrator.', + 'LBL_IMPORT_MODULE_MAP_ERROR' => 'Unable to publish. There is another published Import Map by the same name.', + 'LBL_IMPORT_MODULE_MAP_ERROR2' => 'Unable to un-publish a map owned by another user. You own an Import Map by the same name.', + 'LBL_IMPORT_MODULE_NO_DIRECTORY' => 'The directory ', + 'LBL_IMPORT_MODULE_NO_DIRECTORY_END' => ' does not exist or is not writable', + 'LBL_IMPORT_MODULE_ERROR_NO_UPLOAD' => 'File was not uploaded successfully. It may be that the \'upload_max_filesize\' setting in your php.ini file is set to a small number', + 'LBL_IMPORT_MODULE_ERROR_LARGE_FILE' => 'File is too large. Max:', + 'LBL_IMPORT_MODULE_ERROR_LARGE_FILE_END' => 'Bytes. Change $sugar_config[\'upload_maxsize\'] in config.php', + 'LBL_MODULE_NAME' => 'Import', + 'LBL_TRY_AGAIN' => 'Try Again', + 'LBL_ERROR' => 'Error:', + 'ERR_IMPORT_SYSTEM_ADMININSTRATOR' => 'You cannot import a system administrator user', + 'ERR_MULTIPLE' => 'Multiple columns have been defined with the same field name.', + 'ERR_MISSING_REQUIRED_FIELDS' => 'Missing required fields:', + 'ERR_MISSING_MAP_NAME' => 'Missing custom mapping name', + 'ERR_SELECT_FULL_NAME' => 'You cannot select Full Name when First Name and Last Name are selected.', + 'ERR_SELECT_FILE' => 'Select a file to upload.', + 'LBL_SELECT_FILE' => 'Select file:', + 'LBL_CUSTOM' => 'Custom', + 'LBL_CUSTOM_CSV' => 'Custom comma delimited file', + 'LBL_CSV' => 'Comma delimited file', + 'LBL_TAB' => 'Tab delimited file', + 'LBL_CUSTOM_DELIMITED' => 'Custom delimited file', + 'LBL_CUSTOM_DELIMITER' => 'Fields Delimited By:', + 'LBL_FILE_OPTIONS' => 'File options', + 'LBL_CUSTOM_TAB' => 'Custom tab delimited file', + 'LBL_DONT_MAP' => '-- Do not map this field --', + 'LBL_STEP_1_TITLE' => 'Step 1: Select Data Source and Import Action', + 'LBL_WHAT_IS' => 'What is the Data Source?', + 'LBL_MICROSOFT_OUTLOOK' => 'Microsoft Outlook', + 'LBL_ACT' => 'Act!', + 'LBL_SALESFORCE' => 'Salesforce.com', + 'LBL_MY_SAVED' => 'My Saved Mappings:', + 'LBL_PUBLISH' => 'Publish', + 'LBL_DELETE' => 'Delete', + 'LBL_PUBLISHED_SOURCES' => 'Published Mappings:', + 'LBL_UNPUBLISH' => 'Un-Publish', + 'LBL_NEXT' => 'Next >', + 'LBL_BACK' => '< Back', + 'LBL_STEP_2_TITLE' => 'Step 2: Upload Import File', + 'LBL_HAS_HEADER' => 'Has Header:', + 'LBL_NUM_1' => '1.', + 'LBL_NUM_2' => '2.', + 'LBL_NUM_3' => '3.', + 'LBL_NUM_4' => '4.', + 'LBL_NUM_5' => '5.', + 'LBL_NUM_6' => '6.', + 'LBL_NUM_7' => '7.', + 'LBL_NUM_8' => '8.', + 'LBL_NUM_9' => '9.', + 'LBL_NUM_10' => '10.', + 'LBL_NUM_11' => '11.', + 'LBL_NUM_12' => '12.', + 'LBL_NOTES' => 'Notes:', + 'LBL_NOW_CHOOSE' => 'Now choose that file to import:', + 'LBL_IMPORT_OUTLOOK_TITLE' => 'Microsoft Outlook 98 and 2000 can export data in the Comma Separated Values format, which can be used to import data into the system. To export your data from Outlook, follow the steps below:', + 'LBL_OUTLOOK_NUM_1' => 'Start Outlook', + 'LBL_OUTLOOK_NUM_2' => 'Select the File menu, then the Import and Export ... menu option', + 'LBL_OUTLOOK_NUM_3' => 'Choose Export to a file and click Next', + 'LBL_OUTLOOK_NUM_4' => 'Choose Comma Separated Values (Windows) and click Next.
    Note: You may be prompted to install the export component', + 'LBL_OUTLOOK_NUM_5' => 'Select the Contacts folder and click Next. You can select different contacts folders if your contacts are stored in multiple folders', + 'LBL_OUTLOOK_NUM_6' => 'Choose a filename and click Next', + 'LBL_OUTLOOK_NUM_7' => 'Click Finish', + 'LBL_IMPORT_SF_TITLE' => 'Salesforce.com can export data in the Comma Separated Values format, which can be used to import data into the system. To export your data from Salesforce.com, follow the steps below:', + 'LBL_SF_NUM_1' => 'Open your browser, go to http://www.salesforce.com, and login with your email address and password', + 'LBL_SF_NUM_2' => 'Click on the Reports tab on the top menu', + 'LBL_SF_NUM_3' => 'To export Accounts: Click on the Active Accounts link
    To export Contacts: Click on the Mailing List link', + 'LBL_SF_NUM_4' => 'On Step 1: Select your report type, select Tabular Report click Next', + 'LBL_SF_NUM_5' => 'On Step 2: Select the report columns, choose the columns you want to export and click Next', + 'LBL_SF_NUM_6' => 'On Step 3: Select the information to summarize, just click Next', + 'LBL_SF_NUM_7' => 'On Step 4: Order the report columns, just click Next', + 'LBL_SF_NUM_8' => 'On Step 5: Select your report criteria, under Start Date, choose a date far enough in the past to include all your Accounts. You can also export a subset of Accounts using more advanced criteria. When you are done, click Run Report', + 'LBL_SF_NUM_9' => 'A report will be generated, and the page will display Report Generation Status: Complete. Now click Export to Excel', + 'LBL_SF_NUM_10' => 'On Export Report:, for Export File Format:, choose Comma Delimited .csv. Click Export.', + 'LBL_SF_NUM_11' => 'A dialog will pop up for you to save the export file to your computer.', + 'LBL_IMPORT_ACT_TITLE' => 'Act! can export data in the Comma Separated Values format, which can be used to import data into the system. To export your data from Act!, follow the steps below:', + 'LBL_ACT_NUM_1' => 'Launch ACT!', + 'LBL_ACT_NUM_2' => 'Select the File menu, the Data Exchange menu option, then the Export... menu option', + 'LBL_ACT_NUM_3' => 'Select the file type Text-Delimited', + 'LBL_ACT_NUM_4' => 'Choose a filename and location for the exported data and click Next', + 'LBL_ACT_NUM_5' => 'Select Contacts records only', + 'LBL_ACT_NUM_6' => 'Click the Options... button', + 'LBL_ACT_NUM_7' => 'Select Comma as the field separator character', + 'LBL_ACT_NUM_8' => 'Check the Yes, export field names checkbox and click OK', + 'LBL_ACT_NUM_9' => 'Click Next', + 'LBL_ACT_NUM_10' => 'Select All Records and then click Finish', + 'LBL_IMPORT_CUSTOM_TITLE' => 'Many applications allow you to export data into a Comma Delimited text file (.csv) by following these general steps:', + 'LBL_CUSTOM_NUM_1' => 'Launch the application and open the data file', + 'LBL_CUSTOM_NUM_2' => 'Select the Save As... or Export... menu option', + 'LBL_CUSTOM_NUM_3' => 'Save the file in a CSV or Comma Separated Values format', + 'LBL_IMPORT_TAB_TITLE' => 'Many applications allow you to export data into a Tab Delimited text file (.tsv or .tab) by following these general steps:', + 'LBL_TAB_NUM_1' => 'Launch the application and open the data file', + 'LBL_TAB_NUM_2' => 'Select the Save As... or Export... menu option', + 'LBL_TAB_NUM_3' => 'Save the file in a TSV or Tab Separated Values format', + 'LBL_STEP_3_TITLE' => 'Step 3: Confirm Fields and Import', + 'LBL_SELECT_FIELDS_TO_MAP' => 'In the list below, select the fields in the import file that should be imported into each field in the system. When you are finished, click Import Now:', + 'LBL_DATABASE_FIELD' => 'Database Field', + 'LBL_HEADER_ROW' => 'Header Row', + 'LBL_ROW' => 'Row', + 'LBL_SAVE_AS_CUSTOM' => 'Save as Custom Mapping:', + 'LBL_SAVE_AS_CUSTOM_NAME' => 'Custom Mapping Name:', + 'LBL_CONTACTS_NOTE_1' => 'Either Last Name or Full Name must be mapped.', + 'LBL_CONTACTS_NOTE_2' => 'If Full Name is mapped, then First Name and Last Name are ignored.', + 'LBL_CONTACTS_NOTE_3' => 'If Full Name is mapped, then the data in Full Name will be split into First Name and Last Name when inserted into the database.', + 'LBL_CONTACTS_NOTE_4' => 'Fields ending in Address Street 2 and Address Street 3 are concatenated together with the main Address Street Field when inserted into the database.', + 'LBL_ACCOUNTS_NOTE_1' => 'Fields ending in Address Street 2 and Address Street 3 are concatenated together with the main Address Street Field when inserted into the database.', + 'LBL_REQUIRED_NOTE' => 'Required Field(s): ', + 'LBL_IMPORT_NOW' => 'Import Now', + 'LBL_' => '', + 'LBL_CANNOT_OPEN' => 'Cannot open the imported file for reading', + 'LBL_NOT_SAME_NUMBER' => 'There were not the same number of fields per line in your file', + 'LBL_NO_LINES' => 'There were no lines in your import file', + 'LBL_FILE_ALREADY_BEEN_OR' => 'The import file has already been processed or does not exist', + 'LBL_SUCCESS' => 'Success:', + 'LBL_FAILURE' => 'Import Failed:', + 'LBL_SUCCESSFULLY' => 'Successfully imported', + 'LBL_LAST_IMPORT_UNDONE' => 'Your last import was undone', + 'LBL_NO_IMPORT_TO_UNDO' => 'There was no import to undo.', + 'LBL_FAIL' => 'Fail:', + 'LBL_RECORDS_SKIPPED' => 'Records skipped because they were missing one or more required fields', + 'LBL_IDS_EXISTED_OR_LONGER' => 'Records skipped because the id\'s either existed or were longer than 36 characters', + 'LBL_RESULTS' => 'Results', + 'LBL_IMPORT_MORE' => 'Import More', + 'LBL_FINISHED' => 'Return to ', + 'LBL_UNDO_LAST_IMPORT' => 'Undo Last Import', + 'LBL_LAST_IMPORTED'=>'Last Created', + 'ERR_MULTIPLE_PARENTS' => 'You can only have one Parent ID defined', + 'LBL_DUPLICATES' => 'Duplicates Found', + 'LNK_DUPLICATE_LIST' => 'Download list of duplicates', + 'LNK_ERROR_LIST' => 'Download list of errors', + 'LNK_RECORDS_SKIPPED_DUE_TO_ERROR' => 'Download list of records that were not imported', + 'LBL_UNIQUE_INDEX' => 'Choose index for duplicate comparison', + 'LBL_VERIFY_DUPS' => 'Verify duplicate entries against selected indexes.', + 'LBL_INDEX_USED' => 'Index(es) used:', + 'LBL_INDEX_NOT_USED' => 'Index(es) not used:', + 'LBL_IMPORT_MODULE_ERROR_NO_MOVE' => 'File was not successfully uploaded. Check the file permissions in your Sugar installation cache directory.', + 'LBL_IMPORT_FIELDDEF_ID' => 'Unique ID number', + 'LBL_IMPORT_FIELDDEF_RELATE' => 'Name or ID', + 'LBL_IMPORT_FIELDDEF_PHONE' => 'Phone Number', + 'LBL_IMPORT_FIELDDEF_TEAM_LIST' => 'Team Name or ID', + 'LBL_IMPORT_FIELDDEF_NAME' => 'Any Text', + 'LBL_IMPORT_FIELDDEF_VARCHAR' => 'Any Text', + 'LBL_IMPORT_FIELDDEF_TEXT' => 'Any Text', + 'LBL_IMPORT_FIELDDEF_TIME' => 'Time', + 'LBL_IMPORT_FIELDDEF_DATE' => 'Date', + 'LBL_IMPORT_FIELDDEF_DATETIME' => 'Datetime', + 'LBL_IMPORT_FIELDDEF_ASSIGNED_USER_NAME' => 'User Name or ID', + 'LBL_IMPORT_FIELDDEF_BOOL' => '\'0\' or \'1\'', + 'LBL_IMPORT_FIELDDEF_ENUM' => 'List', + 'LBL_IMPORT_FIELDDEF_EMAIL' => 'EMail Address', + 'LBL_IMPORT_FIELDDEF_INT' => 'Numeric (No Decimal)', + 'LBL_IMPORT_FIELDDEF_DOUBLE' => 'Numeric (No Decimal)', + 'LBL_IMPORT_FIELDDEF_NUM' => 'Numeric (No Decimal)', + 'LBL_IMPORT_FIELDDEF_CURRENCY' => 'Numeric (Decimal Allowed)', + 'LBL_IMPORT_FIELDDEF_FLOAT' => 'Numeric (Decimal Allowed)', + 'LBL_DATE_FORMAT' => 'Date Format:', + 'LBL_TIME_FORMAT' => 'Time Format:', + 'LBL_TIMEZONE' => 'Time Zone:', + 'LBL_ADD_ROW' => 'Add Field', + 'LBL_REMOVE_ROW' => 'Remove Field', + 'LBL_DEFAULT_VALUE' => 'Default Value', + 'LBL_SHOW_ADVANCED_OPTIONS' => 'Show Advanced Options', + 'LBL_HIDE_ADVANCED_OPTIONS' => 'Hide Advanced Options', + 'LBL_SHOW_PREVIEW_COLUMNS' => 'Show Preview Columns', + 'LBL_HIDE_PREVIEW_COLUMNS' => 'Hide Preview Columns', + 'LBL_SAVE_MAPPING_AS' => 'Save Mapping As', + 'LBL_OPTION_ENCLOSURE_QUOTE' => 'Single Quote (\')', + 'LBL_OPTION_ENCLOSURE_DOUBLEQUOTE' => 'Double Quote (")', + 'LBL_OPTION_ENCLOSURE_NONE' => 'None', + 'LBL_OPTION_ENCLOSURE_OTHER' => 'Other:', + 'LBL_IMPORT_COMPLETE' => 'Import Complete', + 'LBL_IMPORT_ERROR' => 'Import Errors Occurred', + 'LBL_IMPORT_RECORDS' => 'Importing Records', + 'LBL_IMPORT_RECORDS_OF' => 'of', + 'LBL_IMPORT_RECORDS_TO' => 'to', + 'LBL_CURRENCY' => 'Currency', + 'LBL_CURRENCY_SIG_DIGITS' => 'Currency Significant Digits', + 'LBL_LOCALE_EXAMPLE_NAME_FORMAT' => 'Example', + 'LBL_NUMBER_GROUPING_SEP' => '1000s separator', + 'LBL_DECIMAL_SEP' => 'Decimal symbol', + 'LBL_LOCALE_DEFAULT_NAME_FORMAT' => 'Name Display Format', + 'LBL_LOCALE_EXAMPLE_NAME_FORMAT' => 'Example', + 'LBL_LOCALE_NAME_FORMAT_DESC' => '"s" Salutation, "f" First Name, "l" Last Name', + 'LBL_CHARSET' => 'File Encoding', + 'LBL_MY_SAVED_HELP' => 'A saved mapping specifies a previously used combination of a specific data source and a set of database fields to map to the fields in the import file.
    Click Publish to make the mapping available to other users.
    Click Un-Publish to make the mapping unavailable to other users.', + 'LBL_MY_PUBLISHED_HELP' => 'A published mapping specifies a previously used combination of a specific data source and a set of database fields to map to the fields in the import file.', + 'LBL_ENCLOSURE_HELP' => '

    The qualifier character is used to enclose the intended field content, including any characters that are used as delimiters.

    Example: If the delimiter is a comma (,) and the qualifier is a quotation mark ("),
    "Cupertino, California" is imported into one field in the application and appears as Cupertino, California.
    If there are no qualifier characters, or if a different character is the qualifier,
    "Cupertino, California" is imported into two adjacent fields as "Cupertino and "California".

    Note: The import file might not contain any qualifier characters.
    The default qualifier character for comma- and tab- delimited files created in Excel is a quotation mark.

    ', + 'LBL_DELIMITER_COMMA_HELP' => 'Select this option if the character that separates the fields in the import file is a comma, or if the file extension is .csv.', + 'LBL_DELIMITER_TAB_HELP' => 'Select this option if the character that separates the fields in the import file is a TAB, and the file extension is .txt.', + 'LBL_DELIMITER_CUSTOM_HELP' => 'Select this option if the character that separates the fields in the import file is neither a comma or a TAB, and type the character in the adjacent field.', + 'LBL_DATABASE_FIELD_HELP' => 'Select a field from list of all fields existing in the database for the module.', + 'LBL_HEADER_ROW_HELP' => 'These are the field titles in the header row of the import file.', + 'LBL_DEFAULT_VALUE_HELP' => 'Indicate a value to use for the field in the created or updated record if the field in the import file contains no data.', + 'LBL_ROW_HELP' => 'This is the data in the first non-header row of the import file.', + 'LBL_SAVE_MAPPING_HELP' => 'Enter a name for the set of database fields used above for mapping to the fields in the import file fields.
    The set of fields, including the order of the fields and the data souce selected in Import Step 1, will be saved during the import attempt.
    The saved mapping can then be selected in Import Step 1 to for another import.', + 'LBL_IMPORT_FILE_SETTINGS_HELP' => 'Specify the settings in the import file to ensure that the data is imported
    correctly. These settings will not override your preferences. The records
    created or updated will contain the settings specified in your My Account page.', + 'LBL_IMPORT_FILE_SETTINGS' => 'Import File Settings', + 'LBL_VERIFY_DUPLCATES_HELP' => 'Select the fields in the import file to be used for the duplicate check.
    If data in the selected fields matches data in fields in existing records, new records will not be created for the rows containing the duplicate field data.
    The rows containing duplicate field data will be identified in the Import Results.', + 'LBL_IMPORT_STARTED' => 'Import Started:', + 'LBL_IMPORT_FILE_SETTINGS' => 'Import File Settings', + 'LBL_RECORD_CANNOT_BE_UPDATED' => 'The record could not be updated due to a permissions issue', + 'LBL_DELETE_MAP_CONFIRMATION' => 'Are you sure you want to delete this mapping?', +); +?> diff --git a/modules/Import/tpls/error.tpl b/modules/Import/tpls/error.tpl new file mode 100644 index 00000000..c8fc45d4 --- /dev/null +++ b/modules/Import/tpls/error.tpl @@ -0,0 +1,59 @@ +{* + +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + + + +*} + +
    + + + + + +

    {$MESSAGE}

    + + + + + +
    + +
    +
    diff --git a/modules/Import/tpls/last.tpl b/modules/Import/tpls/last.tpl new file mode 100644 index 00000000..3f5749d8 --- /dev/null +++ b/modules/Import/tpls/last.tpl @@ -0,0 +1,93 @@ +{* + +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + + + +*} +{$MODULE_TITLE} + +{if $noSuccess} +

    {$MOD.LBL_FAILURE}

    +{else} +

    {$MOD.LBL_SUCCESS}

    +{/if} +{if $createdCount > 0} +{$createdCount} {$MOD.LBL_SUCCESSFULLY_IMPORTED}
    +{/if} +{if $updatedCount > 0} +{$updatedCount} {$MOD.LBL_UPDATE_SUCCESSFULLY}
    +{/if} +{if $errorCount > 0} +{$errorCount} {$MOD.LBL_RECORDS_SKIPPED_DUE_TO_ERROR}
    +{$MOD.LNK_ERROR_LIST}
    +{$MOD.LNK_RECORDS_SKIPPED_DUE_TO_ERROR}
    +{/if} +{if $dupeCount > 0} +{$dupeCount} {$MOD.LBL_DUPLICATES}
    +{$MOD.LNK_DUPLICATE_LIST}
    +{/if} + +
    + + + + +
    + + + + +
    +{if !$noSuccess} + +{/if} + + + {$PROSPECTLISTBUTTON} +
    +
    +{if $PROSPECTLISTBUTTON != ''} +
    + + +
    +{/if} +{$JAVASCRIPT} diff --git a/modules/Import/tpls/step1.tpl b/modules/Import/tpls/step1.tpl new file mode 100644 index 00000000..bc9cf2c3 --- /dev/null +++ b/modules/Import/tpls/step1.tpl @@ -0,0 +1,195 @@ +{* + +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + + + +*} +{overlib_includes} +{$MODULE_TITLE} +{if $ERROR != ''} +{$ERROR} +{/if} + +
    + + + +

    + + + + +
    + + + + +
    + + + + + + + + + + + + + + + + + + + + + {if $show_salesforce} + + + + {/if} + {if $show_outlook} + + + + {/if} + {if $show_act} + + + + {/if} + {foreach from=$custom_mappings item=item name=custommappings} + {capture assign=mapping_label}{$MOD.LBL_CUSTOM_MAPPING_}{$item|upper}{/capture} + + + + {/foreach} + {foreach from=$custom_imports key=key item=item name=saved} + {if $smarty.foreach.saved.first} + + + + {/if} + + + + + {/foreach} + {foreach from=$published_imports key=key item=item name=published} + {if $smarty.foreach.published.first} + + + + {/if} + + + + + {/foreach} + + + + + + + + + +

    {$MOD.LBL_WHAT_IS} *

    +  {$MOD.LBL_CSV} {sugar_help text=$MOD.LBL_DELIMITER_COMMA_HELP}
      {$MOD.LBL_CUSTOM_ENCLOSURE} + + + {sugar_help text=$MOD.LBL_ENCLOSURE_HELP} +
    +  {$MOD.LBL_TAB} {sugar_help text=$MOD.LBL_DELIMITER_TAB_HELP}
    +  {$MOD.LBL_CUSTOM_DELIMITED} {sugar_help text=$MOD.LBL_DELIMITER_CUSTOM_HELP}
    +  {$MOD.LBL_SALESFORCE}
    +  {$MOD.LBL_MICROSOFT_OUTLOOK}
    +  {$MOD.LBL_ACT}
    +  {$mapping_label}
    +
    {$MOD.LBL_MY_SAVED} {sugar_help text=$MOD.LBL_MY_SAVED_HELP}
    + +  {$item.IMPORT_NAME} + + {if $is_admin} + + {/if} + +
    +
    {$MOD.LBL_PUBLISHED_SOURCES} {sugar_help text=$MOD.LBL_MY_PUBLISHED_HELP}
    + +  {$item.IMPORT_NAME} + + {if $is_admin} + + + {/if} +
    +

    {$MOD.LBL_IMPORT_TYPE} *

    + +  {$MOD.LBL_IMPORT_BUTTON} +
    + +  {$MOD.LBL_UPDATE_BUTTON} +
    +
    +
    +

    + +
    + + + + +
    + +
    +{$JAVASCRIPT} diff --git a/modules/Import/tpls/step2.tpl b/modules/Import/tpls/step2.tpl new file mode 100644 index 00000000..91eb86a2 --- /dev/null +++ b/modules/Import/tpls/step2.tpl @@ -0,0 +1,112 @@ +{* + +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + + + +*} +{$MODULE_TITLE} +
    + + + + + + + + +{foreach from=$instructions key=key item=item name=instructions} +{if $smarty.foreach.instructions.first} + + + + + + + +

    {$INSTRUCTIONS_TITLE}

    + +{/if} + + + + +{if $smarty.foreach.instructions.last} +
    {$item.STEP_NUM}{$item.INSTRUCTION_STEP}
    +
    +{/if} +{/foreach} + +
    + + + + + +
    + + + + + + + + + + +
    {$MOD.LBL_SELECT_FILE}
    + + +
    + {$MOD.LBL_HAS_HEADER}  +
    + + +
    + +
    + + + + +
    +   + +
    + +
    +{$JAVASCRIPT} diff --git a/modules/Import/tpls/step3.tpl b/modules/Import/tpls/step3.tpl new file mode 100644 index 00000000..edf4fe7a --- /dev/null +++ b/modules/Import/tpls/step3.tpl @@ -0,0 +1,369 @@ +{* + +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + + + +*} +{literal} + +{/literal} + +{overlib_includes} +{$MODULE_TITLE} +
    + + + + + + + + + + + + + + + + +
    + {$APP.LBL_REQUIRED_SYMBOL} {$APP.NTC_REQUIRED} +
    + +

    +{$MOD.LBL_SELECT_FIELDS_TO_MAP} +

    +
    + +{foreach from=$rows key=key item=item name=rows} +{if $smarty.foreach.rows.first} + + + {if $HAS_HEADER == 'on'} + + {/if} + + + {if $HAS_HEADER != 'on'} + + {/if} + +{/if} + + + {if $HAS_HEADER == 'on'} + + {/if} + + {if $item.show_remove} + + {else} + {if $HAS_HEADER != 'on'} + + {/if} + + {/if} + +{/foreach} + + + + + + +
    + {$MOD.LBL_DATABASE_FIELD}  + {sugar_help text=$MOD.LBL_DATABASE_FIELD_HELP} + + {$MOD.LBL_HEADER_ROW}  + {sugar_help text=$MOD.LBL_HEADER_ROW_HELP} + + {$MOD.LBL_DEFAULT_VALUE}  + {sugar_help text=$MOD.LBL_DEFAULT_VALUE_HELP} + + {$MOD.LBL_ROW} 1  + {sugar_help text=$MOD.LBL_ROW_HELP} + {$MOD.LBL_ROW} 2
    + + {$item.cell1} + {$item.default_field} + + + {$item.cell1}{$item.cell2}
    + + +        + {$MOD.LBL_SAVE_MAPPING_AS} + + +  {sugar_help text=$MOD.LBL_SAVE_MAPPING_HELP} + +
    +{$JAVASCRIPT_CHOOSER} + +{if $NOTETEXT != '' || $required_fields != ''} +

    +{$MOD.LBL_NOTES} +

      +
    • {$MOD.LBL_REQUIRED_NOTE}{$required_fields}
    • +{$NOTETEXT} +
    +

    +{/if} + +
    + + + + +
    +   + +
    + +
    +{literal} + +{/literal} +{$JAVASCRIPT} +{literal} + +{/literal} diff --git a/modules/Import/tpls/undo.tpl b/modules/Import/tpls/undo.tpl new file mode 100644 index 00000000..a457abb9 --- /dev/null +++ b/modules/Import/tpls/undo.tpl @@ -0,0 +1,65 @@ +{* + +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + + + +*} +{if $UNDO_SUCCESS} +

    {$MOD.LBL_SUCCESS} {$MOD.LBL_LAST_IMPORT_UNDONE}

    +{else} +

    {$MOD.LBL_FAIL} {$MOD.LBL_NO_IMPORT_TO_UNDO}

    +{/if} +
    + + + + +
    + + + + +
    + + +
    +
    +{$JAVASCRIPT} diff --git a/modules/Import/vardefs.php b/modules/Import/vardefs.php new file mode 100644 index 00000000..2e5d7f82 --- /dev/null +++ b/modules/Import/vardefs.php @@ -0,0 +1,237 @@ + 'import_maps', + 'comment' => 'Import mapping control table', + 'fields' => array ( + 'id' => array ( + 'name' => 'id', + 'vname' => 'LBL_ID', + 'type' => 'id', + 'required'=>true, + 'reportable'=>false, + 'comment' => 'Unique identifier', + ), + 'name' => array ( + 'name' => 'name', + 'vname' => 'LBL_NAME', + 'type' => 'varchar', + 'len' => '254', + 'required'=>true, + 'comment' => 'Name of import map', + ), + 'source' => array ( + 'name' => 'source', + 'vname' => 'LBL_SOURCE', + 'type' => 'varchar', + 'len' => '36', + 'required'=>true, + 'comment' => '', + ), + 'enclosure' => array ( + 'name' => 'enclosure', + 'vname' => 'LBL_CUSTOM_ENCLOSURE', + 'type' => 'varchar', + 'len' => '1', + 'required'=>true, + 'comment' => '', + 'default' => ' ', + ), + 'delimiter' => array ( + 'name' => 'delimiter', + 'vname' => 'LBL_CUSTOM_DELIMITER', + 'type' => 'varchar', + 'len' => '1', + 'required'=>true, + 'comment' => '', + 'default' => ',', + ), + 'module' => array ( + 'name' => 'module', + 'vname' => 'LBL_MODULE', + 'type' => 'varchar', + 'len' => '36', + 'required'=>true, + 'comment' => 'Module used for import', + ), + 'content' => array ( + 'name' => 'content', + 'vname' => 'LBL_CONTENT', + 'type' => 'text', + 'comment' => 'Mappings for all columns', + ), + 'default_values' => array ( + 'name' => 'default_values', + 'vname' => 'LBL_CONTENT', + 'type' => 'text', + 'comment' => 'Default Values for all columns', + ), + 'has_header' => array ( + 'name' => 'has_header', + 'vname' => 'LBL_HAS_HEADER', + 'type' => 'bool', + 'default' => '1', + 'required'=>true, + 'comment' => 'Indicator if source file contains a header row', + ), + 'deleted' => array ( + 'name' => 'deleted', + 'vname' => 'LBL_DELETED', + 'type' => 'bool', + 'required'=>false, + 'reportable'=>false, + 'comment' => 'Record deletion indicator', + ), + 'date_entered' => array ( + 'name' => 'date_entered', + 'vname' => 'LBL_DATE_ENTERED', + 'type' => 'datetime', + 'required'=>true, + 'comment' => 'Date record created', + ), + 'date_modified' => array ( + 'name' => 'date_modified', + 'vname' => 'LBL_DATE_MODIFIED', + 'type' => 'datetime', + 'required'=>true, + 'comment' => 'Date record last modified', + ), + 'assigned_user_id' => array ( + 'name' => 'assigned_user_id', + 'rname' => 'user_name', + 'id_name' => 'assigned_user_id', + 'vname' => 'LBL_ASSIGNED_TO', + 'type' => 'assigned_user_name', + 'table' => 'users', + 'isnull' => 'false', + 'dbType' => 'id', + 'reportable'=>false, + 'comment' => 'Assigned-to user', + ), + 'is_published' => array ( + 'name' => 'is_published', + 'vname' => 'LBL_IS_PUBLISHED', + 'type' => 'varchar', + 'len' => '3', + 'required'=>true, + 'default'=>'no', + 'comment' => 'Indicator if mapping is published', + ), + ), + 'indices' => array ( + array( + 'name' =>'import_mapspk', + 'type' =>'primary', + 'fields'=>array('id') + ), + array( + 'name' =>'idx_owner_module_name', + 'type' =>'index', + 'fields'=>array('assigned_user_id','module','name','deleted') + ), + ) + ); + +$dictionary['UsersLastImport'] = array ( + 'table' => 'users_last_import', + 'comment' => 'Maintains rows last imported by user', + 'fields' => array ( + 'id' => array ( + 'name' => 'id', + 'vname' => 'LBL_ID', + 'type' => 'id', + 'required'=>true, + 'reportable'=>false, + 'comment' => 'Unique identifier' + ), + 'assigned_user_id' => array ( + 'name' => 'assigned_user_id', + 'rname' => 'user_name', + 'id_name' => 'assigned_user_id', + 'vname' => 'LBL_ASSIGNED_TO', + 'type' => 'assigned_user_name', + 'table' => 'users', + 'isnull' => 'false', + 'dbType' => 'id', + 'reportable'=>false, + 'comment' => 'User assigned to this record' + ), + 'import_module' => array ( + 'name' => 'import_module', + 'vname' => 'LBL_BEAN_TYPE', + 'type' => 'varchar', + 'len' => '36', + 'comment' => 'Module for which import occurs' + ), + 'bean_type' => array ( + 'name' => 'bean_type', + 'vname' => 'LBL_BEAN_TYPE', + 'type' => 'varchar', + 'len' => '36', + 'comment' => 'Bean type for which import occurs' + ), + 'bean_id' => array ( + 'name' => 'bean_id', + 'vname' => 'LBL_BEAN_ID', + 'type' => 'id', + 'reportable'=>false, + 'comment' => 'ID of item identified by bean_type' + ), + 'deleted' => array ( + 'name' => 'deleted', + 'vname' => 'LBL_DELETED', + 'type' => 'bool', + 'reportable'=>false, + 'required'=>false, + 'comment' => 'Record deletion indicator' + ), + ), + 'indices' => array ( + array( + 'name' =>'users_last_importpk', + 'type' =>'primary', + 'fields'=>array('id') + ), + array( + 'name' =>'idx_user_id', + 'type' =>'index', + 'fields'=>array('assigned_user_id') + ) + ) + ); +?> diff --git a/modules/Import/views/view.error.php b/modules/Import/views/view.error.php new file mode 100644 index 00000000..ae98e365 --- /dev/null +++ b/modules/Import/views/view.error.php @@ -0,0 +1,102 @@ +ss->assign("IMPORT_MODULE", $_REQUEST['import_module']); + $this->ss->assign("ACTION", 'Step1'); + $this->ss->assign("MESSAGE",$_REQUEST['message']); + $this->ss->assign("SOURCE",""); + if ( isset($_REQUEST['source']) ) + $this->ss->assign("SOURCE", $_REQUEST['source']); + + $this->ss->display('modules/Import/tpls/error.tpl'); + } +} diff --git a/modules/Import/views/view.last.php b/modules/Import/views/view.last.php new file mode 100644 index 00000000..ed2a1c10 --- /dev/null +++ b/modules/Import/views/view.last.php @@ -0,0 +1,303 @@ +getModuleTitleIconPath($this->module); + $returnArray = array(); + if (!empty($iconPath) && !$browserTitle) { + $returnArray[] = "{$app_list_strings["; + } + else { + $returnArray[] = $app_list_strings['moduleList'][$_REQUEST['import_module']]; + } + $returnArray[] = "".$mod_strings['LBL_MODULE_NAME'].""; + $returnArray[] = $mod_strings['LBL_RESULTS']; + + return $returnArray; + } + + /** + * @see SugarView::display() + */ + public function display() + { + global $mod_strings, $app_strings, $current_user, $sugar_config, $current_language; + + $this->ss->assign("IMPORT_MODULE", $_REQUEST['import_module']); + $this->ss->assign("TYPE", $_REQUEST['type']); + $this->ss->assign("HEADER", $app_strings['LBL_IMPORT']." ". $mod_strings['LBL_MODULE_NAME']); + $this->ss->assign("MODULE_TITLE", $this->getModuleTitle()); + // lookup this module's $mod_strings to get the correct module name + $module_mod_strings = + return_module_language($current_language, $_REQUEST['import_module']); + $this->ss->assign("MODULENAME",$module_mod_strings['LBL_MODULE_NAME']); + + $this->ss->assign("JAVASCRIPT", $this->_getJS()); + + // read status file to get totals for records imported, errors, and duplicates + $count = 0; + $errorCount = 0; + $dupeCount = 0; + $createdCount = 0; + $updatedCount = 0; + $fp = sugar_fopen(ImportCacheFiles::getStatusFileName(),'r'); + while (( $row = fgetcsv($fp, 8192) ) !== FALSE) { + $count += (int) $row[0]; + $errorCount += (int) $row[1]; + $dupeCount += (int) $row[2]; + $createdCount += (int) $row[3]; + $updatedCount += (int) $row[4]; + } + fclose($fp); + + $this->ss->assign("noSuccess",FALSE); + if(($count == $errorCount) || ($dupeCount == $count)){ + $this->ss->assign("noSuccess",TRUE); + } + + $this->ss->assign("errorCount",$errorCount); + $this->ss->assign("dupeCount",$dupeCount); + $this->ss->assign("createdCount",$createdCount); + $this->ss->assign("updatedCount",$updatedCount); + $this->ss->assign("errorFile",ImportCacheFiles::getErrorFileName()); + $this->ss->assign("errorrecordsFile",ImportCacheFiles::getErrorRecordsFileName()); + $this->ss->assign("dupeFile",ImportCacheFiles::getDuplicateFileName()); + + if ( $this->bean->object_name == "Prospect" ) { + $this->ss->assign("PROSPECTLISTBUTTON", + $this->_addToProspectListButton()); + } + else { + $this->ss->assign("PROSPECTLISTBUTTON",""); + } + + $this->ss->display('modules/Import/tpls/last.tpl'); + + foreach ( UsersLastImport::getBeansByImport($_REQUEST['import_module']) as $beanname ) { + // load bean + if ( !( $this->bean instanceof $beanname ) ) { + $this->bean = new $beanname; + } + // build listview to show imported records + require_once('include/ListView/ListViewFacade.php'); + $lvf = new ListViewFacade($this->bean, $this->bean->module_dir, 0); + + $params = array(); + if(!empty($_REQUEST['orderBy'])) { + $params['orderBy'] = $_REQUEST['orderBy']; + $params['overrideOrder'] = true; + if(!empty($_REQUEST['sortOrder'])) $params['sortOrder'] = $_REQUEST['sortOrder']; + } + $beanname = ($this->bean->object_name == 'Case' ? 'aCase' : $this->bean->object_name); + // add users_last_import joins so we only show records done in this import + $params['custom_from'] = ', users_last_import'; + $params['custom_where'] = " AND users_last_import.assigned_user_id = '{$GLOBALS['current_user']->id}' + AND users_last_import.bean_type = '{$beanname}' + AND users_last_import.bean_id = {$this->bean->table_name}.id + AND users_last_import.deleted = 0 + AND {$this->bean->table_name}.deleted = 0"; + $where = " {$this->bean->table_name}.id IN ( + SELECT users_last_import.bean_id + FROM users_last_import + WHERE users_last_import.assigned_user_id = '{$GLOBALS['current_user']->id}' + AND users_last_import.bean_type = '{$beanname}' + AND users_last_import.deleted = 0 )"; + + $lbl_last_imported = $mod_strings['LBL_LAST_IMPORTED']; + $lvf->lv->mergeduplicates = false; + $lvf->lv->showMassupdateFields = false; + if ( $lvf->type == 2 ) { + $lvf->template = 'include/ListView/ListViewNoMassUpdate.tpl'; + } + $module_mod_strings = return_module_language($current_language, $this->bean->module_dir); + $lvf->setup('', $where, $params, $module_mod_strings, 0, -1, '', strtoupper($beanname), array(), 'id'); + $lvf->display($lbl_last_imported.": ".$module_mod_strings['LBL_MODULE_NAME']); + } + } + + /** + * Returns JS used in this view + */ + private function _getJS() + { + return << + + + +EOJAVASCRIPT; + } + /** + * Returns a button to add this list of prospects to a Target List + * + * @return string html code to display button + */ + private function _addToProspectListButton() + { + global $app_strings, $sugar_version, $sugar_config, $current_user; + + $query = "SELECT distinct + prospects.id, + prospects.assigned_user_id, + prospects.first_name, + prospects.last_name, + prospects.phone_work, + prospects.title, + email_addresses.email_address email1, + users.user_name as assigned_user_name + FROM users_last_import,prospects + LEFT JOIN users + ON prospects.assigned_user_id=users.id + LEFT JOIN email_addr_bean_rel on prospects.id = email_addr_bean_rel.bean_id and email_addr_bean_rel.bean_module='Prospect' and email_addr_bean_rel.primary_address=1 and email_addr_bean_rel.deleted=0 + LEFT JOIN email_addresses on email_addresses.id = email_addr_bean_rel.email_address_id + + WHERE + users_last_import.assigned_user_id= + '{$current_user->id}' + AND users_last_import.bean_type='Prospect' + AND users_last_import.bean_id=prospects.id + AND users_last_import.deleted=0 + AND prospects.deleted=0 + "; + + $popup_request_data = array( + 'call_back_function' => 'set_return_and_save_background', + 'form_name' => 'DetailView', + 'field_to_name_array' => array( + 'id' => 'subpanel_id', + ), + 'passthru_data' => array( + 'child_field' => 'notused', + 'return_url' => 'notused', + 'link_field_name' => 'notused', + 'module_name' => 'notused', + 'refresh_page'=>'1', + 'return_type'=>'addtoprospectlist', + 'parent_module'=>'ProspectLists', + 'parent_type'=>'ProspectList', + 'child_id'=>'id', + 'link_attribute'=>'prospects', + 'link_type'=>'default', //polymorphic or default + ) + ); + + $popup_request_data['passthru_data']['query'] = urlencode($query); + + $json = getJSONobj(); + $encoded_popup_request_data = $json->encode($popup_request_data); + + return << + +EOHTML; + + } +} +?> diff --git a/modules/Import/views/view.step1.php b/modules/Import/views/view.step1.php new file mode 100644 index 00000000..645a9887 --- /dev/null +++ b/modules/Import/views/view.step1.php @@ -0,0 +1,324 @@ +getModuleTitleIconPath($this->module); + $returnArray = array(); + if (!empty($iconPath) && !$browserTitle) { + $returnArray[] = "{$app_list_strings["; + } + else { + $returnArray[] = $app_list_strings['moduleList'][$_REQUEST['import_module']]; + } + $returnArray[] = "".$mod_strings['LBL_MODULE_NAME'].""; + $returnArray[] = $mod_strings['LBL_STEP_1_TITLE']; + + return $returnArray; + } + + /** + * @see SugarView::display() + */ + public function display() + { + global $mod_strings, $app_strings, $current_user; + global $sugar_config; + + $this->ss->assign("MODULE_TITLE", $this->getModuleTitle()); + $this->ss->assign("DELETE_INLINE_PNG", SugarThemeRegistry::current()->getImage('delete_inline','align="absmiddle" alt="'.$app_strings['LNK_DELETE'].'" border="0"')); + $this->ss->assign("PUBLISH_INLINE_PNG", SugarThemeRegistry::current()->getImage('publish_inline','align="absmiddle" alt="'.$mod_strings['LBL_PUBLISH'].'" border="0"')); + $this->ss->assign("UNPUBLISH_INLINE_PNG", SugarThemeRegistry::current()->getImage('unpublish_inline','align="absmiddle" alt="'.$mod_strings['LBL_UNPUBLISH'].'" border="0"')); + $this->ss->assign("IMPORT_MODULE", $_REQUEST['import_module']); + $this->ss->assign("JAVASCRIPT", $this->_getJS()); + + + // handle publishing and deleting import maps + if (isset($_REQUEST['delete_map_id'])) { + $import_map = new ImportMap(); + $import_map->mark_deleted($_REQUEST['delete_map_id']); + } + + if (isset($_REQUEST['publish']) ) { + $import_map = new ImportMap(); + $result = 0; + + $import_map = $import_map->retrieve($_REQUEST['import_map_id'], false); + + if ($_REQUEST['publish'] == 'yes') { + $result = $import_map->mark_published($current_user->id,true); + if (!$result) { + $this->ss->assign("ERROR",$mod_strings['LBL_ERROR_UNABLE_TO_PUBLISH']); + } + } + elseif ( $_REQUEST['publish'] == 'no') { + // if you don't own this importmap, you do now! + // unless you have a map by the same name + $result = $import_map->mark_published($current_user->id,false); + if (!$result) { + $this->ss->assign("ERROR",$mod_strings['LBL_ERROR_UNABLE_TO_UNPUBLISH']); + } + } + + } + + // trigger showing other software packages + $this->ss->assign("show_salesforce",false); + $this->ss->assign("show_outlook",false); + $this->ss->assign("show_act",false); + switch ($_REQUEST['import_module']) { + case "Prospects": + break; + case "Accounts": + $this->ss->assign("show_salesforce",true); + $this->ss->assign("show_act",true); + break; + case "Contacts": + $this->ss->assign("show_salesforce",true); + $this->ss->assign("show_outlook",true); + $this->ss->assign("show_act",true); + break; + default: + $this->ss->assign("show_salesforce",true); + break; + } + + // show any custom mappings + if (sugar_is_dir('custom/modules/Import') && $dir = opendir('custom/modules/Import')) { + while (($file = readdir('custom/modules/Import')) !== false) { + if ($file == ".." + || $file == "." + || $file == ".svn" + || $file == "CVS" + || $file == "Attic" + || !sugar_is_dir("./$dirPath".$file) + || sugar_is_file("modules/Import/{$file}") + ) + continue; + require_once("custom/modules/Import/{$file}"); + $classname = str_replace('.php','',$file); + $mappingClass = new $classname; + $custom_mappings[] = $mappingClass->name; + } + } + + + // get user defined import maps + $this->ss->assign('is_admin',is_admin($current_user)); + $import_map_seed = new ImportMap(); + $custom_imports_arr = $import_map_seed->retrieve_all_by_string_fields( + array( + 'assigned_user_id' => $current_user->id, + 'is_published' => 'no', + 'module' => $_REQUEST['import_module'], + ) + ); + + if ( count($custom_imports_arr) ) { + $custom = array(); + foreach ( $custom_imports_arr as $import) { + $custom[] = array( + "IMPORT_NAME" => $import->name, + "IMPORT_ID" => $import->id, + ); + } + $this->ss->assign('custom_imports',$custom); + } + + // get globally defined import maps + $published_imports_arr = $import_map_seed->retrieve_all_by_string_fields( + array( + 'is_published' => 'yes', + 'module' => $_REQUEST['import_module'], + ) + ); + + if ( count($published_imports_arr) ) { + $published = array(); + foreach ( $published_imports_arr as $import) { + $published[] = array( + "IMPORT_NAME" => $import->name, + "IMPORT_ID" => $import->id, + ); + } + $this->ss->assign('published_imports',$published); + } + + $this->ss->display('modules/Import/tpls/step1.tpl'); + } + + /** + * Returns JS used in this view + */ + private function _getJS() + { + global $mod_strings; + + return << + + + +EOJAVASCRIPT; + } +} + +?> diff --git a/modules/Import/views/view.step2.php b/modules/Import/views/view.step2.php new file mode 100644 index 00000000..ef15dace --- /dev/null +++ b/modules/Import/views/view.step2.php @@ -0,0 +1,252 @@ +getModuleTitleIconPath($this->module); + $returnArray = array(); + if (!empty($iconPath) && !$browserTitle) { + $returnArray[] = "{$app_list_strings["; + } + else { + $returnArray[] = $app_list_strings['moduleList'][$_REQUEST['import_module']]; + } + $returnArray[] = "".$mod_strings['LBL_MODULE_NAME'].""; + $returnArray[] = $mod_strings['LBL_STEP_2_TITLE']; + + return $returnArray; + } + + /** + * @see SugarView::display() + */ + public function display() + { + global $mod_strings, $app_list_strings, $app_strings, $current_user, $import_bean_map; + global $import_mod_strings; + + $this->ss->assign("MODULE_TITLE", $this->getModuleTitle()); + $this->ss->assign("IMP", $import_mod_strings); + $this->ss->assign("TYPE",( !empty($_REQUEST['type']) ? $_REQUEST['type'] : "import" )); + $this->ss->assign("CUSTOM_DELIMITER", + ( !empty($_REQUEST['custom_delimiter']) ? $_REQUEST['custom_delimiter'] : "," )); + $this->ss->assign("CUSTOM_ENCLOSURE",htmlentities( + ( !empty($_REQUEST['custom_enclosure']) && $_REQUEST['custom_enclosure'] != 'other' + ? $_REQUEST['custom_enclosure'] : + ( !empty($_REQUEST['custom_enclosure_other']) + ? $_REQUEST['custom_enclosure_other'] : "" ) ))); + + $this->ss->assign("IMPORT_MODULE", $_REQUEST['import_module']); + $this->ss->assign("HEADER", $app_strings['LBL_IMPORT']." ". $mod_strings['LBL_MODULE_NAME']); + $this->ss->assign("JAVASCRIPT", $this->_getJS()); + + // special for importing from Outlook + if ($_REQUEST['source'] == "outlook") { + $this->ss->assign("SOURCE", $_REQUEST['source']); + $this->ss->assign("SOURCE_NAME","Outlook "); + $this->ss->assign("HAS_HEADER_CHECKED"," CHECKED"); + } + // see if the source starts with 'custom' + // if so, pull off the id, load that map, and get the name + elseif ( strncasecmp("custom:",$_REQUEST['source'],7) == 0) { + $id = substr($_REQUEST['source'],7); + $import_map_seed = new ImportMap(); + $import_map_seed->retrieve($id, false); + + $this->ss->assign("SOURCE_ID", $import_map_seed->id); + $this->ss->assign("SOURCE_NAME", $import_map_seed->name); + $this->ss->assign("SOURCE", $import_map_seed->source); + if (isset($import_map_seed->delimiter)) + $this->ss->assign("CUSTOM_DELIMITER", $import_map_seed->delimiter); + if (isset($import_map_seed->enclosure)) + $this->ss->assign("CUSTOM_ENCLOSURE", htmlentities($import_map_seed->enclosure)); + if ($import_map_seed->has_header) + $this->ss->assign("HAS_HEADER_CHECKED"," CHECKED"); + } + else { + $classname = 'ImportMap' . ucfirst($_REQUEST['source']); + if ( file_exists("modules/Import/{$classname}.php") ) + require_once("modules/Import/{$classname}.php"); + elseif ( file_exists("custom/modules/Import/{$classname}.php") ) + require_once("custom/modules/Import/{$classname}.php"); + else { + require_once("custom/modules/Import/ImportMapOther.php"); + $classname = 'ImportMapOther'; + $_REQUEST['source'] = 'other'; + } + if ( class_exists($classname) ) { + $import_map_seed = new $classname; + if (isset($import_map_seed->delimiter)) + $this->ss->assign("CUSTOM_DELIMITER", $import_map_seed->delimiter); + if (isset($import_map_seed->enclosure)) + $this->ss->assign("CUSTOM_ENCLOSURE", htmlentities($import_map_seed->enclosure)); + if ($import_map_seed->has_header) + $this->ss->assign("HAS_HEADER_CHECKED"," CHECKED"); + $this->ss->assign("SOURCE", $_REQUEST['source']); + } + } + + // add instructions for anything other than custom_delimited + if ($_REQUEST['source'] != 'other') + { + $instructions = array(); + $lang_key = ''; + switch($_REQUEST['source']) { + case "act": + $lang_key = "ACT"; + break; + case "outlook": + $lang_key = "OUTLOOK"; + break; + case "salesforce": + $lang_key = "SF"; + break; + case "tab": + $lang_key = "TAB"; + break; + case "csv": + $lang_key = "CUSTOM"; + break; + case "other": + break; + default: + $lang_key = "CUSTOM_MAPPING_".strtoupper($import_map_seed->name); + break; + } + if ( $lang_key != '' ) { + for ($i = 1; isset($mod_strings["LBL_{$lang_key}_NUM_$i"]);$i++) { + $instructions[] = array( + "STEP_NUM" => $mod_strings["LBL_NUM_$i"], + "INSTRUCTION_STEP" => $mod_strings["LBL_{$lang_key}_NUM_$i"], + ); + } + $this->ss->assign("INSTRUCTIONS_TITLE",$mod_strings["LBL_IMPORT_{$lang_key}_TITLE"]); + $this->ss->assign("instructions",$instructions); + } + } + + $this->ss->display('modules/Import/tpls/step2.tpl'); + } + + /** + * Returns JS used in this view + */ + private function _getJS() + { + global $mod_strings; + + return << + + + +EOJAVASCRIPT; + } +} diff --git a/modules/Import/views/view.step3.php b/modules/Import/views/view.step3.php new file mode 100644 index 00000000..be5a1cc0 --- /dev/null +++ b/modules/Import/views/view.step3.php @@ -0,0 +1,793 @@ +getModuleTitleIconPath($this->module); + $returnArray = array(); + if (!empty($iconPath) && !$browserTitle) { + $returnArray[] = "{$app_list_strings["; + } + else { + $returnArray[] = $app_list_strings['moduleList'][$_REQUEST['import_module']]; + } + $returnArray[] = "".$mod_strings['LBL_MODULE_NAME'].""; + $returnArray[] = $mod_strings['LBL_STEP_3_TITLE']; + + return $returnArray; + } + + /** + * @see SugarView::display() + */ + public function display() + { + global $mod_strings, $app_strings, $current_user, $sugar_config, $app_list_strings, $locale; + + $this->ss->assign("IMPORT_MODULE", $_REQUEST['import_module']); + $has_header = ( isset( $_REQUEST['has_header']) ? 1 : 0 ); + $sugar_config['import_max_records_per_file'] = + ( empty($sugar_config['import_max_records_per_file']) + ? 1000 : $sugar_config['import_max_records_per_file'] ); + + // Clear out this user's last import + $seedUsersLastImport = new UsersLastImport(); + $seedUsersLastImport->mark_deleted_by_user_id($current_user->id); + ImportCacheFiles::clearCacheFiles(); + + // attempt to lookup a preexisting field map + // use the custom one if specfied to do so in step 1 + $field_map = array(); + $default_values = array(); + $ignored_fields = array(); + if ( !empty( $_REQUEST['source_id'])) { + $mapping_file = new ImportMap(); + $mapping_file->retrieve( $_REQUEST['source_id'],false); + $_REQUEST['source'] = $mapping_file->source; + $has_header = $mapping_file->has_header; + if (isset($mapping_file->delimiter)) + $_REQUEST['custom_delimiter'] = $mapping_file->delimiter; + if (isset($mapping_file->enclosure)) + $_REQUEST['custom_enclosure'] = htmlentities($mapping_file->enclosure); + $field_map = $mapping_file->getMapping(); + $default_values = $mapping_file->getDefaultValues(); + $this->ss->assign("MAPNAME",$mapping_file->name); + $this->ss->assign("CHECKMAP",'checked="checked" value="on"'); + } + else { + // Try to see if we have a custom mapping we can use + // based upon the where the records are coming from + // and what module we are importing into + $classname = 'ImportMap' . ucfirst($_REQUEST['source']); + if ( file_exists("modules/Import/{$classname}.php") ) + require_once("modules/Import/{$classname}.php"); + elseif ( file_exists("custom/modules/Import/{$classname}.php") ) + require_once("custom/modules/Import/{$classname}.php"); + else { + require_once("custom/modules/Import/ImportMapOther.php"); + $classname = 'ImportMapOther'; + $_REQUEST['source'] = 'other'; + } + if ( class_exists($classname) ) { + $mapping_file = new $classname; + if (isset($mapping_file->delimiter)) + $_REQUEST['custom_delimiter'] = $mapping_file->delimiter; + if (isset($mapping_file->enclosure)) + $_REQUEST['custom_enclosure'] = htmlentities($mapping_file->enclosure); + $ignored_fields = $mapping_file->getIgnoredFields($_REQUEST['import_module']); + $field_map = $mapping_file->getMapping($_REQUEST['import_module']); + } + } + + $this->ss->assign("CUSTOM_DELIMITER", + ( !empty($_REQUEST['custom_delimiter']) ? $_REQUEST['custom_delimiter'] : "," )); + $this->ss->assign("CUSTOM_ENCLOSURE", + ( !empty($_REQUEST['custom_enclosure']) ? $_REQUEST['custom_enclosure'] : "" )); + + // handle uploaded file + $uploadFile = new UploadFile('userfile'); + if (isset($_FILES['userfile']) && $uploadFile->confirm_upload()) + { + $uploadFile->final_move('IMPORT_'.$this->bean->object_name.'_'.$current_user->id); + $uploadFileName = $uploadFile->get_upload_path('IMPORT_'.$this->bean->object_name.'_'.$current_user->id); + } + else { + $this->_showImportError($mod_strings['LBL_IMPORT_MODULE_ERROR_NO_UPLOAD'],$_REQUEST['import_module'],'Step2'); + return; + } + + // split file into parts + $splitter = new ImportFileSplitter( + $uploadFileName, + $sugar_config['import_max_records_per_file']); + $splitter->splitSourceFile( + $_REQUEST['custom_delimiter'], + html_entity_decode($_REQUEST['custom_enclosure'],ENT_QUOTES), + $has_header + ); + + // Now parse the file and look for errors + $importFile = new ImportFile( + $uploadFileName, + $_REQUEST['custom_delimiter'], + html_entity_decode($_REQUEST['custom_enclosure'],ENT_QUOTES) + ); + + if ( !$importFile->fileExists() ) { + $this->_showImportError($mod_strings['LBL_CANNOT_OPEN'],$_REQUEST['import_module'],'Step2'); + return; + } + + // retrieve first 3 rows + $rows = array(); + $system_charset = $locale->default_export_charset; + $user_charset = $locale->getExportCharset(); + $other_charsets = 'UTF-8, UTF-7, ASCII, CP1252, EUC-JP, SJIS, eucJP-win, SJIS-win, JIS, ISO-2022-JP'; + $detectable_charsets = "UTF-8, {$user_charset}, {$system_charset}, {$other_charsets}"; + // Bug 26824 - mb_detect_encoding() thinks CP1252 is IS0-8859-1, so use that instead in the encoding list passed to the function + $detectable_charsets = str_replace('CP1252','ISO-8859-1',$detectable_charsets); + $charset_for_import = $user_charset; //We will set the default import charset option by user's preference. + $able_to_detect = function_exists('mb_detect_encoding'); + for ( $i = 0; $i < 3; $i++ ) { + $rows[$i] = $importFile->getNextRow(); + if(!empty($rows[$i]) && $able_to_detect) { + foreach($rows[$i] as & $temp_value) { + $current_charset = mb_detect_encoding($temp_value, $detectable_charsets); + if(!empty($current_charset) && $current_charset != "UTF-8") { + $temp_value = $locale->translateCharset($temp_value, $current_charset);// we will use utf-8 for displaying the data on the page. + $charset_for_import = $current_charset; + //set the default import charset option according to the current_charset. + //If it is not utf-8, tt may be overwritten by the later one. So the uploaded file should not contain two types of charset($user_charset, $system_charset), and I think this situation will not occur. + } + } + } + } + $ret_field_count = $importFile->getFieldCount(); + + // Bug 14689 - Parse the first data row to make sure it has non-empty data in it + $isempty = true; + if ( $rows[(int)$has_header] != false ) { + foreach ( $rows[(int)$has_header] as $value ) { + if ( strlen(trim($value)) > 0 ) { + $isempty = false; + break; + } + } + } + + if ($isempty || $rows[(int)$has_header] == false) { + $this->_showImportError($mod_strings['LBL_NO_LINES'],$_REQUEST['import_module'],'Step2'); + return; + } + + // save first row to send to step 4 + $this->ss->assign("FIRSTROW", base64_encode(serialize($rows[0]))); + + // Now build template + $this->ss->assign("TMP_FILE", $uploadFileName ); + $this->ss->assign("FILECOUNT", $splitter->getFileCount() ); + $this->ss->assign("RECORDCOUNT", $splitter->getRecordCount() ); + $this->ss->assign("RECORDTHRESHOLD", $sugar_config['import_max_records_per_file']); + $this->ss->assign("SOURCE", $_REQUEST['source'] ); + $this->ss->assign("TYPE", $_REQUEST['type'] ); + $this->ss->assign("DELETE_INLINE_PNG", SugarThemeRegistry::current()->getImage('basic_search','align="absmiddle" alt="'.$app_strings['LNK_DELETE'].'" border="0"')); + $this->ss->assign("PUBLISH_INLINE_PNG", SugarThemeRegistry::current()->getImage('advanced_search','align="absmiddle" alt="'.$mod_strings['LBL_PUBLISH'].'" border="0"')); + $this->ss->assign("MODULE_TITLE", $this->getModuleTitle()); + $this->ss->assign("STEP4_TITLE", + strip_tags(str_replace("\n","",getClassicModuleTitle( + $mod_strings['LBL_MODULE_NAME'], + array($mod_strings['LBL_MODULE_NAME'],$mod_strings['LBL_STEP_4_TITLE']), + false + ))) + ); + $this->ss->assign("HEADER", $app_strings['LBL_IMPORT']." ". $mod_strings['LBL_MODULE_NAME']); + + // we export it as email_address, but import as email1 + $field_map['email_address'] = 'email1'; + + // build each row; row count is determined by the the number of fields in the import file + $columns = array(); + $mappedFields = array(); + + for($field_count = 0; $field_count < $ret_field_count; $field_count++) { + // See if we have any field map matches + $defaultValue = ""; + // Bug 31260 - If the data rows have more columns than the header row, then just add a new header column + if ( !isset($rows[0][$field_count]) ) + $rows[0][$field_count] = ''; + // See if we can match the import row to a field in the list of fields to import + $firstrow_name = trim(str_replace(":","",$rows[0][$field_count])); + if ($has_header && isset( $field_map[$firstrow_name] ) ) { + $defaultValue = $field_map[$firstrow_name]; + } + elseif (isset($field_map[$field_count])) { + $defaultValue = $field_map[$field_count]; + } + elseif (empty( $_REQUEST['source_id'])) { + $defaultValue = trim($rows[0][$field_count]); + } + + // build string of options + $fields = $this->bean->get_importable_fields(); + $options = array(); + $defaultField = ''; + foreach ( $fields as $fieldname => $properties ) { + // get field name + if (!empty ($properties['vname'])) + $displayname = str_replace(":","",translate($properties['vname'] ,$this->bean->module_dir)); + else + $displayname = str_replace(":","",translate($properties['name'] ,$this->bean->module_dir)); + // see if this is required + $req_mark = ""; + $req_class = ""; + if ( array_key_exists($fieldname, $this->bean->get_import_required_fields()) ) { + $req_mark = ' ' . $app_strings['LBL_REQUIRED_SYMBOL']; + $req_class = ' class="required" '; + } + // see if we have a match + $selected = ''; + if ( !empty($defaultValue) && !in_array($fieldname,$mappedFields) + && !in_array($fieldname,$ignored_fields) ) { + if ( strtolower($fieldname) == strtolower($defaultValue) + || strtolower($fieldname) == str_replace(" ","_",strtolower($defaultValue)) + || strtolower($displayname) == strtolower($defaultValue) + || strtolower($displayname) == str_replace(" ","_",strtolower($defaultValue)) ) { + $selected = ' selected="selected" '; + $defaultField = $fieldname; + $mappedFields[] = $fieldname; + } + } + // get field type information + $fieldtype = ''; + if ( isset($properties['type']) + && isset($mod_strings['LBL_IMPORT_FIELDDEF_' . strtoupper($properties['type'])]) ) + $fieldtype = ' [' . $mod_strings['LBL_IMPORT_FIELDDEF_' . strtoupper($properties['type'])] . '] '; + if ( isset($properties['comment']) ) + $fieldtype .= ' - ' . $properties['comment']; + $options[$displayname.$fieldname] = '\n'; + } + + // get default field value + $defaultFieldHTML = ''; + if ( !empty($defaultField) ) { + $defaultFieldHTML = getControl( + $_REQUEST['import_module'], + $defaultField, + $fields[$defaultField], + ( isset($default_values[$defaultField]) ? $default_values[$defaultField] : '' ) + ); + } + + if ( isset($default_values[$defaultField]) ) + unset($default_values[$defaultField]); + + // Bug 27046 - Sort the column name picker alphabetically + ksort($options); + + $columns[] = array( + 'field_choices' => implode('',$options), + 'default_field' => $defaultFieldHTML, + 'cell1' => str_replace(""",'',htmlspecialchars($rows[0][$field_count])), + 'cell2' => str_replace(""",'',htmlspecialchars($rows[1][$field_count])), + 'cell3' => str_replace(""",'',htmlspecialchars($rows[2][$field_count])), + 'show_remove' => false, + ); + } + + // add in extra defaulted fields if they are in the mapping record + if ( count($default_values) > 0 ) { + foreach ( $default_values as $field_name => $default_value ) { + // build string of options + $fields = $this->bean->get_importable_fields(); + $options = array(); + $defaultField = ''; + foreach ( $fields as $fieldname => $properties ) { + // get field name + if (!empty ($properties['vname'])) + $displayname = str_replace(":","",translate($properties['vname'] ,$this->bean->module_dir)); + else + $displayname = str_replace(":","",translate($properties['name'] ,$this->bean->module_dir)); + // see if this is required + $req_mark = ""; + $req_class = ""; + if ( array_key_exists($fieldname, $this->bean->get_import_required_fields()) ) { + $req_mark = ' ' . $app_strings['LBL_REQUIRED_SYMBOL']; + $req_class = ' class="required" '; + } + // see if we have a match + $selected = ''; + if ( strtolower($fieldname) == strtolower($field_name) + && !in_array($fieldname,$mappedFields) + && !in_array($fieldname,$ignored_fields) ) { + $selected = ' selected="selected" '; + $defaultField = $fieldname; + $mappedFields[] = $fieldname; + } + // get field type information + $fieldtype = ''; + if ( isset($properties['type']) + && isset($mod_strings['LBL_IMPORT_FIELDDEF_' . strtoupper($properties['type'])]) ) + $fieldtype = ' [' . $mod_strings['LBL_IMPORT_FIELDDEF_' . strtoupper($properties['type'])] . '] '; + if ( isset($properties['comment']) ) + $fieldtype .= ' - ' . $properties['comment']; + $options[$displayname.$fieldname] = '\n'; + } + + // get default field value + $defaultFieldHTML = ''; + if ( !empty($defaultField) ) { + $defaultFieldHTML = getControl( + $_REQUEST['import_module'], + $defaultField, + $fields[$defaultField], + $default_value + ); + } + + // Bug 27046 - Sort the column name picker alphabetically + ksort($options); + + $columns[] = array( + 'field_choices' => implode('',$options), + 'default_field' => $defaultFieldHTML, + 'show_remove' => true, + ); + + $ret_field_count++; + } + } + + $this->ss->assign("COLUMNCOUNT",$ret_field_count); + $this->ss->assign("rows",$columns); + + // get list of valid date/time formats + $timeFormat = $current_user->getUserDateTimePreferences(); + $timeOptions = get_select_options_with_id($sugar_config['time_formats'], $timeFormat['time']); + $dateOptions = get_select_options_with_id($sugar_config['date_formats'], $timeFormat['date']); + $this->ss->assign('TIMEOPTIONS', $timeOptions); + $this->ss->assign('DATEOPTIONS', $dateOptions); + $this->ss->assign('datetimeformat', $GLOBALS['timedate']->get_cal_date_time_format()); + + // get list of valid timezones + $userTZ = $current_user->getPreference('timezone'); + if(empty($userTZ)) + $userTZ = TimeDate::userTimezone(); + + $this->ss->assign('TIMEZONE_CURRENT', $userTZ); + $this->ss->assign('TIMEZONEOPTIONS', TimeDate::getTimezoneList()); + + // get currency preference + require_once('modules/Currencies/ListCurrency.php'); + $currency = new ListCurrency(); + $cur_id = $locale->getPrecedentPreference('currency', $current_user); + if($cur_id) { + $selectCurrency = $currency->getSelectOptions($cur_id); + $this->ss->assign("CURRENCY", $selectCurrency); + } else { + $selectCurrency = $currency->getSelectOptions(); + $this->ss->assign("CURRENCY", $selectCurrency); + } + + $currenciesVars = ""; + $i=0; + foreach($locale->currencies as $id => $arrVal) { + $currenciesVars .= "currencies[{$i}] = '{$arrVal['symbol']}';\n"; + $i++; + } + $currencySymbolsJs = <<ss->assign('currencySymbolJs', $currencySymbolsJs); + + + // fill significant digits dropdown + $significantDigits = $locale->getPrecedentPreference('default_currency_significant_digits', $current_user); + $sigDigits = ''; + for($i=0; $i<=6; $i++) { + if($significantDigits == $i) { + $sigDigits .= ''; + } else { + $sigDigits .= ''; + } + } + + $this->ss->assign('sigDigits', $sigDigits); + + $num_grp_sep = $current_user->getPreference('num_grp_sep'); + $dec_sep = $current_user->getPreference('dec_sep'); + $this->ss->assign("NUM_GRP_SEP", + ( empty($num_grp_sep) + ? $sugar_config['default_number_grouping_seperator'] : $num_grp_sep )); + $this->ss->assign("DEC_SEP", + ( empty($dec_sep) + ? $sugar_config['default_decimal_seperator'] : $dec_sep )); + $this->ss->assign('getNumberJs', $locale->getNumberJs()); + + // Name display format + $this->ss->assign('default_locale_name_format', $locale->getLocaleFormatMacro($current_user)); + $this->ss->assign('getNameJs', $locale->getNameJs()); + + // Charset + $charsetOptions = get_select_options_with_id( + $locale->getCharsetSelect(), $charset_for_import);//wdong, bug 25927, here we should use the charset testing results from above. + $this->ss->assign('CHARSETOPTIONS', $charsetOptions); + + // handle building index selector + global $dictionary, $current_language; + + require_once("include/templates/TemplateGroupChooser.php"); + + $chooser_array = array(); + $chooser_array[0] = array(); + $idc = new ImportDuplicateCheck($this->bean); + $chooser_array[1] = $idc->getDuplicateCheckIndexes(); + + $chooser = new TemplateGroupChooser(); + $chooser->args['id'] = 'selected_indices'; + $chooser->args['values_array'] = $chooser_array; + $chooser->args['left_name'] = 'choose_index'; + $chooser->args['right_name'] = 'ignore_index'; + $chooser->args['left_label'] = $mod_strings['LBL_INDEX_USED']; + $chooser->args['right_label'] = $mod_strings['LBL_INDEX_NOT_USED']; + $this->ss->assign("TAB_CHOOSER", $chooser->display()); + + // show notes + if ( $this->bean instanceof Person ) + $module_key = "LBL_CONTACTS_NOTE_"; + elseif ( $this->bean instanceof Company ) + $module_key = "LBL_ACCOUNTS_NOTE_"; + else + $module_key = "LBL_".strtoupper($_REQUEST['import_module'])."_NOTE_"; + $notetext = ''; + for ($i = 1;isset($mod_strings[$module_key.$i]);$i++) { + $notetext .= '
  • ' . $mod_strings[$module_key.$i] . '
  • '; + } + $this->ss->assign("NOTETEXT",$notetext); + $this->ss->assign("HAS_HEADER",($has_header ? 'on' : 'off' )); + + // get list of required fields + $required = array(); + foreach ( array_keys($this->bean->get_import_required_fields()) as $name ) { + $properties = $this->bean->getFieldDefinition($name); + if (!empty ($properties['vname'])) + $required[$name] = str_replace(":","",translate($properties['vname'] ,$this->bean->module_dir)); + else + $required[$name] = str_replace(":","",translate($properties['name'] ,$this->bean->module_dir)); + } + // include anything needed for quicksearch to work + require_once("include/TemplateHandler/TemplateHandler.php"); + $quicksearch_js = TemplateHandler::createQuickSearchCode($fields,$fields,'importstep3'); + $this->ss->assign("JAVASCRIPT", $quicksearch_js . "\n" . $this->_getJS($required)); + + $this->ss->assign('required_fields',implode(', ',$required)); + $this->ss->display('modules/Import/tpls/step3.tpl'); + } + + /** + * Displays the Smarty template for an error + * + * @param string $message error message to show + * @param string $module what module we were importing into + * @param string $action what page we should go back to + */ + protected function _showImportError( + $message, + $module, + $action = 'Step1' + ) + { + $ss = new Sugar_Smarty(); + + $ss->assign("MESSAGE",$message); + $ss->assign("ACTION",$action); + $ss->assign("IMPORT_MODULE",$module); + $ss->assign("MOD", $GLOBALS['mod_strings']); + $ss->assign("SOURCE",""); + if ( isset($_REQUEST['source']) ) + $ss->assign("SOURCE", $_REQUEST['source']); + + echo $ss->fetch('modules/Import/tpls/error.tpl'); + } + + /** + * Returns JS used in this view + * + * @param array $required fields that are required for the import + * @return string HTML output with JS code + */ + protected function _getJS($required) + { + global $mod_strings; + + $print_required_array = ""; + foreach ($required as $name=>$display) { + $print_required_array .= "required['$name'] = '". $display . "';\n"; + } + + $sqsWaitImage = SugarThemeRegistry::current()->getImageURL('sqsWait.gif'); + + return << + + + +EOJAVASCRIPT; + } +} diff --git a/modules/Import/views/view.step4.php b/modules/Import/views/view.step4.php new file mode 100644 index 00000000..627fd898 --- /dev/null +++ b/modules/Import/views/view.step4.php @@ -0,0 +1,686 @@ +pause(); + + // use our own error handler + set_error_handler(array('ImportViewStep4','handleImportErrors'),E_ALL); + + global $mod_strings, $app_strings, $current_user, $import_bean_map; + global $app_list_strings, $timedate; + + $update_only = ( isset($_REQUEST['import_type']) && $_REQUEST['import_type'] == 'update' ); + $firstrow = unserialize(base64_decode($_REQUEST['firstrow'])); + + // All the Look Up Caches are initialized here + $enum_lookup_cache=array(); + + // setup the importable fields array. + $importable_fields = $this->bean->get_importable_fields(); + + // loop through all request variables + $importColumns = array(); + foreach ($_REQUEST as $name => $value) { + // only look for var names that start with "fieldNum" + if (strncasecmp($name, "colnum_", 7) != 0) { + continue; + } + + // pull out the column position for this field name + $pos = substr($name, 7); + + if ( isset($importable_fields[$value]) ) { + // now mark that we've seen this field + $importColumns[$pos] = $value; + } + } + + + // set the default locale settings + $ifs = new ImportFieldSanitize(); + $ifs->dateformat = $_REQUEST['importlocale_dateformat']; + $ifs->timeformat = $_REQUEST['importlocale_timeformat']; + $ifs->timezone = $_REQUEST['importlocale_timezone']; + $currency = new Currency(); + $currency->retrieve($_REQUEST['importlocale_currency']); + $ifs->currency_symbol = $currency->symbol; + $ifs->default_currency_significant_digits + = $_REQUEST['importlocale_default_currency_significant_digits']; + $ifs->num_grp_sep + = $_REQUEST['importlocale_num_grp_sep']; + $ifs->dec_sep = $_REQUEST['importlocale_dec_sep']; + $ifs->default_locale_name_format + = $_REQUEST['importlocale_default_locale_name_format']; + + // Check to be sure we are getting an import file that is in the right place + if ( realpath(dirname($_REQUEST['tmp_file']).'/') != realpath($sugar_config['upload_dir']) ) + trigger_error($mod_strings['LBL_CANNOT_OPEN'],E_USER_ERROR); + + // Open the import file + $importFile = new ImportFile( + $_REQUEST['tmp_file'], + $_REQUEST['custom_delimiter'], + html_entity_decode($_REQUEST['custom_enclosure'],ENT_QUOTES) + ); + + if ( !$importFile->fileExists() ) { + trigger_error($mod_strings['LBL_CANNOT_OPEN'],E_USER_ERROR); + } + + $fieldDefs = $this->bean->getFieldDefinitions(); + + while ( $row = $importFile->getNextRow() ) { + $focus = clone $this->bean; + $focus->unPopulateDefaultValues(); + $focus->save_from_post = false; + $focus->team_id = null; + $ifs->createdBeans = array(); + + $do_save = true; + + for ( $fieldNum = 0; $fieldNum < $_REQUEST['columncount']; $fieldNum++ ) { + // loop if this column isn't set + if ( !isset($importColumns[$fieldNum]) ) { + continue; + } + + // get this field's properties + $field = $importColumns[$fieldNum]; + $fieldDef = $focus->getFieldDefinition($field); + $fieldTranslated = translate((isset($fieldDef['vname'])?$fieldDef['vname']:$fieldDef['name']), + $_REQUEST['module'])." (".$fieldDef['name'].")"; + + // Bug 37241 - Don't re-import over a field we already set during the importing of another field + if ( !empty($focus->$field) ) { + continue; + } + + //DETERMINE WHETHER OR NOT $fieldDef['name'] IS DATE_MODIFIED AND SET A VAR, USE DOWN BELOW + + // translate strings + global $locale; + if(empty($locale)) { + $locale = new Localization(); + } + if ( isset($row[$fieldNum]) ) + $rowValue = $locale->translateCharset( + strip_tags(trim($row[$fieldNum])), + $_REQUEST['importlocale_charset'], + $sugar_config['default_charset'] + ); + else + $rowValue = ''; + + // If there is an default value then use it instead + if ( !empty($_REQUEST[$field]) ) { + if ( is_array($_REQUEST[$field]) ) + $defaultRowValue = encodeMultienumValue($_REQUEST[$field]); + else + $defaultRowValue = $_REQUEST[$field]; + // translate default values to the date/time format for the import file + if ( $fieldDef['type'] == 'date' + && $ifs->dateformat != $timedate->get_date_format() ) + $defaultRowValue = $timedate->swap_formats( + $defaultRowValue, $ifs->dateformat, $timedate->get_date_format()); + if ( $fieldDef['type'] == 'time' + && $ifs->timeformat != $timedate->get_time_format() ) + $defaultRowValue = $timedate->swap_formats( + $defaultRowValue, $ifs->timeformat, $timedate->get_time_format()); + if ( ($fieldDef['type'] == 'datetime' || $fieldDef['type'] == 'datetimecombo') + && $ifs->dateformat.' '.$ifs->timeformat != $timedate->get_date_time_format() ) + $defaultRowValue = $timedate->swap_formats( + $defaultRowValue, $ifs->dateformat.' '.$ifs->timeformat, + $timedate->get_date_time_format()); + if ( in_array($fieldDef['type'],array('currency','float','int','num')) + && $ifs->num_grp_sep != $current_user->getPreference('num_grp_sep') ) + $defaultRowValue = str_replace($current_user->getPreference('num_grp_sep'), + $ifs->num_grp_sep,$defaultRowValue); + if ( in_array($fieldDef['type'],array('currency','float')) + && $ifs->dec_sep != $current_user->getPreference('dec_sep') ) + $defaultRowValue = str_replace($current_user->getPreference('dec_sep'), + $ifs->dec_sep,$defaultRowValue); + $currency->retrieve('-99'); + $user_currency_symbol = $currency->symbol; + if ( $fieldDef['type'] == 'currency' + && $ifs->currency_symbol != $user_currency_symbol ) + $defaultRowValue = str_replace($user_currency_symbol, + $ifs->currency_symbol,$defaultRowValue); + + + if ( empty($rowValue) ) { + $rowValue = $defaultRowValue; + unset($defaultRowValue); + } + } + + // Bug 22705 - Don't update the First Name or Last Name value if Full Name is set + if ( in_array($field, array('first_name','last_name')) && !empty($focus->full_name) ) + continue; + + // loop if this value has not been set + if ( !isset($rowValue) ) + continue; + + // If the field is required and blank then error out + if ( array_key_exists($field,$focus->get_import_required_fields()) + && empty($rowValue) + && $rowValue!='0') { + $importFile->writeError( + $mod_strings['LBL_REQUIRED_VALUE'], + $fieldTranslated, + 'NULL' + ); + $do_save = false; + } + + // Handle the special case "Sync to Outlook" + if ( $focus->object_name == "Contacts" && $field == 'sync_contact' ) { + $bad_names = array(); + $returnValue = $ifs->synctooutlook( + $rowValue, + $fieldDef, + $bad_names); + // try the default value on fail + if ( !$returnValue && !empty($defaultRowValue) ) + $returnValue = $ifs->synctooutlook( + $defaultRowValue, + $fieldDef, + $bad_names); + if ( !$returnValue ) { + $importFile->writeError( + $mod_strings['LBL_ERROR_SYNC_USERS'], + $fieldTranslated, + explode(",",$bad_names)); + $do_save = 0; + } + } + + // Handle email1 and email2 fields ( these don't have the type of email ) + if ( $field == 'email1' || $field == 'email2' ) { + $returnValue = $ifs->email($rowValue, $fieldDef, $focus); + // try the default value on fail + if ( !$returnValue && !empty($defaultRowValue) ) + $returnValue = $ifs->email( + $defaultRowValue, + $fieldDef); + if ( $returnValue === FALSE ) { + $do_save=0; + $importFile->writeError( + $mod_strings['LBL_ERROR_INVALID_EMAIL'], + $fieldTranslated, + $rowValue); + } + else { + $rowValue = $returnValue; + // check for current opt_out and invalid email settings for this email address + // if we find any, set them now + $emailres = $focus->db->query( + "SELECT opt_out, invalid_email FROM email_addresses + WHERE email_address = '".$focus->db->quote($rowValue)."'"); + if ( $emailrow = $focus->db->fetchByAssoc($emailres) ) { + $focus->email_opt_out = $emailrow['opt_out']; + $focus->invalid_email = $emailrow['invalid_email']; + } + } + } + + // Handle splitting Full Name into First and Last Name parts + if ( $field == 'full_name' && !empty($rowValue) ) { + $ifs->fullname( + $rowValue, + $fieldDef, + $focus); + } + + // to maintain 451 compatiblity + if(!isset($fieldDef['module']) && $fieldDef['type']=='relate') + $fieldDef['module'] = ucfirst($fieldDef['table']); + + if(isset($fieldDef['custom_type']) && !empty($fieldDef['custom_type'])) + $fieldDef['type'] = $fieldDef['custom_type']; + + // If the field is empty then there is no need to check the data + if( !empty($rowValue) ) { + switch ($fieldDef['type']) { + case 'enum': + case 'multienum': + if ( isset($fieldDef['type']) && $fieldDef['type'] == "multienum" ) + $returnValue = $ifs->multienum($rowValue,$fieldDef); + else + $returnValue = $ifs->enum($rowValue,$fieldDef); + // try the default value on fail + if ( !$returnValue && !empty($defaultRowValue) ) + if ( isset($fieldDef['type']) && $fieldDef['type'] == "multienum" ) + $returnValue = $ifs->multienum($defaultRowValue,$fieldDef); + else + $returnValue = $ifs->enum($defaultRowValue,$fieldDef); + if ( $returnValue === FALSE ) { + $importFile->writeError( + $mod_strings['LBL_ERROR_NOT_IN_ENUM'] + . implode(",",$app_list_strings[$fieldDef['options']]), + $fieldTranslated, + $rowValue); + $do_save = 0; + } + else + $rowValue = $returnValue; + + break; + case 'relate': + case 'parent': + $returnValue = $ifs->relate( + $rowValue, + $fieldDef, + $focus, + empty($defaultRowValue)); + if ( !$returnValue && !empty($defaultRowValue) ) + $returnValue = $ifs->relate( + $defaultRowValue, + $fieldDef, + $focus); + // Bug 33623 - Set the id value found from the above method call as an importColumn + if ( $returnValue !== false ) + $importColumns[] = $fieldDef['id_name']; + break; + case 'teamset': + $returnValue = $ifs->teamset( + $rowValue, + $fieldDef, + $focus); + $importColumns[] = 'team_set_id'; + $importColumns[] = 'team_id'; + break; + case 'fullname': + break; + default: + $fieldtype = $fieldDef['type']; + $returnValue = $ifs->$fieldtype($rowValue, $fieldDef, $focus); + // try the default value on fail + if ( !$returnValue && !empty($defaultRowValue) ) + $returnValue = $ifs->$fieldtype( + $defaultRowValue, + $fieldDef, + $focus); + if ( !$returnValue ) { + $do_save=0; + $importFile->writeError( + $mod_strings['LBL_ERROR_INVALID_'.strtoupper($fieldDef['type'])], + $fieldTranslated, + $rowValue, + $focus); + } + else { + $rowValue = $returnValue; + } + } + } + $focus->$field = $rowValue; + unset($defaultRowValue); + } + + // Now try to validate flex relate fields + if ( isset($focus->field_defs['parent_name']) + && isset($focus->parent_name) + && ($focus->field_defs['parent_name']['type'] == 'parent') ) { + // populate values from the picker widget if the import file doesn't have them + $parent_idField = $focus->field_defs['parent_name']['id_name']; + if ( empty($focus->$parent_idField) && !empty($_REQUEST[$parent_idField]) ) + $focus->$parent_idField = $_REQUEST[$parent_idField]; + $parent_typeField = $focus->field_defs['parent_name']['type_name']; + if ( empty($focus->$parent_typeField) && !empty($_REQUEST[$parent_typeField]) ) + $focus->$parent_typeField = $_REQUEST[$parent_typeField]; + // now validate it + $returnValue = $ifs->parent( + $focus->parent_name, + $focus->field_defs['parent_name'], + $focus, + empty($_REQUEST['parent_name'])); + if ( !$returnValue && !empty($_REQUEST['parent_name']) ) + $returnValue = $ifs->parent( + $_REQUEST['parent_name'], + $focus->field_defs['parent_name'], + $focus); + } + + // check to see that the indexes being entered are unique. + if (isset($_REQUEST['display_tabs_def']) && $_REQUEST['display_tabs_def'] != ""){ + $idc = new ImportDuplicateCheck($focus); + if ( $idc->isADuplicateRecord(explode('&', $_REQUEST['display_tabs_def'])) ){ + $importFile->markRowAsDuplicate(); + $this->_undoCreatedBeans($ifs->createdBeans); + continue; + } + } + + // if the id was specified + $newRecord = true; + if ( !empty($focus->id) ) { + $focus->id = $this->_convertId($focus->id); + + // check if it already exists + $query = "SELECT * FROM {$focus->table_name} WHERE id='".$focus->db->quote($focus->id)."'"; + $result = $focus->db->query($query) + or sugar_die("Error selecting sugarbean: "); + + $dbrow = $focus->db->fetchByAssoc($result); + + if (isset ($dbrow['id']) && $dbrow['id'] != -1) { + // if it exists but was deleted, just remove it + if (isset ($dbrow['deleted']) && $dbrow['deleted'] == 1 && $update_only==false) { + $query2 = "DELETE FROM {$focus->table_name} WHERE id='".$focus->db->quote($focus->id)."'"; + $result2 = $focus->db->query($query2) or sugar_die($mod_strings['LBL_ERROR_DELETING_RECORD']." ".$focus->id); + if ($focus->hasCustomFields()) { + $query3 = "DELETE FROM {$focus->table_name}_cstm WHERE id_c='".$focus->db->quote($focus->id)."'"; + $result2 = $focus->db->query($query3); + } + $focus->new_with_id = true; + } + else { + if( !$update_only ) { + $do_save = 0; + $importFile->writeError($mod_strings['LBL_ID_EXISTS_ALREADY'],'ID',$focus->id); + $this->_undoCreatedBeans($ifs->createdBeans); + continue; + } + $existing_focus = clone $this->bean; + $newRecord = false; + if ( !( $existing_focus->retrieve($dbrow['id']) instanceOf SugarBean ) ) { + $do_save = 0; + $importFile->writeError($mod_strings['LBL_RECORD_CANNOT_BE_UPDATED'],'ID',$focus->id); + $this->_undoCreatedBeans($ifs->createdBeans); + continue; + } + else { + $newData = $focus->toArray(); + foreach ( $newData as $focus_key => $focus_value ) + if ( in_array($focus_key,$importColumns) ) + $existing_focus->$focus_key = $focus_value; + + $focus = $existing_focus; + } + unset($existing_focus); + } + } + else { + $focus->new_with_id = true; + } + } + + if ($do_save) { + // Populate in any default values to the bean + $focus->populateDefaultValues(); + + if ( !isset($focus->assigned_user_id) || $focus->assigned_user_id == '' && $newRecord ) { + $focus->assigned_user_id = $current_user->id; + } + /* + * Bug 34854: Added all conditions besides the empty check on date modified. Currently, if + * we do an update to a record, it doesn't update the date_modified value. + * Hack note: I'm doing a to_display and back to_db on the fetched row to make sure that any truncating that happens + * when $focus->date_modified goes to_display and back to_db also happens on the fetched db value. Otherwise, + * in some cases we truncate the seconds on one and not the other, and the comparison fails when it should pass + */ + if ( ( !empty($focus->new_with_id) && !empty($focus->date_modified) ) || + ( empty($focus->new_with_id) && $timedate->to_db($focus->date_modified) != $timedate->to_db($timedate->to_display_date_time($focus->fetched_row['date_modified'])) ) + ) + $focus->update_date_modified = false; + + $focus->optimistic_lock = false; + if ( $focus->object_name == "Contacts" && isset($focus->sync_contact) ) { + //copy the potential sync list to another varible + $list_of_users=$focus->sync_contact; + //and set it to false for the save + $focus->sync_contact=false; + } else if($focus->object_name == "User" && !empty($current_user) && $focus->is_admin && !is_admin($current_user) && is_admin_for_module($current_user, 'Users')) { + sugar_die($GLOBALS['mod_strings']['ERR_IMPORT_SYSTEM_ADMININSTRATOR']); + } + //bug# 40260 setting it true as the module in focus is involved in an import + $focus->in_import=true; + // call any logic needed for the module preSave + $focus->beforeImportSave(); + + + $focus->save(false); + + // call any logic needed for the module postSave + $focus->afterImportSave(); + + if ( $focus->object_name == "Contacts" && isset($list_of_users) ) + $focus->process_sync_to_outlook($list_of_users); + + // Update the created/updated counter + $importFile->markRowAsImported($newRecord); + + // Add ID to User's Last Import records + if ( $newRecord ) + ImportFile::writeRowToLastImport( + $_REQUEST['import_module'], + ($focus->object_name == 'Case' ? 'aCase' : $focus->object_name), + $focus->id); + } + else + $this->_undoCreatedBeans($ifs->createdBeans); + + unset($defaultRowValue); + } + + // save mapping if requested + if ( isset($_REQUEST['save_map_as']) && $_REQUEST['save_map_as'] != '' ) { + $mapping_file = new ImportMap(); + if ( isset($_REQUEST['has_header']) && $_REQUEST['has_header'] == 'on') { + $header_to_field = array (); + foreach ($importColumns as $pos => $field_name) { + if (isset($firstrow[$pos]) && isset($field_name)) { + $header_to_field[$firstrow[$pos]] = $field_name; + } + } + $mapping_file->setMapping($header_to_field); + } + else { + $mapping_file->setMapping($importColumns); + } + + // save default fields + $defaultValues = array(); + for ( $i = 0; $i < $_REQUEST['columncount']; $i++ ) + + if (isset($importColumns[$i]) && !empty($_REQUEST[$importColumns[$i]])) { + $field = $importColumns[$i]; + $fieldDef = $focus->getFieldDefinition($field); + if(!empty($fieldDef['custom_type']) && $fieldDef['custom_type'] == 'teamset') { + require_once('include/SugarFields/Fields/Teamset/SugarFieldTeamset.php'); + $sugar_field = new SugarFieldTeamset('Teamset'); + $teams = $sugar_field->getTeamsFromRequest($field); + if(isset($_REQUEST['primary_team_name_collection'])) { + $primary_index = $_REQUEST['primary_team_name_collection']; + } + + //If primary_index was selected, ensure that the first Array entry is the primary team + if(isset($primary_index)) { + $count = 0; + $new_teams = array(); + foreach($teams as $id=>$name) { + if($primary_index == $count++) { + $new_teams[$id] = $name; + unset($teams[$id]); + break; + } + } + + foreach($teams as $id=>$name) { + $new_teams[$id] = $name; + } + $teams = $new_teams; + } //if + + $json = getJSONobj(); + $defaultValues[$field] = $json->encode($teams); + } else { + $defaultValues[$field] = $_REQUEST[$importColumns[$i]]; + } + } + + $mapping_file->setDefaultValues($defaultValues); + $result = $mapping_file->save( + $current_user->id, + $_REQUEST['save_map_as'], + $_REQUEST['import_module'], + $_REQUEST['source'], + ( isset($_REQUEST['has_header']) && $_REQUEST['has_header'] == 'on'), + $_REQUEST['custom_delimiter'], + html_entity_decode($_REQUEST['custom_enclosure'],ENT_QUOTES) + ); + } + + $importFile->writeStatus(); + } + + /** + * If a bean save is not done for some reason, this method will undo any of the beans that were created + * + * @param array $ids ids of user_last_import records created + */ + protected function _undoCreatedBeans( + array $ids + ) + { + $focus = new UsersLastImport(); + foreach ($ids as $id) + $focus->undoById($id); + } + + /** + * clean id's when being imported + * + * @param string $string + * @return string + */ + protected function _convertId( + $string + ) + { + return preg_replace_callback( + '|[^A-Za-z0-9\-]|', + create_function( + // single quotes are essential here, + // or alternative escape all $ as \$ + '$matches', + 'return ord($matches[0]);' + ) , + $string); + } + + /** + * Replaces PHP error handler in Step4 + * + * @param int $errno + * @param string $errstr + * @param string $errfile + * @param string $errline + */ + public static function handleImportErrors( + $errno, + $errstr, + $errfile, + $errline + ) + { + if ( !defined('E_DEPRECATED') ) + define('E_DEPRECATED','8192'); + if ( !defined('E_USER_DEPRECATED') ) + define('E_USER_DEPRECATED','16384'); + + // check to see if current reporting level should be included based upon error_reporting() setting, if not + // then just return + if ( !(error_reporting() & $errno) ) + return true; + + switch ($errno) { + case E_USER_ERROR: + echo "ERROR: [$errno] $errstr on line $errline in file $errfile
    \n"; + exit(1); + break; + case E_USER_WARNING: + case E_WARNING: + echo "WARNING: [$errno] $errstr on line $errline in file $errfile
    \n"; + break; + case E_USER_NOTICE: + case E_NOTICE: + echo "NOTICE: [$errno] $errstr on line $errline in file $errfile
    \n"; + break; + case E_STRICT: + case E_DEPRECATED: + case E_USER_DEPRECATED: + // don't worry about these + //echo "STRICT ERROR: [$errno] $errstr on line $errline in file $errfile
    \n"; + break; + default: + echo "Unknown error type: [$errno] $errstr on line $errline in file $errfile
    \n"; + break; + } + + return true; + } +} diff --git a/modules/Import/views/view.undo.php b/modules/Import/views/view.undo.php new file mode 100644 index 00000000..7bd3bda5 --- /dev/null +++ b/modules/Import/views/view.undo.php @@ -0,0 +1,129 @@ +ss->assign("IMPORT_MODULE", $_REQUEST['import_module']); + // lookup this module's $mod_strings to get the correct module name + $old_mod_strings = $mod_strings; + $module_mod_strings = + return_module_language($current_language, $_REQUEST['import_module']); + $this->ss->assign("MODULENAME",$module_mod_strings['LBL_MODULE_NAME']); + // reset old ones afterwards + $mod_strings = $old_mod_strings; + + $last_import = new UsersLastImport(); + $this->ss->assign('UNDO_SUCCESS',$last_import->undo($_REQUEST['import_module'])); + $this->ss->assign("JAVASCRIPT", $this->_getJS()); + + $this->ss->display('modules/Import/tpls/undo.tpl'); + } + + /** + * Returns JS used in this view + */ + private function _getJS() + { + return << + + + +EOJAVASCRIPT; + } +} diff --git a/modules/InboundEmail/Delete.php b/modules/InboundEmail/Delete.php new file mode 100644 index 00000000..8f67979f --- /dev/null +++ b/modules/InboundEmail/Delete.php @@ -0,0 +1,48 @@ +mark_deleted($_REQUEST['record']); + header("Location: index.php?module=".$_REQUEST['return_module']."&action=".$_REQUEST['return_action']."&record=".$_REQUEST['return_id']); +} + +?> diff --git a/modules/InboundEmail/DetailView.html b/modules/InboundEmail/DetailView.html new file mode 100644 index 00000000..b9850abb --- /dev/null +++ b/modules/InboundEmail/DetailView.html @@ -0,0 +1,248 @@ + + + +{MODULE_TITLE} +{ERROR} + + + + + +
    +
    + + + + + + + + + + + + + +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

    {MOD.LBL_BASIC}

    + {MOD.LBL_NAME}: + {NAME}  + {MOD.LBL_STATUS}: + {STATUS} 
    + {MOD.LBL_SERVER_URL}: + {SERVER_URL}  + {MOD.LBL_LOGIN}: + {USER} 
    + {MOD.LBL_SERVER_TYPE}: + {SERVER_TYPE}  +    +    +
    + {MOD.LBL_PORT}: + + {PORT}   + + {MOD.LBL_MAILBOX}: + {MAILBOX} 
    + {MOD.LBL_MAILBOX_SSL}: + {SSL}  + {MOD.LBL_TRASH_FOLDER}: + {TRASHFOLDER} 
    +    +    + + {MOD.LBL_SENT_FOLDER}: + {SENTFOLDER}  
    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

    {MOD.LBL_SERVER_OPTIONS}

    + + +   + + {MOD.LBL_FROM_NAME}:  + {FROM_NAME}   +
    +
    {MOD.LBL_ENABLE_AUTO_IMPORT}:
     
     
    +
    {IS_AUTO_IMPORT_ENABLED}
     
     
    + {MOD.LBL_FROM_ADDR}:   + {FROM_ADDR}   +
    + {MOD.LBL_CREATE_CASE}: + {IS_CREATE_CASE}  + {MOD.LBL_REPLY_TO_NAME}:   + {REPLY_TO_NAME}  +
    + {MOD.LBL_DISTRIBUTION_METHOD}:   + {DISTRIBUTION_METHOD}  + +    +    +
    + {MOD.LBL_CREATE_CASE_REPLY_TEMPLATE}:   + {CREATE_CASE_EMAIL_TEMPLATE}  +
    +    +    + + {MOD.LBL_REPLY_TO_ADDR}:   + {REPLY_TO_ADDR}  +
    + {MOD.LBL_AUTOREPLY}: + {EMAIL_TEMPLATE}  +
    {MOD.LBL_ALLOW_OUTBOUND_GROUP_USAGE}:
     
    +
    {ALLOW_OUTBOUND_GROUP_USAGE}
    +
    + {MOD.LBL_FILTER_DOMAIN}: + {FILTER_DOMAIN}  +
    {MOD.LBL_MAX_AUTO_REPLIES}:
     
    +
    {EMAIL_NUM_AUTOREPLIES_24_HOURS}
      +
    + {MOD.LBL_MARK_READ}: + {LEAVEMESSAGESONMAILSERVER}  +    +    +
    +
    + + \ No newline at end of file diff --git a/modules/InboundEmail/DetailView.php b/modules/InboundEmail/DetailView.php new file mode 100644 index 00000000..cf1590a7 --- /dev/null +++ b/modules/InboundEmail/DetailView.php @@ -0,0 +1,303 @@ +info("InboundEmails DetailView"); +$focus = new InboundEmail(); +$focus->retrieve($_REQUEST['record']); +if (empty($focus->id)) { + sugar_die($app_strings['ERROR_NO_RECORD']); +} // if +$focus->checkImap(); +$detailView = new DetailView(); +$offset=0; + + + +/* end standard DetailView layout process */ +$exServ = explode('::',$focus->service); +if($focus->delete_seen == 1) { + $delete_seen = $mod_strings['LBL_MARK_READ_NO']; +} else { + $delete_seen = $mod_strings['LBL_MARK_READ_YES']; +} + +// deferred +//$r = $focus->db->query("SELECT id, name FROM queues WHERE owner_id = '".$focus->id."'"); +//$a = $focus->db->fetchByAssoc($r); +//$queue = ''.$a['name'].''; +$groupName = ''; +if($focus->group_id) { + + //$group = new Group(); + //$group->retrieve($focus->group_id); + //$groupName = $group->user_name; +} + +if($focus->template_id) { + + $et = new EmailTemplate(); + $et->retrieve($focus->template_id); + $emailTemplate = $et->name; +} else { + $emailTemplate = $mod_strings['LBL_NONE']; +} +$ssl = $app_list_strings['dom_email_bool']['bool_false']; +$allow_outbound_group_usage = $app_list_strings['dom_email_bool']['bool_false']; +$tls = $app_list_strings['dom_email_bool']['bool_false']; +$ca = $app_list_strings['dom_email_bool']['bool_false']; +if(!empty($focus->service)) { + // will always have 2 values: /tls || /notls and /validate-cert || /novalidate-cert + $exServ = explode('::', $focus->service); + if($exServ[0] == 'tls') { + $tls = $app_list_strings['dom_email_bool']['bool_true']; + } + if($exServ[1] == 'validate-cert') { + $cert = $app_list_strings['dom_email_bool']['bool_true']; + } + if(isset($exServ[2]) && !empty($exServ[2]) && $exServ[2] == 'ssl') { + $ssl = $app_list_strings['dom_email_bool']['bool_true']; + } +} + +// FROM NAME FROM ADDRESS STRINGS +$email = new Email(); +$from = $email->getSystemDefaultEmail(); +$default_from_name = $from['name']; +$default_from_addr = $from['email']; +$from_name = ''; +$from_addr = ''; +$reply_to_name = ''; +$reply_to_addr = ''; +$distrib_method =''; +$filterDomain = ''; +$trashFolder = ''; +$sentFolder = ''; +$distributionMethod = ''; +$create_case_email_template=''; +$create_case_email_template_name = $mod_strings['LBL_NONE']; +$leaveMessagesOnMailServer = $app_strings['LBL_EMAIL_NO']; + +//$fromNameAddr = $fromName.' <'.$from['email'].'>
    ('.$mod_strings['LBL_SYSTEM_DEFAULT'].')'; +//$replyNameAddr = $mod_strings['LBL_SAME_AS_ABOVE']; +$onlySince = $mod_strings['LBL_ONLY_SINCE_NO']; + +if(!empty($focus->stored_options)) { + // FROM NAME and Address + $storedOptions = unserialize(base64_decode($focus->stored_options)); + + $from_name = (isset($storedOptions['from_name']) ? $storedOptions['from_name'] : ""); + $from_addr = (isset($storedOptions['from_addr']) ? $storedOptions['from_addr'] : ""); + + $reply_to_name = (isset($storedOptions['reply_to_name'])) ? $storedOptions['reply_to_name'] : ""; + $reply_to_addr = (isset($storedOptions['reply_to_addr'])) ? $storedOptions['reply_to_addr'] : ""; + // only-since option + if($storedOptions['only_since']) { + $onlySince = $mod_strings['LBL_ONLY_SINCE_YES']; + } else { + $onlySince = $mod_strings['LBL_ONLY_SINCE_NO']; + } + // filter-domain + if(isset($storedOptions['filter_domain']) && !empty($storedOptions['filter_domain'])) { + $filterDomain = $storedOptions['filter_domain']; + } else { + $filterDomain = $app_strings['NTC_NO_ITEMS_DISPLAY']; + } + // Trash Folder + if(isset($storedOptions['trashFolder']) && !empty($storedOptions['trashFolder'])) { + $trashFolder = $storedOptions['trashFolder']; + } else { + $trashFolder = $mod_strings['LBL_NONE']; + } + // Sent Folder + if(isset($storedOptions['sentFolder']) && !empty($storedOptions['sentFolder'])) { + $sentFolder = $storedOptions['sentFolder']; + } else { + $sentFolder = $mod_strings['LBL_NONE']; + } + + if(!isset($storedOptions['leaveMessagesOnMailServer']) || $storedOptions['leaveMessagesOnMailServer'] == 1) { + $leaveMessagesOnMailServer = $app_strings['LBL_EMAIL_YES']; + } else { + $leaveMessagesOnMailServer = $app_strings['LBL_EMAIL_NO']; + } // else + if(!isset($storedOptions['leaveMessagesOnMailServer']) || $storedOptions['leaveMessagesOnMailServer'] == 1) { + $leaveMessagesOnMailServer = $app_strings['LBL_EMAIL_YES']; + } else { + $leaveMessagesOnMailServer = $app_strings['LBL_EMAIL_NO']; + } // else + $distrib_method = (isset($storedOptions['distrib_method'])) ? $storedOptions['distrib_method'] : ""; + $create_case_email_template = (isset($storedOptions['create_case_email_template'])) ? $storedOptions['create_case_email_template'] : ""; + $email_num_autoreplies_24_hours = (isset($storedOptions['email_num_autoreplies_24_hours'])) ? $storedOptions['email_num_autoreplies_24_hours'] : $focus->defaultEmailNumAutoreplies24Hours; + + if( isset($storedOptions['allow_outbound_group_usage']) && $storedOptions['allow_outbound_group_usage'] == 1) + $allow_outbound_group_usage = $app_list_strings['dom_email_bool']['bool_true']; + +} + +if(!empty($create_case_email_template)) { + + $et = new EmailTemplate(); + $et->retrieve($create_case_email_template); + $create_case_email_template_name = $et->name; +} +if (!empty($distrib_method)) { + $distributionMethod = $app_list_strings['dom_email_distribution_for_auto_create'][$distrib_method]; +} // if +$xtpl = new XTemplate('modules/InboundEmail/DetailView.html'); +//// ERRORS from Save +if(isset($_REQUEST['error'])) { + $xtpl->assign('ERROR', "
    ".$mod_strings['ERR_NO_OPTS_SAVED']."
    "); +} +//cma, June 24,2008 - Fix bug 21670. User status and group/personal statements are not localized. +$userStatus = $mod_strings['LBL_STATUS_ACTIVE']; +if('Inactive' == $focus->status) { + $userStatus = $mod_strings['LBL_STATUS_INACTIVE']; +} + +$xtpl->assign('MODULE_TITLE', getClassicModuleTitle($mod_strings['LBL_MODULE_TITLE'], array($mod_strings['LBL_MODULE_NAME'],$focus->name), true)); +$xtpl->assign('MOD', $mod_strings); +$xtpl->assign('APP', $app_strings); +$xtpl->assign('CREATED_BY', $focus->created_by_name); +$xtpl->assign('MODIFIED_BY', $focus->modified_by_name); +$xtpl->assign('GRIDLINE', $gridline); +$xtpl->assign('PRINT_URL', 'index.php?'.$GLOBALS['request_string']); +$xtpl->assign('ID', $focus->id); +$xtpl->assign('STATUS', $userStatus); +$xtpl->assign('SERVER_URL', $focus->server_url); +$xtpl->assign('USER', $focus->email_user); +$xtpl->assign('NAME', $focus->name); +$xtpl->assign('MAILBOX', $focus->mailbox); +$xtpl->assign('TRASHFOLDER', $trashFolder); +$xtpl->assign('SENTFOLDER', $sentFolder); + +$protocol = filterInboundEmailPopSelection($app_list_strings['dom_email_server_type']); +$xtpl->assign('SERVER_TYPE', $protocol[$focus->protocol]); +$xtpl->assign('SSL', $ssl); +$xtpl->assign('TLS', $tls); +$xtpl->assign('CERT', $ca); +$xtpl->assign('MARK_READ', $delete_seen); +$xtpl->assign('ALLOW_OUTBOUND_GROUP_USAGE', $allow_outbound_group_usage); + +// deferred +//$xtpl->assign('QUEUE', $queue); +$createCaseRowStyle = "display:none"; +$leaveMessagesOnMailServerStyle = "display:none"; +if ($focus->is_personal) { + $xtpl->assign('EDIT_GROUP_FOLDER_STYLE', "display:none"); +} else { + $is_auto_import = $app_list_strings['checkbox_dom']['2']; + + if (!empty($focus->groupfolder_id)) { + $is_auto_import = $app_list_strings['checkbox_dom']['1']; + $leaveMessagesOnMailServerStyle = "display:''"; + } // if + $xtpl->assign('IS_AUTO_IMPORT_ENABLED', $is_auto_import); + $xtpl->assign('EDIT_GROUP_FOLDER_STYLE', "display:''"); + if ($focus->isMailBoxTypeCreateCase()) { + $createCaseRowStyle = "display:''"; + } + +} +$xtpl->assign('LEAVEMESSAGESONMAILSERVER_STYLE', $leaveMessagesOnMailServerStyle); +$xtpl->assign('LEAVEMESSAGESONMAILSERVER', $leaveMessagesOnMailServer); +$xtpl->assign('CREATE_CASE_ROW_STYLE', $createCaseRowStyle); +$xtpl->assign('DISTRIBUTION_METHOD', $distributionMethod); +$xtpl->assign('CREATE_CASE_EMAIL_TEMPLATE', $create_case_email_template_name); +if ($focus->isPop3Protocol()) { + $xtpl->assign('TRASH_SENT_FOLDER_STYLE', "display:none"); +} else { + $xtpl->assign('TRASH_SENT_FOLDER_STYLE', "display:''"); +} // else + +$possibleAction = "pick"; +if (!isset($app_list_strings['dom_mailbox_type'][$focus->mailbox_type])) { + $possibleAction = $app_list_strings['dom_mailbox_type']['pick']; +} else { + $possibleAction = $app_list_strings['dom_mailbox_type'][$focus->mailbox_type]; +} + +if($focus->mailbox_type == 'createcase') + $is_create_case = $app_list_strings['checkbox_dom']['1']; +else + $is_create_case = $app_list_strings['checkbox_dom']['2']; + + +$xtpl->assign('GROUP_NAME', $groupName); +$xtpl->assign('IS_CREATE_CASE', $is_create_case); +$xtpl->assign('EMAIL_TEMPLATE', $emailTemplate); +$xtpl->assign('FROM_NAME', $from_name); +$xtpl->assign('FROM_ADDR', $from_addr); +$xtpl->assign('DEFAULT_FROM_NAME', $default_from_name); +$xtpl->assign('DEFAULT_FROM_ADDR', $default_from_addr); +$xtpl->assign('REPLY_TO_NAME', $reply_to_name); +$xtpl->assign('REPLY_TO_ADDR', $reply_to_addr); +$xtpl->assign('ONLY_SINCE', $onlySince); +$xtpl->assign('FILTER_DOMAIN', $filterDomain); +$xtpl->assign('EMAIL_NUM_AUTOREPLIES_24_HOURS', $email_num_autoreplies_24_hours); +if(!empty($focus->port)) { + $xtpl->assign('PORT', $focus->port); +} +if($focus->handleIsPersonal()) { + $xtpl->assign('LBL_GROUP_QUEUE', $mod_strings['LBL_ASSIGN_TO_USER']); +} else { + $xtpl->assign('LBL_GROUP_QUEUE', $mod_strings['LBL_GROUP_QUEUE']); +} + +//Overrides for bounce mailbox accounts +if ($focus->mailbox_type == 'bounce') +{ + $xtpl->assign('MODULE_TITLE', getClassicModuleTitle($mod_strings['LBL_MODULE_TITLE'], array($mod_strings['LBL_BOUNCE_MODULE_NAME'],$focus->name), true)); +} +else if( $focus->is_personal == '1') + $xtpl->assign('MODULE_TITLE', getClassicModuleTitle($mod_strings['LBL_MODULE_TITLE'], array($mod_strings['LBL_PERSONAL_MODULE_NAME'],$focus->name), true)); + +$xtpl->parse('main'); +$xtpl->out('main'); +?> \ No newline at end of file diff --git a/modules/InboundEmail/EditGroupFolder.php b/modules/InboundEmail/EditGroupFolder.php new file mode 100644 index 00000000..baf04dd0 --- /dev/null +++ b/modules/InboundEmail/EditGroupFolder.php @@ -0,0 +1,123 @@ +debug("In EditGroupFolder view, about to retrieve record: ".$_REQUEST['record']); + $result = $focus->retrieve($_REQUEST['record']); + if($result == null) + { + sugar_die($app_strings['ERROR_NO_RECORD']); + } +} + +$GLOBALS['log']->info("SugarFolder Edit View"); +/* End standard EditView setup logic */ + +// TEMPLATE ASSIGNMENTS +$smarty = new Sugar_Smarty(); +// standard assigns +$smarty->assign('mod_strings', $mod_strings); +$smarty->assign('app_strings', $app_strings); +$smarty->assign('theme', $theme); +$smarty->assign('jsCustomVersion', $sugar_config['js_custom_version']); +$smarty->assign('sugar_version', $sugar_version); +$smarty->assign('GRIDLINE', $gridline); +$smarty->assign('MODULE', 'InboundEmail'); +$smarty->assign('RETURN_MODULE', 'InboundEmail'); +$smarty->assign('RETURN_ID', $focus->id); +$smarty->assign('RETURN_ACTION', ""); +$smarty->assign('ID', $focus->id); +// module specific + +$ret = $focus->getFoldersForSettings($current_user); +$groupFolders = Array(); +$groupFoldersOrig = array(); +foreach($ret['groupFolders'] as $key => $value) { + if(!empty($focus->id)) { + if ($value['id'] == $focus->id) { + continue; + } + } // if + $groupFolders[$value['id']] = $value['name']; + $groupFoldersOrig[] = $value['origName']; +} // foreach +$groupFolderName = ""; +$addToGroupFolder = ""; +$createGroupFolderStyle = "display:''"; +$editGroupFolderStyle = "display:''"; +if(!empty($focus->id)) { + $groupFolderName = $focus->name; +} +if(!empty($focus->id)) { + $addToGroupFolder = $focus->parent_folder; +} +if(!empty($focus->id)) { + $createGroupFolderStyle = "display:none;"; +} else { + $editGroupFolderStyle = "display:none;"; +} // else +$smarty->assign('createGroupFolderStyle', $createGroupFolderStyle); +$smarty->assign('editGroupFolderStyle', $editGroupFolderStyle); + +$smarty->assign('groupFolderName', $groupFolderName); +$json = getJSONobj(); +$smarty->assign('group_folder_array', $json->encode($groupFoldersOrig)); +$smarty->assign('group_folder_options', get_select_options_with_id($groupFolders, $addToGroupFolder)); + + +$smarty->assign('CSS',SugarThemeRegistry::current()->getCSS()); + + +$smarty->assign('languageStrings', ''); +echo $smarty->fetch("modules/Emails/templates/_createGroupFolder.tpl"); +?> \ No newline at end of file diff --git a/modules/InboundEmail/EditView.html b/modules/InboundEmail/EditView.html new file mode 100644 index 00000000..bd87cba2 --- /dev/null +++ b/modules/InboundEmail/EditView.html @@ -0,0 +1,574 @@ + +
    +
    + +{MODULE_TITLE} +{ERROR_STRING} + + +
    + + + + + + + + + + + + + + + + + + +
    + + + + {APP.LBL_REQUIRED_SYMBOL} {APP.NTC_REQUIRED}{ADMIN_EDIT}
    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

    {MOD.LBL_BASIC}

     {APP.LBL_EMAIL_ACCOUNTS_GMAIL_DEFAULTS} 
    + {MOD.LBL_NAME}: {APP.LBL_REQUIRED_SYMBOL}  + + {MOD.LBL_STATUS}:  +
    + {MOD.LBL_SERVER_URL}: {APP.LBL_REQUIRED_SYMBOL}  + + {MOD.LBL_LOGIN}: + {APP.LBL_REQUIRED_SYMBOL}  +
    + {MOD.LBL_SERVER_TYPE}: + {APP.LBL_REQUIRED_SYMBOL}  + + + {MOD.LBL_PASSWORD}: + {APP.LBL_REQUIRED_SYMBOL}  +
    + {MOD.LBL_PORT}: + {APP.LBL_REQUIRED_SYMBOL}  + + + + {MOD.LBL_MAILBOX}: {APP.LBL_REQUIRED_SYMBOL}  + + +
    + {MOD.LBL_SSL}:   + + + + + + {MOD.LBL_TRASH_FOLDER}: + {APP.LBL_REQUIRED_SYMBOL}  + + + +
    +   +   + {MOD.LBL_SENT_FOLDER}: + + + +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

    {EMAIL_OPTIONS}

    + +   + +   + {MOD.LBL_FROM_NAME}:{APP.LBL_REQUIRED_SYMBOL}  +  
    + {MOD.LBL_ENABLE_AUTO_IMPORT}:    + + + + {MOD.LBL_FROM_ADDR}:{APP.LBL_REQUIRED_SYMBOL}  +
    + {MOD.LBL_CREATE_CASE}:   + + {MOD.LBL_REPLY_TO_NAME}:  + + +
    + {MOD.LBL_DISTRIBUTION_METHOD}:  + +   +  
    + {MOD.LBL_CREATE_CASE_REPLY_TEMPLATE}:   + + + + + +
    +   +   + {MOD.LBL_REPLY_TO_ADDR}:  + +   +
    +   +   + {MOD.LBL_ALLOW_OUTBOUND_GROUP_USAGE}:  +   + + + +
    + {MOD.LBL_AUTOREPLY}:   + + + + + +
    + {MOD.LBL_FILTER_DOMAIN}:   + + {MOD.LBL_MAX_AUTO_REPLIES}:   +
    + {MOD.LBL_MARK_READ}: + +   +  
    +
    + + +
    + + + +{JAVASCRIPT} + \ No newline at end of file diff --git a/modules/InboundEmail/EditView.php b/modules/InboundEmail/EditView.php new file mode 100644 index 00000000..d39cec28 --- /dev/null +++ b/modules/InboundEmail/EditView.php @@ -0,0 +1,366 @@ +checkImap(); +$javascript = new Javascript(); +$email = new Email(); +/* Start standard EditView setup logic */ + +$domMailBoxType = $app_list_strings['dom_mailbox_type']; + +if(isset($_REQUEST['record'])) { + $GLOBALS['log']->debug("In InboundEmail edit view, about to retrieve record: ".$_REQUEST['record']); + $result = $focus->retrieve($_REQUEST['record']); + if($result == null) + { + sugar_die($app_strings['ERROR_NO_RECORD']); + } +} +else +{ + if(!empty($_REQUEST['mailbox_type'])) + $focus->mailbox_type = $_REQUEST['mailbox_type']; + + //Default to imap protocol for new accounts. + $focus->protocol = 'imap'; +} + +if($focus->mailbox_type == 'bounce') +{ + unset($domMailBoxType['pick']); + unset($domMailBoxType['createcase']); +} +else + unset($domMailBoxType['bounce']); + +if(isset($_REQUEST['isDuplicate']) && $_REQUEST['isDuplicate'] == 'true') { + $GLOBALS['log']->debug("isDuplicate found - duplicating record of id: ".$focus->id); + $focus->id = ""; +} + +$GLOBALS['log']->info("InboundEmail Edit View"); +/* End standard EditView setup logic */ + +/* Start custom setup logic */ +// status drop down +$status = get_select_options_with_id_separate_key($app_list_strings['user_status_dom'],$app_list_strings['user_status_dom'], $focus->status); +// default MAILBOX value +if(empty($focus->mailbox)) { + $mailbox = 'INBOX'; +} else { + $mailbox = $focus->mailbox; +} + +// service options breakdown +$tls = ''; +$notls = ''; +$cert = ''; +$novalidate_cert = ''; +$ssl = ''; +if(!empty($focus->service)) { + // will always have 2 values: /tls || /notls and /validate-cert || /novalidate-cert + $exServ = explode('::', $focus->service); + if($exServ[0] == 'tls') { + $tls = "CHECKED"; + } elseif($exServ[5] == 'notls') { + $notls = "CHECKED"; + } + if($exServ[1] == 'validate-cert') { + $cert = "CHECKED"; + } elseif($exServ[4] == 'novalidate-cert') { + $novalidate_cert = 'CHECKED'; + } + if(isset($exServ[2]) && !empty($exServ[2]) && $exServ[2] == 'ssl') { + $ssl = "CHECKED"; + } +} +$mark_read = ''; +if($focus->delete_seen == 0 || empty($focus->delete_seen)) { + $mark_read = 'CHECKED'; +} + +// mailbox type + +if ($focus->is_personal) { + array_splice($domMailBoxType, 1, 1); +} // if +$mailbox_type = get_select_options_with_id($domMailBoxType, $focus->mailbox_type); + +// auto-reply email template +$email_templates_arr = get_bean_select_array(true, 'EmailTemplate','name', '','name',true); + +if(!empty($focus->stored_options)) { + $storedOptions = unserialize(base64_decode($focus->stored_options)); + $from_name = $storedOptions['from_name']; + $from_addr = $storedOptions['from_addr']; + + $reply_to_name = (isset($storedOptions['reply_to_name'])) ? $storedOptions['reply_to_name'] : ""; + $reply_to_addr = (isset($storedOptions['reply_to_addr'])) ? $storedOptions['reply_to_addr'] : ""; + + $trashFolder = (isset($storedOptions['trashFolder'])) ? $storedOptions['trashFolder'] : ""; + $sentFolder = (isset($storedOptions['sentFolder'])) ? $storedOptions['sentFolder'] : ""; + $distrib_method = (isset($storedOptions['distrib_method'])) ? $storedOptions['distrib_method'] : ""; + $create_case_email_template = (isset($storedOptions['create_case_email_template'])) ? $storedOptions['create_case_email_template'] : ""; + $email_num_autoreplies_24_hours = (isset($storedOptions['email_num_autoreplies_24_hours'])) ? $storedOptions['email_num_autoreplies_24_hours'] : $focus->defaultEmailNumAutoreplies24Hours; + + if($storedOptions['only_since']) { + $only_since = 'CHECKED'; + } else { + $only_since = ''; + } + if(isset($storedOptions['filter_domain']) && !empty($storedOptions['filter_domain'])) { + $filterDomain = $storedOptions['filter_domain']; + } else { + $filterDomain = ''; + } + if(!isset($storedOptions['leaveMessagesOnMailServer']) || $storedOptions['leaveMessagesOnMailServer'] == 1) { + $leaveMessagesOnMailServer = 1; + } else { + $leaveMessagesOnMailServer = 0; + } // else +} else { // initialize empty vars for template + $from_name = $current_user->name; + $from_addr = $current_user->email1; + $reply_to_name = ''; + $reply_to_addr = ''; + $only_since = ''; + $filterDomain = ''; + $trashFolder = ''; + $sentFolder = ''; + $distrib_method =''; + $create_case_email_template=''; + $leaveMessagesOnMailServer = 1; + $email_num_autoreplies_24_hours = $focus->defaultEmailNumAutoreplies24Hours; +} // else + +// return action +if(isset($focus->id)) { + $return_action = 'DetailView'; +} else { + $return_action = 'ListView'; +} + +// javascript +$javascript->setSugarBean($focus); +$javascript->setFormName('EditView'); +$javascript->addRequiredFields(); +$javascript->addFieldGeneric('email_user', 'alpha', $mod_strings['LBL_LOGIN'], true); +$javascript->addFieldGeneric('email_password', 'alpha', $mod_strings['LBL_PASSWORD'], false); +$javascript->addFieldRange('email_num_autoreplies_24_hours', 'int', $mod_strings['LBL_MAX_AUTO_REPLIES'], true, "", 1, $focus->maxEmailNumAutoreplies24Hours); + +$r = $focus->db->query('SELECT value FROM config WHERE name = \'fromname\''); +$a = $focus->db->fetchByAssoc($r); +$default_from_name = $a['value']; +$r = $focus->db->query('SELECT value FROM config WHERE name = \'fromaddress\''); +$a = $focus->db->fetchByAssoc($r); +$default_from_addr = $a['value']; + +/* End custom setup logic */ + + +// TEMPLATE ASSIGNMENTS +if ($focus->mailbox_type == 'template') { + $xtpl = new XTemplate('modules/InboundEmail/EmailAccountTemplateEditView.html'); +} else { + $xtpl = new XTemplate('modules/InboundEmail/EditView.html'); +} +// if no IMAP libraries available, disable Save/Test Settings +if(!function_exists('imap_open')) { + $xtpl->assign('IE_DISABLED', 'DISABLED'); +} +// standard assigns +$xtpl->assign('MOD', $mod_strings); +$xtpl->assign('APP', $app_strings); +$xtpl->assign('THEME', SugarThemeRegistry::current()->__toString()); +$xtpl->assign('GRIDLINE', $gridline); +$xtpl->assign('MODULE', 'InboundEmail'); +$xtpl->assign('RETURN_MODULE', 'InboundEmail'); +$xtpl->assign('RETURN_ID', $focus->id); +$xtpl->assign('RETURN_ACTION', $return_action); +// module specific +//$xtpl->assign('ROLLOVER', $email->rolloverStyle); +$xtpl->assign("EMAIL_OPTIONS", $mod_strings['LBL_EMAIL_OPTIONS']); +$xtpl->assign('MODULE_TITLE', getClassicModuleTitle($mod_strings['LBL_MODULE_TITLE'], array($mod_strings['LBL_MODULE_NAME'],$focus->name), true)); +$xtpl->assign('ID', $focus->id); +$xtpl->assign('NAME', $focus->name); +$xtpl->assign('STATUS', $status); +$xtpl->assign('SERVER_URL', $focus->server_url); +$xtpl->assign('USER', $focus->email_user); +// Don't send password back $xtpl->assign('PASSWORD', $focus->email_password); +$xtpl->assign('TRASHFOLDER', $trashFolder); +$xtpl->assign('SENTFOLDER', $sentFolder); +$xtpl->assign('MAILBOX', $mailbox); +$xtpl->assign('TLS', $tls); +$xtpl->assign('NOTLS', $notls); +$xtpl->assign('CERT', $cert); +$xtpl->assign('NOVALIDATE_CERT', $novalidate_cert); +$xtpl->assign('SSL', $ssl); + +$protocol = filterInboundEmailPopSelection($app_list_strings['dom_email_server_type']); +$xtpl->assign('PROTOCOL', get_select_options_with_id($protocol, $focus->protocol)); +$xtpl->assign('MARK_READ', $mark_read); +$xtpl->assign('MAILBOX_TYPE', $focus->mailbox_type); +$xtpl->assign('TEMPLATE_ID', $focus->template_id); +$xtpl->assign('EMAIL_TEMPLATE_OPTIONS', get_select_options_with_id($email_templates_arr, $focus->template_id)); +$xtpl->assign('ONLY_SINCE', $only_since); +$xtpl->assign('FILTER_DOMAIN', $filterDomain); +$xtpl->assign('EMAIL_NUM_AUTOREPLIES_24_HOURS', $email_num_autoreplies_24_hours); +if(!empty($focus->port)) { + $xtpl->assign('PORT', $focus->port); +} +// groups +$groupId = ""; +$is_auto_import = ""; +$allow_outbound = ''; +if(isset($focus->id)) + $groupId = $focus->group_id; +else +{ + $groupId = create_guid(); + $is_auto_import = 'checked'; +} + +$xtpl->assign('GROUP_ID', $groupId); +// auto-reply stuff +$xtpl->assign('FROM_NAME', $from_name); +$xtpl->assign('FROM_ADDR', $from_addr); +$xtpl->assign('DEFAULT_FROM_NAME', $default_from_name); +$xtpl->assign('DEFAULT_FROM_ADDR', $default_from_addr); +$xtpl->assign('REPLY_TO_NAME', $reply_to_name); +$xtpl->assign('REPLY_TO_ADDR', $reply_to_addr); +$createCaseRowStyle = "display:none"; +if($focus->template_id) { + $xtpl->assign("EDIT_TEMPLATE","visibility:inline"); +} else { + $xtpl->assign("EDIT_TEMPLATE","visibility:hidden"); +} +if($focus->port == 110 || $focus->port == 995) { + $xtpl->assign('DISPLAY', "display:''"); +} else { + $xtpl->assign('DISPLAY', "display:none"); +} +$leaveMessagesOnMailServerStyle = "display:none"; +if($focus->is_personal) { + $xtpl->assign('DISABLE_GROUP', 'DISABLED'); + $xtpl->assign('EDIT_GROUP_FOLDER_STYLE', "display:none"); + $xtpl->assign('CREATE_GROUP_FOLDER_STYLE', "display:none"); + $xtpl->assign('MAILBOX_TYPE_STYLE', "display:none"); + $xtpl->assign('AUTO_IMPORT_STYLE', "display:none"); +} else { + $folder = new SugarFolder(); + $xtpl->assign('CREATE_GROUP_FOLDER_STYLE', "display:''"); + $xtpl->assign('MAILBOX_TYPE_STYLE', "display:''"); + $xtpl->assign('AUTO_IMPORT_STYLE', "display:''"); + $ret = $folder->getFoldersForSettings($current_user); + + //For existing records, do not allow + $is_auto_import_disabled = ""; + if (!empty($focus->groupfolder_id)) + { + $is_auto_import = "checked"; + $xtpl->assign('EDIT_GROUP_FOLDER_STYLE', "visibility:inline"); + $leaveMessagesOnMailServerStyle = "display:''"; + $allow_outbound = (isset($storedOptions['allow_outbound_group_usage']) && $storedOptions['allow_outbound_group_usage'] == 1) ? 'CHECKED' : ''; + } + else + { + $xtpl->assign('EDIT_GROUP_FOLDER_STYLE', "visibility:hidden"); + } + + $xtpl->assign('ALLOW_OUTBOUND_USAGE', $allow_outbound); + $xtpl->assign('IS_AUTO_IMPORT', $is_auto_import); + + if ($focus->isMailBoxTypeCreateCase()) + $createCaseRowStyle = "display:''"; + +} + +$xtpl->assign('hasGrpFld',$focus->groupfolder_id == null ? '' : 'checked="1"'); +$xtpl->assign('LEAVEMESSAGESONMAILSERVER_STYLE', $leaveMessagesOnMailServerStyle); +$xtpl->assign('LEAVEMESSAGESONMAILSERVER', get_select_options_with_id($app_list_strings['dom_int_bool'], $leaveMessagesOnMailServer)); +$distributionMethod = get_select_options_with_id($app_list_strings['dom_email_distribution_for_auto_create'], $distrib_method); +$xtpl->assign('DISTRIBUTION_METHOD', $distributionMethod); +$xtpl->assign('CREATE_CASE_ROW_STYLE', $createCaseRowStyle); +$xtpl->assign('CREATE_CASE_EMAIL_TEMPLATE_OPTIONS', get_select_options_with_id($email_templates_arr, $create_case_email_template)); +if(!empty($create_case_email_template)) { + $xtpl->assign("CREATE_CASE_EDIT_TEMPLATE","visibility:inline"); +} else { + $xtpl->assign("CREATE_CASE_EDIT_TEMPLATE","visibility:hidden"); +} + +$quicksearch_js = ""; + +//$javascript = get_set_focus_js(). $javascript->getScript() . $quicksearch_js; +$xtpl->assign('JAVASCRIPT', get_set_focus_js(). $javascript->getScript() . $quicksearch_js); + +// WINDOWS work arounds +//if(is_windows()) { +// $xtpl->assign('MAYBE', ''); +//} +// PARSE AND PRINT +//Overrides for bounce mailbox accounts +if ($focus->mailbox_type == 'bounce') +{ + $xtpl->assign('MODULE_TITLE', getClassicModuleTitle($mod_strings['LBL_MODULE_TITLE'], array($mod_strings['LBL_BOUNCE_MODULE_NAME'],$focus->name), true)); + $xtpl->assign("EMAIL_OPTIONS", $mod_strings['LBL_EMAIL_BOUNCE_OPTIONS']); + $xtpl->assign('MAILBOX_TYPE_STYLE', "display:none"); + $xtpl->assign('AUTO_IMPORT_STYLE', "display:none"); +} +elseif ($focus->mailbox_type == 'createcase') + $xtpl->assign("IS_CREATE_CASE", 'checked'); + +else if( $focus->is_personal == '1') + $xtpl->assign('MODULE_TITLE', getClassicModuleTitle($mod_strings['LBL_MODULE_TITLE'], array($mod_strings['LBL_PERSONAL_MODULE_NAME'],$focus->name), true)); + +//else + + +$xtpl->parse("main"); +$xtpl->out("main"); +?> \ No newline at end of file diff --git a/modules/InboundEmail/InboundEmail.js b/modules/InboundEmail/InboundEmail.js new file mode 100644 index 00000000..afbac72c --- /dev/null +++ b/modules/InboundEmail/InboundEmail.js @@ -0,0 +1,94 @@ +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ +SUGAR.inboundEmail={};Rot13={map:null,convert:function(a){Rot13.init();var s="";for(i=0;i='A'&&b<='Z')||(b>='a'&&b<='z')?Rot13.map[b]:b);} +return s;},init:function(){if(Rot13.map!=null) +return;var map=new Array();var s="abcdefghijklmnopqrstuvwxyz";for(i=0;i0){fragment1=word.substr(0,word.indexOf('&'));fragment2=word.substr(word.indexOf('&')+1,word.length);newWord=fragment1+'::amp::'+fragment2;words[i]=newWord;word=newWord;fragment1='';fragment2='';} +if(word.indexOf('+')>0){fragment1=word.substr(0,word.indexOf('+'));fragment2=word.substr(word.indexOf('+')+1,word.length);newWord=fragment1+'::plus::'+fragment2;words[i]=newWord;word=newWord;fragment1='';fragment2='';} +if(word.indexOf('%')>0){fragment1=word.substr(0,word.indexOf('%'));fragment2=word.substr(word.indexOf('%')+1,word.length);newWord=fragment1+'::percent::'+fragment2;words[i]=newWord;word=newWord;fragment1='';fragment2='';}} +return words;} +function ie_test_open_popup_with_submit(module_name,action,pageTarget,width,height,mail_server,protocol,port,login,password,mailbox,ssl,personal,formName) +{if(!formName)formName="testSettingsView";var words=getEncryptedPassword(login,password,mailbox);var isPersonal=(personal)?'true':'false';if(!isDataValid(formName,true)){return;} +ie_id=(typeof document.getElementById(formName).ie_id!='undefined')?document.getElementById(formName).ie_id:'';URL='index.php?' ++'module='+module_name ++'&to_pdf=1' ++'&action='+action ++'&target='+pageTarget ++'&target1='+pageTarget ++'&server_url='+mail_server ++'&email_user='+words[0] ++'&protocol='+protocol ++'&port='+port ++'&email_password='+words[1] ++'&mailbox='+words[2] ++'&ssl='+ssl ++'&ie_id='+ie_id ++'&personal='+isPersonal;var SI=SUGAR.inboundEmail;if(!SI.testDlg){SI.testDlg=new YAHOO.widget.SimpleDialog("testSettingsDiv",{width:width+"px",draggable:true,dragOnly:true,close:true,constraintoviewport:true,modal:true,loadingText:SUGAR.language.get("app_strings","LBL_EMAIL_LOADING")});SI.testDlg._updateContent=function(o){var w=this.cfg.config.width.value+"px";this.setBody(o.responseText);if(this.evalJS) +SUGAR.util.evalScript(o.responseText);if(!SUGAR.isIE) +this.body.style.width=w}} +var title=SUGAR.language.get('Emails','LBL_TEST_SETTINGS');if(typeof(title)=="undefined"||title=="undefined") +title=SUGAR.language.get('InboundEmail','LBL_TEST_SETTINGS');SI.testDlg.setHeader(title);SI.testDlg.setBody(SUGAR.language.get("app_strings","LBL_EMAIL_LOADING"));SI.testDlg.render(document.body);var Connect=YAHOO.util.Connect;if(Connect.url)URL=Connect.url+"&"+url;Connect.asyncRequest("GET",URL,{success:SI.testDlg._updateContent,failure:SI.testDlg.hide,scope:SI.testDlg});SI.testDlg.show();} +function isDataValid(formName,validateMonitoredFolder){var formObject=document.getElementById(formName);var errors=new Array();var out=new String();if(trim(formObject.server_url.value)==""){errors.push(SUGAR.language.get('app_strings','LBL_EMAIL_ERROR_SERVER'));} +if(trim(formObject.email_user.value)==""){errors.push(SUGAR.language.get('app_strings','LBL_EMAIL_ERROR_USER'));} +if(trim(formObject.email_password.value)==""&&trim(formObject.ie_id.value)==""){errors.push(SUGAR.language.get('app_strings','LBL_EMAIL_ERROR_PASSWORD'));} +if(formObject.protocol.protocol==""){errors.push(SUGAR.language.get('app_strings','LBL_EMAIL_ERROR_PROTOCOL'));} +if(formObject.protocol.value=='imap'&&validateMonitoredFolder){if(trim(formObject.mailbox.value)==""){errors.push(SUGAR.language.get('app_strings','LBL_EMAIL_ERROR_MONITORED_FOLDER'));}} +if(formObject.port.value==""){errors.push(SUGAR.language.get('app_strings','LBL_EMAIL_ERROR_PORT'));} +if(errors.length>0){out=SUGAR.language.get('app_strings','LBL_EMAIL_ERROR_DESC');for(i=0;i', '|', '$',); + var $currentCache; + var $defaultSort = 'date'; + var $defaultDirection = "DESC"; + var $hrSort = array( + 0 => 'flagged', + 1 => 'status', + 2 => 'from', + 3 => 'subj', + 4 => 'date', + ); + var $hrSortLocal = array( + 'flagged' => 'flagged', + 'status' => 'answered', + 'from' => 'fromaddr', + 'subject' => 'subject', + 'date' => 'senddate', + ); + + // default attributes + var $transferEncoding = array(0 => '7BIT', + 1 => '8BIT', + 2 => 'BINARY', + 3 => 'BASE64', + 4 => 'QUOTED-PRINTABLE', + 5 => 'OTHER' + ); + // object attributes + var $safe; // place holder for HTML_Safe class + var $compoundMessageId; // concatenation of messageID and deliveredToEmail + var $serverConnectString; + var $disable_row_level_security = true; + var $InboundEmailCachePath; + var $InboundEmailCacheFile = 'InboundEmail.cache.php'; + var $object_name = 'InboundEmail'; + var $module_dir = 'InboundEmail'; + var $table_name = 'inbound_email'; + var $new_schema = true; + var $process_save_dates = true; + var $order_by; + var $db; + var $dbManager; + var $field_defs; + var $column_fields; + var $required_fields = array('name' => 'name', + 'server_url' => 'server_url', + 'mailbox' => 'mailbox', + 'user' => 'user', + 'port' => 'port', + ); + var $imageTypes = array("JPG", "JPEG", "GIF"); + var $inlineImages = array(); // temporary space to store ID of inlined images + var $defaultEmailNumAutoreplies24Hours = 10; + var $maxEmailNumAutoreplies24Hours = 10; + // custom ListView attributes + var $mailbox_type_name; + var $global_personal_string; + // service attributes + var $tls; + var $ca; + var $ssl; + var $protocol; + var $keyForUsersDefaultIEAccount = 'defaultIEAccount'; + + /** + * Sole constructor + */ + function InboundEmail() { + $this->InboundEmailCachePath = $GLOBALS['sugar_config']['cache_dir'].'modules/InboundEmail'; + parent::SugarBean(); + if(function_exists("imap_timeout")) { + /* + * 1: Open + * 2: Read + * 3: Write + * 4: Close + */ + imap_timeout(1, 60); + imap_timeout(2, 60); + imap_timeout(3, 60); + } + + $this->safe = new HTML_Safe(); + $this->safe->clear(); + $this->smarty = new Sugar_Smarty(); + $this->overview = new Overview(); + } + + /** + * retrieves I-E bean + * @param string id + * @return object Bean + */ + function retrieve($id) { + $ret = parent::retrieve($id); + $this->email_password = blowfishDecode(blowfishGetKey('InboundEmail'), $this->email_password); + $this->retrieveMailBoxFolders(); + return $ret; + } + + /** + * wraps SugarBean->save() + * @param string ID of saved bean + */ + function save($check_notify=false) { + // generate cache table for email 2.0 + $multiDImArray = $this->generateMultiDimArrayFromFlatArray(explode(",", $this->mailbox), $this->retrieveDelimiter()); + $raw = $this->generateFlatArrayFromMultiDimArray($multiDImArray, $this->retrieveDelimiter()); + sort($raw); + //_pp(explode(",", $this->mailbox)); + //_ppd($raw); + $raw = $this->filterMailBoxFromRaw(explode(",", $this->mailbox), $raw); + $this->mailbox = implode(",", $raw); + if(!empty($this->email_password)) { + $this->email_password = blowfishEncode(blowfishGetKey('InboundEmail'), $this->email_password); + } + $ret = parent::save($check_notify); + return $ret; + } + + function filterMailBoxFromRaw($mailboxArray, $rawArray) { + $newArray = array_intersect($mailboxArray, $rawArray); + sort($newArray); + return $newArray; + } // fn + + /** + * Overrides SugarBean's mark_deleted() to drop the related cache table + * @param string $id GUID of I-E instance + */ + function mark_deleted($id) { + parent::mark_deleted($id); + $q = "update inbound_email set groupfolder_id = null WHERE id = $id"; + $r = $this->db->query($q); + $this->deleteCache(); + } + + /** + * Mark cached email answered (replied) + * @param string $mailid (uid for imap, message_id for pop3) + */ + function mark_answered($mailid, $type = 'smtp') { + switch ($type) { + case 'smtp' : + $q = "update email_cache set answered = 1 WHERE imap_uid = $mailid and ie_id = '$this->id'"; + $this->db->query($q); + break; + case 'pop3' : + $q = "update email_cache set answered = 1 WHERE message_id = '$mailid' and ie_id = '$this->id'"; + $this->db->query($q); + break; + } + } + + /** + * Renames an IMAP mailbox + * @param string $newName + */ + function renameFolder($oldName, $newName) { + //$this->mailbox = "INBOX" + $this->connectMailserver(); + $oldConnect = $this->getConnectString('', $oldName); + $newConnect = $this->getConnectString('', $newName); + if(!imap_renamemailbox($this->conn, $oldConnect , $newConnect)) { + $GLOBALS['log']->debug("***INBOUNDEMAIL: failed to rename mailbox [ {$oldConnect} ] to [ {$newConnect} ]"); + } else { + $this->mailbox = str_replace($oldName, $newName, $this->mailbox); + $this->save(); + $sessionFoldersString = $this->getSessionInboundFoldersString($this->server_url, $this->email_user, $this->port, $this->protocol); + $sessionFoldersString = str_replace($oldName, $newName, $sessionFoldersString); + $this->setSessionInboundFoldersString($this->server_url, $this->email_user, $this->port, $this->protocol, $sessionFoldersString); + + } + } + + /////////////////////////////////////////////////////////////////////////// + //// CUSTOM LOGIC HOOKS + /** + * Called from $this->getMessageText() + * Allows upgrade-safe custom processing of message text. + * + * To use: + * 1. Create a directory path: ./custom/modules/InboundEmail if it does not exist + * 2. Create a file in the ./custom/InboundEmail/ folder called "getMessageText.php" + * 3. Define a function named "custom_getMessageText()" that takes a string as an argument and returns a string + * + * @param string $msgPart + * @return string + */ + function customGetMessageText($msgPart) { + $custom = "custom/modules/InboundEmail/getMessageText.php"; + + if(file_exists($custom)) { + include_once($custom); + + if(function_exists("custom_getMessageText")) { + $GLOBALS['log']->debug("*** INBOUND EMAIL-CUSTOM_LOGIC: calling custom_getMessageText()"); + $msgPart = custom_getMessageText($msgPart); + } + } + + return $msgPart; + } + //// END CUSTOM LOGIC HOOKS + /////////////////////////////////////////////////////////////////////////// + + + + /////////////////////////////////////////////////////////////////////////// + //// EMAIL 2.0 SPECIFIC + /** + * constructs a nicely formatted version of raw source + * @param int $uid UID of email + * @return string + */ + function getFormattedRawSource($uid) { + global $app_strings; + + //if($this->protocol == 'pop3') { + //$raw = $app_strings['LBL_EMAIL_VIEW_UNSUPPORTED']; + //} else { + if (empty($this->id)) { + $q = "SELECT raw_source FROM emails_text WHERE email_id = '{$uid}'"; + $r = $this->db->query($q); + $a = $this->db->fetchByAssoc($r); + $ret = array(); + $raw = utf8_encode($a['raw_source']); + if (empty($raw)) { + $raw = $app_strings['LBL_EMAIL_ERROR_VIEW_RAW_SOURCE']; + } + } else { + if ($this->isPop3Protocol()) { + $uid = $this->getCorrectMessageNoForPop3($uid); + } + $raw = imap_fetchheader($this->conn, $uid, FT_UID+FT_PREFETCHTEXT); + $raw .= utf8_encode(imap_body($this->conn, $uid, FT_UID)); + } // else + $raw = to_html($raw); + $raw = nl2br($raw); + //} + + return $raw; + } + + /** + * constructs a nicely formatted version of email headers. + * @param int $uid + * @return string + */ + function getFormattedHeaders($uid) { + global $app_strings; + + //if($this->protocol == 'pop3') { + // $header = $app_strings['LBL_EMAIL_VIEW_UNSUPPORTED']; + //} else { + if ($this->isPop3Protocol()) { + $uid = $this->getCorrectMessageNoForPop3($uid); + } + $headers = imap_fetchheader($this->conn, $uid, FT_UID); + + $lines = explode("\n", $headers); + + $header = ""; + + foreach($lines as $line) { + $line = trim($line); + + if(!empty($line)) { + $key = trim(substr($line, 0, strpos($line, ":"))); + $value = trim(substr($line, strpos($line, ":") + 1)); + $value = to_html($value); + + $header .= ""; + $header .= ""; + $header .= ""; + $header .= ""; + } + } + + $header .= "
    {$key} {$value} 
    "; + //} + return $header; + } + + /** + * Empties Trash folders + */ + function emptyTrash() { + global $sugar_config; + + $this->mailbox = $this->get_stored_options("trashFolder"); + if (empty($this->mailbox)) { + $this->mailbox = 'INBOX.Trash'; + } + $this->connectMailserver(); + + $uids = imap_search($this->conn, "ALL", SE_UID); + + foreach($uids as $uid) { + if(!imap_delete($this->conn, $uid, FT_UID)) { + $lastError = imap_last_error(); + $GLOBALS['log']->warn("INBOUNDEMAIL: emptyTrash() Could not delete message [ {$uid} ] from [ {$this->mailbox} ]. IMAP_ERROR [ {$lastError} ]"); + } + } + + // remove local cache file + $q = "DELETE FROM email_cache WHERE mbox = '{$this->mailbox}' AND ie_id = '{$this->id}'"; + $r = $this->db->query($q); + } + + /** + * Fetches a timestamp + */ + function getCacheTimestamp($mbox) { + $key = $this->db->quote("{$this->id}_{$mbox}"); + $q = "SELECT ie_timestamp FROM inbound_email_cache_ts WHERE id = '{$key}'"; + $r = $this->db->query($q); + $a = $this->db->fetchByAssoc($r); + + if(empty($a)) { + return -1; + } + return $a['ie_timestamp']; + } + + /** + * sets the cache timestamp + * @param string mbox + */ + function setCacheTimestamp($mbox) { + $key = $this->db->quote("{$this->id}_{$mbox}"); + $ts = mktime(); + $tsOld = $this->getCacheTimestamp($mbox); + + if($tsOld < 0) { + $q = "INSERT INTO inbound_email_cache_ts (id, ie_timestamp) VALUES ('{$key}', {$ts})"; + } else { + $q = "UPDATE inbound_email_cache_ts SET ie_timestamp = {$ts} WHERE id = '{$key}'"; + } + + $r = $this->db->query($q, true); + $GLOBALS['log']->info("INBOUNDEMAIL-CACHE: setting timestamp query [ {$q} ]"); + } + + + /** + * Gets a count of all rows that are flagged seen = 0 + * @param string $mbox + * @return int + */ + function getCacheUnreadCount($mbox) { + $q = "SELECT count(*) c FROM email_cache WHERE mbox = '{$mbox}' AND seen = 0 AND ie_id = '{$this->id}'"; + $r = $this->db->query($q); + $a = $this->db->fetchByAssoc($r); + + return $a['c']; + } + + /** + * Returns total number of emails for a mailbox + * @param string mbox + * @return int + */ + function getCacheCount($mbox) { + $q = "SELECT count(*) c FROM email_cache WHERE mbox = '{$mbox}' AND ie_id = '{$this->id}'"; + $r = $this->db->query($q); + $a = $this->db->fetchByAssoc($r); + + return $a['c']; + } + + function getCacheUnread($mbox) { + $q = "SELECT count(*) c FROM email_cache WHERE mbox = '{$mbox}' AND ie_id = '{$this->id}' AND seen = '0'"; + $r = $this->db->query($q); + $a = $this->db->fetchByAssoc($r); + + return $a['c']; + } + + + /** + * Deletes all rows for a given instance + */ + function deleteCache() { + $q = "DELETE FROM email_cache WHERE ie_id = '{$this->id}'"; + + $GLOBALS['log']->info("INBOUNDEMAIL: deleting cache using query [ {$q} ]"); + + $r = $this->db->query($q); + } + + /** + * Deletes all the pop3 data which has been deleted from server + */ + function deletePop3Cache() { + global $sugar_config; + $UIDLs = $this->pop3_getUIDL(); + $cacheUIDLs = $this->pop3_getCacheUidls(); + foreach($cacheUIDLs as $msgNo => $msgId) { + if (!in_array($msgId, $UIDLs)) { + $md5msgIds = md5($msgId); + $file = "{$sugar_config['cache_dir']}modules/Emails/{$this->id}/messages/INBOX{$md5msgIds}.PHP"; + $GLOBALS['log']->debug("INBOUNDEMAIL: deleting file [ {$file} ] "); + if(file_exists($file)) { + if(!unlink($file)) { + $GLOBALS['log']->debug("INBOUNDEMAIL: Could not delete [ {$file} ] "); + } // if + } // if + $q = "DELETE from email_cache where imap_uid = {$msgNo} AND msgno = {$msgNo} AND ie_id = '{$this->id}' AND message_id = '{$msgId}'"; + $r = $this->db->query($q); + } // if + } // for + } // fn + + /** + * Retrieves cached headers + * @return array + */ + function getCacheValueForUIDs($mbox, $UIDs) { + if (!is_array($UIDs) || empty($UIDs)) { + return array(); + } + + $q = "SELECT * FROM email_cache WHERE ie_id = '{$this->id}' AND mbox = '{$mbox}' AND "; + $startIndex = 0; + $endIndex = 5; + + $slicedArray = array_slice($UIDs, $startIndex ,$endIndex); + $columnName = ($this->isPop3Protocol() ? "message_id" : "imap_uid"); + $ret = array( + 'timestamp' => $this->getCacheTimestamp($mbox), + 'uids' => array(), + 'retArr' => array(), + ); + while (!empty($slicedArray)) { + $messageIdString = implode(',', $slicedArray); + $GLOBALS['log']->debug("sliced array = {$messageIdString}"); + $extraWhere = "{$columnName} IN ("; + $i = 0; + foreach($slicedArray as $UID) { + if($i != 0) { + $extraWhere = $extraWhere . ","; + } // if + $i++; + $extraWhere = "{$extraWhere} '{$UID}'"; + } // foreach + $newQuery = $q . $extraWhere . ")"; + $r = $this->db->query($newQuery); + + while($a = $this->db->fetchByAssoc($r)) { + if (isset($a['uid'])) { + if ($this->isPop3Protocol()) { + $ret['uids'][] = $a['message_id']; + } else { + $ret['uids'][] = $a['uid']; + } + } + + $overview = new Overview(); + + foreach($a as $k => $v) { + $k=strtolower($k); + switch($k) { + case "imap_uid": + $overview->imap_uid = $v; + if ($this->isPop3Protocol()) { + $overview->uid = $a['message_id']; + } else { + $overview->uid = $v; + } + break; + case "toaddr": + $overview->to = from_html($v); + break; + + case "fromaddr": + $overview->from = from_html($v); + break; + + case "mailsize": + $overview->size = $v; + break; + + case "senddate": + $overview->date = $v; + break; + + default: + $overview->$k = from_html($v); + break; + } // switch + } // foreach + $ret['retArr'][] = $overview; + } // while + $startIndex = $startIndex + $endIndex; + $slicedArray = array_slice($UIDs, $startIndex ,$endIndex); + $messageIdString = implode(',', $slicedArray); + $GLOBALS['log']->debug("sliced array = {$messageIdString}"); + } // while + return $ret; + } + + /** + * Retrieves cached headers + * @return array + */ + function getCacheValue($mbox, $limit = 20, $page = 1, $sort='', $direction='') { + // try optimizing this call as we don't want repeat queries + if(!empty($this->currentCache)) { + return $this->currentCache; + } + + $sort = (empty($sort)) ? $this->defaultSort : $sort; + $direction = (empty($direction)) ? $this->defaultDirection : $direction; + $order = " ORDER BY {$this->hrSortLocal[$sort]} {$direction}"; + + $q = "SELECT * FROM email_cache WHERE ie_id = '{$this->id}' AND mbox = '{$mbox}' {$order}"; + + if(!empty($limit)) { + $start = ( $page - 1 ) * $limit; + $r = $this->db->limitQuery($q, $start, $limit); + } else { + $r = $this->db->query($q); + } + + $ret = array( + 'timestamp' => $this->getCacheTimestamp($mbox), + 'uids' => array(), + 'retArr' => array(), + ); + + while($a = $this->db->fetchByAssoc($r)) { + if (isset($a['uid'])) { + if ($this->isPop3Protocol()) { + $ret['uids'][] = $a['message_id']; + } else { + $ret['uids'][] = $a['uid']; + } + } + + $overview = new Overview(); + + foreach($a as $k => $v) { + $k=strtolower($k); + switch($k) { + case "imap_uid": + $overview->imap_uid = $v; + if ($this->isPop3Protocol()) { + $overview->uid = $a['message_id']; + } else { + $overview->uid = $v; + } + break; + case "toaddr": + $overview->to = from_html($v); + break; + + case "fromaddr": + $overview->from = from_html($v); + break; + + case "mailsize": + $overview->size = $v; + break; + + case "senddate": + $overview->date = $v; + break; + + default: + $overview->$k = from_html($v); + break; + } + } + $ret['retArr'][] = $overview; + } + + $this->currentCache = $ret; + + return $ret; + } + + /** + * Sets cache values + */ + function setCacheValue($mbox, $insert, $update=array(), $remove=array()) { + if(empty($mbox)) { + return; + } + global $timedate; + + + // reset in-memory cache + $this->currentCache = null; + + $table = 'email_cache'; + $where = "WHERE ie_id = '{$this->id}' AND mbox = '{$mbox}'"; + + // handle removed rows + if(!empty($remove)) { + $removeIds = ''; + foreach($remove as $overview) { + if(!empty($removeIds)) { + $removeIds .= ","; + } + + $removeIds .= "'{$overview->imap_uid}'"; + } + + $q = "DELETE FROM {$table} {$where} AND imap_uid IN ({$removeIds})"; + + $GLOBALS['log']->info("INBOUNDEMAIL-CACHE: delete query [ {$q} ]"); + + $r = $this->db->query($q, true, $q); + } + + // handle insert rows + if(!empty($insert)) { + $q = "SELECT imap_uid FROM {$table} {$where}"; + $GLOBALS['log']->info("INBOUNDEMAIL-CACHE: filter UIDs query [ {$q} ]"); + $r = $this->db->query($q); + $uids = array(); + + while($a = $this->db->fetchByAssoc($r)) { + $uids[] = $a['imap_uid']; + } + $count = count($uids); + $GLOBALS['log']->info("INBOUNDEMAIL-CACHE: found [ {$count} ] UIDs to filter against"); + + $tmp = ''; + foreach($uids as $uid) { + if(!empty($tmp)) + $tmp .= ", "; + $tmp .= "{$uid}"; + } + $GLOBALS['log']->info("INBOUNDEMAIL-CACHE: filter UIDs: [ {$tmp} ]"); + + $cols = ""; + + foreach($this->overview->fieldDefs as $colDef) { + if(!empty($cols)) + $cols .= ","; + + $cols .= "{$colDef['name']}"; + } + foreach($insert as $overview) { + if(in_array($overview->imap_uid, $uids)) { + $update[] = $overview; + continue; + } + + $values = ''; + + foreach($this->overview->fieldDefs as $colDef) { + if(!empty($values)) { + $values .= ", "; + } + + // trim values for Oracle/MSSql + if( isset($colDef['len']) && !empty($colDef['len']) && + isset($colDef['type']) && !empty($colDef['type']) && + $colDef['type'] == 'varchar' + ) { + $overview->$colDef['name'] = substr($overview->$colDef['name'], 0, $colDef['len']); + } + + switch($colDef['name']) { + case "imap_uid": + if(isset($overview->uid) && !empty($overview->uid)) { + $this->imap_uid = $overview->uid; + } + $values .= "'{$this->imap_uid}'"; + break; + + case "ie_id": + $values .= "'{$this->id}'"; + break; + + case "toaddr": + $values .= "'".$this->db->helper->escape_quote($overview->to)."'"; + break; + + case "fromaddr": + $values .= "'".$this->db->helper->escape_quote($overview->from)."'"; + break; + + case "message_id" : + $values .= "'".$this->db->helper->escape_quote($overview->message_id)."'"; + break; + + case "mailsize": + $values .= $overview->size; + break; + + case "senddate": + $conv=$timedate->fromString($overview->date); + if (!empty($conv)) { + $values .= "'" . $conv->asDb() ."'"; + } else { + $values .= "NULL"; + } + break; + + case "mbox": + $values .= "'{$mbox}'"; + break; + + default: + $overview->$colDef['name'] = from_html($overview->$colDef['name']); + $overview->$colDef['name'] = $this->cleanContent($overview->$colDef['name']); + $values .= "'".$this->db->helper->escape_quote($overview->$colDef['name'])."'"; + break; + } + } + + $q = "INSERT INTO {$table} ({$cols}) VALUES ({$values})"; + $GLOBALS['log']->info("INBOUNDEMAIL-CACHE: insert query [ {$q} ]"); + $r = $this->db->query($q, true, $q); + } + } + + // handle update rows + if(!empty($update)) { + $cols = ""; + foreach($this->overview->fieldDefs as $colDef) { + if(!empty($cols)) + $cols .= ","; + + $cols .= "{$colDef['name']}"; + } + + foreach($update as $overview) { + $q = "UPDATE {$table} SET "; + + $set = ''; + foreach($this->overview->fieldDefs as $colDef) { + + switch($colDef['name']) { + case "toaddr": + //$set .= "toaddr = '".$this->db->helper->escape_quote($overview->to)."'"; + break; + + case "fromaddr": + //$set .= "fromaddr = '".$this->db->helper->escape_quote($overview->from)."'"; + break; + + case "mailsize": + //$set .= "mailsize = {$overview->size}"; + break; + + case "senddate": + //$set .= "senddate = '".date("Y-m-d H:i:s", $overview->date)."'"; + break; + + case "mbox": + //$set .= "mbox = '{$mbox}'"; + break; + + default: + if(!empty($set)) { + $set .= ","; + } + $set .= "{$colDef['name']} = '".$this->db->helper->escape_quote($overview->$colDef['name'])."'"; + break; + } + } + + $q .= $set . " WHERE ie_id = '{$this->id}' AND mbox = '{$overview->mbox}' AND imap_uid = '{$overview->imap_uid}'"; + $GLOBALS['log']->info("INBOUNDEMAIL-CACHE: update query [ {$q} ]"); + $r = $this->db->query($q, true, $q); + } + } + + } + + /** + * Opens a socket connection to the pop3 server + * @return bool + */ + function pop3_open() { + if(!is_resource($this->pop3socket)) { + $GLOBALS['log']->info("*** INBOUNDEMAIL: opening socket connection"); + $exServ = explode('::', $this->service); + $socket = ($exServ[2] == 'ssl') ? "ssl://" : "tcp://"; + $socket .= $this->server_url; + $this->pop3socket = fsockopen($socket, $this->port); + } else { + $GLOBALS['log']->info("*** INBOUNDEMAIL: REUSING socket connection"); + return true; + } + + if(!is_resource($this->pop3socket)) { + $GLOBALS['log']->debug("*** INBOUNDEMAIL: unable to open socket connection"); + return false; + } + + // clear buffer + $ret = trim(fgets($this->pop3socket, 1024)); + $GLOBALS['log']->info("*** INBOUNDEMAIL: got socket connection [ {$ret} ]"); + return true; + } + + /** + * Closes connections and runs clean-up routines + */ + function pop3_cleanUp() { + $GLOBALS['log']->info("*** INBOUNDEMAIL: cleaning up socket connection"); + fputs($this->pop3socket, "QUIT\r\n"); + $buf = fgets($this->pop3socket, 1024); + fclose($this->pop3socket); + } + + /** + * sends a command down to the POP3 server + * @param string command + * @param string args + * @param bool return + * @return string + */ + function pop3_sendCommand($command, $args='', $return=true) { + $command .= " {$args}"; + $command = trim($command); + $GLOBALS['log']->info("*** INBOUNDEMAIL: pop3_sendCommand() SEND [ {$command} ]"); + $command .= "\r\n"; + + fputs($this->pop3socket, $command); + + if($return) { + $ret = trim(fgets($this->pop3socket, 1024)); + $GLOBALS['log']->info("*** INBOUNDEMAIL: pop3_sendCommand() RECEIVE [ {$ret} ]"); + return $ret; + } + } + + function getPop3NewMessagesToDownload() { + $pop3UIDL = $this->pop3_getUIDL(); + $cacheUIDLs = $this->pop3_getCacheUidls(); + // new email cache values we should deal with + $diff = array_diff_assoc($pop3UIDL, $cacheUIDLs); + // this is msgNo to UIDL array + $diff = $this->pop3_shiftCache($diff, $cacheUIDLs); + // get all the keys which are msgnos; + return array_keys($diff); + } + + function getPop3NewMessagesToDownloadForCron() { + $pop3UIDL = $this->pop3_getUIDL(); + $cacheUIDLs = $this->pop3_getCacheUidls(); + // new email cache values we should deal with + $diff = array_diff_assoc($pop3UIDL, $cacheUIDLs); + // this is msgNo to UIDL array + $diff = $this->pop3_shiftCache($diff, $cacheUIDLs); + // insert data into email_cache + if ($this->groupfolder_id != null && $this->groupfolder_id != "" && $this->isPop3Protocol()) { + $searchResults = array_keys($diff); + $concatResults = implode(",", $searchResults); + if ($this->connectMailserver() == 'true') { + $fetchedOverviews = imap_fetch_overview($this->conn, $concatResults); + // clean up cache entry + foreach($fetchedOverviews as $k => $overview) { + $overview->message_id = trim($diff[$overview->msgno]); + $fetchedOverviews[$k] = $overview; + } + $this->updateOverviewCacheFile($fetchedOverviews); + } + } // if + return $diff; + } + + /** + * This method returns all the UIDL for this account. This should be called if the protocol is pop3 + * @return array od messageno to UIDL array + */ + function pop3_getUIDL() { + $UIDLs = array(); + if($this->pop3_open()) { + // authenticate + $this->pop3_sendCommand("USER", $this->email_user); + $this->pop3_sendCommand("PASS", $this->email_password); + + // get UIDLs + $this->pop3_sendCommand("UIDL", '', false); // leave socket buffer alone until the while() + fgets($this->pop3socket, 1024); // handle "OK+"; + $UIDLs = array(); + + $buf = '!'; + + if(is_resource($this->pop3socket)) { + while(!feof($this->pop3socket)) { + $buf = fgets($this->pop3socket, 1024); // 8kb max buffer - shouldn't be more than 80 chars via pop3... + //_pp(trim($buf)); + + if(trim($buf) == '.') { + $GLOBALS['log']->debug("*** GOT '.'"); + break; + } + + // format is [msgNo] [UIDL] + $exUidl = explode(" ", $buf); + $UIDLs[$exUidl[0]] = trim($exUidl[1]); + } // while + } // if + $this->pop3_cleanUp(); + } // if + return $UIDLs; + } // fn + + /** + * Special handler for POP3 boxes. Standard IMAP commands are useless. + * This will fetch only partial emails for POP3 and hence needs to be call again and again based on status it returns + */ + function pop3_checkPartialEmail($synch = false) { + require_once('include/utils/array_utils.php'); + global $current_user; + global $sugar_config; + + $cacheDataExists = false; + $diff = array(); + $results = array(); + $cacheFilePath = clean_path("{$sugar_config['cache_dir']}modules/Emails/{$this->id}/folders/MsgNOToUIDLData.php"); + if(file_exists($cacheFilePath)) { + $cacheDataExists = true; + if($fh = @fopen($cacheFilePath, "rb")) { + $data = ""; + $chunksize = 1*(1024*1024); // how many bytes per chunk + while(!feof($fh)) { + $buf = fgets($fh, $chunksize); // 8kb max buffer - shouldn't be more than 80 chars via pop3... + $data = $data . $buf; + flush(); + } // while + fclose($fh); + $diff = unserialize($data); + if (!empty($diff)) { + if (count($diff)> 50) { + $newDiff = array_slice($diff, 50, count($diff), true); + } else { + $newDiff=array(); + } + $results = array_slice(array_keys($diff), 0 ,50); + $data = serialize($newDiff); + if($fh = @fopen($cacheFilePath, "w")) { + fputs($fh, $data); + fclose($fh); + } // if + } + } // if + } // if + if (!$cacheDataExists) { + if ($synch) { + $this->deletePop3Cache(); + } + $UIDLs = $this->pop3_getUIDL(); + if(count($UIDLs) > 0) { + // get cached UIDLs + $cacheUIDLs = $this->pop3_getCacheUidls(); + + // new email cache values we should deal with + $diff = array_diff_assoc($UIDLs, $cacheUIDLs); + $diff = $this->pop3_shiftCache($diff, $cacheUIDLs); + require_once('modules/Emails/EmailUI.php'); + EmailUI::preflightEmailCache("{$sugar_config['cache_dir']}modules/Emails/{$this->id}"); + + if (count($diff)> 50) { + $newDiff = array_slice($diff, 50, count($diff), true); + } else { + $newDiff=array(); + } + + $results = array_slice(array_keys($diff), 0 ,50); + $data = serialize($newDiff); + if($fh = @fopen($cacheFilePath, "w")) { + fputs($fh, $data); + fclose($fh); + } // if + } else { + $GLOBALS['log']->debug("*** INBOUNDEMAIL: could not open socket connection to POP3 server"); + return "could not open socket connection to POP3 server"; + } // else + } // if + + // build up msgNo request + if(count($diff) > 0) { + // remove dirty cache entries + $startingNo = 0; + if (isset($_REQUEST['currentCount']) && $_REQUEST['currentCount'] > -1) { + $startingNo = $_REQUEST['currentCount']; + } + + $this->mailbox = 'INBOX'; + $this->connectMailserver(); + //$searchResults = array_keys($diff); + //$fetchedOverviews = array(); + //$chunkArraySerachResults = array_chunk($searchResults, 50); + $concatResults = implode(",", $results); + $GLOBALS['log']->info('$$$$ '.$concatResults); + $GLOBALS['log']->info("[EMAIL] Start POP3 fetch overview on mailbox [{$this->mailbox}] for user [{$current_user->user_name}] on 50 data"); + $fetchedOverviews = imap_fetch_overview($this->conn, $concatResults); + $GLOBALS['log']->info("[EMAIL] End POP3 fetch overview on mailbox [{$this->mailbox}] for user [{$current_user->user_name}] on " + . sizeof($fetchedOverviews) . " data"); + + // clean up cache entry + foreach($fetchedOverviews as $k => $overview) { + $overview->message_id = trim($diff[$overview->msgno]); + $fetchedOverviews[$k] = $overview; + } + + $GLOBALS['log']->info("[EMAIL] Start updating overview cache for pop3 mailbox [{$this->mailbox}] for user [{$current_user->user_name}]"); + $this->updateOverviewCacheFile($fetchedOverviews); + $GLOBALS['log']->info("[EMAIL] Start updating overview cache for pop3 mailbox [{$this->mailbox}] for user [{$current_user->user_name}]"); + return array('status' => "In Progress", 'mbox' => $this->mailbox, 'count'=> (count($results) + $startingNo), 'totalcount' => count($diff), 'ieid' => $this->id); + } // if + unlink($cacheFilePath); + return array('status' => "done"); + } + + + /** + * Special handler for POP3 boxes. Standard IMAP commands are useless. + */ + function pop3_checkEmail() { + if($this->pop3_open()) { + // authenticate + $this->pop3_sendCommand("USER", $this->email_user); + $this->pop3_sendCommand("PASS", $this->email_password); + + // get UIDLs + $this->pop3_sendCommand("UIDL", '', false); // leave socket buffer alone until the while() + fgets($this->pop3socket, 1024); // handle "OK+"; + $UIDLs = array(); + + $buf = '!'; + + if(is_resource($this->pop3socket)) { + while(!feof($this->pop3socket)) { + $buf = fgets($this->pop3socket, 1024); // 8kb max buffer - shouldn't be more than 80 chars via pop3... + //_pp(trim($buf)); + + if(trim($buf) == '.') { + $GLOBALS['log']->debug("*** GOT '.'"); + break; + } + + // format is [msgNo] [UIDL] + $exUidl = explode(" ", $buf); + $UIDLs[$exUidl[0]] = trim($exUidl[1]); + } + } + + $this->pop3_cleanUp(); + + // get cached UIDLs + $cacheUIDLs = $this->pop3_getCacheUidls(); +// _pp($UIDLs);_pp($cacheUIDLs); + + // new email cache values we should deal with + $diff = array_diff_assoc($UIDLs, $cacheUIDLs); + + // remove dirty cache entries + $diff = $this->pop3_shiftCache($diff, $cacheUIDLs); + + // build up msgNo request + if(!empty($diff)) { + $this->mailbox = 'INBOX'; + $this->connectMailserver(); + $searchResults = array_keys($diff); + $concatResults = implode(",", $searchResults); + $fetchedOverviews = imap_fetch_overview($this->conn, $concatResults); + + // clean up cache entry + foreach($fetchedOverviews as $k => $overview) { + $overview->message_id = trim($diff[$overview->msgno]); + $fetchedOverviews[$k] = $overview; + } + + $this->updateOverviewCacheFile($fetchedOverviews); + } + } else { + $GLOBALS['log']->debug("*** INBOUNDEMAIL: could not open socket connection to POP3 server"); + return false; + } + } + + /** + * Iterates through msgno and message_id to remove dirty cache entries + * @param array diff + */ + function pop3_shiftCache($diff, $cacheUIDLs) { + $msgNos = ""; + $msgIds = ""; + $newArray = array(); + foreach($diff as $msgNo => $msgId) { + if (in_array($msgId, $cacheUIDLs)) { + $q1 = "UPDATE email_cache SET imap_uid = {$msgNo}, msgno = {$msgNo} WHERE ie_id = '{$this->id}' AND message_id = '{$msgId}'"; + $this->db->query($q1); + } else { + $newArray[$msgNo] = $msgId; + } + } + return $newArray; + /* + foreach($diff as $msgNo => $msgId) { + if(!empty($msgNos)) { + $msgNos .= ", "; + } + if(!empty($msgIds)) { + $msgIds .= ", "; + } + + $msgNos .= $msgNo; + $msgIds .= "'{$msgId}'"; + } + + if(!empty($msgNos)) { + $q1 = "DELETE FROM email_cache WHERE ie_id = '{$this->id}' AND msgno IN ({$msgNos})"; + $this->db->query($q1); + } + if(!empty($msgIds)) { + $q2 = "DELETE FROM email_cache WHERE ie_id = '{$this->id}' AND message_id IN ({$msgIds})"; + $this->db->query($q2); + } + */ + } + + /** + * retrieves cached uidl values. + * When dealing with POP3 accounts, the message_id column in email_cache will contain the UIDL. + * @return array + */ + function pop3_getCacheUidls() { + $q = "SELECT msgno, message_id FROM email_cache WHERE ie_id = '{$this->id}'"; + $r = $this->db->query($q); + + $ret = array(); + while($a = $this->db->fetchByAssoc($r)) { + $ret[$a['msgno']] = $a['message_id']; + } + + return $ret; + } + + /** + * This function is used by cron job for group mailbox without group folder + * @param string $msgno for pop + * @param string $uid for imap + */ + function getMessagesInEmailCache($msgno, $uid) { + $fetchedOverviews = array(); + if ($this->isPop3Protocol()) { + $fetchedOverviews = imap_fetch_overview($this->conn, $msgno); + foreach($fetchedOverviews as $k => $overview) { + $overview->message_id = $uid; + $fetchedOverviews[$k] = $overview; + } + } else { + $fetchedOverviews = imap_fetch_overview($this->conn, $uid, FT_UID); + } // else + $this->updateOverviewCacheFile($fetchedOverviews); + + } // fn + + /** + * Checks email (local caching too) for one mailbox + * @param string $mailbox IMAP Mailbox path + * @param bool $prefetch Flag to prefetch email body on check + */ + function checkEmailOneMailbox($mailbox, $prefetch=true, $synchronize=false) { + global $sugar_config; + global $current_user; + global $app_strings; + + $GLOBALS['log']->info("INBOUNDEMAIL: checking mailbox [ {$mailbox} ]"); + $this->mailbox = $mailbox; + $this->connectMailserver(); + + $checkTime = ''; + $shouldProcessRules = true; + + $timestamp = $this->getCacheTimestamp($mailbox); + + if($timestamp > 0) { + $checkTime = date('r', $timestamp); + } + + /* first time through, process ALL emails */ + if(empty($checkTime) || $synchronize) { + // do not process rules for the first time or sunchronize + $shouldProcessRules = false; + $criteria = "ALL UNDELETED"; + $prefetch = false; // do NOT prefetch emails on a brand new account - timeouts happen. + $GLOBALS['log']->info("INBOUNDEMAIL: new account detected - not prefetching email bodies."); + } else { + $criteria = "SINCE \"{$checkTime}\" UNDELETED"; // not using UNSEEN + } + $this->setCacheTimestamp($mailbox); + $GLOBALS['log']->info("[EMAIL] Performing IMAP search using criteria [{$criteria}] on mailbox [{$mailbox}] for user [{$current_user->user_name}]"); + $searchResults = imap_search($this->conn, $criteria, SE_UID); + $GLOBALS['log']->info("[EMAIL] Done IMAP search on mailbox [{$mailbox}] for user [{$current_user->user_name}]. Result count = ".count($searchResults)); + + if(!empty($searchResults)) { + + $concatResults = implode(",", $searchResults); + $GLOBALS['log']->info("[EMAIL] Start IMAP fetch overview on mailbox [{$mailbox}] for user [{$current_user->user_name}]"); + $fetchedOverview = imap_fetch_overview($this->conn, $concatResults, FT_UID); + $GLOBALS['log']->info("[EMAIL] Done IMAP fetch overview on mailbox [{$mailbox}] for user [{$current_user->user_name}]"); + + $GLOBALS['log']->info("[EMAIL] Start updating overview cache for mailbox [{$mailbox}] for user [{$current_user->user_name}]"); + $this->updateOverviewCacheFile($fetchedOverview); + $GLOBALS['log']->info("[EMAIL] Done updating overview cache for mailbox [{$mailbox}] for user [{$current_user->user_name}]"); + + // prefetch emails + if($prefetch == true) { + $GLOBALS['log']->info("[EMAIL] Start fetching emails for mailbox [{$mailbox}] for user [{$current_user->user_name}]"); + $this->fetchCheckedEmails($fetchedOverview); + $GLOBALS['log']->info("[EMAIL] Done fetching emails for mailbox [{$mailbox}] for user [{$current_user->user_name}]"); + } + } else { + $GLOBALS['log']->info("INBOUNDEMAIL: no results for mailbox [ {$mailbox} ]"); + } + + /** + * To handle the use case where an external client is also connected, deleting emails, we need to clear our + * local cache of all emails with the "DELETED" flag + */ + $criteria = 'DELETED'; + $criteria .= (!empty($checkTime)) ? " SINCE \"{$checkTime}\"" : ""; + $GLOBALS['log']->info("INBOUNDEMAIL: checking for deleted emails using [ {$criteria} ]"); + + $trashFolder = $this->get_stored_options("trashFolder"); + if (empty($trashFolder)) { + $trashFolder = "INBOX.Trash"; + } + + if($this->mailbox != $trashFolder) { + $searchResults = imap_search($this->conn, $criteria, SE_UID); + if(!empty($searchResults)) { + $uids = implode($app_strings['LBL_EMAIL_DELIMITER'], $searchResults); + $GLOBALS['log']->info("INBOUNDEMAIL: removing UIDs found deleted [ {$uids} ]"); + $this->getOverviewsFromCacheFile($uids, $mailbox, true); + } + } + } + + /** + * Checks email (local caching too) for one mailbox + * @param string $mailbox IMAP Mailbox path + * @param bool $prefetch Flag to prefetch email body on check + */ + function checkEmailOneMailboxPartial($mailbox, $prefetch=true, $synchronize=false, $start = 0, $max = -1) { + global $sugar_config; + global $current_user; + global $app_strings; + + $GLOBALS['log']->info("INBOUNDEMAIL: checking mailbox [ {$mailbox} ]"); + $this->mailbox = $mailbox; + $this->connectMailserver(); + + $checkTime = ''; + $shouldProcessRules = true; + + $timestamp = $this->getCacheTimestamp($mailbox); + + if($timestamp > 0) { + $checkTime = date('r', $timestamp); + } + + /* first time through, process ALL emails */ + if(empty($checkTime) || $synchronize) { + // do not process rules for the first time or sunchronize + $shouldProcessRules = false; + $criteria = "ALL UNDELETED"; + $prefetch = false; // do NOT prefetch emails on a brand new account - timeouts happen. + $GLOBALS['log']->info("INBOUNDEMAIL: new account detected - not prefetching email bodies."); + } else { + $criteria = "SINCE \"{$checkTime}\" UNDELETED"; // not using UNSEEN + } + $this->setCacheTimestamp($mailbox); + $GLOBALS['log']->info("[EMAIL] Performing IMAP search using criteria [{$criteria}] on mailbox [{$mailbox}] for user [{$current_user->user_name}]"); + $searchResults = $this->getCachedIMAPSearch($criteria); + + if(!empty($searchResults)) { + + $total = sizeof($searchResults); + $searchResults = array_slice($searchResults, $start, $max); + + $GLOBALS['log']->info("INBOUNDEMAIL: there are $total messages in [{$mailbox}], we are on $start"); + $GLOBALS['log']->info("INBOUNDEMAIL: getting the next " . sizeof($searchResults) . " messages"); + $concatResults = implode(",", $searchResults); + $GLOBALS['log']->info("INBOUNDEMAIL: Start IMAP fetch overview on mailbox [{$mailbox}] for user [{$current_user->user_name}]"); + $fetchedOverview = imap_fetch_overview($this->conn, $concatResults, FT_UID); + $GLOBALS['log']->info("INBOUNDEMAIL: Done IMAP fetch overview on mailbox [{$mailbox}] for user [{$current_user->user_name}]"); + + $GLOBALS['log']->info("INBOUNDEMAIL: Start updating overview cache for mailbox [{$mailbox}] for user [{$current_user->user_name}]"); + $this->updateOverviewCacheFile($fetchedOverview); + $GLOBALS['log']->info("INBOUNDEMAIL: Done updating overview cache for mailbox [{$mailbox}] for user [{$current_user->user_name}]"); + + // prefetch emails + if($prefetch == true) { + $GLOBALS['log']->info("INBOUNDEMAIL: Start fetching emails for mailbox [{$mailbox}] for user [{$current_user->user_name}]"); + $this->fetchCheckedEmails($fetchedOverview); + $GLOBALS['log']->info("INBOUNDEMAIL: Done fetching emails for mailbox [{$mailbox}] for user [{$current_user->user_name}]"); + } + $status = ($total > $start + sizeof($searchResults)) ? 'continue' : 'done'; + $ret = array('status' => $status, 'count' => $start + sizeof($searchResults), 'mbox' => $mailbox, 'totalcount' => $total); + $GLOBALS['log']->info("INBOUNDEMAIL: $status : Downloaded " . $start + sizeof($searchResults) . "messages of $total"); + + } else { + $GLOBALS['log']->info("INBOUNDEMAIL: no results for mailbox [ {$mailbox} ]"); + $ret = array('status' =>'done'); + } + + if ($ret['status'] == 'done') { + //Remove the cached search if we are done with this mailbox + $cacheFilePath = clean_path("{$sugar_config['cache_dir']}modules/Emails/{$this->id}/folders/SearchData.php"); + unlink($cacheFilePath); + /** + * To handle the use case where an external client is also connected, deleting emails, we need to clear our + * local cache of all emails with the "DELETED" flag + */ + $criteria = 'DELETED'; + $criteria .= (!empty($checkTime)) ? " SINCE \"{$checkTime}\"" : ""; + $GLOBALS['log']->info("INBOUNDEMAIL: checking for deleted emails using [ {$criteria} ]"); + + $trashFolder = $this->get_stored_options("trashFolder"); + if (empty($trashFolder)) { + $trashFolder = "INBOX.Trash"; + } + + if($this->mailbox != $trashFolder) { + $searchResults = imap_search($this->conn, $criteria, SE_UID); + if(!empty($searchResults)) { + $uids = implode($app_strings['LBL_EMAIL_DELIMITER'], $searchResults); + $GLOBALS['log']->info("INBOUNDEMAIL: removing UIDs found deleted [ {$uids} ]"); + $this->getOverviewsFromCacheFile($uids, $mailbox, true); + } + } + } + return $ret; + } + + function getCachedIMAPSearch($criteria) { + global $current_user; + global $sugar_config; + + $cacheDataExists = false; + $diff = array(); + $results = array(); + $cacheFolderPath = clean_path("{$sugar_config['cache_dir']}modules/Emails/{$this->id}/folders"); + if (!file_exists($cacheFolderPath)) { + mkdir_recursive($cacheFolderPath); + } + $cacheFilePath = $cacheFolderPath . '/SearchData.php'; + $GLOBALS['log']->info("INBOUNDEMAIL: Cache path is $cacheFilePath"); + if(file_exists($cacheFilePath)) { + $cacheDataExists = true; + if($fh = @fopen($cacheFilePath, "rb")) { + $data = ""; + $chunksize = 1*(1024*1024); // how many bytes per chunk + while(!feof($fh)) { + $buf = fgets($fh, $chunksize); // 8kb max buffer - shouldn't be more than 80 chars via pop3... + $data = $data . $buf; + flush(); + } // while + fclose($fh); + $results = unserialize($data); + } // if + } // if + if (!$cacheDataExists) { + $searchResults = imap_search($this->conn, $criteria, SE_UID); + if(count($searchResults) > 0) { + $results = $searchResults; + $data = serialize($searchResults); + if($fh = @fopen($cacheFilePath, "w")) { + fputs($fh, $data); + fclose($fh); + } // if + } + } // if + return $results; + } + + function checkEmailIMAPPartial($prefetch=true, $synch = false) { + $GLOBALS['log']->info("*****************INBOUNDEMAIL: at IMAP check partial"); + global $sugar_config; + $this->connectMailserver(); + $mailboxes = $this->getMailboxes(true); + if (!in_array('INBOX', $mailboxes)) { + $mailboxes[] = 'INBOX'; + } + sort($mailboxes); + if (isset($_REQUEST['mbox']) && !empty($_REQUEST['mbox']) && isset($_REQUEST['currentCount'])) { + $GLOBALS['log']->info("INBOUNDEMAIL: Picking up from where we left off"); + $mbox = $_REQUEST['mbox']; + $count = $_REQUEST['currentCount']; + } else { + if ($synch) { + $GLOBALS['log']->info("INBOUNDEMAIL: Cleaning out the cache"); + $this->cleanOutCache(); + } + $mbox = $mailboxes[0]; + $count = 0; + } + $GLOBALS['log']->info("INBOUNDEMAIL:found " . sizeof($mailboxes) . " Mailboxes"); + $index = array_search($mbox, $mailboxes) + 1; + $ret = $this->checkEmailOneMailboxPartial($mbox, $prefetch, $synch, $count, 100); + while($ret['status'] == 'done' && $index < sizeof($mailboxes)) { + if ($ret['count'] > 100) { + $ret['mbox'] = $mailboxes[$index]; + $ret['status'] = 'continue'; + return $ret; + } + $GLOBALS['log']->info("INBOUNDEMAIL: checking account [ $index => $mbox : $count]"); + $mbox = $mailboxes[$index]; + $ret = $this->checkEmailOneMailboxPartial($mbox, $prefetch, $synch, 0, 100); + $index++; + } + + return $ret; + } + + function checkEmail2_meta() { + global $sugar_config; + + $this->connectMailserver(); + $mailboxes = $this->getMailboxes(true); + $mailboxes[] = 'INBOX'; + sort($mailboxes); + + $GLOBALS['log']->info("INBOUNDEMAIL: checking account [ {$this->name} ]"); + + $mailboxes_meta = array(); + foreach($mailboxes as $mailbox) { + $mailboxes_meta[$mailbox] = $this->getMailboxProcessCount($mailbox); + } + + $ret = array(); + $ret['mailboxes'] = $mailboxes_meta; + + foreach($mailboxes_meta as $count) { + $ret['processCount'] += $count; + } + return $ret; + } + + function getMailboxProcessCount($mailbox) { + global $sugar_config; + + $GLOBALS['log']->info("INBOUNDEMAIL: checking mailbox [ {$mailbox} ]"); + $this->mailbox = $mailbox; + $this->connectMailserver(); + + $timestamp = $this->getCacheTimestamp($mailbox); + + $checkTime = ''; + if($timestamp > 0) { + $checkTime = date('r', $timestamp); + } + + /* first time through, process ALL emails */ + if(empty($checkTime)) { + $criteria = "ALL UNDELETED"; + $prefetch = false; // do NOT prefetch emails on a brand new account - timeouts happen. + $GLOBALS['log']->info("INBOUNDEMAIL: new account detected - not prefetching email bodies."); + } else { + $criteria = "SINCE \"{$checkTime}\" UNDELETED"; // not using UNSEEN + } + + $GLOBALS['log']->info("INBOUNDEMAIL: using [ {$criteria} ]"); + $searchResults = imap_search($this->conn, $criteria, SE_UID); + + if(!empty($searchResults)) { + $concatResults = implode(",", $searchResults); + } else { + $GLOBALS['log']->info("INBOUNDEMAIL: no results for mailbox [ {$mailbox} ]"); + } + + if(empty($searchResults)) { + return 0; + } + + return count($searchResults); + } + + /** + * update INBOX + */ + function checkEmail($prefetch=true, $synch = false) { + global $sugar_config; + + if($this->protocol == 'pop3') { + $this->pop3_checkEmail(); + } else { + $this->connectMailserver(); + $mailboxes = $this->getMailboxes(true); + $mailboxes[] = 'INBOX'; + sort($mailboxes); + + $GLOBALS['log']->info("INBOUNDEMAIL: checking account [ {$this->name} ]"); + + foreach($mailboxes as $mailbox) { + $this->checkEmailOneMailbox($mailbox, $prefetch, $synch); + } + } + } + + /** + * full synchronization + */ + function syncEmail() { + global $sugar_config; + global $current_user; + + $showFolders = unserialize(base64_decode($current_user->getPreference('showFolders', 'Emails'))); + + if(empty($showFolders)) { + $showFolders = array(); + } + + $email = new Email(); + $email->email2init(); + + // personal accounts + if($current_user->hasPersonalEmail()) { + $personals = $this->retrieveByGroupId($current_user->id); + + foreach($personals as $personalAccount) { + if(in_array($personalAccount->id, $showFolders)) { + $personalAccount->email = $email; + if ($personalAccount->isPop3Protocol()) { + $personalAccount->deletePop3Cache(); + continue; + } + $personalAccount->cleanOutCache(); + $personalAccount->connectMailserver(); + $mailboxes = $personalAccount->getMailboxes(true); + $mailboxes[] = 'INBOX'; + sort($mailboxes); + + $GLOBALS['log']->info("[EMAIL] Start checking account [{$personalAccount->name}] for user [{$current_user->user_name}]"); + + foreach($mailboxes as $mailbox) { + $GLOBALS['log']->info("[EMAIL] Start checking mailbox [{$mailbox}] of account [{$personalAccount->name}] for user [{$current_user->user_name}]"); + $personalAccount->checkEmailOneMailbox($mailbox, false, true); + $GLOBALS['log']->info("[EMAIL] Done checking mailbox [{$mailbox}] of account [{$personalAccount->name}] for user [{$current_user->user_name}]"); + } + $GLOBALS['log']->info("[EMAIL] Done checking account [{$personalAccount->name}] for user [{$current_user->user_name}]"); + } + } + } + + // group accounts + $beans = $this->retrieveAllByGroupId($current_user->id, false); + foreach($beans as $k => $groupAccount) { + if(in_array($groupAccount->id, $showFolders)) { + $groupAccount->email = $email; + $groupAccount->cleanOutCache(); + $groupAccount->connectMailserver(); + $mailboxes = $groupAccount->getMailboxes(true); + $mailboxes[] = 'INBOX'; + sort($mailboxes); + + $GLOBALS['log']->info("INBOUNDEMAIL: checking account [ {$groupAccount->name} ]"); + + foreach($mailboxes as $mailbox) { + $groupAccount->checkEmailOneMailbox($mailbox, false, true); + } + } + } + } + + + /** + * Deletes cached messages when moving from folder to folder + * @param string $uids + * @param string $fromFolder + * @param string $toFolder + */ + function deleteCachedMessages($uids, $fromFolder) { + global $sugar_config; + + if(!isset($this->email) && !isset($this->email->et)) { + if(!class_exists('Email')) { + + } + $this->email = new Email(); + $this->email->email2init(); + } + + $uids = $this->email->et->_cleanUIDList($uids); + + foreach($uids as $uid) { + $file = "{$sugar_config['cache_dir']}modules/Emails/{$this->id}/messages/{$fromFolder}{$uid}.php"; + + if(file_exists($file)) { + if(!unlink($file)) { + $GLOBALS['log']->debug("INBOUNDEMAIL: Could not delete [ {$file} ]"); + } + } + } + } + + /** + * similar to imap_fetch_overview, but it gets overviews from a local cache + * file. + * @param string $uids UIDs in comma-delimited format + * @param string $mailbox The mailbox in focus, will default to $this->mailbox + * @param bool $remove Default false + * @return array + */ + function getOverviewsFromCacheFile($uids, $mailbox='', $remove=false) { + global $app_strings; + if(!isset($this->email) && !isset($this->email->et)) { + if(!class_exists('Email')) { + + } + $this->email = new Email(); + $this->email->email2init(); + } + + $uids = $this->email->et->_cleanUIDList($uids, true); + + // load current cache file + $mailbox = empty($mailbox) ? $this->mailbox : $mailbox; + $cacheValue = $this->getCacheValue($mailbox); + $ret = array(); + + // prep UID array + $exUids = explode($app_strings['LBL_EMAIL_DELIMITER'], $uids); + foreach($exUids as $k => $uid) { + $exUids[$k] = trim($uid); + } + + // fill $ret will requested $uids + foreach($cacheValue['retArr'] as $k => $overview) { + if(in_array($overview->imap_uid, $exUids)) { + $ret[] = $overview; + } + } + + // remove requested $uids from current cache file (move_mail() type action) + if($remove) { + $this->setCacheValue($mailbox, array(), array(), $ret); + } + return $ret; + } + + /** + * merges new info with the saved cached file + * @param array $array Array of email Overviews + * @param string $type 'append' or 'remove' + * @param string $mailbox Target mailbox if not current assigned + */ + function updateOverviewCacheFile($array, $type='append', $mailbox='') { + $mailbox = empty($mailbox) ? $this->mailbox : $mailbox; + + $cacheValue = $this->getCacheValue($mailbox); + $uids = $cacheValue['uids']; + + $updateRows = array(); + $insertRows = array(); + $removeRows = array(); + + // update values + if($type == 'append') { // append + /* we are adding overviews to the cache file */ + foreach($array as $overview) { + if(isset($overview->uid)) { + $overview->imap_uid = $overview->uid; // coming from imap_fetch_overview() call + } + + if(!in_array($overview->imap_uid, $uids)) { + $insertRows[] = $overview; + } + } + } else { + $updatedCacheOverviews = array(); + // compare against generated list + /* we are removing overviews from the cache file */ + foreach($cacheValue['retArr'] as $cacheOverview) { + if(!in_array($cacheOverview->imap_uid, $uids)) { + $insertRows[] = $cacheOverview; + } else { + $removeRows[] = $cacheOverview; + } + } + + $cacheValue['retArr'] = $updatedCacheOverviews; + } + + $this->setCacheValue($mailbox, $insertRows, $updateRows, $removeRows); + } + + /** + * Check email prefetches email bodies for quicker display + * @param array array of fetched overviews + */ + function fetchCheckedEmails($fetchedOverviews) { + global $sugar_config; + + if(is_array($fetchedOverviews) && !empty($fetchedOverviews)) { + foreach($fetchedOverviews as $overview) { + if($overview->size < 10000) { + + $uid = $overview->imap_uid; + + if(!empty($uid)) { + $file = "{$this->mailbox}{$uid}.php"; + $cacheFile = clean_path("{$sugar_config['cache_dir']}/modules/Emails/{$this->id}/messages/{$file}"); + + if(!file_exists($cacheFile)) { + $GLOBALS['log']->info("INBOUNDEMAIL: Prefetching email [ {$file} ]"); + $this->setEmailForDisplay($uid); + $out = $this->displayOneEmail($uid, $this->mailbox); + $this->email->et->writeCacheFile('out', $out, $this->id, 'messages', "{$this->mailbox}{$uid}.php"); + } else { + $GLOBALS['log']->debug("INBOUNDEMAIL: Trying to prefetch an email we already fetched! [ {$cacheFile} ]"); + } + } else { + $GLOBALS['log']->debug("*** INBOUNDEMAIL: prefetch has a message with no UID"); + } + } else { + $GLOBALS['log']->debug("INBOUNDEMAIL: skipping email prefetch - size too large [ {$overview->size} ]"); + } + } + } + } + + /** + * Sets flags on emails. Assumes that connection is live, correct folder is + * set. + * @param string $uids Sequence of UIDs, comma separated + * @param string $type Flag to mark + */ + function markEmails($uids, $type) { + switch($type) { + case 'unread': + $result = imap_clearflag_full($this->conn, $uids, '\\SEEN', ST_UID); + break; + case 'read': + $result = imap_setflag_full($this->conn, $uids, '\\SEEN', ST_UID); + break; + case 'flagged': + $result = imap_setflag_full($this->conn, $uids, '\\FLAGGED', ST_UID); + break; + case 'unflagged': + $result = imap_clearflag_full($this->conn, $uids, '\\FLAGGED', ST_UID); + break; + case 'answered': + $result = imap_setflag_full($this->conn, $uids, '\\Answered', ST_UID); + break; + } + } + //// END EMAIL 2.0 SPECIFIC + /////////////////////////////////////////////////////////////////////////// + + + + /////////////////////////////////////////////////////////////////////////// + //// SERVER MANIPULATION METHODS + /** + * Deletes the specified folder + * @param string $mbox "::" delimited IMAP mailbox path, ie, INBOX.saved.stuff + * @return bool + */ + function deleteFolder($mbox) { + $returnArray = array(); + if ($this->getCacheCount($mbox) > 0) { + $returnArray['status'] = false; + $returnArray['errorMessage'] = "Can not delete {$mbox} as it has emails."; + return $returnArray; + } + $connectString = $this->getConnectString('', $mbox); + //Remove Folder cache + global $sugar_config; + unlink("{$sugar_config['cache_dir']}modules/Emails/{$this->id}/folders/folders.php"); + + if(imap_unsubscribe($this->conn, imap_utf7_encode($connectString))) { + if(imap_deletemailbox($this->conn, $connectString)) { + $this->mailbox = str_replace(("," . $mbox), "", $this->mailbox); + $this->save(); + $sessionFoldersString = $this->getSessionInboundFoldersString($this->server_url, $this->email_user, $this->port, $this->protocol); + $sessionFoldersString = str_replace(("," . $mbox), "", $sessionFoldersString); + $this->setSessionInboundFoldersString($this->server_url, $this->email_user, $this->port, $this->protocol, $sessionFoldersString); + $returnArray['status'] = true; + return $returnArray; + } else { + $GLOBALS['log']->error("*** ERROR: EMAIL2.0 - could not delete IMAP mailbox with path: [ {$connectString} ]"); + $returnArray['status'] = false; + $returnArray['errorMessage'] = "NOOP: could not delete folder: {$connectString}"; + return $returnArray; + return false; + } + } else { + $GLOBALS['log']->error("*** ERROR: EMAIL2.0 - could not unsubscribe from folder, {$connectString} before deletion."); + $returnArray['status'] = false; + $returnArray['errorMessage'] = "NOOP: could not unsubscribe from folder, {$connectString} before deletion."; + return $returnArray; + } + } + + /** + * Saves new folders + * @param string $name Name of new IMAP mailbox + * @param string $mbox "::" delimited IMAP mailbox path, ie, INBOX.saved.stuff + * @return bool True on success + */ + function saveNewFolder($name, $mbox) { + global $sugar_config; + //Remove Folder cache + global $sugar_config; + //unlink("{$sugar_config['cache_dir']}modules/Emails/{$this->id}/folders/folders.php"); + + //$mboxImap = $this->getImapMboxFromSugarProprietary($mbox); + $delimiter = $this->get_stored_options('folderDelimiter'); + if (!$delimiter) { + $delimiter = '.'; + } + + $newFolder = $mbox . $delimiter . $name; + $mbox .= $delimiter.str_replace($delimiter, "_", $name); + $connectString = $this->getConnectString('', $mbox); + + if(imap_createmailbox($this->conn, imap_utf7_encode($connectString))) { + imap_subscribe($this->conn, imap_utf7_encode($connectString)); + $status = imap_status($this->conn, str_replace("{$delimiter}{$name}","",$connectString), SA_ALL); + $this->mailbox = $this->mailbox . "," . $newFolder; + $this->save(); + $sessionFoldersString = $this->getSessionInboundFoldersString($this->server_url, $this->email_user, $this->port, $this->protocol); + $sessionFoldersString = $sessionFoldersString . "," . $newFolder; + $this->setSessionInboundFoldersString($this->server_url, $this->email_user, $this->port, $this->protocol, $sessionFoldersString); + + echo json_encode($status); + return true; + } else { + echo "NOOP: could not create folder"; + $GLOBALS['log']->error("*** ERROR: EMAIL2.0 - could not create IMAP mailbox with path: [ {$connectString} ]"); + return false; + } + + } + + /** + * Constructs an IMAP c-client compatible folder path from Sugar proprietary + * @param string $mbox "::" delimited IMAP mailbox path, ie, INBOX.saved.stuff + * @return string + */ + function getImapMboxFromSugarProprietary($mbox) { + $exMbox = explode("::", $mbox); + + $mboxImap = ''; + + for($i=2; $iretrieve($ieId); + $beans[] = $bean; + //$beans = $this->retrieveAllByGroupId($current_user->id, true); + + $subject = urldecode($subject); + + $criteria = ""; + $criteria .= (!empty($subject)) ? 'SUBJECT '.from_html($subject).'' : ""; + //$criteria .= (!empty($subject)) ? 'SUBJECT "'.$GLOBALS['db']->helper->escape_quote($subject).'"' : ""; + $criteria .= (!empty($from)) ? ' FROM "'.$from.'"' : ""; + $criteria .= (!empty($to)) ? ' FROM "'.$to.'"' : ""; + $criteria .= (!empty($body)) ? ' TEXT "'.$body.'"' : ""; + $criteria .= (!empty($dateFrom)) ? ' SINCE "'.$timedate->fromString($dateFrom)->format('d-M-Y').'"' : ""; + $criteria .= (!empty($dateTo)) ? ' BEFORE "'.$timedate->fromString($dateTo)->format('d-M-Y').'"' : ""; + //$criteria .= (!empty($from)) ? ' FROM "'.$from.'"' : ""; + + $showFolders = unserialize(base64_decode($current_user->getPreference('showFolders', 'Emails'))); + + $out = array(); + + foreach($beans as $bean) { + if(!in_array($bean->id, $showFolders)) { + continue; + } + + $GLOBALS['log']->info("*** INBOUNDEMAIL: searching [ {$bean->name} ] for [ {$subject}{$from}{$to}{$body}{$dateFrom}{$dateTo} ]"); + $group = (!$bean->is_personal) ? 'group.' : ''; + $bean->connectMailServer(); + $mailboxes = $bean->getMailboxes(true); + if (!in_array('INBOX', $mailboxes)) { + $mailboxes[] = 'INBOX'; + } + $totalHits = 0; + + foreach($mailboxes as $mbox) { + $bean->mailbox = $mbox; + $searchOverviews = array(); + if ($bean->protocol == 'pop3') { + $pop3Criteria = "SELECT * FROM email_cache WHERE ie_id = '{$bean->id}' AND mbox = '{$mbox}'"; + $pop3Criteria .= (!empty($subject)) ? ' AND subject like "%'.$bean->db->helper->escape_quote($subject).'%"' : ""; + $pop3Criteria .= (!empty($from)) ? ' AND fromaddr like "%'.$from.'%"' : ""; + $pop3Criteria .= (!empty($to)) ? ' AND toaddr like "%'.$to.'%"' : ""; + $pop3Criteria .= (!empty($dateFrom)) ? ' AND senddate > "'.$dateFrom.'"' : ""; + $pop3Criteria .= (!empty($dateTo)) ? ' AND senddate < "'.$dateTo.'"' : ""; + $GLOBALS['log']->info("*** INBOUNDEMAIL: searching [ {$mbox} ] using criteria [ {$pop3Criteria} ]"); + + $r = $bean->db->query($pop3Criteria); + while($a = $bean->db->fetchByAssoc($r)) { + $overview = new Overview(); + + foreach($a as $k => $v) { + $k=strtolower($k); + switch($k) { + case "imap_uid": + $overview->imap_uid = $v; + $overview->uid = $a['message_id']; + break; + case "toaddr": + $overview->to = from_html($v); + break; + + case "fromaddr": + $overview->from = from_html($v); + break; + + case "mailsize": + $overview->size = $v; + break; + + case "senddate": + $overview->date = $timedate->fromString($v)->format('r'); + break; + + default: + $overview->$k = from_html($v); + break; + } // sqitch + } // foreach + $searchOverviews[] = $overview; + } // while + } else { + $bean->connectMailServer(); + $searchResult = imap_search($bean->conn, $criteria, SE_UID); + if (!empty($searchResult)) { + $searchOverviews = imap_fetch_overview($bean->conn, implode(',', $searchResult), FT_UID); + } // if + } // else + $numHits = count($searchOverviews); + + if($numHits > 0) { + $totalHits = $totalHits + $numHits; + $ret = $bean->sortFetchedOverview($searchOverviews, 'date', 'desc', true); + $mbox = "{$bean->id}.SEARCH"; + $out = array_merge($out, $bean->displayFetchedSortedListXML($ret, $mbox, false)); + } + } + } + + $metadata = array(); + $metadata['mbox'] = $app_strings['LBL_EMAIL_SEARCH_RESULTS_TITLE']; + $metadata['ieId'] = $this->id; + $metadata['name'] = $this->name; + $metadata['unreadChecked'] = ($current_user->getPreference('showUnreadOnly', 'Emails') == 1) ? 'CHECKED' : ''; + $metadata['out'] = $out; + + return $metadata; + } + + /** + * repairs the encrypted password for a given I-E account + * @return bool True on success + */ + function repairAccount() { + + for($i=0; $i<3; $i++) { + if($i != 0) { // decode is performed on retrieve already + $this->email_password = blowfishDecode(blowfishGetKey('InboundEmail'), $this->email_password); + } + + if($this->connectMailserver() == 'true') { + $this->save(); // save decoded password (is encoded on save()) + return true; + } + } + + return false; + } + + /** + * soft deletes a User's personal inbox + * @param string id I-E id + * @param string user_name User name of User in focus, NOT current_user + * @return bool True on success + */ + function deletePersonalEmailAccount($id, $user_name) { + $q = "SELECT ie.id FROM inbound_email ie LEFT JOIN users u ON ie.group_id = u.id WHERE u.user_name = '{$user_name}'"; + $r = $this->db->query($q, true); + + while($a = $this->db->fetchByAssoc($r)) { + if(!empty($a) && $a['id'] == $id) { + $this->retrieve($id); + $this->deleted = 1; + $this->save(); + return true; + } + } + return false; + } + + function getTeamSetIdForTeams($teamIds) { + if(!is_array($teamIds)){ + $teamIds = array($teamIds); + } // if + $teamSet = new TeamSet(); + $team_set_id = $teamSet->addTeams($teamIds); + return $team_set_id; + } // fn + + /** + * Saves Personal Inbox settings for Users + * @param string userId ID of user to assign all emails for this account + * @param strings userName Name of account, for Sugar purposes + * @param bool forceSave Default true. Flag to save errored settings. + * @return boolean true on success, false on fail + */ + function savePersonalEmailAccount($userId = '', $userName = '', $forceSave=true) { + $groupId = $userId; + $accountExists = false; + if(isset($_REQUEST['ie_id']) && !empty($_REQUEST['ie_id'])) { + $this->retrieve($_REQUEST['ie_id']); + $accountExists = true; + } + $ie_name = $_REQUEST['ie_name']; + + $this->is_personal = 1; + $this->name = $ie_name; + $this->group_id = $groupId; + $this->status = $_REQUEST['ie_status']; + $this->server_url = trim($_REQUEST['server_url']); + $this->email_user = trim($_REQUEST['email_user']); + if(!empty($_REQUEST['email_password'])) { + $this->email_password = html_entity_decode($_REQUEST['email_password'], ENT_QUOTES); + } + $this->port = trim($_REQUEST['port']); + $this->protocol = $_REQUEST['protocol']; + if ($this->protocol == "pop3") { + $_REQUEST['mailbox'] = "INBOX"; + } + $this->mailbox = $_REQUEST['mailbox']; + $this->mailbox_type = 'pick'; // forcing this + + + if(isset($_REQUEST['ssl']) && $_REQUEST['ssl'] == 1) { $useSsl = true; } + else $useSsl = false; + $this->service = '::::::::::'; + + if($forceSave) { + $id = $this->save(); // saving here to prevent user from having to re-enter all the info in case of error + $this->retrieve($id); + } + + $this->protocol = $_REQUEST['protocol']; // need to set this again since we safe the "service" string to empty explode values + $opts = $this->getSessionConnectionString($this->server_url, $this->email_user, $this->port, $this->protocol); + $detectedOpts = $this->findOptimumSettings($useSsl); + + //If $detectedOpts is empty, there was an error connecting, so clear $opts. If $opts was empty, use $detectedOpts + if (empty($opts) || empty($detectedOpts) || (empty($detectedOpts['good']) && empty($detectedOpts['serial']))) + { + $opts = $detectedOpts; + } + $delimiter = $this->getSessionInboundDelimiterString($this->server_url, $this->email_user, $this->port, $this->protocol); + + if(isset($opts['serial']) && !empty($opts['serial'])) { + $this->service = $opts['serial']; + if(isset($_REQUEST['mark_read']) && $_REQUEST['mark_read'] == 1) { + $this->delete_seen = 0; + } else { + $this->delete_seen = 1; + } + + // handle stored_options serialization + if(isset($_REQUEST['only_since']) && $_REQUEST['only_since'] == 1) { + $onlySince = true; + } else { + $onlySince = false; + } + + $focusUser = new User(); + $focusUser->retrieve($groupId); + $mailerId = (isset($_REQUEST['outbound_email'])) ? $_REQUEST['outbound_email'] : ""; + + $oe = new OutboundEmail(); + $oe->getSystemMailerSettings($focusUser, $mailerId); + + $stored_options = array(); + $stored_options['from_name'] = trim($_REQUEST['from_name']); + $stored_options['from_addr'] = trim($_REQUEST['from_addr']); + $stored_options['reply_to_addr'] = trim($_REQUEST['reply_to_addr']); + + if (!$this->isPop3Protocol()) { + $stored_options['trashFolder'] = (isset($_REQUEST['trashFolder']) ? trim($_REQUEST['trashFolder']) : ""); + $stored_options['sentFolder'] = (isset($_REQUEST['sentFolder']) ? trim($_REQUEST['sentFolder']) : ""); + } // if + $stored_options['only_since'] = $onlySince; + $stored_options['filter_domain'] = ''; + $storedOptions['folderDelimiter'] = $delimiter; + $stored_options['outbound_email'] = (isset($_REQUEST['outbound_email'])) ? $_REQUEST['outbound_email'] : $oe->id; + $this->stored_options = base64_encode(serialize($stored_options)); + + $ieId = $this->save(); + + //If this is the first personal account the user has setup mark it as default for them. + $currentIECount = $this->getUserPersonalAccountCount($focusUser); + if($currentIECount == 1) + $this->setUsersDefaultOutboundServerId($focusUser, $ieId); + + return true; + } else { + // could not find opts, no save + $GLOBALS['log']->debug('-----> InboundEmail could not find optimums for User: '.$ie_name); + return false; + } + } + /** + * Determines if this instance of I-E is for a Group Inbox or Personal Inbox + */ + function handleIsPersonal() { + $qp = 'SELECT users.id, users.user_name FROM users WHERE users.is_group = 0 AND users.deleted = 0 AND users.status = \'active\' AND users.id = \''.$this->group_id.'\''; + $rp = $this->db->query($qp, true); + $personalBox = array(); + while($ap = $this->db->fetchByAssoc($rp)) { + $personalBox[] = array($ap['id'], $ap['user_name']); + } + if(count($personalBox) > 0) { + return true; + } else { + return false; + } + } + + function getUserNameFromGroupId() { + $r = $this->db->query('SELECT users.user_name FROM users WHERE deleted=0 AND id=\''.$this->group_id.'\'', true); + while($a = $this->db->fetchByAssoc($r)) { + return $a['user_name']; + } + return ''; + } + + function getFoldersListForMailBox() { + $return = array(); + $foldersList = $this->getSessionInboundFoldersString($this->server_url, $this->email_user, $this->port, $this->protocol); + if (empty($foldersList)) { + global $mod_strings; + $msg = $this->connectMailserver(true); + if (strpos($msg, "successfully")) { + $foldersList = $this->getSessionInboundFoldersString($this->server_url, $this->email_user, $this->port, $this->protocol); + $return['status'] = true; + $return['foldersList'] = $foldersList; + $return['statusMessage'] = ""; + } else { + $return['status'] = false; + $return['statusMessage'] = $msg; + } // else + } else { + $return['status'] = true; + $return['foldersList'] = $foldersList; + $return['statusMessage'] = ""; + } + return $return; + } // fn + /** + * Programatically determines best-case settings for imap_open() + */ + function findOptimumSettings($useSsl=false, $user='', $pass='', $server='', $port='', $prot='', $mailbox='') { + global $mod_strings; + $serviceArr = array(); + $returnService = array(); + $badService = array(); + $goodService = array(); + $errorArr = array(); + $raw = array(); + $retArray = array( 'good' => $goodService, + 'bad' => $badService, + 'err' => $errorArr); + + if(!function_exists('imap_open')) { + $retArray['err'][0] = $mod_strings['ERR_NO_IMAP']; + return $retArray; + } + + imap_errors(); // clearing error stack + error_reporting(0); // turn off notices from IMAP + + if(isset($_REQUEST['ssl']) && $_REQUEST['ssl'] == 1) { + $useSsl = true; + } + + $exServ = explode('::', $this->service); + $service = '/'.$exServ[1]; + + $nonSsl = array('both-secure' => '/notls/novalidate-cert/secure', + 'both' => '/notls/novalidate-cert', + 'nocert-secure' => '/novalidate-cert/secure', + 'nocert' => '/novalidate-cert', + 'notls-secure' => '/notls/secure', + 'secure' => '/secure', // for POP3 servers that force CRAM-MD5 + 'notls' => '/notls', + 'none' => '', // try default nothing + ); + $ssl = array( + 'ssl-both-on-secure' => '/ssl/tls/validate-cert/secure', + 'ssl-both-on' => '/ssl/tls/validate-cert', + 'ssl-cert-secure' => '/ssl/validate-cert/secure', + 'ssl-cert' => '/ssl/validate-cert', + 'ssl-tls-secure' => '/ssl/tls/secure', + 'ssl-tls' => '/ssl/tls', + 'ssl-both-off-secure' => '/ssl/notls/novalidate-cert/secure', + 'ssl-both-off' => '/ssl/notls/novalidate-cert', + 'ssl-nocert-secure' => '/ssl/novalidate-cert/secure', + 'ssl-nocert' => '/ssl/novalidate-cert', + 'ssl-notls-secure' => '/ssl/notls/secure', + 'ssl-notls' => '/ssl/notls', + 'ssl-secure' => '/ssl/secure', + 'ssl-none' => '/ssl', + ); + + if(isset($user) && !empty($user) && isset($pass) && !empty($pass)) { + $this->email_password = $pass; + $this->email_user = $user; + $this->server_url = $server; + $this->port = $port; + $this->protocol = $prot; + $this->mailbox = $mailbox; + } + + // in case we flip from IMAP to POP3 + if($this->protocol == 'pop3') + $this->mailbox = 'INBOX'; + + //If user has selected multiple mailboxes, we only need to test the first mailbox for the connection string. + $a_mailbox = explode(",", $this->mailbox); + $tmpMailbox = isset($a_mailbox[0]) ? $a_mailbox[0] : ""; + + if($useSsl == true) + { + foreach($ssl as $k => $service) + { + $returnService[$k] = 'foo'.$service; + $serviceArr[$k] = '{'.$this->server_url.':'.$this->port.'/service='.$this->protocol.$service.'}'.$tmpMailbox; + } + } + else + { + foreach($nonSsl as $k => $service) + { + $returnService[$k] = 'foo'.$service; + $serviceArr[$k] = '{'.$this->server_url.':'.$this->port.'/service='.$this->protocol.$service.'}'.$tmpMailbox; + } + } + + $GLOBALS['log']->debug('---------------STARTING FINDOPTIMUMS LOOP----------------'); + $l = 1; + + //php imap library will capture c-client library warnings as errors causing good connections to be ignored. + //Check against known warnings to ensure good connections are used. + $acceptableWarnings = array("SECURITY PROBLEM: insecure server advertised AUTH=PLAIN", //c-client auth_pla.c + "Mailbox is empty"); + $login = $this->email_user; + $passw = $this->email_password; + $foundGoodConnection = false; + foreach($serviceArr as $k => $serviceTest) { + $errors = ''; + $alerts = ''; + $GLOBALS['log']->debug($l.': I-E testing string: '.$serviceTest); + + // open the connection and try the test string + $this->conn = imap_open($serviceTest, $login, $passw); + + if(($errors = imap_last_error()) || ($alerts = imap_alerts())) { + if($errors == 'Too many login failures' || $errors == '[CLOSED] IMAP connection broken (server response)') { // login failure means don't bother trying the rest + $GLOBALS['log']->debug($l.': I-E failed using ['.$serviceTest.']'); + $retArray['err'][$k] = $mod_strings['ERR_BAD_LOGIN_PASSWORD']; + $retArray['bad'][$k] = $serviceTest; + $GLOBALS['log']->debug($l.': I-E ERROR: $ie->findOptimums() failed due to bad user credentials for user login: '.$this->email_user); + return $retArray; + } elseif( in_array($errors, $acceptableWarnings, TRUE)) { // false positive + $GLOBALS['log']->debug($l.': I-E found good connection but with warnings ['.$serviceTest.'] Errors:' . $errors); + $retArray['good'][$k] = $returnService[$k]; + $foundGoodConnection = true; + } + else { + $GLOBALS['log']->debug($l.': I-E failed using ['.$serviceTest.'] - error: '.$errors); + $retArray['err'][$k] = $errors; + $retArray['bad'][$k] = $serviceTest; + } + } else { + $GLOBALS['log']->debug($l.': I-E found good connect using ['.$serviceTest.']'); + $retArray['good'][$k] = $returnService[$k]; + $foundGoodConnection = true; + } + + if(is_resource($this->conn)) { + if (!$this->isPop3Protocol()) { + $serviceTest = str_replace("INBOX", "", $serviceTest); + $boxes = imap_getmailboxes($this->conn, $serviceTest, "*"); + $delimiter = '.'; + // clean MBOX path names + foreach($boxes as $k => $mbox) { + $raw[] = $mbox->name; + if ($mbox->delimiter) { + $delimiter = $mbox->delimiter; + } // if + } // foreach + $this->setSessionInboundDelimiterString($this->server_url, $this->email_user, $this->port, $this->protocol, $delimiter); + } // if + + if(!imap_close($this->conn)) $GLOBALS['log']->debug('imap_close() failed!'); + } + + $GLOBALS['log']->debug($l.': I-E clearing error and alert stacks.'); + imap_errors(); // clear stacks + imap_alerts(); + // If you find a good connection, then don't do any further testing to find URL + if ($foundGoodConnection) { + break; + } // if + $l++; + } + $GLOBALS['log']->debug('---------------end FINDOPTIMUMS LOOP----------------'); + + if(!empty($retArray['good'])) { + $newTls = ''; + $newCert = ''; + $newSsl = ''; + $newNotls = ''; + $newNovalidate_cert = ''; + $good = array_pop($retArray['good']); // get most complete string + $exGood = explode('/', $good); + foreach($exGood as $v) { + switch($v) { + case 'ssl': + $newSsl = 'ssl'; + break; + case 'tls': + $newTls = 'tls'; + break; + case 'notls': + $newNotls = 'notls'; + break; + case 'cert': + $newCert = 'validate-cert'; + break; + case 'novalidate-cert': + $newNovalidate_cert = 'novalidate-cert'; + break; + case 'secure': + $secure = 'secure'; + break; + } + } + + $goodStr['serial'] = $newTls.'::'.$newCert.'::'.$newSsl.'::'.$this->protocol.'::'.$newNovalidate_cert.'::'.$newNotls.'::'.$secure; + $goodStr['service'] = $good; + $testConnectString = str_replace('foo','', $good); + $testConnectString = '{'.$this->server_url.':'.$this->port.'/service='.$this->protocol.$testConnectString.'}'; + $this->setSessionConnectionString($this->server_url, $this->email_user, $this->port, $this->protocol, $goodStr); + $i = 0; + foreach($raw as $mbox) + { + $raw[$i] = str_replace($testConnectString, "", mb_convert_encoding($mbox, "UTF8", "UTF7-IMAP" )); + $i++; + } // foreach + sort($raw); + $this->setSessionInboundFoldersString($this->server_url, $this->email_user, $this->port, $this->protocol, implode(",", $raw)); + return $goodStr; + } else { + return false; + } + } + + function getSessionConnectionString($server_url, $email_user, $port, $protocol) { + $sessionConnectionString = $server_url . $email_user . $port . $protocol; + return (isset($_SESSION[$sessionConnectionString]) ? $_SESSION[$sessionConnectionString] : ""); + } + + function setSessionConnectionString($server_url, $email_user, $port, $protocol, $goodStr) { + $sessionConnectionString = $server_url . $email_user . $port . $protocol; + $_SESSION[$sessionConnectionString] = $goodStr; + } + + function getSessionInboundDelimiterString($server_url, $email_user, $port, $protocol) { + $sessionInboundDelimiterString = $server_url . $email_user . $port . $protocol . "delimiter"; + return (isset($_SESSION[$sessionInboundDelimiterString]) ? $_SESSION[$sessionInboundDelimiterString] : ""); + } + + function setSessionInboundDelimiterString($server_url, $email_user, $port, $protocol, $delimiter) { + $sessionInboundDelimiterString = $server_url . $email_user . $port . $protocol . "delimiter"; + $_SESSION[$sessionInboundDelimiterString] = $delimiter; + } + + function getSessionInboundFoldersString($server_url, $email_user, $port, $protocol) { + $sessionInboundFoldersListString = $server_url . $email_user . $port . $protocol . "foldersList"; + return (isset($_SESSION[$sessionInboundFoldersListString]) ? $_SESSION[$sessionInboundFoldersListString] : ""); + } + + function setSessionInboundFoldersString($server_url, $email_user, $port, $protocol, $foldersList) { + $sessionInboundFoldersListString = $server_url . $email_user . $port . $protocol . "foldersList"; + $_SESSION[$sessionInboundFoldersListString] = $foldersList; + } + + /** + * Checks for duplicate Group User names when creating a new one at save() + * @return GUID returns GUID of Group User if user_name match is + * found + * @return boolean false if NO DUPE IS FOUND + */ + function groupUserDupeCheck() { + $q = "SELECT u.id FROM users u WHERE u.deleted=0 AND u.is_group=1 AND u.user_name = '".$this->name."'"; + $r = $this->db->query($q, true); + $uid = ''; + while($a = $this->db->fetchByAssoc($r)) { + $uid = $a['id']; + } + + if(strlen($uid) > 0) { + return $uid; + } else { + return false; + } + } + + /** + * Returns
    + + + + +
    + + + + + + + + + + +{if !empty($smarty.request.return_module)} + + +{/if} + +{if $bean->aclAccess("save")} + +{/if} + +{if !empty($smarty.request.return_action) && ($smarty.request.return_action == "DetailView" && !empty($record_id))} + +{elseif !empty($smarty.request.return_action) && ($smarty.request.return_action == "DetailView" && !empty($smarty.request.return_id))}'; + +{else} + +{/if} +
    \ No newline at end of file diff --git a/modules/Leads/tpls/DetailViewHeader.tpl b/modules/Leads/tpls/DetailViewHeader.tpl new file mode 100644 index 00000000..d55952d4 --- /dev/null +++ b/modules/Leads/tpls/DetailViewHeader.tpl @@ -0,0 +1,81 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} + +{assign var=preForm value="
    "} +{assign var=displayPreform value=false} +{if isset($bean->contact_id) && !empty($bean->contact_id)} +{assign var=displayPreform value=true} +{assign var=preForm value=$preForm|cat:$MOD.LBL_CONVERTED_CONTACT} +{assign var=preForm value=$preForm|cat:" "} +{assign var=preForm value=$preForm|cat:$bean->contact_name} +{assign var=preForm value=$preForm|cat:""} +{/if} + +{assign var=preForm value=$preForm|cat:""} + +{if isset($bean->account_id) && !empty($bean->account_id)} +{assign var=displayPreform value=true} +{assign var=preForm value=$preForm|cat:$MOD.LBL_CONVERTED_ACCOUNT} +{assign var=preForm value=$preForm|cat:" "} +{assign var=preForm value=$preForm|cat:$bean->account_name} +{assign var=preForm value=$preForm|cat:""} +{/if} + +{assign var=preForm value=$preForm|cat:""} + +{if isset($bean->opportunity_id) && !empty($bean->opportunity_id)} +{assign var=displayPreform value=true} +{assign var=preForm value=$preForm|cat:$MOD.LBL_CONVERTED_OPP} +{assign var=preForm value=$preForm|cat:" "} +{assign var=preForm value=$preForm|cat:$bean->opportunity_name} +{assign var=preForm value=$preForm|cat:""} +{/if} + +{assign var=preForm value=$preForm|cat:"
    "} +{if $displayPreform} +{$preForm} +
    +{/if} + +{{include file='include/DetailView/header.tpl'}} \ No newline at end of file diff --git a/modules/Leads/tpls/QuickCreate.tpl b/modules/Leads/tpls/QuickCreate.tpl new file mode 100644 index 00000000..ae4166c4 --- /dev/null +++ b/modules/Leads/tpls/QuickCreate.tpl @@ -0,0 +1,96 @@ +{* + +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + + + +*} + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + {$APP.LBL_REQUIRED_SYMBOL} {$APP.NTC_REQUIRED}
    + + +"; + $header_cols[]=$td; +} + +if ($diff_field_count>0) { + $xtpl->assign("DIFF_HEADER","".implode(' ',$header_cols).""); + $xtpl->assign("SIMILAR_HEADER",""); + $xtpl->assign("GROUP_PARTITION",""); +} else { + $xtpl->assign("SIMILAR_HEADER","".implode(' ',$header_cols).""); +} +$merge_verify=$mod_strings['LBL_DELETE_MESSAGE'].'\\n'; +foreach ($merge_records_names as $name) { + $merge_verify.= $name."\\n"; +} +$merge_verify.='\\n'.$mod_strings['LBL_PROCEED']; +$xtpl->assign("MERGE_VERIFY",$merge_verify); + +global $beanList; + +//Jenny - Bug 8386 - The object_name couldn't be found because it was searching for +// 'Case' instead of 'aCase'. +if ($focus->merge_bean->object_name == 'Case') { + $focus->merge_bean->object_name = 'aCase'; +} + +$mod=array_search($focus->merge_bean->object_name,$beanList); +$mod_strings = return_module_language($current_language, $mod); + +//add javascript for required fields enforcement. + +$javascript = new javascript(); +$javascript->setFormName('EditView'); +$javascript->setSugarBean($focus->merge_bean); +$javascript->addAllFields(''); +if (isset($focus->merge_bean->field_defs['team_name'])) { + $javascript->addFieldGeneric('team_name', 'varchar', $app_strings['LBL_TEAM'] ,'true'); +} +$xtpl->assign("VALIDATION_JS", $javascript->getScript()); + +$xtpl->parse("main"); +$xtpl->out("main"); + +/* + * function truncates values to max_data_legth and adds the complete value as hover text. + */ +function display_field_value($value) { + global $xtpl, $max_data_length, $mod_strings; + if (strlen($value)-$max_data_length > 3) { + $xtpl->assign("FIELD_VALUE", substr($value,0,$max_data_length).'...'); + } else { + $xtpl->assign("FIELD_VALUE", $value); + } + $xtpl->assign("HOVER_TEXT", $mod_strings['LBL_MERGE_VALUE_OVER'] .': ' . $value); +} +/* + * implements the rules that decide which fields will participate in a merge. + */ +function show_field($field_def) { + global $filter_for_valid_editable_attributes,$invalid_attribute_by_name; + //field in invalid attributes list? + if (isset($invalid_attribute_by_name[$field_def['name']])) { + return false; + } + //field has 'duplicate_merge property set to disabled?' + if (isset($field_def['duplicate_merge']) ) { + if ($field_def['duplicate_merge']=='disabled' or $field_def['duplicate_merge']==false) { + return false; + } + if ($field_def['duplicate_merge']=='enabled' or $field_def['duplicate_merge']==true) { + return true; + } + } + + //field has auto_increment set to true do not participate in merge. + //we have a unique index on that field. + if (isset($field_def['auto_increment']) and $field_def['auto_increment']==true) { + return false; + } + + //set required attribute values in $field_def + if (!isset($field_def['source']) or empty($field_def['source'])) { + $field_def['source']='db'; + } + + if (!isset($field_def['dbType']) or empty($field_def['dbType']) and isset($field_def['type'])) { + $field_def['dbType']=$field_def['type']; + } + + foreach ($filter_for_valid_editable_attributes as $attribute_set) { + $b_all=false; + foreach ($attribute_set as $attr=>$value) { + if (isset($field_def[$attr]) and $field_def[$attr]==$value) { + $b_all=true; + } else { + $b_all=false; + break; + } + } + if ($b_all) { + return true; + } + } + return false; +} +/* if the attribute of type relate and name is empty fetch using the vardef entries. + * + */ +function get_related_name($field_def,$id_value) { + if (!empty($field_def['rname']) && !empty($field_def['id_name']) && !empty($field_def['table'])) { + if (!empty($id_value)) { + + //default the column name to rname in vardefs + $col_name = $field_def['rname']; + //if this module is non db and has a module set, then check to see if this field should be concatenated + if (!empty($field_def['module']) && $field_def['source'] == 'non-db'){ + global $beanList, $beanFiles; + //get the bean field defs based on the module param + $bean = $beanList[$field_def['module']]; + require_once ($beanFiles[$bean]); + $focus = new $bean(); + if(!empty( $focus->field_defs[$field_def['rname']])){ + $related_def = $focus->field_defs[$field_def['rname']]; + //if field defs has concat field array set, then concatenate values + if(isset($related_def['db_concat_fields']) && !empty($related_def['db_concat_fields'])){ + $temp_str = ''; + + if ( ( $focus->db->dbType == 'mysql' ) || ( $focus->db->dbType == 'oci8' ) ){ + foreach($related_def['db_concat_fields'] as $vals){ + if(empty($temp_str)){ + $temp_str .= ' concat('. $vals; + }else{ + $temp_str .= ", ' ', " .$vals; + } + } + $temp_str .= ')'; + }else{ + foreach($related_def['db_concat_fields'] as $vals){ + if(empty($temp_str)){ + $temp_str .= $vals; + }else{ + $temp_str .= " + ' ' + " .$vals; + } + } + } + + $col_name = $temp_str; + } + } + } + + $query = "select ".$col_name." from " .$field_def['table'] ." where id='$id_value'"; + + $result=$GLOBALS['db']->query($query); + $row=$GLOBALS['db']->fetchByAssoc($result); + if (!empty($row[$field_def['rname']])) { + return $row[$field_def['rname']]; + } + } + } + return false; +} +?> diff --git a/modules/MergeRecords/controller.php b/modules/MergeRecords/controller.php new file mode 100644 index 00000000..c85e763c --- /dev/null +++ b/modules/MergeRecords/controller.php @@ -0,0 +1,50 @@ +loadBean()) !== false + && ($bean2 = SugarModule::get($_REQUEST['action_module'])->loadBean()) !== false ) { + $bean1->retrieve($merge_ids[0]); + $bean2->retrieve($merge_ids[1]); + if ( !$bean1->ACLAccess('edit') || !$bean2->ACLAccess('edit') ) { + ACLController::displayNoAccess(); + sugar_die(''); + } + } + + //redirect to step3. + $_REQUEST['record']=$merge_ids[0]; + $_REQUEST['merge_module']=$_REQUEST['action_module']; + unset($merge_ids[0]); + $_REQUEST['mass']=$merge_ids; +} +else { + global $beanList; + global $beanFiles; + $merge_ids = array(); + $bean = $beanList[$_REQUEST['return_module']]; + require_once($beanFiles[$bean]); + $focus = new $bean(); + + if(isset($_SESSION['export_where']) && !empty($_SESSION['export_where'])) { // bug 4679 + $where = $_SESSION['export_where']; + $whereArr = explode (" ", trim($where)); + if ($whereArr[0] == trim('where')) { + $whereClean = array_shift($whereArr); + } + $where = implode(" ", $whereArr); + } + else { + $where = ''; + } + if(empty($order_by))$order_by = ''; + $query = $focus->create_export_query($order_by,$where); + $result = $focus->db->query($query,true); + + /* + $query = 'select * from '.$focus->table_name.' where deleted=0'; + $result = $focus->db->query($query, true, ""); + */ + $row = $focus->db->fetchByAssoc($result); + + while ($row != null) { + //$beanObj = new $bean; + array_push($merge_ids, $row['id']); + $row = $focus->db->fetchByAssoc($result); + } + $_REQUEST['record']=$merge_ids[0]; + $_REQUEST['action']='index.php'; + $_REQUEST['merge_module']=$_REQUEST['return_module']; + unset($merge_ids[0]); + $_REQUEST['mass']=$merge_ids; +} +require('modules/MergeRecords/Step3.php'); + +?> diff --git a/modules/MergeRecords/language/en_us.lang.php b/modules/MergeRecords/language/en_us.lang.php new file mode 100644 index 00000000..d4a7f300 --- /dev/null +++ b/modules/MergeRecords/language/en_us.lang.php @@ -0,0 +1,84 @@ + 'Merge Records', + 'LBL_MODULE_TITLE' => 'Merge Records: Home', + 'LBL_SEARCH_FORM_TITLE' => 'Merge Search', + 'LBL_LIST_FORM_TITLE' => 'Merge List', + + 'LBL_LBL_MERGE_RECORDS_STEP_1' => 'Find Search Records to Merge With', + 'LBL_AVAIL_FIELDS' => 'Available Fields', + 'LBL_FILTER_COND' => 'Filter Condition', + 'LBL_SELECTED_FIELDS' => 'Selected Fields', + 'LBL_MERGE_RECORDS_WITH' => 'Merge Records With', + 'LBL_MERGE_VALUE_OVER' => 'Merge value over', + + 'LBL_NEXT_STEP_TITLE' => 'Move to Next Step[Ctrl+N]', + 'LBL_NEXT_STEP_BUTTON_KEY' => 'N', + 'LBL_NEXT_STEP_BUTTON_LABEL' => 'Next Step >', + + 'LBL_PERFORM_MERGE_BUTTON_TITLE' => 'Perform Merge[Ctrl+P]', + 'LBL_PERFORM_MERGE_BUTTON_KEY' => 'P', + 'LBL_PERFORM_MERGE_BUTTON_LABEL' => 'Perform Merge', + + 'LBL_SAVE_MERGED_RECORD_BUTTON_TITLE' => 'Save Merge[Ctrl+S]', + 'LBL_SAVE_MERGED_RECORD_BUTTON_KEY' => 'S', + 'LBL_SAVE_MERGED_RECORD_BUTTON_LABEL' => 'Save Merge', + + 'LBL_STEP2_FORM_TITLE' => 'Records Found To Merge With', + 'LBL_SELECT_ERROR'=>'You must make a selection before you can proceed.', + 'LBL_SELECT_PRIMARY'=>'Select primary record for the merge.', + 'LBL_CHANGE_PARENT'=>'Set as primary', + 'LBL_REMOVE_FROM_MERGE'=>'Remove', + 'LBL_DIFF_COL_VALUES'=>'Columns whose value in primary row differs from value in merging rows:', + 'LBL_SAME_COL_VALUES'=>'Columns whose value is similar across all rows:', + 'ERR_EXCEEDS_MAX'=>'You are only allowed to merge a maximum of 5 records. Records exceeding the limit were ignored.', + 'LBL_DELETE_MESSAGE'=>'This action will delete following record(s):', + 'LBL_PROCEED'=>'Proceed ?', + 'LBL_STEP1_DIRECTIONS' => 'Find possible duplicate records. If possible duplicates are found, you can select which records to merge with the current record.', +); + + +?> diff --git a/modules/MergeRecords/vardefs.php b/modules/MergeRecords/vardefs.php new file mode 100644 index 00000000..d64eeea6 --- /dev/null +++ b/modules/MergeRecords/vardefs.php @@ -0,0 +1,50 @@ +'does_not_exist', + 'fields' => array (), +); + +?> \ No newline at end of file diff --git a/modules/ModuleBuilder/Forms.php b/modules/ModuleBuilder/Forms.php new file mode 100644 index 00000000..2a9e4983 --- /dev/null +++ b/modules/ModuleBuilder/Forms.php @@ -0,0 +1,38 @@ + \ No newline at end of file diff --git a/modules/ModuleBuilder/MB/AjaxCompose.php b/modules/ModuleBuilder/MB/AjaxCompose.php new file mode 100644 index 00000000..c1141e0d --- /dev/null +++ b/modules/ModuleBuilder/MB/AjaxCompose.php @@ -0,0 +1,103 @@ +'ModuleBuilder.main("Home")',/* 'Assistant'=>'Assistant.mbAssistant.xy=Array("650, 40"); Assistant.mbAssistant.show();'*/); + function addSection($name, $title, $content, $action='activate'){ + $crumb = ''; + if($name == 'center'){ + $crumb = $this->getBreadCrumb(); + } + $this->sections[$name] = array('title'=>$title,'crumb'=>$crumb, 'content'=>$content, 'action'=>$action); + } + + function getJavascript(){ + if(!empty($this->sections['center'])){ + if(empty($this->sections['east']))$this->addSection('east', '', '', 'deactivate'); + if(empty($this->sections['east2']))$this->addSection('east2', '', '', 'deactivate'); + } + + $json = getJSONobj(); + return $json->encode($this->sections); + } + + function addCrumb($name, $action){ + $this->crumbs[$name] = $action; + } + + function getBreadCrumb(){ + $crumbs = ''; + $actions = array(); + $count = 0; + foreach($this->crumbs as $name=>$action){ + if($name == 'Home'){ + $crumbs .= "". getStudioIcon('home', 'home', 16, 16) . ''; + }else if($name=='Assistant'){ + $crumbs .= "". getStudioIcon('assistant', 'assistant', 16, 16) . ''; + }else{ + if($count > 0){ + $crumbs .= ' > '; + }else{ + $crumbs .= ' | '; + } + if(empty($action)){ + $crumbs .="$name"; + $actions[] = ""; + }else { + $crumbs .="$name"; + $actions[] = $action; + } + $count++; + } + + } + if($count > 1 && $actions[$count-2] != ""){ + $crumbs = "". getStudioIcon('back', 'back', 16, 16) . ' '. $crumbs; + } + return $crumbs . '

    '; + + + } + + function echoErrorStatus($labelName=''){ + $sections = array('failure'=>true,'failMsg'=>$labelName); + $json = getJSONobj(); + echo $json->encode($sections); + } + +} +?> \ No newline at end of file diff --git a/modules/ModuleBuilder/MB/MBField.php b/modules/ModuleBuilder/MB/MBField.php new file mode 100644 index 00000000..b70e0e53 --- /dev/null +++ b/modules/ModuleBuilder/MB/MBField.php @@ -0,0 +1,101 @@ +name)){ + $this->error = 'A name is required to create a field'; + return false; + } + if(empty($this->label))$this->label = $this->name; + $this->name = strtolower($this->getDBName($this->name)); + $vardef = array(); + $vardef['name']=$this->name; + if(empty($this->vname))$this->vname = 'LBL_' . strtoupper($this->name); + $vardef['vname'] = $this->addLabel(); + if(!empty($this->required))$vardef['required'] = $this->required; + if(empty($this->reportable))$vardef['reportable'] = false; + if(!empty($this->comment))$vardef['comment'] = $this->comment; + if($this->default !== 'MSI1')$vardef['default'] = $this->default; + switch($this->type){ + case 'date': + case 'datetime': + case 'float': + case 'int': + $vardef['type']=$this->type; + return $vardef; + case 'bool': + $vardef['type'] = 'bool'; + $vardef['default'] = (empty($vardef['default']))?0:1; + return $vardef; + case 'enum': + $vardef['type']='enum'; + if(empty($this->options)){ + $this->options = $this->name . '_list'; + } + $vardef['options'] = $this->addDropdown(); + return $vardef; + default: + $vardef['type']='varchar'; + return $vardef; + + } + } + + function addDropDown(){ + return $this->options; + } + + function addLabel(){ + return $this->vname; + } + +} +?> \ No newline at end of file diff --git a/modules/ModuleBuilder/MB/MBLanguage.php b/modules/ModuleBuilder/MB/MBLanguage.php new file mode 100644 index 00000000..3a6c9118 --- /dev/null +++ b/modules/ModuleBuilder/MB/MBLanguage.php @@ -0,0 +1,253 @@ +path = $path; + $this->name = $name; + $this->key_name = $key_name; + $this->label = $label; + } + + function load(){ + $this->generateModStrings(); + $this->generateAppStrings(); + } + + function loadStrings($file) + { + $module = strtoupper($this->name); + $object_name = strtoupper($this->key_name); + $_object_name = strtolower($this->name); + if(!file_exists($file))return; + + $d = dir($file); + while($e = $d->read()){ + if(substr($e, 0, 1) != '.' && is_file($file . '/' . $e)){ + include($file.'/'. $e); + if(empty($this->strings[$e])){ + + $this->strings[$e] = $mod_strings; + }else{ + $this->strings[$e] = array_merge($this->strings[$e], $mod_strings); + } + + + } + } + } + + function loadAppListStrings($file){ + if(!file_exists($file))return; + //we may not need this when loading in the app strings, but there is no harm + //in setting it. + $object_name = strtolower($this->key_name); + + $d = dir($file); + while($e = $d->read()){ + if(substr($e, 0, 1) != '.' && is_file($file . '/' . $e)){ + include($file.'/'. $e); + if(empty($this->appListStrings[$e])){ + + $this->appListStrings[$e] = $app_list_strings; + }else{ + $this->appListStrings[$e] = array_merge($this->appListStrings[$e], $app_list_strings); + } + + + } + } + } + + function generateModStrings(){ + $this->strings = array(); + $this->loadTemplates(); + + foreach($this->iTemplates as $template=>$val){ + $file = MB_IMPLEMENTS . '/' . $template . '/language'; + $this->loadStrings($file); + } + foreach($this->templates as $template=>$val){ + $file = MB_TEMPLATES . '/' . $template . '/language'; + $this->loadStrings($file); + } + $this->loadStrings($this->path . '/language'); + } + + function getModStrings($language='en_us'){ + $language .= '.lang.php'; + if(!empty($this->strings[$language]) && $language != 'en_us.lang.php'){ + return sugarArrayMerge($this->strings['en_us.lang.php'], $this->strings[$language]); + } + if(!empty($this->strings['en_us.lang.php']))return $this->strings['en_us.lang.php']; + $empty = array(); + return $empty; + } + function getAppListStrings($language='en_us'){ + $language .= '.lang.php'; + if(!empty($this->appListStrings[$language]) && $language != 'en_us.lang.php'){ + return sugarArrayMerge($this->appListStrings['en_us.lang.php'], $this->appListStrings[$language]); + } + if(!empty($this->appListStrings['en_us.lang.php']))return $this->appListStrings['en_us.lang.php']; + $empty = array(); + return $empty; + } + + function generateAppStrings($buildFromTemplate = true){ + $this->appListStrings = array('en_us.lang.php'=>array()); + //By default, generate app strings for the current language as well. + $this->appListStrings[$GLOBALS [ 'current_language' ] . ".lang.php"] = array(); + $this->loadAppListStrings($this->path . '/../../language/application'); + + if($buildFromTemplate){ + //go through the templates application strings and load anything that is needed + foreach($this->iTemplates as $template=>$val){ + $file = MB_IMPLEMENTS . '/' . $template . '/language/application'; + $this->loadAppListStrings($file); + } + foreach($this->templates as $template=>$val){ + $file = MB_TEMPLATES . '/' . $template . '/language/application'; + $this->loadAppListStrings($file); + } + } + } + function save($key_name, $duplicate=false, $rename=false){ + $header = file_get_contents('modules/ModuleBuilder/MB/header.php'); + $save_path = $this->path . '/language'; + mkdir_recursive($save_path); + foreach($this->strings as $lang=>$values){ + //Check if the module Label has changed. + $renameLang = $rename || empty($values) || $this->label != $values['LBL_MODULE_NAME']; + $mod_strings = return_module_language(str_replace('.lang.php','',$lang), 'ModuleBuilder'); + $required = array( + 'LBL_LIST_FORM_TITLE'=>$this->label . " " . $mod_strings['LBL_LIST'], + 'LBL_MODULE_NAME'=>$this->label, + 'LBL_MODULE_TITLE'=>$this->label, + 'LBL_HOMEPAGE_TITLE'=>$mod_strings['LBL_HOMEPAGE_PREFIX'] . " " . $this->label, + //FOR GENERIC MENU + 'LNK_NEW_RECORD'=>$mod_strings['LBL_CREATE'] ." ". $this->label, + 'LNK_LIST'=>$mod_strings['LBL_VIEW'] ." ". $this->label, + 'LNK_IMPORT_'.strtoupper($this->key_name)=>translate('LBL_IMPORT') ." ". $this->label, + 'LBL_SEARCH_FORM_TITLE'=>$mod_strings['LBL_SEARCH'] ." ". $this->label, + 'LBL_HISTORY_SUBPANEL_TITLE'=>$mod_strings['LBL_HISTORY'], + 'LBL_ACTIVITIES_SUBPANEL_TITLE'=>$mod_strings['LBL_ACTIVITIES'], + 'LBL_'.strtoupper($this->key_name).'_SUBPANEL_TITLE'=>$this->label, + 'LBL_NEW_FORM_TITLE' => $mod_strings['LBL_NEW'] ." ". $this->label, + ); + foreach($required as $k=>$v){ + if(empty($values[$k]) || $renameLang){ + $values[$k] = $v; + } + } + write_array_to_file('mod_strings', $values, $save_path .'/'.$lang,'w', $header); + } + $app_save_path = $this->path . '/../../language/application'; + mkdir_recursive($app_save_path); + $key_changed = ($this->key_name != $key_name); + + foreach($this->appListStrings as $lang=>$values){ + if(!$duplicate){ + unset($values['moduleList'][$this->key_name]); + } + $values['moduleList'][$key_name]= $this->label; + $appFile = $header. "\n"; + require_once('include/utils/array_utils.php'); + $this->getGlobalAppListStringsForMB($values); + foreach($values as $key=>$array){ + if($duplicate){ + //keep the original when duplicating + $appFile .= override_value_to_string_recursive2 ('app_list_strings', $key, $array); + } + $okey = $key; + if($key_changed)$key = str_replace($this->key_name, $key_name, $key); + if($key_changed)$key = str_replace(strtolower($this->key_name), strtolower($key_name), $key); + // if we aren't duplicating or the key has changed let's add it + if(!$duplicate || $okey != $key){ + $appFile .= override_value_to_string_recursive2 ('app_list_strings', $key, $array); + } + } + + $fp = sugar_fopen($app_save_path . '/'. $lang, 'w'); + fwrite($fp, $appFile); + fclose($fp); + } + } + + /** + * If there is no this dropdown list in custom\modulebuilder\packages\$package\language\application\$lang.lang.php , + * we will include it from global app_list_string array into custom\modulebuilder\packages\$package\language\application\$lang.lang.php + * when we create a dropdown filed and the value is created in MB.(#20728 ) + **/ + function getGlobalAppListStringsForMB(&$values){ + //Ensure it comes from MB + if(!empty($_REQUEST['view_package']) && !empty($_REQUEST['type']) && $_REQUEST['type']='enum' && !empty($_REQUEST['options'])){ + if(!isset($values[$_REQUEST['options']])){ + global $app_list_strings; + if(!empty($app_list_strings[$_REQUEST['options']])){ + $values[$_REQUEST['options']] = $app_list_strings[$_REQUEST['options']]; + } + } + } + } + + function build($path){ + if(file_exists($this->path.'/language/')) + copy_recursive($this->path.'/language/', $path . '/language/'); + } + + function loadTemplates() { + if(empty($this->templates)){ + if (file_exists("$this->path/config.php")) { + include "$this->path/config.php"; + $this->templates = $config['templates']; + $this->iTemplates = array(); + } + } + } + + /** + * Reset the templates and load the language files again. This is called from + * MBModule->save() once the config file has been written. + */ + function reload(){ + $this->templates = null; + $this->load(); + } + + +} \ No newline at end of file diff --git a/modules/ModuleBuilder/MB/MBModule.php b/modules/ModuleBuilder/MB/MBModule.php new file mode 100644 index 00000000..da6e20c3 --- /dev/null +++ b/modules/ModuleBuilder/MB/MBModule.php @@ -0,0 +1,801 @@ + 1 , 'acl' => 1 , 'has_tab' => 1 , 'studio' => 1 , 'audit' => 1 ) ; + public $mbpublicdefs ; + public $errors = array ( ) ; + public $path = '' ; + public $implementable = array ( + 'has_tab' => 'Navigation Tab' ) ; + public $always_implement = array ( 'assignable' => 'Assignable' , 'acl' => 'Access Controls' , 'studio' => 'Studio Support' , 'audit' => 'Audit Table' ) ; + public $iTemplate = array ( + 'assignable' ) ; + + public $config_md5 = null ; + + function __construct ($name , $path , $package , $package_key) + { + global $mod_strings; + $this->config [ 'templates' ] = array ( 'basic' => 1 ) ; + + $this->name = MBModule::getDBName ( $name ) ; + $this->key_name = $package_key . '_' . $name ; + $this->package = $package ; + $this->package_key = $package_key ; + $this->package_path = $path ; + + $this->implementable = array ( + 'has_tab' => !empty($mod_strings[ 'LBL_NAV_TAB' ]) ? $mod_strings[ 'LBL_NAV_TAB' ] : false) ; + $this->path = $this->getModuleDir () ; + // $this->mbrelationship = new MBRelationship($this->name, $this->path, $this->key_name); + $this->relationships = new UndeployedRelationships ( $this->path ) ; + $this->mbvardefs = new MBVardefs ( $this->name, $this->path, $this->key_name ) ; + + $this->load () ; + } + + function getDBName ($name) + { + return preg_replace ( "/[^\w]+/", "_", $name ) ; + } + + function getModuleName() + { + return $this->name; + } + + function getPackageName() + { + return $this->package; + } + + function getRelationships() + { + return $this->relationships; + } + + /** + * Loads the module based on the module name + * + */ + function load () + { + if (file_exists ( $this->path . '/config.php' )) + { + include ($this->path . '/config.php') ; + $this->config = $config ; + } + $label = (! empty ( $this->config [ 'label' ] )) ? $this->config [ 'label' ] : $this->name ; + $this->mblanguage = new MBLanguage ( $this->name, $this->path, $label, $this->key_name ) ; + foreach ( $this->iTemplate as $temp ) + { + if (! empty ( $this->config [ $temp ] )) + { + $this->mbvardefs->iTemplates [ $temp ] = 1 ; + $this->mblanguage->iTemplates [ $temp ] = $temp ; + } + } + $this->mbvardefs->templates = $this->config [ 'templates' ] ; + $this->mblanguage->templates = $this->config [ 'templates' ] ; + $this->mbvardefs->load () ; + $this->mblanguage->load () ; + + } + + function addTemplate ($template) + { + $this->config [ 'templates' ] [ $template ] = 1 ; + } + + function getModuleDir () + { + return $this->package_path . '/modules/' . $this->name ; + } + + function removeTemplate ($template) + { + unset ( $this->config [ 'templates' ] [ $template ] ) ; + } + + function getVardefs ($by_group = false) + { + $this->mbvardefs->updateVardefs ( $by_group ) ; + return $this->mbvardefs->getVardefs () ; + } + + function addField ($vardef) + { + $this->mbvardefs->addFieldVardef ( $vardef ) ; + } + + function addFieldObject ($field) + { + $vardef = $field->get_field_def () ; + $this->mbvardefs->mergeVardefs(); + $existingVardefs = $this->mbvardefs->getVardefs () ; + //Merge with the existing vardef if it already exists + if(!empty($existingVardefs['fields'][$vardef['name']])){ + $vardef = array_merge( $existingVardefs['fields'][$vardef['name']], $vardef); + } + if (! empty ( $vardef [ 'source' ] ) && $vardef [ 'source' ] == 'custom_fields') + unset ( $vardef [ 'source' ] ) ; + + $this->mbvardefs->load(); + $this->addField ( $vardef ) ; + $this->mbvardefs->save(); + } + + function deleteField ($name) + { + $this->mbvardefs->deleteField ( $name ) ; + } + + function fieldExists ($name = '' , $type = '') + { + $vardefs = $this->mbvardefs->getVardef () ; + if (! empty ( $vardefs )) + { + if (empty ( $type ) && empty ( $name )) + return false ; else if (empty ( $type )) + return ! empty ( $vardefs [ 'fields' ] [ $name ] ) ; else if (empty ( $name )) + { + foreach ( $vardefs [ 'fields' ] as $def ) + { + if ($def [ 'type' ] == $type) + return true ; + } + return false ; + } else + return (! empty ( $vardefs [ 'fields' ] [ $name ] ) && ($vardefs [ 'fields' ] [ $name ] [ 'type' ] == $type)) ; + } else + { + return false ; + } + } + + function getModStrings ($language = 'en_us') + { + return $this->mblanguage->getModStrings ( $language ) ; + } + + function setModStrings ($language = 'en_us' , $mod_strings) + { + $language .= '.lang.php' ; + $this->mblanguage->strings [ $language ] = $mod_strings ; + } + + function setLabel ($language = 'en_us' , $key , $value) + { + $language .= '.lang.php' ; + $this->mblanguage->strings [ $language ] [ $key ] = $value ; + //Ensure this key exists in all languages + foreach ($this->mblanguage->strings as $lang => $values) { + if (empty($values[$key])) { + $this->mblanguage->strings[$lang][$key] = $value; + } + } + } + + function deleteLabel ($language = 'en_us' , $key) + { + foreach ($this->mblanguage->strings as $lang => $values) { + if (!empty($values[$key])) { + unset($this->mblanguage->strings[$lang][$key]); + } + } + } + + /** + * Required for an MB module to work with Dynamic fields + */ + function addLabel ( $displayLabel) + { + $this->setLabel('en_us', $this->getDBName($displayLabel, false), translate($displayLabel)); + $this->save(); + } + + function getLabel ($language = 'en_us' , $key) + { + $language .= '.lang.php' ; + if (empty ( $this->mblanguage->strings [ $language ] [ $key ] )) + { + + return '' ; + } + return $this->mblanguage->strings [ $language ] [ $key ] ; + + } + + function getAppListStrings ($language = 'en_us') + { + return $this->mblanguage->getAppListStrings ( $language ) ; + } + + function setAppListStrings ($language = 'en_us' , $app_list_strings) + { + $language .= '.lang.php' ; + $this->mblanguage->appListStrings [ $language ] = $app_list_strings ; + } + + function setDropDown ($language = 'en_us' , $key , $value) + { + $language .= '.lang.php' ; + $this->mblanguage->appListStrings [ $language ] [ $key ] = $value ; + } + + function deleteDropDown ($language = 'en_us' , $key) + { + $language .= '.lang.php' ; + unset ( $this->mblanguage->appListStrings [ $language ] [ $key ] ) ; + } + + function save () + { + $this->path = $this->getModuleDir () ; + if (mkdir_recursive ( $this->path )) + { + + $this->setConfigMD5 () ; + $old_config_md5 = $this->config_md5 ; + $this->saveConfig () ; + $this->getVardefs () ; + $this->mbvardefs->save ( $this->key_name ) ; + // $this->mbrelationship->save ( $this->key_name ) ; + $this->relationships->save () ; + $this->copyMetaData () ; + $this->copyDashlet () ; + $this->copyViews() ; + if (0 != strcmp ( $old_config_md5, $this->config_md5 )) + { + $this->mblanguage->reload () ; + } + $this->mblanguage->label = $this->config [ 'label' ] ; + //pass in the key_name incase it has changed mblanguage will check if it is different and handle it accordingly + $this->mblanguage->save ( $this->key_name ) ; + + if (! file_exists ( $this->package_path . "/icons/icon_" . ucfirst ( $this->key_name ) . ".gif" )) + { + $this->createIcon () ; + } + $this->errors = array_merge ( $this->errors, $this->mbvardefs->errors ) ; + + } + } + + function copyDashlet() { + $templates = array_reverse ( $this->config [ 'templates' ], true ) ; + foreach ( $templates as $template => $a ) + { + if (file_exists ( MB_TEMPLATES . '/' . $template . '/Dashlets/Dashlet' )) + { + + $this->copyMetaRecursive ( MB_TEMPLATES . '/' . $template . '/Dashlets/Dashlet', $this->path . '/Dashlets/' . $this->key_name . 'Dashlet/' ) ; + + } + } + } + + function copyViews() { + $templates = array_reverse ( $this->config [ 'templates' ], true ) ; + foreach ( $templates as $template => $a ) + { + if (file_exists ( MB_TEMPLATES . '/' . $template . '/views' )) + { + $this->copyMetaRecursive ( MB_TEMPLATES . '/' . $template . '/views', $this->path . '/views/' ) ; + } + } + } + + function copyCustomFiles ( $from , $to ) + { + $d = dir ( $from ) ; + while ( $filename = $d->read () ) + { + if (substr ( $filename, 0, 1 ) == '.') + continue ; + if ( $filename != 'metadata' && $filename != 'Dashlets' && $filename != 'relationships' && $filename != 'language' && $filename != 'config.php' && $filename != 'relationships.php' && $filename != 'vardefs.php' ) + copy_recursive ( "$from/$filename" , "$to/$filename" ) ; + } + } + + function copyMetaData () + { + $templates = array_reverse ( $this->config [ 'templates' ], true ) ; + foreach ( $templates as $template => $a ) + { + if (file_exists ( MB_TEMPLATES . '/' . $template . '/metadata' )) + { + $this->copyMetaRecursive ( MB_TEMPLATES . '/' . $template . '/metadata', $this->path . '/metadata/' ) ; + + } + } + } + + function copyMetaRecursive ($from , $to , $overwrite = false) + { + if (! file_exists ( $from )) + return ; + if (is_dir ( $from )) + { + $findArray = array ( '' , '<_module_name>' , '' , '' , '<_object_name>' , '' ); + $replaceArray = array ( $this->key_name , strtolower ( $this->key_name ) , strtoupper ( $this->key_name ) , + $this->key_name , strtolower ( $this->key_name ) , strtoupper ( $this->key_name ) ); + mkdir_recursive ( $to ) ; + $d = dir ( $from ) ; + while ( $e = $d->read () ) + { + if (substr ( $e, 0, 1 ) == '.') + continue ; + $nfrom = $from . '/' . $e ; + $nto = $to . '/' . str_replace ( 'm-n-', $this->key_name, $e ) ; + if (is_dir ( $nfrom )) + { + $this->copyMetaRecursive ( $nfrom, $nto, $overwrite ) ; + } else + { + if ($overwrite || ! file_exists ( $nto )) + { + $contents = file_get_contents ( $nfrom ) ; + $contents = str_replace ( $findArray, $replaceArray, $contents ) ; + $fw = sugar_fopen ( $nto, 'w' ) ; + fwrite ( $fw, $contents ) ; + fclose ( $fw ) ; + } + } + } + + } + } + + function saveConfig () + { + $header = file_get_contents ( 'modules/ModuleBuilder/MB/header.php' ) ; + if (! write_array_to_file ( 'config', $this->config, $this->path . '/config.php', 'w', $header )) + { + $this->errors [] = 'Could not save config to ' . $this->path . '/config.php' ; + } + $this->setConfigMD5 () ; + } + + function setConfigMD5 () + { + if (file_exists ( $this->path . '/config.php' )) + $this->config_md5 = md5 ( base64_encode ( serialize ( $this->config ) ) ) ; + } + + function build ($basepath) + { + $path = $basepath . '/modules/' . $this->key_name ; + if (mkdir_recursive ( $path )) + { + $this->createClasses ( $path ) ; + if( $this->config['importable'] || in_array ( 'person', array_keys($this->config[ 'templates' ]) ) ) + $this->createMenu ( $path ) ; + $this->copyCustomFiles ( $this->path , $path ) ; + $this->copyMetaRecursive ( $this->path . '/metadata/', $path . '/metadata/', true ) ; + $this->copyMetaRecursive ( $this->path . '/Dashlets/' . $this->key_name . 'Dashlet/', + $path . '/Dashlets/' . $this->key_name . 'Dashlet/', true ) ; + $this->relationships->build ( $basepath ) ; + $this->mblanguage->build ( $path ) ; + } + } + + function createClasses ($path) + { + $class = array ( ) ; + $class [ 'name' ] = $this->key_name ; + $class [ 'table_name' ] = strtolower ( $class [ 'name' ] ) ; + $class [ 'extends' ] = 'Basic' ; + $class [ 'requires' ] [] = MB_TEMPLATES . '/basic/Basic.php' ; + $class [ 'requires' ] = array ( ) ; + $class [ 'audited' ] = (! empty ( $this->config [ 'audit' ] )) ? 'true' : 'false' ; + $class [ 'acl' ] = ! empty ( $this->config [ 'acl' ] ) ; + $class [ 'templates' ] = "'basic'" ; + foreach ( $this->iTemplate as $template ) + { + if (! empty ( $this->config [ $template ] )) + { + $class [ 'templates' ] .= ",'$template'" ; + } + } + foreach ( $this->config [ 'templates' ] as $template => $a ) + { + if ($template == 'basic') + continue ; + $class [ 'templates' ] .= ",'$template'" ; + $class [ 'extends' ] = ucFirst ( $template ) ; + $class [ 'requires' ] [] = MB_TEMPLATES . '/' . $template . '/' . ucfirst ( $template ) . '.php' ; + } + $class [ 'importable' ] = $this->config [ 'importable' ] ; + $this->mbvardefs->updateVardefs () ; + $class [ 'fields' ] = $this->mbvardefs->vardefs [ 'fields' ] ; + $class [ 'fields_string' ] = var_export_helper ( $this->mbvardefs->vardef [ 'fields' ] ) ; + $relationship = array ( ) ; + $class [ 'relationships' ] = var_export_helper ( $this->mbvardefs->vardef [ 'relationships' ] ) ; + $smarty = new Sugar_Smarty ( ) ; + $smarty->left_delimiter = '{{' ; + $smarty->right_delimiter = '}}' ; + $smarty->assign ( 'class', $class ) ; + //write sugar generated class + $fp = sugar_fopen ( $path . '/' . $class [ 'name' ] . '_sugar.php', 'w' ) ; + fwrite ( $fp, $smarty->fetch ( 'modules/ModuleBuilder/tpls/MBModule/Class.tpl' ) ) ; + fclose ( $fp ) ; + //write vardefs + $fp = sugar_fopen ( $path . '/vardefs.php', 'w' ) ; + fwrite ( $fp, $smarty->fetch ( 'modules/ModuleBuilder/tpls/MBModule/vardef.tpl' ) ) ; + fclose ( $fp ) ; + + if (! file_exists ( $path . '/' . $class [ 'name' ] . '.php' )) + { + $fp = sugar_fopen ( $path . '/' . $class [ 'name' ] . '.php', 'w' ) ; + fwrite ( $fp, $smarty->fetch ( 'modules/ModuleBuilder/tpls/MBModule/DeveloperClass.tpl' ) ) ; + fclose ( $fp ) ; + } + if (! file_exists ( $path . '/metadata' )) + mkdir_recursive ( $path . '/metadata' ) ; + if (! empty ( $this->config [ 'studio' ] )) + { + $fp = sugar_fopen ( $path . '/metadata/studio.php', 'w' ) ; + fwrite ( $fp, $smarty->fetch ( 'modules/ModuleBuilder/tpls/MBModule/Studio.tpl' ) ) ; + fclose ( $fp ) ; + } else + { + if (file_exists ( $path . '/metadata/studio.php' )) + unlink ( $path . '/metadata/studio.php' ) ; + } + } + + function createMenu ($path) + { + $smarty = new Sugar_Smarty ( ) ; + $smarty->assign ( 'moduleName', $this->key_name ) ; + $smarty->assign ( 'showvCard', in_array ( 'person', array_keys($this->config[ 'templates' ]) ) ) ; + $smarty->assign ( 'showimport', $this->config['importable'] ); + //write sugar generated class + $fp = sugar_fopen ( $path . '/' . 'Menu.php', 'w' ) ; + fwrite ( $fp, $smarty->fetch ( 'modules/ModuleBuilder/tpls/MBModule/Menu.tpl' ) ) ; + fclose ( $fp ) ; + } + + function addInstallDefs (&$installDefs) + { + $name = $this->key_name ; + $installDefs [ 'copy' ] [] = array ( 'from' => '/SugarModules/modules/' . $name , 'to' => 'modules/' . $name ) ; + $installDefs [ 'beans' ] [] = array ( 'module' => $name , 'class' => $name , 'path' => 'modules/' . $name . '/' . $name . '.php' , 'tab' => $this->config [ 'has_tab' ] ) ; + $this->relationships->addInstallDefs ( $installDefs ) ; + } + + function getNodes () + { + + $lSubs = array ( ) ; + $psubs = $this->getProvidedSubpanels () ; + foreach ( $psubs as $sub ) + { + $subLabel = $sub ; + if ($subLabel == 'default') + { + $subLabel = $GLOBALS [ 'mod_strings' ] [ 'LBL_DEFAULT' ] ; + } + $lSubs [] = array ( 'name' => $subLabel , 'type' => 'list' , 'action' => 'module=ModuleBuilder&MB=true&action=editLayout&view=ListView&view_module=' . $this->name . '&view_package=' . $this->package . '&subpanel=' . $sub . '&subpanelLabel=' . $subLabel . '&local=1' ) ; + } + + $searchSubs = array ( ) ; + $searchSubs [] = array ( 'name' => translate('LBL_BASIC_SEARCH') , 'type' => 'list' , 'action' => "module=ModuleBuilder&MB=true&action=editLayout&view=basic_search&view_module={$this->name}&view_package={$this->package}" ) ; + $searchSubs [] = array ( 'name' => translate('LBL_ADVANCED_SEARCH') , 'type' => 'list' , 'action' => 'module=ModuleBuilder&MB=true&action=editLayout&view=advanced_search&view_module=' . $this->name . '&view_package=' . $this->package ) ; + $dashlets = array( ); + $dashlets [] = array('name' => translate('LBL_DASHLETLISTVIEW') , 'type' => 'dashlet' , 'action' => 'module=ModuleBuilder&MB=true&action=editLayout&view=dashlet&view_module=' . $this->name . '&view_package=' . $this->package ); + $dashlets [] = array('name' => translate('LBL_DASHLETSEARCHVIEW') , 'type' => 'dashletsearch' , 'action' => 'module=ModuleBuilder&MB=true&action=editLayout&view=dashletsearch&view_module=' . $this->name . '&view_package=' . $this->package ); + + $popups = array( ); + $popups [] = array('name' => translate('LBL_POPUPLISTVIEW') , 'type' => 'popuplistview' , 'action' => 'module=ModuleBuilder&action=editLayout&view=popuplist&view_module=' . $this->name . '&view_package=' . $this->package ); + $popups [] = array('name' => translate('LBL_POPUPSEARCH') , 'type' => 'popupsearch' , 'action' => 'module=ModuleBuilder&action=editLayout&view=popupsearch&view_module=' . $this->name . '&view_package=' . $this->package ); + + $layouts = array ( + array ( 'name' => translate('LBL_EDITVIEW') , 'type' => 'edit' , 'action' => 'module=ModuleBuilder&MB=true&action=editLayout&view='.MB_EDITVIEW.'&view_module=' . $this->name . '&view_package=' . $this->package ) , + array ( 'name' => translate('LBL_DETAILVIEW') , 'type' => 'detail' , 'action' => 'module=ModuleBuilder&MB=true&action=editLayout&view='.MB_DETAILVIEW.'&view_module=' . $this->name . '&view_package=' . $this->package ) , + array ( 'name' => translate('LBL_LISTVIEW') , 'type' => 'list' , 'action' => 'module=ModuleBuilder&MB=true&action=editLayout&view='.MB_LISTVIEW.'&view_module=' . $this->name . '&view_package=' . $this->package ) , + array ( 'name' => translate('LBL_QUICKCREATE') , 'type' => MB_QUICKCREATE, 'action' => 'module=ModuleBuilder&MB=true&action=editLayout&view='.MB_QUICKCREATE.'&view_module=' . $this->name . '&view_package=' . $this->package ) , + array ( 'name' => translate('LBL_DASHLET') , 'type' => 'Folder', 'children' => $dashlets, 'action' => 'module=ModuleBuilder&MB=true&action=wizard&view=dashlet&view_module=' . $this->name . '&view_package=' . $this->package ), + array ( 'name' => translate('LBL_POPUP') , 'type' => 'Folder', 'children' => $popups, 'action' => 'module=ModuleBuilder&MB=true&action=wizard&view=popup&view_module=' . $this->name . '&view_package=' . $this->package ), + array ( 'name' => translate('LBL_SEARCH_FORMS') , 'action' => 'module=ModuleBuilder&MB=true&action=wizard&view=search&view_module=' . $this->name . '&view_package=' . $this->package , 'type' => 'folder' , 'children' => $searchSubs ) + ) ; + + $children = array ( + array ( 'name' => translate('LBL_FIELDS') , 'action' => 'module=ModuleBuilder&action=modulefields&view_module=' . $this->name . '&view_package=' . $this->package ) , + array ( 'name' => translate('LBL_LABELS') , 'action' => 'module=ModuleBuilder&action=modulelabels&view_module=' . $this->name . '&view_package=' . $this->package ) , + array ( 'name' => translate('LBL_RELATIONSHIPS') , 'action' => 'module=ModuleBuilder&action=relationships&view_module=' . $this->name . '&view_package=' . $this->package ) , + array ( 'name' => translate('LBL_LAYOUTS') , 'type' => 'Folder' , 'action' => "module=ModuleBuilder&action=wizard&view_module={$this->name}&view_package={$this->package}&MB=1" , 'children' => $layouts ) , + ) ; + + if (count ( $lSubs ) > 0) + { + $children [] = array ( 'name' => translate('LBL_AVAILABLE_SUBPANELS') , 'type' => 'folder' , 'children' => $lSubs ) ; + } + + $nodes = array ( 'name' => $this->name , 'children' => $children , 'action' => 'module=ModuleBuilder&action=module&view_module=' . $this->name . '&view_package=' . $this->package ) ; + + return $nodes ; + } + + + function getProvidedSubpanels () + { + $this->providedSubpanels = array () ; + + $subpanelDir = $this->getModuleDir () . '/metadata/subpanels/' ; + if (file_exists ( $subpanelDir )) + { + $f = dir ( $subpanelDir ) ; + require_once 'modules/ModuleBuilder/parsers/relationships/AbstractRelationships.php' ; + + while ( $g = $f->read () ) + { + // sanity check to confirm that this is a usable subpanel... + if (substr ( $g, 0, 1 ) != '.' && AbstractRelationships::validSubpanel ( $subpanelDir . $g )) + { + $subname = str_replace ( '.php', '', $g ) ; + $this->providedSubpanels [ $subname ] = $subname ; + } + } + } + + return $this->providedSubpanels; + } + + function getTypes () + { + $types = array ( ) ; + $d = dir ( MB_TEMPLATES ) ; + while ( $e = $d->read () ) + { + if (substr ( $e, 0, 1 ) != '.') + { + $types [ $e ] = $e ; + } + } + + return $types ; + } + + function rename ($new_name) + { + $old = $this->getModuleDir () ; + $old_name = $this->key_name; + $this->name = $new_name ; + $this->key_name = $this->package_key . '_' . $this->name ; + $new = $this->getModuleDir () ; + if (file_exists ( $new )) + { + return false ; + } + $renamed = rename ( $old, $new ) ; + if ($renamed) + { + $this->renameMetaData ( $new , $old_name) ; + $this->renameLanguageFiles ( $new ) ; + + } + return $renamed ; + } + + function renameLanguageFiles ($new_dir , $duplicate = false) + { + + $this->mblanguage->name = $this->name ; + $this->mblanguage->path = $new_dir ; + $this->mblanguage->generateAppStrings () ; + $this->mblanguage->save ( $this->key_name, $duplicate, true) ; + } + + function renameMetaData ($new_dir, $old_name) + { + $GLOBALS [ 'log' ]->debug ( 'MBModule.php->renameMetaData: new_dir=' . $new_dir ) ; + if (! file_exists ( $new_dir )) + return ; + $dir = dir ( $new_dir ) ; + while ( $e = $dir->read () ) + { + if (substr ( $e, 0, 1 ) != '.') + { + if (is_dir ( $new_dir . '/' . $e )) + { + $this->renameMetaData ( $new_dir . '/' . $e, $old_name) ; + } + if (is_file ( $new_dir . '/' . $e )) + { + $contents = file_get_contents ( $new_dir . '/' . $e ) ; + $contents = preg_replace ( '/(\$module_name[ ]*=[ ]*\')(.*)(\'[ ]*;)/', '$1' . $this->key_name . '$3', $contents ) ; + $contents = preg_replace ( '/(\$_module_name[ ]*=[ ]*\')(.*)(\'[ ]*;)/', '$1' . strtolower ( $this->key_name ) . '$3', $contents ) ; + $contents = preg_replace ( '/(\$MODULE_NAME[ ]*=[ ]*\')(.*)(\'[ ]*;)/', '$1' . strtoupper ( $this->key_name ) . '$3', $contents ) ; + $contents = preg_replace ( '/(\$object_name[ ]*=[ ]*\')(.*)(\'[ ]*;)/', '$1' . $this->key_name . '$3', $contents ) ; + $contents = preg_replace ( '/(\$_object_name[ ]*=[ ]*\')(.*)(\'[ ]*;)/', '$1' . strtolower ( $this->key_name ) . '$3', $contents ) ; + $contents = preg_replace ( '/(\$OBJECT_NAME[ ]*=[ ]*\')(.*)(\'[ ]*;)/', '$1' . strtoupper ( $this->key_name ) . '$3', $contents ) ; + $contents = str_replace ( "{$old_name}_", $this->key_name . "_", $contents ) ; + $fp = sugar_fopen ( $new_dir . '/' . $e, 'w' ) ; + fwrite ( $fp, $contents ) ; + fclose ( $fp ) ; + } + } + } + + } + + function copy ($new_name) + { + $old = $this->getModuleDir () ; + + $count = 0 ; + $old_name = $this->key_name; + $this->name = $new_name ; + $this->key_name = $this->package_key . '_' . $this->name ; + $new = $this->getModuleDir () ; + while ( file_exists ( $new ) ) + { + $count ++ ; + $this->name = $new_name . $count ; + $this->key_name = $this->package_key . '_' . $this->name ; + $new = $this->getModuleDir () ; + } + + $new = $this->getModuleDir () ; + $copied = copy_recursive ( $old, $new ) ; + + if ($copied) + { + $this->renameMetaData ( $new , $old_name) ; + $this->renameLanguageFiles ( $new, true ) ; + } + return $copied ; + + } + + function delete () + { + return rmdir_recursive ( $this->getModuleDir () ) ; + } + + function populateFromPost () + { + foreach ( $this->implementable as $key => $value ) + { + $this->config [ $key ] = ! empty ( $_REQUEST [ $key ] ) ; + } + foreach ( $this->always_implement as $key => $value ) + { + $this->config [ $key ] = true ; + } + if (! empty ( $_REQUEST [ 'type' ] )) + { + $this->addTemplate ( $_REQUEST [ 'type' ] ) ; + } + + if (! empty ( $_REQUEST [ 'label' ] )) + { + $this->config [ 'label' ] = $_REQUEST [ 'label' ] ; + } + + $this->config [ 'importable' ] = ! empty( $_REQUEST[ 'importable' ] ) ; + + } + + function getAvailibleSubpanelDef ($panelName) + { + $filepath = $this->getModuleDir () . "/metadata/subpanels/{$panelName}.php" ; + if (file_exists ( $filepath )) + { + include ($filepath) ; + return $subpanel_layout ; + } + return array ( ) ; + + } + + function saveAvailibleSubpanelDef ($panelName , $layout) + { + $dir = $this->getModuleDir () . "/metadata/subpanels" ; + $filepath = "$dir/{$panelName}.php" ; + if (mkdir_recursive ( $dir )) + { + // preserve any $module_name entry if one exists + if (file_exists ( $filepath )) + { + include ($filepath) ; + } + $module_name = (isset ( $module_name )) ? $module_name : $this->key_name ; + $layout = "debug ( "About to save this file to $filepath" ) ; + $GLOBALS [ 'log' ]->debug ( $layout ) ; + $fw = sugar_fopen ( $filepath, 'w' ) ; + fwrite ( $fw, $layout ) ; + fclose ( $fw ) ; + } + } + + function getLocalSubpanelDef ($panelName) + { + + } + + function createIcon () + { + $icondir = $this->package_path . "/icons" ; + mkdir_recursive ( $icondir ) ; + $template = "" ; + foreach ( $this->config [ 'templates' ] as $temp => $val ) + $template = $temp ; + copy ( "themes/default/images/icon_$template.gif", "$icondir/icon_" . ucfirst ( $this->key_name ) . ".gif" ) ; + copy ( "include/SugarObjects/templates/$template/icons/$template.gif", "$icondir/" . $this->key_name . ".gif" ) ; + if (file_exists("include/SugarObjects/templates/$template/icons/Create$template.gif")) + copy ( "include/SugarObjects/templates/$template/icons/Create$template.gif", "$icondir/Create" . $this->key_name . ".gif" ) ; + if (file_exists("include/SugarObjects/templates/$template/icons/{$template}_32.gif")) + copy ( "include/SugarObjects/templates/$template/icons/{$template}_32.gif", "$icondir/icon_" . $this->key_name . "_32.gif" ) ; + } + + function removeFieldFromLayouts ( $fieldName ) + { + // hardcoded list of types for now, as also hardcoded in a different form in getNodes + // TODO: replace by similar mechanism to StudioModule to determine the list of available views for this module + $views = array ( 'editview' , 'detailview' , 'listview' , 'basic_search' , 'advanced_search' , 'dashlet' , 'popuplist'); + + foreach ($views as $type ) + { + $parser = ParserFactory::getParser( $type , $this->name , $this->package ) ; + if ($parser->removeField ( $fieldName ) ) + $parser->handleSave(false) ; // don't populate from $_REQUEST, just save as is... + } + //Remove the fields in subpanel + $psubs = $this->getProvidedSubpanels() ; + foreach ( $psubs as $sub ) + { + $parser = ParserFactory::getParser( MB_LISTVIEW , $this->name, $this->package , $sub) ; + if ($parser->removeField ( $fieldName ) ) + $parser->handleSave(false) ; + } + } + +} +?> \ No newline at end of file diff --git a/modules/ModuleBuilder/MB/MBPackage.php b/modules/ModuleBuilder/MB/MBPackage.php new file mode 100644 index 00000000..8e08da54 --- /dev/null +++ b/modules/ModuleBuilder/MB/MBPackage.php @@ -0,0 +1,787 @@ +name = $name; + $this->load(); + + } + function loadModules($force=false){ + if(!file_exists(MB_PACKAGE_PATH . '/' . $this->name .'/modules'))return; + $d = dir(MB_PACKAGE_PATH . '/' . $this->name .'/modules'); + while($e = $d->read()){ + if(substr($e, 0, 1) != '.' && is_dir(MB_PACKAGE_PATH . '/'. $this->name. '/modules/' . $e)){ + $this->getModule($e, $force); + } + } + } + + /** + * Loads the translated module titles from the selected language into. + * Will override currently loaded string to reflect undeployed label changes. + * $app_list_strings + * @return + * @param $languge String language identifyer + */ + function loadModuleTitles($languge = '') + { + if (empty($language)) + { + $language = $GLOBALS['current_language']; + } + global $app_list_strings; + $packLangFilePath = $this->getPackageDir() . "/language/application/" . $language . ".lang.php"; + if (file_exists($packLangFilePath)) + { + + require($packLangFilePath); + } + } + + function getModule($name, $force=true){ + if(!$force && !empty($this->modules[$name]))return; + $path = $this->getPackageDir(); + + $this->modules[$name] = new MBModule($name, $path, $this->name, $this->key); + } + + function deleteModule($name){ + $this->modules[$name]->delete(); + unset($this->modules[$name]); + } + +function getManifest($version_specific = false, $for_export = false){ + //If we are exporting the package, we must ensure a different install key + $pre = $for_export ? MB_EXPORTPREPEND : ""; + $date = TimeDate::getInstance()->nowDb(); + $time = time(); + $this->description = to_html($this->description); + $is_uninstallable = ($this->is_uninstallable ? 'true' : 'false'); + $flavor = "'" . $GLOBALS['sugar_flavor'] . "'"; + if($GLOBALS['sugar_flavor'] == 'CE')$flavor = "'CE', 'PRO','ENT'"; + $version = (!empty($version_specific))?"'" . $GLOBALS['sugar_version'] . "'" : ''; + $header = file_get_contents('modules/ModuleBuilder/MB/header.php'); + return << + array ( + $version + ), + 'acceptable_sugar_flavors' => + array( + $flavor + ), + 'readme'=>'$this->readme', + 'key'=>'$this->key', + 'author' => '$this->author', + 'description' => '$this->description', + 'icon' => '', + 'is_uninstallable' => $is_uninstallable, + 'name' => '$pre$this->name', + 'published_date' => '$date', + 'type' => 'module', + 'version' => '$time', + 'remove_tables' => 'prompt', + ); +EOQ; +} + +function buildInstall($path){ + $installdefs = array ('id' => $this->name, + 'beans'=>array(), + 'layoutdefs'=>array(), + 'relationships'=>array(), + ); + if($this->has_images){ + $installdefs['image_dir'] = '/icons'; + } + foreach(array_keys($this->modules) as $module){ + $this->modules[$module]->build($path); + $this->modules[$module]->addInstallDefs($installdefs); + } + $this->path = $this->getPackageDir(); + if(file_exists($this->path . '/language')){ + $d= dir($this->path . '/language'); + while($e = $d->read()){ + $lang_path = $this->path .'/language/' . $e; + if(substr($e, 0, 1) != '.' && is_dir($lang_path)){ + $f = dir($lang_path); + while($g = $f->read()){ + if(substr($g, 0, 1) != '.' && is_file($lang_path.'/'. $g)){ + $lang = substr($g, 0, strpos($g, '.')); + $installdefs['language'][] = array( + 'from'=> '/SugarModules/language/'.$e . '/'. $g, + 'to_module'=> $e, + 'language'=> $lang + ); + } + } + } + } + + copy_recursive( $this->path . '/language/', $path . '/language/'); + $icon_path = $path . '/../icons/default/images/'; + mkdir_recursive($icon_path); + copy_recursive($this->path . '/icons/', $icon_path); + } + return "\n".'$installdefs = ' . var_export_helper($installdefs). ';'; + +} + + function getPackageDir(){ + return MB_PACKAGE_PATH . '/' . $this->name; + } + + function getBuildDir(){ + return MB_PACKAGE_BUILD . '/' . $this->name; + } + + function getZipDir(){ + return $this->getPackageDir() . '/zips'; + } + + + function load(){ + $path = $this->getPackageDir(); + if(file_exists($path .'/manifest.php')){ + require($path . '/manifest.php'); + if(!empty($manifest)){ + $this->date_modified = $manifest['published_date']; + $this->is_uninstallable = $manifest['is_uninstallable']; + $this->author = $manifest['author']; + $this->key = $manifest['key']; + $this->description = $manifest['description']; + if(!empty($manifest['readme'])) + $this->readme = $manifest['readme']; + } + } + $this->loadModules(true); + } + + function save(){ + $path = $this->getPackageDir(); + if(mkdir_recursive($path)){ + $fp = sugar_fopen($path .'/manifest.php', 'w'); + + + //Save all the modules when we save a package + $this->updateModulesMetaData(true); + fwrite($fp, $this->getManifest() ); + fclose($fp); + } + + + + + } + + function build($export=true, $clean = false){ + $this->loadModules(); + require_once('include/utils/zip_utils.php'); + $package_path = $this->getPackageDir(); + $path = $this->getBuildDir() . '/SugarModules'; + if($clean && file_exists($path))rmdir_recursive($path); + if(mkdir_recursive($path)){ + + $manifest = $this->getManifest().$this->buildInstall($path); + $fp = sugar_fopen($this->getBuildDir() .'/manifest.php', 'w'); + fwrite($fp, $manifest); + fclose($fp); + + } + if(file_exists('modules/ModuleBuilder/MB/LICENSE.txt')){ + copy('modules/ModuleBuilder/MB/LICENSE.txt', $this->getBuildDir() . '/LICENSE.txt'); + }else if(file_exists('LICENSE.txt')){ + copy('LICENSE.txt', $this->getBuildDir() . '/LICENSE.txt'); + } + $package_dir = $this->getPackageDir(); + $date = date('Y_m_d_His'); + $zipDir = $this->getZipDir(); + if(!file_exists($zipDir))mkdir_recursive($zipDir); + $cwd = getcwd(); + chdir($this->getBuildDir()); + zip_dir('.',$cwd . '/'. $zipDir. '/'. $this->name. $date. '.zip'); + chdir($cwd); + if($export){ + header('Location:' . $zipDir. '/'. $this->name. $date. '.zip'); + } + return array( + 'zip'=>$zipDir. '/'. $this->name. $date. '.zip', + 'manifest'=>$this->getBuildDir(). '/manifest.php', + 'name'=>$this->name. $date, + ); + } + + + function getNodes(){ + $this->loadModules(); + $node = array('name'=>$this->name, 'action'=>'module=ModuleBuilder&action=package&package=' . $this->name, 'children'=>array()); + foreach(array_keys($this->modules) as $module){ + $node['children'][] = $this->modules[$module]->getNodes(); + } + return $node; + } + + function populateFromPost(){ + $this->description = $_REQUEST['description']; + $this->author = $_REQUEST['author']; + $this->key = $_REQUEST['key']; + $this->readme = $_REQUEST['readme']; + } + + function rename($new_name){ + $old= $this->getPackageDir(); + $this->name = $new_name; + $new = $this->getPackageDir(); + if(file_exists($new)){ + return false; + } + if(rename($old, $new)){ + return true; + } + + return false; + } + + function updateModulesMetaData($save=false){ + foreach(array_keys($this->modules) as $module){ + $old_name = $this->modules[$module]->key_name; + $this->modules[$module]->key_name = $this->key . '_' . $this->modules[$module]->name; + $this->modules[$module]->renameMetaData($this->modules[$module]->getModuleDir(), $old_name); + $this->modules[$module]->renameLanguageFiles($this->modules[$module]->getModuleDir()); + if($save)$this->modules[$module]->save(); + } + + } + + function copy($new_name){ + $old= $this->getPackageDir(); + + $count = 0; + $this->name = $new_name; + $new= $this->getPackageDir(); + while(file_exists($new)){ + $count++; + $this->name = $new_name . $count; + $new= $this->getPackageDir(); + } + + $new = $this->getPackageDir(); + if(copy_recursive($old, $new)){ + $this->updateModulesMetaData(); + return true; + } + return false; + + } + + function delete(){ + return rmdir_recursive($this->getPackageDir()); + } + + + //creation of the installdefs[] array for the manifest when exporting customizations + function customBuildInstall($modules, $path, $extensions = array()){ + $columns=$this->getColumnsName(); + $installdefs = array ('id' => $this->name); + $include_path="$path/SugarModules/include/language"; + if(file_exists($include_path) && is_dir($include_path)){ + $dd= dir($include_path); + while($gg = $dd->read()){ + if(substr($gg, 0, 1) != '.' && is_file($include_path . '/' . $gg)){ + $lang = substr($gg, 0, strpos($gg, '.')); + $installdefs['language'][] = array( + 'from'=> '/SugarModules/include/language/'. $gg, + 'to_module'=> 'application', + 'language'=>$lang + ); + } + } + } + + foreach($modules as $value){ + $custom_module = $this->getCustomModules($value); + foreach($custom_module as $va){ + if ($va == 'language'){ + $this->getLanguageManifestForModule($value, $installdefs); + $this->getCustomFieldsManifestForModule($value, $installdefs); + }//fi + if($va == 'metadata'){ + $this->getCustomMetadataManifestForModule($value, $installdefs); + }//fi + }//foreach + }//foreach + if (is_dir("$path/Extension")) + { + $this->getExtensionsManifestForPackage($path, $installdefs); + } + return "\n".'$installdefs = ' . var_export_helper($installdefs). ';'; + } + + private function getLanguageManifestForModule($module, &$installdefs) + { + $lang_path = 'custom/modules/' . $module . '/language'; + foreach(scandir($lang_path) as $langFile) + { + if(substr($langFile, 0, 1) != '.' && is_file($lang_path . '/' . $langFile)){ + $lang = substr($langFile, 0, strpos($langFile, '.')); + $installdefs['language'][] = array( + 'from'=> '/SugarModules/modules/' . $module . '/language/'. $langFile, + 'to_module'=> $module, + 'language'=>$lang + ); + } + } + } + + private function getCustomFieldsManifestForModule($module, &$installdefs) + { + $db = DBManagerFactory::getInstance(); + $result=$db->query("SELECT * FROM fields_meta_data where custom_module='$module'"); + while($row = $db->fetchByAssoc($result)){ + $name = $row['id']; + foreach($row as $col=>$res){ + switch ($col) { + case 'custom_module': + $installdefs['custom_fields'][$name]['module'] = $res; + break; + case 'required': + $installdefs['custom_fields'][$name]['require_option'] = $res; + break; + case 'vname': + $installdefs['custom_fields'][$name]['label'] = $res; + break; + case 'required': + $installdefs['custom_fields'][$name]['require_option'] = $res; + break; + case 'massupdate': + $installdefs['custom_fields'][$name]['mass_update'] = $res; + break; + case 'comments': + $installdefs['custom_fields'][$name]['comments'] = $res; + break; + case 'help': + $installdefs['custom_fields'][$name]['help'] = $res; + break; + case 'len': + $installdefs['custom_fields'][$name]['max_size'] = $res; + break; + default: + $installdefs['custom_fields'][$name][$col] = $res; + }//switch + }//foreach + }//while + } + + private function getCustomMetadataManifestForModule($module, &$installdefs) + { + $meta_path = 'custom/modules/' . $module . '/metadata'; + foreach(scandir($meta_path) as $meta_file) + { + if(substr($meta_file, 0, 1) != '.' && is_file($meta_path . '/' . $meta_file)){ + if($meta_file == 'listviewdefs.php'){ + $installdefs['copy'][] = array( + 'from'=> '/SugarModules/modules/'. $module . '/metadata/'. $meta_file, + 'to'=> 'custom/modules/'. $module . '/metadata/' . $meta_file, + ); + } + else{ + $installdefs['copy'][] = array( + 'from'=> '/SugarModules/modules/'. $module . '/metadata/'. $meta_file, + 'to'=> 'custom/modules/'. $module . '/metadata/' . $meta_file, + ); + $installdefs['copy'][] = array( + 'from'=> '/SugarModules/modules/'. $module . '/metadata/'. $meta_file, + 'to'=> 'custom/working/modules/'. $module . '/metadata/' . $meta_file, + ); + } + } + } + } + + private function getExtensionsManifestForPackage($path, &$installdefs) + { + $extPath = "$path/Extension/modules"; + foreach(scandir($extPath) as $moduleDir) + { + if(substr($moduleDir, 0, 1) != '.' && is_dir("$extPath/$moduleDir/Ext")){ + foreach(scandir("$extPath/$moduleDir/Ext") as $type) + { + if(substr($type, 0, 1) != '.' && is_dir("$extPath/$moduleDir/Ext/$type")){ + foreach(scandir("$extPath/$moduleDir/Ext/$type") as $file) + { + if(substr($file, 0, 1) != '.' && strtolower(substr($file, -4)) == ".php") + { + $installdefs['copy'][] = array( + 'from'=> "/Extension/modules/$moduleDir/Ext/$type/$file", + 'to'=> "custom/Extension/modules/$moduleDir/Ext/$type/$file", + ); + } + } + } + } + } + } + } + + + //return an array which contain the name of fields_meta_data table's columns + function getColumnsName(){ + + $meta = new FieldsMetaData(); + $arr = array(); + foreach($meta->getFieldDefinitions() as $key=>$value) { + $arr[] = $key; + } + return $arr; + } + + + //creation of the custom fields ZIP file (use getmanifest() and customBuildInstall() ) + function exportCustom($modules, $export=true, $clean = true){ + $path=$this->getBuildDir(); + if($clean && file_exists($path))rmdir_recursive($path); + //Copy the custom files to the build dir + foreach($modules as $mod){ + $extensions = $this->getExtensionsList($mod); + $pathmod="$path/SugarModules/modules/$mod"; + if(mkdir_recursive($pathmod)){ + if(file_exists("custom/modules/$mod")){ + copy_recursive("custom/modules/$mod", "$pathmod"); + //Don't include cached extension files + if (is_dir("$pathmod/Ext")) + rmdir_recursive("$pathmod/Ext"); + } + //Convert modstring files to extension compatible arrays + $this->convertLangFilesToExtensions("$pathmod/language"); + } + $pathext="$path/Extension/modules/$mod/Ext"; + if (!empty($extensions) && mkdir_recursive($pathext)) + { + foreach($extensions as $type => $files) + { + sugar_mkdir("$pathext/$type"); + foreach($files as $file => $filePath) + { + copy ($filePath, "$pathext/$type/$file"); + } + } + } + } + + $this->copyCustomDropdownValuesForModules($modules,$path); + if(file_exists($path)){ + $manifest = $this->getManifest(true).$this->customBuildInstall($modules,$path); + sugar_file_put_contents($path .'/manifest.php', $manifest);; + } + if(file_exists('modules/ModuleBuilder/MB/LICENSE.txt')){ + copy('modules/ModuleBuilder/MB/LICENSE.txt', $path . '/LICENSE.txt'); + } + else if(file_exists('LICENSE.txt')){ + copy('LICENSE.txt', $path . '/LICENSE.txt'); + } + require_once('include/utils/zip_utils.php'); + $date = date('Y_m_d_His'); + $zipDir = $this->getZipDir(); + if(!file_exists($zipDir))mkdir_recursive($zipDir); + $cwd = getcwd(); + chdir($this->getBuildDir()); + zip_dir('.',$cwd . '/'. $zipDir. '/'. $this->name. $date. '.zip'); + chdir($cwd); + if($clean && file_exists($this->getBuildDir()))rmdir_recursive($this->getBuildDir()); + if($export){ + header('Location:' . $zipDir. '/'. $this->name. $date. '.zip'); + } + return $zipDir. '/'. $this->name. $date. '.zip'; + } + + private function convertLangFilesToExtensions($langDir) + { + if (is_dir($langDir)) + { + foreach(scandir($langDir) as $langFile) + { + $mod_strings = array(); + if (strcasecmp(substr($langFile, -4), ".php") != 0) + continue; + include("$langDir/$langFile"); + $out = " $lbl_val ) + { + $out .= override_value_to_string("mod_strings", $lbl_key, $lbl_val) . "\n"; + } + $out .= "\n?>\n"; + sugar_file_put_contents("$langDir/$langFile", $out); + } + } + } + private function copyCustomDropdownValuesForModules($modules, $path) + { + if(file_exists("custom/include/language")){ + if(mkdir_recursive("$path/SugarModules/include")){ + global $app_list_strings; + $backStrings = $app_list_strings; + foreach(scandir("custom/include/language") as $langFile) + { + $app_list_strings = array(); + if (strcasecmp(substr($langFile, -4), ".php") != 0) + continue; + include("custom/include/language/$langFile"); + $out = "getCustomDropDownStringsForModules($modules, $app_list_strings); + foreach($options as $name => $arr) { + $out .= override_value_to_string('app_list_strings', $name, $arr); + } + mkdir_recursive("$path/SugarModules/include/language/"); + sugar_file_put_contents("$path/SugarModules/include/language/$lang.$this->name.php", $out); + } + $app_list_strings = $backStrings; + } + } + } + + function getCustomDropDownStringsForModules($modules, $list_strings) { + global $beanList, $beanFiles; + $options = array(); + foreach($modules as $module) + { + if (!empty($beanList[$module])) + { + require_once($beanFiles[$beanList[$module]]); + $bean = new $beanList[$module](); + foreach($bean->field_defs as $field => $def) + { + if (isset($def['options']) && isset($list_strings[$def['options']])) + { + $options[$def['options']] = $list_strings[$def['options']]; + } + } + } + } + return $options; + } + + + + //if $module=false : return an array with custom module and there customizations. + //if $module=!false : return an array with the directories of custom/module/$module. + function getCustomModules($module=false){ + global $mod_strings; + $path='custom/modules/'; + $extPath = 'custom/Extension/modules/'; + if(!file_exists($path) || !is_dir($path)){ + return array($mod_strings['LBL_EC_NOCUSTOM'] => ""); + } + else{ + if ($module != false ){ + $path=$path . $module . '/'; + } + $scanlisting = scandir($path); + $dirlisting = array(); + foreach ($scanlisting as $value){ + if(is_dir($path . $value) == true && $value != '.' && $value != '..') { + $dirlisting[] = $value; + } + } + if(empty($dirlisting)){ + return array($mod_strings['LBL_EC_NOCUSTOM'] => ""); + } + if ($module == false ){ + foreach ($dirlisting as $value){ + if(!file_exists('modules/' . $value . '/metadata/studio.php')) + continue; + $custommodules[$value]=$this->getCustomModules($value); + foreach ($custommodules[$value] as $va){ + switch ($va) { + case 'language': + $return[$value][$va] = $mod_strings['LBL_EC_CUSTOMFIELD']; + break; + case 'metadata': + $return[$value][$va] = $mod_strings['LBL_EC_CUSTOMLAYOUT']; + break; + case 'Ext': + + $return[$value][$va] = $mod_strings['LBL_EC_CUSTOMFIELD']; + break; + case '': + $return[$value . " " . $mod_strings['LBL_EC_EMPTYCUSTOM']] = ""; + break; + default: + $return[$value][$va] = $mod_strings['LBL_UNDEFINED']; + } + } + } + return $return; + } + else{ + return $dirlisting; + } + } + } + + private function getExtensionsList($module, $excludeRelationships = true) + { + require_once 'modules/ModuleBuilder/parsers/relationships/DeployedRelationships.php' ; + $extPath = 'custom/Extension/modules/'; + $modExtPath = $extPath . $module . '/Ext'; + $rels = new DeployedRelationships($module); + $relList = $rels->getRelationshipList (); + + $ret = array(); + if (is_dir($modExtPath)) + { + $extFolders = scandir($modExtPath); + foreach($extFolders as $extFolder) + { + if (!is_dir("$modExtPath/$extFolder") || substr($extFolder, 0, 1) == ".") + continue; + + foreach( scandir("$modExtPath/$extFolder") as $extFile) + { + + if (substr($extFile, 0, 1) == "." || strtolower(substr($extFile, -4)) != ".php") + continue; + //Exclude relattionship extension files + if ($excludeRelationships && ( + (substr($extFile, 0, 6) == "custom" && isset($relList[substr($extFile, 6, strlen($extFile) - 10)])) || + (substr($extFile, 6, 6) == "custom" && isset($relList[substr($extFile, 12, strlen($extFile) - 16)])) + )) { + continue; + } + + if (!isset($ret[$extFolder])) + $ret[$extFolder] = array(); + + $ret[$extFolder][$extFile ] = "$modExtPath/$extFolder/$extFile"; + } + } + } + return $ret; + } + + /** + * Returns a set of field defs for fields that will exist when this package is deployed + * based on the relationships in all of its modules. + * + * @param $moduleName (module must be from whithin this package) + * @return array Field defs + */ + function getRelationshipsForModule($moduleName) { + $ret = array(); + if (isset($this->modules[$moduleName])) { + $keyName = $this->modules[$moduleName]->key_name; + foreach($this->modules as $mName => $module) { + $rels = $module->getRelationships(); + $relList = $rels->getRelationshipList(); + foreach($relList as $rName ) { + $rel = $rels->get ( $rName ) ; + if ($rel->lhs_module == $keyName || $rel->rhs_module == $keyName) { + $ret[$rName] = $rel; + } + } + } + } + return $ret; + } + + + + function exportProjectInstall($package, $for_export){ + $pre = $for_export ? MB_EXPORTPREPEND : ""; + $installdefs = array ('id' => $pre . $this->name); + $installdefs['copy'][] = array( + 'from'=> '/' . $this->name, + 'to'=> 'custom/modulebuilder/packages/'. $this->name, + ); + return "\n".'$installdefs = ' . var_export_helper($installdefs). ';'; + + } + + + + function exportProject($package, $export=true, $clean = true){ + $tmppath="custom/modulebuilder/projectTMP/"; + if(file_exists($this->getPackageDir())){ + if(mkdir_recursive($tmppath)){ + copy_recursive($this->getPackageDir(), $tmppath ."/". $this->name); + $manifest = $this->getManifest(true, $export).$this->exportProjectInstall($package, $export); + $fp = sugar_fopen($tmppath .'/manifest.php', 'w'); + fwrite($fp, $manifest); + fclose($fp); + if(file_exists('modules/ModuleBuilder/MB/LICENSE.txt')){ + copy('modules/ModuleBuilder/MB/LICENSE.txt', $tmppath . '/LICENSE.txt'); + } + else if(file_exists('LICENSE.txt')){ + copy('LICENSE.txt', $tmppath . '/LICENSE.txt'); + } + $readme_contents = $this->readme; + $readmefp = sugar_fopen($tmppath.'/README.txt','w'); + fwrite($readmefp, $readme_contents); + fclose($readmefp); + } + } + require_once('include/utils/zip_utils.php'); + $date = date('Y_m_d_His'); + $zipDir = "custom/modulebuilder/packages/ExportProjectZips"; + if(!file_exists($zipDir))mkdir_recursive($zipDir); + $cwd = getcwd(); + chdir($tmppath); + zip_dir('.',$cwd . '/'. $zipDir. '/project_'. $this->name. $date. '.zip'); + chdir($cwd); + if($clean && file_exists($tmppath))rmdir_recursive($tmppath); + if($export){ + header('Location:' . $zipDir. '/project_'. $this->name. $date. '.zip'); + } + return $zipDir. '/project_'. $this->name. $date. '.zip'; + } + + +} +?> diff --git a/modules/ModuleBuilder/MB/MBPackageTree.php b/modules/ModuleBuilder/MB/MBPackageTree.php new file mode 100644 index 00000000..15aa9836 --- /dev/null +++ b/modules/ModuleBuilder/MB/MBPackageTree.php @@ -0,0 +1,79 @@ +tree = new Tree('package_tree'); + $this->tree->id = 'package_tree'; + $this->mb = new ModuleBuilder(); + $this->populateTree($this->mb->getNodes(), $this->tree); + } + + function getName(){ + return 'Packages'; + } + + function populateTree($nodes, &$parent){ + foreach($nodes as $node){ + if(empty($node['label']))$node['label'] = $node['name']; + $yn = new Node($parent->id . '/' . $node['name'],$node['label']); + if(!empty($node['action'])) + $yn->set_property('action', $node['action']); + $yn->set_property('href', 'javascript:void(0);'); + $yn->id = $parent->id . '/' . $node['name']; + if(!empty($node['children']))$this->populateTree($node['children'], $yn); + $parent->add_node($yn); + } + } + + function fetch(){ + //return $this->tree->generate_header() . $this->tree->generate_nodes_array(); + return $this->tree->generate_nodes_array(); + } + + function fetchNodes(){ + return $this->tree->generateNodesRaw(); + } + + + + + +} +?> \ No newline at end of file diff --git a/modules/ModuleBuilder/MB/MBRelationship.php b/modules/ModuleBuilder/MB/MBRelationship.php new file mode 100644 index 00000000..9fba80b7 --- /dev/null +++ b/modules/ModuleBuilder/MB/MBRelationship.php @@ -0,0 +1,176 @@ +implementation = new UndeployedRelationships ( $path ) ; + $this->moduleName = $key_name ; + $this->path = $path ; + $this->updateRelationshipVariable(); + } + + function findRelatableModules () + { + // do not call findRelatableModules in the constructor as it leads to an infinite loop if the implementation calls getPackage() which loads the packages which loads the module which findsRelatableModules which... + $this->relatableModules = $this->implementation->findRelatableModules () ; + } + + /* + * Originally in 5.0 this method expected $_POST variables keyed in the "old" format - lhs_module, relate, msub, rsub etc + * At 5.1 this has been changed to the "new" format of lhs_module, rhs_module, lhs_subpanel, rhs_subpanel, label + * @return AbstractRelationship + */ + function addFromPost () + { + return $this->implementation->addFromPost () ; + } + + /* + * New function to replace the old MBModule subpanel property - now we obtain the 'subpanels' (actually related modules) from the relationships object + */ + function getRelationshipList () + { + return $this->implementation->getRelationshipList () ; + } + + function get ($relationshipName) + { + return $this->implementation->get ( $relationshipName ) ; + } + + /* + * Deprecated + * Add a relationship to this set + * Original MBRelationships could only support one relationship between this module and any other + */ + /* + function addRelationship ($name , $relatedTo , $relatedSubpanel = 'default' , $mysubpanel = 'default' , $type) + { + $this->implementation->add ( new ManyToManyRelationship ( $name, $this->moduleName, $relatedTo, $mysubpanel, $relatedSubpanel ) ) ; + $this->updateRelationshipVariable () ; + } +*/ + + /* Add a relationship to this set + * Original MBRelationships could only support one relationship between this module and any other + * @param array $rel Relationship definition in the old format (defined by self::oldFormatKeys) + */ + function add ($rel) + { + // convert old format definition to new format + if (! isset ( $rel [ 'lhs_module' ] )) + $rel [ 'lhs_module' ] = $this->moduleName ; + $definition = AbstractRelationships::convertFromOldFormat ( $rel ) ; + if (! isset ( $definition ['relationship_type'])) + $definition ['relationship_type'] = 'many-to-many'; + // get relationship object from RelationshipFactory + $relationship = RelationshipFactory::newRelationship ( $definition ) ; + // add relationship to the set of relationships + $this->implementation->add ( $relationship ) ; + $this->updateRelationshipVariable () ; + return $relationship; + } + + function delete ($name) + { + $this->implementation->delete ( $name ) ; + $this->updateRelationshipVariable () ; + } + + function save () + { + $this->implementation->save () ; + } + + function build ($path) + { + $this->implementation->build () ; + } + + function addInstallDefs (&$installDef) + { + $this->implementation->addInstallDefs ( $installDef ) ; + } + + /* + function load () + { + $this->implementation->load () ; + $this->updateRelationshipVariable () ; + } +*/ + /* + * Transitional function to keep the public relationship variable in sync with the implementation master copy + * We have to do this as various things refer directly to MBRelationship->relationships... + */ + + private function updateRelationshipVariable () + { + foreach ( $this->implementation->getRelationshipList () as $relationshipName ) + { + $rel = $this->implementation->getOldFormat ( $relationshipName ) ; + $this->relationships [ $relationshipName ] = $rel ; + } + } + +} + +?> \ No newline at end of file diff --git a/modules/ModuleBuilder/MB/MBVardefs.php b/modules/ModuleBuilder/MB/MBVardefs.php new file mode 100644 index 00000000..cac86ede --- /dev/null +++ b/modules/ModuleBuilder/MB/MBVardefs.php @@ -0,0 +1,146 @@ +path = $path; + $this->name = $name; + $this->key_name = $key_name; + $this->load(); + } + + function loadTemplate($by_group, $template, $file){ + $module = $this->name; + $table_name = $this->name; + $object_name = $this->key_name; + $_object_name = strtolower($this->key_name); + + // required by the vardef template for team security in SugarObjects + $table_name = strtolower($module); + + if(file_exists($file)){ + include($file); + if($by_group){ + $this->vardefs['fields'] [$template]= $vardefs['fields']; + }else{ + $this->vardefs['fields']= array_merge($this->vardefs['fields'], $vardefs['fields']); + if(!empty($vardefs['relationships'])){ + $this->vardefs['relationships']= array_merge($this->vardefs['relationships'], $vardefs['relationships']); + } + } + } + + } + + function mergeVardefs($by_group=false){ + $this->vardefs = array( + 'fields'=>array(), + 'relationships'=>array(), + ); +// $object_name = $this->key_name; +// $_object_name = strtolower($this->name); + $module_name = $this->name; + $this->loadTemplate($by_group,'basic', MB_TEMPLATES . '/basic/vardefs.php'); + foreach($this->iTemplates as $template=>$val){ + $file = MB_IMPLEMENTS . '/' . $template . '/vardefs.php'; + $this->loadTemplate($by_group,$template, $file); + } + foreach($this->templates as $template=>$val){ + if($template == 'basic')continue; + $file = MB_TEMPLATES . '/' . $template . '/vardefs.php'; + $this->loadTemplate($by_group,$template, $file); + } + + if($by_group){ + $this->vardefs['fields'][$this->name] = $this->vardef['fields']; + }else{ + $this->vardefs['fields'] = array_merge($this->vardefs['fields'], $this->vardef['fields']); + } + } + + function updateVardefs($by_group=false){ + $this->mergeVardefs($by_group); + } + + + function getVardefs(){ + return $this->vardefs; + } + + function getVardef(){ + return $this->vardef; + } + + function addFieldVardef($vardef){ + if(empty($vardef['default']))unset($vardef['default']); + $this->vardef['fields'][$vardef['name']] = $vardef; + } + + function deleteField($field){ + unset($this->vardef['fields'][$field->name]); + } + + function save(){ + $header = file_get_contents('modules/ModuleBuilder/MB/header.php'); + write_array_to_file('vardefs', $this->vardef, $this->path . '/vardefs.php','w', $header); + } + + function build($path){ + $header = file_get_contents('modules/ModuleBuilder/MB/header.php'); + write_array_to_file('dictionary["' . $this->name . '"]', $this->getVardefs(), $path . '/vardefs.php', 'w', $header); + } + function load(){ + $this->vardef = array('fields'=>array(), 'relationships'=>array()); + if(file_exists($this->path . '/vardefs.php')){ + include($this->path. '/vardefs.php'); + $this->vardef = $vardefs; + } + } + + + + + +} +?> \ No newline at end of file diff --git a/modules/ModuleBuilder/MB/ModuleBuilder.php b/modules/ModuleBuilder/MB/ModuleBuilder.php new file mode 100644 index 00000000..325ad65c --- /dev/null +++ b/modules/ModuleBuilder/MB/ModuleBuilder.php @@ -0,0 +1,148 @@ +read () ) + { + if (file_exists ( MB_PACKAGE_PATH . '/' . $e . '/manifest.php' )) + { + $list [] = $e ; + } + } + sort ( $list ) ; // order important as generate_nodes_array in Tree.php later loops over this by foreach to generate the package list + return $list ; + + } + + function getPackage ($name) + { + if (! empty ( $this->packages [ $name ] )) + return $this->packages [ $name ] ; + $this->packages [ $name ] = new MBPackage ( $name ) ; + } + + function getPackageKey ($name) + { + $manifestPath = MB_PACKAGE_PATH . '/' . $name . '/manifest.php' ; + if (file_exists ( $manifestPath )) + { + require( $manifestPath ) ; + if(!empty($manifest)) + return $manifest['key']; + } + return false ; + } + + function &getPackageModule ($package , $module) + { + $this->getPackage ( $package ) ; + $this->packages [ $package ]->getModule ( $module ) ; + return $this->packages [ $package ]->modules [ $module ] ; + } + + function save () + { + $packages = array_keys ( $this->packages ) ; + foreach ( $packages as $package ) + { + $this->packages [ $package ]->save () ; + } + } + + function build () + { + $packages = array_keys ( $this->packages ) ; + foreach ( $packages as $package ) + { + if (count ( $packages ) == 1) + { + $this->packages [ $package ]->build ( true ) ; + } else + { + $this->packages [ $package ]->build ( false ) ; + } + } + } + + function getPackages () + { + if (empty ( $this->packages )) + { + $list = $this->getPackageList () ; + foreach ( $list as $package ) + { + if (! empty ( $this->packages [ $package ] )) + continue ; + $this->packages [ $package ] = new MBPackage ( $package ) ; + } + } + } + + function getNodes () + { + $this->getPackages () ; + $nodes = array ( ) ; + foreach ( array_keys ( $this->packages ) as $name ) + { + $nodes [] = $this->packages [ $name ]->getNodes () ; + } + return $nodes ; + } + +} +?> \ No newline at end of file diff --git a/modules/ModuleBuilder/MB/header.php b/modules/ModuleBuilder/MB/header.php new file mode 100644 index 00000000..5a3f5813 --- /dev/null +++ b/modules/ModuleBuilder/MB/header.php @@ -0,0 +1,36 @@ +$mod_strings['LBL_EDIT_DROPDOWNS'], 'action' =>'module=ModuleBuilder&action=globaldropdown&view_package=studio', 'imageTitle' => 'SPUploadCSS', 'help' => 'editDropDownBtn'); + // $nodes[$mod_strings['LBL_ADD_DROPDOWN']] = array( 'name'=>$mod_strings['LBL_ADD_DROPDOWN'], 'action'=>'module=ModuleBuilder&action=globaldropdown&view_package=studio','imageTitle' => 'SPSync', 'help' => 'addDropDownBtn'); + + $my_list_strings = $app_list_strings; + foreach($my_list_strings as $key=>$value){ + if(!is_array($value)){ + unset($my_list_strings[$key]); + } + } + $dropdowns = array_keys($my_list_strings); + asort($dropdowns); + foreach($dropdowns as $dd) + { + $nodes[$dd] = array( 'name'=>$dd, 'action'=>"module=ModuleBuilder&action=dropdown&view_package=studio&dropdown_name=$dd",'imageTitle' => 'SPSync', 'help' => 'editDropDownBtn'); + } + return $nodes; + } + +} +?> \ No newline at end of file diff --git a/modules/ModuleBuilder/Module/DropDownTree.php b/modules/ModuleBuilder/Module/DropDownTree.php new file mode 100644 index 00000000..8ee1d0fa --- /dev/null +++ b/modules/ModuleBuilder/Module/DropDownTree.php @@ -0,0 +1,53 @@ +tree = new Tree('package_tree'); + $this->tree->id = 'package_tree'; + $this->mb = new DropDownBrowser(); + $this->populateTree($this->mb->getNodes(), $this->tree); + } + + function getName(){ + return translate('LBL_SECTION_PACKAGES'); + } +} +?> \ No newline at end of file diff --git a/modules/ModuleBuilder/Module/MainTree.php b/modules/ModuleBuilder/Module/MainTree.php new file mode 100644 index 00000000..d0c5edf5 --- /dev/null +++ b/modules/ModuleBuilder/Module/MainTree.php @@ -0,0 +1,48 @@ +tree = new Tree('package_tree'); + $this->tree->id = 'package_tree'; + $this->mb = new StudioBrowser(); + $this->populateTree(array(), $this->tree); + } + +} +?> \ No newline at end of file diff --git a/modules/ModuleBuilder/Module/StudioBrowser.php b/modules/ModuleBuilder/Module/StudioBrowser.php new file mode 100644 index 00000000..5683e727 --- /dev/null +++ b/modules/ModuleBuilder/Module/StudioBrowser.php @@ -0,0 +1,86 @@ +read()){ + if(substr($e, 0, 1) == '.' || !is_dir('modules/' . $e))continue; + if(file_exists('modules/' . $e . '/metadata/studio.php') && isset($GLOBALS [ 'beanList' ][$e]) && (in_array($e, $access) || is_admin($current_user))) // installed modules must also exist in the beanList + { + $this->modules[$e] = StudioModuleFactory::getStudioModule( $e ) ; + } + } + } + + function loadRelatableModules(){ + $d = dir('modules'); + while($e = $d->read()){ + if(substr($e, 0, 1) == '.' || !is_dir('modules/' . $e))continue; + if(file_exists('modules/' . $e . '/metadata/studio.php') && isset($GLOBALS [ 'beanList' ][$e])) // installed modules must also exist in the beanList + { + $this->modules[$e] = StudioModuleFactory::getStudioModule( $e ) ; + } + } + } + + function getNodes(){ + $this->loadModules(); + $nodes = array(); + foreach($this->modules as $module){ + $nodes[$module->name] = $module->getNodes(); + } + uksort($nodes,'cmp'); // bug 15103 - order is important - this array is later looped over by foreach to generate the module list + return $nodes; + } + + + + + +} +?> \ No newline at end of file diff --git a/modules/ModuleBuilder/Module/StudioModule.php b/modules/ModuleBuilder/Module/StudioModule.php new file mode 100644 index 00000000..8c80dc5a --- /dev/null +++ b/modules/ModuleBuilder/Module/StudioModule.php @@ -0,0 +1,430 @@ +sources = array ( 'editviewdefs.php' => array ( 'name' => translate ('LBL_EDITVIEW') , 'type' => MB_EDITVIEW , 'image' => 'EditView' ) , + 'detailviewdefs.php' => array ( 'name' => translate('LBL_DETAILVIEW') , 'type' => MB_DETAILVIEW , 'image' => 'DetailView' ) , + 'listviewdefs.php' => array ( 'name' => translate('LBL_LISTVIEW') , 'type' => MB_LISTVIEW , 'image' => 'ListView' ) ) ; + + $moduleNames = array_change_key_case ( $GLOBALS [ 'app_list_strings' ] [ 'moduleList' ] ) ; + $this->name = isset ( $moduleNames [ strtolower ( $module ) ] ) ? $moduleNames [ strtolower ( $module ) ] : strtolower ( $module ) ; + $this->module = $module ; + $class = $GLOBALS [ 'beanList' ] [ $this->module ] ; + require_once $GLOBALS [ 'beanFiles' ] [ $class ] ; + $this->seed = new $class ( ) ; + $this->fields = $this->seed->field_defs ; + //$GLOBALS['log']->debug ( get_class($this)."->__construct($module): ".print_r($this->fields,true) ) ; + } + + /* + * Gets the name of this module. Some modules have naming inconsistencies such as Bug Tracker and Bugs which causes warnings in Relationships + * Added to resolve bug #20257 + */ + function getModuleName() + { + $modules_with_odd_names = array( + 'Bug Tracker'=>'Bugs' + ); + if ( isset ( $modules_with_odd_names [ $this->name ] ) ) + return ( $modules_with_odd_names [ $this->name ] ) ; + + return $this->name; + } + + /* + * Attempt to determine the type of a module, for example 'basic' or 'company' + * These types are defined by the SugarObject Templates in /include/SugarObjects/templates + * Custom modules extend one of these standard SugarObject types, so the type can be determined from their parent + * Standard module types can be determined simply from the module name - 'bugs' for example is of type 'issue' + * If all else fails, fall back on type 'basic'... + * @return string Module's type + */ + function getType () + { + // first, get a list of a possible parent types + $templates = array () ; + $d = dir ( 'include/SugarObjects/templates' ) ; + while ( $filename = $d->read() ) + { + if ( substr($filename,0,1) != '.' ) + $templates [ strtolower ( $filename) ] = strtolower ( $filename ) ; + } + + // If a custom module, then its type is determined by the parent SugarObject that it extends + $type = $GLOBALS [ 'beanList' ] [ $this->module ] ; + require_once $GLOBALS [ 'beanFiles' ] [ $type ] ; + + do + { + $seed = new $type () ; + $type = get_parent_class ($seed) ; + } while ( ! in_array ( strtolower ( $type ) , $templates ) && $type != 'SugarBean' ) ; + + if ( $type != 'SugarBean' ) + { + return strtolower ( $type ) ; + } + + // If a standard module then just look up its type - type is implicit for standard modules. Perhaps one day we will make it explicit, just as we have done for custom modules... + $types = array ( + 'Accounts' => 'company' , + 'Bugs' => 'issue' , + 'Cases' => 'issue' , + 'Contacts' => 'person' , + 'Documents' => 'file' , + 'Leads' => 'person' , + 'Opportunities' => 'sale' + ) ; + if ( isset ( $types [ $this->module ] ) ) + return $types [ $this->module ] ; + + return "basic" ; + } + + /* + * Return the fields for this module as sourced from the SugarBean + * @return Array of fields + */ + + function getFields () + { + return $this->fields ; + } + + function getNodes () + { + return array ( 'name' => $this->name , 'module' => $this->module , 'type' => 'StudioModule' , 'action' => "module=ModuleBuilder&action=wizard&view_module={$this->module}" , 'children' => $this->getModule() ) ; + } + + function getModule () + { + $sources = array ( translate('LBL_LABELS') => array ( 'action' => "module=ModuleBuilder&action=editLabels&view_module={$this->module}" , 'imageTitle' => 'Labels' , 'help' => 'labelsBtn' ) , + translate('LBL_FIELDS') => array ( 'action' => "module=ModuleBuilder&action=modulefields&view_package=studio&view_module={$this->module}" , 'imageTitle' => 'Fields' , 'help' => 'fieldsBtn' ) , + translate('LBL_RELATIONSHIPS') => array ( 'action' => "get_tpl=true&module=ModuleBuilder&action=relationships&view_module={$this->module}" , 'imageTitle' => 'Relationships' , 'help' => 'relationshipsBtn' ) , + translate('LBL_LAYOUTS') => array ( 'children' => 'getLayouts' , 'action' => "module=ModuleBuilder&action=wizard&view=layouts&view_module={$this->module}" , 'imageTitle' => 'Layouts' , 'help' => 'layoutsBtn' ) , + translate('LBL_SUBPANELS') => array ( 'children' => 'getSubpanels' , 'action' => "module=ModuleBuilder&action=wizard&view=subpanels&view_module={$this->module}" , 'imageTitle' => 'Subpanels' , 'help' => 'subpanelsBtn' ) ) ; + + $nodes = array () ; + foreach ( $sources as $source => $def ) + { + $nodes [ $source ] = $def ; + $nodes [ $source ] [ 'name' ] = translate ( $source ) ; + if ( isset ( $def [ 'children' ] ) ) + { + $childNodes = $this->$def [ 'children' ] () ; + if ( !empty ( $childNodes ) ) + { + $nodes [ $source ] [ 'type' ] = 'Folder' ; + $nodes [ $source ] [ 'children' ] = $childNodes ; + } + else + unset ( $nodes [ $source ] ) ; + } + } + + return $nodes ; + } + + function getViews() { + $views = array () ; + foreach ( $this->sources as $file => $def ) + { + if (file_exists ( "modules/{$this->module}/metadata/$file" )) + { + $views [ str_replace ( '.php', '' , $file) ] = $def ; + } + } + return $views; + } + + function getLayouts() + { + $views = $this->getViews(); + + // Now add in the QuickCreates - quickcreatedefs can be created by Studio from editviewdefs if they are absent, so just add them in regardless of whether the quickcreatedefs file exists + + $hideQuickCreateForModules = array ( 'kbdocuments' , 'projecttask' , + 'campaigns' + ) ; + // Some modules should not have a QuickCreate form at all, so do not add them to the list + if (! in_array ( strtolower ( $this->module ), $hideQuickCreateForModules )) + $views [ 'quickcreatedefs' ] = array ( 'name' => translate('LBL_QUICKCREATE') , 'type' => MB_QUICKCREATE , 'image' => 'QuickCreate' ) ; + + $layouts = array ( ) ; + foreach ( $views as $def ) + { + $layouts [ $def['name'] ] = array ( 'name' => $def['name'] , 'action' => "module=ModuleBuilder&action=editLayout&view={$def['type']}&view_module={$this->module}" , 'imageTitle' => $def['image'] , 'help' => "viewBtn{$def['type']}" , 'size' => '48' ) ; + } + + if($this->isValidDashletModule($this->module)){ + $dashlets = array( ); + $dashlets [] = array('name' => translate('LBL_DASHLETLISTVIEW') , 'type' => 'dashlet' , 'action' => 'module=ModuleBuilder&action=editLayout&view=dashlet&view_module=' . $this->module ); + $dashlets [] = array('name' => translate('LBL_DASHLETSEARCHVIEW') , 'type' => 'dashletsearch' , 'action' => 'module=ModuleBuilder&action=editLayout&view=dashletsearch&view_module=' . $this->module ); + $layouts [ translate('LBL_DASHLET') ] = array ( 'name' => translate('LBL_DASHLET') , 'type' => 'Folder', 'children' => $dashlets, 'imageTitle' => 'Dashlet', 'action' => 'module=ModuleBuilder&action=wizard&view=dashlet&view_module=' . $this->module); + } + + //For popup tree node + $popups = array( ); + $popups [] = array('name' => translate('LBL_POPUPLISTVIEW') , 'type' => 'popuplistview' , 'action' => 'module=ModuleBuilder&action=editLayout&view=popuplist&view_module=' . $this->module ); + $popups [] = array('name' => translate('LBL_POPUPSEARCH') , 'type' => 'popupsearch' , 'action' => 'module=ModuleBuilder&action=editLayout&view=popupsearch&view_module=' . $this->module ); + $layouts [ translate('LBL_POPUP') ] = array ( 'name' => translate('LBL_POPUP') , 'type' => 'Folder', 'children' => $popups, 'imageTitle' => 'Popup', 'imageName' => 'icon_Popup.gif', 'action' => 'module=ModuleBuilder&action=wizard&view=popup&view_module=' . $this->module); + + $nodes = $this->getSearch () ; + if ( !empty ( $nodes ) ) + { + $layouts [ translate('LBL_SEARCH') ] = array ( 'name' => translate('LBL_SEARCH') , 'type' => 'Folder' , 'children' => $nodes , 'action' => "module=ModuleBuilder&action=wizard&view=search&view_module={$this->module}" , 'imageTitle' => 'SearchForm' , 'help' => 'searchBtn' , 'size' => '48') ; + } + + return $layouts ; + + } + + function isValidDashletModule($moduleName){ + $fileName = "My{$moduleName}Dashlet"; + $customFileName = "{$moduleName}Dashlet"; + if (file_exists ( "modules/{$moduleName}/Dashlets/{$fileName}/{$fileName}.php" ) + || file_exists ( "custom/modules/{$moduleName}/Dashlets/{$fileName}/{$fileName}.php" ) + || file_exists ( "modules/{$moduleName}/Dashlets/{$customFileName}/{$customFileName}.php" ) + || file_exists ( "custom/modules/{$moduleName}/Dashlets/{$customFileName}/{$customFileName}.php" )) + { + return true; + } + return false; + } + + + function getSearch () + { + require_once ('modules/ModuleBuilder/parsers/views/SearchViewMetaDataParser.php') ; + + $nodes = array () ; + foreach ( array ( MB_BASICSEARCH => 'LBL_BASIC_SEARCH' , MB_ADVANCEDSEARCH => 'LBL_ADVANCED_SEARCH' ) as $view => $label ) + { + try + { + $parser = new SearchViewMetaDataParser ( $view , $this->module ) ; + $title = translate ( $label ) ; + if($label == 'LBL_BASIC_SEARCH'){ + $name = 'BasicSearch'; + }elseif($label == 'LBL_ADVANCED_SEARCH'){ + $name = 'AdvancedSearch'; + }else{ + $name = str_replace ( ' ', '', $title ) ; + } + $nodes [ $title ] = array ( 'name' => $title , 'action' => "module=ModuleBuilder&action=editLayout&view={$view}&view_module={$this->module}" , 'imageTitle' => $title , 'imageName' => $name , 'help' => "{$name}Btn" , 'size' => '48' ) ; + } + catch ( Exception $e ) + { + $GLOBALS [ 'log' ]->info( 'No search layout : '. $e->getMessage() ) ; + } + } + + return $nodes ; + } + + /* + * Return an object containing all the relationships participated in by this module + * @return AbstractRelationships Set of relationships + */ + function getRelationships () + { + return new DeployedRelationships ( $this->module ) ; + } + + + /** + * Gets a list of subpanels used by the current module + */ + function getSubpanels () + { + if(!empty($GLOBALS['current_user']) && empty($GLOBALS['modListHeader'])) + $GLOBALS['modListHeader'] = query_module_access_list($GLOBALS['current_user']); + + require_once ('include/SubPanel/SubPanel.php') ; + + $nodes = array ( ) ; + + $GLOBALS [ 'log' ]->debug ( "StudioModule->getSubpanels(): getting subpanels for " . $this->module ) ; + + foreach ( SubPanel::getModuleSubpanels ( $this->module ) as $name => $label ) + { + if ($name == 'users') + continue ; + $subname = sugar_ucfirst ( (! empty ( $label )) ? translate ( $label, $this->module ) : $name ) ; + $nodes [ $subname ] = array ( + 'name' => $name , + 'label' => $subname , + 'action' => "module=ModuleBuilder&action=editLayout&view=ListView&view_module={$this->module}&subpanel={$name}&subpanelLabel={$subname}" , + 'imageTitle' => $subname , + 'imageName' => 'icon_' . ucfirst($name) . '_32', + 'altImageName' => 'Subpanels', + 'size' => '48' + ) ; + } + + return $nodes ; + + } + + /** + * gets a list of subpanels provided to other modules + * + * + */ + function getProvidedSubpanels () + { + require_once 'modules/ModuleBuilder/parsers/relationships/AbstractRelationships.php' ; + $this->providedSubpanels = array () ; + $subpanelDir = 'modules/' . $this->module . '/metadata/subpanels/' ; + foreach(array($subpanelDir, "custom/$subpanelDir") as $dir) + { + if (is_dir ( $dir )) + { + foreach(scandir($dir) as $fileName) + { + // sanity check to confirm that this is a usable subpanel... + if (substr ( $fileName, 0, 1 ) != '.' && substr ( strtolower($fileName), -4 ) == ".php" + && AbstractRelationships::validSubpanel ( "$dir/$fileName" )) + { + $subname = str_replace ( '.php', '', $fileName ) ; + $this->providedSubpanels [ $subname ] = $subname ; + } + } + } + } + + return $this->providedSubpanels; + } + + + function getParentModulesOfSubpanel($subpanel){ + global $moduleList, $beanFiles, $beanList, $module; + + //use tab controller function to get module list with named keys + require_once("modules/MySettings/TabController.php"); + require_once("include/SubPanel/SubPanelDefinitions.php"); + $modules_to_check = TabController::get_key_array($moduleList); + + //change case to match subpanel processing later on + $modules_to_check = array_change_key_case($modules_to_check); + + $spd = ''; + $spd_arr = array(); + //iterate through modules and build subpanel array + foreach($modules_to_check as $mod_name){ + + //skip if module name is not in bean list, otherwise get the bean class name + if(!isset($beanList[$mod_name])) continue; + $class = $beanList[$mod_name]; + + //skip if class name is not in file list, otherwise require the bean file and create new class + if(!isset($beanFiles[$class]) || !file_exists($beanFiles[$class])) continue; + + //retrieve subpanels for this bean + require_once($beanFiles[$class]); + $bean_class = new $class(); + + //create new subpanel definition instance and get list of tabs + $spd = new SubPanelDefinitions($bean_class) ; + if ( isset($spd->layout_defs['subpanel_setup'][strtolower($subpanel)]['module']) ){ + $spd_arr[] = $mod_name; + } + } + return $spd_arr; + } + + function removeFieldFromLayouts ( $fieldName ) + { + require_once("modules/ModuleBuilder/parsers/ParserFactory.php"); + $GLOBALS [ 'log' ]->info ( get_class ( $this ) . "->removeFieldFromLayouts($fieldName)" ) ; + $sources = $this->getViewMetadataSources(); + $sources[] = array('type' => MB_BASICSEARCH); + $sources[] = array('type' => MB_ADVANCEDSEARCH); + + $GLOBALS [ 'log' ]->debug ( print_r( $sources,true) ) ; + foreach ( $sources as $name => $defs ) + { + //If this module type doesn't support a given metadata type, we will get an exception from getParser() + try { + $parser = ParserFactory::getParser( $defs [ 'type' ] , $this->module ) ; + if ($parser->removeField ( $fieldName ) ) + $parser->handleSave(false) ; // don't populate from $_REQUEST, just save as is... + } catch(Exception $e){} + } + + //Remove the fields in subpanel + $data = $this->getParentModulesOfSubpanel($this->module); + foreach($data as $parentModule){ + //If this module type doesn't support a given metadata type, we will get an exception from getParser() + try { + $parser = ParserFactory::getParser( MB_LISTVIEW , $parentModule, null , $this->module) ; + if ($parser->removeField ( $fieldName ) ) + $parser->handleSave(false) ; + } catch(Exception $e){} + } + } + + + + public function getViewMetadataSources() { + $sources = $this->getViews(); + $sources[] = array('type' => MB_BASICSEARCH); + $sources[] = array('type' => MB_ADVANCEDSEARCH); + $sources[] = array('type' => MB_DASHLET); + $sources[] = array('type' => MB_DASHLETSEARCH); + $sources[] = array('type' => MB_POPUPLIST); + $sources[] = array('type' => MB_QUICKCREATE); + + return $sources; + } + + + +} +?> \ No newline at end of file diff --git a/modules/ModuleBuilder/Module/StudioModuleFactory.php b/modules/ModuleBuilder/Module/StudioModuleFactory.php new file mode 100644 index 00000000..8e02dd40 --- /dev/null +++ b/modules/ModuleBuilder/Module/StudioModuleFactory.php @@ -0,0 +1,55 @@ + \ No newline at end of file diff --git a/modules/ModuleBuilder/Module/StudioTree.php b/modules/ModuleBuilder/Module/StudioTree.php new file mode 100644 index 00000000..703c05fd --- /dev/null +++ b/modules/ModuleBuilder/Module/StudioTree.php @@ -0,0 +1,52 @@ +tree = new Tree('package_tree'); + $this->tree->id = 'package_tree'; + $this->mb = new StudioBrowser(); + $this->populateTree($this->mb->getNodes(), $this->tree); + } + + function getName(){ + return translate('LBL_SECTION_MODULES'); + } + +} +?> \ No newline at end of file diff --git a/modules/ModuleBuilder/action_view_map.php b/modules/ModuleBuilder/action_view_map.php new file mode 100644 index 00000000..f5d79475 --- /dev/null +++ b/modules/ModuleBuilder/action_view_map.php @@ -0,0 +1,75 @@ +' => '', + $action_view_map = array( + 'index' => 'main', + 'module'=>'module', + 'modulefields'=>'modulefields', + 'modulelabels'=>'modulelabels', + 'relationships'=>'relationships', + 'relationship'=>'relationship', + 'resetmodule'=>'resetmodule', + 'modulefield'=>'modulefield', + 'displaydeploy'=>'displaydeploy', + 'package'=>'package', + 'dropdown'=>'dropdown', + 'dropdowns'=>'dropdowns', + 'detailview' => 'detail', + 'editview' => 'edit', + 'popup' => 'popup', + 'home'=>'home', + 'visibilityeditor' => 'visibilityeditor', + 'exportcustomizations'=>'exportcustomizations', + + ); + // add those we need from the global action_view_map + $action_view_map['dc'] = 'dc'; + $action_view_map['dcajax'] = 'dcajax'; + $action_view_map['quick'] = 'quick'; + $action_view_map['quickcreate'] = 'quickcreate'; + $action_view_map['spot'] = 'spot'; + $action_view_map['inlinefield'] = 'inlinefield'; + $action_view_map['inlinefieldsave'] = 'inlinefieldsave'; + $action_view_map['pluginlist'] = 'plugins'; + $action_view_map['downloadplugin'] = 'downloadplugin'; +?> diff --git a/modules/ModuleBuilder/controller.php b/modules/ModuleBuilder/controller.php new file mode 100644 index 00000000..172fa3d8 --- /dev/null +++ b/modules/ModuleBuilder/controller.php @@ -0,0 +1,782 @@ +info ( get_class($this).":" ) ; + global $current_user; + $access = get_admin_modules_for_user($current_user); + if(is_admin($current_user) || (is_admin_for_any_module($current_user) && !isset($_REQUEST['view_module']) && (isset($_REQUEST['action']) && $_REQUEST['action'] != 'package'))|| + (isset($_REQUEST['view_module']) && (in_array($_REQUEST['view_module'], $access)|| empty($_REQUEST['view_module']))) || + (isset($_REQUEST['type']) && (($_REQUEST['type']=='dropdowns' && is_admin_for_any_module($current_user))|| + ($_REQUEST['type']=='studio' && displayStudioForCurrentUser() == true)))) + { + $this->hasAccess = true; + } + else + { + $this->hasAccess = false; + } + parent::process(); + } + + + function action_editLayout () + { + switch ( strtolower ( $_REQUEST [ 'view' ] )) + { + case MB_EDITVIEW : + case MB_DETAILVIEW : + case MB_QUICKCREATE : + $this->view = 'layoutView' ; + break ; + case MB_LISTVIEW : + $this->view = 'listView' ; + break ; + case MB_BASICSEARCH : + case MB_ADVANCEDSEARCH : + $this->view = 'searchView' ; + break ; + case MB_DASHLET : + case MB_DASHLETSEARCH : + $this->view = 'dashlet' ; + break ; + case MB_POPUPLIST : + case MB_POPUPSEARCH : + $this->view = 'popupview' ; + break ; + default : + $GLOBALS [ 'log' ]->fatal ( 'Action = editLayout with unknown view=' . $_REQUEST [ 'view' ] ) ; + } + } + + + function action_ViewTree () + { + require_once ('modules/ModuleBuilder/MB/AjaxCompose.php') ; + switch ( $_REQUEST [ 'tree' ]) + { + case 'ModuleBuilder' : + require_once ('modules/ModuleBuilder/MB/MBPackageTree.php') ; + $mbt = new MBPackageTree ( ) ; + break ; + case 'Studio' : + require_once ('modules/ModuleBuilder/Module/StudioTree.php') ; + $mbt = new StudioTree ( ) ; + } + $ajax = new AjaxCompose ( ) ; + $ajax->addSection ( 'west', $mbt->getName (), $mbt->fetchNodes () ) ; + echo $ajax->getJavascript () ; + + sugar_cleanup ( true ) ; + + } + + function action_SavePackage () + { + $mb = new ModuleBuilder ( ) ; + $load = (! empty ( $_REQUEST [ 'original_name' ] )) ? $_REQUEST [ 'original_name' ] : $_REQUEST [ 'name' ] ; + if (! empty ( $load )) + { + $mb->getPackage ( $load ) ; + + if (! empty ( $_REQUEST [ 'duplicate' ] )) + { + $result = $mb->packages [ $load ]->copy ( $_REQUEST [ 'name' ] ) ; + $load = $mb->packages [ $load ]->name ; + $mb->getPackage ( $load ) ; + } + $mb->packages [ $load ]->populateFromPost () ; + $mb->packages [ $load ]->loadModules () ; + $mb->save () ; + if (! empty ( $_REQUEST [ 'original_name' ] ) && $_REQUEST [ 'original_name' ] != $_REQUEST [ 'name' ]) + { + if (! $mb->packages [ $load ]->rename ( $_REQUEST [ 'name' ] )) + { + $mb->packages [ $load ]->name = $_REQUEST [ 'original_name' ] ; + $_REQUEST [ 'name' ] = $_REQUEST [ 'original_name' ] ; + } + } + $_REQUEST [ 'package' ] = $_REQUEST [ 'name' ] ; + $this->view = 'package' ; + } + } + + function action_BuildPackage () + { + $mb = new ModuleBuilder ( ) ; + $load = $_REQUEST [ 'name' ] ; + if (! empty ( $load )) + { + $mb->getPackage ( $load ) ; + $mb->packages [ $load ]->build () ; + } + } + + function action_DeployPackage () + { + if(defined('TEMPLATE_URL')){ + sugar_cache_reset(); + SugarTemplateUtilities::disableCache(); + } + + $mb = new ModuleBuilder ( ) ; + $load = $_REQUEST [ 'package' ] ; + $message = $GLOBALS [ 'mod_strings' ] [ 'LBL_MODULE_DEPLOYED' ] ; + if (! empty ( $load )) + { + $zip = $mb->getPackage ( $load ) ; + require_once ('ModuleInstall/PackageManager/PackageManager.php') ; + $pm = new PackageManager ( ) ; + $info = $mb->packages [ $load ]->build ( false ) ; + mkdir_recursive ( $GLOBALS [ 'sugar_config' ] [ 'cache_dir' ] . '/upload/upgrades/module/') ; + rename ( $info [ 'zip' ], $GLOBALS [ 'sugar_config' ] [ 'cache_dir' ] . '/' . 'upload/upgrades/module/' . $info [ 'name' ] . '.zip' ) ; + copy ( $info [ 'manifest' ], $GLOBALS [ 'sugar_config' ] [ 'cache_dir' ] . '/' . 'upload/upgrades/module/' . $info [ 'name' ] . '-manifest.php' ) ; + $_REQUEST [ 'install_file' ] = $GLOBALS [ 'sugar_config' ] [ 'cache_dir' ] . '/' . 'upload/upgrades/module/' . $info [ 'name' ] . '.zip' ; + $GLOBALS [ 'mi_remove_tables' ] = false ; + $pm->performUninstall ( $load ) ; + //#23177 , js cache clear + clearAllJsAndJsLangFilesWithoutOutput(); + //#30747, clear the cache in memory + $cache_key = 'app_list_strings.'.$GLOBALS['current_language']; + sugar_cache_clear($cache_key ); + sugar_cache_reset(); + //clear end + $pm->performInstall ( $_REQUEST [ 'install_file' ] , true) ; + + //clear the unified_search_module.php file + require_once('modules/Home/UnifiedSearchAdvanced.php'); + UnifiedSearchAdvanced::unlinkUnifiedSearchModulesFile(); + } + echo 'complete' ; + + } + + function action_ExportPackage () + { + $mb = new ModuleBuilder ( ) ; + $load = $_REQUEST [ 'name' ] ; + $author = $_REQUEST [ 'author' ] ; + $description = $_REQUEST [ 'description' ] ; + $readme = $_REQUEST [ 'readme' ] ; + if (! empty ( $load )) + { + $mb->getPackage ( $load ) ; + $mb->packages [ $load ]->author = $author ; + $mb->packages [ $load ]->description = $description ; + $mb->packages [ $load ]->exportProject () ; + $mb->packages [ $load ]->readme = $readme ; + } + } + + function action_DeletePackage () + { + $mb = new ModuleBuilder ( ) ; + $mb->getPackage ( $_REQUEST [ 'package' ] ) ; + $mb->packages [ $_REQUEST [ 'package' ] ]->delete () ; + $this->view = 'deletepackage' ; + } + + function action_SaveModule () + { + $mb = new ModuleBuilder ( ) ; + $load = (! empty ( $_REQUEST [ 'original_name' ] )) ? $_REQUEST [ 'original_name' ] : $_REQUEST [ 'name' ] ; + if (! empty ( $load )) + { + $mb->getPackage ( $_REQUEST [ 'package' ] ) ; + $mb->packages [ $_REQUEST [ 'package' ] ]->getModule ( $load ) ; + $module = & $mb->packages [ $_REQUEST [ 'package' ] ]->modules [ $load ] ; + $module->populateFromPost () ; + $mb->save () ; + if (! empty ( $_REQUEST [ 'duplicate' ] )) + { + $module->copy ( $_REQUEST [ 'name' ] ) ; + } else if (! empty ( $_REQUEST [ 'original_name' ] ) && $_REQUEST [ 'original_name' ] != $_REQUEST [ 'name' ]) + { + if (! $module->rename ( $_REQUEST [ 'name' ] )) + { + $module->name = $_REQUEST [ 'original_name' ] ; + $_REQUEST [ 'name' ] = $_REQUEST [ 'original_name' ] ; + } + } + + $_REQUEST [ 'view_package' ] = $_REQUEST [ 'package' ] ; + $_REQUEST [ 'view_module' ] = $module->name ; + $this->view = 'module' ; + } + } + + function action_DeleteModule () + { + $mb = new ModuleBuilder ( ) ; + $module = & $mb->getPackageModule ( $_REQUEST [ 'package' ], $_REQUEST [ 'view_module' ] ) ; + $module->delete () ; + $this->view = 'package' ; + } + + function action_saveLabels () + { + require_once 'modules/ModuleBuilder/parsers/parser.label.php' ; + $parser = new ParserLabel ( $_REQUEST['view_module'] , isset ( $_REQUEST [ 'view_package' ] ) ? $_REQUEST [ 'view_package' ] : null ) ; + $parser->handleSave ( $_REQUEST, $_REQUEST [ 'selected_lang' ] ) ; + if (isset ( $_REQUEST [ 'view_package' ] )) //MODULE BUILDER + { + $this->view = 'modulelabels' ; + } else //STUDIO + { + $this->view = isset ( $_REQUEST [ 'view' ] ) ? 'edit' : 'labels' ; // detect if we are being called by the LayoutEditor rather than the LabelEditor (set in view.layoutlabel.php) + } + } + + function action_SaveLabel () + { + if (! empty ( $_REQUEST [ 'view_module' ] ) && !empty($_REQUEST [ 'labelValue' ])) + { + $_REQUEST [ "label_" . $_REQUEST [ 'label' ] ] = $_REQUEST [ 'labelValue' ] ; + require_once 'modules/ModuleBuilder/parsers/parser.label.php' ; + $parser = new ParserLabel ( $_REQUEST['view_module'] , isset ( $_REQUEST [ 'view_package' ] ) ? $_REQUEST [ 'view_package' ] : null ) ; + $parser->handleSave ( $_REQUEST, $GLOBALS [ 'current_language' ] ) ; + + } + $this->view = 'modulefields' ; + } + + function action_ExportCustom () + { + $modules = $_REQUEST [ 'modules' ] ; + $name = $_REQUEST [ 'name' ] ; + $author = $_REQUEST [ 'author' ] ; + $description = $_REQUEST [ 'description' ] ; + ob_clean () ; + if (! empty ( $modules ) && ! empty ( $name )) + { + require_once ('modules/ModuleBuilder/MB/ModuleBuilder.php') ; + $mb = new MBPackage ( $name ) ; + $mb->author = $author ; + $mb->description = $description ; + $mb->exportCustom ( $modules, true, true ) ; + } + } + + function action_SaveField () + { + require_once ('modules/DynamicFields/FieldCases.php') ; + $field = get_widget ( $_REQUEST [ 'type' ] ) ; + $_REQUEST [ 'name' ] = trim ( $_REQUEST [ 'name' ] ) ; + + $field->populateFromPost () ; + + if (!isset ( $_REQUEST [ 'view_package' ] )) + { + require_once ('modules/DynamicFields/DynamicField.php') ; + if (! empty ( $_REQUEST [ 'view_module' ] )) + { + $module = $_REQUEST [ 'view_module' ] ; + + $bean = loadBean($module); + if(!empty($bean)) + { + $field_defs = $bean->field_defs; + if(isset($field_defs[$field->name. '_c'])) + { + $GLOBALS['log']->error($GLOBALS['mod_strings']['ERROR_ALREADY_EXISTS'] . '[' . $field->name . ']'); + sugar_die($GLOBALS['mod_strings']['ERROR_ALREADY_EXISTS']); + } + } + + $df = new DynamicField ( $module ) ; + $class_name = $GLOBALS [ 'beanList' ] [ $module ] ; + require_once ($GLOBALS [ 'beanFiles' ] [ $class_name ]) ; + $mod = new $class_name ( ) ; + $df->setup ( $mod ) ; + + $field->save ( $df ) ; + $this->action_SaveLabel () ; + include_once ('modules/Administration/QuickRepairAndRebuild.php') ; + global $mod_strings; + $mod_strings['LBL_ALL_MODULES'] = 'all_modules'; + $repair = new RepairAndClear(); + $repair->repairAndClearAll(array('rebuildExtensions', 'clearVardefs', 'clearTpls'), array($class_name), true, false); + //#28707 ,clear all the js files in cache + $repair->module_list = array(); + $repair->clearJsFiles(); + } + } else + { + $mb = new ModuleBuilder ( ) ; + $module = & $mb->getPackageModule ( $_REQUEST [ 'view_package' ], $_REQUEST [ 'view_module' ] ) ; + $field->save ( $module ) ; + $module->mbvardefs->save () ; + // get the module again to refresh the labels we might have saved with the $field->save (e.g., for address fields) + $module = & $mb->getPackageModule ( $_REQUEST [ 'view_package' ], $_REQUEST [ 'view_module' ] ) ; + if (isset ( $_REQUEST [ 'label' ] ) && isset ( $_REQUEST [ 'labelValue' ] )) + $module->setLabel ( $GLOBALS [ 'current_language' ], $_REQUEST [ 'label' ], $_REQUEST [ 'labelValue' ] ) ; + $module->save(); + } + $this->view = 'modulefields' ; + } + + function action_saveSugarField () + { + global $mod_strings; + require_once ('modules/DynamicFields/FieldCases.php') ; + $field = get_widget ( $_REQUEST [ 'type' ] ) ; + $_REQUEST [ 'name' ] = trim ( $_POST [ 'name' ] ) ; + + $field->populateFromPost () ; + require_once ('modules/ModuleBuilder/parsers/StandardField.php') ; + $module = $_REQUEST [ 'view_module' ] ; + $df = new StandardField ( $module ) ; + $class_name = $GLOBALS [ 'beanList' ] [ $module ] ; + require_once ($GLOBALS [ 'beanFiles' ] [ $class_name ]) ; + $mod = new $class_name ( ) ; + $df->setup ( $mod ) ; + + $field->module = $mod; + $field->save ( $df ) ; + $this->action_SaveLabel () ; + + $MBmodStrings = $mod_strings; + $GLOBALS [ 'mod_strings' ] = return_module_language ( '', 'Administration' ) ; + + include_once ('modules/Administration/QuickRepairAndRebuild.php') ; + $GLOBALS [ 'mod_strings' ]['LBL_ALL_MODULES'] = 'all_modules'; + $_REQUEST['execute_sql'] = true; + + $repair = new RepairAndClear(); + $repair->repairAndClearAll(array('rebuildExtensions', 'clearVardefs', 'clearTpls'), array($class_name), true, false); + //#28707 ,clear all the js files in cache + $repair->module_list = array(); + $repair->clearJsFiles(); + + + // now clear the cache so that the results are immediately visible + include_once ('include/TemplateHandler/TemplateHandler.php') ; + TemplateHandler::clearCache ( $module ) ; + + $GLOBALS [ 'mod_strings' ] = $MBmodStrings; + } + + function action_RefreshField () + { + require_once ('modules/DynamicFields/FieldCases.php') ; + $field = get_widget ( $_POST [ 'type' ] ) ; + $field->populateFromPost () ; + $this->view = 'modulefield' ; + } + + function action_saveVisibility () + { + $packageName = (isset ( $_REQUEST [ 'view_package' ] ) && (strtolower($_REQUEST['view_package']) != 'studio')) ? $_REQUEST [ 'view_package' ] : null ; + require_once 'modules/ModuleBuilder/parsers/ParserFactory.php' ; + $parser = ParserFactory::getParser ( MB_VISIBILITY, $_REQUEST [ 'view_module' ], $packageName ) ; + + $json = getJSONobj(); + $visibility_grid = $json->decode(html_entity_decode(rawurldecode($_REQUEST [ 'visibility_grid' ]), ENT_QUOTES) ); + $parser->saveVisibility ( $_REQUEST [ 'fieldname' ] , $_REQUEST [ 'trigger' ] , $visibility_grid ) ; + + echo $json->encode(array( "visibility_editor_{$_REQUEST['fieldname']}" => array("action" => "deactivate"))); + } + + function action_SaveRelationshipLabel (){ + $selected_lang = (!empty($_REQUEST['relationship_lang'])?$_REQUEST['relationship_lang']:$_SESSION['authenticated_user_language']); + if (empty($_REQUEST [ 'view_package' ])){ + require_once 'modules/ModuleBuilder/parsers/relationships/DeployedRelationships.php' ; + $relationships = new DeployedRelationships ( $_REQUEST [ 'view_module' ] ) ; + if (! empty ( $_REQUEST [ 'relationship_name' ] )) + { + if ($relationship = $relationships->get ( $_REQUEST [ 'relationship_name' ] )){ + $metadata = $relationship->buildLabels(true); + require_once 'modules/ModuleBuilder/parsers/parser.label.php' ; + $parser = new ParserLabel ( $_REQUEST['view_module'] ) ; + $parser->handleSaveRelationshipLabels ( $metadata, $selected_lang ) ; + } + } + } + else { + //TODO FOR MB + } + $this->view = 'relationships' ; + } + + function action_SaveRelationship () + { + if(!empty($GLOBALS['current_user']) && empty($GLOBALS['modListHeader'])) + { + $GLOBALS['modListHeader'] = query_module_access_list($GLOBALS['current_user']); + } + + if (empty($_REQUEST [ 'view_package' ])) + { + require_once 'modules/ModuleBuilder/parsers/relationships/DeployedRelationships.php' ; + $relationships = new DeployedRelationships ( $_REQUEST [ 'view_module' ] ) ; + } else + { + $mb = new ModuleBuilder ( ) ; + $module = & $mb->getPackageModule ( $_REQUEST [ 'view_package' ], $_REQUEST [ 'view_module' ] ) ; + require_once 'modules/ModuleBuilder/parsers/relationships/UndeployedRelationships.php' ; + $relationships = new UndeployedRelationships ( $module->getModuleDir () ) ; + } + + $relationships->addFromPost () ; + $relationships->save () ; + $GLOBALS['log']->debug("\n\nSTART BUILD"); + if (empty($_REQUEST [ 'view_package' ])) { + $relationships->build () ; + + LanguageManager::clearLanguageCache($_REQUEST [ 'view_module' ]); + } + $GLOBALS['log']->debug("\n\nEND BUILD"); + + $this->view = 'relationships' ; + } + + function action_DeleteRelationship () + { + if (isset ( $_REQUEST [ 'relationship_name' ] )) + { + if (empty($_REQUEST [ 'view_package' ] )) + { + require_once 'modules/ModuleBuilder/parsers/relationships/DeployedRelationships.php' ; + if (!empty($_REQUEST['remove_tables'])) + $GLOBALS['mi_remove_tables'] = $_REQUEST['remove_tables']; + $relationships = new DeployedRelationships ( $_REQUEST [ 'view_module' ] ) ; + } else + { + $mb = new ModuleBuilder ( ) ; + $module = & $mb->getPackageModule ( $_REQUEST [ 'view_package' ], $_REQUEST [ 'view_module' ] ) ; + require_once 'modules/ModuleBuilder/parsers/relationships/UndeployedRelationships.php' ; + $relationships = new UndeployedRelationships ( $module->getModuleDir () ) ; + } + $relationships->delete ( $_REQUEST [ 'relationship_name' ] ) ; + $relationships->save () ; + } + $this->view = 'relationships' ; + } + + function action_SaveDropDown () + { + require_once 'modules/ModuleBuilder/parsers/parser.dropdown.php' ; + $parser = new ParserDropDown ( ) ; + $parser->saveDropDown ( $_REQUEST ) ; + $this->view = 'dropdowns' ; + } + + function action_DeleteField () + { + require_once ('modules/DynamicFields/FieldCases.php') ; + $field = get_widget ( $_REQUEST [ 'type' ] ) ; + $field->name = $_REQUEST [ 'name' ] ; + if (!isset ( $_REQUEST [ 'view_package' ] )) + { + if (! empty ( $_REQUEST [ 'name' ] ) && ! empty ( $_REQUEST [ 'view_module' ] )) + { + require_once ('modules/DynamicFields/DynamicField.php') ; + $moduleName = $_REQUEST [ 'view_module' ] ; + $class_name = $GLOBALS [ 'beanList' ] [ $moduleName ] ; + require_once ($GLOBALS [ 'beanFiles' ] [ $class_name ]) ; + $seed = new $class_name ( ) ; + $df = new DynamicField ( $moduleName ) ; + $df->setup ( $seed ) ; + //Need to load the entire field_meta_data for some field types + $field = $df->getFieldWidget($moduleName, $field->name); + $field->delete ( $df ) ; + + $GLOBALS [ 'mod_strings' ]['LBL_ALL_MODULES'] = 'all_modules'; + $_REQUEST['execute_sql'] = true; + include_once ('modules/Administration/QuickRepairAndRebuild.php') ; + $repair = new RepairAndClear(); + $repair->repairAndClearAll(array('rebuildExtensions', 'clearVardefs', 'clearTpls'), array($class_name), true, false); + require_once 'modules/ModuleBuilder/Module/StudioModuleFactory.php' ; + $module = StudioModuleFactory::getStudioModule( $moduleName ) ; + } + } + else + { + $mb = new ModuleBuilder ( ) ; + $module = & $mb->getPackageModule ( $_REQUEST [ 'view_package' ], $_REQUEST [ 'view_module' ] ) ; + $field->delete ( $module ) ; + $mb->save () ; + } + $module->removeFieldFromLayouts( $field->name ); + $this->view = 'modulefields' ; + } + + function action_CloneField () + { + $this->view_object_map [ 'field_name' ] = $_REQUEST [ 'name' ] ; + $this->view_object_map [ 'is_clone' ] = true ; + $this->view = 'modulefield' ; + } + + function action_SaveAssistantPref () + { + global $current_user ; + if (isset ( $_REQUEST [ 'pref_value' ] )) + { + if ($_REQUEST [ 'pref_value' ] == 'ignore') + { + $current_user->setPreference ( 'mb_assist', 'DISABLED', 0, 'Assistant' ) ; + } else + { + $current_user->setPreference ( 'mb_assist', 'ENABLED', 0, 'Assistant' ) ; + } + $current_pref = $current_user->getPreference ( 'mb_assist', 'Assistant' ) ; + echo "Assistant.processUserPref('$current_pref')" ; + sugar_cleanup ( true ) ; //push preferences to DB. + } + } + + // Studio2 Actions + + + function action_EditProperty () + { + $this->view = 'property' ; + } + + function action_saveProperty () + { + require_once 'modules/ModuleBuilder/parsers/parser.label.php' ; + $modules = $_REQUEST['view_module']; + if(!empty($_REQUEST['subpanel'])){ + $modules = $_REQUEST['subpanel']; + } + $parser = new ParserLabel ( $modules , isset ( $_REQUEST [ 'view_package' ] ) ? $_REQUEST [ 'view_package' ] : null ) ; + // if no language provided, then use the user's current language which is most likely what they intended + $language = (isset($_REQUEST [ 'selected_lang' ])) ? $_REQUEST [ 'selected_lang' ] : $GLOBALS['current_language'] ; + $parser->handleSave ( $_REQUEST, $language ) ; + $json = getJSONobj(); + echo $json->encode(array("east" => array("action" => "deactivate"))); + } + + function action_editModule () + { + $this->view = 'module' ; + } + + function action_wizard () + { + $this->view = 'wizard' ; + } + + /** + * Receive a layout through $_REQUEST and save it out to the working files directory + * Expects a series of $_REQUEST parameters all in the format $_REQUEST['slot-panel#-slot#-property']=value + */ + + function action_saveLayout () + { + $parser = ParserFactory::getParser ( $_REQUEST [ 'view' ], $_REQUEST [ 'view_module' ], isset ( $_REQUEST [ 'view_package' ] ) ? $_REQUEST [ 'view_package' ] : null ) ; + $this->view = 'layoutview' ; + $parser->writeWorkingFile () ; + + if(!empty($_REQUEST [ 'sync_detail_and_edit' ]) && $_REQUEST['sync_detail_and_edit'] != false && $_REQUEST['sync_detail_and_edit'] != "false"){ + if(strtolower ($parser->_view) == MB_EDITVIEW){ + $parser2 = ParserFactory::getParser ( MB_DETAILVIEW, $_REQUEST [ 'view_module' ], isset ( $_REQUEST [ 'view_package' ] ) ? $_REQUEST [ 'view_package' ] : null ) ; + $parser2->setUseTabs($parser->getUseTabs()); + $parser2->writeWorkingFile () ; + } + } + } + + function action_saveAndPublishLayout () + { + $parser = ParserFactory::getParser ( $_REQUEST [ 'view' ], $_REQUEST [ 'view_module' ], isset ( $_REQUEST [ 'view_package' ] ) ? $_REQUEST [ 'view_package' ] : null ) ; + $this->view = 'layoutview' ; + $parser->handleSave () ; + + if(!empty($_REQUEST [ 'sync_detail_and_edit' ]) && $_REQUEST['sync_detail_and_edit'] != false && $_REQUEST['sync_detail_and_edit'] != "false"){ + if(strtolower ($parser->_view) == MB_EDITVIEW){ + $parser2 = ParserFactory::getParser ( MB_DETAILVIEW, $_REQUEST [ 'view_module' ], isset ( $_REQUEST [ 'view_package' ] ) ? $_REQUEST [ 'view_package' ] : null ) ; + $parser2->setUseTabs($parser->getUseTabs()); + $parser2->handleSave () ; + } + } + } + + function action_manageBackups () + { + + } + + function action_listViewSave () + { + $GLOBALS [ 'log' ]->info ( "action_listViewSave" ) ; + + $packageName = (isset ( $_REQUEST [ 'view_package' ] ) && (strtolower($_REQUEST['view_package']) != 'studio')) ? $_REQUEST [ 'view_package' ] : null ; + $subpanelName = (! empty ( $_REQUEST [ 'subpanel' ] )) ? $_REQUEST [ 'subpanel' ] : null ; + require_once 'modules/ModuleBuilder/parsers/ParserFactory.php' ; + $parser = ParserFactory::getParser ( $_REQUEST [ 'view' ], $_REQUEST [ 'view_module' ], $packageName, $subpanelName ) ; + $this->view = 'listView' ; + $parser->handleSave () ; + + } + + function action_dashletSave () { + $this->view = 'dashlet' ; + $packageName = (isset ( $_REQUEST [ 'view_package' ] ) && (strtolower($_REQUEST['view_package']) != 'studio')) ? $_REQUEST [ 'view_package' ] : null ; + require_once 'modules/ModuleBuilder/parsers/ParserFactory.php' ; + $parser = ParserFactory::getParser ( $_REQUEST [ 'view' ], $_REQUEST [ 'view_module' ], $packageName ) ; + $parser->handleSave () ; + } + + function action_popupSave(){ + $this->view = 'popupview' ; + $packageName = (isset ( $_REQUEST [ 'view_package' ] ) && (strtolower($_REQUEST['view_package']) != 'studio')) ? $_REQUEST [ 'view_package' ] : null ; + require_once 'modules/ModuleBuilder/parsers/ParserFactory.php' ; + $parser = ParserFactory::getParser ( $_REQUEST [ 'view' ], $_REQUEST [ 'view_module' ], $packageName ) ; + $parser->handleSave () ; + if(empty($packageName)){ + include_once ('modules/Administration/QuickRepairAndRebuild.php') ; + global $mod_strings; + $mod_strings['LBL_ALL_MODULES'] = 'all_modules'; + $repair = new RepairAndClear(); + $repair->show_output = false; + $class_name = $GLOBALS [ 'beanList' ] [ $_REQUEST [ 'view_module' ] ] ; + $repair->module_list = array($class_name); + $repair->clearTpls(); + } + + } + + function action_searchViewSave () + { + $packageName = (isset ( $_REQUEST [ 'view_package' ] )) ? $_REQUEST [ 'view_package' ] : null ; + require_once 'modules/ModuleBuilder/parsers/views/SearchViewMetaDataParser.php' ; + $parser = new SearchViewMetaDataParser ( $_REQUEST [ 'view' ], $_REQUEST [ 'view_module' ], $packageName ) ; + $parser->handleSave () ; + $this->view = 'searchView' ; + } + + function action_editLabels () + { + if (isset ( $_REQUEST [ 'view_package' ] )) //MODULE BUILDER + { + $this->view = 'modulelabels'; + }else{ //STUDIO + $this->view = 'labels'; + } + } + + function action_get_app_list_string () + { + require_once ('include/JSON.php') ; + $json = new JSON ( ) ; + if (isset ( $_REQUEST [ 'key' ] ) && ! empty ( $_REQUEST [ 'key' ] )) + { + $key = $_REQUEST [ 'key' ] ; + $value = array ( ) ; + if (! empty ( $GLOBALS [ 'app_list_strings' ] [ $key ] )) + { + $value = $GLOBALS [ 'app_list_strings' ] [ $key ] ; + } else + { + $package_strings = array ( ) ; + if (! empty ( $_REQUEST [ 'view_package' ] ) && $_REQUEST [ 'view_package' ] != 'studio' && ! empty ( $_REQUEST [ 'view_module' ] )) + { + require_once ('modules/ModuleBuilder/MB/ModuleBuilder.php') ; + $mb = new ModuleBuilder ( ) ; + $module = & $mb->getPackageModule ( $_REQUEST [ 'view_package' ], $_REQUEST [ 'view_module' ] ) ; + $lang = $GLOBALS [ 'current_language' ] ; + $module->mblanguage->generateAppStrings ( false ) ; + $package_strings = $module->mblanguage->appListStrings [ $lang . '.lang.php' ] ; + if (isset ( $package_strings [ $key ] ) && is_array ( $package_strings [ $key ] )) + { + $value = $package_strings [ $key ] ; + } + } + } + echo $json->encode ( $value ) ; + } + } + + function action_history () + { + $this->view = 'history' ; + } + + function resetmodule() + { + $this->view = 'resetmodule'; + } + + + +} +?> \ No newline at end of file diff --git a/modules/ModuleBuilder/javascript/JSTransaction.js b/modules/ModuleBuilder/javascript/JSTransaction.js new file mode 100644 index 00000000..c31ca457 --- /dev/null +++ b/modules/ModuleBuilder/javascript/JSTransaction.js @@ -0,0 +1,79 @@ +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + + + +function JSTransaction(){ + this.JSTransactions = new Array(); + this.JSTransactionIndex = 0; + this.JSTransactionCanRedo = false; + this.JSTransactionTypes = new Array(); + + +} + + JSTransaction.prototype.record = function(transaction, data){ + this.JSTransactions[this.JSTransactionIndex] = {'transaction':transaction , 'data':data}; + this.JSTransactionIndex++; + this.JSTransactionCanRedo = false + } + JSTransaction.prototype.register = function(transaction, undo, redo){ + this.JSTransactionTypes[transaction] = {'undo': undo, 'redo':redo}; + } + JSTransaction.prototype.undo = function(){ + if(this.JSTransactionIndex > 0){ + if(this.JSTransactionIndex > this.JSTransactions.length ){ + this.JSTransactionIndex = this.JSTransactions.length; + } + var transaction = this.JSTransactions[this.JSTransactionIndex - 1]; + var undoFunction = this.JSTransactionTypes[transaction['transaction']]['undo']; + undoFunction(transaction['data']); + this.JSTransactionIndex--; + this.JSTransactionCanRedo = true; + } + } + JSTransaction.prototype.redo = function(){ + if(this.JSTransactionCanRedo && this.JSTransactions.length < 0)this.JSTransactionIndex = 0; + if(this.JSTransactionCanRedo && this.JSTransactionIndex <= this.JSTransactions.length ){ + this.JSTransactionIndex++; + var transaction = this.JSTransactions[this.JSTransactionIndex - 1]; + var redoFunction = this.JSTransactionTypes[transaction['transaction']]['redo']; + redoFunction(transaction['data']); + } + } + + + diff --git a/modules/ModuleBuilder/javascript/ModuleBuilder.js b/modules/ModuleBuilder/javascript/ModuleBuilder.js new file mode 100644 index 00000000..1b7db8ba --- /dev/null +++ b/modules/ModuleBuilder/javascript/ModuleBuilder.js @@ -0,0 +1,1060 @@ +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +function treeinit() {} + +if(typeof('console') == 'undefined'){ +console = { + log: function(message){ + + }} +} +(function() { + var sw = YAHOO.SUGAR, + Event = YAHOO.util.Event, + Connect = YAHOO.util.Connect, + Dom = YAHOO.util.Dom; + +function createTreePanel(treeData, params) { + var tree = new YAHOO.widget.TreeView(params.id); + var root = tree.getRoot(); + addChildNodes(root, treeData); + + return tree; +} + +function addChildNodes(parentNode, parentData) { + var nodes = parentData.nodes || parentData.children; + for (i in nodes) { + if (typeof(nodes[i]) == 'object') { + nodes[i].data.href = 'javascript:void(0);'; + var node = new YAHOO.widget.TextNode(nodes[i].data, parentNode) + node.action = nodes[i].data.action; + if (typeof(nodes[i].nodes) == 'object') { + addChildNodes(node, nodes[i]); + } + } + } +} + +if (typeof(ModuleBuilder) == 'undefined') { + ModuleBuilder = { + init: function(){ + + //Setup the basic ajax request settings + Connect.extraParams = { + to_pdf: true + }; + Connect.url = 'index.php?to_pdf=1&sugar_body_only=1'; + Connect.method = 'POST'; + Connect.timeout = 300000; + + //Setup and read cookie settings + //Ext.state.Manager.setProvider(new Ext.state.CookieProvider()); + + if (SUGAR.themes.tempHideLeftCol) + SUGAR.themes.tempHideLeftCol(); + + var Ck = YAHOO.util.Cookie; + + //Setup the main layout + var tp = ModuleBuilder.tabPanel = new YAHOO.widget.TabView("mbtabs"); + tp.addTab(new YAHOO.widget.Tab({ + label: SUGAR.language.get('ModuleBuilder', 'LBL_SECTION_MAIN'), + scroll : true, + content : "
    ", + id : "center", + active : true + })); + + var viewHeight = document.documentElement ? document.documentElement.clientHeight : self.innerHeight; + var mp = ModuleBuilder.mainPanel = new YAHOO.widget.Layout('mblayout', { + border: false, + height: viewHeight - (document.getElementById('header').clientHeight ) - 40, + //autoHeight: true + //frame: true, + units: [//ModuleBuilder.tree, ModuleBuilder.tabPanel, + { + position: 'center', + body : 'mbcenter', + scroll : true + },{ + position: "left", + header: "Tree", + collapse: true, + width: 230, + minWidth: 100, + resize: true, + scroll : true, + body : "
    " + },{ + id: 'help', + header: SUGAR.language.get('ModuleBuilder', 'LBL_SECTION_HELP'), + position:'right', + body: 'mbhelp', + scroll: true, + width: 250, + minWidth: 200, + resize: true, + collapse: true + },{ + header: SUGAR.util.getAndRemove("footerHTML").innerHTML, + position: 'bottom', + id: 'mbfooter', + height: 30, + border: false + }] + }); + mp.render(); + + ModuleBuilder.nextYear = new Date(); + ModuleBuilder.nextYear.setDate(ModuleBuilder.nextYear.getDate() + 360); + + var nextyear = ModuleBuilder.nextYear; + + if (Ck.getSub("ModuleBuilder", "helpHidden") == "true") { + mp.getUnitByPosition('right').collapse(); + } + if (Ck.getSub("ModuleBuilder", "treeHidden") == "true") { + mp.getUnitByPosition('left').collapse(); + } + + var centerEl = mp.getUnitByPosition('center').get('wrap'); + tp.appendTo(centerEl); + + //YUI does not take the resizers into account when calculating panel size. + var correctW = function(){ + var w = (this.body.offsetWidth - 7) + "px"; + this.body.style.width = w; + this.header.style.width = w; + }; + mp.getUnitByPosition('right').on("resize", correctW); + mp.getUnitByPosition('right').on("collapse", function(){ + Ck.setSub("ModuleBuilder", "helpHidden", "true"); + }); + mp.getUnitByPosition('right').on("expand", function(){ + Ck.setSub("ModuleBuilder", "helpHidden", "false"); + }); + mp.getUnitByPosition('left').on("resize", correctW); + mp.getUnitByPosition('left').on("collapse", function(){ + Ck.setSub("ModuleBuilder", "treeHidden", "true"); + }); + mp.getUnitByPosition('left').on("expand", function(){ + Ck.setSub("ModuleBuilder", "treeHidden", "false"); + }); + mp.resize(true); + Event.on(window, 'resize', ModuleBuilder.autoSetLayout, this, true); + + var tree = ModuleBuilder.tree = createTreePanel(TREE_DATA, { + id: 'mbTree' + }); + tree.setCollapseAnim("TVSlideOut"); + tree.setExpandAnim("TVSlideIn"); + //tree.subscribe("labelClick", ModuleBuilder.handleTreeClick); + tree.subscribe("clickEvent", ModuleBuilder.handleTreeClick); + tree.render(); + + //Setup Browser History + var mbContent = YAHOO.util.History.getBookmarkedState('mbContent'); + + if (ModuleBuilder.mode == 'mb') { + mp.getUnitByPosition('left').header.firstChild.innerHTML = SUGAR.language.get('ModuleBuilder', 'LBL_SECTION_PACKAGES'); + mbContent = mbContent ? mbContent : 'module=ModuleBuilder&action=package&package='; + } + else if (ModuleBuilder.mode == 'studio') { + ModuleBuilder.MBpackage = ''; // set to empty so other views can recognize that dealing with an deployed, rather than undeployed, module + mp.getUnitByPosition('left').header.firstChild.innerHTML = SUGAR.language.get('ModuleBuilder', 'LBL_SECTION_MODULES'); + mbContent = mbContent ? mbContent :'module=ModuleBuilder&action=wizard'; + } + else if (ModuleBuilder.mode == 'dropdowns') { + mp.getUnitByPosition('left').header.firstChild.innerHTML = SUGAR.language.get('ModuleBuilder', 'LBL_SECTION_DROPDOWNS'); + mbContent = mbContent ? mbContent : 'module=ModuleBuilder&action=dropdowns'; + } + else { + mp.getUnitByPosition('left').collapse(false); + mbContent = mbContent ? mbContent : 'module=ModuleBuilder&action=home'; + } + + YAHOO.util.History.register('mbContent', mbContent, ModuleBuilder.navigate); + YAHOO.util.History.initialize("yui-history-field", "yui-history-iframe"); + ModuleBuilder.getContent(mbContent); + + if (SUGAR.themes.tempHideLeftCol) SUGAR.themes.tempHideLeftCol(); + ModuleBuilder.autoSetLayout(); + + ModuleBuilder.tabPanel.on('activeTabChange', function(e) { + ModuleBuilder.helpLoad( e.newValue.get("id") ) ; + }); + + if (Dom.get("HideHandle")){ + if (SUGAR.themes.tempHideLeftCol){ + SUGAR.themes.tempHideLeftCol(); + } + } + + }, + //Empty layout manager + layoutValidation: { + popup_window: null, + popup: function(){ + ModuleBuilder.layoutValidation.popup_window = new YAHOO.widget.SimpleDialog("emptyLayout", { + width: "400px", + draggable: true, + constraintoviewport: true, + modal: true, + fixedcenter: true, + text: SUGAR.language.get('ModuleBuilder', 'ERROR_MINIMUM_FIELDS'), + bodyStyle: "padding:5px", + buttons: [{ + text: SUGAR.language.get('ModuleBuilder', 'LBL_BTN_CLOSE'), + isDefault:true, + handler: function(){ + ModuleBuilder.layoutValidation.popup_window.hide() + } + }] + }); + ModuleBuilder.layoutValidation.popup_window.render(document.body); + ModuleBuilder.layoutValidation.popup_window.show(); + } + }, + //Layout history manager + history: { + popup_window: false, + reverted: false, + params: { }, + browse: function(module, layout, subpanel){ + subpanel = subpanel ? subpanel : ""; + if (!module && ModuleBuilder.module != "undefined") { + module = ModuleBuilder.module; + } + if (!ModuleBuilder.history.popup_window) { + ModuleBuilder.history.popup_window = new YAHOO.SUGAR.AsyncPanel('histWindow', { + width: 300, + draggable: true, + close: true, + constraintoviewport: true, + fixedcenter: false + }); + } + var module_str = module; + if(typeof SUGAR.language.languages['app_list_strings']['moduleList'][module] != 'undefined'){ + module_str = SUGAR.language.languages['app_list_strings']['moduleList'][module]; + } + ModuleBuilder.history.popup_window.setHeader( module_str + ' : ' + SUGAR.language.get('ModuleBuilder', 'LBL_' + layout.toUpperCase()) + SUGAR.language.get('ModuleBuilder', 'LBL_HISTORY_TITLE')); + ModuleBuilder.history.popup_window.setBody("test"); + ModuleBuilder.history.popup_window.render(document.body); + ModuleBuilder.history.params = { + module: 'ModuleBuilder', + histAction: 'browse', + action: 'history', + view_package: ModuleBuilder.MBpackage, + view_module: module, + view: layout, + subpanel: subpanel + }; + ModuleBuilder.history.popup_window.load(ModuleBuilder.paramsToUrl(ModuleBuilder.history.params)); + ModuleBuilder.history.popup_window.show(); + ModuleBuilder.history.popup_window.center(); + }, + preview: function(module, layout, id, subpanel) { + var prevPanel = ModuleBuilder.findTabById('preview:' + id); + if (!prevPanel) { + ModuleBuilder.history.params = { + module: 'ModuleBuilder', + histAction: 'preview', + action: 'history', + view_package: ModuleBuilder.MBpackage, + view_module: module, + view: layout, + sid: id, + subpanel: subpanel + }; + prevPanel = new YAHOO.SUGAR.ClosableTab({ + dataSrc: Connect.url + "&" + ModuleBuilder.paramsToUrl(ModuleBuilder.history.params), + label: SUGAR.language.get("ModuleBuilder", "LBL_MB_PREVIEW"), + id: 'preview:' + id, + scroll: true, + cacheData: true, + active :true + }, ModuleBuilder.tabPanel); + prevPanel.closable = true; + ModuleBuilder.tabPanel.addTab(prevPanel); + } else { + ModuleBuilder.tabPanel.set("activeTab", prevPanel); + } + + }, + revert: function(module, layout, id, subpanel){ + var prevTab = ModuleBuilder.tabPanel.getTabIndex("preview:" + id); + if(prevTab) ModuleBuilder.tabPanel.removeTab(prevTab); + + ModuleBuilder.history.params = { + module: 'ModuleBuilder', + histAction: 'restore', + action: 'history', + view_package: ModuleBuilder.MBpackage, + view_module: module, + view: layout, + sid: id, + subpanel: subpanel + } + ModuleBuilder.asyncRequest(ModuleBuilder.history.params, function(){ + ModuleBuilder.history.reverted = true; + ModuleBuilder.getContent(ModuleBuilder.contentURL); + ModuleBuilder.state.isDirty = true; + }); + }, + cleanup: function() { + if (ModuleBuilder.history.reverted && ModuleBuilder.history.params.histAction) { + ModuleBuilder.history.params.histAction = 'unrestore'; + ModuleBuilder.asyncRequest({params: ModuleBuilder.history.params}); + } + ModuleBuilder.history.params = { }; + ModuleBuilder.history.reverted = false; + }, + update: function() { + if (ModuleBuilder.history.popup_window && ModuleBuilder.history.popup_window.cfg.getProperty("visible")) { + var historyButton = YAHOO.util.Dom.get('historyBtn'); + if (historyButton) { + historyButton.onclick(); + } else { + ModuleBuilder.history.popup_window.hide(); + } + } + } + }, + state: { + isDirty: false, + saving: false, + hideFailedMesage: false, + intended_view: { + url: null, + successCall: null + }, + current_view: { + url: null, + successCall: null + }, + save_url_for_current_view: null, + popup_window: null, + setupState: function(){ + //ModuleBuilder.state.popup(); + document.body.setAttribute("onclose", "ModuleBuilder.state.popup(); ModuleBuilder.state.popup_window.show()"); + return; + }, + onSaveClick: function(){ + //set dirty = false + //call the save method of the current view. + //call the intended action. + ModuleBuilder.state.isDirty = false; + var saveBtn = document.getElementById("saveBtn"); + if (!saveBtn) { + var mbForm = document.forms[1]; + if (mbForm) + var mbButtons = mbForm.getElementsByTagName("input"); + if (mbButtons) { + for (var button = 0; button < mbButtons.length; button++) { + var name = mbButtons[button].getAttribute("name"); + if (name && (name.toUpperCase() == "SAVEBTN" || name.toUpperCase() == "LSAVEBTN")) { + saveBtn = mbButtons[button]; + break; + } + } + } + else { + alert("Could not find the save action for this view."); + } + } + if (saveBtn) { + //After the save call completes, load the next page + ModuleBuilder.state.saving = true; + eval(saveBtn.getAttributeNode('onclick').value); + } + ModuleBuilder.state.popup_window.hide(); + }, + onDontSaveClick: function(){ + //set dirty to false + //call the intended action. + ModuleBuilder.state.isDirty = false; + ModuleBuilder.history.cleanup(); + ModuleBuilder.getContent(ModuleBuilder.state.intended_view.url, ModuleBuilder.state.intended_view.successCall); + ModuleBuilder.state.popup_window.hide(); + }, + loadOnSaveComplete: function() { + ModuleBuilder.state.saving = false; + ModuleBuilder.getContent(ModuleBuilder.state.intended_view.url, ModuleBuilder.state.intended_view.successCall); + }, + popup: function(){ + ModuleBuilder.state.popup_window = new YAHOO.widget.SimpleDialog("confirmUnsaved", { + width: "400px", + draggable: true, + constraintoviewport: true, + modal: true, + fixedcenter: true, + text: SUGAR.language.get('ModuleBuilder', 'LBL_CONFIRM_DONT_SAVE'), + bodyStyle: "padding:5px", + buttons: [{ + text: SUGAR.language.get('ModuleBuilder', 'LBL_BTN_DONT_SAVE'), + handler: ModuleBuilder.state.onDontSaveClick + }, { + text: SUGAR.language.get('ModuleBuilder', 'LBL_BTN_CANCEL'), + isDefault:true, + handler: function(){ + ModuleBuilder.state.popup_window.hide() + } + },{ + text: SUGAR.language.get('ModuleBuilder', 'LBL_BTN_SAVE_CHANGES'), + handler: ModuleBuilder.state.onSaveClick + }] + }); + ModuleBuilder.state.popup_window.setHeader(SUGAR.language.get('ModuleBuilder', 'LBL_CONFIRM_DONT_SAVE_TITLE')); + if(ModuleBuilder.disablePopupPrompt != 1){ + ModuleBuilder.state.popup_window.render(document.body); + }else{ + ModuleBuilder.state.onDontSaveClick(); + } + } + }, + copyFromView: function(module, layout){ + var url = ModuleBuilder.contentURL; + ModuleBuilder.getContent(url+"©FromEditView=true"); + ModuleBuilder.contentURL = url; + ModuleBuilder.state.intended_view.url = url; + ModuleBuilder.state.isDirty = true; + }, + //AJAX Navigation Functions + navigate : function(url) { + //Check if we are just registering the url + if (url != ModuleBuilder.contentURL) { + ModuleBuilder.getContent(url); + } + }, + getContent: function(url, successCall){ + if (!url) return; + + if (url.substring(0, 11) == "javascript:") + { + eval(url.substring(11)); + return; + } + + //save a pointer to intended action + ModuleBuilder.state.intended_view.url = url; + ModuleBuilder.state.intended_view.successCall = successCall; + if(ModuleBuilder.state.isDirty){ //prompt to save current data. + //check if we are editing a property of the current view (such views open up in new tabs) + //if so we leave the state dirty and return + temp_url = url.toLowerCase(); + if(null == temp_url.match(/&action=editproperty/)){ + ModuleBuilder.state.popup(); + ModuleBuilder.state.popup_window.show(); + return; + } + + }else{ + ModuleBuilder.state.current_view.url = url; + ModuleBuilder.state.current_view.successCall = successCall; + } + + ModuleBuilder.contentURL = url; + if (typeof(successCall) != 'function') { + if (ModuleBuilder.callInProgress) + return; + ModuleBuilder.callInProgress = true; + successCall = ModuleBuilder.updateContent; + } + ModuleBuilder.asyncRequest(url, successCall); + }, + updateContent: function(o){ + ModuleBuilder.callInProgress = false; + //Check if a save action was called and now we need to move-on + if (ModuleBuilder.state.saving) { + ModuleBuilder.state.loadOnSaveComplete(); + return; + } + ajaxStatus.flashStatus(SUGAR.language.get('app_strings', 'LBL_REQUEST_PROCESSED'), 2000); + if(ModuleBuilder.checkForErrors(o)) + return false; + + try { + var ajaxResponse = YAHOO.lang.JSON.parse((o.responseText)); + } catch (err) { + YAHOO.SUGAR.MessageBox.show({ + title: SUGAR.language.get('ModuleBuilder', 'ERROR_GENERIC_TITLE'), + msg: o.responseText, + width: 500 + }); + return false; + } + + + if (ajaxResponse.tpl){ + var t = new YAHOO.SUGAR.Template(ajaxResponse.tpl); + ModuleBuilder.ajaxData = ajaxResponse.data; + ModuleBuilder.tabPanel.getTab(0).set(t.exec(ajaxResponse.data)); + SUGAR.util.evalScript(t.exec(ajaxResponse.data)); + return true; + } + + for (var maj in ajaxResponse) { + var name = 'mb' + maj; + var comp = ModuleBuilder.mainPanel.getUnitById(maj); + if (!comp) { + var tabs = ModuleBuilder.tabPanel.get("tabs"); + for (i in tabs) { + if (tabs[i].get && tabs[i].get("id") == maj) + comp = tabs[i]; + } + } + + if (name == 'mbwest') { //refresh package_tree! + var tree = ModuleBuilder.tree; + var root = tree.root; + tree.maxAnim = 0; + tree.collapseAll(); + while (root.hasChildren()) { + tree.removeNode(root.children[0], true); + } + addChildNodes(root, ajaxResponse.west.content.tree_data); + tree.maxAnim = 2; + tree.render(); + } + else { + if (!comp) { + if(ajaxResponse[maj].action == 'deactivate') continue; + comp = new YAHOO.SUGAR.ClosableTab({ + content: "
    " + ((maj == 'center') ? "
    " + ajaxResponse[maj].crumb + "
    " :"") + + ajaxResponse[maj].content + "
    ", + label: ajaxResponse[maj].title, + id: maj, + scroll: true, + closable: true, + active :true + }, ModuleBuilder.tabPanel); + comp.closable = true; + ModuleBuilder.scriptTest = false; + ModuleBuilder.tabPanel.set("activeTab", comp); + ModuleBuilder.tabPanel.addTab(comp); + //Text if the browser automatically evaluated the content's script tags or not. If not, manually evaluate them. + if (!ModuleBuilder.scriptTest) + SUGAR.util.evalScript(ajaxResponse[maj].content); + } else { + //Store Center pane changes in browser history + YAHOO.util.History.navigate('mbContent', ModuleBuilder.contentURL); + if (name == 'mbcenter') { + ModuleBuilder.closeAllTabs(); + comp = ModuleBuilder.tabPanel.getTab(0); + } + ModuleBuilder.tabPanel.set("activeTab", comp); + comp.set('content', "
    " + ajaxResponse[maj].crumb + "
    " + ajaxResponse[maj].content + "
    "); + if (ajaxResponse[maj].title != "no_change") + comp.set('label', ajaxResponse[maj].title); + SUGAR.util.evalScript(ajaxResponse[maj].content); + } + } + ModuleBuilder.history.update(); + } + }, + checkForErrors: function(o){ + if (SUGAR.util.isLoginPage(o.responseText)) + return true; + if (o.responseText.substr(0, 1) == "<") { + YAHOO.SUGAR.MessageBox.show({ + title: SUGAR.language.get('ModuleBuilder', 'ERROR_GENERIC_TITLE'), + msg: o.responseText, + width: 500 + }); + return true; + } + + + return false; + }, + submitForm: function(formname, successCall){ + ajaxStatus.showStatus(SUGAR.language.get('ModuleBuilder', 'LBL_AJAX_LOADING')); + if (typeof(successCall) == 'undefined') { + successCall = ModuleBuilder.updateContent; + } + else { + ModuleBuilder.callLock = true; + } + Connect.setForm(document.getElementById(formname) || document.forms[formname]); + Connect.asyncRequest( + Connect.method, + Connect.url, + {success: successCall, failure: ModuleBuilder.failed} + ); + }, + setMode: function(reqMode){ + ModuleBuilder.mode = reqMode; + }, + main: function(type){ + document.location.href = 'index.php?module=ModuleBuilder&action=index&type=' + type; + }, + failed: function(o){ + if(!ModuleBuilder.state.hideFailedMesage){ + ajaxStatus.flashStatus(SUGAR.language.get('ModuleBuilder', 'LBL_AJAX_FAILED_DATA'), 2000); + } + }, + //Wizard Functions + buttonDown: function(button, name, list){ + if (typeof(name) != 'undefined') { + for (i in ModuleBuilder.buttons[list]) { + ModuleBuilder.buttons[list][i].className = 'wizardButton'; + } + ModuleBuilder.buttonSelect(name, list); + } + button.className = 'wizardButtonDown'; + + }, + buttonOver: function(button){ + button.className = 'button'; + }, + buttonOut: function(button, name, list){ + if (typeof(name) != 'undefined') { + if (ModuleBuilder.buttonGetSelected(list) != name) { + button.className = 'wizardButton' + } + } + else { + button.className = 'wizardButton' + } + + }, + buttonAdd: function(id, name, list){ + if (typeof(ModuleBuilder.buttons[list]) == 'undefined') { + ModuleBuilder.buttons[list] = {}; + + } + ModuleBuilder.buttons[list][name] = document.getElementById(id); + + }, + buttonGetSelected: function(list){ + if (typeof(ModuleBuilder.selected[list]) == 'undefined') { + return false; + } + return ModuleBuilder.selected[list]; + }, + buttonSelect: function(name, list){ + ModuleBuilder.selected[list] = name; + }, + buttonToForm: function(form, field, list){ + var theField = eval('document.' + form + '.' + field); + theField.value = ModuleBuilder.buttonGetSelected(list); + }, + + getTitle: function(title, breadCrumb){ + return "

    " + title + "


    " + breadCrumb; + }, + closeAllTabs: function() { + var tabs = ModuleBuilder.tabPanel.get('tabs'); + for (var i = tabs.length - 1; i > -1; i--) { + var tab = tabs[i]; + if (tab.close) { + tab.close(); + } + } + }, + //Help Functions + helpRegister: function(name){ + var formname = 'document.' + name; + var form = eval(formname); + var i = 0; + for (i = 0; i < form.elements.length; i++) { + if (typeof(form.elements[i].type) != 'undefined' && typeof(form.elements[i].name) != 'undefined' && form.elements[i].type != 'hidden') { + form.elements[i].onmouseover = function(){ + ModuleBuilder.helpToggle(this.name) + }; + form.elements[i].onmouseout = function(){ + ModuleBuilder.helpToggle('default') + }; + + } + } + }, + helpUnregisterByID: function (id){ + var elm = document.getElementById(id); + if (elm) { + elm.onmouseover = function() {}; + elm.onmouseout = function() {}; + } + return; + }, + helpRegisterByID: function(name, tag){ + var parent = document.getElementById(name); + var children = parent.getElementsByTagName(tag); + for (var i = 0; i < children.length; i++) { + if (children[i].id != 'undefined') { + children[i].onmouseover = function(){ + ModuleBuilder.helpToggle(this.id) + }; + //children[i].onmouseover = function(){alert(this.id)}; + children[i].onmouseout = function(){ + ModuleBuilder.helpToggle('default') + }; + } + } + }, + helpSetup: function(group, def, panel){ + if (!ModuleBuilder.panelHelp) ModuleBuilder.panelHelp = []; + + // setup the linkage between this tab/panel and the relevant help + var id = ModuleBuilder.tabPanel.get("activeTab").get("id") ; + ModuleBuilder.panelHelp [ id ] = { lang: group , def: def } ; + + // get the help text if required + if ( ! ModuleBuilder.AllHelpLang ) ModuleBuilder.AllHelpLang = SUGAR.language.get('ModuleBuilder', 'help'); + + if (group && def) { + ModuleBuilder.helpLang = ModuleBuilder.AllHelpLang[group]; + ModuleBuilder.helpDefault = def; + } + + ModuleBuilder.helpToggle('default'); + }, + helpLoad: function(panelId){ + if (!ModuleBuilder.panelHelp) return; + + if ( ! ModuleBuilder.AllHelpLang ) ModuleBuilder.AllHelpLang = SUGAR.language.get('ModuleBuilder', 'help'); + + if ( ModuleBuilder.panelHelp [ panelId ] ) + { + ModuleBuilder.helpLang = ModuleBuilder.AllHelpLang[ ModuleBuilder.panelHelp [ panelId ].lang ]; + ModuleBuilder.helpDefault = ModuleBuilder.panelHelp [ panelId ].def ; + ModuleBuilder.helpToggle('default'); + } + }, + helpToggle: function(name){ + if (name == 'default') + name = ModuleBuilder.helpDefault; + if (ModuleBuilder.helpLang != null && typeof(ModuleBuilder.helpLang[name]) != 'undefined') { + document.getElementById('mbhelp').innerHTML = ModuleBuilder.helpLang[name]; + } + }, + handleSave: function(form, callBack){ + if (check_form(form)) { + ModuleBuilder.state.isDirty=false; + ModuleBuilder.submitForm(form, callBack); + } + }, + //Tree Functions + handleTreeClick: function(o) { + var node = o.node; + ModuleBuilder.getContent(node.data.action); + return false; + }, + treeSubscribe:function(tree){ + tree.subscribe("labelClick", ModuleBuilder.treeLabelClick); + }, + treeRefresh:function(type){ + ModuleBuilder.getContent('module=ModuleBuilder&action=ViewTree&tree=' + type); + }, + //MB Specific + addModule: function(MBpackage){ + ModuleBuilder.getContent('module=ModuleBuilder&action=module&view_package=' + MBpackage); + }, + viewModule: function(MBpackage, module){ + ModuleBuilder.getContent('module=ModuleBuilder&action=module&view_package=' + MBpackage + '&view_module=' + module); + }, + packageDelete: function(MBpackage){ + ajaxStatus.showStatus(SUGAR.language.get('ModuleBuilder', 'LBL_AJAX_DELETING')); + if (confirm(SUGAR.language.get('ModuleBuilder', 'LBL_JS_REMOVE_PACKAGE'))) { + ModuleBuilder.getContent('module=ModuleBuilder&action=DeletePackage&package=' + MBpackage); + var node = ModuleBuilder.tree.getNodeByProperty('id', 'package_tree/' + MBpackage); + if (node) ModuleBuilder.tree.removeNode(node, true); + } + }, + packagePublish: function(form){ + if (check_form(form)) { + ajaxStatus.showStatus(SUGAR.language.get('ModuleBuilder', 'LBL_AJAX_BUILDPROGRESS')); + ModuleBuilder.submitForm(form, ModuleBuilder.packageBuild); + } + }, + packageBuild: function(o){ + //make sure no user changes were made + document.CreatePackage.action.value = 'BuildPackage'; + document.CreatePackage.submit(); + ajaxStatus.flashStatus(SUGAR.language.get('app_strings', 'LBL_REQUEST_PROCESSED'), 2000); + ModuleBuilder.callLock = false; + }, + packageDeploy: function(form, deployed){ + var confirmed = true; + if (deployed){ + confirmed = confirm(SUGAR.language.get('ModuleBuilder', 'LBL_JS_DEPLOY_PACKAGE')); + } + if (confirmed && check_form(form)) { + ajaxStatus.showStatus(SUGAR.language.get('ModuleBuilder', 'LBL_AJAX_DEPLOYPROGRESS')); + ModuleBuilder.submitForm(form, ModuleBuilder.packageInstall); + } + }, + packageInstall: function(o){ + //make sure no user changes were made + document.CreatePackage.action.value = 'displaydeploy'; + ModuleBuilder.callLock = false; + ModuleBuilder.submitForm('CreatePackage', ModuleBuilder.packageInstallCleanup); + }, + packageInstallCleanup: function(o){ + //make sure no user changes were made + document.CreatePackage.action.value = 'displaydeploy'; + ModuleBuilder.callLock = false; + ModuleBuilder.submitForm('CreatePackage'); + }, + beginDeploy: function(p){ + ModuleBuilder.asyncRequest('module=ModuleBuilder&action=DeployPackage&package=' + p, ModuleBuilder.deployComplete); + }, + deployComplete: function(o){ + var resp = o.responseText; + + //check if the deploy completed + if (!resp.match(/^\s*(\s*(Table already exists : [\w_]*)(
    )*\s*)*complete$/m)) + { + //Unknown error occured, warn the user + alert(SUGAR.language.get("ModuleBuilder", "LBL_DEPLOY_FAILED")); + } + //Cleanup in the background + ModuleBuilder.asyncRequest( + 'module=Administration&action=RebuildRelationship&silent=true', + function(){} + ); + ModuleBuilder.asyncRequest( + 'module=Administration&action=RebuildDashlets&silent=true', + function(){} + ); + + ModuleBuilder.failed = function(){}; + ModuleBuilder.state.hideFailedMesage = true; + //Reload the page + window.setTimeout("window.location.assign(window.location.href.split('#')[0])", 2000); + + + }, + packageExport: function(form){ + if (check_form(form)) { + ajaxStatus.showStatus(SUGAR.language.get('ModuleBuilder', 'LBL_AJAX_BUILDPROGRESS')); + ModuleBuilder.submitForm(form, ModuleBuilder.packageExportProject); + } + }, + packageExportProject: function(o){ + //make sure no user changes were made + document.CreatePackage.action.value = 'ExportPackage'; + document.CreatePackage.submit(); + ajaxStatus.flashStatus(SUGAR.language.get('app_strings', 'LBL_REQUEST_PROCESSED'), 2000); + ModuleBuilder.callLock = false; + }, + moduleDelete: function(MBpackage, module){ + ajaxStatus.showStatus(SUGAR.language.get('ModuleBuilder', 'LBL_AJAX_DELETING')); + if (confirm(SUGAR.language.get('ModuleBuilder', 'LBL_JS_REMOVE_MODULE'))) { + ModuleBuilder.getContent('module=ModuleBuilder&action=DeleteModule&package=' + MBpackage + '&view_module=' + module); + var node = ModuleBuilder.tree.getNodeByProperty('id', 'package_tree/' + MBpackage + '/' + module); + if (node) ModuleBuilder.tree.removeNode(node, true); + } + }, + moduleViewFields: function(o){ + + ModuleBuilder.callLock = false; + + ModuleBuilder.getContent('module=ModuleBuilder&action=modulefields&view_package=' + ModuleBuilder.MBpackage + + '&view_module=' + ModuleBuilder.module); + }, + moduleLoadField: function(name, type){ + if (typeof(type) == 'undefined') + type = 0; + if (typeof(formsWithFieldLogic) != 'undefined') + formsWithFieldLogic = 'undefined'; + ModuleBuilder.getContent('module=ModuleBuilder&action=modulefield&view_package=' + ModuleBuilder.MBpackage + + '&view_module=' + ModuleBuilder.module + '&field=' + name + '&type=' + type); + }, + moduleLoadLabels: function(type){ + if (typeof(type) == 'undefined') + type = 0; + else + if (type == "studio") { + ModuleBuilder.getContent('module=ModuleBuilder&action=editLabels&view_module=' + ModuleBuilder.module); + } + else + if (type == "mb") { + ModuleBuilder.getContent('module=ModuleBuilder&action=modulelabels&view_package=' + ModuleBuilder.MBpackage + '&view_module=' + ModuleBuilder.module + '&type=' + type); + } + }, + moduleViewRelationships: function(o){ + ModuleBuilder.callLock = false; + ModuleBuilder.getContent('module=ModuleBuilder&action=relationships&view_package=' + ModuleBuilder.MBpackage + '&view_module=' + ModuleBuilder.module); + }, + moduleLoadRelationship2: function(name, resetLabel, checkLanguage) { + if (resetLabel && Dom.get('rhs_label')) { + Dom.get('rhs_label').value = ""; + } + var panel = ModuleBuilder.findTabById('relEditor'); + if (!panel) { + panel = new YAHOO.SUGAR.ClosableTab({ + label: SUGAR.language.get("ModuleBuilder", "LBL_RELATIONSHIP_EDIT"), + id: 'relEditor', + scroll: true, + cacheData: true, + active :true + }, ModuleBuilder.tabPanel); + ModuleBuilder.tabPanel.addTab(panel); + } else { + ModuleBuilder.tabPanel.set("activeTab", panel); + } + var rtField = Dom.get('relationship_type_field'); + var relType = rtField ? rtField.options[rtField.selectedIndex].value: ""; + if (name == "") { + name = Dom.get('rel_name_id') ? Dom.get('rel_name_id').value : ""; + } + var params = { + module: 'ModuleBuilder', + action: 'relationship', + view_package: ModuleBuilder.MBpackage, + view_module: ModuleBuilder.module, + relationship_name: name, + relationship_type: relType, + lhs_module: Dom.get('lhs_mod_field') ? Dom.get('lhs_mod_field').value : document.forms.relform ? document.forms.relform.lhs_module.value : "", + rhs_module: Dom.get('rhs_mod_field') ? Dom.get('rhs_mod_field').value : "", + lhs_label: Dom.get('lhs_label') ? Dom.get('lhs_label').value : "", + rhs_label: Dom.get('rhs_label') ? Dom.get('rhs_label').value : "", + json: false, + id:'relEditor' + }; + if(checkLanguage){ + params['relationship_lang'] = Dom.get('relationship_lang').value; + params['ajaxLoad'] = '1'; + } + ModuleBuilder.asyncRequest(params, function(o) { + ajaxStatus.hideStatus(); + var tab = ModuleBuilder.findTabById('relEditor'); + tab.set("content", o.responseText); + SUGAR.util.evalScript(o.responseText); + }); + }, + moduleDropDown: function(name, field){ + ModuleBuilder.getContent('module=ModuleBuilder&action=dropdown&view_package=' + ModuleBuilder.MBpackage + '&view_module=' + ModuleBuilder.module + '&dropdown_name=' + name + '&field=' + field); + }, + moduleViewLayouts: function(o){ + ModuleBuilder.callLock = false; + ModuleBuilder.getContent('module=ModuleBuilder&MB=1&action=wizard&view_package=' + ModuleBuilder.MBpackage + '&view_module=' + ModuleBuilder.module); + }, + findTabById : function(id) { + var tabs = ModuleBuilder.tabPanel.get("tabs"); + for (var i = 0; i < tabs.length; i++) { + if (tabs[i].get("id") == id) + return tabs[i]; + } + return null; + }, + autoSetLayout: function(){ + var mp = ModuleBuilder.mainPanel; + var c = Dom.get("mblayout"); + mp.set("height", Dom.getViewportHeight() - Dom.getY(c) - 30); + mp.set("width", Dom.getViewportWidth() - 40); + mp.resize(true); + var tabEl = ModuleBuilder.tabPanel.get("element"); + Dom.setStyle(tabEl.firstChild.nextSibling, "overflow-y", "auto"); + Dom.setStyle(tabEl.firstChild.nextSibling, "height", tabEl.offsetHeight - ModuleBuilder.tabPanel.get("element").firstChild.offsetHeight - 5 + "px"); + //Resize editor layouts + if (document.getElementById('toolbox')) Studio2.resizeDivs(); + if (document.getElementById('edittabs')) resizeDDLists(); + }, + paramsToUrl : function (params) { + url = ""; + for (i in params) { + url += i + "=" + params[i] + "&"; + } + return url; + }, + asyncRequest : function(params, callback) { + var url; + if (typeof params == "object") { + url = ModuleBuilder.paramsToUrl(params); + } else { + url = params; + } + ajaxStatus.showStatus(SUGAR.language.get('app_strings', 'LBL_LOADING_PAGE')); + Connect.asyncRequest( + Connect.method, + Connect.url + '&' + url, + {success: callback, failure: ModuleBuilder.failed} + ); + }, + refreshGlobalDropDown: function(o){ + // just clear the callLock; the convention is that this is done in a handler rather than in updateContent + ModuleBuilder.callLock = false; + ModuleBuilder.updateContent(o); + }, + refreshDropDown: function(){ + ModuleBuilder.callLock = false; + document.popup_form.action.value = 'RefreshField'; + document.popup_form.new_dropdown.value = ModuleBuilder.refreshDD_name; + SimpleList.refreshDD_name = ''; + ModuleBuilder.submitForm("popup_form"); + }, + dropdownChanged: function(value){ + var select = document.getElementById('default[]').options; + while(select.length > 0) { + select[0] = null; + } + ModuleBuilder.asyncRequest( + 'module=ModuleBuilder&action=get_app_list_string&key=' + value + + '&view_package=' + ModuleBuilder.MBpackage + '&view_module=' + ModuleBuilder.module, + ModuleBuilder.dropdownChangedCallback + ); + }, + dropdownChangedCallback : function(o) { + var ajaxResponse = YAHOO.lang.JSON.parse(o.responseText); + var select = document.getElementById('default[]').options; + var count = 0; + for (var key in ajaxResponse) { + select[count] = new Option(ajaxResponse[key], key); + count++; + } + }, + setSelectedOption : function (sel, option) + { + var sel = Dom.get(sel); + for (var i = 0; i < sel.options.length; i++) + { + if(sel.options[i].value == option) { + sel.selectedIndex = i; + return true; + } + } + return false; + } + }; + ModuleBuilder.buttons = {}; + ModuleBuilder.selected = {}; + ModuleBuilder.callLock = false; +} +})(); \ No newline at end of file diff --git a/modules/ModuleBuilder/javascript/SimpleList.js b/modules/ModuleBuilder/javascript/SimpleList.js new file mode 100644 index 00000000..c1041594 --- /dev/null +++ b/modules/ModuleBuilder/javascript/SimpleList.js @@ -0,0 +1,309 @@ +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +if(typeof(SimpleList) == 'undefined'){ + var Dom = YAHOO.util.Dom; + SimpleList = function(){ + var editImage; + var deleteImage; + var ul_list; + var jstransaction; + var lastEdit; + var isIE = isSupportedIE(); + return { + init: function(editImage, deleteImage) { + var ul = document.getElementById('ul1', 'drpdwn'); + SimpleList.lastEdit = null; // Bug 14662 + SimpleList.editImage = editImage; + SimpleList.deleteImage = deleteImage; + new YAHOO.util.DDTarget("ul1"); + + for (i=0;i"; + if(drop_value.value == ""){ + html += "[" + SUGAR.language.get('ModuleBuilder', 'LBL_BLANK') + "]"; + }else{ + html += "["+drop_value.value+"]"; + } + html += ""; + html += ""; + html += "
    + + + + + + + + + + + + + + + + + + + +

    {$MOD.LBL_CONTACT_INFORMATION}

    {$MOD.LBL_FIRST_NAME} {$MOD.LBL_OFFICE_PHONE}
    {$MOD.LBL_LAST_NAME} {$APP.LBL_REQUIRED_SYMBOL}{$MOD.LBL_EMAIL_ADDRESS}
    {$MOD.LBL_LEAD_SOURCE}
    + + \ No newline at end of file diff --git a/modules/Leads/vardefs.php b/modules/Leads/vardefs.php new file mode 100644 index 00000000..f116873c --- /dev/null +++ b/modules/Leads/vardefs.php @@ -0,0 +1,551 @@ + 'leads','audited'=>true, 'unified_search' => true, 'unified_search_default_enabled' => true, 'duplicate_merge'=>true, + 'comment' => 'Leads are persons of interest early in a sales cycle', 'fields' => array ( + + + 'converted' => + array ( + 'name' => 'converted', + 'vname' => 'LBL_CONVERTED', + 'type' => 'bool', + 'default' => '0', + 'comment' => 'Has Lead been converted to a Contact (and other Sugar objects)' + ), + 'refered_by' => + array ( + 'name' => 'refered_by', + 'vname' => 'LBL_REFERED_BY', + 'type' => 'varchar', + 'len' => '100', + 'comment' => 'Identifies who refered the lead', + 'merge_filter' => 'enabled', + ), + 'lead_source' => + array ( + 'name' => 'lead_source', + 'vname' => 'LBL_LEAD_SOURCE', + 'type' => 'enum', + 'options'=> 'lead_source_dom', + 'len' => '100', + 'audited'=>true, + 'comment' => 'Lead source (ex: Web, print)', + 'merge_filter' => 'enabled', + ), + 'lead_source_description' => + array ( + 'name' => 'lead_source_description', + 'vname' => 'LBL_LEAD_SOURCE_DESCRIPTION', + 'type' => 'text', + 'group'=>'lead_source', + 'comment' => 'Description of the lead source' + ), + 'status' => + array ( + 'name' => 'status', + 'vname' => 'LBL_STATUS', + 'type' => 'enum', + 'len' => '100', + 'options' => 'lead_status_dom', + 'audited'=>true, + 'comment' => 'Status of the lead', + 'merge_filter' => 'enabled', + ), + 'status_description' => + array ( + 'name' => 'status_description', + 'vname' => 'LBL_STATUS_DESCRIPTION', + 'type' => 'text', + 'group'=>'status', + 'comment' => 'Description of the status of the lead' + ), + 'department' => + array ( + 'name' => 'department', + 'vname' => 'LBL_DEPARTMENT', + 'type' => 'varchar', + 'len' => '100', + 'comment' => 'Department the lead belongs to', + 'merge_filter' => 'enabled', + ), + 'reports_to_id' => + array ( + 'name' => 'reports_to_id', + 'vname' => 'LBL_REPORTS_TO_ID', + 'type' => 'id', + 'reportable'=>false, + 'comment' => 'ID of Contact the Lead reports to' + ), + 'report_to_name' => + array ( + 'name' => 'report_to_name', + 'rname' => 'name', + 'id_name' => 'reports_to_id', + 'vname' => 'LBL_REPORTS_TO', + 'type' => 'relate', + // 'link'=>'reports_to_link', + 'table' => 'contacts', + 'isnull' => 'true', + 'module' => 'Contacts', + 'dbType' => 'varchar', + 'len' => 'id', + 'source'=>'non-db', + 'reportable'=>false, + 'massupdate' => false, + ), + 'reports_to_link' => + array ( + 'name' => 'reports_to_link', + 'type' => 'link', + 'relationship' => 'lead_direct_reports', + 'link_type'=>'one', + 'side'=>'right', + 'source'=>'non-db', + 'vname'=>'LBL_REPORTS_TO', + ), + /*'acc_name_from_accounts' => + array ( + 'name' => 'acc_name_from_accounts', + 'rname' => 'name', + 'id_name' => 'account_id', + 'vname' => 'LBL_ACCOUNT_NAME_1', + 'type' => 'relate', + 'link' => 'accounts', + 'table' => 'accounts', + 'join_name'=>'accounts', + 'isnull' => 'true', + 'module' => 'Accounts', + 'dbType' => 'varchar', + 'len' => '255', + 'source' => 'non-db', + 'unified_search' => false, + 'massupdate' => false, + 'studio' => 'false', + ), + */ + 'account_name' => + array ( + 'name' => 'account_name', + 'vname' => 'LBL_ACCOUNT_NAME', + 'type' => 'varchar', + 'len' => '255', + 'unified_search' => true, + 'comment' => 'Account name for lead', + ), + + + 'accounts' => + array ( + 'name' => 'accounts', + 'type' => 'link', + 'relationship' => 'account_leads', + 'link_type' => 'one', + 'source' => 'non-db', + 'vname' => 'LBL_ACCOUNT', + 'duplicate_merge'=> 'disabled', + ), + + 'account_description' => + array ( + 'name' => 'account_description', + 'vname' => 'LBL_ACCOUNT_DESCRIPTION', + 'type' => 'text', + 'group'=>'account_name', + 'unified_search' => true, + 'comment' => 'Description of lead account' + ), + 'contact_id' => + array ( + 'name' => 'contact_id', + 'type' => 'id', + 'reportable'=>false, + 'vname'=>'LBL_CONTACT_ID', + 'comment' => 'If converted, Contact ID resulting from the conversion' + ), + 'account_id' => + array ( + 'name' => 'account_id', + 'type' => 'id', + 'reportable'=>false, + 'vname'=>'LBL_ACCOUNT_ID', + 'comment' => 'If converted, Account ID resulting from the conversion' + ), + 'opportunity_id' => + array ( + 'name' => 'opportunity_id', + 'type' => 'id', + 'reportable'=>false, + 'vname'=>'LBL_OPPORTUNITY_ID', + 'comment' => 'If converted, Opportunity ID resulting from the conversion' + ), + 'opportunity_name' => + array ( + 'name' => 'opportunity_name', + 'vname' => 'LBL_OPPORTUNITY_NAME', + 'type' => 'varchar', + 'len' => '255', + 'comment' => 'Opportunity name associated with lead' + ), + 'opportunity_amount' => + array ( + 'name' => 'opportunity_amount', + 'vname' => 'LBL_OPPORTUNITY_AMOUNT', + 'type' => 'varchar', + 'group'=>'opportunity_name', + 'len' => '50', + 'comment' => 'Amount of the opportunity' + ), + 'campaign_id' => + array ( + 'name' => 'campaign_id', + 'type' => 'id', + 'reportable'=>false, + 'vname'=>'LBL_CAMPAIGN_ID', + 'comment' => 'Campaign that generated lead' + ), + + 'campaign_name' => + array ( + 'name' => 'campaign_name', + 'rname' => 'name', + 'id_name' => 'campaign_id', + 'vname' => 'LBL_CAMPAIGN', + 'type' => 'relate', + 'link' => 'campaign_leads', + 'table' => 'campaigns', + 'isnull' => 'true', + 'module' => 'Campaigns', + 'source' => 'non-db', + ), + 'campaign_leads' => + array ( + 'name' => 'campaign_leads', + 'type' => 'link', + 'vname' => 'LBL_CAMPAIGN_LEAD', + 'relationship' => 'campaign_leads', + 'source' => 'non-db', + ), + 'c_accept_status_fields' => + array ( + 'name' => 'c_accept_status_fields', + 'rname' => 'id', + 'relationship_fields'=>array('id' => 'accept_status_id', 'accept_status' => 'accept_status_name'), + 'vname' => 'LBL_LIST_ACCEPT_STATUS', + 'type' => 'relate', + 'link' => 'calls', + 'link_type' => 'relationship_info', + 'source' => 'non-db', + 'importable' => 'false', + 'duplicate_merge'=> 'disabled', + 'studio' => array('listview' => false), + ), + 'm_accept_status_fields' => + array ( + 'name' => 'm_accept_status_fields', + 'rname' => 'id', + 'relationship_fields'=>array('id' => 'accept_status_id', 'accept_status' => 'accept_status_name'), + 'vname' => 'LBL_LIST_ACCEPT_STATUS', + 'type' => 'relate', + 'link' => 'meetings', + 'link_type' => 'relationship_info', + 'source' => 'non-db', + 'importable' => 'false', + 'hideacl'=>true, + 'duplicate_merge'=> 'disabled', + 'studio' => array('listview' => false), + ), + 'accept_status_id' => + array( + 'name' => 'accept_status_id', + 'type' => 'varchar', + 'source' => 'non-db', + 'vname' => 'LBL_LIST_ACCEPT_STATUS', + 'studio' => array('listview' => false), + ), + 'accept_status_name' => + array( + 'massupdate' => false, + 'name' => 'accept_status_name', + 'type' => 'enum', + 'source' => 'non-db', + 'vname' => 'LBL_LIST_ACCEPT_STATUS', + 'options' => 'dom_meeting_accept_status', + 'importable' => 'false', + ), + 'webtolead_email1' => + array ( + 'name' => 'webtolead_email1', + 'vname' => 'LBL_EMAIL_ADDRESS', + 'type' => 'email', + 'len' => '100', + 'source' => 'non-db', + 'comment' => 'Main email address of lead', + 'importable' => 'false', + 'studio' => 'false', + ), + 'webtolead_email2' => + array ( + 'name' => 'webtolead_email2', + 'vname' => 'LBL_OTHER_EMAIL_ADDRESS', + 'type' => 'email', + 'len' => '100', + 'source' => 'non-db', + 'comment' => 'Secondary email address of lead', + 'importable' => 'false', + 'studio' => 'false', + ), + 'webtolead_email_opt_out' => + array ( + 'name' => 'webtolead_email_opt_out', + 'vname' => 'LBL_EMAIL_OPT_OUT', + 'type' => 'bool', + 'source' => 'non-db', + 'comment' => 'Indicator signaling if lead elects to opt out of email campaigns', + 'importable' => 'false', + 'massupdate' => false, + 'studio'=>'false', + ), +'webtolead_invalid_email' => + array ( + 'name' => 'webtolead_invalid_email', + 'vname' => 'LBL_INVALID_EMAIL', + 'type' => 'bool', + 'source' => 'non-db', + 'comment' => 'Indicator that email address for lead is invalid', + 'importable' => 'false', + 'massupdate' => false, + 'studio'=>'false', + ), +'birthdate' => + array ( + 'name' => 'birthdate', + 'vname' => 'LBL_BIRTHDATE', + 'massupdate' => false, + 'type' => 'date', + 'comment' => 'The birthdate of the contact' + ), + + 'portal_name' => + array ( + 'name' => 'portal_name', + 'vname' => 'LBL_PORTAL_NAME', + 'type' => 'varchar', + 'len' => '255', + 'group'=>'portal', + 'comment' => 'Portal user name when lead created via lead portal', + //BEGIN SUGARCRM flav!=ent + 'studio' => 'false', + //END SUGARCRM + ), + 'portal_app' => + array ( + 'name' => 'portal_app', + 'vname' => 'LBL_PORTAL_APP', + 'type' => 'varchar', + 'group'=>'portal', + 'len' => '255', + 'comment' => 'Portal application that resulted in created of lead', + //BEGIN SUGARCRM flav!=ent + 'studio' => 'false', + ), + 'website' => + array ( + 'name' => 'website', + 'vname' => 'LBL_WEBSITE', + 'type' => 'url', + 'dbType' => 'varchar', + 'len' => 255, + 'comment' => 'URL of website for the company', + ), + + 'tasks' => + array ( + 'name' => 'tasks', + 'type' => 'link', + 'relationship' => 'lead_tasks', + 'source'=>'non-db', + 'vname'=>'LBL_TASKS', + ), + 'notes' => + array ( + 'name' => 'notes', + 'type' => 'link', + 'relationship' => 'lead_notes', + 'source'=>'non-db', + 'vname'=>'LBL_NOTES', + ), + 'meetings' => + array ( + 'name' => 'meetings', + 'type' => 'link', + 'relationship' => 'meetings_leads', + 'source'=>'non-db', + 'vname'=>'LBL_MEETINGS', + ), + 'calls' => + array ( + 'name' => 'calls', + 'type' => 'link', + 'relationship' => 'calls_leads', + 'source'=>'non-db', + 'vname'=>'LBL_CALLS', + ), + 'oldmeetings' => + array ( + 'name' => 'oldmeetings', + 'type' => 'link', + 'relationship' => 'lead_meetings', + 'source'=>'non-db', + 'vname'=>'LBL_MEETINGS', + ), + 'oldcalls' => + array ( + 'name' => 'oldcalls', + 'type' => 'link', + 'relationship' => 'lead_calls', + 'source'=>'non-db', + 'vname'=>'LBL_CALLS', + ), + 'emails' => + array ( + 'name' => 'emails', + 'type' => 'link', + 'relationship' => 'emails_leads_rel', + 'source'=>'non-db', + 'unified_search'=>true, + 'vname'=>'LBL_EMAILS', + ), + 'email_addresses' => + array ( + 'name' => 'email_addresses', + 'type' => 'link', + 'relationship' => 'leads_email_addresses', + 'source' => 'non-db', + 'vname' => 'LBL_EMAIL_ADDRESSES', + 'reportable'=>false, + 'rel_fields' => array('primary_address' => array('type'=>'bool')), + ), + 'email_addresses_primary' => + array ( + 'name' => 'email_addresses_primary', + 'type' => 'link', + 'relationship' => 'leads_email_addresses_primary', + 'source' => 'non-db', + 'vname' => 'LBL_EMAIL_ADDRESS_PRIMARY', + 'duplicate_merge'=> 'disabled', + ), + 'campaigns' => + array ( + 'name' => 'campaigns', + 'type' => 'link', + 'relationship' => 'lead_campaign_log', + 'module'=>'CampaignLog', + 'bean_name'=>'CampaignLog', + 'source'=>'non-db', + 'vname'=>'LBL_CAMPAIGNLOG', + ), + 'prospect_lists' => + array ( + 'name' => 'prospect_lists', + 'type' => 'link', + 'relationship' => 'prospect_list_leads', + 'module'=>'ProspectLists', + 'source'=>'non-db', + 'vname'=>'LBL_PROSPECT_LIST', + ), + +) + , 'indices' => array ( + array('name' =>'idx_lead_acct_name_first', 'type'=>'index', 'fields'=>array('account_name','deleted')), + array('name' =>'idx_lead_last_first', 'type'=>'index', 'fields'=>array('last_name','first_name','deleted')), + array('name' =>'idx_lead_del_stat', 'type'=>'index', 'fields'=>array('last_name','status','deleted','first_name')), + array('name' =>'idx_lead_opp_del', 'type'=>'index', 'fields'=>array('opportunity_id','deleted',)), + array('name' =>'idx_leads_acct_del', 'type'=>'index', 'fields'=>array('account_id','deleted',)), + array('name' => 'idx_del_user', 'type' => 'index', 'fields'=> array('deleted', 'assigned_user_id')), + array('name' =>'idx_lead_assigned', 'type'=>'index', 'fields'=>array('assigned_user_id')), + array('name' =>'idx_lead_contact', 'type'=>'index', 'fields'=>array('contact_id')), + array('name' =>'idx_reports_to', 'type'=>'index', 'fields'=>array('reports_to_id')), + + ) +, 'relationships' => array ( + 'lead_direct_reports' => array('lhs_module'=> 'Leads', 'lhs_table'=> 'leads', 'lhs_key' => 'id', + 'rhs_module'=> 'Leads', 'rhs_table'=> 'leads', 'rhs_key' => 'reports_to_id', + 'relationship_type'=>'one-to-many'), + 'lead_tasks' => array('lhs_module'=> 'Leads', 'lhs_table'=> 'leads', 'lhs_key' => 'id', + 'rhs_module'=> 'Tasks', 'rhs_table'=> 'tasks', 'rhs_key' => 'parent_id', + 'relationship_type'=>'one-to-many', 'relationship_role_column'=>'parent_type', + 'relationship_role_column_value'=>'Leads') + ,'lead_notes' => array('lhs_module'=> 'Leads', 'lhs_table'=> 'leads', 'lhs_key' => 'id', + 'rhs_module'=> 'Notes', 'rhs_table'=> 'notes', 'rhs_key' => 'parent_id', + 'relationship_type'=>'one-to-many', 'relationship_role_column'=>'parent_type', + 'relationship_role_column_value'=>'Leads') + + ,'lead_meetings' => array('lhs_module'=> 'Leads', 'lhs_table'=> 'leads', 'lhs_key' => 'id', + 'rhs_module'=> 'Meetings', 'rhs_table'=> 'meetings', 'rhs_key' => 'parent_id', + 'relationship_type'=>'one-to-many', 'relationship_role_column'=>'parent_type', + 'relationship_role_column_value'=>'Leads') + + ,'lead_calls' => array('lhs_module'=> 'Leads', 'lhs_table'=> 'leads', 'lhs_key' => 'id', + 'rhs_module'=> 'Calls', 'rhs_table'=> 'calls', 'rhs_key' => 'parent_id', + 'relationship_type'=>'one-to-many', 'relationship_role_column'=>'parent_type', + 'relationship_role_column_value'=>'Leads') + + ,'lead_emails' => array('lhs_module'=> 'Leads', 'lhs_table'=> 'leads', 'lhs_key' => 'id', + 'rhs_module'=> 'Emails', 'rhs_table'=> 'emails', 'rhs_key' => 'parent_id', + 'relationship_type'=>'one-to-many', 'relationship_role_column'=>'parent_type', + 'relationship_role_column_value'=>'Leads'), + 'lead_campaign_log' => array( + 'lhs_module' => 'Leads', + 'lhs_table' => 'leads', + 'lhs_key' => 'id', + 'rhs_module' => 'CampaignLog', + 'rhs_table' => 'campaign_log', + 'rhs_key' => 'target_id', + 'relationship_type' =>'one-to-many' + ) + + ) + //This enables optimistic locking for Saves From EditView + ,'optimistic_locking'=>true, +); + +VardefManager::createVardef('Leads','Lead', array('default', 'assignable', +'person')); + + +?> diff --git a/modules/Leads/views/view.convertlead.php b/modules/Leads/views/view.convertlead.php new file mode 100644 index 00000000..52e072ec --- /dev/null +++ b/modules/Leads/views/view.convertlead.php @@ -0,0 +1,741 @@ +medataDataFile = $this->fileName; + if (file_exists("custom/$this->fileName")) + { + $this->medataDataFile = "custom/$this->fileName"; + } + } + + public function preDisplay() + { + if (!$this->bean->ACLAccess('edit')) { + ACLController::displayNoAccess(); + sugar_die(''); + } + } + + /** + * @see SugarView::display() + */ + public function display() + { + if (!empty($_REQUEST['handle']) && $_REQUEST['handle'] == 'save') + { + return $this->handleSave(); + } + + global $beanList; + + // get the EditView defs to check if opportunity_name exists, for a check below for populating data + $opportunityNameInLayout = false; + $editviewFile = 'modules/Leads/metadata/editviewdefs.php'; + $this->medataDataFile = $editviewFile; + if (file_exists("custom/{$editviewFile}")) + { + $this->medataDataFile = "custom/{$editviewFile}"; + } + include($this->medataDataFile); + foreach($viewdefs['Leads']['EditView']['panels'] as $panel_index => $section){ + foreach($section as $row_array){ + foreach($row_array as $cell){ + if(isset($cell['name']) && $cell['name'] == 'opportunity_name'){ + $opportunityNameInLayout = true; + } + } + } + } + + $this->medataDataFile = $this->fileName; + if (file_exists("custom/$this->fileName")) + { + $this->medataDataFile = "custom/$this->fileName"; + } + $this->loadDefs(); + $this->getRecord(); + $this->checkForDuplicates($this->focus); + $smarty = new Sugar_Smarty(); + $ev = new EditView(); + $ev->ss = $smarty; + $ev->view = "ConvertLead"; + echo $this->getModuleTitle(); + + require_once("include/QuickSearchDefaults.php"); + $qsd = new QuickSearchDefaults(); + $qsd->setFormName("ConvertLead"); + + $this->contact = new Contact(); + $smarty->assign("contact_def", $this->contact->field_defs); + $smarty->assign("form_name", "ConvertLead"); + $smarty->assign("form_id", "ConvertLead"); + $smarty->assign("module", "Leads"); + $smarty->assign("view", "convertlead"); + $smarty->assign("bean", $this->focus); + $smarty->assign("record_id", $this->focus->id); + $smarty->display("modules/Leads/tpls/ConvertLeadHeader.tpl"); + + echo "
    "; + + foreach($this->defs as $module => $vdef) + { + $bean = $beanList[$module]; + $focus = new $bean(); + $focus->fill_in_additional_detail_fields(); + foreach($focus->field_defs as $field => $def) + { + if(isset($vdef[$ev->view]['copyData']) && $vdef[$ev->view]['copyData']) + { + if ($module == "Accounts" && $field == 'name') + { + $focus->name = $this->focus->account_name; + } + else if ($module == "Opportunities" && $field == 'amount') + { + $focus->amount = unformat_number($this->focus->opportunity_amount); + } + else if ($module == "Opportunities" && $field == 'name') { + if ($opportunityNameInLayout && !empty($this->focus->opportunity_name)){ + $focus->name = $this->focus->opportunity_name; + } + } + else if ($field == "id") + { + //If it is not a contact, don't copy the ID from the lead + if ($module == "Contacts") { + $focus->$field = $this->focus->$field; + } + } else if (is_a($focus, "Company") && $field == 'phone_office') + { + //Special case where company and person have the same field with a different name + $focus->phone_office = $this->focus->phone_work; + } + else if (isset($this->focus->$field)) + { + $focus->$field = $this->focus->$field; + } + } + } + + //Copy over email data + $ev->setup($module, $focus, $this->medataDataFile, "modules/Leads/tpls/ConvertLead.tpl", false); + $ev->process(); + echo($ev->display(false)); + echo($this->getValidationJS($module, $focus, $vdef[$ev->view])); + } + echo "
    "; + echo ($qsd->getQSScriptsJSONAlreadyDefined()); + $smarty->display("modules/Leads/tpls/ConvertLeadFooter.tpl"); + } + + protected function getRecord() + { + $this->focus = new Lead(); + if (isset($_REQUEST['record'])) + { + $this->focus->retrieve($_REQUEST['record']); + } + } + + protected function loadDefs() + { + $viewdefs = array(); + include($this->medataDataFile); + $this->defs = $viewdefs; + } + + /** + * Returns the javascript to enable/disable validation of each module's sub-form + * //TODO: This should probably be on the smarty template + * @param $module String the target module name. + * @param $focus SugarBean instance of the target module. + * @param $focus EditView def for the module. + * @return String, javascript to echo to page. + */ + protected function getValidationJS( + $module, + $focus, + $viewdef + ) + { + $validateSelect = isset($viewdef['required']) && $viewdef['required'] && !empty($viewdef['select']); + $jsOut = " + "; + + return $jsOut; + } + + /** + * Saves a new Contact as well as any related items passed in. + * + * @return null + */ + protected function handleSave() + { + require_once("include/formbase.php"); + $lead = false; + if (!empty($_REQUEST['record'])) + { + $lead = new Lead(); + $lead->retrieve($_REQUEST['record']); + } + + global $beanList; + $this->loadDefs(); + $beans = array(); + $selectedBeans = array(); + $selects = array(); + //Make sure the contact object is availible for relationships. + $beans['Contacts'] = new Contact(); + $beans['Contacts']->id = create_guid(); + $beans['Contacts']->new_with_id = true; + + // Bug 39287 - Check for Duplicates on selected modules before save + if ( !empty($_REQUEST['selectedContact']) ) { + $beans['Contacts']->retrieve($_REQUEST['selectedContact']); + if ( !empty($beans['Contacts']->id) ) { + $beans['Contacts']->new_with_id = false; + unset($_REQUEST["convert_create_Contacts"]); + unset($_POST["convert_create_Contacts"]); + } + } + elseif (!empty($_REQUEST["convert_create_Contacts"]) && $_REQUEST["convert_create_Contacts"] != "false" && !isset($_POST['ContinueContact'])) { + require_once('modules/Contacts/ContactFormBase.php'); + $contactForm = new ContactFormBase(); + $duplicateContacts = $contactForm->checkForDuplicates('Contacts'); + if(isset($duplicateContacts)){ + echo $contactForm->buildTableForm($duplicateContacts, 'Contacts'); + return; + } + } + if ( !empty($_REQUEST['selectedAccount']) ) { + $_REQUEST['account_id'] = $_REQUEST['selectedAccount']; + unset($_REQUEST["convert_create_Accounts"]); + unset($_POST["convert_create_Accounts"]); + } + elseif (!empty($_REQUEST["convert_create_Accounts"]) && $_REQUEST["convert_create_Accounts"] != "false" && empty($_POST['ContinueAccount'])){ + require_once('modules/Accounts/AccountFormBase.php'); + $accountForm = new AccountFormBase(); + $duplicateAccounts = $accountForm->checkForDuplicates('Accounts'); + if(isset($duplicateAccounts)){ + echo $accountForm->buildTableForm($duplicateAccounts); + return; + } + } + + foreach($this->defs as $module => $vdef) + { + //Create a new record if "create" was selected + if (!empty($_REQUEST["convert_create_$module"]) && $_REQUEST["convert_create_$module"] != "false") + { + //Save the new record + $bean = $beanList[$module]; + if (empty($beans[$module])) + $beans[$module] = new $bean(); + + $this->populateNewBean($module, $beans[$module], $beans['Contacts'], $lead); + + } + //If an existing bean was selected, relate it to the contact + else if (!empty($vdef['ConvertLead']['select'])) { + //Save the new record + $select = $vdef['ConvertLead']['select']; + $fieldDef = $beans['Contacts']->field_defs[$select]; + if (!empty($fieldDef['id_name']) && !empty($_REQUEST[$fieldDef['id_name']])) + { + $beans['Contacts']->$fieldDef['id_name'] = $_REQUEST[$fieldDef['id_name']]; + $selects[$module] = $_REQUEST[$fieldDef['id_name']]; + if (!empty($_REQUEST[$select])) + { + $beans['Contacts']->$select = $_REQUEST[$select]; + } + // Bug 39268 - Add the existing beans to a list of beans we'll potentially add the lead's activities to + $bean = loadBean($module); + $bean->retrieve($_REQUEST[$fieldDef['id_name']]); + $selectedBeans[$module] = $bean; + } + } + } + + $this->handleActivities($lead, $beans); + // Bug 39268 - Add the lead's activities to the selected beans + $this->handleActivities($lead, $selectedBeans); + + //link selected account to lead if it exists + if(!empty($selectedBeans['Accounts'])){ + $lead->account_id = $selectedBeans['Accounts']->id; + } + + //Handle non-contacts relationships + foreach($beans as $bean) + { + if (!empty($lead)) + { + if (empty($bean->assigned_user_id)) + { + $bean->assigned_user_id = $lead->assigned_user_id; + } + $leadsRel = $this->findRelationship($bean, $lead); + if (!empty($leadsRel)) + { + + $bean->load_relationship ($leadsRel) ; + $relObject = $bean->$leadsRel->getRelationshipObject(); + if ($relObject->relationship_type == "one-to-many" && $bean->$leadsRel->_get_bean_position()) + { + $id_field = $relObject->rhs_key; + $lead->$id_field = $bean->id; + } else { + $bean->$leadsRel->add($lead->id); + } + } + } + //Special case code for opportunities->Accounts + if ($bean->object_name == "Opportunity" && empty($bean->account_id)) + { + if( isset($beans['Accounts'])) { + $bean->account_id = $beans['Accounts']->id; + $bean->account_name = $beans['Accounts']->name; + } + else if (!empty($selects['Accounts'])){ + $bean->account_id = $selects['Accounts']; + } + } + + $this->copyAddressFields($bean, $beans['Contacts']); + + $bean->save(); + } + if (!empty($lead)) + { //Mark the original Lead converted + $lead->status = "Converted"; + $lead->converted = '1'; + $lead->in_workflow = true; + $lead->save(); + } + + $this->displaySaveResults($beans); + } + + protected function displaySaveResults( + $beans + ) + { + global $beanList; + echo "
      "; + foreach($beans as $bean) + { + $beanName = $bean->object_name; + if ( $beanName == 'Contact' && !$bean->new_with_id ) { + echo "
    • " . translate("LBL_EXISTING_CONTACT") . " - + + {$bean->get_summary_text()} +
    • "; + } + else { + global $app_list_strings; + if(!empty($app_list_strings['moduleListSingular'][$bean->module_dir])) { + $module_name = $app_list_strings['moduleListSingular'][$bean->module_dir]; + } else { + $module_name = translate('LBL_MODULE_NAME', $bean->module_dir); + } + if(empty($module_name)) { + $module_name = translate($beanName); + } + echo "
    • " . translate("LBL_CREATED_NEW") . ' ' . $module_name . " - + + {$bean->get_summary_text()} +
    • "; + } + } + + echo "
    "; + } + + protected function handleActivities( + $lead, + $beans + ) + { + global $app_list_strings; + $parent_types = $app_list_strings['record_type_display']; + + $activities = $this->getActivitiesFromLead($lead); + + foreach($beans as $module => $bean) + { + if (isset($parent_types[$module])) + { + foreach($activities as $activity) + { + $this->copyActivityAndRelateToBean($activity, $bean); + } + } + } + } + + /** + * Gets the list of activities related to the lead + * @param Lead $lead Lead to get activities from + * @return Array of Activity SugarBeans . + */ + protected function getActivitiesFromLead( + $lead + ) + { + if (!$lead) return; + + global $beanList, $db; + + $activitesList = array("Calls", "Tasks", "Meetings", "Emails", "Notes"); + $activities = array(); + + foreach($activitesList as $module) + { + $beanName = $beanList[$module]; + $activity = new $beanName(); + $query = "SELECT id FROM {$activity->table_name} WHERE parent_id = '{$lead->id}' AND parent_type = 'Leads'"; + $result = $db->query($query,true); + while($row = $db->fetchByAssoc($result)) + { + $activity = new $beanName(); + $activity->retrieve($row['id']); + $activity->fixUpFormatting(); + $activities[] = $activity; + } + } + + return $activities; + } + + protected function copyActivityAndRelateToBean( + $activity, + $bean + ) + { + global $beanList; + + $newActivity = clone $activity; + $newActivity->id = create_guid(); + $newActivity->new_with_id = true; + + //Special case to prevent duplicated tasks from appearing under Contacts multiple times + if ($newActivity->module_dir == "Tasks" && $bean->module_dir != "Contacts") + { + $newActivity->contact_id = $activity->contact_name = ""; + } + + if ($rel = $this->findRelationship($newActivity, $bean)) + { + $newActivity->load_relationship ($rel) ; + $relObj = $newActivity->$rel->getRelationshipObject(); + if ( $relObj->relationship_type=='one-to-one' || $relObj->relationship_type == 'one-to-many' ) + { + $key = $relObj->rhs_key; + $newActivity->$key = $bean->id; + } + $newActivity->$rel->add($bean->id); + $newActivity->parent_id = $bean->id; + $newActivity->parent_type = $bean->module_dir; + $newActivity->update_date_modified = false; //bug 41747 + $newActivity->save(); + if ($newActivity->module_dir == "Notes" && $newActivity->filename) { + UploadFile::duplicate_file($activity->id, $newActivity->id, $newActivity->filename); + } + } + } + + /** + * Populates the passed in Bean fron the contact and the $_REQUEST + * @param String $module Module of new bean + * @param SugarBean $bean SugarBean to be populated. + * @param Contact $contact Contact to relate the bean to. + */ + protected function populateNewBean( + $module, + $bean, + $contact, + $lead + ) + { + populateFromPost($module, $bean, true); + + //Copy data from the contact to new bean + foreach($bean->field_defs as $field => $def) + { + if(!isset($_REQUEST[$module . $field]) && isset($lead->$field) && $field != 'id') + { + $bean->$field = $lead->$field; + if($field == 'date_entered') $bean->$field = gmdate($GLOBALS['timedate']->get_db_date_time_format()); //bug 41030 + } + } + //Try to link to the new contact + $contactRel = ""; + if (!empty($vdef['ConvertLead']['select'])) + { + $select = $vdef['ConvertLead']['select']; + $fieldDef = $contact->field_defs[$select]; + if (!empty($fieldDef['id_name'])) + { + $bean->id = create_guid(); + $bean->new_with_id = true; + $contact->$fieldDef['id_name'] = $bean->id ; + if ($fieldDef['id_name'] != $select) { + $rname = isset($fieldDef['rname']) ? $fieldDef['rname'] : ""; + if (!empty($rname) && isset($bean->$rname)) + $contact->$select = $bean->$rname; + else + $contact->$select = $bean->name; + } + } + } else if ($module != "Contacts"){ + $contactRel = $this->findRelationship($contact, $bean); + if (!empty($contactRel)) + { + $bean->id = create_guid(); + $bean->new_with_id = true; + $contact->load_relationship ($contactRel) ; + $relObject = $contact->$contactRel->getRelationshipObject(); + if ($relObject->relationship_type == "one-to-many" && $contact->$contactRel->_get_bean_position()) + { + $id_field = $relObject->rhs_key; + $bean->$id_field = $contact->id; + } else { + $contact->$contactRel->add($bean->id); + } + //Set the parent of activites to the new Contact + if (isset($bean->field_defs['parent_id']) && isset($bean->field_defs['parent_type'])) + { + $bean->parent_id = $contact->id; + $bean->parent_type = "Contacts"; + } + } + } + } + + protected function copyAddressFields($bean, $contact) + { + //Copy over address info from the contact to any beans with address not set + foreach($bean->field_defs as $field => $def) + { + if(!isset($_REQUEST[$bean->module_dir . $field]) && strpos($field, "_address_") !== false) + { + $set = "primary"; + if (strpos($field, "alt_") !== false || strpos($field, "shipping_") !== false) + $set = "alt"; + $type = ""; + + if(strpos($field, "_address_street_2") !== false) + $type = "_address_street_2"; + else if(strpos($field, "_address_street_3") !== false) + $type = "_address_street_3"; + else if(strpos($field, "_address_street_4") !== false) + $type = ""; + else if(strpos($field, "_address_street") !== false) + $type = "_address_street"; + else if(strpos($field, "_address_city") !== false) + $type = "_address_city"; + else if(strpos($field, "_address_state") !== false) + $type = "_address_state"; + else if(strpos($field, "_address_postalcode") !== false) + $type = "_address_postalcode"; + else if(strpos($field, "_address_country") !== false) + $type = "_address_country"; + + $var = $set.$type; + if (isset($contact->$var)) + $bean->$field = $contact->$var; + } + } + } + + + protected function findRelationship( + $from, + $to + ) + { + global $dictionary; + require_once("modules/TableDictionary.php"); + foreach ($from->field_defs as $field=>$def) + { + if (isset($def['type']) && $def['type'] == "link" && isset($def['relationship'])) { + $rel_name = $def['relationship']; + $rel_def = ""; + if (isset($dictionary[$from->object_name]['relationships']) && isset($dictionary[$from->object_name]['relationships'][$rel_name])) + { + $rel_def = $dictionary[$from->object_name]['relationships'][$rel_name]; + } + else if (isset($dictionary[$to->object_name]['relationships']) && isset($dictionary[$to->object_name]['relationships'][$rel_name])) + { + $rel_def = $dictionary[$to->object_name]['relationships'][$rel_name]; + } + else if (isset($dictionary[$rel_name]) && isset($dictionary[$rel_name]['relationships']) + && isset($dictionary[$rel_name]['relationships'][$rel_name])) + { + $rel_def = $dictionary[$rel_name]['relationships'][$rel_name]; + } + if (!empty($rel_def)) { + if ($rel_def['lhs_module'] == $from->module_dir && $rel_def['rhs_module'] == $to->module_dir ) + { + return $field; + } + else if ($rel_def['rhs_module'] == $from->module_dir && $rel_def['lhs_module'] == $to->module_dir ) + { + return $field; + } + } + } + } + return false; + } + + /** + * @see SugarView::_getModuleTitleParams() + */ + protected function _getModuleTitleParams($browserTitle = false) + { + global $mod_strings; + $params = parent::_getModuleTitleParams($browserTitle); + $params[] = "{$this->bean->name}"; + $params[] = $mod_strings['LBL_CONVERTLEAD']; + return $params; + } + + + protected function checkForDuplicates( + $lead + ) + { + if ($lead->status == "Converted") + { + echo ("" . translate('LBL_CONVERTLEAD_WARNING')); + $dupes = array(); + $q = "SELECT id, first_name, last_name FROM contacts WHERE first_name LIKE '{$lead->first_name}' AND last_name LIKE '{$lead->last_name}'"; + $result = $lead->db->query($q); + while($row = $lead->db->fetchByAssoc($result)) { + $contact = new Contact(); + $contact->retrieve($row['id']); + $dupes[$row['id']] = $contact->name; + } + if (!empty($dupes)) + { + foreach($dupes as $id => $name) + { + echo (translate('LBL_CONVERTLEAD_WARNING_INTO_RECORD') . "$name"); + break; + } + } + echo ""; + } + return false; + } +} diff --git a/modules/Leads/views/view.list.php b/modules/Leads/views/view.list.php new file mode 100644 index 00000000..3b9e544b --- /dev/null +++ b/modules/Leads/views/view.list.php @@ -0,0 +1,48 @@ +lv->targetList = true; + } +} diff --git a/modules/MailMerge/DetailView.php b/modules/MailMerge/DetailView.php new file mode 100644 index 00000000..f209db11 --- /dev/null +++ b/modules/MailMerge/DetailView.php @@ -0,0 +1,40 @@ + diff --git a/modules/MailMerge/EditView.php b/modules/MailMerge/EditView.php new file mode 100644 index 00000000..cf6d886d --- /dev/null +++ b/modules/MailMerge/EditView.php @@ -0,0 +1,40 @@ + \ No newline at end of file diff --git a/modules/MailMerge/MailMerge.php b/modules/MailMerge/MailMerge.php new file mode 100644 index 00000000..796a987a --- /dev/null +++ b/modules/MailMerge/MailMerge.php @@ -0,0 +1,153 @@ +mm_data_dir = $data_dir; + $this->list = $list; + $this->fieldList = $fieldList; + } + + function Execute() { + $this->Initialize(); + if( count( $this->list ) > 0 ) { + if(isset($this->template)) { + $this->CreateHeaderFile(); + $this->CreateDataSource(); + $file = $this->CreateDocument($this->template); + return $file; + } + } else return ''; + } + + function Template($template = NULL) { + if(is_array($template)) $this->template = $template; + } + + function CleanUp() { + //remove the temp files + unlink($this->mm_data_dir.'/Temp/'.$this->datasource_file); + unlink($this->mm_data_dir.'/Temp/'.$this->header_file); + rmdir($this->mm_data_dir); + rmdir($this->mm_data_dir.'/Temp/'); + $this->Quit(); + } + + function CreateHeaderFile() { + $this->obj->Documents->Add(); + + $this->obj->ActiveDocument->Tables->Add($this->obj->Selection->Range,1,$this->fieldcnt); + foreach($this->fieldList as $key => $value) { + $this->obj->Selection->TypeText($key); + $this->obj->Selection->MoveRight(); + } + + $this->obj->ActiveDocument->SaveAs($this->mm_data_dir.'/Temp/'.$this->header_file); + $this->obj->ActiveDocument->Close(); + } + + function CreateDataSource() { + $this->obj->Documents->Add(); + $this->obj->ActiveDocument->Tables->Add($this->obj->Selection->Range,$this->rowcnt,$this->fieldcnt); + + for($i = 0; $i < $this->rowcnt; $i++) { + foreach($this->fieldList as $field => $value) + { + $this->obj->Selection->TypeText($this->list[$i]->$field); + $this->obj->Selection->MoveRight(); + } + } + $this->obj->ActiveDocument->SaveAs($this->mm_data_dir.'/Temp/'.$this->datasource_file); + $this->obj->ActiveDocument->Close(); + } + + function CreateDocument($template) { + //$this->obj->Documents->Open($this->mm_data_dir.'/Templates/'.$template[0].'.dot'); + $this->obj->Documents->Open($template[0]); + + $this->obj->ActiveDocument->MailMerge->OpenHeaderSource($this->mm_data_dir.'/Temp/'.$this->header_file); + + $this->obj->ActiveDocument->MailMerge->OpenDataSource($this->mm_data_dir.'/Temp/'.$this->datasource_file); + + $this->obj->ActiveDocument->MailMerge->Execute(); + $this->obj->ActiveDocument->SaveAs($this->mm_data_dir.'/'.$template[1].'.doc'); + //$this->obj->Documents[$template[0]]->Close(); + //$this->obj->Documents[$template[1].'.doc']->Close(); + $this->obj->ActiveDocument->Close(); + return $template[1].'.doc'; + } + + function Initialize() { + $this->rowcnt = count($this->list); + $this->fieldcnt = count($this->fieldList); + $this->obj = new COM("word.application") or die("Unable to instanciate Word"); + $this->obj->Visible = $this->visible; + + //try to make the temp dir + sugar_mkdir($this->mm_data_dir); + sugar_mkdir($this->mm_data_dir.'/Temp/'); + } + + function Quit() { + $this->obj->Quit(); + } + + function SetDataList($list = NULL) { + if(is_array($list)) $this->list = $list; + } + + function SetFieldList($list = NULL) { + if(is_array($list)) $this->fieldList = $list; + } + +} + +?> diff --git a/modules/MailMerge/Menu.php b/modules/MailMerge/Menu.php new file mode 100644 index 00000000..5692926d --- /dev/null +++ b/modules/MailMerge/Menu.php @@ -0,0 +1,51 @@ + \ No newline at end of file diff --git a/modules/MailMerge/Merge.html b/modules/MailMerge/Merge.html new file mode 100644 index 00000000..9432f70e --- /dev/null +++ b/modules/MailMerge/Merge.html @@ -0,0 +1,63 @@ + + +
    +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/modules/MergeRecords/MergeRecord.php b/modules/MergeRecords/MergeRecord.php new file mode 100644 index 00000000..83d0e08b --- /dev/null +++ b/modules/MergeRecords/MergeRecord.php @@ -0,0 +1,348 @@ +load_merge_bean($merge_module, $merge_id); + } + + function retrieve($id) { + if (isset ($_REQUEST['action']) && $_REQUEST['action'] == 'Step2') + $this->load_merge_bean($this->merge_bean, false, $id); + else + parent :: retrieve($id); + } + + function load_merge_bean($merge_module, $load_module_strings = false, $merge_id = '') { + global $moduleList; + global $beanList; + global $beanFiles; + global $current_language; + + $this->merge_module = $merge_module; + $this->merge_bean_class = $beanList[$this->merge_module]; + $this->merge_bean_file_path = $beanFiles[$this->merge_bean_class]; + + require_once ($this->merge_bean_file_path); + $this->merge_bean = new $this->merge_bean_class(); + if ($merge_id != '') + $this->merge_bean->retrieve($merge_id); + + // Bug 18853 - Disable this view if the user doesn't have edit and delete permissions + if ( !$this->merge_bean->ACLAccess('edit') || !$this->merge_bean->ACLAccess('delete') ) { + ACLController::displayNoAccess(); + sugar_die(''); + } + + //load master module strings + if ($load_module_strings) + $this->merge_bean_strings = return_module_language($current_language, $merge_module); + } + + // Bug 22994, when the search key words are in other module, there needs to be another merge_bean. + function load_merge_bean2($merge_module, $load_module_strings = false, $merge_id = '') { + global $moduleList; + global $beanList; + global $beanFiles; + global $current_language; + + $this->merge_module2 = $merge_module; + $this->merge_bean_class2 = $beanList[$this->merge_module2]; + $this->merge_bean_file_path2 = $beanFiles[$this->merge_bean_class2]; + + require_once ($this->merge_bean_file_path2); + $this->merge_bean2 = new $this->merge_bean_class2(); + if ($merge_id != '') + $this->merge_bean2->retrieve($merge_id); + //load master module strings + if ($load_module_strings) + $this->merge_bean_strings2 = return_module_language($current_language, $merge_module); + } + + var $new_schema = true; + + //----------------------------------------------------------------------- + //-------------Wrapping Necessary Merge Bean Calls----------------------- + //----------------------------------------------------------------------- + + function fill_in_additional_list_fields() { + return $this->merge_bean->fill_in_additional_list_fields(); + } + + function fill_in_additional_detail_fields() { + return $this->merge_bean->fill_in_additional_detail_fields(); + } + + function get_summary_text() { + return $this->merge_bean->get_summary_text(); + } + + function get_list_view_data() { + return $this->merge_bean->get_list_view_data(); + } + //----------------------------------------------------------------------- + //----------------------------------------------------------------------- + //----------------------------------------------------------------------- + + /** + builds a generic search based on the query string using or + do not include any $this-> because this is called on without having the class instantiated + */ + function build_generic_where_clause($the_query_string) { + return $this->merge_bean->build_generic_where_clause($the_query_string); + } + + //adding in 4.0+ acl function for possible acl stuff down the line + function bean_implements($interface) { + switch ($interface) { + case 'ACL' : + return true; + } + return false; + } + + function ACLAccess($view,$is_owner='not_set'){ + global $current_user; + + //if the module doesn't implement ACLS or is empty + if(empty($this->merge_bean) || !$this->merge_bean->bean_implements('ACL')) + { + return true; + } + + if($is_owner == 'not_set'){ + $is_owner = $this->merge_bean->isOwner($current_user->id); + } + return ACLController::checkAccess($this->merge_bean->module_dir,'edit', true); + } + + + //keep save function to handle anything special on merges + function save($check_notify = FALSE) { + //something here + return parent :: save($check_notify); + } + + function populate_search_params($search_params) { + foreach ($this->merge_bean->field_defs as $key=>$value) { + $searchFieldString=$key.'SearchField'; + $searchTypeString=$key.'SearchType'; + + if (isset($search_params[$searchFieldString]) ) { + + if (isset($search_params[$searchFieldString]) == '') { + $this->field_search_params[$key]['value']='NULL'; + } else { + $this->field_search_params[$key]['value']=$search_params[$searchFieldString]; + } + if (isset ($search_params[$searchTypeString])) { + $this->field_search_params[$key]['search_type'] = $search_params[$searchTypeString]; + } else { + $this->field_search_params[$key]['search_type'] = 'Exact'; + } + //add field_def to the array. + $this->field_search_params[$key] = array_merge($value,$this->field_search_params[$key] ); + } + } + } + + function get_inputs_for_search_params($search_params) + { + $returnString = ''; + foreach ($this->merge_bean->field_defs as $key=>$value) { + $searchFieldString=$key.'SearchField'; + $searchTypeString=$key.'SearchType'; + + if (isset($search_params[$searchFieldString]) ) { + $returnString .= "\n"; + $returnString .= "\n"; + } + } + + return $returnString; + } + + function email_addresses_query($table, $module, $bean_id) { + $query = $table.".id IN (SELECT ear.bean_id FROM email_addresses ea + LEFT JOIN email_addr_bean_rel ear ON ea.id = ear.email_address_id + WHERE ear.bean_module = '{$module}' + AND ear.bean_id != '{$bean_id}' + AND ear.deleted = 0"; + return $query; + } + + function release_name_query($search_type, $value) { + $this->load_merge_bean2('Releases'); + if($search_type=='like') { + $where = "releases.name LIKE '%".$GLOBALS['db']->quote($value)."%'"; + } + elseif($search_type=='start'){ + $where = "releases.name LIKE '".$GLOBALS['db']->quote($value)."%'"; + } + else { + $where = "releases.name = '".$GLOBALS['db']->quote($value)."'"; + } + $list=$this->merge_bean2->get_releases(false,'Active',$where); + foreach($list as $key => $value){ + $list_to_join[]="'".$GLOBALS['db']->quote($key)."'"; + } + $in=implode(', ', $list_to_join); + return $in; + } + + function create_where_statement() { + $where_clauses = array (); + foreach ($this->field_search_params as $merge_field => $vDefArray) { + if (isset ($vDefArray['source']) && $vDefArray['source'] == 'custom_fields') { + $table_name = $this->merge_bean->table_name."_cstm"; + } else { + $table_name = $this->merge_bean->table_name; + } + + //Should move these if's into a central location for extensibility and addition for other search filters + //Must do the same for pulling values in js dropdown + if (isset ($vDefArray['search_type']) && $vDefArray['search_type'] == 'like') { + if ($merge_field != "email1" && $merge_field != "email2" && $merge_field !="release_name") { + array_push($where_clauses, $table_name.".".$merge_field." LIKE '%".$GLOBALS['db']->quote($vDefArray['value'])."%'"); + } + elseif($merge_field =="release_name"){ + if(isset($vDefArray['value'])){ + $in = $this->release_name_query('like',$vDefArray['value']); + array_push($where_clauses, $table_name.".found_in_release IN ($in)"); + } + } + else { + $query = $this->email_addresses_query($table_name, $this->merge_module, $this->merge_bean->id); + $query .= " AND ea.email_address LIKE '%".$GLOBALS['db']->quote($vDefArray['value'])."%')"; + $where_clauses[] = $query; + } + } + elseif (isset ($vDefArray['search_type']) && $vDefArray['search_type'] == 'start') { + if ($merge_field != "email1" && $merge_field != "email2" && $merge_field !="release_name") { + array_push($where_clauses, $table_name.".".$merge_field." LIKE '".$GLOBALS['db']->quote($vDefArray['value'])."%'"); + } + elseif($merge_field =="release_name"){ + if(isset($vDefArray['value'])){ + $in = $this->release_name_query('start',$vDefArray['value']); + array_push($where_clauses, $table_name.".found_in_release IN ($in)"); + } + } + else { + $query = $this->email_addresses_query($table_name, $this->merge_module, $this->merge_bean->id); + $query .= " AND ea.email_address LIKE '".$GLOBALS['db']->quote($vDefArray['value'])."%')"; + $where_clauses[] = $query; + } + } + else { + if ($merge_field != "email1" && $merge_field != "email2" && $merge_field !="release_name") { + array_push($where_clauses, $table_name.".".$merge_field."='".$GLOBALS['db']->quote($vDefArray['value'])."'"); + } + elseif($merge_field =="release_name"){ + if(isset($vDefArray['value'])){ + $in = $this->release_name_query('exact',$vDefArray['value']); + array_push($where_clauses, $table_name.".found_in_release IN ($in)"); + } + } + else { + $query = $this->email_addresses_query($table_name, $this->merge_module, $this->merge_bean->id); + $query .= " AND ea.email_address = '".$GLOBALS['db']->quote($vDefArray['value'])."')"; + $where_clauses[] = $query; + } + } + } + // Add ACL Check + if($this->merge_bean->bean_implements('ACL') && ACLController::requireOwner($this->merge_bean->module_dir, 'delete') ) + { + global $current_user; + $where_clauses[] = $this->merge_bean->getOwnerWhere($current_user->id); + } + array_push($where_clauses, $this->merge_bean->table_name.".id !='".$GLOBALS['db']->quote($this->merge_bean->id)."'"); + return $where_clauses; + } + + //duplicating utils function for now for possiblity of future or/and and + //other functionality + function generate_where_statement($where_clauses) { + $where = ''; + + foreach ($where_clauses as $clause) { + if ($where != "") + $where .= " AND "; + $where .= $clause; + } + return $where; + } +} +?> \ No newline at end of file diff --git a/modules/MergeRecords/SaveMerge.php b/modules/MergeRecords/SaveMerge.php new file mode 100644 index 00000000..28a8548e --- /dev/null +++ b/modules/MergeRecords/SaveMerge.php @@ -0,0 +1,219 @@ +load_merge_bean($_REQUEST['merge_module'], true, $_REQUEST['record']); + +foreach($focus->merge_bean->column_fields as $field) +{ + if(isset($_POST[$field])) + { + $value = $_POST[$field]; + if(is_array($value) && !empty($focus->merge_bean->field_defs[$field]['isMultiSelect'])) { + if(empty($value[0])) { + unset($value[0]); + } + $value = encodeMultienumValue($value); + } + $focus->merge_bean->$field = $value; + }elseif (isset($focus->merge_bean->field_name_map[$field]['type']) && $focus->merge_bean->field_name_map[$field]['type'] == 'bool' ) { + $focus->merge_bean->$field = 0; + } +} + +foreach($focus->merge_bean->additional_column_fields as $field) +{ + if(isset($_POST[$field])) + { + $value = $_POST[$field]; + if(is_array($value) && !empty($focus->merge_bean->field_defs[$field]->properties['isMultiSelect'])) { + if(empty($value[0])) { + unset($value[0]); + } + $value = encodeMultienumValue($value); + } + $focus->merge_bean->$field = $value; + } +} + +global $check_notify; + +$_REQUEST['useEmailWidget'] = true; +$focus->merge_bean->save($check_notify); +unset($_REQUEST['useEmailWidget']); + +$return_id = $focus->merge_bean->id; +$return_module = $focus->merge_module; +$return_action = 'DetailView'; + +//handle realated data. + +$linked_fields=$focus->merge_bean->get_linked_fields(); + +$exclude = explode(',', $_REQUEST['merged_links']); + +if (is_array($_POST['merged_ids'])) { + foreach ($_POST['merged_ids'] as $id) { + require_once ($focus->merge_bean_file_path); + $mergesource = new $focus->merge_bean_class(); + $mergesource->retrieve($id); + //kbrill Bug #13826 + foreach ($linked_fields as $name => $properties) { + if ($properties['name']=='modified_user_link' || in_array($properties['name'], $exclude)) + { + continue; + } + if (isset($properties['duplicate_merge'])) { + if ($properties['duplicate_merge']=='disabled' or + $properties['duplicate_merge']=='false' or + $properties['name']=='assigned_user_link') { + continue; + } + } + if ($name == 'accounts' && $focus->merge_bean->module_dir == 'Opportunities') + continue; + + + if ($mergesource->load_relationship($name)) { + //check to see if loaded relationship is with email address + $relName=$mergesource->$name->getRelatedModuleName(); + if (!empty($relName) and strtolower($relName)=='emailaddresses'){ + //handle email address merge + handleEmailMerge($focus,$name,$mergesource->$name->get()); + }else{ + $data=$mergesource->$name->get(); + if (is_array($data)) { + if ($focus->merge_bean->load_relationship($name) ) { + foreach ($data as $related_id) { + //add to primary bean + $focus->merge_bean->$name->add($related_id); + } + } + } + } + } + } + //END Bug #13826 + //delete the child bean, this action will cascade into related data too. + $mergesource->mark_deleted($mergesource->id); + } +} +$GLOBALS['log']->debug("Merged record with id of ".$return_id); + +header("Location: index.php?action=$return_action&module=$return_module&record=$return_id"); + + +//This function will compare the email addresses to be merged and only add the email id's +//of the email addresses that are not duplicates. +//$focus - Merge Bean +//$name - name of relationship (email_addresses) +//$data - array of email id's that will be merged into existing bean. +function handleEmailMerge($focus,$name,$data){ + $mrgArray = array(); + //get the email id's to merge + $existingData=$data; + + //make sure id's to merge exist and are in array format + + //get the existing email id's + $focus->merge_bean->load_relationship($name); + $exData=$focus->merge_bean->$name->get(); + + if (!is_array($existingData) || empty($existingData)) { + return ; + } + //query email and retrieve existing email address + $exEmailQuery = 'Select id, email_address from email_addresses where id in ('; + $first = true; + foreach($exData as $id){ + if($first){ + $exEmailQuery .= " '$id' "; + $first = false; + }else{ + $exEmailQuery .= ", '$id' "; + $first = false; + } + } + $exEmailQuery .= ')'; + + $exResult = $focus->merge_bean->db->query($exEmailQuery); + while(($row=$focus->merge_bean->db->fetchByAssoc($exResult))!= null) { + $existingEmails[$row['id']]=$row['email_address']; + } + + + //query email and retrieve email address to be linked. + $newEmailQuery = 'Select id, email_address from email_addresses where id in ('; + $first = true; + foreach($existingData as $id){ + if($first){ + $newEmailQuery .= " '$id' "; + $first = false; + }else{ + $newEmailQuery .= ", '$id' "; + $first = false; + } + } + $newEmailQuery .= ')'; + + $newResult = $focus->merge_bean->db->query($newEmailQuery); + while(($row=$focus->merge_bean->db->fetchByAssoc($newResult))!= null) { + $newEmails[$row['id']]=$row['email_address']; + } + + //compare the two arrays and remove duplicates + foreach($newEmails as $k=>$n){ + if(!in_array($n,$existingEmails)){ + $mrgArray[$k] = $n; + } + } + + //add email id's. + foreach ($mrgArray as $related_id=>$related_val) { + //add to primary bean + $focus->merge_bean->$name->add($related_id); + } +} +?> diff --git a/modules/MergeRecords/SearchForm.html b/modules/MergeRecords/SearchForm.html new file mode 100644 index 00000000..82525ea9 --- /dev/null +++ b/modules/MergeRecords/SearchForm.html @@ -0,0 +1,103 @@ + + + +
    + + + + + + + +

    {MOD.LBL_STEP_5}

     
    +

    + +

    + + +
    +

    + + + diff --git a/modules/MailMerge/Merge.php b/modules/MailMerge/Merge.php new file mode 100644 index 00000000..8a6e4967 --- /dev/null +++ b/modules/MailMerge/Merge.php @@ -0,0 +1,171 @@ +retrieve($document_id); + +if(!empty($relModule)){ +$rel_class_name = $beanList[$relModule ]; +require_once($beanFiles[$rel_class_name]); +$rel_seed = new $rel_class_name(); +} + +global $sugar_config; + +$filter = array(); +if(array_key_exists('mailmerge_filter', $sugar_config)){ + // $filter = $sugar_config['mailmerge_filter']; +} +array_push($filter, 'link'); + +$merge_array = array(); +$merge_array['master_module'] = $module; +$merge_array['related_module'] = $relModule; +//rrs log merge +$ids = array(); + +foreach($item_ids as $key=>$value) +{ + if(!empty($relObjs[$key])){ + $ids[$key] = $relObjs[$key]; + }else{ + $ids[$key] = ''; + } +}//rof +$merge_array['ids'] = $ids; + +$dataDir = getcwd()."/{$GLOBALS['sugar_config']['cache_dir']}MergedDocuments/"; +if(!file_exists($dataDir)) +{ + sugar_mkdir($dataDir); +} +srand((double)microtime()*1000000); +$mTime = microtime(); +$dataFileName = 'sugardata'.$mTime.'.php'; +write_array_to_file('merge_array', $merge_array, $dataDir.$dataFileName); +//Save the temp file so we can remove when we are done +$_SESSION['MAILMERGE_TEMP_FILE_'.$mTime] = $dataDir.$dataFileName; +$site_url = $sugar_config['site_url']; +$templateFile = $site_url.'/'.UploadFile::get_url(from_html($document->filename),$document->id); +$dataFile =$dataFileName; +$redirectUrl = 'index.php?action=index&step=5&module=MailMerge&mtime='.$mTime; +$startUrl = 'index.php?action=index&module=MailMerge&reset=true'; + +$relModule = trim($relModule); +$contents = "SUGARCRM_MAIL_MERGE_TOKEN#$templateFile#$dataFile#$module#$relModule"; + +$rtfFileName = 'sugartokendoc'.$mTime.'.doc'; +$fp = sugar_fopen($dataDir.$rtfFileName, 'w'); +fwrite($fp, $contents); +fclose($fp); + +$_SESSION['mail_merge_file_location'] = $GLOBALS['sugar_config']['cache_dir'].'MergedDocuments/'.$rtfFileName; +$_SESSION['mail_merge_file_name'] = $rtfFileName; + +$xtpl->assign("MAILMERGE_FIREFOX_URL", $site_url .'/'.$GLOBALS['sugar_config']['cache_dir'].'MergedDocuments/'.$rtfFileName); +$xtpl->assign("MAILMERGE_START_URL", $startUrl); +$xtpl->assign("MAILMERGE_TEMPLATE_FILE", $templateFile); +$xtpl->assign("MAILMERGE_DATA_FILE", $dataFile); +$xtpl->assign("MAILMERGE_MODULE", $module); + +$xtpl->assign("MAILMERGE_REL_MODULE", $relModule); +$xtpl->assign("MOD", $mod_strings); +$xtpl->assign("APP", $app_strings); +$xtpl->assign("MAILMERGE_REDIRECT_URL", $redirectUrl); +$xtpl->parse("main"); +$xtpl->out("main"); +?> diff --git a/modules/MailMerge/Save.php b/modules/MailMerge/Save.php new file mode 100644 index 00000000..84b558c2 --- /dev/null +++ b/modules/MailMerge/Save.php @@ -0,0 +1,90 @@ +retrieve($document_id); + +$items = array(); +foreach($item_ids as $key=>$value) +{ + $seed->retrieve($key); + $items[] = $seed; +} + +ini_set('max_execution_time', 600); +ini_set('error_reporting', 'E_ALL'); +$dataDir = getcwd()."\\MergedDocuments\\"; +$fileName = getcwd()."\\".$document->file_url_noimage; +list($outfile, $ext) = preg_split('/[.]/', $document->filename); + +$mm = new MailMerge(null, null, $dataDir); +$mm->SetDataList($items); +$mm->SetFieldList($fields); +$mm->Template(array($fileName, $outfile)); +$file = $mm->Execute(); +$mm->CleanUp(); + +header("Location: index.php?module=MailMerge&action=Step4&file=".urlencode($file)); + + +?> diff --git a/modules/MailMerge/Step1.html b/modules/MailMerge/Step1.html new file mode 100644 index 00000000..6b1893d2 --- /dev/null +++ b/modules/MailMerge/Step1.html @@ -0,0 +1,157 @@ + + + + +
    + + + + + + + + + +

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

    {MOD.LBL_STEP_1}

     
    {MODULE_SELECT} + {ADDIN_NOTICE}
      {MAILMERGE_NUM_SELECTED_OBJECTS}   
        
    {MOD.LBL_MAILMERGE_TEMPLATES}  
     
    +
    +

    + +

    + + +
    +

    +
    +{JAVASCRIPT} + + + + + + + diff --git a/modules/MailMerge/Step1.php b/modules/MailMerge/Step1.php new file mode 100644 index 00000000..8f4c3148 --- /dev/null +++ b/modules/MailMerge/Step1.php @@ -0,0 +1,274 @@ +assign("MOD", $mod_strings); +$xtpl->assign("APP", $app_strings); +$xtpl->assign('JSON_CONFIG_JAVASCRIPT', $json_config->get_static_json_server(false, true)); + +if($_SESSION['MAILMERGE_MODULE'] == 'Campaigns' || $_SESSION['MAILMERGE_MODULE'] == 'CampaignProspects'){ + $modules_array['Campaigns'] = 'Campaigns'; +} +$module_list = $modules_array; + +if(isset($_REQUEST['reset']) && $_REQUEST['reset']) +{ + $_SESSION['MAILMERGE_MODULE'] = null; + $_SESSION['MAILMERGE_DOCUMENT_ID'] = null; + $_SESSION['SELECTED_OBJECTS_DEF'] = null; + $_SESSION['MAILMERGE_SKIP_REL'] = null; + $_SESSION['MAILMERGE_RECORD'] = null; + $_SESSION['MAILMERGE_RECORDS'] = null; + $_SESSION['MAILMERGE_CONTAINS_CONTACT_INFO'] = null; +} +$fromListView = false; +if(!empty($_REQUEST['record'])) +{ + $_SESSION['MAILMERGE_RECORD'] = $_REQUEST['record']; +} +else if(isset($_REQUEST['uid'])) { + $_SESSION['MAILMERGE_RECORD'] = explode(',', $_REQUEST['uid']); + +} +else if(isset($_REQUEST['entire']) && $_REQUEST['entire'] == 'true') { + // do entire list + $focus = 0; + + $bean = $beanList[ $_SESSION['MAILMERGE_MODULE']]; + require_once($beanFiles[$bean]); + $focus = new $bean; + + if(isset($_SESSION['export_where']) && !empty($_SESSION['export_where'])) { // bug 4679 + $where = $_SESSION['export_where']; + } else { + $where = ''; + } + $beginWhere = substr(trim($where), 0, 5); + if ($beginWhere == "where") + $where = substr(trim($where), 5, strlen($where)); + $query = $focus->create_export_query($order_by,$where); + + $result = $db->query($query,true,"Error mail merging {$_SESSION['MAILMERGE_MODULE']}: "."
    $query"); + + $new_arr = array(); + while($val = $db->fetchByAssoc($result,-1,false)) + { + array_push($new_arr, $val['id']); + } + $_SESSION['MAILMERGE_RECORD'] = $new_arr; +} +else if(isset($_SESSION['MAILMERGE_RECORDS'])) +{ + + $fromListView = true; + $_SESSION['MAILMERGE_RECORD'] = $_SESSION['MAILMERGE_RECORDS']; + $_SESSION['MAILMERGE_RECORDS'] = null; +} +$rModule = ''; +if(isset($_SESSION['MAILMERGE_RECORD'])) +{ + if(!empty($_POST['return_module']) && $_POST['return_module'] != "MailMerge") + { + $rModule = $_POST['return_module']; + } + else if($fromListView) + { + $rModule = $_SESSION['MAILMERGE_MODULE_FROM_LISTVIEW']; + $_SESSION['MAILMERGE_MODULE_FROM_LISTVIEW'] = null; + } + else + { + $rModule = $_SESSION['MAILMERGE_MODULE']; + } + if($rModule == 'CampaignProspects'){ + $rModule = 'Campaigns'; + } + + $_SESSION['MAILMERGE_MODULE'] = $rModule; + if(!empty($rModule) && $rModule != "MailMerge") + { + $class_name = $beanList[$rModule]; + $includedir = $beanFiles[$class_name]; + require_once($includedir); + $seed = new $class_name(); + + $selected_objects = ''; + foreach($_SESSION['MAILMERGE_RECORD'] as $record_id) + { + if($rModule == 'Campaigns'){ + + $prospect = new Prospect(); + $prospect_module_list = array('leads', 'contacts', 'prospects', 'users'); + foreach($prospect_module_list as $mname){ + $pList = $prospect->retrieveTargetList("campaigns.id = '$record_id' AND related_type = #$mname#", array('id', 'first_name', 'last_name')); + + foreach($pList['list'] as $bean){ + $selected_objects .= $bean->id.'='.str_replace("&", "##", $bean->name).'&'; + } + } + }else{ + $seed->retrieve($record_id); + $selected_objects .= $record_id.'='.str_replace("&", "##", $seed->name).'&'; + } + } + + + if($rModule != 'Contacts' + && $rModule != 'Leads' && $rModule != 'Products' && $rModule != 'Campaigns' && $rModule != 'Projects' + ) + { + $_SESSION['MAILMERGE_SKIP_REL'] = false; + $xtpl->assign("STEP", "2"); + $xtpl->assign("SELECTED_OBJECTS", $selected_objects); + $_SESSION['SELECTED_OBJECTS_DEF'] = $selected_objects; + } + else + { + $_SESSION['MAILMERGE_SKIP_REL'] = true; + $xtpl->assign("STEP", "2"); + $_SESSION['SELECTED_OBJECTS_DEF'] = $selected_objects; + } + } + else + { + $xtpl->assign("STEP", "2"); + } + +} +else +{ + $xtpl->assign("STEP", "2"); +} +$modules = $module_list; +$func = ""; +if($rModule == 'Campaigns'){ + $func = "disableModuleDropDown();"; +} +$xtpl->assign("MAILMERGE_DISABLE_DROP_DOWN", $func); +$xtpl->assign("MAILMERGE_MODULE_OPTIONS", get_select_options_with_id($modules, $_SESSION['MAILMERGE_MODULE'])); +$xtpl->assign("MAILMERGE_TEMPLATES", get_select_options_with_id(getDocumentRevisions(), '0')); + +if(isset($_SESSION['MAILMERGE_MODULE'])){ + $module_select_text = $mod_strings['LBL_MAILMERGE_SELECTED_MODULE']; + $xtpl->assign("MAILMERGE_NUM_SELECTED_OBJECTS",count($_SESSION['MAILMERGE_RECORD'])." ".$_SESSION['MAILMERGE_MODULE']." Selected"); +} +else{ + $module_select_text = $mod_strings['LBL_MAILMERGE_MODULE']; +} +$xtpl->assign("MODULE_SELECT", $module_select_text); +if($_SESSION['MAILMERGE_MODULE'] == 'Campaigns'){ + $_SESSION['MAILMERGE_MODULE'] = 'CampaignProspects'; +} + +$admin = new Administration(); +$admin->retrieveSettings(); +$user_merge = $current_user->getPreference('mailmerge_on'); +if ($user_merge != 'on' || !isset($admin->settings['system_mailmerge_on']) || !$admin->settings['system_mailmerge_on']){ + $xtpl->assign("ADDIN_NOTICE", $mod_strings['LBL_ADDIN_NOTICE']); + $xtpl->assign("DISABLE_NEXT_BUTTON", "disabled"); +} + + +$xtpl->parse("main"); +$xtpl->out("main"); + +function get_user_module_list($user){ + global $app_list_strings, $current_language; + $app_list_strings = return_app_list_strings_language($current_language); + $modules = query_module_access_list($user); + global $modInvisList; + + return $modules; +} + +function getDocumentRevisions() +{ + $document = new Document(); + + $currentDate = TimeDate::getInstance()->nowDb(); + if ($document->db->dbType=="mysql") { + $empty_date=db_convert("'0000-00-00'", 'datetime'); + } + else { + $empty_date=db_convert("'1970-01-01 00:00:00'", 'datetime'); + } + + $query = "SELECT revision, document_name, document_revisions.id FROM document_revisions +LEFT JOIN documents on documents.id = document_revisions.document_id WHERE ((active_date <= ".db_convert("'".$currentDate."'", 'datetime')." AND exp_date > ".db_convert("'".$currentDate."'", 'datetime').") OR (active_date is NULL) or (active_date = ".$empty_date.") or (active_date <= ".db_convert("'".$currentDate."'", 'datetime')." AND ((exp_date = ".$empty_date.") OR (exp_date is NULL)))) AND is_template = 1 AND template_type = 'mailmerge' AND documents.deleted = 0 ORDER BY document_name"; + + $result = $document->db->query($query,true,"Error retrieving $document->object_name list: "); + + $list = Array(); + $list['None'] = 'None'; + while(($row = $document->db->fetchByAssoc($result)) != null) + { + $revision = null; + $docName = $row['document_name']; + $revision = $row['revision']; + if(!empty($revision)); + { + $docName .= " (rev. ".$revision.")"; + } + $list[$row['id']] = $docName; + } + return $list; + +} +?> diff --git a/modules/MailMerge/Step2.html b/modules/MailMerge/Step2.html new file mode 100644 index 00000000..d9749f7a --- /dev/null +++ b/modules/MailMerge/Step2.html @@ -0,0 +1,383 @@ + + + +{ERROR} + + + +
    + + + + + + + +

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

    {MAIL_MERGE_HEADER_STEP_2}

     
    {MAIL_MERGE_CAMPAIGN_PROSPECT_SELECTOR}
    + + + + + + + + + +
    + {MAILMERGE_PREV} + + {MAILMERGE_NEXT} +
    + + + + + +
    Available + + + + +
    +
    +
    + {MAILMERGE_LEFT_TO_RIGHT} +
    + {MAILMERGE_RIGHT_TO_LEFT} +
    + + + + + +
    Selected + + + + +
    +
    +
    +
    {MAIL_MERGE_CONTAINS_CONTACT_INFO}
    +

    +

    + + + +

    +
    +{JAVASCRIPT} + + + + + + + + diff --git a/modules/MailMerge/Step2.php b/modules/MailMerge/Step2.php new file mode 100644 index 00000000..9db35b36 --- /dev/null +++ b/modules/MailMerge/Step2.php @@ -0,0 +1,174 @@ + assign("MOD", $mod_strings); +$xtpl->assign("APP", $app_strings); +$xtpl->assign('JSON_CONFIG_JAVASCRIPT', $json_config->get_static_json_server(false, true)); + +if(isset($_POST['mailmerge_module'])) +{ + $_SESSION['MAILMERGE_MODULE'] = $_POST['mailmerge_module']; + if($_SESSION['MAILMERGE_MODULE'] == 'Campaigns'){ + $_SESSION['MAILMERGE_MODULE'] = 'CampaignProspects'; + } + if($_SESSION['MAILMERGE_MODULE'] == 'Contacts' || $_SESSION['MAILMERGE_MODULE'] == 'Leads'|| $_SESSION['MAILMERGE_MODULE'] == 'CampaignProspects') + { + + $_SESSION['MAILMERGE_SKIP_REL'] = true; + } +} + +$step_txt = "Step 2: "; +if(!empty($_SESSION['SELECTED_OBJECTS_DEF'])){ + $selObjs = $_SESSION['SELECTED_OBJECTS_DEF']; + $sel_obj = array(); + parse_str($selObjs,$sel_obj); + $idArray = array(); + $_SESSION['MAILMERGE_WHERE'] = ""; + foreach($sel_obj as $key => $value){ + $value = str_replace("##", "&", $value); + $idArray[$key] = $value; + if($_SESSION['MAILMERGE_MODULE'] == 'CampaignProspects'){ + if(isset($_POST['mailmerge_module']) && $_POST['mailmerge_module'] == 'Campaigns'){ + $where = "campaigns.id = '$key'"; + $_SESSION['MAILMERGE_WHERE'] = $where; + $_SESSION['MAILMERGE_CAMPAIGN_ID'] = $key; + $idArray = array(); + break; + } + } + } + + $xtpl->assign("MAILMERGE_WHERE", $_SESSION['MAILMERGE_WHERE']); + $xtpl->assign("MAILMERGE_PRESELECTED_OBJECTS", get_select_options_with_id($idArray, '0')); + $step_txt .= "Refine list of ".$_SESSION['MAILMERGE_MODULE']." to merge."; + $xtpl->assign("MAILMERGE_GET_OBJECTS", 0); +} +else +{ + $step_txt .= "Select list of ".$_SESSION['MAILMERGE_MODULE']." to merge."; + $xtpl->assign("MAILMERGE_GET_OBJECTS", 1); +} + +if(isset($_SESSION['MAILMERGE_SKIP_REL']) && $_SESSION['MAILMERGE_SKIP_REL']) +{ + $xtpl->assign("STEP", "4"); + +} +else +{ + + $selected = ''; + if(isset($_SESSION['MAILMERGE_CONTAINS_CONTACT_INFO']) && $_SESSION['MAILMERGE_CONTAINS_CONTACT_INFO']){ + $selected = $_SESSION['MAILMERGE_CONTAINS_CONTACT_INFO']; + } + $xtpl->assign("STEP", "3"); + //$xtpl->assign("MAIL_MERGE_CONTAINS_CONTACT_INFO", '
    '.$mod_strings['LBL_CONTAINS_CONTACT_INFO'].'
    '); + $rel_options = array(""=>"--None--"); + $seed = loadBean($_SESSION['MAILMERGE_MODULE']); + if($seed->load_relationship('contacts')){ + $rel_options["Contacts"] = "Contacts"; + } + if($_SESSION['MAILMERGE_MODULE'] == "Accounts"){ + $rel_options["Opportunities"] = "Opportunities"; + } + elseif($_SESSION['MAILMERGE_MODULE'] == "Opportunities"){ + $rel_options["Accounts"] = "Accounts"; + } + $xtpl->assign("MAIL_MERGE_CONTAINS_CONTACT_INFO", '
    '.$mod_strings['LBL_CONTAINS_CONTACT_INFO'].'
    '); +} + +$xtpl->assign("MAILMERGE_MODULE", $_SESSION['MAILMERGE_MODULE']); +$xtpl->assign("MAILMERGE_PREV", SugarThemeRegistry::current()->getImage('previous','border="0" style="margin-left: 1px;" alt="Previous" id="prevItems" onClick="decreaseOffset();getObjects();"')); +$xtpl->assign("MAILMERGE_NEXT", SugarThemeRegistry::current()->getImage('next','border="0" style="margin-left: 1px;" alt="Next" id="nextItems" onClick="increaseOffset();getObjects();"')); +$xtpl->assign("MAILMERGE_RIGHT_TO_LEFT", SugarThemeRegistry::current()->getImage('leftarrow_big','border="0" style="margin-left: 1px;" alt="Remove Item(s)" onClick="moveLeft();"')); +$xtpl->assign("MAILMERGE_LEFT_TO_RIGHT", SugarThemeRegistry::current()->getImage('rightarrow_big','border="0" style="margin-left: 1px;" alt="Add Item(s)" onClick="moveRight();"')); +$xtpl->assign("MAIL_MERGE_HEADER_STEP_2", $step_txt); +if($_SESSION['MAILMERGE_MODULE'] == 'CampaignProspects'){ + $rel_options = array("Contacts"=>"Contacts", "Leads" => "Leads", "Prospects" => "Prospects", "Users"=>"Users"); + $xtpl->assign("MAIL_MERGE_CAMPAIGN_PROSPECT_SELECTOR", ''); + +} + + +if(!empty($_POST['document_id'])) +{ + $_SESSION['MAILMERGE_DOCUMENT_ID'] = $_POST['document_id']; +} + + +$xtpl->parse("main"); +$xtpl->out("main"); + +function displaySelectionBox($objectList) +{ + $html = ''; + return $html; +} + +?> diff --git a/modules/MailMerge/Step3.html b/modules/MailMerge/Step3.html new file mode 100644 index 00000000..96aacbcb --- /dev/null +++ b/modules/MailMerge/Step3.html @@ -0,0 +1,98 @@ + + + +{ERROR} + +
    + + + + + + + +

    + + + + + + + + + +

    {STEP_NUM} {STEP3_HEADER}

    +Use the selections below to identify the related information you would like to display in your merged document. Skip this step if your template document contains no related information. +
    + + + + + + + + + + + + + + + + + + + + +
    {MOD.LBL_LIST_NAME}{STEP3_HEADER}
    {MAILMERGE.NAME}{MAILMERGE.CHANGE_RELATIONSHIP}
    + +
    +

    +

    + + + +

    +
    +{JAVASCRIPT} + + diff --git a/modules/MailMerge/Step3.php b/modules/MailMerge/Step3.php new file mode 100644 index 00000000..f526469c --- /dev/null +++ b/modules/MailMerge/Step3.php @@ -0,0 +1,274 @@ +assign("MOD", $mod_strings); +$xtpl->assign("APP", $app_strings); + +if(!isset($_SESSION['MAILMERGE_MODULE'])) +{ + if(isset($_POST['mailmerge_module'])) + { + $_SESSION['MAILMERGE_MODULE'] = $_POST['mailmerge_module']; + } +} + +if(isset($_POST['contains_contact_info'])){ + + $_SESSION['MAILMERGE_CONTAINS_CONTACT_INFO'] = $_POST['contains_contact_info']; + +} + +if(!isset($_SESSION["MAILMERGE_DOCUMENT_ID"])) +{ + if(!empty($_POST['document_id'])) + { + $_SESSION['MAILMERGE_DOCUMENT_ID'] = $_POST['document_id']; + } +} +$document_id = $_SESSION["MAILMERGE_DOCUMENT_ID"]; +$document = new Document(); +$document->retrieve($document_id); +$_SESSION["MAILMERGE_TEMPLATE"] = $document->document_name; + +if(!empty($_POST['selected_objects'])) +{ + $selObjs = urldecode($_POST['selected_objects']); + $_SESSION['SELECTED_OBJECTS_DEF'] = $selObjs; +} +else +{ + $selObjs = $_SESSION['SELECTED_OBJECTS_DEF']; +} +$sel_obj = array(); +parse_str(html_entity_decode($selObjs, ENT_QUOTES),$sel_obj); +$step_num = 3; +if(isset($_SESSION['MAILMERGE_RECORD'])) +{ + $xtpl->assign("PREV_STEP", '2'); + $step_num = 3; + //$xtpl->assign("RECORD", $_SESSION['MAILMERGE_RECORD']); +} +else +{ + $xtpl->assign("PREV_STEP", '2'); +} +$xtpl->assign("STEP_NUM", "Step ".$step_num.":"); +$popup_request_data = array ('call_back_function' => 'set_return', 'form_name' => 'EditView', 'field_to_name_array' => array ('id' => 'rel_id', 'name' => 'rel_name',),); + $json = getJSONobj(); + + // must urlencode to put into the filter request string + // because IE gets an out of memory error when it is passed + // as the usual object literal +$encoded_popup_request_data = urlencode($json->encode($popup_request_data)); + +$modules = $modules_array; + + +$xtpl->assign("MAILMERGE_MODULE_OPTIONS", get_select_options_with_id($modules, '0')); +$change_parent_button = ""; + +$change_parent_button = ""; +$xtpl->assign("CHANGE_PARENT_BUTTON", $change_parent_button); + +$relModule = $_SESSION['MAILMERGE_CONTAINS_CONTACT_INFO']; +$xtpl->assign("STEP3_HEADER", "Set ".get_singular_bean_name($relModule)." Association"); + + +$select = "Select id, name from contacts"; + +$selQuery = array ('Contacts'=>array('Accounts' => 'SELECT contacts.* FROM contacts LEFT JOIN accounts_contacts ON contacts.id=accounts_contacts.contact_id AND (accounts_contacts.deleted is NULL or accounts_contacts.deleted=0)', +'Contacts' => '', +'Opportunities' => 'SELECT contacts.* FROM contacts LEFT JOIN opportunities_contacts ON contacts.id=opportunities_contacts.contact_id AND (opportunities_contacts.deleted is NULL or opportunities_contacts.deleted=0)', +'Leads' => '', +'Cases' => 'SELECT contacts.* FROM contacts LEFT JOIN contacts_cases ON contacts.id=contacts_cases.contact_id AND (contacts_cases.deleted is NULL or contacts_cases.deleted=0)', +'Bugs' => 'SELECT contacts.* FROM contacts LEFT JOIN contacts_bugs ON contacts.id=contacts_bugs.contact_id AND (contacts_bugs.deleted is NULL or contacts_bugs.deleted=0)', +'Quotes' => 'SELECT contacts.* FROM contacts LEFT JOIN quotes_contacts ON contacts.id=quotes_contacts.contact_id AND (quotes_contacts.deleted is NULL or quotes_contacts.deleted=0)'), +'Opportunities'=>array("Accounts"=>'SELECT opportunities.id, opportunities.name FROM opportunities LEFT JOIN accounts_opportunities ON opportunities.id = accounts_opportunities.opportunity_id AND (accounts_opportunities.deleted is NULL or accounts_opportunities.deleted=0)'), +'Accounts'=>array("Opportunities"=>'SELECT accounts.id, accounts.name FROM accounts LEFT JOIN accounts_opportunities ON accounts.id = accounts_opportunities.account_id AND (accounts_opportunities.deleted is NULL or accounts_opportunities.deleted=0)'), +); +$whereQuery = array('Contacts' => array('Accounts' => 'accounts_contacts.contact_id = contacts.id AND accounts_contacts.account_id = ', +'Contacts' => '', +'Opportunities' => 'opportunities_contacts.contact_id = contacts.id AND opportunities_contacts.opportunity_id = ', +'Leads' => '', +'Cases' => 'contacts_cases.contact_id = contacts.id AND contacts_cases.case_id = ', +'Bugs' => 'contacts_bugs.contact_id = contacts.id AND contacts_bugs.bug_id = ', +'Quotes' => 'quotes_contacts.contact_id = contacts.id AND quotes_contacts.quote_id = '), +'Opportunities'=>array('Accounts'=>'accounts_opportunities.opportunity_id = opportunities.id AND accounts_opportunities.account_id = '), +'Accounts'=>array('Opportunities'=>'accounts_opportunities.account_id = accounts.id AND accounts_opportunities.opportunity_id = '), +); + + + +$contact = new Contact(); + + +global $beanList, $beanFiles; +$class_name = $beanList[$relModule ]; +require_once($beanFiles[$class_name]); +$seed = new $class_name(); + +if(isset($_SESSION['MAILMERGE_SKIP_REL']) && $_SESSION['MAILMERGE_SKIP_REL']) +{ + $disabled = 'disabled'; +} +else +{ + $disabled = ''; +} +$oddRow = true; + + +foreach($sel_obj as $key => $value) +{ + $value = str_replace("##", "&", $value); + $value = stripslashes($value); + $code = str_replace('-', '', $key); + $popup_request_data = array ('call_back_function' => 'set_return', 'form_name' => 'EditView', 'field_to_name_array' => array ('id' => 'rel_id_'.$code, 'name' => 'rel_name_'.$code,),); + $encoded_popup_request_data = urlencode($json->encode($popup_request_data)); + + if(empty($selQuery[$relModule][$_SESSION['MAILMERGE_MODULE']])){ + $select = generateSelect($seed, $relModule); + }else{ + $select = $selQuery[$relModule][$_SESSION['MAILMERGE_MODULE']]; + } + if(empty($whereQuery[$relModule][$_SESSION['MAILMERGE_MODULE']])){ + $where = "{$seed->table_name}.id = "; + }else{ + $where = $whereQuery[$relModule][$_SESSION['MAILMERGE_MODULE']]; + } + + if($relModule == "Contacts"){ + $limitSelect = str_replace('contacts.*', 'contacts.first_name, contacts.last_name, contacts.id, contacts.date_entered', $select); + } + else{ + $limitSelect = str_replace(strtolower($relModule).'.*', strtolower($relModule).'.name, '.strtolower($relModule).'.date_entered', $select); + } + $fullQuery = $limitSelect." WHERE ".$where."'".$key."' ORDER BY date_entered"; + + $result = $seed->db->limitQuery($fullQuery, 0, 1, true, "Error performing limit query"); + $full_name = ''; + $contact_id = ''; + if($contact->db->getRowCount($result) > 0) + { + $row = $seed->db->fetchByAssoc($result, 0); + if($relModule == "Contacts"){ + $full_name = $locale->getLocaleFormattedName($row['first_name'], $row['last_name']); + } + else{ + $full_name = $row['name']; + } + $contact_id = $row['id']; + } + $change_parent_button = ""; + $items = array( + 'ID' => $key, + 'NAME' => $value, + 'CODE' => $code, + 'TYPE_OPTIONS' => get_select_options_with_id($modules, '0'), + 'CHANGE_RELATIONSHIP' => $change_parent_button, + 'CONTACT_ID' => $contact_id, + 'CONTACT_NAME' => $full_name, + 'REL_MODULE' => $_SESSION['MAILMERGE_CONTAINS_CONTACT_INFO'], + ); + + $xtpl->assign("MAILMERGE", $items); + + if($oddRow) + { + //todo move to themes + $xtpl->assign("ROW_COLOR", 'oddListRow'); + $xtpl->assign("BG_COLOR", $odd_bg); + } + else + { + //todo move to themes + $xtpl->assign("ROW_COLOR", 'evenListRow'); + $xtpl->assign("BG_COLOR", $even_bg); + } + $oddRow = !$oddRow; + $xtpl->parse("main.items.row"); +} +$xtpl->parse("main.items"); + + +$xtpl->parse("main"); +$xtpl->out("main"); + + +function generateSelect($seed, $relModule){ + $lowerRelModule = strtolower($relModule); + if($seed->load_relationship($lowerRelModule)){ + $params = array(); + $params['join_table_alias'] = 'r1'; + $params['join_table_link_alias'] = 'r2'; + $params['join_type'] = 'LEFT JOIN'; + $join = $seed->$lowerRelModule->getJoin($params); + $select = "SELECT {$seed->table_name}.* FROM {$seed->table_name} ".$join; + return $select; + } + return ""; +} + +?> diff --git a/modules/MailMerge/Step4.html b/modules/MailMerge/Step4.html new file mode 100644 index 00000000..33793f25 --- /dev/null +++ b/modules/MailMerge/Step4.html @@ -0,0 +1,111 @@ + + + +{ERROR} + + + +
    + + + + + + + + + + +

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

    {STEP_NUM} {MOD.LBL_STEP_4}

     
    {MOD.LBL_SELECTED_MODULE} + {MAILMERGE_MODULE} +
    {MOD.LBL_SELECTED_TEMPLATE} + {MAILMERGE_TEMPLATE} +
    {MOD.LBL_SELECTED_ITEMS} + + + + +
    + + + + +
    +
    +
    +
    +

    +

    + + + +

    +
    +{JAVASCRIPT} + + diff --git a/modules/MailMerge/Step4.php b/modules/MailMerge/Step4.php new file mode 100644 index 00000000..e996e48b --- /dev/null +++ b/modules/MailMerge/Step4.php @@ -0,0 +1,153 @@ +assign("MOD", $mod_strings); +$xtpl->assign("APP", $app_strings); + +if(!empty($_POST['document_id'])) +{ + $_SESSION['MAILMERGE_DOCUMENT_ID'] = $_POST['document_id']; +} +$document_id = $_SESSION['MAILMERGE_DOCUMENT_ID']; +$revision = new DocumentRevision(); +$revision->retrieve($document_id); +//$document = new Document(); +//$document->retrieve($document_id); + +if(!empty($_POST['selected_objects'])) +{ + $selObjs = urldecode($_POST['selected_objects']); + $_SESSION['SELECTED_OBJECTS_DEF'] = $selObjs; +} +$selObjs = $_SESSION['SELECTED_OBJECTS_DEF']; +$sel_obj = array(); + +parse_str(stripslashes(html_entity_decode($selObjs, ENT_QUOTES)),$sel_obj); +foreach($sel_obj as $key=>$value) +{ + $sel_obj[$key] = stripslashes($value); +} +$relArray = array(); +//build relationship array +foreach($sel_obj as $key=>$value) +{ + $id = 'rel_id_'.str_replace('-', '', $key); + if(isset($_POST[$id]) && !empty($_POST[$id])) + { + $relArray[$key] = $_POST[$id]; + } +} + + +$builtArray = array(); +if(count($relArray) > 0) +{ +$_SESSION['MAILMERGE_RELATED_CONTACTS'] = $relArray; + +$relModule = $_SESSION['MAILMERGE_CONTAINS_CONTACT_INFO']; +global $beanList, $beanFiles; +$class_name = $beanList[$relModule ]; +require_once($beanFiles[$class_name]); + + $seed = new $class_name(); + foreach($sel_obj as $key=>$value) + { + $builtArray[$key] = $value; + if(isset($relArray[$key])) + { + $seed->retrieve($relArray[$key]); + $name = ""; + if($relModule == "Contacts"){ + $name = $locale->getLocaleFormattedName($seed->first_name,$seed->last_name); + } + else{ + $name = $seed->name; + } + $builtArray[$key] = str_replace('##', '&', $value)." (".$name.")"; + } + } + +} +else +{ + $builtArray = $sel_obj; +} + +$xtpl->assign("MAILMERGE_MODULE", $_SESSION['MAILMERGE_MODULE']); +$xtpl->assign("MAILMERGE_DOCUMENT_ID", $document_id); +$xtpl->assign("MAILMERGE_TEMPLATE", $revision->filename." (rev. ".$revision->revision.")"); +$xtpl->assign("MAILMERGE_SELECTED_OBJECTS", get_select_options_with_id($builtArray,'0')); +$xtpl->assign("MAILMERGE_SELECTED_OBJECTS_DEF", urlencode($selObjs)); +$step_num = 4; + +if(isset($_SESSION['MAILMERGE_SKIP_REL']) && $_SESSION['MAILMERGE_SKIP_REL'] || !isset($_SESSION['MAILMERGE_RELATED_CONTACTS']) || empty($_SESSION['MAILMERGE_RELATED_CONTACTS'])) +{ + $xtpl->assign("PREV_STEP", "2"); + $step_num = 3; +} +else +{ + $xtpl->assign("PREV_STEP", "3"); +} + +$xtpl->assign("STEP_NUM", "Step ".$step_num.":"); + +$xtpl->parse("main"); +$xtpl->out("main"); + +?> diff --git a/modules/MailMerge/Step5.html b/modules/MailMerge/Step5.html new file mode 100644 index 00000000..63b0f4fc --- /dev/null +++ b/modules/MailMerge/Step5.html @@ -0,0 +1,79 @@ + + + +{ERROR} + + + +
    + + + + + + +

    + + +"; +if ($focus->parent_type == "Accounts") $button .= "\n"; +else $button .= "\n"; +$button .= "\n"; +$button .= "
    + + + + + + + +

    {MOD.LBL_STEP_5}

     
    +

    + +

    + + +
    +

    + +{JAVASCRIPT} + + diff --git a/modules/MailMerge/Step5.php b/modules/MailMerge/Step5.php new file mode 100644 index 00000000..14e3cc0a --- /dev/null +++ b/modules/MailMerge/Step5.php @@ -0,0 +1,60 @@ + diff --git a/modules/MailMerge/get_doc.php b/modules/MailMerge/get_doc.php new file mode 100644 index 00000000..d334309d --- /dev/null +++ b/modules/MailMerge/get_doc.php @@ -0,0 +1,63 @@ + diff --git a/modules/MailMerge/index.php b/modules/MailMerge/index.php new file mode 100644 index 00000000..967081a9 --- /dev/null +++ b/modules/MailMerge/index.php @@ -0,0 +1,59 @@ + + diff --git a/modules/MailMerge/language/en_us.lang.php b/modules/MailMerge/language/en_us.lang.php new file mode 100644 index 00000000..0daae8a6 --- /dev/null +++ b/modules/MailMerge/language/en_us.lang.php @@ -0,0 +1,79 @@ + 'Step 1: Select Module and Template', + 'LBL_MAILMERGE_MODULE' => 'Select Module: ', + 'LBL_MAILMERGE_SELECTED_MODULE' => 'Selected Module: ', + 'LBL_MAILMERGE_TEMPLATES' => 'Select Template: ', + 'LBL_STEP_2' => 'Step 2: Select Objects to Merge', + 'LBL_MAILMERGE_OBJECTS' => 'Select Objects: ', + 'LBL_STEP_3' => 'Set Contact Association', + 'LBL_STEP_4' => 'Review and Complete', + 'LBL_SELECTED_MODULE' => 'Selected Module: ', + 'LBL_SELECTED_TEMPLATE' => 'Selected Template: ', + 'LBL_SELECTED_ITEMS' => 'Selected Items: ', + 'LBL_STEP_5' => 'Mail Merge Complete', + 'LBL_MERGED_FILE' => 'Merged File: ', + 'LNK_NEW_MAILMERGE' => 'Begin Mail Merge', + 'LNK_UPLOAD_TEMPLATE' => 'Upload Template', + 'LBL_DOC_NAME' => 'Document Name:', + 'LBL_FILENAME' => 'File Name:', + 'LBL_DOC_VERSION' => 'Revision:', + 'LBL_DOC_DESCRIPTION'=>'Description:', + 'LBL_LIST_NAME' => 'Name', + 'LBL_LIST_RELATIONSHIP' => 'Set Contact Relationship', + 'LBL_FINISH' => 'Begin Merge', + 'LBL_NEXT' => 'Next >', + 'LBL_BACK' => '< Back', + 'LBL_START' => 'Click Here to Continue', + 'LBL_TEMPLATE_NOTICE' => 'Templates are Microsoft Word documents containing merge fields that have been uploaded and stored in the Documents module.', + 'LBL_CONTAINS_CONTACT_INFO' => 'Selected template contains related ', + 'LBL_ADDIN_NOTICE' => 'This requires the installation of Sugar Mail Merge add-in to Microsoft Word.', + 'LBL_BROWSER_NOTICE' => 'You must be running IE 6.0 or greater to perform the actual merge.', +); + + +?> diff --git a/modules/MailMerge/modules_array.php b/modules/MailMerge/modules_array.php new file mode 100644 index 00000000..cebbae11 --- /dev/null +++ b/modules/MailMerge/modules_array.php @@ -0,0 +1,44 @@ + 'Accounts', + 'Cases' => 'Cases', + 'Contacts' => 'Contacts', + 'Leads' => 'Leads', + 'Opportunities' => 'Opportunities'); +?> \ No newline at end of file diff --git a/modules/Meetings/Dashlets/MyMeetingsDashlet/MyMeetingsDashlet.data.php b/modules/Meetings/Dashlets/MyMeetingsDashlet/MyMeetingsDashlet.data.php new file mode 100644 index 00000000..06838a26 --- /dev/null +++ b/modules/Meetings/Dashlets/MyMeetingsDashlet/MyMeetingsDashlet.data.php @@ -0,0 +1,91 @@ + array('default' => ''), + 'status' => array('default' => array('Planned')), + 'date_start' => array('default' => ''), + 'date_entered' => array('default' => ''), + + + 'assigned_user_id' => array('type' => 'assigned_user_name', + 'default' => $current_user->name, + 'label' => 'LBL_ASSIGNED_TO'),); +$dashletData['MyMeetingsDashlet']['columns'] = array('set_complete' => array('width' => '1', + 'label' => 'LBL_LIST_CLOSE', + 'default' => true, + 'sortable' => false, + 'related_fields' => array('status')), + 'name' => array('width' => '40', + 'label' => 'LBL_SUBJECT', + 'link' => true, + 'default' => true), + 'parent_name' => array('width' => '29', + 'label' => 'LBL_LIST_RELATED_TO', + 'sortable' => false, + 'dynamic_module' => 'PARENT_TYPE', + 'link' => true, + 'id' => 'PARENT_ID', + 'ACLTag' => 'PARENT', + 'related_fields' => array('parent_id', 'parent_type'), + 'default' => true), + 'duration' => array('width' => '15', + 'label' => 'LBL_DURATION', + 'sortable' => false, + 'related_fields' => array('duration_hours', 'duration_minutes')), + 'date_start' => array('width' => '15', + 'label' => 'LBL_DATE', + 'default' => true, + 'related_fields' => array('time_start')), + 'status' => array('width' => '8', + 'label' => 'LBL_STATUS'), + 'date_entered' => array('width' => '15', + 'label' => 'LBL_DATE_ENTERED'), + 'date_modified' => array('width' => '15', + 'label' => 'LBL_DATE_MODIFIED'), + 'created_by' => array('width' => '8', + 'label' => 'LBL_CREATED'), + 'assigned_user_name' => array('width' => '8', + 'label' => 'LBL_LIST_ASSIGNED_USER'), + ); + + +?> diff --git a/modules/Meetings/Dashlets/MyMeetingsDashlet/MyMeetingsDashlet.meta.php b/modules/Meetings/Dashlets/MyMeetingsDashlet/MyMeetingsDashlet.meta.php new file mode 100644 index 00000000..3ecd6976 --- /dev/null +++ b/modules/Meetings/Dashlets/MyMeetingsDashlet/MyMeetingsDashlet.meta.php @@ -0,0 +1,47 @@ + 'Meetings', + 'title' => translate('LBL_LIST_MY_MEETINGS', 'Meetings'), + 'description' => 'A customizable view into Meetings', + 'category' => 'Module Views'); +?> diff --git a/modules/Meetings/Dashlets/MyMeetingsDashlet/MyMeetingsDashlet.php b/modules/Meetings/Dashlets/MyMeetingsDashlet/MyMeetingsDashlet.php new file mode 100644 index 00000000..d616cbaa --- /dev/null +++ b/modules/Meetings/Dashlets/MyMeetingsDashlet/MyMeetingsDashlet.php @@ -0,0 +1,188 @@ +title = translate('LBL_LIST_MY_MEETINGS', 'Meetings'); + + $this->searchFields = $dashletData['MyMeetingsDashlet']['searchFields']; + if(empty($def['filters'])){ + if(isset($this->searchFields['status'])){ + if(!empty($this->searchFields['status']['default'])){ + $this->filters['status'] = $this->searchFields['status']['default']; + } + } + } + $this->columns = $dashletData['MyMeetingsDashlet']['columns']; + $this->columns['set_accept_links']= array('width' => '10', + 'label' => translate('LBL_ACCEPT_THIS', 'Meetings'), + 'sortable' => false, + 'default' => true, + 'related_fields' => array('status')); + $this->hasScript = true; // dashlet has javascript attached to it + $this->seedBean = new Meeting(); + } + + function process($lvsParams = array()) { + global $current_language, $app_list_strings, $current_user; + $mod_strings = return_module_language($current_language, 'Meetings'); + + // handle myitems only differently -- set the custom query to show assigned meetings and invitee meetings + if($this->myItemsOnly) { + //join with meeting_users table to process related users + $this->seedBean->listview_inner_join = array('LEFT JOIN meetings_users m_u on m_u.meeting_id = meetings.id'); + + //set the custom query to retrieve invitees AND assigned meetings + $lvsParams['custom_where'] = ' AND (meetings.assigned_user_id = \'' . $current_user->id . '\' OR m_u.user_id = \'' . $current_user->id . '\' AND m_u.deleted=0) '; + } + + $this->myItemsOnly = false; + //query needs to be distinct to avoid multiple records being returned for the same meeting (one for each invited user), + //so we need to make sure date entered is also set so the sort can work with the group by + $lvsParams['custom_select']=', meetings.date_entered '; + $lvsParams['distinct']=true; + + parent::process($lvsParams); + + $keys = array(); + foreach($this->lvs->data['data'] as $num => $row) { + $keys[] = $row['ID']; + } + + // grab meeting status + if(!empty($keys)){ + $query = "SELECT meeting_id, accept_status FROM meetings_users WHERE deleted = 0 AND user_id = '" . $current_user->id . "' AND meeting_id IN ('" . implode("','", $keys) . "')"; + $result = $GLOBALS['db']->query($query); + } + + while($row = $GLOBALS['db']->fetchByAssoc($result)) { + $rowNums = $this->lvs->data['pageData']['idIndex'][$row['meeting_id']]; // figure out which rows have this guid + foreach($rowNums as $rowNum) { + $this->lvs->data['data'][$rowNum]['ACCEPT_STATUS'] = $row['accept_status']; + } + + } + + foreach($this->lvs->data['data'] as $rowNum => $row) { + + if(empty($this->lvs->data['data'][$rowNum]['DURATION_HOURS'])) $this->lvs->data['data'][$rowNum]['DURATION'] = '0' . $mod_strings['LBL_HOURS_ABBREV']; + else $this->lvs->data['data'][$rowNum]['DURATION'] = $this->lvs->data['data'][$rowNum]['DURATION_HOURS'] . $mod_strings['LBL_HOURS_ABBREV']; + + if(empty($this->lvs->data['data'][$rowNum]['DURATION_MINUTES']) || empty($this->seedBean->minutes_values[$this->lvs->data['data'][$rowNum]['DURATION_MINUTES']])) { + $this->lvs->data['data'][$rowNum]['DURATION'] .= '00'; + } + else { + $this->lvs->data['data'][$rowNum]['DURATION'] .= $this->seedBean->minutes_values[$this->lvs->data['data'][$rowNum]['DURATION_MINUTES']]; + } + $this->lvs->data['data'][$rowNum]['DURATION'] .= $mod_strings['LBL_MINSS_ABBREV']; + if (!empty($this->lvs->data['data'][$rowNum]['STATUS']) && $this->lvs->data['data'][$rowNum]['STATUS'] == $app_list_strings['meeting_status_dom']['Planned']) + { + if ($this->lvs->data['data'][$rowNum]['ACCEPT_STATUS'] == ''){ + //if no status has been set, then do not show accept options + $this->lvs->data['data'][$rowNum]['SET_ACCEPT_LINKS'] = "
    id."\" class=\"acceptMeeting\">
    "; + }elseif($this->lvs->data['data'][$rowNum]['ACCEPT_STATUS'] == 'none') + { + $this->lvs->data['data'][$rowNum]['SET_ACCEPT_LINKS'] = ""; + } + else + { + $this->lvs->data['data'][$rowNum]['SET_ACCEPT_LINKS'] = $app_list_strings['dom_meeting_accept_status'][$this->lvs->data['data'][$rowNum]['ACCEPT_STATUS']]; + + } + } + } + $this->displayColumns[]= "set_accept_links"; + } + /** + * Displays the javascript for the dashlet + * + * @return string javascript to use with this dashlet + */ + function displayScript() { + + } + + function displayOptions() { + $this->processDisplayOptions(); + $this->configureSS->assign('strings', array('general' => $GLOBALS['mod_strings']['LBL_DASHLET_CONFIGURE_GENERAL'], + 'filters' => $GLOBALS['mod_strings']['LBL_DASHLET_CONFIGURE_FILTERS'], + 'myItems' => translate('LBL_DASHLET_CONFIGURE_MY_ITEMS_ONLY', 'Meetings'), + 'displayRows' => $GLOBALS['mod_strings']['LBL_DASHLET_CONFIGURE_DISPLAY_ROWS'], + 'title' => $GLOBALS['mod_strings']['LBL_DASHLET_CONFIGURE_TITLE'], + 'save' => $GLOBALS['app_strings']['LBL_SAVE_BUTTON_LABEL'], + 'autoRefresh' => $GLOBALS['app_strings']['LBL_DASHLET_CONFIGURE_AUTOREFRESH'], + )); + + require_once('modules/Meetings/Meeting.php'); + $types = getMeetingsExternalApiDropDown(); + $this->currentSearchFields['type']['input'] = ''; + $this->configureSS->assign('searchFields', $this->currentSearchFields); + + return $this->configureSS->fetch($this->configureTpl); + } + + function saveStatus() + { + + } +} + +?> diff --git a/modules/Meetings/JoinExternalMeeting.php b/modules/Meetings/JoinExternalMeeting.php new file mode 100644 index 00000000..284749fe --- /dev/null +++ b/modules/Meetings/JoinExternalMeeting.php @@ -0,0 +1,83 @@ +query("SELECT id FROM meetings_users WHERE meeting_id = '".$db->quote($_REQUEST['meeting_id'])."' AND user_id = '".$current_user->id."' AND deleted = 0",true); +$row = $db->fetchByAssoc($ret); + +$meetingBean = loadBean('Meetings'); +$meetingBean->retrieve($_REQUEST['meeting_id']); + +if ( $_REQUEST['host_meeting'] == '1' ) { + if($meetingBean->assigned_user_id == $GLOBALS['current_user']->id || is_admin($GLOBALS['current_user']) || is_admin_for_module($GLOBALS['current_user'],'Meetings')){ + SugarApplication::redirect($meetingBean->host_url); + }else{ + //since they are now the owner of the meeting nor an Admin they cannot start the meeting. + $tplFile = 'modules/Meetings/tpls/extMeetingNoStart.tpl'; + if ( file_exists('custom/'.$tplFile) ) { + $tplFile = 'custom/'.$tplFile; + } + + $ss = new Sugar_Smarty(); + $ss->assign('current_user',$current_user); + $ss->assign('bean',$meetingBean->toArray()); + $ss->display($tplFile); + } +}else{ + if(isset($row['id']) || $meetingBean->assigned_user_id == $GLOBALS['current_user']->id || is_admin($GLOBALS['current_user']) || is_admin_for_module($GLOBALS['current_user'],'Meetings')){ + SugarApplication::redirect($meetingBean->join_url); + }else{ + //if the user is not invited or the owner of the meeting or an admin then they cannot join the meeting. + $tplFile = 'modules/Meetings/tpls/extMeetingNotInvited.tpl'; + if ( file_exists('custom/'.$tplFile) ) { + $tplFile = 'custom/'.$tplFile; + } + + $ss = new Sugar_Smarty(); + $ss->assign('current_user',$current_user); + $ss->assign('bean',$meetingBean->toArray()); + $ss->display($tplFile); + } +} \ No newline at end of file diff --git a/modules/Meetings/Meeting.php b/modules/Meetings/Meeting.php new file mode 100644 index 00000000..f2943dc0 --- /dev/null +++ b/modules/Meetings/Meeting.php @@ -0,0 +1,740 @@ +'00','15'=>'15','30'=>'30','45'=>'45'); + var $table_name = "meetings"; + var $rel_users_table = "meetings_users"; + var $rel_contacts_table = "meetings_contacts"; + var $rel_leads_table = "meetings_leads"; + var $module_dir = "Meetings"; + var $object_name = "Meeting"; + + var $importable = true; + // This is used to retrieve related fields from form posts. + var $additional_column_fields = array('assigned_user_name', 'assigned_user_id', 'contact_id', 'user_id', 'contact_name', 'accept_status'); + var $relationship_fields = array('account_id'=>'accounts','opportunity_id'=>'opportunity','case_id'=>'case', + 'assigned_user_id'=>'users','contact_id'=>'contacts', 'user_id'=>'users', 'meeting_id'=>'meetings'); + // so you can run get_users() twice and run query only once + var $cached_get_users = null; + var $new_schema = true; + + /** + * sole constructor + */ + function Meeting() { + parent::SugarBean(); + $this->setupCustomFields('Meetings'); + foreach($this->field_defs as $field) { + $this->field_name_map[$field['name']] = $field; + } +// $this->fill_in_additional_detail_fields(); + } + + /** + * Stub for integration + * @return bool + */ + function hasIntegratedMeeting() { + return false; + } + + // save date_end by calculating user input + // this is for calendar + function save($check_notify = FALSE) { + global $timedate; + global $current_user; + global $disable_date_format; + + if(isset($this->date_start) && isset($this->duration_hours) && isset($this->duration_minutes)) + { + if(isset($this->date_start) && isset($this->duration_hours) && isset($this->duration_minutes)) + { + $td = $timedate->fromDb($this->date_start); + if($td) + { + $this->date_end = $td->modify("+{$this->duration_hours} hours {$this->duration_minutes} mins")->asDb(); + } + } + } + + $check_notify =(!empty($_REQUEST['send_invites']) && $_REQUEST['send_invites'] == '1') ? true : false; + if(empty($_REQUEST['send_invites'])) { + if(!empty($this->id)) { + $old_record = new Meeting(); + $old_record->retrieve($this->id); + $old_assigned_user_id = $old_record->assigned_user_id; + } + if((empty($this->id) && isset($_REQUEST['assigned_user_id']) && !empty($_REQUEST['assigned_user_id']) && $GLOBALS['current_user']->id != $_REQUEST['assigned_user_id']) || (isset($old_assigned_user_id) && !empty($old_assigned_user_id) && isset($_REQUEST['assigned_user_id']) && !empty($_REQUEST['assigned_user_id']) && $old_assigned_user_id != $_REQUEST['assigned_user_id']) ){ + $this->special_notification = true; + $check_notify = true; + if(isset($_REQUEST['assigned_user_name'])) { + $this->new_assigned_user_name = $_REQUEST['assigned_user_name']; + } + } + } + /*nsingh 7/3/08 commenting out as bug #20814 is invalid + if($current_user->getPreference('reminder_time')!= -1 && isset($_POST['reminder_checked']) && isset($_POST['reminder_time']) && $_POST['reminder_checked']==0 && $_POST['reminder_time']==-1){ + $this->reminder_checked = '1'; + $this->reminder_time = $current_user->getPreference('reminder_time'); + }*/ + + if (empty($this->status) ) { + $this->status = $this->getDefaultStatus(); + } + + // Do any external API saving + // Clear out the old external API stuff if we have changed types + if (isset($this->fetched_row) && $this->fetched_row['type'] != $this->type ) { + $this->join_url = ''; + $this->host_url = ''; + $this->external_id = ''; + $this->creator = ''; + } + + if (!empty($this->type) && $this->type != 'Sugar' ) { + require_once('include/externalAPI/ExternalAPIFactory.php'); + $api = ExternalAPIFactory::loadAPI($this->type); + } + + if (empty($this->type)) { + $this->type = 'Sugar'; + } + + if ( isset($api) && is_a($api,'WebMeeting') ) { + // Make sure the API initialized and it supports Web Meetings + // Also make suer we have an ID, the external site needs something to reference + if ( !isset($this->id) || empty($this->id) ) { + $this->id = create_guid(); + $this->new_with_id = true; + } + $response = $api->scheduleMeeting($this); + if ( $response['success'] == TRUE ) { + // Need to send out notifications + if ( $api->canInvite ) { + $notifyList = $this->get_notification_recipients(); + foreach($notifyList as $person) { + $api->inviteAttendee($this,$person,$check_notify); + } + + } + } else { + SugarApplication::appendErrorMessage($GLOBALS['app_strings']['ERR_EXTERNAL_API_SAVE_FAIL']); + return $this->id; + } + + $api->logoff(); + } + + $return_id = parent::save($check_notify); + + if($this->update_vcal) { + vCal::cache_sugar_vcal($current_user); + } + + + + return $return_id; + } + + // this is for calendar + function mark_deleted($id) { + + global $current_user; + + parent::mark_deleted($id); + + if($this->update_vcal) { + vCal::cache_sugar_vcal($current_user); + } + } + + function get_summary_text() { + return "$this->name"; + } + + function create_export_query(&$order_by, &$where, $relate_link_join='') + { + $custom_join = $this->custom_fields->getJOIN(true, true,$where); + if($custom_join) + $custom_join['join'] .= $relate_link_join; + $contact_required = stristr($where, "contacts"); + + if($contact_required) { + $query = "SELECT meetings.*, contacts.first_name, contacts.last_name, contacts.assigned_user_id contact_name_owner "; + if($custom_join) { + $query .= $custom_join['select']; + } + $query .= " FROM contacts, meetings, meetings_contacts "; + $where_auto = " meetings_contacts.contact_id = contacts.id AND meetings_contacts.meeting_id = meetings.id AND meetings.deleted=0 AND contacts.deleted=0"; + } else { + $query = 'SELECT meetings.*'; + if($custom_join) { + $query .= $custom_join['select']; + } + $query .= ' FROM meetings '; + $where_auto = "meetings.deleted=0"; + } + + if($custom_join) { + $query .= $custom_join['join']; + } + + if($where != "") + $query .= " where $where AND ".$where_auto; + else + $query .= " where ".$where_auto; + + if($order_by != "") { + $query .= " ORDER BY $order_by"; + } else { + $alternate_order_by = $this->process_order_by($order_by, null); + if($alternate_order_by != "") + $query .= " ORDER BY ". $alternate_order_by; + } + return $query; + } + + + + function fill_in_additional_detail_fields() { + global $locale; + // Fill in the assigned_user_name + $this->assigned_user_name = get_assigned_user_name($this->assigned_user_id); + + if (!empty($this->contact_id)) { + $query = "SELECT first_name, last_name FROM contacts "; + $query .= "WHERE id='$this->contact_id' AND deleted=0"; + $result = $this->db->limitQuery($query,0,1,true," Error filling in additional detail fields: "); + + // Get the contact name. + $row = $this->db->fetchByAssoc($result); + $GLOBALS['log']->info("additional call fields $query"); + if($row != null) + { + $this->contact_name = $locale->getLocaleFormattedName($row['first_name'], $row['last_name'], '', ''); + $GLOBALS['log']->debug("Call($this->id): contact_name = $this->contact_name"); + $GLOBALS['log']->debug("Call($this->id): contact_id = $this->contact_id"); + } + } + + + + $this->created_by_name = get_assigned_user_name($this->created_by); + $this->modified_by_name = get_assigned_user_name($this->modified_user_id); + $this->fill_in_additional_parent_fields(); + + if (!isset($this->time_hour_start)) { + $this->time_start_hour = intval(substr($this->time_start, 0, 2)); + } //if-else + + if (isset($this->time_minute_start)) { + $time_start_minutes = $this->time_minute_start; + } else { + $time_start_minutes = substr($this->time_start, 3, 5); + if ($time_start_minutes > 0 && $time_start_minutes < 15) { + $time_start_minutes = "15"; + } else if ($time_start_minutes > 15 && $time_start_minutes < 30) { + $time_start_minutes = "30"; + } else if ($time_start_minutes > 30 && $time_start_minutes < 45) { + $time_start_minutes = "45"; + } else if ($time_start_minutes > 45) { + $this->time_start_hour += 1; + $time_start_minutes = "00"; + } //if-else + } //if-else + + + if (isset($this->time_hour_start)) { + $time_start_hour = $this->time_hour_start; + } else { + $time_start_hour = intval(substr($this->time_start, 0, 2)); + } + + global $timedate; + $this->time_meridiem = $timedate->AMPMMenu('', $this->time_start, 'onchange="SugarWidgetScheduler.update_time();"'); + $hours_arr = array (); + $num_of_hours = 13; + $start_at = 1; + + if (empty ($time_meridiem)) { + $num_of_hours = 24; + $start_at = 0; + } //if + + for ($i = $start_at; $i < $num_of_hours; $i ++) { + $i = $i.""; + if (strlen($i) == 1) { + $i = "0".$i; + } + $hours_arr[$i] = $i; + } //for + + if (!isset($this->duration_minutes)) { + $this->duration_minutes = $this->minutes_value_default; + } + + //setting default date and time + if (is_null($this->date_start)) + $this->date_start = $timedate->now(); + if (is_null($this->time_start)) + $this->time_start = $timedate->to_display_time(TimeDate::getInstance()->nowDb(), true); + if (is_null($this->duration_hours)) { + $this->duration_hours = "0"; + } + if (is_null($this->duration_minutes)) + $this->duration_minutes = "1"; + + global $app_list_strings; + $parent_types = $app_list_strings['record_type_display']; + $disabled_parent_types = ACLController::disabledModuleList($parent_types,false, 'list'); + foreach($disabled_parent_types as $disabled_parent_type){ + if($disabled_parent_type != $this->parent_type){ + unset($parent_types[$disabled_parent_type]); + } + } + + $this->parent_type_options = get_select_options_with_id($parent_types, $this->parent_type); + if (empty($this->reminder_time)) { + $this->reminder_time = -1; + } + + if ( empty($this->id) ) { + $reminder_t = $GLOBALS['current_user']->getPreference('reminder_time'); + if ( isset($reminder_t) ) + $this->reminder_time = $reminder_t; + } + $this->reminder_checked = $this->reminder_time == -1 ? false : true; + + if (isset ($_REQUEST['parent_type'])) { + $this->parent_type = $_REQUEST['parent_type']; + } elseif (is_null($this->parent_type)) { + $this->parent_type = $app_list_strings['record_type_default_key']; + } + + } + + function get_list_view_data() { + $meeting_fields = $this->get_list_view_array(); + global $app_list_strings, $focus, $action, $currentModule; + if(isset($this->parent_type)) + $meeting_fields['PARENT_MODULE'] = $this->parent_type; + if($this->status == "Planned") { + //cn: added this if() to deal with sequential Closes in Meetings. this is a hack to a hack(formbase.php->handleRedirect) + if(empty($action)) + $action = "index"; + $setCompleteUrl = ""; + $meeting_fields['SET_COMPLETE'] = $setCompleteUrl . SugarThemeRegistry::current()->getImage("close_inline","title=".translate('LBL_LIST_CLOSE','Meetings')." border='0'").""; + } + global $timedate; + $today = $timedate->nowDb(); + $nextday = $timedate->asDbDate($timedate->getNow()->get("+1 day")); + $mergeTime = $meeting_fields['DATE_START']; //$timedate->merge_date_time($meeting_fields['DATE_START'], $meeting_fields['TIME_START']); + $date_db = $timedate->to_db($mergeTime); + if($date_db < $today ) { + $meeting_fields['DATE_START']= "".$meeting_fields['DATE_START'].""; + }else if($date_db < $nextday) { + $meeting_fields['DATE_START'] = "".$meeting_fields['DATE_START'].""; + } else { + $meeting_fields['DATE_START'] = "".$meeting_fields['DATE_START'].""; + } + $this->fill_in_additional_detail_fields(); + + //make sure we grab the localized version of the contact name, if a contact is provided + if (!empty($this->contact_id)) { + global $locale; + $query = "SELECT first_name, last_name, salutation, title FROM contacts "; + $query .= "WHERE id='$this->contact_id' AND deleted=0"; + $result = $this->db->limitQuery($query,0,1,true," Error filling in contact name fields: "); + + // Get the contact name. + $row = $this->db->fetchByAssoc($result); + + if($row != null) + { + $this->contact_name = $locale->getLocaleFormattedName($row['first_name'], $row['last_name'], $row['salutation'], $row['title']); + } + } + + $meeting_fields['CONTACT_ID'] = $this->contact_id; + $meeting_fields['CONTACT_NAME'] = $this->contact_name; + + $meeting_fields['PARENT_NAME'] = $this->parent_name; + + $meeting_fields['REMINDER_CHECKED'] = $this->reminder_time==-1 ? false : true; + + + return $meeting_fields; + } + + function set_notification_body($xtpl, &$meeting) { + global $sugar_config; + global $app_list_strings; + global $current_user; + global $timedate; + + + // cn: bug 9494 - passing a contact breaks this call + $notifyUser =($meeting->current_notify_user->object_name == 'User') ? $meeting->current_notify_user : $current_user; + // cn: bug 8078 - fixed call to $timedate + $prefDate = $notifyUser->getUserDateTimePreferences(); + + if(strtolower(get_class($meeting->current_notify_user)) == 'contact') { + $xtpl->assign("ACCEPT_URL", $sugar_config['site_url']. + '/index.php?entryPoint=acceptDecline&module=Meetings&contact_id='.$meeting->current_notify_user->id.'&record='.$meeting->id); + } elseif(strtolower(get_class($meeting->current_notify_user)) == 'lead') { + $xtpl->assign("ACCEPT_URL", $sugar_config['site_url']. + '/index.php?entryPoint=acceptDecline&module=Meetings&lead_id='.$meeting->current_notify_user->id.'&record='.$meeting->id); + } else { + $xtpl->assign("ACCEPT_URL", $sugar_config['site_url']. + '/index.php?entryPoint=acceptDecline&module=Meetings&user_id='.$meeting->current_notify_user->id.'&record='.$meeting->id); + } + $xtpl->assign("MEETING_TO", $meeting->current_notify_user->new_assigned_user_name); + $xtpl->assign("MEETING_SUBJECT", trim($meeting->name)); + $xtpl->assign("MEETING_STATUS",(isset($meeting->status)? $app_list_strings['meeting_status_dom'][$meeting->status]:"")); + $typekey = strtolower($meeting->type); + if(isset($meeting->type)) { + if(!empty($app_list_strings['eapm_list'][$typekey])) { + $typestring = $app_list_strings['eapm_list'][$typekey]; + } else { + $typestring = $app_list_strings['meeting_type_dom'][$meeting->type]; + } + } + $xtpl->assign("MEETING_TYPE", isset($meeting->type)? $typestring:""); + $xtpl->assign("MEETING_STARTDATE", $timedate->to_display_date_time($meeting->date_start,true,true,$notifyUser)." ".$prefDate['userGmt']); + $xtpl->assign("MEETING_HOURS", $meeting->duration_hours); + $xtpl->assign("MEETING_MINUTES", $meeting->duration_minutes); + $xtpl->assign("MEETING_DESCRIPTION", $meeting->description); + if ( !empty($meeting->join_url) ) { + $xtpl->assign('MEETING_URL', $meeting->join_url); + $xtpl->parse('Meeting.Meeting_External_API'); + } + + return $xtpl; + } + + function get_meeting_users() { + $template = new User(); + // First, get the list of IDs. + $query = "SELECT meetings_users.required, meetings_users.accept_status, meetings_users.user_id from meetings_users where meetings_users.meeting_id='$this->id' AND meetings_users.deleted=0"; + $GLOBALS['log']->debug("Finding linked records $this->object_name: ".$query); + $result = $this->db->query($query, true); + $list = Array(); + + while($row = $this->db->fetchByAssoc($result)) { + $template = new User(); // PHP 5 will retrieve by reference, always over-writing the "old" one + $record = $template->retrieve($row['user_id']); + $template->required = $row['required']; + $template->accept_status = $row['accept_status']; + + if($record != null) { + // this copies the object into the array + $list[] = $template; + } + } + return $list; + } + + function get_invite_meetings(&$user) { + $template = $this; + // First, get the list of IDs. + $GLOBALS['log']->debug("Finding linked records $this->object_name: ".$query); + $query = "SELECT meetings_users.required, meetings_users.accept_status, meetings_users.meeting_id from meetings_users where meetings_users.user_id='$user->id' AND( meetings_users.accept_status IS NULL OR meetings_users.accept_status='none') AND meetings_users.deleted=0"; + $result = $this->db->query($query, true); + $list = Array(); + + while($row = $this->db->fetchByAssoc($result)) { + $record = $template->retrieve($row['meeting_id']); + $template->required = $row['required']; + $template->accept_status = $row['accept_status']; + + + if($record != null) + { + // this copies the object into the array + $list[] = $template; + } + } + return $list; + } + + + function set_accept_status(&$user,$status) + { + if($user->object_name == 'User') + { + $relate_values = array('user_id'=>$user->id,'meeting_id'=>$this->id); + $data_values = array('accept_status'=>$status); + $this->set_relationship($this->rel_users_table, $relate_values, true, true,$data_values); + global $current_user; + + if($this->update_vcal) + { + vCal::cache_sugar_vcal($user); + } + } + else if($user->object_name == 'Contact') + { + $relate_values = array('contact_id'=>$user->id,'meeting_id'=>$this->id); + $data_values = array('accept_status'=>$status); + $this->set_relationship($this->rel_contacts_table, $relate_values, true, true,$data_values); + } + else if($user->object_name == 'Lead') + { + $relate_values = array('lead_id'=>$user->id,'meeting_id'=>$this->id); + $data_values = array('accept_status'=>$status); + $this->set_relationship($this->rel_leads_table, $relate_values, true, true,$data_values); + } + } + + + function get_notification_recipients() { + if($this->special_notification) { + return parent::get_notification_recipients(); + } + + $list = array(); + if(!is_array($this->contacts_arr)) { + $this->contacts_arr = array(); + } + + if(!is_array($this->users_arr)) { + $this->users_arr = array(); + } + + if(!is_array($this->leads_arr)) { + $this->leads_arr = array(); + } + + foreach($this->users_arr as $user_id) { + $notify_user = new User(); + $notify_user->retrieve($user_id); + $notify_user->new_assigned_user_name = $notify_user->full_name; + $GLOBALS['log']->info("Notifications: recipient is $notify_user->new_assigned_user_name"); + $list[$notify_user->id] = $notify_user; + } + + foreach($this->contacts_arr as $contact_id) { + $notify_user = new Contact(); + $notify_user->retrieve($contact_id); + $notify_user->new_assigned_user_name = $notify_user->full_name; + $GLOBALS['log']->info("Notifications: recipient is $notify_user->new_assigned_user_name"); + $list[$notify_user->id] = $notify_user; + } + + foreach($this->leads_arr as $lead_id) { + $notify_user = new Lead(); + $notify_user->retrieve($lead_id); + $notify_user->new_assigned_user_name = $notify_user->full_name; + $GLOBALS['log']->info("Notifications: recipient is $notify_user->new_assigned_user_name"); + $list[$notify_user->id] = $notify_user; + } + + return $list; + } + + + function bean_implements($interface) { + switch($interface) { + case 'ACL':return true; + } + return false; + } + + function listviewACLHelper() { + $array_assign = parent::listviewACLHelper(); + $is_owner = false; + if(!empty($this->parent_name)) { + + if(!empty($this->parent_name_owner)) { + global $current_user; + $is_owner = $current_user->id == $this->parent_name_owner; + } + } + + if(!ACLController::moduleSupportsACL($this->parent_type) || ACLController::checkAccess($this->parent_type, 'view', $is_owner)) { + $array_assign['PARENT'] = 'a'; + } else { + $array_assign['PARENT'] = 'span'; + } + + $is_owner = false; + + if(!empty($this->contact_name)) { + if(!empty($this->contact_name_owner)) { + global $current_user; + $is_owner = $current_user->id == $this->contact_name_owner; + } + } + + if(ACLController::checkAccess('Contacts', 'view', $is_owner)) { + $array_assign['CONTACT'] = 'a'; + } else { + $array_assign['CONTACT'] = 'span'; + } + return $array_assign; + } + + + function save_relationship_changes($is_update) { + $exclude = array(); + if(empty($this->in_workflow)) { + if(empty($this->in_import)){//if a meeting is being imported then contact_id should not be excluded + //if the global soap_server_object variable is not empty (as in from a soap/OPI call), then process the assigned_user_id relationship, otherwise + //add assigned_user_id to exclude list and let the logic from MeetingFormBase determine whether assigned user id gets added to the relationship + if(!empty($GLOBALS['soap_server_object'])){ + $exclude = array('contact_id', 'user_id'); + }else{ + $exclude = array('contact_id', 'user_id','assigned_user_id'); + } + } + else{ + $exclude = array('user_id'); + } + } + parent::save_relationship_changes($is_update, $exclude); + } + + + /** + * @see SugarBean::afterImportSave() + */ + public function afterImportSave() + { + if ( $this->parent_type == 'Contacts' ) { + $this->load_relationship('contacts'); + if ( !$this->contacts->relationship_exists('contacts',array('id'=>$this->parent_id)) ) + $this->contacts->add($this->parent_id); + } + elseif ( $this->parent_type == 'Leads' ) { + $this->load_relationship('leads'); + if ( !$this->leads->relationship_exists('leads',array('id'=>$this->parent_id)) ) + $this->leads->add($this->parent_id); + } + + parent::afterImportSave(); + } + + public function getDefaultStatus() + { + $def = $this->field_defs['status']; + if (isset($def['default'])) { + return $def['default']; + } else { + $app = return_app_list_strings_language($GLOBALS['current_language']); + if (isset($def['options']) && isset($app[$def['options']])) { + $keys = array_keys($app[$def['options']]); + return $keys[0]; + } + } + return ''; + } +} // end class def + +// External API integration, for the dropdown list of what external API's are available +function getMeetingsExternalApiDropDown($focus = null, $name = null, $value = null, $view = null) { + require_once('include/externalAPI/ExternalAPIFactory.php'); + + $apiList = ExternalAPIFactory::getModuleDropDown('Meetings'); + $apiList = array_merge(array('Sugar'=>$GLOBALS['app_list_strings']['eapm_list']['Sugar']),$apiList); + if(!empty($value) && empty($apiList[$value])){ + $apiList[$value] = $value; + } + return $apiList; + +} + +?> diff --git a/modules/Meetings/MeetingFormBase.php b/modules/Meetings/MeetingFormBase.php new file mode 100644 index 00000000..5cbee47d --- /dev/null +++ b/modules/Meetings/MeetingFormBase.php @@ -0,0 +1,457 @@ +get_cal_date_format(); + +$lbl_required_symbol = $app_strings['LBL_REQUIRED_SYMBOL']; +$lbl_date = $mod_strings['LBL_DATE']; +$lbl_time = $mod_strings['LBL_TIME']; +$ntc_date_format = $timedate->get_user_date_format(); +$ntc_time_format = '('.$timedate->get_user_time_format().')'; + + $user_id = $current_user->id; +$default_status = $app_list_strings['meeting_status_default']; +$default_parent_type= $app_list_strings['record_type_default_key']; +$default_date_start = $timedate->nowDbDate(); +$default_time_start = $timedate->nowDbTime(); +$time_ampm = $timedate->AMPMMenu($prefix, $timedate->nowDbTime()); + // Unimplemented until jscalendar language files are fixed + // $cal_lang =(empty($cal_codes[$current_language])) ? $cal_codes[$default_language] : $cal_codes[$current_language]; +$jsCalendarImage = SugarThemeRegistry::current()->getImageURL('jscalendar.gif'); + $form = << + + + + + +

    $lbl_subject$lbl_required_symbol
    +
    + $lbl_date $lbl_required_symbol $ntc_date_format
    + {$app_strings['LBL_ENTER_DATE']}
    + $lbl_time $lbl_required_symbol $ntc_time_format
    + {$time_ampm}

    + +EOF; + + +$javascript = new javascript(); +$javascript->setFormName($formname); +$javascript->setSugarBean(new Meeting()); +$javascript->addRequiredFields($prefix); +$form .=$javascript->getScript(); +$mod_strings = $temp_strings; +return $form; +} + + + +function getForm($prefix, $mod='Meetings'){ + if(!ACLController::checkAccess('Meetings', 'edit', true)){ + return ''; + } + + global $app_strings; + global $app_list_strings; + + if(!empty($mod)){ + global $current_language; + $mod_strings = return_module_language($current_language, $mod); + } else { + global $mod_strings; + } + + $lbl_save_button_title = $app_strings['LBL_SAVE_BUTTON_TITLE']; + $lbl_save_button_key = $app_strings['LBL_SAVE_BUTTON_KEY']; + $lbl_save_button_label = $app_strings['LBL_SAVE_BUTTON_LABEL']; + + +$the_form = get_left_form_header($mod_strings['LBL_NEW_FORM_TITLE']); +$the_form .= << + + + + +EOQ; +$the_form .= $this->getFormBody($prefix, 'Meetings',"{$prefix}MeetingSave" ); +$the_form .= <<

    + +EOQ; + +$the_form .= get_left_form_footer(); +$the_form .= get_validate_record_js(); + +return $the_form; +} + + +/** + * handles save functionality for meetings + * @param string prefix + * @param bool redirect default True + * @param bool useRequired default True + */ +function handleSave($prefix,$redirect=true, $useRequired=false) { + + + require_once('include/formbase.php'); + + global $current_user; + global $timedate; + + $focus = new Meeting(); + + if($useRequired && !checkRequired($prefix, array_keys($focus->required_fields))) { + return null; + } + + if( !isset($_POST['reminder_checked']) or ( isset($_POST['reminder_checked']) && $_POST['reminder_checked'] == '0')) { + $_POST['reminder_time'] = -1; + } + if(!isset($_POST['reminder_time'])) { + $_POST['reminder_time'] = $current_user->getPreference('reminder_time'); + $_POST['reminder_checked']=1; + } + $time_format = $timedate->get_user_time_format(); + $time_separator = ":"; + if(preg_match('/\d+([^\d])\d+([^\d]*)/s', $time_format, $match)) { + $time_separator = $match[1]; + } + + if(!empty($_POST[$prefix.'time_hour_start']) && empty($_POST['time_start'])) { + $_POST[$prefix.'time_start'] = $_POST[$prefix.'time_hour_start']. $time_separator .$_POST[$prefix.'time_minute_start']; + } + + if(isset($_POST[$prefix.'meridiem']) && !empty($_POST[$prefix.'meridiem'])) { + $_POST[$prefix.'time_start'] = $timedate->merge_time_meridiem($_POST[$prefix.'time_start'],$timedate->get_time_format(), $_POST[$prefix.'meridiem']); + } + + if(isset($_POST[$prefix.'time_start']) && strlen($_POST[$prefix.'date_start']) == 10) { + $_POST[$prefix.'date_start'] = $_POST[$prefix.'date_start'] . ' ' . $_POST[$prefix.'time_start']; + } + + // retrieve happens here + $focus = populateFromPost($prefix, $focus); + if(!$focus->ACLAccess('Save')) { + ACLController::displayNoAccess(true); + sugar_cleanup(true); + } + + //add assigned user and current user if this is the first time bean is saved + if(empty($focus->id) && !empty($_REQUEST['return_module']) && $_REQUEST['return_module'] =='Meetings' && !empty($_REQUEST['return_action']) && $_REQUEST['return_action'] =='DetailView'){ + //if return action is set to detail view and return module to meeting, then this is from the long form, do not add the assigned user (only the current user) + //The current user is already added to UI and we want to give the current user the option of opting out of meeting. + //add current user if the assigned to user is different than current user. + if($current_user->id != $_POST['assigned_user_id']){ + $_POST['user_invitees'] .= ','.$_POST['assigned_user_id'].', '; + $_POST['user_invitees'] = str_replace(',,', ',', $_POST['user_invitees']); + } + }elseif (empty($focus->id) ){ + //this is not from long form so add assigned and current user automatically as there is no invitee list UI. + //This call could be through an ajax call from subpanels or shortcut bar + $_POST['user_invitees'] .= ','.$_POST['assigned_user_id'].', '; + + //add current user if the assigned to user is different than current user. + if($current_user->id != $_POST['assigned_user_id']){ + $_POST['user_invitees'] .= ','.$current_user->id.', '; + } + + //remove any double comma's introduced during appending + $_POST['user_invitees'] = str_replace(',,', ',', $_POST['user_invitees']); + } + + + if(isset($_POST['isSaveFromDetailView']) && $_POST['isSaveFromDetailView'] == 'true'){ + $focus->save(true); + $return_id = $focus->id; + }else{ + if(empty($_REQUEST['return_module']) && empty($_REQUEST['return_action']) && $focus->status == 'Held'){ + //if we are closing the meeting, and the request does not have a return module AND return action set, then + //the request is coming from a dashlet or subpanel close icon and there is no need to process user invitees, + //just save the current values. + $focus->save(true); + }else{ + /////////////////////////////////////////////////////////////////////////// + //// REMOVE INVITEE RELATIONSHIPS + if(!empty($_POST['user_invitees'])) { + $userInvitees = explode(',', trim($_POST['user_invitees'], ',')); + } else { + $userInvitees = array(); + } + + // Calculate which users to flag as deleted and which to add + $deleteUsers = array(); + $focus->load_relationship('users'); + // Get all users for the meeting + $q = 'SELECT mu.user_id, mu.accept_status FROM meetings_users mu WHERE mu.meeting_id = \''.$focus->id.'\''; + $r = $focus->db->query($q); + $acceptStatusUsers = array(); + while($a = $focus->db->fetchByAssoc($r)) { + if(!in_array($a['user_id'], $userInvitees)) { + $deleteUsers[$a['user_id']] = $a['user_id']; + } else { + $acceptStatusUsers[$a['user_id']] = $a['accept_status']; + } + } + + if(count($deleteUsers) > 0) { + $sql = ''; + foreach($deleteUsers as $u) { + $sql .= ",'" . $u . "'"; + } + $sql = substr($sql, 1); + // We could run a delete SQL statement here, but will just mark as deleted instead + $sql = "UPDATE meetings_users set deleted = 1 where user_id in ($sql) AND meeting_id = '". $focus->id . "'"; + $focus->db->query($sql); + } + + // Get all contacts for the meeting + if(!empty($_POST['contact_invitees'])) { + $contactInvitees = explode(',', trim($_POST['contact_invitees'], ',')); + } else { + $contactInvitees = array(); + } + + $deleteContacts = array(); + $focus->load_relationship('contacts'); + $q = 'SELECT mu.contact_id, mu.accept_status FROM meetings_contacts mu WHERE mu.meeting_id = \''.$focus->id.'\''; + $r = $focus->db->query($q); + $acceptStatusContacts = array(); + while($a = $focus->db->fetchByAssoc($r)) { + if(!in_array($a['contact_id'], $contactInvitees)) { + $deleteContacts[$a['contact_id']] = $a['contact_id']; + } else { + $acceptStatusContacts[$a['contact_id']] = $a['accept_status']; + } + } + + if(count($deleteContacts) > 0) { + $sql = ''; + foreach($deleteContacts as $u) { + $sql .= ",'" . $u . "'"; + } + $sql = substr($sql, 1); + // We could run a delete SQL statement here, but will just mark as deleted instead + $sql = "UPDATE meetings_contacts set deleted = 1 where contact_id in ($sql) AND meeting_id = '". $focus->id . "'"; + $focus->db->query($sql); + } + if(!empty($_POST['lead_invitees'])) { + $leadInvitees = explode(',', trim($_POST['lead_invitees'], ',')); + } else { + $leadInvitees = array(); + } + + $deleteLeads = array(); + $focus->load_relationship('leads'); + $q = 'SELECT mu.lead_id, mu.accept_status FROM meetings_leads mu WHERE mu.meeting_id = \''.$focus->id.'\''; + $r = $focus->db->query($q); + $acceptStatusLeads = array(); + while($a = $focus->db->fetchByAssoc($r)) { + if(!in_array($a['lead_id'], $leadInvitees)) { + $deleteLeads[$a['lead_id']] = $a['lead_id']; + } else { + $acceptStatusLeads[$a['lead_id']] = $a['accept_status']; + } + } + + if(count($deleteLeads) > 0) { + $sql = ''; + foreach($deleteLeads as $u) { + $sql .= ",'" . $u . "'"; + } + $sql = substr($sql, 1); + // We could run a delete SQL statement here, but will just mark as deleted instead + $sql = "UPDATE meetings_leads set deleted = 1 where lead_id in ($sql) AND meeting_id = '". $focus->id . "'"; + $focus->db->query($sql); + } + //// END REMOVE + /////////////////////////////////////////////////////////////////////////// + + + /////////////////////////////////////////////////////////////////////////// + //// REBUILD INVITEE RELATIONSHIPS + $focus->users_arr = array(); + $focus->users_arr = $userInvitees; + $focus->contacts_arr = array(); + $focus->contacts_arr = $contactInvitees; + $focus->leads_arr = array(); + $focus->leads_arr = $leadInvitees; + + if(!empty($_POST['parent_id']) && $_POST['parent_type'] == 'Contacts') { + $focus->contacts_arr[] = $_POST['parent_id']; + } + if(!empty($_POST['parent_id']) && $_POST['parent_type'] == 'Leads') { + $focus->leads_arr[] = $_POST['parent_id']; + } + // Call the Meeting module's save function to handle saving other fields besides + // the users and contacts relationships + $focus->save(true); + $return_id = $focus->id; + if(empty($return_id)){ + //this is to handle the situation where the save fails, most likely because of a failure + //in the external api. bug: 42200 + $_REQUEST['action'] = 'EditView'; + $_REQUEST['return_action'] = 'EditView'; + handleRedirect('', 'Meetings'); + } + // Process users + $existing_users = array(); + if(!empty($_POST['existing_invitees'])) { + $existing_users = explode(",", trim($_POST['existing_invitees'], ',')); + } + + foreach($focus->users_arr as $user_id) { + if(empty($user_id) || isset($existing_users[$user_id]) || isset($deleteUsers[$user_id])) { + continue; + } + + if(!isset($acceptStatusUsers[$user_id])) { + $focus->users->add($user_id); + } else { + // update query to preserve accept_status + $qU = 'UPDATE meetings_users SET deleted = 0, accept_status = \''.$acceptStatusUsers[$user_id].'\' '; + $qU .= 'WHERE meeting_id = \''.$focus->id.'\' '; + $qU .= 'AND user_id = \''.$user_id.'\''; + $focus->db->query($qU); + } + } + + // Process contacts + $existing_contacts = array(); + if(!empty($_POST['existing_contact_invitees'])) { + $existing_contacts = explode(",", trim($_POST['existing_contact_invitees'], ',')); + } + + foreach($focus->contacts_arr as $contact_id) { + if(empty($contact_id) || isset($existing_contacts[$contact_id]) || isset($deleteContacts[$contact_id])) { + continue; + } + + if(!isset($acceptStatusContacts[$contact_id])) { + $focus->contacts->add($contact_id); + } else { + // update query to preserve accept_status + $qU = 'UPDATE meetings_contacts SET deleted = 0, accept_status = \''.$acceptStatusContacts[$contact_id].'\' '; + $qU .= 'WHERE meeting_id = \''.$focus->id.'\' '; + $qU .= 'AND contact_id = \''.$contact_id.'\''; + $focus->db->query($qU); + } + } + // Process leads + $existing_leads = array(); + if(!empty($_POST['existing_lead_invitees'])) { + $existing_leads = explode(",", trim($_POST['existing_lead_invitees'], ',')); + } + + foreach($focus->leads_arr as $lead_id) { + if(empty($lead_id) || isset($existing_leads[$lead_id]) || isset($deleteLeads[$lead_id])) { + continue; + } + + if(!isset($acceptStatusLeads[$lead_id])) { + $focus->leads->add($lead_id); + } else { + // update query to preserve accept_status + $qU = 'UPDATE meetings_leads SET deleted = 0, accept_status = \''.$acceptStatusLeads[$lead_id].'\' '; + $qU .= 'WHERE meeting_id = \''.$focus->id.'\' '; + $qU .= 'AND lead_id = \''.$lead_id.'\''; + $focus->db->query($qU); + } + } + + // CCL - Comment out call to set $current_user as invitee + // set organizer to auto-accept + //$focus->set_accept_status($current_user, 'accept'); + + //// END REBUILD INVITEE RELATIONSHIPS + /////////////////////////////////////////////////////////////////////////// + } + } + if (isset($_REQUEST['return_module']) && $_REQUEST['return_module'] == 'Home'){ + header("Location: index.php?module=Home&action=index"); + } + else if($redirect) { + handleRedirect($return_id, 'Meetings'); + } else { + return $focus; + } + +} // end handleSave(); + +} // end Class def +?> diff --git a/modules/Meetings/MeetingsQuickCreate.php b/modules/Meetings/MeetingsQuickCreate.php new file mode 100644 index 00000000..4f1202a3 --- /dev/null +++ b/modules/Meetings/MeetingsQuickCreate.php @@ -0,0 +1,165 @@ +ss->assign("STATUS_OPTIONS", get_select_options_with_id($app_list_strings['meeting_status_dom'], $app_list_strings['meeting_status_default'])); + $this->ss->assign("CALENDAR_DATEFORMAT", $timedate->get_cal_date_format()); + $this->ss->assign("TIME_FORMAT", '('. $timedate->get_user_time_format().')'); + $this->ss->assign("USER_DATEFORMAT", '('. $timedate->get_user_date_format().')'); + + + + + if($this->viaAJAX) { // override for ajax call + $this->ss->assign('saveOnclick', "onclick='if(check_form(\"meetingsQuickCreate\")) return SUGAR.subpanelUtils.inlineSave(this.form.id, \"activities\"); else return false;'"); + $this->ss->assign('cancelOnclick', "onclick='return SUGAR.subpanelUtils.cancelCreate(\"subpanel_activities\")';"); + } + + $this->ss->assign('viaAJAX', $this->viaAJAX); + + $this->javascript = new javascript(); + $this->javascript->setFormName('meetingsQuickCreate'); + + $focus = new Meeting(); + $this->javascript->setSugarBean($focus); + $this->javascript->addAllFields(''); + + if (is_null($focus->date_start)) + $focus->date_start = $timedate->to_display_date(TimeDate::getInstance()->nowDb()); + if (is_null($focus->time_start)) + $focus->time_start = $timedate->to_display_time(TimeDate::getInstance()->nowDb(), true); + if (!isset ($focus->duration_hours)) + $focus->duration_hours = "1"; + + + $date_start_array=explode(" ",trim($focus->date_start)); + if (count($date_start_array)==2) { + $focus->time_start = $timedate->to_db_time($date_start_array[1], false); + //$focus->date_start = $date_start_array[0]; + } + + $this->ss->assign("DATE_START", $focus->date_start); + $this->ss->assign("TIME_START", substr($focus->time_start,0,5)); + $time_start_hour = intval(substr($focus->time_start, 0, 2)); + $time_start_minutes = substr($focus->time_start, 3, 5); + + if ($time_start_minutes > 0 && $time_start_minutes < 15) { + $time_start_minutes = "15"; + } else + if ($time_start_minutes > 15 && $time_start_minutes < 30) { + $time_start_minutes = "30"; + } else + if ($time_start_minutes > 30 && $time_start_minutes < 45) { + $time_start_minutes = "45"; + } else + if ($time_start_minutes > 45) { + $time_start_hour += 1; + $time_start_minutes = "00"; + } + + + // We default the to assume that the time preference is set to 11:00 (i.e. without meridiem) + $hours_arr = array (); + $num_of_hours = 24; + $start_at = 0; + + $time_pref = $timedate->get_time_format(); + if(strpos($time_pref, 'a') || strpos($time_pref, 'A')) { + $num_of_hours = 13; + $start_at = 1; + } + + /* + // Seems to be problematic... $time_meridiem is always empty + if (empty ($time_meridiem)) { + $num_of_hours = 24; + $start_at = 0; + } + */ + + for ($i = $start_at; $i < $num_of_hours; $i ++) { + $i = $i.""; + if (strlen($i) == 1) { + $i = "0".$i; + } + $hours_arr[$i] = $i; + } + + $this->ss->assign("TIME_START_HOUR_OPTIONS", get_select_options_with_id($hours_arr, $time_start_hour)); + $this->ss->assign("TIME_START_MINUTE_OPTIONS", get_select_options_with_id($focus->minutes_values, $time_start_minutes)); + $this->ss->assign("DURATION_HOURS", $focus->duration_hours); + $this->ss->assign("DURATION_MINUTES_OPTIONS", get_select_options_with_id($focus->minutes_values, $focus->duration_minutes)); + // Test to see if time format is 11:00am; otherwise it's 11:00AM + if($num_of_hours == 13) { + + if (strpos($time_pref, 'a')) { + + if(!isset($focus->meridiem_am_values)) { + $focus->meridiem_am_values = array('am'=>'am', 'pm'=>'pm'); + } + + $this->ss->assign("TIME_MERIDIEM", get_select_options_with_id($focus->meridiem_am_values, $time_start_hour < 12 ? 'am' : 'pm')); + + } else { + if(!isset($focus->meridiem_AM_values)) { + $focus->meridiem_AM_values = array('AM'=>'AM', 'PM'=>'PM'); + } + + $this->ss->assign("TIME_MERIDIEM", get_select_options_with_id($focus->meridiem_AM_values, $time_start_hour < 12 ? 'AM' : 'PM')); + + } //if-else + + } + + $this->ss->assign('additionalScripts', $this->javascript->getScript(false)); + } +} +?> diff --git a/modules/Meetings/Menu.php b/modules/Meetings/Menu.php new file mode 100644 index 00000000..17badb60 --- /dev/null +++ b/modules/Meetings/Menu.php @@ -0,0 +1,54 @@ + diff --git a/modules/Meetings/Save.php b/modules/Meetings/Save.php new file mode 100644 index 00000000..c2e39b97 --- /dev/null +++ b/modules/Meetings/Save.php @@ -0,0 +1,50 @@ +handleSave('', true, false); +?> diff --git a/modules/Meetings/SubPanelViewInvitees.html b/modules/Meetings/SubPanelViewInvitees.html new file mode 100644 index 00000000..66f64b6e --- /dev/null +++ b/modules/Meetings/SubPanelViewInvitees.html @@ -0,0 +1,95 @@ + + +

    {APP.LBL_USER_LIST}

    + + + + + + + + + + + + + + + + + + + + + + + + + +
    {APP.LBL_LIST_NAME}{APP.LBL_LIST_USER_NAME}{APP.LBL_LIST_EMAIL}{APP.LBL_LIST_PHONE}
    {USER.FIRST_NAME} {USER.LAST_NAME}{USER.USER_NAME}{USER.EMAIL1}{USER.PHONE_WORK}

    + + + +

    {APP.LBL_CONTACT_LIST}

    + + + + + + + + + + + + + + + + + + + + + +
    {APP.LBL_LIST_CONTACT_NAME}{APP.LBL_LIST_ACCOUNT_NAME}{APP.LBL_LIST_EMAIL}{APP.LBL_LIST_PHONE}
    {CONTACT.FIRST_NAME} {CONTACT.LAST_NAME}{CONTACT.ACCOUNT_NAME}{CONTACT.EMAIL1}{CONTACT.PHONE_WORK}

    + diff --git a/modules/Meetings/SubPanelViewInvitees.php b/modules/Meetings/SubPanelViewInvitees.php new file mode 100644 index 00000000..87271508 --- /dev/null +++ b/modules/Meetings/SubPanelViewInvitees.php @@ -0,0 +1,150 @@ +
    \n"; +$button .= "\n"; +if ($currentModule == 'Accounts') $button .= "\n\n"; +$button .= "\n"; +$button .= "\n"; +$button .= "\n"; +$button .= "\n"; +$button .= "
     
    \n"; + +// Stick the form header out there. +echo get_form_header($mod_strings['LBL_INVITEE'], $button, false); +$xtpl=new XTemplate ('modules/Meetings/SubPanelViewInvitees.html'); +$xtpl->assign("MOD", $mod_strings); +$xtpl->assign("APP", $app_strings); +$xtpl->assign("RETURN_URL", "&return_module=$currentModule&return_action=DetailView&return_id=$focus->id"); +$xtpl->assign("MEETING_ID", $focus->id); + +$oddRow = true; +foreach($focus_users_list as $user) +{ + $user_fields = array( + 'USER_NAME' => $user->user_name, + 'FULL_NAME' => $locale->getLocaleFormattedName($user->first_name, $user->last_name), + 'ID' => $user->id, + 'EMAIL' => $user->email1, + 'PHONE_WORK' => $user->phone_work + ); + + $xtpl->assign("USER", $user_fields); + + if($oddRow) + { + //todo move to themes + $xtpl->assign("ROW_COLOR", 'oddListRow'); + } + else + { + //todo move to themes + $xtpl->assign("ROW_COLOR", 'evenListRow'); + } + $oddRow = !$oddRow; + + $xtpl->parse("users.row"); +// Put the rows in. +} + +$xtpl->parse("users"); +$xtpl->out("users"); + +$oddRow = true; +foreach($focus_contacts_list as $contact) +{ + $contact_fields = array( + 'FIRST_NAME' => $contact->first_name, + 'LAST_NAME' => $contact->last_name, + 'ACCOUNT_NAME' => $contact->account_name, + 'ID' => $contact->id, + 'EMAIL' => $contact->email1, + 'PHONE_WORK' => $contact->phone_work + ); + + $xtpl->assign("CONTACT", $contact_fields); + + if($oddRow) + { + //todo move to themes + $xtpl->assign("ROW_COLOR", 'oddListRow'); + } + else + { + //todo move to themes + $xtpl->assign("ROW_COLOR", 'evenListRow'); + } + $oddRow = !$oddRow; + + $xtpl->parse("contacts.row"); +// Put the rows in. +} + +$xtpl->parse("contacts"); +$xtpl->out("contacts"); + +?> diff --git a/modules/Meetings/action_view_map.php b/modules/Meetings/action_view_map.php new file mode 100644 index 00000000..4c48d890 --- /dev/null +++ b/modules/Meetings/action_view_map.php @@ -0,0 +1,38 @@ + Array("id" + , "date_entered" + , "date_modified" + , "assigned_user_id" + , "modified_user_id" + , "created_by" + , "description" + , "name" + , "status" + , "location" + , "date_start" + , "time_start" + , "date_end" + , "duration_hours" + , "duration_minutes" + , "parent_type" + , "parent_id" + , 'reminder_time' + ,'outlook_id' + ), + 'list_fields' => Array('id', 'location', 'duration_hours', 'name ', 'status', 'parent_type', 'parent_name', 'parent_id', 'date_start', 'time_start', 'assigned_user_name', 'assigned_user_id', 'contact_name', 'contact_id','first_name','last_name','required','accept_status','outlook_id','duration_minutes' + ), + 'required_fields' => array("name"=>1, "date_start"=>2, "time_start"=>3, "duration_hours"=>4), +); +?> \ No newline at end of file diff --git a/modules/Meetings/jsclass_scheduler.js b/modules/Meetings/jsclass_scheduler.js new file mode 100644 index 00000000..44710dbf --- /dev/null +++ b/modules/Meetings/jsclass_scheduler.js @@ -0,0 +1,109 @@ +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ +SugarClass.inherit("SugarWidgetListView","SugarClass");function SugarWidgetListView(){this.init();} +SugarWidgetListView.prototype.init=function(){} +SugarWidgetListView.prototype.load=function(parentNode){this.parentNode=parentNode;this.display();} +SugarWidgetListView.prototype.display=function(){if(typeof GLOBAL_REGISTRY['result_list']=='undefined'){this.display_loading();return;} +var div=document.getElementById('list_div_win');div.style.display='block';var html='';html+='';html+='';html+='';html+='';html+='';html+='';html+='';for(var i=0;i';html+='';html+='';html+='';html+='';html+='';html+='';} +html+='
     '+GLOBAL_REGISTRY['meeting_strings']['LBL_NAME']+''+GLOBAL_REGISTRY['meeting_strings']['LBL_EMAIL']+''+GLOBAL_REGISTRY['meeting_strings']['LBL_PHONE']+' 
    '+bean.fields.full_name+''+bean.fields.email1+''+bean.fields.phone_work+'';hidden='visible';if(!disabled){} +html+='';html+='
    ';this.parentNode.innerHTML=html;} +SugarWidgetListView.prototype.display_loading=function(){} +SugarClass.inherit("SugarWidgetSchedulerSearch","SugarClass");function SugarWidgetSchedulerSearch(){this.init();} +SugarWidgetSchedulerSearch.prototype.init=function(){this.form_id='scheduler_search';GLOBAL_REGISTRY['widget_element_map']=new Object();GLOBAL_REGISTRY['widget_element_map'][this.form_id]=this;} +SugarWidgetSchedulerSearch.prototype.load=function(parentNode){this.parentNode=parentNode;this.display();} +SugarWidgetSchedulerSearch.submit=function(form){var conditions=new Array();if(form.search_first_name.value!=''){conditions[conditions.length]={"name":"first_name","op":"starts_with","value":form.search_first_name.value}} +if(form.search_last_name.value!=''){conditions[conditions.length]={"name":"last_name","op":"starts_with","value":form.search_last_name.value}} +if(form.search_email.value!=''){conditions[conditions.length]={"name":"email1","op":"starts_with","value":form.search_email.value}} +var query={"modules":["Users","Contacts","Leads"],"group":"and","field_list":['id','full_name','email1','phone_work'],"conditions":conditions};global_request_registry[req_count]=[this,'display'];req_id=global_rpcClient.call_method('query',query);global_request_registry[req_id]=[GLOBAL_REGISTRY['widget_element_map'][form.id],'refresh_list'];} +SugarWidgetSchedulerSearch.prototype.refresh_list=function(rslt){GLOBAL_REGISTRY['result_list']=rslt['list'];this.list_view.display();} +SugarWidgetSchedulerSearch.prototype.display=function(){var html='

    '+GLOBAL_REGISTRY['meeting_strings']['LBL_ADD_INVITEE']+'

    ';html+='
    ';html+='
    ';html+='' +html+='';html+='';html+='';html+='';html+='';html+='
    '+GLOBAL_REGISTRY['meeting_strings']['LBL_FIRST_NAME']+':  '+GLOBAL_REGISTRY['meeting_strings']['LBL_LAST_NAME']+':  '+GLOBAL_REGISTRY['meeting_strings']['LBL_EMAIL']+':  
    ';html+='
    ';html+='
    ';this.parentNode.innerHTML+=html;var div=document.createElement('div');div.setAttribute('id','list_div_win');div.style.overflow='auto';div.style.width='100%';div.style.height='125px';div.style.display='none';this.parentNode.appendChild(div);this.list_view=new SugarWidgetListView();this.list_view.load(div);} +SugarClass.inherit("SugarWidgetScheduler","SugarClass");function SugarWidgetScheduler(){this.init();} +SugarWidgetScheduler.prototype.init=function(){} +SugarWidgetScheduler.prototype.load=function(parentNode){this.parentNode=parentNode;this.display();} +SugarWidgetScheduler.fill_invitees=function(form){for(var i=0;i';html+='';html+='';html+='';html+='';html+='';for(var i=0;i<(this.timeslots.length/this.segments);i++){var hours=this.timeslots[i*this.segments].date_obj.getHours();var am_pm='';if(time_reg_format.indexOf('A')>=0||time_reg_format.indexOf('a')>=0){am_pm="AM";if(hours>12){am_pm="PM";hours-=12;} +if(hours==12){am_pm="PM";} +if(hours==0){hours=12;am_pm="AM";} +if(time_reg_format.indexOf('a')>=0){am_pm=am_pm.toLowerCase();} +if(hours!=0&&hours!=12&&i!=0){am_pm="";}} +var form_hours=hours+time_separator+"00";html+='';} +html+='';html+='';html+='

    '+top_date+'

     '+form_hours+am_pm+' 
    ';if(this.parentNode.childNodes.length<1) +this.parentNode.innerHTML+='
    '+html+'
    ';else +this.parentNode.childNodes[0].innerHTML=html;var thetable="schedulerTable";if(typeof(GLOBAL_REGISTRY)=='undefined'){return;} +if((typeof(GLOBAL_REGISTRY.focus.users_arr)=='undefined'||GLOBAL_REGISTRY.focus.users_arr.length==0)&&document.EditView.record.value==''&&typeof(GLOBAL_REGISTRY.FIRST_REMOVE)=='undefined'){GLOBAL_REGISTRY.focus.users_arr=[GLOBAL_REGISTRY.current_user];} +if(typeof GLOBAL_REGISTRY.focus.users_arr_hash=='undefined'){GLOBAL_REGISTRY.focus.users_arr_hash=new Object();} +for(var i=0;i ';td.innerHTML=img;td.innerHTML=td.innerHTML;if(self.focus_bean.fields.full_name) +td.innerHTML+=' '+self.focus_bean.fields.full_name;else +td.innerHTML+=' '+self.focus_bean.fields.name;this.add_freebusy_nodes(tr);var td=document.createElement('td');tr.appendChild(td);td.className='schedulerAttendeeDeleteCell';td.noWrap=true;td.innerHTML=' '+GLOBAL_REGISTRY['meeting_strings']['LBL_REMOVE']+' '+GLOBAL_REGISTRY['meeting_strings']['LBL_REMOVE']+'';this.element=tr;this.element_index=this.thetable.rows.length-1;} +SugarWidgetScheduleRow.deleteRow=function(bean_id){for(var i=0;i=fb_limit){td.style.backgroundColor="#AA4D4D";}else{td.style.backgroundColor="#4D5EAA";}}}}}} \ No newline at end of file diff --git a/modules/Meetings/language/en_us.lang.php b/modules/Meetings/language/en_us.lang.php new file mode 100644 index 00000000..b6f4aedc --- /dev/null +++ b/modules/Meetings/language/en_us.lang.php @@ -0,0 +1,143 @@ + 'A record number must be specified to delete the meeting.', + + 'LBL_ACCEPT_THIS'=>'Accept?', + 'LBL_ADD_BUTTON'=> 'Add', + 'LBL_ADD_INVITEE' => 'Add Invitees', + 'LBL_COLON' => ':', + 'LBL_CONTACT_NAME' => 'Contact:', + 'LBL_CONTACTS_SUBPANEL_TITLE' => 'Contacts', + 'LBL_CREATED_BY'=>'Created by', + 'LBL_DATE_END'=>'Date End', + 'LBL_DATE_TIME' => 'Start Date & Time:', + 'LBL_DATE' => 'Start Date:', + 'LBL_DEFAULT_SUBPANEL_TITLE' => 'Meetings', + 'LBL_DEL'=> 'Del', + 'LBL_DESCRIPTION_INFORMATION' => 'Description Information', + 'LBL_DESCRIPTION' => 'Description:', + 'LBL_DURATION_HOURS' => 'Duration Hours:', + 'LBL_DURATION_MINUTES' => 'Duration Minutes:', + 'LBL_DURATION' => 'Duration:', + 'LBL_EMAIL' => 'Email', + 'LBL_FIRST_NAME' => 'First Name', + 'LBL_HISTORY_SUBPANEL_TITLE' => 'Notes', + 'LBL_HOURS_ABBREV' => 'h', + 'LBL_HOURS_MINS' => '(hours/minutes)', + 'LBL_INVITEE' => 'Invitees', + 'LBL_LAST_NAME' => 'Last Name', + 'LBL_ASSIGNED_TO_NAME'=>'Assigned to:', + 'LBL_LIST_ASSIGNED_TO_NAME' => 'Assigned User', + 'LBL_LIST_CLOSE' => 'Close', + 'LBL_LIST_CONTACT' => 'Contact', + 'LBL_LIST_DATE_MODIFIED'=>'Date Modified', + 'LBL_LIST_DATE' => 'Start Date', + 'LBL_LIST_DIRECTION' => 'Direction', + 'LBL_LIST_DUE_DATE'=>'Due Date', + 'LBL_LIST_FORM_TITLE' => 'Meeting List', + 'LBL_LIST_MY_MEETINGS' => 'My Meetings', + 'LBL_LIST_RELATED_TO' => 'Related to', + 'LBL_LIST_STATUS'=>'Status', + 'LBL_LIST_SUBJECT' => 'Subject', + 'LBL_LIST_TIME' => 'Start Time', + 'LBL_LEADS_SUBPANEL_TITLE' => 'Leads', + 'LBL_LOCATION' => 'Location:', + 'LBL_MEETING' => 'Meeting:', + 'LBL_MINSS_ABBREV' => 'm', + 'LBL_MODIFIED_BY'=>'Modified by', + 'LBL_MODULE_NAME' => 'Meetings', + 'LBL_MODULE_TITLE' => 'Meetings: Home', + 'LBL_NAME' => 'Name', + 'LBL_NEW_FORM_TITLE' => 'Create Appointment', + 'LBL_OUTLOOK_ID' => 'Outlook ID', + 'LBL_PHONE' => 'Phone Office:', + 'LBL_REMINDER_TIME'=>'Reminder Time', + 'LBL_REMINDER' => 'Reminder:', + 'LBL_REMOVE' => 'rem', + 'LBL_SCHEDULING_FORM_TITLE' => 'Scheduling', + 'LBL_SEARCH_BUTTON'=> 'Search', + 'LBL_SEARCH_FORM_TITLE' => 'Meeting Search', + 'LBL_SEND_BUTTON_KEY'=>'I', + 'LBL_SEND_BUTTON_LABEL'=>'Send Invites', + 'LBL_SEND_BUTTON_TITLE'=>'Send Invites [Alt+I]', + 'LBL_STATUS' => 'Status:', + 'LBL_TYPE' => 'Meeting Type', + 'LBL_PASSWORD' => 'Meeting Password', + 'LBL_URL' => 'Start/Join Meeting', + 'LBL_CREATOR' => 'Meeting Creator', + 'LBL_EXTERNALID' => 'External App ID', + 'LBL_SUBJECT' => 'Subject:', + 'LBL_TIME' => 'Start Time:', + 'LBL_USERS_SUBPANEL_TITLE' => 'Users', + 'LBL_ACTIVITIES_REPORTS' => 'Activities Report', + + 'LNK_MEETING_LIST'=>'View Meetings', + 'LNK_NEW_APPOINTMENT' => 'Create Appointment', + 'LNK_NEW_MEETING'=>'Schedule Meeting', + 'LNK_IMPORT_MEETINGS' => 'Import Meetings', + + 'NTC_REMOVE_INVITEE' => 'Are you sure you want to remove this invitee from the meeting?', + 'LBL_CREATED_USER' => 'Created User', + 'LBL_MODIFIED_USER' => 'Modified User', + 'NOTICE_DURATION_TIME' => 'Duration time must be greater than 0', + 'LBL_MEETING_INFORMATION' => 'Meeting Overview', + 'LBL_LIST_JOIN_MEETING' => 'Join Meeting', + 'LBL_JOIN_EXT_MEETING' => 'Join Meeting', + 'LBL_HOST_EXT_MEETING' => 'Start Meeting', + + // You are not invited to the meeting messages + 'LBL_EXTNOT_HEADER' => 'Error: Not Invited', + 'LBL_EXTNOT_MAIN' => 'You are not able to join this meeting because you are not an Invitee.', + 'LBL_EXTNOT_RECORD_LINK' => 'View Meeting', + 'LBL_EXTNOT_GO_BACK' => 'Go back to the previous record', + + //cannot start messages + 'LBL_EXTNOSTART_HEADER' => 'Error: Cannot Start Meeting', + 'LBL_EXTNOSTART_MAIN' => 'You cannot start this meeting because you are not an Administrator or the owner of the meeting.', + +); +?> diff --git a/modules/Meetings/metadata/SearchFields.php b/modules/Meetings/metadata/SearchFields.php new file mode 100644 index 00000000..9dfbcf2f --- /dev/null +++ b/modules/Meetings/metadata/SearchFields.php @@ -0,0 +1,69 @@ + array( 'query_type'=>'default'), + 'contact_name' => array( 'query_type'=>'default','db_field'=>array('contacts.first_name','contacts.last_name')), + 'date_start' => array( 'query_type'=>'default'), + 'current_user_only'=> array('query_type'=>'default','db_field'=>array('assigned_user_id'),'my_items'=>true, 'vname' => 'LBL_CURRENT_USER_FILTER', 'type' => 'bool'), + 'assigned_user_id'=> array('query_type'=>'default'), + 'status'=> array('query_type'=>'default', 'options' => 'meeting_status_dom', 'template_var' => 'STATUS_FILTER'), + + 'open_only' => array( + 'query_type'=>'default', + 'db_field'=>array('status'), + 'operator'=>'not in', + 'closed_values' => array('Held', 'Not Held'), + 'type'=>'bool', + ), + //Range Search Support + 'range_date_entered' => array ('query_type' => 'default', 'enable_range_search' => true, 'is_date_field' => true), + 'start_range_date_entered' => array ('query_type' => 'default', 'enable_range_search' => true, 'is_date_field' => true), + 'end_range_date_entered' => array ('query_type' => 'default', 'enable_range_search' => true, 'is_date_field' => true), + 'range_date_modified' => array ('query_type' => 'default', 'enable_range_search' => true, 'is_date_field' => true), + 'start_range_date_modified' => array ('query_type' => 'default', 'enable_range_search' => true, 'is_date_field' => true), + 'end_range_date_modified' => array ('query_type' => 'default', 'enable_range_search' => true, 'is_date_field' => true), + 'range_date_start' => array ('query_type' => 'default', 'enable_range_search' => true, 'is_date_field' => true), + 'start_range_date_start' => array ('query_type' => 'default', 'enable_range_search' => true, 'is_date_field' => true), + 'end_range_date_start' => array ('query_type' => 'default', 'enable_range_search' => true, 'is_date_field' => true), + 'range_date_end' => array ('query_type' => 'default', 'enable_range_search' => true, 'is_date_field' => true), + 'start_range_date_end' => array ('query_type' => 'default', 'enable_range_search' => true, 'is_date_field' => true), + 'end_range_date_end' => array ('query_type' => 'default', 'enable_range_search' => true, 'is_date_field' => true), + //Range Search Support + ); +?> diff --git a/modules/Meetings/metadata/additionalDetails.php b/modules/Meetings/metadata/additionalDetails.php new file mode 100644 index 00000000..178ccf4c --- /dev/null +++ b/modules/Meetings/metadata/additionalDetails.php @@ -0,0 +1,85 @@ +'. $mod_strings['LBL_DATE_TIME'] . ' ' . $fields['DATE_START'] . '
    '; + if(isset($fields['DURATION_HOURS']) || isset($fields['DURATION_MINUTES'])) { + $overlib_string .= ''. $mod_strings['LBL_DURATION'] . ' '; + if(isset($fields['DURATION_HOURS'])) { + $overlib_string .= $fields['DURATION_HOURS'] . $mod_strings['LBL_HOURS_ABBREV'] . ' '; + } + if(isset($fields['DURATION_MINUTES'])) { + $overlib_string .= $fields['DURATION_MINUTES'] . $mod_strings['LBL_MINSS_ABBREV']; + } + $overlib_string .= '
    '; + } + if(!empty($fields['DESCRIPTION'])) { + $overlib_string .= ''. $mod_strings['LBL_DESCRIPTION'] . ' ' . substr($fields['DESCRIPTION'], 0, 300); + if(strlen($fields['DESCRIPTION']) > 300) $overlib_string .= '...'; + $overlib_string .= '
    '; + } + + $editLink = "index.php?action=EditView&module=Meetings&record={$fields['ID']}"; + $viewLink = "index.php?action=DetailView&module=Meetings&record={$fields['ID']}"; + + $return_module = empty($_REQUEST['module']) ? 'Meetings' : $_REQUEST['module']; + $return_action = empty($_REQUEST['action']) ? 'ListView' : $_REQUEST['action']; + + $editLink .= "&return_module=$return_module&return_action=$return_action"; + $viewLink .= "&return_module=$return_module&return_action=$return_action"; + + return array('fieldToAddTo' => 'NAME', + 'string' => $overlib_string, + 'editLink' => $editLink, + 'viewLink' => $viewLink); + +} + + ?> + + \ No newline at end of file diff --git a/modules/Meetings/metadata/detailviewdefs.php b/modules/Meetings/metadata/detailviewdefs.php new file mode 100644 index 00000000..633698ca --- /dev/null +++ b/modules/Meetings/metadata/detailviewdefs.php @@ -0,0 +1,143 @@ + + array ( + 'templateMeta' => + array ( + 'form' => + array ( + 'buttons' => + array ( + 0 => 'EDIT', + 1 => 'DUPLICATE', + 2 => 'DELETE', + 3 => + array ( + 'customCode' => '{if $fields.status.value != "Held"} {/if}', + ), + 4 => + array ( + 'customCode' => '{if $fields.status.value != "Held"} {/if}', + ), + ), + ), + 'maxColumns' => '2', + 'widths' => + array ( + 0 => + array ( + 'label' => '10', + 'field' => '30', + ), + 1 => + array ( + 'label' => '10', + 'field' => '30', + ), + ), + 'useTabs' => false, + ), + 'panels' => + array ( + 'lbl_meeting_information' => + array ( + array ( + array ( + 'name' => 'name', + 'label' => 'LBL_SUBJECT', + ), + 'status', + ), + array ( + array ( + 'name' => 'date_start', + 'label' => 'LBL_DATE_TIME', + ), + ), + array ( + array ( + 'name' => 'duration_hours', + 'customCode' => '{$fields.duration_hours.value}{$MOD.LBL_HOURS_ABBREV} {$fields.duration_minutes.value}{$MOD.LBL_MINSS_ABBREV} ', + 'label' => 'LBL_DURATION', + ), + array ( + 'name' => 'parent_name', + 'customLabel' => '{sugar_translate label=\'LBL_MODULE_NAME\' module=$fields.parent_type.value}', + ), + ), + array ( + array ( + 'name' => 'reminder_checked', + 'fields' => + array ( + 'reminder_checked', + 'reminder_time', + ), + ), + 'location', + ), + array ( + 'description', + ), + ), + 'LBL_PANEL_ASSIGNMENT' => + array ( + array ( + array ( + 'name' => 'assigned_user_name', + 'label' => 'LBL_ASSIGNED_TO', + ), + array ( + 'name' => 'date_modified', + 'label' => 'LBL_DATE_MODIFIED', + 'customCode' => '{$fields.date_modified.value} {$APP.LBL_BY} {$fields.modified_by_name.value}', + ), + + ), + array ( + array ( + 'name' => 'date_entered', + 'customCode' => '{$fields.date_entered.value} {$APP.LBL_BY} {$fields.created_by_name.value}', + ), + ), + ), + ), + ), +); +?> diff --git a/modules/Meetings/metadata/editviewdefs.php b/modules/Meetings/metadata/editviewdefs.php new file mode 100644 index 00000000..f3f7c395 --- /dev/null +++ b/modules/Meetings/metadata/editviewdefs.php @@ -0,0 +1,171 @@ + + array ( + 'templateMeta' => + array ( + 'maxColumns' => '2', + 'form' => + array ( + 'hidden' => + array ( + 0 => '', + ), + 'buttons' => + array ( + 0 => + array ( + 'customCode' => '', + ), + 1 => 'CANCEL', + 2 => + array ( + 'customCode' => '', + ), + 3 => + array ( + 'customCode' => '{if $fields.status.value != "Held"}{/if}', + ), + ), + 'headerTpl' => 'modules/Meetings/tpls/header.tpl', + 'footerTpl' => 'modules/Meetings/tpls/footer.tpl', + ), + 'widths' => + array ( + 0 => + array ( + 'label' => '10', + 'field' => '30', + ), + 1 => + array ( + 'label' => '10', + 'field' => '30', + ), + ), + 'javascript' => ' + + + + + + +', + 'useTabs' => false, + ), + 'panels' => + array ( + 'lbl_meeting_information' => + array ( + array ( + array ( + 'name' => 'name', + + ), + array ( + 'name' => 'status', + 'fields' => + array ( + array ( + 'name' => 'status', + ), + ), + ), + ), + + + array ( + array ( + 'name' => 'date_start', + 'type' => 'datetimecombo', + 'displayParams' => + array ( + + 'updateCallback' => 'SugarWidgetScheduler.update_time();', + ), + ), + + array ( + 'name' => 'parent_name', + 'label' => 'LBL_LIST_RELATED_TO', + ), + ), + + array ( + array ( + 'name' => 'duration_hours', + 'label' => 'LBL_DURATION', + 'customCode' => '{literal}{/literal}
    {$fields.duration_minutes.value} {$MOD.LBL_HOURS_MINS}
    ', + ), + array ( + 'name' => 'location', + 'comment' => 'Meeting location', + 'label' => 'LBL_LOCATION', + ), + + ), + array ( + array ( + 'name' => 'reminder_time', + 'customCode' => '{if $fields.reminder_checked.value == "1"}{assign var="REMINDER_TIME_DISPLAY" value="inline"}{assign var="REMINDER_CHECKED" value="checked"}{else}{assign var="REMINDER_TIME_DISPLAY" value="none"}{assign var="REMINDER_CHECKED" value=""}{/if}
    {$fields.reminder_time.value}
    ', + 'label' => 'LBL_REMINDER', + ), + ), + array ( + array ( + 'name' => 'description', + 'comment' => 'Full text of the note', + 'label' => 'LBL_DESCRIPTION', + ), + ), + ), + 'LBL_PANEL_ASSIGNMENT' => + array ( + array ( + array ( + 'name' => 'assigned_user_name', + 'label' => 'LBL_ASSIGNED_TO_NAME', + ), + ), + ), + ), + ), +); +?> diff --git a/modules/Meetings/metadata/listviewdefs.php b/modules/Meetings/metadata/listviewdefs.php new file mode 100644 index 00000000..c57630f1 --- /dev/null +++ b/modules/Meetings/metadata/listviewdefs.php @@ -0,0 +1,123 @@ + + array ( + 'width' => '1%', + 'label' => 'LBL_LIST_CLOSE', + 'link' => true, + 'sortable' => false, + 'default' => true, + 'related_fields' => + array ( + 0 => 'status', + ), + ), + 'NAME' => + array ( + 'width' => '40%', + 'label' => 'LBL_LIST_SUBJECT', + 'link' => true, + 'default' => true, + ), + 'CONTACT_NAME' => + array ( + 'width' => '20%', + 'label' => 'LBL_LIST_CONTACT', + 'link' => true, + 'id' => 'CONTACT_ID', + 'module' => 'Contacts', + 'default' => true, + 'ACLTag' => 'CONTACT', + ), + 'PARENT_NAME' => + array ( + 'width' => '20%', + 'label' => 'LBL_LIST_RELATED_TO', + 'dynamic_module' => 'PARENT_TYPE', + 'id' => 'PARENT_ID', + 'link' => true, + 'default' => true, + 'sortable' => false, + 'ACLTag' => 'PARENT', + 'related_fields' => + array ( + 0 => 'parent_id', + 1 => 'parent_type', + ), + ), + 'DATE_START' => + array ( + 'width' => '15%', + 'label' => 'LBL_LIST_DATE', + 'link' => false, + 'default' => true, + 'related_fields' => + array ( + 0 => 'time_start', + ), + ), + 'ASSIGNED_USER_NAME' => + array ( + 'width' => '2%', + 'label' => 'LBL_LIST_ASSIGNED_TO_NAME', + 'module' => 'Employees', + 'id' => 'ASSIGNED_USER_ID', + 'default' => true, + ), + 'DIRECTION' => + array ( + 'type' => 'enum', + 'label' => 'LBL_LIST_DIRECTION', + 'width' => '10%', + 'default' => false, + ), + 'STATUS' => + array ( + 'width' => '10%', + 'label' => 'LBL_LIST_STATUS', + 'link' => false, + 'default' => false, + ), + 'DATE_ENTERED' => array ( + 'width' => '10%', + 'label' => 'LBL_DATE_ENTERED', + 'default' => true + ), +); +?> diff --git a/modules/Meetings/metadata/quickcreatedefs.php b/modules/Meetings/metadata/quickcreatedefs.php new file mode 100644 index 00000000..116c1ff6 --- /dev/null +++ b/modules/Meetings/metadata/quickcreatedefs.php @@ -0,0 +1,177 @@ + + array ( + 'templateMeta' => + array ( + 'maxColumns' => '2', + 'form' => + array ( + 'hidden' => + array ( + '', + ), + 'buttons' => + array ( + + array ( + 'customCode' => '', + ), + 'CANCEL', + + array ( + 'customCode' => '', + ), + + array ( + 'customCode' => '{if $fields.status.value != "Held"}{/if}', + ), + ), + 'headerTpl' => 'modules/Meetings/tpls/header.tpl', + 'footerTpl' => 'modules/Meetings/tpls/footer.tpl', + ), + 'widths' => + array ( + + array ( + 'label' => '10', + 'field' => '30', + ), + + array ( + 'label' => '10', + 'field' => '30', + ), + ), + 'javascript' => ' + + + + +', + 'useTabs' => false, + ), + 'panels' => + array ( + 'default' => + array ( + + array ( + + array ( + 'name' => 'name', + 'displayParams' => + array ( + 'required' => true, + ), + ), + + array ( + 'name' => 'status', + 'fields' => + array ( + + array ( + 'name' => 'status', + ), + ), + ), + ), + array ( + + array ( + 'name' => 'date_start', + 'type' => 'datetimecombo', + 'displayParams' => + array ( + 'required' => true, + 'updateCallback' => 'SugarWidgetScheduler.update_time();', + ), + ), + + array ( + 'name' => 'parent_name', + 'label' => 'LBL_LIST_RELATED_TO', + ), + ), + + array ( + + array ( + 'name' => 'duration_hours', + 'label' => 'LBL_DURATION', + 'customCode' => '{literal}{/literal}
    {$fields.duration_minutes.value} {$MOD.LBL_HOURS_MINS}
    ', + ), + ), + + array ( + + array ( + 'name' => 'reminder_time', + 'customCode' => '{if $fields.reminder_checked.value == "1"}{assign var="REMINDER_TIME_DISPLAY" value="inline"}{assign var="REMINDER_CHECKED" value="checked"}{else}{assign var="REMINDER_TIME_DISPLAY" value="none"}{assign var="REMINDER_CHECKED" value=""}{/if}
    {$fields.reminder_time.value}
    ', + 'label' => 'LBL_REMINDER', + ), + + array ( + 'name' => 'location', + 'comment' => 'Meeting location', + 'label' => 'LBL_LOCATION', + ), + ), + array ( + array ( + 'name' => 'assigned_user_name', + 'label' => 'LBL_ASSIGNED_TO_NAME', + ), + + ), + + array ( + + array ( + 'name' => 'description', + 'comment' => 'Full text of the note', + 'label' => 'LBL_DESCRIPTION', + ), + ), + ), + ), + ), +); +?> diff --git a/modules/Meetings/metadata/searchdefs.php b/modules/Meetings/metadata/searchdefs.php new file mode 100644 index 00000000..2c4ae39f --- /dev/null +++ b/modules/Meetings/metadata/searchdefs.php @@ -0,0 +1,118 @@ + + array ( + 'basic_search' => + array ( + 'name' => + array ( + 'name' => 'name', + 'default' => true, + 'width' => '10%', + ), + 'current_user_only' => + array ( + 'name' => 'current_user_only', + 'label' => 'LBL_CURRENT_USER_FILTER', + 'type' => 'bool', + 'default' => true, + 'width' => '10%', + ), + array ('name' => 'open_only', 'label' => 'LBL_OPEN_ITEMS', 'type' => 'bool', 'default' => false, 'width' => '10%'), + ), + 'advanced_search' => + array ( + 'name' => + array ( + 'name' => 'name', + 'default' => true, + 'width' => '10%', + ), + 'parent_name' => + array ( + 'type' => 'parent', + 'label' => 'LBL_LIST_RELATED_TO', + 'width' => '10%', + 'default' => true, + 'name' => 'parent_name', + ), + 'current_user_only' => + array ( + 'name' => 'current_user_only', + 'label' => 'LBL_CURRENT_USER_FILTER', + 'type' => 'bool', + 'default' => true, + 'width' => '10%', + ), + 'status' => + array ( + 'name' => 'status', + 'default' => true, + 'width' => '10%', + ), + 'assigned_user_id' => + array ( + 'name' => 'assigned_user_id', + 'type' => 'enum', + 'label' => 'LBL_ASSIGNED_TO', + 'function' => + array ( + 'name' => 'get_user_array', + 'params' => + array ( + 0 => false, + ), + ), + 'default' => true, + 'width' => '10%', + ), + + ), + ), + 'templateMeta' => + array ( + 'maxColumns' => '4', + 'widths' => + array ( + 'label' => '10', + 'field' => '30', + ), + ), +); +?> diff --git a/modules/Meetings/metadata/studio.php b/modules/Meetings/metadata/studio.php new file mode 100644 index 00000000..2c09b8fd --- /dev/null +++ b/modules/Meetings/metadata/studio.php @@ -0,0 +1,66 @@ +array( + 'template'=>'xtpl', + 'template_file'=>'modules/Meetings/DetailView.html', + 'php_file'=>'modules/Meetings/DetailView.php', + 'type'=>'DetailView', + ), + 'LBL_EDITVIEW'=>array( + 'template'=>'xtpl', + 'template_file'=>'modules/Meetings/EditView.html', + 'php_file'=>'modules/Meetings/EditView.php', + 'type'=>'EditView', + ), + 'LBL_LISTVIEW'=>array( + 'template'=>'listview', + 'meta_file'=>'modules/Meetings/listviewdefs.php', + 'type'=>'ListView', + ), + 'LBL_SEARCHFORM'=>array( + 'template'=>'xtpl', + 'template_file'=>'modules/Meetings/SearchForm.html', + 'php_file'=>'modules/Meetings/ListView.php', + 'type'=>'SearchForm', + ), + +); diff --git a/modules/Meetings/metadata/subpaneldefs.php b/modules/Meetings/metadata/subpaneldefs.php new file mode 100644 index 00000000..138a2e24 --- /dev/null +++ b/modules/Meetings/metadata/subpaneldefs.php @@ -0,0 +1,98 @@ + array( + 'contacts' => array( + 'top_buttons' => array(), + 'order' => 10, + 'module' => 'Contacts', + 'sort_order' => 'asc', + 'sort_by' => 'last_name, first_name', + 'subpanel_name' => 'ForMeetings', + 'get_subpanel_data'=>'contacts', + 'title_key' => 'LBL_CONTACTS_SUBPANEL_TITLE', + ), + 'users' => array( + 'top_buttons' => array(), + 'order' => 20, + 'module' => 'Users', + 'sort_order' => 'asc', + 'sort_by' => 'name', + 'subpanel_name' => 'ForMeetings', + 'get_subpanel_data'=>'users', + 'title_key' => 'LBL_USERS_SUBPANEL_TITLE', + ), + 'leads' => array( + 'order' => 30, + 'module' => 'Leads', + 'sort_order' => 'asc', + 'sort_by' => 'last_name, first_name', + 'subpanel_name' => 'ForMeetings', + 'get_subpanel_data' => 'leads', + 'title_key' => 'LBL_LEADS_SUBPANEL_TITLE', + 'top_buttons' => array( ), + ), + 'history' => array( + 'order' => 40, + 'sort_order' => 'desc', + 'sort_by' => 'date_entered', + 'title_key' => 'LBL_HISTORY_SUBPANEL_TITLE', + 'type' => 'collection', + 'subpanel_name' => 'history', //this values is not associated with a physical file. + 'header_definition_from_subpanel'=> 'meetings', + 'module'=>'History', + + 'top_buttons' => array( + array('widget_class' => 'SubPanelTopCreateNoteButton'), + ), + + 'collection_list' => array( + 'notes' => array( + 'module' => 'Notes', + 'subpanel_name' => 'ForMeetings', + 'get_subpanel_data' => 'notes', + ), + ) + ), + ), +); +?> diff --git a/modules/Meetings/metadata/subpanels/ForActivities.php b/modules/Meetings/metadata/subpanels/ForActivities.php new file mode 100644 index 00000000..035a51aa --- /dev/null +++ b/modules/Meetings/metadata/subpanels/ForActivities.php @@ -0,0 +1,120 @@ + "(meetings.status !='Held' AND meetings.status !='Not Held')", + + + + 'list_fields' => array( + 'object_image'=>array( + 'widget_class' => 'SubPanelIcon', + 'width' => '2%', + 'image2'=>'__VARIABLE', + 'image2_ext_url_field'=>'displayed_url', + ), + 'close_button'=>array( + 'widget_class' => 'SubPanelCloseButton', + 'vname' => 'LBL_LIST_CLOSE', + 'sortable'=>false, + 'width' => '6%', + ), + 'name'=>array( + 'vname' => 'LBL_LIST_SUBJECT', + 'widget_class' => 'SubPanelDetailViewLink', + 'width' => '30%', + ), + 'status'=>array( + 'widget_class' => 'SubPanelActivitiesStatusField', + 'vname' => 'LBL_LIST_STATUS', + 'width' => '15%', + ), + 'contact_name'=>array( + 'widget_class' => 'SubPanelDetailViewLink', + 'target_record_key' => 'contact_id', + 'target_module' => 'Contacts', + 'module' => 'Contacts', + 'vname' => 'LBL_LIST_CONTACT', + 'width' => '11%', + 'sortable'=>false, + ), + 'contact_id'=>array( + 'usage'=>'query_only', + + ), + 'contact_name_owner'=>array( + 'usage'=>'query_only', + 'force_exists'=>true + ), + 'contact_name_mod'=>array( + 'usage'=>'query_only', + 'force_exists'=>true + ), + 'date_start'=>array( + 'vname' => 'LBL_LIST_DUE_DATE', + 'width' => '10%', + ), + 'assigned_user_name' => array ( + 'name' => 'assigned_user_name', + 'vname' => 'LBL_LIST_ASSIGNED_TO_NAME', + 'widget_class' => 'SubPanelDetailViewLink', + 'target_record_key' => 'assigned_user_id', + 'target_module' => 'Employees', + 'width' => '10%', + ), + 'edit_button'=>array( + 'vname' => 'LBL_EDIT_BUTTON', + 'widget_class' => 'SubPanelEditButton', + 'width' => '2%', + ), + 'remove_button'=>array( + 'vname' => 'LBL_REMOVE', + 'widget_class' => 'SubPanelRemoveButton', + 'width' => '2%', + ), + 'time_start'=>array( + 'usage'=>'query_only', + + ), + ), +); +?> diff --git a/modules/Meetings/metadata/subpanels/ForHistory.php b/modules/Meetings/metadata/subpanels/ForHistory.php new file mode 100644 index 00000000..e4be1be1 --- /dev/null +++ b/modules/Meetings/metadata/subpanels/ForHistory.php @@ -0,0 +1,132 @@ + "(meetings.status='Held' OR meetings.status='Not Held')", + + + + 'list_fields' => array( + 'object_image'=>array( + 'vname' => 'LBL_OBJECT_IMAGE', + 'widget_class' => 'SubPanelIcon', + 'width' => '2%', + 'image2'=>'attachment', + 'image2_url_field'=>'file_url' + ), + 'name'=>array( + 'vname' => 'LBL_LIST_SUBJECT', + 'widget_class' => 'SubPanelDetailViewLink', + 'width' => '30%', + ), + 'status'=>array( + 'widget_class' => 'SubPanelActivitiesStatusField', + 'vname' => 'LBL_LIST_STATUS', + 'width' => '15%', + ), + 'reply_to_status' => array( + 'usage' => 'query_only', + 'force_exists' => true, + 'force_default' => 0, + ), + 'contact_name'=>array( + 'widget_class' => 'SubPanelDetailViewLink', + 'target_record_key' => 'contact_id', + 'target_module' => 'Contacts', + 'module' => 'Contacts', + 'vname' => 'LBL_LIST_CONTACT', + 'width' => '11%', + 'sortable'=>false, + ), + 'contact_id'=>array( + 'usage'=>'query_only', + + ), + 'contact_name_owner'=>array( + 'usage'=>'query_only', + 'force_exists'=>true + ), + 'contact_name_mod'=>array( + 'usage'=>'query_only', + 'force_exists'=>true + ), + 'parent_id'=>array( + 'usage'=>'query_only', + 'force_exists'=>true + ), + 'parent_type'=>array( + 'usage'=>'query_only', + 'force_exists'=>true + ), + 'date_modified'=>array( + 'vname' => 'LBL_LIST_DATE_MODIFIED', + 'width' => '10%', + ), + 'date_entered'=>array( + 'vname' => 'LBL_LIST_DATE_ENTERED', + 'width' => '10%', + ), + 'assigned_user_name' => array ( + 'name' => 'assigned_user_name', + 'vname' => 'LBL_LIST_ASSIGNED_TO_NAME', + 'widget_class' => 'SubPanelDetailViewLink', + 'target_record_key' => 'assigned_user_id', + 'target_module' => 'Employees', + 'width' => '10%', + ), + 'edit_button'=>array( + 'vname' => 'LBL_EDIT_BUTTON', + 'widget_class' => 'SubPanelEditButton', + 'width' => '2%', + ), + 'remove_button'=>array( + 'vname' => 'LBL_REMOVE', + 'widget_class' => 'SubPanelRemoveButton', + 'width' => '2%', + ), + 'filename'=>array( + 'usage'=>'query_only', + 'force_exists'=>true + ), + ), +); +?> diff --git a/modules/Meetings/metadata/subpanels/default.php b/modules/Meetings/metadata/subpanels/default.php new file mode 100644 index 00000000..79d02c26 --- /dev/null +++ b/modules/Meetings/metadata/subpanels/default.php @@ -0,0 +1,78 @@ + array( + array('widget_class'=>'SubPanelTopCreateButton'), + array('widget_class'=>'SubPanelTopSelectButton', 'popup_module' => 'Meetings'), + ), + + 'where' => '', + + + 'list_fields' => array( + 'name'=>array( + 'name' => 'name', + 'vname' => 'LBL_LIST_SUBJECT', + 'widget_class' => 'SubPanelDetailViewLink', + 'width' => '50%', + ), + 'date_start'=>array( + 'name' => 'date_start', + 'vname' => 'LBL_LIST_DATE', + 'width' => '25%', + ), + 'date_end'=>array( + 'name' => 'date_end', + 'vname' => 'LBL_DATE_END', + 'width' => '25%', + ), + 'edit_button'=>array( + 'vname' => 'LBL_EDIT_BUTTON', + 'widget_class' => 'SubPanelEditButton', + 'width' => '2%', + ), + 'remove_button'=>array( + 'vname' => 'LBL_REMOVE', + 'widget_class' => 'SubPanelRemoveButton', + 'width' => '2%', + ), + ), +); +?> \ No newline at end of file diff --git a/modules/Meetings/tpls/QuickCreate.tpl b/modules/Meetings/tpls/QuickCreate.tpl new file mode 100644 index 00000000..eeea979e --- /dev/null +++ b/modules/Meetings/tpls/QuickCreate.tpl @@ -0,0 +1,146 @@ +{* + +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + + + +*} + + +
    + + + + + + + + + + + + + + + + +{if $REQUEST.parent_id} + +{else} + +{/if} +{if $REQUEST.parent_type} + +{else} + +{/if} + + + + + + + + + +
    + + + {$APP.LBL_REQUIRED_SYMBOL} {$APP.NTC_REQUIRED}
    + + + + +
    + + + + + + + + + + + + + + + + + + + + +

    {$MOD.LBL_NEW_FORM_TITLE}

    {$MOD.LBL_SUBJECT} {$APP.LBL_REQUIRED_SYMBOL}{$MOD.LBL_STATUS} {$APP.LBL_REQUIRED_SYMBOL}
    {$MOD.LBL_DESCRIPTION}{$MOD.LBL_DATE_TIME} + + + + + + + + + + +
    + + {$USER_DATEFORMAT}  + {$TIME_SEPARATOR} + + {if $TIME_MERIDIEM} + + {/if} +
    {$USER_DATEFORMAT}{$TIME_FORMAT}
    +
    +
    {$MOD.LBL_DURATION} {$APP.LBL_REQUIRED_SYMBOL} + {$MOD.LBL_HOURS_MINS}
    +
    +
    + + \ No newline at end of file diff --git a/modules/Meetings/tpls/extMeetingNoStart.tpl b/modules/Meetings/tpls/extMeetingNoStart.tpl new file mode 100644 index 00000000..6d43bcfb --- /dev/null +++ b/modules/Meetings/tpls/extMeetingNoStart.tpl @@ -0,0 +1,40 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} +
    {sugar_translate label='LBL_EXTNOSTART_MAIN' module='Meetings'}
    +
    +
    \ No newline at end of file diff --git a/modules/Meetings/tpls/extMeetingNotInvited.tpl b/modules/Meetings/tpls/extMeetingNotInvited.tpl new file mode 100644 index 00000000..398742b8 --- /dev/null +++ b/modules/Meetings/tpls/extMeetingNotInvited.tpl @@ -0,0 +1,40 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} +
    {sugar_translate label='LBL_EXTNOT_MAIN' module='Meetings'}
    +
    +
    \ No newline at end of file diff --git a/modules/Meetings/tpls/footer.tpl b/modules/Meetings/tpls/footer.tpl new file mode 100644 index 00000000..b76b509c --- /dev/null +++ b/modules/Meetings/tpls/footer.tpl @@ -0,0 +1,89 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} + + +{{if $externalJSFile}} + require_once("'".$externalJSFile."'"); +{{/if}} + +{$set_focus_block} + +{{if isset($scriptBlocks)}} + + {{$scriptBlocks}} + +{{/if}} + +
    + + + + +
    +{{if !empty($form) && !empty($form.buttons)}} + {{foreach from=$form.buttons key=val item=button}} + {{sugar_button module="$module" id="$button" view="$view"}} + {{/foreach}} +{{else}} + {{sugar_button module="$module" id="SAVE" view="$view"}} + {{sugar_button module="$module" id="CANCEL" view="$view"}} +{{/if}} + +{{sugar_button module="$module" id="Audit" view="$view"}} +
    \ No newline at end of file diff --git a/modules/Meetings/tpls/header.tpl b/modules/Meetings/tpls/header.tpl new file mode 100644 index 00000000..da69e1e3 --- /dev/null +++ b/modules/Meetings/tpls/header.tpl @@ -0,0 +1,42 @@ +{* +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} +{{include file='include/EditView/header.tpl'}} + + + + \ No newline at end of file diff --git a/modules/Meetings/vardefs.php b/modules/Meetings/vardefs.php new file mode 100644 index 00000000..52a2e46a --- /dev/null +++ b/modules/Meetings/vardefs.php @@ -0,0 +1,383 @@ + 'meetings', + 'unified_search' => true, 'unified_search_default_enabled' => true, + 'comment' => 'Meeting activities' + ,'fields' => array ( + 'name' => + array ( + 'name' => 'name', + 'vname' => 'LBL_SUBJECT', + 'required' => true, + 'type' => 'name', + 'dbType' => 'varchar', + 'unified_search' => true, + 'len' => '50', + 'comment' => 'Meeting name', + 'importable' => 'required', + ), + 'accept_status' => array ( + 'name' => 'accept_status', + 'vname' => 'LBL_SUBJECT', + 'type' => 'varchar', + 'dbType' => 'varchar', + 'len' => '20', + 'source'=>'non-db', + ), + 'location' => + array ( + 'name' => 'location', + 'vname' => 'LBL_LOCATION', + 'type' => 'varchar', + 'len' => '50', + 'comment' => 'Meeting location' + ), + 'password' => + array ( + 'name' => 'password', + 'vname' => 'LBL_PASSWORD', + 'type' => 'varchar', + 'len' => '50', + 'comment' => 'Meeting password', + 'studio' => 'false', + ), + 'join_url' => + array ( + 'name' => 'join_url', + 'vname' => 'LBL_URL', + 'type' => 'varchar', + 'len' => '200', + 'comment' => 'Join URL', + 'studio' => 'false', + 'reportable' => false, + ), + 'host_url' => + array ( + 'name' => 'host_url', + 'vname' => 'LBL_URL', + 'type' => 'varchar', + 'len' => '400', + 'comment' => 'Host URL', + 'studio' => 'false', + 'reportable' => false, + ), + 'displayed_url' => + array ( + 'name' => 'displayed_url', + 'vname' => 'LBL_URL', + 'type' => 'url', + 'len' => '400', + 'comment' => 'Meeting URL', + 'studio' => 'false', + ), + 'creator' => + array ( + 'name' => 'creator', + 'vname' => 'LBL_CREATOR', + 'type' => 'varchar', + 'len' => '50', + 'comment' => 'Meeting creator', + 'studio' => 'false', + ), + 'external_id' => + array ( + 'name' => 'external_id', + 'vname' => 'LBL_EXTERNALID', + 'type' => 'varchar', + 'len' => '50', + 'comment' => 'Meeting ID for external app API', + 'studio' => 'false', + ), + 'duration_hours' => + array ( + 'name' => 'duration_hours', + 'vname' => 'LBL_DURATION_HOURS', + 'type' => 'int', + 'len' => '2', + 'comment' => 'Duration (hours)', + 'importable' => 'required', + 'required' => true, + ), + 'duration_minutes' => + array ( + 'name' => 'duration_minutes', + 'vname' => 'LBL_DURATION_MINUTES', + 'type' => 'int', + 'group'=>'duration_hours', + 'function' => array('name'=>'getDurationMinutesOptions', 'returns'=>'html', 'include'=>'modules/Calls/CallHelper.php'), + 'len' => '2', + 'comment' => 'Duration (minutes)' + ), + 'date_start' => + array ( + 'name' => 'date_start', + 'vname' => 'LBL_DATE', + 'type' => 'datetimecombo', + 'dbType' => 'datetime', + 'comment' => 'Date of start of meeting', + 'importable' => 'required', + 'required' => true, + 'enable_range_search' => true, + ), + + 'date_end' => + array ( + 'name' => 'date_end', + 'vname' => 'LBL_DATE_END', + 'type' => 'datetime', + 'massupdate'=>false, + 'comment' => 'Date meeting ends', + 'enable_range_search' => true, + ), + 'parent_type' => + array ( + 'name' => 'parent_type', + 'vname'=>'LBL_LIST_RELATED_TO', + 'type' =>'parent_type', + 'dbType' => 'varchar', + 'group'=>'parent_name', + 'len' => 100, + 'comment' => 'Module meeting is associated with' + ), + 'status' => + array ( + 'name' => 'status', + 'vname' => 'LBL_STATUS', + 'type' => 'enum', + 'len' => 100, + 'options' => 'meeting_status_dom', + 'comment' => 'Meeting status (ex: Planned, Held, Not held)', + 'default' => 'Planned', + ), + 'type' => + array ( + 'name' => 'type', + 'vname' => 'LBL_TYPE', + 'type' => 'enum', + 'len' => 255, + 'function' => 'getMeetingsExternalApiDropDown', + 'comment' => 'Meeting type (ex: WebEx, Other)', + 'options' => 'eapm_list', + 'default' => 'Sugar', + 'massupdate' => false, + 'studio' => 'false', + ), + // Bug 24170 - Added only to allow the sidequickcreate form to work correctly + 'direction' => + array ( + 'name' => 'direction', + 'vname' => 'LBL_DIRECTION', + 'type' => 'enum', + 'len' => 100, + 'options' => 'call_direction_dom', + 'comment' => 'Indicates whether call is inbound or outbound', + 'source' => 'non-db', + 'importable' => 'false', + 'massupdate'=>false, + 'reportable'=>false, + 'studio' => 'false', + ), + 'parent_id' => + array ( + 'name' => 'parent_id', + 'vname'=>'LBL_LIST_RELATED_TO', + 'type' => 'id', + 'group'=>'parent_name', + 'reportable'=>false, + 'comment' => 'ID of item indicated by parent_type' + ), + 'reminder_checked'=>array( + 'name' => 'reminder_checked', + 'vname' => 'LBL_REMINDER', + 'type' => 'bool', + 'source' => 'non-db', + 'comment' => 'checkbox indicating whether or not the reminder value is set (Meta-data only)', + 'massupdate'=>false, + ), + + 'reminder_time' => + array ( + 'name' => 'reminder_time', + 'vname' => 'LBL_REMINDER_TIME', + 'type' => 'int', + 'function' => array('name'=>'getReminderTime', 'returns'=>'html', 'include'=>'modules/Calls/CallHelper.php', 'onListView'=>true ), + 'reportable' => false, + 'default'=>-1, + 'comment' => 'Specifies when a reminder alert should be issued; -1 means no alert; otherwise the number of seconds prior to the start' + ), + 'outlook_id' => + array ( + 'name' => 'outlook_id', + 'vname' => 'LBL_OUTLOOK_ID', + 'type' => 'varchar', + 'len' => '255', + 'reportable' => false, + 'comment' => 'When the Sugar Plug-in for Microsoft Outlook syncs an Outlook appointment, this is the Outlook appointment item ID' + ), + + 'contact_name' => + array ( + 'name' => 'contact_name', + 'rname' => 'last_name', + 'db_concat_fields'=> array(0=>'first_name', 1=>'last_name'), + 'id_name' => 'contact_id', + 'massupdate' => false, + 'vname' => 'LBL_CONTACT_NAME', + 'type' => 'relate', + 'link'=>'contacts', + 'table' => 'contacts', + 'isnull' => 'true', + 'module' => 'Contacts', + 'join_name' => 'contacts', + 'dbType' => 'varchar', + 'source'=>'non-db', + 'len' => 36, + 'studio' => 'false', + ), + + 'contacts' => + array ( + 'name' => 'contacts', + 'type' => 'link', + 'relationship' => 'meetings_contacts', + 'source'=>'non-db', + 'vname'=>'LBL_CONTACTS', + ), + 'parent_name'=> + array( + 'name'=> 'parent_name', + 'parent_type'=>'record_type_display' , + 'type_name'=>'parent_type', + 'id_name'=>'parent_id', + 'vname'=>'LBL_LIST_RELATED_TO', + 'type'=>'parent', + 'group'=>'parent_name', + 'source'=>'non-db', + 'options'=> 'parent_type_display', + ), + 'users' => + array ( + 'name' => 'users', + 'type' => 'link', + 'relationship' => 'meetings_users', + 'source'=>'non-db', + 'vname'=>'LBL_USERS', + ), + 'accounts' => + array ( + 'name' => 'accounts', + 'type' => 'link', + 'relationship' => 'account_meetings', + 'source'=>'non-db', + 'vname'=>'LBL_ACCOUNT', + ), + 'leads' => + array ( + 'name' => 'leads', + 'type' => 'link', + 'relationship' => 'meetings_leads', + 'source'=>'non-db', + 'vname'=>'LBL_LEADS', + ), + 'opportunity' => + array ( + 'name' => 'opportunity', + 'type' => 'link', + 'relationship' => 'opportunity_meetings', + 'source'=>'non-db', + 'vname'=>'LBL_OPPORTUNITY', + ), + 'case' => + array ( + 'name' => 'case', + 'type' => 'link', + 'relationship' => 'case_meetings', + 'source'=>'non-db', + 'vname'=>'LBL_CASE', + ), + 'notes' => + array ( + 'name' => 'notes', + 'type' => 'link', + 'relationship' => 'meetings_notes', + 'module'=>'Notes', + 'bean_name'=>'Note', + 'source'=>'non-db', + 'vname'=>'LBL_NOTES', + ), + 'contact_id' => array( + 'name' => 'contact_id', + 'type' => 'id', + 'source' => 'non-db', + ), +), + 'relationships' => array ( + 'meetings_assigned_user' => + array('lhs_module'=> 'Users', 'lhs_table'=> 'users', 'lhs_key' => 'id', + 'rhs_module'=> 'Meetings', 'rhs_table'=> 'meetings', 'rhs_key' => 'assigned_user_id', + 'relationship_type'=>'one-to-many') + + ,'meetings_modified_user' => + array('lhs_module'=> 'Users', 'lhs_table'=> 'users', 'lhs_key' => 'id', + 'rhs_module'=> 'Meetings', 'rhs_table'=> 'meetings', 'rhs_key' => 'modified_user_id', + 'relationship_type'=>'one-to-many') + + ,'meetings_created_by' => + array('lhs_module'=> 'Users', 'lhs_table'=> 'users', 'lhs_key' => 'id', + 'rhs_module'=> 'Meetings', 'rhs_table'=> 'meetings', 'rhs_key' => 'created_by', + 'relationship_type'=>'one-to-many') + + ,'meetings_notes' => array('lhs_module'=> 'Meetings', 'lhs_table'=> 'meetings', 'lhs_key' => 'id', + 'rhs_module'=> 'Notes', 'rhs_table'=> 'notes', 'rhs_key' => 'parent_id', + 'relationship_type'=>'one-to-many', 'relationship_role_column'=>'parent_type', + 'relationship_role_column_value'=>'Meetings') + ) + + , 'indices' => array ( + array('name' =>'idx_mtg_name', 'type'=>'index', 'fields'=>array('name')), + array('name' =>'idx_meet_par_del', 'type'=>'index', 'fields'=>array('parent_id','parent_type','deleted')), + array('name' => 'idx_meet_stat_del', 'type' => 'index', 'fields'=> array('assigned_user_id', 'status', 'deleted')), + + ) +//This enables optimistic locking for Saves From EditView + ,'optimistic_locking'=>true, + ); + +VardefManager::createVardef('Meetings','Meeting', array('default', 'assignable', +)); +?> diff --git a/modules/Meetings/views/view.edit.php b/modules/Meetings/views/view.edit.php new file mode 100644 index 00000000..b6af424e --- /dev/null +++ b/modules/Meetings/views/view.edit.php @@ -0,0 +1,91 @@ +bean->status = 'Held'; + } + + parent::preDisplay(); + } + + /** + * @see SugarView::display() + */ + public function display() + { + global $json; + $json = getJSONobj(); + $json_config = new json_config(); + if (isset($this->bean->json_id) && !empty ($this->bean->json_id)) { + $javascript = $json_config->get_static_json_server(false, true, 'Meetings', $this->bean->json_id); + + } else { + $this->bean->json_id = $this->bean->id; + $javascript = $json_config->get_static_json_server(false, true, 'Meetings', $this->bean->id); + + } + $this->ss->assign('JSON_CONFIG_JAVASCRIPT', $javascript); + if($this->ev->isDuplicate){ + $this->bean->status = $this->bean->getDefaultStatus(); + } //if + + parent::display(); + } +} diff --git a/modules/Meetings/views/view.listbytype.php b/modules/Meetings/views/view.listbytype.php new file mode 100644 index 00000000..1bf09219 --- /dev/null +++ b/modules/Meetings/views/view.listbytype.php @@ -0,0 +1,124 @@ + false, 'show_title' => false, 'show_subpanels' => false, 'show_search' => true, 'show_footer' => false, 'show_javascript' => false, 'view_print' => false,); + + function MeetingsViewListbytype() { + parent::ViewList(); + } + + function listViewProcess(){ + if (!$eapmBean = EAPM::getLoginInfo('LotusLive', true) ) { + $smarty = new Sugar_Smarty(); + echo $smarty->fetch('include/externalAPI/LotusLive/LotusLiveSignup.'.$GLOBALS['current_language'].'.tpl'); + return; + } + + $apiName = 'LotusLive'; + $api = ExternalAPIFactory::loadAPI($apiName,true); + $api->loadEAPM($eapmBean); + + $quickCheck = $api->quickCheckLogin(); + if ( ! $quickCheck['success'] ) { + $errorMessage = string_format(translate('LBL_ERR_FAILED_QUICKCHECK','EAPM'), array('LotusLive')); + $errorMessage .= '
    '; + $errorMessage .= ''; + $errorMessage .= ''; + $errorMessage .= ''; + $errorMessage .= ''; + $errorMessage .= ''; + $errorMessage .= ''; + + $errorMessage .= '
     '; + $errorMessage .= ''; + $errorMessage .= '
    '; + echo $errorMessage; + return; + } + + $this->processSearchForm(); + $this->params['orderBy'] = 'meetings.date_start'; + $this->params['overrideOrder'] = true; + $this->lv->searchColumns = $this->searchForm->searchColumns; + $this->lv->show_action_dropdown = false; + $this->lv->multiSelect = false; + + unset($this->searchForm->searchdefs['layout']['advanced_search']); + + if(!$this->headers) { + return; + } + + if(empty($_REQUEST['search_form_only']) || $_REQUEST['search_form_only'] == false){ + $this->lv->ss->assign("SEARCH",false); + if ( !isset($_REQUEST['name_basic']) ) { + $_REQUEST['name_basic'] = ''; + } + $this->lv->ss->assign('DCSEARCH',$_REQUEST['name_basic']); + $this->lv->setup($this->seed, 'include/ListView/ListViewDCMenu.tpl', $this->where, $this->params); + $savedSearchName = empty($_REQUEST['saved_search_select_name']) ? '' : (' - ' . $_REQUEST['saved_search_select_name']); + echo $this->lv->display(); + } + } + + function listViewPrepare() { + $oldRequest = $_REQUEST; + parent::listViewPrepare(); + $_REQUEST = $oldRequest; + } + + function processSearchForm(){ + // $type = 'LotusLiveDirect'; + $type = 'LotusLive'; + $where = " meetings.type = '$type' AND meetings.status != 'Held' AND meetings.status != 'Not Held' AND meetings.date_start > UTC_TIMESTAMP() - 7200 AND ( meetings.assigned_user_id = '".$GLOBALS['db']->quote($GLOBALS['current_user']->id)."' OR exists ( SELECT id FROM meetings_users WHERE meeting_id = meetings.id AND user_id = '".$GLOBALS['db']->quote($GLOBALS['current_user']->id)."' AND deleted = 0 ) ) "; + + if ( isset($_REQUEST['name_basic']) ) { + $name_search = trim($_REQUEST['name_basic']); + if ( ! empty($name_search) ) { + $where .= " AND meetings.name LIKE '".$GLOBALS['db']->quote($name_search)."%' "; + } + } + + $this->where = $where; + } + +} diff --git a/modules/MergeRecords/Menu.php b/modules/MergeRecords/Menu.php new file mode 100644 index 00000000..1becfc01 --- /dev/null +++ b/modules/MergeRecords/Menu.php @@ -0,0 +1,50 @@ + diff --git a/modules/MergeRecords/Merge.js b/modules/MergeRecords/Merge.js new file mode 100644 index 00000000..a379ec06 --- /dev/null +++ b/modules/MergeRecords/Merge.js @@ -0,0 +1,93 @@ +/********************************************************************************* + * SugarCRM is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * 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 Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ +var lbl_remove=SUGAR.language.get('app_strings','LBL_REMOVE');function remove_filter(spanfieldid){var selspan=document.getElementById(spanfieldid);selspan.setAttribute("style","visibility:hidden");selspan.innerHTML='';var ops=object_refs['field_avail_list'].options;var newoption=new Option(selspan.getAttribute("Value"),selspan.getAttribute("ValueId"),false,true);ops.add(newoption);} +function ajax_fetch_sync(url,post_data) +{global_xmlhttp=getXMLHTTPinstance();var method='GET';if(typeof(post_data)!='undefined') +{method='POST';} +try +{global_xmlhttp.open(method,url,false);} +catch(error) +{alert('message:'+error.message+":url:"+url);} +if(method=='POST') +{global_xmlhttp.setRequestHeader('Content-Type','application/x-www-form-urlencoded');} +global_xmlhttp.send(post_data);var ajax_response={"responseText":global_xmlhttp.responseText,"responseXML":global_xmlhttp.responseXML};return ajax_response;} +function get_fields_to_dedup(parent_mod) +{var rel_map_div_obj=document.getElementById('rel_map');if(parent_mod!='') +{var request_id=1;var url=site_url+'/index.php?to_pdf=1&sugar_body_only=1&inline=1&parent_module='+parent_mod+'&module=MigrationMappings&action=GetRelationshipsToMap';var ajax_return_obj=ajax_fetch_sync(url);try{eval("var responseObj ="+ajax_return_obj['responseText']);} +catch(e){alert(ajax_return_obj['responseText']);} +build_avail_rels_array(responseObj);rel_map_div_obj.innerHTML=responseObj['html_content'];} +else +{rel_map_div_obj.innerHTML='';} +return true;} +function get_dedup_fields() +{var parent_div=document.getElementById('filter_def');var node;var spannode;var value;var valueid;var style;document.DedupSetup.dedup_fields.value='';for(node in parent_div.childNodes){spannode=parent_div.childNodes[node];if(spannode.tagName=='SPAN'){value=spannode.getAttribute('value');valueid=spannode.getAttribute('valueid');style=spannode.getAttribute('style');if(typeof(style)=='undefined'||style==null||style==''||style.lastIndexOf('hidden')==-1){if(document.DedupSetup.dedup_fields.value!=''){document.DedupSetup.dedup_fields.value=document.DedupSetup.dedup_fields.value+'#';} +document.DedupSetup.dedup_fields.value=document.DedupSetup.dedup_fields.value+valueid;}}}} +var object_refs=new Object();object_refs['field_include_list']=document.DedupSetup['field_include_list'];object_refs['field_avail_list']=document.DedupSetup['field_avail_list'];function setselected(included_name,avail_name) +{var included_columns_ref=object_refs[included_name];var avail_columns_ref=object_refs[avail_name];var included_td=document.getElementById(included_name+'_td');var avail_td=document.getElementById(avail_name+'_td');var selected_avail=new Array();var notselected_avail=new Array();var notselected_include=new Array();for(i=0;i-1;i--){if(obj[i].selected==true){sel[sel.length]=i;}} +for(i in sel){if(sel[i]!=obj.length-1&&!obj[sel[i]+1].selected){var tmp=new Array(obj[sel[i]+1].text,obj[sel[i]+1].value);obj[sel[i]+1].text=obj[sel[i]].text;obj[sel[i]+1].value=obj[sel[i]].value;obj[sel[i]].text=tmp[0];obj[sel[i]].value=tmp[1];obj[sel[i]+1].selected=true;obj[sel[i]].selected=false;}}} +function buildSelectHTML(info) +{var text;text="
    ";} +text+="
    ";return text;} +var fieldCount=0;function addFieldRow(colName,colLabel){var tableId='search_type';var rowIdName='field';var fieldArrayCount;var optionVal;var optionDispVal;var optionsIndex=0;fieldCount=fieldCount+1;document.DedupSetup.num_fields.value=fieldCount;var selElement=document.createElement("select");var selectName=colName+"SearchType";selElement.setAttribute("name",selectName);var i=0;for(theoption in operator_options){selElement.options[i]=new Option(operator_options[theoption],theoption,false,false);i++;} +var aElement=document.createElement("a");aElement.setAttribute("href","javascript:remove_filter('filter_"+colName+"')");aElement.setAttribute("class","listViewTdToolsS1");var imgElement=document.createElement("img");imgElement.setAttribute("src",delete_inline_image);imgElement.setAttribute("align","absmiddle");imgElement.setAttribute("alt",lbl_remove);imgElement.setAttribute("border","0");imgElement.setAttribute("height","12");imgElement.setAttribute("width","12");aElement.appendChild(imgElement);aElement.appendChild(document.createTextNode(" "));var div=document.getElementById('filter_def');var span1=document.getElementById('filter_'+colName);if(span1==null||span1==''||typeof(span1)=='undefined'){span1=document.createElement("span");}else{span1.setAttribute("style","visibility:visible");} +span1.setAttribute("id",'filter_'+colName);span1.setAttribute("Value",colLabel);span1.setAttribute("ValueId",colName);var table=document.createElement("table");var row=table.insertRow(table.rows.length);table.setAttribute("width","100%");table.setAttribute("border","0");table.setAttribute("cellpadding","0");var td1=document.createElement("td");td1.setAttribute("width","2%");td1.appendChild(aElement);row.appendChild(td1) +var td2=document.createElement("td");td2.setAttribute("width","20%");td2.appendChild(document.createTextNode(colLabel+': '));row.appendChild(td2) +var td3=document.createElement("td");td3.setAttribute("width","10%");td3.appendChild(selElement);row.appendChild(td3);var coldata;eval("coldata=bean_data."+colName+";");var edit=document.createElement("input");edit.setAttribute("type","text");edit.setAttribute("name",colName+'SearchField');edit.setAttribute("id",colName+'SearchField');edit.setAttribute("value",coldata);var td5=document.createElement("td");td5.setAttribute("width","68%");td5.appendChild(edit);row.appendChild(td5);span1.appendChild(table);div.appendChild(span1);} \ No newline at end of file diff --git a/modules/MergeRecords/MergeField.html b/modules/MergeRecords/MergeField.html new file mode 100644 index 00000000..c5bad20c --- /dev/null +++ b/modules/MergeRecords/MergeField.html @@ -0,0 +1,125 @@ + + + + + +
    {FIELD_LABEL} {REQUIRED_SYMBOL} {APP.LBL_ENTER_DATE} {APP.LBL_ENTER_DATE} {USER_DATEFORMAT} +  {FIELD_VALUE} 
    +
    + + + + + + + + + + + +
    {MOD.LBL_NUMBER}   + {MOD.LBL_SUBJECT}  {MOD.LBL_ACCOUNT_NAME}  {APP.LBL_CURRENT_USER_FILTER}   + + + + +
    + {ADVANCED_SEARCH_PNG} {APP.LNK_ADVANCED_SEARCH} +
    +
    +{JAVASCRIPT} + + + + +

    + + + + + + + +
    + + + + + + + + + + + + + + + + + +
    {MOD.LBL_SUBJECT}{MOD.LBL_CASE_NUMBER}  +
    {BASIC_SEARCH_PNG} {APP.LNK_BASIC_SEARCH} +
    {MOD.LBL_ACCOUNT_NAME}{MOD.LBL_STATUS}
    {APP.LBL_ASSIGNED_TO}{MOD.LBL_PRIORITY}
    +
    +
    +{JAVASCRIPT} + diff --git a/modules/MergeRecords/Step1.html b/modules/MergeRecords/Step1.html new file mode 100644 index 00000000..c7dede7a --- /dev/null +++ b/modules/MergeRecords/Step1.html @@ -0,0 +1,130 @@ + + +{MOD.LBL_STEP1_DIRECTIONS} +

    + + +
    + + + + + + + + + + + + + + + +
    {ADMIN_EDIT}
    + + + + + + + + + + + + + + + + + +
    {MOD.LBL_SELECT_MODULE}:  
      
    +
    + + + + + + + + + + + + +
    {MOD.LBL_AVAIL_FIELDS}: {MOD.LBL_FILTER_COND}:
    +
    + + {LBL_ADD_BUTTON} + +
    +
    {PRE_LOADED_FIELDS}
    +
    + +
    +
    + +
    + +{JAVASCRIPT} + + + diff --git a/modules/MergeRecords/Step1.php b/modules/MergeRecords/Step1.php new file mode 100644 index 00000000..3288a4a7 --- /dev/null +++ b/modules/MergeRecords/Step1.php @@ -0,0 +1,189 @@ +merge_module = $_REQUEST['return_module']; +$focus->load_merge_bean($focus->merge_module, true, $_REQUEST['record']); + + +//get all available column fields +//TO DO: add custom field handling +$avail_fields=array(); +$sel_fields=array(); +$temp_field_array = $focus->merge_bean->field_defs; +$bean_data=array(); +foreach($temp_field_array as $field_array) +{ + if (isset($field_array['merge_filter']) + ) { + if (strtolower($field_array['merge_filter'])=='enabled' or strtolower($field_array['merge_filter'])=='selected') { + $col_name = $field_array['name']; + + + if(!isset($focus->merge_bean_strings[$field_array['vname']])) { + $col_label = $col_name; + } + else { + $col_label = str_replace(':', '', $focus->merge_bean_strings[$field_array['vname']]); + } + + if (strtolower($field_array['merge_filter'])=='selected') { + $sel_fields[$col_name]=$col_label; + } else { + $avail_fields[$col_name] = $col_label; + } + + $bean_data[$col_name]=$focus->merge_bean->$col_name; + } + } +} + +///////////////////////////////////////////////////////// + +//Print the master record header to the page +$params = array(); +$params[] = "{$GLOBALS['app_list_strings']['moduleList'][$focus->merge_bean->module_dir]}"; +$params[] = "{$focus->merge_bean->name}"; +$params[] = $mod_strings['LBL_LBL_MERGE_RECORDS_STEP_1']; +echo getClassicModuleTitle($focus->merge_bean->module_dir, $params, true); + +$xtpl = new XTemplate ('modules/MergeRecords/Step1.html'); +$xtpl->assign("MOD", $mod_strings); +$xtpl->assign("APP", $app_strings); +$xtpl->assign("BEANDATA",$json->encode($bean_data)); +//This is for the implemetation of finding all dupes for a module, not just +//dupes for a particular record +//commenting this out for now +//$choose_master_by_options = array('First Record Found', 'Most Recent Record', 'Oldest Record', 'Record Containing Most Data'); +//$xtpl->assign("CHOOSE_MASTER_BY_OPTIONS", get_select_options_with_id($choose_master_by_options, 'First Record Found')); + +$xtpl->assign("MERGE_MODULE", $focus->merge_module); +$xtpl->assign("ID", $focus->merge_bean->id); + +$xtpl->assign("FIELD_AVAIL_OPTIONS", get_select_options_with_id($avail_fields,'')); +$xtpl->assign("LBL_ADD_BUTTON", translate('LBL_ADD_BUTTON')); + +if(isset($_REQUEST['return_id'])) $xtpl->assign("RETURN_ID", $_REQUEST['return_id']); +$xtpl->assign("RETURN_ACTION", $_REQUEST['return_action']); +$xtpl->assign("RETURN_MODULE", $_REQUEST['return_module']); + +//set the url +$port=null; +if(isset($_SERVER['SERVER_PORT']) && $_SERVER['SERVER_PORT'] != 80 && $_SERVER['SERVER_PORT'] != 443) { + $port = $_SERVER['SERVER_PORT']; +} +$xtpl->assign("URL", appendPortToHost($sugar_config['site_url'], $port)); +//set images +$xtpl->assign("RIGHTARROW_BIG_IMAGE", SugarThemeRegistry::current()->getImageURL('rightarrow_big.gif')); +$xtpl->assign("DELETE_INLINE_IMAGE", SugarThemeRegistry::current()->getImageURL('delete_inline.gif')); + +//process preloaded filter. +$pre_loaded=null; +foreach ($sel_fields as $colName=>$colLabel) { + $pre_loaded.=addFieldRow($colName,$colLabel,$bean_data[$colName]); +} +$xtpl->assign("PRE_LOADED_FIELDS",$pre_loaded); +$xtpl->assign("OPERATOR_OPTIONS",$json->encode($app_list_strings['merge_operators_dom'])); + + +$xtpl->parse("main.field_select_block"); + +$xtpl->parse("main"); +$xtpl->out("main"); + + +/** + * This function is equivalent of AddFieldRow in merge.js. is being used to + * preload the filter criteria based on the vardef. + *
    + */ +function addFieldRow($colName,$colLabel,$colValue) { + global $theme, $app_list_strings; + + static $operator_options; + if (empty($operator_options)) { + $operator_options= get_select_options_with_id($app_list_strings['merge_operators_dom'],''); + } + + $LBL_REMOVE = translate('LBL_REMOVE'); + $deleteInlineImage = SugarThemeRegistry::current()->getImageURL('delete_inline.gif'); + $snippet=<< + + + + + + + +
    {$LBL_REMOVE} {$colLabel}: 
    + +EOQ; + + return $snippet; +} diff --git a/modules/MergeRecords/Step2.html b/modules/MergeRecords/Step2.html new file mode 100644 index 00000000..36f440ae --- /dev/null +++ b/modules/MergeRecords/Step2.html @@ -0,0 +1,42 @@ + + + + diff --git a/modules/MergeRecords/Step2.php b/modules/MergeRecords/Step2.php new file mode 100644 index 00000000..7e49ca06 --- /dev/null +++ b/modules/MergeRecords/Step2.php @@ -0,0 +1,214 @@ +load_merge_bean($_REQUEST['merge_module'], true, $_REQUEST['record']); + +$this->bean = $focus->merge_bean; + +$params = array(); +$params[] = "{$GLOBALS['app_list_strings']['moduleList'][$focus->merge_bean->module_dir]}"; +$params[] = "{$focus->merge_bean->name}"; +$params[] = $mod_strings['LBL_STEP2_FORM_TITLE']; +echo getClassicModuleTitle($focus->merge_bean->module_dir, $params, true); + + $order_by_name = $focus->merge_module.'2_'.strtoupper($focus->merge_bean->object_name).'_ORDER_BY' ; + $lvso = isset($_REQUEST['lvso'])?$_REQUEST['lvso']:""; + $request_order_by_name = isset($_REQUEST[$order_by_name])?$_REQUEST[$order_by_name]:""; + +echo '
    ' + .'' + .'' + .'' + .'' + .'' + ."" + .""; + +$focus->populate_search_params($_REQUEST); +echo $focus->get_inputs_for_search_params($_REQUEST); + +$where_clauses = Array(); +$where_clauses = $focus->create_where_statement(); +$where = $focus->generate_where_statement($where_clauses); + +$ListView = new ListViewSmarty(); +$ListView->should_process = true; +$ListView->mergeduplicates = false; +$ListView->export = false; +$ListView->select = false; +$ListView->delete = false; +$module = $_REQUEST['merge_module']; +$metadataFile = null; +$foundViewDefs = false; +if(file_exists('custom/modules/' . $module. '/metadata/listviewdefs.php')){ + $metadataFile = 'custom/modules/' . $module . '/metadata/listviewdefs.php'; + $foundViewDefs = true; +}else{ + if(file_exists('custom/modules/'.$module.'/metadata/metafiles.php')){ + require_once('custom/modules/'.$module.'/metadata/metafiles.php'); + if(!empty($metafiles[$module]['listviewdefs'])){ + $metadataFile = $metafiles[$module]['listviewdefs']; + $foundViewDefs = true; + } + }elseif(file_exists('modules/'.$module.'/metadata/metafiles.php')){ + require_once('modules/'.$module.'/metadata/metafiles.php'); + if(!empty($metafiles[$module]['listviewdefs'])){ + $metadataFile = $metafiles[$module]['listviewdefs']; + $foundViewDefs = true; + } + } +} +if(!$foundViewDefs && file_exists('modules/'.$module.'/metadata/listviewdefs.php')){ + $metadataFile = 'modules/'.$module.'/metadata/listviewdefs.php'; +} +require_once($metadataFile); +$displayColumns = array(); +if(!empty($_REQUEST['displayColumns'])) { + foreach(explode('|', $_REQUEST['displayColumns']) as $num => $col) { + if(!empty($listViewDefs[$module][$col])) + $displayColumns[$col] = $listViewDefs[$module][$col]; + } +} +else { + foreach($listViewDefs[$module] as $col => $params) { + if(!empty($params['default']) && $params['default']) + $displayColumns[$col] = $params; + } +} +$params = array('massupdate' => true, 'export' => false, 'handleMassupdate' => false ); +$ListView->displayColumns = $displayColumns; +$ListView->lvd->listviewName = $focus->merge_module; //27633, this will make the $module to be merge_module instead of 'MergeRecords'. Then the key of offset and orderby will be correct. +$where = $focus->generate_where_statement($focus->create_where_statement()); +$ListView->setup($this->bean, 'include/ListView/ListViewGeneric.tpl', $where, $params); +$ListView->force_mass_update=true; +$ListView->show_mass_update_form=false; +$ListView->show_export_button=false; +$ListView->keep_mass_update_form_open=true; + +$return_id = $_REQUEST['record']; +$merge_module = $focus->merge_module; + +$button_title = $current_module_strings['LBL_PERFORM_MERGE_BUTTON_TITLE']; +$button_key = $current_module_strings['LBL_PERFORM_MERGE_BUTTON_KEY']; +$button_label = $current_module_strings['LBL_PERFORM_MERGE_BUTTON_LABEL']; + +$cancel_title=$app_strings['LBL_CANCEL_BUTTON_TITLE']; +$cancel_key=$app_strings['LBL_CANCEL_BUTTON_KEY']; +$cancel_label=$app_strings['LBL_CANCEL_BUTTON_LABEL']; + +echo ($ListView->display()); + +$error_select=$current_module_strings['LBL_SELECT_ERROR']; +$form_top = << + + + + + + + + + +EOQ; +echo $form_top; +?> \ No newline at end of file diff --git a/modules/MergeRecords/Step3.html b/modules/MergeRecords/Step3.html new file mode 100644 index 00000000..41a7fc33 --- /dev/null +++ b/modules/MergeRecords/Step3.html @@ -0,0 +1,239 @@ + + +

    +

    + + + + + + + + + + + + + {MERGED_IDS} + + + + + + +
      + {APP.LBL_REQUIRED_SYMBOL} {APP.NTC_REQUIRED}
    + + + + +
    + + {DIFF_HEADER} + + {FILE "modules/MergeRecords/MergeField.html"} + + {GROUP_PARTITION} + {SIMILAR_HEADER} + + {FILE "modules/MergeRecords/MergeField.html"} + +
    +
    +
    + + + + +
      +
    +
    +

    + + +{VALIDATION_JS} + \ No newline at end of file diff --git a/modules/MergeRecords/Step3.php b/modules/MergeRecords/Step3.php new file mode 100644 index 00000000..2597da69 --- /dev/null +++ b/modules/MergeRecords/Step3.php @@ -0,0 +1,545 @@ +'datetimecombo','source'=>'db'), + array('type'=>'datetime','source'=>'db'), + array('type'=>'varchar','source'=>'db'), + array('type'=>'enum','source'=>'db'), + array('type'=>'multienum','source'=>'db'), + array('type'=>'text','source'=>'db'), + array('type'=>'date','source'=>'db'), + array('type'=>'time','source'=>'db'), + array('type'=>'int','source'=>'db'), + array('type'=>'long','source'=>'db'), + array('type'=>'double','source'=>'db'), + array('type'=>'float','source'=>'db'), + array('type'=>'short','source'=>'db'), + array('dbType'=>'varchar','source'=>'db'), + array('dbType'=>'double','source'=>'db'), + array('type'=>'relate'), + ); + +$filter_for_valid_related_attributes = array( array('type'=>'link'),); +$filter_for_invalid_related_attributes = array(array('type'=>'link','link_type'=>'one')); + +//following attributes will be ignored from the merge process. +$invalid_attribute_by_name= array('date_entered'=>'date_entered','date_modified'=>'date_modified','modified_user_id'=>'modified_user_id', 'created_by'=>'created_by','deleted'=>'deleted'); + +$merge_ids_array = array (); +if (isset($_REQUEST['change_parent']) && $_REQUEST['change_parent']=='1') { + $base_id=$_REQUEST['change_parent_id']; + foreach ($_REQUEST['merged_ids'] as $id) { + if ($id != $base_id) { + $merge_ids_array[] = $id; + } + } + //add the existing parent to merged_id array. + $merge_ids_array[] = $_REQUEST['record']; +} elseif (isset($_REQUEST['remove']) && $_REQUEST['remove']=='1') { + $base_id=$_REQUEST['record']; + $removed_id= $_REQUEST['remove_id']; + foreach ($_REQUEST['merged_ids'] as $id) { + if ($id != $removed_id) { + $merge_ids_array[] = $id; + } + } +} else { + $base_id=$_REQUEST['record']; + foreach ($_REQUEST['mass'] as $id) { + $merge_ids_array[] = $id; + } +} +$focus = new MergeRecord(); +$focus->load_merge_bean($_REQUEST['merge_module'], true, $base_id); +$params = array(); +$params[] = "{$GLOBALS['app_list_strings']['moduleList'][$focus->merge_bean->module_dir]}"; +$params[] = "{$focus->merge_bean->name}"; +$params[] = $mod_strings['LBL_MODULE_NAME']; +echo getClassicModuleTitle($focus->merge_bean->module_dir, $params, true); + +$mergeBeanArray = array (); +$records=1; +//render a column for each record to merge +$merged_ids=''; +$merge_records_names=array(); +foreach ($merge_ids_array as $id) { + require_once ($focus->merge_bean_file_path); + $mergeBeanArray[$id] = new $focus->merge_bean_class(); + $mergeBeanArray[$id]->retrieve($id); + $merge_records_names[]=$mergeBeanArray[$id]->get_summary_text(); + $records++; + $merged_ids.=""; +} + +$col_width=floor(80/$records).'%'; +global $max_data_length; +$max_data_length=floor(65/$records); +global $xtpl; +$xtpl = new XTemplate("modules/MergeRecords/Step3.html"); +$xtpl->assign("MOD", $mod_strings); +$xtpl->assign("APP", $app_strings); + +$xtpl->assign("ID", $focus->merge_bean->id); +$xtpl->assign("MERGE_MODULE", $focus->merge_module); + +$xtpl->assign("MERGED_IDS", $merged_ids); + +//set return parameters. +if (!empty ($_REQUEST['return_module'])) { + $xtpl->assign("RETURN_MODULE", $_REQUEST['return_module']); +} +if (!empty ($_REQUEST['return_action'])) { + $xtpl->assign("RETURN_ACTION", $_REQUEST['return_action']); +} +if (!empty ($_REQUEST['return_id'])) { + $xtpl->assign("RETURN_ID", $_REQUEST['return_id']); +} + +$temp_field_array = $focus->merge_bean->field_defs; +$field_count = 1; +$json = new JSON(JSON_LOOSE_TYPE); +$diff_field_count=0; +foreach ($temp_field_array as $field_array) { + + + if (show_field($field_array) + ) { + + $select_row_curr_field_value = null; + $b_values_different = false; + $section_name='merge_row_similar'; + + //Prcoess locaton of the field. if values are different show field in first section. else 2nd. + $select_row_curr_field_value = $focus->merge_bean->$field_array['name']; + foreach ($merge_ids_array as $id) { + if (($mergeBeanArray[$id]-> $field_array['name']=='' and $select_row_curr_field_value =='') or $mergeBeanArray[$id]-> $field_array['name'] == $select_row_curr_field_value ) { + $section_name='merge_row_similar'; + } else { + $section_name='merge_row_diff'; + $diff_field_count++; + break; //foreach + } + } + //check for vname in mod strings first, then app, else just display name + $col_name = $field_array['name']; + if (isset ($focus->merge_bean_strings[$field_array['vname']]) && $focus->merge_bean_strings[$field_array['vname']] != '') + $xtpl->assign("FIELD_LABEL", $focus->merge_bean_strings[$field_array['vname']]); + elseif (isset ($app_strings[$field_array['vname']]) && $app_strings[$field_array['vname']] != '') $xtpl->assign("FIELD_LABEL", $app_strings[$field_array['vname']]); + else + $xtpl->assign("FIELD_LABEL", $field_array['name']); + //if required add signage. + if (!empty($focus->merge_bean->required_fields[$col_name]) or $col_name=='team_name') { + $xtpl->assign("REQUIRED_SYMBOL","".$app_strings['LBL_REQUIRED_SYMBOL'].""); + } else { + $xtpl->assign("REQUIRED_SYMBOL",""); + } + + $xtpl->assign("CELL_WIDTH", "20%"); + $xtpl->parse("main.".$section_name.".merge_cell_label"); + + if (isset ($field_array['custom_type']) && $field_array['custom_type'] != '') + $field_check = $field_array['custom_type']; + else + $field_check = $field_array['type']; + + + if(preg_match('/.*?_address_street$/', $field_array['name'])) { + $field_check = 'text'; + } + + $xtpl->assign("EDIT_FIELD_NAME", $field_array['name']); + $xtpl->assign("TAB_INDEX", $field_count); + + switch ($field_check) { + case ('name') : + case ('varchar') : + case ('phone') : + case ('num') : + case ('email') : + case ('custom_fields') : + case ('url') : + case ('int') : + case ('float') : + case ('double') : + case ('currency') : + + $xtpl->assign("EDIT_FIELD_VALUE", $select_row_curr_field_value); + $xtpl->assign("CELL_WIDTH", $col_width); + $xtpl->parse("main.".$section_name.".merge_cell_edit_text"); + break; + case ('text') : + $xtpl->assign("EDIT_FIELD_VALUE", $select_row_curr_field_value); + $xtpl->assign("CELL_WIDTH", $col_width); + $xtpl->parse("main.".$section_name.".merge_cell_edit_textarea"); + break; + case ('enum') : + $xtpl->assign("SELECT_OPTIONS", get_select_options_with_id($app_list_strings[$field_array['options']], $select_row_curr_field_value)); + $xtpl->assign("CELL_WIDTH",$col_width); + $xtpl->parse("main.".$section_name.".merge_cell_edit_dropdown"); + break; + case ('multienum') : + $select_row_curr_field_value = unencodeMultienum($select_row_curr_field_value); + $xtpl->assign("SELECT_OPTIONS", get_select_options_with_id($app_list_strings[$field_array['options']], $select_row_curr_field_value)); + $xtpl->assign("CELL_WIDTH",$col_width); + $xtpl->parse("main.".$section_name.".merge_cell_edit_multidropdown"); + break; + //popup fields need to be fixed.., cant automate with vardefs + case ('relate') : + if(!empty($field_array['link'])) { + $exclude[$field_array['link']] = $field_array['link']; + } + case ('link') : + //get_related_name + if (empty($select_row_curr_field_value)) { + $related_name=get_related_name($field_array,$focus->merge_bean->$field_array['id_name']); + if ($related_name !== false ) { + $select_row_curr_field_value=$related_name; + } + } + if($field_check == 'link') {//relate type should not enter this. + $exclude[$field_array['name']] = $field_array['name']; + } + $xtpl->assign("POPUP_ID_FIELD", $field_array['id_name']); + $xtpl->assign("POPUP_NAME_FIELD", $field_array['name']); + $xtpl->assign("POPUP_NAME_VALUE", $select_row_curr_field_value); + $xtpl->assign("POPUP_ID_VALUE", $focus->merge_bean-> $field_array['id_name']); + $xtpl->assign("POPUP_MODULE", $field_array['module']); + $xtpl->assign("CELL_WIDTH", $col_width); + $xtpl->assign("MERGED_LINKS", implode(',', $exclude)); + + $popup_data = array ('call_back_function' => 'set_return', 'form_name' => 'EditView', 'field_to_name_array' => array ('id' => $field_array['id_name'], 'name' => $field_array['name'],),); + $xtpl->assign('ENCODED_POPUP_DATA', $json->encode($popup_data)); + + $xtpl->parse("main.".$section_name.".merge_cell_edit_popup"); + break; + case ('bool') : + if (($select_row_curr_field_value == '1' || $select_row_curr_field_value == 'yes' || $select_row_curr_field_value == 'on') && !empty($select_row_curr_field_value)) + $xtpl->assign("EDIT_FIELD_VALUE", " checked"); + else + $xtpl->assign("EDIT_FIELD_VALUE", ""); + + $xtpl->assign("CELL_WIDTH", $col_width); + $xtpl->parse("main.".$section_name.".merge_cell_edit_checkbox"); + break; + case ('date') : + case ('datetime') : + $xtpl->assign("CALENDAR_LANG", "en"); + $xtpl->assign("USER_DATEFORMAT", '('.$timedate->get_user_date_format().')'); + $xtpl->assign("CALENDAR_DATEFORMAT", $timedate->get_cal_date_format()); + $xtpl->assign("EDIT_FIELD_VALUE", $select_row_curr_field_value); + $xtpl->assign("CELL_WIDTH", $col_width); + $xtpl->assign("THEME", $theme); + $xtpl->parse("main.".$section_name.".merge_cell_edit_date"); + break; + case ('datetimecombo') : + $xtpl->assign("CALENDAR_LANG", "en"); + $xtpl->assign("USER_DATEFORMAT", $timedate->get_user_time_format()); + $xtpl->assign("CALENDAR_DATEFORMAT", $timedate->get_cal_date_format()); + $xtpl->assign("EDIT_FIELD_VALUE", $select_row_curr_field_value); + $xtpl->assign("CELL_WIDTH", $col_width); + $xtpl->assign("THEME", $theme); + $xtpl->parse("main.".$section_name.".merge_cell_edit_datetime"); + break; + default : + break; + } + + //render a column for each selected record to merge + foreach ($merge_ids_array as $id) { + $xtpl->assign("CELL_WIDTH", $col_width); + $field_name=null; + switch ($field_check) { + case ('bool') : + if (($mergeBeanArray[$id]->$field_array['name'] == '1' || $mergeBeanArray[$id]->$field_array['name'] == 'yes' || $mergeBeanArray[$id]->$field_array['name'] == 'on') && !empty($mergeBeanArray[$id]->$field_array['name'])) { + $xtpl->assign("FIELD_VALUE", " checked"); + } else { + $xtpl->assign("FIELD_VALUE", ""); + } + $field_name="main.".$section_name.".merge_cell_field_value_checkbox"; + break; + case ('enum') : + if ($mergeBeanArray[$id]-> $field_array['name'] != '' and isset($field_array['options']) and isset($app_list_strings[$field_array['options']][$mergeBeanArray[$id]-> $field_array['name']])) { + display_field_value( $app_list_strings[$field_array['options']][$mergeBeanArray[$id]-> $field_array['name']]); + } else { + display_field_value($mergeBeanArray[$id]-> $field_array['name']); + } + $field_name="main.".$section_name.".merge_cell_field_value"; + break; + case ('multienum') : + if ($mergeBeanArray[$id]-> $field_array['name'] != '' and isset($field_array['options']) and isset($app_list_strings[$field_array['options']][$mergeBeanArray[$id]-> $field_array['name']])) { + display_field_value(str_replace("^","",$app_list_strings[$field_array['options']][$mergeBeanArray[$id]-> $field_array['name']])); + } else { + display_field_value(str_replace("^","",$mergeBeanArray[$id]-> $field_array['name'])); + } + $field_name="main.".$section_name.".merge_cell_field_value"; + break; + case ('relate') : + case ('link') : + $related_name=false; + if (empty($mergeBeanArray[$id]-> $field_array['name']) && !empty($mergeBeanArray[$id]-> $field_array['id_name'])) { + $related_name=get_related_name($field_array,$mergeBeanArray[$id]-> $field_array['id_name']); + if ($related_name !== false) { + $mergeBeanArray[$id]-> $field_array['name']=$related_name; + } + } + display_field_value($mergeBeanArray[$id]-> $field_array['name']); + $field_name="main.".$section_name.".merge_cell_field_value"; + break; + default : + display_field_value($mergeBeanArray[$id]-> $field_array['name']); + $field_name="main.".$section_name.".merge_cell_field_value"; + break; + } + + $json_data = array ('field_name' => $field_array['name'], 'field_type' => $field_check,); + //add an array of fields/values to the json array + //for setting all the values for merge + if ($field_check == 'relate' or $field_check == 'link') { + $temp_array = Array (); + $json_data['popup_fields'] = Array ($field_array['name'] => $mergeBeanArray[$id]-> $field_array['name'], $field_array['id_name'] => $mergeBeanArray[$id]-> $field_array['id_name'],); + } else if($field_check == 'teamset') { + $json_data['field_value'] = TeamSetManager::getCommaDelimitedTeams($mergeBeanArray[$id]->team_set_id, $mergeBeanArray[$id]->team_id, true); + $json_data['field_value2'] = TeamSetManager::getTeamsFromSet($mergeBeanArray[$id]->team_set_id); + $json_data['field_value3'] = $mergeBeanArray[$id]->team_set_id; + } else if($field_check == 'multienum') { + $json_data['field_value'] = unencodeMultienum($mergeBeanArray[$id]-> $field_array['name']); + } else { + $json_data['field_value'] = $mergeBeanArray[$id]-> $field_array['name']; + } + $encoded_json_data = $json->encode($json_data); + $xtpl->assign('ENCODED_JSON_DATA', $encoded_json_data); + $xtpl->parse($field_name); + } + + $xtpl->parse("main.".$section_name); + $field_count ++; + } +} + +$header_cols= array(); +foreach ($merge_ids_array as $id) { + $td="

     {$mod_strings['LBL_CHANGE_PARENT']}"; + if (count($merge_ids_array) > 1) { + $td.=" |{$mod_strings['LBL_REMOVE_FROM_MERGE']}"; + } + $td.="
    {$mod_strings['LBL_DIFF_COL_VALUES']}
    {$mod_strings['LBL_SAME_COL_VALUES']}
    {$mod_strings['LBL_SAME_COL_VALUES']}
    "+SimpleList.editImage+""; + html += " "+SimpleList.deleteImage+""; + html += "
    "; + + liObj.innerHTML = html; + ul1.appendChild(liObj); + new Studio2.ListDD(liObj, 'drpdwn', false); + drop_value.value = ""; + drop_name.value = ""; + drop_name.focus(); + + SimpleList.jstransaction.record('deleteDropDown',{'id': liObj.id }); + + }, + + sortAscending: function () + { + // now sort using a Shellsort - do this rather than by using the inbuilt sort function as we need to sort a complex DOM inplace + var parent = YAHOO.util.Dom.get("ul1"); + var items = parent.getElementsByTagName("li") ; + var increment = Math.floor ( items.length / 2 ) ; + + function swapItems(itemA, itemB) { + var placeholder = document.createElement ( "li" ) ; + Dom.insertAfter(placeholder, itemA); + Dom.insertBefore(itemA, itemB); + Dom.insertBefore(itemB, placeholder); + + //Cleanup the placeholder element + parent.removeChild(placeholder); + } + + while ( increment > 0 ) + { + for (var i = increment; i < items.length; i++) + { + var j = i; + var id = items[i].id; + var iValue = document.getElementById( 'input_' + id ).value.toLowerCase() ; + + while ( ( j >= increment ) && ( document.getElementById( 'input_' + items [j-increment].id ).value.toLowerCase() > iValue ) ) + { + // logically, this is what we need to do: items [j] = items [j - increment]; + // but we're working with the DOM through a NodeList (items) which is readonly, so things aren't that simple + // A placeholder will be used to keep track of where in the DOM the swap needs to take place + // especially with IE which enforces the prohibition on duplicate Ids, so copying nodes is problematic + swapItems(items [j], items [j - increment]); + j = j - increment; + } + } + + if (increment == 2) + increment = 1; + else + increment = Math.floor (increment / 2.2); + } + }, + sortDescending: function () + { + this.sortAscending(); + var reverse = function ( children ) + { + var parent = children [ 0 ] . parentNode ; + var start = 0; + if ( children [ 0 ].id == '-blank-' ) // don't include -blank- element in the sort + start = 1 ; + for ( var i = children.length - 1 ; i >= start ; i-- ) + { + parent.appendChild ( children [ i ] ) ; + } + }; + reverse ( YAHOO.util.Dom.get("ul1").getElementsByTagName("li") ) ; + }, + handleSave:function(){ + var parseList = function(ul, title) { + var items = ul.getElementsByTagName("li"); + var out = []; + for (i=0;i 1) { this.reduceFieldWidth( field ); } + _write_("Unregistered:"+field.id); + field.removeChild( field.childNodes[1] ); + field.removeAttribute("expandable"); + field.removeAttribute("state"); + } + }, + isExpandable:function( field ){ + return field.getAttribute("expandable")!=null && !this.isSpecial(field);//&& field.getAttribute("expandable") == "true"; + }, + swapStates:function( src, dest ){ + var old_src= {state:src.getAttribute("state"), img: src.childNodes[1].src}; + src.setAttribute("state", dest.getAttribute("state")); + src.childNodes[1].src = dest.childNodes[1].src; + dest.childNodes[1].src = old_src.img; + dest.setAttribute("state", old_src.state); + }, + + getImageElement:function(default_toggle){ + var img = document.createElement('img'); + if(!default_toggle) + img.src = 'index.php?entryPoint=getImage&themeName='+SUGAR.themes.theme_name+'&imageName=minus_inline.gif'; + else + img.src = 'index.php?entryPoint=getImage&themeName='+SUGAR.themes.theme_name+'&imageName=plus_inline.gif'; + img.className = 'le_edit'; + img.style.paddingRight = 2; + img.style.cssFloat = 'left'; + img.name = 'expandable_field_icon'; + return img; + }, + + + toggleFieldWidth:function(id){ + + var field = YAHOO.util.Dom.get(id); + if ( typeof(field) == 'undefined' || field === null ) return; + var img = field.childNodes[1]; + + if( field.getAttribute("state") && field.getAttribute("state")=='reduced' ){ + field.parentNode.removeChild( Studio2.nextField(field) || Studio2.prevField(field) ); + Studio2.setColumnWidth(id,2); + img.src = 'index.php?entryPoint=getImage&themeName='+SUGAR.themes.theme_name+'&imageName=minus_inline.gif'; + this.setExpanded( field ); + + + }else if( field.getAttribute("state") && field.getAttribute("state")=='expanded' ){ + Studio2.setColumnWidth(id,1); + var newField = Studio2.newField(); + Studio2.setSpecial(newField); + Studio2.activateElement(newField); + field.parentNode.appendChild(newField); + this.setReduced( field ); + img.src='index.php?entryPoint=getImage&themeName='+SUGAR.themes.theme_name+'&imageName=plus_inline.gif'; + + } + }, + setExpanded: function( field ){ + field.setAttribute("expandable","true"); + field.setAttribute("state","expanded"); + _write_("Expanded: "+field.id); + }, + setReduced: function( field ){ + field.setAttribute("expandable","true"); + field.setAttribute("state","reduced"); + _write_("Recued: "+field.id); + }, + isExpanded: function (field ){ + return field.getAttribute('state') == 'expanded'; + }, + isReduced:function (field ){ + return field.getAttribute('state') == 'reduced'; + }, + registerExpandableField: function( field ) {//field = HTML element + if( Studio2.maxColumns < 2 || field == null || typeof(field) == 'undefined' || this.isSpecial (field) ) { return; } + if( !this.isExpandable( field ) ) { + var next = this.nextField ( field ) ; + var prev = this.prevField ( field ) ; + var removeMe = next || prev ; + if( this.isSpecial( next) || this.isSpecial( prev ) || this.isEmpty( next ) || this.isEmpty( prev ) || removeMe == null ){ //Always Expanded + _write_("remove me is :"+removeMe); + if (removeMe != null) { field.parentNode.removeChild(removeMe); } + var img = this.getImageElement ( false ); + img.onclick = function () { Studio2.toggleFieldWidth ( field.id ) }; + field.insertBefore ( img, field.childNodes[1] ); + this.setColumnWidth( field.id, 2 ); + this.setExpanded( field ); + _write_("registered field"); + } + }else{ _write_("Could not Register field:"+field.id); } + }, + setStartId: function(id) { + Studio2.idStack = [id]; + }, + + nextId: function() { + if (Studio2.idStack.length == 1) { // if down to our last id, allocate another + Studio2.idStack[0]++; + Studio2.idStack.push(Studio2.idStack[0]); + } + return Studio2.idStack.pop(); + }, + + setNextId: function(id) { + Studio2.idStack.push(id); + }, + + isSpecial: function(element) { + if(element==null || typeof(element) == 'undefined'){return false;}; + return YAHOO.util.Dom.hasClass(element,'special'); + }, + + setSpecial: function(el) { + YAHOO.util.Dom.addClass(el, 'special'); + }, + + unsetSpecial: function(el) { + YAHOO.util.Dom.removeClass(el, 'special'); + }, + isEmpty: function( element ){ + if (element == null || typeof(element) == 'undefined') {return false;}; + return YAHOO.util.Dom.hasClass(element, 'le_field special'); + }, + count: function(element) { + var count = 0; + for (var j=0;j' + // the displayed label + '(filler)'; // the hidden field that identifies this as something to be saved by prepareForSave() + return newField; + }, + + newRow: function(titleRequired) { + var newRow = document.createElement('div'); + if (titleRequired) { + var child = document.createElement('span'); + child.className = 'panel_name'; + child.appendChild(document.createTextNode(SUGAR.language.get('ModuleBuilder', 'LBL_NEW_ROW') ) ); + newRow.appendChild(child); + } + newRow.className='le_row'; + newRow.id = Studio2.nextId(); + for(var i=0;i1) { + Studio2.removeElement(panel); + Studio2.tidyPanels(); + } else { + // add a blank row back in + var newRow = Studio2.newRow(false); + panel.appendChild(newRow); + Studio2.activateElement(newRow); +// debugger; + } + } + }, + + tidyFields: function(row) { + if (Studio2.count(row) <= 0) { // no fields left + var panel = row.parentNode; + Studio2.removeElement(row); + Studio2.tidyRows(panel); + } + }, + + removeElement: function(element) { + Studio2.reclaimIds(element); + Studio2.reclaimFields(element); + if (element.className.indexOf('le_field') == -1) { + // all fields have been moved to availablefields in Studio2.reclaimFields + element.parentNode.removeChild(element); + } + }, + + swapElements: function(el1,el2) { + // TODO: record this swap in TRANSACTION + var el1Width = Studio2.getFieldWidth(el1); + var el2Width = Studio2.getFieldWidth(el2); + YAHOO.util.DragDropMgr.swapNode(el1, el2); + Studio2.setFieldWidth(el1,el2Width); + Studio2.setFieldWidth(el2,el1Width); + }, + + activateElement: function(element) { + if (!document.getElementById(element.id)) { + document.body.appendChild(element); + } + if (element.className.indexOf('le_panel') != -1) { + new Studio2.PanelDD(element.id,'studio2.panels'); + new YAHOO.util.DDTarget(element.id,'studio2.rows'); // add so a background for row moves + } + if (element.className.indexOf('le_row') != -1) { + new Studio2.RowDD(element.id,'studio2.rows'); + } + if (element.className.indexOf('le_field') != -1) { + new Studio2.FieldDD(element,'studio2.fields'); + } + for (var i=0;i 0) { + var attrs = element.attributes; + for(var i=0;i